From 05288f82b1c62f498f1b6ac08d1901edcc6a3f06 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 4 Apr 2024 11:43:09 +0300 Subject: [PATCH 01/56] refactor: factor out solver integration tests --- Cargo.toml | 1 + cadical/Cargo.toml | 3 + cadical/tests/incremental.rs | 87 +---------- cadical/tests/phasing.rs | 39 +---- cadical/tests/small.rs | 112 ++------------ glucose/Cargo.toml | 3 + glucose/tests/incremental.rs | 88 +---------- glucose/tests/phasing.rs | 39 +---- glucose/tests/small.rs | 71 +-------- kissat/Cargo.toml | 3 + kissat/tests/small.rs | 112 ++------------ minisat/Cargo.toml | 3 + minisat/tests/incremental.rs | 87 +---------- minisat/tests/phasing.rs | 39 +---- minisat/tests/small.rs | 72 +-------- release-plz.toml | 5 + solvertests/Cargo.toml | 16 ++ solvertests/src/lib.rs | 275 +++++++++++++++++++++++++++++++++++ 18 files changed, 367 insertions(+), 688 deletions(-) create mode 100644 solvertests/Cargo.toml create mode 100644 solvertests/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index cc31a465..468b0e15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "glucose", "minisat", "ipasir", + "solvertests", ] resolver = "2" diff --git a/cadical/Cargo.toml b/cadical/Cargo.toml index 8079e9e9..9afb53af 100644 --- a/cadical/Cargo.toml +++ b/cadical/Cargo.toml @@ -50,3 +50,6 @@ cc = { version = "1.0.83", features = ["parallel"] } git2 = "0.18.1" glob = "0.3.1" chrono = "0.4.31" + +[dev-dependencies] +rustsat-solvertests = { path = "../solvertests" } diff --git a/cadical/tests/incremental.rs b/cadical/tests/incremental.rs index 0f0df4e3..aed0e6f7 100644 --- a/cadical/tests/incremental.rs +++ b/cadical/tests/incremental.rs @@ -1,86 +1 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - lit, - solvers::{SolveIncremental, SolverResult}, -}; -use rustsat_cadical::CaDiCaL; - -fn test_assumption_sequence(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver.solve_assumps(&[!lit![0], !lit![1]]).unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -#[test] -fn assumption_sequence() { - let solver = CaDiCaL::default(); - test_assumption_sequence(solver); -} +rustsat_solvertests::incremental_tests!(rustsat_cadical::CaDiCaL); diff --git a/cadical/tests/phasing.rs b/cadical/tests/phasing.rs index 492faf6e..2f1c9370 100644 --- a/cadical/tests/phasing.rs +++ b/cadical/tests/phasing.rs @@ -1,34 +1,5 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - lit, - solvers::{PhaseLit, Solve, SolverResult}, - types::TernaryVal, - var, -}; -use rustsat_cadical::CaDiCaL; - -fn test_phase_saving(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - solver.phase_lit(lit![0]).unwrap(); - solver.phase_lit(!lit![1]).unwrap(); - solver.phase_lit(lit![2]).unwrap(); - solver.phase_lit(!lit![3]).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); - let sol = solver.solution(var![3]).unwrap(); - assert_eq!(sol.lit_value(lit![0]), TernaryVal::True); - assert_eq!(sol.lit_value(lit![1]), TernaryVal::False); - assert_eq!(sol.lit_value(lit![2]), TernaryVal::True); - assert_eq!(sol.lit_value(lit![3]), TernaryVal::False); - solver.unphase_var(var![1]).unwrap(); - solver.unphase_var(var![0]).unwrap(); -} - -#[test] -fn phase_saving() { - let mut solver = CaDiCaL::default(); - solver.set_option("lucky", 0).unwrap(); - test_phase_saving(solver); -} +rustsat_solvertests::phasing_tests!({ + let mut slv = rustsat_cadical::CaDiCaL::default(); + slv.set_option("lucky", 0).unwrap(); + slv +}); diff --git a/cadical/tests/small.rs b/cadical/tests/small.rs index 5bd5d74c..b2e59e52 100644 --- a/cadical/tests/small.rs +++ b/cadical/tests/small.rs @@ -1,102 +1,20 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - solvers::{Solve, SolverResult}, -}; -use rustsat_cadical::CaDiCaL; - -fn small_sat_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/AProVE11-12.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); -} - -fn small_unsat_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf") - .unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -fn ms_segfault_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/minisat-segfault.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); +mod base { + rustsat_solvertests::base_tests!(rustsat_cadical::CaDiCaL); } -#[test] -fn small_sat() { - let solver = CaDiCaL::default(); - small_sat_instance(solver); +mod sat { + rustsat_solvertests::base_tests!({ + let mut slv = rustsat_cadical::CaDiCaL::default(); + slv.set_configuration(rustsat_cadical::Config::SAT).unwrap(); + slv + }); } -#[test] -fn small_unsat() { - let solver = CaDiCaL::default(); - small_unsat_instance(solver); -} - -#[test] -fn ms_segfault() { - let solver = CaDiCaL::default(); - ms_segfault_instance(solver); -} - -#[test] -fn sat_small_sat() { - let mut solver = CaDiCaL::default(); - solver - .set_configuration(rustsat_cadical::Config::SAT) - .unwrap(); - small_sat_instance(solver); -} - -#[test] -fn sat_small_unsat() { - let mut solver = CaDiCaL::default(); - solver - .set_configuration(rustsat_cadical::Config::SAT) - .unwrap(); - small_unsat_instance(solver); -} - -#[test] -fn sat_ms_segfault() { - let mut solver = CaDiCaL::default(); - solver - .set_configuration(rustsat_cadical::Config::SAT) - .unwrap(); - ms_segfault_instance(solver); -} - -#[test] -fn unsat_small_sat() { - let mut solver = CaDiCaL::default(); - solver - .set_configuration(rustsat_cadical::Config::UNSAT) - .unwrap(); - small_sat_instance(solver); -} - -#[test] -fn unsat_small_unsat() { - let mut solver = CaDiCaL::default(); - solver - .set_configuration(rustsat_cadical::Config::UNSAT) - .unwrap(); - small_unsat_instance(solver); -} - -#[test] -fn unsat_ms_segfault() { - let mut solver = CaDiCaL::default(); - solver - .set_configuration(rustsat_cadical::Config::UNSAT) - .unwrap(); - ms_segfault_instance(solver); +mod unsat { + rustsat_solvertests::base_tests!({ + let mut slv = rustsat_cadical::CaDiCaL::default(); + slv.set_configuration(rustsat_cadical::Config::UNSAT) + .unwrap(); + slv + }); } diff --git a/glucose/Cargo.toml b/glucose/Cargo.toml index 62879b18..8481d335 100644 --- a/glucose/Cargo.toml +++ b/glucose/Cargo.toml @@ -30,3 +30,6 @@ git2 = "0.18.1" glob = "0.3.1" chrono = "0.4.31" cmake = "0.1.50" + +[dev-dependencies] +rustsat-solvertests = { path = "../solvertests" } diff --git a/glucose/tests/incremental.rs b/glucose/tests/incremental.rs index 55bbf818..b8ed4aee 100644 --- a/glucose/tests/incremental.rs +++ b/glucose/tests/incremental.rs @@ -1,86 +1,6 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - lit, - solvers::{SolveIncremental, SolverResult}, -}; -use rustsat_glucose::core::Glucose; - -fn test_assumption_sequence(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver.solve_assumps(&[!lit![0], !lit![1]]).unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); +mod core { + rustsat_solvertests::incremental_tests!(rustsat_glucose::core::Glucose); } -#[test] -fn assumption_sequence() { - let solver = Glucose::default(); - test_assumption_sequence(solver); -} +// Note: Cannot test prepro version of glucose with this small example because +// the variable are eliminated by preprocessing diff --git a/glucose/tests/phasing.rs b/glucose/tests/phasing.rs index 4791dc44..20f886bb 100644 --- a/glucose/tests/phasing.rs +++ b/glucose/tests/phasing.rs @@ -1,38 +1,7 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - lit, - solvers::{PhaseLit, Solve, SolverResult}, - types::TernaryVal, - var, -}; -use rustsat_glucose::{core, simp}; - -fn test_phase_saving(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - solver.phase_lit(lit![0]).unwrap(); - solver.phase_lit(!lit![1]).unwrap(); - solver.phase_lit(lit![2]).unwrap(); - solver.phase_lit(!lit![3]).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); - let sol = solver.solution(var![3]).unwrap(); - assert_eq!(sol.lit_value(lit![0]), TernaryVal::True); - assert_eq!(sol.lit_value(lit![1]), TernaryVal::False); - assert_eq!(sol.lit_value(lit![2]), TernaryVal::True); - assert_eq!(sol.lit_value(lit![3]), TernaryVal::False); - solver.unphase_var(var![1]).unwrap(); - solver.unphase_var(var![0]).unwrap(); -} -#[test] -fn core_phase_saving() { - let solver = core::Glucose::default(); - test_phase_saving(solver); +mod core { + rustsat_solvertests::phasing_tests!(rustsat_glucose::core::Glucose); } -#[test] -fn simp_phase_saving() { - let solver = simp::Glucose::default(); - test_phase_saving(solver); +mod simp { + rustsat_solvertests::phasing_tests!(rustsat_glucose::simp::Glucose); } diff --git a/glucose/tests/small.rs b/glucose/tests/small.rs index 35c29c93..c1780d5e 100644 --- a/glucose/tests/small.rs +++ b/glucose/tests/small.rs @@ -1,70 +1,7 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - solvers::{Solve, SolverResult}, -}; -use rustsat_glucose::{core, simp}; - -fn small_sat_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/AProVE11-12.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); -} - -fn small_unsat_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf") - .unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -fn ms_segfault_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/minisat-segfault.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -#[test] -fn core_small_sat() { - let solver = core::Glucose::default(); - small_sat_instance(solver); -} - -// Note: this instance seems too hard for glucose to solve -#[test] -#[ignore] -fn core_small_unsat() { - let solver = core::Glucose::default(); - small_unsat_instance(solver); -} - -#[test] -fn core_ms_segfault() { - let solver = core::Glucose::default(); - ms_segfault_instance(solver); -} - -#[test] -fn simp_small_sat() { - let solver = simp::Glucose::default(); - small_sat_instance(solver); -} - -// Note: this instance seems too hard for glucose to solve -#[test] -#[ignore] -fn simp_small_unsat() { - let solver = simp::Glucose::default(); - small_unsat_instance(solver); +mod core { + rustsat_solvertests::base_tests!(rustsat_glucose::core::Glucose, false, true); } -#[test] -fn simp_ms_segfault() { - let solver = simp::Glucose::default(); - ms_segfault_instance(solver); +mod simp { + rustsat_solvertests::base_tests!(rustsat_glucose::simp::Glucose, false, true); } diff --git a/kissat/Cargo.toml b/kissat/Cargo.toml index cf0817c4..b40c0074 100644 --- a/kissat/Cargo.toml +++ b/kissat/Cargo.toml @@ -35,3 +35,6 @@ cc = { version = "1.0.83", features = ["parallel"] } git2 = "0.18.1" glob = "0.3.1" chrono = "0.4.31" + +[dev-dependencies] +rustsat-solvertests = { path = "../solvertests" } diff --git a/kissat/tests/small.rs b/kissat/tests/small.rs index f7ddd67c..fb3371a0 100644 --- a/kissat/tests/small.rs +++ b/kissat/tests/small.rs @@ -1,102 +1,20 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - solvers::{Solve, SolverResult}, -}; -use rustsat_kissat::Kissat; - -fn small_sat_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/AProVE11-12.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); -} - -fn small_unsat_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf") - .unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -fn ms_segfault_instance(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/minisat-segfault.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); +mod base { + rustsat_solvertests::base_tests!(rustsat_kissat::Kissat); } -#[test] -fn small_sat() { - let solver = Kissat::default(); - small_sat_instance(solver); +mod sat { + rustsat_solvertests::base_tests!({ + let mut slv = rustsat_kissat::Kissat::default(); + slv.set_configuration(rustsat_kissat::Config::SAT).unwrap(); + slv + }); } -#[test] -fn small_unsat() { - let solver = Kissat::default(); - small_unsat_instance(solver); -} - -#[test] -fn ms_segfault() { - let solver = Kissat::default(); - ms_segfault_instance(solver); -} - -#[test] -fn sat_small_sat() { - let mut solver = Kissat::default(); - solver - .set_configuration(rustsat_kissat::Config::SAT) - .unwrap(); - small_sat_instance(solver); -} - -#[test] -fn sat_small_unsat() { - let mut solver = Kissat::default(); - solver - .set_configuration(rustsat_kissat::Config::SAT) - .unwrap(); - small_unsat_instance(solver); -} - -#[test] -fn sat_ms_segfault() { - let mut solver = Kissat::default(); - solver - .set_configuration(rustsat_kissat::Config::SAT) - .unwrap(); - ms_segfault_instance(solver); -} - -#[test] -fn unsat_small_sat() { - let mut solver = Kissat::default(); - solver - .set_configuration(rustsat_kissat::Config::UNSAT) - .unwrap(); - small_sat_instance(solver); -} - -#[test] -fn unsat_small_unsat() { - let mut solver = Kissat::default(); - solver - .set_configuration(rustsat_kissat::Config::UNSAT) - .unwrap(); - small_unsat_instance(solver); -} - -#[test] -fn unsat_ms_segfault() { - let mut solver = Kissat::default(); - solver - .set_configuration(rustsat_kissat::Config::UNSAT) - .unwrap(); - ms_segfault_instance(solver); +mod unsat { + rustsat_solvertests::base_tests!({ + let mut slv = rustsat_kissat::Kissat::default(); + slv.set_configuration(rustsat_kissat::Config::UNSAT) + .unwrap(); + slv + }); } diff --git a/minisat/Cargo.toml b/minisat/Cargo.toml index ace5a5b1..ebae177f 100644 --- a/minisat/Cargo.toml +++ b/minisat/Cargo.toml @@ -30,3 +30,6 @@ git2 = "0.18.1" glob = "0.3.1" chrono = "0.4.31" cmake = "0.1.50" + +[dev-dependencies] +rustsat-solvertests = { path = "../solvertests" } diff --git a/minisat/tests/incremental.rs b/minisat/tests/incremental.rs index a29a9259..75a1f694 100644 --- a/minisat/tests/incremental.rs +++ b/minisat/tests/incremental.rs @@ -1,88 +1,5 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - lit, - solvers::{SolveIncremental, SolverResult}, -}; -use rustsat_minisat::core::Minisat; - -fn test_assumption_sequence(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver.solve_assumps(&[!lit![0], !lit![1]]).unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Sat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -#[test] -fn assumption_sequence() { - let solver = Minisat::default(); - test_assumption_sequence(solver); +mod core { + rustsat_solvertests::incremental_tests!(rustsat_minisat::core::Minisat); } // Note: Cannot test prepro version of minisat with this small example because diff --git a/minisat/tests/phasing.rs b/minisat/tests/phasing.rs index a58eda45..ec89d6b5 100644 --- a/minisat/tests/phasing.rs +++ b/minisat/tests/phasing.rs @@ -1,38 +1,7 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - lit, - solvers::{PhaseLit, Solve, SolverResult}, - types::TernaryVal, - var, -}; -use rustsat_minisat::{core, simp}; - -fn test_phase_saving(mut solver: S) { - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - solver.phase_lit(lit![0]).unwrap(); - solver.phase_lit(!lit![1]).unwrap(); - solver.phase_lit(lit![2]).unwrap(); - solver.phase_lit(!lit![3]).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); - let sol = solver.solution(var![3]).unwrap(); - assert_eq!(sol.lit_value(lit![0]), TernaryVal::True); - assert_eq!(sol.lit_value(lit![1]), TernaryVal::False); - assert_eq!(sol.lit_value(lit![2]), TernaryVal::True); - assert_eq!(sol.lit_value(lit![3]), TernaryVal::False); - solver.unphase_var(var![1]).unwrap(); - solver.unphase_var(var![0]).unwrap(); -} -#[test] -fn core_phase_saving() { - let solver = core::Minisat::default(); - test_phase_saving(solver); +mod core { + rustsat_solvertests::phasing_tests!(rustsat_minisat::core::Minisat); } -#[test] -fn simp_phase_saving() { - let solver = simp::Minisat::default(); - test_phase_saving(solver); +mod simp { + rustsat_solvertests::phasing_tests!(rustsat_minisat::simp::Minisat); } diff --git a/minisat/tests/small.rs b/minisat/tests/small.rs index 154c2c09..fd7e83c7 100644 --- a/minisat/tests/small.rs +++ b/minisat/tests/small.rs @@ -1,71 +1,7 @@ -use rustsat::{ - instances::{BasicVarManager, SatInstance}, - solvers::{Solve, SolverResult}, -}; -use rustsat_minisat::{core, simp}; - -#[test] -fn core_small_sat() { - let mut solver = core::Minisat::default(); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/AProVE11-12.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); -} - -// Note: this instance seems too hard for minisat to solve -#[test] -#[ignore] -fn core_small_unsat() { - let mut solver = core::Minisat::default(); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf") - .unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -#[test] -fn core_ms_segfault() { - let mut solver = core::Minisat::default(); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/minisat-segfault.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); -} - -#[test] -fn simp_small_sat() { - let mut solver = simp::Minisat::default(); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/AProVE11-12.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Sat); -} - -// Note: this instance seems too hard for minisat to solve -#[test] -#[ignore] -fn simp_small_unsat() { - let mut solver = simp::Minisat::default(); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf") - .unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); +mod core { + rustsat_solvertests::base_tests!(rustsat_minisat::core::Minisat, false, true); } -#[test] -fn simp_ms_segfault() { - let mut solver = simp::Minisat::default(); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/minisat-segfault.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, SolverResult::Unsat); +mod simp { + rustsat_solvertests::base_tests!(rustsat_minisat::simp::Minisat, false, true); } diff --git a/release-plz.toml b/release-plz.toml index 8d4d53b1..5a6295d1 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -30,3 +30,8 @@ semver_check = true name = "rustsat-ipasir" release = false git_release_enable = false + +[[package]] +name = "rustsat-solvertests" +release = false +git_release_enable = false diff --git a/solvertests/Cargo.toml b/solvertests/Cargo.toml new file mode 100644 index 00000000..757cc950 --- /dev/null +++ b/solvertests/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rustsat-solvertests" +description = "Test code shared between sat solver crates" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +syn = "2.0" +quote = "1.0" +rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +proc-macro2 = "1.0" diff --git a/solvertests/src/lib.rs b/solvertests/src/lib.rs new file mode 100644 index 00000000..e20b8afd --- /dev/null +++ b/solvertests/src/lib.rs @@ -0,0 +1,275 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::{quote, ToTokens}; +use syn::{ + parse::Parse, parse_macro_input, parse_quote, punctuated::Punctuated, Attribute, Expr, LitBool, + Token, Type, +}; + +enum InitBy { + Default(Type), + Expr(Expr), +} + +impl Parse for InitBy { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let typr: syn::Result = input.parse(); + Ok(if let Ok(typ) = typr { + Self::Default(typ) + } else { + Self::Expr(input.parse()?) + }) + } +} + +impl ToTokens for InitBy { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + match self { + InitBy::Default(typ) => typ.to_tokens(tokens), + InitBy::Expr(expr) => expr.to_tokens(tokens), + } + } +} + +struct MacroInput { + slv: InitBy, + bools: Vec, +} + +impl Parse for MacroInput { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let slv: InitBy = input.parse()?; + if input.is_empty() { + return Ok(Self { slv, bools: vec![] }); + } + let _: Token![,] = input.parse()?; + let bools = Punctuated::::parse_terminated(input)?; + let bools: Vec<_> = bools.into_iter().map(|lit| lit.value).collect(); + Ok(Self { slv, bools }) + } +} + +#[proc_macro] +pub fn base_tests(tokens: TokenStream) -> TokenStream { + let input = parse_macro_input!(tokens as MacroInput); + let slv = input.slv; + let ignoretok = |idx: usize| -> Option { + if input.bools.len() > idx && input.bools[idx] { + Some(parse_quote! {#[ignore]}) + } else { + None + } + }; + let mut ts = quote! { + macro_rules! test_inst { + ($slv:ty, $inst:expr, $res:expr) => {{ + let mut solver = <$slv>::default(); + let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) + .expect("failed to parse instance"); + rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) + .expect("failed to add cnf to solver"); + let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); + assert_eq!(res, $res); + }}; + ($init:expr, $inst:expr, $res:expr) => {{ + let mut solver = $init; + let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) + .expect("failed to parse instance"); + rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) + .expect("failed to add cnf to solver"); + let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); + assert_eq!(res, $res); + }}; + } + }; + let ignore = ignoretok(0); + ts.extend(quote! { + #[test] + #ignore + fn small_sat() { + test_inst!(#slv, "./data/AProVE11-12.cnf", rustsat::solvers::SolverResult::Sat); + } + }); + let ignore = ignoretok(1); + ts.extend(quote! { + #[test] + #ignore + fn small_unsat() { + test_inst!(#slv, "./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf", rustsat::solvers::SolverResult::Unsat); + } + }); + let ignore = ignoretok(2); + ts.extend(quote! { + #[test] + #ignore + fn minisat_segfault() { + test_inst!(#slv, "./data/minisat-segfault.cnf", rustsat::solvers::SolverResult::Unsat); + } + }); + ts.into() +} + +#[proc_macro] +pub fn incremental_tests(tokens: TokenStream) -> TokenStream { + let input = parse_macro_input!(tokens as MacroInput); + let slv = input.slv; + let ignoretok = |idx: usize| -> Option { + if input.bools.len() > idx && input.bools[idx] { + Some(parse_quote! {#[ignore]}) + } else { + None + } + }; + let mut ts = quote! { + macro_rules! init_slv { + ($slv:ty) => { + <$slv>::default() + }; + ($init:expr) => { + $init + }; + } + }; + let ignore = ignoretok(0); + ts.extend(quote! { + #[test] + #ignore + fn assumption_sequence() { + use rustsat::{ + instances::{SatInstance}, + lit, + solvers::{Solve, SolveIncremental, SolverResult::{Sat, Unsat}}, + }; + + let mut solver = init_slv!(#slv); + let inst: SatInstance = + SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); + solver.add_cnf(inst.as_cnf().0).unwrap(); + let res = solver.solve().unwrap(); + assert_eq!(res, Sat); + let res = solver.solve_assumps(&[!lit![0], !lit![1]]).unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + } + }); + ts.into() +} + +#[proc_macro] +pub fn phasing_tests(tokens: TokenStream) -> TokenStream { + let input = parse_macro_input!(tokens as MacroInput); + let slv = input.slv; + let ignoretok = |idx: usize| -> Option { + if input.bools.len() > idx && input.bools[idx] { + Some(parse_quote! {#[ignore]}) + } else { + None + } + }; + let mut ts = quote! { + macro_rules! init_slv { + ($slv:ty) => { + <$slv>::default() + }; + ($init:expr) => { + $init + }; + } + }; + let ignore = ignoretok(0); + ts.extend(quote! { + #[test] + #ignore + fn assumption_sequence() { + use rustsat::{ + instances::{SatInstance}, + lit, + solvers::{PhaseLit, Solve, SolverResult::Sat}, + types::TernaryVal::{True, False}, + var, + }; + let mut solver = init_slv!(#slv); + let inst: SatInstance = + SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); + solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.phase_lit(lit![0]).unwrap(); + solver.phase_lit(!lit![1]).unwrap(); + solver.phase_lit(lit![2]).unwrap(); + solver.phase_lit(!lit![3]).unwrap(); + let res = solver.solve().unwrap(); + assert_eq!(res, Sat); + let sol = solver.solution(var![3]).unwrap(); + assert_eq!(sol.lit_value(lit![0]), True); + assert_eq!(sol.lit_value(lit![1]), False); + assert_eq!(sol.lit_value(lit![2]), True); + assert_eq!(sol.lit_value(lit![3]), False); + solver.unphase_var(var![1]).unwrap(); + solver.unphase_var(var![0]).unwrap(); + } + }); + ts.into() +} From 1ce81bd48611c796711d8bbeaa23a5dadc520215 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Mon, 8 Apr 2024 16:23:58 +0300 Subject: [PATCH 02/56] refactor: factor out C-API factor out C-API into separate crate and tooling around that --- .github/workflows/capi.yml | 54 ++++++++++++++++++++++ .github/workflows/docs.yml | 2 +- .github/workflows/rustsat.yml | 13 ------ Cargo.toml | 1 + README.md | 3 -- capi/Cargo.toml | 26 +++++++++++ capi/README.md | 17 +++++++ {rustsat => capi}/build.rs | 22 +-------- {rustsat => capi}/cbindgen.toml | 35 +++----------- {rustsat => capi}/examples/capi-ipasir.cpp | 0 {rustsat => capi}/examples/capi.cpp | 0 {rustsat => capi}/rustsat.h | 2 - rustsat/src/capi.rs => capi/src/lib.rs | 26 ++++++----- release-plz.toml | 5 ++ rustsat/Cargo.toml | 6 +-- rustsat/src/encodings/pb/dpw.rs | 24 ++++++++-- rustsat/src/lib.rs | 17 +++++-- scripts/sync-versions.sh | 7 +++ 18 files changed, 168 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/capi.yml create mode 100644 capi/Cargo.toml create mode 100644 capi/README.md rename {rustsat => capi}/build.rs (65%) rename {rustsat => capi}/cbindgen.toml (91%) rename {rustsat => capi}/examples/capi-ipasir.cpp (100%) rename {rustsat => capi}/examples/capi.cpp (100%) rename {rustsat => capi}/rustsat.h (99%) rename rustsat/src/capi.rs => capi/src/lib.rs (97%) create mode 100755 scripts/sync-versions.sh diff --git a/.github/workflows/capi.yml b/.github/workflows/capi.yml new file mode 100644 index 00000000..95062a70 --- /dev/null +++ b/.github/workflows/capi.yml @@ -0,0 +1,54 @@ +name: C-API + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build-test: + name: Build and test + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + shared-key: "build-test" + - name: Cargo build + run: cargo build -p rustsat-capi --verbose + env: + CMAKE_BUILD_PARALLEL_LEVEL: ${{ fromJSON('["", "4"]')[matrix.os == 'macos-latest'] }} + - name: Cargo test + run: cargo test -p rustsat-capi --verbose + env: + CMAKE_BUILD_PARALLEL_LEVEL: ${{ fromJSON('["", "4"]')[matrix.os == 'macos-latest'] }} + + version: + name: Ensure C-API crate version is in sync + runs-on: ubuntu-latest + steps: + - name: Check + run: "[ \"$(grep '^version = ' rustsat/Cargo.toml)\" = \"$(grep '^version = ' capi/Cargo.toml)\" ]" + + cbindgen: + name: Test generated C header + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + - name: Check C header + run: | + cargo install cbindgen + cbindgen -c capi/cbindgen.toml --crate rustsat-capi -o capi/rustsat.h --verify diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 54c50aad..ac0db713 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -24,4 +24,4 @@ jobs: - name: Check READMEs run: | cargo install cargo-rdme - for dir in rustsat tools cadical kissat minisat glucose ipasir; do cd ${dir} && (cargo rdme --check || echo "failed for ${dir}"); cd ..; done + for dir in rustsat tools cadical kissat minisat glucose ipasir capi; do cd ${dir} && (cargo rdme --check || echo "failed for ${dir}"); cd ..; done diff --git a/.github/workflows/rustsat.yml b/.github/workflows/rustsat.yml index dba4bfda..8cef835a 100644 --- a/.github/workflows/rustsat.yml +++ b/.github/workflows/rustsat.yml @@ -48,16 +48,3 @@ jobs: run: maturin build -m rustsat/Cargo.toml && pip install --no-index --find-links target/wheels/ rustsat - name: Test stubs run: stubtest --mypy-config-file rustsat/pyproject.toml --allowlist rustsat/stubtest-allowlist.txt rustsat - - cbindgen: - name: Test generated C header - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - name: Install stable toolchain - uses: dtolnay/rust-toolchain@stable - - name: Check C header - run: | - cargo install cbindgen - cbindgen -c rustsat/cbindgen.toml --crate rustsat -o rustsat/rustsat.h --verify diff --git a/Cargo.toml b/Cargo.toml index 468b0e15..6621b4ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "minisat", "ipasir", "solvertests", + "capi", ] resolver = "2" diff --git a/README.md b/README.md index 084b0c61..7c8222a0 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,6 @@ crate](https://crates.io/crates/rustsat_tools) at `tools/src/bin`. For a bigger example you can look at this [multi-objective optimization solver](https://github.com/chrjabs/scuttle). -For an example of how to use the C-API, see `rustsat/examples/capi*.cpp`. -Similarly, for an example of using the Python API, see `rustsat/examples/pyapi*.py`. - ## Python Bindings diff --git a/capi/Cargo.toml b/capi/Cargo.toml new file mode 100644 index 00000000..8f97933a --- /dev/null +++ b/capi/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "rustsat-capi" +version = "0.4.3" +edition = "2021" +authors = ["Christoph Jabs "] +license = "MIT" +description = "C-API for the RustSAT library" +keywords = ["sat", "satisfiability", "encodings"] + +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustsat = { version = "0.4.3", path = "../rustsat", default-features = false, features = [ + "internals", +] } + +[build-dependencies] +cbindgen = "0.26.0" + +[dev-dependencies] +inline-c = "0.1.7" + +[lib] +crate-type = ["staticlib"] diff --git a/capi/README.md b/capi/README.md new file mode 100644 index 00000000..e3a23e8e --- /dev/null +++ b/capi/README.md @@ -0,0 +1,17 @@ +[![Build & Test](https://github.com/chrjabs/rustsat/actions/workflows/capi.yml/badge.svg)](https://github.com/chrjabs/rustsat/actions/workflows/capi.yml) +[![License](https://img.shields.io/crates/l/rustsat)](./LICENSE) + + + +# C-API For RustSAT + +In the C-API, literals are represented as IPASIR literals. + +This is the C-API for RustSAT. Currently this API is very minimal and not +the focus of this project. For now, only the API of certain encodings is +available. + +For the API itself, see `rustsat.h`. To use RustSAT from an external project, +build this crate and link against `librustsat.a` + + diff --git a/rustsat/build.rs b/capi/build.rs similarity index 65% rename from rustsat/build.rs rename to capi/build.rs index f032cf89..7fd6a694 100644 --- a/rustsat/build.rs +++ b/capi/build.rs @@ -8,20 +8,6 @@ fn main() { return; } - #[cfg(feature = "ipasir")] - { - // Link to custom IPASIR solver - // Uncomment and modify this for linking to your static library - // The name of the library should be _without_ the prefix 'lib' and the suffix '.a' - //println!("cargo:rustc-link-lib=static="); - //println!("cargo:rustc-link-search="); - // If your IPASIR solver links to the C++ stdlib, uncomment the next four lines - //#[cfg(target_os = "macos")] - //println!("cargo:rustc-flags=-l dylib=c++"); - //#[cfg(not(target_os = "macos"))] - //println!("cargo:rustc-flags=-l dylib=stdc++"); - } - let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); // Generate C-API header @@ -44,21 +30,17 @@ fn main() { #[cfg(feature = "pyapi")] let python_lib = pyo3_build_config::get().lib_name.as_ref().unwrap(); - let cflags = format!("cargo:rustc-env=INLINE_C_RS_CFLAGS=-I{I} -L{L} -lrustsat -D_DEBUG -D_CRT_SECURE_NO_WARNINGS", I=include_dir, L=ld_dir.to_string_lossy()); + let cflags = format!("cargo:rustc-env=INLINE_C_RS_CFLAGS=-I{I} -L{L} -lrustsat_capi -D_DEBUG -D_CRT_SECURE_NO_WARNINGS", I=include_dir, L=ld_dir.to_string_lossy()); #[cfg(feature = "compression")] let cflags = format!("{} -llzma -lbz2", cflags); - #[cfg(feature = "pyapi")] - let cflags = format!("{} -l{}", cflags, python_lib); println!("{}", cflags); let ldflags = format!( - "cargo:rustc-env=INLINE_C_RS_LDFLAGS={L}/librustsat.a", + "cargo:rustc-env=INLINE_C_RS_LDFLAGS={L}/librustsat_capi.a", L = ld_dir.to_string_lossy() ); #[cfg(feature = "compression")] let ldflags = format!("{} -llzma -lbz2", ldflags); - #[cfg(feature = "pyapi")] - let ldflags = format!("{} -l{}", ldflags, python_lib); println!("{}", ldflags); } diff --git a/rustsat/cbindgen.toml b/capi/cbindgen.toml similarity index 91% rename from rustsat/cbindgen.toml rename to capi/cbindgen.toml index ae4f16ce..63f6d464 100644 --- a/rustsat/cbindgen.toml +++ b/capi/cbindgen.toml @@ -5,11 +5,9 @@ # for detailed documentation of every option here. - language = "C" - ############## Options for Wrapping the Contents of the Header ################# # header = "/* Text to put at the beginning of the generated file. Probably a license. */" @@ -17,7 +15,7 @@ language = "C" include_guard = "rustsat_h" # pragma_once = true # autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" -include_version = true +include_version = false namespace = "RustSAT" namespaces = [] using_namespaces = [] @@ -27,8 +25,6 @@ no_includes = false after_includes = "" - - ############################ Code Style Options ################################ braces = "SameLine" @@ -37,39 +33,33 @@ tab_width = 2 documentation = true documentation_style = "auto" documentation_length = "full" -line_endings = "LF" # also "CR", "CRLF", "Native" - - +line_endings = "LF" # also "CR", "CRLF", "Native" ############################# Codegen Options ################################## style = "both" -sort_by = "Name" # default for `fn.sort_by` and `const.sort_by` +sort_by = "Name" # default for `fn.sort_by` and `const.sort_by` usize_is_size_t = true cpp_compat = true - [defines] # "target_os = freebsd" = "DEFINE_FREEBSD" # "feature = serde" = "DEFINE_SERDE" - [export] -include = [] +include = ["DbTotalizer", "DynamicPolyWatchdog"] exclude = [] # prefix = "CAPI_" item_types = [] renaming_overrides_prefixing = false - [export.rename] - [export.body] @@ -88,8 +78,6 @@ args = "auto" sort_by = "Name" - - [struct] rename_fields = "None" # must_use = "MUST_USE_STRUCT" @@ -104,8 +92,6 @@ derive_gt = false derive_gte = false - - [enum] rename_variants = "None" # must_use = "MUST_USE_ENUM" @@ -123,35 +109,26 @@ enum_class = true private_default_tagged_enum_constructor = false - - [const] allow_static_const = true allow_constexpr = false sort_by = "Name" - - [macro_expansion] bitflags = false - - - - ############## Options for How Your Rust library Should Be Parsed ############## [parse] -parse_deps = false -# include = [] +parse_deps = true +include = ["rustsat"] exclude = [] clean = false extra_bindings = [] - [parse.expand] crates = [] all_features = false diff --git a/rustsat/examples/capi-ipasir.cpp b/capi/examples/capi-ipasir.cpp similarity index 100% rename from rustsat/examples/capi-ipasir.cpp rename to capi/examples/capi-ipasir.cpp diff --git a/rustsat/examples/capi.cpp b/capi/examples/capi.cpp similarity index 100% rename from rustsat/examples/capi.cpp rename to capi/examples/capi.cpp diff --git a/rustsat/rustsat.h b/capi/rustsat.h similarity index 99% rename from rustsat/rustsat.h rename to capi/rustsat.h index bbee73d7..86c815e4 100644 --- a/rustsat/rustsat.h +++ b/capi/rustsat.h @@ -1,8 +1,6 @@ #ifndef rustsat_h #define rustsat_h -/* Generated with cbindgen:0.26.0 */ - #include #include #include diff --git a/rustsat/src/capi.rs b/capi/src/lib.rs similarity index 97% rename from rustsat/src/capi.rs rename to capi/src/lib.rs index 6cb3e63f..095fcb7d 100644 --- a/rustsat/src/capi.rs +++ b/capi/src/lib.rs @@ -2,16 +2,18 @@ //! //! In the C-API, literals are represented as IPASIR literals. //! -//! This is the C-API for RustSAT. Currently this API is very minimal and not -//! the focus of this project. For now, only the API of certain encodings is -//! available. +//! This is the C-API for RustSAT. Currently this API is very minimal and not the focus of this +//! project. For now, only the API of certain encodings is available. +//! +//! For the API itself, see `rustsat.h`. To use RustSAT from an external project, build this crate +//! and link against `librustsat.a` (produced by `cargo` in `target/release`). pub mod encodings { //! # C-API For Encodings use std::ffi::{c_int, c_void}; - use crate::{ + use rustsat::{ encodings::{self, CollectClauses}, instances::ManageVars, types::{Clause, Var}, @@ -129,7 +131,7 @@ pub mod encodings { use std::ffi::{c_int, c_void}; - use crate::{ + use rustsat::{ encodings::card::{BoundUpper, BoundUpperIncremental, DbTotalizer}, types::Lit, }; @@ -286,7 +288,7 @@ pub mod encodings { use std::ffi::{c_int, c_void}; - use crate::{ + use rustsat::{ encodings::pb::{BoundUpper, BoundUpperIncremental, DynamicPolyWatchdog}, types::Lit, }; @@ -314,16 +316,16 @@ pub mod encodings { weight: usize, ) -> MaybeError { let mut boxed = unsafe { Box::from_raw(dpw) }; - if boxed.structure.is_some() { - return MaybeError::InvalidState; - } - boxed.in_lits.insert( + let res = boxed.add_input( Lit::from_ipasir(lit).expect("invalid IPASIR literal"), weight, ); - boxed.weight_sum += weight; Box::into_raw(boxed); - MaybeError::Ok + if res.is_ok() { + MaybeError::Ok + } else { + MaybeError::InvalidState + } } /// Lazily builds the _change in_ pseudo-boolean encoding to enable diff --git a/release-plz.toml b/release-plz.toml index 5a6295d1..efa1dca1 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -35,3 +35,8 @@ git_release_enable = false name = "rustsat-solvertests" release = false git_release_enable = false + +[[package]] +name = "rustsat-capi" +release = false +git_release_enable = false diff --git a/rustsat/Cargo.toml b/rustsat/Cargo.toml index c07f4e87..0592a768 100644 --- a/rustsat/Cargo.toml +++ b/rustsat/Cargo.toml @@ -10,8 +10,6 @@ repository = "https://github.com/chrjabs/rustsat" readme = "README.md" rust-version = "1.66.1" -build = "build.rs" - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -34,11 +32,9 @@ pyo3 = { version = "0.21.0", optional = true, features = [ ] } [build-dependencies] -cbindgen = "0.26.0" pyo3-build-config = { version = "0.21.0", optional = true } [dev-dependencies] -inline-c = "0.1.7" rustsat-minisat = { version = "0.2", path = "../minisat" } rustsat-tools = { version = "0.2", path = "../tools" } @@ -55,7 +51,7 @@ pyapi = ["dep:pyo3", "dep:pyo3-build-config"] all = ["multiopt", "compression", "rand", "fxhash"] [lib] -crate-type = ["lib", "staticlib", "cdylib"] +crate-type = ["lib", "cdylib"] [package.metadata.docs.rs] features = ["all"] diff --git a/rustsat/src/encodings/pb/dpw.rs b/rustsat/src/encodings/pb/dpw.rs index 14e70099..6c735408 100644 --- a/rustsat/src/encodings/pb/dpw.rs +++ b/rustsat/src/encodings/pb/dpw.rs @@ -53,11 +53,11 @@ use pyo3::prelude::*; #[derive(Default)] pub struct DynamicPolyWatchdog { /// Input literals and weights for the encoding - pub(crate) in_lits: RsHashMap, + in_lits: RsHashMap, /// The encoding root and the tares - pub(crate) structure: Option, + structure: Option, /// Sum of all input weight - pub(crate) weight_sum: usize, + weight_sum: usize, /// The number of variables n_vars: u32, /// The number of clauses @@ -74,6 +74,24 @@ impl DynamicPolyWatchdog { None => 0, } } + + /// Helper for the C-API to add input literals to an already existing object. Errors if the + /// object is already encoded. + #[cfg(feature = "internals")] + pub fn add_input(&mut self, lit: Lit, weight: usize) -> Result<(), crate::NotAllowed> { + if self.structure.is_some() { + return Err(crate::NotAllowed( + "cannot add inputs after building the encoding", + )); + } + if let Some(lweight) = self.in_lits.get_mut(&lit) { + *lweight += weight; + } else { + self.in_lits.insert(lit, weight); + } + self.weight_sum += weight; + Ok(()) + } } #[cfg_attr(feature = "internals", visibility::make(pub))] diff --git a/rustsat/src/lib.rs b/rustsat/src/lib.rs index 71d22936..1a8902b2 100644 --- a/rustsat/src/lib.rs +++ b/rustsat/src/lib.rs @@ -61,24 +61,33 @@ //! crate](https://crates.io/crates/rustsat_tools) at `tools/src/bin`. For a bigger //! example you can look at this [multi-objective optimization //! solver](https://github.com/chrjabs/scuttle). -//! -//! For an example of how to use the C-API, see `rustsat/examples/capi*.cpp`. -//! Similarly, for an example of using the Python API, see `rustsat/examples/pyapi*.py`. #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(feature = "bench", feature(test))] +use core::fmt; + +use thiserror::Error; + pub mod encodings; pub mod instances; pub mod solvers; pub mod types; -mod capi; #[cfg(feature = "pyapi")] pub mod pyapi; pub mod utils; +#[derive(Error, Debug)] +pub struct NotAllowed(&'static str); + +impl fmt::Display for NotAllowed { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "action not allowed: {}", self.0) + } +} + #[cfg(feature = "bench")] #[cfg(test)] mod bench; diff --git a/scripts/sync-versions.sh b/scripts/sync-versions.sh new file mode 100755 index 00000000..50ed7831 --- /dev/null +++ b/scripts/sync-versions.sh @@ -0,0 +1,7 @@ +#!/usr/bin/bash + +VERSION=$(grep '^version = "[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+"' rustsat/Cargo.toml | cut -d '"' -f2) +SED_PATTERN="s/^version = \"[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+\"$/version = \"${VERSION}\"/g" + +# sync C-API version +sed -e "${SED_PATTERN}" -i capi/Cargo.toml From bd5cbea23b8d1d9b36956b4d0d3abc97d782eae4 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 9 Apr 2024 15:20:11 +0300 Subject: [PATCH 03/56] refactor: factor out Python API factor out Python API into separate crate and tooling around that --- .github/workflows/docs.yml | 2 +- .github/workflows/pages.yml | 4 +- .github/workflows/pyapi.yml | 64 +++- .github/workflows/rustsat.yml | 16 - .gitignore | 1 + Cargo.toml | 1 + pyapi/Cargo.toml | 28 ++ pyapi/README.md | 21 ++ pyapi/build.rs | 3 + {rustsat => pyapi}/examples/pyapi-dpw.py | 2 +- {rustsat => pyapi}/pyproject.toml | 3 - {rustsat => pyapi}/rustsat/__init__.py | 0 {rustsat => pyapi}/rustsat/__init__.pyi | 2 +- .../rustsat/encodings/__init__.py | 0 .../rustsat/encodings/__init__.pyi | 0 {rustsat => pyapi}/rustsat/py.typed | 0 pyapi/src/encodings.rs | 252 ++++++++++++++++ pyapi/src/instances.rs | 281 ++++++++++++++++++ rustsat/src/pyapi.rs => pyapi/src/lib.rs | 45 +-- pyapi/src/types.rs | 244 +++++++++++++++ {rustsat => pyapi}/stubtest-allowlist.txt | 0 release-plz.toml | 5 + rustsat/Cargo.toml | 12 - rustsat/src/encodings.rs | 12 - rustsat/src/encodings/card/dbtotalizer.rs | 66 ---- rustsat/src/encodings/pb/dbgte.rs | 66 ---- rustsat/src/encodings/pb/dpw.rs | 60 ---- rustsat/src/instances.rs | 27 -- rustsat/src/instances/sat.rs | 246 ++------------- rustsat/src/lib.rs | 3 - rustsat/src/types.rs | 50 ---- rustsat/src/types/constraints.rs | 222 +++----------- scripts/sync-versions.sh | 2 + 33 files changed, 980 insertions(+), 760 deletions(-) create mode 100644 pyapi/Cargo.toml create mode 100644 pyapi/README.md create mode 100644 pyapi/build.rs rename {rustsat => pyapi}/examples/pyapi-dpw.py (97%) rename {rustsat => pyapi}/pyproject.toml (77%) rename {rustsat => pyapi}/rustsat/__init__.py (100%) rename {rustsat => pyapi}/rustsat/__init__.pyi (97%) rename {rustsat => pyapi}/rustsat/encodings/__init__.py (100%) rename {rustsat => pyapi}/rustsat/encodings/__init__.pyi (100%) rename {rustsat => pyapi}/rustsat/py.typed (100%) create mode 100644 pyapi/src/encodings.rs create mode 100644 pyapi/src/instances.rs rename rustsat/src/pyapi.rs => pyapi/src/lib.rs (52%) create mode 100644 pyapi/src/types.rs rename {rustsat => pyapi}/stubtest-allowlist.txt (100%) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ac0db713..6e9faf3e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -24,4 +24,4 @@ jobs: - name: Check READMEs run: | cargo install cargo-rdme - for dir in rustsat tools cadical kissat minisat glucose ipasir capi; do cd ${dir} && (cargo rdme --check || echo "failed for ${dir}"); cd ..; done + for dir in rustsat tools cadical kissat minisat glucose ipasir capi pyapi; do cd ${dir} && (cargo rdme --check || echo "failed for ${dir}"); cd ..; done diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 44e91e48..4e712a18 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -32,9 +32,9 @@ jobs: - name: Build Python package uses: PyO3/maturin-action@v1 with: - args: -i python --manifest-path rustsat/Cargo.toml + args: -i python --manifest-path pyapi/Cargo.toml - name: Install Python package - run: pip install target/wheels/rustsat*.whl + run: pip install --no-index --find-links target/wheels/ rustsat - name: Build Python API docs run: pip install pdoc && pdoc -o _site/pyapi/ rustsat - name: Upload artifact diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index c78d1f76..1b8cdb6a 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -1,7 +1,7 @@ # This file is autogenerated by maturin v1.3.2 # To update, run # -# maturin generate-ci -m rustsat/Cargo.toml github +# maturin generate-ci -m pyapi/Cargo.toml github # name: Python Build @@ -19,6 +19,44 @@ permissions: contents: read jobs: + build-test: + name: Build and test + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Install stable toolchain + uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + shared-key: "build-test" + - name: Cargo build + run: cargo build -p rustsat-pyapi --verbose + env: + CMAKE_BUILD_PARALLEL_LEVEL: ${{ fromJSON('["", "4"]')[matrix.os == 'macos-latest'] }} + - name: Cargo test + run: cargo test -p rustsat-pyapi --verbose + env: + CMAKE_BUILD_PARALLEL_LEVEL: ${{ fromJSON('["", "4"]')[matrix.os == 'macos-latest'] }} + - name: Build Python package + uses: PyO3/maturin-action@v1 + with: + args: -i python --manifest-path pyapi/Cargo.toml + - name: Install Python package + run: pip install --no-index --find-links target/wheels/ rustsat + - name: Test PyAPI example + run: python pyapi/examples/pyapi-dpw.py + + version: + name: Ensure Python API crate version is in sync + runs-on: ubuntu-latest + steps: + - name: Check + run: "[ \"$(grep '^version = ' rustsat/Cargo.toml)\" = \"$(grep '^version = ' pyapi/Cargo.toml)\" ]" + linux: runs-on: ubuntu-latest strategy: @@ -33,7 +71,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist --manifest-path rustsat/Cargo.toml + args: --release --out dist --manifest-path pyapi/Cargo.toml sccache: 'true' manylinux: auto - name: Upload wheels @@ -42,6 +80,22 @@ jobs: name: wheels-linux-${{ matrix.target }} path: dist + pystubs: + name: Test python stubs + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - name: Install maturin from PyPI + uses: install-pinned/maturin@dfebcaa782a69944b584ec164e97fbbd09885352 + - name: Install mypy from PyPI + uses: install-pinned/mypy@c2223951641cbb406fa8526d08f0690899f130e4 + - name: Install python project + run: maturin build -m pyapi/Cargo.toml && pip install --no-index --find-links target/wheels/ rustsat + - name: Test stubs + run: stubtest --mypy-config-file pyapi/pyproject.toml --allowlist pyapi/stubtest-allowlist.txt rustsat + windows: runs-on: windows-latest strategy: @@ -57,7 +111,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist --manifest-path rustsat/Cargo.toml + args: --release --out dist --manifest-path pyapi/Cargo.toml sccache: 'true' - name: Upload wheels uses: actions/upload-artifact@v4 @@ -79,7 +133,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist --manifest-path rustsat/Cargo.toml + args: --release --out dist --manifest-path pyapi/Cargo.toml sccache: 'true' - name: Upload wheels uses: actions/upload-artifact@v4 @@ -95,7 +149,7 @@ jobs: uses: PyO3/maturin-action@v1 with: command: sdist - args: --out dist --manifest-path rustsat/Cargo.toml + args: --out dist --manifest-path pyapi/Cargo.toml - name: Upload sdist uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/rustsat.yml b/.github/workflows/rustsat.yml index 8cef835a..ec6be7a6 100644 --- a/.github/workflows/rustsat.yml +++ b/.github/workflows/rustsat.yml @@ -32,19 +32,3 @@ jobs: run: cargo test -p rustsat --verbose --features=all env: CMAKE_BUILD_PARALLEL_LEVEL: ${{ fromJSON('["", "4"]')[matrix.os == 'macos-latest'] }} - - pystubs: - name: Test python stubs - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - uses: Swatinem/rust-cache@v2 - - name: Install maturin from PyPI - uses: install-pinned/maturin@dfebcaa782a69944b584ec164e97fbbd09885352 - - name: Install mypy from PyPI - uses: install-pinned/mypy@c2223951641cbb406fa8526d08f0690899f130e4 - - name: Install python project - run: maturin build -m rustsat/Cargo.toml && pip install --no-index --find-links target/wheels/ rustsat - - name: Test stubs - run: stubtest --mypy-config-file rustsat/pyproject.toml --allowlist rustsat/stubtest-allowlist.txt rustsat diff --git a/.gitignore b/.gitignore index 9f0fd29e..deec03b3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ **/*.o **/*.out +**/*.so rustsat/pydocs/ **/__pycache__/ diff --git a/Cargo.toml b/Cargo.toml index 6621b4ad..d14392eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "ipasir", "solvertests", "capi", + "pyapi", ] resolver = "2" diff --git a/pyapi/Cargo.toml b/pyapi/Cargo.toml new file mode 100644 index 00000000..793ae8b6 --- /dev/null +++ b/pyapi/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "rustsat-pyapi" +version = "0.4.3" +edition = "2021" +authors = ["Christoph Jabs "] +license = "MIT" +description = "This library aims to provide implementations of elements commonly used in the development on software in the area of satisfiability solving. The focus of the library is to provide as much ease of use without giving up on performance." +keywords = ["sat", "satisfiability", "encodings"] +repository = "https://github.com/chrjabs/rustsat" +readme = "README.md" + +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +pyo3 = { version = "0.21.1", features = [ + "extension-module", + "abi3", + "abi3-py37", +] } + +[build-dependencies] +pyo3-build-config = { version = "0.21.1" } + +[lib] +crate-type = ["cdylib"] diff --git a/pyapi/README.md b/pyapi/README.md new file mode 100644 index 00000000..6c349a66 --- /dev/null +++ b/pyapi/README.md @@ -0,0 +1,21 @@ +[![Build & Test](https://github.com/chrjabs/rustsat/actions/workflows/pyapi.yml/badge.svg)](https://github.com/chrjabs/rustsat/actions/workflows/pyapi.yml) +[![PyPI](https://img.shields.io/pypi/v/rustsat)](https://pypi.org/project/rustsat) +[![License](https://img.shields.io/crates/l/rustsat)](./LICENSE) + + + +# Python API for RustSAT + +This is the Python API for RustSAT. Currently this API is very minimal and +not the focus of this project. For now, only the API of certain encodings is +available. + +## Installation + +The Python bindings can be installed from [PyPI](https://pypi.org/project/rustsat/). + +## Documentation + +Documentation for this API can be found [here](https://christophjabs.info/rustsat/pyapi/). + + diff --git a/pyapi/build.rs b/pyapi/build.rs new file mode 100644 index 00000000..dace4a9b --- /dev/null +++ b/pyapi/build.rs @@ -0,0 +1,3 @@ +fn main() { + pyo3_build_config::add_extension_module_link_args(); +} diff --git a/rustsat/examples/pyapi-dpw.py b/pyapi/examples/pyapi-dpw.py similarity index 97% rename from rustsat/examples/pyapi-dpw.py rename to pyapi/examples/pyapi-dpw.py index a41cf743..cd1e02d1 100644 --- a/rustsat/examples/pyapi-dpw.py +++ b/pyapi/examples/pyapi-dpw.py @@ -13,7 +13,7 @@ # Getting unused variables is handled by a VarManager. Create one that has 5 # variables already used. -vm = VarManager.used(5) +vm = VarManager(n_used = 5) dpw = Dpw(input_lits) diff --git a/rustsat/pyproject.toml b/pyapi/pyproject.toml similarity index 77% rename from rustsat/pyproject.toml rename to pyapi/pyproject.toml index 1343e147..9a983bf4 100644 --- a/rustsat/pyproject.toml +++ b/pyapi/pyproject.toml @@ -5,6 +5,3 @@ requires-python = ">=3.7" [build-system] requires = ["maturin>=1.0,<2.0"] build-backend = "maturin" - -[tool.maturin] -features = ["pyapi"] diff --git a/rustsat/rustsat/__init__.py b/pyapi/rustsat/__init__.py similarity index 100% rename from rustsat/rustsat/__init__.py rename to pyapi/rustsat/__init__.py diff --git a/rustsat/rustsat/__init__.pyi b/pyapi/rustsat/__init__.pyi similarity index 97% rename from rustsat/rustsat/__init__.pyi rename to pyapi/rustsat/__init__.pyi index f2c6c652..dc9cf6b2 100644 --- a/rustsat/rustsat/__init__.pyi +++ b/pyapi/rustsat/__init__.pyi @@ -37,4 +37,4 @@ class VarManager: def __new__(cls, n_used: int = 0) -> VarManager: ... def increase_used(self, n_used: int) -> None: ... def new_var(self) -> int: ... - def n_used(self) -> int: ... \ No newline at end of file + def n_used(self) -> int: ... diff --git a/rustsat/rustsat/encodings/__init__.py b/pyapi/rustsat/encodings/__init__.py similarity index 100% rename from rustsat/rustsat/encodings/__init__.py rename to pyapi/rustsat/encodings/__init__.py diff --git a/rustsat/rustsat/encodings/__init__.pyi b/pyapi/rustsat/encodings/__init__.pyi similarity index 100% rename from rustsat/rustsat/encodings/__init__.pyi rename to pyapi/rustsat/encodings/__init__.pyi diff --git a/rustsat/rustsat/py.typed b/pyapi/rustsat/py.typed similarity index 100% rename from rustsat/rustsat/py.typed rename to pyapi/rustsat/py.typed diff --git a/pyapi/src/encodings.rs b/pyapi/src/encodings.rs new file mode 100644 index 00000000..e7f1bba4 --- /dev/null +++ b/pyapi/src/encodings.rs @@ -0,0 +1,252 @@ +//! # Python API for RustSAT Encodings + +use pyo3::prelude::*; + +use rustsat::{ + encodings::{ + card::{ + BoundUpper as CardBU, BoundUpperIncremental as CardBUI, DbTotalizer, + Encode as CardEncode, + }, + pb::{ + BoundUpper as PbBU, BoundUpperIncremental as PbBUI, DbGte, + DynamicPolyWatchdog as RsDpw, Encode as PbEncode, + }, + EncodeStats, Error, + }, + instances::{BasicVarManager, Cnf as RsCnf}, + types::Lit as RsLit, +}; + +use crate::{ + instances::{Cnf, VarManager}, + types::Lit, +}; + +fn convert_error(err: Error) -> PyErr { + match err { + Error::NotEncoded => { + pyo3::exceptions::PyRuntimeError::new_err("not encoded to enforce bound") + } + Error::Unsat => pyo3::exceptions::PyValueError::new_err("encoding is unsat"), + } +} + +/// Implementation of the binary adder tree totalizer encoding \[1\]. +/// The implementation is incremental as extended in \[2\]. +/// The implementation is based on a node database. +/// For now, this implementation only supports upper bounding. +/// +/// # References +/// +/// - \[1\] Olivier Bailleux and Yacine Boufkhad: _Efficient CNF Encoding of Boolean Cardinality Constraints_, CP 2003. +/// - \[2\] Ruben Martins and Saurabh Joshi and Vasco Manquinho and Ines Lynce: _Incremental Cardinality Constraints for MaxSAT_, CP 2014. +#[pyclass] +#[repr(transparent)] +pub struct Totalizer(DbTotalizer); + +impl From for Totalizer { + fn from(value: DbTotalizer) -> Self { + Self(value) + } +} + +impl From for DbTotalizer { + fn from(value: Totalizer) -> Self { + value.0 + } +} + +#[pymethods] +impl Totalizer { + #[new] + fn new(lits: Vec) -> Self { + let lits: Vec = unsafe { std::mem::transmute(lits) }; + DbTotalizer::from_iter(lits).into() + } + + /// Adds additional input literals to the totalizer + fn extend(&mut self, lits: Vec) { + let lits: Vec = unsafe { std::mem::transmute(lits) }; + self.0.extend(lits) + } + + /// Gets the number of input literals in the encoding + fn n_lits(&self) -> usize { + self.0.n_lits() + } + + /// Gets the number of clauses in the encoding + fn n_clauses(&self) -> usize { + self.0.n_clauses() + } + + /// Gets the number of variables in the encoding + fn n_vars(&self) -> u32 { + self.0.n_vars() + } + + /// Incrementally builds the totalizer encoding to that upper bounds + /// in the range `max_ub..=min_ub` can be enforced. New variables will + /// be taken from `var_manager`. + fn encode_ub(&mut self, max_ub: usize, min_ub: usize, var_manager: &mut VarManager) -> Cnf { + let mut cnf = RsCnf::new(); + let var_manager: &mut BasicVarManager = var_manager.into(); + self.0 + .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager); + cnf.into() + } + + /// Gets assumptions to enforce the given upper bound. Make sure that + /// the required encoding is built first. + fn enforce_ub(&self, ub: usize) -> PyResult> { + let assumps: Vec = + unsafe { std::mem::transmute(self.0.enforce_ub(ub).map_err(convert_error)?) }; + Ok(assumps) + } +} + +/// Implementation of the binary adder tree generalized totalizer encoding +/// \[1\]. The implementation is incremental. The implementation is recursive. +/// This encoding only support upper bounding. Lower bounding can be achieved by +/// negating the input literals. This is implemented in +/// [`super::simulators::Inverted`]. +/// The implementation is based on a node database. +/// +/// # References +/// +/// - \[1\] Saurabh Joshi and Ruben Martins and Vasco Manquinho: _Generalized +/// Totalizer Encoding for Pseudo-Boolean Constraints_, CP 2015. +#[pyclass] +#[repr(transparent)] +pub struct GeneralizedTotalizer(DbGte); + +impl From for GeneralizedTotalizer { + fn from(value: DbGte) -> Self { + Self(value) + } +} + +impl From for DbGte { + fn from(value: GeneralizedTotalizer) -> Self { + value.0 + } +} + +#[pymethods] +impl GeneralizedTotalizer { + #[new] + fn new(lits: Vec<(Lit, usize)>) -> Self { + let lits: Vec<(RsLit, usize)> = unsafe { std::mem::transmute(lits) }; + DbGte::from_iter(lits).into() + } + + /// Adds additional input literals to the generalized totalizer + fn extend(&mut self, lits: Vec<(Lit, usize)>) { + let lits: Vec<(RsLit, usize)> = unsafe { std::mem::transmute(lits) }; + self.0.extend(lits) + } + + /// Gets the sum of weights in the encoding + fn weight_sum(&self) -> usize { + self.0.weight_sum() + } + + /// Gets the number of clauses in the encoding + fn n_clauses(&self) -> usize { + self.0.n_clauses() + } + + /// Gets the number of variables in the encoding + fn n_vars(&self) -> u32 { + self.0.n_vars() + } + + /// Incrementally builds the GTE encoding to that upper bounds + /// in the range `max_ub..=min_ub` can be enforced. New variables will + /// be taken from `var_manager`. + fn encode_ub(&mut self, max_ub: usize, min_ub: usize, var_manager: &mut VarManager) -> Cnf { + let mut cnf = RsCnf::new(); + let var_manager: &mut BasicVarManager = var_manager.into(); + self.0 + .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager); + cnf.into() + } + + /// Gets assumptions to enforce the given upper bound. Make sure that + /// the required encoding is built first. + fn enforce_ub(&self, ub: usize) -> PyResult> { + let assumps = unsafe { std::mem::transmute(self.0.enforce_ub(ub).map_err(convert_error)?) }; + Ok(assumps) + } +} + +/// Implementation of the dynamic polynomial watchdog (DPW) encoding \[1\]. +/// +/// **Note**: +/// This implementation of the DPW encoding only supports incrementally +/// changing the bound, but not adding new input literals. Calling extend after +/// encoding resets the entire encoding and with the next encode and entirely +/// new encoding will be returned. +/// +/// ## References +/// +/// - \[1\] Tobias Paxian and Sven Reimer and Bernd Becker: _Dynamic Polynomial +/// Watchdog Encoding for Solving Weighted MaxSAT_, SAT 2018. +#[pyclass] +#[repr(transparent)] +pub struct DynamicPolyWatchdog(RsDpw); + +impl From for DynamicPolyWatchdog { + fn from(value: RsDpw) -> Self { + Self(value) + } +} + +impl From for RsDpw { + fn from(value: DynamicPolyWatchdog) -> Self { + value.0 + } +} + +#[pymethods] +impl DynamicPolyWatchdog { + #[new] + fn new(lits: Vec<(Lit, usize)>) -> Self { + let lits: Vec<(RsLit, usize)> = unsafe { std::mem::transmute(lits) }; + RsDpw::from_iter(lits).into() + } + + /// Gets the sum of weights in the encoding + fn weight_sum(&self) -> usize { + self.0.weight_sum() + } + + /// Gets the number of clauses in the encoding + fn n_clauses(&self) -> usize { + self.0.n_clauses() + } + + /// Gets the number of variables in the encoding + fn n_vars(&self) -> u32 { + self.0.n_vars() + } + + /// Incrementally builds the DPW encoding to that upper bounds + /// in the range `max_ub..=min_ub` can be enforced. New variables will + /// be taken from `var_manager`. + fn encode_ub(&mut self, max_ub: usize, min_ub: usize, var_manager: &mut VarManager) -> Cnf { + let mut cnf = RsCnf::new(); + let var_manager: &mut BasicVarManager = var_manager.into(); + self.0 + .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager); + cnf.into() + } + + /// Gets assumptions to enforce the given upper bound. Make sure that + /// the required encoding is built first. + fn enforce_ub(&self, ub: usize) -> PyResult> { + let assumps = self.0.enforce_ub(ub).map_err(convert_error)?; + Ok(assumps.into_iter().map(|l| l.into()).collect()) + } +} diff --git a/pyapi/src/instances.rs b/pyapi/src/instances.rs new file mode 100644 index 00000000..f81454ca --- /dev/null +++ b/pyapi/src/instances.rs @@ -0,0 +1,281 @@ +//! # Python API for RustSAT Instance Types + +use pyo3::{ + exceptions::{PyIndexError, PyRuntimeError}, + prelude::*, +}; + +use rustsat::{ + clause, + instances::{BasicVarManager, Cnf as RsCnf, ManageVars}, + types::{Clause as RsClause, Lit as RsLit, Var}, +}; + +use crate::{ + types::{Clause, Lit}, + SingleOrList, SliceOrInt, +}; + +/// Simple counting variable manager +#[pyclass] +#[repr(transparent)] +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct VarManager(BasicVarManager); + +impl From for VarManager { + fn from(value: BasicVarManager) -> Self { + VarManager(value) + } +} + +impl From for BasicVarManager { + fn from(value: VarManager) -> Self { + value.0 + } +} + +impl<'a> From<&'a VarManager> for &'a BasicVarManager { + fn from(value: &'a VarManager) -> Self { + &value.0 + } +} + +impl<'a> From<&'a mut VarManager> for &'a mut BasicVarManager { + fn from(value: &'a mut VarManager) -> Self { + &mut value.0 + } +} + +#[pymethods] +impl VarManager { + /// Creates a new variable manager. Optionally marking `n_used` variables as already used. + #[new] + #[pyo3(text_signature = "(n_used = 0)")] + fn new(n_used: u32) -> Self { + BasicVarManager::from_next_free(Var::new(n_used)).into() + } + + /// Increases the number of variables marked as used + fn increase_used(&mut self, n_used: u32) -> bool { + self.0.increase_next_free(Var::new(n_used)) + } + + /// Gets a new unsued variable + fn new_var(&mut self) -> u32 { + let v = self.0.new_var(); + v.idx32() + 1 + } + + /// Gets the number of used variables + fn n_used(&self) -> u32 { + self.0.n_used() + } +} + +/// Simple type representing a CNF formula. Other than [`SatInstance`], this +/// type only supports clauses and does have an internal variable manager. +#[pyclass] +#[derive(Debug, Clone, Eq, Default)] +pub struct Cnf { + cnf: RsCnf, + modified: bool, +} + +impl From for Cnf { + fn from(value: RsCnf) -> Self { + Self { + cnf: value, + modified: false, + } + } +} + +impl From for RsCnf { + fn from(value: Cnf) -> Self { + value.cnf + } +} + +impl PartialEq for Cnf { + fn eq(&self, other: &Self) -> bool { + self.cnf == other.cnf + } +} + +#[pymethods] +impl Cnf { + /// Adds a clause to the CNF + #[inline] + pub fn add_clause(&mut self, clause: Clause) { + self.modified = true; + self.cnf.add_clause(clause.into()) + } + + /// Adds a unit clause to the CNF + pub fn add_unit(&mut self, unit: Lit) { + self.modified = true; + self.cnf.add_clause(clause![unit.into()]) + } + + /// Adds a binary clause to the CNF + pub fn add_binary(&mut self, lit1: Lit, lit2: Lit) { + self.modified = true; + self.cnf.add_clause(clause![lit1.into(), lit2.into()]) + } + + /// Adds a ternary clause to the CNF + pub fn add_ternary(&mut self, lit1: Lit, lit2: Lit, lit3: Lit) { + self.modified = true; + self.cnf + .add_clause(clause![lit1.into(), lit2.into(), lit3.into()]) + } + + #[new] + #[pyo3(text_signature = "(clauses = [])")] + fn new(clauses: Vec) -> Self { + RsCnf::from_iter(clauses.into_iter().map(Into::::into)).into() + } + + fn __repr__(&self) -> String { + format!("{:?}", self.cnf) + } + + fn __len__(&self) -> usize { + self.cnf.len() + } + + fn __getitem__(&self, idx: SliceOrInt) -> PyResult> { + match idx { + SliceOrInt::Slice(slice) => { + let indices = slice.indices(self.__len__().try_into().unwrap())?; + Ok(SingleOrList::List( + (indices.start as usize..indices.stop as usize) + .step_by(indices.step as usize) + .map(|idx| self.cnf[idx].clone().into()) + .collect(), + )) + } + SliceOrInt::Int(idx) => { + if idx.unsigned_abs() > self.__len__() + || idx >= 0 && idx.unsigned_abs() >= self.__len__() + { + return Err(PyIndexError::new_err("out of bounds")); + } + let idx = if idx >= 0 { + idx.unsigned_abs() + } else { + self.__len__() - idx.unsigned_abs() + }; + Ok(SingleOrList::Single(self.cnf[idx].clone().into())) + } + } + } + + /// Adds an implication of form `a -> b` + fn add_lit_impl_lit(&mut self, a: Lit, b: Lit) { + self.modified = true; + self.cnf.add_lit_impl_lit(a.into(), b.into()) + } + + /// Adds an implication of form `a -> (b1 | b2 | ... | bm)` + fn add_lit_impl_clause(&mut self, a: Lit, b: Vec) { + self.modified = true; + let b: Vec = unsafe { std::mem::transmute(b) }; + self.cnf.add_lit_impl_clause(a.into(), &b) + } + + /// Adds an implication of form `a -> (b1 & b2 & ... & bm)` + fn add_lit_impl_cube(&mut self, a: Lit, b: Vec) { + self.modified = true; + let b: Vec = unsafe { std::mem::transmute(b) }; + self.cnf.add_lit_impl_cube(a.into(), &b) + } + + /// Adds an implication of form `(a1 & a2 & ... & an) -> b` + fn add_cube_impl_lit(&mut self, a: Vec, b: Lit) { + self.modified = true; + let a: Vec = unsafe { std::mem::transmute(a) }; + self.cnf.add_cube_impl_lit(&a, b.into()) + } + + /// Adds an implication of form `(a1 | a2 | ... | an) -> b` + fn add_clause_impl_lit(&mut self, a: Vec, b: Lit) { + self.modified = true; + let a: Vec = unsafe { std::mem::transmute(a) }; + self.cnf.add_clause_impl_lit(&a, b.into()) + } + + /// Adds an implication of form `(a1 & a2 & ... & an) -> (b1 | b2 | ... | bm)` + fn add_cube_impl_clause(&mut self, a: Vec, b: Vec) { + self.modified = true; + let a: Vec = unsafe { std::mem::transmute(a) }; + let b: Vec = unsafe { std::mem::transmute(b) }; + self.cnf.add_cube_impl_clause(&a, &b) + } + + /// Adds an implication of form `(a1 | a2 | ... | an) -> (b1 | b2 | ... | bm)` + fn add_clause_impl_clause(&mut self, a: Vec, b: Vec) { + self.modified = true; + let a: Vec = unsafe { std::mem::transmute(a) }; + let b: Vec = unsafe { std::mem::transmute(b) }; + self.cnf.add_clause_impl_clause(&a, &b) + } + + /// Adds an implication of form `(a1 | a2 | ... | an) -> (b1 & b2 & ... & bm)` + fn add_clause_impl_cube(&mut self, a: Vec, b: Vec) { + self.modified = true; + let a: Vec = unsafe { std::mem::transmute(a) }; + let b: Vec = unsafe { std::mem::transmute(b) }; + self.cnf.add_clause_impl_cube(&a, &b) + } + + /// Adds an implication of form `(a1 & a2 & ... & an) -> (b1 & b2 & ... & bm)` + fn add_cube_impl_cube(&mut self, a: Vec, b: Vec) { + self.modified = true; + let a: Vec = unsafe { std::mem::transmute(a) }; + let b: Vec = unsafe { std::mem::transmute(b) }; + self.cnf.add_cube_impl_cube(&a, &b) + } + + fn __iter__(mut slf: PyRefMut<'_, Self>) -> CnfIter { + slf.modified = false; + CnfIter { + cnf: slf.into(), + index: 0, + } + } + + fn __eq__(&self, other: &Cnf) -> bool { + self == other + } + + fn __ne__(&self, other: &Cnf) -> bool { + self != other + } +} + +#[pyclass] +struct CnfIter { + cnf: Py, + index: usize, +} + +#[pymethods] +impl CnfIter { + fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + slf + } + + fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult> { + if slf.cnf.borrow(slf.py()).modified { + return Err(PyRuntimeError::new_err("cnf modified during iteration")); + } + if slf.index < slf.cnf.borrow(slf.py()).__len__() { + slf.index += 1; + return Ok(Some( + slf.cnf.borrow(slf.py()).cnf[slf.index - 1].clone().into(), + )); + } + Ok(None) + } +} diff --git a/rustsat/src/pyapi.rs b/pyapi/src/lib.rs similarity index 52% rename from rustsat/src/pyapi.rs rename to pyapi/src/lib.rs index c3df8f20..f5d411bf 100644 --- a/rustsat/src/pyapi.rs +++ b/pyapi/src/lib.rs @@ -4,42 +4,23 @@ //! not the focus of this project. For now, only the API of certain encodings is //! available. //! -//! ## Classes +//! ## Installation //! -//! The following classes are available as Python bindings. +//! The Python bindings can be installed from [PyPI](https://pypi.org/project/rustsat/). //! -//! ```bash -//! rustsat -//! ├── Clause -//! ├── Cnf -//! ├── Lit -//! ├── VarManager -//! └── encodings -//! ├── DynamicPolyWatchdog -//! ├── GeneralizedTotalizer -//! └── Totalizer -//! ``` +//! ## Documentation //! -//! They have similar APIs (but reduced functionality) to the following Rust types: -//! -//! | Python Class | Rust Type | -//! | --- | --- | -//! | `rustsat.Clause` | [`crate::types::Clause`] | -//! | `rustsat.Cnf` | [`crate::instances::Cnf`] | -//! | `rustsat.Lit` | [`crate::types::Lit`] | -//! | `rustsat.VarManager` | [`crate::instances::BasicVarManager`] | -//! | `rustsat.encodings.DynamicPolyWatchdog` | [`crate::encodings::pb::DynamicPolyWatchdog`] | -//! | `rustsat.encodings.GeneralizedTotalizer` | [`crate::encodings::pb::GeneralizedTotalizer`] | -//! | `rustsat.encodings.Totalizer` | [`crate::encodings::card::Totalizer`] | +//! Documentation for this API can be found [here](https://christophjabs.info/rustsat/pyapi/). use pyo3::{prelude::*, types::PySlice}; +mod encodings; +mod instances; +mod types; + use crate::{ - encodings::{ - card::DbTotalizer, - pb::{DbGte, DynamicPolyWatchdog}, - }, - instances::{BasicVarManager, Cnf}, + encodings::{DynamicPolyWatchdog, GeneralizedTotalizer, Totalizer}, + instances::{Cnf, VarManager}, types::{Clause, Lit}, }; @@ -72,11 +53,11 @@ fn rustsat(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; - m.add_class::()?; + m.add_class::()?; let encodings = PyModule::new_bound(py, "rustsat.encodings")?; - encodings.add_class::()?; - encodings.add_class::()?; + encodings.add_class::()?; + encodings.add_class::()?; encodings.add_class::()?; m.add("encodings", &encodings)?; diff --git a/pyapi/src/types.rs b/pyapi/src/types.rs new file mode 100644 index 00000000..3686eea4 --- /dev/null +++ b/pyapi/src/types.rs @@ -0,0 +1,244 @@ +//! # Python API for Basic RustSAT Types + +use core::{ffi::c_int, fmt}; + +use pyo3::{ + exceptions::{PyIndexError, PyRuntimeError, PyValueError}, + prelude::*, +}; + +use rustsat::types::{Clause as RsClause, Lit as RsLit}; + +use crate::{SingleOrList, SliceOrInt}; + +/// Type representing literals, possibly negated boolean variables. +/// +/// # Representation in Memory +/// +/// Literal representation is `idx << 1` with the last bit representing +/// whether the literal is negated or not. This way the literal can directly +/// be used to index data structures with the two literals of a variable +/// being close together. +#[pyclass] +#[repr(transparent)] +#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Debug)] +pub struct Lit(RsLit); + +impl From for Lit { + fn from(value: RsLit) -> Self { + Lit(value) + } +} + +impl From for RsLit { + fn from(value: Lit) -> Self { + value.0 + } +} + +impl fmt::Display for Lit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +#[pymethods] +impl Lit { + #[new] + fn new(ipasir: c_int) -> PyResult { + Ok(RsLit::from_ipasir(ipasir) + .map_err(|_| PyValueError::new_err("invalid ipasir lit"))? + .into()) + } + + fn __str__(&self) -> String { + format!("{}", self) + } + + fn __repr__(&self) -> String { + format!("{}", self) + } + + fn __neg__(&self) -> Lit { + Lit(!self.0) + } + + fn __richcmp__(&self, other: &Lit, op: pyo3::basic::CompareOp) -> bool { + op.matches(self.cmp(other)) + } + + fn __hash__(&self) -> u64 { + use std::hash::{Hash, Hasher}; + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + self.hash(&mut hasher); + hasher.finish() + } + + /// Gets the IPASIR/DIMACS representation of the literal + #[allow(clippy::wrong_self_convention)] + fn to_ipasir(&self) -> c_int { + let negated = self.0.is_neg(); + let idx: c_int = (self.0.vidx() + 1) + .try_into() + .expect("variable index too high to fit in c_int"); + if negated { + -idx + } else { + idx + } + } +} + +/// Type representing a clause. +/// Wrapper around a std collection to allow for changing the data structure. +/// Optional clauses as sets will be included in the future. +#[pyclass] +#[derive(Eq, PartialOrd, Ord, Clone, Default)] +pub struct Clause { + cl: RsClause, + modified: bool, +} + +impl From for Clause { + fn from(value: RsClause) -> Self { + Self { + cl: value, + modified: false, + } + } +} + +impl From for RsClause { + fn from(value: Clause) -> Self { + value.cl + } +} + +impl PartialEq for Clause { + fn eq(&self, other: &Self) -> bool { + self.cl == other.cl + } +} + +#[pymethods] +impl Clause { + /// Checks if the clause is a unit clause + #[inline] + pub fn is_unit(&self) -> bool { + self.cl.len() == 1 + } + + /// Checks if the clause is binary + pub fn is_binary(&self) -> bool { + self.cl.len() == 2 + } + + /// Adds a literal to the clause + pub fn add(&mut self, lit: Lit) { + self.modified = true; + self.cl.add(lit.0) + } + + /// Removes the first occurrence of a literal from the clause + /// Returns true if an occurrence was found + pub fn remove(&mut self, lit: &Lit) -> bool { + self.modified = true; + self.cl.remove(&lit.0) + } + + /// Removes all occurrences of a literal from the clause + pub fn remove_thorough(&mut self, lit: &Lit) -> bool { + self.modified = true; + self.cl.remove_thorough(&lit.0) + } + + #[new] + fn new(lits: Vec) -> Self { + let lits: Vec = unsafe { std::mem::transmute(lits) }; + RsClause::from_iter(lits).into() + } + + fn __str__(&self) -> String { + format!("{}", self.cl) + } + + fn __repr__(&self) -> String { + format!("{}", self.cl) + } + + fn __len__(&self) -> usize { + self.cl.len() + } + + fn __getitem__(&self, idx: SliceOrInt) -> PyResult> { + match idx { + SliceOrInt::Slice(slice) => { + let indices = slice.indices(self.__len__().try_into().unwrap())?; + Ok(SingleOrList::List( + (indices.start as usize..indices.stop as usize) + .step_by(indices.step as usize) + .map(|idx| Lit(self.cl[idx])) + .collect(), + )) + } + SliceOrInt::Int(idx) => { + if idx.unsigned_abs() > self.__len__() + || idx >= 0 && idx.unsigned_abs() >= self.__len__() + { + return Err(PyIndexError::new_err("out of bounds")); + } + let idx = if idx >= 0 { + idx.unsigned_abs() + } else { + self.__len__() - idx.unsigned_abs() + }; + Ok(SingleOrList::Single(Lit(self.cl[idx]))) + } + } + } + + fn __iter__(mut slf: PyRefMut<'_, Self>) -> ClauseIter { + slf.modified = false; + ClauseIter { + clause: slf.into(), + index: 0, + } + } + + fn extend(&mut self, lits: Vec) { + let lits: Vec = unsafe { std::mem::transmute(lits) }; + self.cl.extend(lits) + } + + fn __eq__(&self, other: &Clause) -> bool { + self == other + } + + fn __ne__(&self, other: &Clause) -> bool { + self != other + } +} + +#[pyclass] +struct ClauseIter { + clause: Py, + index: usize, +} + +#[pymethods] +impl ClauseIter { + fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + slf + } + + fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult> { + if slf.clause.borrow(slf.py()).modified { + return Err(PyRuntimeError::new_err("clause modified during iteration")); + } + if slf.index < slf.clause.borrow(slf.py()).__len__() { + slf.index += 1; + return Ok(Some(Lit(slf.clause.borrow(slf.py()).cl[slf.index - 1]))); + } + Ok(None) + } +} diff --git a/rustsat/stubtest-allowlist.txt b/pyapi/stubtest-allowlist.txt similarity index 100% rename from rustsat/stubtest-allowlist.txt rename to pyapi/stubtest-allowlist.txt diff --git a/release-plz.toml b/release-plz.toml index efa1dca1..99bf914d 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -40,3 +40,8 @@ git_release_enable = false name = "rustsat-capi" release = false git_release_enable = false + +[[package]] +name = "rustsat-pyapi" +release = false +git_release_enable = false diff --git a/rustsat/Cargo.toml b/rustsat/Cargo.toml index 0592a768..6236bcb7 100644 --- a/rustsat/Cargo.toml +++ b/rustsat/Cargo.toml @@ -25,14 +25,6 @@ rand = { version = "0.8.5", optional = true } visibility = { version = "0.1.0" } anyhow = { version = "1.0.80" } thiserror = { version = "1.0.50" } -pyo3 = { version = "0.21.0", optional = true, features = [ - "extension-module", - "abi3", - "abi3-py37", -] } - -[build-dependencies] -pyo3-build-config = { version = "0.21.0", optional = true } [dev-dependencies] rustsat-minisat = { version = "0.2", path = "../minisat" } @@ -47,12 +39,8 @@ multiopt = ["optimization"] compression = ["dep:bzip2", "dep:flate2", "dep:xz2"] rand = ["dep:rand"] bench = [] -pyapi = ["dep:pyo3", "dep:pyo3-build-config"] all = ["multiopt", "compression", "rand", "fxhash"] -[lib] -crate-type = ["lib", "cdylib"] - [package.metadata.docs.rs] features = ["all"] rustdoc-args = ["--cfg", "docsrs"] diff --git a/rustsat/src/encodings.rs b/rustsat/src/encodings.rs index 15e44f37..9e00e7b0 100644 --- a/rustsat/src/encodings.rs +++ b/rustsat/src/encodings.rs @@ -29,18 +29,6 @@ pub enum Error { Unsat, } -#[cfg(feature = "pyapi")] -impl From for pyo3::PyErr { - fn from(value: Error) -> Self { - match value { - Error::NotEncoded => { - pyo3::exceptions::PyRuntimeError::new_err("not encoded to enforce bound") - } - Error::Unsat => pyo3::exceptions::PyValueError::new_err("encoding is unsat"), - } - } -} - /// Trait for encodings that track statistics. pub trait EncodeStats { /// Gets the number of clauses in the encoding diff --git a/rustsat/src/encodings/card/dbtotalizer.rs b/rustsat/src/encodings/card/dbtotalizer.rs index 41f96cdc..a6f03071 100644 --- a/rustsat/src/encodings/card/dbtotalizer.rs +++ b/rustsat/src/encodings/card/dbtotalizer.rs @@ -21,11 +21,6 @@ use crate::{ use super::{BoundUpper, BoundUpperIncremental, Encode, EncodeIncremental}; -#[cfg(feature = "pyapi")] -use crate::instances::{BasicVarManager, Cnf}; -#[cfg(feature = "pyapi")] -use pyo3::prelude::*; - /// Implementation of the binary adder tree totalizer encoding \[1\]. /// The implementation is incremental as extended in \[2\]. /// The implementation is based on a node database. @@ -35,7 +30,6 @@ use pyo3::prelude::*; /// /// - \[1\] Olivier Bailleux and Yacine Boufkhad: _Efficient CNF Encoding of Boolean Cardinality Constraints_, CP 2003. /// - \[2\] Ruben Martins and Saurabh Joshi and Vasco Manquinho and Ines Lynce: _Incremental Cardinality Constraints for MaxSAT_, CP 2014. -#[cfg_attr(feature = "pyapi", pyclass(name = "Totalizer"))] #[derive(Default)] pub struct DbTotalizer { /// Literals added but not yet in the encoding @@ -1152,66 +1146,6 @@ pub mod referenced { } } -#[cfg(feature = "pyapi")] -#[pymethods] -impl DbTotalizer { - #[new] - fn new(lits: Vec) -> Self { - Self::from(lits) - } - - /// Adds additional input literals to the totalizer - #[pyo3(name = "extend")] - fn py_extend(&mut self, lits: Vec) { - self.extend(lits) - } - - /// Gets the number of input literals in the encoding - #[pyo3(name = "n_lits")] - fn py_n_lits(&self) -> usize { - self.n_lits() - } - - /// Gets the number of clauses in the encoding - #[pyo3(name = "n_clauses")] - fn py_n_clauses(&self) -> usize { - self.n_clauses() - } - - /// Gets the number of variables in the encoding - #[pyo3(name = "n_vars")] - fn py_n_vars(&self) -> u32 { - self.n_vars() - } - - /// Incrementally builds the totalizer encoding to that upper bounds - /// in the range `max_ub..=min_ub` can be enforced. New variables will - /// be taken from `var_manager`. - #[pyo3(name = "encode_ub")] - fn py_encode_ub( - &mut self, - max_ub: usize, - min_ub: usize, - var_manager: &mut BasicVarManager, - ) -> Cnf { - let mut cnf = Cnf::new(); - ::encode_ub_change( - self, - max_ub..=min_ub, - &mut cnf, - var_manager, - ); - cnf - } - - /// Gets assumptions to enforce the given upper bound. Make sure that - /// the required encoding is built first. - #[pyo3(name = "enforce_ub")] - fn py_enforce_ub(&self, ub: usize) -> PyResult> { - Ok(self.enforce_ub(ub)?) - } -} - #[cfg(test)] mod tests { use super::{DbTotalizer, TotDb}; diff --git a/rustsat/src/encodings/pb/dbgte.rs b/rustsat/src/encodings/pb/dbgte.rs index d479c5ea..3b370b9c 100644 --- a/rustsat/src/encodings/pb/dbgte.rs +++ b/rustsat/src/encodings/pb/dbgte.rs @@ -17,11 +17,6 @@ use crate::{ use super::{BoundUpper, BoundUpperIncremental, Encode, EncodeIncremental}; -#[cfg(feature = "pyapi")] -use crate::instances::{BasicVarManager, Cnf}; -#[cfg(feature = "pyapi")] -use pyo3::prelude::*; - /// Implementation of the binary adder tree generalized totalizer encoding /// \[1\]. The implementation is incremental. The implementation is recursive. /// This encoding only support upper bounding. Lower bounding can be achieved by @@ -33,7 +28,6 @@ use pyo3::prelude::*; /// /// - \[1\] Saurabh Joshi and Ruben Martins and Vasco Manquinho: _Generalized /// Totalizer Encoding for Pseudo-Boolean Constraints_, CP 2015. -#[cfg_attr(feature = "pyapi", pyclass(name = "GeneralizedTotalizer"))] #[derive(Default)] pub struct DbGte { /// Input literals and weights not yet in the tree @@ -597,66 +591,6 @@ pub mod referenced { } } -#[cfg(feature = "pyapi")] -#[pymethods] -impl DbGte { - #[new] - fn new(lits: Vec<(Lit, usize)>) -> Self { - Self::from_iter(lits) - } - - /// Adds additional input literals to the generalized totalizer - #[pyo3(name = "extend")] - fn py_extend(&mut self, lits: Vec<(Lit, usize)>) { - self.extend(lits) - } - - /// Gets the sum of weights in the encoding - #[pyo3(name = "weight_sum")] - fn py_weight_sum(&self) -> usize { - self.weight_sum() - } - - /// Gets the number of clauses in the encoding - #[pyo3(name = "n_clauses")] - fn py_n_clauses(&self) -> usize { - self.n_clauses() - } - - /// Gets the number of variables in the encoding - #[pyo3(name = "n_vars")] - fn py_n_vars(&self) -> u32 { - self.n_vars() - } - - /// Incrementally builds the GTE encoding to that upper bounds - /// in the range `max_ub..=min_ub` can be enforced. New variables will - /// be taken from `var_manager`. - #[pyo3(name = "encode_ub")] - fn py_encode_ub( - &mut self, - max_ub: usize, - min_ub: usize, - var_manager: &mut BasicVarManager, - ) -> Cnf { - let mut cnf = Cnf::new(); - ::encode_ub_change( - self, - max_ub..=min_ub, - &mut cnf, - var_manager, - ); - cnf - } - - /// Gets assumptions to enforce the given upper bound. Make sure that - /// the required encoding is built first. - #[pyo3(name = "enforce_ub")] - fn py_enforce_ub(&self, ub: usize) -> PyResult> { - Ok(self.enforce_ub(ub)?) - } -} - #[cfg(test)] mod tests { use super::DbGte; diff --git a/rustsat/src/encodings/pb/dpw.rs b/rustsat/src/encodings/pb/dpw.rs index 6c735408..a8cdb164 100644 --- a/rustsat/src/encodings/pb/dpw.rs +++ b/rustsat/src/encodings/pb/dpw.rs @@ -32,11 +32,6 @@ use crate::{ use super::{BoundUpper, BoundUpperIncremental, Encode, EncodeIncremental}; -#[cfg(feature = "pyapi")] -use crate::instances::{BasicVarManager, Cnf}; -#[cfg(feature = "pyapi")] -use pyo3::prelude::*; - /// Implementation of the dynamic polynomial watchdog (DPW) encoding \[1\]. /// /// **Note**: @@ -49,7 +44,6 @@ use pyo3::prelude::*; /// /// - \[1\] Tobias Paxian and Sven Reimer and Bernd Becker: _Dynamic Polynomial /// Watchdog Encoding for Solving Weighted MaxSAT_, SAT 2018. -#[cfg_attr(feature = "pyapi", pyclass)] #[derive(Default)] pub struct DynamicPolyWatchdog { /// Input literals and weights for the encoding @@ -627,60 +621,6 @@ fn enforce_ub(dpw: &Structure, ub: usize, tot_db: &TotDb) -> Result, Er Ok(assumps) } -#[cfg(feature = "pyapi")] -#[pymethods] -impl DynamicPolyWatchdog { - #[new] - fn new(lits: Vec<(Lit, usize)>) -> Self { - Self::from_iter(lits) - } - - /// Gets the sum of weights in the encoding - #[pyo3(name = "weight_sum")] - fn py_weight_sum(&self) -> usize { - self.weight_sum() - } - - /// Gets the number of clauses in the encoding - #[pyo3(name = "n_clauses")] - fn py_n_clauses(&self) -> usize { - self.n_clauses() - } - - /// Gets the number of variables in the encoding - #[pyo3(name = "n_vars")] - fn py_n_vars(&self) -> u32 { - self.n_vars() - } - - /// Incrementally builds the DPW encoding to that upper bounds - /// in the range `max_ub..=min_ub` can be enforced. New variables will - /// be taken from `var_manager`. - #[pyo3(name = "encode_ub")] - fn py_encode_ub( - &mut self, - max_ub: usize, - min_ub: usize, - var_manager: &mut BasicVarManager, - ) -> Cnf { - let mut cnf = Cnf::new(); - ::encode_ub_change( - self, - max_ub..=min_ub, - &mut cnf, - var_manager, - ); - cnf - } - - /// Gets assumptions to enforce the given upper bound. Make sure that - /// the required encoding is built first. - #[pyo3(name = "enforce_ub")] - fn py_enforce_ub(&self, ub: usize) -> PyResult> { - Ok(self.enforce_ub(ub)?) - } -} - #[cfg(test)] mod tests { use crate::{ diff --git a/rustsat/src/instances.rs b/rustsat/src/instances.rs index 7b71c517..0a4fc47d 100644 --- a/rustsat/src/instances.rs +++ b/rustsat/src/instances.rs @@ -26,9 +26,6 @@ mod multiopt; #[cfg(feature = "multiopt")] pub use multiopt::MultiOptInstance; -#[cfg(feature = "pyapi")] -use pyo3::prelude::*; - pub mod fio; /// Trait for variable managers keeping track of used variables @@ -90,7 +87,6 @@ pub trait ReindexVars: ManageVars { } /// Simple counting variable manager -#[cfg_attr(feature = "pyapi", pyclass(name = "VarManager"))] #[derive(Debug, PartialEq, Eq, Clone)] pub struct BasicVarManager { next_var: Var, @@ -103,29 +99,6 @@ impl BasicVarManager { } } -#[cfg(feature = "pyapi")] -#[pymethods] -impl BasicVarManager { - #[new] - #[pyo3(text_signature = "(n_used = 0)")] - fn new(n_used: u32) -> Self { - BasicVarManager::from_next_free(Var::new(n_used)) - } - - fn increase_used(&mut self, n_used: u32) { - self.next_var = std::cmp::max(self.next_var, Var::new(n_used)); - } - - fn new_var(&mut self) -> u32 { - let v = ::new_var(self); - v.idx32() + 1 - } - - fn n_used(&self) -> u32 { - ::n_used(self) - } -} - impl ManageVars for BasicVarManager { fn new_var(&mut self) -> Var { let v = self.next_var; diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index 3a475205..69e77524 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -12,14 +12,7 @@ use crate::{ }, }; -#[cfg(feature = "pyapi")] -use crate::pyapi::{SingleOrList, SliceOrInt}; use anyhow::Context; -#[cfg(feature = "pyapi")] -use pyo3::{ - exceptions::{PyIndexError, PyRuntimeError}, - prelude::*, -}; use super::{ fio::{self, dimacs::CnfLine}, @@ -28,18 +21,9 @@ use super::{ /// Simple type representing a CNF formula. Other than [`SatInstance`], this /// type only supports clauses and does have an internal variable manager. -#[cfg_attr(feature = "pyapi", pyclass)] -#[derive(Clone, Eq, Default)] +#[derive(Clone, PartialEq, Eq, Default)] pub struct Cnf { pub(super) clauses: Vec, - #[cfg(feature = "pyapi")] - modified: bool, -} - -impl PartialEq for Cnf { - fn eq(&self, other: &Self) -> bool { - self.clauses == other.clauses - } } impl std::fmt::Debug for Cnf { @@ -60,8 +44,6 @@ impl Cnf { pub fn with_capacity(capacity: usize) -> Cnf { Cnf { clauses: Vec::with_capacity(capacity), - #[cfg(feature = "pyapi")] - modified: false, } } @@ -168,8 +150,6 @@ impl Cnf { norm_clauses.dedup(); Self { clauses: norm_clauses, - #[cfg(feature = "pyapi")] - modified: false, } } @@ -178,8 +158,6 @@ impl Cnf { pub fn sanitize(self) -> Self { Self { clauses: self.into_iter().filter_map(|cl| cl.sanitize()).collect(), - #[cfg(feature = "pyapi")] - modified: false, } } @@ -191,6 +169,27 @@ impl Cnf { self.clauses[..].shuffle(&mut rng); self } + + /// Adds a clause to the CNF + #[inline] + pub fn add_clause(&mut self, clause: Clause) { + self.clauses.push(clause); + } + + /// Adds a unit clause to the CNF + pub fn add_unit(&mut self, unit: Lit) { + self.add_clause(clause![unit]) + } + + /// Adds a binary clause to the CNF + pub fn add_binary(&mut self, lit1: Lit, lit2: Lit) { + self.add_clause(clause![lit1, lit2]) + } + + /// Adds a ternary clause to the CNF + pub fn add_ternary(&mut self, lit1: Lit, lit2: Lit, lit3: Lit) { + self.add_clause(clause![lit1, lit2, lit3]) + } } impl CollectClauses for Cnf { @@ -213,8 +212,6 @@ impl FromIterator for Cnf { fn from_iter>(iter: T) -> Self { Self { clauses: iter.into_iter().collect(), - #[cfg(feature = "pyapi")] - modified: false, } } } @@ -242,205 +239,6 @@ impl Index for Cnf { } } -#[cfg_attr(feature = "pyapi", pymethods)] -impl Cnf { - /// Adds a clause to the CNF - #[inline] - pub fn add_clause(&mut self, clause: Clause) { - #[cfg(feature = "pyapi")] - { - self.modified = true; - } - self.clauses.push(clause); - } - - /// Adds a unit clause to the CNF - pub fn add_unit(&mut self, unit: Lit) { - #[cfg(feature = "pyapi")] - { - self.modified = true; - } - self.add_clause(clause![unit]) - } - - /// Adds a binary clause to the CNF - pub fn add_binary(&mut self, lit1: Lit, lit2: Lit) { - #[cfg(feature = "pyapi")] - { - self.modified = true; - } - self.add_clause(clause![lit1, lit2]) - } - - /// Adds a ternary clause to the CNF - pub fn add_ternary(&mut self, lit1: Lit, lit2: Lit, lit3: Lit) { - #[cfg(feature = "pyapi")] - { - self.modified = true; - } - self.add_clause(clause![lit1, lit2, lit3]) - } - - #[cfg(feature = "pyapi")] - #[new] - fn pynew(clauses: Vec) -> Self { - Self::from_iter(clauses) - } - - #[cfg(feature = "pyapi")] - fn __repr__(&self) -> String { - format!("{:?}", self) - } - - #[cfg(feature = "pyapi")] - fn __len__(&self) -> usize { - self.len() - } - - #[cfg(feature = "pyapi")] - fn __getitem__(&self, idx: SliceOrInt) -> PyResult> { - match idx { - SliceOrInt::Slice(slice) => { - let indices = slice.indices(self.len().try_into().unwrap())?; - Ok(SingleOrList::List( - (indices.start as usize..indices.stop as usize) - .step_by(indices.step as usize) - .map(|idx| self[idx].clone()) - .collect(), - )) - } - SliceOrInt::Int(idx) => { - if idx.unsigned_abs() > self.len() || idx >= 0 && idx.unsigned_abs() >= self.len() { - return Err(PyIndexError::new_err("out of bounds")); - } - let idx = if idx >= 0 { - idx.unsigned_abs() - } else { - self.len() - idx.unsigned_abs() - }; - Ok(SingleOrList::Single(self[idx].clone())) - } - } - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `a -> b` - #[pyo3(name = "add_lit_impl_lit")] - fn py_add_lit_impl_lit(&mut self, a: Lit, b: Lit) { - self.modified = true; - self.add_clause(atomics::lit_impl_lit(a, b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `a -> (b1 | b2 | ... | bm)` - #[pyo3(name = "add_lit_impl_clause")] - fn py_add_lit_impl_clause(&mut self, a: Lit, b: Vec) { - self.modified = true; - self.add_clause(atomics::lit_impl_clause(a, &b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `a -> (b1 & b2 & ... & bm)` - #[pyo3(name = "add_lit_impl_cube")] - fn py_add_lit_impl_cube(&mut self, a: Lit, b: Vec) { - self.modified = true; - self.extend(atomics::lit_impl_cube(a, &b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `(a1 & a2 & ... & an) -> b` - #[pyo3(name = "add_cube_impl_lit")] - fn py_add_cube_impl_lit(&mut self, a: Vec, b: Lit) { - self.modified = true; - self.add_clause(atomics::cube_impl_lit(&a, b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `(a1 | a2 | ... | an) -> b` - #[pyo3(name = "add_clause_impl_lit")] - fn py_add_clause_impl_lit(&mut self, a: Vec, b: Lit) { - self.modified = true; - self.extend(atomics::clause_impl_lit(&a, b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `(a1 & a2 & ... & an) -> (b1 | b2 | ... | bm)` - #[pyo3(name = "add_cube_impl_clause")] - fn py_add_cube_impl_clause(&mut self, a: Vec, b: Vec) { - self.modified = true; - self.add_clause(atomics::cube_impl_clause(&a, &b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `(a1 | a2 | ... | an) -> (b1 | b2 | ... | bm)` - #[pyo3(name = "add_clause_impl_clause")] - fn py_add_clause_impl_clause(&mut self, a: Vec, b: Vec) { - self.modified = true; - self.extend(atomics::clause_impl_clause(&a, &b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `(a1 | a2 | ... | an) -> (b1 & b2 & ... & bm)` - #[pyo3(name = "add_clause_impl_cube")] - fn py_add_clause_impl_cube(&mut self, a: Vec, b: Vec) { - self.modified = true; - self.extend(atomics::clause_impl_cube(&a, &b)) - } - - #[cfg(feature = "pyapi")] - /// Adds an implication of form `(a1 & a2 & ... & an) -> (b1 & b2 & ... & bm)` - #[pyo3(name = "add_cube_impl_cube")] - fn py_add_cube_impl_cube(&mut self, a: Vec, b: Vec) { - self.modified = true; - self.extend(atomics::cube_impl_cube(&a, &b)) - } - - #[cfg(feature = "pyapi")] - fn __iter__(mut slf: PyRefMut<'_, Self>) -> CnfIter { - slf.modified = false; - CnfIter { - cnf: slf.into(), - index: 0, - } - } - - #[cfg(feature = "pyapi")] - fn __eq__(&self, other: &Cnf) -> bool { - self == other - } - - #[cfg(feature = "pyapi")] - fn __ne__(&self, other: &Cnf) -> bool { - self != other - } -} - -#[cfg(feature = "pyapi")] -#[pyclass] -struct CnfIter { - cnf: Py, - index: usize, -} - -#[cfg(feature = "pyapi")] -#[pymethods] -impl CnfIter { - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { - slf - } - - fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult> { - if slf.cnf.borrow(slf.py()).modified { - return Err(PyRuntimeError::new_err("cnf modified during iteration")); - } - if slf.index < slf.cnf.borrow(slf.py()).len() { - slf.index += 1; - return Ok(Some(slf.cnf.borrow(slf.py())[slf.index - 1].clone())); - } - return Ok(None); - } -} - /// Type representing a satisfiability instance. Supported constraints are /// clauses, cardinality constraints and pseudo-boolean constraints. #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/rustsat/src/lib.rs b/rustsat/src/lib.rs index 1a8902b2..d05d0f33 100644 --- a/rustsat/src/lib.rs +++ b/rustsat/src/lib.rs @@ -74,9 +74,6 @@ pub mod instances; pub mod solvers; pub mod types; -#[cfg(feature = "pyapi")] -pub mod pyapi; - pub mod utils; #[derive(Error, Debug)] diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index 46c131af..10d13b7a 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -10,9 +10,6 @@ use std::{ use thiserror::Error; -#[cfg(feature = "pyapi")] -use pyo3::{exceptions::PyValueError, prelude::*}; - pub mod constraints; pub use constraints::Clause; @@ -227,7 +224,6 @@ macro_rules! var { /// whether the literal is negated or not. This way the literal can directly /// be used to index data structures with the two literals of a variable /// being close together. -#[cfg_attr(feature = "pyapi", pyclass)] #[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Debug)] #[repr(transparent)] pub struct Lit { @@ -464,52 +460,6 @@ impl fmt::Display for Lit { } } -#[cfg(feature = "pyapi")] -#[pymethods] -impl Lit { - #[new] - fn pynew(ipasir: c_int) -> PyResult { - Self::from_ipasir(ipasir).map_err(|_| PyValueError::new_err("invalid ipasir lit")) - } - - fn __str__(&self) -> String { - format!("{}", self) - } - - fn __repr__(&self) -> String { - format!("{}", self) - } - - fn __neg__(&self) -> Lit { - !*self - } - - fn __richcmp__(&self, other: &Lit, op: pyo3::basic::CompareOp) -> bool { - op.matches(self.cmp(&other)) - } - - fn __hash__(&self) -> u64 { - use std::hash::{Hash, Hasher}; - let mut hasher = std::collections::hash_map::DefaultHasher::new(); - self.hash(&mut hasher); - hasher.finish() - } - - /// Gets the IPASIR/DIMACS representation of the literal - #[pyo3(name = "to_ipasir")] - fn py_ipasir(&self) -> c_int { - let negated = self.is_neg(); - let idx: c_int = (self.vidx() + 1) - .try_into() - .expect("variable index too high to fit in c_int"); - if negated { - -idx - } else { - idx - } - } -} - /// More easily creates literals. Mainly used in tests. /// /// # Examples diff --git a/rustsat/src/types/constraints.rs b/rustsat/src/types/constraints.rs index 5f16e5c8..2856b9b8 100644 --- a/rustsat/src/types/constraints.rs +++ b/rustsat/src/types/constraints.rs @@ -13,29 +13,12 @@ use thiserror::Error; use super::{Assignment, IWLitIter, Lit, LitIter, RsHashSet, TernaryVal, WLitIter}; -#[cfg(feature = "pyapi")] -use crate::pyapi::{SingleOrList, SliceOrInt}; -#[cfg(feature = "pyapi")] -use pyo3::{ - exceptions::{PyIndexError, PyRuntimeError}, - prelude::*, -}; - /// Type representing a clause. /// Wrapper around a std collection to allow for changing the data structure. /// Optional clauses as sets will be included in the future. -#[cfg_attr(feature = "pyapi", pyclass)] -#[derive(Eq, PartialOrd, Ord, Clone, Default)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Default)] pub struct Clause { lits: Vec, - #[cfg(feature = "pyapi")] - modified: bool, -} - -impl PartialEq for Clause { - fn eq(&self, other: &Self) -> bool { - self.lits == other.lits - } } impl std::hash::Hash for Clause { @@ -160,14 +143,54 @@ impl Clause { } false } + + /// Checks if the clause is a unit clause + #[inline] + pub fn is_unit(&self) -> bool { + self.lits.len() == 1 + } + + /// Checks if the clause is binary + pub fn is_binary(&self) -> bool { + self.lits.len() == 2 + } + + /// Adds a literal to the clause + pub fn add(&mut self, lit: Lit) { + self.lits.push(lit) + } + + /// Removes the first occurrence of a literal from the clause + /// Returns true if an occurrence was found + pub fn remove(&mut self, lit: &Lit) -> bool { + for (i, l) in self.lits.iter().enumerate() { + if l == lit { + self.lits.swap_remove(i); + return true; + } + } + false + } + + /// Removes all occurrences of a literal from the clause + pub fn remove_thorough(&mut self, lit: &Lit) -> bool { + let mut idxs = Vec::new(); + for (i, l) in self.lits.iter().enumerate() { + if l == lit { + idxs.push(i); + } + } + for i in idxs.iter().rev() { + self.lits.remove(*i); + } + !idxs.is_empty() + } } impl From<[Lit; N]> for Clause { fn from(value: [Lit; N]) -> Self { Self { lits: Vec::from(value), - #[cfg(feature = "pyapi")] - modified: false, } } } @@ -176,8 +199,6 @@ impl From<&[Lit]> for Clause { fn from(value: &[Lit]) -> Self { Self { lits: Vec::from(value), - #[cfg(feature = "pyapi")] - modified: false, } } } @@ -241,8 +262,6 @@ impl FromIterator for Clause { fn from_iter>(iter: T) -> Self { Self { lits: Vec::from_iter(iter), - #[cfg(feature = "pyapi")] - modified: false, } } } @@ -275,135 +294,6 @@ impl fmt::Debug for Clause { } } -#[cfg_attr(feature = "pyapi", pymethods)] -impl Clause { - /// Checks if the clause is a unit clause - #[inline] - pub fn is_unit(&self) -> bool { - self.lits.len() == 1 - } - - /// Checks if the clause is binary - pub fn is_binary(&self) -> bool { - self.lits.len() == 2 - } - - /// Adds a literal to the clause - pub fn add(&mut self, lit: Lit) { - #[cfg(feature = "pyapi")] - { - self.modified = true; - } - self.lits.push(lit) - } - - /// Removes the first occurrence of a literal from the clause - /// Returns true if an occurrence was found - pub fn remove(&mut self, lit: &Lit) -> bool { - #[cfg(feature = "pyapi")] - { - self.modified = true; - } - for (i, l) in self.lits.iter().enumerate() { - if l == lit { - self.lits.swap_remove(i); - return true; - } - } - false - } - - /// Removes all occurrences of a literal from the clause - pub fn remove_thorough(&mut self, lit: &Lit) -> bool { - #[cfg(feature = "pyapi")] - { - self.modified = true; - } - let mut idxs = Vec::new(); - for (i, l) in self.lits.iter().enumerate() { - if l == lit { - idxs.push(i); - } - } - for i in idxs.iter().rev() { - self.lits.remove(*i); - } - !idxs.is_empty() - } - - #[cfg(feature = "pyapi")] - #[new] - fn pynew(lits: Vec) -> Self { - Self::from_iter(lits) - } - - #[cfg(feature = "pyapi")] - fn __str__(&self) -> String { - format!("{}", self) - } - - #[cfg(feature = "pyapi")] - fn __repr__(&self) -> String { - format!("{}", self) - } - - #[cfg(feature = "pyapi")] - fn __len__(&self) -> usize { - self.len() - } - - #[cfg(feature = "pyapi")] - fn __getitem__(&self, idx: SliceOrInt) -> PyResult> { - match idx { - SliceOrInt::Slice(slice) => { - let indices = slice.indices(self.len().try_into().unwrap())?; - Ok(SingleOrList::List( - (indices.start as usize..indices.stop as usize) - .step_by(indices.step as usize) - .map(|idx| self[idx]) - .collect(), - )) - } - SliceOrInt::Int(idx) => { - if idx.unsigned_abs() > self.len() || idx >= 0 && idx.unsigned_abs() >= self.len() { - return Err(PyIndexError::new_err("out of bounds")); - } - let idx = if idx >= 0 { - idx.unsigned_abs() - } else { - self.len() - idx.unsigned_abs() - }; - Ok(SingleOrList::Single(self[idx])) - } - } - } - - #[cfg(feature = "pyapi")] - fn __iter__(mut slf: PyRefMut<'_, Self>) -> ClauseIter { - slf.modified = false; - ClauseIter { - clause: slf.into(), - index: 0, - } - } - - #[cfg(feature = "pyapi")] - #[pyo3(name = "extend")] - fn py_extend(&mut self, lits: Vec) { - self.extend(lits) - } - - #[cfg(feature = "pyapi")] - fn __eq__(&self, other: &Clause) -> bool { - self == other - } - - #[cfg(feature = "pyapi")] - fn __ne__(&self, other: &Clause) -> bool { - self != other - } -} - #[macro_export] macro_rules! clause { ( $($l:expr),* ) => { @@ -417,32 +307,6 @@ macro_rules! clause { }; } -#[cfg(feature = "pyapi")] -#[pyclass] -struct ClauseIter { - clause: Py, - index: usize, -} - -#[cfg(feature = "pyapi")] -#[pymethods] -impl ClauseIter { - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { - slf - } - - fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult> { - if slf.clause.borrow(slf.py()).modified { - return Err(PyRuntimeError::new_err("clause modified during iteration")); - } - if slf.index < slf.clause.borrow(slf.py()).len() { - slf.index += 1; - return Ok(Some(slf.clause.borrow(slf.py())[slf.index - 1])); - } - return Ok(None); - } -} - /// Type representing a cardinality constraint. #[derive(Hash, Eq, PartialEq, Clone, Debug)] pub enum CardConstraint { diff --git a/scripts/sync-versions.sh b/scripts/sync-versions.sh index 50ed7831..b6079a3b 100755 --- a/scripts/sync-versions.sh +++ b/scripts/sync-versions.sh @@ -5,3 +5,5 @@ SED_PATTERN="s/^version = \"[[:digit:]]\+.[[:digit:]]\+.[[:digit:]]\+\"$/version # sync C-API version sed -e "${SED_PATTERN}" -i capi/Cargo.toml +# sync Python API version +sed -e "${SED_PATTERN}" -i pyapi/Cargo.toml From b636aa2218032c549bd777cb93ba441b8d379c25 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Wed, 10 Apr 2024 14:36:40 +0300 Subject: [PATCH 04/56] refactor: factor out solver unit tests --- cadical/src/lib.rs | 184 +----------------------- glucose/src/core.rs | 99 +------------ glucose/src/simp.rs | 83 +---------- kissat/src/lib.rs | 82 +---------- minisat/src/core.rs | 99 +------------ minisat/src/simp.rs | 99 +------------ solvertests/src/integration.rs | 225 ++++++++++++++++++++++++++++++ solvertests/src/lib.rs | 246 +++++---------------------------- solvertests/src/unit.rs | 218 +++++++++++++++++++++++++++++ 9 files changed, 492 insertions(+), 843 deletions(-) create mode 100644 solvertests/src/integration.rs create mode 100644 solvertests/src/unit.rs diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index 160a64b6..497f0e85 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -797,178 +797,18 @@ impl fmt::Display for Limit { #[cfg(test)] mod test { - use std::{ - sync::{Arc, Mutex}, - thread, - }; - use super::{CaDiCaL, Config, Limit}; use rustsat::{ lit, - solvers::{ - ControlSignal, FreezeVar, Learn, Solve, SolverResult, SolverState, StateError, - Terminate, - }, + solvers::{Solve, SolverState, StateError}, types::TernaryVal, var, }; - #[test] - fn build_destroy() { - let _solver = CaDiCaL::default(); - } - - #[test] - fn build_two() { - let _solver1 = CaDiCaL::default(); - let _solver2 = CaDiCaL::default(); - } - - #[test] - fn tiny_instance_sat() { - let mut solver = CaDiCaL::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - } - - #[test] - fn tiny_instance_unsat() { - let mut solver = CaDiCaL::default(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } - - #[test] - fn tiny_instance_multithreaded_sat() { - let mutex_solver = Arc::new(Mutex::new(CaDiCaL::default())); - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now in another thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now add to solver in other thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - - // Finally, back in the main thread - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } - - #[test] - fn termination_callback() { - let mut solver = CaDiCaL::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_binary(lit![2], !lit![3]).unwrap(); - solver.add_binary(lit![3], !lit![4]).unwrap(); - solver.add_binary(lit![4], !lit![5]).unwrap(); - solver.add_binary(lit![5], !lit![6]).unwrap(); - solver.add_binary(lit![6], !lit![7]).unwrap(); - solver.add_binary(lit![7], !lit![8]).unwrap(); - solver.add_binary(lit![8], !lit![9]).unwrap(); - - solver.attach_terminator(|| ControlSignal::Terminate); - - let ret = solver.solve(); - - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Interrupted), - } - - // Note: since IPASIR doesn't specify _when_ the terminator callback needs - // to be called, there is no guarantee that the callback is actually - // called during solving. This might cause this test to fail with some solvers. - } - - #[test] - fn learner_callback() { - let mut solver = CaDiCaL::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_binary(lit![2], !lit![3]).unwrap(); - solver.add_binary(lit![3], !lit![4]).unwrap(); - solver.add_binary(lit![4], !lit![5]).unwrap(); - solver.add_binary(lit![5], !lit![6]).unwrap(); - solver.add_binary(lit![6], !lit![7]).unwrap(); - solver.add_binary(lit![7], !lit![8]).unwrap(); - solver.add_binary(lit![8], !lit![9]).unwrap(); - solver.add_unit(lit![9]).unwrap(); - solver.add_unit(!lit![0]).unwrap(); - - let mut cl_len = 0; - - solver.attach_learner( - |clause| { - cl_len = clause.len(); - }, - 10, - ); - - let ret = solver.solve(); - - drop(solver); - - // Note: it is hard to create a testing instance on which clause learning - // actually happens and therefore it is not actually tested if the - // callback is called - - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } + rustsat_solvertests::basic_unittests!(CaDiCaL); + rustsat_solvertests::termination_unittests!(CaDiCaL); + rustsat_solvertests::learner_unittests!(CaDiCaL); + rustsat_solvertests::freezing_unittests!(CaDiCaL); #[test] fn configure() { @@ -1019,20 +859,6 @@ mod test { assert_eq!(solver.get_redundant(), 0); assert_eq!(solver.current_lit_val(lit![0]), TernaryVal::DontCare); } - - #[test] - fn freezing() { - let mut solver = CaDiCaL::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - - solver.freeze_var(var![0]).unwrap(); - - assert!(solver.is_frozen(var![0]).unwrap()); - - solver.melt_var(var![0]).unwrap(); - - assert!(!solver.is_frozen(var![0]).unwrap()); - } } mod ffi { diff --git a/glucose/src/core.rs b/glucose/src/core.rs index ea22d76f..566d35d2 100644 --- a/glucose/src/core.rs +++ b/glucose/src/core.rs @@ -323,109 +323,14 @@ impl Drop for Glucose { #[cfg(test)] mod test { - use std::{ - sync::{Arc, Mutex}, - thread, - }; - use super::Glucose; use rustsat::{ lit, - solvers::{Solve, SolveStats, SolverResult}, + solvers::{Solve, SolveStats}, var, }; - #[test] - fn build_destroy() { - let _solver = Glucose::default(); - } - - #[test] - fn build_two() { - let _solver1 = Glucose::default(); - let _solver2 = Glucose::default(); - } - - #[test] - fn tiny_instance_sat() { - let mut solver = Glucose::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - } - - #[test] - fn tiny_instance_multithreaded_sat() { - let mutex_solver = Arc::new(Mutex::new(Glucose::default())); - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now in another thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now add to solver in other thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - - // Finally, back in the main thread - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } - - #[test] - fn tiny_instance_unsat() { - let mut solver = Glucose::default(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } + rustsat_solvertests::basic_unittests!(Glucose); #[test] fn backend_stats() { diff --git a/glucose/src/simp.rs b/glucose/src/simp.rs index f7e54a3b..030e711c 100644 --- a/glucose/src/simp.rs +++ b/glucose/src/simp.rs @@ -352,92 +352,15 @@ impl Drop for Glucose { #[cfg(test)] mod test { - use std::{ - sync::{Arc, Mutex}, - thread, - }; - use super::Glucose; use rustsat::{ lit, - solvers::{Solve, SolveStats, SolverResult}, + solvers::{Solve, SolveStats}, var, }; - #[test] - fn build_destroy() { - let _solver = Glucose::default(); - } - - #[test] - fn build_two() { - let _solver1 = Glucose::default(); - let _solver2 = Glucose::default(); - } - - #[test] - fn tiny_instance_sat() { - let mut solver = Glucose::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - } - - #[test] - fn tiny_instance_unsat() { - let mut solver = Glucose::default(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } - - #[test] - fn tiny_instance_multithreaded_sat() { - let mutex_solver = Arc::new(Mutex::new(Glucose::default())); - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now in another thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Finally, back in the main thread - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - } + rustsat_solvertests::basic_unittests!(Glucose); + rustsat_solvertests::freezing_unittests!(Glucose); #[test] fn backend_stats() { diff --git a/kissat/src/lib.rs b/kissat/src/lib.rs index 424ecf7d..114812d9 100644 --- a/kissat/src/lib.rs +++ b/kissat/src/lib.rs @@ -424,91 +424,13 @@ impl fmt::Display for Limit { #[cfg(test)] mod test { - use std::{ - sync::{Arc, Mutex}, - thread, - }; - use super::{Config, Kissat, Limit}; use rustsat::{ lit, - solvers::{Solve, SolverResult, SolverState, StateError}, - types::{TernaryVal, Var}, + solvers::{Solve, SolverState, StateError}, }; - #[test] - fn build_destroy() { - let _solver = Kissat::default(); - } - - #[test] - fn build_two() { - let _solver1 = Kissat::default(); - let _solver2 = Kissat::default(); - } - - #[test] - fn tiny_instance_sat() { - let mut solver = Kissat::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - } - - #[test] - fn tiny_instance_unsat() { - let mut solver = Kissat::default(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } - - #[test] - fn tiny_instance_multithreaded_sat() { - let mutex_solver = Arc::new(Mutex::new(Kissat::default())); - - { - // Build in one thread - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_unit(lit![0]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - } - - // Now in another thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Finally, back in the main thread - let ret = { - let solver = mutex_solver.lock().unwrap(); - solver.full_solution() - }; - - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res.var_value(Var::new(0)), TernaryVal::True), - } - } + rustsat_solvertests::basic_unittests!(Kissat); #[test] fn configure() { diff --git a/minisat/src/core.rs b/minisat/src/core.rs index 5686f9ca..1589d580 100644 --- a/minisat/src/core.rs +++ b/minisat/src/core.rs @@ -323,109 +323,14 @@ impl Drop for Minisat { #[cfg(test)] mod test { - use std::{ - sync::{Arc, Mutex}, - thread, - }; - use super::Minisat; use rustsat::{ lit, - solvers::{Solve, SolveStats, SolverResult}, + solvers::{Solve, SolveStats}, var, }; - #[test] - fn build_destroy() { - let _solver = Minisat::default(); - } - - #[test] - fn build_two() { - let _solver1 = Minisat::default(); - let _solver2 = Minisat::default(); - } - - #[test] - fn tiny_instance_sat() { - let mut solver = Minisat::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - } - - #[test] - fn tiny_instance_unsat() { - let mut solver = Minisat::default(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } - - #[test] - fn tiny_instance_multithreaded_sat() { - let mutex_solver = Arc::new(Mutex::new(Minisat::default())); - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now in another thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now add to solver in other thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - - // Finally, back in the main thread - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } + rustsat_solvertests::basic_unittests!(Minisat); #[test] fn backend_stats() { diff --git a/minisat/src/simp.rs b/minisat/src/simp.rs index e2a39626..4fc41681 100644 --- a/minisat/src/simp.rs +++ b/minisat/src/simp.rs @@ -352,109 +352,16 @@ impl Drop for Minisat { #[cfg(test)] mod test { - use std::{ - sync::{Arc, Mutex}, - thread, - }; use super::Minisat; use rustsat::{ lit, - solvers::{Solve, SolveStats, SolverResult}, + solvers::{Solve, SolveStats}, var, }; - #[test] - fn build_destroy() { - let _solver = Minisat::default(); - } - - #[test] - fn build_two() { - let _solver1 = Minisat::default(); - let _solver2 = Minisat::default(); - } - - #[test] - fn tiny_instance_sat() { - let mut solver = Minisat::default(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - } - - #[test] - fn tiny_instance_unsat() { - let mut solver = Minisat::default(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - let ret = solver.solve(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } - - #[test] - fn tiny_instance_multithreaded_sat() { - let mutex_solver = Arc::new(Mutex::new(Minisat::default())); - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now in another thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Sat), - } - - // Now add to solver in other thread - let s = mutex_solver.clone(); - let ret = thread::spawn(move || { - let mut solver = s.lock().unwrap(); - solver.add_unit(!lit![0]).unwrap(); - solver.add_unit(lit![2]).unwrap(); - solver.solve() - }) - .join() - .unwrap(); - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - - // Finally, back in the main thread - let ret = { - let mut solver = mutex_solver.lock().unwrap(); - solver.add_binary(lit![0], !lit![1]).unwrap(); - solver.add_binary(lit![1], !lit![2]).unwrap(); - solver.solve() - }; - match ret { - Err(e) => panic!("got error when solving: {}", e), - Ok(res) => assert_eq!(res, SolverResult::Unsat), - } - } + rustsat_solvertests::basic_unittests!(Minisat); + rustsat_solvertests::freezing_unittests!(Minisat); #[test] fn backend_stats() { diff --git a/solvertests/src/integration.rs b/solvertests/src/integration.rs new file mode 100644 index 00000000..67aefabd --- /dev/null +++ b/solvertests/src/integration.rs @@ -0,0 +1,225 @@ +extern crate proc_macro; + +use proc_macro2::TokenStream; +use quote::quote; +use syn::{parse_quote, Attribute}; + +use super::MacroInput; + +pub fn base(input: MacroInput) -> TokenStream { + let slv = input.slv; + let ignoretok = |idx: usize| -> Option { + if input.bools.len() > idx && input.bools[idx] { + Some(parse_quote! {#[ignore]}) + } else { + None + } + }; + let mut ts = quote! { + macro_rules! test_inst { + ($slv:ty, $inst:expr, $res:expr) => {{ + let mut solver = <$slv>::default(); + let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) + .expect("failed to parse instance"); + rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) + .expect("failed to add cnf to solver"); + let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); + assert_eq!(res, $res); + }}; + ($init:expr, $inst:expr, $res:expr) => {{ + let mut solver = $init; + let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) + .expect("failed to parse instance"); + rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) + .expect("failed to add cnf to solver"); + let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); + assert_eq!(res, $res); + }}; + } + }; + let ignore = ignoretok(0); + ts.extend(quote! { + #[test] + #ignore + fn small_sat() { + test_inst!(#slv, "./data/AProVE11-12.cnf", rustsat::solvers::SolverResult::Sat); + } + }); + let ignore = ignoretok(1); + ts.extend(quote! { + #[test] + #ignore + fn small_unsat() { + test_inst!(#slv, "./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf", rustsat::solvers::SolverResult::Unsat); + } + }); + let ignore = ignoretok(2); + ts.extend(quote! { + #[test] + #ignore + fn minisat_segfault() { + test_inst!(#slv, "./data/minisat-segfault.cnf", rustsat::solvers::SolverResult::Unsat); + } + }); + ts +} + +pub fn incremental(input: MacroInput) -> TokenStream { + let slv = input.slv; + let ignoretok = |idx: usize| -> Option { + if input.bools.len() > idx && input.bools[idx] { + Some(parse_quote! {#[ignore]}) + } else { + None + } + }; + let mut ts = quote! { + macro_rules! init_slv { + ($slv:ty) => { + <$slv>::default() + }; + ($init:expr) => { + $init + }; + } + }; + let ignore = ignoretok(0); + ts.extend(quote! { + #[test] + #ignore + fn assumption_sequence() { + use rustsat::{ + instances::{SatInstance}, + lit, + solvers::{Solve, SolveIncremental, SolverResult::{Sat, Unsat}}, + }; + + let mut solver = init_slv!(#slv); + let inst: SatInstance = + SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); + solver.add_cnf(inst.as_cnf().0).unwrap(); + let res = solver.solve().unwrap(); + assert_eq!(res, Sat); + let res = solver.solve_assumps(&[!lit![0], !lit![1]]).unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[lit![0], !lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[!lit![0], lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Sat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], !lit![2], lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + let res = solver + .solve_assumps(&[!lit![0], !lit![1], !lit![2], !lit![3]]) + .unwrap(); + assert_eq!(res, Unsat); + } + }); + ts +} + +pub fn phasing(input: MacroInput) -> TokenStream { + let slv = input.slv; + let ignoretok = |idx: usize| -> Option { + if input.bools.len() > idx && input.bools[idx] { + Some(parse_quote! {#[ignore]}) + } else { + None + } + }; + let mut ts = quote! { + macro_rules! init_slv { + ($slv:ty) => { + <$slv>::default() + }; + ($init:expr) => { + $init + }; + } + }; + let ignore = ignoretok(0); + ts.extend(quote! { + #[test] + #ignore + fn assumption_sequence() { + use rustsat::{ + instances::{SatInstance}, + lit, + solvers::{PhaseLit, Solve, SolverResult::Sat}, + types::TernaryVal::{True, False}, + var, + }; + let mut solver = init_slv!(#slv); + let inst: SatInstance = + SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); + solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.phase_lit(lit![0]).unwrap(); + solver.phase_lit(!lit![1]).unwrap(); + solver.phase_lit(lit![2]).unwrap(); + solver.phase_lit(!lit![3]).unwrap(); + let res = solver.solve().unwrap(); + assert_eq!(res, Sat); + let sol = solver.solution(var![3]).unwrap(); + assert_eq!(sol.lit_value(lit![0]), True); + assert_eq!(sol.lit_value(lit![1]), False); + assert_eq!(sol.lit_value(lit![2]), True); + assert_eq!(sol.lit_value(lit![3]), False); + solver.unphase_var(var![1]).unwrap(); + solver.unphase_var(var![0]).unwrap(); + } + }); + ts +} diff --git a/solvertests/src/lib.rs b/solvertests/src/lib.rs index e20b8afd..e8a0bea1 100644 --- a/solvertests/src/lib.rs +++ b/solvertests/src/lib.rs @@ -1,11 +1,11 @@ extern crate proc_macro; use proc_macro::TokenStream; -use quote::{quote, ToTokens}; -use syn::{ - parse::Parse, parse_macro_input, parse_quote, punctuated::Punctuated, Attribute, Expr, LitBool, - Token, Type, -}; +use quote::ToTokens; +use syn::{parse::Parse, parse_macro_input, punctuated::Punctuated, Expr, LitBool, Token, Type}; + +mod integration; +mod unit; enum InitBy { Default(Type), @@ -50,226 +50,44 @@ impl Parse for MacroInput { } } +#[proc_macro] +pub fn basic_unittests(tokens: TokenStream) -> TokenStream { + let slv = parse_macro_input!(tokens as Type); + unit::basic(slv).into() +} + +#[proc_macro] +pub fn termination_unittests(tokens: TokenStream) -> TokenStream { + let slv = parse_macro_input!(tokens as Type); + unit::termination(slv).into() +} + +#[proc_macro] +pub fn learner_unittests(tokens: TokenStream) -> TokenStream { + let slv = parse_macro_input!(tokens as Type); + unit::learn(slv).into() +} + +#[proc_macro] +pub fn freezing_unittests(tokens: TokenStream) -> TokenStream { + let slv = parse_macro_input!(tokens as Type); + unit::freezing(slv).into() +} + #[proc_macro] pub fn base_tests(tokens: TokenStream) -> TokenStream { let input = parse_macro_input!(tokens as MacroInput); - let slv = input.slv; - let ignoretok = |idx: usize| -> Option { - if input.bools.len() > idx && input.bools[idx] { - Some(parse_quote! {#[ignore]}) - } else { - None - } - }; - let mut ts = quote! { - macro_rules! test_inst { - ($slv:ty, $inst:expr, $res:expr) => {{ - let mut solver = <$slv>::default(); - let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) - .expect("failed to parse instance"); - rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) - .expect("failed to add cnf to solver"); - let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); - assert_eq!(res, $res); - }}; - ($init:expr, $inst:expr, $res:expr) => {{ - let mut solver = $init; - let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) - .expect("failed to parse instance"); - rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) - .expect("failed to add cnf to solver"); - let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); - assert_eq!(res, $res); - }}; - } - }; - let ignore = ignoretok(0); - ts.extend(quote! { - #[test] - #ignore - fn small_sat() { - test_inst!(#slv, "./data/AProVE11-12.cnf", rustsat::solvers::SolverResult::Sat); - } - }); - let ignore = ignoretok(1); - ts.extend(quote! { - #[test] - #ignore - fn small_unsat() { - test_inst!(#slv, "./data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf", rustsat::solvers::SolverResult::Unsat); - } - }); - let ignore = ignoretok(2); - ts.extend(quote! { - #[test] - #ignore - fn minisat_segfault() { - test_inst!(#slv, "./data/minisat-segfault.cnf", rustsat::solvers::SolverResult::Unsat); - } - }); - ts.into() + integration::base(input).into() } #[proc_macro] pub fn incremental_tests(tokens: TokenStream) -> TokenStream { let input = parse_macro_input!(tokens as MacroInput); - let slv = input.slv; - let ignoretok = |idx: usize| -> Option { - if input.bools.len() > idx && input.bools[idx] { - Some(parse_quote! {#[ignore]}) - } else { - None - } - }; - let mut ts = quote! { - macro_rules! init_slv { - ($slv:ty) => { - <$slv>::default() - }; - ($init:expr) => { - $init - }; - } - }; - let ignore = ignoretok(0); - ts.extend(quote! { - #[test] - #ignore - fn assumption_sequence() { - use rustsat::{ - instances::{SatInstance}, - lit, - solvers::{Solve, SolveIncremental, SolverResult::{Sat, Unsat}}, - }; - - let mut solver = init_slv!(#slv); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, Sat); - let res = solver.solve_assumps(&[!lit![0], !lit![1]]).unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Sat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Sat); - let res = solver - .solve_assumps(&[!lit![0], lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Sat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - let res = solver - .solve_assumps(&[!lit![0], !lit![1], !lit![2], !lit![3]]) - .unwrap(); - assert_eq!(res, Unsat); - } - }); - ts.into() + integration::incremental(input).into() } #[proc_macro] pub fn phasing_tests(tokens: TokenStream) -> TokenStream { let input = parse_macro_input!(tokens as MacroInput); - let slv = input.slv; - let ignoretok = |idx: usize| -> Option { - if input.bools.len() > idx && input.bools[idx] { - Some(parse_quote! {#[ignore]}) - } else { - None - } - }; - let mut ts = quote! { - macro_rules! init_slv { - ($slv:ty) => { - <$slv>::default() - }; - ($init:expr) => { - $init - }; - } - }; - let ignore = ignoretok(0); - ts.extend(quote! { - #[test] - #ignore - fn assumption_sequence() { - use rustsat::{ - instances::{SatInstance}, - lit, - solvers::{PhaseLit, Solve, SolverResult::Sat}, - types::TernaryVal::{True, False}, - var, - }; - let mut solver = init_slv!(#slv); - let inst: SatInstance = - SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); - solver.phase_lit(lit![0]).unwrap(); - solver.phase_lit(!lit![1]).unwrap(); - solver.phase_lit(lit![2]).unwrap(); - solver.phase_lit(!lit![3]).unwrap(); - let res = solver.solve().unwrap(); - assert_eq!(res, Sat); - let sol = solver.solution(var![3]).unwrap(); - assert_eq!(sol.lit_value(lit![0]), True); - assert_eq!(sol.lit_value(lit![1]), False); - assert_eq!(sol.lit_value(lit![2]), True); - assert_eq!(sol.lit_value(lit![3]), False); - solver.unphase_var(var![1]).unwrap(); - solver.unphase_var(var![0]).unwrap(); - } - }); - ts.into() + integration::phasing(input).into() } diff --git a/solvertests/src/unit.rs b/solvertests/src/unit.rs new file mode 100644 index 00000000..bfede621 --- /dev/null +++ b/solvertests/src/unit.rs @@ -0,0 +1,218 @@ +extern crate proc_macro; + +use proc_macro2::TokenStream; +use quote::quote; +use syn::Type; + +pub fn basic(slv: Type) -> TokenStream { + quote! { + #[test] + fn build_destroy() { + let _solver = #slv::default(); + } + + #[test] + fn build_two() { + let _solver1 = #slv::default(); + let _solver2 = #slv::default(); + } + + #[test] + fn stats() { + use rustsat::{lit, var, solvers::{Solve, SolveStats}}; + + let mut solver = #slv::default(); + solver.add_binary(lit![0], !lit![1]).unwrap(); + solver.add_binary(lit![1], !lit![2]).unwrap(); + solver.add_binary(lit![2], !lit![3]).unwrap(); + solver.add_binary(lit![3], !lit![4]).unwrap(); + solver.add_binary(lit![4], !lit![5]).unwrap(); + solver.add_binary(lit![5], !lit![6]).unwrap(); + solver.add_binary(lit![6], !lit![7]).unwrap(); + solver.add_binary(lit![7], !lit![8]).unwrap(); + solver.add_binary(lit![8], !lit![9]).unwrap(); + + assert_eq!(solver.n_sat_solves(), 0); + assert_eq!(solver.n_unsat_solves(), 0); + assert_eq!(solver.n_terminated(), 0); + assert_eq!(solver.n_solves(), 0); + assert_eq!(solver.n_clauses(), 9); + assert_eq!(solver.max_var(), Some(var![9])); + assert_eq!(solver.n_vars(), 10); + assert_eq!(solver.avg_clause_len(), 2.); + + solver.solve().unwrap(); + + assert_eq!(solver.n_sat_solves(), 1); + assert_eq!(solver.n_unsat_solves(), 0); + assert_eq!(solver.n_terminated(), 0); + assert_eq!(solver.n_solves(), 1); + } + + #[test] + fn tiny_instance_sat() { + use rustsat::{lit, solvers::{Solve, SolverResult}}; + + let mut solver = #slv::default(); + solver.add_binary(lit![0], !lit![1]).unwrap(); + solver.add_binary(lit![1], !lit![2]).unwrap(); + let ret = solver.solve(); + match ret { + Err(e) => panic!("got error when solving: {}", e), + Ok(res) => assert_eq!(res, SolverResult::Sat), + } + } + + #[test] + fn tiny_instance_unsat() { + use rustsat::{lit, solvers::{Solve, SolverResult}}; + + let mut solver = #slv::default(); + solver.add_unit(!lit![0]).unwrap(); + solver.add_binary(lit![0], !lit![1]).unwrap(); + solver.add_binary(lit![1], !lit![2]).unwrap(); + solver.add_unit(lit![2]).unwrap(); + let ret = solver.solve(); + match ret { + Err(e) => panic!("got error when solving: {}", e), + Ok(res) => assert_eq!(res, SolverResult::Unsat), + } + } + + #[test] + fn tiny_instance_multithreaded_sat() { + use std::{sync::{Arc, Mutex}, thread}; + use rustsat::{lit, var, types::TernaryVal, solvers::{Solve, SolverResult}}; + + let mutex_solver = Arc::new(Mutex::new(#slv::default())); + + { + // Build in one thread + let mut solver = mutex_solver.lock().unwrap(); + solver.add_binary(lit![0], !lit![1]).unwrap(); + solver.add_unit(lit![0]).unwrap(); + solver.add_binary(lit![1], !lit![2]).unwrap(); + } + + // Now in another thread + let s = mutex_solver.clone(); + let ret = thread::spawn(move || { + let mut solver = s.lock().unwrap(); + solver.solve() + }) + .join() + .unwrap(); + match ret { + Err(e) => panic!("got error when solving: {}", e), + Ok(res) => assert_eq!(res, SolverResult::Sat), + } + + // Finally, back in the main thread + let ret = { + let solver = mutex_solver.lock().unwrap(); + solver.full_solution() + }; + + match ret { + Err(e) => panic!("got error when solving: {}", e), + Ok(res) => assert_eq!(res.var_value(var![0]), TernaryVal::True), + } + } + } +} + +pub fn termination(slv: Type) -> TokenStream { + quote! { + #[test] + fn termination_callback() { + use rustsat::{lit, solvers::{Solve, SolverResult, Terminate, ControlSignal}}; + + let mut solver = #slv::default(); + solver.add_binary(lit![0], !lit![1]).unwrap(); + solver.add_binary(lit![1], !lit![2]).unwrap(); + solver.add_binary(lit![2], !lit![3]).unwrap(); + solver.add_binary(lit![3], !lit![4]).unwrap(); + solver.add_binary(lit![4], !lit![5]).unwrap(); + solver.add_binary(lit![5], !lit![6]).unwrap(); + solver.add_binary(lit![6], !lit![7]).unwrap(); + solver.add_binary(lit![7], !lit![8]).unwrap(); + solver.add_binary(lit![8], !lit![9]).unwrap(); + + solver.attach_terminator(|| ControlSignal::Terminate); + + let ret = solver.solve(); + + match ret { + Err(e) => panic!("got error when solving: {}", e), + Ok(res) => assert_eq!(res, SolverResult::Interrupted), + } + + // Note: since IPASIR doesn't specify _when_ the terminator callback needs + // to be called, there is no guarantee that the callback is actually + // called during solving. This might cause this test to fail with some solvers. + } + } +} + +pub fn learn(slv: Type) -> TokenStream { + quote! { + #[test] + fn learner_callback() { + use rustsat::{lit, solvers::{Solve, SolverResult, Learn}}; + + let mut solver = #slv::default(); + solver.add_binary(lit![0], !lit![1]).unwrap(); + solver.add_binary(lit![1], !lit![2]).unwrap(); + solver.add_binary(lit![2], !lit![3]).unwrap(); + solver.add_binary(lit![3], !lit![4]).unwrap(); + solver.add_binary(lit![4], !lit![5]).unwrap(); + solver.add_binary(lit![5], !lit![6]).unwrap(); + solver.add_binary(lit![6], !lit![7]).unwrap(); + solver.add_binary(lit![7], !lit![8]).unwrap(); + solver.add_binary(lit![8], !lit![9]).unwrap(); + solver.add_unit(lit![9]).unwrap(); + solver.add_unit(!lit![0]).unwrap(); + + let mut cl_len = 0; + + solver.attach_learner( + |clause| { + cl_len = clause.len(); + }, + 10, + ); + + let ret = solver.solve(); + + drop(solver); + + // Note: it is hard to create a testing instance on which clause learning + // actually happens and therefore it is not actually tested if the + // callback is called + + match ret { + Err(e) => panic!("got error when solving: {}", e), + Ok(res) => assert_eq!(res, SolverResult::Unsat), + } + } + } +} + +pub fn freezing(slv: Type) -> TokenStream { + quote! { + #[test] + fn freezing() { + use rustsat::{lit, var, solvers::{Solve, FreezeVar}}; + let mut solver = #slv::default(); + solver.add_binary(lit![0], !lit![1]).unwrap(); + + solver.freeze_var(var![0]).unwrap(); + + assert!(solver.is_frozen(var![0]).unwrap()); + + solver.melt_var(var![0]).unwrap(); + + assert!(!solver.is_frozen(var![0]).unwrap()); + } + } +} From 78334a7e9ceb55d67e1251be91c6d614c83720b1 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Wed, 10 Apr 2024 15:08:21 +0300 Subject: [PATCH 05/56] refactor: solver build system - include minisat and glucose as submodules - specify linked libraries in code rather than in the build script --- .github/workflows/docs.yml | 2 + .github/workflows/glucose.yml | 2 + .github/workflows/minisat.yml | 2 + .github/workflows/rustsat.yml | 2 + .github/workflows/tools.yml | 2 + .gitmodules | 6 ++ cadical/build.rs | 14 ++--- cadical/src/lib.rs | 2 + glucose/build.rs | 105 +++++++--------------------------- glucose/cppsrc | 1 + glucose/src/core.rs | 1 + glucose/src/simp.rs | 1 + kissat/build.rs | 2 - kissat/src/lib.rs | 1 + minisat/build.rs | 103 ++++++--------------------------- minisat/cppsrc | 1 + minisat/src/core.rs | 2 +- minisat/src/simp.rs | 1 + 18 files changed, 70 insertions(+), 180 deletions(-) create mode 100644 .gitmodules create mode 160000 glucose/cppsrc create mode 160000 minisat/cppsrc diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6e9faf3e..dbf8daa5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,6 +16,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 + with: + submodules: "recursive" - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/glucose.yml b/.github/workflows/glucose.yml index 025d1e23..e19cc2fc 100644 --- a/.github/workflows/glucose.yml +++ b/.github/workflows/glucose.yml @@ -19,6 +19,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 + with: + submodules: "recursive" - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/minisat.yml b/.github/workflows/minisat.yml index c730e18b..33d86520 100644 --- a/.github/workflows/minisat.yml +++ b/.github/workflows/minisat.yml @@ -19,6 +19,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 + with: + submodules: "recursive" - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/rustsat.yml b/.github/workflows/rustsat.yml index ec6be7a6..cbbc0d10 100644 --- a/.github/workflows/rustsat.yml +++ b/.github/workflows/rustsat.yml @@ -19,6 +19,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 + with: + submodules: "recursive" - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index fc0e49a3..8325252f 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -19,6 +19,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 + with: + submodules: "recursive" - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..7ce0f13d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "minisat/cppsrc"] + path = minisat/cppsrc + url = git@github.com:chrjabs/minisat.git +[submodule "glucose/cppsrc"] + path = glucose/cppsrc + url = git@github.com:chrjabs/glucose4.git diff --git a/cadical/build.rs b/cadical/build.rs index bbbe2311..98f555ab 100644 --- a/cadical/build.rs +++ b/cadical/build.rs @@ -76,6 +76,12 @@ fn main() { let out_dir = env::var("OUT_DIR").unwrap(); + #[cfg(target_os = "macos")] + println!("cargo:rustc-flags=-l dylib=c++"); + + #[cfg(not(target_os = "macos"))] + println!("cargo:rustc-flags=-l dylib=stdc++"); + // Built solver is in out_dir println!("cargo:rustc-link-search={}", out_dir); println!("cargo:rustc-link-search={}/lib", out_dir); @@ -149,14 +155,6 @@ fn build(repo: &str, branch: &str, reference: &str, patch: &str) { .files(src_files) .compile("cadical"); }; - - println!("cargo:rustc-link-lib=static=cadical"); - - #[cfg(target_os = "macos")] - println!("cargo:rustc-flags=-l dylib=c++"); - - #[cfg(not(target_os = "macos"))] - println!("cargo:rustc-flags=-l dylib=stdc++"); } /// Returns true if there were changes, false if not diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index 497f0e85..2dd045bb 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -873,6 +873,7 @@ mod ffi { _private: [u8; 0], } + #[link(name = "cadical", kind = "static")] extern "C" { // Redefinitions of CaDiCaL C API pub fn ccadical_signature() -> *const c_char; @@ -941,6 +942,7 @@ mod ffi { not(feature = "v1-5-0") ) ))] + #[link(name = "cadical", kind = "static")] extern "C" { pub fn ccadical_flip(solver: *mut CaDiCaLHandle, lit: c_int) -> bool; pub fn ccadical_flippable(solver: *mut CaDiCaLHandle, lit: c_int) -> bool; diff --git a/glucose/build.rs b/glucose/build.rs index d2e37b85..f6fefaf3 100644 --- a/glucose/build.rs +++ b/glucose/build.rs @@ -1,4 +1,4 @@ -use std::{env, fs, path::Path, str}; +use std::{env, path::Path}; fn main() { if std::env::var("DOCS_RS").is_ok() { @@ -8,99 +8,34 @@ fn main() { // Build C++ library // Full commit hash needs to be provided - build( - "https://github.com/chrjabs/glucose4.git", - "main", - "a244a12a3f34da6c93377a6196291494fddf491e", - ); + build(); let out_dir = env::var("OUT_DIR").unwrap(); - // Built solver is in out_dir - println!("cargo:rustc-link-search={}", out_dir); - println!("cargo:rustc-link-search={}/lib", out_dir); -} - -fn build(repo: &str, branch: &str, commit: &str) { - let out_dir = env::var("OUT_DIR").unwrap(); - let mut glucose_dir_str = out_dir.clone(); - glucose_dir_str.push_str("/glucose"); - let glucose_dir = Path::new(&glucose_dir_str); - if update_repo(glucose_dir, repo, branch, commit) - || !Path::new(&out_dir) - .join("lib") - .join("libglucose4.a") - .exists() - { - let mut conf = cmake::Config::new(glucose_dir); - conf.define("BUILD_SYRUP", "OFF") - .define("BUILD_EXECUTABLES", "OFF"); - #[cfg(feature = "quiet")] - conf.define("QUIET", "ON"); - #[cfg(not(feature = "debug"))] - conf.profile("Release"); - conf.build(); - }; - - println!("cargo:rustc-link-lib=static=glucose4"); + println!("cargo:rerun-if-changed=cppsrc/"); #[cfg(target_os = "macos")] println!("cargo:rustc-flags=-l dylib=c++"); #[cfg(not(any(target_os = "macos", target_os = "windows")))] println!("cargo:rustc-flags=-l dylib=stdc++"); + + // Built solver is in out_dir + println!("cargo:rustc-link-search={}", out_dir); + println!("cargo:rustc-link-search={}/lib", out_dir); } -/// Returns true if there were changes, false if not -fn update_repo(path: &Path, url: &str, branch: &str, commit: &str) -> bool { - let mut changed = false; - let target_oid = git2::Oid::from_str(commit) - .unwrap_or_else(|e| panic!("Invalid commit hash {}: {}", commit, e)); - let repo = match git2::Repository::open(path) { - Ok(repo) => { - // Check if already at correct commit - if let Some(oid) = repo.head().unwrap().target_peel() { - if oid == target_oid { - return changed; - } - }; - // Check if commit needs to be fetched - if repo.find_commit(target_oid).is_err() { - // Fetch repo - let mut remote = repo.find_remote("origin").unwrap_or_else(|e| { - panic!("Expected remote \"origin\" in git repo {:?}: {}", path, e) - }); - remote.fetch(&[branch], None, None).unwrap_or_else(|e| { - panic!( - "Could not fetch \"origin/{}\" for git repo {:?}: {}", - branch, path, e - ) - }); - drop(remote); - } - repo - } - Err(_) => { - if path.exists() { - fs::remove_dir_all(path).unwrap_or_else(|e| { - panic!( - "Could not delete directory {}: {}", - path.to_str().unwrap(), - e - ) - }); - }; - changed = true; - git2::Repository::clone(url, path) - .unwrap_or_else(|e| panic!("Could not clone repository {}: {}", url, e)) - } - }; - let target_commit = repo - .find_commit(target_oid) - .unwrap_or_else(|e| panic!("Could not find commit {}: {}", commit, e)); - repo.checkout_tree(target_commit.as_object(), None) - .unwrap_or_else(|e| panic!("Could not checkout commit {}: {}", commit, e)); - repo.set_head_detached(target_oid) - .unwrap_or_else(|e| panic!("Could not detach head at {}: {}", commit, e)); - changed +fn build() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let mut glucose_dir_str = crate_dir.clone(); + glucose_dir_str.push_str("/cppsrc"); + let glucose_dir = Path::new(&glucose_dir_str); + let mut conf = cmake::Config::new(glucose_dir); + conf.define("BUILD_SYRUP", "OFF") + .define("BUILD_EXECUTABLES", "OFF"); + #[cfg(feature = "quiet")] + conf.define("QUIET", "ON"); + #[cfg(not(feature = "debug"))] + conf.profile("Release"); + conf.build(); } diff --git a/glucose/cppsrc b/glucose/cppsrc new file mode 160000 index 00000000..a244a12a --- /dev/null +++ b/glucose/cppsrc @@ -0,0 +1 @@ +Subproject commit a244a12a3f34da6c93377a6196291494fddf491e diff --git a/glucose/src/core.rs b/glucose/src/core.rs index 566d35d2..1c4a5231 100644 --- a/glucose/src/core.rs +++ b/glucose/src/core.rs @@ -359,6 +359,7 @@ mod ffi { _private: [u8; 0], } + #[link(name = "glucose4", kind = "static")] extern "C" { // Redefinitions of Glucose C API pub fn cglucose4_signature() -> *const c_char; diff --git a/glucose/src/simp.rs b/glucose/src/simp.rs index 030e711c..133dd083 100644 --- a/glucose/src/simp.rs +++ b/glucose/src/simp.rs @@ -389,6 +389,7 @@ mod ffi { _private: [u8; 0], } + #[link(name = "glucose4", kind = "static")] extern "C" { // Redefinitions of Glucose C API pub fn cglucose4_signature() -> *const c_char; diff --git a/kissat/build.rs b/kissat/build.rs index 14641e46..3199616c 100644 --- a/kissat/build.rs +++ b/kissat/build.rs @@ -110,8 +110,6 @@ fn build(repo: &str, branch: &str, reference: &str) { .files(src_files) .compile("kissat"); }; - - println!("cargo:rustc-link-lib=static=kissat"); } /// Returns true if there were changes, false if not diff --git a/kissat/src/lib.rs b/kissat/src/lib.rs index 114812d9..900a4e1e 100644 --- a/kissat/src/lib.rs +++ b/kissat/src/lib.rs @@ -475,6 +475,7 @@ mod ffi { _private: [u8; 0], } + #[link(name = "kissat", kind = "static")] extern "C" { // Redefinitions of Kissat API pub fn kissat_signature() -> *const c_char; diff --git a/minisat/build.rs b/minisat/build.rs index 1d90a38f..84985e4d 100644 --- a/minisat/build.rs +++ b/minisat/build.rs @@ -1,4 +1,4 @@ -use std::{env, fs, path::Path, str}; +use std::{env, path::Path}; fn main() { if std::env::var("DOCS_RS").is_ok() { @@ -8,98 +8,33 @@ fn main() { // Build C++ library // Full commit hash needs to be provided - build( - "https://github.com/chrjabs/minisat.git", - "master", - "e168f6e72600f4b04769b0f3bbb7f89b1a200a67", - ); + build(); let out_dir = env::var("OUT_DIR").unwrap(); - // Built solver is in out_dir - println!("cargo:rustc-link-search={}", out_dir); - println!("cargo:rustc-link-search={}/lib", out_dir); -} - -fn build(repo: &str, branch: &str, commit: &str) { - let out_dir = env::var("OUT_DIR").unwrap(); - let mut minisat_dir_str = out_dir.clone(); - minisat_dir_str.push_str("/minisat"); - let minisat_dir = Path::new(&minisat_dir_str); - if update_repo(minisat_dir, repo, branch, commit) - || !Path::new(&out_dir) - .join("lib") - .join("libminisat.a") - .exists() - { - let mut conf = cmake::Config::new(minisat_dir); - conf.define("BUILD_BINARIES", "OFF"); - #[cfg(feature = "quiet")] - conf.define("QUIET", "ON"); - #[cfg(not(feature = "debug"))] - conf.profile("Release"); - conf.build(); - }; - - println!("cargo:rustc-link-lib=static=minisat"); + println!("cargo:rerun-if-changed=cppsrc/"); #[cfg(target_os = "macos")] println!("cargo:rustc-flags=-l dylib=c++"); #[cfg(not(any(target_os = "macos", target_os = "windows")))] println!("cargo:rustc-flags=-l dylib=stdc++"); + + // Built solver is in out_dir + println!("cargo:rustc-link-search={}", out_dir); + println!("cargo:rustc-link-search={}/lib", out_dir); } -/// Returns true if there were changes, false if not -fn update_repo(path: &Path, url: &str, branch: &str, commit: &str) -> bool { - let mut changed = false; - let target_oid = git2::Oid::from_str(commit) - .unwrap_or_else(|e| panic!("Invalid commit hash {}: {}", commit, e)); - let repo = match git2::Repository::open(path) { - Ok(repo) => { - // Check if already at correct commit - if let Some(oid) = repo.head().unwrap().target_peel() { - if oid == target_oid { - return changed; - } - }; - // Check if commit needs to be fetched - if repo.find_commit(target_oid).is_err() { - // Fetch repo - let mut remote = repo.find_remote("origin").unwrap_or_else(|e| { - panic!("Expected remote \"origin\" in git repo {:?}: {}", path, e) - }); - remote.fetch(&[branch], None, None).unwrap_or_else(|e| { - panic!( - "Could not fetch \"origin/{}\" for git repo {:?}: {}", - branch, path, e - ) - }); - drop(remote); - } - repo - } - Err(_) => { - if path.exists() { - fs::remove_dir_all(path).unwrap_or_else(|e| { - panic!( - "Could not delete directory {}: {}", - path.to_str().unwrap(), - e - ) - }); - }; - changed = true; - git2::Repository::clone(url, path) - .unwrap_or_else(|e| panic!("Could not clone repository {}: {}", url, e)) - } - }; - let target_commit = repo - .find_commit(target_oid) - .unwrap_or_else(|e| panic!("Could not find commit {}: {}", commit, e)); - repo.checkout_tree(target_commit.as_object(), None) - .unwrap_or_else(|e| panic!("Could not checkout commit {}: {}", commit, e)); - repo.set_head_detached(target_oid) - .unwrap_or_else(|e| panic!("Could not detach head at {}: {}", commit, e)); - changed +fn build() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let mut minisat_dir_str = crate_dir.clone(); + minisat_dir_str.push_str("/cppsrc"); + let minisat_dir = Path::new(&minisat_dir_str); + let mut conf = cmake::Config::new(minisat_dir); + conf.define("BUILD_BINARIES", "OFF"); + #[cfg(feature = "quiet")] + conf.define("QUIET", "ON"); + #[cfg(not(feature = "debug"))] + conf.profile("Release"); + conf.build(); } diff --git a/minisat/cppsrc b/minisat/cppsrc new file mode 160000 index 00000000..e168f6e7 --- /dev/null +++ b/minisat/cppsrc @@ -0,0 +1 @@ +Subproject commit e168f6e72600f4b04769b0f3bbb7f89b1a200a67 diff --git a/minisat/src/core.rs b/minisat/src/core.rs index 1589d580..7fa688ea 100644 --- a/minisat/src/core.rs +++ b/minisat/src/core.rs @@ -358,7 +358,7 @@ mod ffi { pub struct MinisatHandle { _private: [u8; 0], } - + #[link(name = "minisat", kind = "static")] extern "C" { // Redefinitions of Minisat C API pub fn cminisat_signature() -> *const c_char; diff --git a/minisat/src/simp.rs b/minisat/src/simp.rs index 4fc41681..e0991260 100644 --- a/minisat/src/simp.rs +++ b/minisat/src/simp.rs @@ -390,6 +390,7 @@ mod ffi { _private: [u8; 0], } + #[link(name = "minisat", kind = "static")] extern "C" { // Redefinitions of Minisat C API pub fn cminisat_signature() -> *const c_char; From cd7613971ae46ac461351c4bfbf604cc8d3fae6a Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Sat, 6 Apr 2024 11:20:20 +0300 Subject: [PATCH 06/56] chore: clippy --- rustsat/src/encodings/nodedb.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rustsat/src/encodings/nodedb.rs b/rustsat/src/encodings/nodedb.rs index fba5bf17..6bd575e3 100644 --- a/rustsat/src/encodings/nodedb.rs +++ b/rustsat/src/encodings/nodedb.rs @@ -291,6 +291,7 @@ impl NodeCon { } /// Trait for a database managing [`NodeLike`]s by their [`NodeId`]s +#[allow(dead_code)] pub trait NodeById: IndexMut { /// The type of node in the database type Node: NodeLike; From 3d62269f954db519a28db3742868c964b8c55f75 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Sat, 6 Apr 2024 11:23:32 +0300 Subject: [PATCH 07/56] feat: instance ergonomics for member variables Introduces: - `SatInstance::var_manager_ref()` - `SatInstance::var_manager_mut()` - `SatInstance::n_vars()` - `OptInstance::constraints_ref()` - `OptInstance::constraints_mut()` - `OptInstance::objective_ref()` - `OptInstance::objective_mut()` - `MultiOptInstance::constraints_ref()` - `MultiOptInstance::constraints_mut()` - `MultiOptInstance::objective_ref()` - `MultiOptInstance::objective_mut()` Deprecates: - `SatInstance::var_manager()` - `OptInstance::get_constraints()` - `OptInstance::get_objective()` - `MultiOptInstance::get_constraints()` - `MultiOptInstance::get_objective()` --- rustsat/src/instances/multiopt.rs | 46 ++++++++++++++++++++++++++----- rustsat/src/instances/opt.rs | 44 +++++++++++++++++++++++------ rustsat/src/instances/sat.rs | 27 +++++++++++++++--- tools/src/bin/shuffledimacs.rs | 17 ++++++------ 4 files changed, 106 insertions(+), 28 deletions(-) diff --git a/rustsat/src/instances/multiopt.rs b/rustsat/src/instances/multiopt.rs index 53ed0aa3..870efa22 100644 --- a/rustsat/src/instances/multiopt.rs +++ b/rustsat/src/instances/multiopt.rs @@ -40,7 +40,7 @@ impl MultiOptInstance { pub fn compose(mut constraints: SatInstance, objectives: Vec) -> Self { objectives.iter().for_each(|o| { if let Some(mv) = o.max_var() { - constraints.var_manager().increase_next_free(mv + 1); + constraints.var_manager_mut().increase_next_free(mv + 1); } }); MultiOptInstance { @@ -67,35 +67,67 @@ impl MultiOptInstance { } /// Gets a mutable reference to the hard constraints for modifying them + #[deprecated( + since = "0.5.0", + note = "get_constraints has been renamed to constraints_mut and will be removed in a future release" + )] pub fn get_constraints(&mut self) -> &mut SatInstance { &mut self.constrs } + /// Gets a mutable reference to the hard constraints for modifying them + pub fn constraints_mut(&mut self) -> &mut SatInstance { + &mut self.constrs + } + + /// Gets a reference to the hard constraints + pub fn constraints_ref(&self) -> &SatInstance { + &self.constrs + } + /// Reserves a new variable in the internal variable manager. This is a /// shortcut for `inst.get_constraints().var_manager().new_var()`. pub fn new_var(&mut self) -> Var { - self.get_constraints().var_manager().new_var() + self.constraints_mut().var_manager_mut().new_var() } /// Reserves a new variable in the internal variable manager. This is a /// shortcut for `inst.get_constraints().var_manager().new_lit()`. pub fn new_lit(&mut self) -> Lit { - self.get_constraints().var_manager().new_lit() + self.constraints_mut().var_manager_mut().new_lit() } /// Gets the used variable with the highest index. This is a shortcut /// for `inst.get_constraints().var_manager().max_var()`. - pub fn max_var(&mut self) -> Option { - self.get_constraints().var_manager().max_var() + pub fn max_var(&self) -> Option { + self.constraints_ref().var_manager_ref().max_var() } /// Gets a mutable reference to the first objective for modifying it. /// Make sure `obj_idx` does not exceed the number of objectives in the instance. + #[deprecated( + since = "0.5.0", + note = "get_objective has been renamed to objective_mut and will be removed in a future release" + )] pub fn get_objective(&mut self, obj_idx: usize) -> &mut Objective { assert!(obj_idx < self.objs.len()); &mut self.objs[obj_idx] } + /// Gets a mutable reference to the objective with index `obj_idx` for modifying it. + /// Make sure `obj_idx` does not exceed the number of objectives in the instance. + pub fn objective_mut(&mut self, obj_idx: usize) -> &mut Objective { + assert!(obj_idx < self.objs.len()); + &mut self.objs[obj_idx] + } + + /// Gets a reference to the objective with index `obj_idx`. + /// Make sure `obj_idx` does not exceed the number of objectives in the instance. + pub fn objective_ref(&self, obj_idx: usize) -> &Objective { + assert!(obj_idx < self.objs.len()); + &self.objs[obj_idx] + } + /// Returns an iterator over references to the objectives pub fn iter_obj(&self) -> impl Iterator { self.objs.iter() @@ -321,12 +353,12 @@ impl FromIterator for MultiOptInstance { for line in iter { match line { McnfLine::Comment(_) => (), - McnfLine::Hard(cl) => inst.get_constraints().add_clause(cl), + McnfLine::Hard(cl) => inst.constraints_mut().add_clause(cl), McnfLine::Soft(cl, w, oidx) => { if oidx >= inst.objs.len() { inst.objs.resize(oidx + 1, Default::default()) } - inst.get_objective(oidx).add_soft_clause(w, cl); + inst.objective_mut(oidx).add_soft_clause(w, cl); } } } diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index 84bbd64c..3949836d 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -865,7 +865,7 @@ impl OptInstance { /// Creates a new optimization instance from constraints and an objective pub fn compose(mut constraints: SatInstance, objective: Objective) -> Self { if let Some(mv) = objective.max_var() { - constraints.var_manager().increase_next_free(mv); + constraints.var_manager_mut().increase_next_free(mv); } OptInstance { constrs: constraints, @@ -876,37 +876,65 @@ impl OptInstance { /// Decomposes the optimization instance to a [`SatInstance`] and an [`Objective`] pub fn decompose(mut self) -> (SatInstance, Objective) { if let Some(mv) = self.obj.max_var() { - self.constrs.var_manager.increase_next_free(mv + 1); + self.constrs.var_manager_mut().increase_next_free(mv + 1); } (self.constrs, self.obj) } /// Gets a mutable reference to the hard constraints for modifying them + #[deprecated( + since = "0.5.0", + note = "get_constraints has been renamed to constraints_mut and will be removed in a future release" + )] pub fn get_constraints(&mut self) -> &mut SatInstance { &mut self.constrs } + /// Gets a mutable reference to the hard constraints for modifying them + pub fn constraints_mut(&mut self) -> &mut SatInstance { + &mut self.constrs + } + + /// Gets a reference to the hard constraints + pub fn constraints_ref(&self) -> &SatInstance { + &self.constrs + } + /// Gets a mutable reference to the objective for modifying it + #[deprecated( + since = "0.5.0", + note = "get_objective has been renamed to objective_mut and will be removed in a future release" + )] pub fn get_objective(&mut self) -> &mut Objective { &mut self.obj } + /// Gets a mutable reference to the objective for modifying it + pub fn objective_mut(&mut self) -> &mut Objective { + &mut self.obj + } + + /// Gets a reference to the objective + pub fn objective_ref(&self) -> &Objective { + &self.obj + } + /// Reserves a new variable in the internal variable manager. This is a /// shortcut for `inst.get_constraints().var_manager().new_var()`. pub fn new_var(&mut self) -> Var { - self.get_constraints().var_manager().new_var() + self.constraints_mut().var_manager_mut().new_var() } /// Reserves a new variable in the internal variable manager. This is a /// shortcut for `inst.get_constraints().var_manager().new_lit()`. pub fn new_lit(&mut self) -> Lit { - self.get_constraints().var_manager().new_lit() + self.constraints_mut().var_manager_mut().new_lit() } /// Gets the used variable with the highest index. This is a shortcut /// for `inst.get_constraints().var_manager().max_var()`. - pub fn max_var(&mut self) -> Option { - self.get_constraints().var_manager().max_var() + pub fn max_var(&self) -> Option { + self.constraints_ref().var_manager_ref().max_var() } /// Converts the instance to a set of hard and soft clauses, an objective @@ -1134,9 +1162,9 @@ impl FromIterator for OptInstance { for line in iter { match line { WcnfLine::Comment(_) => (), - WcnfLine::Hard(cl) => inst.get_constraints().add_clause(cl), + WcnfLine::Hard(cl) => inst.constraints_mut().add_clause(cl), WcnfLine::Soft(cl, w) => { - inst.get_objective().add_soft_clause(w, cl); + inst.objective_mut().add_soft_clause(w, cl); } } } diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index 69e77524..c9e67c46 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -402,26 +402,45 @@ impl SatInstance { } /// Gets a reference to the variable manager + #[deprecated( + since = "0.5.0", + note = "var_manager has been renamed to var_manager_mut and will be removed in a future release" + )] pub fn var_manager(&mut self) -> &mut VM { &mut self.var_manager } + /// Gets a mutable reference to the variable manager + pub fn var_manager_mut(&mut self) -> &mut VM { + &mut self.var_manager + } + + /// Gets a reference to the variable manager + pub fn var_manager_ref(&self) -> &VM { + &self.var_manager + } + /// Reserves a new variable in the internal variable manager. This is a /// shortcut for `inst.var_manager().new_var()`. pub fn new_var(&mut self) -> Var { - self.var_manager().new_var() + self.var_manager_mut().new_var() } /// Reserves a new variable in the internal variable manager. This is a /// shortcut for `inst.var_manager().new_lit()`. pub fn new_lit(&mut self) -> Lit { - self.var_manager().new_lit() + self.var_manager_mut().new_lit() } /// Gets the used variable with the highest index. This is a shortcut /// for `inst.var_manager().max_var()`. - pub fn max_var(&mut self) -> Option { - self.var_manager().max_var() + pub fn max_var(&self) -> Option { + self.var_manager_ref().max_var() + } + + /// Returns the number of variables in the variable manager of the instance + pub fn n_vars(&self) -> u32 { + self.var_manager_ref().n_used() } /// Converts the included variable manager to a different type diff --git a/tools/src/bin/shuffledimacs.rs b/tools/src/bin/shuffledimacs.rs index 645d1568..ae8fee5e 100644 --- a/tools/src/bin/shuffledimacs.rs +++ b/tools/src/bin/shuffledimacs.rs @@ -7,7 +7,7 @@ use std::path::{Path, PathBuf}; -use rustsat::instances::{self, BasicVarManager, ManageVars, RandReindVarManager}; +use rustsat::instances::{self, BasicVarManager, RandReindVarManager}; macro_rules! print_usage { () => {{ @@ -28,9 +28,9 @@ fn main() { match determine_file_type(&in_path) { FileType::Cnf => { - let mut inst = instances::SatInstance::::from_dimacs_path(in_path) + let inst = instances::SatInstance::::from_dimacs_path(in_path) .expect("Could not parse CNF"); - let n_vars = inst.var_manager().n_used(); + let n_vars = inst.n_vars(); let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() @@ -38,9 +38,9 @@ fn main() { .expect("Could not write CNF"); } FileType::Wcnf => { - let mut inst = instances::OptInstance::::from_dimacs_path(in_path) + let inst = instances::OptInstance::::from_dimacs_path(in_path) .expect("Could not parse WCNF"); - let n_vars = inst.get_constraints().var_manager().n_used(); + let n_vars = inst.constraints_ref().n_vars(); let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() @@ -48,10 +48,9 @@ fn main() { .expect("Could not write WCNF"); } FileType::Mcnf => { - let mut inst = - instances::MultiOptInstance::::from_dimacs_path(in_path) - .expect("Could not parse MCNF"); - let n_vars = inst.get_constraints().var_manager().n_used(); + let inst = instances::MultiOptInstance::::from_dimacs_path(in_path) + .expect("Could not parse MCNF"); + let n_vars = inst.constraints_ref().n_vars(); let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() From 1056f79b74f36a0bb33fbd9ae8cee17dd2e50b3d Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Sat, 6 Apr 2024 13:16:59 +0300 Subject: [PATCH 08/56] feat: ergonomics for opb writing Make `to_opb` and similar opb writing functions take by reference instead of by value. Some still need to take mutable references, provide workarounds in documentation if additional guarantees are known. --- data/tiny-single-opt.opb | 6 + rustsat/.gitignore | 1 + rustsat/src/instances/fio.rs | 4 +- rustsat/src/instances/fio/opb.rs | 250 +++++++++++++++--------------- rustsat/src/instances/multiopt.rs | 61 +++++++- rustsat/src/instances/opt.rs | 177 ++++++++++++++++----- rustsat/src/instances/sat.rs | 12 +- rustsat/src/types/constraints.rs | 30 ++++ 8 files changed, 360 insertions(+), 181 deletions(-) create mode 100644 data/tiny-single-opt.opb create mode 100644 rustsat/.gitignore diff --git a/data/tiny-single-opt.opb b/data/tiny-single-opt.opb new file mode 100644 index 00000000..042f3b78 --- /dev/null +++ b/data/tiny-single-opt.opb @@ -0,0 +1,6 @@ +* #variable= 4 #constraint= 3 +* A handwritten OPB sat instance for basic testing +min: 1 x1 2 x2; +5 x1 -3 x2 >= 4; +5 x3 -3 x4 >= 2; +5 ~x4 >= 4; diff --git a/rustsat/.gitignore b/rustsat/.gitignore new file mode 100644 index 00000000..d2e4a420 --- /dev/null +++ b/rustsat/.gitignore @@ -0,0 +1 @@ +rustsat-test.opb diff --git a/rustsat/src/instances/fio.rs b/rustsat/src/instances/fio.rs index 3ee2cc9f..e639eafd 100644 --- a/rustsat/src/instances/fio.rs +++ b/rustsat/src/instances/fio.rs @@ -17,7 +17,7 @@ pub struct ObjNoExist(usize); /// Opens a reader for the file at Path. /// With feature `compression` supports bzip2 and gzip compression. -pub(crate) fn open_compressed_uncompressed_read>( +pub fn open_compressed_uncompressed_read>( path: P, ) -> Result, io::Error> { let path = path.as_ref(); @@ -39,7 +39,7 @@ pub(crate) fn open_compressed_uncompressed_read>( /// Opens a writer for the file at Path. /// With feature `compression` supports bzip2 and gzip compression. -pub(crate) fn open_compressed_uncompressed_write>( +pub fn open_compressed_uncompressed_write>( path: P, ) -> Result, io::Error> { let path = path.as_ref(); diff --git a/rustsat/src/instances/fio/opb.rs b/rustsat/src/instances/fio/opb.rs index 8c1d941e..5340c551 100644 --- a/rustsat/src/instances/fio/opb.rs +++ b/rustsat/src/instances/fio/opb.rs @@ -350,7 +350,7 @@ fn opb_data(input: &str, opts: Options) -> IResult<&str, OpbData> { /// Writes a [`SatInstance`] to an OPB file pub fn write_sat( writer: &mut W, - inst: SatInstance, + inst: &SatInstance, opts: Options, ) -> Result<(), io::Error> where @@ -371,125 +371,103 @@ where writeln!(writer, "* {} cardinality constraints", inst.cards.len())?; writeln!(writer, "* {} pseudo-boolean constraints", inst.pbs.len())?; inst.cnf - .into_iter() + .iter() .try_for_each(|cl| write_clause(writer, cl, opts))?; inst.cards - .into_iter() + .iter() .try_for_each(|card| write_card(writer, card, opts))?; inst.pbs - .into_iter() + .iter() .try_for_each(|pb| write_pb(writer, pb, opts))?; writer.flush() } #[cfg(feature = "optimization")] -/// Writes an [`OptInstance`] to an OPB file -pub fn write_opt( +/// Writes an optimization instance to an OPB file +pub fn write_opt( writer: &mut W, - inst: OptInstance, + constrs: &SatInstance, + obj: (LI, isize), opts: Options, ) -> Result<(), io::Error> where W: Write, + LI: WLitIter, VM: ManageVars, { - let (constrs, obj) = inst.decompose(); - let cnf = constrs.cnf; - let cards = constrs.cards; - let pbs = constrs.pbs; - let mut vm = constrs.var_manager; - let (hardened, softs) = obj.as_soft_lits(&mut vm); + let cnf = &constrs.cnf; + let cards = &constrs.cards; + let pbs = &constrs.pbs; writeln!( writer, "* #variable = {} #constraint= {}", - vm.n_used(), + constrs.n_vars(), cnf.len() + cards.len() + pbs.len() )?; writeln!(writer, "* OPB file written by RustSAT")?; - if let Some(max_var) = vm.max_var() { + if let Some(max_var) = constrs.max_var() { writeln!(writer, "* maximum variable: {}", max_var)?; } writeln!(writer, "* {} original hard clauses", cnf.len())?; writeln!(writer, "* {} cardinality constraints", cards.len())?; writeln!(writer, "* {} pseudo-boolean constraints", pbs.len())?; - writeln!( - writer, - "* {} relaxed and hardened soft clauses", - hardened.len() - )?; - write_objective(writer, softs, opts)?; - hardened - .into_iter() - .try_for_each(|cl| write_clause(writer, cl, opts))?; - cnf.into_iter() + write_objective(writer, obj, opts)?; + cnf.iter() .try_for_each(|cl| write_clause(writer, cl, opts))?; cards - .into_iter() + .iter() .try_for_each(|card| write_card(writer, card, opts))?; - pbs.into_iter() - .try_for_each(|pb| write_pb(writer, pb, opts))?; + pbs.iter().try_for_each(|pb| write_pb(writer, pb, opts))?; writer.flush() } #[cfg(feature = "multiopt")] /// Writes a [`MultiOptInstance`] to an OPB file -pub fn write_multi_opt( +pub fn write_multi_opt( writer: &mut W, - inst: MultiOptInstance, + constrs: &SatInstance, + mut objs: Iter, opts: Options, ) -> Result<(), io::Error> where W: Write, VM: ManageVars, + Iter: Iterator, + LI: WLitIter, { - let (constrs, objs) = inst.decompose(); - let cnf = constrs.cnf; - let cards = constrs.cards; - let pbs = constrs.pbs; - let mut vm = constrs.var_manager; - let (hardened, objs) = objs - .into_iter() - .map(|o| o.as_soft_lits(&mut vm)) - .unzip::<_, _, Vec<_>, Vec<_>>(); + let cnf = &constrs.cnf; + let cards = &constrs.cards; + let pbs = &constrs.pbs; writeln!( writer, "* #variable = {} #constraint= {}", - vm.n_used(), + constrs.n_vars(), cnf.len() + cards.len() + pbs.len() )?; writeln!(writer, "* OPB file written by RustSAT")?; - if let Some(max_var) = vm.max_var() { + if let Some(max_var) = constrs.max_var() { writeln!(writer, "* maximum variable: {}", max_var)?; } writeln!(writer, "* {} original hard clauses", cnf.len())?; writeln!(writer, "* {} cardinality constraints", cards.len())?; writeln!(writer, "* {} pseudo-boolean constraints", pbs.len())?; write!(writer, "* ( ")?; - hardened - .iter() - .try_for_each(|h| write!(writer, "{} ", h.len()))?; writeln!(writer, ") relaxed and hardened soft clauses",)?; - objs.into_iter() - .try_for_each(|softs| write_objective(writer, softs, opts))?; - hardened.into_iter().try_for_each(|h| { - h.into_iter() - .try_for_each(|cl| write_clause(writer, cl, opts)) - })?; - cnf.into_iter() + objs.try_for_each(|softs| write_objective(writer, softs, opts))?; + cnf.iter() .try_for_each(|cl| write_clause(writer, cl, opts))?; cards - .into_iter() + .iter() .try_for_each(|card| write_card(writer, card, opts))?; - pbs.into_iter() - .try_for_each(|pb| write_pb(writer, pb, opts))?; + pbs.iter().try_for_each(|pb| write_pb(writer, pb, opts))?; writer.flush() } /// Writes a clause to an OPB file -fn write_clause(writer: &mut W, clause: Clause, opts: Options) -> Result<(), io::Error> { +fn write_clause(writer: &mut W, clause: &Clause, opts: Options) -> Result<(), io::Error> { if opts.no_negated_lits { let mut rhs: isize = 1; - clause.into_iter().try_for_each(|l| { + clause.iter().try_for_each(|l| { if l.is_pos() { write!(writer, "1 x{} ", l.vidx32() + opts.first_var_idx) } else { @@ -499,7 +477,7 @@ fn write_clause(writer: &mut W, clause: Clause, opts: Options) -> Resu })?; writeln!(writer, ">= {};", rhs) } else { - clause.into_iter().try_for_each(|l| { + clause.iter().try_for_each(|l| { if l.is_pos() { write!(writer, "1 x{} ", l.vidx32() + opts.first_var_idx) } else { @@ -513,123 +491,137 @@ fn write_clause(writer: &mut W, clause: Clause, opts: Options) -> Resu /// Writes a cardinality constraint to an OPB file fn write_card( writer: &mut W, - card: CardConstraint, + card: &CardConstraint, opts: Options, ) -> Result<(), io::Error> { + let mut iter_a; + let mut iter_b; + let neg_lit = |l: &Lit| !*l; if opts.no_negated_lits { - let (lits, bound, op) = match card { + let (lits, bound, op): (&mut dyn Iterator, _, _) = match card { CardConstraint::UB(constr) => { - let (lits, bound) = constr.decompose(); - let bound = lits.len() as isize - bound as isize; + let (lits, bound) = constr.decompose_ref(); + let bound = lits.len() as isize - *bound as isize; // Flip operator by negating literals - let lits: Vec = lits.into_iter().map(|l| !l).collect(); - (lits, bound, ">=") + iter_a = lits.iter().map(neg_lit); + (&mut iter_a, bound, ">=") } CardConstraint::LB(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound as isize, ">=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound as isize, ">=") } CardConstraint::EQ(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound as isize, "=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound as isize, "=") } }; let mut offset = 0; - lits.into_iter().try_for_each(|l| { + for l in lits { if l.is_pos() { - write!(writer, "1 x{} ", l.vidx32() + opts.first_var_idx) + write!(writer, "1 x{} ", l.vidx32() + opts.first_var_idx)?; } else { offset += 1; - write!(writer, "-1 x{} ", l.vidx32() + opts.first_var_idx) + write!(writer, "-1 x{} ", l.vidx32() + opts.first_var_idx)?; } - })?; + } writeln!(writer, "{} {};", op, bound - offset) } else { - let (lits, bound, op) = match card { + let (lits, bound, op): (&mut dyn Iterator, _, _) = match card { CardConstraint::UB(constr) => { - let (lits, bound) = constr.decompose(); - let bound = lits.len() as isize - bound as isize; + let (lits, bound) = constr.decompose_ref(); + let bound = lits.len() as isize - *bound as isize; // Flip operator by negating literals - let lits: Vec = lits.into_iter().map(|l| !l).collect(); - (lits, bound, ">=") + iter_a = lits.iter().map(neg_lit); + (&mut iter_a, bound, ">=") } CardConstraint::LB(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound as isize, ">=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound as isize, ">=") } CardConstraint::EQ(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound as isize, "=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound as isize, "=") } }; - lits.into_iter().try_for_each(|l| { + for l in lits { if l.is_pos() { - write!(writer, "1 x{} ", l.vidx32() + opts.first_var_idx) + write!(writer, "1 x{} ", l.vidx32() + opts.first_var_idx)?; } else { - write!(writer, "1 ~x{} ", l.vidx32() + opts.first_var_idx) + write!(writer, "1 ~x{} ", l.vidx32() + opts.first_var_idx)?; } - })?; + } writeln!(writer, "{} {};", op, bound) } } /// Writes a pseudo-boolean constraint to an OPB file -fn write_pb(writer: &mut W, pb: PBConstraint, opts: Options) -> Result<(), io::Error> { +fn write_pb(writer: &mut W, pb: &PBConstraint, opts: Options) -> Result<(), io::Error> { + let mut iter_a; + let mut iter_b; + let neg_lit = |(l, w): &(Lit, usize)| (!*l, *w); if opts.no_negated_lits { - let (lits, bound, op) = match pb { + let (lits, bound, op): (&mut dyn Iterator, _, _) = match pb { PBConstraint::UB(constr) => { - let (lits, bound) = constr.decompose(); + let (lits, bound) = constr.decompose_ref(); let weight_sum = lits.iter().fold(0, |sum, (_, w)| sum + w); // Flip operator by negating literals - let lits = lits.into_iter().map(|(l, w)| (!l, w)).collect(); - (lits, weight_sum as isize - bound, ">=") + iter_a = lits.iter().map(neg_lit); + (&mut iter_a, weight_sum as isize - bound, ">=") } PBConstraint::LB(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound, ">=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound, ">=") } PBConstraint::EQ(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound, "=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound, "=") } }; let mut offset: isize = 0; - lits.into_iter().try_for_each(|(l, w)| { + for (l, w) in lits { if l.is_pos() { - write!(writer, "{} x{} ", w, l.vidx32() + opts.first_var_idx) + write!(writer, "{} x{} ", w, l.vidx32() + opts.first_var_idx)?; } else { // TODO: consider returning error for usize -> isize cast let w = w as isize; offset += w; - write!(writer, "{} x{} ", -w, l.vidx32() + opts.first_var_idx) + write!(writer, "{} x{} ", -w, l.vidx32() + opts.first_var_idx)?; } - })?; + } writeln!(writer, "{} {};", op, bound - offset) } else { - let (lits, bound, op) = match pb { + let (lits, bound, op): (&mut dyn Iterator, _, _) = match pb { PBConstraint::UB(constr) => { - let (lits, bound) = constr.decompose(); + let (lits, bound) = constr.decompose_ref(); let weight_sum = lits.iter().fold(0, |sum, (_, w)| sum + w); // Flip operator by negating literals - let lits = lits.into_iter().map(|(l, w)| (!l, w)).collect(); - (lits, weight_sum as isize - bound, ">=") + iter_a = lits.iter().map(neg_lit); + (&mut iter_a, weight_sum as isize - bound, ">=") } PBConstraint::LB(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound, ">=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound, ">=") } PBConstraint::EQ(constr) => { - let (lits, bound) = constr.decompose(); - (lits, bound, "=") + let (lits, bound) = constr.decompose_ref(); + iter_b = lits.iter().copied(); + (&mut iter_b, *bound, "=") } }; - lits.into_iter().try_for_each(|(l, w)| { + for (l, w) in lits { if l.is_pos() { - write!(writer, "{} x{} ", w, l.vidx32() + opts.first_var_idx) + write!(writer, "{} x{} ", w, l.vidx32() + opts.first_var_idx)?; } else { - write!(writer, "{} ~x{} ", w, l.vidx32() + opts.first_var_idx) + write!(writer, "{} ~x{} ", w, l.vidx32() + opts.first_var_idx)?; } - })?; + } writeln!(writer, "{} {};", op, bound) } } @@ -925,7 +917,7 @@ mod test { let mut cursor = Cursor::new(vec![]); - write_clause(&mut cursor, cl.clone(), Options::default()).unwrap(); + write_clause(&mut cursor, &cl, Options::default()).unwrap(); cursor.rewind().unwrap(); @@ -937,7 +929,7 @@ mod test { assert_eq!(cnf.into_iter().next().unwrap().normalize(), cl.normalize()); } - fn write_parse_inst_test(in_inst: SatInstance, true_inst: SatInstance, opts: Options) { + fn write_parse_inst_test(in_inst: &SatInstance, true_inst: SatInstance, opts: Options) { let mut cursor = Cursor::new(vec![]); write_sat(&mut cursor, in_inst, opts).unwrap(); @@ -967,19 +959,19 @@ mod test { in_inst.add_card_constr(CardConstraint::new_ub(vec![!lit![3], lit![4], !lit![5]], 2)); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_ub(lits.clone(), 2)); - write_parse_inst_test(in_inst, true_inst, Options::default()); + write_parse_inst_test(&in_inst, true_inst, Options::default()); let mut in_inst: SatInstance = SatInstance::new(); in_inst.add_card_constr(CardConstraint::new_eq(vec![!lit![3], lit![4], !lit![5]], 2)); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_eq(lits.clone(), 2)); - write_parse_inst_test(in_inst, true_inst, Options::default()); + write_parse_inst_test(&in_inst, true_inst, Options::default()); let mut in_inst: SatInstance = SatInstance::new(); in_inst.add_card_constr(CardConstraint::new_lb(vec![!lit![3], lit![4], !lit![5]], 2)); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_lb(lits.clone(), 2)); - write_parse_inst_test(in_inst, true_inst, Options::default()); + write_parse_inst_test(&in_inst, true_inst, Options::default()); } #[test] @@ -992,26 +984,28 @@ mod test { // constraint as well. let lits = vec![(!lit![3], 1), (lit![4], 1), (!lit![5], 1)]; - let mut alt_opb_opts = Options::default(); - alt_opb_opts.no_negated_lits = false; + let alt_opb_opts = Options { + no_negated_lits: false, + ..Default::default() + }; let mut in_inst: SatInstance = SatInstance::new(); in_inst.add_card_constr(CardConstraint::new_ub(vec![!lit![3], lit![4], !lit![5]], 2)); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_ub(lits.clone(), 2)); - write_parse_inst_test(in_inst, true_inst, alt_opb_opts); + write_parse_inst_test(&in_inst, true_inst, alt_opb_opts); let mut in_inst: SatInstance = SatInstance::new(); in_inst.add_card_constr(CardConstraint::new_eq(vec![!lit![3], lit![4], !lit![5]], 2)); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_eq(lits.clone(), 2)); - write_parse_inst_test(in_inst, true_inst, alt_opb_opts); + write_parse_inst_test(&in_inst, true_inst, alt_opb_opts); let mut in_inst: SatInstance = SatInstance::new(); in_inst.add_card_constr(CardConstraint::new_lb(vec![!lit![3], lit![4], !lit![5]], 2)); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_lb(lits.clone(), 2)); - write_parse_inst_test(in_inst, true_inst, alt_opb_opts); + write_parse_inst_test(&in_inst, true_inst, alt_opb_opts); } #[test] @@ -1020,34 +1014,36 @@ mod test { let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_ub(lits.clone(), 2)); - write_parse_inst_test(true_inst.clone(), true_inst, Options::default()); + write_parse_inst_test(&true_inst, true_inst.clone(), Options::default()); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_eq(lits.clone(), 2)); - write_parse_inst_test(true_inst.clone(), true_inst, Options::default()); + write_parse_inst_test(&true_inst, true_inst.clone(), Options::default()); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_lb(lits.clone(), 2)); - write_parse_inst_test(true_inst.clone(), true_inst, Options::default()); + write_parse_inst_test(&true_inst, true_inst.clone(), Options::default()); } #[test] fn write_parse_pb_neg_lits() { let lits = vec![(!lit![6], 3), (!lit![7], -5), (lit![8], 2), (lit![9], -4)]; - let mut alt_opb_opts = Options::default(); - alt_opb_opts.no_negated_lits = false; + let alt_opb_opts = Options { + no_negated_lits: false, + ..Default::default() + }; let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_ub(lits.clone(), 2)); - write_parse_inst_test(true_inst.clone(), true_inst, alt_opb_opts); + write_parse_inst_test(&true_inst, true_inst.clone(), alt_opb_opts); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_eq(lits.clone(), 2)); - write_parse_inst_test(true_inst.clone(), true_inst, alt_opb_opts); + write_parse_inst_test(&true_inst, true_inst.clone(), alt_opb_opts); let mut true_inst: SatInstance = SatInstance::new(); true_inst.add_pb_constr(PBConstraint::new_lb(lits.clone(), 2)); - write_parse_inst_test(true_inst.clone(), true_inst, alt_opb_opts); + write_parse_inst_test(&true_inst, true_inst.clone(), alt_opb_opts); } } diff --git a/rustsat/src/instances/multiopt.rs b/rustsat/src/instances/multiopt.rs index 870efa22..9312463f 100644 --- a/rustsat/src/instances/multiopt.rs +++ b/rustsat/src/instances/multiopt.rs @@ -248,11 +248,28 @@ impl MultiOptInstance { /// Writes the instance to an OPB file at a path /// - /// # Performance + /// # Mutability /// - /// For performance, consider using a [`std::io::BufWriter`] instance. + /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, + /// these need to be converted to soft literals first, which modifies the instance. This is why + /// this method has to take a _mutable_ reference. + /// + /// If you know that the internal objective only contains soft literals, you can avoid a mutable + /// borrow by directly accessing the [`fio::opb::write_multi_opt`] function: + /// ``` + /// # use rustsat::instances::{MultiOptInstance, fio}; + /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_opb_path("./data/tiny-single-opt.opb", fio::opb::Options::default()).unwrap(); + /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); + /// let constrs = mopt_inst.constraints_ref(); + /// let iter = mopt_inst.iter_obj().map(|o| { + /// debug_assert_eq!(o.n_clauses(), 0); + /// let offset = o.offset(); + /// (o.iter_soft_lits(), offset) + /// }); + /// fio::opb::write_multi_opt(&mut writer, mopt_inst.constraints_ref(), iter, fio::opb::Options::default()); + /// ``` pub fn to_opb_path>( - self, + &mut self, path: P, opts: fio::opb::Options, ) -> Result<(), io::Error> { @@ -261,12 +278,46 @@ impl MultiOptInstance { } /// Writes the instance to an OPB file + /// + /// # Mutability + /// + /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, + /// these need to be converted to soft literals first, which modifies the instance. This is why + /// this method has to take a _mutable_ reference. + /// + /// If you know that the internal objective only contains soft literals, you can avoid a mutable + /// borrow by directly accessing the [`fio::opb::write_multi_opt`] function: + /// ``` + /// # use rustsat::instances::{MultiOptInstance, fio}; + /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_opb_path("./data/tiny-opt.opb", fio::opb::Options::default()).unwrap(); + /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); + /// let constrs = mopt_inst.constraints_ref(); + /// let iter = mopt_inst.iter_obj().map(|o| { + /// debug_assert_eq!(o.n_clauses(), 0); + /// let offset = o.offset(); + /// (o.iter_soft_lits(), offset) + /// }); + /// fio::opb::write_multi_opt(&mut writer, mopt_inst.constraints_ref(), iter, fio::opb::Options::default()); + /// ``` + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. pub fn to_opb( - self, + &mut self, writer: &mut W, opts: fio::opb::Options, ) -> Result<(), io::Error> { - fio::opb::write_multi_opt::(writer, self, opts) + for obj in &mut self.objs { + let vm = self.constrs.var_manager_mut(); + let hardened = obj.to_soft_lits(vm); + self.constrs.cnf.extend(hardened); + } + let iter = self.objs.iter().map(|o| { + let offset = o.offset(); + (o.iter_soft_lits(), offset) + }); + fio::opb::write_multi_opt::(writer, &self.constrs, iter, opts) } /// Calculates the objective values of an assignment. Returns [`None`] if the diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index 3949836d..85b351f0 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -606,33 +606,63 @@ impl Objective { } } + /// Converts the objective to soft literals in place, returning hardened clauses produced in + /// the conversion. + pub fn to_soft_lits(&mut self, var_manager: &mut VM) -> Cnf + where + VM: ManageVars, + { + let mut cnf = Cnf::new(); + match &mut self.0 { + IntObj::Weighted { + soft_lits, + soft_clauses, + .. + } => { + cnf.clauses.reserve(soft_clauses.len()); + soft_lits.reserve(soft_clauses.len()); + for (mut cl, w) in soft_clauses.drain() { + debug_assert!(cl.len() > 1); + let relax_lit = var_manager.new_var().pos_lit(); + cl.add(relax_lit); + cnf.add_clause(cl); + soft_lits.insert(relax_lit, w); + } + } + IntObj::Unweighted { + soft_lits, + soft_clauses, + .. + } => { + cnf.clauses.reserve(soft_clauses.len()); + soft_lits.reserve(soft_clauses.len()); + for mut cl in soft_clauses.drain(..) { + debug_assert!(cl.len() > 1); + let relax_lit = var_manager.new_var().pos_lit(); + cl.add(relax_lit); + cnf.add_clause(cl); + soft_lits.push(relax_lit); + } + } + } + cnf + } + /// Converts the objective to a set of hard clauses, soft literals and an offset pub fn as_soft_lits(mut self, var_manager: &mut VM) -> (Cnf, (impl WLitIter, isize)) where VM: ManageVars, { + let cnf = self.to_soft_lits(var_manager); self.unweighted_2_weighted(); match self.0 { IntObj::Unweighted { .. } => panic!(), IntObj::Weighted { - mut soft_lits, + soft_lits, soft_clauses, offset, } => { - let mut cnf = Cnf::new(); - cnf.clauses.reserve(soft_clauses.len()); - soft_lits.reserve(soft_clauses.len()); - for (mut cl, w) in soft_clauses { - if cl.len() > 1 { - let relax_lit = var_manager.new_var().pos_lit(); - cl.add(relax_lit); - cnf.add_clause(cl); - soft_lits.insert(relax_lit, w); - } else { - assert!(cl.len() == 1); - soft_lits.insert(!cl[0], w); - } - } + debug_assert!(soft_clauses.is_empty()); (cnf, (soft_lits, offset)) } } @@ -642,43 +672,34 @@ impl Objective { /// weight and an offset. If the objective is weighted, the soft literals /// will appear as often as its weight in the output vector. pub fn as_unweighted_soft_lits( - self, + mut self, var_manager: &mut VM, ) -> (Cnf, impl LitIter, usize, isize) where VM: ManageVars, { + let cnf = self.to_soft_lits(var_manager); match self.0 { - IntObj::Weighted { .. } => { - let (cnf, softs) = self.as_soft_lits(var_manager); + IntObj::Weighted { + soft_lits, + soft_clauses, + offset, + } => { + debug_assert!(soft_clauses.is_empty()); let mut soft_unit_lits = vec![]; - softs - .0 + soft_lits .into_iter() .for_each(|(l, w)| soft_unit_lits.resize(soft_unit_lits.len() + w, l)); - (cnf, soft_unit_lits, 1, softs.1) + (cnf, soft_unit_lits, 1, offset) } IntObj::Unweighted { offset, unit_weight, - mut soft_lits, + soft_lits, soft_clauses, } => { + debug_assert!(soft_clauses.is_empty()); if let Some(unit_weight) = unit_weight { - let mut cnf = Cnf::new(); - cnf.clauses.reserve(soft_clauses.len()); - soft_lits.reserve(soft_clauses.len()); - for mut cl in soft_clauses { - if cl.len() > 1 { - let relax_lit = var_manager.new_var().pos_lit(); - cl.add(relax_lit); - cnf.add_clause(cl); - soft_lits.push(relax_lit); - } else { - assert!(cl.len() == 1); - soft_lits.push(!cl[0]); - } - } (cnf, soft_lits, unit_weight, offset) } else { (Cnf::new(), vec![], 1, offset) @@ -813,6 +834,35 @@ impl Objective { }; self } + + /// Gets a weighted literal iterator over only the soft literals + pub fn iter_soft_lits(&self) -> impl WLitIter + '_ { + match &self.0 { + IntObj::Weighted { soft_lits, .. } => ObjSoftLitIter::Weighted(soft_lits.iter()), + IntObj::Unweighted { + soft_lits, + unit_weight, + .. + } => ObjSoftLitIter::Unweighted(soft_lits.iter(), unit_weight.unwrap_or(0)), + } + } +} + +/// A wrapper type for iterators over soft literals in an objective +enum ObjSoftLitIter<'a> { + Weighted(std::collections::hash_map::Iter<'a, Lit, usize>), + Unweighted(std::slice::Iter<'a, Lit>, usize), +} + +impl Iterator for ObjSoftLitIter<'_> { + type Item = (Lit, usize); + + fn next(&mut self) -> Option { + match self { + ObjSoftLitIter::Weighted(iter) => iter.next().map(|(&l, &w)| (l, w)), + ObjSoftLitIter::Unweighted(iter, w) => iter.next().map(|&l| (l, *w)), + } + } } impl FromIterator<(Lit, usize)> for Objective { @@ -1029,11 +1079,27 @@ impl OptInstance { /// Writes the instance to an OPB file at a path /// - /// # Performance + /// # Mutability /// - /// For performance, consider using a [`std::io::BufWriter`] instance. + /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, + /// these need to be converted to soft literals first, which modifies the instance. This is why + /// this method has to take a _mutable_ reference. + /// + /// If you know that the internal objective only contains soft literals, you can avoid a mutable + /// borrow by directly accessing the [`fio::opb::write_opt`] function: + /// ``` + /// # use rustsat::instances::{OptInstance, fio}; + /// # let opt_inst: OptInstance = OptInstance::from_opb_path("./data/tiny-single-opt.opb", fio::opb::Options::default()).unwrap(); + /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); + /// let constrs = opt_inst.constraints_ref(); + /// debug_assert_eq!(opt_inst.objective_ref().n_clauses(), 0); + /// let offset = opt_inst.objective_ref().offset(); + /// let obj = opt_inst.objective_ref().iter_soft_lits(); + /// fio::opb::write_opt(&mut writer, opt_inst.constraints_ref(), (obj, offset), fio::opb::Options::default()); + /// ``` + /// Note that this will not write the entire instance if there are soft clauses present. pub fn to_opb_path>( - self, + &mut self, path: P, opts: fio::opb::Options, ) -> Result<(), io::Error> { @@ -1042,12 +1108,41 @@ impl OptInstance { } /// Writes the instance to an OPB file + /// + /// # Mutability + /// + /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, + /// these need to be converted to soft literals first, which modifies the instance. This is why + /// this method has to take a _mutable_ reference. + /// + /// If you know that the internal objective only contains soft literals, you can avoid a mutable + /// borrow by directly accessing the [`fio::opb::write_opt`] function: + /// ``` + /// # use rustsat::instances::{OptInstance, fio}; + /// # let opt_inst: OptInstance = OptInstance::from_opb_path("./data/tiny-single-opt.opb", fio::opb::Options::default()).unwrap(); + /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); + /// let constrs = opt_inst.constraints_ref(); + /// debug_assert_eq!(opt_inst.objective_ref().n_clauses(), 0); + /// let offset = opt_inst.objective_ref().offset(); + /// let obj = opt_inst.objective_ref().iter_soft_lits(); + /// fio::opb::write_opt(&mut writer, opt_inst.constraints_ref(), (obj, offset), fio::opb::Options::default()); + /// ``` + /// Note that this will not write the entire instance if there are soft clauses present. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance(crate). pub fn to_opb( - self, + &mut self, writer: &mut W, opts: fio::opb::Options, ) -> Result<(), io::Error> { - fio::opb::write_opt::(writer, self, opts) + let vm = self.constrs.var_manager_mut(); + let hardened = self.obj.to_soft_lits(vm); + self.constrs.cnf.extend(hardened); + let offset = self.obj.offset(); + let iter = self.obj.iter_soft_lits(); + fio::opb::write_opt::(writer, &self.constrs, (iter, offset), opts) } /// Calculates the objective value of an assignment. Returns [`None`] if the diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index c9e67c46..6fdae3d3 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -563,12 +563,8 @@ impl SatInstance { } /// Writes the instance to an OPB file at a path - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. pub fn to_opb_path>( - self, + &self, path: P, opts: fio::opb::Options, ) -> Result<(), io::Error> { @@ -577,8 +573,12 @@ impl SatInstance { } /// Writes the instance to an OPB file + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. pub fn to_opb( - self, + &self, writer: &mut W, opts: fio::opb::Options, ) -> Result<(), io::Error> { diff --git a/rustsat/src/types/constraints.rs b/rustsat/src/types/constraints.rs index 2856b9b8..d15c20fa 100644 --- a/rustsat/src/types/constraints.rs +++ b/rustsat/src/types/constraints.rs @@ -494,6 +494,11 @@ impl CardUBConstr { (self.lits, self.b) } + /// Get references to the constraints internals + pub(crate) fn decompose_ref(&self) -> (&Vec, &usize) { + (&self.lits, &self.b) + } + /// Checks if the constraint is always satisfied pub fn is_tautology(&self) -> bool { self.b >= self.lits.len() @@ -523,6 +528,11 @@ impl CardLBConstr { (self.lits, self.b) } + /// Get references to the constraints internals + pub(crate) fn decompose_ref(&self) -> (&Vec, &usize) { + (&self.lits, &self.b) + } + /// Checks if the constraint is always satisfied pub fn is_tautology(&self) -> bool { self.b == 0 @@ -557,6 +567,11 @@ impl CardEQConstr { (self.lits, self.b) } + /// Get references to the constraints internals + pub(crate) fn decompose_ref(&self) -> (&Vec, &usize) { + (&self.lits, &self.b) + } + /// Checks if the constraint is unsatisfiable pub fn is_unsat(&self) -> bool { self.b > self.lits.len() @@ -907,6 +922,11 @@ impl PBUBConstr { (self.lits, self.b) } + /// Gets references to the constraints internals + pub(crate) fn decompose_ref(&self) -> (&Vec<(Lit, usize)>, &isize) { + (&self.lits, &self.b) + } + /// Checks if the constraint is always satisfied pub fn is_tautology(&self) -> bool { if self.b < 0 { @@ -977,6 +997,11 @@ impl PBLBConstr { (self.lits, self.b) } + /// Gets references to the constraints internals + pub(crate) fn decompose_ref(&self) -> (&Vec<(Lit, usize)>, &isize) { + (&self.lits, &self.b) + } + /// Checks if the constraint is always satisfied pub fn is_tautology(&self) -> bool { self.b <= 0 @@ -1048,6 +1073,11 @@ impl PBEQConstr { (self.lits, self.b) } + /// Gets references to the constraints internals + pub(crate) fn decompose_ref(&self) -> (&Vec<(Lit, usize)>, &isize) { + (&self.lits, &self.b) + } + /// Checks if the constraint is unsatisfiable pub fn is_unsat(&self) -> bool { if self.b < 0 { From 8eaba6ce506a47254e9953382f04d0c087ba17cd Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Sun, 7 Apr 2024 14:19:12 +0300 Subject: [PATCH 09/56] feat: ergonomics for dimacs writing Make `to_dimacs` and similar dimacs writing functions take by reference instead of by value. For the high-level instance types mutable references are still needed; provide `Cnf::to_dimacs` and workarounds in documentation if additional guarantees are known. --- rustsat/.gitignore | 3 + rustsat/src/instances/fio/dimacs.rs | 84 +++++++++--------- rustsat/src/instances/multiopt.rs | 68 +++++++++++++-- rustsat/src/instances/opt.rs | 131 +++++++++++++++++++++++++--- rustsat/src/instances/sat.rs | 112 +++++++++++++++++++++--- tools/src/bin/gbmosplit.rs | 2 +- tools/src/bin/mcnf2opb.rs | 2 +- tools/src/bin/opb2cnf.rs | 2 +- tools/src/bin/opb2mcnf.rs | 2 +- tools/src/bin/opb2wcnf.rs | 2 +- tools/src/bin/wcnf2opb.rs | 2 +- 11 files changed, 328 insertions(+), 82 deletions(-) diff --git a/rustsat/.gitignore b/rustsat/.gitignore index d2e4a420..79cbaa16 100644 --- a/rustsat/.gitignore +++ b/rustsat/.gitignore @@ -1 +1,4 @@ rustsat-test.opb +rustsat-test.cnf +rustsat-test.wcnf +rustsat-test.mcnf diff --git a/rustsat/src/instances/fio/dimacs.rs b/rustsat/src/instances/fio/dimacs.rs index 76e9e92e..cd9c7bc6 100644 --- a/rustsat/src/instances/fio/dimacs.rs +++ b/rustsat/src/instances/fio/dimacs.rs @@ -12,7 +12,7 @@ use crate::{ instances::{Cnf, ManageVars, SatInstance}, - types::{Clause, Lit, Var}, + types::{Clause, Lit}, }; use anyhow::Context; use nom::{ @@ -472,22 +472,12 @@ fn parse_clause_ending(input: &str) -> IResult<&str, &str> { /// Writes a CNF to a DIMACS CNF file pub fn write_cnf_annotated( writer: &mut W, - cnf: Cnf, - max_var: Option, + cnf: &Cnf, + n_vars: u32, ) -> Result<(), io::Error> { writeln!(writer, "c CNF file written by RustSAT")?; - writeln!( - writer, - "p cnf {} {}", - if let Some(max_var) = max_var { - max_var.pos_lit().to_ipasir() - } else { - 0 - }, - cnf.len() - )?; - cnf.into_iter() - .try_for_each(|cl| write_clause(writer, cl))?; + writeln!(writer, "p cnf {} {}", n_vars, cnf.len())?; + cnf.iter().try_for_each(|cl| write_clause(writer, cl))?; writer.flush() } @@ -506,7 +496,7 @@ pub fn write_cnf>( ) -> Result<(), io::Error> { data.try_for_each(|dat| match dat { CnfLine::Comment(c) => write!(writer, "c {}", c), - CnfLine::Clause(cl) => write_clause(writer, cl), + CnfLine::Clause(cl) => write_clause(writer, &cl), }) } @@ -514,26 +504,26 @@ pub fn write_cnf>( /// Writes a CNF and soft clauses to a (post 22, no p line) DIMACS WCNF file pub fn write_wcnf_annotated( writer: &mut W, - cnf: Cnf, + cnf: &Cnf, softs: (CI, isize), - max_var: Option, + n_vars: Option, ) -> Result<(), io::Error> { let (soft_cls, offset) = softs; let soft_cls: Vec<(Clause, usize)> = soft_cls.into_iter().collect(); writeln!(writer, "c WCNF file written by RustSAT")?; - if let Some(mv) = max_var { - writeln!(writer, "c highest var: {}", mv.pos_lit().to_ipasir())?; + if let Some(n_vars) = n_vars { + writeln!(writer, "c {} variables", n_vars)?; } writeln!(writer, "c {} hard clauses", cnf.len())?; writeln!(writer, "c {} soft clauses", soft_cls.len())?; writeln!(writer, "c objective offset: {}", offset)?; - cnf.into_iter().try_for_each(|cl| { + cnf.iter().try_for_each(|cl| { write!(writer, "h ")?; write_clause(writer, cl) })?; soft_cls.into_iter().try_for_each(|(cl, w)| { write!(writer, "{} ", w)?; - write_clause(writer, cl) + write_clause(writer, &cl) })?; writer.flush() } @@ -559,22 +549,22 @@ pub fn write_wcnf>( WcnfLine::Comment(c) => write!(writer, "c {}", c), WcnfLine::Hard(cl) => { write!(writer, "h ")?; - write_clause(writer, cl) + write_clause(writer, &cl) } WcnfLine::Soft(cl, w) => { write!(writer, "{} ", w)?; - write_clause(writer, cl) + write_clause(writer, &cl) } }) } #[cfg(feature = "multiopt")] /// Writes a CNF and multiple objectives as sets of soft clauses to a DIMACS MCNF file -pub fn write_mcnf_annotated( +pub fn write_mcnf_annotated, CI: WClsIter>( writer: &mut W, - cnf: Cnf, - softs: Vec<(CI, isize)>, - max_var: Option, + cnf: &Cnf, + softs: Iter, + n_vars: Option, ) -> Result<(), io::Error> { let (soft_cls, offsets) = softs.into_iter().unzip::<_, _, Vec<_>, Vec<_>>(); let soft_cls: Vec> = soft_cls @@ -582,8 +572,8 @@ pub fn write_mcnf_annotated( .map(|ci| ci.into_iter().collect()) .collect(); writeln!(writer, "c MCNF file written by RustSAT")?; - if let Some(mv) = max_var { - writeln!(writer, "c highest var: {}", mv.pos_lit().to_ipasir())?; + if let Some(n_vars) = n_vars { + writeln!(writer, "c {} variables", n_vars)?; } writeln!(writer, "c {} hard clauses", cnf.len())?; writeln!(writer, "c {} objectives", soft_cls.len())?; @@ -597,7 +587,7 @@ pub fn write_mcnf_annotated( .into_iter() .try_for_each(|o| write!(writer, "{} ", o))?; writeln!(writer, ")")?; - cnf.into_iter().try_for_each(|cl| { + cnf.iter().try_for_each(|cl| { write!(writer, "h ")?; write_clause(writer, cl) })?; @@ -607,7 +597,7 @@ pub fn write_mcnf_annotated( .try_for_each(|(idx, sft_cls)| { sft_cls.into_iter().try_for_each(|(cl, w)| { write!(writer, "o{} {} ", idx + 1, w)?; - write_clause(writer, cl) + write_clause(writer, &cl) }) })?; writer.flush() @@ -634,16 +624,16 @@ pub fn write_mcnf>( McnfLine::Comment(c) => writeln!(writer, "c {}", c), McnfLine::Hard(cl) => { write!(writer, "h ")?; - write_clause(writer, cl) + write_clause(writer, &cl) } McnfLine::Soft(cl, w, oidx) => { write!(writer, "o{} {} ", oidx + 1, w)?; - write_clause(writer, cl) + write_clause(writer, &cl) } }) } -fn write_clause(writer: &mut W, clause: Clause) -> Result<(), io::Error> { +fn write_clause(writer: &mut W, clause: &Clause) -> Result<(), io::Error> { clause .into_iter() .try_for_each(|l| write!(writer, "{} ", l.to_ipasir()))?; @@ -659,7 +649,7 @@ mod tests { use crate::{ clause, instances::{Cnf, SatInstance}, - ipasir_lit, var, + ipasir_lit, }; use nom::error::Error as NomError; use std::io::{Cursor, Seek}; @@ -1093,7 +1083,7 @@ mod tests { let mut cursor = Cursor::new(vec![]); - write_cnf_annotated(&mut cursor, true_cnf.clone(), Some(var![1])).unwrap(); + write_cnf_annotated(&mut cursor, &true_cnf, 2).unwrap(); cursor.rewind().unwrap(); @@ -1110,14 +1100,15 @@ mod tests { let mut true_obj = Objective::new(); true_constrs.add_clause(clause![ipasir_lit![1], ipasir_lit![2]]); true_obj.add_soft_clause(10, clause![ipasir_lit![-3], ipasir_lit![4], ipasir_lit![5]]); + let offset = true_obj.offset(); let mut cursor = Cursor::new(vec![]); write_wcnf_annotated( &mut cursor, - true_constrs.clone().as_cnf().0, - true_obj.clone().as_soft_cls(), - Some(var![1]), + &true_constrs.clone().as_cnf().0, + (true_obj.iter_soft_cls(), offset), + Some(5), ) .unwrap(); @@ -1136,18 +1127,21 @@ mod tests { let mut true_obj1 = Objective::new(); true_constrs.add_clause(clause![ipasir_lit![1], ipasir_lit![2]]); true_obj0.add_soft_clause(3, clause![ipasir_lit![-1]]); + let offset0 = true_obj0.offset(); true_obj1.add_soft_clause(10, clause![ipasir_lit![-3], ipasir_lit![4], ipasir_lit![5]]); + let offset1 = true_obj1.offset(); let mut cursor = Cursor::new(vec![]); write_mcnf_annotated( &mut cursor, - true_constrs.clone().as_cnf().0, + &true_constrs.clone().as_cnf().0, vec![ - true_obj0.clone().as_soft_cls(), - true_obj1.clone().as_soft_cls(), - ], - Some(var![4]), + (true_obj0.iter_soft_cls(), offset0), + (true_obj1.iter_soft_cls(), offset1), + ] + .into_iter(), + Some(5), ) .unwrap(); diff --git a/rustsat/src/instances/multiopt.rs b/rustsat/src/instances/multiopt.rs index 9312463f..c3df0176 100644 --- a/rustsat/src/instances/multiopt.rs +++ b/rustsat/src/instances/multiopt.rs @@ -211,16 +211,60 @@ impl MultiOptInstance { /// Writes the instance to a DIMACS MCNF file at a path /// - /// # Performance + /// # Mutability /// - /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_dimacs_path>(self, path: P) -> Result<(), io::Error> { + /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality + /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints + /// need to be converted to CNF first. This is why this method has to take a _mutable_ + /// reference. + /// + /// If you know that the instance only contains clauses, you can avoid a mutable + /// borrow by directly using [`fio::dimacs::write_mcnf_annotated`]. + /// ``` + /// # use rustsat::instances::{MultiOptInstance, fio}; + /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_dimacs_path("./data/small.mcnf").unwrap(); + /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.mcnf").unwrap(); + /// debug_assert_eq!(mopt_inst.constraints_ref().n_cards(), 0); + /// debug_assert_eq!(mopt_inst.constraints_ref().n_pbs(), 0); + /// let iter = mopt_inst.iter_obj().map(|o| { + /// let offset = o.offset(); + /// (o.iter_soft_cls(), offset) + /// }); + /// fio::dimacs::write_mcnf_annotated(&mut writer, mopt_inst.constraints_ref().cnf(), iter, None); + /// ``` + pub fn to_dimacs_path>(&mut self, path: P) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; self.to_dimacs(&mut writer) } /// Write to DIMACS MCNF - pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { + /// + /// # Mutability + /// + /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality + /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints + /// need to be converted to CNF first. This is why this method has to take a _mutable_ + /// reference. + /// + /// If you know that the instance only contains clauses, you can avoid a mutable + /// borrow by directly using [`fio::dimacs::write_mcnf_annotated`]. + /// ``` + /// # use rustsat::instances::{MultiOptInstance, fio}; + /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_dimacs_path("./data/small.mcnf").unwrap(); + /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.mcnf").unwrap(); + /// debug_assert_eq!(mopt_inst.constraints_ref().n_cards(), 0); + /// debug_assert_eq!(mopt_inst.constraints_ref().n_pbs(), 0); + /// let iter = mopt_inst.iter_obj().map(|o| { + /// let offset = o.offset(); + /// (o.iter_soft_cls(), offset) + /// }); + /// fio::dimacs::write_mcnf_annotated(&mut writer, mopt_inst.constraints_ref().cnf(), iter, None); + /// ``` + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + pub fn to_dimacs(&mut self, writer: &mut W) -> Result<(), io::Error> { self.to_dimacs_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, @@ -230,8 +274,12 @@ impl MultiOptInstance { /// Writes the instance to DIMACS MCNF converting non-clausal constraints /// with specific encoders. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. pub fn to_dimacs_with_encoders( - self, + &mut self, card_encoder: CardEnc, pb_encoder: PBEnc, writer: &mut W, @@ -241,9 +289,13 @@ impl MultiOptInstance { CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { - let (cnf, vm) = self.constrs.as_cnf_with_encoders(card_encoder, pb_encoder); - let soft_cls = self.objs.into_iter().map(|o| o.as_soft_cls()).collect(); - fio::dimacs::write_mcnf_annotated(writer, cnf, soft_cls, vm.max_var()) + self.constrs.to_cnf_with_encoders(card_encoder, pb_encoder); + let n_vars = self.constrs.n_vars(); + let iter = self.objs.iter().map(|o| { + let offset = o.offset(); + (o.iter_soft_cls(), offset) + }); + fio::dimacs::write_mcnf_annotated(writer, &self.constrs.cnf, iter, Some(n_vars)) } /// Writes the instance to an OPB file at a path diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index 85b351f0..a51ac7b6 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -1,6 +1,6 @@ //! # Optimization Instance Representations -use std::{cmp, io, path::Path}; +use std::{cmp, collections::hash_map, io, path::Path, slice}; use crate::{ clause, @@ -846,12 +846,33 @@ impl Objective { } => ObjSoftLitIter::Unweighted(soft_lits.iter(), unit_weight.unwrap_or(0)), } } + + /// Gets an iterator over the entire objective as soft clauses + pub fn iter_soft_cls(&self) -> impl WClsIter + '_ { + match &self.0 { + IntObj::Weighted { + soft_lits, + soft_clauses, + .. + } => ObjSoftClauseIter::Weighted(soft_lits.iter(), soft_clauses.iter()), + IntObj::Unweighted { + unit_weight, + soft_lits, + soft_clauses, + .. + } => ObjSoftClauseIter::Unweighted( + soft_lits.iter(), + soft_clauses.iter(), + unit_weight.unwrap_or(0), + ), + } + } } /// A wrapper type for iterators over soft literals in an objective enum ObjSoftLitIter<'a> { - Weighted(std::collections::hash_map::Iter<'a, Lit, usize>), - Unweighted(std::slice::Iter<'a, Lit>, usize), + Weighted(hash_map::Iter<'a, Lit, usize>), + Unweighted(slice::Iter<'a, Lit>, usize), } impl Iterator for ObjSoftLitIter<'_> { @@ -865,6 +886,36 @@ impl Iterator for ObjSoftLitIter<'_> { } } +/// A wrapper type for iterators over soft clauses in an objective +enum ObjSoftClauseIter<'a> { + Weighted( + hash_map::Iter<'a, Lit, usize>, + hash_map::Iter<'a, Clause, usize>, + ), + Unweighted(slice::Iter<'a, Lit>, slice::Iter<'a, Clause>, usize), +} + +impl Iterator for ObjSoftClauseIter<'_> { + type Item = (Clause, usize); + + fn next(&mut self) -> Option { + match self { + ObjSoftClauseIter::Weighted(lit_iter, cl_iter) => { + if let Some((&l, &w)) = lit_iter.next() { + return Some((clause![!l], w)); + } + cl_iter.next().map(|(cl, &w)| (cl.clone(), w)) + } + ObjSoftClauseIter::Unweighted(lit_iter, cl_iter, w) => { + if let Some(&l) = lit_iter.next() { + return Some((clause![!l], *w)); + } + cl_iter.next().map(|cl| (cl.clone(), *w)) + } + } + } +} + impl FromIterator<(Lit, usize)> for Objective { fn from_iter>(iter: T) -> Self { let mut obj = Self::default(); @@ -1042,16 +1093,56 @@ impl OptInstance { /// Writes the instance to a DIMACS WCNF file at a path /// - /// # Performance + /// # Mutability /// - /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_dimacs_path>(self, path: P) -> Result<(), io::Error> { + /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality + /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints + /// need to be converted to CNF first. This is why this method has to take a _mutable_ + /// reference. + /// + /// If you know that the instance only contains clauses, you can avoid a mutable + /// borrow by directly using [`fio::dimacs::write_wcnf_annotated`]. + /// ``` + /// # use rustsat::instances::{OptInstance, fio}; + /// # let opt_inst: OptInstance = OptInstance::from_dimacs_path("./data/small.wcnf").unwrap(); + /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.wcnf").unwrap(); + /// debug_assert_eq!(opt_inst.constraints_ref().n_cards(), 0); + /// debug_assert_eq!(opt_inst.constraints_ref().n_pbs(), 0); + /// let offset = opt_inst.objective_ref().offset(); + /// let soft_cls = opt_inst.objective_ref().iter_soft_cls(); + /// fio::dimacs::write_wcnf_annotated(&mut writer, opt_inst.constraints_ref().cnf(), (soft_cls, offset), None); + /// ``` + pub fn to_dimacs_path>(&mut self, path: P) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; self.to_dimacs(&mut writer) } /// Write to DIMACS WCNF (post 22) - pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { + /// + /// # Mutability + /// + /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality + /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints + /// need to be converted to CNF first. This is why this method has to take a _mutable_ + /// reference. + /// + /// If you know that the instance only contains clauses, you can avoid a mutable + /// borrow by directly using [`fio::dimacs::write_wcnf_annotated`]. + /// ``` + /// # use rustsat::instances::{OptInstance, fio}; + /// # let opt_inst: OptInstance = OptInstance::from_dimacs_path("./data/small.wcnf").unwrap(); + /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.wcnf").unwrap(); + /// debug_assert_eq!(opt_inst.constraints_ref().n_cards(), 0); + /// debug_assert_eq!(opt_inst.constraints_ref().n_pbs(), 0); + /// let offset = opt_inst.objective_ref().offset(); + /// let soft_cls = opt_inst.objective_ref().iter_soft_cls(); + /// fio::dimacs::write_wcnf_annotated(&mut writer, opt_inst.constraints_ref().cnf(), (soft_cls, offset), None); + /// ``` + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + pub fn to_dimacs(&mut self, writer: &mut W) -> Result<(), io::Error> { self.to_dimacs_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, @@ -1061,8 +1152,19 @@ impl OptInstance { /// Writes the instance to DIMACS WCNF (post 22) converting non-clausal /// constraints with specific encoders. + /// + /// # Mutability + /// + /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality + /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints + /// need to be converted to CNF first. This is why this method has to take a _mutable_ + /// reference. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. pub fn to_dimacs_with_encoders( - self, + &mut self, card_encoder: CardEnc, pb_encoder: PBEnc, writer: &mut W, @@ -1072,9 +1174,16 @@ impl OptInstance { CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { - let (cnf, vm) = self.constrs.as_cnf_with_encoders(card_encoder, pb_encoder); - let soft_cls = self.obj.as_soft_cls(); - fio::dimacs::write_wcnf_annotated(writer, cnf, soft_cls, vm.max_var()) + self.constrs.to_cnf_with_encoders(card_encoder, pb_encoder); + let n_vars = self.constrs.n_vars(); + let offset = self.obj.offset(); + let soft_cls = self.obj.iter_soft_cls(); + fio::dimacs::write_wcnf_annotated( + writer, + &self.constrs.cnf, + (soft_cls, offset), + Some(n_vars), + ) } /// Writes the instance to an OPB file at a path diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index 6fdae3d3..e93bb3b8 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -190,6 +190,21 @@ impl Cnf { pub fn add_ternary(&mut self, lit1: Lit, lit2: Lit, lit3: Lit) { self.add_clause(clause![lit1, lit2, lit3]) } + + /// Writes the CNF to a DIMACS CNF file at a path + pub fn to_dimacs_path>(&self, path: P, n_vars: u32) -> Result<(), io::Error> { + let mut writer = fio::open_compressed_uncompressed_write(path)?; + self.to_dimacs(&mut writer, n_vars) + } + + /// Writes the CNF to DIMACS CNF + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + pub fn to_dimacs(&self, writer: &mut W, n_vars: u32) -> Result<(), io::Error> { + fio::dimacs::write_cnf_annotated(writer, self, n_vars) + } } impl CollectClauses for Cnf { @@ -401,6 +416,11 @@ impl SatInstance { self.pbs.push(pb) } + /// Gets a reference to the internal CNF + pub fn cnf(&self) -> &Cnf { + &self.cnf + } + /// Gets a reference to the variable manager #[deprecated( since = "0.5.0", @@ -469,24 +489,46 @@ impl SatInstance { ) } + /// Converts the instance to a set of clauses inplace. + /// Uses the default encoders from the `encodings` module. + pub fn to_cnf(&mut self) { + self.to_cnf_with_encoders( + card::default_encode_cardinality_constraint, + pb::default_encode_pb_constraint, + ) + } + /// Converts the instance to a set of clauses with explicitly specified /// converters for non-clausal constraints. pub fn as_cnf_with_encoders( mut self, - mut card_encoder: CardEnc, - mut pb_encoder: PBEnc, + card_encoder: CardEnc, + pb_encoder: PBEnc, ) -> (Cnf, VM) where CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), + { + self.to_cnf_with_encoders(card_encoder, pb_encoder); + (self.cnf, self.var_manager) + } + + /// Converts the instance inplace to a set of clauses with explicitly specified + /// converters for non-clausal constraints. + pub fn to_cnf_with_encoders( + &mut self, + mut card_encoder: CardEnc, + mut pb_encoder: PBEnc, + ) where + CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), + PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { self.cards - .into_iter() + .drain(..) .for_each(|constr| card_encoder(constr, &mut self.cnf, &mut self.var_manager)); self.pbs - .into_iter() + .drain(..) .for_each(|constr| pb_encoder(constr, &mut self.cnf, &mut self.var_manager)); - (self.cnf, self.var_manager) } /// Extends the instance by another instance @@ -528,16 +570,51 @@ impl SatInstance { /// Writes the instance to a DIMACS CNF file at a path /// - /// # Performance + /// # Mutability /// - /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_dimacs_path>(self, path: P) -> Result<(), io::Error> { + /// Since the [`SatInstance`] class can contain cardinality and pseudo-boolean constraints that + /// cannot be directly written to DIMACS, these constraints need to be converted to CNF first. + /// This is why this method has to take a _mutable_ reference. + /// + /// If you know that the instance only contains clauses, you can avoid a mutable + /// borrow by using [`SatInstance::cnf_ref()`] and [`Cnf::to_dimacs`]. + /// ``` + /// # use rustsat::instances::SatInstance; + /// # let inst: SatInstance = SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); + /// debug_assert_eq!(inst.n_cards(), 0); + /// debug_assert_eq!(inst.n_pbs(), 0); + /// let n_vars = inst.n_vars(); + /// inst.cnf().to_dimacs_path("./rustsat-test.cnf", n_vars); + /// ``` + pub fn to_dimacs_path>(&mut self, path: P) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; self.to_dimacs(&mut writer) } /// Writes the instance to DIMACS CNF - pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { + /// + /// # Mutability + /// + /// Since the [`SatInstance`] class can contain cardinality and pseudo-boolean constraints that + /// cannot be directly written to DIMACS, these constraints need to be converted to CNF first. + /// This is why this method has to take a _mutable_ reference. + /// + /// If you know that the instance only contains clauses, you can avoid a mutable + /// borrow by using [`SatInstance::cnf_ref()`] and [`Cnf::to_dimacs`]. + /// ``` + /// # use rustsat::instances::{SatInstance, fio}; + /// # let inst: SatInstance = SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); + /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.cnf").unwrap(); + /// debug_assert_eq!(inst.n_cards(), 0); + /// debug_assert_eq!(inst.n_pbs(), 0); + /// let n_vars = inst.n_vars(); + /// inst.cnf().to_dimacs(&mut writer, n_vars); + /// ``` + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + pub fn to_dimacs(&mut self, writer: &mut W) -> Result<(), io::Error> { self.to_dimacs_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, @@ -547,8 +624,18 @@ impl SatInstance { /// Writes the instance to DIMACS CNF converting non-clausal constraints /// with specific encoders. + /// + /// # Mutability + /// + /// Since the [`SatInstance`] class can contain cardinality and pseudo-boolean constraints that + /// cannot be directly written to DIMACS, these constraints need to be converted to CNF first. + /// This is why this method has to take a _mutable_ reference. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. pub fn to_dimacs_with_encoders( - self, + &mut self, card_encoder: CardEnc, pb_encoder: PBEnc, writer: &mut W, @@ -558,8 +645,9 @@ impl SatInstance { CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { - let (cnf, vm) = self.as_cnf_with_encoders(card_encoder, pb_encoder); - fio::dimacs::write_cnf_annotated(writer, cnf, vm.max_var()) + self.to_cnf_with_encoders(card_encoder, pb_encoder); + let n_vars = self.n_vars(); + fio::dimacs::write_cnf_annotated(writer, &self.cnf, n_vars) } /// Writes the instance to an OPB file at a path diff --git a/tools/src/bin/gbmosplit.rs b/tools/src/bin/gbmosplit.rs index 7c48f45b..286245e7 100644 --- a/tools/src/bin/gbmosplit.rs +++ b/tools/src/bin/gbmosplit.rs @@ -467,7 +467,7 @@ fn main() { panic!() }); - let (mo_inst, split_stats) = split(so_inst, &cli); + let (mut mo_inst, split_stats) = split(so_inst, &cli); cli.print_split_stats(split_stats); diff --git a/tools/src/bin/mcnf2opb.rs b/tools/src/bin/mcnf2opb.rs index 9830083d..f8c740aa 100644 --- a/tools/src/bin/mcnf2opb.rs +++ b/tools/src/bin/mcnf2opb.rs @@ -28,7 +28,7 @@ fn main() { no_negated_lits: args.avoid_negated_lits, }; - let inst: MultiOptInstance = if let Some(in_path) = args.in_path { + let mut inst: MultiOptInstance = if let Some(in_path) = args.in_path { MultiOptInstance::from_dimacs_path(in_path).expect("error parsing the input file") } else { MultiOptInstance::from_dimacs(io::stdin()).expect("error parsing input") diff --git a/tools/src/bin/opb2cnf.rs b/tools/src/bin/opb2cnf.rs index 9bc13768..1aed2db5 100644 --- a/tools/src/bin/opb2cnf.rs +++ b/tools/src/bin/opb2cnf.rs @@ -25,7 +25,7 @@ fn main() { ..Default::default() }; - let inst: SatInstance = if let Some(in_path) = args.in_path { + let mut inst: SatInstance = if let Some(in_path) = args.in_path { SatInstance::from_opb_path(in_path, opb_opts).expect("error parsing the input file") } else { SatInstance::from_opb(io::stdin(), opb_opts).expect("error parsing input") diff --git a/tools/src/bin/opb2mcnf.rs b/tools/src/bin/opb2mcnf.rs index a7127f8b..8acf511f 100644 --- a/tools/src/bin/opb2mcnf.rs +++ b/tools/src/bin/opb2mcnf.rs @@ -39,7 +39,7 @@ fn main() { println!("c {} pbs", constrs.n_pbs()); println!("c {} objectives", objs.len()); - let inst = MultiOptInstance::compose(constrs, objs); + let mut inst = MultiOptInstance::compose(constrs, objs); if let Some(out_path) = args.out_path { inst.to_dimacs_path(out_path) diff --git a/tools/src/bin/opb2wcnf.rs b/tools/src/bin/opb2wcnf.rs index 3e075a84..488480fb 100644 --- a/tools/src/bin/opb2wcnf.rs +++ b/tools/src/bin/opb2wcnf.rs @@ -38,7 +38,7 @@ fn main() { println!("c {} cards", constrs.n_cards()); println!("c {} pbs", constrs.n_pbs()); - let inst = OptInstance::compose(constrs, obj); + let mut inst = OptInstance::compose(constrs, obj); if let Some(out_path) = args.out_path { inst.to_dimacs_path(out_path) diff --git a/tools/src/bin/wcnf2opb.rs b/tools/src/bin/wcnf2opb.rs index 115ee609..f428c199 100644 --- a/tools/src/bin/wcnf2opb.rs +++ b/tools/src/bin/wcnf2opb.rs @@ -28,7 +28,7 @@ fn main() { no_negated_lits: args.avoid_negated_lits, }; - let inst: OptInstance = if let Some(in_path) = args.in_path { + let mut inst: OptInstance = if let Some(in_path) = args.in_path { OptInstance::from_dimacs_path(in_path).expect("error parsing the input file") } else { OptInstance::from_dimacs(io::stdin()).expect("error parsing input") From 18294d4de2df3266bb481d5a5fbd2aac4db78b9c Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Sun, 7 Apr 2024 19:24:18 +0300 Subject: [PATCH 10/56] feat: add `add_clause_ref` method to `Solve` trait Since external libraries cannot easily take ownership anyway, for most solvers this is more reasonable. Add a default implementation for `add_clause` that can be overwritten for solvers that can truly take ownership. --- cadical/src/lib.rs | 4 ++-- glucose/src/core.rs | 4 ++-- glucose/src/simp.rs | 4 ++-- ipasir/src/lib.rs | 4 ++-- kissat/src/lib.rs | 4 ++-- minisat/src/core.rs | 4 ++-- minisat/src/simp.rs | 4 ++-- rustsat/src/solvers.rs | 17 +++++++++++++++-- 8 files changed, 29 insertions(+), 16 deletions(-) diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index 2dd045bb..589ffac6 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -427,7 +427,7 @@ impl Solve for CaDiCaL<'_, '_> { } } - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()> { // Update wrapper-internal state self.stats.n_clauses += 1; self.stats.avg_clause_len = @@ -436,7 +436,7 @@ impl Solve for CaDiCaL<'_, '_> { self.state = InternalSolverState::Input; // Call CaDiCaL backend clause - .into_iter() + .iter() .for_each(|l| unsafe { ffi::ccadical_add(self.handle, l.to_ipasir()) }); unsafe { ffi::ccadical_add(self.handle, 0) }; Ok(()) diff --git a/glucose/src/core.rs b/glucose/src/core.rs index 1c4a5231..9b70bf8b 100644 --- a/glucose/src/core.rs +++ b/glucose/src/core.rs @@ -150,7 +150,7 @@ impl Solve for Glucose { } } - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()> { // Update wrapper-internal state self.stats.n_clauses += 1; self.stats.avg_clause_len = @@ -158,7 +158,7 @@ impl Solve for Glucose { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call glucose backend - clause.into_iter().for_each(|l| unsafe { + clause.iter().for_each(|l| unsafe { ffi::cglucose4_add(self.handle, l.to_ipasir()); }); unsafe { ffi::cglucose4_add(self.handle, 0) }; diff --git a/glucose/src/simp.rs b/glucose/src/simp.rs index 133dd083..51735f17 100644 --- a/glucose/src/simp.rs +++ b/glucose/src/simp.rs @@ -158,7 +158,7 @@ impl Solve for Glucose { } } - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()> { // Update wrapper-internal state self.stats.n_clauses += 1; self.stats.avg_clause_len = @@ -166,7 +166,7 @@ impl Solve for Glucose { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call glucose backend - clause.into_iter().for_each(|l| unsafe { + clause.iter().for_each(|l| unsafe { ffi::cglucosesimp4_add(self.handle, l.to_ipasir()); }); unsafe { ffi::cglucosesimp4_add(self.handle, 0) }; diff --git a/ipasir/src/lib.rs b/ipasir/src/lib.rs index e4806b45..2b5a9f23 100644 --- a/ipasir/src/lib.rs +++ b/ipasir/src/lib.rs @@ -186,7 +186,7 @@ impl Solve for IpasirSolver<'_, '_> { } } - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()> { // Update wrapper-internal state self.stats.n_clauses += 1; clause.iter().for_each(|l| match self.stats.max_var { @@ -202,7 +202,7 @@ impl Solve for IpasirSolver<'_, '_> { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call IPASIR backend - for lit in &clause { + for lit in clause { unsafe { ffi::ipasir_add(self.handle, lit.to_ipasir()) } } unsafe { ffi::ipasir_add(self.handle, 0) }; diff --git a/kissat/src/lib.rs b/kissat/src/lib.rs index 900a4e1e..05c36dd1 100644 --- a/kissat/src/lib.rs +++ b/kissat/src/lib.rs @@ -260,7 +260,7 @@ impl Solve for Kissat<'_> { } } - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()> { // Kissat is non-incremental, so only add if in input or configuring state if !matches!( self.state, @@ -288,7 +288,7 @@ impl Solve for Kissat<'_> { self.state = InternalSolverState::Input; // Call Kissat backend clause - .into_iter() + .iter() .for_each(|l| unsafe { ffi::kissat_add(self.handle, l.to_ipasir()) }); unsafe { ffi::kissat_add(self.handle, 0) }; Ok(()) diff --git a/minisat/src/core.rs b/minisat/src/core.rs index 7fa688ea..23581606 100644 --- a/minisat/src/core.rs +++ b/minisat/src/core.rs @@ -150,7 +150,7 @@ impl Solve for Minisat { } } - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()> { // Update wrapper-internal state self.stats.n_clauses += 1; self.stats.avg_clause_len = @@ -158,7 +158,7 @@ impl Solve for Minisat { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call minisat backend - clause.into_iter().for_each(|l| unsafe { + clause.iter().for_each(|l| unsafe { ffi::cminisat_add(self.handle, l.to_ipasir()); }); unsafe { ffi::cminisat_add(self.handle, 0) }; diff --git a/minisat/src/simp.rs b/minisat/src/simp.rs index e0991260..14e1019e 100644 --- a/minisat/src/simp.rs +++ b/minisat/src/simp.rs @@ -158,7 +158,7 @@ impl Solve for Minisat { } } - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()> { // Update wrapper-internal state self.stats.n_clauses += 1; self.stats.avg_clause_len = @@ -166,7 +166,7 @@ impl Solve for Minisat { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call minisat backend - clause.into_iter().for_each(|l| unsafe { + clause.iter().for_each(|l| unsafe { ffi::cminisatsimp_add(self.handle, l.to_ipasir()); }); unsafe { ffi::cminisatsimp_add(self.handle, 0) }; diff --git a/rustsat/src/solvers.rs b/rustsat/src/solvers.rs index cc979a8a..03457e63 100644 --- a/rustsat/src/solvers.rs +++ b/rustsat/src/solvers.rs @@ -175,10 +175,19 @@ pub trait Solve: Extend { /// - If the solver is not in the satisfied state /// - A specific implementation might return other errors fn lit_val(&self, lit: Lit) -> anyhow::Result; - /// Adds a clause to the solver + /// Adds a clause to the solver. /// If the solver is in the satisfied or unsatisfied state before, it is in /// the input state afterwards. - fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()>; + /// + /// This method can be implemented by solvers that can truly take ownership of the clause. + /// Otherwise, it will fall back to the mandatory [`Solve::add_clause_ref`] method. + fn add_clause(&mut self, clause: Clause) -> anyhow::Result<()> { + self.add_clause_ref(&clause) + } + /// Adds a clause to the solver by reference. + /// If the solver is in the satisfied or unsatisfied state before, it is in + /// the input state afterwards. + fn add_clause_ref(&mut self, clause: &Clause) -> anyhow::Result<()>; /// Like [`Solve::add_clause`] but for unit clauses (clauses with one literal). fn add_unit(&mut self, lit: Lit) -> anyhow::Result<()> { self.add_clause(clause![lit]) @@ -195,6 +204,10 @@ pub trait Solve: Extend { fn add_cnf(&mut self, cnf: Cnf) -> anyhow::Result<()> { cnf.into_iter().try_for_each(|cl| self.add_clause(cl)) } + /// Adds all clauses from a [`Cnf`] instance by reference. + fn add_cnf_ref(&mut self, cnf: &Cnf) -> anyhow::Result<()> { + cnf.iter().try_for_each(|cl| self.add_clause_ref(cl)) + } } /// Trait for all SAT solvers in this library. From 8b2c3cc78d85879d5d0f6613f0432ffe37f8d7bb Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Sun, 7 Apr 2024 20:04:52 +0300 Subject: [PATCH 11/56] docs: start migration guide for v0.5.0 --- docs/0-5-0-migration-guide.md | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/0-5-0-migration-guide.md diff --git a/docs/0-5-0-migration-guide.md b/docs/0-5-0-migration-guide.md new file mode 100644 index 00000000..c7203dab --- /dev/null +++ b/docs/0-5-0-migration-guide.md @@ -0,0 +1,47 @@ +# Migration Guide for Breaking Changes in v0.5.0 + +This document gives an overview of the breaking API changes in v0.5.0 and how +to update your code accordingly. Mostly, follow the error messages the compiler +will give you after updating to the new RustSAT version. + +## Error Handling + +Error handling in the `Solve` trait, and file parsers now uses the +[`anyhow`](https://docs.rs/anyhow/latest/anyhow/) crate. This allows for better +error messages, and better tracing. In the process, some of the error types or +variants that are not needed any more have been removed: + +- `rustsat::solvers::SolverError` has been removed and only + `rustsat::solvers::StateError` remains +- `rustsat::instances::fio::opb::Error` has been removed +- `rustsat::instances::fio::dimacs::Error` has been removed +- `rustsat::instances::fio::ParsingError` has been removed +- `rustsat::solvers::SolverState::Error` has also been removed as no error + state is needed with proper error returns + +If you need to handle a specific error, you can use `anyhow`'s +[`downcast`](https://docs.rs/anyhow/latest/anyhow/struct.Error.html#method.downcast) +(e.g., on `solvers::StateError`), but I imagine most often these errors are +anyhow just propagated outwards and displayed. + +## Changes to Improve API Ergonomics + +There have been some API changes to improve usability, even though they are breaking. + +- File writing methods: all file writing methods (on `SatInstance`, + `OptInstance` and `MultiOptInstance`) are now called `write_` instead of `to_`. + Furthermore they take references instead of values and will return an error if + a specific format of the instance is expected but the instance does not satisfy + this requirement. +- File reading methods: all file reading methods (DIMACS and OPB, on + `SatInsatnce`, etc) now require a `BufRead` type as input. Previously, the + reader was internally wrapped in a + [`BufReader`](https://doc.rust-lang.org/stable/std/io/struct.BufReader.html) + object. This now has to be done externally to avoid potentially double + buffering. +- "Heavy" conversion function (e.g., `SatInstance::to_cnf`) are now called + `into_`. Additionally, inplace converter functions named `convert_to_` are also + provided. +- Methods providing references to internal data are now named `_ref` and `_mut` + if mutability is allowed. If only a non-mutable accessor is present, the `_ref` + suffix is omitted (e.g., for `SatInstance::cnf`). From 3350a8bd4b3793949575dccb10138602bb886cbe Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 9 Apr 2024 17:05:09 +0300 Subject: [PATCH 12/56] feat: add `add_nary` function --- rustsat/src/instances/sat.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index e93bb3b8..436893dd 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -77,6 +77,11 @@ impl Cnf { self.clauses.len() } + /// Adds a clause from a slice of literals + pub fn add_nary(&mut self, lits: &[Lit]) { + self.add_clause(lits.into()) + } + /// See [`atomics::lit_impl_lit`] pub fn add_lit_impl_lit(&mut self, a: Lit, b: Lit) { self.add_clause(atomics::lit_impl_lit(a, b)) @@ -298,6 +303,11 @@ impl SatInstance { self.cnf.add_clause(cl); } + /// Adds a clause from a slice of literals + pub fn add_nary(&mut self, lits: &[Lit]) { + self.add_clause(lits.into()) + } + /// Adds a unit clause to the instance pub fn add_unit(&mut self, unit: Lit) { self.add_clause(clause![unit]) From 4fa86ecb2af52ac7943b85f3533f095baa0c2150 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Fri, 12 Apr 2024 16:14:03 +0300 Subject: [PATCH 13/56] refactor: mixed cleanup tasks - rename file writing methods `write_` rather than `to_` - make all file writing methods take references and return errors if not in right format - rename all heavy converters `into_` - rename all inplace converters `convert_to_` --- rustsat/src/encodings/card.rs | 2 +- rustsat/src/encodings/pb.rs | 4 +- rustsat/src/instances/fio/dimacs.rs | 6 +- rustsat/src/instances/fio/opb.rs | 6 +- rustsat/src/instances/multiopt.rs | 255 +++++++++++++---------- rustsat/src/instances/opt.rs | 302 +++++++++++++++++----------- rustsat/src/instances/sat.rs | 192 ++++++++++++------ rustsat/src/lib.rs | 8 + rustsat/src/types/constraints.rs | 45 ++++- rustsat/tests/compression.rs | 8 +- rustsat/tests/constraints.rs | 4 +- rustsat/tests/opb.rs | 2 +- solvertests/src/integration.rs | 8 +- tools/src/bin/cnf2opb.rs | 4 +- tools/src/bin/enumerator.rs | 2 +- tools/src/bin/gbmosplit.rs | 6 +- tools/src/bin/mcnf2opb.rs | 13 +- tools/src/bin/opb2cnf.rs | 6 +- tools/src/bin/opb2mcnf.rs | 5 +- tools/src/bin/opb2wcnf.rs | 9 +- tools/src/bin/shuffledimacs.rs | 6 +- tools/src/bin/wcnf2opb.rs | 11 +- 22 files changed, 561 insertions(+), 343 deletions(-) diff --git a/rustsat/src/encodings/card.rs b/rustsat/src/encodings/card.rs index 7bb3ab93..9ba9f4d9 100644 --- a/rustsat/src/encodings/card.rs +++ b/rustsat/src/encodings/card.rs @@ -356,7 +356,7 @@ pub fn encode_cardinality_constraint, Col: Col return; } if constr.is_clause() { - collector.extend([constr.as_clause().unwrap()]); + collector.extend([constr.into_clause().unwrap()]); return; } CE::encode_constr(constr, collector, var_manager).unwrap() diff --git a/rustsat/src/encodings/pb.rs b/rustsat/src/encodings/pb.rs index f52b17b4..ca7557e5 100644 --- a/rustsat/src/encodings/pb.rs +++ b/rustsat/src/encodings/pb.rs @@ -405,11 +405,11 @@ pub fn encode_pb_constraint, Col: Co return; } if constr.is_clause() { - collector.extend([constr.as_clause().unwrap()]); + collector.extend([constr.into_clause().unwrap()]); return; } if constr.is_card() { - let card = constr.as_card_constr().unwrap(); + let card = constr.into_card_constr().unwrap(); return card::default_encode_cardinality_constraint(card, collector, var_manager); } PBE::encode_constr(constr, collector, var_manager).unwrap() diff --git a/rustsat/src/instances/fio/dimacs.rs b/rustsat/src/instances/fio/dimacs.rs index cd9c7bc6..6f47562a 100644 --- a/rustsat/src/instances/fio/dimacs.rs +++ b/rustsat/src/instances/fio/dimacs.rs @@ -1088,7 +1088,7 @@ mod tests { cursor.rewind().unwrap(); let parsed_inst: SatInstance = super::parse_cnf(cursor).unwrap(); - let (parsed_cnf, _) = parsed_inst.as_cnf(); + let (parsed_cnf, _) = parsed_inst.into_cnf(); assert_eq!(parsed_cnf, true_cnf); } @@ -1106,7 +1106,7 @@ mod tests { write_wcnf_annotated( &mut cursor, - &true_constrs.clone().as_cnf().0, + &true_constrs.clone().into_cnf().0, (true_obj.iter_soft_cls(), offset), Some(5), ) @@ -1135,7 +1135,7 @@ mod tests { write_mcnf_annotated( &mut cursor, - &true_constrs.clone().as_cnf().0, + &true_constrs.clone().into_cnf().0, vec![ (true_obj0.iter_soft_cls(), offset0), (true_obj1.iter_soft_cls(), offset1), diff --git a/rustsat/src/instances/fio/opb.rs b/rustsat/src/instances/fio/opb.rs index 5340c551..2353bef9 100644 --- a/rustsat/src/instances/fio/opb.rs +++ b/rustsat/src/instances/fio/opb.rs @@ -923,7 +923,7 @@ mod test { let (cnf, _) = super::parse_sat::<_, BasicVarManager>(cursor, Options::default()) .unwrap() - .as_cnf(); + .into_cnf(); assert_eq!(cnf.len(), 1); assert_eq!(cnf.into_iter().next().unwrap().normalize(), cl.normalize()); @@ -938,8 +938,8 @@ mod test { let parsed_inst: SatInstance = super::parse_sat(cursor, opts).unwrap(); - let (parsed_cnf, parsed_vm) = parsed_inst.as_cnf(); - let (true_cnf, true_vm) = true_inst.as_cnf(); + let (parsed_cnf, parsed_vm) = parsed_inst.into_cnf(); + let (true_cnf, true_vm) = true_inst.into_cnf(); assert_eq!(parsed_vm, true_vm); assert_eq!(parsed_cnf.normalize(), true_cnf.normalize()); diff --git a/rustsat/src/instances/multiopt.rs b/rustsat/src/instances/multiopt.rs index c3df0176..6c8ba1e5 100644 --- a/rustsat/src/instances/multiopt.rs +++ b/rustsat/src/instances/multiopt.rs @@ -8,6 +8,7 @@ use crate::{ constraints::{CardConstraint, PBConstraint}, Assignment, Lit, Var, WClsIter, WLitIter, }, + RequiresClausal, RequiresSoftLits, }; use super::{ @@ -139,8 +140,17 @@ impl MultiOptInstance { } /// Converts the instance to a set of hard and soft clauses + #[deprecated( + since = "0.5.0", + note = "as_hard_cls_soft_cls has been renamed to into_hard_cls_soft_cls and will be removed in a future release" + )] pub fn as_hard_cls_soft_cls(self) -> (Cnf, Vec<(impl WClsIter, isize)>, VM) { - let (cnf, mut vm) = self.constrs.as_cnf(); + self.into_hard_cls_soft_cls() + } + + /// Converts the instance to a set of hard and soft clauses + pub fn into_hard_cls_soft_cls(self) -> (Cnf, Vec<(impl WClsIter, isize)>, VM) { + let (cnf, mut vm) = self.constrs.into_cnf(); let omv = self.objs.iter().fold(Var::new(0), |v, o| { if let Some(mv) = o.max_var() { return std::cmp::max(v, mv); @@ -148,13 +158,22 @@ impl MultiOptInstance { v }); vm.increase_next_free(omv + 1); - let soft_cls = self.objs.into_iter().map(|o| o.as_soft_cls()).collect(); + let soft_cls = self.objs.into_iter().map(|o| o.into_soft_cls()).collect(); (cnf, soft_cls, vm) } /// Converts the instance to a set of hard clauses and soft literals + #[deprecated( + since = "0.5.0", + note = "as_hard_cls_soft_lits has been renamed to into_hard_cls_soft_lits and will be removed in a future release" + )] pub fn as_hard_cls_soft_lits(self) -> (Cnf, Vec<(impl WLitIter, isize)>, VM) { - let (mut cnf, mut vm) = self.constrs.as_cnf(); + self.into_hard_cls_soft_lits() + } + + /// Converts the instance to a set of hard clauses and soft literals + pub fn into_hard_cls_soft_lits(self) -> (Cnf, Vec<(impl WLitIter, isize)>, VM) { + let (mut cnf, mut vm) = self.constrs.into_cnf(); let omv = self.objs.iter().fold(Var::new(0), |v, o| { if let Some(mv) = o.max_var() { return std::cmp::max(v, mv); @@ -166,7 +185,7 @@ impl MultiOptInstance { .objs .into_iter() .map(|o| { - let (hards, softs) = o.as_soft_lits(&mut vm); + let (hards, softs) = o.into_soft_lits(&mut vm); cnf.extend(hards); softs }) @@ -211,60 +230,20 @@ impl MultiOptInstance { /// Writes the instance to a DIMACS MCNF file at a path /// - /// # Mutability - /// - /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality - /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints - /// need to be converted to CNF first. This is why this method has to take a _mutable_ - /// reference. + /// # Performance /// - /// If you know that the instance only contains clauses, you can avoid a mutable - /// borrow by directly using [`fio::dimacs::write_mcnf_annotated`]. - /// ``` - /// # use rustsat::instances::{MultiOptInstance, fio}; - /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_dimacs_path("./data/small.mcnf").unwrap(); - /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.mcnf").unwrap(); - /// debug_assert_eq!(mopt_inst.constraints_ref().n_cards(), 0); - /// debug_assert_eq!(mopt_inst.constraints_ref().n_pbs(), 0); - /// let iter = mopt_inst.iter_obj().map(|o| { - /// let offset = o.offset(); - /// (o.iter_soft_cls(), offset) - /// }); - /// fio::dimacs::write_mcnf_annotated(&mut writer, mopt_inst.constraints_ref().cnf(), iter, None); - /// ``` - pub fn to_dimacs_path>(&mut self, path: P) -> Result<(), io::Error> { + /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated(since = "0.5.0", note = "use write_dimacs_path instead")] + pub fn to_dimacs_path>(self, path: P) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; + #[allow(deprecated)] self.to_dimacs(&mut writer) } /// Write to DIMACS MCNF - /// - /// # Mutability - /// - /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality - /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints - /// need to be converted to CNF first. This is why this method has to take a _mutable_ - /// reference. - /// - /// If you know that the instance only contains clauses, you can avoid a mutable - /// borrow by directly using [`fio::dimacs::write_mcnf_annotated`]. - /// ``` - /// # use rustsat::instances::{MultiOptInstance, fio}; - /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_dimacs_path("./data/small.mcnf").unwrap(); - /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.mcnf").unwrap(); - /// debug_assert_eq!(mopt_inst.constraints_ref().n_cards(), 0); - /// debug_assert_eq!(mopt_inst.constraints_ref().n_pbs(), 0); - /// let iter = mopt_inst.iter_obj().map(|o| { - /// let offset = o.offset(); - /// (o.iter_soft_cls(), offset) - /// }); - /// fio::dimacs::write_mcnf_annotated(&mut writer, mopt_inst.constraints_ref().cnf(), iter, None); - /// ``` - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_dimacs(&mut self, writer: &mut W) -> Result<(), io::Error> { + #[deprecated(since = "0.5.0", note = "use write_dimacs instead")] + pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { + #[allow(deprecated)] self.to_dimacs_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, @@ -274,12 +253,12 @@ impl MultiOptInstance { /// Writes the instance to DIMACS MCNF converting non-clausal constraints /// with specific encoders. - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated( + since = "0.5.0", + note = "use convert_to_cnf_with_encoders and write_dimacs instead" + )] pub fn to_dimacs_with_encoders( - &mut self, + self, card_encoder: CardEnc, pb_encoder: PBEnc, writer: &mut W, @@ -289,87 +268,145 @@ impl MultiOptInstance { CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { - self.constrs.to_cnf_with_encoders(card_encoder, pb_encoder); + let (cnf, vm) = self + .constrs + .into_cnf_with_encoders(card_encoder, pb_encoder); + let soft_cls = self.objs.into_iter().map(|o| o.into_soft_cls()); + fio::dimacs::write_mcnf_annotated(writer, &cnf, soft_cls, Some(vm.n_used())) + } + + /// Writes the instance to a DIMACS MCNF file at a path + /// + /// This requires that the instance is clausal, i.e., does not contain any non-converted + /// cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by + /// [`SatInstance::convert_to_cnf`] or [`SatInstance::convert_to_cnf_with_encoders`] first. + /// + /// # Errors + /// + /// - If the instance is not clausal, returns [`NonClausal`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_dimacs_path>(&self, path: P) -> anyhow::Result<()> { + let mut writer = fio::open_compressed_uncompressed_write(path)?; + self.write_dimacs(&mut writer) + } + + /// Write to DIMACS MCNF + /// + /// This requires that the instance is clausal, i.e., does not contain any non-converted + /// cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by + /// [`SatInstance::convert_to_cnf`] or [`SatInstance::convert_to_cnf_with_encoders`] first. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + /// + /// # Errors + /// + /// - If the instance is not clausal, returns [`NonClausal`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_dimacs(&self, writer: &mut W) -> anyhow::Result<()> { + if self.constrs.n_cards() > 0 || self.constrs.n_pbs() > 0 { + return Err(RequiresClausal.into()); + } let n_vars = self.constrs.n_vars(); let iter = self.objs.iter().map(|o| { let offset = o.offset(); (o.iter_soft_cls(), offset) }); - fio::dimacs::write_mcnf_annotated(writer, &self.constrs.cnf, iter, Some(n_vars)) + Ok(fio::dimacs::write_mcnf_annotated( + writer, + &self.constrs.cnf, + iter, + Some(n_vars), + )?) } /// Writes the instance to an OPB file at a path /// - /// # Mutability - /// - /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, - /// these need to be converted to soft literals first, which modifies the instance. This is why - /// this method has to take a _mutable_ reference. + /// # Performance /// - /// If you know that the internal objective only contains soft literals, you can avoid a mutable - /// borrow by directly accessing the [`fio::opb::write_multi_opt`] function: - /// ``` - /// # use rustsat::instances::{MultiOptInstance, fio}; - /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_opb_path("./data/tiny-single-opt.opb", fio::opb::Options::default()).unwrap(); - /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); - /// let constrs = mopt_inst.constraints_ref(); - /// let iter = mopt_inst.iter_obj().map(|o| { - /// debug_assert_eq!(o.n_clauses(), 0); - /// let offset = o.offset(); - /// (o.iter_soft_lits(), offset) - /// }); - /// fio::opb::write_multi_opt(&mut writer, mopt_inst.constraints_ref(), iter, fio::opb::Options::default()); - /// ``` + /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated(since = "0.5.0", note = "use write_opb_path instead")] pub fn to_opb_path>( - &mut self, + self, path: P, opts: fio::opb::Options, ) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; + #[allow(deprecated)] self.to_opb(&mut writer, opts) } /// Writes the instance to an OPB file - /// - /// # Mutability - /// - /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, - /// these need to be converted to soft literals first, which modifies the instance. This is why - /// this method has to take a _mutable_ reference. - /// - /// If you know that the internal objective only contains soft literals, you can avoid a mutable - /// borrow by directly accessing the [`fio::opb::write_multi_opt`] function: - /// ``` - /// # use rustsat::instances::{MultiOptInstance, fio}; - /// # let mopt_inst: MultiOptInstance = MultiOptInstance::from_opb_path("./data/tiny-opt.opb", fio::opb::Options::default()).unwrap(); - /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); - /// let constrs = mopt_inst.constraints_ref(); - /// let iter = mopt_inst.iter_obj().map(|o| { - /// debug_assert_eq!(o.n_clauses(), 0); - /// let offset = o.offset(); - /// (o.iter_soft_lits(), offset) - /// }); - /// fio::opb::write_multi_opt(&mut writer, mopt_inst.constraints_ref(), iter, fio::opb::Options::default()); - /// ``` - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated(since = "0.5.0", note = "use write_opb instead")] pub fn to_opb( - &mut self, + mut self, writer: &mut W, opts: fio::opb::Options, ) -> Result<(), io::Error> { for obj in &mut self.objs { let vm = self.constrs.var_manager_mut(); - let hardened = obj.to_soft_lits(vm); + let hardened = obj.convert_to_soft_lits(vm); self.constrs.cnf.extend(hardened); } - let iter = self.objs.iter().map(|o| { + let objs = self.objs.iter().map(|o| { let offset = o.offset(); - (o.iter_soft_lits(), offset) + (o.iter_soft_lits().unwrap(), offset) }); - fio::opb::write_multi_opt::(writer, &self.constrs, iter, opts) + fio::opb::write_multi_opt::(writer, &self.constrs, objs, opts) + } + + /// Writes the instance to an OPB file at a path + /// + /// This requires that the objective does not contain soft clauses. If it does, use + /// [`Objective::convert_to_soft_lits`] first. + /// + /// # Errors + /// + /// - If the objective containes soft literals, returns [`RequiresSoftLits`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_opb_path>( + &self, + path: P, + opts: fio::opb::Options, + ) -> anyhow::Result<()> { + let mut writer = fio::open_compressed_uncompressed_write(path)?; + self.write_opb(&mut writer, opts) + } + + /// Writes the instance to an OPB file + /// + /// This requires that the objective does not contain soft clauses. If it does, use + /// [`Objective::convert_to_soft_lits`] first. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance(crate). + /// + /// # Errors + /// + /// - If the objective containes soft literals, returns [`RequiresSoftLits`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_opb( + &self, + writer: &mut W, + opts: fio::opb::Options, + ) -> anyhow::Result<()> { + let objs: Result, RequiresSoftLits> = self + .objs + .iter() + .map(|o| { + let offset = o.offset(); + Ok((o.iter_soft_lits()?, offset)) + }) + .collect(); + let objs = objs?; + Ok(fio::opb::write_multi_opt::( + writer, + &self.constrs, + objs.into_iter(), + opts, + )?) } /// Calculates the objective values of an assignment. Returns [`None`] if the diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index a51ac7b6..c415a1ec 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -9,6 +9,7 @@ use crate::{ constraints::{CardConstraint, PBConstraint}, Assignment, Clause, ClsIter, Lit, LitIter, RsHashMap, TernaryVal, Var, WClsIter, WLitIter, }, + RequiresClausal, RequiresSoftLits, }; /// Internal objective type for not exposing variants @@ -547,7 +548,16 @@ impl Objective { } /// Converts the objective to a set of soft clauses and an offset + #[deprecated( + since = "0.5.0", + note = "as_soft_cls has been renamed to into_soft_cls and will be removed in a future release" + )] pub fn as_soft_cls(self) -> (impl WClsIter, isize) { + self.into_soft_cls() + } + + /// Converts the objective to a set of soft clauses and an offset + pub fn into_soft_cls(self) -> (impl WClsIter, isize) { match self.0 { IntObj::Unweighted { mut soft_clauses, @@ -583,7 +593,18 @@ impl Objective { /// Converts the objective to unweighted soft clauses, a unit weight and an offset. If the /// objective is weighted, the soft clause will appear as often as its /// weight in the output vector. - pub fn as_unweighted_soft_cls(mut self) -> (impl ClsIter, usize, isize) { + #[deprecated( + since = "0.5.0", + note = "as_unweighted_soft_cls has been renamed to into_unweighted_soft_cls and will be removed in a future release" + )] + pub fn as_unweighted_soft_cls(self) -> (impl ClsIter, usize, isize) { + self.into_unweighted_soft_cls() + } + + /// Converts the objective to unweighted soft clauses, a unit weight and an offset. If the + /// objective is weighted, the soft clause will appear as often as its + /// weight in the output vector. + pub fn into_unweighted_soft_cls(mut self) -> (impl ClsIter, usize, isize) { self.weighted_2_unweighted(); match self.0 { IntObj::Weighted { .. } => panic!(), @@ -608,7 +629,9 @@ impl Objective { /// Converts the objective to soft literals in place, returning hardened clauses produced in /// the conversion. - pub fn to_soft_lits(&mut self, var_manager: &mut VM) -> Cnf + /// + /// See [`Self::into_soft_lits`] if you do not need to convert in place. + pub fn convert_to_soft_lits(&mut self, var_manager: &mut VM) -> Cnf where VM: ManageVars, { @@ -649,14 +672,28 @@ impl Objective { } /// Converts the objective to a set of hard clauses, soft literals and an offset - pub fn as_soft_lits(mut self, var_manager: &mut VM) -> (Cnf, (impl WLitIter, isize)) + #[deprecated( + since = "0.5.0", + note = "as_soft_lits has been renamed to into_soft_lits and will be removed in a future release" + )] + pub fn as_soft_lits(self, var_manager: &mut VM) -> (Cnf, (impl WLitIter, isize)) + where + VM: ManageVars, + { + self.into_soft_lits(var_manager) + } + + /// Converts the objective to a set of hard clauses, soft literals and an offset + /// + /// See [`Self::convert_to_soft_lits`] for converting in place + pub fn into_soft_lits(mut self, var_manager: &mut VM) -> (Cnf, (impl WLitIter, isize)) where VM: ManageVars, { - let cnf = self.to_soft_lits(var_manager); + let cnf = self.convert_to_soft_lits(var_manager); self.unweighted_2_weighted(); match self.0 { - IntObj::Unweighted { .. } => panic!(), + IntObj::Unweighted { .. } => unreachable!(), IntObj::Weighted { soft_lits, soft_clauses, @@ -671,14 +708,31 @@ impl Objective { /// Converts the objective to hard clauses, unweighted soft literals, a unit /// weight and an offset. If the objective is weighted, the soft literals /// will appear as often as its weight in the output vector. + #[deprecated( + since = "0.5.0", + note = "as_unweighted_soft_lits has been renamed to into_unweighted_soft_lits and will be removed in a future release" + )] pub fn as_unweighted_soft_lits( + self, + var_manager: &mut VM, + ) -> (Cnf, impl LitIter, usize, isize) + where + VM: ManageVars, + { + self.into_unweighted_soft_lits(var_manager) + } + + /// Converts the objective to hard clauses, unweighted soft literals, a unit + /// weight and an offset. If the objective is weighted, the soft literals + /// will appear as often as its weight in the output vector. + pub fn into_unweighted_soft_lits( mut self, var_manager: &mut VM, ) -> (Cnf, impl LitIter, usize, isize) where VM: ManageVars, { - let cnf = self.to_soft_lits(var_manager); + let cnf = self.convert_to_soft_lits(var_manager); match self.0 { IntObj::Weighted { soft_lits, @@ -836,15 +890,23 @@ impl Objective { } /// Gets a weighted literal iterator over only the soft literals - pub fn iter_soft_lits(&self) -> impl WLitIter + '_ { - match &self.0 { + /// + /// # Errors + /// + /// If the objective contains soft clauses that this iterator would miss, returns + /// [`RequiresSoftLits`] + pub fn iter_soft_lits(&self) -> Result { + if self.n_clauses() > 0 { + return Err(RequiresSoftLits); + } + Ok(match &self.0 { IntObj::Weighted { soft_lits, .. } => ObjSoftLitIter::Weighted(soft_lits.iter()), IntObj::Unweighted { soft_lits, unit_weight, .. } => ObjSoftLitIter::Unweighted(soft_lits.iter(), unit_weight.unwrap_or(0)), - } + }) } /// Gets an iterator over the entire objective as soft clauses @@ -1040,22 +1102,22 @@ impl OptInstance { /// Converts the instance to a set of hard and soft clauses, an objective /// offset and a variable manager - pub fn as_hard_cls_soft_cls(self) -> (Cnf, (impl WClsIter, isize), VM) { - let (cnf, mut vm) = self.constrs.as_cnf(); + pub fn into_hard_cls_soft_cls(self) -> (Cnf, (impl WClsIter, isize), VM) { + let (cnf, mut vm) = self.constrs.into_cnf(); if let Some(mv) = self.obj.max_var() { vm.increase_next_free(mv + 1); } - (cnf, self.obj.as_soft_cls(), vm) + (cnf, self.obj.into_soft_cls(), vm) } /// Converts the instance to a set of hard clauses and soft literals, an /// objective offset and a variable manager - pub fn as_hard_cls_soft_lits(self) -> (Cnf, (impl WLitIter, isize), VM) { - let (mut cnf, mut vm) = self.constrs.as_cnf(); + pub fn into_hard_cls_soft_lits(self) -> (Cnf, (impl WLitIter, isize), VM) { + let (mut cnf, mut vm) = self.constrs.into_cnf(); if let Some(mv) = self.obj.max_var() { vm.increase_next_free(mv + 1); } - let (hard_softs, softs) = self.obj.as_soft_lits(&mut vm); + let (hard_softs, softs) = self.obj.into_soft_lits(&mut vm); cnf.extend(hard_softs); (cnf, softs, vm) } @@ -1093,56 +1155,20 @@ impl OptInstance { /// Writes the instance to a DIMACS WCNF file at a path /// - /// # Mutability - /// - /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality - /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints - /// need to be converted to CNF first. This is why this method has to take a _mutable_ - /// reference. + /// # Performance /// - /// If you know that the instance only contains clauses, you can avoid a mutable - /// borrow by directly using [`fio::dimacs::write_wcnf_annotated`]. - /// ``` - /// # use rustsat::instances::{OptInstance, fio}; - /// # let opt_inst: OptInstance = OptInstance::from_dimacs_path("./data/small.wcnf").unwrap(); - /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.wcnf").unwrap(); - /// debug_assert_eq!(opt_inst.constraints_ref().n_cards(), 0); - /// debug_assert_eq!(opt_inst.constraints_ref().n_pbs(), 0); - /// let offset = opt_inst.objective_ref().offset(); - /// let soft_cls = opt_inst.objective_ref().iter_soft_cls(); - /// fio::dimacs::write_wcnf_annotated(&mut writer, opt_inst.constraints_ref().cnf(), (soft_cls, offset), None); - /// ``` - pub fn to_dimacs_path>(&mut self, path: P) -> Result<(), io::Error> { + /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated(since = "0.5.0", note = "use write_dimacs_path instead")] + pub fn to_dimacs_path>(self, path: P) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; + #[allow(deprecated)] self.to_dimacs(&mut writer) } /// Write to DIMACS WCNF (post 22) - /// - /// # Mutability - /// - /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality - /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints - /// need to be converted to CNF first. This is why this method has to take a _mutable_ - /// reference. - /// - /// If you know that the instance only contains clauses, you can avoid a mutable - /// borrow by directly using [`fio::dimacs::write_wcnf_annotated`]. - /// ``` - /// # use rustsat::instances::{OptInstance, fio}; - /// # let opt_inst: OptInstance = OptInstance::from_dimacs_path("./data/small.wcnf").unwrap(); - /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.wcnf").unwrap(); - /// debug_assert_eq!(opt_inst.constraints_ref().n_cards(), 0); - /// debug_assert_eq!(opt_inst.constraints_ref().n_pbs(), 0); - /// let offset = opt_inst.objective_ref().offset(); - /// let soft_cls = opt_inst.objective_ref().iter_soft_cls(); - /// fio::dimacs::write_wcnf_annotated(&mut writer, opt_inst.constraints_ref().cnf(), (soft_cls, offset), None); - /// ``` - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_dimacs(&mut self, writer: &mut W) -> Result<(), io::Error> { + #[deprecated(since = "0.5.0", note = "use write_dimacs instead")] + pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { + #[allow(deprecated)] self.to_dimacs_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, @@ -1152,19 +1178,12 @@ impl OptInstance { /// Writes the instance to DIMACS WCNF (post 22) converting non-clausal /// constraints with specific encoders. - /// - /// # Mutability - /// - /// Since the [`SatInstance`] class (used for the internal constraints) can contain cardinality - /// and pseudo-boolean constraints that cannot be directly written to DIMACS, these constraints - /// need to be converted to CNF first. This is why this method has to take a _mutable_ - /// reference. - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated( + since = "0.5.0", + note = "use convert_to_cnf_with_encoders and write_dimacs instead" + )] pub fn to_dimacs_with_encoders( - &mut self, + self, card_encoder: CardEnc, pb_encoder: PBEnc, writer: &mut W, @@ -1174,84 +1193,131 @@ impl OptInstance { CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { - self.constrs.to_cnf_with_encoders(card_encoder, pb_encoder); + let (cnf, vm) = self + .constrs + .into_cnf_with_encoders(card_encoder, pb_encoder); + let soft_cls = self.obj.into_soft_cls(); + fio::dimacs::write_wcnf_annotated(writer, &cnf, soft_cls, Some(vm.n_used())) + } + + /// Writes the instance to a DIMACS WCNF file at a path + /// + /// This requires that the instance is clausal, i.e., does not contain any non-converted + /// cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by + /// [`SatInstance::convert_to_cnf`] or [`SatInstance::convert_to_cnf_with_encoders`] first. + /// + /// # Errors + /// + /// - If the instance is not clausal, returns [`NonClausal`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_dimacs_path>(&self, path: P) -> anyhow::Result<()> { + let mut writer = fio::open_compressed_uncompressed_write(path)?; + self.write_dimacs(&mut writer) + } + + /// Write to DIMACS WCNF (post 22) + /// + /// This requires that the instance is clausal, i.e., does not contain any non-converted + /// cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by + /// [`SatInstance::convert_to_cnf`] or [`SatInstance::convert_to_cnf_with_encoders`] first. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + /// + /// # Errors + /// + /// - If the instance is not clausal, returns [`NonClausal`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_dimacs(&self, writer: &mut W) -> anyhow::Result<()> { + if self.constrs.n_cards() > 0 || self.constrs.n_pbs() > 0 { + return Err(RequiresClausal.into()); + } let n_vars = self.constrs.n_vars(); let offset = self.obj.offset(); let soft_cls = self.obj.iter_soft_cls(); - fio::dimacs::write_wcnf_annotated( + Ok(fio::dimacs::write_wcnf_annotated( writer, &self.constrs.cnf, (soft_cls, offset), Some(n_vars), - ) + )?) } /// Writes the instance to an OPB file at a path /// - /// # Mutability - /// - /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, - /// these need to be converted to soft literals first, which modifies the instance. This is why - /// this method has to take a _mutable_ reference. + /// # Performance /// - /// If you know that the internal objective only contains soft literals, you can avoid a mutable - /// borrow by directly accessing the [`fio::opb::write_opt`] function: - /// ``` - /// # use rustsat::instances::{OptInstance, fio}; - /// # let opt_inst: OptInstance = OptInstance::from_opb_path("./data/tiny-single-opt.opb", fio::opb::Options::default()).unwrap(); - /// let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); - /// let constrs = opt_inst.constraints_ref(); - /// debug_assert_eq!(opt_inst.objective_ref().n_clauses(), 0); - /// let offset = opt_inst.objective_ref().offset(); - /// let obj = opt_inst.objective_ref().iter_soft_lits(); - /// fio::opb::write_opt(&mut writer, opt_inst.constraints_ref(), (obj, offset), fio::opb::Options::default()); - /// ``` - /// Note that this will not write the entire instance if there are soft clauses present. + /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated(since = "0.5.0", note = "use write_opb_path instead")] pub fn to_opb_path>( - &mut self, + self, path: P, opts: fio::opb::Options, ) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; + #[allow(deprecated)] self.to_opb(&mut writer, opts) } /// Writes the instance to an OPB file + #[deprecated(since = "0.5.0", note = "use write_opb instead")] + pub fn to_opb( + mut self, + writer: &mut W, + opts: fio::opb::Options, + ) -> Result<(), io::Error> { + let var_manager = self.constrs.var_manager_mut(); + self.obj.convert_to_soft_lits(var_manager); + let offset = self.obj.offset(); + let iter = self.obj.iter_soft_lits().unwrap(); + fio::opb::write_opt::(writer, &self.constrs, (iter, offset), opts) + } + + /// Writes the instance to an OPB file at a path /// - /// # Mutability + /// This requires that the objective does not contain soft clauses. If it does, use + /// [`Objective::convert_to_soft_lits`] first. /// - /// Since the [`Objective`] class can contain soft clauses rather than just soft literals, - /// these need to be converted to soft literals first, which modifies the instance. This is why - /// this method has to take a _mutable_ reference. + /// # Errors /// - /// If you know that the internal objective only contains soft literals, you can avoid a mutable - /// borrow by directly accessing the [`fio::opb::write_opt`] function: - /// ``` - /// # use rustsat::instances::{OptInstance, fio}; - /// # let opt_inst: OptInstance = OptInstance::from_opb_path("./data/tiny-single-opt.opb", fio::opb::Options::default()).unwrap(); - /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.opb").unwrap(); - /// let constrs = opt_inst.constraints_ref(); - /// debug_assert_eq!(opt_inst.objective_ref().n_clauses(), 0); - /// let offset = opt_inst.objective_ref().offset(); - /// let obj = opt_inst.objective_ref().iter_soft_lits(); - /// fio::opb::write_opt(&mut writer, opt_inst.constraints_ref(), (obj, offset), fio::opb::Options::default()); - /// ``` - /// Note that this will not write the entire instance if there are soft clauses present. + /// - If the objective containes soft literals, returns [`RequiresSoftLits`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_opb_path>( + &self, + path: P, + opts: fio::opb::Options, + ) -> anyhow::Result<()> { + let mut writer = fio::open_compressed_uncompressed_write(path)?; + self.write_opb(&mut writer, opts) + } + + /// Writes the instance to an OPB file + /// + /// This requires that the objective does not contain soft clauses. If it does, use + /// [`Objective::convert_to_soft_lits`] first. /// /// # Performance /// /// For performance, consider using a [`std::io::BufWriter`] instance(crate). - pub fn to_opb( - &mut self, + /// + /// # Errors + /// + /// - If the objective containes soft literals, returns [`RequiresSoftLits`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_opb( + &self, writer: &mut W, opts: fio::opb::Options, - ) -> Result<(), io::Error> { - let vm = self.constrs.var_manager_mut(); - let hardened = self.obj.to_soft_lits(vm); - self.constrs.cnf.extend(hardened); + ) -> anyhow::Result<()> { let offset = self.obj.offset(); - let iter = self.obj.iter_soft_lits(); - fio::opb::write_opt::(writer, &self.constrs, (iter, offset), opts) + let iter = self.obj.iter_soft_lits()?; + Ok(fio::opb::write_opt::( + writer, + &self.constrs, + (iter, offset), + opts, + )?) } /// Calculates the objective value of an assignment. Returns [`None`] if the diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index 436893dd..f599e7cd 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -10,6 +10,7 @@ use crate::{ constraints::{CardConstraint, PBConstraint}, Assignment, Clause, Lit, Var, }, + RequiresClausal, }; use anyhow::Context; @@ -197,9 +198,9 @@ impl Cnf { } /// Writes the CNF to a DIMACS CNF file at a path - pub fn to_dimacs_path>(&self, path: P, n_vars: u32) -> Result<(), io::Error> { + pub fn write_dimacs_path>(&self, path: P, n_vars: u32) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; - self.to_dimacs(&mut writer, n_vars) + self.write_dimacs(&mut writer, n_vars) } /// Writes the CNF to DIMACS CNF @@ -207,7 +208,7 @@ impl Cnf { /// # Performance /// /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_dimacs(&self, writer: &mut W, n_vars: u32) -> Result<(), io::Error> { + pub fn write_dimacs(&self, writer: &mut W, n_vars: u32) -> Result<(), io::Error> { fio::dimacs::write_cnf_annotated(writer, self, n_vars) } } @@ -492,8 +493,20 @@ impl SatInstance { /// Converts the instance to a set of clauses. /// Uses the default encoders from the `encodings` module. + #[deprecated( + since = "0.5.0", + note = "as_cnf has been renamed to into_cnf and will be removed in a future release" + )] pub fn as_cnf(self) -> (Cnf, VM) { - self.as_cnf_with_encoders( + self.into_cnf() + } + + /// Converts the instance to a set of clauses. + /// Uses the default encoders from the `encodings` module. + /// + /// See [`Self::convert_to_cnf`] for converting in place + pub fn into_cnf(self) -> (Cnf, VM) { + self.into_cnf_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, ) @@ -501,8 +514,10 @@ impl SatInstance { /// Converts the instance to a set of clauses inplace. /// Uses the default encoders from the `encodings` module. - pub fn to_cnf(&mut self) { - self.to_cnf_with_encoders( + /// + /// See [`Self::into_cnf`] if you don't need to convert in place + pub fn convert_to_cnf(&mut self) { + self.convert_to_cnf_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, ) @@ -510,7 +525,27 @@ impl SatInstance { /// Converts the instance to a set of clauses with explicitly specified /// converters for non-clausal constraints. + #[deprecated( + since = "0.5.0", + note = "as_cnf_with_encoders has been renamed to into_cnf_with_encoders and will be removed in a future release" + )] pub fn as_cnf_with_encoders( + self, + card_encoder: CardEnc, + pb_encoder: PBEnc, + ) -> (Cnf, VM) + where + CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), + PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), + { + self.into_cnf_with_encoders(card_encoder, pb_encoder) + } + + /// Converts the instance to a set of clauses with explicitly specified + /// converters for non-clausal constraints. + /// + /// See [`Self::into_cnf_with_encoders`] to convert in place + pub fn into_cnf_with_encoders( mut self, card_encoder: CardEnc, pb_encoder: PBEnc, @@ -519,13 +554,15 @@ impl SatInstance { CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { - self.to_cnf_with_encoders(card_encoder, pb_encoder); + self.convert_to_cnf_with_encoders(card_encoder, pb_encoder); (self.cnf, self.var_manager) } /// Converts the instance inplace to a set of clauses with explicitly specified /// converters for non-clausal constraints. - pub fn to_cnf_with_encoders( + /// + /// See [`Self::into_cnf_with_encoders`] if you don't need to convert in place + pub fn convert_to_cnf_with_encoders( &mut self, mut card_encoder: CardEnc, mut pb_encoder: PBEnc, @@ -580,51 +617,20 @@ impl SatInstance { /// Writes the instance to a DIMACS CNF file at a path /// - /// # Mutability - /// - /// Since the [`SatInstance`] class can contain cardinality and pseudo-boolean constraints that - /// cannot be directly written to DIMACS, these constraints need to be converted to CNF first. - /// This is why this method has to take a _mutable_ reference. + /// # Performance /// - /// If you know that the instance only contains clauses, you can avoid a mutable - /// borrow by using [`SatInstance::cnf_ref()`] and [`Cnf::to_dimacs`]. - /// ``` - /// # use rustsat::instances::SatInstance; - /// # let inst: SatInstance = SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - /// debug_assert_eq!(inst.n_cards(), 0); - /// debug_assert_eq!(inst.n_pbs(), 0); - /// let n_vars = inst.n_vars(); - /// inst.cnf().to_dimacs_path("./rustsat-test.cnf", n_vars); - /// ``` - pub fn to_dimacs_path>(&mut self, path: P) -> Result<(), io::Error> { + /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated(since = "0.5.0", note = "use write_dimacs_path instead")] + pub fn to_dimacs_path>(self, path: P) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; + #[allow(deprecated)] self.to_dimacs(&mut writer) } /// Writes the instance to DIMACS CNF - /// - /// # Mutability - /// - /// Since the [`SatInstance`] class can contain cardinality and pseudo-boolean constraints that - /// cannot be directly written to DIMACS, these constraints need to be converted to CNF first. - /// This is why this method has to take a _mutable_ reference. - /// - /// If you know that the instance only contains clauses, you can avoid a mutable - /// borrow by using [`SatInstance::cnf_ref()`] and [`Cnf::to_dimacs`]. - /// ``` - /// # use rustsat::instances::{SatInstance, fio}; - /// # let inst: SatInstance = SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - /// # let mut writer = fio::open_compressed_uncompressed_write("./rustsat-test.cnf").unwrap(); - /// debug_assert_eq!(inst.n_cards(), 0); - /// debug_assert_eq!(inst.n_pbs(), 0); - /// let n_vars = inst.n_vars(); - /// inst.cnf().to_dimacs(&mut writer, n_vars); - /// ``` - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_dimacs(&mut self, writer: &mut W) -> Result<(), io::Error> { + #[deprecated(since = "0.5.0", note = "use write_dimacs instead")] + pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { + #[allow(deprecated)] self.to_dimacs_with_encoders( card::default_encode_cardinality_constraint, pb::default_encode_pb_constraint, @@ -634,18 +640,12 @@ impl SatInstance { /// Writes the instance to DIMACS CNF converting non-clausal constraints /// with specific encoders. - /// - /// # Mutability - /// - /// Since the [`SatInstance`] class can contain cardinality and pseudo-boolean constraints that - /// cannot be directly written to DIMACS, these constraints need to be converted to CNF first. - /// This is why this method has to take a _mutable_ reference. - /// - /// # Performance - /// - /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated( + since = "0.5.0", + note = "use convert_to_cnf_with_encoders and write_dimacs instead" + )] pub fn to_dimacs_with_encoders( - &mut self, + self, card_encoder: CardEnc, pb_encoder: PBEnc, writer: &mut W, @@ -655,27 +655,89 @@ impl SatInstance { CardEnc: FnMut(CardConstraint, &mut Cnf, &mut dyn ManageVars), PBEnc: FnMut(PBConstraint, &mut Cnf, &mut dyn ManageVars), { - self.to_cnf_with_encoders(card_encoder, pb_encoder); + let (cnf, vm) = self.into_cnf_with_encoders(card_encoder, pb_encoder); + fio::dimacs::write_cnf_annotated(writer, &cnf, vm.n_used()) + } + + /// Writes the instance to a DIMACS CNF file at a path + /// + /// This requires that the instance is clausal, i.e., does not contain any non-converted + /// cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by + /// [`Self::convert_to_cnf`] or [`Self::convert_to_cnf_with_encoders`] first. + /// + /// # Errors + /// + /// - If the instance is not clausal, returns [`NonClausal`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_dimacs_path>(&self, path: P) -> anyhow::Result<()> { + let mut writer = fio::open_compressed_uncompressed_write(path)?; + self.write_dimacs(&mut writer) + } + + /// Writes the instance to DIMACS CNF + /// + /// This requires that the instance is clausal, i.e., does not contain any non-converted + /// cardinality of pseudo-boolean constraints. If necessary, the instance can be converted by + /// [`Self::convert_to_cnf`] or [`Self::convert_to_cnf_with_encoders`] first. + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + /// + /// # Errors + /// + /// - If the instance is not clausal, returns [`NonClausal`] + /// - Returns [`io::Error`] on errors during writing + pub fn write_dimacs(&self, writer: &mut W) -> anyhow::Result<()> { + if self.n_cards() > 0 || self.n_pbs() > 0 { + return Err(RequiresClausal.into()); + } let n_vars = self.n_vars(); - fio::dimacs::write_cnf_annotated(writer, &self.cnf, n_vars) + Ok(fio::dimacs::write_cnf_annotated(writer, &self.cnf, n_vars)?) } /// Writes the instance to an OPB file at a path + /// + /// # Performance + /// + /// For performance, consider using a [`std::io::BufWriter`] instance. + #[deprecated(since = "0.5.0", note = "use write_opb_path instead")] pub fn to_opb_path>( - &self, + self, path: P, opts: fio::opb::Options, ) -> Result<(), io::Error> { let mut writer = fio::open_compressed_uncompressed_write(path)?; + #[allow(deprecated)] self.to_opb(&mut writer, opts) } + /// Writes the instance to an OPB file + #[deprecated(since = "0.5.0", note = "use write_opb instead")] + pub fn to_opb( + self, + writer: &mut W, + opts: fio::opb::Options, + ) -> Result<(), io::Error> { + fio::opb::write_sat(writer, &self, opts) + } + + /// Writes the instance to an OPB file at a path + pub fn write_opb_path>( + &self, + path: P, + opts: fio::opb::Options, + ) -> Result<(), io::Error> { + let mut writer = fio::open_compressed_uncompressed_write(path)?; + self.write_opb(&mut writer, opts) + } + /// Writes the instance to an OPB file /// /// # Performance /// /// For performance, consider using a [`std::io::BufWriter`] instance. - pub fn to_opb( + pub fn write_opb( &self, writer: &mut W, opts: fio::opb::Options, @@ -716,11 +778,11 @@ impl SatInstance { return None; } if pb.is_clause() { - cnf.add_clause(pb.as_clause().unwrap()); + cnf.add_clause(pb.into_clause().unwrap()); return None; } if pb.is_card() { - cards.push(pb.as_card_constr().unwrap()); + cards.push(pb.into_card_constr().unwrap()); return None; } Some(pb) @@ -747,7 +809,7 @@ impl SatInstance { return None; } if card.is_clause() { - cnf.add_clause(card.as_clause().unwrap()); + cnf.add_clause(card.into_clause().unwrap()); return None; } Some(card) diff --git a/rustsat/src/lib.rs b/rustsat/src/lib.rs index d05d0f33..3095fcfc 100644 --- a/rustsat/src/lib.rs +++ b/rustsat/src/lib.rs @@ -88,3 +88,11 @@ impl fmt::Display for NotAllowed { #[cfg(feature = "bench")] #[cfg(test)] mod bench; + +#[derive(Error, Debug)] +#[error("operation requires a clausal constraint(s) but it is not")] +pub struct RequiresClausal; + +#[derive(Error, Debug)] +#[error("operation requires an objective only consisting of soft literals")] +pub struct RequiresSoftLits; diff --git a/rustsat/src/types/constraints.rs b/rustsat/src/types/constraints.rs index d15c20fa..664298d9 100644 --- a/rustsat/src/types/constraints.rs +++ b/rustsat/src/types/constraints.rs @@ -13,6 +13,8 @@ use thiserror::Error; use super::{Assignment, IWLitIter, Lit, LitIter, RsHashSet, TernaryVal, WLitIter}; +use crate::RequiresClausal; + /// Type representing a clause. /// Wrapper around a std collection to allow for changing the data structure. /// Optional clauses as sets will be included in the future. @@ -433,16 +435,25 @@ impl CardConstraint { } /// Converts the constraint into a clause, if possible + #[deprecated( + since = "0.5.0", + note = "as_clause has been slightly changed and renamed to into_clause and will be removed in a future release" + )] pub fn as_clause(self) -> Option { + self.into_clause().ok() + } + + /// Converts the constraint into a clause, if possible + pub fn into_clause(self) -> Result { if !self.is_clause() { - return None; + return Err(RequiresClausal); } match self { CardConstraint::UB(constr) => { - Some(Clause::from_iter(constr.lits.into_iter().map(Lit::not))) + Ok(Clause::from_iter(constr.lits.into_iter().map(Lit::not))) } - CardConstraint::LB(constr) => Some(Clause::from_iter(constr.lits)), - CardConstraint::EQ(_) => panic!(), + CardConstraint::LB(constr) => Ok(Clause::from_iter(constr.lits)), + CardConstraint::EQ(_) => unreachable!(), } } @@ -778,7 +789,16 @@ impl PBConstraint { } /// Converts the pseudo-boolean constraint into a cardinality constraint, if possible + #[deprecated( + since = "0.5.0", + note = "as_card_constr has been renamed to into_card_constr" + )] pub fn as_card_constr(self) -> Result { + self.into_card_constr() + } + + /// Converts the pseudo-boolean constraint into a cardinality constraint, if possible + pub fn into_card_constr(self) -> Result { if self.is_tautology() { return Err(PBToCardError::Tautology); } @@ -831,18 +851,27 @@ impl PBConstraint { } /// Converts the constraint into a clause, if possible + #[deprecated( + since = "0.5.0", + note = "as_clause has been slightly changed and renamed to into_clause and will be removed in a future release" + )] pub fn as_clause(self) -> Option { + self.into_clause().ok() + } + + /// Converts the constraint into a clause, if possible + pub fn into_clause(self) -> Result { if !self.is_clause() { - return None; + return Err(RequiresClausal); } match self { - PBConstraint::UB(constr) => Some(Clause::from_iter( + PBConstraint::UB(constr) => Ok(Clause::from_iter( constr.lits.into_iter().map(|(lit, _)| !lit), )), - PBConstraint::LB(constr) => Some(Clause::from_iter( + PBConstraint::LB(constr) => Ok(Clause::from_iter( constr.lits.into_iter().map(|(lit, _)| lit), )), - PBConstraint::EQ(_) => panic!(), + PBConstraint::EQ(_) => unreachable!(), } } diff --git a/rustsat/tests/compression.rs b/rustsat/tests/compression.rs index 36f88f7e..cb131106 100644 --- a/rustsat/tests/compression.rs +++ b/rustsat/tests/compression.rs @@ -9,7 +9,7 @@ fn small_sat_instance_gzip() { let inst: SatInstance = SatInstance::from_dimacs_path("./data/AProVE11-12.cnf.gz").unwrap(); let mut solver = rustsat_minisat::core::Minisat::default(); - solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.add_cnf(inst.into_cnf().0).unwrap(); let res = solver.solve().unwrap(); assert_eq!(res, SolverResult::Sat); } @@ -22,7 +22,7 @@ fn small_unsat_instance_gzip() { ) .unwrap(); let mut solver = rustsat_minisat::core::Minisat::default(); - solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.add_cnf(inst.into_cnf().0).unwrap(); let res = solver.solve().unwrap(); assert_eq!(res, SolverResult::Unsat); } @@ -32,7 +32,7 @@ fn small_sat_instance_bz2() { let inst: SatInstance = SatInstance::from_dimacs_path("./data/AProVE11-12.cnf.bz2").unwrap(); let mut solver = rustsat_minisat::core::Minisat::default(); - solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.add_cnf(inst.into_cnf().0).unwrap(); let res = solver.solve().unwrap(); assert_eq!(res, SolverResult::Sat); } @@ -45,7 +45,7 @@ fn small_unsat_instance_bz2() { ) .unwrap(); let mut solver = rustsat_minisat::core::Minisat::default(); - solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.add_cnf(inst.into_cnf().0).unwrap(); let res = solver.solve().unwrap(); assert_eq!(res, SolverResult::Unsat); } diff --git a/rustsat/tests/constraints.rs b/rustsat/tests/constraints.rs index 37aa58e7..1fc3c206 100644 --- a/rustsat/tests/constraints.rs +++ b/rustsat/tests/constraints.rs @@ -12,7 +12,7 @@ macro_rules! test_card { ( $constr:expr, $sat_assump:expr, $unsat_assump:expr ) => {{ let mut inst: SatInstance = SatInstance::new(); inst.add_card_constr($constr); - let (cnf, _) = inst.as_cnf(); + let (cnf, _) = inst.into_cnf(); println!("{:?}", cnf); let mut solver = rustsat_tools::Solver::default(); solver.add_cnf(cnf).unwrap(); @@ -31,7 +31,7 @@ macro_rules! test_pb { ( $constr:expr, $sat_assump:expr, $unsat_assump:expr ) => {{ let mut inst: SatInstance = SatInstance::new(); inst.add_pb_constr($constr); - let (cnf, _) = inst.as_cnf(); + let (cnf, _) = inst.into_cnf(); println!("{:?}", cnf); let mut solver = rustsat_tools::Solver::default(); solver.add_cnf(cnf).unwrap(); diff --git a/rustsat/tests/opb.rs b/rustsat/tests/opb.rs index f0ccdc5a..8f18f8bc 100644 --- a/rustsat/tests/opb.rs +++ b/rustsat/tests/opb.rs @@ -14,7 +14,7 @@ use rustsat::{ macro_rules! opb_test { ($path:expr, $expect:expr) => {{ let inst: SatInstance = SatInstance::from_opb_path($path, Options::default()).unwrap(); - let (cnf, _) = inst.as_cnf(); + let (cnf, _) = inst.into_cnf(); println!("{:?}", cnf); let mut solver = rustsat_minisat::core::Minisat::default(); solver.add_cnf(cnf).unwrap(); diff --git a/solvertests/src/integration.rs b/solvertests/src/integration.rs index 67aefabd..f3dee2ee 100644 --- a/solvertests/src/integration.rs +++ b/solvertests/src/integration.rs @@ -21,7 +21,7 @@ pub fn base(input: MacroInput) -> TokenStream { let mut solver = <$slv>::default(); let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) .expect("failed to parse instance"); - rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) + rustsat::solvers::Solve::add_cnf(&mut solver, inst.into_cnf().0) .expect("failed to add cnf to solver"); let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); assert_eq!(res, $res); @@ -30,7 +30,7 @@ pub fn base(input: MacroInput) -> TokenStream { let mut solver = $init; let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) .expect("failed to parse instance"); - rustsat::solvers::Solve::add_cnf(&mut solver, inst.as_cnf().0) + rustsat::solvers::Solve::add_cnf(&mut solver, inst.into_cnf().0) .expect("failed to add cnf to solver"); let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); assert_eq!(res, $res); @@ -97,7 +97,7 @@ pub fn incremental(input: MacroInput) -> TokenStream { let mut solver = init_slv!(#slv); let inst: SatInstance = SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.add_cnf(inst.into_cnf().0).unwrap(); let res = solver.solve().unwrap(); assert_eq!(res, Sat); let res = solver.solve_assumps(&[!lit![0], !lit![1]]).unwrap(); @@ -205,7 +205,7 @@ pub fn phasing(input: MacroInput) -> TokenStream { let mut solver = init_slv!(#slv); let inst: SatInstance = SatInstance::from_dimacs_path("./data/small.cnf").unwrap(); - solver.add_cnf(inst.as_cnf().0).unwrap(); + solver.add_cnf(inst.into_cnf().0).unwrap(); solver.phase_lit(lit![0]).unwrap(); solver.phase_lit(!lit![1]).unwrap(); solver.phase_lit(lit![2]).unwrap(); diff --git a/tools/src/bin/cnf2opb.rs b/tools/src/bin/cnf2opb.rs index c0153dcc..1473d014 100644 --- a/tools/src/bin/cnf2opb.rs +++ b/tools/src/bin/cnf2opb.rs @@ -35,10 +35,10 @@ fn main() { }; if let Some(out_path) = args.out_path { - inst.to_opb_path(out_path, opb_opts) + inst.write_opb_path(out_path, opb_opts) .expect("io error writing the output file"); } else { - inst.to_opb(&mut io::stdout(), opb_opts) + inst.write_opb(&mut io::stdout(), opb_opts) .expect("io error writing the output file"); } } diff --git a/tools/src/bin/enumerator.rs b/tools/src/bin/enumerator.rs index b885503f..c64b6832 100644 --- a/tools/src/bin/enumerator.rs +++ b/tools/src/bin/enumerator.rs @@ -50,7 +50,7 @@ fn main() { let inst: SatInstance = SatInstance::from_dimacs_path(in_path).expect("error parsing the input file"); - let (cnf, vm) = inst.as_cnf(); + let (cnf, vm) = inst.into_cnf(); let mut solver = rustsat_tools::Solver::default(); solver diff --git a/tools/src/bin/gbmosplit.rs b/tools/src/bin/gbmosplit.rs index 286245e7..e7d2de7c 100644 --- a/tools/src/bin/gbmosplit.rs +++ b/tools/src/bin/gbmosplit.rs @@ -252,7 +252,7 @@ fn split( ); } - let (softs, offset) = obj.as_soft_cls(); + let (softs, offset) = obj.into_soft_cls(); if offset != 0 { cli.warning(&format!( @@ -467,7 +467,7 @@ fn main() { panic!() }); - let (mut mo_inst, split_stats) = split(so_inst, &cli); + let (mo_inst, split_stats) = split(so_inst, &cli); cli.print_split_stats(split_stats); @@ -475,7 +475,7 @@ fn main() { if let Some(out_path) = &cli.out_path { if found_split || cli.always_dump { - mo_inst.to_dimacs_path(out_path).unwrap_or_else(|e| { + mo_inst.write_dimacs_path(out_path).unwrap_or_else(|e| { cli.error(&format!("io error writing the output file: {}", e)); panic!() }); diff --git a/tools/src/bin/mcnf2opb.rs b/tools/src/bin/mcnf2opb.rs index f8c740aa..d6d69b84 100644 --- a/tools/src/bin/mcnf2opb.rs +++ b/tools/src/bin/mcnf2opb.rs @@ -28,17 +28,24 @@ fn main() { no_negated_lits: args.avoid_negated_lits, }; - let mut inst: MultiOptInstance = if let Some(in_path) = args.in_path { + let inst: MultiOptInstance = if let Some(in_path) = args.in_path { MultiOptInstance::from_dimacs_path(in_path).expect("error parsing the input file") } else { MultiOptInstance::from_dimacs(io::stdin()).expect("error parsing input") }; + let (mut constr, mut objs) = inst.decompose(); + for obj in &mut objs { + let hardened = obj.convert_to_soft_lits(constr.var_manager_mut()); + constr.extend(hardened.into()); + } + let inst = MultiOptInstance::compose(constr, objs); + if let Some(out_path) = args.out_path { - inst.to_opb_path(out_path, opb_opts) + inst.write_opb_path(out_path, opb_opts) .expect("io error writing the output file"); } else { - inst.to_opb(&mut io::stdout(), opb_opts) + inst.write_opb(&mut io::stdout(), opb_opts) .expect("io error writing the output file"); } } diff --git a/tools/src/bin/opb2cnf.rs b/tools/src/bin/opb2cnf.rs index 1aed2db5..21718f89 100644 --- a/tools/src/bin/opb2cnf.rs +++ b/tools/src/bin/opb2cnf.rs @@ -35,11 +35,13 @@ fn main() { println!("{} cards", inst.n_cards()); println!("{} pbs", inst.n_pbs()); + inst.convert_to_cnf(); + if let Some(out_path) = args.out_path { - inst.to_dimacs_path(out_path) + inst.write_dimacs_path(out_path) .expect("io error writing the output file"); } else { - inst.to_dimacs(&mut io::stdout()) + inst.write_dimacs(&mut io::stdout()) .expect("io error writing to stdout"); } } diff --git a/tools/src/bin/opb2mcnf.rs b/tools/src/bin/opb2mcnf.rs index 8acf511f..373e23e8 100644 --- a/tools/src/bin/opb2mcnf.rs +++ b/tools/src/bin/opb2mcnf.rs @@ -40,12 +40,13 @@ fn main() { println!("c {} objectives", objs.len()); let mut inst = MultiOptInstance::compose(constrs, objs); + inst.constraints_mut().convert_to_cnf(); if let Some(out_path) = args.out_path { - inst.to_dimacs_path(out_path) + inst.write_dimacs_path(out_path) .expect("io error writing the output file"); } else { - inst.to_dimacs(&mut io::stdout()) + inst.write_dimacs(&mut io::stdout()) .expect("io error writing to stdout"); } } diff --git a/tools/src/bin/opb2wcnf.rs b/tools/src/bin/opb2wcnf.rs index 488480fb..ce772a0d 100644 --- a/tools/src/bin/opb2wcnf.rs +++ b/tools/src/bin/opb2wcnf.rs @@ -32,19 +32,20 @@ fn main() { }; let (constrs, obj) = inst.decompose(); - let constrs = constrs.sanitize(); + let mut constrs = constrs.sanitize(); println!("c {} clauses", constrs.n_clauses()); println!("c {} cards", constrs.n_cards()); println!("c {} pbs", constrs.n_pbs()); - let mut inst = OptInstance::compose(constrs, obj); + constrs.convert_to_cnf(); + let inst = OptInstance::compose(constrs, obj); if let Some(out_path) = args.out_path { - inst.to_dimacs_path(out_path) + inst.write_dimacs_path(out_path) .expect("io error writing the output file"); } else { - inst.to_dimacs(&mut io::stdout()) + inst.write_dimacs(&mut io::stdout()) .expect("io error writing to stdout"); } } diff --git a/tools/src/bin/shuffledimacs.rs b/tools/src/bin/shuffledimacs.rs index ae8fee5e..e24579f0 100644 --- a/tools/src/bin/shuffledimacs.rs +++ b/tools/src/bin/shuffledimacs.rs @@ -34,7 +34,7 @@ fn main() { let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() - .to_dimacs_path(out_path) + .write_dimacs_path(out_path) .expect("Could not write CNF"); } FileType::Wcnf => { @@ -44,7 +44,7 @@ fn main() { let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() - .to_dimacs_path(out_path) + .write_dimacs_path(out_path) .expect("Could not write WCNF"); } FileType::Mcnf => { @@ -54,7 +54,7 @@ fn main() { let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() - .to_dimacs_path(out_path) + .write_dimacs_path(out_path) .expect("Could not write MCNF"); } } diff --git a/tools/src/bin/wcnf2opb.rs b/tools/src/bin/wcnf2opb.rs index f428c199..ee227264 100644 --- a/tools/src/bin/wcnf2opb.rs +++ b/tools/src/bin/wcnf2opb.rs @@ -28,17 +28,22 @@ fn main() { no_negated_lits: args.avoid_negated_lits, }; - let mut inst: OptInstance = if let Some(in_path) = args.in_path { + let inst: OptInstance = if let Some(in_path) = args.in_path { OptInstance::from_dimacs_path(in_path).expect("error parsing the input file") } else { OptInstance::from_dimacs(io::stdin()).expect("error parsing input") }; + let (mut constr, mut obj) = inst.decompose(); + let hardened = obj.convert_to_soft_lits(constr.var_manager_mut()); + constr.extend(hardened.into()); + let inst = OptInstance::compose(constr, obj); + if let Some(out_path) = args.out_path { - inst.to_opb_path(out_path, opb_opts) + inst.write_opb_path(out_path, opb_opts) .expect("io error writing the output file"); } else { - inst.to_opb(&mut io::stdout(), opb_opts) + inst.write_opb(&mut io::stdout(), opb_opts) .expect("io error writing to stdout"); }; } From 066de708ff0b60f0add725864e5c28fe7b39899d Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Fri, 12 Apr 2024 16:31:54 +0300 Subject: [PATCH 14/56] feat: use anyhow in rustsat-tools --- tools/Cargo.toml | 1 + tools/src/bin/cnf2opb.rs | 12 +++++++----- tools/src/bin/encodings.rs | 8 ++++---- tools/src/bin/enumerator.rs | 10 ++++++---- tools/src/bin/mcnf2opb.rs | 12 +++++++----- tools/src/bin/opb2cnf.rs | 12 +++++++----- tools/src/bin/opb2mcnf.rs | 13 ++++++++----- tools/src/bin/opb2wcnf.rs | 12 +++++++----- tools/src/bin/shuffledimacs.rs | 16 +++++++++------- tools/src/bin/wcnf2opb.rs | 12 +++++++----- tools/src/encodings/clustering.rs | 22 ++-------------------- 11 files changed, 65 insertions(+), 65 deletions(-) diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 22c9cc1a..8dfda761 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -27,6 +27,7 @@ atty = { version = "0.2.14" } nom = "7.1.3" rand = "0.8.5" rand_chacha = "0.3.1" +anyhow = { version = "1.0.80" } [features] default = ["minisat"] diff --git a/tools/src/bin/cnf2opb.rs b/tools/src/bin/cnf2opb.rs index 1473d014..f495d115 100644 --- a/tools/src/bin/cnf2opb.rs +++ b/tools/src/bin/cnf2opb.rs @@ -2,6 +2,7 @@ //! //! A small tool for converting DIMACS CNF files to OPB. +use anyhow::Context; use clap::Parser; use rustsat::instances::{fio::opb::Options as OpbOptions, SatInstance}; use std::{io, path::PathBuf}; @@ -21,7 +22,7 @@ struct Args { avoid_negated_lits: bool, } -fn main() { +fn main() -> anyhow::Result<()> { let args = Args::parse(); let opb_opts = OpbOptions { first_var_idx: args.first_var_idx, @@ -29,16 +30,17 @@ fn main() { }; let inst: SatInstance = if let Some(in_path) = args.in_path { - SatInstance::from_dimacs_path(in_path).expect("error parsing the input file") + SatInstance::from_dimacs_path(in_path).context("error parsing the input file")? } else { - SatInstance::from_dimacs(io::stdin()).expect("error parsing input") + SatInstance::from_dimacs(io::stdin()).context("error parsing input")? }; if let Some(out_path) = args.out_path { inst.write_opb_path(out_path, opb_opts) - .expect("io error writing the output file"); + .context("error writing the output file")?; } else { inst.write_opb(&mut io::stdout(), opb_opts) - .expect("io error writing the output file"); + .context("error writing the output file")?; } + Ok(()) } diff --git a/tools/src/bin/encodings.rs b/tools/src/bin/encodings.rs index fc28c61f..95768524 100644 --- a/tools/src/bin/encodings.rs +++ b/tools/src/bin/encodings.rs @@ -14,7 +14,7 @@ use clap::{Args, Parser, Subcommand}; use rustsat::{encodings::pb, instances::fio::dimacs}; use rustsat_tools::encodings::{ - clustering::{self, saturating_map, scaling_map, Encoding, Error, Variant}, + clustering::{self, saturating_map, scaling_map, Encoding, Variant}, knapsack, }; use std::{fs::File, io, path::PathBuf}; @@ -93,7 +93,7 @@ struct KnapsackArgs { seed: u64, } -fn clustering(args: ClusteringArgs) -> Result<(), Error> { +fn clustering(args: ClusteringArgs) -> anyhow::Result<()> { let mcnf_to_wcnf = |line: dimacs::McnfLine| match line { dimacs::McnfLine::Comment(c) => dimacs::WcnfLine::Comment(c), dimacs::McnfLine::Hard(cl) => dimacs::WcnfLine::Hard(cl), @@ -149,7 +149,7 @@ fn clustering(args: ClusteringArgs) -> Result<(), Error> { Ok(()) } -fn knapsack(args: KnapsackArgs) -> Result<(), Error> { +fn knapsack(args: KnapsackArgs) -> anyhow::Result<()> { let encoding = knapsack::Encoding::new::(knapsack::Knapsack::random( args.n_items, args.n_objectives, @@ -167,7 +167,7 @@ fn knapsack(args: KnapsackArgs) -> Result<(), Error> { Ok(()) } -fn main() -> Result<(), Error> { +fn main() -> anyhow::Result<()> { let args = CliArgs::parse(); match args.cmd { diff --git a/tools/src/bin/enumerator.rs b/tools/src/bin/enumerator.rs index c64b6832..2c2efcf8 100644 --- a/tools/src/bin/enumerator.rs +++ b/tools/src/bin/enumerator.rs @@ -4,6 +4,7 @@ //! //! Usage: enumerator [dimacs cnf file] +use anyhow::Context; use rustsat::{ instances::{ManageVars, SatInstance}, solvers::{self, Solve, SolveIncremental}, @@ -45,17 +46,17 @@ impl Iterator for Enumerator { } } -fn main() { +fn main() -> anyhow::Result<()> { let in_path = std::env::args().nth(1).unwrap_or_else(|| print_usage!()); let inst: SatInstance = - SatInstance::from_dimacs_path(in_path).expect("error parsing the input file"); + SatInstance::from_dimacs_path(in_path).context("error parsing the input file")?; let (cnf, vm) = inst.into_cnf(); let mut solver = rustsat_tools::Solver::default(); solver .reserve(vm.max_var().expect("no variables in instance")) - .expect("error reserving memory in solver"); + .context("error reserving memory in solver")?; solver.add_cnf(cnf).expect("error adding cnf to solver"); let enumerator = Enumerator { @@ -63,5 +64,6 @@ fn main() { max_var: vm.max_var().unwrap(), }; - enumerator.for_each(|sol| println!("s {}", sol)) + enumerator.for_each(|sol| println!("s {}", sol)); + Ok(()) } diff --git a/tools/src/bin/mcnf2opb.rs b/tools/src/bin/mcnf2opb.rs index d6d69b84..1ab3c44c 100644 --- a/tools/src/bin/mcnf2opb.rs +++ b/tools/src/bin/mcnf2opb.rs @@ -2,6 +2,7 @@ //! //! A small tool for converting DIMACS MCNF files to OPB. +use anyhow::Context; use clap::Parser; use rustsat::instances::{fio::opb::Options as OpbOptions, MultiOptInstance}; use std::{io, path::PathBuf}; @@ -21,7 +22,7 @@ struct Args { avoid_negated_lits: bool, } -fn main() { +fn main() -> anyhow::Result<()> { let args = Args::parse(); let opb_opts = OpbOptions { first_var_idx: args.first_var_idx, @@ -29,9 +30,9 @@ fn main() { }; let inst: MultiOptInstance = if let Some(in_path) = args.in_path { - MultiOptInstance::from_dimacs_path(in_path).expect("error parsing the input file") + MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")? } else { - MultiOptInstance::from_dimacs(io::stdin()).expect("error parsing input") + MultiOptInstance::from_dimacs(io::stdin()).context("error parsing input")? }; let (mut constr, mut objs) = inst.decompose(); @@ -43,9 +44,10 @@ fn main() { if let Some(out_path) = args.out_path { inst.write_opb_path(out_path, opb_opts) - .expect("io error writing the output file"); + .context("error writing the output file")?; } else { inst.write_opb(&mut io::stdout(), opb_opts) - .expect("io error writing the output file"); + .context("error writing the output file")?; } + Ok(()) } diff --git a/tools/src/bin/opb2cnf.rs b/tools/src/bin/opb2cnf.rs index 21718f89..443a094c 100644 --- a/tools/src/bin/opb2cnf.rs +++ b/tools/src/bin/opb2cnf.rs @@ -2,6 +2,7 @@ //! //! A small tool for converting OPB files to DIMACS CNF. +use anyhow::Context; use clap::Parser; use rustsat::instances::{fio::opb::Options as OpbOptions, SatInstance}; use std::{io, path::PathBuf}; @@ -18,7 +19,7 @@ struct Args { first_var_idx: usize, } -fn main() { +fn main() -> anyhow::Result<()> { let args = Args::parse(); let opb_opts = OpbOptions { first_var_idx: 0, @@ -26,9 +27,9 @@ fn main() { }; let mut inst: SatInstance = if let Some(in_path) = args.in_path { - SatInstance::from_opb_path(in_path, opb_opts).expect("error parsing the input file") + SatInstance::from_opb_path(in_path, opb_opts).context("error parsing the input file")? } else { - SatInstance::from_opb(io::stdin(), opb_opts).expect("error parsing input") + SatInstance::from_opb(io::stdin(), opb_opts).context("error parsing input")? }; println!("{} clauses", inst.n_clauses()); @@ -39,9 +40,10 @@ fn main() { if let Some(out_path) = args.out_path { inst.write_dimacs_path(out_path) - .expect("io error writing the output file"); + .context("error writing the output file")?; } else { inst.write_dimacs(&mut io::stdout()) - .expect("io error writing to stdout"); + .context("error writing to stdout")?; } + Ok(()) } diff --git a/tools/src/bin/opb2mcnf.rs b/tools/src/bin/opb2mcnf.rs index 373e23e8..19068689 100644 --- a/tools/src/bin/opb2mcnf.rs +++ b/tools/src/bin/opb2mcnf.rs @@ -2,6 +2,7 @@ //! //! A small tool for converting OPB files to DIMACS MCNF. +use anyhow::Context; use clap::Parser; use rustsat::instances::{fio::opb::Options as OpbOptions, MultiOptInstance}; use std::{io, path::PathBuf}; @@ -18,7 +19,7 @@ struct Args { first_var_idx: usize, } -fn main() { +fn main() -> anyhow::Result<()> { let args = Args::parse(); let opb_opts = OpbOptions { first_var_idx: 0, @@ -26,9 +27,10 @@ fn main() { }; let inst: MultiOptInstance = if let Some(in_path) = args.in_path { - MultiOptInstance::from_opb_path(in_path, opb_opts).expect("error parsing the input file") + MultiOptInstance::from_opb_path(in_path, opb_opts) + .context("error parsing the input file")? } else { - MultiOptInstance::from_opb(io::stdin(), opb_opts).expect("error parsing input") + MultiOptInstance::from_opb(io::stdin(), opb_opts).context("error parsing input")? }; let (constrs, objs) = inst.decompose(); @@ -44,9 +46,10 @@ fn main() { if let Some(out_path) = args.out_path { inst.write_dimacs_path(out_path) - .expect("io error writing the output file"); + .context("error writing the output file")?; } else { inst.write_dimacs(&mut io::stdout()) - .expect("io error writing to stdout"); + .context("error writing to stdout")?; } + Ok(()) } diff --git a/tools/src/bin/opb2wcnf.rs b/tools/src/bin/opb2wcnf.rs index ce772a0d..558b847f 100644 --- a/tools/src/bin/opb2wcnf.rs +++ b/tools/src/bin/opb2wcnf.rs @@ -2,6 +2,7 @@ //! //! A small tool for converting OPB files to DIMACS WCNF. +use anyhow::Context; use clap::Parser; use rustsat::instances::{fio::opb::Options as OpbOptions, OptInstance}; use std::{io, path::PathBuf}; @@ -18,7 +19,7 @@ struct Args { first_var_idx: usize, } -fn main() { +fn main() -> anyhow::Result<()> { let args = Args::parse(); let opb_opts = OpbOptions { first_var_idx: 0, @@ -26,9 +27,9 @@ fn main() { }; let inst: OptInstance = if let Some(in_path) = args.in_path { - OptInstance::from_opb_path(in_path, opb_opts).expect("error parsing the input file") + OptInstance::from_opb_path(in_path, opb_opts).context("error parsing the input file")? } else { - OptInstance::from_opb(io::stdin(), opb_opts).expect("error parsing input") + OptInstance::from_opb(io::stdin(), opb_opts).context("error parsing input")? }; let (constrs, obj) = inst.decompose(); @@ -43,9 +44,10 @@ fn main() { if let Some(out_path) = args.out_path { inst.write_dimacs_path(out_path) - .expect("io error writing the output file"); + .context("io error writing the output file")?; } else { inst.write_dimacs(&mut io::stdout()) - .expect("io error writing to stdout"); + .context("io error writing to stdout")?; } + Ok(()) } diff --git a/tools/src/bin/shuffledimacs.rs b/tools/src/bin/shuffledimacs.rs index e24579f0..e10c61e9 100644 --- a/tools/src/bin/shuffledimacs.rs +++ b/tools/src/bin/shuffledimacs.rs @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf}; +use anyhow::Context; use rustsat::instances::{self, BasicVarManager, RandReindVarManager}; macro_rules! print_usage { @@ -22,42 +23,43 @@ enum FileType { Mcnf, } -fn main() { +fn main() -> anyhow::Result<()> { let in_path = PathBuf::from(&std::env::args().nth(1).unwrap_or_else(|| print_usage!())); let out_path = PathBuf::from(&std::env::args().nth(2).unwrap_or_else(|| print_usage!())); match determine_file_type(&in_path) { FileType::Cnf => { let inst = instances::SatInstance::::from_dimacs_path(in_path) - .expect("Could not parse CNF"); + .context("Could not parse CNF")?; let n_vars = inst.n_vars(); let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() .write_dimacs_path(out_path) - .expect("Could not write CNF"); + .context("Could not write CNF")?; } FileType::Wcnf => { let inst = instances::OptInstance::::from_dimacs_path(in_path) - .expect("Could not parse WCNF"); + .context("Could not parse WCNF")?; let n_vars = inst.constraints_ref().n_vars(); let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() .write_dimacs_path(out_path) - .expect("Could not write WCNF"); + .context("Could not write WCNF")?; } FileType::Mcnf => { let inst = instances::MultiOptInstance::::from_dimacs_path(in_path) - .expect("Could not parse MCNF"); + .context("Could not parse MCNF")?; let n_vars = inst.constraints_ref().n_vars(); let rand_reindexer = RandReindVarManager::init(n_vars); inst.reindex(rand_reindexer) .shuffle() .write_dimacs_path(out_path) - .expect("Could not write MCNF"); + .context("Could not write MCNF")?; } } + Ok(()) } macro_rules! is_one_of { diff --git a/tools/src/bin/wcnf2opb.rs b/tools/src/bin/wcnf2opb.rs index ee227264..3bccdf12 100644 --- a/tools/src/bin/wcnf2opb.rs +++ b/tools/src/bin/wcnf2opb.rs @@ -2,6 +2,7 @@ //! //! A small tool for converting DIMACS WCNF files to OPB. +use anyhow::Context; use clap::Parser; use rustsat::instances::{fio::opb::Options as OpbOptions, OptInstance}; use std::{io, path::PathBuf}; @@ -21,7 +22,7 @@ struct Args { avoid_negated_lits: bool, } -fn main() { +fn main() -> anyhow::Result<()> { let args = Args::parse(); let opb_opts = OpbOptions { first_var_idx: args.first_var_idx, @@ -29,9 +30,9 @@ fn main() { }; let inst: OptInstance = if let Some(in_path) = args.in_path { - OptInstance::from_dimacs_path(in_path).expect("error parsing the input file") + OptInstance::from_dimacs_path(in_path).context("error parsing the input file")? } else { - OptInstance::from_dimacs(io::stdin()).expect("error parsing input") + OptInstance::from_dimacs(io::stdin()).context("error parsing input")? }; let (mut constr, mut obj) = inst.decompose(); @@ -41,9 +42,10 @@ fn main() { if let Some(out_path) = args.out_path { inst.write_opb_path(out_path, opb_opts) - .expect("io error writing the output file"); + .context("error writing the output file")?; } else { inst.write_opb(&mut io::stdout(), opb_opts) - .expect("io error writing to stdout"); + .context("io error writing to stdout")?; }; + Ok(()) } diff --git a/tools/src/encodings/clustering.rs b/tools/src/encodings/clustering.rs index 00b1387b..d8b078f8 100644 --- a/tools/src/encodings/clustering.rs +++ b/tools/src/encodings/clustering.rs @@ -123,24 +123,6 @@ impl Default for VarManager { } } -#[derive(Debug)] -pub enum Error { - Io(io::Error), - Parsing(String), -} - -impl From for Error { - fn from(value: io::Error) -> Self { - Error::Io(value) - } -} - -impl From>> for Error { - fn from(value: nom::Err>) -> Self { - Error::Parsing(value.to_string()) - } -} - #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Similarity { Similar(usize), @@ -179,7 +161,7 @@ impl Encoding { in_reader: R, variant: Variant, sim_map: Map, - ) -> Result { + ) -> anyhow::Result { if variant != Variant::Binary { panic!("only the binary encoding is implemented so far"); } @@ -187,7 +169,7 @@ impl Encoding { let mut ident_map = RsHashMap::default(); let mut next_idx: u32 = 0; let process_line = - |line: Result| -> Option> { + |line: Result| -> Option> { let line = line.ok()?; let line = line.trim_start(); if line.starts_with('%') { From c7c56594a988ae17bf07229e7f3ded2827398c3c Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Fri, 12 Apr 2024 16:40:26 +0300 Subject: [PATCH 15/56] feat: have file parsers take BufRead types --- rustsat/src/instances/fio.rs | 16 +++++++++++----- rustsat/src/instances/fio/dimacs.rs | 11 ++++------- rustsat/src/instances/fio/opb.rs | 11 +++++------ rustsat/src/instances/multiopt.rs | 4 ++-- rustsat/src/instances/opt.rs | 8 ++++---- rustsat/src/instances/sat.rs | 4 ++-- tools/src/bin/cnf2opb.rs | 2 +- tools/src/bin/mcnf2opb.rs | 3 ++- tools/src/bin/opb2cnf.rs | 3 ++- tools/src/bin/opb2mcnf.rs | 3 ++- tools/src/bin/opb2wcnf.rs | 3 ++- tools/src/bin/wcnf2opb.rs | 2 +- 12 files changed, 38 insertions(+), 32 deletions(-) diff --git a/rustsat/src/instances/fio.rs b/rustsat/src/instances/fio.rs index e639eafd..f258299f 100644 --- a/rustsat/src/instances/fio.rs +++ b/rustsat/src/instances/fio.rs @@ -19,22 +19,28 @@ pub struct ObjNoExist(usize); /// With feature `compression` supports bzip2 and gzip compression. pub fn open_compressed_uncompressed_read>( path: P, -) -> Result, io::Error> { +) -> Result, io::Error> { let path = path.as_ref(); let raw_reader = File::open(path)?; #[cfg(feature = "compression")] if let Some(ext) = path.extension() { if ext.eq_ignore_ascii_case(std::ffi::OsStr::new("bz2")) { - return Ok(Box::new(bzip2::read::BzDecoder::new(raw_reader))); + return Ok(Box::new(io::BufReader::new(bzip2::read::BzDecoder::new( + raw_reader, + )))); } if ext.eq_ignore_ascii_case(std::ffi::OsStr::new("gz")) { - return Ok(Box::new(flate2::read::GzDecoder::new(raw_reader))); + return Ok(Box::new(io::BufReader::new(flate2::read::GzDecoder::new( + raw_reader, + )))); } if ext.eq_ignore_ascii_case(std::ffi::OsStr::new("xz")) { - return Ok(Box::new(xz2::read::XzDecoder::new(raw_reader))); + return Ok(Box::new(io::BufReader::new(xz2::read::XzDecoder::new( + raw_reader, + )))); } } - Ok(Box::new(raw_reader)) + Ok(Box::new(io::BufReader::new(raw_reader))) } /// Opens a writer for the file at Path. diff --git a/rustsat/src/instances/fio/dimacs.rs b/rustsat/src/instances/fio/dimacs.rs index 6f47562a..b089e012 100644 --- a/rustsat/src/instances/fio/dimacs.rs +++ b/rustsat/src/instances/fio/dimacs.rs @@ -27,7 +27,7 @@ use nom::{ }; use std::{ convert::TryFrom, - io::{self, BufRead, BufReader, Read, Write}, + io::{self, BufRead, Write}, }; use thiserror::Error; @@ -53,10 +53,9 @@ pub struct InvalidPLine(String); /// Parses a CNF instance from a reader (typically a (compressed) file) pub fn parse_cnf(reader: R) -> anyhow::Result> where - R: Read, + R: BufRead, VM: ManageVars + Default, { - let reader = BufReader::new(reader); let content = parse_dimacs(reader)?; #[cfg(not(feature = "optimization"))] { @@ -73,12 +72,11 @@ where /// (compressed) file). The objective with the index obj_idx is used. pub fn parse_wcnf_with_idx(reader: R, obj_idx: usize) -> anyhow::Result> where - R: Read, + R: BufRead, VM: ManageVars + Default, { use super::ObjNoExist; - let reader = BufReader::new(reader); let (constrs, mut objs) = parse_dimacs(reader)?; if objs.is_empty() { objs.push(Objective::default()); @@ -95,10 +93,9 @@ where /// Parses a MCNF instance (old or new format) from a reader (typically a (compressed) file) pub fn parse_mcnf(reader: R) -> anyhow::Result> where - R: Read, + R: BufRead, VM: ManageVars + Default, { - let reader = BufReader::new(reader); let (constrs, objs) = parse_dimacs(reader)?; Ok(MultiOptInstance::compose(constrs, objs)) } diff --git a/rustsat/src/instances/fio/opb.rs b/rustsat/src/instances/fio/opb.rs index 2353bef9..a2f78782 100644 --- a/rustsat/src/instances/fio/opb.rs +++ b/rustsat/src/instances/fio/opb.rs @@ -27,7 +27,7 @@ use nom::{ IResult, }; use std::{ - io::{self, BufRead, BufReader, Read, Write}, + io::{self, BufRead, Write}, num::TryFromIntError, }; @@ -92,7 +92,7 @@ enum OpbData { /// Parses the constraints from an OPB file as a [`SatInstance`] pub fn parse_sat(reader: R, opts: Options) -> anyhow::Result> where - R: Read, + R: BufRead, VM: ManageVars + Default, { let data = parse_opb_data(reader, opts)?; @@ -114,7 +114,7 @@ pub fn parse_opt_with_idx( opts: Options, ) -> anyhow::Result> where - R: Read, + R: BufRead, VM: ManageVars + Default, { use super::ObjNoExist; @@ -149,7 +149,7 @@ where /// index (starting from 0). pub fn parse_multi_opt(reader: R, opts: Options) -> anyhow::Result> where - R: Read, + R: BufRead, VM: ManageVars + Default, { let data = parse_opb_data(reader, opts)?; @@ -164,8 +164,7 @@ where } /// Parses all OPB data of a reader -fn parse_opb_data(reader: R, opts: Options) -> anyhow::Result> { - let mut reader = BufReader::new(reader); +fn parse_opb_data(mut reader: R, opts: Options) -> anyhow::Result> { let mut buf = String::new(); let mut data = vec![]; // TODO: consider not necessarily reading a full line diff --git a/rustsat/src/instances/multiopt.rs b/rustsat/src/instances/multiopt.rs index 6c8ba1e5..4ebeb142 100644 --- a/rustsat/src/instances/multiopt.rs +++ b/rustsat/src/instances/multiopt.rs @@ -455,7 +455,7 @@ impl MultiOptInstance { /// positive number preceded by an 'o', indicating what objective this soft /// clause belongs to. After that, the format is identical to a soft clause /// in a WCNF file. - pub fn from_dimacs(reader: R) -> anyhow::Result { + pub fn from_dimacs(reader: R) -> anyhow::Result { fio::dimacs::parse_mcnf(reader) } @@ -474,7 +474,7 @@ impl MultiOptInstance { /// pseudo-boolean optimization instances with multiple objectives defined. /// For details on the file format see /// [here](https://www.cril.univ-artois.fr/PB12/format.pdf). - pub fn from_opb(reader: R, opts: fio::opb::Options) -> anyhow::Result { + pub fn from_opb(reader: R, opts: fio::opb::Options) -> anyhow::Result { fio::opb::parse_multi_opt(reader, opts) } diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index c415a1ec..c8f6ef3f 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -1351,14 +1351,14 @@ impl OptInstance { /// /// If a DIMACS MCNF file is passed to this function, all objectives but the /// first are ignored. - pub fn from_dimacs(reader: R) -> anyhow::Result { + pub fn from_dimacs(reader: R) -> anyhow::Result { Self::from_dimacs_with_idx(reader, 0) } /// Parses a DIMACS instance from a reader object, selecting the objective /// with index `obj_idx` if multiple are available. The index starts at 0. /// For more details see [`OptInstance::from_dimacs`]. - pub fn from_dimacs_with_idx(reader: R, obj_idx: usize) -> anyhow::Result { + pub fn from_dimacs_with_idx(reader: R, obj_idx: usize) -> anyhow::Result { fio::dimacs::parse_wcnf_with_idx(reader, obj_idx) } @@ -1388,14 +1388,14 @@ impl OptInstance { /// The file format expected by this parser is the OPB format for /// pseudo-boolean optimization instances. For details on the file format /// see [here](https://www.cril.univ-artois.fr/PB12/format.pdf). - pub fn from_opb(reader: R, opts: fio::opb::Options) -> anyhow::Result { + pub fn from_opb(reader: R, opts: fio::opb::Options) -> anyhow::Result { Self::from_opb_with_idx(reader, 0, opts) } /// Parses an OPB instance from a reader object, selecting the objective /// with index `obj_idx` if multiple are available. The index starts at 0. /// For more details see [`OptInstance::from_opb`]. - pub fn from_opb_with_idx( + pub fn from_opb_with_idx( reader: R, obj_idx: usize, opts: fio::opb::Options, diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index f599e7cd..287cc81d 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -867,7 +867,7 @@ impl SatInstance { /// /// If a DIMACS WCNF or MCNF file is parsed with this method, the objectives /// are ignored and only the constraints returned. - pub fn from_dimacs(reader: R) -> anyhow::Result { + pub fn from_dimacs(reader: R) -> anyhow::Result { fio::dimacs::parse_cnf(reader) } @@ -887,7 +887,7 @@ impl SatInstance { /// The file format expected by this parser is the OPB format for /// pseudo-boolean satisfaction instances. For details on the file format /// see [here](https://www.cril.univ-artois.fr/PB12/format.pdf). - pub fn from_opb(reader: R, opts: fio::opb::Options) -> anyhow::Result { + pub fn from_opb(reader: R, opts: fio::opb::Options) -> anyhow::Result { fio::opb::parse_sat(reader, opts) } diff --git a/tools/src/bin/cnf2opb.rs b/tools/src/bin/cnf2opb.rs index f495d115..6242c3f9 100644 --- a/tools/src/bin/cnf2opb.rs +++ b/tools/src/bin/cnf2opb.rs @@ -32,7 +32,7 @@ fn main() -> anyhow::Result<()> { let inst: SatInstance = if let Some(in_path) = args.in_path { SatInstance::from_dimacs_path(in_path).context("error parsing the input file")? } else { - SatInstance::from_dimacs(io::stdin()).context("error parsing input")? + SatInstance::from_dimacs(io::BufReader::new(io::stdin())).context("error parsing input")? }; if let Some(out_path) = args.out_path { diff --git a/tools/src/bin/mcnf2opb.rs b/tools/src/bin/mcnf2opb.rs index 1ab3c44c..345d06b4 100644 --- a/tools/src/bin/mcnf2opb.rs +++ b/tools/src/bin/mcnf2opb.rs @@ -32,7 +32,8 @@ fn main() -> anyhow::Result<()> { let inst: MultiOptInstance = if let Some(in_path) = args.in_path { MultiOptInstance::from_dimacs_path(in_path).context("error parsing the input file")? } else { - MultiOptInstance::from_dimacs(io::stdin()).context("error parsing input")? + MultiOptInstance::from_dimacs(io::BufReader::new(io::stdin())) + .context("error parsing input")? }; let (mut constr, mut objs) = inst.decompose(); diff --git a/tools/src/bin/opb2cnf.rs b/tools/src/bin/opb2cnf.rs index 443a094c..0d8244f3 100644 --- a/tools/src/bin/opb2cnf.rs +++ b/tools/src/bin/opb2cnf.rs @@ -29,7 +29,8 @@ fn main() -> anyhow::Result<()> { let mut inst: SatInstance = if let Some(in_path) = args.in_path { SatInstance::from_opb_path(in_path, opb_opts).context("error parsing the input file")? } else { - SatInstance::from_opb(io::stdin(), opb_opts).context("error parsing input")? + SatInstance::from_opb(io::BufReader::new(io::stdin()), opb_opts) + .context("error parsing input")? }; println!("{} clauses", inst.n_clauses()); diff --git a/tools/src/bin/opb2mcnf.rs b/tools/src/bin/opb2mcnf.rs index 19068689..0bb9c873 100644 --- a/tools/src/bin/opb2mcnf.rs +++ b/tools/src/bin/opb2mcnf.rs @@ -30,7 +30,8 @@ fn main() -> anyhow::Result<()> { MultiOptInstance::from_opb_path(in_path, opb_opts) .context("error parsing the input file")? } else { - MultiOptInstance::from_opb(io::stdin(), opb_opts).context("error parsing input")? + MultiOptInstance::from_opb(io::BufReader::new(io::stdin()), opb_opts) + .context("error parsing input")? }; let (constrs, objs) = inst.decompose(); diff --git a/tools/src/bin/opb2wcnf.rs b/tools/src/bin/opb2wcnf.rs index 558b847f..f2fdf3a0 100644 --- a/tools/src/bin/opb2wcnf.rs +++ b/tools/src/bin/opb2wcnf.rs @@ -29,7 +29,8 @@ fn main() -> anyhow::Result<()> { let inst: OptInstance = if let Some(in_path) = args.in_path { OptInstance::from_opb_path(in_path, opb_opts).context("error parsing the input file")? } else { - OptInstance::from_opb(io::stdin(), opb_opts).context("error parsing input")? + OptInstance::from_opb(io::BufReader::new(io::stdin()), opb_opts) + .context("error parsing input")? }; let (constrs, obj) = inst.decompose(); diff --git a/tools/src/bin/wcnf2opb.rs b/tools/src/bin/wcnf2opb.rs index 3bccdf12..6be8aea7 100644 --- a/tools/src/bin/wcnf2opb.rs +++ b/tools/src/bin/wcnf2opb.rs @@ -32,7 +32,7 @@ fn main() -> anyhow::Result<()> { let inst: OptInstance = if let Some(in_path) = args.in_path { OptInstance::from_dimacs_path(in_path).context("error parsing the input file")? } else { - OptInstance::from_dimacs(io::stdin()).context("error parsing input")? + OptInstance::from_dimacs(io::BufReader::new(io::stdin())).context("error parsing input")? }; let (mut constr, mut obj) = inst.decompose(); From f7cbafb01cc10c10a464a03bfd3d1887e9f5a7da Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Mon, 15 Apr 2024 12:10:34 +0300 Subject: [PATCH 16/56] perf: avoid unnecessary cloning in tests and two methods of `Objective` type --- rustsat/src/instances/fio/dimacs.rs | 4 ++-- rustsat/src/instances/opt.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rustsat/src/instances/fio/dimacs.rs b/rustsat/src/instances/fio/dimacs.rs index b089e012..d121a7ed 100644 --- a/rustsat/src/instances/fio/dimacs.rs +++ b/rustsat/src/instances/fio/dimacs.rs @@ -1103,7 +1103,7 @@ mod tests { write_wcnf_annotated( &mut cursor, - &true_constrs.clone().into_cnf().0, + &true_constrs.cnf(), (true_obj.iter_soft_cls(), offset), Some(5), ) @@ -1132,7 +1132,7 @@ mod tests { write_mcnf_annotated( &mut cursor, - &true_constrs.clone().into_cnf().0, + &true_constrs.cnf(), vec![ (true_obj0.iter_soft_cls(), offset0), (true_obj1.iter_soft_cls(), offset1), diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index c8f6ef3f..9c6e6193 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -306,10 +306,10 @@ impl Objective { if let Some(unit_weight) = unit_weight { *self = IntObj::Weighted { offset: *offset, - soft_lits: soft_lits.iter_mut().map(|l| (*l, *unit_weight)).collect(), + soft_lits: soft_lits.drain(..).map(|l| (l, *unit_weight)).collect(), soft_clauses: soft_clauses - .iter_mut() - .map(|cl| (cl.clone(), *unit_weight)) + .drain(..) + .map(|cl| (cl, *unit_weight)) .collect(), } .into() @@ -336,12 +336,12 @@ impl Objective { } => { let mut soft_unit_lits = vec![]; soft_lits - .iter_mut() - .for_each(|(l, w)| soft_unit_lits.resize(soft_unit_lits.len() + *w, *l)); + .drain() + .for_each(|(l, w)| soft_unit_lits.resize(soft_unit_lits.len() + w, l)); let mut soft_unit_clauses = vec![]; - soft_clauses.iter_mut().for_each(|(cl, w)| { - soft_unit_clauses.resize(soft_unit_clauses.len() + *w, cl.clone()) - }); + soft_clauses + .drain() + .for_each(|(cl, w)| soft_unit_clauses.resize(soft_unit_clauses.len() + w, cl)); *self = IntObj::Unweighted { offset: *offset, unit_weight: Some(1), From ed615f80bff8f0e88ffbb3807e896ef6298aba41 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Mon, 15 Apr 2024 14:57:15 +0300 Subject: [PATCH 17/56] feat: `Extend<&Clause>` for solvers --- cadical/src/lib.rs | 9 +++++++++ glucose/src/core.rs | 9 +++++++++ glucose/src/simp.rs | 9 +++++++++ ipasir/src/lib.rs | 9 +++++++++ kissat/src/lib.rs | 9 +++++++++ minisat/src/core.rs | 9 +++++++++ minisat/src/simp.rs | 9 +++++++++ rustsat/src/solvers.rs | 2 +- 8 files changed, 64 insertions(+), 1 deletion(-) diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index 589ffac6..2303370f 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -351,6 +351,15 @@ impl Extend for CaDiCaL<'_, '_> { } } +impl<'a> Extend<&'a Clause> for CaDiCaL<'_, '_> { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend") + }) + } +} + impl Solve for CaDiCaL<'_, '_> { fn signature(&self) -> &'static str { let c_chars = unsafe { ffi::ccadical_signature() }; diff --git a/glucose/src/core.rs b/glucose/src/core.rs index 9b70bf8b..ab9b4769 100644 --- a/glucose/src/core.rs +++ b/glucose/src/core.rs @@ -82,6 +82,15 @@ impl Extend for Glucose { } } +impl<'a> Extend<&'a Clause> for Glucose { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend") + }) + } +} + impl Solve for Glucose { fn signature(&self) -> &'static str { let c_chars = unsafe { ffi::cglucose4_signature() }; diff --git a/glucose/src/simp.rs b/glucose/src/simp.rs index 51735f17..84fcee65 100644 --- a/glucose/src/simp.rs +++ b/glucose/src/simp.rs @@ -90,6 +90,15 @@ impl Extend for Glucose { } } +impl<'a> Extend<&'a Clause> for Glucose { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend") + }) + } +} + impl Solve for Glucose { fn signature(&self) -> &'static str { let c_chars = unsafe { ffi::cglucose4_signature() }; diff --git a/ipasir/src/lib.rs b/ipasir/src/lib.rs index 2b5a9f23..a1938893 100644 --- a/ipasir/src/lib.rs +++ b/ipasir/src/lib.rs @@ -369,6 +369,15 @@ impl Extend for IpasirSolver<'_, '_> { } } +impl<'a> Extend<&'a Clause> for IpasirSolver<'_, '_> { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend") + }) + } +} + /// cbindgen:ignore mod ffi { use super::{LearnCallbackPtr, TermCallbackPtr}; diff --git a/kissat/src/lib.rs b/kissat/src/lib.rs index 05c36dd1..e0172c8a 100644 --- a/kissat/src/lib.rs +++ b/kissat/src/lib.rs @@ -188,6 +188,15 @@ impl Extend for Kissat<'_> { } } +impl<'a> Extend<&'a Clause> for Kissat<'_> { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend") + }) + } +} + impl Solve for Kissat<'_> { fn signature(&self) -> &'static str { let c_chars = unsafe { ffi::kissat_signature() }; diff --git a/minisat/src/core.rs b/minisat/src/core.rs index 23581606..5d1200b4 100644 --- a/minisat/src/core.rs +++ b/minisat/src/core.rs @@ -82,6 +82,15 @@ impl Extend for Minisat { } } +impl<'a> Extend<&'a Clause> for Minisat { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend") + }) + } +} + impl Solve for Minisat { fn signature(&self) -> &'static str { let c_chars = unsafe { ffi::cminisat_signature() }; diff --git a/minisat/src/simp.rs b/minisat/src/simp.rs index 14e1019e..8c56b86b 100644 --- a/minisat/src/simp.rs +++ b/minisat/src/simp.rs @@ -90,6 +90,15 @@ impl Extend for Minisat { } } +impl<'a> Extend<&'a Clause> for Minisat { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(|cl| { + self.add_clause_ref(cl) + .expect("Error adding clause in extend") + }) + } +} + impl Solve for Minisat { fn signature(&self) -> &'static str { let c_chars = unsafe { ffi::cminisat_signature() }; diff --git a/rustsat/src/solvers.rs b/rustsat/src/solvers.rs index 03457e63..08917610 100644 --- a/rustsat/src/solvers.rs +++ b/rustsat/src/solvers.rs @@ -96,7 +96,7 @@ use thiserror::Error; /// Trait for all SAT solvers in this library. /// Solvers outside of this library can also implement this trait to be able to /// use them with this library. -pub trait Solve: Extend { +pub trait Solve: Extend + for<'a> Extend<&'a Clause> { /// Gets a signature of the solver implementation fn signature(&self) -> &'static str; /// Reserves memory in the solver until a maximum variables, if the solver From 783a0f07be99fe5676728d92045e0a23423bb6f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Apr 2024 21:50:23 +0000 Subject: [PATCH 18/56] build(deps): bump install-pinned/mypy Bumps [install-pinned/mypy](https://github.com/install-pinned/mypy) from c2223951641cbb406fa8526d08f0690899f130e4 to 1b1dc20bbf8c461442db4527e6f98e2ae995826f. - [Release notes](https://github.com/install-pinned/mypy/releases) - [Commits](https://github.com/install-pinned/mypy/compare/c2223951641cbb406fa8526d08f0690899f130e4...1b1dc20bbf8c461442db4527e6f98e2ae995826f) --- updated-dependencies: - dependency-name: install-pinned/mypy dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/pyapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index 1b8cdb6a..fad893df 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -90,7 +90,7 @@ jobs: - name: Install maturin from PyPI uses: install-pinned/maturin@dfebcaa782a69944b584ec164e97fbbd09885352 - name: Install mypy from PyPI - uses: install-pinned/mypy@c2223951641cbb406fa8526d08f0690899f130e4 + uses: install-pinned/mypy@1b1dc20bbf8c461442db4527e6f98e2ae995826f - name: Install python project run: maturin build -m pyapi/Cargo.toml && pip install --no-index --find-links target/wheels/ rustsat - name: Test stubs From 069a68dd591a28a6479680bf90f6d96ac7bfcb81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 06:08:57 +0000 Subject: [PATCH 19/56] build(deps): bump install-pinned/maturin Bumps [install-pinned/maturin](https://github.com/install-pinned/maturin) from dfebcaa782a69944b584ec164e97fbbd09885352 to 9ef429e73235cb3ab68a9f8677ca10a189592a5e. - [Release notes](https://github.com/install-pinned/maturin/releases) - [Commits](https://github.com/install-pinned/maturin/compare/dfebcaa782a69944b584ec164e97fbbd09885352...9ef429e73235cb3ab68a9f8677ca10a189592a5e) --- updated-dependencies: - dependency-name: install-pinned/maturin dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/pyapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index fad893df..f1168fc6 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -88,7 +88,7 @@ jobs: uses: actions/checkout@v4 - uses: Swatinem/rust-cache@v2 - name: Install maturin from PyPI - uses: install-pinned/maturin@dfebcaa782a69944b584ec164e97fbbd09885352 + uses: install-pinned/maturin@9ef429e73235cb3ab68a9f8677ca10a189592a5e - name: Install mypy from PyPI uses: install-pinned/mypy@1b1dc20bbf8c461442db4527e6f98e2ae995826f - name: Install python project From 50990b7224bcaef4ecd19823433fd528eb4a0806 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 23 Apr 2024 13:28:13 +0300 Subject: [PATCH 20/56] docs: add missing documentation --- cadical/src/lib.rs | 27 +++++++++++++++++++++++ glucose/src/lib.rs | 7 ++++++ ipasir/src/lib.rs | 3 +++ kissat/src/lib.rs | 3 +++ minisat/src/lib.rs | 7 ++++++ pyapi/src/lib.rs | 2 ++ rustsat/src/encodings.rs | 2 ++ rustsat/src/encodings/card/dbtotalizer.rs | 9 ++++++++ rustsat/src/encodings/card/totalizer.rs | 2 ++ rustsat/src/encodings/nodedb.rs | 7 ++++++ rustsat/src/encodings/pb.rs | 2 ++ rustsat/src/encodings/pb/dbgte.rs | 3 +++ rustsat/src/encodings/pb/dpw.rs | 6 +++++ rustsat/src/encodings/pb/gte.rs | 2 ++ rustsat/src/instances/sat.rs | 1 + rustsat/src/lib.rs | 7 ++++++ rustsat/src/solvers.rs | 3 +++ rustsat/src/types.rs | 8 +++++-- rustsat/src/types/constraints.rs | 4 ++++ 19 files changed, 103 insertions(+), 2 deletions(-) diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index 2303370f..0dad88a3 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -20,6 +20,8 @@ //! Without any features selected, the newest version will be used. //! If conflicting CaDiCaL versions are requested, the newest requested version will be selected. +#![warn(missing_docs)] + use core::ffi::{c_int, c_void, CStr}; use std::{cmp::Ordering, ffi::CString, fmt}; @@ -33,6 +35,7 @@ use rustsat::solvers::{ use rustsat::types::{Clause, Lit, TernaryVal, Var}; use thiserror::Error; +/// Fatal error returned if the CaDiCaL API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("cadical c-api returned an invalid value: {api_call} -> {value}")] pub struct InvalidApiReturn { @@ -274,6 +277,18 @@ impl CaDiCaL<'_, '_> { unsafe { ffi::ccadical_print_statistics(self.handle) } } + /// Executes the given number of preprocessing rounds + /// + /// # CaDiCaL Documentation + /// + /// This function executes the given number of preprocessing rounds. It is + /// similar to 'solve' with 'limits ("preprocessing", rounds)' except that + /// no CDCL nor local search, nor lucky phases are executed. The result + /// values are also the same: 0=UNKNOWN, 10=SATISFIABLE, 20=UNSATISFIABLE. + /// As 'solve' it resets current assumptions and limits before returning. + /// The numbers of rounds should not be negative. If the number of rounds + /// is zero only clauses are restored (if necessary) and top level unit + /// propagation is performed, which both take some time. pub fn simplify(&mut self, rounds: u32) -> anyhow::Result { // If already solved, return state if let InternalSolverState::Sat = self.state { @@ -305,6 +320,18 @@ impl CaDiCaL<'_, '_> { } } + /// Executes the given number of preprocessing rounds under assumptions + /// + /// # CaDiCaL Documentation + /// + /// This function executes the given number of preprocessing rounds. It is + /// similar to 'solve' with 'limits ("preprocessing", rounds)' except that + /// no CDCL nor local search, nor lucky phases are executed. The result + /// values are also the same: 0=UNKNOWN, 10=SATISFIABLE, 20=UNSATISFIABLE. + /// As 'solve' it resets current assumptions and limits before returning. + /// The numbers of rounds should not be negative. If the number of rounds + /// is zero only clauses are restored (if necessary) and top level unit + /// propagation is performed, which both take some time. pub fn simplify_assumps( &mut self, assumps: Vec, diff --git a/glucose/src/lib.rs b/glucose/src/lib.rs index 887e0038..0020227b 100644 --- a/glucose/src/lib.rs +++ b/glucose/src/lib.rs @@ -12,6 +12,8 @@ //! The version of Glucose in this crate is Version 4.2.1. //! The used C++ source repository can be found [here](https://github.com/chrjabs/glucose4). +#![warn(missing_docs)] + use rustsat::{ solvers::SolverState, types::{Lit, Var}, @@ -22,6 +24,7 @@ use thiserror::Error; pub mod core; pub mod simp; +/// Fatal error returned if the Glucose API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("glucose c-api returned an invalid value: {api_call} -> {value}")] pub struct InvalidApiReturn { @@ -29,6 +32,10 @@ pub struct InvalidApiReturn { value: c_int, } +/// Error returned if a provided assumption variable was eliminated in preprocessing by the solver +/// +/// Glucose does not support assumptions over eliminated variables. To prevent this, variables that +/// will be used as assumptions can be frozen via [`rustsat::solvers::FreezeVar`] #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("assumption variable {0} has been eliminated by glucose simplification")] pub struct AssumpEliminated(Var); diff --git a/ipasir/src/lib.rs b/ipasir/src/lib.rs index a1938893..2e53a3d8 100644 --- a/ipasir/src/lib.rs +++ b/ipasir/src/lib.rs @@ -27,6 +27,8 @@ //! println!("cargo:rustc-flags=-l dylib=stdc++"); //! ``` +#![warn(missing_docs)] + use core::ffi::{c_int, c_void, CStr}; use cpu_time::ProcessTime; @@ -40,6 +42,7 @@ use rustsat::{ }; use thiserror::Error; +/// Fatal error returned if the IPASIR API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("ipasir c-api returned an invalid value: {api_call} -> {value}")] pub struct InvalidApiReturn { diff --git a/kissat/src/lib.rs b/kissat/src/lib.rs index e0172c8a..818ab5ea 100644 --- a/kissat/src/lib.rs +++ b/kissat/src/lib.rs @@ -23,6 +23,8 @@ //! Without any features selected, the newest version will be used. //! If conflicting Kissat versions are requested, the newest requested version will be selected. +#![warn(missing_docs)] + use core::ffi::{c_int, c_uint, c_void, CStr}; use std::{ffi::CString, fmt}; @@ -37,6 +39,7 @@ use rustsat::{ }; use thiserror::Error; +/// Fatal error returned if the Kissat API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("kissat c-api returned an invalid value: {api_call} -> {value}")] pub struct InvalidApiReturn { diff --git a/minisat/src/lib.rs b/minisat/src/lib.rs index ea228a29..1fb1f2be 100644 --- a/minisat/src/lib.rs +++ b/minisat/src/lib.rs @@ -12,6 +12,8 @@ //! The version of minisat in this crate is Version 2.2.0. //! The used C++ source repository can be found [here](https://github.com/chrjabs/minisat). +#![warn(missing_docs)] + use rustsat::{ solvers::SolverState, types::{Lit, Var}, @@ -22,6 +24,7 @@ use thiserror::Error; pub mod core; pub mod simp; +/// Fatal error returned if the Minisat API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("minisat c-api returned an invalid value: {api_call} -> {value}")] pub struct InvalidApiReturn { @@ -29,6 +32,10 @@ pub struct InvalidApiReturn { value: c_int, } +/// Error returned if a provided assumption variable was eliminated in preprocessing by the solver +/// +/// Minisat does not support assumptions over eliminated variables. To prevent this, variables that +/// will be used as assumptions can be frozen via [`rustsat::solvers::FreezeVar`] #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("assumption variable {0} has been eliminated by minisat simplification")] pub struct AssumpEliminated(Var); diff --git a/pyapi/src/lib.rs b/pyapi/src/lib.rs index f5d411bf..3ef13937 100644 --- a/pyapi/src/lib.rs +++ b/pyapi/src/lib.rs @@ -12,6 +12,8 @@ //! //! Documentation for this API can be found [here](https://christophjabs.info/rustsat/pyapi/). +#![warn(missing_docs)] + use pyo3::{prelude::*, types::PySlice}; mod encodings; diff --git a/rustsat/src/encodings.rs b/rustsat/src/encodings.rs index 9e00e7b0..a30056aa 100644 --- a/rustsat/src/encodings.rs +++ b/rustsat/src/encodings.rs @@ -59,6 +59,7 @@ mod nodedb { /// Iterate over encoding inputs pub trait IterInputs { + /// The iterator type type Iter<'a>: Iterator where Self: 'a; @@ -68,6 +69,7 @@ pub trait IterInputs { /// Iterate over weighted encoding inputs pub trait IterWeightedInputs { + /// The iterator type type Iter<'a>: Iterator where Self: 'a; diff --git a/rustsat/src/encodings/card/dbtotalizer.rs b/rustsat/src/encodings/card/dbtotalizer.rs index a6f03071..59f10b11 100644 --- a/rustsat/src/encodings/card/dbtotalizer.rs +++ b/rustsat/src/encodings/card/dbtotalizer.rs @@ -45,6 +45,7 @@ pub struct DbTotalizer { } impl DbTotalizer { + /// Creates a totalizer from its internal parts #[cfg(feature = "internals")] pub fn from_raw(root: NodeId, db: TotDb) -> Self { Self { @@ -204,8 +205,11 @@ impl Extend for DbTotalizer { /// A totalizer adder node #[derive(Clone)] pub enum Node { + /// An input literal, i.e., a leaf of the tree Leaf(Lit), + /// An internal node with unit weight Unit(UnitNode), + /// An internal weighted node General(GeneralNode), } @@ -742,6 +746,10 @@ impl TotDb { } } + /// Defines a positive output, assuming that the structure is a non-weighted totalizer + /// + /// The `idx` parameter is the output index, i.e., not the value represented by the output, but + /// `value - 1`. pub fn define_pos_tot( &mut self, id: NodeId, @@ -936,6 +944,7 @@ impl TotDb { } } +/// Totalizer encoding types that do not own but reference their [`TotDb`] #[cfg(feature = "internals")] pub mod referenced { use std::cell::RefCell; diff --git a/rustsat/src/encodings/card/totalizer.rs b/rustsat/src/encodings/card/totalizer.rs index dc569f0a..4f6e6bf2 100644 --- a/rustsat/src/encodings/card/totalizer.rs +++ b/rustsat/src/encodings/card/totalizer.rs @@ -321,10 +321,12 @@ pub(super) type TotIter<'a> = std::iter::Copied>; /// accessed but only through [`Totalizer`]. #[cfg_attr(feature = "internals", visibility::make(pub))] enum Node { + /// An input literal, i.e., a leaf node of the tree Leaf { /// The input literal to the tree lit: Lit, }, + /// An internal node of the tree Internal { /// The output literals of this node out_lits: Vec>, diff --git a/rustsat/src/encodings/nodedb.rs b/rustsat/src/encodings/nodedb.rs index 6bd575e3..9d0cd699 100644 --- a/rustsat/src/encodings/nodedb.rs +++ b/rustsat/src/encodings/nodedb.rs @@ -104,6 +104,7 @@ impl SubAssign for NodeId { /// Trait for nodes in the tree #[allow(clippy::len_without_is_empty)] pub trait NodeLike { + /// The type of iterator over the node's values type ValIter: DoubleEndedIterator; /// Returns true if the node is a leaf @@ -183,6 +184,7 @@ impl NodeCon { } } + /// Creates a node connection that is offset and weighted #[cfg(any(test, feature = "internals"))] pub fn offset_weighted(id: NodeId, offset: usize, weight: usize) -> NodeCon { NodeCon { @@ -218,6 +220,7 @@ impl NodeCon { } } + /// Changes the weight of a node connection #[inline] #[cfg(feature = "internals")] pub fn reweight(self, weight: usize) -> NodeCon { @@ -227,17 +230,20 @@ impl NodeCon { } } + /// Gets the offset of the connection #[inline] pub fn offset(&self) -> usize { self.offset } + /// Gets the divisor of the connection #[inline] pub fn divisor(&self) -> usize { let div: u8 = self.divisor.into(); div.into() } + /// Gets the multiplier of the connection #[inline] pub fn multiplier(&self) -> usize { self.multiplier.into() @@ -266,6 +272,7 @@ impl NodeCon { } } + /// Maps an output value of the connection to its input value, rounding up #[inline] pub fn rev_map_round_up(&self, mut val: usize) -> usize { if let Some(limit) = self.len_limit { diff --git a/rustsat/src/encodings/pb.rs b/rustsat/src/encodings/pb.rs index ca7557e5..bb426bf9 100644 --- a/rustsat/src/encodings/pb.rs +++ b/rustsat/src/encodings/pb.rs @@ -51,7 +51,9 @@ pub mod gte; pub use gte::GeneralizedTotalizer; pub mod simulators; +/// Inverted generalized totalizer that can be used for lower bounding PB expressions pub type InvertedGeneralizedTotalizer = simulators::Inverted; +/// Double generalized totalizer that can be used for upper and lower bounding PB expressions pub type DoubleGeneralizedTotalizer = simulators::Double; diff --git a/rustsat/src/encodings/pb/dbgte.rs b/rustsat/src/encodings/pb/dbgte.rs index 3b370b9c..04552b65 100644 --- a/rustsat/src/encodings/pb/dbgte.rs +++ b/rustsat/src/encodings/pb/dbgte.rs @@ -46,6 +46,7 @@ pub struct DbGte { } impl DbGte { + /// Creates a generalized totalizer from its internal parts #[cfg(feature = "internals")] pub fn from_raw(root: NodeCon, db: TotDb, max_leaf_weight: usize) -> Self { Self { @@ -105,6 +106,7 @@ impl DbGte { } } + /// Gets the depth of the encoding, i.e., the longest path from the root to a leaf pub fn depth(&self) -> usize { self.root.map_or(0, |con| self.db[con.id].depth()) } @@ -287,6 +289,7 @@ impl Extend<(Lit, usize)> for DbGte { } } +/// Generalized totalizer encoding types that do not own but reference their [`TotDb`] #[cfg(feature = "internals")] pub mod referenced { use std::{cell::RefCell, ops::RangeBounds}; diff --git a/rustsat/src/encodings/pb/dpw.rs b/rustsat/src/encodings/pb/dpw.rs index a8cdb164..888c2b70 100644 --- a/rustsat/src/encodings/pb/dpw.rs +++ b/rustsat/src/encodings/pb/dpw.rs @@ -88,6 +88,7 @@ impl DynamicPolyWatchdog { } } +/// Type containing information about the DPW encoding structure #[cfg_attr(feature = "internals", visibility::make(pub))] #[derive(Clone)] pub(crate) struct Structure { @@ -242,6 +243,7 @@ impl FromIterator<(Lit, usize)> for DynamicPolyWatchdog { } } +/// Dynamic polynomial watchdog encoding types that do not own but reference their [`TotDb`] #[cfg(feature = "internals")] pub mod referenced { use std::{cell::RefCell, ops::RangeBounds}; @@ -444,6 +446,7 @@ type DpwIter<'a> = std::iter::Map< fn((&Lit, &usize)) -> (Lit, usize), >; +/// Builds a DPW [`Structure`] over weighted input literals #[cfg_attr(feature = "internals", visibility::make(pub))] fn build_lit_structure>( lits: LI, @@ -458,6 +461,7 @@ fn build_lit_structure>( build_structure(cons.into_iter(), tot_db, var_manager) } +/// Builds a DPW [`Structure`] from [Node connections](NodeCon) #[cfg_attr(feature = "internals", visibility::make(pub))] fn build_structure>( cons: CI, @@ -574,6 +578,7 @@ fn build_structure>( } } +/// Encodes an output of the DPW [`Structure`] #[cfg_attr(feature = "internals", visibility::make(pub))] fn encode_output( dpw: &Structure, @@ -590,6 +595,7 @@ fn encode_output( tot_db.define_pos_tot(dpw.root, oidx, collector, var_manager); } +/// Enforces an upper bound value on a DPW [`Structure`] #[cfg_attr(feature = "internals", visibility::make(pub))] fn enforce_ub(dpw: &Structure, ub: usize, tot_db: &TotDb) -> Result, Error> { let output_weight = 1 << (dpw.output_power()); diff --git a/rustsat/src/encodings/pb/gte.rs b/rustsat/src/encodings/pb/gte.rs index b42d7fe8..1ee15404 100644 --- a/rustsat/src/encodings/pb/gte.rs +++ b/rustsat/src/encodings/pb/gte.rs @@ -331,12 +331,14 @@ impl Extend<(Lit, usize)> for GeneralizedTotalizer { /// [`super::InvertedGeneralizedTotalizer`] structs. #[cfg_attr(feature = "internals", visibility::make(pub))] enum Node { + /// A weighted input literal, i.e., a leaf node of the tree Leaf { /// The input literal to the tree lit: Lit, /// The weight of the input literal weight: usize, }, + /// An internal weighted node of the tree Internal { /// The weighted output literals of this node out_lits: BTreeMap, diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index 287cc81d..ed6a55c0 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -831,6 +831,7 @@ impl SatInstance { } } + /// Checks whether the instance is satisfied by the given assignment pub fn is_sat(&self, assign: &Assignment) -> bool { for clause in self.cnf.iter() { if !clause.is_sat(assign) { diff --git a/rustsat/src/lib.rs b/rustsat/src/lib.rs index 3095fcfc..eb075db9 100644 --- a/rustsat/src/lib.rs +++ b/rustsat/src/lib.rs @@ -64,6 +64,7 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(feature = "bench", feature(test))] +#![warn(missing_docs)] use core::fmt; @@ -76,6 +77,9 @@ pub mod types; pub mod utils; +/// Error returned if the user tries to perform an action that is not allowed +/// +/// The parameter will hold an explanation of why the action is not allowed #[derive(Error, Debug)] pub struct NotAllowed(&'static str); @@ -89,10 +93,13 @@ impl fmt::Display for NotAllowed { #[cfg(test)] mod bench; +/// Error returned if an operation requires clausal constraints, but this is not the case #[derive(Error, Debug)] #[error("operation requires a clausal constraint(s) but it is not")] pub struct RequiresClausal; +/// Error returned if an operation requires an objective represented as soft literals, but this is +/// not the case #[derive(Error, Debug)] #[error("operation requires an objective only consisting of soft literals")] pub struct RequiresSoftLits; diff --git a/rustsat/src/solvers.rs b/rustsat/src/solvers.rs index 08917610..7707a4da 100644 --- a/rustsat/src/solvers.rs +++ b/rustsat/src/solvers.rs @@ -248,6 +248,7 @@ pub trait Learn<'learn> { /// Trait for all solvers that can be asynchronously interrupt. pub trait Interrupt { + /// The interrupter of the solver type Interrupter: InterruptSolver + Send + 'static; /// Gets a thread safe interrupter object that can be used to terminate the solver fn interrupter(&mut self) -> Self::Interrupter; @@ -452,7 +453,9 @@ pub enum ControlSignal { /// A solver state error #[derive(Error, Debug, Clone, PartialEq, Eq)] pub struct StateError { + /// The state required for the operation pub required_state: SolverState, + /// The state that the solver is actually in pub actual_state: SolverState, } diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index 10d13b7a..c6e260e0 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -16,18 +16,21 @@ pub use constraints::Clause; /// The hash map to use throughout the library #[cfg(feature = "fxhash")] pub type RsHashMap = rustc_hash::FxHashMap; +/// The hash map to use throughout the library #[cfg(not(feature = "fxhash"))] pub type RsHashMap = std::collections::HashMap; /// The hash set to use throughout the library #[cfg(feature = "fxhash")] pub type RsHashSet = rustc_hash::FxHashSet; +/// The hash set to use throughout the library #[cfg(not(feature = "fxhash"))] pub type RsHashSet = std::collections::HashSet; -/// The hasher to use throught the library +/// The hasher to use throughout the library #[cfg(feature = "fxhash")] pub type RsHasher = rustc_hash::FxHasher; +/// The hasher to use throughout the library #[cfg(not(feature = "fxhash"))] pub type RsHasher = std::collections::hash_map::DefaultHasher; @@ -603,6 +606,7 @@ impl Assignment { } } + /// Replaces unassigned variables in the assignment with a default value pub fn replace_dont_care(&mut self, def: bool) { self.assignment.iter_mut().for_each(|tv| { if tv == &TernaryVal::DontCare { @@ -836,7 +840,7 @@ mod tests { #[test] fn ternary_var_true() { let tv = TernaryVal::True; - assert_eq!(tv.clone().to_bool_with_def(true), true); + assert_eq!(tv.to_bool_with_def(true), true); assert_eq!(tv.to_bool_with_def(false), true); } diff --git a/rustsat/src/types/constraints.rs b/rustsat/src/types/constraints.rs index 664298d9..01021621 100644 --- a/rustsat/src/types/constraints.rs +++ b/rustsat/src/types/constraints.rs @@ -137,6 +137,7 @@ impl Clause { Some(self) } + /// Checks whether the clause is satisfied by the given assignment pub fn is_sat(&self, assign: &Assignment) -> bool { for &lit in &self.lits { if assign.lit_value(lit) == TernaryVal::True { @@ -296,6 +297,7 @@ impl fmt::Debug for Clause { } } +/// Creates a clause from a list of literals #[macro_export] macro_rules! clause { ( $($l:expr),* ) => { @@ -477,6 +479,7 @@ impl CardConstraint { } } + /// Checks whether the cardinality constraint is satisfied by the given assignment pub fn is_sat(&self, assign: &Assignment) -> bool { let count = self.iter().fold(0, |cnt, lit| { if assign.lit_value(*lit) == TernaryVal::True { @@ -904,6 +907,7 @@ impl PBConstraint { } } + /// Checks whether the PB constraint is satisfied by the given assignment pub fn is_sat(&self, assign: &Assignment) -> bool { let sum = self.iter().fold(0, |sum, (lit, coeff)| { if assign.lit_value(*lit) == TernaryVal::True { From 98a41874a10d83f6ec806084d73d1e4d6d8639b3 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 23 Apr 2024 13:31:59 +0300 Subject: [PATCH 21/56] tests: simply `TernaryVal` tests --- rustsat/src/types.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index c6e260e0..8846bfa4 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -840,22 +840,22 @@ mod tests { #[test] fn ternary_var_true() { let tv = TernaryVal::True; - assert_eq!(tv.to_bool_with_def(true), true); - assert_eq!(tv.to_bool_with_def(false), true); + assert!(tv.to_bool_with_def(true)); + assert!(tv.to_bool_with_def(false)); } #[test] fn ternary_var_false() { let tv = TernaryVal::False; - assert_eq!(tv.clone().to_bool_with_def(true), false); - assert_eq!(tv.to_bool_with_def(false), false); + assert!(!tv.to_bool_with_def(true)); + assert!(!tv.to_bool_with_def(false)); } #[test] fn ternary_var_dnc() { let tv = TernaryVal::DontCare; - assert_eq!(tv.clone().to_bool_with_def(true), true); - assert_eq!(tv.to_bool_with_def(false), false); + assert!(tv.to_bool_with_def(true)); + assert!(!tv.to_bool_with_def(false)); } #[test] From 466749b5fbfca83ee2a0d8c52225b59f5a843480 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 23 Apr 2024 13:44:57 +0300 Subject: [PATCH 22/56] docs: fix broken links --- rustsat/src/instances/multiopt.rs | 4 ++-- rustsat/src/instances/opt.rs | 4 ++-- rustsat/src/instances/sat.rs | 4 ++-- rustsat/src/types.rs | 4 ++-- tools/src/bin/shuffledimacs.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rustsat/src/instances/multiopt.rs b/rustsat/src/instances/multiopt.rs index 4ebeb142..ce0e56dd 100644 --- a/rustsat/src/instances/multiopt.rs +++ b/rustsat/src/instances/multiopt.rs @@ -283,7 +283,7 @@ impl MultiOptInstance { /// /// # Errors /// - /// - If the instance is not clausal, returns [`NonClausal`] + /// - If the instance is not clausal, returns [`RequiresClausal`] /// - Returns [`io::Error`] on errors during writing pub fn write_dimacs_path>(&self, path: P) -> anyhow::Result<()> { let mut writer = fio::open_compressed_uncompressed_write(path)?; @@ -302,7 +302,7 @@ impl MultiOptInstance { /// /// # Errors /// - /// - If the instance is not clausal, returns [`NonClausal`] + /// - If the instance is not clausal, returns [`RequiresClausal`] /// - Returns [`io::Error`] on errors during writing pub fn write_dimacs(&self, writer: &mut W) -> anyhow::Result<()> { if self.constrs.n_cards() > 0 || self.constrs.n_pbs() > 0 { diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index 9c6e6193..86c439d3 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -1208,7 +1208,7 @@ impl OptInstance { /// /// # Errors /// - /// - If the instance is not clausal, returns [`NonClausal`] + /// - If the instance is not clausal, returns [`RequiresClausal`] /// - Returns [`io::Error`] on errors during writing pub fn write_dimacs_path>(&self, path: P) -> anyhow::Result<()> { let mut writer = fio::open_compressed_uncompressed_write(path)?; @@ -1227,7 +1227,7 @@ impl OptInstance { /// /// # Errors /// - /// - If the instance is not clausal, returns [`NonClausal`] + /// - If the instance is not clausal, returns [`RequiresClausal`] /// - Returns [`io::Error`] on errors during writing pub fn write_dimacs(&self, writer: &mut W) -> anyhow::Result<()> { if self.constrs.n_cards() > 0 || self.constrs.n_pbs() > 0 { diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index ed6a55c0..b765983e 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -667,7 +667,7 @@ impl SatInstance { /// /// # Errors /// - /// - If the instance is not clausal, returns [`NonClausal`] + /// - If the instance is not clausal, returns [`RequiresClausal`] /// - Returns [`io::Error`] on errors during writing pub fn write_dimacs_path>(&self, path: P) -> anyhow::Result<()> { let mut writer = fio::open_compressed_uncompressed_write(path)?; @@ -686,7 +686,7 @@ impl SatInstance { /// /// # Errors /// - /// - If the instance is not clausal, returns [`NonClausal`] + /// - If the instance is not clausal, returns [`RequiresClausal`] /// - Returns [`io::Error`] on errors during writing pub fn write_dimacs(&self, writer: &mut W) -> anyhow::Result<()> { if self.n_cards() > 0 || self.n_pbs() > 0 { diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index 8846bfa4..3c9ccdba 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -155,7 +155,7 @@ impl Var { /// will have idx+1 and be negative if the literal is negated. Returns /// `Err(TypeError::IdxTooHigh(_, _))` if the literal does not fit into a `c_int`. As [`c_int` /// will almost always be `i32`](https://doc.rust-lang.org/std/os/raw/type.c_int.html), it is - /// mostly safe to simply use [`to_ipasir`] instead. + /// mostly safe to simply use [`Self::to_ipasir`] instead. pub fn to_ipasir_with_error(self) -> Result { (self.idx32() + 1) .try_into() @@ -396,7 +396,7 @@ impl Lit { /// will have idx+1 and be negative if the literal is negated. Returns /// `Err(TypeError::IdxTooHigh(_, _))` if the literal does not fit into a `c_int`. As [`c_int` /// will almost always be `i32`](https://doc.rust-lang.org/std/os/raw/type.c_int.html), it is - /// mostly safe to simply use [`to_ipasir`] instead. + /// mostly safe to simply use [`Self::to_ipasir`] instead. pub fn to_ipasir_with_error(self) -> Result { let negated = self.is_neg(); let idx: c_int = match (self.vidx() + 1).try_into() { diff --git a/tools/src/bin/shuffledimacs.rs b/tools/src/bin/shuffledimacs.rs index e10c61e9..71f28ef9 100644 --- a/tools/src/bin/shuffledimacs.rs +++ b/tools/src/bin/shuffledimacs.rs @@ -3,7 +3,7 @@ //! A small tool for shuffling the order of constraints and the variable //! indexing in a DIMACS file. //! -//! Usage: shuffledimacs [dimacs [m,w]cnf file] [output path] +//! Usage: `shuffledimacs [dimacs [m,w]cnf file] [output path]` use std::path::{Path, PathBuf}; From ba7bda7674f937aff61ce3cefa7a2c7cd79da7c9 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 23 Apr 2024 15:22:18 +0300 Subject: [PATCH 23/56] tests: check solutions in solver tests --- solvertests/src/integration.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/solvertests/src/integration.rs b/solvertests/src/integration.rs index f3dee2ee..018d272a 100644 --- a/solvertests/src/integration.rs +++ b/solvertests/src/integration.rs @@ -21,19 +21,29 @@ pub fn base(input: MacroInput) -> TokenStream { let mut solver = <$slv>::default(); let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) .expect("failed to parse instance"); - rustsat::solvers::Solve::add_cnf(&mut solver, inst.into_cnf().0) + rustsat::solvers::Solve::add_cnf_ref(&mut solver, inst.cnf()) .expect("failed to add cnf to solver"); let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); assert_eq!(res, $res); + if $res == rustsat::solvers::SolverResult::Sat { + let sol = rustsat::solvers::Solve::solution(&solver, inst.max_var().expect("no variables in instance")) + .expect("failed to get solution from solver"); + assert!(inst.is_sat(&sol)); + } }}; ($init:expr, $inst:expr, $res:expr) => {{ let mut solver = $init; let inst = rustsat::instances::SatInstance::::from_dimacs_path($inst) .expect("failed to parse instance"); - rustsat::solvers::Solve::add_cnf(&mut solver, inst.into_cnf().0) + rustsat::solvers::Solve::add_cnf_ref(&mut solver, inst.cnf()) .expect("failed to add cnf to solver"); let res = rustsat::solvers::Solve::solve(&mut solver).expect("failed solving"); assert_eq!(res, $res); + if $res == rustsat::solvers::SolverResult::Sat { + let sol = rustsat::solvers::Solve::solution(&solver, inst.max_var().expect("no variables in instance")) + .expect("failed to get solution from solver"); + assert!(inst.is_sat(&sol)); + } }}; } }; From eaa96b3b21f0c03b7fd1d9f0cf5ef486b5f41269 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:16:25 +0000 Subject: [PATCH 24/56] build(deps): bump install-pinned/mypy Bumps [install-pinned/mypy](https://github.com/install-pinned/mypy) from 1b1dc20bbf8c461442db4527e6f98e2ae995826f to 421cd57ee7b88af310624e2c56ed6902f70e1429. - [Release notes](https://github.com/install-pinned/mypy/releases) - [Commits](https://github.com/install-pinned/mypy/compare/1b1dc20bbf8c461442db4527e6f98e2ae995826f...421cd57ee7b88af310624e2c56ed6902f70e1429) --- updated-dependencies: - dependency-name: install-pinned/mypy dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/pyapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index f1168fc6..3bacde19 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -90,7 +90,7 @@ jobs: - name: Install maturin from PyPI uses: install-pinned/maturin@9ef429e73235cb3ab68a9f8677ca10a189592a5e - name: Install mypy from PyPI - uses: install-pinned/mypy@1b1dc20bbf8c461442db4527e6f98e2ae995826f + uses: install-pinned/mypy@421cd57ee7b88af310624e2c56ed6902f70e1429 - name: Install python project run: maturin build -m pyapi/Cargo.toml && pip install --no-index --find-links target/wheels/ rustsat - name: Test stubs From 060291ccd705207a7973d5190d9980cfa501a53e Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 16 Apr 2024 14:36:22 +0300 Subject: [PATCH 25/56] example: `minisat-cli` tool --- minisat/Cargo.toml | 2 + minisat/examples/minisat-cli.rs | 136 ++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 minisat/examples/minisat-cli.rs diff --git a/minisat/Cargo.toml b/minisat/Cargo.toml index ebae177f..314f5f3d 100644 --- a/minisat/Cargo.toml +++ b/minisat/Cargo.toml @@ -33,3 +33,5 @@ cmake = "0.1.50" [dev-dependencies] rustsat-solvertests = { path = "../solvertests" } +clap = { version = "4.5.4", features = ["derive"] } +signal-hook = { version = "0.3.17" } diff --git a/minisat/examples/minisat-cli.rs b/minisat/examples/minisat-cli.rs new file mode 100644 index 00000000..48ccc23e --- /dev/null +++ b/minisat/examples/minisat-cli.rs @@ -0,0 +1,136 @@ +//! # Minisat CLI Tool +//! +//! A simple CLI wrapper around the MiniSAT solver Rust interface. This is just an example, if you +//! want to use MiniSAT from the CLI, compile the binary from the C++ source directly. + +use std::{ + io, + path::{Path, PathBuf}, + thread, +}; + +use anyhow::Context; +use clap::Parser; +use rustsat::{ + instances::{fio::opb, ManageVars, SatInstance}, + solvers::{Interrupt, InterruptSolver, Solve, SolveStats, SolverResult}, +}; +use rustsat_minisat::{core, simp}; + +enum FileType { + Cnf, + Opb, +} + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Args { + /// The DIMACS CNF input file. Reads from `stdin` if not given. + in_path: Option, + /// Use the version of MiniSAT with preprocessing + #[arg(short, long)] + simp: bool, + /// Parse the input as an OPB file by default + #[arg(short, long)] + opb: bool, +} + +fn main() -> anyhow::Result<()> { + let args = Args::parse(); + + let inst: SatInstance = if let Some(in_path) = args.in_path { + match determine_file_type(&in_path, args.opb) { + FileType::Cnf => SatInstance::from_dimacs_path(in_path) + .context("error parsing the input file as CNF")?, + FileType::Opb => SatInstance::from_opb_path(in_path, opb::Options::default()) + .context("error parsing the input file as OPB")?, + } + } else if args.opb { + SatInstance::from_opb(io::BufReader::new(io::stdin()), opb::Options::default()) + .context("error parsing input as OPB")? + } else { + SatInstance::from_dimacs(io::BufReader::new(io::stdin())) + .context("error parsing input as CNF")? + }; + + if args.simp { + solve::(inst) + } else { + solve::(inst) + } +} + +fn solve(inst: SatInstance) -> anyhow::Result<()> { + let mut solver = S::default(); + + #[cfg(not(target_family = "windows"))] + { + // Setup signal handling + let interrupter = solver.interrupter(); + let mut signals = signal_hook::iterator::Signals::new([ + signal_hook::consts::SIGTERM, + signal_hook::consts::SIGINT, + signal_hook::consts::SIGXCPU, + signal_hook::consts::SIGABRT, + ])?; + // Thread for catching incoming signals + thread::spawn(move || { + for _ in signals.forever() { + interrupter.interrupt(); + } + }); + } + + let (cnf, vm) = inst.into_cnf(); + if let Some(max_var) = vm.max_var() { + solver.reserve(max_var)?; + } + solver.add_cnf(cnf)?; + match solver.solve() { + Err(err) => { + println!("s UNKNOWN"); + return Err(err); + } + Ok(res) => match res { + SolverResult::Sat => { + println!("s SATISFIABLE"); + println!("v {}", solver.full_solution()?); + } + SolverResult::Unsat => println!("s UNSATISFIABLE"), + SolverResult::Interrupted => println!("s UNKNOWN"), + }, + }; + Ok(()) +} + +macro_rules! is_one_of { + ($a:expr, $($b:expr),*) => { + $( $a == $b || )* false + } +} + +fn determine_file_type(in_path: &Path, opb_default: bool) -> FileType { + if let Some(ext) = in_path.extension() { + let path_without_compr = in_path.with_extension(""); + let ext = if is_one_of!(ext, "gz", "bz2") { + // Strip compression extension + match path_without_compr.extension() { + Some(ext) => ext, + None => return FileType::Cnf, // Fallback default + } + } else { + ext + }; + if "opb" == ext { + return FileType::Opb; + }; + if "cnf" == ext { + return FileType::Cnf; + } + }; + if opb_default { + FileType::Opb + } else { + FileType::Cnf + } // Fallback default +} From e837c478fa44338eeeb76c59128797c812839204 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Wed, 17 Apr 2024 12:45:53 +0300 Subject: [PATCH 26/56] feat: catch memory out in solvers Implemented for - Minisat - Glucose - CaDiCaL --- cadical/patches/v150.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v154.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v156.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v160.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v170.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v171.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v180.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v190.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/patches/v192.patch | 77 ++++++++++++++++++++++++++++++-------- cadical/src/lib.rs | 65 +++++++++++++++++++++++--------- cadical/test-all.sh | 24 ++++++++++++ glucose/cppsrc | 2 +- glucose/src/core.rs | 26 ++++++++----- glucose/src/lib.rs | 13 +++++++ glucose/src/simp.rs | 26 ++++++++----- minisat/cppsrc | 2 +- minisat/src/core.rs | 26 +++++++------ minisat/src/lib.rs | 13 +++++++ minisat/src/simp.rs | 26 +++++++------ rustsat/src/lib.rs | 4 ++ 20 files changed, 724 insertions(+), 196 deletions(-) diff --git a/cadical/patches/v150.patch b/cadical/patches/v150.patch index 9d228f7a..22af07d6 100644 --- a/cadical/patches/v150.patch +++ b/cadical/patches/v150.patch @@ -1,14 +1,14 @@ -From d153963a145ae94c0f3ce695ec1dc89fe73a9815 Mon Sep 17 00:00:00 2001 +From cc5a76a68bd5f05b0b45c9d335605521228e7d5d Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Wed, 23 Aug 2023 11:30:43 +0300 +Date: Thu, 18 Apr 2024 15:04:18 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 ++++++ - src/ccadical.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 17 +++++++++++++++ - src/solver.cpp | 24 +++++++++++++++++++++ - 4 files changed, 101 insertions(+) + src/cadical.hpp | 6 ++++ + src/ccadical.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 24 +++++++++++++ + src/solver.cpp | 24 +++++++++++++ + 4 files changed, 148 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index cbe476d..e5e8a9f 100644 @@ -28,10 +28,10 @@ index cbe476d..e5e8a9f 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index e6e7d28..7fabb24 100644 +index e6e7d28..853d11c 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -177,4 +177,58 @@ int ccadical_frozen (CCaDiCaL * ptr, int lit) { +@@ -177,4 +177,98 @@ int ccadical_frozen (CCaDiCaL * ptr, int lit) { return ((Wrapper*) ptr)->solver->frozen (lit); } @@ -39,6 +39,41 @@ index e6e7d28..7fabb24 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -72,8 +107,13 @@ index e6e7d28..7fabb24 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -91,15 +131,22 @@ index e6e7d28..7fabb24 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 332f842..1a141f4 100644 +index 332f842..db41678 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,23 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,30 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -108,7 +155,7 @@ index 332f842..1a141f4 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -154,5 +201,5 @@ index 31b1610..a079861 100644 void Solver::freeze (int lit) { -- -2.41.0 +2.44.0 diff --git a/cadical/patches/v154.patch b/cadical/patches/v154.patch index 88f6f5a8..099de647 100644 --- a/cadical/patches/v154.patch +++ b/cadical/patches/v154.patch @@ -1,14 +1,14 @@ -From 0a29abb1115e1bf09819f27fb3fb2db09f0b6759 Mon Sep 17 00:00:00 2001 +From 3465e6b4145153961fad7d7d7b8e87f2f1992d33 Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Wed, 23 Aug 2023 11:30:43 +0300 +Date: Thu, 18 Apr 2024 15:05:41 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 +++++++++++++++++++ - 4 files changed, 111 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 158 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index 066c94b..fa252af 100644 @@ -28,10 +28,10 @@ index 066c94b..fa252af 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index e6e7d28..0d1ebad 100644 +index e6e7d28..0c2ca8a 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -177,4 +177,66 @@ int ccadical_frozen (CCaDiCaL * ptr, int lit) { +@@ -177,4 +177,106 @@ int ccadical_frozen (CCaDiCaL * ptr, int lit) { return ((Wrapper*) ptr)->solver->frozen (lit); } @@ -39,6 +39,41 @@ index e6e7d28..0d1ebad 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -72,8 +107,13 @@ index e6e7d28..0d1ebad 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -99,15 +139,22 @@ index e6e7d28..0d1ebad 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 332f842..4c75ce4 100644 +index 332f842..4fc2ac4 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -116,7 +163,7 @@ index 332f842..4c75ce4 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -164,5 +211,5 @@ index 5648101..f7e7a34 100644 void Solver::freeze (int lit) { -- -2.41.0 +2.44.0 diff --git a/cadical/patches/v156.patch b/cadical/patches/v156.patch index 2ff822e0..6aa6c3a4 100644 --- a/cadical/patches/v156.patch +++ b/cadical/patches/v156.patch @@ -1,14 +1,14 @@ -From bbbb4a0392a79340f407e816d4b368468203a052 Mon Sep 17 00:00:00 2001 +From ad523d39c9f1b187911b9c4b4e7ffd030c14821e Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Wed, 23 Aug 2023 11:30:43 +0300 +Date: Thu, 18 Apr 2024 15:06:54 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 ++++++++++++++++++ - 4 files changed, 112 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 159 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index 49310c7..7e40f1d 100644 @@ -28,10 +28,10 @@ index 49310c7..7e40f1d 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index ac11e44..9f7c943 100644 +index ac11e44..4caf767 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -173,4 +173,67 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { +@@ -173,4 +173,107 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { int ccadical_frozen (CCaDiCaL *ptr, int lit) { return ((Wrapper *) ptr)->solver->frozen (lit); } @@ -40,6 +40,41 @@ index ac11e44..9f7c943 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -73,8 +108,13 @@ index ac11e44..9f7c943 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -100,15 +140,22 @@ index ac11e44..9f7c943 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 30a79b3..56fb16b 100644 +index 30a79b3..ca11867 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -117,7 +164,7 @@ index 30a79b3..56fb16b 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -165,5 +212,5 @@ index 63293ad..d1153d6 100644 void Solver::freeze (int lit) { -- -2.41.0 +2.44.0 diff --git a/cadical/patches/v160.patch b/cadical/patches/v160.patch index 1c01fc34..06d3011c 100644 --- a/cadical/patches/v160.patch +++ b/cadical/patches/v160.patch @@ -1,14 +1,14 @@ -From 978c6b563055207218334ea9979802d5367cc09f Mon Sep 17 00:00:00 2001 +From 6cf91b4876a3887f8d676e3092ded5debfd03682 Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Wed, 23 Aug 2023 11:30:43 +0300 +Date: Thu, 18 Apr 2024 15:07:07 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 ++++++++++++++++++ - 4 files changed, 112 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 159 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index 26cb9ca..d7539fc 100644 @@ -28,10 +28,10 @@ index 26cb9ca..d7539fc 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index ac11e44..9f7c943 100644 +index ac11e44..4caf767 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -173,4 +173,67 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { +@@ -173,4 +173,107 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { int ccadical_frozen (CCaDiCaL *ptr, int lit) { return ((Wrapper *) ptr)->solver->frozen (lit); } @@ -40,6 +40,41 @@ index ac11e44..9f7c943 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -73,8 +108,13 @@ index ac11e44..9f7c943 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -100,15 +140,22 @@ index ac11e44..9f7c943 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 30a79b3..56fb16b 100644 +index 30a79b3..ca11867 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -117,7 +164,7 @@ index 30a79b3..56fb16b 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -165,5 +212,5 @@ index 9ac3887..fd964fd 100644 void Solver::freeze (int lit) { -- -2.41.0 +2.44.0 diff --git a/cadical/patches/v170.patch b/cadical/patches/v170.patch index 4a04bba8..81a9cb23 100644 --- a/cadical/patches/v170.patch +++ b/cadical/patches/v170.patch @@ -1,14 +1,14 @@ -From 9f5fe5b55adccf8ff01a6e2934983f61d78a91c7 Mon Sep 17 00:00:00 2001 +From 3587ae5e0ef8385c9736caa1c00b15b999ff67d3 Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Wed, 23 Aug 2023 11:30:43 +0300 +Date: Thu, 18 Apr 2024 15:07:29 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 ++++++++++++++++++ - 4 files changed, 112 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 159 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index 26cb9ca..d7539fc 100644 @@ -28,10 +28,10 @@ index 26cb9ca..d7539fc 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index ac11e44..9f7c943 100644 +index ac11e44..4caf767 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -173,4 +173,67 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { +@@ -173,4 +173,107 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { int ccadical_frozen (CCaDiCaL *ptr, int lit) { return ((Wrapper *) ptr)->solver->frozen (lit); } @@ -40,6 +40,41 @@ index ac11e44..9f7c943 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -73,8 +108,13 @@ index ac11e44..9f7c943 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -100,15 +140,22 @@ index ac11e44..9f7c943 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 30a79b3..56fb16b 100644 +index 30a79b3..ca11867 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -117,7 +164,7 @@ index 30a79b3..56fb16b 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -165,5 +212,5 @@ index 3887a97..6b1727b 100644 void Solver::freeze (int lit) { -- -2.41.0 +2.44.0 diff --git a/cadical/patches/v171.patch b/cadical/patches/v171.patch index 645b4c13..bc6231d2 100644 --- a/cadical/patches/v171.patch +++ b/cadical/patches/v171.patch @@ -1,14 +1,14 @@ -From 1f7e50a76d83dd4c8d6cf9a7c7e129af2d8ad34c Mon Sep 17 00:00:00 2001 +From f3f9648731952547da82db36544d59916032da78 Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Mon, 4 Sep 2023 10:53:33 +0300 +Date: Thu, 18 Apr 2024 15:07:50 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 ++++++++++++++++++ - 4 files changed, 112 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 159 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index 0991695..d6b9357 100644 @@ -28,10 +28,10 @@ index 0991695..d6b9357 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index ac11e44..9f7c943 100644 +index ac11e44..4caf767 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -173,4 +173,67 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { +@@ -173,4 +173,107 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { int ccadical_frozen (CCaDiCaL *ptr, int lit) { return ((Wrapper *) ptr)->solver->frozen (lit); } @@ -40,6 +40,41 @@ index ac11e44..9f7c943 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -73,8 +108,13 @@ index ac11e44..9f7c943 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -100,15 +140,22 @@ index ac11e44..9f7c943 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 30a79b3..56fb16b 100644 +index 30a79b3..ca11867 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -117,7 +164,7 @@ index 30a79b3..56fb16b 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -165,5 +212,5 @@ index 5a5733c..4cbf0bb 100644 void Solver::freeze (int lit) { -- -2.41.0 +2.44.0 diff --git a/cadical/patches/v180.patch b/cadical/patches/v180.patch index 6f846f0a..74155960 100644 --- a/cadical/patches/v180.patch +++ b/cadical/patches/v180.patch @@ -1,14 +1,14 @@ -From e83aaf6d9a15bb93ac2c802c44f5b51c235f3912 Mon Sep 17 00:00:00 2001 +From 30acbccfcc4dd30dde3c39a022a019045c8dca2b Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Tue, 3 Oct 2023 13:39:32 +0300 +Date: Thu, 18 Apr 2024 15:08:09 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 ++++++++++++++++++ - 4 files changed, 112 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 159 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index 0ce3e82..5857d3a 100644 @@ -28,10 +28,10 @@ index 0ce3e82..5857d3a 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index ac11e44..9f7c943 100644 +index ac11e44..4caf767 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -173,4 +173,67 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { +@@ -173,4 +173,107 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { int ccadical_frozen (CCaDiCaL *ptr, int lit) { return ((Wrapper *) ptr)->solver->frozen (lit); } @@ -40,6 +40,41 @@ index ac11e44..9f7c943 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -73,8 +108,13 @@ index ac11e44..9f7c943 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -100,15 +140,22 @@ index ac11e44..9f7c943 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 30a79b3..56fb16b 100644 +index 30a79b3..ca11867 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -117,7 +164,7 @@ index 30a79b3..56fb16b 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -165,5 +212,5 @@ index 520664d..72e56dc 100644 void Solver::freeze (int lit) { -- -2.41.0 +2.44.0 diff --git a/cadical/patches/v190.patch b/cadical/patches/v190.patch index ebfd9ffd..61a9b3a5 100644 --- a/cadical/patches/v190.patch +++ b/cadical/patches/v190.patch @@ -1,14 +1,14 @@ -From d19b6b97766982fe80b4ff8d030d34ffedede473 Mon Sep 17 00:00:00 2001 +From 660b1b5950f0d2872a47b89c2bd4aa73acdd8a5e Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Mon, 18 Dec 2023 10:35:19 +0200 +Date: Thu, 18 Apr 2024 15:08:22 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 ++++++++++++++++++ - 4 files changed, 112 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 159 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index 3270592..dc125d7 100644 @@ -28,10 +28,10 @@ index 3270592..dc125d7 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index ac11e44..9f7c943 100644 +index ac11e44..4caf767 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -173,4 +173,67 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { +@@ -173,4 +173,107 @@ void ccadical_melt (CCaDiCaL *ptr, int lit) { int ccadical_frozen (CCaDiCaL *ptr, int lit) { return ((Wrapper *) ptr)->solver->frozen (lit); } @@ -40,6 +40,41 @@ index ac11e44..9f7c943 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -73,8 +108,13 @@ index ac11e44..9f7c943 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -100,15 +140,22 @@ index ac11e44..9f7c943 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 30a79b3..56fb16b 100644 +index 30a79b3..ca11867 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -50,6 +50,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -50,6 +50,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -117,7 +164,7 @@ index 30a79b3..56fb16b 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -165,5 +212,5 @@ index 590d3f1..1ec241e 100644 void Solver::freeze (int lit) { -- -2.43.0 +2.44.0 diff --git a/cadical/patches/v192.patch b/cadical/patches/v192.patch index 279df042..4f454e4e 100644 --- a/cadical/patches/v192.patch +++ b/cadical/patches/v192.patch @@ -1,14 +1,14 @@ -From d68b6ded46632f026f812efc00a23c345083788f Mon Sep 17 00:00:00 2001 +From 6b7a1295f3703bf640009206310fcb9b69f14a68 Mon Sep 17 00:00:00 2001 From: Christoph Jabs -Date: Mon, 18 Dec 2023 10:44:47 +0200 +Date: Thu, 18 Apr 2024 15:09:21 +0300 Subject: [PATCH] extend C api --- - src/cadical.hpp | 6 +++++ - src/ccadical.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ - src/ccadical.h | 19 +++++++++++++++ - src/solver.cpp | 24 ++++++++++++++++++ - 4 files changed, 112 insertions(+) + src/cadical.hpp | 6 +++ + src/ccadical.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++++++ + src/ccadical.h | 26 ++++++++++++ + src/solver.cpp | 24 +++++++++++ + 4 files changed, 159 insertions(+) diff --git a/src/cadical.hpp b/src/cadical.hpp index a803292..8520e2b 100644 @@ -28,10 +28,10 @@ index a803292..8520e2b 100644 // Enables clausal proof tracing in DRAT format and returns 'true' if diff --git a/src/ccadical.cpp b/src/ccadical.cpp -index 88ab164..54798d7 100644 +index 88ab164..846467e 100644 --- a/src/ccadical.cpp +++ b/src/ccadical.cpp -@@ -185,4 +185,67 @@ void ccadical_close_proof (CCaDiCaL *ptr) { +@@ -185,4 +185,107 @@ void ccadical_close_proof (CCaDiCaL *ptr) { void ccadical_conclude (CCaDiCaL *ptr) { ((Wrapper *) ptr)->solver->conclude (); } @@ -40,6 +40,41 @@ index 88ab164..54798d7 100644 + +// Extending C API (Christoph Jabs) + ++int ccadical_add_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->add (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_assume_mem (CCaDiCaL * wrapper, int lit) { ++ try { ++ ((Wrapper*) wrapper)->solver->assume (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_constrain_mem (CCaDiCaL *wrapper, int lit){ ++ try { ++ ((Wrapper*) wrapper)->solver->constrain (lit); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ ++int ccadical_solve_mem (CCaDiCaL * wrapper) { ++ try { ++ return ((Wrapper*) wrapper)->solver->solve (); ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } ++} ++ +bool ccadical_configure (CCaDiCaL *ptr, const char *name) { + return ((Wrapper *) ptr)->solver->configure (name); +} @@ -73,8 +108,13 @@ index 88ab164..54798d7 100644 + return ((Wrapper *) wrapper)->solver->simplify (rounds); +} + -+void ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { -+ return ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++int ccadical_reserve (CCaDiCaL *wrapper, int min_max_var) { ++ try { ++ ((Wrapper *) wrapper)->solver->reserve (min_max_var); ++ return 0; ++ } catch (std::bad_alloc &) { ++ return OUT_OF_MEM; ++ } +} + +int64_t ccadical_propagations (CCaDiCaL *wrapper) { @@ -100,15 +140,22 @@ index 88ab164..54798d7 100644 +/*------------------------------------------------------------------------*/ } diff --git a/src/ccadical.h b/src/ccadical.h -index 6d1b3ff..7f6892b 100644 +index 6d1b3ff..f9a58a2 100644 --- a/src/ccadical.h +++ b/src/ccadical.h -@@ -54,6 +54,25 @@ int ccadical_simplify (CCaDiCaL *); +@@ -54,6 +54,32 @@ int ccadical_simplify (CCaDiCaL *); /*------------------------------------------------------------------------*/ +// Extending C API (Christoph Jabs) + ++// This value is returned from _solve_mem, _add_mem, _constrain_mem, and _assume_mem ++const int OUT_OF_MEM = 50; ++ ++int ccadical_add_mem (CCaDiCaL *, int lit); ++int ccadical_assume_mem (CCaDiCaL *, int lit); ++int ccadical_constrain_mem (CCaDiCaL *, int lit); ++int ccadical_solve_mem (CCaDiCaL *); +bool ccadical_configure (CCaDiCaL *, const char *); +void ccadical_phase (CCaDiCaL *, int lit); +void ccadical_unphase (CCaDiCaL *, int lit); @@ -117,7 +164,7 @@ index 6d1b3ff..7f6892b 100644 +bool ccadical_limit_ret (CCaDiCaL *, const char *name, int val); +int64_t ccadical_redundant (CCaDiCaL *); +int ccadical_simplify_rounds (CCaDiCaL *, int rounds); -+void ccadical_reserve (CCaDiCaL *, int min_max_var); ++int ccadical_reserve (CCaDiCaL *, int min_max_var); +int64_t ccadical_propagations (CCaDiCaL *); +int64_t ccadical_decisions (CCaDiCaL *); +int64_t ccadical_conflicts (CCaDiCaL *); @@ -165,5 +212,5 @@ index a2505ee..b5a375c 100644 void Solver::freeze (int lit) { -- -2.43.0 +2.44.0 diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index 0dad88a3..11271dbf 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -35,6 +35,26 @@ use rustsat::solvers::{ use rustsat::types::{Clause, Lit, TernaryVal, Var}; use thiserror::Error; +const OUT_OF_MEM: c_int = 50; + +macro_rules! handle_oom { + ($val:expr) => {{ + let val = $val; + if val == crate::OUT_OF_MEM { + return anyhow::Context::context(Err(rustsat::OutOfMemory), "cadical out of memory"); + } + val + }}; + ($val:expr, noanyhow) => {{ + let val = $val; + if val == crate::OUT_OF_MEM { + return Err(rustsat::OutOfMemory::ExternalApi); + } + val + }}; +} +pub(crate) use handle_oom; + /// Fatal error returned if the CaDiCaL API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("cadical c-api returned an invalid value: {api_call} -> {value}")] @@ -83,6 +103,10 @@ unsafe impl Send for CaDiCaL<'_, '_> {} impl Default for CaDiCaL<'_, '_> { fn default() -> Self { + let handle = unsafe { ffi::ccadical_init() }; + if handle.is_null() { + panic!("not enough memory to initialize CaDiCaL solver") + } let solver = Self { handle: unsafe { ffi::ccadical_init() }, state: Default::default(), @@ -120,7 +144,7 @@ impl CaDiCaL<'_, '_> { /// _Note_: If this is used, in addition to [`SolveIncremental::core`], /// [`CaDiCaL::tmp_clause_in_core`] needs to be checked to determine if the /// temporary clause is part of the core. - pub fn add_tmp_clause(&mut self, clause: Clause) { + pub fn add_tmp_clause(&mut self, clause: Clause) -> Result<(), rustsat::OutOfMemory> { // Update wrapper-internal state self.stats.n_clauses += 1; self.stats.avg_clause_len = @@ -129,9 +153,16 @@ impl CaDiCaL<'_, '_> { self.state = InternalSolverState::Input; // Call CaDiCaL backend for lit in &clause { - unsafe { ffi::ccadical_constrain(self.handle, lit.to_ipasir()) } + handle_oom!( + unsafe { ffi::ccadical_constrain_mem(self.handle, lit.to_ipasir()) }, + noanyhow + ); } - unsafe { ffi::ccadical_constrain(self.handle, 0) } + handle_oom!( + unsafe { ffi::ccadical_constrain_mem(self.handle, 0) }, + noanyhow + ); + Ok(()) } /// Checks whether the temporary clause is part of the core if in @@ -347,7 +378,7 @@ impl CaDiCaL<'_, '_> { let rounds: c_int = rounds.try_into()?; // Simplify with CaDiCaL backend under assumptions for a in &assumps { - unsafe { ffi::ccadical_assume(self.handle, a.to_ipasir()) } + handle_oom!(unsafe { ffi::ccadical_assume_mem(self.handle, a.to_ipasir()) }); } match unsafe { ffi::ccadical_simplify_rounds(self.handle, rounds) } { 0 => { @@ -398,7 +429,7 @@ impl Solve for CaDiCaL<'_, '_> { fn reserve(&mut self, max_var: Var) -> anyhow::Result<()> { self.state = InternalSolverState::Input; - unsafe { ffi::ccadical_reserve(self.handle, max_var.to_ipasir()) }; + handle_oom!(unsafe { ffi::ccadical_reserve(self.handle, max_var.to_ipasir()) }); Ok(()) } @@ -414,7 +445,7 @@ impl Solve for CaDiCaL<'_, '_> { } let start = ProcessTime::now(); // Solve with CaDiCaL backend - let res = unsafe { ffi::ccadical_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::ccadical_solve_mem(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -471,10 +502,10 @@ impl Solve for CaDiCaL<'_, '_> { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call CaDiCaL backend - clause - .iter() - .for_each(|l| unsafe { ffi::ccadical_add(self.handle, l.to_ipasir()) }); - unsafe { ffi::ccadical_add(self.handle, 0) }; + for &l in clause { + handle_oom!(unsafe { ffi::ccadical_add_mem(self.handle, l.to_ipasir()) }); + } + handle_oom!(unsafe { ffi::ccadical_add_mem(self.handle, 0) }); Ok(()) } } @@ -484,9 +515,9 @@ impl SolveIncremental for CaDiCaL<'_, '_> { let start = ProcessTime::now(); // Solve with CaDiCaL backend for a in assumps { - unsafe { ffi::ccadical_assume(self.handle, a.to_ipasir()) } + handle_oom!(unsafe { ffi::ccadical_assume_mem(self.handle, a.to_ipasir()) }); } - let res = unsafe { ffi::ccadical_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::ccadical_solve_mem(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -915,9 +946,9 @@ mod ffi { pub fn ccadical_signature() -> *const c_char; pub fn ccadical_init() -> *mut CaDiCaLHandle; pub fn ccadical_release(solver: *mut CaDiCaLHandle); - pub fn ccadical_add(solver: *mut CaDiCaLHandle, lit_or_zero: c_int); - pub fn ccadical_assume(solver: *mut CaDiCaLHandle, lit: c_int); - pub fn ccadical_solve(solver: *mut CaDiCaLHandle) -> c_int; + pub fn ccadical_add_mem(solver: *mut CaDiCaLHandle, lit_or_zero: c_int) -> c_int; + pub fn ccadical_assume_mem(solver: *mut CaDiCaLHandle, lit: c_int) -> c_int; + pub fn ccadical_solve_mem(solver: *mut CaDiCaLHandle) -> c_int; pub fn ccadical_val(solver: *mut CaDiCaLHandle, lit: c_int) -> c_int; pub fn ccadical_failed(solver: *mut CaDiCaLHandle, lit: c_int) -> c_int; pub fn ccadical_set_terminate( @@ -931,7 +962,7 @@ mod ffi { max_length: c_int, learn: Option, ); - pub fn ccadical_constrain(solver: *mut CaDiCaLHandle, lit: c_int); + pub fn ccadical_constrain_mem(solver: *mut CaDiCaLHandle, lit: c_int) -> c_int; pub fn ccadical_constraint_failed(solver: *mut CaDiCaLHandle) -> c_int; pub fn ccadical_set_option_ret( solver: *mut CaDiCaLHandle, @@ -958,7 +989,7 @@ mod ffi { pub fn ccadical_phase(solver: *mut CaDiCaLHandle, lit: c_int); pub fn ccadical_unphase(solver: *mut CaDiCaLHandle, lit: c_int); pub fn ccadical_vars(solver: *mut CaDiCaLHandle) -> c_int; - pub fn ccadical_reserve(solver: *mut CaDiCaLHandle, min_max_var: c_int); + pub fn ccadical_reserve(solver: *mut CaDiCaLHandle, min_max_var: c_int) -> c_int; pub fn ccadical_propagations(solver: *mut CaDiCaLHandle) -> i64; pub fn ccadical_decisions(solver: *mut CaDiCaLHandle) -> i64; pub fn ccadical_conflicts(solver: *mut CaDiCaLHandle) -> i64; diff --git a/cadical/test-all.sh b/cadical/test-all.sh index afdfed3c..c706bde8 100755 --- a/cadical/test-all.sh +++ b/cadical/test-all.sh @@ -1,97 +1,121 @@ #!/usr/bin/bash echo "Testing default (newest) version" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test &> def-test.log echo "Default (newest) test returned: $?" echo "Testing v1.5.0" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-5-0 &> v150-test.log echo "v1.5.0 test returned: $?" echo "Testing v1.5.1" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-5-1 &> v151-test.log echo "v1.5.1 test returned: $?" echo "Testing v1.5.2" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-5-2 &> v152-test.log echo "v1.5.2 test returned: $?" echo "Testing v1.5.3" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-5-3 &> v153-test.log echo "v1.5.3 test returned: $?" echo "Testing v1.5.4" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-5-4 &> v154-test.log echo "v1.5.4 test returned: $?" echo "Testing v1.5.5" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-5-5 &> v155-test.log echo "v1.5.5 test returned: $?" echo "Testing v1.5.6" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-5-6 &> v156-test.log echo "v1.5.6 test returned: $?" echo "Testing v1.6.0" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-6-0 &> v160-test.log echo "v1.6.0 test returned: $?" echo "Testing v1.7.0" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-7-0 &> v170-test.log echo "v1.7.0 test returned: $?" echo "Testing v1.7.1" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-7-1 &> v171-test.log echo "v1.7.1 test returned: $?" echo "Testing v1.7.2" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-7-2 &> v172-test.log echo "v1.7.2 test returned: $?" echo "Testing v1.7.3" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-7-3 &> v173-test.log echo "v1.7.3 test returned: $?" echo "Testing v1.7.4" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-7-4 &> v174-test.log echo "v1.7.4 test returned: $?" echo "Testing v1.7.5" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-7-5 &> v175-test.log echo "v1.7.5 test returned: $?" echo "Testing v1.8.0" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-8-0 &> v180-test.log echo "v1.8.0 test returned: $?" echo "Testing v1.9.0" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-9-0 &> v190-test.log echo "v1.9.0 test returned: $?" echo "Testing v1.9.1" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-9-1 &> v191-test.log echo "v1.9.1 test returned: $?" echo "Testing v1.9.2" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-9-2 &> v192-test.log echo "v1.9.2 test returned: $?" echo "Testing v1.9.3" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-9-3 &> v193-test.log echo "v1.9.3 test returned: $?" echo "Testing v1.9.4" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-9-4 &> v194-test.log echo "v1.9.4 test returned: $?" echo "Testing v1.9.5" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=v1-9-5 &> v195-test.log echo "v1.9.5 test returned: $?" echo "Testing quiet" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=quiet &> quiet-test.log echo "quiet test returned: $?" echo "Testing logging" +if [ "$1" == "--clean" ]; then cargo clean -p rustsat-cadical > /dev/null; fi cargo test --features=logging &> logging-test.log echo "logging test returned: $?" diff --git a/glucose/cppsrc b/glucose/cppsrc index a244a12a..ddb5ef27 160000 --- a/glucose/cppsrc +++ b/glucose/cppsrc @@ -1 +1 @@ -Subproject commit a244a12a3f34da6c93377a6196291494fddf491e +Subproject commit ddb5ef27286ab6729efb66e201d9aeccc72622a5 diff --git a/glucose/src/core.rs b/glucose/src/core.rs index ab9b4769..f3d1bbab 100644 --- a/glucose/src/core.rs +++ b/glucose/src/core.rs @@ -5,6 +5,8 @@ use core::ffi::{c_int, CStr}; +use crate::handle_oom; + use super::{InternalSolverState, InvalidApiReturn, Limit}; use cpu_time::ProcessTime; use ffi::Glucose4Handle; @@ -27,8 +29,12 @@ unsafe impl Send for Glucose {} impl Default for Glucose { fn default() -> Self { + let handle = unsafe { ffi::cglucose4_init() }; + if handle.is_null() { + panic!("not enough memory to initialize glucose solver") + } Self { - handle: unsafe { ffi::cglucose4_init() }, + handle, state: Default::default(), stats: Default::default(), } @@ -112,7 +118,7 @@ impl Solve for Glucose { } let start = ProcessTime::now(); // Solve with glucose backend - let res = unsafe { ffi::cglucose4_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cglucose4_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -167,10 +173,10 @@ impl Solve for Glucose { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call glucose backend - clause.iter().for_each(|l| unsafe { - ffi::cglucose4_add(self.handle, l.to_ipasir()); - }); - unsafe { ffi::cglucose4_add(self.handle, 0) }; + for l in clause { + handle_oom!(unsafe { ffi::cglucose4_add(self.handle, l.to_ipasir()) }); + } + handle_oom!(unsafe { ffi::cglucose4_add(self.handle, 0) }); Ok(()) } } @@ -182,7 +188,7 @@ impl SolveIncremental for Glucose { for a in assumps { unsafe { ffi::cglucose4_assume(self.handle, a.to_ipasir()) } } - let res = unsafe { ffi::cglucose4_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cglucose4_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -247,7 +253,7 @@ impl InterruptSolver for Interrupter { impl PhaseLit for Glucose { /// Forces the default decision phase of a variable to a certain value fn phase_lit(&mut self, lit: Lit) -> anyhow::Result<()> { - unsafe { ffi::cglucose4_phase(self.handle, lit.to_ipasir()) }; + handle_oom!(unsafe { ffi::cglucose4_phase(self.handle, lit.to_ipasir()) }); Ok(()) } @@ -374,12 +380,12 @@ mod ffi { pub fn cglucose4_signature() -> *const c_char; pub fn cglucose4_init() -> *mut Glucose4Handle; pub fn cglucose4_release(solver: *mut Glucose4Handle); - pub fn cglucose4_add(solver: *mut Glucose4Handle, lit_or_zero: c_int); + pub fn cglucose4_add(solver: *mut Glucose4Handle, lit_or_zero: c_int) -> c_int; pub fn cglucose4_assume(solver: *mut Glucose4Handle, lit: c_int); pub fn cglucose4_solve(solver: *mut Glucose4Handle) -> c_int; pub fn cglucose4_val(solver: *mut Glucose4Handle, lit: c_int) -> c_int; pub fn cglucose4_failed(solver: *mut Glucose4Handle, lit: c_int) -> c_int; - pub fn cglucose4_phase(solver: *mut Glucose4Handle, lit: c_int); + pub fn cglucose4_phase(solver: *mut Glucose4Handle, lit: c_int) -> c_int; pub fn cglucose4_unphase(solver: *mut Glucose4Handle, lit: c_int); pub fn cglucose4_n_assigns(solver: *mut Glucose4Handle) -> c_int; pub fn cglucose4_n_clauses(solver: *mut Glucose4Handle) -> c_int; diff --git a/glucose/src/lib.rs b/glucose/src/lib.rs index 0020227b..2377b213 100644 --- a/glucose/src/lib.rs +++ b/glucose/src/lib.rs @@ -24,6 +24,8 @@ use thiserror::Error; pub mod core; pub mod simp; +const OUT_OF_MEM: c_int = 50; + /// Fatal error returned if the Glucose API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("glucose c-api returned an invalid value: {api_call} -> {value}")] @@ -80,3 +82,14 @@ impl fmt::Display for Limit { } } } + +macro_rules! handle_oom { + ($val:expr) => {{ + let val = $val; + if val == crate::OUT_OF_MEM { + return anyhow::Context::context(Err(rustsat::OutOfMemory), "glucose out of memory"); + } + val + }}; +} +pub(crate) use handle_oom; diff --git a/glucose/src/simp.rs b/glucose/src/simp.rs index 84fcee65..d7f14178 100644 --- a/glucose/src/simp.rs +++ b/glucose/src/simp.rs @@ -5,6 +5,8 @@ use core::ffi::{c_int, CStr}; +use crate::handle_oom; + use super::{AssumpEliminated, InternalSolverState, InvalidApiReturn, Limit}; use cpu_time::ProcessTime; use ffi::Glucose4Handle; @@ -28,8 +30,12 @@ unsafe impl Send for Glucose {} impl Default for Glucose { fn default() -> Self { + let handle = unsafe { ffi::cglucosesimp4_init() }; + if handle.is_null() { + panic!("not enough memory to initialize glucose solver") + } Self { - handle: unsafe { ffi::cglucosesimp4_init() }, + handle, state: Default::default(), stats: Default::default(), } @@ -120,7 +126,7 @@ impl Solve for Glucose { } let start = ProcessTime::now(); // Solve with glucose backend - let res = unsafe { ffi::cglucosesimp4_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cglucosesimp4_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -175,10 +181,10 @@ impl Solve for Glucose { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call glucose backend - clause.iter().for_each(|l| unsafe { - ffi::cglucosesimp4_add(self.handle, l.to_ipasir()); - }); - unsafe { ffi::cglucosesimp4_add(self.handle, 0) }; + for l in clause { + handle_oom!(unsafe { ffi::cglucosesimp4_add(self.handle, l.to_ipasir()) }); + } + handle_oom!(unsafe { ffi::cglucosesimp4_add(self.handle, 0) }); Ok(()) } } @@ -195,7 +201,7 @@ impl SolveIncremental for Glucose { for a in assumps { unsafe { ffi::cglucosesimp4_assume(self.handle, a.to_ipasir()) } } - let res = unsafe { ffi::cglucosesimp4_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cglucosesimp4_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -260,7 +266,7 @@ impl InterruptSolver for Interrupter { impl PhaseLit for Glucose { /// Forces the default decision phase of a variable to a certain value fn phase_lit(&mut self, lit: Lit) -> anyhow::Result<()> { - unsafe { ffi::cglucosesimp4_phase(self.handle, lit.to_ipasir()) }; + handle_oom!(unsafe { ffi::cglucosesimp4_phase(self.handle, lit.to_ipasir()) }); Ok(()) } @@ -404,12 +410,12 @@ mod ffi { pub fn cglucose4_signature() -> *const c_char; pub fn cglucosesimp4_init() -> *mut Glucose4Handle; pub fn cglucosesimp4_release(solver: *mut Glucose4Handle); - pub fn cglucosesimp4_add(solver: *mut Glucose4Handle, lit_or_zero: c_int); + pub fn cglucosesimp4_add(solver: *mut Glucose4Handle, lit_or_zero: c_int) -> c_int; pub fn cglucosesimp4_assume(solver: *mut Glucose4Handle, lit: c_int); pub fn cglucosesimp4_solve(solver: *mut Glucose4Handle) -> c_int; pub fn cglucosesimp4_val(solver: *mut Glucose4Handle, lit: c_int) -> c_int; pub fn cglucosesimp4_failed(solver: *mut Glucose4Handle, lit: c_int) -> c_int; - pub fn cglucosesimp4_phase(solver: *mut Glucose4Handle, lit: c_int); + pub fn cglucosesimp4_phase(solver: *mut Glucose4Handle, lit: c_int) -> c_int; pub fn cglucosesimp4_unphase(solver: *mut Glucose4Handle, lit: c_int); pub fn cglucosesimp4_n_assigns(solver: *mut Glucose4Handle) -> c_int; pub fn cglucosesimp4_n_clauses(solver: *mut Glucose4Handle) -> c_int; diff --git a/minisat/cppsrc b/minisat/cppsrc index e168f6e7..c17b905d 160000 --- a/minisat/cppsrc +++ b/minisat/cppsrc @@ -1 +1 @@ -Subproject commit e168f6e72600f4b04769b0f3bbb7f89b1a200a67 +Subproject commit c17b905d3654cdfffe5837cf275402e4f40c3435 diff --git a/minisat/src/core.rs b/minisat/src/core.rs index 5d1200b4..c90fe3c8 100644 --- a/minisat/src/core.rs +++ b/minisat/src/core.rs @@ -5,7 +5,7 @@ use core::ffi::{c_int, CStr}; -use super::{InternalSolverState, InvalidApiReturn, Limit}; +use super::{handle_oom, InternalSolverState, InvalidApiReturn, Limit}; use cpu_time::ProcessTime; use ffi::MinisatHandle; use rustsat::{ @@ -27,8 +27,12 @@ unsafe impl Send for Minisat {} impl Default for Minisat { fn default() -> Self { + let handle = unsafe { ffi::cminisat_init() }; + if handle.is_null() { + panic!("not enough memory to initialize minisat solver") + } Self { - handle: unsafe { ffi::cminisat_init() }, + handle, state: Default::default(), stats: Default::default(), } @@ -112,7 +116,7 @@ impl Solve for Minisat { } let start = ProcessTime::now(); // Solve with minisat backend - let res = unsafe { ffi::cminisat_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cminisat_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -167,10 +171,10 @@ impl Solve for Minisat { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call minisat backend - clause.iter().for_each(|l| unsafe { - ffi::cminisat_add(self.handle, l.to_ipasir()); - }); - unsafe { ffi::cminisat_add(self.handle, 0) }; + for l in clause { + handle_oom!(unsafe { ffi::cminisat_add(self.handle, l.to_ipasir()) }); + } + handle_oom!(unsafe { ffi::cminisat_add(self.handle, 0) }); Ok(()) } } @@ -182,7 +186,7 @@ impl SolveIncremental for Minisat { for a in assumps { unsafe { ffi::cminisat_assume(self.handle, a.to_ipasir()) } } - let res = unsafe { ffi::cminisat_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cminisat_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -247,7 +251,7 @@ impl InterruptSolver for Interrupter { impl PhaseLit for Minisat { /// Forces the default decision phase of a variable to a certain value fn phase_lit(&mut self, lit: Lit) -> anyhow::Result<()> { - unsafe { ffi::cminisat_phase(self.handle, lit.to_ipasir()) }; + handle_oom!(unsafe { ffi::cminisat_phase(self.handle, lit.to_ipasir()) }); Ok(()) } @@ -373,12 +377,12 @@ mod ffi { pub fn cminisat_signature() -> *const c_char; pub fn cminisat_init() -> *mut MinisatHandle; pub fn cminisat_release(solver: *mut MinisatHandle); - pub fn cminisat_add(solver: *mut MinisatHandle, lit_or_zero: c_int); + pub fn cminisat_add(solver: *mut MinisatHandle, lit_or_zero: c_int) -> c_int; pub fn cminisat_assume(solver: *mut MinisatHandle, lit: c_int); pub fn cminisat_solve(solver: *mut MinisatHandle) -> c_int; pub fn cminisat_val(solver: *mut MinisatHandle, lit: c_int) -> c_int; pub fn cminisat_failed(solver: *mut MinisatHandle, lit: c_int) -> c_int; - pub fn cminisat_phase(solver: *mut MinisatHandle, lit: c_int); + pub fn cminisat_phase(solver: *mut MinisatHandle, lit: c_int) -> c_int; pub fn cminisat_unphase(solver: *mut MinisatHandle, lit: c_int); pub fn cminisat_n_assigns(solver: *mut MinisatHandle) -> c_int; pub fn cminisat_n_clauses(solver: *mut MinisatHandle) -> c_int; diff --git a/minisat/src/lib.rs b/minisat/src/lib.rs index 1fb1f2be..da805430 100644 --- a/minisat/src/lib.rs +++ b/minisat/src/lib.rs @@ -24,6 +24,8 @@ use thiserror::Error; pub mod core; pub mod simp; +const OUT_OF_MEM: c_int = 50; + /// Fatal error returned if the Minisat API returns an invalid value #[derive(Error, Clone, Copy, PartialEq, Eq, Debug)] #[error("minisat c-api returned an invalid value: {api_call} -> {value}")] @@ -80,3 +82,14 @@ impl fmt::Display for Limit { } } } + +macro_rules! handle_oom { + ($val:expr) => {{ + let val = $val; + if val == crate::OUT_OF_MEM { + return anyhow::Context::context(Err(rustsat::OutOfMemory), "minisat out of memory"); + } + val + }}; +} +pub(crate) use handle_oom; diff --git a/minisat/src/simp.rs b/minisat/src/simp.rs index 8c56b86b..9a540365 100644 --- a/minisat/src/simp.rs +++ b/minisat/src/simp.rs @@ -5,7 +5,7 @@ use core::ffi::{c_int, CStr}; -use super::{AssumpEliminated, InternalSolverState, InvalidApiReturn, Limit}; +use super::{handle_oom, AssumpEliminated, InternalSolverState, InvalidApiReturn, Limit}; use cpu_time::ProcessTime; use ffi::MinisatHandle; use rustsat::{ @@ -28,8 +28,12 @@ unsafe impl Send for Minisat {} impl Default for Minisat { fn default() -> Self { + let handle = unsafe { ffi::cminisatsimp_init() }; + if handle.is_null() { + panic!("not enough memory to initialize minisat solver") + } Self { - handle: unsafe { ffi::cminisatsimp_init() }, + handle, state: Default::default(), stats: Default::default(), } @@ -120,7 +124,7 @@ impl Solve for Minisat { } let start = ProcessTime::now(); // Solve with minisat backend - let res = unsafe { ffi::cminisatsimp_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cminisatsimp_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -175,10 +179,10 @@ impl Solve for Minisat { / self.stats.n_clauses as f32; self.state = InternalSolverState::Input; // Call minisat backend - clause.iter().for_each(|l| unsafe { - ffi::cminisatsimp_add(self.handle, l.to_ipasir()); - }); - unsafe { ffi::cminisatsimp_add(self.handle, 0) }; + for l in clause { + handle_oom!(unsafe { ffi::cminisatsimp_add(self.handle, l.to_ipasir()) }); + } + handle_oom!(unsafe { ffi::cminisatsimp_add(self.handle, 0) }); Ok(()) } } @@ -195,7 +199,7 @@ impl SolveIncremental for Minisat { for a in assumps { unsafe { ffi::cminisatsimp_assume(self.handle, a.to_ipasir()) } } - let res = unsafe { ffi::cminisatsimp_solve(self.handle) }; + let res = handle_oom!(unsafe { ffi::cminisatsimp_solve(self.handle) }); self.stats.cpu_solve_time += start.elapsed(); match res { 0 => { @@ -260,7 +264,7 @@ impl InterruptSolver for Interrupter { impl PhaseLit for Minisat { /// Forces the default decision phase of a variable to a certain value fn phase_lit(&mut self, lit: Lit) -> anyhow::Result<()> { - unsafe { ffi::cminisatsimp_phase(self.handle, lit.to_ipasir()) }; + handle_oom!(unsafe { ffi::cminisatsimp_phase(self.handle, lit.to_ipasir()) }); Ok(()) } @@ -405,12 +409,12 @@ mod ffi { pub fn cminisat_signature() -> *const c_char; pub fn cminisatsimp_init() -> *mut MinisatHandle; pub fn cminisatsimp_release(solver: *mut MinisatHandle); - pub fn cminisatsimp_add(solver: *mut MinisatHandle, lit_or_zero: c_int); + pub fn cminisatsimp_add(solver: *mut MinisatHandle, lit_or_zero: c_int) -> c_int; pub fn cminisatsimp_assume(solver: *mut MinisatHandle, lit: c_int); pub fn cminisatsimp_solve(solver: *mut MinisatHandle) -> c_int; pub fn cminisatsimp_val(solver: *mut MinisatHandle, lit: c_int) -> c_int; pub fn cminisatsimp_failed(solver: *mut MinisatHandle, lit: c_int) -> c_int; - pub fn cminisatsimp_phase(solver: *mut MinisatHandle, lit: c_int); + pub fn cminisatsimp_phase(solver: *mut MinisatHandle, lit: c_int) -> c_int; pub fn cminisatsimp_unphase(solver: *mut MinisatHandle, lit: c_int); pub fn cminisatsimp_n_assigns(solver: *mut MinisatHandle) -> c_int; pub fn cminisatsimp_n_clauses(solver: *mut MinisatHandle) -> c_int; diff --git a/rustsat/src/lib.rs b/rustsat/src/lib.rs index eb075db9..8c8cae08 100644 --- a/rustsat/src/lib.rs +++ b/rustsat/src/lib.rs @@ -94,6 +94,10 @@ impl fmt::Display for NotAllowed { mod bench; /// Error returned if an operation requires clausal constraints, but this is not the case +#[derive(Error, Debug)] +#[error("operation ran out of memory")] +pub struct OutOfMemory; + #[derive(Error, Debug)] #[error("operation requires a clausal constraint(s) but it is not")] pub struct RequiresClausal; From 036baa6a60768390646f0e8b16d4349c3d41d8f0 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Wed, 17 Apr 2024 15:42:15 +0300 Subject: [PATCH 27/56] chore: cleanup feature-dependent compilation If, e.g., features v1-7-0 and v1-5-2 are selected now, CaDiCaL 1.7.0 will be compiled but flipping literals will not be available in RustSAT. To avoid this however, the conditions around the flipping code would need to be updated with every update to the CaDiCaL backend, which is prone to be forgotten. --- cadical/src/lib.rs | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index 11271dbf..cc0a7309 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -705,18 +705,11 @@ impl FreezeVar for CaDiCaL<'_, '_> { } // >= v1.5.4 -#[cfg(any( - feature = "v1-5-4", - feature = "v1-5-5", - feature = "v1-5-6", - feature = "v1-6-0", - feature = "v1-7-0", - all( - not(feature = "v1-5-3"), - not(feature = "v1-5-2"), - not(feature = "v1-5-1"), - not(feature = "v1-5-0") - ) +#[cfg(all( + not(feature = "v1-5-3"), + not(feature = "v1-5-2"), + not(feature = "v1-5-1"), + not(feature = "v1-5-0") ))] impl rustsat::solvers::FlipLit for CaDiCaL<'_, '_> { fn flip_lit(&mut self, lit: Lit) -> anyhow::Result { @@ -996,18 +989,11 @@ mod ffi { } // >= v1.5.4 - #[cfg(any( - feature = "v1-5-4", - feature = "v1-5-5", - feature = "v1-5-6", - feature = "v1-6-0", - feature = "v1-7-0", - all( - not(feature = "v1-5-3"), - not(feature = "v1-5-2"), - not(feature = "v1-5-1"), - not(feature = "v1-5-0") - ) + #[cfg(all( + not(feature = "v1-5-3"), + not(feature = "v1-5-2"), + not(feature = "v1-5-1"), + not(feature = "v1-5-0") ))] #[link(name = "cadical", kind = "static")] extern "C" { From f4f4babd3d286621ac87cf20a9590906d631d964 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 18 Apr 2024 10:41:51 +0300 Subject: [PATCH 28/56] example: `cadical-cli` tool --- cadical/Cargo.toml | 2 + cadical/examples/cadical-cli.rs | 129 ++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 cadical/examples/cadical-cli.rs diff --git a/cadical/Cargo.toml b/cadical/Cargo.toml index 9afb53af..aa1ed892 100644 --- a/cadical/Cargo.toml +++ b/cadical/Cargo.toml @@ -53,3 +53,5 @@ chrono = "0.4.31" [dev-dependencies] rustsat-solvertests = { path = "../solvertests" } +clap = { version = "4.5.4", features = ["derive"] } +signal-hook = { version = "0.3.17" } diff --git a/cadical/examples/cadical-cli.rs b/cadical/examples/cadical-cli.rs new file mode 100644 index 00000000..6db718af --- /dev/null +++ b/cadical/examples/cadical-cli.rs @@ -0,0 +1,129 @@ +//! # CaDiCaL CLI Tool +//! +//! A simple CLI wrapper around the CaDiCaL solver Rust interface. This is just an example, if you +//! want to use CaDiCaL from the CLI, compile the binary from the C++ source directly. + +use std::{ + io, + path::{Path, PathBuf}, + thread, +}; + +use anyhow::Context; +use clap::Parser; +use rustsat::{ + instances::{fio::opb, ManageVars, SatInstance}, + solvers::{Interrupt, InterruptSolver, Solve, SolveStats, SolverResult}, +}; +use rustsat_cadical::CaDiCaL; + +enum FileType { + Cnf, + Opb, +} + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Args { + /// The DIMACS CNF input file. Reads from `stdin` if not given. + in_path: Option, + /// Parse the input as an OPB file by default + #[arg(short, long)] + opb: bool, +} + +fn main() -> anyhow::Result<()> { + let args = Args::parse(); + + let inst: SatInstance = if let Some(in_path) = args.in_path { + match determine_file_type(&in_path, args.opb) { + FileType::Cnf => SatInstance::from_dimacs_path(in_path) + .context("error parsing the input file as CNF")?, + FileType::Opb => SatInstance::from_opb_path(in_path, opb::Options::default()) + .context("error parsing the input file as OPB")?, + } + } else if args.opb { + SatInstance::from_opb(io::BufReader::new(io::stdin()), opb::Options::default()) + .context("error parsing input as OPB")? + } else { + SatInstance::from_dimacs(io::BufReader::new(io::stdin())) + .context("error parsing input as CNF")? + }; + + solve::(inst) +} + +fn solve(inst: SatInstance) -> anyhow::Result<()> { + let mut solver = S::default(); + + #[cfg(not(target_family = "windows"))] + { + // Setup signal handling + let interrupter = solver.interrupter(); + let mut signals = signal_hook::iterator::Signals::new([ + signal_hook::consts::SIGTERM, + signal_hook::consts::SIGINT, + signal_hook::consts::SIGXCPU, + signal_hook::consts::SIGABRT, + ])?; + // Thread for catching incoming signals + thread::spawn(move || { + for _ in signals.forever() { + interrupter.interrupt(); + } + }); + } + + let (cnf, vm) = inst.into_cnf(); + if let Some(max_var) = vm.max_var() { + solver.reserve(max_var)?; + } + solver.add_cnf(cnf)?; + match solver.solve() { + Err(err) => { + println!("s UNKNOWN"); + return Err(err); + } + Ok(res) => match res { + SolverResult::Sat => { + println!("s SATISFIABLE"); + println!("v {}", solver.full_solution()?); + } + SolverResult::Unsat => println!("s UNSATISFIABLE"), + SolverResult::Interrupted => println!("s UNKNOWN"), + }, + }; + Ok(()) +} + +macro_rules! is_one_of { + ($a:expr, $($b:expr),*) => { + $( $a == $b || )* false + } +} + +fn determine_file_type(in_path: &Path, opb_default: bool) -> FileType { + if let Some(ext) = in_path.extension() { + let path_without_compr = in_path.with_extension(""); + let ext = if is_one_of!(ext, "gz", "bz2") { + // Strip compression extension + match path_without_compr.extension() { + Some(ext) => ext, + None => return FileType::Cnf, // Fallback default + } + } else { + ext + }; + if "opb" == ext { + return FileType::Opb; + }; + if "cnf" == ext { + return FileType::Cnf; + } + }; + if opb_default { + FileType::Opb + } else { + FileType::Cnf + } // Fallback default +} From c4ec581a3857b9da3d54b14b46e94ad4a95ec055 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 18 Apr 2024 16:18:30 +0300 Subject: [PATCH 29/56] feat: allow for abort hooks - `panic_instead_of_abort` to cause a Rust panic on Kissat abort - `call_instead_of_abort` to set up a custom hook function that is called on Kissat abort --- kissat/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/kissat/src/lib.rs b/kissat/src/lib.rs index 818ab5ea..145b7668 100644 --- a/kissat/src/lib.rs +++ b/kissat/src/lib.rs @@ -434,6 +434,20 @@ impl fmt::Display for Limit { } } +extern "C" fn panic_instead_of_abort() { + panic!("kissat called kissat_abort"); +} + +/// Changes Kissat's abort behaviour to cause a Rust panic instead +pub fn panic_intead_of_abort() { + unsafe { ffi::kissat_call_function_instead_of_abort(Some(panic_instead_of_abort)) }; +} + +/// Changes Kissat's abort behaviour to call the given function instead +pub fn call_instead_of_abort(abort: Option) { + unsafe { ffi::kissat_call_function_instead_of_abort(abort) }; +} + #[cfg(test)] mod test { use super::{Config, Kissat, Limit}; @@ -516,6 +530,8 @@ mod ffi { pub fn kissat_set_conflict_limit(solver: *mut KissatHandle, limit: c_uint); pub fn kissat_set_decision_limit(solver: *mut KissatHandle, limit: c_uint); pub fn kissat_print_statistics(solver: *mut KissatHandle); + // This is from `error.h` + pub fn kissat_call_function_instead_of_abort(abort: Option); } // Raw callbacks forwarding to user callbacks From b40d20c7d0bf8dfd267248aa6e6da69f7408e4b7 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 18 Apr 2024 16:19:54 +0300 Subject: [PATCH 30/56] example: `kissat-cli` tool --- kissat/Cargo.toml | 2 + kissat/examples/kissat-cli.rs | 135 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 kissat/examples/kissat-cli.rs diff --git a/kissat/Cargo.toml b/kissat/Cargo.toml index b40c0074..beaae3ed 100644 --- a/kissat/Cargo.toml +++ b/kissat/Cargo.toml @@ -38,3 +38,5 @@ chrono = "0.4.31" [dev-dependencies] rustsat-solvertests = { path = "../solvertests" } +clap = { version = "4.5.4", features = ["derive"] } +signal-hook = { version = "0.3.17" } diff --git a/kissat/examples/kissat-cli.rs b/kissat/examples/kissat-cli.rs new file mode 100644 index 00000000..a8c26084 --- /dev/null +++ b/kissat/examples/kissat-cli.rs @@ -0,0 +1,135 @@ +//! # CaDiCaL CLI Tool +//! +//! A simple CLI wrapper around the CaDiCaL solver Rust interface. This is just an example, if you +//! want to use CaDiCaL from the CLI, compile the binary from the C++ source directly. + +use std::{ + io, + path::{Path, PathBuf}, + thread, +}; + +use anyhow::Context; +use clap::Parser; +use rustsat::{ + instances::{fio::opb, ManageVars, SatInstance}, + solvers::{Interrupt, InterruptSolver, Solve, SolveStats, SolverResult}, +}; +use rustsat_kissat::Kissat; + +enum FileType { + Cnf, + Opb, +} + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Args { + /// The DIMACS CNF input file. Reads from `stdin` if not given. + in_path: Option, + /// Parse the input as an OPB file by default + #[arg(short, long)] + opb: bool, +} + +fn main() -> anyhow::Result<()> { + let args = Args::parse(); + + let inst: SatInstance = if let Some(in_path) = args.in_path { + match determine_file_type(&in_path, args.opb) { + FileType::Cnf => SatInstance::from_dimacs_path(in_path) + .context("error parsing the input file as CNF")?, + FileType::Opb => SatInstance::from_opb_path(in_path, opb::Options::default()) + .context("error parsing the input file as OPB")?, + } + } else if args.opb { + SatInstance::from_opb(io::BufReader::new(io::stdin()), opb::Options::default()) + .context("error parsing input as OPB")? + } else { + SatInstance::from_dimacs(io::BufReader::new(io::stdin())) + .context("error parsing input as CNF")? + }; + + rustsat_kissat::call_instead_of_abort(Some(kissat_abort)); + solve::(inst) +} + +extern "C" fn kissat_abort() { + println!("s UNKNOWN"); + panic!("kissat called abort"); +} + +fn solve(inst: SatInstance) -> anyhow::Result<()> { + let mut solver = S::default(); + + #[cfg(not(target_family = "windows"))] + { + // Setup signal handling + let interrupter = solver.interrupter(); + let mut signals = signal_hook::iterator::Signals::new([ + signal_hook::consts::SIGTERM, + signal_hook::consts::SIGINT, + signal_hook::consts::SIGXCPU, + signal_hook::consts::SIGABRT, + ])?; + // Thread for catching incoming signals + thread::spawn(move || { + for _ in signals.forever() { + interrupter.interrupt(); + } + }); + } + + let (cnf, vm) = inst.into_cnf(); + if let Some(max_var) = vm.max_var() { + solver.reserve(max_var)?; + } + solver.add_cnf(cnf)?; + match solver.solve() { + Err(err) => { + println!("s UNKNOWN"); + return Err(err); + } + Ok(res) => match res { + SolverResult::Sat => { + println!("s SATISFIABLE"); + println!("v {}", solver.full_solution()?); + } + SolverResult::Unsat => println!("s UNSATISFIABLE"), + SolverResult::Interrupted => println!("s UNKNOWN"), + }, + }; + Ok(()) +} + +macro_rules! is_one_of { + ($a:expr, $($b:expr),*) => { + $( $a == $b || )* false + } +} + +fn determine_file_type(in_path: &Path, opb_default: bool) -> FileType { + if let Some(ext) = in_path.extension() { + let path_without_compr = in_path.with_extension(""); + let ext = if is_one_of!(ext, "gz", "bz2") { + // Strip compression extension + match path_without_compr.extension() { + Some(ext) => ext, + None => return FileType::Cnf, // Fallback default + } + } else { + ext + }; + if "opb" == ext { + return FileType::Opb; + }; + if "cnf" == ext { + return FileType::Cnf; + } + }; + if opb_default { + FileType::Opb + } else { + FileType::Cnf + } // Fallback default +} From 5c5de75bb9bacb9590df4eef92cf47396cf1d171 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 25 Apr 2024 20:40:32 +0300 Subject: [PATCH 31/56] build: cleanup build script --- capi/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/capi/build.rs b/capi/build.rs index 7fd6a694..75c47ecb 100644 --- a/capi/build.rs +++ b/capi/build.rs @@ -27,11 +27,8 @@ fn main() { // Setup inline-c let include_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let ld_dir = target_dir().unwrap(); - #[cfg(feature = "pyapi")] - let python_lib = pyo3_build_config::get().lib_name.as_ref().unwrap(); let cflags = format!("cargo:rustc-env=INLINE_C_RS_CFLAGS=-I{I} -L{L} -lrustsat_capi -D_DEBUG -D_CRT_SECURE_NO_WARNINGS", I=include_dir, L=ld_dir.to_string_lossy()); - #[cfg(feature = "compression")] let cflags = format!("{} -llzma -lbz2", cflags); println!("{}", cflags); @@ -39,7 +36,6 @@ fn main() { "cargo:rustc-env=INLINE_C_RS_LDFLAGS={L}/librustsat_capi.a", L = ld_dir.to_string_lossy() ); - #[cfg(feature = "compression")] let ldflags = format!("{} -llzma -lbz2", ldflags); println!("{}", ldflags); } From b0ab426e545c85f11a66b8098c8171d776a95516 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 25 Apr 2024 20:40:42 +0300 Subject: [PATCH 32/56] feat: catch memory outs in clause collector extend `OutOfMemory` error and make `CollectClauses` and encodings return it if not enough memory is available --- cadical/src/lib.rs | 5 +- capi/src/lib.rs | 27 +++- glucose/src/lib.rs | 5 +- minisat/src/lib.rs | 5 +- pyapi/src/encodings.rs | 43 +++-- pyapi/src/lib.rs | 10 ++ rustsat/examples/profiling.rs | 2 +- rustsat/src/encodings.rs | 16 +- rustsat/src/encodings/am1.rs | 4 +- rustsat/src/encodings/am1/pairwise.rs | 6 +- rustsat/src/encodings/card.rs | 92 +++++++---- rustsat/src/encodings/card/dbtotalizer.rs | 146 ++++++++++------- rustsat/src/encodings/card/simulators.rs | 40 ++++- rustsat/src/encodings/card/totalizer.rs | 186 ++++++++++++++-------- rustsat/src/encodings/pb.rs | 101 +++++++----- rustsat/src/encodings/pb/dbgte.rs | 75 +++++---- rustsat/src/encodings/pb/dpw.rs | 57 ++++--- rustsat/src/encodings/pb/gte.rs | 112 +++++++------ rustsat/src/encodings/pb/simulators.rs | 60 +++++-- rustsat/src/instances/multiopt.rs | 18 ++- rustsat/src/instances/opt.rs | 18 ++- rustsat/src/instances/sat.rs | 84 +++++++++- rustsat/src/lib.rs | 27 +++- rustsat/src/solvers.rs | 26 +++ rustsat/src/utils.rs | 30 ++++ rustsat/tests/card_encodings.rs | 70 +++++--- rustsat/tests/pb_encodings.rs | 32 ++-- 27 files changed, 902 insertions(+), 395 deletions(-) diff --git a/cadical/src/lib.rs b/cadical/src/lib.rs index cc0a7309..69a736e5 100644 --- a/cadical/src/lib.rs +++ b/cadical/src/lib.rs @@ -41,7 +41,10 @@ macro_rules! handle_oom { ($val:expr) => {{ let val = $val; if val == crate::OUT_OF_MEM { - return anyhow::Context::context(Err(rustsat::OutOfMemory), "cadical out of memory"); + return anyhow::Context::context( + Err(rustsat::OutOfMemory::ExternalApi), + "cadical out of memory", + ); } val }}; diff --git a/capi/src/lib.rs b/capi/src/lib.rs index 095fcb7d..e92904b0 100644 --- a/capi/src/lib.rs +++ b/capi/src/lib.rs @@ -63,6 +63,25 @@ pub mod encodings { fn n_clauses(&self) -> usize { self.n_clauses } + + fn extend_clauses(&mut self, cl_iter: T) -> Result<(), rustsat::OutOfMemory> + where + T: IntoIterator, + { + cl_iter.into_iter().for_each(|cl| { + cl.into_iter() + .for_each(|l| (self.ccol)(l.to_ipasir(), self.cdata)); + (self.ccol)(0, self.cdata); + }); + Ok(()) + } + + fn add_clause(&mut self, cl: Clause) -> Result<(), rustsat::OutOfMemory> { + cl.into_iter() + .for_each(|l| (self.ccol)(l.to_ipasir(), self.cdata)); + (self.ccol)(0, self.cdata); + Ok(()) + } } impl Extend for ClauseCollector { @@ -186,7 +205,9 @@ pub mod encodings { let mut collector = ClauseCollector::new(collector, collector_data); let mut var_manager = VarManager::new(n_vars_used); let mut boxed = unsafe { Box::from_raw(tot) }; - boxed.encode_ub_change(min_bound..=max_bound, &mut collector, &mut var_manager); + boxed + .encode_ub_change(min_bound..=max_bound, &mut collector, &mut var_manager) + .expect("clause collector returned out of memory"); Box::into_raw(boxed); } @@ -358,7 +379,9 @@ pub mod encodings { let mut collector = ClauseCollector::new(collector, collector_data); let mut var_manager = VarManager::new(n_vars_used); let mut boxed = unsafe { Box::from_raw(dpw) }; - boxed.encode_ub_change(min_bound..=max_bound, &mut collector, &mut var_manager); + boxed + .encode_ub_change(min_bound..=max_bound, &mut collector, &mut var_manager) + .expect("clause collector returned out of memory"); Box::into_raw(boxed); } diff --git a/glucose/src/lib.rs b/glucose/src/lib.rs index 2377b213..4239cca3 100644 --- a/glucose/src/lib.rs +++ b/glucose/src/lib.rs @@ -87,7 +87,10 @@ macro_rules! handle_oom { ($val:expr) => {{ let val = $val; if val == crate::OUT_OF_MEM { - return anyhow::Context::context(Err(rustsat::OutOfMemory), "glucose out of memory"); + return anyhow::Context::context( + Err(rustsat::OutOfMemory::ExternalApi), + "glucose out of memory", + ); } val }}; diff --git a/minisat/src/lib.rs b/minisat/src/lib.rs index da805430..93c36019 100644 --- a/minisat/src/lib.rs +++ b/minisat/src/lib.rs @@ -87,7 +87,10 @@ macro_rules! handle_oom { ($val:expr) => {{ let val = $val; if val == crate::OUT_OF_MEM { - return anyhow::Context::context(Err(rustsat::OutOfMemory), "minisat out of memory"); + return anyhow::Context::context( + Err(rustsat::OutOfMemory::ExternalApi), + "minisat out of memory", + ); } val }}; diff --git a/pyapi/src/encodings.rs b/pyapi/src/encodings.rs index e7f1bba4..b5563651 100644 --- a/pyapi/src/encodings.rs +++ b/pyapi/src/encodings.rs @@ -19,6 +19,7 @@ use rustsat::{ }; use crate::{ + handle_oom, instances::{Cnf, VarManager}, types::Lit, }; @@ -89,12 +90,18 @@ impl Totalizer { /// Incrementally builds the totalizer encoding to that upper bounds /// in the range `max_ub..=min_ub` can be enforced. New variables will /// be taken from `var_manager`. - fn encode_ub(&mut self, max_ub: usize, min_ub: usize, var_manager: &mut VarManager) -> Cnf { + fn encode_ub( + &mut self, + max_ub: usize, + min_ub: usize, + var_manager: &mut VarManager, + ) -> PyResult { let mut cnf = RsCnf::new(); let var_manager: &mut BasicVarManager = var_manager.into(); - self.0 - .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager); - cnf.into() + handle_oom!(self + .0 + .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager)); + Ok(cnf.into()) } /// Gets assumptions to enforce the given upper bound. Make sure that @@ -165,12 +172,18 @@ impl GeneralizedTotalizer { /// Incrementally builds the GTE encoding to that upper bounds /// in the range `max_ub..=min_ub` can be enforced. New variables will /// be taken from `var_manager`. - fn encode_ub(&mut self, max_ub: usize, min_ub: usize, var_manager: &mut VarManager) -> Cnf { + fn encode_ub( + &mut self, + max_ub: usize, + min_ub: usize, + var_manager: &mut VarManager, + ) -> PyResult { let mut cnf = RsCnf::new(); let var_manager: &mut BasicVarManager = var_manager.into(); - self.0 - .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager); - cnf.into() + handle_oom!(self + .0 + .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager)); + Ok(cnf.into()) } /// Gets assumptions to enforce the given upper bound. Make sure that @@ -235,12 +248,18 @@ impl DynamicPolyWatchdog { /// Incrementally builds the DPW encoding to that upper bounds /// in the range `max_ub..=min_ub` can be enforced. New variables will /// be taken from `var_manager`. - fn encode_ub(&mut self, max_ub: usize, min_ub: usize, var_manager: &mut VarManager) -> Cnf { + fn encode_ub( + &mut self, + max_ub: usize, + min_ub: usize, + var_manager: &mut VarManager, + ) -> PyResult { let mut cnf = RsCnf::new(); let var_manager: &mut BasicVarManager = var_manager.into(); - self.0 - .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager); - cnf.into() + handle_oom!(self + .0 + .encode_ub_change(max_ub..=min_ub, &mut cnf, var_manager)); + Ok(cnf.into()) } /// Gets assumptions to enforce the given upper bound. Make sure that diff --git a/pyapi/src/lib.rs b/pyapi/src/lib.rs index 3ef13937..6cf1f0a3 100644 --- a/pyapi/src/lib.rs +++ b/pyapi/src/lib.rs @@ -70,3 +70,13 @@ fn rustsat(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { Ok(()) } + +macro_rules! handle_oom { + ($result:expr) => {{ + match $result { + Ok(val) => val, + Err(err) => return Err(pyo3::exceptions::PyMemoryError::new_err(format!("{}", err))), + } + }}; +} +pub(crate) use handle_oom; diff --git a/rustsat/examples/profiling.rs b/rustsat/examples/profiling.rs index 0cb4f122..954065fd 100644 --- a/rustsat/examples/profiling.rs +++ b/rustsat/examples/profiling.rs @@ -73,7 +73,7 @@ fn build_full_ub>(lits: &[(Lit, usi let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(max_var + 1); let mut collector = Cnf::new(); - enc.encode_ub(.., &mut collector, &mut var_manager); + enc.encode_ub(.., &mut collector, &mut var_manager).unwrap(); } fn main() { diff --git a/rustsat/src/encodings.rs b/rustsat/src/encodings.rs index a30056aa..6433728b 100644 --- a/rustsat/src/encodings.rs +++ b/rustsat/src/encodings.rs @@ -4,7 +4,7 @@ use thiserror::Error; -use crate::types::Lit; +use crate::types::{Clause, Lit}; pub mod am1; pub mod atomics; @@ -13,9 +13,21 @@ pub mod pb; /// Trait for collecting clauses. Mainly used when generating encodings and implemented by /// [`crate::instances::Cnf`], and solvers. -pub trait CollectClauses: Extend { +pub trait CollectClauses { /// Gets the number of clauses in the collection fn n_clauses(&self) -> usize; + /// Extends the clause collector with an iterator of clauses + /// + /// # Error + /// + /// If the collector runs out of memory, return an [`crate::OutOfMemory`] error. + fn extend_clauses(&mut self, cl_iter: T) -> Result<(), crate::OutOfMemory> + where + T: IntoIterator; + /// Adds one clause to the collector + fn add_clause(&mut self, cl: Clause) -> Result<(), crate::OutOfMemory> { + self.extend_clauses([cl]) + } } /// Errors from encodings diff --git a/rustsat/src/encodings/am1.rs b/rustsat/src/encodings/am1.rs index 63648aa4..1190e021 100644 --- a/rustsat/src/encodings/am1.rs +++ b/rustsat/src/encodings/am1.rs @@ -20,7 +20,7 @@ //! enc.encode(&mut encoding, &mut var_manager).unwrap(); //! ``` -use super::{CollectClauses, Error}; +use super::CollectClauses; use crate::instances::ManageVars; mod pairwise; @@ -35,7 +35,7 @@ pub trait Encode { &mut self, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses; } diff --git a/rustsat/src/encodings/am1/pairwise.rs b/rustsat/src/encodings/am1/pairwise.rs index e4513a56..dac0efb0 100644 --- a/rustsat/src/encodings/am1/pairwise.rs +++ b/rustsat/src/encodings/am1/pairwise.rs @@ -7,7 +7,7 @@ use super::Encode; use crate::{ clause, - encodings::{CollectClauses, EncodeStats, Error, IterInputs}, + encodings::{CollectClauses, EncodeStats, IterInputs}, instances::ManageVars, types::Lit, }; @@ -34,7 +34,7 @@ impl Encode for Pairwise { &mut self, collector: &mut Col, _var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, { @@ -43,7 +43,7 @@ impl Encode for Pairwise { let clause_iter = (0..self.in_lits.len()).flat_map(|first| { (first + 1..self.in_lits.len()).map(move |second| clause![!lits[first], !lits[second]]) }); - collector.extend(clause_iter); + collector.extend_clauses(clause_iter)?; self.n_clauses = collector.n_clauses() - prev_clauses; Ok(()) } diff --git a/rustsat/src/encodings/card.rs b/rustsat/src/encodings/card.rs index 9ba9f4d9..a0825641 100644 --- a/rustsat/src/encodings/card.rs +++ b/rustsat/src/encodings/card.rs @@ -67,7 +67,8 @@ pub trait BoundUpper: Encode { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; /// Returns assumptions/units for enforcing an upper bound (`sum of lits <= @@ -76,24 +77,28 @@ pub trait BoundUpper: Encode { /// [`Error::NotEncoded`] will be returned. fn enforce_ub(&self, ub: usize) -> Result, Error>; /// Encodes an upper bound cardinality constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_ub_constr( constr: CardUBConstr, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator + Sized, { let (lits, ub) = constr.decompose(); let mut enc = Self::from_iter(lits); - enc.encode_ub(ub..ub + 1, collector, var_manager); - collector.extend( + enc.encode_ub(ub..ub + 1, collector, var_manager)?; + collector.extend_clauses( enc.enforce_ub(ub) .unwrap() .into_iter() .map(|unit| clause![unit]), - ); + )?; Ok(()) } } @@ -110,7 +115,8 @@ pub trait BoundLower: Encode { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; /// Returns assumptions/units for enforcing a lower bound (`sum of lits >= @@ -121,24 +127,28 @@ pub trait BoundLower: Encode { /// returned. fn enforce_lb(&self, lb: usize) -> Result, Error>; /// Encodes a lower bound cardinality constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_lb_constr( constr: CardLBConstr, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator + Sized, { let (lits, lb) = constr.decompose(); let mut enc = Self::from_iter(lits); - enc.encode_lb(lb..lb + 1, collector, var_manager); - collector.extend( + enc.encode_lb(lb..lb + 1, collector, var_manager)?; + collector.extend_clauses( enc.enforce_lb(lb) .unwrap() .into_iter() .map(|unit| clause![unit]), - ); + )?; Ok(()) } } @@ -154,12 +164,14 @@ pub trait BoundBoth: BoundUpper + BoundLower { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds + Clone, { - self.encode_ub(range.clone(), collector, var_manager); - self.encode_lb(range, collector, var_manager); + self.encode_ub(range.clone(), collector, var_manager)?; + self.encode_lb(range, collector, var_manager)?; + Ok(()) } /// Returns assumptions for enforcing an equality (`sum of lits = b`) or an /// error if the encoding does not support one of the two required bound @@ -174,32 +186,40 @@ pub trait BoundBoth: BoundUpper + BoundLower { Ok(assumps) } /// Encodes an equality cardinality constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_eq_constr( constr: CardEQConstr, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator + Sized, { let (lits, b) = constr.decompose(); let mut enc = Self::from_iter(lits); - enc.encode_both(b..b + 1, collector, var_manager); - collector.extend( + enc.encode_both(b..b + 1, collector, var_manager)?; + collector.extend_clauses( enc.enforce_eq(b) .unwrap() .into_iter() .map(|unit| clause![unit]), - ); + )?; Ok(()) } /// Encodes any cardinality constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_constr( constr: CardConstraint, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator + Sized, @@ -235,7 +255,8 @@ pub trait BoundUpperIncremental: BoundUpper + EncodeIncremental { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; } @@ -252,7 +273,8 @@ pub trait BoundLowerIncremental: BoundLower + EncodeIncremental { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; } @@ -268,11 +290,12 @@ pub trait BoundBothIncremental: BoundUpperIncremental + BoundLowerIncremental { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds + Clone, { - self.encode_ub_change(range.clone(), collector, var_manager); + self.encode_ub_change(range.clone(), collector, var_manager)?; self.encode_lb_change(range, collector, var_manager) } } @@ -330,7 +353,7 @@ pub fn default_encode_cardinality_constraint( constr: CardConstraint, collector: &mut Col, var_manager: &mut dyn ManageVars, -) { +) -> Result<(), crate::OutOfMemory> { encode_cardinality_constraint::(constr, collector, var_manager) } @@ -339,27 +362,28 @@ pub fn encode_cardinality_constraint, Col: Col constr: CardConstraint, collector: &mut Col, var_manager: &mut dyn ManageVars, -) { +) -> Result<(), crate::OutOfMemory> { if constr.is_tautology() { - return; + return Ok(()); } if constr.is_unsat() { - collector.extend([Clause::new()]); - return; + return collector.add_clause(Clause::new()); } if constr.is_positive_assignment() { - collector.extend(constr.into_lits().into_iter().map(|lit| clause![lit])); - return; + return collector.extend_clauses(constr.into_lits().into_iter().map(|lit| clause![lit])); } if constr.is_negative_assignment() { - collector.extend(constr.into_lits().into_iter().map(|lit| clause![!lit])); - return; + return collector.extend_clauses(constr.into_lits().into_iter().map(|lit| clause![!lit])); } if constr.is_clause() { - collector.extend([constr.into_clause().unwrap()]); - return; + return collector.add_clause(constr.into_clause().unwrap()); + } + match CE::encode_constr(constr, collector, var_manager) { + Ok(_) => Ok(()), + Err(err) => Err(err + .downcast::() + .expect("unexpected error when encoding constraint")), } - CE::encode_constr(constr, collector, var_manager).unwrap() } fn prepare_ub_range>(enc: &Enc, range: R) -> Range { diff --git a/rustsat/src/encodings/card/dbtotalizer.rs b/rustsat/src/encodings/card/dbtotalizer.rs index 59f10b11..099d823f 100644 --- a/rustsat/src/encodings/card/dbtotalizer.rs +++ b/rustsat/src/encodings/card/dbtotalizer.rs @@ -99,7 +99,12 @@ impl EncodeIncremental for DbTotalizer { } impl BoundUpper for DbTotalizer { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -141,24 +146,26 @@ impl BoundUpperIncremental for DbTotalizer { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } self.extend_tree(); if let Some(id) = self.root { let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); for idx in range { - self.db.define_pos_tot(id, idx, collector, var_manager); + self.db.define_pos_tot(id, idx, collector, var_manager)?; } self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; - } + }; + Ok(()) } } @@ -639,7 +646,7 @@ impl TotDb { val: usize, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Option + ) -> Result, crate::OutOfMemory> where Col: CollectClauses, { @@ -649,23 +656,28 @@ impl TotDb { Node::Leaf(lit) => { debug_assert_eq!(val, 1); if val != 1 { - return None; + return Ok(None); } - Some(*lit) + Ok(Some(*lit)) } Node::Unit(node) => { if val > node.lits.len() || val == 0 { - return None; + return Ok(None); } // Check if already encoded if let LitData::Lit { lit, enc_pos, .. } = node.lits[val - 1] { if enc_pos { - return Some(lit); + return Ok(Some(lit)); } } - Some(self.define_pos_tot(id, val - 1, collector, var_manager)) + Ok(Some(self.define_pos_tot( + id, + val - 1, + collector, + var_manager, + )?)) } Node::General(node) => { // Check if already encoded @@ -674,10 +686,10 @@ impl TotDb { lit, enc_pos: true, .. } = lit_data { - return Some(*lit); + return Ok(Some(*lit)); } } else { - return None; + return Ok(None); } debug_assert!(val <= node.max_val); @@ -698,16 +710,16 @@ impl TotDb { // Propagate value if lcon.is_possible(val) && lcon.rev_map(val) <= self[lcon.id].max_val() { if let Some(llit) = - self.define_pos(lcon.id, lcon.rev_map(val), collector, var_manager) + self.define_pos(lcon.id, lcon.rev_map(val), collector, var_manager)? { - collector.extend([atomics::lit_impl_lit(llit, olit)]); + collector.add_clause(atomics::lit_impl_lit(llit, olit))?; } } if rcon.is_possible(val) && rcon.rev_map(val) <= self[rcon.id].max_val() { if let Some(rlit) = - self.define_pos(rcon.id, rcon.rev_map(val), collector, var_manager) + self.define_pos(rcon.id, rcon.rev_map(val), collector, var_manager)? { - collector.extend([atomics::lit_impl_lit(rlit, olit)]); + collector.add_clause(atomics::lit_impl_lit(rlit, olit))?; }; } @@ -721,15 +733,16 @@ impl TotDb { let rval_rev = rcon.rev_map(rval); if rcon.is_possible(rval) && rval_rev <= rmax { if let Some(rlit) = - self.define_pos(rcon.id, rval_rev, collector, var_manager) + self.define_pos(rcon.id, rval_rev, collector, var_manager)? { debug_assert!( lcon.len_limit.is_none() || lcon.offset() + 1 == lval ); let llit = self - .define_pos(lcon.id, lval, collector, var_manager) + .define_pos(lcon.id, lval, collector, var_manager)? .unwrap(); - collector.extend([atomics::cube_impl_lit(&[llit, rlit], olit)]); + collector + .add_clause(atomics::cube_impl_lit(&[llit, rlit], olit))?; } } } @@ -741,7 +754,7 @@ impl TotDb { LitData::Lit { enc_pos, .. } => *enc_pos = true, }; - Some(olit) + Ok(Some(olit)) } } } @@ -756,7 +769,7 @@ impl TotDb { idx: usize, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Lit + ) -> Result where Col: CollectClauses, { @@ -764,7 +777,7 @@ impl TotDb { debug_assert!(idx < node.max_val()); if node.is_leaf() { debug_assert_eq!(idx, 0); - return node[1]; + return Ok(node[1]); } let lcon = node.left().unwrap(); let rcon = node.right().unwrap(); @@ -777,7 +790,7 @@ impl TotDb { // Check if already encoded if let LitData::Lit { lit, enc_pos, .. } = node.lits[idx] { if enc_pos { - return lit; + return Ok(lit); } } @@ -803,10 +816,10 @@ impl TotDb { // Encode children (recurse) for lidx in l_min_idx..=l_max_idx { - self.define_pos_tot(lcon.id, con_idx(lidx, lcon), collector, var_manager); + self.define_pos_tot(lcon.id, con_idx(lidx, lcon), collector, var_manager)?; } for ridx in r_min_idx..=r_max_idx { - self.define_pos_tot(rcon.id, con_idx(ridx, rcon), collector, var_manager); + self.define_pos_tot(rcon.id, con_idx(ridx, rcon), collector, var_manager)?; } // Reserve variable for this node, if needed @@ -840,16 +853,16 @@ impl TotDb { // Encode this node if l_max_idx == idx { - collector.extend([atomics::lit_impl_lit( + collector.add_clause(atomics::lit_impl_lit( *llits[con_idx(idx, lcon)].lit().unwrap(), olit, - )]); + ))?; } if r_max_idx == idx { - collector.extend([atomics::lit_impl_lit( + collector.add_clause(atomics::lit_impl_lit( *rlits[con_idx(idx, rcon)].lit().unwrap(), olit, - )]); + ))?; } let clause_for_lidx = |lidx: usize| { let ridx = idx - lidx - 1; @@ -859,7 +872,7 @@ impl TotDb { atomics::cube_impl_lit(&[llit, rlit], olit) }; let clause_iter = (l_min_idx..cmp::min(l_max_idx + 1, idx)).map(clause_for_lidx); - collector.extend(clause_iter); + collector.extend_clauses(clause_iter)?; // Mark positive literal as encoded match &mut self[id].mut_unit().lits[idx] { @@ -867,7 +880,7 @@ impl TotDb { LitData::Lit { enc_pos, .. } => *enc_pos = true, }; - olit + Ok(olit) } /// Recursively reserves all variables in the subtree rooted at the given node @@ -1045,7 +1058,8 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: std::ops::RangeBounds, { @@ -1081,7 +1095,8 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: std::ops::RangeBounds, { @@ -1117,18 +1132,20 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: std::ops::RangeBounds, { let range = super::super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } for idx in range { self.db - .define_pos_tot(self.root, idx, collector, var_manager); + .define_pos_tot(self.root, idx, collector, var_manager)?; } + Ok(()) } } @@ -1138,19 +1155,21 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: std::ops::RangeBounds, { let range = super::super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } for idx in range { self.db .borrow_mut() - .define_pos_tot(self.root, idx, collector, var_manager); + .define_pos_tot(self.root, idx, collector, var_manager)?; } + Ok(()) } } } @@ -1177,22 +1196,26 @@ mod tests { var_manager.increase_next_free(var![4]); let mut cnf = Cnf::new(); - db.define_pos_tot(root, 0, &mut cnf, &mut var_manager); + db.define_pos_tot(root, 0, &mut cnf, &mut var_manager) + .unwrap(); debug_assert_eq!(cnf.len(), 6); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos_tot(root, 1, &mut cnf, &mut var_manager); + db.define_pos_tot(root, 1, &mut cnf, &mut var_manager) + .unwrap(); debug_assert_eq!(cnf.len(), 9); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos_tot(root, 2, &mut cnf, &mut var_manager); + db.define_pos_tot(root, 2, &mut cnf, &mut var_manager) + .unwrap(); debug_assert_eq!(cnf.len(), 8); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos_tot(root, 3, &mut cnf, &mut var_manager); + db.define_pos_tot(root, 3, &mut cnf, &mut var_manager) + .unwrap(); debug_assert_eq!(cnf.len(), 3); } @@ -1209,32 +1232,32 @@ mod tests { var_manager.increase_next_free(var![4]); let mut cnf = Cnf::new(); - db.define_pos(root, 1, &mut cnf, &mut var_manager); + db.define_pos(root, 1, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 0); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 4, &mut cnf, &mut var_manager); + db.define_pos(root, 4, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 3); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 7, &mut cnf, &mut var_manager); + db.define_pos(root, 7, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 3); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 8, &mut cnf, &mut var_manager); + db.define_pos(root, 8, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 2); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 15, &mut cnf, &mut var_manager); + db.define_pos(root, 15, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 4); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 22, &mut cnf, &mut var_manager); + db.define_pos(root, 22, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 3); } @@ -1251,32 +1274,32 @@ mod tests { var_manager.increase_next_free(var![3]); let mut cnf = Cnf::new(); - db.define_pos(root, 1, &mut cnf, &mut var_manager); + db.define_pos(root, 1, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 2); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 2, &mut cnf, &mut var_manager); + db.define_pos(root, 2, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 2); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 3, &mut cnf, &mut var_manager); + db.define_pos(root, 3, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 3); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 4, &mut cnf, &mut var_manager); + db.define_pos(root, 4, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 2); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 5, &mut cnf, &mut var_manager); + db.define_pos(root, 5, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 2); db.reset_encoded(); let mut cnf = Cnf::new(); - db.define_pos(root, 6, &mut cnf, &mut var_manager); + db.define_pos(root, 6, &mut cnf, &mut var_manager).unwrap(); debug_assert_eq!(cnf.len(), 2); } @@ -1288,7 +1311,7 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf = Cnf::new(); - tot.encode_ub(0..5, &mut cnf, &mut var_manager); + tot.encode_ub(0..5, &mut cnf, &mut var_manager).unwrap(); assert_eq!(tot.depth(), 3); println!("len: {}, {:?}", cnf.len(), cnf); assert_eq!(cnf.len(), 14); @@ -1304,7 +1327,7 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf = Cnf::new(); - tot.encode_ub(3..4, &mut cnf, &mut var_manager); + tot.encode_ub(3..4, &mut cnf, &mut var_manager).unwrap(); assert_eq!(tot.depth(), 3); assert_eq!(cnf.len(), 3); assert_eq!(cnf.len(), tot.n_clauses()); @@ -1317,14 +1340,15 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf1 = Cnf::new(); - tot1.encode_ub(0..5, &mut cnf1, &mut var_manager); + tot1.encode_ub(0..5, &mut cnf1, &mut var_manager).unwrap(); let mut tot2 = DbTotalizer::default(); tot2.extend(vec![lit![0], lit![1], lit![2], lit![3]]); let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf2 = Cnf::new(); - tot2.encode_ub(0..3, &mut cnf2, &mut var_manager); - tot2.encode_ub_change(0..5, &mut cnf2, &mut var_manager); + tot2.encode_ub(0..3, &mut cnf2, &mut var_manager).unwrap(); + tot2.encode_ub_change(0..5, &mut cnf2, &mut var_manager) + .unwrap(); assert_eq!(cnf1.len(), cnf2.len()); assert_eq!(cnf1.len(), tot1.n_clauses()); assert_eq!(cnf2.len(), tot2.n_clauses()); diff --git a/rustsat/src/encodings/card/simulators.rs b/rustsat/src/encodings/card/simulators.rs index ca8a1634..7f4b8ed5 100644 --- a/rustsat/src/encodings/card/simulators.rs +++ b/rustsat/src/encodings/card/simulators.rs @@ -121,7 +121,12 @@ impl BoundUpper for Inverted where CE: BoundLower, { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -147,7 +152,12 @@ impl BoundLower for Inverted where CE: BoundUpper, { - fn encode_lb(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_lb( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -178,7 +188,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -199,7 +210,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -325,7 +337,12 @@ where UBE: BoundUpper, LBE: BoundLower, { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -343,7 +360,12 @@ where UBE: BoundUpper, LBE: BoundLower, { - fn encode_lb(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_lb( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -366,7 +388,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -384,7 +407,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { diff --git a/rustsat/src/encodings/card/totalizer.rs b/rustsat/src/encodings/card/totalizer.rs index 4f6e6bf2..71c65241 100644 --- a/rustsat/src/encodings/card/totalizer.rs +++ b/rustsat/src/encodings/card/totalizer.rs @@ -121,14 +121,19 @@ impl EncodeIncremental for Totalizer { } impl BoundUpper for Totalizer { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); }; self.extend_tree(); match &mut self.root { @@ -136,11 +141,12 @@ impl BoundUpper for Totalizer { Some(root) => { let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); - root.rec_encode_ub(range, collector, var_manager); + root.rec_encode_ub(range, collector, var_manager)?; self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; } - } + }; + Ok(()) } fn enforce_ub(&self, ub: usize) -> Result, Error> { @@ -169,14 +175,19 @@ impl BoundUpper for Totalizer { } impl BoundLower for Totalizer { - fn encode_lb(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_lb( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_lb_range(self, range); if range.is_empty() { - return; + return Ok(()); }; self.extend_tree(); match &mut self.root { @@ -184,11 +195,12 @@ impl BoundLower for Totalizer { Some(root) => { let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); - root.rec_encode_lb(range, collector, var_manager); + root.rec_encode_lb(range, collector, var_manager)?; self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; } - } + }; + Ok(()) } fn enforce_lb(&self, lb: usize) -> Result, Error> { @@ -224,13 +236,14 @@ impl BoundUpperIncremental for Totalizer { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); }; self.extend_tree(); match &mut self.root { @@ -238,11 +251,12 @@ impl BoundUpperIncremental for Totalizer { Some(root) => { let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); - root.rec_encode_ub_change(range, collector, var_manager); + root.rec_encode_ub_change(range, collector, var_manager)?; self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; } - } + }; + Ok(()) } } @@ -252,13 +266,14 @@ impl BoundLowerIncremental for Totalizer { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_lb_range(self, range); if range.is_empty() { - return; + return Ok(()); }; self.extend_tree(); match &mut self.root { @@ -266,11 +281,12 @@ impl BoundLowerIncremental for Totalizer { Some(root) => { let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); - root.rec_encode_lb_change(range, collector, var_manager); + root.rec_encode_lb_change(range, collector, var_manager)?; self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; } - } + }; + Ok(()) } } @@ -391,12 +407,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } // Reserve vars if needed @@ -449,9 +466,11 @@ impl Node { (0..=right_lits.len()) .filter_map(move |right_val| clause_for_vals(left_val, right_val)) }); - collector.extend(clause_iter); + collector.extend_clauses(clause_iter)?; } - } + }; + + Ok(()) } /// Encodes the lower bound adder for this node in a given range. This @@ -462,12 +481,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } // Reserve vars if needed @@ -527,9 +547,11 @@ impl Node { (0..=right_lits.len()) .filter_map(move |right_val| clause_for_vals(left_val, right_val)) }); - collector.extend(clause_iter); + collector.extend_clauses(clause_iter)?; } - } + }; + + Ok(()) } /// Encodes the upper bound adder from the children to this node in a given @@ -540,12 +562,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } match self { @@ -562,16 +585,17 @@ impl Node { let left_range = Node::compute_required_range(range.clone(), right.max_val()); let right_range = Node::compute_required_range(range.clone(), left.max_val()); // Recurse - left.rec_encode_ub(left_range, collector, var_manager); - right.rec_encode_ub(right_range, collector, var_manager); + left.rec_encode_ub(left_range, collector, var_manager)?; + right.rec_encode_ub(right_range, collector, var_manager)?; // Ignore all previous encoding and encode from scratch let n_clauses_before = collector.n_clauses(); - self.encode_ub_range(range.clone(), collector, var_manager); + self.encode_ub_range(range.clone(), collector, var_manager)?; self.update_stats(range, lb_range, collector.n_clauses() - n_clauses_before); } } + Ok(()) } /// Encodes the lower bound adder from the children to this node in a given @@ -582,12 +606,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } match self { @@ -604,16 +629,18 @@ impl Node { let left_range = Node::compute_required_range(range.clone(), right.max_val()); let right_range = Node::compute_required_range(range.clone(), left.max_val()); // Recurse - left.rec_encode_lb(left_range, collector, var_manager); - right.rec_encode_lb(right_range, collector, var_manager); + left.rec_encode_lb(left_range, collector, var_manager)?; + right.rec_encode_lb(right_range, collector, var_manager)?; // Ignore all previous encoding and encode from scratch let n_clauses_before = collector.n_clauses(); - self.encode_lb_range(range.clone(), collector, var_manager); + self.encode_lb_range(range.clone(), collector, var_manager)?; self.update_stats(ub_range, range, collector.n_clauses() - n_clauses_before); } - } + }; + + Ok(()) } /// Encodes the upper bound adder from the children to this node in a given @@ -623,12 +650,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } match self { @@ -647,27 +675,29 @@ impl Node { let left_range = Node::compute_required_range(range.clone(), right.max_val()); let right_range = Node::compute_required_range(range.clone(), left.max_val()); // Recurse - left.rec_encode_ub_change(left_range, collector, var_manager); - right.rec_encode_ub_change(right_range, collector, var_manager); + left.rec_encode_ub_change(left_range, collector, var_manager)?; + right.rec_encode_ub_change(right_range, collector, var_manager)?; // Encode changes for current node let n_clauses_before = collector.n_clauses(); if ub_range.is_empty() { // First time encoding this node - self.encode_ub_range(range.clone(), collector, var_manager) + self.encode_ub_range(range.clone(), collector, var_manager)?; } else { // Part already encoded if range.start < ub_range.start { - self.encode_ub_range(range.start..ub_range.start, collector, var_manager); + self.encode_ub_range(range.start..ub_range.start, collector, var_manager)?; }; if range.end > ub_range.end { - self.encode_ub_range(ub_range.end..range.end, collector, var_manager); + self.encode_ub_range(ub_range.end..range.end, collector, var_manager)?; }; }; self.update_stats(range, lb_range, collector.n_clauses() - n_clauses_before); } - } + }; + + Ok(()) } /// Encodes the lower bound adder from the children to this node in a given @@ -677,7 +707,8 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { match self { @@ -696,27 +727,29 @@ impl Node { let left_range = Node::compute_required_range(range.clone(), right.max_val()); let right_range = Node::compute_required_range(range.clone(), left.max_val()); // Recurse - left.rec_encode_lb_change(left_range, collector, var_manager); - right.rec_encode_lb_change(right_range, collector, var_manager); + left.rec_encode_lb_change(left_range, collector, var_manager)?; + right.rec_encode_lb_change(right_range, collector, var_manager)?; // Encode changes for current node let n_clauses_before = collector.n_clauses(); if lb_range.is_empty() { // First time encoding this node - self.encode_lb_range(range.clone(), collector, var_manager) + self.encode_lb_range(range.clone(), collector, var_manager)?; } else { // Part already encoded if range.start < lb_range.start { - self.encode_lb_range(range.start..lb_range.start, collector, var_manager); + self.encode_lb_range(range.start..lb_range.start, collector, var_manager)?; }; if range.end > lb_range.end { - self.encode_lb_range(lb_range.end..range.end, collector, var_manager); + self.encode_lb_range(lb_range.end..range.end, collector, var_manager)?; }; }; self.update_stats(ub_range, range, collector.n_clauses() - n_clauses_before); } - } + }; + + Ok(()) } /// Reserves variables this node might need for indices in a given range. @@ -854,8 +887,10 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![2]); let mut cnf = Cnf::new(); - node.encode_ub_range(0..3, &mut cnf, &mut var_manager); - node.encode_lb_range(0..3, &mut cnf, &mut var_manager); + node.encode_ub_range(0..3, &mut cnf, &mut var_manager) + .unwrap(); + node.encode_lb_range(0..3, &mut cnf, &mut var_manager) + .unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 2), @@ -892,8 +927,10 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![5]); let mut cnf = Cnf::new(); - node.encode_ub_range(0..5, &mut cnf, &mut var_manager); - node.encode_lb_range(0..5, &mut cnf, &mut var_manager); + node.encode_ub_range(0..5, &mut cnf, &mut var_manager) + .unwrap(); + node.encode_lb_range(0..5, &mut cnf, &mut var_manager) + .unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 4), @@ -910,7 +947,8 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![2]); let mut cnf = Cnf::new(); - node.encode_lb_range(0..2, &mut cnf, &mut var_manager); + node.encode_lb_range(0..2, &mut cnf, &mut var_manager) + .unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 1), @@ -947,8 +985,10 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![7]); let mut cnf = Cnf::new(); - node.encode_ub_range(0..4, &mut cnf, &mut var_manager); - node.encode_lb_range(0..4, &mut cnf, &mut var_manager); + node.encode_ub_range(0..4, &mut cnf, &mut var_manager) + .unwrap(); + node.encode_lb_range(0..4, &mut cnf, &mut var_manager) + .unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 4), @@ -985,8 +1025,10 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![7]); let mut cnf = Cnf::new(); - node.encode_ub_range(3..3, &mut cnf, &mut var_manager); - node.encode_lb_range(3..3, &mut cnf, &mut var_manager); + node.encode_ub_range(3..3, &mut cnf, &mut var_manager) + .unwrap(); + node.encode_lb_range(3..3, &mut cnf, &mut var_manager) + .unwrap(); assert_eq!(cnf.len(), 0); } @@ -1019,8 +1061,10 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![7]); let mut cnf = Cnf::new(); - node.encode_ub_range(2..4, &mut cnf, &mut var_manager); - node.encode_lb_range(2..4, &mut cnf, &mut var_manager); + node.encode_ub_range(2..4, &mut cnf, &mut var_manager) + .unwrap(); + node.encode_lb_range(2..4, &mut cnf, &mut var_manager) + .unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 4), @@ -1037,8 +1081,8 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf = Cnf::new(); - tot.encode_ub(0..5, &mut cnf, &mut var_manager); - tot.encode_lb(0..5, &mut cnf, &mut var_manager); + tot.encode_ub(0..5, &mut cnf, &mut var_manager).unwrap(); + tot.encode_lb(0..5, &mut cnf, &mut var_manager).unwrap(); assert_eq!(tot.depth(), 3); assert_eq!(cnf.len(), 28); assert_eq!(tot.n_clauses(), 28); @@ -1054,7 +1098,7 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf = Cnf::new(); - tot.encode_both(3..4, &mut cnf, &mut var_manager); + tot.encode_both(3..4, &mut cnf, &mut var_manager).unwrap(); assert_eq!(tot.depth(), 3); assert_eq!(cnf.len(), 12); assert_eq!(cnf.len(), tot.n_clauses()); @@ -1067,14 +1111,15 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf1 = Cnf::new(); - tot1.encode_ub(0..5, &mut cnf1, &mut var_manager); + tot1.encode_ub(0..5, &mut cnf1, &mut var_manager).unwrap(); let mut tot2 = Totalizer::default(); tot2.extend(vec![lit![0], lit![1], lit![2], lit![3]]); let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf2 = Cnf::new(); - tot2.encode_ub(0..3, &mut cnf2, &mut var_manager); - tot2.encode_ub_change(0..5, &mut cnf2, &mut var_manager); + tot2.encode_ub(0..3, &mut cnf2, &mut var_manager).unwrap(); + tot2.encode_ub_change(0..5, &mut cnf2, &mut var_manager) + .unwrap(); assert_eq!(cnf1.len(), cnf2.len()); assert_eq!(cnf1.len(), tot1.n_clauses()); assert_eq!(cnf2.len(), tot2.n_clauses()); @@ -1087,14 +1132,15 @@ mod tests { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf1 = Cnf::new(); - tot1.encode_lb(0..5, &mut cnf1, &mut var_manager); + tot1.encode_lb(0..5, &mut cnf1, &mut var_manager).unwrap(); let mut tot2 = Totalizer::default(); tot2.extend(vec![lit![0], lit![1], lit![2], lit![3]]); let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); let mut cnf2 = Cnf::new(); - tot2.encode_lb(0..3, &mut cnf2, &mut var_manager); - tot2.encode_lb_change(0..5, &mut cnf2, &mut var_manager); + tot2.encode_lb(0..3, &mut cnf2, &mut var_manager).unwrap(); + tot2.encode_lb_change(0..5, &mut cnf2, &mut var_manager) + .unwrap(); assert_eq!(cnf1.len(), cnf2.len()); assert_eq!(cnf1.len(), tot1.n_clauses()); assert_eq!(cnf2.len(), tot2.n_clauses()); diff --git a/rustsat/src/encodings/pb.rs b/rustsat/src/encodings/pb.rs index bb426bf9..b8f1e470 100644 --- a/rustsat/src/encodings/pb.rs +++ b/rustsat/src/encodings/pb.rs @@ -91,7 +91,8 @@ pub trait BoundUpper: Encode { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; /// Returns assumptions/units for enforcing an upper bound (`weighted sum of @@ -100,29 +101,33 @@ pub trait BoundUpper: Encode { /// [`Error::NotEncoded`] will be returned. fn enforce_ub(&self, ub: usize) -> Result, Error>; /// Encodes an upper bound pseudo-boolean constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_ub_constr( constr: PBUBConstr, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator<(Lit, usize)> + Sized, { let (lits, ub) = constr.decompose(); let ub = if ub < 0 { - return Err(Error::Unsat); + anyhow::bail!(Error::Unsat); } else { ub as usize }; let mut enc = Self::from_iter(lits); - enc.encode_ub(ub..ub + 1, collector, var_manager); - collector.extend( + enc.encode_ub(ub..ub + 1, collector, var_manager)?; + collector.extend_clauses( enc.enforce_ub(ub) .unwrap() .into_iter() .map(|unit| clause![unit]), - ); + )?; Ok(()) } /// Gets the next smaller upper bound value that can be _easily_ encoded. This @@ -145,7 +150,8 @@ pub trait BoundLower: Encode { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; /// Returns assumptions/units for enforcing a lower bound (`sum of lits >= @@ -156,11 +162,15 @@ pub trait BoundLower: Encode { /// is returned. fn enforce_lb(&self, lb: usize) -> Result, Error>; /// Encodes a lower bound pseudo-boolean constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_lb_constr( constr: PBLBConstr, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator<(Lit, usize)> + Sized, @@ -172,13 +182,13 @@ pub trait BoundLower: Encode { lb as usize }; let mut enc = Self::from_iter(lits); - enc.encode_lb(lb..lb + 1, collector, var_manager); - collector.extend( + enc.encode_lb(lb..lb + 1, collector, var_manager)?; + collector.extend_clauses( enc.enforce_lb(lb) .unwrap() .into_iter() .map(|unit| clause![unit]), - ); + )?; Ok(()) } /// Gets the next greater lower bound value that can be _easily_ encoded. This @@ -199,12 +209,14 @@ pub trait BoundBoth: BoundUpper + BoundLower { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds + Clone, { - self.encode_ub(range.clone(), collector, var_manager); - self.encode_lb(range, collector, var_manager); + self.encode_ub(range.clone(), collector, var_manager)?; + self.encode_lb(range, collector, var_manager)?; + Ok(()) } /// Returns assumptions for enforcing an equality (`sum of lits = b`) or an /// error if the encoding does not support one of the two required bound @@ -219,37 +231,45 @@ pub trait BoundBoth: BoundUpper + BoundLower { Ok(assumps) } /// Encodes an equality pseudo-boolean constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_eq_constr( constr: PBEQConstr, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator<(Lit, usize)> + Sized, { let (lits, b) = constr.decompose(); let b = if b < 0 { - return Err(Error::Unsat); + anyhow::bail!(Error::Unsat); } else { b as usize }; let mut enc = Self::from_iter(lits); - enc.encode_both(b..b + 1, collector, var_manager); - collector.extend( + enc.encode_both(b..b + 1, collector, var_manager)?; + collector.extend_clauses( enc.enforce_eq(b) .unwrap() .into_iter() .map(|unit| clause![unit]), - ); + )?; Ok(()) } /// Encodes any pseudo-boolean constraint to CNF + /// + /// # Errors + /// + /// Either an [`Error`] of [`crate::OutOfMemory`] fn encode_constr( constr: PBConstraint, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) -> Result<(), Error> + ) -> anyhow::Result<()> where Col: CollectClauses, Self: FromIterator<(Lit, usize)> + Sized, @@ -285,7 +305,8 @@ pub trait BoundUpperIncremental: BoundUpper + EncodeIncremental { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; } @@ -302,7 +323,8 @@ pub trait BoundLowerIncremental: BoundLower + EncodeIncremental { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds; } @@ -318,12 +340,14 @@ pub trait BoundBothIncremental: BoundUpperIncremental + BoundLowerIncremental { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds + Clone, { - self.encode_ub_change(range.clone(), collector, var_manager); - self.encode_lb_change(range, collector, var_manager); + self.encode_ub_change(range.clone(), collector, var_manager)?; + self.encode_lb_change(range, collector, var_manager)?; + Ok(()) } } @@ -381,7 +405,7 @@ pub fn default_encode_pb_constraint( constr: PBConstraint, collector: &mut Col, var_manager: &mut dyn ManageVars, -) { +) -> Result<(), crate::OutOfMemory> { encode_pb_constraint::(constr, collector, var_manager) } @@ -390,31 +414,34 @@ pub fn encode_pb_constraint, Col: Co constr: PBConstraint, collector: &mut Col, var_manager: &mut dyn ManageVars, -) { +) -> Result<(), crate::OutOfMemory> { if constr.is_tautology() { - return; + return Ok(()); } if constr.is_unsat() { - collector.extend([Clause::new()]); - return; + return collector.add_clause(Clause::new()); } if constr.is_positive_assignment() { - collector.extend(constr.into_lits().into_iter().map(|(lit, _)| clause![lit])); - return; + return collector + .extend_clauses(constr.into_lits().into_iter().map(|(lit, _)| clause![lit])); } if constr.is_negative_assignment() { - collector.extend(constr.into_lits().into_iter().map(|(lit, _)| clause![!lit])); - return; + return collector + .extend_clauses(constr.into_lits().into_iter().map(|(lit, _)| clause![!lit])); } if constr.is_clause() { - collector.extend([constr.into_clause().unwrap()]); - return; + return collector.add_clause(constr.into_clause().unwrap()); } if constr.is_card() { let card = constr.into_card_constr().unwrap(); return card::default_encode_cardinality_constraint(card, collector, var_manager); } - PBE::encode_constr(constr, collector, var_manager).unwrap() + match PBE::encode_constr(constr, collector, var_manager) { + Ok(_) => Ok(()), + Err(err) => Err(err + .downcast::() + .expect("unexpected error when encoding constraint")), + } } fn prepare_ub_range>(enc: &Enc, range: R) -> Range { diff --git a/rustsat/src/encodings/pb/dbgte.rs b/rustsat/src/encodings/pb/dbgte.rs index 04552b65..8187c048 100644 --- a/rustsat/src/encodings/pb/dbgte.rs +++ b/rustsat/src/encodings/pb/dbgte.rs @@ -158,13 +158,18 @@ impl EncodeIncremental for DbGte { } impl BoundUpper for DbGte { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, { self.db.reset_encoded(); - self.encode_ub_change(range, collector, var_manager); + self.encode_ub_change(range, collector, var_manager) } fn enforce_ub(&self, ub: usize) -> Result, Error> { @@ -221,13 +226,14 @@ impl BoundUpperIncremental for DbGte { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); @@ -238,14 +244,16 @@ impl BoundUpperIncremental for DbGte { con.rev_map_round_up(range.start + 1) ..=con.rev_map(range.end + self.max_leaf_weight), ) - .for_each(|val| { + .try_for_each(|val| { self.db - .define_pos(con.id, val, collector, var_manager) + .define_pos(con.id, val, collector, var_manager)? .unwrap(); - }) + Ok::<(), crate::OutOfMemory>(()) + })? } self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; + Ok(()) } } @@ -435,7 +443,8 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -490,7 +499,8 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -545,24 +555,27 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } self.db[self.root.id] .vals( self.root.rev_map_round_up(range.start + 1) ..=self.root.rev_map(range.end + self.max_leaf_weight), ) - .for_each(|val| { + .try_for_each(|val| { self.db - .define_pos(self.root.id, val, collector, var_manager) + .define_pos(self.root.id, val, collector, var_manager)? .unwrap(); - }); + Ok::<(), crate::OutOfMemory>(()) + })?; + Ok(()) } } @@ -572,24 +585,27 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } - let vals = self.db.borrow()[self.root.id].vals( + let mut vals = self.db.borrow()[self.root.id].vals( self.root.rev_map_round_up(range.start + 1) ..=self.root.rev_map(range.end + self.max_leaf_weight), ); - vals.for_each(|val| { + vals.try_for_each(|val| { self.db .borrow_mut() - .define_pos(self.root.id, val, collector, var_manager) + .define_pos(self.root.id, val, collector, var_manager)? .unwrap(); - }); + Ok::<(), crate::OutOfMemory>(()) + })?; + Ok(()) } } } @@ -620,7 +636,8 @@ mod tests { gte.extend(lits); assert_eq!(gte.enforce_ub(4), Err(Error::NotEncoded)); let mut var_manager = BasicVarManager::default(); - gte.encode_ub(0..7, &mut Cnf::new(), &mut var_manager); + gte.encode_ub(0..7, &mut Cnf::new(), &mut var_manager) + .unwrap(); assert_eq!(gte.depth(), 3); assert_eq!(gte.n_vars(), 10); } @@ -636,13 +653,14 @@ mod tests { gte1.extend(lits.clone()); let mut var_manager = BasicVarManager::default(); let mut cnf1 = Cnf::new(); - gte1.encode_ub(0..5, &mut cnf1, &mut var_manager); + gte1.encode_ub(0..5, &mut cnf1, &mut var_manager).unwrap(); let mut gte2 = DbGte::default(); gte2.extend(lits); let mut var_manager = BasicVarManager::default(); let mut cnf2 = Cnf::new(); - gte2.encode_ub(0..3, &mut cnf2, &mut var_manager); - gte2.encode_ub_change(0..5, &mut cnf2, &mut var_manager); + gte2.encode_ub(0..3, &mut cnf2, &mut var_manager).unwrap(); + gte2.encode_ub_change(0..5, &mut cnf2, &mut var_manager) + .unwrap(); assert_eq!(cnf1.len(), cnf2.len()); assert_eq!(cnf1.len(), gte1.n_clauses()); assert_eq!(cnf2.len(), gte2.n_clauses()); @@ -659,7 +677,7 @@ mod tests { gte1.extend(lits); let mut var_manager = BasicVarManager::default(); let mut cnf1 = Cnf::new(); - gte1.encode_ub(0..5, &mut cnf1, &mut var_manager); + gte1.encode_ub(0..5, &mut cnf1, &mut var_manager).unwrap(); let mut gte2 = DbGte::default(); let mut lits = RsHashMap::default(); lits.insert(lit![0], 10); @@ -669,7 +687,7 @@ mod tests { gte2.extend(lits); let mut var_manager = BasicVarManager::default(); let mut cnf2 = Cnf::new(); - gte2.encode_ub(0..9, &mut cnf2, &mut var_manager); + gte2.encode_ub(0..9, &mut cnf2, &mut var_manager).unwrap(); assert_eq!(cnf1.len(), cnf2.len()); assert_eq!(cnf1.len(), gte1.n_clauses()); assert_eq!(cnf2.len(), gte2.n_clauses()); @@ -692,7 +710,8 @@ mod tests { lits.insert(lit![6], 1); gte.extend(lits); let mut gte_cnf = Cnf::new(); - gte.encode_ub(3..8, &mut gte_cnf, &mut var_manager_gte); + gte.encode_ub(3..8, &mut gte_cnf, &mut var_manager_gte) + .unwrap(); // Set up Tot let mut tot = card::Totalizer::default(); tot.extend(vec![ @@ -705,7 +724,7 @@ mod tests { lit![6], ]); let mut tot_cnf = Cnf::new(); - card::BoundUpper::encode_ub(&mut tot, 3..8, &mut tot_cnf, &mut var_manager_tot); + card::BoundUpper::encode_ub(&mut tot, 3..8, &mut tot_cnf, &mut var_manager_tot).unwrap(); println!("{:?}", gte_cnf); println!("{:?}", tot_cnf); assert_eq!(var_manager_gte.new_var(), var_manager_tot.new_var()); diff --git a/rustsat/src/encodings/pb/dpw.rs b/rustsat/src/encodings/pb/dpw.rs index 888c2b70..4ba90a46 100644 --- a/rustsat/src/encodings/pb/dpw.rs +++ b/rustsat/src/encodings/pb/dpw.rs @@ -130,7 +130,12 @@ impl EncodeIncremental for DynamicPolyWatchdog { } impl BoundUpper for DynamicPolyWatchdog { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -180,13 +185,14 @@ impl BoundUpperIncremental for DynamicPolyWatchdog { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_ub_range(self, range); if range.is_empty() || self.in_lits.len() <= 1 { - return; + return Ok(()); } let n_vars_before = var_manager.n_used(); if self.structure.is_none() && !self.in_lits.is_empty() { @@ -202,13 +208,14 @@ impl BoundUpperIncremental for DynamicPolyWatchdog { let output_weight = 1 << (structure.output_power()); let output_range = range.start / output_weight..(range.end - 1) / output_weight + 1; for oidx in output_range { - encode_output(structure, oidx, &mut self.db, collector, var_manager); + encode_output(structure, oidx, &mut self.db, collector, var_manager)?; } self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; } None => (), - } + }; + Ok(()) } } @@ -345,7 +352,8 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -369,7 +377,8 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -393,19 +402,21 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } let output_weight = 1 << self.structure.output_power(); let output_range = range.start / output_weight..(range.end - 1) / output_weight + 1; for oidx in output_range { - encode_output(self.structure, oidx, self.db, collector, var_manager); + encode_output(self.structure, oidx, self.db, collector, var_manager)?; } + Ok(()) } } @@ -415,13 +426,14 @@ pub mod referenced { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); } let output_weight = 1 << self.structure.output_power(); let output_range = range.start / output_weight..(range.end - 1) / output_weight + 1; @@ -432,8 +444,9 @@ pub mod referenced { &mut self.db.borrow_mut(), collector, var_manager, - ); + )?; } + Ok(()) } } } @@ -586,13 +599,15 @@ fn encode_output( tot_db: &mut TotDb, collector: &mut Col, var_manager: &mut dyn ManageVars, -) where +) -> Result<(), crate::OutOfMemory> +where Col: CollectClauses, { if oidx >= tot_db[dpw.root].max_val() { - return; + return Ok(()); } - tot_db.define_pos_tot(dpw.root, oidx, collector, var_manager); + tot_db.define_pos_tot(dpw.root, oidx, collector, var_manager)?; + Ok(()) } /// Enforces an upper bound value on a DPW [`Structure`] @@ -649,7 +664,7 @@ mod tests { let mut dpw = DynamicPolyWatchdog::from(lits); let mut var_manager = BasicVarManager::from_next_free(Var::new(4)); let mut cnf = Cnf::new(); - dpw.encode_ub(0..=6, &mut cnf, &mut var_manager); + dpw.encode_ub(0..=6, &mut cnf, &mut var_manager).unwrap(); assert_eq!(dpw.n_vars(), 9); assert_eq!(cnf.len(), 13); } @@ -661,7 +676,7 @@ mod tests { let mut dpw = DynamicPolyWatchdog::from(lits); let mut var_manager = BasicVarManager::from_next_free(Var::new(1)); let mut cnf = Cnf::new(); - dpw.encode_ub(0..=6, &mut cnf, &mut var_manager); + dpw.encode_ub(0..=6, &mut cnf, &mut var_manager).unwrap(); assert_eq!(dpw.n_vars(), 0); assert_eq!(cnf.len(), 0); debug_assert!(dpw.enforce_ub(4).unwrap().is_empty()); @@ -676,7 +691,7 @@ mod tests { let mut dpw = DynamicPolyWatchdog::from(lits); let mut var_manager = BasicVarManager::default(); let mut cnf = Cnf::new(); - dpw.encode_ub(0..=6, &mut cnf, &mut var_manager); + dpw.encode_ub(0..=6, &mut cnf, &mut var_manager).unwrap(); assert_eq!(dpw.n_vars(), 0); assert_eq!(cnf.len(), 0); debug_assert!(dpw.enforce_ub(4).unwrap().is_empty()); @@ -693,7 +708,7 @@ mod tests { let mut dpw = DynamicPolyWatchdog::from(lits); let mut var_manager = BasicVarManager::default(); let mut cnf = Cnf::new(); - dpw.encode_ub(0..23, &mut cnf, &mut var_manager); + dpw.encode_ub(0..23, &mut cnf, &mut var_manager).unwrap(); for ub in 7..23 { let coarse_ub = dpw.coarse_ub(ub); debug_assert!(coarse_ub <= ub); @@ -715,7 +730,7 @@ mod tests { let mut dpw = DynamicPolyWatchdog::from(lits); let mut var_manager = BasicVarManager::default(); let mut cnf = Cnf::new(); - dpw.encode_ub(0..=4, &mut cnf, &mut var_manager); + dpw.encode_ub(0..=4, &mut cnf, &mut var_manager).unwrap(); for ub in 0..4 { let coarse_ub = dpw.coarse_ub(ub); debug_assert_eq!(coarse_ub, ub); diff --git a/rustsat/src/encodings/pb/gte.rs b/rustsat/src/encodings/pb/gte.rs index 1ee15404..323ba6de 100644 --- a/rustsat/src/encodings/pb/gte.rs +++ b/rustsat/src/encodings/pb/gte.rs @@ -154,14 +154,19 @@ impl EncodeIncremental for GeneralizedTotalizer { } impl BoundUpper for GeneralizedTotalizer { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); }; let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); @@ -172,10 +177,11 @@ impl BoundUpper for GeneralizedTotalizer { range.start + 1..range.end + self.max_leaf_weight + 1, collector, var_manager, - ), + )?, }; self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; + Ok(()) } fn enforce_ub(&self, ub: usize) -> Result, Error> { @@ -236,13 +242,14 @@ impl BoundUpperIncremental for GeneralizedTotalizer { range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { let range = super::prepare_ub_range(self, range); if range.is_empty() { - return; + return Ok(()); }; let n_vars_before = var_manager.n_used(); let n_clauses_before = collector.n_clauses(); @@ -252,10 +259,11 @@ impl BoundUpperIncremental for GeneralizedTotalizer { range.start + 1..range.end + self.max_leaf_weight, collector, var_manager, - ); + )?; } self.n_clauses += collector.n_clauses() - n_clauses_before; self.n_vars += var_manager.n_used() - n_vars_before; + Ok(()) } } @@ -412,12 +420,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } // Reserve vars if needed @@ -436,19 +445,17 @@ impl Node { let right_lits = right.lit_map(&mut right_tmp_map); // Encode adder for current node // Propagate left value - for (&left_val, &left_lit) in left_lits.range(range.clone()) { - collector.extend([atomics::lit_impl_lit( - left_lit, - *out_lits.get(&left_val).unwrap(), - )]); - } + collector.extend_clauses(left_lits.range(range.clone()).map( + |(left_val, &left_lit)| { + atomics::lit_impl_lit(left_lit, *out_lits.get(left_val).unwrap()) + }, + ))?; // Propagate right value - for (&right_val, &right_lit) in right_lits.range(range.clone()) { - collector.extend([atomics::lit_impl_lit( - right_lit, - *out_lits.get(&right_val).unwrap(), - )]); - } + collector.extend_clauses(right_lits.range(range.clone()).map( + |(right_val, &right_lit)| { + atomics::lit_impl_lit(right_lit, *out_lits.get(right_val).unwrap()) + }, + ))?; // Propagate sum if range.end > 1 { let clause_from_data = @@ -479,10 +486,11 @@ impl Node { clause_from_data(left_val, right_val, left_lit, right_lit) }) }); - collector.extend(clause_iter); + collector.extend_clauses(clause_iter)?; } } - } + }; + Ok(()) } /// Encodes the output literals from the children to this node in a given @@ -493,12 +501,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } // Ignore all previous encoding and encode from scratch @@ -508,16 +517,18 @@ impl Node { let left_range = Node::compute_required_min_enc(range.clone(), right.max_val()); let right_range = Node::compute_required_min_enc(range.clone(), left.max_val()); // Recurse - left.rec_encode(left_range, collector, var_manager); - right.rec_encode(right_range, collector, var_manager); + left.rec_encode(left_range, collector, var_manager)?; + right.rec_encode(right_range, collector, var_manager)?; // Encode current node let n_clauses_before = collector.n_clauses(); - self.encode_range(range.clone(), collector, var_manager); + self.encode_range(range.clone(), collector, var_manager)?; self.update_stats(range, collector.n_clauses() - n_clauses_before); } - } + }; + + Ok(()) } /// Encodes the output literals from the children to this node in a given @@ -527,12 +538,13 @@ impl Node { range: Range, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, { let range = self.limit_range(range); if range.is_empty() { - return; + return Ok(()); } match self { @@ -549,27 +561,28 @@ impl Node { let left_range = Node::compute_required_min_enc(range.clone(), right.max_val()); let right_range = Node::compute_required_min_enc(range.clone(), left.max_val()); // Recurse - left.rec_encode_change(left_range, collector, var_manager); - right.rec_encode_change(right_range, collector, var_manager); + left.rec_encode_change(left_range, collector, var_manager)?; + right.rec_encode_change(right_range, collector, var_manager)?; // Encode changes for current node let n_clauses_before = collector.n_clauses(); if enc_range.is_empty() { // First time encoding this node - self.encode_range(range.clone(), collector, var_manager); + self.encode_range(range.clone(), collector, var_manager)?; } else { // Partially encoded if range.start < enc_range.start { - self.encode_range(range.start..enc_range.start, collector, var_manager); + self.encode_range(range.start..enc_range.start, collector, var_manager)?; }; if range.end > enc_range.end { - self.encode_range(enc_range.end..range.end, collector, var_manager); + self.encode_range(enc_range.end..range.end, collector, var_manager)?; }; }; self.update_stats(range, collector.n_clauses() - n_clauses_before); } - } + }; + Ok(()) } /// Reserves variables this node might need in a given range @@ -715,7 +728,7 @@ mod tests { let mut node = Node::new_internal(child1, child2); let mut var_manager = BasicVarManager::default(); let mut cnf = Cnf::new(); - node.encode_range(0..9, &mut cnf, &mut var_manager); + node.encode_range(0..9, &mut cnf, &mut var_manager).unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 3), @@ -757,7 +770,7 @@ mod tests { let mut node = Node::new_internal(child1, child2); let mut var_manager = BasicVarManager::default(); let mut cnf = Cnf::new(); - node.encode_range(0..7, &mut cnf, &mut var_manager); + node.encode_range(0..7, &mut cnf, &mut var_manager).unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 3), @@ -799,7 +812,7 @@ mod tests { let mut node = Node::new_internal(child1, child2); let mut var_manager = BasicVarManager::default(); let mut cnf = Cnf::new(); - node.encode_range(4..7, &mut cnf, &mut var_manager); + node.encode_range(4..7, &mut cnf, &mut var_manager).unwrap(); match &node { Node::Leaf { .. } => panic!(), Node::Internal { out_lits, .. } => assert_eq!(out_lits.len(), 2), @@ -841,7 +854,7 @@ mod tests { let mut node = Node::new_internal(child1, child2); let mut var_manager = BasicVarManager::default(); let mut cnf = Cnf::new(); - node.encode_range(6..5, &mut cnf, &mut var_manager); + node.encode_range(6..5, &mut cnf, &mut var_manager).unwrap(); assert_eq!(cnf.len(), 0); } @@ -856,7 +869,8 @@ mod tests { gte.extend(lits); assert_eq!(gte.enforce_ub(4), Err(Error::NotEncoded)); let mut var_manager = BasicVarManager::default(); - gte.encode_ub(0..7, &mut Cnf::new(), &mut var_manager); + gte.encode_ub(0..7, &mut Cnf::new(), &mut var_manager) + .unwrap(); assert_eq!(gte.depth(), 3); assert_eq!(gte.n_vars(), 10); } @@ -872,13 +886,14 @@ mod tests { gte1.extend(lits.clone()); let mut var_manager = BasicVarManager::default(); let mut cnf1 = Cnf::new(); - gte1.encode_ub(0..5, &mut cnf1, &mut var_manager); + gte1.encode_ub(0..5, &mut cnf1, &mut var_manager).unwrap(); let mut gte2 = GeneralizedTotalizer::default(); gte2.extend(lits); let mut var_manager = BasicVarManager::default(); let mut cnf2 = Cnf::new(); - gte2.encode_ub(0..3, &mut cnf2, &mut var_manager); - gte2.encode_ub_change(0..5, &mut cnf2, &mut var_manager); + gte2.encode_ub(0..3, &mut cnf2, &mut var_manager).unwrap(); + gte2.encode_ub_change(0..5, &mut cnf2, &mut var_manager) + .unwrap(); assert_eq!(cnf1.len(), cnf2.len()); assert_eq!(cnf1.len(), gte1.n_clauses()); assert_eq!(cnf2.len(), gte2.n_clauses()); @@ -895,7 +910,7 @@ mod tests { gte1.extend(lits); let mut var_manager = BasicVarManager::default(); let mut cnf1 = Cnf::new(); - gte1.encode_ub(0..5, &mut cnf1, &mut var_manager); + gte1.encode_ub(0..5, &mut cnf1, &mut var_manager).unwrap(); let mut gte2 = GeneralizedTotalizer::default(); let mut lits = RsHashMap::default(); lits.insert(lit![0], 10); @@ -905,7 +920,7 @@ mod tests { gte2.extend(lits); let mut var_manager = BasicVarManager::default(); let mut cnf2 = Cnf::new(); - gte2.encode_ub(0..9, &mut cnf2, &mut var_manager); + gte2.encode_ub(0..9, &mut cnf2, &mut var_manager).unwrap(); assert_eq!(cnf1.len(), cnf2.len()); assert_eq!(cnf1.len(), gte1.n_clauses()); assert_eq!(cnf2.len(), gte2.n_clauses()); @@ -928,7 +943,8 @@ mod tests { lits.insert(lit![6], 1); gte.extend(lits); let mut gte_cnf = Cnf::new(); - gte.encode_ub(3..8, &mut gte_cnf, &mut var_manager_gte); + gte.encode_ub(3..8, &mut gte_cnf, &mut var_manager_gte) + .unwrap(); // Set up Tot let mut tot = card::Totalizer::default(); tot.extend(vec![ @@ -941,7 +957,7 @@ mod tests { lit![6], ]); let mut tot_cnf = Cnf::new(); - card::BoundUpper::encode_ub(&mut tot, 3..8, &mut tot_cnf, &mut var_manager_tot); + card::BoundUpper::encode_ub(&mut tot, 3..8, &mut tot_cnf, &mut var_manager_tot).unwrap(); println!("{:?}", gte_cnf); println!("{:?}", tot_cnf); assert_eq!(var_manager_gte.new_var(), var_manager_tot.new_var()); diff --git a/rustsat/src/encodings/pb/simulators.rs b/rustsat/src/encodings/pb/simulators.rs index 022d9578..20528062 100644 --- a/rustsat/src/encodings/pb/simulators.rs +++ b/rustsat/src/encodings/pb/simulators.rs @@ -132,7 +132,12 @@ impl BoundUpper for Inverted where PBE: BoundLower, { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -158,7 +163,12 @@ impl BoundLower for Inverted where PBE: BoundUpper, { - fn encode_lb(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_lb( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -189,7 +199,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -210,7 +221,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -347,7 +359,12 @@ where UBE: BoundUpper, LBE: BoundLower, { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -365,7 +382,12 @@ where UBE: BoundUpper, LBE: BoundLower, { - fn encode_lb(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_lb( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -388,7 +410,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -406,7 +429,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -529,7 +553,12 @@ impl BoundUpper for Card where CE: card::BoundUpper, { - fn encode_ub(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_ub( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -546,7 +575,12 @@ impl BoundLower for Card where CE: card::BoundLower, { - fn encode_lb(&mut self, range: R, collector: &mut Col, var_manager: &mut dyn ManageVars) + fn encode_lb( + &mut self, + range: R, + collector: &mut Col, + var_manager: &mut dyn ManageVars, + ) -> Result<(), crate::OutOfMemory> where Col: CollectClauses, R: RangeBounds, @@ -568,7 +602,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { @@ -586,7 +621,8 @@ where range: R, collector: &mut Col, var_manager: &mut dyn ManageVars, - ) where + ) -> Result<(), crate::OutOfMemory> + where Col: CollectClauses, R: RangeBounds, { diff --git a/rustsat/src/instances/multiopt.rs b/rustsat/src/instances/multiopt.rs index ce0e56dd..ff95748e 100644 --- a/rustsat/src/instances/multiopt.rs +++ b/rustsat/src/instances/multiopt.rs @@ -149,6 +149,10 @@ impl MultiOptInstance { } /// Converts the instance to a set of hard and soft clauses + /// + /// # Panic + /// + /// This might panic if the conversion to [`Cnf`] runs out of memory. pub fn into_hard_cls_soft_cls(self) -> (Cnf, Vec<(impl WClsIter, isize)>, VM) { let (cnf, mut vm) = self.constrs.into_cnf(); let omv = self.objs.iter().fold(Var::new(0), |v, o| { @@ -172,6 +176,10 @@ impl MultiOptInstance { } /// Converts the instance to a set of hard clauses and soft literals + /// + /// # Panic + /// + /// This might panic if the conversion to [`Cnf`] runs out of memory. pub fn into_hard_cls_soft_lits(self) -> (Cnf, Vec<(impl WLitIter, isize)>, VM) { let (mut cnf, mut vm) = self.constrs.into_cnf(); let omv = self.objs.iter().fold(Var::new(0), |v, o| { @@ -245,8 +253,14 @@ impl MultiOptInstance { pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { #[allow(deprecated)] self.to_dimacs_with_encoders( - card::default_encode_cardinality_constraint, - pb::default_encode_pb_constraint, + |constr, cnf, vm| { + card::default_encode_cardinality_constraint(constr, cnf, vm) + .expect("cardinality encoding ran out of memory") + }, + |constr, cnf, vm| { + pb::default_encode_pb_constraint(constr, cnf, vm) + .expect("pb encoding ran out of memory") + }, writer, ) } diff --git a/rustsat/src/instances/opt.rs b/rustsat/src/instances/opt.rs index 86c439d3..9c6854aa 100644 --- a/rustsat/src/instances/opt.rs +++ b/rustsat/src/instances/opt.rs @@ -1102,6 +1102,10 @@ impl OptInstance { /// Converts the instance to a set of hard and soft clauses, an objective /// offset and a variable manager + /// + /// # Panic + /// + /// This might panic if the conversion to [`Cnf`] runs out of memory. pub fn into_hard_cls_soft_cls(self) -> (Cnf, (impl WClsIter, isize), VM) { let (cnf, mut vm) = self.constrs.into_cnf(); if let Some(mv) = self.obj.max_var() { @@ -1112,6 +1116,10 @@ impl OptInstance { /// Converts the instance to a set of hard clauses and soft literals, an /// objective offset and a variable manager + /// + /// # Panic + /// + /// This might panic if the conversion to [`Cnf`] runs out of memory. pub fn into_hard_cls_soft_lits(self) -> (Cnf, (impl WLitIter, isize), VM) { let (mut cnf, mut vm) = self.constrs.into_cnf(); if let Some(mv) = self.obj.max_var() { @@ -1170,8 +1178,14 @@ impl OptInstance { pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { #[allow(deprecated)] self.to_dimacs_with_encoders( - card::default_encode_cardinality_constraint, - pb::default_encode_pb_constraint, + |constr, cnf, vm| { + card::default_encode_cardinality_constraint(constr, cnf, vm) + .expect("cardinality encoding ran out of memory") + }, + |constr, cnf, vm| { + pb::default_encode_pb_constraint(constr, cnf, vm) + .expect("pb encoding ran out of memory") + }, writer, ) } diff --git a/rustsat/src/instances/sat.rs b/rustsat/src/instances/sat.rs index b765983e..e2d9ac31 100644 --- a/rustsat/src/instances/sat.rs +++ b/rustsat/src/instances/sat.rs @@ -1,6 +1,6 @@ //! # Satsifiability Instance Representations -use std::{collections::TryReserveError, io, ops::Index, path::Path}; +use std::{cmp, collections::TryReserveError, io, ops::Index, path::Path}; use crate::{ clause, @@ -10,6 +10,7 @@ use crate::{ constraints::{CardConstraint, PBConstraint}, Assignment, Clause, Lit, Var, }, + utils::LimitedIter, RequiresClausal, }; @@ -217,6 +218,28 @@ impl CollectClauses for Cnf { fn n_clauses(&self) -> usize { self.clauses.len() } + + fn extend_clauses(&mut self, cl_iter: T) -> Result<(), crate::OutOfMemory> + where + T: IntoIterator, + { + let cl_iter = cl_iter.into_iter(); + if let Some(ub) = cl_iter.size_hint().1 { + self.try_reserve(ub)?; + self.extend(cl_iter); + } else { + // Extend by reserving in exponential chunks + let mut cl_iter = cl_iter.peekable(); + while cl_iter.peek().is_some() { + let additional = (self.len() + cmp::max(cl_iter.size_hint().0, 1)) + .next_power_of_two() + - self.len(); + self.try_reserve(additional)?; + self.extend(LimitedIter::new(&mut cl_iter, additional)); + } + } + Ok(()) + } } impl IntoIterator for Cnf { @@ -505,10 +528,20 @@ impl SatInstance { /// Uses the default encoders from the `encodings` module. /// /// See [`Self::convert_to_cnf`] for converting in place + /// + /// # Panic + /// + /// This might panic if the conversion to [`Cnf`] runs out of memory. pub fn into_cnf(self) -> (Cnf, VM) { self.into_cnf_with_encoders( - card::default_encode_cardinality_constraint, - pb::default_encode_pb_constraint, + |constr, cnf, vm| { + card::default_encode_cardinality_constraint(constr, cnf, vm) + .expect("cardinality encoding ran out of memory") + }, + |constr, cnf, vm| { + pb::default_encode_pb_constraint(constr, cnf, vm) + .expect("pb encoding ran out of memory") + }, ) } @@ -516,10 +549,20 @@ impl SatInstance { /// Uses the default encoders from the `encodings` module. /// /// See [`Self::into_cnf`] if you don't need to convert in place + /// + /// # Panic + /// + /// This might panic if the conversion to [`Cnf`] runs out of memory. pub fn convert_to_cnf(&mut self) { self.convert_to_cnf_with_encoders( - card::default_encode_cardinality_constraint, - pb::default_encode_pb_constraint, + |constr, cnf, vm| { + card::default_encode_cardinality_constraint(constr, cnf, vm) + .expect("cardinality encoding ran out of memory") + }, + |constr, cnf, vm| { + pb::default_encode_pb_constraint(constr, cnf, vm) + .expect("pb encoding ran out of memory") + }, ) } @@ -545,6 +588,10 @@ impl SatInstance { /// converters for non-clausal constraints. /// /// See [`Self::into_cnf_with_encoders`] to convert in place + /// + /// # Panic + /// + /// The encoder functions might panic if the conversion runs out of memory. pub fn into_cnf_with_encoders( mut self, card_encoder: CardEnc, @@ -562,6 +609,10 @@ impl SatInstance { /// converters for non-clausal constraints. /// /// See [`Self::into_cnf_with_encoders`] if you don't need to convert in place + /// + /// # Panic + /// + /// The encoder functions might panic if the conversion runs out of memory. pub fn convert_to_cnf_with_encoders( &mut self, mut card_encoder: CardEnc, @@ -632,8 +683,14 @@ impl SatInstance { pub fn to_dimacs(self, writer: &mut W) -> Result<(), io::Error> { #[allow(deprecated)] self.to_dimacs_with_encoders( - card::default_encode_cardinality_constraint, - pb::default_encode_pb_constraint, + |constr, cnf, vm| { + card::default_encode_cardinality_constraint(constr, cnf, vm) + .expect("cardinality encoding ran out of memory") + }, + |constr, cnf, vm| { + pb::default_encode_pb_constraint(constr, cnf, vm) + .expect("pb encoding ran out of memory") + }, writer, ) } @@ -944,3 +1001,16 @@ impl From for SatInstance { inst } } + +impl CollectClauses for SatInstance { + fn n_clauses(&self) -> usize { + self.n_clauses() + } + + fn extend_clauses(&mut self, cl_iter: T) -> Result<(), crate::OutOfMemory> + where + T: IntoIterator, + { + self.cnf.extend_clauses(cl_iter) + } +} diff --git a/rustsat/src/lib.rs b/rustsat/src/lib.rs index 8c8cae08..e212494c 100644 --- a/rustsat/src/lib.rs +++ b/rustsat/src/lib.rs @@ -67,6 +67,7 @@ #![warn(missing_docs)] use core::fmt; +use std::collections::TryReserveError; use thiserror::Error; @@ -93,11 +94,29 @@ impl fmt::Display for NotAllowed { #[cfg(test)] mod bench; -/// Error returned if an operation requires clausal constraints, but this is not the case -#[derive(Error, Debug)] -#[error("operation ran out of memory")] -pub struct OutOfMemory; +/// Error returned when an operation ran out of memory +/// +/// The library is not _fully_ memory safe, meaning there are cases where memory allocation failing +/// can lead to a panic instead to an error. Mainly add clauses to solvers and collecting clauses +/// from encodings are done in a safe way. This is intended, e.g., for anytime solvers that might +/// want a change to print a final output if they run out of memory. +#[derive(Error, Debug, PartialEq, Eq)] +pub enum OutOfMemory { + /// A `try_reserve` operation in Rust ran out of memory + #[error("try reserve error: {0}")] + TryReserve(TryReserveError), + /// An external API (typically a solver) ran out of memory + #[error("external API operation ran out of memory")] + ExternalApi, +} +impl From for OutOfMemory { + fn from(value: TryReserveError) -> Self { + OutOfMemory::TryReserve(value) + } +} + +/// Error returned if an operation requires clausal constraints, but this is not the case #[derive(Error, Debug)] #[error("operation requires a clausal constraint(s) but it is not")] pub struct RequiresClausal; diff --git a/rustsat/src/solvers.rs b/rustsat/src/solvers.rs index 7707a4da..c0aefc2c 100644 --- a/rustsat/src/solvers.rs +++ b/rustsat/src/solvers.rs @@ -469,8 +469,34 @@ impl fmt::Display for StateError { } } +macro_rules! pass_oom_or_panic { + ($result:expr) => {{ + match $result { + Ok(res) => res, + Err(err) => match err.downcast::() { + Ok(oom) => return Err(oom), + Err(err) => panic!("unexpected error in clause collector: {err}"), + }, + } + }}; +} + impl CollectClauses for S { fn n_clauses(&self) -> usize { self.n_clauses() } + + fn extend_clauses(&mut self, cl_iter: T) -> Result<(), crate::OutOfMemory> + where + T: IntoIterator, + { + for cl in cl_iter { + pass_oom_or_panic!(self.add_clause(cl)); + } + Ok(()) + } + + fn add_clause(&mut self, cl: Clause) -> Result<(), crate::OutOfMemory> { + Ok(pass_oom_or_panic!(self.add_clause(cl))) + } } diff --git a/rustsat/src/utils.rs b/rustsat/src/utils.rs index f2732e54..d0875651 100644 --- a/rustsat/src/utils.rs +++ b/rustsat/src/utils.rs @@ -32,6 +32,36 @@ pub(crate) fn digits(mut number: usize, mut basis: u8) -> u32 { digits } +/// A wrapper around an iterator to only yield a limited number of elements and then stop +/// +/// As opposed to [`std::iter::Take`] this does not take ownership of the original iterator +pub struct LimitedIter<'iter, I> { + iter: &'iter mut I, + remaining: usize, +} + +impl<'iter, I> LimitedIter<'iter, I> { + /// Creates a new iterator that yields at most `remaining` elements + pub fn new(iter: &'iter mut I, remaining: usize) -> Self { + Self { iter, remaining } + } +} + +impl Iterator for LimitedIter<'_, I> +where + I: Iterator, +{ + type Item = ::Item; + + fn next(&mut self) -> Option { + if self.remaining == 0 { + return None; + } + self.remaining -= 1; + self.iter.next() + } +} + #[cfg(test)] mod tests { #[test] diff --git a/rustsat/tests/card_encodings.rs b/rustsat/tests/card_encodings.rs index 1b5e3af3..ba31a267 100644 --- a/rustsat/tests/card_encodings.rs +++ b/rustsat/tests/card_encodings.rs @@ -39,7 +39,8 @@ fn test_inc_both_card + Default>() { let mut enc = CE::default(); enc.extend(vec![lit![0], lit![1], lit![2], lit![3], lit![4]]); - enc.encode_both(2..3, &mut solver, &mut var_manager); + enc.encode_both(2..3, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_lb(2).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); @@ -48,31 +49,36 @@ fn test_inc_both_card + Default>() { let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_both_change(0..4, &mut solver, &mut var_manager); + enc.encode_both_change(0..4, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(3).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); enc.extend(vec![lit![5]]); - enc.encode_both_change(0..4, &mut solver, &mut var_manager); + enc.encode_both_change(0..4, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(3).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_both_change(0..5, &mut solver, &mut var_manager); + enc.encode_both_change(0..5, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(4).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); enc.extend(vec![lit![6], lit![7], lit![8], lit![9], lit![10]]); - enc.encode_both_change(0..5, &mut solver, &mut var_manager); + enc.encode_both_change(0..5, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(4).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_both_change(0..8, &mut solver, &mut var_manager); + enc.encode_both_change(0..8, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(7).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); @@ -103,36 +109,41 @@ fn test_inc_ub_card + Default>() { let mut enc = CE::default(); enc.extend(vec![lit![0], lit![1], lit![2], lit![3], lit![4]]); - enc.encode_ub(2..3, &mut solver, &mut var_manager); + enc.encode_ub(2..3, &mut solver, &mut var_manager).unwrap(); let assumps = enc.enforce_ub(2).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_ub_change(0..4, &mut solver, &mut var_manager); + enc.encode_ub_change(0..4, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(3).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); enc.extend(vec![lit![5]]); - enc.encode_ub_change(0..4, &mut solver, &mut var_manager); + enc.encode_ub_change(0..4, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(3).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_ub_change(0..5, &mut solver, &mut var_manager); + enc.encode_ub_change(0..5, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(4).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); enc.extend(vec![lit![6], lit![7], lit![8], lit![9], lit![10]]); - enc.encode_ub_change(0..5, &mut solver, &mut var_manager); + enc.encode_ub_change(0..5, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(4).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_ub_change(0..8, &mut solver, &mut var_manager); + enc.encode_ub_change(0..8, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(7).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); @@ -156,7 +167,8 @@ fn test_both_card>>() { // Set up totalizer let mut enc = CE::from(vec![!lit![0], !lit![1], !lit![2], !lit![3], !lit![4]]); - enc.encode_both(2..4, &mut solver, &mut var_manager); + enc.encode_both(2..4, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(2).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); @@ -179,7 +191,8 @@ fn test_both_card_min_enc>>() { let mut enc = CE::from(vec![lit![0], lit![1], lit![2], lit![3]]); - enc.encode_both(3..4, &mut solver, &mut var_manager); + enc.encode_both(3..4, &mut solver, &mut var_manager) + .unwrap(); let mut assumps = enc.enforce_eq(3).unwrap(); assumps.extend(vec![lit![0], lit![1], lit![2], !lit![3]]); let res = solver.solve_assumps(&assumps).unwrap(); @@ -274,7 +287,7 @@ fn test_ub_exhaustive>>() { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); - enc.encode_ub(0..1, &mut solver, &mut var_manager); + enc.encode_ub(0..1, &mut solver, &mut var_manager).unwrap(); let assumps = enc.enforce_ub(0).unwrap(); test_all!( @@ -297,7 +310,8 @@ fn test_ub_exhaustive>>() { Sat // 0000 ); - enc.encode_ub_change(1..2, &mut solver, &mut var_manager); + enc.encode_ub_change(1..2, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(1).unwrap(); test_all!( @@ -320,7 +334,8 @@ fn test_ub_exhaustive>>() { Sat // 0000 ); - enc.encode_ub_change(2..3, &mut solver, &mut var_manager); + enc.encode_ub_change(2..3, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(2).unwrap(); test_all!( @@ -343,7 +358,8 @@ fn test_ub_exhaustive>>() { Sat // 0000 ); - enc.encode_ub_change(3..4, &mut solver, &mut var_manager); + enc.encode_ub_change(3..4, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(3).unwrap(); test_all!( @@ -366,7 +382,8 @@ fn test_ub_exhaustive>>() { Sat // 0000 ); - enc.encode_ub_change(4..5, &mut solver, &mut var_manager); + enc.encode_ub_change(4..5, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(4).unwrap(); test_all!( @@ -396,7 +413,8 @@ fn test_both_exhaustive>>() { let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); - enc.encode_both(0..1, &mut solver, &mut var_manager); + enc.encode_both(0..1, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_eq(0).unwrap(); test_all!( @@ -419,7 +437,8 @@ fn test_both_exhaustive>>() { Sat // 0000 ); - enc.encode_both_change(1..2, &mut solver, &mut var_manager); + enc.encode_both_change(1..2, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_eq(1).unwrap(); test_all!( @@ -442,7 +461,8 @@ fn test_both_exhaustive>>() { Unsat // 0000 ); - enc.encode_both_change(2..3, &mut solver, &mut var_manager); + enc.encode_both_change(2..3, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_eq(2).unwrap(); test_all!( @@ -465,7 +485,8 @@ fn test_both_exhaustive>>() { Unsat // 0000 ); - enc.encode_both_change(3..4, &mut solver, &mut var_manager); + enc.encode_both_change(3..4, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_eq(3).unwrap(); test_all!( @@ -488,7 +509,8 @@ fn test_both_exhaustive>>() { Unsat // 0000 ); - enc.encode_both_change(4..5, &mut solver, &mut var_manager); + enc.encode_both_change(4..5, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_eq(4).unwrap(); test_all!( diff --git a/rustsat/tests/pb_encodings.rs b/rustsat/tests/pb_encodings.rs index 45dc8b80..176611bf 100644 --- a/rustsat/tests/pb_encodings.rs +++ b/rustsat/tests/pb_encodings.rs @@ -49,17 +49,19 @@ fn test_inc_pb_ub + Default>() let mut enc = PBE::default(); enc.extend(lits); - enc.encode_ub(0..3, &mut solver, &mut var_manager); + enc.encode_ub(0..3, &mut solver, &mut var_manager).unwrap(); let assumps = enc.enforce_ub(2).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_ub_change(0..5, &mut solver, &mut var_manager); + enc.encode_ub_change(0..5, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(4).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_ub_change(0..6, &mut solver, &mut var_manager); + enc.encode_ub_change(0..6, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(5).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); @@ -68,12 +70,14 @@ fn test_inc_pb_ub + Default>() lits.insert(lit![5], 4); enc.extend(lits); - enc.encode_ub_change(0..6, &mut solver, &mut var_manager); + enc.encode_ub_change(0..6, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(5).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_ub_change(0..10, &mut solver, &mut var_manager); + enc.encode_ub_change(0..10, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(9).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); @@ -86,12 +90,14 @@ fn test_inc_pb_ub + Default>() lits.insert(lit![10], 2); enc.extend(lits); - enc.encode_ub_change(0..10, &mut solver, &mut var_manager); + enc.encode_ub_change(0..10, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(9).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); - enc.encode_ub_change(0..15, &mut solver, &mut var_manager); + enc.encode_ub_change(0..15, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(14).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Sat); @@ -109,7 +115,8 @@ fn test_pb_eq>>() { lits.insert(lit![2], 2); let mut enc = PBE::from(lits); - enc.encode_both(4..5, &mut solver, &mut var_manager); + enc.encode_both(4..5, &mut solver, &mut var_manager) + .unwrap(); let mut assumps = enc.enforce_eq(4).unwrap(); assumps.extend(vec![lit![0], lit![1], lit![2]]); @@ -170,7 +177,7 @@ fn test_pb_lb>>() { lits.insert(lit![2], 3); let mut enc = PBE::from(lits); - enc.encode_lb(0..11, &mut solver, &mut var_manager); + enc.encode_lb(0..11, &mut solver, &mut var_manager).unwrap(); let assumps = enc.enforce_lb(10).unwrap(); let res = solver.solve_assumps(&assumps).unwrap(); assert_eq!(res, SolverResult::Unsat); @@ -193,7 +200,7 @@ fn test_pb_ub_min_enc>>() { lits.insert(lit![2], 1); let mut enc = PBE::from(lits); - enc.encode_ub(2..3, &mut solver, &mut var_manager); + enc.encode_ub(2..3, &mut solver, &mut var_manager).unwrap(); let mut assumps = enc.enforce_ub(2).unwrap(); assumps.extend(vec![lit![0], lit![1], lit![2]]); let res = solver.solve_assumps(&assumps).unwrap(); @@ -291,7 +298,7 @@ fn test_ub_exhaustive>>( let mut var_manager = BasicVarManager::default(); var_manager.increase_next_free(var![4]); - let max_val = weights.iter().fold(0, |sum, &w| sum + w); + let max_val = weights.iter().sum::(); let expected = |assign: usize, bound: usize| { let sum = (0..4).fold(0, |sum, idx| sum + ((assign >> idx) & 1) * weights[3 - idx]); if sum <= bound { @@ -306,7 +313,8 @@ fn test_ub_exhaustive>>( bound = max_val - bound; } - enc.encode_ub_change(bound..bound + 1, &mut solver, &mut var_manager); + enc.encode_ub_change(bound..bound + 1, &mut solver, &mut var_manager) + .unwrap(); let assumps = enc.enforce_ub(bound).unwrap(); test_all!( From 65bbeb9cdab35162c6fd4714f079ef761ff401ec Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 25 Apr 2024 21:08:17 +0300 Subject: [PATCH 33/56] docs: add memory error section to migration guide --- docs/0-5-0-migration-guide.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/0-5-0-migration-guide.md b/docs/0-5-0-migration-guide.md index c7203dab..89f49e3b 100644 --- a/docs/0-5-0-migration-guide.md +++ b/docs/0-5-0-migration-guide.md @@ -45,3 +45,20 @@ There have been some API changes to improve usability, even though they are brea - Methods providing references to internal data are now named `_ref` and `_mut` if mutability is allowed. If only a non-mutable accessor is present, the `_ref` suffix is omitted (e.g., for `SatInstance::cnf`). + +## Handling Out-Of-Memory + +This release also includes a push towards catching the most common cases where +this library could run out of memory. The two main cases of this are adding +clauses to solvers and generating CNF encodings. For the first, C++ error +exceptions are now caught in the C-API wrapper and a Rust error +(`rustsat::OutOfMemory::ExternalApi`) is returned. The other case is if a +clause collector used when generating an encoding runs out of memory. For this +reason, the `CollectClauses` trait now does not use Rust's standard `Extend` +crate any more, but has the functions `extend_clauses` and `add_clause`. +`CollectClauses` is mainly implemented by `Cnf` and solver (and newly by +`SatInstance`). In the Rust types, `try_reserve` is now used and +`rustsat::OutOfMemory::TryReserve` will be returned if memory allocation fails. +For most use cases, there are at most some more errors that you can treat with +`unwrap` or `expect` to get the same behaviour as previously. This just enables +more sophisticated memory error handling now. From fdc23c99a0cc9d656c8ea91a595cbe08322692eb Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 25 Apr 2024 21:20:46 +0300 Subject: [PATCH 34/56] build: fix external api version checks --- .github/workflows/capi.yml | 2 ++ .github/workflows/pyapi.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/capi.yml b/.github/workflows/capi.yml index 95062a70..a68ca0c8 100644 --- a/.github/workflows/capi.yml +++ b/.github/workflows/capi.yml @@ -37,6 +37,8 @@ jobs: name: Ensure C-API crate version is in sync runs-on: ubuntu-latest steps: + - name: Checkout sources + uses: actions/checkout@v4 - name: Check run: "[ \"$(grep '^version = ' rustsat/Cargo.toml)\" = \"$(grep '^version = ' capi/Cargo.toml)\" ]" diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index 3bacde19..2af819a5 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -54,6 +54,8 @@ jobs: name: Ensure Python API crate version is in sync runs-on: ubuntu-latest steps: + - name: Checkout sources + uses: actions/checkout@v4 - name: Check run: "[ \"$(grep '^version = ' rustsat/Cargo.toml)\" = \"$(grep '^version = ' pyapi/Cargo.toml)\" ]" From f4ca1efc82c4dce51d19ddc42c074e70c967d0b3 Mon Sep 17 00:00:00 2001 From: atimaly Date: Thu, 11 Apr 2024 12:45:05 +0200 Subject: [PATCH 35/56] feat: parse solver output allow parsing of output of externally run SAT solvers closes #86 SAT solver output parser SAT solver output parser Error handling Adding constructor and reorganizing code Adding tests and small correction Adding tests for empty solution and error Adding tests for types and correction for parsing Adding InvalidVline error and cleaning up logic docs: Add simple documentation File reading tests and other additions --- data/cadical-AProVW11-12.txt | 4021 ++++++++++++++++ ...qfbv-aigs-ext_con_032_008_0256-tseitin.txt | 169 + data/gimsatul-AProVE11-12.txt | 4090 +++++++++++++++++ ...qfbv-aigs-ext_con_032_008_0256-tseitin.txt | 122 + data/kissat-AProVE11-12.txt | 4047 ++++++++++++++++ ...qfbv-aigs-exp_con_032_008_0256-tseitin.txt | 147 + rustsat/src/instances/fio.rs | 185 +- rustsat/src/types.rs | 229 +- 8 files changed, 13008 insertions(+), 2 deletions(-) create mode 100644 data/cadical-AProVW11-12.txt create mode 100644 data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt create mode 100644 data/gimsatul-AProVE11-12.txt create mode 100644 data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt create mode 100644 data/kissat-AProVE11-12.txt create mode 100644 data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt diff --git a/data/cadical-AProVW11-12.txt b/data/cadical-AProVW11-12.txt new file mode 100644 index 00000000..22068db9 --- /dev/null +++ b/data/cadical-AProVW11-12.txt @@ -0,0 +1,4021 @@ +c --- [ banner ] ------------------------------------------------------------- +c +c CaDiCaL SAT Solver +c Copyright (c) 2016-2024 A. Biere, M. Fleury, N. Froleyks, K. Fazekas, F. Pollitt +c +c Version 2.0.0 2df7b7fed0f9c522fd4cdf6e88cecad4cac8a2df +c g++ (GCC) 13.2.1 20230801 -Wall -Wextra -O3 -DNDEBUG +c Wed Apr 24 16:34:54 EEST 2024 Linux Christoph-laptop 6.8.2-arch2-1 x86_64 +c +c --- [ parsing input ] ------------------------------------------------------ +c +c reading DIMACS file from '../sat-rs/rustsat/data/AProVE11-12.cnf' +c opening file to read '../sat-rs/rustsat/data/AProVE11-12.cnf' +c found 'p cnf 44805 149118' header +c parsed 149118 clauses in 0.07 seconds process time +c +c --- [ options ] ------------------------------------------------------------ +c +c all options are set to their default value +c +c --- [ solving ] ------------------------------------------------------------ +c +c time measured in process time since initialization +c +c seconds reductions redundant irredundant +c MB restarts trail variables +c level conflicts glue remaining +c +c * 0.07 27 0 0 0 0 0 0% 0 147360 44195 99% +c { 0.08 29 0 0 0 0 0 0% 0 147360 44195 99% +c i 0.09 29 8 0 0 20 18 4% 2 147360 41239 92% +c i 0.10 29 48 0 17 237 206 27% 2 147360 41228 92% +c i 0.11 29 57 0 17 261 227 29% 2 147360 41227 92% +c - 0.13 28 65 1 22 300 260 31% 2 131824 41227 92% +c i 0.14 29 72 1 25 324 283 32% 2 131824 41126 92% +c i 0.16 29 115 1 29 472 421 45% 2 131824 41060 92% +c i 0.16 29 116 1 29 476 424 45% 2 131824 41017 92% +c i 0.17 29 126 1 29 509 456 48% 2 131824 41015 92% +c i 0.17 29 128 1 29 516 462 48% 2 131824 41013 92% +c i 0.17 29 134 1 29 540 485 51% 2 131824 41011 92% +c i 0.17 29 136 1 29 547 491 51% 2 131824 41009 92% +c } 0.17 29 155 1 29 617 556 56% 2 131824 41009 92% +c 1 0.17 29 155 1 29 617 556 56% 2 131824 41009 92% +c +c --- [ result ] ------------------------------------------------------------- +c +s SATISFIABLE +v -1 2 -3 4 -5 6 -7 8 -9 10 -11 12 -13 14 -15 16 -17 18 -19 20 -21 22 -23 24 +v -25 26 -27 28 -29 30 -31 32 -33 34 -35 36 -37 38 -39 40 -41 42 -43 44 -45 46 +v -47 48 -49 50 -51 52 -53 54 -55 56 -57 58 -59 60 -61 62 -63 64 -65 66 -67 68 +v -69 70 -71 72 73 -74 -75 76 -77 78 79 80 81 82 -83 -84 85 -86 87 88 89 90 91 +v -92 -93 94 -95 96 97 98 99 100 -101 -102 103 -104 105 106 107 108 109 -110 +v -111 112 -113 114 115 116 117 118 -119 -120 121 -122 123 124 125 126 127 +v -128 -129 130 -131 132 133 134 135 136 -137 -138 139 -140 141 142 143 144 +v -145 146 -147 148 -149 150 151 -152 153 -154 155 -156 157 -158 159 160 -161 +v 162 163 -164 -165 166 -167 168 169 170 171 172 -173 -174 175 -176 177 178 +v 179 180 181 -182 -183 184 -185 186 187 188 189 190 -191 -192 193 -194 195 +v 196 197 198 199 -200 -201 202 -203 204 205 206 207 208 -209 -210 211 -212 +v 213 214 215 216 217 -218 -219 220 -221 222 223 224 225 226 -227 -228 229 +v -230 231 232 233 234 235 -236 -237 238 -239 240 241 242 243 244 -245 -246 +v 247 -248 249 250 251 252 253 -254 -255 256 -257 258 259 260 261 262 -263 +v -264 265 -266 267 268 269 270 271 -272 -273 274 -275 276 277 278 279 280 +v -281 -282 283 -284 285 286 287 288 289 -290 -291 292 -293 294 295 296 297 +v 298 -299 -300 301 -302 303 304 305 306 -307 308 -309 310 -311 312 313 -314 +v 315 -316 317 -318 319 -320 321 322 -323 324 325 -326 -327 328 -329 330 331 +v 332 333 334 -335 -336 337 -338 339 340 341 342 343 -344 -345 346 -347 348 +v 349 350 351 352 -353 -354 355 -356 357 358 359 360 361 -362 -363 364 -365 +v 366 367 368 369 370 -371 -372 373 -374 375 376 377 378 379 -380 -381 382 +v -383 384 385 386 387 388 -389 -390 391 -392 393 394 395 396 397 -398 -399 +v 400 -401 402 403 404 405 406 -407 -408 409 -410 411 412 413 414 415 -416 +v -417 418 -419 420 421 422 423 424 -425 -426 427 -428 429 430 431 432 433 +v -434 -435 436 -437 438 439 440 441 -442 443 -444 445 -446 447 448 -449 450 +v -451 452 -453 454 -455 456 457 -458 459 -460 461 -462 463 -464 465 466 -467 +v 468 469 -470 -471 472 -473 474 475 476 477 478 -479 -480 481 -482 483 484 +v 485 486 487 -488 -489 490 -491 492 493 494 495 496 -497 -498 499 -500 501 +v 502 503 504 505 -506 -507 508 -509 510 511 512 513 -514 515 -516 517 -518 +v 519 520 -521 522 523 -524 -525 526 -527 528 529 530 531 532 -533 -534 535 +v -536 537 538 539 540 541 -542 -543 544 -545 546 547 548 549 550 -551 -552 +v 553 -554 555 556 557 558 559 -560 -561 562 -563 564 565 566 567 -568 569 +v -570 571 -572 573 574 -575 576 -577 578 -579 580 -581 582 583 -584 585 -586 +v 587 -588 589 -590 591 592 -593 594 595 -596 -597 598 -599 600 601 602 603 +v 604 -605 -606 607 -608 609 610 611 612 613 -614 -615 616 -617 618 619 620 +v 621 622 -623 -624 625 -626 627 628 629 630 631 -632 -633 634 -635 636 637 +v 638 639 -640 641 -642 643 -644 645 646 -647 648 649 -650 -651 652 -653 654 +v 655 656 657 658 -659 -660 661 -662 663 664 665 666 667 -668 -669 670 -671 +v 672 673 674 675 676 -677 -678 679 -680 681 682 683 684 685 -686 -687 688 +v -689 690 691 692 693 694 -695 -696 697 -698 699 700 701 702 703 -704 -705 +v 706 -707 708 709 710 711 712 -713 -714 715 -716 717 718 719 720 -721 722 +v -723 724 -725 726 727 -728 729 -730 731 -732 733 -734 735 736 -737 738 739 +v -740 -741 742 -743 744 745 746 747 748 -749 -750 751 -752 753 754 755 756 +v 757 -758 -759 760 -761 762 763 764 765 766 -767 -768 769 -770 771 772 773 +v 774 775 -776 -777 778 -779 780 781 782 783 784 -785 -786 787 -788 789 790 +v 791 792 793 -794 -795 796 -797 798 799 800 801 802 -803 -804 805 -806 807 +v 808 809 810 811 -812 -813 814 -815 816 817 818 819 820 -821 -822 823 -824 +v 825 826 827 828 829 -830 -831 832 -833 834 835 836 837 838 -839 -840 841 +v -842 843 844 845 846 847 -848 -849 850 -851 852 853 854 855 856 -857 -858 +v 859 -860 861 862 863 864 865 -866 -867 868 -869 870 871 872 873 874 -875 +v -876 877 -878 879 880 881 882 -883 884 -885 886 -887 888 889 -890 891 -892 +v 893 -894 895 -896 897 898 -899 900 901 -902 -903 904 -905 906 907 908 909 +v 910 -911 -912 913 -914 915 916 917 918 919 -920 -921 922 -923 924 925 926 +v 927 928 -929 -930 931 -932 933 934 935 936 937 -938 -939 940 -941 942 943 +v 944 945 946 -947 -948 949 -950 951 952 953 954 955 -956 -957 958 -959 960 +v 961 962 963 964 -965 -966 967 -968 969 970 971 972 973 -974 -975 976 -977 +v 978 979 980 981 982 -983 -984 985 -986 987 988 989 990 991 -992 -993 994 +v -995 996 997 998 999 1000 -1001 -1002 1003 -1004 1005 1006 1007 1008 1009 +v -1010 -1011 1012 -1013 1014 1015 1016 1017 1018 -1019 -1020 1021 -1022 1023 +v 1024 1025 1026 1027 -1028 -1029 1030 -1031 1032 1033 1034 1035 1036 -1037 +v -1038 1039 -1040 1041 1042 1043 1044 -1045 1046 -1047 1048 -1049 1050 1051 +v -1052 1053 -1054 1055 -1056 1057 -1058 1059 1060 -1061 1062 1063 -1064 -1065 +v 1066 -1067 1068 1069 1070 1071 1072 -1073 -1074 1075 -1076 1077 1078 1079 +v 1080 1081 -1082 -1083 1084 -1085 1086 1087 1088 1089 1090 -1091 -1092 1093 +v -1094 1095 1096 1097 1098 1099 -1100 -1101 1102 -1103 1104 1105 1106 1107 +v 1108 -1109 -1110 1111 -1112 1113 1114 1115 1116 1117 -1118 -1119 1120 -1121 +v 1122 1123 1124 1125 1126 -1127 -1128 1129 -1130 1131 1132 1133 1134 1135 +v -1136 -1137 1138 -1139 1140 1141 1142 1143 1144 -1145 -1146 1147 -1148 1149 +v 1150 1151 1152 1153 -1154 -1155 1156 -1157 1158 1159 1160 1161 1162 -1163 +v -1164 1165 -1166 1167 1168 1169 1170 1171 -1172 -1173 1174 -1175 1176 1177 +v 1178 1179 1180 -1181 -1182 1183 -1184 1185 1186 1187 1188 1189 -1190 -1191 +v 1192 -1193 1194 1195 1196 1197 1198 -1199 -1200 1201 -1202 1203 1204 1205 +v 1206 -1207 1208 -1209 1210 -1211 1212 1213 -1214 1215 -1216 1217 -1218 1219 +v -1220 1221 1222 -1223 1224 1225 -1226 -1227 1228 -1229 1230 1231 1232 1233 +v 1234 -1235 -1236 1237 -1238 1239 1240 1241 1242 1243 -1244 -1245 1246 -1247 +v 1248 1249 1250 1251 1252 -1253 -1254 1255 -1256 1257 1258 1259 1260 1261 +v -1262 -1263 1264 -1265 1266 1267 1268 1269 1270 -1271 -1272 1273 -1274 1275 +v 1276 1277 1278 1279 -1280 -1281 1282 -1283 1284 1285 1286 1287 1288 -1289 +v -1290 1291 -1292 1293 1294 1295 1296 1297 -1298 -1299 -1300 -1301 -1302 +v -1303 -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 -1313 -1314 +v -1315 -1316 1317 -1318 -1319 -1320 -1321 1322 -1323 -1324 -1325 1326 -1327 +v -1328 -1329 1330 -1331 -1332 -1333 1334 -1335 -1336 -1337 1338 -1339 -1340 +v -1341 1342 -1343 -1344 -1345 1346 -1347 -1348 -1349 1350 -1351 -1352 -1353 +v 1354 -1355 -1356 -1357 1358 -1359 -1360 -1361 1362 -1363 -1364 -1365 1366 +v -1367 -1368 1369 1370 1371 1372 -1373 -1374 -1375 1376 1377 -1378 -1379 1380 +v -1381 1382 -1383 1384 -1385 1386 -1387 1388 -1389 1390 -1391 1392 -1393 +v -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 -1404 -1405 +v -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 -1416 -1417 +v -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 -1428 -1429 +v -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 -1440 -1441 +v -1442 -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 -1452 -1453 +v -1454 -1455 -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 -1464 -1465 +v -1466 -1467 -1468 -1469 -1470 -1471 -1472 -1473 -1474 -1475 -1476 -1477 +v -1478 -1479 -1480 -1481 -1482 -1483 -1484 -1485 -1486 -1487 -1488 -1489 1490 +v 1491 1492 -1493 -1494 -1495 1496 -1497 -1498 -1499 1500 -1501 -1502 -1503 +v 1504 -1505 -1506 -1507 1508 -1509 -1510 -1511 1512 -1513 -1514 -1515 1516 +v -1517 -1518 -1519 1520 -1521 -1522 -1523 1524 -1525 -1526 -1527 -1528 -1529 +v -1530 -1531 -1532 -1533 -1534 -1535 -1536 -1537 -1538 -1539 -1540 -1541 +v -1542 -1543 -1544 1545 1546 1547 -1548 -1549 -1550 -1551 -1552 1553 1554 +v -1555 -1556 -1557 -1558 -1559 -1560 -1561 -1562 -1563 -1564 -1565 -1566 +v -1567 -1568 -1569 -1570 -1571 1572 1573 1574 1575 1576 1577 -1578 -1579 +v -1580 -1581 -1582 -1583 -1584 -1585 -1586 -1587 -1588 -1589 1590 1591 -1592 +v -1593 -1594 -1595 1596 -1597 -1598 -1599 -1600 -1601 -1602 -1603 -1604 -1605 +v -1606 1607 1608 1609 -1610 -1611 1612 -1613 -1614 -1615 -1616 -1617 -1618 +v -1619 -1620 -1621 -1622 -1623 1624 -1625 -1626 1627 -1628 1629 -1630 -1631 +v -1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 -1641 -1642 -1643 +v -1644 -1645 -1646 -1647 1648 1649 -1650 -1651 -1652 -1653 -1654 -1655 -1656 +v -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 -1665 -1666 -1667 -1668 +v -1669 -1670 -1671 -1672 -1673 -1674 -1675 -1676 -1677 -1678 -1679 -1680 +v -1681 -1682 -1683 -1684 1685 1686 -1687 -1688 -1689 -1690 -1691 -1692 -1693 +v 1694 1695 -1696 -1697 -1698 -1699 1700 -1701 -1702 -1703 -1704 -1705 -1706 +v 1707 -1708 1709 -1710 -1711 1712 -1713 1714 -1715 -1716 -1717 1718 -1719 +v 1720 1721 1722 1723 1724 -1725 -1726 1727 -1728 -1729 1730 -1731 -1732 -1733 +v -1734 -1735 -1736 -1737 -1738 -1739 -1740 1741 1742 1743 -1744 1745 -1746 +v 1747 1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 -1757 -1758 -1759 +v -1760 -1761 -1762 -1763 -1764 -1765 -1766 -1767 -1768 1769 1770 1771 1772 +v 1773 1774 -1775 -1776 -1777 -1778 -1779 -1780 -1781 -1782 -1783 -1784 -1785 +v -1786 1787 1788 -1789 -1790 -1791 -1792 1793 -1794 -1795 -1796 -1797 -1798 +v -1799 -1800 -1801 -1802 -1803 1804 1805 1806 -1807 -1808 1809 -1810 -1811 +v -1812 -1813 -1814 -1815 -1816 -1817 -1818 -1819 -1820 1821 -1822 -1823 1824 +v -1825 1826 -1827 -1828 -1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 +v -1838 -1839 -1840 -1841 -1842 -1843 -1844 1845 1846 -1847 -1848 -1849 -1850 +v -1851 -1852 -1853 -1854 -1855 -1856 -1857 -1858 -1859 -1860 -1861 -1862 +v -1863 -1864 -1865 -1866 -1867 -1868 -1869 -1870 -1871 -1872 -1873 -1874 +v -1875 -1876 -1877 -1878 -1879 -1880 -1881 1882 1883 -1884 -1885 -1886 -1887 +v -1888 -1889 -1890 1891 1892 -1893 -1894 -1895 -1896 1897 -1898 -1899 -1900 +v -1901 -1902 -1903 1904 -1905 1906 -1907 -1908 1909 -1910 1911 -1912 -1913 +v -1914 1915 -1916 1917 1918 1919 1920 1921 -1922 -1923 1924 -1925 -1926 1927 +v -1928 -1929 -1930 -1931 -1932 -1933 -1934 -1935 -1936 -1937 1938 1939 1940 +v -1941 1942 -1943 1944 1945 -1946 1947 -1948 1949 1950 -1951 -1952 1953 -1954 +v -1955 -1956 -1957 -1958 -1959 -1960 -1961 -1962 -1963 -1964 -1965 -1966 +v -1967 1968 1969 -1970 -1971 1972 -1973 -1974 1975 -1976 1977 -1978 -1979 +v -1980 -1981 -1982 -1983 -1984 -1985 -1986 -1987 -1988 -1989 1990 1991 1992 +v -1993 1994 -1995 -1996 1997 -1998 -1999 -2000 -2001 -2002 2003 -2004 -2005 +v -2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 -2020 +v -2021 2022 -2023 -2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 -2034 +v -2035 -2036 2037 2038 -2039 -2040 -2041 2042 -2043 -2044 -2045 -2046 2047 +v -2048 -2049 2050 -2051 -2052 2053 -2054 2055 -2056 -2057 2058 -2059 2060 +v -2061 -2062 2063 -2064 2065 2066 2067 -2068 -2069 2070 2071 -2072 -2073 +v -2074 -2075 2076 -2077 -2078 2079 -2080 -2081 -2082 -2083 -2084 2085 -2086 +v -2087 -2088 -2089 -2090 -2091 -2092 -2093 2094 2095 2096 2097 2098 2099 +v -2100 -2101 -2102 2103 2104 2105 2106 2107 -2108 -2109 -2110 -2111 -2112 +v -2113 -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 +v -2125 -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 2136 -2137 +v -2138 2139 -2140 -2141 -2142 -2143 2144 -2145 -2146 -2147 -2148 -2149 2150 +v -2151 -2152 -2153 -2154 -2155 -2156 -2157 -2158 2159 2160 -2161 -2162 -2163 +v -2164 -2165 2166 2167 -2168 -2169 -2170 -2171 -2172 2173 -2174 -2175 -2176 +v 2177 2178 -2179 -2180 2181 2182 -2183 -2184 -2185 2186 2187 -2188 -2189 +v -2190 2191 -2192 2193 2194 -2195 -2196 -2197 2198 -2199 -2200 -2201 -2202 +v -2203 -2204 -2205 -2206 -2207 -2208 -2209 -2210 -2211 2212 2213 2214 -2215 +v -2216 -2217 2218 2219 2220 2221 2222 -2223 -2224 -2225 -2226 -2227 -2228 +v -2229 -2230 -2231 -2232 -2233 -2234 2235 2236 -2237 -2238 -2239 -2240 2241 +v -2242 -2243 -2244 -2245 -2246 -2247 -2248 -2249 -2250 -2251 -2252 -2253 +v -2254 -2255 -2256 -2257 -2258 -2259 -2260 -2261 -2262 -2263 -2264 2265 2266 +v -2267 -2268 -2269 -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 +v -2279 -2280 -2281 -2282 -2283 -2284 -2285 -2286 -2287 -2288 -2289 -2290 +v -2291 -2292 -2293 -2294 -2295 -2296 -2297 -2298 -2299 -2300 -2301 2302 2303 +v -2304 -2305 -2306 -2307 -2308 -2309 2310 2311 -2312 -2313 -2314 2315 -2316 +v -2317 -2318 -2319 -2320 -2321 2322 2323 -2324 -2325 -2326 -2327 -2328 -2329 +v 2330 -2331 2332 -2333 -2334 2335 -2336 2337 -2338 -2339 -2340 2341 -2342 +v 2343 2344 2345 2346 -2347 -2348 2349 -2350 -2351 2352 -2353 -2354 -2355 +v -2356 -2357 -2358 -2359 -2360 -2361 2362 2363 2364 -2365 -2366 -2367 -2368 +v -2369 -2370 -2371 -2372 -2373 -2374 -2375 -2376 -2377 -2378 -2379 -2380 +v -2381 -2382 -2383 -2384 -2385 -2386 -2387 -2388 -2389 -2390 -2391 -2392 +v -2393 2394 -2395 2396 -2397 -2398 2399 -2400 2401 2402 2403 -2404 -2405 +v -2406 -2407 -2408 -2409 -2410 2411 2412 2413 2414 -2415 2416 -2417 -2418 +v -2419 2420 2421 2422 2423 2424 -2425 -2426 2427 -2428 2429 -2430 2431 -2432 +v 2433 -2434 -2435 2436 -2437 -2438 -2439 -2440 2441 -2442 -2443 2444 -2445 +v -2446 -2447 -2448 2449 2450 2451 -2452 -2453 -2454 -2455 -2456 -2457 2458 +v 2459 -2460 2461 -2462 -2463 2464 -2465 -2466 -2467 -2468 -2469 2470 2471 +v 2472 2473 -2474 2475 -2476 -2477 -2478 -2479 -2480 -2481 -2482 -2483 2484 +v -2485 -2486 2487 -2488 -2489 2490 -2491 2492 -2493 -2494 -2495 -2496 -2497 +v -2498 2499 -2500 -2501 2502 -2503 -2504 -2505 -2506 2507 -2508 2509 -2510 +v -2511 -2512 2513 -2514 2515 2516 2517 2518 2519 -2520 -2521 2522 2523 2524 +v -2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 -2533 2534 2535 2536 -2537 +v 2538 -2539 2540 2541 -2542 -2543 -2544 -2545 -2546 -2547 -2548 -2549 -2550 +v -2551 -2552 -2553 -2554 -2555 -2556 -2557 -2558 -2559 -2560 -2561 -2562 +v -2563 -2564 -2565 -2566 -2567 -2568 -2569 -2570 -2571 -2572 -2573 -2574 +v -2575 -2576 -2577 -2578 -2579 -2580 -2581 -2582 -2583 -2584 -2585 2586 2587 +v -2588 -2589 -2590 -2591 -2592 -2593 -2594 2595 2596 -2597 -2598 -2599 -2600 +v 2601 -2602 -2603 -2604 -2605 -2606 -2607 -2608 -2609 2610 2611 2612 -2613 +v -2614 2615 -2616 -2617 -2618 -2619 -2620 -2621 -2622 -2623 -2624 -2625 -2626 +v 2627 -2628 -2629 2630 -2631 2632 -2633 -2634 -2635 -2636 -2637 -2638 -2639 +v -2640 -2641 -2642 -2643 -2644 -2645 -2646 -2647 -2648 -2649 2650 2651 2652 +v 2653 -2654 -2655 -2656 -2657 -2658 -2659 -2660 -2661 -2662 -2663 -2664 -2665 +v 2666 2667 -2668 -2669 -2670 -2671 2672 -2673 -2674 -2675 -2676 -2677 -2678 +v -2679 2680 -2681 2682 -2683 -2684 2685 -2686 2687 -2688 -2689 -2690 -2691 +v 2692 -2693 2694 2695 2696 2697 2698 -2699 -2700 2701 -2702 -2703 2704 -2705 +v -2706 -2707 -2708 -2709 -2710 -2711 -2712 -2713 -2714 2715 2716 2717 -2718 +v 2719 -2720 2721 2722 -2723 -2724 -2725 -2726 -2727 -2728 -2729 -2730 -2731 +v -2732 -2733 -2734 -2735 -2736 -2737 -2738 -2739 -2740 -2741 -2742 -2743 +v -2744 -2745 -2746 -2747 -2748 -2749 -2750 -2751 -2752 -2753 -2754 -2755 +v -2756 -2757 -2758 -2759 -2760 -2761 -2762 -2763 -2764 -2765 -2766 2767 2768 +v -2769 -2770 -2771 -2772 -2773 -2774 -2775 2776 2777 -2778 -2779 -2780 -2781 +v 2782 -2783 -2784 -2785 -2786 -2787 -2788 -2789 -2790 2791 2792 2793 -2794 +v -2795 2796 -2797 -2798 -2799 -2800 -2801 -2802 -2803 -2804 -2805 -2806 -2807 +v 2808 -2809 -2810 2811 -2812 2813 -2814 -2815 -2816 -2817 -2818 -2819 -2820 +v -2821 -2822 -2823 -2824 -2825 -2826 -2827 -2828 -2829 -2830 2831 2832 2833 +v 2834 -2835 -2836 -2837 -2838 -2839 -2840 -2841 -2842 -2843 -2844 -2845 -2846 +v 2847 2848 -2849 -2850 -2851 -2852 2853 -2854 -2855 -2856 -2857 -2858 -2859 +v -2860 2861 -2862 2863 -2864 -2865 2866 -2867 2868 -2869 -2870 -2871 -2872 +v 2873 -2874 2875 2876 2877 2878 2879 -2880 -2881 2882 -2883 -2884 2885 -2886 +v -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 2896 2897 2898 -2899 +v 2900 -2901 2902 2903 -2904 2905 -2906 2907 -2908 -2909 -2910 -2911 -2912 +v -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 -2923 -2924 +v -2925 -2926 2927 2928 2929 2930 -2931 -2932 -2933 -2934 -2935 -2936 -2937 +v -2938 -2939 -2940 -2941 -2942 2943 2944 -2945 -2946 -2947 -2948 2949 -2950 +v -2951 -2952 -2953 -2954 -2955 -2956 -2957 -2958 -2959 2960 2961 2962 -2963 +v -2964 2965 -2966 -2967 -2968 -2969 -2970 -2971 -2972 -2973 -2974 -2975 -2976 +v -2977 -2978 -2979 -2980 -2981 -2982 -2983 -2984 2985 2986 2987 -2988 -2989 +v -2990 2991 -2992 -2993 -2994 -2995 -2996 -2997 -2998 -2999 -3000 -3001 3002 +v -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 3011 -3012 -3013 -3014 -3015 +v -3016 -3017 3018 -3019 3020 -3021 -3022 -3023 -3024 -3025 -3026 -3027 -3028 +v -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 -3039 -3040 +v -3041 -3042 -3043 -3044 -3045 -3046 -3047 -3048 -3049 -3050 -3051 -3052 +v -3053 -3054 -3055 -3056 -3057 -3058 -3059 -3060 -3061 -3062 -3063 3064 3065 +v -3066 -3067 -3068 -3069 -3070 -3071 -3072 3073 3074 -3075 -3076 -3077 -3078 +v 3079 -3080 -3081 -3082 -3083 -3084 -3085 3086 -3087 3088 -3089 -3090 3091 +v -3092 3093 -3094 -3095 -3096 3097 -3098 3099 3100 3101 3102 3103 -3104 -3105 +v 3106 -3107 -3108 3109 -3110 -3111 -3112 -3113 -3114 -3115 -3116 -3117 -3118 +v -3119 3120 3121 3122 -3123 3124 -3125 3126 3127 -3128 -3129 -3130 -3131 +v -3132 3133 -3134 -3135 -3136 -3137 3138 3139 3140 -3141 -3142 -3143 -3144 +v -3145 -3146 -3147 -3148 -3149 -3150 -3151 -3152 -3153 -3154 -3155 -3156 +v -3157 -3158 -3159 3160 3161 3162 3163 -3164 -3165 -3166 -3167 -3168 -3169 +v -3170 -3171 -3172 -3173 -3174 -3175 3176 3177 -3178 -3179 -3180 -3181 3182 +v -3183 -3184 -3185 -3186 -3187 -3188 -3189 -3190 -3191 -3192 3193 3194 3195 +v -3196 -3197 3198 -3199 -3200 -3201 -3202 -3203 -3204 -3205 -3206 -3207 -3208 +v -3209 -3210 -3211 -3212 -3213 -3214 -3215 -3216 -3217 3218 3219 3220 -3221 +v -3222 -3223 3224 -3225 -3226 -3227 -3228 -3229 -3230 -3231 -3232 -3233 -3234 +v 3235 -3236 -3237 -3238 -3239 -3240 -3241 -3242 -3243 3244 -3245 -3246 -3247 +v -3248 -3249 -3250 3251 -3252 3253 -3254 -3255 -3256 -3257 -3258 -3259 -3260 +v -3261 -3262 -3263 -3264 -3265 -3266 -3267 -3268 -3269 -3270 -3271 -3272 +v -3273 -3274 -3275 -3276 -3277 -3278 -3279 -3280 -3281 -3282 -3283 -3284 +v -3285 -3286 -3287 -3288 -3289 -3290 -3291 -3292 -3293 -3294 -3295 -3296 3297 +v 3298 -3299 -3300 -3301 -3302 -3303 -3304 -3305 3306 3307 -3308 -3309 -3310 +v -3311 3312 -3313 -3314 -3315 -3316 -3317 -3318 3319 -3320 3321 -3322 -3323 +v 3324 -3325 3326 -3327 -3328 -3329 3330 -3331 3332 3333 3334 3335 3336 -3337 +v -3338 3339 -3340 -3341 3342 -3343 -3344 -3345 -3346 -3347 -3348 -3349 -3350 +v -3351 -3352 3353 3354 3355 -3356 3357 -3358 3359 3360 -3361 -3362 -3363 +v -3364 -3365 3366 -3367 -3368 -3369 -3370 3371 3372 3373 -3374 3375 -3376 +v 3377 3378 -3379 3380 -3381 -3382 -3383 -3384 -3385 -3386 -3387 -3388 -3389 +v -3390 -3391 -3392 -3393 -3394 -3395 -3396 3397 3398 -3399 3400 -3401 -3402 +v -3403 -3404 -3405 -3406 -3407 -3408 -3409 -3410 -3411 -3412 3413 3414 3415 +v -3416 3417 -3418 -3419 3420 -3421 -3422 -3423 -3424 -3425 3426 -3427 -3428 +v -3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 -3443 +v -3444 3445 -3446 -3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 -3457 +v -3458 -3459 3460 3461 -3462 -3463 -3464 3465 -3466 -3467 -3468 -3469 3470 +v -3471 -3472 3473 -3474 -3475 3476 -3477 3478 -3479 -3480 3481 -3482 3483 +v -3484 -3485 3486 -3487 3488 -3489 -3490 -3491 -3492 -3493 -3494 3495 -3496 +v -3497 3498 -3499 -3500 -3501 -3502 -3503 -3504 3505 3506 3507 3508 -3509 +v 3510 3511 3512 3513 3514 -3515 -3516 -3517 -3518 -3519 -3520 -3521 -3522 +v -3523 -3524 -3525 -3526 -3527 -3528 -3529 -3530 -3531 -3532 -3533 -3534 +v -3535 -3536 -3537 -3538 -3539 -3540 -3541 -3542 3543 -3544 -3545 3546 -3547 +v -3548 -3549 -3550 3551 -3552 -3553 -3554 -3555 -3556 3557 -3558 -3559 -3560 +v -3561 -3562 -3563 -3564 -3565 3566 3567 -3568 -3569 -3570 -3571 -3572 3573 +v 3574 -3575 -3576 -3577 -3578 -3579 3580 -3581 -3582 -3583 3584 3585 -3586 +v -3587 3588 3589 -3590 -3591 -3592 3593 3594 -3595 -3596 -3597 3598 -3599 +v 3600 3601 -3602 -3603 -3604 3605 -3606 -3607 -3608 -3609 -3610 -3611 -3612 +v -3613 -3614 -3615 -3616 -3617 -3618 3619 3620 3621 -3622 -3623 -3624 -3625 +v -3626 -3627 -3628 -3629 -3630 -3631 -3632 -3633 -3634 -3635 -3636 -3637 +v -3638 -3639 -3640 -3641 -3642 -3643 -3644 -3645 -3646 -3647 -3648 -3649 +v -3650 -3651 -3652 -3653 -3654 -3655 -3656 -3657 -3658 -3659 -3660 -3661 +v -3662 -3663 -3664 3665 3666 -3667 -3668 -3669 -3670 -3671 -3672 3673 3674 +v -3675 -3676 -3677 3678 -3679 -3680 -3681 -3682 -3683 -3684 3685 3686 -3687 +v -3688 -3689 -3690 -3691 -3692 -3693 3694 3695 3696 -3697 -3698 -3699 -3700 +v -3701 -3702 -3703 -3704 -3705 -3706 -3707 -3708 3709 3710 -3711 -3712 -3713 +v -3714 3715 -3716 -3717 -3718 -3719 -3720 3721 -3722 3723 -3724 -3725 3726 +v -3727 3728 -3729 -3730 -3731 3732 -3733 3734 3735 3736 3737 -3738 -3739 3740 +v -3741 -3742 3743 -3744 -3745 -3746 -3747 -3748 -3749 -3750 -3751 -3752 3753 +v 3754 3755 -3756 -3757 -3758 -3759 -3760 -3761 -3762 -3763 -3764 -3765 -3766 +v -3767 -3768 -3769 -3770 -3771 -3772 -3773 -3774 -3775 -3776 -3777 -3778 +v -3779 -3780 3781 -3782 3783 -3784 -3785 3786 -3787 3788 3789 3790 -3791 +v -3792 -3793 -3794 -3795 -3796 -3797 3798 3799 3800 3801 -3802 3803 -3804 +v -3805 -3806 3807 3808 3809 3810 3811 -3812 -3813 3814 -3815 3816 -3817 3818 +v -3819 -3820 -3821 -3822 -3823 -3824 -3825 -3826 3827 -3828 -3829 3830 -3831 +v -3832 -3833 -3834 3835 3836 3837 -3838 -3839 -3840 -3841 -3842 -3843 3844 +v 3845 -3846 3847 -3848 -3849 3850 -3851 -3852 -3853 -3854 -3855 3856 3857 +v 3858 3859 -3860 3861 -3862 -3863 -3864 -3865 -3866 -3867 -3868 -3869 -3870 +v -3871 -3872 -3873 -3874 3875 3876 3877 3878 -3879 -3880 3881 -3882 -3883 +v -3884 -3885 -3886 -3887 -3888 3889 -3890 -3891 -3892 -3893 -3894 -3895 -3896 +v -3897 3898 -3899 -3900 -3901 -3902 -3903 -3904 -3905 -3906 3907 -3908 -3909 +v -3910 -3911 -3912 -3913 3914 -3915 -3916 -3917 -3918 -3919 -3920 3921 -3922 +v -3923 3924 -3925 -3926 -3927 -3928 3929 -3930 3931 -3932 -3933 -3934 3935 +v -3936 3937 3938 3939 3940 3941 -3942 -3943 3944 3945 3946 -3947 -3948 -3949 +v -3950 -3951 -3952 -3953 -3954 -3955 3956 3957 3958 -3959 3960 -3961 3962 +v 3963 -3964 -3965 -3966 -3967 -3968 3969 -3970 -3971 -3972 -3973 3974 3975 +v 3976 -3977 -3978 -3979 -3980 -3981 -3982 -3983 -3984 -3985 -3986 -3987 -3988 +v -3989 -3990 -3991 -3992 -3993 -3994 -3995 -3996 -3997 -3998 -3999 -4000 +v -4001 -4002 -4003 -4004 -4005 -4006 -4007 -4008 -4009 -4010 -4011 -4012 +v -4013 -4014 -4015 -4016 -4017 -4018 -4019 -4020 -4021 4022 4023 -4024 -4025 +v -4026 -4027 -4028 -4029 -4030 4031 4032 -4033 -4034 -4035 -4036 4037 -4038 +v -4039 -4040 -4041 -4042 -4043 -4044 -4045 4046 4047 4048 -4049 -4050 4051 +v -4052 -4053 -4054 -4055 -4056 -4057 -4058 -4059 -4060 -4061 -4062 -4063 +v -4064 -4065 -4066 -4067 -4068 -4069 -4070 4071 4072 4073 -4074 -4075 -4076 +v 4077 -4078 -4079 -4080 -4081 -4082 -4083 -4084 -4085 -4086 -4087 4088 -4089 +v -4090 -4091 -4092 -4093 -4094 -4095 -4096 4097 -4098 -4099 -4100 -4101 -4102 +v -4103 4104 -4105 4106 -4107 -4108 -4109 -4110 -4111 -4112 -4113 -4114 -4115 +v -4116 -4117 -4118 -4119 -4120 -4121 -4122 -4123 4124 4125 4126 4127 -4128 +v -4129 -4130 -4131 -4132 -4133 -4134 -4135 -4136 -4137 -4138 -4139 4140 4141 +v -4142 -4143 -4144 -4145 4146 -4147 -4148 -4149 -4150 -4151 -4152 -4153 4154 +v -4155 4156 -4157 -4158 4159 -4160 4161 -4162 -4163 -4164 -4165 4166 -4167 +v 4168 4169 4170 4171 4172 -4173 -4174 4175 -4176 -4177 4178 -4179 -4180 -4181 +v -4182 -4183 -4184 -4185 -4186 -4187 -4188 4189 4190 4191 -4192 4193 -4194 +v 4195 4196 -4197 -4198 -4199 -4200 -4201 4202 -4203 -4204 -4205 -4206 4207 +v 4208 4209 -4210 -4211 -4212 -4213 -4214 -4215 -4216 -4217 -4218 -4219 -4220 +v -4221 -4222 -4223 -4224 -4225 -4226 -4227 -4228 -4229 -4230 -4231 -4232 +v -4233 -4234 -4235 -4236 -4237 -4238 -4239 -4240 -4241 -4242 -4243 -4244 +v -4245 -4246 -4247 -4248 -4249 -4250 -4251 -4252 -4253 -4254 4255 4256 -4257 +v -4258 -4259 -4260 -4261 -4262 -4263 4264 4265 -4266 -4267 -4268 -4269 4270 +v -4271 -4272 -4273 -4274 -4275 -4276 -4277 -4278 4279 4280 4281 -4282 -4283 +v 4284 -4285 -4286 -4287 -4288 -4289 -4290 -4291 -4292 -4293 -4294 -4295 -4296 +v -4297 -4298 -4299 -4300 -4301 -4302 -4303 4304 4305 4306 -4307 -4308 -4309 +v 4310 -4311 -4312 -4313 -4314 -4315 -4316 -4317 -4318 -4319 -4320 4321 -4322 +v -4323 -4324 -4325 -4326 -4327 -4328 -4329 4330 -4331 -4332 -4333 -4334 -4335 +v -4336 4337 -4338 4339 -4340 -4341 -4342 -4343 -4344 -4345 -4346 -4347 -4348 +v -4349 -4350 -4351 -4352 -4353 -4354 -4355 -4356 4357 4358 4359 4360 -4361 +v -4362 -4363 -4364 -4365 -4366 -4367 -4368 -4369 -4370 -4371 -4372 4373 4374 +v -4375 -4376 -4377 -4378 4379 -4380 -4381 -4382 -4383 -4384 -4385 -4386 4387 +v -4388 4389 -4390 -4391 4392 -4393 4394 -4395 -4396 -4397 -4398 4399 -4400 +v 4401 4402 4403 4404 4405 -4406 -4407 4408 -4409 -4410 4411 -4412 -4413 -4414 +v -4415 -4416 -4417 -4418 -4419 -4420 -4421 4422 4423 4424 -4425 4426 -4427 +v 4428 4429 -4430 -4431 -4432 -4433 -4434 4435 -4436 -4437 -4438 -4439 4440 +v 4441 4442 -4443 4444 -4445 4446 4447 -4448 -4449 4450 4451 -4452 -4453 -4454 +v -4455 4456 4457 4458 4459 4460 4461 4462 4463 -4464 -4465 4466 4467 -4468 +v -4469 -4470 4471 4472 -4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 +v 4483 4484 4485 -4486 4487 -4488 4489 -4490 -4491 4492 4493 4494 4495 -4496 +v -4497 -4498 4499 -4500 -4501 -4502 4503 4504 4505 4506 -4507 -4508 -4509 +v -4510 4511 -4512 4513 4514 -4515 4516 -4517 -4518 4519 4520 -4521 -4522 +v -4523 -4524 -4525 -4526 -4527 4528 4529 4530 -4531 -4532 -4533 -4534 4535 +v 4536 4537 4538 4539 -4540 -4541 4542 -4543 -4544 4545 -4546 -4547 4548 -4549 +v 4550 -4551 -4552 4553 -4554 -4555 -4556 -4557 -4558 4559 4560 4561 4562 +v -4563 -4564 -4565 -4566 -4567 -4568 -4569 -4570 -4571 -4572 -4573 -4574 +v -4575 -4576 -4577 -4578 -4579 -4580 -4581 -4582 -4583 -4584 -4585 -4586 +v -4587 -4588 -4589 -4590 -4591 -4592 -4593 4594 -4595 4596 -4597 -4598 -4599 +v 4600 -4601 4602 -4603 -4604 4605 -4606 -4607 -4608 -4609 -4610 -4611 4612 +v 4613 4614 4615 -4616 -4617 -4618 -4619 -4620 -4621 -4622 -4623 -4624 -4625 +v -4626 -4627 -4628 -4629 -4630 -4631 -4632 -4633 -4634 -4635 -4636 -4637 +v -4638 -4639 -4640 -4641 -4642 -4643 -4644 -4645 -4646 4647 -4648 4649 -4650 +v -4651 -4652 4653 -4654 4655 -4656 -4657 4658 -4659 -4660 -4661 -4662 -4663 +v -4664 4665 4666 4667 4668 -4669 -4670 -4671 -4672 -4673 -4674 -4675 -4676 +v -4677 -4678 -4679 -4680 -4681 -4682 -4683 -4684 -4685 -4686 -4687 -4688 +v -4689 -4690 -4691 -4692 -4693 -4694 -4695 -4696 -4697 -4698 -4699 4700 -4701 +v 4702 -4703 -4704 -4705 4706 -4707 4708 -4709 -4710 4711 -4712 -4713 -4714 +v -4715 -4716 -4717 4718 4719 4720 4721 -4722 -4723 -4724 -4725 -4726 -4727 +v -4728 -4729 -4730 -4731 -4732 -4733 -4734 -4735 -4736 -4737 -4738 -4739 +v -4740 -4741 -4742 -4743 -4744 -4745 -4746 -4747 -4748 -4749 -4750 -4751 +v -4752 -4753 -4754 -4755 -4756 -4757 -4758 -4759 -4760 -4761 -4762 -4763 +v -4764 -4765 -4766 -4767 -4768 -4769 -4770 -4771 -4772 -4773 -4774 -4775 +v -4776 -4777 -4778 -4779 -4780 -4781 -4782 -4783 -4784 -4785 -4786 -4787 +v -4788 -4789 -4790 -4791 -4792 -4793 -4794 -4795 -4796 -4797 -4798 -4799 +v -4800 -4801 -4802 -4803 -4804 -4805 -4806 -4807 -4808 -4809 -4810 -4811 +v -4812 -4813 -4814 -4815 -4816 -4817 -4818 -4819 -4820 -4821 -4822 -4823 +v -4824 -4825 -4826 -4827 -4828 -4829 -4830 -4831 -4832 -4833 -4834 -4835 +v -4836 -4837 -4838 -4839 -4840 -4841 -4842 -4843 -4844 -4845 -4846 -4847 +v -4848 -4849 -4850 -4851 -4852 -4853 -4854 -4855 -4856 -4857 -4858 -4859 +v -4860 -4861 -4862 -4863 -4864 -4865 -4866 -4867 -4868 -4869 -4870 -4871 +v -4872 -4873 -4874 -4875 -4876 -4877 -4878 -4879 -4880 -4881 -4882 -4883 +v -4884 -4885 -4886 -4887 -4888 -4889 -4890 4891 -4892 4893 -4894 -4895 -4896 +v 4897 -4898 4899 -4900 -4901 -4902 -4903 4904 -4905 4906 -4907 -4908 -4909 +v -4910 4911 -4912 4913 -4914 -4915 4916 -4917 -4918 -4919 -4920 -4921 -4922 +v -4923 -4924 -4925 -4926 4927 4928 4929 4930 -4931 -4932 -4933 -4934 -4935 +v -4936 -4937 -4938 -4939 -4940 -4941 -4942 -4943 -4944 -4945 -4946 -4947 +v -4948 -4949 -4950 -4951 -4952 -4953 -4954 -4955 -4956 -4957 -4958 -4959 +v -4960 -4961 -4962 -4963 -4964 -4965 -4966 -4967 -4968 -4969 -4970 -4971 +v -4972 -4973 -4974 -4975 -4976 -4977 -4978 -4979 -4980 -4981 -4982 -4983 +v -4984 -4985 -4986 -4987 -4988 -4989 -4990 -4991 -4992 -4993 -4994 -4995 +v -4996 -4997 -4998 -4999 -5000 -5001 -5002 -5003 -5004 -5005 -5006 -5007 +v -5008 -5009 -5010 -5011 -5012 -5013 -5014 -5015 -5016 -5017 -5018 -5019 +v -5020 -5021 -5022 -5023 -5024 -5025 -5026 -5027 -5028 -5029 -5030 -5031 +v -5032 -5033 -5034 -5035 -5036 -5037 -5038 -5039 -5040 -5041 -5042 -5043 +v -5044 -5045 -5046 -5047 -5048 -5049 -5050 -5051 -5052 -5053 -5054 -5055 +v -5056 -5057 -5058 -5059 -5060 -5061 -5062 -5063 -5064 -5065 -5066 -5067 +v -5068 -5069 -5070 -5071 -5072 -5073 -5074 -5075 -5076 -5077 -5078 -5079 +v -5080 -5081 -5082 -5083 -5084 -5085 -5086 -5087 -5088 -5089 -5090 -5091 +v -5092 -5093 -5094 -5095 -5096 -5097 5098 -5099 5100 -5101 -5102 -5103 5104 +v -5105 5106 -5107 -5108 -5109 -5110 5111 -5112 5113 -5114 -5115 -5116 -5117 +v 5118 -5119 5120 -5121 -5122 5123 -5124 -5125 -5126 -5127 -5128 -5129 -5130 +v -5131 -5132 -5133 5134 5135 5136 5137 -5138 -5139 -5140 -5141 -5142 -5143 +v -5144 -5145 -5146 -5147 -5148 -5149 -5150 -5151 -5152 -5153 -5154 -5155 +v -5156 -5157 -5158 -5159 -5160 -5161 -5162 -5163 -5164 -5165 -5166 -5167 +v -5168 -5169 -5170 -5171 -5172 -5173 -5174 -5175 -5176 -5177 -5178 -5179 +v -5180 -5181 -5182 -5183 -5184 -5185 -5186 -5187 -5188 -5189 -5190 -5191 +v -5192 -5193 -5194 -5195 -5196 -5197 -5198 -5199 -5200 -5201 -5202 -5203 +v -5204 -5205 -5206 -5207 -5208 -5209 -5210 -5211 -5212 -5213 -5214 -5215 +v -5216 -5217 -5218 -5219 -5220 -5221 -5222 -5223 -5224 -5225 -5226 -5227 +v -5228 -5229 -5230 -5231 -5232 -5233 -5234 -5235 -5236 -5237 -5238 -5239 +v -5240 -5241 -5242 -5243 -5244 -5245 -5246 -5247 -5248 -5249 -5250 -5251 +v -5252 -5253 -5254 -5255 -5256 -5257 -5258 -5259 -5260 -5261 -5262 -5263 +v -5264 -5265 -5266 -5267 -5268 -5269 -5270 -5271 -5272 -5273 -5274 -5275 +v -5276 -5277 -5278 -5279 -5280 -5281 -5282 -5283 -5284 -5285 -5286 -5287 +v -5288 -5289 -5290 -5291 -5292 -5293 -5294 -5295 -5296 -5297 -5298 5299 -5300 +v 5301 -5302 -5303 -5304 5305 -5306 5307 -5308 -5309 -5310 -5311 5312 -5313 +v 5314 -5315 -5316 -5317 -5318 5319 -5320 5321 -5322 -5323 5324 -5325 -5326 +v -5327 -5328 -5329 -5330 -5331 -5332 -5333 -5334 5335 5336 5337 5338 -5339 +v -5340 -5341 -5342 -5343 -5344 -5345 -5346 -5347 -5348 -5349 -5350 -5351 +v -5352 -5353 -5354 -5355 -5356 -5357 -5358 -5359 -5360 -5361 -5362 -5363 +v -5364 -5365 -5366 -5367 -5368 -5369 -5370 -5371 -5372 -5373 -5374 -5375 +v -5376 -5377 -5378 -5379 -5380 -5381 -5382 -5383 -5384 -5385 -5386 -5387 +v -5388 -5389 -5390 -5391 -5392 -5393 -5394 -5395 -5396 -5397 -5398 -5399 +v -5400 -5401 -5402 -5403 -5404 -5405 -5406 -5407 -5408 -5409 -5410 -5411 +v -5412 -5413 -5414 -5415 -5416 -5417 -5418 -5419 -5420 -5421 -5422 -5423 +v -5424 -5425 -5426 -5427 -5428 -5429 -5430 -5431 -5432 -5433 -5434 -5435 +v -5436 -5437 -5438 -5439 -5440 -5441 -5442 -5443 -5444 -5445 -5446 -5447 +v -5448 -5449 -5450 -5451 -5452 -5453 -5454 -5455 -5456 -5457 -5458 -5459 +v -5460 -5461 -5462 -5463 -5464 -5465 -5466 -5467 -5468 -5469 -5470 -5471 +v -5472 -5473 -5474 -5475 -5476 -5477 -5478 -5479 -5480 -5481 -5482 -5483 +v -5484 -5485 -5486 -5487 -5488 -5489 -5490 -5491 -5492 -5493 -5494 -5495 +v -5496 -5497 -5498 -5499 -5500 -5501 -5502 -5503 -5504 -5505 5506 -5507 5508 +v -5509 -5510 -5511 5512 -5513 5514 -5515 -5516 -5517 -5518 5519 -5520 5521 +v -5522 -5523 -5524 -5525 5526 -5527 5528 -5529 -5530 5531 -5532 -5533 -5534 +v -5535 -5536 -5537 -5538 -5539 -5540 -5541 5542 5543 5544 5545 -5546 -5547 +v -5548 -5549 -5550 -5551 -5552 -5553 -5554 -5555 -5556 -5557 -5558 -5559 +v -5560 -5561 -5562 -5563 -5564 -5565 -5566 -5567 -5568 -5569 -5570 -5571 +v -5572 -5573 -5574 -5575 -5576 5577 -5578 5579 -5580 -5581 -5582 5583 -5584 +v 5585 -5586 -5587 5588 -5589 -5590 -5591 -5592 -5593 -5594 5595 5596 5597 +v 5598 -5599 5600 -5601 5602 -5603 5604 5605 5606 5607 -5608 -5609 -5610 -5611 +v -5612 -5613 -5614 -5615 -5616 -5617 -5618 -5619 -5620 -5621 -5622 -5623 +v -5624 -5625 -5626 -5627 -5628 -5629 -5630 -5631 -5632 -5633 -5634 -5635 +v -5636 -5637 -5638 -5639 -5640 -5641 -5642 -5643 -5644 -5645 -5646 -5647 +v -5648 -5649 -5650 -5651 -5652 -5653 5654 -5655 -5656 5657 -5658 -5659 -5660 +v -5661 -5662 -5663 -5664 -5665 -5666 -5667 -5668 -5669 -5670 -5671 -5672 +v -5673 -5674 -5675 -5676 -5677 -5678 -5679 -5680 -5681 -5682 -5683 -5684 +v -5685 -5686 -5687 -5688 -5689 -5690 -5691 -5692 -5693 -5694 -5695 -5696 +v -5697 -5698 -5699 -5700 -5701 -5702 -5703 -5704 -5705 -5706 -5707 -5708 +v -5709 -5710 -5711 -5712 -5713 -5714 -5715 -5716 -5717 -5718 -5719 -5720 +v -5721 -5722 -5723 -5724 -5725 -5726 -5727 -5728 -5729 -5730 -5731 -5732 +v -5733 -5734 -5735 -5736 -5737 -5738 -5739 -5740 -5741 -5742 -5743 -5744 +v -5745 -5746 -5747 -5748 -5749 -5750 -5751 -5752 -5753 -5754 -5755 -5756 +v -5757 -5758 -5759 -5760 -5761 -5762 -5763 -5764 -5765 -5766 -5767 -5768 +v -5769 -5770 -5771 -5772 -5773 -5774 -5775 -5776 -5777 -5778 -5779 -5780 +v -5781 -5782 -5783 -5784 -5785 -5786 -5787 -5788 -5789 -5790 -5791 -5792 +v -5793 -5794 -5795 -5796 -5797 -5798 -5799 -5800 -5801 -5802 -5803 -5804 +v -5805 -5806 -5807 -5808 -5809 -5810 -5811 -5812 -5813 -5814 -5815 -5816 +v -5817 -5818 -5819 -5820 -5821 -5822 -5823 -5824 -5825 -5826 -5827 -5828 +v -5829 -5830 -5831 -5832 -5833 -5834 -5835 -5836 -5837 -5838 -5839 -5840 +v -5841 -5842 -5843 -5844 -5845 -5846 -5847 -5848 -5849 -5850 -5851 -5852 +v -5853 -5854 -5855 -5856 -5857 -5858 -5859 -5860 -5861 -5862 -5863 -5864 +v -5865 -5866 -5867 -5868 -5869 -5870 -5871 -5872 -5873 -5874 -5875 -5876 +v -5877 -5878 -5879 -5880 -5881 -5882 -5883 -5884 -5885 5886 -5887 -5888 -5889 +v -5890 -5891 -5892 -5893 -5894 -5895 -5896 -5897 -5898 -5899 -5900 -5901 +v -5902 -5903 -5904 -5905 -5906 -5907 -5908 -5909 -5910 -5911 -5912 -5913 +v -5914 -5915 -5916 -5917 -5918 -5919 -5920 -5921 -5922 -5923 -5924 -5925 +v -5926 -5927 -5928 -5929 -5930 -5931 -5932 -5933 -5934 -5935 -5936 -5937 +v -5938 -5939 -5940 -5941 -5942 -5943 -5944 -5945 -5946 -5947 -5948 -5949 +v -5950 -5951 -5952 -5953 -5954 -5955 -5956 -5957 -5958 -5959 -5960 -5961 +v -5962 -5963 -5964 -5965 -5966 -5967 -5968 -5969 -5970 -5971 -5972 -5973 +v -5974 -5975 -5976 -5977 -5978 -5979 -5980 -5981 -5982 -5983 -5984 -5985 +v -5986 -5987 -5988 -5989 -5990 -5991 -5992 -5993 -5994 -5995 -5996 -5997 +v -5998 -5999 -6000 -6001 -6002 -6003 -6004 -6005 -6006 -6007 -6008 -6009 +v -6010 -6011 -6012 -6013 -6014 -6015 -6016 -6017 -6018 -6019 -6020 -6021 +v -6022 -6023 -6024 -6025 -6026 -6027 -6028 -6029 -6030 -6031 -6032 -6033 +v -6034 -6035 -6036 -6037 -6038 -6039 -6040 -6041 -6042 -6043 -6044 -6045 +v -6046 -6047 -6048 -6049 -6050 -6051 -6052 6053 -6054 6055 -6056 -6057 6058 +v -6059 6060 -6061 -6062 6063 -6064 6065 -6066 -6067 -6068 6069 -6070 6071 +v -6072 -6073 -6074 6075 -6076 6077 -6078 -6079 -6080 6081 -6082 6083 -6084 +v -6085 6086 -6087 -6088 -6089 -6090 -6091 -6092 -6093 -6094 -6095 -6096 -6097 +v -6098 -6099 -6100 6101 6102 6103 6104 6105 -6106 -6107 -6108 -6109 -6110 +v -6111 6112 -6113 -6114 -6115 6116 -6117 -6118 -6119 -6120 -6121 -6122 -6123 +v -6124 -6125 -6126 -6127 -6128 -6129 -6130 -6131 -6132 -6133 -6134 -6135 +v -6136 -6137 -6138 -6139 -6140 -6141 -6142 -6143 -6144 -6145 -6146 -6147 +v -6148 -6149 -6150 -6151 -6152 -6153 -6154 -6155 -6156 -6157 -6158 -6159 +v -6160 -6161 -6162 -6163 -6164 -6165 -6166 -6167 -6168 -6169 -6170 -6171 +v -6172 -6173 -6174 -6175 -6176 -6177 -6178 -6179 -6180 -6181 -6182 -6183 +v -6184 -6185 -6186 -6187 -6188 -6189 -6190 -6191 -6192 -6193 -6194 -6195 +v -6196 -6197 -6198 -6199 -6200 -6201 -6202 -6203 -6204 -6205 -6206 -6207 +v -6208 -6209 -6210 -6211 -6212 -6213 -6214 -6215 -6216 -6217 -6218 -6219 +v -6220 -6221 -6222 -6223 -6224 -6225 -6226 -6227 -6228 -6229 -6230 -6231 +v -6232 -6233 -6234 -6235 -6236 6237 -6238 6239 -6240 -6241 -6242 6243 -6244 +v 6245 -6246 -6247 -6248 6249 -6250 6251 -6252 -6253 -6254 6255 -6256 6257 +v -6258 -6259 6260 -6261 -6262 -6263 -6264 -6265 -6266 -6267 -6268 -6269 -6270 +v 6271 6272 6273 6274 -6275 -6276 -6277 -6278 -6279 -6280 -6281 -6282 -6283 +v -6284 -6285 -6286 -6287 -6288 -6289 -6290 -6291 -6292 -6293 -6294 -6295 +v -6296 -6297 -6298 -6299 -6300 -6301 -6302 -6303 -6304 -6305 -6306 -6307 +v -6308 -6309 -6310 -6311 -6312 -6313 -6314 -6315 -6316 -6317 -6318 -6319 +v -6320 -6321 -6322 -6323 -6324 -6325 -6326 -6327 6328 -6329 6330 -6331 -6332 +v 6333 -6334 6335 -6336 -6337 -6338 6339 -6340 6341 -6342 -6343 -6344 6345 +v -6346 6347 -6348 -6349 6350 -6351 -6352 -6353 -6354 -6355 -6356 -6357 -6358 +v -6359 -6360 6361 6362 6363 6364 -6365 -6366 -6367 -6368 -6369 -6370 -6371 +v -6372 -6373 -6374 -6375 -6376 -6377 -6378 -6379 -6380 -6381 -6382 -6383 +v -6384 -6385 -6386 -6387 -6388 -6389 -6390 -6391 -6392 -6393 -6394 -6395 +v -6396 -6397 -6398 -6399 -6400 -6401 -6402 -6403 -6404 -6405 -6406 -6407 +v -6408 -6409 -6410 -6411 -6412 -6413 -6414 -6415 -6416 -6417 -6418 -6419 +v -6420 -6421 -6422 -6423 -6424 -6425 -6426 -6427 -6428 -6429 -6430 -6431 +v -6432 -6433 -6434 -6435 -6436 -6437 -6438 -6439 -6440 -6441 -6442 -6443 +v -6444 -6445 -6446 -6447 -6448 -6449 -6450 -6451 -6452 -6453 -6454 -6455 +v -6456 -6457 -6458 -6459 -6460 -6461 -6462 -6463 -6464 -6465 -6466 -6467 +v -6468 -6469 -6470 -6471 -6472 -6473 -6474 -6475 -6476 -6477 -6478 -6479 +v -6480 -6481 -6482 -6483 -6484 -6485 -6486 -6487 -6488 -6489 -6490 6491 -6492 +v -6493 -6494 -6495 -6496 -6497 -6498 -6499 -6500 -6501 -6502 -6503 -6504 +v -6505 -6506 -6507 -6508 -6509 -6510 -6511 -6512 -6513 -6514 -6515 -6516 +v -6517 -6518 -6519 -6520 -6521 -6522 -6523 -6524 -6525 -6526 -6527 -6528 +v -6529 -6530 -6531 -6532 -6533 6534 -6535 6536 -6537 -6538 -6539 6540 -6541 +v 6542 -6543 -6544 -6545 6546 -6547 6548 -6549 -6550 -6551 6552 -6553 6554 +v -6555 -6556 6557 -6558 -6559 -6560 -6561 -6562 -6563 -6564 -6565 -6566 -6567 +v 6568 6569 6570 -6571 -6572 -6573 -6574 -6575 -6576 -6577 -6578 -6579 -6580 +v -6581 -6582 -6583 6584 -6585 -6586 6587 -6588 -6589 -6590 -6591 -6592 -6593 +v 6594 6595 6596 6597 -6598 6599 -6600 -6601 -6602 -6603 -6604 -6605 -6606 +v -6607 -6608 -6609 -6610 -6611 -6612 6613 -6614 -6615 6616 -6617 -6618 -6619 +v -6620 -6621 6622 6623 6624 -6625 -6626 -6627 -6628 -6629 -6630 -6631 -6632 +v -6633 6634 6635 -6636 6637 -6638 -6639 6640 -6641 -6642 -6643 -6644 -6645 +v -6646 6647 -6648 -6649 -6650 -6651 -6652 -6653 -6654 -6655 -6656 -6657 -6658 +v -6659 -6660 -6661 6662 -6663 -6664 6665 -6666 -6667 -6668 -6669 -6670 6671 +v -6672 6673 -6674 -6675 -6676 6677 -6678 6679 6680 6681 6682 6683 -6684 -6685 +v 6686 6687 6688 -6689 -6690 -6691 -6692 -6693 -6694 -6695 -6696 -6697 6698 +v 6699 6700 -6701 -6702 -6703 -6704 -6705 -6706 -6707 -6708 -6709 -6710 -6711 +v -6712 -6713 -6714 -6715 -6716 -6717 -6718 -6719 -6720 -6721 -6722 6723 -6724 +v -6725 -6726 -6727 -6728 -6729 -6730 6731 -6732 6733 -6734 -6735 -6736 6737 +v -6738 6739 -6740 -6741 6742 -6743 -6744 -6745 -6746 -6747 -6748 6749 6750 +v 6751 -6752 -6753 -6754 -6755 -6756 -6757 -6758 -6759 -6760 -6761 -6762 -6763 +v -6764 -6765 -6766 -6767 -6768 -6769 -6770 -6771 -6772 -6773 6774 -6775 -6776 +v -6777 -6778 -6779 -6780 -6781 6782 -6783 6784 -6785 -6786 -6787 6788 -6789 +v 6790 -6791 -6792 6793 -6794 -6795 -6796 -6797 -6798 -6799 6800 6801 6802 +v -6803 -6804 -6805 -6806 -6807 -6808 -6809 -6810 -6811 -6812 -6813 -6814 +v -6815 -6816 -6817 -6818 -6819 -6820 -6821 -6822 -6823 -6824 6825 -6826 -6827 +v -6828 -6829 -6830 -6831 -6832 6833 -6834 6835 -6836 -6837 -6838 6839 -6840 +v 6841 -6842 -6843 6844 -6845 -6846 -6847 -6848 -6849 -6850 6851 6852 6853 +v -6854 -6855 -6856 -6857 -6858 -6859 -6860 -6861 -6862 -6863 -6864 -6865 +v -6866 -6867 -6868 -6869 -6870 -6871 -6872 -6873 -6874 -6875 -6876 -6877 +v -6878 -6879 -6880 -6881 -6882 -6883 -6884 -6885 -6886 -6887 -6888 -6889 +v -6890 -6891 -6892 -6893 -6894 -6895 -6896 -6897 -6898 -6899 -6900 -6901 +v -6902 -6903 -6904 -6905 -6906 -6907 -6908 -6909 -6910 -6911 -6912 -6913 +v -6914 -6915 -6916 -6917 -6918 -6919 -6920 -6921 -6922 -6923 -6924 -6925 +v -6926 -6927 -6928 -6929 -6930 -6931 -6932 -6933 -6934 -6935 -6936 -6937 +v -6938 -6939 -6940 -6941 -6942 -6943 -6944 -6945 -6946 6947 -6948 -6949 -6950 +v -6951 -6952 -6953 -6954 -6955 -6956 -6957 -6958 -6959 -6960 -6961 -6962 +v -6963 -6964 -6965 -6966 -6967 -6968 -6969 -6970 -6971 -6972 -6973 -6974 +v -6975 -6976 -6977 -6978 -6979 -6980 -6981 -6982 -6983 -6984 -6985 -6986 +v -6987 -6988 -6989 -6990 -6991 -6992 -6993 -6994 -6995 -6996 -6997 -6998 +v -6999 -7000 -7001 -7002 -7003 -7004 -7005 -7006 -7007 -7008 -7009 -7010 +v -7011 -7012 -7013 -7014 -7015 7016 -7017 7018 -7019 -7020 -7021 7022 -7023 +v 7024 -7025 -7026 -7027 -7028 7029 -7030 7031 -7032 -7033 -7034 -7035 7036 +v -7037 7038 -7039 -7040 7041 -7042 -7043 -7044 -7045 -7046 -7047 -7048 -7049 +v -7050 -7051 7052 7053 7054 -7055 -7056 -7057 -7058 -7059 -7060 -7061 -7062 +v -7063 -7064 -7065 -7066 -7067 -7068 -7069 -7070 -7071 -7072 -7073 -7074 +v -7075 -7076 -7077 -7078 -7079 -7080 -7081 -7082 -7083 -7084 -7085 -7086 +v -7087 -7088 -7089 -7090 -7091 -7092 -7093 -7094 -7095 -7096 -7097 -7098 +v -7099 -7100 -7101 -7102 -7103 -7104 -7105 -7106 -7107 -7108 -7109 -7110 +v -7111 -7112 -7113 -7114 -7115 -7116 -7117 -7118 -7119 -7120 -7121 -7122 +v -7123 -7124 -7125 -7126 -7127 -7128 -7129 -7130 -7131 -7132 -7133 -7134 +v -7135 -7136 -7137 -7138 -7139 -7140 -7141 -7142 -7143 -7144 -7145 -7146 +v -7147 7148 -7149 -7150 -7151 -7152 -7153 -7154 -7155 -7156 -7157 -7158 -7159 +v -7160 -7161 -7162 -7163 -7164 -7165 -7166 -7167 -7168 -7169 -7170 -7171 +v -7172 -7173 -7174 -7175 -7176 -7177 -7178 -7179 -7180 -7181 -7182 -7183 +v -7184 -7185 -7186 -7187 -7188 -7189 -7190 -7191 -7192 -7193 -7194 -7195 +v -7196 -7197 -7198 -7199 -7200 -7201 -7202 -7203 -7204 -7205 -7206 -7207 +v -7208 -7209 -7210 -7211 -7212 -7213 -7214 -7215 -7216 7217 -7218 7219 -7220 +v -7221 -7222 7223 -7224 7225 -7226 -7227 -7228 -7229 7230 -7231 7232 -7233 +v -7234 -7235 -7236 7237 -7238 7239 -7240 -7241 7242 -7243 -7244 -7245 -7246 +v -7247 -7248 -7249 -7250 -7251 -7252 7253 7254 7255 -7256 -7257 -7258 -7259 +v -7260 -7261 -7262 -7263 -7264 -7265 -7266 -7267 -7268 -7269 -7270 -7271 +v -7272 -7273 -7274 -7275 -7276 -7277 -7278 -7279 -7280 -7281 -7282 -7283 +v -7284 -7285 -7286 -7287 -7288 -7289 -7290 -7291 -7292 -7293 -7294 -7295 +v -7296 -7297 -7298 -7299 -7300 -7301 -7302 -7303 -7304 -7305 -7306 -7307 +v -7308 -7309 -7310 -7311 -7312 -7313 -7314 -7315 -7316 -7317 -7318 -7319 +v -7320 -7321 -7322 -7323 -7324 -7325 -7326 -7327 -7328 -7329 -7330 -7331 +v -7332 -7333 -7334 -7335 -7336 -7337 -7338 -7339 -7340 -7341 -7342 -7343 +v -7344 -7345 -7346 -7347 -7348 7349 -7350 -7351 -7352 -7353 -7354 -7355 -7356 +v -7357 -7358 -7359 -7360 -7361 -7362 -7363 -7364 -7365 -7366 -7367 -7368 +v -7369 -7370 -7371 -7372 -7373 -7374 -7375 -7376 -7377 -7378 -7379 -7380 +v -7381 -7382 -7383 -7384 -7385 -7386 -7387 -7388 -7389 -7390 -7391 -7392 +v -7393 -7394 -7395 -7396 -7397 -7398 -7399 -7400 -7401 -7402 -7403 -7404 +v -7405 -7406 -7407 -7408 -7409 -7410 -7411 -7412 -7413 -7414 -7415 -7416 +v -7417 7418 -7419 7420 -7421 -7422 -7423 7424 -7425 7426 -7427 -7428 -7429 +v -7430 7431 -7432 7433 -7434 -7435 -7436 -7437 7438 -7439 7440 -7441 -7442 +v 7443 -7444 -7445 -7446 -7447 -7448 -7449 -7450 -7451 -7452 -7453 7454 7455 +v 7456 -7457 -7458 -7459 -7460 -7461 -7462 -7463 -7464 -7465 -7466 -7467 -7468 +v -7469 -7470 -7471 -7472 -7473 -7474 -7475 -7476 -7477 -7478 -7479 -7480 +v -7481 -7482 -7483 -7484 -7485 -7486 -7487 -7488 -7489 -7490 -7491 -7492 +v -7493 -7494 -7495 -7496 -7497 -7498 -7499 -7500 -7501 -7502 -7503 -7504 +v -7505 -7506 -7507 -7508 -7509 -7510 -7511 -7512 -7513 -7514 -7515 -7516 +v -7517 -7518 -7519 -7520 -7521 -7522 -7523 -7524 -7525 -7526 -7527 -7528 +v -7529 -7530 -7531 -7532 -7533 -7534 -7535 -7536 -7537 -7538 -7539 -7540 +v -7541 -7542 -7543 -7544 -7545 -7546 -7547 -7548 -7549 7550 -7551 -7552 -7553 +v -7554 -7555 -7556 -7557 -7558 -7559 -7560 -7561 -7562 -7563 -7564 -7565 +v -7566 -7567 -7568 -7569 -7570 -7571 -7572 -7573 -7574 -7575 -7576 -7577 +v -7578 -7579 -7580 -7581 -7582 -7583 -7584 -7585 -7586 -7587 -7588 -7589 +v -7590 -7591 -7592 -7593 -7594 -7595 -7596 -7597 -7598 -7599 -7600 -7601 +v -7602 -7603 -7604 -7605 -7606 -7607 -7608 -7609 -7610 -7611 -7612 -7613 +v -7614 -7615 -7616 -7617 -7618 7619 -7620 7621 -7622 -7623 -7624 7625 -7626 +v 7627 -7628 -7629 -7630 -7631 7632 -7633 7634 -7635 -7636 -7637 -7638 7639 +v -7640 7641 -7642 -7643 7644 -7645 -7646 -7647 -7648 -7649 -7650 -7651 -7652 +v -7653 -7654 7655 7656 7657 -7658 -7659 -7660 -7661 -7662 -7663 -7664 -7665 +v -7666 -7667 -7668 -7669 -7670 -7671 -7672 -7673 -7674 -7675 -7676 -7677 +v -7678 -7679 7680 -7681 -7682 -7683 -7684 -7685 -7686 -7687 7688 -7689 7690 +v -7691 -7692 -7693 7694 -7695 7696 -7697 -7698 7699 -7700 -7701 -7702 -7703 +v -7704 -7705 7706 7707 7708 -7709 -7710 -7711 -7712 -7713 -7714 -7715 -7716 +v -7717 -7718 -7719 -7720 -7721 -7722 -7723 -7724 -7725 -7726 -7727 -7728 +v -7729 -7730 -7731 -7732 -7733 -7734 -7735 -7736 -7737 7738 -7739 7740 -7741 +v -7742 -7743 7744 -7745 7746 -7747 -7748 7749 -7750 -7751 -7752 -7753 -7754 +v -7755 7756 7757 7758 7759 -7760 -7761 -7762 -7763 -7764 -7765 -7766 -7767 +v -7768 -7769 -7770 -7771 -7772 -7773 -7774 -7775 -7776 -7777 -7778 -7779 +v -7780 -7781 -7782 -7783 -7784 -7785 -7786 -7787 -7788 7789 -7790 7791 -7792 +v -7793 -7794 7795 -7796 7797 -7798 -7799 7800 -7801 -7802 -7803 -7804 -7805 +v -7806 7807 7808 7809 7810 -7811 -7812 -7813 -7814 -7815 -7816 -7817 -7818 +v -7819 -7820 -7821 -7822 -7823 -7824 -7825 -7826 -7827 -7828 -7829 -7830 +v -7831 -7832 -7833 -7834 -7835 -7836 -7837 -7838 -7839 7840 -7841 7842 -7843 +v -7844 -7845 7846 -7847 7848 -7849 -7850 7851 -7852 -7853 -7854 -7855 -7856 +v -7857 7858 7859 7860 7861 -7862 -7863 -7864 -7865 -7866 -7867 -7868 -7869 +v -7870 -7871 -7872 -7873 -7874 -7875 -7876 -7877 -7878 -7879 -7880 -7881 +v -7882 -7883 -7884 -7885 -7886 -7887 -7888 -7889 -7890 -7891 -7892 -7893 +v -7894 -7895 -7896 -7897 -7898 -7899 -7900 -7901 -7902 -7903 -7904 -7905 +v -7906 -7907 -7908 -7909 -7910 -7911 -7912 -7913 -7914 -7915 -7916 -7917 +v -7918 -7919 -7920 -7921 -7922 -7923 -7924 -7925 -7926 -7927 -7928 -7929 +v -7930 -7931 -7932 -7933 -7934 -7935 -7936 -7937 -7938 -7939 -7940 -7941 +v -7942 -7943 -7944 -7945 -7946 -7947 -7948 -7949 -7950 -7951 -7952 -7953 +v -7954 -7955 -7956 -7957 -7958 -7959 -7960 -7961 -7962 -7963 -7964 -7965 +v -7966 -7967 -7968 -7969 -7970 -7971 -7972 -7973 -7974 -7975 -7976 -7977 +v -7978 -7979 -7980 -7981 -7982 -7983 -7984 -7985 -7986 -7987 -7988 -7989 +v -7990 -7991 -7992 -7993 -7994 -7995 -7996 -7997 -7998 -7999 -8000 -8001 +v -8002 -8003 -8004 -8005 -8006 -8007 -8008 -8009 -8010 -8011 -8012 -8013 +v -8014 -8015 -8016 -8017 -8018 -8019 -8020 -8021 -8022 8023 -8024 8025 -8026 +v -8027 -8028 8029 -8030 8031 -8032 -8033 -8034 -8035 8036 -8037 8038 -8039 +v -8040 -8041 -8042 8043 -8044 8045 -8046 -8047 8048 -8049 -8050 -8051 -8052 +v -8053 -8054 -8055 -8056 -8057 -8058 8059 8060 8061 8062 -8063 -8064 -8065 +v -8066 -8067 -8068 -8069 -8070 -8071 -8072 -8073 -8074 -8075 -8076 -8077 +v -8078 -8079 -8080 -8081 -8082 -8083 -8084 -8085 -8086 -8087 -8088 -8089 +v -8090 -8091 -8092 -8093 -8094 -8095 -8096 -8097 -8098 -8099 -8100 -8101 +v -8102 -8103 -8104 -8105 -8106 -8107 -8108 -8109 -8110 -8111 -8112 -8113 +v -8114 -8115 -8116 -8117 -8118 -8119 -8120 -8121 -8122 -8123 -8124 -8125 +v -8126 -8127 -8128 -8129 -8130 -8131 -8132 -8133 -8134 -8135 -8136 -8137 +v -8138 -8139 -8140 -8141 -8142 -8143 -8144 -8145 -8146 -8147 -8148 -8149 +v -8150 -8151 -8152 -8153 -8154 -8155 -8156 -8157 -8158 -8159 -8160 -8161 +v -8162 -8163 -8164 -8165 -8166 -8167 -8168 -8169 -8170 -8171 -8172 -8173 +v -8174 -8175 -8176 -8177 -8178 -8179 -8180 -8181 -8182 -8183 -8184 -8185 +v -8186 -8187 -8188 -8189 -8190 -8191 -8192 -8193 -8194 -8195 -8196 -8197 +v -8198 -8199 -8200 -8201 -8202 -8203 -8204 -8205 -8206 -8207 -8208 -8209 +v -8210 -8211 -8212 -8213 -8214 -8215 -8216 -8217 -8218 -8219 -8220 -8221 +v -8222 -8223 8224 -8225 8226 -8227 -8228 -8229 8230 -8231 8232 -8233 -8234 +v -8235 -8236 8237 -8238 8239 -8240 -8241 -8242 -8243 8244 -8245 8246 -8247 +v -8248 8249 -8250 -8251 -8252 -8253 -8254 -8255 -8256 -8257 -8258 -8259 8260 +v 8261 8262 8263 -8264 -8265 -8266 -8267 -8268 -8269 -8270 -8271 -8272 -8273 +v -8274 -8275 -8276 -8277 -8278 -8279 -8280 -8281 -8282 -8283 -8284 -8285 +v -8286 -8287 -8288 -8289 -8290 -8291 -8292 -8293 -8294 -8295 -8296 -8297 +v -8298 -8299 -8300 -8301 -8302 -8303 -8304 -8305 -8306 -8307 -8308 -8309 +v -8310 -8311 -8312 -8313 -8314 -8315 -8316 -8317 -8318 -8319 -8320 -8321 +v -8322 -8323 -8324 -8325 -8326 -8327 -8328 -8329 -8330 -8331 -8332 -8333 +v -8334 -8335 -8336 -8337 -8338 -8339 -8340 -8341 -8342 -8343 -8344 -8345 +v -8346 -8347 -8348 -8349 -8350 -8351 -8352 -8353 -8354 -8355 -8356 -8357 +v -8358 -8359 -8360 -8361 -8362 -8363 -8364 -8365 -8366 -8367 -8368 -8369 +v -8370 -8371 -8372 -8373 -8374 -8375 -8376 -8377 -8378 -8379 -8380 -8381 +v -8382 -8383 -8384 -8385 -8386 -8387 -8388 -8389 -8390 -8391 -8392 -8393 +v -8394 -8395 -8396 -8397 -8398 -8399 -8400 -8401 -8402 -8403 -8404 -8405 +v -8406 -8407 -8408 -8409 -8410 -8411 -8412 -8413 -8414 -8415 -8416 -8417 +v -8418 -8419 -8420 -8421 -8422 -8423 -8424 8425 -8426 8427 -8428 -8429 -8430 +v 8431 -8432 8433 -8434 -8435 -8436 -8437 8438 -8439 8440 -8441 -8442 -8443 +v -8444 8445 -8446 8447 -8448 -8449 8450 -8451 -8452 -8453 -8454 -8455 -8456 +v -8457 -8458 -8459 -8460 8461 8462 8463 8464 -8465 -8466 -8467 -8468 -8469 +v -8470 -8471 -8472 -8473 -8474 -8475 -8476 -8477 -8478 -8479 -8480 -8481 +v -8482 -8483 -8484 -8485 -8486 -8487 -8488 -8489 -8490 -8491 -8492 -8493 +v -8494 -8495 -8496 -8497 -8498 -8499 -8500 -8501 -8502 -8503 -8504 -8505 +v -8506 -8507 -8508 -8509 -8510 -8511 -8512 -8513 -8514 -8515 -8516 -8517 +v -8518 -8519 -8520 -8521 -8522 -8523 -8524 -8525 -8526 -8527 -8528 -8529 +v -8530 -8531 -8532 -8533 -8534 -8535 -8536 -8537 -8538 -8539 -8540 -8541 +v -8542 -8543 -8544 -8545 -8546 -8547 -8548 -8549 -8550 -8551 -8552 -8553 +v -8554 -8555 -8556 -8557 -8558 -8559 -8560 -8561 -8562 -8563 -8564 -8565 +v -8566 -8567 -8568 -8569 -8570 -8571 -8572 -8573 -8574 -8575 -8576 -8577 +v -8578 -8579 -8580 -8581 -8582 -8583 -8584 -8585 -8586 -8587 -8588 -8589 +v -8590 -8591 -8592 -8593 -8594 -8595 -8596 -8597 -8598 -8599 -8600 -8601 +v -8602 -8603 -8604 -8605 -8606 -8607 -8608 -8609 -8610 -8611 -8612 -8613 +v -8614 -8615 -8616 -8617 -8618 -8619 -8620 -8621 -8622 -8623 -8624 -8625 8626 +v -8627 8628 -8629 -8630 -8631 8632 -8633 8634 -8635 -8636 -8637 -8638 8639 +v -8640 8641 -8642 -8643 -8644 -8645 8646 -8647 8648 -8649 -8650 8651 -8652 +v -8653 -8654 -8655 -8656 -8657 -8658 -8659 -8660 -8661 8662 8663 8664 8665 +v -8666 -8667 -8668 -8669 -8670 -8671 -8672 -8673 -8674 -8675 -8676 -8677 +v -8678 -8679 -8680 -8681 -8682 -8683 -8684 -8685 -8686 -8687 -8688 -8689 +v -8690 -8691 -8692 -8693 -8694 8695 -8696 8697 -8698 -8699 -8700 8701 -8702 +v 8703 -8704 -8705 8706 -8707 -8708 -8709 -8710 -8711 -8712 8713 8714 8715 +v 8716 -8717 8718 -8719 8720 -8721 8722 8723 -8724 -8725 -8726 -8727 -8728 +v -8729 -8730 -8731 -8732 -8733 -8734 -8735 -8736 -8737 -8738 -8739 -8740 +v -8741 -8742 -8743 -8744 -8745 -8746 -8747 -8748 -8749 -8750 -8751 -8752 +v -8753 -8754 -8755 -8756 -8757 -8758 -8759 -8760 -8761 -8762 -8763 -8764 +v -8765 -8766 -8767 -8768 -8769 -8770 -8771 -8772 -8773 -8774 -8775 -8776 +v -8777 -8778 -8779 -8780 -8781 -8782 -8783 -8784 -8785 -8786 -8787 -8788 +v -8789 -8790 -8791 -8792 -8793 -8794 -8795 -8796 -8797 -8798 -8799 -8800 +v -8801 -8802 -8803 -8804 -8805 -8806 -8807 -8808 -8809 -8810 -8811 -8812 +v -8813 -8814 -8815 -8816 -8817 -8818 -8819 -8820 -8821 -8822 -8823 -8824 +v -8825 -8826 -8827 -8828 -8829 -8830 -8831 -8832 -8833 -8834 -8835 -8836 +v -8837 -8838 -8839 -8840 -8841 -8842 -8843 -8844 -8845 -8846 -8847 -8848 +v -8849 -8850 -8851 -8852 -8853 -8854 -8855 -8856 -8857 -8858 -8859 -8860 +v -8861 -8862 -8863 -8864 -8865 -8866 -8867 -8868 -8869 -8870 -8871 -8872 +v -8873 -8874 -8875 -8876 -8877 -8878 -8879 -8880 -8881 -8882 -8883 -8884 +v -8885 -8886 -8887 -8888 -8889 -8890 -8891 -8892 -8893 -8894 -8895 -8896 +v -8897 -8898 -8899 -8900 -8901 -8902 -8903 -8904 -8905 -8906 -8907 -8908 +v -8909 -8910 -8911 -8912 -8913 -8914 -8915 -8916 -8917 -8918 -8919 -8920 +v -8921 -8922 -8923 -8924 -8925 -8926 -8927 -8928 -8929 -8930 -8931 -8932 +v -8933 -8934 -8935 -8936 -8937 -8938 -8939 -8940 -8941 -8942 -8943 -8944 +v -8945 -8946 -8947 -8948 -8949 -8950 -8951 -8952 -8953 -8954 -8955 -8956 +v -8957 -8958 -8959 -8960 -8961 -8962 -8963 -8964 -8965 -8966 -8967 -8968 +v -8969 -8970 -8971 -8972 -8973 -8974 -8975 -8976 -8977 -8978 -8979 -8980 +v -8981 -8982 -8983 -8984 -8985 -8986 -8987 -8988 -8989 -8990 -8991 -8992 +v -8993 -8994 -8995 -8996 -8997 -8998 -8999 -9000 -9001 -9002 -9003 -9004 +v -9005 -9006 -9007 -9008 -9009 -9010 -9011 -9012 -9013 -9014 -9015 -9016 +v -9017 -9018 -9019 -9020 -9021 -9022 -9023 -9024 -9025 -9026 -9027 -9028 +v -9029 -9030 -9031 -9032 -9033 -9034 -9035 -9036 -9037 -9038 -9039 -9040 +v -9041 -9042 -9043 -9044 -9045 -9046 -9047 -9048 -9049 -9050 -9051 -9052 +v -9053 -9054 -9055 -9056 -9057 -9058 -9059 -9060 -9061 -9062 -9063 -9064 +v -9065 -9066 -9067 -9068 -9069 -9070 -9071 -9072 -9073 -9074 -9075 -9076 +v -9077 -9078 -9079 -9080 -9081 -9082 -9083 -9084 -9085 -9086 -9087 -9088 +v -9089 -9090 -9091 -9092 -9093 -9094 -9095 -9096 -9097 -9098 -9099 -9100 +v -9101 -9102 -9103 -9104 -9105 -9106 -9107 -9108 -9109 -9110 -9111 -9112 +v -9113 -9114 -9115 -9116 -9117 -9118 -9119 -9120 -9121 -9122 -9123 -9124 +v -9125 -9126 -9127 9128 -9129 9130 -9131 -9132 -9133 9134 -9135 9136 -9137 +v -9138 -9139 9140 -9141 9142 -9143 -9144 -9145 -9146 9147 -9148 9149 -9150 +v -9151 -9152 -9153 9154 -9155 9156 -9157 -9158 -9159 -9160 9161 -9162 9163 +v -9164 -9165 9166 -9167 -9168 -9169 -9170 -9171 -9172 -9173 -9174 -9175 -9176 +v -9177 -9178 -9179 -9180 9181 9182 9183 9184 9185 -9186 -9187 -9188 -9189 +v -9190 -9191 9192 -9193 -9194 -9195 -9196 -9197 -9198 -9199 -9200 -9201 -9202 +v -9203 -9204 -9205 -9206 -9207 -9208 -9209 -9210 -9211 -9212 -9213 -9214 +v -9215 -9216 -9217 -9218 -9219 -9220 -9221 -9222 -9223 -9224 -9225 -9226 +v -9227 -9228 -9229 -9230 -9231 -9232 -9233 -9234 -9235 -9236 -9237 -9238 +v -9239 -9240 -9241 -9242 -9243 -9244 -9245 -9246 -9247 -9248 -9249 -9250 +v -9251 -9252 -9253 -9254 -9255 -9256 -9257 -9258 -9259 -9260 -9261 -9262 +v -9263 -9264 -9265 -9266 -9267 -9268 -9269 -9270 -9271 -9272 -9273 -9274 +v -9275 -9276 -9277 -9278 -9279 -9280 -9281 -9282 -9283 -9284 -9285 -9286 +v -9287 -9288 -9289 -9290 -9291 -9292 -9293 -9294 -9295 -9296 -9297 -9298 +v -9299 -9300 -9301 -9302 -9303 -9304 -9305 -9306 -9307 -9308 -9309 -9310 +v -9311 -9312 9313 -9314 9315 -9316 -9317 -9318 9319 -9320 9321 -9322 -9323 +v -9324 9325 -9326 9327 -9328 -9329 -9330 9331 -9332 9333 -9334 -9335 9336 +v -9337 -9338 -9339 -9340 -9341 -9342 -9343 -9344 -9345 -9346 9347 9348 9349 +v 9350 -9351 -9352 -9353 -9354 -9355 -9356 -9357 -9358 -9359 -9360 -9361 -9362 +v -9363 -9364 -9365 -9366 -9367 -9368 -9369 -9370 -9371 -9372 -9373 -9374 +v -9375 -9376 -9377 -9378 -9379 -9380 -9381 -9382 -9383 -9384 -9385 -9386 +v -9387 -9388 -9389 -9390 -9391 -9392 -9393 -9394 -9395 -9396 -9397 -9398 +v -9399 -9400 -9401 -9402 -9403 9404 -9405 9406 -9407 -9408 9409 -9410 9411 +v -9412 -9413 -9414 9415 -9416 9417 -9418 -9419 -9420 9421 -9422 9423 -9424 +v -9425 9426 -9427 -9428 -9429 -9430 -9431 -9432 -9433 -9434 -9435 -9436 9437 +v 9438 9439 9440 -9441 -9442 -9443 -9444 -9445 -9446 -9447 -9448 -9449 -9450 +v -9451 -9452 -9453 -9454 -9455 -9456 -9457 -9458 -9459 -9460 -9461 -9462 +v -9463 -9464 -9465 -9466 -9467 -9468 -9469 -9470 -9471 -9472 -9473 -9474 +v -9475 -9476 -9477 -9478 -9479 -9480 -9481 -9482 -9483 -9484 -9485 -9486 +v -9487 -9488 -9489 -9490 -9491 -9492 -9493 -9494 -9495 -9496 -9497 -9498 +v -9499 -9500 -9501 -9502 -9503 -9504 -9505 -9506 -9507 -9508 -9509 -9510 +v -9511 -9512 -9513 -9514 -9515 -9516 -9517 -9518 -9519 -9520 -9521 -9522 +v -9523 -9524 -9525 -9526 -9527 -9528 -9529 -9530 -9531 -9532 -9533 -9534 +v -9535 -9536 -9537 -9538 -9539 -9540 -9541 -9542 -9543 -9544 -9545 -9546 +v -9547 -9548 -9549 -9550 -9551 -9552 -9553 -9554 -9555 -9556 -9557 -9558 +v -9559 -9560 -9561 -9562 -9563 -9564 -9565 -9566 -9567 -9568 -9569 -9570 +v -9571 -9572 -9573 -9574 -9575 -9576 -9577 -9578 -9579 -9580 -9581 -9582 +v -9583 -9584 -9585 -9586 -9587 -9588 -9589 -9590 -9591 -9592 -9593 -9594 +v -9595 -9596 -9597 -9598 -9599 -9600 -9601 -9602 -9603 -9604 -9605 -9606 +v -9607 9608 -9609 9610 -9611 -9612 9613 -9614 9615 -9616 -9617 9618 -9619 +v 9620 -9621 -9622 -9623 9624 -9625 9626 -9627 -9628 -9629 9630 -9631 9632 +v -9633 -9634 9635 -9636 -9637 -9638 -9639 -9640 -9641 -9642 -9643 -9644 -9645 +v -9646 9647 9648 9649 -9650 -9651 -9652 -9653 -9654 -9655 -9656 -9657 -9658 +v -9659 -9660 -9661 -9662 9663 -9664 -9665 9666 -9667 -9668 -9669 -9670 -9671 +v -9672 9673 9674 9675 -9676 -9677 -9678 -9679 -9680 -9681 -9682 -9683 -9684 +v -9685 -9686 -9687 -9688 -9689 9690 -9691 -9692 9693 -9694 -9695 -9696 -9697 +v -9698 9699 9700 9701 -9702 -9703 -9704 -9705 -9706 -9707 -9708 -9709 -9710 +v 9711 9712 -9713 9714 -9715 -9716 9717 -9718 -9719 -9720 -9721 -9722 -9723 +v 9724 -9725 -9726 -9727 -9728 -9729 -9730 -9731 -9732 -9733 -9734 -9735 -9736 +v -9737 -9738 9739 -9740 -9741 9742 -9743 -9744 -9745 -9746 -9747 9748 -9749 +v 9750 -9751 -9752 -9753 9754 -9755 9756 9757 9758 9759 9760 -9761 -9762 9763 +v 9764 9765 -9766 -9767 -9768 -9769 -9770 -9771 -9772 -9773 -9774 9775 9776 +v 9777 -9778 -9779 -9780 -9781 -9782 -9783 -9784 -9785 -9786 -9787 -9788 -9789 +v -9790 -9791 -9792 -9793 -9794 -9795 -9796 -9797 -9798 -9799 9800 -9801 -9802 +v -9803 -9804 -9805 -9806 -9807 9808 -9809 9810 -9811 -9812 -9813 9814 -9815 +v 9816 -9817 -9818 9819 -9820 -9821 -9822 -9823 -9824 -9825 9826 9827 9828 +v -9829 -9830 -9831 -9832 -9833 -9834 -9835 -9836 -9837 -9838 -9839 -9840 +v -9841 -9842 -9843 -9844 -9845 -9846 -9847 -9848 -9849 -9850 9851 -9852 -9853 +v -9854 -9855 -9856 -9857 -9858 9859 -9860 9861 -9862 -9863 -9864 9865 -9866 +v 9867 -9868 -9869 9870 -9871 -9872 -9873 -9874 -9875 -9876 9877 9878 9879 +v -9880 -9881 -9882 -9883 -9884 -9885 -9886 -9887 -9888 -9889 -9890 -9891 +v -9892 -9893 -9894 -9895 -9896 -9897 -9898 -9899 -9900 -9901 9902 -9903 -9904 +v -9905 -9906 -9907 -9908 -9909 9910 -9911 9912 -9913 -9914 -9915 9916 -9917 +v 9918 -9919 -9920 9921 -9922 -9923 -9924 -9925 -9926 -9927 9928 9929 9930 +v -9931 -9932 -9933 -9934 -9935 -9936 -9937 -9938 -9939 -9940 -9941 -9942 +v -9943 -9944 -9945 -9946 -9947 -9948 -9949 -9950 -9951 -9952 -9953 -9954 +v -9955 -9956 -9957 -9958 -9959 -9960 -9961 -9962 -9963 -9964 -9965 -9966 +v -9967 -9968 -9969 -9970 -9971 -9972 -9973 -9974 -9975 -9976 -9977 -9978 +v -9979 -9980 -9981 -9982 -9983 -9984 -9985 -9986 -9987 -9988 -9989 -9990 +v -9991 -9992 -9993 -9994 -9995 -9996 -9997 -9998 -9999 -10000 -10001 -10002 +v -10003 -10004 -10005 -10006 -10007 -10008 -10009 -10010 -10011 -10012 -10013 +v -10014 -10015 -10016 -10017 -10018 -10019 -10020 -10021 -10022 -10023 10024 +v -10025 -10026 -10027 -10028 -10029 -10030 -10031 -10032 -10033 -10034 -10035 +v -10036 -10037 -10038 -10039 -10040 -10041 -10042 -10043 -10044 -10045 -10046 +v -10047 -10048 -10049 -10050 -10051 -10052 -10053 -10054 -10055 -10056 -10057 +v -10058 -10059 -10060 -10061 -10062 -10063 -10064 -10065 -10066 -10067 -10068 +v -10069 -10070 -10071 -10072 -10073 -10074 -10075 -10076 -10077 -10078 -10079 +v -10080 -10081 -10082 -10083 -10084 -10085 -10086 -10087 -10088 -10089 -10090 +v -10091 -10092 10093 -10094 10095 -10096 -10097 -10098 10099 -10100 10101 +v -10102 -10103 -10104 -10105 10106 -10107 10108 -10109 -10110 -10111 -10112 +v 10113 -10114 10115 -10116 -10117 10118 -10119 -10120 -10121 -10122 -10123 +v -10124 -10125 -10126 -10127 -10128 10129 10130 10131 -10132 -10133 -10134 +v -10135 -10136 -10137 -10138 -10139 -10140 -10141 -10142 -10143 -10144 -10145 +v -10146 -10147 -10148 -10149 -10150 -10151 -10152 -10153 -10154 -10155 -10156 +v -10157 -10158 -10159 -10160 -10161 -10162 -10163 -10164 -10165 -10166 -10167 +v -10168 -10169 -10170 -10171 -10172 -10173 -10174 -10175 -10176 -10177 -10178 +v -10179 -10180 -10181 -10182 -10183 -10184 -10185 -10186 -10187 -10188 -10189 +v -10190 -10191 -10192 -10193 -10194 -10195 -10196 -10197 -10198 -10199 -10200 +v -10201 -10202 -10203 -10204 -10205 -10206 -10207 -10208 -10209 -10210 -10211 +v -10212 -10213 -10214 -10215 -10216 -10217 -10218 -10219 -10220 -10221 -10222 +v -10223 -10224 10225 -10226 -10227 -10228 -10229 -10230 -10231 -10232 -10233 +v -10234 -10235 -10236 -10237 -10238 -10239 -10240 -10241 -10242 -10243 -10244 +v -10245 -10246 -10247 -10248 -10249 -10250 -10251 -10252 -10253 -10254 -10255 +v -10256 -10257 -10258 -10259 -10260 -10261 -10262 -10263 -10264 -10265 -10266 +v -10267 -10268 -10269 -10270 -10271 -10272 -10273 -10274 -10275 -10276 -10277 +v -10278 -10279 -10280 -10281 -10282 -10283 -10284 -10285 -10286 -10287 -10288 +v -10289 -10290 -10291 -10292 -10293 10294 -10295 10296 -10297 -10298 -10299 +v 10300 -10301 10302 -10303 -10304 -10305 -10306 10307 -10308 10309 -10310 +v -10311 -10312 -10313 10314 -10315 10316 -10317 -10318 10319 -10320 -10321 +v -10322 -10323 -10324 -10325 -10326 -10327 -10328 -10329 10330 10331 10332 +v -10333 -10334 -10335 -10336 -10337 -10338 -10339 -10340 -10341 -10342 -10343 +v -10344 -10345 -10346 -10347 -10348 -10349 -10350 -10351 -10352 -10353 -10354 +v -10355 -10356 -10357 -10358 -10359 -10360 -10361 -10362 -10363 -10364 -10365 +v -10366 -10367 -10368 -10369 -10370 -10371 -10372 -10373 -10374 -10375 -10376 +v -10377 -10378 -10379 -10380 -10381 -10382 -10383 -10384 -10385 -10386 -10387 +v -10388 -10389 -10390 -10391 -10392 -10393 -10394 -10395 -10396 -10397 -10398 +v -10399 -10400 -10401 -10402 -10403 -10404 -10405 -10406 -10407 -10408 -10409 +v -10410 -10411 -10412 -10413 -10414 -10415 -10416 -10417 -10418 -10419 -10420 +v -10421 -10422 -10423 -10424 -10425 10426 -10427 -10428 -10429 -10430 -10431 +v -10432 -10433 -10434 -10435 -10436 -10437 -10438 -10439 -10440 -10441 -10442 +v -10443 -10444 -10445 -10446 -10447 -10448 -10449 -10450 -10451 -10452 -10453 +v -10454 -10455 -10456 -10457 -10458 -10459 -10460 -10461 -10462 -10463 -10464 +v -10465 -10466 -10467 -10468 -10469 -10470 -10471 -10472 -10473 -10474 -10475 +v -10476 -10477 -10478 -10479 -10480 -10481 -10482 -10483 -10484 -10485 -10486 +v -10487 -10488 -10489 -10490 -10491 -10492 -10493 -10494 10495 -10496 10497 +v -10498 -10499 -10500 10501 -10502 10503 -10504 -10505 -10506 -10507 10508 +v -10509 10510 -10511 -10512 -10513 -10514 10515 -10516 10517 -10518 -10519 +v 10520 -10521 -10522 -10523 -10524 -10525 -10526 -10527 -10528 -10529 -10530 +v 10531 10532 10533 -10534 -10535 -10536 -10537 -10538 -10539 -10540 -10541 +v -10542 -10543 -10544 -10545 -10546 -10547 -10548 -10549 -10550 -10551 -10552 +v -10553 -10554 -10555 -10556 -10557 -10558 -10559 -10560 -10561 -10562 -10563 +v -10564 -10565 -10566 -10567 -10568 -10569 -10570 -10571 -10572 -10573 -10574 +v -10575 -10576 -10577 -10578 -10579 -10580 -10581 -10582 -10583 -10584 -10585 +v -10586 -10587 -10588 -10589 -10590 -10591 -10592 -10593 -10594 -10595 -10596 +v -10597 -10598 -10599 -10600 -10601 -10602 -10603 -10604 -10605 -10606 -10607 +v -10608 -10609 -10610 -10611 -10612 -10613 -10614 -10615 -10616 -10617 -10618 +v -10619 -10620 -10621 -10622 -10623 -10624 -10625 -10626 10627 -10628 -10629 +v -10630 -10631 -10632 -10633 -10634 -10635 -10636 -10637 -10638 -10639 -10640 +v -10641 -10642 -10643 -10644 -10645 -10646 -10647 -10648 -10649 -10650 -10651 +v -10652 -10653 -10654 -10655 -10656 -10657 -10658 -10659 -10660 -10661 -10662 +v -10663 -10664 -10665 -10666 -10667 -10668 -10669 -10670 -10671 -10672 -10673 +v -10674 -10675 -10676 -10677 -10678 -10679 -10680 -10681 -10682 -10683 -10684 +v -10685 -10686 -10687 -10688 -10689 -10690 -10691 -10692 -10693 -10694 -10695 +v 10696 -10697 10698 -10699 -10700 -10701 10702 -10703 10704 -10705 -10706 +v -10707 -10708 10709 -10710 10711 -10712 -10713 -10714 -10715 10716 -10717 +v 10718 -10719 -10720 10721 -10722 -10723 -10724 -10725 -10726 -10727 -10728 +v -10729 -10730 -10731 10732 10733 10734 -10735 -10736 -10737 -10738 -10739 +v -10740 -10741 -10742 -10743 -10744 -10745 -10746 -10747 -10748 -10749 -10750 +v -10751 -10752 -10753 -10754 -10755 -10756 10757 -10758 -10759 -10760 -10761 +v -10762 -10763 -10764 10765 -10766 10767 -10768 -10769 -10770 10771 -10772 +v 10773 -10774 -10775 10776 -10777 -10778 -10779 -10780 -10781 -10782 10783 +v 10784 10785 10786 10787 10788 10789 -10790 -10791 -10792 -10793 -10794 10795 +v 10796 -10797 10798 -10799 10800 10801 -10802 10803 -10804 -10805 10806 +v -10807 -10808 10809 -10810 -10811 -10812 -10813 -10814 -10815 10816 10817 +v 10818 10819 -10820 -10821 -10822 -10823 -10824 10825 10826 -10827 10828 +v -10829 10830 10831 -10832 10833 -10834 -10835 10836 -10837 -10838 10839 +v -10840 -10841 -10842 -10843 -10844 -10845 10846 10847 10848 10849 -10850 +v -10851 -10852 -10853 -10854 10855 10856 -10857 10858 -10859 10860 10861 +v -10862 10863 -10864 -10865 10866 -10867 -10868 10869 -10870 -10871 -10872 +v -10873 -10874 -10875 10876 10877 10878 10879 10880 -10881 10882 -10883 10884 +v 10885 10886 10887 10888 10889 10890 10891 -10892 10893 -10894 10895 10896 +v -10897 -10898 -10899 10900 -10901 -10902 -10903 10904 10905 10906 10907 +v 10908 10909 10910 10911 10912 10913 10914 -10915 10916 -10917 -10918 -10919 +v -10920 -10921 -10922 10923 10924 10925 -10926 10927 10928 -10929 -10930 +v 10931 10932 10933 10934 10935 10936 10937 10938 -10939 -10940 10941 10942 +v -10943 -10944 10945 -10946 10947 -10948 -10949 -10950 10951 -10952 10953 +v -10954 -10955 10956 -10957 -10958 -10959 -10960 -10961 -10962 -10963 -10964 +v 10965 10966 10967 -10968 -10969 10970 10971 -10972 -10973 -10974 -10975 +v -10976 -10977 -10978 -10979 -10980 10981 10982 -10983 -10984 -10985 -10986 +v -10987 -10988 -10989 -10990 -10991 10992 10993 -10994 -10995 -10996 -10997 +v -10998 -10999 -11000 -11001 -11002 11003 11004 11005 11006 11007 11008 +v -11009 -11010 -11011 11012 11013 11014 -11015 -11016 11017 11018 -11019 +v 11020 11021 11022 11023 11024 -11025 -11026 11027 -11028 -11029 11030 11031 +v -11032 -11033 11034 -11035 -11036 11037 11038 11039 11040 -11041 -11042 +v -11043 -11044 11045 11046 11047 11048 -11049 -11050 -11051 -11052 11053 +v 11054 11055 11056 -11057 -11058 -11059 -11060 -11061 -11062 -11063 -11064 +v -11065 -11066 -11067 -11068 -11069 -11070 -11071 -11072 -11073 -11074 11075 +v -11076 11077 -11078 -11079 -11080 11081 -11082 11083 -11084 -11085 11086 +v -11087 -11088 -11089 -11090 -11091 -11092 11093 11094 11095 11096 -11097 +v -11098 -11099 -11100 -11101 -11102 -11103 -11104 -11105 -11106 -11107 -11108 +v -11109 -11110 -11111 -11112 11113 -11114 11115 -11116 -11117 -11118 11119 +v -11120 11121 -11122 -11123 11124 -11125 -11126 -11127 -11128 -11129 -11130 +v 11131 11132 11133 11134 -11135 -11136 11137 11138 11139 11140 -11141 -11142 +v -11143 -11144 11145 11146 11147 11148 -11149 -11150 -11151 -11152 -11153 +v -11154 -11155 -11156 -11157 -11158 -11159 -11160 -11161 -11162 -11163 -11164 +v -11165 -11166 -11167 -11168 -11169 11170 -11171 11172 -11173 -11174 -11175 +v -11176 11177 -11178 11179 -11180 -11181 11182 -11183 -11184 -11185 -11186 +v -11187 -11188 11189 11190 11191 11192 11193 11194 -11195 -11196 -11197 +v -11198 -11199 -11200 -11201 -11202 -11203 -11204 -11205 -11206 -11207 -11208 +v -11209 -11210 -11211 -11212 -11213 -11214 -11215 11216 -11217 11218 -11219 +v -11220 -11221 -11222 11223 -11224 11225 -11226 -11227 11228 -11229 -11230 +v -11231 -11232 -11233 -11234 11235 11236 11237 11238 -11239 -11240 11241 +v -11242 11243 -11244 11245 -11246 -11247 -11248 11249 11250 11251 11252 +v -11253 -11254 -11255 11256 11257 -11258 -11259 11260 11261 -11262 -11263 +v -11264 -11265 -11266 11267 11268 11269 11270 -11271 -11272 11273 11274 +v -11275 -11276 11277 11278 -11279 -11280 11281 11282 -11283 11284 -11285 +v 11286 -11287 -11288 -11289 -11290 -11291 -11292 11293 11294 -11295 11296 +v -11297 11298 -11299 -11300 -11301 -11302 -11303 -11304 11305 11306 -11307 +v -11308 11309 11310 -11311 -11312 11313 11314 -11315 11316 -11317 11318 +v -11319 -11320 -11321 -11322 -11323 -11324 11325 -11326 -11327 11328 -11329 +v 11330 -11331 11332 -11333 -11334 -11335 11336 11337 11338 11339 11340 11341 +v 11342 11343 11344 11345 -11346 -11347 11348 11349 -11350 -11351 11352 -11353 +v 11354 -11355 -11356 -11357 -11358 11359 11360 11361 -11362 -11363 11364 +v -11365 -11366 11367 11368 11369 -11370 -11371 11372 -11373 11374 -11375 +v -11376 11377 11378 11379 -11380 -11381 -11382 11383 -11384 11385 11386 11387 +v -11388 -11389 11390 11391 11392 -11393 -11394 -11395 -11396 -11397 -11398 +v 11399 11400 11401 11402 -11403 -11404 -11405 -11406 -11407 -11408 -11409 +v -11410 -11411 -11412 -11413 -11414 -11415 -11416 -11417 -11418 -11419 -11420 +v -11421 -11422 -11423 -11424 -11425 -11426 -11427 -11428 -11429 -11430 -11431 +v -11432 -11433 11434 -11435 11436 -11437 -11438 -11439 11440 -11441 11442 +v -11443 -11444 11445 -11446 -11447 -11448 -11449 -11450 -11451 11452 11453 +v 11454 11455 -11456 -11457 -11458 -11459 -11460 -11461 -11462 -11463 -11464 +v -11465 -11466 -11467 -11468 -11469 -11470 -11471 -11472 -11473 -11474 -11475 +v -11476 -11477 -11478 -11479 -11480 -11481 -11482 -11483 -11484 -11485 -11486 +v 11487 -11488 11489 -11490 -11491 -11492 11493 -11494 11495 -11496 -11497 +v 11498 -11499 -11500 -11501 -11502 -11503 -11504 11505 11506 11507 11508 +v -11509 -11510 -11511 -11512 -11513 -11514 -11515 -11516 -11517 -11518 -11519 +v -11520 -11521 -11522 -11523 -11524 -11525 -11526 -11527 -11528 -11529 -11530 +v -11531 -11532 -11533 -11534 -11535 -11536 -11537 -11538 -11539 11540 -11541 +v 11542 -11543 -11544 -11545 11546 -11547 11548 -11549 -11550 11551 -11552 +v -11553 -11554 -11555 -11556 -11557 11558 11559 11560 11561 -11562 -11563 +v -11564 -11565 -11566 -11567 -11568 -11569 -11570 -11571 -11572 -11573 -11574 +v -11575 -11576 -11577 -11578 -11579 -11580 -11581 -11582 -11583 -11584 -11585 +v -11586 -11587 -11588 -11589 -11590 -11591 -11592 -11593 -11594 -11595 -11596 +v -11597 -11598 -11599 -11600 -11601 -11602 -11603 -11604 -11605 -11606 -11607 +v -11608 -11609 -11610 -11611 -11612 -11613 -11614 -11615 -11616 -11617 -11618 +v -11619 -11620 -11621 -11622 -11623 -11624 -11625 -11626 -11627 -11628 -11629 +v -11630 -11631 -11632 -11633 -11634 -11635 -11636 -11637 -11638 -11639 -11640 +v -11641 -11642 -11643 -11644 -11645 -11646 -11647 -11648 -11649 -11650 -11651 +v -11652 -11653 -11654 -11655 -11656 -11657 -11658 -11659 -11660 -11661 -11662 +v -11663 -11664 -11665 -11666 -11667 -11668 -11669 -11670 -11671 -11672 -11673 +v -11674 -11675 -11676 -11677 -11678 -11679 -11680 -11681 -11682 -11683 -11684 +v -11685 -11686 -11687 -11688 -11689 -11690 -11691 -11692 -11693 -11694 -11695 +v -11696 -11697 -11698 -11699 -11700 -11701 -11702 -11703 -11704 -11705 -11706 +v -11707 -11708 -11709 -11710 -11711 -11712 -11713 -11714 -11715 -11716 -11717 +v -11718 -11719 -11720 -11721 -11722 -11723 -11724 -11725 -11726 -11727 -11728 +v -11729 -11730 -11731 -11732 -11733 -11734 -11735 -11736 -11737 -11738 -11739 +v -11740 -11741 -11742 -11743 -11744 11745 -11746 11747 -11748 -11749 -11750 +v 11751 -11752 11753 -11754 -11755 -11756 -11757 11758 -11759 11760 -11761 +v -11762 -11763 -11764 11765 -11766 11767 -11768 -11769 11770 -11771 -11772 +v -11773 -11774 -11775 -11776 -11777 -11778 -11779 -11780 11781 11782 11783 +v 11784 -11785 -11786 -11787 -11788 -11789 -11790 -11791 -11792 -11793 -11794 +v -11795 -11796 -11797 -11798 -11799 -11800 -11801 -11802 -11803 -11804 -11805 +v -11806 -11807 -11808 -11809 -11810 -11811 -11812 -11813 -11814 -11815 11816 +v -11817 11818 -11819 -11820 -11821 11822 -11823 11824 -11825 -11826 11827 +v -11828 -11829 -11830 -11831 -11832 -11833 11834 11835 11836 11837 -11838 +v 11839 -11840 11841 -11842 11843 11844 11845 -11846 -11847 -11848 -11849 +v -11850 -11851 -11852 -11853 -11854 -11855 -11856 -11857 -11858 -11859 -11860 +v -11861 -11862 -11863 -11864 -11865 -11866 -11867 -11868 -11869 -11870 -11871 +v -11872 -11873 -11874 -11875 -11876 -11877 -11878 -11879 -11880 -11881 -11882 +v -11883 -11884 -11885 -11886 -11887 -11888 -11889 -11890 -11891 -11892 -11893 +v -11894 -11895 -11896 -11897 -11898 -11899 -11900 -11901 -11902 -11903 -11904 +v -11905 -11906 -11907 -11908 -11909 -11910 -11911 -11912 -11913 -11914 -11915 +v -11916 -11917 -11918 -11919 -11920 -11921 -11922 -11923 -11924 -11925 -11926 +v -11927 -11928 -11929 -11930 -11931 -11932 -11933 -11934 -11935 -11936 -11937 +v -11938 -11939 -11940 -11941 -11942 -11943 -11944 -11945 -11946 -11947 -11948 +v -11949 -11950 -11951 -11952 -11953 -11954 -11955 -11956 -11957 -11958 -11959 +v -11960 -11961 -11962 -11963 -11964 -11965 -11966 -11967 -11968 -11969 -11970 +v -11971 -11972 -11973 -11974 -11975 -11976 -11977 -11978 -11979 -11980 -11981 +v -11982 -11983 -11984 -11985 -11986 -11987 -11988 -11989 -11990 -11991 -11992 +v -11993 -11994 -11995 -11996 -11997 -11998 -11999 -12000 -12001 -12002 -12003 +v -12004 -12005 -12006 -12007 -12008 -12009 -12010 -12011 -12012 -12013 -12014 +v -12015 -12016 -12017 -12018 -12019 -12020 -12021 -12022 -12023 -12024 -12025 +v -12026 -12027 -12028 -12029 -12030 -12031 -12032 -12033 -12034 -12035 -12036 +v -12037 -12038 -12039 -12040 -12041 -12042 -12043 -12044 -12045 -12046 -12047 +v -12048 -12049 -12050 -12051 -12052 -12053 -12054 -12055 -12056 -12057 -12058 +v -12059 -12060 -12061 -12062 -12063 -12064 -12065 -12066 -12067 -12068 -12069 +v -12070 -12071 -12072 -12073 -12074 -12075 -12076 -12077 -12078 -12079 -12080 +v -12081 -12082 -12083 -12084 -12085 -12086 -12087 -12088 -12089 -12090 -12091 +v -12092 -12093 -12094 -12095 -12096 -12097 -12098 -12099 -12100 -12101 -12102 +v -12103 -12104 -12105 -12106 -12107 -12108 -12109 -12110 -12111 -12112 -12113 +v -12114 -12115 -12116 -12117 -12118 -12119 -12120 -12121 -12122 -12123 -12124 +v -12125 -12126 -12127 -12128 -12129 -12130 -12131 -12132 -12133 -12134 -12135 +v -12136 -12137 -12138 -12139 -12140 -12141 -12142 -12143 -12144 -12145 -12146 +v -12147 -12148 -12149 -12150 -12151 -12152 -12153 -12154 -12155 -12156 -12157 +v -12158 -12159 -12160 -12161 -12162 -12163 -12164 -12165 -12166 -12167 -12168 +v -12169 -12170 -12171 -12172 -12173 -12174 -12175 -12176 -12177 -12178 -12179 +v -12180 -12181 -12182 -12183 -12184 -12185 -12186 -12187 -12188 -12189 -12190 +v -12191 -12192 -12193 -12194 -12195 -12196 -12197 -12198 -12199 -12200 -12201 +v -12202 -12203 -12204 -12205 -12206 -12207 -12208 -12209 -12210 -12211 -12212 +v -12213 -12214 -12215 -12216 -12217 -12218 -12219 -12220 -12221 -12222 -12223 +v -12224 -12225 -12226 -12227 -12228 -12229 -12230 -12231 -12232 -12233 -12234 +v -12235 -12236 -12237 -12238 -12239 -12240 -12241 -12242 -12243 -12244 -12245 +v -12246 -12247 -12248 -12249 -12250 -12251 -12252 -12253 -12254 -12255 -12256 +v -12257 -12258 -12259 -12260 -12261 -12262 -12263 -12264 -12265 -12266 12267 +v -12268 12269 -12270 -12271 12272 -12273 12274 -12275 -12276 -12277 12278 +v -12279 12280 -12281 -12282 -12283 12284 -12285 12286 -12287 -12288 -12289 +v 12290 -12291 12292 -12293 -12294 12295 -12296 12297 -12298 -12299 -12300 +v -12301 -12302 -12303 -12304 -12305 -12306 -12307 -12308 -12309 -12310 -12311 +v 12312 12313 12314 12315 12316 -12317 -12318 -12319 -12320 -12321 -12322 +v 12323 -12324 -12325 -12326 -12327 -12328 -12329 -12330 -12331 -12332 -12333 +v -12334 -12335 -12336 -12337 -12338 -12339 -12340 -12341 -12342 -12343 -12344 +v -12345 -12346 -12347 -12348 -12349 -12350 -12351 -12352 -12353 -12354 -12355 +v -12356 -12357 -12358 -12359 -12360 -12361 -12362 -12363 -12364 -12365 -12366 +v -12367 -12368 -12369 -12370 -12371 -12372 -12373 -12374 -12375 -12376 -12377 +v -12378 -12379 -12380 -12381 -12382 -12383 -12384 -12385 -12386 -12387 -12388 +v -12389 -12390 -12391 -12392 -12393 -12394 -12395 -12396 -12397 -12398 -12399 +v -12400 -12401 -12402 -12403 -12404 -12405 -12406 -12407 -12408 -12409 -12410 +v -12411 -12412 -12413 -12414 -12415 -12416 -12417 -12418 -12419 -12420 -12421 +v -12422 -12423 -12424 -12425 -12426 -12427 -12428 -12429 -12430 -12431 -12432 +v -12433 -12434 -12435 -12436 -12437 -12438 -12439 -12440 -12441 -12442 -12443 +v -12444 -12445 12446 -12447 12448 -12449 -12450 -12451 -12452 12453 -12454 +v 12455 -12456 -12457 -12458 -12459 12460 -12461 12462 -12463 -12464 -12465 +v -12466 12467 -12468 12469 -12470 -12471 12472 -12473 12474 -12475 -12476 +v 12477 -12478 -12479 -12480 -12481 -12482 -12483 -12484 -12485 -12486 -12487 +v -12488 -12489 12490 12491 12492 12493 -12494 -12495 -12496 -12497 -12498 +v -12499 -12500 -12501 -12502 -12503 -12504 -12505 -12506 -12507 -12508 -12509 +v -12510 -12511 -12512 -12513 -12514 -12515 -12516 -12517 -12518 -12519 -12520 +v -12521 -12522 -12523 -12524 -12525 -12526 -12527 -12528 -12529 -12530 -12531 +v -12532 -12533 -12534 -12535 -12536 -12537 -12538 -12539 -12540 -12541 -12542 +v -12543 -12544 12545 -12546 -12547 12548 -12549 -12550 -12551 12552 -12553 +v -12554 -12555 12556 -12557 -12558 -12559 -12560 -12561 -12562 -12563 -12564 +v -12565 -12566 -12567 12568 -12569 12570 12571 12572 12573 -12574 -12575 +v -12576 -12577 -12578 -12579 -12580 -12581 -12582 -12583 -12584 -12585 -12586 +v -12587 -12588 -12589 -12590 -12591 -12592 -12593 -12594 -12595 -12596 -12597 +v -12598 -12599 -12600 -12601 -12602 -12603 -12604 -12605 -12606 -12607 -12608 +v -12609 -12610 -12611 -12612 -12613 -12614 -12615 -12616 -12617 -12618 -12619 +v -12620 -12621 -12622 -12623 -12624 -12625 -12626 -12627 -12628 -12629 -12630 +v -12631 -12632 -12633 -12634 -12635 -12636 -12637 -12638 -12639 -12640 -12641 +v -12642 -12643 -12644 -12645 -12646 -12647 -12648 -12649 -12650 -12651 -12652 +v -12653 -12654 -12655 -12656 -12657 -12658 -12659 -12660 -12661 -12662 -12663 +v -12664 -12665 -12666 -12667 -12668 -12669 -12670 -12671 -12672 -12673 -12674 +v -12675 -12676 -12677 -12678 -12679 -12680 -12681 -12682 -12683 -12684 -12685 +v -12686 -12687 -12688 -12689 -12690 -12691 -12692 -12693 -12694 -12695 -12696 +v -12697 -12698 -12699 -12700 -12701 -12702 -12703 -12704 12705 -12706 -12707 +v -12708 -12709 -12710 -12711 -12712 -12713 -12714 -12715 -12716 -12717 -12718 +v -12719 -12720 -12721 -12722 -12723 -12724 -12725 -12726 -12727 -12728 -12729 +v -12730 -12731 -12732 -12733 -12734 -12735 -12736 -12737 -12738 -12739 -12740 +v -12741 -12742 -12743 -12744 -12745 -12746 -12747 -12748 -12749 -12750 -12751 +v -12752 12753 -12754 12755 -12756 -12757 -12758 12759 -12760 12761 -12762 +v -12763 -12764 12765 -12766 12767 -12768 -12769 -12770 12771 -12772 12773 +v -12774 -12775 12776 -12777 -12778 -12779 -12780 -12781 -12782 -12783 -12784 +v -12785 -12786 -12787 12788 12789 12790 12791 -12792 -12793 -12794 -12795 +v -12796 -12797 -12798 -12799 -12800 -12801 -12802 -12803 -12804 12805 -12806 +v -12807 12808 -12809 -12810 -12811 -12812 -12813 -12814 12815 12816 12817 +v -12818 -12819 -12820 -12821 -12822 -12823 -12824 -12825 -12826 -12827 -12828 +v -12829 -12830 -12831 -12832 -12833 -12834 -12835 -12836 -12837 -12838 -12839 +v -12840 -12841 -12842 -12843 -12844 -12845 -12846 -12847 -12848 -12849 -12850 +v -12851 -12852 -12853 -12854 -12855 -12856 -12857 -12858 -12859 -12860 -12861 +v -12862 -12863 -12864 -12865 -12866 -12867 -12868 -12869 -12870 -12871 -12872 +v -12873 -12874 -12875 -12876 -12877 -12878 -12879 -12880 -12881 -12882 -12883 +v 12884 -12885 -12886 -12887 -12888 -12889 -12890 -12891 -12892 -12893 12894 +v 12895 -12896 -12897 -12898 12899 -12900 -12901 -12902 -12903 -12904 -12905 +v -12906 -12907 -12908 -12909 -12910 -12911 -12912 -12913 -12914 -12915 -12916 +v -12917 -12918 -12919 -12920 -12921 -12922 -12923 -12924 -12925 -12926 -12927 +v -12928 -12929 -12930 -12931 -12932 -12933 12934 12935 12936 12937 -12938 +v -12939 -12940 -12941 -12942 -12943 -12944 -12945 -12946 -12947 -12948 -12949 +v -12950 -12951 -12952 -12953 -12954 -12955 -12956 -12957 -12958 -12959 12960 +v 12961 -12962 -12963 -12964 -12965 12966 -12967 -12968 -12969 -12970 -12971 +v -12972 -12973 -12974 12975 -12976 12977 -12978 -12979 -12980 12981 -12982 +v 12983 -12984 -12985 -12986 -12987 12988 -12989 12990 12991 12992 12993 12994 +v -12995 -12996 12997 -12998 -12999 13000 -13001 -13002 -13003 -13004 -13005 +v -13006 -13007 -13008 -13009 -13010 13011 13012 13013 13014 -13015 -13016 +v -13017 -13018 -13019 -13020 -13021 -13022 -13023 -13024 -13025 -13026 -13027 +v -13028 13029 -13030 -13031 13032 -13033 -13034 -13035 -13036 -13037 13038 +v 13039 -13040 -13041 -13042 -13043 13044 13045 -13046 -13047 -13048 -13049 +v 13050 -13051 -13052 -13053 -13054 -13055 -13056 -13057 -13058 13059 13060 +v 13061 -13062 13063 13064 -13065 13066 -13067 -13068 -13069 13070 -13071 +v -13072 -13073 -13074 -13075 -13076 -13077 -13078 -13079 -13080 -13081 -13082 +v -13083 -13084 -13085 -13086 -13087 -13088 -13089 -13090 -13091 -13092 -13093 +v -13094 -13095 -13096 -13097 -13098 -13099 -13100 -13101 -13102 -13103 -13104 +v -13105 -13106 -13107 -13108 -13109 -13110 -13111 -13112 -13113 -13114 -13115 +v -13116 -13117 -13118 -13119 -13120 -13121 -13122 13123 13124 -13125 13126 +v 13127 13128 -13129 13130 13131 -13132 -13133 13134 -13135 -13136 13137 +v -13138 -13139 -13140 -13141 -13142 -13143 -13144 -13145 -13146 -13147 -13148 +v -13149 -13150 -13151 -13152 -13153 -13154 -13155 13156 13157 13158 13159 +v 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169 13170 13171 +v -13172 -13173 -13174 -13175 -13176 -13177 -13178 -13179 -13180 -13181 -13182 +v -13183 -13184 -13185 -13186 -13187 -13188 -13189 -13190 -13191 -13192 -13193 +v -13194 -13195 -13196 -13197 -13198 -13199 -13200 -13201 -13202 -13203 -13204 +v -13205 -13206 -13207 -13208 -13209 -13210 -13211 -13212 -13213 -13214 -13215 +v -13216 -13217 -13218 -13219 -13220 -13221 13222 13223 -13224 13225 -13226 +v -13227 -13228 13229 -13230 -13231 -13232 -13233 -13234 -13235 -13236 -13237 +v -13238 -13239 -13240 -13241 13242 -13243 -13244 -13245 -13246 -13247 -13248 +v -13249 -13250 -13251 -13252 -13253 -13254 13255 13256 -13257 -13258 -13259 +v -13260 -13261 -13262 -13263 -13264 -13265 -13266 -13267 -13268 -13269 -13270 +v -13271 -13272 -13273 -13274 -13275 -13276 -13277 -13278 -13279 -13280 -13281 +v -13282 -13283 -13284 -13285 -13286 13287 -13288 -13289 -13290 -13291 -13292 +v -13293 -13294 -13295 -13296 13297 13298 13299 -13300 -13301 -13302 -13303 +v -13304 -13305 -13306 -13307 -13308 -13309 -13310 -13311 -13312 -13313 -13314 +v -13315 -13316 -13317 -13318 13319 13320 -13321 -13322 -13323 -13324 -13325 +v -13326 -13327 -13328 -13329 13330 -13331 -13332 -13333 -13334 -13335 -13336 +v -13337 -13338 -13339 13340 13341 13342 -13343 -13344 13345 13346 -13347 +v -13348 13349 -13350 -13351 -13352 -13353 -13354 -13355 -13356 -13357 -13358 +v -13359 -13360 -13361 -13362 -13363 -13364 -13365 -13366 -13367 -13368 -13369 +v -13370 -13371 13372 13373 -13374 13375 13376 13377 -13378 13379 -13380 +v -13381 13382 -13383 -13384 13385 -13386 -13387 -13388 -13389 -13390 -13391 +v -13392 -13393 -13394 13395 13396 13397 13398 13399 -13400 -13401 -13402 +v -13403 -13404 -13405 -13406 -13407 -13408 13409 13410 -13411 13412 13413 +v -13414 13415 -13416 -13417 13418 -13419 -13420 13421 -13422 -13423 -13424 +v -13425 -13426 -13427 -13428 13429 13430 13431 13432 13433 13434 13435 13436 +v 13437 13438 13439 -13440 -13441 -13442 -13443 -13444 -13445 -13446 -13447 +v -13448 -13449 -13450 -13451 -13452 -13453 -13454 -13455 -13456 13457 13458 +v -13459 -13460 -13461 -13462 -13463 13464 -13465 -13466 -13467 -13468 -13469 +v -13470 -13471 -13472 -13473 -13474 -13475 -13476 13477 -13478 -13479 -13480 +v -13481 13482 -13483 13484 -13485 -13486 13487 -13488 13489 -13490 -13491 +v 13492 -13493 13494 13495 13496 13497 -13498 -13499 13500 -13501 -13502 +v -13503 13504 -13505 13506 -13507 -13508 -13509 13510 -13511 13512 -13513 +v -13514 13515 -13516 -13517 -13518 -13519 -13520 -13521 -13522 -13523 -13524 +v -13525 -13526 -13527 -13528 13529 13530 13531 -13532 -13533 -13534 -13535 +v -13536 13537 13538 13539 -13540 -13541 -13542 -13543 -13544 -13545 -13546 +v -13547 -13548 -13549 13550 13551 -13552 -13553 13554 -13555 -13556 -13557 +v -13558 -13559 -13560 -13561 -13562 -13563 -13564 -13565 -13566 -13567 -13568 +v -13569 -13570 -13571 -13572 -13573 -13574 -13575 -13576 -13577 -13578 -13579 +v -13580 -13581 -13582 13583 13584 13585 -13586 -13587 -13588 -13589 -13590 +v -13591 -13592 -13593 13594 13595 -13596 -13597 -13598 13599 -13600 -13601 +v -13602 -13603 -13604 -13605 -13606 -13607 -13608 -13609 -13610 -13611 13612 +v 13613 -13614 -13615 -13616 -13617 -13618 -13619 -13620 13621 -13622 13623 +v -13624 -13625 -13626 13627 -13628 13629 -13630 -13631 -13632 13633 -13634 +v 13635 13636 13637 13638 -13639 -13640 13641 -13642 -13643 13644 -13645 +v -13646 -13647 -13648 -13649 -13650 -13651 -13652 -13653 -13654 13655 13656 +v 13657 13658 -13659 -13660 -13661 -13662 -13663 -13664 -13665 -13666 -13667 +v -13668 -13669 -13670 -13671 -13672 -13673 -13674 -13675 -13676 -13677 -13678 +v -13679 -13680 13681 -13682 -13683 -13684 -13685 -13686 -13687 -13688 -13689 +v -13690 13691 13692 -13693 -13694 -13695 13696 -13697 -13698 -13699 -13700 +v -13701 -13702 -13703 -13704 -13705 -13706 -13707 -13708 -13709 -13710 13711 +v -13712 13713 -13714 -13715 13716 -13717 13718 -13719 -13720 -13721 13722 +v -13723 13724 13725 13726 13727 -13728 -13729 13730 -13731 -13732 13733 +v -13734 -13735 -13736 -13737 -13738 -13739 -13740 -13741 -13742 -13743 13744 +v 13745 13746 13747 -13748 -13749 -13750 -13751 -13752 -13753 -13754 -13755 +v -13756 -13757 -13758 -13759 -13760 -13761 -13762 -13763 -13764 -13765 -13766 +v -13767 -13768 -13769 -13770 -13771 -13772 -13773 -13774 -13775 -13776 -13777 +v -13778 -13779 -13780 -13781 -13782 -13783 -13784 -13785 -13786 -13787 -13788 +v -13789 -13790 -13791 -13792 -13793 -13794 -13795 -13796 -13797 -13798 -13799 +v -13800 -13801 -13802 -13803 -13804 -13805 -13806 -13807 -13808 -13809 -13810 +v -13811 -13812 -13813 13814 -13815 -13816 -13817 -13818 -13819 -13820 -13821 +v -13822 -13823 13824 13825 -13826 -13827 -13828 13829 -13830 -13831 -13832 +v -13833 -13834 -13835 -13836 -13837 -13838 -13839 -13840 13841 13842 13843 +v -13844 -13845 -13846 -13847 -13848 -13849 -13850 -13851 13852 -13853 -13854 +v -13855 -13856 -13857 -13858 -13859 -13860 -13861 -13862 -13863 13864 -13865 +v -13866 -13867 -13868 -13869 -13870 -13871 -13872 13873 -13874 13875 13876 +v 13877 -13878 -13879 -13880 -13881 -13882 -13883 -13884 -13885 -13886 -13887 +v -13888 -13889 -13890 -13891 -13892 -13893 -13894 -13895 -13896 -13897 -13898 +v -13899 13900 13901 -13902 -13903 -13904 -13905 13906 -13907 -13908 -13909 +v -13910 -13911 -13912 -13913 -13914 -13915 13916 -13917 13918 -13919 -13920 +v -13921 13922 -13923 13924 -13925 -13926 -13927 13928 -13929 13930 13931 +v 13932 13933 -13934 -13935 13936 -13937 -13938 13939 -13940 -13941 -13942 +v -13943 -13944 -13945 -13946 -13947 -13948 -13949 13950 13951 13952 -13953 +v -13954 -13955 -13956 -13957 -13958 -13959 -13960 -13961 -13962 -13963 -13964 +v -13965 13966 -13967 -13968 13969 -13970 -13971 -13972 -13973 -13974 -13975 +v 13976 13977 13978 -13979 -13980 -13981 -13982 -13983 -13984 -13985 -13986 +v -13987 -13988 -13989 -13990 -13991 -13992 -13993 -13994 -13995 -13996 -13997 +v -13998 -13999 -14000 14001 -14002 -14003 -14004 -14005 -14006 -14007 -14008 +v 14009 -14010 14011 -14012 -14013 -14014 14015 -14016 14017 -14018 -14019 +v 14020 -14021 -14022 -14023 -14024 -14025 -14026 14027 14028 14029 -14030 +v -14031 -14032 -14033 -14034 -14035 -14036 -14037 -14038 -14039 -14040 -14041 +v -14042 -14043 -14044 -14045 -14046 -14047 -14048 -14049 -14050 -14051 14052 +v -14053 -14054 -14055 -14056 -14057 -14058 -14059 14060 -14061 14062 -14063 +v -14064 -14065 14066 -14067 14068 -14069 -14070 14071 -14072 -14073 -14074 +v -14075 -14076 -14077 14078 14079 14080 -14081 -14082 -14083 -14084 -14085 +v -14086 -14087 -14088 -14089 -14090 -14091 -14092 -14093 -14094 -14095 -14096 +v -14097 -14098 -14099 -14100 -14101 -14102 14103 -14104 -14105 -14106 -14107 +v -14108 -14109 -14110 14111 -14112 14113 -14114 -14115 -14116 14117 -14118 +v 14119 -14120 -14121 14122 -14123 -14124 -14125 -14126 -14127 -14128 14129 +v 14130 14131 -14132 -14133 -14134 -14135 -14136 -14137 -14138 -14139 -14140 +v -14141 -14142 -14143 -14144 -14145 -14146 -14147 -14148 -14149 -14150 -14151 +v -14152 -14153 -14154 -14155 -14156 -14157 -14158 -14159 -14160 -14161 -14162 +v -14163 -14164 -14165 -14166 -14167 -14168 -14169 -14170 -14171 -14172 -14173 +v -14174 -14175 -14176 -14177 -14178 -14179 -14180 -14181 -14182 -14183 -14184 +v -14185 -14186 -14187 -14188 -14189 -14190 -14191 -14192 -14193 -14194 -14195 +v -14196 -14197 -14198 -14199 -14200 -14201 -14202 -14203 -14204 -14205 -14206 +v -14207 -14208 -14209 -14210 -14211 -14212 -14213 -14214 -14215 -14216 -14217 +v -14218 -14219 -14220 -14221 -14222 -14223 -14224 -14225 -14226 -14227 -14228 +v -14229 14230 -14231 -14232 -14233 -14234 -14235 -14236 -14237 -14238 -14239 +v -14240 -14241 -14242 -14243 -14244 -14245 -14246 -14247 -14248 -14249 -14250 +v -14251 -14252 -14253 -14254 -14255 -14256 -14257 -14258 -14259 -14260 -14261 +v -14262 -14263 -14264 -14265 -14266 -14267 -14268 -14269 -14270 -14271 -14272 +v -14273 -14274 -14275 -14276 -14277 -14278 -14279 -14280 -14281 -14282 -14283 +v -14284 -14285 -14286 -14287 -14288 -14289 -14290 -14291 -14292 -14293 -14294 +v -14295 -14296 -14297 -14298 -14299 -14300 -14301 -14302 -14303 14304 -14305 +v 14306 -14307 -14308 -14309 14310 -14311 14312 -14313 -14314 -14315 -14316 +v 14317 -14318 14319 -14320 -14321 -14322 -14323 14324 -14325 14326 -14327 +v -14328 14329 -14330 -14331 -14332 -14333 -14334 -14335 -14336 -14337 -14338 +v -14339 14340 14341 14342 -14343 -14344 -14345 -14346 -14347 -14348 -14349 +v -14350 -14351 -14352 -14353 -14354 -14355 -14356 -14357 -14358 -14359 -14360 +v -14361 -14362 -14363 -14364 14365 -14366 -14367 -14368 -14369 -14370 -14371 +v -14372 14373 -14374 14375 -14376 -14377 -14378 14379 -14380 14381 -14382 +v -14383 14384 -14385 -14386 -14387 -14388 -14389 -14390 14391 14392 14393 +v -14394 -14395 -14396 -14397 -14398 -14399 -14400 -14401 -14402 -14403 -14404 +v -14405 -14406 -14407 -14408 -14409 -14410 -14411 -14412 -14413 -14414 -14415 +v -14416 -14417 -14418 -14419 -14420 -14421 -14422 -14423 -14424 -14425 -14426 +v -14427 -14428 -14429 -14430 -14431 -14432 -14433 -14434 -14435 -14436 -14437 +v 14438 14439 14440 -14441 -14442 -14443 -14444 -14445 -14446 -14447 -14448 +v -14449 -14450 -14451 -14452 -14453 14454 -14455 14456 -14457 -14458 -14459 +v 14460 -14461 -14462 -14463 -14464 -14465 -14466 -14467 -14468 -14469 -14470 +v 14471 -14472 -14473 -14474 -14475 -14476 -14477 -14478 -14479 -14480 -14481 +v -14482 -14483 -14484 -14485 -14486 -14487 -14488 -14489 -14490 -14491 -14492 +v -14493 -14494 -14495 -14496 -14497 14498 14499 14500 14501 -14502 -14503 +v -14504 -14505 -14506 -14507 -14508 -14509 -14510 -14511 -14512 -14513 -14514 +v -14515 -14516 -14517 -14518 -14519 -14520 -14521 -14522 -14523 14524 14525 +v -14526 -14527 -14528 -14529 14530 -14531 -14532 -14533 -14534 -14535 -14536 +v -14537 -14538 -14539 14540 -14541 14542 -14543 -14544 -14545 -14546 14547 +v -14548 14549 -14550 -14551 -14552 -14553 14554 -14555 14556 14557 14558 +v 14559 14560 -14561 -14562 14563 -14564 -14565 14566 -14567 -14568 -14569 +v -14570 -14571 -14572 -14573 -14574 -14575 -14576 14577 14578 14579 -14580 +v -14581 -14582 -14583 -14584 -14585 -14586 -14587 -14588 -14589 -14590 -14591 +v -14592 -14593 -14594 -14595 -14596 -14597 -14598 -14599 -14600 -14601 -14602 +v -14603 -14604 -14605 -14606 -14607 -14608 14609 -14610 14611 -14612 -14613 +v -14614 14615 -14616 14617 -14618 -14619 14620 -14621 -14622 -14623 -14624 +v -14625 -14626 14627 14628 14629 14630 -14631 -14632 -14633 -14634 -14635 +v -14636 -14637 -14638 -14639 -14640 -14641 -14642 -14643 -14644 -14645 -14646 +v -14647 -14648 -14649 -14650 -14651 -14652 -14653 -14654 -14655 -14656 -14657 +v -14658 -14659 14660 -14661 14662 -14663 -14664 -14665 14666 -14667 14668 +v -14669 -14670 14671 -14672 -14673 -14674 -14675 -14676 -14677 14678 14679 +v 14680 14681 -14682 -14683 -14684 -14685 -14686 -14687 -14688 -14689 -14690 +v -14691 -14692 -14693 -14694 -14695 -14696 -14697 -14698 -14699 -14700 -14701 +v -14702 -14703 -14704 -14705 -14706 -14707 -14708 -14709 -14710 14711 -14712 +v 14713 -14714 -14715 -14716 14717 -14718 14719 -14720 -14721 14722 -14723 +v -14724 -14725 -14726 -14727 -14728 14729 14730 14731 14732 -14733 -14734 +v -14735 -14736 -14737 -14738 -14739 -14740 -14741 -14742 -14743 -14744 -14745 +v -14746 -14747 -14748 -14749 -14750 -14751 -14752 -14753 -14754 -14755 -14756 +v -14757 -14758 -14759 -14760 -14761 -14762 -14763 -14764 -14765 -14766 -14767 +v -14768 -14769 -14770 -14771 -14772 -14773 -14774 -14775 -14776 -14777 -14778 +v -14779 -14780 -14781 -14782 -14783 -14784 -14785 -14786 -14787 -14788 -14789 +v -14790 -14791 -14792 -14793 -14794 -14795 -14796 -14797 -14798 -14799 -14800 +v -14801 -14802 -14803 -14804 -14805 -14806 -14807 -14808 -14809 -14810 -14811 +v -14812 -14813 -14814 -14815 -14816 -14817 -14818 -14819 -14820 -14821 -14822 +v -14823 -14824 -14825 -14826 -14827 -14828 -14829 -14830 -14831 -14832 -14833 +v -14834 -14835 -14836 -14837 -14838 -14839 -14840 -14841 -14842 -14843 -14844 +v -14845 -14846 -14847 -14848 -14849 -14850 -14851 -14852 -14853 -14854 -14855 +v -14856 -14857 -14858 -14859 -14860 -14861 -14862 -14863 -14864 -14865 -14866 +v -14867 -14868 -14869 -14870 -14871 -14872 -14873 -14874 -14875 -14876 -14877 +v -14878 -14879 -14880 -14881 -14882 -14883 -14884 -14885 -14886 -14887 -14888 +v -14889 -14890 -14891 -14892 -14893 -14894 -14895 -14896 -14897 -14898 -14899 +v -14900 -14901 -14902 -14903 14904 -14905 14906 -14907 -14908 -14909 14910 +v -14911 14912 -14913 -14914 -14915 -14916 14917 -14918 14919 -14920 -14921 +v -14922 -14923 14924 -14925 14926 -14927 -14928 14929 -14930 -14931 -14932 +v -14933 -14934 -14935 -14936 -14937 -14938 -14939 14940 14941 14942 14943 +v -14944 -14945 -14946 -14947 -14948 -14949 -14950 -14951 -14952 -14953 -14954 +v -14955 -14956 -14957 -14958 -14959 -14960 -14961 -14962 -14963 -14964 -14965 +v -14966 -14967 -14968 -14969 -14970 -14971 -14972 14973 -14974 14975 -14976 +v -14977 -14978 14979 -14980 14981 -14982 -14983 14984 -14985 -14986 -14987 +v -14988 -14989 -14990 14991 14992 14993 14994 -14995 14996 -14997 14998 +v -14999 15000 15001 -15002 -15003 -15004 -15005 -15006 -15007 -15008 -15009 +v -15010 -15011 -15012 -15013 -15014 -15015 -15016 -15017 -15018 -15019 -15020 +v -15021 -15022 -15023 -15024 -15025 -15026 -15027 -15028 -15029 -15030 -15031 +v -15032 -15033 -15034 -15035 -15036 -15037 -15038 -15039 -15040 -15041 -15042 +v -15043 -15044 -15045 -15046 -15047 -15048 -15049 -15050 -15051 -15052 -15053 +v -15054 -15055 -15056 -15057 -15058 -15059 -15060 -15061 -15062 -15063 -15064 +v -15065 -15066 -15067 -15068 -15069 -15070 -15071 -15072 -15073 -15074 -15075 +v -15076 -15077 -15078 -15079 -15080 -15081 -15082 -15083 -15084 -15085 -15086 +v -15087 -15088 -15089 -15090 -15091 -15092 -15093 -15094 -15095 -15096 -15097 +v -15098 -15099 -15100 -15101 -15102 -15103 -15104 -15105 -15106 -15107 -15108 +v -15109 -15110 -15111 -15112 -15113 -15114 -15115 -15116 -15117 -15118 -15119 +v -15120 -15121 -15122 -15123 -15124 -15125 -15126 -15127 -15128 -15129 -15130 +v -15131 -15132 -15133 -15134 -15135 -15136 -15137 -15138 -15139 -15140 -15141 +v -15142 -15143 -15144 -15145 -15146 -15147 -15148 -15149 -15150 -15151 -15152 +v -15153 -15154 -15155 -15156 -15157 -15158 -15159 -15160 -15161 -15162 -15163 +v -15164 -15165 -15166 -15167 -15168 -15169 -15170 -15171 -15172 -15173 -15174 +v -15175 -15176 -15177 -15178 -15179 -15180 -15181 -15182 -15183 -15184 -15185 +v -15186 -15187 -15188 -15189 -15190 -15191 -15192 -15193 -15194 -15195 -15196 +v -15197 -15198 -15199 -15200 -15201 -15202 -15203 -15204 -15205 -15206 -15207 +v -15208 -15209 -15210 -15211 -15212 -15213 -15214 -15215 -15216 -15217 -15218 +v -15219 -15220 -15221 -15222 -15223 -15224 -15225 -15226 -15227 -15228 -15229 +v -15230 -15231 -15232 -15233 -15234 -15235 -15236 -15237 -15238 -15239 -15240 +v -15241 -15242 -15243 -15244 -15245 -15246 -15247 -15248 -15249 -15250 -15251 +v -15252 -15253 -15254 -15255 -15256 -15257 -15258 -15259 -15260 -15261 -15262 +v -15263 -15264 -15265 -15266 -15267 -15268 -15269 -15270 -15271 -15272 -15273 +v -15274 -15275 -15276 -15277 -15278 -15279 -15280 -15281 -15282 -15283 -15284 +v -15285 -15286 -15287 -15288 -15289 -15290 -15291 -15292 -15293 -15294 -15295 +v -15296 -15297 -15298 -15299 -15300 -15301 -15302 -15303 -15304 -15305 -15306 +v -15307 -15308 -15309 -15310 -15311 -15312 -15313 -15314 -15315 -15316 -15317 +v -15318 -15319 -15320 -15321 -15322 -15323 -15324 -15325 -15326 -15327 -15328 +v -15329 -15330 -15331 -15332 -15333 -15334 -15335 -15336 -15337 -15338 -15339 +v -15340 -15341 -15342 -15343 -15344 -15345 -15346 -15347 -15348 -15349 -15350 +v -15351 -15352 -15353 -15354 -15355 -15356 -15357 -15358 -15359 -15360 -15361 +v -15362 -15363 -15364 -15365 -15366 -15367 -15368 -15369 -15370 -15371 -15372 +v -15373 -15374 -15375 -15376 -15377 -15378 -15379 -15380 -15381 -15382 -15383 +v -15384 15385 -15386 15387 -15388 -15389 -15390 15391 -15392 15393 -15394 +v -15395 -15396 -15397 15398 -15399 15400 -15401 -15402 -15403 -15404 15405 +v -15406 15407 -15408 -15409 -15410 -15411 15412 -15413 15414 -15415 -15416 +v 15417 -15418 15419 -15420 -15421 -15422 -15423 -15424 -15425 -15426 -15427 +v -15428 -15429 -15430 -15431 -15432 -15433 15434 15435 15436 15437 15438 +v -15439 -15440 -15441 -15442 -15443 -15444 15445 -15446 -15447 -15448 -15449 +v -15450 -15451 -15452 -15453 -15454 -15455 -15456 -15457 -15458 -15459 -15460 +v -15461 -15462 -15463 -15464 -15465 -15466 -15467 -15468 -15469 -15470 -15471 +v -15472 -15473 -15474 -15475 -15476 -15477 -15478 -15479 -15480 -15481 -15482 +v -15483 -15484 -15485 -15486 -15487 -15488 -15489 -15490 -15491 -15492 -15493 +v -15494 -15495 -15496 -15497 -15498 -15499 -15500 -15501 -15502 -15503 -15504 +v -15505 -15506 -15507 -15508 -15509 -15510 -15511 -15512 -15513 -15514 -15515 +v -15516 -15517 -15518 -15519 -15520 -15521 -15522 -15523 -15524 -15525 -15526 +v -15527 -15528 -15529 -15530 -15531 -15532 -15533 -15534 -15535 -15536 -15537 +v -15538 -15539 -15540 -15541 -15542 -15543 -15544 -15545 -15546 -15547 -15548 +v -15549 -15550 -15551 -15552 -15553 -15554 -15555 -15556 -15557 -15558 -15559 +v -15560 -15561 -15562 -15563 -15564 -15565 15566 -15567 15568 -15569 -15570 +v -15571 -15572 15573 -15574 15575 -15576 -15577 -15578 -15579 15580 -15581 +v 15582 -15583 -15584 -15585 -15586 15587 -15588 15589 -15590 -15591 15592 +v -15593 15594 -15595 -15596 15597 -15598 -15599 -15600 -15601 -15602 -15603 +v -15604 -15605 -15606 -15607 -15608 -15609 15610 15611 15612 15613 -15614 +v -15615 -15616 -15617 -15618 -15619 -15620 -15621 -15622 -15623 -15624 -15625 +v -15626 -15627 -15628 -15629 -15630 -15631 -15632 -15633 -15634 -15635 -15636 +v -15637 -15638 -15639 -15640 -15641 -15642 -15643 -15644 -15645 -15646 -15647 +v -15648 -15649 -15650 -15651 -15652 -15653 -15654 -15655 -15656 -15657 -15658 +v -15659 -15660 -15661 -15662 -15663 -15664 15665 -15666 -15667 15668 -15669 +v -15670 -15671 15672 -15673 -15674 -15675 15676 -15677 -15678 -15679 -15680 +v -15681 -15682 -15683 -15684 -15685 -15686 -15687 15688 -15689 15690 15691 +v 15692 15693 -15694 -15695 -15696 -15697 -15698 -15699 -15700 -15701 -15702 +v -15703 -15704 -15705 -15706 -15707 -15708 -15709 -15710 -15711 -15712 -15713 +v -15714 -15715 -15716 -15717 -15718 -15719 -15720 -15721 -15722 -15723 -15724 +v -15725 -15726 -15727 -15728 -15729 -15730 -15731 -15732 -15733 -15734 -15735 +v -15736 -15737 -15738 -15739 -15740 -15741 -15742 -15743 -15744 -15745 -15746 +v -15747 -15748 -15749 -15750 -15751 -15752 -15753 -15754 -15755 -15756 -15757 +v -15758 -15759 -15760 -15761 -15762 -15763 -15764 -15765 -15766 -15767 -15768 +v -15769 -15770 -15771 -15772 -15773 -15774 -15775 -15776 -15777 -15778 -15779 +v -15780 -15781 -15782 -15783 -15784 -15785 -15786 -15787 -15788 -15789 -15790 +v -15791 -15792 -15793 -15794 -15795 -15796 -15797 -15798 -15799 -15800 -15801 +v -15802 -15803 -15804 -15805 -15806 -15807 -15808 -15809 -15810 -15811 -15812 +v -15813 -15814 -15815 -15816 -15817 -15818 -15819 -15820 -15821 -15822 -15823 +v -15824 -15825 -15826 -15827 -15828 -15829 -15830 -15831 -15832 -15833 -15834 +v -15835 -15836 -15837 -15838 -15839 -15840 -15841 -15842 -15843 -15844 -15845 +v -15846 -15847 -15848 -15849 -15850 -15851 -15852 -15853 -15854 -15855 -15856 +v -15857 -15858 15859 -15860 15861 -15862 -15863 15864 -15865 15866 -15867 +v -15868 15869 -15870 15871 -15872 -15873 -15874 15875 -15876 15877 -15878 +v -15879 -15880 15881 -15882 15883 -15884 -15885 15886 -15887 -15888 -15889 +v -15890 -15891 -15892 -15893 -15894 -15895 -15896 -15897 -15898 15899 15900 +v 15901 15902 -15903 -15904 -15905 -15906 -15907 -15908 -15909 -15910 -15911 +v -15912 -15913 -15914 -15915 15916 -15917 -15918 15919 -15920 -15921 -15922 +v -15923 -15924 -15925 15926 15927 15928 -15929 -15930 -15931 -15932 -15933 +v -15934 -15935 -15936 -15937 -15938 -15939 -15940 -15941 -15942 -15943 -15944 +v -15945 -15946 -15947 -15948 -15949 -15950 -15951 -15952 -15953 -15954 -15955 +v -15956 -15957 -15958 -15959 -15960 -15961 -15962 -15963 -15964 -15965 -15966 +v -15967 -15968 -15969 -15970 -15971 -15972 -15973 -15974 -15975 -15976 -15977 +v -15978 -15979 -15980 -15981 -15982 -15983 -15984 -15985 -15986 -15987 -15988 +v -15989 -15990 -15991 -15992 -15993 -15994 15995 -15996 -15997 -15998 -15999 +v -16000 -16001 -16002 -16003 -16004 16005 16006 -16007 -16008 -16009 16010 +v -16011 -16012 -16013 -16014 -16015 -16016 -16017 -16018 -16019 -16020 -16021 +v -16022 -16023 -16024 -16025 -16026 -16027 -16028 -16029 -16030 -16031 -16032 +v -16033 -16034 -16035 -16036 -16037 -16038 -16039 -16040 -16041 -16042 -16043 +v -16044 16045 16046 16047 16048 -16049 -16050 -16051 -16052 -16053 -16054 +v -16055 -16056 -16057 -16058 -16059 -16060 -16061 -16062 -16063 -16064 -16065 +v -16066 -16067 -16068 -16069 -16070 16071 16072 -16073 -16074 -16075 -16076 +v 16077 -16078 -16079 -16080 -16081 -16082 -16083 -16084 -16085 16086 -16087 +v 16088 -16089 -16090 -16091 16092 -16093 16094 -16095 -16096 -16097 -16098 +v 16099 -16100 16101 16102 16103 16104 16105 -16106 -16107 16108 -16109 -16110 +v 16111 -16112 -16113 -16114 -16115 -16116 -16117 -16118 -16119 -16120 -16121 +v 16122 16123 16124 16125 -16126 -16127 -16128 -16129 -16130 -16131 -16132 +v -16133 -16134 -16135 -16136 -16137 -16138 -16139 16140 -16141 -16142 16143 +v -16144 -16145 -16146 -16147 -16148 16149 16150 -16151 -16152 -16153 -16154 +v 16155 16156 -16157 -16158 -16159 -16160 16161 -16162 -16163 -16164 -16165 +v -16166 -16167 -16168 -16169 16170 16171 16172 -16173 16174 16175 -16176 +v 16177 -16178 -16179 -16180 16181 -16182 -16183 -16184 -16185 -16186 -16187 +v -16188 -16189 -16190 -16191 -16192 -16193 -16194 -16195 -16196 -16197 -16198 +v -16199 -16200 -16201 -16202 -16203 -16204 -16205 -16206 -16207 -16208 -16209 +v -16210 -16211 -16212 -16213 -16214 -16215 -16216 -16217 -16218 -16219 -16220 +v -16221 -16222 -16223 -16224 -16225 -16226 -16227 -16228 -16229 -16230 -16231 +v -16232 -16233 16234 16235 -16236 16237 16238 16239 -16240 16241 16242 -16243 +v -16244 16245 -16246 -16247 16248 -16249 -16250 -16251 -16252 -16253 -16254 +v -16255 -16256 -16257 -16258 -16259 -16260 -16261 -16262 -16263 -16264 -16265 +v -16266 16267 16268 16269 16270 16271 16272 16273 16274 16275 16276 16277 +v 16278 16279 16280 16281 16282 -16283 -16284 -16285 -16286 -16287 -16288 +v -16289 -16290 -16291 -16292 -16293 -16294 -16295 -16296 -16297 -16298 -16299 +v -16300 -16301 -16302 -16303 -16304 -16305 -16306 -16307 -16308 -16309 -16310 +v -16311 -16312 -16313 -16314 -16315 -16316 -16317 -16318 -16319 -16320 -16321 +v -16322 -16323 -16324 -16325 -16326 -16327 -16328 -16329 -16330 -16331 -16332 +v 16333 16334 -16335 16336 -16337 -16338 -16339 16340 -16341 -16342 -16343 +v -16344 -16345 -16346 -16347 -16348 -16349 -16350 -16351 -16352 16353 -16354 +v -16355 -16356 -16357 -16358 -16359 -16360 -16361 -16362 -16363 -16364 -16365 +v -16366 -16367 -16368 -16369 -16370 -16371 -16372 -16373 -16374 -16375 -16376 +v -16377 -16378 16379 -16380 -16381 -16382 -16383 -16384 -16385 -16386 -16387 +v -16388 16389 16390 16391 -16392 -16393 -16394 -16395 -16396 -16397 -16398 +v -16399 -16400 -16401 -16402 -16403 -16404 -16405 -16406 -16407 -16408 -16409 +v -16410 16411 16412 -16413 -16414 -16415 -16416 -16417 -16418 -16419 -16420 +v -16421 16422 -16423 -16424 -16425 -16426 -16427 -16428 -16429 -16430 -16431 +v 16432 16433 -16434 -16435 16436 -16437 -16438 16439 -16440 -16441 -16442 +v -16443 -16444 -16445 -16446 -16447 -16448 -16449 -16450 -16451 -16452 -16453 +v -16454 -16455 -16456 -16457 -16458 -16459 -16460 -16461 16462 16463 -16464 +v 16465 16466 16467 -16468 16469 -16470 -16471 16472 -16473 -16474 16475 +v -16476 -16477 -16478 -16479 -16480 -16481 -16482 -16483 -16484 16485 16486 +v 16487 16488 16489 -16490 -16491 -16492 -16493 -16494 -16495 -16496 -16497 +v -16498 16499 16500 -16501 16502 16503 -16504 16505 -16506 -16507 16508 +v -16509 -16510 16511 -16512 -16513 -16514 -16515 -16516 -16517 -16518 16519 +v 16520 16521 16522 16523 16524 16525 16526 16527 16528 16529 -16530 -16531 +v -16532 -16533 -16534 -16535 -16536 -16537 -16538 -16539 -16540 -16541 -16542 +v -16543 -16544 -16545 -16546 16547 16548 -16549 -16550 -16551 -16552 -16553 +v 16554 -16555 -16556 -16557 -16558 -16559 -16560 -16561 -16562 -16563 -16564 +v -16565 -16566 16567 -16568 -16569 -16570 -16571 16572 -16573 16574 -16575 +v -16576 -16577 16578 -16579 16580 -16581 -16582 -16583 16584 -16585 16586 +v 16587 16588 16589 16590 -16591 -16592 16593 -16594 -16595 -16596 -16597 +v 16598 -16599 16600 -16601 -16602 -16603 -16604 16605 -16606 16607 -16608 +v -16609 16610 -16611 -16612 -16613 -16614 -16615 -16616 -16617 -16618 -16619 +v -16620 -16621 -16622 -16623 16624 16625 16626 -16627 -16628 -16629 -16630 +v -16631 16632 16633 16634 -16635 -16636 -16637 -16638 -16639 -16640 -16641 +v -16642 -16643 -16644 16645 16646 -16647 -16648 16649 -16650 -16651 -16652 +v -16653 -16654 -16655 -16656 -16657 -16658 -16659 -16660 -16661 -16662 -16663 +v -16664 -16665 -16666 -16667 -16668 -16669 -16670 -16671 -16672 -16673 -16674 +v -16675 -16676 -16677 16678 16679 16680 -16681 -16682 -16683 -16684 -16685 +v -16686 -16687 -16688 16689 16690 -16691 -16692 -16693 16694 -16695 -16696 +v -16697 -16698 -16699 -16700 -16701 -16702 -16703 -16704 -16705 -16706 16707 +v 16708 -16709 -16710 -16711 -16712 -16713 -16714 -16715 16716 -16717 16718 +v -16719 -16720 -16721 16722 -16723 16724 -16725 -16726 -16727 16728 -16729 +v 16730 16731 16732 16733 -16734 -16735 16736 -16737 -16738 16739 -16740 +v -16741 -16742 -16743 -16744 -16745 -16746 -16747 -16748 -16749 16750 16751 +v 16752 16753 -16754 -16755 -16756 -16757 -16758 -16759 -16760 -16761 -16762 +v -16763 -16764 -16765 -16766 -16767 -16768 -16769 -16770 -16771 -16772 -16773 +v -16774 -16775 16776 -16777 -16778 -16779 -16780 -16781 -16782 -16783 -16784 +v -16785 16786 16787 -16788 -16789 -16790 16791 -16792 -16793 -16794 -16795 +v -16796 -16797 -16798 -16799 -16800 -16801 -16802 -16803 -16804 -16805 16806 +v -16807 16808 -16809 -16810 16811 -16812 16813 -16814 -16815 -16816 16817 +v -16818 16819 16820 16821 16822 -16823 -16824 16825 -16826 -16827 16828 +v -16829 -16830 -16831 -16832 -16833 -16834 -16835 -16836 -16837 -16838 16839 +v 16840 16841 16842 -16843 -16844 -16845 -16846 -16847 -16848 -16849 -16850 +v -16851 -16852 -16853 -16854 -16855 -16856 -16857 -16858 -16859 -16860 -16861 +v -16862 -16863 -16864 -16865 -16866 -16867 -16868 -16869 -16870 -16871 -16872 +v -16873 -16874 -16875 -16876 -16877 -16878 -16879 -16880 -16881 -16882 -16883 +v -16884 -16885 -16886 -16887 -16888 -16889 -16890 -16891 -16892 -16893 -16894 +v -16895 -16896 -16897 -16898 -16899 -16900 -16901 -16902 -16903 -16904 -16905 +v -16906 -16907 -16908 16909 -16910 -16911 -16912 -16913 -16914 -16915 -16916 +v -16917 -16918 16919 16920 -16921 -16922 -16923 16924 -16925 -16926 -16927 +v -16928 -16929 -16930 -16931 -16932 16933 16934 16935 -16936 -16937 -16938 +v -16939 -16940 -16941 -16942 -16943 -16944 -16945 -16946 -16947 -16948 -16949 +v -16950 -16951 -16952 -16953 -16954 -16955 -16956 -16957 16958 16959 -16960 +v -16961 -16962 -16963 16964 -16965 -16966 -16967 -16968 -16969 -16970 -16971 +v -16972 -16973 -16974 -16975 -16976 -16977 16978 16979 16980 -16981 -16982 +v -16983 -16984 -16985 -16986 -16987 16988 -16989 -16990 -16991 -16992 -16993 +v -16994 -16995 -16996 -16997 -16998 -16999 17000 -17001 -17002 -17003 -17004 +v -17005 -17006 -17007 -17008 17009 -17010 17011 -17012 -17013 17014 -17015 +v 17016 -17017 -17018 17019 -17020 17021 -17022 -17023 -17024 17025 -17026 +v 17027 17028 17029 17030 -17031 -17032 17033 -17034 -17035 17036 -17037 +v -17038 -17039 -17040 -17041 -17042 -17043 -17044 -17045 -17046 -17047 17048 +v 17049 17050 -17051 -17052 -17053 -17054 -17055 -17056 -17057 -17058 -17059 +v -17060 -17061 -17062 -17063 17064 -17065 -17066 17067 -17068 -17069 -17070 +v -17071 -17072 -17073 17074 17075 17076 -17077 -17078 -17079 -17080 -17081 +v -17082 -17083 -17084 -17085 -17086 -17087 -17088 -17089 -17090 -17091 -17092 +v -17093 -17094 -17095 -17096 -17097 -17098 17099 -17100 -17101 -17102 -17103 +v -17104 -17105 -17106 17107 -17108 17109 -17110 -17111 -17112 17113 -17114 +v 17115 -17116 -17117 17118 -17119 -17120 -17121 -17122 -17123 -17124 17125 +v 17126 17127 -17128 -17129 -17130 -17131 -17132 -17133 -17134 -17135 -17136 +v -17137 -17138 -17139 -17140 -17141 -17142 -17143 -17144 -17145 -17146 -17147 +v -17148 -17149 17150 -17151 -17152 -17153 -17154 -17155 -17156 -17157 17158 +v -17159 17160 -17161 -17162 -17163 17164 -17165 17166 -17167 -17168 17169 +v -17170 -17171 -17172 -17173 -17174 -17175 17176 17177 17178 -17179 -17180 +v -17181 -17182 -17183 -17184 -17185 -17186 -17187 -17188 -17189 -17190 -17191 +v -17192 -17193 -17194 -17195 -17196 -17197 -17198 -17199 -17200 17201 -17202 +v -17203 -17204 -17205 -17206 -17207 -17208 17209 -17210 17211 -17212 -17213 +v -17214 17215 -17216 17217 -17218 -17219 17220 -17221 -17222 -17223 -17224 +v -17225 -17226 17227 17228 17229 -17230 -17231 -17232 -17233 -17234 -17235 +v -17236 -17237 -17238 -17239 -17240 -17241 -17242 -17243 -17244 -17245 -17246 +v -17247 -17248 -17249 -17250 -17251 -17252 -17253 -17254 -17255 -17256 -17257 +v -17258 -17259 -17260 -17261 -17262 -17263 -17264 -17265 -17266 -17267 -17268 +v -17269 -17270 -17271 -17272 -17273 -17274 -17275 -17276 -17277 -17278 -17279 +v -17280 -17281 -17282 -17283 -17284 -17285 -17286 -17287 -17288 -17289 -17290 +v -17291 -17292 -17293 -17294 -17295 -17296 -17297 -17298 -17299 -17300 -17301 +v -17302 -17303 -17304 -17305 -17306 -17307 -17308 -17309 -17310 -17311 -17312 +v -17313 -17314 -17315 -17316 -17317 -17318 -17319 -17320 -17321 -17322 -17323 +v -17324 -17325 -17326 -17327 17328 -17329 -17330 -17331 -17332 -17333 -17334 +v -17335 -17336 -17337 -17338 -17339 -17340 -17341 -17342 -17343 -17344 -17345 +v -17346 -17347 -17348 -17349 -17350 -17351 -17352 -17353 -17354 -17355 -17356 +v -17357 -17358 -17359 -17360 -17361 -17362 -17363 -17364 -17365 -17366 -17367 +v -17368 -17369 -17370 -17371 -17372 -17373 -17374 -17375 -17376 -17377 -17378 +v -17379 -17380 -17381 -17382 -17383 -17384 -17385 -17386 -17387 -17388 -17389 +v -17390 -17391 -17392 -17393 -17394 -17395 -17396 -17397 -17398 -17399 -17400 +v -17401 17402 -17403 17404 -17405 -17406 -17407 17408 -17409 17410 -17411 +v -17412 -17413 -17414 17415 -17416 17417 -17418 -17419 -17420 -17421 17422 +v -17423 17424 -17425 -17426 17427 -17428 -17429 -17430 -17431 -17432 -17433 +v -17434 -17435 -17436 -17437 17438 17439 17440 -17441 -17442 -17443 -17444 +v -17445 -17446 -17447 -17448 -17449 -17450 -17451 -17452 -17453 -17454 -17455 +v -17456 -17457 -17458 -17459 -17460 -17461 -17462 17463 -17464 -17465 -17466 +v -17467 -17468 -17469 -17470 17471 -17472 17473 -17474 -17475 -17476 17477 +v -17478 17479 -17480 -17481 17482 -17483 -17484 -17485 -17486 -17487 -17488 +v 17489 17490 17491 -17492 -17493 -17494 -17495 -17496 -17497 -17498 -17499 +v -17500 -17501 -17502 -17503 -17504 -17505 -17506 -17507 -17508 -17509 -17510 +v -17511 -17512 -17513 -17514 -17515 -17516 -17517 -17518 -17519 -17520 -17521 +v -17522 -17523 -17524 -17525 -17526 -17527 -17528 -17529 -17530 -17531 -17532 +v -17533 -17534 -17535 17536 17537 17538 -17539 -17540 -17541 -17542 -17543 +v -17544 -17545 -17546 -17547 -17548 -17549 -17550 -17551 17552 -17553 17554 +v -17555 -17556 -17557 17558 -17559 -17560 -17561 -17562 -17563 -17564 -17565 +v -17566 -17567 -17568 17569 -17570 -17571 -17572 -17573 -17574 -17575 -17576 +v -17577 -17578 -17579 -17580 -17581 -17582 -17583 -17584 -17585 -17586 -17587 +v -17588 -17589 -17590 -17591 -17592 -17593 -17594 -17595 17596 17597 17598 +v 17599 -17600 -17601 -17602 -17603 -17604 -17605 -17606 -17607 -17608 -17609 +v -17610 -17611 -17612 -17613 -17614 -17615 -17616 -17617 -17618 -17619 -17620 +v -17621 17622 17623 -17624 -17625 -17626 -17627 17628 -17629 -17630 -17631 +v -17632 -17633 -17634 -17635 -17636 -17637 17638 -17639 17640 -17641 -17642 +v -17643 -17644 17645 -17646 17647 -17648 -17649 -17650 -17651 17652 -17653 +v 17654 17655 17656 17657 17658 -17659 -17660 17661 -17662 -17663 17664 -17665 +v -17666 -17667 -17668 -17669 -17670 -17671 -17672 -17673 -17674 17675 17676 +v 17677 17678 17679 17680 17681 17682 17683 17684 17685 -17686 -17687 -17688 +v -17689 17690 -17691 -17692 17693 -17694 -17695 17696 -17697 17698 -17699 +v -17700 17701 -17702 -17703 -17704 -17705 -17706 17707 17708 17709 17710 +v -17711 -17712 17713 -17714 -17715 17716 17717 17718 17719 -17720 -17721 +v -17722 -17723 -17724 -17725 -17726 -17727 -17728 -17729 -17730 -17731 -17732 +v -17733 -17734 -17735 -17736 -17737 17738 -17739 17740 -17741 -17742 -17743 +v 17744 -17745 17746 -17747 -17748 17749 -17750 -17751 -17752 -17753 -17754 +v -17755 17756 17757 17758 17759 -17760 -17761 -17762 -17763 -17764 -17765 +v -17766 -17767 -17768 -17769 -17770 -17771 -17772 -17773 -17774 -17775 17776 +v -17777 17778 -17779 -17780 -17781 17782 -17783 17784 -17785 -17786 17787 +v -17788 -17789 -17790 -17791 -17792 -17793 17794 17795 17796 17797 -17798 +v -17799 -17800 -17801 -17802 -17803 -17804 -17805 -17806 -17807 -17808 -17809 +v -17810 -17811 -17812 -17813 17814 -17815 17816 -17817 -17818 -17819 17820 +v -17821 17822 -17823 -17824 17825 -17826 -17827 -17828 -17829 -17830 -17831 +v 17832 17833 17834 17835 -17836 -17837 -17838 -17839 17840 17841 17842 17843 +v -17844 -17845 -17846 -17847 -17848 -17849 -17850 -17851 -17852 -17853 -17854 +v -17855 -17856 -17857 -17858 -17859 -17860 -17861 -17862 -17863 -17864 -17865 +v -17866 -17867 -17868 -17869 -17870 -17871 -17872 -17873 -17874 -17875 -17876 +v -17877 -17878 -17879 -17880 -17881 -17882 -17883 17884 -17885 17886 -17887 +v -17888 -17889 17890 -17891 17892 -17893 -17894 17895 -17896 -17897 -17898 +v -17899 -17900 -17901 17902 17903 17904 17905 17906 17907 -17908 -17909 +v -17910 -17911 -17912 -17913 -17914 -17915 -17916 -17917 17918 -17919 -17920 +v -17921 -17922 17923 17924 17925 17926 -17927 -17928 17929 -17930 17931 +v -17932 17933 -17934 -17935 -17936 17937 17938 17939 17940 17941 -17942 +v -17943 17944 17945 -17946 -17947 17948 17949 -17950 -17951 -17952 -17953 +v -17954 17955 17956 17957 17958 -17959 -17960 17961 17962 -17963 17964 -17965 +v 17966 -17967 -17968 -17969 -17970 -17971 -17972 17973 17974 -17975 17976 +v -17977 17978 -17979 -17980 -17981 -17982 -17983 -17984 17985 17986 -17987 +v 17988 -17989 17990 -17991 -17992 -17993 -17994 -17995 -17996 17997 17998 +v -17999 -18000 18001 18002 -18003 -18004 18005 -18006 -18007 18008 -18009 +v 18010 -18011 18012 -18013 -18014 -18015 18016 18017 18018 18019 18020 18021 +v 18022 18023 18024 18025 -18026 18027 -18028 -18029 18030 -18031 -18032 +v -18033 -18034 -18035 -18036 -18037 18038 18039 18040 18041 18042 18043 18044 +v -18045 -18046 18047 -18048 18049 -18050 -18051 -18052 -18053 -18054 18055 +v -18056 18057 18058 18059 -18060 -18061 18062 18063 18064 18065 -18066 -18067 +v 18068 -18069 -18070 18071 -18072 -18073 -18074 -18075 -18076 -18077 -18078 +v 18079 18080 18081 18082 18083 18084 18085 18086 18087 18088 18089 18090 +v 18091 -18092 -18093 -18094 -18095 18096 -18097 -18098 18099 -18100 -18101 +v 18102 -18103 18104 -18105 -18106 18107 -18108 -18109 -18110 -18111 -18112 +v 18113 18114 18115 18116 -18117 -18118 -18119 -18120 -18121 -18122 -18123 +v -18124 -18125 -18126 -18127 -18128 -18129 -18130 -18131 -18132 -18133 -18134 +v -18135 -18136 -18137 -18138 -18139 -18140 -18141 -18142 -18143 -18144 -18145 +v -18146 -18147 18148 -18149 18150 -18151 -18152 -18153 18154 -18155 18156 +v -18157 -18158 18159 -18160 -18161 -18162 -18163 -18164 -18165 18166 18167 +v 18168 18169 -18170 -18171 -18172 -18173 -18174 -18175 -18176 -18177 -18178 +v -18179 -18180 -18181 -18182 -18183 -18184 -18185 -18186 -18187 -18188 -18189 +v -18190 -18191 -18192 -18193 -18194 -18195 -18196 -18197 -18198 -18199 -18200 +v 18201 -18202 18203 -18204 -18205 -18206 18207 -18208 18209 -18210 -18211 +v 18212 -18213 -18214 -18215 -18216 -18217 -18218 18219 18220 18221 18222 +v -18223 -18224 -18225 -18226 -18227 -18228 -18229 -18230 -18231 -18232 -18233 +v -18234 -18235 -18236 -18237 -18238 -18239 -18240 -18241 -18242 -18243 -18244 +v -18245 -18246 -18247 -18248 -18249 -18250 -18251 -18252 -18253 18254 -18255 +v 18256 -18257 -18258 -18259 18260 -18261 18262 -18263 -18264 18265 -18266 +v -18267 -18268 -18269 -18270 -18271 18272 18273 18274 18275 -18276 -18277 +v -18278 -18279 -18280 -18281 -18282 -18283 -18284 -18285 -18286 -18287 -18288 +v -18289 -18290 -18291 -18292 -18293 -18294 -18295 -18296 -18297 -18298 -18299 +v -18300 -18301 -18302 -18303 -18304 -18305 -18306 -18307 -18308 -18309 -18310 +v -18311 -18312 -18313 -18314 -18315 -18316 -18317 -18318 -18319 -18320 -18321 +v -18322 -18323 -18324 -18325 -18326 -18327 -18328 -18329 -18330 -18331 -18332 +v -18333 -18334 -18335 -18336 -18337 -18338 -18339 -18340 -18341 -18342 -18343 +v -18344 -18345 -18346 -18347 -18348 -18349 -18350 -18351 -18352 -18353 -18354 +v -18355 -18356 -18357 -18358 -18359 -18360 -18361 -18362 -18363 -18364 -18365 +v -18366 -18367 -18368 -18369 -18370 -18371 -18372 -18373 -18374 -18375 -18376 +v -18377 -18378 -18379 -18380 -18381 -18382 -18383 -18384 -18385 -18386 -18387 +v -18388 -18389 -18390 -18391 -18392 -18393 -18394 -18395 -18396 -18397 -18398 +v -18399 -18400 -18401 -18402 -18403 -18404 -18405 -18406 -18407 -18408 -18409 +v -18410 -18411 -18412 -18413 -18414 -18415 -18416 -18417 -18418 -18419 -18420 +v -18421 -18422 -18423 -18424 -18425 -18426 -18427 -18428 -18429 -18430 -18431 +v -18432 -18433 -18434 -18435 -18436 -18437 -18438 -18439 -18440 -18441 -18442 +v -18443 -18444 18445 -18446 18447 -18448 -18449 -18450 18451 -18452 18453 +v -18454 -18455 -18456 -18457 18458 -18459 18460 -18461 -18462 -18463 -18464 +v 18465 -18466 18467 -18468 -18469 18470 -18471 -18472 -18473 -18474 -18475 +v -18476 -18477 -18478 -18479 -18480 18481 18482 18483 18484 -18485 -18486 +v -18487 -18488 -18489 -18490 -18491 -18492 -18493 -18494 -18495 -18496 -18497 +v -18498 -18499 -18500 -18501 -18502 -18503 -18504 -18505 -18506 -18507 -18508 +v -18509 -18510 -18511 -18512 -18513 -18514 -18515 -18516 -18517 -18518 -18519 +v -18520 -18521 -18522 -18523 -18524 -18525 -18526 -18527 -18528 -18529 -18530 +v -18531 -18532 -18533 -18534 -18535 -18536 -18537 -18538 -18539 -18540 -18541 +v -18542 -18543 -18544 -18545 -18546 -18547 -18548 -18549 -18550 -18551 -18552 +v -18553 -18554 -18555 -18556 -18557 -18558 -18559 -18560 -18561 -18562 -18563 +v -18564 -18565 -18566 -18567 -18568 -18569 -18570 -18571 -18572 -18573 -18574 +v -18575 -18576 -18577 -18578 -18579 -18580 -18581 -18582 -18583 -18584 -18585 +v -18586 -18587 -18588 -18589 -18590 -18591 -18592 -18593 -18594 -18595 -18596 +v -18597 -18598 -18599 -18600 -18601 -18602 -18603 -18604 -18605 -18606 -18607 +v -18608 -18609 -18610 -18611 -18612 -18613 -18614 -18615 -18616 -18617 -18618 +v -18619 -18620 -18621 -18622 -18623 -18624 -18625 -18626 -18627 -18628 -18629 +v -18630 -18631 -18632 -18633 -18634 -18635 -18636 -18637 -18638 -18639 -18640 +v -18641 -18642 -18643 -18644 -18645 -18646 -18647 -18648 -18649 -18650 -18651 +v 18652 -18653 18654 -18655 -18656 -18657 18658 -18659 18660 -18661 -18662 +v -18663 -18664 18665 -18666 18667 -18668 -18669 -18670 -18671 18672 -18673 +v 18674 -18675 -18676 18677 -18678 -18679 -18680 -18681 -18682 -18683 -18684 +v -18685 -18686 -18687 18688 18689 18690 18691 -18692 -18693 -18694 -18695 +v -18696 -18697 -18698 -18699 -18700 -18701 -18702 -18703 -18704 -18705 -18706 +v -18707 -18708 -18709 -18710 -18711 -18712 -18713 -18714 -18715 -18716 -18717 +v -18718 -18719 -18720 -18721 -18722 -18723 -18724 -18725 -18726 -18727 -18728 +v -18729 -18730 -18731 -18732 -18733 -18734 -18735 -18736 -18737 -18738 -18739 +v -18740 -18741 -18742 -18743 -18744 -18745 -18746 -18747 -18748 -18749 -18750 +v -18751 -18752 -18753 -18754 -18755 -18756 -18757 -18758 -18759 -18760 -18761 +v -18762 -18763 -18764 -18765 -18766 -18767 -18768 -18769 -18770 -18771 -18772 +v -18773 -18774 -18775 -18776 -18777 -18778 -18779 -18780 -18781 -18782 -18783 +v -18784 -18785 -18786 -18787 -18788 -18789 -18790 -18791 -18792 -18793 -18794 +v -18795 -18796 -18797 -18798 -18799 -18800 -18801 -18802 -18803 -18804 -18805 +v -18806 -18807 -18808 -18809 -18810 -18811 -18812 -18813 -18814 -18815 -18816 +v -18817 -18818 -18819 -18820 -18821 -18822 -18823 -18824 -18825 -18826 -18827 +v -18828 -18829 -18830 -18831 -18832 -18833 -18834 -18835 -18836 -18837 -18838 +v -18839 -18840 -18841 -18842 -18843 -18844 -18845 -18846 -18847 -18848 -18849 +v -18850 -18851 -18852 18853 -18854 18855 -18856 -18857 -18858 18859 -18860 +v 18861 -18862 -18863 -18864 -18865 18866 -18867 18868 -18869 -18870 -18871 +v -18872 18873 -18874 18875 -18876 -18877 18878 -18879 -18880 -18881 -18882 +v -18883 -18884 -18885 -18886 -18887 -18888 18889 18890 18891 18892 -18893 +v -18894 -18895 -18896 -18897 -18898 -18899 -18900 -18901 -18902 -18903 -18904 +v -18905 -18906 -18907 -18908 -18909 -18910 -18911 -18912 -18913 -18914 -18915 +v -18916 -18917 -18918 -18919 -18920 -18921 -18922 -18923 -18924 -18925 -18926 +v -18927 -18928 -18929 -18930 -18931 -18932 -18933 -18934 -18935 -18936 -18937 +v -18938 -18939 -18940 -18941 -18942 -18943 -18944 -18945 -18946 -18947 -18948 +v -18949 -18950 -18951 -18952 -18953 -18954 -18955 -18956 -18957 -18958 -18959 +v -18960 -18961 -18962 -18963 -18964 -18965 -18966 -18967 -18968 -18969 -18970 +v -18971 -18972 -18973 -18974 -18975 -18976 -18977 -18978 -18979 -18980 -18981 +v -18982 -18983 -18984 -18985 -18986 -18987 -18988 -18989 -18990 -18991 -18992 +v -18993 -18994 -18995 -18996 -18997 -18998 -18999 -19000 -19001 -19002 -19003 +v -19004 -19005 -19006 -19007 -19008 -19009 -19010 -19011 -19012 -19013 -19014 +v -19015 -19016 -19017 -19018 -19019 -19020 -19021 -19022 -19023 -19024 -19025 +v -19026 -19027 -19028 -19029 -19030 -19031 -19032 -19033 -19034 -19035 -19036 +v -19037 -19038 -19039 -19040 -19041 -19042 -19043 -19044 -19045 -19046 -19047 +v -19048 -19049 -19050 -19051 -19052 -19053 -19054 -19055 -19056 -19057 -19058 +v -19059 19060 -19061 19062 -19063 -19064 -19065 19066 -19067 19068 -19069 +v -19070 -19071 -19072 19073 -19074 19075 -19076 -19077 -19078 -19079 19080 +v -19081 19082 -19083 -19084 19085 -19086 -19087 -19088 -19089 -19090 -19091 +v -19092 -19093 -19094 -19095 19096 19097 19098 19099 -19100 -19101 -19102 +v -19103 -19104 -19105 -19106 -19107 -19108 -19109 -19110 -19111 -19112 -19113 +v -19114 -19115 -19116 -19117 -19118 -19119 -19120 -19121 -19122 -19123 -19124 +v -19125 -19126 -19127 -19128 -19129 -19130 19131 -19132 19133 -19134 -19135 +v -19136 19137 -19138 19139 -19140 -19141 19142 -19143 -19144 -19145 -19146 +v -19147 -19148 19149 19150 19151 19152 -19153 19154 -19155 19156 -19157 19158 +v 19159 19160 -19161 -19162 -19163 -19164 -19165 -19166 -19167 -19168 -19169 +v -19170 -19171 -19172 -19173 -19174 -19175 -19176 -19177 -19178 -19179 -19180 +v -19181 -19182 -19183 -19184 -19185 -19186 -19187 -19188 -19189 -19190 -19191 +v -19192 -19193 -19194 -19195 -19196 -19197 -19198 -19199 -19200 -19201 -19202 +v -19203 -19204 -19205 -19206 -19207 -19208 -19209 -19210 -19211 -19212 -19213 +v -19214 -19215 -19216 -19217 -19218 -19219 -19220 -19221 -19222 -19223 -19224 +v -19225 -19226 -19227 -19228 -19229 -19230 -19231 -19232 -19233 -19234 -19235 +v -19236 -19237 -19238 -19239 -19240 -19241 -19242 -19243 -19244 -19245 -19246 +v -19247 -19248 -19249 -19250 -19251 -19252 -19253 -19254 -19255 -19256 -19257 +v -19258 -19259 -19260 -19261 -19262 -19263 -19264 -19265 -19266 -19267 -19268 +v -19269 -19270 -19271 -19272 -19273 -19274 -19275 -19276 -19277 -19278 -19279 +v -19280 -19281 -19282 -19283 -19284 -19285 -19286 -19287 -19288 -19289 -19290 +v -19291 -19292 -19293 -19294 -19295 -19296 -19297 -19298 -19299 -19300 -19301 +v -19302 -19303 -19304 -19305 -19306 -19307 -19308 -19309 -19310 -19311 -19312 +v -19313 -19314 -19315 -19316 -19317 -19318 -19319 -19320 -19321 -19322 -19323 +v -19324 -19325 -19326 -19327 -19328 -19329 -19330 -19331 -19332 -19333 -19334 +v -19335 -19336 -19337 -19338 -19339 -19340 -19341 -19342 -19343 -19344 -19345 +v -19346 -19347 -19348 -19349 -19350 -19351 -19352 -19353 -19354 -19355 -19356 +v -19357 -19358 -19359 -19360 -19361 -19362 -19363 -19364 -19365 -19366 -19367 +v -19368 -19369 -19370 -19371 -19372 -19373 -19374 -19375 -19376 -19377 -19378 +v -19379 -19380 -19381 -19382 -19383 -19384 -19385 -19386 -19387 -19388 -19389 +v -19390 -19391 -19392 -19393 -19394 -19395 -19396 -19397 -19398 -19399 -19400 +v -19401 -19402 -19403 -19404 -19405 -19406 -19407 -19408 -19409 -19410 -19411 +v -19412 -19413 -19414 -19415 -19416 -19417 -19418 -19419 -19420 -19421 -19422 +v -19423 -19424 -19425 -19426 -19427 -19428 -19429 -19430 -19431 -19432 -19433 +v -19434 -19435 -19436 -19437 -19438 -19439 -19440 -19441 -19442 -19443 -19444 +v -19445 -19446 -19447 -19448 -19449 -19450 -19451 -19452 -19453 -19454 -19455 +v -19456 -19457 -19458 -19459 -19460 -19461 -19462 -19463 -19464 -19465 -19466 +v -19467 -19468 -19469 -19470 -19471 -19472 -19473 -19474 -19475 -19476 -19477 +v -19478 -19479 -19480 -19481 -19482 -19483 -19484 -19485 -19486 -19487 -19488 +v -19489 -19490 -19491 -19492 -19493 -19494 -19495 -19496 -19497 -19498 -19499 +v -19500 -19501 -19502 -19503 -19504 -19505 -19506 -19507 -19508 -19509 -19510 +v -19511 -19512 -19513 -19514 -19515 -19516 -19517 -19518 -19519 -19520 -19521 +v -19522 -19523 -19524 -19525 -19526 -19527 -19528 -19529 -19530 -19531 -19532 +v -19533 -19534 -19535 -19536 -19537 -19538 -19539 -19540 -19541 -19542 -19543 +v -19544 -19545 -19546 -19547 -19548 -19549 -19550 -19551 -19552 -19553 -19554 +v -19555 -19556 -19557 -19558 -19559 -19560 -19561 -19562 -19563 -19564 -19565 +v -19566 -19567 -19568 -19569 -19570 -19571 -19572 -19573 -19574 -19575 -19576 +v -19577 -19578 -19579 -19580 -19581 -19582 -19583 -19584 -19585 -19586 -19587 +v -19588 -19589 -19590 -19591 -19592 -19593 -19594 -19595 -19596 -19597 -19598 +v -19599 -19600 -19601 -19602 -19603 -19604 -19605 -19606 -19607 -19608 -19609 +v -19610 -19611 -19612 -19613 -19614 -19615 -19616 -19617 -19618 -19619 -19620 +v -19621 -19622 -19623 -19624 -19625 -19626 -19627 -19628 -19629 -19630 -19631 +v -19632 -19633 -19634 -19635 -19636 -19637 -19638 -19639 -19640 -19641 -19642 +v -19643 -19644 -19645 -19646 -19647 -19648 -19649 -19650 -19651 -19652 -19653 +v -19654 -19655 -19656 -19657 -19658 -19659 -19660 -19661 -19662 -19663 -19664 +v -19665 -19666 -19667 -19668 -19669 -19670 -19671 -19672 -19673 -19674 -19675 +v -19676 -19677 -19678 -19679 -19680 -19681 -19682 -19683 -19684 -19685 -19686 +v -19687 -19688 -19689 -19690 -19691 -19692 -19693 -19694 -19695 -19696 -19697 +v -19698 -19699 -19700 -19701 -19702 -19703 -19704 -19705 -19706 -19707 19708 +v -19709 19710 -19711 -19712 19713 -19714 19715 -19716 -19717 19718 -19719 +v 19720 -19721 -19722 -19723 19724 -19725 19726 -19727 -19728 -19729 19730 +v -19731 19732 -19733 -19734 -19735 19736 -19737 19738 -19739 -19740 19741 +v -19742 -19743 -19744 -19745 -19746 -19747 -19748 -19749 -19750 -19751 -19752 +v -19753 -19754 -19755 19756 19757 19758 19759 19760 -19761 -19762 -19763 +v -19764 -19765 -19766 19767 -19768 -19769 -19770 -19771 -19772 -19773 -19774 +v -19775 -19776 -19777 -19778 -19779 -19780 -19781 -19782 -19783 -19784 -19785 +v -19786 -19787 -19788 -19789 -19790 -19791 -19792 -19793 -19794 -19795 -19796 +v -19797 -19798 -19799 -19800 -19801 -19802 -19803 -19804 -19805 -19806 -19807 +v -19808 -19809 -19810 -19811 -19812 -19813 -19814 -19815 -19816 -19817 -19818 +v -19819 -19820 -19821 -19822 -19823 -19824 -19825 -19826 -19827 -19828 -19829 +v -19830 -19831 -19832 -19833 -19834 -19835 -19836 -19837 -19838 -19839 -19840 +v -19841 -19842 -19843 -19844 -19845 -19846 -19847 -19848 -19849 -19850 -19851 +v -19852 -19853 -19854 -19855 -19856 -19857 -19858 -19859 -19860 -19861 -19862 +v -19863 -19864 -19865 -19866 -19867 -19868 -19869 -19870 -19871 -19872 -19873 +v -19874 -19875 -19876 -19877 -19878 -19879 -19880 -19881 -19882 -19883 -19884 +v -19885 -19886 -19887 -19888 -19889 -19890 -19891 -19892 -19893 -19894 -19895 +v -19896 -19897 -19898 19899 -19900 19901 -19902 -19903 -19904 19905 -19906 +v 19907 -19908 -19909 -19910 19911 -19912 19913 -19914 -19915 -19916 19917 +v -19918 19919 -19920 -19921 -19922 19923 -19924 19925 -19926 -19927 19928 +v -19929 -19930 -19931 -19932 -19933 -19934 -19935 -19936 -19937 -19938 -19939 +v 19940 19941 19942 -19943 -19944 -19945 -19946 -19947 -19948 -19949 -19950 +v -19951 -19952 -19953 -19954 -19955 -19956 -19957 -19958 -19959 -19960 -19961 +v -19962 -19963 -19964 -19965 -19966 -19967 -19968 -19969 -19970 -19971 -19972 +v -19973 -19974 -19975 -19976 -19977 -19978 -19979 -19980 -19981 -19982 -19983 +v -19984 -19985 -19986 -19987 -19988 -19989 -19990 -19991 -19992 -19993 -19994 +v -19995 19996 -19997 19998 -19999 -20000 20001 -20002 20003 -20004 -20005 +v -20006 20007 -20008 20009 -20010 -20011 -20012 20013 -20014 20015 -20016 +v -20017 20018 -20019 -20020 -20021 -20022 -20023 -20024 -20025 -20026 -20027 +v -20028 20029 20030 20031 20032 -20033 -20034 -20035 -20036 -20037 -20038 +v -20039 -20040 -20041 -20042 -20043 -20044 -20045 -20046 -20047 -20048 -20049 +v -20050 -20051 -20052 -20053 -20054 -20055 -20056 -20057 -20058 -20059 -20060 +v -20061 -20062 -20063 -20064 -20065 -20066 -20067 -20068 -20069 -20070 -20071 +v -20072 -20073 -20074 -20075 -20076 -20077 -20078 -20079 -20080 -20081 -20082 +v -20083 -20084 -20085 -20086 -20087 -20088 -20089 -20090 -20091 -20092 -20093 +v -20094 -20095 -20096 -20097 -20098 -20099 -20100 -20101 -20102 20103 -20104 +v -20105 -20106 -20107 -20108 -20109 -20110 -20111 -20112 -20113 -20114 -20115 +v -20116 -20117 -20118 -20119 -20120 -20121 -20122 -20123 -20124 -20125 -20126 +v -20127 -20128 -20129 -20130 20131 -20132 20133 -20134 -20135 -20136 20137 +v -20138 20139 -20140 -20141 -20142 20143 -20144 20145 -20146 -20147 -20148 +v 20149 -20150 20151 -20152 -20153 20154 -20155 -20156 -20157 -20158 -20159 +v -20160 -20161 -20162 -20163 -20164 20165 20166 20167 -20168 -20169 -20170 +v -20171 -20172 -20173 -20174 -20175 -20176 -20177 -20178 -20179 -20180 20181 +v -20182 -20183 20184 -20185 -20186 -20187 -20188 -20189 -20190 20191 20192 +v 20193 20194 -20195 20196 -20197 -20198 -20199 -20200 -20201 -20202 -20203 +v -20204 -20205 -20206 -20207 -20208 -20209 20210 -20211 -20212 20213 -20214 +v -20215 -20216 -20217 -20218 20219 20220 20221 -20222 -20223 -20224 -20225 +v -20226 -20227 -20228 -20229 -20230 20231 20232 -20233 20234 -20235 -20236 +v 20237 -20238 -20239 -20240 -20241 -20242 -20243 20244 -20245 -20246 -20247 +v -20248 -20249 -20250 -20251 -20252 -20253 -20254 -20255 -20256 -20257 -20258 +v 20259 -20260 -20261 20262 -20263 -20264 -20265 -20266 -20267 20268 -20269 +v 20270 -20271 -20272 -20273 20274 -20275 20276 20277 20278 20279 20280 -20281 +v -20282 20283 20284 20285 -20286 -20287 -20288 -20289 -20290 -20291 -20292 +v -20293 -20294 20295 20296 20297 -20298 -20299 -20300 -20301 -20302 -20303 +v -20304 -20305 -20306 -20307 -20308 -20309 -20310 -20311 -20312 -20313 -20314 +v -20315 -20316 -20317 -20318 -20319 20320 -20321 -20322 -20323 -20324 -20325 +v -20326 -20327 20328 -20329 20330 -20331 -20332 -20333 20334 -20335 20336 +v -20337 -20338 20339 -20340 -20341 -20342 -20343 -20344 -20345 20346 20347 +v 20348 -20349 -20350 -20351 -20352 -20353 -20354 -20355 -20356 -20357 -20358 +v -20359 -20360 -20361 -20362 -20363 -20364 -20365 -20366 -20367 -20368 -20369 +v -20370 20371 -20372 -20373 -20374 -20375 -20376 -20377 -20378 20379 -20380 +v 20381 -20382 -20383 -20384 20385 -20386 20387 -20388 -20389 20390 -20391 +v -20392 -20393 -20394 -20395 -20396 20397 20398 20399 -20400 -20401 -20402 +v -20403 -20404 -20405 -20406 -20407 -20408 -20409 -20410 -20411 -20412 -20413 +v -20414 -20415 -20416 -20417 -20418 -20419 -20420 -20421 20422 -20423 -20424 +v -20425 -20426 -20427 -20428 -20429 20430 -20431 20432 -20433 -20434 -20435 +v 20436 -20437 20438 -20439 -20440 20441 -20442 -20443 -20444 -20445 -20446 +v -20447 20448 20449 20450 -20451 -20452 -20453 -20454 -20455 -20456 -20457 +v -20458 -20459 -20460 -20461 -20462 -20463 -20464 -20465 -20466 -20467 -20468 +v -20469 -20470 -20471 -20472 -20473 -20474 -20475 -20476 -20477 -20478 -20479 +v -20480 -20481 -20482 -20483 -20484 -20485 -20486 -20487 -20488 -20489 -20490 +v -20491 -20492 -20493 -20494 -20495 -20496 -20497 -20498 -20499 -20500 -20501 +v -20502 -20503 -20504 -20505 -20506 -20507 -20508 -20509 -20510 -20511 -20512 +v -20513 -20514 -20515 -20516 -20517 -20518 -20519 -20520 -20521 -20522 -20523 +v -20524 -20525 -20526 -20527 -20528 -20529 -20530 -20531 -20532 -20533 -20534 +v -20535 -20536 -20537 -20538 -20539 -20540 -20541 -20542 -20543 20544 -20545 +v -20546 -20547 -20548 -20549 -20550 -20551 -20552 -20553 -20554 -20555 -20556 +v -20557 -20558 -20559 -20560 -20561 -20562 -20563 -20564 -20565 -20566 -20567 +v -20568 -20569 -20570 -20571 -20572 -20573 -20574 -20575 -20576 -20577 -20578 +v -20579 -20580 -20581 -20582 -20583 -20584 -20585 -20586 -20587 -20588 -20589 +v -20590 -20591 -20592 -20593 -20594 -20595 -20596 -20597 -20598 -20599 -20600 +v -20601 -20602 -20603 -20604 -20605 -20606 -20607 -20608 -20609 -20610 -20611 +v -20612 20613 -20614 20615 -20616 -20617 -20618 20619 -20620 20621 -20622 +v -20623 -20624 -20625 20626 -20627 20628 -20629 -20630 -20631 -20632 20633 +v -20634 20635 -20636 -20637 20638 -20639 -20640 -20641 -20642 -20643 -20644 +v -20645 -20646 -20647 -20648 20649 20650 20651 -20652 -20653 -20654 -20655 +v -20656 -20657 -20658 -20659 -20660 -20661 -20662 -20663 -20664 -20665 -20666 +v -20667 -20668 -20669 -20670 -20671 -20672 -20673 -20674 -20675 -20676 -20677 +v -20678 -20679 -20680 -20681 -20682 -20683 -20684 -20685 -20686 -20687 -20688 +v -20689 -20690 -20691 -20692 -20693 -20694 -20695 -20696 -20697 -20698 -20699 +v -20700 -20701 -20702 -20703 -20704 -20705 -20706 -20707 -20708 -20709 -20710 +v -20711 -20712 -20713 -20714 -20715 -20716 -20717 -20718 -20719 -20720 -20721 +v -20722 -20723 -20724 -20725 -20726 -20727 -20728 -20729 -20730 -20731 -20732 +v -20733 -20734 -20735 -20736 -20737 -20738 -20739 -20740 -20741 -20742 -20743 +v -20744 20745 -20746 -20747 -20748 -20749 -20750 -20751 -20752 -20753 -20754 +v -20755 -20756 -20757 -20758 -20759 -20760 -20761 -20762 -20763 -20764 -20765 +v -20766 -20767 -20768 -20769 -20770 -20771 -20772 -20773 -20774 -20775 -20776 +v -20777 -20778 -20779 -20780 -20781 -20782 -20783 -20784 -20785 -20786 -20787 +v -20788 -20789 -20790 -20791 -20792 -20793 -20794 -20795 -20796 -20797 -20798 +v -20799 -20800 -20801 -20802 -20803 -20804 -20805 -20806 -20807 -20808 -20809 +v -20810 -20811 -20812 -20813 20814 -20815 20816 -20817 -20818 -20819 20820 +v -20821 20822 -20823 -20824 -20825 -20826 20827 -20828 20829 -20830 -20831 +v -20832 -20833 20834 -20835 20836 -20837 -20838 20839 -20840 -20841 -20842 +v -20843 -20844 -20845 -20846 -20847 -20848 -20849 20850 20851 20852 -20853 +v -20854 -20855 -20856 -20857 -20858 -20859 -20860 -20861 -20862 -20863 -20864 +v -20865 -20866 -20867 -20868 -20869 -20870 -20871 -20872 -20873 -20874 -20875 +v -20876 -20877 -20878 -20879 -20880 -20881 -20882 -20883 -20884 -20885 -20886 +v -20887 -20888 -20889 -20890 -20891 -20892 -20893 -20894 -20895 -20896 -20897 +v -20898 -20899 -20900 -20901 -20902 -20903 -20904 -20905 -20906 -20907 -20908 +v -20909 -20910 -20911 -20912 -20913 -20914 -20915 -20916 -20917 -20918 -20919 +v -20920 -20921 -20922 -20923 -20924 -20925 -20926 -20927 -20928 -20929 -20930 +v -20931 -20932 -20933 -20934 -20935 -20936 -20937 -20938 -20939 -20940 -20941 +v -20942 -20943 -20944 -20945 20946 -20947 -20948 -20949 -20950 -20951 -20952 +v -20953 -20954 -20955 -20956 -20957 -20958 -20959 -20960 -20961 -20962 -20963 +v -20964 -20965 -20966 -20967 -20968 -20969 -20970 -20971 -20972 -20973 -20974 +v -20975 -20976 -20977 -20978 -20979 -20980 -20981 -20982 -20983 -20984 -20985 +v -20986 -20987 -20988 -20989 -20990 -20991 -20992 -20993 -20994 -20995 -20996 +v -20997 -20998 -20999 -21000 -21001 -21002 -21003 -21004 -21005 -21006 -21007 +v -21008 -21009 -21010 -21011 -21012 -21013 -21014 21015 -21016 21017 -21018 +v -21019 -21020 21021 -21022 21023 -21024 -21025 -21026 -21027 21028 -21029 +v 21030 -21031 -21032 -21033 -21034 21035 -21036 21037 -21038 -21039 21040 +v -21041 -21042 -21043 -21044 -21045 -21046 -21047 -21048 -21049 -21050 21051 +v 21052 21053 -21054 -21055 -21056 -21057 -21058 -21059 -21060 -21061 -21062 +v -21063 -21064 -21065 -21066 -21067 -21068 -21069 -21070 -21071 -21072 -21073 +v -21074 -21075 -21076 -21077 -21078 -21079 -21080 -21081 -21082 -21083 -21084 +v -21085 -21086 -21087 -21088 -21089 -21090 -21091 -21092 -21093 -21094 -21095 +v -21096 -21097 -21098 -21099 -21100 -21101 -21102 -21103 -21104 -21105 -21106 +v -21107 -21108 -21109 -21110 -21111 -21112 -21113 -21114 -21115 -21116 -21117 +v -21118 -21119 -21120 -21121 -21122 -21123 -21124 -21125 -21126 -21127 -21128 +v -21129 -21130 -21131 -21132 -21133 -21134 -21135 -21136 -21137 -21138 -21139 +v -21140 -21141 -21142 -21143 -21144 -21145 -21146 21147 -21148 -21149 -21150 +v -21151 -21152 -21153 -21154 -21155 -21156 -21157 -21158 -21159 -21160 -21161 +v -21162 -21163 -21164 -21165 -21166 -21167 -21168 -21169 -21170 -21171 -21172 +v -21173 -21174 -21175 -21176 -21177 -21178 -21179 -21180 -21181 -21182 -21183 +v -21184 -21185 -21186 -21187 -21188 -21189 -21190 -21191 -21192 -21193 -21194 +v -21195 -21196 -21197 -21198 -21199 -21200 -21201 -21202 -21203 -21204 -21205 +v -21206 -21207 -21208 -21209 -21210 -21211 -21212 -21213 -21214 -21215 21216 +v -21217 21218 -21219 -21220 -21221 21222 -21223 21224 -21225 -21226 -21227 +v -21228 21229 -21230 21231 -21232 -21233 -21234 -21235 21236 -21237 21238 +v -21239 -21240 21241 -21242 -21243 -21244 -21245 -21246 -21247 -21248 -21249 +v -21250 -21251 21252 21253 21254 -21255 -21256 -21257 -21258 -21259 -21260 +v -21261 -21262 -21263 -21264 -21265 -21266 -21267 -21268 -21269 -21270 -21271 +v -21272 -21273 -21274 -21275 -21276 21277 -21278 -21279 -21280 -21281 -21282 +v -21283 -21284 21285 -21286 21287 -21288 -21289 -21290 21291 -21292 21293 +v -21294 -21295 21296 -21297 -21298 -21299 -21300 -21301 -21302 21303 21304 +v 21305 -21306 -21307 -21308 -21309 -21310 -21311 -21312 -21313 -21314 -21315 +v -21316 -21317 -21318 -21319 -21320 -21321 -21322 -21323 -21324 -21325 -21326 +v -21327 -21328 -21329 -21330 -21331 -21332 -21333 -21334 21335 -21336 21337 +v -21338 -21339 -21340 21341 -21342 21343 -21344 -21345 21346 -21347 -21348 +v -21349 -21350 -21351 -21352 21353 21354 21355 21356 -21357 -21358 -21359 +v -21360 -21361 -21362 -21363 -21364 -21365 -21366 -21367 -21368 -21369 -21370 +v -21371 -21372 -21373 -21374 -21375 -21376 -21377 -21378 -21379 -21380 -21381 +v -21382 -21383 -21384 -21385 21386 -21387 21388 -21389 -21390 -21391 21392 +v -21393 21394 -21395 -21396 21397 -21398 -21399 -21400 -21401 -21402 -21403 +v 21404 21405 21406 21407 -21408 -21409 -21410 -21411 -21412 -21413 -21414 +v -21415 -21416 -21417 -21418 -21419 -21420 -21421 -21422 -21423 -21424 -21425 +v -21426 -21427 -21428 -21429 -21430 -21431 -21432 -21433 -21434 -21435 -21436 +v 21437 -21438 21439 -21440 -21441 -21442 21443 -21444 21445 -21446 -21447 +v 21448 -21449 -21450 -21451 -21452 -21453 -21454 21455 21456 21457 21458 +v -21459 -21460 -21461 -21462 -21463 -21464 -21465 -21466 -21467 -21468 -21469 +v -21470 -21471 -21472 -21473 -21474 -21475 -21476 -21477 -21478 -21479 -21480 +v -21481 -21482 -21483 -21484 -21485 -21486 -21487 -21488 -21489 -21490 -21491 +v -21492 -21493 -21494 -21495 -21496 -21497 -21498 -21499 -21500 -21501 -21502 +v -21503 -21504 -21505 -21506 -21507 -21508 -21509 -21510 -21511 -21512 -21513 +v -21514 -21515 -21516 -21517 -21518 -21519 -21520 -21521 -21522 -21523 -21524 +v -21525 -21526 -21527 -21528 -21529 -21530 -21531 -21532 -21533 -21534 -21535 +v -21536 -21537 -21538 -21539 -21540 -21541 -21542 -21543 -21544 -21545 -21546 +v -21547 -21548 -21549 -21550 -21551 -21552 -21553 -21554 -21555 -21556 -21557 +v -21558 -21559 -21560 -21561 -21562 -21563 -21564 -21565 -21566 -21567 -21568 +v -21569 -21570 -21571 -21572 -21573 -21574 -21575 -21576 -21577 -21578 -21579 +v -21580 -21581 -21582 -21583 -21584 -21585 -21586 -21587 -21588 -21589 -21590 +v -21591 -21592 -21593 -21594 -21595 -21596 -21597 -21598 -21599 -21600 -21601 +v -21602 -21603 -21604 -21605 -21606 -21607 -21608 -21609 -21610 -21611 -21612 +v -21613 -21614 -21615 -21616 -21617 -21618 -21619 21620 -21621 21622 -21623 +v -21624 -21625 21626 -21627 21628 -21629 -21630 -21631 -21632 21633 -21634 +v 21635 -21636 -21637 -21638 -21639 21640 -21641 21642 -21643 -21644 21645 +v -21646 -21647 -21648 -21649 -21650 -21651 -21652 -21653 -21654 -21655 21656 +v 21657 21658 21659 -21660 -21661 -21662 -21663 -21664 -21665 -21666 -21667 +v -21668 -21669 -21670 -21671 -21672 -21673 -21674 -21675 -21676 -21677 -21678 +v -21679 -21680 -21681 -21682 -21683 -21684 -21685 -21686 -21687 -21688 -21689 +v -21690 -21691 -21692 -21693 -21694 -21695 -21696 -21697 -21698 -21699 -21700 +v -21701 -21702 -21703 -21704 -21705 -21706 -21707 -21708 -21709 -21710 -21711 +v -21712 -21713 -21714 -21715 -21716 -21717 -21718 -21719 -21720 -21721 -21722 +v -21723 -21724 -21725 -21726 -21727 -21728 -21729 -21730 -21731 -21732 -21733 +v -21734 -21735 -21736 -21737 -21738 -21739 -21740 -21741 -21742 -21743 -21744 +v -21745 -21746 -21747 -21748 -21749 -21750 -21751 -21752 -21753 -21754 -21755 +v -21756 -21757 -21758 -21759 -21760 -21761 -21762 -21763 -21764 -21765 -21766 +v -21767 -21768 -21769 -21770 -21771 -21772 -21773 -21774 -21775 -21776 -21777 +v -21778 -21779 -21780 -21781 -21782 -21783 -21784 -21785 -21786 -21787 -21788 +v -21789 -21790 -21791 -21792 -21793 -21794 -21795 -21796 -21797 -21798 -21799 +v -21800 -21801 -21802 -21803 -21804 -21805 -21806 -21807 -21808 -21809 -21810 +v -21811 -21812 -21813 -21814 -21815 -21816 -21817 -21818 -21819 -21820 21821 +v -21822 21823 -21824 -21825 -21826 21827 -21828 21829 -21830 -21831 -21832 +v -21833 21834 -21835 21836 -21837 -21838 -21839 -21840 21841 -21842 21843 +v -21844 -21845 21846 -21847 -21848 -21849 -21850 -21851 -21852 -21853 -21854 +v -21855 -21856 21857 21858 21859 21860 -21861 -21862 -21863 -21864 -21865 +v -21866 -21867 -21868 -21869 -21870 -21871 -21872 -21873 -21874 -21875 -21876 +v -21877 -21878 -21879 -21880 -21881 -21882 -21883 -21884 -21885 -21886 -21887 +v -21888 -21889 -21890 -21891 -21892 -21893 -21894 -21895 -21896 -21897 -21898 +v -21899 -21900 -21901 -21902 -21903 -21904 -21905 -21906 -21907 -21908 -21909 +v -21910 -21911 -21912 -21913 -21914 -21915 -21916 -21917 -21918 -21919 -21920 +v -21921 -21922 -21923 -21924 -21925 -21926 -21927 -21928 -21929 -21930 -21931 +v -21932 -21933 -21934 -21935 -21936 -21937 -21938 -21939 -21940 -21941 -21942 +v -21943 -21944 -21945 -21946 -21947 -21948 -21949 -21950 -21951 -21952 -21953 +v -21954 -21955 -21956 -21957 -21958 -21959 -21960 -21961 -21962 -21963 -21964 +v -21965 -21966 -21967 -21968 -21969 -21970 -21971 -21972 -21973 -21974 -21975 +v -21976 -21977 -21978 -21979 -21980 -21981 -21982 -21983 -21984 -21985 -21986 +v -21987 -21988 -21989 -21990 -21991 -21992 -21993 -21994 -21995 -21996 -21997 +v -21998 -21999 -22000 -22001 -22002 -22003 -22004 -22005 -22006 -22007 -22008 +v -22009 -22010 -22011 -22012 -22013 -22014 -22015 -22016 -22017 -22018 -22019 +v -22020 -22021 22022 -22023 22024 -22025 -22026 -22027 22028 -22029 22030 +v -22031 -22032 -22033 -22034 22035 -22036 22037 -22038 -22039 -22040 -22041 +v 22042 -22043 22044 -22045 -22046 22047 -22048 -22049 -22050 -22051 -22052 +v -22053 -22054 -22055 -22056 -22057 22058 22059 22060 22061 -22062 -22063 +v -22064 -22065 -22066 -22067 -22068 -22069 -22070 -22071 -22072 -22073 -22074 +v -22075 -22076 -22077 -22078 -22079 -22080 -22081 -22082 -22083 -22084 -22085 +v -22086 -22087 -22088 -22089 -22090 -22091 -22092 -22093 -22094 -22095 -22096 +v -22097 -22098 -22099 -22100 -22101 -22102 -22103 -22104 -22105 -22106 -22107 +v -22108 -22109 -22110 -22111 -22112 -22113 -22114 -22115 -22116 -22117 -22118 +v -22119 -22120 -22121 -22122 -22123 -22124 -22125 -22126 -22127 -22128 -22129 +v -22130 -22131 -22132 -22133 -22134 -22135 -22136 -22137 -22138 -22139 -22140 +v -22141 -22142 -22143 -22144 -22145 -22146 -22147 -22148 -22149 -22150 -22151 +v -22152 -22153 -22154 -22155 -22156 -22157 -22158 -22159 -22160 -22161 -22162 +v -22163 -22164 -22165 -22166 -22167 -22168 -22169 -22170 -22171 -22172 -22173 +v -22174 -22175 -22176 -22177 -22178 -22179 -22180 -22181 -22182 -22183 -22184 +v -22185 -22186 -22187 -22188 -22189 -22190 -22191 -22192 -22193 -22194 -22195 +v -22196 -22197 -22198 -22199 -22200 -22201 -22202 -22203 -22204 -22205 -22206 +v -22207 -22208 -22209 -22210 -22211 -22212 -22213 -22214 -22215 -22216 -22217 +v -22218 -22219 -22220 -22221 -22222 22223 -22224 22225 -22226 -22227 -22228 +v 22229 -22230 22231 -22232 -22233 -22234 -22235 22236 -22237 22238 -22239 +v -22240 -22241 -22242 22243 -22244 22245 -22246 -22247 22248 -22249 -22250 +v -22251 -22252 -22253 -22254 -22255 -22256 -22257 -22258 22259 22260 22261 +v 22262 -22263 -22264 -22265 -22266 -22267 -22268 -22269 -22270 -22271 -22272 +v -22273 -22274 -22275 -22276 -22277 -22278 -22279 -22280 -22281 -22282 -22283 +v -22284 -22285 -22286 -22287 -22288 -22289 -22290 -22291 22292 -22293 22294 +v -22295 -22296 -22297 22298 -22299 22300 -22301 -22302 22303 -22304 -22305 +v -22306 -22307 -22308 -22309 22310 22311 22312 22313 -22314 22315 -22316 +v 22317 -22318 22319 22320 -22321 -22322 -22323 -22324 -22325 -22326 -22327 +v -22328 -22329 -22330 -22331 -22332 -22333 -22334 -22335 -22336 -22337 -22338 +v -22339 -22340 -22341 -22342 -22343 -22344 -22345 -22346 -22347 -22348 -22349 +v -22350 -22351 -22352 -22353 -22354 -22355 -22356 -22357 -22358 -22359 -22360 +v -22361 -22362 -22363 -22364 -22365 -22366 -22367 -22368 -22369 -22370 -22371 +v -22372 -22373 -22374 -22375 -22376 -22377 -22378 -22379 -22380 -22381 -22382 +v -22383 -22384 -22385 -22386 -22387 -22388 -22389 -22390 -22391 -22392 -22393 +v -22394 -22395 -22396 -22397 -22398 -22399 -22400 -22401 -22402 -22403 -22404 +v -22405 -22406 -22407 -22408 -22409 -22410 -22411 -22412 -22413 -22414 -22415 +v -22416 -22417 -22418 -22419 -22420 -22421 -22422 -22423 -22424 -22425 -22426 +v -22427 -22428 -22429 -22430 -22431 -22432 -22433 -22434 -22435 -22436 -22437 +v -22438 -22439 -22440 -22441 -22442 -22443 -22444 -22445 -22446 -22447 -22448 +v -22449 -22450 -22451 -22452 -22453 -22454 -22455 -22456 -22457 -22458 -22459 +v -22460 -22461 -22462 -22463 -22464 -22465 -22466 -22467 -22468 -22469 -22470 +v -22471 -22472 -22473 -22474 -22475 -22476 -22477 -22478 -22479 -22480 -22481 +v -22482 -22483 -22484 -22485 -22486 -22487 -22488 -22489 -22490 -22491 -22492 +v -22493 -22494 -22495 -22496 -22497 -22498 -22499 -22500 -22501 -22502 -22503 +v -22504 -22505 -22506 -22507 -22508 -22509 -22510 -22511 -22512 -22513 -22514 +v -22515 -22516 -22517 -22518 -22519 -22520 -22521 -22522 -22523 -22524 -22525 +v -22526 -22527 -22528 -22529 -22530 -22531 -22532 -22533 -22534 -22535 -22536 +v -22537 -22538 -22539 -22540 -22541 -22542 -22543 -22544 -22545 -22546 -22547 +v -22548 -22549 -22550 -22551 -22552 -22553 -22554 -22555 -22556 -22557 -22558 +v -22559 -22560 -22561 -22562 -22563 -22564 -22565 -22566 -22567 -22568 -22569 +v -22570 -22571 -22572 -22573 -22574 -22575 -22576 -22577 -22578 -22579 -22580 +v -22581 -22582 -22583 -22584 -22585 -22586 -22587 -22588 -22589 -22590 -22591 +v -22592 -22593 -22594 -22595 -22596 -22597 -22598 -22599 -22600 -22601 -22602 +v -22603 -22604 -22605 -22606 -22607 -22608 -22609 -22610 -22611 -22612 -22613 +v -22614 -22615 -22616 -22617 -22618 -22619 -22620 -22621 -22622 -22623 -22624 +v -22625 -22626 -22627 -22628 -22629 -22630 -22631 -22632 -22633 -22634 -22635 +v -22636 -22637 -22638 -22639 -22640 -22641 -22642 -22643 -22644 -22645 -22646 +v -22647 -22648 -22649 -22650 -22651 -22652 -22653 -22654 -22655 -22656 -22657 +v -22658 -22659 -22660 -22661 -22662 -22663 -22664 -22665 -22666 -22667 -22668 +v -22669 -22670 -22671 -22672 -22673 -22674 -22675 -22676 -22677 -22678 -22679 +v -22680 -22681 -22682 -22683 -22684 -22685 -22686 -22687 -22688 -22689 -22690 +v -22691 -22692 -22693 -22694 -22695 -22696 -22697 -22698 -22699 -22700 -22701 +v -22702 -22703 -22704 -22705 -22706 -22707 -22708 -22709 -22710 -22711 -22712 +v -22713 -22714 -22715 -22716 -22717 -22718 -22719 -22720 -22721 -22722 -22723 +v -22724 -22725 -22726 -22727 -22728 -22729 -22730 -22731 -22732 -22733 -22734 +v -22735 -22736 -22737 -22738 -22739 -22740 -22741 -22742 -22743 -22744 -22745 +v -22746 -22747 -22748 -22749 -22750 -22751 -22752 -22753 -22754 -22755 -22756 +v -22757 -22758 -22759 -22760 -22761 -22762 -22763 -22764 -22765 -22766 -22767 +v -22768 -22769 -22770 -22771 -22772 -22773 -22774 -22775 -22776 -22777 -22778 +v -22779 -22780 -22781 -22782 -22783 -22784 -22785 -22786 -22787 -22788 -22789 +v -22790 -22791 -22792 -22793 -22794 -22795 -22796 -22797 -22798 -22799 -22800 +v -22801 -22802 -22803 -22804 -22805 -22806 -22807 -22808 -22809 -22810 -22811 +v -22812 -22813 -22814 -22815 -22816 -22817 -22818 -22819 -22820 -22821 -22822 +v -22823 -22824 -22825 -22826 -22827 -22828 -22829 -22830 -22831 -22832 -22833 +v -22834 -22835 -22836 -22837 -22838 -22839 -22840 -22841 -22842 -22843 -22844 +v -22845 -22846 -22847 -22848 -22849 -22850 -22851 -22852 -22853 -22854 -22855 +v -22856 -22857 -22858 -22859 -22860 -22861 -22862 -22863 -22864 -22865 -22866 +v -22867 -22868 -22869 -22870 -22871 -22872 -22873 -22874 -22875 -22876 22877 +v -22878 22879 -22880 -22881 -22882 22883 -22884 22885 -22886 -22887 -22888 +v 22889 -22890 22891 -22892 -22893 -22894 22895 -22896 22897 -22898 -22899 +v -22900 22901 -22902 22903 -22904 -22905 -22906 22907 -22908 22909 -22910 +v -22911 22912 -22913 -22914 -22915 -22916 -22917 -22918 -22919 -22920 -22921 +v -22922 -22923 -22924 -22925 -22926 22927 22928 22929 22930 22931 -22932 +v -22933 -22934 -22935 -22936 -22937 22938 -22939 -22940 -22941 -22942 -22943 +v -22944 -22945 -22946 -22947 -22948 -22949 -22950 -22951 -22952 -22953 -22954 +v -22955 -22956 -22957 -22958 -22959 -22960 -22961 -22962 -22963 -22964 -22965 +v -22966 -22967 -22968 -22969 -22970 -22971 -22972 -22973 -22974 -22975 -22976 +v -22977 -22978 -22979 -22980 -22981 -22982 -22983 -22984 -22985 -22986 -22987 +v -22988 -22989 -22990 -22991 -22992 -22993 -22994 -22995 -22996 -22997 -22998 +v -22999 -23000 -23001 -23002 -23003 -23004 -23005 -23006 -23007 -23008 -23009 +v -23010 -23011 -23012 -23013 -23014 -23015 -23016 -23017 -23018 -23019 -23020 +v -23021 -23022 -23023 -23024 -23025 -23026 -23027 -23028 -23029 -23030 -23031 +v -23032 -23033 -23034 -23035 -23036 -23037 -23038 -23039 -23040 -23041 -23042 +v -23043 -23044 -23045 -23046 -23047 -23048 -23049 -23050 -23051 -23052 -23053 +v -23054 -23055 -23056 -23057 -23058 -23059 -23060 -23061 -23062 -23063 -23064 +v -23065 -23066 -23067 23068 -23069 23070 -23071 -23072 -23073 23074 -23075 +v 23076 -23077 -23078 -23079 23080 -23081 23082 -23083 -23084 -23085 23086 +v -23087 23088 -23089 -23090 -23091 23092 -23093 23094 -23095 -23096 23097 +v -23098 -23099 -23100 -23101 -23102 -23103 -23104 -23105 -23106 -23107 -23108 +v 23109 23110 23111 -23112 -23113 -23114 -23115 -23116 -23117 -23118 -23119 +v -23120 -23121 -23122 -23123 -23124 -23125 -23126 -23127 -23128 -23129 -23130 +v -23131 -23132 -23133 -23134 -23135 -23136 -23137 -23138 -23139 -23140 -23141 +v -23142 -23143 -23144 -23145 -23146 -23147 -23148 -23149 -23150 -23151 -23152 +v -23153 -23154 -23155 -23156 -23157 -23158 -23159 -23160 -23161 -23162 -23163 +v -23164 23165 -23166 23167 -23168 -23169 23170 -23171 23172 -23173 -23174 +v -23175 23176 -23177 23178 -23179 -23180 -23181 23182 -23183 23184 -23185 +v -23186 23187 -23188 -23189 -23190 -23191 -23192 -23193 -23194 -23195 -23196 +v -23197 23198 23199 23200 23201 -23202 -23203 -23204 -23205 -23206 -23207 +v -23208 -23209 -23210 -23211 -23212 -23213 -23214 -23215 -23216 -23217 -23218 +v -23219 -23220 -23221 -23222 -23223 -23224 -23225 -23226 -23227 -23228 -23229 +v -23230 -23231 -23232 -23233 -23234 -23235 -23236 -23237 -23238 -23239 -23240 +v -23241 -23242 -23243 -23244 -23245 -23246 -23247 -23248 -23249 -23250 -23251 +v -23252 -23253 -23254 -23255 -23256 -23257 -23258 -23259 -23260 -23261 -23262 +v -23263 -23264 -23265 -23266 -23267 -23268 -23269 -23270 -23271 -23272 -23273 +v -23274 -23275 -23276 -23277 -23278 -23279 -23280 -23281 -23282 -23283 -23284 +v -23285 -23286 -23287 -23288 -23289 -23290 -23291 -23292 -23293 -23294 -23295 +v -23296 23297 -23298 23299 -23300 -23301 23302 -23303 23304 -23305 -23306 +v 23307 -23308 23309 -23310 -23311 -23312 23313 -23314 23315 -23316 -23317 +v -23318 23319 -23320 23321 -23322 -23323 23324 -23325 -23326 -23327 -23328 +v -23329 -23330 -23331 -23332 -23333 -23334 -23335 23336 23337 23338 -23339 +v -23340 -23341 -23342 -23343 -23344 -23345 -23346 -23347 -23348 -23349 -23350 +v -23351 23352 -23353 -23354 23355 -23356 -23357 -23358 -23359 -23360 -23361 +v 23362 23363 23364 -23365 -23366 -23367 -23368 -23369 -23370 -23371 -23372 +v -23373 -23374 -23375 -23376 -23377 -23378 23379 -23380 -23381 23382 -23383 +v -23384 -23385 -23386 -23387 23388 23389 23390 -23391 -23392 -23393 -23394 +v -23395 -23396 -23397 -23398 -23399 23400 23401 -23402 23403 -23404 -23405 +v 23406 -23407 -23408 -23409 -23410 -23411 -23412 23413 -23414 -23415 -23416 +v -23417 -23418 -23419 -23420 -23421 -23422 -23423 -23424 -23425 -23426 -23427 +v 23428 -23429 -23430 23431 -23432 -23433 -23434 -23435 -23436 23437 -23438 +v 23439 -23440 -23441 -23442 23443 -23444 23445 23446 23447 23448 23449 -23450 +v -23451 23452 23453 23454 -23455 -23456 -23457 -23458 -23459 -23460 -23461 +v -23462 -23463 23464 23465 23466 -23467 -23468 -23469 -23470 -23471 -23472 +v -23473 -23474 -23475 -23476 -23477 -23478 -23479 -23480 -23481 -23482 -23483 +v -23484 -23485 -23486 -23487 -23488 23489 -23490 -23491 -23492 -23493 -23494 +v -23495 -23496 23497 -23498 23499 -23500 -23501 -23502 23503 -23504 23505 +v -23506 -23507 23508 -23509 -23510 -23511 -23512 -23513 -23514 23515 23516 +v 23517 -23518 -23519 -23520 -23521 -23522 -23523 -23524 -23525 -23526 -23527 +v -23528 -23529 -23530 -23531 -23532 -23533 -23534 -23535 -23536 -23537 -23538 +v -23539 23540 -23541 -23542 -23543 -23544 -23545 -23546 -23547 23548 -23549 +v 23550 -23551 -23552 -23553 23554 -23555 23556 -23557 -23558 23559 -23560 +v -23561 -23562 -23563 -23564 -23565 23566 23567 23568 -23569 -23570 -23571 +v -23572 -23573 -23574 -23575 -23576 -23577 -23578 -23579 -23580 -23581 -23582 +v -23583 -23584 -23585 -23586 -23587 -23588 -23589 -23590 23591 -23592 -23593 +v -23594 -23595 -23596 -23597 -23598 23599 -23600 23601 -23602 -23603 -23604 +v 23605 -23606 23607 -23608 -23609 23610 -23611 -23612 -23613 -23614 -23615 +v -23616 23617 23618 23619 -23620 -23621 -23622 -23623 -23624 -23625 -23626 +v -23627 -23628 -23629 -23630 -23631 -23632 -23633 -23634 -23635 -23636 -23637 +v -23638 -23639 -23640 -23641 -23642 -23643 -23644 -23645 -23646 -23647 -23648 +v -23649 -23650 -23651 -23652 -23653 -23654 -23655 -23656 -23657 -23658 -23659 +v -23660 -23661 -23662 -23663 -23664 -23665 -23666 -23667 -23668 -23669 -23670 +v -23671 -23672 -23673 -23674 -23675 -23676 -23677 -23678 -23679 -23680 -23681 +v -23682 -23683 -23684 -23685 -23686 -23687 -23688 -23689 -23690 -23691 -23692 +v -23693 -23694 -23695 -23696 -23697 -23698 -23699 -23700 -23701 -23702 -23703 +v -23704 -23705 -23706 -23707 -23708 -23709 -23710 -23711 -23712 23713 -23714 +v -23715 -23716 -23717 -23718 -23719 -23720 -23721 -23722 -23723 -23724 -23725 +v -23726 -23727 -23728 -23729 -23730 -23731 -23732 -23733 -23734 -23735 -23736 +v -23737 -23738 -23739 -23740 -23741 -23742 -23743 -23744 -23745 -23746 -23747 +v -23748 -23749 -23750 -23751 -23752 -23753 -23754 -23755 -23756 -23757 -23758 +v -23759 -23760 -23761 -23762 -23763 -23764 -23765 -23766 -23767 -23768 -23769 +v -23770 -23771 -23772 -23773 -23774 -23775 -23776 -23777 -23778 -23779 -23780 +v -23781 23782 -23783 23784 -23785 -23786 -23787 23788 -23789 23790 -23791 +v -23792 -23793 -23794 23795 -23796 23797 -23798 -23799 -23800 -23801 23802 +v -23803 23804 -23805 -23806 23807 -23808 -23809 -23810 -23811 -23812 -23813 +v -23814 -23815 -23816 -23817 23818 23819 23820 -23821 -23822 -23823 -23824 +v -23825 -23826 -23827 -23828 -23829 -23830 -23831 -23832 -23833 -23834 -23835 +v -23836 -23837 -23838 -23839 -23840 -23841 -23842 -23843 -23844 -23845 -23846 +v -23847 -23848 -23849 -23850 -23851 -23852 -23853 -23854 -23855 -23856 -23857 +v -23858 -23859 -23860 -23861 -23862 -23863 -23864 -23865 -23866 -23867 -23868 +v -23869 -23870 -23871 -23872 -23873 -23874 -23875 -23876 -23877 -23878 -23879 +v -23880 -23881 -23882 -23883 -23884 -23885 -23886 -23887 -23888 -23889 -23890 +v -23891 -23892 -23893 -23894 -23895 -23896 -23897 -23898 -23899 -23900 -23901 +v -23902 -23903 -23904 -23905 -23906 -23907 -23908 -23909 -23910 -23911 -23912 +v -23913 23914 -23915 -23916 -23917 -23918 -23919 -23920 -23921 -23922 -23923 +v -23924 -23925 -23926 -23927 -23928 -23929 -23930 -23931 -23932 -23933 -23934 +v -23935 -23936 -23937 -23938 -23939 -23940 -23941 -23942 -23943 -23944 -23945 +v -23946 -23947 -23948 -23949 -23950 -23951 -23952 -23953 -23954 -23955 -23956 +v -23957 -23958 -23959 -23960 -23961 -23962 -23963 -23964 -23965 -23966 -23967 +v -23968 -23969 -23970 -23971 -23972 -23973 -23974 -23975 -23976 -23977 -23978 +v -23979 -23980 -23981 -23982 23983 -23984 23985 -23986 -23987 -23988 23989 +v -23990 23991 -23992 -23993 -23994 -23995 23996 -23997 23998 -23999 -24000 +v -24001 -24002 24003 -24004 24005 -24006 -24007 24008 -24009 -24010 -24011 +v -24012 -24013 -24014 -24015 -24016 -24017 -24018 24019 24020 24021 -24022 +v -24023 -24024 -24025 -24026 -24027 -24028 -24029 -24030 -24031 -24032 -24033 +v -24034 -24035 -24036 -24037 -24038 -24039 -24040 -24041 -24042 -24043 -24044 +v -24045 -24046 -24047 -24048 -24049 -24050 -24051 -24052 -24053 -24054 -24055 +v -24056 -24057 -24058 -24059 -24060 -24061 -24062 -24063 -24064 -24065 -24066 +v -24067 -24068 -24069 -24070 -24071 -24072 -24073 -24074 -24075 -24076 -24077 +v -24078 -24079 -24080 -24081 -24082 -24083 -24084 -24085 -24086 -24087 -24088 +v -24089 -24090 -24091 -24092 -24093 -24094 -24095 -24096 -24097 -24098 -24099 +v -24100 -24101 -24102 -24103 -24104 -24105 -24106 -24107 -24108 -24109 -24110 +v -24111 -24112 -24113 -24114 24115 -24116 -24117 -24118 -24119 -24120 -24121 +v -24122 -24123 -24124 -24125 -24126 -24127 -24128 -24129 -24130 -24131 -24132 +v -24133 -24134 -24135 -24136 -24137 -24138 -24139 -24140 -24141 -24142 -24143 +v -24144 -24145 -24146 -24147 -24148 -24149 -24150 -24151 -24152 -24153 -24154 +v -24155 -24156 -24157 -24158 -24159 -24160 -24161 -24162 -24163 -24164 -24165 +v -24166 -24167 -24168 -24169 -24170 -24171 -24172 -24173 -24174 -24175 -24176 +v -24177 -24178 -24179 -24180 -24181 -24182 -24183 24184 -24185 24186 -24187 +v -24188 -24189 24190 -24191 24192 -24193 -24194 -24195 -24196 24197 -24198 +v 24199 -24200 -24201 -24202 -24203 24204 -24205 24206 -24207 -24208 24209 +v -24210 -24211 -24212 -24213 -24214 -24215 -24216 -24217 -24218 -24219 24220 +v 24221 24222 -24223 -24224 -24225 -24226 -24227 -24228 -24229 -24230 -24231 +v -24232 -24233 -24234 -24235 -24236 -24237 -24238 -24239 -24240 -24241 -24242 +v -24243 -24244 -24245 -24246 -24247 -24248 -24249 -24250 -24251 -24252 -24253 +v -24254 -24255 -24256 -24257 -24258 -24259 -24260 -24261 -24262 -24263 -24264 +v -24265 -24266 -24267 -24268 -24269 -24270 -24271 -24272 -24273 -24274 -24275 +v -24276 -24277 -24278 -24279 -24280 -24281 -24282 -24283 -24284 -24285 -24286 +v -24287 -24288 -24289 -24290 -24291 -24292 -24293 -24294 -24295 -24296 -24297 +v -24298 -24299 -24300 -24301 -24302 -24303 -24304 -24305 -24306 -24307 -24308 +v -24309 -24310 -24311 -24312 -24313 -24314 -24315 24316 -24317 -24318 -24319 +v -24320 -24321 -24322 -24323 -24324 -24325 -24326 -24327 -24328 -24329 -24330 +v -24331 -24332 -24333 -24334 -24335 -24336 -24337 -24338 -24339 -24340 -24341 +v -24342 -24343 -24344 -24345 -24346 -24347 -24348 -24349 -24350 -24351 -24352 +v -24353 -24354 -24355 -24356 -24357 -24358 -24359 -24360 -24361 -24362 -24363 +v -24364 -24365 -24366 -24367 -24368 -24369 -24370 -24371 -24372 -24373 -24374 +v -24375 -24376 -24377 -24378 -24379 -24380 -24381 -24382 -24383 -24384 24385 +v -24386 24387 -24388 -24389 -24390 24391 -24392 24393 -24394 -24395 -24396 +v -24397 24398 -24399 24400 -24401 -24402 -24403 -24404 24405 -24406 24407 +v -24408 -24409 24410 -24411 -24412 -24413 -24414 -24415 -24416 -24417 -24418 +v -24419 -24420 24421 24422 24423 -24424 -24425 -24426 -24427 -24428 -24429 +v -24430 -24431 -24432 -24433 -24434 -24435 -24436 -24437 -24438 -24439 -24440 +v -24441 -24442 -24443 -24444 -24445 24446 -24447 -24448 -24449 -24450 -24451 +v -24452 -24453 24454 -24455 24456 -24457 -24458 -24459 24460 -24461 24462 +v -24463 -24464 24465 -24466 -24467 -24468 -24469 -24470 -24471 24472 24473 +v 24474 -24475 -24476 -24477 -24478 -24479 -24480 -24481 -24482 -24483 -24484 +v -24485 -24486 -24487 -24488 -24489 -24490 -24491 -24492 -24493 -24494 -24495 +v -24496 -24497 -24498 -24499 -24500 -24501 -24502 -24503 24504 -24505 24506 +v -24507 -24508 -24509 24510 -24511 24512 -24513 -24514 24515 -24516 -24517 +v -24518 -24519 -24520 -24521 24522 24523 24524 24525 -24526 -24527 -24528 +v -24529 -24530 -24531 -24532 -24533 -24534 -24535 -24536 -24537 -24538 -24539 +v -24540 -24541 -24542 -24543 -24544 -24545 -24546 -24547 -24548 -24549 -24550 +v -24551 -24552 -24553 -24554 24555 -24556 24557 -24558 -24559 -24560 24561 +v -24562 24563 -24564 -24565 24566 -24567 -24568 -24569 -24570 -24571 -24572 +v 24573 24574 24575 24576 -24577 -24578 -24579 -24580 -24581 -24582 -24583 +v -24584 -24585 -24586 -24587 -24588 -24589 -24590 -24591 -24592 -24593 -24594 +v -24595 -24596 -24597 -24598 -24599 -24600 -24601 -24602 -24603 -24604 -24605 +v 24606 -24607 24608 -24609 -24610 -24611 24612 -24613 24614 -24615 -24616 +v 24617 -24618 -24619 -24620 -24621 -24622 -24623 24624 24625 24626 24627 +v -24628 -24629 -24630 -24631 -24632 -24633 -24634 -24635 -24636 -24637 -24638 +v -24639 -24640 -24641 -24642 -24643 -24644 -24645 -24646 -24647 -24648 -24649 +v -24650 -24651 -24652 -24653 -24654 -24655 -24656 -24657 -24658 -24659 -24660 +v -24661 -24662 -24663 -24664 -24665 -24666 -24667 -24668 -24669 -24670 -24671 +v -24672 -24673 -24674 -24675 -24676 -24677 -24678 -24679 -24680 -24681 -24682 +v -24683 -24684 -24685 -24686 -24687 -24688 -24689 -24690 -24691 -24692 -24693 +v -24694 -24695 -24696 -24697 -24698 -24699 -24700 -24701 -24702 -24703 -24704 +v -24705 -24706 -24707 -24708 -24709 -24710 -24711 -24712 -24713 -24714 -24715 +v -24716 -24717 -24718 -24719 -24720 -24721 -24722 -24723 -24724 -24725 -24726 +v -24727 -24728 -24729 -24730 -24731 -24732 -24733 -24734 -24735 -24736 -24737 +v -24738 -24739 -24740 -24741 -24742 -24743 -24744 -24745 -24746 -24747 -24748 +v -24749 -24750 -24751 -24752 -24753 -24754 -24755 -24756 -24757 -24758 -24759 +v -24760 -24761 -24762 -24763 -24764 -24765 -24766 -24767 -24768 -24769 -24770 +v -24771 -24772 -24773 -24774 -24775 -24776 -24777 -24778 -24779 -24780 -24781 +v -24782 -24783 -24784 -24785 -24786 -24787 -24788 24789 -24790 24791 -24792 +v -24793 -24794 24795 -24796 24797 -24798 -24799 -24800 -24801 24802 -24803 +v 24804 -24805 -24806 -24807 -24808 24809 -24810 24811 -24812 -24813 24814 +v -24815 -24816 -24817 -24818 -24819 -24820 -24821 -24822 -24823 -24824 24825 +v 24826 24827 24828 -24829 -24830 -24831 -24832 -24833 -24834 -24835 -24836 +v -24837 -24838 -24839 -24840 -24841 -24842 -24843 -24844 -24845 -24846 -24847 +v -24848 -24849 -24850 -24851 -24852 -24853 -24854 -24855 -24856 -24857 -24858 +v -24859 -24860 -24861 -24862 -24863 -24864 -24865 -24866 -24867 -24868 -24869 +v -24870 -24871 -24872 -24873 -24874 -24875 -24876 -24877 -24878 -24879 -24880 +v -24881 -24882 -24883 -24884 -24885 -24886 -24887 -24888 -24889 -24890 -24891 +v -24892 -24893 -24894 -24895 -24896 -24897 -24898 -24899 -24900 -24901 -24902 +v -24903 -24904 -24905 -24906 -24907 -24908 -24909 -24910 -24911 -24912 -24913 +v -24914 -24915 -24916 -24917 -24918 -24919 -24920 -24921 -24922 -24923 -24924 +v -24925 -24926 -24927 -24928 -24929 -24930 -24931 -24932 -24933 -24934 -24935 +v -24936 -24937 -24938 -24939 -24940 -24941 -24942 -24943 -24944 -24945 -24946 +v -24947 -24948 -24949 -24950 -24951 -24952 -24953 -24954 -24955 -24956 -24957 +v -24958 -24959 -24960 -24961 -24962 -24963 -24964 -24965 -24966 -24967 -24968 +v -24969 -24970 -24971 -24972 -24973 -24974 -24975 -24976 -24977 -24978 -24979 +v -24980 -24981 -24982 -24983 -24984 -24985 -24986 -24987 -24988 -24989 24990 +v -24991 24992 -24993 -24994 -24995 24996 -24997 24998 -24999 -25000 -25001 +v -25002 25003 -25004 25005 -25006 -25007 -25008 -25009 25010 -25011 25012 +v -25013 -25014 25015 -25016 -25017 -25018 -25019 -25020 -25021 -25022 -25023 +v -25024 -25025 25026 25027 25028 25029 -25030 -25031 -25032 -25033 -25034 +v -25035 -25036 -25037 -25038 -25039 -25040 -25041 -25042 -25043 -25044 -25045 +v -25046 -25047 -25048 -25049 -25050 -25051 -25052 -25053 -25054 -25055 -25056 +v -25057 -25058 -25059 -25060 -25061 -25062 -25063 -25064 -25065 -25066 -25067 +v -25068 -25069 -25070 -25071 -25072 -25073 -25074 -25075 -25076 -25077 -25078 +v -25079 -25080 -25081 -25082 -25083 -25084 -25085 -25086 -25087 -25088 -25089 +v -25090 -25091 -25092 -25093 -25094 -25095 -25096 -25097 -25098 -25099 -25100 +v -25101 -25102 -25103 -25104 -25105 -25106 -25107 -25108 -25109 -25110 -25111 +v -25112 -25113 -25114 -25115 -25116 -25117 -25118 -25119 -25120 -25121 -25122 +v -25123 -25124 -25125 -25126 -25127 -25128 -25129 -25130 -25131 -25132 -25133 +v -25134 -25135 -25136 -25137 -25138 -25139 -25140 -25141 -25142 -25143 -25144 +v -25145 -25146 -25147 -25148 -25149 -25150 -25151 -25152 -25153 -25154 -25155 +v -25156 -25157 -25158 -25159 -25160 -25161 -25162 -25163 -25164 -25165 -25166 +v -25167 -25168 -25169 -25170 -25171 -25172 -25173 -25174 -25175 -25176 -25177 +v -25178 -25179 -25180 -25181 -25182 -25183 -25184 -25185 -25186 -25187 -25188 +v -25189 -25190 25191 -25192 25193 -25194 -25195 -25196 25197 -25198 25199 +v -25200 -25201 -25202 -25203 25204 -25205 25206 -25207 -25208 -25209 -25210 +v 25211 -25212 25213 -25214 -25215 25216 -25217 -25218 -25219 -25220 -25221 +v -25222 -25223 -25224 -25225 -25226 25227 25228 25229 25230 -25231 -25232 +v -25233 -25234 -25235 -25236 -25237 -25238 -25239 -25240 -25241 -25242 -25243 +v -25244 -25245 -25246 -25247 -25248 -25249 -25250 -25251 -25252 -25253 -25254 +v -25255 -25256 -25257 -25258 -25259 -25260 -25261 -25262 -25263 -25264 -25265 +v -25266 -25267 -25268 -25269 -25270 -25271 -25272 -25273 -25274 -25275 -25276 +v -25277 -25278 -25279 -25280 -25281 -25282 -25283 -25284 -25285 -25286 -25287 +v -25288 -25289 -25290 -25291 -25292 -25293 -25294 -25295 -25296 -25297 -25298 +v -25299 -25300 -25301 -25302 -25303 -25304 -25305 -25306 -25307 -25308 -25309 +v -25310 -25311 -25312 -25313 -25314 -25315 -25316 -25317 -25318 -25319 -25320 +v -25321 -25322 -25323 -25324 -25325 -25326 -25327 -25328 -25329 -25330 -25331 +v -25332 -25333 -25334 -25335 -25336 -25337 -25338 -25339 -25340 -25341 -25342 +v -25343 -25344 -25345 -25346 -25347 -25348 -25349 -25350 -25351 -25352 -25353 +v -25354 -25355 -25356 -25357 -25358 -25359 -25360 -25361 -25362 -25363 -25364 +v -25365 -25366 -25367 -25368 -25369 -25370 -25371 -25372 -25373 -25374 -25375 +v -25376 -25377 -25378 -25379 -25380 -25381 -25382 -25383 -25384 -25385 -25386 +v -25387 -25388 -25389 -25390 -25391 25392 -25393 25394 -25395 -25396 -25397 +v 25398 -25399 25400 -25401 -25402 -25403 -25404 25405 -25406 25407 -25408 +v -25409 -25410 -25411 25412 -25413 25414 -25415 -25416 25417 -25418 -25419 +v -25420 -25421 -25422 -25423 -25424 -25425 -25426 -25427 25428 25429 25430 +v 25431 -25432 -25433 -25434 -25435 -25436 -25437 -25438 -25439 -25440 -25441 +v -25442 -25443 -25444 -25445 -25446 -25447 -25448 -25449 -25450 -25451 -25452 +v -25453 -25454 -25455 -25456 -25457 -25458 -25459 -25460 25461 -25462 25463 +v -25464 -25465 -25466 25467 -25468 25469 -25470 -25471 25472 -25473 -25474 +v -25475 -25476 -25477 -25478 25479 25480 25481 25482 -25483 25484 -25485 +v 25486 -25487 25488 25489 -25490 -25491 -25492 -25493 -25494 -25495 -25496 +v -25497 -25498 -25499 -25500 -25501 -25502 -25503 -25504 -25505 -25506 -25507 +v -25508 -25509 -25510 -25511 -25512 -25513 -25514 -25515 -25516 -25517 -25518 +v -25519 -25520 -25521 -25522 -25523 -25524 -25525 -25526 -25527 -25528 -25529 +v -25530 -25531 -25532 -25533 -25534 -25535 -25536 -25537 -25538 -25539 -25540 +v -25541 -25542 -25543 -25544 -25545 -25546 -25547 -25548 -25549 -25550 -25551 +v -25552 -25553 -25554 -25555 -25556 -25557 -25558 -25559 -25560 -25561 -25562 +v -25563 -25564 -25565 -25566 -25567 -25568 -25569 -25570 -25571 -25572 -25573 +v -25574 -25575 -25576 -25577 -25578 -25579 -25580 -25581 -25582 -25583 -25584 +v -25585 -25586 -25587 -25588 -25589 -25590 -25591 -25592 -25593 -25594 -25595 +v -25596 -25597 -25598 -25599 -25600 -25601 -25602 -25603 -25604 -25605 -25606 +v -25607 -25608 -25609 -25610 -25611 -25612 -25613 -25614 -25615 -25616 -25617 +v -25618 -25619 -25620 -25621 -25622 -25623 -25624 -25625 -25626 -25627 -25628 +v -25629 -25630 -25631 -25632 -25633 -25634 -25635 -25636 -25637 -25638 -25639 +v -25640 -25641 -25642 -25643 -25644 -25645 -25646 -25647 -25648 -25649 -25650 +v -25651 -25652 -25653 -25654 -25655 -25656 -25657 -25658 -25659 -25660 -25661 +v -25662 -25663 -25664 -25665 -25666 -25667 -25668 -25669 -25670 -25671 -25672 +v -25673 -25674 -25675 -25676 -25677 -25678 -25679 -25680 -25681 -25682 -25683 +v -25684 -25685 -25686 -25687 -25688 -25689 -25690 -25691 -25692 -25693 -25694 +v -25695 -25696 -25697 -25698 -25699 -25700 -25701 -25702 -25703 -25704 -25705 +v -25706 -25707 -25708 -25709 -25710 -25711 -25712 -25713 -25714 -25715 -25716 +v -25717 -25718 -25719 -25720 -25721 -25722 -25723 -25724 -25725 -25726 -25727 +v -25728 -25729 -25730 -25731 -25732 -25733 -25734 -25735 -25736 -25737 -25738 +v -25739 -25740 -25741 -25742 -25743 -25744 -25745 -25746 -25747 -25748 -25749 +v -25750 -25751 -25752 -25753 -25754 -25755 -25756 -25757 -25758 -25759 -25760 +v -25761 -25762 -25763 -25764 -25765 -25766 -25767 -25768 -25769 -25770 -25771 +v -25772 -25773 -25774 -25775 -25776 -25777 -25778 -25779 -25780 -25781 -25782 +v -25783 -25784 -25785 -25786 -25787 -25788 -25789 -25790 -25791 -25792 -25793 +v -25794 -25795 -25796 -25797 -25798 -25799 -25800 -25801 -25802 -25803 -25804 +v -25805 -25806 -25807 -25808 -25809 -25810 -25811 -25812 -25813 -25814 -25815 +v -25816 -25817 -25818 -25819 -25820 -25821 -25822 -25823 -25824 -25825 -25826 +v -25827 -25828 -25829 -25830 -25831 -25832 -25833 -25834 -25835 -25836 -25837 +v -25838 -25839 -25840 -25841 -25842 -25843 -25844 -25845 -25846 -25847 -25848 +v -25849 -25850 -25851 -25852 -25853 -25854 -25855 -25856 -25857 -25858 -25859 +v -25860 -25861 -25862 -25863 -25864 -25865 -25866 -25867 -25868 -25869 -25870 +v -25871 -25872 -25873 -25874 -25875 -25876 -25877 -25878 -25879 -25880 -25881 +v -25882 -25883 -25884 -25885 -25886 -25887 -25888 -25889 -25890 -25891 -25892 +v -25893 -25894 -25895 -25896 -25897 -25898 -25899 -25900 -25901 -25902 -25903 +v -25904 -25905 -25906 -25907 -25908 -25909 -25910 -25911 -25912 -25913 -25914 +v -25915 -25916 -25917 -25918 -25919 -25920 -25921 -25922 -25923 -25924 -25925 +v -25926 -25927 -25928 -25929 -25930 -25931 -25932 -25933 -25934 -25935 -25936 +v -25937 -25938 -25939 -25940 -25941 -25942 -25943 -25944 -25945 -25946 -25947 +v -25948 -25949 -25950 -25951 -25952 -25953 -25954 -25955 -25956 -25957 -25958 +v -25959 -25960 -25961 -25962 -25963 -25964 -25965 -25966 -25967 -25968 -25969 +v -25970 -25971 -25972 -25973 -25974 -25975 -25976 -25977 -25978 -25979 -25980 +v -25981 -25982 -25983 -25984 -25985 -25986 -25987 -25988 -25989 -25990 -25991 +v -25992 -25993 -25994 -25995 -25996 -25997 -25998 -25999 -26000 -26001 -26002 +v -26003 -26004 -26005 -26006 -26007 -26008 -26009 -26010 -26011 -26012 -26013 +v -26014 -26015 -26016 -26017 -26018 -26019 -26020 -26021 -26022 -26023 -26024 +v -26025 -26026 -26027 -26028 26029 -26030 26031 -26032 -26033 26034 -26035 +v 26036 -26037 -26038 26039 -26040 26041 -26042 -26043 -26044 26045 -26046 +v 26047 -26048 -26049 -26050 26051 -26052 26053 -26054 -26055 -26056 26057 +v -26058 26059 -26060 -26061 26062 -26063 -26064 -26065 -26066 -26067 -26068 +v -26069 -26070 -26071 -26072 -26073 -26074 -26075 -26076 26077 26078 26079 +v 26080 26081 -26082 -26083 -26084 -26085 -26086 -26087 26088 -26089 -26090 +v -26091 -26092 -26093 -26094 -26095 -26096 -26097 -26098 -26099 -26100 -26101 +v -26102 -26103 -26104 -26105 -26106 -26107 -26108 -26109 -26110 -26111 -26112 +v -26113 -26114 -26115 -26116 -26117 -26118 -26119 -26120 -26121 -26122 -26123 +v -26124 -26125 -26126 -26127 -26128 -26129 -26130 -26131 -26132 -26133 -26134 +v -26135 -26136 -26137 -26138 -26139 -26140 -26141 -26142 -26143 -26144 -26145 +v -26146 -26147 -26148 -26149 -26150 -26151 -26152 -26153 -26154 -26155 -26156 +v -26157 -26158 -26159 -26160 -26161 -26162 -26163 -26164 -26165 -26166 -26167 +v -26168 -26169 -26170 -26171 -26172 -26173 -26174 -26175 -26176 -26177 -26178 +v -26179 -26180 -26181 -26182 -26183 -26184 -26185 -26186 -26187 -26188 -26189 +v -26190 -26191 -26192 -26193 -26194 -26195 -26196 -26197 -26198 -26199 -26200 +v -26201 -26202 -26203 -26204 -26205 -26206 -26207 -26208 -26209 -26210 -26211 +v -26212 -26213 -26214 -26215 -26216 -26217 26218 -26219 26220 -26221 -26222 +v -26223 26224 -26225 26226 -26227 -26228 -26229 26230 -26231 26232 -26233 +v -26234 -26235 26236 -26237 26238 -26239 -26240 -26241 26242 -26243 26244 +v -26245 -26246 26247 -26248 -26249 -26250 -26251 -26252 -26253 -26254 -26255 +v -26256 -26257 -26258 26259 26260 26261 -26262 -26263 -26264 -26265 -26266 +v -26267 -26268 -26269 -26270 -26271 -26272 -26273 -26274 -26275 -26276 -26277 +v -26278 -26279 -26280 -26281 -26282 -26283 -26284 -26285 -26286 -26287 -26288 +v -26289 -26290 -26291 -26292 -26293 -26294 -26295 -26296 -26297 -26298 -26299 +v -26300 -26301 -26302 -26303 -26304 -26305 -26306 -26307 -26308 -26309 -26310 +v -26311 -26312 -26313 -26314 26315 -26316 26317 -26318 -26319 26320 -26321 +v 26322 -26323 -26324 -26325 26326 -26327 26328 -26329 -26330 -26331 26332 +v -26333 26334 -26335 -26336 26337 -26338 -26339 -26340 -26341 -26342 -26343 +v -26344 -26345 -26346 -26347 26348 26349 26350 26351 -26352 -26353 -26354 +v -26355 -26356 -26357 -26358 -26359 -26360 -26361 -26362 -26363 -26364 -26365 +v -26366 -26367 -26368 -26369 -26370 -26371 -26372 -26373 -26374 -26375 -26376 +v -26377 -26378 -26379 -26380 -26381 -26382 -26383 -26384 -26385 -26386 -26387 +v -26388 -26389 -26390 -26391 -26392 -26393 -26394 -26395 -26396 -26397 -26398 +v -26399 -26400 -26401 -26402 -26403 -26404 -26405 -26406 -26407 -26408 -26409 +v -26410 -26411 -26412 -26413 -26414 -26415 -26416 -26417 -26418 -26419 -26420 +v -26421 26422 -26423 -26424 -26425 -26426 -26427 -26428 -26429 -26430 -26431 +v -26432 -26433 -26434 -26435 -26436 -26437 -26438 -26439 -26440 -26441 -26442 +v -26443 -26444 -26445 -26446 -26447 -26448 -26449 26450 -26451 26452 -26453 +v -26454 -26455 26456 -26457 26458 -26459 -26460 -26461 26462 -26463 26464 +v -26465 -26466 -26467 26468 -26469 26470 -26471 -26472 26473 -26474 -26475 +v -26476 -26477 -26478 -26479 -26480 -26481 -26482 -26483 26484 26485 26486 +v -26487 -26488 -26489 -26490 -26491 -26492 -26493 -26494 -26495 -26496 -26497 +v -26498 -26499 26500 -26501 -26502 26503 -26504 -26505 -26506 -26507 -26508 +v -26509 26510 26511 26512 -26513 -26514 -26515 -26516 -26517 -26518 -26519 +v -26520 -26521 -26522 -26523 -26524 -26525 -26526 26527 -26528 -26529 26530 +v -26531 -26532 -26533 -26534 -26535 26536 26537 26538 -26539 -26540 -26541 +v -26542 -26543 -26544 -26545 -26546 -26547 26548 26549 -26550 26551 -26552 +v -26553 26554 -26555 -26556 -26557 -26558 -26559 -26560 26561 -26562 -26563 +v -26564 -26565 -26566 -26567 -26568 -26569 -26570 -26571 -26572 -26573 -26574 +v -26575 26576 -26577 -26578 26579 -26580 -26581 -26582 -26583 -26584 26585 +v -26586 26587 -26588 -26589 -26590 26591 -26592 26593 26594 26595 26596 26597 +v -26598 -26599 26600 26601 26602 -26603 -26604 -26605 -26606 -26607 -26608 +v -26609 -26610 -26611 26612 26613 26614 -26615 -26616 -26617 -26618 -26619 +v -26620 -26621 -26622 -26623 -26624 -26625 -26626 -26627 -26628 -26629 -26630 +v -26631 -26632 -26633 -26634 -26635 -26636 26637 -26638 -26639 -26640 -26641 +v -26642 -26643 -26644 26645 -26646 26647 -26648 -26649 -26650 26651 -26652 +v 26653 -26654 -26655 26656 -26657 -26658 -26659 -26660 -26661 -26662 26663 +v 26664 26665 -26666 -26667 -26668 -26669 -26670 -26671 -26672 -26673 -26674 +v -26675 -26676 -26677 -26678 -26679 -26680 -26681 -26682 -26683 -26684 -26685 +v -26686 -26687 26688 -26689 -26690 -26691 -26692 -26693 -26694 -26695 26696 +v -26697 26698 -26699 -26700 -26701 26702 -26703 26704 -26705 -26706 26707 +v -26708 -26709 -26710 -26711 -26712 -26713 26714 26715 26716 -26717 -26718 +v -26719 -26720 -26721 -26722 -26723 -26724 -26725 -26726 -26727 -26728 -26729 +v -26730 -26731 -26732 -26733 -26734 -26735 -26736 -26737 -26738 26739 -26740 +v -26741 -26742 -26743 -26744 -26745 -26746 26747 -26748 26749 -26750 -26751 +v -26752 26753 -26754 26755 -26756 -26757 26758 -26759 -26760 -26761 -26762 +v -26763 -26764 26765 26766 26767 -26768 -26769 -26770 -26771 -26772 -26773 +v -26774 -26775 -26776 -26777 -26778 -26779 -26780 -26781 -26782 -26783 -26784 +v -26785 -26786 -26787 -26788 -26789 -26790 -26791 -26792 -26793 -26794 -26795 +v -26796 -26797 -26798 -26799 -26800 -26801 -26802 -26803 -26804 -26805 -26806 +v -26807 -26808 -26809 -26810 -26811 -26812 -26813 -26814 -26815 -26816 -26817 +v -26818 -26819 -26820 -26821 -26822 -26823 -26824 -26825 -26826 -26827 -26828 +v -26829 -26830 -26831 -26832 -26833 -26834 -26835 -26836 -26837 -26838 -26839 +v -26840 -26841 -26842 -26843 -26844 -26845 -26846 -26847 -26848 -26849 -26850 +v -26851 -26852 -26853 -26854 -26855 -26856 -26857 -26858 -26859 -26860 26861 +v -26862 -26863 -26864 -26865 -26866 -26867 -26868 -26869 -26870 -26871 -26872 +v -26873 -26874 -26875 -26876 -26877 -26878 -26879 -26880 -26881 -26882 -26883 +v -26884 -26885 -26886 -26887 -26888 -26889 -26890 -26891 -26892 -26893 -26894 +v -26895 -26896 -26897 -26898 -26899 -26900 -26901 -26902 -26903 -26904 -26905 +v -26906 -26907 -26908 -26909 -26910 -26911 -26912 -26913 -26914 -26915 -26916 +v -26917 -26918 -26919 -26920 -26921 -26922 -26923 -26924 -26925 -26926 -26927 +v -26928 -26929 26930 -26931 26932 -26933 -26934 -26935 26936 -26937 26938 +v -26939 -26940 -26941 -26942 26943 -26944 26945 -26946 -26947 -26948 -26949 +v 26950 -26951 26952 -26953 -26954 26955 -26956 -26957 -26958 -26959 -26960 +v -26961 -26962 -26963 -26964 -26965 26966 26967 26968 -26969 -26970 -26971 +v -26972 -26973 -26974 -26975 -26976 -26977 -26978 -26979 -26980 -26981 -26982 +v -26983 -26984 -26985 -26986 -26987 -26988 -26989 -26990 -26991 -26992 -26993 +v -26994 -26995 -26996 -26997 -26998 -26999 -27000 -27001 -27002 -27003 -27004 +v -27005 -27006 -27007 -27008 -27009 -27010 -27011 -27012 -27013 -27014 -27015 +v -27016 -27017 -27018 -27019 -27020 -27021 -27022 -27023 -27024 -27025 -27026 +v -27027 -27028 -27029 -27030 -27031 -27032 -27033 -27034 -27035 -27036 -27037 +v -27038 -27039 -27040 -27041 -27042 -27043 -27044 -27045 -27046 -27047 -27048 +v -27049 -27050 -27051 -27052 -27053 -27054 -27055 -27056 -27057 -27058 -27059 +v -27060 -27061 27062 -27063 -27064 -27065 -27066 -27067 -27068 -27069 -27070 +v -27071 -27072 -27073 -27074 -27075 -27076 -27077 -27078 -27079 -27080 -27081 +v -27082 -27083 -27084 -27085 -27086 -27087 -27088 -27089 -27090 -27091 -27092 +v -27093 -27094 -27095 -27096 -27097 -27098 -27099 -27100 -27101 -27102 -27103 +v -27104 -27105 -27106 -27107 -27108 -27109 -27110 -27111 -27112 -27113 -27114 +v -27115 -27116 -27117 -27118 -27119 -27120 -27121 -27122 -27123 -27124 -27125 +v -27126 -27127 -27128 -27129 -27130 27131 -27132 27133 -27134 -27135 -27136 +v 27137 -27138 27139 -27140 -27141 -27142 -27143 27144 -27145 27146 -27147 +v -27148 -27149 -27150 27151 -27152 27153 -27154 -27155 27156 -27157 -27158 +v -27159 -27160 -27161 -27162 -27163 -27164 -27165 -27166 27167 27168 27169 +v -27170 -27171 -27172 -27173 -27174 -27175 -27176 -27177 -27178 -27179 -27180 +v -27181 -27182 -27183 -27184 -27185 -27186 -27187 -27188 -27189 -27190 -27191 +v -27192 -27193 -27194 -27195 -27196 -27197 -27198 -27199 -27200 -27201 -27202 +v -27203 -27204 -27205 -27206 -27207 -27208 -27209 -27210 -27211 -27212 -27213 +v -27214 -27215 -27216 -27217 -27218 -27219 -27220 -27221 -27222 -27223 -27224 +v -27225 -27226 -27227 -27228 -27229 -27230 -27231 -27232 -27233 -27234 -27235 +v -27236 -27237 -27238 -27239 -27240 -27241 -27242 -27243 -27244 -27245 -27246 +v -27247 -27248 -27249 -27250 -27251 -27252 -27253 -27254 -27255 -27256 -27257 +v -27258 -27259 -27260 -27261 -27262 27263 -27264 -27265 -27266 -27267 -27268 +v -27269 -27270 -27271 -27272 -27273 -27274 -27275 -27276 -27277 -27278 -27279 +v -27280 -27281 -27282 -27283 -27284 -27285 -27286 -27287 -27288 -27289 -27290 +v -27291 -27292 -27293 -27294 -27295 -27296 -27297 -27298 -27299 -27300 -27301 +v -27302 -27303 -27304 -27305 -27306 -27307 -27308 -27309 -27310 -27311 -27312 +v -27313 -27314 -27315 -27316 -27317 -27318 -27319 -27320 -27321 -27322 -27323 +v -27324 -27325 -27326 -27327 -27328 -27329 -27330 -27331 27332 -27333 27334 +v -27335 -27336 -27337 27338 -27339 27340 -27341 -27342 -27343 -27344 27345 +v -27346 27347 -27348 -27349 -27350 -27351 27352 -27353 27354 -27355 -27356 +v 27357 -27358 -27359 -27360 -27361 -27362 -27363 -27364 -27365 -27366 -27367 +v 27368 27369 27370 -27371 -27372 -27373 -27374 -27375 -27376 -27377 -27378 +v -27379 -27380 -27381 -27382 -27383 -27384 -27385 -27386 -27387 -27388 -27389 +v -27390 -27391 -27392 -27393 -27394 -27395 -27396 -27397 -27398 -27399 -27400 +v -27401 -27402 -27403 -27404 -27405 -27406 -27407 -27408 -27409 -27410 -27411 +v -27412 -27413 -27414 -27415 -27416 -27417 -27418 -27419 -27420 -27421 -27422 +v -27423 -27424 -27425 -27426 -27427 -27428 -27429 -27430 -27431 -27432 -27433 +v -27434 -27435 -27436 -27437 -27438 -27439 -27440 -27441 -27442 -27443 -27444 +v -27445 -27446 -27447 -27448 -27449 -27450 -27451 -27452 -27453 -27454 -27455 +v -27456 -27457 -27458 -27459 -27460 -27461 -27462 -27463 27464 -27465 -27466 +v -27467 -27468 -27469 -27470 -27471 -27472 -27473 -27474 -27475 -27476 -27477 +v -27478 -27479 -27480 -27481 -27482 -27483 -27484 -27485 -27486 -27487 -27488 +v -27489 -27490 -27491 -27492 -27493 -27494 -27495 -27496 -27497 -27498 -27499 +v -27500 -27501 -27502 -27503 -27504 -27505 -27506 -27507 -27508 -27509 -27510 +v -27511 -27512 -27513 -27514 -27515 -27516 -27517 -27518 -27519 -27520 -27521 +v -27522 -27523 -27524 -27525 -27526 -27527 -27528 -27529 -27530 -27531 -27532 +v 27533 -27534 27535 -27536 -27537 -27538 27539 -27540 27541 -27542 -27543 +v -27544 -27545 27546 -27547 27548 -27549 -27550 -27551 -27552 27553 -27554 +v 27555 -27556 -27557 27558 -27559 -27560 -27561 -27562 -27563 -27564 -27565 +v -27566 -27567 -27568 27569 27570 27571 -27572 -27573 -27574 -27575 -27576 +v -27577 -27578 -27579 -27580 -27581 -27582 -27583 -27584 -27585 -27586 -27587 +v -27588 -27589 -27590 -27591 -27592 -27593 27594 -27595 -27596 -27597 -27598 +v -27599 -27600 -27601 27602 -27603 27604 -27605 -27606 -27607 27608 -27609 +v 27610 -27611 -27612 27613 -27614 -27615 -27616 -27617 -27618 -27619 27620 +v 27621 27622 -27623 -27624 -27625 -27626 -27627 -27628 -27629 -27630 -27631 +v -27632 -27633 -27634 -27635 -27636 -27637 -27638 -27639 -27640 -27641 -27642 +v -27643 -27644 -27645 -27646 -27647 -27648 -27649 -27650 -27651 27652 -27653 +v 27654 -27655 -27656 -27657 27658 -27659 27660 -27661 -27662 27663 -27664 +v -27665 -27666 -27667 -27668 -27669 27670 27671 27672 27673 -27674 -27675 +v -27676 -27677 -27678 -27679 -27680 -27681 -27682 -27683 -27684 -27685 -27686 +v -27687 -27688 -27689 -27690 -27691 -27692 -27693 -27694 -27695 -27696 -27697 +v -27698 -27699 -27700 -27701 -27702 27703 -27704 27705 -27706 -27707 -27708 +v 27709 -27710 27711 -27712 -27713 27714 -27715 -27716 -27717 -27718 -27719 +v -27720 27721 27722 27723 27724 -27725 -27726 -27727 -27728 -27729 -27730 +v -27731 -27732 -27733 -27734 -27735 -27736 -27737 -27738 -27739 -27740 -27741 +v -27742 -27743 -27744 -27745 -27746 -27747 -27748 -27749 -27750 -27751 -27752 +v -27753 27754 -27755 27756 -27757 -27758 -27759 27760 -27761 27762 -27763 +v -27764 27765 -27766 -27767 -27768 -27769 -27770 -27771 27772 27773 27774 +v 27775 -27776 -27777 -27778 -27779 -27780 -27781 -27782 -27783 -27784 -27785 +v -27786 -27787 -27788 -27789 -27790 -27791 -27792 -27793 -27794 -27795 -27796 +v -27797 -27798 -27799 -27800 -27801 -27802 -27803 -27804 -27805 -27806 -27807 +v -27808 -27809 -27810 -27811 -27812 -27813 -27814 -27815 -27816 -27817 -27818 +v -27819 -27820 -27821 -27822 -27823 -27824 -27825 -27826 -27827 -27828 -27829 +v -27830 -27831 -27832 -27833 -27834 -27835 -27836 -27837 -27838 -27839 -27840 +v -27841 -27842 -27843 -27844 -27845 -27846 -27847 -27848 -27849 -27850 -27851 +v -27852 -27853 -27854 -27855 -27856 -27857 -27858 -27859 -27860 -27861 -27862 +v -27863 -27864 -27865 -27866 -27867 -27868 -27869 -27870 -27871 -27872 -27873 +v -27874 -27875 -27876 -27877 -27878 -27879 -27880 -27881 -27882 -27883 -27884 +v -27885 -27886 -27887 -27888 -27889 -27890 -27891 -27892 -27893 -27894 -27895 +v -27896 -27897 -27898 -27899 -27900 -27901 -27902 -27903 -27904 -27905 -27906 +v -27907 -27908 -27909 -27910 -27911 -27912 -27913 -27914 -27915 -27916 -27917 +v -27918 -27919 -27920 -27921 -27922 -27923 -27924 -27925 -27926 -27927 -27928 +v -27929 -27930 -27931 -27932 -27933 -27934 -27935 -27936 27937 -27938 27939 +v -27940 -27941 -27942 27943 -27944 27945 -27946 -27947 -27948 -27949 27950 +v -27951 27952 -27953 -27954 -27955 -27956 27957 -27958 27959 -27960 -27961 +v 27962 -27963 -27964 -27965 -27966 -27967 -27968 -27969 -27970 -27971 -27972 +v 27973 27974 27975 27976 -27977 -27978 -27979 -27980 -27981 -27982 -27983 +v -27984 -27985 -27986 -27987 -27988 -27989 -27990 -27991 -27992 -27993 -27994 +v -27995 -27996 -27997 -27998 -27999 -28000 -28001 -28002 -28003 -28004 -28005 +v -28006 -28007 -28008 -28009 -28010 -28011 -28012 -28013 -28014 -28015 -28016 +v -28017 -28018 -28019 -28020 -28021 -28022 -28023 -28024 -28025 -28026 -28027 +v -28028 -28029 -28030 -28031 -28032 -28033 -28034 -28035 -28036 -28037 -28038 +v -28039 -28040 -28041 -28042 -28043 -28044 -28045 -28046 -28047 -28048 -28049 +v -28050 -28051 -28052 -28053 -28054 -28055 -28056 -28057 -28058 -28059 -28060 +v -28061 -28062 -28063 -28064 -28065 -28066 -28067 -28068 -28069 -28070 -28071 +v -28072 -28073 -28074 -28075 -28076 -28077 -28078 -28079 -28080 -28081 -28082 +v -28083 -28084 -28085 -28086 -28087 -28088 -28089 -28090 -28091 -28092 -28093 +v -28094 -28095 -28096 -28097 -28098 -28099 -28100 -28101 -28102 -28103 -28104 +v -28105 -28106 -28107 -28108 -28109 -28110 -28111 -28112 -28113 -28114 -28115 +v -28116 -28117 -28118 -28119 -28120 -28121 -28122 -28123 -28124 -28125 -28126 +v -28127 -28128 -28129 -28130 -28131 -28132 -28133 -28134 -28135 -28136 -28137 +v 28138 -28139 28140 -28141 -28142 -28143 28144 -28145 28146 -28147 -28148 +v -28149 -28150 28151 -28152 28153 -28154 -28155 -28156 -28157 28158 -28159 +v 28160 -28161 -28162 28163 -28164 -28165 -28166 -28167 -28168 -28169 -28170 +v -28171 -28172 -28173 28174 28175 28176 28177 -28178 -28179 -28180 -28181 +v -28182 -28183 -28184 -28185 -28186 -28187 -28188 -28189 -28190 -28191 -28192 +v -28193 -28194 -28195 -28196 -28197 -28198 -28199 -28200 -28201 -28202 -28203 +v -28204 -28205 -28206 -28207 -28208 -28209 -28210 -28211 -28212 -28213 -28214 +v -28215 -28216 -28217 -28218 -28219 -28220 -28221 -28222 -28223 -28224 -28225 +v -28226 -28227 -28228 -28229 -28230 -28231 -28232 -28233 -28234 -28235 -28236 +v -28237 -28238 -28239 -28240 -28241 -28242 -28243 -28244 -28245 -28246 -28247 +v -28248 -28249 -28250 -28251 -28252 -28253 -28254 -28255 -28256 -28257 -28258 +v -28259 -28260 -28261 -28262 -28263 -28264 -28265 -28266 -28267 -28268 -28269 +v -28270 -28271 -28272 -28273 -28274 -28275 -28276 -28277 -28278 -28279 -28280 +v -28281 -28282 -28283 -28284 -28285 -28286 -28287 -28288 -28289 -28290 -28291 +v -28292 -28293 -28294 -28295 -28296 -28297 -28298 -28299 -28300 -28301 -28302 +v -28303 -28304 -28305 -28306 -28307 -28308 -28309 -28310 -28311 -28312 -28313 +v -28314 -28315 -28316 -28317 -28318 -28319 -28320 -28321 -28322 -28323 -28324 +v -28325 -28326 -28327 -28328 -28329 -28330 -28331 -28332 -28333 -28334 -28335 +v -28336 -28337 -28338 28339 -28340 28341 -28342 -28343 -28344 28345 -28346 +v 28347 -28348 -28349 -28350 -28351 28352 -28353 28354 -28355 -28356 -28357 +v -28358 28359 -28360 28361 -28362 -28363 28364 -28365 -28366 -28367 -28368 +v -28369 -28370 -28371 -28372 -28373 -28374 28375 28376 28377 28378 -28379 +v -28380 -28381 -28382 -28383 -28384 -28385 -28386 -28387 -28388 -28389 -28390 +v -28391 -28392 -28393 -28394 -28395 -28396 -28397 -28398 -28399 -28400 -28401 +v -28402 -28403 -28404 -28405 -28406 -28407 -28408 -28409 -28410 -28411 -28412 +v -28413 -28414 -28415 -28416 -28417 -28418 -28419 -28420 -28421 -28422 -28423 +v -28424 -28425 -28426 -28427 -28428 -28429 -28430 -28431 -28432 -28433 -28434 +v -28435 -28436 -28437 -28438 -28439 -28440 -28441 -28442 -28443 -28444 -28445 +v -28446 -28447 -28448 -28449 -28450 -28451 -28452 -28453 -28454 -28455 -28456 +v -28457 -28458 -28459 -28460 -28461 -28462 -28463 -28464 -28465 -28466 -28467 +v -28468 -28469 -28470 -28471 -28472 -28473 -28474 -28475 -28476 -28477 -28478 +v -28479 -28480 -28481 -28482 -28483 -28484 -28485 -28486 -28487 -28488 -28489 +v -28490 -28491 -28492 -28493 -28494 -28495 -28496 -28497 -28498 -28499 -28500 +v -28501 -28502 -28503 -28504 -28505 -28506 -28507 -28508 -28509 -28510 -28511 +v -28512 -28513 -28514 -28515 -28516 -28517 -28518 -28519 -28520 -28521 -28522 +v -28523 -28524 -28525 -28526 -28527 -28528 -28529 -28530 -28531 -28532 -28533 +v -28534 -28535 -28536 -28537 -28538 -28539 28540 -28541 28542 -28543 -28544 +v -28545 28546 -28547 28548 -28549 -28550 -28551 -28552 28553 -28554 28555 +v -28556 -28557 -28558 -28559 28560 -28561 28562 -28563 -28564 28565 -28566 +v -28567 -28568 -28569 -28570 -28571 -28572 -28573 -28574 -28575 28576 28577 +v 28578 28579 -28580 -28581 -28582 -28583 -28584 -28585 -28586 -28587 -28588 +v -28589 -28590 -28591 -28592 -28593 -28594 -28595 -28596 -28597 -28598 -28599 +v -28600 -28601 -28602 -28603 -28604 -28605 -28606 -28607 -28608 28609 -28610 +v 28611 -28612 -28613 -28614 28615 -28616 28617 -28618 -28619 28620 -28621 +v -28622 -28623 -28624 -28625 -28626 28627 28628 28629 28630 -28631 28632 +v -28633 28634 -28635 28636 28637 -28638 -28639 -28640 -28641 -28642 -28643 +v -28644 -28645 -28646 -28647 -28648 -28649 -28650 -28651 -28652 -28653 -28654 +v -28655 -28656 -28657 -28658 -28659 -28660 -28661 -28662 -28663 -28664 -28665 +v -28666 -28667 -28668 -28669 -28670 -28671 -28672 -28673 -28674 -28675 -28676 +v -28677 -28678 -28679 -28680 -28681 -28682 -28683 -28684 -28685 -28686 -28687 +v -28688 -28689 -28690 -28691 -28692 -28693 -28694 -28695 -28696 -28697 -28698 +v -28699 -28700 -28701 -28702 -28703 -28704 -28705 -28706 -28707 -28708 -28709 +v -28710 -28711 -28712 -28713 -28714 -28715 -28716 -28717 -28718 -28719 -28720 +v -28721 -28722 -28723 -28724 -28725 -28726 -28727 -28728 -28729 -28730 -28731 +v -28732 -28733 -28734 -28735 -28736 -28737 -28738 -28739 -28740 -28741 -28742 +v -28743 -28744 -28745 -28746 -28747 -28748 -28749 -28750 -28751 -28752 -28753 +v -28754 -28755 -28756 -28757 -28758 -28759 -28760 -28761 -28762 -28763 -28764 +v -28765 -28766 -28767 -28768 -28769 -28770 -28771 -28772 -28773 -28774 -28775 +v -28776 -28777 -28778 -28779 -28780 -28781 -28782 -28783 -28784 -28785 -28786 +v -28787 -28788 -28789 -28790 -28791 -28792 -28793 -28794 -28795 -28796 -28797 +v -28798 -28799 -28800 -28801 -28802 -28803 -28804 -28805 -28806 -28807 -28808 +v -28809 -28810 -28811 -28812 -28813 -28814 -28815 -28816 -28817 -28818 -28819 +v -28820 -28821 -28822 -28823 -28824 -28825 -28826 -28827 -28828 -28829 -28830 +v -28831 -28832 -28833 -28834 -28835 -28836 -28837 -28838 -28839 -28840 -28841 +v -28842 -28843 -28844 -28845 -28846 -28847 -28848 -28849 -28850 -28851 -28852 +v -28853 -28854 -28855 -28856 -28857 -28858 -28859 -28860 -28861 -28862 -28863 +v -28864 -28865 -28866 -28867 -28868 -28869 -28870 -28871 -28872 -28873 -28874 +v -28875 -28876 -28877 -28878 -28879 -28880 -28881 -28882 -28883 -28884 -28885 +v -28886 -28887 -28888 -28889 -28890 -28891 -28892 -28893 -28894 -28895 -28896 +v -28897 -28898 -28899 -28900 -28901 -28902 -28903 -28904 -28905 -28906 -28907 +v -28908 -28909 -28910 -28911 -28912 -28913 -28914 -28915 -28916 -28917 -28918 +v -28919 -28920 -28921 -28922 -28923 -28924 -28925 -28926 -28927 -28928 -28929 +v -28930 -28931 -28932 -28933 -28934 -28935 -28936 -28937 -28938 -28939 -28940 +v -28941 -28942 -28943 -28944 -28945 -28946 -28947 -28948 -28949 -28950 -28951 +v -28952 -28953 -28954 -28955 -28956 -28957 -28958 -28959 -28960 -28961 -28962 +v -28963 -28964 -28965 -28966 -28967 -28968 -28969 -28970 -28971 -28972 -28973 +v -28974 -28975 -28976 -28977 -28978 -28979 -28980 -28981 -28982 -28983 -28984 +v -28985 -28986 -28987 -28988 -28989 -28990 -28991 -28992 -28993 -28994 -28995 +v -28996 -28997 -28998 -28999 -29000 -29001 -29002 -29003 -29004 -29005 -29006 +v -29007 -29008 -29009 -29010 -29011 -29012 -29013 -29014 -29015 -29016 -29017 +v -29018 -29019 -29020 -29021 -29022 -29023 -29024 -29025 -29026 -29027 -29028 +v -29029 -29030 -29031 -29032 -29033 -29034 -29035 -29036 -29037 -29038 -29039 +v -29040 -29041 -29042 -29043 -29044 -29045 -29046 -29047 -29048 -29049 -29050 +v -29051 -29052 -29053 -29054 -29055 -29056 -29057 -29058 -29059 -29060 -29061 +v -29062 -29063 -29064 -29065 -29066 -29067 -29068 -29069 -29070 -29071 -29072 +v -29073 -29074 -29075 -29076 -29077 -29078 -29079 -29080 -29081 -29082 -29083 +v -29084 -29085 -29086 -29087 -29088 -29089 -29090 -29091 -29092 -29093 -29094 +v -29095 -29096 -29097 -29098 -29099 -29100 -29101 -29102 -29103 -29104 -29105 +v -29106 -29107 -29108 -29109 -29110 -29111 -29112 -29113 -29114 -29115 -29116 +v -29117 -29118 -29119 -29120 -29121 -29122 -29123 -29124 -29125 -29126 -29127 +v -29128 -29129 -29130 -29131 -29132 -29133 -29134 -29135 -29136 -29137 -29138 +v -29139 -29140 -29141 -29142 -29143 -29144 -29145 -29146 -29147 -29148 -29149 +v -29150 -29151 -29152 -29153 -29154 -29155 -29156 -29157 -29158 -29159 -29160 +v -29161 -29162 -29163 -29164 -29165 -29166 -29167 -29168 -29169 -29170 -29171 +v -29172 -29173 -29174 -29175 -29176 -29177 -29178 -29179 -29180 -29181 -29182 +v -29183 -29184 -29185 -29186 -29187 -29188 -29189 -29190 -29191 -29192 -29193 +v 29194 -29195 29196 -29197 -29198 -29199 29200 -29201 29202 -29203 -29204 +v -29205 29206 -29207 29208 -29209 -29210 -29211 29212 -29213 29214 -29215 +v -29216 -29217 29218 -29219 29220 -29221 -29222 -29223 29224 -29225 29226 +v -29227 -29228 29229 -29230 -29231 -29232 -29233 -29234 -29235 -29236 -29237 +v -29238 -29239 -29240 -29241 -29242 -29243 29244 29245 29246 29247 29248 +v -29249 -29250 -29251 -29252 -29253 -29254 29255 -29256 -29257 -29258 -29259 +v -29260 -29261 -29262 -29263 -29264 -29265 -29266 -29267 -29268 -29269 -29270 +v -29271 -29272 -29273 -29274 -29275 -29276 -29277 -29278 -29279 -29280 -29281 +v -29282 -29283 -29284 -29285 -29286 -29287 -29288 -29289 -29290 -29291 -29292 +v -29293 -29294 -29295 -29296 -29297 -29298 -29299 -29300 -29301 -29302 -29303 +v -29304 -29305 -29306 -29307 -29308 -29309 -29310 -29311 -29312 -29313 -29314 +v -29315 -29316 -29317 -29318 -29319 -29320 -29321 -29322 -29323 -29324 -29325 +v -29326 -29327 -29328 -29329 -29330 -29331 -29332 -29333 -29334 -29335 -29336 +v -29337 -29338 -29339 -29340 -29341 -29342 -29343 -29344 -29345 -29346 -29347 +v -29348 -29349 -29350 -29351 -29352 -29353 -29354 -29355 -29356 -29357 -29358 +v -29359 -29360 -29361 -29362 -29363 -29364 -29365 -29366 -29367 -29368 -29369 +v -29370 -29371 -29372 -29373 -29374 -29375 -29376 -29377 -29378 -29379 -29380 +v -29381 -29382 -29383 -29384 29385 -29386 29387 -29388 -29389 -29390 29391 +v -29392 29393 -29394 -29395 -29396 29397 -29398 29399 -29400 -29401 -29402 +v 29403 -29404 29405 -29406 -29407 -29408 29409 -29410 29411 -29412 -29413 +v 29414 -29415 -29416 -29417 -29418 -29419 -29420 -29421 -29422 -29423 -29424 +v -29425 29426 29427 29428 -29429 -29430 -29431 -29432 -29433 -29434 -29435 +v -29436 -29437 -29438 -29439 -29440 -29441 -29442 -29443 -29444 -29445 -29446 +v -29447 -29448 -29449 -29450 -29451 -29452 -29453 -29454 -29455 -29456 -29457 +v -29458 -29459 -29460 -29461 -29462 -29463 -29464 -29465 -29466 -29467 -29468 +v -29469 -29470 -29471 -29472 -29473 -29474 -29475 -29476 -29477 -29478 -29479 +v -29480 -29481 29482 -29483 29484 -29485 -29486 29487 -29488 29489 -29490 +v -29491 -29492 29493 -29494 29495 -29496 -29497 -29498 29499 -29500 29501 +v -29502 -29503 29504 -29505 -29506 -29507 -29508 -29509 -29510 -29511 -29512 +v -29513 -29514 29515 29516 29517 29518 -29519 -29520 -29521 -29522 -29523 +v -29524 -29525 -29526 -29527 -29528 -29529 -29530 -29531 -29532 -29533 -29534 +v -29535 -29536 -29537 -29538 -29539 -29540 -29541 -29542 -29543 -29544 -29545 +v -29546 -29547 -29548 -29549 -29550 -29551 -29552 -29553 -29554 -29555 -29556 +v -29557 -29558 -29559 -29560 -29561 -29562 -29563 -29564 -29565 -29566 -29567 +v -29568 -29569 -29570 -29571 -29572 -29573 -29574 -29575 -29576 -29577 -29578 +v -29579 -29580 -29581 -29582 -29583 -29584 -29585 -29586 -29587 -29588 -29589 +v -29590 -29591 -29592 -29593 -29594 -29595 -29596 -29597 -29598 -29599 -29600 +v -29601 -29602 -29603 -29604 -29605 -29606 -29607 -29608 -29609 -29610 -29611 +v -29612 -29613 29614 -29615 29616 -29617 -29618 29619 -29620 29621 -29622 +v -29623 29624 -29625 29626 -29627 -29628 -29629 29630 -29631 29632 -29633 +v -29634 -29635 29636 -29637 29638 -29639 -29640 29641 -29642 -29643 -29644 +v -29645 -29646 -29647 -29648 -29649 -29650 -29651 -29652 29653 29654 29655 +v -29656 -29657 -29658 -29659 -29660 -29661 -29662 -29663 -29664 -29665 -29666 +v -29667 -29668 29669 -29670 -29671 29672 -29673 -29674 -29675 -29676 -29677 +v -29678 29679 29680 29681 -29682 -29683 -29684 -29685 -29686 -29687 -29688 +v -29689 -29690 -29691 -29692 -29693 -29694 -29695 29696 -29697 -29698 29699 +v -29700 -29701 -29702 -29703 -29704 29705 29706 29707 -29708 -29709 -29710 +v -29711 -29712 -29713 -29714 -29715 -29716 29717 29718 -29719 29720 -29721 +v -29722 29723 -29724 -29725 -29726 -29727 -29728 -29729 29730 -29731 -29732 +v -29733 -29734 -29735 -29736 -29737 -29738 -29739 -29740 -29741 -29742 -29743 +v -29744 29745 -29746 -29747 29748 -29749 -29750 -29751 -29752 -29753 29754 +v -29755 29756 -29757 -29758 -29759 29760 -29761 29762 29763 29764 29765 29766 +v -29767 -29768 29769 29770 29771 -29772 -29773 -29774 -29775 -29776 -29777 +v -29778 -29779 -29780 29781 29782 29783 -29784 -29785 -29786 -29787 -29788 +v -29789 -29790 -29791 -29792 -29793 -29794 -29795 -29796 -29797 -29798 -29799 +v -29800 -29801 -29802 -29803 -29804 -29805 29806 -29807 -29808 -29809 -29810 +v -29811 -29812 -29813 29814 -29815 29816 -29817 -29818 -29819 29820 -29821 +v 29822 -29823 -29824 29825 -29826 -29827 -29828 -29829 -29830 -29831 29832 +v 29833 29834 -29835 -29836 -29837 -29838 -29839 -29840 -29841 -29842 -29843 +v -29844 -29845 -29846 -29847 -29848 -29849 -29850 -29851 -29852 -29853 -29854 +v -29855 -29856 29857 -29858 -29859 -29860 -29861 -29862 -29863 -29864 29865 +v -29866 29867 -29868 -29869 -29870 29871 -29872 29873 -29874 -29875 29876 +v -29877 -29878 -29879 -29880 -29881 -29882 29883 29884 29885 -29886 -29887 +v -29888 -29889 -29890 -29891 -29892 -29893 -29894 -29895 -29896 -29897 -29898 +v -29899 -29900 -29901 -29902 -29903 -29904 -29905 -29906 -29907 29908 -29909 +v -29910 -29911 -29912 -29913 -29914 -29915 29916 -29917 29918 -29919 -29920 +v -29921 29922 -29923 29924 -29925 -29926 29927 -29928 -29929 -29930 -29931 +v -29932 -29933 29934 29935 29936 -29937 -29938 -29939 -29940 -29941 -29942 +v -29943 -29944 -29945 -29946 -29947 -29948 -29949 -29950 -29951 -29952 -29953 +v -29954 -29955 -29956 -29957 -29958 -29959 -29960 -29961 -29962 -29963 -29964 +v -29965 -29966 -29967 -29968 -29969 -29970 -29971 -29972 -29973 -29974 -29975 +v -29976 -29977 -29978 -29979 -29980 -29981 -29982 -29983 -29984 -29985 -29986 +v -29987 -29988 -29989 -29990 -29991 -29992 -29993 -29994 -29995 -29996 -29997 +v -29998 -29999 -30000 -30001 -30002 -30003 -30004 -30005 -30006 -30007 -30008 +v -30009 -30010 -30011 -30012 -30013 -30014 -30015 -30016 -30017 -30018 -30019 +v -30020 -30021 -30022 -30023 -30024 -30025 -30026 -30027 -30028 -30029 30030 +v -30031 -30032 -30033 -30034 -30035 -30036 -30037 -30038 -30039 -30040 -30041 +v -30042 -30043 -30044 -30045 -30046 -30047 -30048 -30049 -30050 -30051 -30052 +v -30053 -30054 -30055 -30056 -30057 -30058 -30059 -30060 -30061 -30062 -30063 +v -30064 -30065 -30066 -30067 -30068 -30069 -30070 -30071 -30072 -30073 -30074 +v -30075 -30076 -30077 -30078 -30079 -30080 -30081 -30082 -30083 -30084 -30085 +v -30086 -30087 -30088 -30089 -30090 -30091 -30092 -30093 -30094 -30095 -30096 +v -30097 -30098 30099 -30100 30101 -30102 -30103 -30104 30105 -30106 30107 +v -30108 -30109 -30110 -30111 30112 -30113 30114 -30115 -30116 -30117 -30118 +v 30119 -30120 30121 -30122 -30123 30124 -30125 -30126 -30127 -30128 -30129 +v -30130 -30131 -30132 -30133 -30134 30135 30136 30137 -30138 -30139 -30140 +v -30141 -30142 -30143 -30144 -30145 -30146 -30147 -30148 -30149 -30150 -30151 +v -30152 -30153 -30154 -30155 -30156 -30157 -30158 -30159 -30160 -30161 -30162 +v -30163 -30164 -30165 -30166 -30167 -30168 -30169 -30170 -30171 -30172 -30173 +v -30174 -30175 -30176 -30177 -30178 -30179 -30180 -30181 -30182 -30183 -30184 +v -30185 -30186 -30187 -30188 -30189 -30190 -30191 -30192 -30193 -30194 -30195 +v -30196 -30197 -30198 -30199 -30200 -30201 -30202 -30203 -30204 -30205 -30206 +v -30207 -30208 -30209 -30210 -30211 -30212 -30213 -30214 -30215 -30216 -30217 +v -30218 -30219 -30220 -30221 -30222 -30223 -30224 -30225 -30226 -30227 -30228 +v -30229 -30230 30231 -30232 -30233 -30234 -30235 -30236 -30237 -30238 -30239 +v -30240 -30241 -30242 -30243 -30244 -30245 -30246 -30247 -30248 -30249 -30250 +v -30251 -30252 -30253 -30254 -30255 -30256 -30257 -30258 -30259 -30260 -30261 +v -30262 -30263 -30264 -30265 -30266 -30267 -30268 -30269 -30270 -30271 -30272 +v -30273 -30274 -30275 -30276 -30277 -30278 -30279 -30280 -30281 -30282 -30283 +v -30284 -30285 -30286 -30287 -30288 -30289 -30290 -30291 -30292 -30293 -30294 +v -30295 -30296 -30297 -30298 -30299 30300 -30301 30302 -30303 -30304 -30305 +v 30306 -30307 30308 -30309 -30310 -30311 -30312 30313 -30314 30315 -30316 +v -30317 -30318 -30319 30320 -30321 30322 -30323 -30324 30325 -30326 -30327 +v -30328 -30329 -30330 -30331 -30332 -30333 -30334 -30335 30336 30337 30338 +v -30339 -30340 -30341 -30342 -30343 -30344 -30345 -30346 -30347 -30348 -30349 +v -30350 -30351 -30352 -30353 -30354 -30355 -30356 -30357 -30358 -30359 -30360 +v -30361 -30362 -30363 -30364 -30365 -30366 -30367 -30368 -30369 -30370 -30371 +v -30372 -30373 -30374 -30375 -30376 -30377 -30378 -30379 -30380 -30381 -30382 +v -30383 -30384 -30385 -30386 -30387 -30388 -30389 -30390 -30391 -30392 -30393 +v -30394 -30395 -30396 -30397 -30398 -30399 -30400 -30401 -30402 -30403 -30404 +v -30405 -30406 -30407 -30408 -30409 -30410 -30411 -30412 -30413 -30414 -30415 +v -30416 -30417 -30418 -30419 -30420 -30421 -30422 -30423 -30424 -30425 -30426 +v -30427 -30428 -30429 -30430 -30431 30432 -30433 -30434 -30435 -30436 -30437 +v -30438 -30439 -30440 -30441 -30442 -30443 -30444 -30445 -30446 -30447 -30448 +v -30449 -30450 -30451 -30452 -30453 -30454 -30455 -30456 -30457 -30458 -30459 +v -30460 -30461 -30462 -30463 -30464 -30465 -30466 -30467 -30468 -30469 -30470 +v -30471 -30472 -30473 -30474 -30475 -30476 -30477 -30478 -30479 -30480 -30481 +v -30482 -30483 -30484 -30485 -30486 -30487 -30488 -30489 -30490 -30491 -30492 +v -30493 -30494 -30495 -30496 -30497 -30498 -30499 -30500 30501 -30502 30503 +v -30504 -30505 -30506 30507 -30508 30509 -30510 -30511 -30512 -30513 30514 +v -30515 30516 -30517 -30518 -30519 -30520 30521 -30522 30523 -30524 -30525 +v 30526 -30527 -30528 -30529 -30530 -30531 -30532 -30533 -30534 -30535 -30536 +v 30537 30538 30539 -30540 -30541 -30542 -30543 -30544 -30545 -30546 -30547 +v -30548 -30549 -30550 -30551 -30552 -30553 -30554 -30555 -30556 -30557 -30558 +v -30559 -30560 -30561 -30562 -30563 -30564 -30565 -30566 -30567 -30568 -30569 +v -30570 -30571 -30572 -30573 -30574 -30575 -30576 -30577 -30578 -30579 -30580 +v -30581 -30582 -30583 -30584 -30585 -30586 -30587 -30588 -30589 -30590 -30591 +v -30592 -30593 -30594 -30595 -30596 -30597 -30598 -30599 -30600 -30601 -30602 +v -30603 -30604 -30605 -30606 -30607 -30608 -30609 -30610 -30611 -30612 -30613 +v -30614 -30615 -30616 -30617 -30618 -30619 -30620 -30621 -30622 -30623 -30624 +v -30625 -30626 -30627 -30628 -30629 -30630 -30631 -30632 30633 -30634 -30635 +v -30636 -30637 -30638 -30639 -30640 -30641 -30642 -30643 -30644 -30645 -30646 +v -30647 -30648 -30649 -30650 -30651 -30652 -30653 -30654 -30655 -30656 -30657 +v -30658 -30659 -30660 -30661 -30662 -30663 -30664 -30665 -30666 -30667 -30668 +v -30669 -30670 -30671 -30672 -30673 -30674 -30675 -30676 -30677 -30678 -30679 +v -30680 -30681 -30682 -30683 -30684 -30685 -30686 -30687 -30688 -30689 -30690 +v -30691 -30692 -30693 -30694 -30695 -30696 -30697 -30698 -30699 -30700 -30701 +v 30702 -30703 30704 -30705 -30706 -30707 30708 -30709 30710 -30711 -30712 +v -30713 -30714 30715 -30716 30717 -30718 -30719 -30720 -30721 30722 -30723 +v 30724 -30725 -30726 30727 -30728 -30729 -30730 -30731 -30732 -30733 -30734 +v -30735 -30736 -30737 30738 30739 30740 -30741 -30742 -30743 -30744 -30745 +v -30746 -30747 -30748 -30749 -30750 -30751 -30752 -30753 -30754 -30755 -30756 +v -30757 -30758 -30759 -30760 -30761 -30762 30763 -30764 -30765 -30766 -30767 +v -30768 -30769 -30770 30771 -30772 30773 -30774 -30775 -30776 30777 -30778 +v 30779 -30780 -30781 30782 -30783 -30784 -30785 -30786 -30787 -30788 30789 +v 30790 30791 30792 -30793 -30794 30795 -30796 -30797 30798 -30799 30800 +v -30801 -30802 30803 -30804 30805 30806 30807 -30808 -30809 30810 -30811 +v -30812 -30813 -30814 -30815 -30816 -30817 -30818 30819 30820 30821 30822 +v -30823 30824 -30825 -30826 30827 -30828 30829 -30830 -30831 -30832 30833 +v 30834 30835 30836 30837 -30838 30839 -30840 30841 30842 -30843 -30844 -30845 +v 30846 -30847 -30848 -30849 30850 30851 30852 30853 -30854 -30855 -30856 +v -30857 30858 -30859 30860 30861 30862 30863 -30864 -30865 30866 30867 30868 +v 30869 -30870 -30871 30872 30873 30874 -30875 -30876 -30877 -30878 -30879 +v -30880 -30881 -30882 30883 30884 30885 30886 -30887 30888 -30889 -30890 +v -30891 -30892 -30893 -30894 -30895 -30896 -30897 30898 30899 -30900 -30901 +v 30902 -30903 -30904 30905 30906 30907 30908 -30909 -30910 -30911 -30912 +v 30913 30914 30915 30916 -30917 -30918 -30919 -30920 30921 30922 30923 30924 +v -30925 -30926 -30927 -30928 -30929 -30930 -30931 -30932 -30933 -30934 -30935 +v -30936 -30937 -30938 -30939 -30940 -30941 -30942 -30943 -30944 30945 -30946 +v 30947 -30948 -30949 -30950 30951 -30952 30953 -30954 -30955 30956 -30957 +v -30958 -30959 -30960 -30961 -30962 30963 30964 30965 30966 -30967 -30968 +v -30969 -30970 -30971 -30972 -30973 -30974 -30975 -30976 -30977 -30978 -30979 +v -30980 -30981 -30982 -30983 -30984 30985 -30986 30987 -30988 -30989 -30990 +v 30991 -30992 30993 -30994 -30995 30996 -30997 -30998 -30999 -31000 -31001 +v -31002 31003 31004 31005 31006 -31007 -31008 -31009 -31010 31011 31012 31013 +v 31014 -31015 -31016 -31017 -31018 -31019 -31020 -31021 -31022 -31023 -31024 +v -31025 -31026 -31027 -31028 -31029 -31030 -31031 -31032 -31033 -31034 -31035 +v -31036 -31037 -31038 -31039 -31040 31041 -31042 31043 -31044 -31045 -31046 +v -31047 31048 -31049 31050 -31051 -31052 31053 -31054 31055 -31056 -31057 +v -31058 -31059 -31060 -31061 -31062 -31063 31064 31065 31066 31067 31068 +v 31069 -31070 -31071 -31072 -31073 -31074 -31075 -31076 -31077 -31078 -31079 +v -31080 -31081 -31082 -31083 -31084 -31085 -31086 -31087 -31088 -31089 -31090 +v -31091 -31092 -31093 -31094 -31095 31096 -31097 31098 -31099 -31100 -31101 +v -31102 31103 -31104 31105 -31106 -31107 31108 -31109 31110 -31111 -31112 +v -31113 -31114 -31115 -31116 -31117 -31118 31119 31120 31121 31122 -31123 +v -31124 31125 -31126 31127 -31128 31129 -31130 -31131 -31132 31133 31134 +v 31135 31136 31137 -31138 31139 -31140 -31141 -31142 31143 -31144 31145 +v -31146 -31147 -31148 31149 31150 31151 31152 31153 31154 31155 -31156 31157 +v -31158 31159 -31160 -31161 -31162 -31163 -31164 31165 -31166 31167 31168 +v 31169 31170 -31171 -31172 31173 31174 31175 31176 -31177 -31178 31179 -31180 +v -31181 31182 -31183 -31184 -31185 -31186 -31187 -31188 -31189 31190 31191 +v 31192 31193 -31194 -31195 31196 31197 -31198 -31199 31200 31201 -31202 +v -31203 31204 31205 -31206 31207 -31208 31209 -31210 -31211 -31212 -31213 +v -31214 -31215 31216 31217 -31218 31219 -31220 31221 -31222 -31223 -31224 +v -31225 -31226 -31227 31228 31229 -31230 -31231 31232 31233 -31234 31235 +v -31236 31237 -31238 -31239 -31240 -31241 -31242 -31243 31244 -31245 -31246 +v 31247 -31248 31249 -31250 31251 -31252 -31253 -31254 31255 31256 31257 31258 +v -31259 -31260 31261 31262 -31263 -31264 31265 31266 -31267 -31268 -31269 +v -31270 -31271 31272 31273 31274 31275 -31276 31277 31278 31279 -31280 -31281 +v 31282 31283 -31284 -31285 -31286 31287 -31288 -31289 -31290 -31291 31292 +v -31293 31294 -31295 -31296 31297 -31298 31299 31300 31301 -31302 31303 31304 +v 31305 -31306 -31307 -31308 -31309 -31310 -31311 -31312 31313 31314 31315 +v -31316 -31317 -31318 -31319 -31320 -31321 -31322 31323 -31324 -31325 -31326 +v -31327 -31328 -31329 -31330 -31331 -31332 -31333 -31334 -31335 31336 -31337 +v -31338 -31339 -31340 -31341 -31342 -31343 -31344 31345 31346 -31347 31348 +v 31349 -31350 -31351 31352 -31353 -31354 -31355 -31356 -31357 -31358 -31359 +v -31360 -31361 -31362 -31363 -31364 -31365 -31366 -31367 -31368 -31369 -31370 +v -31371 -31372 -31373 -31374 -31375 31376 31377 31378 31379 31380 -31381 +v -31382 -31383 -31384 -31385 -31386 31387 -31388 -31389 31390 -31391 -31392 +v -31393 31394 31395 31396 -31397 31398 -31399 -31400 -31401 -31402 -31403 +v -31404 31405 -31406 31407 -31408 -31409 31410 -31411 31412 -31413 -31414 +v -31415 -31416 31417 -31418 31419 31420 31421 31422 31423 -31424 -31425 31426 +v 31427 -31428 31429 -31430 -31431 31432 -31433 -31434 31435 -31436 -31437 +v -31438 -31439 -31440 -31441 -31442 -31443 -31444 -31445 -31446 31447 31448 +v 31449 -31450 -31451 -31452 -31453 -31454 -31455 -31456 -31457 -31458 -31459 +v -31460 -31461 -31462 -31463 -31464 -31465 -31466 -31467 -31468 -31469 -31470 +v -31471 -31472 31473 31474 -31475 31476 -31477 -31478 -31479 -31480 -31481 +v -31482 -31483 -31484 -31485 -31486 -31487 31488 31489 31490 31491 31492 +v 31493 31494 31495 -31496 -31497 -31498 -31499 31500 -31501 -31502 31503 +v -31504 31505 -31506 -31507 -31508 -31509 -31510 -31511 -31512 -31513 -31514 +v -31515 -31516 -31517 -31518 -31519 -31520 -31521 -31522 -31523 -31524 -31525 +v -31526 31527 31528 31529 31530 31531 31532 31533 31534 31535 31536 31537 +v -31538 -31539 -31540 -31541 -31542 -31543 31544 -31545 31546 -31547 -31548 +v -31549 31550 -31551 31552 -31553 31554 31555 -31556 -31557 31558 31559 +v -31560 31561 -31562 31563 -31564 31565 -31566 -31567 31568 -31569 -31570 +v -31571 -31572 -31573 -31574 -31575 -31576 -31577 -31578 31579 31580 31581 +v -31582 -31583 -31584 -31585 31586 -31587 -31588 -31589 31590 -31591 -31592 +v -31593 -31594 -31595 -31596 -31597 -31598 -31599 -31600 -31601 -31602 -31603 +v -31604 31605 31606 31607 -31608 -31609 -31610 31611 31612 31613 31614 -31615 +v -31616 31617 -31618 -31619 -31620 -31621 -31622 -31623 -31624 -31625 -31626 +v -31627 -31628 -31629 -31630 -31631 -31632 -31633 -31634 -31635 -31636 -31637 +v -31638 -31639 31640 31641 31642 31643 -31644 -31645 -31646 -31647 31648 +v -31649 -31650 31651 -31652 -31653 -31654 31655 -31656 -31657 -31658 -31659 +v -31660 -31661 -31662 -31663 -31664 31665 31666 -31667 -31668 31669 31670 +v 31671 31672 -31673 -31674 -31675 -31676 -31677 31678 -31679 31680 -31681 +v -31682 31683 -31684 31685 -31686 -31687 -31688 31689 -31690 31691 31692 +v 31693 31694 -31695 -31696 31697 -31698 31699 -31700 31701 -31702 -31703 +v 31704 -31705 -31706 31707 -31708 -31709 -31710 -31711 -31712 -31713 -31714 +v -31715 -31716 -31717 -31718 31719 31720 31721 31722 -31723 31724 31725 31726 +v -31727 -31728 -31729 31730 31731 -31732 -31733 -31734 -31735 -31736 -31737 +v -31738 -31739 31740 -31741 -31742 -31743 -31744 -31745 -31746 -31747 31748 +v -31749 -31750 -31751 -31752 -31753 -31754 31755 31756 31757 31758 -31759 +v -31760 31761 -31762 31763 -31764 31765 -31766 -31767 -31768 31769 -31770 +v -31771 -31772 -31773 -31774 -31775 -31776 31777 31778 31779 31780 31781 +v 31782 31783 31784 31785 31786 31787 -31788 -31789 -31790 -31791 -31792 +v -31793 -31794 -31795 -31796 -31797 31798 -31799 -31800 -31801 -31802 -31803 +v -31804 -31805 -31806 -31807 -31808 31809 -31810 31811 31812 31813 -31814 +v -31815 31816 -31817 -31818 31819 31820 -31821 -31822 -31823 -31824 31825 +v -31826 31827 -31828 -31829 -31830 -31831 -31832 -31833 -31834 31835 31836 +v 31837 31838 31839 31840 -31841 -31842 -31843 31844 -31845 -31846 31847 +v -31848 -31849 -31850 -31851 -31852 -31853 -31854 -31855 -31856 31857 31858 +v 31859 31860 31861 31862 31863 31864 31865 31866 31867 -31868 -31869 -31870 +v -31871 31872 -31873 31874 -31875 -31876 -31877 -31878 -31879 -31880 -31881 +v -31882 31883 -31884 31885 -31886 -31887 31888 -31889 31890 31891 31892 +v -31893 -31894 31895 -31896 -31897 31898 -31899 31900 31901 -31902 -31903 +v 31904 -31905 31906 -31907 -31908 31909 -31910 -31911 -31912 -31913 -31914 +v -31915 -31916 -31917 -31918 -31919 -31920 31921 31922 31923 31924 -31925 +v 31926 -31927 -31928 -31929 -31930 -31931 -31932 -31933 -31934 -31935 -31936 +v -31937 31938 31939 -31940 31941 -31942 31943 -31944 -31945 -31946 -31947 +v -31948 31949 -31950 -31951 -31952 -31953 -31954 -31955 -31956 -31957 -31958 +v -31959 -31960 31961 31962 -31963 31964 -31965 -31966 -31967 31968 -31969 +v 31970 -31971 -31972 -31973 -31974 -31975 -31976 -31977 -31978 -31979 -31980 +v 31981 31982 -31983 31984 -31985 31986 -31987 -31988 -31989 -31990 -31991 +v 31992 -31993 -31994 -31995 -31996 -31997 -31998 -31999 -32000 -32001 -32002 +v -32003 32004 32005 -32006 -32007 32008 -32009 -32010 32011 32012 32013 32014 +v -32015 -32016 -32017 -32018 -32019 -32020 -32021 -32022 -32023 -32024 -32025 +v -32026 -32027 -32028 -32029 -32030 -32031 -32032 32033 -32034 32035 -32036 +v -32037 -32038 32039 -32040 32041 -32042 -32043 32044 -32045 -32046 -32047 +v -32048 -32049 -32050 32051 32052 32053 32054 -32055 -32056 -32057 -32058 +v -32059 -32060 -32061 -32062 -32063 -32064 -32065 -32066 -32067 -32068 -32069 +v -32070 32071 -32072 32073 -32074 -32075 -32076 32077 -32078 32079 -32080 +v -32081 32082 -32083 -32084 -32085 -32086 -32087 -32088 32089 32090 32091 +v 32092 -32093 -32094 -32095 -32096 -32097 -32098 -32099 -32100 -32101 -32102 +v -32103 -32104 -32105 -32106 -32107 -32108 32109 -32110 32111 -32112 -32113 +v -32114 32115 -32116 32117 -32118 -32119 32120 -32121 -32122 -32123 -32124 +v -32125 -32126 32127 32128 32129 32130 -32131 -32132 -32133 -32134 32135 +v 32136 32137 32138 -32139 -32140 -32141 -32142 -32143 -32144 -32145 -32146 +v -32147 -32148 -32149 -32150 -32151 -32152 -32153 -32154 -32155 -32156 -32157 +v -32158 -32159 32160 -32161 32162 -32163 -32164 -32165 -32166 32167 -32168 +v 32169 -32170 -32171 32172 -32173 -32174 -32175 -32176 -32177 -32178 32179 +v 32180 32181 32182 32183 32184 -32185 -32186 -32187 -32188 -32189 -32190 +v -32191 -32192 -32193 -32194 -32195 -32196 32197 -32198 -32199 -32200 -32201 +v 32202 32203 32204 32205 -32206 -32207 32208 -32209 32210 -32211 32212 -32213 +v -32214 -32215 32216 32217 32218 32219 -32220 -32221 -32222 32223 32224 +v -32225 -32226 32227 32228 -32229 -32230 -32231 -32232 -32233 32234 32235 +v 32236 32237 -32238 -32239 32240 32241 -32242 32243 -32244 32245 -32246 +v -32247 -32248 -32249 -32250 -32251 32252 32253 -32254 32255 -32256 32257 +v -32258 -32259 -32260 -32261 -32262 -32263 32264 32265 -32266 32267 -32268 +v 32269 -32270 -32271 -32272 -32273 -32274 -32275 32276 32277 -32278 -32279 +v 32280 32281 -32282 -32283 32284 -32285 -32286 32287 -32288 32289 -32290 +v 32291 -32292 -32293 -32294 32295 32296 32297 32298 32299 -32300 32301 32302 +v 32303 -32304 -32305 -32306 32307 32308 -32309 -32310 -32311 -32312 -32313 +v -32314 -32315 -32316 32317 -32318 -32319 -32320 -32321 -32322 -32323 -32324 +v -32325 32326 32327 32328 -32329 -32330 32331 32332 -32333 32334 -32335 +v -32336 -32337 32338 -32339 -32340 -32341 -32342 -32343 -32344 -32345 32346 +v 32347 32348 32349 32350 32351 32352 32353 32354 32355 32356 -32357 -32358 +v -32359 -32360 -32361 -32362 -32363 -32364 32365 -32366 32367 -32368 -32369 +v 32370 -32371 32372 32373 32374 -32375 -32376 32377 -32378 -32379 32380 +v -32381 32382 32383 -32384 -32385 32386 -32387 32388 -32389 -32390 32391 +v -32392 -32393 -32394 -32395 -32396 -32397 -32398 -32399 -32400 -32401 -32402 +v 32403 32404 32405 32406 -32407 -32408 32409 32410 -32411 -32412 -32413 +v -32414 -32415 -32416 -32417 -32418 -32419 -32420 -32421 -32422 -32423 -32424 +v -32425 -32426 -32427 -32428 -32429 -32430 -32431 -32432 -32433 -32434 -32435 +v -32436 -32437 -32438 -32439 -32440 -32441 -32442 -32443 -32444 -32445 -32446 +v -32447 -32448 -32449 -32450 -32451 -32452 -32453 -32454 -32455 -32456 -32457 +v -32458 -32459 -32460 -32461 -32462 -32463 32464 -32465 -32466 32467 -32468 +v 32469 -32470 -32471 -32472 -32473 -32474 -32475 -32476 -32477 -32478 -32479 +v -32480 -32481 -32482 -32483 -32484 -32485 -32486 -32487 -32488 -32489 -32490 +v -32491 -32492 -32493 -32494 -32495 -32496 -32497 -32498 -32499 -32500 -32501 +v -32502 -32503 -32504 -32505 -32506 -32507 -32508 -32509 -32510 -32511 -32512 +v -32513 -32514 -32515 -32516 -32517 -32518 -32519 -32520 -32521 -32522 -32523 +v -32524 -32525 -32526 32527 -32528 32529 -32530 -32531 -32532 32533 -32534 +v 32535 -32536 -32537 -32538 -32539 32540 -32541 32542 -32543 -32544 -32545 +v -32546 32547 -32548 32549 -32550 -32551 32552 -32553 -32554 -32555 -32556 +v -32557 -32558 -32559 -32560 -32561 -32562 32563 32564 32565 32566 -32567 +v -32568 -32569 32570 -32571 -32572 -32573 -32574 -32575 -32576 -32577 -32578 +v -32579 -32580 -32581 -32582 -32583 -32584 -32585 -32586 -32587 -32588 -32589 +v 32590 -32591 32592 -32593 -32594 32595 -32596 -32597 -32598 -32599 32600 +v 32601 32602 32603 -32604 -32605 32606 -32607 -32608 32609 32610 32611 32612 +v -32613 -32614 -32615 -32616 -32617 -32618 -32619 -32620 -32621 -32622 -32623 +v -32624 32625 -32626 -32627 -32628 -32629 -32630 -32631 -32632 -32633 -32634 +v -32635 -32636 32637 -32638 -32639 -32640 -32641 -32642 -32643 -32644 32645 +v -32646 -32647 32648 -32649 32650 -32651 32652 -32653 -32654 -32655 -32656 +v -32657 -32658 32659 32660 32661 -32662 32663 -32664 -32665 32666 -32667 +v -32668 -32669 -32670 -32671 32672 32673 32674 32675 32676 -32677 -32678 +v -32679 -32680 32681 -32682 -32683 -32684 -32685 -32686 -32687 -32688 -32689 +v -32690 -32691 32692 32693 -32694 -32695 -32696 -32697 -32698 -32699 -32700 +v 32701 -32702 -32703 -32704 -32705 -32706 -32707 -32708 -32709 32710 -32711 +v -32712 32713 -32714 32715 -32716 32717 -32718 -32719 32720 -32721 -32722 +v 32723 32724 32725 32726 32727 -32728 -32729 -32730 -32731 -32732 -32733 +v 32734 32735 -32736 -32737 -32738 -32739 -32740 -32741 -32742 32743 -32744 +v -32745 -32746 -32747 -32748 -32749 -32750 -32751 -32752 -32753 32754 32755 +v 32756 -32757 -32758 -32759 -32760 -32761 -32762 -32763 -32764 -32765 -32766 +v -32767 32768 -32769 -32770 -32771 -32772 -32773 -32774 -32775 32776 -32777 +v 32778 -32779 -32780 -32781 32782 -32783 32784 32785 32786 32787 32788 -32789 +v -32790 32791 -32792 -32793 -32794 -32795 32796 -32797 32798 -32799 -32800 +v 32801 -32802 -32803 -32804 -32805 -32806 -32807 -32808 -32809 -32810 -32811 +v 32812 32813 32814 -32815 -32816 -32817 -32818 -32819 -32820 -32821 -32822 +v -32823 -32824 -32825 -32826 -32827 -32828 -32829 -32830 -32831 -32832 -32833 +v -32834 -32835 -32836 -32837 -32838 -32839 -32840 -32841 -32842 -32843 32844 +v -32845 32846 -32847 -32848 32849 -32850 32851 -32852 -32853 32854 -32855 +v -32856 -32857 -32858 -32859 32860 32861 32862 -32863 -32864 32865 -32866 +v -32867 32868 32869 32870 32871 32872 32873 -32874 32875 32876 -32877 -32878 +v -32879 32880 32881 32882 -32883 -32884 -32885 -32886 -32887 -32888 -32889 +v -32890 -32891 -32892 -32893 -32894 -32895 -32896 -32897 -32898 -32899 -32900 +v -32901 -32902 -32903 -32904 -32905 32906 32907 -32908 -32909 32910 -32911 +v -32912 32913 -32914 32915 -32916 -32917 -32918 -32919 -32920 -32921 -32922 +v -32923 -32924 -32925 -32926 -32927 -32928 -32929 32930 32931 -32932 -32933 +v 32934 32935 32936 -32937 32938 32939 -32940 -32941 32942 -32943 -32944 32945 +v -32946 -32947 -32948 -32949 -32950 -32951 -32952 -32953 -32954 -32955 -32956 +v -32957 -32958 -32959 -32960 -32961 -32962 -32963 -32964 -32965 32966 32967 +v 32968 32969 32970 32971 32972 32973 32974 32975 32976 32977 32978 32979 +v 32980 32981 -32982 -32983 -32984 -32985 -32986 -32987 -32988 -32989 -32990 +v -32991 -32992 -32993 -32994 -32995 -32996 -32997 -32998 -32999 -33000 -33001 +v -33002 -33003 -33004 -33005 -33006 -33007 -33008 -33009 -33010 -33011 -33012 +v -33013 33014 33015 33016 -33017 -33018 33019 -33020 33021 -33022 -33023 +v -33024 -33025 -33026 33027 -33028 -33029 -33030 -33031 -33032 -33033 -33034 +v -33035 -33036 -33037 -33038 -33039 -33040 -33041 33042 33043 33044 -33045 +v -33046 -33047 33048 33049 -33050 -33051 -33052 33053 -33054 -33055 -33056 +v -33057 -33058 33059 -33060 -33061 -33062 -33063 -33064 -33065 -33066 -33067 +v 33068 33069 33070 -33071 -33072 -33073 33074 33075 33076 -33077 -33078 +v -33079 33080 -33081 -33082 -33083 -33084 -33085 33086 -33087 -33088 -33089 +v -33090 -33091 -33092 -33093 -33094 33095 33096 33097 -33098 -33099 -33100 +v 33101 33102 33103 33104 33105 33106 33107 33108 33109 33110 -33111 -33112 +v 33113 -33114 -33115 -33116 -33117 -33118 -33119 -33120 -33121 33122 33123 +v -33124 33125 33126 33127 -33128 33129 -33130 -33131 33132 -33133 -33134 +v -33135 -33136 -33137 -33138 -33139 -33140 -33141 33142 33143 33144 33145 +v 33146 33147 -33148 -33149 33150 -33151 -33152 33153 -33154 -33155 33156 +v -33157 -33158 -33159 -33160 -33161 -33162 -33163 -33164 -33165 -33166 -33167 +v -33168 -33169 -33170 -33171 -33172 33173 33174 33175 -33176 33177 33178 +v 33179 -33180 33181 33182 -33183 -33184 33185 -33186 -33187 33188 -33189 +v -33190 -33191 -33192 -33193 -33194 -33195 -33196 -33197 -33198 -33199 33200 +v 33201 33202 33203 33204 33205 -33206 -33207 -33208 -33209 -33210 -33211 +v -33212 -33213 33214 33215 -33216 33217 33218 33219 -33220 -33221 -33222 +v 33223 33224 -33225 -33226 33227 -33228 33229 -33230 -33231 -33232 -33233 +v -33234 -33235 -33236 -33237 -33238 -33239 33240 33241 33242 33243 33244 +v 33245 33246 33247 33248 33249 33250 33251 33252 33253 33254 -33255 -33256 +v -33257 -33258 -33259 -33260 -33261 -33262 -33263 -33264 -33265 -33266 -33267 +v -33268 -33269 -33270 -33271 -33272 -33273 -33274 -33275 -33276 -33277 -33278 +v -33279 -33280 -33281 -33282 -33283 33284 -33285 -33286 33287 33288 -33289 +v -33290 -33291 33292 -33293 -33294 -33295 -33296 -33297 -33298 -33299 33300 +v -33301 -33302 -33303 -33304 -33305 -33306 -33307 -33308 -33309 -33310 -33311 +v -33312 33313 33314 33315 -33316 -33317 -33318 -33319 33320 -33321 -33322 +v 33323 -33324 -33325 -33326 -33327 -33328 -33329 33330 -33331 -33332 -33333 +v -33334 -33335 -33336 -33337 -33338 -33339 -33340 -33341 -33342 -33343 -33344 +v 33345 33346 33347 -33348 -33349 -33350 -33351 33352 33353 33354 -33355 +v -33356 -33357 33358 -33359 -33360 -33361 -33362 -33363 33364 -33365 -33366 +v -33367 -33368 -33369 -33370 -33371 -33372 -33373 -33374 33375 33376 33377 +v -33378 -33379 -33380 33381 33382 33383 -33384 -33385 -33386 33387 -33388 +v -33389 -33390 -33391 -33392 33393 -33394 -33395 -33396 -33397 -33398 -33399 +v -33400 -33401 -33402 -33403 -33404 -33405 -33406 33407 33408 33409 -33410 +v -33411 -33412 33413 33414 33415 33416 33417 33418 -33419 -33420 33421 -33422 +v -33423 -33424 -33425 -33426 -33427 -33428 -33429 -33430 -33431 -33432 33433 +v 33434 -33435 33436 -33437 -33438 33439 -33440 -33441 -33442 -33443 -33444 +v -33445 -33446 -33447 -33448 -33449 -33450 -33451 -33452 33453 33454 -33455 +v -33456 -33457 33458 33459 33460 33461 -33462 -33463 -33464 -33465 -33466 +v -33467 -33468 -33469 -33470 -33471 33472 33473 -33474 33475 33476 -33477 +v -33478 -33479 33480 -33481 -33482 -33483 -33484 -33485 -33486 -33487 -33488 +v 33489 -33490 33491 -33492 -33493 33494 -33495 33496 -33497 -33498 33499 +v -33500 33501 -33502 -33503 33504 -33505 33506 33507 33508 -33509 -33510 +v 33511 33512 33513 -33514 -33515 33516 33517 33518 33519 -33520 -33521 33522 +v 33523 33524 -33525 -33526 -33527 -33528 -33529 -33530 -33531 -33532 -33533 +v -33534 -33535 -33536 -33537 -33538 -33539 -33540 -33541 33542 33543 33544 +v 33545 -33546 33547 -33548 -33549 -33550 33551 33552 33553 -33554 -33555 +v 33556 -33557 -33558 -33559 -33560 -33561 -33562 -33563 -33564 -33565 -33566 +v -33567 -33568 -33569 -33570 -33571 -33572 -33573 -33574 -33575 -33576 33577 +v -33578 33579 -33580 -33581 -33582 33583 -33584 33585 -33586 -33587 33588 +v -33589 -33590 -33591 -33592 -33593 -33594 33595 33596 33597 33598 33599 +v -33600 -33601 33602 -33603 -33604 -33605 -33606 -33607 -33608 -33609 -33610 +v -33611 -33612 -33613 -33614 -33615 -33616 -33617 -33618 -33619 -33620 -33621 +v -33622 33623 -33624 33625 -33626 -33627 -33628 33629 -33630 33631 -33632 +v -33633 33634 -33635 -33636 -33637 -33638 -33639 -33640 33641 33642 33643 +v 33644 33645 -33646 -33647 33648 -33649 -33650 -33651 -33652 -33653 -33654 +v -33655 -33656 -33657 -33658 -33659 -33660 -33661 -33662 -33663 -33664 -33665 +v -33666 -33667 -33668 33669 -33670 33671 -33672 -33673 -33674 33675 -33676 +v 33677 -33678 -33679 33680 -33681 -33682 -33683 -33684 -33685 -33686 33687 +v 33688 33689 33690 33691 -33692 -33693 33694 -33695 -33696 -33697 -33698 +v -33699 -33700 -33701 -33702 -33703 -33704 -33705 -33706 -33707 -33708 -33709 +v -33710 -33711 -33712 -33713 -33714 -33715 -33716 -33717 -33718 -33719 -33720 +v -33721 -33722 -33723 -33724 -33725 -33726 -33727 -33728 -33729 -33730 -33731 +v -33732 -33733 -33734 -33735 -33736 -33737 -33738 -33739 -33740 -33741 -33742 +v -33743 -33744 -33745 -33746 -33747 -33748 -33749 -33750 -33751 -33752 -33753 +v -33754 -33755 -33756 -33757 -33758 -33759 -33760 -33761 -33762 -33763 -33764 +v -33765 -33766 -33767 -33768 -33769 -33770 -33771 -33772 -33773 -33774 -33775 +v -33776 -33777 -33778 -33779 -33780 -33781 -33782 -33783 -33784 -33785 -33786 +v -33787 -33788 -33789 -33790 -33791 -33792 -33793 -33794 -33795 -33796 -33797 +v -33798 -33799 -33800 -33801 -33802 -33803 -33804 -33805 -33806 -33807 -33808 +v -33809 -33810 -33811 -33812 -33813 -33814 -33815 -33816 -33817 -33818 -33819 +v -33820 -33821 -33822 -33823 -33824 -33825 -33826 -33827 -33828 33829 -33830 +v 33831 -33832 -33833 -33834 33835 -33836 33837 -33838 -33839 -33840 33841 +v -33842 33843 -33844 -33845 -33846 -33847 33848 -33849 33850 -33851 -33852 +v 33853 -33854 -33855 -33856 -33857 -33858 -33859 -33860 -33861 -33862 -33863 +v 33864 33865 33866 33867 33868 -33869 -33870 33871 -33872 -33873 -33874 +v -33875 -33876 -33877 -33878 -33879 -33880 -33881 -33882 -33883 -33884 -33885 +v -33886 -33887 -33888 -33889 -33890 -33891 33892 -33893 33894 -33895 -33896 +v -33897 33898 -33899 33900 -33901 -33902 33903 -33904 -33905 -33906 -33907 +v -33908 -33909 33910 33911 33912 33913 -33914 -33915 33916 -33917 -33918 +v 33919 33920 33921 -33922 -33923 -33924 -33925 -33926 -33927 -33928 -33929 +v -33930 -33931 -33932 -33933 -33934 -33935 -33936 -33937 -33938 -33939 -33940 +v -33941 -33942 -33943 -33944 -33945 -33946 -33947 -33948 -33949 -33950 -33951 +v -33952 -33953 -33954 -33955 -33956 -33957 -33958 -33959 -33960 -33961 -33962 +v -33963 -33964 -33965 -33966 -33967 -33968 -33969 -33970 -33971 -33972 -33973 +v -33974 -33975 -33976 -33977 -33978 -33979 -33980 -33981 -33982 -33983 -33984 +v -33985 -33986 -33987 -33988 -33989 -33990 -33991 -33992 -33993 -33994 -33995 +v -33996 -33997 -33998 -33999 -34000 -34001 -34002 -34003 -34004 -34005 -34006 +v -34007 -34008 -34009 -34010 -34011 -34012 -34013 -34014 -34015 -34016 -34017 +v -34018 -34019 -34020 -34021 -34022 -34023 -34024 -34025 -34026 -34027 -34028 +v -34029 -34030 -34031 -34032 -34033 -34034 -34035 -34036 -34037 -34038 -34039 +v -34040 -34041 -34042 -34043 -34044 -34045 -34046 -34047 -34048 -34049 -34050 +v -34051 -34052 -34053 -34054 -34055 -34056 -34057 -34058 -34059 -34060 -34061 +v -34062 -34063 -34064 -34065 -34066 -34067 -34068 -34069 -34070 -34071 -34072 +v -34073 -34074 -34075 -34076 -34077 -34078 -34079 -34080 -34081 -34082 -34083 +v -34084 -34085 -34086 -34087 -34088 -34089 -34090 -34091 -34092 -34093 -34094 +v -34095 -34096 -34097 -34098 -34099 -34100 -34101 -34102 -34103 -34104 -34105 +v -34106 -34107 -34108 -34109 -34110 -34111 -34112 -34113 -34114 -34115 -34116 +v -34117 -34118 -34119 -34120 -34121 -34122 -34123 -34124 -34125 -34126 -34127 +v -34128 -34129 -34130 -34131 -34132 -34133 -34134 -34135 -34136 -34137 -34138 +v -34139 -34140 -34141 -34142 -34143 -34144 -34145 -34146 -34147 -34148 -34149 +v -34150 -34151 -34152 -34153 -34154 -34155 -34156 -34157 -34158 -34159 -34160 +v -34161 -34162 -34163 -34164 -34165 -34166 -34167 -34168 -34169 -34170 -34171 +v -34172 -34173 -34174 -34175 -34176 -34177 -34178 -34179 -34180 -34181 -34182 +v -34183 -34184 -34185 -34186 -34187 -34188 -34189 -34190 -34191 -34192 -34193 +v -34194 -34195 -34196 -34197 -34198 -34199 -34200 -34201 -34202 -34203 -34204 +v -34205 -34206 -34207 -34208 -34209 -34210 -34211 -34212 -34213 -34214 -34215 +v -34216 -34217 -34218 -34219 -34220 -34221 -34222 -34223 -34224 -34225 -34226 +v -34227 -34228 -34229 -34230 -34231 -34232 -34233 -34234 -34235 -34236 -34237 +v -34238 -34239 -34240 -34241 -34242 -34243 -34244 -34245 -34246 -34247 -34248 +v -34249 -34250 -34251 -34252 -34253 -34254 -34255 -34256 -34257 -34258 -34259 +v -34260 -34261 -34262 -34263 -34264 -34265 -34266 -34267 -34268 -34269 -34270 +v -34271 -34272 -34273 -34274 -34275 -34276 -34277 -34278 -34279 -34280 -34281 +v -34282 -34283 -34284 -34285 -34286 -34287 -34288 -34289 -34290 -34291 -34292 +v -34293 -34294 -34295 -34296 -34297 -34298 -34299 -34300 -34301 -34302 -34303 +v -34304 -34305 -34306 -34307 -34308 -34309 -34310 -34311 -34312 -34313 -34314 +v -34315 -34316 -34317 -34318 -34319 -34320 -34321 -34322 -34323 -34324 -34325 +v -34326 -34327 -34328 -34329 -34330 -34331 -34332 -34333 -34334 -34335 -34336 +v -34337 -34338 -34339 -34340 -34341 -34342 -34343 -34344 -34345 -34346 -34347 +v 34348 -34349 34350 -34351 -34352 34353 -34354 34355 -34356 -34357 -34358 +v 34359 -34360 34361 -34362 -34363 -34364 -34365 34366 -34367 34368 -34369 +v -34370 -34371 -34372 34373 -34374 34375 -34376 -34377 -34378 -34379 34380 +v -34381 34382 -34383 -34384 34385 -34386 34387 -34388 -34389 34390 -34391 +v -34392 -34393 -34394 -34395 -34396 -34397 -34398 -34399 -34400 -34401 -34402 +v -34403 -34404 -34405 34406 34407 34408 34409 -34410 -34411 -34412 -34413 +v -34414 34415 -34416 -34417 -34418 -34419 -34420 -34421 -34422 -34423 -34424 +v -34425 -34426 -34427 -34428 -34429 -34430 -34431 -34432 -34433 -34434 -34435 +v -34436 -34437 -34438 -34439 -34440 -34441 -34442 -34443 -34444 -34445 -34446 +v -34447 -34448 -34449 -34450 -34451 -34452 -34453 -34454 -34455 -34456 -34457 +v -34458 -34459 -34460 -34461 -34462 -34463 -34464 -34465 -34466 -34467 -34468 +v -34469 -34470 -34471 -34472 -34473 -34474 -34475 -34476 -34477 -34478 -34479 +v -34480 -34481 -34482 -34483 -34484 -34485 -34486 -34487 -34488 -34489 -34490 +v -34491 -34492 -34493 -34494 -34495 -34496 -34497 -34498 -34499 -34500 -34501 +v -34502 -34503 -34504 -34505 -34506 -34507 -34508 -34509 -34510 -34511 -34512 +v -34513 -34514 -34515 -34516 -34517 -34518 -34519 -34520 -34521 34522 -34523 +v 34524 -34525 -34526 -34527 -34528 34529 -34530 34531 -34532 -34533 -34534 +v -34535 34536 -34537 34538 -34539 -34540 -34541 -34542 34543 -34544 34545 +v -34546 -34547 34548 -34549 34550 -34551 -34552 34553 -34554 -34555 -34556 +v -34557 -34558 -34559 -34560 -34561 -34562 -34563 -34564 -34565 34566 34567 +v 34568 34569 -34570 -34571 -34572 -34573 -34574 -34575 -34576 -34577 -34578 +v -34579 -34580 -34581 -34582 -34583 -34584 -34585 -34586 -34587 -34588 -34589 +v -34590 -34591 -34592 -34593 -34594 -34595 -34596 -34597 -34598 -34599 -34600 +v -34601 -34602 -34603 -34604 -34605 -34606 -34607 -34608 -34609 -34610 -34611 +v -34612 -34613 -34614 -34615 -34616 34617 -34618 -34619 34620 -34621 -34622 +v 34623 -34624 -34625 -34626 34627 -34628 -34629 -34630 -34631 -34632 -34633 +v -34634 -34635 -34636 -34637 -34638 34639 -34640 34641 34642 34643 34644 +v -34645 -34646 -34647 -34648 -34649 -34650 -34651 -34652 -34653 -34654 -34655 +v -34656 -34657 -34658 -34659 -34660 -34661 -34662 -34663 -34664 -34665 -34666 +v -34667 -34668 -34669 -34670 -34671 -34672 -34673 -34674 -34675 -34676 -34677 +v -34678 -34679 -34680 -34681 -34682 -34683 -34684 -34685 -34686 -34687 -34688 +v -34689 -34690 -34691 -34692 -34693 -34694 -34695 -34696 -34697 -34698 -34699 +v -34700 -34701 -34702 34703 -34704 -34705 -34706 -34707 -34708 -34709 -34710 +v -34711 -34712 -34713 -34714 -34715 -34716 -34717 -34718 -34719 -34720 -34721 +v -34722 -34723 -34724 -34725 -34726 -34727 -34728 -34729 -34730 34731 -34732 +v 34733 -34734 -34735 -34736 34737 -34738 34739 -34740 -34741 -34742 34743 +v -34744 34745 -34746 -34747 -34748 34749 -34750 34751 -34752 -34753 34754 +v -34755 -34756 -34757 -34758 -34759 -34760 -34761 -34762 -34763 -34764 -34765 +v 34766 34767 34768 34769 -34770 -34771 -34772 -34773 -34774 -34775 -34776 +v -34777 34778 -34779 34780 -34781 34782 -34783 -34784 -34785 -34786 34787 +v 34788 34789 34790 -34791 -34792 -34793 -34794 -34795 -34796 -34797 -34798 +v -34799 -34800 -34801 -34802 -34803 -34804 -34805 -34806 -34807 -34808 -34809 +v -34810 -34811 -34812 -34813 -34814 -34815 -34816 -34817 -34818 -34819 -34820 +v -34821 -34822 -34823 -34824 -34825 -34826 -34827 -34828 -34829 -34830 -34831 +v -34832 -34833 -34834 -34835 -34836 34837 -34838 -34839 -34840 -34841 -34842 +v -34843 -34844 -34845 34846 34847 -34848 -34849 -34850 34851 -34852 -34853 +v -34854 -34855 -34856 -34857 -34858 -34859 -34860 -34861 -34862 -34863 -34864 +v -34865 -34866 -34867 -34868 -34869 -34870 -34871 -34872 -34873 -34874 -34875 +v -34876 34877 34878 34879 34880 -34881 -34882 -34883 -34884 -34885 -34886 +v -34887 -34888 -34889 -34890 -34891 -34892 -34893 34894 -34895 34896 -34897 +v -34898 -34899 34900 -34901 -34902 -34903 -34904 -34905 -34906 -34907 -34908 +v 34909 -34910 34911 -34912 -34913 -34914 34915 -34916 34917 -34918 -34919 +v -34920 34921 -34922 34923 34924 34925 34926 34927 -34928 -34929 34930 -34931 +v -34932 34933 -34934 -34935 -34936 -34937 -34938 -34939 -34940 -34941 -34942 +v -34943 34944 34945 34946 34947 -34948 -34949 -34950 -34951 -34952 -34953 +v -34954 -34955 -34956 34957 -34958 -34959 34960 -34961 -34962 -34963 -34964 +v -34965 34966 34967 34968 34969 -34970 -34971 34972 -34973 -34974 -34975 +v -34976 -34977 -34978 -34979 -34980 -34981 -34982 -34983 34984 34985 -34986 +v -34987 34988 -34989 -34990 34991 -34992 -34993 -34994 34995 -34996 -34997 +v -34998 -34999 -35000 -35001 -35002 -35003 -35004 -35005 -35006 -35007 -35008 +v -35009 -35010 -35011 -35012 -35013 -35014 -35015 -35016 -35017 -35018 -35019 +v -35020 -35021 -35022 -35023 35024 35025 -35026 -35027 35028 35029 35030 +v -35031 35032 -35033 -35034 -35035 35036 -35037 -35038 35039 -35040 -35041 +v -35042 -35043 -35044 -35045 -35046 -35047 -35048 -35049 -35050 -35051 -35052 +v 35053 35054 35055 35056 35057 35058 -35059 -35060 -35061 35062 -35063 -35064 +v 35065 -35066 -35067 -35068 -35069 -35070 -35071 -35072 -35073 -35074 -35075 +v -35076 -35077 -35078 -35079 -35080 -35081 -35082 -35083 -35084 -35085 -35086 +v -35087 -35088 -35089 -35090 -35091 -35092 -35093 -35094 -35095 -35096 -35097 +v 35098 35099 35100 -35101 35102 35103 35104 -35105 35106 -35107 -35108 35109 +v -35110 -35111 35112 -35113 -35114 -35115 -35116 -35117 -35118 -35119 -35120 +v -35121 -35122 -35123 -35124 -35125 35126 35127 35128 35129 35130 35131 35132 +v 35133 35134 35135 35136 -35137 -35138 -35139 -35140 -35141 -35142 -35143 +v -35144 -35145 -35146 -35147 35148 35149 -35150 -35151 -35152 -35153 35154 +v -35155 -35156 -35157 -35158 -35159 -35160 -35161 -35162 -35163 -35164 -35165 +v -35166 35167 -35168 -35169 -35170 -35171 -35172 -35173 -35174 -35175 -35176 +v -35177 -35178 -35179 -35180 -35181 -35182 -35183 -35184 -35185 -35186 -35187 +v -35188 -35189 35190 35191 -35192 35193 -35194 -35195 -35196 -35197 -35198 +v -35199 -35200 -35201 -35202 -35203 -35204 -35205 -35206 35207 35208 -35209 +v 35210 35211 -35212 -35213 35214 -35215 -35216 -35217 -35218 -35219 -35220 +v -35221 -35222 -35223 -35224 -35225 -35226 35227 35228 35229 35230 35231 +v 35232 35233 35234 35235 35236 -35237 -35238 -35239 -35240 -35241 -35242 +v -35243 -35244 -35245 -35246 -35247 35248 35249 -35250 -35251 35252 35253 +v -35254 -35255 -35256 -35257 35258 -35259 -35260 35261 -35262 -35263 -35264 +v -35265 -35266 -35267 -35268 -35269 35270 35271 35272 35273 -35274 -35275 +v -35276 -35277 -35278 -35279 -35280 -35281 -35282 35283 -35284 35285 35286 +v -35287 -35288 -35289 -35290 35291 -35292 -35293 -35294 -35295 -35296 -35297 +v -35298 35299 35300 35301 35302 -35303 -35304 -35305 35306 -35307 -35308 +v -35309 -35310 -35311 -35312 -35313 -35314 -35315 -35316 -35317 -35318 -35319 +v -35320 35321 35322 -35323 35324 35325 35326 -35327 35328 -35329 -35330 35331 +v -35332 -35333 35334 -35335 -35336 -35337 -35338 -35339 -35340 -35341 -35342 +v -35343 -35344 35345 35346 35347 35348 35349 35350 35351 35352 35353 35354 +v 35355 35356 35357 35358 35359 35360 -35361 -35362 -35363 -35364 -35365 +v -35366 -35367 -35368 -35369 -35370 -35371 -35372 -35373 -35374 -35375 -35376 +v -35377 -35378 -35379 -35380 -35381 -35382 -35383 -35384 -35385 35386 35387 +v -35388 -35389 35390 -35391 -35392 -35393 35394 -35395 -35396 -35397 -35398 +v -35399 -35400 -35401 -35402 -35403 -35404 -35405 -35406 35407 -35408 -35409 +v -35410 -35411 -35412 -35413 -35414 -35415 35416 35417 -35418 -35419 -35420 +v -35421 -35422 -35423 -35424 -35425 -35426 -35427 -35428 -35429 -35430 35431 +v -35432 35433 -35434 -35435 35436 -35437 35438 -35439 -35440 35441 -35442 +v 35443 35444 35445 35446 -35447 -35448 35449 -35450 -35451 -35452 35453 +v -35454 35455 -35456 -35457 -35458 35459 -35460 35461 -35462 -35463 35464 +v -35465 -35466 -35467 -35468 -35469 -35470 -35471 -35472 -35473 -35474 -35475 +v -35476 -35477 35478 35479 35480 -35481 -35482 -35483 -35484 35485 35486 +v 35487 35488 -35489 -35490 -35491 -35492 -35493 -35494 -35495 -35496 -35497 +v -35498 35499 35500 -35501 -35502 35503 -35504 -35505 -35506 -35507 -35508 +v -35509 -35510 -35511 -35512 -35513 -35514 35515 35516 35517 -35518 -35519 +v -35520 -35521 -35522 -35523 -35524 35525 35526 -35527 -35528 35529 -35530 +v -35531 -35532 -35533 -35534 -35535 -35536 -35537 -35538 -35539 -35540 -35541 +v 35542 35543 -35544 -35545 -35546 -35547 -35548 -35549 -35550 35551 -35552 +v 35553 -35554 -35555 -35556 35557 -35558 35559 -35560 -35561 -35562 35563 +v -35564 35565 35566 35567 35568 -35569 -35570 35571 -35572 -35573 35574 +v -35575 -35576 -35577 -35578 -35579 -35580 -35581 -35582 -35583 -35584 35585 +v 35586 35587 35588 -35589 -35590 -35591 -35592 -35593 -35594 -35595 -35596 +v -35597 -35598 -35599 -35600 -35601 -35602 -35603 -35604 -35605 -35606 -35607 +v -35608 -35609 35610 -35611 -35612 -35613 -35614 -35615 -35616 -35617 -35618 +v 35619 35620 -35621 -35622 -35623 35624 -35625 -35626 -35627 -35628 -35629 +v -35630 -35631 -35632 -35633 -35634 -35635 -35636 35637 -35638 35639 -35640 +v -35641 35642 -35643 35644 -35645 -35646 35647 -35648 35649 35650 35651 35652 +v -35653 -35654 35655 -35656 -35657 35658 -35659 -35660 -35661 -35662 -35663 +v -35664 -35665 -35666 -35667 -35668 35669 35670 35671 35672 -35673 -35674 +v -35675 -35676 -35677 -35678 -35679 -35680 -35681 -35682 -35683 -35684 -35685 +v -35686 -35687 -35688 -35689 -35690 -35691 -35692 -35693 35694 -35695 -35696 +v -35697 -35698 -35699 -35700 -35701 -35702 35703 35704 -35705 -35706 -35707 +v 35708 -35709 -35710 -35711 -35712 -35713 -35714 -35715 -35716 35717 35718 +v 35719 -35720 -35721 -35722 -35723 -35724 -35725 -35726 -35727 35728 -35729 +v -35730 -35731 -35732 -35733 -35734 -35735 -35736 35737 -35738 35739 35740 +v 35741 -35742 -35743 -35744 -35745 -35746 -35747 -35748 35749 35750 -35751 +v -35752 35753 -35754 -35755 -35756 -35757 -35758 -35759 -35760 -35761 -35762 +v 35763 -35764 35765 -35766 -35767 -35768 35769 -35770 35771 -35772 -35773 +v -35774 35775 -35776 35777 35778 35779 35780 -35781 -35782 35783 -35784 +v -35785 35786 -35787 -35788 -35789 -35790 -35791 -35792 -35793 -35794 -35795 +v -35796 35797 35798 35799 -35800 -35801 -35802 -35803 -35804 -35805 -35806 +v -35807 35808 -35809 35810 -35811 -35812 -35813 -35814 -35815 35816 35817 +v 35818 35819 35820 -35821 35822 -35823 -35824 -35825 -35826 -35827 -35828 +v -35829 -35830 -35831 -35832 -35833 -35834 -35835 -35836 35837 -35838 -35839 +v -35840 -35841 -35842 35843 -35844 35845 -35846 -35847 -35848 35849 -35850 +v 35851 -35852 -35853 35854 -35855 -35856 -35857 -35858 -35859 -35860 35861 +v 35862 35863 35864 -35865 35866 -35867 -35868 -35869 -35870 -35871 -35872 +v -35873 -35874 -35875 -35876 -35877 -35878 -35879 -35880 35881 -35882 -35883 +v -35884 -35885 -35886 35887 -35888 35889 -35890 -35891 -35892 35893 -35894 +v 35895 -35896 -35897 35898 -35899 -35900 -35901 -35902 -35903 -35904 35905 +v 35906 35907 35908 -35909 35910 -35911 -35912 -35913 -35914 -35915 -35916 +v -35917 -35918 -35919 -35920 -35921 -35922 -35923 -35924 35925 -35926 -35927 +v -35928 -35929 -35930 35931 -35932 35933 -35934 -35935 -35936 35937 -35938 +v 35939 -35940 -35941 35942 -35943 -35944 -35945 -35946 -35947 -35948 35949 +v 35950 35951 35952 -35953 35954 -35955 -35956 -35957 -35958 -35959 -35960 +v -35961 -35962 -35963 -35964 -35965 -35966 -35967 -35968 -35969 -35970 -35971 +v -35972 -35973 -35974 -35975 -35976 -35977 -35978 -35979 -35980 -35981 -35982 +v -35983 -35984 -35985 -35986 -35987 -35988 -35989 -35990 -35991 -35992 -35993 +v -35994 -35995 -35996 -35997 -35998 -35999 -36000 -36001 -36002 -36003 -36004 +v -36005 -36006 -36007 -36008 -36009 -36010 -36011 -36012 -36013 -36014 -36015 +v -36016 -36017 -36018 -36019 -36020 -36021 -36022 -36023 -36024 36025 -36026 +v -36027 -36028 -36029 -36030 -36031 -36032 -36033 -36034 -36035 -36036 -36037 +v -36038 -36039 -36040 -36041 -36042 -36043 -36044 -36045 -36046 -36047 -36048 +v -36049 -36050 -36051 -36052 -36053 -36054 -36055 -36056 -36057 -36058 -36059 +v -36060 -36061 -36062 -36063 -36064 -36065 -36066 -36067 -36068 -36069 -36070 +v -36071 -36072 -36073 -36074 -36075 -36076 -36077 -36078 -36079 -36080 -36081 +v -36082 36083 -36084 36085 -36086 -36087 -36088 36089 -36090 36091 -36092 +v -36093 -36094 36095 -36096 36097 -36098 -36099 -36100 -36101 36102 -36103 +v 36104 -36105 -36106 36107 -36108 -36109 -36110 -36111 -36112 -36113 -36114 +v -36115 -36116 -36117 36118 36119 36120 36121 -36122 36123 -36124 -36125 +v -36126 -36127 -36128 -36129 -36130 -36131 -36132 -36133 -36134 -36135 -36136 +v -36137 36138 -36139 -36140 -36141 -36142 -36143 36144 -36145 36146 -36147 +v -36148 -36149 36150 -36151 36152 -36153 -36154 36155 -36156 -36157 -36158 +v -36159 -36160 -36161 36162 36163 36164 -36165 -36166 -36167 -36168 -36169 +v -36170 -36171 -36172 -36173 -36174 -36175 -36176 -36177 -36178 -36179 -36180 +v -36181 -36182 -36183 -36184 -36185 -36186 -36187 36188 36189 36190 36191 +v -36192 -36193 -36194 -36195 -36196 -36197 -36198 -36199 -36200 -36201 -36202 +v -36203 -36204 -36205 36206 -36207 36208 -36209 -36210 -36211 36212 -36213 +v -36214 -36215 -36216 -36217 -36218 -36219 -36220 -36221 36222 -36223 -36224 +v -36225 -36226 -36227 -36228 -36229 -36230 -36231 -36232 -36233 -36234 -36235 +v -36236 -36237 -36238 -36239 -36240 -36241 36242 36243 36244 36245 -36246 +v -36247 -36248 -36249 -36250 -36251 -36252 -36253 -36254 -36255 -36256 -36257 +v -36258 36259 -36260 36261 -36262 -36263 -36264 36265 -36266 -36267 -36268 +v -36269 -36270 -36271 -36272 -36273 -36274 36275 -36276 36277 -36278 -36279 +v -36280 -36281 36282 -36283 36284 -36285 -36286 -36287 -36288 36289 -36290 +v 36291 36292 36293 36294 36295 -36296 -36297 36298 -36299 -36300 36301 -36302 +v -36303 -36304 -36305 -36306 -36307 -36308 -36309 -36310 -36311 36312 36313 +v 36314 36315 -36316 36317 -36318 -36319 -36320 -36321 -36322 -36323 -36324 +v -36325 -36326 -36327 -36328 -36329 -36330 -36331 -36332 -36333 -36334 -36335 +v -36336 36337 -36338 36339 -36340 -36341 -36342 36343 -36344 36345 -36346 +v -36347 36348 -36349 -36350 -36351 -36352 -36353 -36354 36355 36356 36357 +v 36358 36359 -36360 36361 -36362 -36363 -36364 -36365 -36366 -36367 -36368 +v -36369 -36370 -36371 -36372 -36373 -36374 -36375 -36376 -36377 -36378 -36379 +v -36380 36381 -36382 36383 -36384 -36385 -36386 36387 -36388 36389 -36390 +v -36391 36392 -36393 -36394 -36395 -36396 -36397 -36398 36399 36400 36401 +v 36402 36403 -36404 36405 -36406 -36407 -36408 -36409 -36410 -36411 -36412 +v -36413 -36414 -36415 -36416 -36417 -36418 -36419 -36420 -36421 -36422 -36423 +v -36424 36425 -36426 36427 -36428 -36429 -36430 36431 -36432 36433 -36434 +v -36435 36436 -36437 -36438 -36439 -36440 -36441 -36442 36443 36444 36445 +v 36446 36447 -36448 36449 -36450 -36451 -36452 -36453 -36454 -36455 -36456 +v -36457 -36458 -36459 -36460 -36461 -36462 -36463 -36464 -36465 -36466 -36467 +v -36468 -36469 -36470 -36471 -36472 -36473 -36474 -36475 -36476 -36477 -36478 +v -36479 -36480 -36481 -36482 -36483 -36484 -36485 -36486 -36487 -36488 -36489 +v -36490 -36491 -36492 -36493 -36494 -36495 -36496 -36497 -36498 -36499 -36500 +v -36501 -36502 -36503 -36504 -36505 -36506 -36507 -36508 -36509 -36510 -36511 +v -36512 -36513 -36514 -36515 -36516 -36517 -36518 -36519 -36520 -36521 -36522 +v -36523 -36524 -36525 -36526 -36527 -36528 -36529 -36530 -36531 -36532 -36533 +v -36534 -36535 -36536 -36537 -36538 -36539 -36540 -36541 -36542 -36543 -36544 +v -36545 -36546 -36547 -36548 -36549 -36550 -36551 -36552 -36553 -36554 -36555 +v -36556 -36557 -36558 -36559 -36560 -36561 -36562 -36563 -36564 -36565 -36566 +v -36567 -36568 -36569 -36570 -36571 -36572 -36573 -36574 -36575 -36576 36577 +v -36578 36579 -36580 -36581 -36582 36583 -36584 36585 -36586 -36587 -36588 +v 36589 -36590 36591 -36592 -36593 -36594 -36595 36596 -36597 36598 -36599 +v -36600 36601 -36602 -36603 -36604 -36605 -36606 -36607 -36608 -36609 -36610 +v -36611 36612 36613 36614 36615 36616 -36617 36618 -36619 -36620 -36621 +v -36622 -36623 -36624 -36625 -36626 -36627 -36628 -36629 -36630 -36631 -36632 +v -36633 -36634 -36635 -36636 -36637 36638 -36639 36640 -36641 -36642 -36643 +v 36644 -36645 36646 -36647 -36648 36649 -36650 -36651 -36652 -36653 -36654 +v -36655 36656 36657 36658 36659 -36660 -36661 36662 -36663 -36664 36665 36666 +v -36667 -36668 -36669 -36670 -36671 -36672 -36673 -36674 -36675 -36676 -36677 +v -36678 -36679 -36680 -36681 -36682 -36683 -36684 -36685 -36686 -36687 -36688 +v -36689 -36690 -36691 -36692 -36693 -36694 -36695 -36696 -36697 -36698 -36699 +v -36700 -36701 -36702 -36703 -36704 -36705 -36706 -36707 -36708 -36709 -36710 +v -36711 -36712 -36713 -36714 -36715 -36716 -36717 -36718 -36719 -36720 -36721 +v -36722 -36723 -36724 -36725 -36726 -36727 -36728 -36729 -36730 -36731 -36732 +v -36733 -36734 -36735 -36736 -36737 -36738 -36739 -36740 -36741 -36742 -36743 +v -36744 -36745 -36746 -36747 -36748 -36749 -36750 -36751 -36752 -36753 -36754 +v -36755 -36756 -36757 -36758 -36759 -36760 -36761 -36762 -36763 -36764 -36765 +v -36766 -36767 -36768 -36769 -36770 -36771 -36772 -36773 -36774 -36775 -36776 +v -36777 -36778 -36779 -36780 -36781 -36782 -36783 -36784 -36785 -36786 -36787 +v -36788 -36789 -36790 -36791 -36792 -36793 -36794 -36795 -36796 -36797 -36798 +v -36799 -36800 -36801 -36802 -36803 -36804 -36805 -36806 -36807 -36808 -36809 +v -36810 -36811 -36812 -36813 -36814 -36815 -36816 -36817 -36818 -36819 -36820 +v -36821 -36822 -36823 -36824 -36825 -36826 -36827 -36828 -36829 -36830 -36831 +v -36832 -36833 -36834 -36835 -36836 -36837 -36838 -36839 -36840 -36841 -36842 +v -36843 -36844 -36845 -36846 -36847 -36848 -36849 -36850 -36851 -36852 -36853 +v -36854 -36855 -36856 -36857 -36858 -36859 -36860 -36861 -36862 -36863 -36864 +v -36865 -36866 -36867 -36868 -36869 -36870 -36871 -36872 -36873 -36874 -36875 +v -36876 -36877 -36878 -36879 -36880 -36881 -36882 -36883 -36884 -36885 -36886 +v -36887 -36888 -36889 -36890 -36891 -36892 -36893 -36894 -36895 -36896 -36897 +v -36898 -36899 -36900 -36901 -36902 -36903 -36904 -36905 -36906 -36907 -36908 +v -36909 -36910 -36911 -36912 -36913 -36914 -36915 -36916 -36917 -36918 -36919 +v -36920 -36921 -36922 -36923 -36924 -36925 -36926 -36927 -36928 -36929 -36930 +v -36931 -36932 -36933 -36934 -36935 -36936 -36937 -36938 -36939 -36940 -36941 +v -36942 -36943 -36944 -36945 -36946 -36947 -36948 -36949 -36950 -36951 -36952 +v -36953 -36954 -36955 -36956 -36957 -36958 -36959 -36960 -36961 -36962 -36963 +v -36964 -36965 -36966 -36967 -36968 -36969 -36970 -36971 -36972 -36973 -36974 +v -36975 -36976 -36977 -36978 -36979 -36980 -36981 -36982 -36983 -36984 -36985 +v -36986 -36987 -36988 -36989 -36990 -36991 -36992 -36993 -36994 -36995 -36996 +v -36997 -36998 -36999 -37000 -37001 -37002 -37003 -37004 -37005 -37006 -37007 +v -37008 -37009 -37010 -37011 -37012 -37013 -37014 -37015 -37016 -37017 -37018 +v -37019 -37020 -37021 -37022 -37023 -37024 -37025 -37026 -37027 -37028 -37029 +v -37030 -37031 -37032 -37033 -37034 -37035 -37036 -37037 -37038 -37039 -37040 +v -37041 -37042 -37043 -37044 -37045 -37046 -37047 -37048 -37049 -37050 -37051 +v -37052 -37053 -37054 -37055 -37056 -37057 -37058 -37059 -37060 -37061 -37062 +v -37063 -37064 -37065 -37066 -37067 -37068 -37069 -37070 -37071 -37072 37073 +v -37074 37075 -37076 -37077 37078 -37079 37080 -37081 -37082 -37083 37084 +v -37085 37086 -37087 -37088 -37089 -37090 37091 -37092 37093 -37094 -37095 +v -37096 -37097 37098 -37099 37100 -37101 -37102 -37103 -37104 37105 -37106 +v 37107 -37108 -37109 37110 -37111 37112 -37113 -37114 37115 -37116 -37117 +v -37118 -37119 -37120 -37121 -37122 -37123 -37124 -37125 -37126 -37127 -37128 +v -37129 -37130 37131 37132 37133 37134 -37135 -37136 -37137 -37138 -37139 +v 37140 -37141 -37142 -37143 -37144 -37145 -37146 -37147 -37148 -37149 -37150 +v -37151 -37152 -37153 -37154 -37155 -37156 -37157 -37158 -37159 -37160 -37161 +v -37162 -37163 -37164 -37165 -37166 -37167 -37168 -37169 -37170 -37171 -37172 +v -37173 -37174 -37175 -37176 -37177 -37178 -37179 -37180 -37181 -37182 -37183 +v -37184 -37185 -37186 -37187 -37188 -37189 -37190 -37191 -37192 -37193 -37194 +v -37195 -37196 -37197 -37198 -37199 -37200 -37201 -37202 -37203 -37204 -37205 +v -37206 -37207 -37208 -37209 -37210 -37211 -37212 -37213 -37214 -37215 -37216 +v -37217 -37218 -37219 -37220 -37221 -37222 -37223 -37224 -37225 -37226 -37227 +v -37228 -37229 -37230 -37231 -37232 -37233 -37234 -37235 -37236 -37237 -37238 +v -37239 -37240 -37241 -37242 -37243 -37244 37245 -37246 37247 -37248 -37249 +v -37250 -37251 37252 -37253 37254 -37255 -37256 -37257 -37258 37259 -37260 +v 37261 -37262 -37263 -37264 -37265 37266 -37267 37268 -37269 -37270 37271 +v -37272 37273 -37274 -37275 37276 -37277 -37278 -37279 -37280 -37281 -37282 +v -37283 -37284 -37285 -37286 -37287 -37288 37289 37290 37291 37292 -37293 +v -37294 -37295 -37296 -37297 -37298 -37299 -37300 -37301 -37302 -37303 -37304 +v -37305 -37306 -37307 -37308 -37309 -37310 -37311 -37312 -37313 -37314 -37315 +v -37316 -37317 -37318 -37319 -37320 -37321 -37322 -37323 -37324 -37325 -37326 +v -37327 -37328 -37329 -37330 -37331 -37332 -37333 -37334 -37335 -37336 -37337 +v -37338 -37339 37340 -37341 -37342 37343 -37344 -37345 37346 -37347 -37348 +v -37349 37350 -37351 -37352 -37353 -37354 -37355 -37356 -37357 -37358 -37359 +v -37360 -37361 37362 -37363 37364 37365 37366 37367 -37368 -37369 -37370 +v -37371 -37372 -37373 -37374 -37375 -37376 -37377 -37378 -37379 -37380 -37381 +v -37382 -37383 -37384 -37385 -37386 -37387 -37388 -37389 -37390 -37391 -37392 +v -37393 -37394 -37395 -37396 -37397 -37398 -37399 -37400 -37401 -37402 -37403 +v -37404 -37405 -37406 -37407 -37408 -37409 -37410 -37411 -37412 -37413 -37414 +v -37415 -37416 -37417 -37418 -37419 -37420 -37421 -37422 -37423 -37424 -37425 +v 37426 -37427 -37428 -37429 -37430 -37431 -37432 -37433 -37434 -37435 -37436 +v -37437 -37438 -37439 -37440 -37441 -37442 -37443 -37444 -37445 -37446 -37447 +v -37448 -37449 -37450 -37451 -37452 -37453 37454 -37455 37456 -37457 -37458 +v -37459 37460 -37461 37462 -37463 -37464 -37465 37466 -37467 37468 -37469 +v -37470 -37471 37472 -37473 37474 -37475 -37476 37477 -37478 -37479 -37480 +v -37481 -37482 -37483 -37484 -37485 -37486 -37487 -37488 37489 37490 37491 +v 37492 -37493 -37494 -37495 -37496 -37497 -37498 -37499 -37500 37501 -37502 +v 37503 -37504 37505 -37506 -37507 -37508 -37509 37510 37511 37512 37513 +v -37514 -37515 -37516 -37517 -37518 -37519 -37520 -37521 -37522 -37523 -37524 +v -37525 -37526 -37527 -37528 -37529 -37530 -37531 -37532 -37533 -37534 -37535 +v -37536 -37537 -37538 -37539 -37540 -37541 -37542 -37543 -37544 -37545 -37546 +v -37547 -37548 -37549 -37550 -37551 -37552 -37553 -37554 -37555 -37556 -37557 +v -37558 -37559 37560 -37561 -37562 -37563 -37564 -37565 -37566 -37567 -37568 +v 37569 37570 -37571 -37572 -37573 37574 -37575 -37576 -37577 -37578 -37579 +v -37580 -37581 -37582 -37583 -37584 -37585 -37586 -37587 -37588 -37589 -37590 +v -37591 -37592 -37593 -37594 -37595 -37596 -37597 -37598 -37599 37600 37601 +v 37602 37603 -37604 -37605 -37606 -37607 -37608 -37609 -37610 -37611 -37612 +v -37613 -37614 -37615 -37616 37617 -37618 37619 -37620 -37621 -37622 37623 +v -37624 -37625 -37626 -37627 -37628 -37629 -37630 -37631 37632 -37633 37634 +v -37635 -37636 -37637 37638 -37639 37640 -37641 -37642 -37643 37644 -37645 +v 37646 37647 37648 37649 37650 -37651 -37652 37653 -37654 -37655 37656 -37657 +v -37658 -37659 -37660 -37661 -37662 -37663 -37664 -37665 -37666 37667 37668 +v 37669 37670 -37671 -37672 -37673 -37674 -37675 -37676 -37677 -37678 -37679 +v 37680 -37681 -37682 37683 -37684 -37685 -37686 -37687 -37688 37689 37690 +v 37691 37692 -37693 -37694 37695 -37696 -37697 -37698 -37699 -37700 -37701 +v -37702 -37703 -37704 -37705 -37706 37707 37708 -37709 -37710 37711 -37712 +v -37713 37714 -37715 -37716 -37717 37718 -37719 -37720 -37721 -37722 -37723 +v -37724 -37725 -37726 -37727 -37728 -37729 -37730 -37731 -37732 -37733 -37734 +v -37735 -37736 -37737 -37738 -37739 -37740 -37741 -37742 -37743 -37744 -37745 +v -37746 37747 37748 -37749 -37750 37751 37752 37753 -37754 37755 -37756 +v -37757 -37758 37759 -37760 -37761 37762 -37763 -37764 -37765 -37766 -37767 +v -37768 -37769 -37770 -37771 -37772 -37773 -37774 -37775 37776 37777 37778 +v 37779 37780 37781 -37782 -37783 -37784 37785 -37786 -37787 37788 -37789 +v -37790 -37791 -37792 -37793 -37794 -37795 -37796 -37797 -37798 -37799 -37800 +v -37801 -37802 -37803 -37804 -37805 -37806 -37807 -37808 -37809 -37810 -37811 +v -37812 -37813 -37814 -37815 -37816 -37817 -37818 -37819 -37820 37821 37822 +v 37823 -37824 37825 37826 37827 -37828 37829 -37830 -37831 37832 -37833 +v -37834 37835 -37836 -37837 -37838 -37839 -37840 -37841 -37842 -37843 -37844 +v -37845 -37846 -37847 -37848 37849 37850 37851 37852 37853 37854 37855 37856 +v 37857 37858 37859 -37860 -37861 -37862 -37863 -37864 -37865 -37866 -37867 +v -37868 -37869 -37870 37871 37872 -37873 -37874 -37875 -37876 37877 -37878 +v -37879 -37880 -37881 -37882 -37883 -37884 -37885 -37886 -37887 -37888 -37889 +v 37890 -37891 -37892 -37893 -37894 -37895 -37896 -37897 -37898 -37899 -37900 +v -37901 -37902 -37903 -37904 -37905 -37906 -37907 -37908 -37909 -37910 -37911 +v -37912 37913 37914 -37915 37916 -37917 -37918 -37919 -37920 -37921 -37922 +v -37923 -37924 -37925 -37926 -37927 -37928 -37929 37930 37931 -37932 37933 +v 37934 -37935 -37936 37937 -37938 -37939 -37940 -37941 -37942 -37943 -37944 +v -37945 -37946 -37947 -37948 -37949 37950 37951 37952 37953 37954 37955 37956 +v 37957 -37958 -37959 -37960 -37961 -37962 -37963 -37964 -37965 -37966 -37967 +v -37968 37969 37970 -37971 -37972 37973 37974 -37975 -37976 -37977 -37978 +v 37979 -37980 -37981 37982 -37983 -37984 -37985 -37986 -37987 -37988 -37989 +v -37990 37991 37992 37993 37994 -37995 -37996 -37997 -37998 -37999 -38000 +v -38001 -38002 -38003 38004 -38005 38006 38007 -38008 -38009 -38010 -38011 +v 38012 -38013 -38014 -38015 -38016 -38017 -38018 -38019 38020 38021 38022 +v 38023 -38024 -38025 -38026 38027 -38028 -38029 -38030 -38031 -38032 -38033 +v -38034 -38035 -38036 -38037 -38038 -38039 -38040 -38041 38042 38043 -38044 +v 38045 38046 38047 -38048 38049 -38050 -38051 38052 -38053 -38054 38055 +v -38056 -38057 -38058 -38059 -38060 -38061 -38062 -38063 -38064 -38065 38066 +v 38067 38068 38069 38070 38071 38072 38073 38074 38075 38076 38077 38078 +v 38079 38080 38081 -38082 -38083 -38084 -38085 -38086 -38087 -38088 -38089 +v -38090 -38091 -38092 -38093 -38094 -38095 -38096 -38097 -38098 -38099 -38100 +v -38101 -38102 -38103 -38104 -38105 -38106 38107 38108 -38109 -38110 38111 +v -38112 -38113 -38114 38115 -38116 -38117 -38118 -38119 -38120 -38121 -38122 +v -38123 -38124 -38125 -38126 -38127 38128 -38129 -38130 -38131 -38132 -38133 +v -38134 -38135 -38136 38137 38138 -38139 -38140 -38141 -38142 -38143 -38144 +v -38145 -38146 -38147 -38148 -38149 -38150 -38151 38152 -38153 38154 -38155 +v -38156 38157 -38158 38159 -38160 -38161 38162 -38163 38164 38165 38166 38167 +v -38168 -38169 38170 -38171 -38172 -38173 38174 -38175 38176 -38177 -38178 +v -38179 38180 -38181 38182 -38183 -38184 38185 -38186 -38187 -38188 -38189 +v -38190 -38191 -38192 -38193 -38194 -38195 -38196 -38197 -38198 38199 38200 +v 38201 -38202 -38203 -38204 -38205 38206 38207 38208 38209 -38210 -38211 +v -38212 -38213 -38214 -38215 -38216 -38217 -38218 -38219 38220 38221 -38222 +v -38223 38224 -38225 -38226 -38227 -38228 -38229 -38230 -38231 -38232 -38233 +v -38234 -38235 38236 38237 38238 -38239 -38240 -38241 -38242 -38243 -38244 +v -38245 38246 38247 -38248 -38249 38250 -38251 -38252 -38253 -38254 -38255 +v -38256 -38257 -38258 -38259 -38260 -38261 -38262 38263 38264 -38265 -38266 +v -38267 -38268 -38269 -38270 -38271 38272 -38273 38274 -38275 -38276 -38277 +v 38278 -38279 38280 -38281 -38282 -38283 38284 -38285 38286 38287 38288 38289 +v -38290 -38291 38292 -38293 -38294 38295 -38296 -38297 -38298 -38299 -38300 +v -38301 -38302 -38303 -38304 -38305 38306 38307 38308 38309 -38310 -38311 +v -38312 -38313 -38314 -38315 -38316 -38317 -38318 -38319 -38320 -38321 -38322 +v -38323 -38324 -38325 -38326 -38327 -38328 -38329 -38330 38331 -38332 -38333 +v -38334 -38335 -38336 -38337 -38338 -38339 38340 38341 -38342 -38343 -38344 +v 38345 -38346 -38347 -38348 -38349 -38350 -38351 -38352 -38353 -38354 -38355 +v -38356 -38357 38358 -38359 38360 -38361 -38362 38363 -38364 38365 -38366 +v -38367 38368 -38369 38370 38371 38372 38373 -38374 -38375 38376 -38377 +v -38378 38379 -38380 -38381 -38382 -38383 -38384 -38385 -38386 -38387 -38388 +v -38389 38390 38391 38392 38393 -38394 -38395 -38396 -38397 -38398 -38399 +v -38400 -38401 -38402 -38403 -38404 -38405 -38406 -38407 -38408 -38409 -38410 +v -38411 -38412 -38413 -38414 38415 -38416 -38417 -38418 -38419 -38420 -38421 +v -38422 -38423 38424 38425 -38426 -38427 -38428 38429 -38430 -38431 -38432 +v -38433 -38434 -38435 -38436 -38437 38438 38439 38440 -38441 -38442 -38443 +v -38444 -38445 -38446 -38447 -38448 38449 -38450 -38451 -38452 -38453 -38454 +v -38455 -38456 -38457 38458 -38459 38460 38461 38462 -38463 -38464 -38465 +v -38466 -38467 -38468 -38469 38470 38471 -38472 -38473 38474 -38475 -38476 +v -38477 -38478 -38479 -38480 -38481 -38482 -38483 38484 -38485 38486 -38487 +v -38488 -38489 38490 -38491 38492 -38493 -38494 -38495 38496 -38497 38498 +v 38499 38500 38501 -38502 -38503 38504 -38505 -38506 38507 -38508 -38509 +v -38510 -38511 -38512 -38513 -38514 -38515 -38516 -38517 38518 38519 38520 +v -38521 -38522 -38523 -38524 -38525 -38526 -38527 -38528 38529 -38530 38531 +v -38532 -38533 -38534 -38535 -38536 38537 38538 38539 38540 38541 -38542 +v 38543 -38544 -38545 -38546 -38547 -38548 -38549 -38550 -38551 -38552 -38553 +v -38554 -38555 -38556 -38557 38558 -38559 -38560 -38561 -38562 -38563 38564 +v -38565 38566 -38567 -38568 -38569 38570 -38571 38572 -38573 -38574 38575 +v -38576 -38577 -38578 -38579 -38580 -38581 38582 38583 38584 38585 -38586 +v 38587 -38588 -38589 -38590 -38591 -38592 -38593 -38594 -38595 -38596 -38597 +v -38598 -38599 -38600 -38601 38602 -38603 -38604 -38605 -38606 -38607 38608 +v -38609 38610 -38611 -38612 -38613 38614 -38615 38616 -38617 -38618 38619 +v -38620 -38621 -38622 -38623 -38624 -38625 38626 38627 38628 38629 -38630 +v 38631 -38632 -38633 -38634 -38635 -38636 -38637 -38638 -38639 -38640 -38641 +v -38642 -38643 -38644 -38645 38646 -38647 -38648 -38649 -38650 -38651 38652 +v -38653 38654 -38655 -38656 -38657 38658 -38659 38660 -38661 -38662 38663 +v -38664 -38665 -38666 -38667 -38668 -38669 38670 38671 38672 38673 -38674 +v 38675 -38676 -38677 -38678 -38679 -38680 -38681 -38682 -38683 -38684 -38685 +v -38686 -38687 -38688 -38689 -38690 -38691 -38692 -38693 -38694 -38695 -38696 +v -38697 -38698 -38699 -38700 -38701 -38702 -38703 -38704 -38705 -38706 -38707 +v -38708 -38709 -38710 -38711 -38712 -38713 -38714 -38715 -38716 -38717 -38718 +v -38719 -38720 -38721 -38722 -38723 -38724 -38725 -38726 -38727 -38728 -38729 +v -38730 -38731 -38732 -38733 -38734 -38735 -38736 -38737 -38738 -38739 -38740 +v -38741 -38742 -38743 -38744 -38745 38746 -38747 -38748 -38749 -38750 -38751 +v -38752 -38753 -38754 -38755 -38756 -38757 -38758 -38759 -38760 -38761 -38762 +v -38763 -38764 -38765 -38766 -38767 -38768 -38769 -38770 -38771 -38772 -38773 +v -38774 -38775 -38776 -38777 -38778 -38779 -38780 -38781 -38782 -38783 -38784 +v -38785 -38786 -38787 -38788 -38789 -38790 -38791 -38792 -38793 -38794 -38795 +v -38796 -38797 -38798 -38799 -38800 -38801 -38802 -38803 38804 -38805 38806 +v -38807 -38808 -38809 38810 -38811 38812 -38813 -38814 -38815 38816 -38817 +v 38818 -38819 -38820 -38821 -38822 38823 -38824 38825 -38826 -38827 38828 +v -38829 -38830 -38831 -38832 -38833 -38834 -38835 -38836 -38837 -38838 38839 +v 38840 38841 38842 -38843 38844 -38845 -38846 -38847 -38848 -38849 -38850 +v -38851 -38852 -38853 -38854 -38855 -38856 -38857 -38858 38859 -38860 -38861 +v -38862 -38863 -38864 38865 -38866 38867 -38868 -38869 -38870 38871 -38872 +v 38873 -38874 -38875 38876 -38877 -38878 -38879 -38880 -38881 -38882 38883 +v 38884 38885 -38886 -38887 -38888 -38889 -38890 -38891 -38892 -38893 -38894 +v -38895 -38896 -38897 -38898 -38899 -38900 -38901 -38902 -38903 -38904 -38905 +v -38906 -38907 -38908 38909 38910 38911 38912 -38913 -38914 -38915 -38916 +v -38917 -38918 -38919 -38920 -38921 -38922 -38923 -38924 -38925 -38926 38927 +v -38928 38929 -38930 -38931 -38932 38933 -38934 -38935 -38936 -38937 -38938 +v -38939 -38940 -38941 -38942 38943 -38944 -38945 -38946 -38947 -38948 -38949 +v -38950 -38951 -38952 -38953 -38954 -38955 -38956 -38957 -38958 -38959 -38960 +v -38961 -38962 38963 38964 38965 38966 -38967 -38968 -38969 -38970 -38971 +v -38972 -38973 -38974 -38975 -38976 -38977 -38978 -38979 38980 -38981 38982 +v -38983 -38984 -38985 38986 -38987 -38988 -38989 -38990 -38991 -38992 -38993 +v -38994 -38995 38996 -38997 38998 -38999 -39000 -39001 -39002 39003 -39004 +v 39005 -39006 -39007 -39008 -39009 39010 -39011 39012 39013 39014 39015 39016 +v -39017 -39018 39019 -39020 -39021 39022 -39023 -39024 -39025 -39026 -39027 +v -39028 -39029 -39030 -39031 -39032 39033 39034 39035 39036 -39037 39038 +v -39039 -39040 -39041 -39042 -39043 -39044 -39045 -39046 -39047 -39048 -39049 +v -39050 -39051 -39052 -39053 -39054 -39055 -39056 -39057 39058 -39059 39060 +v -39061 -39062 -39063 39064 -39065 39066 -39067 -39068 39069 -39070 -39071 +v -39072 -39073 -39074 -39075 39076 39077 39078 39079 39080 -39081 39082 +v -39083 -39084 -39085 -39086 -39087 -39088 -39089 -39090 -39091 -39092 -39093 +v -39094 -39095 -39096 -39097 -39098 -39099 -39100 -39101 39102 -39103 39104 +v -39105 -39106 -39107 39108 -39109 39110 -39111 -39112 39113 -39114 -39115 +v -39116 -39117 -39118 -39119 39120 39121 39122 39123 39124 -39125 39126 +v -39127 -39128 -39129 -39130 -39131 -39132 -39133 -39134 -39135 -39136 -39137 +v -39138 -39139 -39140 -39141 -39142 -39143 -39144 -39145 39146 -39147 39148 +v -39149 -39150 -39151 39152 -39153 39154 -39155 -39156 39157 -39158 -39159 +v -39160 -39161 -39162 -39163 39164 39165 39166 39167 39168 -39169 39170 +v -39171 -39172 -39173 -39174 -39175 -39176 -39177 -39178 -39179 -39180 -39181 +v -39182 -39183 -39184 -39185 -39186 -39187 -39188 -39189 -39190 -39191 -39192 +v -39193 -39194 -39195 -39196 -39197 -39198 -39199 -39200 -39201 -39202 -39203 +v -39204 -39205 -39206 -39207 -39208 -39209 -39210 -39211 -39212 -39213 -39214 +v -39215 -39216 -39217 -39218 -39219 -39220 -39221 -39222 -39223 -39224 -39225 +v -39226 -39227 -39228 -39229 -39230 -39231 -39232 -39233 -39234 -39235 -39236 +v -39237 -39238 -39239 -39240 -39241 -39242 -39243 -39244 -39245 -39246 -39247 +v -39248 -39249 -39250 -39251 -39252 -39253 -39254 -39255 -39256 -39257 -39258 +v -39259 -39260 -39261 -39262 -39263 -39264 -39265 -39266 -39267 -39268 -39269 +v -39270 -39271 -39272 -39273 -39274 -39275 -39276 -39277 -39278 -39279 -39280 +v -39281 -39282 -39283 -39284 -39285 -39286 -39287 -39288 -39289 -39290 -39291 +v -39292 -39293 -39294 -39295 -39296 -39297 39298 -39299 39300 -39301 -39302 +v -39303 39304 -39305 39306 -39307 -39308 -39309 39310 -39311 39312 -39313 +v -39314 -39315 -39316 39317 -39318 39319 -39320 -39321 39322 -39323 -39324 +v -39325 -39326 -39327 -39328 -39329 -39330 -39331 -39332 39333 39334 39335 +v 39336 39337 -39338 39339 -39340 -39341 -39342 -39343 -39344 -39345 -39346 +v -39347 -39348 -39349 -39350 -39351 -39352 -39353 -39354 -39355 -39356 -39357 +v -39358 39359 -39360 39361 -39362 -39363 -39364 39365 -39366 39367 -39368 +v -39369 39370 -39371 -39372 -39373 -39374 -39375 -39376 39377 39378 39379 +v 39380 -39381 -39382 39383 -39384 -39385 39386 39387 -39388 -39389 -39390 +v -39391 -39392 -39393 -39394 -39395 -39396 -39397 -39398 -39399 -39400 -39401 +v -39402 -39403 -39404 -39405 -39406 -39407 -39408 -39409 -39410 -39411 -39412 +v -39413 -39414 -39415 -39416 -39417 -39418 -39419 -39420 -39421 -39422 -39423 +v -39424 -39425 -39426 -39427 -39428 -39429 -39430 -39431 -39432 -39433 -39434 +v -39435 -39436 -39437 -39438 -39439 -39440 -39441 -39442 -39443 -39444 -39445 +v -39446 -39447 -39448 -39449 -39450 -39451 -39452 -39453 -39454 -39455 -39456 +v -39457 -39458 -39459 -39460 -39461 -39462 -39463 -39464 -39465 -39466 -39467 +v -39468 -39469 -39470 -39471 -39472 -39473 -39474 -39475 -39476 -39477 -39478 +v -39479 -39480 -39481 -39482 -39483 -39484 -39485 -39486 -39487 -39488 -39489 +v -39490 -39491 -39492 -39493 -39494 -39495 -39496 -39497 -39498 -39499 -39500 +v -39501 -39502 -39503 -39504 -39505 -39506 -39507 -39508 -39509 -39510 -39511 +v -39512 -39513 -39514 -39515 -39516 -39517 -39518 -39519 -39520 -39521 -39522 +v -39523 -39524 -39525 -39526 -39527 -39528 -39529 -39530 -39531 -39532 -39533 +v -39534 -39535 -39536 -39537 -39538 -39539 -39540 -39541 -39542 -39543 -39544 +v -39545 -39546 -39547 -39548 -39549 -39550 -39551 -39552 -39553 -39554 -39555 +v -39556 -39557 -39558 -39559 -39560 -39561 -39562 -39563 -39564 -39565 -39566 +v -39567 -39568 -39569 -39570 -39571 -39572 -39573 -39574 -39575 -39576 -39577 +v -39578 -39579 -39580 -39581 -39582 -39583 -39584 -39585 -39586 -39587 -39588 +v -39589 -39590 -39591 -39592 -39593 -39594 -39595 -39596 -39597 -39598 -39599 +v -39600 -39601 -39602 -39603 -39604 -39605 -39606 -39607 -39608 -39609 -39610 +v -39611 -39612 -39613 -39614 -39615 -39616 -39617 -39618 -39619 -39620 -39621 +v -39622 -39623 -39624 -39625 -39626 -39627 -39628 -39629 -39630 -39631 -39632 +v -39633 -39634 -39635 -39636 -39637 -39638 -39639 -39640 -39641 -39642 -39643 +v -39644 -39645 -39646 -39647 -39648 -39649 -39650 -39651 -39652 -39653 -39654 +v -39655 -39656 -39657 -39658 -39659 -39660 39661 -39662 -39663 -39664 -39665 +v -39666 -39667 -39668 -39669 -39670 -39671 -39672 -39673 -39674 -39675 -39676 +v -39677 -39678 -39679 -39680 -39681 -39682 -39683 -39684 -39685 -39686 -39687 +v -39688 -39689 -39690 -39691 -39692 -39693 -39694 -39695 -39696 -39697 -39698 +v -39699 -39700 -39701 -39702 -39703 -39704 -39705 -39706 -39707 -39708 -39709 +v -39710 -39711 -39712 -39713 -39714 -39715 -39716 -39717 -39718 -39719 -39720 +v -39721 -39722 -39723 -39724 -39725 -39726 -39727 -39728 -39729 -39730 -39731 +v -39732 -39733 -39734 -39735 -39736 -39737 -39738 -39739 -39740 -39741 -39742 +v -39743 -39744 -39745 -39746 -39747 -39748 -39749 -39750 -39751 -39752 -39753 +v -39754 -39755 -39756 -39757 -39758 -39759 -39760 -39761 -39762 -39763 -39764 +v -39765 -39766 -39767 -39768 -39769 -39770 -39771 -39772 -39773 -39774 -39775 +v -39776 -39777 -39778 -39779 -39780 -39781 -39782 -39783 -39784 -39785 -39786 +v -39787 -39788 -39789 -39790 -39791 -39792 -39793 -39794 -39795 -39796 -39797 +v -39798 -39799 -39800 -39801 -39802 -39803 -39804 -39805 -39806 -39807 -39808 +v -39809 -39810 -39811 -39812 -39813 -39814 -39815 -39816 -39817 -39818 -39819 +v -39820 -39821 -39822 -39823 -39824 -39825 -39826 -39827 -39828 -39829 -39830 +v -39831 -39832 -39833 -39834 -39835 -39836 -39837 -39838 -39839 -39840 -39841 +v -39842 -39843 -39844 -39845 -39846 -39847 -39848 -39849 -39850 -39851 -39852 +v -39853 -39854 -39855 -39856 -39857 -39858 -39859 -39860 -39861 -39862 -39863 +v -39864 -39865 -39866 -39867 -39868 -39869 -39870 -39871 39872 -39873 39874 +v -39875 -39876 39877 -39878 39879 -39880 -39881 -39882 39883 -39884 39885 +v -39886 -39887 -39888 39889 -39890 39891 -39892 -39893 -39894 39895 -39896 +v 39897 -39898 -39899 -39900 39901 -39902 39903 -39904 -39905 39906 -39907 +v 39908 -39909 -39910 -39911 -39912 -39913 -39914 -39915 -39916 -39917 -39918 +v -39919 -39920 -39921 -39922 -39923 39924 39925 39926 39927 -39928 -39929 +v -39930 -39931 -39932 39933 -39934 -39935 -39936 -39937 -39938 -39939 -39940 +v -39941 -39942 -39943 -39944 -39945 -39946 -39947 -39948 -39949 -39950 -39951 +v -39952 -39953 -39954 -39955 -39956 -39957 -39958 -39959 -39960 -39961 -39962 +v -39963 -39964 -39965 -39966 -39967 -39968 -39969 -39970 -39971 -39972 -39973 +v -39974 -39975 -39976 -39977 -39978 -39979 -39980 -39981 -39982 -39983 -39984 +v -39985 -39986 -39987 -39988 -39989 -39990 -39991 -39992 -39993 -39994 -39995 +v -39996 -39997 -39998 -39999 -40000 -40001 -40002 -40003 -40004 -40005 -40006 +v -40007 -40008 -40009 -40010 -40011 -40012 -40013 -40014 -40015 -40016 -40017 +v -40018 -40019 -40020 -40021 -40022 -40023 -40024 -40025 -40026 -40027 -40028 +v -40029 -40030 -40031 -40032 -40033 -40034 -40035 -40036 -40037 -40038 -40039 +v -40040 -40041 -40042 -40043 -40044 -40045 -40046 -40047 -40048 -40049 -40050 +v -40051 -40052 -40053 40054 -40055 40056 -40057 -40058 -40059 -40060 40061 +v -40062 40063 -40064 -40065 -40066 -40067 40068 -40069 40070 -40071 -40072 +v -40073 -40074 40075 -40076 40077 -40078 -40079 40080 -40081 40082 -40083 +v -40084 40085 -40086 -40087 -40088 -40089 -40090 -40091 -40092 -40093 -40094 +v -40095 -40096 -40097 40098 40099 40100 40101 -40102 -40103 -40104 -40105 +v -40106 -40107 -40108 -40109 -40110 -40111 -40112 -40113 -40114 -40115 -40116 +v -40117 -40118 -40119 -40120 -40121 -40122 -40123 -40124 -40125 -40126 -40127 +v -40128 -40129 -40130 -40131 -40132 -40133 -40134 -40135 -40136 -40137 -40138 +v -40139 -40140 -40141 -40142 -40143 -40144 -40145 -40146 -40147 -40148 40149 +v -40150 -40151 40152 -40153 -40154 40155 -40156 -40157 -40158 40159 -40160 +v -40161 -40162 -40163 -40164 -40165 -40166 -40167 -40168 -40169 -40170 40171 +v -40172 40173 40174 40175 40176 -40177 -40178 -40179 -40180 -40181 -40182 +v -40183 -40184 -40185 -40186 -40187 -40188 -40189 -40190 -40191 -40192 -40193 +v -40194 -40195 -40196 -40197 -40198 -40199 -40200 -40201 -40202 -40203 -40204 +v -40205 -40206 -40207 -40208 -40209 -40210 -40211 -40212 -40213 -40214 -40215 +v -40216 -40217 -40218 -40219 -40220 -40221 -40222 -40223 -40224 -40225 -40226 +v -40227 -40228 -40229 -40230 -40231 -40232 -40233 -40234 -40235 -40236 -40237 +v -40238 -40239 -40240 -40241 -40242 -40243 -40244 -40245 -40246 -40247 -40248 +v -40249 -40250 -40251 -40252 -40253 -40254 -40255 -40256 -40257 -40258 -40259 +v -40260 -40261 40262 -40263 40264 -40265 -40266 40267 -40268 40269 -40270 +v -40271 40272 -40273 40274 -40275 -40276 -40277 40278 -40279 40280 -40281 +v -40282 40283 -40284 -40285 -40286 -40287 -40288 -40289 -40290 -40291 -40292 +v -40293 40294 -40295 40296 40297 40298 40299 -40300 -40301 -40302 -40303 +v -40304 -40305 -40306 -40307 40308 -40309 40310 -40311 40312 -40313 -40314 +v -40315 -40316 40317 40318 40319 40320 -40321 -40322 -40323 -40324 -40325 +v -40326 -40327 -40328 -40329 -40330 -40331 -40332 -40333 -40334 -40335 -40336 +v -40337 -40338 -40339 -40340 -40341 -40342 -40343 -40344 -40345 -40346 -40347 +v -40348 -40349 -40350 -40351 -40352 -40353 -40354 -40355 -40356 -40357 -40358 +v -40359 -40360 -40361 -40362 -40363 -40364 -40365 -40366 40367 -40368 -40369 +v -40370 -40371 -40372 -40373 -40374 -40375 40376 40377 -40378 -40379 -40380 +v 40381 -40382 -40383 -40384 -40385 -40386 -40387 -40388 -40389 -40390 -40391 +v -40392 -40393 -40394 -40395 -40396 -40397 -40398 -40399 -40400 -40401 -40402 +v -40403 -40404 -40405 -40406 40407 40408 40409 40410 -40411 -40412 -40413 +v -40414 -40415 -40416 -40417 -40418 -40419 -40420 -40421 -40422 -40423 40424 +v -40425 40426 -40427 -40428 -40429 40430 -40431 -40432 -40433 -40434 -40435 +v -40436 -40437 -40438 40439 -40440 40441 -40442 -40443 -40444 40445 -40446 +v 40447 -40448 -40449 -40450 40451 -40452 40453 40454 40455 40456 40457 -40458 +v -40459 40460 -40461 -40462 40463 -40464 -40465 -40466 -40467 -40468 -40469 +v -40470 -40471 -40472 -40473 40474 40475 40476 40477 -40478 -40479 -40480 +v -40481 -40482 -40483 -40484 -40485 -40486 40487 -40488 -40489 40490 -40491 +v -40492 -40493 -40494 -40495 40496 40497 40498 40499 -40500 -40501 -40502 +v -40503 -40504 40505 -40506 40507 -40508 40509 -40510 40511 -40512 -40513 +v 40514 -40515 -40516 40517 -40518 -40519 -40520 -40521 -40522 -40523 -40524 +v -40525 40526 40527 40528 40529 40530 40531 -40532 -40533 40534 40535 40536 +v 40537 40538 40539 40540 40541 -40542 -40543 -40544 -40545 -40546 -40547 +v -40548 -40549 -40550 -40551 -40552 -40553 -40554 -40555 -40556 -40557 -40558 +v -40559 -40560 -40561 -40562 -40563 -40564 -40565 40566 40567 -40568 -40569 +v 40570 -40571 -40572 -40573 -40574 -40575 -40576 -40577 -40578 -40579 -40580 +v -40581 -40582 -40583 -40584 -40585 -40586 40587 -40588 -40589 -40590 -40591 +v -40592 -40593 -40594 40595 40596 40597 -40598 -40599 -40600 -40601 -40602 +v -40603 -40604 -40605 -40606 -40607 -40608 -40609 -40610 -40611 -40612 40613 +v -40614 -40615 -40616 -40617 -40618 -40619 -40620 -40621 -40622 -40623 -40624 +v -40625 -40626 -40627 -40628 -40629 -40630 -40631 -40632 -40633 -40634 -40635 +v -40636 -40637 -40638 40639 40640 40641 -40642 -40643 -40644 -40645 -40646 +v -40647 -40648 -40649 -40650 -40651 40652 -40653 -40654 -40655 -40656 -40657 +v -40658 -40659 -40660 40661 -40662 -40663 -40664 -40665 -40666 -40667 -40668 +v -40669 -40670 40671 40672 40673 -40674 -40675 -40676 -40677 -40678 -40679 +v 40680 40681 40682 40683 -40684 -40685 -40686 -40687 -40688 40689 -40690 +v -40691 -40692 -40693 -40694 -40695 -40696 -40697 -40698 -40699 -40700 -40701 +v -40702 -40703 -40704 -40705 -40706 -40707 -40708 -40709 -40710 -40711 -40712 +v -40713 -40714 -40715 40716 40717 40718 -40719 -40720 -40721 -40722 -40723 +v -40724 -40725 40726 40727 -40728 -40729 -40730 -40731 40732 -40733 -40734 +v -40735 -40736 -40737 40738 -40739 -40740 -40741 -40742 -40743 -40744 -40745 +v -40746 -40747 -40748 -40749 -40750 -40751 -40752 -40753 -40754 -40755 -40756 +v -40757 -40758 -40759 -40760 -40761 -40762 -40763 -40764 -40765 -40766 -40767 +v -40768 -40769 40770 -40771 -40772 40773 -40774 -40775 -40776 -40777 -40778 +v -40779 -40780 -40781 -40782 -40783 -40784 -40785 -40786 -40787 40788 40789 +v 40790 40791 -40792 40793 40794 40795 -40796 -40797 -40798 -40799 -40800 +v -40801 -40802 -40803 -40804 -40805 -40806 -40807 -40808 40809 40810 -40811 +v -40812 -40813 -40814 -40815 40816 -40817 -40818 -40819 -40820 -40821 40822 +v -40823 -40824 -40825 -40826 -40827 -40828 -40829 -40830 -40831 40832 40833 +v -40834 -40835 40836 40837 40838 40839 40840 40841 40842 -40843 -40844 -40845 +v -40846 -40847 -40848 -40849 -40850 -40851 40852 40853 -40854 -40855 -40856 +v -40857 40858 -40859 -40860 -40861 -40862 -40863 -40864 -40865 -40866 -40867 +v -40868 -40869 -40870 40871 -40872 -40873 -40874 -40875 40876 40877 -40878 +v -40879 -40880 -40881 -40882 -40883 -40884 -40885 -40886 -40887 -40888 -40889 +v 40890 -40891 -40892 -40893 -40894 -40895 -40896 -40897 -40898 -40899 -40900 +v -40901 -40902 -40903 -40904 -40905 -40906 40907 -40908 -40909 -40910 -40911 +v -40912 -40913 -40914 -40915 -40916 -40917 -40918 -40919 -40920 -40921 -40922 +v -40923 -40924 -40925 -40926 -40927 -40928 40929 40930 -40931 -40932 -40933 +v -40934 -40935 -40936 -40937 -40938 40939 -40940 -40941 -40942 -40943 -40944 +v -40945 -40946 -40947 40948 -40949 -40950 -40951 -40952 -40953 -40954 40955 +v 40956 -40957 -40958 -40959 -40960 -40961 40962 40963 40964 40965 -40966 +v -40967 -40968 -40969 -40970 -40971 -40972 -40973 -40974 -40975 -40976 -40977 +v -40978 40979 40980 -40981 -40982 -40983 -40984 -40985 40986 40987 -40988 +v -40989 -40990 -40991 40992 -40993 -40994 -40995 -40996 -40997 40998 -40999 +v -41000 -41001 -41002 -41003 -41004 41005 41006 -41007 -41008 -41009 41010 +v 41011 41012 -41013 -41014 -41015 -41016 -41017 -41018 41019 -41020 41021 +v -41022 -41023 41024 -41025 41026 -41027 -41028 -41029 41030 -41031 41032 +v 41033 41034 41035 -41036 -41037 41038 -41039 -41040 -41041 41042 -41043 +v 41044 41045 41046 41047 -41048 -41049 41050 -41051 -41052 41053 -41054 +v -41055 -41056 -41057 -41058 -41059 -41060 -41061 -41062 -41063 -41064 -41065 +v -41066 -41067 41068 41069 41070 41071 -41072 -41073 41074 41075 41076 41077 +v -41078 -41079 -41080 -41081 -41082 -41083 -41084 -41085 -41086 -41087 41088 +v 41089 -41090 -41091 41092 -41093 -41094 -41095 -41096 -41097 -41098 -41099 +v -41100 -41101 -41102 -41103 -41104 -41105 -41106 -41107 -41108 -41109 -41110 +v -41111 -41112 -41113 -41114 -41115 -41116 -41117 -41118 41119 41120 41121 +v -41122 -41123 -41124 -41125 -41126 -41127 -41128 41129 41130 -41131 -41132 +v 41133 -41134 -41135 -41136 -41137 -41138 -41139 -41140 -41141 -41142 -41143 +v -41144 -41145 41146 41147 -41148 -41149 -41150 -41151 -41152 -41153 -41154 +v 41155 -41156 41157 -41158 -41159 -41160 41161 -41162 41163 -41164 -41165 +v -41166 41167 -41168 41169 41170 41171 41172 -41173 -41174 41175 -41176 +v -41177 41178 -41179 -41180 -41181 -41182 -41183 -41184 -41185 -41186 -41187 +v -41188 41189 41190 41191 41192 -41193 -41194 -41195 -41196 -41197 -41198 +v -41199 -41200 -41201 -41202 -41203 -41204 -41205 -41206 -41207 -41208 -41209 +v -41210 -41211 -41212 -41213 41214 -41215 -41216 -41217 -41218 -41219 -41220 +v -41221 -41222 41223 41224 -41225 -41226 -41227 41228 -41229 -41230 -41231 +v -41232 -41233 -41234 -41235 -41236 -41237 -41238 -41239 -41240 41241 -41242 +v 41243 -41244 -41245 41246 -41247 41248 -41249 -41250 41251 -41252 41253 +v 41254 41255 41256 -41257 -41258 41259 -41260 -41261 41262 -41263 -41264 +v -41265 -41266 -41267 -41268 -41269 -41270 -41271 -41272 41273 41274 41275 +v 41276 -41277 -41278 -41279 -41280 -41281 -41282 -41283 -41284 -41285 -41286 +v -41287 -41288 -41289 -41290 -41291 -41292 -41293 -41294 -41295 -41296 -41297 +v 41298 -41299 -41300 -41301 -41302 -41303 -41304 -41305 -41306 41307 41308 +v -41309 -41310 -41311 41312 -41313 -41314 -41315 -41316 -41317 -41318 -41319 +v 41320 41321 41322 -41323 -41324 -41325 -41326 -41327 -41328 -41329 41330 +v 41331 -41332 -41333 41334 -41335 -41336 -41337 -41338 -41339 -41340 -41341 +v -41342 -41343 -41344 -41345 -41346 41347 41348 41349 -41350 -41351 -41352 +v -41353 -41354 -41355 41356 -41357 -41358 -41359 -41360 -41361 -41362 -41363 +v 41364 -41365 41366 -41367 -41368 41369 -41370 41371 -41372 -41373 41374 +v -41375 41376 41377 41378 41379 -41380 -41381 41382 -41383 -41384 41385 +v -41386 -41387 -41388 -41389 -41390 -41391 -41392 -41393 -41394 -41395 41396 +v 41397 41398 41399 -41400 -41401 -41402 -41403 -41404 -41405 -41406 -41407 +v 41408 -41409 41410 -41411 -41412 -41413 -41414 -41415 41416 41417 41418 +v 41419 41420 -41421 41422 -41423 -41424 -41425 -41426 -41427 -41428 -41429 +v -41430 -41431 -41432 -41433 -41434 -41435 -41436 41437 -41438 -41439 -41440 +v -41441 -41442 41443 -41444 41445 -41446 -41447 -41448 41449 -41450 41451 +v -41452 -41453 41454 -41455 -41456 -41457 -41458 -41459 -41460 41461 41462 +v 41463 41464 -41465 41466 -41467 -41468 -41469 -41470 -41471 -41472 -41473 +v -41474 -41475 -41476 -41477 -41478 -41479 -41480 41481 -41482 -41483 -41484 +v -41485 -41486 41487 -41488 41489 -41490 -41491 -41492 41493 -41494 41495 +v -41496 -41497 41498 -41499 -41500 -41501 -41502 -41503 -41504 41505 41506 +v 41507 41508 -41509 41510 -41511 -41512 -41513 -41514 -41515 -41516 -41517 +v -41518 -41519 -41520 -41521 -41522 -41523 -41524 41525 -41526 -41527 -41528 +v -41529 -41530 41531 -41532 41533 -41534 -41535 -41536 41537 -41538 41539 +v -41540 -41541 41542 -41543 -41544 -41545 -41546 -41547 -41548 41549 41550 +v 41551 41552 -41553 41554 -41555 -41556 -41557 -41558 -41559 -41560 -41561 +v -41562 -41563 -41564 -41565 -41566 -41567 -41568 -41569 -41570 -41571 -41572 +v -41573 -41574 -41575 -41576 -41577 -41578 -41579 -41580 -41581 -41582 -41583 +v -41584 -41585 -41586 -41587 -41588 -41589 -41590 -41591 -41592 -41593 -41594 +v -41595 -41596 -41597 -41598 -41599 -41600 -41601 -41602 -41603 -41604 -41605 +v -41606 -41607 -41608 -41609 -41610 -41611 -41612 -41613 -41614 -41615 -41616 +v -41617 -41618 -41619 -41620 -41621 -41622 -41623 -41624 41625 -41626 -41627 +v -41628 -41629 -41630 -41631 -41632 -41633 -41634 -41635 -41636 -41637 -41638 +v -41639 -41640 -41641 -41642 -41643 -41644 -41645 -41646 -41647 -41648 -41649 +v -41650 -41651 -41652 -41653 -41654 -41655 -41656 -41657 -41658 -41659 -41660 +v -41661 -41662 -41663 -41664 -41665 -41666 -41667 -41668 -41669 -41670 -41671 +v -41672 -41673 -41674 -41675 -41676 -41677 -41678 -41679 -41680 -41681 -41682 +v 41683 -41684 41685 -41686 -41687 -41688 41689 -41690 41691 -41692 -41693 +v -41694 41695 -41696 41697 -41698 -41699 -41700 -41701 41702 -41703 41704 +v -41705 -41706 41707 -41708 -41709 -41710 -41711 -41712 -41713 -41714 -41715 +v -41716 -41717 41718 41719 41720 41721 -41722 41723 -41724 -41725 -41726 +v -41727 -41728 -41729 -41730 -41731 -41732 -41733 -41734 -41735 -41736 -41737 +v 41738 -41739 -41740 -41741 -41742 -41743 41744 -41745 41746 -41747 -41748 +v -41749 41750 -41751 41752 -41753 -41754 41755 -41756 -41757 -41758 -41759 +v -41760 -41761 41762 41763 41764 -41765 -41766 -41767 -41768 -41769 -41770 +v -41771 -41772 -41773 -41774 -41775 -41776 -41777 -41778 -41779 -41780 -41781 +v -41782 -41783 -41784 -41785 -41786 -41787 41788 41789 41790 41791 -41792 +v -41793 -41794 -41795 -41796 -41797 -41798 -41799 -41800 -41801 -41802 -41803 +v -41804 -41805 41806 -41807 41808 -41809 -41810 -41811 41812 -41813 -41814 +v -41815 -41816 -41817 -41818 -41819 -41820 -41821 41822 -41823 -41824 -41825 +v -41826 -41827 -41828 -41829 -41830 -41831 -41832 -41833 -41834 -41835 -41836 +v -41837 -41838 -41839 -41840 -41841 41842 41843 41844 41845 -41846 -41847 +v -41848 -41849 -41850 -41851 -41852 -41853 -41854 -41855 -41856 -41857 -41858 +v 41859 -41860 41861 -41862 -41863 -41864 41865 -41866 -41867 -41868 -41869 +v -41870 -41871 -41872 -41873 -41874 41875 -41876 41877 -41878 -41879 -41880 +v -41881 41882 -41883 41884 -41885 -41886 -41887 -41888 41889 -41890 41891 +v 41892 41893 41894 41895 -41896 -41897 41898 -41899 -41900 41901 -41902 +v -41903 -41904 -41905 -41906 -41907 -41908 -41909 -41910 -41911 41912 41913 +v 41914 41915 -41916 41917 -41918 -41919 -41920 -41921 -41922 -41923 -41924 +v -41925 -41926 -41927 -41928 -41929 -41930 -41931 -41932 -41933 -41934 -41935 +v -41936 41937 -41938 41939 -41940 -41941 -41942 41943 -41944 41945 -41946 +v -41947 41948 -41949 -41950 -41951 -41952 -41953 -41954 41955 41956 41957 +v 41958 41959 -41960 41961 -41962 -41963 -41964 -41965 -41966 -41967 -41968 +v -41969 -41970 -41971 -41972 -41973 -41974 -41975 -41976 -41977 -41978 -41979 +v -41980 41981 -41982 41983 -41984 -41985 -41986 41987 -41988 41989 -41990 +v -41991 41992 -41993 -41994 -41995 -41996 -41997 -41998 41999 42000 42001 +v 42002 42003 -42004 42005 -42006 -42007 -42008 -42009 -42010 -42011 -42012 +v -42013 -42014 -42015 -42016 -42017 -42018 -42019 -42020 -42021 -42022 -42023 +v -42024 42025 -42026 42027 -42028 -42029 -42030 42031 -42032 42033 -42034 +v -42035 42036 -42037 -42038 -42039 -42040 -42041 -42042 42043 42044 42045 +v 42046 42047 -42048 42049 -42050 -42051 -42052 -42053 -42054 -42055 -42056 +v -42057 -42058 -42059 -42060 -42061 -42062 -42063 -42064 -42065 -42066 -42067 +v -42068 -42069 -42070 -42071 -42072 -42073 -42074 -42075 -42076 -42077 -42078 +v -42079 -42080 -42081 -42082 -42083 -42084 -42085 -42086 -42087 -42088 -42089 +v -42090 -42091 -42092 -42093 -42094 -42095 -42096 -42097 -42098 -42099 -42100 +v -42101 -42102 -42103 -42104 -42105 -42106 -42107 -42108 -42109 -42110 -42111 +v -42112 -42113 -42114 -42115 -42116 -42117 -42118 -42119 -42120 -42121 -42122 +v -42123 -42124 -42125 -42126 -42127 -42128 -42129 -42130 -42131 -42132 -42133 +v -42134 -42135 -42136 -42137 -42138 -42139 -42140 -42141 -42142 -42143 -42144 +v -42145 -42146 -42147 -42148 -42149 -42150 -42151 -42152 -42153 -42154 -42155 +v -42156 -42157 -42158 -42159 -42160 -42161 -42162 -42163 -42164 -42165 -42166 +v -42167 -42168 -42169 -42170 -42171 -42172 -42173 -42174 -42175 -42176 42177 +v -42178 42179 -42180 -42181 -42182 42183 -42184 42185 -42186 -42187 -42188 +v 42189 -42190 42191 -42192 -42193 -42194 -42195 42196 -42197 42198 -42199 +v -42200 42201 -42202 -42203 -42204 -42205 -42206 -42207 -42208 -42209 -42210 +v -42211 42212 42213 42214 42215 42216 -42217 42218 -42219 -42220 -42221 +v -42222 -42223 -42224 -42225 -42226 -42227 -42228 -42229 -42230 -42231 -42232 +v -42233 -42234 -42235 -42236 -42237 42238 -42239 42240 -42241 -42242 -42243 +v 42244 -42245 42246 -42247 -42248 42249 -42250 -42251 -42252 -42253 -42254 +v -42255 42256 42257 42258 42259 -42260 -42261 42262 -42263 -42264 42265 42266 +v -42267 -42268 -42269 -42270 -42271 -42272 -42273 -42274 -42275 -42276 -42277 +v -42278 -42279 -42280 -42281 -42282 -42283 -42284 -42285 -42286 -42287 -42288 +v -42289 -42290 -42291 -42292 -42293 -42294 -42295 -42296 -42297 -42298 -42299 +v -42300 -42301 -42302 -42303 -42304 -42305 -42306 -42307 -42308 -42309 -42310 +v -42311 -42312 -42313 -42314 -42315 -42316 -42317 -42318 -42319 -42320 -42321 +v -42322 -42323 -42324 -42325 -42326 -42327 -42328 -42329 -42330 -42331 -42332 +v -42333 -42334 -42335 -42336 -42337 -42338 -42339 -42340 -42341 -42342 -42343 +v -42344 -42345 -42346 -42347 -42348 -42349 -42350 -42351 -42352 -42353 -42354 +v -42355 -42356 -42357 -42358 -42359 -42360 -42361 -42362 -42363 -42364 -42365 +v -42366 -42367 -42368 -42369 -42370 -42371 -42372 -42373 -42374 -42375 -42376 +v -42377 -42378 -42379 -42380 -42381 -42382 -42383 -42384 -42385 -42386 -42387 +v -42388 -42389 -42390 -42391 -42392 -42393 -42394 -42395 -42396 -42397 -42398 +v -42399 -42400 -42401 -42402 -42403 -42404 -42405 -42406 -42407 -42408 -42409 +v -42410 -42411 -42412 -42413 -42414 -42415 -42416 -42417 -42418 -42419 -42420 +v -42421 -42422 -42423 -42424 -42425 -42426 -42427 -42428 -42429 -42430 -42431 +v -42432 -42433 -42434 -42435 -42436 -42437 -42438 -42439 -42440 -42441 -42442 +v -42443 -42444 -42445 -42446 -42447 -42448 -42449 -42450 -42451 -42452 -42453 +v -42454 -42455 -42456 -42457 -42458 -42459 -42460 -42461 -42462 -42463 -42464 +v -42465 -42466 -42467 -42468 -42469 -42470 -42471 -42472 -42473 -42474 -42475 +v -42476 -42477 -42478 -42479 -42480 -42481 -42482 -42483 -42484 -42485 -42486 +v -42487 -42488 -42489 -42490 -42491 -42492 -42493 -42494 -42495 -42496 -42497 +v -42498 -42499 -42500 -42501 -42502 -42503 -42504 -42505 -42506 -42507 -42508 +v -42509 -42510 -42511 -42512 -42513 -42514 -42515 -42516 -42517 -42518 -42519 +v -42520 -42521 -42522 -42523 -42524 -42525 -42526 -42527 -42528 -42529 -42530 +v -42531 -42532 -42533 -42534 -42535 -42536 -42537 -42538 -42539 -42540 -42541 +v -42542 -42543 -42544 -42545 -42546 -42547 -42548 -42549 -42550 -42551 -42552 +v -42553 -42554 -42555 -42556 -42557 -42558 -42559 -42560 -42561 -42562 -42563 +v -42564 -42565 -42566 -42567 -42568 -42569 -42570 -42571 -42572 -42573 -42574 +v -42575 -42576 -42577 -42578 -42579 -42580 -42581 -42582 -42583 -42584 -42585 +v -42586 -42587 -42588 -42589 -42590 -42591 -42592 -42593 -42594 -42595 -42596 +v -42597 -42598 -42599 -42600 -42601 -42602 -42603 -42604 -42605 -42606 -42607 +v -42608 -42609 -42610 -42611 -42612 -42613 -42614 -42615 -42616 -42617 -42618 +v -42619 -42620 -42621 -42622 -42623 -42624 -42625 -42626 -42627 -42628 -42629 +v -42630 -42631 -42632 -42633 -42634 -42635 -42636 -42637 -42638 -42639 -42640 +v -42641 -42642 -42643 -42644 -42645 -42646 -42647 -42648 -42649 -42650 -42651 +v -42652 -42653 -42654 -42655 -42656 -42657 -42658 -42659 -42660 -42661 -42662 +v -42663 -42664 -42665 -42666 -42667 -42668 -42669 -42670 -42671 -42672 -42673 +v -42674 -42675 -42676 -42677 -42678 -42679 -42680 -42681 -42682 -42683 -42684 +v -42685 -42686 -42687 -42688 -42689 -42690 -42691 -42692 -42693 -42694 -42695 +v -42696 -42697 -42698 -42699 -42700 -42701 -42702 -42703 -42704 -42705 -42706 +v -42707 -42708 -42709 -42710 -42711 -42712 -42713 -42714 -42715 -42716 -42717 +v -42718 -42719 -42720 -42721 -42722 -42723 -42724 -42725 -42726 -42727 -42728 +v -42729 -42730 -42731 -42732 -42733 -42734 -42735 -42736 -42737 -42738 -42739 +v -42740 -42741 -42742 -42743 42744 -42745 42746 -42747 -42748 42749 -42750 +v 42751 -42752 -42753 -42754 42755 -42756 42757 -42758 -42759 -42760 42761 +v -42762 42763 -42764 -42765 -42766 42767 -42768 42769 -42770 -42771 -42772 +v 42773 -42774 42775 -42776 -42777 42778 -42779 42780 -42781 -42782 -42783 +v -42784 -42785 -42786 -42787 -42788 -42789 -42790 -42791 -42792 -42793 -42794 +v -42795 42796 42797 42798 42799 -42800 -42801 -42802 -42803 -42804 42805 +v -42806 -42807 -42808 -42809 -42810 -42811 -42812 -42813 -42814 -42815 -42816 +v -42817 -42818 -42819 -42820 -42821 -42822 -42823 -42824 -42825 -42826 -42827 +v -42828 -42829 -42830 -42831 -42832 -42833 -42834 -42835 -42836 -42837 -42838 +v -42839 -42840 -42841 -42842 -42843 -42844 -42845 -42846 -42847 -42848 -42849 +v -42850 -42851 -42852 -42853 -42854 -42855 -42856 -42857 -42858 -42859 -42860 +v -42861 -42862 -42863 -42864 -42865 -42866 -42867 -42868 -42869 -42870 -42871 +v -42872 -42873 -42874 -42875 -42876 -42877 -42878 -42879 -42880 -42881 -42882 +v -42883 -42884 -42885 -42886 -42887 -42888 -42889 -42890 -42891 -42892 -42893 +v -42894 -42895 -42896 -42897 -42898 -42899 -42900 -42901 -42902 -42903 -42904 +v -42905 -42906 -42907 -42908 -42909 -42910 -42911 -42912 -42913 -42914 -42915 +v -42916 -42917 -42918 -42919 -42920 -42921 -42922 -42923 -42924 -42925 42926 +v -42927 42928 -42929 -42930 -42931 -42932 42933 -42934 42935 -42936 -42937 +v -42938 -42939 42940 -42941 42942 -42943 -42944 -42945 -42946 42947 -42948 +v 42949 -42950 -42951 42952 -42953 42954 -42955 -42956 42957 -42958 -42959 +v -42960 -42961 -42962 -42963 -42964 -42965 -42966 -42967 -42968 -42969 42970 +v 42971 42972 42973 -42974 -42975 -42976 -42977 -42978 -42979 -42980 -42981 +v -42982 -42983 -42984 -42985 -42986 -42987 -42988 -42989 -42990 -42991 -42992 +v -42993 -42994 -42995 -42996 -42997 -42998 -42999 -43000 -43001 -43002 -43003 +v -43004 -43005 -43006 -43007 -43008 -43009 -43010 -43011 -43012 -43013 -43014 +v -43015 -43016 -43017 -43018 -43019 -43020 43021 -43022 -43023 43024 -43025 +v -43026 43027 -43028 -43029 -43030 43031 -43032 -43033 -43034 -43035 -43036 +v -43037 -43038 -43039 -43040 -43041 -43042 43043 -43044 43045 43046 43047 +v 43048 -43049 -43050 -43051 -43052 -43053 -43054 -43055 -43056 -43057 -43058 +v -43059 -43060 -43061 -43062 -43063 -43064 -43065 -43066 -43067 -43068 -43069 +v -43070 -43071 -43072 -43073 -43074 -43075 -43076 -43077 -43078 -43079 -43080 +v -43081 -43082 -43083 -43084 -43085 -43086 -43087 -43088 -43089 -43090 -43091 +v -43092 -43093 -43094 -43095 -43096 -43097 -43098 -43099 -43100 -43101 -43102 +v -43103 -43104 -43105 -43106 -43107 -43108 -43109 -43110 -43111 -43112 -43113 +v -43114 -43115 -43116 -43117 -43118 -43119 -43120 -43121 -43122 -43123 -43124 +v -43125 -43126 -43127 -43128 -43129 -43130 -43131 -43132 -43133 43134 -43135 +v 43136 -43137 -43138 43139 -43140 43141 -43142 -43143 43144 -43145 43146 +v -43147 -43148 -43149 43150 -43151 43152 -43153 -43154 43155 -43156 -43157 +v -43158 -43159 -43160 -43161 -43162 -43163 -43164 -43165 43166 -43167 43168 +v 43169 43170 43171 -43172 -43173 -43174 -43175 -43176 -43177 -43178 -43179 +v 43180 -43181 43182 -43183 43184 -43185 -43186 -43187 -43188 43189 43190 +v 43191 43192 -43193 -43194 -43195 -43196 -43197 -43198 -43199 -43200 -43201 +v -43202 -43203 -43204 -43205 -43206 -43207 -43208 -43209 -43210 -43211 -43212 +v -43213 -43214 -43215 -43216 -43217 -43218 -43219 -43220 -43221 -43222 -43223 +v -43224 -43225 -43226 -43227 -43228 -43229 -43230 -43231 -43232 -43233 -43234 +v -43235 -43236 -43237 -43238 43239 -43240 -43241 -43242 -43243 -43244 -43245 +v -43246 -43247 43248 43249 -43250 -43251 -43252 43253 -43254 -43255 -43256 +v -43257 -43258 -43259 -43260 -43261 -43262 -43263 -43264 -43265 -43266 -43267 +v -43268 -43269 -43270 -43271 -43272 -43273 -43274 -43275 -43276 -43277 -43278 +v 43279 43280 43281 43282 -43283 -43284 -43285 -43286 -43287 -43288 -43289 +v -43290 -43291 -43292 -43293 -43294 -43295 43296 -43297 43298 -43299 -43300 +v -43301 43302 -43303 -43304 -43305 -43306 -43307 -43308 -43309 -43310 43311 +v -43312 43313 -43314 -43315 -43316 43317 -43318 43319 -43320 -43321 -43322 +v 43323 -43324 43325 43326 43327 43328 43329 -43330 -43331 43332 -43333 -43334 +v 43335 -43336 -43337 -43338 -43339 -43340 -43341 -43342 -43343 -43344 -43345 +v 43346 43347 43348 43349 -43350 -43351 -43352 -43353 -43354 -43355 -43356 +v -43357 -43358 43359 -43360 -43361 43362 -43363 -43364 -43365 -43366 -43367 +v 43368 43369 43370 43371 -43372 -43373 -43374 -43375 -43376 43377 -43378 +v 43379 -43380 43381 -43382 43383 -43384 -43385 43386 -43387 -43388 43389 +v -43390 -43391 -43392 -43393 -43394 -43395 -43396 -43397 43398 43399 43400 +v 43401 43402 43403 -43404 -43405 43406 43407 43408 43409 43410 43411 43412 +v 43413 -43414 -43415 -43416 -43417 -43418 -43419 -43420 -43421 -43422 -43423 +v -43424 -43425 -43426 -43427 -43428 -43429 -43430 -43431 -43432 -43433 -43434 +v -43435 -43436 -43437 43438 43439 -43440 -43441 43442 -43443 -43444 -43445 +v -43446 -43447 -43448 -43449 -43450 -43451 -43452 -43453 -43454 -43455 -43456 +v -43457 -43458 43459 -43460 -43461 -43462 -43463 -43464 -43465 -43466 43467 +v 43468 43469 -43470 -43471 -43472 -43473 -43474 -43475 -43476 -43477 -43478 +v -43479 -43480 -43481 -43482 -43483 -43484 43485 -43486 -43487 -43488 -43489 +v -43490 -43491 -43492 -43493 -43494 -43495 -43496 -43497 -43498 -43499 -43500 +v -43501 -43502 -43503 -43504 -43505 -43506 -43507 -43508 -43509 -43510 43511 +v 43512 43513 -43514 -43515 -43516 -43517 -43518 -43519 -43520 -43521 -43522 +v -43523 43524 -43525 -43526 -43527 -43528 -43529 -43530 -43531 -43532 43533 +v -43534 -43535 -43536 -43537 -43538 -43539 -43540 -43541 -43542 43543 43544 +v 43545 -43546 -43547 -43548 -43549 -43550 -43551 43552 43553 43554 43555 +v -43556 -43557 -43558 -43559 -43560 43561 -43562 -43563 -43564 -43565 -43566 +v -43567 -43568 -43569 -43570 -43571 -43572 -43573 -43574 -43575 -43576 -43577 +v -43578 -43579 -43580 -43581 -43582 -43583 -43584 -43585 -43586 -43587 43588 +v 43589 43590 -43591 -43592 -43593 -43594 -43595 -43596 -43597 43598 43599 +v -43600 -43601 -43602 -43603 43604 -43605 -43606 -43607 -43608 -43609 43610 +v -43611 -43612 -43613 -43614 -43615 -43616 -43617 -43618 -43619 -43620 -43621 +v -43622 -43623 -43624 -43625 -43626 -43627 -43628 -43629 -43630 -43631 -43632 +v -43633 -43634 -43635 -43636 -43637 -43638 -43639 -43640 -43641 43642 -43643 +v -43644 43645 -43646 -43647 -43648 -43649 -43650 -43651 -43652 -43653 -43654 +v -43655 -43656 -43657 -43658 -43659 43660 43661 43662 43663 -43664 43665 +v 43666 43667 -43668 -43669 -43670 -43671 -43672 -43673 -43674 -43675 -43676 +v -43677 -43678 -43679 -43680 43681 43682 -43683 -43684 -43685 -43686 -43687 +v 43688 -43689 -43690 -43691 -43692 -43693 43694 -43695 -43696 -43697 -43698 +v -43699 -43700 -43701 -43702 -43703 43704 43705 -43706 -43707 43708 43709 +v 43710 43711 43712 43713 43714 -43715 -43716 -43717 -43718 -43719 -43720 +v -43721 -43722 -43723 43724 43725 -43726 -43727 -43728 -43729 43730 -43731 +v -43732 -43733 -43734 -43735 -43736 -43737 -43738 -43739 -43740 -43741 -43742 +v 43743 -43744 -43745 -43746 -43747 43748 43749 -43750 -43751 -43752 -43753 +v -43754 -43755 -43756 -43757 -43758 -43759 -43760 -43761 43762 -43763 -43764 +v -43765 -43766 -43767 -43768 -43769 -43770 -43771 -43772 -43773 -43774 -43775 +v -43776 -43777 -43778 43779 -43780 -43781 -43782 -43783 -43784 -43785 -43786 +v -43787 -43788 -43789 -43790 -43791 -43792 -43793 -43794 -43795 -43796 -43797 +v -43798 -43799 -43800 43801 43802 -43803 -43804 -43805 -43806 -43807 -43808 +v -43809 -43810 43811 -43812 -43813 -43814 -43815 -43816 -43817 -43818 -43819 +v 43820 -43821 -43822 -43823 -43824 -43825 -43826 43827 43828 -43829 -43830 +v -43831 -43832 -43833 43834 43835 43836 43837 -43838 -43839 -43840 -43841 +v -43842 -43843 -43844 -43845 -43846 -43847 -43848 -43849 -43850 43851 43852 +v -43853 -43854 -43855 -43856 -43857 43858 43859 -43860 -43861 -43862 -43863 +v 43864 -43865 -43866 -43867 -43868 -43869 43870 -43871 -43872 -43873 -43874 +v -43875 -43876 43877 43878 -43879 -43880 -43881 43882 43883 43884 -43885 +v -43886 -43887 -43888 -43889 -43890 43891 -43892 43893 -43894 -43895 43896 +v -43897 43898 -43899 -43900 -43901 43902 -43903 43904 43905 43906 43907 +v -43908 -43909 43910 -43911 -43912 -43913 43914 -43915 43916 43917 43918 +v 43919 -43920 -43921 43922 -43923 -43924 43925 -43926 -43927 -43928 -43929 +v -43930 -43931 -43932 -43933 -43934 -43935 -43936 -43937 -43938 -43939 43940 +v 43941 43942 43943 -43944 -43945 43946 43947 43948 43949 -43950 -43951 -43952 +v -43953 -43954 -43955 -43956 -43957 -43958 -43959 43960 43961 -43962 -43963 +v 43964 -43965 -43966 -43967 -43968 -43969 -43970 -43971 -43972 -43973 -43974 +v -43975 -43976 -43977 -43978 -43979 -43980 -43981 -43982 -43983 -43984 -43985 +v -43986 -43987 -43988 -43989 -43990 43991 43992 43993 -43994 -43995 -43996 +v -43997 -43998 -43999 -44000 44001 44002 -44003 -44004 44005 -44006 -44007 +v -44008 -44009 -44010 -44011 -44012 -44013 -44014 -44015 -44016 -44017 44018 +v 44019 -44020 -44021 -44022 -44023 -44024 -44025 -44026 44027 -44028 44029 +v -44030 -44031 -44032 44033 -44034 44035 -44036 -44037 -44038 44039 -44040 +v 44041 44042 44043 44044 -44045 -44046 44047 -44048 -44049 44050 -44051 +v -44052 -44053 -44054 -44055 -44056 -44057 -44058 -44059 -44060 44061 44062 +v 44063 44064 -44065 -44066 -44067 -44068 -44069 -44070 -44071 -44072 -44073 +v -44074 -44075 -44076 -44077 -44078 -44079 -44080 -44081 -44082 -44083 -44084 +v -44085 44086 -44087 -44088 -44089 -44090 -44091 -44092 -44093 -44094 44095 +v 44096 -44097 -44098 -44099 44100 -44101 -44102 -44103 -44104 -44105 -44106 +v -44107 -44108 -44109 -44110 -44111 -44112 44113 -44114 44115 -44116 -44117 +v 44118 -44119 44120 -44121 -44122 44123 -44124 44125 44126 44127 44128 -44129 +v -44130 44131 -44132 -44133 44134 -44135 -44136 -44137 -44138 -44139 -44140 +v -44141 -44142 -44143 -44144 44145 44146 44147 44148 -44149 -44150 -44151 +v -44152 -44153 -44154 -44155 -44156 -44157 -44158 -44159 -44160 -44161 -44162 +v -44163 -44164 -44165 -44166 -44167 -44168 -44169 44170 -44171 -44172 -44173 +v -44174 -44175 -44176 -44177 -44178 44179 44180 -44181 -44182 -44183 44184 +v -44185 -44186 -44187 -44188 -44189 -44190 -44191 44192 44193 44194 -44195 +v -44196 -44197 -44198 -44199 -44200 -44201 44202 44203 -44204 -44205 44206 +v -44207 -44208 -44209 -44210 -44211 -44212 -44213 -44214 -44215 -44216 -44217 +v -44218 44219 44220 44221 -44222 -44223 -44224 -44225 -44226 -44227 44228 +v -44229 -44230 -44231 -44232 -44233 -44234 -44235 44236 -44237 44238 -44239 +v -44240 44241 -44242 44243 -44244 -44245 44246 -44247 44248 44249 44250 44251 +v -44252 -44253 44254 -44255 -44256 44257 -44258 -44259 -44260 -44261 -44262 +v -44263 -44264 -44265 -44266 -44267 44268 44269 44270 44271 -44272 -44273 +v -44274 -44275 -44276 -44277 -44278 -44279 44280 -44281 44282 -44283 -44284 +v -44285 -44286 -44287 44288 44289 44290 44291 44292 -44293 44294 -44295 +v -44296 -44297 -44298 -44299 -44300 -44301 -44302 -44303 -44304 -44305 -44306 +v -44307 -44308 44309 -44310 -44311 -44312 -44313 -44314 44315 -44316 44317 +v -44318 -44319 -44320 44321 -44322 44323 -44324 -44325 44326 -44327 -44328 +v -44329 -44330 -44331 -44332 44333 44334 44335 44336 -44337 44338 -44339 +v -44340 -44341 -44342 -44343 -44344 -44345 -44346 -44347 -44348 -44349 -44350 +v -44351 -44352 44353 -44354 -44355 -44356 -44357 -44358 44359 -44360 44361 +v -44362 -44363 -44364 44365 -44366 44367 -44368 -44369 44370 -44371 -44372 +v -44373 -44374 -44375 -44376 44377 44378 44379 44380 -44381 44382 -44383 +v -44384 -44385 -44386 -44387 -44388 -44389 -44390 -44391 -44392 -44393 -44394 +v -44395 -44396 44397 -44398 -44399 -44400 -44401 -44402 44403 -44404 44405 +v -44406 -44407 -44408 44409 -44410 44411 -44412 -44413 44414 -44415 -44416 +v -44417 -44418 -44419 -44420 44421 44422 44423 44424 -44425 44426 -44427 +v -44428 -44429 -44430 -44431 -44432 -44433 -44434 -44435 -44436 -44437 -44438 +v -44439 -44440 -44441 -44442 -44443 -44444 -44445 -44446 -44447 -44448 -44449 +v -44450 -44451 -44452 -44453 -44454 -44455 -44456 -44457 -44458 -44459 -44460 +v -44461 -44462 -44463 -44464 -44465 -44466 -44467 -44468 -44469 -44470 -44471 +v -44472 -44473 -44474 -44475 -44476 -44477 -44478 -44479 -44480 -44481 -44482 +v -44483 -44484 -44485 -44486 -44487 -44488 -44489 -44490 -44491 -44492 -44493 +v -44494 -44495 -44496 44497 -44498 -44499 -44500 -44501 -44502 -44503 -44504 +v -44505 -44506 -44507 -44508 -44509 -44510 -44511 -44512 -44513 -44514 -44515 +v -44516 -44517 -44518 -44519 -44520 -44521 -44522 -44523 -44524 -44525 -44526 +v -44527 -44528 -44529 -44530 -44531 -44532 -44533 -44534 -44535 -44536 -44537 +v -44538 -44539 -44540 -44541 -44542 -44543 -44544 -44545 -44546 -44547 -44548 +v -44549 -44550 -44551 -44552 -44553 -44554 44555 -44556 44557 -44558 -44559 +v -44560 44561 -44562 44563 -44564 -44565 -44566 44567 -44568 44569 -44570 +v -44571 -44572 -44573 44574 -44575 44576 -44577 -44578 44579 -44580 -44581 +v -44582 -44583 -44584 -44585 -44586 -44587 -44588 -44589 44590 44591 44592 +v 44593 -44594 44595 -44596 -44597 -44598 -44599 -44600 -44601 -44602 -44603 +v -44604 -44605 -44606 -44607 -44608 -44609 44610 -44611 -44612 -44613 -44614 +v -44615 44616 -44617 44618 -44619 -44620 -44621 44622 -44623 44624 -44625 +v -44626 44627 -44628 -44629 -44630 -44631 -44632 -44633 44634 44635 44636 +v 44637 -44638 -44639 -44640 -44641 -44642 -44643 -44644 -44645 -44646 44647 +v -44648 -44649 -44650 -44651 -44652 -44653 -44654 -44655 -44656 -44657 44658 +v 44659 44660 44661 44662 44663 44664 44665 44666 -44667 -44668 -44669 -44670 +v -44671 -44672 44673 -44674 -44675 44676 44677 -44678 44679 44680 -44681 +v -44682 -44683 -44684 44685 -44686 44687 -44688 -44689 -44690 -44691 -44692 +v -44693 44694 -44695 -44696 44697 -44698 -44699 -44700 44701 44702 -44703 +v -44704 -44705 44706 -44707 -44708 -44709 -44710 44711 44712 44713 44714 +v 44715 44716 44717 44718 -44719 -44720 -44721 -44722 44723 -44724 -44725 +v -44726 44727 -44728 44729 44730 -44731 44732 44733 -44734 -44735 -44736 +v -44737 44738 -44739 44740 -44741 -44742 -44743 -44744 -44745 -44746 44747 +v -44748 44749 -44750 -44751 -44752 -44753 44754 -44755 44756 44757 44758 +v 44759 44760 -44761 -44762 44763 44764 44765 44766 44767 -44768 -44769 44770 +v -44771 -44772 44773 -44774 -44775 -44776 -44777 -44778 -44779 -44780 -44781 +v -44782 -44783 44784 44785 44786 44787 -44788 -44789 44790 44791 -44792 +v -44793 44794 44795 -44796 -44797 -44798 -44799 -44800 44801 44802 44803 +v 44804 44805 0 +c +c --- [ run-time profiling ] ------------------------------------------------- +c +c process time taken by individual solving procedures +c (percentage relative to process time for solving) +c +c 0.10 99.82% search +c 0.09 87.22% unstable +c 0.07 67.05% parse +c 0.01 12.55% lucky +c 0.00 0.00% simplify +c ================================= +c 0.10 58.12% solve +c +c last line shows process time for solving +c (percentage relative to total process time) +c +c --- [ statistics ] --------------------------------------------------------- +c +c chronological: 295 47.81 % of conflicts +c conflicts: 617 6003.35 per second +c decisions: 2749 26747.49 per second +c fixed: 3796 8.47 % of all variables +c learned: 591 95.79 % per conflict +c learned_lits: 3011 100.00 % learned literals +c minimized: 0 0.00 % learned literals +c shrunken: 536 17.80 % learned literals +c minishrunken: 236 7.84 % learned literals +c otfs: 20 3.24 % of conflict +c propagations: 338004 3.29 M per second +c restarts: 29 21.28 interval +c subsumed: 22 0.01 % of all clauses +c strengthened: 20 0.01 % of all clauses +c trail reuses: 0 0.00 % of incremental calls +c +c seconds are measured in process time for solving +c +c --- [ resources ] ---------------------------------------------------------- +c +c total process time since initialization: 0.18 seconds +c total real time since initialization: 0.18 seconds +c maximum resident set size of process: 30.37 MB +c +c --- [ shutting down ] ------------------------------------------------------ +c +c exit 10 diff --git a/data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt b/data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt new file mode 100644 index 00000000..f90d85f3 --- /dev/null +++ b/data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt @@ -0,0 +1,169 @@ +c --- [ banner ] ------------------------------------------------------------- +c +c CaDiCaL SAT Solver +c Copyright (c) 2016-2024 A. Biere, M. Fleury, N. Froleyks, K. Fazekas, F. Pollitt +c +c Version 2.0.0 2df7b7fed0f9c522fd4cdf6e88cecad4cac8a2df +c g++ (GCC) 13.2.1 20230801 -Wall -Wextra -O3 -DNDEBUG +c Wed Apr 24 16:34:54 EEST 2024 Linux Christoph-laptop 6.8.2-arch2-1 x86_64 +c +c --- [ parsing input ] ------------------------------------------------------ +c +c reading DIMACS file from '../sat-rs/rustsat/data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf' +c opening file to read '../sat-rs/rustsat/data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf' +c found 'p cnf 27224 68879' header +c parsed 68879 clauses in 0.06 seconds process time +c +c --- [ options ] ------------------------------------------------------------ +c +c all options are set to their default value +c +c --- [ solving ] ------------------------------------------------------------ +c +c time measured in process time since initialization +c +c seconds reductions redundant irredundant +c MB restarts trail variables +c level conflicts glue remaining +c +c * 0.06 16 0 0 0 0 0 0% 0 68877 27158 100% +c { 0.07 17 0 0 0 0 0 0% 0 68877 27158 100% +c i 0.09 17 96 0 0 222 166 52% 2 68877 27156 100% +c - 0.12 17 144 1 20 304 223 56% 14 68710 27156 100% +c - 0.23 20 166 2 109 904 714 40% 41 68710 27156 100% +c } 0.26 20 172 2 140 1000 809 41% 45 68710 27156 100% +c [ 0.26 20 0 2 140 1000 809 0% 0 68710 27156 100% +c O 0.26 20 1586 2 140 1010 819 78% 101 68710 27156 100% +c ] 0.28 20 1507 2 140 3030 838 70% 92 68710 27156 100% +c { 0.28 20 172 2 140 3030 838 41% 45 68710 27156 100% +c - 0.29 20 172 3 141 3030 526 41% 45 68710 27156 100% +c s 0.31 22 172 3 141 3030 523 41% 45 68710 27156 100% +c v 0.33 22 172 3 141 3030 523 41% 45 68710 27156 100% +c w 0.33 22 172 3 141 3030 523 41% 45 68710 27156 100% +c t 0.35 22 172 3 141 3030 522 41% 45 68710 27050 99% +c e 0.56 23 172 3 141 3030 1 41% 45 8487 2294 8% +c s 0.56 25 172 3 141 3030 1 41% 45 8469 2294 8% +c e 0.57 25 172 3 141 3030 1 41% 45 8448 2286 8% +c F 0.59 20 172 3 141 3031 1 6% 44 8448 2286 8% +c - 0.60 20 132 4 158 4231 988 12% 23 8448 2286 8% +c +c seconds reductions redundant irredundant +c MB restarts trail variables +c level conflicts glue remaining +c +c 2 0.60 20 121 4 158 5001 1675 12% 17 8448 2260 8% +c p 0.60 20 121 4 158 5001 1677 12% 17 8448 2211 8% +c i 0.60 20 119 4 158 5047 1679 11% 17 8448 2210 8% +c i 0.60 20 119 4 158 5123 1686 12% 17 8448 2209 8% +c i 0.60 20 118 4 158 5199 1693 12% 17 8448 2208 8% +c i 0.60 20 118 4 158 5275 1700 12% 17 8448 2207 8% +c i 0.61 20 117 4 158 5353 1707 12% 17 8448 2206 8% +c i 0.61 20 116 4 158 5429 1714 12% 17 8448 2204 8% +c i 0.61 20 116 4 158 5435 1717 12% 17 8448 2203 8% +c i 0.61 20 116 4 158 5437 1718 12% 17 8448 2202 8% +c i 0.61 20 116 4 158 5439 1719 12% 17 8448 2200 8% +c i 0.61 20 116 4 158 5441 1719 12% 17 8448 2198 8% +c i 0.61 20 116 4 158 5443 1719 12% 17 8448 2196 8% +c i 0.61 20 116 4 158 5445 1719 12% 17 8448 2194 8% +c i 0.61 20 116 4 158 5447 1719 12% 17 8448 2192 8% +c i 0.61 20 116 4 158 5449 1719 12% 17 8448 2190 8% +c i 0.61 20 116 4 158 5451 1719 12% 17 8448 2188 8% +c i 0.61 20 116 4 158 5453 1719 12% 17 8448 2186 8% +c i 0.61 20 116 4 158 5455 1719 12% 17 8448 2184 8% +c i 0.61 20 116 4 158 5457 1719 12% 17 8448 2182 8% +c +c seconds reductions redundant irredundant +c MB restarts trail variables +c level conflicts glue remaining +c +c i 0.61 20 116 4 158 5459 1719 12% 17 8448 2180 8% +c i 0.61 20 116 4 158 5461 1719 12% 17 8448 2178 8% +c i 0.61 20 116 4 158 5463 1719 12% 17 8448 2176 8% +c i 0.61 20 116 4 158 5465 1719 12% 17 8448 2174 8% +c i 0.61 20 116 4 158 5467 1719 12% 17 8448 2172 8% +c i 0.61 20 116 4 158 5469 1719 12% 17 8448 2170 8% +c i 0.61 20 116 4 158 5471 1719 12% 17 8448 2168 8% +c i 0.61 20 116 4 158 5473 1719 12% 17 8448 2166 8% +c i 0.61 20 116 4 158 5475 1719 12% 17 8448 2164 8% +c i 0.61 20 116 4 158 5477 1719 12% 17 8448 2162 8% +c i 0.61 20 116 4 158 5479 1719 12% 17 8448 2160 8% +c i 0.61 20 116 4 158 5481 1719 12% 17 8448 2158 8% +c i 0.61 20 116 4 158 5483 1719 12% 17 8448 2156 8% +c i 0.61 20 116 4 158 5485 1719 12% 17 8448 2154 8% +c i 0.61 20 116 4 158 5487 1719 12% 17 8448 2152 8% +c i 0.61 20 116 4 158 5489 1719 12% 17 8448 2150 8% +c i 0.61 20 116 4 158 5491 1719 12% 17 8448 2148 8% +c i 0.61 20 116 4 158 5493 1719 12% 17 8448 2146 8% +c i 0.61 20 116 4 158 5495 1719 12% 17 8448 2144 8% +c i 0.61 20 116 4 158 5497 1719 12% 17 8448 2142 8% +c +c seconds reductions redundant irredundant +c MB restarts trail variables +c level conflicts glue remaining +c +c i 0.61 20 116 4 158 5499 1719 12% 17 8448 2140 8% +c i 0.61 20 116 4 158 5503 1720 12% 17 8448 2135 8% +c } 0.61 20 116 4 158 5505 1720 12% 17 8448 2130 8% +c 0 0.61 20 116 4 158 5505 1720 12% 17 8448 2130 8% +c +c --- [ result ] ------------------------------------------------------------- +c +s UNSATISFIABLE +c +c --- [ run-time profiling ] ------------------------------------------------- +c +c process time taken by individual solving procedures +c (percentage relative to process time for solving) +c +c 0.28 50.29% simplify +c 0.27 49.70% search +c 0.24 43.20% unstable +c 0.22 39.47% elim +c 0.06 10.63% parse +c 0.02 4.20% stable +c 0.02 3.85% subsume +c 0.02 3.49% vivify +c 0.01 2.29% lucky +c 0.00 0.34% ternary +c 0.00 0.09% probe +c ================================= +c 0.55 90.36% solve +c +c last line shows process time for solving +c (percentage relative to total process time) +c +c --- [ statistics ] --------------------------------------------------------- +c +c chronological: 3004 54.57 % of conflicts +c conflicts: 5505 10049.64 per second +c decisions: 50385 91980.19 per second +c eliminated: 24764 90.96 % of all variables +c fixed: 330 1.21 % of all variables +c learned: 3090 56.13 % per conflict +c learned_lits: 81296 100.00 % learned literals +c minimized: 0 0.00 % learned literals +c shrunken: 13994 17.21 % learned literals +c minishrunken: 1880 2.31 % learned literals +c otfs: 428 7.77 % of conflict +c propagations: 4000893 7.30 M per second +c reduced: 333 6.05 % per conflict +c rephased: 2 2752.50 interval +c restarts: 158 34.84 interval +c stabilizing: 1 36.88 % of conflicts +c subsumed: 3134 2.36 % of all clauses +c strengthened: 3248 2.45 % of all clauses +c trail reuses: 0 0.00 % of incremental calls +c vivified: 99 0.07 % of all clauses +c weakened: 95591 3.98 average size +c +c seconds are measured in process time for solving +c +c --- [ resources ] ---------------------------------------------------------- +c +c total process time since initialization: 0.61 seconds +c total real time since initialization: 0.68 seconds +c maximum resident set size of process: 27.41 MB +c +c --- [ shutting down ] ------------------------------------------------------ +c +c exit 20 diff --git a/data/gimsatul-AProVE11-12.txt b/data/gimsatul-AProVE11-12.txt new file mode 100644 index 00000000..d0c80964 --- /dev/null +++ b/data/gimsatul-AProVE11-12.txt @@ -0,0 +1,4090 @@ +c GimSATul SAT Solver +c Copyright (c) 2022-2023 Armin Biere University of Freiburg +c +c Version 1.1.2 09b1b3bcb5d86ef6f75bc9a0f69717c42ced70d4 +c gcc (GCC) 13.2.1 20230801 -Wall -O3 -DNDEBUG +c Wed Apr 24 16:38:17 EEST 2024 Linux Christoph-laptop 6.8.2-arch2-1 x86_64 +c +c parsing DIMACS file '../sat-rs/rustsat/data/AProVE11-12.cnf' +c parsed 'p cnf 44805 149118' header +c parsing took 0.04 seconds +c +c starting full simplification #1 +c +c [1] substituted 2477 variables 6% in 0.01 seconds +c [1] removed 0 duplicated binary clauses 0% in 0.00 seconds +c [1] subsumed 549 clauses 0% and strengthened 2062 clauses 1% in 0.02 seconds +c [1] eliminated 19825 variables 44% with bound 0 in 0.07 seconds +c [1] all candidate variables 100% tried +c +c [2] substituted 51 variables 0% in 0.02 seconds +c [2] removed 198 duplicated binary clauses 0% in 0.00 seconds +c [2] subsumed 2621 clauses 2% and strengthened 8736 clauses 6% in 0.05 seconds +c [2] eliminated 2638 variables 6% with bound 0 in 0.04 seconds +c [2] all candidate variables 100% tried +c +c [3] substituted 20 variables 0% in 0.01 seconds +c [3] removed 402 duplicated binary clauses 0% in 0.00 seconds +c [3] subsumed 4923 clauses 3% and strengthened 1689 clauses 1% in 0.03 seconds +c [3] eliminated 444 variables 1% with bound 0 in 0.02 seconds +c [3] all candidate variables 100% tried +c +c [4] substituted 39 variables 0% in 0.00 seconds +c [4] removed 127 duplicated binary clauses 0% in 0.00 seconds +c [4] subsumed 900 clauses 1% and strengthened 865 clauses 1% in 0.01 seconds +c [4] eliminated 298 variables 1% with bound 0 in 0.01 seconds +c [4] all candidate variables 100% tried +c +c [5] substituted 1 variables 0% in 0.00 seconds +c [5] removed 27 duplicated binary clauses 0% in 0.00 seconds +c [5] subsumed 550 clauses 0% and strengthened 187 clauses 0% in 0.01 seconds +c [5] eliminated 232 variables 1% with bound 0 in 0.01 seconds +c [5] all candidate variables 100% tried +c +c [6] substituted 0 variables 0% in 0.00 seconds +c [6] removed 45 duplicated binary clauses 0% in 0.00 seconds +c [6] subsumed 460 clauses 0% and strengthened 169 clauses 0% in 0.01 seconds +c [6] eliminated 228 variables 1% with bound 0 in 0.00 seconds +c [6] all candidate variables 100% tried +c +c [7] substituted 0 variables 0% in 0.00 seconds +c [7] removed 1 duplicated binary clauses 0% in 0.00 seconds +c [7] subsumed 52 clauses 0% and strengthened 112 clauses 0% in 0.01 seconds +c [7] eliminated 9 variables 0% with bound 0 in 0.00 seconds +c [7] all candidate variables 100% tried +c +c [8] substituted 0 variables 0% in 0.00 seconds +c [8] removed 0 duplicated binary clauses 0% in 0.00 seconds +c [8] subsumed 22 clauses 0% and strengthened 38 clauses 0% in 0.01 seconds +c [8] eliminated 3 variables 0% with bound 0 in 0.00 seconds +c [8] all candidate variables 100% tried +c +c [9] substituted 0 variables 0% in 0.00 seconds +c [9] removed 2 duplicated binary clauses 0% in 0.00 seconds +c [9] subsumed 18 clauses 0% and strengthened 6 clauses 0% in 0.01 seconds +c [9] eliminated 2 variables 0% with bound 0 in 0.00 seconds +c [9] all candidate variables 100% tried +c +c [10] substituted 0 variables 0% in 0.00 seconds +c [10] removed 2 duplicated binary clauses 0% in 0.00 seconds +c [10] subsumed 8 clauses 0% and strengthened 6 clauses 0% in 0.01 seconds +c [10] eliminated 2 variables 0% with bound 0 in 0.00 seconds +c [10] all candidate variables 100% tried +c +c [11] substituted 0 variables 0% in 0.00 seconds +c [11] removed 4 duplicated binary clauses 0% in 0.00 seconds +c [11] subsumed 8 clauses 0% and strengthened 12 clauses 0% in 0.01 seconds +c [11] eliminated 2 variables 0% with bound 0 in 0.00 seconds +c [11] all candidate variables 100% tried +c +c [12] substituted 0 variables 0% in 0.00 seconds +c [12] removed 8 duplicated binary clauses 0% in 0.00 seconds +c [12] subsumed 6 clauses 0% and strengthened 2 clauses 0% in 0.01 seconds +c [12] eliminated 2 variables 0% with bound 0 in 0.00 seconds +c [12] all candidate variables 100% tried +c +c [13] substituted 0 variables 0% in 0.00 seconds +c [13] removed 4 duplicated binary clauses 0% in 0.00 seconds +c [13] subsumed 2 clauses 0% and strengthened 0 clauses 0% in 0.01 seconds +c [13] eliminated 0 variables 0% with bound 0 in 0.00 seconds +c [13] all candidate variables 100% tried +c +c [14] substituted 0 variables 0% in 0.00 seconds +c [14] removed 0 duplicated binary clauses 0% in 0.00 seconds +c [14] subsumed 0 clauses 0% and strengthened 0 clauses 0% in 0.01 seconds +c [14] eliminated 0 variables 0% with bound 0 in 0.00 seconds +c [14] all candidate variables 100% tried +c +c removed 30818 variables 69% with 13986 remaining 31% +c removed 75416 clauses 51% with 73701 remaining 49% +c increasing elimination bound to 1 +c +c simplification #1 took 0.65 seconds +c +c cloning first ring solver +c memory increased by 0.97 from 21.20 MB to 20.56 MB +c +c +c running single ring in main thread +c +c seconds MB level reductions restarts rate conflicts redundant trail glue irredundant variables +c +c0 { 0.70 21 0 0 0 0 0 0 0% 0.0 73701 13986 31% +c0 i 0.71 21 25 0 0 2 96 95 6% 2.1 73701 13985 31% +c0 i 0.72 21 19 0 38 4 252 250 11% 2.5 73701 13980 31% +c0 i 0.73 21 21 0 65 6 346 343 13% 2.9 73701 13924 31% +c0 i 0.73 21 20 0 70 6 357 353 13% 2.9 73701 13833 31% +c0 i 0.73 21 20 0 75 5 369 364 13% 2.9 73701 13826 31% +c0 i 0.73 21 19 0 77 5 376 370 13% 2.9 73701 13823 31% +c0 i 0.73 21 19 0 80 5 398 391 13% 2.8 73701 13819 31% +c0 i 0.73 21 18 0 94 5 444 436 12% 3.1 73701 13813 31% +c0 i 0.75 21 18 0 111 6 503 493 14% 3.2 73701 13809 31% +c0 i 0.75 21 17 0 115 6 532 521 13% 3.1 73701 13790 31% +c0 i 0.81 21 23 0 160 8 734 722 21% 3.6 73701 13789 31% +c0 i 0.81 21 23 0 160 8 735 722 21% 3.5 73701 13788 31% +c0 } 0.82 21 25 0 164 7 893 880 24% 3.4 73701 13788 31% +c0 1 0.82 21 25 0 164 7 893 880 24% 3.4 73701 13788 31% +c +s SATISFIABLE +v -1 2 3 -4 -5 6 -7 8 9 -10 -11 12 -13 14 -15 16 -17 18 -19 20 21 -22 -23 24 +v -25 26 27 -28 -29 30 -31 32 33 -34 -35 36 -37 38 -39 40 -41 42 -43 44 -45 46 +v -47 48 -49 50 -51 52 -53 54 -55 56 -57 58 -59 60 -61 62 -63 64 -65 66 -67 68 +v -69 70 -71 72 -73 74 75 -76 -77 78 -79 -80 81 -82 83 84 -85 -86 87 -88 -89 90 +v -91 92 -93 94 -95 96 97 -98 99 -100 101 102 -103 104 -105 -106 -107 108 -109 +v 110 111 -112 113 -114 -115 -116 117 -118 119 120 -121 122 -123 -124 -125 126 +v -127 128 129 -130 131 -132 -133 -134 135 -136 137 138 -139 140 -141 -142 -143 +v 144 -145 146 -147 148 -149 150 151 -152 153 -154 155 156 -157 158 -159 -160 +v -161 162 -163 164 165 -166 -167 168 -169 -170 171 -172 173 174 -175 -176 177 +v -178 -179 180 -181 182 -183 184 -185 186 187 -188 189 190 -191 -192 193 -194 +v 195 196 197 198 -199 200 201 -202 203 -204 -205 -206 207 -208 209 210 -211 +v 212 -213 -214 -215 216 -217 218 219 -220 221 -222 -223 -224 225 -226 227 228 +v -229 230 -231 -232 -233 234 -235 236 237 -238 -239 240 -241 -242 243 -244 245 +v 246 -247 -248 249 -250 -251 252 -253 254 -255 256 -257 258 259 -260 261 -262 +v 263 264 -265 266 -267 -268 -269 270 -271 272 273 -274 275 -276 -277 -278 279 +v -280 281 282 -283 284 -285 -286 -287 288 -289 290 291 -292 293 -294 -295 -296 +v 297 -298 299 300 -301 302 -303 -304 -305 306 -307 308 -309 310 -311 312 313 +v -314 315 -316 317 318 -319 320 -321 -322 -323 324 -325 326 327 -328 -329 330 +v -331 -332 333 -334 335 336 -337 -338 339 -340 -341 342 -343 344 -345 346 -347 +v 348 349 -350 351 -352 353 354 -355 356 -357 -358 -359 360 -361 362 363 -364 +v 365 -366 -367 -368 369 -370 371 372 -373 374 -375 -376 -377 378 -379 380 381 +v -382 383 -384 -385 -386 387 -388 389 390 -391 392 -393 -394 -395 396 -397 398 +v 399 -400 -401 402 -403 -404 405 -406 407 408 -409 -410 411 -412 -413 414 -415 +v 416 -417 418 -419 420 421 -422 423 -424 425 426 -427 428 -429 -430 -431 432 +v -433 434 435 -436 437 -438 -439 -440 441 -442 443 -444 445 -446 447 448 -449 +v 450 451 -452 -453 454 -455 456 457 458 459 -460 461 -462 463 -464 465 466 +v -467 468 -469 470 471 -472 -473 474 -475 -476 477 -478 479 480 -481 -482 483 +v -484 -485 486 -487 488 -489 490 -491 492 493 -494 495 -496 497 498 -499 500 +v -501 -502 -503 504 -505 506 507 -508 509 -510 -511 -512 513 -514 515 516 -517 +v -518 519 -520 -521 522 -523 524 525 -526 -527 528 -529 -530 531 -532 533 534 +v -535 -536 537 -538 -539 540 -541 542 -543 544 -545 546 547 -548 549 -550 551 +v 552 -553 554 -555 -556 -557 558 -559 560 561 -562 563 -564 -565 -566 567 -568 +v 569 -570 571 -572 573 574 -575 576 -577 578 -579 580 581 -582 -583 -584 585 +v -586 587 -588 589 -590 591 592 -593 594 -595 596 597 -598 -599 600 -601 -602 +v 603 -604 605 606 -607 -608 609 -610 -611 612 -613 614 -615 616 -617 618 619 +v -620 621 -622 623 624 -625 626 -627 -628 -629 630 -631 632 633 -634 635 -636 +v -637 -638 639 -640 641 642 -643 644 -645 -646 -647 648 -649 650 651 -652 -653 +v 654 -655 -656 657 -658 659 660 -661 -662 663 -664 -665 666 -667 668 -669 670 +v -671 672 673 -674 675 -676 677 678 -679 680 -681 -682 -683 684 -685 686 687 +v -688 689 -690 -691 -692 693 -694 695 696 -697 698 -699 -700 -701 702 -703 704 +v 705 -706 707 -708 -709 -710 711 -712 713 714 -715 716 -717 -718 -719 720 -721 +v 722 -723 724 -725 726 727 -728 729 -730 731 732 -733 734 -735 -736 -737 738 +v -739 740 741 -742 -743 744 -745 -746 747 -748 749 750 -751 -752 753 -754 -755 +v 756 -757 758 -759 760 -761 762 763 -764 765 -766 767 768 -769 770 -771 -772 +v -773 774 -775 776 777 -778 779 -780 -781 -782 783 -784 785 786 -787 788 -789 +v -790 -791 792 -793 794 795 -796 797 -798 -799 -800 801 -802 803 804 -805 806 +v -807 -808 -809 810 -811 812 813 -814 -815 816 -817 -818 819 -820 821 822 -823 +v -824 825 -826 -827 828 -829 830 -831 832 -833 834 835 -836 837 -838 839 840 +v -841 842 -843 -844 -845 846 -847 848 849 -850 851 -852 -853 -854 855 -856 857 +v 858 -859 860 -861 -862 -863 864 -865 866 867 -868 869 -870 -871 -872 873 -874 +v 875 876 -877 878 -879 -880 -881 882 -883 884 -885 886 -887 888 889 -890 891 +v -892 893 894 -895 896 -897 -898 -899 900 -901 902 903 -904 -905 906 -907 -908 +v 909 -910 911 912 -913 -914 915 -916 -917 918 -919 920 -921 922 -923 924 925 +v -926 927 -928 929 930 -931 932 -933 -934 -935 936 937 -938 -939 940 -941 942 +v 943 944 945 -946 947 948 -949 950 -951 -952 -953 954 955 -956 -957 958 -959 +v 960 961 962 963 -964 965 966 -967 968 -969 -970 -971 972 -973 974 975 -976 +v -977 978 -979 -980 981 -982 983 984 -985 -986 987 -988 -989 990 -991 992 -993 +v 994 -995 996 997 -998 999 -1000 1001 1002 -1003 1004 -1005 -1006 -1007 1008 +v -1009 1010 1011 -1012 1013 -1014 -1015 -1016 1017 -1018 1019 1020 -1021 1022 +v -1023 -1024 -1025 1026 -1027 1028 1029 -1030 1031 -1032 -1033 -1034 1035 +v -1036 1037 1038 -1039 1040 -1041 -1042 -1043 1044 -1045 1046 -1047 1048 -1049 +v 1050 1051 -1052 1053 -1054 1055 1056 -1057 1058 -1059 -1060 -1061 1062 -1063 +v 1064 1065 -1066 -1067 1068 -1069 -1070 1071 -1072 1073 1074 -1075 -1076 1077 +v -1078 -1079 1080 -1081 1082 -1083 1084 -1085 1086 1087 -1088 1089 -1090 1091 +v 1092 -1093 1094 -1095 -1096 -1097 1098 -1099 1100 1101 -1102 1103 -1104 -1105 +v -1106 1107 -1108 1109 1110 -1111 1112 -1113 -1114 -1115 1116 -1117 1118 1119 +v -1120 1121 -1122 -1123 -1124 1125 -1126 1127 1128 -1129 1130 -1131 -1132 +v -1133 1134 -1135 1136 1137 -1138 -1139 1140 -1141 -1142 1143 -1144 1145 1146 +v -1147 -1148 1149 -1150 -1151 1152 -1153 1154 -1155 1156 -1157 1158 1159 -1160 +v 1161 -1162 1163 1164 -1165 1166 -1167 -1168 -1169 1170 -1171 1172 1173 -1174 +v 1175 -1176 -1177 -1178 1179 -1180 1181 1182 -1183 1184 -1185 -1186 -1187 1188 +v -1189 1190 1191 -1192 1193 -1194 -1195 -1196 1197 -1198 1199 1200 -1201 1202 +v -1203 -1204 -1205 1206 -1207 1208 -1209 1210 -1211 1212 1213 -1214 1215 -1216 +v 1217 -1218 1219 -1220 1221 1222 -1223 1224 -1225 1226 1227 -1228 -1229 1230 +v -1231 -1232 1233 -1234 1235 1236 -1237 -1238 1239 -1240 -1241 1242 -1243 1244 +v -1245 1246 -1247 1248 1249 -1250 1251 -1252 1253 1254 -1255 1256 -1257 -1258 +v -1259 1260 -1261 1262 1263 -1264 1265 -1266 -1267 -1268 1269 -1270 1271 1272 +v -1273 1274 -1275 -1276 -1277 1278 -1279 1280 1281 -1282 1283 -1284 -1285 +v -1286 1287 -1288 1289 1290 -1291 1292 -1293 -1294 -1295 1296 1297 -1298 -1299 +v -1300 -1301 -1302 -1303 -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 +v -1313 -1314 -1315 -1316 -1317 -1318 -1319 -1320 -1321 -1322 -1323 -1324 1325 +v -1326 -1327 -1328 -1329 1330 -1331 -1332 -1333 1334 -1335 -1336 -1337 1338 +v -1339 -1340 -1341 1342 -1343 -1344 -1345 1346 -1347 -1348 -1349 1350 -1351 +v -1352 -1353 1354 -1355 -1356 -1357 1358 -1359 -1360 -1361 1362 -1363 -1364 +v -1365 1366 -1367 -1368 -1369 1370 -1371 -1372 -1373 1374 -1375 -1376 -1377 +v 1378 -1379 -1380 -1381 1382 -1383 -1384 -1385 1386 -1387 -1388 -1389 1390 +v -1391 -1392 -1393 -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 +v -1404 -1405 -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 -1416 +v -1417 -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 -1428 -1429 +v -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 -1440 -1441 -1442 +v -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 -1452 -1453 -1454 -1455 +v -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 -1464 -1465 -1466 -1467 -1468 +v -1469 -1470 -1471 -1472 -1473 -1474 -1475 -1476 -1477 -1478 -1479 -1480 -1481 +v -1482 -1483 -1484 -1485 -1486 -1487 -1488 -1489 1490 1491 1492 -1493 -1494 +v -1495 1496 -1497 -1498 -1499 1500 -1501 -1502 -1503 1504 -1505 -1506 -1507 +v 1508 -1509 -1510 -1511 1512 -1513 -1514 -1515 1516 -1517 -1518 -1519 1520 +v -1521 -1522 -1523 1524 -1525 -1526 -1527 -1528 -1529 -1530 -1531 -1532 -1533 +v -1534 -1535 -1536 -1537 -1538 -1539 -1540 -1541 -1542 -1543 -1544 1545 1546 +v 1547 -1548 -1549 -1550 -1551 -1552 1553 1554 -1555 -1556 -1557 -1558 -1559 +v 1560 1561 1562 1563 -1564 -1565 -1566 1567 1568 -1569 1570 1571 -1572 -1573 +v -1574 -1575 1576 1577 1578 -1579 -1580 -1581 1582 -1583 -1584 -1585 1586 1587 +v 1588 -1589 -1590 1591 -1592 -1593 -1594 1595 -1596 -1597 -1598 1599 -1600 +v -1601 -1602 -1603 1604 1605 1606 1607 1608 1609 -1610 -1611 1612 -1613 -1614 +v 1615 -1616 -1617 -1618 -1619 -1620 -1621 -1622 -1623 1624 -1625 -1626 1627 +v -1628 1629 -1630 -1631 1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 +v -1641 -1642 1643 1644 -1645 -1646 1647 -1648 -1649 -1650 -1651 -1652 -1653 +v -1654 -1655 -1656 -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 1665 1666 +v -1667 -1668 1669 1670 1671 1672 1673 -1674 -1675 -1676 -1677 -1678 -1679 +v -1680 -1681 1682 -1683 -1684 -1685 -1686 -1687 -1688 -1689 -1690 -1691 1692 +v -1693 -1694 -1695 1696 1697 1698 1699 1700 -1701 -1702 -1703 -1704 -1705 +v -1706 1707 -1708 1709 -1710 -1711 1712 -1713 1714 1715 1716 1717 -1718 -1719 +v 1720 -1721 1722 1723 1724 -1725 -1726 1727 -1728 -1729 1730 -1731 -1732 -1733 +v -1734 -1735 -1736 -1737 -1738 -1739 -1740 1741 1742 1743 -1744 1745 -1746 +v 1747 1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 1757 1758 1759 1760 +v -1761 -1762 -1763 1764 1765 -1766 1767 1768 -1769 -1770 -1771 -1772 1773 1774 +v 1775 -1776 -1777 -1778 1779 -1780 -1781 -1782 1783 1784 1785 -1786 -1787 1788 +v -1789 -1790 -1791 1792 -1793 -1794 -1795 1796 -1797 -1798 -1799 -1800 1801 +v 1802 1803 1804 1805 1806 -1807 -1808 1809 -1810 -1811 1812 -1813 -1814 -1815 +v -1816 -1817 -1818 -1819 -1820 1821 -1822 -1823 1824 -1825 1826 -1827 -1828 +v 1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 -1838 -1839 1840 1841 +v -1842 -1843 1844 -1845 -1846 -1847 -1848 -1849 -1850 -1851 -1852 -1853 -1854 +v -1855 -1856 -1857 -1858 -1859 -1860 -1861 1862 1863 -1864 -1865 1866 1867 +v 1868 1869 1870 -1871 -1872 -1873 -1874 -1875 -1876 -1877 -1878 1879 -1880 +v -1881 -1882 -1883 -1884 -1885 -1886 -1887 -1888 1889 -1890 -1891 -1892 1893 +v 1894 1895 1896 1897 -1898 -1899 -1900 -1901 -1902 -1903 1904 -1905 1906 -1907 +v -1908 1909 -1910 1911 1912 1913 1914 -1915 -1916 1917 -1918 1919 1920 1921 +v -1922 -1923 1924 -1925 -1926 1927 -1928 -1929 -1930 -1931 -1932 -1933 -1934 +v -1935 -1936 -1937 1938 1939 1940 -1941 1942 -1943 1944 1945 -1946 1947 -1948 +v 1949 1950 -1951 -1952 1953 -1954 -1955 -1956 -1957 -1958 -1959 -1960 -1961 +v -1962 -1963 -1964 -1965 -1966 -1967 1968 1969 -1970 -1971 1972 1973 1974 1975 +v 1976 1977 1978 1979 -1980 -1981 -1982 -1983 -1984 -1985 -1986 1987 1988 -1989 +v 1990 -1991 -1992 -1993 -1994 -1995 -1996 -1997 -1998 -1999 2000 -2001 -2002 +v 2003 -2004 2005 2006 2007 -2008 -2009 2010 -2011 -2012 -2013 2014 -2015 2016 +v 2017 2018 2019 -2020 -2021 2022 -2023 -2024 2025 2026 2027 2028 2029 2030 +v 2031 2032 -2033 -2034 -2035 2036 2037 2038 2039 -2040 -2041 2042 -2043 -2044 +v -2045 -2046 2047 -2048 -2049 2050 -2051 -2052 2053 -2054 2055 -2056 -2057 +v 2058 -2059 2060 -2061 -2062 2063 -2064 2065 2066 2067 -2068 -2069 2070 2071 +v -2072 -2073 -2074 -2075 2076 -2077 -2078 2079 -2080 -2081 -2082 -2083 -2084 +v 2085 -2086 -2087 -2088 -2089 -2090 -2091 -2092 -2093 2094 2095 2096 2097 2098 +v 2099 2100 2101 2102 2103 2104 2105 2106 2107 -2108 -2109 -2110 -2111 -2112 +v -2113 -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 -2125 +v -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 2136 -2137 -2138 +v 2139 -2140 2141 -2142 2143 -2144 -2145 -2146 2147 -2148 -2149 2150 -2151 +v -2152 -2153 -2154 -2155 -2156 -2157 -2158 2159 2160 -2161 -2162 -2163 -2164 +v -2165 2166 2167 -2168 -2169 -2170 -2171 -2172 2173 -2174 -2175 -2176 2177 +v 2178 -2179 -2180 2181 2182 -2183 2184 2185 2186 2187 -2188 -2189 2190 -2191 +v 2192 -2193 -2194 -2195 -2196 -2197 2198 -2199 -2200 -2201 -2202 -2203 -2204 +v -2205 -2206 -2207 -2208 -2209 -2210 -2211 2212 2213 2214 -2215 -2216 -2217 +v -2218 -2219 -2220 -2221 -2222 -2223 -2224 -2225 -2226 -2227 -2228 -2229 -2230 +v -2231 -2232 -2233 -2234 -2235 -2236 -2237 2238 -2239 -2240 -2241 -2242 -2243 +v -2244 -2245 -2246 -2247 -2248 -2249 -2250 -2251 -2252 -2253 -2254 -2255 -2256 +v -2257 -2258 -2259 -2260 -2261 -2262 -2263 -2264 -2265 -2266 -2267 -2268 -2269 +v -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 -2279 -2280 -2281 -2282 +v -2283 -2284 -2285 -2286 -2287 -2288 -2289 -2290 -2291 -2292 -2293 -2294 -2295 +v -2296 -2297 -2298 -2299 -2300 -2301 -2302 -2303 -2304 -2305 -2306 -2307 -2308 +v -2309 -2310 -2311 2312 -2313 -2314 -2315 -2316 -2317 -2318 -2319 -2320 -2321 +v -2322 -2323 2324 -2325 -2326 -2327 -2328 -2329 2330 -2331 2332 -2333 -2334 +v 2335 -2336 2337 -2338 -2339 -2340 2341 -2342 2343 -2344 -2345 -2346 2347 +v -2348 2349 2350 2351 -2352 -2353 -2354 -2355 -2356 -2357 -2358 -2359 -2360 +v -2361 2362 2363 2364 -2365 -2366 -2367 -2368 -2369 -2370 -2371 -2372 -2373 +v -2374 -2375 -2376 -2377 -2378 -2379 -2380 -2381 -2382 -2383 -2384 -2385 -2386 +v -2387 -2388 -2389 -2390 -2391 -2392 -2393 2394 -2395 2396 -2397 -2398 2399 +v -2400 2401 2402 2403 -2404 -2405 -2406 -2407 -2408 -2409 -2410 2411 2412 2413 +v 2414 -2415 2416 -2417 -2418 -2419 2420 2421 2422 2423 2424 -2425 -2426 2427 +v -2428 2429 -2430 2431 -2432 2433 -2434 2435 2436 -2437 -2438 -2439 2440 2441 +v 2442 2443 2444 2445 2446 -2447 2448 -2449 2450 -2451 -2452 -2453 -2454 -2455 +v 2456 -2457 2458 2459 -2460 -2461 -2462 -2463 2464 -2465 -2466 -2467 2468 2469 +v 2470 2471 2472 -2473 -2474 2475 -2476 -2477 2478 -2479 -2480 -2481 -2482 +v -2483 2484 -2485 -2486 2487 -2488 -2489 2490 -2491 2492 -2493 2494 -2495 +v -2496 -2497 2498 2499 2500 2501 2502 2503 2504 -2505 -2506 2507 -2508 2509 +v 2510 2511 2512 -2513 -2514 2515 -2516 2517 2518 2519 -2520 -2521 2522 -2523 +v -2524 2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 -2533 2534 2535 2536 +v -2537 2538 -2539 2540 2541 -2542 -2543 -2544 -2545 -2546 -2547 -2548 -2549 +v 2550 -2551 -2552 -2553 -2554 -2555 -2556 -2557 -2558 -2559 -2560 -2561 -2562 +v -2563 -2564 -2565 2566 2567 -2568 -2569 2570 2571 2572 2573 2574 -2575 -2576 +v -2577 -2578 -2579 -2580 -2581 -2582 2583 -2584 -2585 -2586 -2587 -2588 -2589 +v -2590 -2591 -2592 2593 -2594 -2595 -2596 2597 2598 2599 2600 2601 -2602 -2603 +v -2604 -2605 -2606 -2607 2608 2609 -2610 2611 2612 -2613 -2614 2615 -2616 +v -2617 2618 -2619 -2620 -2621 -2622 -2623 -2624 -2625 -2626 2627 -2628 -2629 +v 2630 -2631 2632 -2633 -2634 -2635 -2636 -2637 -2638 -2639 2640 2641 2642 2643 +v -2644 -2645 -2646 -2647 2648 2649 -2650 -2651 2652 2653 2654 -2655 -2656 +v -2657 2658 -2659 -2660 -2661 2662 2663 2664 -2665 -2666 2667 -2668 -2669 +v -2670 2671 -2672 -2673 -2674 2675 -2676 -2677 -2678 -2679 2680 -2681 2682 +v -2683 -2684 2685 -2686 2687 2688 2689 2690 2691 -2692 -2693 2694 2695 2696 +v 2697 2698 -2699 -2700 2701 -2702 -2703 2704 -2705 -2706 -2707 -2708 -2709 +v -2710 -2711 -2712 -2713 -2714 2715 2716 2717 -2718 2719 -2720 2721 2722 -2723 +v -2724 -2725 -2726 -2727 -2728 -2729 -2730 2731 -2732 -2733 -2734 -2735 -2736 +v -2737 -2738 -2739 -2740 -2741 -2742 -2743 -2744 -2745 -2746 2747 2748 -2749 +v -2750 2751 2752 2753 2754 2755 -2756 -2757 -2758 -2759 -2760 -2761 -2762 +v -2763 2764 -2765 -2766 -2767 -2768 -2769 -2770 -2771 -2772 -2773 2774 -2775 +v -2776 -2777 2778 2779 2780 2781 2782 -2783 -2784 -2785 -2786 -2787 -2788 2789 +v 2790 -2791 2792 2793 -2794 -2795 2796 -2797 -2798 2799 -2800 -2801 -2802 +v -2803 -2804 -2805 -2806 -2807 2808 -2809 -2810 2811 -2812 2813 -2814 -2815 +v -2816 -2817 -2818 -2819 -2820 2821 2822 2823 2824 -2825 -2826 -2827 -2828 +v 2829 2830 -2831 -2832 2833 2834 2835 -2836 -2837 -2838 2839 -2840 -2841 -2842 +v 2843 2844 2845 -2846 -2847 2848 -2849 -2850 -2851 2852 -2853 -2854 -2855 2856 +v -2857 -2858 -2859 -2860 2861 -2862 2863 -2864 -2865 2866 -2867 2868 2869 2870 +v 2871 2872 -2873 -2874 2875 2876 2877 2878 2879 -2880 -2881 2882 -2883 -2884 +v 2885 -2886 -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 2896 2897 +v 2898 -2899 2900 -2901 2902 2903 -2904 2905 -2906 2907 -2908 -2909 -2910 -2911 +v -2912 -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 -2923 -2924 +v -2925 2926 2927 -2928 2929 -2930 -2931 -2932 -2933 -2934 -2935 -2936 -2937 +v -2938 -2939 -2940 -2941 2942 2943 2944 -2945 2946 -2947 -2948 2949 -2950 +v -2951 -2952 -2953 -2954 -2955 -2956 -2957 -2958 -2959 2960 2961 2962 2963 +v -2964 2965 -2966 -2967 -2968 -2969 -2970 -2971 -2972 -2973 -2974 -2975 -2976 +v -2977 -2978 -2979 -2980 -2981 -2982 -2983 -2984 2985 2986 2987 2988 -2989 +v -2990 2991 -2992 -2993 -2994 -2995 -2996 -2997 -2998 -2999 -3000 -3001 3002 +v -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 3011 -3012 -3013 -3014 -3015 +v -3016 -3017 3018 -3019 3020 -3021 -3022 -3023 -3024 -3025 -3026 -3027 -3028 +v -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 -3039 -3040 -3041 +v -3042 -3043 -3044 3045 -3046 -3047 3048 -3049 -3050 -3051 -3052 -3053 -3054 +v -3055 -3056 -3057 -3058 -3059 -3060 -3061 3062 3063 -3064 -3065 -3066 -3067 +v -3068 -3069 -3070 -3071 -3072 3073 3074 -3075 3076 -3077 -3078 3079 -3080 +v -3081 -3082 -3083 -3084 -3085 3086 -3087 3088 -3089 -3090 3091 -3092 3093 +v -3094 -3095 -3096 3097 -3098 3099 3100 3101 3102 3103 -3104 -3105 3106 3107 +v 3108 -3109 -3110 -3111 -3112 -3113 -3114 -3115 -3116 -3117 -3118 -3119 3120 +v 3121 3122 -3123 3124 -3125 3126 3127 -3128 -3129 -3130 -3131 -3132 3133 -3134 +v -3135 -3136 -3137 3138 3139 3140 -3141 -3142 -3143 -3144 -3145 -3146 -3147 +v -3148 -3149 -3150 -3151 -3152 -3153 -3154 -3155 -3156 -3157 -3158 3159 3160 +v -3161 3162 -3163 -3164 -3165 -3166 -3167 -3168 -3169 -3170 -3171 -3172 -3173 +v -3174 3175 3176 3177 -3178 3179 -3180 -3181 3182 -3183 -3184 -3185 -3186 +v -3187 -3188 -3189 -3190 -3191 -3192 3193 3194 3195 3196 -3197 3198 -3199 +v -3200 -3201 -3202 -3203 -3204 -3205 -3206 -3207 -3208 -3209 -3210 -3211 -3212 +v -3213 -3214 -3215 -3216 -3217 3218 3219 3220 3221 -3222 -3223 3224 -3225 +v -3226 -3227 -3228 -3229 -3230 -3231 -3232 -3233 -3234 3235 -3236 -3237 -3238 +v -3239 -3240 -3241 -3242 -3243 3244 -3245 -3246 -3247 -3248 -3249 -3250 3251 +v -3252 3253 -3254 -3255 -3256 -3257 -3258 -3259 -3260 -3261 -3262 -3263 -3264 +v -3265 -3266 -3267 -3268 -3269 -3270 -3271 -3272 -3273 -3274 -3275 -3276 -3277 +v 3278 -3279 -3280 3281 -3282 -3283 -3284 -3285 -3286 -3287 -3288 -3289 -3290 +v -3291 -3292 -3293 -3294 3295 3296 -3297 -3298 -3299 -3300 -3301 -3302 -3303 +v -3304 -3305 3306 3307 -3308 3309 -3310 -3311 3312 -3313 -3314 -3315 -3316 +v -3317 -3318 3319 -3320 3321 -3322 -3323 3324 -3325 3326 -3327 -3328 -3329 +v 3330 -3331 3332 3333 3334 3335 3336 -3337 -3338 3339 3340 3341 -3342 -3343 +v -3344 -3345 -3346 -3347 -3348 -3349 -3350 -3351 -3352 3353 3354 3355 -3356 +v 3357 -3358 3359 3360 -3361 -3362 -3363 -3364 -3365 3366 -3367 -3368 -3369 +v -3370 3371 3372 3373 -3374 3375 -3376 3377 3378 -3379 3380 -3381 -3382 -3383 +v -3384 -3385 -3386 -3387 -3388 -3389 -3390 -3391 -3392 -3393 -3394 -3395 -3396 +v 3397 3398 3399 3400 3401 3402 -3403 -3404 -3405 -3406 -3407 -3408 -3409 3410 +v 3411 -3412 3413 -3414 -3415 -3416 -3417 -3418 -3419 -3420 -3421 -3422 3423 +v -3424 -3425 3426 -3427 3428 3429 3430 -3431 -3432 3433 -3434 -3435 -3436 3437 +v -3438 3439 3440 3441 3442 -3443 -3444 3445 -3446 -3447 3448 3449 3450 3451 +v 3452 3453 3454 3455 -3456 -3457 -3458 3459 3460 3461 3462 -3463 -3464 3465 +v -3466 -3467 -3468 -3469 3470 -3471 -3472 3473 -3474 -3475 3476 -3477 3478 +v -3479 -3480 3481 -3482 3483 -3484 -3485 3486 -3487 3488 -3489 -3490 -3491 +v -3492 -3493 -3494 3495 -3496 -3497 3498 -3499 -3500 -3501 -3502 -3503 -3504 +v 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 -3515 -3516 -3517 -3518 +v -3519 -3520 -3521 -3522 -3523 -3524 -3525 -3526 -3527 -3528 -3529 -3530 -3531 +v -3532 -3533 -3534 -3535 -3536 -3537 -3538 -3539 -3540 -3541 -3542 3543 -3544 +v -3545 3546 -3547 3548 -3549 3550 -3551 -3552 -3553 3554 -3555 -3556 3557 +v -3558 -3559 -3560 -3561 -3562 -3563 -3564 -3565 3566 3567 -3568 -3569 -3570 +v -3571 -3572 3573 3574 -3575 -3576 -3577 -3578 -3579 3580 -3581 -3582 -3583 +v 3584 3585 -3586 -3587 3588 3589 -3590 3591 3592 3593 3594 -3595 -3596 3597 +v -3598 3599 -3600 -3601 -3602 -3603 -3604 3605 -3606 -3607 -3608 -3609 -3610 +v -3611 -3612 -3613 -3614 -3615 -3616 -3617 -3618 3619 3620 3621 -3622 -3623 +v -3624 -3625 -3626 -3627 -3628 -3629 -3630 -3631 -3632 -3633 -3634 -3635 -3636 +v -3637 -3638 -3639 -3640 -3641 -3642 -3643 -3644 -3645 -3646 -3647 -3648 -3649 +v -3650 -3651 -3652 -3653 -3654 -3655 -3656 -3657 -3658 -3659 -3660 -3661 -3662 +v -3663 -3664 -3665 -3666 -3667 -3668 -3669 -3670 -3671 -3672 -3673 -3674 3675 +v -3676 -3677 -3678 -3679 -3680 -3681 -3682 -3683 -3684 -3685 -3686 3687 -3688 +v -3689 -3690 -3691 -3692 -3693 -3694 -3695 -3696 -3697 -3698 -3699 -3700 -3701 +v -3702 -3703 -3704 -3705 -3706 -3707 -3708 -3709 -3710 -3711 3712 -3713 -3714 +v -3715 -3716 -3717 -3718 -3719 -3720 3721 -3722 3723 -3724 -3725 3726 -3727 +v 3728 -3729 -3730 -3731 3732 -3733 3734 -3735 -3736 -3737 3738 -3739 3740 3741 +v 3742 -3743 -3744 -3745 -3746 -3747 -3748 -3749 -3750 -3751 -3752 3753 3754 +v 3755 -3756 -3757 -3758 -3759 -3760 -3761 -3762 -3763 -3764 -3765 -3766 -3767 +v -3768 -3769 -3770 -3771 -3772 -3773 -3774 -3775 -3776 -3777 -3778 -3779 -3780 +v 3781 -3782 3783 -3784 -3785 3786 -3787 3788 3789 3790 -3791 -3792 -3793 -3794 +v -3795 -3796 -3797 3798 3799 3800 3801 -3802 3803 -3804 -3805 -3806 3807 3808 +v 3809 3810 3811 -3812 -3813 3814 -3815 3816 -3817 3818 -3819 -3820 -3821 -3822 +v -3823 -3824 -3825 -3826 3827 -3828 -3829 3830 -3831 -3832 -3833 -3834 3835 +v 3836 3837 -3838 -3839 -3840 -3841 -3842 -3843 3844 3845 -3846 3847 -3848 +v -3849 3850 -3851 -3852 -3853 -3854 -3855 3856 3857 3858 3859 -3860 3861 -3862 +v -3863 -3864 -3865 -3866 -3867 -3868 -3869 -3870 -3871 -3872 -3873 -3874 3875 +v 3876 3877 3878 -3879 -3880 3881 -3882 -3883 -3884 -3885 -3886 -3887 -3888 +v 3889 -3890 -3891 -3892 -3893 -3894 -3895 -3896 -3897 3898 -3899 -3900 -3901 +v -3902 -3903 -3904 -3905 -3906 3907 -3908 -3909 -3910 -3911 -3912 -3913 3914 +v -3915 -3916 -3917 -3918 -3919 -3920 3921 -3922 -3923 3924 -3925 -3926 -3927 +v -3928 3929 -3930 3931 -3932 -3933 -3934 3935 -3936 3937 3938 3939 3940 3941 +v -3942 -3943 3944 3945 3946 -3947 -3948 -3949 -3950 -3951 -3952 -3953 -3954 +v -3955 3956 3957 3958 -3959 3960 -3961 3962 3963 -3964 -3965 -3966 -3967 -3968 +v 3969 -3970 -3971 -3972 -3973 3974 3975 3976 -3977 -3978 -3979 -3980 -3981 +v -3982 -3983 -3984 -3985 -3986 -3987 -3988 -3989 -3990 -3991 -3992 -3993 -3994 +v -3995 -3996 -3997 -3998 -3999 -4000 -4001 -4002 4003 -4004 -4005 4006 -4007 +v -4008 -4009 -4010 -4011 -4012 -4013 -4014 -4015 -4016 -4017 -4018 -4019 4020 +v 4021 -4022 -4023 -4024 -4025 -4026 -4027 -4028 -4029 -4030 4031 4032 -4033 +v 4034 -4035 -4036 4037 -4038 -4039 -4040 -4041 -4042 -4043 -4044 -4045 4046 +v 4047 4048 4049 -4050 4051 -4052 -4053 -4054 -4055 -4056 -4057 -4058 -4059 +v -4060 -4061 -4062 -4063 -4064 -4065 -4066 -4067 -4068 -4069 -4070 4071 4072 +v 4073 4074 -4075 -4076 4077 -4078 -4079 -4080 -4081 -4082 -4083 -4084 -4085 +v -4086 -4087 4088 -4089 -4090 -4091 -4092 -4093 -4094 -4095 -4096 4097 -4098 +v -4099 -4100 -4101 -4102 -4103 4104 -4105 4106 -4107 -4108 -4109 -4110 -4111 +v -4112 -4113 -4114 -4115 -4116 -4117 -4118 -4119 -4120 -4121 -4122 4123 4124 +v -4125 4126 -4127 -4128 -4129 -4130 -4131 -4132 -4133 -4134 -4135 -4136 -4137 +v -4138 4139 4140 4141 -4142 4143 -4144 -4145 4146 -4147 -4148 -4149 -4150 +v -4151 -4152 -4153 4154 -4155 4156 -4157 -4158 4159 -4160 4161 -4162 -4163 +v -4164 -4165 4166 -4167 4168 4169 4170 4171 4172 -4173 -4174 4175 4176 4177 +v -4178 -4179 -4180 -4181 -4182 -4183 -4184 -4185 -4186 -4187 -4188 4189 4190 +v 4191 -4192 4193 -4194 4195 4196 -4197 -4198 -4199 -4200 -4201 4202 -4203 +v -4204 -4205 -4206 4207 4208 4209 -4210 -4211 -4212 -4213 -4214 -4215 -4216 +v -4217 -4218 -4219 -4220 -4221 -4222 -4223 -4224 -4225 -4226 -4227 -4228 -4229 +v -4230 -4231 -4232 -4233 -4234 -4235 4236 -4237 -4238 4239 -4240 -4241 -4242 +v -4243 -4244 -4245 -4246 -4247 -4248 -4249 -4250 -4251 -4252 4253 4254 -4255 +v -4256 -4257 -4258 -4259 -4260 -4261 -4262 -4263 4264 4265 -4266 4267 -4268 +v -4269 4270 -4271 -4272 -4273 -4274 -4275 -4276 -4277 -4278 4279 4280 4281 +v 4282 -4283 4284 -4285 -4286 -4287 -4288 -4289 -4290 -4291 -4292 -4293 -4294 +v -4295 -4296 -4297 -4298 -4299 -4300 -4301 -4302 -4303 4304 4305 4306 4307 +v -4308 -4309 4310 -4311 -4312 -4313 -4314 -4315 -4316 -4317 -4318 -4319 -4320 +v 4321 -4322 -4323 -4324 -4325 -4326 -4327 -4328 -4329 4330 -4331 -4332 -4333 +v -4334 -4335 -4336 4337 -4338 4339 -4340 -4341 -4342 -4343 -4344 -4345 -4346 +v -4347 -4348 -4349 -4350 -4351 -4352 -4353 -4354 -4355 4356 4357 -4358 4359 +v -4360 -4361 -4362 -4363 -4364 -4365 -4366 -4367 -4368 -4369 -4370 -4371 4372 +v 4373 4374 -4375 4376 -4377 -4378 4379 -4380 -4381 -4382 -4383 -4384 -4385 +v -4386 4387 -4388 4389 -4390 -4391 4392 -4393 4394 -4395 -4396 -4397 -4398 +v 4399 -4400 4401 4402 4403 4404 4405 -4406 -4407 4408 4409 4410 -4411 -4412 +v -4413 -4414 -4415 -4416 -4417 -4418 -4419 -4420 -4421 4422 4423 4424 -4425 +v 4426 -4427 4428 4429 -4430 -4431 -4432 -4433 -4434 4435 -4436 -4437 -4438 +v -4439 4440 4441 4442 -4443 4444 -4445 4446 4447 -4448 -4449 4450 4451 -4452 +v -4453 -4454 -4455 4456 4457 4458 4459 4460 4461 4462 4463 -4464 -4465 4466 +v 4467 -4468 -4469 -4470 4471 4472 -4473 4474 4475 4476 4477 4478 4479 4480 +v 4481 4482 4483 4484 4485 -4486 4487 -4488 4489 -4490 -4491 4492 4493 4494 +v 4495 -4496 -4497 -4498 4499 -4500 -4501 -4502 4503 4504 4505 4506 -4507 -4508 +v -4509 -4510 4511 -4512 4513 4514 -4515 4516 -4517 -4518 4519 4520 -4521 -4522 +v -4523 -4524 -4525 -4526 -4527 4528 4529 4530 -4531 -4532 -4533 -4534 4535 +v 4536 4537 4538 4539 -4540 -4541 4542 -4543 -4544 4545 -4546 -4547 4548 -4549 +v 4550 -4551 -4552 4553 -4554 -4555 -4556 -4557 -4558 4559 4560 4561 4562 -4563 +v -4564 -4565 -4566 -4567 -4568 -4569 -4570 -4571 -4572 -4573 -4574 -4575 -4576 +v -4577 -4578 -4579 -4580 -4581 -4582 -4583 -4584 -4585 -4586 -4587 -4588 -4589 +v -4590 -4591 -4592 -4593 4594 -4595 4596 -4597 -4598 -4599 4600 -4601 4602 +v -4603 -4604 4605 -4606 -4607 -4608 -4609 -4610 -4611 4612 4613 4614 4615 +v -4616 -4617 -4618 -4619 -4620 -4621 -4622 -4623 -4624 -4625 -4626 -4627 -4628 +v -4629 -4630 -4631 -4632 -4633 -4634 -4635 -4636 -4637 -4638 -4639 -4640 -4641 +v -4642 -4643 -4644 -4645 -4646 4647 -4648 4649 -4650 -4651 -4652 4653 -4654 +v 4655 -4656 -4657 4658 -4659 -4660 -4661 -4662 -4663 -4664 4665 4666 4667 4668 +v -4669 -4670 -4671 -4672 -4673 -4674 -4675 -4676 -4677 -4678 -4679 -4680 -4681 +v -4682 -4683 -4684 -4685 -4686 -4687 -4688 -4689 -4690 -4691 -4692 -4693 -4694 +v -4695 -4696 -4697 -4698 -4699 4700 -4701 4702 -4703 -4704 -4705 4706 -4707 +v 4708 -4709 -4710 4711 -4712 -4713 -4714 -4715 -4716 -4717 4718 4719 4720 4721 +v -4722 -4723 -4724 -4725 -4726 -4727 -4728 -4729 -4730 -4731 -4732 -4733 -4734 +v -4735 -4736 -4737 -4738 -4739 -4740 -4741 -4742 -4743 -4744 -4745 -4746 -4747 +v -4748 -4749 -4750 -4751 -4752 -4753 -4754 -4755 -4756 -4757 -4758 -4759 -4760 +v -4761 -4762 -4763 -4764 -4765 -4766 -4767 -4768 -4769 -4770 -4771 -4772 -4773 +v -4774 -4775 -4776 -4777 -4778 -4779 -4780 -4781 -4782 -4783 -4784 -4785 -4786 +v -4787 -4788 -4789 -4790 -4791 -4792 -4793 -4794 -4795 -4796 -4797 -4798 -4799 +v -4800 -4801 -4802 -4803 -4804 -4805 -4806 -4807 -4808 -4809 -4810 -4811 -4812 +v -4813 -4814 -4815 -4816 -4817 -4818 -4819 -4820 -4821 -4822 -4823 -4824 -4825 +v -4826 -4827 -4828 -4829 -4830 -4831 -4832 -4833 -4834 -4835 -4836 -4837 -4838 +v -4839 -4840 -4841 -4842 -4843 -4844 -4845 -4846 -4847 -4848 -4849 -4850 -4851 +v -4852 -4853 -4854 -4855 -4856 -4857 -4858 -4859 -4860 -4861 -4862 -4863 -4864 +v -4865 -4866 -4867 -4868 -4869 -4870 -4871 -4872 -4873 -4874 -4875 -4876 -4877 +v -4878 -4879 -4880 -4881 -4882 -4883 -4884 -4885 -4886 -4887 -4888 -4889 -4890 +v 4891 -4892 4893 -4894 -4895 -4896 4897 -4898 4899 -4900 -4901 -4902 -4903 +v 4904 -4905 4906 -4907 -4908 -4909 -4910 4911 -4912 4913 -4914 -4915 4916 +v -4917 -4918 -4919 -4920 -4921 -4922 -4923 -4924 -4925 -4926 4927 4928 4929 +v 4930 -4931 -4932 -4933 -4934 -4935 -4936 -4937 -4938 -4939 -4940 -4941 -4942 +v -4943 -4944 -4945 -4946 -4947 -4948 -4949 -4950 -4951 -4952 -4953 -4954 -4955 +v -4956 -4957 -4958 -4959 -4960 -4961 -4962 -4963 -4964 -4965 -4966 -4967 -4968 +v -4969 -4970 -4971 -4972 -4973 -4974 -4975 -4976 -4977 -4978 -4979 -4980 -4981 +v -4982 -4983 -4984 -4985 -4986 -4987 -4988 -4989 -4990 -4991 -4992 -4993 -4994 +v -4995 -4996 -4997 -4998 -4999 -5000 -5001 -5002 -5003 -5004 -5005 -5006 -5007 +v -5008 -5009 -5010 -5011 -5012 -5013 -5014 -5015 -5016 -5017 -5018 -5019 -5020 +v -5021 -5022 -5023 -5024 -5025 -5026 -5027 -5028 -5029 -5030 -5031 -5032 -5033 +v -5034 -5035 -5036 -5037 -5038 -5039 -5040 -5041 -5042 -5043 -5044 -5045 -5046 +v -5047 -5048 -5049 -5050 -5051 -5052 -5053 -5054 -5055 -5056 -5057 -5058 -5059 +v -5060 -5061 -5062 -5063 -5064 -5065 -5066 -5067 -5068 -5069 -5070 -5071 -5072 +v -5073 -5074 -5075 -5076 -5077 -5078 -5079 -5080 -5081 -5082 -5083 -5084 -5085 +v -5086 -5087 -5088 -5089 -5090 -5091 -5092 -5093 -5094 -5095 -5096 -5097 5098 +v -5099 5100 -5101 -5102 -5103 5104 -5105 5106 -5107 -5108 -5109 -5110 5111 +v -5112 5113 -5114 -5115 -5116 -5117 5118 -5119 5120 -5121 -5122 5123 -5124 +v -5125 -5126 -5127 -5128 -5129 -5130 -5131 -5132 -5133 5134 5135 5136 5137 +v -5138 -5139 -5140 -5141 -5142 -5143 -5144 -5145 -5146 -5147 -5148 -5149 -5150 +v -5151 -5152 -5153 -5154 -5155 -5156 -5157 -5158 -5159 -5160 -5161 -5162 -5163 +v -5164 -5165 -5166 -5167 -5168 -5169 -5170 -5171 -5172 -5173 -5174 -5175 -5176 +v -5177 -5178 -5179 -5180 -5181 -5182 -5183 -5184 -5185 -5186 -5187 -5188 -5189 +v -5190 -5191 -5192 -5193 -5194 -5195 -5196 -5197 -5198 -5199 -5200 -5201 -5202 +v -5203 -5204 -5205 -5206 -5207 -5208 -5209 -5210 -5211 -5212 -5213 -5214 -5215 +v -5216 -5217 -5218 -5219 -5220 -5221 -5222 -5223 -5224 -5225 -5226 -5227 -5228 +v -5229 -5230 -5231 -5232 -5233 -5234 -5235 -5236 -5237 -5238 -5239 -5240 -5241 +v -5242 -5243 -5244 -5245 -5246 -5247 -5248 -5249 -5250 -5251 -5252 -5253 -5254 +v -5255 -5256 -5257 -5258 -5259 -5260 -5261 -5262 -5263 -5264 -5265 -5266 -5267 +v -5268 -5269 -5270 -5271 -5272 -5273 -5274 -5275 -5276 -5277 -5278 -5279 -5280 +v -5281 -5282 -5283 -5284 -5285 -5286 -5287 -5288 -5289 -5290 -5291 -5292 -5293 +v -5294 -5295 -5296 -5297 -5298 5299 -5300 5301 -5302 -5303 -5304 5305 -5306 +v 5307 -5308 -5309 -5310 -5311 5312 -5313 5314 -5315 -5316 -5317 -5318 5319 +v -5320 5321 -5322 -5323 5324 -5325 -5326 -5327 -5328 -5329 -5330 -5331 -5332 +v -5333 -5334 5335 5336 5337 5338 -5339 -5340 -5341 -5342 -5343 -5344 -5345 +v -5346 -5347 -5348 -5349 -5350 -5351 -5352 -5353 -5354 -5355 -5356 -5357 -5358 +v -5359 -5360 -5361 -5362 -5363 -5364 -5365 -5366 -5367 -5368 -5369 -5370 -5371 +v -5372 -5373 -5374 -5375 -5376 -5377 -5378 -5379 -5380 -5381 -5382 -5383 -5384 +v -5385 -5386 -5387 -5388 -5389 -5390 -5391 -5392 -5393 -5394 -5395 -5396 -5397 +v -5398 -5399 -5400 -5401 -5402 -5403 -5404 -5405 -5406 -5407 -5408 -5409 -5410 +v -5411 -5412 -5413 -5414 -5415 -5416 -5417 -5418 -5419 -5420 -5421 -5422 -5423 +v -5424 -5425 -5426 -5427 -5428 -5429 -5430 -5431 -5432 -5433 -5434 -5435 -5436 +v -5437 -5438 -5439 -5440 -5441 -5442 -5443 -5444 -5445 -5446 -5447 -5448 -5449 +v -5450 -5451 -5452 -5453 -5454 -5455 -5456 -5457 -5458 -5459 -5460 -5461 -5462 +v -5463 -5464 -5465 -5466 -5467 -5468 -5469 -5470 -5471 -5472 -5473 -5474 -5475 +v -5476 -5477 -5478 -5479 -5480 -5481 -5482 -5483 -5484 -5485 -5486 -5487 -5488 +v -5489 -5490 -5491 -5492 -5493 -5494 -5495 -5496 -5497 -5498 -5499 -5500 -5501 +v -5502 -5503 -5504 -5505 5506 -5507 5508 -5509 -5510 -5511 5512 -5513 5514 +v -5515 -5516 -5517 -5518 5519 -5520 5521 -5522 -5523 -5524 -5525 5526 -5527 +v 5528 -5529 -5530 5531 -5532 -5533 -5534 -5535 -5536 -5537 -5538 -5539 -5540 +v -5541 5542 5543 5544 5545 -5546 -5547 -5548 -5549 -5550 -5551 -5552 -5553 +v -5554 -5555 -5556 -5557 -5558 -5559 -5560 -5561 -5562 -5563 -5564 -5565 -5566 +v -5567 -5568 -5569 -5570 -5571 -5572 -5573 -5574 -5575 -5576 5577 -5578 5579 +v -5580 -5581 -5582 5583 -5584 5585 -5586 -5587 5588 -5589 -5590 -5591 -5592 +v -5593 -5594 5595 5596 5597 5598 -5599 5600 -5601 5602 -5603 5604 5605 5606 +v 5607 -5608 -5609 -5610 -5611 -5612 -5613 -5614 -5615 -5616 -5617 -5618 -5619 +v -5620 -5621 -5622 -5623 -5624 -5625 -5626 -5627 -5628 -5629 -5630 -5631 -5632 +v -5633 -5634 -5635 -5636 -5637 -5638 -5639 -5640 -5641 -5642 -5643 -5644 -5645 +v -5646 -5647 -5648 -5649 -5650 -5651 -5652 -5653 5654 -5655 -5656 5657 -5658 +v -5659 -5660 -5661 -5662 -5663 -5664 -5665 -5666 -5667 -5668 -5669 -5670 -5671 +v -5672 -5673 -5674 -5675 -5676 -5677 -5678 -5679 -5680 -5681 -5682 -5683 -5684 +v -5685 -5686 -5687 -5688 -5689 -5690 -5691 -5692 -5693 -5694 -5695 -5696 -5697 +v -5698 -5699 -5700 -5701 -5702 -5703 -5704 -5705 -5706 -5707 -5708 -5709 -5710 +v -5711 -5712 -5713 -5714 -5715 -5716 -5717 -5718 -5719 -5720 -5721 -5722 -5723 +v -5724 -5725 -5726 -5727 -5728 -5729 -5730 -5731 -5732 -5733 -5734 -5735 -5736 +v -5737 -5738 -5739 -5740 -5741 -5742 -5743 -5744 -5745 -5746 -5747 -5748 -5749 +v -5750 -5751 -5752 -5753 -5754 -5755 -5756 -5757 -5758 -5759 -5760 -5761 -5762 +v -5763 -5764 -5765 -5766 -5767 -5768 -5769 -5770 -5771 -5772 -5773 -5774 -5775 +v -5776 -5777 -5778 -5779 -5780 -5781 -5782 -5783 -5784 -5785 -5786 -5787 -5788 +v -5789 -5790 -5791 -5792 -5793 -5794 -5795 -5796 -5797 -5798 -5799 -5800 -5801 +v -5802 -5803 -5804 -5805 -5806 -5807 -5808 -5809 -5810 -5811 -5812 -5813 -5814 +v -5815 -5816 -5817 -5818 -5819 -5820 -5821 -5822 -5823 -5824 -5825 -5826 -5827 +v -5828 -5829 -5830 -5831 -5832 -5833 -5834 -5835 -5836 -5837 -5838 -5839 -5840 +v -5841 -5842 -5843 -5844 -5845 -5846 -5847 -5848 -5849 -5850 -5851 -5852 -5853 +v -5854 -5855 -5856 -5857 -5858 -5859 -5860 -5861 -5862 -5863 -5864 -5865 -5866 +v -5867 -5868 -5869 -5870 -5871 -5872 -5873 -5874 -5875 -5876 -5877 -5878 -5879 +v -5880 -5881 -5882 -5883 -5884 -5885 5886 -5887 -5888 -5889 -5890 -5891 -5892 +v -5893 -5894 -5895 -5896 -5897 -5898 -5899 -5900 -5901 -5902 -5903 -5904 -5905 +v -5906 -5907 -5908 -5909 -5910 -5911 -5912 -5913 -5914 -5915 -5916 -5917 -5918 +v -5919 -5920 -5921 -5922 -5923 -5924 -5925 -5926 -5927 -5928 -5929 -5930 -5931 +v -5932 -5933 -5934 -5935 -5936 -5937 -5938 -5939 -5940 -5941 -5942 -5943 -5944 +v -5945 -5946 -5947 -5948 -5949 -5950 -5951 -5952 -5953 -5954 -5955 -5956 -5957 +v -5958 -5959 -5960 -5961 -5962 -5963 -5964 -5965 -5966 -5967 -5968 -5969 -5970 +v -5971 -5972 -5973 -5974 -5975 -5976 -5977 -5978 -5979 -5980 -5981 -5982 -5983 +v -5984 -5985 -5986 -5987 -5988 -5989 -5990 -5991 -5992 -5993 -5994 -5995 -5996 +v -5997 -5998 -5999 -6000 -6001 -6002 -6003 -6004 -6005 -6006 -6007 -6008 -6009 +v -6010 -6011 -6012 -6013 -6014 -6015 -6016 -6017 -6018 -6019 -6020 -6021 -6022 +v -6023 -6024 -6025 -6026 -6027 -6028 -6029 -6030 -6031 -6032 -6033 -6034 -6035 +v -6036 -6037 -6038 -6039 -6040 -6041 -6042 -6043 -6044 -6045 -6046 -6047 -6048 +v -6049 -6050 -6051 -6052 6053 -6054 6055 -6056 -6057 6058 -6059 6060 -6061 +v -6062 6063 -6064 6065 -6066 -6067 -6068 6069 -6070 6071 -6072 -6073 -6074 +v 6075 -6076 6077 -6078 -6079 -6080 6081 -6082 6083 -6084 -6085 6086 -6087 +v -6088 -6089 -6090 -6091 -6092 -6093 -6094 -6095 -6096 -6097 -6098 -6099 -6100 +v 6101 6102 6103 6104 6105 -6106 -6107 -6108 -6109 -6110 -6111 6112 -6113 -6114 +v -6115 6116 -6117 -6118 -6119 -6120 -6121 -6122 -6123 -6124 -6125 -6126 -6127 +v -6128 -6129 -6130 -6131 -6132 -6133 -6134 -6135 -6136 -6137 -6138 -6139 -6140 +v -6141 -6142 -6143 -6144 -6145 -6146 -6147 -6148 -6149 -6150 -6151 -6152 -6153 +v -6154 -6155 -6156 -6157 -6158 -6159 -6160 -6161 -6162 -6163 -6164 -6165 -6166 +v -6167 -6168 -6169 -6170 -6171 -6172 -6173 -6174 -6175 -6176 -6177 -6178 -6179 +v -6180 -6181 -6182 -6183 -6184 -6185 -6186 -6187 -6188 -6189 -6190 -6191 -6192 +v -6193 -6194 -6195 -6196 -6197 -6198 -6199 -6200 -6201 -6202 -6203 -6204 -6205 +v -6206 -6207 -6208 -6209 -6210 -6211 -6212 -6213 -6214 -6215 -6216 -6217 -6218 +v -6219 -6220 -6221 -6222 -6223 -6224 -6225 -6226 -6227 -6228 -6229 -6230 -6231 +v -6232 -6233 -6234 -6235 -6236 6237 -6238 6239 -6240 -6241 -6242 6243 -6244 +v 6245 -6246 -6247 -6248 6249 -6250 6251 -6252 -6253 -6254 6255 -6256 6257 +v -6258 -6259 6260 -6261 -6262 -6263 -6264 -6265 -6266 -6267 -6268 -6269 -6270 +v 6271 6272 6273 6274 -6275 -6276 -6277 -6278 -6279 -6280 -6281 -6282 -6283 +v -6284 -6285 -6286 -6287 -6288 -6289 -6290 -6291 -6292 -6293 -6294 -6295 -6296 +v -6297 -6298 -6299 -6300 -6301 -6302 -6303 -6304 -6305 -6306 -6307 -6308 -6309 +v -6310 -6311 -6312 -6313 -6314 -6315 -6316 -6317 -6318 -6319 -6320 -6321 -6322 +v -6323 -6324 -6325 -6326 -6327 6328 -6329 6330 -6331 -6332 6333 -6334 6335 +v -6336 -6337 -6338 6339 -6340 6341 -6342 -6343 -6344 6345 -6346 6347 -6348 +v -6349 6350 -6351 -6352 -6353 -6354 -6355 -6356 -6357 -6358 -6359 -6360 6361 +v 6362 6363 6364 -6365 -6366 -6367 -6368 -6369 -6370 -6371 -6372 -6373 -6374 +v -6375 -6376 -6377 -6378 -6379 -6380 -6381 -6382 -6383 -6384 -6385 -6386 -6387 +v -6388 -6389 -6390 -6391 -6392 -6393 -6394 -6395 -6396 -6397 -6398 -6399 -6400 +v -6401 -6402 -6403 -6404 -6405 -6406 -6407 -6408 -6409 -6410 -6411 -6412 -6413 +v -6414 -6415 -6416 -6417 -6418 -6419 -6420 -6421 -6422 -6423 -6424 -6425 -6426 +v -6427 -6428 -6429 -6430 -6431 -6432 -6433 -6434 -6435 -6436 -6437 -6438 -6439 +v -6440 -6441 -6442 -6443 -6444 -6445 -6446 -6447 -6448 -6449 -6450 -6451 -6452 +v -6453 -6454 -6455 -6456 -6457 -6458 -6459 -6460 -6461 -6462 -6463 -6464 -6465 +v -6466 -6467 -6468 -6469 -6470 -6471 -6472 -6473 -6474 -6475 -6476 -6477 -6478 +v -6479 -6480 -6481 -6482 -6483 -6484 -6485 -6486 -6487 -6488 -6489 -6490 6491 +v -6492 -6493 -6494 -6495 -6496 -6497 -6498 -6499 -6500 -6501 -6502 -6503 -6504 +v -6505 -6506 -6507 -6508 -6509 -6510 -6511 -6512 -6513 -6514 -6515 -6516 -6517 +v -6518 -6519 -6520 -6521 -6522 -6523 -6524 -6525 -6526 -6527 -6528 -6529 -6530 +v -6531 -6532 -6533 6534 -6535 6536 -6537 -6538 -6539 6540 -6541 6542 -6543 +v -6544 -6545 6546 -6547 6548 -6549 -6550 -6551 6552 -6553 6554 -6555 -6556 +v 6557 -6558 -6559 -6560 -6561 -6562 -6563 -6564 -6565 -6566 -6567 6568 6569 +v 6570 -6571 -6572 -6573 -6574 -6575 -6576 -6577 -6578 -6579 -6580 -6581 -6582 +v -6583 6584 -6585 -6586 6587 -6588 -6589 -6590 -6591 -6592 -6593 6594 6595 +v 6596 6597 -6598 6599 -6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 +v -6611 -6612 6613 6614 6615 6616 6617 6618 -6619 6620 6621 6622 -6623 -6624 +v -6625 -6626 -6627 -6628 6629 -6630 6631 6632 -6633 -6634 -6635 -6636 -6637 +v -6638 -6639 -6640 -6641 -6642 6643 -6644 -6645 -6646 6647 -6648 -6649 6650 +v 6651 6652 6653 6654 6655 6656 6657 6658 6659 -6660 -6661 6662 6663 6664 6665 +v 6666 6667 -6668 6669 6670 -6671 -6672 6673 6674 6675 6676 -6677 -6678 6679 +v 6680 -6681 -6682 -6683 6684 -6685 6686 -6687 -6688 6689 -6690 -6691 -6692 +v -6693 -6694 -6695 -6696 -6697 6698 6699 6700 -6701 -6702 -6703 -6704 -6705 +v -6706 -6707 -6708 -6709 -6710 -6711 -6712 -6713 -6714 -6715 -6716 -6717 -6718 +v -6719 -6720 -6721 -6722 6723 -6724 -6725 -6726 -6727 -6728 -6729 -6730 6731 +v -6732 6733 -6734 -6735 -6736 6737 -6738 6739 -6740 -6741 6742 -6743 -6744 +v -6745 -6746 -6747 -6748 6749 6750 6751 -6752 -6753 -6754 -6755 -6756 -6757 +v -6758 -6759 -6760 -6761 -6762 -6763 -6764 -6765 -6766 -6767 -6768 -6769 -6770 +v -6771 -6772 -6773 6774 -6775 -6776 -6777 -6778 -6779 -6780 -6781 6782 -6783 +v 6784 -6785 -6786 -6787 6788 -6789 6790 -6791 -6792 6793 -6794 -6795 -6796 +v -6797 -6798 -6799 6800 6801 6802 -6803 -6804 -6805 -6806 -6807 -6808 -6809 +v -6810 -6811 -6812 -6813 -6814 -6815 -6816 -6817 -6818 -6819 -6820 -6821 -6822 +v -6823 -6824 6825 -6826 -6827 -6828 -6829 -6830 -6831 -6832 6833 -6834 6835 +v -6836 -6837 -6838 6839 -6840 6841 -6842 -6843 6844 -6845 -6846 -6847 -6848 +v -6849 -6850 6851 6852 6853 -6854 -6855 -6856 -6857 -6858 -6859 -6860 -6861 +v -6862 -6863 -6864 -6865 -6866 -6867 -6868 -6869 -6870 -6871 -6872 -6873 -6874 +v -6875 -6876 -6877 -6878 -6879 -6880 -6881 -6882 -6883 -6884 -6885 -6886 -6887 +v -6888 -6889 -6890 -6891 -6892 -6893 -6894 -6895 -6896 -6897 -6898 -6899 -6900 +v -6901 -6902 -6903 -6904 -6905 -6906 -6907 -6908 -6909 -6910 -6911 -6912 -6913 +v -6914 -6915 -6916 -6917 -6918 -6919 -6920 -6921 -6922 -6923 -6924 -6925 -6926 +v -6927 -6928 -6929 -6930 -6931 -6932 -6933 -6934 -6935 -6936 -6937 -6938 -6939 +v -6940 -6941 -6942 -6943 -6944 -6945 -6946 6947 -6948 -6949 -6950 -6951 -6952 +v -6953 -6954 -6955 -6956 -6957 -6958 -6959 -6960 -6961 -6962 -6963 -6964 -6965 +v -6966 -6967 -6968 -6969 -6970 -6971 -6972 -6973 -6974 -6975 -6976 -6977 -6978 +v -6979 -6980 -6981 -6982 -6983 -6984 -6985 -6986 -6987 -6988 -6989 -6990 -6991 +v -6992 -6993 -6994 -6995 -6996 -6997 -6998 -6999 -7000 -7001 -7002 -7003 -7004 +v -7005 -7006 -7007 -7008 -7009 -7010 -7011 -7012 -7013 -7014 -7015 7016 -7017 +v 7018 -7019 -7020 -7021 7022 -7023 7024 -7025 -7026 -7027 -7028 7029 -7030 +v 7031 -7032 -7033 -7034 -7035 7036 -7037 7038 -7039 -7040 7041 -7042 -7043 +v -7044 -7045 -7046 -7047 -7048 -7049 -7050 -7051 7052 7053 7054 -7055 -7056 +v -7057 -7058 -7059 -7060 -7061 -7062 -7063 -7064 -7065 -7066 -7067 -7068 -7069 +v -7070 -7071 -7072 -7073 -7074 -7075 -7076 -7077 -7078 -7079 -7080 -7081 -7082 +v -7083 -7084 -7085 -7086 -7087 -7088 -7089 -7090 -7091 -7092 -7093 -7094 -7095 +v -7096 -7097 -7098 -7099 -7100 -7101 -7102 -7103 -7104 -7105 -7106 -7107 -7108 +v -7109 -7110 -7111 -7112 -7113 -7114 -7115 -7116 -7117 -7118 -7119 -7120 -7121 +v -7122 -7123 -7124 -7125 -7126 -7127 -7128 -7129 -7130 -7131 -7132 -7133 -7134 +v -7135 -7136 -7137 -7138 -7139 -7140 -7141 -7142 -7143 -7144 -7145 -7146 -7147 +v 7148 -7149 -7150 -7151 -7152 -7153 -7154 -7155 -7156 -7157 -7158 -7159 -7160 +v -7161 -7162 -7163 -7164 -7165 -7166 -7167 -7168 -7169 -7170 -7171 -7172 -7173 +v -7174 -7175 -7176 -7177 -7178 -7179 -7180 -7181 -7182 -7183 -7184 -7185 -7186 +v -7187 -7188 -7189 -7190 -7191 -7192 -7193 -7194 -7195 -7196 -7197 -7198 -7199 +v -7200 -7201 -7202 -7203 -7204 -7205 -7206 -7207 -7208 -7209 -7210 -7211 -7212 +v -7213 -7214 -7215 -7216 7217 -7218 7219 -7220 -7221 -7222 7223 -7224 7225 +v -7226 -7227 -7228 -7229 7230 -7231 7232 -7233 -7234 -7235 -7236 7237 -7238 +v 7239 -7240 -7241 7242 -7243 -7244 -7245 -7246 -7247 -7248 -7249 -7250 -7251 +v -7252 7253 7254 7255 -7256 -7257 -7258 -7259 -7260 -7261 -7262 -7263 -7264 +v -7265 -7266 -7267 -7268 -7269 -7270 -7271 -7272 -7273 -7274 -7275 -7276 -7277 +v -7278 -7279 -7280 -7281 -7282 -7283 -7284 -7285 -7286 -7287 -7288 -7289 -7290 +v -7291 -7292 -7293 -7294 -7295 -7296 -7297 -7298 -7299 -7300 -7301 -7302 -7303 +v -7304 -7305 -7306 -7307 -7308 -7309 -7310 -7311 -7312 -7313 -7314 -7315 -7316 +v -7317 -7318 -7319 -7320 -7321 -7322 -7323 -7324 -7325 -7326 -7327 -7328 -7329 +v -7330 -7331 -7332 -7333 -7334 -7335 -7336 -7337 -7338 -7339 -7340 -7341 -7342 +v -7343 -7344 -7345 -7346 -7347 -7348 7349 -7350 -7351 -7352 -7353 -7354 -7355 +v -7356 -7357 -7358 -7359 -7360 -7361 -7362 -7363 -7364 -7365 -7366 -7367 -7368 +v -7369 -7370 -7371 -7372 -7373 -7374 -7375 -7376 -7377 -7378 -7379 -7380 -7381 +v -7382 -7383 -7384 -7385 -7386 -7387 -7388 -7389 -7390 -7391 -7392 -7393 -7394 +v -7395 -7396 -7397 -7398 -7399 -7400 -7401 -7402 -7403 -7404 -7405 -7406 -7407 +v -7408 -7409 -7410 -7411 -7412 -7413 -7414 -7415 -7416 -7417 7418 -7419 7420 +v -7421 -7422 -7423 7424 -7425 7426 -7427 -7428 -7429 -7430 7431 -7432 7433 +v -7434 -7435 -7436 -7437 7438 -7439 7440 -7441 -7442 7443 -7444 -7445 -7446 +v -7447 -7448 -7449 -7450 -7451 -7452 -7453 7454 7455 7456 -7457 -7458 -7459 +v -7460 -7461 -7462 -7463 -7464 -7465 -7466 -7467 -7468 -7469 -7470 -7471 -7472 +v -7473 -7474 -7475 -7476 -7477 -7478 -7479 -7480 -7481 -7482 -7483 -7484 -7485 +v -7486 -7487 -7488 -7489 -7490 -7491 -7492 -7493 -7494 -7495 -7496 -7497 -7498 +v -7499 -7500 -7501 -7502 -7503 -7504 -7505 -7506 -7507 -7508 -7509 -7510 -7511 +v -7512 -7513 -7514 -7515 -7516 -7517 -7518 -7519 -7520 -7521 -7522 -7523 -7524 +v -7525 -7526 -7527 -7528 -7529 -7530 -7531 -7532 -7533 -7534 -7535 -7536 -7537 +v -7538 -7539 -7540 -7541 -7542 -7543 -7544 -7545 -7546 -7547 -7548 -7549 7550 +v -7551 -7552 -7553 -7554 -7555 -7556 -7557 -7558 -7559 -7560 -7561 -7562 -7563 +v -7564 -7565 -7566 -7567 -7568 -7569 -7570 -7571 -7572 -7573 -7574 -7575 -7576 +v -7577 -7578 -7579 -7580 -7581 -7582 -7583 -7584 -7585 -7586 -7587 -7588 -7589 +v -7590 -7591 -7592 -7593 -7594 -7595 -7596 -7597 -7598 -7599 -7600 -7601 -7602 +v -7603 -7604 -7605 -7606 -7607 -7608 -7609 -7610 -7611 -7612 -7613 -7614 -7615 +v -7616 -7617 -7618 7619 -7620 7621 -7622 -7623 -7624 7625 -7626 7627 -7628 +v -7629 -7630 -7631 7632 -7633 7634 -7635 -7636 -7637 -7638 7639 -7640 7641 +v -7642 -7643 7644 -7645 -7646 -7647 -7648 -7649 -7650 -7651 -7652 -7653 -7654 +v 7655 7656 7657 -7658 -7659 -7660 -7661 -7662 -7663 -7664 -7665 -7666 -7667 +v -7668 -7669 -7670 -7671 -7672 -7673 -7674 -7675 -7676 -7677 -7678 -7679 7680 +v -7681 -7682 -7683 -7684 -7685 -7686 -7687 7688 -7689 7690 -7691 -7692 -7693 +v 7694 -7695 7696 -7697 -7698 7699 -7700 -7701 -7702 -7703 -7704 -7705 7706 +v 7707 7708 -7709 -7710 -7711 -7712 -7713 -7714 -7715 -7716 -7717 -7718 -7719 +v -7720 -7721 -7722 -7723 -7724 -7725 -7726 -7727 -7728 -7729 -7730 -7731 -7732 +v -7733 -7734 -7735 -7736 -7737 7738 -7739 7740 -7741 -7742 -7743 7744 -7745 +v 7746 -7747 -7748 7749 -7750 -7751 -7752 -7753 -7754 -7755 7756 7757 7758 7759 +v -7760 -7761 -7762 -7763 -7764 -7765 -7766 -7767 -7768 -7769 -7770 -7771 -7772 +v -7773 -7774 -7775 -7776 -7777 -7778 -7779 -7780 -7781 -7782 -7783 -7784 -7785 +v -7786 -7787 -7788 7789 -7790 7791 -7792 -7793 -7794 7795 -7796 7797 -7798 +v -7799 7800 -7801 -7802 -7803 -7804 -7805 -7806 7807 7808 7809 7810 -7811 +v -7812 -7813 -7814 -7815 -7816 -7817 -7818 -7819 -7820 -7821 -7822 -7823 -7824 +v -7825 -7826 -7827 -7828 -7829 -7830 -7831 -7832 -7833 -7834 -7835 -7836 -7837 +v -7838 -7839 7840 -7841 7842 -7843 -7844 -7845 7846 -7847 7848 -7849 -7850 +v 7851 -7852 -7853 -7854 -7855 -7856 -7857 7858 7859 7860 7861 -7862 -7863 +v -7864 -7865 -7866 -7867 -7868 -7869 -7870 -7871 -7872 -7873 -7874 -7875 -7876 +v -7877 -7878 -7879 -7880 -7881 -7882 -7883 -7884 -7885 -7886 -7887 -7888 -7889 +v -7890 -7891 -7892 -7893 -7894 -7895 -7896 -7897 -7898 -7899 -7900 -7901 -7902 +v -7903 -7904 -7905 -7906 -7907 -7908 -7909 -7910 -7911 -7912 -7913 -7914 -7915 +v -7916 -7917 -7918 -7919 -7920 -7921 -7922 -7923 -7924 -7925 -7926 -7927 -7928 +v -7929 -7930 -7931 -7932 -7933 -7934 -7935 -7936 -7937 -7938 -7939 -7940 -7941 +v -7942 -7943 -7944 -7945 -7946 -7947 -7948 -7949 -7950 -7951 -7952 -7953 -7954 +v -7955 -7956 -7957 -7958 -7959 -7960 -7961 -7962 -7963 -7964 -7965 -7966 -7967 +v -7968 -7969 -7970 -7971 -7972 -7973 -7974 -7975 -7976 -7977 -7978 -7979 -7980 +v -7981 -7982 -7983 -7984 -7985 -7986 -7987 -7988 -7989 -7990 -7991 -7992 -7993 +v -7994 -7995 -7996 -7997 -7998 -7999 -8000 -8001 -8002 -8003 -8004 -8005 -8006 +v -8007 -8008 -8009 -8010 -8011 -8012 -8013 -8014 -8015 -8016 -8017 -8018 -8019 +v -8020 -8021 -8022 8023 -8024 8025 -8026 -8027 -8028 8029 -8030 8031 -8032 +v -8033 -8034 -8035 8036 -8037 8038 -8039 -8040 -8041 -8042 8043 -8044 8045 +v -8046 -8047 8048 -8049 -8050 -8051 -8052 -8053 -8054 -8055 -8056 -8057 -8058 +v 8059 8060 8061 8062 -8063 -8064 -8065 -8066 -8067 -8068 -8069 -8070 -8071 +v -8072 -8073 -8074 -8075 -8076 -8077 -8078 -8079 -8080 -8081 -8082 -8083 -8084 +v -8085 -8086 -8087 -8088 -8089 -8090 -8091 -8092 -8093 -8094 -8095 -8096 -8097 +v -8098 -8099 -8100 -8101 -8102 -8103 -8104 -8105 -8106 -8107 -8108 -8109 -8110 +v -8111 -8112 -8113 -8114 -8115 -8116 -8117 -8118 -8119 -8120 -8121 -8122 -8123 +v -8124 -8125 -8126 -8127 -8128 -8129 -8130 -8131 -8132 -8133 -8134 -8135 -8136 +v -8137 -8138 -8139 -8140 -8141 -8142 -8143 -8144 -8145 -8146 -8147 -8148 -8149 +v -8150 -8151 -8152 -8153 -8154 -8155 -8156 -8157 -8158 -8159 -8160 -8161 -8162 +v -8163 -8164 -8165 -8166 -8167 -8168 -8169 -8170 -8171 -8172 -8173 -8174 -8175 +v -8176 -8177 -8178 -8179 -8180 -8181 -8182 -8183 -8184 -8185 -8186 -8187 -8188 +v -8189 -8190 -8191 -8192 -8193 -8194 -8195 -8196 -8197 -8198 -8199 -8200 -8201 +v -8202 -8203 -8204 -8205 -8206 -8207 -8208 -8209 -8210 -8211 -8212 -8213 -8214 +v -8215 -8216 -8217 -8218 -8219 -8220 -8221 -8222 -8223 8224 -8225 8226 -8227 +v -8228 -8229 8230 -8231 8232 -8233 -8234 -8235 -8236 8237 -8238 8239 -8240 +v -8241 -8242 -8243 8244 -8245 8246 -8247 -8248 8249 -8250 -8251 -8252 -8253 +v -8254 -8255 -8256 -8257 -8258 -8259 8260 8261 8262 8263 -8264 -8265 -8266 +v -8267 -8268 -8269 -8270 -8271 -8272 -8273 -8274 -8275 -8276 -8277 -8278 -8279 +v -8280 -8281 -8282 -8283 -8284 -8285 -8286 -8287 -8288 -8289 -8290 -8291 -8292 +v -8293 -8294 -8295 -8296 -8297 -8298 -8299 -8300 -8301 -8302 -8303 -8304 -8305 +v -8306 -8307 -8308 -8309 -8310 -8311 -8312 -8313 -8314 -8315 -8316 -8317 -8318 +v -8319 -8320 -8321 -8322 -8323 -8324 -8325 -8326 -8327 -8328 -8329 -8330 -8331 +v -8332 -8333 -8334 -8335 -8336 -8337 -8338 -8339 -8340 -8341 -8342 -8343 -8344 +v -8345 -8346 -8347 -8348 -8349 -8350 -8351 -8352 -8353 -8354 -8355 -8356 -8357 +v -8358 -8359 -8360 -8361 -8362 -8363 -8364 -8365 -8366 -8367 -8368 -8369 -8370 +v -8371 -8372 -8373 -8374 -8375 -8376 -8377 -8378 -8379 -8380 -8381 -8382 -8383 +v -8384 -8385 -8386 -8387 -8388 -8389 -8390 -8391 -8392 -8393 -8394 -8395 -8396 +v -8397 -8398 -8399 -8400 -8401 -8402 -8403 -8404 -8405 -8406 -8407 -8408 -8409 +v -8410 -8411 -8412 -8413 -8414 -8415 -8416 -8417 -8418 -8419 -8420 -8421 -8422 +v -8423 -8424 8425 -8426 8427 -8428 -8429 -8430 8431 -8432 8433 -8434 -8435 +v -8436 -8437 8438 -8439 8440 -8441 -8442 -8443 -8444 8445 -8446 8447 -8448 +v -8449 8450 -8451 -8452 -8453 -8454 -8455 -8456 -8457 -8458 -8459 -8460 8461 +v 8462 8463 8464 -8465 -8466 -8467 -8468 -8469 -8470 -8471 -8472 -8473 -8474 +v -8475 -8476 -8477 -8478 -8479 -8480 -8481 -8482 -8483 -8484 -8485 -8486 -8487 +v -8488 -8489 -8490 -8491 -8492 -8493 -8494 -8495 -8496 -8497 -8498 -8499 -8500 +v -8501 -8502 -8503 -8504 -8505 -8506 -8507 -8508 -8509 -8510 -8511 -8512 -8513 +v -8514 -8515 -8516 -8517 -8518 -8519 -8520 -8521 -8522 -8523 -8524 -8525 -8526 +v -8527 -8528 -8529 -8530 -8531 -8532 -8533 -8534 -8535 -8536 -8537 -8538 -8539 +v -8540 -8541 -8542 -8543 -8544 -8545 -8546 -8547 -8548 -8549 -8550 -8551 -8552 +v -8553 -8554 -8555 -8556 -8557 -8558 -8559 -8560 -8561 -8562 -8563 -8564 -8565 +v -8566 -8567 -8568 -8569 -8570 -8571 -8572 -8573 -8574 -8575 -8576 -8577 -8578 +v -8579 -8580 -8581 -8582 -8583 -8584 -8585 -8586 -8587 -8588 -8589 -8590 -8591 +v -8592 -8593 -8594 -8595 -8596 -8597 -8598 -8599 -8600 -8601 -8602 -8603 -8604 +v -8605 -8606 -8607 -8608 -8609 -8610 -8611 -8612 -8613 -8614 -8615 -8616 -8617 +v -8618 -8619 -8620 -8621 -8622 -8623 -8624 -8625 8626 -8627 8628 -8629 -8630 +v -8631 8632 -8633 8634 -8635 -8636 -8637 -8638 8639 -8640 8641 -8642 -8643 +v -8644 -8645 8646 -8647 8648 -8649 -8650 8651 -8652 -8653 -8654 -8655 -8656 +v -8657 -8658 -8659 -8660 -8661 8662 8663 8664 8665 -8666 -8667 -8668 -8669 +v -8670 -8671 -8672 -8673 -8674 -8675 -8676 -8677 -8678 -8679 -8680 -8681 -8682 +v -8683 -8684 -8685 -8686 -8687 -8688 -8689 -8690 -8691 -8692 -8693 -8694 8695 +v -8696 8697 -8698 -8699 -8700 8701 -8702 8703 -8704 -8705 8706 -8707 -8708 +v -8709 -8710 -8711 -8712 8713 8714 8715 8716 -8717 8718 -8719 8720 -8721 8722 +v 8723 -8724 -8725 -8726 -8727 -8728 -8729 -8730 -8731 -8732 -8733 -8734 -8735 +v -8736 -8737 -8738 -8739 -8740 -8741 -8742 -8743 -8744 -8745 -8746 -8747 -8748 +v -8749 -8750 -8751 -8752 -8753 -8754 -8755 -8756 -8757 -8758 -8759 -8760 -8761 +v -8762 -8763 -8764 -8765 -8766 -8767 -8768 -8769 -8770 -8771 -8772 -8773 -8774 +v -8775 -8776 -8777 -8778 -8779 -8780 -8781 -8782 -8783 -8784 -8785 -8786 -8787 +v -8788 -8789 -8790 -8791 -8792 -8793 -8794 -8795 -8796 -8797 -8798 -8799 -8800 +v -8801 -8802 -8803 -8804 -8805 -8806 -8807 -8808 -8809 -8810 -8811 -8812 -8813 +v -8814 -8815 -8816 -8817 -8818 -8819 -8820 -8821 -8822 -8823 -8824 -8825 -8826 +v -8827 -8828 -8829 -8830 -8831 -8832 -8833 -8834 -8835 -8836 -8837 -8838 -8839 +v -8840 -8841 -8842 -8843 -8844 -8845 -8846 -8847 -8848 -8849 -8850 -8851 -8852 +v -8853 -8854 -8855 -8856 -8857 -8858 -8859 -8860 -8861 -8862 -8863 -8864 -8865 +v -8866 -8867 -8868 -8869 -8870 -8871 -8872 -8873 -8874 -8875 -8876 -8877 -8878 +v -8879 -8880 -8881 -8882 -8883 -8884 -8885 -8886 -8887 -8888 -8889 -8890 -8891 +v -8892 -8893 -8894 -8895 -8896 -8897 -8898 -8899 -8900 -8901 -8902 -8903 -8904 +v -8905 -8906 -8907 -8908 -8909 -8910 -8911 -8912 -8913 -8914 -8915 -8916 -8917 +v -8918 -8919 -8920 -8921 -8922 -8923 -8924 -8925 -8926 -8927 -8928 -8929 -8930 +v -8931 -8932 -8933 -8934 -8935 -8936 -8937 -8938 -8939 -8940 -8941 -8942 -8943 +v -8944 -8945 -8946 -8947 -8948 -8949 -8950 -8951 -8952 -8953 -8954 -8955 -8956 +v -8957 -8958 -8959 -8960 -8961 -8962 -8963 -8964 -8965 -8966 -8967 -8968 -8969 +v -8970 -8971 -8972 -8973 -8974 -8975 -8976 -8977 -8978 -8979 -8980 -8981 -8982 +v -8983 -8984 -8985 -8986 -8987 -8988 -8989 -8990 -8991 -8992 -8993 -8994 -8995 +v -8996 -8997 -8998 -8999 -9000 -9001 -9002 -9003 -9004 -9005 -9006 -9007 -9008 +v -9009 -9010 -9011 -9012 -9013 -9014 -9015 -9016 -9017 -9018 -9019 -9020 -9021 +v -9022 -9023 -9024 -9025 -9026 -9027 -9028 -9029 -9030 -9031 -9032 -9033 -9034 +v -9035 -9036 -9037 -9038 -9039 -9040 -9041 -9042 -9043 -9044 -9045 -9046 -9047 +v -9048 -9049 -9050 -9051 -9052 -9053 -9054 -9055 -9056 -9057 -9058 -9059 -9060 +v -9061 -9062 -9063 -9064 -9065 -9066 -9067 -9068 -9069 -9070 -9071 -9072 -9073 +v -9074 -9075 -9076 -9077 -9078 -9079 -9080 -9081 -9082 -9083 -9084 -9085 -9086 +v -9087 -9088 -9089 -9090 -9091 -9092 -9093 -9094 -9095 -9096 -9097 -9098 -9099 +v -9100 -9101 -9102 -9103 -9104 -9105 -9106 -9107 -9108 -9109 -9110 -9111 -9112 +v -9113 -9114 -9115 -9116 -9117 -9118 -9119 -9120 -9121 -9122 -9123 -9124 -9125 +v -9126 -9127 9128 -9129 9130 -9131 -9132 -9133 9134 -9135 9136 -9137 -9138 +v -9139 9140 -9141 9142 -9143 -9144 -9145 -9146 9147 -9148 9149 -9150 -9151 +v -9152 -9153 9154 -9155 9156 -9157 -9158 -9159 -9160 9161 -9162 9163 -9164 +v -9165 9166 -9167 -9168 -9169 -9170 -9171 -9172 -9173 -9174 -9175 -9176 -9177 +v -9178 -9179 -9180 9181 9182 9183 9184 9185 -9186 -9187 -9188 -9189 -9190 +v -9191 9192 -9193 -9194 -9195 -9196 -9197 -9198 -9199 -9200 -9201 -9202 -9203 +v -9204 -9205 -9206 -9207 -9208 -9209 -9210 -9211 -9212 -9213 -9214 -9215 -9216 +v -9217 -9218 -9219 -9220 -9221 -9222 -9223 -9224 -9225 -9226 -9227 -9228 -9229 +v -9230 -9231 -9232 -9233 -9234 -9235 -9236 -9237 -9238 -9239 -9240 -9241 -9242 +v -9243 -9244 -9245 -9246 -9247 -9248 -9249 -9250 -9251 -9252 -9253 -9254 -9255 +v -9256 -9257 -9258 -9259 -9260 -9261 -9262 -9263 -9264 -9265 -9266 -9267 -9268 +v -9269 -9270 -9271 -9272 -9273 -9274 -9275 -9276 -9277 -9278 -9279 -9280 -9281 +v -9282 -9283 -9284 -9285 -9286 -9287 -9288 -9289 -9290 -9291 -9292 -9293 -9294 +v -9295 -9296 -9297 -9298 -9299 -9300 -9301 -9302 -9303 -9304 -9305 -9306 -9307 +v -9308 -9309 -9310 -9311 -9312 9313 -9314 9315 -9316 -9317 -9318 9319 -9320 +v 9321 -9322 -9323 -9324 9325 -9326 9327 -9328 -9329 -9330 9331 -9332 9333 +v -9334 -9335 9336 -9337 -9338 -9339 -9340 -9341 -9342 -9343 -9344 -9345 -9346 +v 9347 9348 9349 9350 -9351 -9352 -9353 -9354 -9355 -9356 -9357 -9358 -9359 +v -9360 -9361 -9362 -9363 -9364 -9365 -9366 -9367 -9368 -9369 -9370 -9371 -9372 +v -9373 -9374 -9375 -9376 -9377 -9378 -9379 -9380 -9381 -9382 -9383 -9384 -9385 +v -9386 -9387 -9388 -9389 -9390 -9391 -9392 -9393 -9394 -9395 -9396 -9397 -9398 +v -9399 -9400 -9401 -9402 -9403 9404 -9405 9406 -9407 -9408 9409 -9410 9411 +v -9412 -9413 -9414 9415 -9416 9417 -9418 -9419 -9420 9421 -9422 9423 -9424 +v -9425 9426 -9427 -9428 -9429 -9430 -9431 -9432 -9433 -9434 -9435 -9436 9437 +v 9438 9439 9440 -9441 -9442 -9443 -9444 -9445 -9446 -9447 -9448 -9449 -9450 +v -9451 -9452 -9453 -9454 -9455 -9456 -9457 -9458 -9459 -9460 -9461 -9462 -9463 +v -9464 -9465 -9466 -9467 -9468 -9469 -9470 -9471 -9472 -9473 -9474 -9475 -9476 +v -9477 -9478 -9479 -9480 -9481 -9482 -9483 -9484 -9485 -9486 -9487 -9488 -9489 +v -9490 -9491 -9492 -9493 -9494 -9495 -9496 -9497 -9498 -9499 -9500 -9501 -9502 +v -9503 -9504 -9505 -9506 -9507 -9508 -9509 -9510 -9511 -9512 -9513 -9514 -9515 +v -9516 -9517 -9518 -9519 -9520 -9521 -9522 -9523 -9524 -9525 -9526 -9527 -9528 +v -9529 -9530 -9531 -9532 -9533 -9534 -9535 -9536 -9537 -9538 -9539 -9540 -9541 +v -9542 -9543 -9544 -9545 -9546 -9547 -9548 -9549 -9550 -9551 -9552 -9553 -9554 +v -9555 -9556 -9557 -9558 -9559 -9560 -9561 -9562 -9563 -9564 -9565 -9566 -9567 +v -9568 -9569 -9570 -9571 -9572 -9573 -9574 -9575 -9576 -9577 -9578 -9579 -9580 +v -9581 -9582 -9583 -9584 -9585 -9586 -9587 -9588 -9589 -9590 -9591 -9592 -9593 +v -9594 -9595 -9596 -9597 -9598 -9599 -9600 -9601 -9602 -9603 -9604 -9605 -9606 +v -9607 9608 -9609 9610 -9611 -9612 9613 -9614 9615 -9616 -9617 9618 -9619 9620 +v -9621 -9622 -9623 9624 -9625 9626 -9627 -9628 -9629 9630 -9631 9632 -9633 +v -9634 9635 -9636 -9637 -9638 -9639 -9640 -9641 -9642 -9643 -9644 -9645 -9646 +v 9647 9648 9649 -9650 -9651 -9652 -9653 -9654 -9655 -9656 -9657 -9658 -9659 +v -9660 -9661 -9662 9663 -9664 -9665 9666 -9667 -9668 -9669 -9670 -9671 -9672 +v 9673 9674 9675 -9676 -9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 +v -9688 -9689 9690 9691 9692 9693 9694 9695 -9696 9697 9698 9699 -9700 -9701 +v -9702 -9703 -9704 -9705 9706 -9707 9708 9709 -9710 -9711 -9712 -9713 -9714 +v -9715 -9716 -9717 -9718 -9719 9720 -9721 -9722 -9723 9724 -9725 -9726 9727 +v 9728 9729 9730 9731 9732 9733 9734 9735 9736 -9737 -9738 9739 9740 9741 9742 +v 9743 9744 -9745 9746 9747 -9748 -9749 9750 9751 9752 9753 -9754 -9755 9756 +v 9757 -9758 -9759 -9760 9761 -9762 9763 -9764 -9765 9766 -9767 -9768 -9769 +v -9770 -9771 -9772 -9773 -9774 9775 9776 9777 -9778 -9779 -9780 -9781 -9782 +v -9783 -9784 -9785 -9786 -9787 -9788 -9789 -9790 -9791 -9792 -9793 -9794 -9795 +v -9796 -9797 -9798 -9799 9800 -9801 -9802 -9803 -9804 -9805 -9806 -9807 9808 +v -9809 9810 -9811 -9812 -9813 9814 -9815 9816 -9817 -9818 9819 -9820 -9821 +v -9822 -9823 -9824 -9825 9826 9827 9828 -9829 -9830 -9831 -9832 -9833 -9834 +v -9835 -9836 -9837 -9838 -9839 -9840 -9841 -9842 -9843 -9844 -9845 -9846 -9847 +v -9848 -9849 -9850 9851 -9852 -9853 -9854 -9855 -9856 -9857 -9858 9859 -9860 +v 9861 -9862 -9863 -9864 9865 -9866 9867 -9868 -9869 9870 -9871 -9872 -9873 +v -9874 -9875 -9876 9877 9878 9879 -9880 -9881 -9882 -9883 -9884 -9885 -9886 +v -9887 -9888 -9889 -9890 -9891 -9892 -9893 -9894 -9895 -9896 -9897 -9898 -9899 +v -9900 -9901 9902 -9903 -9904 -9905 -9906 -9907 -9908 -9909 9910 -9911 9912 +v -9913 -9914 -9915 9916 -9917 9918 -9919 -9920 9921 -9922 -9923 -9924 -9925 +v -9926 -9927 9928 9929 9930 -9931 -9932 -9933 -9934 -9935 -9936 -9937 -9938 +v -9939 -9940 -9941 -9942 -9943 -9944 -9945 -9946 -9947 -9948 -9949 -9950 -9951 +v -9952 -9953 -9954 -9955 -9956 -9957 -9958 -9959 -9960 -9961 -9962 -9963 -9964 +v -9965 -9966 -9967 -9968 -9969 -9970 -9971 -9972 -9973 -9974 -9975 -9976 -9977 +v -9978 -9979 -9980 -9981 -9982 -9983 -9984 -9985 -9986 -9987 -9988 -9989 -9990 +v -9991 -9992 -9993 -9994 -9995 -9996 -9997 -9998 -9999 -10000 -10001 -10002 +v -10003 -10004 -10005 -10006 -10007 -10008 -10009 -10010 -10011 -10012 -10013 +v -10014 -10015 -10016 -10017 -10018 -10019 -10020 -10021 -10022 -10023 10024 +v -10025 -10026 -10027 -10028 -10029 -10030 -10031 -10032 -10033 -10034 -10035 +v -10036 -10037 -10038 -10039 -10040 -10041 -10042 -10043 -10044 -10045 -10046 +v -10047 -10048 -10049 -10050 -10051 -10052 -10053 -10054 -10055 -10056 -10057 +v -10058 -10059 -10060 -10061 -10062 -10063 -10064 -10065 -10066 -10067 -10068 +v -10069 -10070 -10071 -10072 -10073 -10074 -10075 -10076 -10077 -10078 -10079 +v -10080 -10081 -10082 -10083 -10084 -10085 -10086 -10087 -10088 -10089 -10090 +v -10091 -10092 10093 -10094 10095 -10096 -10097 -10098 10099 -10100 10101 +v -10102 -10103 -10104 -10105 10106 -10107 10108 -10109 -10110 -10111 -10112 +v 10113 -10114 10115 -10116 -10117 10118 -10119 -10120 -10121 -10122 -10123 +v -10124 -10125 -10126 -10127 -10128 10129 10130 10131 -10132 -10133 -10134 +v -10135 -10136 -10137 -10138 -10139 -10140 -10141 -10142 -10143 -10144 -10145 +v -10146 -10147 -10148 -10149 -10150 -10151 -10152 -10153 -10154 -10155 -10156 +v -10157 -10158 -10159 -10160 -10161 -10162 -10163 -10164 -10165 -10166 -10167 +v -10168 -10169 -10170 -10171 -10172 -10173 -10174 -10175 -10176 -10177 -10178 +v -10179 -10180 -10181 -10182 -10183 -10184 -10185 -10186 -10187 -10188 -10189 +v -10190 -10191 -10192 -10193 -10194 -10195 -10196 -10197 -10198 -10199 -10200 +v -10201 -10202 -10203 -10204 -10205 -10206 -10207 -10208 -10209 -10210 -10211 +v -10212 -10213 -10214 -10215 -10216 -10217 -10218 -10219 -10220 -10221 -10222 +v -10223 -10224 10225 -10226 -10227 -10228 -10229 -10230 -10231 -10232 -10233 +v -10234 -10235 -10236 -10237 -10238 -10239 -10240 -10241 -10242 -10243 -10244 +v -10245 -10246 -10247 -10248 -10249 -10250 -10251 -10252 -10253 -10254 -10255 +v -10256 -10257 -10258 -10259 -10260 -10261 -10262 -10263 -10264 -10265 -10266 +v -10267 -10268 -10269 -10270 -10271 -10272 -10273 -10274 -10275 -10276 -10277 +v -10278 -10279 -10280 -10281 -10282 -10283 -10284 -10285 -10286 -10287 -10288 +v -10289 -10290 -10291 -10292 -10293 10294 -10295 10296 -10297 -10298 -10299 +v 10300 -10301 10302 -10303 -10304 -10305 -10306 10307 -10308 10309 -10310 +v -10311 -10312 -10313 10314 -10315 10316 -10317 -10318 10319 -10320 -10321 +v -10322 -10323 -10324 -10325 -10326 -10327 -10328 -10329 10330 10331 10332 +v -10333 -10334 -10335 -10336 -10337 -10338 -10339 -10340 -10341 -10342 -10343 +v -10344 -10345 -10346 -10347 -10348 -10349 -10350 -10351 -10352 -10353 -10354 +v -10355 -10356 -10357 -10358 -10359 -10360 -10361 -10362 -10363 -10364 -10365 +v -10366 -10367 -10368 -10369 -10370 -10371 -10372 -10373 -10374 -10375 -10376 +v -10377 -10378 -10379 -10380 -10381 -10382 -10383 -10384 -10385 -10386 -10387 +v -10388 -10389 -10390 -10391 -10392 -10393 -10394 -10395 -10396 -10397 -10398 +v -10399 -10400 -10401 -10402 -10403 -10404 -10405 -10406 -10407 -10408 -10409 +v -10410 -10411 -10412 -10413 -10414 -10415 -10416 -10417 -10418 -10419 -10420 +v -10421 -10422 -10423 -10424 -10425 10426 -10427 -10428 -10429 -10430 -10431 +v -10432 -10433 -10434 -10435 -10436 -10437 -10438 -10439 -10440 -10441 -10442 +v -10443 -10444 -10445 -10446 -10447 -10448 -10449 -10450 -10451 -10452 -10453 +v -10454 -10455 -10456 -10457 -10458 -10459 -10460 -10461 -10462 -10463 -10464 +v -10465 -10466 -10467 -10468 -10469 -10470 -10471 -10472 -10473 -10474 -10475 +v -10476 -10477 -10478 -10479 -10480 -10481 -10482 -10483 -10484 -10485 -10486 +v -10487 -10488 -10489 -10490 -10491 -10492 -10493 -10494 10495 -10496 10497 +v -10498 -10499 -10500 10501 -10502 10503 -10504 -10505 -10506 -10507 10508 +v -10509 10510 -10511 -10512 -10513 -10514 10515 -10516 10517 -10518 -10519 +v 10520 -10521 -10522 -10523 -10524 -10525 -10526 -10527 -10528 -10529 -10530 +v 10531 10532 10533 -10534 -10535 -10536 -10537 -10538 -10539 -10540 -10541 +v -10542 -10543 -10544 -10545 -10546 -10547 -10548 -10549 -10550 -10551 -10552 +v -10553 -10554 -10555 -10556 -10557 -10558 -10559 -10560 -10561 -10562 -10563 +v -10564 -10565 -10566 -10567 -10568 -10569 -10570 -10571 -10572 -10573 -10574 +v -10575 -10576 -10577 -10578 -10579 -10580 -10581 -10582 -10583 -10584 -10585 +v -10586 -10587 -10588 -10589 -10590 -10591 -10592 -10593 -10594 -10595 -10596 +v -10597 -10598 -10599 -10600 -10601 -10602 -10603 -10604 -10605 -10606 -10607 +v -10608 -10609 -10610 -10611 -10612 -10613 -10614 -10615 -10616 -10617 -10618 +v -10619 -10620 -10621 -10622 -10623 -10624 -10625 -10626 10627 -10628 -10629 +v -10630 -10631 -10632 -10633 -10634 -10635 -10636 -10637 -10638 -10639 -10640 +v -10641 -10642 -10643 -10644 -10645 -10646 -10647 -10648 -10649 -10650 -10651 +v -10652 -10653 -10654 -10655 -10656 -10657 -10658 -10659 -10660 -10661 -10662 +v -10663 -10664 -10665 -10666 -10667 -10668 -10669 -10670 -10671 -10672 -10673 +v -10674 -10675 -10676 -10677 -10678 -10679 -10680 -10681 -10682 -10683 -10684 +v -10685 -10686 -10687 -10688 -10689 -10690 -10691 -10692 -10693 -10694 -10695 +v 10696 -10697 10698 -10699 -10700 -10701 10702 -10703 10704 -10705 -10706 +v -10707 -10708 10709 -10710 10711 -10712 -10713 -10714 -10715 10716 -10717 +v 10718 -10719 -10720 10721 -10722 -10723 -10724 -10725 -10726 -10727 -10728 +v -10729 -10730 -10731 10732 10733 10734 -10735 -10736 -10737 -10738 -10739 +v -10740 -10741 -10742 -10743 -10744 -10745 -10746 -10747 -10748 -10749 -10750 +v -10751 -10752 -10753 -10754 -10755 -10756 10757 -10758 -10759 -10760 -10761 +v -10762 -10763 -10764 10765 -10766 10767 -10768 -10769 -10770 10771 -10772 +v 10773 -10774 -10775 10776 -10777 -10778 -10779 -10780 -10781 -10782 10783 +v 10784 10785 10786 10787 10788 10789 -10790 -10791 -10792 -10793 10794 -10795 +v 10796 -10797 10798 -10799 10800 10801 10802 10803 -10804 -10805 10806 10807 +v 10808 -10809 -10810 -10811 -10812 -10813 -10814 -10815 10816 10817 10818 +v 10819 -10820 -10821 -10822 -10823 10824 -10825 10826 -10827 10828 -10829 +v 10830 10831 10832 10833 -10834 -10835 10836 10837 10838 -10839 -10840 -10841 +v -10842 -10843 -10844 -10845 10846 10847 10848 10849 -10850 -10851 -10852 +v -10853 -10854 -10855 -10856 -10857 10858 -10859 10860 -10861 -10862 -10863 +v 10864 -10865 10866 10867 10868 -10869 -10870 -10871 -10872 -10873 -10874 +v -10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 -10885 10886 +v -10887 -10888 10889 -10890 -10891 -10892 10893 10894 10895 10896 10897 10898 +v 10899 10900 10901 10902 10903 -10904 10905 -10906 -10907 -10908 -10909 -10910 +v -10911 -10912 -10913 10914 -10915 -10916 -10917 10918 -10919 -10920 -10921 +v -10922 10923 10924 10925 -10926 10927 10928 -10929 -10930 10931 10932 10933 +v 10934 10935 10936 10937 10938 -10939 -10940 10941 10942 -10943 -10944 10945 +v -10946 10947 -10948 -10949 -10950 10951 -10952 10953 10954 10955 -10956 +v -10957 -10958 -10959 -10960 -10961 -10962 -10963 -10964 10965 10966 10967 +v -10968 -10969 10970 10971 -10972 -10973 -10974 -10975 -10976 -10977 -10978 +v -10979 -10980 10981 10982 -10983 -10984 -10985 -10986 -10987 -10988 -10989 +v -10990 -10991 10992 10993 -10994 10995 -10996 -10997 -10998 -10999 -11000 +v -11001 -11002 11003 11004 11005 11006 11007 11008 11009 -11010 -11011 11012 +v 11013 11014 -11015 -11016 11017 11018 11019 -11020 -11021 -11022 -11023 +v -11024 11025 11026 11027 -11028 -11029 11030 11031 -11032 -11033 11034 -11035 +v -11036 11037 11038 11039 11040 -11041 -11042 -11043 -11044 11045 11046 11047 +v 11048 -11049 -11050 -11051 -11052 11053 11054 11055 11056 -11057 -11058 +v -11059 -11060 -11061 -11062 -11063 -11064 -11065 -11066 -11067 -11068 -11069 +v -11070 -11071 -11072 -11073 -11074 11075 -11076 11077 -11078 -11079 -11080 +v 11081 -11082 11083 -11084 -11085 11086 -11087 -11088 -11089 -11090 -11091 +v -11092 11093 11094 11095 11096 -11097 -11098 -11099 -11100 -11101 -11102 +v -11103 -11104 -11105 -11106 -11107 -11108 -11109 -11110 -11111 -11112 11113 +v -11114 11115 -11116 -11117 -11118 11119 -11120 11121 -11122 -11123 11124 +v -11125 -11126 -11127 -11128 -11129 -11130 11131 11132 11133 11134 -11135 +v -11136 11137 11138 11139 11140 -11141 -11142 -11143 -11144 11145 11146 11147 +v 11148 -11149 -11150 -11151 -11152 -11153 -11154 -11155 -11156 -11157 -11158 +v -11159 -11160 -11161 -11162 -11163 -11164 -11165 -11166 -11167 -11168 -11169 +v 11170 -11171 11172 -11173 -11174 -11175 -11176 11177 -11178 11179 -11180 +v -11181 11182 -11183 -11184 -11185 -11186 -11187 -11188 11189 11190 11191 +v 11192 11193 11194 -11195 -11196 -11197 -11198 -11199 -11200 -11201 -11202 +v -11203 -11204 -11205 -11206 -11207 -11208 -11209 -11210 -11211 -11212 -11213 +v -11214 -11215 11216 -11217 11218 -11219 -11220 -11221 -11222 11223 -11224 +v 11225 -11226 -11227 11228 -11229 -11230 -11231 -11232 -11233 -11234 11235 +v 11236 11237 11238 -11239 -11240 11241 -11242 11243 -11244 11245 -11246 -11247 +v -11248 11249 11250 11251 11252 11253 -11254 -11255 11256 11257 -11258 -11259 +v 11260 11261 -11262 -11263 -11264 -11265 -11266 11267 11268 11269 11270 -11271 +v -11272 11273 11274 -11275 -11276 11277 11278 -11279 -11280 11281 11282 -11283 +v 11284 -11285 11286 -11287 -11288 -11289 -11290 -11291 -11292 11293 11294 +v -11295 11296 -11297 11298 -11299 -11300 -11301 -11302 -11303 -11304 11305 +v 11306 -11307 -11308 11309 11310 -11311 -11312 11313 11314 -11315 11316 -11317 +v 11318 -11319 -11320 -11321 -11322 -11323 -11324 11325 -11326 -11327 11328 +v -11329 11330 -11331 11332 -11333 -11334 -11335 11336 11337 11338 11339 11340 +v 11341 11342 11343 11344 11345 -11346 -11347 11348 11349 -11350 -11351 11352 +v 11353 -11354 -11355 -11356 -11357 -11358 11359 11360 11361 -11362 -11363 +v 11364 -11365 -11366 11367 11368 11369 11370 11371 11372 -11373 11374 -11375 +v -11376 11377 11378 11379 11380 11381 11382 -11383 -11384 11385 -11386 -11387 +v 11388 -11389 11390 -11391 -11392 11393 -11394 -11395 -11396 -11397 -11398 +v 11399 11400 11401 11402 -11403 -11404 -11405 -11406 -11407 -11408 -11409 +v -11410 -11411 -11412 -11413 -11414 -11415 -11416 -11417 -11418 -11419 -11420 +v -11421 -11422 -11423 -11424 -11425 -11426 -11427 -11428 -11429 -11430 -11431 +v -11432 -11433 11434 -11435 11436 -11437 -11438 -11439 11440 -11441 11442 +v -11443 -11444 11445 -11446 -11447 -11448 -11449 -11450 -11451 11452 11453 +v 11454 11455 -11456 -11457 -11458 -11459 -11460 -11461 -11462 -11463 -11464 +v -11465 -11466 -11467 -11468 -11469 -11470 -11471 -11472 -11473 -11474 -11475 +v -11476 -11477 -11478 -11479 -11480 -11481 -11482 -11483 -11484 -11485 -11486 +v 11487 -11488 11489 -11490 -11491 -11492 11493 -11494 11495 -11496 -11497 +v 11498 -11499 -11500 -11501 -11502 -11503 -11504 11505 11506 11507 11508 +v -11509 -11510 -11511 -11512 -11513 -11514 -11515 -11516 -11517 -11518 -11519 +v -11520 -11521 -11522 -11523 -11524 -11525 -11526 -11527 -11528 -11529 -11530 +v -11531 -11532 -11533 -11534 -11535 -11536 -11537 -11538 -11539 11540 -11541 +v 11542 -11543 -11544 -11545 11546 -11547 11548 -11549 -11550 11551 -11552 +v -11553 -11554 -11555 -11556 -11557 11558 11559 11560 11561 11562 -11563 +v -11564 -11565 -11566 -11567 -11568 -11569 -11570 -11571 -11572 -11573 -11574 +v -11575 -11576 -11577 -11578 -11579 -11580 -11581 -11582 -11583 -11584 -11585 +v -11586 -11587 -11588 -11589 -11590 -11591 -11592 -11593 -11594 -11595 -11596 +v -11597 -11598 -11599 -11600 -11601 -11602 -11603 -11604 -11605 -11606 -11607 +v -11608 -11609 -11610 -11611 -11612 -11613 -11614 -11615 -11616 -11617 -11618 +v -11619 -11620 -11621 -11622 -11623 -11624 -11625 -11626 -11627 -11628 -11629 +v -11630 -11631 -11632 -11633 -11634 -11635 -11636 -11637 -11638 -11639 -11640 +v -11641 -11642 -11643 -11644 -11645 -11646 -11647 -11648 -11649 -11650 -11651 +v -11652 -11653 -11654 -11655 -11656 -11657 -11658 -11659 -11660 -11661 -11662 +v -11663 -11664 -11665 -11666 -11667 -11668 -11669 -11670 -11671 -11672 -11673 +v -11674 -11675 -11676 -11677 -11678 -11679 -11680 -11681 -11682 -11683 -11684 +v -11685 -11686 -11687 -11688 -11689 -11690 -11691 -11692 -11693 -11694 -11695 +v -11696 -11697 -11698 -11699 -11700 -11701 -11702 -11703 -11704 -11705 -11706 +v -11707 -11708 -11709 -11710 -11711 -11712 -11713 -11714 -11715 -11716 -11717 +v -11718 -11719 -11720 -11721 -11722 -11723 -11724 -11725 -11726 -11727 -11728 +v -11729 -11730 -11731 -11732 -11733 -11734 -11735 -11736 -11737 -11738 -11739 +v -11740 -11741 -11742 -11743 -11744 11745 -11746 11747 -11748 -11749 -11750 +v 11751 -11752 11753 -11754 -11755 -11756 -11757 11758 -11759 11760 -11761 +v -11762 -11763 -11764 11765 -11766 11767 -11768 -11769 11770 -11771 -11772 +v -11773 -11774 -11775 -11776 -11777 -11778 -11779 -11780 11781 11782 11783 +v 11784 -11785 -11786 -11787 -11788 -11789 -11790 -11791 -11792 -11793 -11794 +v -11795 -11796 -11797 -11798 -11799 -11800 -11801 -11802 -11803 -11804 -11805 +v -11806 -11807 -11808 -11809 -11810 -11811 -11812 -11813 -11814 -11815 11816 +v -11817 11818 -11819 -11820 -11821 11822 -11823 11824 -11825 -11826 11827 +v -11828 -11829 -11830 -11831 -11832 -11833 11834 11835 11836 11837 -11838 +v 11839 -11840 11841 -11842 11843 11844 11845 -11846 -11847 -11848 -11849 +v -11850 -11851 -11852 -11853 -11854 -11855 -11856 -11857 -11858 -11859 -11860 +v -11861 -11862 -11863 -11864 -11865 -11866 -11867 -11868 -11869 -11870 -11871 +v -11872 -11873 -11874 -11875 -11876 -11877 -11878 -11879 -11880 -11881 -11882 +v -11883 -11884 -11885 -11886 -11887 -11888 -11889 -11890 -11891 -11892 -11893 +v -11894 -11895 -11896 -11897 -11898 -11899 -11900 -11901 -11902 -11903 -11904 +v -11905 -11906 -11907 -11908 -11909 -11910 -11911 -11912 -11913 -11914 -11915 +v -11916 -11917 -11918 -11919 -11920 -11921 -11922 -11923 -11924 -11925 -11926 +v -11927 -11928 -11929 -11930 -11931 -11932 -11933 -11934 -11935 -11936 -11937 +v -11938 -11939 -11940 -11941 -11942 -11943 -11944 -11945 -11946 -11947 -11948 +v -11949 -11950 -11951 -11952 -11953 -11954 -11955 -11956 -11957 -11958 -11959 +v -11960 -11961 -11962 -11963 -11964 -11965 -11966 -11967 -11968 -11969 -11970 +v -11971 -11972 -11973 -11974 -11975 -11976 -11977 -11978 -11979 -11980 -11981 +v -11982 -11983 -11984 -11985 -11986 -11987 -11988 -11989 -11990 -11991 -11992 +v -11993 -11994 -11995 -11996 -11997 -11998 -11999 -12000 -12001 -12002 -12003 +v -12004 -12005 -12006 12007 -12008 -12009 -12010 -12011 -12012 -12013 -12014 +v -12015 -12016 -12017 -12018 -12019 -12020 -12021 -12022 -12023 -12024 -12025 +v -12026 -12027 -12028 -12029 -12030 -12031 -12032 -12033 -12034 -12035 -12036 +v -12037 -12038 -12039 -12040 -12041 -12042 -12043 -12044 -12045 -12046 -12047 +v -12048 -12049 -12050 -12051 -12052 -12053 -12054 -12055 -12056 -12057 -12058 +v -12059 -12060 -12061 -12062 -12063 -12064 -12065 -12066 -12067 -12068 -12069 +v -12070 -12071 -12072 -12073 -12074 -12075 -12076 -12077 -12078 -12079 -12080 +v -12081 -12082 -12083 -12084 -12085 -12086 -12087 -12088 -12089 -12090 -12091 +v -12092 -12093 -12094 -12095 -12096 -12097 -12098 -12099 -12100 -12101 -12102 +v -12103 -12104 -12105 -12106 -12107 -12108 -12109 -12110 -12111 -12112 -12113 +v -12114 -12115 -12116 -12117 -12118 -12119 -12120 -12121 -12122 -12123 -12124 +v -12125 -12126 -12127 -12128 -12129 -12130 -12131 -12132 -12133 -12134 -12135 +v -12136 -12137 -12138 -12139 -12140 -12141 -12142 -12143 -12144 -12145 -12146 +v -12147 -12148 -12149 -12150 -12151 -12152 -12153 -12154 -12155 -12156 -12157 +v -12158 -12159 -12160 -12161 -12162 -12163 -12164 -12165 -12166 -12167 -12168 +v -12169 -12170 -12171 -12172 -12173 -12174 -12175 -12176 -12177 -12178 -12179 +v -12180 -12181 -12182 -12183 -12184 -12185 -12186 -12187 -12188 -12189 -12190 +v -12191 -12192 -12193 -12194 -12195 -12196 -12197 -12198 -12199 -12200 -12201 +v -12202 -12203 -12204 -12205 -12206 -12207 -12208 -12209 -12210 -12211 -12212 +v -12213 -12214 -12215 -12216 -12217 -12218 -12219 -12220 -12221 -12222 -12223 +v -12224 -12225 -12226 -12227 -12228 -12229 -12230 -12231 -12232 -12233 -12234 +v -12235 -12236 -12237 -12238 -12239 -12240 -12241 -12242 -12243 -12244 -12245 +v -12246 -12247 -12248 -12249 -12250 -12251 -12252 -12253 -12254 -12255 -12256 +v -12257 -12258 -12259 -12260 -12261 -12262 -12263 -12264 -12265 -12266 12267 +v -12268 12269 -12270 -12271 12272 -12273 12274 -12275 -12276 -12277 12278 +v -12279 12280 -12281 -12282 -12283 12284 -12285 12286 -12287 -12288 -12289 +v 12290 -12291 12292 -12293 -12294 12295 -12296 12297 -12298 -12299 -12300 +v -12301 -12302 -12303 -12304 -12305 -12306 -12307 -12308 -12309 -12310 -12311 +v 12312 12313 12314 12315 12316 -12317 -12318 -12319 -12320 -12321 -12322 12323 +v -12324 -12325 -12326 -12327 -12328 -12329 -12330 -12331 -12332 -12333 -12334 +v -12335 -12336 -12337 -12338 -12339 -12340 -12341 -12342 -12343 -12344 -12345 +v -12346 -12347 -12348 -12349 -12350 -12351 -12352 -12353 -12354 -12355 -12356 +v -12357 -12358 -12359 -12360 -12361 -12362 -12363 -12364 -12365 -12366 -12367 +v -12368 -12369 -12370 -12371 -12372 -12373 -12374 -12375 -12376 -12377 -12378 +v -12379 -12380 -12381 -12382 -12383 -12384 -12385 -12386 -12387 -12388 -12389 +v -12390 -12391 -12392 -12393 -12394 -12395 -12396 -12397 -12398 -12399 -12400 +v -12401 -12402 -12403 -12404 -12405 -12406 -12407 -12408 -12409 -12410 -12411 +v -12412 -12413 -12414 -12415 -12416 -12417 -12418 -12419 -12420 -12421 -12422 +v -12423 -12424 -12425 -12426 -12427 -12428 -12429 -12430 -12431 -12432 -12433 +v -12434 -12435 -12436 -12437 -12438 -12439 -12440 -12441 -12442 -12443 -12444 +v -12445 12446 -12447 12448 -12449 -12450 -12451 -12452 12453 -12454 12455 +v -12456 -12457 -12458 -12459 12460 -12461 12462 -12463 -12464 -12465 -12466 +v 12467 -12468 12469 -12470 -12471 12472 -12473 12474 -12475 -12476 12477 +v -12478 -12479 -12480 -12481 -12482 -12483 -12484 -12485 -12486 -12487 -12488 +v -12489 12490 12491 12492 12493 -12494 -12495 -12496 -12497 -12498 -12499 +v -12500 -12501 -12502 -12503 -12504 -12505 -12506 -12507 -12508 -12509 -12510 +v -12511 -12512 -12513 -12514 -12515 -12516 -12517 -12518 -12519 -12520 -12521 +v -12522 -12523 -12524 -12525 -12526 -12527 -12528 -12529 -12530 -12531 -12532 +v -12533 -12534 -12535 -12536 -12537 -12538 -12539 -12540 -12541 -12542 -12543 +v -12544 12545 -12546 -12547 12548 -12549 -12550 -12551 12552 -12553 -12554 +v -12555 12556 -12557 -12558 -12559 -12560 -12561 -12562 -12563 -12564 -12565 +v -12566 -12567 12568 -12569 12570 12571 12572 12573 -12574 -12575 -12576 +v -12577 -12578 -12579 -12580 -12581 -12582 -12583 -12584 -12585 -12586 -12587 +v -12588 -12589 -12590 -12591 -12592 -12593 -12594 -12595 -12596 -12597 -12598 +v -12599 -12600 -12601 -12602 -12603 -12604 -12605 -12606 -12607 -12608 -12609 +v -12610 -12611 -12612 -12613 -12614 -12615 -12616 -12617 -12618 -12619 -12620 +v -12621 -12622 -12623 -12624 -12625 -12626 -12627 -12628 -12629 -12630 -12631 +v -12632 -12633 -12634 -12635 -12636 -12637 -12638 -12639 -12640 -12641 -12642 +v -12643 -12644 -12645 -12646 -12647 -12648 -12649 -12650 -12651 -12652 -12653 +v -12654 -12655 -12656 -12657 -12658 -12659 -12660 -12661 -12662 -12663 -12664 +v -12665 -12666 -12667 -12668 -12669 -12670 -12671 -12672 -12673 -12674 -12675 +v -12676 -12677 -12678 -12679 -12680 -12681 -12682 -12683 -12684 -12685 -12686 +v -12687 -12688 -12689 -12690 -12691 -12692 -12693 -12694 -12695 -12696 -12697 +v -12698 -12699 -12700 -12701 -12702 -12703 -12704 12705 -12706 -12707 -12708 +v -12709 -12710 -12711 -12712 -12713 -12714 -12715 -12716 -12717 -12718 -12719 +v -12720 -12721 -12722 -12723 -12724 -12725 -12726 -12727 -12728 -12729 -12730 +v -12731 -12732 -12733 -12734 -12735 -12736 -12737 -12738 -12739 -12740 -12741 +v -12742 -12743 -12744 -12745 -12746 -12747 -12748 -12749 -12750 -12751 -12752 +v 12753 -12754 12755 -12756 -12757 -12758 12759 -12760 12761 -12762 -12763 +v -12764 12765 -12766 12767 -12768 -12769 -12770 12771 -12772 12773 -12774 +v -12775 12776 -12777 -12778 -12779 -12780 -12781 -12782 -12783 -12784 -12785 +v -12786 -12787 12788 12789 12790 12791 -12792 -12793 -12794 -12795 -12796 +v -12797 -12798 -12799 -12800 -12801 -12802 -12803 -12804 12805 -12806 -12807 +v 12808 -12809 -12810 -12811 -12812 -12813 -12814 12815 12816 12817 -12818 +v -12819 -12820 -12821 -12822 -12823 -12824 -12825 -12826 -12827 -12828 -12829 +v -12830 -12831 -12832 -12833 -12834 -12835 -12836 -12837 -12838 -12839 -12840 +v -12841 12842 12843 -12844 -12845 -12846 -12847 -12848 12849 -12850 -12851 +v -12852 -12853 -12854 -12855 -12856 12857 12858 12859 -12860 -12861 -12862 +v 12863 -12864 -12865 12866 -12867 -12868 -12869 -12870 -12871 -12872 12873 +v -12874 -12875 -12876 -12877 12878 12879 -12880 -12881 12882 12883 -12884 +v -12885 -12886 -12887 -12888 -12889 -12890 12891 -12892 12893 12894 12895 +v 12896 -12897 -12898 12899 -12900 12901 -12902 -12903 -12904 -12905 -12906 +v -12907 -12908 12909 -12910 12911 -12912 -12913 -12914 12915 -12916 -12917 +v -12918 12919 12920 -12921 -12922 -12923 -12924 -12925 -12926 -12927 -12928 +v -12929 12930 -12931 -12932 12933 12934 -12935 12936 -12937 -12938 -12939 +v -12940 12941 -12942 -12943 -12944 -12945 -12946 -12947 -12948 -12949 -12950 +v 12951 -12952 12953 -12954 -12955 12956 12957 -12958 12959 12960 12961 -12962 +v 12963 -12964 -12965 12966 -12967 -12968 12969 -12970 12971 -12972 -12973 +v -12974 12975 -12976 12977 12978 12979 12980 -12981 -12982 12983 12984 12985 +v 12986 12987 -12988 -12989 12990 12991 12992 12993 12994 -12995 -12996 12997 +v 12998 12999 -13000 -13001 -13002 -13003 -13004 -13005 -13006 -13007 -13008 +v -13009 -13010 13011 13012 13013 13014 -13015 -13016 -13017 -13018 -13019 +v -13020 -13021 -13022 -13023 -13024 -13025 -13026 -13027 -13028 13029 -13030 +v -13031 13032 -13033 -13034 -13035 -13036 -13037 13038 13039 -13040 -13041 +v -13042 -13043 13044 13045 -13046 -13047 -13048 -13049 13050 -13051 -13052 +v -13053 -13054 -13055 -13056 -13057 -13058 13059 13060 13061 -13062 13063 +v 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 -13074 -13075 +v -13076 -13077 -13078 -13079 -13080 -13081 -13082 -13083 -13084 -13085 -13086 +v -13087 -13088 -13089 -13090 -13091 -13092 -13093 -13094 -13095 -13096 -13097 +v -13098 -13099 -13100 -13101 -13102 -13103 -13104 -13105 -13106 -13107 -13108 +v -13109 -13110 -13111 -13112 -13113 -13114 -13115 -13116 -13117 -13118 13119 +v -13120 -13121 13122 13123 -13124 -13125 -13126 13127 -13128 -13129 -13130 +v -13131 -13132 -13133 -13134 -13135 -13136 -13137 -13138 -13139 13140 -13141 +v -13142 -13143 -13144 -13145 -13146 -13147 -13148 -13149 -13150 -13151 -13152 +v 13153 13154 13155 -13156 -13157 -13158 -13159 -13160 13161 -13162 -13163 +v 13164 -13165 -13166 -13167 -13168 -13169 -13170 13171 -13172 -13173 -13174 +v -13175 -13176 -13177 -13178 -13179 -13180 -13181 -13182 -13183 -13184 -13185 +v -13186 -13187 -13188 -13189 -13190 -13191 -13192 -13193 -13194 -13195 -13196 +v -13197 -13198 -13199 -13200 -13201 -13202 -13203 -13204 -13205 -13206 -13207 +v -13208 -13209 -13210 -13211 -13212 -13213 -13214 -13215 -13216 -13217 -13218 +v -13219 -13220 13221 13222 13223 -13224 -13225 -13226 -13227 -13228 13229 +v 13230 13231 -13232 -13233 -13234 -13235 13236 -13237 -13238 -13239 -13240 +v -13241 13242 -13243 -13244 -13245 -13246 -13247 -13248 -13249 -13250 -13251 +v -13252 -13253 -13254 13255 13256 -13257 -13258 13259 13260 -13261 -13262 +v -13263 -13264 -13265 -13266 -13267 -13268 -13269 -13270 -13271 -13272 -13273 +v -13274 -13275 -13276 -13277 -13278 -13279 -13280 -13281 -13282 -13283 -13284 +v -13285 -13286 13287 -13288 -13289 -13290 -13291 -13292 -13293 -13294 -13295 +v -13296 13297 13298 13299 -13300 -13301 -13302 -13303 -13304 -13305 -13306 +v -13307 -13308 -13309 -13310 -13311 -13312 -13313 -13314 -13315 -13316 -13317 +v -13318 13319 13320 -13321 -13322 -13323 -13324 -13325 -13326 -13327 -13328 +v -13329 13330 -13331 -13332 -13333 -13334 -13335 -13336 -13337 -13338 -13339 +v 13340 13341 13342 -13343 -13344 13345 13346 13347 13348 13349 13350 13351 +v 13352 -13353 -13354 -13355 -13356 -13357 -13358 -13359 -13360 -13361 -13362 +v -13363 -13364 -13365 -13366 -13367 13368 13369 -13370 -13371 -13372 -13373 +v -13374 13375 -13376 -13377 -13378 -13379 -13380 -13381 -13382 -13383 -13384 +v -13385 -13386 -13387 13388 -13389 -13390 -13391 -13392 13393 13394 -13395 +v -13396 -13397 -13398 -13399 -13400 -13401 -13402 -13403 -13404 -13405 -13406 +v 13407 -13408 -13409 -13410 -13411 -13412 -13413 -13414 -13415 -13416 -13417 +v -13418 -13419 -13420 -13421 -13422 -13423 -13424 -13425 -13426 -13427 13428 +v -13429 -13430 -13431 -13432 13433 -13434 -13435 13436 -13437 -13438 -13439 +v -13440 -13441 -13442 -13443 -13444 -13445 -13446 -13447 -13448 -13449 -13450 +v -13451 -13452 -13453 -13454 -13455 -13456 13457 13458 -13459 -13460 -13461 +v -13462 -13463 13464 13465 13466 -13467 -13468 -13469 -13470 13471 -13472 +v -13473 -13474 -13475 -13476 13477 -13478 -13479 -13480 -13481 13482 -13483 +v 13484 -13485 -13486 13487 -13488 13489 -13490 -13491 13492 -13493 13494 13495 +v 13496 13497 -13498 -13499 13500 -13501 -13502 -13503 13504 -13505 13506 13507 +v 13508 13509 -13510 -13511 13512 -13513 -13514 13515 -13516 -13517 -13518 +v -13519 -13520 -13521 -13522 -13523 -13524 -13525 -13526 -13527 -13528 13529 +v 13530 13531 -13532 -13533 -13534 -13535 13536 -13537 -13538 13539 -13540 +v -13541 -13542 -13543 -13544 -13545 -13546 -13547 -13548 13549 13550 13551 +v 13552 -13553 13554 -13555 -13556 -13557 -13558 -13559 -13560 -13561 -13562 +v -13563 -13564 -13565 -13566 -13567 -13568 -13569 -13570 -13571 -13572 -13573 +v -13574 -13575 -13576 -13577 -13578 -13579 -13580 -13581 13582 -13583 13584 +v -13585 -13586 -13587 -13588 -13589 -13590 -13591 -13592 13593 13594 13595 +v 13596 -13597 -13598 13599 -13600 -13601 -13602 -13603 -13604 -13605 -13606 +v -13607 -13608 -13609 -13610 -13611 13612 13613 -13614 13615 -13616 -13617 +v -13618 -13619 -13620 13621 -13622 13623 -13624 -13625 -13626 13627 -13628 +v 13629 -13630 -13631 -13632 13633 -13634 13635 13636 13637 13638 -13639 -13640 +v 13641 13642 13643 -13644 -13645 -13646 -13647 -13648 -13649 -13650 -13651 +v -13652 -13653 -13654 13655 13656 13657 13658 -13659 -13660 13661 -13662 13663 +v -13664 -13665 -13666 -13667 -13668 -13669 -13670 -13671 -13672 -13673 -13674 +v -13675 -13676 -13677 -13678 13679 13680 -13681 -13682 -13683 -13684 -13685 +v -13686 -13687 -13688 -13689 -13690 13691 13692 13693 -13694 -13695 13696 +v -13697 -13698 -13699 -13700 -13701 -13702 -13703 -13704 -13705 -13706 -13707 +v -13708 -13709 -13710 13711 -13712 13713 -13714 -13715 13716 -13717 13718 +v -13719 -13720 -13721 13722 -13723 13724 13725 13726 13727 -13728 -13729 13730 +v 13731 13732 -13733 -13734 -13735 -13736 -13737 -13738 -13739 -13740 -13741 +v -13742 -13743 13744 13745 13746 13747 -13748 -13749 -13750 -13751 -13752 +v -13753 -13754 -13755 -13756 -13757 -13758 -13759 -13760 -13761 -13762 -13763 +v -13764 -13765 -13766 -13767 -13768 -13769 -13770 -13771 -13772 -13773 -13774 +v -13775 -13776 -13777 -13778 -13779 -13780 -13781 -13782 -13783 -13784 -13785 +v -13786 -13787 -13788 -13789 -13790 -13791 -13792 -13793 -13794 -13795 -13796 +v -13797 -13798 -13799 -13800 -13801 -13802 -13803 -13804 -13805 -13806 -13807 +v -13808 -13809 -13810 -13811 -13812 -13813 -13814 -13815 -13816 -13817 -13818 +v -13819 -13820 -13821 -13822 -13823 -13824 -13825 13826 -13827 -13828 -13829 +v -13830 -13831 -13832 -13833 -13834 -13835 -13836 -13837 -13838 -13839 -13840 +v -13841 -13842 -13843 -13844 -13845 -13846 -13847 -13848 -13849 -13850 -13851 +v -13852 -13853 13854 -13855 -13856 -13857 -13858 -13859 -13860 -13861 -13862 +v -13863 -13864 -13865 13866 -13867 -13868 -13869 -13870 -13871 -13872 13873 +v -13874 -13875 -13876 -13877 -13878 -13879 -13880 -13881 -13882 -13883 -13884 +v -13885 -13886 -13887 -13888 -13889 -13890 -13891 -13892 -13893 -13894 -13895 +v -13896 -13897 -13898 -13899 -13900 -13901 -13902 13903 -13904 -13905 -13906 +v -13907 -13908 -13909 -13910 -13911 -13912 -13913 -13914 -13915 13916 -13917 +v 13918 -13919 -13920 -13921 13922 -13923 13924 -13925 -13926 -13927 13928 +v -13929 13930 -13931 -13932 -13933 13934 -13935 13936 13937 13938 -13939 +v -13940 -13941 -13942 -13943 -13944 -13945 -13946 -13947 -13948 -13949 13950 +v 13951 13952 -13953 -13954 -13955 -13956 -13957 -13958 -13959 -13960 -13961 +v -13962 -13963 -13964 -13965 13966 -13967 -13968 13969 -13970 -13971 -13972 +v -13973 -13974 -13975 13976 13977 13978 -13979 -13980 -13981 -13982 -13983 +v -13984 -13985 -13986 -13987 -13988 -13989 -13990 -13991 -13992 -13993 -13994 +v -13995 -13996 -13997 -13998 -13999 -14000 14001 -14002 -14003 -14004 -14005 +v -14006 -14007 -14008 14009 -14010 14011 -14012 -14013 -14014 14015 -14016 +v 14017 -14018 -14019 14020 -14021 -14022 -14023 -14024 -14025 -14026 14027 +v 14028 14029 -14030 -14031 -14032 -14033 -14034 -14035 -14036 -14037 -14038 +v -14039 -14040 -14041 -14042 -14043 -14044 -14045 -14046 -14047 -14048 -14049 +v -14050 -14051 14052 -14053 -14054 -14055 -14056 -14057 -14058 -14059 14060 +v -14061 14062 -14063 -14064 -14065 14066 -14067 14068 -14069 -14070 14071 +v -14072 -14073 -14074 -14075 -14076 -14077 14078 14079 14080 -14081 -14082 +v -14083 -14084 -14085 -14086 -14087 -14088 -14089 -14090 -14091 -14092 -14093 +v -14094 -14095 -14096 -14097 -14098 -14099 -14100 -14101 -14102 14103 -14104 +v -14105 -14106 -14107 -14108 -14109 -14110 14111 -14112 14113 -14114 -14115 +v -14116 14117 -14118 14119 -14120 -14121 14122 -14123 -14124 -14125 -14126 +v -14127 -14128 14129 14130 14131 -14132 -14133 -14134 -14135 -14136 -14137 +v -14138 -14139 -14140 -14141 -14142 -14143 -14144 -14145 -14146 -14147 -14148 +v -14149 -14150 -14151 -14152 -14153 -14154 -14155 -14156 -14157 -14158 -14159 +v -14160 -14161 -14162 -14163 -14164 -14165 -14166 -14167 -14168 -14169 -14170 +v -14171 -14172 -14173 -14174 -14175 -14176 -14177 -14178 -14179 -14180 -14181 +v -14182 -14183 -14184 -14185 -14186 -14187 -14188 -14189 -14190 -14191 -14192 +v -14193 -14194 -14195 -14196 -14197 -14198 -14199 -14200 -14201 -14202 -14203 +v -14204 -14205 -14206 -14207 -14208 -14209 -14210 -14211 -14212 -14213 -14214 +v -14215 -14216 -14217 -14218 -14219 -14220 -14221 -14222 -14223 -14224 -14225 +v -14226 -14227 -14228 -14229 14230 -14231 -14232 -14233 -14234 -14235 -14236 +v -14237 -14238 -14239 -14240 -14241 -14242 -14243 -14244 -14245 -14246 -14247 +v -14248 -14249 -14250 -14251 -14252 -14253 -14254 -14255 -14256 -14257 -14258 +v -14259 -14260 -14261 -14262 -14263 -14264 -14265 -14266 -14267 -14268 -14269 +v -14270 -14271 -14272 -14273 -14274 -14275 -14276 -14277 -14278 -14279 -14280 +v -14281 -14282 -14283 -14284 -14285 -14286 -14287 -14288 -14289 -14290 -14291 +v -14292 -14293 -14294 -14295 -14296 -14297 -14298 -14299 -14300 -14301 -14302 +v -14303 14304 -14305 14306 -14307 -14308 -14309 14310 -14311 14312 -14313 +v -14314 -14315 -14316 14317 -14318 14319 -14320 -14321 -14322 -14323 14324 +v -14325 14326 -14327 -14328 14329 -14330 -14331 -14332 -14333 -14334 -14335 +v -14336 -14337 -14338 -14339 14340 14341 14342 -14343 -14344 -14345 -14346 +v -14347 -14348 -14349 -14350 -14351 -14352 -14353 -14354 -14355 -14356 -14357 +v -14358 -14359 -14360 -14361 -14362 -14363 -14364 14365 -14366 -14367 -14368 +v -14369 -14370 -14371 -14372 14373 -14374 14375 -14376 -14377 -14378 14379 +v -14380 14381 -14382 -14383 14384 -14385 -14386 -14387 -14388 -14389 -14390 +v 14391 14392 14393 -14394 -14395 -14396 -14397 -14398 14399 14400 -14401 +v -14402 -14403 -14404 14405 -14406 -14407 -14408 -14409 -14410 -14411 -14412 +v -14413 -14414 -14415 -14416 -14417 -14418 -14419 14420 14421 -14422 -14423 +v -14424 -14425 -14426 -14427 -14428 -14429 -14430 -14431 -14432 -14433 -14434 +v -14435 14436 14437 -14438 14439 14440 14441 14442 14443 -14444 -14445 -14446 +v -14447 -14448 -14449 14450 14451 14452 -14453 -14454 -14455 -14456 14457 +v -14458 -14459 -14460 -14461 -14462 14463 14464 14465 14466 14467 -14468 +v -14469 -14470 14471 -14472 -14473 -14474 -14475 14476 -14477 -14478 -14479 +v -14480 -14481 -14482 -14483 -14484 14485 14486 -14487 -14488 -14489 14490 +v -14491 -14492 -14493 -14494 14495 14496 14497 14498 -14499 14500 14501 14502 +v -14503 -14504 -14505 -14506 14507 14508 -14509 -14510 -14511 -14512 14513 +v -14514 -14515 -14516 -14517 14518 14519 14520 14521 -14522 -14523 -14524 +v -14525 -14526 14527 -14528 -14529 -14530 -14531 14532 14533 14534 14535 14536 +v -14537 -14538 -14539 14540 -14541 14542 -14543 14544 -14545 14546 -14547 +v -14548 14549 -14550 -14551 -14552 -14553 14554 -14555 14556 -14557 -14558 +v -14559 -14560 14561 -14562 14563 14564 14565 -14566 -14567 -14568 -14569 +v -14570 -14571 -14572 -14573 -14574 -14575 -14576 14577 14578 14579 -14580 +v -14581 -14582 -14583 -14584 -14585 -14586 -14587 -14588 -14589 -14590 -14591 +v -14592 -14593 -14594 -14595 -14596 -14597 -14598 -14599 -14600 -14601 -14602 +v -14603 -14604 -14605 -14606 -14607 -14608 14609 -14610 14611 -14612 -14613 +v -14614 14615 -14616 14617 -14618 -14619 14620 -14621 -14622 -14623 -14624 +v -14625 -14626 14627 14628 14629 14630 -14631 -14632 -14633 -14634 -14635 +v -14636 -14637 -14638 -14639 -14640 -14641 -14642 -14643 -14644 -14645 -14646 +v -14647 -14648 -14649 -14650 -14651 -14652 -14653 -14654 -14655 -14656 -14657 +v -14658 -14659 14660 -14661 14662 -14663 -14664 -14665 14666 -14667 14668 +v -14669 -14670 14671 -14672 -14673 -14674 -14675 -14676 -14677 14678 14679 +v 14680 14681 -14682 -14683 -14684 -14685 -14686 -14687 -14688 -14689 -14690 +v -14691 -14692 -14693 -14694 -14695 -14696 -14697 -14698 -14699 -14700 -14701 +v -14702 -14703 -14704 -14705 -14706 -14707 -14708 -14709 -14710 14711 -14712 +v 14713 -14714 -14715 -14716 14717 -14718 14719 -14720 -14721 14722 -14723 +v -14724 -14725 -14726 -14727 -14728 14729 14730 14731 14732 -14733 -14734 +v -14735 -14736 -14737 -14738 -14739 -14740 -14741 -14742 -14743 -14744 -14745 +v -14746 -14747 -14748 -14749 -14750 -14751 -14752 -14753 -14754 -14755 -14756 +v -14757 -14758 -14759 -14760 -14761 -14762 -14763 -14764 -14765 -14766 -14767 +v -14768 -14769 -14770 -14771 -14772 -14773 -14774 -14775 -14776 -14777 -14778 +v -14779 -14780 -14781 -14782 -14783 -14784 -14785 -14786 -14787 -14788 -14789 +v -14790 -14791 -14792 -14793 -14794 -14795 -14796 -14797 -14798 -14799 -14800 +v -14801 -14802 -14803 -14804 -14805 -14806 -14807 -14808 -14809 -14810 -14811 +v -14812 -14813 -14814 -14815 -14816 -14817 -14818 -14819 -14820 -14821 -14822 +v -14823 -14824 -14825 -14826 -14827 -14828 -14829 -14830 -14831 -14832 -14833 +v -14834 -14835 -14836 -14837 -14838 -14839 -14840 -14841 -14842 -14843 -14844 +v -14845 -14846 -14847 -14848 -14849 -14850 -14851 -14852 -14853 -14854 -14855 +v -14856 -14857 -14858 -14859 -14860 -14861 -14862 -14863 -14864 -14865 -14866 +v -14867 -14868 -14869 -14870 -14871 -14872 -14873 -14874 -14875 -14876 -14877 +v -14878 -14879 -14880 -14881 -14882 -14883 -14884 -14885 -14886 -14887 -14888 +v -14889 -14890 -14891 -14892 -14893 -14894 -14895 -14896 -14897 -14898 -14899 +v -14900 -14901 -14902 -14903 14904 -14905 14906 -14907 -14908 -14909 14910 +v -14911 14912 -14913 -14914 -14915 -14916 14917 -14918 14919 -14920 -14921 +v -14922 -14923 14924 -14925 14926 -14927 -14928 14929 -14930 -14931 -14932 +v -14933 -14934 -14935 -14936 -14937 -14938 -14939 14940 14941 14942 14943 +v -14944 -14945 -14946 -14947 -14948 -14949 -14950 -14951 -14952 -14953 -14954 +v -14955 -14956 -14957 -14958 -14959 -14960 -14961 -14962 -14963 -14964 -14965 +v -14966 -14967 -14968 -14969 -14970 -14971 -14972 14973 -14974 14975 -14976 +v -14977 -14978 14979 -14980 14981 -14982 -14983 14984 -14985 -14986 -14987 +v -14988 -14989 -14990 14991 14992 14993 14994 -14995 14996 -14997 14998 -14999 +v 15000 15001 -15002 -15003 -15004 -15005 -15006 -15007 -15008 -15009 -15010 +v -15011 -15012 -15013 -15014 -15015 -15016 -15017 -15018 -15019 -15020 -15021 +v -15022 -15023 -15024 -15025 -15026 -15027 -15028 -15029 -15030 -15031 -15032 +v -15033 -15034 -15035 -15036 -15037 -15038 -15039 -15040 -15041 -15042 -15043 +v -15044 -15045 -15046 -15047 -15048 -15049 -15050 -15051 -15052 -15053 -15054 +v -15055 -15056 -15057 -15058 -15059 -15060 -15061 -15062 -15063 -15064 -15065 +v -15066 -15067 -15068 -15069 -15070 -15071 -15072 -15073 -15074 -15075 -15076 +v -15077 -15078 -15079 -15080 -15081 -15082 -15083 -15084 -15085 -15086 -15087 +v -15088 -15089 -15090 -15091 -15092 -15093 -15094 -15095 -15096 -15097 -15098 +v -15099 -15100 -15101 -15102 -15103 -15104 -15105 -15106 -15107 -15108 -15109 +v -15110 -15111 -15112 -15113 -15114 -15115 -15116 -15117 -15118 -15119 -15120 +v -15121 -15122 -15123 -15124 -15125 -15126 -15127 -15128 -15129 -15130 -15131 +v -15132 -15133 -15134 -15135 -15136 -15137 -15138 -15139 -15140 -15141 -15142 +v -15143 -15144 -15145 -15146 -15147 -15148 -15149 -15150 -15151 -15152 -15153 +v -15154 -15155 -15156 -15157 -15158 -15159 -15160 -15161 -15162 -15163 -15164 +v -15165 -15166 -15167 -15168 -15169 -15170 -15171 -15172 -15173 -15174 -15175 +v -15176 -15177 -15178 -15179 -15180 -15181 -15182 -15183 -15184 -15185 -15186 +v -15187 -15188 -15189 -15190 -15191 -15192 -15193 -15194 -15195 -15196 -15197 +v -15198 -15199 -15200 -15201 -15202 -15203 -15204 -15205 -15206 -15207 -15208 +v -15209 -15210 -15211 -15212 -15213 -15214 -15215 -15216 -15217 -15218 -15219 +v -15220 -15221 -15222 -15223 -15224 -15225 -15226 -15227 -15228 -15229 -15230 +v -15231 -15232 -15233 -15234 -15235 -15236 -15237 -15238 -15239 -15240 -15241 +v -15242 -15243 -15244 -15245 -15246 -15247 -15248 -15249 -15250 -15251 -15252 +v -15253 -15254 -15255 -15256 -15257 -15258 -15259 -15260 -15261 -15262 -15263 +v -15264 -15265 -15266 -15267 -15268 -15269 -15270 -15271 -15272 -15273 -15274 +v -15275 -15276 -15277 -15278 -15279 -15280 -15281 -15282 -15283 -15284 -15285 +v -15286 -15287 -15288 -15289 -15290 -15291 -15292 -15293 -15294 -15295 -15296 +v -15297 -15298 -15299 -15300 -15301 -15302 -15303 -15304 -15305 -15306 -15307 +v -15308 -15309 -15310 -15311 -15312 -15313 -15314 -15315 -15316 -15317 -15318 +v -15319 -15320 -15321 -15322 -15323 -15324 -15325 -15326 -15327 -15328 -15329 +v -15330 -15331 -15332 -15333 -15334 -15335 -15336 -15337 -15338 -15339 -15340 +v -15341 -15342 -15343 -15344 -15345 -15346 -15347 -15348 -15349 -15350 -15351 +v -15352 -15353 -15354 -15355 -15356 -15357 -15358 -15359 -15360 -15361 -15362 +v -15363 -15364 -15365 -15366 -15367 -15368 -15369 -15370 -15371 -15372 -15373 +v -15374 -15375 -15376 -15377 -15378 -15379 -15380 -15381 -15382 -15383 -15384 +v 15385 -15386 15387 -15388 -15389 -15390 15391 -15392 15393 -15394 -15395 +v -15396 -15397 15398 -15399 15400 -15401 -15402 -15403 -15404 15405 -15406 +v 15407 -15408 -15409 -15410 -15411 15412 -15413 15414 -15415 -15416 15417 +v -15418 15419 -15420 -15421 -15422 -15423 -15424 -15425 -15426 -15427 -15428 +v -15429 -15430 -15431 -15432 -15433 15434 15435 15436 15437 15438 -15439 +v -15440 -15441 -15442 -15443 -15444 15445 -15446 -15447 -15448 -15449 -15450 +v -15451 -15452 -15453 -15454 -15455 -15456 -15457 -15458 -15459 -15460 -15461 +v -15462 -15463 -15464 -15465 -15466 -15467 -15468 -15469 -15470 -15471 -15472 +v -15473 -15474 -15475 -15476 -15477 -15478 -15479 -15480 -15481 -15482 -15483 +v -15484 -15485 -15486 -15487 -15488 -15489 -15490 -15491 -15492 -15493 -15494 +v -15495 -15496 -15497 -15498 -15499 -15500 -15501 -15502 -15503 -15504 -15505 +v -15506 -15507 -15508 -15509 -15510 -15511 -15512 -15513 -15514 -15515 -15516 +v -15517 -15518 -15519 -15520 -15521 -15522 -15523 -15524 -15525 -15526 -15527 +v -15528 -15529 -15530 -15531 -15532 -15533 -15534 -15535 -15536 -15537 -15538 +v -15539 -15540 -15541 -15542 -15543 -15544 -15545 -15546 -15547 -15548 -15549 +v -15550 -15551 -15552 -15553 -15554 -15555 -15556 -15557 -15558 -15559 -15560 +v -15561 -15562 -15563 -15564 -15565 15566 -15567 15568 -15569 -15570 -15571 +v -15572 15573 -15574 15575 -15576 -15577 -15578 -15579 15580 -15581 15582 +v -15583 -15584 -15585 -15586 15587 -15588 15589 -15590 -15591 15592 -15593 +v 15594 -15595 -15596 15597 -15598 -15599 -15600 -15601 -15602 -15603 -15604 +v -15605 -15606 -15607 -15608 -15609 15610 15611 15612 15613 -15614 -15615 +v -15616 -15617 -15618 -15619 -15620 -15621 -15622 -15623 -15624 -15625 -15626 +v -15627 -15628 -15629 -15630 -15631 -15632 -15633 -15634 -15635 -15636 -15637 +v -15638 -15639 -15640 -15641 -15642 -15643 -15644 -15645 -15646 -15647 -15648 +v -15649 -15650 -15651 -15652 -15653 -15654 -15655 -15656 -15657 -15658 -15659 +v -15660 -15661 -15662 -15663 -15664 15665 -15666 -15667 15668 -15669 -15670 +v -15671 15672 -15673 -15674 -15675 15676 -15677 -15678 -15679 -15680 -15681 +v -15682 -15683 -15684 -15685 -15686 -15687 15688 -15689 15690 15691 15692 +v 15693 -15694 -15695 -15696 -15697 -15698 -15699 -15700 -15701 -15702 -15703 +v -15704 -15705 -15706 -15707 -15708 -15709 -15710 -15711 -15712 -15713 -15714 +v -15715 -15716 -15717 -15718 -15719 -15720 -15721 -15722 -15723 -15724 -15725 +v -15726 -15727 -15728 -15729 -15730 -15731 -15732 -15733 -15734 -15735 -15736 +v -15737 -15738 -15739 -15740 -15741 -15742 -15743 -15744 -15745 -15746 -15747 +v -15748 -15749 -15750 -15751 -15752 -15753 -15754 -15755 -15756 -15757 -15758 +v -15759 -15760 -15761 -15762 -15763 -15764 -15765 -15766 -15767 -15768 -15769 +v -15770 -15771 -15772 -15773 -15774 -15775 -15776 -15777 -15778 -15779 -15780 +v -15781 -15782 -15783 -15784 -15785 -15786 -15787 -15788 -15789 -15790 -15791 +v -15792 -15793 -15794 -15795 -15796 -15797 -15798 -15799 -15800 -15801 -15802 +v -15803 -15804 -15805 -15806 -15807 -15808 -15809 -15810 -15811 -15812 -15813 +v -15814 -15815 -15816 -15817 -15818 -15819 -15820 -15821 -15822 -15823 -15824 +v -15825 -15826 -15827 -15828 -15829 -15830 -15831 -15832 -15833 -15834 -15835 +v -15836 -15837 -15838 -15839 -15840 -15841 -15842 -15843 -15844 -15845 -15846 +v -15847 -15848 -15849 -15850 -15851 -15852 -15853 -15854 -15855 -15856 -15857 +v -15858 15859 -15860 15861 -15862 -15863 15864 -15865 15866 -15867 -15868 +v 15869 -15870 15871 -15872 -15873 -15874 15875 -15876 15877 -15878 -15879 +v -15880 15881 -15882 15883 -15884 -15885 15886 -15887 -15888 -15889 -15890 +v -15891 -15892 -15893 -15894 -15895 -15896 -15897 -15898 15899 15900 15901 +v 15902 -15903 -15904 -15905 -15906 -15907 -15908 -15909 -15910 -15911 -15912 +v -15913 -15914 -15915 15916 -15917 -15918 15919 -15920 -15921 -15922 -15923 +v -15924 -15925 15926 15927 15928 -15929 -15930 -15931 -15932 -15933 -15934 +v -15935 15936 -15937 -15938 -15939 -15940 -15941 -15942 -15943 -15944 -15945 +v -15946 -15947 -15948 -15949 -15950 -15951 -15952 -15953 -15954 -15955 -15956 +v -15957 -15958 -15959 -15960 -15961 -15962 -15963 -15964 -15965 -15966 -15967 +v -15968 -15969 -15970 -15971 -15972 15973 15974 -15975 -15976 15977 15978 +v 15979 15980 15981 -15982 -15983 -15984 -15985 -15986 -15987 -15988 -15989 +v -15990 -15991 15992 -15993 -15994 -15995 -15996 -15997 -15998 -15999 -16000 +v -16001 -16002 16003 16004 -16005 -16006 16007 16008 16009 16010 -16011 -16012 +v 16013 -16014 -16015 -16016 -16017 -16018 -16019 -16020 -16021 -16022 -16023 +v -16024 -16025 -16026 -16027 -16028 -16029 -16030 -16031 -16032 -16033 16034 +v 16035 16036 16037 -16038 -16039 -16040 -16041 -16042 16043 16044 -16045 +v -16046 16047 16048 16049 -16050 -16051 -16052 -16053 -16054 -16055 -16056 +v 16057 -16058 -16059 -16060 -16061 -16062 -16063 -16064 -16065 -16066 16067 +v 16068 16069 -16070 -16071 16072 -16073 -16074 -16075 16076 -16077 -16078 +v -16079 16080 -16081 -16082 -16083 -16084 -16085 16086 -16087 16088 -16089 +v -16090 -16091 16092 -16093 16094 16095 16096 16097 16098 -16099 -16100 16101 +v -16102 16103 16104 16105 -16106 -16107 16108 -16109 -16110 16111 -16112 +v -16113 -16114 -16115 -16116 -16117 -16118 -16119 -16120 -16121 16122 16123 +v 16124 16125 -16126 -16127 -16128 -16129 -16130 -16131 -16132 -16133 -16134 +v -16135 -16136 -16137 -16138 -16139 16140 -16141 -16142 16143 -16144 -16145 +v -16146 -16147 -16148 16149 16150 -16151 -16152 -16153 -16154 16155 16156 +v -16157 -16158 -16159 -16160 16161 -16162 -16163 -16164 -16165 -16166 -16167 +v -16168 -16169 16170 16171 16172 -16173 16174 16175 16176 16177 16178 16179 +v 16180 16181 16182 16183 16184 -16185 -16186 -16187 -16188 -16189 -16190 +v -16191 -16192 -16193 -16194 -16195 -16196 -16197 -16198 -16199 -16200 -16201 +v -16202 -16203 -16204 -16205 -16206 -16207 -16208 -16209 -16210 -16211 -16212 +v -16213 -16214 -16215 -16216 -16217 -16218 -16219 -16220 -16221 -16222 -16223 +v -16224 -16225 -16226 -16227 -16228 -16229 16230 -16231 -16232 16233 16234 +v -16235 -16236 -16237 16238 -16239 -16240 -16241 -16242 -16243 -16244 -16245 +v -16246 -16247 -16248 -16249 -16250 16251 -16252 -16253 -16254 -16255 -16256 +v -16257 -16258 -16259 -16260 -16261 -16262 -16263 16264 16265 16266 -16267 +v -16268 -16269 -16270 -16271 16272 -16273 -16274 16275 -16276 -16277 -16278 +v -16279 -16280 -16281 16282 -16283 -16284 -16285 -16286 -16287 -16288 -16289 +v -16290 -16291 -16292 -16293 -16294 -16295 -16296 -16297 -16298 -16299 -16300 +v -16301 -16302 -16303 -16304 -16305 -16306 -16307 -16308 -16309 -16310 -16311 +v -16312 -16313 -16314 -16315 -16316 -16317 -16318 -16319 -16320 -16321 -16322 +v -16323 -16324 -16325 -16326 -16327 -16328 -16329 -16330 -16331 16332 16333 +v 16334 -16335 -16336 -16337 -16338 -16339 16340 16341 16342 -16343 -16344 +v -16345 -16346 16347 -16348 -16349 -16350 -16351 -16352 16353 -16354 -16355 +v -16356 -16357 -16358 -16359 -16360 -16361 -16362 -16363 -16364 -16365 -16366 +v -16367 -16368 -16369 -16370 -16371 -16372 -16373 -16374 -16375 -16376 -16377 +v -16378 16379 -16380 -16381 -16382 -16383 -16384 -16385 -16386 -16387 -16388 +v 16389 16390 16391 -16392 -16393 -16394 -16395 -16396 -16397 -16398 -16399 +v -16400 -16401 -16402 -16403 -16404 -16405 -16406 -16407 -16408 -16409 -16410 +v 16411 16412 -16413 -16414 -16415 -16416 -16417 -16418 -16419 -16420 -16421 +v 16422 -16423 -16424 -16425 -16426 -16427 -16428 -16429 -16430 -16431 16432 +v 16433 -16434 -16435 16436 16437 16438 16439 16440 16441 16442 -16443 -16444 +v -16445 -16446 -16447 -16448 -16449 -16450 -16451 -16452 -16453 -16454 -16455 +v -16456 -16457 16458 16459 -16460 -16461 -16462 -16463 -16464 16465 -16466 +v -16467 -16468 -16469 -16470 -16471 -16472 -16473 -16474 -16475 -16476 -16477 +v 16478 -16479 -16480 -16481 -16482 16483 16484 -16485 -16486 -16487 -16488 +v -16489 -16490 -16491 -16492 -16493 -16494 -16495 -16496 16497 -16498 -16499 +v -16500 -16501 -16502 -16503 -16504 -16505 -16506 -16507 -16508 -16509 -16510 +v -16511 -16512 -16513 -16514 -16515 -16516 -16517 16518 -16519 -16520 -16521 +v -16522 16523 -16524 -16525 16526 -16527 -16528 -16529 -16530 -16531 -16532 +v -16533 -16534 -16535 -16536 -16537 -16538 -16539 -16540 -16541 -16542 -16543 +v -16544 -16545 -16546 16547 16548 -16549 -16550 -16551 -16552 -16553 16554 +v 16555 16556 -16557 -16558 -16559 -16560 16561 -16562 -16563 -16564 -16565 +v -16566 16567 -16568 -16569 -16570 -16571 16572 -16573 16574 -16575 -16576 +v -16577 16578 -16579 16580 -16581 -16582 -16583 16584 -16585 16586 16587 16588 +v 16589 16590 -16591 -16592 16593 -16594 -16595 -16596 -16597 16598 -16599 +v 16600 16601 16602 16603 16604 -16605 -16606 16607 -16608 -16609 16610 -16611 +v -16612 -16613 -16614 -16615 -16616 -16617 -16618 -16619 -16620 -16621 -16622 +v -16623 16624 16625 16626 -16627 -16628 -16629 -16630 16631 -16632 -16633 +v 16634 -16635 -16636 -16637 -16638 -16639 -16640 -16641 -16642 -16643 16644 +v 16645 16646 16647 -16648 16649 -16650 -16651 -16652 -16653 -16654 -16655 +v -16656 -16657 -16658 -16659 -16660 -16661 -16662 -16663 -16664 -16665 -16666 +v -16667 -16668 -16669 -16670 -16671 -16672 -16673 -16674 -16675 -16676 16677 +v -16678 16679 -16680 -16681 -16682 -16683 -16684 -16685 -16686 -16687 16688 +v 16689 16690 16691 -16692 -16693 16694 -16695 -16696 -16697 -16698 -16699 +v -16700 -16701 -16702 -16703 -16704 -16705 -16706 16707 16708 -16709 16710 +v -16711 -16712 -16713 -16714 -16715 16716 -16717 16718 -16719 -16720 -16721 +v 16722 -16723 16724 -16725 -16726 -16727 16728 -16729 16730 16731 16732 16733 +v -16734 -16735 16736 16737 16738 -16739 -16740 -16741 -16742 -16743 -16744 +v -16745 -16746 -16747 -16748 -16749 16750 16751 16752 16753 -16754 -16755 +v 16756 -16757 16758 -16759 -16760 -16761 -16762 -16763 -16764 -16765 -16766 +v -16767 -16768 -16769 -16770 -16771 -16772 -16773 16774 16775 -16776 -16777 +v -16778 -16779 -16780 -16781 -16782 -16783 -16784 -16785 16786 16787 16788 +v -16789 -16790 16791 -16792 -16793 -16794 -16795 -16796 -16797 -16798 -16799 +v -16800 -16801 -16802 -16803 -16804 -16805 16806 -16807 16808 -16809 -16810 +v 16811 -16812 16813 -16814 -16815 -16816 16817 -16818 16819 16820 16821 16822 +v -16823 -16824 16825 16826 16827 -16828 -16829 -16830 -16831 -16832 -16833 +v -16834 -16835 -16836 -16837 -16838 16839 16840 16841 16842 -16843 -16844 +v -16845 -16846 -16847 -16848 -16849 -16850 -16851 -16852 -16853 -16854 -16855 +v -16856 -16857 -16858 -16859 -16860 -16861 -16862 -16863 -16864 -16865 -16866 +v -16867 -16868 -16869 -16870 -16871 -16872 -16873 -16874 -16875 -16876 -16877 +v -16878 -16879 -16880 -16881 -16882 -16883 -16884 -16885 -16886 -16887 -16888 +v -16889 -16890 -16891 -16892 -16893 -16894 -16895 -16896 -16897 -16898 -16899 +v -16900 -16901 -16902 -16903 -16904 -16905 -16906 -16907 -16908 -16909 -16910 +v -16911 -16912 -16913 -16914 -16915 -16916 -16917 -16918 -16919 -16920 16921 +v -16922 -16923 -16924 -16925 -16926 -16927 -16928 -16929 -16930 -16931 -16932 +v -16933 -16934 -16935 -16936 -16937 -16938 -16939 -16940 -16941 -16942 -16943 +v -16944 -16945 -16946 -16947 -16948 -16949 -16950 -16951 -16952 -16953 -16954 +v -16955 -16956 -16957 -16958 -16959 -16960 16961 -16962 -16963 -16964 -16965 +v -16966 -16967 -16968 -16969 -16970 -16971 -16972 -16973 -16974 -16975 -16976 +v -16977 -16978 -16979 -16980 -16981 -16982 -16983 -16984 -16985 -16986 -16987 +v -16988 -16989 16990 -16991 -16992 -16993 -16994 -16995 -16996 -16997 -16998 +v -16999 -17000 -17001 17002 -17003 -17004 -17005 -17006 -17007 -17008 17009 +v -17010 17011 -17012 -17013 17014 -17015 17016 -17017 -17018 17019 -17020 +v 17021 -17022 -17023 -17024 17025 -17026 17027 -17028 -17029 -17030 17031 +v -17032 17033 17034 17035 -17036 -17037 -17038 -17039 -17040 -17041 -17042 +v -17043 -17044 -17045 -17046 -17047 17048 17049 17050 -17051 -17052 -17053 +v -17054 -17055 -17056 -17057 -17058 -17059 -17060 -17061 -17062 -17063 17064 +v -17065 -17066 17067 -17068 -17069 -17070 -17071 -17072 -17073 17074 17075 +v 17076 -17077 -17078 -17079 -17080 -17081 -17082 -17083 -17084 -17085 -17086 +v -17087 -17088 -17089 -17090 -17091 -17092 -17093 -17094 -17095 -17096 -17097 +v -17098 17099 -17100 -17101 -17102 -17103 -17104 -17105 -17106 17107 -17108 +v 17109 -17110 -17111 -17112 17113 -17114 17115 -17116 -17117 17118 -17119 +v -17120 -17121 -17122 -17123 -17124 17125 17126 17127 -17128 -17129 -17130 +v -17131 -17132 -17133 -17134 -17135 -17136 -17137 -17138 -17139 -17140 -17141 +v -17142 -17143 -17144 -17145 -17146 -17147 -17148 -17149 17150 -17151 -17152 +v -17153 -17154 -17155 -17156 -17157 17158 -17159 17160 -17161 -17162 -17163 +v 17164 -17165 17166 -17167 -17168 17169 -17170 -17171 -17172 -17173 -17174 +v -17175 17176 17177 17178 -17179 -17180 -17181 -17182 -17183 -17184 -17185 +v -17186 -17187 -17188 -17189 -17190 -17191 -17192 -17193 -17194 -17195 -17196 +v -17197 -17198 -17199 -17200 17201 -17202 -17203 -17204 -17205 -17206 -17207 +v -17208 17209 -17210 17211 -17212 -17213 -17214 17215 -17216 17217 -17218 +v -17219 17220 -17221 -17222 -17223 -17224 -17225 -17226 17227 17228 17229 +v -17230 -17231 -17232 -17233 -17234 -17235 -17236 -17237 -17238 -17239 -17240 +v -17241 -17242 -17243 -17244 -17245 -17246 -17247 -17248 -17249 -17250 -17251 +v -17252 -17253 -17254 -17255 -17256 -17257 -17258 -17259 -17260 -17261 -17262 +v -17263 -17264 -17265 -17266 -17267 -17268 -17269 -17270 -17271 -17272 -17273 +v -17274 -17275 -17276 -17277 -17278 -17279 -17280 -17281 -17282 -17283 -17284 +v -17285 -17286 -17287 -17288 -17289 -17290 -17291 -17292 -17293 -17294 -17295 +v -17296 -17297 -17298 -17299 -17300 -17301 -17302 -17303 -17304 -17305 -17306 +v -17307 -17308 -17309 -17310 -17311 -17312 -17313 -17314 -17315 -17316 -17317 +v -17318 -17319 -17320 -17321 -17322 -17323 -17324 -17325 -17326 -17327 17328 +v -17329 -17330 -17331 -17332 -17333 -17334 -17335 -17336 -17337 -17338 -17339 +v -17340 -17341 -17342 -17343 -17344 -17345 -17346 -17347 -17348 -17349 -17350 +v -17351 -17352 -17353 -17354 -17355 -17356 -17357 -17358 -17359 -17360 -17361 +v -17362 -17363 -17364 -17365 -17366 -17367 -17368 -17369 -17370 -17371 -17372 +v -17373 -17374 -17375 -17376 -17377 -17378 -17379 -17380 -17381 -17382 -17383 +v -17384 -17385 -17386 -17387 -17388 -17389 -17390 -17391 -17392 -17393 -17394 +v -17395 -17396 -17397 -17398 -17399 -17400 -17401 17402 -17403 17404 -17405 +v -17406 -17407 17408 -17409 17410 -17411 -17412 -17413 -17414 17415 -17416 +v 17417 -17418 -17419 -17420 -17421 17422 -17423 17424 -17425 -17426 17427 +v -17428 -17429 -17430 -17431 -17432 -17433 -17434 -17435 -17436 -17437 17438 +v 17439 17440 -17441 -17442 -17443 -17444 -17445 -17446 -17447 -17448 -17449 +v -17450 -17451 -17452 -17453 -17454 -17455 -17456 -17457 -17458 -17459 -17460 +v -17461 -17462 17463 -17464 -17465 -17466 -17467 -17468 -17469 -17470 17471 +v -17472 17473 -17474 -17475 -17476 17477 -17478 17479 -17480 -17481 17482 +v -17483 -17484 -17485 -17486 -17487 -17488 17489 17490 17491 -17492 -17493 +v -17494 -17495 -17496 17497 17498 17499 -17500 -17501 -17502 17503 -17504 +v -17505 -17506 -17507 -17508 -17509 -17510 -17511 -17512 -17513 -17514 -17515 +v -17516 -17517 17518 17519 -17520 -17521 -17522 -17523 -17524 -17525 -17526 +v -17527 -17528 -17529 -17530 17531 17532 17533 -17534 17535 -17536 -17537 +v 17538 -17539 17540 -17541 -17542 -17543 -17544 -17545 -17546 17547 17548 +v 17549 17550 17551 17552 17553 17554 -17555 -17556 -17557 17558 17559 17560 +v 17561 17562 17563 17564 17565 -17566 -17567 -17568 17569 -17570 -17571 -17572 +v -17573 17574 -17575 -17576 -17577 -17578 -17579 -17580 -17581 -17582 17583 +v 17584 17585 17586 17587 17588 17589 -17590 -17591 17592 17593 -17594 17595 +v -17596 -17597 17598 -17599 -17600 -17601 -17602 -17603 -17604 17605 17606 +v -17607 17608 -17609 -17610 17611 -17612 -17613 -17614 -17615 17616 17617 +v 17618 17619 17620 17621 17622 17623 -17624 -17625 -17626 17627 17628 17629 +v 17630 17631 17632 17633 17634 -17635 -17636 -17637 17638 -17639 17640 -17641 +v 17642 -17643 17644 -17645 -17646 17647 -17648 17649 -17650 17651 -17652 +v -17653 17654 -17655 -17656 -17657 -17658 17659 -17660 17661 -17662 -17663 +v 17664 -17665 -17666 -17667 -17668 -17669 -17670 -17671 -17672 -17673 -17674 +v 17675 17676 17677 17678 17679 17680 17681 17682 17683 17684 17685 -17686 +v -17687 -17688 -17689 17690 -17691 -17692 17693 -17694 -17695 17696 -17697 +v 17698 -17699 -17700 17701 -17702 -17703 -17704 -17705 -17706 17707 17708 +v 17709 17710 -17711 -17712 17713 -17714 -17715 17716 17717 17718 17719 -17720 +v -17721 -17722 -17723 -17724 -17725 -17726 -17727 -17728 -17729 -17730 -17731 +v -17732 -17733 -17734 -17735 -17736 -17737 17738 -17739 17740 -17741 -17742 +v -17743 17744 -17745 17746 -17747 -17748 17749 -17750 -17751 -17752 -17753 +v -17754 -17755 17756 17757 17758 17759 -17760 -17761 -17762 -17763 -17764 +v -17765 -17766 -17767 -17768 -17769 -17770 -17771 -17772 -17773 -17774 -17775 +v 17776 -17777 17778 -17779 -17780 -17781 17782 -17783 17784 -17785 -17786 +v 17787 -17788 -17789 -17790 -17791 -17792 -17793 17794 17795 17796 17797 +v -17798 -17799 -17800 -17801 -17802 -17803 -17804 -17805 -17806 -17807 -17808 +v -17809 -17810 -17811 -17812 -17813 17814 -17815 17816 -17817 -17818 -17819 +v 17820 -17821 17822 -17823 -17824 17825 -17826 -17827 -17828 -17829 -17830 +v -17831 17832 17833 17834 17835 -17836 -17837 -17838 -17839 17840 17841 17842 +v 17843 -17844 -17845 -17846 -17847 -17848 -17849 -17850 -17851 -17852 -17853 +v -17854 -17855 -17856 -17857 -17858 -17859 -17860 -17861 -17862 -17863 -17864 +v -17865 -17866 -17867 -17868 -17869 -17870 -17871 -17872 -17873 -17874 -17875 +v -17876 -17877 -17878 -17879 -17880 -17881 -17882 -17883 17884 -17885 17886 +v -17887 -17888 -17889 17890 -17891 17892 -17893 -17894 17895 -17896 -17897 +v -17898 -17899 -17900 -17901 17902 17903 17904 17905 17906 17907 -17908 -17909 +v -17910 -17911 -17912 -17913 -17914 -17915 -17916 -17917 17918 -17919 -17920 +v -17921 -17922 17923 17924 17925 17926 -17927 -17928 17929 -17930 17931 -17932 +v 17933 -17934 -17935 -17936 17937 17938 17939 17940 17941 -17942 -17943 17944 +v 17945 -17946 -17947 17948 17949 -17950 -17951 -17952 -17953 -17954 17955 +v 17956 17957 17958 -17959 -17960 17961 17962 -17963 17964 -17965 17966 -17967 +v -17968 -17969 -17970 -17971 -17972 17973 17974 -17975 17976 -17977 17978 +v -17979 -17980 -17981 -17982 -17983 -17984 17985 17986 -17987 17988 -17989 +v 17990 -17991 -17992 -17993 -17994 -17995 -17996 17997 17998 -17999 -18000 +v 18001 18002 -18003 -18004 18005 -18006 -18007 18008 -18009 18010 -18011 18012 +v -18013 -18014 -18015 18016 18017 18018 18019 18020 18021 18022 18023 18024 +v 18025 -18026 18027 -18028 -18029 18030 -18031 -18032 -18033 18034 -18035 +v -18036 18037 -18038 18039 -18040 -18041 18042 -18043 -18044 -18045 -18046 +v 18047 18048 18049 18050 -18051 -18052 -18053 -18054 18055 -18056 18057 18058 +v 18059 -18060 -18061 18062 18063 18064 18065 -18066 -18067 18068 18069 18070 +v -18071 -18072 -18073 -18074 -18075 -18076 -18077 -18078 18079 18080 18081 +v 18082 18083 18084 18085 18086 18087 18088 18089 18090 18091 -18092 -18093 +v -18094 -18095 18096 -18097 -18098 18099 -18100 -18101 18102 -18103 18104 +v -18105 -18106 18107 -18108 -18109 -18110 -18111 -18112 18113 18114 18115 +v 18116 -18117 -18118 -18119 -18120 -18121 -18122 -18123 -18124 -18125 -18126 +v -18127 -18128 -18129 -18130 -18131 -18132 -18133 -18134 -18135 -18136 -18137 +v -18138 -18139 -18140 -18141 -18142 -18143 -18144 -18145 -18146 -18147 18148 +v -18149 18150 -18151 -18152 -18153 18154 -18155 18156 -18157 -18158 18159 +v -18160 -18161 -18162 -18163 -18164 -18165 18166 18167 18168 18169 -18170 +v -18171 -18172 -18173 -18174 -18175 -18176 -18177 -18178 -18179 -18180 -18181 +v -18182 -18183 -18184 -18185 -18186 -18187 -18188 -18189 -18190 -18191 -18192 +v -18193 -18194 -18195 -18196 -18197 -18198 -18199 -18200 18201 -18202 18203 +v -18204 -18205 -18206 18207 -18208 18209 -18210 -18211 18212 -18213 -18214 +v -18215 -18216 -18217 -18218 18219 18220 18221 18222 -18223 -18224 -18225 +v -18226 -18227 -18228 -18229 -18230 -18231 -18232 -18233 -18234 -18235 -18236 +v -18237 -18238 -18239 -18240 -18241 -18242 -18243 -18244 -18245 -18246 -18247 +v -18248 -18249 -18250 -18251 -18252 -18253 18254 -18255 18256 -18257 -18258 +v -18259 18260 -18261 18262 -18263 -18264 18265 -18266 -18267 -18268 -18269 +v -18270 -18271 18272 18273 18274 18275 -18276 -18277 -18278 -18279 -18280 +v -18281 -18282 -18283 -18284 -18285 -18286 -18287 -18288 -18289 -18290 -18291 +v -18292 -18293 -18294 -18295 -18296 -18297 -18298 -18299 -18300 -18301 -18302 +v -18303 -18304 -18305 -18306 -18307 -18308 -18309 -18310 -18311 -18312 -18313 +v -18314 -18315 -18316 -18317 -18318 -18319 -18320 -18321 -18322 -18323 -18324 +v -18325 -18326 -18327 -18328 -18329 -18330 -18331 -18332 -18333 -18334 -18335 +v -18336 -18337 -18338 -18339 -18340 -18341 -18342 -18343 -18344 -18345 -18346 +v -18347 -18348 -18349 -18350 -18351 -18352 -18353 -18354 -18355 -18356 -18357 +v -18358 -18359 -18360 -18361 -18362 -18363 -18364 -18365 -18366 -18367 -18368 +v -18369 -18370 -18371 -18372 -18373 -18374 -18375 -18376 -18377 -18378 -18379 +v -18380 -18381 -18382 -18383 -18384 -18385 -18386 -18387 -18388 -18389 -18390 +v -18391 -18392 -18393 -18394 -18395 -18396 -18397 -18398 -18399 -18400 -18401 +v -18402 -18403 -18404 -18405 -18406 -18407 -18408 -18409 -18410 -18411 -18412 +v -18413 -18414 -18415 -18416 -18417 -18418 -18419 -18420 -18421 -18422 -18423 +v -18424 -18425 -18426 -18427 -18428 -18429 -18430 -18431 -18432 -18433 -18434 +v -18435 -18436 -18437 -18438 -18439 -18440 -18441 -18442 -18443 -18444 18445 +v -18446 18447 -18448 -18449 -18450 18451 -18452 18453 -18454 -18455 -18456 +v -18457 18458 -18459 18460 -18461 -18462 -18463 -18464 18465 -18466 18467 +v -18468 -18469 18470 -18471 -18472 -18473 -18474 -18475 -18476 -18477 -18478 +v -18479 -18480 18481 18482 18483 18484 -18485 -18486 -18487 -18488 -18489 +v -18490 -18491 -18492 -18493 -18494 -18495 -18496 -18497 -18498 -18499 -18500 +v -18501 -18502 -18503 -18504 -18505 -18506 -18507 -18508 -18509 -18510 -18511 +v -18512 -18513 -18514 -18515 -18516 -18517 -18518 -18519 -18520 -18521 -18522 +v -18523 -18524 -18525 -18526 -18527 -18528 -18529 -18530 -18531 -18532 -18533 +v -18534 -18535 -18536 -18537 -18538 -18539 -18540 -18541 -18542 -18543 -18544 +v -18545 -18546 -18547 -18548 -18549 -18550 -18551 -18552 -18553 -18554 -18555 +v -18556 -18557 -18558 -18559 -18560 -18561 -18562 -18563 -18564 -18565 -18566 +v -18567 -18568 -18569 -18570 -18571 -18572 -18573 -18574 -18575 -18576 -18577 +v -18578 -18579 -18580 -18581 -18582 -18583 -18584 -18585 -18586 -18587 -18588 +v -18589 -18590 -18591 -18592 -18593 -18594 -18595 -18596 -18597 -18598 -18599 +v -18600 -18601 -18602 -18603 -18604 -18605 -18606 -18607 -18608 -18609 -18610 +v -18611 -18612 -18613 -18614 -18615 -18616 -18617 -18618 -18619 -18620 -18621 +v -18622 -18623 -18624 -18625 -18626 -18627 -18628 -18629 -18630 -18631 -18632 +v -18633 -18634 -18635 -18636 -18637 -18638 -18639 -18640 -18641 -18642 -18643 +v -18644 -18645 -18646 -18647 -18648 -18649 -18650 -18651 18652 -18653 18654 +v -18655 -18656 -18657 18658 -18659 18660 -18661 -18662 -18663 -18664 18665 +v -18666 18667 -18668 -18669 -18670 -18671 18672 -18673 18674 -18675 -18676 +v 18677 -18678 -18679 -18680 -18681 -18682 -18683 -18684 -18685 -18686 -18687 +v 18688 18689 18690 18691 -18692 -18693 -18694 -18695 -18696 -18697 -18698 +v -18699 -18700 -18701 -18702 -18703 -18704 -18705 -18706 -18707 -18708 -18709 +v -18710 -18711 -18712 -18713 -18714 -18715 -18716 -18717 -18718 -18719 -18720 +v -18721 -18722 -18723 -18724 -18725 -18726 -18727 -18728 -18729 -18730 -18731 +v -18732 -18733 -18734 -18735 -18736 -18737 -18738 -18739 -18740 -18741 -18742 +v -18743 -18744 -18745 -18746 -18747 -18748 -18749 -18750 -18751 -18752 -18753 +v -18754 -18755 -18756 -18757 -18758 -18759 -18760 -18761 -18762 -18763 -18764 +v -18765 -18766 -18767 -18768 -18769 -18770 -18771 -18772 -18773 -18774 -18775 +v -18776 -18777 -18778 -18779 -18780 -18781 -18782 -18783 -18784 -18785 -18786 +v -18787 -18788 -18789 -18790 -18791 -18792 -18793 -18794 -18795 -18796 -18797 +v -18798 -18799 -18800 -18801 -18802 -18803 -18804 -18805 -18806 -18807 -18808 +v -18809 -18810 -18811 -18812 -18813 -18814 -18815 -18816 -18817 -18818 -18819 +v -18820 -18821 -18822 -18823 -18824 -18825 -18826 -18827 -18828 -18829 -18830 +v -18831 -18832 -18833 -18834 -18835 -18836 -18837 -18838 -18839 -18840 -18841 +v -18842 -18843 -18844 -18845 -18846 -18847 -18848 -18849 -18850 -18851 -18852 +v 18853 -18854 18855 -18856 -18857 -18858 18859 -18860 18861 -18862 -18863 +v -18864 -18865 18866 -18867 18868 -18869 -18870 -18871 -18872 18873 -18874 +v 18875 -18876 -18877 18878 -18879 -18880 -18881 -18882 -18883 -18884 -18885 +v -18886 -18887 -18888 18889 18890 18891 18892 -18893 -18894 -18895 -18896 +v -18897 -18898 -18899 -18900 -18901 -18902 -18903 -18904 -18905 -18906 -18907 +v -18908 -18909 -18910 -18911 -18912 -18913 -18914 -18915 -18916 -18917 -18918 +v -18919 -18920 -18921 -18922 -18923 -18924 -18925 -18926 -18927 -18928 -18929 +v -18930 -18931 -18932 -18933 -18934 -18935 -18936 -18937 -18938 -18939 -18940 +v -18941 -18942 -18943 -18944 -18945 -18946 -18947 -18948 -18949 -18950 -18951 +v -18952 -18953 -18954 -18955 -18956 -18957 -18958 -18959 -18960 -18961 -18962 +v -18963 -18964 -18965 -18966 -18967 -18968 -18969 -18970 -18971 -18972 -18973 +v -18974 -18975 -18976 -18977 -18978 -18979 -18980 -18981 -18982 -18983 -18984 +v -18985 -18986 -18987 -18988 -18989 -18990 -18991 -18992 -18993 -18994 -18995 +v -18996 -18997 -18998 -18999 -19000 -19001 -19002 -19003 -19004 -19005 -19006 +v -19007 -19008 -19009 -19010 -19011 -19012 -19013 -19014 -19015 -19016 -19017 +v -19018 -19019 -19020 -19021 -19022 -19023 -19024 -19025 -19026 -19027 -19028 +v -19029 -19030 -19031 -19032 -19033 -19034 -19035 -19036 -19037 -19038 -19039 +v -19040 -19041 -19042 -19043 -19044 -19045 -19046 -19047 -19048 -19049 -19050 +v -19051 -19052 -19053 -19054 -19055 -19056 -19057 -19058 -19059 19060 -19061 +v 19062 -19063 -19064 -19065 19066 -19067 19068 -19069 -19070 -19071 -19072 +v 19073 -19074 19075 -19076 -19077 -19078 -19079 19080 -19081 19082 -19083 +v -19084 19085 -19086 -19087 -19088 -19089 -19090 -19091 -19092 -19093 -19094 +v -19095 19096 19097 19098 19099 -19100 -19101 -19102 -19103 -19104 -19105 +v -19106 -19107 -19108 -19109 -19110 -19111 -19112 -19113 -19114 -19115 -19116 +v -19117 -19118 -19119 -19120 -19121 -19122 -19123 -19124 -19125 -19126 -19127 +v -19128 -19129 -19130 19131 -19132 19133 -19134 -19135 -19136 19137 -19138 +v 19139 -19140 -19141 19142 -19143 -19144 -19145 -19146 -19147 -19148 19149 +v 19150 19151 19152 -19153 19154 -19155 19156 -19157 19158 19159 19160 -19161 +v -19162 -19163 -19164 -19165 -19166 -19167 -19168 -19169 -19170 -19171 -19172 +v -19173 -19174 -19175 -19176 -19177 -19178 -19179 -19180 -19181 -19182 -19183 +v -19184 -19185 -19186 -19187 -19188 -19189 -19190 -19191 -19192 -19193 -19194 +v -19195 -19196 -19197 -19198 -19199 -19200 -19201 -19202 -19203 -19204 -19205 +v -19206 -19207 -19208 -19209 -19210 -19211 -19212 -19213 -19214 -19215 -19216 +v -19217 -19218 -19219 -19220 -19221 -19222 -19223 -19224 -19225 -19226 -19227 +v -19228 -19229 -19230 -19231 -19232 -19233 -19234 -19235 -19236 -19237 -19238 +v -19239 -19240 -19241 -19242 -19243 -19244 -19245 -19246 -19247 -19248 -19249 +v -19250 -19251 -19252 -19253 -19254 -19255 -19256 -19257 -19258 -19259 -19260 +v -19261 -19262 -19263 -19264 -19265 -19266 -19267 -19268 -19269 -19270 -19271 +v -19272 -19273 -19274 -19275 -19276 -19277 -19278 -19279 -19280 -19281 -19282 +v -19283 -19284 -19285 -19286 -19287 -19288 -19289 -19290 -19291 -19292 -19293 +v -19294 -19295 -19296 -19297 -19298 -19299 -19300 -19301 -19302 -19303 -19304 +v -19305 -19306 -19307 -19308 -19309 -19310 -19311 -19312 -19313 -19314 -19315 +v -19316 -19317 -19318 -19319 -19320 -19321 -19322 -19323 -19324 -19325 -19326 +v -19327 -19328 -19329 -19330 -19331 -19332 -19333 -19334 -19335 -19336 -19337 +v -19338 -19339 -19340 -19341 -19342 -19343 -19344 -19345 -19346 -19347 -19348 +v -19349 -19350 -19351 -19352 -19353 -19354 -19355 -19356 -19357 -19358 -19359 +v -19360 -19361 -19362 -19363 -19364 -19365 -19366 -19367 -19368 -19369 -19370 +v -19371 -19372 -19373 -19374 -19375 -19376 -19377 -19378 -19379 -19380 -19381 +v -19382 -19383 -19384 -19385 -19386 -19387 -19388 -19389 -19390 -19391 -19392 +v -19393 -19394 -19395 -19396 -19397 -19398 -19399 -19400 -19401 -19402 -19403 +v -19404 -19405 -19406 -19407 -19408 -19409 -19410 -19411 -19412 -19413 -19414 +v -19415 -19416 -19417 -19418 -19419 -19420 -19421 -19422 -19423 -19424 -19425 +v -19426 -19427 -19428 -19429 -19430 -19431 -19432 -19433 -19434 -19435 -19436 +v -19437 -19438 -19439 -19440 -19441 -19442 -19443 -19444 -19445 -19446 -19447 +v -19448 -19449 -19450 -19451 -19452 -19453 -19454 -19455 -19456 -19457 -19458 +v -19459 -19460 -19461 -19462 -19463 -19464 -19465 -19466 -19467 -19468 -19469 +v -19470 -19471 -19472 -19473 -19474 -19475 -19476 -19477 -19478 -19479 -19480 +v -19481 -19482 -19483 -19484 -19485 -19486 -19487 -19488 -19489 -19490 -19491 +v -19492 -19493 -19494 -19495 -19496 -19497 -19498 -19499 -19500 -19501 -19502 +v -19503 -19504 -19505 -19506 -19507 -19508 -19509 -19510 -19511 -19512 -19513 +v -19514 -19515 -19516 -19517 -19518 -19519 -19520 -19521 -19522 -19523 -19524 +v -19525 -19526 -19527 -19528 -19529 -19530 -19531 -19532 -19533 -19534 -19535 +v -19536 -19537 -19538 -19539 -19540 -19541 -19542 -19543 -19544 -19545 -19546 +v -19547 -19548 -19549 -19550 -19551 -19552 -19553 -19554 -19555 -19556 -19557 +v -19558 -19559 -19560 -19561 -19562 -19563 -19564 -19565 -19566 -19567 -19568 +v -19569 -19570 -19571 -19572 -19573 -19574 -19575 -19576 -19577 -19578 -19579 +v -19580 -19581 -19582 -19583 -19584 -19585 -19586 -19587 -19588 -19589 -19590 +v -19591 -19592 -19593 -19594 -19595 -19596 -19597 -19598 -19599 -19600 -19601 +v -19602 -19603 -19604 -19605 -19606 -19607 -19608 -19609 -19610 -19611 -19612 +v -19613 -19614 -19615 -19616 -19617 -19618 -19619 -19620 -19621 -19622 -19623 +v -19624 -19625 -19626 -19627 -19628 -19629 -19630 -19631 -19632 -19633 -19634 +v -19635 -19636 -19637 -19638 -19639 -19640 -19641 -19642 -19643 -19644 -19645 +v -19646 -19647 -19648 -19649 -19650 -19651 -19652 -19653 -19654 -19655 -19656 +v -19657 -19658 -19659 -19660 -19661 -19662 -19663 -19664 -19665 -19666 -19667 +v -19668 -19669 -19670 -19671 -19672 -19673 -19674 -19675 -19676 -19677 -19678 +v -19679 -19680 -19681 -19682 -19683 -19684 -19685 -19686 -19687 -19688 -19689 +v -19690 -19691 -19692 -19693 -19694 -19695 -19696 -19697 -19698 -19699 -19700 +v -19701 -19702 -19703 -19704 -19705 -19706 -19707 19708 -19709 19710 -19711 +v -19712 19713 -19714 19715 -19716 -19717 19718 -19719 19720 -19721 -19722 +v -19723 19724 -19725 19726 -19727 -19728 -19729 19730 -19731 19732 -19733 +v -19734 -19735 19736 -19737 19738 -19739 -19740 19741 -19742 -19743 -19744 +v -19745 -19746 -19747 -19748 -19749 -19750 -19751 -19752 -19753 -19754 -19755 +v 19756 19757 19758 19759 19760 -19761 -19762 -19763 -19764 -19765 -19766 19767 +v -19768 -19769 -19770 -19771 -19772 -19773 -19774 -19775 -19776 -19777 -19778 +v -19779 -19780 -19781 -19782 -19783 -19784 -19785 -19786 -19787 -19788 -19789 +v -19790 -19791 -19792 -19793 -19794 -19795 -19796 -19797 -19798 -19799 -19800 +v -19801 -19802 -19803 -19804 -19805 -19806 -19807 -19808 -19809 -19810 -19811 +v -19812 -19813 -19814 -19815 -19816 -19817 -19818 -19819 -19820 -19821 -19822 +v -19823 -19824 -19825 -19826 -19827 -19828 -19829 -19830 -19831 -19832 -19833 +v -19834 -19835 -19836 -19837 -19838 -19839 -19840 -19841 -19842 -19843 -19844 +v -19845 -19846 -19847 -19848 -19849 -19850 -19851 -19852 -19853 -19854 -19855 +v -19856 -19857 -19858 -19859 -19860 -19861 -19862 -19863 -19864 -19865 -19866 +v -19867 -19868 -19869 -19870 -19871 -19872 -19873 -19874 -19875 -19876 -19877 +v -19878 -19879 -19880 -19881 -19882 -19883 -19884 -19885 -19886 -19887 -19888 +v -19889 -19890 -19891 -19892 -19893 -19894 -19895 -19896 -19897 -19898 19899 +v -19900 19901 -19902 -19903 -19904 19905 -19906 19907 -19908 -19909 -19910 +v 19911 -19912 19913 -19914 -19915 -19916 19917 -19918 19919 -19920 -19921 +v -19922 19923 -19924 19925 -19926 -19927 19928 -19929 -19930 -19931 -19932 +v -19933 -19934 -19935 -19936 -19937 -19938 -19939 19940 19941 19942 -19943 +v -19944 -19945 -19946 -19947 -19948 -19949 -19950 -19951 -19952 -19953 -19954 +v -19955 -19956 -19957 -19958 -19959 -19960 -19961 -19962 -19963 -19964 -19965 +v -19966 -19967 -19968 -19969 -19970 -19971 -19972 -19973 -19974 -19975 -19976 +v -19977 -19978 -19979 -19980 -19981 -19982 -19983 -19984 -19985 -19986 -19987 +v -19988 -19989 -19990 -19991 -19992 -19993 -19994 -19995 19996 -19997 19998 +v -19999 -20000 20001 -20002 20003 -20004 -20005 -20006 20007 -20008 20009 +v -20010 -20011 -20012 20013 -20014 20015 -20016 -20017 20018 -20019 -20020 +v -20021 -20022 -20023 -20024 -20025 -20026 -20027 -20028 20029 20030 20031 +v 20032 -20033 -20034 -20035 -20036 -20037 -20038 -20039 -20040 -20041 -20042 +v -20043 -20044 -20045 -20046 -20047 -20048 -20049 -20050 -20051 -20052 -20053 +v -20054 -20055 -20056 -20057 -20058 -20059 -20060 -20061 -20062 -20063 -20064 +v -20065 -20066 -20067 -20068 -20069 -20070 -20071 -20072 -20073 -20074 -20075 +v -20076 -20077 -20078 -20079 -20080 -20081 -20082 -20083 -20084 -20085 -20086 +v -20087 -20088 -20089 -20090 -20091 -20092 -20093 -20094 -20095 -20096 -20097 +v -20098 -20099 -20100 -20101 -20102 20103 -20104 -20105 -20106 -20107 -20108 +v -20109 -20110 -20111 -20112 -20113 -20114 -20115 -20116 -20117 -20118 -20119 +v -20120 -20121 -20122 -20123 -20124 -20125 -20126 -20127 -20128 -20129 -20130 +v 20131 -20132 20133 -20134 -20135 -20136 20137 -20138 20139 -20140 -20141 +v -20142 20143 -20144 20145 -20146 -20147 -20148 20149 -20150 20151 -20152 +v -20153 20154 -20155 -20156 -20157 -20158 -20159 -20160 -20161 -20162 -20163 +v -20164 20165 20166 20167 -20168 -20169 -20170 -20171 -20172 -20173 -20174 +v -20175 -20176 -20177 -20178 -20179 -20180 20181 -20182 -20183 20184 -20185 +v -20186 -20187 -20188 -20189 -20190 20191 20192 20193 20194 -20195 20196 +v -20197 20198 20199 20200 20201 20202 20203 20204 20205 20206 20207 -20208 +v -20209 20210 20211 20212 20213 20214 20215 -20216 20217 20218 20219 -20220 +v -20221 -20222 -20223 -20224 -20225 20226 -20227 20228 20229 -20230 -20231 +v -20232 -20233 -20234 -20235 -20236 -20237 -20238 -20239 20240 -20241 -20242 +v -20243 20244 -20245 -20246 20247 20248 20249 20250 20251 20252 20253 20254 +v 20255 20256 -20257 -20258 20259 20260 20261 20262 20263 20264 -20265 20266 +v 20267 -20268 -20269 20270 20271 20272 20273 -20274 -20275 20276 20277 -20278 +v -20279 -20280 20281 -20282 20283 -20284 -20285 20286 -20287 -20288 -20289 +v -20290 -20291 -20292 -20293 -20294 20295 20296 20297 -20298 -20299 -20300 +v -20301 -20302 -20303 -20304 -20305 -20306 -20307 -20308 -20309 -20310 -20311 +v -20312 -20313 -20314 -20315 -20316 -20317 -20318 -20319 20320 -20321 -20322 +v -20323 -20324 -20325 -20326 -20327 20328 -20329 20330 -20331 -20332 -20333 +v 20334 -20335 20336 -20337 -20338 20339 -20340 -20341 -20342 -20343 -20344 +v -20345 20346 20347 20348 -20349 -20350 -20351 -20352 -20353 -20354 -20355 +v -20356 -20357 -20358 -20359 -20360 -20361 -20362 -20363 -20364 -20365 -20366 +v -20367 -20368 -20369 -20370 20371 -20372 -20373 -20374 -20375 -20376 -20377 +v -20378 20379 -20380 20381 -20382 -20383 -20384 20385 -20386 20387 -20388 +v -20389 20390 -20391 -20392 -20393 -20394 -20395 -20396 20397 20398 20399 +v -20400 -20401 -20402 -20403 -20404 -20405 -20406 -20407 -20408 -20409 -20410 +v -20411 -20412 -20413 -20414 -20415 -20416 -20417 -20418 -20419 -20420 -20421 +v 20422 -20423 -20424 -20425 -20426 -20427 -20428 -20429 20430 -20431 20432 +v -20433 -20434 -20435 20436 -20437 20438 -20439 -20440 20441 -20442 -20443 +v -20444 -20445 -20446 -20447 20448 20449 20450 -20451 -20452 -20453 -20454 +v -20455 -20456 -20457 -20458 -20459 -20460 -20461 -20462 -20463 -20464 -20465 +v -20466 -20467 -20468 -20469 -20470 -20471 -20472 -20473 -20474 -20475 -20476 +v -20477 -20478 -20479 -20480 -20481 -20482 -20483 -20484 -20485 -20486 -20487 +v -20488 -20489 -20490 -20491 -20492 -20493 -20494 -20495 -20496 -20497 -20498 +v -20499 -20500 -20501 -20502 -20503 -20504 -20505 -20506 -20507 -20508 -20509 +v -20510 -20511 -20512 -20513 -20514 -20515 -20516 -20517 -20518 -20519 -20520 +v -20521 -20522 -20523 -20524 -20525 -20526 -20527 -20528 -20529 -20530 -20531 +v -20532 -20533 -20534 -20535 -20536 -20537 -20538 -20539 -20540 -20541 -20542 +v -20543 20544 -20545 -20546 -20547 -20548 -20549 -20550 -20551 -20552 -20553 +v -20554 -20555 -20556 -20557 -20558 -20559 -20560 -20561 -20562 -20563 -20564 +v -20565 -20566 -20567 -20568 -20569 -20570 -20571 -20572 -20573 -20574 -20575 +v -20576 -20577 -20578 -20579 -20580 -20581 -20582 -20583 -20584 -20585 -20586 +v -20587 -20588 -20589 -20590 -20591 -20592 -20593 -20594 -20595 -20596 -20597 +v -20598 -20599 -20600 -20601 -20602 -20603 -20604 -20605 -20606 -20607 -20608 +v -20609 -20610 -20611 -20612 20613 -20614 20615 -20616 -20617 -20618 20619 +v -20620 20621 -20622 -20623 -20624 -20625 20626 -20627 20628 -20629 -20630 +v -20631 -20632 20633 -20634 20635 -20636 -20637 20638 -20639 -20640 -20641 +v -20642 -20643 -20644 -20645 -20646 -20647 -20648 20649 20650 20651 -20652 +v -20653 -20654 -20655 -20656 -20657 -20658 -20659 -20660 -20661 -20662 -20663 +v -20664 -20665 -20666 -20667 -20668 -20669 -20670 -20671 -20672 -20673 -20674 +v -20675 -20676 -20677 -20678 -20679 -20680 -20681 -20682 -20683 -20684 -20685 +v -20686 -20687 -20688 -20689 -20690 -20691 -20692 -20693 -20694 -20695 -20696 +v -20697 -20698 -20699 -20700 -20701 -20702 -20703 -20704 -20705 -20706 -20707 +v -20708 -20709 -20710 -20711 -20712 -20713 -20714 -20715 -20716 -20717 -20718 +v -20719 -20720 -20721 -20722 -20723 -20724 -20725 -20726 -20727 -20728 -20729 +v -20730 -20731 -20732 -20733 -20734 -20735 -20736 -20737 -20738 -20739 -20740 +v -20741 -20742 -20743 -20744 20745 -20746 -20747 -20748 -20749 -20750 -20751 +v -20752 -20753 -20754 -20755 -20756 -20757 -20758 -20759 -20760 -20761 -20762 +v -20763 -20764 -20765 -20766 -20767 -20768 -20769 -20770 -20771 -20772 -20773 +v -20774 -20775 -20776 -20777 -20778 -20779 -20780 -20781 -20782 -20783 -20784 +v -20785 -20786 -20787 -20788 -20789 -20790 -20791 -20792 -20793 -20794 -20795 +v -20796 -20797 -20798 -20799 -20800 -20801 -20802 -20803 -20804 -20805 -20806 +v -20807 -20808 -20809 -20810 -20811 -20812 -20813 20814 -20815 20816 -20817 +v -20818 -20819 20820 -20821 20822 -20823 -20824 -20825 -20826 20827 -20828 +v 20829 -20830 -20831 -20832 -20833 20834 -20835 20836 -20837 -20838 20839 +v -20840 -20841 -20842 -20843 -20844 -20845 -20846 -20847 -20848 -20849 20850 +v 20851 20852 -20853 -20854 -20855 -20856 -20857 -20858 -20859 -20860 -20861 +v -20862 -20863 -20864 -20865 -20866 -20867 -20868 -20869 -20870 -20871 -20872 +v -20873 -20874 -20875 -20876 -20877 -20878 -20879 -20880 -20881 -20882 -20883 +v -20884 -20885 -20886 -20887 -20888 -20889 -20890 -20891 -20892 -20893 -20894 +v -20895 -20896 -20897 -20898 -20899 -20900 -20901 -20902 -20903 -20904 -20905 +v -20906 -20907 -20908 -20909 -20910 -20911 -20912 -20913 -20914 -20915 -20916 +v -20917 -20918 -20919 -20920 -20921 -20922 -20923 -20924 -20925 -20926 -20927 +v -20928 -20929 -20930 -20931 -20932 -20933 -20934 -20935 -20936 -20937 -20938 +v -20939 -20940 -20941 -20942 -20943 -20944 -20945 20946 -20947 -20948 -20949 +v -20950 -20951 -20952 -20953 -20954 -20955 -20956 -20957 -20958 -20959 -20960 +v -20961 -20962 -20963 -20964 -20965 -20966 -20967 -20968 -20969 -20970 -20971 +v -20972 -20973 -20974 -20975 -20976 -20977 -20978 -20979 -20980 -20981 -20982 +v -20983 -20984 -20985 -20986 -20987 -20988 -20989 -20990 -20991 -20992 -20993 +v -20994 -20995 -20996 -20997 -20998 -20999 -21000 -21001 -21002 -21003 -21004 +v -21005 -21006 -21007 -21008 -21009 -21010 -21011 -21012 -21013 -21014 21015 +v -21016 21017 -21018 -21019 -21020 21021 -21022 21023 -21024 -21025 -21026 +v -21027 21028 -21029 21030 -21031 -21032 -21033 -21034 21035 -21036 21037 +v -21038 -21039 21040 -21041 -21042 -21043 -21044 -21045 -21046 -21047 -21048 +v -21049 -21050 21051 21052 21053 -21054 -21055 -21056 -21057 -21058 -21059 +v -21060 -21061 -21062 -21063 -21064 -21065 -21066 -21067 -21068 -21069 -21070 +v -21071 -21072 -21073 -21074 -21075 -21076 -21077 -21078 -21079 -21080 -21081 +v -21082 -21083 -21084 -21085 -21086 -21087 -21088 -21089 -21090 -21091 -21092 +v -21093 -21094 -21095 -21096 -21097 -21098 -21099 -21100 -21101 -21102 -21103 +v -21104 -21105 -21106 -21107 -21108 -21109 -21110 -21111 -21112 -21113 -21114 +v -21115 -21116 -21117 -21118 -21119 -21120 -21121 -21122 -21123 -21124 -21125 +v -21126 -21127 -21128 -21129 -21130 -21131 -21132 -21133 -21134 -21135 -21136 +v -21137 -21138 -21139 -21140 -21141 -21142 -21143 -21144 -21145 -21146 21147 +v -21148 -21149 -21150 -21151 -21152 -21153 -21154 -21155 -21156 -21157 -21158 +v -21159 -21160 -21161 -21162 -21163 -21164 -21165 -21166 -21167 -21168 -21169 +v -21170 -21171 -21172 -21173 -21174 -21175 -21176 -21177 -21178 -21179 -21180 +v -21181 -21182 -21183 -21184 -21185 -21186 -21187 -21188 -21189 -21190 -21191 +v -21192 -21193 -21194 -21195 -21196 -21197 -21198 -21199 -21200 -21201 -21202 +v -21203 -21204 -21205 -21206 -21207 -21208 -21209 -21210 -21211 -21212 -21213 +v -21214 -21215 21216 -21217 21218 -21219 -21220 -21221 21222 -21223 21224 +v -21225 -21226 -21227 -21228 21229 -21230 21231 -21232 -21233 -21234 -21235 +v 21236 -21237 21238 -21239 -21240 21241 -21242 -21243 -21244 -21245 -21246 +v -21247 -21248 -21249 -21250 -21251 21252 21253 21254 -21255 -21256 -21257 +v -21258 -21259 -21260 -21261 -21262 -21263 -21264 -21265 -21266 -21267 -21268 +v -21269 -21270 -21271 -21272 -21273 -21274 -21275 -21276 21277 -21278 -21279 +v -21280 -21281 -21282 -21283 -21284 21285 -21286 21287 -21288 -21289 -21290 +v 21291 -21292 21293 -21294 -21295 21296 -21297 -21298 -21299 -21300 -21301 +v -21302 21303 21304 21305 -21306 -21307 -21308 -21309 -21310 -21311 -21312 +v -21313 -21314 -21315 -21316 -21317 -21318 -21319 -21320 -21321 -21322 -21323 +v -21324 -21325 -21326 -21327 -21328 -21329 -21330 -21331 -21332 -21333 -21334 +v 21335 -21336 21337 -21338 -21339 -21340 21341 -21342 21343 -21344 -21345 +v 21346 -21347 -21348 -21349 -21350 -21351 -21352 21353 21354 21355 21356 +v -21357 -21358 -21359 -21360 -21361 -21362 -21363 -21364 -21365 -21366 -21367 +v -21368 -21369 -21370 -21371 -21372 -21373 -21374 -21375 -21376 -21377 -21378 +v -21379 -21380 -21381 -21382 -21383 -21384 -21385 21386 -21387 21388 -21389 +v -21390 -21391 21392 -21393 21394 -21395 -21396 21397 -21398 -21399 -21400 +v -21401 -21402 -21403 21404 21405 21406 21407 -21408 -21409 -21410 -21411 +v -21412 -21413 -21414 -21415 -21416 -21417 -21418 -21419 -21420 -21421 -21422 +v -21423 -21424 -21425 -21426 -21427 -21428 -21429 -21430 -21431 -21432 -21433 +v -21434 -21435 -21436 21437 -21438 21439 -21440 -21441 -21442 21443 -21444 +v 21445 -21446 -21447 21448 -21449 -21450 -21451 -21452 -21453 -21454 21455 +v 21456 21457 21458 -21459 -21460 -21461 -21462 -21463 -21464 -21465 -21466 +v -21467 -21468 -21469 -21470 -21471 -21472 -21473 -21474 -21475 -21476 -21477 +v -21478 -21479 -21480 -21481 -21482 -21483 -21484 -21485 -21486 -21487 -21488 +v -21489 -21490 -21491 -21492 -21493 -21494 -21495 -21496 -21497 -21498 -21499 +v -21500 -21501 -21502 -21503 -21504 -21505 -21506 -21507 -21508 -21509 -21510 +v -21511 -21512 -21513 -21514 -21515 -21516 -21517 -21518 -21519 -21520 -21521 +v -21522 -21523 -21524 -21525 -21526 -21527 -21528 -21529 -21530 -21531 -21532 +v -21533 -21534 -21535 -21536 -21537 -21538 -21539 -21540 -21541 -21542 -21543 +v -21544 -21545 -21546 -21547 -21548 -21549 -21550 -21551 -21552 -21553 -21554 +v -21555 -21556 -21557 -21558 -21559 -21560 -21561 -21562 -21563 -21564 -21565 +v -21566 -21567 -21568 -21569 -21570 -21571 -21572 -21573 -21574 -21575 -21576 +v -21577 -21578 -21579 -21580 -21581 -21582 -21583 -21584 -21585 -21586 -21587 +v -21588 -21589 -21590 -21591 -21592 -21593 -21594 -21595 -21596 -21597 -21598 +v -21599 -21600 -21601 -21602 -21603 -21604 -21605 -21606 -21607 -21608 -21609 +v -21610 -21611 -21612 -21613 -21614 -21615 -21616 -21617 -21618 -21619 21620 +v -21621 21622 -21623 -21624 -21625 21626 -21627 21628 -21629 -21630 -21631 +v -21632 21633 -21634 21635 -21636 -21637 -21638 -21639 21640 -21641 21642 +v -21643 -21644 21645 -21646 -21647 -21648 -21649 -21650 -21651 -21652 -21653 +v -21654 -21655 21656 21657 21658 21659 -21660 -21661 -21662 -21663 -21664 +v -21665 -21666 -21667 -21668 -21669 -21670 -21671 -21672 -21673 -21674 -21675 +v -21676 -21677 -21678 -21679 -21680 -21681 -21682 -21683 -21684 -21685 -21686 +v -21687 -21688 -21689 -21690 -21691 -21692 -21693 -21694 -21695 -21696 -21697 +v -21698 -21699 -21700 -21701 -21702 -21703 -21704 -21705 -21706 -21707 -21708 +v -21709 -21710 -21711 -21712 -21713 -21714 -21715 -21716 -21717 -21718 -21719 +v -21720 -21721 -21722 -21723 -21724 -21725 -21726 -21727 -21728 -21729 -21730 +v -21731 -21732 -21733 -21734 -21735 -21736 -21737 -21738 -21739 -21740 -21741 +v -21742 -21743 -21744 -21745 -21746 -21747 -21748 -21749 -21750 -21751 -21752 +v -21753 -21754 -21755 -21756 -21757 -21758 -21759 -21760 -21761 -21762 -21763 +v -21764 -21765 -21766 -21767 -21768 -21769 -21770 -21771 -21772 -21773 -21774 +v -21775 -21776 -21777 -21778 -21779 -21780 -21781 -21782 -21783 -21784 -21785 +v -21786 -21787 -21788 -21789 -21790 -21791 -21792 -21793 -21794 -21795 -21796 +v -21797 -21798 -21799 -21800 -21801 -21802 -21803 -21804 -21805 -21806 -21807 +v -21808 -21809 -21810 -21811 -21812 -21813 -21814 -21815 -21816 -21817 -21818 +v -21819 -21820 21821 -21822 21823 -21824 -21825 -21826 21827 -21828 21829 +v -21830 -21831 -21832 -21833 21834 -21835 21836 -21837 -21838 -21839 -21840 +v 21841 -21842 21843 -21844 -21845 21846 -21847 -21848 -21849 -21850 -21851 +v -21852 -21853 -21854 -21855 -21856 21857 21858 21859 21860 -21861 -21862 +v -21863 -21864 -21865 -21866 -21867 -21868 -21869 -21870 -21871 -21872 -21873 +v -21874 -21875 -21876 -21877 -21878 -21879 -21880 -21881 -21882 -21883 -21884 +v -21885 -21886 -21887 -21888 -21889 -21890 -21891 -21892 -21893 -21894 -21895 +v -21896 -21897 -21898 -21899 -21900 -21901 -21902 -21903 -21904 -21905 -21906 +v -21907 -21908 -21909 -21910 -21911 -21912 -21913 -21914 -21915 -21916 -21917 +v -21918 -21919 -21920 -21921 -21922 -21923 -21924 -21925 -21926 -21927 -21928 +v -21929 -21930 -21931 -21932 -21933 -21934 -21935 -21936 -21937 -21938 -21939 +v -21940 -21941 -21942 -21943 -21944 -21945 -21946 -21947 -21948 -21949 -21950 +v -21951 -21952 -21953 -21954 -21955 -21956 -21957 -21958 -21959 -21960 -21961 +v -21962 -21963 -21964 -21965 -21966 -21967 -21968 -21969 -21970 -21971 -21972 +v -21973 -21974 -21975 -21976 -21977 -21978 -21979 -21980 -21981 -21982 -21983 +v -21984 -21985 -21986 -21987 -21988 -21989 -21990 -21991 -21992 -21993 -21994 +v -21995 -21996 -21997 -21998 -21999 -22000 -22001 -22002 -22003 -22004 -22005 +v -22006 -22007 -22008 -22009 -22010 -22011 -22012 -22013 -22014 -22015 -22016 +v -22017 -22018 -22019 -22020 -22021 22022 -22023 22024 -22025 -22026 -22027 +v 22028 -22029 22030 -22031 -22032 -22033 -22034 22035 -22036 22037 -22038 +v -22039 -22040 -22041 22042 -22043 22044 -22045 -22046 22047 -22048 -22049 +v -22050 -22051 -22052 -22053 -22054 -22055 -22056 -22057 22058 22059 22060 +v 22061 -22062 -22063 -22064 -22065 -22066 -22067 -22068 -22069 -22070 -22071 +v -22072 -22073 -22074 -22075 -22076 -22077 -22078 -22079 -22080 -22081 -22082 +v -22083 -22084 -22085 -22086 -22087 -22088 -22089 -22090 -22091 -22092 -22093 +v -22094 -22095 -22096 -22097 -22098 -22099 -22100 -22101 -22102 -22103 -22104 +v -22105 -22106 -22107 -22108 -22109 -22110 -22111 -22112 -22113 -22114 -22115 +v -22116 -22117 -22118 -22119 -22120 -22121 -22122 -22123 -22124 -22125 -22126 +v -22127 -22128 -22129 -22130 -22131 -22132 -22133 -22134 -22135 -22136 -22137 +v -22138 -22139 -22140 -22141 -22142 -22143 -22144 -22145 -22146 -22147 -22148 +v -22149 -22150 -22151 -22152 -22153 -22154 -22155 -22156 -22157 -22158 -22159 +v -22160 -22161 -22162 -22163 -22164 -22165 -22166 -22167 -22168 -22169 -22170 +v -22171 -22172 -22173 -22174 -22175 -22176 -22177 -22178 -22179 -22180 -22181 +v -22182 -22183 -22184 -22185 -22186 -22187 -22188 -22189 -22190 -22191 -22192 +v -22193 -22194 -22195 -22196 -22197 -22198 -22199 -22200 -22201 -22202 -22203 +v -22204 -22205 -22206 -22207 -22208 -22209 -22210 -22211 -22212 -22213 -22214 +v -22215 -22216 -22217 -22218 -22219 -22220 -22221 -22222 22223 -22224 22225 +v -22226 -22227 -22228 22229 -22230 22231 -22232 -22233 -22234 -22235 22236 +v -22237 22238 -22239 -22240 -22241 -22242 22243 -22244 22245 -22246 -22247 +v 22248 -22249 -22250 -22251 -22252 -22253 -22254 -22255 -22256 -22257 -22258 +v 22259 22260 22261 22262 -22263 -22264 -22265 -22266 -22267 -22268 -22269 +v -22270 -22271 -22272 -22273 -22274 -22275 -22276 -22277 -22278 -22279 -22280 +v -22281 -22282 -22283 -22284 -22285 -22286 -22287 -22288 -22289 -22290 -22291 +v 22292 -22293 22294 -22295 -22296 -22297 22298 -22299 22300 -22301 -22302 +v 22303 -22304 -22305 -22306 -22307 -22308 -22309 22310 22311 22312 22313 +v -22314 22315 -22316 22317 -22318 22319 22320 -22321 -22322 -22323 -22324 +v -22325 -22326 -22327 -22328 -22329 -22330 -22331 -22332 -22333 -22334 -22335 +v -22336 -22337 -22338 -22339 -22340 -22341 -22342 -22343 -22344 -22345 -22346 +v -22347 -22348 -22349 -22350 -22351 -22352 -22353 -22354 -22355 -22356 -22357 +v -22358 -22359 -22360 -22361 -22362 -22363 -22364 -22365 -22366 -22367 -22368 +v -22369 -22370 -22371 -22372 -22373 -22374 -22375 -22376 -22377 -22378 -22379 +v -22380 -22381 -22382 -22383 -22384 -22385 -22386 -22387 -22388 -22389 -22390 +v -22391 -22392 -22393 -22394 -22395 -22396 -22397 -22398 -22399 -22400 -22401 +v -22402 -22403 -22404 -22405 -22406 -22407 -22408 -22409 -22410 -22411 -22412 +v -22413 -22414 -22415 -22416 -22417 -22418 -22419 -22420 -22421 -22422 -22423 +v -22424 -22425 -22426 -22427 -22428 -22429 -22430 -22431 -22432 -22433 -22434 +v -22435 -22436 -22437 -22438 -22439 -22440 -22441 -22442 -22443 -22444 -22445 +v -22446 -22447 -22448 -22449 -22450 -22451 -22452 -22453 -22454 -22455 -22456 +v -22457 -22458 -22459 -22460 -22461 -22462 -22463 -22464 -22465 -22466 -22467 +v -22468 -22469 -22470 -22471 -22472 -22473 -22474 -22475 -22476 -22477 -22478 +v -22479 -22480 -22481 -22482 -22483 -22484 -22485 -22486 -22487 -22488 -22489 +v -22490 -22491 -22492 -22493 -22494 -22495 -22496 -22497 -22498 -22499 -22500 +v -22501 -22502 -22503 -22504 -22505 -22506 -22507 -22508 -22509 -22510 -22511 +v -22512 -22513 -22514 -22515 -22516 -22517 -22518 -22519 -22520 -22521 -22522 +v -22523 -22524 -22525 -22526 -22527 -22528 -22529 -22530 -22531 -22532 -22533 +v -22534 -22535 -22536 -22537 -22538 -22539 -22540 -22541 -22542 -22543 -22544 +v -22545 -22546 -22547 -22548 -22549 -22550 -22551 -22552 -22553 -22554 -22555 +v -22556 -22557 -22558 -22559 -22560 -22561 -22562 -22563 -22564 -22565 -22566 +v -22567 -22568 -22569 -22570 -22571 -22572 -22573 -22574 -22575 -22576 -22577 +v -22578 -22579 -22580 -22581 -22582 -22583 -22584 -22585 -22586 -22587 -22588 +v -22589 -22590 -22591 -22592 -22593 -22594 -22595 -22596 -22597 -22598 -22599 +v -22600 -22601 -22602 -22603 -22604 -22605 -22606 -22607 -22608 -22609 -22610 +v -22611 -22612 -22613 -22614 -22615 -22616 -22617 -22618 -22619 -22620 -22621 +v -22622 -22623 -22624 -22625 -22626 -22627 -22628 -22629 -22630 -22631 -22632 +v -22633 -22634 -22635 -22636 -22637 -22638 -22639 -22640 -22641 -22642 -22643 +v -22644 -22645 -22646 -22647 -22648 -22649 -22650 -22651 -22652 -22653 -22654 +v -22655 -22656 -22657 -22658 -22659 -22660 -22661 -22662 -22663 -22664 -22665 +v -22666 -22667 -22668 -22669 -22670 -22671 -22672 -22673 -22674 -22675 -22676 +v -22677 -22678 -22679 -22680 -22681 -22682 -22683 -22684 -22685 -22686 -22687 +v -22688 -22689 -22690 -22691 -22692 -22693 -22694 -22695 -22696 -22697 -22698 +v -22699 -22700 -22701 -22702 -22703 -22704 -22705 -22706 -22707 -22708 -22709 +v -22710 -22711 -22712 -22713 -22714 -22715 -22716 -22717 -22718 -22719 -22720 +v -22721 -22722 -22723 -22724 -22725 -22726 -22727 -22728 -22729 -22730 -22731 +v -22732 -22733 -22734 -22735 -22736 -22737 -22738 -22739 -22740 -22741 -22742 +v -22743 -22744 -22745 -22746 -22747 -22748 -22749 -22750 -22751 -22752 -22753 +v -22754 -22755 -22756 -22757 -22758 -22759 -22760 -22761 -22762 -22763 -22764 +v -22765 -22766 -22767 -22768 -22769 -22770 -22771 -22772 -22773 -22774 -22775 +v -22776 -22777 -22778 -22779 -22780 -22781 -22782 -22783 -22784 -22785 -22786 +v -22787 -22788 -22789 -22790 -22791 -22792 -22793 -22794 -22795 -22796 -22797 +v -22798 -22799 -22800 -22801 -22802 -22803 -22804 -22805 -22806 -22807 -22808 +v -22809 -22810 -22811 -22812 -22813 -22814 -22815 -22816 -22817 -22818 -22819 +v -22820 -22821 -22822 -22823 -22824 -22825 -22826 -22827 -22828 -22829 -22830 +v -22831 -22832 -22833 -22834 -22835 -22836 -22837 -22838 -22839 -22840 -22841 +v -22842 -22843 -22844 -22845 -22846 -22847 -22848 -22849 -22850 -22851 -22852 +v -22853 -22854 -22855 -22856 -22857 -22858 -22859 -22860 -22861 -22862 -22863 +v -22864 -22865 -22866 -22867 -22868 -22869 -22870 -22871 -22872 -22873 -22874 +v -22875 -22876 22877 -22878 22879 -22880 -22881 -22882 22883 -22884 22885 +v -22886 -22887 -22888 22889 -22890 22891 -22892 -22893 -22894 22895 -22896 +v 22897 -22898 -22899 -22900 22901 -22902 22903 -22904 -22905 -22906 22907 +v -22908 22909 -22910 -22911 22912 -22913 -22914 -22915 -22916 -22917 -22918 +v -22919 -22920 -22921 -22922 -22923 -22924 -22925 -22926 22927 22928 22929 +v 22930 22931 -22932 -22933 -22934 -22935 -22936 -22937 22938 -22939 -22940 +v -22941 -22942 -22943 -22944 -22945 -22946 -22947 -22948 -22949 -22950 -22951 +v -22952 -22953 -22954 -22955 -22956 -22957 -22958 -22959 -22960 -22961 -22962 +v -22963 -22964 -22965 -22966 -22967 -22968 -22969 -22970 -22971 -22972 -22973 +v -22974 -22975 -22976 -22977 -22978 -22979 -22980 -22981 -22982 -22983 -22984 +v -22985 -22986 -22987 -22988 -22989 -22990 -22991 -22992 -22993 -22994 -22995 +v -22996 -22997 -22998 -22999 -23000 -23001 -23002 -23003 -23004 -23005 -23006 +v -23007 -23008 -23009 -23010 -23011 -23012 -23013 -23014 -23015 -23016 -23017 +v -23018 -23019 -23020 -23021 -23022 -23023 -23024 -23025 -23026 -23027 -23028 +v -23029 -23030 -23031 -23032 -23033 -23034 -23035 -23036 -23037 -23038 -23039 +v -23040 -23041 -23042 -23043 -23044 -23045 -23046 -23047 -23048 -23049 -23050 +v -23051 -23052 -23053 -23054 -23055 -23056 -23057 -23058 -23059 -23060 -23061 +v -23062 -23063 -23064 -23065 -23066 -23067 23068 -23069 23070 -23071 -23072 +v -23073 23074 -23075 23076 -23077 -23078 -23079 23080 -23081 23082 -23083 +v -23084 -23085 23086 -23087 23088 -23089 -23090 -23091 23092 -23093 23094 +v -23095 -23096 23097 -23098 -23099 -23100 -23101 -23102 -23103 -23104 -23105 +v -23106 -23107 -23108 23109 23110 23111 -23112 -23113 -23114 -23115 -23116 +v -23117 -23118 -23119 -23120 -23121 -23122 -23123 -23124 -23125 -23126 -23127 +v -23128 -23129 -23130 -23131 -23132 -23133 -23134 -23135 -23136 -23137 -23138 +v -23139 -23140 -23141 -23142 -23143 -23144 -23145 -23146 -23147 -23148 -23149 +v -23150 -23151 -23152 -23153 -23154 -23155 -23156 -23157 -23158 -23159 -23160 +v -23161 -23162 -23163 -23164 23165 -23166 23167 -23168 -23169 23170 -23171 +v 23172 -23173 -23174 -23175 23176 -23177 23178 -23179 -23180 -23181 23182 +v -23183 23184 -23185 -23186 23187 -23188 -23189 -23190 -23191 -23192 -23193 +v -23194 -23195 -23196 -23197 23198 23199 23200 23201 -23202 -23203 -23204 +v -23205 -23206 -23207 -23208 -23209 -23210 -23211 -23212 -23213 -23214 -23215 +v -23216 -23217 -23218 -23219 -23220 -23221 -23222 -23223 -23224 -23225 -23226 +v -23227 -23228 -23229 -23230 -23231 -23232 -23233 -23234 -23235 -23236 -23237 +v -23238 -23239 -23240 -23241 -23242 -23243 -23244 -23245 -23246 -23247 -23248 +v -23249 -23250 -23251 -23252 -23253 -23254 -23255 -23256 -23257 -23258 -23259 +v -23260 -23261 -23262 -23263 -23264 -23265 -23266 -23267 -23268 -23269 -23270 +v -23271 -23272 -23273 -23274 -23275 -23276 -23277 -23278 -23279 -23280 -23281 +v -23282 -23283 -23284 -23285 -23286 -23287 -23288 -23289 -23290 -23291 -23292 +v -23293 -23294 -23295 -23296 23297 -23298 23299 -23300 -23301 23302 -23303 +v 23304 -23305 -23306 23307 -23308 23309 -23310 -23311 -23312 23313 -23314 +v 23315 -23316 -23317 -23318 23319 -23320 23321 -23322 -23323 23324 -23325 +v -23326 -23327 -23328 -23329 -23330 -23331 -23332 -23333 -23334 -23335 23336 +v 23337 23338 -23339 -23340 -23341 -23342 -23343 -23344 -23345 -23346 -23347 +v -23348 -23349 -23350 -23351 23352 -23353 -23354 23355 -23356 -23357 -23358 +v -23359 -23360 -23361 23362 23363 23364 -23365 -23366 23367 23368 23369 23370 +v 23371 23372 23373 23374 23375 23376 -23377 -23378 23379 23380 23381 23382 +v 23383 23384 -23385 23386 23387 23388 -23389 -23390 -23391 -23392 -23393 +v -23394 23395 -23396 23397 23398 -23399 -23400 -23401 -23402 -23403 -23404 +v -23405 -23406 -23407 -23408 23409 -23410 -23411 -23412 23413 -23414 -23415 +v 23416 23417 23418 23419 23420 23421 23422 23423 23424 23425 -23426 -23427 +v 23428 23429 23430 23431 23432 23433 -23434 23435 23436 -23437 -23438 23439 +v 23440 23441 23442 -23443 -23444 23445 23446 -23447 -23448 -23449 23450 -23451 +v 23452 -23453 -23454 23455 -23456 -23457 -23458 -23459 -23460 -23461 -23462 +v -23463 23464 23465 23466 -23467 -23468 -23469 -23470 -23471 -23472 -23473 +v -23474 -23475 -23476 -23477 -23478 -23479 -23480 -23481 -23482 -23483 -23484 +v -23485 -23486 -23487 -23488 23489 -23490 -23491 -23492 -23493 -23494 -23495 +v -23496 23497 -23498 23499 -23500 -23501 -23502 23503 -23504 23505 -23506 +v -23507 23508 -23509 -23510 -23511 -23512 -23513 -23514 23515 23516 23517 +v -23518 -23519 -23520 -23521 -23522 -23523 -23524 -23525 -23526 -23527 -23528 +v -23529 -23530 -23531 -23532 -23533 -23534 -23535 -23536 -23537 -23538 -23539 +v 23540 -23541 -23542 -23543 -23544 -23545 -23546 -23547 23548 -23549 23550 +v -23551 -23552 -23553 23554 -23555 23556 -23557 -23558 23559 -23560 -23561 +v -23562 -23563 -23564 -23565 23566 23567 23568 -23569 -23570 -23571 -23572 +v -23573 -23574 -23575 -23576 -23577 -23578 -23579 -23580 -23581 -23582 -23583 +v -23584 -23585 -23586 -23587 -23588 -23589 -23590 23591 -23592 -23593 -23594 +v -23595 -23596 -23597 -23598 23599 -23600 23601 -23602 -23603 -23604 23605 +v -23606 23607 -23608 -23609 23610 -23611 -23612 -23613 -23614 -23615 -23616 +v 23617 23618 23619 -23620 -23621 -23622 -23623 -23624 -23625 -23626 -23627 +v -23628 -23629 -23630 -23631 -23632 -23633 -23634 -23635 -23636 -23637 -23638 +v -23639 -23640 -23641 -23642 -23643 -23644 -23645 -23646 -23647 -23648 -23649 +v -23650 -23651 -23652 -23653 -23654 -23655 -23656 -23657 -23658 -23659 -23660 +v -23661 -23662 -23663 -23664 -23665 -23666 -23667 -23668 -23669 -23670 -23671 +v -23672 -23673 -23674 -23675 -23676 -23677 -23678 -23679 -23680 -23681 -23682 +v -23683 -23684 -23685 -23686 -23687 -23688 -23689 -23690 -23691 -23692 -23693 +v -23694 -23695 -23696 -23697 -23698 -23699 -23700 -23701 -23702 -23703 -23704 +v -23705 -23706 -23707 -23708 -23709 -23710 -23711 -23712 23713 -23714 -23715 +v -23716 -23717 -23718 -23719 -23720 -23721 -23722 -23723 -23724 -23725 -23726 +v -23727 -23728 -23729 -23730 -23731 -23732 -23733 -23734 -23735 -23736 -23737 +v -23738 -23739 -23740 -23741 -23742 -23743 -23744 -23745 -23746 -23747 -23748 +v -23749 -23750 -23751 -23752 -23753 -23754 -23755 -23756 -23757 -23758 -23759 +v -23760 -23761 -23762 -23763 -23764 -23765 -23766 -23767 -23768 -23769 -23770 +v -23771 -23772 -23773 -23774 -23775 -23776 -23777 -23778 -23779 -23780 -23781 +v 23782 -23783 23784 -23785 -23786 -23787 23788 -23789 23790 -23791 -23792 +v -23793 -23794 23795 -23796 23797 -23798 -23799 -23800 -23801 23802 -23803 +v 23804 -23805 -23806 23807 -23808 -23809 -23810 -23811 -23812 -23813 -23814 +v -23815 -23816 -23817 23818 23819 23820 -23821 -23822 -23823 -23824 -23825 +v -23826 -23827 -23828 -23829 -23830 -23831 -23832 -23833 -23834 -23835 -23836 +v -23837 -23838 -23839 -23840 -23841 -23842 -23843 -23844 -23845 -23846 -23847 +v -23848 -23849 -23850 -23851 -23852 -23853 -23854 -23855 -23856 -23857 -23858 +v -23859 -23860 -23861 -23862 -23863 -23864 -23865 -23866 -23867 -23868 -23869 +v -23870 -23871 -23872 -23873 -23874 -23875 -23876 -23877 -23878 -23879 -23880 +v -23881 -23882 -23883 -23884 -23885 -23886 -23887 -23888 -23889 -23890 -23891 +v -23892 -23893 -23894 -23895 -23896 -23897 -23898 -23899 -23900 -23901 -23902 +v -23903 -23904 -23905 -23906 -23907 -23908 -23909 -23910 -23911 -23912 -23913 +v 23914 -23915 -23916 -23917 -23918 -23919 -23920 -23921 -23922 -23923 -23924 +v -23925 -23926 -23927 -23928 -23929 -23930 -23931 -23932 -23933 -23934 -23935 +v -23936 -23937 -23938 -23939 -23940 -23941 -23942 -23943 -23944 -23945 -23946 +v -23947 -23948 -23949 -23950 -23951 -23952 -23953 -23954 -23955 -23956 -23957 +v -23958 -23959 -23960 -23961 -23962 -23963 -23964 -23965 -23966 -23967 -23968 +v -23969 -23970 -23971 -23972 -23973 -23974 -23975 -23976 -23977 -23978 -23979 +v -23980 -23981 -23982 23983 -23984 23985 -23986 -23987 -23988 23989 -23990 +v 23991 -23992 -23993 -23994 -23995 23996 -23997 23998 -23999 -24000 -24001 +v -24002 24003 -24004 24005 -24006 -24007 24008 -24009 -24010 -24011 -24012 +v -24013 -24014 -24015 -24016 -24017 -24018 24019 24020 24021 -24022 -24023 +v -24024 -24025 -24026 -24027 -24028 -24029 -24030 -24031 -24032 -24033 -24034 +v -24035 -24036 -24037 -24038 -24039 -24040 -24041 -24042 -24043 -24044 -24045 +v -24046 -24047 -24048 -24049 -24050 -24051 -24052 -24053 -24054 -24055 -24056 +v -24057 -24058 -24059 -24060 -24061 -24062 -24063 -24064 -24065 -24066 -24067 +v -24068 -24069 -24070 -24071 -24072 -24073 -24074 -24075 -24076 -24077 -24078 +v -24079 -24080 -24081 -24082 -24083 -24084 -24085 -24086 -24087 -24088 -24089 +v -24090 -24091 -24092 -24093 -24094 -24095 -24096 -24097 -24098 -24099 -24100 +v -24101 -24102 -24103 -24104 -24105 -24106 -24107 -24108 -24109 -24110 -24111 +v -24112 -24113 -24114 24115 -24116 -24117 -24118 -24119 -24120 -24121 -24122 +v -24123 -24124 -24125 -24126 -24127 -24128 -24129 -24130 -24131 -24132 -24133 +v -24134 -24135 -24136 -24137 -24138 -24139 -24140 -24141 -24142 -24143 -24144 +v -24145 -24146 -24147 -24148 -24149 -24150 -24151 -24152 -24153 -24154 -24155 +v -24156 -24157 -24158 -24159 -24160 -24161 -24162 -24163 -24164 -24165 -24166 +v -24167 -24168 -24169 -24170 -24171 -24172 -24173 -24174 -24175 -24176 -24177 +v -24178 -24179 -24180 -24181 -24182 -24183 24184 -24185 24186 -24187 -24188 +v -24189 24190 -24191 24192 -24193 -24194 -24195 -24196 24197 -24198 24199 +v -24200 -24201 -24202 -24203 24204 -24205 24206 -24207 -24208 24209 -24210 +v -24211 -24212 -24213 -24214 -24215 -24216 -24217 -24218 -24219 24220 24221 +v 24222 -24223 -24224 -24225 -24226 -24227 -24228 -24229 -24230 -24231 -24232 +v -24233 -24234 -24235 -24236 -24237 -24238 -24239 -24240 -24241 -24242 -24243 +v -24244 -24245 -24246 -24247 -24248 -24249 -24250 -24251 -24252 -24253 -24254 +v -24255 -24256 -24257 -24258 -24259 -24260 -24261 -24262 -24263 -24264 -24265 +v -24266 -24267 -24268 -24269 -24270 -24271 -24272 -24273 -24274 -24275 -24276 +v -24277 -24278 -24279 -24280 -24281 -24282 -24283 -24284 -24285 -24286 -24287 +v -24288 -24289 -24290 -24291 -24292 -24293 -24294 -24295 -24296 -24297 -24298 +v -24299 -24300 -24301 -24302 -24303 -24304 -24305 -24306 -24307 -24308 -24309 +v -24310 -24311 -24312 -24313 -24314 -24315 24316 -24317 -24318 -24319 -24320 +v -24321 -24322 -24323 -24324 -24325 -24326 -24327 -24328 -24329 -24330 -24331 +v -24332 -24333 -24334 -24335 -24336 -24337 -24338 -24339 -24340 -24341 -24342 +v -24343 -24344 -24345 -24346 -24347 -24348 -24349 -24350 -24351 -24352 -24353 +v -24354 -24355 -24356 -24357 -24358 -24359 -24360 -24361 -24362 -24363 -24364 +v -24365 -24366 -24367 -24368 -24369 -24370 -24371 -24372 -24373 -24374 -24375 +v -24376 -24377 -24378 -24379 -24380 -24381 -24382 -24383 -24384 24385 -24386 +v 24387 -24388 -24389 -24390 24391 -24392 24393 -24394 -24395 -24396 -24397 +v 24398 -24399 24400 -24401 -24402 -24403 -24404 24405 -24406 24407 -24408 +v -24409 24410 -24411 -24412 -24413 -24414 -24415 -24416 -24417 -24418 -24419 +v -24420 24421 24422 24423 -24424 -24425 -24426 -24427 -24428 -24429 -24430 +v -24431 -24432 -24433 -24434 -24435 -24436 -24437 -24438 -24439 -24440 -24441 +v -24442 -24443 -24444 -24445 24446 -24447 -24448 -24449 -24450 -24451 -24452 +v -24453 24454 -24455 24456 -24457 -24458 -24459 24460 -24461 24462 -24463 +v -24464 24465 -24466 -24467 -24468 -24469 -24470 -24471 24472 24473 24474 +v -24475 -24476 -24477 -24478 -24479 -24480 -24481 -24482 -24483 -24484 -24485 +v -24486 -24487 -24488 -24489 -24490 -24491 -24492 -24493 -24494 -24495 -24496 +v -24497 -24498 -24499 -24500 -24501 -24502 -24503 24504 -24505 24506 -24507 +v -24508 -24509 24510 -24511 24512 -24513 -24514 24515 -24516 -24517 -24518 +v -24519 -24520 -24521 24522 24523 24524 24525 -24526 -24527 -24528 -24529 +v -24530 -24531 -24532 -24533 -24534 -24535 -24536 -24537 -24538 -24539 -24540 +v -24541 -24542 -24543 -24544 -24545 -24546 -24547 -24548 -24549 -24550 -24551 +v -24552 -24553 -24554 24555 -24556 24557 -24558 -24559 -24560 24561 -24562 +v 24563 -24564 -24565 24566 -24567 -24568 -24569 -24570 -24571 -24572 24573 +v 24574 24575 24576 -24577 -24578 -24579 -24580 -24581 -24582 -24583 -24584 +v -24585 -24586 -24587 -24588 -24589 -24590 -24591 -24592 -24593 -24594 -24595 +v -24596 -24597 -24598 -24599 -24600 -24601 -24602 -24603 -24604 -24605 24606 +v -24607 24608 -24609 -24610 -24611 24612 -24613 24614 -24615 -24616 24617 +v -24618 -24619 -24620 -24621 -24622 -24623 24624 24625 24626 24627 -24628 +v -24629 -24630 -24631 -24632 -24633 -24634 -24635 -24636 -24637 -24638 -24639 +v -24640 -24641 -24642 -24643 -24644 -24645 -24646 -24647 -24648 -24649 -24650 +v -24651 -24652 -24653 -24654 -24655 -24656 -24657 -24658 -24659 -24660 -24661 +v -24662 -24663 -24664 -24665 -24666 -24667 -24668 -24669 -24670 -24671 -24672 +v -24673 -24674 -24675 -24676 -24677 -24678 -24679 -24680 -24681 -24682 -24683 +v -24684 -24685 -24686 -24687 -24688 -24689 -24690 -24691 -24692 -24693 -24694 +v -24695 -24696 -24697 -24698 -24699 -24700 -24701 -24702 -24703 -24704 -24705 +v -24706 -24707 -24708 -24709 -24710 -24711 -24712 -24713 -24714 -24715 -24716 +v -24717 -24718 -24719 -24720 -24721 -24722 -24723 -24724 -24725 -24726 -24727 +v -24728 -24729 -24730 -24731 -24732 -24733 -24734 -24735 -24736 -24737 -24738 +v -24739 -24740 -24741 -24742 -24743 -24744 -24745 -24746 -24747 -24748 -24749 +v -24750 -24751 -24752 -24753 -24754 -24755 -24756 -24757 -24758 -24759 -24760 +v -24761 -24762 -24763 -24764 -24765 -24766 -24767 -24768 -24769 -24770 -24771 +v -24772 -24773 -24774 -24775 -24776 -24777 -24778 -24779 -24780 -24781 -24782 +v -24783 -24784 -24785 -24786 -24787 -24788 24789 -24790 24791 -24792 -24793 +v -24794 24795 -24796 24797 -24798 -24799 -24800 -24801 24802 -24803 24804 +v -24805 -24806 -24807 -24808 24809 -24810 24811 -24812 -24813 24814 -24815 +v -24816 -24817 -24818 -24819 -24820 -24821 -24822 -24823 -24824 24825 24826 +v 24827 24828 -24829 -24830 -24831 -24832 -24833 -24834 -24835 -24836 -24837 +v -24838 -24839 -24840 -24841 -24842 -24843 -24844 -24845 -24846 -24847 -24848 +v -24849 -24850 -24851 -24852 -24853 -24854 -24855 -24856 -24857 -24858 -24859 +v -24860 -24861 -24862 -24863 -24864 -24865 -24866 -24867 -24868 -24869 -24870 +v -24871 -24872 -24873 -24874 -24875 -24876 -24877 -24878 -24879 -24880 -24881 +v -24882 -24883 -24884 -24885 -24886 -24887 -24888 -24889 -24890 -24891 -24892 +v -24893 -24894 -24895 -24896 -24897 -24898 -24899 -24900 -24901 -24902 -24903 +v -24904 -24905 -24906 -24907 -24908 -24909 -24910 -24911 -24912 -24913 -24914 +v -24915 -24916 -24917 -24918 -24919 -24920 -24921 -24922 -24923 -24924 -24925 +v -24926 -24927 -24928 -24929 -24930 -24931 -24932 -24933 -24934 -24935 -24936 +v -24937 -24938 -24939 -24940 -24941 -24942 -24943 -24944 -24945 -24946 -24947 +v -24948 -24949 -24950 -24951 -24952 -24953 -24954 -24955 -24956 -24957 -24958 +v -24959 -24960 -24961 -24962 -24963 -24964 -24965 -24966 -24967 -24968 -24969 +v -24970 -24971 -24972 -24973 -24974 -24975 -24976 -24977 -24978 -24979 -24980 +v -24981 -24982 -24983 -24984 -24985 -24986 -24987 -24988 -24989 24990 -24991 +v 24992 -24993 -24994 -24995 24996 -24997 24998 -24999 -25000 -25001 -25002 +v 25003 -25004 25005 -25006 -25007 -25008 -25009 25010 -25011 25012 -25013 +v -25014 25015 -25016 -25017 -25018 -25019 -25020 -25021 -25022 -25023 -25024 +v -25025 25026 25027 25028 25029 -25030 -25031 -25032 -25033 -25034 -25035 +v -25036 -25037 -25038 -25039 -25040 -25041 -25042 -25043 -25044 -25045 -25046 +v -25047 -25048 -25049 -25050 -25051 -25052 -25053 -25054 -25055 -25056 -25057 +v -25058 -25059 -25060 -25061 -25062 -25063 -25064 -25065 -25066 -25067 -25068 +v -25069 -25070 -25071 -25072 -25073 -25074 -25075 -25076 -25077 -25078 -25079 +v -25080 -25081 -25082 -25083 -25084 -25085 -25086 -25087 -25088 -25089 -25090 +v -25091 -25092 -25093 -25094 -25095 -25096 -25097 -25098 -25099 -25100 -25101 +v -25102 -25103 -25104 -25105 -25106 -25107 -25108 -25109 -25110 -25111 -25112 +v -25113 -25114 -25115 -25116 -25117 -25118 -25119 -25120 -25121 -25122 -25123 +v -25124 -25125 -25126 -25127 -25128 -25129 -25130 -25131 -25132 -25133 -25134 +v -25135 -25136 -25137 -25138 -25139 -25140 -25141 -25142 -25143 -25144 -25145 +v -25146 -25147 -25148 -25149 -25150 -25151 -25152 -25153 -25154 -25155 -25156 +v -25157 -25158 -25159 -25160 -25161 -25162 -25163 -25164 -25165 -25166 -25167 +v -25168 -25169 -25170 -25171 -25172 -25173 -25174 -25175 -25176 -25177 -25178 +v -25179 -25180 -25181 -25182 -25183 -25184 -25185 -25186 -25187 -25188 -25189 +v -25190 25191 -25192 25193 -25194 -25195 -25196 25197 -25198 25199 -25200 +v -25201 -25202 -25203 25204 -25205 25206 -25207 -25208 -25209 -25210 25211 +v -25212 25213 -25214 -25215 25216 -25217 -25218 -25219 -25220 -25221 -25222 +v -25223 -25224 -25225 -25226 25227 25228 25229 25230 -25231 -25232 -25233 +v -25234 -25235 -25236 -25237 -25238 -25239 -25240 -25241 -25242 -25243 -25244 +v -25245 -25246 -25247 -25248 -25249 -25250 -25251 -25252 -25253 -25254 -25255 +v -25256 -25257 -25258 -25259 -25260 -25261 -25262 -25263 -25264 -25265 -25266 +v -25267 -25268 -25269 -25270 -25271 -25272 -25273 -25274 -25275 -25276 -25277 +v -25278 -25279 -25280 -25281 -25282 -25283 -25284 -25285 -25286 -25287 -25288 +v -25289 -25290 -25291 -25292 -25293 -25294 -25295 -25296 -25297 -25298 -25299 +v -25300 -25301 -25302 -25303 -25304 -25305 -25306 -25307 -25308 -25309 -25310 +v -25311 -25312 -25313 -25314 -25315 -25316 -25317 -25318 -25319 -25320 -25321 +v -25322 -25323 -25324 -25325 -25326 -25327 -25328 -25329 -25330 -25331 -25332 +v -25333 -25334 -25335 -25336 -25337 -25338 -25339 -25340 -25341 -25342 -25343 +v -25344 -25345 -25346 -25347 -25348 -25349 -25350 -25351 -25352 -25353 -25354 +v -25355 -25356 -25357 -25358 -25359 -25360 -25361 -25362 -25363 -25364 -25365 +v -25366 -25367 -25368 -25369 -25370 -25371 -25372 -25373 -25374 -25375 -25376 +v -25377 -25378 -25379 -25380 -25381 -25382 -25383 -25384 -25385 -25386 -25387 +v -25388 -25389 -25390 -25391 25392 -25393 25394 -25395 -25396 -25397 25398 +v -25399 25400 -25401 -25402 -25403 -25404 25405 -25406 25407 -25408 -25409 +v -25410 -25411 25412 -25413 25414 -25415 -25416 25417 -25418 -25419 -25420 +v -25421 -25422 -25423 -25424 -25425 -25426 -25427 25428 25429 25430 25431 +v -25432 -25433 -25434 -25435 -25436 -25437 -25438 -25439 -25440 -25441 -25442 +v -25443 -25444 -25445 -25446 -25447 -25448 -25449 -25450 -25451 -25452 -25453 +v -25454 -25455 -25456 -25457 -25458 -25459 -25460 25461 -25462 25463 -25464 +v -25465 -25466 25467 -25468 25469 -25470 -25471 25472 -25473 -25474 -25475 +v -25476 -25477 -25478 25479 25480 25481 25482 -25483 25484 -25485 25486 -25487 +v 25488 25489 -25490 -25491 -25492 -25493 -25494 -25495 -25496 -25497 -25498 +v -25499 -25500 -25501 -25502 -25503 -25504 -25505 -25506 -25507 -25508 -25509 +v -25510 -25511 -25512 -25513 -25514 -25515 -25516 -25517 -25518 -25519 -25520 +v -25521 -25522 -25523 -25524 -25525 -25526 -25527 -25528 -25529 -25530 -25531 +v -25532 -25533 -25534 -25535 -25536 -25537 -25538 -25539 -25540 -25541 -25542 +v -25543 -25544 -25545 -25546 -25547 -25548 -25549 -25550 -25551 -25552 -25553 +v -25554 -25555 -25556 -25557 -25558 -25559 -25560 -25561 -25562 -25563 -25564 +v -25565 -25566 -25567 -25568 -25569 -25570 -25571 -25572 -25573 -25574 -25575 +v -25576 -25577 -25578 -25579 -25580 -25581 -25582 -25583 -25584 -25585 -25586 +v -25587 -25588 -25589 -25590 -25591 -25592 -25593 -25594 -25595 -25596 -25597 +v -25598 -25599 -25600 -25601 -25602 -25603 -25604 -25605 -25606 -25607 -25608 +v -25609 -25610 -25611 -25612 -25613 -25614 -25615 -25616 -25617 -25618 -25619 +v -25620 -25621 -25622 -25623 -25624 -25625 -25626 -25627 -25628 -25629 -25630 +v -25631 -25632 -25633 -25634 -25635 -25636 -25637 -25638 -25639 -25640 -25641 +v -25642 -25643 -25644 -25645 -25646 -25647 -25648 -25649 -25650 -25651 -25652 +v -25653 -25654 -25655 -25656 -25657 -25658 -25659 -25660 -25661 -25662 -25663 +v -25664 -25665 -25666 -25667 -25668 -25669 -25670 -25671 -25672 -25673 -25674 +v -25675 -25676 -25677 -25678 -25679 -25680 -25681 -25682 -25683 -25684 -25685 +v -25686 -25687 -25688 -25689 -25690 -25691 -25692 -25693 -25694 -25695 -25696 +v -25697 -25698 -25699 -25700 -25701 -25702 -25703 -25704 -25705 -25706 -25707 +v -25708 -25709 -25710 -25711 -25712 -25713 -25714 -25715 -25716 -25717 -25718 +v -25719 -25720 -25721 -25722 -25723 -25724 -25725 -25726 -25727 -25728 -25729 +v -25730 -25731 -25732 -25733 -25734 -25735 -25736 -25737 -25738 -25739 -25740 +v -25741 -25742 -25743 -25744 -25745 -25746 -25747 -25748 -25749 -25750 -25751 +v -25752 -25753 -25754 -25755 -25756 -25757 -25758 -25759 -25760 -25761 -25762 +v -25763 -25764 -25765 -25766 -25767 -25768 -25769 -25770 -25771 -25772 -25773 +v -25774 -25775 -25776 -25777 -25778 -25779 -25780 -25781 -25782 -25783 -25784 +v -25785 -25786 -25787 -25788 -25789 -25790 -25791 -25792 -25793 -25794 -25795 +v -25796 -25797 -25798 -25799 -25800 -25801 -25802 -25803 -25804 -25805 -25806 +v -25807 -25808 -25809 -25810 -25811 -25812 -25813 -25814 -25815 -25816 -25817 +v -25818 -25819 -25820 -25821 -25822 -25823 -25824 -25825 -25826 -25827 -25828 +v -25829 -25830 -25831 -25832 -25833 -25834 -25835 -25836 -25837 -25838 -25839 +v -25840 -25841 -25842 -25843 -25844 -25845 -25846 -25847 -25848 -25849 -25850 +v -25851 -25852 -25853 -25854 -25855 -25856 -25857 -25858 -25859 -25860 -25861 +v -25862 -25863 -25864 -25865 -25866 -25867 -25868 -25869 -25870 -25871 -25872 +v -25873 -25874 -25875 -25876 -25877 -25878 -25879 -25880 -25881 -25882 -25883 +v -25884 -25885 -25886 -25887 -25888 -25889 -25890 -25891 -25892 -25893 -25894 +v -25895 -25896 -25897 -25898 -25899 -25900 -25901 -25902 -25903 -25904 -25905 +v -25906 -25907 -25908 -25909 -25910 -25911 -25912 -25913 -25914 -25915 -25916 +v -25917 -25918 -25919 -25920 -25921 -25922 -25923 -25924 -25925 -25926 -25927 +v -25928 -25929 -25930 -25931 -25932 -25933 -25934 -25935 -25936 -25937 -25938 +v -25939 -25940 -25941 -25942 -25943 -25944 -25945 -25946 -25947 -25948 -25949 +v -25950 -25951 -25952 -25953 -25954 -25955 -25956 -25957 -25958 -25959 -25960 +v -25961 -25962 -25963 -25964 -25965 -25966 -25967 -25968 -25969 -25970 -25971 +v -25972 -25973 -25974 -25975 -25976 -25977 -25978 -25979 -25980 -25981 -25982 +v -25983 -25984 -25985 -25986 -25987 -25988 -25989 -25990 -25991 -25992 -25993 +v -25994 -25995 -25996 -25997 -25998 -25999 -26000 -26001 -26002 -26003 -26004 +v -26005 -26006 -26007 -26008 -26009 -26010 -26011 -26012 -26013 -26014 -26015 +v -26016 -26017 -26018 -26019 -26020 -26021 -26022 -26023 -26024 -26025 -26026 +v -26027 -26028 26029 -26030 26031 -26032 -26033 26034 -26035 26036 -26037 +v -26038 26039 -26040 26041 -26042 -26043 -26044 26045 -26046 26047 -26048 +v -26049 -26050 26051 -26052 26053 -26054 -26055 -26056 26057 -26058 26059 +v -26060 -26061 26062 -26063 -26064 -26065 -26066 -26067 -26068 -26069 -26070 +v -26071 -26072 -26073 -26074 -26075 -26076 26077 26078 26079 26080 26081 +v -26082 -26083 -26084 -26085 -26086 -26087 26088 -26089 -26090 -26091 -26092 +v -26093 -26094 -26095 -26096 -26097 -26098 -26099 -26100 -26101 -26102 -26103 +v -26104 -26105 -26106 -26107 -26108 -26109 -26110 -26111 -26112 -26113 -26114 +v -26115 -26116 -26117 -26118 -26119 -26120 -26121 -26122 -26123 -26124 -26125 +v -26126 -26127 -26128 -26129 -26130 -26131 -26132 -26133 -26134 -26135 -26136 +v -26137 -26138 -26139 -26140 -26141 -26142 -26143 -26144 -26145 -26146 -26147 +v -26148 -26149 -26150 -26151 -26152 -26153 -26154 -26155 -26156 -26157 -26158 +v -26159 -26160 -26161 -26162 -26163 -26164 -26165 -26166 -26167 -26168 -26169 +v -26170 -26171 -26172 -26173 -26174 -26175 -26176 -26177 -26178 -26179 -26180 +v -26181 -26182 -26183 -26184 -26185 -26186 -26187 -26188 -26189 -26190 -26191 +v -26192 -26193 -26194 -26195 -26196 -26197 -26198 -26199 -26200 -26201 -26202 +v -26203 -26204 -26205 -26206 -26207 -26208 -26209 -26210 -26211 -26212 -26213 +v -26214 -26215 -26216 -26217 26218 -26219 26220 -26221 -26222 -26223 26224 +v -26225 26226 -26227 -26228 -26229 26230 -26231 26232 -26233 -26234 -26235 +v 26236 -26237 26238 -26239 -26240 -26241 26242 -26243 26244 -26245 -26246 +v 26247 -26248 -26249 -26250 -26251 -26252 -26253 -26254 -26255 -26256 -26257 +v -26258 26259 26260 26261 -26262 -26263 -26264 -26265 -26266 -26267 -26268 +v -26269 -26270 -26271 -26272 -26273 -26274 -26275 -26276 -26277 -26278 -26279 +v -26280 -26281 -26282 -26283 -26284 -26285 -26286 -26287 -26288 -26289 -26290 +v -26291 -26292 -26293 -26294 -26295 -26296 -26297 -26298 -26299 -26300 -26301 +v -26302 -26303 -26304 -26305 -26306 -26307 -26308 -26309 -26310 -26311 -26312 +v -26313 -26314 26315 -26316 26317 -26318 -26319 26320 -26321 26322 -26323 +v -26324 -26325 26326 -26327 26328 -26329 -26330 -26331 26332 -26333 26334 +v -26335 -26336 26337 -26338 -26339 -26340 -26341 -26342 -26343 -26344 -26345 +v -26346 -26347 26348 26349 26350 26351 -26352 -26353 -26354 -26355 -26356 +v -26357 -26358 -26359 -26360 -26361 -26362 -26363 -26364 -26365 -26366 -26367 +v -26368 -26369 -26370 -26371 -26372 -26373 -26374 -26375 -26376 -26377 -26378 +v -26379 -26380 -26381 -26382 -26383 -26384 -26385 -26386 -26387 -26388 -26389 +v -26390 -26391 -26392 -26393 -26394 -26395 -26396 -26397 -26398 -26399 -26400 +v -26401 -26402 -26403 -26404 -26405 -26406 -26407 -26408 -26409 -26410 -26411 +v -26412 -26413 -26414 -26415 -26416 -26417 -26418 -26419 -26420 -26421 26422 +v -26423 -26424 -26425 -26426 -26427 -26428 -26429 -26430 -26431 -26432 -26433 +v -26434 -26435 -26436 -26437 -26438 -26439 -26440 -26441 -26442 -26443 -26444 +v -26445 -26446 -26447 -26448 -26449 26450 -26451 26452 -26453 -26454 -26455 +v 26456 -26457 26458 -26459 -26460 -26461 26462 -26463 26464 -26465 -26466 +v -26467 26468 -26469 26470 -26471 -26472 26473 -26474 -26475 -26476 -26477 +v -26478 -26479 -26480 -26481 -26482 -26483 26484 26485 26486 -26487 -26488 +v -26489 -26490 -26491 -26492 -26493 -26494 -26495 -26496 -26497 -26498 -26499 +v 26500 -26501 -26502 26503 -26504 -26505 -26506 -26507 -26508 -26509 26510 +v 26511 26512 -26513 -26514 26515 26516 26517 26518 26519 26520 26521 26522 +v 26523 26524 -26525 -26526 26527 26528 26529 26530 26531 26532 -26533 26534 +v 26535 26536 -26537 -26538 -26539 -26540 -26541 -26542 26543 -26544 26545 +v 26546 -26547 -26548 -26549 -26550 -26551 -26552 -26553 -26554 -26555 -26556 +v 26557 -26558 -26559 -26560 26561 -26562 -26563 26564 26565 26566 26567 26568 +v 26569 26570 26571 26572 26573 -26574 -26575 26576 26577 26578 26579 26580 +v 26581 -26582 26583 26584 -26585 -26586 26587 26588 26589 26590 -26591 -26592 +v 26593 26594 -26595 -26596 -26597 26598 -26599 26600 -26601 -26602 26603 +v -26604 -26605 -26606 -26607 -26608 -26609 -26610 -26611 26612 26613 26614 +v -26615 -26616 -26617 -26618 -26619 -26620 -26621 -26622 -26623 -26624 -26625 +v -26626 -26627 -26628 -26629 -26630 -26631 -26632 -26633 -26634 -26635 -26636 +v 26637 -26638 -26639 -26640 -26641 -26642 -26643 -26644 26645 -26646 26647 +v -26648 -26649 -26650 26651 -26652 26653 -26654 -26655 26656 -26657 -26658 +v -26659 -26660 -26661 -26662 26663 26664 26665 -26666 -26667 -26668 -26669 +v -26670 -26671 -26672 -26673 -26674 -26675 -26676 -26677 -26678 -26679 -26680 +v -26681 -26682 -26683 -26684 -26685 -26686 -26687 26688 -26689 -26690 -26691 +v -26692 -26693 -26694 -26695 26696 -26697 26698 -26699 -26700 -26701 26702 +v -26703 26704 -26705 -26706 26707 -26708 -26709 -26710 -26711 -26712 -26713 +v 26714 26715 26716 -26717 -26718 -26719 -26720 -26721 -26722 -26723 -26724 +v -26725 -26726 -26727 -26728 -26729 -26730 -26731 -26732 -26733 -26734 -26735 +v -26736 -26737 -26738 26739 -26740 -26741 -26742 -26743 -26744 -26745 -26746 +v 26747 -26748 26749 -26750 -26751 -26752 26753 -26754 26755 -26756 -26757 +v 26758 -26759 -26760 -26761 -26762 -26763 -26764 26765 26766 26767 -26768 +v -26769 -26770 -26771 -26772 -26773 -26774 -26775 -26776 -26777 -26778 -26779 +v -26780 -26781 -26782 -26783 -26784 -26785 -26786 -26787 -26788 -26789 -26790 +v -26791 -26792 -26793 -26794 -26795 -26796 -26797 -26798 -26799 -26800 -26801 +v -26802 -26803 -26804 -26805 -26806 -26807 -26808 -26809 -26810 -26811 -26812 +v -26813 -26814 -26815 -26816 -26817 -26818 -26819 -26820 -26821 -26822 -26823 +v -26824 -26825 -26826 -26827 -26828 -26829 -26830 -26831 -26832 -26833 -26834 +v -26835 -26836 -26837 -26838 -26839 -26840 -26841 -26842 -26843 -26844 -26845 +v -26846 -26847 -26848 -26849 -26850 -26851 -26852 -26853 -26854 -26855 -26856 +v -26857 -26858 -26859 -26860 26861 -26862 -26863 -26864 -26865 -26866 -26867 +v -26868 -26869 -26870 -26871 -26872 -26873 -26874 -26875 -26876 -26877 -26878 +v -26879 -26880 -26881 -26882 -26883 -26884 -26885 -26886 -26887 -26888 -26889 +v -26890 -26891 -26892 -26893 -26894 -26895 -26896 -26897 -26898 -26899 -26900 +v -26901 -26902 -26903 -26904 -26905 -26906 -26907 -26908 -26909 -26910 -26911 +v -26912 -26913 -26914 -26915 -26916 -26917 -26918 -26919 -26920 -26921 -26922 +v -26923 -26924 -26925 -26926 -26927 -26928 -26929 26930 -26931 26932 -26933 +v -26934 -26935 26936 -26937 26938 -26939 -26940 -26941 -26942 26943 -26944 +v 26945 -26946 -26947 -26948 -26949 26950 -26951 26952 -26953 -26954 26955 +v -26956 -26957 -26958 -26959 -26960 -26961 -26962 -26963 -26964 -26965 26966 +v 26967 26968 -26969 -26970 -26971 -26972 -26973 -26974 -26975 -26976 -26977 +v -26978 -26979 -26980 -26981 -26982 -26983 -26984 -26985 -26986 -26987 -26988 +v -26989 -26990 -26991 -26992 -26993 -26994 -26995 -26996 -26997 -26998 -26999 +v -27000 -27001 -27002 -27003 -27004 -27005 -27006 -27007 -27008 -27009 -27010 +v -27011 -27012 -27013 -27014 -27015 -27016 -27017 -27018 -27019 -27020 -27021 +v -27022 -27023 -27024 -27025 -27026 -27027 -27028 -27029 -27030 -27031 -27032 +v -27033 -27034 -27035 -27036 -27037 -27038 -27039 -27040 -27041 -27042 -27043 +v -27044 -27045 -27046 -27047 -27048 -27049 -27050 -27051 -27052 -27053 -27054 +v -27055 -27056 -27057 -27058 -27059 -27060 -27061 27062 -27063 -27064 -27065 +v -27066 -27067 -27068 -27069 -27070 -27071 -27072 -27073 -27074 -27075 -27076 +v -27077 -27078 -27079 -27080 -27081 -27082 -27083 -27084 -27085 -27086 -27087 +v -27088 -27089 -27090 -27091 -27092 -27093 -27094 -27095 -27096 -27097 -27098 +v -27099 -27100 -27101 -27102 -27103 -27104 -27105 -27106 -27107 -27108 -27109 +v -27110 -27111 -27112 -27113 -27114 -27115 -27116 -27117 -27118 -27119 -27120 +v -27121 -27122 -27123 -27124 -27125 -27126 -27127 -27128 -27129 -27130 27131 +v -27132 27133 -27134 -27135 -27136 27137 -27138 27139 -27140 -27141 -27142 +v -27143 27144 -27145 27146 -27147 -27148 -27149 -27150 27151 -27152 27153 +v -27154 -27155 27156 -27157 -27158 -27159 -27160 -27161 -27162 -27163 -27164 +v -27165 -27166 27167 27168 27169 -27170 -27171 -27172 -27173 -27174 -27175 +v -27176 -27177 -27178 -27179 -27180 -27181 -27182 -27183 -27184 -27185 -27186 +v -27187 -27188 -27189 -27190 -27191 -27192 -27193 -27194 -27195 -27196 -27197 +v -27198 -27199 -27200 -27201 -27202 -27203 -27204 -27205 -27206 -27207 -27208 +v -27209 -27210 -27211 -27212 -27213 -27214 -27215 -27216 -27217 -27218 -27219 +v -27220 -27221 -27222 -27223 -27224 -27225 -27226 -27227 -27228 -27229 -27230 +v -27231 -27232 -27233 -27234 -27235 -27236 -27237 -27238 -27239 -27240 -27241 +v -27242 -27243 -27244 -27245 -27246 -27247 -27248 -27249 -27250 -27251 -27252 +v -27253 -27254 -27255 -27256 -27257 -27258 -27259 -27260 -27261 -27262 27263 +v -27264 -27265 -27266 -27267 -27268 -27269 -27270 -27271 -27272 -27273 -27274 +v -27275 -27276 -27277 -27278 -27279 -27280 -27281 -27282 -27283 -27284 -27285 +v -27286 -27287 -27288 -27289 -27290 -27291 -27292 -27293 -27294 -27295 -27296 +v -27297 -27298 -27299 -27300 -27301 -27302 -27303 -27304 -27305 -27306 -27307 +v -27308 -27309 -27310 -27311 -27312 -27313 -27314 -27315 -27316 -27317 -27318 +v -27319 -27320 -27321 -27322 -27323 -27324 -27325 -27326 -27327 -27328 -27329 +v -27330 -27331 27332 -27333 27334 -27335 -27336 -27337 27338 -27339 27340 +v -27341 -27342 -27343 -27344 27345 -27346 27347 -27348 -27349 -27350 -27351 +v 27352 -27353 27354 -27355 -27356 27357 -27358 -27359 -27360 -27361 -27362 +v -27363 -27364 -27365 -27366 -27367 27368 27369 27370 -27371 -27372 -27373 +v -27374 -27375 -27376 -27377 -27378 -27379 -27380 -27381 -27382 -27383 -27384 +v -27385 -27386 -27387 -27388 -27389 -27390 -27391 -27392 -27393 -27394 -27395 +v -27396 -27397 -27398 -27399 -27400 -27401 -27402 -27403 -27404 -27405 -27406 +v -27407 -27408 -27409 -27410 -27411 -27412 -27413 -27414 -27415 -27416 -27417 +v -27418 -27419 -27420 -27421 -27422 -27423 -27424 -27425 -27426 -27427 -27428 +v -27429 -27430 -27431 -27432 -27433 -27434 -27435 -27436 -27437 -27438 -27439 +v -27440 -27441 -27442 -27443 -27444 -27445 -27446 -27447 -27448 -27449 -27450 +v -27451 -27452 -27453 -27454 -27455 -27456 -27457 -27458 -27459 -27460 -27461 +v -27462 -27463 27464 -27465 -27466 -27467 -27468 -27469 -27470 -27471 -27472 +v -27473 -27474 -27475 -27476 -27477 -27478 -27479 -27480 -27481 -27482 -27483 +v -27484 -27485 -27486 -27487 -27488 -27489 -27490 -27491 -27492 -27493 -27494 +v -27495 -27496 -27497 -27498 -27499 -27500 -27501 -27502 -27503 -27504 -27505 +v -27506 -27507 -27508 -27509 -27510 -27511 -27512 -27513 -27514 -27515 -27516 +v -27517 -27518 -27519 -27520 -27521 -27522 -27523 -27524 -27525 -27526 -27527 +v -27528 -27529 -27530 -27531 -27532 27533 -27534 27535 -27536 -27537 -27538 +v 27539 -27540 27541 -27542 -27543 -27544 -27545 27546 -27547 27548 -27549 +v -27550 -27551 -27552 27553 -27554 27555 -27556 -27557 27558 -27559 -27560 +v -27561 -27562 -27563 -27564 -27565 -27566 -27567 -27568 27569 27570 27571 +v -27572 -27573 -27574 -27575 -27576 -27577 -27578 -27579 -27580 -27581 -27582 +v -27583 -27584 -27585 -27586 -27587 -27588 -27589 -27590 -27591 -27592 -27593 +v 27594 -27595 -27596 -27597 -27598 -27599 -27600 -27601 27602 -27603 27604 +v -27605 -27606 -27607 27608 -27609 27610 -27611 -27612 27613 -27614 -27615 +v -27616 -27617 -27618 -27619 27620 27621 27622 -27623 -27624 -27625 -27626 +v -27627 -27628 -27629 -27630 -27631 -27632 -27633 -27634 -27635 -27636 -27637 +v -27638 -27639 -27640 -27641 -27642 -27643 -27644 -27645 -27646 -27647 -27648 +v -27649 -27650 -27651 27652 -27653 27654 -27655 -27656 -27657 27658 -27659 +v 27660 -27661 -27662 27663 -27664 -27665 -27666 -27667 -27668 -27669 27670 +v 27671 27672 27673 -27674 -27675 -27676 -27677 -27678 -27679 -27680 -27681 +v -27682 -27683 -27684 -27685 -27686 -27687 -27688 -27689 -27690 -27691 -27692 +v -27693 -27694 -27695 -27696 -27697 -27698 -27699 -27700 -27701 -27702 27703 +v -27704 27705 -27706 -27707 -27708 27709 -27710 27711 -27712 -27713 27714 +v -27715 -27716 -27717 -27718 -27719 -27720 27721 27722 27723 27724 -27725 +v -27726 -27727 -27728 -27729 -27730 -27731 -27732 -27733 -27734 -27735 -27736 +v -27737 -27738 -27739 -27740 -27741 -27742 -27743 -27744 -27745 -27746 -27747 +v -27748 -27749 -27750 -27751 -27752 -27753 27754 -27755 27756 -27757 -27758 +v -27759 27760 -27761 27762 -27763 -27764 27765 -27766 -27767 -27768 -27769 +v -27770 -27771 27772 27773 27774 27775 -27776 -27777 -27778 -27779 -27780 +v -27781 -27782 -27783 -27784 -27785 -27786 -27787 -27788 -27789 -27790 -27791 +v -27792 -27793 -27794 -27795 -27796 -27797 -27798 -27799 -27800 -27801 -27802 +v -27803 -27804 -27805 -27806 -27807 -27808 -27809 -27810 -27811 -27812 -27813 +v -27814 -27815 -27816 -27817 -27818 -27819 -27820 -27821 -27822 -27823 -27824 +v -27825 -27826 -27827 -27828 -27829 -27830 -27831 -27832 -27833 -27834 -27835 +v -27836 -27837 -27838 -27839 -27840 -27841 -27842 -27843 -27844 -27845 -27846 +v -27847 -27848 -27849 -27850 -27851 -27852 -27853 -27854 -27855 -27856 -27857 +v -27858 -27859 -27860 -27861 -27862 -27863 -27864 -27865 -27866 -27867 -27868 +v -27869 -27870 -27871 -27872 -27873 -27874 -27875 -27876 -27877 -27878 -27879 +v -27880 -27881 -27882 -27883 -27884 -27885 -27886 -27887 -27888 -27889 -27890 +v -27891 -27892 -27893 -27894 -27895 -27896 -27897 -27898 -27899 -27900 -27901 +v -27902 -27903 -27904 -27905 -27906 -27907 -27908 -27909 -27910 -27911 -27912 +v -27913 -27914 -27915 -27916 -27917 -27918 -27919 -27920 -27921 -27922 -27923 +v -27924 -27925 -27926 -27927 -27928 -27929 -27930 -27931 -27932 -27933 -27934 +v -27935 -27936 27937 -27938 27939 -27940 -27941 -27942 27943 -27944 27945 +v -27946 -27947 -27948 -27949 27950 -27951 27952 -27953 -27954 -27955 -27956 +v 27957 -27958 27959 -27960 -27961 27962 -27963 -27964 -27965 -27966 -27967 +v -27968 -27969 -27970 -27971 -27972 27973 27974 27975 27976 -27977 -27978 +v -27979 -27980 -27981 -27982 -27983 -27984 -27985 -27986 -27987 -27988 -27989 +v -27990 -27991 -27992 -27993 -27994 -27995 -27996 -27997 -27998 -27999 -28000 +v -28001 -28002 -28003 -28004 -28005 -28006 -28007 -28008 -28009 -28010 -28011 +v -28012 -28013 -28014 -28015 -28016 -28017 -28018 -28019 -28020 -28021 -28022 +v -28023 -28024 -28025 -28026 -28027 -28028 -28029 -28030 -28031 -28032 -28033 +v -28034 -28035 -28036 -28037 -28038 -28039 -28040 -28041 -28042 -28043 -28044 +v -28045 -28046 -28047 -28048 -28049 -28050 -28051 -28052 -28053 -28054 -28055 +v -28056 -28057 -28058 -28059 -28060 -28061 -28062 -28063 -28064 -28065 -28066 +v -28067 -28068 -28069 -28070 -28071 -28072 -28073 -28074 -28075 -28076 -28077 +v -28078 -28079 -28080 -28081 -28082 -28083 -28084 -28085 -28086 -28087 -28088 +v -28089 -28090 -28091 -28092 -28093 -28094 -28095 -28096 -28097 -28098 -28099 +v -28100 -28101 -28102 -28103 -28104 -28105 -28106 -28107 -28108 -28109 -28110 +v -28111 -28112 -28113 -28114 -28115 -28116 -28117 -28118 -28119 -28120 -28121 +v -28122 -28123 -28124 -28125 -28126 -28127 -28128 -28129 -28130 -28131 -28132 +v -28133 -28134 -28135 -28136 -28137 28138 -28139 28140 -28141 -28142 -28143 +v 28144 -28145 28146 -28147 -28148 -28149 -28150 28151 -28152 28153 -28154 +v -28155 -28156 -28157 28158 -28159 28160 -28161 -28162 28163 -28164 -28165 +v -28166 -28167 -28168 -28169 -28170 -28171 -28172 -28173 28174 28175 28176 +v 28177 -28178 -28179 -28180 -28181 -28182 -28183 -28184 -28185 -28186 -28187 +v -28188 -28189 -28190 -28191 -28192 -28193 -28194 -28195 -28196 -28197 -28198 +v -28199 -28200 -28201 -28202 -28203 -28204 -28205 -28206 -28207 -28208 -28209 +v -28210 -28211 -28212 -28213 -28214 -28215 -28216 -28217 -28218 -28219 -28220 +v -28221 -28222 -28223 -28224 -28225 -28226 -28227 -28228 -28229 -28230 -28231 +v -28232 -28233 -28234 -28235 -28236 -28237 -28238 -28239 -28240 -28241 -28242 +v -28243 -28244 -28245 -28246 -28247 -28248 -28249 -28250 -28251 -28252 -28253 +v -28254 -28255 -28256 -28257 -28258 -28259 -28260 -28261 -28262 -28263 -28264 +v -28265 -28266 -28267 -28268 -28269 -28270 -28271 -28272 -28273 -28274 -28275 +v -28276 -28277 -28278 -28279 -28280 -28281 -28282 -28283 -28284 -28285 -28286 +v -28287 -28288 -28289 -28290 -28291 -28292 -28293 -28294 -28295 -28296 -28297 +v -28298 -28299 -28300 -28301 -28302 -28303 -28304 -28305 -28306 -28307 -28308 +v -28309 -28310 -28311 -28312 -28313 -28314 -28315 -28316 -28317 -28318 -28319 +v -28320 -28321 -28322 -28323 -28324 -28325 -28326 -28327 -28328 -28329 -28330 +v -28331 -28332 -28333 -28334 -28335 -28336 -28337 -28338 28339 -28340 28341 +v -28342 -28343 -28344 28345 -28346 28347 -28348 -28349 -28350 -28351 28352 +v -28353 28354 -28355 -28356 -28357 -28358 28359 -28360 28361 -28362 -28363 +v 28364 -28365 -28366 -28367 -28368 -28369 -28370 -28371 -28372 -28373 -28374 +v 28375 28376 28377 28378 -28379 -28380 -28381 -28382 -28383 -28384 -28385 +v -28386 -28387 -28388 -28389 -28390 -28391 -28392 -28393 -28394 -28395 -28396 +v -28397 -28398 -28399 -28400 -28401 -28402 -28403 -28404 -28405 -28406 -28407 +v -28408 -28409 -28410 -28411 -28412 -28413 -28414 -28415 -28416 -28417 -28418 +v -28419 -28420 -28421 -28422 -28423 -28424 -28425 -28426 -28427 -28428 -28429 +v -28430 -28431 -28432 -28433 -28434 -28435 -28436 -28437 -28438 -28439 -28440 +v -28441 -28442 -28443 -28444 -28445 -28446 -28447 -28448 -28449 -28450 -28451 +v -28452 -28453 -28454 -28455 -28456 -28457 -28458 -28459 -28460 -28461 -28462 +v -28463 -28464 -28465 -28466 -28467 -28468 -28469 -28470 -28471 -28472 -28473 +v -28474 -28475 -28476 -28477 -28478 -28479 -28480 -28481 -28482 -28483 -28484 +v -28485 -28486 -28487 -28488 -28489 -28490 -28491 -28492 -28493 -28494 -28495 +v -28496 -28497 -28498 -28499 -28500 -28501 -28502 -28503 -28504 -28505 -28506 +v -28507 -28508 -28509 -28510 -28511 -28512 -28513 -28514 -28515 -28516 -28517 +v -28518 -28519 -28520 -28521 -28522 -28523 -28524 -28525 -28526 -28527 -28528 +v -28529 -28530 -28531 -28532 -28533 -28534 -28535 -28536 -28537 -28538 -28539 +v 28540 -28541 28542 -28543 -28544 -28545 28546 -28547 28548 -28549 -28550 +v -28551 -28552 28553 -28554 28555 -28556 -28557 -28558 -28559 28560 -28561 +v 28562 -28563 -28564 28565 -28566 -28567 -28568 -28569 -28570 -28571 -28572 +v -28573 -28574 -28575 28576 28577 28578 28579 -28580 -28581 -28582 -28583 +v -28584 -28585 -28586 -28587 -28588 -28589 -28590 -28591 -28592 -28593 -28594 +v -28595 -28596 -28597 -28598 -28599 -28600 -28601 -28602 -28603 -28604 -28605 +v -28606 -28607 -28608 28609 -28610 28611 -28612 -28613 -28614 28615 -28616 +v 28617 -28618 -28619 28620 -28621 -28622 -28623 -28624 -28625 -28626 28627 +v 28628 28629 28630 -28631 28632 -28633 28634 -28635 28636 28637 -28638 -28639 +v -28640 -28641 -28642 -28643 -28644 -28645 -28646 -28647 -28648 -28649 -28650 +v -28651 -28652 -28653 -28654 -28655 -28656 -28657 -28658 -28659 -28660 -28661 +v -28662 -28663 -28664 -28665 -28666 -28667 -28668 -28669 -28670 -28671 -28672 +v -28673 -28674 -28675 -28676 -28677 -28678 -28679 -28680 -28681 -28682 -28683 +v -28684 -28685 -28686 -28687 -28688 -28689 -28690 -28691 -28692 -28693 -28694 +v -28695 -28696 -28697 -28698 -28699 -28700 -28701 -28702 -28703 -28704 -28705 +v -28706 -28707 -28708 -28709 -28710 -28711 -28712 -28713 -28714 -28715 -28716 +v -28717 -28718 -28719 -28720 -28721 -28722 -28723 -28724 -28725 -28726 -28727 +v -28728 -28729 -28730 -28731 -28732 -28733 -28734 -28735 -28736 -28737 -28738 +v -28739 -28740 -28741 -28742 -28743 -28744 -28745 -28746 -28747 -28748 -28749 +v -28750 -28751 -28752 -28753 -28754 -28755 -28756 -28757 -28758 -28759 -28760 +v -28761 -28762 -28763 -28764 -28765 -28766 -28767 -28768 -28769 -28770 -28771 +v -28772 -28773 -28774 -28775 -28776 -28777 -28778 -28779 -28780 -28781 -28782 +v -28783 -28784 -28785 -28786 -28787 -28788 -28789 -28790 -28791 -28792 -28793 +v -28794 -28795 -28796 -28797 -28798 -28799 -28800 -28801 -28802 -28803 -28804 +v -28805 -28806 -28807 -28808 -28809 -28810 -28811 -28812 -28813 -28814 -28815 +v -28816 -28817 -28818 -28819 -28820 -28821 -28822 -28823 -28824 -28825 -28826 +v -28827 -28828 -28829 -28830 -28831 -28832 -28833 -28834 -28835 -28836 -28837 +v -28838 -28839 -28840 -28841 -28842 -28843 -28844 -28845 -28846 -28847 -28848 +v -28849 -28850 -28851 -28852 -28853 -28854 -28855 -28856 -28857 -28858 -28859 +v -28860 -28861 -28862 -28863 -28864 -28865 -28866 -28867 -28868 -28869 -28870 +v -28871 -28872 -28873 -28874 -28875 -28876 -28877 -28878 -28879 -28880 -28881 +v -28882 -28883 -28884 -28885 -28886 -28887 -28888 -28889 -28890 -28891 -28892 +v -28893 -28894 -28895 -28896 -28897 -28898 -28899 -28900 -28901 -28902 -28903 +v -28904 -28905 -28906 -28907 -28908 -28909 -28910 -28911 -28912 -28913 -28914 +v -28915 -28916 -28917 -28918 -28919 -28920 -28921 -28922 -28923 -28924 -28925 +v -28926 -28927 -28928 -28929 -28930 -28931 -28932 -28933 -28934 -28935 -28936 +v -28937 -28938 -28939 -28940 -28941 -28942 -28943 -28944 -28945 -28946 -28947 +v -28948 -28949 -28950 -28951 -28952 -28953 -28954 -28955 -28956 -28957 -28958 +v -28959 -28960 -28961 -28962 -28963 -28964 -28965 -28966 -28967 -28968 -28969 +v -28970 -28971 -28972 -28973 -28974 -28975 -28976 -28977 -28978 -28979 -28980 +v -28981 -28982 -28983 -28984 -28985 -28986 -28987 -28988 -28989 -28990 -28991 +v -28992 -28993 -28994 -28995 -28996 -28997 -28998 -28999 -29000 -29001 -29002 +v -29003 -29004 -29005 -29006 -29007 -29008 -29009 -29010 -29011 -29012 -29013 +v -29014 -29015 -29016 -29017 -29018 -29019 -29020 -29021 -29022 -29023 -29024 +v -29025 -29026 -29027 -29028 -29029 -29030 -29031 -29032 -29033 -29034 -29035 +v -29036 -29037 -29038 -29039 -29040 -29041 -29042 -29043 -29044 -29045 -29046 +v -29047 -29048 -29049 -29050 -29051 -29052 -29053 -29054 -29055 -29056 -29057 +v -29058 -29059 -29060 -29061 -29062 -29063 -29064 -29065 -29066 -29067 -29068 +v -29069 -29070 -29071 -29072 -29073 -29074 -29075 -29076 -29077 -29078 -29079 +v -29080 -29081 -29082 -29083 -29084 -29085 -29086 -29087 -29088 -29089 -29090 +v -29091 -29092 -29093 -29094 -29095 -29096 -29097 -29098 -29099 -29100 -29101 +v -29102 -29103 -29104 -29105 -29106 -29107 -29108 -29109 -29110 -29111 -29112 +v -29113 -29114 -29115 -29116 -29117 -29118 -29119 -29120 -29121 -29122 -29123 +v -29124 -29125 -29126 -29127 -29128 -29129 -29130 -29131 -29132 -29133 -29134 +v -29135 -29136 -29137 -29138 -29139 -29140 -29141 -29142 -29143 -29144 -29145 +v -29146 -29147 -29148 -29149 -29150 -29151 -29152 -29153 -29154 -29155 -29156 +v -29157 -29158 -29159 -29160 -29161 -29162 -29163 -29164 -29165 -29166 -29167 +v -29168 -29169 -29170 -29171 -29172 -29173 -29174 -29175 -29176 -29177 -29178 +v -29179 -29180 -29181 -29182 -29183 -29184 -29185 -29186 -29187 -29188 -29189 +v -29190 -29191 -29192 -29193 29194 -29195 29196 -29197 -29198 -29199 29200 +v -29201 29202 -29203 -29204 -29205 29206 -29207 29208 -29209 -29210 -29211 +v 29212 -29213 29214 -29215 -29216 -29217 29218 -29219 29220 -29221 -29222 +v -29223 29224 -29225 29226 -29227 -29228 29229 -29230 -29231 -29232 -29233 +v -29234 -29235 -29236 -29237 -29238 -29239 -29240 -29241 -29242 -29243 29244 +v 29245 29246 29247 29248 -29249 -29250 -29251 -29252 -29253 -29254 29255 +v -29256 -29257 -29258 -29259 -29260 -29261 -29262 -29263 -29264 -29265 -29266 +v -29267 -29268 -29269 -29270 -29271 -29272 -29273 -29274 -29275 -29276 -29277 +v -29278 -29279 -29280 -29281 -29282 -29283 -29284 -29285 -29286 -29287 -29288 +v -29289 -29290 -29291 -29292 -29293 -29294 -29295 -29296 -29297 -29298 -29299 +v -29300 -29301 -29302 -29303 -29304 -29305 -29306 -29307 -29308 -29309 -29310 +v -29311 -29312 -29313 -29314 -29315 -29316 -29317 -29318 -29319 -29320 -29321 +v -29322 -29323 -29324 -29325 -29326 -29327 -29328 -29329 -29330 -29331 -29332 +v -29333 -29334 -29335 -29336 -29337 -29338 -29339 -29340 -29341 -29342 -29343 +v -29344 -29345 -29346 -29347 -29348 -29349 -29350 -29351 -29352 -29353 -29354 +v -29355 -29356 -29357 -29358 -29359 -29360 -29361 -29362 -29363 -29364 -29365 +v -29366 -29367 -29368 -29369 -29370 -29371 -29372 -29373 -29374 -29375 -29376 +v -29377 -29378 -29379 -29380 -29381 -29382 -29383 -29384 29385 -29386 29387 +v -29388 -29389 -29390 29391 -29392 29393 -29394 -29395 -29396 29397 -29398 +v 29399 -29400 -29401 -29402 29403 -29404 29405 -29406 -29407 -29408 29409 +v -29410 29411 -29412 -29413 29414 -29415 -29416 -29417 -29418 -29419 -29420 +v -29421 -29422 -29423 -29424 -29425 29426 29427 29428 -29429 -29430 -29431 +v -29432 -29433 -29434 -29435 -29436 -29437 -29438 -29439 -29440 -29441 -29442 +v -29443 -29444 -29445 -29446 -29447 -29448 -29449 -29450 -29451 -29452 -29453 +v -29454 -29455 -29456 -29457 -29458 -29459 -29460 -29461 -29462 -29463 -29464 +v -29465 -29466 -29467 -29468 -29469 -29470 -29471 -29472 -29473 -29474 -29475 +v -29476 -29477 -29478 -29479 -29480 -29481 29482 -29483 29484 -29485 -29486 +v 29487 -29488 29489 -29490 -29491 -29492 29493 -29494 29495 -29496 -29497 +v -29498 29499 -29500 29501 -29502 -29503 29504 -29505 -29506 -29507 -29508 +v -29509 -29510 -29511 -29512 -29513 -29514 29515 29516 29517 29518 -29519 +v -29520 -29521 -29522 -29523 -29524 -29525 -29526 -29527 -29528 -29529 -29530 +v -29531 -29532 -29533 -29534 -29535 -29536 -29537 -29538 -29539 -29540 -29541 +v -29542 -29543 -29544 -29545 -29546 -29547 -29548 -29549 -29550 -29551 -29552 +v -29553 -29554 -29555 -29556 -29557 -29558 -29559 -29560 -29561 -29562 -29563 +v -29564 -29565 -29566 -29567 -29568 -29569 -29570 -29571 -29572 -29573 -29574 +v -29575 -29576 -29577 -29578 -29579 -29580 -29581 -29582 -29583 -29584 -29585 +v -29586 -29587 -29588 -29589 -29590 -29591 -29592 -29593 -29594 -29595 -29596 +v -29597 -29598 -29599 -29600 -29601 -29602 -29603 -29604 -29605 -29606 -29607 +v -29608 -29609 -29610 -29611 -29612 -29613 29614 -29615 29616 -29617 -29618 +v 29619 -29620 29621 -29622 -29623 29624 -29625 29626 -29627 -29628 -29629 +v 29630 -29631 29632 -29633 -29634 -29635 29636 -29637 29638 -29639 -29640 +v 29641 -29642 -29643 -29644 -29645 -29646 -29647 -29648 -29649 -29650 -29651 +v -29652 29653 29654 29655 -29656 -29657 -29658 -29659 -29660 -29661 -29662 +v -29663 -29664 -29665 -29666 -29667 -29668 29669 -29670 -29671 29672 -29673 +v -29674 -29675 -29676 -29677 -29678 29679 29680 29681 -29682 -29683 -29684 +v -29685 -29686 -29687 -29688 -29689 -29690 -29691 -29692 -29693 -29694 -29695 +v 29696 -29697 -29698 29699 -29700 -29701 -29702 -29703 -29704 29705 29706 +v 29707 -29708 -29709 -29710 -29711 -29712 -29713 -29714 -29715 -29716 29717 +v 29718 -29719 29720 -29721 -29722 29723 -29724 -29725 -29726 -29727 -29728 +v -29729 29730 -29731 -29732 -29733 -29734 -29735 -29736 -29737 -29738 -29739 +v -29740 -29741 -29742 -29743 -29744 29745 -29746 -29747 29748 -29749 -29750 +v -29751 -29752 -29753 29754 -29755 29756 -29757 -29758 -29759 29760 -29761 +v 29762 29763 29764 29765 29766 -29767 -29768 29769 29770 29771 -29772 -29773 +v -29774 -29775 -29776 -29777 -29778 -29779 -29780 29781 29782 29783 -29784 +v -29785 -29786 -29787 -29788 -29789 -29790 -29791 -29792 -29793 -29794 -29795 +v -29796 -29797 -29798 -29799 -29800 -29801 -29802 -29803 -29804 -29805 29806 +v -29807 -29808 -29809 -29810 -29811 -29812 -29813 29814 -29815 29816 -29817 +v -29818 -29819 29820 -29821 29822 -29823 -29824 29825 -29826 -29827 -29828 +v -29829 -29830 -29831 29832 29833 29834 -29835 -29836 -29837 -29838 -29839 +v -29840 -29841 -29842 -29843 -29844 -29845 -29846 -29847 -29848 -29849 -29850 +v -29851 -29852 -29853 -29854 -29855 -29856 29857 -29858 -29859 -29860 -29861 +v -29862 -29863 -29864 29865 -29866 29867 -29868 -29869 -29870 29871 -29872 +v 29873 -29874 -29875 29876 -29877 -29878 -29879 -29880 -29881 -29882 29883 +v 29884 29885 -29886 -29887 -29888 -29889 -29890 -29891 -29892 -29893 -29894 +v -29895 -29896 -29897 -29898 -29899 -29900 -29901 -29902 -29903 -29904 -29905 +v -29906 -29907 29908 -29909 -29910 -29911 -29912 -29913 -29914 -29915 29916 +v -29917 29918 -29919 -29920 -29921 29922 -29923 29924 -29925 -29926 29927 +v -29928 -29929 -29930 -29931 -29932 -29933 29934 29935 29936 -29937 -29938 +v -29939 -29940 -29941 -29942 -29943 -29944 -29945 -29946 -29947 -29948 -29949 +v -29950 -29951 -29952 -29953 -29954 -29955 -29956 -29957 -29958 -29959 -29960 +v -29961 -29962 -29963 -29964 -29965 -29966 -29967 -29968 -29969 -29970 -29971 +v -29972 -29973 -29974 -29975 -29976 -29977 -29978 -29979 -29980 -29981 -29982 +v -29983 -29984 -29985 -29986 -29987 -29988 -29989 -29990 -29991 -29992 -29993 +v -29994 -29995 -29996 -29997 -29998 -29999 -30000 -30001 -30002 -30003 -30004 +v -30005 -30006 -30007 -30008 -30009 -30010 -30011 -30012 -30013 -30014 -30015 +v -30016 -30017 -30018 -30019 -30020 -30021 -30022 -30023 -30024 -30025 -30026 +v -30027 -30028 -30029 30030 -30031 -30032 -30033 -30034 -30035 -30036 -30037 +v -30038 -30039 -30040 -30041 -30042 -30043 -30044 -30045 -30046 -30047 -30048 +v -30049 -30050 -30051 -30052 -30053 -30054 -30055 -30056 -30057 -30058 -30059 +v -30060 -30061 -30062 -30063 -30064 -30065 -30066 -30067 -30068 -30069 -30070 +v -30071 -30072 -30073 -30074 -30075 -30076 -30077 -30078 -30079 -30080 -30081 +v -30082 -30083 -30084 -30085 -30086 -30087 -30088 -30089 -30090 -30091 -30092 +v -30093 -30094 -30095 -30096 -30097 -30098 30099 -30100 30101 -30102 -30103 +v -30104 30105 -30106 30107 -30108 -30109 -30110 -30111 30112 -30113 30114 +v -30115 -30116 -30117 -30118 30119 -30120 30121 -30122 -30123 30124 -30125 +v -30126 -30127 -30128 -30129 -30130 -30131 -30132 -30133 -30134 30135 30136 +v 30137 -30138 -30139 -30140 -30141 -30142 -30143 -30144 -30145 -30146 -30147 +v -30148 -30149 -30150 -30151 -30152 -30153 -30154 -30155 -30156 -30157 -30158 +v -30159 -30160 -30161 -30162 -30163 -30164 -30165 -30166 -30167 -30168 -30169 +v -30170 -30171 -30172 -30173 -30174 -30175 -30176 -30177 -30178 -30179 -30180 +v -30181 -30182 -30183 -30184 -30185 -30186 -30187 -30188 -30189 -30190 -30191 +v -30192 -30193 -30194 -30195 -30196 -30197 -30198 -30199 -30200 -30201 -30202 +v -30203 -30204 -30205 -30206 -30207 -30208 -30209 -30210 -30211 -30212 -30213 +v -30214 -30215 -30216 -30217 -30218 -30219 -30220 -30221 -30222 -30223 -30224 +v -30225 -30226 -30227 -30228 -30229 -30230 30231 -30232 -30233 -30234 -30235 +v -30236 -30237 -30238 -30239 -30240 -30241 -30242 -30243 -30244 -30245 -30246 +v -30247 -30248 -30249 -30250 -30251 -30252 -30253 -30254 -30255 -30256 -30257 +v -30258 -30259 -30260 -30261 -30262 -30263 -30264 -30265 -30266 -30267 -30268 +v -30269 -30270 -30271 -30272 -30273 -30274 -30275 -30276 -30277 -30278 -30279 +v -30280 -30281 -30282 -30283 -30284 -30285 -30286 -30287 -30288 -30289 -30290 +v -30291 -30292 -30293 -30294 -30295 -30296 -30297 -30298 -30299 30300 -30301 +v 30302 -30303 -30304 -30305 30306 -30307 30308 -30309 -30310 -30311 -30312 +v 30313 -30314 30315 -30316 -30317 -30318 -30319 30320 -30321 30322 -30323 +v -30324 30325 -30326 -30327 -30328 -30329 -30330 -30331 -30332 -30333 -30334 +v -30335 30336 30337 30338 -30339 -30340 -30341 -30342 -30343 -30344 -30345 +v -30346 -30347 -30348 -30349 -30350 -30351 -30352 -30353 -30354 -30355 -30356 +v -30357 -30358 -30359 -30360 -30361 -30362 -30363 -30364 -30365 -30366 -30367 +v -30368 -30369 -30370 -30371 -30372 -30373 -30374 -30375 -30376 -30377 -30378 +v -30379 -30380 -30381 -30382 -30383 -30384 -30385 -30386 -30387 -30388 -30389 +v -30390 -30391 -30392 -30393 -30394 -30395 -30396 -30397 -30398 -30399 -30400 +v -30401 -30402 -30403 -30404 -30405 -30406 -30407 -30408 -30409 -30410 -30411 +v -30412 -30413 -30414 -30415 -30416 -30417 -30418 -30419 -30420 -30421 -30422 +v -30423 -30424 -30425 -30426 -30427 -30428 -30429 -30430 -30431 30432 -30433 +v -30434 -30435 -30436 -30437 -30438 -30439 -30440 -30441 -30442 -30443 -30444 +v -30445 -30446 -30447 -30448 -30449 -30450 -30451 -30452 -30453 -30454 -30455 +v -30456 -30457 -30458 -30459 -30460 -30461 -30462 -30463 -30464 -30465 -30466 +v -30467 -30468 -30469 -30470 -30471 -30472 -30473 -30474 -30475 -30476 -30477 +v -30478 -30479 -30480 -30481 -30482 -30483 -30484 -30485 -30486 -30487 -30488 +v -30489 -30490 -30491 -30492 -30493 -30494 -30495 -30496 -30497 -30498 -30499 +v -30500 30501 -30502 30503 -30504 -30505 -30506 30507 -30508 30509 -30510 +v -30511 -30512 -30513 30514 -30515 30516 -30517 -30518 -30519 -30520 30521 +v -30522 30523 -30524 -30525 30526 -30527 -30528 -30529 -30530 -30531 -30532 +v -30533 -30534 -30535 -30536 30537 30538 30539 -30540 -30541 -30542 -30543 +v -30544 -30545 -30546 -30547 -30548 -30549 -30550 -30551 -30552 -30553 -30554 +v -30555 -30556 -30557 -30558 -30559 -30560 -30561 -30562 -30563 -30564 -30565 +v -30566 -30567 -30568 -30569 -30570 -30571 -30572 -30573 -30574 -30575 -30576 +v -30577 -30578 -30579 -30580 -30581 -30582 -30583 -30584 -30585 -30586 -30587 +v -30588 -30589 -30590 -30591 -30592 -30593 -30594 -30595 -30596 -30597 -30598 +v -30599 -30600 -30601 -30602 -30603 -30604 -30605 -30606 -30607 -30608 -30609 +v -30610 -30611 -30612 -30613 -30614 -30615 -30616 -30617 -30618 -30619 -30620 +v -30621 -30622 -30623 -30624 -30625 -30626 -30627 -30628 -30629 -30630 -30631 +v -30632 30633 -30634 -30635 -30636 -30637 -30638 -30639 -30640 -30641 -30642 +v -30643 -30644 -30645 -30646 -30647 -30648 -30649 -30650 -30651 -30652 -30653 +v -30654 -30655 -30656 -30657 -30658 -30659 -30660 -30661 -30662 -30663 -30664 +v -30665 -30666 -30667 -30668 -30669 -30670 -30671 -30672 -30673 -30674 -30675 +v -30676 -30677 -30678 -30679 -30680 -30681 -30682 -30683 -30684 -30685 -30686 +v -30687 -30688 -30689 -30690 -30691 -30692 -30693 -30694 -30695 -30696 -30697 +v -30698 -30699 -30700 -30701 30702 -30703 30704 -30705 -30706 -30707 30708 +v -30709 30710 -30711 -30712 -30713 -30714 30715 -30716 30717 -30718 -30719 +v -30720 -30721 30722 -30723 30724 -30725 -30726 30727 -30728 -30729 -30730 +v -30731 -30732 -30733 -30734 -30735 -30736 -30737 30738 30739 30740 -30741 +v -30742 -30743 -30744 -30745 -30746 -30747 -30748 -30749 -30750 -30751 -30752 +v -30753 -30754 -30755 -30756 -30757 -30758 -30759 -30760 -30761 -30762 30763 +v -30764 -30765 -30766 -30767 -30768 -30769 -30770 30771 -30772 30773 -30774 +v -30775 -30776 30777 -30778 30779 -30780 -30781 30782 -30783 -30784 -30785 +v -30786 -30787 -30788 30789 30790 30791 30792 -30793 -30794 30795 30796 -30797 +v 30798 -30799 30800 30801 30802 -30803 -30804 30805 -30806 -30807 30808 -30809 +v 30810 30811 -30812 -30813 -30814 -30815 -30816 -30817 -30818 30819 30820 +v 30821 30822 -30823 30824 30825 30826 30827 30828 30829 30830 30831 30832 +v 30833 -30834 30835 -30836 -30837 -30838 30839 30840 30841 30842 30843 30844 +v 30845 30846 30847 30848 30849 -30850 30851 -30852 -30853 -30854 -30855 -30856 +v 30857 -30858 -30859 30860 30861 -30862 -30863 30864 -30865 30866 30867 -30868 +v -30869 30870 -30871 30872 -30873 -30874 30875 -30876 -30877 -30878 -30879 +v -30880 -30881 -30882 30883 30884 30885 30886 -30887 -30888 -30889 -30890 +v -30891 -30892 -30893 -30894 -30895 -30896 -30897 30898 30899 -30900 -30901 +v 30902 -30903 -30904 30905 30906 30907 30908 -30909 -30910 -30911 -30912 30913 +v 30914 30915 30916 -30917 -30918 -30919 -30920 30921 30922 30923 30924 -30925 +v -30926 -30927 -30928 -30929 -30930 -30931 -30932 -30933 -30934 -30935 -30936 +v -30937 -30938 -30939 -30940 -30941 -30942 -30943 -30944 30945 -30946 30947 +v -30948 -30949 -30950 30951 -30952 30953 -30954 -30955 30956 -30957 -30958 +v -30959 -30960 -30961 -30962 30963 30964 30965 30966 -30967 -30968 -30969 +v -30970 -30971 -30972 -30973 -30974 -30975 -30976 -30977 -30978 -30979 -30980 +v -30981 -30982 -30983 -30984 30985 -30986 30987 -30988 -30989 -30990 30991 +v -30992 30993 -30994 -30995 30996 -30997 -30998 -30999 -31000 -31001 -31002 +v 31003 31004 31005 31006 -31007 -31008 -31009 -31010 31011 31012 31013 31014 +v -31015 -31016 -31017 -31018 -31019 -31020 -31021 -31022 -31023 -31024 -31025 +v -31026 -31027 -31028 -31029 -31030 -31031 -31032 -31033 -31034 -31035 -31036 +v -31037 -31038 -31039 -31040 31041 -31042 31043 -31044 -31045 -31046 -31047 +v 31048 -31049 31050 -31051 -31052 31053 -31054 31055 -31056 -31057 -31058 +v -31059 -31060 -31061 -31062 -31063 31064 31065 31066 31067 31068 31069 -31070 +v -31071 -31072 -31073 -31074 -31075 -31076 -31077 -31078 -31079 -31080 -31081 +v -31082 -31083 -31084 -31085 -31086 -31087 -31088 -31089 -31090 -31091 -31092 +v -31093 -31094 -31095 31096 -31097 31098 -31099 -31100 -31101 -31102 31103 +v -31104 31105 -31106 -31107 31108 -31109 31110 -31111 -31112 -31113 -31114 +v -31115 -31116 -31117 -31118 31119 31120 31121 31122 -31123 -31124 31125 +v -31126 31127 -31128 31129 -31130 -31131 -31132 31133 31134 31135 31136 31137 +v -31138 31139 -31140 -31141 -31142 31143 -31144 31145 -31146 -31147 -31148 +v 31149 31150 31151 -31152 31153 -31154 -31155 -31156 31157 31158 31159 31160 +v -31161 -31162 -31163 -31164 31165 -31166 31167 31168 31169 31170 -31171 +v -31172 31173 31174 31175 31176 -31177 -31178 31179 31180 31181 -31182 -31183 +v -31184 -31185 -31186 -31187 -31188 -31189 31190 31191 31192 31193 -31194 +v -31195 31196 31197 -31198 -31199 31200 31201 -31202 -31203 31204 31205 -31206 +v 31207 -31208 31209 -31210 -31211 -31212 -31213 -31214 -31215 31216 31217 +v -31218 31219 -31220 31221 -31222 -31223 -31224 -31225 -31226 -31227 31228 +v 31229 -31230 -31231 31232 31233 -31234 31235 -31236 31237 -31238 -31239 +v -31240 -31241 -31242 -31243 31244 -31245 -31246 31247 -31248 31249 -31250 +v 31251 -31252 -31253 -31254 31255 31256 31257 31258 -31259 -31260 31261 31262 +v -31263 -31264 31265 31266 -31267 -31268 -31269 -31270 -31271 31272 31273 +v 31274 31275 -31276 31277 31278 31279 -31280 -31281 31282 31283 -31284 -31285 +v -31286 31287 -31288 -31289 -31290 -31291 31292 -31293 31294 -31295 -31296 +v 31297 -31298 31299 31300 31301 -31302 31303 31304 -31305 -31306 -31307 -31308 +v -31309 -31310 -31311 -31312 31313 31314 31315 -31316 -31317 -31318 -31319 +v -31320 31321 31322 -31323 -31324 -31325 31326 -31327 -31328 -31329 -31330 +v -31331 -31332 -31333 31334 31335 31336 31337 -31338 -31339 -31340 -31341 +v 31342 31343 31344 -31345 31346 -31347 -31348 -31349 -31350 31351 -31352 +v -31353 -31354 31355 -31356 -31357 -31358 -31359 -31360 -31361 -31362 31363 +v 31364 -31365 -31366 -31367 -31368 31369 -31370 -31371 -31372 -31373 -31374 +v 31375 31376 31377 31378 31379 31380 31381 31382 -31383 -31384 31385 31386 +v -31387 31388 31389 31390 -31391 -31392 -31393 -31394 -31395 -31396 -31397 +v -31398 31399 -31400 31401 -31402 -31403 -31404 31405 -31406 31407 -31408 +v -31409 31410 -31411 31412 31413 31414 31415 31416 -31417 -31418 31419 31420 +v 31421 31422 31423 -31424 -31425 31426 -31427 -31428 -31429 31430 -31431 31432 +v -31433 -31434 31435 -31436 -31437 -31438 -31439 -31440 -31441 -31442 -31443 +v -31444 -31445 -31446 31447 31448 31449 -31450 -31451 -31452 -31453 -31454 +v 31455 31456 -31457 -31458 -31459 -31460 31461 -31462 -31463 -31464 -31465 +v -31466 -31467 -31468 31469 31470 31471 -31472 31473 -31474 -31475 31476 +v -31477 -31478 -31479 31480 -31481 -31482 -31483 -31484 -31485 31486 31487 +v 31488 31489 31490 31491 -31492 31493 31494 31495 31496 -31497 -31498 -31499 +v 31500 -31501 -31502 31503 -31504 31505 31506 31507 31508 31509 -31510 -31511 +v -31512 -31513 31514 -31515 -31516 -31517 -31518 -31519 -31520 -31521 31522 +v -31523 31524 31525 -31526 -31527 -31528 -31529 -31530 31531 -31532 -31533 +v -31534 -31535 31536 31537 31538 31539 31540 -31541 -31542 -31543 31544 -31545 +v 31546 -31547 31548 31549 -31550 -31551 31552 -31553 -31554 -31555 31556 +v -31557 31558 -31559 -31560 -31561 -31562 31563 -31564 31565 31566 31567 +v -31568 -31569 -31570 -31571 -31572 -31573 -31574 -31575 -31576 -31577 -31578 +v 31579 31580 31581 -31582 -31583 -31584 -31585 -31586 31587 31588 31589 31590 +v -31591 -31592 -31593 -31594 -31595 -31596 -31597 -31598 -31599 -31600 -31601 +v -31602 -31603 -31604 -31605 31606 31607 -31608 -31609 -31610 -31611 -31612 +v -31613 -31614 -31615 -31616 31617 -31618 -31619 -31620 -31621 -31622 -31623 +v -31624 -31625 -31626 -31627 -31628 -31629 -31630 -31631 -31632 -31633 -31634 +v -31635 -31636 -31637 -31638 -31639 31640 -31641 -31642 -31643 -31644 -31645 +v -31646 -31647 -31648 -31649 -31650 -31651 -31652 31653 -31654 -31655 -31656 +v -31657 -31658 -31659 -31660 -31661 -31662 -31663 -31664 -31665 -31666 31667 +v 31668 -31669 -31670 31671 31672 31673 -31674 -31675 -31676 -31677 31678 +v -31679 31680 -31681 -31682 31683 -31684 31685 -31686 -31687 -31688 31689 +v -31690 31691 31692 31693 31694 -31695 -31696 31697 -31698 -31699 -31700 +v -31701 31702 -31703 31704 -31705 -31706 31707 -31708 -31709 -31710 -31711 +v -31712 -31713 -31714 -31715 -31716 -31717 -31718 31719 31720 31721 31722 +v 31723 31724 31725 31726 -31727 -31728 -31729 31730 31731 -31732 31733 31734 +v -31735 -31736 31737 31738 31739 31740 31741 31742 31743 31744 -31745 31746 +v 31747 -31748 -31749 -31750 -31751 31752 31753 31754 31755 -31756 31757 31758 +v -31759 -31760 31761 -31762 -31763 -31764 31765 -31766 -31767 31768 -31769 +v -31770 -31771 31772 -31773 -31774 31775 31776 31777 31778 31779 31780 31781 +v -31782 -31783 31784 31785 31786 31787 31788 -31789 -31790 -31791 -31792 +v -31793 -31794 31795 31796 31797 -31798 -31799 -31800 31801 -31802 -31803 +v -31804 -31805 -31806 -31807 -31808 31809 31810 31811 31812 31813 31814 31815 +v 31816 -31817 31818 31819 31820 -31821 -31822 -31823 31824 31825 31826 31827 +v 31828 31829 -31830 -31831 -31832 31833 31834 -31835 31836 31837 -31838 -31839 +v 31840 -31841 -31842 31843 -31844 -31845 -31846 31847 -31848 -31849 31850 +v -31851 -31852 -31853 -31854 31855 31856 31857 31858 31859 31860 31861 -31862 +v -31863 31864 31865 31866 31867 31868 -31869 -31870 31871 -31872 -31873 -31874 +v -31875 -31876 -31877 -31878 -31879 -31880 -31881 -31882 31883 -31884 31885 +v 31886 31887 -31888 -31889 31890 -31891 -31892 31893 -31894 31895 -31896 +v -31897 31898 -31899 31900 -31901 -31902 -31903 31904 -31905 31906 -31907 +v -31908 31909 -31910 -31911 -31912 -31913 -31914 -31915 -31916 -31917 -31918 +v -31919 -31920 31921 31922 31923 31924 -31925 31926 -31927 -31928 -31929 31930 +v -31931 -31932 -31933 -31934 -31935 -31936 -31937 31938 31939 -31940 31941 +v -31942 -31943 -31944 -31945 -31946 31947 -31948 31949 -31950 -31951 -31952 +v -31953 -31954 -31955 -31956 -31957 -31958 -31959 -31960 31961 31962 -31963 +v -31964 -31965 31966 -31967 31968 -31969 -31970 -31971 -31972 -31973 -31974 +v -31975 -31976 -31977 -31978 -31979 -31980 31981 31982 -31983 31984 -31985 +v 31986 -31987 -31988 -31989 31990 -31991 31992 -31993 -31994 -31995 -31996 +v -31997 -31998 -31999 -32000 -32001 -32002 -32003 32004 32005 -32006 -32007 +v 32008 -32009 -32010 32011 32012 32013 32014 -32015 -32016 -32017 -32018 +v -32019 -32020 -32021 -32022 -32023 -32024 -32025 -32026 -32027 -32028 -32029 +v -32030 -32031 -32032 32033 -32034 32035 -32036 -32037 -32038 32039 -32040 +v 32041 -32042 -32043 32044 -32045 -32046 -32047 -32048 -32049 -32050 32051 +v 32052 32053 32054 -32055 -32056 -32057 -32058 -32059 -32060 -32061 -32062 +v -32063 -32064 -32065 -32066 -32067 -32068 -32069 -32070 32071 -32072 32073 +v -32074 -32075 -32076 32077 -32078 32079 -32080 -32081 32082 -32083 -32084 +v -32085 -32086 -32087 -32088 32089 32090 32091 32092 -32093 -32094 -32095 +v -32096 -32097 -32098 -32099 -32100 -32101 -32102 -32103 -32104 -32105 -32106 +v -32107 -32108 32109 -32110 32111 -32112 -32113 -32114 32115 -32116 32117 +v -32118 -32119 32120 -32121 -32122 -32123 -32124 -32125 -32126 32127 32128 +v 32129 32130 -32131 -32132 -32133 -32134 32135 32136 32137 32138 -32139 -32140 +v -32141 -32142 -32143 -32144 -32145 -32146 -32147 -32148 -32149 -32150 -32151 +v -32152 -32153 -32154 -32155 -32156 -32157 -32158 -32159 32160 -32161 32162 +v -32163 -32164 -32165 -32166 32167 -32168 32169 -32170 -32171 32172 -32173 +v -32174 -32175 -32176 -32177 -32178 32179 32180 32181 32182 32183 32184 -32185 +v -32186 -32187 -32188 -32189 -32190 -32191 -32192 -32193 -32194 -32195 -32196 +v 32197 -32198 -32199 -32200 -32201 32202 32203 32204 32205 -32206 -32207 32208 +v -32209 32210 -32211 32212 -32213 -32214 -32215 32216 32217 32218 32219 32220 +v -32221 -32222 32223 32224 -32225 -32226 32227 32228 -32229 -32230 -32231 +v -32232 -32233 32234 32235 32236 32237 -32238 -32239 32240 32241 -32242 32243 +v -32244 32245 -32246 -32247 -32248 -32249 -32250 -32251 32252 32253 -32254 +v 32255 -32256 32257 -32258 -32259 -32260 -32261 -32262 -32263 32264 32265 +v -32266 32267 -32268 32269 -32270 -32271 -32272 -32273 -32274 -32275 32276 +v 32277 -32278 -32279 32280 32281 -32282 -32283 32284 -32285 -32286 32287 +v -32288 32289 -32290 32291 -32292 -32293 -32294 32295 32296 32297 32298 32299 +v 32300 32301 32302 32303 -32304 -32305 -32306 32307 32308 -32309 32310 32311 +v -32312 -32313 32314 32315 32316 32317 32318 32319 32320 32321 -32322 -32323 +v 32324 32325 32326 -32327 32328 -32329 -32330 32331 -32332 -32333 32334 -32335 +v -32336 32337 -32338 -32339 -32340 32341 -32342 -32343 32344 32345 32346 32347 +v 32348 32349 32350 -32351 -32352 32353 32354 32355 32356 32357 -32358 -32359 +v -32360 -32361 -32362 -32363 -32364 32365 -32366 32367 32368 32369 -32370 +v -32371 32372 -32373 -32374 32375 -32376 32377 -32378 -32379 32380 -32381 +v 32382 -32383 -32384 -32385 32386 -32387 32388 -32389 -32390 32391 -32392 +v -32393 -32394 -32395 -32396 -32397 -32398 -32399 -32400 -32401 -32402 32403 +v 32404 32405 32406 -32407 -32408 32409 32410 -32411 -32412 -32413 -32414 +v -32415 -32416 -32417 -32418 -32419 -32420 -32421 -32422 -32423 -32424 -32425 +v -32426 -32427 -32428 -32429 -32430 -32431 -32432 -32433 -32434 -32435 -32436 +v -32437 -32438 -32439 -32440 -32441 -32442 -32443 -32444 -32445 -32446 -32447 +v -32448 -32449 -32450 -32451 -32452 -32453 -32454 -32455 -32456 -32457 -32458 +v -32459 -32460 -32461 -32462 -32463 32464 -32465 -32466 32467 -32468 32469 +v -32470 -32471 -32472 -32473 -32474 -32475 -32476 -32477 -32478 -32479 -32480 +v -32481 -32482 -32483 -32484 -32485 -32486 -32487 -32488 -32489 -32490 -32491 +v -32492 -32493 -32494 -32495 -32496 -32497 -32498 -32499 -32500 -32501 -32502 +v -32503 -32504 -32505 -32506 -32507 -32508 -32509 -32510 -32511 -32512 -32513 +v -32514 -32515 -32516 -32517 -32518 -32519 -32520 -32521 -32522 -32523 -32524 +v -32525 -32526 32527 -32528 32529 -32530 -32531 -32532 32533 -32534 32535 +v -32536 -32537 -32538 -32539 32540 -32541 32542 -32543 -32544 -32545 -32546 +v 32547 -32548 32549 -32550 -32551 32552 -32553 -32554 -32555 -32556 -32557 +v -32558 -32559 -32560 -32561 -32562 32563 32564 32565 32566 -32567 -32568 +v -32569 32570 -32571 -32572 -32573 -32574 -32575 -32576 -32577 -32578 -32579 +v -32580 -32581 -32582 -32583 -32584 -32585 -32586 -32587 -32588 -32589 32590 +v -32591 32592 -32593 -32594 32595 -32596 -32597 -32598 -32599 32600 32601 +v 32602 32603 -32604 -32605 32606 -32607 -32608 32609 32610 32611 32612 -32613 +v -32614 -32615 -32616 -32617 -32618 -32619 -32620 -32621 -32622 -32623 -32624 +v 32625 -32626 -32627 -32628 -32629 -32630 -32631 -32632 -32633 -32634 -32635 +v -32636 32637 -32638 -32639 -32640 -32641 -32642 -32643 -32644 32645 -32646 +v -32647 32648 32649 32650 32651 32652 32653 32654 -32655 -32656 32657 -32658 +v 32659 -32660 -32661 -32662 -32663 -32664 -32665 -32666 -32667 -32668 -32669 +v -32670 32671 -32672 -32673 -32674 -32675 -32676 -32677 -32678 -32679 -32680 +v 32681 -32682 -32683 -32684 -32685 -32686 -32687 -32688 -32689 -32690 -32691 +v 32692 32693 -32694 -32695 -32696 -32697 -32698 -32699 -32700 32701 -32702 +v -32703 -32704 -32705 -32706 -32707 -32708 -32709 32710 -32711 -32712 32713 +v -32714 32715 -32716 32717 -32718 -32719 32720 -32721 -32722 32723 32724 32725 +v 32726 32727 -32728 -32729 -32730 -32731 -32732 -32733 32734 32735 -32736 +v -32737 -32738 -32739 -32740 -32741 -32742 32743 -32744 -32745 -32746 -32747 +v -32748 -32749 -32750 -32751 -32752 -32753 32754 32755 32756 -32757 -32758 +v -32759 -32760 -32761 -32762 -32763 -32764 -32765 -32766 -32767 32768 -32769 +v -32770 -32771 -32772 -32773 -32774 -32775 32776 -32777 32778 -32779 -32780 +v -32781 32782 -32783 32784 32785 32786 32787 32788 -32789 -32790 32791 -32792 +v -32793 -32794 -32795 32796 -32797 32798 -32799 -32800 32801 -32802 -32803 +v -32804 -32805 -32806 -32807 -32808 -32809 -32810 -32811 32812 32813 32814 +v -32815 -32816 -32817 -32818 -32819 -32820 -32821 -32822 -32823 -32824 -32825 +v -32826 -32827 -32828 -32829 -32830 -32831 -32832 -32833 -32834 -32835 -32836 +v -32837 -32838 -32839 -32840 -32841 -32842 -32843 32844 -32845 32846 -32847 +v -32848 32849 -32850 32851 -32852 -32853 32854 -32855 -32856 -32857 -32858 +v -32859 32860 32861 32862 -32863 -32864 32865 -32866 -32867 32868 32869 32870 +v 32871 32872 32873 -32874 32875 32876 -32877 -32878 -32879 32880 32881 32882 +v -32883 -32884 -32885 -32886 -32887 -32888 -32889 -32890 -32891 -32892 -32893 +v -32894 -32895 -32896 -32897 -32898 -32899 -32900 -32901 -32902 -32903 -32904 +v -32905 32906 32907 -32908 32909 32910 -32911 32912 32913 32914 32915 32916 +v 32917 -32918 -32919 -32920 -32921 -32922 -32923 -32924 -32925 32926 -32927 +v -32928 32929 -32930 32931 -32932 -32933 32934 -32935 -32936 -32937 -32938 +v -32939 -32940 -32941 -32942 -32943 -32944 32945 -32946 -32947 32948 -32949 +v -32950 -32951 -32952 -32953 -32954 -32955 -32956 -32957 -32958 -32959 -32960 +v -32961 -32962 32963 32964 32965 32966 32967 32968 -32969 -32970 -32971 -32972 +v -32973 -32974 -32975 -32976 32977 32978 32979 32980 32981 32982 32983 32984 +v -32985 -32986 -32987 -32988 -32989 -32990 -32991 -32992 -32993 -32994 -32995 +v -32996 -32997 -32998 -32999 -33000 -33001 -33002 -33003 -33004 -33005 -33006 +v -33007 -33008 33009 33010 -33011 -33012 33013 -33014 -33015 -33016 -33017 +v -33018 -33019 -33020 -33021 -33022 -33023 -33024 -33025 -33026 -33027 -33028 +v -33029 33030 -33031 -33032 -33033 -33034 -33035 -33036 -33037 -33038 -33039 +v 33040 33041 -33042 -33043 -33044 -33045 -33046 -33047 -33048 -33049 -33050 +v -33051 -33052 -33053 -33054 -33055 -33056 -33057 -33058 -33059 -33060 -33061 +v -33062 -33063 -33064 -33065 -33066 33067 -33068 -33069 -33070 -33071 -33072 +v -33073 -33074 -33075 33076 -33077 -33078 33079 -33080 -33081 -33082 -33083 +v -33084 -33085 -33086 -33087 -33088 -33089 -33090 -33091 -33092 -33093 33094 +v -33095 -33096 -33097 -33098 -33099 -33100 33101 33102 33103 -33104 -33105 +v -33106 33107 -33108 -33109 -33110 -33111 -33112 -33113 -33114 -33115 -33116 +v -33117 -33118 -33119 -33120 33121 -33122 -33123 -33124 -33125 33126 33127 +v 33128 33129 -33130 33131 -33132 -33133 -33134 -33135 -33136 -33137 -33138 +v -33139 -33140 33141 -33142 -33143 33144 33145 33146 33147 -33148 -33149 33150 +v -33151 33152 33153 33154 33155 33156 -33157 -33158 -33159 -33160 -33161 +v -33162 -33163 -33164 -33165 -33166 -33167 -33168 -33169 33170 33171 -33172 +v -33173 33174 33175 -33176 -33177 -33178 -33179 -33180 33181 33182 -33183 +v -33184 -33185 -33186 -33187 33188 -33189 -33190 33191 -33192 -33193 -33194 +v -33195 -33196 -33197 33198 33199 33200 33201 -33202 -33203 33204 -33205 +v -33206 -33207 -33208 -33209 -33210 -33211 -33212 -33213 33214 33215 33216 +v 33217 33218 33219 -33220 -33221 -33222 33223 33224 -33225 33226 33227 -33228 +v 33229 33230 33231 33232 33233 -33234 -33235 -33236 -33237 33238 33239 -33240 +v -33241 33242 33243 33244 -33245 -33246 33247 -33248 -33249 -33250 33251 +v -33252 33253 -33254 -33255 -33256 -33257 -33258 -33259 -33260 -33261 -33262 +v -33263 -33264 -33265 -33266 -33267 -33268 -33269 -33270 -33271 -33272 -33273 +v -33274 -33275 -33276 -33277 -33278 -33279 -33280 -33281 -33282 33283 33284 +v -33285 -33286 33287 33288 33289 -33290 33291 33292 33293 -33294 33295 -33296 +v 33297 -33298 -33299 33300 -33301 -33302 -33303 -33304 -33305 -33306 -33307 +v -33308 -33309 -33310 -33311 -33312 33313 33314 33315 33316 33317 33318 33319 +v 33320 -33321 -33322 33323 33324 33325 33326 33327 33328 33329 33330 33331 +v -33332 -33333 -33334 -33335 -33336 -33337 -33338 -33339 -33340 -33341 33342 +v 33343 -33344 33345 -33346 -33347 -33348 -33349 33350 33351 -33352 -33353 +v -33354 -33355 -33356 -33357 -33358 -33359 -33360 33361 -33362 -33363 -33364 +v -33365 -33366 33367 -33368 -33369 -33370 -33371 -33372 33373 33374 -33375 +v -33376 -33377 33378 33379 33380 -33381 -33382 -33383 -33384 -33385 -33386 +v -33387 -33388 33389 33390 33391 33392 33393 -33394 -33395 -33396 -33397 +v -33398 -33399 -33400 -33401 -33402 -33403 33404 33405 -33406 -33407 33408 +v 33409 -33410 -33411 -33412 -33413 -33414 -33415 -33416 -33417 -33418 -33419 +v -33420 33421 -33422 -33423 33424 -33425 -33426 -33427 -33428 -33429 -33430 +v 33431 33432 33433 33434 -33435 -33436 -33437 -33438 -33439 -33440 -33441 +v -33442 -33443 -33444 -33445 -33446 -33447 -33448 -33449 -33450 -33451 33452 +v 33453 -33454 -33455 -33456 33457 -33458 -33459 33460 -33461 -33462 -33463 +v -33464 -33465 -33466 -33467 -33468 -33469 -33470 33471 33472 -33473 33474 +v 33475 33476 -33477 -33478 -33479 33480 -33481 -33482 -33483 -33484 -33485 +v -33486 -33487 -33488 33489 -33490 33491 -33492 -33493 33494 -33495 33496 +v -33497 -33498 33499 -33500 33501 33502 33503 -33504 -33505 33506 33507 33508 +v -33509 -33510 33511 -33512 -33513 33514 -33515 33516 33517 33518 33519 -33520 +v -33521 33522 -33523 -33524 33525 -33526 -33527 -33528 -33529 -33530 -33531 +v -33532 -33533 -33534 -33535 -33536 -33537 -33538 -33539 -33540 -33541 33542 +v 33543 33544 33545 -33546 33547 -33548 -33549 -33550 33551 33552 -33553 -33554 +v -33555 -33556 -33557 -33558 -33559 -33560 -33561 -33562 -33563 -33564 -33565 +v -33566 -33567 -33568 -33569 -33570 -33571 -33572 -33573 -33574 -33575 -33576 +v 33577 -33578 33579 -33580 -33581 -33582 33583 -33584 33585 -33586 -33587 +v 33588 -33589 -33590 -33591 -33592 -33593 -33594 33595 33596 33597 33598 +v -33599 -33600 -33601 -33602 -33603 -33604 -33605 -33606 -33607 -33608 -33609 +v -33610 -33611 -33612 -33613 -33614 -33615 -33616 -33617 -33618 -33619 -33620 +v -33621 -33622 33623 -33624 33625 -33626 -33627 -33628 33629 -33630 33631 +v -33632 -33633 33634 -33635 -33636 -33637 -33638 -33639 -33640 33641 33642 +v 33643 33644 -33645 -33646 -33647 -33648 -33649 -33650 -33651 -33652 -33653 +v -33654 -33655 -33656 -33657 -33658 -33659 -33660 -33661 -33662 -33663 -33664 +v -33665 -33666 -33667 -33668 33669 -33670 33671 -33672 -33673 -33674 33675 +v -33676 33677 -33678 -33679 33680 -33681 -33682 -33683 -33684 -33685 -33686 +v 33687 33688 33689 33690 33691 -33692 -33693 33694 -33695 -33696 -33697 -33698 +v -33699 -33700 -33701 -33702 -33703 -33704 -33705 -33706 -33707 -33708 -33709 +v -33710 -33711 -33712 -33713 -33714 -33715 -33716 -33717 -33718 -33719 -33720 +v -33721 -33722 -33723 -33724 -33725 -33726 -33727 -33728 -33729 -33730 -33731 +v -33732 -33733 -33734 -33735 -33736 -33737 -33738 -33739 -33740 -33741 -33742 +v -33743 -33744 -33745 -33746 -33747 -33748 -33749 -33750 -33751 -33752 -33753 +v -33754 -33755 -33756 -33757 -33758 -33759 -33760 -33761 -33762 -33763 -33764 +v -33765 -33766 -33767 -33768 -33769 -33770 -33771 -33772 -33773 -33774 -33775 +v -33776 -33777 -33778 -33779 -33780 -33781 -33782 -33783 -33784 -33785 -33786 +v -33787 -33788 -33789 -33790 -33791 -33792 -33793 -33794 -33795 -33796 -33797 +v -33798 -33799 -33800 -33801 -33802 -33803 -33804 -33805 -33806 -33807 -33808 +v -33809 -33810 -33811 -33812 -33813 -33814 -33815 -33816 -33817 -33818 -33819 +v -33820 -33821 -33822 -33823 -33824 -33825 -33826 -33827 -33828 33829 -33830 +v 33831 -33832 -33833 -33834 33835 -33836 33837 -33838 -33839 -33840 33841 +v -33842 33843 -33844 -33845 -33846 -33847 33848 -33849 33850 -33851 -33852 +v 33853 -33854 -33855 -33856 -33857 -33858 -33859 -33860 -33861 -33862 -33863 +v 33864 33865 33866 33867 -33868 -33869 -33870 -33871 -33872 -33873 -33874 +v -33875 -33876 -33877 -33878 -33879 -33880 -33881 -33882 -33883 -33884 -33885 +v -33886 -33887 -33888 -33889 -33890 -33891 33892 -33893 33894 -33895 -33896 +v -33897 33898 -33899 33900 -33901 -33902 33903 -33904 -33905 -33906 -33907 +v -33908 -33909 33910 33911 33912 33913 -33914 -33915 33916 -33917 -33918 33919 +v 33920 33921 -33922 -33923 -33924 -33925 -33926 -33927 -33928 -33929 -33930 +v -33931 -33932 -33933 -33934 -33935 -33936 -33937 -33938 -33939 -33940 -33941 +v -33942 -33943 -33944 -33945 -33946 -33947 -33948 -33949 -33950 -33951 -33952 +v -33953 -33954 -33955 -33956 -33957 -33958 -33959 -33960 -33961 -33962 -33963 +v -33964 -33965 -33966 -33967 -33968 -33969 -33970 -33971 -33972 -33973 -33974 +v -33975 -33976 -33977 -33978 -33979 -33980 -33981 -33982 -33983 -33984 -33985 +v -33986 -33987 -33988 -33989 -33990 -33991 -33992 -33993 -33994 -33995 -33996 +v -33997 -33998 -33999 -34000 -34001 -34002 -34003 -34004 -34005 -34006 -34007 +v -34008 -34009 -34010 -34011 -34012 -34013 -34014 -34015 -34016 -34017 -34018 +v -34019 -34020 -34021 -34022 -34023 -34024 -34025 -34026 -34027 -34028 -34029 +v -34030 -34031 -34032 -34033 -34034 -34035 -34036 -34037 -34038 -34039 -34040 +v -34041 -34042 -34043 -34044 -34045 -34046 -34047 -34048 -34049 -34050 -34051 +v -34052 -34053 -34054 -34055 -34056 -34057 -34058 -34059 -34060 -34061 -34062 +v -34063 -34064 -34065 -34066 -34067 -34068 -34069 -34070 -34071 -34072 -34073 +v -34074 -34075 -34076 -34077 -34078 -34079 -34080 -34081 -34082 -34083 -34084 +v -34085 -34086 -34087 -34088 -34089 -34090 -34091 -34092 -34093 -34094 -34095 +v -34096 -34097 -34098 -34099 -34100 -34101 -34102 -34103 -34104 -34105 -34106 +v -34107 -34108 -34109 -34110 -34111 -34112 -34113 -34114 -34115 -34116 -34117 +v -34118 -34119 -34120 -34121 -34122 -34123 -34124 -34125 -34126 -34127 -34128 +v -34129 -34130 -34131 -34132 -34133 -34134 -34135 -34136 -34137 -34138 -34139 +v -34140 -34141 -34142 -34143 -34144 -34145 -34146 -34147 -34148 -34149 -34150 +v -34151 -34152 -34153 -34154 -34155 -34156 -34157 -34158 -34159 -34160 -34161 +v -34162 -34163 -34164 -34165 -34166 -34167 -34168 -34169 -34170 -34171 -34172 +v -34173 -34174 -34175 -34176 -34177 -34178 -34179 -34180 -34181 -34182 -34183 +v -34184 -34185 -34186 -34187 -34188 -34189 -34190 -34191 -34192 -34193 -34194 +v -34195 -34196 -34197 -34198 -34199 -34200 -34201 -34202 -34203 -34204 -34205 +v -34206 -34207 -34208 -34209 -34210 -34211 -34212 -34213 -34214 -34215 -34216 +v -34217 -34218 -34219 -34220 -34221 -34222 -34223 -34224 -34225 -34226 -34227 +v -34228 -34229 -34230 -34231 -34232 -34233 -34234 -34235 -34236 -34237 -34238 +v -34239 -34240 -34241 -34242 -34243 -34244 -34245 -34246 -34247 -34248 -34249 +v -34250 -34251 -34252 -34253 -34254 -34255 -34256 -34257 -34258 -34259 -34260 +v -34261 -34262 -34263 -34264 -34265 -34266 -34267 -34268 -34269 -34270 -34271 +v -34272 -34273 -34274 -34275 -34276 -34277 -34278 -34279 -34280 -34281 -34282 +v -34283 -34284 -34285 -34286 -34287 -34288 -34289 -34290 -34291 -34292 -34293 +v -34294 -34295 -34296 -34297 -34298 -34299 -34300 -34301 -34302 -34303 -34304 +v -34305 -34306 -34307 -34308 -34309 -34310 -34311 -34312 -34313 -34314 -34315 +v -34316 -34317 -34318 -34319 -34320 -34321 -34322 -34323 -34324 -34325 -34326 +v -34327 -34328 -34329 -34330 -34331 -34332 -34333 -34334 -34335 -34336 -34337 +v -34338 -34339 -34340 -34341 -34342 -34343 -34344 -34345 -34346 -34347 34348 +v -34349 34350 -34351 -34352 34353 -34354 34355 -34356 -34357 -34358 34359 +v -34360 34361 -34362 -34363 -34364 -34365 34366 -34367 34368 -34369 -34370 +v -34371 -34372 34373 -34374 34375 -34376 -34377 -34378 -34379 34380 -34381 +v 34382 -34383 -34384 34385 -34386 34387 -34388 -34389 34390 -34391 -34392 +v -34393 -34394 -34395 -34396 -34397 -34398 -34399 -34400 -34401 -34402 -34403 +v -34404 -34405 34406 34407 34408 34409 -34410 -34411 -34412 -34413 -34414 +v 34415 -34416 -34417 -34418 -34419 -34420 -34421 -34422 -34423 -34424 -34425 +v -34426 -34427 -34428 -34429 -34430 -34431 -34432 -34433 -34434 -34435 -34436 +v -34437 -34438 -34439 -34440 -34441 -34442 -34443 -34444 -34445 -34446 -34447 +v -34448 -34449 -34450 -34451 -34452 -34453 -34454 -34455 -34456 -34457 -34458 +v -34459 -34460 -34461 -34462 -34463 -34464 -34465 -34466 -34467 -34468 -34469 +v -34470 -34471 -34472 -34473 -34474 -34475 -34476 -34477 -34478 -34479 -34480 +v -34481 -34482 -34483 -34484 -34485 -34486 -34487 -34488 -34489 -34490 -34491 +v -34492 -34493 -34494 -34495 -34496 -34497 -34498 -34499 -34500 -34501 -34502 +v -34503 -34504 -34505 -34506 -34507 -34508 -34509 -34510 -34511 -34512 -34513 +v -34514 -34515 -34516 -34517 -34518 -34519 -34520 -34521 34522 -34523 34524 +v -34525 -34526 -34527 -34528 34529 -34530 34531 -34532 -34533 -34534 -34535 +v 34536 -34537 34538 -34539 -34540 -34541 -34542 34543 -34544 34545 -34546 +v -34547 34548 -34549 34550 -34551 -34552 34553 -34554 -34555 -34556 -34557 +v -34558 -34559 -34560 -34561 -34562 -34563 -34564 -34565 34566 34567 34568 +v 34569 -34570 -34571 -34572 -34573 -34574 -34575 -34576 -34577 -34578 -34579 +v -34580 -34581 -34582 -34583 -34584 -34585 -34586 -34587 -34588 -34589 -34590 +v -34591 -34592 -34593 -34594 -34595 -34596 -34597 -34598 -34599 -34600 -34601 +v -34602 -34603 -34604 -34605 -34606 -34607 -34608 -34609 -34610 -34611 -34612 +v -34613 -34614 -34615 -34616 34617 -34618 -34619 34620 -34621 -34622 34623 +v -34624 -34625 -34626 34627 -34628 -34629 -34630 -34631 -34632 -34633 -34634 +v -34635 -34636 -34637 -34638 34639 -34640 34641 34642 34643 34644 -34645 +v -34646 -34647 -34648 -34649 -34650 -34651 -34652 -34653 -34654 -34655 -34656 +v -34657 -34658 -34659 -34660 -34661 -34662 -34663 -34664 -34665 -34666 -34667 +v -34668 -34669 -34670 -34671 -34672 -34673 -34674 -34675 -34676 -34677 -34678 +v -34679 -34680 -34681 -34682 -34683 -34684 -34685 -34686 -34687 -34688 -34689 +v -34690 -34691 -34692 -34693 -34694 -34695 -34696 -34697 -34698 -34699 -34700 +v -34701 -34702 34703 -34704 -34705 -34706 -34707 -34708 -34709 -34710 -34711 +v -34712 -34713 -34714 -34715 -34716 -34717 -34718 -34719 -34720 -34721 -34722 +v -34723 -34724 -34725 -34726 -34727 -34728 -34729 -34730 34731 -34732 34733 +v -34734 -34735 -34736 34737 -34738 34739 -34740 -34741 -34742 34743 -34744 +v 34745 -34746 -34747 -34748 34749 -34750 34751 -34752 -34753 34754 -34755 +v -34756 -34757 -34758 -34759 -34760 -34761 -34762 -34763 -34764 -34765 34766 +v 34767 34768 34769 -34770 -34771 -34772 -34773 -34774 -34775 -34776 -34777 +v 34778 -34779 34780 -34781 34782 -34783 -34784 -34785 -34786 34787 34788 34789 +v 34790 34791 -34792 34793 -34794 -34795 -34796 -34797 34798 34799 34800 -34801 +v -34802 -34803 34804 -34805 -34806 -34807 -34808 -34809 -34810 -34811 -34812 +v 34813 34814 34815 34816 34817 -34818 -34819 34820 34821 34822 34823 34824 +v 34825 34826 34827 -34828 -34829 -34830 -34831 34832 34833 -34834 -34835 +v -34836 -34837 -34838 -34839 -34840 -34841 -34842 -34843 34844 -34845 -34846 +v 34847 34848 34849 34850 34851 34852 -34853 -34854 -34855 -34856 -34857 -34858 +v -34859 34860 -34861 -34862 -34863 34864 34865 34866 34867 34868 34869 34870 +v -34871 -34872 34873 34874 -34875 34876 -34877 -34878 34879 -34880 -34881 +v -34882 -34883 34884 34885 -34886 -34887 -34888 -34889 34890 34891 34892 34893 +v 34894 34895 34896 -34897 -34898 -34899 34900 34901 34902 34903 34904 34905 +v 34906 34907 -34908 34909 -34910 34911 34912 -34913 34914 -34915 -34916 34917 +v 34918 -34919 34920 -34921 -34922 34923 34924 -34925 -34926 -34927 34928 +v -34929 34930 -34931 -34932 34933 -34934 -34935 -34936 -34937 -34938 -34939 +v -34940 -34941 -34942 -34943 34944 34945 34946 34947 -34948 -34949 -34950 +v -34951 -34952 -34953 -34954 -34955 -34956 34957 -34958 -34959 34960 -34961 +v -34962 -34963 -34964 -34965 34966 34967 34968 34969 -34970 -34971 34972 +v -34973 -34974 -34975 -34976 -34977 -34978 -34979 -34980 -34981 -34982 -34983 +v 34984 34985 -34986 -34987 34988 -34989 -34990 34991 -34992 -34993 -34994 +v 34995 -34996 -34997 -34998 -34999 -35000 -35001 -35002 -35003 -35004 -35005 +v -35006 -35007 -35008 -35009 -35010 -35011 -35012 -35013 -35014 -35015 -35016 +v -35017 -35018 -35019 -35020 -35021 -35022 -35023 35024 35025 -35026 -35027 +v 35028 35029 35030 -35031 35032 35033 -35034 -35035 35036 -35037 -35038 35039 +v -35040 -35041 -35042 -35043 -35044 -35045 -35046 -35047 -35048 -35049 -35050 +v -35051 -35052 35053 35054 35055 35056 35057 35058 35059 -35060 35061 35062 +v 35063 35064 35065 35066 35067 35068 -35069 -35070 -35071 -35072 -35073 -35074 +v -35075 -35076 -35077 -35078 -35079 -35080 -35081 -35082 -35083 -35084 -35085 +v -35086 -35087 -35088 -35089 -35090 -35091 -35092 -35093 35094 35095 -35096 +v -35097 35098 -35099 -35100 -35101 -35102 -35103 -35104 -35105 35106 -35107 +v -35108 -35109 -35110 -35111 -35112 -35113 -35114 35115 -35116 -35117 -35118 +v -35119 -35120 -35121 -35122 -35123 35124 35125 -35126 -35127 -35128 -35129 +v -35130 35131 -35132 -35133 -35134 -35135 -35136 -35137 -35138 -35139 -35140 +v -35141 -35142 -35143 -35144 -35145 -35146 -35147 35148 35149 -35150 -35151 +v -35152 -35153 -35154 -35155 -35156 -35157 35158 -35159 -35160 -35161 -35162 +v -35163 -35164 -35165 -35166 35167 -35168 -35169 -35170 -35171 -35172 -35173 +v -35174 -35175 -35176 -35177 -35178 -35179 -35180 -35181 -35182 -35183 -35184 +v -35185 -35186 -35187 -35188 -35189 35190 35191 35192 35193 35194 35195 -35196 +v -35197 -35198 -35199 -35200 -35201 -35202 -35203 35204 -35205 35206 35207 +v -35208 -35209 -35210 -35211 -35212 -35213 -35214 -35215 -35216 35217 -35218 +v -35219 -35220 -35221 -35222 -35223 -35224 35225 35226 35227 -35228 -35229 +v 35230 35231 -35232 -35233 35234 -35235 -35236 -35237 -35238 -35239 -35240 +v -35241 -35242 -35243 -35244 -35245 -35246 -35247 35248 35249 -35250 35251 +v 35252 35253 -35254 35255 -35256 -35257 35258 -35259 -35260 35261 -35262 +v -35263 -35264 -35265 -35266 -35267 -35268 -35269 35270 35271 35272 35273 +v 35274 -35275 -35276 -35277 -35278 -35279 -35280 -35281 -35282 35283 -35284 +v 35285 35286 -35287 35288 -35289 -35290 35291 -35292 -35293 -35294 -35295 +v -35296 -35297 -35298 35299 35300 35301 35302 35303 -35304 35305 35306 35307 +v 35308 -35309 -35310 -35311 -35312 -35313 -35314 -35315 -35316 -35317 35318 +v 35319 -35320 -35321 -35322 -35323 -35324 -35325 -35326 -35327 35328 -35329 +v -35330 -35331 -35332 -35333 -35334 -35335 -35336 35337 -35338 -35339 -35340 +v -35341 35342 35343 35344 -35345 -35346 -35347 -35348 -35349 -35350 35351 +v -35352 -35353 -35354 -35355 -35356 -35357 -35358 -35359 35360 -35361 -35362 +v -35363 -35364 -35365 -35366 -35367 -35368 -35369 -35370 -35371 -35372 -35373 +v -35374 -35375 -35376 -35377 -35378 -35379 -35380 -35381 -35382 -35383 -35384 +v 35385 35386 35387 -35388 -35389 -35390 -35391 -35392 -35393 -35394 -35395 +v -35396 -35397 35398 -35399 -35400 -35401 -35402 -35403 -35404 -35405 -35406 +v 35407 -35408 -35409 -35410 -35411 -35412 -35413 -35414 -35415 35416 35417 +v -35418 -35419 -35420 -35421 -35422 35423 -35424 -35425 -35426 -35427 -35428 +v -35429 -35430 35431 -35432 35433 -35434 -35435 35436 -35437 35438 -35439 +v -35440 35441 -35442 35443 35444 35445 35446 -35447 -35448 35449 -35450 -35451 +v -35452 35453 -35454 35455 -35456 -35457 -35458 35459 -35460 35461 35462 35463 +v -35464 -35465 -35466 -35467 -35468 -35469 -35470 -35471 -35472 -35473 -35474 +v -35475 -35476 -35477 35478 35479 35480 -35481 -35482 -35483 35484 35485 +v -35486 -35487 35488 -35489 -35490 -35491 -35492 -35493 -35494 -35495 -35496 +v -35497 35498 35499 35500 35501 -35502 35503 -35504 -35505 -35506 -35507 +v -35508 -35509 -35510 -35511 -35512 -35513 35514 -35515 35516 -35517 -35518 +v -35519 -35520 -35521 -35522 -35523 35524 35525 35526 35527 -35528 35529 +v -35530 -35531 -35532 -35533 -35534 -35535 -35536 -35537 -35538 -35539 -35540 +v -35541 35542 35543 -35544 35545 -35546 -35547 -35548 -35549 -35550 35551 +v -35552 35553 -35554 -35555 -35556 35557 -35558 35559 -35560 -35561 -35562 +v 35563 -35564 35565 35566 35567 35568 -35569 -35570 35571 35572 35573 -35574 +v -35575 -35576 -35577 -35578 -35579 -35580 -35581 -35582 -35583 -35584 35585 +v 35586 35587 35588 -35589 -35590 35591 -35592 35593 -35594 -35595 -35596 +v -35597 -35598 -35599 -35600 -35601 -35602 -35603 -35604 -35605 -35606 -35607 +v 35608 35609 -35610 -35611 -35612 -35613 -35614 -35615 -35616 -35617 -35618 +v 35619 35620 35621 -35622 -35623 35624 -35625 -35626 -35627 -35628 -35629 +v -35630 -35631 -35632 -35633 -35634 -35635 -35636 35637 -35638 35639 -35640 +v -35641 35642 -35643 35644 -35645 -35646 35647 -35648 35649 35650 35651 35652 +v -35653 -35654 35655 35656 35657 -35658 -35659 -35660 -35661 -35662 -35663 +v -35664 -35665 -35666 -35667 -35668 35669 35670 35671 35672 -35673 -35674 +v -35675 -35676 -35677 -35678 -35679 -35680 -35681 -35682 -35683 -35684 -35685 +v -35686 -35687 -35688 -35689 -35690 -35691 -35692 -35693 -35694 -35695 -35696 +v -35697 -35698 -35699 -35700 -35701 -35702 -35703 -35704 35705 -35706 -35707 +v -35708 -35709 -35710 -35711 -35712 -35713 -35714 -35715 -35716 -35717 -35718 +v -35719 -35720 -35721 -35722 -35723 -35724 -35725 -35726 -35727 -35728 -35729 +v 35730 -35731 -35732 -35733 -35734 -35735 -35736 35737 -35738 -35739 -35740 +v -35741 -35742 -35743 -35744 -35745 -35746 -35747 -35748 -35749 -35750 35751 +v -35752 -35753 -35754 -35755 -35756 -35757 -35758 -35759 -35760 -35761 -35762 +v 35763 -35764 35765 -35766 -35767 -35768 35769 -35770 35771 -35772 -35773 +v -35774 35775 -35776 35777 -35778 -35779 -35780 35781 -35782 35783 35784 35785 +v -35786 -35787 -35788 -35789 -35790 -35791 -35792 -35793 -35794 -35795 -35796 +v 35797 35798 35799 -35800 -35801 -35802 -35803 -35804 -35805 -35806 -35807 +v 35808 -35809 35810 -35811 -35812 -35813 -35814 -35815 35816 35817 35818 35819 +v -35820 -35821 -35822 -35823 -35824 -35825 -35826 -35827 -35828 -35829 -35830 +v -35831 -35832 -35833 -35834 -35835 -35836 35837 -35838 -35839 -35840 -35841 +v -35842 35843 -35844 35845 -35846 -35847 -35848 35849 -35850 35851 -35852 +v -35853 35854 -35855 -35856 -35857 -35858 -35859 -35860 35861 35862 35863 +v -35864 -35865 -35866 -35867 -35868 -35869 -35870 -35871 -35872 -35873 -35874 +v -35875 -35876 -35877 -35878 -35879 -35880 35881 -35882 -35883 -35884 -35885 +v -35886 35887 -35888 35889 -35890 -35891 -35892 35893 -35894 35895 -35896 +v -35897 35898 -35899 -35900 -35901 -35902 -35903 -35904 35905 35906 35907 +v -35908 -35909 -35910 -35911 -35912 -35913 -35914 -35915 -35916 -35917 -35918 +v -35919 -35920 -35921 -35922 -35923 -35924 35925 -35926 -35927 -35928 -35929 +v -35930 35931 -35932 35933 -35934 -35935 -35936 35937 -35938 35939 -35940 +v -35941 35942 -35943 -35944 -35945 -35946 -35947 -35948 35949 35950 35951 +v 35952 -35953 35954 -35955 -35956 -35957 -35958 -35959 -35960 -35961 -35962 +v -35963 -35964 -35965 -35966 -35967 -35968 -35969 -35970 -35971 -35972 -35973 +v -35974 -35975 -35976 -35977 -35978 -35979 -35980 -35981 -35982 -35983 -35984 +v -35985 -35986 -35987 -35988 -35989 -35990 -35991 -35992 -35993 -35994 -35995 +v -35996 -35997 -35998 -35999 -36000 -36001 -36002 -36003 -36004 -36005 -36006 +v -36007 -36008 -36009 -36010 -36011 -36012 -36013 -36014 -36015 -36016 -36017 +v -36018 -36019 -36020 -36021 -36022 -36023 -36024 36025 -36026 -36027 -36028 +v -36029 -36030 -36031 -36032 -36033 -36034 -36035 -36036 -36037 -36038 -36039 +v -36040 -36041 -36042 -36043 -36044 -36045 -36046 -36047 -36048 -36049 -36050 +v -36051 -36052 -36053 -36054 -36055 -36056 -36057 -36058 -36059 -36060 -36061 +v -36062 -36063 -36064 -36065 -36066 -36067 -36068 -36069 -36070 -36071 -36072 +v -36073 -36074 -36075 -36076 -36077 -36078 -36079 -36080 -36081 -36082 36083 +v -36084 36085 -36086 -36087 -36088 36089 -36090 36091 -36092 -36093 -36094 +v 36095 -36096 36097 -36098 -36099 -36100 -36101 36102 -36103 36104 -36105 +v -36106 36107 -36108 -36109 -36110 -36111 -36112 -36113 -36114 -36115 -36116 +v -36117 36118 36119 36120 -36121 -36122 -36123 -36124 -36125 -36126 -36127 +v -36128 -36129 -36130 -36131 -36132 -36133 -36134 -36135 -36136 -36137 36138 +v -36139 -36140 -36141 -36142 -36143 36144 -36145 36146 -36147 -36148 -36149 +v 36150 -36151 36152 -36153 -36154 36155 -36156 -36157 -36158 -36159 -36160 +v -36161 36162 36163 36164 36165 -36166 36167 -36168 -36169 -36170 -36171 36172 +v 36173 36174 -36175 -36176 -36177 36178 -36179 -36180 -36181 -36182 -36183 +v 36184 36185 -36186 36187 -36188 -36189 -36190 36191 -36192 36193 -36194 +v -36195 -36196 -36197 -36198 -36199 36200 36201 36202 36203 36204 36205 36206 +v 36207 36208 -36209 -36210 -36211 36212 36213 36214 36215 36216 36217 36218 +v 36219 -36220 -36221 36222 -36223 -36224 36225 -36226 -36227 -36228 36229 +v 36230 36231 36232 36233 36234 36235 -36236 -36237 36238 36239 -36240 36241 +v -36242 -36243 36244 -36245 -36246 -36247 -36248 36249 36250 -36251 -36252 +v -36253 -36254 36255 36256 36257 36258 36259 36260 36261 -36262 -36263 -36264 +v 36265 36266 36267 36268 36269 36270 36271 36272 -36273 -36274 36275 -36276 +v 36277 -36278 36279 -36280 36281 -36282 -36283 36284 -36285 36286 -36287 36288 +v -36289 -36290 36291 -36292 -36293 -36294 -36295 36296 -36297 36298 -36299 +v -36300 36301 -36302 -36303 -36304 -36305 -36306 -36307 -36308 -36309 -36310 +v -36311 36312 36313 36314 -36315 -36316 -36317 -36318 -36319 -36320 -36321 +v -36322 -36323 -36324 -36325 -36326 -36327 -36328 -36329 -36330 -36331 -36332 +v -36333 -36334 -36335 -36336 36337 -36338 36339 -36340 -36341 -36342 36343 +v -36344 36345 -36346 -36347 36348 -36349 -36350 -36351 -36352 -36353 -36354 +v 36355 36356 36357 36358 -36359 -36360 -36361 -36362 -36363 -36364 -36365 +v -36366 -36367 -36368 -36369 -36370 -36371 -36372 -36373 -36374 -36375 -36376 +v -36377 -36378 -36379 -36380 36381 -36382 36383 -36384 -36385 -36386 36387 +v -36388 36389 -36390 -36391 36392 -36393 -36394 -36395 -36396 -36397 -36398 +v 36399 36400 36401 36402 -36403 -36404 -36405 -36406 -36407 -36408 -36409 +v -36410 -36411 -36412 -36413 -36414 -36415 -36416 -36417 -36418 -36419 -36420 +v -36421 -36422 -36423 -36424 36425 -36426 36427 -36428 -36429 -36430 36431 +v -36432 36433 -36434 -36435 36436 -36437 -36438 -36439 -36440 -36441 -36442 +v 36443 36444 36445 36446 36447 -36448 36449 -36450 -36451 -36452 -36453 -36454 +v -36455 -36456 -36457 -36458 -36459 -36460 -36461 -36462 -36463 -36464 -36465 +v -36466 -36467 -36468 -36469 -36470 -36471 -36472 -36473 -36474 -36475 -36476 +v -36477 -36478 -36479 -36480 -36481 -36482 -36483 -36484 -36485 -36486 -36487 +v -36488 -36489 -36490 -36491 -36492 -36493 -36494 -36495 -36496 -36497 -36498 +v -36499 -36500 -36501 -36502 -36503 -36504 -36505 -36506 -36507 -36508 -36509 +v -36510 -36511 -36512 -36513 -36514 -36515 -36516 -36517 -36518 -36519 -36520 +v -36521 -36522 -36523 -36524 -36525 -36526 -36527 -36528 -36529 -36530 -36531 +v -36532 -36533 -36534 -36535 -36536 -36537 -36538 -36539 -36540 -36541 -36542 +v -36543 -36544 -36545 -36546 -36547 -36548 -36549 -36550 -36551 -36552 -36553 +v -36554 -36555 -36556 -36557 -36558 -36559 -36560 -36561 -36562 -36563 -36564 +v -36565 -36566 -36567 -36568 -36569 -36570 -36571 -36572 -36573 -36574 -36575 +v -36576 36577 -36578 36579 -36580 -36581 -36582 36583 -36584 36585 -36586 +v -36587 -36588 36589 -36590 36591 -36592 -36593 -36594 -36595 36596 -36597 +v 36598 -36599 -36600 36601 -36602 -36603 -36604 -36605 -36606 -36607 -36608 +v -36609 -36610 -36611 36612 36613 36614 36615 -36616 -36617 -36618 -36619 +v -36620 -36621 -36622 -36623 -36624 -36625 -36626 -36627 -36628 -36629 -36630 +v -36631 -36632 -36633 -36634 -36635 -36636 -36637 36638 -36639 36640 -36641 +v -36642 -36643 36644 -36645 36646 -36647 -36648 36649 -36650 -36651 -36652 +v -36653 -36654 -36655 36656 36657 36658 36659 -36660 -36661 36662 -36663 +v -36664 36665 36666 -36667 -36668 -36669 -36670 -36671 -36672 -36673 -36674 +v -36675 -36676 -36677 -36678 -36679 -36680 -36681 -36682 -36683 -36684 -36685 +v -36686 -36687 -36688 -36689 -36690 -36691 -36692 -36693 -36694 -36695 -36696 +v -36697 -36698 -36699 -36700 -36701 -36702 -36703 -36704 -36705 -36706 -36707 +v -36708 -36709 -36710 -36711 -36712 -36713 -36714 -36715 -36716 -36717 -36718 +v -36719 -36720 -36721 -36722 -36723 -36724 -36725 -36726 -36727 -36728 -36729 +v -36730 -36731 -36732 -36733 -36734 -36735 -36736 -36737 -36738 -36739 -36740 +v -36741 -36742 -36743 -36744 -36745 -36746 -36747 -36748 -36749 -36750 -36751 +v -36752 -36753 -36754 -36755 -36756 -36757 -36758 -36759 -36760 -36761 -36762 +v -36763 -36764 -36765 -36766 -36767 -36768 -36769 -36770 -36771 -36772 -36773 +v -36774 -36775 -36776 -36777 -36778 -36779 -36780 -36781 -36782 -36783 -36784 +v -36785 -36786 -36787 -36788 -36789 -36790 -36791 -36792 -36793 -36794 -36795 +v -36796 -36797 -36798 -36799 -36800 -36801 -36802 -36803 -36804 -36805 -36806 +v -36807 -36808 -36809 -36810 -36811 -36812 -36813 -36814 -36815 -36816 -36817 +v -36818 -36819 -36820 -36821 -36822 -36823 -36824 -36825 -36826 -36827 -36828 +v -36829 -36830 -36831 -36832 -36833 -36834 -36835 -36836 -36837 -36838 -36839 +v -36840 -36841 -36842 -36843 -36844 -36845 -36846 -36847 -36848 -36849 -36850 +v -36851 -36852 -36853 -36854 -36855 -36856 -36857 -36858 -36859 -36860 -36861 +v -36862 -36863 -36864 -36865 -36866 -36867 -36868 -36869 -36870 -36871 -36872 +v -36873 -36874 -36875 -36876 -36877 -36878 -36879 -36880 -36881 -36882 -36883 +v -36884 -36885 -36886 -36887 -36888 -36889 -36890 -36891 -36892 -36893 -36894 +v -36895 -36896 -36897 -36898 -36899 -36900 -36901 -36902 -36903 -36904 -36905 +v -36906 -36907 -36908 -36909 -36910 -36911 -36912 -36913 -36914 -36915 -36916 +v -36917 -36918 -36919 -36920 -36921 -36922 -36923 -36924 -36925 -36926 -36927 +v -36928 -36929 -36930 -36931 -36932 -36933 -36934 -36935 -36936 -36937 -36938 +v -36939 -36940 -36941 -36942 -36943 -36944 -36945 -36946 -36947 -36948 -36949 +v -36950 -36951 -36952 -36953 -36954 -36955 -36956 -36957 -36958 -36959 -36960 +v -36961 -36962 -36963 -36964 -36965 -36966 -36967 -36968 -36969 -36970 -36971 +v -36972 -36973 -36974 -36975 -36976 -36977 -36978 -36979 -36980 -36981 -36982 +v -36983 -36984 -36985 -36986 -36987 -36988 -36989 -36990 -36991 -36992 -36993 +v -36994 -36995 -36996 -36997 -36998 -36999 -37000 -37001 -37002 -37003 -37004 +v -37005 -37006 -37007 -37008 -37009 -37010 -37011 -37012 -37013 -37014 -37015 +v -37016 -37017 -37018 -37019 -37020 -37021 -37022 -37023 -37024 -37025 -37026 +v -37027 -37028 -37029 -37030 -37031 -37032 -37033 -37034 -37035 -37036 -37037 +v -37038 -37039 -37040 -37041 -37042 -37043 -37044 -37045 -37046 -37047 -37048 +v -37049 -37050 -37051 -37052 -37053 -37054 -37055 -37056 -37057 -37058 -37059 +v -37060 -37061 -37062 -37063 -37064 -37065 -37066 -37067 -37068 -37069 -37070 +v -37071 -37072 37073 -37074 37075 -37076 -37077 37078 -37079 37080 -37081 +v -37082 -37083 37084 -37085 37086 -37087 -37088 -37089 -37090 37091 -37092 +v 37093 -37094 -37095 -37096 -37097 37098 -37099 37100 -37101 -37102 -37103 +v -37104 37105 -37106 37107 -37108 -37109 37110 -37111 37112 -37113 -37114 +v 37115 -37116 -37117 -37118 -37119 -37120 -37121 -37122 -37123 -37124 -37125 +v -37126 -37127 -37128 -37129 -37130 37131 37132 37133 37134 -37135 -37136 +v -37137 -37138 -37139 37140 -37141 -37142 -37143 -37144 -37145 -37146 -37147 +v -37148 -37149 -37150 -37151 -37152 -37153 -37154 -37155 -37156 -37157 -37158 +v -37159 -37160 -37161 -37162 -37163 -37164 -37165 -37166 -37167 -37168 -37169 +v -37170 -37171 -37172 -37173 -37174 -37175 -37176 -37177 -37178 -37179 -37180 +v -37181 -37182 -37183 -37184 -37185 -37186 -37187 -37188 -37189 -37190 -37191 +v -37192 -37193 -37194 -37195 -37196 -37197 -37198 -37199 -37200 -37201 -37202 +v -37203 -37204 -37205 -37206 -37207 -37208 -37209 -37210 -37211 -37212 -37213 +v -37214 -37215 -37216 -37217 -37218 -37219 -37220 -37221 -37222 -37223 -37224 +v -37225 -37226 -37227 -37228 -37229 -37230 -37231 -37232 -37233 -37234 -37235 +v -37236 -37237 -37238 -37239 -37240 -37241 -37242 -37243 -37244 37245 -37246 +v 37247 -37248 -37249 -37250 -37251 37252 -37253 37254 -37255 -37256 -37257 +v -37258 37259 -37260 37261 -37262 -37263 -37264 -37265 37266 -37267 37268 +v -37269 -37270 37271 -37272 37273 -37274 -37275 37276 -37277 -37278 -37279 +v -37280 -37281 -37282 -37283 -37284 -37285 -37286 -37287 -37288 37289 37290 +v 37291 37292 -37293 -37294 -37295 -37296 -37297 -37298 -37299 -37300 -37301 +v -37302 -37303 -37304 -37305 -37306 -37307 -37308 -37309 -37310 -37311 -37312 +v -37313 -37314 -37315 -37316 -37317 -37318 -37319 -37320 -37321 -37322 -37323 +v -37324 -37325 -37326 -37327 -37328 -37329 -37330 -37331 -37332 -37333 -37334 +v -37335 -37336 -37337 -37338 -37339 37340 -37341 -37342 37343 -37344 -37345 +v 37346 -37347 -37348 -37349 37350 -37351 -37352 -37353 -37354 -37355 -37356 +v -37357 -37358 -37359 -37360 -37361 37362 -37363 37364 37365 37366 37367 +v -37368 -37369 -37370 -37371 -37372 -37373 -37374 -37375 -37376 -37377 -37378 +v -37379 -37380 -37381 -37382 -37383 -37384 -37385 -37386 -37387 -37388 -37389 +v -37390 -37391 -37392 -37393 -37394 -37395 -37396 -37397 -37398 -37399 -37400 +v -37401 -37402 -37403 -37404 -37405 -37406 -37407 -37408 -37409 -37410 -37411 +v -37412 -37413 -37414 -37415 -37416 -37417 -37418 -37419 -37420 -37421 -37422 +v -37423 -37424 -37425 37426 -37427 -37428 -37429 -37430 -37431 -37432 -37433 +v -37434 -37435 -37436 -37437 -37438 -37439 -37440 -37441 -37442 -37443 -37444 +v -37445 -37446 -37447 -37448 -37449 -37450 -37451 -37452 -37453 37454 -37455 +v 37456 -37457 -37458 -37459 37460 -37461 37462 -37463 -37464 -37465 37466 +v -37467 37468 -37469 -37470 -37471 37472 -37473 37474 -37475 -37476 37477 +v -37478 -37479 -37480 -37481 -37482 -37483 -37484 -37485 -37486 -37487 -37488 +v 37489 37490 37491 37492 -37493 -37494 -37495 -37496 -37497 -37498 -37499 +v -37500 37501 -37502 37503 -37504 37505 -37506 -37507 -37508 -37509 37510 +v 37511 37512 37513 37514 -37515 37516 -37517 -37518 -37519 -37520 37521 37522 +v 37523 -37524 -37525 -37526 37527 -37528 -37529 -37530 -37531 -37532 -37533 +v -37534 -37535 37536 37537 37538 37539 37540 -37541 -37542 37543 37544 37545 +v 37546 37547 37548 37549 37550 -37551 -37552 -37553 -37554 37555 37556 -37557 +v -37558 -37559 -37560 -37561 -37562 -37563 -37564 -37565 -37566 37567 -37568 +v -37569 37570 37571 37572 37573 37574 37575 -37576 -37577 -37578 -37579 -37580 +v -37581 -37582 37583 -37584 -37585 -37586 37587 37588 37589 37590 37591 37592 +v 37593 -37594 -37595 37596 37597 -37598 37599 -37600 -37601 37602 -37603 +v -37604 -37605 -37606 37607 37608 -37609 -37610 -37611 -37612 37613 37614 +v 37615 37616 37617 37618 37619 -37620 -37621 -37622 37623 37624 37625 37626 +v 37627 37628 37629 37630 -37631 37632 -37633 37634 37635 -37636 37637 -37638 +v -37639 37640 37641 -37642 37643 -37644 -37645 37646 37647 -37648 -37649 +v -37650 37651 -37652 37653 -37654 -37655 37656 -37657 -37658 -37659 -37660 +v -37661 -37662 -37663 -37664 -37665 -37666 37667 37668 37669 37670 -37671 +v -37672 -37673 -37674 -37675 -37676 -37677 -37678 -37679 37680 -37681 -37682 +v 37683 -37684 -37685 -37686 -37687 -37688 37689 37690 37691 37692 -37693 +v -37694 37695 -37696 -37697 -37698 -37699 -37700 -37701 -37702 -37703 -37704 +v -37705 -37706 37707 37708 -37709 -37710 37711 -37712 -37713 37714 -37715 +v -37716 -37717 37718 -37719 -37720 -37721 -37722 -37723 -37724 -37725 -37726 +v -37727 -37728 -37729 -37730 -37731 -37732 -37733 -37734 -37735 -37736 -37737 +v -37738 -37739 -37740 -37741 -37742 -37743 -37744 -37745 -37746 37747 37748 +v -37749 -37750 37751 37752 37753 -37754 37755 37756 -37757 -37758 37759 -37760 +v -37761 37762 -37763 -37764 -37765 -37766 -37767 -37768 -37769 -37770 -37771 +v -37772 -37773 -37774 -37775 37776 37777 37778 37779 37780 37781 37782 -37783 +v 37784 37785 37786 37787 37788 37789 37790 37791 -37792 -37793 -37794 -37795 +v -37796 -37797 -37798 -37799 -37800 -37801 -37802 -37803 -37804 -37805 -37806 +v -37807 -37808 -37809 -37810 -37811 -37812 -37813 -37814 -37815 -37816 37817 +v 37818 -37819 -37820 37821 -37822 -37823 -37824 -37825 -37826 -37827 -37828 +v 37829 -37830 -37831 -37832 -37833 -37834 -37835 -37836 -37837 37838 -37839 +v -37840 -37841 -37842 -37843 -37844 -37845 -37846 37847 37848 -37849 -37850 +v -37851 -37852 -37853 37854 -37855 -37856 -37857 -37858 -37859 -37860 -37861 +v -37862 -37863 -37864 -37865 -37866 -37867 -37868 -37869 -37870 37871 37872 +v -37873 -37874 -37875 -37876 -37877 -37878 -37879 -37880 37881 -37882 -37883 +v -37884 -37885 -37886 -37887 -37888 -37889 37890 -37891 -37892 -37893 -37894 +v -37895 -37896 -37897 -37898 -37899 -37900 -37901 -37902 -37903 -37904 -37905 +v -37906 -37907 -37908 -37909 -37910 -37911 -37912 37913 37914 37915 37916 +v 37917 37918 -37919 -37920 -37921 -37922 -37923 -37924 -37925 -37926 37927 +v -37928 37929 37930 -37931 -37932 -37933 -37934 -37935 -37936 -37937 -37938 +v -37939 37940 -37941 -37942 -37943 -37944 -37945 -37946 -37947 37948 37949 +v -37950 -37951 37952 -37953 -37954 37955 -37956 -37957 -37958 -37959 -37960 +v -37961 -37962 -37963 -37964 -37965 -37966 -37967 -37968 37969 37970 -37971 +v 37972 37973 37974 -37975 37976 -37977 -37978 37979 -37980 -37981 37982 -37983 +v -37984 -37985 -37986 -37987 -37988 -37989 -37990 37991 37992 37993 37994 +v 37995 -37996 -37997 -37998 -37999 -38000 -38001 -38002 -38003 38004 -38005 +v 38006 38007 -38008 38009 -38010 -38011 38012 -38013 -38014 -38015 -38016 +v -38017 -38018 -38019 38020 38021 38022 38023 38024 -38025 38026 38027 38028 +v 38029 -38030 -38031 -38032 -38033 -38034 -38035 -38036 -38037 -38038 38039 +v 38040 -38041 -38042 -38043 -38044 -38045 -38046 -38047 -38048 38049 -38050 +v -38051 -38052 -38053 -38054 -38055 -38056 -38057 38058 -38059 -38060 -38061 +v -38062 38063 38064 38065 -38066 -38067 -38068 -38069 -38070 -38071 38072 +v -38073 -38074 -38075 -38076 -38077 -38078 -38079 -38080 38081 -38082 -38083 +v -38084 -38085 -38086 -38087 -38088 -38089 -38090 -38091 -38092 -38093 -38094 +v -38095 -38096 -38097 -38098 -38099 -38100 -38101 -38102 -38103 -38104 -38105 +v 38106 38107 38108 -38109 -38110 -38111 -38112 -38113 -38114 -38115 -38116 +v -38117 -38118 38119 -38120 -38121 -38122 -38123 -38124 -38125 -38126 -38127 +v 38128 -38129 -38130 -38131 -38132 -38133 -38134 -38135 -38136 38137 38138 +v -38139 -38140 -38141 -38142 -38143 38144 -38145 -38146 -38147 -38148 -38149 +v -38150 -38151 38152 -38153 38154 -38155 -38156 38157 -38158 38159 -38160 +v -38161 38162 -38163 38164 38165 38166 38167 -38168 -38169 38170 -38171 -38172 +v -38173 38174 -38175 38176 -38177 -38178 -38179 38180 -38181 38182 38183 38184 +v -38185 -38186 -38187 -38188 -38189 -38190 -38191 -38192 -38193 -38194 -38195 +v -38196 -38197 -38198 38199 38200 38201 -38202 -38203 -38204 38205 38206 +v -38207 -38208 38209 -38210 -38211 -38212 -38213 -38214 -38215 -38216 -38217 +v -38218 38219 38220 38221 38222 -38223 38224 -38225 -38226 -38227 -38228 +v -38229 -38230 -38231 -38232 -38233 -38234 38235 -38236 38237 -38238 -38239 +v -38240 -38241 -38242 -38243 -38244 38245 38246 38247 38248 -38249 38250 +v -38251 -38252 -38253 -38254 -38255 -38256 -38257 -38258 -38259 -38260 -38261 +v -38262 38263 38264 -38265 38266 -38267 -38268 -38269 -38270 -38271 38272 +v -38273 38274 -38275 -38276 -38277 38278 -38279 38280 -38281 -38282 -38283 +v 38284 -38285 38286 38287 38288 38289 -38290 -38291 38292 38293 38294 -38295 +v -38296 -38297 -38298 -38299 -38300 -38301 -38302 -38303 -38304 -38305 38306 +v 38307 38308 38309 -38310 -38311 38312 -38313 38314 -38315 -38316 -38317 +v -38318 -38319 -38320 -38321 -38322 -38323 -38324 -38325 -38326 -38327 -38328 +v 38329 38330 -38331 -38332 -38333 -38334 -38335 -38336 -38337 -38338 -38339 +v 38340 38341 38342 -38343 -38344 38345 -38346 -38347 -38348 -38349 -38350 +v -38351 -38352 -38353 -38354 -38355 -38356 -38357 38358 -38359 38360 -38361 +v -38362 38363 -38364 38365 -38366 -38367 38368 -38369 38370 38371 38372 38373 +v -38374 -38375 38376 38377 38378 -38379 -38380 -38381 -38382 -38383 -38384 +v -38385 -38386 -38387 -38388 -38389 38390 38391 38392 38393 -38394 -38395 +v -38396 -38397 -38398 -38399 -38400 -38401 -38402 -38403 -38404 -38405 -38406 +v -38407 -38408 -38409 -38410 -38411 -38412 -38413 -38414 -38415 -38416 -38417 +v -38418 -38419 -38420 -38421 -38422 -38423 -38424 -38425 38426 -38427 -38428 +v -38429 -38430 -38431 -38432 -38433 -38434 -38435 -38436 -38437 -38438 -38439 +v -38440 -38441 -38442 -38443 -38444 -38445 -38446 -38447 -38448 -38449 -38450 +v 38451 -38452 -38453 -38454 -38455 -38456 -38457 38458 -38459 -38460 -38461 +v -38462 -38463 -38464 -38465 -38466 -38467 -38468 -38469 -38470 -38471 38472 +v -38473 -38474 -38475 -38476 -38477 -38478 -38479 -38480 -38481 -38482 -38483 +v 38484 -38485 38486 -38487 -38488 -38489 38490 -38491 38492 -38493 -38494 +v -38495 38496 -38497 38498 -38499 -38500 -38501 38502 -38503 38504 38505 38506 +v -38507 -38508 -38509 -38510 -38511 -38512 -38513 -38514 -38515 -38516 -38517 +v 38518 38519 38520 -38521 -38522 -38523 -38524 -38525 -38526 -38527 -38528 +v 38529 -38530 38531 -38532 -38533 -38534 -38535 -38536 38537 38538 38539 38540 +v -38541 -38542 -38543 -38544 -38545 -38546 -38547 -38548 -38549 -38550 -38551 +v -38552 -38553 -38554 -38555 -38556 -38557 38558 -38559 -38560 -38561 -38562 +v -38563 38564 -38565 38566 -38567 -38568 -38569 38570 -38571 38572 -38573 +v -38574 38575 -38576 -38577 -38578 -38579 -38580 -38581 38582 38583 38584 +v -38585 -38586 -38587 -38588 -38589 -38590 -38591 -38592 -38593 -38594 -38595 +v -38596 -38597 -38598 -38599 -38600 -38601 38602 -38603 -38604 -38605 -38606 +v -38607 38608 -38609 38610 -38611 -38612 -38613 38614 -38615 38616 -38617 +v -38618 38619 -38620 -38621 -38622 -38623 -38624 -38625 38626 38627 38628 +v -38629 -38630 -38631 -38632 -38633 -38634 -38635 -38636 -38637 -38638 -38639 +v -38640 -38641 -38642 -38643 -38644 -38645 38646 -38647 -38648 -38649 -38650 +v -38651 38652 -38653 38654 -38655 -38656 -38657 38658 -38659 38660 -38661 +v -38662 38663 -38664 -38665 -38666 -38667 -38668 -38669 38670 38671 38672 +v 38673 -38674 38675 -38676 -38677 -38678 -38679 -38680 -38681 -38682 -38683 +v -38684 -38685 -38686 -38687 -38688 -38689 -38690 -38691 -38692 -38693 -38694 +v -38695 -38696 -38697 -38698 -38699 -38700 -38701 -38702 -38703 -38704 -38705 +v -38706 -38707 -38708 -38709 -38710 -38711 -38712 -38713 -38714 -38715 -38716 +v -38717 -38718 -38719 -38720 -38721 -38722 -38723 -38724 -38725 -38726 -38727 +v -38728 -38729 -38730 -38731 -38732 -38733 -38734 -38735 -38736 -38737 -38738 +v -38739 -38740 -38741 -38742 -38743 -38744 -38745 38746 -38747 -38748 -38749 +v -38750 -38751 -38752 -38753 -38754 -38755 -38756 -38757 -38758 -38759 -38760 +v -38761 -38762 -38763 -38764 -38765 -38766 -38767 -38768 -38769 -38770 -38771 +v -38772 -38773 -38774 -38775 -38776 -38777 -38778 -38779 -38780 -38781 -38782 +v -38783 -38784 -38785 -38786 -38787 -38788 -38789 -38790 -38791 -38792 -38793 +v -38794 -38795 -38796 -38797 -38798 -38799 -38800 -38801 -38802 -38803 38804 +v -38805 38806 -38807 -38808 -38809 38810 -38811 38812 -38813 -38814 -38815 +v 38816 -38817 38818 -38819 -38820 -38821 -38822 38823 -38824 38825 -38826 +v -38827 38828 -38829 -38830 -38831 -38832 -38833 -38834 -38835 -38836 -38837 +v -38838 38839 38840 38841 -38842 -38843 -38844 -38845 -38846 -38847 -38848 +v -38849 -38850 -38851 -38852 -38853 -38854 -38855 -38856 -38857 -38858 38859 +v -38860 -38861 -38862 -38863 -38864 38865 -38866 38867 -38868 -38869 -38870 +v 38871 -38872 38873 -38874 -38875 38876 -38877 -38878 -38879 -38880 -38881 +v -38882 38883 38884 38885 -38886 -38887 -38888 -38889 -38890 -38891 -38892 +v -38893 -38894 -38895 -38896 -38897 -38898 -38899 -38900 -38901 -38902 -38903 +v -38904 -38905 -38906 -38907 38908 38909 -38910 -38911 38912 -38913 -38914 +v -38915 -38916 -38917 -38918 -38919 -38920 -38921 -38922 -38923 -38924 -38925 +v 38926 38927 -38928 38929 38930 -38931 -38932 38933 -38934 -38935 -38936 +v -38937 -38938 -38939 -38940 -38941 -38942 38943 -38944 -38945 -38946 -38947 +v -38948 -38949 -38950 -38951 -38952 -38953 -38954 -38955 -38956 -38957 -38958 +v -38959 -38960 -38961 38962 38963 -38964 38965 -38966 -38967 -38968 -38969 +v -38970 -38971 -38972 -38973 -38974 -38975 -38976 -38977 -38978 38979 38980 +v -38981 38982 38983 -38984 -38985 38986 -38987 -38988 -38989 -38990 -38991 +v -38992 -38993 -38994 -38995 38996 -38997 38998 -38999 -39000 -39001 -39002 +v 39003 -39004 39005 -39006 -39007 -39008 -39009 39010 -39011 39012 39013 39014 +v 39015 39016 -39017 -39018 39019 39020 39021 -39022 -39023 -39024 -39025 +v -39026 -39027 -39028 -39029 -39030 -39031 -39032 39033 39034 39035 -39036 +v -39037 -39038 -39039 -39040 -39041 -39042 -39043 -39044 -39045 -39046 -39047 +v -39048 -39049 -39050 -39051 -39052 -39053 -39054 -39055 -39056 -39057 39058 +v -39059 39060 -39061 -39062 -39063 39064 -39065 39066 -39067 -39068 39069 +v -39070 -39071 -39072 -39073 -39074 -39075 39076 39077 39078 39079 -39080 +v -39081 -39082 -39083 -39084 -39085 -39086 -39087 -39088 -39089 -39090 -39091 +v -39092 -39093 -39094 -39095 -39096 -39097 -39098 -39099 -39100 -39101 39102 +v -39103 39104 -39105 -39106 -39107 39108 -39109 39110 -39111 -39112 39113 +v -39114 -39115 -39116 -39117 -39118 -39119 39120 39121 39122 39123 -39124 +v -39125 -39126 -39127 -39128 -39129 -39130 -39131 -39132 -39133 -39134 -39135 +v -39136 -39137 -39138 -39139 -39140 -39141 -39142 -39143 -39144 -39145 39146 +v -39147 39148 -39149 -39150 -39151 39152 -39153 39154 -39155 -39156 39157 +v -39158 -39159 -39160 -39161 -39162 -39163 39164 39165 39166 39167 39168 +v -39169 39170 -39171 -39172 -39173 -39174 -39175 -39176 -39177 -39178 -39179 +v -39180 -39181 -39182 -39183 -39184 -39185 -39186 -39187 -39188 -39189 -39190 +v -39191 -39192 -39193 -39194 -39195 -39196 -39197 -39198 -39199 -39200 -39201 +v -39202 -39203 -39204 -39205 -39206 -39207 -39208 -39209 -39210 -39211 -39212 +v -39213 -39214 -39215 -39216 -39217 -39218 -39219 -39220 -39221 -39222 -39223 +v -39224 -39225 -39226 -39227 -39228 -39229 -39230 -39231 -39232 -39233 -39234 +v -39235 -39236 -39237 -39238 -39239 -39240 -39241 -39242 -39243 -39244 -39245 +v -39246 -39247 -39248 -39249 -39250 -39251 -39252 -39253 -39254 -39255 -39256 +v -39257 -39258 -39259 -39260 -39261 -39262 -39263 -39264 -39265 -39266 -39267 +v -39268 -39269 -39270 -39271 -39272 -39273 -39274 -39275 -39276 -39277 -39278 +v -39279 -39280 -39281 -39282 -39283 -39284 -39285 -39286 -39287 -39288 -39289 +v -39290 -39291 -39292 -39293 -39294 -39295 -39296 -39297 39298 -39299 39300 +v -39301 -39302 -39303 39304 -39305 39306 -39307 -39308 -39309 39310 -39311 +v 39312 -39313 -39314 -39315 -39316 39317 -39318 39319 -39320 -39321 39322 +v -39323 -39324 -39325 -39326 -39327 -39328 -39329 -39330 -39331 -39332 39333 +v 39334 39335 39336 -39337 -39338 -39339 -39340 -39341 -39342 -39343 -39344 +v -39345 -39346 -39347 -39348 -39349 -39350 -39351 -39352 -39353 -39354 -39355 +v -39356 -39357 -39358 39359 -39360 39361 -39362 -39363 -39364 39365 -39366 +v 39367 -39368 -39369 39370 -39371 -39372 -39373 -39374 -39375 -39376 39377 +v 39378 39379 39380 -39381 -39382 39383 -39384 -39385 39386 39387 -39388 -39389 +v -39390 -39391 -39392 -39393 -39394 -39395 -39396 -39397 -39398 -39399 -39400 +v -39401 -39402 -39403 -39404 -39405 -39406 -39407 -39408 -39409 -39410 -39411 +v -39412 -39413 -39414 -39415 -39416 -39417 -39418 -39419 -39420 -39421 -39422 +v -39423 -39424 -39425 -39426 -39427 -39428 -39429 -39430 -39431 -39432 -39433 +v -39434 -39435 -39436 -39437 -39438 -39439 -39440 -39441 -39442 -39443 -39444 +v -39445 -39446 -39447 -39448 -39449 -39450 -39451 -39452 -39453 -39454 -39455 +v -39456 -39457 -39458 -39459 -39460 -39461 -39462 -39463 -39464 -39465 -39466 +v -39467 -39468 -39469 -39470 -39471 -39472 -39473 -39474 -39475 -39476 -39477 +v -39478 -39479 -39480 -39481 -39482 -39483 -39484 -39485 -39486 -39487 -39488 +v -39489 -39490 -39491 -39492 -39493 -39494 -39495 -39496 -39497 -39498 -39499 +v -39500 -39501 -39502 -39503 -39504 -39505 -39506 -39507 -39508 -39509 -39510 +v -39511 -39512 -39513 -39514 -39515 -39516 -39517 -39518 -39519 -39520 -39521 +v -39522 -39523 -39524 -39525 -39526 -39527 -39528 -39529 -39530 -39531 -39532 +v -39533 -39534 -39535 -39536 -39537 -39538 -39539 -39540 -39541 -39542 -39543 +v -39544 -39545 -39546 -39547 -39548 -39549 -39550 -39551 -39552 -39553 -39554 +v -39555 -39556 -39557 -39558 -39559 -39560 -39561 -39562 -39563 -39564 -39565 +v -39566 -39567 -39568 -39569 -39570 -39571 -39572 -39573 -39574 -39575 -39576 +v -39577 -39578 -39579 -39580 -39581 -39582 -39583 -39584 -39585 -39586 -39587 +v -39588 -39589 -39590 -39591 -39592 -39593 -39594 -39595 -39596 -39597 -39598 +v -39599 -39600 -39601 -39602 -39603 -39604 -39605 -39606 -39607 -39608 -39609 +v -39610 -39611 -39612 -39613 -39614 -39615 -39616 -39617 -39618 -39619 -39620 +v -39621 -39622 -39623 -39624 -39625 -39626 -39627 -39628 -39629 -39630 -39631 +v -39632 -39633 -39634 -39635 -39636 -39637 -39638 -39639 -39640 -39641 -39642 +v -39643 -39644 -39645 -39646 -39647 -39648 -39649 -39650 -39651 -39652 -39653 +v -39654 -39655 -39656 -39657 -39658 -39659 -39660 39661 -39662 -39663 -39664 +v -39665 -39666 -39667 -39668 -39669 -39670 -39671 -39672 -39673 -39674 -39675 +v -39676 -39677 -39678 -39679 -39680 -39681 -39682 -39683 -39684 -39685 -39686 +v -39687 -39688 -39689 -39690 -39691 -39692 -39693 -39694 -39695 -39696 -39697 +v -39698 -39699 -39700 -39701 -39702 -39703 -39704 -39705 -39706 -39707 -39708 +v -39709 -39710 -39711 -39712 -39713 -39714 -39715 -39716 -39717 -39718 -39719 +v -39720 -39721 -39722 -39723 -39724 -39725 -39726 -39727 -39728 -39729 -39730 +v -39731 -39732 -39733 -39734 -39735 -39736 -39737 -39738 -39739 -39740 -39741 +v -39742 -39743 -39744 -39745 -39746 -39747 -39748 -39749 -39750 -39751 -39752 +v -39753 -39754 -39755 -39756 -39757 -39758 -39759 -39760 -39761 -39762 -39763 +v -39764 -39765 -39766 -39767 -39768 -39769 -39770 -39771 -39772 -39773 -39774 +v -39775 -39776 -39777 -39778 -39779 -39780 -39781 -39782 -39783 -39784 -39785 +v -39786 -39787 -39788 -39789 -39790 -39791 -39792 -39793 -39794 -39795 -39796 +v -39797 -39798 -39799 -39800 -39801 -39802 -39803 -39804 -39805 -39806 -39807 +v -39808 -39809 -39810 -39811 -39812 -39813 -39814 -39815 -39816 -39817 -39818 +v -39819 -39820 -39821 -39822 -39823 -39824 -39825 -39826 -39827 -39828 -39829 +v -39830 -39831 -39832 -39833 -39834 -39835 -39836 -39837 -39838 -39839 -39840 +v -39841 -39842 -39843 -39844 -39845 -39846 -39847 -39848 -39849 -39850 -39851 +v -39852 -39853 -39854 -39855 -39856 -39857 -39858 -39859 -39860 -39861 -39862 +v -39863 -39864 -39865 -39866 -39867 -39868 -39869 -39870 -39871 39872 -39873 +v 39874 -39875 -39876 39877 -39878 39879 -39880 -39881 -39882 39883 -39884 +v 39885 -39886 -39887 -39888 39889 -39890 39891 -39892 -39893 -39894 39895 +v -39896 39897 -39898 -39899 -39900 39901 -39902 39903 -39904 -39905 39906 +v -39907 39908 -39909 -39910 -39911 -39912 -39913 -39914 -39915 -39916 -39917 +v -39918 -39919 -39920 -39921 -39922 -39923 39924 39925 39926 39927 -39928 +v -39929 -39930 -39931 -39932 39933 -39934 -39935 -39936 -39937 -39938 -39939 +v -39940 -39941 -39942 -39943 -39944 -39945 -39946 -39947 -39948 -39949 -39950 +v -39951 -39952 -39953 -39954 -39955 -39956 -39957 -39958 -39959 -39960 -39961 +v -39962 -39963 -39964 -39965 -39966 -39967 -39968 -39969 -39970 -39971 -39972 +v -39973 -39974 -39975 -39976 -39977 -39978 -39979 -39980 -39981 -39982 -39983 +v -39984 -39985 -39986 -39987 -39988 -39989 -39990 -39991 -39992 -39993 -39994 +v -39995 -39996 -39997 -39998 -39999 -40000 -40001 -40002 -40003 -40004 -40005 +v -40006 -40007 -40008 -40009 -40010 -40011 -40012 -40013 -40014 -40015 -40016 +v -40017 -40018 -40019 -40020 -40021 -40022 -40023 -40024 -40025 -40026 -40027 +v -40028 -40029 -40030 -40031 -40032 -40033 -40034 -40035 -40036 -40037 -40038 +v -40039 -40040 -40041 -40042 -40043 -40044 -40045 -40046 -40047 -40048 -40049 +v -40050 -40051 -40052 -40053 40054 -40055 40056 -40057 -40058 -40059 -40060 +v 40061 -40062 40063 -40064 -40065 -40066 -40067 40068 -40069 40070 -40071 +v -40072 -40073 -40074 40075 -40076 40077 -40078 -40079 40080 -40081 40082 +v -40083 -40084 40085 -40086 -40087 -40088 -40089 -40090 -40091 -40092 -40093 +v -40094 -40095 -40096 -40097 40098 40099 40100 40101 -40102 -40103 -40104 +v -40105 -40106 -40107 -40108 -40109 -40110 -40111 -40112 -40113 -40114 -40115 +v -40116 -40117 -40118 -40119 -40120 -40121 -40122 -40123 -40124 -40125 -40126 +v -40127 -40128 -40129 -40130 -40131 -40132 -40133 -40134 -40135 -40136 -40137 +v -40138 -40139 -40140 -40141 -40142 -40143 -40144 -40145 -40146 -40147 -40148 +v 40149 -40150 -40151 40152 -40153 -40154 40155 -40156 -40157 -40158 40159 +v -40160 -40161 -40162 -40163 -40164 -40165 -40166 -40167 -40168 -40169 -40170 +v 40171 -40172 40173 40174 40175 40176 -40177 -40178 -40179 -40180 -40181 +v -40182 -40183 -40184 -40185 -40186 -40187 -40188 -40189 -40190 -40191 -40192 +v -40193 -40194 -40195 -40196 -40197 -40198 -40199 -40200 -40201 -40202 -40203 +v -40204 -40205 -40206 -40207 -40208 -40209 -40210 -40211 -40212 -40213 -40214 +v -40215 -40216 -40217 -40218 -40219 -40220 -40221 -40222 -40223 -40224 -40225 +v -40226 -40227 -40228 -40229 -40230 -40231 -40232 -40233 -40234 -40235 -40236 +v -40237 -40238 -40239 -40240 -40241 -40242 -40243 -40244 -40245 -40246 -40247 +v -40248 -40249 -40250 -40251 -40252 -40253 -40254 -40255 -40256 -40257 -40258 +v -40259 -40260 -40261 40262 -40263 40264 -40265 -40266 40267 -40268 40269 +v -40270 -40271 40272 -40273 40274 -40275 -40276 -40277 40278 -40279 40280 +v -40281 -40282 40283 -40284 -40285 -40286 -40287 -40288 -40289 -40290 -40291 +v -40292 -40293 40294 -40295 40296 40297 40298 40299 -40300 -40301 -40302 +v -40303 -40304 -40305 -40306 -40307 40308 -40309 40310 -40311 40312 -40313 +v -40314 -40315 -40316 40317 40318 40319 40320 40321 -40322 -40323 -40324 +v -40325 -40326 -40327 40328 40329 -40330 -40331 -40332 -40333 40334 -40335 +v -40336 -40337 -40338 -40339 -40340 -40341 -40342 40343 40344 40345 -40346 +v 40347 -40348 -40349 40350 -40351 -40352 -40353 40354 -40355 -40356 -40357 +v -40358 -40359 -40360 -40361 -40362 40363 40364 40365 40366 -40367 -40368 +v -40369 -40370 -40371 -40372 -40373 -40374 40375 40376 40377 40378 -40379 +v 40380 40381 40382 40383 -40384 -40385 -40386 -40387 -40388 -40389 40390 +v -40391 -40392 -40393 40394 40395 -40396 -40397 -40398 40399 -40400 -40401 +v -40402 -40403 40404 40405 40406 40407 -40408 40409 40410 40411 -40412 -40413 +v 40414 -40415 -40416 -40417 -40418 -40419 40420 40421 40422 -40423 -40424 +v -40425 -40426 40427 -40428 -40429 -40430 -40431 -40432 40433 40434 40435 +v 40436 40437 -40438 40439 -40440 40441 40442 -40443 40444 -40445 -40446 40447 +v -40448 -40449 -40450 40451 -40452 40453 -40454 -40455 -40456 -40457 40458 +v -40459 40460 40461 40462 -40463 -40464 -40465 -40466 -40467 -40468 -40469 +v -40470 -40471 -40472 -40473 40474 40475 40476 40477 -40478 -40479 -40480 +v -40481 -40482 -40483 -40484 -40485 -40486 40487 -40488 -40489 40490 -40491 +v -40492 -40493 -40494 -40495 40496 40497 40498 40499 -40500 -40501 -40502 +v -40503 -40504 40505 -40506 40507 -40508 40509 -40510 40511 -40512 -40513 +v 40514 -40515 -40516 40517 -40518 -40519 -40520 -40521 -40522 -40523 -40524 +v -40525 40526 40527 40528 40529 40530 40531 -40532 -40533 40534 40535 40536 +v 40537 40538 40539 40540 40541 -40542 -40543 -40544 -40545 -40546 -40547 +v -40548 -40549 -40550 -40551 -40552 -40553 -40554 -40555 -40556 -40557 -40558 +v -40559 -40560 -40561 -40562 -40563 -40564 -40565 40566 40567 -40568 -40569 +v 40570 -40571 -40572 -40573 -40574 -40575 -40576 -40577 40578 -40579 -40580 +v -40581 -40582 -40583 -40584 -40585 -40586 40587 -40588 -40589 -40590 -40591 +v -40592 -40593 -40594 40595 40596 40597 -40598 -40599 -40600 -40601 -40602 +v 40603 40604 -40605 40606 -40607 -40608 -40609 -40610 -40611 -40612 40613 +v -40614 -40615 -40616 -40617 -40618 -40619 -40620 -40621 -40622 -40623 -40624 +v -40625 -40626 -40627 -40628 -40629 -40630 -40631 -40632 -40633 -40634 -40635 +v -40636 -40637 -40638 40639 40640 40641 -40642 -40643 -40644 -40645 -40646 +v -40647 40648 40649 40650 -40651 40652 -40653 -40654 40655 -40656 -40657 +v -40658 -40659 -40660 40661 -40662 -40663 -40664 -40665 -40666 -40667 -40668 +v -40669 -40670 40671 40672 40673 -40674 -40675 -40676 40677 40678 40679 40680 +v -40681 -40682 40683 -40684 -40685 -40686 -40687 -40688 40689 -40690 -40691 +v -40692 -40693 -40694 -40695 -40696 -40697 -40698 -40699 -40700 -40701 -40702 +v -40703 -40704 -40705 -40706 -40707 -40708 -40709 -40710 -40711 -40712 -40713 +v -40714 -40715 40716 40717 40718 -40719 -40720 -40721 -40722 -40723 -40724 +v 40725 40726 40727 -40728 40729 -40730 -40731 40732 -40733 -40734 -40735 +v -40736 -40737 40738 -40739 -40740 -40741 -40742 -40743 -40744 -40745 -40746 +v -40747 -40748 -40749 -40750 -40751 -40752 -40753 -40754 -40755 -40756 -40757 +v -40758 -40759 -40760 -40761 -40762 -40763 -40764 -40765 -40766 -40767 -40768 +v -40769 40770 -40771 -40772 40773 -40774 -40775 -40776 -40777 -40778 -40779 +v -40780 -40781 -40782 -40783 -40784 -40785 -40786 -40787 40788 40789 40790 +v 40791 40792 40793 40794 40795 -40796 -40797 -40798 -40799 -40800 -40801 +v -40802 -40803 -40804 -40805 -40806 -40807 -40808 40809 40810 -40811 -40812 +v 40813 40814 -40815 -40816 -40817 -40818 40819 -40820 -40821 40822 -40823 +v -40824 -40825 -40826 -40827 -40828 -40829 -40830 -40831 40832 40833 40834 +v 40835 40836 -40837 -40838 40839 40840 40841 40842 -40843 -40844 -40845 -40846 +v -40847 -40848 -40849 -40850 -40851 40852 40853 -40854 -40855 -40856 -40857 +v -40858 -40859 -40860 -40861 40862 -40863 -40864 -40865 -40866 -40867 -40868 +v -40869 -40870 40871 -40872 -40873 -40874 -40875 40876 40877 -40878 -40879 +v -40880 -40881 40882 -40883 -40884 -40885 -40886 -40887 -40888 -40889 40890 +v -40891 -40892 -40893 -40894 -40895 40896 -40897 -40898 -40899 -40900 -40901 +v -40902 -40903 -40904 -40905 -40906 40907 -40908 -40909 -40910 40911 40912 +v -40913 40914 -40915 -40916 -40917 -40918 -40919 -40920 -40921 -40922 -40923 +v -40924 -40925 -40926 -40927 -40928 40929 40930 -40931 -40932 -40933 -40934 +v 40935 40936 40937 -40938 40939 -40940 -40941 40942 -40943 -40944 -40945 +v -40946 -40947 40948 -40949 -40950 -40951 -40952 -40953 -40954 40955 40956 +v -40957 -40958 40959 40960 40961 40962 -40963 -40964 40965 -40966 -40967 +v -40968 -40969 -40970 -40971 -40972 -40973 -40974 -40975 -40976 -40977 -40978 +v 40979 40980 -40981 -40982 -40983 -40984 40985 40986 40987 -40988 40989 -40990 +v -40991 40992 -40993 -40994 -40995 -40996 -40997 40998 -40999 -41000 -41001 +v -41002 -41003 -41004 41005 41006 -41007 -41008 -41009 41010 41011 41012 +v -41013 -41014 -41015 -41016 -41017 -41018 41019 -41020 41021 -41022 -41023 +v 41024 -41025 41026 -41027 -41028 -41029 41030 -41031 41032 41033 41034 41035 +v -41036 -41037 41038 -41039 -41040 -41041 41042 -41043 41044 41045 41046 41047 +v -41048 -41049 41050 41051 41052 -41053 -41054 -41055 -41056 -41057 -41058 +v -41059 -41060 -41061 -41062 -41063 -41064 -41065 -41066 -41067 41068 41069 +v 41070 41071 -41072 41073 41074 -41075 -41076 41077 -41078 -41079 -41080 +v -41081 -41082 -41083 -41084 -41085 -41086 41087 41088 41089 41090 -41091 +v 41092 -41093 -41094 -41095 -41096 -41097 -41098 -41099 -41100 -41101 -41102 +v -41103 -41104 -41105 -41106 -41107 -41108 -41109 -41110 -41111 -41112 -41113 +v -41114 -41115 -41116 -41117 41118 -41119 41120 -41121 -41122 -41123 -41124 +v -41125 -41126 -41127 41128 41129 41130 41131 -41132 41133 -41134 -41135 +v -41136 -41137 -41138 -41139 -41140 -41141 -41142 -41143 -41144 -41145 41146 +v 41147 -41148 41149 -41150 -41151 -41152 -41153 -41154 41155 -41156 41157 +v -41158 -41159 -41160 41161 -41162 41163 -41164 -41165 -41166 41167 -41168 +v 41169 41170 41171 41172 -41173 -41174 41175 41176 41177 -41178 -41179 -41180 +v -41181 -41182 -41183 -41184 -41185 -41186 -41187 -41188 41189 41190 41191 +v 41192 -41193 -41194 41195 -41196 41197 -41198 -41199 -41200 -41201 -41202 +v -41203 -41204 -41205 -41206 -41207 -41208 -41209 -41210 -41211 41212 41213 +v -41214 -41215 -41216 -41217 -41218 -41219 -41220 -41221 -41222 41223 41224 +v 41225 -41226 -41227 41228 -41229 -41230 -41231 -41232 -41233 -41234 -41235 +v -41236 -41237 -41238 -41239 -41240 41241 -41242 41243 -41244 -41245 41246 +v -41247 41248 -41249 -41250 41251 -41252 41253 41254 41255 41256 -41257 -41258 +v 41259 41260 41261 -41262 -41263 -41264 -41265 -41266 -41267 -41268 -41269 +v -41270 -41271 -41272 41273 41274 41275 41276 -41277 -41278 -41279 -41280 +v -41281 -41282 -41283 -41284 -41285 -41286 -41287 -41288 -41289 -41290 -41291 +v -41292 -41293 -41294 -41295 -41296 -41297 -41298 -41299 -41300 -41301 -41302 +v -41303 -41304 -41305 -41306 -41307 -41308 41309 -41310 -41311 -41312 -41313 +v -41314 -41315 -41316 -41317 -41318 -41319 -41320 -41321 -41322 -41323 -41324 +v -41325 -41326 -41327 -41328 -41329 -41330 -41331 41332 -41333 -41334 -41335 +v -41336 -41337 -41338 -41339 -41340 -41341 -41342 -41343 -41344 -41345 -41346 +v -41347 -41348 -41349 -41350 -41351 -41352 -41353 -41354 -41355 -41356 -41357 +v 41358 -41359 -41360 -41361 -41362 -41363 41364 -41365 41366 -41367 -41368 +v 41369 -41370 41371 -41372 -41373 41374 -41375 41376 -41377 -41378 -41379 +v 41380 -41381 41382 41383 41384 -41385 -41386 -41387 -41388 -41389 -41390 +v -41391 -41392 -41393 -41394 -41395 41396 41397 41398 41399 -41400 -41401 +v -41402 -41403 -41404 -41405 -41406 -41407 41408 -41409 41410 -41411 -41412 +v -41413 -41414 -41415 41416 41417 41418 41419 -41420 -41421 -41422 -41423 +v -41424 -41425 -41426 -41427 -41428 -41429 -41430 -41431 -41432 -41433 -41434 +v -41435 -41436 41437 -41438 -41439 -41440 -41441 -41442 41443 -41444 41445 +v -41446 -41447 -41448 41449 -41450 41451 -41452 -41453 41454 -41455 -41456 +v -41457 -41458 -41459 -41460 41461 41462 41463 -41464 -41465 -41466 -41467 +v -41468 -41469 -41470 -41471 -41472 -41473 -41474 -41475 -41476 -41477 -41478 +v -41479 -41480 41481 -41482 -41483 -41484 -41485 -41486 41487 -41488 41489 +v -41490 -41491 -41492 41493 -41494 41495 -41496 -41497 41498 -41499 -41500 +v -41501 -41502 -41503 -41504 41505 41506 41507 -41508 -41509 -41510 -41511 +v -41512 -41513 -41514 -41515 -41516 -41517 -41518 -41519 -41520 -41521 -41522 +v -41523 -41524 41525 -41526 -41527 -41528 -41529 -41530 41531 -41532 41533 +v -41534 -41535 -41536 41537 -41538 41539 -41540 -41541 41542 -41543 -41544 +v -41545 -41546 -41547 -41548 41549 41550 41551 41552 -41553 41554 -41555 +v -41556 -41557 -41558 -41559 -41560 -41561 -41562 -41563 -41564 -41565 -41566 +v -41567 -41568 -41569 -41570 -41571 -41572 -41573 -41574 -41575 -41576 -41577 +v -41578 -41579 -41580 -41581 -41582 -41583 -41584 -41585 -41586 -41587 -41588 +v -41589 -41590 -41591 -41592 -41593 -41594 -41595 -41596 -41597 -41598 -41599 +v -41600 -41601 -41602 -41603 -41604 -41605 -41606 -41607 -41608 -41609 -41610 +v -41611 -41612 -41613 -41614 -41615 -41616 -41617 -41618 -41619 -41620 -41621 +v -41622 -41623 -41624 41625 -41626 -41627 -41628 -41629 -41630 -41631 -41632 +v -41633 -41634 -41635 -41636 -41637 -41638 -41639 -41640 -41641 -41642 -41643 +v -41644 -41645 -41646 -41647 -41648 -41649 -41650 -41651 -41652 -41653 -41654 +v -41655 -41656 -41657 -41658 -41659 -41660 -41661 -41662 -41663 -41664 -41665 +v -41666 -41667 -41668 -41669 -41670 -41671 -41672 -41673 -41674 -41675 -41676 +v -41677 -41678 -41679 -41680 -41681 -41682 41683 -41684 41685 -41686 -41687 +v -41688 41689 -41690 41691 -41692 -41693 -41694 41695 -41696 41697 -41698 +v -41699 -41700 -41701 41702 -41703 41704 -41705 -41706 41707 -41708 -41709 +v -41710 -41711 -41712 -41713 -41714 -41715 -41716 -41717 41718 41719 41720 +v -41721 -41722 -41723 -41724 -41725 -41726 -41727 -41728 -41729 -41730 -41731 +v -41732 -41733 -41734 -41735 -41736 -41737 41738 -41739 -41740 -41741 -41742 +v -41743 41744 -41745 41746 -41747 -41748 -41749 41750 -41751 41752 -41753 +v -41754 41755 -41756 -41757 -41758 -41759 -41760 -41761 41762 41763 41764 +v -41765 -41766 41767 -41768 -41769 -41770 -41771 -41772 -41773 41774 -41775 +v -41776 -41777 -41778 -41779 -41780 -41781 -41782 -41783 -41784 -41785 41786 +v 41787 -41788 -41789 41790 41791 41792 41793 41794 -41795 -41796 -41797 -41798 +v -41799 -41800 41801 -41802 -41803 41804 -41805 -41806 41807 41808 -41809 +v -41810 -41811 -41812 41813 -41814 41815 -41816 -41817 -41818 -41819 -41820 +v -41821 41822 -41823 -41824 -41825 -41826 -41827 -41828 -41829 -41830 41831 +v 41832 41833 41834 -41835 -41836 -41837 -41838 -41839 41840 41841 -41842 +v -41843 41844 41845 41846 -41847 -41848 -41849 41850 -41851 -41852 -41853 +v -41854 41855 -41856 41857 -41858 -41859 41860 41861 -41862 -41863 -41864 +v -41865 41866 -41867 41868 -41869 -41870 -41871 -41872 -41873 -41874 41875 +v -41876 41877 -41878 -41879 -41880 -41881 41882 -41883 41884 41885 41886 41887 +v 41888 -41889 -41890 41891 41892 41893 41894 41895 -41896 -41897 41898 -41899 +v -41900 41901 -41902 -41903 -41904 -41905 -41906 -41907 -41908 -41909 -41910 +v -41911 41912 41913 41914 -41915 -41916 -41917 -41918 -41919 -41920 -41921 +v -41922 -41923 -41924 -41925 -41926 -41927 -41928 -41929 -41930 -41931 -41932 +v -41933 -41934 -41935 -41936 41937 -41938 41939 -41940 -41941 -41942 41943 +v -41944 41945 -41946 -41947 41948 -41949 -41950 -41951 -41952 -41953 -41954 +v 41955 41956 41957 41958 -41959 -41960 -41961 -41962 -41963 -41964 -41965 +v -41966 -41967 -41968 -41969 -41970 -41971 -41972 -41973 -41974 -41975 -41976 +v -41977 -41978 -41979 -41980 41981 -41982 41983 -41984 -41985 -41986 41987 +v -41988 41989 -41990 -41991 41992 -41993 -41994 -41995 -41996 -41997 -41998 +v 41999 42000 42001 42002 -42003 -42004 -42005 -42006 -42007 -42008 -42009 +v -42010 -42011 -42012 -42013 -42014 -42015 -42016 -42017 -42018 -42019 -42020 +v -42021 -42022 -42023 -42024 42025 -42026 42027 -42028 -42029 -42030 42031 +v -42032 42033 -42034 -42035 42036 -42037 -42038 -42039 -42040 -42041 -42042 +v 42043 42044 42045 42046 42047 -42048 42049 -42050 -42051 -42052 -42053 -42054 +v -42055 -42056 -42057 -42058 -42059 -42060 -42061 -42062 -42063 -42064 -42065 +v -42066 -42067 -42068 -42069 -42070 -42071 -42072 -42073 -42074 -42075 -42076 +v -42077 -42078 -42079 -42080 -42081 -42082 -42083 -42084 -42085 -42086 -42087 +v -42088 -42089 -42090 -42091 -42092 -42093 -42094 -42095 -42096 -42097 -42098 +v -42099 -42100 -42101 -42102 -42103 -42104 -42105 -42106 -42107 -42108 -42109 +v -42110 -42111 -42112 -42113 -42114 -42115 -42116 -42117 -42118 -42119 -42120 +v -42121 -42122 -42123 -42124 -42125 -42126 -42127 -42128 -42129 -42130 -42131 +v -42132 -42133 -42134 -42135 -42136 -42137 -42138 -42139 -42140 -42141 -42142 +v -42143 -42144 -42145 -42146 -42147 -42148 -42149 -42150 -42151 -42152 -42153 +v -42154 -42155 -42156 -42157 -42158 -42159 -42160 -42161 -42162 -42163 -42164 +v -42165 -42166 -42167 -42168 -42169 -42170 -42171 -42172 -42173 -42174 -42175 +v -42176 42177 -42178 42179 -42180 -42181 -42182 42183 -42184 42185 -42186 +v -42187 -42188 42189 -42190 42191 -42192 -42193 -42194 -42195 42196 -42197 +v 42198 -42199 -42200 42201 -42202 -42203 -42204 -42205 -42206 -42207 -42208 +v -42209 -42210 -42211 42212 42213 42214 42215 -42216 -42217 -42218 -42219 +v -42220 -42221 -42222 -42223 -42224 -42225 -42226 -42227 -42228 -42229 -42230 +v -42231 -42232 -42233 -42234 -42235 -42236 -42237 42238 -42239 42240 -42241 +v -42242 -42243 42244 -42245 42246 -42247 -42248 42249 -42250 -42251 -42252 +v -42253 -42254 -42255 42256 42257 42258 42259 -42260 -42261 42262 -42263 +v -42264 42265 42266 -42267 -42268 -42269 -42270 -42271 -42272 -42273 -42274 +v -42275 -42276 -42277 -42278 -42279 -42280 -42281 -42282 -42283 -42284 -42285 +v -42286 -42287 -42288 -42289 -42290 -42291 -42292 -42293 -42294 -42295 -42296 +v -42297 -42298 -42299 -42300 -42301 -42302 -42303 -42304 -42305 -42306 -42307 +v -42308 -42309 -42310 -42311 -42312 -42313 -42314 -42315 -42316 -42317 -42318 +v -42319 -42320 -42321 -42322 -42323 -42324 -42325 -42326 -42327 -42328 -42329 +v -42330 -42331 -42332 -42333 -42334 -42335 -42336 -42337 -42338 -42339 -42340 +v -42341 -42342 -42343 -42344 -42345 -42346 -42347 -42348 -42349 -42350 -42351 +v -42352 -42353 -42354 -42355 -42356 -42357 -42358 -42359 -42360 -42361 -42362 +v -42363 -42364 -42365 -42366 -42367 -42368 -42369 -42370 -42371 -42372 -42373 +v -42374 -42375 -42376 -42377 -42378 -42379 -42380 -42381 -42382 -42383 -42384 +v -42385 -42386 -42387 -42388 -42389 -42390 -42391 -42392 -42393 -42394 -42395 +v -42396 -42397 -42398 -42399 -42400 -42401 -42402 -42403 -42404 -42405 -42406 +v -42407 -42408 -42409 -42410 -42411 -42412 -42413 -42414 -42415 -42416 -42417 +v -42418 -42419 -42420 -42421 -42422 -42423 -42424 -42425 -42426 -42427 -42428 +v -42429 -42430 -42431 -42432 -42433 -42434 -42435 -42436 -42437 -42438 -42439 +v -42440 -42441 -42442 -42443 -42444 -42445 -42446 -42447 -42448 -42449 -42450 +v -42451 -42452 -42453 -42454 -42455 -42456 -42457 -42458 -42459 -42460 -42461 +v -42462 -42463 -42464 -42465 -42466 -42467 -42468 -42469 -42470 -42471 -42472 +v -42473 -42474 -42475 -42476 -42477 -42478 -42479 -42480 -42481 -42482 -42483 +v -42484 -42485 -42486 -42487 -42488 -42489 -42490 -42491 -42492 -42493 -42494 +v -42495 -42496 -42497 -42498 -42499 -42500 -42501 -42502 -42503 -42504 -42505 +v -42506 -42507 -42508 -42509 -42510 -42511 -42512 -42513 -42514 -42515 -42516 +v -42517 -42518 -42519 -42520 -42521 -42522 -42523 -42524 -42525 -42526 -42527 +v -42528 -42529 -42530 -42531 -42532 -42533 -42534 -42535 -42536 -42537 -42538 +v -42539 -42540 -42541 -42542 -42543 -42544 -42545 -42546 -42547 -42548 -42549 +v -42550 -42551 -42552 -42553 -42554 -42555 -42556 -42557 -42558 -42559 -42560 +v -42561 -42562 -42563 -42564 -42565 -42566 -42567 -42568 -42569 -42570 -42571 +v -42572 -42573 -42574 -42575 -42576 -42577 -42578 -42579 -42580 -42581 -42582 +v -42583 -42584 -42585 -42586 -42587 -42588 -42589 -42590 -42591 -42592 -42593 +v -42594 -42595 -42596 -42597 -42598 -42599 -42600 -42601 -42602 -42603 -42604 +v -42605 -42606 -42607 -42608 -42609 -42610 -42611 -42612 -42613 -42614 -42615 +v -42616 -42617 -42618 -42619 -42620 -42621 -42622 -42623 -42624 -42625 -42626 +v -42627 -42628 -42629 -42630 -42631 -42632 -42633 -42634 -42635 -42636 -42637 +v -42638 -42639 -42640 -42641 -42642 -42643 -42644 -42645 -42646 -42647 -42648 +v -42649 -42650 -42651 -42652 -42653 -42654 -42655 -42656 -42657 -42658 -42659 +v -42660 -42661 -42662 -42663 -42664 -42665 -42666 -42667 -42668 -42669 -42670 +v -42671 -42672 -42673 -42674 -42675 -42676 -42677 -42678 -42679 -42680 -42681 +v -42682 -42683 -42684 -42685 -42686 -42687 -42688 -42689 -42690 -42691 -42692 +v -42693 -42694 -42695 -42696 -42697 -42698 -42699 -42700 -42701 -42702 -42703 +v -42704 -42705 -42706 -42707 -42708 -42709 -42710 -42711 -42712 -42713 -42714 +v -42715 -42716 -42717 -42718 -42719 -42720 -42721 -42722 -42723 -42724 -42725 +v -42726 -42727 -42728 -42729 -42730 -42731 -42732 -42733 -42734 -42735 -42736 +v -42737 -42738 -42739 -42740 -42741 -42742 -42743 42744 -42745 42746 -42747 +v -42748 42749 -42750 42751 -42752 -42753 -42754 42755 -42756 42757 -42758 +v -42759 -42760 42761 -42762 42763 -42764 -42765 -42766 42767 -42768 42769 +v -42770 -42771 -42772 42773 -42774 42775 -42776 -42777 42778 -42779 42780 +v -42781 -42782 -42783 -42784 -42785 -42786 -42787 -42788 -42789 -42790 -42791 +v -42792 -42793 -42794 -42795 42796 42797 42798 42799 -42800 -42801 -42802 +v -42803 -42804 42805 -42806 -42807 -42808 -42809 -42810 -42811 -42812 -42813 +v -42814 -42815 -42816 -42817 -42818 -42819 -42820 -42821 -42822 -42823 -42824 +v -42825 -42826 -42827 -42828 -42829 -42830 -42831 -42832 -42833 -42834 -42835 +v -42836 -42837 -42838 -42839 -42840 -42841 -42842 -42843 -42844 -42845 -42846 +v -42847 -42848 -42849 -42850 -42851 -42852 -42853 -42854 -42855 -42856 -42857 +v -42858 -42859 -42860 -42861 -42862 -42863 -42864 -42865 -42866 -42867 -42868 +v -42869 -42870 -42871 -42872 -42873 -42874 -42875 -42876 -42877 -42878 -42879 +v -42880 -42881 -42882 -42883 -42884 -42885 -42886 -42887 -42888 -42889 -42890 +v -42891 -42892 -42893 -42894 -42895 -42896 -42897 -42898 -42899 -42900 -42901 +v -42902 -42903 -42904 -42905 -42906 -42907 -42908 -42909 -42910 -42911 -42912 +v -42913 -42914 -42915 -42916 -42917 -42918 -42919 -42920 -42921 -42922 -42923 +v -42924 -42925 42926 -42927 42928 -42929 -42930 -42931 -42932 42933 -42934 +v 42935 -42936 -42937 -42938 -42939 42940 -42941 42942 -42943 -42944 -42945 +v -42946 42947 -42948 42949 -42950 -42951 42952 -42953 42954 -42955 -42956 +v 42957 -42958 -42959 -42960 -42961 -42962 -42963 -42964 -42965 -42966 -42967 +v -42968 -42969 42970 42971 42972 42973 -42974 -42975 -42976 -42977 -42978 +v -42979 -42980 -42981 -42982 -42983 -42984 -42985 -42986 -42987 -42988 -42989 +v -42990 -42991 -42992 -42993 -42994 -42995 -42996 -42997 -42998 -42999 -43000 +v -43001 -43002 -43003 -43004 -43005 -43006 -43007 -43008 -43009 -43010 -43011 +v -43012 -43013 -43014 -43015 -43016 -43017 -43018 -43019 -43020 43021 -43022 +v -43023 43024 -43025 -43026 43027 -43028 -43029 -43030 43031 -43032 -43033 +v -43034 -43035 -43036 -43037 -43038 -43039 -43040 -43041 -43042 43043 -43044 +v 43045 43046 43047 43048 -43049 -43050 -43051 -43052 -43053 -43054 -43055 +v -43056 -43057 -43058 -43059 -43060 -43061 -43062 -43063 -43064 -43065 -43066 +v -43067 -43068 -43069 -43070 -43071 -43072 -43073 -43074 -43075 -43076 -43077 +v -43078 -43079 -43080 -43081 -43082 -43083 -43084 -43085 -43086 -43087 -43088 +v -43089 -43090 -43091 -43092 -43093 -43094 -43095 -43096 -43097 -43098 -43099 +v -43100 -43101 -43102 -43103 -43104 -43105 -43106 -43107 -43108 -43109 -43110 +v -43111 -43112 -43113 -43114 -43115 -43116 -43117 -43118 -43119 -43120 -43121 +v -43122 -43123 -43124 -43125 -43126 -43127 -43128 -43129 -43130 -43131 -43132 +v -43133 43134 -43135 43136 -43137 -43138 43139 -43140 43141 -43142 -43143 +v 43144 -43145 43146 -43147 -43148 -43149 43150 -43151 43152 -43153 -43154 +v 43155 -43156 -43157 -43158 -43159 -43160 -43161 -43162 -43163 -43164 -43165 +v 43166 -43167 43168 43169 43170 43171 -43172 -43173 -43174 -43175 -43176 +v -43177 -43178 -43179 43180 -43181 43182 -43183 43184 -43185 -43186 -43187 +v -43188 43189 43190 43191 43192 43193 -43194 43195 -43196 -43197 -43198 -43199 +v 43200 43201 43202 -43203 -43204 -43205 43206 -43207 -43208 -43209 -43210 +v -43211 -43212 -43213 -43214 43215 43216 43217 43218 43219 -43220 -43221 43222 +v 43223 43224 43225 43226 43227 43228 43229 -43230 -43231 -43232 -43233 43234 +v 43235 -43236 -43237 -43238 -43239 -43240 -43241 -43242 -43243 -43244 -43245 +v 43246 -43247 -43248 43249 43250 43251 43252 43253 43254 -43255 -43256 -43257 +v -43258 -43259 -43260 -43261 43262 -43263 -43264 -43265 43266 43267 43268 +v 43269 43270 43271 43272 -43273 -43274 43275 43276 -43277 43278 -43279 -43280 +v 43281 -43282 -43283 -43284 -43285 43286 43287 -43288 -43289 -43290 -43291 +v 43292 43293 43294 43295 43296 43297 43298 -43299 -43300 -43301 43302 43303 +v 43304 43305 43306 43307 43308 43309 -43310 43311 -43312 43313 43314 -43315 +v 43316 -43317 -43318 43319 43320 -43321 43322 -43323 -43324 43325 43326 -43327 +v -43328 -43329 43330 -43331 43332 -43333 -43334 43335 -43336 -43337 -43338 +v -43339 -43340 -43341 -43342 -43343 -43344 -43345 43346 43347 43348 43349 +v -43350 -43351 -43352 -43353 -43354 -43355 -43356 -43357 -43358 43359 -43360 +v -43361 43362 -43363 -43364 -43365 -43366 -43367 43368 43369 43370 43371 +v -43372 -43373 -43374 -43375 -43376 43377 -43378 43379 -43380 43381 -43382 +v 43383 -43384 -43385 43386 -43387 -43388 43389 -43390 -43391 -43392 -43393 +v -43394 -43395 -43396 -43397 43398 43399 43400 43401 43402 43403 -43404 -43405 +v 43406 43407 43408 43409 43410 43411 43412 43413 -43414 -43415 -43416 -43417 +v -43418 -43419 -43420 -43421 -43422 -43423 -43424 -43425 -43426 -43427 -43428 +v -43429 -43430 -43431 -43432 -43433 -43434 -43435 -43436 -43437 43438 43439 +v -43440 -43441 43442 -43443 -43444 -43445 -43446 -43447 -43448 -43449 43450 +v -43451 -43452 -43453 -43454 -43455 -43456 -43457 -43458 43459 -43460 -43461 +v -43462 -43463 -43464 -43465 -43466 43467 43468 43469 -43470 -43471 -43472 +v -43473 -43474 43475 43476 -43477 43478 -43479 -43480 -43481 -43482 -43483 +v -43484 43485 -43486 -43487 -43488 -43489 -43490 -43491 -43492 -43493 -43494 +v -43495 -43496 -43497 -43498 -43499 -43500 -43501 -43502 -43503 -43504 -43505 +v -43506 -43507 -43508 -43509 -43510 43511 43512 43513 -43514 -43515 -43516 +v -43517 -43518 -43519 43520 43521 43522 -43523 43524 -43525 -43526 43527 +v -43528 -43529 -43530 -43531 -43532 43533 -43534 -43535 -43536 -43537 -43538 +v -43539 -43540 -43541 -43542 43543 43544 43545 -43546 -43547 -43548 43549 +v 43550 43551 43552 -43553 -43554 43555 -43556 -43557 -43558 -43559 -43560 +v 43561 -43562 -43563 -43564 -43565 -43566 -43567 -43568 -43569 -43570 -43571 +v -43572 -43573 -43574 -43575 -43576 -43577 -43578 -43579 -43580 -43581 -43582 +v -43583 -43584 -43585 -43586 -43587 43588 43589 43590 -43591 -43592 -43593 +v -43594 -43595 -43596 43597 43598 43599 -43600 43601 -43602 -43603 43604 +v -43605 -43606 -43607 -43608 -43609 43610 -43611 -43612 -43613 -43614 -43615 +v -43616 -43617 -43618 -43619 -43620 -43621 -43622 -43623 -43624 -43625 -43626 +v -43627 -43628 -43629 -43630 -43631 -43632 -43633 -43634 -43635 -43636 -43637 +v -43638 -43639 -43640 -43641 43642 -43643 -43644 43645 -43646 -43647 -43648 +v -43649 -43650 -43651 -43652 -43653 -43654 -43655 -43656 -43657 -43658 -43659 +v 43660 43661 43662 43663 43664 43665 43666 43667 -43668 -43669 -43670 -43671 +v -43672 -43673 -43674 -43675 -43676 -43677 -43678 -43679 -43680 43681 43682 +v -43683 -43684 43685 43686 -43687 -43688 -43689 -43690 43691 -43692 -43693 +v 43694 -43695 -43696 -43697 -43698 -43699 -43700 -43701 -43702 -43703 43704 +v 43705 43706 43707 43708 -43709 -43710 43711 43712 43713 43714 -43715 -43716 +v -43717 -43718 -43719 -43720 -43721 -43722 -43723 43724 43725 -43726 -43727 +v -43728 -43729 -43730 -43731 -43732 -43733 43734 -43735 -43736 -43737 -43738 +v -43739 -43740 -43741 -43742 43743 -43744 -43745 -43746 -43747 43748 43749 +v -43750 -43751 -43752 -43753 43754 -43755 -43756 -43757 -43758 -43759 -43760 +v -43761 43762 -43763 -43764 -43765 -43766 -43767 43768 -43769 -43770 -43771 +v -43772 -43773 -43774 -43775 -43776 -43777 -43778 43779 -43780 -43781 -43782 +v 43783 43784 -43785 43786 -43787 -43788 -43789 -43790 -43791 -43792 -43793 +v -43794 -43795 -43796 -43797 -43798 -43799 -43800 43801 43802 -43803 -43804 +v -43805 -43806 43807 43808 43809 -43810 43811 -43812 -43813 43814 -43815 +v -43816 -43817 -43818 -43819 43820 -43821 -43822 -43823 -43824 -43825 -43826 +v 43827 43828 -43829 -43830 43831 43832 43833 43834 -43835 -43836 43837 -43838 +v -43839 -43840 -43841 -43842 -43843 -43844 -43845 -43846 -43847 -43848 -43849 +v -43850 43851 43852 -43853 -43854 -43855 -43856 43857 43858 43859 -43860 43861 +v -43862 -43863 43864 -43865 -43866 -43867 -43868 -43869 43870 -43871 -43872 +v -43873 -43874 -43875 -43876 43877 43878 -43879 -43880 -43881 43882 43883 +v 43884 -43885 -43886 -43887 -43888 -43889 -43890 43891 -43892 43893 -43894 +v -43895 43896 -43897 43898 -43899 -43900 -43901 43902 -43903 43904 43905 43906 +v 43907 -43908 -43909 43910 -43911 -43912 -43913 43914 -43915 43916 43917 43918 +v 43919 -43920 -43921 43922 43923 43924 -43925 -43926 -43927 -43928 -43929 +v -43930 -43931 -43932 -43933 -43934 -43935 -43936 -43937 -43938 -43939 43940 +v 43941 43942 43943 -43944 43945 43946 -43947 -43948 43949 -43950 -43951 -43952 +v -43953 -43954 -43955 -43956 -43957 -43958 43959 43960 43961 43962 -43963 +v 43964 -43965 -43966 -43967 -43968 -43969 -43970 -43971 -43972 -43973 -43974 +v -43975 -43976 -43977 -43978 -43979 -43980 -43981 -43982 -43983 -43984 -43985 +v -43986 -43987 -43988 -43989 43990 -43991 43992 -43993 -43994 -43995 -43996 +v -43997 -43998 -43999 44000 44001 44002 44003 -44004 44005 -44006 -44007 +v -44008 -44009 -44010 -44011 -44012 -44013 -44014 -44015 -44016 -44017 44018 +v 44019 -44020 44021 -44022 -44023 -44024 -44025 -44026 44027 -44028 44029 +v -44030 -44031 -44032 44033 -44034 44035 -44036 -44037 -44038 44039 -44040 +v 44041 44042 44043 44044 -44045 -44046 44047 44048 44049 -44050 -44051 -44052 +v -44053 -44054 -44055 -44056 -44057 -44058 -44059 -44060 44061 44062 44063 +v 44064 -44065 -44066 44067 -44068 44069 -44070 -44071 -44072 -44073 -44074 +v -44075 -44076 -44077 -44078 -44079 -44080 -44081 -44082 -44083 44084 44085 +v -44086 -44087 -44088 -44089 -44090 -44091 -44092 -44093 -44094 44095 44096 +v 44097 -44098 -44099 44100 -44101 -44102 -44103 -44104 -44105 -44106 -44107 +v -44108 -44109 -44110 -44111 -44112 44113 -44114 44115 -44116 -44117 44118 +v -44119 44120 -44121 -44122 44123 -44124 44125 44126 44127 44128 -44129 -44130 +v 44131 44132 44133 -44134 -44135 -44136 -44137 -44138 -44139 -44140 -44141 +v -44142 -44143 -44144 44145 44146 44147 44148 -44149 -44150 -44151 -44152 +v -44153 -44154 -44155 -44156 -44157 -44158 -44159 -44160 -44161 -44162 -44163 +v -44164 -44165 -44166 -44167 -44168 -44169 -44170 -44171 -44172 -44173 -44174 +v -44175 -44176 -44177 -44178 -44179 -44180 44181 -44182 -44183 -44184 -44185 +v -44186 -44187 -44188 -44189 -44190 -44191 -44192 -44193 -44194 -44195 -44196 +v -44197 -44198 -44199 -44200 -44201 -44202 -44203 44204 -44205 -44206 -44207 +v -44208 -44209 -44210 -44211 -44212 -44213 -44214 -44215 -44216 -44217 -44218 +v -44219 -44220 -44221 -44222 -44223 -44224 -44225 -44226 -44227 -44228 -44229 +v 44230 -44231 -44232 -44233 -44234 -44235 44236 -44237 44238 -44239 -44240 +v 44241 -44242 44243 -44244 -44245 44246 -44247 44248 -44249 -44250 -44251 +v 44252 -44253 44254 44255 44256 -44257 -44258 -44259 -44260 -44261 -44262 +v -44263 -44264 -44265 -44266 -44267 44268 44269 44270 44271 -44272 -44273 +v -44274 -44275 -44276 -44277 -44278 -44279 44280 -44281 44282 -44283 -44284 +v -44285 -44286 -44287 44288 44289 44290 44291 -44292 -44293 -44294 -44295 +v -44296 -44297 -44298 -44299 -44300 -44301 -44302 -44303 -44304 -44305 -44306 +v -44307 -44308 44309 -44310 -44311 -44312 -44313 -44314 44315 -44316 44317 +v -44318 -44319 -44320 44321 -44322 44323 -44324 -44325 44326 -44327 -44328 +v -44329 -44330 -44331 -44332 44333 44334 44335 -44336 -44337 -44338 -44339 +v -44340 -44341 -44342 -44343 -44344 -44345 -44346 -44347 -44348 -44349 -44350 +v -44351 -44352 44353 -44354 -44355 -44356 -44357 -44358 44359 -44360 44361 +v -44362 -44363 -44364 44365 -44366 44367 -44368 -44369 44370 -44371 -44372 +v -44373 -44374 -44375 -44376 44377 44378 44379 -44380 -44381 -44382 -44383 +v -44384 -44385 -44386 -44387 -44388 -44389 -44390 -44391 -44392 -44393 -44394 +v -44395 -44396 44397 -44398 -44399 -44400 -44401 -44402 44403 -44404 44405 +v -44406 -44407 -44408 44409 -44410 44411 -44412 -44413 44414 -44415 -44416 +v -44417 -44418 -44419 -44420 44421 44422 44423 44424 -44425 44426 -44427 +v -44428 -44429 -44430 -44431 -44432 -44433 -44434 -44435 -44436 -44437 -44438 +v -44439 -44440 -44441 -44442 -44443 -44444 -44445 -44446 -44447 -44448 -44449 +v -44450 -44451 -44452 -44453 -44454 -44455 -44456 -44457 -44458 -44459 -44460 +v -44461 -44462 -44463 -44464 -44465 -44466 -44467 -44468 -44469 -44470 -44471 +v -44472 -44473 -44474 -44475 -44476 -44477 -44478 -44479 -44480 -44481 -44482 +v -44483 -44484 -44485 -44486 -44487 -44488 -44489 -44490 -44491 -44492 -44493 +v -44494 -44495 -44496 44497 -44498 -44499 -44500 -44501 -44502 -44503 -44504 +v -44505 -44506 -44507 -44508 -44509 -44510 -44511 -44512 -44513 -44514 -44515 +v -44516 -44517 -44518 -44519 -44520 -44521 -44522 -44523 -44524 -44525 -44526 +v -44527 -44528 -44529 -44530 -44531 -44532 -44533 -44534 -44535 -44536 -44537 +v -44538 -44539 -44540 -44541 -44542 -44543 -44544 -44545 -44546 -44547 -44548 +v -44549 -44550 -44551 -44552 -44553 -44554 44555 -44556 44557 -44558 -44559 +v -44560 44561 -44562 44563 -44564 -44565 -44566 44567 -44568 44569 -44570 +v -44571 -44572 -44573 44574 -44575 44576 -44577 -44578 44579 -44580 -44581 +v -44582 -44583 -44584 -44585 -44586 -44587 -44588 -44589 44590 44591 44592 +v -44593 -44594 -44595 -44596 -44597 -44598 -44599 -44600 -44601 -44602 -44603 +v -44604 -44605 -44606 -44607 -44608 -44609 44610 -44611 -44612 -44613 -44614 +v -44615 44616 -44617 44618 -44619 -44620 -44621 44622 -44623 44624 -44625 +v -44626 44627 -44628 -44629 -44630 -44631 -44632 -44633 44634 44635 44636 +v -44637 -44638 -44639 -44640 -44641 -44642 -44643 -44644 -44645 -44646 -44647 +v -44648 -44649 -44650 -44651 -44652 -44653 -44654 -44655 -44656 -44657 -44658 +v 44659 44660 -44661 -44662 44663 -44664 -44665 -44666 -44667 -44668 -44669 +v -44670 -44671 -44672 -44673 -44674 -44675 -44676 44677 44678 -44679 44680 +v 44681 -44682 -44683 44684 -44685 -44686 -44687 -44688 -44689 -44690 -44691 +v -44692 -44693 44694 -44695 -44696 -44697 -44698 -44699 -44700 -44701 -44702 +v -44703 -44704 -44705 -44706 -44707 -44708 -44709 -44710 -44711 -44712 44713 +v 44714 -44715 44716 -44717 -44718 -44719 -44720 -44721 -44722 -44723 -44724 +v -44725 -44726 -44727 -44728 -44729 44730 44731 -44732 44733 44734 -44735 +v -44736 44737 -44738 -44739 -44740 -44741 -44742 -44743 -44744 -44745 -44746 +v 44747 -44748 44749 -44750 -44751 -44752 -44753 44754 -44755 44756 -44757 +v -44758 -44759 -44760 44761 -44762 44763 44764 44765 44766 44767 -44768 -44769 +v 44770 44771 44772 -44773 -44774 -44775 -44776 -44777 -44778 -44779 -44780 +v -44781 -44782 -44783 44784 44785 44786 44787 -44788 -44789 44790 44791 -44792 +v -44793 44794 44795 -44796 -44797 -44798 -44799 -44800 44801 44802 44803 44804 +v 44805 0 +c +c0 0.11 seconds 85.3 % search +c0 0.11 seconds 85.3 % focus +c0 0.00 seconds 0.0 % fail +c0 0.00 seconds 0.0 % probe +c0 0.00 seconds 0.0 % reduce +c0 0.00 seconds 0.0 % stable +c0 0.00 seconds 0.0 % vivify +c0 0.00 seconds 0.0 % walk +c0 ----------------------------------------- +c0 0.13 seconds 100.0 % solving +c +c0 conflicts: 893 7861.95 per second +c0 chronological: 9 1.01 % conflicts +c0 decisions: 6739 7.55 per conflict +c0 heap-decisions: 0 0.00 % decisions +c0 negative-decisions: 3453 51.24 % decisions +c0 positive-decisions: 3286 48.76 % decisions +c0 queue-decisions: 6557 97.30 % decisions +c0 random-decisions: 182 2.70 % decisions +c0 random-sequences: 1 182.00 decisions +c0 solving-fixed: 198 0.44 % variables +c0 failed-literals: 0 0.00 % variables +c0 lifted-literals: 0 0.00 % variables +c0 fixed-variables: 198 0.44 % variables +c0 learned-units: 13 6.57 % fixed +c0 flips: 0 0.00 thousands per second +c0 vivified-clauses: 0 0.00 % per tried clause +c0 vivify-tried: 0 0.00 % per learned clause +c0 vivify-reused: 0 0.00 % per vivify-tried +c0 learned-literals: 6619 7.52 per learned clause +c0 learned-clauses: 880 7747.50 per second +c0 learned-binaries: 89 10.11 % learned clauses +c0 learned-tier1: 418 47.50 % learned clauses +c0 learned-tier2: 354 40.23 % learned clauses +c0 learned-tier3: 108 12.27 % learned clauses +c0 jumped: 171547 21.65 % propagations +c0 propagations: 792294 6.98 millions per second +c0 probings: 0 0.00 conflict interval +c0 reductions: 0 0.00 conflict interval +c0 rephased: 0 0.00 conflict interval +c0 restarts: 164 5.45 conflict interval +c0 simplifications: 0 0.00 conflict interval +c0 switched: 0 0.00 conflict interval +c0 walked: 0 0.00 flips per walked +c +c 0.65 seconds 78.9 % simplify +c 0.20 seconds 24.4 % subsume +c 0.16 seconds 19.3 % eliminate +c 0.11 seconds 13.9 % solve +c 0.07 seconds 8.9 % substitute +c 0.04 seconds 4.9 % parse +c 0.04 seconds 4.8 % deduplicate +c 0.02 seconds 1.9 % clone +c -------------------------------------------- +c 0.82 seconds 100.0 % total +c +c eliminated: 23685 52.86 % variables +c definitions: 17618 74.38 % eliminated variables +c substituted: 2588 5.78 % variables +c deduplicated: 820 7.50 % subsumed clauses +c self-subsumed: 232 2.12 % subsumed clauses +c strengthened: 13884 9.31 % original clauses +c simplifications: 1 +c subsumed: 10939 7.34 % original clauses +c weakened: 124855 83.73 % original clauses +c simplifying-fixed: 4545 95.81 % total-fixed +c solving-fixed: 198 4.17 % total-fixed +c total-fixed: 4744 10.59 % variables +c +c utilization: 100.40 % +c process-time: 0.82 seconds +c wall-clock-time: 0.82 seconds +c maximum-resident-set-size: 22.07 MB +c +c exit 10 diff --git a/data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt b/data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt new file mode 100644 index 00000000..c49c2b24 --- /dev/null +++ b/data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt @@ -0,0 +1,122 @@ +c GimSATul SAT Solver +c Copyright (c) 2022-2023 Armin Biere University of Freiburg +c +c Version 1.1.2 09b1b3bcb5d86ef6f75bc9a0f69717c42ced70d4 +c gcc (GCC) 13.2.1 20230801 -Wall -O3 -DNDEBUG +c Wed Apr 24 16:38:17 EEST 2024 Linux Christoph-laptop 6.8.2-arch2-1 x86_64 +c +c parsing DIMACS file '../sat-rs/rustsat/data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf' +c parsed 'p cnf 27224 68879' header +c parsing took 0.02 seconds +c +c starting full simplification #1 +c +c [1] substituted 0 variables 0% in 0.00 seconds +c [1] removed 0 duplicated binary clauses 0% in 0.00 seconds +c [1] subsumed 0 clauses 0% and strengthened 0 clauses 0% in 0.00 seconds +c [1] eliminated 19247 variables 71% with bound 0 in 0.05 seconds +c [1] all candidate variables 100% tried +c +c [2] substituted 0 variables 0% in 0.01 seconds +c [2] removed 0 duplicated binary clauses 0% in 0.00 seconds +c [2] subsumed 0 clauses 0% and strengthened 480 clauses 1% in 0.01 seconds +c [2] eliminated 4904 variables 18% with bound 0 in 0.08 seconds +c [2] all candidate variables 100% tried +c +c [3] substituted 0 variables 0% in 0.00 seconds +c [3] removed 0 duplicated binary clauses 0% in 0.00 seconds +c [3] subsumed 0 clauses 0% and strengthened 0 clauses 0% in 0.00 seconds +c [3] eliminated 1352 variables 5% with bound 0 in 0.02 seconds +c [3] all candidate variables 100% tried +c +c [4] substituted 0 variables 0% in 0.00 seconds +c [4] removed 0 duplicated binary clauses 0% in 0.00 seconds +c [4] subsumed 1613 clauses 2% and strengthened 12160 clauses 18% in 0.00 seconds +c [4] eliminated 1555 variables 6% with bound 0 in 0.00 seconds +c [4] all candidate variables 100% tried +c +c removed 27222 variables 100% with 0 remaining 0% +c removed 66491 clauses 97% with 2386 remaining 3% +c +c simplification #1 took 0.18 seconds +c +c cloning first ring solver +c memory increased by 1.05 from 14.56 MB to 15.25 MB +c +s UNSATISFIABLE +c +c0 0.00 seconds 0.0 % fail +c0 0.00 seconds 0.0 % focus +c0 0.00 seconds 0.0 % probe +c0 0.00 seconds 0.0 % reduce +c0 0.00 seconds 0.0 % search +c0 0.00 seconds 0.0 % stable +c0 0.00 seconds 0.0 % vivify +c0 0.00 seconds 0.0 % walk +c0 ----------------------------------------- +c0 0.00 seconds 100.0 % solving +c +c0 conflicts: 0 0.00 per second +c0 chronological: 0 0.00 % conflicts +c0 decisions: 0 0.00 per conflict +c0 heap-decisions: 0 0.00 % decisions +c0 negative-decisions: 0 0.00 % decisions +c0 positive-decisions: 0 0.00 % decisions +c0 queue-decisions: 0 0.00 % decisions +c0 random-decisions: 0 0.00 % decisions +c0 random-sequences: 0 0.00 decisions +c0 solving-fixed: 0 0.00 % variables +c0 failed-literals: 0 0.00 % variables +c0 lifted-literals: 0 0.00 % variables +c0 fixed-variables: 0 0.00 % variables +c0 learned-units: 0 0.00 % fixed +c0 flips: 0 0.00 thousands per second +c0 vivified-clauses: 0 0.00 % per tried clause +c0 vivify-tried: 0 0.00 % per learned clause +c0 vivify-reused: 0 0.00 % per vivify-tried +c0 learned-literals: 0 0.00 per learned clause +c0 learned-clauses: 0 0.00 per second +c0 learned-binaries: 0 0.00 % learned clauses +c0 learned-tier1: 0 0.00 % learned clauses +c0 learned-tier2: 0 0.00 % learned clauses +c0 learned-tier3: 0 0.00 % learned clauses +c0 jumped: 0 0.00 % propagations +c0 propagations: 0 0.00 millions per second +c0 probings: 0 0.00 conflict interval +c0 reductions: 0 0.00 conflict interval +c0 rephased: 0 0.00 conflict interval +c0 restarts: 0 0.00 conflict interval +c0 simplifications: 0 0.00 conflict interval +c0 switched: 0 0.00 conflict interval +c0 walked: 0 0.00 flips per walked +c +c 0.18 seconds 91.7 % simplify +c 0.14 seconds 70.4 % eliminate +c 0.02 seconds 7.5 % parse +c 0.01 seconds 7.1 % subsume +c 0.01 seconds 5.9 % substitute +c 0.00 seconds 1.3 % deduplicate +c 0.00 seconds 0.7 % clone +c 0.00 seconds 0.0 % solve +c -------------------------------------------- +c 0.20 seconds 100.0 % total +c +c eliminated: 27058 99.39 % variables +c definitions: 11078 40.94 % eliminated variables +c substituted: 0 0.00 % variables +c deduplicated: 0 0.00 % subsumed clauses +c self-subsumed: 1613 100.00 % subsumed clauses +c strengthened: 12640 18.35 % original clauses +c simplifications: 1 +c subsumed: 1613 2.34 % original clauses +c weakened: 111741 162.23 % original clauses +c simplifying-fixed: 164 98.80 % total-fixed +c solving-fixed: 0 0.00 % total-fixed +c total-fixed: 166 0.61 % variables +c +c utilization: 100.86 % +c process-time: 0.20 seconds +c wall-clock-time: 0.20 seconds +c maximum-resident-set-size: 16.06 MB +c +c exit 20 diff --git a/data/kissat-AProVE11-12.txt b/data/kissat-AProVE11-12.txt new file mode 100644 index 00000000..d9fb9f6c --- /dev/null +++ b/data/kissat-AProVE11-12.txt @@ -0,0 +1,4047 @@ +c ---- [ banner ] ------------------------------------------------------------ +c +c Kissat SAT Solver +c +c Copyright (c) 2021-2023 Armin Biere University of Freiburg +c Copyright (c) 2019-2021 Armin Biere Johannes Kepler University Linz +c +c Version 3.1.1 71caafb4d182ced9f76cef45b00f37cc598f2a37 +c gcc (GCC) 13.2.1 20230801 -W -Wall -O3 -DNDEBUG +c Wed Apr 24 16:38:09 EEST 2024 Linux Christoph-laptop 6.8.2-arch2-1 x86_64 +c +c ---- [ parsing ] ----------------------------------------------------------- +c +c opened and reading DIMACS file: +c +c ../sat-rs/rustsat/data/AProVE11-12.cnf +c +c parsed 'p cnf 44805 149118' header +c closing input after reading 2717714 bytes (3 MB) +c finished parsing after 0.04 seconds +c +c ---- [ solving ] ----------------------------------------------------------- +c +c seconds switched conflicts irredundant variables +c MB reductions redundant trail remaining +c level restarts binary glue +c +c * 0.04 12 0 0 0 0 0 0 63646 83714 0% 0 44195 99% +c { 0.04 13 0 0 0 0 0 0 63646 83714 0% 0 44195 99% +c i 0.04 14 30 0 0 1 27 16 63655 83713 17% 2 41235 92% +c i 0.04 14 17 0 0 1 65 41 63663 83713 10% 2 41233 92% +c i 0.07 14 43 0 0 30 137 105 63669 83712 16% 3 41132 92% +c i 0.07 14 43 0 0 30 138 105 63669 83712 16% 3 41130 92% +c i 0.11 15 140 0 0 68 519 422 63691 83710 24% 3 41126 92% +c i 0.11 15 140 0 0 70 521 422 63692 83710 24% 3 40930 91% +c i 0.12 15 140 0 0 70 524 422 63693 83710 24% 3 40928 91% +c i 0.12 15 141 0 0 70 528 423 63695 83710 24% 3 40926 91% +c i 0.12 15 142 0 0 70 535 428 63696 83710 24% 3 40924 91% +c i 0.14 15 122 0 0 102 653 530 63706 83709 23% 3 40922 91% +c i 0.14 15 122 0 0 102 655 531 63706 83709 23% 3 40920 91% +c i 0.16 15 117 0 0 114 726 571 63720 83709 24% 3 40911 91% +c i 0.16 15 114 0 0 114 743 585 63721 83709 24% 3 40902 91% +c i 0.17 15 107 0 0 118 889 710 63739 83709 26% 3 40900 91% +c i 0.17 15 108 0 0 118 893 712 63740 83709 26% 3 40898 91% +c i 0.17 15 109 0 0 118 900 717 63741 83709 26% 3 40887 91% +c i 0.17 15 109 0 0 118 901 717 63741 83709 26% 3 40886 91% +c i 0.17 15 109 0 0 118 902 717 63741 83709 26% 3 40874 91% +c +c seconds switched conflicts irredundant variables +c MB reductions redundant trail remaining +c level restarts binary glue +c +c i 0.17 15 109 0 0 118 905 719 63741 83709 26% 3 40871 91% +c i 0.18 15 104 0 0 135 965 772 63745 83709 26% 3 40464 90% +c i 0.19 15 102 0 0 140 981 785 63747 83709 26% 3 40358 90% +c - 0.21 15 104 0 1 147 1001 710 54699 83709 27% 3 40358 90% +c } 0.21 15 104 1 1 147 1001 710 54699 83709 27% 3 40358 90% +c [ 0.21 15 0 1 1 147 1001 710 54699 83709 0% 0 40358 90% +c B 0.21 15 0 1 1 147 1001 710 54699 83709 0% 0 40358 90% +c i 0.22 15 361 1 1 147 1031 727 54706 83709 85% 2 40356 90% +c i 0.22 15 365 1 1 147 1042 735 54706 83709 87% 2 40354 90% +c i 0.22 15 366 1 1 147 1048 738 54706 83709 87% 2 40352 90% +c i 0.22 15 367 1 1 147 1052 739 54708 83708 88% 2 40350 90% +c i 0.22 15 367 1 1 147 1054 739 54709 83708 88% 2 40348 90% +c i 0.22 15 367 1 1 147 1055 739 54709 83708 88% 2 40287 90% +c i 0.22 15 369 1 1 147 1065 745 54710 83708 89% 2 40285 90% +c i 0.22 15 369 1 1 147 1067 746 54710 83708 89% 2 40283 90% +c i 0.22 15 370 1 1 147 1070 748 54710 83708 89% 2 40281 90% +c i 0.22 15 370 1 1 147 1072 748 54711 83708 89% 2 40259 90% +c i 0.22 15 370 1 1 147 1075 749 54711 83708 89% 2 40114 90% +c i 0.23 15 369 1 1 147 1087 756 54712 83708 90% 2 40099 89% +c i 0.23 15 370 1 1 147 1097 763 54712 83708 90% 2 40097 89% +c +c seconds switched conflicts irredundant variables +c MB reductions redundant trail remaining +c level restarts binary glue +c +c i 0.23 15 372 1 1 147 1111 770 54715 83708 91% 2 40093 89% +c i 0.23 15 374 1 1 147 1132 784 54716 83708 92% 2 40089 89% +c i 0.23 15 374 1 1 147 1133 784 54716 83708 92% 2 40073 89% +c i 0.23 15 376 1 1 147 1143 789 54718 83708 92% 2 40063 89% +c ] 0.23 15 376 1 1 147 1143 789 54718 83708 92% 2 40063 89% +c 1 0.23 15 104 1 1 147 1143 789 54718 83708 27% 3 40063 89% +c +c ---- [ result ] ------------------------------------------------------------ +c +s SATISFIABLE +v -1 2 -3 4 -5 6 -7 8 -9 10 -11 12 -13 14 -15 16 -17 18 -19 20 21 -22 -23 24 +v -25 26 -27 28 -29 30 -31 32 33 -34 -35 36 -37 38 -39 40 -41 42 -43 44 -45 46 +v -47 48 -49 50 -51 52 -53 54 -55 56 -57 58 -59 60 -61 62 -63 64 -65 66 -67 68 +v -69 70 -71 72 -73 74 75 -76 77 -78 -79 -80 81 -82 83 84 -85 86 -87 -88 -89 +v 90 -91 92 93 -94 95 -96 -97 -98 99 -100 101 102 -103 104 -105 -106 -107 108 +v -109 110 -111 112 -113 114 115 -116 117 -118 119 120 -121 122 -123 -124 -125 +v 126 -127 128 129 -130 -131 132 -133 -134 135 136 -137 -138 139 -140 141 142 +v 143 144 -145 146 -147 148 -149 150 151 -152 153 -154 155 -156 157 158 -159 +v -160 -161 162 163 -164 -165 166 -167 168 169 170 171 -172 173 174 -175 176 +v -177 -178 -179 180 -181 182 -183 184 185 -186 -187 -188 189 -190 191 192 +v -193 194 -195 -196 -197 198 199 -200 -201 202 -203 204 205 206 207 -208 209 +v 210 -211 212 -213 -214 -215 216 -217 218 219 -220 221 -222 -223 -224 225 +v -226 227 -228 229 -230 231 232 -233 234 -235 236 237 -238 239 -240 -241 -242 +v 243 -244 245 246 -247 248 -249 -250 -251 252 -253 254 255 -256 257 -258 -259 +v -260 261 -262 263 264 -265 266 -267 -268 -269 270 -271 272 273 -274 275 -276 +v -277 -278 279 -280 281 282 -283 284 -285 -286 -287 288 -289 290 291 -292 293 +v -294 -295 -296 297 -298 299 300 -301 -302 303 -304 -305 306 -307 308 -309 +v 310 -311 312 313 -314 315 -316 317 -318 319 320 -321 -322 -323 324 -325 326 +v -327 328 329 -330 -331 -332 333 334 -335 -336 337 -338 339 340 341 342 -343 +v 344 345 -346 347 -348 -349 -350 351 -352 353 354 -355 356 -357 -358 -359 360 +v -361 362 363 -364 365 -366 -367 -368 369 -370 371 372 -373 374 -375 -376 +v -377 378 -379 380 381 -382 383 -384 -385 -386 387 -388 389 390 -391 392 -393 +v -394 -395 396 -397 398 399 -400 401 -402 -403 -404 405 -406 407 408 -409 410 +v -411 -412 -413 414 -415 416 417 -418 419 -420 -421 -422 423 -424 425 426 +v -427 428 -429 -430 -431 432 433 -434 -435 436 -437 438 439 440 441 -442 443 +v -444 445 -446 447 448 -449 450 -451 452 453 -454 455 -456 -457 -458 459 -460 +v 461 -462 463 -464 465 466 -467 468 -469 470 471 -472 473 -474 -475 -476 477 +v -478 479 480 -481 482 -483 -484 -485 486 -487 488 489 -490 491 -492 -493 +v -494 495 -496 497 498 -499 500 -501 -502 -503 504 -505 506 507 -508 509 -510 +v -511 -512 513 -514 515 -516 517 -518 519 520 -521 522 -523 524 525 -526 527 +v -528 -529 -530 531 -532 533 534 -535 536 -537 -538 -539 540 -541 542 543 +v -544 545 -546 -547 -548 549 -550 551 552 -553 554 -555 -556 -557 558 -559 +v 560 561 -562 563 -564 -565 -566 567 -568 569 -570 571 -572 573 574 -575 576 +v -577 578 579 -580 -581 582 -583 -584 585 -586 587 -588 589 -590 591 592 -593 +v 594 -595 596 597 -598 -599 600 -601 -602 603 -604 605 606 -607 -608 609 -610 +v -611 612 -613 614 615 -616 -617 618 -619 -620 621 -622 623 624 -625 -626 627 +v -628 -629 630 -631 632 633 -634 -635 636 -637 -638 639 -640 641 642 -643 +v -644 645 -646 -647 648 -649 650 651 -652 -653 654 -655 -656 657 -658 659 660 +v -661 -662 663 -664 -665 666 -667 668 669 -670 -671 672 -673 -674 675 -676 +v 677 678 -679 -680 681 -682 -683 684 -685 686 687 -688 -689 690 -691 -692 693 +v -694 695 696 -697 -698 699 -700 -701 702 -703 704 705 -706 -707 708 -709 +v -710 711 -712 713 714 -715 -716 717 -718 -719 720 -721 722 -723 724 -725 726 +v 727 -728 729 -730 731 732 -733 734 -735 -736 -737 738 -739 740 741 -742 -743 +v 744 -745 -746 747 -748 749 750 -751 -752 753 -754 -755 756 -757 758 759 -760 +v -761 762 -763 -764 765 -766 767 768 -769 -770 771 -772 -773 774 -775 776 777 +v -778 -779 780 -781 -782 783 -784 785 786 -787 -788 789 -790 -791 792 -793 +v 794 795 -796 -797 798 -799 -800 801 -802 803 804 -805 -806 807 -808 -809 810 +v -811 812 813 -814 -815 816 -817 -818 819 -820 821 822 -823 -824 825 -826 +v -827 828 -829 830 831 -832 -833 834 -835 -836 837 -838 839 840 -841 -842 843 +v -844 -845 846 -847 848 849 -850 -851 852 -853 -854 855 -856 857 858 -859 +v -860 861 -862 -863 864 -865 866 867 -868 -869 870 -871 -872 873 -874 875 876 +v -877 -878 879 -880 -881 882 -883 884 -885 886 -887 888 889 -890 891 -892 893 +v 894 -895 896 -897 -898 -899 900 -901 902 903 -904 -905 906 -907 -908 909 +v -910 911 912 -913 -914 915 -916 -917 918 -919 920 921 -922 -923 924 -925 +v -926 927 -928 929 930 -931 -932 933 -934 -935 936 -937 938 939 -940 -941 942 +v -943 -944 945 -946 947 948 -949 -950 951 -952 -953 954 -955 956 957 -958 +v -959 960 -961 -962 963 -964 965 966 -967 -968 969 -970 -971 972 -973 974 975 +v -976 -977 978 -979 -980 981 -982 983 984 -985 -986 987 -988 -989 990 -991 +v 992 993 -994 -995 996 -997 -998 999 -1000 1001 1002 -1003 -1004 1005 -1006 +v -1007 1008 -1009 1010 1011 -1012 -1013 1014 -1015 -1016 1017 -1018 1019 1020 +v -1021 -1022 1023 -1024 -1025 1026 -1027 1028 1029 -1030 -1031 1032 -1033 +v -1034 1035 -1036 1037 1038 -1039 -1040 1041 -1042 -1043 1044 -1045 1046 +v -1047 1048 -1049 1050 1051 -1052 1053 -1054 1055 1056 -1057 1058 -1059 -1060 +v -1061 1062 -1063 1064 1065 -1066 -1067 1068 -1069 -1070 1071 -1072 1073 1074 +v -1075 -1076 1077 -1078 -1079 1080 -1081 1082 1083 -1084 -1085 1086 -1087 +v -1088 1089 -1090 1091 1092 -1093 -1094 1095 -1096 -1097 1098 -1099 1100 1101 +v -1102 -1103 1104 -1105 -1106 1107 -1108 1109 1110 -1111 -1112 1113 -1114 +v -1115 1116 -1117 1118 1119 -1120 -1121 1122 -1123 -1124 1125 -1126 1127 1128 +v -1129 -1130 1131 -1132 -1133 1134 -1135 1136 1137 -1138 -1139 1140 -1141 +v -1142 1143 -1144 1145 1146 -1147 -1148 1149 -1150 -1151 1152 -1153 1154 1155 +v -1156 -1157 1158 -1159 -1160 1161 -1162 1163 1164 -1165 -1166 1167 -1168 +v -1169 1170 -1171 1172 1173 -1174 -1175 1176 -1177 -1178 1179 -1180 1181 1182 +v -1183 -1184 1185 -1186 -1187 1188 -1189 1190 1191 -1192 -1193 1194 -1195 +v -1196 1197 -1198 1199 1200 -1201 -1202 1203 -1204 -1205 1206 -1207 1208 +v -1209 1210 -1211 1212 1213 -1214 1215 -1216 1217 1218 -1219 -1220 1221 -1222 +v -1223 1224 -1225 1226 1227 -1228 -1229 1230 -1231 -1232 1233 -1234 1235 1236 +v -1237 -1238 1239 -1240 -1241 1242 -1243 1244 1245 -1246 -1247 1248 -1249 +v -1250 1251 -1252 1253 1254 -1255 -1256 1257 -1258 -1259 1260 -1261 1262 1263 +v -1264 -1265 1266 -1267 -1268 1269 -1270 1271 1272 -1273 -1274 1275 -1276 +v -1277 1278 -1279 1280 1281 -1282 -1283 1284 -1285 -1286 1287 -1288 1289 1290 +v -1291 -1292 1293 -1294 -1295 1296 1297 -1298 -1299 -1300 -1301 -1302 -1303 +v -1304 -1305 -1306 -1307 -1308 -1309 -1310 -1311 -1312 -1313 -1314 -1315 +v -1316 -1317 -1318 -1319 -1320 -1321 -1322 -1323 -1324 -1325 -1326 -1327 +v -1328 -1329 -1330 -1331 -1332 -1333 -1334 -1335 -1336 -1337 -1338 -1339 +v -1340 -1341 -1342 -1343 -1344 -1345 -1346 -1347 -1348 -1349 -1350 -1351 +v -1352 -1353 -1354 -1355 -1356 -1357 -1358 -1359 -1360 -1361 -1362 -1363 +v -1364 1365 -1366 -1367 -1368 1369 1370 1371 1372 -1373 -1374 -1375 1376 1377 +v -1378 -1379 1380 -1381 1382 -1383 1384 -1385 1386 -1387 1388 -1389 1390 +v -1391 1392 -1393 -1394 -1395 -1396 -1397 -1398 -1399 -1400 -1401 -1402 -1403 +v -1404 -1405 -1406 -1407 -1408 -1409 -1410 -1411 -1412 -1413 -1414 -1415 +v -1416 -1417 -1418 -1419 -1420 -1421 -1422 -1423 -1424 -1425 -1426 -1427 +v -1428 -1429 -1430 -1431 -1432 -1433 -1434 -1435 -1436 -1437 -1438 -1439 +v -1440 -1441 -1442 -1443 -1444 -1445 -1446 -1447 -1448 -1449 -1450 -1451 +v -1452 -1453 -1454 -1455 -1456 -1457 -1458 -1459 -1460 -1461 -1462 -1463 +v -1464 -1465 -1466 -1467 -1468 -1469 -1470 -1471 -1472 -1473 -1474 -1475 +v -1476 -1477 -1478 -1479 -1480 -1481 -1482 -1483 -1484 -1485 -1486 -1487 +v -1488 -1489 1490 1491 1492 -1493 -1494 -1495 1496 -1497 -1498 -1499 1500 +v -1501 -1502 -1503 1504 -1505 -1506 -1507 1508 -1509 -1510 -1511 1512 -1513 +v -1514 -1515 1516 -1517 -1518 -1519 1520 -1521 -1522 -1523 1524 -1525 -1526 +v -1527 -1528 -1529 -1530 -1531 -1532 -1533 -1534 -1535 -1536 -1537 -1538 +v -1539 -1540 -1541 -1542 -1543 -1544 1545 1546 1547 -1548 -1549 -1550 -1551 +v -1552 1553 1554 -1555 -1556 -1557 -1558 -1559 -1560 -1561 -1562 -1563 -1564 +v -1565 -1566 1567 1568 -1569 -1570 1571 1572 1573 1574 1575 1576 1577 1578 +v -1579 -1580 -1581 -1582 -1583 -1584 -1585 1586 1587 -1588 1589 -1590 -1591 +v -1592 -1593 -1594 -1595 -1596 -1597 -1598 1599 -1600 -1601 -1602 -1603 1604 +v 1605 1606 -1607 -1608 -1609 -1610 -1611 -1612 -1613 -1614 1615 -1616 -1617 +v -1618 -1619 -1620 -1621 -1622 -1623 1624 -1625 -1626 1627 -1628 1629 -1630 +v -1631 1632 -1633 -1634 -1635 -1636 -1637 -1638 -1639 -1640 -1641 -1642 1643 +v 1644 -1645 -1646 -1647 1648 1649 -1650 -1651 -1652 -1653 -1654 -1655 -1656 +v -1657 -1658 -1659 -1660 -1661 -1662 -1663 -1664 -1665 1666 -1667 -1668 1669 +v -1670 -1671 -1672 -1673 -1674 -1675 -1676 -1677 -1678 -1679 -1680 -1681 +v -1682 1683 1684 1685 1686 1687 -1688 -1689 -1690 -1691 1692 -1693 -1694 +v -1695 -1696 -1697 -1698 -1699 -1700 -1701 -1702 -1703 -1704 -1705 -1706 1707 +v -1708 1709 -1710 -1711 1712 -1713 1714 1715 1716 1717 -1718 -1719 1720 -1721 +v -1722 -1723 -1724 1725 -1726 1727 -1728 -1729 1730 -1731 -1732 -1733 -1734 +v -1735 -1736 -1737 -1738 -1739 -1740 1741 1742 1743 -1744 1745 -1746 1747 +v 1748 -1749 -1750 -1751 -1752 -1753 -1754 -1755 -1756 -1757 -1758 -1759 -1760 +v -1761 -1762 -1763 1764 1765 -1766 -1767 1768 -1769 -1770 1771 -1772 1773 +v -1774 -1775 -1776 -1777 -1778 -1779 -1780 -1781 -1782 -1783 -1784 -1785 1786 +v 1787 1788 -1789 1790 -1791 -1792 1793 -1794 -1795 -1796 -1797 -1798 -1799 +v -1800 -1801 -1802 -1803 1804 1805 1806 1807 -1808 1809 -1810 -1811 -1812 +v -1813 -1814 -1815 -1816 -1817 -1818 -1819 -1820 1821 -1822 -1823 1824 -1825 +v 1826 -1827 -1828 1829 -1830 -1831 -1832 -1833 -1834 -1835 -1836 -1837 -1838 +v -1839 1840 1841 -1842 -1843 -1844 -1845 -1846 -1847 -1848 -1849 -1850 -1851 +v -1852 -1853 -1854 -1855 -1856 -1857 -1858 -1859 -1860 -1861 -1862 1863 -1864 +v -1865 1866 -1867 -1868 -1869 -1870 -1871 -1872 -1873 -1874 -1875 -1876 -1877 +v -1878 -1879 1880 1881 -1882 -1883 -1884 -1885 -1886 -1887 -1888 -1889 -1890 +v 1891 1892 -1893 1894 -1895 -1896 1897 -1898 -1899 -1900 -1901 -1902 -1903 +v 1904 -1905 1906 -1907 -1908 1909 -1910 1911 -1912 -1913 -1914 1915 -1916 +v 1917 1918 1919 1920 1921 -1922 -1923 1924 1925 1926 -1927 -1928 -1929 -1930 +v -1931 -1932 -1933 -1934 -1935 -1936 -1937 1938 1939 1940 -1941 1942 -1943 +v 1944 1945 -1946 1947 -1948 1949 1950 -1951 -1952 1953 -1954 -1955 -1956 +v -1957 -1958 -1959 -1960 -1961 -1962 -1963 -1964 -1965 -1966 -1967 -1968 +v -1969 -1970 -1971 -1972 -1973 -1974 1975 -1976 -1977 -1978 -1979 -1980 -1981 +v -1982 -1983 -1984 -1985 -1986 -1987 -1988 -1989 -1990 -1991 -1992 -1993 1994 +v -1995 -1996 -1997 -1998 -1999 -2000 -2001 -2002 2003 -2004 -2005 -2006 2007 +v -2008 -2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 -2020 -2021 +v 2022 -2023 -2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 -2034 -2035 +v 2036 -2037 -2038 -2039 -2040 -2041 -2042 -2043 -2044 -2045 -2046 2047 -2048 +v -2049 2050 -2051 -2052 2053 -2054 2055 -2056 -2057 2058 -2059 2060 -2061 +v -2062 2063 -2064 2065 2066 2067 -2068 -2069 2070 2071 -2072 -2073 -2074 +v -2075 2076 -2077 -2078 2079 -2080 -2081 -2082 -2083 -2084 -2085 -2086 -2087 +v -2088 -2089 -2090 -2091 -2092 -2093 2094 2095 -2096 -2097 2098 2099 -2100 +v -2101 -2102 2103 -2104 -2105 -2106 -2107 -2108 -2109 -2110 -2111 -2112 -2113 +v -2114 -2115 -2116 -2117 -2118 -2119 -2120 -2121 -2122 -2123 -2124 -2125 +v -2126 -2127 -2128 -2129 -2130 -2131 -2132 -2133 -2134 -2135 -2136 -2137 +v -2138 -2139 2140 2141 -2142 2143 2144 -2145 -2146 2147 -2148 -2149 -2150 +v -2151 -2152 -2153 -2154 -2155 -2156 -2157 -2158 2159 2160 -2161 -2162 -2163 +v -2164 -2165 2166 2167 -2168 -2169 -2170 -2171 -2172 2173 -2174 -2175 -2176 +v -2177 -2178 -2179 -2180 2181 -2182 2183 2184 2185 -2186 -2187 2188 2189 +v -2190 2191 -2192 2193 2194 -2195 2196 2197 2198 -2199 -2200 -2201 -2202 +v -2203 -2204 -2205 -2206 -2207 -2208 -2209 -2210 -2211 2212 2213 2214 2215 +v 2216 2217 2218 2219 2220 2221 2222 2223 -2224 -2225 -2226 -2227 -2228 -2229 +v -2230 2231 2232 -2233 2234 -2235 -2236 -2237 -2238 -2239 -2240 -2241 -2242 +v -2243 2244 -2245 -2246 -2247 -2248 2249 -2250 -2251 -2252 -2253 -2254 -2255 +v -2256 -2257 -2258 -2259 2260 2261 -2262 -2263 -2264 2265 2266 -2267 -2268 +v -2269 -2270 -2271 -2272 -2273 -2274 -2275 -2276 -2277 -2278 -2279 -2280 +v -2281 -2282 2283 -2284 -2285 2286 -2287 -2288 -2289 -2290 -2291 -2292 -2293 +v -2294 -2295 -2296 -2297 -2298 -2299 2300 2301 2302 2303 2304 -2305 -2306 +v -2307 -2308 2309 -2310 -2311 -2312 -2313 -2314 -2315 -2316 -2317 -2318 -2319 +v -2320 2321 -2322 -2323 -2324 -2325 -2326 -2327 -2328 -2329 2330 -2331 2332 +v -2333 -2334 2335 -2336 2337 2338 2339 2340 -2341 -2342 2343 -2344 -2345 +v -2346 2347 -2348 2349 -2350 -2351 2352 -2353 -2354 -2355 -2356 -2357 -2358 +v -2359 -2360 -2361 2362 2363 2364 -2365 -2366 -2367 -2368 -2369 -2370 -2371 +v -2372 -2373 -2374 -2375 -2376 -2377 -2378 -2379 -2380 -2381 -2382 -2383 +v -2384 -2385 -2386 -2387 -2388 -2389 -2390 -2391 -2392 -2393 2394 -2395 2396 +v -2397 -2398 2399 -2400 2401 2402 2403 -2404 -2405 -2406 -2407 -2408 -2409 +v -2410 2411 2412 2413 2414 -2415 2416 -2417 -2418 -2419 2420 2421 2422 2423 +v 2424 -2425 -2426 2427 -2428 2429 -2430 2431 -2432 2433 -2434 2435 2436 -2437 +v -2438 -2439 2440 2441 2442 2443 2444 2445 2446 -2447 2448 -2449 2450 -2451 +v -2452 -2453 -2454 -2455 2456 -2457 2458 2459 -2460 -2461 -2462 -2463 2464 +v -2465 -2466 -2467 2468 2469 2470 2471 2472 -2473 -2474 2475 -2476 -2477 2478 +v -2479 -2480 -2481 -2482 -2483 2484 -2485 -2486 2487 -2488 -2489 2490 -2491 +v 2492 -2493 2494 -2495 -2496 -2497 2498 2499 2500 2501 2502 2503 2504 -2505 +v -2506 2507 -2508 2509 2510 2511 2512 -2513 -2514 2515 -2516 2517 2518 2519 +v -2520 -2521 2522 -2523 -2524 2525 -2526 -2527 -2528 -2529 -2530 -2531 -2532 +v -2533 2534 2535 2536 -2537 2538 -2539 2540 2541 -2542 -2543 -2544 -2545 +v -2546 -2547 -2548 -2549 -2550 -2551 -2552 -2553 -2554 -2555 -2556 -2557 +v -2558 -2559 -2560 -2561 -2562 -2563 -2564 -2565 -2566 2567 -2568 -2569 2570 +v -2571 -2572 -2573 -2574 -2575 -2576 -2577 -2578 -2579 -2580 -2581 -2582 +v -2583 2584 2585 2586 2587 2588 -2589 -2590 -2591 -2592 2593 -2594 -2595 +v -2596 -2597 -2598 -2599 -2600 -2601 -2602 -2603 -2604 -2605 -2606 -2607 2608 +v 2609 -2610 -2611 -2612 -2613 -2614 -2615 -2616 -2617 2618 -2619 -2620 -2621 +v -2622 -2623 -2624 -2625 -2626 2627 -2628 -2629 2630 -2631 2632 -2633 -2634 +v -2635 -2636 -2637 -2638 -2639 -2640 -2641 -2642 -2643 -2644 -2645 -2646 +v -2647 -2648 2649 2650 2651 2652 2653 2654 -2655 -2656 -2657 -2658 -2659 +v -2660 -2661 2662 2663 -2664 2665 -2666 -2667 -2668 -2669 -2670 -2671 -2672 +v -2673 -2674 2675 -2676 -2677 -2678 -2679 2680 -2681 2682 -2683 -2684 2685 +v -2686 2687 2688 2689 2690 2691 -2692 -2693 2694 -2695 -2696 -2697 -2698 2699 +v -2700 2701 -2702 -2703 2704 -2705 -2706 -2707 -2708 -2709 -2710 -2711 -2712 +v -2713 -2714 2715 2716 2717 -2718 2719 -2720 2721 2722 -2723 -2724 -2725 +v -2726 -2727 -2728 -2729 -2730 2731 -2732 -2733 -2734 -2735 -2736 -2737 -2738 +v -2739 -2740 -2741 -2742 -2743 -2744 -2745 -2746 2747 2748 -2749 -2750 2751 +v 2752 2753 2754 2755 -2756 -2757 -2758 -2759 -2760 -2761 -2762 -2763 2764 +v -2765 -2766 -2767 -2768 -2769 -2770 -2771 -2772 -2773 2774 -2775 -2776 -2777 +v 2778 2779 2780 2781 2782 -2783 -2784 -2785 -2786 -2787 -2788 2789 2790 -2791 +v 2792 2793 -2794 -2795 2796 -2797 -2798 2799 -2800 -2801 -2802 -2803 -2804 +v -2805 -2806 -2807 2808 -2809 -2810 2811 -2812 2813 -2814 -2815 -2816 -2817 +v -2818 -2819 -2820 2821 2822 2823 2824 -2825 -2826 -2827 -2828 2829 2830 +v -2831 -2832 2833 2834 2835 -2836 -2837 -2838 2839 -2840 -2841 -2842 2843 +v 2844 2845 -2846 -2847 2848 -2849 -2850 -2851 2852 -2853 -2854 -2855 2856 +v -2857 -2858 -2859 -2860 2861 -2862 2863 -2864 -2865 2866 -2867 2868 2869 +v 2870 2871 2872 -2873 -2874 2875 2876 2877 2878 2879 -2880 -2881 2882 -2883 +v -2884 2885 -2886 -2887 -2888 -2889 -2890 -2891 -2892 -2893 -2894 -2895 2896 +v 2897 2898 -2899 2900 -2901 2902 2903 -2904 2905 -2906 2907 -2908 -2909 -2910 +v -2911 -2912 -2913 -2914 -2915 -2916 -2917 -2918 -2919 -2920 -2921 -2922 +v -2923 -2924 -2925 2926 2927 2928 2929 2930 2931 -2932 -2933 -2934 -2935 +v -2936 -2937 -2938 2939 2940 -2941 2942 -2943 -2944 -2945 -2946 -2947 -2948 +v -2949 -2950 -2951 2952 -2953 -2954 -2955 -2956 2957 2958 2959 -2960 -2961 +v -2962 -2963 -2964 -2965 -2966 -2967 2968 -2969 -2970 -2971 -2972 -2973 -2974 +v -2975 -2976 -2977 -2978 -2979 -2980 -2981 2982 2983 2984 -2985 -2986 -2987 +v -2988 -2989 -2990 -2991 -2992 -2993 2994 -2995 -2996 -2997 -2998 -2999 -3000 +v -3001 3002 -3003 -3004 -3005 -3006 -3007 -3008 -3009 -3010 3011 -3012 -3013 +v -3014 -3015 -3016 -3017 3018 -3019 3020 -3021 -3022 -3023 -3024 -3025 -3026 +v -3027 -3028 -3029 -3030 -3031 -3032 -3033 -3034 -3035 -3036 -3037 -3038 +v -3039 -3040 -3041 -3042 -3043 -3044 3045 -3046 -3047 3048 -3049 -3050 -3051 +v -3052 -3053 -3054 -3055 -3056 -3057 -3058 -3059 -3060 -3061 3062 3063 3064 +v 3065 3066 -3067 -3068 -3069 -3070 3071 -3072 -3073 -3074 -3075 -3076 -3077 +v -3078 -3079 -3080 -3081 -3082 -3083 -3084 -3085 3086 -3087 3088 -3089 -3090 +v 3091 -3092 3093 3094 3095 3096 -3097 -3098 3099 -3100 -3101 -3102 -3103 3104 +v -3105 3106 -3107 -3108 3109 -3110 -3111 -3112 -3113 -3114 -3115 -3116 -3117 +v -3118 -3119 3120 3121 3122 -3123 3124 -3125 3126 3127 -3128 -3129 -3130 +v -3131 -3132 3133 -3134 -3135 -3136 -3137 3138 3139 3140 -3141 -3142 -3143 +v -3144 -3145 -3146 -3147 -3148 -3149 -3150 -3151 -3152 -3153 -3154 -3155 +v -3156 -3157 -3158 3159 3160 -3161 3162 -3163 -3164 -3165 -3166 -3167 -3168 +v -3169 -3170 -3171 -3172 -3173 -3174 3175 3176 3177 -3178 3179 -3180 -3181 +v 3182 -3183 -3184 -3185 -3186 -3187 -3188 -3189 -3190 -3191 -3192 3193 3194 +v 3195 3196 -3197 3198 -3199 -3200 -3201 -3202 -3203 -3204 -3205 -3206 -3207 +v -3208 -3209 -3210 -3211 -3212 -3213 -3214 -3215 -3216 -3217 3218 3219 3220 +v 3221 -3222 -3223 3224 -3225 -3226 -3227 -3228 -3229 -3230 -3231 -3232 -3233 +v -3234 3235 -3236 -3237 -3238 -3239 -3240 -3241 -3242 -3243 3244 -3245 -3246 +v -3247 -3248 -3249 -3250 3251 -3252 3253 -3254 -3255 -3256 -3257 -3258 -3259 +v -3260 -3261 -3262 -3263 -3264 -3265 -3266 -3267 -3268 -3269 -3270 -3271 +v -3272 -3273 -3274 -3275 -3276 -3277 3278 -3279 -3280 3281 -3282 -3283 -3284 +v -3285 -3286 -3287 -3288 -3289 -3290 -3291 -3292 -3293 -3294 3295 3296 -3297 +v -3298 -3299 -3300 -3301 -3302 -3303 -3304 -3305 3306 3307 -3308 3309 -3310 +v -3311 3312 -3313 -3314 -3315 -3316 -3317 -3318 3319 -3320 3321 -3322 -3323 +v 3324 -3325 3326 -3327 -3328 -3329 3330 -3331 3332 3333 3334 3335 3336 -3337 +v -3338 3339 3340 3341 -3342 -3343 -3344 -3345 -3346 -3347 -3348 -3349 -3350 +v -3351 -3352 3353 3354 3355 -3356 3357 -3358 3359 3360 -3361 -3362 -3363 +v -3364 -3365 3366 -3367 -3368 -3369 -3370 3371 3372 3373 -3374 3375 -3376 +v 3377 3378 3379 3380 -3381 -3382 -3383 -3384 -3385 -3386 -3387 -3388 -3389 +v -3390 -3391 -3392 -3393 -3394 -3395 -3396 -3397 3398 -3399 -3400 -3401 -3402 +v -3403 -3404 -3405 -3406 -3407 -3408 -3409 -3410 -3411 -3412 -3413 -3414 +v -3415 -3416 3417 -3418 -3419 -3420 -3421 -3422 -3423 -3424 -3425 3426 -3427 +v -3428 -3429 3430 -3431 -3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 +v 3442 -3443 -3444 3445 -3446 -3447 3448 -3449 3450 3451 3452 3453 3454 3455 +v 3456 -3457 3458 3459 -3460 3461 -3462 -3463 3464 -3465 -3466 3467 -3468 +v -3469 3470 -3471 3472 3473 3474 3475 3476 3477 3478 -3479 -3480 3481 3482 +v 3483 3484 3485 -3486 -3487 3488 -3489 -3490 -3491 -3492 -3493 -3494 3495 +v -3496 -3497 3498 -3499 -3500 -3501 -3502 -3503 -3504 3505 3506 3507 3508 +v -3509 3510 -3511 -3512 -3513 -3514 -3515 -3516 -3517 -3518 -3519 -3520 -3521 +v -3522 -3523 -3524 -3525 -3526 -3527 -3528 -3529 -3530 -3531 -3532 -3533 +v -3534 -3535 -3536 -3537 -3538 -3539 -3540 -3541 -3542 -3543 -3544 -3545 +v -3546 3547 3548 -3549 3550 3551 -3552 -3553 3554 -3555 -3556 -3557 -3558 +v -3559 -3560 -3561 -3562 -3563 -3564 -3565 -3566 3567 -3568 -3569 -3570 -3571 +v -3572 -3573 -3574 3575 -3576 3577 -3578 -3579 3580 -3581 -3582 -3583 -3584 +v -3585 3586 3587 -3588 -3589 -3590 3591 3592 3593 3594 -3595 -3596 3597 3598 +v 3599 -3600 -3601 -3602 -3603 -3604 -3605 -3606 -3607 -3608 -3609 -3610 -3611 +v -3612 3613 -3614 -3615 -3616 -3617 -3618 3619 3620 3621 -3622 -3623 -3624 +v -3625 -3626 -3627 -3628 -3629 -3630 -3631 -3632 -3633 -3634 -3635 -3636 +v -3637 -3638 -3639 -3640 -3641 -3642 -3643 -3644 -3645 3646 -3647 -3648 3649 +v -3650 -3651 -3652 -3653 -3654 -3655 -3656 -3657 -3658 -3659 -3660 -3661 +v -3662 3663 3664 3665 3666 3667 -3668 -3669 -3670 -3671 3672 -3673 -3674 +v -3675 -3676 -3677 -3678 -3679 -3680 -3681 -3682 -3683 3684 -3685 -3686 -3687 +v -3688 -3689 -3690 -3691 -3692 3693 3694 3695 3696 3697 -3698 -3699 -3700 +v -3701 -3702 -3703 -3704 3705 3706 -3707 3708 -3709 -3710 -3711 -3712 -3713 +v -3714 -3715 -3716 -3717 3718 -3719 -3720 3721 -3722 3723 -3724 -3725 3726 +v -3727 3728 3729 3730 3731 -3732 -3733 3734 -3735 -3736 -3737 3738 -3739 3740 +v 3741 -3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 -3753 -3754 +v 3755 -3756 -3757 -3758 -3759 -3760 -3761 -3762 -3763 -3764 -3765 -3766 -3767 +v -3768 -3769 -3770 -3771 -3772 -3773 -3774 -3775 -3776 -3777 -3778 -3779 +v -3780 3781 -3782 3783 -3784 -3785 3786 -3787 3788 3789 3790 -3791 -3792 +v -3793 -3794 -3795 -3796 -3797 3798 3799 3800 3801 3802 -3803 -3804 3805 3806 +v -3807 -3808 -3809 -3810 3811 3812 -3813 3814 -3815 3816 -3817 3818 -3819 +v -3820 -3821 -3822 -3823 -3824 -3825 -3826 3827 -3828 -3829 3830 -3831 -3832 +v -3833 -3834 3835 3836 3837 -3838 -3839 -3840 -3841 -3842 -3843 3844 3845 +v -3846 3847 -3848 -3849 3850 -3851 -3852 -3853 -3854 -3855 3856 3857 3858 +v 3859 -3860 3861 -3862 -3863 -3864 -3865 -3866 -3867 -3868 -3869 -3870 -3871 +v -3872 -3873 -3874 3875 3876 3877 3878 -3879 -3880 3881 -3882 -3883 -3884 +v -3885 -3886 -3887 -3888 3889 -3890 -3891 -3892 -3893 -3894 -3895 -3896 -3897 +v 3898 -3899 -3900 -3901 -3902 -3903 -3904 -3905 -3906 3907 -3908 -3909 -3910 +v -3911 -3912 -3913 3914 -3915 -3916 -3917 -3918 -3919 -3920 3921 -3922 -3923 +v 3924 -3925 -3926 -3927 -3928 3929 -3930 3931 -3932 -3933 -3934 3935 -3936 +v 3937 3938 3939 3940 3941 -3942 -3943 3944 3945 3946 -3947 -3948 -3949 -3950 +v -3951 -3952 -3953 -3954 -3955 3956 3957 3958 -3959 3960 -3961 3962 3963 +v -3964 -3965 -3966 -3967 -3968 3969 -3970 -3971 -3972 -3973 3974 3975 3976 +v -3977 -3978 -3979 -3980 -3981 -3982 -3983 -3984 -3985 -3986 -3987 -3988 +v -3989 -3990 -3991 -3992 -3993 -3994 -3995 -3996 -3997 -3998 -3999 -4000 +v -4001 -4002 4003 -4004 -4005 4006 -4007 -4008 -4009 -4010 -4011 -4012 -4013 +v -4014 -4015 -4016 -4017 -4018 -4019 4020 4021 4022 4023 4024 -4025 -4026 +v -4027 -4028 4029 -4030 -4031 -4032 -4033 -4034 -4035 -4036 -4037 -4038 -4039 +v -4040 -4041 -4042 -4043 4044 4045 -4046 -4047 -4048 -4049 -4050 -4051 -4052 +v -4053 4054 -4055 -4056 -4057 -4058 -4059 -4060 -4061 -4062 -4063 -4064 -4065 +v -4066 -4067 4068 4069 4070 -4071 -4072 -4073 -4074 -4075 -4076 -4077 -4078 +v -4079 4080 -4081 -4082 -4083 -4084 -4085 -4086 -4087 4088 -4089 -4090 -4091 +v -4092 -4093 -4094 -4095 -4096 4097 -4098 -4099 -4100 -4101 -4102 -4103 4104 +v -4105 4106 -4107 -4108 -4109 -4110 -4111 -4112 -4113 -4114 -4115 -4116 -4117 +v -4118 -4119 -4120 -4121 -4122 4123 4124 4125 4126 4127 4128 -4129 -4130 +v -4131 -4132 -4133 -4134 -4135 4136 4137 -4138 4139 -4140 -4141 -4142 -4143 +v -4144 -4145 -4146 -4147 -4148 4149 -4150 -4151 -4152 -4153 4154 -4155 4156 +v -4157 -4158 4159 -4160 4161 4162 4163 4164 4165 -4166 -4167 4168 -4169 -4170 +v -4171 -4172 4173 -4174 4175 -4176 -4177 4178 -4179 -4180 -4181 -4182 -4183 +v -4184 -4185 -4186 -4187 -4188 4189 4190 4191 -4192 4193 -4194 4195 4196 +v -4197 -4198 -4199 -4200 -4201 4202 -4203 -4204 -4205 -4206 4207 4208 4209 +v -4210 -4211 -4212 -4213 -4214 -4215 -4216 -4217 -4218 -4219 -4220 -4221 +v -4222 -4223 -4224 -4225 -4226 -4227 -4228 -4229 -4230 -4231 -4232 -4233 +v -4234 -4235 4236 -4237 -4238 4239 -4240 -4241 -4242 -4243 -4244 -4245 -4246 +v -4247 -4248 -4249 -4250 -4251 -4252 4253 4254 -4255 -4256 -4257 -4258 -4259 +v -4260 -4261 -4262 -4263 4264 4265 -4266 4267 -4268 -4269 4270 -4271 -4272 +v -4273 -4274 -4275 -4276 -4277 -4278 4279 4280 4281 4282 -4283 4284 -4285 +v -4286 -4287 -4288 -4289 -4290 -4291 -4292 -4293 -4294 -4295 -4296 -4297 +v -4298 -4299 -4300 -4301 -4302 -4303 4304 4305 4306 4307 -4308 -4309 4310 +v -4311 -4312 -4313 -4314 -4315 -4316 -4317 -4318 -4319 -4320 4321 -4322 -4323 +v -4324 -4325 -4326 -4327 -4328 -4329 4330 -4331 -4332 -4333 -4334 -4335 -4336 +v 4337 -4338 4339 -4340 -4341 -4342 -4343 -4344 -4345 -4346 -4347 -4348 -4349 +v -4350 -4351 -4352 -4353 -4354 -4355 4356 4357 -4358 4359 -4360 -4361 -4362 +v -4363 -4364 -4365 -4366 -4367 -4368 -4369 -4370 -4371 4372 4373 4374 -4375 +v 4376 -4377 -4378 4379 -4380 -4381 -4382 -4383 -4384 -4385 -4386 4387 -4388 +v 4389 -4390 -4391 4392 -4393 4394 -4395 -4396 -4397 -4398 4399 -4400 4401 +v 4402 4403 4404 4405 -4406 -4407 4408 4409 4410 -4411 -4412 -4413 -4414 -4415 +v -4416 -4417 -4418 -4419 -4420 -4421 4422 4423 4424 -4425 4426 -4427 4428 +v 4429 -4430 -4431 -4432 -4433 -4434 4435 -4436 -4437 -4438 -4439 4440 4441 +v 4442 -4443 4444 -4445 4446 4447 -4448 -4449 4450 4451 -4452 -4453 -4454 +v -4455 4456 4457 4458 4459 4460 4461 4462 4463 -4464 -4465 4466 4467 -4468 +v -4469 -4470 4471 4472 -4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 +v 4483 4484 4485 -4486 4487 -4488 4489 -4490 -4491 4492 4493 4494 4495 -4496 +v -4497 -4498 4499 -4500 -4501 -4502 4503 4504 4505 4506 -4507 -4508 -4509 +v -4510 4511 -4512 4513 4514 -4515 4516 -4517 -4518 4519 4520 -4521 -4522 +v -4523 -4524 -4525 -4526 -4527 4528 4529 4530 -4531 -4532 -4533 -4534 4535 +v 4536 4537 4538 4539 -4540 -4541 4542 -4543 -4544 4545 -4546 -4547 4548 -4549 +v 4550 -4551 -4552 4553 -4554 -4555 -4556 -4557 -4558 4559 4560 4561 4562 +v -4563 -4564 -4565 -4566 -4567 -4568 -4569 -4570 -4571 -4572 -4573 -4574 +v -4575 -4576 -4577 -4578 -4579 -4580 -4581 -4582 -4583 -4584 -4585 -4586 +v -4587 -4588 -4589 -4590 -4591 -4592 -4593 4594 -4595 4596 -4597 -4598 -4599 +v 4600 -4601 4602 -4603 -4604 4605 -4606 -4607 -4608 -4609 -4610 -4611 4612 +v 4613 4614 4615 -4616 -4617 -4618 -4619 -4620 -4621 -4622 -4623 -4624 -4625 +v -4626 -4627 -4628 -4629 -4630 -4631 -4632 -4633 -4634 -4635 -4636 -4637 +v -4638 -4639 -4640 -4641 -4642 -4643 -4644 -4645 -4646 4647 -4648 4649 -4650 +v -4651 -4652 4653 -4654 4655 -4656 -4657 4658 -4659 -4660 -4661 -4662 -4663 +v -4664 4665 4666 4667 4668 -4669 -4670 -4671 -4672 -4673 -4674 -4675 -4676 +v -4677 -4678 -4679 -4680 -4681 -4682 -4683 -4684 -4685 -4686 -4687 -4688 +v -4689 -4690 -4691 -4692 -4693 -4694 -4695 -4696 -4697 -4698 -4699 4700 -4701 +v 4702 -4703 -4704 -4705 4706 -4707 4708 -4709 -4710 4711 -4712 -4713 -4714 +v -4715 -4716 -4717 4718 4719 4720 4721 -4722 -4723 -4724 -4725 -4726 -4727 +v -4728 -4729 -4730 -4731 -4732 -4733 -4734 -4735 -4736 -4737 -4738 -4739 +v -4740 -4741 -4742 -4743 -4744 -4745 -4746 -4747 -4748 -4749 -4750 -4751 +v -4752 -4753 -4754 -4755 -4756 -4757 -4758 -4759 -4760 -4761 -4762 -4763 +v -4764 -4765 -4766 -4767 -4768 -4769 -4770 -4771 -4772 -4773 -4774 -4775 +v -4776 -4777 -4778 -4779 -4780 -4781 -4782 -4783 -4784 -4785 -4786 -4787 +v -4788 -4789 -4790 -4791 -4792 -4793 -4794 -4795 -4796 -4797 -4798 -4799 +v -4800 -4801 -4802 -4803 -4804 -4805 -4806 -4807 -4808 -4809 -4810 -4811 +v -4812 -4813 -4814 -4815 -4816 -4817 -4818 -4819 -4820 -4821 -4822 -4823 +v -4824 -4825 -4826 -4827 -4828 -4829 -4830 -4831 -4832 -4833 -4834 -4835 +v -4836 -4837 -4838 -4839 -4840 -4841 -4842 -4843 -4844 -4845 -4846 -4847 +v -4848 -4849 -4850 -4851 -4852 -4853 -4854 -4855 -4856 -4857 -4858 -4859 +v -4860 -4861 -4862 -4863 -4864 -4865 -4866 -4867 -4868 -4869 -4870 -4871 +v -4872 -4873 -4874 -4875 -4876 -4877 -4878 -4879 -4880 -4881 -4882 -4883 +v -4884 -4885 -4886 -4887 -4888 -4889 -4890 4891 -4892 4893 -4894 -4895 -4896 +v 4897 -4898 4899 -4900 -4901 -4902 -4903 4904 -4905 4906 -4907 -4908 -4909 +v -4910 4911 -4912 4913 -4914 -4915 4916 -4917 -4918 -4919 -4920 -4921 -4922 +v -4923 -4924 -4925 -4926 4927 4928 4929 4930 -4931 -4932 -4933 -4934 -4935 +v -4936 -4937 -4938 -4939 -4940 -4941 -4942 -4943 -4944 -4945 -4946 -4947 +v -4948 -4949 -4950 -4951 -4952 -4953 -4954 -4955 -4956 -4957 -4958 -4959 +v -4960 -4961 -4962 -4963 -4964 -4965 -4966 -4967 -4968 -4969 -4970 -4971 +v -4972 -4973 -4974 -4975 -4976 -4977 -4978 -4979 -4980 -4981 -4982 -4983 +v -4984 -4985 -4986 -4987 -4988 -4989 -4990 -4991 -4992 -4993 -4994 -4995 +v -4996 -4997 -4998 -4999 -5000 -5001 -5002 -5003 -5004 -5005 -5006 -5007 +v -5008 -5009 -5010 -5011 -5012 -5013 -5014 -5015 -5016 -5017 -5018 -5019 +v -5020 -5021 -5022 -5023 -5024 -5025 -5026 -5027 -5028 -5029 -5030 -5031 +v -5032 -5033 -5034 -5035 -5036 -5037 -5038 -5039 -5040 -5041 -5042 -5043 +v -5044 -5045 -5046 -5047 -5048 -5049 -5050 -5051 -5052 -5053 -5054 -5055 +v -5056 -5057 -5058 -5059 -5060 -5061 -5062 -5063 -5064 -5065 -5066 -5067 +v -5068 -5069 -5070 -5071 -5072 -5073 -5074 -5075 -5076 -5077 -5078 -5079 +v -5080 -5081 -5082 -5083 -5084 -5085 -5086 -5087 -5088 -5089 -5090 -5091 +v -5092 -5093 -5094 -5095 -5096 -5097 5098 -5099 5100 -5101 -5102 -5103 5104 +v -5105 5106 -5107 -5108 -5109 -5110 5111 -5112 5113 -5114 -5115 -5116 -5117 +v 5118 -5119 5120 -5121 -5122 5123 -5124 -5125 -5126 -5127 -5128 -5129 -5130 +v -5131 -5132 -5133 5134 5135 5136 5137 -5138 -5139 -5140 -5141 -5142 -5143 +v -5144 -5145 -5146 -5147 -5148 -5149 -5150 -5151 -5152 -5153 -5154 -5155 +v -5156 -5157 -5158 -5159 -5160 -5161 -5162 -5163 -5164 -5165 -5166 -5167 +v -5168 -5169 -5170 -5171 -5172 -5173 -5174 -5175 -5176 -5177 -5178 -5179 +v -5180 -5181 -5182 -5183 -5184 -5185 -5186 -5187 -5188 -5189 -5190 -5191 +v -5192 -5193 -5194 -5195 -5196 -5197 -5198 -5199 -5200 -5201 -5202 -5203 +v -5204 -5205 -5206 -5207 -5208 -5209 -5210 -5211 -5212 -5213 -5214 -5215 +v -5216 -5217 -5218 -5219 -5220 -5221 -5222 -5223 -5224 -5225 -5226 -5227 +v -5228 -5229 -5230 -5231 -5232 -5233 -5234 -5235 -5236 -5237 -5238 -5239 +v -5240 -5241 -5242 -5243 -5244 -5245 -5246 -5247 -5248 -5249 -5250 -5251 +v -5252 -5253 -5254 -5255 -5256 -5257 -5258 -5259 -5260 -5261 -5262 -5263 +v -5264 -5265 -5266 -5267 -5268 -5269 -5270 -5271 -5272 -5273 -5274 -5275 +v -5276 -5277 -5278 -5279 -5280 -5281 -5282 -5283 -5284 -5285 -5286 -5287 +v -5288 -5289 -5290 -5291 -5292 -5293 -5294 -5295 -5296 -5297 -5298 5299 -5300 +v 5301 -5302 -5303 -5304 5305 -5306 5307 -5308 -5309 -5310 -5311 5312 -5313 +v 5314 -5315 -5316 -5317 -5318 5319 -5320 5321 -5322 -5323 5324 -5325 -5326 +v -5327 -5328 -5329 -5330 -5331 -5332 -5333 -5334 5335 5336 5337 5338 -5339 +v -5340 -5341 -5342 -5343 -5344 -5345 -5346 -5347 -5348 -5349 -5350 -5351 +v -5352 -5353 -5354 -5355 -5356 -5357 -5358 -5359 -5360 -5361 -5362 -5363 +v -5364 -5365 -5366 -5367 -5368 -5369 -5370 -5371 -5372 -5373 -5374 -5375 +v -5376 -5377 -5378 -5379 -5380 -5381 -5382 -5383 -5384 -5385 -5386 -5387 +v -5388 -5389 -5390 -5391 -5392 -5393 -5394 -5395 -5396 -5397 -5398 -5399 +v -5400 -5401 -5402 -5403 -5404 -5405 -5406 -5407 -5408 -5409 -5410 -5411 +v -5412 -5413 -5414 -5415 -5416 -5417 -5418 -5419 -5420 -5421 -5422 -5423 +v -5424 -5425 -5426 -5427 -5428 -5429 -5430 -5431 -5432 -5433 -5434 -5435 +v -5436 -5437 -5438 -5439 -5440 -5441 -5442 -5443 -5444 -5445 -5446 -5447 +v -5448 -5449 -5450 -5451 -5452 -5453 -5454 -5455 -5456 -5457 -5458 -5459 +v -5460 -5461 -5462 -5463 -5464 -5465 -5466 -5467 -5468 -5469 -5470 -5471 +v -5472 -5473 -5474 -5475 -5476 -5477 -5478 -5479 -5480 -5481 -5482 -5483 +v -5484 -5485 -5486 -5487 -5488 -5489 -5490 -5491 -5492 -5493 -5494 -5495 +v -5496 -5497 -5498 -5499 -5500 -5501 -5502 -5503 -5504 -5505 5506 -5507 5508 +v -5509 -5510 -5511 5512 -5513 5514 -5515 -5516 -5517 -5518 5519 -5520 5521 +v -5522 -5523 -5524 -5525 5526 -5527 5528 -5529 -5530 5531 -5532 -5533 -5534 +v -5535 -5536 -5537 -5538 -5539 -5540 -5541 5542 5543 5544 5545 -5546 -5547 +v -5548 -5549 -5550 -5551 -5552 -5553 -5554 -5555 -5556 -5557 -5558 -5559 +v -5560 -5561 -5562 -5563 -5564 -5565 -5566 -5567 -5568 -5569 -5570 -5571 +v -5572 -5573 -5574 -5575 -5576 5577 -5578 5579 -5580 -5581 -5582 5583 -5584 +v 5585 -5586 -5587 5588 -5589 -5590 -5591 -5592 -5593 -5594 5595 5596 5597 +v 5598 -5599 5600 -5601 5602 -5603 5604 5605 5606 -5607 -5608 -5609 -5610 +v -5611 -5612 -5613 -5614 -5615 -5616 -5617 -5618 -5619 -5620 -5621 -5622 +v -5623 -5624 -5625 -5626 -5627 -5628 -5629 -5630 -5631 -5632 -5633 -5634 +v -5635 -5636 -5637 -5638 -5639 -5640 -5641 -5642 -5643 -5644 -5645 -5646 +v -5647 -5648 -5649 -5650 -5651 -5652 -5653 5654 -5655 -5656 5657 -5658 -5659 +v -5660 -5661 -5662 -5663 -5664 -5665 -5666 -5667 -5668 -5669 -5670 -5671 +v -5672 -5673 -5674 -5675 -5676 -5677 -5678 -5679 -5680 -5681 -5682 -5683 +v -5684 -5685 -5686 -5687 -5688 -5689 -5690 -5691 -5692 -5693 -5694 -5695 +v -5696 -5697 -5698 -5699 -5700 -5701 -5702 -5703 -5704 -5705 -5706 -5707 +v -5708 -5709 -5710 -5711 -5712 -5713 -5714 -5715 -5716 -5717 -5718 -5719 +v -5720 -5721 -5722 -5723 -5724 -5725 -5726 -5727 -5728 -5729 -5730 -5731 +v -5732 -5733 -5734 -5735 -5736 -5737 -5738 -5739 -5740 -5741 -5742 -5743 +v -5744 -5745 -5746 -5747 -5748 -5749 -5750 -5751 -5752 -5753 -5754 -5755 +v -5756 -5757 -5758 -5759 -5760 -5761 -5762 -5763 -5764 -5765 -5766 -5767 +v -5768 -5769 -5770 -5771 -5772 -5773 -5774 -5775 -5776 -5777 -5778 -5779 +v -5780 -5781 -5782 -5783 -5784 -5785 -5786 -5787 -5788 -5789 -5790 -5791 +v -5792 -5793 -5794 -5795 -5796 -5797 -5798 -5799 -5800 -5801 -5802 -5803 +v -5804 -5805 -5806 -5807 -5808 -5809 -5810 -5811 -5812 -5813 -5814 -5815 +v -5816 -5817 -5818 -5819 -5820 -5821 -5822 -5823 -5824 -5825 -5826 -5827 +v -5828 -5829 -5830 -5831 -5832 -5833 -5834 -5835 -5836 -5837 -5838 -5839 +v -5840 -5841 -5842 -5843 -5844 -5845 -5846 -5847 -5848 -5849 -5850 -5851 +v -5852 -5853 -5854 -5855 -5856 -5857 -5858 -5859 -5860 -5861 -5862 -5863 +v -5864 -5865 -5866 -5867 -5868 -5869 -5870 -5871 -5872 -5873 -5874 -5875 +v -5876 -5877 -5878 -5879 -5880 -5881 -5882 -5883 -5884 -5885 5886 -5887 -5888 +v -5889 -5890 -5891 -5892 -5893 -5894 -5895 -5896 -5897 -5898 -5899 -5900 +v -5901 -5902 -5903 -5904 -5905 -5906 -5907 -5908 -5909 -5910 -5911 -5912 +v -5913 -5914 -5915 -5916 -5917 -5918 -5919 -5920 -5921 -5922 -5923 -5924 +v -5925 -5926 -5927 -5928 -5929 -5930 -5931 -5932 -5933 -5934 -5935 -5936 +v -5937 -5938 -5939 -5940 -5941 -5942 -5943 -5944 -5945 -5946 -5947 -5948 +v -5949 -5950 -5951 -5952 -5953 -5954 -5955 -5956 -5957 -5958 -5959 -5960 +v -5961 -5962 -5963 -5964 -5965 -5966 -5967 -5968 -5969 -5970 -5971 -5972 +v -5973 -5974 -5975 -5976 -5977 -5978 -5979 -5980 -5981 -5982 -5983 -5984 +v -5985 -5986 -5987 -5988 -5989 -5990 -5991 -5992 -5993 -5994 -5995 -5996 +v -5997 -5998 -5999 -6000 -6001 -6002 -6003 -6004 -6005 -6006 -6007 -6008 +v -6009 -6010 -6011 -6012 -6013 -6014 -6015 -6016 -6017 -6018 -6019 -6020 +v -6021 -6022 -6023 -6024 -6025 -6026 -6027 -6028 -6029 -6030 -6031 -6032 +v -6033 -6034 -6035 -6036 -6037 -6038 -6039 -6040 -6041 -6042 -6043 -6044 +v -6045 -6046 -6047 -6048 -6049 -6050 -6051 -6052 6053 -6054 6055 -6056 -6057 +v 6058 -6059 6060 -6061 -6062 6063 -6064 6065 -6066 -6067 -6068 6069 -6070 +v 6071 -6072 -6073 -6074 6075 -6076 6077 -6078 -6079 -6080 6081 -6082 6083 +v -6084 -6085 6086 -6087 -6088 -6089 -6090 -6091 -6092 -6093 -6094 -6095 -6096 +v -6097 -6098 -6099 -6100 6101 6102 6103 6104 6105 -6106 -6107 -6108 -6109 +v -6110 -6111 6112 -6113 -6114 -6115 6116 -6117 -6118 -6119 -6120 -6121 -6122 +v -6123 -6124 -6125 -6126 -6127 -6128 -6129 -6130 -6131 -6132 -6133 -6134 +v -6135 -6136 -6137 -6138 -6139 -6140 -6141 -6142 -6143 -6144 -6145 -6146 +v -6147 -6148 -6149 -6150 -6151 -6152 -6153 -6154 -6155 -6156 -6157 -6158 +v -6159 -6160 -6161 -6162 -6163 -6164 -6165 -6166 -6167 -6168 -6169 -6170 +v -6171 -6172 -6173 -6174 -6175 -6176 -6177 -6178 -6179 -6180 -6181 -6182 +v -6183 -6184 -6185 -6186 -6187 -6188 -6189 -6190 -6191 -6192 -6193 -6194 +v -6195 -6196 -6197 -6198 -6199 -6200 -6201 -6202 -6203 -6204 -6205 -6206 +v -6207 -6208 -6209 -6210 -6211 -6212 -6213 -6214 -6215 -6216 -6217 -6218 +v -6219 -6220 -6221 -6222 -6223 -6224 -6225 -6226 -6227 -6228 -6229 -6230 +v -6231 -6232 -6233 -6234 -6235 -6236 6237 -6238 6239 -6240 -6241 -6242 6243 +v -6244 6245 -6246 -6247 -6248 6249 -6250 6251 -6252 -6253 -6254 6255 -6256 +v 6257 -6258 -6259 6260 -6261 -6262 -6263 -6264 -6265 -6266 -6267 -6268 -6269 +v -6270 6271 6272 6273 6274 -6275 -6276 -6277 -6278 -6279 -6280 -6281 -6282 +v -6283 -6284 -6285 -6286 -6287 -6288 -6289 -6290 -6291 -6292 -6293 -6294 +v -6295 -6296 -6297 -6298 -6299 -6300 -6301 -6302 -6303 -6304 -6305 -6306 +v -6307 -6308 -6309 -6310 -6311 -6312 -6313 -6314 -6315 -6316 -6317 -6318 +v -6319 -6320 -6321 -6322 -6323 -6324 -6325 -6326 -6327 6328 -6329 6330 -6331 +v -6332 6333 -6334 6335 -6336 -6337 -6338 6339 -6340 6341 -6342 -6343 -6344 +v 6345 -6346 6347 -6348 -6349 6350 -6351 -6352 -6353 -6354 -6355 -6356 -6357 +v -6358 -6359 -6360 6361 6362 6363 6364 -6365 -6366 -6367 -6368 -6369 -6370 +v -6371 -6372 -6373 -6374 -6375 -6376 -6377 -6378 -6379 -6380 -6381 -6382 +v -6383 -6384 -6385 -6386 -6387 -6388 -6389 -6390 -6391 -6392 -6393 -6394 +v -6395 -6396 -6397 -6398 -6399 -6400 -6401 -6402 -6403 -6404 -6405 -6406 +v -6407 -6408 -6409 -6410 -6411 -6412 -6413 -6414 -6415 -6416 -6417 -6418 +v -6419 -6420 -6421 -6422 -6423 -6424 -6425 -6426 -6427 -6428 -6429 -6430 +v -6431 -6432 -6433 -6434 -6435 -6436 -6437 -6438 -6439 -6440 -6441 -6442 +v -6443 -6444 -6445 -6446 -6447 -6448 -6449 -6450 -6451 -6452 -6453 -6454 +v -6455 -6456 -6457 -6458 -6459 -6460 -6461 -6462 -6463 -6464 -6465 -6466 +v -6467 -6468 -6469 -6470 -6471 -6472 -6473 -6474 -6475 -6476 -6477 -6478 +v -6479 -6480 -6481 -6482 -6483 -6484 -6485 -6486 -6487 -6488 -6489 -6490 6491 +v -6492 -6493 -6494 -6495 -6496 -6497 -6498 -6499 -6500 -6501 -6502 -6503 +v -6504 -6505 -6506 -6507 -6508 -6509 -6510 -6511 -6512 -6513 -6514 -6515 +v -6516 -6517 -6518 -6519 -6520 -6521 -6522 -6523 -6524 -6525 -6526 -6527 +v -6528 -6529 -6530 -6531 -6532 -6533 6534 -6535 6536 -6537 -6538 -6539 6540 +v -6541 6542 -6543 -6544 -6545 6546 -6547 6548 -6549 -6550 -6551 6552 -6553 +v 6554 -6555 -6556 6557 -6558 -6559 -6560 -6561 -6562 -6563 -6564 -6565 -6566 +v -6567 6568 6569 6570 -6571 -6572 -6573 -6574 -6575 -6576 -6577 -6578 -6579 +v -6580 -6581 -6582 -6583 6584 -6585 -6586 6587 -6588 -6589 -6590 -6591 -6592 +v -6593 6594 6595 6596 6597 -6598 6599 -6600 -6601 -6602 -6603 6604 -6605 +v -6606 -6607 -6608 -6609 -6610 -6611 6612 6613 6614 6615 6616 6617 6618 -6619 +v -6620 6621 -6622 6623 -6624 -6625 -6626 -6627 -6628 -6629 -6630 6631 6632 +v -6633 6634 6635 -6636 -6637 -6638 -6639 6640 -6641 -6642 6643 -6644 -6645 +v -6646 6647 -6648 -6649 -6650 -6651 -6652 6653 -6654 -6655 -6656 -6657 -6658 +v -6659 -6660 6661 6662 6663 6664 6665 6666 6667 -6668 -6669 -6670 6671 -6672 +v 6673 6674 6675 6676 -6677 -6678 6679 -6680 6681 6682 6683 -6684 -6685 6686 +v -6687 -6688 6689 -6690 -6691 -6692 -6693 -6694 -6695 -6696 -6697 6698 6699 +v 6700 -6701 -6702 -6703 -6704 -6705 -6706 -6707 -6708 -6709 -6710 -6711 -6712 +v -6713 -6714 -6715 -6716 -6717 -6718 -6719 -6720 -6721 -6722 6723 -6724 -6725 +v -6726 -6727 -6728 -6729 -6730 6731 -6732 6733 -6734 -6735 -6736 6737 -6738 +v 6739 -6740 -6741 6742 -6743 -6744 -6745 -6746 -6747 -6748 6749 6750 6751 +v -6752 -6753 -6754 -6755 -6756 -6757 -6758 -6759 -6760 -6761 -6762 -6763 +v -6764 -6765 -6766 -6767 -6768 -6769 -6770 -6771 -6772 -6773 6774 -6775 -6776 +v -6777 -6778 -6779 -6780 -6781 6782 -6783 6784 -6785 -6786 -6787 6788 -6789 +v 6790 -6791 -6792 6793 -6794 -6795 -6796 -6797 -6798 -6799 6800 6801 6802 +v -6803 -6804 -6805 -6806 -6807 -6808 -6809 -6810 -6811 -6812 -6813 -6814 +v -6815 -6816 -6817 -6818 -6819 -6820 -6821 -6822 -6823 -6824 6825 -6826 -6827 +v -6828 -6829 -6830 -6831 -6832 6833 -6834 6835 -6836 -6837 -6838 6839 -6840 +v 6841 -6842 -6843 6844 -6845 -6846 -6847 -6848 -6849 -6850 6851 6852 6853 +v -6854 -6855 -6856 -6857 -6858 -6859 -6860 -6861 -6862 -6863 -6864 -6865 +v -6866 -6867 -6868 -6869 -6870 -6871 -6872 -6873 -6874 -6875 -6876 -6877 +v -6878 -6879 -6880 -6881 -6882 -6883 -6884 -6885 -6886 -6887 -6888 -6889 +v -6890 -6891 -6892 -6893 -6894 -6895 -6896 -6897 -6898 -6899 -6900 -6901 +v -6902 -6903 -6904 -6905 -6906 -6907 -6908 -6909 -6910 -6911 -6912 -6913 +v -6914 -6915 -6916 -6917 -6918 -6919 -6920 -6921 -6922 -6923 -6924 -6925 +v -6926 -6927 -6928 -6929 -6930 -6931 -6932 -6933 -6934 -6935 -6936 -6937 +v -6938 -6939 -6940 -6941 -6942 -6943 -6944 -6945 -6946 6947 -6948 -6949 -6950 +v -6951 -6952 -6953 -6954 -6955 -6956 -6957 -6958 -6959 -6960 -6961 -6962 +v -6963 -6964 -6965 -6966 -6967 -6968 -6969 -6970 -6971 -6972 -6973 -6974 +v -6975 -6976 -6977 -6978 -6979 -6980 -6981 -6982 -6983 -6984 -6985 -6986 +v -6987 -6988 -6989 -6990 -6991 -6992 -6993 -6994 -6995 -6996 -6997 -6998 +v -6999 -7000 -7001 -7002 -7003 -7004 -7005 -7006 -7007 -7008 -7009 -7010 +v -7011 -7012 -7013 -7014 -7015 7016 -7017 7018 -7019 -7020 -7021 7022 -7023 +v 7024 -7025 -7026 -7027 -7028 7029 -7030 7031 -7032 -7033 -7034 -7035 7036 +v -7037 7038 -7039 -7040 7041 -7042 -7043 -7044 -7045 -7046 -7047 -7048 -7049 +v -7050 -7051 7052 7053 7054 -7055 -7056 -7057 -7058 -7059 -7060 -7061 -7062 +v -7063 -7064 -7065 -7066 -7067 -7068 -7069 -7070 -7071 -7072 -7073 -7074 +v -7075 -7076 -7077 -7078 -7079 -7080 -7081 -7082 -7083 -7084 -7085 -7086 +v -7087 -7088 -7089 -7090 -7091 -7092 -7093 -7094 -7095 -7096 -7097 -7098 +v -7099 -7100 -7101 -7102 -7103 -7104 -7105 -7106 -7107 -7108 -7109 -7110 +v -7111 -7112 -7113 -7114 -7115 -7116 -7117 -7118 -7119 -7120 -7121 -7122 +v -7123 -7124 -7125 -7126 -7127 -7128 -7129 -7130 -7131 -7132 -7133 -7134 +v -7135 -7136 -7137 -7138 -7139 -7140 -7141 -7142 -7143 -7144 -7145 -7146 +v -7147 7148 -7149 -7150 -7151 -7152 -7153 -7154 -7155 -7156 -7157 -7158 -7159 +v -7160 -7161 -7162 -7163 -7164 -7165 -7166 -7167 -7168 -7169 -7170 -7171 +v -7172 -7173 -7174 -7175 -7176 -7177 -7178 -7179 -7180 -7181 -7182 -7183 +v -7184 -7185 -7186 -7187 -7188 -7189 -7190 -7191 -7192 -7193 -7194 -7195 +v -7196 -7197 -7198 -7199 -7200 -7201 -7202 -7203 -7204 -7205 -7206 -7207 +v -7208 -7209 -7210 -7211 -7212 -7213 -7214 -7215 -7216 7217 -7218 7219 -7220 +v -7221 -7222 7223 -7224 7225 -7226 -7227 -7228 -7229 7230 -7231 7232 -7233 +v -7234 -7235 -7236 7237 -7238 7239 -7240 -7241 7242 -7243 -7244 -7245 -7246 +v -7247 -7248 -7249 -7250 -7251 -7252 7253 7254 7255 -7256 -7257 -7258 -7259 +v -7260 -7261 -7262 -7263 -7264 -7265 -7266 -7267 -7268 -7269 -7270 -7271 +v -7272 -7273 -7274 -7275 -7276 -7277 -7278 -7279 -7280 -7281 -7282 -7283 +v -7284 -7285 -7286 -7287 -7288 -7289 -7290 -7291 -7292 -7293 -7294 -7295 +v -7296 -7297 -7298 -7299 -7300 -7301 -7302 -7303 -7304 -7305 -7306 -7307 +v -7308 -7309 -7310 -7311 -7312 -7313 -7314 -7315 -7316 -7317 -7318 -7319 +v -7320 -7321 -7322 -7323 -7324 -7325 -7326 -7327 -7328 -7329 -7330 -7331 +v -7332 -7333 -7334 -7335 -7336 -7337 -7338 -7339 -7340 -7341 -7342 -7343 +v -7344 -7345 -7346 -7347 -7348 7349 -7350 -7351 -7352 -7353 -7354 -7355 -7356 +v -7357 -7358 -7359 -7360 -7361 -7362 -7363 -7364 -7365 -7366 -7367 -7368 +v -7369 -7370 -7371 -7372 -7373 -7374 -7375 -7376 -7377 -7378 -7379 -7380 +v -7381 -7382 -7383 -7384 -7385 -7386 -7387 -7388 -7389 -7390 -7391 -7392 +v -7393 -7394 -7395 -7396 -7397 -7398 -7399 -7400 -7401 -7402 -7403 -7404 +v -7405 -7406 -7407 -7408 -7409 -7410 -7411 -7412 -7413 -7414 -7415 -7416 +v -7417 7418 -7419 7420 -7421 -7422 -7423 7424 -7425 7426 -7427 -7428 -7429 +v -7430 7431 -7432 7433 -7434 -7435 -7436 -7437 7438 -7439 7440 -7441 -7442 +v 7443 -7444 -7445 -7446 -7447 -7448 -7449 -7450 -7451 -7452 -7453 7454 7455 +v 7456 -7457 -7458 -7459 -7460 -7461 -7462 -7463 -7464 -7465 -7466 -7467 -7468 +v -7469 -7470 -7471 -7472 -7473 -7474 -7475 -7476 -7477 -7478 -7479 -7480 +v -7481 -7482 -7483 -7484 -7485 -7486 -7487 -7488 -7489 -7490 -7491 -7492 +v -7493 -7494 -7495 -7496 -7497 -7498 -7499 -7500 -7501 -7502 -7503 -7504 +v -7505 -7506 -7507 -7508 -7509 -7510 -7511 -7512 -7513 -7514 -7515 -7516 +v -7517 -7518 -7519 -7520 -7521 -7522 -7523 -7524 -7525 -7526 -7527 -7528 +v -7529 -7530 -7531 -7532 -7533 -7534 -7535 -7536 -7537 -7538 -7539 -7540 +v -7541 -7542 -7543 -7544 -7545 -7546 -7547 -7548 -7549 7550 -7551 -7552 -7553 +v -7554 -7555 -7556 -7557 -7558 -7559 -7560 -7561 -7562 -7563 -7564 -7565 +v -7566 -7567 -7568 -7569 -7570 -7571 -7572 -7573 -7574 -7575 -7576 -7577 +v -7578 -7579 -7580 -7581 -7582 -7583 -7584 -7585 -7586 -7587 -7588 -7589 +v -7590 -7591 -7592 -7593 -7594 -7595 -7596 -7597 -7598 -7599 -7600 -7601 +v -7602 -7603 -7604 -7605 -7606 -7607 -7608 -7609 -7610 -7611 -7612 -7613 +v -7614 -7615 -7616 -7617 -7618 7619 -7620 7621 -7622 -7623 -7624 7625 -7626 +v 7627 -7628 -7629 -7630 -7631 7632 -7633 7634 -7635 -7636 -7637 -7638 7639 +v -7640 7641 -7642 -7643 7644 -7645 -7646 -7647 -7648 -7649 -7650 -7651 -7652 +v -7653 -7654 7655 7656 7657 -7658 -7659 -7660 -7661 -7662 -7663 -7664 -7665 +v -7666 -7667 -7668 -7669 -7670 -7671 -7672 -7673 -7674 -7675 -7676 -7677 +v -7678 -7679 7680 -7681 -7682 -7683 -7684 -7685 -7686 -7687 7688 -7689 7690 +v -7691 -7692 -7693 7694 -7695 7696 -7697 -7698 7699 -7700 -7701 -7702 -7703 +v -7704 -7705 7706 7707 7708 -7709 -7710 -7711 -7712 -7713 -7714 -7715 -7716 +v -7717 -7718 -7719 -7720 -7721 -7722 -7723 -7724 -7725 -7726 -7727 -7728 +v -7729 -7730 -7731 -7732 -7733 -7734 -7735 -7736 -7737 7738 -7739 7740 -7741 +v -7742 -7743 7744 -7745 7746 -7747 -7748 7749 -7750 -7751 -7752 -7753 -7754 +v -7755 7756 7757 7758 7759 -7760 -7761 -7762 -7763 -7764 -7765 -7766 -7767 +v -7768 -7769 -7770 -7771 -7772 -7773 -7774 -7775 -7776 -7777 -7778 -7779 +v -7780 -7781 -7782 -7783 -7784 -7785 -7786 -7787 -7788 7789 -7790 7791 -7792 +v -7793 -7794 7795 -7796 7797 -7798 -7799 7800 -7801 -7802 -7803 -7804 -7805 +v -7806 7807 7808 7809 7810 -7811 -7812 -7813 -7814 -7815 -7816 -7817 -7818 +v -7819 -7820 -7821 -7822 -7823 -7824 -7825 -7826 -7827 -7828 -7829 -7830 +v -7831 -7832 -7833 -7834 -7835 -7836 -7837 -7838 -7839 7840 -7841 7842 -7843 +v -7844 -7845 7846 -7847 7848 -7849 -7850 7851 -7852 -7853 -7854 -7855 -7856 +v -7857 7858 7859 7860 7861 -7862 -7863 -7864 -7865 -7866 -7867 -7868 -7869 +v -7870 -7871 -7872 -7873 -7874 -7875 -7876 -7877 -7878 -7879 -7880 -7881 +v -7882 -7883 -7884 -7885 -7886 -7887 -7888 -7889 -7890 -7891 -7892 -7893 +v -7894 -7895 -7896 -7897 -7898 -7899 -7900 -7901 -7902 -7903 -7904 -7905 +v -7906 -7907 -7908 -7909 -7910 -7911 -7912 -7913 -7914 -7915 -7916 -7917 +v -7918 -7919 -7920 -7921 -7922 -7923 -7924 -7925 -7926 -7927 -7928 -7929 +v -7930 -7931 -7932 -7933 -7934 -7935 -7936 -7937 -7938 -7939 -7940 -7941 +v -7942 -7943 -7944 -7945 -7946 -7947 -7948 -7949 -7950 -7951 -7952 -7953 +v -7954 -7955 -7956 -7957 -7958 -7959 -7960 -7961 -7962 -7963 -7964 -7965 +v -7966 -7967 -7968 -7969 -7970 -7971 -7972 -7973 -7974 -7975 -7976 -7977 +v -7978 -7979 -7980 -7981 -7982 -7983 -7984 -7985 -7986 -7987 -7988 -7989 +v -7990 -7991 -7992 -7993 -7994 -7995 -7996 -7997 -7998 -7999 -8000 -8001 +v -8002 -8003 -8004 -8005 -8006 -8007 -8008 -8009 -8010 -8011 -8012 -8013 +v -8014 -8015 -8016 -8017 -8018 -8019 -8020 -8021 -8022 8023 -8024 8025 -8026 +v -8027 -8028 8029 -8030 8031 -8032 -8033 -8034 -8035 8036 -8037 8038 -8039 +v -8040 -8041 -8042 8043 -8044 8045 -8046 -8047 8048 -8049 -8050 -8051 -8052 +v -8053 -8054 -8055 -8056 -8057 -8058 8059 8060 8061 8062 -8063 -8064 -8065 +v -8066 -8067 -8068 -8069 -8070 -8071 -8072 -8073 -8074 -8075 -8076 -8077 +v -8078 -8079 -8080 -8081 -8082 -8083 -8084 -8085 -8086 -8087 -8088 -8089 +v -8090 -8091 -8092 -8093 -8094 -8095 -8096 -8097 -8098 -8099 -8100 -8101 +v -8102 -8103 -8104 -8105 -8106 -8107 -8108 -8109 -8110 -8111 -8112 -8113 +v -8114 -8115 -8116 -8117 -8118 -8119 -8120 -8121 -8122 -8123 -8124 -8125 +v -8126 -8127 -8128 -8129 -8130 -8131 -8132 -8133 -8134 -8135 -8136 -8137 +v -8138 -8139 -8140 -8141 -8142 -8143 -8144 -8145 -8146 -8147 -8148 -8149 +v -8150 -8151 -8152 -8153 -8154 -8155 -8156 -8157 -8158 -8159 -8160 -8161 +v -8162 -8163 -8164 -8165 -8166 -8167 -8168 -8169 -8170 -8171 -8172 -8173 +v -8174 -8175 -8176 -8177 -8178 -8179 -8180 -8181 -8182 -8183 -8184 -8185 +v -8186 -8187 -8188 -8189 -8190 -8191 -8192 -8193 -8194 -8195 -8196 -8197 +v -8198 -8199 -8200 -8201 -8202 -8203 -8204 -8205 -8206 -8207 -8208 -8209 +v -8210 -8211 -8212 -8213 -8214 -8215 -8216 -8217 -8218 -8219 -8220 -8221 +v -8222 -8223 8224 -8225 8226 -8227 -8228 -8229 8230 -8231 8232 -8233 -8234 +v -8235 -8236 8237 -8238 8239 -8240 -8241 -8242 -8243 8244 -8245 8246 -8247 +v -8248 8249 -8250 -8251 -8252 -8253 -8254 -8255 -8256 -8257 -8258 -8259 8260 +v 8261 8262 8263 -8264 -8265 -8266 -8267 -8268 -8269 -8270 -8271 -8272 -8273 +v -8274 -8275 -8276 -8277 -8278 -8279 -8280 -8281 -8282 -8283 -8284 -8285 +v -8286 -8287 -8288 -8289 -8290 -8291 -8292 -8293 -8294 -8295 -8296 -8297 +v -8298 -8299 -8300 -8301 -8302 -8303 -8304 -8305 -8306 -8307 -8308 -8309 +v -8310 -8311 -8312 -8313 -8314 -8315 -8316 -8317 -8318 -8319 -8320 -8321 +v -8322 -8323 -8324 -8325 -8326 -8327 -8328 -8329 -8330 -8331 -8332 -8333 +v -8334 -8335 -8336 -8337 -8338 -8339 -8340 -8341 -8342 -8343 -8344 -8345 +v -8346 -8347 -8348 -8349 -8350 -8351 -8352 -8353 -8354 -8355 -8356 -8357 +v -8358 -8359 -8360 -8361 -8362 -8363 -8364 -8365 -8366 -8367 -8368 -8369 +v -8370 -8371 -8372 -8373 -8374 -8375 -8376 -8377 -8378 -8379 -8380 -8381 +v -8382 -8383 -8384 -8385 -8386 -8387 -8388 -8389 -8390 -8391 -8392 -8393 +v -8394 -8395 -8396 -8397 -8398 -8399 -8400 -8401 -8402 -8403 -8404 -8405 +v -8406 -8407 -8408 -8409 -8410 -8411 -8412 -8413 -8414 -8415 -8416 -8417 +v -8418 -8419 -8420 -8421 -8422 -8423 -8424 8425 -8426 8427 -8428 -8429 -8430 +v 8431 -8432 8433 -8434 -8435 -8436 -8437 8438 -8439 8440 -8441 -8442 -8443 +v -8444 8445 -8446 8447 -8448 -8449 8450 -8451 -8452 -8453 -8454 -8455 -8456 +v -8457 -8458 -8459 -8460 8461 8462 8463 8464 -8465 -8466 -8467 -8468 -8469 +v -8470 -8471 -8472 -8473 -8474 -8475 -8476 -8477 -8478 -8479 -8480 -8481 +v -8482 -8483 -8484 -8485 -8486 -8487 -8488 -8489 -8490 -8491 -8492 -8493 +v -8494 -8495 -8496 -8497 -8498 -8499 -8500 -8501 -8502 -8503 -8504 -8505 +v -8506 -8507 -8508 -8509 -8510 -8511 -8512 -8513 -8514 -8515 -8516 -8517 +v -8518 -8519 -8520 -8521 -8522 -8523 -8524 -8525 -8526 -8527 -8528 -8529 +v -8530 -8531 -8532 -8533 -8534 -8535 -8536 -8537 -8538 -8539 -8540 -8541 +v -8542 -8543 -8544 -8545 -8546 -8547 -8548 -8549 -8550 -8551 -8552 -8553 +v -8554 -8555 -8556 -8557 -8558 -8559 -8560 -8561 -8562 -8563 -8564 -8565 +v -8566 -8567 -8568 -8569 -8570 -8571 -8572 -8573 -8574 -8575 -8576 -8577 +v -8578 -8579 -8580 -8581 -8582 -8583 -8584 -8585 -8586 -8587 -8588 -8589 +v -8590 -8591 -8592 -8593 -8594 -8595 -8596 -8597 -8598 -8599 -8600 -8601 +v -8602 -8603 -8604 -8605 -8606 -8607 -8608 -8609 -8610 -8611 -8612 -8613 +v -8614 -8615 -8616 -8617 -8618 -8619 -8620 -8621 -8622 -8623 -8624 -8625 8626 +v -8627 8628 -8629 -8630 -8631 8632 -8633 8634 -8635 -8636 -8637 -8638 8639 +v -8640 8641 -8642 -8643 -8644 -8645 8646 -8647 8648 -8649 -8650 8651 -8652 +v -8653 -8654 -8655 -8656 -8657 -8658 -8659 -8660 -8661 8662 8663 8664 8665 +v -8666 -8667 -8668 -8669 -8670 -8671 -8672 -8673 -8674 -8675 -8676 -8677 +v -8678 -8679 -8680 -8681 -8682 -8683 -8684 -8685 -8686 -8687 -8688 -8689 +v -8690 -8691 -8692 -8693 -8694 8695 -8696 8697 -8698 -8699 -8700 8701 -8702 +v 8703 -8704 -8705 8706 -8707 -8708 -8709 -8710 -8711 -8712 8713 8714 8715 +v 8716 -8717 8718 -8719 8720 -8721 8722 8723 -8724 -8725 -8726 -8727 -8728 +v -8729 -8730 -8731 -8732 -8733 -8734 -8735 -8736 -8737 -8738 -8739 -8740 +v -8741 -8742 -8743 -8744 -8745 -8746 -8747 -8748 -8749 -8750 -8751 -8752 +v -8753 -8754 -8755 -8756 -8757 -8758 -8759 -8760 -8761 -8762 -8763 -8764 +v -8765 -8766 -8767 -8768 -8769 -8770 -8771 -8772 -8773 -8774 -8775 -8776 +v -8777 -8778 -8779 -8780 -8781 -8782 -8783 -8784 -8785 -8786 -8787 -8788 +v -8789 -8790 -8791 -8792 -8793 -8794 -8795 -8796 -8797 -8798 -8799 -8800 +v -8801 -8802 -8803 -8804 -8805 -8806 -8807 -8808 -8809 -8810 -8811 -8812 +v -8813 -8814 -8815 -8816 -8817 -8818 -8819 -8820 -8821 -8822 -8823 -8824 +v -8825 -8826 -8827 -8828 -8829 -8830 -8831 -8832 -8833 -8834 -8835 -8836 +v -8837 -8838 -8839 -8840 -8841 -8842 -8843 -8844 -8845 -8846 -8847 -8848 +v -8849 -8850 -8851 -8852 -8853 -8854 -8855 -8856 -8857 -8858 -8859 -8860 +v -8861 -8862 -8863 -8864 -8865 -8866 -8867 -8868 -8869 -8870 -8871 -8872 +v -8873 -8874 -8875 -8876 -8877 -8878 -8879 -8880 -8881 -8882 -8883 -8884 +v -8885 -8886 -8887 -8888 -8889 -8890 -8891 -8892 -8893 -8894 -8895 -8896 +v -8897 -8898 -8899 -8900 -8901 -8902 -8903 -8904 -8905 -8906 -8907 -8908 +v -8909 -8910 -8911 -8912 -8913 -8914 -8915 -8916 -8917 -8918 -8919 -8920 +v -8921 -8922 -8923 -8924 -8925 -8926 -8927 -8928 -8929 -8930 -8931 -8932 +v -8933 -8934 -8935 -8936 -8937 -8938 -8939 -8940 -8941 -8942 -8943 -8944 +v -8945 -8946 -8947 -8948 -8949 -8950 -8951 -8952 -8953 -8954 -8955 -8956 +v -8957 -8958 -8959 -8960 -8961 -8962 -8963 -8964 -8965 -8966 -8967 -8968 +v -8969 -8970 -8971 -8972 -8973 -8974 -8975 -8976 -8977 -8978 -8979 -8980 +v -8981 -8982 -8983 -8984 -8985 -8986 -8987 -8988 -8989 -8990 -8991 -8992 +v -8993 -8994 -8995 -8996 -8997 -8998 -8999 -9000 -9001 -9002 -9003 -9004 +v -9005 -9006 -9007 -9008 -9009 -9010 -9011 -9012 -9013 -9014 -9015 -9016 +v -9017 -9018 -9019 -9020 -9021 -9022 -9023 -9024 -9025 -9026 -9027 -9028 +v -9029 -9030 -9031 -9032 -9033 -9034 -9035 -9036 -9037 -9038 -9039 -9040 +v -9041 -9042 -9043 -9044 -9045 -9046 -9047 -9048 -9049 -9050 -9051 -9052 +v -9053 -9054 -9055 -9056 -9057 -9058 -9059 -9060 -9061 -9062 -9063 -9064 +v -9065 -9066 -9067 -9068 -9069 -9070 -9071 -9072 -9073 -9074 -9075 -9076 +v -9077 -9078 -9079 -9080 -9081 -9082 -9083 -9084 -9085 -9086 -9087 -9088 +v -9089 -9090 -9091 -9092 -9093 -9094 -9095 -9096 -9097 -9098 -9099 -9100 +v -9101 -9102 -9103 -9104 -9105 -9106 -9107 -9108 -9109 -9110 -9111 -9112 +v -9113 -9114 -9115 -9116 -9117 -9118 -9119 -9120 -9121 -9122 -9123 -9124 +v -9125 -9126 -9127 9128 -9129 9130 -9131 -9132 -9133 9134 -9135 9136 -9137 +v -9138 -9139 9140 -9141 9142 -9143 -9144 -9145 -9146 9147 -9148 9149 -9150 +v -9151 -9152 -9153 9154 -9155 9156 -9157 -9158 -9159 -9160 9161 -9162 9163 +v -9164 -9165 9166 -9167 -9168 -9169 -9170 -9171 -9172 -9173 -9174 -9175 -9176 +v -9177 -9178 -9179 -9180 9181 9182 9183 9184 9185 -9186 -9187 -9188 -9189 +v -9190 -9191 9192 -9193 -9194 -9195 -9196 -9197 -9198 -9199 -9200 -9201 -9202 +v -9203 -9204 -9205 -9206 -9207 -9208 -9209 -9210 -9211 -9212 -9213 -9214 +v -9215 -9216 -9217 -9218 -9219 -9220 -9221 -9222 -9223 -9224 -9225 -9226 +v -9227 -9228 -9229 -9230 -9231 -9232 -9233 -9234 -9235 -9236 -9237 -9238 +v -9239 -9240 -9241 -9242 -9243 -9244 -9245 -9246 -9247 -9248 -9249 -9250 +v -9251 -9252 -9253 -9254 -9255 -9256 -9257 -9258 -9259 -9260 -9261 -9262 +v -9263 -9264 -9265 -9266 -9267 -9268 -9269 -9270 -9271 -9272 -9273 -9274 +v -9275 -9276 -9277 -9278 -9279 -9280 -9281 -9282 -9283 -9284 -9285 -9286 +v -9287 -9288 -9289 -9290 -9291 -9292 -9293 -9294 -9295 -9296 -9297 -9298 +v -9299 -9300 -9301 -9302 -9303 -9304 -9305 -9306 -9307 -9308 -9309 -9310 +v -9311 -9312 9313 -9314 9315 -9316 -9317 -9318 9319 -9320 9321 -9322 -9323 +v -9324 9325 -9326 9327 -9328 -9329 -9330 9331 -9332 9333 -9334 -9335 9336 +v -9337 -9338 -9339 -9340 -9341 -9342 -9343 -9344 -9345 -9346 9347 9348 9349 +v 9350 -9351 -9352 -9353 -9354 -9355 -9356 -9357 -9358 -9359 -9360 -9361 -9362 +v -9363 -9364 -9365 -9366 -9367 -9368 -9369 -9370 -9371 -9372 -9373 -9374 +v -9375 -9376 -9377 -9378 -9379 -9380 -9381 -9382 -9383 -9384 -9385 -9386 +v -9387 -9388 -9389 -9390 -9391 -9392 -9393 -9394 -9395 -9396 -9397 -9398 +v -9399 -9400 -9401 -9402 -9403 9404 -9405 9406 -9407 -9408 9409 -9410 9411 +v -9412 -9413 -9414 9415 -9416 9417 -9418 -9419 -9420 9421 -9422 9423 -9424 +v -9425 9426 -9427 -9428 -9429 -9430 -9431 -9432 -9433 -9434 -9435 -9436 9437 +v 9438 9439 9440 -9441 -9442 -9443 -9444 -9445 -9446 -9447 -9448 -9449 -9450 +v -9451 -9452 -9453 -9454 -9455 -9456 -9457 -9458 -9459 -9460 -9461 -9462 +v -9463 -9464 -9465 -9466 -9467 -9468 -9469 -9470 -9471 -9472 -9473 -9474 +v -9475 -9476 -9477 -9478 -9479 -9480 -9481 -9482 -9483 -9484 -9485 -9486 +v -9487 -9488 -9489 -9490 -9491 -9492 -9493 -9494 -9495 -9496 -9497 -9498 +v -9499 -9500 -9501 -9502 -9503 -9504 -9505 -9506 -9507 -9508 -9509 -9510 +v -9511 -9512 -9513 -9514 -9515 -9516 -9517 -9518 -9519 -9520 -9521 -9522 +v -9523 -9524 -9525 -9526 -9527 -9528 -9529 -9530 -9531 -9532 -9533 -9534 +v -9535 -9536 -9537 -9538 -9539 -9540 -9541 -9542 -9543 -9544 -9545 -9546 +v -9547 -9548 -9549 -9550 -9551 -9552 -9553 -9554 -9555 -9556 -9557 -9558 +v -9559 -9560 -9561 -9562 -9563 -9564 -9565 -9566 -9567 -9568 -9569 -9570 +v -9571 -9572 -9573 -9574 -9575 -9576 -9577 -9578 -9579 -9580 -9581 -9582 +v -9583 -9584 -9585 -9586 -9587 -9588 -9589 -9590 -9591 -9592 -9593 -9594 +v -9595 -9596 -9597 -9598 -9599 -9600 -9601 -9602 -9603 -9604 -9605 -9606 +v -9607 9608 -9609 9610 -9611 -9612 9613 -9614 9615 -9616 -9617 9618 -9619 +v 9620 -9621 -9622 -9623 9624 -9625 9626 -9627 -9628 -9629 9630 -9631 9632 +v -9633 -9634 9635 -9636 -9637 -9638 -9639 -9640 -9641 -9642 -9643 -9644 -9645 +v -9646 9647 9648 9649 -9650 -9651 -9652 -9653 -9654 -9655 -9656 -9657 -9658 +v -9659 -9660 -9661 -9662 9663 -9664 -9665 9666 -9667 -9668 -9669 -9670 -9671 +v -9672 9673 9674 9675 -9676 -9677 -9678 -9679 -9680 9681 -9682 -9683 -9684 +v -9685 -9686 -9687 -9688 9689 9690 9691 9692 9693 9694 9695 -9696 -9697 9698 +v -9699 9700 -9701 -9702 -9703 -9704 -9705 -9706 -9707 9708 9709 -9710 9711 +v 9712 -9713 -9714 -9715 -9716 9717 -9718 -9719 9720 -9721 -9722 -9723 9724 +v -9725 -9726 -9727 -9728 -9729 9730 -9731 -9732 -9733 -9734 -9735 -9736 -9737 +v 9738 9739 9740 9741 9742 9743 9744 -9745 -9746 -9747 9748 -9749 9750 9751 +v 9752 9753 -9754 -9755 9756 -9757 9758 9759 9760 -9761 -9762 9763 -9764 -9765 +v 9766 -9767 -9768 -9769 -9770 -9771 -9772 -9773 -9774 9775 9776 9777 -9778 +v -9779 -9780 -9781 -9782 -9783 -9784 -9785 -9786 -9787 -9788 -9789 -9790 +v -9791 -9792 -9793 -9794 -9795 -9796 -9797 -9798 -9799 9800 -9801 -9802 -9803 +v -9804 -9805 -9806 -9807 9808 -9809 9810 -9811 -9812 -9813 9814 -9815 9816 +v -9817 -9818 9819 -9820 -9821 -9822 -9823 -9824 -9825 9826 9827 9828 -9829 +v -9830 -9831 -9832 -9833 -9834 -9835 -9836 -9837 -9838 -9839 -9840 -9841 +v -9842 -9843 -9844 -9845 -9846 -9847 -9848 -9849 -9850 9851 -9852 -9853 -9854 +v -9855 -9856 -9857 -9858 9859 -9860 9861 -9862 -9863 -9864 9865 -9866 9867 +v -9868 -9869 9870 -9871 -9872 -9873 -9874 -9875 -9876 9877 9878 9879 -9880 +v -9881 -9882 -9883 -9884 -9885 -9886 -9887 -9888 -9889 -9890 -9891 -9892 +v -9893 -9894 -9895 -9896 -9897 -9898 -9899 -9900 -9901 9902 -9903 -9904 -9905 +v -9906 -9907 -9908 -9909 9910 -9911 9912 -9913 -9914 -9915 9916 -9917 9918 +v -9919 -9920 9921 -9922 -9923 -9924 -9925 -9926 -9927 9928 9929 9930 -9931 +v -9932 -9933 -9934 -9935 -9936 -9937 -9938 -9939 -9940 -9941 -9942 -9943 +v -9944 -9945 -9946 -9947 -9948 -9949 -9950 -9951 -9952 -9953 -9954 -9955 +v -9956 -9957 -9958 -9959 -9960 -9961 -9962 -9963 -9964 -9965 -9966 -9967 +v -9968 -9969 -9970 -9971 -9972 -9973 -9974 -9975 -9976 -9977 -9978 -9979 +v -9980 -9981 -9982 -9983 -9984 -9985 -9986 -9987 -9988 -9989 -9990 -9991 +v -9992 -9993 -9994 -9995 -9996 -9997 -9998 -9999 -10000 -10001 -10002 -10003 +v -10004 -10005 -10006 -10007 -10008 -10009 -10010 -10011 -10012 -10013 -10014 +v -10015 -10016 -10017 -10018 -10019 -10020 -10021 -10022 -10023 10024 -10025 +v -10026 -10027 -10028 -10029 -10030 -10031 -10032 -10033 -10034 -10035 -10036 +v -10037 -10038 -10039 -10040 -10041 -10042 -10043 -10044 -10045 -10046 -10047 +v -10048 -10049 -10050 -10051 -10052 -10053 -10054 -10055 -10056 -10057 -10058 +v -10059 -10060 -10061 -10062 -10063 -10064 -10065 -10066 -10067 -10068 -10069 +v -10070 -10071 -10072 -10073 -10074 -10075 -10076 -10077 -10078 -10079 -10080 +v -10081 -10082 -10083 -10084 -10085 -10086 -10087 -10088 -10089 -10090 -10091 +v -10092 10093 -10094 10095 -10096 -10097 -10098 10099 -10100 10101 -10102 +v -10103 -10104 -10105 10106 -10107 10108 -10109 -10110 -10111 -10112 10113 +v -10114 10115 -10116 -10117 10118 -10119 -10120 -10121 -10122 -10123 -10124 +v -10125 -10126 -10127 -10128 10129 10130 10131 -10132 -10133 -10134 -10135 +v -10136 -10137 -10138 -10139 -10140 -10141 -10142 -10143 -10144 -10145 -10146 +v -10147 -10148 -10149 -10150 -10151 -10152 -10153 -10154 -10155 -10156 -10157 +v -10158 -10159 -10160 -10161 -10162 -10163 -10164 -10165 -10166 -10167 -10168 +v -10169 -10170 -10171 -10172 -10173 -10174 -10175 -10176 -10177 -10178 -10179 +v -10180 -10181 -10182 -10183 -10184 -10185 -10186 -10187 -10188 -10189 -10190 +v -10191 -10192 -10193 -10194 -10195 -10196 -10197 -10198 -10199 -10200 -10201 +v -10202 -10203 -10204 -10205 -10206 -10207 -10208 -10209 -10210 -10211 -10212 +v -10213 -10214 -10215 -10216 -10217 -10218 -10219 -10220 -10221 -10222 -10223 +v -10224 10225 -10226 -10227 -10228 -10229 -10230 -10231 -10232 -10233 -10234 +v -10235 -10236 -10237 -10238 -10239 -10240 -10241 -10242 -10243 -10244 -10245 +v -10246 -10247 -10248 -10249 -10250 -10251 -10252 -10253 -10254 -10255 -10256 +v -10257 -10258 -10259 -10260 -10261 -10262 -10263 -10264 -10265 -10266 -10267 +v -10268 -10269 -10270 -10271 -10272 -10273 -10274 -10275 -10276 -10277 -10278 +v -10279 -10280 -10281 -10282 -10283 -10284 -10285 -10286 -10287 -10288 -10289 +v -10290 -10291 -10292 -10293 10294 -10295 10296 -10297 -10298 -10299 10300 +v -10301 10302 -10303 -10304 -10305 -10306 10307 -10308 10309 -10310 -10311 +v -10312 -10313 10314 -10315 10316 -10317 -10318 10319 -10320 -10321 -10322 +v -10323 -10324 -10325 -10326 -10327 -10328 -10329 10330 10331 10332 -10333 +v -10334 -10335 -10336 -10337 -10338 -10339 -10340 -10341 -10342 -10343 -10344 +v -10345 -10346 -10347 -10348 -10349 -10350 -10351 -10352 -10353 -10354 -10355 +v -10356 -10357 -10358 -10359 -10360 -10361 -10362 -10363 -10364 -10365 -10366 +v -10367 -10368 -10369 -10370 -10371 -10372 -10373 -10374 -10375 -10376 -10377 +v -10378 -10379 -10380 -10381 -10382 -10383 -10384 -10385 -10386 -10387 -10388 +v -10389 -10390 -10391 -10392 -10393 -10394 -10395 -10396 -10397 -10398 -10399 +v -10400 -10401 -10402 -10403 -10404 -10405 -10406 -10407 -10408 -10409 -10410 +v -10411 -10412 -10413 -10414 -10415 -10416 -10417 -10418 -10419 -10420 -10421 +v -10422 -10423 -10424 -10425 10426 -10427 -10428 -10429 -10430 -10431 -10432 +v -10433 -10434 -10435 -10436 -10437 -10438 -10439 -10440 -10441 -10442 -10443 +v -10444 -10445 -10446 -10447 -10448 -10449 -10450 -10451 -10452 -10453 -10454 +v -10455 -10456 -10457 -10458 -10459 -10460 -10461 -10462 -10463 -10464 -10465 +v -10466 -10467 -10468 -10469 -10470 -10471 -10472 -10473 -10474 -10475 -10476 +v -10477 -10478 -10479 -10480 -10481 -10482 -10483 -10484 -10485 -10486 -10487 +v -10488 -10489 -10490 -10491 -10492 -10493 -10494 10495 -10496 10497 -10498 +v -10499 -10500 10501 -10502 10503 -10504 -10505 -10506 -10507 10508 -10509 +v 10510 -10511 -10512 -10513 -10514 10515 -10516 10517 -10518 -10519 10520 +v -10521 -10522 -10523 -10524 -10525 -10526 -10527 -10528 -10529 -10530 10531 +v 10532 10533 -10534 -10535 -10536 -10537 -10538 -10539 -10540 -10541 -10542 +v -10543 -10544 -10545 -10546 -10547 -10548 -10549 -10550 -10551 -10552 -10553 +v -10554 -10555 -10556 -10557 -10558 -10559 -10560 -10561 -10562 -10563 -10564 +v -10565 -10566 -10567 -10568 -10569 -10570 -10571 -10572 -10573 -10574 -10575 +v -10576 -10577 -10578 -10579 -10580 -10581 -10582 -10583 -10584 -10585 -10586 +v -10587 -10588 -10589 -10590 -10591 -10592 -10593 -10594 -10595 -10596 -10597 +v -10598 -10599 -10600 -10601 -10602 -10603 -10604 -10605 -10606 -10607 -10608 +v -10609 -10610 -10611 -10612 -10613 -10614 -10615 -10616 -10617 -10618 -10619 +v -10620 -10621 -10622 -10623 -10624 -10625 -10626 10627 -10628 -10629 -10630 +v -10631 -10632 -10633 -10634 -10635 -10636 -10637 -10638 -10639 -10640 -10641 +v -10642 -10643 -10644 -10645 -10646 -10647 -10648 -10649 -10650 -10651 -10652 +v -10653 -10654 -10655 -10656 -10657 -10658 -10659 -10660 -10661 -10662 -10663 +v -10664 -10665 -10666 -10667 -10668 -10669 -10670 -10671 -10672 -10673 -10674 +v -10675 -10676 -10677 -10678 -10679 -10680 -10681 -10682 -10683 -10684 -10685 +v -10686 -10687 -10688 -10689 -10690 -10691 -10692 -10693 -10694 -10695 10696 +v -10697 10698 -10699 -10700 -10701 10702 -10703 10704 -10705 -10706 -10707 +v -10708 10709 -10710 10711 -10712 -10713 -10714 -10715 10716 -10717 10718 +v -10719 -10720 10721 -10722 -10723 -10724 -10725 -10726 -10727 -10728 -10729 +v -10730 -10731 10732 10733 10734 -10735 -10736 -10737 -10738 -10739 -10740 +v -10741 -10742 -10743 -10744 -10745 -10746 -10747 -10748 -10749 -10750 -10751 +v -10752 -10753 -10754 -10755 -10756 10757 -10758 -10759 -10760 -10761 -10762 +v -10763 -10764 10765 -10766 10767 -10768 -10769 -10770 10771 -10772 10773 +v -10774 -10775 10776 -10777 -10778 -10779 -10780 -10781 -10782 10783 10784 +v 10785 10786 10787 10788 10789 10790 -10791 -10792 10793 10794 10795 10796 +v 10797 -10798 -10799 10800 -10801 10802 -10803 10804 -10805 10806 -10807 +v -10808 10809 -10810 -10811 -10812 -10813 -10814 -10815 10816 10817 10818 +v 10819 -10820 -10821 -10822 -10823 10824 -10825 10826 -10827 10828 -10829 +v 10830 10831 10832 10833 -10834 -10835 10836 10837 10838 -10839 -10840 -10841 +v -10842 -10843 -10844 -10845 10846 10847 10848 10849 10850 -10851 -10852 +v 10853 10854 10855 10856 10857 -10858 -10859 10860 -10861 10862 -10863 10864 +v -10865 10866 -10867 -10868 10869 -10870 -10871 -10872 -10873 -10874 -10875 +v 10876 10877 10878 10879 -10880 -10881 -10882 -10883 -10884 -10885 10886 +v 10887 10888 10889 10890 10891 -10892 10893 10894 -10895 -10896 -10897 -10898 +v -10899 -10900 -10901 -10902 -10903 10904 -10905 -10906 -10907 10908 10909 +v 10910 10911 -10912 -10913 -10914 10915 -10916 10917 -10918 -10919 -10920 +v -10921 -10922 10923 10924 10925 -10926 10927 10928 -10929 -10930 10931 +v -10932 -10933 10934 -10935 -10936 -10937 -10938 10939 -10940 10941 10942 +v 10943 10944 -10945 -10946 10947 10948 10949 10950 -10951 -10952 10953 -10954 +v -10955 10956 -10957 -10958 -10959 -10960 -10961 -10962 -10963 -10964 10965 +v 10966 10967 -10968 -10969 10970 -10971 -10972 10973 -10974 -10975 -10976 +v -10977 -10978 -10979 -10980 10981 10982 -10983 -10984 -10985 -10986 -10987 +v -10988 -10989 -10990 -10991 10992 -10993 -10994 10995 -10996 -10997 -10998 +v -10999 -11000 -11001 -11002 11003 11004 11005 11006 11007 11008 11009 -11010 +v -11011 11012 11013 11014 -11015 -11016 11017 11018 11019 -11020 -11021 +v -11022 -11023 -11024 11025 11026 11027 -11028 -11029 11030 11031 -11032 +v -11033 11034 -11035 -11036 11037 11038 11039 11040 -11041 -11042 -11043 +v -11044 11045 11046 11047 11048 -11049 -11050 -11051 -11052 11053 11054 11055 +v 11056 -11057 -11058 -11059 -11060 -11061 -11062 -11063 -11064 -11065 -11066 +v -11067 -11068 -11069 -11070 -11071 -11072 -11073 -11074 11075 -11076 11077 +v -11078 -11079 -11080 11081 -11082 11083 -11084 -11085 11086 -11087 -11088 +v -11089 -11090 -11091 -11092 11093 11094 11095 11096 -11097 -11098 -11099 +v -11100 -11101 -11102 -11103 -11104 -11105 -11106 -11107 -11108 -11109 -11110 +v -11111 -11112 11113 -11114 11115 -11116 -11117 -11118 11119 -11120 11121 +v -11122 -11123 11124 -11125 -11126 -11127 -11128 -11129 -11130 11131 11132 +v 11133 11134 -11135 -11136 11137 11138 11139 11140 -11141 -11142 -11143 +v -11144 11145 11146 11147 11148 -11149 -11150 -11151 -11152 -11153 -11154 +v -11155 -11156 -11157 -11158 -11159 -11160 -11161 -11162 -11163 -11164 -11165 +v -11166 -11167 -11168 -11169 11170 -11171 11172 -11173 -11174 -11175 -11176 +v 11177 -11178 11179 -11180 -11181 11182 -11183 -11184 -11185 -11186 -11187 +v -11188 11189 11190 11191 11192 11193 11194 -11195 -11196 -11197 -11198 +v -11199 -11200 -11201 -11202 -11203 -11204 -11205 -11206 -11207 -11208 -11209 +v -11210 -11211 -11212 -11213 -11214 -11215 11216 -11217 11218 -11219 -11220 +v -11221 -11222 11223 -11224 11225 -11226 -11227 11228 -11229 -11230 -11231 +v -11232 -11233 -11234 11235 11236 11237 11238 -11239 -11240 11241 -11242 +v 11243 -11244 11245 -11246 -11247 -11248 11249 11250 11251 11252 11253 -11254 +v -11255 11256 11257 -11258 -11259 11260 11261 -11262 -11263 -11264 -11265 +v -11266 11267 11268 11269 11270 -11271 -11272 11273 11274 -11275 -11276 11277 +v 11278 -11279 -11280 11281 11282 -11283 11284 -11285 11286 -11287 -11288 +v -11289 -11290 -11291 -11292 11293 11294 -11295 11296 -11297 11298 -11299 +v -11300 -11301 -11302 -11303 -11304 11305 11306 -11307 -11308 11309 11310 +v -11311 -11312 11313 11314 -11315 11316 -11317 11318 -11319 -11320 -11321 +v -11322 -11323 -11324 11325 -11326 -11327 11328 -11329 11330 -11331 11332 +v -11333 -11334 -11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 +v 11345 -11346 -11347 11348 11349 -11350 -11351 11352 11353 -11354 -11355 +v -11356 -11357 -11358 11359 11360 11361 -11362 -11363 11364 -11365 -11366 +v 11367 11368 11369 -11370 -11371 11372 -11373 11374 -11375 -11376 11377 11378 +v 11379 -11380 -11381 -11382 11383 -11384 11385 11386 11387 -11388 -11389 +v 11390 11391 11392 -11393 -11394 -11395 -11396 -11397 -11398 11399 11400 +v 11401 11402 -11403 -11404 -11405 -11406 -11407 -11408 -11409 -11410 -11411 +v -11412 -11413 -11414 -11415 -11416 -11417 -11418 -11419 -11420 -11421 -11422 +v -11423 -11424 -11425 -11426 -11427 -11428 -11429 -11430 -11431 -11432 -11433 +v 11434 -11435 11436 -11437 -11438 -11439 11440 -11441 11442 -11443 -11444 +v 11445 -11446 -11447 -11448 -11449 -11450 -11451 11452 11453 11454 11455 +v -11456 -11457 -11458 -11459 -11460 -11461 -11462 -11463 -11464 -11465 -11466 +v -11467 -11468 -11469 -11470 -11471 -11472 -11473 -11474 -11475 -11476 -11477 +v -11478 -11479 -11480 -11481 -11482 -11483 -11484 -11485 -11486 11487 -11488 +v 11489 -11490 -11491 -11492 11493 -11494 11495 -11496 -11497 11498 -11499 +v -11500 -11501 -11502 -11503 -11504 11505 11506 11507 11508 -11509 -11510 +v -11511 -11512 -11513 -11514 -11515 -11516 -11517 -11518 -11519 -11520 -11521 +v -11522 -11523 -11524 -11525 -11526 -11527 -11528 -11529 -11530 -11531 -11532 +v -11533 -11534 -11535 -11536 -11537 -11538 -11539 11540 -11541 11542 -11543 +v -11544 -11545 11546 -11547 11548 -11549 -11550 11551 -11552 -11553 -11554 +v -11555 -11556 -11557 11558 11559 11560 11561 11562 -11563 -11564 -11565 +v -11566 -11567 -11568 -11569 -11570 -11571 -11572 -11573 -11574 -11575 -11576 +v -11577 -11578 -11579 -11580 -11581 -11582 -11583 -11584 -11585 -11586 -11587 +v -11588 -11589 -11590 -11591 -11592 -11593 -11594 -11595 -11596 -11597 -11598 +v -11599 -11600 -11601 -11602 -11603 -11604 -11605 -11606 -11607 -11608 -11609 +v -11610 -11611 -11612 -11613 -11614 -11615 -11616 -11617 -11618 -11619 -11620 +v -11621 -11622 -11623 -11624 -11625 -11626 -11627 -11628 -11629 -11630 -11631 +v -11632 -11633 -11634 -11635 -11636 -11637 -11638 -11639 -11640 -11641 -11642 +v -11643 -11644 -11645 -11646 -11647 -11648 -11649 -11650 -11651 -11652 -11653 +v -11654 -11655 -11656 -11657 -11658 -11659 -11660 -11661 -11662 -11663 -11664 +v -11665 -11666 -11667 -11668 -11669 -11670 -11671 -11672 -11673 -11674 -11675 +v -11676 -11677 -11678 -11679 -11680 -11681 -11682 -11683 -11684 -11685 -11686 +v -11687 -11688 -11689 -11690 -11691 -11692 -11693 -11694 -11695 -11696 -11697 +v -11698 -11699 -11700 -11701 -11702 -11703 -11704 -11705 -11706 -11707 -11708 +v -11709 -11710 -11711 -11712 -11713 -11714 -11715 -11716 -11717 -11718 -11719 +v -11720 -11721 -11722 -11723 -11724 -11725 -11726 -11727 -11728 -11729 -11730 +v -11731 -11732 -11733 -11734 -11735 -11736 -11737 -11738 -11739 -11740 -11741 +v -11742 -11743 -11744 11745 -11746 11747 -11748 -11749 -11750 11751 -11752 +v 11753 -11754 -11755 -11756 -11757 11758 -11759 11760 -11761 -11762 -11763 +v -11764 11765 -11766 11767 -11768 -11769 11770 -11771 -11772 -11773 -11774 +v -11775 -11776 -11777 -11778 -11779 -11780 11781 11782 11783 11784 -11785 +v -11786 -11787 -11788 -11789 -11790 -11791 -11792 -11793 -11794 -11795 -11796 +v -11797 -11798 -11799 -11800 -11801 -11802 -11803 -11804 -11805 -11806 -11807 +v -11808 -11809 -11810 -11811 -11812 -11813 -11814 -11815 11816 -11817 11818 +v -11819 -11820 -11821 11822 -11823 11824 -11825 -11826 11827 -11828 -11829 +v -11830 -11831 -11832 -11833 11834 11835 11836 11837 -11838 11839 -11840 +v 11841 -11842 11843 11844 11845 -11846 -11847 -11848 -11849 -11850 -11851 +v -11852 -11853 -11854 -11855 -11856 -11857 -11858 -11859 -11860 -11861 -11862 +v -11863 -11864 -11865 -11866 -11867 -11868 -11869 -11870 -11871 -11872 -11873 +v -11874 -11875 -11876 -11877 -11878 -11879 -11880 -11881 -11882 -11883 -11884 +v -11885 -11886 -11887 -11888 -11889 -11890 -11891 -11892 -11893 -11894 -11895 +v -11896 -11897 -11898 -11899 -11900 -11901 -11902 -11903 -11904 -11905 -11906 +v -11907 -11908 -11909 -11910 -11911 -11912 -11913 -11914 -11915 -11916 -11917 +v -11918 -11919 -11920 -11921 -11922 -11923 -11924 -11925 -11926 -11927 -11928 +v -11929 -11930 -11931 -11932 -11933 -11934 -11935 -11936 -11937 -11938 -11939 +v -11940 -11941 -11942 -11943 -11944 -11945 -11946 -11947 -11948 -11949 -11950 +v -11951 -11952 -11953 -11954 -11955 -11956 -11957 -11958 -11959 -11960 -11961 +v -11962 -11963 -11964 -11965 -11966 -11967 -11968 -11969 -11970 -11971 -11972 +v -11973 -11974 -11975 -11976 -11977 -11978 -11979 -11980 -11981 -11982 -11983 +v -11984 -11985 -11986 -11987 -11988 -11989 -11990 -11991 -11992 -11993 -11994 +v -11995 -11996 -11997 -11998 -11999 -12000 -12001 -12002 -12003 -12004 -12005 +v -12006 12007 -12008 -12009 -12010 -12011 -12012 -12013 -12014 -12015 -12016 +v -12017 -12018 -12019 -12020 -12021 -12022 -12023 -12024 -12025 -12026 -12027 +v -12028 -12029 -12030 -12031 -12032 -12033 -12034 -12035 -12036 -12037 -12038 +v -12039 -12040 -12041 -12042 -12043 -12044 -12045 -12046 -12047 -12048 -12049 +v -12050 -12051 -12052 -12053 -12054 -12055 -12056 -12057 -12058 -12059 -12060 +v -12061 -12062 -12063 -12064 -12065 -12066 -12067 -12068 -12069 -12070 -12071 +v -12072 -12073 -12074 -12075 -12076 -12077 -12078 -12079 -12080 -12081 -12082 +v -12083 -12084 -12085 -12086 -12087 -12088 -12089 -12090 -12091 -12092 -12093 +v -12094 -12095 -12096 -12097 -12098 -12099 -12100 -12101 -12102 -12103 -12104 +v -12105 -12106 -12107 -12108 -12109 -12110 -12111 -12112 -12113 -12114 -12115 +v -12116 -12117 -12118 -12119 -12120 -12121 -12122 -12123 -12124 -12125 -12126 +v -12127 -12128 -12129 -12130 -12131 -12132 -12133 -12134 -12135 -12136 -12137 +v -12138 -12139 -12140 -12141 -12142 -12143 -12144 -12145 -12146 -12147 -12148 +v -12149 -12150 -12151 -12152 -12153 -12154 -12155 -12156 -12157 -12158 -12159 +v -12160 -12161 -12162 -12163 -12164 -12165 -12166 -12167 -12168 -12169 -12170 +v -12171 -12172 -12173 -12174 -12175 -12176 -12177 -12178 -12179 -12180 -12181 +v -12182 -12183 -12184 -12185 -12186 -12187 -12188 -12189 -12190 -12191 -12192 +v -12193 -12194 -12195 -12196 -12197 -12198 -12199 -12200 -12201 -12202 -12203 +v -12204 -12205 -12206 -12207 -12208 -12209 -12210 -12211 -12212 -12213 -12214 +v -12215 -12216 -12217 -12218 -12219 -12220 -12221 -12222 -12223 -12224 -12225 +v -12226 -12227 -12228 -12229 -12230 -12231 -12232 -12233 -12234 -12235 -12236 +v -12237 -12238 -12239 -12240 -12241 -12242 -12243 -12244 -12245 -12246 -12247 +v -12248 -12249 -12250 -12251 -12252 -12253 -12254 -12255 -12256 -12257 -12258 +v -12259 -12260 -12261 -12262 -12263 -12264 -12265 -12266 12267 -12268 12269 +v -12270 -12271 12272 -12273 12274 -12275 -12276 -12277 12278 -12279 12280 +v -12281 -12282 -12283 12284 -12285 12286 -12287 -12288 -12289 12290 -12291 +v 12292 -12293 -12294 12295 -12296 12297 -12298 -12299 -12300 -12301 -12302 +v -12303 -12304 -12305 -12306 -12307 -12308 -12309 -12310 -12311 12312 12313 +v 12314 12315 12316 -12317 -12318 -12319 -12320 -12321 -12322 12323 -12324 +v -12325 -12326 -12327 -12328 -12329 -12330 -12331 -12332 -12333 -12334 -12335 +v -12336 -12337 -12338 -12339 -12340 -12341 -12342 -12343 -12344 -12345 -12346 +v -12347 -12348 -12349 -12350 -12351 -12352 -12353 -12354 -12355 -12356 -12357 +v -12358 -12359 -12360 -12361 -12362 -12363 -12364 -12365 -12366 -12367 -12368 +v -12369 -12370 -12371 -12372 -12373 -12374 -12375 -12376 -12377 -12378 -12379 +v -12380 -12381 -12382 -12383 -12384 -12385 -12386 -12387 -12388 -12389 -12390 +v -12391 -12392 -12393 -12394 -12395 -12396 -12397 -12398 -12399 -12400 -12401 +v -12402 -12403 -12404 -12405 -12406 -12407 -12408 -12409 -12410 -12411 -12412 +v -12413 -12414 -12415 -12416 -12417 -12418 -12419 -12420 -12421 -12422 -12423 +v -12424 -12425 -12426 -12427 -12428 -12429 -12430 -12431 -12432 -12433 -12434 +v -12435 -12436 -12437 -12438 -12439 -12440 -12441 -12442 -12443 -12444 -12445 +v 12446 -12447 12448 -12449 -12450 -12451 -12452 12453 -12454 12455 -12456 +v -12457 -12458 -12459 12460 -12461 12462 -12463 -12464 -12465 -12466 12467 +v -12468 12469 -12470 -12471 12472 -12473 12474 -12475 -12476 12477 -12478 +v -12479 -12480 -12481 -12482 -12483 -12484 -12485 -12486 -12487 -12488 -12489 +v 12490 12491 12492 12493 -12494 -12495 -12496 -12497 -12498 -12499 -12500 +v -12501 -12502 -12503 -12504 -12505 -12506 -12507 -12508 -12509 -12510 -12511 +v -12512 -12513 -12514 -12515 -12516 -12517 -12518 -12519 -12520 -12521 -12522 +v -12523 -12524 -12525 -12526 -12527 -12528 -12529 -12530 -12531 -12532 -12533 +v -12534 -12535 -12536 -12537 -12538 -12539 -12540 -12541 -12542 -12543 -12544 +v 12545 -12546 -12547 12548 -12549 -12550 -12551 12552 -12553 -12554 -12555 +v 12556 -12557 -12558 -12559 -12560 -12561 -12562 -12563 -12564 -12565 -12566 +v -12567 12568 -12569 12570 12571 12572 12573 12574 -12575 -12576 -12577 +v -12578 -12579 -12580 -12581 -12582 -12583 -12584 -12585 -12586 -12587 -12588 +v -12589 -12590 -12591 -12592 -12593 -12594 -12595 -12596 -12597 -12598 -12599 +v -12600 -12601 -12602 -12603 -12604 -12605 -12606 -12607 -12608 -12609 -12610 +v -12611 -12612 -12613 -12614 -12615 -12616 -12617 -12618 -12619 -12620 -12621 +v -12622 -12623 -12624 -12625 -12626 -12627 -12628 -12629 -12630 -12631 -12632 +v -12633 -12634 -12635 -12636 -12637 -12638 -12639 -12640 -12641 -12642 -12643 +v -12644 -12645 -12646 -12647 -12648 -12649 -12650 -12651 -12652 -12653 -12654 +v -12655 -12656 -12657 -12658 -12659 -12660 -12661 -12662 -12663 -12664 -12665 +v -12666 -12667 -12668 -12669 -12670 -12671 -12672 -12673 -12674 -12675 -12676 +v -12677 -12678 -12679 -12680 -12681 -12682 -12683 -12684 -12685 -12686 -12687 +v -12688 -12689 -12690 -12691 -12692 -12693 -12694 -12695 -12696 -12697 -12698 +v -12699 -12700 -12701 -12702 -12703 -12704 12705 -12706 -12707 -12708 -12709 +v -12710 -12711 -12712 -12713 -12714 -12715 -12716 -12717 -12718 -12719 -12720 +v -12721 -12722 -12723 -12724 -12725 -12726 -12727 -12728 -12729 -12730 -12731 +v -12732 -12733 -12734 -12735 -12736 -12737 -12738 -12739 -12740 -12741 -12742 +v -12743 -12744 -12745 -12746 -12747 -12748 -12749 -12750 -12751 -12752 12753 +v -12754 12755 -12756 -12757 -12758 12759 -12760 12761 -12762 -12763 -12764 +v 12765 -12766 12767 -12768 -12769 -12770 12771 -12772 12773 -12774 -12775 +v 12776 -12777 -12778 -12779 -12780 -12781 -12782 -12783 -12784 -12785 -12786 +v -12787 12788 12789 12790 12791 -12792 -12793 -12794 -12795 -12796 -12797 +v -12798 -12799 -12800 -12801 -12802 -12803 -12804 12805 -12806 -12807 12808 +v -12809 -12810 -12811 -12812 -12813 -12814 12815 12816 12817 -12818 -12819 +v -12820 -12821 -12822 12823 12824 12825 12826 12827 12828 12829 12830 12831 +v 12832 -12833 -12834 -12835 -12836 -12837 -12838 -12839 -12840 12841 -12842 +v 12843 12844 -12845 -12846 -12847 12848 -12849 -12850 -12851 -12852 -12853 +v -12854 -12855 -12856 12857 12858 12859 -12860 -12861 -12862 12863 12864 +v 12865 12866 12867 12868 12869 12870 -12871 -12872 12873 -12874 -12875 -12876 +v -12877 12878 12879 -12880 12881 12882 -12883 -12884 -12885 -12886 -12887 +v -12888 -12889 -12890 12891 12892 12893 -12894 12895 12896 12897 12898 12899 +v 12900 12901 12902 12903 12904 -12905 -12906 12907 -12908 -12909 -12910 +v -12911 12912 -12913 -12914 -12915 -12916 -12917 -12918 -12919 -12920 12921 +v 12922 12923 12924 12925 12926 12927 -12928 -12929 12930 12931 -12932 12933 +v -12934 -12935 12936 -12937 -12938 -12939 -12940 -12941 -12942 12943 12944 +v 12945 12946 12947 12948 12949 12950 12951 -12952 12953 12954 -12955 12956 +v 12957 -12958 12959 12960 12961 12962 12963 12964 12965 12966 12967 12968 +v 12969 12970 12971 12972 12973 12974 -12975 -12976 12977 -12978 12979 -12980 +v 12981 -12982 12983 12984 -12985 12986 -12987 12988 -12989 12990 12991 -12992 +v 12993 -12994 12995 -12996 12997 -12998 -12999 13000 -13001 -13002 -13003 +v -13004 -13005 -13006 -13007 -13008 -13009 -13010 13011 13012 13013 13014 +v -13015 -13016 -13017 -13018 -13019 -13020 -13021 -13022 -13023 -13024 -13025 +v -13026 -13027 -13028 13029 -13030 -13031 13032 -13033 -13034 -13035 -13036 +v -13037 13038 13039 -13040 -13041 -13042 -13043 13044 13045 -13046 -13047 +v -13048 -13049 13050 -13051 -13052 -13053 -13054 -13055 -13056 -13057 -13058 +v 13059 13060 13061 -13062 -13063 13064 -13065 -13066 -13067 -13068 -13069 +v 13070 -13071 -13072 -13073 -13074 -13075 -13076 -13077 -13078 -13079 -13080 +v -13081 -13082 -13083 -13084 -13085 -13086 -13087 -13088 -13089 -13090 -13091 +v -13092 -13093 -13094 -13095 -13096 -13097 -13098 -13099 -13100 -13101 -13102 +v -13103 -13104 -13105 -13106 -13107 -13108 -13109 -13110 -13111 -13112 -13113 +v -13114 -13115 -13116 -13117 -13118 -13119 -13120 -13121 -13122 13123 13124 +v -13125 13126 -13127 -13128 -13129 -13130 13131 -13132 -13133 -13134 -13135 +v -13136 13137 -13138 -13139 -13140 -13141 -13142 -13143 -13144 -13145 -13146 +v -13147 -13148 -13149 -13150 -13151 -13152 -13153 -13154 -13155 13156 13157 +v 13158 -13159 -13160 13161 13162 -13163 13164 -13165 -13166 -13167 13168 +v -13169 -13170 -13171 -13172 -13173 -13174 -13175 -13176 -13177 -13178 -13179 +v -13180 -13181 -13182 -13183 -13184 -13185 -13186 -13187 -13188 -13189 -13190 +v -13191 -13192 -13193 -13194 -13195 -13196 -13197 -13198 -13199 -13200 -13201 +v -13202 -13203 -13204 -13205 -13206 -13207 -13208 -13209 -13210 -13211 -13212 +v -13213 -13214 -13215 -13216 -13217 -13218 -13219 -13220 -13221 -13222 -13223 +v -13224 13225 13226 13227 -13228 13229 13230 13231 -13232 13233 -13234 -13235 +v 13236 -13237 -13238 13239 -13240 -13241 -13242 -13243 -13244 -13245 -13246 +v -13247 -13248 -13249 -13250 -13251 -13252 -13253 -13254 -13255 -13256 13257 +v 13258 13259 13260 -13261 13262 -13263 -13264 -13265 -13266 -13267 -13268 +v -13269 -13270 -13271 -13272 -13273 -13274 -13275 -13276 -13277 -13278 -13279 +v -13280 -13281 -13282 -13283 -13284 -13285 -13286 13287 -13288 -13289 -13290 +v -13291 -13292 -13293 -13294 -13295 -13296 13297 13298 -13299 -13300 -13301 +v -13302 -13303 -13304 -13305 -13306 -13307 -13308 -13309 -13310 -13311 -13312 +v -13313 -13314 -13315 -13316 -13317 -13318 -13319 -13320 -13321 13322 13323 +v -13324 -13325 -13326 13327 -13328 -13329 -13330 -13331 -13332 -13333 -13334 +v -13335 -13336 -13337 -13338 -13339 -13340 -13341 13342 13343 13344 13345 +v 13346 -13347 -13348 13349 13350 13351 -13352 -13353 -13354 -13355 -13356 +v -13357 -13358 -13359 -13360 -13361 -13362 -13363 -13364 -13365 -13366 -13367 +v -13368 -13369 -13370 -13371 13372 13373 -13374 -13375 -13376 -13377 -13378 +v 13379 -13380 -13381 -13382 -13383 -13384 13385 -13386 -13387 -13388 -13389 +v -13390 -13391 -13392 -13393 -13394 13395 13396 -13397 -13398 13399 -13400 +v -13401 -13402 -13403 -13404 -13405 -13406 -13407 -13408 13409 13410 -13411 +v -13412 -13413 -13414 13415 -13416 -13417 -13418 -13419 -13420 13421 -13422 +v -13423 -13424 -13425 -13426 -13427 -13428 13429 13430 -13431 -13432 13433 +v 13434 -13435 13436 -13437 -13438 -13439 -13440 -13441 -13442 -13443 -13444 +v -13445 -13446 -13447 -13448 -13449 -13450 -13451 -13452 -13453 -13454 -13455 +v -13456 -13457 -13458 -13459 -13460 13461 13462 -13463 13464 13465 13466 +v -13467 13468 -13469 -13470 13471 -13472 -13473 13474 -13475 -13476 -13477 +v -13478 -13479 -13480 -13481 13482 -13483 13484 -13485 -13486 13487 -13488 +v 13489 -13490 -13491 13492 -13493 13494 -13495 -13496 -13497 13498 -13499 +v 13500 13501 13502 13503 -13504 -13505 13506 13507 13508 13509 -13510 -13511 +v 13512 13513 13514 -13515 -13516 -13517 -13518 -13519 -13520 -13521 -13522 +v -13523 -13524 -13525 -13526 -13527 -13528 13529 13530 13531 -13532 -13533 +v -13534 -13535 13536 -13537 -13538 13539 -13540 -13541 -13542 -13543 -13544 +v -13545 -13546 -13547 -13548 13549 13550 13551 13552 -13553 13554 -13555 +v -13556 -13557 -13558 -13559 -13560 -13561 -13562 -13563 -13564 -13565 -13566 +v -13567 -13568 -13569 -13570 -13571 -13572 -13573 -13574 -13575 -13576 -13577 +v -13578 -13579 -13580 -13581 13582 -13583 13584 -13585 -13586 -13587 -13588 +v -13589 -13590 -13591 -13592 13593 13594 13595 13596 -13597 -13598 13599 +v -13600 -13601 -13602 -13603 -13604 -13605 -13606 -13607 -13608 -13609 -13610 +v -13611 13612 13613 -13614 13615 -13616 -13617 -13618 -13619 -13620 13621 +v -13622 13623 -13624 -13625 -13626 13627 -13628 13629 -13630 -13631 -13632 +v 13633 -13634 13635 13636 13637 13638 -13639 -13640 13641 13642 13643 -13644 +v -13645 -13646 -13647 -13648 -13649 -13650 -13651 -13652 -13653 -13654 13655 +v 13656 13657 13658 -13659 -13660 13661 -13662 13663 -13664 -13665 -13666 +v -13667 -13668 -13669 -13670 -13671 -13672 -13673 -13674 -13675 -13676 -13677 +v -13678 13679 13680 -13681 -13682 -13683 -13684 -13685 -13686 -13687 -13688 +v -13689 -13690 13691 13692 13693 -13694 -13695 13696 -13697 -13698 -13699 +v -13700 -13701 -13702 -13703 -13704 -13705 -13706 -13707 -13708 -13709 -13710 +v 13711 -13712 13713 -13714 -13715 13716 -13717 13718 -13719 -13720 -13721 +v 13722 -13723 13724 13725 13726 13727 -13728 -13729 13730 13731 13732 -13733 +v -13734 -13735 -13736 -13737 -13738 -13739 -13740 -13741 -13742 -13743 13744 +v 13745 13746 13747 -13748 -13749 -13750 -13751 -13752 -13753 -13754 -13755 +v -13756 -13757 -13758 -13759 -13760 -13761 -13762 -13763 -13764 -13765 -13766 +v -13767 -13768 -13769 -13770 -13771 -13772 -13773 -13774 -13775 -13776 -13777 +v -13778 -13779 -13780 -13781 -13782 -13783 -13784 -13785 -13786 -13787 -13788 +v -13789 -13790 -13791 -13792 13793 -13794 -13795 13796 -13797 -13798 -13799 +v -13800 -13801 -13802 -13803 -13804 -13805 -13806 -13807 -13808 -13809 -13810 +v -13811 13812 13813 13814 13815 -13816 -13817 -13818 -13819 -13820 -13821 +v 13822 13823 -13824 -13825 -13826 -13827 -13828 -13829 -13830 -13831 13832 +v -13833 -13834 -13835 -13836 -13837 -13838 13839 13840 -13841 -13842 -13843 +v -13844 -13845 -13846 -13847 -13848 -13849 -13850 13851 -13852 -13853 -13854 +v -13855 -13856 -13857 -13858 -13859 -13860 -13861 -13862 13863 -13864 -13865 +v -13866 -13867 -13868 -13869 -13870 -13871 -13872 13873 13874 13875 13876 +v 13877 13878 -13879 -13880 -13881 -13882 -13883 -13884 -13885 -13886 -13887 +v -13888 -13889 -13890 -13891 -13892 -13893 -13894 -13895 13896 13897 -13898 +v 13899 -13900 -13901 -13902 -13903 -13904 -13905 -13906 -13907 -13908 13909 +v -13910 -13911 -13912 -13913 -13914 -13915 13916 -13917 13918 -13919 -13920 +v -13921 13922 -13923 13924 13925 13926 13927 -13928 -13929 13930 -13931 +v -13932 -13933 13934 -13935 13936 -13937 -13938 13939 -13940 -13941 -13942 +v -13943 -13944 -13945 -13946 -13947 -13948 -13949 13950 13951 13952 -13953 +v -13954 -13955 -13956 -13957 -13958 -13959 -13960 -13961 -13962 -13963 -13964 +v -13965 13966 -13967 -13968 13969 -13970 -13971 -13972 -13973 -13974 -13975 +v 13976 13977 13978 -13979 -13980 -13981 -13982 -13983 -13984 -13985 -13986 +v -13987 -13988 -13989 -13990 -13991 -13992 -13993 -13994 -13995 -13996 -13997 +v -13998 -13999 -14000 14001 -14002 -14003 -14004 -14005 -14006 -14007 -14008 +v 14009 -14010 14011 -14012 -14013 -14014 14015 -14016 14017 -14018 -14019 +v 14020 -14021 -14022 -14023 -14024 -14025 -14026 14027 14028 14029 -14030 +v -14031 -14032 -14033 -14034 -14035 -14036 -14037 -14038 -14039 -14040 -14041 +v -14042 -14043 -14044 -14045 -14046 -14047 -14048 -14049 -14050 -14051 14052 +v -14053 -14054 -14055 -14056 -14057 -14058 -14059 14060 -14061 14062 -14063 +v -14064 -14065 14066 -14067 14068 -14069 -14070 14071 -14072 -14073 -14074 +v -14075 -14076 -14077 14078 14079 14080 -14081 -14082 -14083 -14084 -14085 +v -14086 -14087 -14088 -14089 -14090 -14091 -14092 -14093 -14094 -14095 -14096 +v -14097 -14098 -14099 -14100 -14101 -14102 14103 -14104 -14105 -14106 -14107 +v -14108 -14109 -14110 14111 -14112 14113 -14114 -14115 -14116 14117 -14118 +v 14119 -14120 -14121 14122 -14123 -14124 -14125 -14126 -14127 -14128 14129 +v 14130 14131 -14132 -14133 -14134 -14135 -14136 -14137 -14138 -14139 -14140 +v -14141 -14142 -14143 -14144 -14145 -14146 -14147 -14148 -14149 -14150 -14151 +v -14152 -14153 -14154 -14155 -14156 -14157 -14158 -14159 -14160 -14161 -14162 +v -14163 -14164 -14165 -14166 -14167 -14168 -14169 -14170 -14171 -14172 -14173 +v -14174 -14175 -14176 -14177 -14178 -14179 -14180 -14181 -14182 -14183 -14184 +v -14185 -14186 -14187 -14188 -14189 -14190 -14191 -14192 -14193 -14194 -14195 +v -14196 -14197 -14198 -14199 -14200 -14201 -14202 -14203 -14204 -14205 -14206 +v -14207 -14208 -14209 -14210 -14211 -14212 -14213 -14214 -14215 -14216 -14217 +v -14218 -14219 -14220 -14221 -14222 -14223 -14224 -14225 -14226 -14227 -14228 +v -14229 14230 -14231 -14232 -14233 -14234 -14235 -14236 -14237 -14238 -14239 +v -14240 -14241 -14242 -14243 -14244 -14245 -14246 -14247 -14248 -14249 -14250 +v -14251 -14252 -14253 -14254 -14255 -14256 -14257 -14258 -14259 -14260 -14261 +v -14262 -14263 -14264 -14265 -14266 -14267 -14268 -14269 -14270 -14271 -14272 +v -14273 -14274 -14275 -14276 -14277 -14278 -14279 -14280 -14281 -14282 -14283 +v -14284 -14285 -14286 -14287 -14288 -14289 -14290 -14291 -14292 -14293 -14294 +v -14295 -14296 -14297 -14298 -14299 -14300 -14301 -14302 -14303 14304 -14305 +v 14306 -14307 -14308 -14309 14310 -14311 14312 -14313 -14314 -14315 -14316 +v 14317 -14318 14319 -14320 -14321 -14322 -14323 14324 -14325 14326 -14327 +v -14328 14329 -14330 -14331 -14332 -14333 -14334 -14335 -14336 -14337 -14338 +v -14339 14340 14341 14342 -14343 -14344 -14345 -14346 -14347 -14348 -14349 +v -14350 -14351 -14352 -14353 -14354 -14355 -14356 -14357 -14358 -14359 -14360 +v -14361 -14362 -14363 -14364 14365 -14366 -14367 -14368 -14369 -14370 -14371 +v -14372 14373 -14374 14375 -14376 -14377 -14378 14379 -14380 14381 -14382 +v -14383 14384 -14385 -14386 -14387 -14388 -14389 -14390 14391 14392 14393 +v -14394 -14395 -14396 -14397 -14398 -14399 -14400 -14401 -14402 -14403 -14404 +v -14405 -14406 -14407 -14408 -14409 -14410 -14411 -14412 -14413 -14414 -14415 +v -14416 -14417 -14418 -14419 -14420 -14421 -14422 -14423 -14424 -14425 -14426 +v -14427 -14428 -14429 -14430 -14431 -14432 -14433 -14434 -14435 -14436 14437 +v 14438 14439 14440 14441 14442 14443 -14444 -14445 -14446 -14447 -14448 +v -14449 14450 -14451 14452 14453 -14454 -14455 -14456 -14457 -14458 -14459 +v -14460 -14461 -14462 14463 -14464 -14465 -14466 -14467 -14468 -14469 -14470 +v 14471 -14472 -14473 -14474 -14475 -14476 -14477 -14478 -14479 -14480 -14481 +v -14482 -14483 -14484 -14485 -14486 -14487 -14488 -14489 -14490 -14491 -14492 +v -14493 -14494 -14495 -14496 14497 14498 14499 14500 14501 14502 -14503 +v -14504 -14505 -14506 -14507 -14508 -14509 -14510 -14511 -14512 -14513 -14514 +v -14515 -14516 -14517 -14518 -14519 14520 14521 -14522 14523 -14524 -14525 +v -14526 -14527 -14528 -14529 -14530 -14531 -14532 14533 -14534 -14535 -14536 +v -14537 -14538 -14539 14540 -14541 14542 -14543 -14544 -14545 -14546 14547 +v -14548 14549 14550 14551 14552 14553 -14554 -14555 14556 -14557 -14558 +v -14559 -14560 14561 -14562 14563 -14564 -14565 14566 -14567 -14568 -14569 +v -14570 -14571 -14572 -14573 -14574 -14575 -14576 14577 14578 14579 -14580 +v -14581 -14582 -14583 -14584 -14585 -14586 -14587 -14588 -14589 -14590 -14591 +v -14592 -14593 -14594 -14595 -14596 -14597 -14598 -14599 -14600 -14601 -14602 +v -14603 -14604 -14605 -14606 -14607 -14608 14609 -14610 14611 -14612 -14613 +v -14614 14615 -14616 14617 -14618 -14619 14620 -14621 -14622 -14623 -14624 +v -14625 -14626 14627 14628 14629 14630 -14631 -14632 -14633 -14634 -14635 +v -14636 -14637 -14638 -14639 -14640 -14641 -14642 -14643 -14644 -14645 -14646 +v -14647 -14648 -14649 -14650 -14651 -14652 -14653 -14654 -14655 -14656 -14657 +v -14658 -14659 14660 -14661 14662 -14663 -14664 -14665 14666 -14667 14668 +v -14669 -14670 14671 -14672 -14673 -14674 -14675 -14676 -14677 14678 14679 +v 14680 14681 -14682 -14683 -14684 -14685 -14686 -14687 -14688 -14689 -14690 +v -14691 -14692 -14693 -14694 -14695 -14696 -14697 -14698 -14699 -14700 -14701 +v -14702 -14703 -14704 -14705 -14706 -14707 -14708 -14709 -14710 14711 -14712 +v 14713 -14714 -14715 -14716 14717 -14718 14719 -14720 -14721 14722 -14723 +v -14724 -14725 -14726 -14727 -14728 14729 14730 14731 14732 -14733 -14734 +v -14735 -14736 -14737 -14738 -14739 -14740 -14741 -14742 -14743 -14744 -14745 +v -14746 -14747 -14748 -14749 -14750 -14751 -14752 -14753 -14754 -14755 -14756 +v -14757 -14758 -14759 -14760 -14761 -14762 -14763 -14764 -14765 -14766 -14767 +v -14768 -14769 -14770 -14771 -14772 -14773 -14774 -14775 -14776 -14777 -14778 +v -14779 -14780 -14781 -14782 -14783 -14784 -14785 -14786 -14787 -14788 -14789 +v -14790 -14791 -14792 -14793 -14794 -14795 -14796 -14797 -14798 -14799 -14800 +v -14801 -14802 -14803 -14804 -14805 -14806 -14807 -14808 -14809 -14810 -14811 +v -14812 -14813 -14814 -14815 -14816 -14817 -14818 -14819 -14820 -14821 -14822 +v -14823 -14824 -14825 -14826 -14827 -14828 -14829 -14830 -14831 -14832 -14833 +v -14834 -14835 -14836 -14837 -14838 -14839 -14840 -14841 -14842 -14843 -14844 +v -14845 -14846 -14847 -14848 -14849 -14850 -14851 -14852 -14853 -14854 -14855 +v -14856 -14857 -14858 -14859 -14860 -14861 -14862 -14863 -14864 -14865 -14866 +v -14867 -14868 -14869 -14870 -14871 -14872 -14873 -14874 -14875 -14876 -14877 +v -14878 -14879 -14880 -14881 -14882 -14883 -14884 -14885 -14886 -14887 -14888 +v -14889 -14890 -14891 -14892 -14893 -14894 -14895 -14896 -14897 -14898 -14899 +v -14900 -14901 -14902 -14903 14904 -14905 14906 -14907 -14908 -14909 14910 +v -14911 14912 -14913 -14914 -14915 -14916 14917 -14918 14919 -14920 -14921 +v -14922 -14923 14924 -14925 14926 -14927 -14928 14929 -14930 -14931 -14932 +v -14933 -14934 -14935 -14936 -14937 -14938 -14939 14940 14941 14942 14943 +v -14944 -14945 -14946 -14947 -14948 -14949 -14950 -14951 -14952 -14953 -14954 +v -14955 -14956 -14957 -14958 -14959 -14960 -14961 -14962 -14963 -14964 -14965 +v -14966 -14967 -14968 -14969 -14970 -14971 -14972 14973 -14974 14975 -14976 +v -14977 -14978 14979 -14980 14981 -14982 -14983 14984 -14985 -14986 -14987 +v -14988 -14989 -14990 14991 14992 14993 14994 -14995 14996 -14997 14998 +v -14999 15000 15001 -15002 -15003 -15004 -15005 -15006 -15007 -15008 -15009 +v -15010 -15011 -15012 -15013 -15014 -15015 -15016 -15017 -15018 -15019 -15020 +v -15021 -15022 -15023 -15024 -15025 -15026 -15027 -15028 -15029 -15030 -15031 +v -15032 -15033 -15034 -15035 -15036 -15037 -15038 -15039 -15040 -15041 -15042 +v -15043 -15044 -15045 -15046 -15047 -15048 -15049 -15050 -15051 -15052 -15053 +v -15054 -15055 -15056 -15057 -15058 -15059 -15060 -15061 -15062 -15063 -15064 +v -15065 -15066 -15067 -15068 -15069 -15070 -15071 -15072 -15073 -15074 -15075 +v -15076 -15077 -15078 -15079 -15080 -15081 -15082 -15083 -15084 -15085 -15086 +v -15087 -15088 -15089 -15090 -15091 -15092 -15093 -15094 -15095 -15096 -15097 +v -15098 -15099 -15100 -15101 -15102 -15103 -15104 -15105 -15106 -15107 -15108 +v -15109 -15110 -15111 -15112 -15113 -15114 -15115 -15116 -15117 -15118 -15119 +v -15120 -15121 -15122 -15123 -15124 -15125 -15126 -15127 -15128 -15129 -15130 +v -15131 -15132 -15133 -15134 -15135 -15136 -15137 -15138 -15139 -15140 -15141 +v -15142 -15143 -15144 -15145 -15146 -15147 -15148 -15149 -15150 -15151 -15152 +v -15153 -15154 -15155 -15156 -15157 -15158 -15159 -15160 -15161 -15162 -15163 +v -15164 -15165 -15166 -15167 -15168 -15169 -15170 -15171 -15172 -15173 -15174 +v -15175 -15176 -15177 -15178 -15179 -15180 -15181 -15182 -15183 -15184 -15185 +v -15186 -15187 -15188 -15189 -15190 -15191 -15192 -15193 -15194 -15195 -15196 +v -15197 -15198 -15199 -15200 -15201 -15202 -15203 -15204 -15205 -15206 -15207 +v -15208 -15209 -15210 -15211 -15212 -15213 -15214 -15215 -15216 -15217 -15218 +v -15219 -15220 -15221 -15222 -15223 -15224 -15225 -15226 -15227 -15228 -15229 +v -15230 -15231 -15232 -15233 -15234 -15235 -15236 -15237 -15238 -15239 -15240 +v -15241 -15242 -15243 -15244 -15245 -15246 -15247 -15248 -15249 -15250 -15251 +v -15252 -15253 -15254 -15255 -15256 -15257 -15258 -15259 -15260 -15261 -15262 +v -15263 -15264 -15265 -15266 -15267 -15268 -15269 -15270 -15271 -15272 -15273 +v -15274 -15275 -15276 -15277 -15278 -15279 -15280 -15281 -15282 -15283 -15284 +v -15285 -15286 -15287 -15288 -15289 -15290 -15291 -15292 -15293 -15294 -15295 +v -15296 -15297 -15298 -15299 -15300 -15301 -15302 -15303 -15304 -15305 -15306 +v -15307 -15308 -15309 -15310 -15311 -15312 -15313 -15314 -15315 -15316 -15317 +v -15318 -15319 -15320 -15321 -15322 -15323 -15324 -15325 -15326 -15327 -15328 +v -15329 -15330 -15331 -15332 -15333 -15334 -15335 -15336 -15337 -15338 -15339 +v -15340 -15341 -15342 -15343 -15344 -15345 -15346 -15347 -15348 -15349 -15350 +v -15351 -15352 -15353 -15354 -15355 -15356 -15357 -15358 -15359 -15360 -15361 +v -15362 -15363 -15364 -15365 -15366 -15367 -15368 -15369 -15370 -15371 -15372 +v -15373 -15374 -15375 -15376 -15377 -15378 -15379 -15380 -15381 -15382 -15383 +v -15384 15385 -15386 15387 -15388 -15389 -15390 15391 -15392 15393 -15394 +v -15395 -15396 -15397 15398 -15399 15400 -15401 -15402 -15403 -15404 15405 +v -15406 15407 -15408 -15409 -15410 -15411 15412 -15413 15414 -15415 -15416 +v 15417 -15418 15419 -15420 -15421 -15422 -15423 -15424 -15425 -15426 -15427 +v -15428 -15429 -15430 -15431 -15432 -15433 15434 15435 15436 15437 15438 +v -15439 -15440 -15441 -15442 -15443 -15444 15445 -15446 -15447 -15448 -15449 +v -15450 -15451 -15452 -15453 -15454 -15455 -15456 -15457 -15458 -15459 -15460 +v -15461 -15462 -15463 -15464 -15465 -15466 -15467 -15468 -15469 -15470 -15471 +v -15472 -15473 -15474 -15475 -15476 -15477 -15478 -15479 -15480 -15481 -15482 +v -15483 -15484 -15485 -15486 -15487 -15488 -15489 -15490 -15491 -15492 -15493 +v -15494 -15495 -15496 -15497 -15498 -15499 -15500 -15501 -15502 -15503 -15504 +v -15505 -15506 -15507 -15508 -15509 -15510 -15511 -15512 -15513 -15514 -15515 +v -15516 -15517 -15518 -15519 -15520 -15521 -15522 -15523 -15524 -15525 -15526 +v -15527 -15528 -15529 -15530 -15531 -15532 -15533 -15534 -15535 -15536 -15537 +v -15538 -15539 -15540 -15541 -15542 -15543 -15544 -15545 -15546 -15547 -15548 +v -15549 -15550 -15551 -15552 -15553 -15554 -15555 -15556 -15557 -15558 -15559 +v -15560 -15561 -15562 -15563 -15564 -15565 15566 -15567 15568 -15569 -15570 +v -15571 -15572 15573 -15574 15575 -15576 -15577 -15578 -15579 15580 -15581 +v 15582 -15583 -15584 -15585 -15586 15587 -15588 15589 -15590 -15591 15592 +v -15593 15594 -15595 -15596 15597 -15598 -15599 -15600 -15601 -15602 -15603 +v -15604 -15605 -15606 -15607 -15608 -15609 15610 15611 15612 15613 -15614 +v -15615 -15616 -15617 -15618 -15619 -15620 -15621 -15622 -15623 -15624 -15625 +v -15626 -15627 -15628 -15629 -15630 -15631 -15632 -15633 -15634 -15635 -15636 +v -15637 -15638 -15639 -15640 -15641 -15642 -15643 -15644 -15645 -15646 -15647 +v -15648 -15649 -15650 -15651 -15652 -15653 -15654 -15655 -15656 -15657 -15658 +v -15659 -15660 -15661 -15662 -15663 -15664 15665 -15666 -15667 15668 -15669 +v -15670 -15671 15672 -15673 -15674 -15675 15676 -15677 -15678 -15679 -15680 +v -15681 -15682 -15683 -15684 -15685 -15686 -15687 15688 -15689 15690 15691 +v 15692 15693 -15694 -15695 -15696 -15697 -15698 -15699 -15700 -15701 -15702 +v -15703 -15704 -15705 -15706 -15707 -15708 -15709 -15710 -15711 -15712 -15713 +v -15714 -15715 -15716 -15717 -15718 -15719 -15720 -15721 -15722 -15723 -15724 +v -15725 -15726 -15727 -15728 -15729 -15730 -15731 -15732 -15733 -15734 -15735 +v -15736 -15737 -15738 -15739 -15740 -15741 -15742 -15743 -15744 -15745 -15746 +v -15747 -15748 -15749 -15750 -15751 -15752 -15753 -15754 -15755 -15756 -15757 +v -15758 -15759 -15760 -15761 -15762 -15763 -15764 -15765 -15766 -15767 -15768 +v -15769 -15770 -15771 -15772 -15773 -15774 -15775 -15776 -15777 -15778 -15779 +v -15780 -15781 -15782 -15783 -15784 -15785 -15786 -15787 -15788 -15789 -15790 +v -15791 -15792 -15793 -15794 -15795 -15796 -15797 -15798 -15799 -15800 -15801 +v -15802 -15803 -15804 -15805 -15806 -15807 -15808 -15809 -15810 -15811 -15812 +v -15813 -15814 -15815 -15816 -15817 -15818 -15819 -15820 -15821 -15822 -15823 +v -15824 -15825 -15826 -15827 -15828 -15829 -15830 -15831 -15832 -15833 -15834 +v -15835 -15836 -15837 -15838 -15839 -15840 -15841 -15842 -15843 -15844 -15845 +v -15846 -15847 -15848 -15849 -15850 -15851 -15852 -15853 -15854 -15855 -15856 +v -15857 -15858 15859 -15860 15861 -15862 -15863 15864 -15865 15866 -15867 +v -15868 15869 -15870 15871 -15872 -15873 -15874 15875 -15876 15877 -15878 +v -15879 -15880 15881 -15882 15883 -15884 -15885 15886 -15887 -15888 -15889 +v -15890 -15891 -15892 -15893 -15894 -15895 -15896 -15897 -15898 15899 15900 +v 15901 15902 -15903 -15904 -15905 -15906 -15907 -15908 -15909 -15910 -15911 +v -15912 -15913 -15914 -15915 15916 -15917 -15918 15919 -15920 -15921 -15922 +v -15923 -15924 -15925 15926 15927 15928 -15929 -15930 -15931 -15932 -15933 +v 15934 15935 -15936 15937 -15938 -15939 15940 -15941 -15942 -15943 -15944 +v -15945 -15946 -15947 -15948 -15949 -15950 -15951 -15952 -15953 -15954 15955 +v 15956 -15957 -15958 -15959 -15960 -15961 -15962 -15963 -15964 -15965 -15966 +v -15967 -15968 -15969 -15970 15971 15972 15973 15974 -15975 -15976 15977 +v 15978 15979 15980 15981 15982 15983 15984 -15985 -15986 -15987 -15988 -15989 +v 15990 15991 -15992 -15993 -15994 15995 -15996 -15997 -15998 -15999 -16000 +v -16001 16002 -16003 -16004 16005 16006 -16007 -16008 16009 16010 16011 16012 +v 16013 -16014 -16015 -16016 -16017 -16018 -16019 -16020 -16021 -16022 16023 +v -16024 -16025 -16026 -16027 -16028 -16029 -16030 -16031 16032 16033 -16034 +v -16035 -16036 16037 -16038 -16039 -16040 -16041 16042 16043 16044 16045 +v 16046 16047 16048 16049 -16050 -16051 -16052 -16053 16054 16055 16056 -16057 +v -16058 -16059 16060 -16061 -16062 -16063 -16064 16065 16066 16067 16068 +v 16069 -16070 16071 16072 -16073 -16074 -16075 16076 16077 16078 16079 16080 +v 16081 16082 16083 -16084 -16085 16086 -16087 16088 16089 -16090 16091 -16092 +v -16093 16094 -16095 16096 -16097 16098 -16099 -16100 16101 -16102 -16103 +v -16104 -16105 16106 -16107 16108 -16109 -16110 16111 -16112 -16113 -16114 +v -16115 -16116 -16117 -16118 -16119 -16120 -16121 16122 16123 16124 16125 +v -16126 -16127 -16128 -16129 -16130 -16131 -16132 -16133 -16134 -16135 -16136 +v -16137 -16138 -16139 16140 -16141 -16142 16143 -16144 -16145 -16146 -16147 +v -16148 16149 16150 -16151 -16152 -16153 -16154 16155 16156 -16157 -16158 +v -16159 -16160 16161 -16162 -16163 -16164 -16165 -16166 -16167 -16168 -16169 +v 16170 16171 16172 -16173 -16174 16175 -16176 -16177 -16178 -16179 -16180 +v 16181 -16182 -16183 -16184 -16185 -16186 -16187 -16188 -16189 -16190 -16191 +v -16192 -16193 -16194 -16195 -16196 -16197 -16198 -16199 -16200 -16201 -16202 +v -16203 -16204 -16205 -16206 -16207 -16208 -16209 -16210 -16211 -16212 -16213 +v -16214 -16215 -16216 -16217 -16218 -16219 -16220 -16221 -16222 -16223 -16224 +v -16225 -16226 -16227 -16228 -16229 -16230 -16231 -16232 -16233 16234 16235 +v -16236 16237 -16238 -16239 -16240 -16241 16242 -16243 -16244 -16245 -16246 +v -16247 16248 -16249 -16250 -16251 -16252 -16253 -16254 -16255 -16256 -16257 +v -16258 -16259 -16260 -16261 -16262 -16263 -16264 -16265 -16266 16267 16268 +v 16269 -16270 -16271 16272 16273 -16274 16275 -16276 -16277 -16278 16279 +v -16280 -16281 -16282 -16283 -16284 -16285 -16286 -16287 -16288 -16289 -16290 +v -16291 -16292 -16293 -16294 -16295 -16296 -16297 -16298 -16299 -16300 -16301 +v -16302 -16303 -16304 -16305 -16306 -16307 -16308 -16309 -16310 -16311 -16312 +v -16313 -16314 -16315 -16316 -16317 -16318 -16319 -16320 -16321 -16322 -16323 +v -16324 -16325 -16326 -16327 -16328 -16329 -16330 -16331 -16332 -16333 -16334 +v -16335 16336 16337 16338 -16339 16340 16341 16342 -16343 16344 -16345 -16346 +v 16347 -16348 -16349 16350 -16351 -16352 -16353 -16354 -16355 -16356 -16357 +v -16358 -16359 -16360 -16361 -16362 -16363 -16364 -16365 -16366 -16367 -16368 +v -16369 -16370 -16371 -16372 -16373 -16374 -16375 -16376 -16377 -16378 16379 +v -16380 -16381 -16382 -16383 -16384 -16385 -16386 -16387 -16388 16389 16390 +v -16391 -16392 -16393 -16394 -16395 -16396 -16397 -16398 -16399 -16400 -16401 +v -16402 -16403 -16404 -16405 -16406 -16407 -16408 -16409 -16410 -16411 -16412 +v -16413 16414 16415 -16416 -16417 -16418 16419 -16420 -16421 -16422 -16423 +v -16424 -16425 -16426 -16427 -16428 -16429 -16430 -16431 -16432 -16433 16434 +v 16435 16436 -16437 -16438 16439 16440 16441 -16442 -16443 -16444 -16445 +v -16446 -16447 -16448 -16449 -16450 -16451 -16452 -16453 -16454 -16455 -16456 +v -16457 -16458 -16459 -16460 -16461 16462 16463 -16464 -16465 -16466 -16467 +v -16468 16469 -16470 -16471 -16472 -16473 -16474 16475 -16476 -16477 -16478 +v -16479 -16480 -16481 -16482 -16483 -16484 16485 16486 -16487 -16488 16489 +v -16490 -16491 -16492 -16493 -16494 -16495 -16496 -16497 -16498 16499 16500 +v -16501 -16502 -16503 -16504 16505 -16506 -16507 -16508 -16509 -16510 16511 +v -16512 -16513 -16514 -16515 -16516 -16517 -16518 16519 16520 -16521 -16522 +v 16523 16524 -16525 16526 -16527 -16528 -16529 -16530 -16531 -16532 -16533 +v -16534 -16535 -16536 -16537 -16538 -16539 -16540 -16541 -16542 -16543 -16544 +v -16545 -16546 -16547 -16548 -16549 -16550 16551 16552 -16553 16554 16555 +v 16556 -16557 16558 -16559 -16560 16561 -16562 -16563 16564 -16565 -16566 +v -16567 -16568 -16569 -16570 -16571 16572 -16573 16574 -16575 -16576 -16577 +v 16578 -16579 16580 -16581 -16582 -16583 16584 -16585 16586 -16587 -16588 +v -16589 -16590 16591 -16592 16593 16594 16595 16596 16597 -16598 -16599 16600 +v 16601 16602 16603 16604 -16605 -16606 16607 16608 16609 -16610 -16611 -16612 +v -16613 -16614 -16615 -16616 -16617 -16618 -16619 -16620 -16621 -16622 -16623 +v 16624 16625 16626 -16627 -16628 -16629 -16630 16631 -16632 -16633 16634 +v -16635 -16636 -16637 -16638 -16639 -16640 -16641 -16642 -16643 16644 16645 +v 16646 16647 -16648 16649 -16650 -16651 -16652 -16653 -16654 -16655 -16656 +v -16657 -16658 -16659 -16660 -16661 -16662 -16663 -16664 -16665 -16666 -16667 +v -16668 -16669 -16670 -16671 -16672 -16673 -16674 -16675 -16676 16677 -16678 +v 16679 -16680 -16681 -16682 -16683 -16684 -16685 -16686 -16687 16688 16689 +v 16690 16691 -16692 -16693 16694 -16695 -16696 -16697 -16698 -16699 -16700 +v -16701 -16702 -16703 -16704 -16705 -16706 16707 16708 -16709 16710 -16711 +v -16712 -16713 -16714 -16715 16716 -16717 16718 -16719 -16720 -16721 16722 +v -16723 16724 -16725 -16726 -16727 16728 -16729 16730 16731 16732 16733 +v -16734 -16735 16736 16737 16738 -16739 -16740 -16741 -16742 -16743 -16744 +v -16745 -16746 -16747 -16748 -16749 16750 16751 16752 16753 -16754 -16755 +v 16756 -16757 16758 -16759 -16760 -16761 -16762 -16763 -16764 -16765 -16766 +v -16767 -16768 -16769 -16770 -16771 -16772 -16773 16774 16775 -16776 -16777 +v -16778 -16779 -16780 -16781 -16782 -16783 -16784 -16785 16786 16787 16788 +v -16789 -16790 16791 -16792 -16793 -16794 -16795 -16796 -16797 -16798 -16799 +v -16800 -16801 -16802 -16803 -16804 -16805 16806 -16807 16808 -16809 -16810 +v 16811 -16812 16813 -16814 -16815 -16816 16817 -16818 16819 16820 16821 16822 +v -16823 -16824 16825 16826 16827 -16828 -16829 -16830 -16831 -16832 -16833 +v -16834 -16835 -16836 -16837 -16838 16839 16840 16841 16842 -16843 -16844 +v -16845 -16846 -16847 -16848 -16849 -16850 -16851 -16852 -16853 -16854 -16855 +v -16856 -16857 -16858 -16859 -16860 -16861 -16862 -16863 -16864 -16865 -16866 +v -16867 -16868 -16869 -16870 -16871 -16872 -16873 -16874 -16875 -16876 -16877 +v -16878 -16879 -16880 -16881 -16882 -16883 -16884 -16885 -16886 -16887 16888 +v -16889 -16890 16891 -16892 -16893 -16894 -16895 -16896 -16897 -16898 -16899 +v -16900 -16901 -16902 -16903 -16904 -16905 -16906 16907 16908 16909 16910 +v -16911 -16912 -16913 -16914 -16915 -16916 16917 16918 -16919 -16920 -16921 +v -16922 -16923 -16924 -16925 -16926 16927 -16928 -16929 -16930 -16931 16932 +v 16933 16934 16935 16936 -16937 -16938 -16939 -16940 -16941 -16942 -16943 +v -16944 -16945 -16946 -16947 -16948 -16949 -16950 -16951 -16952 -16953 16954 +v 16955 -16956 16957 -16958 -16959 -16960 -16961 -16962 -16963 -16964 -16965 +v -16966 16967 -16968 -16969 -16970 -16971 -16972 -16973 -16974 16975 16976 +v -16977 -16978 -16979 -16980 -16981 -16982 -16983 -16984 -16985 -16986 16987 +v -16988 -16989 -16990 -16991 -16992 -16993 -16994 -16995 -16996 -16997 -16998 +v 16999 -17000 -17001 -17002 -17003 -17004 -17005 -17006 -17007 -17008 17009 +v -17010 17011 -17012 -17013 17014 -17015 17016 -17017 -17018 17019 -17020 +v 17021 17022 17023 17024 -17025 -17026 17027 -17028 -17029 -17030 17031 +v -17032 17033 -17034 -17035 17036 -17037 -17038 -17039 -17040 -17041 -17042 +v -17043 -17044 -17045 -17046 -17047 17048 17049 17050 -17051 -17052 -17053 +v -17054 -17055 -17056 -17057 -17058 -17059 -17060 -17061 -17062 -17063 17064 +v -17065 -17066 17067 -17068 -17069 -17070 -17071 -17072 -17073 17074 17075 +v 17076 -17077 -17078 -17079 -17080 -17081 -17082 -17083 -17084 -17085 -17086 +v -17087 -17088 -17089 -17090 -17091 -17092 -17093 -17094 -17095 -17096 -17097 +v -17098 17099 -17100 -17101 -17102 -17103 -17104 -17105 -17106 17107 -17108 +v 17109 -17110 -17111 -17112 17113 -17114 17115 -17116 -17117 17118 -17119 +v -17120 -17121 -17122 -17123 -17124 17125 17126 17127 -17128 -17129 -17130 +v -17131 -17132 -17133 -17134 -17135 -17136 -17137 -17138 -17139 -17140 -17141 +v -17142 -17143 -17144 -17145 -17146 -17147 -17148 -17149 17150 -17151 -17152 +v -17153 -17154 -17155 -17156 -17157 17158 -17159 17160 -17161 -17162 -17163 +v 17164 -17165 17166 -17167 -17168 17169 -17170 -17171 -17172 -17173 -17174 +v -17175 17176 17177 17178 -17179 -17180 -17181 -17182 -17183 -17184 -17185 +v -17186 -17187 -17188 -17189 -17190 -17191 -17192 -17193 -17194 -17195 -17196 +v -17197 -17198 -17199 -17200 17201 -17202 -17203 -17204 -17205 -17206 -17207 +v -17208 17209 -17210 17211 -17212 -17213 -17214 17215 -17216 17217 -17218 +v -17219 17220 -17221 -17222 -17223 -17224 -17225 -17226 17227 17228 17229 +v -17230 -17231 -17232 -17233 -17234 -17235 -17236 -17237 -17238 -17239 -17240 +v -17241 -17242 -17243 -17244 -17245 -17246 -17247 -17248 -17249 -17250 -17251 +v -17252 -17253 -17254 -17255 -17256 -17257 -17258 -17259 -17260 -17261 -17262 +v -17263 -17264 -17265 -17266 -17267 -17268 -17269 -17270 -17271 -17272 -17273 +v -17274 -17275 -17276 -17277 -17278 -17279 -17280 -17281 -17282 -17283 -17284 +v -17285 -17286 -17287 -17288 -17289 -17290 -17291 -17292 -17293 -17294 -17295 +v -17296 -17297 -17298 -17299 -17300 -17301 -17302 -17303 -17304 -17305 -17306 +v -17307 -17308 -17309 -17310 -17311 -17312 -17313 -17314 -17315 -17316 -17317 +v -17318 -17319 -17320 -17321 -17322 -17323 -17324 -17325 -17326 -17327 17328 +v -17329 -17330 -17331 -17332 -17333 -17334 -17335 -17336 -17337 -17338 -17339 +v -17340 -17341 -17342 -17343 -17344 -17345 -17346 -17347 -17348 -17349 -17350 +v -17351 -17352 -17353 -17354 -17355 -17356 -17357 -17358 -17359 -17360 -17361 +v -17362 -17363 -17364 -17365 -17366 -17367 -17368 -17369 -17370 -17371 -17372 +v -17373 -17374 -17375 -17376 -17377 -17378 -17379 -17380 -17381 -17382 -17383 +v -17384 -17385 -17386 -17387 -17388 -17389 -17390 -17391 -17392 -17393 -17394 +v -17395 -17396 -17397 -17398 -17399 -17400 -17401 17402 -17403 17404 -17405 +v -17406 -17407 17408 -17409 17410 -17411 -17412 -17413 -17414 17415 -17416 +v 17417 -17418 -17419 -17420 -17421 17422 -17423 17424 -17425 -17426 17427 +v -17428 -17429 -17430 -17431 -17432 -17433 -17434 -17435 -17436 -17437 17438 +v 17439 17440 -17441 -17442 -17443 -17444 -17445 -17446 -17447 -17448 -17449 +v -17450 -17451 -17452 -17453 -17454 -17455 -17456 -17457 -17458 -17459 -17460 +v -17461 -17462 17463 -17464 -17465 -17466 -17467 -17468 -17469 -17470 17471 +v -17472 17473 -17474 -17475 -17476 17477 -17478 17479 -17480 -17481 17482 +v -17483 -17484 -17485 -17486 -17487 -17488 17489 17490 17491 -17492 -17493 +v -17494 -17495 -17496 17497 17498 -17499 17500 -17501 -17502 17503 -17504 +v -17505 -17506 -17507 -17508 -17509 -17510 -17511 -17512 -17513 -17514 -17515 +v -17516 -17517 17518 17519 -17520 -17521 -17522 -17523 -17524 -17525 -17526 +v -17527 -17528 -17529 -17530 -17531 -17532 -17533 17534 17535 17536 17537 +v 17538 17539 17540 17541 -17542 -17543 -17544 -17545 -17546 -17547 17548 +v 17549 17550 -17551 17552 17553 17554 -17555 -17556 -17557 17558 17559 17560 +v 17561 17562 17563 17564 17565 -17566 -17567 -17568 17569 -17570 -17571 +v -17572 -17573 17574 -17575 -17576 -17577 -17578 -17579 -17580 -17581 -17582 +v 17583 17584 -17585 -17586 -17587 17588 -17589 -17590 -17591 -17592 17593 +v 17594 17595 17596 17597 17598 17599 17600 -17601 -17602 -17603 -17604 17605 +v 17606 17607 -17608 -17609 -17610 17611 -17612 -17613 -17614 -17615 17616 +v 17617 17618 17619 17620 -17621 17622 17623 -17624 -17625 -17626 17627 17628 +v 17629 17630 17631 17632 17633 17634 -17635 -17636 -17637 17638 -17639 17640 +v -17641 17642 -17643 17644 -17645 -17646 17647 -17648 17649 -17650 17651 +v -17652 -17653 17654 -17655 -17656 -17657 -17658 17659 -17660 17661 -17662 +v -17663 17664 -17665 -17666 -17667 -17668 -17669 -17670 -17671 -17672 -17673 +v -17674 17675 17676 17677 17678 17679 17680 17681 17682 17683 17684 17685 +v -17686 -17687 -17688 -17689 17690 -17691 -17692 17693 -17694 -17695 17696 +v -17697 17698 -17699 -17700 17701 -17702 -17703 -17704 -17705 -17706 17707 +v 17708 17709 17710 -17711 -17712 17713 -17714 -17715 17716 17717 17718 17719 +v -17720 -17721 -17722 -17723 -17724 -17725 -17726 -17727 -17728 -17729 -17730 +v -17731 -17732 -17733 -17734 -17735 -17736 -17737 17738 -17739 17740 -17741 +v -17742 -17743 17744 -17745 17746 -17747 -17748 17749 -17750 -17751 -17752 +v -17753 -17754 -17755 17756 17757 17758 17759 -17760 -17761 -17762 -17763 +v -17764 -17765 -17766 -17767 -17768 -17769 -17770 -17771 -17772 -17773 -17774 +v -17775 17776 -17777 17778 -17779 -17780 -17781 17782 -17783 17784 -17785 +v -17786 17787 -17788 -17789 -17790 -17791 -17792 -17793 17794 17795 17796 +v 17797 -17798 -17799 -17800 -17801 -17802 -17803 -17804 -17805 -17806 -17807 +v -17808 -17809 -17810 -17811 -17812 -17813 17814 -17815 17816 -17817 -17818 +v -17819 17820 -17821 17822 -17823 -17824 17825 -17826 -17827 -17828 -17829 +v -17830 -17831 17832 17833 17834 17835 -17836 -17837 -17838 -17839 17840 +v 17841 17842 17843 -17844 -17845 -17846 -17847 -17848 -17849 -17850 -17851 +v -17852 -17853 -17854 -17855 -17856 -17857 -17858 -17859 -17860 -17861 -17862 +v -17863 -17864 -17865 -17866 -17867 -17868 -17869 -17870 -17871 -17872 -17873 +v -17874 -17875 -17876 -17877 -17878 -17879 -17880 -17881 -17882 -17883 17884 +v -17885 17886 -17887 -17888 -17889 17890 -17891 17892 -17893 -17894 17895 +v -17896 -17897 -17898 -17899 -17900 -17901 17902 17903 17904 17905 17906 +v 17907 -17908 -17909 -17910 -17911 -17912 -17913 -17914 -17915 -17916 -17917 +v 17918 -17919 -17920 -17921 -17922 17923 17924 17925 17926 -17927 -17928 +v 17929 -17930 17931 -17932 17933 -17934 -17935 -17936 17937 17938 17939 17940 +v 17941 -17942 -17943 17944 17945 -17946 -17947 17948 17949 -17950 -17951 +v -17952 -17953 -17954 17955 17956 17957 17958 -17959 -17960 17961 17962 +v -17963 17964 -17965 17966 -17967 -17968 -17969 -17970 -17971 -17972 17973 +v 17974 -17975 17976 -17977 17978 -17979 -17980 -17981 -17982 -17983 -17984 +v 17985 17986 -17987 17988 -17989 17990 -17991 -17992 -17993 -17994 -17995 +v -17996 17997 17998 -17999 -18000 18001 18002 -18003 -18004 18005 -18006 +v -18007 18008 -18009 18010 -18011 18012 -18013 -18014 -18015 18016 18017 +v 18018 18019 18020 18021 18022 18023 18024 18025 -18026 -18027 -18028 -18029 +v -18030 -18031 -18032 -18033 -18034 -18035 -18036 -18037 -18038 18039 18040 +v 18041 18042 18043 18044 -18045 -18046 18047 18048 -18049 -18050 -18051 +v -18052 -18053 -18054 18055 -18056 18057 18058 18059 -18060 -18061 18062 +v -18063 -18064 -18065 18066 -18067 18068 -18069 -18070 18071 -18072 -18073 +v -18074 -18075 -18076 -18077 -18078 18079 18080 18081 18082 18083 18084 18085 +v 18086 18087 18088 18089 18090 18091 -18092 -18093 -18094 -18095 18096 -18097 +v -18098 18099 -18100 -18101 18102 -18103 18104 -18105 -18106 18107 -18108 +v -18109 -18110 -18111 -18112 18113 18114 18115 18116 -18117 -18118 -18119 +v -18120 -18121 -18122 -18123 -18124 -18125 -18126 -18127 -18128 -18129 -18130 +v -18131 -18132 -18133 -18134 -18135 -18136 -18137 -18138 -18139 -18140 -18141 +v -18142 -18143 -18144 -18145 -18146 -18147 18148 -18149 18150 -18151 -18152 +v -18153 18154 -18155 18156 -18157 -18158 18159 -18160 -18161 -18162 -18163 +v -18164 -18165 18166 18167 18168 18169 -18170 -18171 -18172 -18173 -18174 +v -18175 -18176 -18177 -18178 -18179 -18180 -18181 -18182 -18183 -18184 -18185 +v -18186 -18187 -18188 -18189 -18190 -18191 -18192 -18193 -18194 -18195 -18196 +v -18197 -18198 -18199 -18200 18201 -18202 18203 -18204 -18205 -18206 18207 +v -18208 18209 -18210 -18211 18212 -18213 -18214 -18215 -18216 -18217 -18218 +v 18219 18220 18221 18222 -18223 -18224 -18225 -18226 -18227 -18228 -18229 +v -18230 -18231 -18232 -18233 -18234 -18235 -18236 -18237 -18238 -18239 -18240 +v -18241 -18242 -18243 -18244 -18245 -18246 -18247 -18248 -18249 -18250 -18251 +v -18252 -18253 18254 -18255 18256 -18257 -18258 -18259 18260 -18261 18262 +v -18263 -18264 18265 -18266 -18267 -18268 -18269 -18270 -18271 18272 18273 +v 18274 18275 -18276 -18277 -18278 -18279 -18280 -18281 -18282 -18283 -18284 +v -18285 -18286 -18287 -18288 -18289 -18290 -18291 -18292 -18293 -18294 -18295 +v -18296 -18297 -18298 -18299 -18300 -18301 -18302 -18303 -18304 -18305 -18306 +v -18307 -18308 -18309 -18310 -18311 -18312 -18313 -18314 -18315 -18316 -18317 +v -18318 -18319 -18320 -18321 -18322 -18323 -18324 -18325 -18326 -18327 -18328 +v -18329 -18330 -18331 -18332 -18333 -18334 -18335 -18336 -18337 -18338 -18339 +v -18340 -18341 -18342 -18343 -18344 -18345 -18346 -18347 -18348 -18349 -18350 +v -18351 -18352 -18353 -18354 -18355 -18356 -18357 -18358 -18359 -18360 -18361 +v -18362 -18363 -18364 -18365 -18366 -18367 -18368 -18369 -18370 -18371 -18372 +v -18373 -18374 -18375 -18376 -18377 -18378 -18379 -18380 -18381 -18382 -18383 +v -18384 -18385 -18386 -18387 -18388 -18389 -18390 -18391 -18392 -18393 -18394 +v -18395 -18396 -18397 -18398 -18399 -18400 -18401 -18402 -18403 -18404 -18405 +v -18406 -18407 -18408 -18409 -18410 -18411 -18412 -18413 -18414 -18415 -18416 +v -18417 -18418 -18419 -18420 -18421 -18422 -18423 -18424 -18425 -18426 -18427 +v -18428 -18429 -18430 -18431 -18432 -18433 -18434 -18435 -18436 -18437 -18438 +v -18439 -18440 -18441 -18442 -18443 -18444 18445 -18446 18447 -18448 -18449 +v -18450 18451 -18452 18453 -18454 -18455 -18456 -18457 18458 -18459 18460 +v -18461 -18462 -18463 -18464 18465 -18466 18467 -18468 -18469 18470 -18471 +v -18472 -18473 -18474 -18475 -18476 -18477 -18478 -18479 -18480 18481 18482 +v 18483 18484 -18485 -18486 -18487 -18488 -18489 -18490 -18491 -18492 -18493 +v -18494 -18495 -18496 -18497 -18498 -18499 -18500 -18501 -18502 -18503 -18504 +v -18505 -18506 -18507 -18508 -18509 -18510 -18511 -18512 -18513 -18514 -18515 +v -18516 -18517 -18518 -18519 -18520 -18521 -18522 -18523 -18524 -18525 -18526 +v -18527 -18528 -18529 -18530 -18531 -18532 -18533 -18534 -18535 -18536 -18537 +v -18538 -18539 -18540 -18541 -18542 -18543 -18544 -18545 -18546 -18547 -18548 +v -18549 -18550 -18551 -18552 -18553 -18554 -18555 -18556 -18557 -18558 -18559 +v -18560 -18561 -18562 -18563 -18564 -18565 -18566 -18567 -18568 -18569 -18570 +v -18571 -18572 -18573 -18574 -18575 -18576 -18577 -18578 -18579 -18580 -18581 +v -18582 -18583 -18584 -18585 -18586 -18587 -18588 -18589 -18590 -18591 -18592 +v -18593 -18594 -18595 -18596 -18597 -18598 -18599 -18600 -18601 -18602 -18603 +v -18604 -18605 -18606 -18607 -18608 -18609 -18610 -18611 -18612 -18613 -18614 +v -18615 -18616 -18617 -18618 -18619 -18620 -18621 -18622 -18623 -18624 -18625 +v -18626 -18627 -18628 -18629 -18630 -18631 -18632 -18633 -18634 -18635 -18636 +v -18637 -18638 -18639 -18640 -18641 -18642 -18643 -18644 -18645 -18646 -18647 +v -18648 -18649 -18650 -18651 18652 -18653 18654 -18655 -18656 -18657 18658 +v -18659 18660 -18661 -18662 -18663 -18664 18665 -18666 18667 -18668 -18669 +v -18670 -18671 18672 -18673 18674 -18675 -18676 18677 -18678 -18679 -18680 +v -18681 -18682 -18683 -18684 -18685 -18686 -18687 18688 18689 18690 18691 +v -18692 -18693 -18694 -18695 -18696 -18697 -18698 -18699 -18700 -18701 -18702 +v -18703 -18704 -18705 -18706 -18707 -18708 -18709 -18710 -18711 -18712 -18713 +v -18714 -18715 -18716 -18717 -18718 -18719 -18720 -18721 -18722 -18723 -18724 +v -18725 -18726 -18727 -18728 -18729 -18730 -18731 -18732 -18733 -18734 -18735 +v -18736 -18737 -18738 -18739 -18740 -18741 -18742 -18743 -18744 -18745 -18746 +v -18747 -18748 -18749 -18750 -18751 -18752 -18753 -18754 -18755 -18756 -18757 +v -18758 -18759 -18760 -18761 -18762 -18763 -18764 -18765 -18766 -18767 -18768 +v -18769 -18770 -18771 -18772 -18773 -18774 -18775 -18776 -18777 -18778 -18779 +v -18780 -18781 -18782 -18783 -18784 -18785 -18786 -18787 -18788 -18789 -18790 +v -18791 -18792 -18793 -18794 -18795 -18796 -18797 -18798 -18799 -18800 -18801 +v -18802 -18803 -18804 -18805 -18806 -18807 -18808 -18809 -18810 -18811 -18812 +v -18813 -18814 -18815 -18816 -18817 -18818 -18819 -18820 -18821 -18822 -18823 +v -18824 -18825 -18826 -18827 -18828 -18829 -18830 -18831 -18832 -18833 -18834 +v -18835 -18836 -18837 -18838 -18839 -18840 -18841 -18842 -18843 -18844 -18845 +v -18846 -18847 -18848 -18849 -18850 -18851 -18852 18853 -18854 18855 -18856 +v -18857 -18858 18859 -18860 18861 -18862 -18863 -18864 -18865 18866 -18867 +v 18868 -18869 -18870 -18871 -18872 18873 -18874 18875 -18876 -18877 18878 +v -18879 -18880 -18881 -18882 -18883 -18884 -18885 -18886 -18887 -18888 18889 +v 18890 18891 18892 -18893 -18894 -18895 -18896 -18897 -18898 -18899 -18900 +v -18901 -18902 -18903 -18904 -18905 -18906 -18907 -18908 -18909 -18910 -18911 +v -18912 -18913 -18914 -18915 -18916 -18917 -18918 -18919 -18920 -18921 -18922 +v -18923 -18924 -18925 -18926 -18927 -18928 -18929 -18930 -18931 -18932 -18933 +v -18934 -18935 -18936 -18937 -18938 -18939 -18940 -18941 -18942 -18943 -18944 +v -18945 -18946 -18947 -18948 -18949 -18950 -18951 -18952 -18953 -18954 -18955 +v -18956 -18957 -18958 -18959 -18960 -18961 -18962 -18963 -18964 -18965 -18966 +v -18967 -18968 -18969 -18970 -18971 -18972 -18973 -18974 -18975 -18976 -18977 +v -18978 -18979 -18980 -18981 -18982 -18983 -18984 -18985 -18986 -18987 -18988 +v -18989 -18990 -18991 -18992 -18993 -18994 -18995 -18996 -18997 -18998 -18999 +v -19000 -19001 -19002 -19003 -19004 -19005 -19006 -19007 -19008 -19009 -19010 +v -19011 -19012 -19013 -19014 -19015 -19016 -19017 -19018 -19019 -19020 -19021 +v -19022 -19023 -19024 -19025 -19026 -19027 -19028 -19029 -19030 -19031 -19032 +v -19033 -19034 -19035 -19036 -19037 -19038 -19039 -19040 -19041 -19042 -19043 +v -19044 -19045 -19046 -19047 -19048 -19049 -19050 -19051 -19052 -19053 -19054 +v -19055 -19056 -19057 -19058 -19059 19060 -19061 19062 -19063 -19064 -19065 +v 19066 -19067 19068 -19069 -19070 -19071 -19072 19073 -19074 19075 -19076 +v -19077 -19078 -19079 19080 -19081 19082 -19083 -19084 19085 -19086 -19087 +v -19088 -19089 -19090 -19091 -19092 -19093 -19094 -19095 19096 19097 19098 +v 19099 -19100 -19101 -19102 -19103 -19104 -19105 -19106 -19107 -19108 -19109 +v -19110 -19111 -19112 -19113 -19114 -19115 -19116 -19117 -19118 -19119 -19120 +v -19121 -19122 -19123 -19124 -19125 -19126 -19127 -19128 -19129 -19130 19131 +v -19132 19133 -19134 -19135 -19136 19137 -19138 19139 -19140 -19141 19142 +v -19143 -19144 -19145 -19146 -19147 -19148 19149 19150 19151 19152 -19153 +v 19154 -19155 19156 -19157 19158 19159 19160 -19161 -19162 -19163 -19164 +v -19165 -19166 -19167 -19168 -19169 -19170 -19171 -19172 -19173 -19174 -19175 +v -19176 -19177 -19178 -19179 -19180 -19181 -19182 -19183 -19184 -19185 -19186 +v -19187 -19188 -19189 -19190 -19191 -19192 -19193 -19194 -19195 -19196 -19197 +v -19198 -19199 -19200 -19201 -19202 -19203 -19204 -19205 -19206 -19207 -19208 +v -19209 -19210 -19211 -19212 -19213 -19214 -19215 -19216 -19217 -19218 -19219 +v -19220 -19221 -19222 -19223 -19224 -19225 -19226 -19227 -19228 -19229 -19230 +v -19231 -19232 -19233 -19234 -19235 -19236 -19237 -19238 -19239 -19240 -19241 +v -19242 -19243 -19244 -19245 -19246 -19247 -19248 -19249 -19250 -19251 -19252 +v -19253 -19254 -19255 -19256 -19257 -19258 -19259 -19260 -19261 -19262 -19263 +v -19264 -19265 -19266 -19267 -19268 -19269 -19270 -19271 -19272 -19273 -19274 +v -19275 -19276 -19277 -19278 -19279 -19280 -19281 -19282 -19283 -19284 -19285 +v -19286 -19287 -19288 -19289 -19290 -19291 -19292 -19293 -19294 -19295 -19296 +v -19297 -19298 -19299 -19300 -19301 -19302 -19303 -19304 -19305 -19306 -19307 +v -19308 -19309 -19310 -19311 -19312 -19313 -19314 -19315 -19316 -19317 -19318 +v -19319 -19320 -19321 -19322 -19323 -19324 -19325 -19326 -19327 -19328 -19329 +v -19330 -19331 -19332 -19333 -19334 -19335 -19336 -19337 -19338 -19339 -19340 +v -19341 -19342 -19343 -19344 -19345 -19346 -19347 -19348 -19349 -19350 -19351 +v -19352 -19353 -19354 -19355 -19356 -19357 -19358 -19359 -19360 -19361 -19362 +v -19363 -19364 -19365 -19366 -19367 -19368 -19369 -19370 -19371 -19372 -19373 +v -19374 -19375 -19376 -19377 -19378 -19379 -19380 -19381 -19382 -19383 -19384 +v -19385 -19386 -19387 -19388 -19389 -19390 -19391 -19392 -19393 -19394 -19395 +v -19396 -19397 -19398 -19399 -19400 -19401 -19402 -19403 -19404 -19405 -19406 +v -19407 -19408 -19409 -19410 -19411 -19412 -19413 -19414 -19415 -19416 -19417 +v -19418 -19419 -19420 -19421 -19422 -19423 -19424 -19425 -19426 -19427 -19428 +v -19429 -19430 -19431 -19432 -19433 -19434 -19435 -19436 -19437 -19438 -19439 +v -19440 -19441 -19442 -19443 -19444 -19445 -19446 -19447 -19448 -19449 -19450 +v -19451 -19452 -19453 -19454 -19455 -19456 -19457 -19458 -19459 -19460 -19461 +v -19462 -19463 -19464 -19465 -19466 -19467 -19468 -19469 -19470 -19471 -19472 +v -19473 -19474 -19475 -19476 -19477 -19478 -19479 -19480 -19481 -19482 -19483 +v -19484 -19485 -19486 -19487 -19488 -19489 -19490 -19491 -19492 -19493 -19494 +v -19495 -19496 -19497 -19498 -19499 -19500 -19501 -19502 -19503 -19504 -19505 +v -19506 -19507 -19508 -19509 -19510 -19511 -19512 -19513 -19514 -19515 -19516 +v -19517 -19518 -19519 -19520 -19521 -19522 -19523 -19524 -19525 -19526 -19527 +v -19528 -19529 -19530 -19531 -19532 -19533 -19534 -19535 -19536 -19537 -19538 +v -19539 -19540 -19541 -19542 -19543 -19544 -19545 -19546 -19547 -19548 -19549 +v -19550 -19551 -19552 -19553 -19554 -19555 -19556 -19557 -19558 -19559 -19560 +v -19561 -19562 -19563 -19564 -19565 -19566 -19567 -19568 -19569 -19570 -19571 +v -19572 -19573 -19574 -19575 -19576 -19577 -19578 -19579 -19580 -19581 -19582 +v -19583 -19584 -19585 -19586 -19587 -19588 -19589 -19590 -19591 -19592 -19593 +v -19594 -19595 -19596 -19597 -19598 -19599 -19600 -19601 -19602 -19603 -19604 +v -19605 -19606 -19607 -19608 -19609 -19610 -19611 -19612 -19613 -19614 -19615 +v -19616 -19617 -19618 -19619 -19620 -19621 -19622 -19623 -19624 -19625 -19626 +v -19627 -19628 -19629 -19630 -19631 -19632 -19633 -19634 -19635 -19636 -19637 +v -19638 -19639 -19640 -19641 -19642 -19643 -19644 -19645 -19646 -19647 -19648 +v -19649 -19650 -19651 -19652 -19653 -19654 -19655 -19656 -19657 -19658 -19659 +v -19660 -19661 -19662 -19663 -19664 -19665 -19666 -19667 -19668 -19669 -19670 +v -19671 -19672 -19673 -19674 -19675 -19676 -19677 -19678 -19679 -19680 -19681 +v -19682 -19683 -19684 -19685 -19686 -19687 -19688 -19689 -19690 -19691 -19692 +v -19693 -19694 -19695 -19696 -19697 -19698 -19699 -19700 -19701 -19702 -19703 +v -19704 -19705 -19706 -19707 19708 -19709 19710 -19711 -19712 19713 -19714 +v 19715 -19716 -19717 19718 -19719 19720 -19721 -19722 -19723 19724 -19725 +v 19726 -19727 -19728 -19729 19730 -19731 19732 -19733 -19734 -19735 19736 +v -19737 19738 -19739 -19740 19741 -19742 -19743 -19744 -19745 -19746 -19747 +v -19748 -19749 -19750 -19751 -19752 -19753 -19754 -19755 19756 19757 19758 +v 19759 19760 -19761 -19762 -19763 -19764 -19765 -19766 19767 -19768 -19769 +v -19770 -19771 -19772 -19773 -19774 -19775 -19776 -19777 -19778 -19779 -19780 +v -19781 -19782 -19783 -19784 -19785 -19786 -19787 -19788 -19789 -19790 -19791 +v -19792 -19793 -19794 -19795 -19796 -19797 -19798 -19799 -19800 -19801 -19802 +v -19803 -19804 -19805 -19806 -19807 -19808 -19809 -19810 -19811 -19812 -19813 +v -19814 -19815 -19816 -19817 -19818 -19819 -19820 -19821 -19822 -19823 -19824 +v -19825 -19826 -19827 -19828 -19829 -19830 -19831 -19832 -19833 -19834 -19835 +v -19836 -19837 -19838 -19839 -19840 -19841 -19842 -19843 -19844 -19845 -19846 +v -19847 -19848 -19849 -19850 -19851 -19852 -19853 -19854 -19855 -19856 -19857 +v -19858 -19859 -19860 -19861 -19862 -19863 -19864 -19865 -19866 -19867 -19868 +v -19869 -19870 -19871 -19872 -19873 -19874 -19875 -19876 -19877 -19878 -19879 +v -19880 -19881 -19882 -19883 -19884 -19885 -19886 -19887 -19888 -19889 -19890 +v -19891 -19892 -19893 -19894 -19895 -19896 -19897 -19898 19899 -19900 19901 +v -19902 -19903 -19904 19905 -19906 19907 -19908 -19909 -19910 19911 -19912 +v 19913 -19914 -19915 -19916 19917 -19918 19919 -19920 -19921 -19922 19923 +v -19924 19925 -19926 -19927 19928 -19929 -19930 -19931 -19932 -19933 -19934 +v -19935 -19936 -19937 -19938 -19939 19940 19941 19942 -19943 -19944 -19945 +v -19946 -19947 -19948 -19949 -19950 -19951 -19952 -19953 -19954 -19955 -19956 +v -19957 -19958 -19959 -19960 -19961 -19962 -19963 -19964 -19965 -19966 -19967 +v -19968 -19969 -19970 -19971 -19972 -19973 -19974 -19975 -19976 -19977 -19978 +v -19979 -19980 -19981 -19982 -19983 -19984 -19985 -19986 -19987 -19988 -19989 +v -19990 -19991 -19992 -19993 -19994 -19995 19996 -19997 19998 -19999 -20000 +v 20001 -20002 20003 -20004 -20005 -20006 20007 -20008 20009 -20010 -20011 +v -20012 20013 -20014 20015 -20016 -20017 20018 -20019 -20020 -20021 -20022 +v -20023 -20024 -20025 -20026 -20027 -20028 20029 20030 20031 20032 -20033 +v -20034 -20035 -20036 -20037 -20038 -20039 -20040 -20041 -20042 -20043 -20044 +v -20045 -20046 -20047 -20048 -20049 -20050 -20051 -20052 -20053 -20054 -20055 +v -20056 -20057 -20058 -20059 -20060 -20061 -20062 -20063 -20064 -20065 -20066 +v -20067 -20068 -20069 -20070 -20071 -20072 -20073 -20074 -20075 -20076 -20077 +v -20078 -20079 -20080 -20081 -20082 -20083 -20084 -20085 -20086 -20087 -20088 +v -20089 -20090 -20091 -20092 -20093 -20094 -20095 -20096 -20097 -20098 -20099 +v -20100 -20101 -20102 20103 -20104 -20105 -20106 -20107 -20108 -20109 -20110 +v -20111 -20112 -20113 -20114 -20115 -20116 -20117 -20118 -20119 -20120 -20121 +v -20122 -20123 -20124 -20125 -20126 -20127 -20128 -20129 -20130 20131 -20132 +v 20133 -20134 -20135 -20136 20137 -20138 20139 -20140 -20141 -20142 20143 +v -20144 20145 -20146 -20147 -20148 20149 -20150 20151 -20152 -20153 20154 +v -20155 -20156 -20157 -20158 -20159 -20160 -20161 -20162 -20163 -20164 20165 +v 20166 20167 -20168 -20169 -20170 -20171 -20172 -20173 -20174 -20175 -20176 +v -20177 -20178 -20179 -20180 20181 -20182 -20183 20184 -20185 -20186 -20187 +v -20188 -20189 -20190 20191 20192 20193 20194 -20195 20196 -20197 20198 20199 +v 20200 20201 20202 20203 20204 20205 20206 20207 -20208 -20209 20210 20211 +v 20212 20213 20214 20215 -20216 20217 20218 20219 -20220 -20221 -20222 -20223 +v -20224 -20225 20226 -20227 20228 20229 -20230 -20231 -20232 -20233 -20234 +v -20235 -20236 -20237 -20238 -20239 20240 -20241 -20242 -20243 20244 -20245 +v -20246 20247 20248 20249 20250 20251 20252 20253 20254 20255 20256 -20257 +v -20258 20259 20260 20261 20262 20263 20264 -20265 20266 20267 -20268 -20269 +v 20270 20271 20272 20273 -20274 -20275 20276 20277 -20278 -20279 -20280 20281 +v -20282 20283 -20284 -20285 20286 -20287 -20288 -20289 -20290 -20291 -20292 +v -20293 -20294 20295 20296 20297 -20298 -20299 -20300 -20301 -20302 -20303 +v -20304 -20305 -20306 -20307 -20308 -20309 -20310 -20311 -20312 -20313 -20314 +v -20315 -20316 -20317 -20318 -20319 20320 -20321 -20322 -20323 -20324 -20325 +v -20326 -20327 20328 -20329 20330 -20331 -20332 -20333 20334 -20335 20336 +v -20337 -20338 20339 -20340 -20341 -20342 -20343 -20344 -20345 20346 20347 +v 20348 -20349 -20350 -20351 -20352 -20353 -20354 -20355 -20356 -20357 -20358 +v -20359 -20360 -20361 -20362 -20363 -20364 -20365 -20366 -20367 -20368 -20369 +v -20370 20371 -20372 -20373 -20374 -20375 -20376 -20377 -20378 20379 -20380 +v 20381 -20382 -20383 -20384 20385 -20386 20387 -20388 -20389 20390 -20391 +v -20392 -20393 -20394 -20395 -20396 20397 20398 20399 -20400 -20401 -20402 +v -20403 -20404 -20405 -20406 -20407 -20408 -20409 -20410 -20411 -20412 -20413 +v -20414 -20415 -20416 -20417 -20418 -20419 -20420 -20421 20422 -20423 -20424 +v -20425 -20426 -20427 -20428 -20429 20430 -20431 20432 -20433 -20434 -20435 +v 20436 -20437 20438 -20439 -20440 20441 -20442 -20443 -20444 -20445 -20446 +v -20447 20448 20449 20450 -20451 -20452 -20453 -20454 -20455 -20456 -20457 +v -20458 -20459 -20460 -20461 -20462 -20463 -20464 -20465 -20466 -20467 -20468 +v -20469 -20470 -20471 -20472 -20473 -20474 -20475 -20476 -20477 -20478 -20479 +v -20480 -20481 -20482 -20483 -20484 -20485 -20486 -20487 -20488 -20489 -20490 +v -20491 -20492 -20493 -20494 -20495 -20496 -20497 -20498 -20499 -20500 -20501 +v -20502 -20503 -20504 -20505 -20506 -20507 -20508 -20509 -20510 -20511 -20512 +v -20513 -20514 -20515 -20516 -20517 -20518 -20519 -20520 -20521 -20522 -20523 +v -20524 -20525 -20526 -20527 -20528 -20529 -20530 -20531 -20532 -20533 -20534 +v -20535 -20536 -20537 -20538 -20539 -20540 -20541 -20542 -20543 20544 -20545 +v -20546 -20547 -20548 -20549 -20550 -20551 -20552 -20553 -20554 -20555 -20556 +v -20557 -20558 -20559 -20560 -20561 -20562 -20563 -20564 -20565 -20566 -20567 +v -20568 -20569 -20570 -20571 -20572 -20573 -20574 -20575 -20576 -20577 -20578 +v -20579 -20580 -20581 -20582 -20583 -20584 -20585 -20586 -20587 -20588 -20589 +v -20590 -20591 -20592 -20593 -20594 -20595 -20596 -20597 -20598 -20599 -20600 +v -20601 -20602 -20603 -20604 -20605 -20606 -20607 -20608 -20609 -20610 -20611 +v -20612 20613 -20614 20615 -20616 -20617 -20618 20619 -20620 20621 -20622 +v -20623 -20624 -20625 20626 -20627 20628 -20629 -20630 -20631 -20632 20633 +v -20634 20635 -20636 -20637 20638 -20639 -20640 -20641 -20642 -20643 -20644 +v -20645 -20646 -20647 -20648 20649 20650 20651 -20652 -20653 -20654 -20655 +v -20656 -20657 -20658 -20659 -20660 -20661 -20662 -20663 -20664 -20665 -20666 +v -20667 -20668 -20669 -20670 -20671 -20672 -20673 -20674 -20675 -20676 -20677 +v -20678 -20679 -20680 -20681 -20682 -20683 -20684 -20685 -20686 -20687 -20688 +v -20689 -20690 -20691 -20692 -20693 -20694 -20695 -20696 -20697 -20698 -20699 +v -20700 -20701 -20702 -20703 -20704 -20705 -20706 -20707 -20708 -20709 -20710 +v -20711 -20712 -20713 -20714 -20715 -20716 -20717 -20718 -20719 -20720 -20721 +v -20722 -20723 -20724 -20725 -20726 -20727 -20728 -20729 -20730 -20731 -20732 +v -20733 -20734 -20735 -20736 -20737 -20738 -20739 -20740 -20741 -20742 -20743 +v -20744 20745 -20746 -20747 -20748 -20749 -20750 -20751 -20752 -20753 -20754 +v -20755 -20756 -20757 -20758 -20759 -20760 -20761 -20762 -20763 -20764 -20765 +v -20766 -20767 -20768 -20769 -20770 -20771 -20772 -20773 -20774 -20775 -20776 +v -20777 -20778 -20779 -20780 -20781 -20782 -20783 -20784 -20785 -20786 -20787 +v -20788 -20789 -20790 -20791 -20792 -20793 -20794 -20795 -20796 -20797 -20798 +v -20799 -20800 -20801 -20802 -20803 -20804 -20805 -20806 -20807 -20808 -20809 +v -20810 -20811 -20812 -20813 20814 -20815 20816 -20817 -20818 -20819 20820 +v -20821 20822 -20823 -20824 -20825 -20826 20827 -20828 20829 -20830 -20831 +v -20832 -20833 20834 -20835 20836 -20837 -20838 20839 -20840 -20841 -20842 +v -20843 -20844 -20845 -20846 -20847 -20848 -20849 20850 20851 20852 -20853 +v -20854 -20855 -20856 -20857 -20858 -20859 -20860 -20861 -20862 -20863 -20864 +v -20865 -20866 -20867 -20868 -20869 -20870 -20871 -20872 -20873 -20874 -20875 +v -20876 -20877 -20878 -20879 -20880 -20881 -20882 -20883 -20884 -20885 -20886 +v -20887 -20888 -20889 -20890 -20891 -20892 -20893 -20894 -20895 -20896 -20897 +v -20898 -20899 -20900 -20901 -20902 -20903 -20904 -20905 -20906 -20907 -20908 +v -20909 -20910 -20911 -20912 -20913 -20914 -20915 -20916 -20917 -20918 -20919 +v -20920 -20921 -20922 -20923 -20924 -20925 -20926 -20927 -20928 -20929 -20930 +v -20931 -20932 -20933 -20934 -20935 -20936 -20937 -20938 -20939 -20940 -20941 +v -20942 -20943 -20944 -20945 20946 -20947 -20948 -20949 -20950 -20951 -20952 +v -20953 -20954 -20955 -20956 -20957 -20958 -20959 -20960 -20961 -20962 -20963 +v -20964 -20965 -20966 -20967 -20968 -20969 -20970 -20971 -20972 -20973 -20974 +v -20975 -20976 -20977 -20978 -20979 -20980 -20981 -20982 -20983 -20984 -20985 +v -20986 -20987 -20988 -20989 -20990 -20991 -20992 -20993 -20994 -20995 -20996 +v -20997 -20998 -20999 -21000 -21001 -21002 -21003 -21004 -21005 -21006 -21007 +v -21008 -21009 -21010 -21011 -21012 -21013 -21014 21015 -21016 21017 -21018 +v -21019 -21020 21021 -21022 21023 -21024 -21025 -21026 -21027 21028 -21029 +v 21030 -21031 -21032 -21033 -21034 21035 -21036 21037 -21038 -21039 21040 +v -21041 -21042 -21043 -21044 -21045 -21046 -21047 -21048 -21049 -21050 21051 +v 21052 21053 -21054 -21055 -21056 -21057 -21058 -21059 -21060 -21061 -21062 +v -21063 -21064 -21065 -21066 -21067 -21068 -21069 -21070 -21071 -21072 -21073 +v -21074 -21075 -21076 -21077 -21078 -21079 -21080 -21081 -21082 -21083 -21084 +v -21085 -21086 -21087 -21088 -21089 -21090 -21091 -21092 -21093 -21094 -21095 +v -21096 -21097 -21098 -21099 -21100 -21101 -21102 -21103 -21104 -21105 -21106 +v -21107 -21108 -21109 -21110 -21111 -21112 -21113 -21114 -21115 -21116 -21117 +v -21118 -21119 -21120 -21121 -21122 -21123 -21124 -21125 -21126 -21127 -21128 +v -21129 -21130 -21131 -21132 -21133 -21134 -21135 -21136 -21137 -21138 -21139 +v -21140 -21141 -21142 -21143 -21144 -21145 -21146 21147 -21148 -21149 -21150 +v -21151 -21152 -21153 -21154 -21155 -21156 -21157 -21158 -21159 -21160 -21161 +v -21162 -21163 -21164 -21165 -21166 -21167 -21168 -21169 -21170 -21171 -21172 +v -21173 -21174 -21175 -21176 -21177 -21178 -21179 -21180 -21181 -21182 -21183 +v -21184 -21185 -21186 -21187 -21188 -21189 -21190 -21191 -21192 -21193 -21194 +v -21195 -21196 -21197 -21198 -21199 -21200 -21201 -21202 -21203 -21204 -21205 +v -21206 -21207 -21208 -21209 -21210 -21211 -21212 -21213 -21214 -21215 21216 +v -21217 21218 -21219 -21220 -21221 21222 -21223 21224 -21225 -21226 -21227 +v -21228 21229 -21230 21231 -21232 -21233 -21234 -21235 21236 -21237 21238 +v -21239 -21240 21241 -21242 -21243 -21244 -21245 -21246 -21247 -21248 -21249 +v -21250 -21251 21252 21253 21254 -21255 -21256 -21257 -21258 -21259 -21260 +v -21261 -21262 -21263 -21264 -21265 -21266 -21267 -21268 -21269 -21270 -21271 +v -21272 -21273 -21274 -21275 -21276 21277 -21278 -21279 -21280 -21281 -21282 +v -21283 -21284 21285 -21286 21287 -21288 -21289 -21290 21291 -21292 21293 +v -21294 -21295 21296 -21297 -21298 -21299 -21300 -21301 -21302 21303 21304 +v 21305 -21306 -21307 -21308 -21309 -21310 -21311 -21312 -21313 -21314 -21315 +v -21316 -21317 -21318 -21319 -21320 -21321 -21322 -21323 -21324 -21325 -21326 +v -21327 -21328 -21329 -21330 -21331 -21332 -21333 -21334 21335 -21336 21337 +v -21338 -21339 -21340 21341 -21342 21343 -21344 -21345 21346 -21347 -21348 +v -21349 -21350 -21351 -21352 21353 21354 21355 21356 -21357 -21358 -21359 +v -21360 -21361 -21362 -21363 -21364 -21365 -21366 -21367 -21368 -21369 -21370 +v -21371 -21372 -21373 -21374 -21375 -21376 -21377 -21378 -21379 -21380 -21381 +v -21382 -21383 -21384 -21385 21386 -21387 21388 -21389 -21390 -21391 21392 +v -21393 21394 -21395 -21396 21397 -21398 -21399 -21400 -21401 -21402 -21403 +v 21404 21405 21406 21407 -21408 -21409 -21410 -21411 -21412 -21413 -21414 +v -21415 -21416 -21417 -21418 -21419 -21420 -21421 -21422 -21423 -21424 -21425 +v -21426 -21427 -21428 -21429 -21430 -21431 -21432 -21433 -21434 -21435 -21436 +v 21437 -21438 21439 -21440 -21441 -21442 21443 -21444 21445 -21446 -21447 +v 21448 -21449 -21450 -21451 -21452 -21453 -21454 21455 21456 21457 21458 +v -21459 -21460 -21461 -21462 -21463 -21464 -21465 -21466 -21467 -21468 -21469 +v -21470 -21471 -21472 -21473 -21474 -21475 -21476 -21477 -21478 -21479 -21480 +v -21481 -21482 -21483 -21484 -21485 -21486 -21487 -21488 -21489 -21490 -21491 +v -21492 -21493 -21494 -21495 -21496 -21497 -21498 -21499 -21500 -21501 -21502 +v -21503 -21504 -21505 -21506 -21507 -21508 -21509 -21510 -21511 -21512 -21513 +v -21514 -21515 -21516 -21517 -21518 -21519 -21520 -21521 -21522 -21523 -21524 +v -21525 -21526 -21527 -21528 -21529 -21530 -21531 -21532 -21533 -21534 -21535 +v -21536 -21537 -21538 -21539 -21540 -21541 -21542 -21543 -21544 -21545 -21546 +v -21547 -21548 -21549 -21550 -21551 -21552 -21553 -21554 -21555 -21556 -21557 +v -21558 -21559 -21560 -21561 -21562 -21563 -21564 -21565 -21566 -21567 -21568 +v -21569 -21570 -21571 -21572 -21573 -21574 -21575 -21576 -21577 -21578 -21579 +v -21580 -21581 -21582 -21583 -21584 -21585 -21586 -21587 -21588 -21589 -21590 +v -21591 -21592 -21593 -21594 -21595 -21596 -21597 -21598 -21599 -21600 -21601 +v -21602 -21603 -21604 -21605 -21606 -21607 -21608 -21609 -21610 -21611 -21612 +v -21613 -21614 -21615 -21616 -21617 -21618 -21619 21620 -21621 21622 -21623 +v -21624 -21625 21626 -21627 21628 -21629 -21630 -21631 -21632 21633 -21634 +v 21635 -21636 -21637 -21638 -21639 21640 -21641 21642 -21643 -21644 21645 +v -21646 -21647 -21648 -21649 -21650 -21651 -21652 -21653 -21654 -21655 21656 +v 21657 21658 21659 -21660 -21661 -21662 -21663 -21664 -21665 -21666 -21667 +v -21668 -21669 -21670 -21671 -21672 -21673 -21674 -21675 -21676 -21677 -21678 +v -21679 -21680 -21681 -21682 -21683 -21684 -21685 -21686 -21687 -21688 -21689 +v -21690 -21691 -21692 -21693 -21694 -21695 -21696 -21697 -21698 -21699 -21700 +v -21701 -21702 -21703 -21704 -21705 -21706 -21707 -21708 -21709 -21710 -21711 +v -21712 -21713 -21714 -21715 -21716 -21717 -21718 -21719 -21720 -21721 -21722 +v -21723 -21724 -21725 -21726 -21727 -21728 -21729 -21730 -21731 -21732 -21733 +v -21734 -21735 -21736 -21737 -21738 -21739 -21740 -21741 -21742 -21743 -21744 +v -21745 -21746 -21747 -21748 -21749 -21750 -21751 -21752 -21753 -21754 -21755 +v -21756 -21757 -21758 -21759 -21760 -21761 -21762 -21763 -21764 -21765 -21766 +v -21767 -21768 -21769 -21770 -21771 -21772 -21773 -21774 -21775 -21776 -21777 +v -21778 -21779 -21780 -21781 -21782 -21783 -21784 -21785 -21786 -21787 -21788 +v -21789 -21790 -21791 -21792 -21793 -21794 -21795 -21796 -21797 -21798 -21799 +v -21800 -21801 -21802 -21803 -21804 -21805 -21806 -21807 -21808 -21809 -21810 +v -21811 -21812 -21813 -21814 -21815 -21816 -21817 -21818 -21819 -21820 21821 +v -21822 21823 -21824 -21825 -21826 21827 -21828 21829 -21830 -21831 -21832 +v -21833 21834 -21835 21836 -21837 -21838 -21839 -21840 21841 -21842 21843 +v -21844 -21845 21846 -21847 -21848 -21849 -21850 -21851 -21852 -21853 -21854 +v -21855 -21856 21857 21858 21859 21860 -21861 -21862 -21863 -21864 -21865 +v -21866 -21867 -21868 -21869 -21870 -21871 -21872 -21873 -21874 -21875 -21876 +v -21877 -21878 -21879 -21880 -21881 -21882 -21883 -21884 -21885 -21886 -21887 +v -21888 -21889 -21890 -21891 -21892 -21893 -21894 -21895 -21896 -21897 -21898 +v -21899 -21900 -21901 -21902 -21903 -21904 -21905 -21906 -21907 -21908 -21909 +v -21910 -21911 -21912 -21913 -21914 -21915 -21916 -21917 -21918 -21919 -21920 +v -21921 -21922 -21923 -21924 -21925 -21926 -21927 -21928 -21929 -21930 -21931 +v -21932 -21933 -21934 -21935 -21936 -21937 -21938 -21939 -21940 -21941 -21942 +v -21943 -21944 -21945 -21946 -21947 -21948 -21949 -21950 -21951 -21952 -21953 +v -21954 -21955 -21956 -21957 -21958 -21959 -21960 -21961 -21962 -21963 -21964 +v -21965 -21966 -21967 -21968 -21969 -21970 -21971 -21972 -21973 -21974 -21975 +v -21976 -21977 -21978 -21979 -21980 -21981 -21982 -21983 -21984 -21985 -21986 +v -21987 -21988 -21989 -21990 -21991 -21992 -21993 -21994 -21995 -21996 -21997 +v -21998 -21999 -22000 -22001 -22002 -22003 -22004 -22005 -22006 -22007 -22008 +v -22009 -22010 -22011 -22012 -22013 -22014 -22015 -22016 -22017 -22018 -22019 +v -22020 -22021 22022 -22023 22024 -22025 -22026 -22027 22028 -22029 22030 +v -22031 -22032 -22033 -22034 22035 -22036 22037 -22038 -22039 -22040 -22041 +v 22042 -22043 22044 -22045 -22046 22047 -22048 -22049 -22050 -22051 -22052 +v -22053 -22054 -22055 -22056 -22057 22058 22059 22060 22061 -22062 -22063 +v -22064 -22065 -22066 -22067 -22068 -22069 -22070 -22071 -22072 -22073 -22074 +v -22075 -22076 -22077 -22078 -22079 -22080 -22081 -22082 -22083 -22084 -22085 +v -22086 -22087 -22088 -22089 -22090 -22091 -22092 -22093 -22094 -22095 -22096 +v -22097 -22098 -22099 -22100 -22101 -22102 -22103 -22104 -22105 -22106 -22107 +v -22108 -22109 -22110 -22111 -22112 -22113 -22114 -22115 -22116 -22117 -22118 +v -22119 -22120 -22121 -22122 -22123 -22124 -22125 -22126 -22127 -22128 -22129 +v -22130 -22131 -22132 -22133 -22134 -22135 -22136 -22137 -22138 -22139 -22140 +v -22141 -22142 -22143 -22144 -22145 -22146 -22147 -22148 -22149 -22150 -22151 +v -22152 -22153 -22154 -22155 -22156 -22157 -22158 -22159 -22160 -22161 -22162 +v -22163 -22164 -22165 -22166 -22167 -22168 -22169 -22170 -22171 -22172 -22173 +v -22174 -22175 -22176 -22177 -22178 -22179 -22180 -22181 -22182 -22183 -22184 +v -22185 -22186 -22187 -22188 -22189 -22190 -22191 -22192 -22193 -22194 -22195 +v -22196 -22197 -22198 -22199 -22200 -22201 -22202 -22203 -22204 -22205 -22206 +v -22207 -22208 -22209 -22210 -22211 -22212 -22213 -22214 -22215 -22216 -22217 +v -22218 -22219 -22220 -22221 -22222 22223 -22224 22225 -22226 -22227 -22228 +v 22229 -22230 22231 -22232 -22233 -22234 -22235 22236 -22237 22238 -22239 +v -22240 -22241 -22242 22243 -22244 22245 -22246 -22247 22248 -22249 -22250 +v -22251 -22252 -22253 -22254 -22255 -22256 -22257 -22258 22259 22260 22261 +v 22262 -22263 -22264 -22265 -22266 -22267 -22268 -22269 -22270 -22271 -22272 +v -22273 -22274 -22275 -22276 -22277 -22278 -22279 -22280 -22281 -22282 -22283 +v -22284 -22285 -22286 -22287 -22288 -22289 -22290 -22291 22292 -22293 22294 +v -22295 -22296 -22297 22298 -22299 22300 -22301 -22302 22303 -22304 -22305 +v -22306 -22307 -22308 -22309 22310 22311 22312 22313 -22314 22315 -22316 +v 22317 -22318 22319 22320 -22321 -22322 -22323 -22324 -22325 -22326 -22327 +v -22328 -22329 -22330 -22331 -22332 -22333 -22334 -22335 -22336 -22337 -22338 +v -22339 -22340 -22341 -22342 -22343 -22344 -22345 -22346 -22347 -22348 -22349 +v -22350 -22351 -22352 -22353 -22354 -22355 -22356 -22357 -22358 -22359 -22360 +v -22361 -22362 -22363 -22364 -22365 -22366 -22367 -22368 -22369 -22370 -22371 +v -22372 -22373 -22374 -22375 -22376 -22377 -22378 -22379 -22380 -22381 -22382 +v -22383 -22384 -22385 -22386 -22387 -22388 -22389 -22390 -22391 -22392 -22393 +v -22394 -22395 -22396 -22397 -22398 -22399 -22400 -22401 -22402 -22403 -22404 +v -22405 -22406 -22407 -22408 -22409 -22410 -22411 -22412 -22413 -22414 -22415 +v -22416 -22417 -22418 -22419 -22420 -22421 -22422 -22423 -22424 -22425 -22426 +v -22427 -22428 -22429 -22430 -22431 -22432 -22433 -22434 -22435 -22436 -22437 +v -22438 -22439 -22440 -22441 -22442 -22443 -22444 -22445 -22446 -22447 -22448 +v -22449 -22450 -22451 -22452 -22453 -22454 -22455 -22456 -22457 -22458 -22459 +v -22460 -22461 -22462 -22463 -22464 -22465 -22466 -22467 -22468 -22469 -22470 +v -22471 -22472 -22473 -22474 -22475 -22476 -22477 -22478 -22479 -22480 -22481 +v -22482 -22483 -22484 -22485 -22486 -22487 -22488 -22489 -22490 -22491 -22492 +v -22493 -22494 -22495 -22496 -22497 -22498 -22499 -22500 -22501 -22502 -22503 +v -22504 -22505 -22506 -22507 -22508 -22509 -22510 -22511 -22512 -22513 -22514 +v -22515 -22516 -22517 -22518 -22519 -22520 -22521 -22522 -22523 -22524 -22525 +v -22526 -22527 -22528 -22529 -22530 -22531 -22532 -22533 -22534 -22535 -22536 +v -22537 -22538 -22539 -22540 -22541 -22542 -22543 -22544 -22545 -22546 -22547 +v -22548 -22549 -22550 -22551 -22552 -22553 -22554 -22555 -22556 -22557 -22558 +v -22559 -22560 -22561 -22562 -22563 -22564 -22565 -22566 -22567 -22568 -22569 +v -22570 -22571 -22572 -22573 -22574 -22575 -22576 -22577 -22578 -22579 -22580 +v -22581 -22582 -22583 -22584 -22585 -22586 -22587 -22588 -22589 -22590 -22591 +v -22592 -22593 -22594 -22595 -22596 -22597 -22598 -22599 -22600 -22601 -22602 +v -22603 -22604 -22605 -22606 -22607 -22608 -22609 -22610 -22611 -22612 -22613 +v -22614 -22615 -22616 -22617 -22618 -22619 -22620 -22621 -22622 -22623 -22624 +v -22625 -22626 -22627 -22628 -22629 -22630 -22631 -22632 -22633 -22634 -22635 +v -22636 -22637 -22638 -22639 -22640 -22641 -22642 -22643 -22644 -22645 -22646 +v -22647 -22648 -22649 -22650 -22651 -22652 -22653 -22654 -22655 -22656 -22657 +v -22658 -22659 -22660 -22661 -22662 -22663 -22664 -22665 -22666 -22667 -22668 +v -22669 -22670 -22671 -22672 -22673 -22674 -22675 -22676 -22677 -22678 -22679 +v -22680 -22681 -22682 -22683 -22684 -22685 -22686 -22687 -22688 -22689 -22690 +v -22691 -22692 -22693 -22694 -22695 -22696 -22697 -22698 -22699 -22700 -22701 +v -22702 -22703 -22704 -22705 -22706 -22707 -22708 -22709 -22710 -22711 -22712 +v -22713 -22714 -22715 -22716 -22717 -22718 -22719 -22720 -22721 -22722 -22723 +v -22724 -22725 -22726 -22727 -22728 -22729 -22730 -22731 -22732 -22733 -22734 +v -22735 -22736 -22737 -22738 -22739 -22740 -22741 -22742 -22743 -22744 -22745 +v -22746 -22747 -22748 -22749 -22750 -22751 -22752 -22753 -22754 -22755 -22756 +v -22757 -22758 -22759 -22760 -22761 -22762 -22763 -22764 -22765 -22766 -22767 +v -22768 -22769 -22770 -22771 -22772 -22773 -22774 -22775 -22776 -22777 -22778 +v -22779 -22780 -22781 -22782 -22783 -22784 -22785 -22786 -22787 -22788 -22789 +v -22790 -22791 -22792 -22793 -22794 -22795 -22796 -22797 -22798 -22799 -22800 +v -22801 -22802 -22803 -22804 -22805 -22806 -22807 -22808 -22809 -22810 -22811 +v -22812 -22813 -22814 -22815 -22816 -22817 -22818 -22819 -22820 -22821 -22822 +v -22823 -22824 -22825 -22826 -22827 -22828 -22829 -22830 -22831 -22832 -22833 +v -22834 -22835 -22836 -22837 -22838 -22839 -22840 -22841 -22842 -22843 -22844 +v -22845 -22846 -22847 -22848 -22849 -22850 -22851 -22852 -22853 -22854 -22855 +v -22856 -22857 -22858 -22859 -22860 -22861 -22862 -22863 -22864 -22865 -22866 +v -22867 -22868 -22869 -22870 -22871 -22872 -22873 -22874 -22875 -22876 22877 +v -22878 22879 -22880 -22881 -22882 22883 -22884 22885 -22886 -22887 -22888 +v 22889 -22890 22891 -22892 -22893 -22894 22895 -22896 22897 -22898 -22899 +v -22900 22901 -22902 22903 -22904 -22905 -22906 22907 -22908 22909 -22910 +v -22911 22912 -22913 -22914 -22915 -22916 -22917 -22918 -22919 -22920 -22921 +v -22922 -22923 -22924 -22925 -22926 22927 22928 22929 22930 22931 -22932 +v -22933 -22934 -22935 -22936 -22937 22938 -22939 -22940 -22941 -22942 -22943 +v -22944 -22945 -22946 -22947 -22948 -22949 -22950 -22951 -22952 -22953 -22954 +v -22955 -22956 -22957 -22958 -22959 -22960 -22961 -22962 -22963 -22964 -22965 +v -22966 -22967 -22968 -22969 -22970 -22971 -22972 -22973 -22974 -22975 -22976 +v -22977 -22978 -22979 -22980 -22981 -22982 -22983 -22984 -22985 -22986 -22987 +v -22988 -22989 -22990 -22991 -22992 -22993 -22994 -22995 -22996 -22997 -22998 +v -22999 -23000 -23001 -23002 -23003 -23004 -23005 -23006 -23007 -23008 -23009 +v -23010 -23011 -23012 -23013 -23014 -23015 -23016 -23017 -23018 -23019 -23020 +v -23021 -23022 -23023 -23024 -23025 -23026 -23027 -23028 -23029 -23030 -23031 +v -23032 -23033 -23034 -23035 -23036 -23037 -23038 -23039 -23040 -23041 -23042 +v -23043 -23044 -23045 -23046 -23047 -23048 -23049 -23050 -23051 -23052 -23053 +v -23054 -23055 -23056 -23057 -23058 -23059 -23060 -23061 -23062 -23063 -23064 +v -23065 -23066 -23067 23068 -23069 23070 -23071 -23072 -23073 23074 -23075 +v 23076 -23077 -23078 -23079 23080 -23081 23082 -23083 -23084 -23085 23086 +v -23087 23088 -23089 -23090 -23091 23092 -23093 23094 -23095 -23096 23097 +v -23098 -23099 -23100 -23101 -23102 -23103 -23104 -23105 -23106 -23107 -23108 +v 23109 23110 23111 -23112 -23113 -23114 -23115 -23116 -23117 -23118 -23119 +v -23120 -23121 -23122 -23123 -23124 -23125 -23126 -23127 -23128 -23129 -23130 +v -23131 -23132 -23133 -23134 -23135 -23136 -23137 -23138 -23139 -23140 -23141 +v -23142 -23143 -23144 -23145 -23146 -23147 -23148 -23149 -23150 -23151 -23152 +v -23153 -23154 -23155 -23156 -23157 -23158 -23159 -23160 -23161 -23162 -23163 +v -23164 23165 -23166 23167 -23168 -23169 23170 -23171 23172 -23173 -23174 +v -23175 23176 -23177 23178 -23179 -23180 -23181 23182 -23183 23184 -23185 +v -23186 23187 -23188 -23189 -23190 -23191 -23192 -23193 -23194 -23195 -23196 +v -23197 23198 23199 23200 23201 -23202 -23203 -23204 -23205 -23206 -23207 +v -23208 -23209 -23210 -23211 -23212 -23213 -23214 -23215 -23216 -23217 -23218 +v -23219 -23220 -23221 -23222 -23223 -23224 -23225 -23226 -23227 -23228 -23229 +v -23230 -23231 -23232 -23233 -23234 -23235 -23236 -23237 -23238 -23239 -23240 +v -23241 -23242 -23243 -23244 -23245 -23246 -23247 -23248 -23249 -23250 -23251 +v -23252 -23253 -23254 -23255 -23256 -23257 -23258 -23259 -23260 -23261 -23262 +v -23263 -23264 -23265 -23266 -23267 -23268 -23269 -23270 -23271 -23272 -23273 +v -23274 -23275 -23276 -23277 -23278 -23279 -23280 -23281 -23282 -23283 -23284 +v -23285 -23286 -23287 -23288 -23289 -23290 -23291 -23292 -23293 -23294 -23295 +v -23296 23297 -23298 23299 -23300 -23301 23302 -23303 23304 -23305 -23306 +v 23307 -23308 23309 -23310 -23311 -23312 23313 -23314 23315 -23316 -23317 +v -23318 23319 -23320 23321 -23322 -23323 23324 -23325 -23326 -23327 -23328 +v -23329 -23330 -23331 -23332 -23333 -23334 -23335 23336 23337 23338 -23339 +v -23340 -23341 -23342 -23343 -23344 -23345 -23346 -23347 -23348 -23349 -23350 +v -23351 23352 -23353 -23354 23355 -23356 -23357 -23358 -23359 -23360 -23361 +v 23362 23363 23364 -23365 -23366 23367 23368 23369 23370 23371 23372 23373 +v 23374 23375 23376 -23377 -23378 23379 23380 23381 23382 23383 23384 -23385 +v 23386 23387 23388 -23389 -23390 -23391 -23392 -23393 -23394 23395 -23396 +v 23397 23398 -23399 -23400 -23401 -23402 -23403 -23404 -23405 -23406 -23407 +v -23408 23409 -23410 -23411 -23412 23413 -23414 -23415 23416 23417 23418 +v 23419 23420 23421 23422 23423 23424 23425 -23426 -23427 23428 23429 23430 +v 23431 23432 23433 -23434 23435 23436 -23437 -23438 23439 23440 23441 23442 +v -23443 -23444 23445 23446 -23447 -23448 -23449 23450 -23451 23452 -23453 +v -23454 23455 -23456 -23457 -23458 -23459 -23460 -23461 -23462 -23463 23464 +v 23465 23466 -23467 -23468 -23469 -23470 -23471 -23472 -23473 -23474 -23475 +v -23476 -23477 -23478 -23479 -23480 -23481 -23482 -23483 -23484 -23485 -23486 +v -23487 -23488 23489 -23490 -23491 -23492 -23493 -23494 -23495 -23496 23497 +v -23498 23499 -23500 -23501 -23502 23503 -23504 23505 -23506 -23507 23508 +v -23509 -23510 -23511 -23512 -23513 -23514 23515 23516 23517 -23518 -23519 +v -23520 -23521 -23522 -23523 -23524 -23525 -23526 -23527 -23528 -23529 -23530 +v -23531 -23532 -23533 -23534 -23535 -23536 -23537 -23538 -23539 23540 -23541 +v -23542 -23543 -23544 -23545 -23546 -23547 23548 -23549 23550 -23551 -23552 +v -23553 23554 -23555 23556 -23557 -23558 23559 -23560 -23561 -23562 -23563 +v -23564 -23565 23566 23567 23568 -23569 -23570 -23571 -23572 -23573 -23574 +v -23575 -23576 -23577 -23578 -23579 -23580 -23581 -23582 -23583 -23584 -23585 +v -23586 -23587 -23588 -23589 -23590 23591 -23592 -23593 -23594 -23595 -23596 +v -23597 -23598 23599 -23600 23601 -23602 -23603 -23604 23605 -23606 23607 +v -23608 -23609 23610 -23611 -23612 -23613 -23614 -23615 -23616 23617 23618 +v 23619 -23620 -23621 -23622 -23623 -23624 -23625 -23626 -23627 -23628 -23629 +v -23630 -23631 -23632 -23633 -23634 -23635 -23636 -23637 -23638 -23639 -23640 +v -23641 -23642 -23643 -23644 -23645 -23646 -23647 -23648 -23649 -23650 -23651 +v -23652 -23653 -23654 -23655 -23656 -23657 -23658 -23659 -23660 -23661 -23662 +v -23663 -23664 -23665 -23666 -23667 -23668 -23669 -23670 -23671 -23672 -23673 +v -23674 -23675 -23676 -23677 -23678 -23679 -23680 -23681 -23682 -23683 -23684 +v -23685 -23686 -23687 -23688 -23689 -23690 -23691 -23692 -23693 -23694 -23695 +v -23696 -23697 -23698 -23699 -23700 -23701 -23702 -23703 -23704 -23705 -23706 +v -23707 -23708 -23709 -23710 -23711 -23712 23713 -23714 -23715 -23716 -23717 +v -23718 -23719 -23720 -23721 -23722 -23723 -23724 -23725 -23726 -23727 -23728 +v -23729 -23730 -23731 -23732 -23733 -23734 -23735 -23736 -23737 -23738 -23739 +v -23740 -23741 -23742 -23743 -23744 -23745 -23746 -23747 -23748 -23749 -23750 +v -23751 -23752 -23753 -23754 -23755 -23756 -23757 -23758 -23759 -23760 -23761 +v -23762 -23763 -23764 -23765 -23766 -23767 -23768 -23769 -23770 -23771 -23772 +v -23773 -23774 -23775 -23776 -23777 -23778 -23779 -23780 -23781 23782 -23783 +v 23784 -23785 -23786 -23787 23788 -23789 23790 -23791 -23792 -23793 -23794 +v 23795 -23796 23797 -23798 -23799 -23800 -23801 23802 -23803 23804 -23805 +v -23806 23807 -23808 -23809 -23810 -23811 -23812 -23813 -23814 -23815 -23816 +v -23817 23818 23819 23820 -23821 -23822 -23823 -23824 -23825 -23826 -23827 +v -23828 -23829 -23830 -23831 -23832 -23833 -23834 -23835 -23836 -23837 -23838 +v -23839 -23840 -23841 -23842 -23843 -23844 -23845 -23846 -23847 -23848 -23849 +v -23850 -23851 -23852 -23853 -23854 -23855 -23856 -23857 -23858 -23859 -23860 +v -23861 -23862 -23863 -23864 -23865 -23866 -23867 -23868 -23869 -23870 -23871 +v -23872 -23873 -23874 -23875 -23876 -23877 -23878 -23879 -23880 -23881 -23882 +v -23883 -23884 -23885 -23886 -23887 -23888 -23889 -23890 -23891 -23892 -23893 +v -23894 -23895 -23896 -23897 -23898 -23899 -23900 -23901 -23902 -23903 -23904 +v -23905 -23906 -23907 -23908 -23909 -23910 -23911 -23912 -23913 23914 -23915 +v -23916 -23917 -23918 -23919 -23920 -23921 -23922 -23923 -23924 -23925 -23926 +v -23927 -23928 -23929 -23930 -23931 -23932 -23933 -23934 -23935 -23936 -23937 +v -23938 -23939 -23940 -23941 -23942 -23943 -23944 -23945 -23946 -23947 -23948 +v -23949 -23950 -23951 -23952 -23953 -23954 -23955 -23956 -23957 -23958 -23959 +v -23960 -23961 -23962 -23963 -23964 -23965 -23966 -23967 -23968 -23969 -23970 +v -23971 -23972 -23973 -23974 -23975 -23976 -23977 -23978 -23979 -23980 -23981 +v -23982 23983 -23984 23985 -23986 -23987 -23988 23989 -23990 23991 -23992 +v -23993 -23994 -23995 23996 -23997 23998 -23999 -24000 -24001 -24002 24003 +v -24004 24005 -24006 -24007 24008 -24009 -24010 -24011 -24012 -24013 -24014 +v -24015 -24016 -24017 -24018 24019 24020 24021 -24022 -24023 -24024 -24025 +v -24026 -24027 -24028 -24029 -24030 -24031 -24032 -24033 -24034 -24035 -24036 +v -24037 -24038 -24039 -24040 -24041 -24042 -24043 -24044 -24045 -24046 -24047 +v -24048 -24049 -24050 -24051 -24052 -24053 -24054 -24055 -24056 -24057 -24058 +v -24059 -24060 -24061 -24062 -24063 -24064 -24065 -24066 -24067 -24068 -24069 +v -24070 -24071 -24072 -24073 -24074 -24075 -24076 -24077 -24078 -24079 -24080 +v -24081 -24082 -24083 -24084 -24085 -24086 -24087 -24088 -24089 -24090 -24091 +v -24092 -24093 -24094 -24095 -24096 -24097 -24098 -24099 -24100 -24101 -24102 +v -24103 -24104 -24105 -24106 -24107 -24108 -24109 -24110 -24111 -24112 -24113 +v -24114 24115 -24116 -24117 -24118 -24119 -24120 -24121 -24122 -24123 -24124 +v -24125 -24126 -24127 -24128 -24129 -24130 -24131 -24132 -24133 -24134 -24135 +v -24136 -24137 -24138 -24139 -24140 -24141 -24142 -24143 -24144 -24145 -24146 +v -24147 -24148 -24149 -24150 -24151 -24152 -24153 -24154 -24155 -24156 -24157 +v -24158 -24159 -24160 -24161 -24162 -24163 -24164 -24165 -24166 -24167 -24168 +v -24169 -24170 -24171 -24172 -24173 -24174 -24175 -24176 -24177 -24178 -24179 +v -24180 -24181 -24182 -24183 24184 -24185 24186 -24187 -24188 -24189 24190 +v -24191 24192 -24193 -24194 -24195 -24196 24197 -24198 24199 -24200 -24201 +v -24202 -24203 24204 -24205 24206 -24207 -24208 24209 -24210 -24211 -24212 +v -24213 -24214 -24215 -24216 -24217 -24218 -24219 24220 24221 24222 -24223 +v -24224 -24225 -24226 -24227 -24228 -24229 -24230 -24231 -24232 -24233 -24234 +v -24235 -24236 -24237 -24238 -24239 -24240 -24241 -24242 -24243 -24244 -24245 +v -24246 -24247 -24248 -24249 -24250 -24251 -24252 -24253 -24254 -24255 -24256 +v -24257 -24258 -24259 -24260 -24261 -24262 -24263 -24264 -24265 -24266 -24267 +v -24268 -24269 -24270 -24271 -24272 -24273 -24274 -24275 -24276 -24277 -24278 +v -24279 -24280 -24281 -24282 -24283 -24284 -24285 -24286 -24287 -24288 -24289 +v -24290 -24291 -24292 -24293 -24294 -24295 -24296 -24297 -24298 -24299 -24300 +v -24301 -24302 -24303 -24304 -24305 -24306 -24307 -24308 -24309 -24310 -24311 +v -24312 -24313 -24314 -24315 24316 -24317 -24318 -24319 -24320 -24321 -24322 +v -24323 -24324 -24325 -24326 -24327 -24328 -24329 -24330 -24331 -24332 -24333 +v -24334 -24335 -24336 -24337 -24338 -24339 -24340 -24341 -24342 -24343 -24344 +v -24345 -24346 -24347 -24348 -24349 -24350 -24351 -24352 -24353 -24354 -24355 +v -24356 -24357 -24358 -24359 -24360 -24361 -24362 -24363 -24364 -24365 -24366 +v -24367 -24368 -24369 -24370 -24371 -24372 -24373 -24374 -24375 -24376 -24377 +v -24378 -24379 -24380 -24381 -24382 -24383 -24384 24385 -24386 24387 -24388 +v -24389 -24390 24391 -24392 24393 -24394 -24395 -24396 -24397 24398 -24399 +v 24400 -24401 -24402 -24403 -24404 24405 -24406 24407 -24408 -24409 24410 +v -24411 -24412 -24413 -24414 -24415 -24416 -24417 -24418 -24419 -24420 24421 +v 24422 24423 -24424 -24425 -24426 -24427 -24428 -24429 -24430 -24431 -24432 +v -24433 -24434 -24435 -24436 -24437 -24438 -24439 -24440 -24441 -24442 -24443 +v -24444 -24445 24446 -24447 -24448 -24449 -24450 -24451 -24452 -24453 24454 +v -24455 24456 -24457 -24458 -24459 24460 -24461 24462 -24463 -24464 24465 +v -24466 -24467 -24468 -24469 -24470 -24471 24472 24473 24474 -24475 -24476 +v -24477 -24478 -24479 -24480 -24481 -24482 -24483 -24484 -24485 -24486 -24487 +v -24488 -24489 -24490 -24491 -24492 -24493 -24494 -24495 -24496 -24497 -24498 +v -24499 -24500 -24501 -24502 -24503 24504 -24505 24506 -24507 -24508 -24509 +v 24510 -24511 24512 -24513 -24514 24515 -24516 -24517 -24518 -24519 -24520 +v -24521 24522 24523 24524 24525 -24526 -24527 -24528 -24529 -24530 -24531 +v -24532 -24533 -24534 -24535 -24536 -24537 -24538 -24539 -24540 -24541 -24542 +v -24543 -24544 -24545 -24546 -24547 -24548 -24549 -24550 -24551 -24552 -24553 +v -24554 24555 -24556 24557 -24558 -24559 -24560 24561 -24562 24563 -24564 +v -24565 24566 -24567 -24568 -24569 -24570 -24571 -24572 24573 24574 24575 +v 24576 -24577 -24578 -24579 -24580 -24581 -24582 -24583 -24584 -24585 -24586 +v -24587 -24588 -24589 -24590 -24591 -24592 -24593 -24594 -24595 -24596 -24597 +v -24598 -24599 -24600 -24601 -24602 -24603 -24604 -24605 24606 -24607 24608 +v -24609 -24610 -24611 24612 -24613 24614 -24615 -24616 24617 -24618 -24619 +v -24620 -24621 -24622 -24623 24624 24625 24626 24627 -24628 -24629 -24630 +v -24631 -24632 -24633 -24634 -24635 -24636 -24637 -24638 -24639 -24640 -24641 +v -24642 -24643 -24644 -24645 -24646 -24647 -24648 -24649 -24650 -24651 -24652 +v -24653 -24654 -24655 -24656 -24657 -24658 -24659 -24660 -24661 -24662 -24663 +v -24664 -24665 -24666 -24667 -24668 -24669 -24670 -24671 -24672 -24673 -24674 +v -24675 -24676 -24677 -24678 -24679 -24680 -24681 -24682 -24683 -24684 -24685 +v -24686 -24687 -24688 -24689 -24690 -24691 -24692 -24693 -24694 -24695 -24696 +v -24697 -24698 -24699 -24700 -24701 -24702 -24703 -24704 -24705 -24706 -24707 +v -24708 -24709 -24710 -24711 -24712 -24713 -24714 -24715 -24716 -24717 -24718 +v -24719 -24720 -24721 -24722 -24723 -24724 -24725 -24726 -24727 -24728 -24729 +v -24730 -24731 -24732 -24733 -24734 -24735 -24736 -24737 -24738 -24739 -24740 +v -24741 -24742 -24743 -24744 -24745 -24746 -24747 -24748 -24749 -24750 -24751 +v -24752 -24753 -24754 -24755 -24756 -24757 -24758 -24759 -24760 -24761 -24762 +v -24763 -24764 -24765 -24766 -24767 -24768 -24769 -24770 -24771 -24772 -24773 +v -24774 -24775 -24776 -24777 -24778 -24779 -24780 -24781 -24782 -24783 -24784 +v -24785 -24786 -24787 -24788 24789 -24790 24791 -24792 -24793 -24794 24795 +v -24796 24797 -24798 -24799 -24800 -24801 24802 -24803 24804 -24805 -24806 +v -24807 -24808 24809 -24810 24811 -24812 -24813 24814 -24815 -24816 -24817 +v -24818 -24819 -24820 -24821 -24822 -24823 -24824 24825 24826 24827 24828 +v -24829 -24830 -24831 -24832 -24833 -24834 -24835 -24836 -24837 -24838 -24839 +v -24840 -24841 -24842 -24843 -24844 -24845 -24846 -24847 -24848 -24849 -24850 +v -24851 -24852 -24853 -24854 -24855 -24856 -24857 -24858 -24859 -24860 -24861 +v -24862 -24863 -24864 -24865 -24866 -24867 -24868 -24869 -24870 -24871 -24872 +v -24873 -24874 -24875 -24876 -24877 -24878 -24879 -24880 -24881 -24882 -24883 +v -24884 -24885 -24886 -24887 -24888 -24889 -24890 -24891 -24892 -24893 -24894 +v -24895 -24896 -24897 -24898 -24899 -24900 -24901 -24902 -24903 -24904 -24905 +v -24906 -24907 -24908 -24909 -24910 -24911 -24912 -24913 -24914 -24915 -24916 +v -24917 -24918 -24919 -24920 -24921 -24922 -24923 -24924 -24925 -24926 -24927 +v -24928 -24929 -24930 -24931 -24932 -24933 -24934 -24935 -24936 -24937 -24938 +v -24939 -24940 -24941 -24942 -24943 -24944 -24945 -24946 -24947 -24948 -24949 +v -24950 -24951 -24952 -24953 -24954 -24955 -24956 -24957 -24958 -24959 -24960 +v -24961 -24962 -24963 -24964 -24965 -24966 -24967 -24968 -24969 -24970 -24971 +v -24972 -24973 -24974 -24975 -24976 -24977 -24978 -24979 -24980 -24981 -24982 +v -24983 -24984 -24985 -24986 -24987 -24988 -24989 24990 -24991 24992 -24993 +v -24994 -24995 24996 -24997 24998 -24999 -25000 -25001 -25002 25003 -25004 +v 25005 -25006 -25007 -25008 -25009 25010 -25011 25012 -25013 -25014 25015 +v -25016 -25017 -25018 -25019 -25020 -25021 -25022 -25023 -25024 -25025 25026 +v 25027 25028 25029 -25030 -25031 -25032 -25033 -25034 -25035 -25036 -25037 +v -25038 -25039 -25040 -25041 -25042 -25043 -25044 -25045 -25046 -25047 -25048 +v -25049 -25050 -25051 -25052 -25053 -25054 -25055 -25056 -25057 -25058 -25059 +v -25060 -25061 -25062 -25063 -25064 -25065 -25066 -25067 -25068 -25069 -25070 +v -25071 -25072 -25073 -25074 -25075 -25076 -25077 -25078 -25079 -25080 -25081 +v -25082 -25083 -25084 -25085 -25086 -25087 -25088 -25089 -25090 -25091 -25092 +v -25093 -25094 -25095 -25096 -25097 -25098 -25099 -25100 -25101 -25102 -25103 +v -25104 -25105 -25106 -25107 -25108 -25109 -25110 -25111 -25112 -25113 -25114 +v -25115 -25116 -25117 -25118 -25119 -25120 -25121 -25122 -25123 -25124 -25125 +v -25126 -25127 -25128 -25129 -25130 -25131 -25132 -25133 -25134 -25135 -25136 +v -25137 -25138 -25139 -25140 -25141 -25142 -25143 -25144 -25145 -25146 -25147 +v -25148 -25149 -25150 -25151 -25152 -25153 -25154 -25155 -25156 -25157 -25158 +v -25159 -25160 -25161 -25162 -25163 -25164 -25165 -25166 -25167 -25168 -25169 +v -25170 -25171 -25172 -25173 -25174 -25175 -25176 -25177 -25178 -25179 -25180 +v -25181 -25182 -25183 -25184 -25185 -25186 -25187 -25188 -25189 -25190 25191 +v -25192 25193 -25194 -25195 -25196 25197 -25198 25199 -25200 -25201 -25202 +v -25203 25204 -25205 25206 -25207 -25208 -25209 -25210 25211 -25212 25213 +v -25214 -25215 25216 -25217 -25218 -25219 -25220 -25221 -25222 -25223 -25224 +v -25225 -25226 25227 25228 25229 25230 -25231 -25232 -25233 -25234 -25235 +v -25236 -25237 -25238 -25239 -25240 -25241 -25242 -25243 -25244 -25245 -25246 +v -25247 -25248 -25249 -25250 -25251 -25252 -25253 -25254 -25255 -25256 -25257 +v -25258 -25259 -25260 -25261 -25262 -25263 -25264 -25265 -25266 -25267 -25268 +v -25269 -25270 -25271 -25272 -25273 -25274 -25275 -25276 -25277 -25278 -25279 +v -25280 -25281 -25282 -25283 -25284 -25285 -25286 -25287 -25288 -25289 -25290 +v -25291 -25292 -25293 -25294 -25295 -25296 -25297 -25298 -25299 -25300 -25301 +v -25302 -25303 -25304 -25305 -25306 -25307 -25308 -25309 -25310 -25311 -25312 +v -25313 -25314 -25315 -25316 -25317 -25318 -25319 -25320 -25321 -25322 -25323 +v -25324 -25325 -25326 -25327 -25328 -25329 -25330 -25331 -25332 -25333 -25334 +v -25335 -25336 -25337 -25338 -25339 -25340 -25341 -25342 -25343 -25344 -25345 +v -25346 -25347 -25348 -25349 -25350 -25351 -25352 -25353 -25354 -25355 -25356 +v -25357 -25358 -25359 -25360 -25361 -25362 -25363 -25364 -25365 -25366 -25367 +v -25368 -25369 -25370 -25371 -25372 -25373 -25374 -25375 -25376 -25377 -25378 +v -25379 -25380 -25381 -25382 -25383 -25384 -25385 -25386 -25387 -25388 -25389 +v -25390 -25391 25392 -25393 25394 -25395 -25396 -25397 25398 -25399 25400 +v -25401 -25402 -25403 -25404 25405 -25406 25407 -25408 -25409 -25410 -25411 +v 25412 -25413 25414 -25415 -25416 25417 -25418 -25419 -25420 -25421 -25422 +v -25423 -25424 -25425 -25426 -25427 25428 25429 25430 25431 -25432 -25433 +v -25434 -25435 -25436 -25437 -25438 -25439 -25440 -25441 -25442 -25443 -25444 +v -25445 -25446 -25447 -25448 -25449 -25450 -25451 -25452 -25453 -25454 -25455 +v -25456 -25457 -25458 -25459 -25460 25461 -25462 25463 -25464 -25465 -25466 +v 25467 -25468 25469 -25470 -25471 25472 -25473 -25474 -25475 -25476 -25477 +v -25478 25479 25480 25481 25482 -25483 25484 -25485 25486 -25487 25488 25489 +v -25490 -25491 -25492 -25493 -25494 -25495 -25496 -25497 -25498 -25499 -25500 +v -25501 -25502 -25503 -25504 -25505 -25506 -25507 -25508 -25509 -25510 -25511 +v -25512 -25513 -25514 -25515 -25516 -25517 -25518 -25519 -25520 -25521 -25522 +v -25523 -25524 -25525 -25526 -25527 -25528 -25529 -25530 -25531 -25532 -25533 +v -25534 -25535 -25536 -25537 -25538 -25539 -25540 -25541 -25542 -25543 -25544 +v -25545 -25546 -25547 -25548 -25549 -25550 -25551 -25552 -25553 -25554 -25555 +v -25556 -25557 -25558 -25559 -25560 -25561 -25562 -25563 -25564 -25565 -25566 +v -25567 -25568 -25569 -25570 -25571 -25572 -25573 -25574 -25575 -25576 -25577 +v -25578 -25579 -25580 -25581 -25582 -25583 -25584 -25585 -25586 -25587 -25588 +v -25589 -25590 -25591 -25592 -25593 -25594 -25595 -25596 -25597 -25598 -25599 +v -25600 -25601 -25602 -25603 -25604 -25605 -25606 -25607 -25608 -25609 -25610 +v -25611 -25612 -25613 -25614 -25615 -25616 -25617 -25618 -25619 -25620 -25621 +v -25622 -25623 -25624 -25625 -25626 -25627 -25628 -25629 -25630 -25631 -25632 +v -25633 -25634 -25635 -25636 -25637 -25638 -25639 -25640 -25641 -25642 -25643 +v -25644 -25645 -25646 -25647 -25648 -25649 -25650 -25651 -25652 -25653 -25654 +v -25655 -25656 -25657 -25658 -25659 -25660 -25661 -25662 -25663 -25664 -25665 +v -25666 -25667 -25668 -25669 -25670 -25671 -25672 -25673 -25674 -25675 -25676 +v -25677 -25678 -25679 -25680 -25681 -25682 -25683 -25684 -25685 -25686 -25687 +v -25688 -25689 -25690 -25691 -25692 -25693 -25694 -25695 -25696 -25697 -25698 +v -25699 -25700 -25701 -25702 -25703 -25704 -25705 -25706 -25707 -25708 -25709 +v -25710 -25711 -25712 -25713 -25714 -25715 -25716 -25717 -25718 -25719 -25720 +v -25721 -25722 -25723 -25724 -25725 -25726 -25727 -25728 -25729 -25730 -25731 +v -25732 -25733 -25734 -25735 -25736 -25737 -25738 -25739 -25740 -25741 -25742 +v -25743 -25744 -25745 -25746 -25747 -25748 -25749 -25750 -25751 -25752 -25753 +v -25754 -25755 -25756 -25757 -25758 -25759 -25760 -25761 -25762 -25763 -25764 +v -25765 -25766 -25767 -25768 -25769 -25770 -25771 -25772 -25773 -25774 -25775 +v -25776 -25777 -25778 -25779 -25780 -25781 -25782 -25783 -25784 -25785 -25786 +v -25787 -25788 -25789 -25790 -25791 -25792 -25793 -25794 -25795 -25796 -25797 +v -25798 -25799 -25800 -25801 -25802 -25803 -25804 -25805 -25806 -25807 -25808 +v -25809 -25810 -25811 -25812 -25813 -25814 -25815 -25816 -25817 -25818 -25819 +v -25820 -25821 -25822 -25823 -25824 -25825 -25826 -25827 -25828 -25829 -25830 +v -25831 -25832 -25833 -25834 -25835 -25836 -25837 -25838 -25839 -25840 -25841 +v -25842 -25843 -25844 -25845 -25846 -25847 -25848 -25849 -25850 -25851 -25852 +v -25853 -25854 -25855 -25856 -25857 -25858 -25859 -25860 -25861 -25862 -25863 +v -25864 -25865 -25866 -25867 -25868 -25869 -25870 -25871 -25872 -25873 -25874 +v -25875 -25876 -25877 -25878 -25879 -25880 -25881 -25882 -25883 -25884 -25885 +v -25886 -25887 -25888 -25889 -25890 -25891 -25892 -25893 -25894 -25895 -25896 +v -25897 -25898 -25899 -25900 -25901 -25902 -25903 -25904 -25905 -25906 -25907 +v -25908 -25909 -25910 -25911 -25912 -25913 -25914 -25915 -25916 -25917 -25918 +v -25919 -25920 -25921 -25922 -25923 -25924 -25925 -25926 -25927 -25928 -25929 +v -25930 -25931 -25932 -25933 -25934 -25935 -25936 -25937 -25938 -25939 -25940 +v -25941 -25942 -25943 -25944 -25945 -25946 -25947 -25948 -25949 -25950 -25951 +v -25952 -25953 -25954 -25955 -25956 -25957 -25958 -25959 -25960 -25961 -25962 +v -25963 -25964 -25965 -25966 -25967 -25968 -25969 -25970 -25971 -25972 -25973 +v -25974 -25975 -25976 -25977 -25978 -25979 -25980 -25981 -25982 -25983 -25984 +v -25985 -25986 -25987 -25988 -25989 -25990 -25991 -25992 -25993 -25994 -25995 +v -25996 -25997 -25998 -25999 -26000 -26001 -26002 -26003 -26004 -26005 -26006 +v -26007 -26008 -26009 -26010 -26011 -26012 -26013 -26014 -26015 -26016 -26017 +v -26018 -26019 -26020 -26021 -26022 -26023 -26024 -26025 -26026 -26027 -26028 +v 26029 -26030 26031 -26032 -26033 26034 -26035 26036 -26037 -26038 26039 +v -26040 26041 -26042 -26043 -26044 26045 -26046 26047 -26048 -26049 -26050 +v 26051 -26052 26053 -26054 -26055 -26056 26057 -26058 26059 -26060 -26061 +v 26062 -26063 -26064 -26065 -26066 -26067 -26068 -26069 -26070 -26071 -26072 +v -26073 -26074 -26075 -26076 26077 26078 26079 26080 26081 -26082 -26083 +v -26084 -26085 -26086 -26087 26088 -26089 -26090 -26091 -26092 -26093 -26094 +v -26095 -26096 -26097 -26098 -26099 -26100 -26101 -26102 -26103 -26104 -26105 +v -26106 -26107 -26108 -26109 -26110 -26111 -26112 -26113 -26114 -26115 -26116 +v -26117 -26118 -26119 -26120 -26121 -26122 -26123 -26124 -26125 -26126 -26127 +v -26128 -26129 -26130 -26131 -26132 -26133 -26134 -26135 -26136 -26137 -26138 +v -26139 -26140 -26141 -26142 -26143 -26144 -26145 -26146 -26147 -26148 -26149 +v -26150 -26151 -26152 -26153 -26154 -26155 -26156 -26157 -26158 -26159 -26160 +v -26161 -26162 -26163 -26164 -26165 -26166 -26167 -26168 -26169 -26170 -26171 +v -26172 -26173 -26174 -26175 -26176 -26177 -26178 -26179 -26180 -26181 -26182 +v -26183 -26184 -26185 -26186 -26187 -26188 -26189 -26190 -26191 -26192 -26193 +v -26194 -26195 -26196 -26197 -26198 -26199 -26200 -26201 -26202 -26203 -26204 +v -26205 -26206 -26207 -26208 -26209 -26210 -26211 -26212 -26213 -26214 -26215 +v -26216 -26217 26218 -26219 26220 -26221 -26222 -26223 26224 -26225 26226 +v -26227 -26228 -26229 26230 -26231 26232 -26233 -26234 -26235 26236 -26237 +v 26238 -26239 -26240 -26241 26242 -26243 26244 -26245 -26246 26247 -26248 +v -26249 -26250 -26251 -26252 -26253 -26254 -26255 -26256 -26257 -26258 26259 +v 26260 26261 -26262 -26263 -26264 -26265 -26266 -26267 -26268 -26269 -26270 +v -26271 -26272 -26273 -26274 -26275 -26276 -26277 -26278 -26279 -26280 -26281 +v -26282 -26283 -26284 -26285 -26286 -26287 -26288 -26289 -26290 -26291 -26292 +v -26293 -26294 -26295 -26296 -26297 -26298 -26299 -26300 -26301 -26302 -26303 +v -26304 -26305 -26306 -26307 -26308 -26309 -26310 -26311 -26312 -26313 -26314 +v 26315 -26316 26317 -26318 -26319 26320 -26321 26322 -26323 -26324 -26325 +v 26326 -26327 26328 -26329 -26330 -26331 26332 -26333 26334 -26335 -26336 +v 26337 -26338 -26339 -26340 -26341 -26342 -26343 -26344 -26345 -26346 -26347 +v 26348 26349 26350 26351 -26352 -26353 -26354 -26355 -26356 -26357 -26358 +v -26359 -26360 -26361 -26362 -26363 -26364 -26365 -26366 -26367 -26368 -26369 +v -26370 -26371 -26372 -26373 -26374 -26375 -26376 -26377 -26378 -26379 -26380 +v -26381 -26382 -26383 -26384 -26385 -26386 -26387 -26388 -26389 -26390 -26391 +v -26392 -26393 -26394 -26395 -26396 -26397 -26398 -26399 -26400 -26401 -26402 +v -26403 -26404 -26405 -26406 -26407 -26408 -26409 -26410 -26411 -26412 -26413 +v -26414 -26415 -26416 -26417 -26418 -26419 -26420 -26421 26422 -26423 -26424 +v -26425 -26426 -26427 -26428 -26429 -26430 -26431 -26432 -26433 -26434 -26435 +v -26436 -26437 -26438 -26439 -26440 -26441 -26442 -26443 -26444 -26445 -26446 +v -26447 -26448 -26449 26450 -26451 26452 -26453 -26454 -26455 26456 -26457 +v 26458 -26459 -26460 -26461 26462 -26463 26464 -26465 -26466 -26467 26468 +v -26469 26470 -26471 -26472 26473 -26474 -26475 -26476 -26477 -26478 -26479 +v -26480 -26481 -26482 -26483 26484 26485 26486 -26487 -26488 -26489 -26490 +v -26491 -26492 -26493 -26494 -26495 -26496 -26497 -26498 -26499 26500 -26501 +v -26502 26503 -26504 -26505 -26506 -26507 -26508 -26509 26510 26511 26512 +v -26513 -26514 26515 26516 26517 26518 26519 26520 26521 26522 26523 26524 +v -26525 -26526 26527 26528 26529 26530 26531 26532 -26533 26534 26535 26536 +v -26537 -26538 -26539 -26540 -26541 -26542 26543 -26544 26545 26546 -26547 +v -26548 -26549 -26550 -26551 -26552 -26553 -26554 -26555 -26556 26557 -26558 +v -26559 -26560 26561 -26562 -26563 26564 26565 26566 26567 26568 26569 26570 +v 26571 26572 26573 -26574 -26575 26576 26577 26578 26579 26580 26581 -26582 +v 26583 26584 -26585 -26586 26587 26588 26589 26590 -26591 -26592 26593 26594 +v -26595 -26596 -26597 26598 -26599 26600 -26601 -26602 26603 -26604 -26605 +v -26606 -26607 -26608 -26609 -26610 -26611 26612 26613 26614 -26615 -26616 +v -26617 -26618 -26619 -26620 -26621 -26622 -26623 -26624 -26625 -26626 -26627 +v -26628 -26629 -26630 -26631 -26632 -26633 -26634 -26635 -26636 26637 -26638 +v -26639 -26640 -26641 -26642 -26643 -26644 26645 -26646 26647 -26648 -26649 +v -26650 26651 -26652 26653 -26654 -26655 26656 -26657 -26658 -26659 -26660 +v -26661 -26662 26663 26664 26665 -26666 -26667 -26668 -26669 -26670 -26671 +v -26672 -26673 -26674 -26675 -26676 -26677 -26678 -26679 -26680 -26681 -26682 +v -26683 -26684 -26685 -26686 -26687 26688 -26689 -26690 -26691 -26692 -26693 +v -26694 -26695 26696 -26697 26698 -26699 -26700 -26701 26702 -26703 26704 +v -26705 -26706 26707 -26708 -26709 -26710 -26711 -26712 -26713 26714 26715 +v 26716 -26717 -26718 -26719 -26720 -26721 -26722 -26723 -26724 -26725 -26726 +v -26727 -26728 -26729 -26730 -26731 -26732 -26733 -26734 -26735 -26736 -26737 +v -26738 26739 -26740 -26741 -26742 -26743 -26744 -26745 -26746 26747 -26748 +v 26749 -26750 -26751 -26752 26753 -26754 26755 -26756 -26757 26758 -26759 +v -26760 -26761 -26762 -26763 -26764 26765 26766 26767 -26768 -26769 -26770 +v -26771 -26772 -26773 -26774 -26775 -26776 -26777 -26778 -26779 -26780 -26781 +v -26782 -26783 -26784 -26785 -26786 -26787 -26788 -26789 -26790 -26791 -26792 +v -26793 -26794 -26795 -26796 -26797 -26798 -26799 -26800 -26801 -26802 -26803 +v -26804 -26805 -26806 -26807 -26808 -26809 -26810 -26811 -26812 -26813 -26814 +v -26815 -26816 -26817 -26818 -26819 -26820 -26821 -26822 -26823 -26824 -26825 +v -26826 -26827 -26828 -26829 -26830 -26831 -26832 -26833 -26834 -26835 -26836 +v -26837 -26838 -26839 -26840 -26841 -26842 -26843 -26844 -26845 -26846 -26847 +v -26848 -26849 -26850 -26851 -26852 -26853 -26854 -26855 -26856 -26857 -26858 +v -26859 -26860 26861 -26862 -26863 -26864 -26865 -26866 -26867 -26868 -26869 +v -26870 -26871 -26872 -26873 -26874 -26875 -26876 -26877 -26878 -26879 -26880 +v -26881 -26882 -26883 -26884 -26885 -26886 -26887 -26888 -26889 -26890 -26891 +v -26892 -26893 -26894 -26895 -26896 -26897 -26898 -26899 -26900 -26901 -26902 +v -26903 -26904 -26905 -26906 -26907 -26908 -26909 -26910 -26911 -26912 -26913 +v -26914 -26915 -26916 -26917 -26918 -26919 -26920 -26921 -26922 -26923 -26924 +v -26925 -26926 -26927 -26928 -26929 26930 -26931 26932 -26933 -26934 -26935 +v 26936 -26937 26938 -26939 -26940 -26941 -26942 26943 -26944 26945 -26946 +v -26947 -26948 -26949 26950 -26951 26952 -26953 -26954 26955 -26956 -26957 +v -26958 -26959 -26960 -26961 -26962 -26963 -26964 -26965 26966 26967 26968 +v -26969 -26970 -26971 -26972 -26973 -26974 -26975 -26976 -26977 -26978 -26979 +v -26980 -26981 -26982 -26983 -26984 -26985 -26986 -26987 -26988 -26989 -26990 +v -26991 -26992 -26993 -26994 -26995 -26996 -26997 -26998 -26999 -27000 -27001 +v -27002 -27003 -27004 -27005 -27006 -27007 -27008 -27009 -27010 -27011 -27012 +v -27013 -27014 -27015 -27016 -27017 -27018 -27019 -27020 -27021 -27022 -27023 +v -27024 -27025 -27026 -27027 -27028 -27029 -27030 -27031 -27032 -27033 -27034 +v -27035 -27036 -27037 -27038 -27039 -27040 -27041 -27042 -27043 -27044 -27045 +v -27046 -27047 -27048 -27049 -27050 -27051 -27052 -27053 -27054 -27055 -27056 +v -27057 -27058 -27059 -27060 -27061 27062 -27063 -27064 -27065 -27066 -27067 +v -27068 -27069 -27070 -27071 -27072 -27073 -27074 -27075 -27076 -27077 -27078 +v -27079 -27080 -27081 -27082 -27083 -27084 -27085 -27086 -27087 -27088 -27089 +v -27090 -27091 -27092 -27093 -27094 -27095 -27096 -27097 -27098 -27099 -27100 +v -27101 -27102 -27103 -27104 -27105 -27106 -27107 -27108 -27109 -27110 -27111 +v -27112 -27113 -27114 -27115 -27116 -27117 -27118 -27119 -27120 -27121 -27122 +v -27123 -27124 -27125 -27126 -27127 -27128 -27129 -27130 27131 -27132 27133 +v -27134 -27135 -27136 27137 -27138 27139 -27140 -27141 -27142 -27143 27144 +v -27145 27146 -27147 -27148 -27149 -27150 27151 -27152 27153 -27154 -27155 +v 27156 -27157 -27158 -27159 -27160 -27161 -27162 -27163 -27164 -27165 -27166 +v 27167 27168 27169 -27170 -27171 -27172 -27173 -27174 -27175 -27176 -27177 +v -27178 -27179 -27180 -27181 -27182 -27183 -27184 -27185 -27186 -27187 -27188 +v -27189 -27190 -27191 -27192 -27193 -27194 -27195 -27196 -27197 -27198 -27199 +v -27200 -27201 -27202 -27203 -27204 -27205 -27206 -27207 -27208 -27209 -27210 +v -27211 -27212 -27213 -27214 -27215 -27216 -27217 -27218 -27219 -27220 -27221 +v -27222 -27223 -27224 -27225 -27226 -27227 -27228 -27229 -27230 -27231 -27232 +v -27233 -27234 -27235 -27236 -27237 -27238 -27239 -27240 -27241 -27242 -27243 +v -27244 -27245 -27246 -27247 -27248 -27249 -27250 -27251 -27252 -27253 -27254 +v -27255 -27256 -27257 -27258 -27259 -27260 -27261 -27262 27263 -27264 -27265 +v -27266 -27267 -27268 -27269 -27270 -27271 -27272 -27273 -27274 -27275 -27276 +v -27277 -27278 -27279 -27280 -27281 -27282 -27283 -27284 -27285 -27286 -27287 +v -27288 -27289 -27290 -27291 -27292 -27293 -27294 -27295 -27296 -27297 -27298 +v -27299 -27300 -27301 -27302 -27303 -27304 -27305 -27306 -27307 -27308 -27309 +v -27310 -27311 -27312 -27313 -27314 -27315 -27316 -27317 -27318 -27319 -27320 +v -27321 -27322 -27323 -27324 -27325 -27326 -27327 -27328 -27329 -27330 -27331 +v 27332 -27333 27334 -27335 -27336 -27337 27338 -27339 27340 -27341 -27342 +v -27343 -27344 27345 -27346 27347 -27348 -27349 -27350 -27351 27352 -27353 +v 27354 -27355 -27356 27357 -27358 -27359 -27360 -27361 -27362 -27363 -27364 +v -27365 -27366 -27367 27368 27369 27370 -27371 -27372 -27373 -27374 -27375 +v -27376 -27377 -27378 -27379 -27380 -27381 -27382 -27383 -27384 -27385 -27386 +v -27387 -27388 -27389 -27390 -27391 -27392 -27393 -27394 -27395 -27396 -27397 +v -27398 -27399 -27400 -27401 -27402 -27403 -27404 -27405 -27406 -27407 -27408 +v -27409 -27410 -27411 -27412 -27413 -27414 -27415 -27416 -27417 -27418 -27419 +v -27420 -27421 -27422 -27423 -27424 -27425 -27426 -27427 -27428 -27429 -27430 +v -27431 -27432 -27433 -27434 -27435 -27436 -27437 -27438 -27439 -27440 -27441 +v -27442 -27443 -27444 -27445 -27446 -27447 -27448 -27449 -27450 -27451 -27452 +v -27453 -27454 -27455 -27456 -27457 -27458 -27459 -27460 -27461 -27462 -27463 +v 27464 -27465 -27466 -27467 -27468 -27469 -27470 -27471 -27472 -27473 -27474 +v -27475 -27476 -27477 -27478 -27479 -27480 -27481 -27482 -27483 -27484 -27485 +v -27486 -27487 -27488 -27489 -27490 -27491 -27492 -27493 -27494 -27495 -27496 +v -27497 -27498 -27499 -27500 -27501 -27502 -27503 -27504 -27505 -27506 -27507 +v -27508 -27509 -27510 -27511 -27512 -27513 -27514 -27515 -27516 -27517 -27518 +v -27519 -27520 -27521 -27522 -27523 -27524 -27525 -27526 -27527 -27528 -27529 +v -27530 -27531 -27532 27533 -27534 27535 -27536 -27537 -27538 27539 -27540 +v 27541 -27542 -27543 -27544 -27545 27546 -27547 27548 -27549 -27550 -27551 +v -27552 27553 -27554 27555 -27556 -27557 27558 -27559 -27560 -27561 -27562 +v -27563 -27564 -27565 -27566 -27567 -27568 27569 27570 27571 -27572 -27573 +v -27574 -27575 -27576 -27577 -27578 -27579 -27580 -27581 -27582 -27583 -27584 +v -27585 -27586 -27587 -27588 -27589 -27590 -27591 -27592 -27593 27594 -27595 +v -27596 -27597 -27598 -27599 -27600 -27601 27602 -27603 27604 -27605 -27606 +v -27607 27608 -27609 27610 -27611 -27612 27613 -27614 -27615 -27616 -27617 +v -27618 -27619 27620 27621 27622 -27623 -27624 -27625 -27626 -27627 -27628 +v -27629 -27630 -27631 -27632 -27633 -27634 -27635 -27636 -27637 -27638 -27639 +v -27640 -27641 -27642 -27643 -27644 -27645 -27646 -27647 -27648 -27649 -27650 +v -27651 27652 -27653 27654 -27655 -27656 -27657 27658 -27659 27660 -27661 +v -27662 27663 -27664 -27665 -27666 -27667 -27668 -27669 27670 27671 27672 +v 27673 -27674 -27675 -27676 -27677 -27678 -27679 -27680 -27681 -27682 -27683 +v -27684 -27685 -27686 -27687 -27688 -27689 -27690 -27691 -27692 -27693 -27694 +v -27695 -27696 -27697 -27698 -27699 -27700 -27701 -27702 27703 -27704 27705 +v -27706 -27707 -27708 27709 -27710 27711 -27712 -27713 27714 -27715 -27716 +v -27717 -27718 -27719 -27720 27721 27722 27723 27724 -27725 -27726 -27727 +v -27728 -27729 -27730 -27731 -27732 -27733 -27734 -27735 -27736 -27737 -27738 +v -27739 -27740 -27741 -27742 -27743 -27744 -27745 -27746 -27747 -27748 -27749 +v -27750 -27751 -27752 -27753 27754 -27755 27756 -27757 -27758 -27759 27760 +v -27761 27762 -27763 -27764 27765 -27766 -27767 -27768 -27769 -27770 -27771 +v 27772 27773 27774 27775 -27776 -27777 -27778 -27779 -27780 -27781 -27782 +v -27783 -27784 -27785 -27786 -27787 -27788 -27789 -27790 -27791 -27792 -27793 +v -27794 -27795 -27796 -27797 -27798 -27799 -27800 -27801 -27802 -27803 -27804 +v -27805 -27806 -27807 -27808 -27809 -27810 -27811 -27812 -27813 -27814 -27815 +v -27816 -27817 -27818 -27819 -27820 -27821 -27822 -27823 -27824 -27825 -27826 +v -27827 -27828 -27829 -27830 -27831 -27832 -27833 -27834 -27835 -27836 -27837 +v -27838 -27839 -27840 -27841 -27842 -27843 -27844 -27845 -27846 -27847 -27848 +v -27849 -27850 -27851 -27852 -27853 -27854 -27855 -27856 -27857 -27858 -27859 +v -27860 -27861 -27862 -27863 -27864 -27865 -27866 -27867 -27868 -27869 -27870 +v -27871 -27872 -27873 -27874 -27875 -27876 -27877 -27878 -27879 -27880 -27881 +v -27882 -27883 -27884 -27885 -27886 -27887 -27888 -27889 -27890 -27891 -27892 +v -27893 -27894 -27895 -27896 -27897 -27898 -27899 -27900 -27901 -27902 -27903 +v -27904 -27905 -27906 -27907 -27908 -27909 -27910 -27911 -27912 -27913 -27914 +v -27915 -27916 -27917 -27918 -27919 -27920 -27921 -27922 -27923 -27924 -27925 +v -27926 -27927 -27928 -27929 -27930 -27931 -27932 -27933 -27934 -27935 -27936 +v 27937 -27938 27939 -27940 -27941 -27942 27943 -27944 27945 -27946 -27947 +v -27948 -27949 27950 -27951 27952 -27953 -27954 -27955 -27956 27957 -27958 +v 27959 -27960 -27961 27962 -27963 -27964 -27965 -27966 -27967 -27968 -27969 +v -27970 -27971 -27972 27973 27974 27975 27976 -27977 -27978 -27979 -27980 +v -27981 -27982 -27983 -27984 -27985 -27986 -27987 -27988 -27989 -27990 -27991 +v -27992 -27993 -27994 -27995 -27996 -27997 -27998 -27999 -28000 -28001 -28002 +v -28003 -28004 -28005 -28006 -28007 -28008 -28009 -28010 -28011 -28012 -28013 +v -28014 -28015 -28016 -28017 -28018 -28019 -28020 -28021 -28022 -28023 -28024 +v -28025 -28026 -28027 -28028 -28029 -28030 -28031 -28032 -28033 -28034 -28035 +v -28036 -28037 -28038 -28039 -28040 -28041 -28042 -28043 -28044 -28045 -28046 +v -28047 -28048 -28049 -28050 -28051 -28052 -28053 -28054 -28055 -28056 -28057 +v -28058 -28059 -28060 -28061 -28062 -28063 -28064 -28065 -28066 -28067 -28068 +v -28069 -28070 -28071 -28072 -28073 -28074 -28075 -28076 -28077 -28078 -28079 +v -28080 -28081 -28082 -28083 -28084 -28085 -28086 -28087 -28088 -28089 -28090 +v -28091 -28092 -28093 -28094 -28095 -28096 -28097 -28098 -28099 -28100 -28101 +v -28102 -28103 -28104 -28105 -28106 -28107 -28108 -28109 -28110 -28111 -28112 +v -28113 -28114 -28115 -28116 -28117 -28118 -28119 -28120 -28121 -28122 -28123 +v -28124 -28125 -28126 -28127 -28128 -28129 -28130 -28131 -28132 -28133 -28134 +v -28135 -28136 -28137 28138 -28139 28140 -28141 -28142 -28143 28144 -28145 +v 28146 -28147 -28148 -28149 -28150 28151 -28152 28153 -28154 -28155 -28156 +v -28157 28158 -28159 28160 -28161 -28162 28163 -28164 -28165 -28166 -28167 +v -28168 -28169 -28170 -28171 -28172 -28173 28174 28175 28176 28177 -28178 +v -28179 -28180 -28181 -28182 -28183 -28184 -28185 -28186 -28187 -28188 -28189 +v -28190 -28191 -28192 -28193 -28194 -28195 -28196 -28197 -28198 -28199 -28200 +v -28201 -28202 -28203 -28204 -28205 -28206 -28207 -28208 -28209 -28210 -28211 +v -28212 -28213 -28214 -28215 -28216 -28217 -28218 -28219 -28220 -28221 -28222 +v -28223 -28224 -28225 -28226 -28227 -28228 -28229 -28230 -28231 -28232 -28233 +v -28234 -28235 -28236 -28237 -28238 -28239 -28240 -28241 -28242 -28243 -28244 +v -28245 -28246 -28247 -28248 -28249 -28250 -28251 -28252 -28253 -28254 -28255 +v -28256 -28257 -28258 -28259 -28260 -28261 -28262 -28263 -28264 -28265 -28266 +v -28267 -28268 -28269 -28270 -28271 -28272 -28273 -28274 -28275 -28276 -28277 +v -28278 -28279 -28280 -28281 -28282 -28283 -28284 -28285 -28286 -28287 -28288 +v -28289 -28290 -28291 -28292 -28293 -28294 -28295 -28296 -28297 -28298 -28299 +v -28300 -28301 -28302 -28303 -28304 -28305 -28306 -28307 -28308 -28309 -28310 +v -28311 -28312 -28313 -28314 -28315 -28316 -28317 -28318 -28319 -28320 -28321 +v -28322 -28323 -28324 -28325 -28326 -28327 -28328 -28329 -28330 -28331 -28332 +v -28333 -28334 -28335 -28336 -28337 -28338 28339 -28340 28341 -28342 -28343 +v -28344 28345 -28346 28347 -28348 -28349 -28350 -28351 28352 -28353 28354 +v -28355 -28356 -28357 -28358 28359 -28360 28361 -28362 -28363 28364 -28365 +v -28366 -28367 -28368 -28369 -28370 -28371 -28372 -28373 -28374 28375 28376 +v 28377 28378 -28379 -28380 -28381 -28382 -28383 -28384 -28385 -28386 -28387 +v -28388 -28389 -28390 -28391 -28392 -28393 -28394 -28395 -28396 -28397 -28398 +v -28399 -28400 -28401 -28402 -28403 -28404 -28405 -28406 -28407 -28408 -28409 +v -28410 -28411 -28412 -28413 -28414 -28415 -28416 -28417 -28418 -28419 -28420 +v -28421 -28422 -28423 -28424 -28425 -28426 -28427 -28428 -28429 -28430 -28431 +v -28432 -28433 -28434 -28435 -28436 -28437 -28438 -28439 -28440 -28441 -28442 +v -28443 -28444 -28445 -28446 -28447 -28448 -28449 -28450 -28451 -28452 -28453 +v -28454 -28455 -28456 -28457 -28458 -28459 -28460 -28461 -28462 -28463 -28464 +v -28465 -28466 -28467 -28468 -28469 -28470 -28471 -28472 -28473 -28474 -28475 +v -28476 -28477 -28478 -28479 -28480 -28481 -28482 -28483 -28484 -28485 -28486 +v -28487 -28488 -28489 -28490 -28491 -28492 -28493 -28494 -28495 -28496 -28497 +v -28498 -28499 -28500 -28501 -28502 -28503 -28504 -28505 -28506 -28507 -28508 +v -28509 -28510 -28511 -28512 -28513 -28514 -28515 -28516 -28517 -28518 -28519 +v -28520 -28521 -28522 -28523 -28524 -28525 -28526 -28527 -28528 -28529 -28530 +v -28531 -28532 -28533 -28534 -28535 -28536 -28537 -28538 -28539 28540 -28541 +v 28542 -28543 -28544 -28545 28546 -28547 28548 -28549 -28550 -28551 -28552 +v 28553 -28554 28555 -28556 -28557 -28558 -28559 28560 -28561 28562 -28563 +v -28564 28565 -28566 -28567 -28568 -28569 -28570 -28571 -28572 -28573 -28574 +v -28575 28576 28577 28578 28579 -28580 -28581 -28582 -28583 -28584 -28585 +v -28586 -28587 -28588 -28589 -28590 -28591 -28592 -28593 -28594 -28595 -28596 +v -28597 -28598 -28599 -28600 -28601 -28602 -28603 -28604 -28605 -28606 -28607 +v -28608 28609 -28610 28611 -28612 -28613 -28614 28615 -28616 28617 -28618 +v -28619 28620 -28621 -28622 -28623 -28624 -28625 -28626 28627 28628 28629 +v 28630 -28631 28632 -28633 28634 -28635 28636 28637 -28638 -28639 -28640 +v -28641 -28642 -28643 -28644 -28645 -28646 -28647 -28648 -28649 -28650 -28651 +v -28652 -28653 -28654 -28655 -28656 -28657 -28658 -28659 -28660 -28661 -28662 +v -28663 -28664 -28665 -28666 -28667 -28668 -28669 -28670 -28671 -28672 -28673 +v -28674 -28675 -28676 -28677 -28678 -28679 -28680 -28681 -28682 -28683 -28684 +v -28685 -28686 -28687 -28688 -28689 -28690 -28691 -28692 -28693 -28694 -28695 +v -28696 -28697 -28698 -28699 -28700 -28701 -28702 -28703 -28704 -28705 -28706 +v -28707 -28708 -28709 -28710 -28711 -28712 -28713 -28714 -28715 -28716 -28717 +v -28718 -28719 -28720 -28721 -28722 -28723 -28724 -28725 -28726 -28727 -28728 +v -28729 -28730 -28731 -28732 -28733 -28734 -28735 -28736 -28737 -28738 -28739 +v -28740 -28741 -28742 -28743 -28744 -28745 -28746 -28747 -28748 -28749 -28750 +v -28751 -28752 -28753 -28754 -28755 -28756 -28757 -28758 -28759 -28760 -28761 +v -28762 -28763 -28764 -28765 -28766 -28767 -28768 -28769 -28770 -28771 -28772 +v -28773 -28774 -28775 -28776 -28777 -28778 -28779 -28780 -28781 -28782 -28783 +v -28784 -28785 -28786 -28787 -28788 -28789 -28790 -28791 -28792 -28793 -28794 +v -28795 -28796 -28797 -28798 -28799 -28800 -28801 -28802 -28803 -28804 -28805 +v -28806 -28807 -28808 -28809 -28810 -28811 -28812 -28813 -28814 -28815 -28816 +v -28817 -28818 -28819 -28820 -28821 -28822 -28823 -28824 -28825 -28826 -28827 +v -28828 -28829 -28830 -28831 -28832 -28833 -28834 -28835 -28836 -28837 -28838 +v -28839 -28840 -28841 -28842 -28843 -28844 -28845 -28846 -28847 -28848 -28849 +v -28850 -28851 -28852 -28853 -28854 -28855 -28856 -28857 -28858 -28859 -28860 +v -28861 -28862 -28863 -28864 -28865 -28866 -28867 -28868 -28869 -28870 -28871 +v -28872 -28873 -28874 -28875 -28876 -28877 -28878 -28879 -28880 -28881 -28882 +v -28883 -28884 -28885 -28886 -28887 -28888 -28889 -28890 -28891 -28892 -28893 +v -28894 -28895 -28896 -28897 -28898 -28899 -28900 -28901 -28902 -28903 -28904 +v -28905 -28906 -28907 -28908 -28909 -28910 -28911 -28912 -28913 -28914 -28915 +v -28916 -28917 -28918 -28919 -28920 -28921 -28922 -28923 -28924 -28925 -28926 +v -28927 -28928 -28929 -28930 -28931 -28932 -28933 -28934 -28935 -28936 -28937 +v -28938 -28939 -28940 -28941 -28942 -28943 -28944 -28945 -28946 -28947 -28948 +v -28949 -28950 -28951 -28952 -28953 -28954 -28955 -28956 -28957 -28958 -28959 +v -28960 -28961 -28962 -28963 -28964 -28965 -28966 -28967 -28968 -28969 -28970 +v -28971 -28972 -28973 -28974 -28975 -28976 -28977 -28978 -28979 -28980 -28981 +v -28982 -28983 -28984 -28985 -28986 -28987 -28988 -28989 -28990 -28991 -28992 +v -28993 -28994 -28995 -28996 -28997 -28998 -28999 -29000 -29001 -29002 -29003 +v -29004 -29005 -29006 -29007 -29008 -29009 -29010 -29011 -29012 -29013 -29014 +v -29015 -29016 -29017 -29018 -29019 -29020 -29021 -29022 -29023 -29024 -29025 +v -29026 -29027 -29028 -29029 -29030 -29031 -29032 -29033 -29034 -29035 -29036 +v -29037 -29038 -29039 -29040 -29041 -29042 -29043 -29044 -29045 -29046 -29047 +v -29048 -29049 -29050 -29051 -29052 -29053 -29054 -29055 -29056 -29057 -29058 +v -29059 -29060 -29061 -29062 -29063 -29064 -29065 -29066 -29067 -29068 -29069 +v -29070 -29071 -29072 -29073 -29074 -29075 -29076 -29077 -29078 -29079 -29080 +v -29081 -29082 -29083 -29084 -29085 -29086 -29087 -29088 -29089 -29090 -29091 +v -29092 -29093 -29094 -29095 -29096 -29097 -29098 -29099 -29100 -29101 -29102 +v -29103 -29104 -29105 -29106 -29107 -29108 -29109 -29110 -29111 -29112 -29113 +v -29114 -29115 -29116 -29117 -29118 -29119 -29120 -29121 -29122 -29123 -29124 +v -29125 -29126 -29127 -29128 -29129 -29130 -29131 -29132 -29133 -29134 -29135 +v -29136 -29137 -29138 -29139 -29140 -29141 -29142 -29143 -29144 -29145 -29146 +v -29147 -29148 -29149 -29150 -29151 -29152 -29153 -29154 -29155 -29156 -29157 +v -29158 -29159 -29160 -29161 -29162 -29163 -29164 -29165 -29166 -29167 -29168 +v -29169 -29170 -29171 -29172 -29173 -29174 -29175 -29176 -29177 -29178 -29179 +v -29180 -29181 -29182 -29183 -29184 -29185 -29186 -29187 -29188 -29189 -29190 +v -29191 -29192 -29193 29194 -29195 29196 -29197 -29198 -29199 29200 -29201 +v 29202 -29203 -29204 -29205 29206 -29207 29208 -29209 -29210 -29211 29212 +v -29213 29214 -29215 -29216 -29217 29218 -29219 29220 -29221 -29222 -29223 +v 29224 -29225 29226 -29227 -29228 29229 -29230 -29231 -29232 -29233 -29234 +v -29235 -29236 -29237 -29238 -29239 -29240 -29241 -29242 -29243 29244 29245 +v 29246 29247 29248 -29249 -29250 -29251 -29252 -29253 -29254 29255 -29256 +v -29257 -29258 -29259 -29260 -29261 -29262 -29263 -29264 -29265 -29266 -29267 +v -29268 -29269 -29270 -29271 -29272 -29273 -29274 -29275 -29276 -29277 -29278 +v -29279 -29280 -29281 -29282 -29283 -29284 -29285 -29286 -29287 -29288 -29289 +v -29290 -29291 -29292 -29293 -29294 -29295 -29296 -29297 -29298 -29299 -29300 +v -29301 -29302 -29303 -29304 -29305 -29306 -29307 -29308 -29309 -29310 -29311 +v -29312 -29313 -29314 -29315 -29316 -29317 -29318 -29319 -29320 -29321 -29322 +v -29323 -29324 -29325 -29326 -29327 -29328 -29329 -29330 -29331 -29332 -29333 +v -29334 -29335 -29336 -29337 -29338 -29339 -29340 -29341 -29342 -29343 -29344 +v -29345 -29346 -29347 -29348 -29349 -29350 -29351 -29352 -29353 -29354 -29355 +v -29356 -29357 -29358 -29359 -29360 -29361 -29362 -29363 -29364 -29365 -29366 +v -29367 -29368 -29369 -29370 -29371 -29372 -29373 -29374 -29375 -29376 -29377 +v -29378 -29379 -29380 -29381 -29382 -29383 -29384 29385 -29386 29387 -29388 +v -29389 -29390 29391 -29392 29393 -29394 -29395 -29396 29397 -29398 29399 +v -29400 -29401 -29402 29403 -29404 29405 -29406 -29407 -29408 29409 -29410 +v 29411 -29412 -29413 29414 -29415 -29416 -29417 -29418 -29419 -29420 -29421 +v -29422 -29423 -29424 -29425 29426 29427 29428 -29429 -29430 -29431 -29432 +v -29433 -29434 -29435 -29436 -29437 -29438 -29439 -29440 -29441 -29442 -29443 +v -29444 -29445 -29446 -29447 -29448 -29449 -29450 -29451 -29452 -29453 -29454 +v -29455 -29456 -29457 -29458 -29459 -29460 -29461 -29462 -29463 -29464 -29465 +v -29466 -29467 -29468 -29469 -29470 -29471 -29472 -29473 -29474 -29475 -29476 +v -29477 -29478 -29479 -29480 -29481 29482 -29483 29484 -29485 -29486 29487 +v -29488 29489 -29490 -29491 -29492 29493 -29494 29495 -29496 -29497 -29498 +v 29499 -29500 29501 -29502 -29503 29504 -29505 -29506 -29507 -29508 -29509 +v -29510 -29511 -29512 -29513 -29514 29515 29516 29517 29518 -29519 -29520 +v -29521 -29522 -29523 -29524 -29525 -29526 -29527 -29528 -29529 -29530 -29531 +v -29532 -29533 -29534 -29535 -29536 -29537 -29538 -29539 -29540 -29541 -29542 +v -29543 -29544 -29545 -29546 -29547 -29548 -29549 -29550 -29551 -29552 -29553 +v -29554 -29555 -29556 -29557 -29558 -29559 -29560 -29561 -29562 -29563 -29564 +v -29565 -29566 -29567 -29568 -29569 -29570 -29571 -29572 -29573 -29574 -29575 +v -29576 -29577 -29578 -29579 -29580 -29581 -29582 -29583 -29584 -29585 -29586 +v -29587 -29588 -29589 -29590 -29591 -29592 -29593 -29594 -29595 -29596 -29597 +v -29598 -29599 -29600 -29601 -29602 -29603 -29604 -29605 -29606 -29607 -29608 +v -29609 -29610 -29611 -29612 -29613 29614 -29615 29616 -29617 -29618 29619 +v -29620 29621 -29622 -29623 29624 -29625 29626 -29627 -29628 -29629 29630 +v -29631 29632 -29633 -29634 -29635 29636 -29637 29638 -29639 -29640 29641 +v -29642 -29643 -29644 -29645 -29646 -29647 -29648 -29649 -29650 -29651 -29652 +v 29653 29654 29655 -29656 -29657 -29658 -29659 -29660 -29661 -29662 -29663 +v -29664 -29665 -29666 -29667 -29668 29669 -29670 -29671 29672 -29673 -29674 +v -29675 -29676 -29677 -29678 29679 29680 29681 -29682 -29683 29684 29685 +v 29686 -29687 -29688 -29689 29690 -29691 -29692 29693 29694 29695 29696 +v -29697 -29698 29699 29700 29701 29702 29703 -29704 -29705 -29706 29707 +v -29708 -29709 -29710 -29711 29712 -29713 -29714 -29715 -29716 -29717 -29718 +v -29719 29720 -29721 -29722 -29723 -29724 -29725 -29726 -29727 -29728 -29729 +v 29730 -29731 -29732 29733 29734 29735 -29736 -29737 -29738 29739 -29740 +v -29741 29742 29743 29744 29745 -29746 -29747 29748 29749 29750 29751 29752 +v 29753 -29754 -29755 29756 -29757 -29758 -29759 29760 -29761 29762 -29763 +v -29764 -29765 -29766 29767 -29768 29769 29770 29771 -29772 -29773 -29774 +v -29775 -29776 -29777 -29778 -29779 -29780 29781 29782 29783 -29784 -29785 +v -29786 -29787 -29788 -29789 -29790 -29791 -29792 -29793 -29794 -29795 -29796 +v -29797 -29798 -29799 -29800 -29801 -29802 -29803 -29804 -29805 29806 -29807 +v -29808 -29809 -29810 -29811 -29812 -29813 29814 -29815 29816 -29817 -29818 +v -29819 29820 -29821 29822 -29823 -29824 29825 -29826 -29827 -29828 -29829 +v -29830 -29831 29832 29833 29834 -29835 -29836 -29837 -29838 -29839 -29840 +v -29841 -29842 -29843 -29844 -29845 -29846 -29847 -29848 -29849 -29850 -29851 +v -29852 -29853 -29854 -29855 -29856 29857 -29858 -29859 -29860 -29861 -29862 +v -29863 -29864 29865 -29866 29867 -29868 -29869 -29870 29871 -29872 29873 +v -29874 -29875 29876 -29877 -29878 -29879 -29880 -29881 -29882 29883 29884 +v 29885 -29886 -29887 -29888 -29889 -29890 -29891 -29892 -29893 -29894 -29895 +v -29896 -29897 -29898 -29899 -29900 -29901 -29902 -29903 -29904 -29905 -29906 +v -29907 29908 -29909 -29910 -29911 -29912 -29913 -29914 -29915 29916 -29917 +v 29918 -29919 -29920 -29921 29922 -29923 29924 -29925 -29926 29927 -29928 +v -29929 -29930 -29931 -29932 -29933 29934 29935 29936 -29937 -29938 -29939 +v -29940 -29941 -29942 -29943 -29944 -29945 -29946 -29947 -29948 -29949 -29950 +v -29951 -29952 -29953 -29954 -29955 -29956 -29957 -29958 -29959 -29960 -29961 +v -29962 -29963 -29964 -29965 -29966 -29967 -29968 -29969 -29970 -29971 -29972 +v -29973 -29974 -29975 -29976 -29977 -29978 -29979 -29980 -29981 -29982 -29983 +v -29984 -29985 -29986 -29987 -29988 -29989 -29990 -29991 -29992 -29993 -29994 +v -29995 -29996 -29997 -29998 -29999 -30000 -30001 -30002 -30003 -30004 -30005 +v -30006 -30007 -30008 -30009 -30010 -30011 -30012 -30013 -30014 -30015 -30016 +v -30017 -30018 -30019 -30020 -30021 -30022 -30023 -30024 -30025 -30026 -30027 +v -30028 -30029 30030 -30031 -30032 -30033 -30034 -30035 -30036 -30037 -30038 +v -30039 -30040 -30041 -30042 -30043 -30044 -30045 -30046 -30047 -30048 -30049 +v -30050 -30051 -30052 -30053 -30054 -30055 -30056 -30057 -30058 -30059 -30060 +v -30061 -30062 -30063 -30064 -30065 -30066 -30067 -30068 -30069 -30070 -30071 +v -30072 -30073 -30074 -30075 -30076 -30077 -30078 -30079 -30080 -30081 -30082 +v -30083 -30084 -30085 -30086 -30087 -30088 -30089 -30090 -30091 -30092 -30093 +v -30094 -30095 -30096 -30097 -30098 30099 -30100 30101 -30102 -30103 -30104 +v 30105 -30106 30107 -30108 -30109 -30110 -30111 30112 -30113 30114 -30115 +v -30116 -30117 -30118 30119 -30120 30121 -30122 -30123 30124 -30125 -30126 +v -30127 -30128 -30129 -30130 -30131 -30132 -30133 -30134 30135 30136 30137 +v -30138 -30139 -30140 -30141 -30142 -30143 -30144 -30145 -30146 -30147 -30148 +v -30149 -30150 -30151 -30152 -30153 -30154 -30155 -30156 -30157 -30158 -30159 +v -30160 -30161 -30162 -30163 -30164 -30165 -30166 -30167 -30168 -30169 -30170 +v -30171 -30172 -30173 -30174 -30175 -30176 -30177 -30178 -30179 -30180 -30181 +v -30182 -30183 -30184 -30185 -30186 -30187 -30188 -30189 -30190 -30191 -30192 +v -30193 -30194 -30195 -30196 -30197 -30198 -30199 -30200 -30201 -30202 -30203 +v -30204 -30205 -30206 -30207 -30208 -30209 -30210 -30211 -30212 -30213 -30214 +v -30215 -30216 -30217 -30218 -30219 -30220 -30221 -30222 -30223 -30224 -30225 +v -30226 -30227 -30228 -30229 -30230 30231 -30232 -30233 -30234 -30235 -30236 +v -30237 -30238 -30239 -30240 -30241 -30242 -30243 -30244 -30245 -30246 -30247 +v -30248 -30249 -30250 -30251 -30252 -30253 -30254 -30255 -30256 -30257 -30258 +v -30259 -30260 -30261 -30262 -30263 -30264 -30265 -30266 -30267 -30268 -30269 +v -30270 -30271 -30272 -30273 -30274 -30275 -30276 -30277 -30278 -30279 -30280 +v -30281 -30282 -30283 -30284 -30285 -30286 -30287 -30288 -30289 -30290 -30291 +v -30292 -30293 -30294 -30295 -30296 -30297 -30298 -30299 30300 -30301 30302 +v -30303 -30304 -30305 30306 -30307 30308 -30309 -30310 -30311 -30312 30313 +v -30314 30315 -30316 -30317 -30318 -30319 30320 -30321 30322 -30323 -30324 +v 30325 -30326 -30327 -30328 -30329 -30330 -30331 -30332 -30333 -30334 -30335 +v 30336 30337 30338 -30339 -30340 -30341 -30342 -30343 -30344 -30345 -30346 +v -30347 -30348 -30349 -30350 -30351 -30352 -30353 -30354 -30355 -30356 -30357 +v -30358 -30359 -30360 -30361 -30362 -30363 -30364 -30365 -30366 -30367 -30368 +v -30369 -30370 -30371 -30372 -30373 -30374 -30375 -30376 -30377 -30378 -30379 +v -30380 -30381 -30382 -30383 -30384 -30385 -30386 -30387 -30388 -30389 -30390 +v -30391 -30392 -30393 -30394 -30395 -30396 -30397 -30398 -30399 -30400 -30401 +v -30402 -30403 -30404 -30405 -30406 -30407 -30408 -30409 -30410 -30411 -30412 +v -30413 -30414 -30415 -30416 -30417 -30418 -30419 -30420 -30421 -30422 -30423 +v -30424 -30425 -30426 -30427 -30428 -30429 -30430 -30431 30432 -30433 -30434 +v -30435 -30436 -30437 -30438 -30439 -30440 -30441 -30442 -30443 -30444 -30445 +v -30446 -30447 -30448 -30449 -30450 -30451 -30452 -30453 -30454 -30455 -30456 +v -30457 -30458 -30459 -30460 -30461 -30462 -30463 -30464 -30465 -30466 -30467 +v -30468 -30469 -30470 -30471 -30472 -30473 -30474 -30475 -30476 -30477 -30478 +v -30479 -30480 -30481 -30482 -30483 -30484 -30485 -30486 -30487 -30488 -30489 +v -30490 -30491 -30492 -30493 -30494 -30495 -30496 -30497 -30498 -30499 -30500 +v 30501 -30502 30503 -30504 -30505 -30506 30507 -30508 30509 -30510 -30511 +v -30512 -30513 30514 -30515 30516 -30517 -30518 -30519 -30520 30521 -30522 +v 30523 -30524 -30525 30526 -30527 -30528 -30529 -30530 -30531 -30532 -30533 +v -30534 -30535 -30536 30537 30538 30539 -30540 -30541 -30542 -30543 -30544 +v -30545 -30546 -30547 -30548 -30549 -30550 -30551 -30552 -30553 -30554 -30555 +v -30556 -30557 -30558 -30559 -30560 -30561 -30562 -30563 -30564 -30565 -30566 +v -30567 -30568 -30569 -30570 -30571 -30572 -30573 -30574 -30575 -30576 -30577 +v -30578 -30579 -30580 -30581 -30582 -30583 -30584 -30585 -30586 -30587 -30588 +v -30589 -30590 -30591 -30592 -30593 -30594 -30595 -30596 -30597 -30598 -30599 +v -30600 -30601 -30602 -30603 -30604 -30605 -30606 -30607 -30608 -30609 -30610 +v -30611 -30612 -30613 -30614 -30615 -30616 -30617 -30618 -30619 -30620 -30621 +v -30622 -30623 -30624 -30625 -30626 -30627 -30628 -30629 -30630 -30631 -30632 +v 30633 -30634 -30635 -30636 -30637 -30638 -30639 -30640 -30641 -30642 -30643 +v -30644 -30645 -30646 -30647 -30648 -30649 -30650 -30651 -30652 -30653 -30654 +v -30655 -30656 -30657 -30658 -30659 -30660 -30661 -30662 -30663 -30664 -30665 +v -30666 -30667 -30668 -30669 -30670 -30671 -30672 -30673 -30674 -30675 -30676 +v -30677 -30678 -30679 -30680 -30681 -30682 -30683 -30684 -30685 -30686 -30687 +v -30688 -30689 -30690 -30691 -30692 -30693 -30694 -30695 -30696 -30697 -30698 +v -30699 -30700 -30701 30702 -30703 30704 -30705 -30706 -30707 30708 -30709 +v 30710 -30711 -30712 -30713 -30714 30715 -30716 30717 -30718 -30719 -30720 +v -30721 30722 -30723 30724 -30725 -30726 30727 -30728 -30729 -30730 -30731 +v -30732 -30733 -30734 -30735 -30736 -30737 30738 30739 30740 -30741 -30742 +v -30743 -30744 -30745 -30746 -30747 -30748 -30749 -30750 -30751 -30752 -30753 +v -30754 -30755 -30756 -30757 -30758 -30759 -30760 -30761 -30762 30763 -30764 +v -30765 -30766 -30767 -30768 -30769 -30770 30771 -30772 30773 -30774 -30775 +v -30776 30777 -30778 30779 -30780 -30781 30782 -30783 -30784 -30785 -30786 +v -30787 -30788 30789 30790 30791 30792 -30793 -30794 30795 30796 -30797 30798 +v -30799 30800 30801 30802 -30803 -30804 30805 -30806 -30807 30808 -30809 +v 30810 -30811 -30812 -30813 -30814 -30815 -30816 -30817 -30818 30819 30820 +v 30821 30822 -30823 -30824 -30825 -30826 -30827 -30828 30829 -30830 -30831 +v -30832 30833 30834 30835 30836 30837 -30838 30839 30840 -30841 -30842 -30843 +v -30844 -30845 -30846 -30847 -30848 -30849 30850 -30851 -30852 30853 -30854 +v -30855 -30856 -30857 30858 -30859 30860 30861 30862 30863 -30864 -30865 +v 30866 -30867 -30868 -30869 30870 -30871 30872 30873 30874 -30875 -30876 +v -30877 -30878 -30879 -30880 -30881 -30882 30883 30884 30885 30886 -30887 +v -30888 -30889 -30890 -30891 -30892 -30893 -30894 -30895 -30896 -30897 30898 +v 30899 -30900 -30901 30902 -30903 -30904 30905 30906 30907 30908 -30909 +v -30910 -30911 -30912 30913 30914 30915 30916 -30917 -30918 -30919 -30920 +v 30921 30922 30923 30924 -30925 -30926 -30927 -30928 -30929 -30930 -30931 +v -30932 -30933 -30934 -30935 -30936 -30937 -30938 -30939 -30940 -30941 -30942 +v -30943 -30944 30945 -30946 30947 -30948 -30949 -30950 30951 -30952 30953 +v -30954 -30955 30956 -30957 -30958 -30959 -30960 -30961 -30962 30963 30964 +v 30965 30966 -30967 -30968 -30969 -30970 -30971 -30972 -30973 -30974 -30975 +v -30976 -30977 -30978 -30979 -30980 -30981 -30982 -30983 -30984 30985 -30986 +v 30987 -30988 -30989 -30990 30991 -30992 30993 -30994 -30995 30996 -30997 +v -30998 -30999 -31000 -31001 -31002 31003 31004 31005 31006 -31007 -31008 +v -31009 -31010 31011 31012 31013 31014 -31015 -31016 -31017 -31018 -31019 +v -31020 -31021 -31022 -31023 -31024 -31025 -31026 -31027 -31028 -31029 -31030 +v -31031 -31032 -31033 -31034 -31035 -31036 -31037 -31038 -31039 -31040 31041 +v -31042 31043 -31044 -31045 -31046 -31047 31048 -31049 31050 -31051 -31052 +v 31053 -31054 31055 -31056 -31057 -31058 -31059 -31060 -31061 -31062 -31063 +v 31064 31065 31066 31067 31068 31069 -31070 -31071 -31072 -31073 -31074 +v -31075 -31076 -31077 -31078 -31079 -31080 -31081 -31082 -31083 -31084 -31085 +v -31086 -31087 -31088 -31089 -31090 -31091 -31092 -31093 -31094 -31095 31096 +v -31097 31098 -31099 -31100 -31101 -31102 31103 -31104 31105 -31106 -31107 +v 31108 -31109 31110 -31111 -31112 -31113 -31114 -31115 -31116 -31117 -31118 +v 31119 31120 31121 31122 -31123 -31124 31125 -31126 31127 -31128 31129 -31130 +v -31131 -31132 31133 31134 31135 31136 31137 -31138 -31139 -31140 -31141 +v -31142 -31143 -31144 31145 -31146 -31147 -31148 31149 31150 31151 31152 +v 31153 31154 31155 -31156 31157 31158 -31159 -31160 -31161 -31162 -31163 +v -31164 31165 -31166 31167 31168 31169 31170 -31171 -31172 31173 -31174 +v -31175 -31176 31177 -31178 31179 -31180 -31181 31182 -31183 -31184 -31185 +v -31186 -31187 -31188 -31189 31190 31191 31192 31193 -31194 -31195 31196 +v 31197 -31198 -31199 31200 31201 -31202 -31203 31204 31205 -31206 31207 +v -31208 31209 -31210 -31211 -31212 -31213 -31214 -31215 31216 31217 -31218 +v 31219 -31220 31221 -31222 -31223 -31224 -31225 -31226 -31227 31228 31229 +v -31230 -31231 31232 31233 -31234 31235 -31236 31237 -31238 -31239 -31240 +v -31241 -31242 -31243 31244 -31245 -31246 31247 -31248 31249 -31250 31251 +v -31252 -31253 -31254 31255 31256 31257 31258 -31259 -31260 31261 31262 +v -31263 -31264 31265 31266 -31267 -31268 -31269 -31270 -31271 31272 31273 +v 31274 31275 -31276 31277 31278 31279 -31280 -31281 31282 31283 -31284 -31285 +v 31286 31287 31288 -31289 -31290 -31291 31292 -31293 31294 31295 31296 -31297 +v -31298 31299 -31300 -31301 -31302 -31303 31304 31305 -31306 -31307 -31308 +v -31309 -31310 -31311 -31312 31313 31314 31315 -31316 -31317 -31318 -31319 +v -31320 31321 31322 31323 31324 31325 31326 31327 31328 31329 -31330 -31331 +v -31332 31333 31334 -31335 -31336 -31337 -31338 -31339 31340 31341 31342 +v 31343 -31344 -31345 -31346 31347 31348 31349 31350 31351 31352 -31353 31354 +v 31355 31356 -31357 -31358 -31359 -31360 -31361 -31362 31363 31364 31365 +v 31366 31367 31368 31369 31370 31371 31372 -31373 -31374 -31375 -31376 31377 +v -31378 -31379 -31380 -31381 31382 -31383 31384 31385 -31386 -31387 31388 +v -31389 -31390 31391 -31392 31393 31394 31395 31396 31397 31398 31399 -31400 +v 31401 31402 31403 -31404 31405 -31406 31407 31408 31409 -31410 -31411 31412 +v -31413 -31414 -31415 -31416 31417 -31418 31419 -31420 31421 -31422 31423 +v -31424 -31425 31426 -31427 31428 -31429 31430 -31431 31432 -31433 -31434 +v 31435 -31436 -31437 -31438 -31439 -31440 -31441 -31442 -31443 -31444 -31445 +v -31446 31447 31448 31449 -31450 -31451 -31452 -31453 -31454 31455 31456 +v -31457 31458 -31459 -31460 31461 -31462 -31463 -31464 -31465 -31466 -31467 +v -31468 31469 31470 31471 31472 31473 -31474 -31475 31476 31477 31478 31479 +v 31480 31481 -31482 -31483 -31484 31485 31486 -31487 -31488 -31489 31490 +v 31491 31492 31493 31494 31495 -31496 -31497 -31498 -31499 31500 -31501 +v -31502 31503 31504 31505 31506 31507 31508 31509 -31510 -31511 -31512 -31513 +v 31514 -31515 31516 -31517 -31518 -31519 -31520 -31521 31522 -31523 31524 +v 31525 31526 -31527 31528 31529 -31530 -31531 -31532 31533 31534 31535 31536 +v 31537 31538 31539 31540 -31541 -31542 -31543 31544 -31545 31546 -31547 31548 +v 31549 -31550 -31551 31552 -31553 31554 31555 -31556 -31557 31558 -31559 +v -31560 31561 -31562 31563 -31564 31565 -31566 -31567 31568 -31569 -31570 +v -31571 -31572 -31573 -31574 -31575 -31576 -31577 -31578 31579 31580 31581 +v -31582 -31583 31584 31585 -31586 31587 -31588 -31589 -31590 -31591 -31592 +v 31593 -31594 -31595 31596 31597 31598 31599 31600 31601 31602 31603 -31604 +v -31605 -31606 -31607 -31608 31609 31610 31611 31612 31613 31614 31615 31616 +v 31617 -31618 31619 31620 31621 -31622 -31623 -31624 -31625 -31626 -31627 +v 31628 31629 31630 31631 31632 31633 31634 31635 31636 31637 -31638 -31639 +v 31640 31641 31642 31643 31644 -31645 31646 31647 -31648 31649 -31650 -31651 +v -31652 -31653 -31654 -31655 -31656 -31657 31658 31659 31660 -31661 31662 +v -31663 -31664 -31665 -31666 -31667 31668 31669 31670 31671 31672 31673 +v -31674 -31675 -31676 -31677 31678 -31679 31680 31681 31682 -31683 -31684 +v 31685 -31686 -31687 -31688 31689 -31690 31691 -31692 31693 31694 -31695 +v -31696 31697 31698 -31699 31700 -31701 31702 -31703 31704 -31705 -31706 +v 31707 -31708 -31709 -31710 -31711 -31712 -31713 -31714 -31715 -31716 -31717 +v -31718 31719 31720 31721 31722 -31723 31724 -31725 -31726 -31727 -31728 +v -31729 -31730 -31731 31732 31733 31734 31735 31736 31737 31738 31739 31740 +v 31741 -31742 -31743 -31744 -31745 -31746 -31747 -31748 -31749 -31750 -31751 +v -31752 -31753 -31754 -31755 31756 31757 -31758 -31759 31760 31761 -31762 +v -31763 -31764 -31765 31766 -31767 -31768 31769 -31770 -31771 -31772 -31773 +v -31774 -31775 -31776 31777 31778 31779 31780 31781 -31782 -31783 31784 31785 +v 31786 31787 -31788 -31789 -31790 -31791 -31792 -31793 -31794 -31795 -31796 +v -31797 -31798 -31799 -31800 -31801 -31802 -31803 -31804 -31805 -31806 -31807 +v -31808 31809 -31810 -31811 31812 -31813 -31814 -31815 -31816 31817 31818 +v -31819 31820 -31821 -31822 -31823 31824 -31825 -31826 -31827 -31828 -31829 +v -31830 -31831 -31832 -31833 -31834 -31835 -31836 -31837 31838 31839 31840 +v -31841 -31842 31843 31844 31845 31846 31847 -31848 -31849 -31850 -31851 +v -31852 -31853 -31854 -31855 -31856 -31857 31858 -31859 -31860 31861 -31862 +v -31863 31864 -31865 -31866 -31867 -31868 -31869 -31870 -31871 -31872 31873 +v 31874 31875 31876 31877 31878 31879 -31880 -31881 -31882 31883 -31884 31885 +v -31886 -31887 31888 -31889 31890 31891 31892 -31893 -31894 31895 -31896 +v -31897 31898 -31899 31900 -31901 -31902 -31903 31904 -31905 31906 -31907 +v -31908 31909 -31910 -31911 -31912 -31913 -31914 -31915 -31916 -31917 -31918 +v -31919 -31920 31921 31922 31923 31924 -31925 -31926 -31927 31928 -31929 +v -31930 -31931 -31932 -31933 -31934 -31935 -31936 -31937 31938 31939 -31940 +v -31941 -31942 31943 -31944 -31945 -31946 31947 -31948 31949 -31950 -31951 +v -31952 -31953 -31954 -31955 -31956 -31957 -31958 -31959 -31960 31961 31962 +v -31963 -31964 -31965 -31966 -31967 31968 -31969 31970 -31971 -31972 -31973 +v -31974 -31975 -31976 -31977 -31978 -31979 -31980 31981 31982 -31983 -31984 +v -31985 31986 -31987 -31988 -31989 31990 -31991 31992 -31993 -31994 -31995 +v -31996 -31997 -31998 -31999 -32000 -32001 -32002 -32003 32004 32005 -32006 +v -32007 32008 -32009 -32010 32011 32012 32013 32014 -32015 -32016 -32017 +v -32018 -32019 -32020 -32021 -32022 -32023 -32024 -32025 -32026 -32027 -32028 +v -32029 -32030 -32031 -32032 32033 -32034 32035 -32036 -32037 -32038 32039 +v -32040 32041 -32042 -32043 32044 -32045 -32046 -32047 -32048 -32049 -32050 +v 32051 32052 32053 32054 -32055 -32056 -32057 -32058 -32059 -32060 -32061 +v -32062 -32063 -32064 -32065 -32066 -32067 -32068 -32069 -32070 32071 -32072 +v 32073 -32074 -32075 -32076 32077 -32078 32079 -32080 -32081 32082 -32083 +v -32084 -32085 -32086 -32087 -32088 32089 32090 32091 32092 -32093 -32094 +v -32095 -32096 -32097 -32098 -32099 -32100 -32101 -32102 -32103 -32104 -32105 +v -32106 -32107 -32108 32109 -32110 32111 -32112 -32113 -32114 32115 -32116 +v 32117 -32118 -32119 32120 -32121 -32122 -32123 -32124 -32125 -32126 32127 +v 32128 32129 32130 -32131 -32132 -32133 -32134 32135 32136 32137 32138 -32139 +v -32140 -32141 -32142 -32143 -32144 -32145 -32146 -32147 -32148 -32149 -32150 +v -32151 -32152 -32153 -32154 -32155 -32156 -32157 -32158 -32159 32160 -32161 +v 32162 -32163 -32164 -32165 -32166 32167 -32168 32169 -32170 -32171 32172 +v -32173 -32174 -32175 -32176 -32177 -32178 32179 32180 32181 32182 32183 +v 32184 -32185 -32186 -32187 -32188 -32189 -32190 -32191 -32192 -32193 -32194 +v -32195 -32196 32197 -32198 -32199 -32200 -32201 32202 32203 32204 32205 +v -32206 -32207 32208 -32209 32210 -32211 32212 -32213 -32214 -32215 32216 +v 32217 32218 32219 -32220 -32221 -32222 32223 32224 -32225 -32226 32227 32228 +v -32229 -32230 -32231 -32232 -32233 32234 32235 32236 32237 -32238 -32239 +v 32240 32241 -32242 32243 -32244 32245 -32246 -32247 -32248 -32249 -32250 +v -32251 32252 32253 -32254 32255 -32256 32257 -32258 -32259 -32260 -32261 +v -32262 -32263 32264 32265 -32266 32267 -32268 32269 -32270 -32271 -32272 +v -32273 -32274 -32275 32276 32277 -32278 -32279 32280 32281 -32282 -32283 +v 32284 -32285 -32286 32287 -32288 32289 -32290 32291 -32292 -32293 -32294 +v 32295 32296 32297 32298 32299 -32300 32301 -32302 -32303 -32304 -32305 +v -32306 -32307 -32308 32309 32310 32311 -32312 -32313 32314 32315 32316 32317 +v 32318 -32319 -32320 -32321 -32322 -32323 -32324 -32325 -32326 32327 32328 +v -32329 -32330 -32331 32332 -32333 -32334 -32335 -32336 -32337 32338 -32339 +v -32340 -32341 -32342 -32343 -32344 -32345 32346 32347 -32348 -32349 32350 +v 32351 -32352 32353 -32354 -32355 -32356 -32357 -32358 -32359 -32360 -32361 +v -32362 -32363 -32364 32365 -32366 32367 -32368 -32369 32370 -32371 32372 +v -32373 -32374 32375 -32376 32377 32378 32379 -32380 -32381 32382 32383 32384 +v 32385 -32386 -32387 32388 32389 32390 -32391 -32392 -32393 -32394 -32395 +v -32396 -32397 -32398 -32399 -32400 -32401 -32402 32403 32404 32405 32406 +v -32407 -32408 32409 32410 -32411 -32412 -32413 -32414 -32415 -32416 -32417 +v -32418 -32419 -32420 32421 -32422 -32423 -32424 -32425 32426 -32427 -32428 +v -32429 -32430 -32431 -32432 -32433 -32434 -32435 -32436 -32437 -32438 -32439 +v -32440 -32441 -32442 -32443 -32444 -32445 -32446 -32447 -32448 -32449 -32450 +v -32451 -32452 -32453 -32454 -32455 -32456 -32457 -32458 -32459 -32460 -32461 +v -32462 -32463 32464 -32465 -32466 32467 -32468 32469 -32470 -32471 32472 +v -32473 -32474 -32475 -32476 -32477 -32478 -32479 -32480 -32481 -32482 -32483 +v -32484 -32485 -32486 -32487 -32488 -32489 32490 -32491 -32492 -32493 32494 +v -32495 -32496 -32497 -32498 -32499 -32500 -32501 -32502 -32503 -32504 -32505 +v -32506 -32507 -32508 -32509 -32510 -32511 -32512 -32513 -32514 -32515 -32516 +v -32517 -32518 -32519 -32520 -32521 -32522 -32523 -32524 -32525 -32526 32527 +v -32528 32529 -32530 -32531 -32532 32533 -32534 32535 -32536 -32537 -32538 +v -32539 32540 -32541 32542 -32543 -32544 -32545 -32546 32547 -32548 32549 +v -32550 -32551 32552 -32553 -32554 -32555 -32556 -32557 -32558 -32559 -32560 +v -32561 -32562 32563 32564 32565 32566 -32567 -32568 -32569 32570 -32571 +v -32572 -32573 -32574 -32575 -32576 -32577 -32578 -32579 -32580 -32581 -32582 +v -32583 -32584 -32585 -32586 -32587 -32588 -32589 32590 -32591 32592 -32593 +v -32594 32595 -32596 -32597 -32598 -32599 32600 32601 32602 32603 -32604 +v -32605 32606 -32607 -32608 32609 32610 32611 32612 -32613 -32614 -32615 +v -32616 -32617 -32618 -32619 -32620 -32621 -32622 -32623 32624 32625 32626 +v 32627 32628 32629 -32630 32631 -32632 32633 -32634 -32635 -32636 -32637 +v -32638 -32639 -32640 -32641 -32642 -32643 32644 32645 -32646 -32647 32648 +v -32649 -32650 -32651 32652 -32653 -32654 -32655 -32656 32657 -32658 32659 +v 32660 32661 -32662 -32663 -32664 -32665 32666 -32667 -32668 -32669 -32670 +v 32671 32672 32673 -32674 -32675 -32676 -32677 -32678 -32679 -32680 32681 +v 32682 -32683 32684 -32685 -32686 -32687 -32688 -32689 -32690 -32691 32692 +v 32693 32694 32695 32696 -32697 32698 -32699 -32700 32701 -32702 -32703 +v -32704 -32705 -32706 -32707 -32708 -32709 32710 -32711 -32712 32713 -32714 +v 32715 -32716 32717 -32718 -32719 32720 -32721 -32722 32723 32724 32725 32726 +v 32727 -32728 -32729 -32730 -32731 -32732 -32733 32734 32735 -32736 32737 +v -32738 -32739 -32740 32741 -32742 32743 -32744 -32745 -32746 -32747 -32748 +v -32749 -32750 -32751 -32752 -32753 32754 32755 32756 -32757 32758 32759 +v 32760 -32761 32762 -32763 -32764 32765 -32766 -32767 32768 -32769 -32770 +v -32771 -32772 -32773 -32774 -32775 32776 -32777 32778 -32779 -32780 -32781 +v 32782 -32783 32784 32785 32786 32787 32788 -32789 -32790 32791 32792 32793 +v 32794 32795 -32796 -32797 32798 32799 32800 -32801 -32802 -32803 -32804 +v -32805 -32806 -32807 -32808 -32809 -32810 -32811 32812 32813 32814 -32815 +v -32816 -32817 -32818 -32819 -32820 -32821 -32822 -32823 -32824 -32825 -32826 +v -32827 -32828 -32829 -32830 -32831 -32832 -32833 -32834 -32835 -32836 -32837 +v -32838 -32839 -32840 -32841 -32842 -32843 32844 -32845 32846 -32847 -32848 +v 32849 -32850 32851 -32852 -32853 32854 -32855 -32856 -32857 -32858 -32859 +v 32860 32861 32862 -32863 -32864 32865 -32866 -32867 32868 32869 32870 32871 +v 32872 32873 -32874 32875 32876 -32877 -32878 -32879 32880 32881 32882 -32883 +v -32884 32885 32886 32887 -32888 32889 -32890 -32891 -32892 -32893 32894 +v -32895 -32896 -32897 -32898 32899 -32900 -32901 -32902 32903 -32904 -32905 +v 32906 32907 -32908 -32909 -32910 -32911 -32912 -32913 -32914 32915 -32916 +v -32917 -32918 -32919 -32920 -32921 -32922 32923 32924 32925 -32926 32927 +v 32928 32929 32930 32931 -32932 -32933 32934 -32935 -32936 32937 32938 32939 +v 32940 32941 32942 32943 32944 32945 32946 32947 32948 32949 32950 32951 +v 32952 32953 32954 32955 -32956 -32957 -32958 32959 32960 -32961 -32962 32963 +v -32964 -32965 32966 -32967 32968 32969 -32970 32971 -32972 -32973 32974 +v -32975 -32976 32977 -32978 -32979 -32980 -32981 -32982 -32983 -32984 -32985 +v -32986 -32987 -32988 -32989 -32990 -32991 -32992 -32993 32994 32995 32996 +v 32997 32998 32999 33000 33001 -33002 -33003 33004 33005 -33006 33007 -33008 +v -33009 33010 33011 -33012 -33013 -33014 -33015 33016 33017 33018 33019 33020 +v 33021 33022 33023 33024 33025 33026 33027 -33028 33029 -33030 -33031 -33032 +v 33033 -33034 -33035 -33036 -33037 33038 33039 33040 33041 -33042 33043 33044 +v 33045 -33046 -33047 -33048 33049 -33050 -33051 33052 -33053 -33054 -33055 +v -33056 -33057 -33058 33059 -33060 -33061 -33062 -33063 -33064 -33065 33066 +v 33067 33068 33069 33070 -33071 -33072 -33073 33074 33075 33076 33077 -33078 +v 33079 33080 33081 33082 33083 -33084 -33085 33086 -33087 -33088 -33089 +v -33090 -33091 -33092 33093 33094 33095 33096 33097 -33098 33099 33100 -33101 +v -33102 33103 33104 33105 33106 33107 33108 33109 33110 33111 33112 33113 +v 33114 33115 33116 -33117 -33118 33119 -33120 -33121 33122 -33123 33124 +v -33125 33126 33127 -33128 33129 -33130 33131 -33132 -33133 -33134 -33135 +v -33136 -33137 -33138 33139 -33140 -33141 -33142 33143 33144 33145 33146 +v 33147 -33148 -33149 33150 -33151 -33152 33153 -33154 33155 -33156 -33157 +v -33158 -33159 -33160 -33161 33162 -33163 33164 33165 33166 33167 33168 33169 +v -33170 33171 -33172 33173 33174 33175 -33176 33177 33178 33179 33180 33181 +v 33182 33183 33184 33185 33186 33187 33188 33189 33190 33191 33192 -33193 +v -33194 -33195 33196 33197 33198 -33199 33200 -33201 33202 -33203 -33204 +v 33205 -33206 -33207 -33208 -33209 -33210 -33211 -33212 -33213 33214 33215 +v -33216 33217 33218 33219 -33220 -33221 -33222 33223 33224 -33225 -33226 +v 33227 -33228 33229 33230 33231 33232 33233 -33234 -33235 -33236 -33237 33238 +v 33239 -33240 -33241 -33242 33243 33244 33245 33246 33247 33248 33249 33250 +v 33251 -33252 33253 33254 33255 33256 33257 -33258 -33259 -33260 -33261 +v -33262 -33263 33264 33265 33266 33267 33268 33269 33270 33271 33272 33273 +v 33274 -33275 -33276 -33277 -33278 33279 -33280 33281 33282 -33283 -33284 +v 33285 -33286 -33287 -33288 33289 -33290 33291 33292 -33293 33294 33295 +v -33296 33297 -33298 -33299 -33300 -33301 -33302 33303 33304 33305 33306 +v 33307 -33308 -33309 33310 -33311 -33312 -33313 -33314 -33315 33316 33317 +v 33318 33319 33320 -33321 -33322 -33323 33324 -33325 -33326 33327 -33328 +v -33329 -33330 -33331 -33332 -33333 -33334 33335 33336 33337 -33338 33339 +v -33340 33341 -33342 33343 33344 -33345 -33346 33347 -33348 33349 33350 33351 +v 33352 33353 33354 -33355 -33356 33357 33358 33359 33360 33361 33362 33363 +v 33364 33365 33366 33367 33368 33369 -33370 33371 -33372 33373 -33374 33375 +v -33376 -33377 33378 -33379 33380 -33381 -33382 33383 33384 -33385 33386 +v -33387 -33388 33389 -33390 -33391 -33392 -33393 -33394 -33395 -33396 -33397 +v -33398 33399 -33400 33401 33402 33403 -33404 33405 -33406 -33407 -33408 +v -33409 33410 33411 33412 33413 33414 33415 33416 33417 33418 33419 33420 +v 33421 -33422 33423 -33424 -33425 -33426 -33427 -33428 33429 -33430 33431 +v 33432 -33433 33434 33435 -33436 -33437 33438 33439 33440 33441 33442 33443 +v -33444 -33445 -33446 -33447 -33448 -33449 33450 -33451 33452 33453 33454 +v 33455 -33456 33457 -33458 -33459 33460 -33461 -33462 -33463 -33464 -33465 +v -33466 -33467 -33468 33469 -33470 33471 33472 33473 33474 33475 33476 -33477 +v -33478 33479 33480 33481 33482 33483 33484 -33485 -33486 -33487 -33488 33489 +v -33490 33491 33492 33493 -33494 -33495 33496 33497 33498 -33499 -33500 33501 +v -33502 -33503 33504 -33505 33506 -33507 -33508 33509 -33510 33511 -33512 +v -33513 33514 -33515 33516 -33517 -33518 -33519 33520 -33521 33522 33523 +v 33524 -33525 -33526 -33527 -33528 -33529 -33530 -33531 -33532 -33533 -33534 +v -33535 -33536 -33537 -33538 -33539 -33540 -33541 33542 33543 33544 33545 +v -33546 33547 -33548 -33549 -33550 33551 33552 33553 -33554 -33555 -33556 +v -33557 -33558 -33559 -33560 -33561 -33562 -33563 -33564 -33565 -33566 -33567 +v -33568 -33569 -33570 -33571 -33572 -33573 -33574 -33575 -33576 33577 -33578 +v 33579 -33580 -33581 -33582 33583 -33584 33585 -33586 -33587 33588 -33589 +v -33590 -33591 -33592 -33593 -33594 33595 33596 33597 33598 33599 -33600 +v -33601 -33602 -33603 -33604 -33605 -33606 -33607 -33608 -33609 -33610 -33611 +v -33612 -33613 -33614 -33615 -33616 -33617 -33618 -33619 -33620 -33621 -33622 +v 33623 -33624 33625 -33626 -33627 -33628 33629 -33630 33631 -33632 -33633 +v 33634 -33635 -33636 -33637 -33638 -33639 -33640 33641 33642 33643 33644 +v 33645 -33646 -33647 -33648 -33649 -33650 -33651 -33652 -33653 -33654 -33655 +v -33656 -33657 -33658 -33659 -33660 -33661 -33662 -33663 -33664 -33665 -33666 +v -33667 -33668 33669 -33670 33671 -33672 -33673 -33674 33675 -33676 33677 +v -33678 -33679 33680 -33681 -33682 -33683 -33684 -33685 -33686 33687 33688 +v 33689 33690 33691 -33692 -33693 -33694 -33695 -33696 -33697 -33698 -33699 +v -33700 -33701 -33702 -33703 -33704 -33705 -33706 -33707 -33708 -33709 -33710 +v -33711 -33712 -33713 -33714 -33715 -33716 -33717 -33718 -33719 -33720 -33721 +v -33722 -33723 -33724 -33725 -33726 -33727 -33728 -33729 -33730 -33731 -33732 +v -33733 -33734 -33735 -33736 -33737 -33738 -33739 -33740 -33741 -33742 -33743 +v -33744 -33745 -33746 -33747 -33748 -33749 -33750 -33751 -33752 -33753 -33754 +v -33755 -33756 -33757 -33758 -33759 -33760 -33761 -33762 -33763 -33764 -33765 +v -33766 -33767 -33768 -33769 -33770 -33771 -33772 -33773 -33774 -33775 -33776 +v -33777 -33778 -33779 -33780 -33781 -33782 -33783 -33784 -33785 -33786 -33787 +v -33788 -33789 -33790 -33791 -33792 -33793 -33794 -33795 -33796 -33797 -33798 +v -33799 -33800 -33801 -33802 -33803 -33804 -33805 -33806 -33807 -33808 -33809 +v -33810 -33811 -33812 -33813 -33814 -33815 -33816 -33817 -33818 -33819 -33820 +v -33821 -33822 -33823 -33824 -33825 -33826 -33827 -33828 33829 -33830 33831 +v -33832 -33833 -33834 33835 -33836 33837 -33838 -33839 -33840 33841 -33842 +v 33843 -33844 -33845 -33846 -33847 33848 -33849 33850 -33851 -33852 33853 +v -33854 -33855 -33856 -33857 -33858 -33859 -33860 -33861 -33862 -33863 33864 +v 33865 33866 33867 33868 -33869 -33870 -33871 -33872 -33873 -33874 -33875 +v -33876 -33877 -33878 -33879 -33880 -33881 -33882 -33883 -33884 -33885 -33886 +v -33887 -33888 -33889 -33890 -33891 33892 -33893 33894 -33895 -33896 -33897 +v 33898 -33899 33900 -33901 -33902 33903 -33904 -33905 -33906 -33907 -33908 +v -33909 33910 33911 33912 33913 -33914 -33915 33916 -33917 -33918 33919 33920 +v 33921 -33922 -33923 -33924 -33925 -33926 -33927 -33928 -33929 -33930 -33931 +v -33932 -33933 -33934 -33935 -33936 -33937 -33938 -33939 -33940 -33941 -33942 +v -33943 -33944 -33945 -33946 -33947 -33948 -33949 -33950 -33951 -33952 -33953 +v -33954 -33955 -33956 -33957 -33958 -33959 -33960 -33961 -33962 -33963 -33964 +v -33965 -33966 -33967 -33968 -33969 -33970 -33971 -33972 -33973 -33974 -33975 +v -33976 -33977 -33978 -33979 -33980 -33981 -33982 -33983 -33984 -33985 -33986 +v -33987 -33988 -33989 -33990 -33991 -33992 -33993 -33994 -33995 -33996 -33997 +v -33998 -33999 -34000 -34001 -34002 -34003 -34004 -34005 -34006 -34007 -34008 +v -34009 -34010 -34011 -34012 -34013 -34014 -34015 -34016 -34017 -34018 -34019 +v -34020 -34021 -34022 -34023 -34024 -34025 -34026 -34027 -34028 -34029 -34030 +v -34031 -34032 -34033 -34034 -34035 -34036 -34037 -34038 -34039 -34040 -34041 +v -34042 -34043 -34044 -34045 -34046 -34047 -34048 -34049 -34050 -34051 -34052 +v -34053 -34054 -34055 -34056 -34057 -34058 -34059 -34060 -34061 -34062 -34063 +v -34064 -34065 -34066 -34067 -34068 -34069 -34070 -34071 -34072 -34073 -34074 +v -34075 -34076 -34077 -34078 -34079 -34080 -34081 -34082 -34083 -34084 -34085 +v -34086 -34087 -34088 -34089 -34090 -34091 -34092 -34093 -34094 -34095 -34096 +v -34097 -34098 -34099 -34100 -34101 -34102 -34103 -34104 -34105 -34106 -34107 +v -34108 -34109 -34110 -34111 -34112 -34113 -34114 -34115 -34116 -34117 -34118 +v -34119 -34120 -34121 -34122 -34123 -34124 -34125 -34126 -34127 -34128 -34129 +v -34130 -34131 -34132 -34133 -34134 -34135 -34136 -34137 -34138 -34139 -34140 +v -34141 -34142 -34143 -34144 -34145 -34146 -34147 -34148 -34149 -34150 -34151 +v -34152 -34153 -34154 -34155 -34156 -34157 -34158 -34159 -34160 -34161 -34162 +v -34163 -34164 -34165 -34166 -34167 -34168 -34169 -34170 -34171 -34172 -34173 +v -34174 -34175 -34176 -34177 -34178 -34179 -34180 -34181 -34182 -34183 -34184 +v -34185 -34186 -34187 -34188 -34189 -34190 -34191 -34192 -34193 -34194 -34195 +v -34196 -34197 -34198 -34199 -34200 -34201 -34202 -34203 -34204 -34205 -34206 +v -34207 -34208 -34209 -34210 -34211 -34212 -34213 -34214 -34215 -34216 -34217 +v -34218 -34219 -34220 -34221 -34222 -34223 -34224 -34225 -34226 -34227 -34228 +v -34229 -34230 -34231 -34232 -34233 -34234 -34235 -34236 -34237 -34238 -34239 +v -34240 -34241 -34242 -34243 -34244 -34245 -34246 -34247 -34248 -34249 -34250 +v -34251 -34252 -34253 -34254 -34255 -34256 -34257 -34258 -34259 -34260 -34261 +v -34262 -34263 -34264 -34265 -34266 -34267 -34268 -34269 -34270 -34271 -34272 +v -34273 -34274 -34275 -34276 -34277 -34278 -34279 -34280 -34281 -34282 -34283 +v -34284 -34285 -34286 -34287 -34288 -34289 -34290 -34291 -34292 -34293 -34294 +v -34295 -34296 -34297 -34298 -34299 -34300 -34301 -34302 -34303 -34304 -34305 +v -34306 -34307 -34308 -34309 -34310 -34311 -34312 -34313 -34314 -34315 -34316 +v -34317 -34318 -34319 -34320 -34321 -34322 -34323 -34324 -34325 -34326 -34327 +v -34328 -34329 -34330 -34331 -34332 -34333 -34334 -34335 -34336 -34337 -34338 +v -34339 -34340 -34341 -34342 -34343 -34344 -34345 -34346 -34347 34348 -34349 +v 34350 -34351 -34352 34353 -34354 34355 -34356 -34357 -34358 34359 -34360 +v 34361 -34362 -34363 -34364 -34365 34366 -34367 34368 -34369 -34370 -34371 +v -34372 34373 -34374 34375 -34376 -34377 -34378 -34379 34380 -34381 34382 +v -34383 -34384 34385 -34386 34387 -34388 -34389 34390 -34391 -34392 -34393 +v -34394 -34395 -34396 -34397 -34398 -34399 -34400 -34401 -34402 -34403 -34404 +v -34405 34406 34407 34408 34409 -34410 -34411 -34412 -34413 -34414 34415 +v -34416 -34417 -34418 -34419 -34420 -34421 -34422 -34423 -34424 -34425 -34426 +v -34427 -34428 -34429 -34430 -34431 -34432 -34433 -34434 -34435 -34436 -34437 +v -34438 -34439 -34440 -34441 -34442 -34443 -34444 -34445 -34446 -34447 -34448 +v -34449 -34450 -34451 -34452 -34453 -34454 -34455 -34456 -34457 -34458 -34459 +v -34460 -34461 -34462 -34463 -34464 -34465 -34466 -34467 -34468 -34469 -34470 +v -34471 -34472 -34473 -34474 -34475 -34476 -34477 -34478 -34479 -34480 -34481 +v -34482 -34483 -34484 -34485 -34486 -34487 -34488 -34489 -34490 -34491 -34492 +v -34493 -34494 -34495 -34496 -34497 -34498 -34499 -34500 -34501 -34502 -34503 +v -34504 -34505 -34506 -34507 -34508 -34509 -34510 -34511 -34512 -34513 -34514 +v -34515 -34516 -34517 -34518 -34519 -34520 -34521 34522 -34523 34524 -34525 +v -34526 -34527 -34528 34529 -34530 34531 -34532 -34533 -34534 -34535 34536 +v -34537 34538 -34539 -34540 -34541 -34542 34543 -34544 34545 -34546 -34547 +v 34548 -34549 34550 -34551 -34552 34553 -34554 -34555 -34556 -34557 -34558 +v -34559 -34560 -34561 -34562 -34563 -34564 -34565 34566 34567 34568 34569 +v -34570 -34571 -34572 -34573 -34574 -34575 -34576 -34577 -34578 -34579 -34580 +v -34581 -34582 -34583 -34584 -34585 -34586 -34587 -34588 -34589 -34590 -34591 +v -34592 -34593 -34594 -34595 -34596 -34597 -34598 -34599 -34600 -34601 -34602 +v -34603 -34604 -34605 -34606 -34607 -34608 -34609 -34610 -34611 -34612 -34613 +v -34614 -34615 -34616 34617 -34618 -34619 34620 -34621 -34622 34623 -34624 +v -34625 -34626 34627 -34628 -34629 -34630 -34631 -34632 -34633 -34634 -34635 +v -34636 -34637 -34638 34639 -34640 34641 34642 34643 34644 -34645 -34646 +v -34647 -34648 -34649 -34650 -34651 -34652 -34653 -34654 -34655 -34656 -34657 +v -34658 -34659 -34660 -34661 -34662 -34663 -34664 -34665 -34666 -34667 -34668 +v -34669 -34670 -34671 -34672 -34673 -34674 -34675 -34676 -34677 -34678 -34679 +v -34680 -34681 -34682 -34683 -34684 -34685 -34686 -34687 -34688 -34689 -34690 +v -34691 -34692 -34693 -34694 -34695 -34696 -34697 -34698 -34699 -34700 -34701 +v -34702 34703 -34704 -34705 -34706 -34707 -34708 -34709 -34710 -34711 -34712 +v -34713 -34714 -34715 -34716 -34717 -34718 -34719 -34720 -34721 -34722 -34723 +v -34724 -34725 -34726 -34727 -34728 -34729 -34730 34731 -34732 34733 -34734 +v -34735 -34736 34737 -34738 34739 -34740 -34741 -34742 34743 -34744 34745 +v -34746 -34747 -34748 34749 -34750 34751 -34752 -34753 34754 -34755 -34756 +v -34757 -34758 -34759 -34760 -34761 -34762 -34763 -34764 -34765 34766 34767 +v 34768 34769 -34770 -34771 -34772 -34773 -34774 -34775 -34776 -34777 34778 +v -34779 34780 -34781 34782 -34783 -34784 -34785 -34786 34787 34788 34789 +v 34790 -34791 -34792 -34793 -34794 -34795 -34796 -34797 -34798 -34799 -34800 +v -34801 -34802 -34803 -34804 -34805 -34806 -34807 -34808 -34809 -34810 -34811 +v -34812 -34813 -34814 -34815 -34816 34817 -34818 -34819 34820 -34821 -34822 +v -34823 -34824 -34825 -34826 -34827 -34828 -34829 -34830 -34831 -34832 -34833 +v -34834 34835 34836 34837 34838 -34839 -34840 -34841 -34842 -34843 -34844 +v 34845 -34846 -34847 -34848 -34849 -34850 -34851 -34852 -34853 -34854 -34855 +v -34856 -34857 -34858 -34859 -34860 -34861 -34862 -34863 -34864 -34865 -34866 +v -34867 -34868 -34869 -34870 -34871 -34872 -34873 -34874 -34875 34876 34877 +v 34878 34879 34880 34881 -34882 -34883 -34884 -34885 -34886 -34887 -34888 +v -34889 34890 -34891 34892 34893 -34894 -34895 -34896 -34897 -34898 -34899 +v -34900 -34901 -34902 34903 -34904 -34905 -34906 -34907 -34908 34909 -34910 +v 34911 -34912 -34913 -34914 34915 -34916 34917 34918 34919 34920 -34921 +v -34922 34923 -34924 -34925 -34926 -34927 34928 -34929 34930 -34931 -34932 +v 34933 -34934 -34935 -34936 -34937 -34938 -34939 -34940 -34941 -34942 -34943 +v 34944 34945 34946 34947 -34948 -34949 -34950 -34951 -34952 -34953 -34954 +v -34955 -34956 34957 -34958 -34959 34960 -34961 -34962 -34963 -34964 -34965 +v 34966 34967 34968 34969 -34970 -34971 34972 -34973 -34974 -34975 -34976 +v -34977 -34978 -34979 -34980 -34981 -34982 -34983 34984 34985 -34986 -34987 +v -34988 -34989 -34990 -34991 -34992 -34993 -34994 34995 -34996 -34997 -34998 +v -34999 -35000 -35001 -35002 -35003 -35004 -35005 -35006 -35007 -35008 -35009 +v -35010 -35011 -35012 -35013 -35014 -35015 -35016 -35017 -35018 -35019 -35020 +v -35021 -35022 -35023 35024 35025 -35026 -35027 35028 -35029 -35030 -35031 +v -35032 -35033 -35034 -35035 -35036 -35037 -35038 35039 -35040 -35041 -35042 +v -35043 -35044 -35045 -35046 -35047 -35048 -35049 -35050 -35051 -35052 35053 +v 35054 35055 -35056 -35057 35058 -35059 -35060 35061 -35062 -35063 -35064 +v 35065 -35066 -35067 -35068 -35069 -35070 -35071 -35072 -35073 -35074 -35075 +v -35076 -35077 -35078 -35079 -35080 -35081 -35082 -35083 -35084 -35085 -35086 +v -35087 -35088 -35089 -35090 -35091 -35092 -35093 -35094 -35095 -35096 -35097 +v 35098 35099 35100 -35101 35102 35103 35104 -35105 -35106 -35107 -35108 35109 +v -35110 -35111 35112 -35113 -35114 -35115 -35116 -35117 -35118 -35119 -35120 +v -35121 -35122 -35123 -35124 -35125 35126 35127 35128 35129 35130 -35131 +v -35132 35133 35134 35135 35136 -35137 -35138 -35139 -35140 -35141 -35142 +v -35143 -35144 -35145 -35146 -35147 35148 35149 -35150 -35151 -35152 -35153 +v -35154 -35155 -35156 -35157 35158 -35159 -35160 -35161 -35162 -35163 -35164 +v -35165 -35166 35167 -35168 -35169 -35170 -35171 -35172 -35173 -35174 -35175 +v -35176 -35177 -35178 -35179 -35180 -35181 -35182 -35183 -35184 -35185 -35186 +v -35187 -35188 -35189 -35190 35191 -35192 -35193 -35194 -35195 -35196 -35197 +v -35198 -35199 -35200 -35201 -35202 -35203 -35204 -35205 -35206 -35207 -35208 +v -35209 -35210 35211 -35212 -35213 -35214 -35215 -35216 -35217 -35218 -35219 +v -35220 -35221 -35222 -35223 -35224 -35225 -35226 35227 -35228 -35229 35230 +v 35231 35232 35233 35234 35235 35236 -35237 -35238 -35239 -35240 -35241 +v -35242 -35243 -35244 -35245 -35246 -35247 35248 35249 -35250 35251 -35252 +v -35253 -35254 -35255 -35256 -35257 -35258 -35259 -35260 35261 -35262 -35263 +v -35264 -35265 -35266 -35267 -35268 -35269 35270 35271 -35272 -35273 -35274 +v -35275 -35276 -35277 -35278 -35279 -35280 -35281 -35282 35283 -35284 -35285 +v -35286 -35287 -35288 -35289 -35290 -35291 -35292 -35293 -35294 -35295 -35296 +v -35297 -35298 35299 -35300 -35301 35302 -35303 -35304 35305 -35306 -35307 +v -35308 -35309 -35310 -35311 -35312 -35313 -35314 -35315 -35316 -35317 -35318 +v -35319 -35320 35321 35322 -35323 35324 35325 35326 -35327 -35328 -35329 +v -35330 35331 -35332 -35333 35334 -35335 -35336 -35337 -35338 -35339 -35340 +v -35341 -35342 -35343 -35344 35345 35346 35347 35348 35349 35350 -35351 +v -35352 35353 35354 35355 35356 35357 35358 35359 35360 -35361 -35362 -35363 +v -35364 -35365 -35366 -35367 -35368 -35369 -35370 -35371 -35372 -35373 -35374 +v -35375 -35376 -35377 -35378 -35379 -35380 -35381 -35382 -35383 -35384 -35385 +v 35386 35387 -35388 -35389 35390 -35391 -35392 -35393 -35394 -35395 -35396 +v -35397 35398 -35399 -35400 -35401 -35402 -35403 -35404 -35405 -35406 35407 +v -35408 -35409 -35410 -35411 -35412 -35413 -35414 -35415 35416 35417 -35418 +v -35419 -35420 -35421 -35422 35423 -35424 -35425 -35426 -35427 -35428 -35429 +v -35430 35431 -35432 35433 -35434 -35435 35436 -35437 35438 -35439 -35440 +v 35441 -35442 35443 35444 35445 35446 -35447 -35448 35449 -35450 -35451 +v -35452 35453 -35454 35455 -35456 -35457 -35458 35459 -35460 35461 35462 +v 35463 -35464 -35465 -35466 -35467 -35468 -35469 -35470 -35471 -35472 -35473 +v -35474 -35475 -35476 -35477 35478 35479 35480 -35481 -35482 -35483 35484 +v 35485 -35486 -35487 35488 -35489 -35490 -35491 -35492 -35493 -35494 -35495 +v -35496 -35497 35498 35499 35500 35501 -35502 35503 -35504 -35505 -35506 +v -35507 -35508 -35509 -35510 -35511 -35512 -35513 35514 -35515 35516 -35517 +v -35518 -35519 -35520 -35521 -35522 -35523 35524 35525 35526 35527 -35528 +v 35529 -35530 -35531 -35532 -35533 -35534 -35535 -35536 -35537 -35538 -35539 +v -35540 -35541 35542 35543 -35544 35545 -35546 -35547 -35548 -35549 -35550 +v 35551 -35552 35553 -35554 -35555 -35556 35557 -35558 35559 -35560 -35561 +v -35562 35563 -35564 35565 35566 35567 35568 -35569 -35570 35571 35572 35573 +v -35574 -35575 -35576 -35577 -35578 -35579 -35580 -35581 -35582 -35583 -35584 +v 35585 35586 35587 35588 -35589 -35590 35591 -35592 35593 -35594 -35595 +v -35596 -35597 -35598 -35599 -35600 -35601 -35602 -35603 -35604 -35605 -35606 +v -35607 35608 35609 -35610 -35611 -35612 -35613 -35614 -35615 -35616 -35617 +v -35618 35619 35620 35621 -35622 -35623 35624 -35625 -35626 -35627 -35628 +v -35629 -35630 -35631 -35632 -35633 -35634 -35635 -35636 35637 -35638 35639 +v -35640 -35641 35642 -35643 35644 -35645 -35646 35647 -35648 35649 35650 +v 35651 35652 -35653 -35654 35655 35656 35657 -35658 -35659 -35660 -35661 +v -35662 -35663 -35664 -35665 -35666 -35667 -35668 35669 35670 35671 35672 +v -35673 -35674 35675 -35676 35677 -35678 -35679 -35680 -35681 -35682 -35683 +v -35684 -35685 -35686 -35687 -35688 -35689 -35690 -35691 35692 35693 35694 +v 35695 -35696 -35697 -35698 -35699 -35700 -35701 35702 -35703 -35704 -35705 +v -35706 -35707 -35708 -35709 -35710 -35711 -35712 -35713 -35714 -35715 35716 +v -35717 -35718 -35719 -35720 -35721 -35722 -35723 -35724 -35725 -35726 35727 +v -35728 -35729 -35730 -35731 -35732 -35733 -35734 -35735 -35736 35737 35738 +v 35739 35740 35741 35742 -35743 -35744 -35745 35746 35747 35748 -35749 -35750 +v -35751 -35752 -35753 -35754 -35755 35756 -35757 -35758 -35759 -35760 -35761 +v -35762 35763 -35764 35765 -35766 -35767 -35768 35769 -35770 35771 35772 +v 35773 35774 -35775 -35776 35777 -35778 -35779 -35780 35781 -35782 35783 +v -35784 -35785 35786 -35787 -35788 -35789 -35790 -35791 -35792 -35793 -35794 +v -35795 -35796 35797 35798 35799 -35800 -35801 -35802 -35803 -35804 -35805 +v -35806 -35807 35808 -35809 35810 -35811 -35812 -35813 -35814 -35815 35816 +v 35817 35818 35819 35820 -35821 -35822 -35823 -35824 -35825 -35826 -35827 +v -35828 -35829 -35830 -35831 -35832 -35833 -35834 -35835 -35836 35837 -35838 +v -35839 -35840 -35841 -35842 35843 -35844 35845 -35846 -35847 -35848 35849 +v -35850 35851 -35852 -35853 35854 -35855 -35856 -35857 -35858 -35859 -35860 +v 35861 35862 35863 35864 -35865 -35866 -35867 -35868 -35869 -35870 -35871 +v -35872 -35873 -35874 -35875 -35876 -35877 -35878 -35879 -35880 35881 -35882 +v -35883 -35884 -35885 -35886 35887 -35888 35889 -35890 -35891 -35892 35893 +v -35894 35895 -35896 -35897 35898 -35899 -35900 -35901 -35902 -35903 -35904 +v 35905 35906 35907 35908 -35909 -35910 -35911 -35912 -35913 -35914 -35915 +v -35916 -35917 -35918 -35919 -35920 -35921 -35922 -35923 -35924 35925 -35926 +v -35927 -35928 -35929 -35930 35931 -35932 35933 -35934 -35935 -35936 35937 +v -35938 35939 -35940 -35941 35942 -35943 -35944 -35945 -35946 -35947 -35948 +v 35949 35950 35951 35952 -35953 -35954 -35955 -35956 -35957 -35958 -35959 +v -35960 -35961 -35962 -35963 -35964 -35965 -35966 -35967 -35968 -35969 -35970 +v -35971 -35972 -35973 -35974 -35975 -35976 -35977 -35978 -35979 -35980 -35981 +v -35982 -35983 -35984 -35985 -35986 -35987 -35988 -35989 -35990 -35991 -35992 +v -35993 -35994 -35995 -35996 -35997 -35998 -35999 -36000 -36001 -36002 -36003 +v -36004 -36005 -36006 -36007 -36008 -36009 -36010 -36011 -36012 -36013 -36014 +v -36015 -36016 -36017 -36018 -36019 -36020 -36021 -36022 -36023 -36024 36025 +v -36026 -36027 -36028 -36029 -36030 -36031 -36032 -36033 -36034 -36035 -36036 +v -36037 -36038 -36039 -36040 -36041 -36042 -36043 -36044 -36045 -36046 -36047 +v -36048 -36049 -36050 -36051 -36052 -36053 -36054 -36055 -36056 -36057 -36058 +v -36059 -36060 -36061 -36062 -36063 -36064 -36065 -36066 -36067 -36068 -36069 +v -36070 -36071 -36072 -36073 -36074 -36075 -36076 -36077 -36078 -36079 -36080 +v -36081 -36082 36083 -36084 36085 -36086 -36087 -36088 36089 -36090 36091 +v -36092 -36093 -36094 36095 -36096 36097 -36098 -36099 -36100 -36101 36102 +v -36103 36104 -36105 -36106 36107 -36108 -36109 -36110 -36111 -36112 -36113 +v -36114 -36115 -36116 -36117 36118 36119 36120 36121 -36122 -36123 -36124 +v -36125 -36126 -36127 -36128 -36129 -36130 -36131 -36132 -36133 -36134 -36135 +v -36136 -36137 36138 -36139 -36140 -36141 -36142 -36143 36144 -36145 36146 +v -36147 -36148 -36149 36150 -36151 36152 -36153 -36154 36155 -36156 -36157 +v -36158 -36159 -36160 -36161 36162 36163 36164 36165 -36166 36167 -36168 +v -36169 -36170 -36171 36172 36173 36174 36175 36176 36177 36178 36179 36180 +v 36181 -36182 -36183 36184 36185 -36186 36187 -36188 -36189 -36190 36191 +v -36192 36193 -36194 -36195 -36196 -36197 36198 36199 36200 36201 36202 +v -36203 36204 36205 36206 -36207 36208 36209 36210 36211 36212 36213 36214 +v 36215 36216 36217 36218 36219 36220 -36221 36222 -36223 -36224 36225 -36226 +v -36227 -36228 36229 36230 36231 36232 36233 36234 36235 -36236 -36237 36238 +v 36239 -36240 36241 -36242 -36243 36244 -36245 -36246 -36247 -36248 36249 +v 36250 36251 36252 36253 36254 36255 -36256 36257 36258 36259 -36260 36261 +v 36262 36263 36264 36265 36266 36267 36268 36269 36270 36271 36272 36273 +v 36274 -36275 -36276 36277 36278 -36279 36280 -36281 36282 -36283 36284 36285 +v -36286 36287 -36288 36289 -36290 36291 36292 -36293 36294 -36295 36296 +v -36297 36298 -36299 -36300 36301 -36302 -36303 -36304 -36305 -36306 -36307 +v -36308 -36309 -36310 -36311 36312 36313 36314 36315 -36316 -36317 -36318 +v -36319 -36320 -36321 -36322 -36323 -36324 -36325 -36326 -36327 -36328 -36329 +v -36330 -36331 -36332 -36333 -36334 -36335 -36336 36337 -36338 36339 -36340 +v -36341 -36342 36343 -36344 36345 -36346 -36347 36348 -36349 -36350 -36351 +v -36352 -36353 -36354 36355 36356 36357 36358 36359 -36360 -36361 -36362 +v -36363 -36364 -36365 -36366 -36367 -36368 -36369 -36370 -36371 -36372 -36373 +v -36374 -36375 -36376 -36377 -36378 -36379 -36380 36381 -36382 36383 -36384 +v -36385 -36386 36387 -36388 36389 -36390 -36391 36392 -36393 -36394 -36395 +v -36396 -36397 -36398 36399 36400 36401 36402 36403 -36404 -36405 -36406 +v -36407 -36408 -36409 -36410 -36411 -36412 -36413 -36414 -36415 -36416 -36417 +v -36418 -36419 -36420 -36421 -36422 -36423 -36424 36425 -36426 36427 -36428 +v -36429 -36430 36431 -36432 36433 -36434 -36435 36436 -36437 -36438 -36439 +v -36440 -36441 -36442 36443 36444 36445 36446 36447 -36448 -36449 -36450 +v -36451 -36452 -36453 -36454 -36455 -36456 -36457 -36458 -36459 -36460 -36461 +v -36462 -36463 -36464 -36465 -36466 -36467 -36468 -36469 -36470 -36471 -36472 +v -36473 -36474 -36475 -36476 -36477 -36478 -36479 -36480 -36481 -36482 -36483 +v -36484 -36485 -36486 -36487 -36488 -36489 -36490 -36491 -36492 -36493 -36494 +v -36495 -36496 -36497 -36498 -36499 -36500 -36501 -36502 -36503 -36504 -36505 +v -36506 -36507 -36508 -36509 -36510 -36511 -36512 -36513 -36514 -36515 -36516 +v -36517 -36518 -36519 -36520 -36521 -36522 -36523 -36524 -36525 -36526 -36527 +v -36528 -36529 -36530 -36531 -36532 -36533 -36534 -36535 -36536 -36537 -36538 +v -36539 -36540 -36541 -36542 -36543 -36544 -36545 -36546 -36547 -36548 -36549 +v -36550 -36551 -36552 -36553 -36554 -36555 -36556 -36557 -36558 -36559 -36560 +v -36561 -36562 -36563 -36564 -36565 -36566 -36567 -36568 -36569 -36570 -36571 +v -36572 -36573 -36574 -36575 -36576 36577 -36578 36579 -36580 -36581 -36582 +v 36583 -36584 36585 -36586 -36587 -36588 36589 -36590 36591 -36592 -36593 +v -36594 -36595 36596 -36597 36598 -36599 -36600 36601 -36602 -36603 -36604 +v -36605 -36606 -36607 -36608 -36609 -36610 -36611 36612 36613 36614 36615 +v 36616 -36617 -36618 -36619 -36620 -36621 -36622 -36623 -36624 -36625 -36626 +v -36627 -36628 -36629 -36630 -36631 -36632 -36633 -36634 -36635 -36636 -36637 +v 36638 -36639 36640 -36641 -36642 -36643 36644 -36645 36646 -36647 -36648 +v 36649 -36650 -36651 -36652 -36653 -36654 -36655 36656 36657 36658 36659 +v -36660 -36661 36662 -36663 -36664 36665 36666 -36667 -36668 -36669 -36670 +v -36671 -36672 -36673 -36674 -36675 -36676 -36677 -36678 -36679 -36680 -36681 +v -36682 -36683 -36684 -36685 -36686 -36687 -36688 -36689 -36690 -36691 -36692 +v -36693 -36694 -36695 -36696 -36697 -36698 -36699 -36700 -36701 -36702 -36703 +v -36704 -36705 -36706 -36707 -36708 -36709 -36710 -36711 -36712 -36713 -36714 +v -36715 -36716 -36717 -36718 -36719 -36720 -36721 -36722 -36723 -36724 -36725 +v -36726 -36727 -36728 -36729 -36730 -36731 -36732 -36733 -36734 -36735 -36736 +v -36737 -36738 -36739 -36740 -36741 -36742 -36743 -36744 -36745 -36746 -36747 +v -36748 -36749 -36750 -36751 -36752 -36753 -36754 -36755 -36756 -36757 -36758 +v -36759 -36760 -36761 -36762 -36763 -36764 -36765 -36766 -36767 -36768 -36769 +v -36770 -36771 -36772 -36773 -36774 -36775 -36776 -36777 -36778 -36779 -36780 +v -36781 -36782 -36783 -36784 -36785 -36786 -36787 -36788 -36789 -36790 -36791 +v -36792 -36793 -36794 -36795 -36796 -36797 -36798 -36799 -36800 -36801 -36802 +v -36803 -36804 -36805 -36806 -36807 -36808 -36809 -36810 -36811 -36812 -36813 +v -36814 -36815 -36816 -36817 -36818 -36819 -36820 -36821 -36822 -36823 -36824 +v -36825 -36826 -36827 -36828 -36829 -36830 -36831 -36832 -36833 -36834 -36835 +v -36836 -36837 -36838 -36839 -36840 -36841 -36842 -36843 -36844 -36845 -36846 +v -36847 -36848 -36849 -36850 -36851 -36852 -36853 -36854 -36855 -36856 -36857 +v -36858 -36859 -36860 -36861 -36862 -36863 -36864 -36865 -36866 -36867 -36868 +v -36869 -36870 -36871 -36872 -36873 -36874 -36875 -36876 -36877 -36878 -36879 +v -36880 -36881 -36882 -36883 -36884 -36885 -36886 -36887 -36888 -36889 -36890 +v -36891 -36892 -36893 -36894 -36895 -36896 -36897 -36898 -36899 -36900 -36901 +v -36902 -36903 -36904 -36905 -36906 -36907 -36908 -36909 -36910 -36911 -36912 +v -36913 -36914 -36915 -36916 -36917 -36918 -36919 -36920 -36921 -36922 -36923 +v -36924 -36925 -36926 -36927 -36928 -36929 -36930 -36931 -36932 -36933 -36934 +v -36935 -36936 -36937 -36938 -36939 -36940 -36941 -36942 -36943 -36944 -36945 +v -36946 -36947 -36948 -36949 -36950 -36951 -36952 -36953 -36954 -36955 -36956 +v -36957 -36958 -36959 -36960 -36961 -36962 -36963 -36964 -36965 -36966 -36967 +v -36968 -36969 -36970 -36971 -36972 -36973 -36974 -36975 -36976 -36977 -36978 +v -36979 -36980 -36981 -36982 -36983 -36984 -36985 -36986 -36987 -36988 -36989 +v -36990 -36991 -36992 -36993 -36994 -36995 -36996 -36997 -36998 -36999 -37000 +v -37001 -37002 -37003 -37004 -37005 -37006 -37007 -37008 -37009 -37010 -37011 +v -37012 -37013 -37014 -37015 -37016 -37017 -37018 -37019 -37020 -37021 -37022 +v -37023 -37024 -37025 -37026 -37027 -37028 -37029 -37030 -37031 -37032 -37033 +v -37034 -37035 -37036 -37037 -37038 -37039 -37040 -37041 -37042 -37043 -37044 +v -37045 -37046 -37047 -37048 -37049 -37050 -37051 -37052 -37053 -37054 -37055 +v -37056 -37057 -37058 -37059 -37060 -37061 -37062 -37063 -37064 -37065 -37066 +v -37067 -37068 -37069 -37070 -37071 -37072 37073 -37074 37075 -37076 -37077 +v 37078 -37079 37080 -37081 -37082 -37083 37084 -37085 37086 -37087 -37088 +v -37089 -37090 37091 -37092 37093 -37094 -37095 -37096 -37097 37098 -37099 +v 37100 -37101 -37102 -37103 -37104 37105 -37106 37107 -37108 -37109 37110 +v -37111 37112 -37113 -37114 37115 -37116 -37117 -37118 -37119 -37120 -37121 +v -37122 -37123 -37124 -37125 -37126 -37127 -37128 -37129 -37130 37131 37132 +v 37133 37134 -37135 -37136 -37137 -37138 -37139 37140 -37141 -37142 -37143 +v -37144 -37145 -37146 -37147 -37148 -37149 -37150 -37151 -37152 -37153 -37154 +v -37155 -37156 -37157 -37158 -37159 -37160 -37161 -37162 -37163 -37164 -37165 +v -37166 -37167 -37168 -37169 -37170 -37171 -37172 -37173 -37174 -37175 -37176 +v -37177 -37178 -37179 -37180 -37181 -37182 -37183 -37184 -37185 -37186 -37187 +v -37188 -37189 -37190 -37191 -37192 -37193 -37194 -37195 -37196 -37197 -37198 +v -37199 -37200 -37201 -37202 -37203 -37204 -37205 -37206 -37207 -37208 -37209 +v -37210 -37211 -37212 -37213 -37214 -37215 -37216 -37217 -37218 -37219 -37220 +v -37221 -37222 -37223 -37224 -37225 -37226 -37227 -37228 -37229 -37230 -37231 +v -37232 -37233 -37234 -37235 -37236 -37237 -37238 -37239 -37240 -37241 -37242 +v -37243 -37244 37245 -37246 37247 -37248 -37249 -37250 -37251 37252 -37253 +v 37254 -37255 -37256 -37257 -37258 37259 -37260 37261 -37262 -37263 -37264 +v -37265 37266 -37267 37268 -37269 -37270 37271 -37272 37273 -37274 -37275 +v 37276 -37277 -37278 -37279 -37280 -37281 -37282 -37283 -37284 -37285 -37286 +v -37287 -37288 37289 37290 37291 37292 -37293 -37294 -37295 -37296 -37297 +v -37298 -37299 -37300 -37301 -37302 -37303 -37304 -37305 -37306 -37307 -37308 +v -37309 -37310 -37311 -37312 -37313 -37314 -37315 -37316 -37317 -37318 -37319 +v -37320 -37321 -37322 -37323 -37324 -37325 -37326 -37327 -37328 -37329 -37330 +v -37331 -37332 -37333 -37334 -37335 -37336 -37337 -37338 -37339 37340 -37341 +v -37342 37343 -37344 -37345 37346 -37347 -37348 -37349 37350 -37351 -37352 +v -37353 -37354 -37355 -37356 -37357 -37358 -37359 -37360 -37361 37362 -37363 +v 37364 37365 37366 37367 -37368 -37369 -37370 -37371 -37372 -37373 -37374 +v -37375 -37376 -37377 -37378 -37379 -37380 -37381 -37382 -37383 -37384 -37385 +v -37386 -37387 -37388 -37389 -37390 -37391 -37392 -37393 -37394 -37395 -37396 +v -37397 -37398 -37399 -37400 -37401 -37402 -37403 -37404 -37405 -37406 -37407 +v -37408 -37409 -37410 -37411 -37412 -37413 -37414 -37415 -37416 -37417 -37418 +v -37419 -37420 -37421 -37422 -37423 -37424 -37425 37426 -37427 -37428 -37429 +v -37430 -37431 -37432 -37433 -37434 -37435 -37436 -37437 -37438 -37439 -37440 +v -37441 -37442 -37443 -37444 -37445 -37446 -37447 -37448 -37449 -37450 -37451 +v -37452 -37453 37454 -37455 37456 -37457 -37458 -37459 37460 -37461 37462 +v -37463 -37464 -37465 37466 -37467 37468 -37469 -37470 -37471 37472 -37473 +v 37474 -37475 -37476 37477 -37478 -37479 -37480 -37481 -37482 -37483 -37484 +v -37485 -37486 -37487 -37488 37489 37490 37491 37492 -37493 -37494 -37495 +v -37496 -37497 -37498 -37499 -37500 37501 -37502 37503 -37504 37505 -37506 +v -37507 -37508 -37509 37510 37511 37512 37513 -37514 -37515 -37516 -37517 +v -37518 -37519 -37520 -37521 -37522 -37523 -37524 -37525 -37526 -37527 -37528 +v -37529 -37530 -37531 -37532 -37533 -37534 -37535 -37536 -37537 -37538 -37539 +v 37540 -37541 -37542 37543 -37544 -37545 -37546 -37547 -37548 -37549 -37550 +v -37551 -37552 -37553 -37554 -37555 -37556 -37557 37558 37559 37560 37561 +v -37562 -37563 -37564 -37565 -37566 -37567 37568 -37569 -37570 -37571 -37572 +v -37573 -37574 -37575 -37576 -37577 -37578 -37579 -37580 -37581 -37582 -37583 +v -37584 -37585 -37586 -37587 -37588 -37589 -37590 -37591 -37592 -37593 -37594 +v -37595 -37596 -37597 -37598 37599 37600 37601 37602 37603 37604 -37605 +v -37606 -37607 -37608 -37609 -37610 -37611 -37612 37613 -37614 37615 37616 +v -37617 -37618 -37619 -37620 -37621 -37622 -37623 -37624 -37625 37626 -37627 +v -37628 -37629 -37630 -37631 37632 -37633 37634 -37635 -37636 -37637 37638 +v -37639 37640 37641 37642 37643 -37644 -37645 37646 -37647 -37648 -37649 +v -37650 37651 -37652 37653 -37654 -37655 37656 -37657 -37658 -37659 -37660 +v -37661 -37662 -37663 -37664 -37665 -37666 37667 37668 37669 37670 -37671 +v -37672 -37673 -37674 -37675 -37676 -37677 -37678 -37679 37680 -37681 -37682 +v 37683 -37684 -37685 -37686 -37687 -37688 37689 37690 37691 37692 -37693 +v -37694 37695 -37696 -37697 -37698 -37699 -37700 -37701 -37702 -37703 -37704 +v -37705 -37706 37707 37708 -37709 -37710 -37711 -37712 -37713 -37714 -37715 +v -37716 -37717 37718 -37719 -37720 -37721 -37722 -37723 -37724 -37725 -37726 +v -37727 -37728 -37729 -37730 -37731 -37732 -37733 -37734 -37735 -37736 -37737 +v -37738 -37739 -37740 -37741 -37742 -37743 -37744 -37745 -37746 37747 37748 +v -37749 -37750 37751 -37752 -37753 -37754 -37755 -37756 -37757 -37758 -37759 +v -37760 -37761 37762 -37763 -37764 -37765 -37766 -37767 -37768 -37769 -37770 +v -37771 -37772 -37773 -37774 -37775 37776 37777 37778 -37779 -37780 37781 +v -37782 -37783 37784 -37785 -37786 -37787 37788 -37789 -37790 -37791 -37792 +v -37793 -37794 -37795 -37796 -37797 -37798 -37799 -37800 -37801 -37802 -37803 +v -37804 -37805 -37806 -37807 -37808 -37809 -37810 -37811 -37812 -37813 -37814 +v -37815 -37816 -37817 -37818 -37819 -37820 37821 37822 37823 -37824 37825 +v 37826 37827 -37828 -37829 -37830 -37831 37832 -37833 -37834 37835 -37836 +v -37837 -37838 -37839 -37840 -37841 -37842 -37843 -37844 -37845 -37846 -37847 +v -37848 37849 37850 37851 37852 37853 -37854 -37855 37856 37857 37858 37859 +v -37860 -37861 -37862 -37863 -37864 -37865 -37866 -37867 -37868 -37869 -37870 +v 37871 37872 -37873 -37874 -37875 -37876 -37877 -37878 -37879 -37880 37881 +v -37882 -37883 -37884 -37885 -37886 -37887 -37888 -37889 37890 -37891 -37892 +v -37893 -37894 -37895 -37896 -37897 -37898 -37899 -37900 -37901 -37902 -37903 +v -37904 -37905 -37906 -37907 -37908 -37909 -37910 -37911 -37912 -37913 37914 +v -37915 -37916 -37917 -37918 -37919 -37920 -37921 -37922 -37923 -37924 -37925 +v -37926 -37927 -37928 -37929 -37930 -37931 -37932 -37933 37934 -37935 -37936 +v -37937 -37938 -37939 -37940 -37941 -37942 -37943 -37944 -37945 -37946 -37947 +v -37948 -37949 -37950 -37951 37952 37953 37954 37955 37956 37957 -37958 +v -37959 -37960 -37961 -37962 -37963 -37964 -37965 -37966 -37967 -37968 37969 +v 37970 -37971 37972 -37973 -37974 -37975 -37976 -37977 -37978 -37979 -37980 +v -37981 37982 -37983 -37984 -37985 -37986 -37987 -37988 -37989 -37990 37991 +v 37992 -37993 -37994 -37995 -37996 -37997 -37998 -37999 -38000 -38001 -38002 +v -38003 38004 -38005 -38006 -38007 -38008 -38009 -38010 -38011 -38012 -38013 +v -38014 -38015 -38016 -38017 -38018 -38019 38020 -38021 -38022 38023 -38024 +v -38025 38026 -38027 -38028 -38029 -38030 -38031 -38032 -38033 -38034 -38035 +v -38036 -38037 -38038 -38039 -38040 -38041 38042 38043 -38044 38045 38046 +v 38047 -38048 -38049 -38050 -38051 38052 -38053 -38054 38055 -38056 -38057 +v -38058 -38059 -38060 -38061 -38062 -38063 -38064 -38065 38066 38067 38068 +v 38069 38070 38071 -38072 -38073 38074 38075 38076 38077 38078 38079 38080 +v 38081 -38082 -38083 -38084 -38085 -38086 -38087 -38088 -38089 -38090 -38091 +v -38092 -38093 -38094 -38095 -38096 -38097 -38098 -38099 -38100 -38101 -38102 +v -38103 -38104 -38105 -38106 38107 38108 -38109 -38110 38111 -38112 -38113 +v -38114 -38115 -38116 -38117 -38118 38119 -38120 -38121 -38122 -38123 -38124 +v -38125 -38126 -38127 38128 -38129 -38130 -38131 -38132 -38133 -38134 -38135 +v -38136 38137 38138 -38139 -38140 -38141 -38142 -38143 38144 -38145 -38146 +v -38147 -38148 -38149 -38150 -38151 38152 -38153 38154 -38155 -38156 38157 +v -38158 38159 -38160 -38161 38162 -38163 38164 38165 38166 38167 -38168 +v -38169 38170 -38171 -38172 -38173 38174 -38175 38176 -38177 -38178 -38179 +v 38180 -38181 38182 38183 38184 -38185 -38186 -38187 -38188 -38189 -38190 +v -38191 -38192 -38193 -38194 -38195 -38196 -38197 -38198 38199 38200 38201 +v -38202 -38203 -38204 38205 38206 -38207 -38208 38209 -38210 -38211 -38212 +v -38213 -38214 -38215 -38216 -38217 -38218 38219 38220 38221 38222 -38223 +v 38224 -38225 -38226 -38227 -38228 -38229 -38230 -38231 -38232 -38233 -38234 +v 38235 -38236 38237 -38238 -38239 -38240 -38241 -38242 -38243 -38244 38245 +v 38246 38247 38248 -38249 38250 -38251 -38252 -38253 -38254 -38255 -38256 +v -38257 -38258 -38259 -38260 -38261 -38262 38263 38264 -38265 38266 -38267 +v -38268 -38269 -38270 -38271 38272 -38273 38274 -38275 -38276 -38277 38278 +v -38279 38280 -38281 -38282 -38283 38284 -38285 38286 38287 38288 38289 +v -38290 -38291 38292 38293 38294 -38295 -38296 -38297 -38298 -38299 -38300 +v -38301 -38302 -38303 -38304 -38305 38306 38307 38308 38309 -38310 -38311 +v 38312 -38313 38314 -38315 -38316 -38317 -38318 -38319 -38320 -38321 -38322 +v -38323 -38324 -38325 -38326 -38327 -38328 38329 38330 -38331 -38332 -38333 +v -38334 -38335 -38336 -38337 -38338 -38339 38340 38341 38342 -38343 -38344 +v 38345 -38346 -38347 -38348 -38349 -38350 -38351 -38352 -38353 -38354 -38355 +v -38356 -38357 38358 -38359 38360 -38361 -38362 38363 -38364 38365 -38366 +v -38367 38368 -38369 38370 38371 38372 38373 -38374 -38375 38376 38377 38378 +v -38379 -38380 -38381 -38382 -38383 -38384 -38385 -38386 -38387 -38388 -38389 +v 38390 38391 38392 38393 -38394 -38395 38396 -38397 38398 -38399 -38400 +v -38401 -38402 -38403 -38404 -38405 -38406 -38407 -38408 -38409 -38410 -38411 +v -38412 38413 38414 38415 38416 -38417 -38418 -38419 -38420 -38421 -38422 +v 38423 -38424 -38425 -38426 -38427 -38428 -38429 -38430 -38431 -38432 -38433 +v -38434 -38435 -38436 38437 -38438 -38439 -38440 -38441 -38442 -38443 -38444 +v -38445 -38446 -38447 38448 -38449 -38450 -38451 -38452 -38453 -38454 -38455 +v -38456 -38457 38458 38459 38460 38461 38462 38463 -38464 -38465 -38466 38467 +v 38468 38469 -38470 -38471 -38472 -38473 -38474 -38475 -38476 38477 -38478 +v -38479 -38480 -38481 -38482 -38483 38484 -38485 38486 -38487 -38488 -38489 +v 38490 -38491 38492 38493 38494 38495 -38496 -38497 38498 -38499 -38500 +v -38501 38502 -38503 38504 -38505 -38506 38507 -38508 -38509 -38510 -38511 +v -38512 -38513 -38514 -38515 -38516 -38517 38518 38519 38520 -38521 -38522 +v -38523 -38524 -38525 -38526 -38527 -38528 38529 -38530 38531 -38532 -38533 +v -38534 -38535 -38536 38537 38538 38539 38540 38541 -38542 -38543 -38544 +v -38545 -38546 -38547 -38548 -38549 -38550 -38551 -38552 -38553 -38554 -38555 +v -38556 -38557 38558 -38559 -38560 -38561 -38562 -38563 38564 -38565 38566 +v -38567 -38568 -38569 38570 -38571 38572 -38573 -38574 38575 -38576 -38577 +v -38578 -38579 -38580 -38581 38582 38583 38584 38585 -38586 -38587 -38588 +v -38589 -38590 -38591 -38592 -38593 -38594 -38595 -38596 -38597 -38598 -38599 +v -38600 -38601 38602 -38603 -38604 -38605 -38606 -38607 38608 -38609 38610 +v -38611 -38612 -38613 38614 -38615 38616 -38617 -38618 38619 -38620 -38621 +v -38622 -38623 -38624 -38625 38626 38627 38628 38629 -38630 -38631 -38632 +v -38633 -38634 -38635 -38636 -38637 -38638 -38639 -38640 -38641 -38642 -38643 +v -38644 -38645 38646 -38647 -38648 -38649 -38650 -38651 38652 -38653 38654 +v -38655 -38656 -38657 38658 -38659 38660 -38661 -38662 38663 -38664 -38665 +v -38666 -38667 -38668 -38669 38670 38671 38672 38673 -38674 -38675 -38676 +v -38677 -38678 -38679 -38680 -38681 -38682 -38683 -38684 -38685 -38686 -38687 +v -38688 -38689 -38690 -38691 -38692 -38693 -38694 -38695 -38696 -38697 -38698 +v -38699 -38700 -38701 -38702 -38703 -38704 -38705 -38706 -38707 -38708 -38709 +v -38710 -38711 -38712 -38713 -38714 -38715 -38716 -38717 -38718 -38719 -38720 +v -38721 -38722 -38723 -38724 -38725 -38726 -38727 -38728 -38729 -38730 -38731 +v -38732 -38733 -38734 -38735 -38736 -38737 -38738 -38739 -38740 -38741 -38742 +v -38743 -38744 -38745 38746 -38747 -38748 -38749 -38750 -38751 -38752 -38753 +v -38754 -38755 -38756 -38757 -38758 -38759 -38760 -38761 -38762 -38763 -38764 +v -38765 -38766 -38767 -38768 -38769 -38770 -38771 -38772 -38773 -38774 -38775 +v -38776 -38777 -38778 -38779 -38780 -38781 -38782 -38783 -38784 -38785 -38786 +v -38787 -38788 -38789 -38790 -38791 -38792 -38793 -38794 -38795 -38796 -38797 +v -38798 -38799 -38800 -38801 -38802 -38803 38804 -38805 38806 -38807 -38808 +v -38809 38810 -38811 38812 -38813 -38814 -38815 38816 -38817 38818 -38819 +v -38820 -38821 -38822 38823 -38824 38825 -38826 -38827 38828 -38829 -38830 +v -38831 -38832 -38833 -38834 -38835 -38836 -38837 -38838 38839 38840 38841 +v 38842 -38843 -38844 -38845 -38846 -38847 -38848 -38849 -38850 -38851 -38852 +v -38853 -38854 -38855 -38856 -38857 -38858 38859 -38860 -38861 -38862 -38863 +v -38864 38865 -38866 38867 -38868 -38869 -38870 38871 -38872 38873 -38874 +v -38875 38876 -38877 -38878 -38879 -38880 -38881 -38882 38883 38884 38885 +v 38886 -38887 38888 -38889 -38890 -38891 -38892 38893 38894 38895 38896 38897 +v 38898 38899 38900 38901 38902 -38903 -38904 38905 38906 -38907 38908 -38909 +v -38910 -38911 38912 -38913 38914 -38915 -38916 -38917 -38918 38919 38920 +v 38921 38922 38923 -38924 38925 38926 38927 -38928 38929 38930 38931 38932 +v 38933 38934 38935 38936 38937 38938 38939 38940 38941 -38942 38943 -38944 +v -38945 38946 -38947 -38948 -38949 38950 38951 38952 38953 38954 38955 38956 +v -38957 -38958 38959 38960 -38961 38962 -38963 -38964 38965 -38966 -38967 +v -38968 -38969 38970 38971 38972 38973 38974 38975 38976 -38977 38978 38979 +v 38980 -38981 38982 38983 38984 38985 38986 38987 38988 38989 38990 38991 +v 38992 38993 38994 38995 -38996 -38997 38998 38999 -39000 39001 -39002 39003 +v -39004 39005 39006 -39007 39008 -39009 39010 -39011 39012 39013 -39014 39015 +v -39016 39017 -39018 39019 -39020 -39021 39022 -39023 -39024 -39025 -39026 +v -39027 -39028 -39029 -39030 -39031 -39032 39033 39034 39035 39036 -39037 +v -39038 -39039 -39040 -39041 -39042 -39043 -39044 -39045 -39046 -39047 -39048 +v -39049 -39050 -39051 -39052 -39053 -39054 -39055 -39056 -39057 39058 -39059 +v 39060 -39061 -39062 -39063 39064 -39065 39066 -39067 -39068 39069 -39070 +v -39071 -39072 -39073 -39074 -39075 39076 39077 39078 39079 39080 -39081 +v -39082 -39083 -39084 -39085 -39086 -39087 -39088 -39089 -39090 -39091 -39092 +v -39093 -39094 -39095 -39096 -39097 -39098 -39099 -39100 -39101 39102 -39103 +v 39104 -39105 -39106 -39107 39108 -39109 39110 -39111 -39112 39113 -39114 +v -39115 -39116 -39117 -39118 -39119 39120 39121 39122 39123 39124 -39125 +v -39126 -39127 -39128 -39129 -39130 -39131 -39132 -39133 -39134 -39135 -39136 +v -39137 -39138 -39139 -39140 -39141 -39142 -39143 -39144 -39145 39146 -39147 +v 39148 -39149 -39150 -39151 39152 -39153 39154 -39155 -39156 39157 -39158 +v -39159 -39160 -39161 -39162 -39163 39164 39165 39166 39167 39168 -39169 +v -39170 -39171 -39172 -39173 -39174 -39175 -39176 -39177 -39178 -39179 -39180 +v -39181 -39182 -39183 -39184 -39185 -39186 -39187 -39188 -39189 -39190 -39191 +v -39192 -39193 -39194 -39195 -39196 -39197 -39198 -39199 -39200 -39201 -39202 +v -39203 -39204 -39205 -39206 -39207 -39208 -39209 -39210 -39211 -39212 -39213 +v -39214 -39215 -39216 -39217 -39218 -39219 -39220 -39221 -39222 -39223 -39224 +v -39225 -39226 -39227 -39228 -39229 -39230 -39231 -39232 -39233 -39234 -39235 +v -39236 -39237 -39238 -39239 -39240 -39241 -39242 -39243 -39244 -39245 -39246 +v -39247 -39248 -39249 -39250 -39251 -39252 -39253 -39254 -39255 -39256 -39257 +v -39258 -39259 -39260 -39261 -39262 -39263 -39264 -39265 -39266 -39267 -39268 +v -39269 -39270 -39271 -39272 -39273 -39274 -39275 -39276 -39277 -39278 -39279 +v -39280 -39281 -39282 -39283 -39284 -39285 -39286 -39287 -39288 -39289 -39290 +v -39291 -39292 -39293 -39294 -39295 -39296 -39297 39298 -39299 39300 -39301 +v -39302 -39303 39304 -39305 39306 -39307 -39308 -39309 39310 -39311 39312 +v -39313 -39314 -39315 -39316 39317 -39318 39319 -39320 -39321 39322 -39323 +v -39324 -39325 -39326 -39327 -39328 -39329 -39330 -39331 -39332 39333 39334 +v 39335 39336 39337 -39338 -39339 -39340 -39341 -39342 -39343 -39344 -39345 +v -39346 -39347 -39348 -39349 -39350 -39351 -39352 -39353 -39354 -39355 -39356 +v -39357 -39358 39359 -39360 39361 -39362 -39363 -39364 39365 -39366 39367 +v -39368 -39369 39370 -39371 -39372 -39373 -39374 -39375 -39376 39377 39378 +v 39379 39380 -39381 -39382 39383 -39384 -39385 39386 39387 -39388 -39389 +v -39390 -39391 -39392 -39393 -39394 -39395 -39396 -39397 -39398 -39399 -39400 +v -39401 -39402 -39403 -39404 -39405 -39406 -39407 -39408 -39409 -39410 -39411 +v -39412 -39413 -39414 -39415 -39416 -39417 -39418 -39419 -39420 -39421 -39422 +v -39423 -39424 -39425 -39426 -39427 -39428 -39429 -39430 -39431 -39432 -39433 +v -39434 -39435 -39436 -39437 -39438 -39439 -39440 -39441 -39442 -39443 -39444 +v -39445 -39446 -39447 -39448 -39449 -39450 -39451 -39452 -39453 -39454 -39455 +v -39456 -39457 -39458 -39459 -39460 -39461 -39462 -39463 -39464 -39465 -39466 +v -39467 -39468 -39469 -39470 -39471 -39472 -39473 -39474 -39475 -39476 -39477 +v -39478 -39479 -39480 -39481 -39482 -39483 -39484 -39485 -39486 -39487 -39488 +v -39489 -39490 -39491 -39492 -39493 -39494 -39495 -39496 -39497 -39498 -39499 +v -39500 -39501 -39502 -39503 -39504 -39505 -39506 -39507 -39508 -39509 -39510 +v -39511 -39512 -39513 -39514 -39515 -39516 -39517 -39518 -39519 -39520 -39521 +v -39522 -39523 -39524 -39525 -39526 -39527 -39528 -39529 -39530 -39531 -39532 +v -39533 -39534 -39535 -39536 -39537 -39538 -39539 -39540 -39541 -39542 -39543 +v -39544 -39545 -39546 -39547 -39548 -39549 -39550 -39551 -39552 -39553 -39554 +v -39555 -39556 -39557 -39558 -39559 -39560 -39561 -39562 -39563 -39564 -39565 +v -39566 -39567 -39568 -39569 -39570 -39571 -39572 -39573 -39574 -39575 -39576 +v -39577 -39578 -39579 -39580 -39581 -39582 -39583 -39584 -39585 -39586 -39587 +v -39588 -39589 -39590 -39591 -39592 -39593 -39594 -39595 -39596 -39597 -39598 +v -39599 -39600 -39601 -39602 -39603 -39604 -39605 -39606 -39607 -39608 -39609 +v -39610 -39611 -39612 -39613 -39614 -39615 -39616 -39617 -39618 -39619 -39620 +v -39621 -39622 -39623 -39624 -39625 -39626 -39627 -39628 -39629 -39630 -39631 +v -39632 -39633 -39634 -39635 -39636 -39637 -39638 -39639 -39640 -39641 -39642 +v -39643 -39644 -39645 -39646 -39647 -39648 -39649 -39650 -39651 -39652 -39653 +v -39654 -39655 -39656 -39657 -39658 -39659 -39660 39661 -39662 -39663 -39664 +v -39665 -39666 -39667 -39668 -39669 -39670 -39671 -39672 -39673 -39674 -39675 +v -39676 -39677 -39678 -39679 -39680 -39681 -39682 -39683 -39684 -39685 -39686 +v -39687 -39688 -39689 -39690 -39691 -39692 -39693 -39694 -39695 -39696 -39697 +v -39698 -39699 -39700 -39701 -39702 -39703 -39704 -39705 -39706 -39707 -39708 +v -39709 -39710 -39711 -39712 -39713 -39714 -39715 -39716 -39717 -39718 -39719 +v -39720 -39721 -39722 -39723 -39724 -39725 -39726 -39727 -39728 -39729 -39730 +v -39731 -39732 -39733 -39734 -39735 -39736 -39737 -39738 -39739 -39740 -39741 +v -39742 -39743 -39744 -39745 -39746 -39747 -39748 -39749 -39750 -39751 -39752 +v -39753 -39754 -39755 -39756 -39757 -39758 -39759 -39760 -39761 -39762 -39763 +v -39764 -39765 -39766 -39767 -39768 -39769 -39770 -39771 -39772 -39773 -39774 +v -39775 -39776 -39777 -39778 -39779 -39780 -39781 -39782 -39783 -39784 -39785 +v -39786 -39787 -39788 -39789 -39790 -39791 -39792 -39793 -39794 -39795 -39796 +v -39797 -39798 -39799 -39800 -39801 -39802 -39803 -39804 -39805 -39806 -39807 +v -39808 -39809 -39810 -39811 -39812 -39813 -39814 -39815 -39816 -39817 -39818 +v -39819 -39820 -39821 -39822 -39823 -39824 -39825 -39826 -39827 -39828 -39829 +v -39830 -39831 -39832 -39833 -39834 -39835 -39836 -39837 -39838 -39839 -39840 +v -39841 -39842 -39843 -39844 -39845 -39846 -39847 -39848 -39849 -39850 -39851 +v -39852 -39853 -39854 -39855 -39856 -39857 -39858 -39859 -39860 -39861 -39862 +v -39863 -39864 -39865 -39866 -39867 -39868 -39869 -39870 -39871 39872 -39873 +v 39874 -39875 -39876 39877 -39878 39879 -39880 -39881 -39882 39883 -39884 +v 39885 -39886 -39887 -39888 39889 -39890 39891 -39892 -39893 -39894 39895 +v -39896 39897 -39898 -39899 -39900 39901 -39902 39903 -39904 -39905 39906 +v -39907 39908 -39909 -39910 -39911 -39912 -39913 -39914 -39915 -39916 -39917 +v -39918 -39919 -39920 -39921 -39922 -39923 39924 39925 39926 39927 -39928 +v -39929 -39930 -39931 -39932 39933 -39934 -39935 -39936 -39937 -39938 -39939 +v -39940 -39941 -39942 -39943 -39944 -39945 -39946 -39947 -39948 -39949 -39950 +v -39951 -39952 -39953 -39954 -39955 -39956 -39957 -39958 -39959 -39960 -39961 +v -39962 -39963 -39964 -39965 -39966 -39967 -39968 -39969 -39970 -39971 -39972 +v -39973 -39974 -39975 -39976 -39977 -39978 -39979 -39980 -39981 -39982 -39983 +v -39984 -39985 -39986 -39987 -39988 -39989 -39990 -39991 -39992 -39993 -39994 +v -39995 -39996 -39997 -39998 -39999 -40000 -40001 -40002 -40003 -40004 -40005 +v -40006 -40007 -40008 -40009 -40010 -40011 -40012 -40013 -40014 -40015 -40016 +v -40017 -40018 -40019 -40020 -40021 -40022 -40023 -40024 -40025 -40026 -40027 +v -40028 -40029 -40030 -40031 -40032 -40033 -40034 -40035 -40036 -40037 -40038 +v -40039 -40040 -40041 -40042 -40043 -40044 -40045 -40046 -40047 -40048 -40049 +v -40050 -40051 -40052 -40053 40054 -40055 40056 -40057 -40058 -40059 -40060 +v 40061 -40062 40063 -40064 -40065 -40066 -40067 40068 -40069 40070 -40071 +v -40072 -40073 -40074 40075 -40076 40077 -40078 -40079 40080 -40081 40082 +v -40083 -40084 40085 -40086 -40087 -40088 -40089 -40090 -40091 -40092 -40093 +v -40094 -40095 -40096 -40097 40098 40099 40100 40101 -40102 -40103 -40104 +v -40105 -40106 -40107 -40108 -40109 -40110 -40111 -40112 -40113 -40114 -40115 +v -40116 -40117 -40118 -40119 -40120 -40121 -40122 -40123 -40124 -40125 -40126 +v -40127 -40128 -40129 -40130 -40131 -40132 -40133 -40134 -40135 -40136 -40137 +v -40138 -40139 -40140 -40141 -40142 -40143 -40144 -40145 -40146 -40147 -40148 +v 40149 -40150 -40151 40152 -40153 -40154 40155 -40156 -40157 -40158 40159 +v -40160 -40161 -40162 -40163 -40164 -40165 -40166 -40167 -40168 -40169 -40170 +v 40171 -40172 40173 40174 40175 40176 -40177 -40178 -40179 -40180 -40181 +v -40182 -40183 -40184 -40185 -40186 -40187 -40188 -40189 -40190 -40191 -40192 +v -40193 -40194 -40195 -40196 -40197 -40198 -40199 -40200 -40201 -40202 -40203 +v -40204 -40205 -40206 -40207 -40208 -40209 -40210 -40211 -40212 -40213 -40214 +v -40215 -40216 -40217 -40218 -40219 -40220 -40221 -40222 -40223 -40224 -40225 +v -40226 -40227 -40228 -40229 -40230 -40231 -40232 -40233 -40234 -40235 -40236 +v -40237 -40238 -40239 -40240 -40241 -40242 -40243 -40244 -40245 -40246 -40247 +v -40248 -40249 -40250 -40251 -40252 -40253 -40254 -40255 -40256 -40257 -40258 +v -40259 -40260 -40261 40262 -40263 40264 -40265 -40266 40267 -40268 40269 +v -40270 -40271 40272 -40273 40274 -40275 -40276 -40277 40278 -40279 40280 +v -40281 -40282 40283 -40284 -40285 -40286 -40287 -40288 -40289 -40290 -40291 +v -40292 -40293 40294 -40295 40296 40297 40298 40299 -40300 -40301 -40302 +v -40303 -40304 -40305 -40306 -40307 40308 -40309 40310 -40311 40312 -40313 +v -40314 -40315 -40316 40317 40318 40319 40320 -40321 -40322 -40323 -40324 +v -40325 -40326 -40327 -40328 -40329 -40330 -40331 -40332 -40333 -40334 -40335 +v -40336 -40337 -40338 -40339 -40340 -40341 -40342 -40343 -40344 -40345 -40346 +v 40347 -40348 -40349 40350 -40351 -40352 -40353 -40354 -40355 -40356 -40357 +v -40358 -40359 -40360 -40361 -40362 -40363 -40364 40365 40366 40367 40368 +v -40369 -40370 -40371 -40372 -40373 -40374 40375 -40376 -40377 -40378 -40379 +v -40380 -40381 -40382 -40383 -40384 -40385 -40386 -40387 -40388 -40389 -40390 +v -40391 -40392 -40393 -40394 -40395 -40396 -40397 -40398 -40399 -40400 -40401 +v -40402 -40403 -40404 -40405 40406 40407 40408 40409 40410 40411 -40412 +v -40413 -40414 -40415 -40416 -40417 -40418 -40419 40420 -40421 40422 40423 +v -40424 -40425 -40426 -40427 -40428 -40429 -40430 -40431 -40432 40433 -40434 +v -40435 -40436 -40437 -40438 40439 -40440 40441 -40442 -40443 -40444 40445 +v -40446 40447 40448 40449 40450 -40451 -40452 40453 -40454 -40455 -40456 +v -40457 40458 -40459 40460 -40461 -40462 40463 -40464 -40465 -40466 -40467 +v -40468 -40469 -40470 -40471 -40472 -40473 40474 40475 40476 40477 -40478 +v -40479 -40480 -40481 -40482 -40483 -40484 -40485 -40486 40487 -40488 -40489 +v 40490 -40491 -40492 -40493 -40494 -40495 40496 40497 40498 40499 -40500 +v -40501 -40502 -40503 -40504 40505 -40506 40507 -40508 40509 -40510 40511 +v -40512 -40513 40514 -40515 -40516 40517 -40518 -40519 -40520 -40521 -40522 +v -40523 -40524 -40525 40526 40527 40528 40529 40530 40531 -40532 -40533 +v -40534 40535 -40536 -40537 40538 -40539 -40540 -40541 -40542 -40543 -40544 +v -40545 -40546 -40547 -40548 -40549 -40550 -40551 -40552 -40553 -40554 -40555 +v -40556 -40557 -40558 -40559 -40560 -40561 -40562 -40563 -40564 -40565 -40566 +v -40567 -40568 -40569 40570 40571 40572 -40573 40574 40575 40576 -40577 +v -40578 -40579 -40580 40581 -40582 -40583 40584 -40585 -40586 -40587 -40588 +v -40589 -40590 -40591 -40592 -40593 -40594 -40595 -40596 -40597 40598 40599 +v 40600 40601 40602 40603 -40604 -40605 40606 40607 40608 40609 40610 40611 +v 40612 40613 -40614 -40615 -40616 -40617 -40618 -40619 -40620 -40621 -40622 +v -40623 -40624 -40625 -40626 -40627 -40628 -40629 -40630 -40631 -40632 -40633 +v -40634 -40635 -40636 -40637 -40638 -40639 40640 40641 -40642 -40643 40644 +v -40645 -40646 -40647 -40648 -40649 -40650 -40651 -40652 -40653 -40654 -40655 +v -40656 -40657 -40658 -40659 -40660 40661 -40662 -40663 -40664 -40665 -40666 +v -40667 -40668 -40669 -40670 40671 40672 40673 -40674 -40675 -40676 -40677 +v -40678 40679 -40680 -40681 40682 -40683 -40684 -40685 -40686 -40687 -40688 +v 40689 -40690 -40691 -40692 -40693 -40694 -40695 -40696 -40697 -40698 -40699 +v -40700 -40701 -40702 -40703 -40704 -40705 -40706 -40707 -40708 -40709 -40710 +v -40711 -40712 -40713 -40714 -40715 40716 40717 40718 -40719 -40720 -40721 +v -40722 -40723 -40724 40725 40726 40727 -40728 40729 -40730 -40731 40732 +v -40733 -40734 -40735 -40736 -40737 40738 -40739 -40740 -40741 -40742 -40743 +v -40744 -40745 -40746 -40747 -40748 -40749 -40750 -40751 -40752 -40753 -40754 +v -40755 -40756 -40757 -40758 -40759 -40760 -40761 -40762 -40763 -40764 -40765 +v -40766 -40767 -40768 -40769 40770 -40771 -40772 40773 -40774 -40775 -40776 +v -40777 -40778 -40779 -40780 -40781 -40782 -40783 -40784 -40785 -40786 -40787 +v 40788 40789 40790 40791 -40792 -40793 40794 -40795 -40796 -40797 -40798 +v -40799 -40800 -40801 -40802 -40803 -40804 -40805 -40806 -40807 -40808 -40809 +v -40810 -40811 40812 40813 40814 -40815 40816 -40817 -40818 40819 -40820 +v -40821 -40822 -40823 -40824 -40825 -40826 -40827 -40828 -40829 -40830 -40831 +v -40832 -40833 40834 40835 40836 40837 40838 40839 40840 40841 -40842 -40843 +v -40844 -40845 -40846 -40847 -40848 -40849 -40850 -40851 -40852 -40853 -40854 +v 40855 40856 -40857 -40858 40859 40860 -40861 -40862 -40863 -40864 40865 +v -40866 -40867 40868 -40869 -40870 -40871 -40872 -40873 -40874 -40875 -40876 +v -40877 40878 40879 40880 40881 -40882 -40883 -40884 -40885 -40886 -40887 +v -40888 -40889 -40890 40891 -40892 40893 40894 -40895 -40896 -40897 -40898 +v 40899 -40900 -40901 -40902 -40903 -40904 -40905 -40906 -40907 40908 40909 +v 40910 40911 -40912 -40913 40914 40915 40916 40917 -40918 -40919 -40920 +v -40921 -40922 -40923 -40924 -40925 -40926 -40927 -40928 40929 40930 -40931 +v -40932 -40933 -40934 -40935 -40936 -40937 -40938 -40939 -40940 -40941 -40942 +v -40943 -40944 -40945 -40946 -40947 40948 -40949 -40950 -40951 -40952 -40953 +v -40954 40955 40956 -40957 -40958 -40959 -40960 40961 -40962 -40963 40964 +v -40965 -40966 -40967 -40968 -40969 -40970 -40971 -40972 -40973 -40974 -40975 +v -40976 -40977 -40978 40979 40980 -40981 -40982 -40983 -40984 40985 40986 +v 40987 -40988 40989 -40990 -40991 40992 -40993 -40994 -40995 -40996 -40997 +v 40998 -40999 -41000 -41001 -41002 -41003 -41004 41005 41006 -41007 -41008 +v -41009 41010 41011 41012 -41013 -41014 -41015 -41016 -41017 -41018 41019 +v -41020 41021 -41022 -41023 41024 -41025 41026 -41027 -41028 -41029 41030 +v -41031 41032 41033 41034 41035 -41036 -41037 41038 -41039 -41040 -41041 +v 41042 -41043 41044 41045 41046 41047 -41048 -41049 41050 41051 41052 -41053 +v -41054 -41055 -41056 -41057 -41058 -41059 -41060 -41061 -41062 -41063 -41064 +v -41065 -41066 -41067 41068 41069 41070 41071 -41072 41073 41074 -41075 +v -41076 41077 -41078 -41079 -41080 -41081 -41082 -41083 -41084 -41085 -41086 +v 41087 41088 41089 41090 -41091 41092 -41093 -41094 -41095 -41096 -41097 +v -41098 -41099 -41100 -41101 -41102 -41103 -41104 -41105 -41106 -41107 -41108 +v -41109 -41110 -41111 -41112 -41113 -41114 -41115 -41116 -41117 41118 -41119 +v 41120 -41121 -41122 -41123 -41124 -41125 -41126 -41127 41128 41129 41130 +v 41131 -41132 41133 -41134 -41135 -41136 -41137 -41138 -41139 -41140 -41141 +v -41142 -41143 -41144 -41145 41146 41147 -41148 41149 -41150 -41151 -41152 +v -41153 -41154 41155 -41156 41157 -41158 -41159 -41160 41161 -41162 41163 +v -41164 -41165 -41166 41167 -41168 41169 41170 41171 41172 -41173 -41174 +v 41175 41176 41177 -41178 -41179 -41180 -41181 -41182 -41183 -41184 -41185 +v -41186 -41187 -41188 41189 41190 41191 41192 -41193 -41194 41195 -41196 +v 41197 -41198 -41199 -41200 -41201 -41202 -41203 -41204 -41205 -41206 -41207 +v -41208 -41209 -41210 -41211 41212 41213 -41214 -41215 -41216 -41217 -41218 +v -41219 -41220 -41221 -41222 41223 41224 41225 -41226 -41227 41228 -41229 +v -41230 -41231 -41232 -41233 -41234 -41235 -41236 -41237 -41238 -41239 -41240 +v 41241 -41242 41243 -41244 -41245 41246 -41247 41248 -41249 -41250 41251 +v -41252 41253 41254 41255 41256 -41257 -41258 41259 41260 41261 -41262 -41263 +v -41264 -41265 -41266 -41267 -41268 -41269 -41270 -41271 -41272 41273 41274 +v 41275 41276 -41277 -41278 41279 -41280 41281 -41282 -41283 -41284 -41285 +v -41286 -41287 -41288 -41289 -41290 -41291 -41292 -41293 -41294 -41295 41296 +v 41297 41298 41299 -41300 -41301 -41302 -41303 -41304 -41305 41306 -41307 +v -41308 -41309 -41310 -41311 -41312 -41313 -41314 -41315 -41316 -41317 -41318 +v 41319 41320 41321 41322 41323 -41324 -41325 -41326 41327 41328 41329 -41330 +v -41331 -41332 -41333 -41334 -41335 -41336 41337 -41338 -41339 -41340 -41341 +v -41342 -41343 -41344 41345 41346 -41347 -41348 -41349 -41350 -41351 -41352 +v -41353 -41354 41355 -41356 -41357 -41358 -41359 -41360 -41361 -41362 -41363 +v 41364 -41365 41366 -41367 -41368 41369 -41370 41371 41372 41373 -41374 +v -41375 41376 -41377 -41378 -41379 41380 -41381 41382 -41383 -41384 41385 +v -41386 -41387 -41388 -41389 -41390 -41391 -41392 -41393 -41394 -41395 41396 +v 41397 41398 41399 -41400 -41401 -41402 -41403 -41404 -41405 -41406 -41407 +v 41408 -41409 41410 -41411 -41412 -41413 -41414 -41415 41416 41417 41418 +v 41419 41420 -41421 -41422 -41423 -41424 -41425 -41426 -41427 -41428 -41429 +v -41430 -41431 -41432 -41433 -41434 -41435 -41436 41437 -41438 -41439 -41440 +v -41441 -41442 41443 -41444 41445 -41446 -41447 -41448 41449 -41450 41451 +v -41452 -41453 41454 -41455 -41456 -41457 -41458 -41459 -41460 41461 41462 +v 41463 41464 -41465 -41466 -41467 -41468 -41469 -41470 -41471 -41472 -41473 +v -41474 -41475 -41476 -41477 -41478 -41479 -41480 41481 -41482 -41483 -41484 +v -41485 -41486 41487 -41488 41489 -41490 -41491 -41492 41493 -41494 41495 +v -41496 -41497 41498 -41499 -41500 -41501 -41502 -41503 -41504 41505 41506 +v 41507 41508 -41509 -41510 -41511 -41512 -41513 -41514 -41515 -41516 -41517 +v -41518 -41519 -41520 -41521 -41522 -41523 -41524 41525 -41526 -41527 -41528 +v -41529 -41530 41531 -41532 41533 -41534 -41535 -41536 41537 -41538 41539 +v -41540 -41541 41542 -41543 -41544 -41545 -41546 -41547 -41548 41549 41550 +v 41551 41552 -41553 -41554 -41555 -41556 -41557 -41558 -41559 -41560 -41561 +v -41562 -41563 -41564 -41565 -41566 -41567 -41568 -41569 -41570 -41571 -41572 +v -41573 -41574 -41575 -41576 -41577 -41578 -41579 -41580 -41581 -41582 -41583 +v -41584 -41585 -41586 -41587 -41588 -41589 -41590 -41591 -41592 -41593 -41594 +v -41595 -41596 -41597 -41598 -41599 -41600 -41601 -41602 -41603 -41604 -41605 +v -41606 -41607 -41608 -41609 -41610 -41611 -41612 -41613 -41614 -41615 -41616 +v -41617 -41618 -41619 -41620 -41621 -41622 -41623 -41624 41625 -41626 -41627 +v -41628 -41629 -41630 -41631 -41632 -41633 -41634 -41635 -41636 -41637 -41638 +v -41639 -41640 -41641 -41642 -41643 -41644 -41645 -41646 -41647 -41648 -41649 +v -41650 -41651 -41652 -41653 -41654 -41655 -41656 -41657 -41658 -41659 -41660 +v -41661 -41662 -41663 -41664 -41665 -41666 -41667 -41668 -41669 -41670 -41671 +v -41672 -41673 -41674 -41675 -41676 -41677 -41678 -41679 -41680 -41681 -41682 +v 41683 -41684 41685 -41686 -41687 -41688 41689 -41690 41691 -41692 -41693 +v -41694 41695 -41696 41697 -41698 -41699 -41700 -41701 41702 -41703 41704 +v -41705 -41706 41707 -41708 -41709 -41710 -41711 -41712 -41713 -41714 -41715 +v -41716 -41717 41718 41719 41720 41721 -41722 -41723 -41724 -41725 -41726 +v -41727 -41728 -41729 -41730 -41731 -41732 -41733 -41734 -41735 -41736 -41737 +v 41738 -41739 -41740 -41741 -41742 -41743 41744 -41745 41746 -41747 -41748 +v -41749 41750 -41751 41752 -41753 -41754 41755 -41756 -41757 -41758 -41759 +v -41760 -41761 41762 41763 41764 41765 -41766 41767 -41768 -41769 -41770 +v -41771 41772 41773 41774 41775 41776 41777 41778 41779 41780 41781 -41782 +v -41783 41784 41785 -41786 41787 -41788 -41789 -41790 41791 -41792 41793 +v -41794 -41795 -41796 -41797 41798 41799 41800 41801 41802 -41803 41804 41805 +v 41806 -41807 41808 41809 41810 41811 41812 41813 41814 41815 41816 41817 +v 41818 41819 41820 -41821 41822 -41823 -41824 41825 -41826 -41827 -41828 +v 41829 41830 41831 41832 41833 41834 41835 -41836 -41837 41838 41839 -41840 +v 41841 -41842 -41843 41844 -41845 -41846 -41847 -41848 41849 41850 41851 +v 41852 41853 41854 41855 -41856 41857 41858 41859 -41860 41861 41862 41863 +v 41864 41865 41866 41867 41868 41869 41870 41871 41872 41873 41874 -41875 +v -41876 41877 41878 -41879 41880 -41881 41882 -41883 41884 41885 -41886 41887 +v -41888 41889 -41890 41891 41892 -41893 41894 -41895 41896 -41897 41898 +v -41899 -41900 41901 -41902 -41903 -41904 -41905 -41906 -41907 -41908 -41909 +v -41910 -41911 41912 41913 41914 41915 -41916 -41917 -41918 -41919 -41920 +v -41921 -41922 -41923 -41924 -41925 -41926 -41927 -41928 -41929 -41930 -41931 +v -41932 -41933 -41934 -41935 -41936 41937 -41938 41939 -41940 -41941 -41942 +v 41943 -41944 41945 -41946 -41947 41948 -41949 -41950 -41951 -41952 -41953 +v -41954 41955 41956 41957 41958 41959 -41960 -41961 -41962 -41963 -41964 +v -41965 -41966 -41967 -41968 -41969 -41970 -41971 -41972 -41973 -41974 -41975 +v -41976 -41977 -41978 -41979 -41980 41981 -41982 41983 -41984 -41985 -41986 +v 41987 -41988 41989 -41990 -41991 41992 -41993 -41994 -41995 -41996 -41997 +v -41998 41999 42000 42001 42002 42003 -42004 -42005 -42006 -42007 -42008 +v -42009 -42010 -42011 -42012 -42013 -42014 -42015 -42016 -42017 -42018 -42019 +v -42020 -42021 -42022 -42023 -42024 42025 -42026 42027 -42028 -42029 -42030 +v 42031 -42032 42033 -42034 -42035 42036 -42037 -42038 -42039 -42040 -42041 +v -42042 42043 42044 42045 42046 42047 -42048 -42049 -42050 -42051 -42052 +v -42053 -42054 -42055 -42056 -42057 -42058 -42059 -42060 -42061 -42062 -42063 +v -42064 -42065 -42066 -42067 -42068 -42069 -42070 -42071 -42072 -42073 -42074 +v -42075 -42076 -42077 -42078 -42079 -42080 -42081 -42082 -42083 -42084 -42085 +v -42086 -42087 -42088 -42089 -42090 -42091 -42092 -42093 -42094 -42095 -42096 +v -42097 -42098 -42099 -42100 -42101 -42102 -42103 -42104 -42105 -42106 -42107 +v -42108 -42109 -42110 -42111 -42112 -42113 -42114 -42115 -42116 -42117 -42118 +v -42119 -42120 -42121 -42122 -42123 -42124 -42125 -42126 -42127 -42128 -42129 +v -42130 -42131 -42132 -42133 -42134 -42135 -42136 -42137 -42138 -42139 -42140 +v -42141 -42142 -42143 -42144 -42145 -42146 -42147 -42148 -42149 -42150 -42151 +v -42152 -42153 -42154 -42155 -42156 -42157 -42158 -42159 -42160 -42161 -42162 +v -42163 -42164 -42165 -42166 -42167 -42168 -42169 -42170 -42171 -42172 -42173 +v -42174 -42175 -42176 42177 -42178 42179 -42180 -42181 -42182 42183 -42184 +v 42185 -42186 -42187 -42188 42189 -42190 42191 -42192 -42193 -42194 -42195 +v 42196 -42197 42198 -42199 -42200 42201 -42202 -42203 -42204 -42205 -42206 +v -42207 -42208 -42209 -42210 -42211 42212 42213 42214 42215 42216 -42217 +v -42218 -42219 -42220 -42221 -42222 -42223 -42224 -42225 -42226 -42227 -42228 +v -42229 -42230 -42231 -42232 -42233 -42234 -42235 -42236 -42237 42238 -42239 +v 42240 -42241 -42242 -42243 42244 -42245 42246 -42247 -42248 42249 -42250 +v -42251 -42252 -42253 -42254 -42255 42256 42257 42258 42259 -42260 -42261 +v 42262 -42263 -42264 42265 42266 -42267 -42268 -42269 -42270 -42271 -42272 +v -42273 -42274 -42275 -42276 -42277 -42278 -42279 -42280 -42281 -42282 -42283 +v -42284 -42285 -42286 -42287 -42288 -42289 -42290 -42291 -42292 -42293 -42294 +v -42295 -42296 -42297 -42298 -42299 -42300 -42301 -42302 -42303 -42304 -42305 +v -42306 -42307 -42308 -42309 -42310 -42311 -42312 -42313 -42314 -42315 -42316 +v -42317 -42318 -42319 -42320 -42321 -42322 -42323 -42324 -42325 -42326 -42327 +v -42328 -42329 -42330 -42331 -42332 -42333 -42334 -42335 -42336 -42337 -42338 +v -42339 -42340 -42341 -42342 -42343 -42344 -42345 -42346 -42347 -42348 -42349 +v -42350 -42351 -42352 -42353 -42354 -42355 -42356 -42357 -42358 -42359 -42360 +v -42361 -42362 -42363 -42364 -42365 -42366 -42367 -42368 -42369 -42370 -42371 +v -42372 -42373 -42374 -42375 -42376 -42377 -42378 -42379 -42380 -42381 -42382 +v -42383 -42384 -42385 -42386 -42387 -42388 -42389 -42390 -42391 -42392 -42393 +v -42394 -42395 -42396 -42397 -42398 -42399 -42400 -42401 -42402 -42403 -42404 +v -42405 -42406 -42407 -42408 -42409 -42410 -42411 -42412 -42413 -42414 -42415 +v -42416 -42417 -42418 -42419 -42420 -42421 -42422 -42423 -42424 -42425 -42426 +v -42427 -42428 -42429 -42430 -42431 -42432 -42433 -42434 -42435 -42436 -42437 +v -42438 -42439 -42440 -42441 -42442 -42443 -42444 -42445 -42446 -42447 -42448 +v -42449 -42450 -42451 -42452 -42453 -42454 -42455 -42456 -42457 -42458 -42459 +v -42460 -42461 -42462 -42463 -42464 -42465 -42466 -42467 -42468 -42469 -42470 +v -42471 -42472 -42473 -42474 -42475 -42476 -42477 -42478 -42479 -42480 -42481 +v -42482 -42483 -42484 -42485 -42486 -42487 -42488 -42489 -42490 -42491 -42492 +v -42493 -42494 -42495 -42496 -42497 -42498 -42499 -42500 -42501 -42502 -42503 +v -42504 -42505 -42506 -42507 -42508 -42509 -42510 -42511 -42512 -42513 -42514 +v -42515 -42516 -42517 -42518 -42519 -42520 -42521 -42522 -42523 -42524 -42525 +v -42526 -42527 -42528 -42529 -42530 -42531 -42532 -42533 -42534 -42535 -42536 +v -42537 -42538 -42539 -42540 -42541 -42542 -42543 -42544 -42545 -42546 -42547 +v -42548 -42549 -42550 -42551 -42552 -42553 -42554 -42555 -42556 -42557 -42558 +v -42559 -42560 -42561 -42562 -42563 -42564 -42565 -42566 -42567 -42568 -42569 +v -42570 -42571 -42572 -42573 -42574 -42575 -42576 -42577 -42578 -42579 -42580 +v -42581 -42582 -42583 -42584 -42585 -42586 -42587 -42588 -42589 -42590 -42591 +v -42592 -42593 -42594 -42595 -42596 -42597 -42598 -42599 -42600 -42601 -42602 +v -42603 -42604 -42605 -42606 -42607 -42608 -42609 -42610 -42611 -42612 -42613 +v -42614 -42615 -42616 -42617 -42618 -42619 -42620 -42621 -42622 -42623 -42624 +v -42625 -42626 -42627 -42628 -42629 -42630 -42631 -42632 -42633 -42634 -42635 +v -42636 -42637 -42638 -42639 -42640 -42641 -42642 -42643 -42644 -42645 -42646 +v -42647 -42648 -42649 -42650 -42651 -42652 -42653 -42654 -42655 -42656 -42657 +v -42658 -42659 -42660 -42661 -42662 -42663 -42664 -42665 -42666 -42667 -42668 +v -42669 -42670 -42671 -42672 -42673 -42674 -42675 -42676 -42677 -42678 -42679 +v -42680 -42681 -42682 -42683 -42684 -42685 -42686 -42687 -42688 -42689 -42690 +v -42691 -42692 -42693 -42694 -42695 -42696 -42697 -42698 -42699 -42700 -42701 +v -42702 -42703 -42704 -42705 -42706 -42707 -42708 -42709 -42710 -42711 -42712 +v -42713 -42714 -42715 -42716 -42717 -42718 -42719 -42720 -42721 -42722 -42723 +v -42724 -42725 -42726 -42727 -42728 -42729 -42730 -42731 -42732 -42733 -42734 +v -42735 -42736 -42737 -42738 -42739 -42740 -42741 -42742 -42743 42744 -42745 +v 42746 -42747 -42748 42749 -42750 42751 -42752 -42753 -42754 42755 -42756 +v 42757 -42758 -42759 -42760 42761 -42762 42763 -42764 -42765 -42766 42767 +v -42768 42769 -42770 -42771 -42772 42773 -42774 42775 -42776 -42777 42778 +v -42779 42780 -42781 -42782 -42783 -42784 -42785 -42786 -42787 -42788 -42789 +v -42790 -42791 -42792 -42793 -42794 -42795 42796 42797 42798 42799 -42800 +v -42801 -42802 -42803 -42804 42805 -42806 -42807 -42808 -42809 -42810 -42811 +v -42812 -42813 -42814 -42815 -42816 -42817 -42818 -42819 -42820 -42821 -42822 +v -42823 -42824 -42825 -42826 -42827 -42828 -42829 -42830 -42831 -42832 -42833 +v -42834 -42835 -42836 -42837 -42838 -42839 -42840 -42841 -42842 -42843 -42844 +v -42845 -42846 -42847 -42848 -42849 -42850 -42851 -42852 -42853 -42854 -42855 +v -42856 -42857 -42858 -42859 -42860 -42861 -42862 -42863 -42864 -42865 -42866 +v -42867 -42868 -42869 -42870 -42871 -42872 -42873 -42874 -42875 -42876 -42877 +v -42878 -42879 -42880 -42881 -42882 -42883 -42884 -42885 -42886 -42887 -42888 +v -42889 -42890 -42891 -42892 -42893 -42894 -42895 -42896 -42897 -42898 -42899 +v -42900 -42901 -42902 -42903 -42904 -42905 -42906 -42907 -42908 -42909 -42910 +v -42911 -42912 -42913 -42914 -42915 -42916 -42917 -42918 -42919 -42920 -42921 +v -42922 -42923 -42924 -42925 42926 -42927 42928 -42929 -42930 -42931 -42932 +v 42933 -42934 42935 -42936 -42937 -42938 -42939 42940 -42941 42942 -42943 +v -42944 -42945 -42946 42947 -42948 42949 -42950 -42951 42952 -42953 42954 +v -42955 -42956 42957 -42958 -42959 -42960 -42961 -42962 -42963 -42964 -42965 +v -42966 -42967 -42968 -42969 42970 42971 42972 42973 -42974 -42975 -42976 +v -42977 -42978 -42979 -42980 -42981 -42982 -42983 -42984 -42985 -42986 -42987 +v -42988 -42989 -42990 -42991 -42992 -42993 -42994 -42995 -42996 -42997 -42998 +v -42999 -43000 -43001 -43002 -43003 -43004 -43005 -43006 -43007 -43008 -43009 +v -43010 -43011 -43012 -43013 -43014 -43015 -43016 -43017 -43018 -43019 -43020 +v 43021 -43022 -43023 43024 -43025 -43026 43027 -43028 -43029 -43030 43031 +v -43032 -43033 -43034 -43035 -43036 -43037 -43038 -43039 -43040 -43041 -43042 +v 43043 -43044 43045 43046 43047 43048 -43049 -43050 -43051 -43052 -43053 +v -43054 -43055 -43056 -43057 -43058 -43059 -43060 -43061 -43062 -43063 -43064 +v -43065 -43066 -43067 -43068 -43069 -43070 -43071 -43072 -43073 -43074 -43075 +v -43076 -43077 -43078 -43079 -43080 -43081 -43082 -43083 -43084 -43085 -43086 +v -43087 -43088 -43089 -43090 -43091 -43092 -43093 -43094 -43095 -43096 -43097 +v -43098 -43099 -43100 -43101 -43102 -43103 -43104 -43105 -43106 -43107 -43108 +v -43109 -43110 -43111 -43112 -43113 -43114 -43115 -43116 -43117 -43118 -43119 +v -43120 -43121 -43122 -43123 -43124 -43125 -43126 -43127 -43128 -43129 -43130 +v -43131 -43132 -43133 43134 -43135 43136 -43137 -43138 43139 -43140 43141 +v -43142 -43143 43144 -43145 43146 -43147 -43148 -43149 43150 -43151 43152 +v -43153 -43154 43155 -43156 -43157 -43158 -43159 -43160 -43161 -43162 -43163 +v -43164 -43165 43166 -43167 43168 43169 43170 43171 -43172 -43173 -43174 +v -43175 -43176 -43177 -43178 -43179 43180 -43181 43182 -43183 43184 -43185 +v -43186 -43187 -43188 43189 43190 43191 43192 -43193 -43194 -43195 -43196 +v -43197 -43198 -43199 -43200 -43201 -43202 -43203 -43204 -43205 -43206 -43207 +v -43208 -43209 -43210 -43211 -43212 -43213 -43214 -43215 -43216 -43217 -43218 +v 43219 -43220 -43221 43222 -43223 -43224 -43225 -43226 -43227 -43228 -43229 +v -43230 -43231 -43232 -43233 -43234 -43235 -43236 43237 43238 43239 43240 +v -43241 -43242 -43243 -43244 -43245 -43246 43247 -43248 -43249 -43250 -43251 +v -43252 -43253 -43254 -43255 -43256 -43257 -43258 -43259 -43260 -43261 -43262 +v -43263 -43264 -43265 -43266 -43267 -43268 -43269 -43270 -43271 -43272 -43273 +v -43274 -43275 -43276 -43277 43278 43279 43280 43281 43282 43283 -43284 +v -43285 -43286 -43287 -43288 -43289 -43290 -43291 43292 -43293 43294 43295 +v -43296 -43297 -43298 -43299 -43300 -43301 -43302 -43303 -43304 43305 -43306 +v -43307 -43308 -43309 -43310 43311 -43312 43313 -43314 -43315 -43316 43317 +v -43318 43319 43320 43321 43322 -43323 -43324 43325 -43326 -43327 -43328 +v -43329 43330 -43331 43332 -43333 -43334 43335 -43336 -43337 -43338 -43339 +v -43340 -43341 -43342 -43343 -43344 -43345 43346 43347 43348 43349 -43350 +v -43351 -43352 -43353 -43354 -43355 -43356 -43357 -43358 43359 -43360 -43361 +v 43362 -43363 -43364 -43365 -43366 -43367 43368 43369 43370 43371 -43372 +v -43373 -43374 -43375 -43376 43377 -43378 43379 -43380 43381 -43382 43383 +v -43384 -43385 43386 -43387 -43388 43389 -43390 -43391 -43392 -43393 -43394 +v -43395 -43396 -43397 43398 43399 43400 43401 43402 43403 -43404 -43405 +v -43406 43407 -43408 -43409 43410 -43411 -43412 -43413 -43414 -43415 -43416 +v -43417 -43418 -43419 -43420 -43421 -43422 -43423 -43424 -43425 -43426 -43427 +v -43428 -43429 -43430 -43431 -43432 -43433 -43434 -43435 -43436 -43437 -43438 +v -43439 -43440 -43441 43442 43443 43444 -43445 43446 43447 43448 -43449 +v -43450 -43451 -43452 43453 -43454 -43455 43456 -43457 -43458 -43459 -43460 +v -43461 -43462 -43463 -43464 -43465 -43466 -43467 -43468 -43469 43470 43471 +v 43472 43473 43474 43475 -43476 -43477 43478 43479 43480 43481 43482 43483 +v 43484 43485 -43486 -43487 -43488 -43489 -43490 -43491 -43492 -43493 -43494 +v -43495 -43496 -43497 -43498 -43499 -43500 -43501 -43502 -43503 -43504 -43505 +v -43506 -43507 -43508 -43509 -43510 -43511 43512 43513 -43514 -43515 43516 +v -43517 -43518 -43519 -43520 -43521 -43522 -43523 -43524 -43525 -43526 -43527 +v -43528 -43529 -43530 -43531 -43532 43533 -43534 -43535 -43536 -43537 -43538 +v -43539 -43540 -43541 -43542 43543 43544 43545 -43546 -43547 -43548 -43549 +v -43550 43551 -43552 -43553 43554 -43555 -43556 -43557 -43558 -43559 -43560 +v 43561 -43562 -43563 -43564 -43565 -43566 -43567 -43568 -43569 -43570 -43571 +v -43572 -43573 -43574 -43575 -43576 -43577 -43578 -43579 -43580 -43581 -43582 +v -43583 -43584 -43585 -43586 -43587 43588 43589 43590 -43591 -43592 -43593 +v -43594 -43595 -43596 43597 43598 43599 -43600 43601 -43602 -43603 43604 +v -43605 -43606 -43607 -43608 -43609 43610 -43611 -43612 -43613 -43614 -43615 +v -43616 -43617 -43618 -43619 -43620 -43621 -43622 -43623 -43624 -43625 -43626 +v -43627 -43628 -43629 -43630 -43631 -43632 -43633 -43634 -43635 -43636 -43637 +v -43638 -43639 -43640 -43641 43642 -43643 -43644 43645 -43646 -43647 -43648 +v -43649 -43650 -43651 -43652 -43653 -43654 -43655 -43656 -43657 -43658 -43659 +v 43660 43661 43662 43663 -43664 -43665 43666 -43667 -43668 -43669 -43670 +v -43671 -43672 -43673 -43674 -43675 -43676 -43677 -43678 -43679 -43680 -43681 +v -43682 -43683 43684 43685 43686 -43687 43688 -43689 -43690 43691 -43692 +v -43693 -43694 -43695 -43696 -43697 -43698 -43699 -43700 -43701 -43702 -43703 +v -43704 -43705 43706 43707 43708 43709 43710 43711 43712 43713 -43714 -43715 +v -43716 -43717 -43718 -43719 -43720 -43721 -43722 -43723 -43724 -43725 -43726 +v 43727 43728 -43729 -43730 43731 43732 -43733 -43734 -43735 -43736 43737 +v -43738 -43739 43740 -43741 -43742 -43743 -43744 -43745 -43746 -43747 -43748 +v -43749 43750 43751 43752 43753 -43754 -43755 -43756 -43757 -43758 -43759 +v -43760 -43761 -43762 43763 -43764 43765 43766 -43767 -43768 -43769 -43770 +v 43771 -43772 -43773 -43774 -43775 -43776 -43777 -43778 -43779 43780 43781 +v 43782 43783 -43784 -43785 43786 43787 43788 43789 -43790 -43791 -43792 +v -43793 -43794 -43795 -43796 -43797 -43798 -43799 -43800 43801 43802 -43803 +v -43804 -43805 -43806 -43807 -43808 -43809 -43810 -43811 -43812 -43813 -43814 +v -43815 -43816 -43817 -43818 -43819 43820 -43821 -43822 -43823 -43824 -43825 +v -43826 43827 43828 -43829 -43830 -43831 -43832 43833 -43834 -43835 43836 +v -43837 -43838 -43839 -43840 -43841 -43842 -43843 -43844 -43845 -43846 -43847 +v -43848 -43849 -43850 43851 43852 -43853 -43854 -43855 -43856 43857 43858 +v 43859 -43860 43861 -43862 -43863 43864 -43865 -43866 -43867 -43868 -43869 +v 43870 -43871 -43872 -43873 -43874 -43875 -43876 43877 43878 -43879 -43880 +v -43881 43882 43883 43884 -43885 -43886 -43887 -43888 -43889 -43890 43891 +v -43892 43893 -43894 -43895 43896 -43897 43898 -43899 -43900 -43901 43902 +v -43903 43904 43905 43906 43907 -43908 -43909 43910 -43911 -43912 -43913 +v 43914 -43915 43916 43917 43918 43919 -43920 -43921 43922 43923 43924 -43925 +v -43926 -43927 -43928 -43929 -43930 -43931 -43932 -43933 -43934 -43935 -43936 +v -43937 -43938 -43939 43940 43941 43942 43943 -43944 43945 43946 -43947 +v -43948 43949 -43950 -43951 -43952 -43953 -43954 -43955 -43956 -43957 -43958 +v 43959 43960 43961 43962 -43963 43964 -43965 -43966 -43967 -43968 -43969 +v -43970 -43971 -43972 -43973 -43974 -43975 -43976 -43977 -43978 -43979 -43980 +v -43981 -43982 -43983 -43984 -43985 -43986 -43987 -43988 -43989 43990 -43991 +v 43992 -43993 -43994 -43995 -43996 -43997 -43998 -43999 44000 44001 44002 +v 44003 -44004 44005 -44006 -44007 -44008 -44009 -44010 -44011 -44012 -44013 +v -44014 -44015 -44016 -44017 44018 44019 -44020 44021 -44022 -44023 -44024 +v -44025 -44026 44027 -44028 44029 -44030 -44031 -44032 44033 -44034 44035 +v -44036 -44037 -44038 44039 -44040 44041 44042 44043 44044 -44045 -44046 +v 44047 44048 44049 -44050 -44051 -44052 -44053 -44054 -44055 -44056 -44057 +v -44058 -44059 -44060 44061 44062 44063 44064 -44065 -44066 44067 -44068 +v 44069 -44070 -44071 -44072 -44073 -44074 -44075 -44076 -44077 -44078 -44079 +v -44080 -44081 -44082 -44083 44084 44085 -44086 -44087 -44088 -44089 -44090 +v -44091 -44092 -44093 -44094 44095 44096 44097 -44098 -44099 44100 -44101 +v -44102 -44103 -44104 -44105 -44106 -44107 -44108 -44109 -44110 -44111 -44112 +v 44113 -44114 44115 -44116 -44117 44118 -44119 44120 -44121 -44122 44123 +v -44124 44125 44126 44127 44128 -44129 -44130 44131 44132 44133 -44134 -44135 +v -44136 -44137 -44138 -44139 -44140 -44141 -44142 -44143 -44144 44145 44146 +v 44147 44148 -44149 -44150 44151 -44152 44153 -44154 -44155 -44156 -44157 +v -44158 -44159 -44160 -44161 -44162 -44163 -44164 -44165 -44166 -44167 44168 +v 44169 44170 44171 -44172 -44173 -44174 -44175 -44176 -44177 44178 -44179 +v -44180 -44181 -44182 -44183 -44184 -44185 -44186 -44187 -44188 -44189 -44190 +v 44191 44192 44193 44194 44195 -44196 -44197 -44198 44199 44200 44201 -44202 +v -44203 -44204 -44205 -44206 -44207 -44208 44209 -44210 -44211 -44212 -44213 +v -44214 -44215 -44216 44217 44218 -44219 -44220 -44221 -44222 -44223 -44224 +v -44225 -44226 44227 -44228 -44229 -44230 -44231 -44232 -44233 -44234 -44235 +v 44236 -44237 44238 -44239 -44240 44241 -44242 44243 44244 44245 -44246 +v -44247 44248 -44249 -44250 -44251 44252 -44253 44254 -44255 -44256 44257 +v -44258 -44259 -44260 -44261 -44262 -44263 -44264 -44265 -44266 -44267 44268 +v 44269 44270 44271 -44272 -44273 -44274 -44275 -44276 -44277 -44278 -44279 +v 44280 -44281 44282 -44283 -44284 -44285 -44286 -44287 44288 44289 44290 +v 44291 44292 -44293 -44294 -44295 -44296 -44297 -44298 -44299 -44300 -44301 +v -44302 -44303 -44304 -44305 -44306 -44307 -44308 44309 -44310 -44311 -44312 +v -44313 -44314 44315 -44316 44317 -44318 -44319 -44320 44321 -44322 44323 +v -44324 -44325 44326 -44327 -44328 -44329 -44330 -44331 -44332 44333 44334 +v 44335 44336 -44337 -44338 -44339 -44340 -44341 -44342 -44343 -44344 -44345 +v -44346 -44347 -44348 -44349 -44350 -44351 -44352 44353 -44354 -44355 -44356 +v -44357 -44358 44359 -44360 44361 -44362 -44363 -44364 44365 -44366 44367 +v -44368 -44369 44370 -44371 -44372 -44373 -44374 -44375 -44376 44377 44378 +v 44379 44380 -44381 -44382 -44383 -44384 -44385 -44386 -44387 -44388 -44389 +v -44390 -44391 -44392 -44393 -44394 -44395 -44396 44397 -44398 -44399 -44400 +v -44401 -44402 44403 -44404 44405 -44406 -44407 -44408 44409 -44410 44411 +v -44412 -44413 44414 -44415 -44416 -44417 -44418 -44419 -44420 44421 44422 +v 44423 44424 -44425 -44426 -44427 -44428 -44429 -44430 -44431 -44432 -44433 +v -44434 -44435 -44436 -44437 -44438 -44439 -44440 -44441 -44442 -44443 -44444 +v -44445 -44446 -44447 -44448 -44449 -44450 -44451 -44452 -44453 -44454 -44455 +v -44456 -44457 -44458 -44459 -44460 -44461 -44462 -44463 -44464 -44465 -44466 +v -44467 -44468 -44469 -44470 -44471 -44472 -44473 -44474 -44475 -44476 -44477 +v -44478 -44479 -44480 -44481 -44482 -44483 -44484 -44485 -44486 -44487 -44488 +v -44489 -44490 -44491 -44492 -44493 -44494 -44495 -44496 44497 -44498 -44499 +v -44500 -44501 -44502 -44503 -44504 -44505 -44506 -44507 -44508 -44509 -44510 +v -44511 -44512 -44513 -44514 -44515 -44516 -44517 -44518 -44519 -44520 -44521 +v -44522 -44523 -44524 -44525 -44526 -44527 -44528 -44529 -44530 -44531 -44532 +v -44533 -44534 -44535 -44536 -44537 -44538 -44539 -44540 -44541 -44542 -44543 +v -44544 -44545 -44546 -44547 -44548 -44549 -44550 -44551 -44552 -44553 -44554 +v 44555 -44556 44557 -44558 -44559 -44560 44561 -44562 44563 -44564 -44565 +v -44566 44567 -44568 44569 -44570 -44571 -44572 -44573 44574 -44575 44576 +v -44577 -44578 44579 -44580 -44581 -44582 -44583 -44584 -44585 -44586 -44587 +v -44588 -44589 44590 44591 44592 44593 -44594 -44595 -44596 -44597 -44598 +v -44599 -44600 -44601 -44602 -44603 -44604 -44605 -44606 -44607 -44608 -44609 +v 44610 -44611 -44612 -44613 -44614 -44615 44616 -44617 44618 -44619 -44620 +v -44621 44622 -44623 44624 -44625 -44626 44627 -44628 -44629 -44630 -44631 +v -44632 -44633 44634 44635 44636 44637 -44638 44639 -44640 -44641 -44642 +v -44643 44644 44645 44646 44647 44648 44649 44650 44651 44652 44653 -44654 +v -44655 44656 44657 -44658 44659 -44660 -44661 -44662 44663 -44664 44665 +v -44666 -44667 -44668 -44669 44670 44671 44672 44673 44674 -44675 44676 44677 +v 44678 -44679 44680 44681 44682 44683 44684 44685 44686 44687 44688 44689 +v 44690 44691 44692 -44693 44694 -44695 -44696 44697 -44698 -44699 -44700 +v 44701 44702 44703 44704 44705 44706 44707 -44708 -44709 44710 44711 -44712 +v 44713 -44714 -44715 44716 -44717 -44718 -44719 -44720 44721 44722 44723 +v 44724 44725 44726 44727 -44728 44729 44730 44731 -44732 44733 44734 44735 +v 44736 44737 44738 44739 44740 44741 44742 44743 44744 44745 44746 -44747 +v -44748 44749 44750 -44751 44752 -44753 44754 -44755 44756 44757 -44758 44759 +v -44760 44761 -44762 44763 44764 -44765 44766 -44767 44768 -44769 44770 +v -44771 -44772 44773 -44774 -44775 -44776 -44777 -44778 -44779 -44780 -44781 +v -44782 -44783 44784 44785 44786 44787 -44788 -44789 44790 44791 -44792 +v -44793 44794 44795 -44796 -44797 -44798 -44799 -44800 44801 44802 44803 +v 44804 44805 0 +c +c ---- [ profiling ] --------------------------------------------------------- +c +c 0.19 82.65 % search +c 0.18 76.24 % focused +c 0.04 15.31 % parse +c 0.01 6.36 % stable +c 0.00 1.38 % reduce +c 0.00 0.00 % simplify +c ============================================= +c 0.23 100.00 % total +c +c ---- [ statistics ] -------------------------------------------------------- +c +c chronological: 95 8 % conflicts +c conflicts: 1143 4862.01 per second +c decisions: 14767 12.92 per conflict +c jumped_reasons: 420178 20 % propagations +c propagations: 2142807 9114914 per second +c queue_decisions: 13121 89 % decision +c random_decisions: 700 5 % decision +c random_sequences: 1 1143 interval +c reductions: 1 1143 interval +c rephased: 1 1143 interval +c restarts: 147 7.78 interval +c score_decisions: 946 6 % decision +c switched: 1 1143 interval +c vivify_checks: 0 0 per vivify +c vivify_units: 0 0 % variables +c +c ---- [ resources ] --------------------------------------------------------- +c +c maximum-resident-set-size: 15581184 bytes 15 MB +c process-time: 0.23 seconds +c +c ---- [ shutting down ] ----------------------------------------------------- +c +c exit 10 diff --git a/data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt b/data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt new file mode 100644 index 00000000..9348ab06 --- /dev/null +++ b/data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt @@ -0,0 +1,147 @@ +c ---- [ banner ] ------------------------------------------------------------ +c +c Kissat SAT Solver +c +c Copyright (c) 2021-2023 Armin Biere University of Freiburg +c Copyright (c) 2019-2021 Armin Biere Johannes Kepler University Linz +c +c Version 3.1.1 71caafb4d182ced9f76cef45b00f37cc598f2a37 +c gcc (GCC) 13.2.1 20230801 -W -Wall -O3 -DNDEBUG +c Wed Apr 24 16:38:09 EEST 2024 Linux Christoph-laptop 6.8.2-arch2-1 x86_64 +c +c ---- [ parsing ] ----------------------------------------------------------- +c +c opened and reading DIMACS file: +c +c ../sat-rs/rustsat/data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf +c +c parsed 'p cnf 27224 68879' header +c closing input after reading 1111443 bytes (1 MB) +c finished parsing after 0.02 seconds +c +c ---- [ solving ] ----------------------------------------------------------- +c +c seconds switched conflicts irredundant variables +c MB reductions redundant trail remaining +c level restarts binary glue +c +c * 0.02 7 0 0 0 0 0 0 45918 22959 0% 0 27158 100% +c { 0.02 7 0 0 0 0 0 0 45918 22959 0% 0 27158 100% +c i 0.03 8 73 0 0 0 210 153 45974 22959 18% 2 27156 100% +c i 0.05 8 208 0 0 84 413 292 46032 22959 19% 14 27154 100% +c - 0.11 8 266 0 1 132 1023 145 45801 22959 23% 46 27154 100% +c } 0.11 8 266 1 1 132 1023 145 45801 22959 23% 46 27154 100% +c [ 0.11 8 0 1 1 132 1023 145 45801 22959 0% 0 27154 100% +c B 0.11 8 0 1 1 132 1023 145 45801 22959 0% 0 27154 100% +c i 0.13 8 100 1 1 132 1239 304 45857 22959 19% 2 27153 100% +c - 0.20 8 412 1 2 132 2034 283 45804 22959 26% 76 27153 100% +c W 0.20 9 412 1 2 132 2034 283 45804 22925 26% 76 27153 100% +c d 0.22 9 378 1 2 133 2340 548 45837 22888 25% 74 27151 100% +c b 0.22 9 378 1 2 133 2340 548 45837 22888 25% 74 27148 100% +c u 0.23 9 378 1 2 133 2340 505 45880 22888 25% 74 27148 100% +c v 0.23 9 378 1 2 133 2340 495 45889 22888 25% 74 27147 100% +c w 0.24 9 378 1 2 133 2340 495 45917 22752 25% 74 26735 98% +c = 0.26 9 378 1 2 133 2340 495 46806 22222 25% 74 26286 97% +c d 0.27 9 378 1 2 133 2340 474 45668 21979 25% 74 26281 97% +c i 0.27 9 378 1 2 133 2340 474 45668 21979 25% 74 26281 97% +c i 0.28 9 377 1 2 133 2391 524 45668 21979 25% 73 26280 97% +c +c seconds switched conflicts irredundant variables +c MB reductions redundant trail remaining +c level restarts binary glue +c +c i 0.28 9 374 1 2 133 2420 552 45668 21979 24% 73 26278 97% +c ] 0.32 10 361 2 2 133 2891 1023 45668 21979 24% 68 26278 97% +c { 0.32 10 266 2 2 133 2891 1023 45668 21979 23% 46 26278 97% +c i 0.33 10 226 2 2 138 3176 1193 45780 21979 22% 37 26277 97% +c - 0.37 10 294 2 3 182 3448 454 44424 21979 24% 35 26277 97% +c } 0.46 10 442 3 3 362 3891 870 44437 21979 28% 38 26277 97% +c [ 0.46 10 361 3 3 362 3891 870 44437 21979 24% 68 26277 97% +c I 0.53 10 476 3 3 362 4293 1272 44437 21979 27% 65 26277 97% +c d 0.56 10 429 3 3 362 4673 1529 44176 21940 26% 64 26128 96% +c u 0.57 10 429 3 3 362 4673 1444 44261 21940 26% 64 26128 96% +c v 0.57 10 429 3 3 362 4673 1443 44262 21940 26% 64 26128 96% +c = 0.61 10 429 3 3 362 4673 1443 44330 21940 26% 64 26094 96% +c d 0.62 10 429 3 3 362 4673 1443 44188 21940 26% 64 26092 96% +c - 0.66 10 414 3 4 363 5181 521 44131 21940 25% 62 26092 96% +c ] 0.78 10 381 4 4 364 6762 2054 44131 21940 24% 59 26092 96% +c { 0.78 10 442 4 4 364 6762 2054 44131 21940 28% 38 26092 96% +c i 0.79 10 425 4 4 369 6890 2116 44187 21940 28% 36 26091 96% +c - 0.80 10 400 4 5 382 7196 591 44128 21940 27% 39 26091 96% +c } 0.92 10 439 5 5 510 9130 2395 44181 21940 28% 43 26091 96% +c [ 0.92 10 381 5 5 510 9130 2395 44181 21940 24% 59 26091 96% +c +c seconds switched conflicts irredundant variables +c MB reductions redundant trail remaining +c level restarts binary glue +c +c B 0.92 10 381 5 5 510 9130 2395 44181 21940 24% 59 26091 96% +c - 0.95 10 377 5 6 510 9432 791 44181 21940 24% 58 26091 96% +c u 0.97 10 375 5 6 510 9506 813 44233 21938 24% 58 26091 96% +c v 0.97 10 375 5 6 510 9506 813 44233 21938 24% 58 26091 96% +c = 1.02 10 375 5 6 510 9506 813 44235 21938 24% 58 26090 96% +c d 1.02 10 375 5 6 510 9506 813 44231 21938 24% 58 26090 96% +c t 1.03 10 375 5 6 510 9506 813 44228 21938 24% 58 26090 96% +c ] 1.23 10 323 6 6 512 11535 2770 44228 21938 23% 56 26090 96% +c { 1.23 10 439 6 6 512 11535 2770 44228 21938 28% 43 26090 96% +c 2 1.23 10 437 6 6 514 11703 2858 44171 21938 28% 41 26090 96% +c e 1.31 12 437 6 6 514 11703 2858 20 5 28% 41 1 0% +c } 1.31 12 437 6 6 514 11703 2858 20 5 28% 41 1 0% +c 0 1.31 12 437 6 6 514 11703 2858 20 5 28% 41 1 0% +c +c ---- [ result ] ------------------------------------------------------------ +c +s UNSATISFIABLE +c +c ---- [ profiling ] --------------------------------------------------------- +c +c 1.02 78.08 % search +c 0.64 49.11 % stable +c 0.38 28.97 % focused +c 0.27 20.62 % simplify +c 0.19 14.56 % probe +c 0.08 6.35 % sweep +c 0.07 5.72 % eliminate +c 0.06 4.70 % vivify +c 0.02 1.69 % substitute +c 0.02 1.28 % parse +c 0.01 0.98 % backbone +c 0.01 0.83 % transitive +c 0.01 0.56 % reduce +c 0.00 0.34 % walking +c 0.00 0.25 % subsume +c 0.00 0.00 % warmup +c ============================================= +c 1.31 100.00 % total +c +c ---- [ statistics ] -------------------------------------------------------- +c +c chronological: 6826 58 % conflicts +c conflicts: 11703 8931.73 per second +c decisions: 805237 68.81 per conflict +c eliminated: 26038 96 % variables +c jumped_reasons: 6564398 36 % propagations +c propagations: 18029274 13759937 per second +c queue_decisions: 402857 50 % decision +c random_decisions: 26955 3 % decision +c random_sequences: 8 1463 interval +c reductions: 6 1950 interval +c rephased: 4 2926 interval +c restarts: 514 22.77 interval +c score_decisions: 375425 47 % decision +c substituted: 635 2 % variables +c switched: 6 1950 interval +c vivified: 331 1 % checks +c vivify_checks: 62713 20904 per vivify +c vivify_units: 109 0 % variables +c walk_improved: 1 100 % walks +c walks: 1 11703 interval +c +c ---- [ resources ] --------------------------------------------------------- +c +c maximum-resident-set-size: 12193792 bytes 12 MB +c process-time: 1s 1.31 seconds +c +c ---- [ shutting down ] ----------------------------------------------------- +c +c exit 20 diff --git a/rustsat/src/instances/fio.rs b/rustsat/src/instances/fio.rs index f258299f..eeb08e64 100644 --- a/rustsat/src/instances/fio.rs +++ b/rustsat/src/instances/fio.rs @@ -4,9 +4,18 @@ //! through the interface of instance types rather than using these functions //! directly. -use std::{fs::File, io, path::Path}; +use std::{ + fs::File, + io::{self, BufRead}, + path::Path, +}; use thiserror::Error; +use crate::{ + solvers::{Solve, SolverResult}, + types::{self, Assignment}, +}; + pub mod dimacs; pub mod opb; @@ -72,3 +81,177 @@ pub fn open_compressed_uncompressed_write>( } Ok(Box::new(io::BufWriter::new(raw_writer))) } + +/// Possible results from SAT solver output parsing +#[derive(Debug, PartialEq, Eq)] +pub enum SolverOutput { + Sat(types::Assignment), + Unsat, + Unknown, +} + +/// Possible errors in SAT solver output parsing +#[derive(Error, Debug)] +pub enum SatSolverOutputError { + #[error("No solution line found in the output.")] + NoSLine, + #[error("No value line found in the output.")] + NoVLine, + #[error("Invalid solution line found in the output.")] + InvalidSLine, +} + +/// Possible errors in parsing a SAT solver value line +#[derive(Error, Debug)] +pub enum InvalidVLine { + #[error("The value line does not start with 'v ' but with {0}")] + InvalidTag(char), + #[error("The output of the SAT solver assigned different values to variable {0}")] + ConflictingAssignment(types::Var), + #[error("Empty value line")] + EmptyLine, +} + +/// Parses SAT solver output +pub fn parse_sat_solver_output(reader: R) -> anyhow::Result { + let mut is_sat = false; + let mut solution: Option = None; + + for line in reader.lines() { + let line = &line?; + + //Solution line + if line.starts_with("s ") { + let line = &line[1..].trim_start(); + match line { + line if line.starts_with("UNSATISFIABLE") => return Ok(SolverOutput::Unsat), + line if line.starts_with("UNKNOWN") || line.starts_with("INDETERMINATE") => { + return Ok(SolverOutput::Unknown) + } + line if line.starts_with("SATISFIABLE") => { + is_sat = true; + } + _ => anyhow::bail!(SatSolverOutputError::InvalidSLine), + } + } + + //Value line + if line.starts_with("v ") { + //Have we already seen a vline? + match &mut solution { + Some(assign) => assign.extend_from_vline(&line)?, + _ => solution = Some(Assignment::from_vline(&line)?), + } + } + } + + //There is no solution line so we can not trust the output + if !is_sat { + return anyhow::bail!(SatSolverOutputError::NoSLine); + } + + if let Some(solution) = solution { + return Ok(SolverOutput::Sat(solution)); + } + + anyhow::bail!(SatSolverOutputError::NoVLine); +} + +#[cfg(test)] +mod tests { + use std::io; + + use crate::{ + instances::{self, fio::SatSolverOutputError, SatInstance}, + types::{Assignment, TernaryVal}, + }; + + use super::{parse_sat_solver_output, SolverOutput}; + + #[test] + fn parse_solver_output_sat() { + let ground_truth = SolverOutput::Sat(Assignment::from(vec![ + TernaryVal::True, + TernaryVal::False, + TernaryVal::DontCare, + TernaryVal::True, + TernaryVal::False, + TernaryVal::True, + ])); + + let data = "c this is a comment\ns SATISFIABLE\nv 1 -2 4 -5 6 0\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader).unwrap(); + assert_eq!(res, ground_truth); + + let data = "c this is a comment\nv 1 -2 4 -5 6 0\ns SATISFIABLE\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader).unwrap(); + assert_eq!(res, ground_truth); + + let data = "c this is a comment\ns SATISFIABLE\nv 1 -2 4 \nv -5 6 0\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader).unwrap(); + assert_eq!(res, ground_truth); + } + + #[test] + fn parse_solver_output_unsat() { + let data = "c this is a comment\ns UNSATISFIABLE\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader).unwrap(); + assert_eq!(res, SolverOutput::Unsat); + } + + #[test] + fn parse_solver_output_unknown() { + let data = "c this is a comment\ns UNKNOWN\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader).unwrap(); + assert_eq!(res, SolverOutput::Unknown); + } + + #[test] + fn parse_solver_output_indeterminate() { + let data = "c this is a comment\ns INDETERMINATE\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader).unwrap(); + assert_eq!(res, SolverOutput::Unknown); + } + + #[test] + fn parse_solver_output_noslinewithvline() { + let data = "c this is a comment\nv 1 -2 4 -5 6 0\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader); + match res.unwrap_err().downcast::() { + Ok(err) => match err { + SatSolverOutputError::NoSLine => assert!(true), + _ => panic!(), + }, + Err(_) => panic!(), + } + } + + #[test] + fn parse_solver_output_novlinewithsatisfy() { + let data = "c this is a comment\ns SATISFIABLE\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader); + match res.unwrap_err().downcast::() { + Ok(err) => match err { + SatSolverOutputError::NoVLine => assert!(true), + _ => panic!(), + }, + Err(_) => panic!(), + } + } + + #[test] + fn parse_solver_output_emptysolution() { + let data = "c this is a comment\ns SATISFIABLE\nv 0\n"; + let reader = io::Cursor::new(data); + let res = parse_sat_solver_output(reader).unwrap(); + assert_eq!(res, SolverOutput::Sat(Assignment::default())); + } +} diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index 3c9ccdba..bb1a534d 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -6,13 +6,20 @@ use core::ffi::c_int; use std::{ fmt, ops::{self, Index, IndexMut}, + path::Path, }; +use anyhow::Context; use thiserror::Error; pub mod constraints; pub use constraints::Clause; +use crate::instances::{ + self, + fio::{InvalidVLine, SatSolverOutputError, SolverOutput}, +}; + /// The hash map to use throughout the library #[cfg(feature = "fxhash")] pub type RsHashMap = rustc_hash::FxHashMap; @@ -651,6 +658,67 @@ impl Assignment { Some(var![self.assignment.len() as u32 - 1]) } } + + /// Reads a solution from SAT solver output given the path + /// + /// If it is unclear whether the SAT solver indicated satisfiability, use [`instances::fio::parse_sat_solver_output`] instead. + pub fn from_solver_output_path>(path: P) -> anyhow::Result { + let reader = std::io::BufReader::new( + instances::fio::open_compressed_uncompressed_read(path) + .context("failed to open reader")?, + ); + let output = instances::fio::parse_sat_solver_output(reader)?; + match output { + SolverOutput::Sat(solution) => Ok(solution), + _ => anyhow::bail!("solver output does not indicate satisfiability"), + } + } + + /// Creates an assignment from a SAT solver value line + pub fn from_vline(line: &str) -> anyhow::Result { + let mut assignment = Assignment::default(); + assignment.extend_from_vline(line)?; + Ok(assignment) + } + + /// Parses and saves literals from a value line. + pub fn extend_from_vline(&mut self, lines: &str) -> anyhow::Result<()> { + for line in lines.lines() { + if !line.starts_with("v ") { + if line.is_empty() { + anyhow::bail!(InvalidVLine::EmptyLine); + } + + anyhow::bail!(InvalidVLine::InvalidTag(line.chars().next().unwrap())); + } + + let line = &line[1..]; + for number in line.split_whitespace() { + let number = number.parse::()?; + + //End of the value lines + if number == 0 { + continue; + } + + let literal = Lit::from_ipasir(number)?; + let val = self.lit_value(literal); + if val == TernaryVal::True && literal.is_neg() + || val == TernaryVal::False && literal.is_pos() + { + // Catch conflicting assignments + anyhow::bail!(InvalidVLine::ConflictingAssignment(literal.var())); + } + self.assign_lit(literal); + } + } + + if lines.is_empty() { + anyhow::bail!(InvalidVLine::EmptyLine) + } + + Ok(()) + } } impl fmt::Debug for Assignment { @@ -749,7 +817,9 @@ impl> IWLitIter for I {} #[cfg(test)] mod tests { - use std::mem::size_of; + use std::{mem::size_of, num::ParseIntError}; + + use crate::instances::fio::InvalidVLine; use super::{Assignment, Lit, TernaryVal, Var}; @@ -935,4 +1005,161 @@ mod tests { fn ternary_val_size() { assert_eq!(size_of::(), 1); } + + #[test] + fn parse_vline() { + let vline = "v 1 -2 4 -5 6 0"; + let ground_truth = Assignment::from(vec![ + TernaryVal::True, + TernaryVal::False, + TernaryVal::DontCare, + TernaryVal::True, + TernaryVal::False, + TernaryVal::True, + ]); + assert_eq!(Assignment::from_vline(vline).unwrap(), ground_truth); + assert_eq!( + { + let mut asign = Assignment::default(); + asign.extend_from_vline(vline).unwrap(); + asign + }, + ground_truth + ); + } + + #[test] + fn vline_invalid_lit_from() { + let vline = "v 1 -2 4 foo -5 bar 6 0"; + let res = Assignment::from_vline(vline); + match res.unwrap_err().downcast::() { + Ok(err) => match err { + ParseIntError => assert!(true), + _ => panic!(), + }, + Err(_) => panic!(), + } + } + + #[test] + fn vline_invalid_lit_extend() { + let vline = "v 1 -2 4 foo -5 bar 6 0"; + let mut assign = Assignment::default(); + let res = assign.extend_from_vline(vline); + match res.unwrap_err().downcast::() { + Ok(err) => match err { + ParseIntError => assert!(true), + _ => panic!(), + }, + Err(_) => panic!(), + } + } + + #[test] + fn vline_invalid_tag_from() { + let vline = "b 1 -2 4 -5 6 0"; + let res = Assignment::from_vline(vline); + match res.unwrap_err().downcast::() { + Ok(err) => match err { + InvalidVLine::InvalidTag(ck) => assert_eq!(ck, 'b'), + _ => panic!(), + }, + Err(_) => panic!(), + } + } + + #[test] + fn vline_invalid_tag_extend() { + let vline = "b 1 -2 4 -5 6 0"; + let mut assign = Assignment::default(); + let res = assign.extend_from_vline(vline); + match res.unwrap_err().downcast::() { + Ok(err) => match err { + InvalidVLine::InvalidTag(ck) => assert_eq!(ck, 'b'), + _ => panic!(), + }, + Err(_) => panic!(), + } + } + + #[test] + fn vline_invalid_empty() { + let vline = ""; + let res = Assignment::from_vline(vline); + match res.unwrap_err().downcast::() { + Ok(err) => match err { + InvalidVLine::EmptyLine => assert!(true), + _ => panic!(), + }, + Err(_) => panic!(), + } + } + + #[test] + fn multi_vline() { + let vline = "v 1 2 3\nv 4 5 6 0"; + let ground_truth = Assignment::from(vec![ + TernaryVal::True, + TernaryVal::True, + TernaryVal::True, + TernaryVal::True, + TernaryVal::True, + TernaryVal::True, + ]); + let res = Assignment::from_vline(vline).unwrap(); + assert_eq!(res, ground_truth); + } + + #[test] + fn sat_solveable_solution_output_reading() { + use crate::instances::{BasicVarManager, SatInstance}; + let instance = + SatInstance::::from_dimacs_path("../data/AProVE11-12.cnf").unwrap(); + + let assign_gimsatul = + Assignment::from_solver_output_path("../data/gimsatul-AProVE11-12.txt").unwrap(); + let assign_kissat = + Assignment::from_solver_output_path("../data/kissat-AProVE11-12.txt").unwrap(); + let assign_cadical = + Assignment::from_solver_output_path("../data/cadical-AProVW11-12.txt").unwrap(); + + assert!(instance.is_sat(&assign_gimsatul)); + assert!(instance.is_sat(&assign_kissat)); + assert!(instance.is_sat(&assign_cadical)); + } + + #[test] + fn sat_unsolveable_solution_output_reading() { + use crate::instances::{BasicVarManager, SatInstance}; + let instance = SatInstance::::from_dimacs_path( + "../data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf", + ) + .unwrap(); + + let assign_gimsatul = Assignment::from_solver_output_path( + "../data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt", + ) + .unwrap_err(); + let assign_kissat = Assignment::from_solver_output_path( + "../data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt", + ) + .unwrap_err(); + let assign_cadical = Assignment::from_solver_output_path( + "../data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt", + ) + .unwrap_err(); + + assert_eq!( + format!("{}", assign_gimsatul), + "solver output does not indicate satisfiability" + ); + assert_eq!( + format!("{}", assign_kissat), + "solver output does not indicate satisfiability" + ); + assert_eq!( + format!("{}", assign_cadical), + "solver output does not indicate satisfiability" + ); + } } From 81c27d4ed80ef53f86ad0e608bb7440affddc390 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Mon, 29 Apr 2024 15:11:37 +0300 Subject: [PATCH 36/56] chore: cleanup output parsing --- ...ProVW11-12.txt => cadical-AProVE11-12.log} | 0 ...fbv-aigs-ext_con_032_008_0256-tseitin.log} | 0 ...roVE11-12.txt => gimsatul-AProVE11-12.log} | 0 ...fbv-aigs-ext_con_032_008_0256-tseitin.log} | 0 ...AProVE11-12.txt => kissat-AProVE11-12.log} | 0 ...fbv-aigs-ext_con_032_008_0256-tseitin.log} | 0 rustsat/src/instances/fio.rs | 103 +++++++++++---- rustsat/src/types.rs | 120 +++++------------- 8 files changed, 104 insertions(+), 119 deletions(-) rename data/{cadical-AProVW11-12.txt => cadical-AProVE11-12.log} (100%) rename data/{cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt => cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log} (100%) rename data/{gimsatul-AProVE11-12.txt => gimsatul-AProVE11-12.log} (100%) rename data/{gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt => gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log} (100%) rename data/{kissat-AProVE11-12.txt => kissat-AProVE11-12.log} (100%) rename data/{kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt => kissat-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log} (100%) diff --git a/data/cadical-AProVW11-12.txt b/data/cadical-AProVE11-12.log similarity index 100% rename from data/cadical-AProVW11-12.txt rename to data/cadical-AProVE11-12.log diff --git a/data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt b/data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log similarity index 100% rename from data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt rename to data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log diff --git a/data/gimsatul-AProVE11-12.txt b/data/gimsatul-AProVE11-12.log similarity index 100% rename from data/gimsatul-AProVE11-12.txt rename to data/gimsatul-AProVE11-12.log diff --git a/data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt b/data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log similarity index 100% rename from data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt rename to data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log diff --git a/data/kissat-AProVE11-12.txt b/data/kissat-AProVE11-12.log similarity index 100% rename from data/kissat-AProVE11-12.txt rename to data/kissat-AProVE11-12.log diff --git a/data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt b/data/kissat-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log similarity index 100% rename from data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt rename to data/kissat-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log diff --git a/rustsat/src/instances/fio.rs b/rustsat/src/instances/fio.rs index eeb08e64..2983f2c7 100644 --- a/rustsat/src/instances/fio.rs +++ b/rustsat/src/instances/fio.rs @@ -11,10 +11,7 @@ use std::{ }; use thiserror::Error; -use crate::{ - solvers::{Solve, SolverResult}, - types::{self, Assignment}, -}; +use crate::types::{self, Assignment}; pub mod dimacs; pub mod opb; @@ -85,33 +82,28 @@ pub fn open_compressed_uncompressed_write>( /// Possible results from SAT solver output parsing #[derive(Debug, PartialEq, Eq)] pub enum SolverOutput { + /// The solver indicates satisfiability with the given assignment Sat(types::Assignment), + /// The solver indicates unsatisfiability Unsat, + /// The solver did not solve the instance Unknown, } /// Possible errors in SAT solver output parsing #[derive(Error, Debug)] pub enum SatSolverOutputError { + /// The solver output does not contain an `s` line #[error("No solution line found in the output.")] NoSLine, + /// The solver output does indicate satisfiability but does not contain an assignment #[error("No value line found in the output.")] NoVLine, + /// The solver output contains an invalid `s` line #[error("Invalid solution line found in the output.")] InvalidSLine, } -/// Possible errors in parsing a SAT solver value line -#[derive(Error, Debug)] -pub enum InvalidVLine { - #[error("The value line does not start with 'v ' but with {0}")] - InvalidTag(char), - #[error("The output of the SAT solver assigned different values to variable {0}")] - ConflictingAssignment(types::Var), - #[error("Empty value line")] - EmptyLine, -} - /// Parses SAT solver output pub fn parse_sat_solver_output(reader: R) -> anyhow::Result { let mut is_sat = false; @@ -120,7 +112,7 @@ pub fn parse_sat_solver_output(reader: R) -> anyhow::Result(reader: R) -> anyhow::Result assign.extend_from_vline(&line)?, - _ => solution = Some(Assignment::from_vline(&line)?), + Some(assign) => assign.extend_from_vline(line)?, + _ => solution = Some(Assignment::from_vline(line)?), } } } - //There is no solution line so we can not trust the output - if !is_sat { - return anyhow::bail!(SatSolverOutputError::NoSLine); - } + // There is no solution line so we can not trust the output + anyhow::ensure!(is_sat, SatSolverOutputError::NoSLine); if let Some(solution) = solution { return Ok(SolverOutput::Sat(solution)); @@ -162,11 +151,11 @@ mod tests { use std::io; use crate::{ - instances::{self, fio::SatSolverOutputError, SatInstance}, + instances::SatInstance, types::{Assignment, TernaryVal}, }; - use super::{parse_sat_solver_output, SolverOutput}; + use super::{parse_sat_solver_output, SatSolverOutputError, SolverOutput}; #[test] fn parse_solver_output_sat() { @@ -226,7 +215,7 @@ mod tests { let res = parse_sat_solver_output(reader); match res.unwrap_err().downcast::() { Ok(err) => match err { - SatSolverOutputError::NoSLine => assert!(true), + SatSolverOutputError::NoSLine => (), _ => panic!(), }, Err(_) => panic!(), @@ -240,7 +229,7 @@ mod tests { let res = parse_sat_solver_output(reader); match res.unwrap_err().downcast::() { Ok(err) => match err { - SatSolverOutputError::NoVLine => assert!(true), + SatSolverOutputError::NoVLine => (), _ => panic!(), }, Err(_) => panic!(), @@ -254,4 +243,62 @@ mod tests { let res = parse_sat_solver_output(reader).unwrap(); assert_eq!(res, SolverOutput::Sat(Assignment::default())); } + + #[test] + fn parse_solver_output_sat_logs() { + let instance: SatInstance = + SatInstance::from_dimacs_path("./data/AProVE11-12.cnf").unwrap(); + + let reader = + super::open_compressed_uncompressed_read("./data/gimsatul-AProVE11-12.log").unwrap(); + let res = parse_sat_solver_output(reader).unwrap(); + match res { + SolverOutput::Sat(sol) => assert!(instance.is_sat(&sol)), + _ => panic!(), + } + + let reader = + super::open_compressed_uncompressed_read("./data/kissat-AProVE11-12.log").unwrap(); + let res = parse_sat_solver_output(reader).unwrap(); + match res { + SolverOutput::Sat(sol) => assert!(instance.is_sat(&sol)), + _ => panic!(), + } + + let reader = + super::open_compressed_uncompressed_read("./data/cadical-AProVE11-12.log").unwrap(); + let res = parse_sat_solver_output(reader).unwrap(); + match res { + SolverOutput::Sat(sol) => assert!(instance.is_sat(&sol)), + _ => panic!(), + } + } + + #[test] + fn parse_solver_output_unsat_logs() { + let reader = super::open_compressed_uncompressed_read( + "./data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log", + ) + .unwrap(); + assert_eq!( + parse_sat_solver_output(reader).unwrap(), + SolverOutput::Unsat + ); + let reader = super::open_compressed_uncompressed_read( + "./data/kissat-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log", + ) + .unwrap(); + assert_eq!( + parse_sat_solver_output(reader,).unwrap(), + SolverOutput::Unsat + ); + let reader = super::open_compressed_uncompressed_read( + "./data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.log", + ) + .unwrap(); + assert_eq!( + parse_sat_solver_output(reader,).unwrap(), + SolverOutput::Unsat + ); + } } diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index bb1a534d..53682ddf 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -15,10 +15,7 @@ use thiserror::Error; pub mod constraints; pub use constraints::Clause; -use crate::instances::{ - self, - fio::{InvalidVLine, SatSolverOutputError, SolverOutput}, -}; +use crate::instances::fio::{self, SolverOutput}; /// The hash map to use throughout the library #[cfg(feature = "fxhash")] @@ -582,6 +579,20 @@ impl ops::Neg for TernaryVal { } } +/// Possible errors in parsing a SAT solver value (`v`) line +#[derive(Error, Debug)] +pub enum InvalidVLine { + /// The given `v` line starts with an invalid character + #[error("The value line does not start with 'v ' but with {0}")] + InvalidTag(char), + /// The `v` line contains a conflicting assignment on the given variable + #[error("The output of the SAT solver assigned different values to variable {0}")] + ConflictingAssignment(Var), + /// The given `v` line is empty + #[error("Empty value line")] + EmptyLine, +} + /// Type representing an assignment of variables. #[derive(Clone, PartialEq, Eq, Default)] #[repr(transparent)] @@ -661,13 +672,12 @@ impl Assignment { /// Reads a solution from SAT solver output given the path /// - /// If it is unclear whether the SAT solver indicated satisfiability, use [`instances::fio::parse_sat_solver_output`] instead. + /// If it is unclear whether the SAT solver indicated satisfiability, use [`fio::parse_sat_solver_output`] instead. pub fn from_solver_output_path>(path: P) -> anyhow::Result { let reader = std::io::BufReader::new( - instances::fio::open_compressed_uncompressed_read(path) - .context("failed to open reader")?, + fio::open_compressed_uncompressed_read(path).context("failed to open reader")?, ); - let output = instances::fio::parse_sat_solver_output(reader)?; + let output = fio::parse_sat_solver_output(reader)?; match output { SolverOutput::Sat(solution) => Ok(solution), _ => anyhow::bail!("solver output does not indicate satisfiability"), @@ -684,19 +694,17 @@ impl Assignment { /// Parses and saves literals from a value line. pub fn extend_from_vline(&mut self, lines: &str) -> anyhow::Result<()> { for line in lines.lines() { - if !line.starts_with("v ") { - if line.is_empty() { - anyhow::bail!(InvalidVLine::EmptyLine); - } - - anyhow::bail!(InvalidVLine::InvalidTag(line.chars().next().unwrap())); - } + anyhow::ensure!(!line.is_empty(), InvalidVLine::EmptyLine); + anyhow::ensure!( + line.starts_with("v "), + InvalidVLine::InvalidTag(line.chars().next().unwrap()) + ); let line = &line[1..]; for number in line.split_whitespace() { let number = number.parse::()?; - //End of the value lines + // End of the value lines if number == 0 { continue; } @@ -713,10 +721,7 @@ impl Assignment { } } - if lines.is_empty() { - anyhow::bail!(InvalidVLine::EmptyLine) - } - + anyhow::ensure!(!lines.is_empty(), InvalidVLine::EmptyLine); Ok(()) } } @@ -819,9 +824,7 @@ impl> IWLitIter for I {} mod tests { use std::{mem::size_of, num::ParseIntError}; - use crate::instances::fio::InvalidVLine; - - use super::{Assignment, Lit, TernaryVal, Var}; + use super::{Assignment, InvalidVLine, Lit, TernaryVal, Var}; #[test] fn var_index() { @@ -1032,13 +1035,7 @@ mod tests { fn vline_invalid_lit_from() { let vline = "v 1 -2 4 foo -5 bar 6 0"; let res = Assignment::from_vline(vline); - match res.unwrap_err().downcast::() { - Ok(err) => match err { - ParseIntError => assert!(true), - _ => panic!(), - }, - Err(_) => panic!(), - } + res.unwrap_err().downcast::().unwrap(); } #[test] @@ -1046,13 +1043,7 @@ mod tests { let vline = "v 1 -2 4 foo -5 bar 6 0"; let mut assign = Assignment::default(); let res = assign.extend_from_vline(vline); - match res.unwrap_err().downcast::() { - Ok(err) => match err { - ParseIntError => assert!(true), - _ => panic!(), - }, - Err(_) => panic!(), - } + res.unwrap_err().downcast::().unwrap(); } #[test] @@ -1088,7 +1079,7 @@ mod tests { let res = Assignment::from_vline(vline); match res.unwrap_err().downcast::() { Ok(err) => match err { - InvalidVLine::EmptyLine => assert!(true), + InvalidVLine::EmptyLine => (), _ => panic!(), }, Err(_) => panic!(), @@ -1109,57 +1100,4 @@ mod tests { let res = Assignment::from_vline(vline).unwrap(); assert_eq!(res, ground_truth); } - - #[test] - fn sat_solveable_solution_output_reading() { - use crate::instances::{BasicVarManager, SatInstance}; - let instance = - SatInstance::::from_dimacs_path("../data/AProVE11-12.cnf").unwrap(); - - let assign_gimsatul = - Assignment::from_solver_output_path("../data/gimsatul-AProVE11-12.txt").unwrap(); - let assign_kissat = - Assignment::from_solver_output_path("../data/kissat-AProVE11-12.txt").unwrap(); - let assign_cadical = - Assignment::from_solver_output_path("../data/cadical-AProVW11-12.txt").unwrap(); - - assert!(instance.is_sat(&assign_gimsatul)); - assert!(instance.is_sat(&assign_kissat)); - assert!(instance.is_sat(&assign_cadical)); - } - - #[test] - fn sat_unsolveable_solution_output_reading() { - use crate::instances::{BasicVarManager, SatInstance}; - let instance = SatInstance::::from_dimacs_path( - "../data/smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.cnf", - ) - .unwrap(); - - let assign_gimsatul = Assignment::from_solver_output_path( - "../data/gimsatul-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt", - ) - .unwrap_err(); - let assign_kissat = Assignment::from_solver_output_path( - "../data/kissat-smtlib-qfbv-aigs-exp_con_032_008_0256-tseitin.txt", - ) - .unwrap_err(); - let assign_cadical = Assignment::from_solver_output_path( - "../data/cadical-smtlib-qfbv-aigs-ext_con_032_008_0256-tseitin.txt", - ) - .unwrap_err(); - - assert_eq!( - format!("{}", assign_gimsatul), - "solver output does not indicate satisfiability" - ); - assert_eq!( - format!("{}", assign_kissat), - "solver output does not indicate satisfiability" - ); - assert_eq!( - format!("{}", assign_cadical), - "solver output does not indicate satisfiability" - ); - } } From 28c68a1c6b6c1f4e2a5b4ece98bbd28eb24c0c4d Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Mon, 29 Apr 2024 16:32:18 +0300 Subject: [PATCH 37/56] feat: `ipasir-display` feature enabling this feature changes the behaviour of the `Var` and `Lit` implementations of the `Display` trait to use IPASIR indexing --- rustsat/Cargo.toml | 1 + rustsat/examples/print-lits.rs | 31 +++++++++++++++++++++++++++++++ rustsat/src/lib.rs | 7 ++++--- rustsat/src/types.rs | 11 ++++++----- 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 rustsat/examples/print-lits.rs diff --git a/rustsat/Cargo.toml b/rustsat/Cargo.toml index 6236bcb7..c33eb14b 100644 --- a/rustsat/Cargo.toml +++ b/rustsat/Cargo.toml @@ -39,6 +39,7 @@ multiopt = ["optimization"] compression = ["dep:bzip2", "dep:flate2", "dep:xz2"] rand = ["dep:rand"] bench = [] +ipasir-display = [] all = ["multiopt", "compression", "rand", "fxhash"] [package.metadata.docs.rs] diff --git a/rustsat/examples/print-lits.rs b/rustsat/examples/print-lits.rs new file mode 100644 index 00000000..3bf5e963 --- /dev/null +++ b/rustsat/examples/print-lits.rs @@ -0,0 +1,31 @@ +//! Example to showcase `ipasir-display` feature + +macro_rules! show_ipasir_var { + ($ipasir:expr) => {{ + println!( + "`Display` IPASIR literal {:3}: {:>16}", + $ipasir, + format!("{}", rustsat::ipasir_lit![$ipasir]) + ); + println!( + "`Display` IPASIR literal {:3}: {:>16}", + -$ipasir, + format!("{}", rustsat::ipasir_lit![-$ipasir]) + ); + println!( + " `Debug` IPASIR literal {:3}: {:>2?}", + $ipasir, + rustsat::ipasir_lit![$ipasir] + ); + println!( + " `Debug` IPASIR literal {:3}: {:>2?}", + -$ipasir, + rustsat::ipasir_lit![-$ipasir] + ); + }}; +} + +fn main() { + show_ipasir_var![1]; + show_ipasir_var![42]; +} diff --git a/rustsat/src/lib.rs b/rustsat/src/lib.rs index e212494c..239f44f2 100644 --- a/rustsat/src/lib.rs +++ b/rustsat/src/lib.rs @@ -47,13 +47,14 @@ //! //! | Feature name | Description | //! | --- | --- | -//! | `internals` | Make some internal data structures for e.g. encodings public. This is useful when basing a more complex encoding on the `rustsat` implementation of another encoding. Note that the internal API might change between releases. | -//! | `fxhash` | Use the faster firefox hash function from `rustc-hash` in `rustsat`. | //! | `optimization` | Include optimization (MaxSAT) data structures etc. | //! | `multiopt` | Include data structures etc. for multi-objective optimization. | //! | `compression` | Enable parsing and writing compressed input. | -//! | `bench` | Enable benchmark tests. Behind feature flag since it requires unstable Rust. | +//! | `fxhash` | Use the faster firefox hash function from `rustc-hash` in `rustsat`. | //! | `rand` | Enable randomization features. (Shuffling clauses etc.) | +//! | `ipasir-display` | Changes `Display` trait for `Lit` and `Var` types to follow IPASIR variables indexing. | +//! | `bench` | Enable benchmark tests. Behind feature flag since it requires unstable Rust. | +//! | `internals` | Make some internal data structures for e.g. encodings public. This is useful when basing a more complex encoding on the `rustsat` implementation of another encoding. Note that the internal API might change between releases. | //! //! ## Examples //! diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index 53682ddf..7421a751 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -204,7 +204,11 @@ impl ops::SubAssign for Var { /// Variables can be printed with the [`Display`](std::fmt::Display) trait impl fmt::Display for Var { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "x{}", self.idx) + if cfg!(feature = "ipasir-display") { + write!(f, "x{}", self.to_ipasir()) + } else { + write!(f, "x{}", self.idx()) + } } } @@ -460,10 +464,7 @@ impl ops::Sub for Lit { /// Literals can be printed with the [`Display`](std::fmt::Display) trait impl fmt::Display for Lit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.is_neg() { - true => write!(f, "~x{}", self.vidx()), - false => write!(f, "x{}", self.vidx()), - } + write!(f, "{}{}", if self.is_neg() { "~" } else { "" }, self.var()) } } From 0fb0e12a88d43ecdad6a6c7fca26fcb5297682bf Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Mon, 29 Apr 2024 16:39:40 +0300 Subject: [PATCH 38/56] chore: cleanup capi examples --- capi/examples/Makefile | 9 +++++++++ capi/src/lib.rs | 2 +- rustsat/examples/Makefile | 7 ------- 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 capi/examples/Makefile delete mode 100644 rustsat/examples/Makefile diff --git a/capi/examples/Makefile b/capi/examples/Makefile new file mode 100644 index 00000000..0a5776e4 --- /dev/null +++ b/capi/examples/Makefile @@ -0,0 +1,9 @@ +all: capi capi-ipasir + +capi: capi.cpp + g++ -I.. -c capi.cpp -o capi.o + g++ capi.o ../../target/release/librustsat_capi.a -o capi.out + +capi-ipasir: capi-ipasir.cpp + g++ -I.. -I${IPASIR_INC} -c capi-ipasir.cpp -o capi-ipasir.o + g++ capi-ipasir.o ../../target/release/librustsat_capi.a ${IPASIR_LIB} -o capi-ipasir.out diff --git a/capi/src/lib.rs b/capi/src/lib.rs index e92904b0..f5fef5e6 100644 --- a/capi/src/lib.rs +++ b/capi/src/lib.rs @@ -6,7 +6,7 @@ //! project. For now, only the API of certain encodings is available. //! //! For the API itself, see `rustsat.h`. To use RustSAT from an external project, build this crate -//! and link against `librustsat.a` (produced by `cargo` in `target/release`). +//! and link against `librustsat_capi.a` (produced by `cargo` in `target/release`). pub mod encodings { //! # C-API For Encodings diff --git a/rustsat/examples/Makefile b/rustsat/examples/Makefile deleted file mode 100644 index a5259405..00000000 --- a/rustsat/examples/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -capi: capi.cpp - g++ -I.. -c capi.cpp -o capi.o - g++ capi.o ../../target/release/librustsat.a -o capi.out - -capi-ipasir: capi-ipasir.cpp - g++ -I.. -I${IPASIR_INC} -c capi-ipasir.cpp -o capi-ipasir.o - g++ capi-ipasir.o ../../target/release/librustsat.a ${IPASIR_LIB} -o capi-ipasir.out From f0135be0a55c5e7366dd611233caccf6f0507ef4 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Fri, 26 Apr 2024 14:55:38 +0300 Subject: [PATCH 39/56] Revert "Ignore ipasir package release for now" This reverts commit 5dd2bede1d24c0a9e90a6004353b526a4f523d47. --- release-plz.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/release-plz.toml b/release-plz.toml index 99bf914d..fe2e31a4 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -26,11 +26,6 @@ publish_allow_dirty = false # disable running `cargo-semver-checks` semver_check = true -[[package]] -name = "rustsat-ipasir" -release = false -git_release_enable = false - [[package]] name = "rustsat-solvertests" release = false From 3568fac30dc97ece0e4985f73e9e205038cf744e Mon Sep 17 00:00:00 2001 From: Christoph <98587286+chrjabs@users.noreply.github.com> Date: Mon, 29 Apr 2024 13:49:31 +0000 Subject: [PATCH 40/56] chore: release Signed-off-by: Christoph <98587286+chrjabs@users.noreply.github.com> --- CHANGELOG.md | 51 ++++++++++++++++++++++++++++++++++++++++++ cadical/CHANGELOG.md | 40 +++++++++++++++++++++++++++++++++ cadical/Cargo.toml | 4 ++-- capi/CHANGELOG.md | 7 ++++++ capi/Cargo.toml | 4 ++-- glucose/CHANGELOG.md | 33 +++++++++++++++++++++++++++ glucose/Cargo.toml | 4 ++-- ipasir/CHANGELOG.md | 3 +++ ipasir/Cargo.toml | 2 +- kissat/CHANGELOG.md | 33 +++++++++++++++++++++++++++ kissat/Cargo.toml | 4 ++-- minisat/CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++ minisat/Cargo.toml | 4 ++-- pyapi/CHANGELOG.md | 7 ++++++ pyapi/Cargo.toml | 4 ++-- rustsat/Cargo.toml | 6 ++--- solvertests/Cargo.toml | 2 +- tools/CHANGELOG.md | 17 ++++++++++++++ tools/Cargo.toml | 8 +++---- 19 files changed, 254 insertions(+), 21 deletions(-) create mode 100644 capi/CHANGELOG.md create mode 100644 pyapi/CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 437c288e..a876d106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,57 @@ All notable changes to this project will be documented in this file. +## [0.5.0] - 2024-04-30 + +This release contains breaking changes. For detailed instructions on how to +handle migration, please refer to the [migration +guide](https://github.com/chrjabs/rustsat/blob/main/docs/0-5-0-migration-guide.md). + +### Bug Fixes + +- Incorrect coarse_ub in dpw when unweighted +- Dynamic polynomial watchdog edge cases with < 2 inputs + +### Documentation + +- Clarify lit rep and relation to IPASIR/DIMACS +- Add missing documentation +- Fix broken links + +### Features + +- Migrate error handling to `anyhow` create +- Move IPASIR bindings to separate crate +- Instance ergonomics for member variables +- Ergonomics for opb writing +- Ergonomics for dimacs writing +- Add `add_clause_ref` method to `Solve` trait +- Add `add_nary` function +- Have file parsers take `BufRead` types +- `Extend<&Clause>` for solvers +- Catch memory out in solvers +- Catch memory outs in clause collector +- Parse external solver output +- `ipasir-display` feature + +### Miscellaneous Tasks + +- Update to `pyo3` 0.21 +- Specify minimum rust version + +### Performance + +- Add `BufWriter` when writing to file +- Avoid unnecessary cloning + +### Refactor + +- Clean up control flow in solver methods +- Clean up control flow in dimacs parsing +- Factor out C-API +- Factor out Python API + + ## [0.4.3] - 2024-02-22 ### Features diff --git a/cadical/CHANGELOG.md b/cadical/CHANGELOG.md index 7b1d2715..813ad61b 100644 --- a/cadical/CHANGELOG.md +++ b/cadical/CHANGELOG.md @@ -2,6 +2,46 @@ All notable changes to this project will be documented in this file. +## [0.3.0] - 2024-04-30 + +The corresponding RustSAT release contains breaking changes. For detailed +instructions on how to handle migration, please refer to the [migration +guide](https://github.com/chrjabs/rustsat/blob/main/docs/0-5-0-migration-guide.md). + +### Documentation + +- Add missing documentation + +### Features + +- Cadical version 1.9.5 +- Migrate error handling to `anyhow` create +- Exclude `ipasir.cpp` to avoid conflicts with other linked ipasir libs +- Add `add_clause_ref` method to `Solve` trait +- `Extend<&Clause>` for solvers +- Catch memory out in solvers +- Catch memory outs in clause collector + +### Miscellaneous Tasks + +- Cleanup feature-dependent compilation + +### Refactor + +- Clean up control flow in solver methods +- Factor out solver integration tests +- Factor out solver unit tests +- Solver build system + +### Testing + +- Minisat segfault tests + +### Example + +- `cadical-cli` tool + + ## [0.2.4] - 2024-02-22 ### Miscellaneous Tasks diff --git a/cadical/Cargo.toml b/cadical/Cargo.toml index aa1ed892..977786ec 100644 --- a/cadical/Cargo.toml +++ b/cadical/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-cadical" -version = "0.2.4" +version = "0.3.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -41,7 +41,7 @@ v1-9-5 = [] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/capi/CHANGELOG.md b/capi/CHANGELOG.md new file mode 100644 index 00000000..75c5ebfc --- /dev/null +++ b/capi/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.5.0] - 2024-04-30 + +Factor C-API out into its own crate. diff --git a/capi/Cargo.toml b/capi/Cargo.toml index 8f97933a..ca67ef73 100644 --- a/capi/Cargo.toml +++ b/capi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-capi" -version = "0.4.3" +version = "0.5.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -12,7 +12,7 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false, features = [ +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false, features = [ "internals", ] } diff --git a/glucose/CHANGELOG.md b/glucose/CHANGELOG.md index fb883bd7..7651918a 100644 --- a/glucose/CHANGELOG.md +++ b/glucose/CHANGELOG.md @@ -2,6 +2,39 @@ All notable changes to this project will be documented in this file. +## [0.3.0] - 2024-04-30 + +The corresponding RustSAT release contains breaking changes. For detailed +instructions on how to handle migration, please refer to the [migration +guide](https://github.com/chrjabs/rustsat/blob/main/docs/0-5-0-migration-guide.md). + +### Documentation + +- Add missing documentation + +### Features + +- `quiet` feature to disable `stdout` printing +- Migrate error handling to `anyhow` create +- `FreezeVar` trait +- Return error when assumption is eliminated +- Add `add_clause_ref` method to `Solve` trait +- `Extend<&Clause>` for solvers +- Catch memory out in solvers +- Catch memory outs in clause collector + +### Refactor + +- Clean up control flow in solver methods +- Factor out solver integration tests +- Factor out solver unit tests +- Solver build system + +### Testing + +- Minisat segfault tests + + ## [0.2.4] - 2024-02-22 ### Bug Fixes diff --git a/glucose/Cargo.toml b/glucose/Cargo.toml index 8481d335..0c5273ba 100644 --- a/glucose/Cargo.toml +++ b/glucose/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-glucose" -version = "0.2.4" +version = "0.3.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -20,7 +20,7 @@ default = ["quiet"] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/ipasir/CHANGELOG.md b/ipasir/CHANGELOG.md index ba811889..65da3c5d 100644 --- a/ipasir/CHANGELOG.md +++ b/ipasir/CHANGELOG.md @@ -2,3 +2,6 @@ All notable changes to this project will be documented in this file. +## [0.1.0] - 2024-04-30 + +Factor IPASIR API out from RustSAT into its own crate. diff --git a/ipasir/Cargo.toml b/ipasir/Cargo.toml index ab859bc1..b77f3d5b 100644 --- a/ipasir/Cargo.toml +++ b/ipasir/Cargo.toml @@ -13,6 +13,6 @@ readme = "README.md" [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/kissat/CHANGELOG.md b/kissat/CHANGELOG.md index 8dfe5114..13bf508f 100644 --- a/kissat/CHANGELOG.md +++ b/kissat/CHANGELOG.md @@ -2,6 +2,39 @@ All notable changes to this project will be documented in this file. +## [0.2.0] - 2024-04-30 + +The corresponding RustSAT release contains breaking changes. For detailed +instructions on how to handle migration, please refer to the [migration +guide](https://github.com/chrjabs/rustsat/blob/main/docs/0-5-0-migration-guide.md). + +### Documentation + +- Add missing documentation + +### Features + +- Migrate error handling to `anyhow` create +- Add `add_clause_ref` method to `Solve` trait +- `Extend<&Clause>` for solvers +- Allow for abort hooks + +### Refactor + +- Clean up control flow in solver methods +- Factor out solver integration tests +- Factor out solver unit tests +- Solver build system + +### Testing + +- Minisat segfault tests + +### Example + +- `kissat-cli` tool + + ## [0.1.6] - 2024-02-22 ### Miscellaneous Tasks diff --git a/kissat/Cargo.toml b/kissat/Cargo.toml index beaae3ed..32491090 100644 --- a/kissat/Cargo.toml +++ b/kissat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-kissat" -version = "0.1.6" +version = "0.2.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -26,7 +26,7 @@ sc2022-bulky = [] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/minisat/CHANGELOG.md b/minisat/CHANGELOG.md index f4175cdf..224993d1 100644 --- a/minisat/CHANGELOG.md +++ b/minisat/CHANGELOG.md @@ -2,6 +2,48 @@ All notable changes to this project will be documented in this file. +## [0.3.0] - 2024-04-30 + +The corresponding RustSAT release contains breaking changes. For detailed +instructions on how to handle migration, please refer to the [migration +guide](https://github.com/chrjabs/rustsat/blob/main/docs/0-5-0-migration-guide.md). + +### Bug Fixes + +- Variable freezing and return value for `var_eliminated` +- Segfault in minisat + +### Documentation + +- Add missing documentation + +### Features + +- `quiet` feature to disable stdout printing +- Migrate error handling to `anyhow` create +- `FreezeVar` trait +- Return error when assumption is eliminated +- Add `add_clause_ref` method to `Solve` trait +- `Extend<&Clause>` for solvers +- Catch memory out in solvers +- Catch memory outs in clause collector + +### Refactor + +- Clean up control flow in solver methods +- Factor out solver integration tests +- Factor out solver unit tests +- Solver build system + +### Testing + +- Minisat segfault tests + +### Example + +- `minisat-cli` tool + + ## [0.2.4] - 2024-02-22 ### Bug Fixes diff --git a/minisat/Cargo.toml b/minisat/Cargo.toml index 314f5f3d..ce2d0076 100644 --- a/minisat/Cargo.toml +++ b/minisat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-minisat" -version = "0.2.4" +version = "0.3.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -20,7 +20,7 @@ default = ["quiet"] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/pyapi/CHANGELOG.md b/pyapi/CHANGELOG.md new file mode 100644 index 00000000..b053d745 --- /dev/null +++ b/pyapi/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.5.0] - 2024-04-30 + +Factor Python API out into its own crate. diff --git a/pyapi/Cargo.toml b/pyapi/Cargo.toml index 793ae8b6..e4afd7d3 100644 --- a/pyapi/Cargo.toml +++ b/pyapi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-pyapi" -version = "0.4.3" +version = "0.5.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -14,7 +14,7 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } pyo3 = { version = "0.21.1", features = [ "extension-module", "abi3", diff --git a/rustsat/Cargo.toml b/rustsat/Cargo.toml index c33eb14b..5f98e78c 100644 --- a/rustsat/Cargo.toml +++ b/rustsat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat" -version = "0.4.3" +version = "0.5.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -27,8 +27,8 @@ anyhow = { version = "1.0.80" } thiserror = { version = "1.0.50" } [dev-dependencies] -rustsat-minisat = { version = "0.2", path = "../minisat" } -rustsat-tools = { version = "0.2", path = "../tools" } +rustsat-minisat = { version = "0.3", path = "../minisat" } +rustsat-tools = { version = "0.3", path = "../tools" } [features] default = ["optimization", "fxhash"] diff --git a/solvertests/Cargo.toml b/solvertests/Cargo.toml index 757cc950..0f66ddb1 100644 --- a/solvertests/Cargo.toml +++ b/solvertests/Cargo.toml @@ -12,5 +12,5 @@ proc-macro = true [dependencies] syn = "2.0" quote = "1.0" -rustsat = { version = "0.4.3", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } proc-macro2 = "1.0" diff --git a/tools/CHANGELOG.md b/tools/CHANGELOG.md index 940a381e..415f493b 100644 --- a/tools/CHANGELOG.md +++ b/tools/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. +## [0.3.0] - 2024-04-29 + +The corresponding RustSAT release contains breaking changes. For detailed +instructions on how to handle migration, please refer to the [migration +guide](https://github.com/chrjabs/rustsat/blob/main/docs/0-5-0-migration-guide.md). + +### Documentation + +- Fix broken links + +### Features + +- Instance ergonomics for member variables +- Ergonomics for dimacs writing +- Use `anyhow` crate + + ## [0.2.4] - 2024-02-22 ### Features diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 8dfda761..275784ca 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-tools" -version = "0.2.4" +version = "0.3.0" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -12,14 +12,14 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustsat = { version = "0.4.3", path = "../rustsat", features = [ +rustsat = { version = "0.5.0", path = "../rustsat", features = [ "compression", "multiopt", "rand", "internals", ] } -rustsat-cadical = { version = "0.2.4", path = "../cadical", optional = true } -rustsat-minisat = { version = "0.2.4", path = "../minisat", optional = true } +rustsat-cadical = { version = "0.3.0", path = "../cadical", optional = true } +rustsat-minisat = { version = "0.3.0", path = "../minisat", optional = true } clap = { version = "4.2.4", features = ["derive", "cargo"] } concolor-clap = { version = "0.1.0" } termcolor = { version = "1.2.0" } From 5549018096ac4ecd5c88a7dfd30557ee8b03b041 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 30 Apr 2024 17:09:28 +0300 Subject: [PATCH 41/56] chore: fix release --- rustsat/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustsat/Cargo.toml b/rustsat/Cargo.toml index 5f98e78c..e1ca6679 100644 --- a/rustsat/Cargo.toml +++ b/rustsat/Cargo.toml @@ -27,8 +27,8 @@ anyhow = { version = "1.0.80" } thiserror = { version = "1.0.50" } [dev-dependencies] -rustsat-minisat = { version = "0.3", path = "../minisat" } -rustsat-tools = { version = "0.3", path = "../tools" } +rustsat-minisat = { path = "../minisat" } +rustsat-tools = { path = "../tools" } [features] default = ["optimization", "fxhash"] From f8d6dd8b8bd837ece694d2ad89bf2e28bd6966cb Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 30 Apr 2024 17:15:08 +0300 Subject: [PATCH 42/56] chore: fix release --- .github/workflows/release-plz.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml index 7f6d4743..0fb94c17 100644 --- a/.github/workflows/release-plz.yml +++ b/.github/workflows/release-plz.yml @@ -15,6 +15,7 @@ jobs: with: fetch-depth: 0 token: ${{ secrets.RELEASE_PLZ_TOKEN }} + submodules: "recursive" - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable From ca2b7e00758bf56213b31650ae7537684953f2a2 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Thu, 2 May 2024 10:38:19 +0300 Subject: [PATCH 43/56] fix(ci): fix release-plz checking next version if a file is ignored in a repository but still committed in it, that really messes with release-plz. remove committed Makefiles from glucose repo to fix ci --- glucose/cppsrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glucose/cppsrc b/glucose/cppsrc index ddb5ef27..f8dc4e9e 160000 --- a/glucose/cppsrc +++ b/glucose/cppsrc @@ -1 +1 @@ -Subproject commit ddb5ef27286ab6729efb66e201d9aeccc72622a5 +Subproject commit f8dc4e9ee77be9fc8b79cf7fcc2bc6d6d3a96dd1 From 9e8e5f57d82026786b14ed4c337f8dd7feae8560 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 21:28:27 +0000 Subject: [PATCH 44/56] build(deps): bump install-pinned/mypy Bumps [install-pinned/mypy](https://github.com/install-pinned/mypy) from 421cd57ee7b88af310624e2c56ed6902f70e1429 to 2f42ad87a5ce739fd68da21a074d6cc44281a487. - [Release notes](https://github.com/install-pinned/mypy/releases) - [Commits](https://github.com/install-pinned/mypy/compare/421cd57ee7b88af310624e2c56ed6902f70e1429...2f42ad87a5ce739fd68da21a074d6cc44281a487) --- updated-dependencies: - dependency-name: install-pinned/mypy dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/pyapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index 2af819a5..b5596bea 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -92,7 +92,7 @@ jobs: - name: Install maturin from PyPI uses: install-pinned/maturin@9ef429e73235cb3ab68a9f8677ca10a189592a5e - name: Install mypy from PyPI - uses: install-pinned/mypy@421cd57ee7b88af310624e2c56ed6902f70e1429 + uses: install-pinned/mypy@2f42ad87a5ce739fd68da21a074d6cc44281a487 - name: Install python project run: maturin build -m pyapi/Cargo.toml && pip install --no-index --find-links target/wheels/ rustsat - name: Test stubs From d4eff51821d9cc68808fdae4e37db13b5a691e52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:09:40 +0000 Subject: [PATCH 45/56] build(deps): bump install-pinned/maturin Bumps [install-pinned/maturin](https://github.com/install-pinned/maturin) from 9ef429e73235cb3ab68a9f8677ca10a189592a5e to 0620ca40d2c575adaa48574fe2f6c76aa188e2c6. - [Release notes](https://github.com/install-pinned/maturin/releases) - [Commits](https://github.com/install-pinned/maturin/compare/9ef429e73235cb3ab68a9f8677ca10a189592a5e...0620ca40d2c575adaa48574fe2f6c76aa188e2c6) --- updated-dependencies: - dependency-name: install-pinned/maturin dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/pyapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index b5596bea..092ed8d2 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -90,7 +90,7 @@ jobs: uses: actions/checkout@v4 - uses: Swatinem/rust-cache@v2 - name: Install maturin from PyPI - uses: install-pinned/maturin@9ef429e73235cb3ab68a9f8677ca10a189592a5e + uses: install-pinned/maturin@0620ca40d2c575adaa48574fe2f6c76aa188e2c6 - name: Install mypy from PyPI uses: install-pinned/mypy@2f42ad87a5ce739fd68da21a074d6cc44281a487 - name: Install python project From ccfdebe16fbb3a0c8dec116bac51d1b8fe319fd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:45:31 +0000 Subject: [PATCH 46/56] build(deps): bump install-pinned/mypy Bumps [install-pinned/mypy](https://github.com/install-pinned/mypy) from 2f42ad87a5ce739fd68da21a074d6cc44281a487 to cec260456eec5126750b72b8f0a6e6011eb85223. - [Release notes](https://github.com/install-pinned/mypy/releases) - [Commits](https://github.com/install-pinned/mypy/compare/2f42ad87a5ce739fd68da21a074d6cc44281a487...cec260456eec5126750b72b8f0a6e6011eb85223) --- updated-dependencies: - dependency-name: install-pinned/mypy dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/pyapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pyapi.yml b/.github/workflows/pyapi.yml index 092ed8d2..584b3655 100644 --- a/.github/workflows/pyapi.yml +++ b/.github/workflows/pyapi.yml @@ -92,7 +92,7 @@ jobs: - name: Install maturin from PyPI uses: install-pinned/maturin@0620ca40d2c575adaa48574fe2f6c76aa188e2c6 - name: Install mypy from PyPI - uses: install-pinned/mypy@2f42ad87a5ce739fd68da21a074d6cc44281a487 + uses: install-pinned/mypy@cec260456eec5126750b72b8f0a6e6011eb85223 - name: Install python project run: maturin build -m pyapi/Cargo.toml && pip install --no-index --find-links target/wheels/ rustsat - name: Test stubs From 9920fcc1bd5d8162d36257104350194c4025d431 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 11 Jun 2024 14:41:40 +0300 Subject: [PATCH 47/56] ci: fix cargo rdme check --- .github/workflows/docs.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index dbf8daa5..2ba71b56 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -26,4 +26,13 @@ jobs: - name: Check READMEs run: | cargo install cargo-rdme - for dir in rustsat tools cadical kissat minisat glucose ipasir capi pyapi; do cd ${dir} && (cargo rdme --check || echo "failed for ${dir}"); cd ..; done + return=true + for dir in rustsat tools cadical kissat minisat glucose ipasir capi pyapi; do + cd ${dir} + if ! cargo rdme --check; then + echo "failed for ${dir}" + return=false + fi + cd .. + done + ${return} From 5b26348157cca72f64fad99f90640a8813482d7d Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 11 Jun 2024 15:00:22 +0300 Subject: [PATCH 48/56] doc: update readmes --- README.md | 7 ++++--- capi/README.md | 9 ++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7c8222a0..763736cc 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,14 @@ To install the binary tools in `rustsat-tools` run `cargo install rustsat-tools` | Feature name | Description | | --- | --- | -| `internals` | Make some internal data structures for e.g. encodings public. This is useful when basing a more complex encoding on the `rustsat` implementation of another encoding. Note that the internal API might change between releases. | -| `fxhash` | Use the faster firefox hash function from `rustc-hash` in `rustsat`. | | `optimization` | Include optimization (MaxSAT) data structures etc. | | `multiopt` | Include data structures etc. for multi-objective optimization. | | `compression` | Enable parsing and writing compressed input. | -| `bench` | Enable benchmark tests. Behind feature flag since it requires unstable Rust. | +| `fxhash` | Use the faster firefox hash function from `rustc-hash` in `rustsat`. | | `rand` | Enable randomization features. (Shuffling clauses etc.) | +| `ipasir-display` | Changes `Display` trait for `Lit` and `Var` types to follow IPASIR variables indexing. | +| `bench` | Enable benchmark tests. Behind feature flag since it requires unstable Rust. | +| `internals` | Make some internal data structures for e.g. encodings public. This is useful when basing a more complex encoding on the `rustsat` implementation of another encoding. Note that the internal API might change between releases. | ## Examples diff --git a/capi/README.md b/capi/README.md index e3a23e8e..ad139772 100644 --- a/capi/README.md +++ b/capi/README.md @@ -7,11 +7,10 @@ In the C-API, literals are represented as IPASIR literals. -This is the C-API for RustSAT. Currently this API is very minimal and not -the focus of this project. For now, only the API of certain encodings is -available. +This is the C-API for RustSAT. Currently this API is very minimal and not the focus of this +project. For now, only the API of certain encodings is available. -For the API itself, see `rustsat.h`. To use RustSAT from an external project, -build this crate and link against `librustsat.a` +For the API itself, see `rustsat.h`. To use RustSAT from an external project, build this crate +and link against `librustsat_capi.a` (produced by `cargo` in `target/release`). From 09e62646bf9ebb27843efe11bd63490d616409dd Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Wed, 10 Apr 2024 10:14:14 +0300 Subject: [PATCH 49/56] feat: incremental precision in DPW --- capi/rustsat.h | 109 +++- capi/src/lib.rs | 178 ++++- data/inc-sis-fails.wcnf | 10 + rustsat/src/encodings/card/dbtotalizer.rs | 109 +++- rustsat/src/encodings/nodedb.rs | 2 +- rustsat/src/encodings/pb/dbgte.rs | 3 + rustsat/src/encodings/pb/dpw.rs | 752 +++++++++++++++++++--- rustsat/tests/pb_encodings.rs | 174 +++++ tools/src/utils.rs | 6 +- 9 files changed, 1201 insertions(+), 142 deletions(-) create mode 100644 data/inc-sis-fails.wcnf diff --git a/capi/rustsat.h b/capi/rustsat.h index 86c815e4..756bf81a 100644 --- a/capi/rustsat.h +++ b/capi/rustsat.h @@ -16,7 +16,7 @@ typedef enum MaybeError { /** * No error */ - Ok, + Ok = 0, /** * Encode was not called before using the encoding */ @@ -29,6 +29,18 @@ typedef enum MaybeError { * The encoding is in an invalid state to perform this action */ InvalidState, + /** + * Invalid IPASIR-style literal + */ + InvalidLiteral, + /** + * Precision divisor is not a power of 2 + */ + PrecisionNotPow2, + /** + * Attempting to decrease precision + */ + PrecisionDecreased, } MaybeError; /** @@ -69,9 +81,14 @@ extern "C" { #endif // __cplusplus /** - * Adds a new input literal to a [`DynamicPolyWatchdog`]. Input - * literals can only be added _before_ the encoding is built for the - * first time. Otherwise [`MaybeError::InvalidState`] is returned. + * Adds a new input literal to a [`DynamicPolyWatchdog`]. + * + * # Errors + * + * - If `lit` is not a valid IPASIR-style literal (e.g., `lit = 0`), + * [`MaybeError::InvalidLiteral`] is returned + * - If a literal is added _after_ the encoding is build, [`MaybeError::InvalidState`] is + * returned * * # Safety * @@ -147,20 +164,102 @@ enum MaybeError dpw_enforce_ub(struct DynamicPolyWatchdog *dpw, CAssumpCollector collector, void *collector_data); +/** + * Checks whether the encoding is already at the maximum precision + * + * # Safety + * + * `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + * not yet been called on. + */ +bool dpw_is_max_precision(struct DynamicPolyWatchdog *dpw); + +/** + * Given a range of output values to limit the encoding to, returns additional clauses that + * "shrink" the encoding through hardening + * + * The output value range must be a range considering _all_ input literals, not only the + * encoded ones. + * + * This is intended for, e.g., a MaxSAT solving application where a global lower bound is + * derived and parts of the encoding can be hardened. + * + * The min and max bounds are inclusive. After a call to [`dpw_limit_range`] with + * `min_value=2` and `max_value=4`, the encoding is valid for the value range `2 <= range + * <= 4`. + * + * To not specify a bound, pass `0` for the lower bound or `SIZE_MAX` for the upper bound. + * + * Clauses are returned via the `collector`. The `collector` function should expect + * clauses to be passed similarly to `ipasir_add`, as a 0-terminated sequence of literals + * where the literals are passed as the first argument and the `collector_data` as a + * second. + * + * # Safety + * + * `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + * not yet been called on. + */ +void dpw_limit_range(struct DynamicPolyWatchdog *dpw, + size_t min_value, + size_t max_value, + CClauseCollector collector, + void *collector_data); + /** * Creates a new [`DynamicPolyWatchdog`] cardinality encoding */ struct DynamicPolyWatchdog *dpw_new(void); +/** + * Gets the next possible precision divisor value + * + * Note that this is not the next possible precision value from the last _set_ precision but + * from the last _encoded_ precision. The divisor value will always be a power of two so that + * calling `set_precision` and then encoding will produce the smalles non-empty next segment + * of the encoding. + * + * # Safety + * + * `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + * not yet been called on. + */ +size_t dpw_next_precision(struct DynamicPolyWatchdog *dpw); + +/** + * Set the precision at which to build the encoding at. With `divisor = 8` the encoding will + * effectively be built such that the weight of every input literal is divided by `divisor` + * (interger division, rounding down). Divisor values must be powers of 2. After building + * the encoding, the precision can only be increased, i.e., only call this function with + * _decreasing_ divisor values. + * + * # Errors + * + * - If `divisor` is not a power of 2, [`MaybeError::PrecisionNotPow2`] is returned + * - If `divisor` is larger than the last divisor, i.e., precision is attemted to be + * decreased, [`MaybeError::PrecisionDecreased`] is returned + * + * # Safety + * + * `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + * not yet been called on. + */ +enum MaybeError dpw_set_precision(struct DynamicPolyWatchdog *dpw, size_t divisor); + /** * Adds a new input literal to a [`DbTotalizer`] * + * # Errors + * + * - If `lit` is not a valid IPASIR-style literal (e.g., `lit = 0`), + * [`MaybeError::InvalidLiteral`] is returned + * * # Safety * * `tot` must be a return value of [`tot_new`] that [`tot_drop`] has * not yet been called on. */ -void tot_add(struct DbTotalizer *tot, int lit); +enum MaybeError tot_add(struct DbTotalizer *tot, int lit); /** * Frees the memory associated with a [`DbTotalizer`] diff --git a/capi/src/lib.rs b/capi/src/lib.rs index f5fef5e6..58776936 100644 --- a/capi/src/lib.rs +++ b/capi/src/lib.rs @@ -22,13 +22,19 @@ pub mod encodings { #[repr(C)] pub enum MaybeError { /// No error - Ok, + Ok = 0, /// Encode was not called before using the encoding NotEncoded, /// The requested encoding is unsatisfiable Unsat, /// The encoding is in an invalid state to perform this action InvalidState, + /// Invalid IPASIR-style literal + InvalidLiteral, + /// Precision divisor is not a power of 2 + PrecisionNotPow2, + /// Attempting to decrease precision + PrecisionDecreased, } impl From for MaybeError { @@ -40,6 +46,20 @@ pub mod encodings { } } + impl From> for MaybeError { + fn from(value: Result<(), encodings::pb::dpw::PrecisionError>) -> Self { + match value { + Ok(_) => MaybeError::Ok, + Err(err) => match err { + encodings::pb::dpw::PrecisionError::NotPow2 => MaybeError::PrecisionNotPow2, + encodings::pb::dpw::PrecisionError::PrecisionDecreased => { + MaybeError::PrecisionDecreased + } + }, + } + } + } + pub type CClauseCollector = extern "C" fn(lit: c_int, data: *mut c_void); pub type CAssumpCollector = extern "C" fn(lit: c_int, data: *mut c_void); @@ -165,15 +185,26 @@ pub mod encodings { /// Adds a new input literal to a [`DbTotalizer`] /// + /// # Errors + /// + /// - If `lit` is not a valid IPASIR-style literal (e.g., `lit = 0`), + /// [`MaybeError::InvalidLiteral`] is returned + /// /// # Safety /// /// `tot` must be a return value of [`tot_new`] that [`tot_drop`] has /// not yet been called on. #[no_mangle] - pub unsafe extern "C" fn tot_add(tot: *mut DbTotalizer, lit: c_int) { + pub unsafe extern "C" fn tot_add(tot: *mut DbTotalizer, lit: c_int) -> MaybeError { let mut boxed = unsafe { Box::from_raw(tot) }; - boxed.extend([Lit::from_ipasir(lit).expect("invalid IPASIR literal")]); + let lit = if let Ok(lit) = Lit::from_ipasir(lit) { + lit + } else { + return MaybeError::InvalidLiteral; + }; + boxed.extend([lit]); Box::into_raw(boxed); + MaybeError::Ok } /// Lazily builds the _change in_ cardinality encoding to enable upper @@ -322,9 +353,14 @@ pub mod encodings { Box::into_raw(Box::default()) } - /// Adds a new input literal to a [`DynamicPolyWatchdog`]. Input - /// literals can only be added _before_ the encoding is built for the - /// first time. Otherwise [`MaybeError::InvalidState`] is returned. + /// Adds a new input literal to a [`DynamicPolyWatchdog`]. + /// + /// # Errors + /// + /// - If `lit` is not a valid IPASIR-style literal (e.g., `lit = 0`), + /// [`MaybeError::InvalidLiteral`] is returned + /// - If a literal is added _after_ the encoding is build, [`MaybeError::InvalidState`] is + /// returned /// /// # Safety /// @@ -337,10 +373,12 @@ pub mod encodings { weight: usize, ) -> MaybeError { let mut boxed = unsafe { Box::from_raw(dpw) }; - let res = boxed.add_input( - Lit::from_ipasir(lit).expect("invalid IPASIR literal"), - weight, - ); + let lit = if let Ok(lit) = Lit::from_ipasir(lit) { + lit + } else { + return MaybeError::InvalidLiteral; + }; + let res = boxed.add_input(lit, weight); Box::into_raw(boxed); if res.is_ok() { MaybeError::Ok @@ -434,6 +472,107 @@ pub mod encodings { ret } + /// Set the precision at which to build the encoding at. With `divisor = 8` the encoding will + /// effectively be built such that the weight of every input literal is divided by `divisor` + /// (interger division, rounding down). Divisor values must be powers of 2. After building + /// the encoding, the precision can only be increased, i.e., only call this function with + /// _decreasing_ divisor values. + /// + /// # Errors + /// + /// - If `divisor` is not a power of 2, [`MaybeError::PrecisionNotPow2`] is returned + /// - If `divisor` is larger than the last divisor, i.e., precision is attemted to be + /// decreased, [`MaybeError::PrecisionDecreased`] is returned + /// + /// # Safety + /// + /// `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + /// not yet been called on. + #[no_mangle] + pub unsafe extern "C" fn dpw_set_precision( + dpw: *mut DynamicPolyWatchdog, + divisor: usize, + ) -> MaybeError { + let mut boxed = unsafe { Box::from_raw(dpw) }; + let ret = boxed.set_precision(divisor).into(); + Box::into_raw(boxed); + ret + } + + /// Gets the next possible precision divisor value + /// + /// Note that this is not the next possible precision value from the last _set_ precision but + /// from the last _encoded_ precision. The divisor value will always be a power of two so that + /// calling `set_precision` and then encoding will produce the smalles non-empty next segment + /// of the encoding. + /// + /// # Safety + /// + /// `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + /// not yet been called on. + #[no_mangle] + pub unsafe extern "C" fn dpw_next_precision(dpw: *mut DynamicPolyWatchdog) -> usize { + let boxed = unsafe { Box::from_raw(dpw) }; + let ret = boxed.next_precision(); + Box::into_raw(boxed); + ret + } + + /// Checks whether the encoding is already at the maximum precision + /// + /// # Safety + /// + /// `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + /// not yet been called on. + #[no_mangle] + pub unsafe extern "C" fn dpw_is_max_precision(dpw: *mut DynamicPolyWatchdog) -> bool { + let boxed = unsafe { Box::from_raw(dpw) }; + let ret = boxed.is_max_precision(); + Box::into_raw(boxed); + ret + } + + /// Given a range of output values to limit the encoding to, returns additional clauses that + /// "shrink" the encoding through hardening + /// + /// The output value range must be a range considering _all_ input literals, not only the + /// encoded ones. + /// + /// This is intended for, e.g., a MaxSAT solving application where a global lower bound is + /// derived and parts of the encoding can be hardened. + /// + /// The min and max bounds are inclusive. After a call to [`dpw_limit_range`] with + /// `min_value=2` and `max_value=4`, the encoding is valid for the value range `2 <= range + /// <= 4`. + /// + /// To not specify a bound, pass `0` for the lower bound or `SIZE_MAX` for the upper bound. + /// + /// Clauses are returned via the `collector`. The `collector` function should expect + /// clauses to be passed similarly to `ipasir_add`, as a 0-terminated sequence of literals + /// where the literals are passed as the first argument and the `collector_data` as a + /// second. + /// + /// # Safety + /// + /// `dpw` must be a return value of [`dpw_new`] that [`dpw_drop`] has + /// not yet been called on. + #[no_mangle] + pub unsafe extern "C" fn dpw_limit_range( + dpw: *mut DynamicPolyWatchdog, + min_value: usize, + max_value: usize, + collector: CClauseCollector, + collector_data: *mut c_void, + ) { + assert!(min_value <= max_value); + let mut collector = ClauseCollector::new(collector, collector_data); + let boxed = unsafe { Box::from_raw(dpw) }; + boxed + .limit_range(min_value..=max_value, &mut collector) + .expect("clause collector returned out of memory"); + Box::into_raw(boxed); + } + /// Frees the memory associated with a [`DynamicPolyWatchdog`] /// /// # Safety @@ -481,10 +620,10 @@ pub mod encodings { int main() { DynamicPolyWatchdog *dpw = dpw_new(); - dpw_add(dpw, 1, 1); - dpw_add(dpw, 2, 1); - dpw_add(dpw, 3, 2); - dpw_add(dpw, 4, 2); + assert(dpw_add(dpw, 1, 1) == Ok); + assert(dpw_add(dpw, 2, 1) == Ok); + assert(dpw_add(dpw, 3, 2) == Ok); + assert(dpw_add(dpw, 4, 2) == Ok); int n_used = 4; int n_clauses = 0; dpw_encode_ub(dpw, 0, 6, &n_used, &clause_counter, &n_clauses); @@ -518,16 +657,17 @@ pub mod encodings { int main() { DynamicPolyWatchdog *dpw = dpw_new(); - dpw_add(dpw, 1, 5); - dpw_add(dpw, 2, 3); - dpw_add(dpw, 3, 8); - dpw_add(dpw, 4, 7); + assert(dpw_add(dpw, 1, 5) == Ok); + assert(dpw_add(dpw, 2, 3) == Ok); + assert(dpw_add(dpw, 3, 8) == Ok); + assert(dpw_add(dpw, 4, 7) == Ok); int n_used = 4; int n_clauses = 0; dpw_encode_ub(dpw, 0, 23, &n_used, &clause_counter, &n_clauses); - for (size_t ub = 8; ub <= 23; ub++) { + for (size_t ub = 7; ub < 23; ub++) { size_t coarse_ub = dpw_coarse_ub(dpw, ub); assert(coarse_ub <= ub); + if (ub % 8 == 7) assert(coarse_ub == ub); int n_assumps = 0; assert(dpw_enforce_ub(dpw, coarse_ub, &assump_counter, &n_assumps) == Ok); assert(n_assumps == 1); diff --git a/data/inc-sis-fails.wcnf b/data/inc-sis-fails.wcnf new file mode 100644 index 00000000..e7b4678a --- /dev/null +++ b/data/inc-sis-fails.wcnf @@ -0,0 +1,10 @@ +h 1 2 3 0 +8632 -4 0 +h -5 -6 0 +h -7 3 0 +h 7 4 -5 0 +1937 -2 0 +h -7 8 0 +h 5 7 0 +h 6 -8 -3 0 +h -3 5 0 diff --git a/rustsat/src/encodings/card/dbtotalizer.rs b/rustsat/src/encodings/card/dbtotalizer.rs index 099d823f..fc5f2917 100644 --- a/rustsat/src/encodings/card/dbtotalizer.rs +++ b/rustsat/src/encodings/card/dbtotalizer.rs @@ -133,7 +133,7 @@ impl BoundUpper for DbTotalizer { } } } - Node::General(_) => panic!(), + Node::General(_) | Node::Dummy => panic!(), } } Err(Error::NotEncoded) @@ -210,7 +210,7 @@ impl Extend for DbTotalizer { } /// A totalizer adder node -#[derive(Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Node { /// An input literal, i.e., a leaf of the tree Leaf(Lit), @@ -218,16 +218,23 @@ pub enum Node { Unit(UnitNode), /// An internal weighted node General(GeneralNode), + /// A dummy node to patch in another structure later on + Dummy, } impl NodeLike for Node { type ValIter = std::iter::Chain, std::vec::IntoIter>; + fn is_leaf(&self) -> bool { + matches!(self, Node::Leaf(_)) + } + fn max_val(&self) -> usize { match self { Node::Leaf(_) => 1, Node::Unit(node) => node.lits.len(), Node::General(node) => node.max_val, + Node::Dummy => 0, } } @@ -236,6 +243,7 @@ impl NodeLike for Node { Node::Leaf(_) => 1, Node::Unit(node) => node.lits.len(), Node::General(node) => node.lits.len(), + Node::Dummy => 0, } } @@ -267,28 +275,29 @@ impl NodeLike for Node { let vals: Vec<_> = node.lits.range(range).map(|(val, _)| *val).collect(); (0..0).chain(vals) } + Node::Dummy => (0..0).chain(vec![]), } } fn right(&self) -> Option { match self { - Node::Leaf(..) => None, - Node::Unit(node) => Some(node.left), - Node::General(node) => Some(node.left), + Node::Leaf(..) | Node::Dummy => None, + Node::Unit(node) => Some(node.right), + Node::General(node) => Some(node.right), } } fn left(&self) -> Option { match self { - Node::Leaf(..) => None, - Node::Unit(node) => Some(node.right), - Node::General(node) => Some(node.right), + Node::Leaf(..) | Node::Dummy => None, + Node::Unit(node) => Some(node.left), + Node::General(node) => Some(node.left), } } fn depth(&self) -> usize { match self { - Node::Leaf(..) => 1, + Node::Leaf(..) | Node::Dummy => 1, Node::Unit(node) => node.depth, Node::General(node) => node.depth, } @@ -345,6 +354,7 @@ impl Node { } Node::Unit(node) => node.lit(val), Node::General(node) => node.lit(val), + Node::Dummy => None, } } @@ -359,11 +369,12 @@ impl Node { } Node::Unit(node) => node.encoded_pos(val), Node::General(node) => node.encoded_pos(val), + Node::Dummy => true, } } /// Returns the internal node and panics if the node is not a unit - pub(super) fn unit(&self) -> &UnitNode { + pub(crate) fn unit(&self) -> &UnitNode { match self { Node::Unit(node) => node, _ => panic!("called `unit` on non-unit node"), @@ -371,7 +382,7 @@ impl Node { } /// Returns the internal node and panics if the node is not a unit - pub(super) fn mut_unit(&mut self) -> &mut UnitNode { + pub(crate) fn mut_unit(&mut self) -> &mut UnitNode { match self { Node::Unit(node) => node, _ => panic!("called `unit` on non-unit node"), @@ -379,7 +390,7 @@ impl Node { } /// Returns the internal node and panics if the node is not general - pub(super) fn mut_general(&mut self) -> &mut GeneralNode { + pub(crate) fn mut_general(&mut self) -> &mut GeneralNode { match self { Node::General(node) => node, _ => panic!("called `unit` on non-general node"), @@ -391,7 +402,7 @@ impl Node { /// [`NodeId`] as an Error. fn drain(&mut self, range: Range) -> Result<(), NodeId> { match self { - Node::Leaf(_) => Ok(()), + Node::Leaf(_) | Node::Dummy => Ok(()), Node::Unit(UnitNode { left, right, .. }) | Node::General(GeneralNode { left, right, .. }) => { if range.contains(&left.id) { @@ -423,7 +434,7 @@ impl Index for Node { } /// An internal node of the totalizer -#[derive(Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct UnitNode { pub(crate) lits: Vec, pub(crate) depth: usize, @@ -467,7 +478,7 @@ impl Index for UnitNode { } /// An internal _general_ (weighted) node -#[derive(Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct GeneralNode { pub(crate) lits: BTreeMap, pub(crate) depth: usize, @@ -517,7 +528,7 @@ impl GeneralNode { } /// Data associated with an output literal in a [`Node`] -#[derive(Default, Clone)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub(crate) enum LitData { #[default] None, @@ -562,17 +573,28 @@ pub(in crate::encodings) struct TotDb { nodes: Vec, /// Mapping literals to leaf nodes lookup_leaf: RsHashMap, + /// Dummy Node ID + dummy_id: Option, } impl NodeById for TotDb { type Node = Node; fn insert(&mut self, node: Self::Node) -> NodeId { - if let Node::Leaf(lit) = node { - if let Some(&id) = self.lookup_leaf.get(&lit) { - return id; + match node { + Node::Leaf(lit) => { + if let Some(&id) = self.lookup_leaf.get(&lit) { + return id; + } + self.lookup_leaf.insert(lit, NodeId(self.nodes.len())); } - self.lookup_leaf.insert(lit, NodeId(self.nodes.len())); + Node::Dummy => { + if let Some(id) = self.dummy_id { + return id; + } + self.dummy_id = Some(NodeId(self.nodes.len())); + } + _ => (), } self.nodes.push(node); NodeId(self.nodes.len() - 1) @@ -756,6 +778,7 @@ impl TotDb { Ok(Some(olit)) } + Node::Dummy => Ok(None), } } @@ -781,8 +804,14 @@ impl TotDb { } let lcon = node.left().unwrap(); let rcon = node.right().unwrap(); - debug_assert!(matches!(self[lcon.id], Node::Leaf(_) | Node::Unit(_))); - debug_assert!(matches!(self[rcon.id], Node::Leaf(_) | Node::Unit(_))); + debug_assert!(matches!( + self[rcon.id], + Node::Leaf(_) | Node::Unit(_) | Node::Dummy + )); + debug_assert!(matches!( + self[lcon.id], + Node::Leaf(_) | Node::Unit(_) | Node::Dummy + )); debug_assert_eq!(lcon.multiplier(), 1); debug_assert_eq!(rcon.multiplier(), 1); let node = node.unit(); @@ -796,6 +825,32 @@ impl TotDb { let con_idx = |idx: usize, con: NodeCon| con.rev_map(idx + 1) - 1; + // treat dummy nodes by passing through other connection + if matches!(self[lcon.id], Node::Dummy) || matches!(self[rcon.id], Node::Dummy) { + let realcon = if matches!(self[lcon.id], Node::Dummy) { + &rcon + } else { + &lcon + }; + debug_assert!(matches!(self[realcon.id], Node::Leaf(_) | Node::Unit(_))); + let ilit = + self.define_pos_tot(realcon.id, con_idx(idx, *realcon), collector, var_manager)?; + // Reserve variable for this node, if needed + let olit = if let Some(&olit) = self[id].lit(idx + 1) { + olit + } else { + let olit = var_manager.new_var().pos_lit(); + self[id].mut_unit().lits[idx] = LitData::new_lit(olit); + olit + }; + collector.add_clause(atomics::lit_impl_lit(ilit, olit))?; + match &mut self[id].mut_unit().lits[idx] { + LitData::None => unreachable!(), + LitData::Lit { enc_pos, .. } => *enc_pos = true, + }; + return Ok(olit); + } + // The maximum indices of left and right that influence the current // literal (ignoring offset and divisor) let l_max_idx = cmp::min(self.con_len(lcon) - 1, idx); @@ -908,7 +963,7 @@ impl TotDb { } } } - Node::Leaf(_) => panic!(), + Node::Leaf(_) | Node::Dummy => panic!(), } } @@ -930,7 +985,7 @@ impl TotDb { } } } - Node::Leaf(_) => (), + Node::Leaf(_) | Node::Dummy => (), } } } @@ -941,7 +996,7 @@ impl TotDb { pub fn reset_vars(&mut self) { for node in &mut self.nodes { match node { - Node::Leaf(_) => (), + Node::Leaf(_) | Node::Dummy => (), Node::Unit(UnitNode { lits, .. }) => { for lit in lits { *lit = LitData::None; @@ -1083,7 +1138,7 @@ pub mod referenced { } } } - Node::General(_) => panic!(), + Node::General(_) | Node::Dummy => panic!(), } Err(Error::NotEncoded) } @@ -1120,7 +1175,7 @@ pub mod referenced { } } } - Node::General(_) => panic!(), + Node::General(_) | Node::Dummy => panic!(), } Err(Error::NotEncoded) } diff --git a/rustsat/src/encodings/nodedb.rs b/rustsat/src/encodings/nodedb.rs index 9d0cd699..f859dfaa 100644 --- a/rustsat/src/encodings/nodedb.rs +++ b/rustsat/src/encodings/nodedb.rs @@ -142,7 +142,7 @@ pub trait NodeLike { } /// A connection to another node. -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct NodeCon { /// The child node pub id: NodeId, diff --git a/rustsat/src/encodings/pb/dbgte.rs b/rustsat/src/encodings/pb/dbgte.rs index 8187c048..a8efa73a 100644 --- a/rustsat/src/encodings/pb/dbgte.rs +++ b/rustsat/src/encodings/pb/dbgte.rs @@ -212,6 +212,7 @@ impl BoundUpper for DbGte { } } } + Node::Dummy => panic!(), } Err(Error::NotEncoded) })? @@ -486,6 +487,7 @@ pub mod referenced { } } } + Node::Dummy => panic!(), } Err(Error::NotEncoded) })?; @@ -542,6 +544,7 @@ pub mod referenced { } } } + Node::Dummy => panic!(), } Err(Error::NotEncoded) })?; diff --git a/rustsat/src/encodings/pb/dpw.rs b/rustsat/src/encodings/pb/dpw.rs index 4ba90a46..9c9b368b 100644 --- a/rustsat/src/encodings/pb/dpw.rs +++ b/rustsat/src/encodings/pb/dpw.rs @@ -14,24 +14,41 @@ //! Watchdog Encoding for Solving Weighted MaxSAT_, SAT 2018. use std::{ + cmp, collections::BTreeMap, num::{NonZeroU8, NonZeroUsize}, ops::RangeBounds, }; use crate::{ + clause, encodings::{ - card::dbtotalizer::{Node, TotDb}, + atomics, + card::dbtotalizer::{GeneralNode, LitData, Node, TotDb, UnitNode}, nodedb::{NodeById, NodeCon, NodeId, NodeLike}, CollectClauses, EncodeStats, Error, IterWeightedInputs, }, instances::ManageVars, + lit, types::{Lit, RsHashMap}, utils, }; use super::{BoundUpper, BoundUpperIncremental, Encode, EncodeIncremental}; +type WeightQ = BTreeMap>; + +/// Errors related to incremental precision +#[derive(Error, Debug, PartialEq, Eq)] +pub enum PrecisionError { + /// Precision divisor was not a power of 2 + #[error("precision divisor must be a power of 2")] + NotPow2, + /// Precision divisor was higher than previous one + #[error("precision can only be increased")] + PrecisionDecreased, +} + /// Implementation of the dynamic polynomial watchdog (DPW) encoding \[1\]. /// /// **Note**: @@ -50,6 +67,10 @@ pub struct DynamicPolyWatchdog { in_lits: RsHashMap, /// The encoding root and the tares structure: Option, + /// Queue by weight of children that still have to be added to the tree + weight_queue: WeightQ, + /// The current precision divisor of the encoding + prec_div: usize, /// Sum of all input weight weight_sum: usize, /// The number of variables @@ -64,7 +85,7 @@ impl DynamicPolyWatchdog { /// Gets the maximum depth of the tree pub fn depth(&self) -> usize { match &self.structure { - Some(Structure { root, .. }) => self.db[*root].depth(), + Some(structure) => self.db[structure.root()].depth(), None => 0, } } @@ -84,6 +105,110 @@ impl DynamicPolyWatchdog { self.in_lits.insert(lit, weight); } self.weight_sum += weight; + let node = self.db.insert(Node::Leaf(lit)); + let con = NodeCon::full(node); + if let Some(cons) = self.weight_queue.get_mut(&weight) { + cons.push(con); + } else { + self.weight_queue.insert(weight, vec![con]); + } + Ok(()) + } + + /// Set the precision at which to build the encoding at. With `divisor = 8` the encoding will + /// effectively be built such that the weight of every input literal is divided by `divisor` + /// (interger division, rounding down). Divisor values must be powers of 2. After building + /// the encoding, the precision can only be increased, i.e., only call this function with + /// _decreasing_ divisor values. + /// + /// # Errors + /// + /// Returns an error if the divisor value is not a power of 2 or was increased. + pub fn set_precision(&mut self, divisor: usize) -> Result<(), PrecisionError> { + if !(divisor <= 1 || (divisor & (divisor - 1)) == 0) { + return Err(PrecisionError::NotPow2); + } + if self.structure.is_some() && divisor > self.prec_div { + return Err(PrecisionError::PrecisionDecreased); + } + self.prec_div = divisor; + Ok(()) + } + + /// Gets the next possible precision divisor value + /// + /// Note that this is not the next possible precision value from the last _set_ precision but + /// from the last _encoded_ precision. The divisor value will always be a power of two so that + /// calling `set_precision` and then encoding will produce the smalles non-empty next segment + /// of the encoding. + pub fn next_precision(&self) -> usize { + if self.weight_queue.is_empty() { + return 1; + } + let digits = utils::digits(*self.weight_queue.iter().next_back().unwrap().0, 2) as usize; + 1 << (digits - 1) + } + + /// Checks whether the encoding is already at the maximum precision + pub fn is_max_precision(&self) -> bool { + self.weight_queue.is_empty() + } + + /// Given a range of output values to limit the encoding to, returns additional clauses that + /// "shrink" the encoding through hardening + /// + /// The output value range must be a range considering _all_ input literals, not only the + /// encoded ones. + /// + /// This is intended for, e.g., a MaxSAT solving application where a global lower bound is + /// derived and parts of the encoding can be hardened. + pub fn limit_range( + &self, + range: R, + collector: &mut Col, + ) -> Result<(), crate::OutOfMemory> + where + Col: CollectClauses, + R: RangeBounds, + { + let range = super::prepare_ub_range(self, range); + if let Some(structure) = &self.structure { + if self.is_max_precision() { + let output_weight = 1 << (structure.output_power()); + let range = + range.start / output_weight..(range.end + output_weight - 1) / output_weight; + let root = &self.db[structure.root()]; + // positively harden lower bound + collector.extend_clauses( + root.vals(..=range.start) + .flat_map(|val| root.lit(val).map(|&olit| clause![olit])), + )?; + // negatively harden upper bound + collector.extend_clauses( + root.vals(range.end..) + .filter_map(|val| root.lit(val).map(|&olit| clause![!olit])), + )?; + } else { + let idx_offset = utils::digits(structure.prec_div, 2) - 1; + for (idx, &bottom) in structure.bottom_buckets.iter().rev().enumerate() { + let div = 2usize.pow(idx as u32 + idx_offset); + let range = range.start / div..(range.end + div - 1) / div; + let top_con = self.db[bottom].left().unwrap(); + debug_assert_eq!(top_con.divisor(), 1); + let top = &self.db[top_con.id]; + // positively harden lower bound + collector.extend_clauses( + top.vals(..=top_con.rev_map(range.start)) + .flat_map(|val| top.lit(val).map(|&olit| clause![olit])), + )?; + // negatively harden upper bound + collector.extend_clauses( + top.vals(top_con.rev_map_round_up(range.end)..) + .filter_map(|val| top.lit(val).map(|&olit| clause![!olit])), + )?; + } + } + }; Ok(()) } } @@ -92,14 +217,22 @@ impl DynamicPolyWatchdog { #[cfg_attr(feature = "internals", visibility::make(pub))] #[derive(Clone)] pub(crate) struct Structure { - /// The root of the structure - pub root: NodeId, + /// The bottom buckets of the encoding. The first one of them is the root of the encoding. + /// Sorted from highest to lowest. This might skip some bottom buckets, if their level is + /// empty. + pub bottom_buckets: Vec, /// The tare variables needed to enforce specific bounds. First in vector is /// the tare to the second largest top bucket, then decreasing. pub tares: Vec, + /// The precision level of this structure + prec_div: usize, } impl Structure { + /// Gets the root of the structure + pub fn root(&self) -> NodeId { + self.bottom_buckets[0] + } /// Gets the power of the output literals (they represent a weight of /// 2^power) pub fn output_power(&self) -> usize { @@ -123,8 +256,8 @@ impl IterWeightedInputs for DynamicPolyWatchdog { impl EncodeIncremental for DynamicPolyWatchdog { fn reserve(&mut self, var_manager: &mut dyn ManageVars) { - if let Some(Structure { root, .. }) = &self.structure { - self.db.reserve_vars(*root, var_manager); + if let Some(structure) = &self.structure { + self.db.reserve_vars(structure.root(), var_manager); } } } @@ -145,19 +278,34 @@ impl BoundUpper for DynamicPolyWatchdog { } fn enforce_ub(&self, ub: usize) -> Result, Error> { + if self.weight_sum() <= ub && self.prec_div <= 1 { + return Ok(vec![]); + } match &self.structure { - Some(structure) => enforce_ub(structure, ub, &self.db), - None => { - if self.weight_sum() <= ub { - return Ok(vec![]); + Some(structure) => { + if !self.weight_queue.is_empty() + && self.weight_queue.iter().next_back().unwrap().0 >= &self.prec_div + { + return Err(Error::NotEncoded); } + debug_assert!(structure.prec_div >= self.prec_div); + let ub = ub + / 2_usize.pow( + utils::digits(structure.prec_div, 2) - utils::digits(self.prec_div, 2), + ); + enforce_ub(structure, ub, &self.db) + } + None => { if self.in_lits.len() > 1 { return Err(Error::NotEncoded); } debug_assert_eq!(self.in_lits.len(), 1); let (l, w) = self.in_lits.iter().next().unwrap(); - debug_assert!(*w > ub); - Ok(vec![-(*l)]) + Ok(if *w <= ub * std::cmp::min(self.prec_div, 1) { + vec![] + } else { + vec![-(*l)] + }) } } } @@ -195,16 +343,34 @@ impl BoundUpperIncremental for DynamicPolyWatchdog { return Ok(()); } let n_vars_before = var_manager.n_used(); + let mut fresh = false; if self.structure.is_none() && !self.in_lits.is_empty() { - self.structure = Some(build_lit_structure( - self.in_lits.iter().map(|(&l, &w)| (l, w)), + fresh = true; + self.structure = Some(build_structure( + &mut self.weight_queue, + self.prec_div, + true, &mut self.db, var_manager, - )); + )) } - match &self.structure { + match &mut self.structure { Some(structure) => { let n_clauses_before = collector.n_clauses(); + if !fresh + && !self.weight_queue.is_empty() + && self.weight_queue.iter().next_back().unwrap().0 >= &self.prec_div + { + // precision has been increased, need to extend encoding + let new_struct = build_structure( + &mut self.weight_queue, + self.prec_div, + false, + &mut self.db, + var_manager, + ); + merge_structures(structure, new_struct, &mut self.db, collector, var_manager)?; + } let output_weight = 1 << (structure.output_power()); let output_range = range.start / output_weight..(range.end - 1) / output_weight + 1; for oidx in output_range { @@ -232,13 +398,17 @@ impl EncodeStats for DynamicPolyWatchdog { impl From> for DynamicPolyWatchdog { fn from(lits: RsHashMap) -> Self { let weight_sum = lits.iter().fold(0, |sum, (_, w)| sum + *w); + let mut db = Default::default(); + let weight_queue = lit_weight_queue(lits.clone().into_iter(), &mut db); Self { - in_lits: lits.clone(), + in_lits: lits, structure: Default::default(), + weight_queue, + prec_div: 1, weight_sum, n_vars: Default::default(), n_clauses: Default::default(), - db: Default::default(), + db, } } } @@ -302,7 +472,7 @@ pub mod referenced { /// Gets the maximum depth of the tree pub fn depth(&self) -> usize { - self.db[self.structure.root].depth() + self.db[self.structure.root()].depth() } } @@ -314,27 +484,27 @@ pub mod referenced { /// Gets the maximum depth of the tree pub fn depth(&self) -> usize { - self.db.borrow()[self.structure.root].depth() + self.db.borrow()[self.structure.root()].depth() } } impl Encode for DynamicPolyWatchdog<'_> { fn weight_sum(&self) -> usize { let output_weight = 1 << self.structure.output_power(); - self.db[self.structure.root].len() * output_weight + self.db[self.structure.root()].len() * output_weight } } impl Encode for DynamicPolyWatchdogCell<'_> { fn weight_sum(&self) -> usize { let output_weight = 1 << self.structure.output_power(); - self.db.borrow()[self.structure.root].len() * output_weight + self.db.borrow()[self.structure.root()].len() * output_weight } } impl EncodeIncremental for DynamicPolyWatchdog<'_> { fn reserve(&mut self, var_manager: &mut dyn ManageVars) { - self.db.reserve_vars(self.structure.root, var_manager); + self.db.reserve_vars(self.structure.root(), var_manager); } } @@ -342,7 +512,7 @@ pub mod referenced { fn reserve(&mut self, var_manager: &mut dyn ManageVars) { self.db .borrow_mut() - .reserve_vars(self.structure.root, var_manager); + .reserve_vars(self.structure.root(), var_manager); } } @@ -461,28 +631,18 @@ type DpwIter<'a> = std::iter::Map< /// Builds a DPW [`Structure`] over weighted input literals #[cfg_attr(feature = "internals", visibility::make(pub))] -fn build_lit_structure>( - lits: LI, - tot_db: &mut TotDb, - var_manager: &mut dyn ManageVars, -) -> Structure { +fn lit_weight_queue>(lits: LI, tot_db: &mut TotDb) -> WeightQ { let lit_to_con = |(lit, weight)| { let node = tot_db.insert(Node::Leaf(lit)); NodeCon::weighted(node, weight) }; - let cons: Vec<_> = lits.map(lit_to_con).collect(); - build_structure(cons.into_iter(), tot_db, var_manager) + con_weight_queue(lits.map(lit_to_con)) } /// Builds a DPW [`Structure`] from [Node connections](NodeCon) #[cfg_attr(feature = "internals", visibility::make(pub))] -fn build_structure>( - cons: CI, - tot_db: &mut TotDb, - var_manager: &mut dyn ManageVars, -) -> Structure { - // Initialize weight queue - let mut weight_queue: BTreeMap> = BTreeMap::new(); +fn con_weight_queue>(cons: CI) -> WeightQ { + let mut weight_queue: WeightQ = BTreeMap::new(); for con in cons { if let Some(cons) = weight_queue.get_mut(&con.multiplier()) { cons.push(NodeCon { @@ -499,20 +659,41 @@ fn build_structure>( ); } } + weight_queue +} + +/// Builds a DPW [`Structure`] from up to a given `precision` from a `weight_queue` +#[cfg_attr(feature = "internals", visibility::make(pub))] +fn build_structure( + weight_queue: &mut WeightQ, + prec_div: usize, + topmost: bool, + tot_db: &mut TotDb, + var_manager: &mut dyn ManageVars, +) -> Structure { + // prec_div has to be a power of 2 + debug_assert!(prec_div <= 1 || (prec_div & (prec_div - 1)) == 0); + let skipped_levels = utils::digits(prec_div, 2) as usize - 1; + let basis_len = utils::digits(*weight_queue.iter().next_back().unwrap().0, 2) as usize; + let mut structure = Structure { + bottom_buckets: Vec::with_capacity(basis_len), + tares: Vec::with_capacity(basis_len - 1), + prec_div, + }; // Children to be merged to a given top bucket - let mut top_buckets = vec![vec![]; basis_len]; + let mut top_buckets = vec![vec![]; basis_len - skipped_levels]; // Converts a digit number to a corresponding index in the // `top_buckets`. Top buckets are ordered from smallest to highest. - let tb_idx = |digits: u32| (digits - 1) as usize; + let tb_idx = |digits: usize| (digits - 1 - skipped_levels) as usize; // Loop while there are new weights that need to be added and distribute // them to relevant top buckets - while !weight_queue.is_empty() { + while !weight_queue.is_empty() && weight_queue.iter().next_back().unwrap().0 >= &prec_div { let (weight, cons) = weight_queue.pop_last().unwrap(); let merged = tot_db.merge_balanced(&cons); - let digits = utils::digits(weight, 2); + let digits = utils::digits(weight, 2) as usize; let current_weight = 1 << (digits - 1); top_buckets[tb_idx(digits)].push(merged); // Insert remainder of totalizer as new child @@ -526,69 +707,220 @@ fn build_structure>( } } - if basis_len == 1 { + if basis_len == 1 && topmost { debug_assert_eq!(top_buckets[0].len(), 1); + debug_assert_eq!(top_buckets[0][0].offset(), 0); + debug_assert_eq!(top_buckets[0][0].multiplier(), 1); + debug_assert_eq!(top_buckets[0][0].divisor(), 1); + debug_assert!(structure.bottom_buckets.is_empty()); return Structure { - root: top_buckets[0][0].id, + bottom_buckets: vec![top_buckets[0][0].id], tares: vec![], + prec_div, }; } // Prepare tares - let mut tares: Vec<_> = (0..basis_len - 1) - .map(|_| var_manager.new_var().pos_lit()) - .collect(); - let tare_nodes: Vec<_> = tares - .iter() - .map(|&lit| tot_db.insert(Node::Leaf(lit))) - .collect(); - tares.shrink_to_fit(); + structure.tares.extend( + (0..basis_len - skipped_levels - if topmost { 1 } else { 0 }) + .map(|_| var_manager.new_var().pos_lit()), + ); // Merge top buckets and merge with bottom buckets - let mut last_bottom_bucket = None; + let mut bottom_buckets = Vec::with_capacity(basis_len - skipped_levels); + let mut bb_offset = 0; for (idx, mut cons) in top_buckets.into_iter().enumerate() { - if idx != basis_len - 1 { + let has_tare = if !topmost || idx != basis_len - skipped_levels - 1 { // Merge top bucket (except for last) with tare - cons.push(NodeCon::full(tare_nodes[idx])); - } + let tare = structure.tares[idx]; + cons.push(NodeCon::full(tot_db.insert(Node::Leaf(tare)))); + true + } else { + false + }; cons.sort_unstable_by_key(|&con| tot_db.con_len(con)); let top_bucket = tot_db.merge_balanced(&cons); - if last_bottom_bucket.is_none() { - // special case: lowest bucket does not need bottom buckets - if tot_db.con_len(top_bucket) == 1 { + if bottom_buckets.is_empty() { + // special case: lowest bucket either gets dummy or no bottom bucket + if has_tare && tot_db.con_len(top_bucket) == 1 { // top bucket is empty (except for tare), tare can be // omitted: shift to next layer continue; } debug_assert_eq!(top_bucket.divisor(), 1); - last_bottom_bucket = Some(NodeCon { - id: top_bucket.id, - offset: top_bucket.offset, - divisor: NonZeroU8::new(2).unwrap(), - multiplier: NonZeroUsize::new(1).unwrap(), - len_limit: None, - }); + if weight_queue.is_empty() { + // very last bottom bucket does not need bottom bucket + bottom_buckets.push(top_bucket.id); + bb_offset = top_bucket.offset; + } else { + // last bottom bucket for this segment, leave dummy node to path in extension + let dummy = tot_db.insert(Node::Dummy); + let right = NodeCon::full(dummy); + let bottom = tot_db.insert(Node::internal(top_bucket, right, tot_db)); + bottom_buckets.push(bottom); + bb_offset = 0; + } continue; } - let right = last_bottom_bucket.unwrap(); - let bottom = tot_db.insert(Node::internal(top_bucket, right, tot_db)); - last_bottom_bucket = Some(NodeCon { - id: bottom, - offset: 0, + let right = NodeCon { + id: *bottom_buckets.last().unwrap(), + offset: bb_offset, divisor: NonZeroU8::new(2).unwrap(), multiplier: NonZeroUsize::new(1).unwrap(), len_limit: None, - }); + }; + let bottom = tot_db.insert(Node::internal(top_bucket, right, tot_db)); + bottom_buckets.push(bottom); + bb_offset = 0; } - let root = last_bottom_bucket.unwrap(); - debug_assert_eq!(root.offset(), 0); - debug_assert_eq!(root.divisor(), 2); - Structure { - root: root.id, - tares, + structure + .bottom_buckets + .extend(bottom_buckets.into_iter().rev()); + structure +} + +/// Merges two DPW [`Structure`]s into a big one +/// +/// This is used when incrementally increasing the precision of the DPW +#[cfg_attr(feature = "internals", visibility::make(pub))] +fn merge_structures( + bot_struct: &mut Structure, + top_struct: Structure, + tot_db: &mut TotDb, + collector: &mut Col, + var_manager: &mut dyn ManageVars, +) -> Result<(), crate::OutOfMemory> +where + Col: CollectClauses, +{ + debug_assert!( + bot_struct.prec_div >= top_struct.prec_div * 2_usize.pow(top_struct.tares.len() as u32 - 1) + ); + let skipped_between: usize = (utils::digits( + bot_struct.prec_div / (top_struct.prec_div * 2_usize.pow(top_struct.tares.len() as u32)), + 2, + ) - 1) + .try_into() + .expect("error fitting u32 into usize"); + let n_old_tares = bot_struct.tares.len(); + let n_old_bbs = bot_struct.bottom_buckets.len(); + bot_struct.prec_div = top_struct.prec_div; + // step 1: rearrange tares, make space for new tares, move old ones to the back, put new tares + // in structure + bot_struct.tares.resize( + bot_struct.tares.len() + top_struct.tares.len() + skipped_between, + lit![0], + ); + bot_struct.tares[..].copy_within(..n_old_tares, top_struct.tares.len() + skipped_between); + for tare_idx in top_struct.tares.len()..top_struct.tares.len() + skipped_between { + bot_struct.tares[tare_idx] = var_manager.new_var().pos_lit(); + } + bot_struct.tares[..top_struct.tares.len()].copy_from_slice(&top_struct.tares); + // step 2: add tares that were previously unnecessary in bot_struct and additional tares that + // need to go inbetween the structures. this adds some new bottom buckets + for &tare in bot_struct.tares[top_struct.tares.len()..bot_struct.tares.len() - (n_old_bbs - 1)] + .iter() + .rev() + { + let dummy = tot_db.insert(Node::Dummy); + let right = NodeCon::full(dummy); + let tare_node = tot_db.insert(Node::Leaf(tare)); + let new_bottom = tot_db.insert(Node::internal(NodeCon::full(tare_node), right, tot_db)); + let last_bottom = *bot_struct.bottom_buckets.last().unwrap(); + debug_assert_eq!(tot_db[tot_db[last_bottom].right().unwrap().id], Node::Dummy); + match &mut tot_db[last_bottom] { + Node::Leaf(_) | Node::Dummy => unreachable!(), + Node::Unit(UnitNode { right, .. }) | Node::General(GeneralNode { right, .. }) => { + *right = NodeCon { + id: new_bottom, + offset: 0, + divisor: NonZeroU8::new(2).unwrap(), + multiplier: NonZeroUsize::new(1).unwrap(), + len_limit: None, + } + } + } + bot_struct.bottom_buckets.push(new_bottom); + } + debug_assert_eq!( + bot_struct.bottom_buckets.len(), + bot_struct.tares.len() - top_struct.tares.len() + 1 + ); + // step 3: patch together structures + let last_bottom = *bot_struct.bottom_buckets.last().unwrap(); + debug_assert_eq!(tot_db[tot_db[last_bottom].right().unwrap().id], Node::Dummy); + match &mut tot_db[last_bottom] { + Node::Leaf(_) | Node::Dummy => panic!(), + Node::Unit(UnitNode { right, .. }) | Node::General(GeneralNode { right, .. }) => { + *right = NodeCon { + id: *top_struct.bottom_buckets.first().unwrap(), + offset: 0, + divisor: NonZeroU8::new(2).unwrap(), + multiplier: NonZeroUsize::new(1).unwrap(), + len_limit: None, + } + } } + // step 4: concatenate bottom buckets + let n_top_bbs = top_struct.bottom_buckets.len(); + bot_struct.bottom_buckets.extend(top_struct.bottom_buckets); + // step 5: extend old bottom buckets + let mut old_right_max = 0; + for &bbid in bot_struct.bottom_buckets[..bot_struct.bottom_buckets.len() - n_top_bbs] + .iter() + .rev() + { + let bot_buck = &tot_db[bbid]; + let right = bot_buck.right().unwrap(); + let right_max = tot_db.con_len(right); + let left = bot_buck.left().unwrap(); + let left_max = tot_db.con_len(left); + debug_assert_eq!(right.divisor(), 2); + // encode outputs with new rlits + let bot_buck = tot_db[bbid].unit(); + let olits_to_extend: Vec<_> = bot_buck + .lits + .iter() + .enumerate() + .filter_map(|(idx, litdat)| { + if let &LitData::Lit { lit, enc_pos } = litdat { + if enc_pos && idx + 1 >= old_right_max { + return Some((lit, idx + 1)); + } + } + None + }) + .collect(); + for (olit, val) in olits_to_extend { + for rval in tot_db[right.id].vals( + right.rev_map(old_right_max + 1)..right.rev_map(cmp::min(right_max + 1, val)) + 1, + ) { + let lval = val - right.map(rval); + if left.is_possible(lval) { + let rlit = tot_db.define_pos_tot(right.id, rval - 1, collector, var_manager)?; + if lval == 0 { + collector.add_clause(atomics::lit_impl_lit(rlit, olit))?; + } else { + debug_assert_eq!(left.divisor(), 1); + let llit = + tot_db.define_pos_tot(left.id, lval - 1, collector, var_manager)?; + collector.add_clause(atomics::cube_impl_lit(&[rlit, llit], olit))?; + } + } + } + } + // next old right max + let bot_buck = tot_db[bbid].mut_unit(); + old_right_max = bot_buck.lits.len() / 2; + // add new output literals + let len = right_max + left_max; + debug_assert!(bot_buck.lits.len() <= len); + bot_buck.lits.resize(len, LitData::None); + } + + Ok(()) } /// Encodes an output of the DPW [`Structure`] @@ -603,10 +935,10 @@ fn encode_output( where Col: CollectClauses, { - if oidx >= tot_db[dpw.root].max_val() { + if oidx >= tot_db[dpw.root()].max_val() { return Ok(()); } - tot_db.define_pos_tot(dpw.root, oidx, collector, var_manager)?; + tot_db.define_pos_tot(dpw.root(), oidx, collector, var_manager)?; Ok(()) } @@ -615,10 +947,10 @@ where fn enforce_ub(dpw: &Structure, ub: usize, tot_db: &TotDb) -> Result, Error> { let output_weight = 1 << (dpw.output_power()); let oidx = ub / output_weight; - if oidx >= tot_db[dpw.root].max_val() { + if oidx >= tot_db[dpw.root()].max_val() { return Ok(vec![]); } - let olit = match tot_db[dpw.root].lit(oidx + 1) { + let olit = match tot_db[dpw.root()].lit(oidx + 1) { Some(&lit) => lit, None => return Err(Error::NotEncoded), }; @@ -645,11 +977,14 @@ fn enforce_ub(dpw: &Structure, ub: usize, tot_db: &TotDb) -> Result, Er #[cfg(test)] mod tests { use crate::{ - encodings::{pb::BoundUpper, EncodeStats}, + encodings::{ + pb::{BoundUpper, BoundUpperIncremental}, + EncodeStats, + }, instances::{BasicVarManager, Cnf}, lit, - types::RsHashMap, - types::Var, + types::{RsHashMap, Var}, + var, }; use super::DynamicPolyWatchdog; @@ -738,4 +1073,251 @@ mod tests { debug_assert_eq!(assumps.len(), 1); } } + + #[test] + fn incremental_precision() { + let mut lits = RsHashMap::default(); + lits.insert(lit![0], 5); + lits.insert(lit![1], 3); + lits.insert(lit![2], 8); + lits.insert(lit![3], 7); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::default(); + // step 1 + debug_assert_eq!(dpw.next_precision(), 8); + dpw.set_precision(8).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=4, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + // step 2 + debug_assert_eq!(dpw.next_precision(), 4); + dpw.set_precision(4).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=4, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + // step 3 + debug_assert_eq!(dpw.next_precision(), 2); + dpw.set_precision(2).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=4, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + // step 3 + debug_assert_eq!(dpw.next_precision(), 1); + dpw.set_precision(1).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=4, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + // last check + debug_assert_eq!(dpw.next_precision(), 1); + } + + #[test] + fn incremental_precision_2() { + let mut lits = RsHashMap::default(); + lits.insert(lit![3], 8632); + lits.insert(lit![1], 1937); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(var![8]); + + let mut n_inc_clauses = 0; + debug_assert_eq!(dpw.next_precision(), 8192); + dpw.set_precision(8192).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=1, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + n_inc_clauses += cnf.len(); + + dpw.set_precision(1024).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=9, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + n_inc_clauses += cnf.len(); + + let mut lits = RsHashMap::default(); + lits.insert(lit![3], 8632); + lits.insert(lit![1], 1937); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(var![8]); + dpw.set_precision(1024).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=9, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + + debug_assert_eq!(n_inc_clauses, cnf.len()); + } + + #[test] + fn incremental_precision_3() { + let mut lits = RsHashMap::default(); + lits.insert(lit![3], 8632); + lits.insert(lit![1], 1937); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(var![8]); + + let mut n_inc_clauses = 0; + debug_assert_eq!(dpw.next_precision(), 8192); + dpw.set_precision(2048).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=1, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + n_inc_clauses += cnf.len(); + + dpw.set_precision(1024).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=9, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + n_inc_clauses += cnf.len(); + + let mut lits = RsHashMap::default(); + lits.insert(lit![3], 8632); + lits.insert(lit![1], 1937); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(var![8]); + dpw.set_precision(1024).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=9, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + + debug_assert_eq!(n_inc_clauses, cnf.len()); + } + + #[test] + fn incremental_precision_4() { + let mut lits = RsHashMap::default(); + lits.insert(lit![0], 8); + lits.insert(lit![6], 16); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(var![7]); + + let mut n_inc_clauses = 0; + debug_assert_eq!(dpw.next_precision(), 16); + dpw.set_precision(8).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=3, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + n_inc_clauses += cnf.len(); + let assumps = dpw.enforce_ub(1).unwrap(); + debug_assert!(!assumps.is_empty()); + println!("{:?}", assumps); + let assumps = dpw.enforce_ub(0).unwrap(); + debug_assert!(!assumps.is_empty()); + println!("{:?}", assumps); + + dpw.set_precision(1).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=24, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(cnf.is_empty()); + println!("{:?}", cnf); + n_inc_clauses += cnf.len(); + let assumps = dpw.enforce_ub(8).unwrap(); + debug_assert!(!assumps.is_empty()); + println!("{:?}", assumps); + let assumps = dpw.enforce_ub(7).unwrap(); + debug_assert!(!assumps.is_empty()); + println!("{:?}", assumps); + + let mut lits = RsHashMap::default(); + lits.insert(lit![0], 8); + lits.insert(lit![6], 16); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(var![7]); + dpw.set_precision(1).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(0..=24, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + + debug_assert_eq!(n_inc_clauses, cnf.len()); + } + + #[test] + fn incremental_precision_5() { + let mut lits = RsHashMap::default(); + lits.insert(lit![15], 69); + lits.insert(lit![21], 64); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(var![22]); + + debug_assert_eq!(dpw.next_precision(), 64); + dpw.set_precision(64).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(1..=2, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + let assumps = dpw.enforce_ub(1).unwrap(); + debug_assert!(!assumps.is_empty()); + println!("{:?}", assumps); + + dpw.set_precision(1).unwrap(); + let mut cnf = Cnf::new(); + dpw.encode_ub_change(133..=133, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(cnf.is_empty()); + println!("{:?}", cnf); + let assumps = dpw.enforce_ub(133).unwrap(); + debug_assert!(assumps.is_empty()); + println!("{:?}", assumps); + + let mut cnf = Cnf::new(); + dpw.encode_ub_change(69..=69, &mut cnf, &mut var_manager) + .unwrap(); + debug_assert!(!cnf.is_empty()); + println!("{:?}", cnf); + let assumps = dpw.enforce_ub(69).unwrap(); + debug_assert!(!assumps.is_empty()); + println!("{:?}", assumps); + } + + #[test] + fn reduce_range() { + let mut lits = RsHashMap::default(); + lits.insert(lit![0], 5); + lits.insert(lit![1], 3); + lits.insert(lit![2], 8); + lits.insert(lit![3], 7); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(Var::new(4)); + let mut cnf = Cnf::new(); + dpw.encode_ub(.., &mut cnf, &mut var_manager).unwrap(); + let mut hardened = Cnf::new(); + dpw.limit_range(8..33, &mut hardened).unwrap(); + assert_eq!(hardened.len(), 2); + } + + #[test] + fn reduce_tot() { + let mut lits = RsHashMap::default(); + lits.insert(lit![0], 1); + lits.insert(lit![1], 1); + lits.insert(lit![2], 1); + lits.insert(lit![3], 1); + let mut dpw = DynamicPolyWatchdog::from(lits); + let mut var_manager = BasicVarManager::from_next_free(Var::new(4)); + let mut cnf = Cnf::new(); + dpw.encode_ub(.., &mut cnf, &mut var_manager).unwrap(); + let mut hardened = Cnf::new(); + dpw.limit_range(1..4, &mut hardened).unwrap(); + assert_eq!(hardened.len(), 2); + } } diff --git a/rustsat/tests/pb_encodings.rs b/rustsat/tests/pb_encodings.rs index 176611bf..a617ea11 100644 --- a/rustsat/tests/pb_encodings.rs +++ b/rustsat/tests/pb_encodings.rs @@ -312,6 +312,7 @@ fn test_ub_exhaustive>>( if decreasing { bound = max_val - bound; } + println!("bound: {}", bound); enc.encode_ub_change(bound..bound + 1, &mut solver, &mut var_manager) .unwrap(); @@ -423,3 +424,176 @@ generate_exhaustive!( tot_sim, simulators::Card ); + +mod dpw_inc_prec { + use rustsat::{ + encodings::pb::{dpw::DynamicPolyWatchdog, BoundUpper, BoundUpperIncremental}, + instances::{BasicVarManager, Cnf, ManageVars, OptInstance}, + lit, + solvers::{ + Solve, SolveIncremental, + SolverResult::{self, Sat, Unsat}, + }, + types::RsHashMap, + var, + }; + use rustsat_tools::{test_all, test_assignment}; + + #[test] + fn incremental_precision() { + let weights = [5, 8, 7, 3]; + let mut lits = RsHashMap::default(); + lits.insert(lit![0], weights[0]); + lits.insert(lit![1], weights[1]); + lits.insert(lit![2], weights[2]); + lits.insert(lit![3], weights[3]); + for decreasing in [false, true] { + println!("decreasing: {}", decreasing); + let mut solver = rustsat_minisat::core::Minisat::default(); + let mut enc = DynamicPolyWatchdog::from(lits.clone()); + let mut var_manager = BasicVarManager::default(); + var_manager.increase_next_free(var![4]); + + for prec in 0..3 { + let prec_div = 1 << (3 - prec); + println!("precision: {}", prec_div); + enc.set_precision(prec_div).unwrap(); + + let max_val = weights.iter().fold(0, |sum, &w| sum + (w / prec_div)); + let expected = |assign: usize, bound: usize| { + let sum = (0..4).fold(0, |sum, idx| { + sum + ((assign >> idx) & 1) * (weights[3 - idx] / prec_div) + }); + if sum <= bound { + Sat + } else { + Unsat + } + }; + + for mut bound in 0..=max_val { + if decreasing { + bound = max_val - bound; + } + println!("bound: {}", bound); + let mut cnf = Cnf::default(); + enc.encode_ub_change(bound..bound + 1, &mut cnf, &mut var_manager); + println!("extending encoding: {:?}", cnf); + solver.add_cnf(cnf).unwrap(); + let assumps = enc.enforce_ub(bound).unwrap(); + + test_all!( + solver, + assumps, // + expected(0b1111, bound), + expected(0b1110, bound), + expected(0b1101, bound), + expected(0b1100, bound), + expected(0b1011, bound), + expected(0b1010, bound), + expected(0b1001, bound), + expected(0b1000, bound), + expected(0b0111, bound), + expected(0b0110, bound), + expected(0b0101, bound), + expected(0b0100, bound), + expected(0b0011, bound), + expected(0b0010, bound), + expected(0b0001, bound), + expected(0b0000, bound) + ); + } + } + } + } + + #[test] + fn incremental_precision_2() { + let inst: OptInstance = OptInstance::from_dimacs_path("./data/inc-sis-fails.wcnf").unwrap(); + let (constr, obj) = inst.decompose(); + let (cnf, mut vm) = constr.as_cnf(); + let (hardened, (softs, offset)) = obj.as_soft_lits(&mut vm); + debug_assert!(hardened.is_empty()); + debug_assert_eq!(offset, 0); + let mut solver = rustsat_minisat::core::Minisat::default(); + solver.add_cnf(cnf).unwrap(); + let mut enc = DynamicPolyWatchdog::from_iter(softs); + + enc.set_precision(8192).unwrap(); + enc.encode_ub_change(0..=1, &mut solver, &mut vm); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(1).unwrap()).unwrap(), + SolverResult::Sat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(0).unwrap()).unwrap(), + SolverResult::Unsat + ); + + enc.set_precision(1024).unwrap(); + enc.encode_ub_change(0..=9, &mut solver, &mut vm); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(9).unwrap()).unwrap(), + SolverResult::Sat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(8).unwrap()).unwrap(), + SolverResult::Sat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(7).unwrap()).unwrap(), + SolverResult::Unsat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(0).unwrap()).unwrap(), + SolverResult::Unsat + ); + } + + #[test] + fn incremental_precision_3() { + let inst: OptInstance = OptInstance::from_dimacs_path("./data/inc-sis-fails.wcnf").unwrap(); + let (constr, obj) = inst.decompose(); + let (cnf, mut vm) = constr.as_cnf(); + let (hardened, (softs, offset)) = obj.as_soft_lits(&mut vm); + debug_assert!(hardened.is_empty()); + debug_assert_eq!(offset, 0); + let mut solver = rustsat_minisat::core::Minisat::default(); + solver.add_cnf(cnf).unwrap(); + let mut enc = DynamicPolyWatchdog::from_iter(softs); + + enc.set_precision(2048).unwrap(); + enc.encode_ub_change(0..=4, &mut solver, &mut vm); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(4).unwrap()).unwrap(), + SolverResult::Sat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(2).unwrap()).unwrap(), + SolverResult::Unsat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(0).unwrap()).unwrap(), + SolverResult::Unsat + ); + + enc.set_precision(1024).unwrap(); + enc.encode_ub_change(0..=9, &mut solver, &mut vm); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(9).unwrap()).unwrap(), + SolverResult::Sat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(8).unwrap()).unwrap(), + SolverResult::Sat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(7).unwrap()).unwrap(), + SolverResult::Unsat + ); + debug_assert_eq!( + solver.solve_assumps(&enc.enforce_ub(0).unwrap()).unwrap(), + SolverResult::Unsat + ); + } +} diff --git a/tools/src/utils.rs b/tools/src/utils.rs index 9f781761..c6494901 100644 --- a/tools/src/utils.rs +++ b/tools/src/utils.rs @@ -7,11 +7,7 @@ macro_rules! test_assignment { assumps.extend($assumps); let res = $solver.solve_assumps(&assumps).unwrap(); if res == rustsat::solvers::SolverResult::Sat && res != $result { - let mut max_var = rustsat::var![0]; - for a in assumps { - max_var = std::cmp::max(a.var(), max_var); - } - println!("{}", $solver.solution(max_var).unwrap()); + println!("{}", $solver.full_solution().unwrap()); } debug_assert_eq!(res, $result); }}; From e66152af17eadc7a5fa1e87d1817e8d10f5fa981 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 11 Jun 2024 12:19:36 +0300 Subject: [PATCH 50/56] tests: fix warnings --- rustsat/tests/pb_encodings.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/rustsat/tests/pb_encodings.rs b/rustsat/tests/pb_encodings.rs index a617ea11..58eb10e9 100644 --- a/rustsat/tests/pb_encodings.rs +++ b/rustsat/tests/pb_encodings.rs @@ -477,7 +477,8 @@ mod dpw_inc_prec { } println!("bound: {}", bound); let mut cnf = Cnf::default(); - enc.encode_ub_change(bound..bound + 1, &mut cnf, &mut var_manager); + enc.encode_ub_change(bound..bound + 1, &mut cnf, &mut var_manager) + .unwrap(); println!("extending encoding: {:?}", cnf); solver.add_cnf(cnf).unwrap(); let assumps = enc.enforce_ub(bound).unwrap(); @@ -511,8 +512,8 @@ mod dpw_inc_prec { fn incremental_precision_2() { let inst: OptInstance = OptInstance::from_dimacs_path("./data/inc-sis-fails.wcnf").unwrap(); let (constr, obj) = inst.decompose(); - let (cnf, mut vm) = constr.as_cnf(); - let (hardened, (softs, offset)) = obj.as_soft_lits(&mut vm); + let (cnf, mut vm) = constr.into_cnf(); + let (hardened, (softs, offset)) = obj.into_soft_lits(&mut vm); debug_assert!(hardened.is_empty()); debug_assert_eq!(offset, 0); let mut solver = rustsat_minisat::core::Minisat::default(); @@ -520,7 +521,7 @@ mod dpw_inc_prec { let mut enc = DynamicPolyWatchdog::from_iter(softs); enc.set_precision(8192).unwrap(); - enc.encode_ub_change(0..=1, &mut solver, &mut vm); + enc.encode_ub_change(0..=1, &mut solver, &mut vm).unwrap(); debug_assert_eq!( solver.solve_assumps(&enc.enforce_ub(1).unwrap()).unwrap(), SolverResult::Sat @@ -531,7 +532,7 @@ mod dpw_inc_prec { ); enc.set_precision(1024).unwrap(); - enc.encode_ub_change(0..=9, &mut solver, &mut vm); + enc.encode_ub_change(0..=9, &mut solver, &mut vm).unwrap(); debug_assert_eq!( solver.solve_assumps(&enc.enforce_ub(9).unwrap()).unwrap(), SolverResult::Sat @@ -554,8 +555,8 @@ mod dpw_inc_prec { fn incremental_precision_3() { let inst: OptInstance = OptInstance::from_dimacs_path("./data/inc-sis-fails.wcnf").unwrap(); let (constr, obj) = inst.decompose(); - let (cnf, mut vm) = constr.as_cnf(); - let (hardened, (softs, offset)) = obj.as_soft_lits(&mut vm); + let (cnf, mut vm) = constr.into_cnf(); + let (hardened, (softs, offset)) = obj.into_soft_lits(&mut vm); debug_assert!(hardened.is_empty()); debug_assert_eq!(offset, 0); let mut solver = rustsat_minisat::core::Minisat::default(); @@ -563,7 +564,7 @@ mod dpw_inc_prec { let mut enc = DynamicPolyWatchdog::from_iter(softs); enc.set_precision(2048).unwrap(); - enc.encode_ub_change(0..=4, &mut solver, &mut vm); + enc.encode_ub_change(0..=4, &mut solver, &mut vm).unwrap(); debug_assert_eq!( solver.solve_assumps(&enc.enforce_ub(4).unwrap()).unwrap(), SolverResult::Sat @@ -578,7 +579,7 @@ mod dpw_inc_prec { ); enc.set_precision(1024).unwrap(); - enc.encode_ub_change(0..=9, &mut solver, &mut vm); + enc.encode_ub_change(0..=9, &mut solver, &mut vm).unwrap(); debug_assert_eq!( solver.solve_assumps(&enc.enforce_ub(9).unwrap()).unwrap(), SolverResult::Sat From 042b136ec16670cb66f6a709f0111636221730cd Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Fri, 19 Apr 2024 14:43:33 +0300 Subject: [PATCH 51/56] feat: format vars and lits nicely with debug --- rustsat/src/types.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/rustsat/src/types.rs b/rustsat/src/types.rs index 7421a751..d242a215 100644 --- a/rustsat/src/types.rs +++ b/rustsat/src/types.rs @@ -42,7 +42,7 @@ pub type RsHasher = std::collections::hash_map::DefaultHasher; /// RustSAT starts from 0 and the maximum index is `(u32::MAX - 1) / 2`. This is /// because literals are represented as a single `u32` as well. The memory /// representation of variables is `u32`. -#[derive(Hash, Eq, PartialEq, PartialOrd, Clone, Copy, Ord, Debug)] +#[derive(Hash, Eq, PartialEq, PartialOrd, Clone, Copy, Ord)] #[repr(transparent)] pub struct Var { idx: u32, @@ -212,6 +212,13 @@ impl fmt::Display for Var { } } +/// Variables can be printed with the [`Debug`](std::fmt::Debug) trait +impl fmt::Debug for Var { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "x{}", self.idx) + } +} + /// More easily creates variables. Mainly used in tests. /// /// # Examples @@ -235,7 +242,7 @@ macro_rules! var { /// whether the literal is negated or not. This way the literal can directly /// be used to index data structures with the two literals of a variable /// being close together. -#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Debug)] +#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] #[repr(transparent)] pub struct Lit { lidx: u32, @@ -468,6 +475,16 @@ impl fmt::Display for Lit { } } +/// Literals can be printed with the [`Debug`](std::fmt::Debug) trait +impl fmt::Debug for Lit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.is_neg() { + true => write!(f, "~x{}", self.vidx()), + false => write!(f, "x{}", self.vidx()), + } + } +} + /// More easily creates literals. Mainly used in tests. /// /// # Examples From d65a0e0d154ac4d802a99a3f036c6c518a027591 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Wed, 8 May 2024 17:41:30 +0300 Subject: [PATCH 52/56] doc: improve dpw documentation --- capi/rustsat.h | 14 +++++++++----- capi/src/lib.rs | 14 +++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/capi/rustsat.h b/capi/rustsat.h index 756bf81a..81c99520 100644 --- a/capi/rustsat.h +++ b/capi/rustsat.h @@ -125,12 +125,16 @@ void dpw_drop(struct DynamicPolyWatchdog *dpw); * literals at the moment. * * The min and max bounds are inclusive. After a call to - * [`dpw_encode_ub`] with `min_bound=2` and `max_bound=4` bound - * including `<= 2` and `<= 4` can be enforced. + * [`dpw_encode_ub`] with `min_bound=2` and `max_bound=4`, bounds + * satisfying `2 <= bound <= 4` can be enforced. * - * A call to `var_manager` must yield a new variable. The - * encoding will be returned via the given callback function as - * 0-terminated clauses (in the same way as IPASIR's `add`). + * Clauses are returned via the `collector`. The `collector` function should expect + * clauses to be passed similarly to `ipasir_add`, as a 0-terminated sequence of literals + * where the literals are passed as the first argument and the `collector_data` as a + * second. + * + * `n_vars_used` must be the number of variables already used and will be incremented by + * the number of variables used up in the encoding. * * # Safety * diff --git a/capi/src/lib.rs b/capi/src/lib.rs index 58776936..06aef39e 100644 --- a/capi/src/lib.rs +++ b/capi/src/lib.rs @@ -393,12 +393,16 @@ pub mod encodings { /// literals at the moment. /// /// The min and max bounds are inclusive. After a call to - /// [`dpw_encode_ub`] with `min_bound=2` and `max_bound=4` bound - /// including `<= 2` and `<= 4` can be enforced. + /// [`dpw_encode_ub`] with `min_bound=2` and `max_bound=4`, bounds + /// satisfying `2 <= bound <= 4` can be enforced. /// - /// A call to `var_manager` must yield a new variable. The - /// encoding will be returned via the given callback function as - /// 0-terminated clauses (in the same way as IPASIR's `add`). + /// Clauses are returned via the `collector`. The `collector` function should expect + /// clauses to be passed similarly to `ipasir_add`, as a 0-terminated sequence of literals + /// where the literals are passed as the first argument and the `collector_data` as a + /// second. + /// + /// `n_vars_used` must be the number of variables already used and will be incremented by + /// the number of variables used up in the encoding. /// /// # Safety /// From 954b2968154794b9688d16701ff8944146033c96 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 11 Jun 2024 15:31:34 +0300 Subject: [PATCH 53/56] doc: update contributing guidelines --- .github/pull_request_template.md | 1 + CONTRIBUTING.md | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 109027da..69910c85 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -14,3 +14,4 @@ - [ ] I have added documentation for new features - [ ] The test suite still passes on this PR - [ ] I have added tests for new features / tests that would have caught the bug this PR fixes (please explain if not) +- [ ] If this PR contains breaking changes, it is against the [`next-major`](https://github.com/chrjabs/rustsat/tree/next-major) branch, not against [`main`](https://github.com/chrjabs/rustsat/tree/main) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5709dd7e..c1b95094 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,11 @@ In a possible future publication related to RustSAT, the [contributors on GitHub](https://github.com/chrjabs/rustsat/graphs/contributors) will be acknowledged, but authorship remains with the maintainers of the project. +Pull requests with non-breaking changes should be against the +[`main`](https://github.com/chrjabs/rustsat/tree/main) branch. If the PR +contains breaking changes, it should be against the +[`next-major`](https://github.com/chrjabs/rustsat/tree/next-major) branch. + Before contributing, kindly go through the following checklist: - Format code with `rustfmt` / `cargo fmt --all`. If this is not true, the From 5f734bc44e2740f04879e5e9afaa43f10f1b9cb4 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 11 Jun 2024 16:17:31 +0300 Subject: [PATCH 54/56] fix: make `Node` type opaque the internals of this type were never supposed to be visible without the `internals` feature --- rustsat/src/encodings/card/dbtotalizer.rs | 228 ++++++++++++---------- rustsat/src/encodings/pb/dbgte.rs | 34 ++-- rustsat/src/encodings/pb/dpw.rs | 36 ++-- 3 files changed, 165 insertions(+), 133 deletions(-) diff --git a/rustsat/src/encodings/card/dbtotalizer.rs b/rustsat/src/encodings/card/dbtotalizer.rs index fc5f2917..c800690a 100644 --- a/rustsat/src/encodings/card/dbtotalizer.rs +++ b/rustsat/src/encodings/card/dbtotalizer.rs @@ -121,19 +121,19 @@ impl BoundUpper for DbTotalizer { return Err(Error::NotEncoded); } if let Some(id) = self.root { - match &self.db[id] { - Node::Leaf(lit) => { + match &self.db[id].0 { + INode::Leaf(lit) => { debug_assert_eq!(ub, 0); return Ok(vec![!*lit]); } - Node::Unit(node) => { + INode::Unit(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[ub] { if enc_pos { return Ok(vec![!lit]); } } } - Node::General(_) | Node::Dummy => panic!(), + INode::General(_) | INode::Dummy => panic!(), } } Err(Error::NotEncoded) @@ -211,7 +211,28 @@ impl Extend for DbTotalizer { /// A totalizer adder node #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Node { +#[repr(transparent)] +#[cfg(not(feature = "internals"))] +pub struct Node(pub(in crate::encodings) INode); + +/// A totalizer adder node +/// +/// The internal node [`INode`] representation is only accessible on crate feature `internals`. +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +#[cfg(feature = "internals")] +pub struct Node(pub INode); + +impl From for Node { + fn from(value: INode) -> Self { + Self(value) + } +} + +/// The internal totalizer node type +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "internals", visibility::make(pub))] +pub(in crate::encodings) enum INode { /// An input literal, i.e., a leaf of the tree Leaf(Lit), /// An internal node with unit weight @@ -226,24 +247,24 @@ impl NodeLike for Node { type ValIter = std::iter::Chain, std::vec::IntoIter>; fn is_leaf(&self) -> bool { - matches!(self, Node::Leaf(_)) + matches!(self.0, INode::Leaf(_)) } fn max_val(&self) -> usize { - match self { - Node::Leaf(_) => 1, - Node::Unit(node) => node.lits.len(), - Node::General(node) => node.max_val, - Node::Dummy => 0, + match &self.0 { + INode::Leaf(_) => 1, + INode::Unit(node) => node.lits.len(), + INode::General(node) => node.max_val, + INode::Dummy => 0, } } fn len(&self) -> usize { - match self { - Node::Leaf(_) => 1, - Node::Unit(node) => node.lits.len(), - Node::General(node) => node.lits.len(), - Node::Dummy => 0, + match &self.0 { + INode::Leaf(_) => 1, + INode::Unit(node) => node.lits.len(), + INode::General(node) => node.lits.len(), + INode::Dummy => 0, } } @@ -251,14 +272,14 @@ impl NodeLike for Node { where R: RangeBounds, { - match self { - Node::Leaf(_) => { + match &self.0 { + INode::Leaf(_) => { if range.contains(&1) { return (1..2).chain(vec![]); } (0..0).chain(vec![]) } - Node::Unit(node) => { + INode::Unit(node) => { let lb = match range.start_bound() { Bound::Included(b) => cmp::max(*b, 1), Bound::Excluded(b) => b + 1, @@ -271,35 +292,35 @@ impl NodeLike for Node { }; (lb..ub).chain(vec![]) } - Node::General(node) => { + INode::General(node) => { let vals: Vec<_> = node.lits.range(range).map(|(val, _)| *val).collect(); (0..0).chain(vals) } - Node::Dummy => (0..0).chain(vec![]), + INode::Dummy => (0..0).chain(vec![]), } } fn right(&self) -> Option { - match self { - Node::Leaf(..) | Node::Dummy => None, - Node::Unit(node) => Some(node.right), - Node::General(node) => Some(node.right), + match &self.0 { + INode::Leaf(..) | INode::Dummy => None, + INode::Unit(node) => Some(node.right), + INode::General(node) => Some(node.right), } } fn left(&self) -> Option { - match self { - Node::Leaf(..) | Node::Dummy => None, - Node::Unit(node) => Some(node.left), - Node::General(node) => Some(node.left), + match &self.0 { + INode::Leaf(..) | INode::Dummy => None, + INode::Unit(node) => Some(node.left), + INode::General(node) => Some(node.left), } } fn depth(&self) -> usize { - match self { - Node::Leaf(..) | Node::Dummy => 1, - Node::Unit(node) => node.depth, - Node::General(node) => node.depth, + match &self.0 { + INode::Leaf(..) | INode::Dummy => 1, + INode::Unit(node) => node.depth, + INode::General(node) => node.depth, } } @@ -308,8 +329,8 @@ impl NodeLike for Node { Db: NodeById, { let general = left.multiplier != right.multiplier - || matches!(&db[left.id], Node::General(_)) - || matches!(&db[right.id], Node::General(_)); + || matches!(&db[left.id].0, INode::General(_)) + || matches!(&db[right.id].0, INode::General(_)); if general { let lvals: Vec<_> = db[left.id] .vals(left.offset()..) @@ -319,80 +340,82 @@ impl NodeLike for Node { .vals(right.offset()..) .map(|val| right.map(val)) .collect(); - return Self::General(GeneralNode::new( + return INode::General(GeneralNode::new( &lvals, &rvals, std::cmp::max(db[left.id].depth(), db[right.id].depth()) + 1, left, right, - )); + )) + .into(); } // if both inputs have the same weight, the multiplier should be 1 debug_assert!(left.multiplier() == 1 && right.multiplier() == 1); - Self::Unit(UnitNode::new( + INode::Unit(UnitNode::new( db.con_len(left) + db.con_len(right), std::cmp::max(db[left.id].depth(), db[right.id].depth()) + 1, left, right, )) + .into() } fn leaf(lit: Lit) -> Self { - Self::Leaf(lit) + INode::Leaf(lit).into() } } impl Node { /// Panic-safe version of literal indexing pub fn lit(&self, val: usize) -> Option<&Lit> { - match self { - Node::Leaf(lit, ..) => { + match &self.0 { + INode::Leaf(lit, ..) => { if val != 1 { return None; } Some(lit) } - Node::Unit(node) => node.lit(val), - Node::General(node) => node.lit(val), - Node::Dummy => None, + INode::Unit(node) => node.lit(val), + INode::General(node) => node.lit(val), + INode::Dummy => None, } } /// Checks if a given output value is positively encoded pub fn encoded_pos(&self, val: usize) -> bool { - match self { - Node::Leaf(..) => { + match &self.0 { + INode::Leaf(..) => { if val != 1 { return false; } true } - Node::Unit(node) => node.encoded_pos(val), - Node::General(node) => node.encoded_pos(val), - Node::Dummy => true, + INode::Unit(node) => node.encoded_pos(val), + INode::General(node) => node.encoded_pos(val), + INode::Dummy => true, } } /// Returns the internal node and panics if the node is not a unit pub(crate) fn unit(&self) -> &UnitNode { - match self { - Node::Unit(node) => node, + match &self.0 { + INode::Unit(node) => node, _ => panic!("called `unit` on non-unit node"), } } /// Returns the internal node and panics if the node is not a unit pub(crate) fn mut_unit(&mut self) -> &mut UnitNode { - match self { - Node::Unit(node) => node, + match &mut self.0 { + INode::Unit(node) => node, _ => panic!("called `unit` on non-unit node"), } } /// Returns the internal node and panics if the node is not general pub(crate) fn mut_general(&mut self) -> &mut GeneralNode { - match self { - Node::General(node) => node, + match &mut self.0 { + INode::General(node) => node, _ => panic!("called `unit` on non-general node"), } } @@ -401,10 +424,10 @@ impl Node { /// nodes references a nodes within the drained range, it returns that /// [`NodeId`] as an Error. fn drain(&mut self, range: Range) -> Result<(), NodeId> { - match self { - Node::Leaf(_) | Node::Dummy => Ok(()), - Node::Unit(UnitNode { left, right, .. }) - | Node::General(GeneralNode { left, right, .. }) => { + match &mut self.0 { + INode::Leaf(_) | INode::Dummy => Ok(()), + INode::Unit(UnitNode { left, right, .. }) + | INode::General(GeneralNode { left, right, .. }) => { if range.contains(&left.id) { return Err(left.id); } @@ -581,14 +604,14 @@ impl NodeById for TotDb { type Node = Node; fn insert(&mut self, node: Self::Node) -> NodeId { - match node { - Node::Leaf(lit) => { + match node.0 { + INode::Leaf(lit) => { if let Some(&id) = self.lookup_leaf.get(&lit) { return id; } self.lookup_leaf.insert(lit, NodeId(self.nodes.len())); } - Node::Dummy => { + INode::Dummy => { if let Some(id) = self.dummy_id { return id; } @@ -674,15 +697,15 @@ impl TotDb { { debug_assert!(val <= self[id].max_val()); debug_assert!(val > 0); - match &self[id] { - Node::Leaf(lit) => { + match &self[id].0 { + INode::Leaf(lit) => { debug_assert_eq!(val, 1); if val != 1 { return Ok(None); } Ok(Some(*lit)) } - Node::Unit(node) => { + INode::Unit(node) => { if val > node.lits.len() || val == 0 { return Ok(None); } @@ -701,7 +724,7 @@ impl TotDb { var_manager, )?)) } - Node::General(node) => { + INode::General(node) => { // Check if already encoded if let Some(lit_data) = node.lits.get(&val) { if let LitData::Lit { @@ -778,7 +801,7 @@ impl TotDb { Ok(Some(olit)) } - Node::Dummy => Ok(None), + INode::Dummy => Ok(None), } } @@ -805,12 +828,12 @@ impl TotDb { let lcon = node.left().unwrap(); let rcon = node.right().unwrap(); debug_assert!(matches!( - self[rcon.id], - Node::Leaf(_) | Node::Unit(_) | Node::Dummy + self[rcon.id].0, + INode::Leaf(_) | INode::Unit(_) | INode::Dummy )); debug_assert!(matches!( - self[lcon.id], - Node::Leaf(_) | Node::Unit(_) | Node::Dummy + self[lcon.id].0, + INode::Leaf(_) | INode::Unit(_) | INode::Dummy )); debug_assert_eq!(lcon.multiplier(), 1); debug_assert_eq!(rcon.multiplier(), 1); @@ -826,13 +849,16 @@ impl TotDb { let con_idx = |idx: usize, con: NodeCon| con.rev_map(idx + 1) - 1; // treat dummy nodes by passing through other connection - if matches!(self[lcon.id], Node::Dummy) || matches!(self[rcon.id], Node::Dummy) { - let realcon = if matches!(self[lcon.id], Node::Dummy) { + if matches!(self[lcon.id].0, INode::Dummy) || matches!(self[rcon.id].0, INode::Dummy) { + let realcon = if matches!(self[lcon.id].0, INode::Dummy) { &rcon } else { &lcon }; - debug_assert!(matches!(self[realcon.id], Node::Leaf(_) | Node::Unit(_))); + debug_assert!(matches!( + self[realcon.id].0, + INode::Leaf(_) | INode::Unit(_) + )); let ilit = self.define_pos_tot(realcon.id, con_idx(idx, *realcon), collector, var_manager)?; // Reserve variable for this node, if needed @@ -888,21 +914,21 @@ impl TotDb { // Get reference to literals of children let tmp_olit_l; - let llits = match &self[lcon.id] { - Node::Leaf(lit) => { + let llits = match &self[lcon.id].0 { + INode::Leaf(lit) => { tmp_olit_l = LitData::new_lit(*lit); std::slice::from_ref(&tmp_olit_l) } - Node::Unit(UnitNode { lits, .. }) => lits, + INode::Unit(UnitNode { lits, .. }) => lits, _ => panic!(), }; let tmp_olit_r; - let rlits = match &self[rcon.id] { - Node::Leaf(lit) => { + let rlits = match &self[rcon.id].0 { + INode::Leaf(lit) => { tmp_olit_r = LitData::new_lit(*lit); std::slice::from_ref(&tmp_olit_r) } - Node::Unit(UnitNode { lits, .. }) => lits, + INode::Unit(UnitNode { lits, .. }) => lits, _ => panic!(), }; @@ -948,44 +974,44 @@ impl TotDb { self.reserve_vars(self[id].left().unwrap().id, var_manager); self.reserve_vars(self[id].right().unwrap().id, var_manager); - match &mut self[id] { - Node::Unit(UnitNode { lits, .. }) => { + match &mut self[id].0 { + INode::Unit(UnitNode { lits, .. }) => { for olit in lits { if let LitData::None = olit { *olit = LitData::new_lit(var_manager.new_var().pos_lit()) } } } - Node::General(GeneralNode { lits, .. }) => { + INode::General(GeneralNode { lits, .. }) => { for (_, olit) in lits.iter_mut() { if let LitData::None = olit { *olit = LitData::new_lit(var_manager.new_var().pos_lit()) } } } - Node::Leaf(_) | Node::Dummy => panic!(), + INode::Leaf(_) | INode::Dummy => panic!(), } } /// Resets the status of what has already been encoded pub fn reset_encoded(&mut self) { for node in &mut self.nodes { - match node { - Node::Unit(UnitNode { lits, .. }) => { + match &mut node.0 { + INode::Unit(UnitNode { lits, .. }) => { for lit in lits { if let LitData::Lit { enc_pos, .. } = lit { *enc_pos = false } } } - Node::General(GeneralNode { lits, .. }) => { + INode::General(GeneralNode { lits, .. }) => { for lit in lits.values_mut() { if let LitData::Lit { enc_pos, .. } = lit { *enc_pos = false } } } - Node::Leaf(_) | Node::Dummy => (), + INode::Leaf(_) | INode::Dummy => (), } } } @@ -995,14 +1021,14 @@ impl TotDb { #[cfg(feature = "internals")] pub fn reset_vars(&mut self) { for node in &mut self.nodes { - match node { - Node::Leaf(_) | Node::Dummy => (), - Node::Unit(UnitNode { lits, .. }) => { + match &mut node.0 { + INode::Leaf(_) | INode::Dummy => (), + INode::Unit(UnitNode { lits, .. }) => { for lit in lits { *lit = LitData::None; } } - Node::General(GeneralNode { lits, .. }) => { + INode::General(GeneralNode { lits, .. }) => { for lit in lits.values_mut() { *lit = LitData::None; } @@ -1027,7 +1053,7 @@ pub mod referenced { types::Lit, }; - use super::{LitData, Node, TotDb}; + use super::{INode, LitData, TotDb}; /// Implementation of the binary adder tree totalizer encoding \[1\]. /// The implementation is incremental as extended in \[2\]. @@ -1126,19 +1152,19 @@ pub mod referenced { if ub >= self.n_lits() { return Ok(vec![]); } - match &self.db[self.root] { - Node::Leaf(lit) => { + match &self.db[self.root].0 { + INode::Leaf(lit) => { debug_assert_eq!(ub, 0); return Ok(vec![!*lit]); } - Node::Unit(node) => { + INode::Unit(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[ub] { if enc_pos { return Ok(vec![!lit]); } } } - Node::General(_) | Node::Dummy => panic!(), + INode::General(_) | INode::Dummy => panic!(), } Err(Error::NotEncoded) } @@ -1163,19 +1189,19 @@ pub mod referenced { if ub >= self.n_lits() { return Ok(vec![]); } - match &self.db.borrow()[self.root] { - Node::Leaf(lit) => { + match &self.db.borrow()[self.root].0 { + INode::Leaf(lit) => { debug_assert_eq!(ub, 0); return Ok(vec![!*lit]); } - Node::Unit(node) => { + INode::Unit(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[ub] { if enc_pos { return Ok(vec![!lit]); } } } - Node::General(_) | Node::Dummy => panic!(), + INode::General(_) | INode::Dummy => panic!(), } Err(Error::NotEncoded) } diff --git a/rustsat/src/encodings/pb/dbgte.rs b/rustsat/src/encodings/pb/dbgte.rs index a8efa73a..752e8695 100644 --- a/rustsat/src/encodings/pb/dbgte.rs +++ b/rustsat/src/encodings/pb/dbgte.rs @@ -7,7 +7,7 @@ use std::ops::RangeBounds; use crate::{ encodings::{ - card::dbtotalizer::{LitData, Node, TotDb}, + card::dbtotalizer::{INode, LitData, TotDb}, nodedb::{NodeById, NodeCon, NodeLike}, CollectClauses, EncodeStats, Error, }, @@ -191,12 +191,12 @@ impl BoundUpper for DbGte { self.db[con.id] .vals(con.rev_map_round_up(ub + 1)..=con.rev_map(ub + self.max_leaf_weight)) .try_for_each(|val| { - match &self.db[con.id] { - Node::Leaf(lit) => { + match &self.db[con.id].0 { + INode::Leaf(lit) => { assumps.push(!*lit); return Ok(()); } - Node::Unit(node) => { + INode::Unit(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[val - 1] { if enc_pos { assumps.push(!lit); @@ -204,7 +204,7 @@ impl BoundUpper for DbGte { } } } - Node::General(node) => { + INode::General(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[&val] { if enc_pos { assumps.push(!lit); @@ -212,7 +212,7 @@ impl BoundUpper for DbGte { } } } - Node::Dummy => panic!(), + INode::Dummy => panic!(), } Err(Error::NotEncoded) })? @@ -305,7 +305,7 @@ pub mod referenced { use crate::{ encodings::{ - card::dbtotalizer::{LitData, Node, TotDb}, + card::dbtotalizer::{INode, LitData, TotDb}, nodedb::{NodeCon, NodeLike}, pb::{BoundUpper, BoundUpperIncremental, Encode, EncodeIncremental}, CollectClauses, Error, @@ -466,12 +466,12 @@ pub mod referenced { ..=self.root.rev_map(ub + self.max_leaf_weight), ) .try_for_each(|val| { - match &self.db[self.root.id] { - Node::Leaf(lit) => { + match &self.db[self.root.id].0 { + INode::Leaf(lit) => { assumps.push(!*lit); return Ok(()); } - Node::Unit(node) => { + INode::Unit(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[val - 1] { if enc_pos { assumps.push(!lit); @@ -479,7 +479,7 @@ pub mod referenced { } } } - Node::General(node) => { + INode::General(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[&val] { if enc_pos { assumps.push(!lit); @@ -487,7 +487,7 @@ pub mod referenced { } } } - Node::Dummy => panic!(), + INode::Dummy => panic!(), } Err(Error::NotEncoded) })?; @@ -523,12 +523,12 @@ pub mod referenced { ..=self.root.rev_map(ub + self.max_leaf_weight), ) .try_for_each(|val| { - match &self.db.borrow()[self.root.id] { - Node::Leaf(lit) => { + match &self.db.borrow()[self.root.id].0 { + INode::Leaf(lit) => { assumps.push(!*lit); return Ok(()); } - Node::Unit(node) => { + INode::Unit(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[val - 1] { if enc_pos { assumps.push(!lit); @@ -536,7 +536,7 @@ pub mod referenced { } } } - Node::General(node) => { + INode::General(node) => { if let LitData::Lit { lit, enc_pos } = node.lits[&val] { if enc_pos { assumps.push(!lit); @@ -544,7 +544,7 @@ pub mod referenced { } } } - Node::Dummy => panic!(), + INode::Dummy => panic!(), } Err(Error::NotEncoded) })?; diff --git a/rustsat/src/encodings/pb/dpw.rs b/rustsat/src/encodings/pb/dpw.rs index 9c9b368b..525fc443 100644 --- a/rustsat/src/encodings/pb/dpw.rs +++ b/rustsat/src/encodings/pb/dpw.rs @@ -24,7 +24,7 @@ use crate::{ clause, encodings::{ atomics, - card::dbtotalizer::{GeneralNode, LitData, Node, TotDb, UnitNode}, + card::dbtotalizer::{GeneralNode, INode, LitData, Node, TotDb, UnitNode}, nodedb::{NodeById, NodeCon, NodeId, NodeLike}, CollectClauses, EncodeStats, Error, IterWeightedInputs, }, @@ -105,7 +105,7 @@ impl DynamicPolyWatchdog { self.in_lits.insert(lit, weight); } self.weight_sum += weight; - let node = self.db.insert(Node::Leaf(lit)); + let node = self.db.insert(Node::leaf(lit)); let con = NodeCon::full(node); if let Some(cons) = self.weight_queue.get_mut(&weight) { cons.push(con); @@ -633,7 +633,7 @@ type DpwIter<'a> = std::iter::Map< #[cfg_attr(feature = "internals", visibility::make(pub))] fn lit_weight_queue>(lits: LI, tot_db: &mut TotDb) -> WeightQ { let lit_to_con = |(lit, weight)| { - let node = tot_db.insert(Node::Leaf(lit)); + let node = tot_db.insert(Node::leaf(lit)); NodeCon::weighted(node, weight) }; con_weight_queue(lits.map(lit_to_con)) @@ -733,7 +733,7 @@ fn build_structure( let has_tare = if !topmost || idx != basis_len - skipped_levels - 1 { // Merge top bucket (except for last) with tare let tare = structure.tares[idx]; - cons.push(NodeCon::full(tot_db.insert(Node::Leaf(tare)))); + cons.push(NodeCon::full(tot_db.insert(Node::leaf(tare)))); true } else { false @@ -754,7 +754,7 @@ fn build_structure( bb_offset = top_bucket.offset; } else { // last bottom bucket for this segment, leave dummy node to path in extension - let dummy = tot_db.insert(Node::Dummy); + let dummy = tot_db.insert(INode::Dummy.into()); let right = NodeCon::full(dummy); let bottom = tot_db.insert(Node::internal(top_bucket, right, tot_db)); bottom_buckets.push(bottom); @@ -824,15 +824,18 @@ where .iter() .rev() { - let dummy = tot_db.insert(Node::Dummy); + let dummy = tot_db.insert(INode::Dummy.into()); let right = NodeCon::full(dummy); - let tare_node = tot_db.insert(Node::Leaf(tare)); + let tare_node = tot_db.insert(Node::leaf(tare)); let new_bottom = tot_db.insert(Node::internal(NodeCon::full(tare_node), right, tot_db)); let last_bottom = *bot_struct.bottom_buckets.last().unwrap(); - debug_assert_eq!(tot_db[tot_db[last_bottom].right().unwrap().id], Node::Dummy); - match &mut tot_db[last_bottom] { - Node::Leaf(_) | Node::Dummy => unreachable!(), - Node::Unit(UnitNode { right, .. }) | Node::General(GeneralNode { right, .. }) => { + debug_assert_eq!( + tot_db[tot_db[last_bottom].right().unwrap().id].0, + INode::Dummy + ); + match &mut tot_db[last_bottom].0 { + INode::Leaf(_) | INode::Dummy => unreachable!(), + INode::Unit(UnitNode { right, .. }) | INode::General(GeneralNode { right, .. }) => { *right = NodeCon { id: new_bottom, offset: 0, @@ -850,10 +853,13 @@ where ); // step 3: patch together structures let last_bottom = *bot_struct.bottom_buckets.last().unwrap(); - debug_assert_eq!(tot_db[tot_db[last_bottom].right().unwrap().id], Node::Dummy); - match &mut tot_db[last_bottom] { - Node::Leaf(_) | Node::Dummy => panic!(), - Node::Unit(UnitNode { right, .. }) | Node::General(GeneralNode { right, .. }) => { + debug_assert_eq!( + tot_db[tot_db[last_bottom].right().unwrap().id].0, + INode::Dummy + ); + match &mut tot_db[last_bottom].0 { + INode::Leaf(_) | INode::Dummy => panic!(), + INode::Unit(UnitNode { right, .. }) | INode::General(GeneralNode { right, .. }) => { *right = NodeCon { id: *top_struct.bottom_buckets.first().unwrap(), offset: 0, From 07a4197ca11fc49439304dc0cb9840fcdf6bbe92 Mon Sep 17 00:00:00 2001 From: Christoph Jabs Date: Tue, 11 Jun 2024 16:26:02 +0300 Subject: [PATCH 55/56] ci: add semver checks --- .github/workflows/cadical.yml | 1 - .github/workflows/kissat.yml | 1 - .github/workflows/semver-checks.yml | 45 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/semver-checks.yml diff --git a/.github/workflows/cadical.yml b/.github/workflows/cadical.yml index d8afed51..7bace07e 100644 --- a/.github/workflows/cadical.yml +++ b/.github/workflows/cadical.yml @@ -32,4 +32,3 @@ jobs: run: cargo test -p rustsat-cadical --verbose env: CMAKE_BUILD_PARALLEL_LEVEL: ${{ fromJSON('["", "4"]')[matrix.os == 'macos-latest'] }} - diff --git a/.github/workflows/kissat.yml b/.github/workflows/kissat.yml index 8e0b14c5..7e95c1de 100644 --- a/.github/workflows/kissat.yml +++ b/.github/workflows/kissat.yml @@ -32,4 +32,3 @@ jobs: run: cargo test -p rustsat-kissat --verbose env: CMAKE_BUILD_PARALLEL_LEVEL: ${{ fromJSON('["", "4"]')[matrix.os == 'macos-latest'] }} - diff --git a/.github/workflows/semver-checks.yml b/.github/workflows/semver-checks.yml new file mode 100644 index 00000000..4c9b2b0c --- /dev/null +++ b/.github/workflows/semver-checks.yml @@ -0,0 +1,45 @@ +name: Semver checks + +on: + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + rustsat: + name: Semver checks + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + with: + submodules: "recursive" + - name: RustSAT + uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: rustsat + feature-group: only-explicit-features + features: all + - name: CaDiCaL + uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: rustsat-cadical + feature-group: default-features + - name: Minisat + uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: rustsat-minisat + - name: Glucose + uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: rustsat-glucose + - name: Kissat + uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: rustsat-kissat + - name: IPASIR + uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: rustsat-ipasir From ff1a3d6fea12e8d16aa97678c72b91f39eabe7bf Mon Sep 17 00:00:00 2001 From: Christoph Jabs <98587286+chrjabs@users.noreply.github.com> Date: Tue, 11 Jun 2024 19:27:11 +0300 Subject: [PATCH 56/56] chore: release --- CHANGELOG.md | 20 ++++++++++++++++++++ cadical/CHANGELOG.md | 7 +++++++ cadical/Cargo.toml | 4 ++-- capi/CHANGELOG.md | 4 ++++ capi/Cargo.toml | 4 ++-- glucose/CHANGELOG.md | 7 +++++++ glucose/Cargo.toml | 4 ++-- ipasir/CHANGELOG.md | 7 +++++++ ipasir/Cargo.toml | 4 ++-- kissat/CHANGELOG.md | 7 +++++++ kissat/Cargo.toml | 4 ++-- minisat/CHANGELOG.md | 7 +++++++ minisat/Cargo.toml | 4 ++-- pyapi/CHANGELOG.md | 6 ++++++ pyapi/Cargo.toml | 4 ++-- rustsat/Cargo.toml | 2 +- solvertests/Cargo.toml | 2 +- tools/CHANGELOG.md | 7 +++++++ tools/Cargo.toml | 8 ++++---- 19 files changed, 92 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a876d106..e10dbcf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ All notable changes to this project will be documented in this file. +## [0.5.1] - 2024-06-12 + +### Features + +- Incremental precision in DPW +- Format vars and lits nicely with debug + +### Bug Fixes + +- Make `Node` type (of `dbtotalizer`) opaque. This is technically a breaking + change, but since the `Node` type was never intended to be transparent, we are + _not_ treating it as one. If you are relying on having access to the `Node` + type, use the feature `internal` instead, but note that the internal API is + unstable. + +### Testing + +- Fix warnings + + ## [0.5.0] - 2024-04-30 This release contains breaking changes. For detailed instructions on how to diff --git a/cadical/CHANGELOG.md b/cadical/CHANGELOG.md index 813ad61b..34779c32 100644 --- a/cadical/CHANGELOG.md +++ b/cadical/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [0.3.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + ## [0.3.0] - 2024-04-30 The corresponding RustSAT release contains breaking changes. For detailed diff --git a/cadical/Cargo.toml b/cadical/Cargo.toml index 977786ec..17438912 100644 --- a/cadical/Cargo.toml +++ b/cadical/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-cadical" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -41,7 +41,7 @@ v1-9-5 = [] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/capi/CHANGELOG.md b/capi/CHANGELOG.md index 75c5ebfc..2a07ca66 100644 --- a/capi/CHANGELOG.md +++ b/capi/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [0.5.1] - 2024-06-12 + +Incrementally adjustable precision for DPW encoding. + ## [0.5.0] - 2024-04-30 Factor C-API out into its own crate. diff --git a/capi/Cargo.toml b/capi/Cargo.toml index ca67ef73..97b40b0e 100644 --- a/capi/Cargo.toml +++ b/capi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-capi" -version = "0.5.0" +version = "0.5.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -12,7 +12,7 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false, features = [ +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false, features = [ "internals", ] } diff --git a/glucose/CHANGELOG.md b/glucose/CHANGELOG.md index 7651918a..cc515ee6 100644 --- a/glucose/CHANGELOG.md +++ b/glucose/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [0.3.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + ## [0.3.0] - 2024-04-30 The corresponding RustSAT release contains breaking changes. For detailed diff --git a/glucose/Cargo.toml b/glucose/Cargo.toml index 0c5273ba..cfc729f4 100644 --- a/glucose/Cargo.toml +++ b/glucose/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-glucose" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -20,7 +20,7 @@ default = ["quiet"] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/ipasir/CHANGELOG.md b/ipasir/CHANGELOG.md index 65da3c5d..1a8cc61d 100644 --- a/ipasir/CHANGELOG.md +++ b/ipasir/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [0.1.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + ## [0.1.0] - 2024-04-30 Factor IPASIR API out from RustSAT into its own crate. diff --git a/ipasir/Cargo.toml b/ipasir/Cargo.toml index b77f3d5b..4f74ce9c 100644 --- a/ipasir/Cargo.toml +++ b/ipasir/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-ipasir" -version = "0.1.0" +version = "0.1.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -13,6 +13,6 @@ readme = "README.md" [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/kissat/CHANGELOG.md b/kissat/CHANGELOG.md index 13bf508f..d26fe36c 100644 --- a/kissat/CHANGELOG.md +++ b/kissat/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [0.2.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + ## [0.2.0] - 2024-04-30 The corresponding RustSAT release contains breaking changes. For detailed diff --git a/kissat/Cargo.toml b/kissat/Cargo.toml index 32491090..f1d123cc 100644 --- a/kissat/Cargo.toml +++ b/kissat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-kissat" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -26,7 +26,7 @@ sc2022-bulky = [] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/minisat/CHANGELOG.md b/minisat/CHANGELOG.md index 224993d1..82703e48 100644 --- a/minisat/CHANGELOG.md +++ b/minisat/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [0.3.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + ## [0.3.0] - 2024-04-30 The corresponding RustSAT release contains breaking changes. For detailed diff --git a/minisat/Cargo.toml b/minisat/Cargo.toml index ce2d0076..9fa5dfe5 100644 --- a/minisat/Cargo.toml +++ b/minisat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-minisat" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -20,7 +20,7 @@ default = ["quiet"] [dependencies] cpu-time = "1.0.0" -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false } thiserror = { version = "1.0.57" } anyhow = { version = "1.0.80" } diff --git a/pyapi/CHANGELOG.md b/pyapi/CHANGELOG.md index b053d745..ff27a673 100644 --- a/pyapi/CHANGELOG.md +++ b/pyapi/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [0.5.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + ## [0.5.0] - 2024-04-30 Factor Python API out into its own crate. diff --git a/pyapi/Cargo.toml b/pyapi/Cargo.toml index e4afd7d3..293aa974 100644 --- a/pyapi/Cargo.toml +++ b/pyapi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-pyapi" -version = "0.5.0" +version = "0.5.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -14,7 +14,7 @@ build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false } pyo3 = { version = "0.21.1", features = [ "extension-module", "abi3", diff --git a/rustsat/Cargo.toml b/rustsat/Cargo.toml index e1ca6679..d9c82ff5 100644 --- a/rustsat/Cargo.toml +++ b/rustsat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat" -version = "0.5.0" +version = "0.5.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" diff --git a/solvertests/Cargo.toml b/solvertests/Cargo.toml index 0f66ddb1..910e2092 100644 --- a/solvertests/Cargo.toml +++ b/solvertests/Cargo.toml @@ -12,5 +12,5 @@ proc-macro = true [dependencies] syn = "2.0" quote = "1.0" -rustsat = { version = "0.5.0", path = "../rustsat", default-features = false } +rustsat = { version = "0.5.1", path = "../rustsat", default-features = false } proc-macro2 = "1.0" diff --git a/tools/CHANGELOG.md b/tools/CHANGELOG.md index 415f493b..be2ae042 100644 --- a/tools/CHANGELOG.md +++ b/tools/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [0.3.1] - 2024-06-12 + +### Miscellaneous Tasks + +- Updated the following local packages: rustsat + + ## [0.3.0] - 2024-04-29 The corresponding RustSAT release contains breaking changes. For detailed diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 275784ca..cc863af2 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustsat-tools" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Christoph Jabs "] license = "MIT" @@ -12,14 +12,14 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustsat = { version = "0.5.0", path = "../rustsat", features = [ +rustsat = { version = "0.5.1", path = "../rustsat", features = [ "compression", "multiopt", "rand", "internals", ] } -rustsat-cadical = { version = "0.3.0", path = "../cadical", optional = true } -rustsat-minisat = { version = "0.3.0", path = "../minisat", optional = true } +rustsat-cadical = { version = "0.3.1", path = "../cadical", optional = true } +rustsat-minisat = { version = "0.3.1", path = "../minisat", optional = true } clap = { version = "4.2.4", features = ["derive", "cargo"] } concolor-clap = { version = "0.1.0" } termcolor = { version = "1.2.0" }