diff --git a/Cargo.toml b/Cargo.toml index e1d9ec6..2cd6f38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,11 @@ tracing-subscriber = { version = "^0.2" } anyhow = { version = "^1.0.0", features = ["backtrace"] } thiserror = { version = "^1.0.0" } pretty_assertions = { version = "^1.3.0" } +serde_json = { version = "^1.0" } +serde = { version = "^1.0", features = ["derive"] } + +[dev-dependencies] +tempfile = "3" [[bin]] name = "nmlcc" diff --git a/dat/CMakeLists.txt b/dat/CMakeLists.txt new file mode 100644 index 0000000..fdc10d2 --- /dev/null +++ b/dat/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.22) +project(arbor-nmlcc LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 17) + +find_package(arbor REQUIRED) +find_package(nlohmann_json 3.11.0 REQUIRED) + +add_executable(main main.cxx) +target_link_libraries(main PUBLIC arbor::arbor arbor::arborio arbor::arborenv nlohmann_json::nlohmann_json) diff --git a/dat/main.cxx b/dat/main.cxx new file mode 100644 index 0000000..691c873 --- /dev/null +++ b/dat/main.cxx @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +using json = nlohmann::json; + +arb::mechanism_catalogue compile(const std::filesystem::path& here) { + auto fn = here / \"local-catalogue.so\"; + return arb::load_catalogue(fn); +} + +std::string read_file(const std::filesystem::path& fn) { + auto fd = std::ifstream{fn}; + return std::string(std::istreambuf_iterator{fd}, {}); +} + + +arb::locset on_segment(size_t seg, const std::string& frac) { + return arb::ls::on_components(std::stod(frac), arb::reg::named(std::to_string(seg))); +}; + +std::string mk_label(const std::string& pfx, size_t seg, const std::string& frac) { + return pfx + \"@seg_\" + std::to_string(seg) + \"_frac_\" + frac; +} + +arb::cell_local_label_type mk_lid(const std::string& l) { + return {l, arb::lid_selection_policy::round_robin}; +} + +arb::cell_global_label_type mk_gid(arb::cell_gid_type c, const std::string& l) { + return {c, {l, arb::lid_selection_policy::round_robin}}; +} + +struct recipe: public arb::recipe { + + recipe(const std::filesystem::path& cwd, const std::string& network): here{cwd} { + auto cat = compile(here); + gprop.default_parameters = arb::neuron_parameter_defaults; + gprop.catalogue.import(cat, prefix); + + std::ifstream fd{(here / \"dat\" / network).replace_extension(\"json\")}; + auto data = json::parse(fd); + + gid_to_cell = data[\"gid_to_cell\"]; + cell_to_morph = data[\"cell_to_morph\"]; + i_clamps = data[\"i_clamps\"]; + poisson_generators = data[\"poisson_generators\"]; + regular_generators = data[\"regular_generators\"]; + for (const auto& [k, v]: data[\"gid_to_inputs\"].items()) gid_to_inputs[std::stoi(k)] = v; + for (const auto& [k, v]: data[\"gid_to_synapses\"].items()) gid_to_synapses[std::stoi(k)] = v; + for (const auto& [k, v]: data[\"gid_to_detectors\"].items()) gid_to_detectors[std::stoi(k)] = v; + for (const auto& [k, v]: data[\"gid_to_connections\"].items()) gid_to_connections[std::stoi(k)] = v; + count = data[\"count\"]; + } + + std::any get_global_properties(arb::cell_kind) const override { return gprop; } + arb::cell_size_type num_cells() const override { return count; } + std::vector get_probes(arb::cell_gid_type gid) const override { return {arb::cable_probe_membrane_voltage{arb::ls::location(0, 0.5)}}; } + + arb::util::unique_any get_cell_description(arb::cell_gid_type gid) const override { + const auto& cid = gid_to_cell.at(gid); + const auto& mid = cell_to_morph.at(cid); + + auto mrf = read_file((here / \"mrf\" / mid).replace_extension(\"nml\")); + auto acc = read_file((here / \"acc\" / cid).replace_extension(\"acc\")); + + auto nml = arborio::neuroml{mrf}; + auto morph = nml.morphology(mid, arborio::neuroml_options::allow_spherical_root); + + auto label = arb::label_dict{}; + label.set(\"all\", arb::reg::all()); + label.import(morph->segments); + label.import(morph->named_segments); + label.import(morph->groups); + + auto decor = std::get(arborio::parse_component(acc)->component); + + if (gid_to_inputs.count(gid)) { + for (const auto& [seg, frac, inp]: gid_to_inputs.at(gid)) { + if (i_clamps.count(inp)) { + auto tag = on_segment(seg, frac); + auto lbl = mk_label(\"ic_\" + inp, seg, frac); + const auto& [lag, dur, amp] = i_clamps.at(inp); + decor.place(tag, arb::i_clamp{lag, dur, amp}, lbl); + } + } + } + + if (gid_to_synapses.count(gid)) { + for (const auto& [seg, frac, syn]: gid_to_synapses.at(gid)) { + auto tag = on_segment(seg, frac); + auto lbl = mk_label(\"syn_\" + syn, seg, frac); + decor.place(tag, arb::synapse{prefix + syn}, lbl); + } + } + + if (gid_to_detectors.count(gid)) { + for (const auto& [seg, frac, thr]: gid_to_detectors.at(gid)) { + auto tag = on_segment(seg, frac); + auto lbl = mk_label(\"sd\", seg, frac); + decor.place(tag, arb::threshold_detector{thr}, lbl); + } + } + + return arb::cable_cell{morph->morphology, decor, label}; + } + + arb::cell_kind get_cell_kind(arb::cell_gid_type) const override { return arb::cell_kind::cable; } + + std::vector connections_on(arb::cell_gid_type gid) const override { + std::vector res; + if (gid_to_connections.count(gid)) { + for (const auto& [src, dec, syn, loc, wgt, del]: gid_to_connections.at(gid)) { + auto from = mk_gid(src, \"sd@\" + dec); + auto delay = std::max(min_delay, del); + auto to = mk_lid(\"syn_\" + syn + \"@\" + loc); + res.emplace_back(from, to, wgt, delay); + } + } + return res; + } + + std::vector event_generators(arb::cell_gid_type gid) const override { + std::vector res; + if (gid_to_inputs.count(gid)) { + for (const auto& [seg, frac, inp]: gid_to_inputs.at(gid)) { + if (poisson_generators.count(inp)) { + const auto& [syn, avg, wgt] = poisson_generators.at(inp); + auto tgt = mk_label(\"syn_\" + syn, seg, frac); + res.push_back(arb::poisson_generator(tgt, wgt, 0, avg, std::mt19937_64{gid})); + } + else if (regular_generators.count(inp)) { + throw std::runtime_error{\"Regular generators not implemented yet.\"}; + } + else if (i_clamps.count(inp)) { + // OK, handled those above + } + else { + // throw std::runtime_error{\"Unknown generator type.\"}; + } + } + } + return res; + } + + std::vector gid_to_cell; + std::unordered_map cell_to_morph; + std::unordered_map>> gid_to_inputs; + std::unordered_map>> gid_to_synapses; + std::unordered_map>> gid_to_detectors; + std::unordered_map>> gid_to_connections; + std::unordered_map> i_clamps; + std::unordered_map> regular_generators; + std::unordered_map> poisson_generators; + + arb::cell_size_type count; + std::string prefix = \"local_\"; + arb::cable_cell_global_properties gprop; + + std::filesystem::path here; + + double min_delay = 0.025; +}; + +int main(int argc, char* argv[]) { + double dt = 0.025; // ms + double T = 1000.0; // ms + + if (argc != 2) { + std::cerr << \"Usage: main \\n\"; + return -42; + } + auto cwd = std::filesystem::path{argv[0]}.parent_path(); + auto net = std::string{argv[1]}; + auto ctx = arb::make_context(); + auto mdl = recipe(cwd, net); + mdl.min_delay = dt; + auto ddc = arb::partition_load_balance(mdl, ctx); + auto sim = arb::simulation(mdl, ctx, ddc); + sim.set_binning_policy(arb::binning_kind::regular, dt); + sim.run(T, dt); +} diff --git a/dat/main.py b/dat/main.py new file mode 100644 index 0000000..864c133 --- /dev/null +++ b/dat/main.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 + +import arbor as A + +import subprocess as sp +from pathlib import Path +from time import perf_counter as pc +import sys +import json + +here = Path(__file__).parent + +def compile(here): + here = here.resolve() + fn = here / 'local-catalogue.so' + cat = here / 'cat' + recompile = False + if fn.exists(): + for src in cat.glob('*.mod'): + src = Path(src).resolve() + if src.stat().st_mtime > fn.stat().st_mtime: + recompile = True + break + else: + recompile = True + if recompile: + sp.run(f'arbor-build-catalogue local {cat}', shell=True, check=True) + return A.load_catalogue(fn) + +class recipe(A.recipe): + def __init__(self, network): + A.recipe.__init__(self) + self.seed = 42 + self.prefix = 'local_' + self.props = A.neuron_cable_properties() + cat = compile(here) + self.props.catalogue.extend(cat, self.prefix) + + with open((here / network).with_suffix('.json')) as fd: + data = json.load(fd) + + self.gid_to_cell = data['gid_to_cell'].items() + self.gid_to_inputs = { int(k): v for k, v in data['gid_to_inputs'].items() } + self.gid_to_synapses = { int(k): v for k, v in data['gid_to_synapses'].items() } + self.gid_to_detectors = { int(k): v for k, v in data['gid_to_detectors'].items() } + self.gid_to_connections = { int(k): v for k, v in data['gid_to_connections'].items() } + self.cell_to_morph = data['cell_to_morph'] + self.i_clamps = data['i_clamps'] + self.poisson_generators = data['poisson_generators'] + self.regular_generators = data['regular_generators'] + self.count = data['count'] + + def num_cells(self): + return self.count + + def cell_kind(self, _): + return A.cell_kind.cable + + def cell_description(self, gid): + cid = self.gid_to_cell[gid] + mrf = self.cell_to_morph[cid] + nml = A.neuroml(f'{here}/mrf/{mrf}.nml').morphology(mrf, allow_spherical_root=True) + lbl = A.label_dict() + lbl.append(nml.segments()) + lbl.append(nml.named_segments()) + lbl.append(nml.groups()) + lbl['all'] = '(all)' + dec = A.load_component(f'{here}/acc/{cid}.acc').component + dec.discretization(A.cv_policy_every_segment()) + if gid in self.gid_to_inputs: + for seg, frac, inp in self.gid_to_inputs[gid]: + tag = f'(on-components {frac} (region \"{seg}\"))' + if inp in self.i_clamps: + lag, dur, amp = self.i_clamps[inp] + dec.place(tag, A.iclamp(lag, dur, amp), f'ic_{inp}@seg_{seg}_frac_{frac}') + if gid in self.gid_to_synapses: + for seg, frac, syn in self.gid_to_synapses[gid]: + tag = f'(on-components {frac} (region \"{seg}\"))' + dec.place(tag, A.synapse(self.prefix + syn), f'syn_{syn}@seg_{seg}_frac_{frac}') + if gid in self.gid_to_detectors: + for seg, frac, thr in self.gid_to_detectors[gid]: + tag = f'(on-components {frac} (region \"{seg}\"))' + dec.place(tag, A.threshold_detector(thr), f'sd@seg_{seg}_frac_{frac}') + return A.cable_cell(nml.morphology, dec, lbl) + + def probes(self, _): + # Example: probe center of the root (likely the soma) + return [A.cable_probe_membrane_voltage('(location 0 0.5)')] + + def global_properties(self, kind): + return self.props + + def connections_on(self, gid): + res = [] + if gid in self.gid_to_connections: + for src, dec, syn, loc, w, d in self.gid_to_connections[gid]: + conn = A.connection((src, A.cell_local_label(f'sd@{dec}', A.selection_policy.round_robin)), A.cell_local_label(f'syn_{syn}@{loc}', A.selection_policy.round_robin), w, d) + res.append(conn) + return res + + def event_generators(self, gid): + res = [] + if gid in self.gid_to_inputs: + for seg, frac, inp in self.gid_to_inputs[gid]: + if inp in self.poisson_generators: + syn, avg, wgt = self.poisson_generators[inp] + res.append(A.event_generator(f'syn_{syn}@seg_{seg}_frac_{frac}', wgt, A.poisson_schedule(0, avg, gid))) + elif inp in self.regular_generators: + raise NotImplementedError() + else: + pass + return res + +if len(sys.argv) != 2: + print('Usage: main.py ') + exit(-42) + +ctx = A.context() +mdl = recipe(sys.argv[1]) +ddc = A.partition_load_balance(mdl, ctx) +sim = A.simulation(mdl, ctx, ddc) +hdl = sim.sample((0, 0), A.regular_schedule(0.1)) + +print('Running simulation for 1s...') +t0 = pc() +sim.run(1000, 0.025) +t1 = pc() +print(f'Simulation done, took: {t1-t0:.3f}s') + +print('Trying to plot...') +try: + import pandas as pd + import seaborn as sns + + for data, meta in sim.samples(hdl): + df = pd.DataFrame({'t/ms': data[:, 0], 'U/mV': data[:, 1]}) + sns.relplot(data=df, kind='line', x='t/ms', y='U/mV', ci=None).savefig('result.pdf') + print('Ok') +except: + print('Failure, are seaborn and matplotlib installed?') diff --git a/dat/run.sh b/dat/run.sh new file mode 100644 index 0000000..bdbb59c --- /dev/null +++ b/dat/run.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +cmake -S . -B build +cmake --build build +cp build/main . +arbor-build-catalogue local cat +./main $* diff --git a/src/acc.rs b/src/acc.rs index 29d87f0..4424f0a 100644 --- a/src/acc.rs +++ b/src/acc.rs @@ -23,28 +23,45 @@ use std::fs::write; use std::path::PathBuf; use tracing::{info, trace, warn}; -pub fn to_decor( - lems: &LemsFile, - nml: &[String], - ions: &[String], -) -> Result>> { +#[derive(Debug, Default, PartialEq, PartialOrd)] +pub struct Cell { + pub decor: Vec, + pub spike_threshold: Option, +} + +impl Cell { + fn append(&mut self, rhs: &Self) -> Result<()> { + if self.spike_threshold.is_some() { + if self.spike_threshold.is_some() && self.spike_threshold != rhs.spike_threshold { + return Err(nml2_error!("Duplicated, mismatching spike threshold.")); + } + } else { + self.spike_threshold = rhs.spike_threshold; + } + self.decor.extend_from_slice(&rhs.decor[..]); + Ok(()) + } +} + +pub fn to_cell_list(lems: &LemsFile, nml: &[String], ions: &[String]) -> Result> { let mut cells = Map::new(); process_files(nml, |_, node| { if node.tag_name().name() == "cell" { if let Some(id) = node.attribute("id") { - let mut result = Vec::new(); + let mut cell: Cell = Default::default(); let inhomogeneous_parameters = parse_inhomogeneous_parameters(node)?; for bpp in node.children() { if bpp.tag_name().name() == "biophysicalProperties" { - result.append(&mut biophys( + let tmp = &mut biophys( &XML::from_node(&bpp), lems, ions, &inhomogeneous_parameters, - )?); + )?; + cell.append(tmp)?; } } - *cells.entry(id.to_string()).or_default() = result; + *cells.entry(id.to_string()).or_default() = cell; } } Ok(()) @@ -124,13 +141,14 @@ pub fn export( ) -> Result<()> { trace!("Creating path {}", pfx); std::fs::create_dir_all(pfx)?; - let cells = to_decor(lems, nml, ions)?; - for (cell, decor) in cells { + let cells = to_cell_list(lems, nml, ions)?; + for (name, cell) in cells { let mut file = PathBuf::from(pfx); - file.push(cell); + file.push(name); file.set_extension("acc"); info!("Writing ACC to {:?}", &file); - let decor = decor + let decor = cell + .decor .iter() .map(|d| d.add_catalogue_prefix(cat_prefix)) .collect::>(); @@ -431,23 +449,24 @@ pub fn biophys( lems: &LemsFile, ions: &[String], inhomogeneous_parameters: &Map, -) -> Result> { +) -> Result { use BiophysicalPropertiesBody::*; - let mut decor = Vec::new(); + let mut result: Cell = Default::default(); for item in &prop.body { match item { membraneProperties(m) => { - decor.append(&mut membrane(m, ions, inhomogeneous_parameters)?) + let cell = &mut membrane(m, ions, inhomogeneous_parameters)?; + result.append(cell)?; } - intracellularProperties(i) => decor.append(&mut intra(i)?), - extracellularProperties(e) => decor.append(&mut extra(e)?), + intracellularProperties(i) => result.decor.append(&mut intra(i)?), + extracellularProperties(e) => result.decor.append(&mut extra(e)?), property(_) | notes(_) | annotation(_) => {} } } - for it in decor.iter_mut() { + for it in result.decor.iter_mut() { *it = it.normalise(lems)?; } - Ok(decor) + Ok(result) } fn make_variable_parameter_map( @@ -500,9 +519,9 @@ fn membrane( membrane: &MembraneProperties, known_ions: &[String], inhomogeneous_parameters: &Map, -) -> Result> { +) -> Result { use MembranePropertiesBody::*; - let mut result = Vec::new(); + let mut result: Cell = Default::default(); for item in &membrane.body { match item { channelDensity(ChannelDensity { @@ -515,13 +534,17 @@ fn membrane( .. }) => { if !body.is_empty() { - return Err(acc_unimplemented("Non-empty body in MembraneProperties")); + return Err(acc_unimplemented( + "Non-empty body in ChannelDensityProperties", + )); } - let mut gs = simple_ion(known_ions, &mut result, ion, segmentGroup, erev)?; + let mut gs = simple_ion(known_ions, &mut result.decor, ion, segmentGroup, erev)?; if let Some(g) = condDensity { gs.insert(String::from("conductance"), g.clone()); } - result.push(Decor::mechanism(segmentGroup, ionChannel, &gs)); + result + .decor + .push(Decor::mechanism(segmentGroup, ionChannel, &gs)); } channelDensityNernst(ChannelDensityNernst { ionChannel, @@ -539,8 +562,10 @@ fn membrane( } else { Map::new() }; - result.push(Decor::mechanism(segmentGroup, ionChannel, &gs)); - result.push(Decor::nernst(ion)); + result + .decor + .push(Decor::mechanism(segmentGroup, ionChannel, &gs)); + result.decor.push(Decor::nernst(ion)); } channelDensityNonUniform(ChannelDensityNonUniform { ionChannel, @@ -554,8 +579,8 @@ fn membrane( "expected VariableParameter in ChannelDensityNonUniform" ))?; let ns = make_variable_parameter_map(vp, inhomogeneous_parameters)?; - let ps = simple_ion(known_ions, &mut result, ion, &vp.segmentGroup, erev)?; - result.push(Decor::non_uniform_mechanism( + let ps = simple_ion(known_ions, &mut result.decor, ion, &vp.segmentGroup, erev)?; + result.decor.push(Decor::non_uniform_mechanism( &vp.segmentGroup, ionChannel, &ps, @@ -573,23 +598,23 @@ fn membrane( "expected VariableParameter in ChannelDensityNonUniformNernst" ))?; let ns = make_variable_parameter_map(vp, inhomogeneous_parameters)?; - result.push(Decor::nernst(ion)); - result.push(Decor::non_uniform_mechanism( + result.decor.push(Decor::nernst(ion)); + result.decor.push(Decor::non_uniform_mechanism( &vp.segmentGroup, ionChannel, &Map::new(), &ns, )); } - spikeThresh(_) => {} + spikeThresh(v) => result.spike_threshold = Some(Quantity::parse(&v.value)?.value), specificCapacitance(SpecificCapacitance { value, segmentGroup, - }) => result.push(Decor::cm(segmentGroup, value)), + }) => result.decor.push(Decor::cm(segmentGroup, value)), initMembPotential(InitMembPotential { value, segmentGroup, - }) => result.push(Decor::vm(segmentGroup, value)), + }) => result.decor.push(Decor::vm(segmentGroup, value)), channelPopulation(_) | channelDensityVShift(_) | channelDensityGHK(_) diff --git a/src/bundle.rs b/src/bundle.rs index 86a7639..45c2122 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -18,321 +18,197 @@ use crate::{ xml::XML, Map, Set, }; -use std::fmt::Write as _; +use serde::Serialize; +use serde_json; use std::fs::{create_dir_all, write}; use tracing::{info, trace}; -pub fn export( - lems: &LemsFile, - nml: &[String], - bundle: &str, - use_super_mechs: bool, - ions: &[String], - cat_prefix: &str, -) -> Result<()> { - export_template(lems, nml, bundle)?; +static RUN_SH: &str = include_str!(r"../dat/run.sh"); +static CMAKE: &str = include_str!(r"../dat/CMakeLists.txt"); +static MAIN_CXX: &str = include_str!(r"../dat/main.cxx"); +static MAIN_PY: &str = include_str!(r"../dat/main.py"); + +pub struct Bundle { + pub dir: String, + pub cxx: bool, + pub py: bool, + pub super_mechanisms: bool, + pub cat_prefix: String, +} + +pub fn export(lems: &LemsFile, nml: &[String], ions: &[String], cfg: Bundle) -> Result<()> { + export_template(lems, nml, &cfg.dir)?; // We always export these to keep synapse etc alive - nmodl::export(lems, nml, "-*", &format!("{bundle}/cat"), ions)?; + nmodl::export(lems, nml, "-*", &format!("{}/cat", &cfg.dir), ions)?; - if use_super_mechs { - export_with_super_mechanisms(lems, nml, bundle, ions, cat_prefix)?; + if cfg.super_mechanisms { + export_with_super_mechanisms(lems, nml, &cfg.dir, ions, &cfg.cat_prefix)?; } else { - acc::export(lems, nml, &format!("{bundle}/acc"), ions, cat_prefix)?; + acc::export( + lems, + nml, + &format!("{}/acc", &cfg.dir), + ions, + &cfg.cat_prefix, + )?; + } + if cfg.py { + write(format!("{}/main.py", &cfg.dir), MAIN_PY)?; + } + if cfg.cxx { + write(format!("{}/run.sh", &cfg.dir), RUN_SH)?; + write(format!("{}/CMakeLists.txt", &cfg.dir), CMAKE)?; + write(format!("{}/main.cxx", &cfg.dir), MAIN_CXX)?; } Ok(()) } -fn mk_main_py( - cells: &[(String, String)], - stimuli: &Map, - net: &Network, -) -> Result { - let mut cell_to_morph = String::from("{"); - for (c, m) in cells { - write!(cell_to_morph, "'{c}': '{m}', ").unwrap(); - } - cell_to_morph.push('}'); - - let mut count = 0; - let mut pop_to_gid = Map::new(); - let mut gid_to_cell = String::from("["); - let mut gid_to_pop = String::from("["); - let mut inputs = Map::new(); - for (id, pop) in &net.populations { - pop_to_gid.insert(id.clone(), count); - for _ in &pop.members { - count += 1; - gid_to_cell.push_str(&format!("'{}', ", pop.component)); - gid_to_pop.push_str(&format!("'{id}', ")); - } - } +type ConnectionData = (i64, String, String, String, f64, f64); + +#[derive(Serialize)] +struct SimulationData { + gid_to_cell: Vec, + cell_to_morph: Map, + gid_to_inputs: Map>, + gid_to_synapses: Map>, + gid_to_detectors: Map>, + gid_to_connections: Map>, + // Inputs & Stimuli + i_clamps: Map, + regular_generators: Map, + poisson_generators: Map, + // cells + count: usize, +} - let mut synapses: Map> = Map::new(); - for network::Input { - source, - target, - segment, - fraction, - } in &net.inputs - { - let (pop, id) = get_cell_id(target)?; - let fst = pop_to_gid[&pop]; - let idx = if let Some(p) = net.populations.get(&pop) { - p.members - .iter() - .position(|ix| id == *ix as i64) - .ok_or_else(|| nml2_error!("Bad index {id} in population {pop}."))? - } else { - return Err(nml2_error!("Indexing into an unknown population: {pop}.")); - }; - let gid: i64 = (fst + idx) as i64; - let val = (source.clone(), segment, fraction); - inputs.entry(gid).or_insert_with(Vec::new).push(val); - match stimuli.get(source) { - Some(Input::Poisson(synapse, _, _)) => { - synapses.entry(gid).or_insert_with(Set::new).insert(( - *segment, - fraction.clone(), - synapse.clone(), - )); +impl SimulationData { + fn new( + cell_to_morph: &Map, + cell_to_threshold: &Map, + stimuli: &Map, + net: &Network, + ) -> Result { + let mut gid = 0; + let mut gid_to_cell = Vec::new(); + let mut pop_to_gid = Map::new(); + for (id, pop) in &net.populations { + pop_to_gid.insert(id.clone(), gid); + let cell = pop.component.to_string(); + for _ in &pop.members { + gid_to_cell.push(cell.clone()); + gid += 1; } - Some(_) => todo!(), - None => {} } - } - gid_to_cell.push(']'); - gid_to_pop.push(']'); - - let mut gid_to_inputs = String::from("{"); - for (key, vals) in inputs { - gid_to_inputs.push_str(&format!("\n {key}: [")); - for (src, seg, frac) in vals { - gid_to_inputs.push_str(&format!("({seg}, '{frac}', \"{src}\"), ")); + let count = gid; + + let mut gid_to_inputs = Map::new(); + let mut gid_to_synapses: Map<_, Vec<_>> = Map::new(); + for network::Input { + source, + target, + segment, + fraction, + } in &net.inputs + { + let (pop, id) = get_cell_id(target)?; + let fst = pop_to_gid[&pop]; + let idx = if let Some(p) = net.populations.get(&pop) { + p.members + .iter() + .position(|ix| id == *ix as i64) + .ok_or_else(|| nml2_error!("Bad index {id} in population {pop}."))? + } else { + return Err(nml2_error!("Indexing into an unknown population: {pop}.")); + }; + let gid: i64 = (fst + idx) as i64; + let val = (*segment, fraction.to_string(), source.clone()); + gid_to_inputs.entry(gid).or_insert_with(Vec::new).push(val); + match stimuli.get(source) { + Some(Input::Poisson(synapse, _, _)) => { + gid_to_synapses.entry(gid).or_default().push(( + *segment, + fraction.clone(), + synapse.clone(), + )); + } + None | Some(Input::Pulse(..)) => {} + } } - gid_to_inputs.push_str("], "); - } - gid_to_inputs.push('}'); - - // In arbor - let mut detectors = Map::new(); - let mut conns = Map::new(); - for Projection { - synapse, - pre, - post, - connections, - } in &net.projections - { - let pre = pop_to_gid[pre] as i64; - let post = pop_to_gid[post] as i64; - for Connection { - from, - to, - weight, - delay, - } in connections + + let mut gid_to_detectors: Map<_, Vec<_>> = Map::new(); + let mut gid_to_connections = Map::new(); + for Projection { + synapse, + pre, + post, + connections, + } in &net.projections { - let from_gid = pre + from.cell; - let to_gid = post + to.cell; - detectors - .entry(from_gid) - .or_insert_with(Set::new) - .insert((from.segment, from.fraction.clone())); - synapses.entry(to_gid).or_insert_with(Set::new).insert(( - to.segment, - to.fraction.clone(), - synapse.clone(), - )); - conns.entry(to_gid).or_insert_with(Vec::new).push(( - from_gid, - from.to_label(), - synapse.to_string(), - to.to_label(), + let pre_gid = pop_to_gid[pre] as i64; + let post_gid = pop_to_gid[post] as i64; + for Connection { + from, + to, weight, delay, - )); + } in connections + { + let pre_cell_id = &net.populations[pre].component; + let threshold = cell_to_threshold[pre_cell_id]; + let from_gid = pre_gid + from.cell; + let to_gid = post_gid + to.cell; + gid_to_detectors.entry(from_gid).or_default().push(( + from.segment, + from.fraction.clone(), + threshold, + )); + gid_to_synapses.entry(to_gid).or_default().push(( + to.segment, + to.fraction.clone(), + synapse.clone(), + )); + gid_to_connections + .entry(to_gid) + .or_insert_with(Vec::new) + .push(( + from_gid, + from.to_label(), + synapse.to_string(), + to.to_label(), + *weight, + *delay, + )); + } } - } - let mut i_clamps = String::from("{"); - let mut poisson = String::from("{"); - let mut regular = String::from("{"); - for (lbl, stimulus) in stimuli { - match stimulus { - Input::Pulse(delay, dt, stop) => { - i_clamps.push_str(&format!("'{lbl}': ({delay}, {dt}, {stop}), ")) - } - Input::Poisson(syn, avg, wgt) => { - poisson.push_str(&format!("'{lbl}': ('{syn}', {avg}, {wgt})")) + let mut i_clamps = Map::new(); + let mut poisson_generators = Map::new(); + let regular_generators = Map::new(); + for (lbl, stimulus) in stimuli { + match stimulus { + Input::Pulse(delay, dt, stop) => { + i_clamps.insert(lbl.to_string(), (*delay, *dt, *stop)); + } + Input::Poisson(syn, avg, wgt) => { + poisson_generators.insert(lbl.to_string(), (syn.to_string(), *avg, *wgt)); + } } } - } - i_clamps.push('}'); - poisson.push('}'); - regular.push('}'); - - let mut gid_to_synapses = String::from("{\n"); - for (gid, vs) in &synapses { - gid_to_synapses.push_str(&format!(" {gid}: [")); - for (seg, frac, syn) in vs { - gid_to_synapses.push_str(&format!("({seg}, '{frac}', \"{syn}\"), ")); - } - gid_to_synapses.push_str("],\n"); - } - gid_to_synapses.push_str(" }"); - let mut gid_to_detectors = String::from("{\n"); - for (gid, vs) in &detectors { - gid_to_detectors.push_str(&format!(" {gid}: [")); - for (seg, frac) in vs { - gid_to_detectors.push_str(&format!("({seg}, '{frac}'), ")); - } - gid_to_detectors.push_str("],\n"); - } - gid_to_detectors.push_str(" }"); - - let mut gid_to_connections = String::from("{\n"); - for (gid, vs) in &conns { - gid_to_connections.push_str(&format!(" {gid}: [")); - for (fgid, floc, syn, tloc, weight, delay) in vs { - gid_to_connections.push_str(&format!( - "({fgid}, \"{floc}\", \"{syn}\", \"{tloc}\", {weight}, {delay}), " - )); - } - gid_to_connections.push_str("],\n"); + Ok(SimulationData { + gid_to_cell, + cell_to_morph: cell_to_morph.clone(), + gid_to_inputs, + gid_to_synapses, + gid_to_detectors, + gid_to_connections, + i_clamps, + regular_generators, + poisson_generators, + count, + }) } - gid_to_connections.push_str(" }"); - - let cat_prefix = "local_"; - - Ok(format!( - "#!/usr/bin/env python3 -import arbor as A - -import subprocess as sp -from pathlib import Path -from time import perf_counter as pc -import sys - -here = Path(__file__).parent - -def compile(fn, cat): - fn = fn.resolve() - cat = cat.resolve() - recompile = False - if fn.exists(): - for src in cat.glob('*.mod'): - src = Path(src).resolve() - if src.stat().st_mtime > fn.stat().st_mtime: - recompile = True - break - sp.run(f'arbor-build-catalogue local {{cat}}', shell=True, check=True) - return A.load_catalogue(fn) - -class recipe(A.recipe): - def __init__(self): - A.recipe.__init__(self) - self.seed = 42 - self.prefix = '{cat_prefix}' - self.props = A.neuron_cable_properties() - cat = compile(here / 'local-catalogue.so', here / 'cat') - self.props.catalogue.extend(cat, self.prefix) - self.cell_to_morph = {cell_to_morph} - self.gid_to_cell = {gid_to_cell} - self.i_clamps = {i_clamps} - self.poisson_generators = {poisson} - self.regular_generators = {regular} - self.gid_to_inputs = {gid_to_inputs} - self.gid_to_synapses = {gid_to_synapses} - self.gid_to_detectors = {gid_to_detectors} - self.gid_to_connections = {gid_to_connections} - - def num_cells(self): - return {count} - - def cell_kind(self, _): - return A.cell_kind.cable - - def cell_description(self, gid): - cid = self.gid_to_cell[gid] - mrf = self.cell_to_morph[cid] - nml = A.neuroml(f'{{here}}/mrf/{{mrf}}.nml').morphology(mrf, allow_spherical_root=True) - lbl = A.label_dict() - lbl.append(nml.segments()) - lbl.append(nml.named_segments()) - lbl.append(nml.groups()) - lbl['all'] = '(all)' - dec = A.load_component(f'{{here}}/acc/{{cid}}.acc').component - dec.discretization(A.cv_policy_every_segment()) - if gid in self.gid_to_inputs: - for seg, frac, inp in self.gid_to_inputs[gid]: - tag = f'(on-components {{frac}} (region \"{{seg}}\"))' - if inp in self.i_clamps: - lag, dur, amp = self.i_clamps[inp] - dec.place(tag, A.iclamp(lag, dur, amp), f'ic_{{inp}}@seg_{{seg}}_frac_{{frac}}') - if gid in self.gid_to_synapses: - for seg, frac, syn in self.gid_to_synapses[gid]: - tag = f'(on-components {{frac}} (region \"{{seg}}\"))' - dec.place(tag, A.synapse(self.prefix + syn), f'syn_{{syn}}@seg_{{seg}}_frac_{{frac}}') - if gid in self.gid_to_detectors: - for seg, frac in self.gid_to_detectors[gid]: - tag = f'(on-components {{frac}} (region \"{{seg}}\"))' - dec.place(tag, A.threshold_detector(-40), f'sd@seg_{{seg}}_frac_{{frac}}') # -40 is a phony value!!! - return A.cable_cell(nml.morphology, dec, lbl) - - def probes(self, _): - # Example: probe center of the root (likely the soma) - return [A.cable_probe_membrane_voltage('(location 0 0.5)')] - - def global_properties(self, kind): - return self.props - - def connections_on(self, gid): - res = [] - if gid in self.gid_to_connections: - for src, dec, syn, loc, w, d in self.gid_to_connections[gid]: - conn = A.connection((src, A.cell_local_label(f'sd@{{dec}}', A.selection_policy.round_robin)), A.cell_local_label(f'syn_{{syn}}@{{loc}}', A.selection_policy.round_robin), w, d) - res.append(conn) - return res - - def event_generators(self, gid): - res = [] - if gid in self.gid_to_inputs: - for seg, frac, inp in self.gid_to_inputs[gid]: - tag = f'(on-components {{frac}} (region \"{{seg}}\"))' - if inp in self.poisson_generators: - syn, avg, wgt = self.poisson_generators[inp] - res.append(A.event_generator(f'syn_{{syn}}@seg_{{seg}}_frac_{{frac}}', wgt, A.poisson_schedule(0, avg, gid))) - if inp in self.regular_generators: - raise \"oops\" - return res - - -ctx = A.context() -mdl = recipe() -ddc = A.partition_load_balance(mdl, ctx) -sim = A.simulation(mdl, ctx, ddc) -hdl = sim.sample((0, 0), A.regular_schedule(0.1)) - -print('Running simulation for 1s...') -t0 = pc() -sim.run(1000, 0.0025) -t1 = pc() -print(f'Simulation done, took: {{t1-t0:.3f}}s') - -print('Trying to plot...') -try: - import pandas as pd - import seaborn as sns - - for data, meta in sim.samples(hdl): - df = pd.DataFrame({{'t/ms': data[:, 0], 'U/mV': data[:, 1]}}) - sns.relplot(data=df, kind='line', x='t/ms', y='U/mV', ci=None).savefig('result.pdf') - print('Ok') -except: - print('Failure, are seaborn and matplotlib installed?') -")) } fn mk_mrf(id: &str, mrf: &str) -> String { @@ -349,6 +225,8 @@ fn mk_mrf(id: &str, mrf: &str) -> String { ) } +#[derive(Debug)] +#[non_exhaustive] enum Input { Pulse(f64, f64, f64), Poisson(String, f64, f64), @@ -360,6 +238,7 @@ fn export_template(lems: &LemsFile, nml: &[String], bundle: &str) -> Result<()> create_dir_all(format!("{bundle}/mrf"))?; create_dir_all(format!("{bundle}/acc"))?; create_dir_all(format!("{bundle}/cat"))?; + create_dir_all(format!("{bundle}/dat"))?; let norm = |v: &str| -> Result { let q = Quantity::parse(v)?; @@ -368,7 +247,8 @@ fn export_template(lems: &LemsFile, nml: &[String], bundle: &str) -> Result<()> }; let mut inputs = Map::new(); - let mut cells = Vec::new(); + let mut cells = Map::new(); + let mut thresholds = Map::new(); let mut nets = Vec::new(); process_files(nml, |_, node| { let doc = node.document().input_text(); @@ -392,7 +272,16 @@ fn export_template(lems: &LemsFile, nml: &[String], bundle: &str) -> Result<()> let morph = mrf .attribute("id") .ok_or_else(|| nml2_error!("Morph has no id"))?; - cells.push((cell.to_string(), morph.to_string())); + cells.insert(cell.to_string(), morph.to_string()); + } + } + for spk in node.descendants() { + if spk.tag_name().name() == "spikeThresh" { + let val = spk + .attribute("value") + .ok_or_else(|| nml2_error!("SpikeThresh has no value"))?; + let val = Quantity::parse(val)?; + thresholds.insert(cell.to_string(), val.value); } } } @@ -420,7 +309,6 @@ fn export_template(lems: &LemsFile, nml: &[String], bundle: &str) -> Result<()> ); } "network" => { - eprintln!("Found network: {:?}", node.attribute("id")); let inst = Instance::new(lems, node)?; let net = Network::new(&inst)?; nets.push(net); @@ -430,20 +318,14 @@ fn export_template(lems: &LemsFile, nml: &[String], bundle: &str) -> Result<()> Ok(()) })?; - match &nets[..] { - [] => Ok(()), - [net] => { - trace!("Writing main.py"); - write( - format!("{bundle}/main.py"), - mk_main_py(&cells, &inputs, net)?, - )?; - Ok(()) - } - _ => Err(nml2_error!( - "Currently only one Network per bundle is supported.", - )), + for net in &nets { + write( + format!("{bundle}/dat/{}.json", net.name), + serde_json::to_string_pretty(&SimulationData::new(&cells, &thresholds, &inputs, net)?) + .unwrap(), + )?; } + Ok(()) } #[derive(Clone, Debug)] @@ -702,7 +584,7 @@ fn split_decor( )?; let mut non_uniform_args: Map> = Map::new(); // collect non uniform args as they must be kept as PARAMETERS - for d in biophys.iter() { + for d in biophys.decor.iter() { match d { Decor::Paint(ref r, Paintable::NonUniformMech { ref name, ns, .. }) if densities.contains(name) => @@ -717,7 +599,7 @@ fn split_decor( _ => (), } } - for d in biophys { + for d in biophys.decor { match d { Decor::Paint(r, Paintable::Mech(name, _)) if densities.contains(&name) => { if !seen.contains(&r) { diff --git a/src/expr.rs b/src/expr.rs index 782d290..608d58d 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -382,10 +382,15 @@ impl Boolean { (Boolean::Cmp(el, xl, yl), Boolean::Cmp(er, xr, yr)) if xl == xr && yl == yr => { - match (&el, &er) { + match (el, er) { // ... - (u, v) if u == v => { - return Boolean::Cmp(**u, xl.clone(), yl.clone()) + (Cmp::Eq, Cmp::Eq) + | (Cmp::Ne, Cmp::Ne) + | (Cmp::Gt, Cmp::Gt) + | (Cmp::Lt, Cmp::Lt) + | (Cmp::Ge, Cmp::Ge) + | (Cmp::Le, Cmp::Le) => { + return Boolean::Cmp(*el, xl.clone(), yl.clone()) } // contradiction (Cmp::Ne, Cmp::Eq) @@ -400,32 +405,34 @@ impl Boolean { | (Cmp::Lt, Cmp::Ge) | (Cmp::Gt, Cmp::Le) | (Cmp::Le, Cmp::Gt) => return Boolean::Lit(false), - // redundant - (Cmp::Le, Cmp::Eq) + (Cmp::Le, Cmp::Eq) // x <= y && x == y => x == y | (Cmp::Eq, Cmp::Le) - | (Cmp::Le, Cmp::Lt) - | (Cmp::Lt, Cmp::Le) => { - return Boolean::Cmp(Cmp::Le, xl.clone(), yl.clone()) - } - (Cmp::Ge, Cmp::Eq) + | (Cmp::Ge, Cmp::Eq) // x >= y && x == y => x == y | (Cmp::Eq, Cmp::Ge) - | (Cmp::Ge, Cmp::Gt) - | (Cmp::Gt, Cmp::Ge) => { - return Boolean::Cmp(Cmp::Ge, xl.clone(), yl.clone()) - } - (Cmp::Ne, Cmp::Gt) | (Cmp::Gt, Cmp::Ne) => { - return Boolean::Cmp(Cmp::Gt, xl.clone(), yl.clone()) + | (Cmp::Ge, Cmp::Le) // x >= y && x <= y => x == y + | (Cmp::Le, Cmp::Ge) => { + return Boolean::Cmp(Cmp::Eq, xl.clone(), yl.clone()) } - (Cmp::Ne, Cmp::Lt) | (Cmp::Lt, Cmp::Ne) => { + (Cmp::Ge, Cmp::Gt) // x > y && x >= y => x > y + | (Cmp::Gt, Cmp::Ge) + | (Cmp::Ne, Cmp::Ge) // x /= y && x >= y => x > y + | (Cmp::Ge, Cmp::Ne) + | (Cmp::Ne, Cmp::Gt) // x /= y && x > y => x > y + | (Cmp::Gt, Cmp::Ne) => { return Boolean::Cmp(Cmp::Gt, xl.clone(), yl.clone()) } - // intersection - (Cmp::Ge, Cmp::Le) | (Cmp::Le, Cmp::Ge) => { - return Boolean::Cmp(Cmp::Eq, xl.clone(), yl.clone()) + (Cmp::Ne, Cmp::Le) // x /= y && x <= y => x < y + | (Cmp::Le, Cmp::Ne) + | (Cmp::Le, Cmp::Lt) // x <= y && x < y => x < y + | (Cmp::Lt, Cmp::Le) + | (Cmp::Ne, Cmp::Lt) // x /= y && x < y => x < y + | (Cmp::Lt, Cmp::Ne) => { + return Boolean::Cmp(Cmp::Lt, xl.clone(), yl.clone()) } - _ => unreachable!(), } } + // Cross the beams + // x `O` y && y `P` x => x `O` y && x `!P` y (l @ Boolean::Cmp(_, xl, yl), Boolean::Cmp(er, xr, yr)) if xl == yr && yl == xr => { @@ -457,10 +464,15 @@ impl Boolean { (Boolean::Cmp(el, xl, yl), Boolean::Cmp(er, xr, yr)) if xl == xr && yl == yr => { - match (&el, &er) { + match (*el, *er) { // ... - (u, v) if u == v => { - return Boolean::Cmp(**u, xl.clone(), xr.clone()) + (Cmp::Eq, Cmp::Eq) + | (Cmp::Ne, Cmp::Ne) + | (Cmp::Gt, Cmp::Gt) + | (Cmp::Lt, Cmp::Lt) + | (Cmp::Ge, Cmp::Ge) + | (Cmp::Le, Cmp::Le) => { + return Boolean::Cmp(*el, xl.clone(), yl.clone()) } // x > y || x < y => x /= y (Cmp::Lt, Cmp::Gt) | (Cmp::Gt, Cmp::Lt) => { @@ -474,24 +486,39 @@ impl Boolean { | (Cmp::Gt, Cmp::Le) | (Cmp::Le, Cmp::Gt) | (Cmp::Ge, Cmp::Lt) + | (Cmp::Ge, Cmp::Ne) + | (Cmp::Ne, Cmp::Ge) + | (Cmp::Le, Cmp::Ne) + | (Cmp::Ne, Cmp::Le) | (Cmp::Lt, Cmp::Ge) => return Boolean::Lit(true), // redundant - (Cmp::Ge, Cmp::Eq) | (Cmp::Eq, Cmp::Ge) => { + (Cmp::Ge, Cmp::Eq) + | (Cmp::Eq, Cmp::Ge) + | (Cmp::Ge, Cmp::Gt) + | (Cmp::Gt, Cmp::Ge) + | (Cmp::Eq, Cmp::Gt) + | (Cmp::Gt, Cmp::Eq) => { return Boolean::Cmp(Cmp::Ge, xl.clone(), yl.clone()) } - (Cmp::Le, Cmp::Eq) | (Cmp::Eq, Cmp::Le) => { + (Cmp::Le, Cmp::Eq) + | (Cmp::Eq, Cmp::Le) + | (Cmp::Le, Cmp::Lt) + | (Cmp::Lt, Cmp::Le) + | (Cmp::Eq, Cmp::Lt) + | (Cmp::Lt, Cmp::Eq) => { return Boolean::Cmp(Cmp::Le, xl.clone(), yl.clone()) } - // return the weaker condition + // x /= y || x {<, >} y => x /= y (Cmp::Gt, Cmp::Ne) | (Cmp::Ne, Cmp::Gt) | (Cmp::Lt, Cmp::Ne) | (Cmp::Ne, Cmp::Lt) => { return Boolean::Cmp(Cmp::Ne, xl.clone(), yl.clone()) } - _ => unreachable!(), } } + // Cross the beams + // x `O` y || y `P` x => x `O` y || x `!P` y (l @ Boolean::Cmp(_, xl, yl), Boolean::Cmp(er, xr, yr)) if xl == yr && yl == xr => { @@ -1218,5 +1245,13 @@ mod test { Boolean::parse("(x .neq. y) .and. (x .eq. y)").unwrap(), Boolean::Lit(false) ); + assert_eq!( + Boolean::parse("(x .eq. y) .or. (x .gt. y)").unwrap(), + Boolean::parse("x .geq. y").unwrap() + ); + assert_eq!( + Boolean::parse("(x .neq. y) .or. (x .geq. y)").unwrap(), + Boolean::Lit(true) + ); } } diff --git a/src/lems/file.rs b/src/lems/file.rs index 9c552f2..f5fb8f5 100644 --- a/src/lems/file.rs +++ b/src/lems/file.rs @@ -55,8 +55,7 @@ fn normalise_quantity( } } else { Err(unit_error(format!( - "Failed to find unit {} for quantity {:?}", - u, quantity + "Failed to find unit {u} for quantity {quantity:?}" ))) } } else { diff --git a/src/lems/mod.rs b/src/lems/mod.rs index 51aff7e..24036d6 100644 --- a/src/lems/mod.rs +++ b/src/lems/mod.rs @@ -66,8 +66,7 @@ impl Lems { done.push(name.to_string()); } else { return Err(lems_error(format!( - "Could not find LEMS file {} in paths {:?}", - name, paths + "Could not find LEMS file {name} in paths {paths:?}" ))); } } diff --git a/src/lems/raw.rs b/src/lems/raw.rs index 2298bbb..6bc5739 100644 --- a/src/lems/raw.rs +++ b/src/lems/raw.rs @@ -231,7 +231,7 @@ impl XML for ComponentType { "Dynamics" => body.push(ComponentTypeBody::Dynamics(Dynamics::from_node(&child))), "Structure" => body.push(ComponentTypeBody::Structure(Structure::from_node(&child))), "Simulation" => body.push(ComponentTypeBody::Simulation(Simulation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ComponentType.") + t => panic!("Unexpected tag {} in body of ComponentType.", t) }; } ComponentType { @@ -268,7 +268,7 @@ impl XML for ConditionalDerivedVariable { } match child.tag_name().name() { "Case" => body.push(ConditionalDerivedVariableBody::Case(Case::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ConditionalDerivedVariable.") + t => panic!("Unexpected tag {} in body of ConditionalDerivedVariable.", t) }; } ConditionalDerivedVariable { @@ -462,7 +462,7 @@ impl XML for Dynamics { "OnCondition" => body.push(DynamicsBody::OnCondition(OnCondition::from_node(&child))), "Regime" => body.push(DynamicsBody::Regime(Regime::from_node(&child))), "KineticScheme" => body.push(DynamicsBody::KineticScheme(KineticScheme::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Dynamics.") + t => panic!("Unexpected tag {} in body of Dynamics.", t) }; } Dynamics { @@ -504,7 +504,7 @@ impl XML for EventConnection { } match child.tag_name().name() { "Assign" => body.push(EventConnectionBody::Assign(Assign::from_node(&child))), - t => panic!("Unexpected tag {t} in body of EventConnection.") + t => panic!("Unexpected tag {} in body of EventConnection.", t) }; } EventConnection { @@ -654,7 +654,7 @@ impl XML for ForEach { } match child.tag_name().name() { "MultiInstantiate" => body.push(ForEachBody::MultiInstantiate(MultiInstantiate::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ForEach.") + t => panic!("Unexpected tag {} in body of ForEach.", t) }; } ForEach { @@ -778,7 +778,7 @@ impl XML for Lems { "Constant" => body.push(LemsBody::Constant(Constant::from_node(&child))), "ComponentType" => body.push(LemsBody::ComponentType(ComponentType::from_node(&child))), "Component" => body.push(LemsBody::Component(Component::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Lems.") + t => panic!("Unexpected tag {} in body of Lems.", t) }; } Lems { @@ -870,7 +870,7 @@ impl XML for OnCondition { "StateAssignment" => body.push(OnConditionBody::StateAssignment(StateAssignment::from_node(&child))), "EventOut" => body.push(OnConditionBody::EventOut(EventOut::from_node(&child))), "Transition" => body.push(OnConditionBody::Transition(Transition::from_node(&child))), - t => panic!("Unexpected tag {t} in body of OnCondition.") + t => panic!("Unexpected tag {} in body of OnCondition.", t) }; } OnCondition { @@ -899,7 +899,7 @@ impl XML for OnEntry { } match child.tag_name().name() { "StateAssignment" => body.push(OnEntryBody::StateAssignment(StateAssignment::from_node(&child))), - t => panic!("Unexpected tag {t} in body of OnEntry.") + t => panic!("Unexpected tag {} in body of OnEntry.", t) }; } OnEntry { @@ -931,7 +931,7 @@ impl XML for OnEvent { match child.tag_name().name() { "StateAssignment" => body.push(OnEventBody::StateAssignment(StateAssignment::from_node(&child))), "EventOut" => body.push(OnEventBody::EventOut(EventOut::from_node(&child))), - t => panic!("Unexpected tag {t} in body of OnEvent.") + t => panic!("Unexpected tag {} in body of OnEvent.", t) }; } OnEvent { @@ -960,7 +960,7 @@ impl XML for OnStart { } match child.tag_name().name() { "StateAssignment" => body.push(OnStartBody::StateAssignment(StateAssignment::from_node(&child))), - t => panic!("Unexpected tag {t} in body of OnStart.") + t => panic!("Unexpected tag {} in body of OnStart.", t) }; } OnStart { @@ -1079,7 +1079,7 @@ impl XML for Regime { "TimeDerivative" => body.push(RegimeBody::TimeDerivative(TimeDerivative::from_node(&child))), "OnEntry" => body.push(RegimeBody::OnEntry(OnEntry::from_node(&child))), "OnCondition" => body.push(RegimeBody::OnCondition(OnCondition::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Regime.") + t => panic!("Unexpected tag {} in body of Regime.", t) }; } Regime { @@ -1162,7 +1162,7 @@ impl XML for Simulation { "Run" => body.push(SimulationBody::Run(Run::from_node(&child))), "DataWriter" => body.push(SimulationBody::DataWriter(DataWriter::from_node(&child))), "EventWriter" => body.push(SimulationBody::EventWriter(EventWriter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Simulation.") + t => panic!("Unexpected tag {} in body of Simulation.", t) }; } Simulation { @@ -1240,7 +1240,7 @@ impl XML for Structure { "With" => body.push(StructureBody::With(With::from_node(&child))), "Tunnel" => body.push(StructureBody::Tunnel(Tunnel::from_node(&child))), "EventConnection" => body.push(StructureBody::EventConnection(EventConnection::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Structure.") + t => panic!("Unexpected tag {} in body of Structure.", t) }; } Structure { @@ -1346,7 +1346,7 @@ impl XML for Tunnel { } match child.tag_name().name() { "Assign" => body.push(TunnelBody::Assign(Assign::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Tunnel.") + t => panic!("Unexpected tag {} in body of Tunnel.", t) }; } Tunnel { diff --git a/src/main.rs b/src/main.rs index 62234ef..888cae4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,11 +55,17 @@ enum Cmd { }, /// DWIM creation of an Arbor simulation template Bundle { - /// NeuroML2 compliant XML file + /// NeuroML2 compliant XML files nml: String, /// Try to combine channels per segment group #[clap(short, long)] super_mechanisms: bool, + /// Export a C++ simulation file + #[clap(long)] + cxx: bool, + /// Export a Python simulation file + #[clap(long, default_value = "true")] + py: bool, /// Change catalogue prefix. /// Set to empty string if mechanisms do not collide with internal mechanisms #[clap(short, long, default_value = "local_")] @@ -122,15 +128,21 @@ fn main() -> Result<()> { dir, super_mechanisms, cat_prefix, + cxx, + py, } => { - get_runtime_types(&mut lems, &[nml.clone()])?; + get_runtime_types(&mut lems, &[nml.to_string()])?; bundle::export( &lems, &[nml], - &dir, - super_mechanisms, &ions[..], - &cat_prefix, + bundle::Bundle { + dir, + cxx, + py, + super_mechanisms, + cat_prefix, + }, )?; } } diff --git a/src/network.rs b/src/network.rs index 1e8d551..926d714 100644 --- a/src/network.rs +++ b/src/network.rs @@ -13,13 +13,15 @@ use crate::{ #[derive(Clone, Debug)] pub struct Network { - pub temperature: f64, + pub name: String, + pub temperature: Option, pub inputs: Vec, pub populations: Map, pub projections: Vec, } #[derive(Clone, Debug)] +#[non_exhaustive] pub struct Input { /// id of source pub source: String, @@ -74,13 +76,11 @@ impl Network { .as_deref() .ok_or_else(|| nml2_error!("Instance has no id attribute."))? .to_string(); - let temperature = if let Some(t) = inst.attributes.get("temperature") { - t.parse::() - .map_err(|_| nml2_error!("Could not parse T='{}'", t))? - } else { - warn!("No temperature given, resorting to 0K!"); - 0.0 - }; + + let temperature = inst + .attributes + .get("temperature") + .and_then(|t| t.parse::().ok()); let populations = if let Some(pops) = inst.children.get("populations") { get_populations(pops)? @@ -101,6 +101,7 @@ impl Network { Vec::new() }; Ok(Network { + name: id, temperature, inputs, populations, diff --git a/src/neuroml/raw.rs b/src/neuroml/raw.rs index 00c35e5..377d1b8 100644 --- a/src/neuroml/raw.rs +++ b/src/neuroml/raw.rs @@ -58,7 +58,7 @@ impl XML for AdExIaFCell { "notes" => body.push(AdExIaFCellBody::notes(String::from_node(&child))), "property" => body.push(AdExIaFCellBody::property(Property::from_node(&child))), "annotation" => body.push(AdExIaFCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of AdExIaFCell.") + t => panic!("Unexpected tag {} in body of AdExIaFCell.", t) }; } AdExIaFCell { @@ -114,7 +114,7 @@ impl XML for AlphaCondSynapse { "notes" => body.push(AlphaCondSynapseBody::notes(String::from_node(&child))), "property" => body.push(AlphaCondSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(AlphaCondSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of AlphaCondSynapse.") + t => panic!("Unexpected tag {} in body of AlphaCondSynapse.", t) }; } AlphaCondSynapse { @@ -159,7 +159,7 @@ impl XML for AlphaCurrSynapse { "notes" => body.push(AlphaCurrSynapseBody::notes(String::from_node(&child))), "property" => body.push(AlphaCurrSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(AlphaCurrSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of AlphaCurrSynapse.") + t => panic!("Unexpected tag {} in body of AlphaCurrSynapse.", t) }; } AlphaCurrSynapse { @@ -205,7 +205,7 @@ impl XML for AlphaCurrentSynapse { "notes" => body.push(AlphaCurrentSynapseBody::notes(String::from_node(&child))), "property" => body.push(AlphaCurrentSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(AlphaCurrentSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of AlphaCurrentSynapse.") + t => panic!("Unexpected tag {} in body of AlphaCurrentSynapse.", t) }; } AlphaCurrentSynapse { @@ -254,7 +254,7 @@ impl XML for AlphaSynapse { "notes" => body.push(AlphaSynapseBody::notes(String::from_node(&child))), "property" => body.push(AlphaSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(AlphaSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of AlphaSynapse.") + t => panic!("Unexpected tag {} in body of AlphaSynapse.", t) }; } AlphaSynapse { @@ -326,7 +326,7 @@ impl XML for BaseCell { "notes" => body.push(BaseCellBody::notes(String::from_node(&child))), "property" => body.push(BaseCellBody::property(Property::from_node(&child))), "annotation" => body.push(BaseCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BaseCell.") + t => panic!("Unexpected tag {} in body of BaseCell.", t) }; } BaseCell { @@ -369,7 +369,7 @@ impl XML for BaseCellMembPotCap { "notes" => body.push(BaseCellMembPotCapBody::notes(String::from_node(&child))), "property" => body.push(BaseCellMembPotCapBody::property(Property::from_node(&child))), "annotation" => body.push(BaseCellMembPotCapBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BaseCellMembPotCap.") + t => panic!("Unexpected tag {} in body of BaseCellMembPotCap.", t) }; } BaseCellMembPotCap { @@ -415,7 +415,7 @@ impl XML for BaseConductanceBasedSynapse { "notes" => body.push(BaseConductanceBasedSynapseBody::notes(String::from_node(&child))), "property" => body.push(BaseConductanceBasedSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(BaseConductanceBasedSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BaseConductanceBasedSynapse.") + t => panic!("Unexpected tag {} in body of BaseConductanceBasedSynapse.", t) }; } BaseConductanceBasedSynapse { @@ -464,7 +464,7 @@ impl XML for BaseConductanceBasedSynapseTwo { "notes" => body.push(BaseConductanceBasedSynapseTwoBody::notes(String::from_node(&child))), "property" => body.push(BaseConductanceBasedSynapseTwoBody::property(Property::from_node(&child))), "annotation" => body.push(BaseConductanceBasedSynapseTwoBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BaseConductanceBasedSynapseTwo.") + t => panic!("Unexpected tag {} in body of BaseConductanceBasedSynapseTwo.", t) }; } BaseConductanceBasedSynapseTwo { @@ -595,7 +595,7 @@ impl XML for BaseCurrentBasedSynapse { "notes" => body.push(BaseCurrentBasedSynapseBody::notes(String::from_node(&child))), "property" => body.push(BaseCurrentBasedSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(BaseCurrentBasedSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BaseCurrentBasedSynapse.") + t => panic!("Unexpected tag {} in body of BaseCurrentBasedSynapse.", t) }; } BaseCurrentBasedSynapse { @@ -678,7 +678,7 @@ impl XML for BasePynnSynapse { "notes" => body.push(BasePynnSynapseBody::notes(String::from_node(&child))), "property" => body.push(BasePynnSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(BasePynnSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BasePynnSynapse.") + t => panic!("Unexpected tag {} in body of BasePynnSynapse.", t) }; } BasePynnSynapse { @@ -720,7 +720,7 @@ impl XML for BaseSynapse { "notes" => body.push(BaseSynapseBody::notes(String::from_node(&child))), "property" => body.push(BaseSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(BaseSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BaseSynapse.") + t => panic!("Unexpected tag {} in body of BaseSynapse.", t) }; } BaseSynapse { @@ -761,7 +761,7 @@ impl XML for BaseVoltageDepSynapse { "notes" => body.push(BaseVoltageDepSynapseBody::notes(String::from_node(&child))), "property" => body.push(BaseVoltageDepSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(BaseVoltageDepSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BaseVoltageDepSynapse.") + t => panic!("Unexpected tag {} in body of BaseVoltageDepSynapse.", t) }; } BaseVoltageDepSynapse { @@ -822,7 +822,7 @@ impl XML for BiophysicalProperties { "notes" => body.push(BiophysicalPropertiesBody::notes(String::from_node(&child))), "property" => body.push(BiophysicalPropertiesBody::property(Property::from_node(&child))), "annotation" => body.push(BiophysicalPropertiesBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BiophysicalProperties.") + t => panic!("Unexpected tag {} in body of BiophysicalProperties.", t) }; } BiophysicalProperties { @@ -869,7 +869,7 @@ impl XML for BiophysicalProperties2CaPools { "notes" => body.push(BiophysicalProperties2CaPoolsBody::notes(String::from_node(&child))), "property" => body.push(BiophysicalProperties2CaPoolsBody::property(Property::from_node(&child))), "annotation" => body.push(BiophysicalProperties2CaPoolsBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BiophysicalProperties2CaPools.") + t => panic!("Unexpected tag {} in body of BiophysicalProperties2CaPools.", t) }; } BiophysicalProperties2CaPools { @@ -948,7 +948,7 @@ impl XML for BlockingPlasticSynapse { "notes" => body.push(BlockingPlasticSynapseBody::notes(String::from_node(&child))), "property" => body.push(BlockingPlasticSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(BlockingPlasticSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of BlockingPlasticSynapse.") + t => panic!("Unexpected tag {} in body of BlockingPlasticSynapse.", t) }; } BlockingPlasticSynapse { @@ -1018,7 +1018,7 @@ impl XML for Cell { "notes" => body.push(CellBody::notes(String::from_node(&child))), "property" => body.push(CellBody::property(Property::from_node(&child))), "annotation" => body.push(CellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Cell.") + t => panic!("Unexpected tag {} in body of Cell.", t) }; } Cell { @@ -1071,7 +1071,7 @@ impl XML for Cell2CaPools { "notes" => body.push(Cell2CaPoolsBody::notes(String::from_node(&child))), "property" => body.push(Cell2CaPoolsBody::property(Property::from_node(&child))), "annotation" => body.push(Cell2CaPoolsBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Cell2CaPools.") + t => panic!("Unexpected tag {} in body of Cell2CaPools.", t) }; } Cell2CaPools { @@ -1140,7 +1140,7 @@ impl XML for ChannelDensity { } match child.tag_name().name() { "variableParameter" => body.push(ChannelDensityBody::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelDensity.") + t => panic!("Unexpected tag {} in body of ChannelDensity.", t) }; } ChannelDensity { @@ -1254,7 +1254,7 @@ impl XML for ChannelDensityNernst { } match child.tag_name().name() { "variableParameter" => body.push(ChannelDensityNernstBody::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelDensityNernst.") + t => panic!("Unexpected tag {} in body of ChannelDensityNernst.", t) }; } ChannelDensityNernst { @@ -1303,7 +1303,7 @@ impl XML for ChannelDensityNernstCa2 { } match child.tag_name().name() { "variableParameter" => body.push(ChannelDensityNernstCa2Body::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelDensityNernstCa2.") + t => panic!("Unexpected tag {} in body of ChannelDensityNernstCa2.", t) }; } ChannelDensityNernstCa2 { @@ -1348,7 +1348,7 @@ impl XML for ChannelDensityNonUniform { } match child.tag_name().name() { "variableParameter" => body.push(ChannelDensityNonUniformBody::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelDensityNonUniform.") + t => panic!("Unexpected tag {} in body of ChannelDensityNonUniform.", t) }; } ChannelDensityNonUniform { @@ -1389,7 +1389,7 @@ impl XML for ChannelDensityNonUniformGHK { } match child.tag_name().name() { "variableParameter" => body.push(ChannelDensityNonUniformGHKBody::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelDensityNonUniformGHK.") + t => panic!("Unexpected tag {} in body of ChannelDensityNonUniformGHK.", t) }; } ChannelDensityNonUniformGHK { @@ -1429,7 +1429,7 @@ impl XML for ChannelDensityNonUniformNernst { } match child.tag_name().name() { "variableParameter" => body.push(ChannelDensityNonUniformNernstBody::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelDensityNonUniformNernst.") + t => panic!("Unexpected tag {} in body of ChannelDensityNonUniformNernst.", t) }; } ChannelDensityNonUniformNernst { @@ -1479,7 +1479,7 @@ impl XML for ChannelDensityVShift { } match child.tag_name().name() { "variableParameter" => body.push(ChannelDensityVShiftBody::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelDensityVShift.") + t => panic!("Unexpected tag {} in body of ChannelDensityVShift.", t) }; } ChannelDensityVShift { @@ -1532,7 +1532,7 @@ impl XML for ChannelPopulation { } match child.tag_name().name() { "variableParameter" => body.push(ChannelPopulationBody::variableParameter(VariableParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ChannelPopulation.") + t => panic!("Unexpected tag {} in body of ChannelPopulation.", t) }; } ChannelPopulation { @@ -1603,7 +1603,7 @@ impl XML for ComponentType { "Requirement" => body.push(ComponentTypeBody::Requirement(Requirement::from_node(&child))), "InstanceRequirement" => body.push(ComponentTypeBody::InstanceRequirement(InstanceRequirement::from_node(&child))), "Dynamics" => body.push(ComponentTypeBody::Dynamics(Dynamics::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ComponentType.") + t => panic!("Unexpected tag {} in body of ComponentType.", t) }; } ComponentType { @@ -1650,7 +1650,7 @@ impl XML for CompoundInput { "notes" => body.push(CompoundInputBody::notes(String::from_node(&child))), "property" => body.push(CompoundInputBody::property(Property::from_node(&child))), "annotation" => body.push(CompoundInputBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of CompoundInput.") + t => panic!("Unexpected tag {} in body of CompoundInput.", t) }; } CompoundInput { @@ -1697,7 +1697,7 @@ impl XML for CompoundInputDL { "notes" => body.push(CompoundInputDLBody::notes(String::from_node(&child))), "property" => body.push(CompoundInputDLBody::property(Property::from_node(&child))), "annotation" => body.push(CompoundInputDLBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of CompoundInputDL.") + t => panic!("Unexpected tag {} in body of CompoundInputDL.", t) }; } CompoundInputDL { @@ -1736,7 +1736,7 @@ impl XML for ConditionalDerivedVariable { } match child.tag_name().name() { "Case" => body.push(ConditionalDerivedVariableBody::Case(Case::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ConditionalDerivedVariable.") + t => panic!("Unexpected tag {} in body of ConditionalDerivedVariable.", t) }; } ConditionalDerivedVariable { @@ -2005,7 +2005,7 @@ impl XML for ContinuousProjection { "continuousConnection" => body.push(ContinuousProjectionBody::continuousConnection(ContinuousConnection::from_node(&child))), "continuousConnectionInstance" => body.push(ContinuousProjectionBody::continuousConnectionInstance(ContinuousConnectionInstance::from_node(&child))), "continuousConnectionInstanceW" => body.push(ContinuousProjectionBody::continuousConnectionInstanceW(ContinuousConnectionInstanceW::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ContinuousProjection.") + t => panic!("Unexpected tag {} in body of ContinuousProjection.", t) }; } ContinuousProjection { @@ -2055,7 +2055,7 @@ impl XML for DecayingPoolConcentrationModel { "notes" => body.push(DecayingPoolConcentrationModelBody::notes(String::from_node(&child))), "property" => body.push(DecayingPoolConcentrationModelBody::property(Property::from_node(&child))), "annotation" => body.push(DecayingPoolConcentrationModelBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of DecayingPoolConcentrationModel.") + t => panic!("Unexpected tag {} in body of DecayingPoolConcentrationModel.", t) }; } DecayingPoolConcentrationModel { @@ -2151,7 +2151,7 @@ impl XML for DoubleSynapse { "notes" => body.push(DoubleSynapseBody::notes(String::from_node(&child))), "property" => body.push(DoubleSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(DoubleSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of DoubleSynapse.") + t => panic!("Unexpected tag {} in body of DoubleSynapse.", t) }; } DoubleSynapse { @@ -2192,7 +2192,7 @@ impl XML for Dynamics { "DerivedVariable" => body.push(DynamicsBody::DerivedVariable(DerivedVariable::from_node(&child))), "ConditionalDerivedVariable" => body.push(DynamicsBody::ConditionalDerivedVariable(ConditionalDerivedVariable::from_node(&child))), "TimeDerivative" => body.push(DynamicsBody::TimeDerivative(TimeDerivative::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Dynamics.") + t => panic!("Unexpected tag {} in body of Dynamics.", t) }; } Dynamics { @@ -2264,7 +2264,7 @@ impl XML for EIF_cond_alpha_isfa_ista { "notes" => body.push(EIF_cond_alpha_isfa_istaBody::notes(String::from_node(&child))), "property" => body.push(EIF_cond_alpha_isfa_istaBody::property(Property::from_node(&child))), "annotation" => body.push(EIF_cond_alpha_isfa_istaBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of EIF_cond_alpha_isfa_ista.") + t => panic!("Unexpected tag {} in body of EIF_cond_alpha_isfa_ista.", t) }; } EIF_cond_alpha_isfa_ista { @@ -2356,7 +2356,7 @@ impl XML for EIF_cond_exp_isfa_ista { "notes" => body.push(EIF_cond_exp_isfa_istaBody::notes(String::from_node(&child))), "property" => body.push(EIF_cond_exp_isfa_istaBody::property(Property::from_node(&child))), "annotation" => body.push(EIF_cond_exp_isfa_istaBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of EIF_cond_exp_isfa_ista.") + t => panic!("Unexpected tag {} in body of EIF_cond_exp_isfa_ista.", t) }; } EIF_cond_exp_isfa_ista { @@ -2533,7 +2533,7 @@ impl XML for ElectricalProjection { "electricalConnection" => body.push(ElectricalProjectionBody::electricalConnection(ElectricalConnection::from_node(&child))), "electricalConnectionInstance" => body.push(ElectricalProjectionBody::electricalConnectionInstance(ElectricalConnectionInstance::from_node(&child))), "electricalConnectionInstanceW" => body.push(ElectricalProjectionBody::electricalConnectionInstanceW(ElectricalConnectionInstanceW::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ElectricalProjection.") + t => panic!("Unexpected tag {} in body of ElectricalProjection.", t) }; } ElectricalProjection { @@ -2579,7 +2579,7 @@ impl XML for ExpCondSynapse { "notes" => body.push(ExpCondSynapseBody::notes(String::from_node(&child))), "property" => body.push(ExpCondSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(ExpCondSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ExpCondSynapse.") + t => panic!("Unexpected tag {} in body of ExpCondSynapse.", t) }; } ExpCondSynapse { @@ -2624,7 +2624,7 @@ impl XML for ExpCurrSynapse { "notes" => body.push(ExpCurrSynapseBody::notes(String::from_node(&child))), "property" => body.push(ExpCurrSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(ExpCurrSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ExpCurrSynapse.") + t => panic!("Unexpected tag {} in body of ExpCurrSynapse.", t) }; } ExpCurrSynapse { @@ -2672,7 +2672,7 @@ impl XML for ExpOneSynapse { "notes" => body.push(ExpOneSynapseBody::notes(String::from_node(&child))), "property" => body.push(ExpOneSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(ExpOneSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ExpOneSynapse.") + t => panic!("Unexpected tag {} in body of ExpOneSynapse.", t) }; } ExpOneSynapse { @@ -2728,7 +2728,7 @@ impl XML for ExpThreeSynapse { "notes" => body.push(ExpThreeSynapseBody::notes(String::from_node(&child))), "property" => body.push(ExpThreeSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(ExpThreeSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ExpThreeSynapse.") + t => panic!("Unexpected tag {} in body of ExpThreeSynapse.", t) }; } ExpThreeSynapse { @@ -2783,7 +2783,7 @@ impl XML for ExpTwoSynapse { "notes" => body.push(ExpTwoSynapseBody::notes(String::from_node(&child))), "property" => body.push(ExpTwoSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(ExpTwoSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ExpTwoSynapse.") + t => panic!("Unexpected tag {} in body of ExpTwoSynapse.", t) }; } ExpTwoSynapse { @@ -2862,7 +2862,7 @@ impl XML for ExtracellularProperties { } match child.tag_name().name() { "species" => body.push(ExtracellularPropertiesBody::species(Species::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ExtracellularProperties.") + t => panic!("Unexpected tag {} in body of ExtracellularProperties.", t) }; } ExtracellularProperties { @@ -2892,7 +2892,7 @@ impl XML for ExtracellularPropertiesLocal { } match child.tag_name().name() { "species" => body.push(ExtracellularPropertiesLocalBody::species(Species::from_node(&child))), - t => panic!("Unexpected tag {t} in body of ExtracellularPropertiesLocal.") + t => panic!("Unexpected tag {} in body of ExtracellularPropertiesLocal.", t) }; } ExtracellularPropertiesLocal { @@ -2942,7 +2942,7 @@ impl XML for FitzHughNagumo1969Cell { "notes" => body.push(FitzHughNagumo1969CellBody::notes(String::from_node(&child))), "property" => body.push(FitzHughNagumo1969CellBody::property(Property::from_node(&child))), "annotation" => body.push(FitzHughNagumo1969CellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of FitzHughNagumo1969Cell.") + t => panic!("Unexpected tag {} in body of FitzHughNagumo1969Cell.", t) }; } FitzHughNagumo1969Cell { @@ -2991,7 +2991,7 @@ impl XML for FitzHughNagumoCell { "notes" => body.push(FitzHughNagumoCellBody::notes(String::from_node(&child))), "property" => body.push(FitzHughNagumoCellBody::property(Property::from_node(&child))), "annotation" => body.push(FitzHughNagumoCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of FitzHughNagumoCell.") + t => panic!("Unexpected tag {} in body of FitzHughNagumoCell.", t) }; } FitzHughNagumoCell { @@ -3041,7 +3041,7 @@ impl XML for FixedFactorConcentrationModel { "notes" => body.push(FixedFactorConcentrationModelBody::notes(String::from_node(&child))), "property" => body.push(FixedFactorConcentrationModelBody::property(Property::from_node(&child))), "annotation" => body.push(FixedFactorConcentrationModelBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of FixedFactorConcentrationModel.") + t => panic!("Unexpected tag {} in body of FixedFactorConcentrationModel.", t) }; } FixedFactorConcentrationModel { @@ -3111,7 +3111,7 @@ impl XML for GapJunction { "notes" => body.push(GapJunctionBody::notes(String::from_node(&child))), "property" => body.push(GapJunctionBody::property(Property::from_node(&child))), "annotation" => body.push(GapJunctionBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GapJunction.") + t => panic!("Unexpected tag {} in body of GapJunction.", t) }; } GapJunction { @@ -3153,7 +3153,7 @@ impl XML for GateFractional { "notes" => body.push(GateFractionalBody::notes(String::from_node(&child))), "q10Settings" => body.push(GateFractionalBody::q10Settings(Q10Settings::from_node(&child))), "subGate" => body.push(GateFractionalBody::subGate(GateFractionalSubgate::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateFractional.") + t => panic!("Unexpected tag {} in body of GateFractional.", t) }; } GateFractional { @@ -3196,7 +3196,7 @@ impl XML for GateFractionalSubgate { "q10Settings" => body.push(GateFractionalSubgateBody::q10Settings(Q10Settings::from_node(&child))), "steadyState" => body.push(GateFractionalSubgateBody::steadyState(HHVariable::from_node(&child))), "timeCourse" => body.push(GateFractionalSubgateBody::timeCourse(HHTime::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateFractionalSubgate.") + t => panic!("Unexpected tag {} in body of GateFractionalSubgate.", t) }; } GateFractionalSubgate { @@ -3235,7 +3235,7 @@ impl XML for GateHHInstantaneous { match child.tag_name().name() { "notes" => body.push(GateHHInstantaneousBody::notes(String::from_node(&child))), "steadyState" => body.push(GateHHInstantaneousBody::steadyState(HHVariable::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateHHInstantaneous.") + t => panic!("Unexpected tag {} in body of GateHHInstantaneous.", t) }; } GateHHInstantaneous { @@ -3278,7 +3278,7 @@ impl XML for GateHHRates { "q10Settings" => body.push(GateHHRatesBody::q10Settings(Q10Settings::from_node(&child))), "forwardRate" => body.push(GateHHRatesBody::forwardRate(HHRate::from_node(&child))), "reverseRate" => body.push(GateHHRatesBody::reverseRate(HHRate::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateHHRates.") + t => panic!("Unexpected tag {} in body of GateHHRates.", t) }; } GateHHRates { @@ -3323,7 +3323,7 @@ impl XML for GateHHRatesInf { "forwardRate" => body.push(GateHHRatesInfBody::forwardRate(HHRate::from_node(&child))), "reverseRate" => body.push(GateHHRatesInfBody::reverseRate(HHRate::from_node(&child))), "steadyState" => body.push(GateHHRatesInfBody::steadyState(HHVariable::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateHHRatesInf.") + t => panic!("Unexpected tag {} in body of GateHHRatesInf.", t) }; } GateHHRatesInf { @@ -3368,7 +3368,7 @@ impl XML for GateHHRatesTau { "forwardRate" => body.push(GateHHRatesTauBody::forwardRate(HHRate::from_node(&child))), "reverseRate" => body.push(GateHHRatesTauBody::reverseRate(HHRate::from_node(&child))), "timeCourse" => body.push(GateHHRatesTauBody::timeCourse(HHTime::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateHHRatesTau.") + t => panic!("Unexpected tag {} in body of GateHHRatesTau.", t) }; } GateHHRatesTau { @@ -3415,7 +3415,7 @@ impl XML for GateHHRatesTauInf { "reverseRate" => body.push(GateHHRatesTauInfBody::reverseRate(HHRate::from_node(&child))), "timeCourse" => body.push(GateHHRatesTauInfBody::timeCourse(HHTime::from_node(&child))), "steadyState" => body.push(GateHHRatesTauInfBody::steadyState(HHVariable::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateHHRatesTauInf.") + t => panic!("Unexpected tag {} in body of GateHHRatesTauInf.", t) }; } GateHHRatesTauInf { @@ -3458,7 +3458,7 @@ impl XML for GateHHTauInf { "q10Settings" => body.push(GateHHTauInfBody::q10Settings(Q10Settings::from_node(&child))), "timeCourse" => body.push(GateHHTauInfBody::timeCourse(HHTime::from_node(&child))), "steadyState" => body.push(GateHHTauInfBody::steadyState(HHVariable::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateHHTauInf.") + t => panic!("Unexpected tag {} in body of GateHHTauInf.", t) }; } GateHHTauInf { @@ -3509,7 +3509,7 @@ impl XML for GateHHUndetermined { "timeCourse" => body.push(GateHHUndeterminedBody::timeCourse(HHTime::from_node(&child))), "steadyState" => body.push(GateHHUndeterminedBody::steadyState(HHVariable::from_node(&child))), "subGate" => body.push(GateHHUndeterminedBody::subGate(GateFractionalSubgate::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateHHUndetermined.") + t => panic!("Unexpected tag {} in body of GateHHUndetermined.", t) }; } GateHHUndetermined { @@ -3559,7 +3559,7 @@ impl XML for GateKS { "forwardTransition" => body.push(GateKSBody::forwardTransition(ForwardTransition::from_node(&child))), "reverseTransition" => body.push(GateKSBody::reverseTransition(ReverseTransition::from_node(&child))), "tauInfTransition" => body.push(GateKSBody::tauInfTransition(TauInfTransition::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GateKS.") + t => panic!("Unexpected tag {} in body of GateKS.", t) }; } GateKS { @@ -3610,7 +3610,7 @@ impl XML for GradedSynapse { "notes" => body.push(GradedSynapseBody::notes(String::from_node(&child))), "property" => body.push(GradedSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(GradedSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of GradedSynapse.") + t => panic!("Unexpected tag {} in body of GradedSynapse.", t) }; } GradedSynapse { @@ -3776,7 +3776,7 @@ impl XML for HH_cond_exp { "notes" => body.push(HH_cond_expBody::notes(String::from_node(&child))), "property" => body.push(HH_cond_expBody::property(Property::from_node(&child))), "annotation" => body.push(HH_cond_expBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of HH_cond_exp.") + t => panic!("Unexpected tag {} in body of HH_cond_exp.", t) }; } HH_cond_exp { @@ -3855,7 +3855,7 @@ impl XML for IF_cond_alpha { "notes" => body.push(IF_cond_alphaBody::notes(String::from_node(&child))), "property" => body.push(IF_cond_alphaBody::property(Property::from_node(&child))), "annotation" => body.push(IF_cond_alphaBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IF_cond_alpha.") + t => panic!("Unexpected tag {} in body of IF_cond_alpha.", t) }; } IF_cond_alpha { @@ -3932,7 +3932,7 @@ impl XML for IF_cond_exp { "notes" => body.push(IF_cond_expBody::notes(String::from_node(&child))), "property" => body.push(IF_cond_expBody::property(Property::from_node(&child))), "annotation" => body.push(IF_cond_expBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IF_cond_exp.") + t => panic!("Unexpected tag {} in body of IF_cond_exp.", t) }; } IF_cond_exp { @@ -4005,7 +4005,7 @@ impl XML for IF_curr_alpha { "notes" => body.push(IF_curr_alphaBody::notes(String::from_node(&child))), "property" => body.push(IF_curr_alphaBody::property(Property::from_node(&child))), "annotation" => body.push(IF_curr_alphaBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IF_curr_alpha.") + t => panic!("Unexpected tag {} in body of IF_curr_alpha.", t) }; } IF_curr_alpha { @@ -4076,7 +4076,7 @@ impl XML for IF_curr_exp { "notes" => body.push(IF_curr_expBody::notes(String::from_node(&child))), "property" => body.push(IF_curr_expBody::property(Property::from_node(&child))), "annotation" => body.push(IF_curr_expBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IF_curr_exp.") + t => panic!("Unexpected tag {} in body of IF_curr_exp.", t) }; } IF_curr_exp { @@ -4137,7 +4137,7 @@ impl XML for IafCell { "notes" => body.push(IafCellBody::notes(String::from_node(&child))), "property" => body.push(IafCellBody::property(Property::from_node(&child))), "annotation" => body.push(IafCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IafCell.") + t => panic!("Unexpected tag {} in body of IafCell.", t) }; } IafCell { @@ -4195,7 +4195,7 @@ impl XML for IafRefCell { "notes" => body.push(IafRefCellBody::notes(String::from_node(&child))), "property" => body.push(IafRefCellBody::property(Property::from_node(&child))), "annotation" => body.push(IafRefCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IafRefCell.") + t => panic!("Unexpected tag {} in body of IafRefCell.", t) }; } IafRefCell { @@ -4250,7 +4250,7 @@ impl XML for IafTauCell { "notes" => body.push(IafTauCellBody::notes(String::from_node(&child))), "property" => body.push(IafTauCellBody::property(Property::from_node(&child))), "annotation" => body.push(IafTauCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IafTauCell.") + t => panic!("Unexpected tag {} in body of IafTauCell.", t) }; } IafTauCell { @@ -4305,7 +4305,7 @@ impl XML for IafTauRefCell { "notes" => body.push(IafTauRefCellBody::notes(String::from_node(&child))), "property" => body.push(IafTauRefCellBody::property(Property::from_node(&child))), "annotation" => body.push(IafTauRefCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IafTauRefCell.") + t => panic!("Unexpected tag {} in body of IafTauRefCell.", t) }; } IafTauRefCell { @@ -4379,7 +4379,7 @@ impl XML for InhomogeneousParameter { match child.tag_name().name() { "proximal" => body.push(InhomogeneousParameterBody::proximal(ProximalDetails::from_node(&child))), "distal" => body.push(InhomogeneousParameterBody::distal(DistalDetails::from_node(&child))), - t => panic!("Unexpected tag {t} in body of InhomogeneousParameter.") + t => panic!("Unexpected tag {} in body of InhomogeneousParameter.", t) }; } InhomogeneousParameter { @@ -4481,7 +4481,7 @@ impl XML for InputList { match child.tag_name().name() { "input" => body.push(InputListBody::input(Input::from_node(&child))), "inputW" => body.push(InputListBody::inputW(InputW::from_node(&child))), - t => panic!("Unexpected tag {t} in body of InputList.") + t => panic!("Unexpected tag {} in body of InputList.", t) }; } InputList { @@ -4550,7 +4550,7 @@ impl XML for Instance { } match child.tag_name().name() { "location" => body.push(InstanceBody::location(Location::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Instance.") + t => panic!("Unexpected tag {} in body of Instance.", t) }; } Instance { @@ -4601,7 +4601,7 @@ impl XML for IntracellularProperties { match child.tag_name().name() { "species" => body.push(IntracellularPropertiesBody::species(Species::from_node(&child))), "resistivity" => body.push(IntracellularPropertiesBody::resistivity(Resistivity::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IntracellularProperties.") + t => panic!("Unexpected tag {} in body of IntracellularProperties.", t) }; } IntracellularProperties { @@ -4631,7 +4631,7 @@ impl XML for IntracellularProperties2CaPools { match child.tag_name().name() { "species" => body.push(IntracellularProperties2CaPoolsBody::species(Species::from_node(&child))), "resistivity" => body.push(IntracellularProperties2CaPoolsBody::resistivity(Resistivity::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IntracellularProperties2CaPools.") + t => panic!("Unexpected tag {} in body of IntracellularProperties2CaPools.", t) }; } IntracellularProperties2CaPools { @@ -4693,7 +4693,7 @@ impl XML for IonChannel { "notes" => body.push(IonChannelBody::notes(String::from_node(&child))), "property" => body.push(IonChannelBody::property(Property::from_node(&child))), "annotation" => body.push(IonChannelBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IonChannel.") + t => panic!("Unexpected tag {} in body of IonChannel.", t) }; } IonChannel { @@ -4761,7 +4761,7 @@ impl XML for IonChannelHH { "notes" => body.push(IonChannelHHBody::notes(String::from_node(&child))), "property" => body.push(IonChannelHHBody::property(Property::from_node(&child))), "annotation" => body.push(IonChannelHHBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IonChannelHH.") + t => panic!("Unexpected tag {} in body of IonChannelHH.", t) }; } IonChannelHH { @@ -4811,7 +4811,7 @@ impl XML for IonChannelKS { "notes" => body.push(IonChannelKSBody::notes(String::from_node(&child))), "property" => body.push(IonChannelKSBody::property(Property::from_node(&child))), "annotation" => body.push(IonChannelKSBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IonChannelKS.") + t => panic!("Unexpected tag {} in body of IonChannelKS.", t) }; } IonChannelKS { @@ -4856,7 +4856,7 @@ impl XML for IonChannelScalable { "notes" => body.push(IonChannelScalableBody::notes(String::from_node(&child))), "property" => body.push(IonChannelScalableBody::property(Property::from_node(&child))), "annotation" => body.push(IonChannelScalableBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IonChannelScalable.") + t => panic!("Unexpected tag {} in body of IonChannelScalable.", t) }; } IonChannelScalable { @@ -4923,7 +4923,7 @@ impl XML for IonChannelVShift { "notes" => body.push(IonChannelVShiftBody::notes(String::from_node(&child))), "property" => body.push(IonChannelVShiftBody::property(Property::from_node(&child))), "annotation" => body.push(IonChannelVShiftBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IonChannelVShift.") + t => panic!("Unexpected tag {} in body of IonChannelVShift.", t) }; } IonChannelVShift { @@ -4988,7 +4988,7 @@ impl XML for Izhikevich2007Cell { "notes" => body.push(Izhikevich2007CellBody::notes(String::from_node(&child))), "property" => body.push(Izhikevich2007CellBody::property(Property::from_node(&child))), "annotation" => body.push(Izhikevich2007CellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Izhikevich2007Cell.") + t => panic!("Unexpected tag {} in body of Izhikevich2007Cell.", t) }; } Izhikevich2007Cell { @@ -5051,7 +5051,7 @@ impl XML for IzhikevichCell { "notes" => body.push(IzhikevichCellBody::notes(String::from_node(&child))), "property" => body.push(IzhikevichCellBody::property(Property::from_node(&child))), "annotation" => body.push(IzhikevichCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of IzhikevichCell.") + t => panic!("Unexpected tag {} in body of IzhikevichCell.", t) }; } IzhikevichCell { @@ -5117,7 +5117,7 @@ impl XML for Layout { "random" => body.push(LayoutBody::random(RandomLayout::from_node(&child))), "grid" => body.push(LayoutBody::grid(GridLayout::from_node(&child))), "unstructured" => body.push(LayoutBody::unstructured(UnstructuredLayout::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Layout.") + t => panic!("Unexpected tag {} in body of Layout.", t) }; } Layout { @@ -5158,7 +5158,7 @@ impl XML for LinearGradedSynapse { "notes" => body.push(LinearGradedSynapseBody::notes(String::from_node(&child))), "property" => body.push(LinearGradedSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(LinearGradedSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of LinearGradedSynapse.") + t => panic!("Unexpected tag {} in body of LinearGradedSynapse.", t) }; } LinearGradedSynapse { @@ -5246,7 +5246,7 @@ impl XML for MembraneProperties { "spikeThresh" => body.push(MembranePropertiesBody::spikeThresh(SpikeThresh::from_node(&child))), "specificCapacitance" => body.push(MembranePropertiesBody::specificCapacitance(SpecificCapacitance::from_node(&child))), "initMembPotential" => body.push(MembranePropertiesBody::initMembPotential(InitMembPotential::from_node(&child))), - t => panic!("Unexpected tag {t} in body of MembraneProperties.") + t => panic!("Unexpected tag {} in body of MembraneProperties.", t) }; } MembraneProperties { @@ -5298,7 +5298,7 @@ impl XML for MembraneProperties2CaPools { "spikeThresh" => body.push(MembraneProperties2CaPoolsBody::spikeThresh(SpikeThresh::from_node(&child))), "specificCapacitance" => body.push(MembraneProperties2CaPoolsBody::specificCapacitance(SpecificCapacitance::from_node(&child))), "initMembPotential" => body.push(MembraneProperties2CaPoolsBody::initMembPotential(InitMembPotential::from_node(&child))), - t => panic!("Unexpected tag {t} in body of MembraneProperties2CaPools.") + t => panic!("Unexpected tag {} in body of MembraneProperties2CaPools.", t) }; } MembraneProperties2CaPools { @@ -5340,7 +5340,7 @@ impl XML for Morphology { "notes" => body.push(MorphologyBody::notes(String::from_node(&child))), "property" => body.push(MorphologyBody::property(Property::from_node(&child))), "annotation" => body.push(MorphologyBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Morphology.") + t => panic!("Unexpected tag {} in body of Morphology.", t) }; } Morphology { @@ -5450,7 +5450,7 @@ impl XML for Network { "notes" => body.push(NetworkBody::notes(String::from_node(&child))), "property" => body.push(NetworkBody::property(Property::from_node(&child))), "annotation" => body.push(NetworkBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Network.") + t => panic!("Unexpected tag {} in body of Network.", t) }; } Network { @@ -5627,7 +5627,7 @@ impl XML for NeuroMLDocument { "notes" => body.push(NeuroMLDocumentBody::notes(String::from_node(&child))), "property" => body.push(NeuroMLDocumentBody::property(Property::from_node(&child))), "annotation" => body.push(NeuroMLDocumentBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of NeuroMLDocument.") + t => panic!("Unexpected tag {} in body of NeuroMLDocument.", t) }; } NeuroMLDocument { @@ -5697,7 +5697,7 @@ impl XML for Path { match child.tag_name().name() { "from" => body.push(PathBody::from(SegmentEndPoint::from_node(&child))), "to" => body.push(PathBody::to(SegmentEndPoint::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Path.") + t => panic!("Unexpected tag {} in body of Path.", t) }; } Path { @@ -5777,7 +5777,7 @@ impl XML for PinskyRinzelCA3Cell { "notes" => body.push(PinskyRinzelCA3CellBody::notes(String::from_node(&child))), "property" => body.push(PinskyRinzelCA3CellBody::property(Property::from_node(&child))), "annotation" => body.push(PinskyRinzelCA3CellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of PinskyRinzelCA3Cell.") + t => panic!("Unexpected tag {} in body of PinskyRinzelCA3Cell.", t) }; } PinskyRinzelCA3Cell { @@ -5891,7 +5891,7 @@ impl XML for PoissonFiringSynapse { "notes" => body.push(PoissonFiringSynapseBody::notes(String::from_node(&child))), "property" => body.push(PoissonFiringSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(PoissonFiringSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of PoissonFiringSynapse.") + t => panic!("Unexpected tag {} in body of PoissonFiringSynapse.", t) }; } PoissonFiringSynapse { @@ -5947,7 +5947,7 @@ impl XML for Population { "notes" => body.push(PopulationBody::notes(String::from_node(&child))), "property" => body.push(PopulationBody::property(Property::from_node(&child))), "annotation" => body.push(PopulationBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Population.") + t => panic!("Unexpected tag {} in body of Population.", t) }; } Population { @@ -5994,7 +5994,7 @@ impl XML for Projection { match child.tag_name().name() { "connection" => body.push(ProjectionBody::connection(Connection::from_node(&child))), "connectionWD" => body.push(ProjectionBody::connectionWD(ConnectionWD::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Projection.") + t => panic!("Unexpected tag {} in body of Projection.", t) }; } Projection { @@ -6074,7 +6074,7 @@ impl XML for PulseGenerator { "notes" => body.push(PulseGeneratorBody::notes(String::from_node(&child))), "property" => body.push(PulseGeneratorBody::property(Property::from_node(&child))), "annotation" => body.push(PulseGeneratorBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of PulseGenerator.") + t => panic!("Unexpected tag {} in body of PulseGenerator.", t) }; } PulseGenerator { @@ -6124,7 +6124,7 @@ impl XML for PulseGeneratorDL { "notes" => body.push(PulseGeneratorDLBody::notes(String::from_node(&child))), "property" => body.push(PulseGeneratorDLBody::property(Property::from_node(&child))), "annotation" => body.push(PulseGeneratorDLBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of PulseGeneratorDL.") + t => panic!("Unexpected tag {} in body of PulseGeneratorDL.", t) }; } PulseGeneratorDL { @@ -6218,7 +6218,7 @@ impl XML for RampGenerator { "notes" => body.push(RampGeneratorBody::notes(String::from_node(&child))), "property" => body.push(RampGeneratorBody::property(Property::from_node(&child))), "annotation" => body.push(RampGeneratorBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of RampGenerator.") + t => panic!("Unexpected tag {} in body of RampGenerator.", t) }; } RampGenerator { @@ -6274,7 +6274,7 @@ impl XML for RampGeneratorDL { "notes" => body.push(RampGeneratorDLBody::notes(String::from_node(&child))), "property" => body.push(RampGeneratorDLBody::property(Property::from_node(&child))), "annotation" => body.push(RampGeneratorDLBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of RampGeneratorDL.") + t => panic!("Unexpected tag {} in body of RampGeneratorDL.", t) }; } RampGeneratorDL { @@ -6440,7 +6440,7 @@ impl XML for Segment { "parent" => body.push(SegmentBody::parent(SegmentParent::from_node(&child))), "proximal" => body.push(SegmentBody::proximal(Point3DWithDiam::from_node(&child))), "distal" => body.push(SegmentBody::distal(Point3DWithDiam::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Segment.") + t => panic!("Unexpected tag {} in body of Segment.", t) }; } Segment { @@ -6503,7 +6503,7 @@ impl XML for SegmentGroup { "path" => body.push(SegmentGroupBody::path(Path::from_node(&child))), "subTree" => body.push(SegmentGroupBody::subTree(SubTree::from_node(&child))), "inhomogeneousParameter" => body.push(SegmentGroupBody::inhomogeneousParameter(InhomogeneousParameter::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SegmentGroup.") + t => panic!("Unexpected tag {} in body of SegmentGroup.", t) }; } SegmentGroup { @@ -6560,7 +6560,7 @@ impl XML for SilentSynapse { "notes" => body.push(SilentSynapseBody::notes(String::from_node(&child))), "property" => body.push(SilentSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(SilentSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SilentSynapse.") + t => panic!("Unexpected tag {} in body of SilentSynapse.", t) }; } SilentSynapse { @@ -6611,7 +6611,7 @@ impl XML for SineGenerator { "notes" => body.push(SineGeneratorBody::notes(String::from_node(&child))), "property" => body.push(SineGeneratorBody::property(Property::from_node(&child))), "annotation" => body.push(SineGeneratorBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SineGenerator.") + t => panic!("Unexpected tag {} in body of SineGenerator.", t) }; } SineGenerator { @@ -6667,7 +6667,7 @@ impl XML for SineGeneratorDL { "notes" => body.push(SineGeneratorDLBody::notes(String::from_node(&child))), "property" => body.push(SineGeneratorDLBody::property(Property::from_node(&child))), "annotation" => body.push(SineGeneratorDLBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SineGeneratorDL.") + t => panic!("Unexpected tag {} in body of SineGeneratorDL.", t) }; } SineGeneratorDL { @@ -6709,7 +6709,7 @@ impl XML for Space { } match child.tag_name().name() { "structure" => body.push(SpaceBody::structure(SpaceStructure::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Space.") + t => panic!("Unexpected tag {} in body of Space.", t) }; } Space { @@ -6847,7 +6847,7 @@ impl XML for SpikeArray { "notes" => body.push(SpikeArrayBody::notes(String::from_node(&child))), "property" => body.push(SpikeArrayBody::property(Property::from_node(&child))), "annotation" => body.push(SpikeArrayBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SpikeArray.") + t => panic!("Unexpected tag {} in body of SpikeArray.", t) }; } SpikeArray { @@ -6890,7 +6890,7 @@ impl XML for SpikeGenerator { "notes" => body.push(SpikeGeneratorBody::notes(String::from_node(&child))), "property" => body.push(SpikeGeneratorBody::property(Property::from_node(&child))), "annotation" => body.push(SpikeGeneratorBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SpikeGenerator.") + t => panic!("Unexpected tag {} in body of SpikeGenerator.", t) }; } SpikeGenerator { @@ -6934,7 +6934,7 @@ impl XML for SpikeGeneratorPoisson { "notes" => body.push(SpikeGeneratorPoissonBody::notes(String::from_node(&child))), "property" => body.push(SpikeGeneratorPoissonBody::property(Property::from_node(&child))), "annotation" => body.push(SpikeGeneratorPoissonBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SpikeGeneratorPoisson.") + t => panic!("Unexpected tag {} in body of SpikeGeneratorPoisson.", t) }; } SpikeGeneratorPoisson { @@ -6980,7 +6980,7 @@ impl XML for SpikeGeneratorRandom { "notes" => body.push(SpikeGeneratorRandomBody::notes(String::from_node(&child))), "property" => body.push(SpikeGeneratorRandomBody::property(Property::from_node(&child))), "annotation" => body.push(SpikeGeneratorRandomBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SpikeGeneratorRandom.") + t => panic!("Unexpected tag {} in body of SpikeGeneratorRandom.", t) }; } SpikeGeneratorRandom { @@ -7027,7 +7027,7 @@ impl XML for SpikeGeneratorRefPoisson { "notes" => body.push(SpikeGeneratorRefPoissonBody::notes(String::from_node(&child))), "property" => body.push(SpikeGeneratorRefPoissonBody::property(Property::from_node(&child))), "annotation" => body.push(SpikeGeneratorRefPoissonBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SpikeGeneratorRefPoisson.") + t => panic!("Unexpected tag {} in body of SpikeGeneratorRefPoisson.", t) }; } SpikeGeneratorRefPoisson { @@ -7076,7 +7076,7 @@ impl XML for SpikeSourcePoisson { "notes" => body.push(SpikeSourcePoissonBody::notes(String::from_node(&child))), "property" => body.push(SpikeSourcePoissonBody::property(Property::from_node(&child))), "annotation" => body.push(SpikeSourcePoissonBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SpikeSourcePoisson.") + t => panic!("Unexpected tag {} in body of SpikeSourcePoisson.", t) }; } SpikeSourcePoisson { @@ -7137,7 +7137,7 @@ impl XML for Standalone { "notes" => body.push(StandaloneBody::notes(String::from_node(&child))), "property" => body.push(StandaloneBody::property(Property::from_node(&child))), "annotation" => body.push(StandaloneBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of Standalone.") + t => panic!("Unexpected tag {} in body of Standalone.", t) }; } Standalone { @@ -7193,7 +7193,7 @@ impl XML for SubTree { match child.tag_name().name() { "from" => body.push(SubTreeBody::from(SegmentEndPoint::from_node(&child))), "to" => body.push(SubTreeBody::to(SegmentEndPoint::from_node(&child))), - t => panic!("Unexpected tag {t} in body of SubTree.") + t => panic!("Unexpected tag {} in body of SubTree.", t) }; } SubTree { @@ -7254,7 +7254,7 @@ impl XML for TauInfTransition { match child.tag_name().name() { "steadyState" => body.push(TauInfTransitionBody::steadyState(HHVariable::from_node(&child))), "timeCourse" => body.push(TauInfTransitionBody::timeCourse(HHTime::from_node(&child))), - t => panic!("Unexpected tag {t} in body of TauInfTransition.") + t => panic!("Unexpected tag {} in body of TauInfTransition.", t) }; } TauInfTransition { @@ -7319,7 +7319,7 @@ impl XML for TimedSynapticInput { "notes" => body.push(TimedSynapticInputBody::notes(String::from_node(&child))), "property" => body.push(TimedSynapticInputBody::property(Property::from_node(&child))), "annotation" => body.push(TimedSynapticInputBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of TimedSynapticInput.") + t => panic!("Unexpected tag {} in body of TimedSynapticInput.", t) }; } TimedSynapticInput { @@ -7372,7 +7372,7 @@ impl XML for TransientPoissonFiringSynapse { "notes" => body.push(TransientPoissonFiringSynapseBody::notes(String::from_node(&child))), "property" => body.push(TransientPoissonFiringSynapseBody::property(Property::from_node(&child))), "annotation" => body.push(TransientPoissonFiringSynapseBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of TransientPoissonFiringSynapse.") + t => panic!("Unexpected tag {} in body of TransientPoissonFiringSynapse.", t) }; } TransientPoissonFiringSynapse { @@ -7426,7 +7426,7 @@ impl XML for VariableParameter { } match child.tag_name().name() { "inhomogeneousValue" => body.push(VariableParameterBody::inhomogeneousValue(InhomogeneousValue::from_node(&child))), - t => panic!("Unexpected tag {t} in body of VariableParameter.") + t => panic!("Unexpected tag {} in body of VariableParameter.", t) }; } VariableParameter { @@ -7474,7 +7474,7 @@ impl XML for VoltageClamp { "notes" => body.push(VoltageClampBody::notes(String::from_node(&child))), "property" => body.push(VoltageClampBody::property(Property::from_node(&child))), "annotation" => body.push(VoltageClampBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of VoltageClamp.") + t => panic!("Unexpected tag {} in body of VoltageClamp.", t) }; } VoltageClamp { @@ -7533,7 +7533,7 @@ impl XML for VoltageClampTriple { "notes" => body.push(VoltageClampTripleBody::notes(String::from_node(&child))), "property" => body.push(VoltageClampTripleBody::property(Property::from_node(&child))), "annotation" => body.push(VoltageClampTripleBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of VoltageClampTriple.") + t => panic!("Unexpected tag {} in body of VoltageClampTriple.", t) }; } VoltageClampTriple { @@ -7591,7 +7591,7 @@ impl XML for basePyNNCell { "notes" => body.push(basePyNNCellBody::notes(String::from_node(&child))), "property" => body.push(basePyNNCellBody::property(Property::from_node(&child))), "annotation" => body.push(basePyNNCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of basePyNNCell.") + t => panic!("Unexpected tag {} in body of basePyNNCell.", t) }; } basePyNNCell { @@ -7657,7 +7657,7 @@ impl XML for basePyNNIaFCell { "notes" => body.push(basePyNNIaFCellBody::notes(String::from_node(&child))), "property" => body.push(basePyNNIaFCellBody::property(Property::from_node(&child))), "annotation" => body.push(basePyNNIaFCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of basePyNNIaFCell.") + t => panic!("Unexpected tag {} in body of basePyNNIaFCell.", t) }; } basePyNNIaFCell { @@ -7732,7 +7732,7 @@ impl XML for basePyNNIaFCondCell { "notes" => body.push(basePyNNIaFCondCellBody::notes(String::from_node(&child))), "property" => body.push(basePyNNIaFCondCellBody::property(Property::from_node(&child))), "annotation" => body.push(basePyNNIaFCondCellBody::annotation(Annotation::from_node(&child))), - t => panic!("Unexpected tag {t} in body of basePyNNIaFCondCell.") + t => panic!("Unexpected tag {} in body of basePyNNIaFCondCell.", t) }; } basePyNNIaFCondCell { diff --git a/src/nmodl.rs b/src/nmodl.rs index cdef96d..aa064f6 100644 --- a/src/nmodl.rs +++ b/src/nmodl.rs @@ -239,8 +239,6 @@ impl Nmodl { .into_iter(), ); - parameters.insert(String::from("celsius"), None); - let mut symbols: Set<_> = [ String::from("v"), String::from("celsius"), @@ -581,7 +579,7 @@ fn nmodl_break_block(n: &Nmodl) -> Result { fn nmodl_param_block(n: &Nmodl) -> Result { let mut ps = n.parameters.clone(); let read = read_variable(n)?; - for p in ["diam"] { + for p in ["diam", "celsius"] { if read.contains(p) { ps.insert(p.to_string(), None); } @@ -765,7 +763,7 @@ fn nmodl_neuron_block(n: &Nmodl) -> Result { match ns.as_slice() { [] => {} [name] => { - result.push(format!(" NONSPECIFIC_CURRENT {}\n", name)); + result.push(format!(" NONSPECIFIC_CURRENT {name}\n")); } _ => { // collapse multiple NONSPECIFIC_CURRENTs into one @@ -858,10 +856,7 @@ fn sorted_dependencies_of( continue 'a; } } - return Err(nmodl_error(format!( - "Could not resolve variables {:?}", - todo - ))); + return Err(nmodl_error(format!("Could not resolve variables {todo:?}"))); } Ok(result) } @@ -1084,8 +1079,7 @@ pub fn to_nmodl( mk_nmodl(n) } _ => Err(nmodl_error(format!( - "Type {} deriving an expected base {}", - ty, base + "Type {ty} deriving an expected base {base}" ))), } } @@ -1093,6 +1087,7 @@ pub fn to_nmodl( fn simplify(variables: &mut Map, fixed: &mut Map, keep: &Set) { loop { let mut new = Map::new(); + // Update constants and a=b assignments for (k, v) in variables.iter() { match v { Stmnt::Ass(k, x @ Expr::F64(_)) if !keep.contains(k) => { @@ -1107,6 +1102,7 @@ fn simplify(variables: &mut Map, fixed: &mut Map, k } } + // Substitute in from simple assignments for v in new.values_mut() { let y = v .map(&|e| { @@ -1124,6 +1120,21 @@ fn simplify(variables: &mut Map, fixed: &mut Map, k *v = y; } + // Now try to de-duplicate RHS as a precursor to CSE + // This is slightly awkward as Expr (and thus Stmnt) cannot be Eq + // nor Ord (just Partial) due to the f64 contained. + let mut unique_assignments: Vec<(String, Expr)> = Vec::new(); + for (k, v) in new.iter_mut() { + if let Stmnt::Ass(_, val) = v { + if let Some(it) = unique_assignments.iter().find(|it| it.1 == *val) { + let res = Stmnt::Ass(k.clone(), Expr::Var(it.0.clone())); + *v = res; + } else { + unique_assignments.push((k.clone(), val.clone())); + } + } + } + if new == *variables { break; } diff --git a/src/schema.rs b/src/schema.rs index 42822a2..079faac 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -461,8 +461,8 @@ fn emit_src(state: &Schema) -> Result { }; ty.push(format!(" pub {name}: {kind},")); nd.push(format!( - " let {} = node.attribute(\"{}\"){}.map({}){};", - name, m.name, default, convert, unwrap + " let {name} = node.attribute(\"{}\"){default}.map({convert}){unwrap};", + m.name )); } match t.body { @@ -484,15 +484,15 @@ fn emit_src(state: &Schema) -> Result { let v = v.to_rs(); bd.push(format!(" {k}({v}),")); lp.push(format!( - " \"{}\" => body.push({}Body::{}({}::from_node(&child))),", - k, t.name, k, v + " \"{k}\" => body.push({}Body::{k}({v}::from_node(&child))),", + t.name )); } else { return Err(format!("Unresolved element {x:?}")); } } lp.push(format!( - " t => panic!(\"Unexpected tag {{}} in body of {}.\", t)", + " t => panic!(\"Unexpected tag {{t}} in body of {}.\")", t.name )); lp.push(String::from(" };")); diff --git a/tests/hay11/.test.jnml.omt b/tests/hay11/.test.jnml.omt new file mode 100644 index 0000000..953ad1d --- /dev/null +++ b/tests/hay11/.test.jnml.omt @@ -0,0 +1,18 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation +# Still in development, subject to change without notice!! + +target: LEMS_L5bPyrCellHayEtAl2011_LowDt.xml +engine: jNeuroML +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: CG_TestCML_0.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.00046 diff --git a/tests/hay11/.test.jnmleden.omt b/tests/hay11/.test.jnmleden.omt new file mode 100644 index 0000000..23eca03 --- /dev/null +++ b/tests/hay11/.test.jnmleden.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/borismarin/osb-model-validation + +target: LEMS_L5bPyrCellHayEtAl2011_LowDt.xml +engine: jNeuroML_EDEN +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: CG_TestCML_0.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.00020152256455791017 diff --git a/tests/hay11/.test.jnmlnetpyne.omt b/tests/hay11/.test.jnmlnetpyne.omt new file mode 100644 index 0000000..43c1de3 --- /dev/null +++ b/tests/hay11/.test.jnmlnetpyne.omt @@ -0,0 +1,18 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation +# Still in development, subject to change without notice!! + +target: LEMS_L5bPyrCellHayEtAl2011_LowDt.xml +engine: jNeuroML_NetPyNE +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: CG_TestCML_0.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0 diff --git a/tests/hay11/.test.jnmlnrn.omt b/tests/hay11/.test.jnmlnrn.omt new file mode 100644 index 0000000..e2e1f5a --- /dev/null +++ b/tests/hay11/.test.jnmlnrn.omt @@ -0,0 +1,18 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation +# Still in development, subject to change without notice!! + +target: LEMS_L5bPyrCellHayEtAl2011_LowDt.xml +engine: jNeuroML_NEURON +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: CG_TestCML_0.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0 diff --git a/tests/hay11/.test.l5b.jnmlnrn.omt b/tests/hay11/.test.l5b.jnmlnrn.omt new file mode 100644 index 0000000..39c8ea3 --- /dev/null +++ b/tests/hay11/.test.l5b.jnmlnrn.omt @@ -0,0 +1,18 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + + +target: LEMS_TestL5PC.xml +engine: jNeuroML_NEURON +mep: ../../NEURON/test/.test.step.mep +experiments: + step: + observables: + spike times: + file: + path: CellGroup_1_0.0.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.013478760097319098 diff --git a/tests/hay11/.test.mep b/tests/hay11/.test.mep new file mode 100644 index 0000000..b699fdb --- /dev/null +++ b/tests/hay11/.test.mep @@ -0,0 +1,6 @@ +system: Testing a single compartment cell + +experiments: + Current clamp: + expected: + spike times: [306.3125, 320.075, 334.6425, 349.9375, 365.5425, 381.2625, 397.0275] diff --git a/tests/hay11/.test.validate.omt b/tests/hay11/.test.validate.omt new file mode 100644 index 0000000..f48c0de --- /dev/null +++ b/tests/hay11/.test.validate.omt @@ -0,0 +1,7 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation +# Still in development, subject to change without notice!! + + +# This test will validate MOST all of the NeuroML 2 files in the current directory +target: "*.c*.nml" +engine: jNeuroML_validate diff --git a/tests/hay11/CaDynamics_E2_NML2.nml b/tests/hay11/CaDynamics_E2_NML2.nml new file mode 100644 index 0000000..c8b21a0 --- /dev/null +++ b/tests/hay11/CaDynamics_E2_NML2.nml @@ -0,0 +1,68 @@ + + + + NeuroML 2 implementation of the Ca Pool mechanism + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/CaDynamics_E2_NML2__decay122__gamma5_09Emin4.nml b/tests/hay11/CaDynamics_E2_NML2__decay122__gamma5_09Emin4.nml new file mode 100644 index 0000000..73d38cb --- /dev/null +++ b/tests/hay11/CaDynamics_E2_NML2__decay122__gamma5_09Emin4.nml @@ -0,0 +1,78 @@ + + + + + + + NeuroML 2 implementation of the Ca Pool mechanism + + + + + + + + + + + + + diff --git a/tests/hay11/CaDynamics_E2_NML2__decay460__gamma5_01Emin4.nml b/tests/hay11/CaDynamics_E2_NML2__decay460__gamma5_01Emin4.nml new file mode 100644 index 0000000..150e9d6 --- /dev/null +++ b/tests/hay11/CaDynamics_E2_NML2__decay460__gamma5_01Emin4.nml @@ -0,0 +1,78 @@ + + + + + + + NeuroML 2 implementation of the Ca Pool mechanism + + + + + + + + + + + + + diff --git a/tests/hay11/Ca_HVA.channel.nml b/tests/hay11/Ca_HVA.channel.nml new file mode 100644 index 0000000..4219413 --- /dev/null +++ b/tests/hay11/Ca_HVA.channel.nml @@ -0,0 +1,49 @@ + + + + NeuroML file containing a single Channel description + + + + High voltage activated Ca2+ current. + +Comment from original mod file: +Reuveni, Friedman, Amitai, and Gutnick, J.Neurosci. 1993 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + Calcium channels + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/Ca_LVAst.channel.nml b/tests/hay11/Ca_LVAst.channel.nml new file mode 100644 index 0000000..886e956 --- /dev/null +++ b/tests/hay11/Ca_LVAst.channel.nml @@ -0,0 +1,76 @@ + + + + NeuroML file containing a single Channel description + + + + Low voltage activated Ca2+ current + +Comment from original mod file: +Note: mtau is an approximation from the plots +:Reference : : Avery and Johnston 1996, tau from Randall 1997 +:Comment: shifted by -10 mv to correct for junction potential +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + Ca channels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/Ih.channel.nml b/tests/hay11/Ih.channel.nml new file mode 100644 index 0000000..5b980df --- /dev/null +++ b/tests/hay11/Ih.channel.nml @@ -0,0 +1,36 @@ + + + + NeuroML file containing a single Channel description + + + + Non-specific cation current + +Comment from original mod file: +Reference : : Kole,Hallermann,and Stuart, J. Neurosci. 2006 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + + + + + + + + + diff --git a/tests/hay11/Im.channel.nml b/tests/hay11/Im.channel.nml new file mode 100644 index 0000000..0dd18fe --- /dev/null +++ b/tests/hay11/Im.channel.nml @@ -0,0 +1,46 @@ + + + + NeuroML file containing a single Channel description + + + + Muscarinic K+ current + +Comment from original mod file: +:Reference : : Adams et al. 1982 - M-currents and other potassium currents in bullfrog sympathetic neurones +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + K channels + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/K_Pst.channel.nml b/tests/hay11/K_Pst.channel.nml new file mode 100644 index 0000000..97caafc --- /dev/null +++ b/tests/hay11/K_Pst.channel.nml @@ -0,0 +1,79 @@ + + + + NeuroML file containing a single Channel description + + + + Slow inactivating K+ current + +Comment from original mod file: +:Comment : The persistent component of the K current +:Reference : : Voltage-gated K+ channels in layer 5 neocortical pyramidal neurones from young rats:subtypes and gradients,Korngreen and Sakmann, J. Physiology, 2000 +:Comment : shifted -10 mv to correct for junction potential +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + K channels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/K_Tst.channel.nml b/tests/hay11/K_Tst.channel.nml new file mode 100644 index 0000000..fa167b8 --- /dev/null +++ b/tests/hay11/K_Tst.channel.nml @@ -0,0 +1,76 @@ + + + + NeuroML file containing a single Channel description + + + + Fast inactivating K+ current + +Comment from original mod file: +:Comment : The transient component of the K current +:Reference : : Voltage-gated K+ channels in layer 5 neocortical pyramidal neurones from young rats:subtypes and gradients,Korngreen and Sakmann, J. Physiology, 2000 +:Comment : shifted -10 mv to correct for junction potential +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + K channels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/L5PC.cell.nml b/tests/hay11/L5PC.cell.nml new file mode 100644 index 0000000..95dcf4f --- /dev/null +++ b/tests/hay11/L5PC.cell.nml @@ -0,0 +1,31902 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cell: L5PCtemplate_0 exported from NEURON ModelView + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/L5PC.cell.nml.bak b/tests/hay11/L5PC.cell.nml.bak new file mode 100644 index 0000000..b32f53e --- /dev/null +++ b/tests/hay11/L5PC.cell.nml.bak @@ -0,0 +1,31902 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cell: L5PCtemplate_0 exported from NEURON ModelView + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/L5bPyrCellHayEtAl2011.net.nml b/tests/hay11/L5bPyrCellHayEtAl2011.net.nml new file mode 100644 index 0000000..c62af6d --- /dev/null +++ b/tests/hay11/L5bPyrCellHayEtAl2011.net.nml @@ -0,0 +1,67 @@ + + + + + +Network structure (NeuroML 2beta3) for project: L5bPyrCellHayEtAl2011 saved with neuroConstruct v1.7.1 on: 13:38:55, 18-Mar-14 + +Cell Group: CG_TestCML contains 1 cells + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/hay11/LEMS_L5bPyrCellHayEtAl2011.xml b/tests/hay11/LEMS_L5bPyrCellHayEtAl2011.xml new file mode 100644 index 0000000..30441fd --- /dev/null +++ b/tests/hay11/LEMS_L5bPyrCellHayEtAl2011.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/hay11/LEMS_L5bPyrCellHayEtAl2011_LowDt.xml b/tests/hay11/LEMS_L5bPyrCellHayEtAl2011_LowDt.xml new file mode 100644 index 0000000..76295ca --- /dev/null +++ b/tests/hay11/LEMS_L5bPyrCellHayEtAl2011_LowDt.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/hay11/LEMS_TestL5PC.xml b/tests/hay11/LEMS_TestL5PC.xml new file mode 100644 index 0000000..0a94370 --- /dev/null +++ b/tests/hay11/LEMS_TestL5PC.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + diff --git a/tests/hay11/NaTa_t.channel.nml b/tests/hay11/NaTa_t.channel.nml new file mode 100644 index 0000000..36bcd19 --- /dev/null +++ b/tests/hay11/NaTa_t.channel.nml @@ -0,0 +1,51 @@ + + + + NeuroML file containing a single Channel description + + + + Fast inactivating Na+ current + +Comment from original mod file: +:Reference :Colbert and Pan 2002 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + Na channels + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/Nap_Et2.channel.nml b/tests/hay11/Nap_Et2.channel.nml new file mode 100644 index 0000000..28f7dd3 --- /dev/null +++ b/tests/hay11/Nap_Et2.channel.nml @@ -0,0 +1,76 @@ + + + + NeuroML file containing a single Channel description + + + + Persistent Na+ current + +Comment from original mod file: +:Comment : mtau deduced from text (said to be 6 times faster than for NaTa) +:Comment : so I used the equations from NaT and multiplied by 6 +:Reference : Modeled according to kinetics derived from Magistretti and Alonso 1999 +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + Na channels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/README--GENERATED-FILES b/tests/hay11/README--GENERATED-FILES new file mode 100644 index 0000000..0f37b26 --- /dev/null +++ b/tests/hay11/README--GENERATED-FILES @@ -0,0 +1,2 @@ +These files are not the source files for the model, they have been generated from the source of the model in the neuroConstruct directory. +These have been added to provide examples of valid NeuroML files for testing applications & the OSB website and may be removed at any time. \ No newline at end of file diff --git a/tests/hay11/SK_E2.channel.nml b/tests/hay11/SK_E2.channel.nml new file mode 100644 index 0000000..23cff5e --- /dev/null +++ b/tests/hay11/SK_E2.channel.nml @@ -0,0 +1,71 @@ + + + + NeuroML file containing a single Channel description + + + + Small-conductance, Ca2+ activated K+ current + +Comment from original mod file: +: SK-type calcium-activated potassium current +: Reference : Kohler et al. 1996 + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + K channels + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/SKv3_1.channel.nml b/tests/hay11/SKv3_1.channel.nml new file mode 100644 index 0000000..30a471e --- /dev/null +++ b/tests/hay11/SKv3_1.channel.nml @@ -0,0 +1,55 @@ + + + + NeuroML file containing a single Channel description + + + + Fast, non inactivating K+ current + +Comment from original mod file: +:Reference : : Characterization of a Shaw-related potassium channel family in rat brain, The EMBO Journal, vol.11, no.7,2473-2486 (1992) + + + + + + + + Models of Neocortical Layer 5b Pyramidal Cells Capturing a Wide Range of Dendritic and Perisomatic Active Properties, + Etay Hay, Sean Hill, Felix Schürmann, Henry Markram and Idan Segev, PLoS Comp Biol 2011 + + + + + + + + K channels + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/Soma_AllCML.cell.nml b/tests/hay11/Soma_AllCML.cell.nml new file mode 100644 index 0000000..e848d61 --- /dev/null +++ b/tests/hay11/Soma_AllCML.cell.nml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A single segment/compartment cell + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/hay11/TestL5PC.net.nml b/tests/hay11/TestL5PC.net.nml new file mode 100644 index 0000000..14292f8 --- /dev/null +++ b/tests/hay11/TestL5PC.net.nml @@ -0,0 +1,62 @@ + + + + + +Network structure (NeuroML 2beta3) for project: L5bPyrCellHayEtAl2011 saved with neuroConstruct v1.7.1 on: 17:33:24, 19-Aug-14 + +Cell Group: CellGroup_1 contains 1 cells + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/hay11/analyse_chans.sh b/tests/hay11/analyse_chans.sh new file mode 100755 index 0000000..090f6b8 --- /dev/null +++ b/tests/hay11/analyse_chans.sh @@ -0,0 +1,7 @@ +pynml-channelanalysis NaTa_t.channel.nml Nap_Et2.channel.nml \ + K_Pst.channel.nml K_Tst.channel.nml \ + SK_E2.channel.nml SKv3_1.channel.nml \ + Ih.channel.nml \ + Ca_LVAst.channel.nml Ca_HVA.channel.nml -caConc 4.3e-4 -html + +# Im.channel.nml problematic... \ No newline at end of file diff --git a/tests/hay11/c b/tests/hay11/c new file mode 100644 index 0000000..b7d605d --- /dev/null +++ b/tests/hay11/c @@ -0,0 +1,3 @@ + +cd /home/llandsmeer/repos/llandsmeer/nmlcc +python3 compare.py diff --git a/tests/hay11/cell2_fromNeurolucida.nml b/tests/hay11/cell2_fromNeurolucida.nml new file mode 100644 index 0000000..2b37aa6 --- /dev/null +++ b/tests/hay11/cell2_fromNeurolucida.nml @@ -0,0 +1,49158 @@ + + + + + + Cell morphology generated by neuroConstruct from file: cell2.asc +V3 text file written for MicroBrightField products. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/hay11/compare_nml2_mods.py b/tests/hay11/compare_nml2_mods.py new file mode 100644 index 0000000..d4fa09e --- /dev/null +++ b/tests/hay11/compare_nml2_mods.py @@ -0,0 +1,83 @@ + +import matplotlib.pyplot as pylab +import os.path + +chans = ['NaTa_t', 'Nap_Et2', 'K_Tst', 'K_Pst', 'Ca_LVAst', 'Ca_HVA', 'Ih', 'SKv3_1'] +problematic = ['Im'] +#chans = ['NaTa_t'] + +gates = ['m', 'h'] + +for channel_id in chans: + + + vramp_lems_file = '%s.rampV.lems.dat'%(channel_id) + + ts = [] + volts = [] + for line in open(vramp_lems_file): + ts.append(float(line.split()[0])*1000) + volts.append(float(line.split()[1])*1000) + + fig = pylab.figure() + fig.canvas.set_window_title("Time Course(s) of activation variables of %s"%(channel_id)) + + pylab.xlabel('Membrane potential (V)') + pylab.ylabel('Time Course - tau (s)') + pylab.grid('on') + + for gate in gates: + + tau_lems_file = '%s.%s.tau.lems.dat'%(channel_id, gate) + + if os.path.isfile(tau_lems_file): + taus = [] + for line in open(tau_lems_file): + ts.append(float(line.split()[0])*1000) + taus.append(float(line.split()[1])*1000) + + pylab.plot(volts, taus, linestyle='-', linewidth=2, label="LEMS %s %s tau"%(channel_id, gate)) + + tau_mod_file = 'mods/%s.%s.tau.dat'%(channel_id, gate) + vs = [] + taus = [] + for line in open(tau_mod_file): + vs.append(float(line.split()[0])) + taus.append(float(line.split()[1])) + + pylab.plot(vs, taus, '--x', label="Mod %s %s tau"%(channel_id, gate)) + + + pylab.legend() + + + fig = pylab.figure() + fig.canvas.set_window_title("Steady state(s) of activation variables of %s"%(channel_id)) + + pylab.xlabel('Membrane potential (V)') + pylab.ylabel('Steady state (inf)') + pylab.grid('on') + + for gate in gates: + + inf_lems_file = '%s.%s.inf.lems.dat'%(channel_id, gate) + + if os.path.isfile(inf_lems_file): + infs = [] + for line in open(inf_lems_file): + infs.append(float(line.split()[1])) + + pylab.plot(volts, infs, linestyle='-', linewidth=2, label="LEMS %s %s inf"%(channel_id, gate)) + + inf_mod_file = 'mods/%s.%s.inf.dat'%(channel_id, gate) + vs = [] + infs = [] + for line in open(inf_mod_file): + vs.append(float(line.split()[0])) + infs.append(float(line.split()[1])) + + pylab.plot(vs, infs, '--x', label="Mod %s %s inf"%(channel_id, gate)) + + pylab.legend() + +pylab.show() diff --git a/tests/hay11/mods/Ca_HVA.mod b/tests/hay11/mods/Ca_HVA.mod new file mode 100644 index 0000000..c2d99e3 --- /dev/null +++ b/tests/hay11/mods/Ca_HVA.mod @@ -0,0 +1,72 @@ +:Comment : +:Reference : : Reuveni, Friedman, Amitai, and Gutnick, J.Neurosci. 1993 + +NEURON { + SUFFIX Ca_HVA + USEION ca READ eca WRITE ica + RANGE gCa_HVAbar, gCa_HVA, ica +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gCa_HVAbar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + eca (mV) + ica (mA/cm2) + gCa_HVA (S/cm2) + mInf + mTau + mAlpha + mBeta + hInf + hTau + hAlpha + hBeta +} + +STATE { + m + h +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gCa_HVA = gCa_HVAbar*m*m*h + ica = gCa_HVA*(v-eca) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau + h' = (hInf-h)/hTau +} + +INITIAL{ + rates() + m = mInf + h = hInf +} + +PROCEDURE rates(){ + UNITSOFF + if((v == -27) ){ + v = v+0.0001 + } + mAlpha = (0.055*(-27-v))/(exp((-27-v)/3.8) - 1) + mBeta = (0.94*exp((-75-v)/17)) + mInf = mAlpha/(mAlpha + mBeta) + mTau = 1/(mAlpha + mBeta) + hAlpha = (0.000457*exp((-13-v)/50)) + hBeta = (0.0065/(exp((-v-15)/28)+1)) + hInf = hAlpha/(hAlpha + hBeta) + hTau = 1/(hAlpha + hBeta) + UNITSON +} diff --git a/tests/hay11/mods/Ca_LVAst.mod b/tests/hay11/mods/Ca_LVAst.mod new file mode 100644 index 0000000..3683caf --- /dev/null +++ b/tests/hay11/mods/Ca_LVAst.mod @@ -0,0 +1,68 @@ +:Comment : LVA ca channel. Note: mtau is an approximation from the plots +:Reference : : Avery and Johnston 1996, tau from Randall 1997 +:Comment: shifted by -10 mv to correct for junction potential +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + +NEURON { + SUFFIX Ca_LVAst + USEION ca READ eca WRITE ica + RANGE gCa_LVAstbar, gCa_LVAst, ica +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gCa_LVAstbar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + eca (mV) + ica (mA/cm2) + gCa_LVAst (S/cm2) + mInf + mTau + hInf + hTau +} + +STATE { + m + h +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gCa_LVAst = gCa_LVAstbar*m*m*h + ica = gCa_LVAst*(v-eca) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau + h' = (hInf-h)/hTau +} + +INITIAL{ + rates() + m = mInf + h = hInf +} + +PROCEDURE rates(){ + LOCAL qt + qt = 2.3^((34-21)/10) + + UNITSOFF + v = v + 10 + mInf = 1.0000/(1+ exp((v - -30.000)/-6)) + mTau = (5.0000 + 20.0000/(1+exp((v - -25.000)/5)))/qt + hInf = 1.0000/(1+ exp((v - -80.000)/6.4)) + hTau = (20.0000 + 50.0000/(1+exp((v - -40.000)/7)))/qt + v = v - 10 + UNITSON +} diff --git a/tests/hay11/mods/Ih.mod b/tests/hay11/mods/Ih.mod new file mode 100644 index 0000000..a16a03e --- /dev/null +++ b/tests/hay11/mods/Ih.mod @@ -0,0 +1,61 @@ +:Comment : +:Reference : : Kole,Hallermann,and Stuart, J. Neurosci. 2006 + +NEURON { + SUFFIX Ih + NONSPECIFIC_CURRENT ihcn + RANGE gIhbar, gIh, ihcn +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gIhbar = 0.00001 (S/cm2) + ehcn = -45.0 (mV) +} + +ASSIGNED { + v (mV) + ihcn (mA/cm2) + gIh (S/cm2) + mInf + mTau + mAlpha + mBeta +} + +STATE { + m +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gIh = gIhbar*m + ihcn = gIh*(v-ehcn) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau +} + +INITIAL{ + rates() + m = mInf +} + +PROCEDURE rates(){ + UNITSOFF + if(v == -154.9){ + v = v + 0.0001 + } + mAlpha = 0.001*6.43*(v+154.9)/(exp((v+154.9)/11.9)-1) + mBeta = 0.001*193*exp(v/33.1) + mInf = mAlpha/(mAlpha + mBeta) + mTau = 1/(mAlpha + mBeta) + UNITSON +} diff --git a/tests/hay11/mods/Im.mod b/tests/hay11/mods/Im.mod new file mode 100644 index 0000000..7066097 --- /dev/null +++ b/tests/hay11/mods/Im.mod @@ -0,0 +1,61 @@ +:Reference : : Adams et al. 1982 - M-currents and other potassium currents in bullfrog sympathetic neurones +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + +NEURON { + SUFFIX Im + USEION k READ ek WRITE ik + RANGE gImbar, gIm, ik +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gImbar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + ek (mV) + ik (mA/cm2) + gIm (S/cm2) + mInf + mTau + mAlpha + mBeta +} + +STATE { + m +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gIm = gImbar*m + ik = gIm*(v-ek) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau +} + +INITIAL{ + rates() + m = mInf +} + +PROCEDURE rates(){ + LOCAL qt + qt = 2.3^((34-21)/10) + + UNITSOFF + mAlpha = 3.3e-3*exp(2.5*0.04*(v - -35)) + mBeta = 3.3e-3*exp(-2.5*0.04*(v - -35)) + mInf = mAlpha/(mAlpha + mBeta) + mTau = (1/(mAlpha + mBeta))/qt + UNITSON +} diff --git a/tests/hay11/mods/K_Pst.mod b/tests/hay11/mods/K_Pst.mod new file mode 100644 index 0000000..5be6631 --- /dev/null +++ b/tests/hay11/mods/K_Pst.mod @@ -0,0 +1,72 @@ +:Comment : The persistent component of the K current +:Reference : : Voltage-gated K+ channels in layer 5 neocortical pyramidal neurones from young rats:subtypes and gradients,Korngreen and Sakmann, J. Physiology, 2000 +:Comment : shifted -10 mv to correct for junction potential +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + + +NEURON { + SUFFIX K_Pst + USEION k READ ek WRITE ik + RANGE gK_Pstbar, gK_Pst, ik +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gK_Pstbar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + ek (mV) + ik (mA/cm2) + gK_Pst (S/cm2) + mInf + mTau + hInf + hTau +} + +STATE { + m + h +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gK_Pst = gK_Pstbar*m*m*h + ik = gK_Pst*(v-ek) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau + h' = (hInf-h)/hTau +} + +INITIAL{ + rates() + m = mInf + h = hInf +} + +PROCEDURE rates(){ + LOCAL qt + qt = 2.3^((34-21)/10) + UNITSOFF + v = v + 10 + mInf = (1/(1 + exp(-(v+1)/12))) + if(v<-50){ + mTau = (1.25+175.03*exp(-v * -0.026))/qt + }else{ + mTau = ((1.25+13*exp(-v*0.026)))/qt + } + hInf = 1/(1 + exp(-(v+54)/-11)) + hTau = (360+(1010+24*(v+55))*exp(-((v+75)/48)^2))/qt + v = v - 10 + UNITSON +} diff --git a/tests/hay11/mods/K_Tst.mod b/tests/hay11/mods/K_Tst.mod new file mode 100644 index 0000000..0cb8928 --- /dev/null +++ b/tests/hay11/mods/K_Tst.mod @@ -0,0 +1,68 @@ +:Comment : The transient component of the K current +:Reference : : Voltage-gated K+ channels in layer 5 neocortical pyramidal neurones from young rats:subtypes and gradients,Korngreen and Sakmann, J. Physiology, 2000 +:Comment : shifted -10 mv to correct for junction potential +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + +NEURON { + SUFFIX K_Tst + USEION k READ ek WRITE ik + RANGE gK_Tstbar, gK_Tst, ik +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gK_Tstbar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + ek (mV) + ik (mA/cm2) + gK_Tst (S/cm2) + mInf + mTau + hInf + hTau +} + +STATE { + m + h +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gK_Tst = gK_Tstbar*(m^4)*h + ik = gK_Tst*(v-ek) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau + h' = (hInf-h)/hTau +} + +INITIAL{ + rates() + m = mInf + h = hInf +} + +PROCEDURE rates(){ + LOCAL qt + qt = 2.3^((34-21)/10) + + UNITSOFF + v = v + 10 + mInf = 1/(1 + exp(-(v+0)/19)) + mTau = (0.34+0.92*exp(-((v+71)/59)^2))/qt + hInf = 1/(1 + exp(-(v+66)/-10)) + hTau = (8+49*exp(-((v+73)/23)^2))/qt + v = v - 10 + UNITSON +} diff --git a/tests/hay11/mods/NaTa_t.mod b/tests/hay11/mods/NaTa_t.mod new file mode 100644 index 0000000..c5096da --- /dev/null +++ b/tests/hay11/mods/NaTa_t.mod @@ -0,0 +1,79 @@ +:Reference :Colbert and Pan 2002 + +NEURON { + SUFFIX NaTa_t + USEION na READ ena WRITE ina + RANGE gNaTa_tbar, gNaTa_t, ina +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gNaTa_tbar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + ena (mV) + ina (mA/cm2) + gNaTa_t (S/cm2) + mInf + mTau + mAlpha + mBeta + hInf + hTau + hAlpha + hBeta +} + +STATE { + m + h +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gNaTa_t = gNaTa_tbar*m*m*m*h + ina = gNaTa_t*(v-ena) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau + h' = (hInf-h)/hTau +} + +INITIAL{ + rates() + m = mInf + h = hInf +} + +PROCEDURE rates(){ + LOCAL qt + qt = 2.3^((34-21)/10) + + UNITSOFF + if(v == -38){ + v = v+0.0001 + } + mAlpha = (0.182 * (v- -38))/(1-(exp(-(v- -38)/6))) + mBeta = (0.124 * (-v -38))/(1-(exp(-(-v -38)/6))) + mTau = (1/(mAlpha + mBeta))/qt + mInf = mAlpha/(mAlpha + mBeta) + + if(v == -66){ + v = v + 0.0001 + } + + hAlpha = (-0.015 * (v- -66))/(1-(exp((v- -66)/6))) + hBeta = (-0.015 * (-v -66))/(1-(exp((-v -66)/6))) + hTau = (1/(hAlpha + hBeta))/qt + hInf = hAlpha/(hAlpha + hBeta) + UNITSON +} \ No newline at end of file diff --git a/tests/hay11/mods/NaTs2_t.mod b/tests/hay11/mods/NaTs2_t.mod new file mode 100644 index 0000000..8d429ee --- /dev/null +++ b/tests/hay11/mods/NaTs2_t.mod @@ -0,0 +1,79 @@ +:Reference :Colbert and Pan 2002 +:comment: took the NaTa and shifted both activation/inactivation by 6 mv + +NEURON { + SUFFIX NaTs2_t + USEION na READ ena WRITE ina + RANGE gNaTs2_tbar, gNaTs2_t, ina +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gNaTs2_tbar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + ena (mV) + ina (mA/cm2) + gNaTs2_t (S/cm2) + mInf + mTau + mAlpha + mBeta + hInf + hTau + hAlpha + hBeta +} + +STATE { + m + h +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gNaTs2_t = gNaTs2_tbar*m*m*m*h + ina = gNaTs2_t*(v-ena) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau + h' = (hInf-h)/hTau +} + +INITIAL{ + rates() + m = mInf + h = hInf +} + +PROCEDURE rates(){ + LOCAL qt + qt = 2.3^((34-21)/10) + + UNITSOFF + if(v == -32){ + v = v+0.0001 + } + mAlpha = (0.182 * (v- -32))/(1-(exp(-(v- -32)/6))) + mBeta = (0.124 * (-v -32))/(1-(exp(-(-v -32)/6))) + mInf = mAlpha/(mAlpha + mBeta) + mTau = (1/(mAlpha + mBeta))/qt + + if(v == -60){ + v = v + 0.0001 + } + hAlpha = (-0.015 * (v- -60))/(1-(exp((v- -60)/6))) + hBeta = (-0.015 * (-v -60))/(1-(exp((-v -60)/6))) + hInf = hAlpha/(hAlpha + hBeta) + hTau = (1/(hAlpha + hBeta))/qt + UNITSON +} \ No newline at end of file diff --git a/tests/hay11/mods/Nap_Et2.mod b/tests/hay11/mods/Nap_Et2.mod new file mode 100644 index 0000000..ac639b9 --- /dev/null +++ b/tests/hay11/mods/Nap_Et2.mod @@ -0,0 +1,85 @@ +:Comment : mtau deduced from text (said to be 6 times faster than for NaTa) +:Comment : so I used the equations from NaT and multiplied by 6 +:Reference : Modeled according to kinetics derived from Magistretti & Alonso 1999 +:Comment: corrected rates using q10 = 2.3, target temperature 34, orginal 21 + +NEURON { + SUFFIX Nap_Et2 + USEION na READ ena WRITE ina + RANGE gNap_Et2bar, gNap_Et2, ina +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gNap_Et2bar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + ena (mV) + ina (mA/cm2) + gNap_Et2 (S/cm2) + mInf + mTau + mAlpha + mBeta + hInf + hTau + hAlpha + hBeta +} + +STATE { + m + h +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gNap_Et2 = gNap_Et2bar*m*m*m*h + ina = gNap_Et2*(v-ena) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau + h' = (hInf-h)/hTau +} + +INITIAL{ + rates() + m = mInf + h = hInf +} + +PROCEDURE rates(){ + LOCAL qt + qt = 2.3^((34-21)/10) + + UNITSOFF + mInf = 1.0/(1+exp((v- -52.6)/-4.6)) + if(v == -38){ + v = v+0.0001 + } + mAlpha = (0.182 * (v- -38))/(1-(exp(-(v- -38)/6))) + mBeta = (0.124 * (-v -38))/(1-(exp(-(-v -38)/6))) + mTau = 6*(1/(mAlpha + mBeta))/qt + + if(v == -17){ + v = v + 0.0001 + } + if(v == -64.4){ + v = v+0.0001 + } + + hInf = 1.0/(1+exp((v- -48.8)/10)) + hAlpha = -2.88e-6 * (v + 17) / (1 - exp((v + 17)/4.63)) + hBeta = 6.94e-6 * (v + 64.4) / (1 - exp(-(v + 64.4)/2.63)) + hTau = (1/(hAlpha + hBeta))/qt + UNITSON +} \ No newline at end of file diff --git a/tests/hay11/mods/SK_E2.mod b/tests/hay11/mods/SK_E2.mod new file mode 100644 index 0000000..e411d13 --- /dev/null +++ b/tests/hay11/mods/SK_E2.mod @@ -0,0 +1,56 @@ +: SK-type calcium-activated potassium current +: Reference : Kohler et al. 1996 + +NEURON { + SUFFIX SK_E2 + USEION k READ ek WRITE ik + USEION ca READ cai + RANGE gSK_E2bar, gSK_E2, ik +} + +UNITS { + (mV) = (millivolt) + (mA) = (milliamp) + (mM) = (milli/liter) +} + +PARAMETER { + v (mV) + gSK_E2bar = .000001 (mho/cm2) + zTau = 1 (ms) + ek (mV) + cai (mM) +} + +ASSIGNED { + zInf + ik (mA/cm2) + gSK_E2 (S/cm2) +} + +STATE { + z FROM 0 TO 1 +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gSK_E2 = gSK_E2bar * z + ik = gSK_E2 * (v - ek) +} + +DERIVATIVE states { + rates(cai) + z' = (zInf - z) / zTau +} + +PROCEDURE rates(ca(mM)) { + if(ca < 1e-7){ + ca = ca + 1e-07 + } + zInf = 1/(1 + (0.00043 / ca)^4.8) +} + +INITIAL { + rates(cai) + z = zInf +} diff --git a/tests/hay11/mods/SKv3_1.mod b/tests/hay11/mods/SKv3_1.mod new file mode 100644 index 0000000..a281419 --- /dev/null +++ b/tests/hay11/mods/SKv3_1.mod @@ -0,0 +1,54 @@ +:Comment : +:Reference : : Characterization of a Shaw-related potassium channel family in rat brain, The EMBO Journal, vol.11, no.7,2473-2486 (1992) + +NEURON { + SUFFIX SKv3_1 + USEION k READ ek WRITE ik + RANGE gSKv3_1bar, gSKv3_1, ik +} + +UNITS { + (S) = (siemens) + (mV) = (millivolt) + (mA) = (milliamp) +} + +PARAMETER { + gSKv3_1bar = 0.00001 (S/cm2) +} + +ASSIGNED { + v (mV) + ek (mV) + ik (mA/cm2) + gSKv3_1 (S/cm2) + mInf + mTau +} + +STATE { + m +} + +BREAKPOINT { + SOLVE states METHOD cnexp + gSKv3_1 = gSKv3_1bar*m + ik = gSKv3_1*(v-ek) +} + +DERIVATIVE states { + rates() + m' = (mInf-m)/mTau +} + +INITIAL{ + rates() + m = mInf +} + +PROCEDURE rates(){ + UNITSOFF + mInf = 1/(1+exp(((v -(18.700))/(-9.700)))) + mTau = 0.2*20.000/(1+exp(((v -(-46.560))/(-44.140)))) + UNITSON +} diff --git a/tests/hay11/mods/analyse_mods.sh b/tests/hay11/mods/analyse_mods.sh new file mode 100755 index 0000000..ccf4187 --- /dev/null +++ b/tests/hay11/mods/analyse_mods.sh @@ -0,0 +1,13 @@ +# CaDynamics_E2.mod Ca_HVA.mod Ca_LVAst.mod Ih.mod Im.mod K_Pst.mod K_Tst.mod NaTa_t.mod NaTs2_t.mod Nap_Et2.mod SK_E2.mod SKv3_1.mod + +pynml-modchananalysis NaTa_t -stepV 5 -temperature 6.3 +pynml-modchananalysis Nap_Et2 -stepV 5 -temperature 6.3 +pynml-modchananalysis K_Pst -stepV 5 -temperature 6.3 +pynml-modchananalysis K_Tst -stepV 5 -temperature 6.3 +pynml-modchananalysis Ca_HVA -stepV 5 -temperature 6.3 +pynml-modchananalysis Ca_LVAst -stepV 5 -temperature 6.3 +pynml-modchananalysis Ih -stepV 5 -temperature 6.3 +pynml-modchananalysis SKv3_1 -stepV 5 -temperature 6.3 + +# pynml-modchananalysis SK_E2 -stepV 5 -temperature 6.3 # inf is constant => no change in state var z => can't work out tau... +pynml-modchananalysis Im -stepV 5 -temperature 6.3 \ No newline at end of file diff --git a/tests/hay11/pas.channel.nml b/tests/hay11/pas.channel.nml new file mode 100644 index 0000000..02de1f4 --- /dev/null +++ b/tests/hay11/pas.channel.nml @@ -0,0 +1,13 @@ + + + + NeuroML file containing a single Channel description + + + + Simple example of a leak/passive conductance. Note: for GENESIS cells with a single leak conductance, + it is better to use the Rm and Em variables for a passive current. + + + + diff --git a/tests/test_hay11.rs b/tests/test_hay11.rs new file mode 100644 index 0000000..16fd8f6 --- /dev/null +++ b/tests/test_hay11.rs @@ -0,0 +1,64 @@ +use nml2::{ + bundle, + error::Result, + lems::{self, file::LemsFile}, + neuroml, + xml::XML, +}; +use std::process::Command; +use tempfile; + +fn get_runtime_types(lems: &mut LemsFile, nml: &[String]) -> Result<()> { + // from main.rs .. should import actually + neuroml::process_files(nml, |_, node| { + if node.tag_name().name() == "ComponentType" { + let ct: lems::raw::ComponentType = XML::from_node(node); + lems.add_component_type(&ct)?; + } + Ok(()) + }) +} + +#[test] +fn hay11() -> Result<()> { + let nml = String::from(concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/hay11/TestL5PC.net.nml" + )); + let tmpdir = tempfile::TempDir::new()?; + let dir = String::from(tmpdir.path().to_str().unwrap()); + let cxx = true; + let py = true; + let super_mechanisms = false; + let cat_prefix = String::from("local_"); + let ions = vec![String::from("ca"), String::from("na"), String::from("k")]; + let mut lems = lems::file::LemsFile::core(); + get_runtime_types(&mut lems, &[nml.to_string()]).unwrap(); + bundle::export( + &lems, + &[nml], + &ions[..], + bundle::Bundle { + dir: dir.to_string(), + cxx, + py, + super_mechanisms, + cat_prefix, + }, + )?; + let path_main_py = tmpdir.path().join("main.py"); + let main_py = std::fs::read_to_string(&path_main_py)?; + let main_py = main_py.replace("sim.run(1000, 0.025)", "sim.run(10, 0.025)"); + std::fs::write(path_main_py, main_py)?; + Command::new("python3") + .args(["main.py", "dat/network_L5bPyrCellHayEtAl2011.json"]) + .current_dir(tmpdir.path()) + .status()?; + assert!(tmpdir.path().join("result.pdf").exists()); + Command::new("bash") + .args(["run.sh", "network_L5bPyrCellHayEtAl2011"]) + .current_dir(tmpdir.path()) + .status()?; + tmpdir.close()?; + Ok(()) +}