From 2517556a459b5f9b986878526756355122069f3c Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 7 Nov 2025 10:03:01 -0800 Subject: [PATCH 1/2] 1.2.0 release candidate --- nt2/__init__.py | 2 +- nt2/containers/data.py | 16 +- nt2/containers/particles.py | 689 ++++++++++++++++++++++++++++++----- nt2/readers/base.py | 2 - nt2/tests/test_cli.py | 2 + nt2/tests/test_containers.py | 15 - nt2/tests/test_reader.py | 12 +- nt2/utils.py | 3 +- 8 files changed, 606 insertions(+), 135 deletions(-) diff --git a/nt2/__init__.py b/nt2/__init__.py index 5a81e39..b7e3338 100644 --- a/nt2/__init__.py +++ b/nt2/__init__.py @@ -1,4 +1,4 @@ -__version__ = "1.1.0" +__version__ = "1.2.0" import nt2.containers.data as nt2_data diff --git a/nt2/containers/data.py b/nt2/containers/data.py index d706cee..de2c511 100644 --- a/nt2/containers/data.py +++ b/nt2/containers/data.py @@ -242,9 +242,8 @@ def makeMovie( if time is None: if self.fields_defined: time = self.fields.t.values - elif self.particles_defined: - species = sorted(list(self.particles.keys())) - time = self.particles[species[0]].t.values + elif self.particles_defined and self.particles is not None: + time = list(self.particles.times) else: raise ValueError("No time values found.") assert time is not None, "Time values must be provided." @@ -311,14 +310,13 @@ def compactify(lst: list[Any] | KeysView[Any]) -> str: string += f" - total size: {ToHumanReadable(self.fields.nbytes)}\n\n" else: string += "Fields: empty\n\n" - if self.particles_defined: - species = sorted(list(self.particles.keys())) + if self.particles_defined and self.particles is not None: + species = sorted(self.particles.species) string += "Particle species:\n" string += f" - species: {compactify(species)}\n" - string += f" - timesteps: {len(self.particles[species[0]].t)}\n" - string += f" - quantities: {compactify(self.particles[species[0]].data_vars.keys())}\n" - string += f" - max # per species: {[self.particles[sp].idx.shape[0] for sp in species]}\n" - string += f" - total size: {ToHumanReadable(sum([self.particles[sp].nbytes for sp in species]))}\n\n" + string += f" - timesteps: {len(self.particles.times)}\n" + string += f" - quantities: {compactify(self.particles.columns)}\n" + string += f" - total size: {ToHumanReadable(self.particles.nbytes)}\n\n" else: string += "Particles: empty\n\n" diff --git a/nt2/containers/particles.py b/nt2/containers/particles.py index bb17a33..cf5dc6f 100644 --- a/nt2/containers/particles.py +++ b/nt2/containers/particles.py @@ -1,50 +1,496 @@ -from typing import Any +from typing import Any, Callable, List, Optional, Sequence, Tuple, Literal +from copy import copy import dask import dask.array as da -import xarray as xr +import dask.dataframe as dd +from dask.delayed import delayed +import pandas as pd import numpy as np +import matplotlib.pyplot as plt +import matplotlib.axes as maxes + from nt2.containers.container import BaseContainer from nt2.readers.base import BaseReader -class Particles(BaseContainer): - """Parent class to manage the particles dataframe.""" +IntSelector = int | Sequence[int] | slice | Tuple[int, int] +FloatSelector = float | slice | Sequence[float] | Tuple[float, float] - @staticmethod - @dask.delayed - def __read_species_quantity( - path: str, reader: BaseReader, species_quantity: str, step: int, pad: int - ) -> Any: - """Reads a species from the data. - This is a dask-delayed function used further to build the dataset. +class Selection: + def __init__( + self, + type: Literal["value", "range", "list"], + value: Optional[int | float | list | tuple] = None, + ): + self.type = type + self.value = value - Parameters - ---------- - path : str - Main path to the data. - reader : BaseReader - Reader to use to read the data. - species_quantity : str - Quantity specific to a species to read. - step : int - Step to read. - pad : int - Length to pad the array to. + def intersect(self, other: "Selection") -> "Selection": + if self.value is None: + return copy(other) + elif other.value is None: + return copy(self) + if self.type == "value" and other.type == "value": + if self.value == other.value: + return Selection("value", self.value) + else: + return Selection("value") + elif self.type == "value" and other.type == "list": + assert isinstance(other.value, list), "other.value must be a list" + if self.value in other.value: + return Selection("value", self.value) + else: + return Selection("value") + elif self.type == "value" and other.type == "range": + assert ( + isinstance(other.value, tuple) and len(other.value) == 2 + ), "other.value must be a tuple of length 2" + lo, hi = other.value + if lo <= self.value < hi: + return Selection("value", self.value) + else: + return Selection("value") + elif self.type == "list" and other.type == "value": + return other.intersect(self) + elif self.type == "list" and other.type == "list": + assert isinstance(self.value, list), "self.value must be a list" + assert isinstance(other.value, list), "other.value must be a list" + new_values = [v for v in self.value if v in other.value] + return Selection("list", new_values) + elif self.type == "list" and other.type == "range": + assert ( + isinstance(other.value, tuple) and len(other.value) == 2 + ), "other.value must be a tuple of length 2" + assert isinstance(self.value, list), "self.value must be a list" + lo, hi = other.value + new_values = [v for v in self.value if lo <= v <= hi] + return Selection("list", new_values) + elif self.type == "range" and other.type == "value": + return other.intersect(self) + elif self.type == "range" and other.type == "list": + return other.intersect(self) + elif self.type == "range" and other.type == "range": + assert ( + isinstance(self.value, tuple) and len(self.value) == 2 + ), "self.value must be a tuple of length 2" + assert ( + isinstance(other.value, tuple) and len(other.value) == 2 + ), "other.value must be a tuple of length 2" + lo1, hi1 = self.value + lo2, hi2 = other.value + new_lo = max(lo1, lo2) + new_hi = min(hi1, hi2) + if new_lo <= new_hi: + return Selection("range", (new_lo, new_hi)) + else: + return Selection("value") + else: + raise ValueError(f"Unknown selection types: {self.type}, {other.type}") - Returns - ------- - Any - Species data. + def __repr__(self) -> str: + if self.type == "value": + return "all" if self.value is None else f"{self.value:.3g}" + elif self.type == "range": + if self.value is None: + return "all" + else: + assert ( + isinstance(self.value, tuple) and len(self.value) == 2 + ), "value must be a tuple of length 2" + lo, hi = self.value + lo_str = "..." if lo is None or lo == -np.inf else f"{lo:.3g}" + hi_str = "..." if hi is None or hi == np.inf else f"{hi:.3g}" + return f"[ {lo_str} -> {hi_str} ]" + elif self.type == "list": + assert isinstance(self.value, list), "value must be a list" + return "{ " + ", ".join(f"{v:.3g}" for v in self.value) + " }" + else: + return "InvalidSelection" + + def __str__(self) -> str: + return self.__repr__() + + +def _coerce_selector_to_mask( + s: IntSelector | FloatSelector, + series: Any, + inclusive_tuple: bool = True, + method="exact", +): + from operator import ior + from functools import reduce + + if isinstance(s, slice): + lo = s.start if s.start is not None else -np.inf + hi = s.stop if s.stop is not None else np.inf + step = s.step + mask = (series >= lo) & (series <= hi) + if step not in (None, 1): + mask = mask & (((series - lo) % step) == 0) + return mask, ("range", (lo, hi)) + elif isinstance(s, tuple) and len(s) == 2 and inclusive_tuple: + lo, hi = s + if lo is None: + lo = -np.inf + if hi is None: + hi = np.inf + return (series >= lo) & (series <= hi), ("range", (lo, hi)) + elif isinstance(s, (list, tuple, np.ndarray, pd.Index, pd.Series)): + if method == "exact": + return series.isin(list(s)), ("list", list(s)) + else: + return reduce( + ior, [np.abs(series - v) == np.abs(series - v).min() for v in s] + ), ("list", list(s)) + else: + if method == "exact": + return series == s, ("value", s) + else: + return np.abs(series - s) == np.abs(series - s).min(), ("value", s) + + +class ParticleDataset: + def __init__( + self, + species: List[int], + read_steps: Callable[[], np.ndarray], + read_times: Callable[[], np.ndarray], + read_column: Callable[[int, str], np.ndarray], + read_colnames: Callable[[int], List[str]], + fprec: Optional[type] = np.float32, + selection: Optional[dict[str, Selection]] = None, + ddf_index: dd.DataFrame | None = None, + ): + self.species = species + self.read_steps = read_steps + self.read_times = read_times + self.read_column = read_column + self.read_colnames = read_colnames + self.fprec = fprec + self.index_cols = ("id", "sp") + self._all_columns_cache: Optional[List[str]] = None + + if selection is not None: + self.selection = selection + else: + self.selection = { + "t": Selection("range"), + "st": Selection("range"), + "sp": Selection("range"), + "id": Selection("range"), + } + + self.steps = read_steps() + self.times = read_times() + + self._dtypes = { + "id": np.int64, + "sp": np.int32, + "row": np.int64, + "st": np.int64, + "t": fprec, + "x": fprec, + "y": fprec, + "z": fprec, + "ux": fprec, + "uy": fprec, + "uz": fprec, + } + + if ddf_index is not None: + self._ddf_index = ddf_index + else: + self._ddf_index = self._build_index_ddf() + + @property + def ddf(self) -> dd.DataFrame: + return self._ddf_index + + @property + def nbytes(self) -> int: + return self.ddf.memory_usage(index=True, deep=True).sum().compute() + + @property + def columns(self) -> List[str]: + if self._all_columns_cache is None: + self._all_columns_cache = self.read_colnames(self.steps[0]) + return self._all_columns_cache + + def sel( + self, + t: Optional[IntSelector | FloatSelector] = None, + st: Optional[IntSelector] = None, + sp: Optional[IntSelector] = None, + id: Optional[IntSelector] = None, + method: str = "exact", + ) -> "ParticleDataset": + ddf = self._ddf_index + new_selection = {k: copy(v) for k, v in self.selection.items()} + if st is not None: + ddf_sel, (sel_type, sel_value) = _coerce_selector_to_mask( + st, ddf["st"], method="exact" + ) + ddf = ddf[ddf_sel] + new_selection["st"] = new_selection["st"].intersect( + Selection(sel_type, sel_value) + ) + if t is not None: + ddf_sel, (sel_type, sel_value) = _coerce_selector_to_mask( + t, ddf["t"], method=method + ) + ddf = ddf[ddf_sel] + new_selection["t"] = new_selection["t"].intersect( + Selection(sel_type, sel_value) + ) + if sp is not None: + ddf_sel, (sel_type, sel_value) = _coerce_selector_to_mask( + sp, ddf["sp"], method="exact" + ) + ddf = ddf[ddf_sel] + new_selection["sp"] = new_selection["sp"].intersect( + Selection(sel_type, sel_value) + ) + if id is not None: + ddf_sel, (sel_type, sel_value) = _coerce_selector_to_mask( + id, ddf["id"], method="exact" + ) + ddf = ddf[ddf_sel] + new_selection["id"] = new_selection["id"].intersect( + Selection(sel_type, sel_value) + ) + + return ParticleDataset( + species=self.species, + read_steps=self.read_steps, + read_times=self.read_times, + read_column=self.read_column, + read_colnames=self.read_colnames, + fprec=self.fprec, + selection=new_selection, + ddf_index=ddf, + ) + + def isel( + self, t: Optional[IntSelector] = None, st: Optional[IntSelector] = None + ) -> "ParticleDataset": + ddf = self._ddf_index + new_selection = {k: v for k, v in self.selection.items()} + for t_or_s, t_or_s_str, t_or_s_arr in zip( + [t, st], ["t", "st"], [self.times, self.steps] + ): + if t_or_s is not None: + if isinstance(t_or_s, slice): + lo = t_or_s.start if t_or_s.start is not None else 0 + hi = t_or_s.stop if t_or_s.stop is not None else -1 + ddf_sel, (sel_type, sel_value) = _coerce_selector_to_mask( + slice(t_or_s_arr[lo], t_or_s_arr[hi]), + ddf[t_or_s_str], + method="exact", + ) + ddf = ddf[ddf_sel] + new_selection[t_or_s_str] = new_selection[t_or_s_str].intersect( + Selection(sel_type, sel_value) + ) + elif isinstance(t_or_s, (list, tuple, np.ndarray, pd.Index, pd.Series)): + ddf_sel, (sel_type, sel_value) = _coerce_selector_to_mask( + [t_or_s_arr[ti] for ti in t_or_s], + ddf[t_or_s_str], + method="exact", + ) + ddf = ddf[ddf_sel] + new_selection[t_or_s_str] = new_selection[t_or_s_str].intersect( + Selection(sel_type, sel_value) + ) + else: + ddf_sel, (sel_type, sel_value) = _coerce_selector_to_mask( + t_or_s_arr[t_or_s], ddf[t_or_s_str], method="exact" + ) + ddf = ddf[ddf_sel] + new_selection[t_or_s_str] = new_selection[t_or_s_str].intersect( + Selection(sel_type, sel_value) + ) + return ParticleDataset( + species=self.species, + read_steps=self.read_steps, + read_times=self.read_times, + read_column=self.read_column, + read_colnames=self.read_colnames, + fprec=self.fprec, + selection=new_selection, + ddf_index=ddf, + ) + + def _build_index_ddf(self) -> dd.DataFrame: + def _load_index_partition(st: int, t: float, index_cols: Tuple[str, ...]): + cols = {c: self.read_column(st, c) for c in index_cols} + n = len(next(iter(cols.values()))) + df = pd.DataFrame(cols) + df["st"] = np.asarray(st, dtype=np.int64) + df["t"] = np.asarray(t, dtype=float) + df["row"] = np.arange(n, dtype=np.int64) + return df + + delayed_parts = [ + delayed(_load_index_partition)(st, t, self.index_cols) + for st, t in zip(self.steps, self.times) + ] + + meta = pd.DataFrame( + { + **{ + c: np.array([], dtype=self._dtypes.get(c, "O")) + for c in self.index_cols + }, + "st": np.array([], dtype=self._dtypes.get("st", np.int64)), + "t": np.array([], dtype=self._dtypes.get("t", np.int64)), + "row": np.array([], dtype=self._dtypes.get("row", np.int64)), + } + ) + + ddf = dd.from_delayed(delayed_parts, meta=meta) + return ddf + + def load(self, cols: Sequence[str] = None) -> pd.DataFrame: + if cols is None: + cols = self.columns + + cols = [c for c in cols if c not in ("t", "st", "row")] + + meta_dict = { + c: np.array([], dtype=self._dtypes.get(c, np.float64)) for c in cols + } + meta = self._ddf_index._meta.assign(**meta_dict) + + read_column = self.read_column + cols_tuple = tuple(cols) + + def _attach_columns(part: pd.DataFrame) -> pd.DataFrame: + if len(part) == 0: + for c in cols_tuple: + part[c] = np.array([], dtype=meta.dtypes[c]) + return part + st_val = int(part["st"].iloc[0]) + + arrays = {c: read_column(st_val, c) for c in cols_tuple} + + sel = part["row"].to_numpy() + for c in cols_tuple: + part[c] = np.asarray(arrays[c])[sel] + return part + + return ( + self._ddf_index.map_partitions(_attach_columns, meta=meta) + .compute() + .drop(columns=["row"]) + ) + + def __repr__(self) -> str: + ret = "ParticleDataset:\n" + for k, v in self.selection.items(): + ret += f" {k}: {v}\n" + ret += f" columns: {self.columns}\n" + ret += f" total rows: {len(self._ddf_index)}\n" + return ret + + def __str__(self) -> str: + return self.__repr__() + + def spectrum_plot( + self, + ax: maxes.Axes | None = None, + bins: np.ndarray | None = None, + quantity: Callable[[pd.DataFrame], np.ndarray] | None = None, + ): + if ax is None: + ax = plt.gca() + + if "ux" in self.columns: + cols = ["ux", "uy", "uz"] + if quantity is None: + uSqr = lambda df: np.sum( + [df[c].to_numpy(dtype=np.float64) ** 2 for c in cols], axis=0 + ) + quantity = lambda df: uSqr(df) * np.sqrt(1.0 + uSqr(df)) + else: + cols = ["ur", "uth", "uph"] + if quantity is None: + uSqr = lambda df: np.sum( + [df[c].to_numpy(dtype=np.float64) ** 2 for c in cols], axis=0 + ) + quantity = lambda df: uSqr(df) * np.sqrt(1.0 + uSqr(df)) + df = self.load(cols=["sp", *cols]) + species = sorted(df["sp"].unique()) + arrays = df.groupby("sp").apply(quantity, include_groups=False) + if bins is None: + bins = np.logspace(0, 4, 100) + hists = {sp: np.histogram(arrays[sp], bins=bins)[0] for sp in species} + bins = 0.5 * (bins[1:] + bins[:-1]) + for sp in species: + ax.loglog(bins, hists[sp], label=f"{sp}") + if bins.min() > 0 and bins.max() / bins.min() > 100: + ax.set(xscale="log", yscale="log") + + def phase_plot( + self, + ax: maxes.Axes | None = None, + x_quantity: Callable[[pd.DataFrame], np.ndarray] | None = None, + y_quantity: Callable[[pd.DataFrame], np.ndarray] | None = None, + xy_bins: Tuple[np.ndarray, np.ndarray] | None = None, + **kwargs: Any, + ): + if ax is None: + ax = plt.gca() + + if "ux" in self.columns: + cols = ["ux", "uy", "uz"] + for c in "xyz": + if c in self.columns: + cols.append(c) + if x_quantity is None: + x_quantity = lambda df: df["x"].to_numpy(dtype=np.float64) + if y_quantity is None: + y_quantity = lambda df: df["ux"].to_numpy(dtype=np.float64) + else: + cols = ["ur", "uth", "uph"] + for c in ["r", "th", "ph"]: + if c in self.columns: + cols.append(c) + if x_quantity is None: + x_quantity = lambda df: df["r"].to_numpy(dtype=np.float64) + if y_quantity is None: + y_quantity = lambda df: df["ur"].to_numpy(dtype=np.float64) + + df = self.load(cols=[*cols]) + x_array = x_quantity(df) + y_array = y_quantity(df) + + if xy_bins is None: + x_bins = np.linspace(x_array.min(), x_array.max(), 100) + y_bins = np.linspace(y_array.min(), y_array.max(), 100) + xy_bins = (x_bins, y_bins) + else: + x_bins, y_bins = xy_bins + + h2d, xedges, yedges = np.histogram2d(x_array, y_array, bins=[x_bins, y_bins]) + X, Y = np.meshgrid( + 0.5 * (xedges[1:] + xedges[:-1]), 0.5 * (yedges[1:] + yedges[:-1]) + ) + pcm = ax.pcolormesh( + X, + Y, + h2d.T, + shading="auto", + rasterized=True, + **kwargs, + ) + return pcm - """ - arr = reader.ReadArrayAtTimestep(path, "particles", species_quantity, step) - shape = reader.ReadArrayShapeAtTimestep( - path, "particles", species_quantity, step - )[0] - return da.pad(arr, ((0, pad - shape),), mode="constant", constant_values=np.nan) + +class Particles(BaseContainer): + """Parent class to manage the particles dataframe.""" def __init__(self, **kwargs: Any) -> None: """Initializer for the Particles class. @@ -64,7 +510,7 @@ def __init__(self, **kwargs: Any) -> None: self.__particles = self.__read_particles() else: self.__particles_defined = False - self.__particles = {} + self.__particles = None @property def particles_present(self) -> bool: @@ -96,59 +542,42 @@ def particles_defined(self) -> bool: return self.__particles_defined @property - def particles(self) -> dict[int, xr.Dataset]: + def particles(self) -> ParticleDataset | None: """Returns the particles data. Returns ------- - dict[int, xr.Dataset] + ParticleDataset Dictionary of datasets for each step. """ return self.__particles - def __read_particles(self) -> dict[int, xr.Dataset]: + def __read_particles(self) -> ParticleDataset: """Helper function to read all particles data.""" - self.reader.VerifySameCategoryNames(self.path, "particles", "p") - self.reader.VerifySameParticleShapes(self.path) - valid_steps = self.nonempty_steps - prtl_species = self.reader.ReadParticleSpeciesAtTimestep( - self.path, valid_steps[0] + + quantities = self.reader.ReadCategoryNamesAtTimestep( + self.path, "particles", "p", valid_steps[0] ) - prtl_quantities = set( - q.split("_")[0] - for q in self.reader.ReadCategoryNamesAtTimestep( - self.path, "particles", "p", valid_steps[0] + unique_quantities = sorted( + list( + set( + [ + q.split("_")[0] + for q in quantities + if not q.startswith("pIDX") and not q.startswith("pRNK") + ] + ) ) - if q.startswith("p") ) - prtl_quantities = sorted(prtl_quantities) - - first_quantity = next(iter(prtl_quantities)) - maxlens = { - sp: np.max( - [ - self.reader.ReadArrayShapeAtTimestep( - self.path, "particles", f"{first_quantity}_{sp}", st - ) - for st in valid_steps - ] - ) - for sp in prtl_species - } - - times = self.reader.ReadPerTimestepVariable(self.path, "particles", "Time", "t") - steps = self.reader.ReadPerTimestepVariable(self.path, "particles", "Step", "s") - idxs: dict[int, dict[str, np.ndarray]] = { - sp: {"idx": np.arange(maxlens[sp])} for sp in prtl_species - } + all_species = sorted(list(set([int(q.split("_")[1]) for q in quantities]))) - all_dims = {sp: {**times, **(idxs[sp])}.keys() for sp in prtl_species} - all_coords = { - sp: {**times, **(idxs[sp]), "s": ("t", steps["s"])} for sp in prtl_species - } + sp_with_idx = sorted( + [int(q.split("_")[1]) for q in quantities if q.startswith("pIDX")] + ) + sp_without_idx = sorted([sp for sp in all_species if sp not in sp_with_idx]) def remap_quantity(name: str) -> str: """ @@ -158,32 +587,100 @@ def remap_quantity(name: str) -> str: return self.remap["particles"](name) return name - def get_quantity(species: int, quantity: str, step: int, maxlen: int) -> Any: - return Particles.__read_species_quantity( - self.path, self.reader, f"{quantity}_{species}", step, maxlen + def GetCount(step: int, sp: int) -> np.int64: + return np.int64( + self.reader.ReadArrayShapeAtTimestep( + self.path, "particles", f"pX1_{sp}", step + )[0] ) - return { - sp: xr.Dataset( - { - remap_quantity(quantity): xr.DataArray( - da.stack( - [ - da.from_delayed( - get_quantity(sp, quantity, step, maxlens[sp]), - shape=(maxlens[sp],), - dtype="float", - ) - for step in valid_steps - ], - axis=0, - ), - name=remap_quantity(quantity), - dims=all_dims[sp], - coords=all_coords[sp], + def ReadSteps() -> np.ndarray: + return np.array(self.reader.GetValidSteps(self.path, "particles")) + + def ReadTimes() -> np.ndarray: + return self.reader.ReadPerTimestepVariable( + self.path, "particles", "Time", "t" + )["t"] + + def ReadColnames(step: int) -> list[str]: + return [remap_quantity(q) for q in unique_quantities] + ["id", "sp"] + + def ReadColumn(step: int, colname: str) -> np.ndarray: + read_colname = None + if colname == "id": + idx = np.concat( + [ + self.reader.ReadArrayAtTimestep( + self.path, "particles", f"pIDX_{sp}", step + ).astype(np.int64) + for sp in sp_with_idx + ] + + [ + np.zeros(GetCount(step, sp), dtype=np.int64) - 100 + for sp in sp_without_idx + ] + ) + if len(sp_with_idx) > 0 and f"pRNK_{sp_with_idx[0]}" in quantities: + rnk = np.concat( + [ + self.reader.ReadArrayAtTimestep( + self.path, "particles", f"pRNK_{sp}", step + ).astype(np.int64) + for sp in sp_with_idx + ] + + [ + np.zeros(GetCount(step, sp), dtype=np.int64) - 100 + for sp in sp_without_idx + ] ) - for quantity in prtl_quantities - } + return (idx + rnk) * (idx + rnk + 1) // 2 + rnk + else: + return idx + elif colname == "x" or colname == "r": + read_colname = "pX1" + elif colname == "y" or colname == "th": + read_colname = "pX2" + elif colname == "z" or colname == "ph": + read_colname = "pX3" + elif colname == "ux" or colname == "ur": + read_colname = "pU1" + elif colname == "uy" or colname == "uth": + read_colname = "pU2" + elif colname == "uz" or colname == "uph": + read_colname = "pU3" + elif colname == "w": + read_colname = "pW" + elif colname == "sp": + return np.concat( + [ + np.zeros(GetCount(step, sp), dtype=np.int32) + sp + for sp in sp_with_idx + ] + + [ + np.zeros(GetCount(step, sp), dtype=np.int32) + sp + for sp in sp_without_idx + ] + ) + else: + read_colname = f"p{colname}" + + def get_quantity_for_species(sp: int) -> np.ndarray: + if f"{read_colname}_{sp}" in quantities: + return self.reader.ReadArrayAtTimestep( + self.path, "particles", f"{read_colname}_{sp}", step + ) + else: + return np.zeros(GetCount(step, sp)) * np.nan + + return np.concat( + [get_quantity_for_species(sp) for sp in sp_with_idx] + + [get_quantity_for_species(sp) for sp in sp_without_idx] ) - for sp in prtl_species - } + + return ParticleDataset( + species=all_species, + read_steps=ReadSteps, + read_times=ReadTimes, + read_colnames=ReadColnames, + read_column=ReadColumn, + ) diff --git a/nt2/readers/base.py b/nt2/readers/base.py index d547c81..7f31551 100644 --- a/nt2/readers/base.py +++ b/nt2/readers/base.py @@ -1,5 +1,3 @@ -# pyright: reportUnusedParameter=false - from typing import Any import numpy.typing as npt import os, re, logging diff --git a/nt2/tests/test_cli.py b/nt2/tests/test_cli.py index 272262f..731c2be 100644 --- a/nt2/tests/test_cli.py +++ b/nt2/tests/test_cli.py @@ -46,6 +46,8 @@ def test_plot_png(test): [ "plot", PATH, + "--what", + "fields", "--sel", "x=slice(None, 5);y=slice(-5.0, 5.0)", "--isel", diff --git a/nt2/tests/test_containers.py b/nt2/tests/test_containers.py index 77302c4..8ad2e92 100644 --- a/nt2/tests/test_containers.py +++ b/nt2/tests/test_containers.py @@ -144,19 +144,4 @@ def prtl_remap(Xold: str) -> str: reader=reader, remap={"particles": prtl_remap}, ) - steps = reader.GetValidSteps(path=PATH, category="particles") assert particles.particles is not None, "Particles are None" - for p in prtl_coords: - if p == "z" and test["dim"] == "2D" and test.get("coords", "cart") == "cart": - continue - for i, (_, parts) in enumerate(particles.particles.items()): - if isinstance(test["particles"]["num"], list): - num = test["particles"]["num"][i] - else: - num = test["particles"]["num"] - check_shape(parts[p].shape, (len(steps), num)) - for i, st in enumerate(steps): - assert ( - parts[p].isel(t=i).s.values[()] == st - ), f"Step {st} does not match in particle {p}" - check_shape(parts[p].isel(t=i).shape, (num,)) diff --git a/nt2/tests/test_reader.py b/nt2/tests/test_reader.py index 28bae7e..17a889e 100644 --- a/nt2/tests/test_reader.py +++ b/nt2/tests/test_reader.py @@ -209,19 +209,9 @@ def test_reader(test): # Check prtl shapes for step in reader.GetValidSteps(path=PATH, category="particles"): for sp in range(nspec): - shape = reader.ReadArrayShapeAtTimestep( + reader.ReadArrayShapeAtTimestep( path=PATH, category="particles", quantity=f"pW_{sp+1}", step=step, ) - for p in prtl_names: - if not p.endswith(f"_{sp+1}"): - continue - prtl_shape = reader.ReadArrayShapeAtTimestep( - path=PATH, category="particles", quantity=p, step=step - ) - check_equal_arrays(prtl_shape, shape) - - # Check that all timesteps have the same names - reader.VerifySameCategoryNames(path=PATH, category="particles", prefix="p") diff --git a/nt2/utils.py b/nt2/utils.py index d85cece..700c738 100644 --- a/nt2/utils.py +++ b/nt2/utils.py @@ -2,6 +2,7 @@ import os import re import inspect +import numpy as np import xarray as xr @@ -78,7 +79,7 @@ def ToHumanReadable(num: float | int, suffix: str = "B") -> str: The number in human-readable format with SI prefixes. """ for unit in ("", "K", "M", "G", "T", "P", "E", "Z"): - if abs(num) < 1e3: + if np.abs(num) < 1e3: return f"{num:3.1f} {unit}{suffix}" num /= 1e3 return f"{num:.1f} Y{suffix}" From db0b70456627b38aa72e1367274ca4f2b8785558 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 7 Nov 2025 10:05:08 -0800 Subject: [PATCH 2/2] new particles reader --- dist/nt2py-1.2.0-py3-none-any.whl | Bin 0 -> 39719 bytes dist/nt2py-1.2.0.tar.gz | Bin 0 -> 34374 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 dist/nt2py-1.2.0-py3-none-any.whl create mode 100644 dist/nt2py-1.2.0.tar.gz diff --git a/dist/nt2py-1.2.0-py3-none-any.whl b/dist/nt2py-1.2.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..c1aae6eb3e13a0c32b80d7e443f14ef3e8fbba32 GIT binary patch literal 39719 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 I+UckN1527aM*si- literal 0 HcmV?d00001 diff --git a/dist/nt2py-1.2.0.tar.gz b/dist/nt2py-1.2.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..43eec3e0961431483c7798847a2defdb15294563 GIT binary patch literal 34374 zcmV)0K+eA(iwFP!rp^)q|LnbcW7{^eIJ$r9Q*hZmCsZmkk{l;p?W(tF((dML+s$pV zub{;6VTcDavt@KI}HOL;?d~Fc=Kxg`^m+cSi$% z==UG^=TQ+9MHZcHiZK7pt^M@j=h4H5^cQ~2zy1E>N5AP0hmVd=hR5`LFnrh_{>JJ5 z<^%j}@*>EfE5G@5{v^fl0Zew0)9-mu1U}%yKY!~iqPPgNalFW#d9+y2hgF!JhxF;F z2)9M&H+Mfj|M{2e|Jx_uJ^%Wvm#_RNxz#rIum8TW{s+V3$9L=hL;OU^EZ)pR=bPtG zzxwXwR~_;F`>&on`}Qk;HJ4A;yLFcS5Y7s}NLTUQ%K7E3|Mf15&X>h3O%~C)|3jW8 zA7=eO91M;1e>^v@-@pIL292d6oEO-$VOLyc<-~l}HAGq-0w1=;=aGhqwlVk_4 z7eSnd%G0m5>o}T4HE;ixTqNn6`1tYh-TMC!Kfydo z^Wk_r^ap)^0KZ^9hMgeUMd^6_(Eq*P?*!R-nhcL-i$w(GPN0DiNH4+!Uc*;kDNI{#`0&uSr}7)9^{SbRJIQAcQ&f;KpAv*({C73P8<44r`8ML;<#vc2}owH38&#@~*_-~!&#h^2T zvSE>?agH^x{w&O(4IEq_Ai}eg4jb$MI{`J8L6(QbQIck>AdcR`sR+P7^oN}p@IL6r zX8`6i_>yksYj_Zc_Tp$VZpvbOX+Gg9`~^~@Hr{cO}5@KOu>WQEJn~U4>0=9 zJjgG2mrn3&c(yrbg`v5J@O_qML6Jg*6Q9b5i%lNRx2qUIV87>4&JXi*1yHyRXMoe> z9FdF&Tfh|IW}gFIRslW5zAxgam_i$DFjNqF%n|p{Klu#iVe#WU!5$&pMV_z2nbOd5 zFrdLaf~w0CftWra4!-XQ?n8VT6tiVaJ%WkCXB zsQe6@x?IO;L9GEUJJCD|2ztL05wDM3jnyjnV{1 zfuQ=GAHsP=aDNZI{+}rMAsDjBeAGdlo$%@E)3}VZt z&LiwSo7NQ|FlJ@o3y|L?;cEe4<>zZ!wF6ojtKE7x1;GP20~`N4J3G?EJ_zZF}m@9;{Suxx}Z#pT| z&!TylBMc-4>{)Qm76lGu9VD>+Sn)o6OJ__Wk_&o=hsdY^8&p0ER%}7xn=DVUzqmx; zOEG5?iN%T~TP1vvufr{TEd;AwM{!K7bHD(_L4iY?M;Wa-;AtJi`1wwZ3XWtz*UNB| zPfIinsV=-(7gJoX7g53H_yiv3u=ZmdHWILWOm(klP@>{;~Jc8c+>&ds@ zAk*(tfw!w4p*TZC7B0dp1bV@)0_DS2(m`BvOg@Vk3n!-dGEC;fS6PrR8CO5PgdMg+WjE)t4M600qalS&*e1sbgoFbwk4iRN1$l9T$ z43^r_EDrJw z4Ha)08aR<`W=E@NmZe8*Qjp_qvgoJ?SGe**A;JJp1AHB0zmUq`%-%%vV#yZB;JEW9 zJfnR+C*Co@d51?pOeq(O`h+QXmJ`c95-Szwyx-Zv`U-ZX@X^`s-oo;_jAmiEEA%^W zqgf$%_uFW_rWJ*~yFK|oUxsn)C(-tnWz0SD|6n*cG4+4P$9MYw4|e`vU!3R8|K%`I z$@wD?06zKLxpJ=Y@Vwr^OZRv%bbFoaQKy41{nf=wq!tJ3C&4Oo#*PcLG!HM`KhUEh zx(vTW>HB%I-V`~!e-jl;YU>YN$v}Wyw)%f}wccI3_Qx-1a}IOYUq@>yLh?T=%yd@t zxd=d5p--1NEWYq44q*MkQUbnnL^_Tc@JlN278W$>H?XhYJez*={LAm3eE+ZMizl!C z3_YbDKnZ^pT!i05XIYT#P(7mdJ1^#8a_P@z@PGNVgbTlEJ^dN>IRJU@9u_ z0+^Sh%rTGiwqk7KwE}>a=y{0hkv2V8M6CR5nF?BPfR>I34UQ-}A34AC-Ylcpk`K0v zvwrX1AAYqen4gUP2kpPh&Dn!DX?C#yIW&K;-hiZ#Fa6y+Dg5{G|A&Kz2LC@9KEC7s zA7=i6caNMGv=SY53JN=&G#NRQ^(J4Qb~-<#XZZ-0D5+9Lw8XPbk{@B2&Dka?Hb*Ed z0T-cnc@eJj5oZ`j&L$7@5iNd@${xVUcXp9(iZ3pYc?pNMg^~Q`IPn516xk+}Fjya7 zhJ~|Pi>{(dLRQinAwiJ~m0w&wtZj&kowz$hI2adUx<;$dIXj$(YmnCQgb?Nu2H;`j z{HFpExi|3Al9e89*5_G(HZ;C}Nq%cE;_{uNl%q}KXi;J4V(-u!t1|vS2-aK<>lHRe z8}e(`^6SPym3xE$@Pcs$Nit<$M-F2nJ{&-jV#z@_0!& zef6As@H>A{1n2p^t}(NCjC^puJYq8pQ@f6iIBWVM3*#`z!v~jx`iX|q2k&5fw6ZrS)uYdXKJLme>x&3JTpNUNm%45{+7ydCrSK>>EDVlBcoyG`cAI;Ij(>71)ENzBr2v; znD7sE{)gpm%74S-!JYrl2l<&!x%@Mo;t`$*!R>Ifi31ejm-mL=c`E4%#{pa?FxXmPs_tzlW|X$t3qD1meA%N?9xS8DZt{_Fo>ji+#G3G*mO7?hVUP*do>Tra~cngub! znuiPLS;!13A#y=J05toJ;M|jSoukkBs2FV5b!7!S%Q?hinK*@i=-DEQ!yFJ#U(TaT zJn;cUpB=bgpy?4|uyg5={Neb7Gaj|gN`DWB<1EpN(r4Bwd1!iNbR}KLp73VB528G* z!ufj;Z^Ey#EX^dW=Ve_1F3Oz^bLjE~8t5-jMtGiPaK;AQPTWNl#`E0mIWAgJqZyz9 zzYqatfqTl-j({azZ-+=KVU%Y;@qS9^7z1JZgux%uD52Tu$s%3lC@af_+bAz`PXp6c zkC+ahq%oJAwKvr#(B%d8HAOXZUd*G+fL*B);ql*Jp{InGE!_XT66LS|?f-jzb#?XG z^)-A1^eptsryT=K93~!hw(ETE^heds!8@+er(%=-sjWAnm=DK>98cVy>%*$-RsoVy zfyjOK1!x}D)J6JL$kki8+{aL*)RA)~x^(Tk46~J*?$dM= z&z&SKoVi@g3J|Qwn8T~|&zn_{d>;mL^oR6-$&8#uoWhd$570x=bMnn%5p8L~B76DL zC6)o-B)@pdydRtZdGA>WEFy)^ON4uralm4ok%s5xa|f6%Kn?R&ECV+KtydaXC>!N& z7;FWzesfNvmgg_9lWSC=;isa6;{jTNO$>;}vHHzS%7o2fz(Q&}e3jYYD%`+f2kUz- zGM2yKuW#|!pYYc!{PhBVeTBdNk4lC>tI66A&T^c?uJcD{5FYD<#))&`Ug0bs`-8=` zbA|0)Uoo6qyRtl@{J|JubgEUU=D*5He4hdC{5&5%dy&RL=FRgFY_=qM=V3uKbC#xY zNi?W<#ZHSo21+3p9zJu{2!LVciTVnrH;?9F7S3fU1OWJ2!p>g2Nu7DL;(8*Oz07q2 znB5Ri4pZX(fB&!R0Dj$K>F$|S>}NTv*(Pl0X3zN=y>*=w8+ilEP@hqbHxD}llRAeJ zOSH5`#ix-y?BbE!LxLRUUVR+%wkkb@75uq7e6R_ICsWF z>W)}#XD(_wBxJ!B7AA#5@`fPAS4$Y2^yK3!Bxj=+wR7BjNkyyy5bLOHh40byUdIa{ z6guxur%)KqdC=x}X`=8&^(8Q!a(SG=1R&P9(C43r#VSh?6Z%rXaw>Rag?bZaGoOyN zO6v4MvAZMV$2$Mb;^@|OKzrlA`eyvsasTAx?)>-h=6@AL$p@VOlZTc0e|UHP|8VDj zALm;r0ALg9bl{h_&eC%--;L3m17z4cZu#q2|40oVPX9j`JgoTt4TmRp_P-DE!xufd z$@WmO-$Sh*afOOgt>6$(5|HoEl}jl6$}j;S8~lX2zja&?9|4Jyp!*n#w!GO4d;iD$?Mc2c7e<9fkW=>NE2*M=1~R>r`gUg53XHRa7TdJMC4)Y!M}1E z=FzN}z?UAX6`cP_B|{!Zv+z{T5Y)lrnCmJ-V@+ILGetlcPf>9Ov;`l1JOHh|uAi^t zsPNoBa77K4!WKt++65>aE}nU&J%^O7s1y(3To!twH3ic%)ED=hAUnq{m>n3qJ!jC> z3qv{jE6U2Z0Aq?VSx^AuE#@Rx=A5bCGtn%peftGHq02#}T~P^Jdua6AYKU;tpo z5%%>xA61(2aSk&V0u9{jIrkX%(OT`+q6C2*%Hs27`o@#yicz`2l*)8myz&bhqX_oa z$2SY&_zdIB%Dtec72usg7ARCG&>gp@EED>8N~(}vhp&3-^O!8+WbH21^lV3BsdLgP zbQBk^9Rs*E$`;w!al8D<8vVLVsnSxfnT@BnDsf;6p^Bsvi~M zD)+i%{3CrcN+c->$vdq;4%b|-h#E^ zUM-l@!8$od_W|i4A=g!TUNDaU-=)QKWNIiNhI8(t@In+P`2+KRh=YDqmUVVvA>17F z*2ICNRa-Av;r1=5$bTQln0hHuJI37Ue;<_IzPD!vJly{G@Zrf_{-=*U|MKIz62PAM zA09s%nDhU5a2Nmi;p~4*(=XKfPeB?-FRBhR1E7S8j#U@{!2Cg2u`l8C_w-zP(c+`0 zf@-95%nR{L6%ucjX^c5CoFLhiKAa>QqU#Eilf#80IFTj@FG_h_>iT<%z8HHp zQhKSrTLo)XE)yf3;Mdb0LOMMK`3z40AOz4sz|^%v2cJWyB9;(L`s!*Z5WYCFlHqt~ zalSKrcGWEpJ>J%a>c%$)?5HEI)aGTNK8Wp@ER4F1PjM1#Fac3cTTE%qeNR=(g8??W z!F@gDQ037L#hl#nNMoG$5mbGR9UilevmSl1&Qj<@v6D1PMknfnrt#%n$L}-+WND|aD92Y{9bBm-7rm}) zlJ&N1w48aZZRN2_1vLLO9l^X!PdILB`vSNryV8zgv~KRH!umdwe)UFxUMXO4=<$Q4>%CRyy1dOPt ztHDydR_lEEqEbbP_2jA=Uh8Y7s2bYWRYZTq`C&~OtmX`HIoj9v-8{+f%;au&NI zv{Lc(Xd@>&Ptq)$h-B({un529h7sN;)KH#^GuyW)rZVs#A_Dsi&O@@9NwHnw03DSX z=4=DNvf@N1Q{7f8-TpDpc5HjML!WfvndZd4M-_&Cv!miOLgQ_o5Wkg&3+0H|bV9VB z+{7VKp4Zd^0)}%k%UFZ~Rxr(QmXu*{a}5;kX>%t{%=pir)Ctoz#ZK)UYh5VIIJ};E zsJk(ySegaQitcz3KU$#*J&5y^S!5N0QQ~k*Vv%1h>Upi*=Zi|zF^1Dt#sw#CwjWj$ z`6U7^p}$HKoceep((8~ST5Wy6n59ZLW&zrmnIqZ)WJk4m_2Bo35{RibPNL~jkfAKT zSfQ<_E^=G5=x|7t5GrBdT9LU#iF2(+pPEXCQg-un6C8_()gXe*wjZDr>?-hV!Lapq z9BbUH`&aa@pg8>hrto`)OEREH9{K7>UviTOd5+(&m7X-k#u_C&jA>_8zEh47;ba z(yd$21l-@OF)_Ax|2}=S;>#^JqTCf;qKs_XAeLQHYACtGfX9*;R{V48ez<23{+SF$r;TN)1*L-U zN|?G`8wJ%>m7n2cv5tdT=(&9yYhj_-17Hjg#`fJ{3=zie-C!IejJJDW@Z14o2av~{ zkWGZbWHf^)L+NEFuCMM*?>V0e=*aunr{7|lW+F!Td+oL%Cni%KN=_n}p|KEcw*MTs zBb={Zi=sm;x@%SR7>mB$Q}i0cy*=jag1@_M5VFpSc>3ceND4Ucga>0LUxN5>$ZGp} zppuIIjXJPt)q}rL4>qm3@Hgthrd1#Qfkof6ns_-Cy>eC>NI*M2jVs3||DXT*KlaKb z+tAdGX&8ybSUnAfD zSjbd4e|7-pZ`TRV`rGy5hs%g}|OD(DqdEP8tR1`|&C*`tQNrh?;I)>{IYWON1LwG_Tvtv3t$B(sB zeUG7POuxIO)dFpUWV)#}Tf}KGQmpE=W|?oJ9PdiQIC&A@hm9)N-%9HMmMIxz5h1h1 z5akJl7Sx(ClFe#5TW?r&ZC#=J_sQnOo!c?4XU9z%dRj5I)?D`~;0NX_NTL-b_T(4+ zWB_Cy&RMwIVv~@bzEsy9YVklQBZ?FvE51rePb7FC5>!0GjN}+61jvlTGQQbEJRvEq zm%AKuc2fE`o(l~6JKxNx9=7Fc$c2`fNiU8rF!X?Y%Y#_&MZ(IE4FKz0B5CKsEFr8u z5=~?uKn5f*)uZ>&(I^WUge*wTLuoodhb;^K)VykDZna8&H8aN=vxUD2a%V=fIEMv7 zrpCo4j(0Wb)=X`C#0Olb6sKjx7}Io4ip6=ART6};TGlUohQg{+oJvV9CVaXgP zktuEB!twNaKEBG^tIrKKrp`YxFjddUqpk$XME5Y^pi)i5rwi&(b|)!YmC4#vOf$71 zZsTqqtu`^EHmv0GfIifxRx!fGFLm+z>vZk8ysETf*CPZ=PS3D{e;>cMq>J%rS{adh8S4EvWN; z!Meuy%Lt1`3LE2Z{kh=LWAQQUn`O0TGUic-2=zo@x#Gv@*P&3?QuS-!;#b6MxWui380+Y?R_VKR$T zH0ojp7DP;?Q+qi#t2JI~v)FlYUhplP%sc;)Zf*44eu|pu41gXb#1{G;Gv9DL#hnjZ zu~`tP+UL%RU4)%sx<>ckNkx#fm$r35f`K!6JiYE&>QX%@F|egkolQnZ!_$r$S&VaF zWq?gv4X=meVJz9hH=uvzXe2Um<3;QC;r?#SHsf0;Ej6y5~`H5+Ice zn0>F?t$>_|aS=?>T|RTWN->y*i*((R&|{Rj%TZqw*Z@~V7m>7 zA=F@CF(2H>A69Wm(Xio;2g4eTadcIwcSebKEWLvYr#A7TbO&%<+d{!EVEAh8+LsEi z>kk*z>eW$S0k~@)noI zC^AX_-6*IjMMM6+4g)gMR;JF_#};IY4Q*O@D|?wr!7a>KAL+v?$nJ$wOC372SsHIv zNt<5nrGOIX4TwOxIcjuJ+2fgeC6hFy6ME@x2=C$CZ{O@yF+rsDsfUEJz+s?%`tcup ziN1RT$e#RdMT}ck)wz|O+Pq?LtRtJH9X zR2wyB#B%0T-NSIrRNTW#w>|p6NTb`{L;n7KyVAB2Y-#gHXDjE19_gZG?#r#A2Trnh z{i;;N<~#x!qZmSYAqcN>KydFrQ2kP=^& zcNJR->dt|}7okasR@V;cVjCMOZvgRX)j>MgQex5d`haJ8;QV75GL}(t$kNdi@2(&) z4GI>$z2;t(y(vec^+|b5>K-f4Zt6$J%B=S{{O2%U<5H1!28A&-c0wh&zlRx!)Gwik zpt|o+Eo37-{N#4`Kq1n9xeV4Sj8>J{o~hO9GipLFT6oUtxk( z;JSFDoOI$>Fx}BFr+R^jyim8xz7TLs8JF3`FU>&CfT-IkNzxO@Su# zAf%KdQJd>jkLpbKQ8x-w_~z|LA)#Gej2xj>Ic16(Qq!>0v!^>Y4+|gXCB!M7-Sfk3=u%I_;=XhZd-!HrcK*7eW@7o8F#xVvxm3cLlub=U z4^G+0yQjhyo%5{7or>#3P82ABbu`nXZMt5BnV6)%2U(<^sg31=#Y_(}+tNM^Dl!1_ z$x}`7;ru+D)>7D4@b*vwtIRabGTtgBCYigss}tR^`X_nYJ1?`{4i9X&^m&3yty>{|1>!{1{?u`&t0-}iSUvu* zr?$;$_fU|*c0WkXn@>lI0lS=>AjTBpD?;4;`?OAaAcL}E*Bnt==@QYE@LUdj&4BH76FY+&{bZnf51wZ&oWHcUZ?Rcp@>Fz^>*q_H-9pHacJ5qLF(ByHI5h;v|xj%|S zSPNHxcWS_YRncE6^1RmARmbXJRuW@Z-Udh_h239n9{70?%r5G^=_ZYCWKbXHXv%dB z-d+zxoksYu_d70Y@>YKx4*B!5qTk)6K^kyta2=Pro9N`apRIz_B#8Kfe2vCD^W#$Jq@i6 zhz#!IisWlV%T-z;=R9Q%|L8BM0jB)f zgr(LGulLDv7#>MvJ?7aua$GrPcHg%0eN;J)GSGIPcJ8bMgzph(RnLp}$>X!O07xfU zX`PLD>~JKLtk1w2Z|rWk94}+FE47lW#DXWMv;=a1L|lPmpr!4=h>9x5U*ie`Wnev` zBsj;pD&otVp9o$9nn0@gIiiWJIxC*4f>j;nXz`WTWGnCZRoS|DRfl2%gT9dfn+&3)wri2Mz)I>I>1K_zS{Ef2%4MM-wP{t{ z@*+d64)<~&I}>)%#ii6!@TIq4j}(}vo#ttxhI$J0n<4XOw0drJlJ_pfmeam~kL zMz=d>Y--;3GOKUJvd(V5k(<(=I`szmDGbm~eO3}_M|?lM9c6%YJaE)4!zeMt62m>D z4s<+5$=@T0P^qf+rsaZuyU-qitc102Kz|(b@@=*oAvAlea*tQ--qz-o?+e6SxIElY zxl{_tQ~JN-m+PK$RZ{M?+wHV<+9E9U3ebJ2aWzVd7k|jxvvV*2=YW>h9h7Zz3)2-$MnBTsbbK$hlZHh8^jfe8NVcwyPZYJEZ*eNWjG~*9Fcz!ca~x$#Pwt0HkcL4EqbUiLGPdd z8{?Xii071~m*j*4(4+@w7GmUXr&A3j%*DlMB_fEeYH}*Zpy<0f^PMW&>FB3BE6b&MGUq_! z8+v(yY!v6C+k@tV2JXeA4lS7K6WUAWq{!?!>$(3NgSY6@OKPCo)pk8b@x+4|(OcIz z>zj|wdMq-zOI_rmvUs$gS+HeckEGiyP`GTXdwjJs$Q{+;AOo zS-y)^`eAZ)ZF7={S_ett04%_jpi&Hn&}-nWtLkC&zjDH*-}-nm($4+ z*fFGWF6Gz9#1VdFxp7%%pChwcsp_}j0vo8FeJoaNH*a5Z-L@p)a(~HdBil@sg3P<7 zs^sHUQr3_ULSDfM>k@5a#iNIMN7%sFJ9VwmyDWXvP_d|ghp&k0jOW{$=ewHcZ)=`! z>Hux(AZ;w5t~G*{JYo;QPRoMhveI7Hd$ksOLeVnp8NRLeuE&>U?gE8>)kxxHr)mJQ z*vJwlOraeVK=N1ND$RD&O&*+w9)TT`ybX}THGS;*`DW#HeT?wj6rtCUHG()v*|20G z)q{MM_1HzUy24`%yY$MnrbUly*sFjlPeXVCahT(>P5&D)k_ z@{`Q_B92Wm#>X{87xl*N`9hL%bs3;~N#oMw&b{7wmtFG?YK5JP>!`2wQ%e1c#D?j1 zah%#IvOluSOof7D&nZ+71nwcYiAzRh<0RP-rq1wyHF;-FD=IxXJ_elopc+pVMQ^2V z<#u8lW=-cXgVG1VoIsq4Hzls|Hqd6p+IvD;zWy-uwifiZexLNVw$j`B{h%(Ie-P9~ zbB;O?Y~CO05O@`J`1ICLXYN1-xAkl(B*yBoq-UI2h4eT!4kwm!ELD_oKCzTzd*RqT zqu5K*Hao8Fyn1Pp!^Y(qrDyKw41;40^}Px;F<}HgRT5T_S59@ecJ}SHdw1jav@>2F zv?o$*?GzRW>dffxlup3>Gn~p1%G=2Bc%9JU9oEZ)ViNd1Hz`jSJ>@K-M8H)H8?2q? zEO@$(OZ3*%n^tsltYE1~)xVo+(Y_TBDeYuMrdZX!R+O>>yMOcTF)T@iIDW63r%9Zi zs`EBkMyCzV>&Usv32$)xHr3$mz0mitNIR=k`cz?<%DX1Ec?0%YKM+&JD#-7~de-+$ z788X6iikx!77^vAr5C4nB=PPfQI{0@JPSCk^L8qcf+M_F? zI&m6^Dio5z=Ch!{I+ByP8+WNF9&!I}5;c6^Kkb@RUPpO9~;|zHo7s6T@Bo#Nyl!xxMALPXFsY5JcOK32wwJMcl9l}ku z0;)?z71H{8NpmZFG0Ycg*dxUs(4>${oSCSRqT;O6*QHSvJyXNq?Nr0ddQKr^#8T$# zDVpZ8l9C@2SXN+Sd`}GF{rmRx^s^B|6XF%kPz+6~8k=(b&OlE6tJ}466-iFUfGdTs z>s0@3y5KTrLNS3hm49ncdm%}U`+ithv>w{EErW&FIrI=qjpS%w3Q&C$RG9W$5GryI zq(C0;z_^2q2jP1RO9~BKXl>;}l+HiS?MhwFOL$&X(#3W<#>>g9Bmf2pAWClrdBo{4 zq;?H5o}%HfVkv1)mBK!WnAiK!sZIf3H^zz3pW<`iE_rmGc=zwiZfSY})hKB4RShM~ zGXjr3_?L4+o#_Wf5zLlCyY1nGkF@D&m@na30o)nu)m@*cp~7_5&|@#NVltELQpY$U zh9MlvbnASz5QdS=5v33o>O|cXs?|81k;Y$l(85;5o~3VB2u9zs%JE!x%v~ILA~i-k z0H$N47%{KPdH145M+@J0SVs{PlZv>fqN3uX(qxD7>52}qdE}l!9actwKZ==0dpyrl zOc6nq#~c-1tGu!|v86Mvs8_Unr~8#96<-dKMD*$cQ{!H0sYaF8y#HlRX8KxJn&l&f zk!opDOB8p_ip+zicvt^AX^*0dS2wFE#unCDrh@H=#TxogF!HeGevY#UM_nF?>&o$z zt~=GcLuDAcYsel43%sLkYu^C^w3Dvm!att{s-YV%Cf#hy1QcSzY}?0#?!{v_-jN0P z)Z}JjH1!U;o0mVLWh@R>XY&9gHNp{^JFQG@0%G7yVE|J26MF^7L(Wj=1b{IXr{5wp zUiMe(5%$rW1O42m&i$Ab-oWoWpUM~A#{4n@R~cccpo{SE_NO~+m3mx~cCh_18Bco7 zedzeyqxj64Ob+;`>+|2#`K>$9Cl&NqIrUdKC6^t;F09_QhdO66lp z)~6X>AN4dp6)+|Pz>dTJ1g6J&%DMw=CydAF zq`$s)E9l_9g`Ycp@*HK4Fyp!NKz|R2s5FVXh;2R#;&ALj+c42P<(tBK*Gt%yZh`M^ zr|-^D@n?5SaJIWC+X~oWU)7PesBKFX`cq-|l8w0A-CNgwVMTL0YJ0d;!vuIjB|4{^ z(Rx0ql+kz-GL5a<#1hTcb}d@lHMF*A+1$-H4vF`PoALWT*@c~_KixUVKI|OqX|8!c zGIyfwlnHQSWrVn`DXc;i*y#n-Rmb^&eL&l(vb(@1+Ff|N!Vy}2Mb>NVI;>Q z{Y(D}nDAd2O6z4XkCOAT8*GZyup?zbUW8fnHk^;kkQ{Sw=yhtX0?^xv&-_iYu9x?5 zSQ4*me)mj)rEOd7b6d+U{@l`A%Z|6paBWc|w8(c|-Uq5L+Ul(-Q-0-Doy!3~|5h(x zsZWz#Qh=T*TRv}-EZf##ZN6-^#nKtR>H}LD^+DOP%T{3K9S#9^%plo`%fjT{Ew;qf zQcICQAMuhCW;P>vxz=4+D_Zt97C|Xmr^~10-YagdWFGExl_pPbWGqvyw>QZbZ6i27 z>WQHxG!nVBNx8>$pO*WvYD}d+wz#hy8~#yArg>O0>k1WC5P@HK61xKo%y`siE;l*e zy6U-W%jN3b20y#c70;a0{R`nHY2!=UIV^L0rPaONE4yW=B>5r8xL1QNd9dt42iyc< zw4Y%J{O&;IGMh+E6c z@4x$tYv&NBt=U0WPp@22lksbE3lFypPa8N$w6+nRq8EUocbj5wr_p>{Gb^nDTlgNK z$3_yo*>qFrEl={bqS#VL%pA)_Zt=3$r(IhHXn8KXc@}6v=cO9-y<~(gm(vZBLYI{f z$_ouLz|(YtqLau4-J|FjkrY}O#p@z^>1EATmj~UPu#dki-1R>PQ_@q`?824xZIA=@ zgNZs~WLyVV8?DUzTMm_&EX}@RL53}wZIkrB(^_IFuNTk}LmoNRZa$U4U0P!BxEflf z3WUZo`%&Qt6?Tv3>`56TYwrWI8%uKJ{$SwXgK?U;pfTH+zLOtS!z zHHbrpZZ}rCZzFW>A${PUjkGUk)(>)2dUe51J0W~!V%ltGskjs@-1h-vu}n98-Q?{0QAYL;B=r<`W$d1ngR zLq&XSd#UI^N;-_1>M3d;RoyaW9ZX&IJ-6dVxQ-xC`4s5`4W;Eb_&w-44<0x}_Wb}y zYYy4$C^_q^EN<&MbXQ6FBy(-jgvK{^B`kP zH`w;bGSG9f6@JbTZ{vYK=s86+W+C~=Ncl&0&C}I2`hZT+V#B^*CHYmP{Ip!wLV^n> z`z&u`5yfIOV>cCm&3U#I#u5xDFEh>J85}!V^_8h4L3Y2zJg;2s>Vy$9XGIRh`>sSr z6yqZ5`UMY=n|NGTt=a6;Rd^maqcOuCiyd0$*_58U4FA6RE=$ki zaP>efL$N$vp8P<`u&ek!uA^kLre@A^uX;Hb!LG(TVI!<6ZJ2wyqnD&k)tVi&zN+~` zi6;FwL6*Q@y-V(QsTc^Mn&b;KREJrV&OzSTB=erLjzhd}hlGR0&Iz~cIGRO8Ol0<& zx{e;T_ap-EjWAxa=iD>Kz@A^fb}a^mdALfa8E2LizXS3C8M({IFF@~ysv}3?zpD{M*WZ(b&NmqScgxi7_IkJ~|n`Us37%RE;;OLURVT=wP zhCKS77d!M%KKk4xt#g`<1#@Hzh@PS9`oe`%Ui@Z^lf!*;JK`)y$p%==>Ji$@WRE`M z%AO-eKC3x*Ba-@l-8GDpA*rZH zHPv&JFQ;|467Ip0JwFLyuGiY~N!a+j5+n!6z^She6b3k~LRW`YJt6}Y0}U%>h>WWR z4lgGUZt^2{|Qv;pckDcRUE zgrlqBJlpRvR%kfNZu0>vh`FCxMSiZI!J!|UR9u5aS$xIIDu9N2009YNZ&i51CU~mp zA;eqSy$STThb^%y-A`3emeM;cy|a{VU^!fp^IxR#?mV@4ba^C&!dQ^-_y~D`>J}Y) z^V6>B6kAeTDT{J?8&CwYZHXa6sXpag|55c#5CdV1kq&4hCWHeAra8w{>_goLI5V3UjVX!oAkEI$63G6(LvYBbx#%0(y#zDC1bz0y-aHlNY1@ReO zvSMTuiQ?GeT+Q)uVmeoU90gJB`5$CuI85Dw_GjPue=zJ1O#RRCLeugm$^2V56Z551UiMC3k$OhT-LcLm&U#1t@5qVHlQat_S%{7B3x=fg{VPmO z#9nXiuvnw z?YZKyc4Wm^xLCxFwo_JRi#`;Z#~7mjUAY8O5E z4)5n!e5f!JMN-M|EU<7{mz_Mg#4B_YM{l-dr|G6xZwirTSj7%|!)zT?*QSAD z8-+aNn*=JFLw#V3HN6b8H(6AK7N*IX9Hxh+Rpaz^5XCHD1kvconJJebL+$~S*H7#R_nv$r|b1zT+hhbQ6VRFE@E#g=rT-7 ztnj{kwGCG5IMne=Uq1i*bA=FCBV+dga*_u{`hY#a6^c`o!QjWoeWrCSKsMv+&_$Ej z6f+XBrE_dMMZ@_nOmfV4=B|@-Qdq1oh=m@3C~vG*u|nM-iB<|<5TwWVmJ)OPfQ22J zLid5362Wsy-T@p#BXttJ?op+CJ?9>c<6igrzxuXfY;;iWxO+YKZ6)Lw5g3dTK)D^| zoXaOq%k5PK<4UZHPl_Pu9wljB%%j9rpULTQ)$H<_X9Hdqb&mU84K&T`l#O#gBr5Hq z$g2T~l$zRfsD);uOLYKobhaHndZ>+QmM!-8K_Ma+Z?MvO0s=F%JH;|_xK)8q`lHKJ z;25i*81FWh4~PAAZyn6XvoMOi=*@#+_x^CizAWjB*0UX5IA`gNq+yqH1+FC3Bjs%s z#ZKrFvtjhkYMh#sgP72>6R}q;fVxznvWje5a-Xt7m`Vp45!cA^s$5?Sc-+L8fTvtk zezuXNV8sS&V4dNVFHN>iNtsDkK}Zz`1LU*)YL?DJBViQp6T<`WBWLp0znoShx8!zc zD7h=Oal{CrS8Z87f;9u(R=R%w#$t)__TeLPu|WI9D4w#%kMY8&xATT9STxS1*cCl~kB1oM=##^Pk6LZu1bZa6J&E!sO56~J2A+or@ui%FiGo^5ZS^a%UY$Fz+*141JNv`NZk!yHVIwe;}K#ITiCMZQ|J;m0-lv|n-UJU z3eo`bvKHA8XRvfIf z!C)l8s}hbz&Xxt{a}Sytq;LY+hY!aqgPMs>0ygJ)I7^dKy5p=x9!8E`FS^R0#7ZU&p}?x(Y3v;~wsu1zBr>m2+lnVTxVvaT6Bmzd`t7 zThxPlz4B-~c*My_rUPKQ3h0-RCh@Z>T^a~L>Rhe00@7K)U+)9~uj4{3lXB7YJWkJo zm~iqWnZJZ3rlb@qA9_Vp$;4ak0+txrBHL9`HPTY8O-Mqii;6amn5-nT%y$jt1Z<+v z-9>bcx6x7$uOD1N=ldt~Yad1YYK2*x=4SFh>)CgUtPH3C{~%2QRzv%7n-;>zxeBlC zXKKEqi!eyRK`OXW6gaE351&A6M2ARDGi!F+EWCOFpFB~Tzx{;dLE@hCG|ZEG1q^}m z&9f7u6BQjL5Hrom;nSxwxknWhZ9DB1-m4FGb3Dp4K;n zuF*E?v0T2VifBibaU?9+*fhv@$;?w|4`49Cl0Z>=qP_^7BIyZbR#uS9j941hj>p@9 zR)2H%bLao3>i^MHiPF_A7yz2}{|_HMI(}I3{~SEN)Bk^nALUR~Ir6+LHfQ;G!8r0> zL&3f+w)!6SA~>GXF3moQGE8K}7u$?A45aCAim1Hv8^zh@`S96`G!B$9f_!~uzAE>9 z(|jS57tQl&K-$4H8`UKpV*Q!Ic>~1hOo-Cv^|R)C%vU8Vs;L_=)8JIkDy8Qmq#Tmr ze7cCjc%Cy=06##$zbZ@SA6xF_#lgMT!!GT&EOjmlI^{E#OBclD}`z`jN@uY>{7!7gTq>cQ1lQ&AfF;8y6lfu5&_Y4AS3|$spGM)6z_N6 zEYGtwGW>Y(hrDMzYO}`xc6%Czl`xERltJJP+18O{vFEJ09_wz;c|$%eV`vu9wgsR| z{mD}GV+gBPB?$Pa$3g-2JfDDg^uuX2C%5AJMt!K3_(3UAy-@+(3?lS^AVh!a{Lpp& zC`h(bje$ad=xgdM(6^M*R~^5`#CaFhR2@< zN5!@#I*XZ_JWEH!5_8y35cx2lur56u1)B~207j`lU;|dt;aFiP*)cAgdquof@6~0C zUM-a#T<+5q!W|iu&PG+Pr-bZ_{Z8Ya zGTOhXRQWf7h7k^|iE{Df=aNZSeU{I%FsO#;Czvhd7)bC3q{ZrMv@4KLF{9TbX8`}A zE)}l&+ijK29MNTW;pQ`eT7&62&DniZHJ;YQE#h<*6lpdV74eEJ{>)3Z;{kx0kaCoE)od+X5HZgijN$9gQ?3gF1^F*3gj2jdRh@A>Pn|cylY=t z-6P8b6zrC@HAp#qSQWC099RcMG$90NxN*ZDH$kl4>0Uu|CEa3~i4b-7q{T<8HuUNZ zw-O5JGj{?sG%$}788d}OEDy!pT(|{wm7Iisp@A9M54EjuR6Wq^L}4-elr}6XCu~X5 zuIEL<$P?i8hoW309eTRH^DJBhq{(E8VWrQMgn%%Ms*1)={0&W6Z>4351btgQ?_>DIF_QdPjUoU$e>(EbPot`B_bi(teA> z;?>9y>AZ=6lF;087CK=9jnBfl@BCG`>0u3M`cjO(G(^8Hd+?fH)hY~{wDYMwzeg&N`PYBWT@Y+MLMh`&XLCR(&jwvj%pLo$+0T&=QwP- z4{%^Vg-k`-Ue*@&ayppr$%bPzQh%|vE(cX$l{8ylNTJR8LM0K_mr;nVcgS7k`%yb= zkJ{m{6Sexb(R=swNUc^TtxmMfI7>7+r6_tXLCzY&4!L4}!1*7@uLv(GL{?0gXIZl6 zn^{UsYsK2#6$xp4I1LT>8~i-m~}+KqcPYLQ-z0;E(ISQ0679e$=L?h`56 zAstc@7yLE73^M&P8By?aGcf|36*LVD_j12rK1LTPX%Sc~=XFnQ96}jN?ft|WzA9Ej zS&XSTuu*JJIBf;V&YOUcPKPKjU-X;>PeZpb&Z3q}i%(k++|9eUr)vso8oO5QR<%o~ z9bI_W-(vwIW~~yG_FZb|3VgTQ>D0E!lk4lxEhu2jbHB7d{vZ3}@9d9XRUTh!28~6%rTG$u)q~%p z5%;X31`KU}%5HU2a#i)3%Hox8wPh;?c&LL{lj7};Uw!#M-@US=cwLcdpJrgfil5p} zIZ&+juvX5YfPf<|$A5@;S%p(8Un1UCD=5|@TsH{ph&3oVIOYA>Ck4~YLRq>=oAtGZc10lvCZyg+xl!85{6YdK22%2GNAE_<55@`*#f-K01v!$r8aP~NZ?ku+=(y;vSY zRp?cb-c?&B4qdyv1#@%~h_nKHol zodM;w;}9M=-T)1$%Cl})Nm<7%-&L3t4$473U@dFc5pll_%;I$H_dCYUZzCTre=zE) zlW=Sb$jYuNL>wm#`S;e^O< zSF?EIRu{uq|Eh1+!U7B#2jk#T{d8 z$7qa}uH?j1U6gEhy&}yeJ-P{8jZ{I5nL-D8P*L(G9E|qr2YU5i{Ef-OexOWPBdaR} zpHVBlF(=4zz1njJXNe0cl#eH;`*aHE7|MCYkyCnz9-)Wm=iKA(;685m^>KSpA9-_e zc#a%7PG@8HEX*k%i^z%R=Bpr%mB=dLQIc=g%qw)^B2T`etzAtcQG9<+^@;m<_fxWP0dm+aYgImwlPQS(X<_^Z97EcX1AUy8l9h@4#)I$Kz|*@ zm!q1E9tqGL5gk@X?;>n?OOs%G8*J$<95A%E*A2%py;C3gXr^}tk485*tQmcBlN8o5 z*(u8A?1U}z0`l`3CI=*xcRMwNVkr)DP%VyqnBvvBTKYky9(B@6-J&Yp9ER!Eg3R5E z&I#)`q7^^1DGvQ+#Vx8wVxW3Q((`(qDO-@^x)rIQdk`LB6hN)MQ|lw)2>ZyTI{%yW z{5yC?OLbgwrg5Dj+#E!{Th)&PP+csuFkjlHOTNTxU*#COHyFgr-Aat37F)8pvHZjo z@#d&eCzs^2AP&caeXblg&}9Gu_sW!p&I612YZ|N2eNYsSh(zG`sx&A;?CjRAR>4RJ z5oN#vX)2(riAgz-d=p*F%*l^S(#3~bl}xa$m)?^9~jl#VRCjKt4=Av&k&8Z z{T4Q97+f4uf*ialo?<#?akTO($9}fJ#x?t$*rWz^jBQZSVNH>8ZPx?O(r~eW`Fx{= zAZc4K+GAjY_6L*`OFsJC`Tg&IZxO;2fGA{RhWYe-(D!7`F5OXTuZW%R-@h+`*vI~0 z%u3tGZ+(lmDde!aiXfSxvdEkZ#81!UO*M-{AoFINOd~r|463#u%zRE9fS7c(wn$?S zZ&}uUiC<>gbCmCh>-y&TvaY=_qwcnhU5&2{G+bmslCLp6&t#XM0$Ux{SP)S{8f%=D zM5me-vmh_R49;M4OA=mnlOD_2Y31>B06~;|eh*F90W}iA6p5hG3apnV`l#_F;+tZx zc~dO$UQhy*{vEx+vNTz_4s35d3u;(R75b3l!SX>8w-)eCEsQLd` z-1BW*|FiG@-{GVFBlG^BlSg;=|9r&zfA%KSV~evI+0^TFtx5buw!NFA+Ixae$kwhe z%xcm-Dp`|uuPLR4af=ZR?FNY*?i&f2*oI)w)1)VIxSar3?hDuyxW>I5^BwdOy_Gv?SQU3@uctu1PfO<8`dHuZNZ} z4QXzN2GG{M9a=XOTOO%LJ?EifSl2}u+rWsl?+Z(i$T)Qy2*vK5&jPROmwTPZ)09-x zMHi@-oyNf~-N;1D{H$lY?m(sIhU>RfXYDS5O%aq$(US*9PBvW2#dv`|sIvPJ zvoF`~|7*NSaTbU9yUPH3_WwsGj~|=)e;+;^-tGS%;>WgGTb#c>TDDxeV7F=S-U?H( ztKJy2lTSD5Be++Tt}D0YYj$_yFU%Jv8?eU8U{97Z^?O1hxkLBMtuU>gk@5d=UiXSgAE z(itAv=jUN=^i{c)1m?pbkY{1>CJf1Eh-LYJ6F=Z}OG%P8c{ulVTDy54c8B(1XXyix zG4w&D%El~GtEgx|Ls6E&w&qA8D@p^!&KsPVe0^=)xc%Kbx6c+_?L{@B-O{aS~9w)aqvb8mxxi3G;RZSOE6>^EASD+P{DdJg{ISEPNFX9t8u zhjfM{j+R0w3$gFg`rgU+HD?A^xRg74z*~7ux}xhWY%>Rye(B9=Lh@vLs-ys+w)FQq z^?hT{2G7bJsnUho<8P0pd_X!OK=O2}(~En9ldZYjD`!~7R2!9w1Yl~ISg0Pw5VKDh zBg`078w-yWWOKFw_kHDR6v^$BwokZZS zH3D}xK;W((fjbj{yTcJEyF?$fgvLE*+H-hsr95Zmhp|kjwTnI4X~q*aVVqS>Pc5Ng za!UIY1>mvolfmfJ`INt$jE)A1W@Km7*r_#kY7Hf&vvC7;0K$B!lu&a&`{m~3S!l0k zL8oESNecf}uhZH#Xt`io?GEZon61LwR$lN7{=4qSzjmqq{LdT`-@pF)kQq)D%NKaP*3<0B`E;nNu8vAmnj#_*kzx1woWlM&Us9i)T0nK z7k8V^2_9ZSSY*-JM!6ob`6|gPT8($w$=6YGNi?;5edVO7;dz+qU$&j?+>pJ31 z_mpnoRSvk>^lB>`HR&7lsHgS)Q)h@^js`6Nd6(%W4| zD-Q9aE~Hzg@0u~SrEr7XDuhHcrcC+`6`?leXPv^6xlS<%B$X*fol%=}&xC57isR2K zJm`o+6k2eiMHJ2}Cn!B$K?3XY1C)d?eCCj7;8sT@8rEVNN`sUfA~}ULUNN8;Vi(0y zy;UAByeD7C-0%TmbYVPg9=qeMthCxd>_oCAjT`@*D&s+5ZjL08DB-E9n6!r(P~pH z+e1?4Vc(tG`12CWqddW@2vwGXMc?^~U9U}PzTy3AHlwerwCfv_-kjrH@K2`*;REWv zjoYnry>ph1D5Gucj$ntfB~0TFMP0TFy9mt{9Lr^wq*E4mpu$w-%I7y~i%z}HV2(HW zYr|iS-%e06UXEF&s)6M2-2H2#x6MHM`y#PmFj2cWX_iP2(^^!;Le?m%LSFRP}D*OId?Pnb-+PbyrlCFztF_S4}Z&peG8Gf=GM8 zQPjiC3A!RmPP<+~BE2V(Uh(TFtBz%%s!mHA2wq9e`hu1cej)V|Sx4pI#(L8|tw!`{ z?Mj|@*lK;AYt6Nz>zaY%Hmy}w@?IWn zKxUz!)+%~X!MJOZ&|;;@sOR+2kbGo3s)4oJ18Y!)W!%BVIjDDE7V=-I7}3Q&hDIjU z?n7pc;TlAfO%dKnUUtdrV0lZqc`suzbgYXt8}~C=ini_|JkMyKN_^)jmvYWh+A~~e z4JLBV#GSKXc0u2?-JO+Hhn24Xffq52KxPuRd0PANHJ???-3`J+a1k>st35f430iq4v4X9AO|FNB9eK%zW;gs1EeVGuq^_A_YP|i`F|I z5t?C#k)T83z!v%5Pw}OXC2q-;WHqHVb(Vs3 zolo4%mDZv?C1IwkMU~ui*dPxtL%R*-V5D9syW}=k-FXqSj6m`z@t`)|bg3hZy`H5x zy)FUmY5<9n&XE<6Xh*peEKAo_m+(pkaF)j$#bwMyLV5c10%w?3D4&KXuRt+NXs5e~ z;&@63gaUnAzHdgkU!%}bL$RJmdD?&i0GHCtcmF;OqiX`%wF0zj0K}DP6ANufX5fi# z_hh@Yq!k%}wyccFhU%WDC`;Arss&&sU@)N5#kTy24NQyWlwet9jeV?Qmcnyh2tRi$ z8>lY&$>+%TXv6DPH$1(HcedV+J}(fEb$DPqIETHOy*?#Uka)saR=;b69c0A5C%m=Oj#akTn%M3P5Oh-=ya%R)w=uxD=xW=s%Pv!QaXpcT zkbGjv(eP#&!O@s`%yWeFBsJD#xPp~Rfjc{UkS^{)~e3pB=A z5hO$J2uNy+`-HUU*xTUPql2kE$=sINwis&>?65mAZ#a?VcS`wPi}I`BTp8#kAL(WN zP`3AS{Q3s#fOF-!*%r6WW0oSFV(pD?dKR}4`B*3NE_3@^X@@bST%BS@ytL!&f z*B{>NXq0Cj7f(S#1bW5L*(e_yYgfHi1j}lwB!xYX%fpG4Gbsxi_O`yE4blP0gUudD zM-@;e5-Qh{6E+5%ddmJ_IepxVp;qX~UaGWj37ifmBQiZgDTwQx!if-JjJ6OVlkO%h80hr-$qY|aio`3I;c$E;Qk^go<6 zIqFjUJhTm*4=-#@tCzm2CsewWv~=MLLB^Yf$R@&hOWnD+C>d`=hU!P6y4EC~d5vc9 zG`jBu%QE6>z3OqTN-nOh)La~}D2^GE6{FBb^AjcK#bL|Ec_3T?Pghzol4$*TMERyGNVt2PNkhAp_A$ z8f;8coZzPTPV6X3zrITgvs;~37D&1gy|hA>KB}+%MtxPSiA+0@mZi#bsg}jPrc{wd z^$k)s_;qZ+SjW=>mexg7b(96r`c#H;i->tHH zO9gmLC*uA|x5BTjt^>cOT4a~kk-zJ7*vk)K4fAZF=#WHVy{3+YUI9ES^d zN|}4yC4hd5#{by0sLAvVz|wQ^t`arPIJ91ao>fXp{;U@kkDKKT47hMz`3Yi zoIOO0?-XorZAG`TsG2s|R#FtyN2rTg1{T$KP!lDmu0?XP)Z%zY@upkR4F_AFf)RfU z^Ubua(0$@lLJeCdtR58K^4=Z1U>u~IHECdhUc#ZLdDdapUXJ@N$){T0PBXW@;g?5= zx_V`@{cg25a3XeX1r*IEv(>3lg#7Ezg1I+ad3_^!0#6FY^MRo{W>wDFWe{r`ViB~l zh=ZaC)teZ2Ny9tU!^h;Ymv_771rr*D8P^_Vdb3i^K4qDvkL>R-X|)cA>C$al_y$P$ zvH~g_)OLw-Wgk(e?<*_ARH|gdW(c3|g-|R9^}`Xpz#%sS8SVk{>3$#?pX@BS4DmuS zB)`onK@HyQ!t(%GJsfY>AU0{*sHuko>`@QRnn}i!kz_`=5_4q5H=1dKb<%1~VNbi& z@nkl_F1roCYu+<0{B$66Y^3F5&fZDZ^)X9iu%;(H=ZJYYkA^*m{+u?$93BXBFxm_9 zxGhM8)e7Rn!ys11-Jk{%gvOOLwX3IB&n+fe#Fa*d9BQXFhOM$VdM(R}hMVqv{iV?~ z&Fn4GGt%De(Q*rD4-bJ>Gghv&Cr+-IN_+B2#R^;N%Y>5W(YCYKPYK&QDvbnil7ar? zavq^rMsY{o}>Z!>G-s3#uv7ze=I*e zwAZ(+Ql`%}R%3mbqGwBl$#XpEKzQy&_Q${|d$luODKpPAb_1@t2AE-;Nld*;tfd2F zi2Av)i*)DOTX|me868%69nLbTjwf2`u`HtUOxmOTpyI?? zP4$ZBT%mHS(o;<{|2+HL$pY{A7kB^V<@_&5H`G><-nh!rj{+Ge<$xo3nhpz%8>=n-zwC&UbkS-3ie(9OwrG0AL`C)cJhu zc*i|wFyz~b1xyMRVB-xt<*^XYDdMrmJn5C~NMwVi=duS`C_bgRErqT6$mczvH-!Yj zh#sGwt?TmLe2u0jIFWoqX|BsceBtG2 zg~W*rqN8R>I3Z^_){P2I*kk|87yORzFVKxQnsHRwL4Sp2sjnk-zlGgBG?L=8to3Uj z3$mV98rR->0tVmQtL;BZ`+Q)AmkIjet%zW+~+UDJ=eu{?dpS~OMuqa?IgDAE{wk&*l zg9w;POn8>NeuGRP2&!XEN=8YQMWRaUz0_>J5NQO$?j0Ru)RidtaT8@_M?7A;TYJea zRNQ-kxHiesO_mllHqgDv1=p3JqmzM7whPf56cQV8B~08hZ;ES%D|#*v~+ z6wGJEsEGmSw`^F}8?EuLH*x#|I>Hy6%kDhFtcJCg?8{FL%u|7pl)@sHR4l5 zN{)l{+<&?(qbxp$mB61`qdj<^xW~7BeKxI4s@Q6M!fZ{T0z;HonRNa)i4RIPQP`8B z$ZkelH5<+$G}n@fO151~MPj90j5t1~LBUdBh28}Vpu3>N0t!{h5#4cF)NV7(TP ztK#gJ3bP>6*~pox44z@4<^oOZ;l6wGx_f!YOLQZsojqmNjM*|6ML9p^^sq|;;L)#` zGtiDro*M7O4>}FvsKAdu3)WG=t~~8tJIWH5a_V`OZq}A{-r@@1maL_7<4!j5Aq$l^ z(Dm0S*zFNbRl>HAZmZMg4QRPW=+s>yU>N6NF(u8pH=|DO*>5GHr!zY}&#Z)u#c#UB zLEU%V;%J_nt62*I?RNGsXA-V!*1eTQUjbqjEHgQ5hD{@I#7-9aD>Suunft&0oDBXm z{Lk^}?_lO;%@P@nifNq`>Z>O@np#%=eUO%Ro$s>XH|jiEEJAVxV$gC@bIe0% zFM|@Ic>$wH(VZX?ZG^-o^354_Pv*sv{v!EBv|fkvDK)3;BOQAry(M}cKs|>75eYJx zjM6O8#W3TmK3c@IwWgV3nhJb!*nhmv-wix?dl1pRQCk+nM;lWIjGaGX@#u^!cpx&P z4h=tSGx#noo|oO{St5B|E+#0$lPA=Q{p3K4iJ8>kuj>#U8W~k%I`7oZE9NrF3 zQ>Zpy@$6c_j!rTH60~fJ%_$&1!5qe|9m|kCXekV9I^J>$BrY3f;b&$of{|lyRsB5> zSs0*$BJaLB_W?mgZ#7_YB%o1d=kN{PzI8Au&^+7ez$5`R4FyL|O-=clFEgXIu;AD$ z(<_nHQecEpA1+tlM0y<QS zdb;*R3i~WYE2Xlwq2#Aa(zHs;)4QJef-ho~hHpT0h`$!JrX#aZI&d@EGN_~lUA=sH=`HZ?6+Y?KS>Lc+?&PC zG9Qn6-i<#=z4ZP)mkrdm;l4KlR*_$g*=T|IL-?6aXe~(dr)XhPc^$iT)ev*&{3ipA+3O6xFrLURFl_L1|aajde}gr=?KFeKR7iA;~s}B24u@i^G=~HldO89^EjG zQ#YciG`QwqSvUp_6ZV^5=5{MEVeGGXX)xZbb2Ch6lV4-L#hdaLe!h;Q!gHr?cVdR` zlT)GeCT!weTv;zVi~4$ZEtK{h!@hNZrS|=9)HYMDN`++NWVgTldiHBs^nd_of9rg1xD?Hc;#^RzM;zZt72*^GYkhLgk%p66v zyO@!rzvn){h5KFVlzrp~(i}j_ECe|4YG4CZDR%|wEVIw8(Kve*nRPvCmO5r8{B>)~ zTbnbRPhJ{DSHiHgD5=t?@Y=tkS?hl`$B%R+AX~#Ee_Xq^W0i>bdWpAPyxUo-$pQ z(nZ79x9WEc`YSiJafJeFLj#MDhUuYRHXm`D&RXt`(3|`b=)wR`RjGeBY zAXm@rEL<1PUtbc-wuUQ7ysP;{bmtp;%awBFEh8dW)#^phe4Koq0|T~^r*v;1Hjn&F z@fz$gCm?dCDqQQxzM?;LMPcsL`aXv`9kR`_vK!I6D)TWY@7Rd{48jP0MC@!*}C zV#)n#m{5Z}sG{gb49IjNyJJAr$d`Rf_>P+x+~kI$wq5%DdzeLw-Am}Irj~vWhBQ4t z9c!0e0ULlYSbuz72A52yl+z4j?|vO-vUfgZmaei)9k=hW$x4mcHS{WzV#*dHA%YN7iLe|ohN(ing33&XRA#YjB-_GdlPcMoBE zR(g9=ND#w{9`8{-)=8}ZCtW%O*2c0~cp<49$)wSi6Yk?~q!%?MDxI~FjpjYGwp-*W z)ZP6|g;}27BU6#lO?6D=<}9OO5j8Y#EFO1Zc~`S)Dylh#y+&?`$q#8$#DtJlc}3t~ zj=tGqd=nm0j{?uhUBez7l5z;aZ+R8fFkbnF09rNw;O}6knE*gYIXzbP1f4G%TT;` zzy09dyZr?$$mYF^KGGSDNk0dzS?OoR`Ck;al6lZx%#Aj)a^3&pB%xbfyNZ`s-SS;$ zMLZQAZ^{y=cQ-6sEvZ{yYRbgEH-XAFG*hNp-&CeD22glEs?K};Q<|k8af(zLUN}E$ z*|pZLB}G?GGpk~KR4a{XOkD+HG(D=l^}AUxyanm6B^x|!{;Wb0CLOw-Ugf~2nrk$$ zT>EVAPd;%ABIC~#QKLo(howF=_pH+4_F%bFFf1G;so142C5*k5AZpp(p0V4n1)thu z>Su{k(=^sLyQj-=c7gtGblXEkO$kep-LWmlNm}urmZp-a7iTzqHDCryZqK|2rCcNCKd0>xV>Y+o)Ec6!rp3;hC zzZVw4|G&Lw?P?oYazE==^l|pw#Ti@X5hfYtGIxz_zwn-+3jlW4 z=Ci;P@<^(6T8GM8Wc>){E>RUcgpr6ksOoU*zG7o2OAk^y>| z3_h2v`dj6vcmf<2vL`+Yhi4FkGRQ9XuI8b(sR4!y{1#18cu?oh6;ga|@t9_MAS-{= z?B5SL-xKrut^)Ln`G6lM#5obx<*$s@P~gS1sYrbHu2z>6{0S*jzewKuQ)dQW4J~{I zB0iR=c5`X+)Kd7l^DrOnvdrNBocX=iYkxlX_d4_UpE2|I)3JO-!o}0FgwJKNENbS= z;G37u=a3wWJ_pOOJaD#uwp8Gsq_BU0^L&<#qtF;mJl|~?uDp|e6xZcwl)_zfANrB)!X-a2`9I$q(x2~NH4NM* zhDWIjEi?>}iWxVC~jyi5jKy}2Id>FFn+>H2@@wR!|J?!)c z*zNOKSCvTMPF$oDxJGX!naWc5{e9wPFl3Bt=Mo40_2uL0#R2D9L+Mu0Kfjvi;D14cj(C5Goy>!2Om{Z+(z@&6$?YgX;am9jBJ?uoZkoX~Imm|WkyN`vsWHw1 zA07havSLmc#Mu9jD$Dd$mFiYGa23?D&pn^U?(gkO0Ew# zyfOg=fj5ePSn)lG(u9k|73Pp11UpBn1U)YL5>chlDH*yzJK&>a5+dIYpfesQbOIXo zk|?BP{XZ6)`!)6`z^Vc$zX$c0YT>G#MC!K}>y9@ahcW_H%g)L6CO^`sz=hm*-wgxdH$$=x99EfWU+5lgKxz{^RH#ND)X=9y(~Gw2S0KzHbks zgr>5F;>Fm$!!F>`#@(WN?tXfR{7?X_<$J1MeHli=Nuo5Z>ncP#iE*vf)L=zm zqozsgdA?S1nRKJ@-(ZHKOB(A2X?V`yEC(0EaT0KwJ`Rs&c!_ykn-TWSh!fFwnDoCUxNc}V>p z)Cs|4V8SR&p0y@^mqmeJ11^*;UpXwxb0<8FVaq2r2P@Qi6JUfZu=K`@Nh<58dDKy- z$(tk!*f|%wZ?=CFP=un#r8zPM2%+Q25Ew+zXv0cz>u0Sfgt>(2y78lXn(DlUmfA=RJ7+UtvW6$n<$ zN$3Udcyl2ec3{Itzx8pBfIcCVB{^(DR5y1^Npjk8R)uutN}@ zP;djVt#!5ETmL)hwmPT%&dS^PjQ+R%`qkq3PoNWSul2vL@jK|Z#ZJBD+Y>a4cndO+&&0x`G`TMo+qB6%Xk%R)&rlz%?B{BSW!tlylM= zTcUt5&d=w)PQNeCdZPRG{G7d)`*F^WUb#l?}o*vZ%R3J{z2I8dqwmX1g zgR>eoYCQZ*oE?g{onGr0Zkq?)lkVUHb>y%+IK{ROp|PeoZ}tY=*2PJ)C(bW==V$$n zfMFT!ZohTX?7r=^O=ulj6rFdS(}Cz8H&0HMjuQJmH^zewbh3GH(lMwd7-hTL>$C7di=U7QcPXQx#d`Fj9M&uBH_(>6i(?39KI5IXC9z)BGY1pJzKf82rRJp?F0 zs)-=z1H@W`QZWPC0{{+6V-%;Iqm%AY=d{(q-kf1A@4Nj@73Qkj#{yk$_I(rDyr3cD z96_%Px-4OAjb>7G4@I;6u8ZAPg<WRfDiyCz~^qUj}(H!{&-E0=SetY~Sz zdQ&y*MU8v!)@zJdO{$ZVgLE4(rp60G`>LrTV|c(AfT9^5aGE>MhGCu0&by^Sfi~um zr9i8kR8gY}Vuxi}=@^Zyxe12e;d4-f0L~XUGQ;R&!eKOSq-^y?8zsR&jS@kDfkJ3J zQzt=^tqWcSD6m+#duplk_PAX(WaJ+1*|uR&E&DXLSbn2|dwPv5YT%1X74$MWwK4PY zo*?D@(emjya&F-R8pc5P51DU9_7xQK*pNee2FTx`momZR-kviSjvXS8w;jY71y(0Y z5}C#*#-I~^e!kV*Xb2@#>J$9E5PucZMDHE*>pTXIU(+7D7h?L~qU049#ZG34y`&}@ z*-sdhJ0XiM;dVy_!B7WhM|kZGy~jhIoxLoJ_)y#>Xcx zkyP~yN`00~GYF9LK){YjP)p=!f(9ZUd=0B{BmCL|Q6|hb@RO>A`LACfE_HbFQdqS< z?P_zJ_Xe3P0nJm-#(A+FS>=4%a}m_m( z2_+tvnpLW149#y;0i;y#|B9{6#qT|?U^g$j?DwMF9l*m~o)tB?)CV~j#X@YPZu3Th ztHxXocYS0O2OrHq+Tli}=<(wF@+hbKo96E0gDrK9kRRk>P+k1FMD-irp(PUJeJN5j zCfhoT&pfE*wHsyELm2SJ9Mlr=Qp|NQ5#Rk+dBc0IG~m@jad`5H^6`W6@wjRX(_hhT zX};N)FSo^ai*+w~7~?}ABxHI;Fp0!=fhO>VAZaZV$^Z=bv7txZ5ZGo_!G8A<48ym{ zKB2${hAY>gjw;MW1k1&Yoyd<8JtrU3It6VeDi$mDW--0|{Bq!RPmvT0&Jc*aIAd4q8`DpmjVL*oFX(HPI*2O z9s?aciBs##d0H_O8;UJCK#!wfegyMNak{uxrq#I-F-p>iOlr0~lFsyC3jMtcyl@|e zzPW|hHqsZobOJlxuN))?N1DGL(l(spX*hgY3@)&5rPywZcnmPF6KyBlUPAWrDlWIK zG-Z2)eCv`XRZCr;?pLtWv;E3s2LDe(AY&~4!x0;}4N%j|^)CfLs@oVZ3>m25oCd?B+tU&zlu=;; z7mUJHvPcY(*x^WSK*61o*PIO<1K|;bm3c481tdu0t4|GJAvNFgK3+)u=j>OK3Z+Dd zG0tF%-K{Faa-I=GcU@-JHm&rHEya%!$KT>KZXooQ;SkefmWHul9X_EG-X|d+JmZs* zl3W}7S-ypf5}e-5CgUU>0Iy77*%-G`9ucKYIi*Vs70tFmelL)UW&)_NK@xN+`7PR} zh_nu6>BuA?M^R63ny3f6*EI#}5V=$_@CiOy`6QQ`F-Sy#w(&-vTmsQb{ zR!JDcV_}pTjX`}SaU7_tMf#b=Glh-|3CQ(xqC!rne7(~QnjL27jczE*s+Jn!@hn{w z0c#2a(6QseIYt;P47IR*mf@-owM|io$Ng5UywqP%R=c61g{UdiN}Z_*CYe^5YE7+z z!?RL0|K8iOSpQ{((<7e&qS9O#y^S!ul>j+J>nbfenU06F6Yb(gaU7*&iDunhyUUP+ z1THyB*JPbSSMu-jT-X*o<#kF%e>yZEZ2)e~FaL-2(yIWbCBnv?Wz_w3+ z1~GLTFOH7S`hz}RO)aw!8W4|3JRC+3j;a!)#B*`g-=p$oGyd4nSs2krAoKb8RHcy> za%66gpQ9?ob7DU;M~=Oqf)t8U<|*DmEJKyT2S?DM2M^m38U<4QT?Q$5t}|(_l+Me^BT)RD@4_@ zWQfVVv2b3n0IpCnW|3azP7;luYS?U;YTJOpk)61P(PtN=e0E%PhI93MHv2HSgn?!@ zJC11ch~mv2A={0Yq?oS|`0`k{T2$ot9t`FYmMaW4L#e_Wx$#LuUO|^gFMd-TBUiML z$^?Of9xZH#$%$lM@gBLX>@^x&+pkTK!_2L{H?QBkZlFuUBn9f&@=+m*aytznHI5zK zfy6M0?x7WuN~2hY^BqvIZJl({nhSW5IvpidOD8o#lzam z%5GWIBU+&qTcY$EcHIX6=K4Kumre+b=GSt78!zunsJx{Sv>X!K#ZRKXYq5v}tit*Tgc2GCGFt3}+r>IZ0h&0b z#lukT&@e2NQ*N|u!XS%tE54c!lH7CjblJ;{Ax<9FBmjOnXrBU2viFuzg`EbK?-SJ9CxF!!HpO^v@&Bao?3hSrJVOy5(ogtow>5{T;R-7F zEs$`WrC|DaYK9{bQxr#zTy$xc6^h`_Q_I;&&-;q^-6WVQMhaQOZfo!X)J*Sz-6^fJemO|FHrDZDZkths*qiUu*^J7Jb8lN< zsqHN=q%}*KmSJ-H*(h$pxSGerIgMG@x>r?{*W4;o?~+?6Hc*Kl^xrFbH zR~*REK*P#bq*0kQyrlR~d3BWh$FOs^pEEtoylw7UO2`%q$db`|=^Ic-X7xnKuo*Q? zG0%@5VIa&-H;Q)ms*tw4jPJ4-T9*e4B8P>zRtG0qQY&~x5u7Ip(51tTB=h}LGYej8 zLgqsm>yPBk8sFc1)Wc&!aPo1Jy30ae zk+Blsw7qW=;j^`>$iAg`&+Egm3BvkKV$hQjDzUU@6E6xdZS38Jl0&U}H8~G;k2u8x zrWls!Uc&v}E7tK|^0gBlH>723cLeC`d!M$ErabXdL)AP@G`cS)*uq$a(oLlzpJ7cc)w?A+t zFjZ0Cw=XJW^FvGx+)&0fKjye{qFb13Nhaz$hi%Y5l?caOcOet9yOsLQ1Nc^DPmpiF zjJJde3)t!yRF!Sl6&(a7Xx{`Q>D`Sz+MB^^#!RI&dV*yYFdDsR!zjO$>V}h@fq9U1 zUU4Ki^L(nDg7UoHUSI~})%kbzDbteRw?k*1Pm!-`$xL!N7k7`<-i7TC6{Wg&OxudP z!Ttl$A-X?S6F(y7ER?=#Gj5z57d#>^#ka#KFM`Tab49<2WW5hl&qHUHA$Fa|JA5K~ zm^WrVA9C_C@y zz_|z@UU7r<&Zl#+>C7TBNDiPQNypedJMrU#`5EVrqen)iySarB2?6mAORp4-58no2 z+e?uI5fB>}%3i4GqZp79umS_Nj%B#1dG?Tl_Gt$%uO1WGTNkF%6pEI2OS1=~hRDID zxq8o`3wXCdlY0f+JHq}Q>%Ap^%ya+PTD#-W!c)R)g>(cTrS>`9>sXhZqH(ph?>&U^ zu4cQ9mMZLmFE<~m0g!dkfKi|eD=6HxOKXu4fjT;TvB|;QKJVhr#_|k%JYW15X=i2U zZ@PHt$Bot92aQ|Ay8W>gUUC0=Hg3BpnqjXnkZhUkaw$jvDoeU~wwh!7v!?*t@#%3* zAjKTC3Zi1ktq|JaknKj4k~QRySI)8!{onjM60Sw}H9bv++$Xb$jl#YdI#xHaBaI6T z7zLMy>I!0Zkk$(^c&b{!c3ET{x$Wt1%X}# z(@Cm5FHnb~X(RaZqE#+&7RV4z#!-DbAQ(Kdgesa1+Y?NJhCJ)2q7vaE8?(Q;X3=It z6%UMUL)fGPkYfzh>66{o4(m)Ys7S$wU?)N&Y8%{66VgSoTBwph*e?hW5aJ|RH|!Ant` zKNp_zl9YP`^7={hk)7*V3H7d>V>I-tXJc&5xWh=e&Pwb5!4TJ)@xAtg`s7v4fAi0v OSaSNJz+HkVCGjtX-HE&a literal 0 HcmV?d00001