From af62e778cb325354253fd7e910a435bfc649ed81 Mon Sep 17 00:00:00 2001 From: kaeldai Date: Sun, 16 Jun 2024 11:36:29 -0700 Subject: [PATCH 1/4] fixes for Ch5 of workshop tutorial; remove dt attribute in filternet in create_environment, automatic support for npz movies, fix issue with separable kernel when kernel is empty --- bmtk/simulator/filternet/filtersimulator.py | 16 +++++++++++++--- bmtk/simulator/filternet/lgnmodel/cursor.py | 12 +++++++++--- bmtk/utils/create_environment/__main__.py | 2 +- .../create_environment/create_environment.py | 4 ++-- bmtk/utils/create_environment/env_builder.py | 9 +++++++++ 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/bmtk/simulator/filternet/filtersimulator.py b/bmtk/simulator/filternet/filtersimulator.py index 0b31673e9..127ef1f3f 100644 --- a/bmtk/simulator/filternet/filtersimulator.py +++ b/bmtk/simulator/filternet/filtersimulator.py @@ -48,6 +48,16 @@ def add_movie(self, movie_type, params): else: raise Exception('Could not find movie "data_file" in config to use as input.') + # If file passed in is a npz compressed file then it is in a dictionary format and need to find + # the key-value pair containing the array + if isinstance(m_data, np.lib.npyio.NpzFile): + try: + for key in m_data: + m_data = m_data[key] + break + except IndexError as ie: + io.log_warning('Was unable to find array from compressed numpy matrix file.') + # contrast_min, contrast_max = m_data.min(), m_data.max() normalize_data = params.get('normalize', False) if normalize_data: @@ -181,13 +191,13 @@ def run(self): ten_percent = int(np.ceil(n_cells_on_rank*0.1)) rank_msg = '' if bmtk_world_comm.MPI_size < 2 else ' (on rank {})'.format(bmtk_world_comm.MPI_rank) - max_fr = np.empty(len(cells_on_rank)) + # max_fr = np.empty(len(cells_on_rank)) for cell_num, cell in enumerate(cells_on_rank): for movie, options in zip(self._movies, self._eval_options): if cell_num > 0 and cell_num % ten_percent == 0: io.log_debug(' Processing cell {} of {}{}.'.format(cell_num, n_cells_on_rank, rank_msg)) ts, f_rates = cell.lgn_cell_obj.evaluate(movie, **options) - max_fr[cell_num] = np.max(f_rates) + # max_fr[cell_num] = np.max(f_rates) if movie.padding: f_rates = f_rates[int(movie.data.shape[0]-movie.data_orig.shape[0]):] ts = ts[int(movie.data.shape[0]-movie.data_orig.shape[0]):] @@ -195,7 +205,7 @@ def run(self): for mod in self._sim_mods: mod.save(self, cell, ts, f_rates) - io.log_info('Max firing rate: {}'.format(np.max(max_fr))) + # io.log_info('Max firing rate: {}'.format(np.max(max_fr))) io.log_info('Done.') for mod in self._sim_mods: mod.finalize(self) diff --git a/bmtk/simulator/filternet/lgnmodel/cursor.py b/bmtk/simulator/filternet/lgnmodel/cursor.py index 24f4f3ca1..f5ecdf607 100644 --- a/bmtk/simulator/filternet/lgnmodel/cursor.py +++ b/bmtk/simulator/filternet/lgnmodel/cursor.py @@ -225,14 +225,20 @@ def evaluate(self, threshold=0): full_temporal_kernel = self.temporal_kernel.full() # Convolve every frame in the movie with the spatial filter. First find the range of rows (range min and max) - # and columns in the filter that are above threshold, that way only portion of movie/filter are multiplied + # and columns in the filter that are above threshold, that way only portion of movie/filter are multiplied # together # Using > instead of >= makes the code faster if there are many zeros in the # spatial kernel. This will not affect the results. nonzero_inds = np.where(np.abs(full_spatial_kernel[0, :, :]) > threshold) - rm, rM = nonzero_inds[0].min(), nonzero_inds[0].max() - cm, cM = nonzero_inds[1].min(), nonzero_inds[1].max() + if len(nonzero_inds[0]) == 0: + # If spatial kernel is all 0's then don't try to segment the receptive filed. Use full frame during convolve. + rm, rM = 0, 0 + cm, cM = full_spatial_kernel.shape[1], full_spatial_kernel.shape[2] + else: + rm, rM = nonzero_inds[0].min(), nonzero_inds[0].max() + cm, cM = nonzero_inds[1].min(), nonzero_inds[1].max() + convolution_answer_sep_spatial = (self.movie.data[:, rm:rM+1, cm:cM+1] * full_spatial_kernel[:, rm:rM+1, cm:cM+1]).sum(axis=1).sum(axis=1) diff --git a/bmtk/utils/create_environment/__main__.py b/bmtk/utils/create_environment/__main__.py index d5a7b32db..ac74f6f8b 100644 --- a/bmtk/utils/create_environment/__main__.py +++ b/bmtk/utils/create_environment/__main__.py @@ -52,7 +52,7 @@ def __split_list(options, opt_name): parser.add_option('-c', '--components-dir', dest='components_dir', default=None, help="Directory to use for parameter files, morphology, and other used components.") parser.add_option('--tstop', type='float', dest='tstop', default=1000.0) - parser.add_option('--dt', type=float, dest='dt', help='simulation time step dt', default=0.001) + parser.add_option('--dt', type=float, dest='dt', help='simulation time step dt', default=None) parser.add_option('--report-vars', dest='report_vars', type='string', action='callback', callback=__list_parser, default=[], help='A list of membrane variables to record from; v, cai, etc.') diff --git a/bmtk/utils/create_environment/create_environment.py b/bmtk/utils/create_environment/create_environment.py index 886d271e4..973a6b280 100644 --- a/bmtk/utils/create_environment/create_environment.py +++ b/bmtk/utils/create_environment/create_environment.py @@ -41,7 +41,7 @@ def create_environment(simulator, se_voltage_clamp=None, tstart=0.0, tstop=1000.0, - dt=0.001, + dt=None, dL=20.0, spikes_threshold=-15.0, nsteps_block=5000, @@ -50,7 +50,7 @@ def create_environment(simulator, compile_mechanisms=False, use_relative_paths=True, include_examples=False - ): + ): """ :param simulator: diff --git a/bmtk/utils/create_environment/env_builder.py b/bmtk/utils/create_environment/env_builder.py index 973b87dbe..8705de731 100644 --- a/bmtk/utils/create_environment/env_builder.py +++ b/bmtk/utils/create_environment/env_builder.py @@ -776,6 +776,15 @@ def target_simulator(self): @property def bmtk_simulator(self): return 'filternet' + + def _add_run_params(self, tstart=0.0, tstop=1000.0, dt=None, **kwargs): + self._simulation_config['run'] = { + 'tstart': tstart, + 'tstop': tstop + } + + if dt is not None: + self._simulation_config['run']['dt'] = dt def _add_output_section(self): super(FilterNetEnvBuilder, self)._add_output_section() From 1b58f44c1714ae8d7d71202385e24145b7e568e8 Mon Sep 17 00:00:00 2001 From: kaeldai Date: Mon, 24 Jun 2024 17:44:39 -0700 Subject: [PATCH 2/4] small fix to xstim and larger update of SEClamp module --- bmtk/simulator/bionet/biosimulator.py | 35 +--------- bmtk/simulator/bionet/modules/__init__.py | 1 + bmtk/simulator/bionet/modules/seclamp.py | 70 +++++++++++++++++++ .../bionet/modules/xstim_waveforms.py | 2 +- 4 files changed, 73 insertions(+), 35 deletions(-) create mode 100644 bmtk/simulator/bionet/modules/seclamp.py diff --git a/bmtk/simulator/bionet/biosimulator.py b/bmtk/simulator/bionet/biosimulator.py index 06f8bb4cd..954e5f9b7 100644 --- a/bmtk/simulator/bionet/biosimulator.py +++ b/bmtk/simulator/bionet/biosimulator.py @@ -376,41 +376,8 @@ def from_config(cls, config, network, set_recordings=True): sim.add_mod(mods.IClampMod(input_type=sim_input.input_type, **sim_input.params)) elif sim_input.module == "SEClamp": - node_set = network.get_node_set(sim_input.node_set) - try: - len(sim_input.params['amps']) - except: - sim_input.params['amps']=[float(sim_input.params['amps'])] + sim.add_mod(mods.SEClamp(input_type=sim_input.input_type, **sim_input.params)) - try: - len(sim_input.params['durations']) - except: - sim_input.params['durations']=[float(sim_input.params['durations'])] - - amplitudes = sim_input.params['amps'] - durations = sim_input.params['durations'] - rs = None - - if "rs" in sim_input.params.keys(): - try: - len(sim_input.params['rs']) - except: - sim_input.params['rs']=[float(sim_input.params['rs'])] - if len(sim_input.params['rs'])>1: - sim_input.params['rs']=[float(i) for i in sim_input.params['rs']] - rs = sim_input.params["rs"] - - try: - sim_input.params['gids'] - except: - sim_input.params['gids'] = None - if sim_input.params['gids'] is not None: - gids = sim_input.params['gids'] - else: - gids = list(node_set.gids()) - - sim.attach_se_voltage_clamp(amplitudes, durations, gids, rs) - elif sim_input.module == 'xstim': sim.add_mod(mods.XStimMod(**sim_input.params)) diff --git a/bmtk/simulator/bionet/modules/__init__.py b/bmtk/simulator/bionet/modules/__init__.py index fc61001b7..c0ecca3fb 100644 --- a/bmtk/simulator/bionet/modules/__init__.py +++ b/bmtk/simulator/bionet/modules/__init__.py @@ -30,3 +30,4 @@ from .iclamp import IClampMod from .comsol import ComsolMod from .ecephys_module import BioECEphysUnitsModule +from .seclamp import SEClamp \ No newline at end of file diff --git a/bmtk/simulator/bionet/modules/seclamp.py b/bmtk/simulator/bionet/modules/seclamp.py new file mode 100644 index 000000000..5d5dbe665 --- /dev/null +++ b/bmtk/simulator/bionet/modules/seclamp.py @@ -0,0 +1,70 @@ +import numpy as np +from neuron import h + +from bmtk.simulator.bionet.modules.sim_module import SimulatorMod +from bmtk.simulator.bionet.io_tools import io +from bmtk.simulator.core.modules import iclamp + + +class SEClamp(SimulatorMod): + def __init__(self, input_type, **mod_args): + + # Select location to place iclamp, if not specified use the center of the soma + self._section_name = mod_args.get('section_name', 'soma') + self._section_index = mod_args.get('section_index', 0) + self._section_dist = mod_args.get('section_dist', 0.5) + + self._rs = mod_args.get('resistance', 1.0) + self._vc = mod_args.get('vc', 0.0) + + self._delay = mod_args['delay'] + self._amp = mod_args['amp'] + self._duration = mod_args['duration'] + self._ton = self._delay + self._toff = self._delay + self._duration + + # Check f section_index is a range (ie. "section_index": [500.0, 1000.0]) + self._ranged_index = isinstance(self._section_index, (list, tuple)) + + # SEClamp objects need to be saved in memory otherwise NRN will try to garbage collect them + # prematurly + self._seclamp = None + + self._node_set = mod_args.get('node_set', 'all') + + def initialize(self, sim): + select_gids = list(sim.net.get_node_set(self._node_set).gids()) + gids_on_rank = list(set(select_gids) & set(select_gids)) + + for gid in gids_on_rank: + cell = sim.net.get_cell_gid(gid) + + if self._ranged_index: + hobj_sec = self._find_section(cell) + else: + hobj_sec = getattr(cell.hobj, self._section_name)[self._section_index](self._section_dist) + + self._seclamp = self.create_clamp(hobj_sec) + + def step(self, sim, tstep): + if self._ton <= sim.dt*tstep <= self._toff: + self._seclamp.rs = self._rs + # print(sim.dt*tstep) + else: + self._seclamp.rs = 10.0e20 + + + def create_clamp(self, hobj): + stim = h.SEClamp(hobj) + + stim.dur1 = self._delay + stim.dur2 = self._duration + stim.dur3 = 0.0 + + stim.amp1 = 0.0 + stim.amp2 = self._amp + stim.amp3 = 0.0 + stim.vc = self._vc + + return stim + \ No newline at end of file diff --git a/bmtk/simulator/bionet/modules/xstim_waveforms.py b/bmtk/simulator/bionet/modules/xstim_waveforms.py index c31e449e1..cf17bc86b 100644 --- a/bmtk/simulator/bionet/modules/xstim_waveforms.py +++ b/bmtk/simulator/bionet/modules/xstim_waveforms.py @@ -56,7 +56,7 @@ def calculate(self, t): # TODO better name class WaveformCustom(BaseWaveform): """Custom waveform defined by csv file""" def __init__(self, waveform_file): - self.definition = pd.read_csv(waveform_file, sep='\t') + self.definition = pd.read_csv(waveform_file, sep=' ') def calculate(self, t): return np.interp(t, self.definition["time"], self.definition["amplitude"]) From 4eb01f9d356ece4621a24be00d8e211238a44865 Mon Sep 17 00:00:00 2001 From: kaeldai Date: Tue, 25 Jun 2024 16:28:51 -0700 Subject: [PATCH 3/4] Adding fix to make using NESTML a bit more robust + another NESTML example --- .../pointnet/modules/spikes_inputs.py | 2 +- bmtk/simulator/pointnet/pointnetwork.py | 6 ++ bmtk/simulator/pointnet/pointsimulator.py | 51 +++++++++++++++++ examples/point_nestml_izh/config.circuit.json | 38 ++++++++++++ .../point_nestml_izh/config.simulation.json | 41 +++++++++++++ .../point_nestml_izh/custom_izh_neuron.nestml | 38 ++++++++++++ examples/point_nestml_izh/generate_model.py | 54 ++++++++++++++++++ .../inputs/thalamus_spikes.h5 | Bin 0 -> 45608 bytes .../network/cortex_cortex_edge_types.csv | 3 + .../network/cortex_cortex_edges.h5 | Bin 0 -> 87404 bytes .../network/cortex_node_types.csv | 3 + .../point_nestml_izh/network/cortex_nodes.h5 | Bin 0 -> 14688 bytes .../network/thalamus_cortex_edge_types.csv | 3 + .../network/thalamus_cortex_edges.h5 | Bin 0 -> 75798 bytes .../network/thalamus_node_types.csv | 2 + .../network/thalamus_nodes.h5 | Bin 0 -> 8512 bytes examples/point_nestml_izh/run_pointnet.py | 31 ++++++++++ 17 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 examples/point_nestml_izh/config.circuit.json create mode 100644 examples/point_nestml_izh/config.simulation.json create mode 100644 examples/point_nestml_izh/custom_izh_neuron.nestml create mode 100644 examples/point_nestml_izh/generate_model.py create mode 100644 examples/point_nestml_izh/inputs/thalamus_spikes.h5 create mode 100644 examples/point_nestml_izh/network/cortex_cortex_edge_types.csv create mode 100644 examples/point_nestml_izh/network/cortex_cortex_edges.h5 create mode 100644 examples/point_nestml_izh/network/cortex_node_types.csv create mode 100644 examples/point_nestml_izh/network/cortex_nodes.h5 create mode 100644 examples/point_nestml_izh/network/thalamus_cortex_edge_types.csv create mode 100644 examples/point_nestml_izh/network/thalamus_cortex_edges.h5 create mode 100644 examples/point_nestml_izh/network/thalamus_node_types.csv create mode 100644 examples/point_nestml_izh/network/thalamus_nodes.h5 create mode 100644 examples/point_nestml_izh/run_pointnet.py diff --git a/bmtk/simulator/pointnet/modules/spikes_inputs.py b/bmtk/simulator/pointnet/modules/spikes_inputs.py index 1e305fc25..f193b0391 100644 --- a/bmtk/simulator/pointnet/modules/spikes_inputs.py +++ b/bmtk/simulator/pointnet/modules/spikes_inputs.py @@ -24,7 +24,7 @@ from bmtk.simulator.pointnet.modules.sim_module import SimulatorMod from bmtk.simulator.pointnet.io_tools import io from bmtk.utils.reports.spike_trains import SpikeTrains -from bmtk.simulator.bionet.pyfunction_cache import py_modules +from bmtk.simulator.pointnet.pyfunction_cache import py_modules class SpikesInputsMod(SimulatorMod): diff --git a/bmtk/simulator/pointnet/pointnetwork.py b/bmtk/simulator/pointnet/pointnetwork.py index 56f6aae2e..54f18eb25 100644 --- a/bmtk/simulator/pointnet/pointnetwork.py +++ b/bmtk/simulator/pointnet/pointnetwork.py @@ -86,6 +86,8 @@ def __init__(self, **properties): self._nodes_table = {} self._gid2nestid = {} + self._nest_modules = [] + self._gid_map = GidPool() self._virtual_gids = GidPool() @@ -131,6 +133,10 @@ def add_weight_function(self, fnc, name=None, **kwargs): fnc_name = name if name is not None else function.__name__ self.__weight_functions[fnc_name] = functools.partial(fnc) + def add_nest_module(self, module_path): + if module_path not in self._nest_modules: + self._nest_modules.append(module_path) + def set_default_weight_function(self, fnc): self.add_weight_function(fnc, 'default_weight_fnc', overwrite=True) diff --git a/bmtk/simulator/pointnet/pointsimulator.py b/bmtk/simulator/pointnet/pointsimulator.py index b6a4af0ec..f6dde7f9a 100644 --- a/bmtk/simulator/pointnet/pointsimulator.py +++ b/bmtk/simulator/pointnet/pointsimulator.py @@ -25,6 +25,8 @@ import nest from six import string_types from six import moves +from pathlib import Path +import platform from bmtk.simulator.core.simulator import Simulator from bmtk.simulator.pointnet.config import Config @@ -72,6 +74,7 @@ def __init__(self, graph, dt=0.001, overwrite=True, print_time=False, n_thread=1 # TODO: move this into it's own function and make sure it is called before network is built nest.ResetKernel() nest.SetKernelStatus({"resolution": self._dt, "overwrite_files": self._overwrite, "print_time": print_time, "local_num_threads": n_thread}) + self._load_nest_modules() @property def tstart(self): @@ -131,6 +134,54 @@ def _get_block_trial(self, duration): data_res = -1 return n, res, data_res + def _add_library_path(self, lib_path): + if isinstance(lib_path, Path): + lib_path = lib_path.as_posix() + system = platform.system() + env_var = "LD_LIBRARY_PATH" if system in ['Linux', 'Windows', 'Java'] else 'DYLD_LIBRARY_PATH' + env_val = os.environ.get(env_var, '') + + if lib_path not in env_val: + os.environ[env_var] = os.pathsep.join([lib_path, env_val]) + + + def _load_nest_modules(self): + # If there is a "nest_modules" entry in the configuration "components" then go through and add them to + # the network _nest_modules list. They will be processed the same as calling network.add_nest_module(). + components_path = self.net._components.get('nest_modules', []) + if isinstance(components_path, str): + self.net.add_nest_module(components_path) + elif isinstance(components_path, list): + for cpath in components_path: + self.net.add_nest_module(cpath) + else: + raise ValueError('Unable to load components/nest_modules value.') + + # Go through all added nest modules and try to call nest.Install() for them. + for module in self.net._nest_modules: + if Path(module).is_dir(): + # If module is a directory then add path to LD_LIBRARY_PATH then try to load all the .so/.a library binaries in directory + lib_dir = Path(module).resolve() + self._add_library_path(lib_dir) + so_search = Path(lib_dir) / '*.so' + a_search = Path(lib_dir) / '*.a' + + for lib_file in glob.glob(so_search.as_posix()) + glob.glob(a_search.as_posix()): # lib_path.parent.resolve() + module_name = Path(lib_file).name + nest.Install(module_name) + + elif Path(module).is_file(): + # If user tries to pass in a path to a library binary + lib_path = Path(module) + lib_dir = lib_path.parent.resolve() + lib_filename = lib_path.name + self._add_library_path(lib_dir) + nest.Install(lib_filename) + + else: + # If user just tries nest.Install('mymodule') + nest.Install(module) + ''' def set_spikes_recordings(self): # TODO: Pass in output-dir and file name to save to diff --git a/examples/point_nestml_izh/config.circuit.json b/examples/point_nestml_izh/config.circuit.json new file mode 100644 index 000000000..d932bc3bb --- /dev/null +++ b/examples/point_nestml_izh/config.circuit.json @@ -0,0 +1,38 @@ +{ + "manifest": { + "$BASE_DIR": ".", + "$NETWORK_DIR": "$BASE_DIR/network", + "$MODELS_DIR": "$BASE_DIR/../point_components" + }, + + "components": { + "point_neuron_models_dir": "$MODELS_DIR/cell_models", + "synaptic_models_dir": "$MODELS_DIR/synaptic_models", + "nest_modules": "components/nestml/nestml_izh_module.so" + }, + + "networks": { + "nodes": [ + { + "nodes_file": "$NETWORK_DIR/cortex_nodes.h5", + "node_types_file": "$NETWORK_DIR/cortex_node_types.csv" + }, + { + "nodes_file": "$NETWORK_DIR/thalamus_nodes.h5", + "node_types_file": "$NETWORK_DIR/thalamus_node_types.csv" + } + ], + "edges": [ + { + "edges_file": "$NETWORK_DIR/cortex_cortex_edges.h5", + "edge_types_file": "$NETWORK_DIR/cortex_cortex_edge_types.csv", + "enabled": false + }, + { + "edges_file": "$NETWORK_DIR/thalamus_cortex_edges.h5", + "edge_types_file": "$NETWORK_DIR/thalamus_cortex_edge_types.csv", + "enabled": true + } + ] + } +} diff --git a/examples/point_nestml_izh/config.simulation.json b/examples/point_nestml_izh/config.simulation.json new file mode 100644 index 000000000..14207c138 --- /dev/null +++ b/examples/point_nestml_izh/config.simulation.json @@ -0,0 +1,41 @@ +{ + "manifest": { + "$BASE_DIR": "${configdir}", + "$NETWORK_DIR": "$BASE_DIR/network", + "$MODELS_DIR": "$BASE_DIR/../point_components", + "$OUTPUT_DIR": "$BASE_DIR/output", + "$INPUT_DIR": "$BASE_DIR/inputs" + }, + + "run": { + "tstop": 3000.0, + "dt": 0.001, + "block_run": false, + "block_size": 1000.0 + }, + + "inputs": { + "thalamus_spikes": { + "input_type": "spikes", + "module": "sonata", + "input_file": "$INPUT_DIR/thalamus_spikes.h5", + "node_set": "thalamus" + } + }, + + "reports": { + }, + + "output": { + "log_file": "log.txt", + "spikes_file": "spikes.h5", + "spikes_file_csv": "spikes.csv", + "output_dir": "$OUTPUT_DIR", + "overwrite_output_dir": true, + "quiet_simulator": true + }, + + "target_simulator":"NEST", + "rebuild_nestml": true, + "network": "config.circuit.json" +} diff --git a/examples/point_nestml_izh/custom_izh_neuron.nestml b/examples/point_nestml_izh/custom_izh_neuron.nestml new file mode 100644 index 000000000..0535e6bba --- /dev/null +++ b/examples/point_nestml_izh/custom_izh_neuron.nestml @@ -0,0 +1,38 @@ + +model custom_izh_neuron: + + state: + v mV = -65 mV # Membrane potential in mV + u real = 0 # Membrane potential recovery variable + + equations: + v' = (.04 * v * v / mV + 5 * v + (140 - u) * mV + (I_e * GOhm)) / ms + u' = a * (b * v - u * mV) / (mV * ms) + + parameters: + a real = .02 # describes time scale of recovery variable + b real = .2 # sensitivity of recovery variable + c mV = -65 mV # after-spike reset value of v + d real = 8. # after-spike reset value of u + + input: + spikes <- spike + I_e pA <- continuous + + output: + spike + + update: + integrate_odes() + + onReceive(spikes): + # add synaptic current + v += spikes * mV * s + + onCondition(v >= 30mV): + # threshold crossing + v = c + u += d + emit_spike() + + diff --git a/examples/point_nestml_izh/generate_model.py b/examples/point_nestml_izh/generate_model.py new file mode 100644 index 000000000..093d54aaf --- /dev/null +++ b/examples/point_nestml_izh/generate_model.py @@ -0,0 +1,54 @@ +# import matplotlib.pyplot as plt +import nest +import numpy as np +import os +import re + +from pynestml.codegeneration.nest_code_generator_utils import NESTCodeGeneratorUtils + + +nestml_izh_model = ''' +model custom_izh_neuron: + + state: + v mV = -65 mV # Membrane potential in mV + u real = 0 # Membrane potential recovery variable + + equations: + v' = (.04 * v * v / mV + 5 * v + (140 - u) * mV + (I_e * GOhm)) / ms + u' = a * (b * v - u * mV) / (mV * ms) + + parameters: + a real = .02 # describes time scale of recovery variable + b real = .2 # sensitivity of recovery variable + c mV = -65 mV # after-spike reset value of v + d real = 8. # after-spike reset value of u + + input: + spikes <- spike + I_e pA <- continuous + + output: + spike + + update: + integrate_odes() + + onReceive(spikes): + # add synaptic current + v += spikes * mV * s + + onCondition(v >= 30mV): + # threshold crossing + v = c + u += d + emit_spike() + +''' + +# generate and build code +module_name, neuron_model_name_adapt_curr = NESTCodeGeneratorUtils.generate_code_for( + nestml_izh_model, + module_name='nestml_izh_module', + target_path='components/nestml' +) diff --git a/examples/point_nestml_izh/inputs/thalamus_spikes.h5 b/examples/point_nestml_izh/inputs/thalamus_spikes.h5 new file mode 100644 index 0000000000000000000000000000000000000000..48cc4d498243d1f8662e5136a9bb4b1858f7ad78 GIT binary patch literal 45608 zcmeFZcR1GX|37Rbk_IXj84X0kuBbdHQf5Sv5u)t9W$$?zmp!hnh$50El4LX}O%;WP zk%m;{e)Xw-_vik6kKggVfA?SaaeUv`ar8Q0*K2v5&+9y&#{vP%h~)LynUQJ-2dx+?7#2)+r7W-uZR9V^LIx5>(Bg`4Lfnw zuj~F^^|v2?UXD%t&wTpt<{jnFd;c@<{)>tKM;!RidG~ib;m`Q_YXslpwyw5re#FfC z{rNlY@%O<0VQXSwxck=#{yXj-{fQTUpZlNV`2XTUnA$&SvI!DMZepBw*Oe*9}E0rfqyLUj|Kj*z&{rF#{&OY;2#V8 zV}XAx@Q(%lvB3ZTEWpmj{k!J>Q~0z0VJ6uB@Emvl;E{h@PU8HpOZmms|6ssiQ<~4F zH2Vh!<|2;%I?utu@vkTH{COTH`|-8Edmmx_?^Y1_^ORo~Z!6)o`@eCIxop314?lM& z-(OI}e}{Yg!X^IV9=|b)|F=lizrPI|+izTp_Qn5$>Ivy&AM`4-N8lh7g;xJS5sz9kU5kmZ={jWTdFtHnWSe4?E)&Xak4^$ku zG^Vfejt-?Ap90{`#4YY-noR{0i(kHMifm$HDcwVI*?T5#<|SJRt|>!^;vG_5fi)T% zZP`Ug$1&GxsJ<}E4+&;-HMs>NP`9U6kFFPia83EtD`rW!-eSwDe0MFC(KR&%=x#C56PX1@}Ajn2FGY4!Up?^}Uw(C+N z3^Q*9G<-}iF+X0mp2Dj#LkqvTIN6|@z6rGupAg`?AVsGHWxCNx!#Ef z1;zALV9#J48<#L-cYM z+Cn{H#A;ibPmjZ>>3+7(^GR49`bPNzITi6HIsDptGQjTly79nJ2D+1;Ii66=gjNmb zx>uibk*{k*mhe>!4!Yc#&qJE>sTb{B*boEG(h|Xw~+V+i-cO^qe*VV3%n}lz#_A5KelF-;5TX*vT3DlzPy0x!Kc*u2+X48{_ zn>-!Ou_;-oTe8pp;T|$(OfI^-)5*obSskb7g9T`keLuK;a}oBq-}@Y4U5e!C@R#!aM=92(sUq>ea<^$ zED{X$7JIVfvJ-f@hV!OC)(PBiJMhiy%n9@@5PFm}8G)#!XOt>TqH$Gv6F$qu;yvdI zX&IFS)N9zNZ^=wRUVnv*9eXm4?78{gyDJ4AO}hhboJmE{y}q1P+tUzYUb|r`jD#zD zcEx=R&%mRY?Tl`|OjLKZTg)@h0Z&KGd6AGDB%Slxt0J6_t)D$kR2Sr9N_r7_b5TBy zT$>mFr7j=Uxn8^*e&*u@OKg!AtpL3b??r7CFT^!Q@8q$KC6MB;lJ&Y=iUZvjc80lA zU^m{wCc;g{3EytsEt*tZFwI}mCQF0*(`2#WVj5h^0{MhaFtDw0nK_w_g)c(Zw)bPb zu#a)z_R|V)q;Hs3l;`nB`h(|3@+yPiGOzVI?R7ZjiIuK>cQqP2pE?hZ*Cb(KqVMMy z&yr9>Kfm~+W;(i-%<~b8Ai+%ZSx{0X3H1s^)Pm3q13w0^73T=V7Zb zGn9?+$q}BHKggInw!reOVGbTi%I9-)Oco zRu&(rh>&^O*tCcSy5tJA=T{i0G2PguUB$$j=q39U$CyZf*(%C36Xn(kizmUtD4%H$ zTPF+Z!WSdV%8enR5#=FUa}c@V>g;>_J@9kU;EmV3UeNw2>RqVsjedV=+5&NZgyaur z``87bt#fMK{HI}PTH9&2{3c;PRdTUfV=R*T&M)!!5Q{CA6E-7#NmwKier@_92@0f@ z7w7)W#PARH?1b&PC|LaCM{RsA#1F>)xRIKR>fJ$X)b)9|6E=Ls?pPiycU30e_sz$h z%F|-fC-V_)Cq10RU4U%=+Wd~mLhS6jEiqnE1g+9yfr@p-Xgas@g-s&`BQu+a-{n$~ zP%+i$(@({WPEYd56b9yxUt6=`Bm*~ANM8JUfq@O(V!V<4448=Z-0Acp=G%Tf>);tC z>ZClr>E2?Y(~CR5=nV^`QyLT7SZ3H{IU{SyJOZWVMGRq;V<6FkpX8nPKxD?{?GtXk zU~N*qbVb-7Z?Bt76s`+^sDo;QKyD-q7cH9QYK+9aIPPcrH^oBE_ted=MBE>|K0f3p zoQ%V712b}Nrz0_Wt{lfo5-v~HYea=*Kuo!O;*E4BzGIkA`2`sV=kGc5EjS0JmANmn zw-sQlv^sd@U@;P{ILE1WCAgIuY5bFq0_Icu3!Qva6kUmlxuZdabT2C|N{fb?s=Pfi z>*!FNQ zI;d{w{8qGim4gqwJH8yEy8FP#@3l&Osvq`yOOuo*gK_5KJP5jPt_!8Y@`w#9{csxcwX&xx-;?0b-}xYaQzp)q?pZGj-4JG)j?sDu_RVg+!i>^P`O9AIZszDo-j&r;2`uavPpzvB>{CgAwL3>p%>vS_v zO51XwZ$A^&p0p?WSDCoJT{B?I3l{b+ACp6G~oIxtv1VZTez68V9eKbzVe zK&yIsuy(5lJoa)dHNWivMd!Np?V?_&h{@;k%JxFPoYCoHVZPX2wd>U02ceL?e3|2` zVI=mQH!aMpO2g(A0d}X!=`a*3ThUyc4j;Zb=U!-$P`8^Jzdt_%?%82&b3SB1B+UCx zm2fs%9?QNwpp*;4=Py@lN9EyS+h?~ICi!?`KDp}9_k6f?d?DvF79jVN)NVWDB9txt z@bznHDI_nj4ONCwLCv(jn^{7GYG?lsy;2%(o}oOJzQw?(#l!s{S21BaTYYLrH4|>p zZx=3l%!K-bl2v`1%RqW0ApZ5W9Te7>NjuTJ(aZRFIj7DCcFA3?x_-eh=&Wnh!EOQ)D;7VyDw|54s-q<1{xQ&-MK zbNKC{SCx50URn40pmRRb&MN1;bt}gEt*akDyHJeF%~wo6_7vmIs|##Tri&q;?`NDd zS&IAWiaOw;ph}pX?za( z7|~A)_bTp2nQSn(-}`35M#g=&#e>4mWb~Aixr{q=aLVT1X}&GFsMFj1&Gc#>8Vo;% zFG(oC25ZZX=4S<%7qM7d;6(vs+J2l|?o|wfrs$VNFG`TV^ArD_&{9}F-Qr8qr+{=~ znln9<0)y*e&P*B=G4t66oJ8q3LsnfFw1|P;n?I{w9%8^v{Px#d4Gfr#+Kt8p_>bWN6B?smaUedlJ8Y;SC+ zc$Zjt&~~_PN&XggB(1yHe?-b$iam2RQeM!BG0@YE@tnO57`N^Dess9 z++Chitd>@YddZA&qphPf9G>sYUq$#$aVa&8H$>gUT$15L#c6*A4E! zX5vKPwY~Qw%TUt2g}+@^1y?p$zCOBR3j{glte|!63qQcW%{k=353sN6cY`;ZClgNfOF=jN#-L=WL{YXQX zuVar`GaVjA!{3htGr_SkQa@ou8H6LA+ZXyC!bfX)C(G~7xK%eU?6A}a>4y^~Ew6>( z=*9bGO{XJarX=Y3g&vLI;rCy>&Lu*&V6t2=FAWbjIM3{UlLpU+E9)0|lMpxLZ#TJu z40CtNK(byQRFm$dPae)g)W=(Ddu;NsM!`>{sGDa$uFEa$US5s^e6q+&o;e_NH=UQZv zTo9xDYK83LKpf_Hnz3R@Fa#dvh;g}xW8z7wnyhgIGJUEzU(Jogu1h>x{HZaplhb&6 zRf)hU&TusyC`*B@d-7sy_EbEW4GwxIkdDoKot%pXNZ8WkxcqHrCRQ9W$P4Hs{E@Bd zCq;v7GkpT~Q(H9t`(Znj_=H!P=XyeMV|Ky}D+1KL zuZzmxMvcGn4EX@AO+(qKaM4_E81p0zRVhP?&7CCNFkgLdvt1Un zo`*|Gp2)(qje^z4*E~#RGwHpAUm*uA&^#+$g3@s7hX(9a$Tsf{E!s^3^Tu-%he8@$ z?|6(+73eVE)jjT(Mu$U#TxxYT1LaHZE1a6gL}Xf-10PX`?All#8ux*Tw4KK~RL5B; zlRX%9W0IJ6jnQJNgD$v~`SzT*jwd#6aKAKH))%9fU1p{p1me^p8kOHU1_s)1CDMvw zkhx*%>{hQhSY}EtUeJ<=m4~ytdHPeak)!s@^9NaolyE3N7@v)eqDDXH=g1g*YPhDT zjf}{BBMmBcIT-pZ|Aw(7AC405c}S;;`1(qGj{MExvvF#5Xr`2yUD9R9SYwFsy3 zORfojDaFsBIh+ad6m0&X6A_tC!4YYhG;v!7F2C`#txaTLaW76et!F|xEzm~alZjq~ zAD@m~W@3wWK~yAB=Sc8~K6>~00Gxfl8QbWaV%u;|y(tbNX(2~+?^Qb(^rzM*o^e5% z%>I&wqhYwl`(d|cQy2{N)b0*eMS^QHL*~9n3~YSg(!^C`Fe_&+y5&YJu0I$Q+U^vG zZ-z|IV}%Lu$xrNeXiY(W(8^?f$uxYFSg@%|nW(2%a|BJ;lJLnSXi?0*4BQ|;UNI|} z38x1)SJkLyV$MuKzA=HD%}cGiqy8ulW;3j|(DQ{bTTb(RPbtOvCzlIbMJQ-~ndsQQ zi-Iow%2y71s92cS#T)EMwA?OZse~V5Ot1=W^wBU-{qyvTej0wh`7zNYO^2+88}Gdx zbgcCDm)lxO$K^v+=O~})2s7WZdCqDkLQWJyrGtr1wF{R%thImvJ$j>Gun(N$T)uKo z1!Ge3=LI**NZb}S$vgKflE{~2UhVCRg5-{@8}oW%!MjjQcj@tXv}{>aI#(nG)|q-; z*UqP6M}B3DlL-mw-#)!56WfNuQYjqJC7F6wNv92eX|AmN)PR;;r0<6Z+=@ z;V(mfbU;4{ek;~xKkN@dg8kijUwM|l5L(OB^9TFI}?N(H5Qjpf6~ zsW|uCz03bb21@F04X8Mfan3kZWYO*dbmv_q^_CTY_f5*ZJC_TwFDGK?k~&c@3VK;7 z6XQj1;z5A9Dg~<-7{8joi;gRYEB-5;zjRvcS8O^K$AB7Cz2D$49r+K(y$b zyTRc`C^hAJ@KwqMp`KiC$5=jCDYou?*LVoR9&R{eBp->hbT_|a&kV+YsJd=jb z$e_R%ni(J~bxWJA%LD>Pu3Rb2#E(Jw3L~v7Bq>Km=YkkF(*xaocXJUF6ko7hst|8) zeO}=2ScL0cT0`;KMeup`@(8CwG4ArU95vcdf^r}A-k!QrXhw!t3-*>`2hIkWanLYd z!|kM7039rawv4n$I-(8iJMKPZ;9f!fhbOg6P~S-fiC%GQRbIH-c92T43MS(8X1=8Bq2TkaHz~6Xhr)ha%lPOh7==AwcH(jz z9BS`BanVl4MC5Wdzt8FLx_0Hrj`U2_-(FC`-jjs^jv?P0@3QcYo56c_DhrqM*6LSh zWaG)?k$YWUIjH>Ub?K->9#-WW|FG>Vz^w&4NwacAQ0uZEN}edfmiC~x3qBTM+4{5d z-`SVI{I*tY$W{s(Pfq3zo~EE%&(Bt(ibCXj?c$6U3LdWtRM;X##p0vxtc{llzoJ_D z{KXsw=V?87#)M7A zqL`QkWq7jhQ&GpmSkyL4`IA%j!aI=DeUm`?CtoeS!wdRXL?U69~VmHJ6&s zq9clX@1;mx2KcgilH>O=;r}-JO+z#j^-~f<7Fk4|YGCs&?I{aC*RPE5IdU9%NBq+> zd%W>cO}X`^ODJad>&I?0j=|#2n7*Kz7z{4E_uIEsMqlbvIF78qXPiA4)wtXC4o5^Tj$H{i%AQ|lM zk8fk+%L7--xy@ICOX0aeDZ7fmlgdNtU0vr;@bg0?X%X>z?-LJcyXi~CT%G$a+No4< zTg)(xyJ!$CWa$YKepdam()O#fbfibr9B%bvfW#c(eg236j_O4A=S!IQI+G`G?D$nGy@Jc7G^L0N9w|FEEuO~HRdbLEnr^3Wjc zRDC{Qr{x5+`i)+2NQHqXuchLpMKT70+q{JJQ*bw|>0zW@8oDO#hO<7A(E4!npxe?+ zsK{Iz@m3}yKb)D#m?ER8p=r;PpJbdC_jT_rOySi-AgVoE{ z+xACHaqpG!(hLBZ=&vT7k&2p(NGTh zeCr$dVymZFx0Z($n zxfq1ruormDNy1kT8?{ZFN#KqVrs>xPRt7r^{y4MG{}o*ejFmv@XX+hQ))X60cIf& zTzHxI*)g+^jliQt@@L{DcbDPtanhm*_cCxtK3l0QsSCx}j;nLxby2@UAe?l<9Fd7H zwB=j8VQW?LuI;H0NV#rR7BfNk9@fb5_ERLvG*)rOO2(roGvkiCNCNJQwz|%KP6n+g zK-58s1g-Sc!i6Q7u)cV3&m1o@np5I0IXdQ`Rx)UvQ+y82dT-&UIOc)H*6(!PssI)e zE0$asD#Xt$iO^=gBJ5kL+VD)X2${o*TbNgiFfH?C)j&ouq(>9D-6rfo&ffgf@{dpLFDtylp1I8_LcZSVh!1UG9p;9%SsVo%=XgCkLBONe8EWu-`KLyr%5=K)9e#t<2#MPP@hx4q?yqDHz;K}Aa^Bf6Yd5H0l zUOd2nQ-;HBl`JOY(k%6Rt}*fOL96T9L>6Wi-QrLq>Qr}r?kjJCv{9Ki|7PC@C*R;7^Oig(5!W{Rs>n)aAT2upOO-Mq;9Y!qI4Ki5%i^}N-^&7% zWHP&}KNtF~2Yl{b&WDqAm&*B|LX70|@F^A)Vx?g;v%RDcY3quY9&;$cik7t7p}r;f z%3xf4bG8H#k`XUFM@j*qkk*($D!is9Vo$%NVwAe}bEP&N2}#V(Q6hi7cOZGMUNs%d zi~7+qL&wA-&&sS<41{nHm=aM3i_3j#9VKulBf(GH?+6@vd)N@KQ|}fmWN$AL=-dm& zSKY)Pb>`6F=t!SYIt;(X{r9$?v4cwIvZmQ?XRNZ+x)Mos!TP3PnpCWh%Z3!y_DD%Z zHpF>Pr|5I%B1BJgZdiIQp)+u6t0l&lyR1&Y7mWg7`Pr-ulLc5P|8kw1MKR`vdac~j zT7t`5MFNg06etYk@*H19gY20v*Q5!2F|s%OjDUW>BL0Tl1A-| z$5~K$6|hUJngxqO+4gxPGZe_kdl%-};nAfpyiwwAn5VI%XY-&x?5o30Czb}_>pmMH zT6q|rnk%b#7{(waqb9ieSt4Rj+bB!rBq3YtS?uW#NeC})(>HjUjM?6!i~Dz_pyajL z;`Mt{ppoo5_t2*_Ogb?er~8R`QIxW9z$q6|GQ#ga9?65Qnk8ri-;!sVe5U&zKu6T zdGmX&jC#ZTYgv;N!NaBK^t^A@jDY8sEnb`iuKLoJrjtueLj38>U3=fAVntc^mg49% z+(_2Cd8s-b>!UV(e0x6={also>K`+~ZImsp|CJ1RqrLQS>q3OKH0=n|2* zQVd_*d1j2LllXMR+Ol^O_(F5v^16$J9_3DZ$jBNhtlxZA`M8e;AO1NB-&YXxpr@$M z*NUhk`!!2mX4BEWzQbZ_D+A;DKl`oQ894Kk7ELGS#p#v1)yf1}@EBeh7^Gc>?z-Xe z_FW3NEgF|ywca0=(?yI|&!`IDWR;WZ{B_ zg#3hLHu^W1xg0VlgDkO~x`e13>EY}A$9%|;;v_luR+5qIaYcXPRt~Om9t-WV&BdCW zhQ{wU1+Z>pndJu+;ovbY;a>k@#JUgg6$TX})OYO8J|Yf0QIs7SH!g+xyBi&m%uNB{fdi(m z`l-2;;N$qMcNi7VGVw7V>iz^@vu%GIujPIgxGsFC5m78d7RO|6xnmiY&bD)=Wh{le zMc2K)9(kC^X!gy7>)@ec_<=E9J%T5@tExS85Q~CE2PWV6Ld*74`bjo_98x9+S?UI2 zyWfb;j8!0Rmpf9()`7V8h3#>$UI^;%r8J6sjKu6$gO2haQRoTSb-qQ;^~vjAK-dW~&` z3vsF<+Oc>?F%(55^OY?Ky~pE&$0EuIe$TD^)mKMi+%27+vvr1oFCAl2r(3D$-8Ot` zcQawHbH?)vW#|Z5J;j?x;9QnZZkU$q5OwC*g(t&{2s<>%&EF?ohKQdMg|;8|!|~_y z?D#XDs5+`ZQG4ZuZRyQD+unpDH$S$s^kX>Mhlh%s$0NY6n`)Yw9);KZFU|?_MkDX@ z#f#@HqY1r~Zg)&e40xBb7cF@hgYp~O-B88*+{jqd*|w`Tm=76qxAbZkSJ@AXRB7aP$pP zM-C0DIeSpC@ikj?Rvi^1y=50aH&bzW-UzSMM=FdT7dXH8LPhl6ojP~bh`9Xn+l3SI zgx{zhIB!K_VMiWwPY9g_+Wj{t<|!G%>f)ukq^q{z*qO>T-R6qW$bz>~x7^TmS7EeS z+8s`OzO?BocML4vEh)U&8yjz=k0f98hX1>Cw%Y3f*n8|j*A@PFOx$%9VRJ~p-oS6M zKSBu|48uIfVq*sEk4&wlSY$y>j3zL0JPS|B@9P%@Wx@H)55?Dea!@R?Wvrt)2i=_A zD$fWUvol+JOK)L5UUGYLg)5GgV(ucKb5F= zkH`jf5d4A21FchaG+4`dJo~hV0p&Gc%M{#LnCld;wSI>yWZjQf&ntF=P+-+Viy&Y0 zKaR~lBOZYEw#?WwbpcS;YHfaC7=&dKMlrmqp}3t~)+)mnjt9qczP>yY3DsM3I4X$W zd3RN4OzmI_!Um$&d?a*k3aRqf3M13emymJnVnrqzJvX}7J7;60SP58zCn00__)+ zw=!WqYnN=ckkB`+JhpL{P8qgUxxqPmKjtU9tTmBx!wW9Clv54CNcnKLwTM3g^NJi_ zjJ=6~)W_@B<`6hj%zWe3i7bK_dFY4euaU?+u~vq}N{8CT4<|!|7~tI{`-4i<2L_)rPDegr!Rd;?(EynvXfb$u^CmeE zk2Sn5ek={f+H)ocqVENxC84n_MIjWSCI%a?=$*jTt5)v>uZ1IDk#+TXPc%ZtFMII} z$79>FkVCA&BpB)oJ)wJNVgJ7G35(UqusyYRHcTWJ8`kLa^eX4UPyN11Yj+;hjnBFH z1rfShPvJA2gkICK;EaM!Tp^e_N|x0GZ)%vK!R;qNsYfnDVKz*)P zBxXWKj=g=8VK)nUtD2OP2_D2qQ{|bty%An;+7;E0I^e3W+^ge-Zn*h#P@tkb6mq@y zV_x5mM9l)*;WgJ{K_ab}vlWg#0+q@0c&sw<&FU4D~6wI2;ZThG?%kI;Z` zdz>~15`0JN{m|RnW8)`iD+EyiaJhw~v z>-7>esrKgHVy6&!M~r2eDHTsT3p(ErJW<=36-P%(sR-3tHQ}^@2L0|Bb`nwF62hTY zFA4*9Y}0~|U1UK)?1RX2)iOlUEF@AlwW<4xRM971m|%z%BFvHQh;*6wJf@WooJ17O z>Rtt*yEAFhGb{r2&+v4-E(RV?LJY`usSxr}(;Omnw=QLkV!a15QQ2CgKSt=0FVE+> zXu2aC3nW4|1;&%HOl9FiJ)c~dI=&&&?|kUReHQ7vLd2sDA|H237UG^^nZ1*irBYtTDQT#6lL$0vTPM?2p;_U%O6}GP^yqvgX`Xi zBHKT_ur~m7t5p(fjp88NCrQ5Kl8ELL`#z5DPsN1Ex3VCEble-eaLxN>I=H&y#JbLr z@NU12*2jyP@SnHwXs%us_{M0{Cnd5WyhBg5=}0!-3Vdi)pCu#PXIn|%+#Eum^eSn| z{9N3P+H|&|i{Q^Dty%ILi}7Vnb)LuLVnj_9&OdUl6f25e;u$9eS4;%Q(g?k|YshHq zBLc^C@IAIbEtLtJ%uksmbkq0KB5qNSmZ5<6+xvY6?uc~-GztAn%;N09rMmuDkrnw> zNH`jN=M@~dkH*5e{L#kF-ej!YJi##~n}Yk~H1DZf>4?-9NNyb?fqeVC??6xvxIUL^ zo?VlNr8Pf?X20j5`}j!38!aL(98r|Bn2V%0QNI$dlapWYY2QbPpTAji^O{LD9K!`^j`rUDtBV_+&z64J$D2Z5DJ= zxZ8`)5~yaw)_HE1@)3AgEL&qZAD6o%Ws;T@g0dle<5YVw+~-O}c$!gQ+f=1Fae{&m z=Fxq5@f6Uvm9WPYQ=oqTal}=Ehta3j#QprS8=Y@Qw|ScwqPThQL+fMakZ!K>td_Gt zQ|Xd+t~IuJGJCrvw#fmi-_P$0g(KvbUEW){#}^w1w@rxi1;JZ+hxtm06PRs1{bf^p z7&4SjR(!k|hV)`}Ve)hs&d<$ULERn!j;v7Oz=#Muls?a{w;=)V&wdhkzB?Ht9;u24 zjVX``(@%7%&Oi{&yghL)=MVVXK04bu8@?^!H%)!>nAF5AUQwT znQKlS!9#4N2gnp+VA8?6Nu>x^xQkOsW5wXPc$2f3je_If*PdNQ;OlZ5@@F3CP+=2N zSm*3RLmr8D&Uaygr_$wGB0=c7?N+N63owrZjNZNNis!kpYb#_5R6P8AuAu(7(4k6L#;VPHuUWiG3VhWv8!X zVJlm^_(LKNh3NIH(9v!N`o|2E6X?$9sQHT>%9V73ng;;v#i1*~v zBDf_Pxt&NX#@cBa_qxxesMJ>{yI-ea?mY!3Y6KlNW896^1de<}&F_?bG863O9s@%J z?v%%QvtITh6UA?yG;z!=!`%0uI>v;`uyUUR>p{Rq(A+HgznBw3Z?rzO<;s{`2 zO3gCFJB)=lr1TuaDi-?04c=DB%E0Bksyu&%2_CnevftNq0BerZW7PVOVZ2yeUc=Q3 zZ5bWwW0yyOe6(g|$W$au+4Uqh-XQX%Gik32S0o^&r8V5vAsP1zOjob_nF^nxPWzkN z(uurBDnGuMgc`;MjSA%~(C@VgifUvbW%I)J^#rb5u50#wh%FnF_75WMw~|pBVtGGE zF$Y;y^K~cAuqA1<-0r33WYb=~{~fAVy^BzP4I51-z)X%Qv#odNbMk4u!nYu=i+#OXs=KE1$X z!}Sn6(92+@TnNVv@ssso`_nFcn1sP6fsRF=GVp0rV2|yQOq4Wj7HA@6LRQ%E zW@>ph3S4Bgg-+(cZ^4S326`?gr{^4DlPe_FwZxR^5qir|Tg}a*3>s#~cTJ7e59l`NG$d|ef0*B-|4HL8tn3d;D^A^%vxU*8L|dy`NJSs zx~@%3E)pNCPxm)PCBd8b#ET(953Uv@>S~`&!fvyhQ`7S^FkVOFvALE3Lxm%AJP6&{ zaI0#VZfO?!4!_iuX(IFhs}|`C6YIY=*(J%&kn>>Wkp1>8fmaFY>NK5jD}eNp$#y28 z*HXW{rsvbwVhG$#%brf9U`gtRO&UbpHz}TsJx%B#x2bMy2^A*z9JTdK)-;XKnN628 zK4zefeR9f}o3Q)Il!0AJOx)X|RqJZTglaXv(Cn5nn7esgS#hikMT;&KDT=5-b}Xkc zN7s+|Pk>)-(x>_1n;T1C?qeW~T5kvD&WS*NX_tNJXd=G&-?I&Fgc{1sD`yNhuW-z>KPD`u=JG7?tIgIz&A#Q`Rpz99jepmpiqW2tR9; z%w|k=pyG|ubN3XY-n^Nx;Oy8ifiE2M{KC{F^h$4+n4Yk5#$vh4)+Zl&Vwd1BmG`tS zj);if7dQ3C-aDSso|54R9hrEy%{l_BL*nK$L!+=gbXm&i>lo0DALRwf#p8ah=}Y~w zM37W9c+NdahwkW}gfS`!?!qSi_JrQQYEkNNnR*r;_ISviXv@aykFA$UQhA88%02y* z&=HckMcMtn=40lGo1~&>G0w-{4Qd=J#zy$Q!9SyGV10HaK{mR@~rYV z{iELqd@SsXcAGdIhX&6bZciq3Ic6T0nvIzVk8rxMbY2;PJy%oclLzpWmF1DM#vZ&Y zFUM^@MXZAgP5*L~h|`Z&ai20J>WSv}e8R>_@u=#aOxNU2$2Kck`++*buCx&Y`?^vwaT2f45;n!>frd?<4}EOjK}(*FA&b)2$^b&1>QSuu{#33v++Xv;mP z;;iYS-o2X%y?RoMLnxuYU;cgzt9CyfjYanoBYfzXpDz6~{Tbo!)p!N(6XTB6YrW;& zDh4)RpH}bRO6UP24xe-~WMWy5)n_|GzZJ7&amCjO7QQF@CGA;T21|{LAA8kwkXF@G zv79py`&yMFxH3W!{B!)~t-=TxeXMRdb0-RG^R&3m6YJhIgoCGIY!aX)oOQ!tQ8L!E zOMSijG94zpF-EJcN$7}pG~Re316Q8Q7oQQ%M0)T#X`;qnpKIsd#SU@@&j3aFwXj z&&C70r4eiFvSAx9alu)LO#B|wobOf>{-&@pY=S)(#kP?#XNn35z0Hp~%P$pTg-3HH!TyiMD)^>kkvR82rQCF4A*UO(DAQMGre4mMKF06!%YTe6nab!BfsYx&o zU&j}vHklDTaHQ(ohF3-4XKQ2(8Wlq!eSXXQ`viWww@2)(Kq=}!i9S6i$bfZS^#;LH z1peQ_eP(9@F$KIm5J&)rL^un5R5YM$}=Yp`pTz!wmG8 zseBkD^wy0zynL7TGGTX@a`yqTu41w3p?dS{OhRwbEe2y2!AlENY>pw9Y^qSJqv12y+|SQ65R)?O6Q4nb&-~xaa#FUl<@qNEfMeJE2-93 zor^Iu(fcv_0D)s1x_Z;hm*8*i%J!G`QLsj6N$IQ}6`9^Kx49lt2|cK^#PPiZ9`|7? zMTXEv`mKnITu-c*QYcv8^Y|PSkNg*Gts&x}n#bV{b>E15YZ*_MHrILe=UX<5y<2@0 zo`OE5iwT`yhjp(bIo2B-uA8GbcKbkyd8(`CP5|_q!>lgagur9d!?PoTVVHbsW!iEx z7Gb?-Ek=|Qan@(E`SFNkjAng_-=dz0v5?0zYvyHPxp8~kYF;vY$)$_m^5Ap%B6$SL}2T6~X?CR;@7Mr=Jw33<(kSee)DmK|PefRn7Kj z>2p)Tzi#PB3xR{(x$=!+A47$_!3I9h3>vto7mqtl(IDCD7RnG|fM;i4^@J`lA3xL{ z8Y0$DGAt`~Ub}08Yj9v|cSR7+PCrN&hz`enG3VJY$x(0#UV3>)MiitrE$CfW7>#AS zv*vqe$3ss4yT9J9M0`78Gk+ydGR`R8h@sC<#~1G)?*2d$m~+0fWfqZ8{O%2xk3a^F zUA?-y?_m~B2~^%%LaZw%=PebO-;#r_h*5nVS}tl&F6rkU%thr<&MCI@`MBGg+1aOG zfNfjyn2Yxjes%fJ^S8^3P%o0cOFz8?UF92A$L5#7VoAgf)j|rMsg~S0)J{QpMQZlj zZB&rlk51kq)=jpzyczGlL98#=-Em)l@WVpK#Wyt&dT-T<7v2g){n<)dM!Mt4fNbWv zLl3o>|5tNo{topU_3@G=vK1gIAtF8J`5T@mxUSdbC-*sK%>B9VbKd6-W8njQ4RqHK1oXbpVDQM&9Qm9V&beAOZG>aGvu)a?>FW#}pWJc}HmZk_MY(LnFqg z(_msucbjK>22@|49d_B73GU6eHr~FEIvd|9wfu%m7|WQc*F@dPro_?=x-gt~Jg$35 zD-!D^H8pGftFqx#!$|A_S{`(?q<jml#-zo{H=b>N1cAll*r<;qxF{z@!iD(2v>vSJmE;xhuaLs`l9d}Ua6EUn0^n&!c z+Sq8vKv?|B5S(Tm4vb$EZrA8UK)2++ncLF}u4o<&p;C^|KT>0W zc6~Oj=2jfoE4#DP<38+u?Ojpt9rUe8+0G#OiU7Zp6FsHHGC_{Qr@95_ zwa9HR^gOGGa2T37ss%_;Z~Vl3bT0|6_|ZB(I+36%vs#`D^+ul!zXnl^3n9u7TOwS^y~_CemLE3Q9xvpF-f+1DjJ#wnWc>iChJcs@C!>+@X;WwzT zRO7c+^cNMRe-)O05=33el#9CH91X6{#38&rt-E#gA?7aV3S$8n@VRkR3u8D;F!h%O^kD_4it(&m&^(1iF-#fWu zF$oC6OW%eVQ{hm%6cal`8uTsQ|Mddv(akRV;)K%E;JCZia49$L+n(2jW!B;AFEGl>$^>W^|9C}===og`;!=S^BI{r*|n{9f~z%@!|coRsD=~>`9^<>FiHI=7}`0hF52#3?>{+{J;|s~z07MhG((>OY|l}b-bsMAgpr=66cR{XetTMnF9%GB z&#g+sb75^09fO5=9%vMsu^o&rfcFfSlQrs4pZ(Emi{Dfc7zqb*&TOE-oyB`~KMg1l zf5_E^c%1?!i`5Tfswpu1Wj0K{7SEskv|-gSDiCF0t9Mxm3^cv_np$20)=!2uw4BHO zl*G@+`UQp{+zd3K!tL`QU*Q?p_f8?9mmo5bX2Fk6rdn z3IL)IYeUac5NKPqxeHXpK?@-w=;`YeaL>#a$QMcl$`Qkq|4^5Dv;6Lr@q1}-l%!WX z+nfdz-_O~5UJ^i-hp()hkO_2pyt1B!nb3BAU#}N;7SPlbNb5J?ykkWRW2t*KoN0SM zqTYh@fXdH?9F%flwB-b^^tn9X$n;B5wJLyZrsSB`iUQzo>Mg8rDFm60<_;n=8J^!b z)O9kJ4DV~2*8kKgg5foRYU((brdvT5Pov;%cxgZRAzv{B3g2k^fcncWMw1O9DLDVJ z@bcS~BMnH5b)x|(G_cv>+}oO@4KCw-xBYXC;fGJYmXD1MNN=Cmf8m7}lnVEsV!%4G z|FM{^Pq?q{I!;(iu!sV)lInS;tK)Dx3pS#LM;|@Pg=jg0;C8w^P@OU>`cF3>90pGq@ye2+G=-skfv*U5FLC73sZ-!URr*2d zUMtZk+)i?hD>C*}auC=!!iV(&~K@ zB&Wvy3burU`Z)8G$@LL1_w&(DUO}8U2|4w}qMiUsGR(7f2R{mE;O;U?Uu;Mg^=>1xNl2Xcj}}06rj$YNjJN*f*Qf9a!mU{}3aVTtiGLQOMoj*qBy0qZgBI^d@T0NNdC+P=FU4&1q5uarGy`VYf_r9ItflxV> zq^QFg0vcaS`~-G|Lxt#pu7Qu?Fu9@XAx$(6s@pvChsv-Y=P)pEvmq7!mLJormdSuw zZ9aqh*mv_9mrUM-dZ^0ssjad2{N{Tw8@L(g*IV}cAM?TU=%Bys2?f0O_u26F?6O5Y zEdS$#1gtNzafui&w|x2#9t>!~~@ z#vT7bWXclv$y;t_~!bDXpQr!iqlt6PQC%umx!07U z&r4i^kghI_&$`f_TN%Jy@(Cq!vN@EuSvf4caR4s!j&9YRIG64jEAdL%4brv_^!us> zg5YrV9-H())W4oz&=rjY0j`_z#_`br(_zWwkuh*9z=x10i}y86!4#v0B>2JNU{PG3 z3MVI1GE=dy*+xxzt<#$c6V<)%D}%CO$zs7UpEn;UZk=pF>SVaF^S~0jFY3FznxCCV zeSqN&&-s~s6!^4_8ku*S3L|2a>yDezZzfm#)o}^zr_ZS~FyQm|a)pf)4~+(kaS`jT zRN?a_o@=&4MFUK=wVVAs^g+mrKRRdO1cXt{!ik4Y<6LM1#j?){rj>PPoOZi`iCT{5 zXZ4HVY|`UtALa{vf>D0o8FPvG^g!4eM#wvRX?a^Q6&4bzktYexo zyq+HOK%Hm66At=j8icx-a(Ta|p$@^ODx}Q-*o|6kBMnai|7W${32{>(a<2E~R5}NF zIYf!z$KIe^_W8)>zd;b{Prmj(Aqp05IXK=u9u0>}RTy#)$Aj>u9Qm2csB@8Zk1s<# zGQ--DLmTMQ!T8X9S))no$`K``0XH1eBiGGSrGxe7hk(6Br1gcCQebJryR~rCKo!{D;0r2MEITC zcpmUGXLfFBp}=i}8R7yyFUpP_xA0=8Lfin`2dL?A3=u^msc4+7;P;pa52FsRkp=PG9z2A67DJX$|S0%O9+ z_t}wX_|e+)ap7?sBwvwu_gOO@RLGn3#R8Mz-jpEsm7gi_x9%Rl5#C2!j|qkB3&?;V zR%ebSCG4v;(r*&Lb7GE`?vwZE`xmz%q4G*kHe}euZtg%o2v6_Es`~@jCkPG>BS{v5 z!rC4Kxisv1JV}{2d4&vDe>7kI@tO?rj2EV-QQx98(C*z)gZuUTtmhS3d>w=}e|P#7 zgKb(+*3Pr2YYBW(ehTYb=C|KJZFQo-#j1>3{m=0J;heW<h-Cy*I_fw5weGSL;Pv{$ zJ9ZkN4@9fBu|sGk&~GaexTcl`Kj>M{$3O`R=tr{3a1NMXtSW+lKX@ z3A-y_#dE=!!t!UkS^?Bf4h|o0D}dkg#!=iG$-v;kOT32;9sS_~$d`pH*fih=hnYP`FOA-|rtt!*#* z?0G93zlVB@>e!QY9$2^Sj5d@GWi7>eB-dr*2j(DKX5=K#>lsj*N+B$y(W)3(HKxSxsYku z6$2j*UKqV}C=QIgDufgBlJUOt&?wM31v;%QGB@5z1-Ilw&vIU(kKMKwR=YPiSL~h6 zNFK?6cQq}uZ(9i<08DXRv6=8TphGjcH4E~F`@TKfMS^m**$vVsQEx){H5ZM2u}5A5 z?BWFUa}aRRX^km_KM%*mXP*^<&cczh%psiryh2mZ=)tF=rai$qKKTq^vE4KDV2;>u;!m$<~Vhx|FqGQ?Tc-QHllh zJPYL0yl4%*qY{l#+`(`p`JL1+tUn|Y?Kkhlx#`~iHJW=#F(6RR!x@7*@26z_?{_4V z!L`lxxubI$%pHzfw|+x9>hiqGgWWS=p`_n3{AVUax#ycP;Xbh0V?cI%I|(9GrE>G5 zNicaP%qP2q1d8bzcR3%BV7JtGp=(hNtf?!zv#%Zf7_&CyeD%(SnCZaIV>LK0-0d#x zhPrMCw#z>8l11?Lttc%)lmb(=o-Y0uD4=*@IQ}&O_d|=Fx$99kb?R@3YRs(?aPJ*3 z%WWxvu_7beX?hyOtWzsJj^}GR9IpS^sSl+mlRUT5oriA~T~_kqHgEzyz5Z6=4lm!P zGd(x;gw0Zhb6sLyAojQ52``;DSl9iaU%SB(@Uck`$Z%;I+ zDhj7PIvfLm!SmXwEXk1CH9^RzPJ!}?29MEzROt0ca?JHg2X9MFN#I5Ol<&6n^SiKr zW1w!TWS0ppzZBz5eQ>_5a*&!PMufK_14}p6Nf7r%VJ7HB4p^mU(H+{H3!8d=FvjDY zsGFIvp%T6>bWJ~W?RFIaTjqKG<0R~Z@!e?d8b%$9wnkdQd=c)?O%uDdiy?Ha*r}lc z><1{4#@Kh_-0P^O&VBU~7;V~N^7B~|SV!Ky{>)+DgPJYC3dzMlV;cf^I z6fA|AxC!=~W~HDvBg5U|Pzqf>S4WoU4g#&w{T%y8E$A*ktf;A^18cXjrcAY*hmyp; z(*yiokRWB1(Xu@V%53H%zBmNKr(BUMA7(>gPM>EgnmGo}&L!R;XvBd)&nd5?Sf89w z7Uo)8l>kCFKPz**#QDL5j^47xbV#qZZ1fE#!13=+Lru)t@a;=*wvtaSY<%@tzAq2w zzvhpo8Q0~*x2sHpzrUmZ$+l972E1SHyU=Bqj=oH+?U!9YT`q!dEs~*&816IUSx1N! z6v*_}k<)yM`qwBE`x^9_@Y}fLaD51M4o00@e^gL`t7gnNqP7I8vMAGLaqjS&`fYT# z!$o*4a)bWsQE%9@*Wtc5EgZbghvhJ2#=u_{vCDqhI2U`ox}kJ779^UI33FfLpvc1@ z$@drb&!4Hd$&)j{yo>O*@dg1LU%bfIJBszl4(*19BBPC z+1Bs`{Y*-KhCQJxfXAJtw{M}}j()e^QWUZqr_7Qe8q}C2hqD~?wP9h^n6$0XNEgnaO!Mm1cM<&jM zgZ1ZXgT%TRm=9GdwlGTsM{7!m)lCv;hCfbZqUFMtC61(ZsMGv<%ZHJC8-0F0PYgCs z;M`%+z3W@f;612&h-Cun7#-_Q1&-;_pkYgE^@0fvr1su=?_@)Rp1Ah5C;aGxI-O3x z_+1j18B5ypI80%SvD0g}Bc5K434daoC**$Co?})%PSrjSBtwGY^u1Wb<;`KPwd! zv$l6sqi$#mvE(n^i*!g(GZcdC(cjBPE-80CelCul{kVG!>saaSLUhr__OK(OVbsDB z{d&n^N}D4v|Ix4VQOZFu(h!_CSQ7`#zRLSa_DLXpZ2!T8>*;V`cGQV20`kC& zNZjVALAusdB+1+xzEReG{_@u!8n4z}zSbTF`L8;0 zq{=DH;DzN!_BkVrTX{M;jNIE z``esM7~qwj7L6kUZzv1Z^JX?E%FKP?-jxHHZv?)4E-8RlQti$iJUG88(|IJ!vJg0r zo|>A*K6T8|vMWo+$iOnzJR@`)UzZomcU_;NZZlI}xW5-cS6P$KcxN%p z{ADjX_yK*Vf==64j+8)s-GN}|^)wJS?hvwgLxZr}YZjMo><9ZF>x6Ekp251%*ruC& z0T9X*%Bkrd0{aIvD${bpfNpU71aTn>c6Mq<+qOpo@7RJY1jN8|mHCi6Jn>*GBDs#g zKN*aC46|}^ZuC%GxT7T2;eX7Xykm@Yc+-u)<>Cd=Kjduy%dzk1uX#UXYDoe6)0tJQ z=2m1#=zaBkvw0Di7PlBZ9z6$+>0TFlx$S@>XwZ2rw>xZpCT`}L<_E&UZ!S)Y`$Kr# z@Vp&Q0Gv{JCGhS*AZ!V%jptGig-%ue?O#rZ0ilXVd59+h-j_|Bt}Kj(U5$@67zrj| zzcbq7utE|Lg%z|)@1#K2zLu}Dv8f>QJpNSW-Be)cawsp|oCYJ(;b9J_CsU}YZ7j|u z!22!CE}A0*;BlqM6k240h;#_Jr4!+TIr*~2U=D-@wTIrT&V@|sg^@=wc|hpjG#RXx z4~YUw=kv_b@9hRp=5r-7Xz5H1B?qGZV&7GR%{>(0SnFA#^d9RDJ2pDDoGJ$WgG2Xq z@qBxEX8$I~Kq|y?e6)C#L?Q&*zvO+oerp!=So{tSL|vt( zJb9|Goe1SqPyIp%@%-C%Lq{qY&vCUUtLJA(px4-SiJldGEjU|^523GYkH%D9^GF{2 zJshQ&+Esx5JmcFg=Hq=FH#?VB^lcIdR`=8{fl9lBB#SpCkn{6H{ePP0L9sFKAG8yFSH%flzqQD==FFq<>6tE~$Wn*VU|D_+=8ytvKus4njFtEe9um0GO zKQ~KYFu?kjd0z>XZJjVAV_!%=K~FI7suA?_DsE~o^nr`fSA)v8`9qVvo%ubiPbyb4 z$qe6#fd0f2k=IfGdM%NZ&$2rKwDJnvE`CaY*rz)lv~i?>HS59p#fNFIK|Vldw?aC^ zFx4*l;yy0s7tIs!D;*g3mFykG&)J0{?KZK>OlUEeRC(P>f`R`uLpcv+L!VYPjoU37 z($7RMiD6yrg<7du$VRLKjs+iXTFQrJ*MO&jwFQtWE#Ju@kG?chC4rTGsEfJ0&|No0 zfnYVoL2aOdm~Sx4h#vmlXCE~V>yV9^=4lB(D%waiT#W<@8 zHq2+W!;U#FHyjxAU&4v&FE<-8=D%bUuD=@K!aV*Z+_?U~h6iK(Yc^wy)y5XgX*IAF z^H@#rVm>PkALg(c;m5pIlK=g;maBp7n8$Jx{QtZaq%Z&uaTxs@T4l98q#{JhwVT^x;G_Ji` z*^9X?7yB^QawCH={}r;h_P=I7##oKWVO}eRJjPyW4qy%|g#yO@|KK35vl1v`+~q(C z<17ct80TN1f@`l94q-0Ki7Lih2@Yf2n9p*ciE;il zS{P$F(Z+bIfuoqmYC{KeT1_0od{z^>n9p*ehw)YleT@CDIF4&CHwGAUr7*vm2@%|MjaqX4B7~`%qCYZxYV~RPf7EWO~YpZ?FUgvI0XWk=a|`V4*~Qxk~; zu+Pt*{E<%{Bdsd&W$~X;AQ^E2@nc8#@1Iak`!`8WtS_AWRn!rA{6~$zp#Hr_Mu#WT zYp>G#S!W)MtU2?tR>|;s9OQ)mkmXpf>Fc^=qII^%e2Kz|l8K^;B{SzOn5~#-SHbL* zjO_oq9UGEcnDS;4UsS)VCe~)HT(w}?(*Ij7U$UgTXGY;j$(Q}V|JknG&ezzk)U53A zd)w6}+LgCmCCBTZ_TTjFDuV&YVEuSJW-nX0I&1y()yt+Qe>vXkyR#$yO^z8pqF=0G zue-Z14|HovH^N{Q@W8m^}#+{Gzh`kCWhr%qN zGmgj_=PSv5aAtOfLb4)0fByX0o{Hk9K)yud>R8eJ@E}N4z zefhHGYZlL39p^RGRDaYFN;WN7Tk>}z`!pq^bkbKcE;DKT$^RzTRguID{4{1i=z7!F zEuBlWuD$(=eVoh8*nYl|POj@8TjzYDyFZfr;r7kJ-siDod~(zhiTg`z-H&6v|IXOS zF@KH&`;Hiz-KLm81-H+q2R<9{`DuE5vQ#2*dl~=AW8MhljX>TATA9)tC`I*T!7p?ri+y3_)54UmEvNbDb zXHCz(9lBsnBC&er%6VC<|HqE!)YIp!T()NU^hi#m+DqqTt+$`-_|>~E&q`+FsdFN+ zVCkF%v-PCg_v12M;14qQ=PzSZvPu7c%-`=lC%e8Oz4?RVoR|H-V+8!1Y$Dy^ws>M> z+Viiat9D(QlkcJA{&w2_x@4FB|JY8`pBtW^Hvaz|t1b6?F_$-9lAZe zu&cmn(EV_`{G84GnMyv_(;3_Kx!hvnhrqgU7Ib@hVvm44B27%dcK>$9t^++@E-?q3ThK+m(w@p?kS>%STKyxu*o{fPIxyS*!kUk=@W zual0%^SD0I2ix1F`|I`EopiU`>(J}h^-Lq*Na%4IjolV{U3vWuBHsP!i|u*O!X5{` z{dqlmyYag7b~}Rn9pGT-`W9gqgKnqSV}Ihk{X4!A@!en-SRT6n9uKdRqNIC!aXGik z{qsC{d&!`j{WZt#0W+cN@p|!g=Jm3Md|q$vueY}nq$1u zqxA>P}!$7Lw-9xoq{yxn@c z_PX)BRim88$>Znob^eLu^L~E@w%h0J$Mt($@{!Nu;_b%c?(%N0$II(-CgtZq_tW#^ zc^pOhTDTG#-X9GlqA>LSXfd|^d7ZW=-t*@1cYW@k*M<8(iE<5~``HJ(6RZtAz8-JS zo5$7T;&txv^Z0nZdz?Jq&GFw87J^<+p6}wsd;2bi?S3r6o&h~>-VVGjd_Ls%*C)UC z2d+PZc#ogkxq$e_a4vLtuh$90*M&o&=eaC)7wGnR{5;=nN%#J%4)%2DdGhw}{nko!}B zc(0fK*luS@Y|n$&b3Wp;;A-gg*d5#ZYp*}gM@7<`LAS&6w}g1F&pO!Uq1U_DnVZl@%8#}`v;M3zuulapWffPf3DB-JcIHX za4q!wHo^9M4aasp_BW1rk4HXik6%4(Z_nNyJg#2Po-ePL!Ibmh4?w8k1 zE8=||@;um|`|I`N_2>Qfe9Di6Uf15vOA+t=Uk0|hYh!ymse(NO_Ji)f*Mt4kBfSu;3q8*sUvEE+ zNv{Asp7pUCLT`^_v1h_+(BqSVT^4#>dVVVr@8hhuLyx1!!Sm?-r?zaaTMpYD(QokhCG$L;Yt z^?uO%Kd&FJn<y`T2HEhXN^70iU!Z4)BA z9eG{3eO{mT?{?U48OnRSmtZe~1z`I2;r_NIy)$%wdtx_&-QgPO{kP}E{dT+DKaWF8 z${B_DQ674K>3+8--p3ywkGvgJAw3g%9K6mv&oxPRdwO7d`*b_JuD$-eU-Ev^+l}YP z+pqUq9xwN&7xj4i?1H0lho>%w7{rCFyym-Iid22?y8pD#%`}Nh>Mk#){KR!N9C4M>V1if8(JiLBA z{;sbd`Q3icyT{k#-n-@kH6dH`6*2~?-#s|+#lEH`Sv>ZcI|q-PCcF;?>YGQJQT#v4_iZT-x=86 zzj=H1`Lp*&-X4pP-`hcNY>%JUjrVt1q`N<^$KzFlbg!pc*xoKYPA)&5bdRsspXbZ# z!T!ANy?uN9R^rF~DUR*^l-HTt?{Vu&zJ<`+vA3&X#Ct#F_IUr}{f*a=$IboncII{K z_NMO_mQj!A*ZYM9#1Do>OMZA>ynpsM)Fr(v^!o68WfJfGgvZJK^LA8^d|t;M2hYz` z(%Zwz(Az;H?C#L*7>Vumu?pMez3x0OUdJ8>??=3ScwKp3rs2=y=W#Dbd|&8!^E`U} zk0#yg&hzDdxgBH3=X$-a`w;K>@Va&UT++Q>y+8GM?M%9lLmvND#8-e`zb^0nis!}q zUDxmZinrGW_*nwoU-xq$@!k)5{JcIhNiPJwU9QD;`(1t=@t$AT=k|G?+-{Gv*Q3`* zar}7wyImcLFADQRkB7H2uMhXr^XUCoPs+`LUTC&i(LsdH?49-2}?J-|mn7y4~LX zGRW_F9EIH%di=c|lp)^x7w2<7-7l{%k5^O5&44~Gd4IBoc#oftpI-moPRRD#`q!}j)27u)N?+pX7YZPJ@S!~VVB^Zvo@^SIle*M;ZP>v<3k zy&v%Q?(y;V;r4pH7pI*2yB2#q^g3Od7T+SRoafWy@A2_|#eSAh&h>gb@jQ5bJbyFD z@A6)kuHW0Q$KB)MdKyyR^I(5XiFZ3%V>`e1YfkS#dUxn`?Rob+4JF;}XpZge*vD6& zhj<-(yPZbt@xyY;*kBcI3HP|KV;=eHK#$vS z>{4(PG&1<%b(V?kb>sb<{dzs;BcI#t^O=6cSA^cLx;-9ex8K`?wF$Ty<@0X$)9262$?y7{&-D!^-Tn6Xc^!EB@%;5Azx$Jc?RlAj-3WSr>FpxD|K6TG z|D7r4{at=+AD_Kmye^lJJ`8$(Mq|6bn12|a$N!XWe@@Zsa!0WsBlc(M^_bK2c92u_ zc97fj@nc7^81tB0^nO0KS%QA#6utk=X?p*e(=1K@bBaFx|55t9zAIWX{ zyyMT(=dn3OpO^mCtjzk(X;#5+PSN)b{_ga7RBqAN9XZV!%vVm+=gYZ8U#I-L^!fIV zVr|AXr!&}Fds%rtc&CQTo0@ZqfGx z{w{3BJnv}w{!4DL1^xO@>HB6m%~rH)N3k{a(oTl%8|EJ8PUBAcP zWQ>U+Vq4upjN&(dh~J#%BK-bcxS00*UActzZgDmKbDL|Z=l8gld^?)!s5hq>=Ld1@wo>i*Z9DyU zG$MD{fomQ{(N&w68zH)Ux)S z%2Z#ec^&V#^fHcjzI3MMPyfBOybhIJt5pO$arRGolotoEW9p`-ZkshC#?y`>Co}KO|)plL>V>>mE)3(NK|2;_2O3&-G)H11gQse!5Tj`FE ze9mj8){`3Nc$c;9Jf`EFFExH^X_20qXM1*PKKr-N)N=l9I`8k<_La)ivZ?XuzMLx9KSUm>1p;AdAF68 z8lRd!)&JJww-)DmQp=|P-ddT|IR6g%w|%DCj!X5O9+#d!J>6x~>q?DxnQi$>jo;eu zt;N}=>q%wgcNueQ`P1{I=1ukIvgzsDv(wY;?>~v(TAB2?RNKEz*ZuD>%2@8V%h_LQ zy3@?9rKQK&kIMudmrkdp#{0L^w&urisd-cLr^jzCE%K!1OSMyfyRLMmmQDBXG;?cZ zx0jac&tUuxOZ->%nmIrI1Yx?F0$?fFm5@879)InH!is?XH8?d6NK zt>tx@t)-{dlbSCzuj5mF`?u4a-|^{my7N0dJ$`GpTAAQhAfNrj~%Qcsv*^sYDqguwWSQHj#O8wC)Jl4 zNDZY%Qe&x!)KqFFHJ4gQEu~gcYpIRYR%$1;mpVutrA|`(ZD#!4Wc-a|{GDR_?O^;J zVEm0<{5@T!)LZH!^_BWb{iOlYKxvS)vou&5A`O*>NyDWP(nx8PG+G)Xjg`hp+Eyg>B@jhU@ zgBS0)#XD&6{#d-z74KKYJ5ljIQoJ)1@AJgFI`Q7jdTCc_gS4BpQQBSFL)uf?ByE=V zlJ=JNk@l7LllGSmkPeg%k`9&*kq(s(lMa`TkdBm&l8%;+k&cy)la7~8kWQ3Nl1`RR zkxrFPlTMe;kj|9OlFpX4NaslBO6N)EOBYBNN*75NOP5HON|#BOOIJu&N>@o&OV>!( zO4mu(OE*Y2N;gS2OSee3O1DY3OLs_jN_Rm8 zOHW8oO8=6clAe~Hk)D;Flb)AekY1Etl3tcxkzSQvlU|qJklvKulHQiyk=~Wwlirs; zkUo??l0KF`kv^3^lRlTekiL|@lD?L{k-n9_lfIXJkbabYl75zck$#mD`SgD&zf?df zC>4?lOGTujQZcExR6;5#m6A$JWu&rFIjOuTKk}6A8q^eRisk&4{swvfyc9LpK z8B!gou2fH|FEx-FN{yt(QWL4E)J$qFwUAm$t)$jc8>y|-PHHc8kUC18q|QMr$=dP=>dOsTijN9rr}lln^oq=C{PX=iD$G(;LI4U>jTBczeiC~34bMj9)Plg3LE zq>0ibX|lA7G)0;!O_QceGo+c)ENQkhN6M1sO7o=o(gJCrv`AVkEs>T=%cSMf3TdUZ zN?I+gk=9D2(v`N}5?IrCk?IZ0g?I-Oo9UvVj9V8tr9U>hn z9VQ(v9U&bl9VHzt9U~np9VZeIk7-eI|V_eIb1*eINjpikr3|T#R9C7e)t4Gb4W&j>W2uSMRB9$Q zms&_IrB+gFsg2ZDYA3aqI!GO*PEu#7i_}%>CUuv3NIj)qQl`{f>Lc})`bqtz0n$Ke zkhHTjSQ;V?m4->fr4iCdX_Pct8Y7LB#!2I)3DQJqk~CS`MVcZ_m8MD4r5VypX_how znj>XNbESFGd})ESP+BA{mX=6MrDf7`X@#^>S|zQP)<|omb<%oiS80Q^o3v5dUD`w1 zQ`#hLmiChNmiCeMmG+bNmky8)ln#;(mJX2)l@5~*myVE*l#Y^)mX48*m5!5+mrjsQ zlunXPmQImQl}?jRm(GyRl+KdQmbOUeNasrDN#{!!NEb>MNf%3(NS8{NNta7kNLNZ% zNmonPNY_f&N!Lp^NHsv*^s zYDqguwWSQHj#O8wC)Jl4NDZY%Qe&x!)KqFFHJ4gQEu~gcYpIRYR%$1;mpVutrA|_3 zsf*NA>LzuUdPqH`UQ(viTk0eAmHJ8jr2*1FX^^zDG*}uU4V8vT!=(|@NNJQbS{fsb zmBvZqr3unRX_7Qq+C`coO_ioe)1?{GOlg)hTbd(fNpq!n(tK%wv`|_kEtZx@OQmJf za%qLMQd%XgmexpXrFGJJX;*23w41b1+Fja1+EdyjZI1H%T{3w@9~2 zw@J54cSv_icS(0k_el3j_eu9l4@eJ64@nP8k4TS7k4cY9Pe@Nn|B{}Po|c}Go|T@H zo|j&bUX)&vUY1^wUX@;xUYFjG-jv>w-j?2x-j&{y-j_a*K9oL^K9)X_K9xR`K9|0b zzLdU_zLvg`zLma{zL$QGew2QaewKcbew7jhwf#%^r2iR2 zlvG+OBbAlPN#&&qQbnnfR9UJbRh6nq)ukFzO{tc&lT=&Ekm^WvrFv3*se#l`Y9uw5 znn+EhW>Ryhh161NCAF5?NNuHdQhTX`)KTgrb(XqFU8QbPcd3WeQ|cvUO1-5%QeUZ` z)L$AP4U`5+J4=J5A<|H3m^54(A&rzqNu#AP(pYJnG+vq@O_U}{lcimxDbiGFnlxRS zAQW)J)}LQP10s*FKKUSA8B7{KWTsI0O>&KAn9P~5b03qFzImV2&aSv2=-asdSli zxpakerF4~awRDYit#qAqy>x?gqjZyWvviAet8|-myL5+ir*xNew{(wmuXLYuzx06g zp!AURu=I%ZsPvfhxb%edr1UT8Dd}nH8R=Q+Iq7-n1?ffUCFy1973o#!HR*Nf4e3qk zE$MCP9qC=^J?VYv1L;HQBk5!56X{dwGwE~b3+YSgE9qNjpikr3|T#R9C7e)t4Gb4W&j>W2uSMRB9$Qms&_IrB+gFsg2ZDYA3aq zI!GO*PEu#7i_}%>CUuv3NIj)qQl`{f>Lc})`bqtz0n$KekhHTjSQ;V?m4->fr4iCd zX_Pct8Y7LB#!2I)3DQJqk~CS`MVcZ_m8MD4r5VypX_hownj>XNbESFGd})ESP+BA{ zmX=6MrDf7`X@#^>S|zQP)<|omb<%oiS80Q^o3v5dUD`w1Q`#hLmf}({PkCdIw+8ao zK;9b2TLXD(Aa4!it%1BXkhcc%)Yank83Hc;VV`*EQDN-p{{3SVeoYI>R6S>j7a|pkCXx5wf7l2N>fd{0 zba^8E?hLoEelQcOXRe%=wR-yMWz$zJTeEU@mgAFF#3yq&KK4BkGP3{sfBzG!H}a&f z-}>>Qu0lW7A9gzuQ{Bb67tfkCii*&dZ8rnl(pUFvsyrm(2+? zQnIr+{`c1JnBgP(A&Z<6h(}D<#J`Q@`SIdC~0n{P~lPin6CEkZ(%7 z@~^O|NRs~VCja|l<@HfLa)i?PjJvCX})&BL(G6S2*+vCa7Vn+WDjNi+LzYU1bJ*k=4qOawFj{w0F> zR?Z8McMJ0WwFf~*k%)K zvjeu-6Wbh)ZBD{Av#`zO*ycuTGu}OqV8(mp5zKgZJc4-AZ#<1>5xfe6t$qW_4_{2DVuf+pL9c?u2dD#x^ss%{tg-U2L-+ zwpkzBY=CVx#5R4O$ZSly*#z5cifuN-Hk)IcEwIg&*k&ti)Ay;&Hl&+vvCVeaW_xV2 z1Gd=_+w6pGcE&clV4GdBP2Wc|yOVDAz&3kgo4v5jOl-3^w%G^U?2B#o!#4Y4n**@T zf!O9CY;$L9b1=3!1lt^nZ4SdWhhv)~u+5R!<|u4)G`2Yg+Z>B+j>9&`W1ADO&579N zBy4jswz&(oIR)FCifvBAHm75oGqBB>*yb#3b2hd)2iwfTHs@lS^RUhN*yaLkb0N05 z2-{qYZ7#t!mtvdCu+8Pz<_c_cCAPT=+gy!puE93fVw>x*&Gp#ZdcK?fT`8xE1cabpgCvS3BpQ3=Mk zt|G+ut|G+u3nIif3?le>^5c|$HyNG%9m@Ebem+_VKZW64jG=SS}?x<5Fx$+ z5y8*PUGHlAu7UB5z6kN1z6hm~$o^h#{G3UDX2Bw`D2(rhMTl>QMd(I+cX&fGI{SO3 z@iU8hJUaBm}Iu>Zy?9d)A8%~BpTtjF|17fD$wt5jG^3mxGVJgLnqV!!qn^i zNKN8BFP~w@H$o%CH=80H0ppuV5w3>uO{EBz!_(mDa2oBN4&&Q95!ynplY?n*4eE8f zPNUrE@a1Ij?C&ARPrpypk@RZ#@q04YkpEh^k#xVe65o4`5Z`=_aBC9T-+GRp@ok<6 zeh(qO+Y}+b-4r3dw-zD3xfa3iZ>%ES+g*IKEkb;!H9~x=HNx@aI{|u}kHl_FxhC*F z;=Rs}vmaQJaVQ0SdGuwny6kTU$In^h?}*<{FuwB^A^Tfz;zIH*f?rdAd@m}3&y!kE z&hKNyH;5vn-w%8|8U5RPevR?d1g77QTZLaAHxD6Sd{Zofj}u-uji|RV+%uUiu?fa^ z`y#}*`y%+b>-XN4F>ZdZ?9ODi#9i=0#^EA30Y4LAd_y>b*Hwq4nf-nF_<0Ea4~4y9 zAJ~h2Wx{!IKCFlT`fxwW?GLlR(Hj+EA51xqTYNJt!dvhJ+I=FtmiX&n`u*1tzWI*jkBMTl>zMYxuH@on7*tLXP?xQKY4N4!Hlevi-ZyPi*epBKe9 z*CL#dME1WK5I?J8SA&D`KLqB-e*t(G?YZu7w5YW5HA>QvH`#2NdnvAfJbkEz9l=F4PqqIA|?HyqQ z+zs9b?}vV${%8F3!+(FcE8GCf(U0=5E%EJO3;ec(zAlRIZAPe_L?Q$3MZUe^aQu#d zzAlaLO-6|Cf=7sNgGccDx$$kw2rDS(^WHtNH^F1+r_WP;UhM0-%jw4z@L+fd^!vkg zsL#jw*|f*^_lqT)ll}et_&JGmU$^aqzX9YM2ul%P8eUDjuN&e!pb_F*pb^T^pYqV> z#on*)h96&NJVZMlhFvJv72Zbv+hKfTG(sl)g7`0C8OF7&Nqjl@G<*j7y58sI-ml(7 z`bYSQZ^TBJMEqnpCK;Xm?-a$)ZuFx&+(t8erbf~$oD+-eWPa7w;ApQ(>JSr<$?Qi#Oe#TFH zuQ$RM@JrYw8J+#_TgA`x_ZNClPfysI{B7VZ(AUYHm-x19gb(TOM{qs$`Z(zAD88#3 z;X=mYBG`_4+e2T6T#uhelEt$BJ*D{R`+UAH+?RTNAMh&tUJW}^Zzs4G`tJsOT$oJ# zJ`XHJzDcxWGR%N=;1iVdal+TNO-Wx#`&Pl7h_4O3pZ$*Xx8XbR0r(*7Pq_hb30w-F zfzQIBlpAJ0#6JYjgg$Tb-@o;tUyWd6=;K6un>a!Z{QADQ|6XGb=|!1`VsIe&2SMLg z`;2ry-}c{g6rtXta0K*uOW9;IetXaGHTvW8*gmB9g=?vI9ee}63H|poSK{Yw%K5oO zA?hy-FC+bOco}{!hffp#47>=x7sKlGy9V?;4X3=Xo7Pa@E5yHQ|HMB7)8Fs%b+zx4 zl%`x6xEtj*!l|^=`-%A0c!YPL?`yq5dwtyBO!{-l?AiaOS^TVw-zqS^M;#%)Ngct* zrJM10Vlq1W--C;vqwzZiHX@(zlkH4DeBIX@zwy292>p^s^oK2JM=N*~{*H#16MqF9 zNWFvLIq+O~9Da|7b@5XV=EF~Z==(4pS8vxoZx~NG-)9;?KL)}lsOL%O$ z{AhS7<-8yDc6J`^f1Z3Vz@oIvf0uY1`HqJkSD%N?qMfthC&ok9yGinf=NCCGlTDAD7o+|A?QTpwAn3 zp`G93=LhKh#6t2Hce~(I(ARn2P|vr}+lB8#ZN`u1;WWzoIb$o@(Hi=^qbB*fuzr0V zyo7b)>o~s$GMaqdXh(PW0{LHr^{B_|dKdCdfzzqi_o@AyVHEM+FXzY4gY@qqcszc* zU-EUd&jUWBoUeO5j|br2_ho*;PY?3y6aNaF z&p0iBzv9<_ICLZBydS@w`h4HCKJ(z`C?DhJ6X^Sr7vjgy2_{pn1@SH6VU#-@#=jL3 z!Piaq5PvW9bKz?!e?&5S_P_ZXKYt|tC+Pj;?eyRGLHEPGv)l=%W}rY_aV=wo-NSVnck23 zIQkwZTmVv&m z^>g+3_kAMdgZbgQWb|*}r}A;`2>jQhAHJ_O1$!#&O1ry3pQm@A{3rPT6t<#VYv}W? z;h;(Z=?GUYrDK9Bwc|EE*$8PMzGW&F${-)!jTNaabthjRBqUq{|T{`t(q0$7>& zDzFoNIz#WruEpOP;(gzs8|At~Z^wJ$e}8xYTu=Xfp6u)P*YJB0=@-K))a&ym--o!0 zc;APvfPddN`W}C;kndGEg?3Jb-tXQ)`R9p$0s6jqZS43rqawt=8x_IlZ67Ah-@fm3 zGxiwrjfGwpey?sVe*K(g59~dm=iT=?CgOJzoJPB+!>X_vTuVN07u~SC!(*uDSa>_* zbO*eK_-kQ#;w!**_-POQT-ndfeV#m+{6pa|=U{$i zBEB%(k8(cm@ODyx^--U3Y5@HnZT#C`5xn2+Lb}(nulwsJvnA@mAE?jA`AccXW$rXciG(`rTw1g&nWjfbUPly_H}d{?C+V^AE2-M z4kZ0%`g;rXc|;HDf1Ywa@AP{fuMuB|{?~g!FuKG6Hw=g8lYe)znsHg*PVh@VEVH0}4g zsmZwbJ;JV}`@HQ9>^Gs$lU}1ePeVUP>rA`4z)jS<8SX>=ec=YU8{9&y^5K6t907ac*Y8QRqFie@jduG!(!1329(;;? zeh$ZU zS5nVaaBsK|^mRiI>hpPj2kgD@vo{!F{U7Qp_Bd|$%})a&!upXt{x@G8przRyD97r~~q$IopJBmd#> z8~lF@ucF?oVJZBShQ|_r9NdKe&G1?BJqI_DZ!`3D!@n5!RpeU@kD*=1!Ub?4dzpn#^l5ZIFb0NPs z(w%nqfbD5l2UwVLMc{AS9pil}a7bO!|&tJ_vw6{>hrwo@mCmsMPOst1nvem zIv&4Gp|2x+U4J+6_rO-v(;6N`I}e5>VJWzQa=Ss_7o5O+TtNJV(D%_j54#iZ^TPVr z4WN%pwdv1Lwin+AJcxRHAL|ZmKWBS`cD@Py+}p>c(!`g6zfkY5@ErV|3m;@$9)b;E zL+JDDGbr!-Fuv~dycMNCzRvP_>IhaX#ucOiA9}BxsPgi(3yaM{Z!u|L;mUv$$ zoIyQj!bFu#YrlKGrXyXU}T zsMq~C9e-!QU*NCs0OrNlB|a~%gr6+(&4p{IXD!@FJ9dY@FLO2J{obvw+YhDOVX!9k z*MdH;%*6I~brJqr(GH(idB3|8<3AqyKEu1@e-Hi(zfZw69O8tJX&gT^mliu3n1pVA#Bkg+z zzrN1fiF#|pi^=EXwAV>V{P{l0S=fFr$j=#v5I+=_roZlY1N{5FggWH&eU25hVbo5APd z3()sXe4Xj%6s_>ToOb#+;^THz+S{Lc2f*c&^Su6q{WEMqIlqV5m2%zSNb-$>?$>Ul zKT5o>i$0hon+7XV&d&{eo$Bkn0rYzyJcE9o2{VcB4ZGsc?}_=nwQ=<4Me_MLv?uM` z1bv_WDf|y3emMLXegcNy7bKK~{3KS4gf$9fok4u>a_?<9CP z_1*)09r6M8bJX)ZTn*R2NAdHRN&Mr`=QS77-vY!JguX9u9_0@p-+^!`?e@HWgZ(YM z3qNgf-C9`5__KN0^kybC|RPvG}VW{_TqepQCe zVGH;gd>yj<625Qk^J35Y66VeGdK>lJ4n0rvu*czdJZwz`ZJ^H+C*t=C`g0}pb^4pw zz7DvO{6|vHQSdGDy$we(uA|`q=;wCV(5`EtuZw&hc`ttMgXL*=1=y5!G=o3j|3~QO zuwM6liSGw}oVuR!o9Tz|gS|xj%W!|%c>sKgcD)RL#_un1IQje>FAIAv#BIXIS=0M3 zvo0CU*4SoeY_l)6IRe}Cb1-u@>88)GOy6HM_a?vT^G0(E>896>c{AzeJ=o?G*yan^ z=9}2&N7&}~*k(TF$1H(u`u>Jln{=}=w%HQf?2c{vew{gvbaOJcxd_`_jcxk4ZXQUw zc^tOs>l)MhRr6-@oA+azzWy-1-!y%FYko_4)6WUa(yVv02DVub+w}g?^nC$y5c$oq z*rw0N%q66oKK_~;NH-6{Hhtb;o<_RqN& zc(XjVSqIx}f^BxdHoc!V$CGYO$2ON^o9nU7{jg2n7c+go)jXH{rjOs|t)!dxV4F{1 zo3CS=pJJQeVVeax4w%KU&6?PzuYb)>q??1VO+RlmecoU$CBL~lws`=y>FYc54AM>C zhcW#;)4Y@X=EKcwngNoSL ziYN$(K~WS7Dg?!=K@p9L^5C5L@>YC{mz8^yT$3=YHNS7l8D{>oXTCl2t#@QPj1!zB zNE;6P{4^e#2>X$W21y7sMC z+tY?>QteYD#kAxxoF{%NW0e0W1sv^d-G>M4M@CIqX&tdMN{pC=^FtGc5|lkUQU(7e zMTxzBZr4IIJ$8$9+8CM;jh_}B6c!OOlr!8f9(IX5JEr=P%2{DUb%Esb4?RoM7Kg?s zL@bQ?zrUk%en}0F;_#1$OX%#s|6Ny9KRd{}8tN81{Mx!&PWm;vt~h%A)8diVl{~Q@ zN{^6*@rj|yzu&s@a&==4+c0H!CyCus>*aGhrus3;Un(%tKJbK(Q;(ml?_b*o+Jrdu zseSdA|7A4wcUOSg2g=Dn-3dh||FI+gd>=q!x70rHxgGzpz4`05PN(s*{Q^!jyiapH zZaVQJhPG~YpvXPsaSUrbyxuu`FtE#chf>4&TwGl2Dc~pVaMR_-vn$Y$@-R3_S`Oit z1&&?u(i};*+$VA#D7#7~>0B93zC5X?H-S8i06mfq9C=5mMQKW-)r}po3cFxf|KT7n z#o?D4Q@T-pC}jj3UzavyeVjnK4P+Vr{C*c8<>Yllqhukk9ojfjPK=BuOwyD-q9iRw zC{8FrC`m}kNKGR(O=P-hlSn->?KEn8n?mws3FQdo2^9zx36%(y2~`MH3DpSI38xZj z5NZ-?5o#0a5b6?A_NGtL284!$Muf(MCWNMh(+J7&on}tb7KE0BR)p4sHiSTEOUNL! zBV-Z|9p2f&fp9t@wf>w)dIq60;Y>moLRUgJLU%$BLQg_3LT^GJLKdMfp&y|?;Vi=0 zgmVbz63!zGAPgi7A`B)BA)HSbO1OY9j4+%qf-sWsE5azkXu=r6g@mz$afI=N!)M&# zkjMdT5#eIOBtoixqvQxOs>7eF1GO$j$Ohw9e+_@UU)e!k?SBow@;}johdqn( z?D+rjvxy7RLAhLH?sEvgEc_>W@Uw>k?0957X!7g|f01*?NcSfl1s$%H9{sf5(#F^!~uD~7+L1VqfIv6+|>%T5e6!cK?9 zFI*HmT>8s&%>3aSVospWEmS`Ose<2`zkUCaX5Vj!%G>;W?_o5SW;93+v?K3B^5kgt z`Fm>J?>wT>=0+9x^A(`h>FE6qNBhzH9gYr6Vv6>JqxU-;A-QH!R0wEfr^px~x)x}Ps6H~0K_Bpf$u>NT@QIxSk_gtR{9pAr)l?KOZ$4JI=W7fOIl>6(7t95w8$9Z*gw*T&Y2 zoS29UM!2>0&@IUt5ipiBGn}zWQkTly=gT8L5iZ z%jz-*)|-KPonqs=dkkE|r0FaTrqke zHQ!VQvL4yr|5vgZ^i&>C(NWQWL&^7DG~Wthm{8;Saj)s%Tfb&NA;<`dgHn|y2FYMc zgwuzU*;ddFi+6td!4`Mdhi-H_Z;HqE@#hz?0E~9+U`)(bf;{1_2c@f&K|Q~Ju;QXF zNUVEfk!J-EonyMwL*IcN;Yf z;OM(;ZT9I*uuq!VW$X;#ziq*b1OZ97&wTYlX^JhBdj~LPx9K9oNF>b9NE+Y2v^yQq zWD8^It^jSun7eL8x|`i|o8}`Yx?Hu#K-#&nY46N+@ajcVr|1lMaO$k#QZ<&uhTVyC zLyDQOrG0XOF9YD!$!66a=USWEGOqfZTPo=F;ltW%J`S++4s)O+)&ak5N>V-ZP86<3 zmBof`V*tG;)pd`gIdWxLe=4;!huDhg-_8?c!r?>K&q@wIs^%80iX05mhitX+8ST4G zASSA0;$sUvoHt;lZmeqtQHm1Xvi|zOwb^>{v-RLO-(F80aR9f$s`%b#W?0r?8REX>sZF|1!Gc{0 zhWJiy;!_7dBk0^yAb4YvDGF|xL?2p_lGG+Eb5<93b5N0$hwfX-6c zM;GSWqJS9vn7jZB&S~8a7QEz$A7N>~fI15bwhg>g-lmBqH`?FGwoe29X**Ij%wgf? z3BB{4OqqdrB(wHhs|oCQ)#G{fjvrhc$XjW2%>q}ew7oI8Iuo)SD zZty%|P8F-%9cLQOF1Rw;78v7Rd>!%B6NO*$9KRXCg7V1LaZmWH@!*a~2UZLVkGwF` zEU9n?-=xLP=a1>*a)&HE9vxeN{Dh?z&C~I&dHds=#WSIB79%4s%p2qL{3dRG?TioJ z7L{I}?|~(k`dV!FnnCo*?){gI+%ZZfnl2O1g3xeS6<+5Bbg35`=;IjR`e2e?aGfdO zm{TrG-L!GJ%b~6_teaB`+XtEeYt_hAQN|MofUCkWeMNztz7R_ z<_WHE+eJ!)yl|lEY<(?w^TWGLsjmc_vLEwxMPVjV%TQtD=Ih988}dkm|aeBj~^u@yq?_P9E6 zQrhtc+}Ja)I*7H+4N&EBRFtn4=AI6ZX?o}bWs{|zp5*fZ-qvr7dyU=EqD1ak{YOB4 z0kiH2yvleZqg4?a3^c~8xt9rWr} zv>Z9?io)*c+jREZVR)>jg2BP5=yftXeyI=(4jlNjF5{CsnhWZQJzUBI#m*<6x>oza z9btJ7YjaPO-)*TmB|{Qse_VX~-CZB>QxrQTc+?2=^6ZJIQz_D`kz`ln;q!^pk#N3)SJ{3HO1>o!5)b)k349(hMaVu$55>mo z_-;sHV8;uoX&XHmcz&Ai*(V~VuxYY5xBYhm)p0E@(eb)=X!hg1S7W;vXffVbyW7?T z_O5E{TXNI@dh%trn0>8>nbQK~s*dQRK=8TaAHtYuR+QA67GVI8e8w>Ot`VM4cqQ{t;>U!urX3#S(X}*>7a{6{A2Fl zIH`s;IWr3{mpZ_~IH%D2+x78AWY0(MObd)H&(y2eQbDyhZlaegl)%C2-j0t$?~`Sf zF3&4-bfH+z=)A&R8z|^bipaN}jyr;<@q5G>pw*kQbr#y@VDK>M-Gbv*IIwZOY|>^X z`gQ827vE~Aj24ZK$yAibOJ?ZnF>l6e zH&ZAqw06$j$%M+E8n~owb)YP`FOa!I4b^wO&oiDN3Tn?%uDQ_7VbZh0=RcGJx`y{% z7xgp2Gx8z{bHml4KxSQQTCf#p&GH{K57&TebJXun4_ClMXSK_9n-D)um0m@Ca_ps&Jn5>c$&s!>9#n6Gd|n@ zujT5nFl2Ahnuwz6IgZzIE)*Ib>#g-c kqOX~;QBVPS->Dvo+$4eDPmK-tTi^h0*=mz_CNtoF0HY>R%(&GQR90x~dn8K#xpI^Vr$CgfCw0PEn`Tsj!N)*%8GehKXBqjde|D0DY z=j)tTDpuU>>bzP-xsvBq)L#Fze-qEEG#Vg{@#FT$o|!c_Yu=K@8QBXmrY=~NJ$+ep z#N)f21MVhA3?9-mjA4(v9gJJ2mpG1hGueM!us@pz-p>~`MSjljUCje86pq4||Hrjp zvcjPSJP&NAITpg9)uSJOHqMIIjE*;}O@uu};yiE%bJv!m+;b zA1O+ywBpWRFl~Cq!UYSL%+1OU>zWG6KjaY<6)nmw`W@w+Ry0a0@=K45ef&2XSNUR@ zq*IT1(D^2gTPhc8R_)(s?CV^5+P@Ds)Q4;M$N$Zlc(30c{c!oVVLx_t*5sP|oFZdAu(0`qayYe_bPlcy|;F|0Z3s1(Ge0Y=LA8 zBwHZa0?8Igwm`B4k}Z&Ifn*CLTOip2f5#Ts|NBZa2S)YI*?pz358-{KXm27tN18V! zmM7W+VIyQu_SvFxL>no8zR#9>ZB)>T1^!szEq^rsCf2^R$G<)&{qy#yx-qJ1tCD}L z^53&PT*k!Jtx~yC#sG2KliY?lfnPX zTfooB#!`=HHjl-ICOrR|zj*oloO};u|DUJB&x)$_-*KKMJ~!N&(Ek7B!|X3BeqD0% zW2)ZRC7>TS^+*U;7CX9z$6|iGQxX4`(A_c=+v&B&?gv}I%CIlwad2!3_GFj=ef_J2 z-3Pi}Rj?aF&)eg%ovy>X9m;UreguesXyx5Z?Vb0Nd^0ejbB=dO~=&8;@IKUc`sJ;3JkaHGz0>gbcyoPyKDk^~2I*W&A@iMdcJXaTu--87UA8# z4X|s#;n3lE?J4H*=JL3|JYV=ccKu6}&M@fn((Rd!zsHU1>+$aK(wuNUpPX-7{M}#U zv7L|S2j}l`Fo|$Z*X41&J>Pizb|Sp%?SA+9x96{>#CJK}J{~6?|L#|h zSBLj_c6gWH?dy8D+z#(@^do=wv&V<~vkS*Pzx%v$e`ayKI&?p}{yuMg-n$+if1WoS z-~H`*#^v$(?s}1(-UW(W3Uod`pFEzXaNOrZH|*XC@!SqBm*+{3FZcHV;#GhiZ?3=7 z_dMr*^*rnG;Pl*{iR+6Zr0?>$o^B71508f?g!g##`P~?Q_rJ$!VtcsVd|tS}-F_Y~ zu9uHHUtf>hZytB9zvn~OvpVH+KY3iZo*viD2sesMc{e0C#V;&^jE`8;%cwc&;5z- za+#iI-EWEY8%I2+@Ae*szsHT&NiMJZ!S$#?_%!JL8-?wDO~>|lAA;@v@ciiW!tGs~ zaL&iaT|OUozx({~xOV%vJ>9SFKaUHazdnzukZ*nH>yq2S`MTUbFDet>=S>E-^J|Xn z^T6{`8vY*7K0j*W?|$|9;C}HqbG<#@o!>~}yWKo5x!fL?KA&7~x3}kK&x>v+=j-@R zzdQMPz2b4_a(TQt9govi#7l$rcYM!J9-o{hu9w?)BK{r^4)61-2**9n9d8K!&0rVk_DRKV2(zHav+LIj ze~)L6TbJMC%Kg@Y@NSm|*dDj8M+*Kv|6M-!x69@6<9d01alJhMy8WEL%b%W*e;RgT zz4GGke0yL|g+5Q+t}d7B@8cdPuD{2N+qWC(dHzht_Hp-b8vaht=fBUNrX2Tm#^>{3 z{5}3WpSt~gJ@7o?{_*_g@#k^hn)E6_*W2UW?VN|>9v7}(Rs5Z9Uu^fg=R@b`^0?k( z310?g!otw=liS<#n9sv>!c~J_m$_bv`8mF?1DV8gz1>gc@ppYvu$#k7==03u#Qov+ z$VE7h3-^=z!}*LPoXh9_bGtcR*W2US@!c=(uf*|@kMwH==knuk5jj^ubZBqTrRhd%i;6O z>H2!&apCb=obvcQ^?6$nfA@12Y|rDhvD2Z;`@C|0^e4Q_>;BKg-}$;--LD?U zRSD{)O;&`fhjkOLdMLU$*zO1SpXbqH9QXWP0^9B8db(eIJ@vfdc67VA zKb?>J!}at$;PN_M&u=~tJiqj$Jf`b48GoNo?XaDm+sF0G%W?OI`^)Ep+sW5Qk8ju4 z_3?OgIxe^KcRwbc$39Qpk13R=Bus~Hud>)Kr^k=;cl!`5=KLn$;r!fA9w$EU9KIgm zJ>Rv)c0Bi|+u7sS{a>E&?oXG~;eB2aEav&r`6srs&o|FY&fn?wA|a2bn%K^70Ji(n zCpY)@$K>D^PoQAd>*);-R@Z&cYNpP>xAbe*T?gb%QuDi9#`&f*DEn!pT8c* zE}!Q^w~yyRj}wp6;pFFhJYEy~!R^wU@QLl_e7kVGJxqbAFh3jv2Sd-JJ}+H9&ub1} ziSX_hw@Y{YTSB*=$8jzEJ>DI!AO23?2$p=aXRj2k8}60+sp0i_ICR@zWd+dnv$=_wfoicl>5o^P9DO$Jsd6_e~({> zOH9}8Jelw}#)8obGRXXwA&OT2(Z&cy<6zFzvKe?S6aeN%~b;;M~Cir{4c7Co`Iga~$ zcDs8VyS^B@g>&j%hi>G-?;o=5EOaZn>6oX>;m_-cV0 z&oeHc``zP%Y+|1G-S4i4$GQ8fJrUfGo`>A-PRHThUv9^~#P@N>^LTN)cpNx=&l7Gh z*Sj|9RfTS6pI>e-w~O1+@jMTB9MvZsk9XJC?csKFJ=_jHFTH*$N;*a-ezbt@KlhXC z>3P)S)%kiHv?RXE>-5|%9yc8c*A0674#)QKbnFc1aorT#>5s?u88?Jd1d*%duM?khb%?Js&B z-d`-vILIk_9kjPBNqKgczV78TOH+?wV} zxwrJXes}5nmAz#H`swe&hLmS_>HEBWWn=Q)U-W&`f119p+u!s)!(YYb^j}WX_rH5e z->2sky^ryqqW6LRDz>3NbBb+AZ&&pG%l>A2%9B&4)pdjD=u>HV|6 z3%%c&Q%tA-|0;GPzrTvz$!~wL2kGxAdlGL?*^78N&EBNDuk1rQ`-^=^e}Azb>F;m$ zC!hVz0pzo{97z1VFjR~C!gKr2*U4*BMG;+97X*7 z&C%quuN*@KOF@7{78@%I-ZIf-=km6J(le=~!8a*COxx3|n9 z{-1FQ$M=*|iI-EHMtXb7>BQULJb-+1iZe)WPdSr#`^s6Q^H*~=`R*;}5Px?$m+(2o zd8C(9oKJc=%>|^pyIe^4z2$+#-%~Ck-kx$X@p6jUq?c1%LVEj~OUY+%c@XjUm0{ja zD%l3fF_0Vs$uW=|1IaOv90SQQkQ@WaF_0Vs`(q4*{hp+fZIB!T$uW=|1OJ_4fUTz_ zk}Z&Ifn*CLTOip2$rebqK(YnmEs&yrQ>9!|ZYhtHSIQ^lmkLM)r9x6+sfbimDkc?| zN=PN8Qc`KDj8s-CCzY2fNEM|@Qe~-%R8^`brAgJL8d6QEmQ-7+Bh{7aN%f@$QbVbc z)L3dFHIX@E3P8YB&thDbxDVbXAEgfvnbC5@KGNa5|R@CH_RODeqS6y8z_ zZy1HQgTk9TnNpTCMVcyw9gJ|75#Ig?Z)}9OFT$G>;Vp*nCPH|-AiNO}p5lim?%^qV zcoH6-YKJG(;i+8*; z2I(m2XlbLgN!lzOBW;n6m5!5+mrjsQlunXPmQImQl}?jRm(GyRl+KdQmd=sRmClpS zmoAVllrEAkmbOZlNS8{NNta7kNZX_{m=`QJR=^p7`=|1Ux=>h3M=^^Q1=@IEs=`rbX=?Upc=_%=H=^5!+={f0n z=>=)0^rG~V^s@Ad^s4ll^t$wh^rrNd^tSYl^se-t^uF|g^r7^T^s)4b^r`fj^ttqf z^riHb^tJSj^sV%r^u6?h^rQ5X^t1Gf^sDrn6#n;eDN?GGOUfTQU$4^R7t8VRgtPn)uc43x>Q4|DbL_)RI!j%ou2QMsqD21+LS z=_Ki7=@jWy=``td=?v*i=`87N=^W`?={)It=>q9O=_2W3X{&UJbg6Wibh&hev`xBF z+AdusT`gTBT`OHDT`%1r?T~JiZjx@6Zjo-4Zj)}8?vU=3?vn17?vd`5?vw799*`cC z9+DoG9+4iE9+MuIo{*lDo|2xHo{^rFo|B%JUXXT5FG?>-FH5gTuS%~;uS;)8Z%S`T zZ%gk;?@I4U?@J#@A4(rdA4{J|pGu!epG#jzUrJv|UrXOe-%8&}-%CG8KT1DIKTE$z zze>MJ;liIHrAoP^+)^GXuar;9FBOmqN`<7tQW2@BR7@%^m5@qGrKHkQ8L6yPPAV@| zkSa=*q{>nisj5^>N|UNfHKdwSEvdFtN2)8;lj=(iq=r%>sj<{VYAQ98noBLDmQpLJ zwbVvxE47o_OC6++QYWdi)J5tlrAytU?otn_r_@X8E%lN5O8un%(g10oG)NjO4UvXQ z!=&NT2x+7=N*XPVk;Y2nr18=OX`(bqnk;2VnNpTCMVcy2lcq}tNHe6F(kyAVG)I~% z&6DO!3#5h8fzl#rv6L+>k(NpaNz0_=(!tUS=@98qX{B_Sv`Shnt&!GB>!ib__0kd2 zk%ik}j6EN|#8NN|#BOOIJwSq${QE(pA#c(lyex(sk1H(hbrM=|<@$>1OE` z=~n4B>2~Q3=}ze`>2B#B>0aqR>3-<}=|Sls>0#*+=~3x1>2c`^=}GA+>1pX1=~?MH z>3Qh|X{Yp}^pf)H^po_n^o#VX^qUkG{V7taluODj<&pAA`K0_(0jZ!= zNGdE9k%~&iq~cNusiag&DlL_f%1Y&=@=^t7xy`X+0qhesdSLEOj<4- zEUl0Zkq(tsN{30Sq}9?IX|1$QI$T;W9U&blZIF(Vj+Qn`o21RsG13<4Sm`+Fc%iFB!SnRK~yg|tn& zQra$EC0#9DBV8+9CtWYyAnlNDlx~u4mTr-5m2Q)6m+p}6lrD^mg-1#rFv3*se#l`Y9uw5nn+EhW>Ryhh161N zCAF5?NNuHdQhTX`)KTgrb(XqFU8QuXo77$EA@!7cNxh{$QeUZ`)L$AP4U`5+gQX$T zP-&PnTpA&bltxLTr7_Z2X`D1(njlS-CP|Z}3@KB}lBP&grD@W1=>TblG*g--&6eg! zbESFGd})ESP&!arBrTS*r6tl*=^$yDv|Kt^S|J@G9V)Gq4wF_%tEDy4T4|khxU^n6 zLON2~ARQ$gEp3#-vN5S-8zjd-attKLKynNu$3SunB*#E<3?#=uattKLKynNu$3Sun zB*#E<4E%8nq{R1(%4_c^xDxREWE%WH*$EdUZLfFOK{Oq?MsFiJLK|5 zNdEf|Yk|JKx(y9g9!tI3!A}`Kn6d1vMKh*nXJjwPSiE4#qN&sEA6daa3Ss{+R)b56 z|NFoH38OcJNgTiP!%IhUo5M>-a=RM8lXpbnlH)gOhkx3?e>Q%%F@D@0i?Zg=m>!1d z^l9R(Y4)GLU|KN4k$4dM?`r&x7(AqBN-XvF@m(jpv?k|xgR$p_m)PVyK6^919WHUa zN1^{Y|E9$9L~TZcq{QD)RXe6e9?NKo@Mt}_L_3$Rdm&_TDQe?%{n9fxS;0RwHA*Ny zGfl3Pi^A)Ra;x%1^uMe8<3Gy8adpw1|GqdLSA)aLnMwD*S|ATTW>IXjGPYS4+iZqy zcEvXPV4Fj*&C%HA1Z;B(wmBQyT!3wQ{G01IZf?Og!+XNPnde1j%-o7?GCjrL{SAk1 z;<$Maw)q6M`5d zhIgBSGsAmJ!I?X-&G0@_aAtTPDL6B{gA|+@-Zcu&4DS~OXNGr&f-}QALcy8gy`bRC zT)89L4Da;>XNLE9f-}>w%?8+JcpoP?GrV&XoEhG=3C;}f)&ysU_i2JN!#gy=nc-cT z;LPw&OmJp+-z7LRyx$U>xd}V+{m=dTA6Qq0KWmZud#)>^vL*jbwm`B4k}Z&Ifn*E( zGg^S#muQbkRc1N;J6W#9OfO$d?;DtTX*M$-w(0#CvjE4qdhS+8!Y_l=8*#z5cifuN-Hk)IcEwIg& z*k&tivo*Ha2HR|lZMMTU+hdy@u+5IxW+!a3Gq%|U+w?x1na**u8@AaU+w6gD_QW=O zVVk|N%|6&>Uu?4O#5MGvHz5y9$QCfetSG9dvNvn;F4<37;Zf_#6J=ShVL8& zcPh+9xZJQN`PPErJ3YaLZ}kLsT!i>H)WT0c-wxjb3NHL@c5r@fby8%;zp)m6ZY10$ z7``bKT==d~aK643h|Kuk(ubdJ*U6MK1BUON1Q)(}5?uIxNpRsCCc&+x-s|9Nk$3EM z7{0v_oS$pnf_*FOOu4$i#QTX6_>YA1$#($^-)adie6J$wO}um9Z!kuE8WXMwEKNI=f%yoZAFd|c8t4ti6vDflJ`ck8cY+Jw z;0ez2R8hi*?=l1zzReKab>wqBY)!Z}FnpgXxbTgt;BJE9n_R)gzeN>(kY7#cd8KMN zCRZ&&{Cf@IXAkmsx%^&@=aJQvXAJp_g%^;{g>Vu6i(&XSPjIipRd6*7-{J}GV^|Cp zhv8ch!3~7rn-IZ;??MFU^ZH%#^ZPBYVxLaA&wzg3UWxc;laI%B;{HqcCPi?=VSZQu zt|6bb(C;%GL4KR@KL(Z|URmh(i6(KpAM6hk_lHJC#fg6#GyL>2o7?61_v(WGLBziR zUI;yo+G1Cr9B!9pA+lWa2=VVQhM&)3kEC9sU`^=j=0VuY;BCaa9TtVfVECp-aN}Y4 zK2vZW7avj1@V&O+!go-DbGb3~-e=^#Am1;c`(+*ReI6I!c=%pSaN(OV!5u>Whr%r4 zO@V&jWg_9viO14=DX17G_$F6ye*frJ z?DE8~03U%$_;y%uHz$;1I^hn0o8V^H zoOD~j@U5-j!uPh~j&Lb(E&l6ZMf@wlFNpRfJQjK#@DcXMFnr@BIIlCkE*nO9{JzgC zq<<;&I%;?nJ^qc_@H2cXCpf>ClZhR^MH8H_>xYw0@5np;P2BL)>xhE*C+^>!NV!ge z;X8`KJqSO8;roTbl^`Eqck|M2`C#~_S#W;OtS;f}!H%TU3H}fTkAL?x{Cu4F;d^bt zWfN`*bibvNp68i%9PdcHPH=OSO#B4^P z&oJ0N@{WJUIQ;yGbUubh5zp&D&!fxmZ$>)JVG&pqhHu3M7rqx4+)EMS->VHjkH+2z zR}$_pNHM%TiGM#T1kJ~Isz5pXo@-6)TJST{{T$XN!8&j%=}d#|V0$=~a!i8@NOvLh z_K)wg&c**c=yl@@3Q7kJehPe;I+i_y6Xe{KZI%ITOC#-d>YJ4xO{Lq`TM@m z=jlTnznJ4&;S2chgddWw$EELceIHnk9vGSN?|z4$?&t6wwcuVQ-fOTg{{7&y)blxb73IAe zhVRM+=XFVC!uh&BpKw0Uysj)r`Wp$q2_`;|@_l^xj$3fXP4h()T*53U*aEn{?*D zy!hvXUN@bDU5WBnhO?Xwyq5A@2M@%55%hI=J@!-N`!rlhyu)Bq>Jh$|7o7Kj{2sF3 z?+)J~4bJyfJqcf#d|dAyQLtD~crx`k1^T|ZH1Q6=e+KMFJfBxyM-;+;8{vE%^*rnQ zn%@ZL``9DNX9M)UoX36Q^I5N}4=0}^NpC{}kHYr8!$R68e0MK6ugk8(-|O5)*p1;Q zQSkV8+r!Vkl(Qf7eef-m$K&#R;(ML+1;>3~!!j*v~$*&a5jej1v1TKZwlJ0fz zY4{B6L^*w4Rwmsl@MqHb1un)v8~Q%wZPHnR{~_=ccq%**o&>!v%SHTwa1ivoIurXS zcr-i~9tXoWc7yYE{XlI09meeFaQy$d5PpVlH3sK(a`^UUaGoc_H#URwd-Sa$Gyeag z2tV(p9q)0w68>2@3;)@0ARGkOP(I&RxE*p6zY6863da(D9GpNp6QTb;=XC7E=kvef z?|qpbq|+0=#qqb{UC{OPyzY7D2af*;eP4YC?UeXFg4cB&s80{#^@OYNUkyK{T%W$622S$-J$PG!#78RYel%$uxaES|NoVQpFQ#K z1-)d${y)K4lM$zK`ACBN&x!?B%{dY#;TcW|aU;OaS>zcbr?{4@)6g>X_#t1)WQ2v?l1b8C!dAS(d=lx*P z^K*&1qpg>ddYo@1 z|942|T{sSUUH2H_9*5_{3*dO#V**UazZ>*@^A8+2CM{qoqw2eJ^~kT-1|PKW1j)% z5zhAsbIE@m^g91B%Hw^AVjTB%tQz(4eU`5y=M(P&IE8$t!h6Wy^ML2!HiY+m{!Z*n z!e_zF`1?Ez-%Ji}CG?2@n>e&W%z`rBB2wn`Ig5EbD zOZhyGU5;6lC!2J=&YMg4d2j_h1bW?fJ@tQr{GNo~H)=t;?q^>|4kVtRqf95<0q`KW z3?2^G!_VOt@Gf{aEJQgA!#?=;g<1Gdfwl3k1N-3bb@xvEUxfEl&j(=me=Y>)ef>Pt zFE1=kJC}f7_x(gZUU#%79p49);rIpkUkHoC5->mc6o3t2L+EwE2c(xpIi|o&(#e9a zLO<8?eU10^>XS|b=)VUJ|L=?7zQO-nIG1wxJb#mLZ$Zyn0|@VRRyuYw;x~uRw;{)G zAe|j>KK={f-BGb(_rNi5EG$Jl-xvKtykB7z!uh#kIoi$7X0g`a0@$s`nXI5xx`Yc825ep8)$(j(*Vl4E{UdJd`6Z^ggcV znNg%O8dfKt8t`_~y#pSD{}$-`h+Z7O6MxS;H)7ueZzi8x;JxrZ_$A@Kg0pF-Ij|V{ z6o=c1cNM&ta9g4K!S8K)-ERlQgBC&ET!@Ht2Q755zAHOTgTe&;9K87<`}fG3k5)-=qBR!>;(J!#hdW_Zj|s zZ(p~)ujF;>M#67`>7?5YK1n+~1%2P(`{JGWd!4%y`!IMi>3Cn`ILdiE>`FMVBM0F> z7#>c1uNykiUY+5El-vF2dEd`T#*+Rx_&Mo)0pG;`E!dcRy)V9#a4*6S;D^xj*r$}E zEo=wZxgPL%;++6z;qQIZ{?yCwO{^oF+o2eCakvP2pXp4}I}4VhUgcpI((ejAFWkxT z0>mo_eP2D9@F!ERQ{XG`Ral>J4PX!aeV?B}K3->f-_7fy4C<2!eIM+0x(0vm3+EyI zywKO3pD6$B@D5l8mWAgL&+F)7*gj92QeI!Dy>B}c|1qR97W%nNW$a;aIDDM+pMXW7 z^Ib-}Er*4OR~UXvzJBh~koNF(v?}RUgMJRP1Ur@Zx!_>p4}rc8^yc`LG6DuVWv_{|V^x{3C2%7rgG-hX0lDZTJqHPQC}gbExOJ@Ll}hgI>4!KI#bS<$9iu zeFi+7@~?;92V8@F7~xjI;pF4@3cb#{oa47}{8l&$x*vbU_P&qb^YwN1N9z3(yaV0| zYZ1RTd=h`(*LfZ3^R6o8ss=qzd7styab6eux%hPIe;@69KfICrZh{Y!?jz9mot-#7 z6V8I(w|bfMUdI0w*pYmFo$|cnb=5M$Er)*3_8HQ<1YQcgPMk>iUnu9V@D0Mf34I^y z^UC+tZ3&-6I#b|x@O!v|@_XIz4Dp_YURTz{_P(_1U7vIsz;~h7Etk>nmqWi7;PUKs$At59CEsUzAN4ER9E)NmzVR#bh zo(ylJT(`q73HKFThQIF%wqsufTfx?_Dy#-akk3f?2>y>k-v<|^{BMx&n{YYxald8 z2jTB|%=_RzuXhm6_l@4iXhb<5-Prwl5anlhjj8nzgJwD{wYBGLU02-3VNSm40ayU%?nSbTxY=g_&0z9h&K@WzSq}* zjg)H>^mE5v#GgvK)8K8Sb362T>Fb2=Q$FK(LF!oudS1SQ^sXV?wQw2qxL!y(4ul{^ zu;0Ib_ZtUZf-gg#SDrU~9+W2kVbJTA-Xz=yzRvMCpx6CBlfKX6G>(_Rza*@Ke_dFC zbSuIR_;-YB=!dniBCG_jCfqgfdH4d1(atHb2Km&4^Y9P;-$nD+sp@dYs)s`TSnN@z|b+zb3x#TfGnS z9_e_VYfrh|?hlgAL$EBzeP6o)`zUw_`5X%C;a?wmTyMkPNxCmW-xuZP_$!p}Rp|4~ z>v~_;Zy|n9@^!maB%Mmodb@HpZf4~O7C6h1;ap67j^UxDzxPo0JB zabJr3p2GiWcoOOQK7R-HjnM1xG~#<7;8c#^ga5s-2IcRL*Pb=>Q^4#evSza-pO za0>oY;kWpI2g~DM0e(!rpTO5?uQy;z;khZ`T8^)SshoGYU;*+e2>o2n z`&4%k?{4UJJB|D^D0e3OlyINHHH2FWJx?qke_t2V34addI2XF#s+0aO(($^hF7ezB zrAfC8Y{&8T(D&hkIX-}N2g0x6H_+GBDuf@0|9I$il<&)z;lCWNhrTZ^LOF`UC2%Qp zzk6NVjdth`hmhV-_!xW~E}(t9jyRQcPlH}pyPf@aMkA=-*@Qa>dSA`^I#-hZcIfl` z1j_df^uEtoggYDVAYI?rZpFR?dSBsv(zzA?+u*VId!9KQdp-0%gZC9*!{66k-)CGy zd-*mmo<%v`j$UVt<@iCQ=Y2E(9nu8+`%{hq@LTfv z4tibbb^kr&cQ3q#c-O)M@Sg#_@70y`%EEH+7sCAtucqABK%X~5DDSQKdmZ;P_Ajt4 z>G(W6jeNW>^eE+g4Ej9qx;=w*GNI=UzsFgZ^y)#cThAoDFW{GOGUdsDM-lI6*dBUb zpGvrC@KKKYyqkkP7rLBTl-KjhAdU|rox$)c%Jnt$yzJ*JCGal^y>GXj_k z?{n}&;(Y{X5pOnpf^t0xpCg>tffMkb2wQTz6`VpoUI+9cUEil)h3$RPZ?M0GT}Y=Z z%m?$s)uiw1$WPcFXXj#{2aks*z$4(1(DU-a)TblrCJ06(*l8 zl=E149qC>Vo5L3HCephZwjiF@QP0wT9{0Wu`aY!r`8I^zNw)`VN_x#;EyC4?)k)v$ z%KntY>yB*F@j75I$9K7A1kZ!#!&eFS8uY$FZ}NW-fA6yurrnFcvj}%K z+y?zz$oHil2gi`F&!cvv(;gmA{1f0}!e_%(a5cP;a2LU{l(!tr!r%7=HxO?J+(fv| zFdyS6KRk(WCqv)I-br~MAfDSPo&3Bndp`CB(B&#mJh!8t^PPbIiO|nkypQSYuJ?)N zk?wprm~#0((EFxGQlAbS_dJ}A-3=Bdog&cd!Vjo_4F4238-MS!y^jAIa0NUBZh^j#nkVCZ$jM&b>JBcT88%j>?f)Z6bZdEa>q;eDNX2YVv2aWfO!%*Hkk z!8SKwo5y0CXJVUPCz-xJn4YK17l?1ZiEVy?ZF=0A-v2U-(%z=8d#10;W_`k&9#3XB zj+;ZU&2iYK&kxi4{pM1_n`^MmQ?Si*vCT`d&1u}z;xrtddQ-*20Xh;MpcH$8uwClcQDI>Ee*)3acX8jf(E-N|MnJ`t85x2kvV_H;Cy#pL$Vc$#k)uaG zf=7>j3+<}+dm4vK2qI=C(?wFh+PbLz*Q=^mJs(raw%Y2(YGZ@%n@UsXk{bOWgiTVS zd9BZo@ZbmdDIp0j>e1FUP+mv>L4_2|P~P3y+G?Vf+P{)&Gqplez81tRD+N-mEouA0 zJ-oGA=^S>ZVhoSu`p2V;+G9#9{*v|BYrb9Am}b|bXI7XRE;|C}dJ>gy@(!?wnAf4|q2j`JJqDjJpx3$3g7j4NJO zqF1@a`Rhve=>YptJtkgdUuTCV?b32V?K&jCSah{_B&`jr-OXaR+HbxcFSh@3X}8`1DiZ1#4Ubqn^9ujG5L% zQBmxw%A^=odW$5~uBOP(Y?bnWcFmhf6hJfOp&pb4+UdDAx4J+Bimm=O1e=7#8mn&V zhpL+?zOIR^PlCD)EaPA2`zq==j*QB}v14kf$H>fD@~Tfg`E_tT+yFO1l~Jcrr-|t{ zjkIIhjc#w-Dc=Ei!T>hGU2r$t1NXvxa6dc%55hz6FgyZ}!ej6_RC_x?{v{C;J~ z(Ow#U9sw>{so018A~XNHZ2o;i zzQ>q?zjqYZEXSky-wNpW81-NEJ~^uw7Y3x8g!;+M~L1E%B$Cm(hxtC8>bUV|@RY>5K3GqC*mEF4z12Pyg)g=l}o! literal 0 HcmV?d00001 diff --git a/examples/point_nestml_izh/run_pointnet.py b/examples/point_nestml_izh/run_pointnet.py new file mode 100644 index 000000000..b34b7619a --- /dev/null +++ b/examples/point_nestml_izh/run_pointnet.py @@ -0,0 +1,31 @@ +import os, sys + +from bmtk.simulator import pointnet +import nest + +# nest.ResetKernel() +# nest.Install('nestml_39f5da2aef404887ac26009e1449206e_module') + + +# neuron = nest.Create('ornstein_uhlenbeck_noise_neuron') +# print(list(neuron)) + +def run(config_file): + configure = pointnet.Config.from_json(config_file) + configure.build_env() + + network = pointnet.PointNetwork.from_config(configure) + # network.add_nest_module('/local1/workspace/bmtk/examples/point_nestml_izh/components/nestml/') + # network.add_nest_module('nestml_izh_module') + # network.add_nest_module('/local1/workspace/bmtk/examples/point_nestml_izh/components/nestml/nestml_izh_module.so') + + + # nest.Install('nestml_39f5da2aef404887ac26009e1449206e_module') + sim = pointnet.PointSimulator.from_config(configure, network) + sim.run() + + +if __name__ == '__main__': + # Find the appropriate config.json file + run('config.simulation.json') + # run('config.simulation_perturbations.json') From 1e67511fcbef984db05204109c885ca70a8b9d6a Mon Sep 17 00:00:00 2001 From: kaeldai Date: Sat, 6 Jul 2024 10:44:09 -0700 Subject: [PATCH 4/4] some minor fixes --- bmtk/builder/builder_utils.py | 2 ++ bmtk/simulator/pointnet/modules/spikes_inputs.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bmtk/builder/builder_utils.py b/bmtk/builder/builder_utils.py index af0ff1f22..7137c07d7 100644 --- a/bmtk/builder/builder_utils.py +++ b/bmtk/builder/builder_utils.py @@ -87,6 +87,8 @@ def check_properties_across_ranks(properties, graph_type='node'): phash = hashlib.md5(pval.encode('utf-8')).hexdigest() elif isinstance(pval, (int, float, bool)): + if np.isnan(pval): + pval = 'NONE' phash = pval elif isinstance(pval, (list, tuple)): diff --git a/bmtk/simulator/pointnet/modules/spikes_inputs.py b/bmtk/simulator/pointnet/modules/spikes_inputs.py index f193b0391..f872ec456 100644 --- a/bmtk/simulator/pointnet/modules/spikes_inputs.py +++ b/bmtk/simulator/pointnet/modules/spikes_inputs.py @@ -48,7 +48,7 @@ def initialize(self, sim): io.log_exception(f'Could not find @spikes_generator function "{spikes_generator}" required for {self._name} inputs.') spikes_func = py_modules.spikes_generator(name=spikes_generator) - self._spike_trains = SpikeTrains(cace_to_disk=False) + self._spike_trains = SpikeTrains(cache_to_disk=False) for node in node_set.fetch_nodes(): timestamps = spikes_func(node, sim) self._spike_trains.add_spikes(