From 04a1c2bb47c93796fe0e6c5f05e2ca2e88834b7e Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Wed, 19 Aug 2026 16:47:53 -0700 Subject: [PATCH 01/16] update references to tatc for version 3.5.0 --- pyproject.toml | 2 +- src/tatc_app/coverage/tasks.py | 3 +-- src/tatc_app/generation/tasks.py | 12 ++++++------ src/tatc_app/latency/tasks.py | 3 +-- src/tatc_app/overflight/tasks.py | 13 ++++++++----- src/tatc_app/tracking/router.py | 5 +---- src/tatc_app/tracking/schemas.py | 9 +-------- src/tatc_app/tracking/tasks.py | 24 ++++++++++++++++-------- tests/test_celestrak.py | 4 ++-- tests/test_cells.py | 4 ++-- tests/test_coverage.py | 12 ++++++------ tests/test_ground_track.py | 8 ++++---- tests/test_latency.py | 14 +++++++------- tests/test_orbit_track.py | 8 ++++---- tests/test_overflight.py | 8 ++++---- tests/test_points.py | 8 ++++---- 16 files changed, 68 insertions(+), 69 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 09a7da6..ce7af50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "geojson-pydantic", "msgpack-asgi", "python-dotenv", - "tatc >= 3.2.1", + "tatc >= 3.5.0", "tzlocal", "uvicorn[standard]" ] diff --git a/src/tatc_app/coverage/tasks.py b/src/tatc_app/coverage/tasks.py index b9b2505..6a8496c 100644 --- a/src/tatc_app/coverage/tasks.py +++ b/src/tatc_app/coverage/tasks.py @@ -10,8 +10,7 @@ import geopandas as gpd -from tatc.schemas.point import Point -from tatc.schemas.satellite import Satellite +from tatc.schemas import Point, Satellite from tatc.analysis.coverage import ( collect_multi_observations, aggregate_observations, diff --git a/src/tatc_app/generation/tasks.py b/src/tatc_app/generation/tasks.py index 7a28438..23b05f1 100644 --- a/src/tatc_app/generation/tasks.py +++ b/src/tatc_app/generation/tasks.py @@ -8,10 +8,10 @@ import geopandas as gpd from shapely.geometry import shape from tatc.generation.points import ( - generate_equally_spaced_points, - generate_fibonacci_lattice_points, + generate_points_uniform_spacing, + generate_points_fibonacci_lattice, ) -from tatc.generation.cells import generate_equally_spaced_cells +from tatc.generation.cells import generate_cells_uniform_spacing from .schemas import KnownShape from ..worker import app @@ -66,7 +66,7 @@ def generate_equally_spaced_points_task( Returns: str: GeoJSON serialized points. """ - return generate_equally_spaced_points( + return generate_points_uniform_spacing( distance, elevation, ( @@ -96,7 +96,7 @@ def generate_fibonacci_lattice_points_task( Returns: str: GeoJSON serialized points. """ - return generate_fibonacci_lattice_points( + return generate_points_fibonacci_lattice( distance, elevation, ( @@ -127,7 +127,7 @@ def generate_equally_spaced_cells_task( Returns: str: GeoJSON serialized cells. """ - return generate_equally_spaced_cells( + return generate_cells_uniform_spacing( distance, elevation, ( diff --git a/src/tatc_app/latency/tasks.py b/src/tatc_app/latency/tasks.py index 7948448..5a5f38c 100644 --- a/src/tatc_app/latency/tasks.py +++ b/src/tatc_app/latency/tasks.py @@ -10,8 +10,7 @@ import geopandas as gpd -from tatc.schemas.point import Point, GroundStation -from tatc.schemas.satellite import Satellite +from tatc.schemas import Point, GroundStation, Satellite from tatc.analysis.latency import ( collect_downlinks, compute_latencies, diff --git a/src/tatc_app/overflight/tasks.py b/src/tatc_app/overflight/tasks.py index b5f29a8..887d8df 100644 --- a/src/tatc_app/overflight/tasks.py +++ b/src/tatc_app/overflight/tasks.py @@ -10,9 +10,7 @@ import json import geopandas as gpd -from tatc.schemas.instrument import Instrument -from tatc.schemas.point import Point -from tatc.schemas.satellite import Satellite +from tatc.schemas import Instrument, Point, Satellite from tatc.analysis.coverage import collect_observations, aggregate_observations from ..worker import app @@ -37,12 +35,17 @@ def collect_observations_task( FeatureCollection: GeoJSON serialized observations. """ # call analysis function + sat = Satellite.model_validate_json(satellite) + if instrument is not None: + sat = sat.model_copy( + update={"instruments": [Instrument.model_validate_json(instrument)]} + ) results = collect_observations( Point.model_validate_json(point), - Satellite.model_validate_json(satellite), - Instrument.model_validate_json(instrument), + sat, datetime.fromisoformat(start), datetime.fromisoformat(end), + 0, omit_solar, ) # serialize constituent data diff --git a/src/tatc_app/tracking/router.py b/src/tatc_app/tracking/router.py index 3137c10..3ace33e 100644 --- a/src/tatc_app/tracking/router.py +++ b/src/tatc_app/tracking/router.py @@ -129,11 +129,8 @@ async def enqueue_ground_track_analysis(request: GroundTrackAnalysisRequest): [time.isoformat() for time in times], request.elevation, request.model_dump().get("mask", None), - request.crs, - ) - for times in np.array_split( - times, max(1, len(times) // (100 if request.crs == "EPSG:4087" else 20)) ) + for times in np.array_split(times, max(1, len(times) // 100)) for satellite in request.satellite.generate_members() ), merge_feature_collections_task.s(), diff --git a/src/tatc_app/tracking/schemas.py b/src/tatc_app/tracking/schemas.py index abea45a..54eac3b 100644 --- a/src/tatc_app/tracking/schemas.py +++ b/src/tatc_app/tracking/schemas.py @@ -13,8 +13,7 @@ from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel from shapely.geometry import box, mapping -from tatc.schemas.satellite import Satellite, TrainConstellation, WalkerConstellation -from tatc.schemas.instrument import Instrument +from tatc.schemas import Satellite, TrainConstellation, WalkerConstellation, Instrument from ..generation.schemas import TimeGenerator @@ -75,9 +74,3 @@ class GroundTrackAnalysisRequest(OrbitTrackAnalysisRequest): """ User request to perform ground track analysis. """ - - # TODO add validator for crs - crs: str = Field( - "EPSG:4087", - description="Coordinate reference system for which to compute ground track. (Note: `utm` uses Universal Transverse Mercator (UTM) zones).", - ) diff --git a/src/tatc_app/tracking/tasks.py b/src/tatc_app/tracking/tasks.py index c8194c9..f08a094 100644 --- a/src/tatc_app/tracking/tasks.py +++ b/src/tatc_app/tracking/tasks.py @@ -10,7 +10,7 @@ from shapely.geometry import shape from tatc.analysis.track import collect_orbit_track, collect_ground_track -from tatc import schemas +from tatc.schemas import Satellite, Instrument from ..worker import app @@ -32,10 +32,15 @@ def collect_orbit_track_task( Returns: str: GeoJSON serialized orbit track. """ + sat = Satellite.model_validate_json(satellite) + if instrument is not None: + sat = sat.model_copy( + update={"instruments": [Instrument.model_validate_json(instrument)]} + ) results = collect_orbit_track( - schemas.satellite.Satellite.model_validate_json(satellite), - schemas.instrument.Instrument.model_validate_json(instrument), + sat, [datetime.fromisoformat(time) for time in times], + 0, elevation, shape(mask) if mask is not None else None, ) @@ -46,7 +51,7 @@ def collect_orbit_track_task( @app.task def collect_ground_track_task( - satellite: str, instrument: str, times: list, elevation: float, mask: str, crs: str + satellite: str, instrument: str, times: list, elevation: float, mask: str ) -> str: """ Task to collect ground track. @@ -57,18 +62,21 @@ def collect_ground_track_task( times (list): List of ISO 8601 serialized times for which to compute orbit track. elevation (float): Elevation (meters) above datum in the WGS 84 coordinate system. mask (str): Optional GeoJSON serialized mask to constrain points. - crs (str): Coordinate reference system (CRS) in which to project ground track. Returns: str: GeoJSON serialized ground track. """ + sat = Satellite.model_validate_json(satellite) + if instrument is not None: + sat = sat.model_copy( + update={"instruments": [Instrument.model_validate_json(instrument)]} + ) results = collect_ground_track( - schemas.satellite.Satellite.model_validate_json(satellite), - schemas.instrument.Instrument.parse_raw(instrument), + sat, [datetime.fromisoformat(time) for time in times], + 0, elevation, shape(mask) if mask is not None else None, - crs, ) # serialize Timestamp results["time"] = results["time"].apply(lambda t: t.isoformat()) diff --git a/tests/test_celestrak.py b/tests/test_celestrak.py index 7f850a3..62695e4 100644 --- a/tests/test_celestrak.py +++ b/tests/test_celestrak.py @@ -1,5 +1,5 @@ import warnings -from tatc.schemas import TwoLineElements +from tatc.schemas import GeneralPerturbationsOrbit from .base import TatcTestCase @@ -36,7 +36,7 @@ def test_get_tle_valid_user(self): response = self.client.get("/celestrak/tle?name=zarya") self.assertEqual(response.status_code, 200) self.assertEqual(len(response.text.splitlines()), 3) - TwoLineElements(tle=response.text.splitlines()[1:3]) + GeneralPerturbationsOrbit.from_tle(response.text.splitlines()[1:3]) def test_get_tle_empty_response(self): # ignore warning for unclosed socket diff --git a/tests/test_cells.py b/tests/test_cells.py index bf61547..e41573b 100644 --- a/tests/test_cells.py +++ b/tests/test_cells.py @@ -2,7 +2,7 @@ import geopandas as gpd -from tatc.generation import generate_equally_spaced_cells +from tatc.generation import generate_cells_uniform_spacing from .base import TatcTestCase @@ -18,6 +18,6 @@ def test_generate_cells_equally_spaced(self): json.loads(response.content), crs="EPSG:4326" ) gdf = gdf.reindex(columns=sorted(gdf.columns)) - tatc_results = generate_equally_spaced_cells(5000e3) + tatc_results = generate_cells_uniform_spacing(5000e3) tatc_results = tatc_results.reindex(columns=sorted(tatc_results.columns)) self.assertTrue(gdf.equals(tatc_results)) diff --git a/tests/test_coverage.py b/tests/test_coverage.py index 7ccf99a..80c9762 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -11,8 +11,8 @@ reduce_observations, grid_observations, ) -from tatc.generation import generate_equally_spaced_points, generate_equally_spaced_cells -from tatc.schemas import Point, WalkerConstellation, TwoLineElements, Instrument +from tatc.generation import generate_points_uniform_spacing, generate_cells_uniform_spacing +from tatc.schemas import Point, WalkerConstellation, GeneralPerturbationsOrbit, Instrument from .base import TatcTestCase from tatc_app.coverage.schemas import CoverageAnalysisRequest @@ -30,8 +30,8 @@ def test_analyze_coverage(self): distance=5000e3, ) instrument = Instrument(name="Test", field_of_regard=180.0) - orbit = TwoLineElements( - tle=[ + orbit = GeneralPerturbationsOrbit.from_tle( + [ "1 25544U 98067A 22171.11255782 .00008307 00000+0 15444-3 0 9992", "2 25544 51.6448 322.0970 0003980 282.3738 231.6559 15.49798078345636", ] @@ -74,7 +74,7 @@ def test_analyze_coverage(self): point, satellite.generate_members(), start, end ) ) - for point in generate_equally_spaced_points(5000e3).apply( + for point in generate_points_uniform_spacing(5000e3).apply( lambda r: Point( id=r.point_id, latitude=r.geometry.y, longitude=r.geometry.x ), @@ -95,7 +95,7 @@ def test_analyze_coverage(self): gdf_cells["revisit"] = gdf_cells["revisit"].astype("timedelta64[ns]") gdf_cells["access"] = gdf_cells["access"].astype("timedelta64[ns]") tatc_results_cells = grid_observations( - tatc_results_points, generate_equally_spaced_cells(5000e3) + tatc_results_points, generate_cells_uniform_spacing(5000e3) ) tatc_results_cells = tatc_results_cells.reindex( columns=sorted(tatc_results_cells.columns) diff --git a/tests/test_ground_track.py b/tests/test_ground_track.py index a4c749f..82230e3 100644 --- a/tests/test_ground_track.py +++ b/tests/test_ground_track.py @@ -5,7 +5,7 @@ import geopandas as gpd from tatc.analysis import collect_ground_track -from tatc.schemas import Satellite, TwoLineElements, Instrument +from tatc.schemas import Satellite, GeneralPerturbationsOrbit, Instrument from .base import TatcTestCase from tatc_app.tracking.schemas import GroundTrackAnalysisRequest @@ -14,8 +14,8 @@ class AnalyzeGroundTrackTestCase(TatcTestCase): def test_analyze_ground_track(self): instrument = Instrument(name="Test", field_of_regard=180.0) - orbit = TwoLineElements( - tle=[ + orbit = GeneralPerturbationsOrbit.from_tle( + [ "1 25544U 98067A 22171.11255782 .00008307 00000+0 15444-3 0 9992", "2 25544 51.6448 322.0970 0003980 282.3738 231.6559 15.49798078345636", ] @@ -43,7 +43,7 @@ def test_analyze_ground_track(self): ) gdf = gdf.reindex(columns=sorted(gdf.columns)) gdf["time"] = gdf["time"].astype("datetime64[ns, utc]") - tatc_results = collect_ground_track(satellite, instrument, times) + tatc_results = collect_ground_track(satellite, times) tatc_results = tatc_results.reindex(columns=sorted(tatc_results.columns)) #TODO perform more comprehensive verification self.assertEqual(len(gdf), len(tatc_results)) \ No newline at end of file diff --git a/tests/test_latency.py b/tests/test_latency.py index 97c4d70..863acd8 100644 --- a/tests/test_latency.py +++ b/tests/test_latency.py @@ -12,12 +12,12 @@ reduce_latencies, grid_latencies, ) -from tatc.generation import generate_equally_spaced_points, generate_equally_spaced_cells +from tatc.generation import generate_points_uniform_spacing, generate_cells_uniform_spacing from tatc.schemas import ( Point, GroundStation, WalkerConstellation, - TwoLineElements, + GeneralPerturbationsOrbit, Instrument, ) @@ -37,8 +37,8 @@ def test_analyze_latency(self): distance=5000e3, ) instrument = Instrument(name="Test", field_of_regard=180.0) - orbit = TwoLineElements( - tle=[ + orbit = GeneralPerturbationsOrbit.from_tle( + [ "1 25544U 98067A 22171.11255782 .00008307 00000+0 15444-3 0 9992", "2 25544 51.6448 322.0970 0003980 282.3738 231.6559 15.49798078345636", ] @@ -93,8 +93,8 @@ def test_analyze_latency(self): ) tatc_results_observations = pd.concat( [ - collect_observations(point, sat, instrument, start, end) - for point in generate_equally_spaced_points(5000e3).apply( + collect_observations(point, sat, start, end) + for point in generate_points_uniform_spacing(5000e3).apply( lambda r: Point( id=r.point_id, latitude=r.geometry.y, @@ -119,7 +119,7 @@ def test_analyze_latency(self): gdf_cells = gdf_cells.reindex(columns=sorted(gdf_cells.columns)) gdf_cells["latency"] = gdf_cells["latency"].astype("timedelta64[ns]") tatc_results_cells = grid_latencies( - tatc_results_points, generate_equally_spaced_cells(5000e3) + tatc_results_points, generate_cells_uniform_spacing(5000e3) ) tatc_results_cells = tatc_results_cells.reindex( columns=sorted(tatc_results_cells.columns) diff --git a/tests/test_orbit_track.py b/tests/test_orbit_track.py index f986073..a97fa86 100644 --- a/tests/test_orbit_track.py +++ b/tests/test_orbit_track.py @@ -5,7 +5,7 @@ import geopandas as gpd from tatc.analysis import collect_orbit_track -from tatc.schemas import Satellite, TwoLineElements, Instrument +from tatc.schemas import Satellite, GeneralPerturbationsOrbit, Instrument from .base import TatcTestCase from tatc_app.tracking.schemas import OrbitTrackAnalysisRequest @@ -14,8 +14,8 @@ class AnalyzeOrbitTrackTestCase(TatcTestCase): def test_analyze_orbit_track(self): instrument = Instrument(name="Test", field_of_regard=180.0) - orbit = TwoLineElements( - tle=[ + orbit = GeneralPerturbationsOrbit.from_tle( + [ "1 25544U 98067A 22171.11255782 .00008307 00000+0 15444-3 0 9992", "2 25544 51.6448 322.0970 0003980 282.3738 231.6559 15.49798078345636", ] @@ -43,7 +43,7 @@ def test_analyze_orbit_track(self): ) gdf = gdf.reindex(columns=sorted(gdf.columns)) gdf["time"] = gdf["time"].astype("datetime64[ns, utc]") - tatc_results = collect_orbit_track(satellite, instrument, times) + tatc_results = collect_orbit_track(satellite, times) tatc_results = tatc_results.reindex(columns=sorted(tatc_results.columns)) #TODO perform more comprehensive verification self.assertEqual(len(gdf), len(tatc_results)) diff --git a/tests/test_overflight.py b/tests/test_overflight.py index 6982b35..8339326 100644 --- a/tests/test_overflight.py +++ b/tests/test_overflight.py @@ -5,7 +5,7 @@ import geopandas as gpd from tatc.analysis import collect_observations, aggregate_observations -from tatc.schemas import Point, Satellite, TwoLineElements, Instrument +from tatc.schemas import Point, Satellite, GeneralPerturbationsOrbit, Instrument from .base import TatcTestCase from tatc_app.overflight.schemas import OverflightAnalysisRequest @@ -15,8 +15,8 @@ class OverflightAnalysisTestCase(TatcTestCase): def test_analyze_overflight(self): point = Point(id=0, latitude=0, longitude=0) instrument = Instrument(name="Test", field_of_regard=180.0) - orbit = TwoLineElements( - tle=[ + orbit = GeneralPerturbationsOrbit.from_tle( + [ "1 25544U 98067A 22171.11255782 .00008307 00000+0 15444-3 0 9992", "2 25544 51.6448 322.0970 0003980 282.3738 231.6559 15.49798078345636", ] @@ -49,7 +49,7 @@ def test_analyze_overflight(self): gdf["revisit"] = gdf["revisit"].astype("timedelta64[ns]") gdf["access"] = gdf["access"].astype("timedelta64[ns]") tatc_results = aggregate_observations( - collect_observations(point, satellite, instrument, start, end) + collect_observations(point, satellite, start, end) ) tatc_results = tatc_results.reindex(columns=sorted(tatc_results.columns)) self.assertTrue(gdf.equals(tatc_results)) diff --git a/tests/test_points.py b/tests/test_points.py index 63684e9..06544dd 100644 --- a/tests/test_points.py +++ b/tests/test_points.py @@ -3,8 +3,8 @@ import geopandas as gpd from tatc.generation import ( - generate_equally_spaced_points, - generate_fibonacci_lattice_points, + generate_points_uniform_spacing, + generate_points_fibonacci_lattice, ) from .base import TatcTestCase @@ -21,7 +21,7 @@ def test_generate_points_equally_spaced(self): json.loads(response.content), crs="EPSG:4326" ) gdf = gdf.reindex(columns=sorted(gdf.columns)) - tatc_results = generate_equally_spaced_points(5000e3) + tatc_results = generate_points_uniform_spacing(5000e3) tatc_results = tatc_results.reindex(columns=sorted(tatc_results.columns)) print(tatc_results.columns) self.assertTrue(gdf.equals(tatc_results)) @@ -36,7 +36,7 @@ def test_generate_points_fibonacci_lattice(self): json.loads(response.content), crs="EPSG:4326" ) gdf = gdf.reindex(columns=sorted(gdf.columns)) - tatc_results = generate_fibonacci_lattice_points(5000e3) + tatc_results = generate_points_fibonacci_lattice(5000e3) tatc_results = tatc_results.reindex(columns=sorted(tatc_results.columns)) #TODO perform more comprehensive verification self.assertEqual(len(gdf), len(tatc_results)) From 1e6e3dfcf6f728c12997c5f5634dcad4370dccef Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Wed, 19 Aug 2026 20:39:30 -0700 Subject: [PATCH 02/16] fix removed geopandas datasets --- pyproject.toml | 3 ++ src/tatc_app/generation/tasks.py | 31 ++++++++++++++++-- .../resources/ne_110m_admin_0_countries.zip | Bin 0 -> 214976 bytes 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/tatc_app/resources/ne_110m_admin_0_countries.zip diff --git a/pyproject.toml b/pyproject.toml index ce7af50..ebae789 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,9 @@ Issues = "https://github.com/code-lab-org/tatc-app/issues" [tool.setuptools.packages.find] where = ["src"] +[tool.setuptools.package-data] +tatc_app = ["resources/*.zip"] + [project.optional-dependencies] dev = [ "black >= 24.2", diff --git a/src/tatc_app/generation/tasks.py b/src/tatc_app/generation/tasks.py index 23b05f1..841f721 100644 --- a/src/tatc_app/generation/tasks.py +++ b/src/tatc_app/generation/tasks.py @@ -5,6 +5,10 @@ @author: Paul T. Grogan """ +import io +from functools import lru_cache +from importlib import resources + import geopandas as gpd from shapely.geometry import shape from tatc.generation.points import ( @@ -17,6 +21,19 @@ from ..worker import app +@lru_cache(maxsize=None) +def _load_resource(filename: str) -> gpd.GeoDataFrame: + """ + Loads a zipped shapefile bundled in the `tatc_app` package's `resources` + directory (declared as package data in `pyproject.toml`), independent of + the process's current working directory. Cached since parsing a bundled + shapefile takes tens of milliseconds and its contents never change + within a process's lifetime. + """ + data = (resources.files("tatc_app") / "resources" / filename).read_bytes() + return gpd.read_file(io.BytesIO(data)) + + def load_country_mask(iso_3166_1_alpha3: str): """ Load a country geometry from its ISO 3166-1 alpha-3 code. @@ -27,8 +44,16 @@ def load_country_mask(iso_3166_1_alpha3: str): Returns: Union[Polygon, MultiPolygon]: the country's border geometry """ - world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")) - return world.query(f'iso_a3 == "{iso_3166_1_alpha3}"').to_crs("EPSG:4326").geometry + # `geopandas.datasets` (and its bundled `naturalearth_lowres` sample) was + # removed in geopandas 1.0, so this dataset (Natural Earth 110m admin-0 + # countries) is instead bundled directly with the application. + world = _load_resource("ne_110m_admin_0_countries.zip") + # `ISO_A3_EH` (rather than `ISO_A3`) is used because several countries + # (e.g. France, Norway) have a placeholder `-99` in `ISO_A3` due to a + # long-standing Natural Earth data issue. + return ( + world.query(f'ISO_A3_EH == "{iso_3166_1_alpha3}"').to_crs("EPSG:4326").geometry + ) def load_known_shape(shape: KnownShape): @@ -42,7 +67,7 @@ def load_known_shape(shape: KnownShape): Union[Polygon, MultiPolygon]: the known shape's geometry """ if shape == KnownShape.conus: - usa = gpd.read_file("resources/cb_2020_us_state_20m.zip") + usa = _load_resource("cb_2020_us_state_20m.zip") return ( usa[(usa.STUSPS != "AK") & (usa.STUSPS != "HI") & (usa.STUSPS != "PR")] .dissolve() diff --git a/src/tatc_app/resources/ne_110m_admin_0_countries.zip b/src/tatc_app/resources/ne_110m_admin_0_countries.zip new file mode 100644 index 0000000000000000000000000000000000000000..aca6ab277f9479ef47d16c49656efcc83c639717 GIT binary patch literal 214976 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�ATd+KvJArJq-1JzChml`1bv5`20x-v6%oP=mViEW^uSISB8grL!fg|yV`h8ywNXIYoPdtkv?b-K=-tm$H-{(FM^1NO4 zglqlOgaW)ho(%KI#)4`13MJ!$KfWOer|0*gQ&3HVTx!r5GVh5Z1{`naF&7?|C?s|A zp2SyYcknjk1dxmOk~GnypA{}^tG6H}8UwQfnz^_@#Rq&CHSxRn;!uY!L zA^dr0bP=iafchPTUt;wQN+usyu+P8?u=cEjg(b^En+wR(>$PnJOu6?th7d2>wa#qc z>;3G+Zu{}I_S!XK9dU^IM#@nm^v+VZST*9#SEEKm{NEu3E9(ivj?D&Lfac55vMfDZ zaS9(u?e_>{afHG5WjH|D1arDj=5f3|&O;tA0hDie8hbzOY6$YMpe?c!JTqAwB~FqE zlc2z7nFlbdhGhj)2<1j~3D&Zw*!)KUlYW%hZA9^?nK=9{nv2cTmCwP-XD?mtKGa?v{8ah2;hOxOpHqA;!?op1@+*>^8{Q)&I``J?M66GhVCJW=xdrEAO7x-jf@m}h z6kt!tRbp!h&a@Ec^urL)waE`wxxIj{KA6(Jlo`15@L_X?fh%^S6EmOiFk@CL=}%2S z9ehb!6awVA@ZRt6c;HJh1fQPYIYLt7@3QRq*jvjUls?xyw>woe9Q~)QKT()jrRF>T zkFwOUCmonxTWO_GMNs0i(#zCJ#JBiaDD#(#Uk~nvY}R{k(JD+nufkD? zVPm69_ozEZHmph>_>;@XD-4l1_I`4nvwI{o`+*$&4|La>d^dt!eHk>I6_ajvyD+uyQmATbDMoMmyECUg2i zuCW9qTd<{-n!}uPacH%Ids8;PCV=38=NJKC@$=UI_pV(`n=XmIzvBql4IKsK{QMq8 zec4leIO(WWCzircL}Wje}e`UN2KTqZyDtMq7Bu=;w$w;>u-A z2;K)`P0_HL1asL!OoFi9Plolg3!Lg)JjsYH^F;53LmvO<#Si)S2>O%GIY|cXwNGsI(pdCSO!`D zQyqHQk3{jgp}6|9VxJ(j;b8HAFRRa^Uu**nv-~TOWz_w#E)rh+ z9+T$YI`P6R0OBtf{aDQNY$Yw#K8J;Rpe%i^Gl^wAunJr*NWn;x%I0`HPqm{6yR@%4 zCqe#_7yl)ih#CPgIDH%%^-EujfMn$mmx#U%n?pi+P4`$ghB;@zQcQFRe@Ihs4ASc+ znADNkL30x&u2u~kf7^2_3b!Y6ixn0T(q!6U=Ed~j$G@0&#NQYf{islYrM+*{25NBp za-;e{5-qV^^G-#3{+(Dhy}l^g4D3LWnXMHI%dtptHxFMswz}x@?Y^A(&vhr!v-_#B zRTAya$IYIpseySR2ou`UhwadTL!7?>k`zcD`eAwQ;##5A)BC2&;QvcSxtMGXvXeZL z|Eni`{yR*@O8T-0@L=X1NzYr*0@&6qgzPEef+V}T6XQ@_nofm#0kCUdneiWw|k?Msl+Sa3Pp(I+*3y<27e&$znwDo{Qw`{=eNITpx^cw#;qsC3qoiVJgmd2AN zbmc4j7Pjk}n(JJ`W399kg92MY@oB;?U!&~l zA-GhAyb+!6j(A5;ArLqzl76%jcY(MXM=?JdA~(K|D#O*bPexnx&bk2g^~9uupx7rK zggxksXenV23&C;rKzFR$V_f^bnRn}+=kiW??je+Q`SS@V2^|O}J}kb8)!EKB$67;6 zr`=0Z>r1dj3m-XUGYN~AgDBB2rSr1STb=pSJZ$tam{E2$(JouZ9#3~1)aq?!@?pnX zaRapM#a{d7Rv#|kbF^YhVzyyV^jjBqgO;&;W}gm+FJ6kAT(4_6)c~NLY6x4@@h(V28!NR*rt3S!tk^GZ#}IIWu+{sPutE8R9wKy za8>YW>O7!`J$Jj@BR%EMuq17h?<~M5-7#_7AptYNz^71Awh$O!^OtA-M~{1pFI9To zE4!7xg&(cFCXBD9d%>G3nvplmD+hOBu|hOWfYV$qR^M z$&)qn-(x>FPP%D@-(wizgYsN7<6|A+VoNs6n|20xXqOBpA-Z>%wJ8mkE^!H1D z%;)J|aRLx`HUn>bw!o{=3pRe|8c+MT4`Cq|k*30@V~S*CS6Q~QXoc@pt2FPV26Gl? zriOXI55D-|cJ9EcrF{Z6ASwZ4QYAOajKKD<>%#kuB@esvx%n{60X9cLeWK?!aKDO?TE&$?<^N4Ihl}|rfweRmmeeFFlr40y+1wi^rp;*!$zRGnFw>+v zGuQS_00ryT!X=)2HzwWGlt-h#4eW!w*T5L9`{>5Mq@YLWUc+1AkIon_lR2y+S=mqO=9 zH;a!u9tbkV+wtq4X%!XC!HtD>lsEd}g}V;W&-<<{*#LzQ=kcXqKg^l9;2<4%S zG^}Q4biUO)4GS><+_iO*Pa(>>|ERVJI4`c7G0t1c%~k{aM#zgVCK`Jq0&z8r`!kKWqSF2ZZ4>3N?*DeabEDQW*i|{g zGU44m#mbjl!pzCAUPNh%MyO+yc>TTr88vLr`16gFnnbV+*9P#GfBdx)54bL@TJz}; zI?2$+v6!^obPJ4WQ7{x2uqf@NVAXCX_WVJXIGM7c*X z*=3lTW)Vplf!0zYTA5x6^Guf_F6W_wArt{^Okivx^wZB6@H=m#M(4H5-ak`3V-GR1 zy_R=>AP%yF9M|?@;Q{U8LBeKl+-Dg)dEk?@Fg^mC-dHYz3g9p>?8we+mks1kJ&A-N zns6C!@$s#fJ^j2`{QW!%u8;eHttq?C1A$MwN1o%0jWcKgUG^%@4EhXb$qd4aU?2)4 zyP;2=s#7GXlc64e!V@Fk`Mk6nw*GN4ZE|`ZUu*CccXaW7O7a`w!2s{?d*^V`1joT+ z3nwO@*hVEvsYx|cGpr}F(TSZ!rg}utLx*kWAeVrbwR(w%k%>S*{xiM!^T(=0%Pf)XVlQO+)8fv=RH!Fg z@*nH50s20^s}13{hVZh^TE+u%*vD(AF0a?d)%!MKzioyE2z6e0zn7)M#8l!{7_qk! zbfVXU-B?7BA#>spNS7fqYGQ_JMui;@pygh4kV+LcLxr!wq0&883qL2}J7*n#eMlWB z)F5h-lq_XNW4v1yW|KZH_wv9qX{~u1yvw9&Ca8nF#Us{Oy&{@*$?qjF~iva_rIYnslLe&|b^px~hw9q`ShUED2 zUNyGnL36G0&248KW?waw1b%{$>fV5{NR4Rvi|D^3e~OR_GIoqC32ngw{s^^|7?zls z`^k?){_CXusOUYEQUUqB_$-gzTNecYKE7JJN}XOFjY}o14drqMqqI(-WtlBcR78Y0 z9q%`x1jh01ryt30`3a?7r?M773()&OgVH!7V+)iE@v)u~4#~d+L7GOw%-=PuQ*daY z47t$00-PM7!q);$jM8>dH4S=2HxDkyI`y0c)3*Vlj!aY7;v9qWCT+=D9PjwP4W_)k zy(mcq-<=jVgby{m827F3Ak9Ob2MSJj~2*c^D4l9v`4_DhA;JD;TYTJqCcz7rz% zaK3hQ3n3~4WmY#slM8S%$&vgL;+S-SH_?+H6e2^MZ~PxzBG7!c$q%Jn{T$zEG4Bz+ zpigsI|ApI_#zhMNnZ*b+jpOF}~A;twZ;?m$EfPd^&}x*Hq_Ai@5DZ;wx0s zb+M9bt1F+4)Z!N?nu>RHGq5|XCRE7W*Dl06nJ1N0w+u8T`U3tHzDW1vT6YP-$_ot> zo3aFr@JcDMJdZIo`B|1EYzx$Qd3m&7eAilh#dfd8&$bM7a8RJySjF&(l#VgWW=H=s z2y4juM@=0*W~at9jX~y(!>En+hctpu^@k9GJ zEVB4S?6D@&6HVvuWH6>lf-^DXY6kJ}nZ%h6@D;0sfLHmdZ}v-m8xe@~g%;T>&!@EK z_>wSZQXZ^8L^9ARk&){lTbyVFxVOQm@`ZHN`?5`^Il@Mt2|HEN+%S+C=-bHLFfPkr zN33%T`H3gjD#0Byex(Jm9V}ii!tFevCr9tZJh?9A%dGv&4p1#{;uY^y1$ru^}Vc$>F*LO>T$RpB=gU%FHEh?I!vPB7@Q) zD&~yr2o3^r?s86BHj;b5mBJOz@Q`MuYO>ns*)wmF81?|apeIA8Zaq5lst1M8&SWIt zOBO$HF*C|A^nxY0`Asw9_>;4F%u5%Pv1cAZlx=`w(@PG+)^uC}p_@!1uqFK>aW%2a z@4=~0SBo)+bh0Emw+e8bsE%(?+b~%G_jC%=H!iyAhJ-2kqfMc&t0XC^%{TX%~A>`B;v`vgXwh0(+E$2Wa^|u_>1))F4O2l#D>7U@{ zEpbW}>hg3yOIw<~wy)-pWj(^?O%2QY{bFy$^ync-gAVOb>ao2}y@Ao7_d|!df-e4m zZ6LUGXEU%&v+NtVsT_#E1(s*e!yfr4_X#4#@jDLF8qz4^mWim#mlJHHcqbn3DFsgX z@g_#`EX?_8NMm|yjd)n%>F2M%>m0w8yo20@VqD;tn;BASf6w|8kbXA$Y;F#-cm9x_ z_yS!gi}fM>;xrN^&zb1FsN$XLSzQ~1cA{31nkUJ%^Ih<-E3K3X!>@-VSD{|zKtrK+ zw`+?90^XAjw_|Irhg0j`o8Ef$ghL#vw>iawT>V0lx2`cj3w0J-Pp2KNq;QRd66V!; zA%iDtzZM6R8Oe>YAR!-|ed|B|?`bA$`YgDvyxg3MsUimPH6e)4wJP6b0&!Y3?|;>y z3F&Xoq|(LwXHKfms%PhfmXwug@AnVlX=?=3^`VTFNUb7fZw=_zW9n{*XKnIB8uv+> zka>$!B2mi>N-25gf2|`*h^vYUvJYC%GGM5uu=?TyIjG*qtctO)j@^;c8B<7C zNY5j%HSR{<+wpowismiT9n2Y~JvK0|4Ts|XI&WH^Q~>pNC0k2fxo(GufI9`Popkvy z%HCVeNuX&8D52tDi+Hp1O1cCj6J(ZsSAV$&i(}@NE#_LpP9gMS(^}?~_AZs|65>cn zspXc&*+Cem*B0{cSv|0d;gSz(%X$7)7&q_w?arKs)BD0{dFc*@dbyec|Mi%d?XPBv zP6rr-7Lgs{CnOV~?+eJflN|EP!sWs8VR=L7>mUiYWnNP?pRU^ADSWEl=5mi(a58c^ z@D=Yfup(EnwgEa6UBfha(r^CzQ;g3jdtm9ix%yP{>iUovO%VgxG*AX8E`6L|oByQ` z;Noq*9$CmiwCu6SvC}bcAH+f{Se818i5onSQ-^z@N|IZLBVNpn>y;$Ig)+w~B@jgf zlYZd@e@;i-wb5toPT!1tXagwz(r^XWhY#h}4Dm9grb{@jJq#R5;(ckzocc8z~ohK8PnhiQQX| zYjUWR1Rswp>N*GJ2+DUBwZ(LVToVKtad#Vs4h|4jZ4Q;yW}8Y1?h*>C-?1jr)&60* zkR24?4({eO^Fe;L10KE~Aw0@-2QWM*Mvs>V;|Tk9BpH&vMXa5;MTqcrE)%coC&W8;J5 zM$33W+A;uOul zd$}>*)7>Zejj7N*&^DgQ@Jbp=KEP6j2vdG4RYSTHaUqLayTgOlMsEpi0i`;(TPFPs zA?|@n4a`sHw(}G^i7Ln&n*STcWKb%|ZU1dwnU5WA3O1rmX2~|6AiZjG%j7`sUZ85z zSIA9G2;LYA%t5&|BjvNUIAJ$EI5`T>GN_9|GTlSY8=SQh+~_WdWv2-X@{Jja5~ITg zLt8S}sC81$8s3D4ak=+yeDSR2#matWjxzewx$*q<4&>8#*TW-NQFhd_5ecASC6GlC zN%?jqL;+H{%cMDlSf0_dbQ?6QD@orlp#E0^GqRRmXCTS^kVSen%va}jf3ehSHWMQP z)7}2!4>;dCR><}F0f{f^N_`<}jkfxR%PW}Je7)VzkKznF?P=drXws1j*?kHBbN7{{ zqbTH2ATDe2;6$+E$a`fH7= zf$+_{h;!MPikd~55!I5Q0h`!ixK5_?ar#f3FIjPjSw;XhonZZmssb(wW|XaFR0(bi z$f}9BUfB!Ct8AY|VE~F84~Rf#mH@kS_+W?#ii$N=Kju=Q*WEV1bs_WjL5+IAiF!~Y zjFwL~m|%a&7v8LC5aUo49D>$ohxrqL0~}{0)8)@dH-z0VW0oy3MmRii>nY*l_koKD z&=JyC|FEZ&70V|KIqPe37+{P-ScTj6?Jn7w<{~s6X@BT~`rLiD_8D1f=feR$CkocO zP5IuoEyU|O$U6FLW{-9walN`Ag!ijRj(f{($2RsN!BpgAGG!th0voWDy_XgI#dsjZ5;}0GZ&rJMRdwP8H8-}-) zO48ERS=D%18owV|#LXhhm#*yY7}Q=Z$BDDv4xddhnZ5ytqEp7E0kNt6+5voT!8I%Kalg}98%yZ!E*er1Zlo<;+Z(=jSC z{^-&UJ(}{$>qs*Gb7gH-Tc40 zvc`dY9?u9mL56H9t;{x0$CNYnP~-8Dy^b5RLI^W-jJYlG2fQj@tH?Kk1{2(4i>M~- zAN_M9kn>kfizqGLd$&tN8<&$mteg11RQUd35s8?eha3^378EqJ9bd#Cf{l%?e$lNl zfBt96fyQaftSFY_FlpEl@|(7bY3&?^mzn;i{{NOE3tg96HecL6tG)R@`1|qwld*Y^ zcj;qk_BKW7n?g;z#J~HJo;PGSfpP@)KuOMR6b>HV`Hzt%&i)MBUP9r>a_%3U0s(MP7GRf{C8R9Mq*hOa40hI&aVJEk62pw9AmWpigCqZa? zdY@g8anh%&(!;U3G#?5Sy?7xC>Vmk8%r?V9g+vF zW2`MS0jC&$f?%$&k+R#Ox{h}12V2CU_m=$Z<}pLwfqTsMHXG@pk;3u1A6)AF&R`p9 zFG-OzDn*_&;aQ#q5Nu>~iP^GoobdF?0+0ZwrMcclH_`0NYUV;WS`D%QA-X*wISMQx zycV+h^f;+{dD19dEv*92htmuDEpB9L@-yYpM3r8-8m95eH8rlXl@tG)n8R)%-Af?5 z^iZoI;yJLoZi>9WggAza!e1%EO~(j18`m*HvR2vI9M0dGjciM1Lk!{P_~J3_8Hc%&DSogz+4y zxwmMsrafu2P&0xzL%dh?>xPFe``ZgG!AD|UKKEFA?HvDRw`)j)p#WDXn|F)Am4Fd* znVCzi#fEa(ydl6lgq8j!yutv!$fgCu9q%Sr^bYL2(CR1HMh+D}rp=fC>?*>dNp2(M zpFQvAy_JRONA)JdXn`^E|8Hd}gW{cW>;6rpy>xTa^ApCqBUE?TnZ3sk;j@ZvS9XhG zfz=#=!FK8))p$S?M^uekv<2KU-c}J;fXT{jc5M0|qFa5a`J&Yprs^}cG6DQ|fO2fv ze0}#mUAz(VE?V5^ofdNBlSmOaNJL$G)z+G~qSeR#v&ZdO1Z{d&ak;{Zk!Kjw)c7en z2E|`aW<-nSvD2ppUln{1Dr4^BNX?$CfC>S`UQQaYLOCRsOuN~ zGeR4Dya*g_0}R=&{9|ID1o(*la(?tO(LApg6B&DRgrMo+&VV5pN zxS*;3ZWABMNebwk$3?SChMQoW^?9#6J|T&N+B zgG^=mn~3)%)OFHt9o>1U=qrc4zy)6*2B2om!p&TR|DoCZu4<`wdc<{POz8mpbXhRA zK5pa)4FuKQ()~_-WKg_G4)!sGBl^$FgKvWwL?R?g?}QK1>F_7uSRcTpEa=MyCeP~w z`@_$oYhz9sD|UDh@+dH-marR9a$f$x9oia&Ma;fXx&C{%7YjD%+&jD$x7$~~xM=xl z>u^1d`Df{|p=EFAHJ6%r(Iq(}==-)}-Uqa5D6CpeHvyGu{OTYBLA_0Lhz#8+>gX_V zVisNAakRr1_cE=w4P~M>P&9{TG(G|CrBp2>jC&6kj{uIJJUCrzHgNwztnQ<~cTp=p z*!HK&QkXcIx>x1jTGLD-3(VrRnvwKA1y;>VHEhAZ66~WVv&tdW`T1Ty4CVGt;*L%^ z--YM!qDDFJw+L{sRVpji#KUg)eQ~@fR@o+sBu$E1FA4?Pu-Jt1s!pbRgv?ugZxbgU zK2K-tU)N1B0OSXmsf5&b>3a=Fvj&BX??f-ED$64r3}70&J7>diO^dt{m~8HcS@^=x z;ekk}w3R*9{&=Q>-~xmEw~JN-eN{D}LKG#sn=?+kkmW6DWbuc4^Bmx`)3In4zm66i zfqJS|GP(tqOp#Tj=5}kf*145+mGebm4#!U3nVrx3gQt^B-66d8@~68<&qoqll1YYy zEIB`=%OmZiKZ$dfp~_~}S&91|9~*<03M;&ft6F0=zd-1(&+9m^{xH_2;^E%g))nEg zfH|!*;pNHQ&n=_!-G5L-(4ViXqc{FFS7-1Ee?v!ogdN8v?prgWxx$o-DaMO#`8bYGCZklG zv;EpRoJx=1JDqJ5uDwtg1HgVR!G06R?P_a4m%ZziSgXurnJgp(%ZWR$J!NCqTFSL8 zM#2denrXBdrJsELL!Dwe#XUr~(p65>RmL8TjwCM*hjW8S9~FJDOlrC^u}-pbU*6DR zCc|(x+GXL4JVWQ-OpFDv^p(!8r?Em~c%(#H&oIIyO+{K0h-TGWmsWdyINJ-1Np&K= zY8xHdd6T7WYa=o$9OQx1kx7N`EaDMN+V_Qir!&3S83E}?rAw~sol0s0^Vz`2n{TIk zTe@TNe&f7wCXe@H3!mHvN%`^=C87EP{;}a#!}T7DkfNad{`!-OV!`^i{Dw2rWV=GA zuges^AE3D(a(MAgD(O{_p1yvj(-2cS`e5S21BRLSq&%)r33gDwJ?T{sbGzHvK4&CSfu`4Tl91;IAiYfTDo3sYn7+H1k@1n1&1}-)bsM46 ztVKAuw5WmvBsufbImL(vGq%T^M!|7J7VC3|KD9US!OZ%2qpa_RmNzgKJ&JJkv89(F8s zHidIUI1m%O#5nb`DcVOoXETMh7UZvnIUTOk zemh+4>aw#DdHh-v-t6})AX%-J$x7k1fOABHhlk9QPfLvzEQjmAtn{_ypHi3u^jo&~@8yD%*QC3vV2Qcyz;R>8|JmbFMY}C>4yrmBt z0s?`f*dtgv&PcKqa)Pk;hd9Ut5R~iwr%#dBBSjBE+oQw!N}@jcQ<2yvd}jWM2_b`p~I$<*VcCcRtTr4ARcLeC$|v63jWc5I)?wS_fSMj) zXbMRi@kN`z=2@aD^KQXTd-zN|lRErG|G5j}`vF zb){@n4xWWU#9~gh@p5O)6lA`ZGS1Wbox8iKFxs(ah*uK=Duss4tnaWj2aqYN^`*>A zxTgZ8R!>f8bl>(G;b!rvAZ=6D$UR_dW2ieUgi2w6z{u<*1N28>sQ=Cpa;v{a?l_wR zJ;C)j@^`;wEx>7^ozl=YjQRGybR+PH=8vP+iWX* zzCL7wFA(atngiD|VO)4F2WX?(hXu$-NqlkX_l|?p16x+$jNarZ8Kh6I-LF&T~c1p$p-i%Mf@%@dcuY@?NV&fGo!q-lQ(ma;^9b)adMA4O;qWUe2 z7{)ef@V^qoV9f@zzvd8An&=E|_N*u!|+~n~D%#Khz_C$FA#zilj7LXl)_NprPqkrXC{}XyH z)H%QB*f$6#uIXaIB63ghmq(W>kV`~l+KuUdRj-ZU?fE3}N#P-7^u))WO)SW^0_6@{M)Od86)%5J3_Txd`+Cg6D*e8Em zk-*v?ceOQV-d@LXh41row+~zrPV+2Y;(1BW~-lK2VgQbzYsP;s2}UL>F_ds{HXS-MB#XQ6po%W zbQARy8aJwS^Sfxez=osPTM&{nVOr z;%J_xk1h;#j=YFm`1-?kuDZPEWNIXRT4*E%OmPJ(=fe8R<^6Hz(V3lw^+RTzomCRL#8tdA*{8tZ> zxrJChrAu?eX5PXR$hmxNmeLQXrhQva5W58Ah@O|-D>B(!22$*kb;PXwE0fAF^8PvH zCGUqxqF-D(&oG#QBIzV%zpC>_5L@}AdyTQe1@n+;nNY$EFk(&ZzEdQVN$_vd1Dyo3 zg4JB9GIfDsri<0|kGftphzXe?n}!CfB*LC-H;xq@9Z;u3PF7YXP|l~97l0mgH?AL6 zsJe53w7G~_m{d9Z8*b%g@8jFr%MLajzRPv2q-2qRe7$2KY%A9;fxTuC=3CF)&=PmtsYEM!R!;`Jq@YQR3iFsV$ zoTsGewnm?Paf_^!$`?Z0Qy*SQpI#eXS9W{20Z@iQm!V)B8{}a~^2wd>ui^P6TBI12 zjzHjRYz6>E-U0DDVNxF47+WNS)=yY6H2OelQn%lYjRf*b((_nO;$ehpy>Kj}%w-YY z&1kO5sH77iWU2{Q{?KhU(JNrj>+C0to5sljCd_hwr=@q#s&D@COHi$C8&A3CMjp*? ztyp?Cr)@+076dqWpq^Rx1liozNl4wnp@8v&_8-v=vbHI4`Z$9ObtFs11V7of;T5hkAlsSD2x9@e{v`t0crBExAI- z0HGiW^BHs#cio%fS92_Q>y58e!gYqZOdnb|sOE#&K3dqXEld<+>rYZA{3jwgKBBJ1 zi&R5MO2OH?!z%Yv;HbrW3h^o~Oa@G)HcpJ_$m@rzEhZl1dT_~)FZ3|2y88nb;r0~T zpD?=hsZ(@+y*t(1OcH{L0xR5H0n$;&WnGrd`?<4QS+x2<4A=M95BGCQ>vNnvp9jNN zTyENadimP5-X4gJMCho!Dn_))Ulu;7tva03QxLY`1NmG}P0k&4@Mh_aHN84>x*s2y zo63eLgg2&Y8`x+HW$5#f#WlF=>NGS@mda}sR?bYncb5j~*v#VX+OKn(^Ce)L5O!HY zF&$SI*y!%Lo~0ACWwlF8Qvu*0n6Rw>>Wc*Ls{8Q(Q=lK@4QimgQjg@e$!wqzNnw4q z{Z!A#b3>gP8{ulW5=~WMr)qp-q6_4*PAU*EKIw6oqNvg$Xb1eG_ZxUY_%GDsp_WBR zLo`mZOu&ShX>e0xeaOIAZHciNJ`wnn@cuQ%+P@(m6;oVrPy4?qj{g zoQ=9b=We1c!JN^5ev)@e!RednZ+yI_Aq5l(3fPABpGN1xNwb;_WZq>lNl;k!@3 z&VBRPw~Q)@Kd3l&QnEfAy<>eMRMsG={fq1*U`LDfO!X$@vhMj4hbo-cSXQC;+u{}5 zq+8eO(%m7?_&$HNo8R>RqM;aVgV(6$)JPw%?CRS~2ofaRJOL|~R>kJZlRk`<|HRq! zkI-1Vns4GhVAOQHw|+CTuz%S#$9-};e(&$L+mo#DN{7gipkIyZa?V4??yvIT2tg49 zuMrJ*UC!wOuqZ^FBH)^-|4k8ujKt8pD=grlF+$}Z!2mkBf_ccPnKAxaAWi{w@zsXl zZ^bB$4fLpIfW}Nu@JxX;$vlk@9^t$#opKjEiB>{Uet3lqxEYvwQGoc$`WfK`=ecG3!M~V zelT(M`ZSh^-%*Eg7@bo=$lx?Ol9+dr$Y!{9gNHR7yoP*3h9w{Wdw|Vz3*r4eIy8}U z!DIUg7t{ni1Lo8QL9iMDB%w1y9^gQ1!iG0dH8~ELT$mO6v;@fe6X3irCk<;t&g@)LS5DQ+x_wwMb^H?;+!+ z<^FRLg%!%=(t8ekwRP#Y{7Fj2Kj1u#5K)ub3nBK-`kQhG@s4ta z1yF{Ee6Di!N zb_Z8Q9p_P1)Tfe>iH2Y9$e#`-L!=PwQ70_fx?kfY9T=uq9XR_gwqV*|z$ayLe#yX% zkv|h0$7}Tex7l)Q#P@B4%V?;xSk>hcP7KspheJ$B<*18~&_kS6Wbw6wzmmP+IhDG5 zKd+J6@#=`zwGqFBfX9T$q`;K*e{piliukBS_$bi9R#agO?IK|P(=iOcRm>g^) zxe^##xyvqG7|8QUY~qieZG2R??Q`1+w1>c;pF-!K%$>aiUi7NW2bNbnPEH>E1_ytm zsgFT8%wJ3A>O=DXx5A27Q>MAK|U<|vN z^tX2I>^QOBt@pLk(Y%feMbxTi{S4og5;6uqcl;o@JaMQUyp7-D8*d7Lftcf<9x~Z?U$e<&FPrk@RjsOQ!IC&N6v&=Ysi5iOpr*T zj`FnwQfKTFWd=57xM@EwKXn*f8YN4HK?WfGxL$P7$cHf@Z1Co0+S@);E%_7Q zJkT}wCF+8-6ywS^cMz{iMH_M1s&}Fa)jq5PEa___w7Iaobeu=;_E)zn zE&{VpvA-{h4b<-#no8=a0xr10^!?#B!?dl3q?g4TwSdZ4u=OLw{DUBdQj)^B_m`G)DegnDnN`EUA4C5IMsUTn?Oyt` zS25xFRc#67l&H^#p9m0b$w`@eYrsdSaz?fQ$lGkzQOv&=h4J59e+OQ*rI!pM{M%H* z2ku9si4DSA z*KzWAG3qi^@~ZjsVYy-4-||>2Ar(nV%2r9U^@D+YNVE$+F0S?-F6FB~>-%a~jAhzF zeXz(WW2Vm^WSVJVm-F>dLjR%4S4l*ZUD&iKSH`!Gnwh{;t?p5_Z#9^4amYlxY+)E035 zdUV+>ucH45Y%LQ6RrCm4vrLU&?_OwWK~mStSDQ|5j&@S(cUDh*gw+Tx_ypJ$UiXF8 z(`mjEAh4^%XqbbP@atNQl|Zv%Hd$gw4Lr&S)ob_+%HWqX)tOBRUPUo|(bU3mJ(E-8 z(Ue?oZ~znPz3DJq0yJux4}Zs)yERR&IJTy4LQTrIG`d6;kY#0f$z;p~XIT=DD|P|& zFl~iMQOt63Q8d+v&K-eO2nG2c_zkp+bhdS@b=tI-yoC*-BQ37Zp9T1b+#7@*k9B$v zC#DCcyoKpy<5WbU!cCEl`dvrHZLsy0V%(Q1v_?w!q8>yQg!CfmxA8O-K*nAM>Yi{1 zl)ch~X|Ex!qJCP|)bE+dx!0I?b`-cT^`ovivU}e^#`lqBVS^3e6@G# z*yCM1fQ_CUj;_qT;(F=w7U<*w0P=QaTlnfiY#M$1g5L_haa?1$d1T?QUrNuCt$wMv zHN`wOrM(?+wfc1?>ZsNAo4KxCHkOIk{rGZP+RfdCV=F|2{KY|wbHSUp4HNv(TvZu} zm08MC2Y`Mo#W`cQ2NgfJBJXWiA9&q+)J60DBcOEo-8#~Yp4(T0@O^gCpiuUZZsR5G9Ao(Rek zE9uY%$X2KlV4{`T;qXrf<&0&iO9;h6OKwL!H#2uG>q>usI)6Qs*H8L8&7eG z4GhyA9QS!g#!vCPGMcko8eLq>f%|No?&YR7MBK0qj9lerGk&M=)nYF;CaK9n zdOH&WO^WQ8kW0LLQ+fs4Qtn<@A8s-#9(pAIZl<>*IR3y}S+n(Q-FnapV?XNB7-iGn zCb}%1B3s_%V6M<~t@7qr#SAGwV;4NJawSR^;2$=p1%B+Qre`q%3lr!|qZMdby<+~H z^82mmAMCu5ef`v`SUXXzWPyPBYmD)e^0dCY2uVk_=8C892(TG@poX6pO`NfGk zq-n~^djI&Lj|Ql1j7mAB`@$JI|2`V?CBao0h*LfenxA%sYA!^a2#Y$HG?WcZfI;qw z79sb91SBI5897^riOF<$$f9DLtT2LLsFmgSLt!Sr80kP^uW-X-1|nPxW5f|=v>wXB zewhLf&=LH++OwM%wJhVI5+T%*E3HFvVuc%jlh)A_>t(SfR*{r3bio#mYPNnM@B6QZ7wy68g<>{9 ztNu?GrX*nzuyf=C+Fv`NjJ*$lv=mExzs-`hp!rpj*GgZ8d*YBF#cKOQfXUqomn&)W zd~lTcr}8yH(l7EHY*utJSuW8fQZ$XrGu>>Qlk1{m?@$3@1G;iLhhrfegI3hrErp3* zpg7bI7uIl>L3$E9K5KsYBl`+|x=>gadKZ#I{E~!T#5MZ?-@MjhRmHrKXP(M^YbxWU>5_!N3Gog|JP zsS}9z1wiV05exIPP6Ua#KVEtjIp|+$gUhZ{e~@mRWU~0POLpw4p7CD z3-D;ViY(+g^Ow3U&E}6*I93&>onsv|EOzpK`5~Cu3{`Z-4B2$q?Cyl&;9HHJ(mfL@ z+lL=qLIZvf6%Mgi{VOb7BF;H@J*p_Vb!&=HKSl`{m9;m$c_(c34fiXPIOT<>XO(%K zmA5^a78f5SnwSMFM025|;Zd?&8J|wjZfF%R7)%&UD1j^Ab=eHIw)O4meUHSh{GjAB z+tTkdAYtQ;&3bP0b*=yoVXm|XS(R4bZV!}~ul;rd>|f6zoN)@UW7KbQG6gIysUHEe zuNMmj4#xRe$p-aEc^daMSykVxT{l4=XY+net@X zlmssbrdov%3FpC_<0Q)7R1c^ndao#MrtD1QpZ;`*f3lc%o6K7;q~>B`f*&WC`S9g+ zC>6ZRfeXZSPz88t=}IvCkgrYsnoljQ78+Ks-_Q&4z6Y-o#?|*_T?4(qr_pbs@)2M2 zA@43wx0RboLb~V)aX54ODp-+!0iF+|pqn{70mh156O4Gqri1+<4o`Y|Wub`2q7ECH z1bKUvvaifKVOS{OluCn7nFaNk9o}sU&!z)lS>Eba(;F{JZU!?4n}%Or9dD66wi{&q zRQDt1arhWgzcs5kb$8VrFHzO_^W9d0t52Vo{alc)zO_1 z9jaPyu8{$tL@v@f-@5WW8FVPB6{{_$BF%JC z*yh;7;GQJgrK(s*C1VwEx~=GaY}2&TyR)=`T7I+_MMXbepRtl!2YzWd1kUL{o%eap z+}pmqG}I@UpxvA->Ajoj_!H+spozuYJ@A~dF@W9Q1atJjvNA2JWb5de8a*;VK4G11{{t~K=XlRFh??%*fPIV^m zIV0HM#d!7XhzTtD$$%J@Hk3P7#**SnN)lagm&?BPHLQ5G(&)Sis$?U$`6EvQ(p`BH z68hHu^Lm_t{svxgw~gm+o*9*7I01|>OpAK^>xWv0VRwgbz7V{<36r<|0rSK@>7Do1 z1siKJvsmp7JU}zp;Y=mjedbj4+kv9avwaa_bPep$Z$6nMbDAeT=`Q{nfaU9L`n_%b zil06|FK$V+ON+tZH|ihW!VjukihX<86hW1e*wDS=nMlxY#V%&&L5s3Z<8J7<*|TRWc-a&Or< z9k$-pNugAxQtA~!h}6sP99qL!=mgx-soW}1@^nlVosZQGjHQVV^lrmvys2J$t#Ce# z9siE%i8>rk5nS1P0*8E{R6uuj$;ZW}JF^-*6(oAjS~ASUJ_8rpqFXB)BAgPKT;T!w2J$Sm z5DELL`p%&eovKoDjoa2;Qi5&~`14HW2lzPs{AukW36<`-~CXaDy-8g^HRQ@3vNGIppZ%A`_*-%HB8L>pI7XII044Q}N zXR&5gAk&I-j{8rb{&;%R**NM6CKERrXBz2%%|Pug?OrU>&outJKLuAX<{4l1zwZ|K z3;RQtd+jc7MN$a|HK*E*u0{WQmt8K5oyd)|FLyDph;Nm=yz%#@ig-8wrn`mjk}K+r0Ih&C;AEf8fum zrk{>HCb?kXvRF-QN+}pD9)t|GY&|vCY$+wjRK6lt_&0=y#V7VVvY?!*5pQkA0$AM} zg~QTuXMKr4_o0)~liZgA#a1-@3I+Wspt58&u?0as17fDX2Pp9rY~2mM!FVsp9%xn; zy7Z59UP~KbcG%Hf<}0R7Gzt5lxs`!WiDmEza;mlD>(0W5Tr+{R-;)%zKc8V=X6mN!(6T%%+In} zjlAXg<0%b0y=~SMY*sY#Vh>!o7K(067I$QE6M1Xv<-WtHi%;7ftqx^R6IYd(|85|c z5@Q1^%sWxu!a*hIRzPDy>%ntD(FLfV;ks=MYXS8?O}8?-dxDfQ-pLk&C*d9tN=n?< zm59zn00WiRcskkE<=MbM_GPqcdHUJI>O} z3R|fxszLBXI6Ne;u1VoI@7oH49f2M%UW?UDCM?5!8NSqO$O4vl4N5^|_qsihUZgMb ztc7CNFhfdAb+OW3n!zmcT7SeP2%N?ame|%U+T;PmwGf|G+m|(~s6I`kXZ*R+LK!8Y zI#avq&EUsU<Z2oXMvYtb7!E)d**6Fk}>}~ctP$sABBbV`iywwaA!FT zFua<+4XOa$4KiP+9r&Td#*fVGCP+C(0`j)|JOvFi%q!z4Gfh{$n zsfUkcT6D=9_`$Q9dO8GpBj%d;JjT32edxk9ul~SiHC&__IJg^}2|}Q1Im7|R>MILq zw)ZxBJ{SRf7kB&-`aBPE1#C>N==O`$o7Nk$_!&H z{z3=m0jEBr2!S0k`pcuf_DJbGq3V9Fu7*Qyt3$2|?22w&tdnJ=h}?ya#M$MKKNB?^ zq9dEI1x$2zb$2D_?xfcXZxWd2BuhU^qn=T}~1WR6+$qM*P+FnCb7RX&X<-vd6LO!$4Mbapwz9YFWb z%u?!bT8eP<7N^cm}RRSw*XjRJQA+If>ZdDF7Nw@uV# z5+tD15IqO;kZdezQVFH=Yq#kDN3xjkKcn!UwGksy_yraatSVA}rKkO*@LgFf+}l-> zfB^XjR8B9TV=13-QmPvK{RK~`fwI+|{zFtb?#E|>CKcn=wOb?hbni%?`tv0i(8@46 z|2q>i!A*q_;kGjpA7*L4kMoP8{Xh?%Tn$3EU09281F_5j(+46UH33@V^9yig@n-a((AvM@JIUll(fRor&2Z zdw;!%lr~}!HIU|%fA#XHcBQ42fqnJO04&y-a=iwYUO#hHf5W4=NI86FJ{w|umO zfxCZ>&S|R{r;rXr8j2i|%p^78T=}={*QcgwY>nI>cfI#&>1$_wtARCe#OphF*-`+r zSbd2Sa&~s~yT|0vdLFfJ8c9`_uKD`YvMmlU7~18O(u1dBkiC7Shc(=6aR)FzpXK_sgGh zvrlhqAFI|6lkz8>%m{auMC<0v+MDp*n+Th0K?a8|>^dlSE!-4Z0ECW0D=mEOz~3^z zHr6F4Cu|Ypvd(-4G-XXKhhXgpHb+w-m>pN*62@eMzS7BZCu z72uGRRXimh&IPCuJXdqMa2Txj45)kdr#Z>maT~vdHz%L3(7OL5*c{aFR z%b8SXYqFd;n|hl#mfGeb1b(_5;<#0{x;XQDjPZBWgTv}gOZbd3Tw%|qAkqbuH|bCd z|Eoy4U4oSk8+Nx-YVJLUEe6W}H(@k&~EhHJ3Nj3k^bsciQdb9 zEh3oyT}05y0G&P!b2-ly0FHI$`#j-ASel1&xQ@Cc%MuA_ghMc4t~nh-dGk!`qe_TJ zwa~|V0G3A1n7LCu2DCr8e(-01m1$^7IdSTk3!i`*dy&}Xr3<6J+_?=&3Uv?7HbQ#@ zy)U9M2n%6n8L4j23S8Ik%g`#kXt$1MR@M2kERXM${vovka2vTkM|ySl`W~3wIkJ1Z z)h>TV{3#!`%5QMd?_GQ^BIJ1@i&qc{d&!k_G_m}f$XLVnU~wrN)mJhm18eUoJEJjV zRiqxnG}>ByiNCbjd#b#!ul?!3G?h26Wn`3kxa#0}(0b+e%gV%qkOfM7T+oIGDxezg(Id~`pPI+Jec;;u zl+5H37CW$>ZAaERRR~&*HN4-86J04nSsh`GKRevn%)ItKwLjSeo~(b^0o<8!->>za zHs|2O~V+leNf71Bfu^i=4C%~`W>xRz6hrznL*AoEdrAQGN{WC~iY2zF30FD7 zsxbdsR^;;l2)YBL>g1U-ly0#lcc_ehB8{~U4oOzCZ>*pC<@5@MnL<>f=oj3M#TPPZ z=RF*2mGv~M76%+9AYZnBVrsE#C4-0W!F?s>a2<*;Q+R0iaMl+YI-|F}>LY|k@2B0F zt%sipbScneDw#t4qM!2T!DR7&IBTPgXL3d{3djnX|8%V?9fsu`I|?-E)4T!ky4PyY zTUAfmvJ%u?TMIm<-*HMU8{Lgx6C=AxK;jtVSD%xNds@@S)y^+HTPaGhsNFE$yBlho zssu%qo^(~+Kj+)(ymEHTz1$c_{nb3YFz(#CV7Rta1dAn#sG>P=d?{KdfsqVtFWpOP zTabwz9Zkn}a6Oq+S($Z7E^@jo{VG^L7uyY6;t86$L<=9oT@S#OY4{1zQx$lm26TYz z_kB9vK%HBNUs5Dd^jP@cHGAdELfh$WU5^EiY@HAIwhuu~)n-ivtNb*X$pHIlm-%%4 zT+?e1Z!S6}^~~#^p71lfX>B<2`6VCH{rq{U=a!8yzv@6cm%ncPLR@GwYjP;Du2W9e ztg^pw%^c@1ZE=^JQJ5(JgoQ_D5U8n9I)It8Dx@$aXl~QbM70GfIzv!lZzX6F3gX42- z=0o;1Dc=-Jh>QGa4-pyT#Y*WTf1?>hLuhPB!v1N8`{S7DRqJ4Gt(GBWB0kOCH*vhvAS#Iq14j2Tb8?aCmZn4d8yV5Qzt@h6MlkdKg+8J})= z9tJ~-9Oqt(7JpNT0Ed+Hmu`wGbLA)IV+4bxIm!~9nuHC!jDC`8X)$=0k`3=5Bp@Cv zhfjuZ%<2;5p+?^kN`2uT`E3gDv_bCLO4Sl8@num0KJza(jnh=y3fMP6oR9eGmm@s6 zA)4;3_=^v4%a{c_YU$MA?33{)qA59smrUkH;jt<*tV6T_3U@#YGj`P*AvWGVdp7?G znTH?N0QCk9)drX5rO#Vvq-w4{B#%czIY0KUH3cv4y7xlN0Q+?O9@9^#Zj@xYC zf{npxmEQD$#}|P1TV}}5lC?Un2C?s7L9++ZQskgf936AHExKU!GFrqO*C3{o zx-HMD^hQ7g5rGmaVZ9ZvBmdQh3wq(AC!;)Ex_z|-VZ;#2AaWIKL(gkLYs zi<&eX%H*0)PJleGTA`KKK4Ks9j9unepPVBEd-C}OO?Mc3s8aX`FrJ5PA4lukv%G4L z0lD{^uP!KV(rkiD6Vok2Vn1nL1BM(3UO5I;%gfi%u=~CrNlD-L^LX-bv=y;0{D?yc z`!ww)B7q88OWb6uLBknuc`qXBjG{}G7cx;>82WuzYiVQKIFGA5f;(7SG22*4 zNMC6MZidV%d>v5bd9b^_aD5gAz-p85F)lfiRjiOZ>)3ksp6`T&RQpcc$>a4nVMYL( z)8j!Oj||nC&SU#MYfH zB|q!3VE@8bl)l3Ol1+4aZ5hhpmGlyRnV|Wz;X8z91q%I!O9fTXThuN)Q$dp*6K`^0 zH*z3cQ7HIm4Q3`3(a4j5@Q6oAj-;dn_6eorNReXgyGPG=|FGU#BIPmkDEiqd(ep$z zPyCBO-wm4CXfV(PoYU*Xv>PQ+Jxo8&$e{Y9=5MfcwZ1%?Y%YHw*!b`An-p1DXR}#%1-HGk{s(98R3X;<>)z#_oH_2e8f=Z?F zE5aF2c4-oXK?CNGEQ@6L(a>;=TH0XhZpP%vmTwV3WhIfc&^@?~c~R7p4N#Kxr<4NO z$rZs}0wW%HyuP@peT`cT2Fs6D!V6s)HK?a-{4|Y~)QDiH)JHRcKns_DBK%!G+fJww zByzfB7+WnN(VO$zu59LT7}R{6U+}B>l?QPD2iz&31ijk_qvRN3S;Ld}ux)qY;~^lJ z!#dRLZW%)u3ZEafuT!!<6YnDQ?o*C;K9D zc6-%0o5|SSgUyC%`gg~jcMx1Xaon5GZM&UYK6x>a##-T^4X#w{v9htl2`Q=UP=+WC zSPU2-z-yei9ABZPVOjp}FHf*M{Hx-2nd+hk8*x6)h=+0praoBcFqC4$ic7CpF^+Js z=0EYuU*%6wSqEhTt7NPYI|W=5$q6*|G!L}$5>2^xTg6Y=Rtvvs99w?bE|5NF@m|wAPF5R_S360vJff|95a1O3Ut3tw@Jh3k5f4f$ZP*7{w}h`sqlQOe;{XRR^+zI*dU zeH?RrE*^DPS`L+i@kiw4?IWCbn_4xwyf!j%XTU}dOz4j=BS1xR=`+6UG}zmmK*fsy z;-m97IZ0Rtu9Y~~8&Q2uXZ0k9m}bIb%ee|{uO{UndGOUy4EF%m#xut&Ev{k%x}UII z_T_bG;d%&HUlL@gVuKF33HPsP7Qt=~z3e^XZogHo-pAm9>i>DdTB{2dM>1a**}iVh zt?SpRh)?sll!`Ew+h&j)8733V{JO>jvN5|+3NVa5W3{2^qLL@%hNohMQMl!8vl29G zdZ{&Uw~(~}mbltNFH0b=Nf(n8!dQWp?Cr}-9W&k{c8RW30k3n$*$g?C{vG6w)G8XV zYp%#0tvuLGqnEt_!|iC4w@iF~>l!K!mYu<)pTNqE zUxu*5a5*7(_SxK>y|)Myh=_JGiF~Sz7>Fm}i3B_?_Pke7LLT@luzYjiw)NG=`o4P; z|BSs${sl0}KQJ&K{qtDnW!^u?n$d;4rr8`DcQ%GoAk|w5d5mxw1TJLsgql1qY51B3F`~tWO@oM9<5{^WzPK8{O~&cIuKb*>oebw#MHI3 zcZp744vun?KXy}DD`enaV>>7#MM?E|x_YX?tI zZgT|_50SPs5a!{kgctb*`pdCLilsK>t6S|HC5U7VKMo5n=2%N1f4!|cLXSu6o*Nt; z*5yoIPusaokG5=CJQ_(rUfmv6DH*!~ole^0#~8TO9zAuUc+i)h2zy$*mdExIX_9N& zd>%2@vD>=B&myp@+VG~`V1I{jsfiA%(8T9f$@d6bTqQJegygz}F*YZw7Qixc`^shR&7SoYAR7G1R%*Cklc@=#ONAH$f--99IXr&ub-^C`pmWt?8g<1KcR zEfu=HA-jj=5=KzJF>yH@*qm76m!ZEREB&X6?zrUgYIbOru3n4OGeA@F0yjtn)_;XO zIJO_SL?^8kJ7|@dAIg0B@qcu^WmMGb`#o%cNDI;_B?t^9NP~2DDJk9EAqYyBfHXsQ zH`3BQ49(CzL&s1<$TND*|NA>{p0_O4f_2?j?0wyzdv7&~AP#5-y)>#8;b97(tr9aj zO>Fm$r~!x;UhI`d1}Y<0<_yYGNwJiqAXeq975Z)SO112ht$O?c2Ms*JNF_-g+MZ3u{md-d!>29LC`ZCGI`FE zALcD28((<#ZlJ{vmCU z;~NYrKWA5YDSp)&_>N={Fiv#FuSKFqpHG#&oBD)~x=x2_hjbz&Bh8|$jqC$|^n^z# zy2sVvfsze>m0uND%|?(K^aZ(EA{sQ+OkS`idE&x>G>s$uDDZAl?)^!+pDk& z1$Qqcnsi?B3b~17kbfj^y)_=>$)t8GuG3TKy@Ge3&!IG{?TO%@8Ri(eqLa0gzqK1H z4Q|mX=2hS4Jd#{2vK-`@XL?4d9V4Mwl4j zy072Hl(Lc{o(l&ARyXg?;HQjZmS{BUjZhOzF^cz}kD4!VEmNL?GDoe-%BX6yIBd8r zMkp66`cfy*ldG0}J~cP+akhBV5Q|(P%o?AeDTsOoR(ls40%rRRpp%t+lRWgEao@ci zhpHI94Fguc>`HfFW%=-|Eh@f87I3l?qP6J3NRhqevB0{EUKc6&FFi&!#{fJ2jSC0c z8=K_3!~f$RfZR_=J#e!g!gg=-EY1iMb@u=yTN$EBLS@5g&r_l^pC%oSz zZLBt5##}C^z1Z%svK6*bL##I6w~DNyH(WDM)?>!BTKNVvC}>C`M-pp#vmJF4Ixrzk z4_Ve`lg&f(>CDysX=Htm$3X+*JB8r)QnLLfw@lw{xZ83Q+;D~gLs8D+{ zK=j!FK>OvUn?&wZ3>#ZD$$3+F1H6)aFkq9XKF!D9j{lC53~OjDMG~ufN%F|w!DCnR z=dA0b$!ViDGzTHHjF3=x*46JZ(_NR@tiY@)r(q*62rI9h|y z?x}qQa~r-g8q95Bg0(n6K;~+;1a5ntA~h~aC;amfw?hi}j-u>Q%LS_bSuL4GZ%RbV ztH~))|A>x;z2lnQlnj@W$=8y%-zck{HRnp$5-_l|TNn>L%M&~MN}%q!%LTrjz7R6_nfR)Ws-A-pAu}>DYSu=#G6C5ff(^3qw!Tb* zvb@Ev>CB-_h7F!?+^ZR{Q}VJ7 z^TZg-9pN&{A?zIsSIp)jg?5FZf{ua?C#K~x<9*#0Q(=ncF^B%GL2Nbywz7ry+cUbE zUOcKp-!Okqe&)T~8moJGoO!oF6yK-rg?+&$!d z(*6&^GO51}`(HN21r$6W#IO}JH`F0iewRzOOgW5fE-cZs2ze<_x;-PgG=*9}M5AgM zf;4RQ2?(&emx}b6K+>uKLur!+ZVLp|KIPI=zQU6NHJMnqbu)fn&y*Y`elxW2FK94-3#5iQ z{RTOX1m61sVHt`4Z{hK$=^z5z$?gAdF*k`4^AbJRI;4MJ7h;$bkpqjM8mtTECa66Gj{aLQdP0HWDJC7Y$`7V zL~C4ZyoZZ=ER7F5jPEGsL4ly6a!QHyho_4Uz~Csq9}2|CDd=4OR0^6erHr;phRQY- zQ2^hEAeWuVmduxeDtH3aG-ifsqe+XwdeC1U{$-utwL62!*Ux8hFrYHFQ>%9yNR@6ZK%y@ViyNRlncdYzh!u@jj>j7Q??pKu>D8!<~`N%LcGxHJL}OA5`~ktnG_Km&WD1~kWV(^RS- z0Y~x<&%X8M&Da~;mQ*a8J7`lgVk@|xo_cp!t8tF&`0J+{0P`@}z?rHrt#9%Lk@itB z4p>U|Sc+bPQ3ydzuy-H0@hQ;Oy#$muCQ_GIIiz)*ksQ6v8cWV5I2Xy+OL2S%qfmQ1 zOUufvSW?P{9`vluRicTtVU3$sPDgVY1G$W85*vriJ*9tBYR%{|GK&;m`@bj_)N<-+ z28{w3Ju1lx9Uch~D=lj>$RLR#&d{r3t33Gc#Gyo!xb=m5elqq>xg3Q1u-)S?RCbU2 z%F$no(6WYj%e+Xg9F-7>&lTos;hu5=Y{)Aa`5nsDnKZCkwAzth*O zPha)X9&huNB08rolOhaKzMCU z#d;Qe*DVCj1IQE8 z(_EJsU>Wrp!m7LK5HLbUN@||ahAgT0iGU8_OfAJqv#d8%ns80^I`3@Q^sK!|R;o|N zO#$|K*wOm~Z4JCMcBCFyIkEGjhlkk71%W{H zU{FBzXp-&L?aUhNZejt(KWx{Gk_PzY;!Ret$A8HXa^8al^;yu?6l%)s*x0VS_++#1 zvO4?2vZ*FwiGlEn(f?3*((ehmaA+-8&yrjU`I8&jBRL0V-j|djo)(4Vk7NS6{p=Q= zSnJX+5&6g$-{X@#ClbcJ$+^AU>+PRzBBxt*G<4->n)aBd_;BJ}oDGl2v1dHKbJ|Eb z)-LWb;%?4yHGG#;C*<(+K%af%g=?Ey@Uxmp0zJ2q_)>74ID^83o01khBBJ(nM94a| z;1$@8X8D=0rBS->`iOHpgM)MxtlHskA_l1;1HsY(uklE8M>$L$ec$}%&B)b|bdD?H1J%3gZ|Z;6 z)(f(ha(3);ot)RibF_dxjaor07q}huO$J+CfbM7U50waxmmG8jm>b}SBY=6N-X${G z0-Ar{_U6Z~Aa=wbj;|P5e4vDp-5y+edy6f48X_7^9TSBA$+tj>C~wDDARY5B-EUIC zZ?trtbBD?{+dV201B4+zZDd1}fL^%QL)Xa9JxvozBRou+4pN$P`2V>1$&EmsCbA`} z9xu@vEht-Hia~R&@wnNnbQSRlB{VbUo9!soU%BDjQjb>&efh36kp_565ErWskO~=5 zcsw;U>ZnX}8EmqGXTSWD2Ssl>!|)ANR-KI#>`vQ*?KXqDbN5d*@sUTu34`Ro)vP;?M^UcqUzC~U^Oe0u#m;(OO116h zOgx`RS^@+O`{rRN6KftdCw+2KJrTMothlTY^1>FBKnu#0l_aOm-WdxpyuRP5i zNzo6*5U3(q&~*@CH=g{jK=DFTHt*2|pgLa~o=0M6l-j_!J=kQEBpdC^+Z8<|O(W87v^;HZ@1 z{jDq<0i7QbTdP{= z#v(v@Z2~dX*KsfcP6J4wq#I$s-s{BJM|ATBJtQZ!EaMR$Y(Rg!H&bvf|D@Lopf9IheM(6}+$`!CO1rDZ+VoV_ zqS`#-xoo|a#fZ5~o%uI)eR(Mdnzz&puOt4^VIm%x{K-PW|KwA}Rg7Q|AhQO3HCOe;VkEWIu*P-u&4;b@)Sr1^ zgv58LA%NtF-Kp=38ww^j5g0ds%R-^c1v3Qv)gR`7qu2>--tDpTUi2LK+n9puDUsi( z5g$JhPqmC`Z>St4`cG&21?GQ0_7FxL{&e__j><>IlIk(eZU*nFh<2;WUv7erO;R?-_0 z;qAuOhb6}NfF49Rh5ce0kDJqCH$I2MBC`0+EX|N+Da=~(^J8zQ1n5mpG6n=nBi*%p z*{`uYl%&ljE>r$}FNQBBv*j#rilwh%rsUaP*PBesD)TJ1OUYk?Xbnl=HaLyEaHnJm zbaP^)kz!DhB9d+m5ipUnMPwPv$L`@DlPR%9MbKow@A7cFc;v#?c&OCi?wdg%PgM%= zFGqb4sDplDAqEI{;?>IT z#U3w`H^*?3mu?L*X7x3FIvAJx{Bpe>;cS#yR-X!g# z;&AS?10g}hk8JUX2n#i}o?0otN^>Ah%Te%_k`m+PS+SO+8cj-jz2JI+edD`oEJtwI z>i`jehHUA3B405AEO9kkG`kIQUL#yKfwr7-ZzUB7H2Dj|3ylS8T(!O#c>HgJ`Osgzn+=M_PQ@^@ZRS?4OgHqpinPweBe(nan zdB$QIVD8NbgZhvwEM=4<;7|W|)>8>UBbTt3l44&$)IHWyn}~#TGrQ<$mdo8Q==GM7 zLeQGaG)c_g@e&pk=C10Rh;Aw{6TJhZ!My#OQI`qH&LyrM3|Ch80z6GWb+dRFuBnCt zby)Kcr|lqfgt1N6e(DE;Z38?WprQX4r9{tHR^_E^D-(Ff^suGC-Hz=%?1@>IAIu|M z%Y@9~A^9w|`q>a#-NOELpl=@tcPg{4%2!rh@(&!Qd~2Bo*r}Ybqxl=FZ<0{#aLrdM z&4y0e#a$@?_0jJ<%LJ&X%Gin6%i+NEcsE&8lgJ8Bf2!Zb`t;9`1{|9-lH(F?A_JFr z+!K>z$6Ki5oX266UYL6?DPoA&TVyawhoVg9Y&^cdf+G&-t(c#cjBo}Gp$+MTC5S%; ziW-t17JMTD+o5axXgwSe+8-7Y9LCOkP${izu8TIJFyWi?rB>7bJ>_$gnLJJ{I^h}y ziuKZ&CUU$=3j{}0om78Uj6v_EA2pyWzT2Hlwep7MS7g?>woY;SK+CNsPC-2Y-s+YF z@%!|w&`!2@tNrlEc=gbV%RVqcaQf1A5fyb{DKy+x+!2gFk|K+4v9z6EDPwTd$;Aj$M49p;Bi%! zTT-*MzitC#-yitZFy6Y#uJAj729gK5IrXHi4whawVM&kMS?9yrfRP|$Cd5-52SA0s zRNrGV!K{l@1eo_CXYOU1;GuJD#$pB26X0UP*H}=1zC1fHh734`7Vg>lfHnJZQSNtr zLpsr$x?n)l8UuG@M=CV|PJKt(3z2}g$Gr24_NFjU>r@^2{rHoA`G>2HmHU7Z@)_35 z1&;&l|DS%uGoz!_ccpTtVGzKBroy;?O^GSf(f$Q^wx4<>r~Z;SHS_<_5Bz>myD}ZV zX?%W4DO0hD;+&?2YYHHuoHE|Ld3Xm{6@|6|%*v@xl9RW6le5w+3`fLAqT8I0)koPlmBbw|wP=*Q&-vd=+r$jZ*sjd;*kF*-$B zI(RwT?&(ptySCDLHp5L;N5N=*Vtu7ciA#PC0=l!!54xpCdv+q3dq=VjdFe#UmEb!U z%tjV&Sm@C)uVJ^fq^R)e0*O2Yl3wksi93}1gMbBArxLA>E>nNHhjzM2K-=tCExnhV zAkBuoG&^37GSD!LY9eDbWBD0PUnD)XXvql=P6M=9oumNH7)Oa*UJe5C7qg+IunUFw z=LbzMTg~6W+jzL!NxCx9Si>E2Os5$gs)K#Z(;714Z>_5n;_ z04#NhjEWX~*Ax6k=Zk}i7_M7K5zmBsE-9r5V>Ad0&S>nw-Bj&HCfS$llh*_Fw=FrE zahr2K(_m{VsJ5P1b8TG8M48jXy2)vs2rz~x?~_Yt7`C}OeSj6=5UzOli7$W*a1;fng!h$bsoqI z6tEyKj|2}Pe<#cI3&IJkenH1;Oe7|hzDcK-nEEqjqKL+vDqB&22}yr3A8E(ua1%BjR|#hz7f)QKMMJ36_|6i^970Al=cPW>!nGg20*)!VLv6 zG9BN&Mv!6ahR_vRMFLlI9;kH5y~VCVKuF)`^5~^J-mft>PrG)EXd17;yl)GCHfosl z-g^dLf&wiRjx%D%Z{c*up*MbB&;S|@mR+6(GG(CE?^4uuh8mhg?-bI_w|f2Pcc0VJ z^#opScc^wYoZB#aw*lVH_5pt`rW2uxgl=Ch_RS#W)Pp8(*Ccc2p7td^8cmu=5br4q z-#D{3yf@y=ymd5?{ddIogZ4F$Sn1Z5c4ix|yx8%kZr@rm>7Lqfv6{`VICM&+QI0(qMyddhkHyr>wZh!vJN_Y#FQivRxX z#<>R2Uomq4D23F1|D5(&O!a1@Pa#qm0{X>@gYwt}tIcV&hFLZ9IF2;YPNTS)@apUvDui3gOy*w3> zb44PEgPE!4k8M#j*QTW3yjO5_+`uk&m#H5xN*J$H?C`RGl6Ro*cUXGkf(#M)XH>!_ z@EOs$gy-gDtmCop!q0ug?aodGXTZNFafDG3?nz;T_KEabAXNR~K};W07G$J>F*|xq zJzlh8)VZM-hgO5SI3IiTlRu?Z{@3x{WZ#nAk2crN21)-UQd?W7s9cA2+$m^R;rZ_m z4GYxe-_m&D(4Z~f+v~;X!0@IyVcySNq3P|0|L%a^Ll*-1PCl$xxf}(s3aPToon@*N zeeWHSc0D5ecTE{e0!Q*EIg!U|Xv4Y8jAkXJdBs*t5q35vR6xC48XJ>WZvQNTju_|O-+-9^KwuM#k#}w&6R55tV`oN5ZuSr- z7qyvFevPZ#4;*W?;J(Iu(!?_bAK zL*=-dZPGgBui5A(S?X1S8m>RVhqf$v#)^Z}+L7Y(|*6PqJP4 z0V9&h##bH#ooCuXFwi(y^Z!2j z{G);aFsnWV8|MkI$69hREeW%Ebk_kq;H^C}tXRV^ZGMDt5%#oPq`@=Ue*tzil|h4Z z>>zah@Ak>^;OB8}BNrT7c4 zN%6Hbe@K38(i~y}3+k-tr@e>Wtr2UXk*_a2&y$a5i$v}XkWAPX$%K1BLt8m7!$dT~ z)zLkJ9YmvLX$CX)fB_c$W)fW7gam}{YIE3QV$eco*#e{jKZ7E2+p_sy`#wf<$-(xD znh%RePxn-yZ(Ay$(gj-(j%-E;w7Le*!E}8(60E+ww=Ol7HSD+eAUaw;;aB2DR5^Y` zV68g~2&Jiuz5SM0VD3hk>nk-k2^&vEi=SV=n#WN-cR=5mU4JQRq_SF=26%e@p7!eG zDs&{_mo;h1o#`;}=wOiw8Y=4-pLC%@w$&i6|=wBgr^0j0lZfg^lr?AO2bf@Bv)yiJIE^^c2A zV0RrR#{V~pb$aGF2U>0P4k*MfnuY{iRy@1 zN(3aB4VEI;rj6v9ZhvO*+$5Udhe=Iwx5_wn^P&}mrM%*dmIRlWnp(Z2f~zv!5HQ z#OKrvB_g5+B`Y>GJOk<(ERubfgpc(GYkNo%O{XpxK@%Z(V~ujH@zo$__t@CfY9WE* z{`cKOou|EllG$QfR_%(%6-j7R=`;^ih-P6hq!6{9a-fNOI)v%<5qBa zL+sR0@@r6!X*VPe{s?Ua-3RqZFJj+QgEGoW9Kl4 z9r~i;1vmS(mu4_2gsdHtdv{vC2$w4+R@4Fv1|d1-s0fs1&nr+XuNcsx$AVuUAZwkNo^CBDV;AH@Ku_ z`Yi@w%@SR=UFY&s0W?h!Bc|4Z%)n4n-8+*zYd_B4%pKKBj(g1bAA}94UVT}*t^3G6 z(zvBl>gi7i_EuX;Y6zeDVP#0Ai}~STv6_WT=B@v*ko0+G{nHNCqL&Q>cxexIXL_u# zq4eaCcaE$MQPB&WdV9e9FByv|rcQP>sCU3wm4*A>%NLJ;mUuGq!Q;UG$$kF*iN`P@ ziKaK`A_M7Q$9u1r;%>_7P3j5W5lzz_pPhN;#RN=ot5qP>iPRxbwd1ACr89rnP3SrU znu`MR?kfu7GJ&u(4gkNYI=2J}9WR#w!E1r|c5ka_JLClAZ0-$oeFxvMf;ATh52MKS zoORgu)+X9hna3(QG{vdURM|A-T*U{1}^#r9t z!uX`RI?ZqGB;WZ!!S?g6T5ikFBk5gkOzgO>cY>N%7+@5-4iw1Kq67v^6n^Z3aHWe5 z$V6J?T(*rt5XdDKHrsJohn2_cY0U^0>4G5~S6>|9nGMv|&)>g}YrKxW7XGz) zYWrjMjNsFCSx`4@=*{~bQ3m#1M40TE$r)E$d-@!`TAKg!nKAT42hze<_gKGNO9Kpp zrX_1^Wy;8_uS{_%TRXdiB+Oz(m+bdvrzu^8fhpgtPC%_)eV$Jrfh`{cp@j?!BvcDt z9PJ1{=gpmy{woP`XcJv`;g{LZwF^rVjk`HYISKxgzx-?+;ma+2VYx-g5`AQ#$jf%^|=fjs@BknsJ^xam-_An@MQRP1O`t)m- zxmT(-nMe=0G~1(A+w~pFTlxv@SXTI!3(J4PvR@9@okBVzM#Z_%D5%Aq#LK$|GgD0# z)4*(3iNu;l2wR|ER$Nbl?y)UL2X-TC_)OqBX^y2%_ew8Xe9S6*w=UuV1-?X2D2XojKSh)R_eV;YZ&-)fK zUs8f>kpdeVn6SIuvrl*4eo4KKPq_jfKM*H(Mt15`4P)j^%_Fp)c=>VjYiB!Qnm1+? zrQ8W6YJ95`;Ix*_-gKKFJ^zAxgjKG@haR>_>K0Djk}ohx4g=?=*{csfJCyWH?p&m% z@0V-vD2x5JHfv@`Ju7nj%+TarZkOKiGwR=`@VbjoqCJZAB6f$USclQk__6f7N8=R> z(XC-tk8kn@XLl%$!ZTo;dh19###Vu;xix#=Za))>7sr^_ow79izt$7s^qh^8om|zE zMR}%k2HR;9!}Bi#K>6VF>k{kGIs$+DfYXoM_GY$IXF&Q=TwbgcVy-1{TI(vCBI?jS zrX#UKXhu~U;PSWKYG`t@sA1;sYVMlfYd)1dp)yS(tiT(-$xs|^Vig7tLr#m4ZJ?>* zZrD!KeNEABShPi?E2pk{tVi-{bj8myodjsuz_~?f{RIn~cYI_oYA3%S{uTCQ!YF{x=1pU~PqhL2ZPO){9jW+!rV(__O-##8#RQ z)Sg#)2}eXgJ9JOH3D7&FoOjAq#cYzy(^$^Aznra4KlK_@Y3{>{%;F&=9Ep!8j_3!` zk@YyvuwFeU6BOO3e4dMjBsCmK$)c?cl!Jo!t^57XoTgB^(;_LkCU6RZA)X>oE9ac3 z6mkaWAHeh17;^31Dll#Sbg%?_DbuN~#2CpJ3W}a@hVPC>07ZLrSo}x&Au{P2JvgI8 z!XEy;H_Z7pa5^%U_JScR*Mp?I0FQ$^E@qOXZ(Bh~64C=Ug<_e~v3O+8ROd3WrLIe3 zC`fCbNL<|yE>U|L@^k7HO9VsIYt%om38;u3*~?E;)Jh_UqScVLgXPkEM61t?+m(;v zacSuS*!eo>Gk(8Y{mY^du7huV@|sFD4QEK*vqwb9C?5&<7<{#hS%-pmfphhfnLWe@ zj(ny;c%Rwt9vy4o8FPXF}tG zZ{0nQgL-kp(WJRs%pw3F(~=$Adx<&k9KCeyc>SCvbzGe+y8X8A>mfv~+9@jww*{g5 zFE#diJYD$#{5XsJfEF#}7Y-?7K@fbLY=UC@w7~ulG6joB13fs^!*F zn<@{XX`)M+r}p_g(?nm=iGERQ=*2NN|2&>?VDwIA_O1w`S8sP^uW|{Z5=_Rjz;ubT zK3K~1bm*}wS(fp|G0N^VUYAls;u(P`ZB1lrG=YL$Hopuv!C-CuL3K}(AQ`iEkRv(K zK}dx3gg0AVaB+srx+EX*3C|c^iIC+P$Q#7MQ-)kuJ`M(%E@hN9ZY9K7*`LYzTr#3= z>+CKn6g=6sHf=v6y-PvEyTlMjJs{l5PA=-RI$iuSl9h0Macy^J?w9ikLiB!TYS6Ch zCqlDpG>P#wQxOe3{P9*6G4AlxELqI5=`LwMj+t{F^68xrb+xu8iWN?npXovO4qOIt z%!CYhp05enuj9JCUU#xIL#D8S_*GD9?9=o{F7@HU-5%tl7EMI#JDXq;x7FAs8D&IC z^MzwY0MR5RQq6W8loJGE>9=dHfiHl*&{0-;bebP5RgeH6z5f7_swfG24Xv5S0JmI) zTRk&OTFd!_NJ1kCIU7Q$_s}Qo*95`IZf?qW{OnJV4m{~6O=~o_F}CY5SnnPjYl{jx zh^pH|DFmEpiGjyOf3^2-)4k+okCA=%kSlNn`DASk})(cEKWzi z1dAdf)Ey2o5`=@Yy|k$D+Ncx{^GVuVl{K#|43SJXjW?aqq-PD|)u;Bk+W1(hTz19=AS4d$9b)#ig%0WsWXd$V!rg!&yP&5nJ*wl?DL( zHWmKO#Q)s0Fvc|JQ0PK8qz-Xg=NsS`@Ng9zeC0|!t1?#ga6NW&k-X^lj*;!o`(k4! z+LHW=_yK;xd3T>RpqGLLNzQJ(C;R5vi6a$*7~9ABZFAs&3#_*$+vG|4ndH^T_2~Kv zAume%$?WIS7ef42>c>olr)ZUjl+`aRRbv9{Fz8*7sM&M-dAb6(6mG(_PUrt(e48ilt0!#`ud>{v>ZXo z;MxCoX!WnJ84nCcaE3G%R%q?tpq*}#!tZcPf{U)5D}a78rh#H-C5dG0Z#2~=SY&IN znM$byuUt?%B58<8dGroa0q@cPVEYE888qA;vfEpZY*)f0n;2S^4{jaJ-Rb+tk091% zqn=LUdEfA0gQv1AS|RpLOX|{YY@40s`Z@6;EYl<2nxq}^;ZAs7WnT zTtW zp)H_h`jkK6&)NPv#$4agzTqXu8~5dtx^%|ClZvJNh0f^>6&mV#B!3zLpq{C>oc$)*&T4PRp1;>R6llyb)tn1R#DH zy>z~>QLY)!7IYN#><%N@0`il^PBZ>YshoMlFBXLs?}c}cLN~5Xe8~31A@odUrEU(-!R2pNf^ z2YCE((-gwt1dGs`G|yF{;_CzXs>nhL+3&i5*&N~XZ@L=`?FZiCC4!5{PV`|tVlpB$I5J~PV;J(@WW4z-5sZauK$f7iLUnq zzmfx`TotAdYyN>`ME^oE$}?^+#pA<7TG=X0+uux(mpGF5f!UR*#wHAxC}vppfL~{o zT1n=QHi|teF>(jxQs3UC!EL6{P%^8(c1EnFI>^a0MKnf~MSHkUf8kq0WYApD zI7N+RV_?lmbYOC=*8_T3qCWpFf$g;ZjBet6Jvm3QGagztJ>LPQ$EP=E;lvCSS|9Jv zI|q$LS3&E1$|ZL+BV5*|_1hY)QvP93Jt>1lGyuEUbwLhOhLxI4|Z z(E1d!6^bim-3dvnY>0001Ew*b37kN?L*`#zW3K24eIu2Y#ndFAU7L4c=T-vnM7QaX z36Hb0M0BL9#&+KR)W#NcxrjE3>C_h?H;P()8udG(Hy~=99rwwH0K5Q-04mD|Ia=>H z^--CGIrn}9388aWl;qn{_Y~cTDT1^qJ^>|Z$%L0V4kM2WTBDwNSysA69`3^?Xlwc^ znKBrr0lPKEjbK5J*K{_gf~c-~^*Hx#(uXRH(ZC0BQ)pvGV8khO{74xf&E@`NKyT<69nx(y0U8^V zu4jC4H0gh@vqob5rBz{W-@DaO=A%+NT{vcHBO%uO1vxmqwS?4U#qSI&Hvnaey zEpZInk+Of-%UD?GwZ<6EN>twzTHNy`Rbg24o?OmoU%_6=eRSVkFxl+zciAPhAjI3s zIcxdG+wj3N)b=|fSH87X7O0`1|8bW+ZV)jGT%;PuzZr{w<^1Ea#OhKLn{D&(7lfx|P(l%?#uQms`)~w=xouS9h*Q zp|^FAq+@Nn{0|%!`(bXDgL~4J%T;gZ`Tb6ZBY=@#Mn4bQ;St6rL;XbJ!YKMds9KyC zAgvC_ejl}*dXt8031XW2(>bKA&`ixu#KuYYwdELTZXQDxx$esx9e>~aimB5L%VrrE zn{bVDvRb`X-FDK76hUpBTYN|Q{JlrW1X<^c0Q`WqC2Ax6BZ-ToZ5l68a!(BCN3v{q z+?Lzf6ALV*-`7n+uR|)8GPvSjtm}h6Vt{3=DcU8W8pkPlhwXUKx4*pV-Yy9|!SN>m zvLj#XAePr~2?|AhdA-O#`849@!qfA}J*n(R4J1=U8iCC!p82Q?z7@Lp0bcd@b5e!A zb>4Q$;o@b*#n)54n~5F0LO{wJrc;!44vBj#K~Wp;S2vcz_LVYfH-+ZXBp~cDxU^&i zIP_?MrD}FyU?q$Cp2MVlV3oKZE0o4I3h6OOXxganW>^&5O^IVPvw!*77-=l~zbq%_ zOBqf2te8k-vR(4-SeL;tI}ISI`XbuIfRagY3K+}X^RaxFY7`}re98g*#7n|yf z`k$TBwghz13rgz7=0zZ;-u4CLjr$r~2`R*U%HxY#8L^@IEBhpEHA7Vrn)iCnuYQX( ztX8S>Y`G}7c8Tr-+C=*8JR>)q+GARL_nOxFA=Zx5tViitsBXWj`HsBLWaQ0LL)^RI z;w9W89}^rzbZhA)t;;Y6hquJ`wXRjD}Q_7JiW?{uxVN2JUvcbn6`Vb%#f- z4)$ZEESKNc*YHIv&MUBkw=#+>Fh`KhmoewN z<0;aO;l(CL5}8x^4^hJPW})BlSTE z@}HxrU#Kbq=o^^K@Qv3oSVyY-ruLniCG2acxGkEV;%BdsS!Ul9q8TtF`HIKMKhTy4 z*3%`JU#@<8f=+fEPpQ!nu~#h<$cX9NYI#b`nQOW8 zm~tqqBpWQxxEk0Ply+o}UW_e`ER`*dAdV0Yqgi}?-B}-)BXx*EU$CKpi1=2dAD&Kq zD95^w!G^kiYcw~91u9jC{kn!>z`gD3?$3x+0<|gde!14=^cQmQnQe7O=%xnN1Nig9X79p&q;0H0 zKp=kbRYK*F$sc!hi#Hd7Rc~X{4L~W66qeVYF}fWkNAE0AA=TkKbU)B2*Qa7&(C-Xxbj^x;6hLz8pqBp@EVJ5Bj`B^GAx+P<2~< z8_a)$S18zvL5T9EQh}@rP7(T|wYbbiM7x-6W?Rf-v@Wg|m; z$ca#O3=@y4PGHT_6M4!R{=}X1I_<082#JLQDNQ5%`||OdKM^MSs#%+dWxnle&W9y} zTdVE*6ut}>Zf-_QHA9y2^iw{teIR0Ik72zuO-Dpmn}0HbQ&(Fm;J!YwzKf?^Ng zon2=8*j&%z0dLLo_?u*+0j*U;>e>Ft>)X%mLv_J9Pqf3Ui(TXi8RD{Cot?{7rxfni^=b2Pr#wVG{=%q$Mn_HW8nwys-9ZH2}T}S68V>xaP zUG6|epWKiSO^-K*!9T`6QvvbX*Xa*QvmSqHgVYooHzvuHwexEGvbWp-jl6zx@>O#> z`)+RV%PjI&3_?6sPO7jnv!j|UgwXD9f05N2eyplMM+u}e6D}g&_?a~5iPaC^D3t1j zh!d0lj0>&9It{-Ebk zGB$K++%Xm@Yik6^e=%Km8ik&^y#Zuq6R@+@(a}w89IC|3GQiC*d4t6 zJIq;BKDRtxQYCIV8|L{)_~?Zj&Qzej>h|O%^7k5k7MIl8Ih7I+Pq4q%%5HSk`mtAI ziuuzo6TPeG!-*hu33ncC8bVP6S^Z*~chnpCI-g{$NTj87vC}OvuYu!9<0Z1~VNW28B!*~npH&kh0Xc^6F*@) zTW<%BksneE60Q{aB&)}T1=&6BK&witj@um=!;rJz-8~IcrYji7Rld&aI!Gtqls<@u zL!%c2bkz(2wbxE$EFy)?mvze4sR50Lepv=gmS5dskyR|ACy`8+U6VWJSveRnYAaPE zj%v8hLq{O+uxGpEdh+D{{!k=3SvI%mIrAL%?N5n6GWqS)2NDot= zL~H{oqdjM(c<+y(MNol{+ILgbMSk(zc5?{maoUy6F!GYp1 z$w!@}*p`B!NCyYdfa_G;Jm^@)QV@-;?>EdI`n7{shHFc)(Y3Co2BI+02sF|i6FRE_ z#u^}gkh;_XC6IFkhp7>m9$lUZ?e!3W@uI_@?Qz-)=q~cNywF)}hTtQA+UVr5&iWf~ zJ=l@7w-K1IO~mm6FR2>Wz=Z6kJnroH|r=GM0&IrK&tyAo*tB^vb zR!4>g#!YYgLUDzypF@G6%y9dkc&rbTb?cawy|D<3%knAdo; zc(_-XPJodZReOF+ZXHm;ehGNC5nfmbKyRp#Bxb$+wY*88{}GX?p;w^0g1q zI7N$Am6w<07DrVU84%qtzYMP%=h?DNoPyXcEVoO$E_lqnhql5_NLAoX2Ty~OfUby? z8x2fA|Ccwb@4G;OHn^m#B{L)u=Jdd$m_|gIWx{&7GrHKpn@92g5%x~em3`axaGZ*5 z+p5@hg%wt8+pf4`+qNpUo$T1QZGZcB?!D)p+x`#V!+O{cd$l&_9IcN&#~P#e%C=^H z;|0i|E9i~#oxps8VSr>4xo-`}{hg?WC038#HVBP&GYaK?%+MM!V#gobiTbr=OI@Jo)%*yYiSJK z0aI9`U-s+SQ-oiZ-^-454p6{SS%a6e?NO_EY(+WgZ&BjayKMc&9NyVDcyznS|890g z?lpy0oo147B}6VAwH+d96Ny-lVfN+H=oEf44qpivNyqx z$nXY>83{75uDe<|M$EOXciUGb=;pVL`wbxl>8+EU3Pqsjr9rat+6ySF3E>5sPRX!; zU?@QW%8T*8Ndfh=xmYNtB$;99Z&gzI@=RsbF#B@{T&D43(cY^}QDQkntf*rlgiCIq zgS~*e#(_utF-_kBsrjQr=s!M2p2A785LretnAK1Zuax6l{BgyZz7o~wr4PDRG*$BapmsoF{K9x2oVs&Z=X{Xj1p>Id9S%%S_;Fr4AIPK-}@_N4S8{V-{Z`SDMy5iDgRaqZ3{%yoqy~-9(6-La?|P-CI~o{ z2NisL@Hovr`MLLoN{=;BK5xD5QWcDv6AzlB`r1sQ7@W0?7Rev^WB#;FpNXWJ+1$$o z=IR9>JU*6eQv?AS0>59I@6G$_@3Sriy?=SI)+ahP;mc=UJFoC{lmKA<5B>VHwwf`+ zEectQYM`Vg`vJdhx%W9n98T^K@EfF!q%?peJQ(QOKut@I8`o|Y0mmb#9qNUso7?>~ zf6^wQ48NmwkE7VycbEUaycV_K;@uCGvFVQIJL+=KClP+JYaSuvvg>6JP!YmGCxJqz zkMKC3F&v2P=Juy9gsikcl7D;BV@h|v5+5UapUO-da_p)167Rqd?7z}TIb7>P=2tGI zyCcsdF07 z)yh>QC#uO=!|uFP`eW9v$rL`O+cavhQCnPzL(E{zw5r#!I@ZBe`BRCrvf}^>^)c`5 zXk3e^+GFzRDP_v9W%VNOzr%GZ8LGaXW^|!&f(+p2YgPI(6jwh;^{-2U^@>lU5Q%)F zQJv4|Vu73u74t@`-^&E5iKa>z zex7?|1J4s18E@u5-`|>^_G=Qp##HzB1-=x9ALE0-SE|SJO-fx9ow~qd&T0#H{mtz> z=G7fkJ%hniZ+umrc-1javh7Vf?_9)FM$lp|d(*TPKcr(~FrgK$&ud&gqd~@ln7JF4 zcG*csA}-I}8P&$l!`_JPYM-k4st6Gq<5q*>C1dczU|bSbOOV@~TT9?oF;OGyj|@Z2 zoEA{|qot!ortB}LA%i_u>if?Y4(7w+pZ|qOQ_1Ozh^!0CI}KO}vXgnZy6bDJi9)#` zChVhoV%Na-Yuo>3(n1VV><`tDs@kq@4z+u&EQZsrf0lp>?^0!`wNez;qEzcS^TMJ zBzj6pBicyrUiJ`$kB()IAypZboG@U057ry}i;*o&0w@#Uqs}W*>5+tiHB=WowmRicCh5z z(&TGrX>w+@1o2l&IP?tQk%O%#~Z&7MM;P9p4vIwr9Zf>fw2oyluBfK!wkfWo8xuPVulE|Cs_+ z2l}O)2lcXh1=sre(4VDaS$g@%I-Sn#RWw+1BAiQab2wY8^O?LJA7ZM zIX3L}?cS)fB(A+j+ntn|)n9O6@;_FlTORi>e7pt)l_Peh=557PuD)0gRGL9Xm!B+f zT8PG=m3CM_Hj#$PWQ3)yIpEeJ&(lp*(fLEdED#X;g6_YokfJbWliwwApR{wwp*4;y zvX8$!3!0I`K&l}|)XA|{H=1`2UpY5)2$5p8Dq4|yVyymF?9x-483A;og%Im<}S;NQ)k?hoS*mUtObLnAA z$r;+?i3E00(h~y6>%V(}PkFQGLdwb#Dc`%kNqHeUY@dNq>D$E!8V_aOdjaV^)R*jz zmXFkjy@y`kJ>CUr=882MN7(|6x=5u46l;;GE7IoAs_<+*nn&fEADg=;h$K z+a}14%r)K6JRU5hHnVPjvANG1PS-ka9I8_PhGrD;kjoA!%o}%D`LLSapzE~AbllF( zY|N{I_%YvNva$TP=FT`jV(n@8Ic}b4&jOK&S2AQ!WDfYA;$jAE3MxB)8-gnWeyw>f zXH<4u16D6O9fJ%UjEKdw&c|YHFPEqG6RId}(MP3ry)QdVHvUB@Kdl^G->>)4*99so z@a9dog0LHULC)B|x6zdcyqG1%&;49x`S; zR|iuow57x!&2IUjJIMhYe)OOFYGh8J6KNd+A%J5gUfGIey4CL>7*!EBzwn;{KFG*m zh|%6hpFJ>+|ATSJ&5b~DQps;XACppzI*7)S&x{l} zmFc3-OjV{{IZesYh72_WC%}DI$sXjx!W>IqtIRjqVN2FH05SCkZghvl)OCbXF(N#ip!jNaCqoLuXR>|I|#SNNla_ zZh6h9b2RhmDR*EbjBZ`;~Ko^6ZJ1TWQ9oE@dK4#JQW=U zq;QyEcO~FonLI4+iqGzHqx__f4*eMbcdQ+0^$*=-U_4GYFU=$$Pz_!Z3wzDFi&tj4 z&X?!cl4p{GetZnd%Kbg^Rz@`LQ|iDV|2!{PBx)Z&N{Pv2=}fS0}?!N z9M2jWswb-$q50L4jR#Vb{L;1VY|HpVr-}YEq}D^Q@AzY9{5L}$GKDkzyT%`_@lGkp zBzTj>CrPA5BW#Dcuk4mpFX&;|iwB@o!i_#eZmX9N=@iY#@-nH*yyX^+IfDLD+|nZ3 zE0*Rn2#^&-eXJX^C5UY`+$Q5m#Zsu#pQT7H<$Sh1-gQp@cllrg*zjwv?iDH-&9BGx zo%Z$Ll|D6LgDEWME2TQntUOGpuwwLKWx>63jyJUCk#eZWaIh)aHh`6K_Elzrdl=_{ zVq|zJaO`yChFPX9H$hBchFa`DC?+ttJZQFBaYJV~cmGx%#}9?k_MMdHN(03qf1a{4 zXY~gXZP=Uh7tlnzfvr z;4^E~#g8Ng_v1?nB-GXw>1ymhz4B$Mq+H6`b?7FUQS}eYRR9 z*11nPj=4L4tvp}+!;Z6*MDdEP8A^|Oz`JbnIF?H1#r(8Kv{D>YKH;h`FKAY~Mstrt z_*Ld%#xxR^CyPkzOUEc*9&u$QezNv z?I5K9Cg(s>=g#djItoutQ0m?7DOY4QK46_El2MHd_)oyF9?AwtUns%o#Xy*ds{1ck z3f^{&u{p=Td8pNxtZL}x2@k@%EMPs0qnZu4OKGwLcBunK6N}1q+F~y!rVI+ye-=_~ zDgR#YJfvDCPa8r$h~+im^3;UEDBWba>B12|7je5zape4b$ihQUkj;+9)pQVLDAZSP zuxS!}@$vn$Wpk~Eq-*iy3RR8nH5;`yZ#kgc3cC~@i!Ba*z`eJ6 zw`+gem(GkTW&S%z!b1BuU}MJ>ynr;*dGkK`%jC(%{56ie%=L zzPUg+Yls?L!LV0Ro?XzibT&$s6xrvPJ8IFPGSem!ff%t|IJcGXF8JR;h_+q+Ai&bh z*G8w-fiaxi=3wN}Q-ad{9Gg}IIoGbYM93lX?rnY_Gr@x&pTspXnfLO}nniB#C~zpB z|64(fg~9#aO?wV>N;Fk|&Tx|oOPh5Jj}TQ|zD8Cd5^Bw(7mC1^^tl>po@`V36uI-I z>9r(SWJXK(R>U>;_bTOY{OqBzFA;9MvqAL%GgV#Az3c)H`%fFX43VD>mapayt%yQ3 zd3Wi^vM1%!Az!c!5Tdwre6eirFIw!*wkkguJ$NjQ2N4=$19WB>bunb7LCREW%N;F? zaDa7`ZOsz6Y3?d!+Q0Punqv|{K%Ff4Rlf+1p+Tt(?{5W;y4y(~SOI{zgIh>dJD?27 z*)t$w=AXzlI?vp8WtG3@P1o7hp-+jh-Z`f9Ke9>9g77|yn}+36jF}Zo(R;f3jj<`sIt&jlUR2J*K*r8--n-CO~F%e z-%fo?-V(j`?z1dc3<8?B;p_2bp7icBG}EgUQXuFMh`If)1@9&)g%54y69UnZJaWHO zbG^U>J5D~gc(#df*1%azN*T~FM98~4_+XC3L|xQT+tW+X70B(Ix<7)6sG;r7 zc{XdNGB0#g7#ZIB(QKpsOH{xQ8pHZQi6CoJ{`r{`*57TjcUo_h2>%v3eHj0zAnAS> z{V2^WW8Zse@}ScR7y|h5Z18T?{hx;_&n~A4H%3-kM_4nsT&I*QvzaPMa8S}|&1Nmd zzbM?nl=JoSfMic6WF>QSBu{^LF7Xf~2abGUe4nlYvDV5&=3Ip&4fwoN(OZtWVJE3NFzVhw9%UfRq2!%M`<7?a`ZU{NB8UZOJ8uw z0hsn_Ujb=ah14l4{b`^5$LUF@GJ|s%9fUcS2=5GCi{(q4K?G9y$(Jkgp*h>n$-&NC z$%sgar}$fhV}OlGK(%Sk`dGAly7kC@f~H!G;1W?#SlNKQAzfY2DB6~YB_Qa4BEh%` zRZnuW;R8B}h2aYs>`^S$sd>wy8dVXa;_9kk;V1_aQ}6-FaQjPCLfncYld*vGZ9|pK)Fm5y%g0FqAqx-V|G-tm47V_Np>l8e zSlPm08?r#)53xvDdsyx4`e4JXhH(p;zmP6?_n8fXfgH{KBsRAsVbXC&i62{}jke}GkMy-#VsZQV~d)&B=h{t5qB8ORFS5;dxR(#jBfoINmi#5e|-YDMCC)<4!W zLP!4)mckF5hE}eWhS5-R6~OJ-Cs6uq#PKDdy!nGD*C~`>!?L+Y$)#a~;kxGs(;L77 zbecQH{`kAdk(wek0A@8Sg1v@Nq8pzS?}dEoTVHwQ6Koj;H%bX{ev!6y^fdQ1%_aj@ z788NQmI_?@8m%XtbVcBR=+4sXF&}Te=er_O*4e7j?dXqX=rFUlov{KZexM7pYZR{@Pzv zr{#(ThK{4< zgEVD>!J(;T9siXeYVRD;-<2y#I}d-7lLcNE1C~aF^woOt`FnMd{uTy#Ij$eu)a{=(TqgQHi;x_OgQ;Bu28UI|}w7^i#o76o>*O zW$SF2A~G>OM5|=zm(fXXHAtk_oNmeyXSs3DV7B63KBZg%(;gb@Lo~vJat@m7xdU%r z8@uVx5|Lr;yRbaA-&U{}4UZ$_|Jl$l}?%qo4 z(`8Ps$>mXaQZGHC(SqgmJ2o>e(`272!LnqZy{Xa(BJsDbiUeXLL91#iKT*7r zH;yMCe~cgu>M8rOdz}V$^Fy(MC3PI~Hg>%0nq zdGh^MoXK_)smRNb-G<_)=BW94OY(^S{Wqh{N7oBA>-YPUi_VGpgo)#cnY9H4{<(M& z(^m>L_gj|PubW9(O@oVtnbX>;5P+4Th|F}W>@PvrUa!F`xTdn8HXUhu9JAnux<$bjO*dnfP`vS$gI{lav>D(}%9t|8UQGWNsi% z{ZAUNAmwqJl@FiFbCQBP1KHvhUCWX$$-tmS6abwn>MK3YN8u^45n}hAP6$ZZw%NAM zW7g191)KQ^x2h9Drj?KVTM`Aegcyv#{+UN&`zLnPlzPA@&+_NA`e!CX7@BHbRMbr=K&+mP66?M%!q zV&^Vp#0*j?M_TTfjs4`kUxli9f9*PW5|6SO|KbU`=Sa=Z^4rzbYscKax47~1)|ZQV zMB}#QNxR$Lj-H1x<&MEWfM$^ycWG-5Id!(~zYKrpS(!OuPY3FDB^mKaqS>_abvacq z>DUJ`MG)!F@w|S$kJsYy6I)$5#;oi265`!=#pS zzwXog_jL~Xo?aegoG~O%vny6<=42n+s_Ra0FFTNEdJAjHF@PAD_HmN##y(|lvh-9K zOFgwPe2#incIh9o<^r+~HL`d7wPr5#<8%RTjBG5m)GFcDpd$6Uqjmxa&J^V66sc9> z;p~3p5S8b<$jJuqD|E?V+0Oe3d}LBoGr~mfSISI?uSmAtUI+$trVPUa{)}-yuEzDX!S2yBD?TS~K+)QxcLyJm(54M@Lj7J9nWE zZm2<=J$N2e|2Z41m~7Ii7a?D)4E?c&p6{gx~C7T z@kyTdA4i~EOSd}M7T1!&)loRDm5U9>=ym`aIrCj6Q&zhp?2-z2n1-+)K&^(L`Uq-m;&|11C84>VOX@5 zAA1M+yvR0)#2ch!?Feo^)UQK8*_u(@h{JxhQH4ljP_g=qr^V$>>|H2l?Om`Ct43Pf zf}L_eQ2CMieMi&P+Qkt$+6deDus6i1r?nONHcEzngHX4z_*tB{#3dlvK--{ACj+6- zj2+EFg=9*DTEVnY(CQUyZ7%K<7L^wOBO&h7;k#RTpOm~chKY^QNXJZH_|RC3s`Duk zXoAJ@$EwTnqt&35c8 zG&UhxjLP!NUs;S2w^?(QJurM)Ewt!Tm=81DMkN5qYTX2-mu^Ly-X>YIZd-HP9)4&+ zpokySjm&ndx74nsLmQAE{SUX66FG9k%scxul)!uu3Y~mxZ04Vy-DUcCyY;Z6dYzO| zgNV)kSqSN@Md9jYqFVa-Y{RvlF(;mKCoD3`bF7)&l_{NZDPzyG{^9`>rYIS7W8#%9MLS%Kg?77ptu)3 zKsOHGqg6LA(bm7n5(3k02^CBORz2Op4*l8zUdO|Hm2R*_YMhwd+o1b zES^8M6qRrbi{oW4jY+dR-za&BeuUZ;^=omxzB358b8e9J-%PnJ*4Ia@^h&uhrxRoq z3T*i%>)^hTJytf5U^u0(*~w6Wi%prJ7Q~Tf2X^CwP59$d)P<{u2uQ}d2q1`oCl z8E77d9XcJ^9&07D+I;z2<5t2mj5h=#n6!afjkkZ(4eu1@*$9t{5oEoa<;Pv-^5jm{ zTzze+2k-6>Co=KXnT!PNqkr$;QTPzeX&e47xb?!!?66x|b;t`W5Yd>Z3;?*s&~7at z5+DtE1~qt9&;ZHAUV5(Pqh@u2^6M9l@g<&AbO$%)g&r-UnXdMlIvf!-ou<2sJGrv z$~6Y@pv-o!?3PqRuYG)}E2|q zR@TFOTpIVcirDpADTZ71Dlr)6En-J(4TF5B!%vpboXcLR3B7u+xQTaNJ}1`%>aPPq zTcqn*1y5J>7^d-TKI!V4%n31?2Yeg_2%Qf}?U0cA``ae6$N}CiBV<_EPvtH!3;tYDTjH^GZM3Rqom zo}SN?%7lIu>YT8@loKwC)dbB#hFQ$UF(r;pb>FO~-W`ldc}qP!zHnflPx*wqPp9K6 zpJlI`vtw%*kl#l^LVK|@5&Oaw6-rgL7;a<@5kR+l2cVKtSCNeHt$kGz*?fO`(fXim zS>A1tyAO_3h^RXdl0HA=S)<)KMFyljF&cU{4vSy8$ku4H@d+S)zQ4VOWcP`6NBbY)$l7SeR|}42*3oZ1tG+jO<)& zogFPqoEYsLEmc)uK)`b{-3{}AkBd7T2q?rOC?m`EhC(vO6 z|93&rNi-}H@L(VvePI7T3vx2I|M!Bx6aJqCS$9HfPi;MM>B`8?GGbha&us2B=v^#X z)~NFap~8|#i;T#Np!|)mB;^sIB`GusCKn@t+40LcxVZc1e)sIS+ItYV6nL8On(9;_ zB(y=v{#qikGj?YpLYjL1+6MZDygdv%7%{VTJanIZh9G=Ry=qs*&ENa2eP84F@=j`> z$>G@3A3|7o@ZUp-bsi;qD@jF`M*XS)hx--vIFZQwtaY@ESAu4l0e@ZBV_8S$w7bor zaO*j_28EsC`I_h;gm1m>BdQ)Uh3w|$|75I&|84E^X3cLJWNTwwCNUx!{0m0UO)lH+ zw*-=;a@En0aBuv9SrFOR(x=}CLqypY=_#Z-V;v0-z2m$ zz6kG^M9|?EbJbnc-v=h}rZVJNc5{_>BAz7}$k=R4kt~~|0>2LV6sotg!gTS?Wh-35 z6j=KT)aAsIT=uqKf@~yNE8uTdi>A-YiXCFD3bE_iXRmWUp_O^s^OFa5{J0_-G2-Af z2}A2UDFt*>Z`|IWiF`i;zcP^AeBx!36Px3I<#@`n;KYGw9cyrR8d(12;82jm&Z*ji zzj2t~3dOY~k^7{VjyZbbr4s1h>d36T3(oFC>_L0(^mtG4#|1o}quue~lk{_*-23y8 z@VU8<%57jp$NIhukB`?=?eZ~g^7EFq4N97p@1 z5=w4MGi#kb7*}St9TF78_heXh9|zGI&YIq8T|h9ecB3{;QT&;71IzZ=X=_d|$sf!z z(~K4`?6^!s>wZyTmevOfyR~QLRxDn;J{n;BSl-P0d(nngN^NWhs8bPjK*+*q-OBtu zSC&d>QRuG~b*fuM;`GJ#z9)1I8r9tba&U}z;$YUiO+zvnQSW;)L%LPInquErI7tFRL-Xgy`D$oRpogtrq#7(YJv%{Z5 zpjwCjsVQ(zZ@t-0%g=cK54iQy=FI$}_$kr)PmkG2P{(H1KY@QZFez5T8_IY=%+OhI z&2KK1p4SaPtSi}jynV@148_ z(NUA|_K#6zxu|xK-KF%B5~MlhT16O@7t2s{gUO_y>6m*HD z`6-Mso=k@Bt<%6B95CqQ;)jc~20HBOD32rx(`;`$)!8zIDMRwSM7U&-Ax z?c1i|?No)YcDcUB0c<(DHm~pclQg>R*RX`=adjQDh59W;6v1;E^E)NdkLGSVe{h8w zi_J_!=;!B8>tCf@t{W8zsr6%s-?j0gOZLM_KgJa2)X16bhTEy8#A>aY_pIjVAflVi zc-mn}_;=Kj?tg*l$?EmBYk-)&Wb7{&uJo4a!=>4Dd8a-}EGGnb{NjRLfhg`&(=JiA zf(C!{<#&C;4Xw|IpAckQ^Z&RDvCh0HpbP|-3x@HPKRXEd72bX#R8OoEI|cTnG1(q! zA8pE)G3Gv4$eHY zvp7^FT*vfSGsTrr@8n^>3c+zs%c>W=lfq&Lm_2G6r}gy>O9$^dP(AZBw z_LPrWc90|^-J8)-qz4?Q$ig=Ag*jS?zDgJlUDhhNe`efVs;eLkGmeeBkj)DI4ctJS_6LB=r7!Zm_5 z*lK`GVKslSCpgENeH1(r3e)9c*Z^9%^zbrPL$6~4FmmrUd*eJA_Qkql=RFJ{VNlrr zKEkGJw2JwS=jEv7{!F&y>6_^ZW0mKR@Un(1;>F#pk^1=s=cGnWsCz4f;IZBnN|4+L z^&)-SC+J$fi+W=bSX2Bf@Yy|dIRg5#Sz!H4JUKQe)a);A<7M_*>g3gvWWImTQIlpB zAeP5YW{P+Y{0XjjsJpvAq^vL!Y-_nq7L_#hM?93YCwW?|v0OZ>G=BW9bh_lMX*^>5 zyyUEU{PQ1YEHaDl(rx6Labi>!+|sS&HWU_u(q_`HBC|~KLDD&>Ye zua)3Wbo<$mnQ$vW5g1nHyx5Z0TD}AXF*xDGs$9<|23UkF#G!Zm);)Wm=0UANkixbM zVckBPt>H|;k=RXpf4o=pf|~Gh%wQMiL-o6)5}Az$rPx4XfP~^UZ_qjYVB-Ks^j2%x z_s$3`aF^HbG5X$d+6mDO%9{*rkFD6m`!R9RiqFUW^RJUI4|sVBzEir{XfI0sjgb>h zt$?}dBbW;!4|a=H^~WyVaR1F?8DVxs1Wr%uWQGL}VKjp91=4^rHu4x& zJ`NXZNX%2V7aLhDsQ37Sck@s%NqhC7Ed}#$8yRE<%#Z?iHj|#&9_6_;H_^I%)35a_ z2)*o4UxG4O5eM_71RErFigFi#4=efFw7 z;>|>AML3CVmdtn{ijD0#ibC~?zpi3K^qdt*lmFz1e^Z{Euq+WBX-CjJ5`;7wAAVPj z>UaL5XFyABj2aLi!rw_$gq@3C?=p@Phg{fpGHudxL3yiA5LwXe2~WK&_qhmJaC1xq z?ugM*jqnV)m#Bi&>vjq+mG`VniS5@|*g3On(&K=bQRYMS&CWBu#tB)!XHMNxy|6DJ z){WsqaUG9Gk@Dw4vyk?}(?P%K_fLX4?iqt%fA>4X0||cxXZNSRAD~E3yNZd?u2j9l ztgg~FZ|6dZl((YO5#0Zoq>!uTeKI1u_vfJiw5dwR`b*X#HKWWG_5=l+lv916z6Pa3Yr zq+%2dfmtZz=)f2);y25yje(F#zGY{>lb>;QHiez!ajWzD#1$zlXll2?atTcw=&l`O z<}UAXOzD`wDoQVLo72;8D*q2(`i8KKF_7$+if23bw>@7I^}I=Es7i-@b;tdO;j-|G z*}euG`{#+K3U~{@4okDf;|2AAsR<8Ov&PpQJgU}YI63EU@$@_$P8md(bKh7$AF~jl zSR$gkqi_1-UeXs$CE%Ce&u8?#3xS3*X7qZgLm+di17%*=*Zm?5XE(r7}2y=G~@=#{6GmT!>q_y=8zQTj?fDa zXY#Iy>3SGfkf`?eMrEN-n1|o)DAkgQqGt~*d3sjua)uUOchEuwY7FgotU2A8oy!N2 zy8UpM+@@m@sc;f5ALJh-^?A(RV5WCgct{nKUkkLRFuh(JoTVI92&i0ViKvXd(N$aa z;M!KRd>iIIvE4>=n%&Bn6i*Lsk^I(O_B^M?SGtI$Q6eQl9=Y^TXAbUy)1;8Qxk0en zY>7~%Zv3C3X}ok~!R(xm=;F8?~`|R3N8aF|ye^OgxaGJv$9?_+acc1G_>E<^`^SWP=gU~a6z$EfLhbizx ze79$3;btOu3@V@yAYK@f$eT3H0DJQ43rn~_iD<5ks|;BjQB!!9nkk+r%=tKxsA9xfH7yQ zpI79&+WGtJ(mt~3@IJktKJ&9-^DrR;+So^v=JACRj)voB;(ZW*?~&F)SM78}e1vZ{ zvV-2|ey<$;es|ppvr7b(vl#tj*6ElCtPa!_U+)6TK7fQBbExG9AO6WXQbsWC z3$)$i)nkBq5`BdbCfw1lOHYR%J$Ms-uGYznraLV^#*4@tHfx{l@8Y9;=`%~|dzHPe z5IC*fRvCVn8hkg1aflPhm0E6R&j_BQ_FcLOo=apxnZUhk)$t+8>a!z4gK5MhRD231 zN@Vhk42vGO!vMtIL8^*;w)_dB^V6W%sJjjhB@r{wU>QC($Y;X;4)1#BH7s;fWIB9N z{UTIzvg=~EhRv1z=T1(`JGbK0N?DX1JSWzcsOG`HDzPupOdsQ*kLINZUiF|?j1v56 zMX$5Yw~W*IQ`f-ijH%j_`0 zQIChxl3(`6$x}$pDI<%2y0dl)(}@7rBs3{wTSTh!#tQm?)=jR3KM?uBSF}wQ)1_va;M@Do8a4vERuW6 z-X#^D1rvM&kgc9|K}W8-=wxfqaZ8&`fg+V6U411j9)_K$x*PB; zT*A3&cxBPsXJg6e0HVryju6e*db9*r@jRL;pAC}s5Ho0UqPL*kG($#ZXxamJJZ>)Y zhXuG|P?}d|2M89|TJ$2{wj&sWJ}%fdcKqi7Y~P5Vy`McFof+J=eR$;EKWupr`KZvc zb`imyx^tAeWF=+RnL1_g=7wqEBNv5%Ugd?UE~hVxBwI@g<5sm0d$y{)uDQ6v>=_f*q1e8?G|D3KmFKUcb!*;nmGhrB8Fr#>Xyf)|3J}b>&U(kYUPQPK1sDW)Ww&cU{Wu!iTm2 z>|jg6vAbnHuz^ff9l02uDnRd|W&AdZQ#)77Q>MS7F({igsR?i01(ZcbxT<6i5W5|A zR;e@m*nvL!&M9jb#XU0>SowaDh4?NDM5Tl{$q0BEb=C zC|1>vU#5M1JH@)$_oi5-Uo5a9Vp6rnhn&>Wch(lmSy6&aZWr?1 zP*`Xe%fWHS9FVuQ2bC{e$mrx<{*&n4Xdg`9E-oAmy^=a7$my^Gqpshr>iYQ{9_8!? zxIWZXH~(t0IUOjmZWv*9?|r_2r5#sKp7NR;DjwO3=nik~ok&!!aoGBVcI#BVyu`f< zmF`ou6W&0;Y@jR|hkMHlx7pg{gXTmof;Ywy+;2Uoi?Y~-lKvbY2Uxx20hG#2&EPnf zeJwU7DcJ?_G*=uM=PWoVI|0Q~ruug`Pv_lv?Z_?a}mI zW;m>|R6K_AZ}#P}UO5W|i>R;@D0KqwKWEBdCwhyzNJ4DyJ!wk58M+F9lUQ7;OrZJ_ggR`y({To?wo;ivl& zVh^7s0lkI2k7_m{6$uC$sZW(;hehoTt3fRRs5$RRKY^h~)B@Gx9QD>j9%$4mI6vNR zT129P4Eed-wIhThGf|LYos}BqgdU_#7aV{&{BymT-0GVJuJbe%as>x0{0M4`y^1c> z$3~1|T7~nkWG3tb{#&yT4QX(+v8qL&puT#>o3=D zZ(k`#FTkyT^8Hg9m@4^c$5G6g1M_Nl0_Up?P=Lr-dCm{xN{#T|=~}1*OJd{Ld_b|c zlDY{-5ARN?by&LUzz_`Z5zZ(*IX<(7*!>ifdFxxMUm|VtF*e#lJMa}Ww6kwki259n z#6;~HrZzgH{*wJwTXy5h@*!a$-*Q4-iJCl8IA*p#9^F?fXn`(qK)*<>%^tzs_A?mHx#Ab7B1bWoEX)kllkE@^-v9x?N2e_CJn9+@`bH>6&h#l<{p zeGf+rt2=-tzrmuS`4|{Hzyte@=0RcZAUvk0{KCoO=uLRMvZUyZjvK2*)Yx_bq@sH zpU~g2jS5-oCqGY_oAn_G_lMFPf!FR~5b5pWQ96%u57}r5AM-Q3&NshJ_`N3Z_vvZ0 zQ-kPbuY2?`#6!9?bv#}*LFJkpnPx$v&~vdKXzq~333+e6o*22Z!P$253sfkuAeS5y zPGxldfsBXrsGvND={Y9L(@SPF?tL53Ssc3qi>Yx#3CH}N+NUh3rKg>U(ebn zd^FcCzecAv1CTC@HEqwN?YBolp9tYyKXsZ$az-M``$aGBYhjrG8hxJ@U+p_sDcV{8NU(2T?SL@V&mo=k9(u`jjk3T#q%+=TL5Fhsn34 zVv1w5I0NRV7*dua;HjVZLtQY3-$dj|%_qV|!uOe4v$?4_28LE7^iV6YekP@P3aCAe zCa_9>T3c8*!*{rTHg}cQ^U1ze7a0?^_fzuO_gzP4OtFeC`ZutL{|2O7pkWH z6j1#ti3vT0oo18e8|CwX3)A;V*g@4Y7mJvqIw89}Pltg>Me9GjSXV!eW7NcUOhdQnKfB;oLN$9*?)Kv&4J z$}W`B|753>C@Rn6l02lEJS2vj)pabsa}M6l*w>zFx%+DJds=^(LQ3bGSy*{`h*ow} zJU@<`iM#F_(6agX0KJS=@!&tuti-}ideD1+Oow_uCz6MkWZKooh`i3up@ zXDJCODf^^DF!l^c$lP)_9GbNhzR+Tu)@X#JQ|6yB^O(lCQO*~98qKDzyBP>JbCD&m zofV3-ds*CCAapg|aU9O*kG z0gMklICLRUB~o*r*;v%?T(far8wlCeT}4}Id;VtXIAWcqC|(~~dCqcG(14p4ZqfcF z1bFv$5#4c5L!XjW=qq>5)JG|khj}7G^EX$sPN90d!qCZ_UxEv0ko0t8{B7&o*Ya=p zHLThH9{_DYlD~M?SZ1kPvKy40zn*gPH<=%^Ahv3e8?3L4Jmz}H6P4*dXFNIW23HTr z>M5vrVdj<+o3Erj-Smq}#Yc(1wj}5Zqk;HCQVI>C2fXq8!`=+5+ip

OFG$oHuG8 zJm;-`%`?EuPy-{4>uJtRyM`%stF)br+ z^~CZrW|r42_kY%ZTZh=^^kFt$Vl4a4=SGK1@%KvOE7*8axL~D(AsvS0&ZF!sHZH6G z^igFB9bTO6%bOF;MloNz*65$U5WFM)kgo|FlV=3ApX8%Mc%;dveMDc)E*cu_d+ZC! zU$#9>v}a?T)V*^D&-wyKiS?DA*rV!-6AsRK;0x1aC$Ar>W24mcYSlFYbg*0c!g8*F zAGYpLX7ttjLjLiz#VaHI(0_bb$k}XPXsW1CUy|yF--mlMw%qfD{lY@uOz!w$@E1=H zw;R4NlwGxV+fF|WySPHma~vIZPoBI!W|JSTF8p@{~o0~t035uKI4;61>;_=O% z-SQt9(73&r8JNw)lVFgp_mBYv4`@XhlbE>cUFYGFmkgkFWKO)@#6U}u|NJ5Y40flT z_c3B%#~G2IyNemneuvhz={xb?34D7k10*FkmhfMpqitSqXRjv%K3w>zy4IM1R~!5; z$<1KETj^5 z)x`Hcc+J{iMDGF}j>Y7Ee-l6UbdrxzY=M(=tSZ=~W?XNxnwJkTa zEXeqy*RdU^`GRV>)~}UU8F;uoT4w7)UpUqslq^oxPk_*49~n>G4!efRVFo&Ge)Uqg z%@=a3IMdAnnHaFvvwM~(9RfdWn;L(PiKb7AzAc(ghrz1_fl+6fcrD=E>mD+{+0lbU56VIdSe17V6h1-f3Ww_2?UlpU%rdd*dOo z_iQ>$%(ru&yPS!hy{S(W!sxK?R`ST5txRk?(mZJ}g%0__CJUCNGjYcwzSUjZ2)}$2 ztU95~L~9#^bhG<(h&|qy=WNZynP-oDUh{zt8J}-&_{d`7le?QslL`Gq>G0MJlkrb{ z%Ez}-odM1ki-Pu>v+&*#;~*zX27KZz%$v`Ey_J39i*5X{DyEW#$S7MFpmKhnJW#7r~9KzN5c;H z0tU=qU-je>#~)w4EV8^&&Vci}8#Vf;5PK(UAr9SUKt{fPT3ebwu9=nVX?KSKUH1zD zRX6&heR1fb350(aE|~XhAjBVaw|Hu}(}+D1q+YC|;E$*6x7|pLVuB>GFP<&*L)G8! zE+nTgVPfpAOWzOr;f3_Qg;E|&a9mXCwK>@j)nk}bXR0y5uSUx*!ORcG$1qe_ zQ@z+|I~yMkN^hS;{1fN6@X_}TCoxgnNZtlKFMNB046&ajBMp)g4Ky)N$bu4jNjJV`GxdK-VJH9PihB6n&&heVXg0&8;ughh^&{{QFUB!Y0$*h>12G=n3{&8BQPn88| z`b=qOW*9!ZQ<-&ZDhs402hZ8`EeubcGVX}yW5Gj(;CH_x!f`IKM|Xewcf1P83!^G` zaT`e)~I>gI(q4yhA5>La^!GfE}wih@E9pLMuF=^?T%ni?JNc_%%0C zUd{ua#>8%4zJP-{zvlJ@5LiUGRibVU2lIZuo$5urI zW7V|dbngc&FwAwi_Uw5OHhh!0x%Jg#_huqzya zlPpYgpn=Na7sd~GA~1jMtCy)WX%I|1fAQU{2n>u7!`-uJAb(1!cHx1%NQiQC; z$a>5?f95OXX;YLK6^85_SGXI&sN?Z2&l3&K0g$jKiO1T6aTO@pwZ}hYA9ADSXoalW5O@t8U8Jw z{?u<|!pPIZ_CKV;aQp22n{L)JVLY{AGdB#scm!oz++o6XDh@?93`ftAMOiS1_Bi@Y zM<|Y-0}}Z&dhVeaimCDM&rc9$!KZ%X8A@kEkP3s*e944Q(M@5V&LQ|MCtuQ?%;$UD z9>oXyL-0i7mFby^EYNvB@rprg2wn(FD0^T;{7EuQCG`+=6!XZRHJt@Qe0MLeofv{? z;$#4%e{OuX-)2o&P#lcSBBDW0oSASUedp_|LBW_#jb}O&GI}$=?=&R%eEw!fMIX`E zRGh(-U^F4<&#hrVAw4Ij-GoMlJRV~wqoXs5af3$dCAlv`rVZ; zZ2~(K>l5?bUDZhc?V86fEDpu;>HA+T0mdKx2*tqB4Q2-9EYn-wD-ed_)CQdgV{Cua zFASYW$H4%4Z*|>_>0zi6{UO*fi`WxG>Mk+$q1f`!zi;Md2Bbm9_UZFNvAxW((KnX? z317P-ixonVLeqj>jIsUcouN4Tdzb-5`Cp=Rl*5q6J8PmZvG)gp9qoFTgkgE)a8CXK z1}uE6JLSZlFwBTF@-ra*LDKmuLtDWx9ME`E(C~l(LezojEW+Q(>o;}ZXFy_$lgY)7 zFl(m*<-VmkY3YtPOcb2@J8k-5t z7n_&DYMk2+l@BvOF@N}!l&6~^kypF~G0%gsr09{Sg73fd`|aywIWeUmJW%DM zu21GOy3ZdKG^Y9uLvJhc+tV8Z(do76;&lm37+vLNkl}pd3Bug?=4ShT#@K#*QP5cbDn$NK2NwH+Fq=BJ zF#UIaqsJSEgU94i9CPe^iyn-l=Mo8H``tV$!DHul!AuxEhYt)MYu|tgp`$V8!DHu3 zVgI%_dj3}QXZ|x-5KqL9)cio)6n0?g9B~#5eLk!vGdB=ZsCcw~CQP8_y*_a4e1XW@ z?#r`dYd;6#1G2pHtC&EAEp4<2LSF&5hU3?mpnUy~w3T@fhEwPEZI) z@ja&k@YoNY5;Jc$yw}`#&x+XBEa_gUC3H44{1kIpRqv07wp#Ie&tQ+~mr#G4SC)J! zUxhsu&-K}FEIw134KFBiy6T6cczVkkiw`0G0~I#4`5_BtXO{lpY4XFKGR^MQwJcb& z^pKvDqd#UV4t$H;${LFgJ>!oKLrcHj+{l8~@m{xzrs7_W+zt#U-_~V9_>te*Y^0m{AaXzO{`7l}mk= zKI0D@yR-401zyxSvOZbwtpTs)McDt~&n4Thddn++9IRIswOPU*i~Y{_$5A=Gh7G5P z*gIzJkH4yq($=hHLl7}bO4#+ity%D@WNd8V4orH%5Pl*<I`Pa4^O&Yu~0BH-Ha?K(D0l_i*4 zNXJ#n7rt#I{f)|%HedX6ZaWr_*yn@1RD4D$8%$l_mCpX;gWi;U+(qcie4PVFhK}CU z?=m)^@EReDayq(EfjaZpFiQ7t>3D0HFgk|~uIbuwm&55;OvMosc=SB$3mr$#2`$;M z`_j(5N#P81p$J#|KYTI9;vYY=#^O7CnYg~3DDYm^82_g+iM|oLx%LqYM&rt?{=`4E zuwX*}0*PnOnYf9HziMJZSC%8c67lB~cW{y|uCie2kzU%24klVHC6-Sy3pSV=Z61+f z;nJy(_nzCpf_s!4PGjNshe|5>OIWZ*b1L0z7YmO#OJ2?;{+mcm%iTQ#EaWde8av0E z*gv*Q0!v@BaG_{@c)uMBEXB8u_gc!r(YQbd7W_~v)_+af+fUt{F=UO!8>qAKY5816 z+yoYUJ$1rFm(a&(eCrg#|CIh*>xb-Ht>4v%d>Eyp9=|d9r@#W5v8;D|gg?63Iv=zq z_LuSX(=+D9`(yr#V-@{2EU0CCdaLx&4_QmBYiD_~#^kBE|JeGH`HcR)@k8EipQg&M zV8Pks>%r-Ee)zF1X5-Q**4X;&@Ebc1CitM(Chw;oc2IWSE*1pOVv1aB@Iw>oJdp6` zCMtd>&<{uBY-?EHXE5!kl&c>ecbb>2*vf+85d+7xB0r?UW~cU(`jnu%mkBLF8Q`QD+<4{PAMv`k%4U|MGvu z#fK^PZ!__k@5Wv89@F7O-luJ|zcTUEJGs8>20A?GXz0?hC+kZ)u!~VghdjeneN|r; zo^d4$@`?_ladyTmEQq+xn<>nI0H+sIJ-;zAnu?c`WPohPov*B$OdO!}C=Ua&Pt5yL zSjQaGpQJu_|9KKUj!VP?F|*dAG&F(%$JC$fNqG~1>u*es>vm;8)wjnF?Ii-SXl8s+ z3b8li&-rJpjt|70Nn6*oIT3qQFRS>#ogKtb=i zGv_Y`qJfB>dh%Qb)Je7d{JJp^m+AIgo4Jkwy2n>Omh=e3hJ!b%MN%1X&3W?T6Y7EZ zlreGNnmLSr#&_d{oRg(09qUEebv6AoXhVNt*$H%H5V4;1od*53p$i_*^~KS91)Ve~ z;NwpjeCvZz#jPg&B{Udn+R9`4+6Sd4>Fimskp`o9*Yw3vzSuy6k~zfSyXA|ccN@>p z{^`$PRY>Y*9y%&ctNXSm%MB>?AokD~N8`v`-C#8CERD!JDsIWt4Q`}HwQk_`9g82g za04IlMamiAi&eb)m0kJWpklCi!rS@2D9c>IeE-80_E2Gm!t^nF*~kst*PLFXGMSDF zvyN6z33L0Wf1c4Rnqs4ONxnUqag)9z7Ulc0=Wcjw1o;#ZT&830G2`8@h%H53^c=mw zNB-WB^qnL=0t=BOL6SU4$|UKKbcXleyC2-K5Ztj6+_4ngu@>C17~HWM+_4$nmUj_}Y>`UTZp_z&W8plBD zN=lKgD~#TMbt3Ik1OMp)Cr*2^=dWd;4rRQzxd7*@;1b`X3@o~@_91tJ3s53n`z)C+ z72{0SlTzJH1Wu#oJIw{0sd4XTjM>hwogr&~K!;1K$x_6P|}^IWx5_oyNCNcHoTfd-@H zoFSbWha?kml%AYn;7;dUISXQo5>;SV=sdQ!Gna|&jR!(!q&kDwqWarOlSn>g18jB% zQOXAxVPF^4F3CSZxm1K6(nf6)XW*Z{R<>gW6N{)lK>{bO-_-pnory`+3%AL0oPi3l zpPR=-6-u|*ID?+t$G!Q>i7gS6w7uHQdCXSXz(j)?N z{&h0Htoy~2W1OImm|Dfx$oQ!}8e=EW@cEFc)6N`|&%91BsGo9CZ-lf*;eC%Is8Dwq z#<8%Jh`aV8N9f`=kuW2^Omhg)0AC$JlycIDtqv6#!jE;F#^kju3k@hew9N_h<{jj% zR%0QJ(gz_<&_&&KBDQ;APKHydh!Zro(^NuKvCI+l@`{EHe=$*qclPX#1&&biy5#FdV(ZmY>+AZbJQ*K)4If%j z=P-6RMvjHzSCwp6#5+JKb%!p9h4sXhU+3TeC5JvO&RWgFf%6k?FB$^is3oQ?J;*`} z!v639z-w_L|BGuxp1gmDmNfwRN~s=#w^@jkt+5@TdkS$*q}Vu2%mX6_fW$t@hau){ z%%FT|egKnS%j?$ovB&oElI$Ukn7q*uM4nTZ11{P@0=2inW@9;Zr$g8dlqkVq$HwN- zy#rg=e#b|^O^uCRi+*N4NwWbOB@a~Ds4^sNc&eL-B`8`QK zHEv@|$f5X^jDJ)v9JBpjV*_Hg?{vksJ>g7q(aJb zrYtaitYZuGJr-5Zl8L=SU7qu?1?p0L-A4r`{G4sXG{p1F$Rk$injTwqtv3 zCj!RSXQ?fiPm`B9MA{l$| zqV{0c1*5p|dgbUidpJS)?nNYDpWjmFs{Nm{h7jy(=#sM|Fn>?)$7KZ06MlSgPk{Z{ zU1&#=Pu=k*@Ze%XXjel}g>l)m+|M5BmpyFEVufN6bti5-jE(rC0}SfjU43b8IMOJ2ChZ7CQH3?a2g9*-l4dED(d zW*=P+C-%r*(M@7bP(JHv^7;?qSh=wL*WD#fQ2q4h$MCP=$TNfJxff1g@_g6#C6gnt zlJb9ah&@qamb_p>1SXX$p4Z<>?1hGFjwdHZp!mzlCWF77L5Mo5P>Vnn>W*WS3-CV) zzb`KwfjrdZ*iILa4-r~G=Z(OesH#H`eOy7OFrfXh*9m?o`W#RExht_g zyABcjn1)|;&vhF+E7}o`qi0HGZh!Xn!^ikZ?%!B@>y2mGPZOhY^iI6A39QrI;yg1x z8dY3{HkqWE`86;(8m~}zmm&3ulpMb}`maAtUCH{kJR0|%do;sjk}-_# zsS%jEQi%S>u#39upBar$M2P}DV+8^dbS z{47%cpnBEFT0IjuLD>f+UvS#XXYtM^U_{iD@{(xmrtUo1oBT8X(Y=n9(PMjw*G#}L z-Pvm$>Hlp(gZZNp6G)@<`o`$7vzx6ZP-H|D<<@8{B+I#=-UQCvFOgojGa8#d5W;z4 z0@RUIHG#`*&uGAV6L{_t;ZU$G8mZ|U@tJ}FbvZVN;N!wQo~LjB?SJ&FGd~*N?C*+l z(KiJ#YIAOPG>+b3kT8W}kK0odjz#0KwFwIaC!0bNbtkhl8i{m|HM21Nr~c?2ON>U^ z`ug(q7fj*C0?*^BSEBKA^4wDSBc`Cb?DCJ7XQOd9p1ib#X*#yIeLfm%L{I8U0Y?W5{Oqr1?c7E!?B^96Y)&v&x=`Z@;cM5*^5k$Z zFF9E_bfy=yFE1a4(;TG#-dX=@rxz?XySsd4EeA_i(oW(eZ^*6*5U_mC!Hh-8!h-VN z5T&jvJ6SpsyGXvSqBltXxPExIWh7cim3I8L_lEF5_M7X=BC+{)UHHT6-cZnapd_In z5{2G-dMH2fhU%7tw#fUDnDnDYxNl{YrN1@`D{Glq8vZ^IC}#OBg1`O_N;&3EWK zZ;isd1?Gi(U%Ww2JFC#+0;%7=cO0wJ8#deDy}0;66dG`}HmIKRhBbG$l=lrqp-x@y z$B)~*!JuhyNyZP-zvP62A8+ADBAs zhI$uikCvV+oKWHezTH5y6Fz2IK#M;p8rjhuUXGXt!>Aa&{f>rZY+ zW0%0ZMELCqnoOrfK1BX>ZP_+`UA-r;mBpi6gkz9rVrd8Gz9;ZaZZ%QYj=^$^;{B(} zJOL#OZ|-r6!CtMrP4cTf!O~l}*CL9@ql$Ch?tz}rs45<%zMGW4l>70Lu_xG{zJEb$ zUkv6Sd3w~&-4iOq6?SVbi@}6b@^YeUJRy0!&cwEm7|d8gJDGdJ6CUyF+`eQPgE>>H z-fsFt#@BdJR9KRXr(f-ZAg>o>?!7ADIF8h}vun*X^@4qJt%E%eqjA83f0kON7iejE z_+GsejY8dJQrGu*L5+q-zsiMZ#}q7vA^r27!i)q8pouK0GWa&>G_n8qI@~yPij*&ei^lo@U;# zs(J9+jiG3yKj3LHPxXe?W%n<{{f@@8x1JvE?%v@4>Of@pgcxEEecz(6&KqtOXc&Y} zk3j>{-%~$t=;znb=e3W)(zTfi-v}ILsG3si5QE~$=7rOUJc%Iq|7IP7Is?5K3irHW z(ZekR+vqVU@15p!>X$dvi$-ez&!Dh0a1b$sY2T98i&hv%;gU{!$wX|76 z#*-=Wbs&olW`};T%1vXC_St9EytQ<2d3@{gao-qxJfUEv)G0dL59oR)m>Ppg3A*D_ zZqgy*?EJFEjWKA_+90#wH62d6-L+bNA_h^FcC&gM1J-Qw_FCLd=*P39^{Xrc9`kJ& z$|d$ddcXAc)fNmmYNTr1K{9;c+;;QXm>1UtO_l>Ny5%_#pfEpb+7|tc4j=ESSyW{rqKZ zQE0NsGiJ>m2JGj(;Uq%jyHbe!>378pxV~a>X;DfPo|sfnQ?ZeZkFh*f+AIna&WPBS zt!04q;rkbprbJ=asks87D;aQpk>C9g9n6R=sVyMfk-#(eQ$AECv@14Gy;Z zLgkinnKsi{G=0L;G~$j{TD4*LB_cxy+Biztuh{l>0)uPvYr{o#Fes-zePX2VEzY zb@`t596hT@8Z)GL{>u{)Ub#GL4-KxU?G9!h_5;bP=pCM}G^l?){o=G_KhWVM3;SEq zh+hl|O7r}n&f53&_bNBAyW4eXwTBW!A6(tg} zmkqtSB{otwT;av_!*>eP*%0tFG-P|JE7T`_IMwo#1>FkqM#+m@p-?8`{d{vaY>UlQ zklp11Uj6&Gubse#foD7GuP<@|o^_UG2gOPIL(l7)^jyHo_ENgx8y2|kI_JI3-UaUe zkeWZafdwWP+vabd>jGFUEU!MB1^)Acu6$kU0xBPDZjI+*LERo^R_Y2D*t+GU(Dhy> z99S(V5Rv2pLzTk$`!_P7Ppa|9%)_Mr=dnk;W-%e7oTsU5gA0_-`YzBUS_~-!OsB_YAzt&{IRJ! zp8;BRo*oGz#IK)!gSE_=0Y$$m-_AJg3?B-v>|UzFfO6w?>|K7&Ag1o7c0io*cP;Bf z&pOKgro+X1H5v(9oFV+m@=p~f=@2iJw`ubZXGmLIm|9juhd{+*!pex@6O#g5JVBv(g0yR-`B%v801Qa?lmSCoZtDMf>T^UA~ZZM7PxR zfeWxB-#$3Q>kDNwE6TT`3nXowBAB|?2X?NWefOg=Sug+cxC>K#AUjc+5fbAHl`@An zGXlMVmgkVdgRamXeKj=>yaCO9jKx8 zyxjdX%>zDlH=A~fxxnqTm%HiU0gX;S%bdEMA@Ge#iK?XsScK9}F5x5V#ha+ME6@Yz zpPlpWS&;b`jIW+S$_MUY^3RSX^l@SRk(T4`(3POf7{A2@IBza@$}DgvM9=?bn2*rw z!6iErrn>`8rFeg^hAY74TRzI#?vR%+FE`1@74jat^Bg|t4$TXKuJky#!tkAknt7$} zz$vSHn!ewa;CqVTTp16@S+;Gu>sePwy6`^9dW{F<)wIpmDRzafSW~7;p$C-bFY6MT z>IUtu<#A~wzpLn+_sqF&VDZ$QCvv<8a3nql{EBk}p0$I=w&aukmJJPBXA_>6W4DF! zyF>megQ(BmZZJ&6VCK?bnA+bpb^{&#ioN}wG{9%XA#rm9NSz}1K9B}!zCUM_t#bo; zDh5T6Huf&=GdED7-gGH-gZeqb--;f&!GE%)yfS)6iV+RUQ>F;+T0_Qlb?>;v+ekZW zZ~2&TNWBfW^S7L&0lnaHgkPN-G%Mw8GPWXk{b+b@$ejkIdd14a{WMT{u2S+khz4D} zr5y{s-C-d5evWFCJCxpTn}4F+9m;9md!?p%K-x8)rjbYPkk+vv)YRD%I8iP4Lspaa zh&y)uktZZHEj8TkOX^WU$eIWm(+6T8dvd(t(r=4#3K#pePvYrEEe9s?h zw*Mghg-V`S|93K;ljEz)7yCe-O`4NCp|kb_Gvq77eZb%}GfOAb1Mt;D&D|Y7(7szR zJ83zgJAq+0!{t7}^RhQ%>O&96zW|vpE)aW;I;Y?ve&8u#`MI8S=(V)-56~xe`}EA; zCyBjcL2bBtc|uxp)cX4(3@B~nX);YGc+l={4<+*BKiLi?!`Yk*49H`xYpL2n@IssA zyq3tLUa6JKCrJ=LG={MxP>cylIYD-22A-gCWH@^RhY7Tk@^YK`3EyoHXWE4@0n#%S zDz12d4fWQ4etbmut~}!g zE7r{q>ic)r^Gzajf93A9k|;kYJt)8HR67k!@+@aapYsE-l3CjPh6ddFj;KIE9v@8rn(1*#;y0}wQO3wtC;~YR$3cUWn7@-OZlPa1q@K% zan5^ltutJg*d46U$biK}?niEQ2H5`k%c-vnXi|BU>rvtScP%z0Z=2pZ&lyUH-re<) z0oAe9g2yGD;i=z~eZ5H9KUf#;rcCl{moHdO?95}sif4xvok7L;QaW=l1DMS<8XN7M zp|G=l;OH@82T#y<>0Rm!8XfgXvVIIu>pK#p8|DmlXN2>w00Zvi_ge{0aE7g)%MY>D z7|?F_a|Z3Y6YNu*XxiOJhc5lTDc+4v0CR7!ydTqHUzwHVz!oRCD4+DpX#xZELNgWO zQk+0&+Nw!%lNsQz?HfN?+KJfrwdbdPq5q||d9!r(c3h`}yhO3`&XbOCOmugrK`|W) zYS&ztU*-tnmRnT@570qLMP_O3h$F=DN4&pJy|H+7Z{`MLCkTBf)!!{bhXY9lQC16_ zfOX=Qk58>HY}KkTSXt%-5{!=8*E4*KUKOr#gFvXWbLiSa>MUfD*e{GWTbWGvp z;YWT_hVh3l)krcR$@Tx#6K_)at$3Rs51)CXzP2qA1{6Lf%%qFpv9oVpo|23L(7Etq zMzqJ3*s*>ip6%zQg$hvT&RTQ9w^|72)Qh0a`>-8M_C{T5>K34x&1~~)% z{FfI-fl5+X(=k7JT)|QqT%8^TE9tzpxKIJ@zU!AtL_|UP+&3S;y-+}njT>9k;|P3N z-^_pG6s%t4=zlIV3Kr(94csBCf`L=$jmvjM!P%GgsXI;8Ff07)u6swLAas7L*)|O| zY^ATZ%_)t7G^e|k96@y~S)T4>do>Eu4OBmchpVILlTw?K3sKPg_*UV^E9zKR$lHIo zBMJ<3PRfPv)WG{$=M5&eMnV0)wShs?G;!$uz5HH``iobKLf%tCRZ*~9&%-CUK?8ll zzXq(|8wHO8oTMLa*1)(qa~7B{C*^m&Rc&z8z@oHgxqdNGP?)c=S#?AWn{qcw>oEyF z)L&=qe4&cf-}H4hIz)lcxs0hpftWv;Pi48H1p`GvwI&2dP2YNvcIaL(tc|trItu26e|?)JEDe9PkHIj ztc?UA&DUAy8ETmB;!c+-CUoMIm=tQGh8hE(FK!^~pRm{@>EL`ht&0ZWHnF@kI>>Ria^k#M>E?ZIe(h`@F$2jp)B`+Si}+(qEzw4GGOHPWQ#7kblB~ zaY>|pdz0Ad;IrcB|LTSAFHu65D~_&>VThqd(B-!ozoOvuc;U0&6%%mYCx3pgK0;5o zPiSnQ3E>Cf1DP`)Mgd(W)+z79cod&I$4L5V)L*);s71lhezJc1-``5G6~Nh^?s>M~ z3I6mtrhNP@h}m^vzfKB9gZSmh!|UD&|1+N<#_FFXZ^(LImU;I&R1Pb2wC8EGM?sOQ zWA_b0uP5%Bytr^P3ifwiGm3PXjF}((`76&8`plUit>iozgXas)T2>eZc|9#o#}wpI zXYlhyll4*1`|kK_$)B=#VEfIhk8-0xC*k`zCzQd3ZJJ+Fx(Hff8~MFnZh3kiOncAd0W$C(w$D~(GnEo!!t@!-^S#xE6F zoEB$zqm|Ha^JU+_`uj4tBI4_=r!OdeoA+eSLTLfiufxRcO9ACeFU|qg8~gPkoEiQjoyVq0bkM2;4gmG&4O- z3Nt<3#Z!Jq0qrhl*19(`=&1Id=k$jtI2D?$bJ14zAADv-er;m}M#I%rFD__=%HWXW zf<(TkXy_8TBOL22izTj;)Ym3QLy_0Ml(gIOf92NjbIz=9Itmzkch_{?^k@jwm;)!> z6fyJdN)_W2QvZ|rM9DG&5Bl>5#**=^*kyT3LjiZ5ShUVBAQ}wbiJe|hAcv0^9onBl zkA{KY1`if)lE%LFdA`rt(O?<*eO$_P>3_yYM4~VyRwP!6q-VcE58y36KD>eS| zPWjtdUH^A7F!4`}G4-cK(#$`$PZ&vYBqfrxgrvhHoh0czNmK`I{|~v#&4=84TCN-U zXlGU=bO(P7(aKjrk*6Dx!4UL2*_Jt3^*HrLrxZ#bX#*tu> z+96(lUj>U&o_T>oB;;?|WoaEV6)T(W1;+YCLRYWWNUz%zRPqZhp6DG39M>3uq!04A zU0n7_xosry>}yQCvsDJmg&y}G`OSf}OV^B!&XmNcn-Q)if+ z<3I*$ZR}QGQ50<{wYh$r0|PbY6K78rM{x)Dy!8DXpij3xR-Ph`WxK5(TjX;I2`U%%KQkB61D z=Xo>``g&B*+Mz0kwaVHbM(%PT&wY_x)lC`P)Oau7sf`2q4eM^uKFi|w*@u)32%NEc z-jfZFu54g;a$3RR(r;^?}#X`&cU7!3T{-cjf<5f#*>`vWh8LjK@v*f>`l z`x;cEf9(wg@#y@;#$P93on^%P(4&`kpcL@QW*DEG&N_bME zG-qbOunmD#w(+gr(P^K^t9LQcnUo)XaB6ef7kdSp-JJ_&llJHD=zoiE8PyE&uk?5RU*2+_Wkzks*^$!J`=dK`O=J! zef9?HiP}HdjGy!nM7c2`dWJEl-aZCM81emZ@oKP0FNDz1Q}lr)a!}#}1Z>|_VNc}4#w|7iTPI-ocmAfY8bqE5IjNTQh~RnO;O9M( zgr1c@CiKspfXRl^^Vfch02Sx*t5-EAU~v2)DVY8&}kzxD$*G$v|WJ&(_ZiK0y>}PC@sSJ`P_;B@96WY*h4@%ne+W81fw~|P` z+iE{JZ>sCyPtt!#-3KAH=9|8)bVLA13%(p@FkoNm|KR4l9s+MH8`wEKV$VH(+0(xv>{2*n z^!v=+#@lDlPTQ(7#2*2_RcXdOf$!}_-`<^ON#tkE+2`tw9^dT)O?^URd`W*XRrZ@{?!2#JTvWNA_KvA@pbO!r`}ON#$GZJN9SUNxxjn!hxsDr{>D8NA_ZG z5+jS92z;d|^+{~Iy>_VEfeRA|tRa}G5Prvg>!p-Ed&d#@km63^;;x$eJeAL0S%*W> z1HQqo^+Pp3INj|j;bgq(*ACk5`cRY68Pa^~At}Ex)OOdImo*kgboQ=mCNO8A;dG0S zHH`{<;YZGf!^#%tPl1i^Yb@?&op_QT4xEC}9#NO!8g_cq#~spxWHbg1{JiQ5tmT`dnYX4{CO?uw>~9~;9V=a%_Ig=$HB^jqO*G=VFR z*}2^$c9h8n;e5-|a43I9{D5_`cx=3%tm@`)m|suiv#Jbcha8(Tk>I0U{pMZYM-m9y zsTTJ0N%gpYhC0ZHLMW`;6+8J>?eR0LD+Vw|yG4Ke1@5%E{T`fM+}3C|M5J zbJK5-$mZ40C5iq%aP`LAEDh{5e7AMrav0=Au{F!4sN>S6tP}gbg#o?&Rv~Yd8s;e$ zZMP@*NLaT2;AgfvHr9yWFE%9j3heS&GN6uX*G}d%>4!thiTqi|i2mnp|8((&o+o|; z?x*M6l~l!@zZ8z9Wf1)C&7al!P6Zz=Z`$~vDjbB4A6;s1pn^dgAYnl{p=ZP49cR2$ zG0f!MR(Cp~2j=os!cSEZG*c~fe}qBkJ6Xm4eX3Z*NLn%QJq+|}E^fH~QUyKI|L@RzpUfV3K(Ia!z*J~Iruy_}??+b;mycQFuDJmm6 z?he*|9}2l4A457XtDyWNqd}FDP)HA9YktU3#f!@i8eRztg+yUX+oKgKIO}@WiF@jy zkPtP!p#W77+l&^@dL9Dxzan>+7ZCqrGh@l>Lm^<(GG3(4P6hL~Z|DgRA>*B6eJp8c zDt=&gx5wy(fKX@J+246nvFFo;XLS-GpnEI+pqPX*3QBeIiti1EjO?(c*>k2~*?Ete zFI$44_qo=H{24{W=&dR-0m0Dz_UHbNctzBDcz2r5>R>P!QLde{Lk`WhZs_^a91Nva z({{hUCx-)OBkFtkL!i0l(eg=AlmEf*$=~$@C*??gpC5!}g?y~(6Yu0*s}>CV!ySI@ z${MNp(A{PIz#>Z}vZ@xf3OaWUUz9v>c9bkOi~b}&GK>y@k(Lb$24 zHKuEEFw{TJ-0;Xk0=HMaUc_D)48z3ly_-PBBPZRzSU(u9Y7oDBg&dANK71$dYYCu#aAF=+uDyhpkcT(+>v%E~vAX(f?^*U^CIQE-?_gwrRhZTEqt;9Zus}o}|9H zlu3M=2+-cJWz`h}VdcT`nD|)?ls%`qa@qr+T%@*A`h^ty=Ntd$3)5+zP(QJeHZGT7ZS%mb^h*%@X033rzjo2S{9$6`xW}YCYgw&h zeNRnH*4f%}958|SW@bK`xp!NZt7Cc(HGnhFRS6SqVVrANw=Qev_ zkJV`}$%m$+--})HXCGh!Nz;uF?BAxtzy}%3oeLQrWA(%tW8bLC{R0os$KXDXvEM@a z*c$_uo?~w}IMH$Rx=fJgSb5H${N0{^%l|i?a_U~-WjgkTu0P(mz!P^Y58(g(l0Np$ zv-zHX-r8Z{-u@$Xo&@F|-}iR+2>xa-+^)A`a)h}Zp1nWm)6ae{Z1&+BZ_96wADq0? zttGwD;c&NS#dyHVll0x+#l3MsX}7208o*7qQj<{68~FqD^vjC@i$84-J7(sM$8I$7 z%o+rA7IZo^+n&IJ3&pI>9q_G#_sHu)FU%EQDE73(0h{c~Z$y@Pp_7$H!Mr)*0m=Px^F9(ic7SYjR8co$=C+8L5jSd~sWP=fbkp&R8*d`PTg} zd{OTQ;m{q<=yuV3bLR{?UeQ{kd?n5qf9$DvxzUY|PraPetaF@^b2YiT$c~P+&0Du6 z3cBF@jdsFwr06J@ZfiHF?}FXgQ+jH4_r|psVYoAhK|gI z4bkVaT=D9Wb#4cX=$N|m-5SX?uDHyyz$`k>y*#nha-SQX`ciUg!b&<`^=aNaNrHy=3&?mH z=~z7>H^?!Fh6YF1-Lx8{ ze#D{F-yOFav>#Yt$3$hFwzk*d?ijMmuHhG(iN5QL1k(-N@jrflw*TFl+EN;t8MMDh z*Ja{{NxFH9lW3S_>vh?Xv>zkSW8$PtL*^R&v|=UF-&$L{oTqLm#P=-pEE$hpX#~eH z*$o@R=P9#aGO#}Hw0zx7SIkR%VQKW1fmWV#TZ+?Nao^zVagKKwc=*E;iKrM?e17KI zLdAy+oU=CdxUPvSt}IMD-}s4vDz43YvlLv>`AUKOnI{aKSCN$5-0gxYK4CsPNq@iO z+S)wNx}e3U+Z)yjGqG{Do_>*v3r@TAv-nm&1Dl-Zwrmq{!T6c&QF}=FsO;17>t{RT zLJ!=v-B(xZ)v1{wi>#MBL>ZF$4 zS$PJ2w<)p?n`wo+$E82GsKCJSQM-9D%K~%M_nD4=NcgSfiOW&}3mncZmK3X@L?1NN)QepF+#EYPPw1TE^FfPqAN*s5EHK8!d&D>18_RM6gIC=~u|9J~>LGDYeCQ@EYm{sGSD(%c(bWE`Y=wz&uC>AsJh0+| z+?j+vD_r@oN2b}%6PLPomabc3jWM08n{I6PME;T{lN-;i(Z%Vlk&UJo8i)C;_UW|w zN1u(UWxivSE-!CrxncW;iKBPJ?)*=84o>MTUAEnDRF^OKqsyiLAG(}dmvZY`Ze83h z>}gX(WNkk6J;cMFC{DeDM`YW7{fBPgFZ@E@G4^htA`{bY>RN4m!bM-z zF%ULcA6hN!i8Sht>>V3^E3>={DOr?6D9(BjapU9@#>>~k=9{<=D z=S9wEP~U_555LZSCJSb}GVqvv#P(f|Mp$&vH@M4|fzB_D_W1rVLUG8R?XASX6$`)Q zRm2V-%WiJj&Mo`7 zbpyBV;MOhNx`$ggaqBK_-Nvo^xOF49?&Q|3+`5-rH*@Q5Zr#qU`?+lcZrg#|w&1os zxNQ?|+lAYPzR?r>yp{{2k5@z*`@uq5m2 zw?rli(rR*F&i)^4;;?2L1^3mr+}KskL>lR@Sk(h{pDR0;G&Av{xo5?uW_SFsDPD8c z6(*`FM*rNn#vNN$efBu}l!D@pr8!K0wOx9~apNR^GcHfpTbity=ZR*$Kb*W@2^U*>g(8P8b|BK{kZLME%!tD@`?=uwugG#sjfT9Qg1- zjd!~vrdMdKIPSqjow-GV?VBAjwWc6Hj^Mu|CH1)KRR@%Qw{4%+R|bx&4AcrEzR}Yy z#akymW}sWA+{%5XfZ|hcGMWf|e@v+jJN3>EbJsS`JJrU(@b1EWE9C94SZZKy@G}PP z>JwkG_OT82#+2s1uVUbmO;g|ZAGAh?_3?*d%NR(rvt4lEEYY?6>DxMYGq5Fn>ihA< z=2$-@_^ovf18tXo$t#aB#ZM)^oom*U_HTLg9Jy+YT611lwiEdgv*YX==^!I)vhun- zu$X~r3%1_8C};GKJSQqrl<3xBO1G+P;&BWK(*eEhv1VshPeY4)%_2MW>_L2-&r@pw znbFw5^gp__-cn3PB*6A>+(_lly=_z0*aD9>>x)>K49Z8(F3Fl>3+<+Z|2TX6jfJa(nKt6*l0tX8*xC+cmNIOwBjX2pho2 z!%qTtYGZGcNZO(j8#t%env(oc8#xb-l+7peJ-d0_+%uIrIJ~#bxni#^1m<^$=ZEMZ zr``G0R9~qIL&X zYobm@n{#NZ8Ej8bs2ne>g?VN}4O8OHKuGFF)WQ)>43cU&Qlo7KSy$#yoHJbu>sYZ1bb4BuGG>&Cq{Ut|1>jk*v{QEqT3l3ISGU>(@^{XAa?5B6 zsyLNMNEDbrT7k=|$5$0`K#rEVP|gIz-*9GC-B3gxV*~S2VG}6#+!&>us)W6K=E=`z z8$%n%`k2msCCs_C z^sxb044Y3p@KOoI?dAI}Z8d-()5$qImn)!<3|UW>0njX`?OvNHhaha{<%83pcM0LI zg>uL#v^sT3bQ%by-#g4VActMum7Ih$T}b$;T>I#;944opyC!o;2ii}@A6yY9kN@#< z?@;E3mpXFz@mx*8j%Or4JX_~twJav%PP={mI^g>_c`5UkG~QdQyD!Q~7gY3b-ktPS z3dMCe^UnU%g-YjBSslt!7!h+@%pz+V7;MV>t(hZ*D%s5M4CCpblUVAZ!6S(VhpkST zd+5QyfwZ&sB9d6XLwBFR96ivf@C{Valfvfx(GxtU=|j78IwSkJ6xNtuGtUi}0dUMW z5F;co!%~a4dDTpyJMAy$w25JRMyNp{uK{$$o1XmaCW=X?cpRlZ&4j#53od-G7>}Ha zPkQDF2Ec(J_twrIHTfqiYqFjg0MEV7T^|cS*VHGpIZI|60?%?Q#YMMY*Cgo}n6EfU z;E6IK$p(*Vaz51Ve0r3?MJu<=ynM2Thjvaa{{ewL%idjBe&4=y#4Opc&JcbV?DW|b z`OZE~P)tUl#}KgTlgWmsKkR9DiWaKL8v#r%pZ&XU9OS45ZMz#|1e~P7GDQ~%Pk7KGaByALL zp{Ynid;hynvpfj>p1iB)c3l$adw1?#{N4nThSz%Lcu2tT(l+PnQd6MkslKXuB@VoM zLk-Roenf+mG%H165pI^S+3M1Ym1WYP(#L0)b=dN+u6SM4>!%oR1-u5`ohu5Y!A&pusoMl=7`Sq{ z`CX2qpmISEW z7D)@LumM=`yY}}z2}tv<4z1F$1%sit(uJEOpy-}Rn&$rG^`RYG3fU;L$}K{!pm%EK0Z-}XCE^X^+sL#*H<8wWC<3q4ylRPv$_$(NdH3rRDs z-e2H94r%nDZIJ@Dpz>mSN7H!$tR(qYU2P$wTjlq=AQ9x&*F=R+p0Cv)@5mWGc>)_eytjMaCv^}~p1w?lz_c>!y`P6PA%>LS zM&N;WrM6ERwBUE=_`2{VGzeEMoojPn3no1pgQNbyM|Ph4;&Olnr@vL2u^(%J)Sk_A zoSx7?%=gsxSRHNnNPT}>)g6{lZ%c(}gXg%GmWnWU$j_U!)NFzdP*2TSZ~7l@|HHL4 z^)CKOZMf0%vXj2X9lpLvYXUzlaF%Pi&_rN2zO)G%G)GMO2I$hgQo`=wY;tjRyRHf-q_jzXs-lg37u{SDro4M$rrf+ zLS#U`;GN0+r*1?q)y5p_5{Kvs4q_fOH=teLPCL*h02S0b{`Ib4TWLM#LKqKFPv=z$ zxsJWn)IMMzOg-4X#RU?DsfXC_+q3QGPh*aEfd@?L0p|BLOQ;FIc81wZk&Bl#zSeNl z49=PF1lxh!bS<8 zseeD6GWUP5GxeVMBqz8}z0uYn3MI#c4}36pg5u8#mz>Xu!mX@`x3B%2pgf{n@%(#H zm~k@uy6pldNQ#;IZ8fhbd^zO&diPByP}=SGi^G`!2^2oxI|20sQ`(1uWJLXQ)e)KD)hPs9tYa>8?O zJHaz{No{+S1ai|4!S5sO<8*<$dS#o{i?PL_zjxg}w$@s2=x(??kUxEE2ghR}*x8 zy!&MN#0=zR5AgNUw4iyi$)InS8K}&YD|mNZ3plrVGc7aCplc5Gc%n9RJ+u^vS!o75 zmQnh4YjmLb-S_dA+|2-VZ;9XZ(1riz+C_b@Mqd}iOLJH57dC?;m)#SM-jMu5mB;!# zNqy>#y(`l|oO+OY2Fa)1o8LNp>Ouzafsg>Z*cWc@1?Zz;A zh}uE$Gm2~zP#OKTgpBRgRyPUE^9TNKZ8ApR^0NI4kG`Fm0{?@lw-e_%{)KraDty<@ zcO-g#P4EMLQ&2HoRwR?|2wkDqQ=?iZm0P;uF( z5#~hf&3Qy$5WZFUIkc#2&;Z0^PNlBoI0BAy^1t9g?BBCpE)lw<|7~>%Qx55a_>u85 zznhWr)MHicde9zvWXn!9(*Ak<#zd9rF!~nQ2M55%{d8#^V!u=0+bDJb73#Z8({uo- zH#=t&IJLOS=b#qQY%Vi*h7q|)J=lI+PHonk1z&AIMXH#u`xdcJqFENX z!`6Rc@kb?FqaRxTEnmK|S?`XLHE=$zcKhT?@E6y!WHnj=?(sb;+E4K7w{C{fQY$E` zo0axkfsFT|)zzROOW@GY4Y#{!0Oy#>r?^H-zyli<3(lC(?NWxz)#WgDgWd3tbv4=3Ff16)apMu%EkBGa)DcJaLW~L zxx+1&xaHPAa*bQ=amht)xydb8x#cdmT;`VB<=zgo>DHwF@qKZ7K5D}7h$hFY$`o>H zvlac+G$Amvtk;6a6!LO6`kno(21z+q) z5lVjg>@JZ4{In|Ci1<+x1O@YmPUG+tkN;{2 zaO!uhXPz=}emppG=`8V|l{)#>3QdIpL0V@0LLz_6H8T?i2wcl&7e(X|kJE_eEPiEx zsoQvr6b%5*rR?SZN!C`hFsM|*R|}trw;@7OrnQ>5IzvhhkIUoV{Z1dM(&rd2RMIB%j#w7gpbtgVN{p1N&V$hEaF8?q38&Y;~v8qU@+NB_J@xtWK190_2i5`BvEe;J|=XT-N3$DIrA?s zs@z_rFss8D%C|i=zp}#gA3aPsRDvX=__|?+bs~K)6Vp9EtM>~U!HMbCeLr6_u>8<* z$JuXZ*IhM@pt@LQu3Q)s(_E^~*OUAk8{;*Fm;G<-|INjjo)>&N zzzFtFnfBcw$N48|4K?(A6Y% zW}Xb`zjfJ(DaVZ<+@L+`m=P0mpPie`uV4(hbuBk$5O~V^}foMb+kDCh|AV z-cxnZ7$%=uw^q}O`4@NRHuHy0)?{M$1j(Zc&j^0F@JCQ8Nz$l%{SQ~Uld@M^?=}RZ zti~BZ(hQ7oSISuTVr(50{;UHx-nj9~jd$*K`Dfj@#$~c0K6dA;|Mji6rC74~3!&BTq)z~SSWJumr;!MA%T{m1tWRnL22M@hEWt3@InAN`Iyi%-e3)@bDM|ov+@G zp^@?$Ya3_$u3@0`uQux(nh|&iPZrtR@xQf^xb#z1?k&N$%}V!ytA_v3FVhB1p2MobrG;kT4_0UmfFb`-zTc7xO;}G4VpJx$uxQG3PRNT-K}mQAEFtkbl(-~Z>(4F3UGs>&|gm9 zyI&`yFA~kMMp8OnWD_o#C^3j1N4;mo#Zu4tr*m!5F90dzR zne$QbU{$1N#4k6{S#0p);~8hj&l_JI-|Ghd;qP3L?CttfZcsX{!a$|a8NO_{*S$yj z7vl3Te)h&03fouDeMrV#7L{2r?SnIvQtzL>bcJ3@mrrnkBu2iXQMD`hnDk8v0T<}C zdi$W+*%ef-mu*uEae>NC;zWLRfk4k!?}gl40482@yWZsj-Z&+QwzK;Dsn zMx#Q~UeGM2$YN*UP_nq(1xi0Z8|e^shW%!JQ<~~rKk8%R~;&pFNzHtMK;`G~1f@sLdG8#ef&94zp`pA^pb}INYx0G_iCdnBRye}I zI)f-pLwCsM+2pK6cLbq*Pj$PL+@ZI+$85(*2WVfES@7K59TH}D1V@xRKu(Tps(7?J zh@1cDZq0N6+Ufp_TMFDkN2;T?PRRl4HyA`+FLH;Z$3j7Rk`7=|P-2r&?+!v6=vEp= z4iNZa&4t-7+#yZ>YHDB?K>01Js+ZF|fTOWiWFK`EFCketd#VTMSeP=em=IHR?a<(7 z4U*qlx;8-?ppsfoK@XU!Epgkd!5%`IU2pJB^Z*0ufnNd}u#a|7a6;nj61(;GApPmv zmLK6He-BTws*gRi>cv;2t@D7S88`f5SK341%!7gRc6dN(i1Xez&YMrsW;vea`^b|8i(y*59;b9t@nfg zH(F-pGdoxkTM(OF=LzL!*5szVvW03@f7OYvJmKrfUO(jsTX?p%dhLyeo?!4{bM#d! zTeyApoOkXQPsl^#78`vVpgBAeJuKrz#;11ebEh@r&M_}EjP!zaT?zGu=4;I& z7gTK^{At_#RfoNyC`Gqy+7D~s!5w|=)!xuM!9;aBflG8Y33U({h>NT`)fS3a3pIA} z`G8ts$f0)>ItA=`!Y}E31)U6bk^Z>+e;rP7c5@bs%{Tz z)yul-^?jl1*3P|Cv+N=GkU^CAd|$}$$n2jXYzMB#Zs*t5`2x=z!AGshcEIv}dQD~` zo!HL4)e#$PVUfU3p$j&2NclGD%>{Eixagy;M^EqsY(LVuT2~t5eFDfIVbaD2?KC-`)s)$@~3ZKcCOM-s^duyPWNwbMCq4&`T?s(5`v(>^Oc`h~bs- z*vbT6IUzw47q}91%x7RZULP-C_cwsrkIwV=Rxlx(m)}1R^H+~TM0yDm@;lULcqKSN z#fyvLdluvMi}I^1NOl4dr^I*fLzy7Kt393O1j&2q#;=*m1f4G$?{+C+d2wi)EuSzG zS|1In9a!N!>SOBmhZ{WK&NgR&cS~Q*l3_wc3I9h4H)lw?cJN&{4bL}b(~|6+&X9w* zIXzGO{o6$S{#!1Pv}XH$t|}8sBoAM>WaawzeYx)o+V^z0K=-iXn_Ce~=xSIU@gDCp zeY_fk``c}JnVS=jE}u7 zF^}CKsV!yw=0|wFMR?(I?hvWksr_(>2{$qp^Yx#@`wup0*J`jveQDG``RpZF(8P14 z&h!8SUi}(OFV@d8?@qez4kI<5Ut{<`UgXw`+Yh*xN{SGM->LL36$T!_6Bri~V8VaQZUtU>pl5KEG;9tGz*b zH6}$i)^-W8puE1-Ima98MVK7pv{~>PFDFZs1*yDR&z|_-lW(RJi{N=ZnsdG> zkOixcy3ENskLhOjdahhJ3vQbwbnS1#a5V4pPfo|*^AgY>XTo+~E#+e@s9j*?zn~nC zUo=$o@C^4TYXp%Tw%TEhsB>7!5J(Vsq5p+hS$8j`I>CV z-vqVCP1sn@HEDk_WrG~=FhiUTKGXE(di1kkh*!Vp3D*Cx8YZiZ|6ReO{OVN}JlKf^ zCVpR<2af_Q4|r!&8f>`1tGD8W<;Cy2Q5O^0kjlSHL}4lmHb#d(bN6RM@Y3UFX7phC z+!jXaOFdSA(*I1tPpcIPPpP zPyR4x-!m3;@y-m+v0?j>Q@NLf+0gy!3De{#hR-uRVGM8B^W&jn0~`8WraU-n$p$XZ z#q@y2x;FTsjcaY7De2Z(_Xj&bo2}!C<5w zA$znAiA@lQ@ajf=W^9;YsK~nFuroVsG=F|SUeBgx+oNe=V7;_!<=_JhpQHwvHj^-LU6u8Fd_9IIuiVJG zP)NFj4Jb^1?^0utx30rAexoWh`$ zSBGX98`88_9eN!V28F7d7o-HRA%Rz;dRZ7ebIw^Mh3URGvr;$cbr>|6UO8!$jOpHH zT+E4+;XrK+Hs2eI+aq;_!og>x3<~}}UUYBE?dhZYg(Dj%KQ8z#Z<-Dgov!Ca=i>24 z>KaABNL{*U{64R+$HfS^jnxKP3>%)!p0ewMR3tp$TWPZd%cG6FTE(i7P%H7eaJBrO zn(5+^qksR#{K>$KWf=*Xykfn#v0UQSs+}1LuOaTF*_1`X3p(h^9{?V z88g17oR1vcpIWhe#oO@D&ygU<%M1Dr?;oy%A3qpJ!GQalt@KBjzZ(3HF7=24v6>4- zCS7>H;nkZ-kAiFpd$;uq7Kr7eW9MU{K;k?$M5nTWcXa-9a})%ht3MxR`KLyE#f;JX zmSPxx?T?<@-AS&+88Ht1M?G$ixtGR?vJH?K~PatvhNhS;G{44;`68lM<3 zz&+k;G-W21UpzZ(MGVk*c4#8rpLq4OF5>rBZjiB=@$#PjaU~fvM~I4 z`qSxH0Fw__nW=dGygEtWW1*aPmYv2LtwY6$`$NYp_~YMz?8{HA${qe|YrLXvJmrY> zIgKUqSC_{DinK}!#qH$pucHnG#z79R*0LHC26%jK7&odaLHCIm1D-K+Fb@K%A z^LxHCB*Nn$;pXN|Q0Na$8{O_do)rfby!tXr{ef2wFlTNYB%eGu?mojGhDtx*^Nq*t z(35rDTK@2iSJPTQ4rsi>HqQQ_xU6)))xB64c-pdJ{!2gT=G9iNiiONIi_T@=_ZzL# zxH@*U9@}C+FvsLLEie{(Z`gkk*7pP8?I&KbAc56}=e@oVGi&MACPnp_@2PCDUs)kQ|a2OnsvPNr($_w$9f`<}bw12mo< z5rx~l8uijX(0#3MwWezfP`>haADZL?X`dXz=2^x-Ay2O;@`mL3(M#%GFn#d~uFdv_ zF07v2o`C1e)5i?FVc@-@KqVyxf_d__0Nba6FBkl3iUz=H{h1}$KAl@|KlXYw$f>nU z93Ak43SLZ2LG&m*R(Oue(M{1%ICA#uIa+6PIez{aBWAl7lvnnwZ=W3vO|gD?S1a)N zA?H6jFO7zQfhT6(GkjpAUQj-6Cj~A&e%uGd)~iH+!u?04$9ZPH$LpCMomX-z8W@qC zO=`lvAi}c;1Y;nFXE&7iLbd!H^wtiq*JVS}Ta3RF@pJNX7Q{e1rHz05Ha{rm?GsyY zI|&2A-5)?&XwWqQzt7XB?EK*hPk#@Hfss0E_x#{S^f8Ke4AnJ={7#fs>)C}7ezN+_@Kg?3*3m+4W^Zr)?< zw!vq#ZrJNc$iKMKJUZMPT1(a@q{>ENdI+UD`C|M1w)%3KRuqWvW8 z`OCW#rR)W+ym{qDK|b#+Z=WY5tgX|Ul@kRCyuz|Vp0JT8?^j^?9*Y$f8wLpS&R$qi zKs`6Kwr@GMTPC|c7sm3w39D6!+8!{(s}H3R1(c<9i|O0kp=mjzZfS2MFnF;jzuiEL zM;}ikAu=s*!$74QY{c8N(aA_acsp;4cLV8JpLHpF@&3e<&v9-rv|RjaC*F@l+PxMg z6}iE)nMH@cgyZM=#>U9q4elvixcx0S66%`DeRLJwKqtVyf!B8S^tBpk^Y(Y#P9CYt z=LR*?=2i0AJ9cv1dCy1W0ylD0pEq@b@!X^By!PZ>x3qI``}Gy`gACjjo80ho$9y-~ zroWqUAO`QZCjM{7FLHxD-0v-Rc>jzW>~MD%cZVT2=g>Qmks$E_8>H#(uyMn6C%249 zXbpI9PodNutbfGqRyY(1IxSi2Q!sqMYF>9?btH_{Sc??$kKrU<}~Z&ePxkAD`pF(Phmi9+?Phn9K1hc@)&yU z0XMcY4(3HfLhvnYhW7c`7KiK zBcMWpZ!NQf0r?MBm&e|VfP}e>V<)F$`QkmKu235R;jaGiKF2(v^{9@LN>Kz9YBi+K zcCk#A0o`Ga@+YVe!pzSdQ+GV2WW!t3=6%WI{4_UfCeo#aB7=jiv*d ztay5|vlmD#u`F{mo(}mhp7zE6#PrL2VOoseuP8g#8gb7P^0o6NLi&ON&K_p~X?D@|O7zp$@DDxr= zBF&zPNxWr1p8rIP+zVk~Wq4r!S4lix^!W_ayfE0cjyB_liYG|8SZ+WM2%_XXW0fo<#qNX1Wh5V?L@g+G7xWQ*oa|!FCa>sgVmLF!o467ma znaZJ1y;V3%uZRKL79BFl`92LcO9!gvcQQci(Otcl)zh%u5~!-E?g?Fy-`-tFn+A6q zTILRzVR_%bmCIx}P(%QAh;yi)=QNO1ASRm}nNxYk;=LtesRoQG72&&tJ$Jy30;EH_x z8R^~tI8zh7L-feM`Mk+|-()^;GG92EPn^s*PUa&g^OckN%*lM`WIl8EdC-e1_ z`TWUz|71M?vR(jLPk^j9K-ME5>lKjo49I#1WIY73UIJN9fvmSc)?*;+HIVfj$n(a@ zPv#k2O$i!}F?HgCG*4e23i^9qnyQgEoRby|nY?<5##}ha^LI@Mf%@lIas14I$~9DB z&7ol6g)T=`b3k3@n(WHtV3^2@>8{|w(OuN{ju(T#@;z3(>p4*L`k~D@ZV>F_-64O< z0cW0nMlEQxe&%>Cgh~}2*?B7vrrJzMe{9({E zn0vk{toRrQq&Suo6g`?K`(63&RbypI_I4`NMD{Gf88@CASTVB)mM#C94c=7f_tPd)$=U=K;%!VDGd(4bf zqCix3tyx_Y8y5}xmDo4l6`+3<>Yj?)u0 zTAy(`d-R<9YZMss>dpJ&{siYdZ>*03o_V8*+ck$D=2&BWv+~)!LJEh%rS%(34#&ug6nsOmz!!5rL&I~Z|Ypnc4 z<$~Z>ld5D)?>bEieoizlWQ67`Ou>5YrTf)_cWt?l$-T6w2k(3G`1uV3E@%iH*)nIV zC%9>*92%#N-_Hz6&BOa}V-kD%&Z%4o=$a;(F^>UO%2o@{WBODwdt84Y66*==1}|(U za3MSQ;1{7=9uVu&f9D8=3k9=Y6@-BY{L1%!eQy%pHy*vQbjN&Ix2J1YBkrGEUzfiV zL-)KTP^)`tx^=Pq4X9E}d~FU(R;V;nbiBdZGrdZs)C{-^=iaZg#Pa*?$u;v|nSrwU z*PymJ-Z06%Nb;Pk1?0;so{q}*hLU5mo$fO&;cjJ>@3$4+5G)eeICRMpyw3I57Ge7{ zA*U;#?1&{OhFo^a^YZ>@{Gt!kqDhy$;BHOv*P*#=tQWgnTlLi&LaRkD=#;RbHLcX( zRg*Vd7rp${0@L5>N4u+ydwigHT`ExCvLUVhlmJmcuD`&Q9eyAwcKNBY1P8>OX1aE& zFu~iMmLadm0m07|hch=ZVd=taY4^=IAni8Obt2wxz8ZD@Qn%;8F1u}o>n&MO_R)dX zrpAFs6wS=d6IdYWP8<3v&H>XR)4rQJOsINl5MkBB290yiA}SjEU_)XLw-WOc+NdNf z>EH|Vze#Vup38<7x%MHyWj>Jp?B)(8&!1N*+gM)Z4Ts7wBB$VX>qE_RcfH}^wyvoK zFIkZMYEtgjD?YF(wntj=I1B6=u1J4N^MPL<7d>BA!h(bFSpKlm8BfY!P`kAi*M8}p5y zc)`lavd@FNqTu45BKzj)UQp@o$z1z33XZP~aeUJ53G0{2FRAT|f@L+=rk{-Pgx6kg zu6>f80r_XHO&`p_`f!bUb53Uz6y7^N*`b&LQv2=pv^PgV>3+E>j87hLJ#_J> zJIulJ6}k`wHF1n%I`JM5{5xJI4@E%?cUSDwSJ?iserWNzHVR7SbiVpAn*m2e=!=7| zVEM48t@OejydT=lORB$$zkeSV`ev~wWM0oJ<3AMz3w_pcYrlKKGR}p>mZ~V&X65+k z$Pq7yQTj+px*rAA(;^2pb$CJG;tZEF*goGnV^{1mMQ_LwI>_Jm0Dm9x%jltz_doEA zmI$^v{X7<()&O6_Mkf4RmROtG9*b(8tp62zm#o6CCVcG_ zYW2v7LnC*j7BNTfPR))(BlXlnm}CA)r2NM}Io4kK$A7t-w_lpXjplU|WBmi~yBwu? zW`S`?tt`|*``llDCmM^d8f(w`6Mw~9_M3D(-kVz!DqgW*(6h?_dSo2hm2s+Z6K+S@ zugY3x8i(A@i|W#wSztWp5TCt89QrnJ!FTx$)<5GFDqAnOa~7cF_k)}9L++3h=JI{* zV*m2m zr8`6#s^8tW!U<5&s_V1caDU#V2Bj;VpyX+tM(BNa(D4-O_qc@L&uuGRa@rkA6c+w? z)s?l7=7%DZ}>6BM4N+-9ZW??w1k`g;M=9;$tE zHFAf-MReU8r2y8kov(Zu?!Zv--OG0kpzGMR>GN0Pwx@fvnk{~=A~^GXsXJ7^$uPUf z1gzIGj-}SSLzmgl*Nj`Ztr%}g`RM)+JSd~7g0Apl=~Q@U4i`D-`$%nft5Mtl2Td5c z5M~Dg{}bCfjxutI^6xhz?=;ws-t{Wvppo;7HrvrVW(zrJq>C2YQN1dagJeg}KW$;; zyBZGa=AG}%vIVlg%RE2Ny#MAfHm8who-NSMYfqZs%|Qx2mwP2UY(~Nq?gny@cHz2; z4nEsa{tMusk$U%QZ9#x{X9f4?xK-P;rTgFh)F` zX7v3Tf5s28hU5Ek+pKW=o*Gt|>aBpyJKs(D4~Fv;Cbk={_!8vU-@_wRTk zI*roqG?LrbSU`t|V!J^9h?lr4be)MI2a;RsH%jQ&^X7u(T@` z+XlR|oO}})9&Z%*Ab|ta=ugv}l}&(GD!dWvIy@68`@S*ouCMx=a3F4#kLkQDebDCR zlM3cQJWpp2G=$LmwXdY-a=;)~{$+5G9w?O$&(B}Mfh(HV_ufm<0$%9I!LuC5HY%B0 z@Ja(rw+vlE?>Ml}eVX1}{Qe=HPX+6uJd>(pu09~%8SZ-yknkX5m&n*AGWIErdU@xN zfCIQplQR)d!Ov&5En9Tn4j#*=sIOelg09%~s-K3oFxR=UvN@FnjBWwPBfR{=S9;3YONvKyC`s*E|$GiahZ%#E12ojXew&M0$SmZIMYx|I9#`E$_on?hy+!s zop!VUL!Y9+svxYJ>4)UH9X5we{eG8jyR%^6Zk%x1ICD^M2(Z(~^NVzGV!UfN1E<;7 z(k4x1fzG>Z-8sKaV2WIdI#YuM?Zfwr%W6y@!nn4hoWg?Ez5?5aS7>m;t0?d_Zi7e9 zmIn$ni2a#8C-goOsQ%(-R#+KpM z?$s5FSctCcq21HahZnP=PiP1*LDKXAPz=|Z~P#0Ag)ByMHimOU%r%k*bmz0%Wb+@paXrA<|N5Y@&oG3^uS9! zTHsmPRvLWP7kXAvoCU+))V ztPWgXb9}aM8ivnur+25<7{Uu*r%fGSnNT6VvL}Bo4ena@Z=QhhlQ};%UD4PK0>1n4 zu`vDIIOW>;BGLk$-uZHpn}g|TPu-8nqILLYJS4?!~(N#V}e7pCkCzxE}qm z;on%kljddK>;yab-1kIl50(!%uDf&)E(-|4w(e_LE+kB^QsaKG{44izAS5?$ zo()_WSoB;H+p6Szb)$}aj5ucvYDsBJ4lm?@TJFX@YnEC9?}&bJ7zawW?reB^&K#!m zV((^gpq&?cm1qGU6a^|<(m4>gzwB7+U31Xp-BZrtfVr;F^XV@wL1AWTt-NP3>GLjF-{OwmzxQ`RJh7<$ ziVHznLu~p6r@wtiZC0*3D{qI^I14H|cW_}-_`xN!TFsFf&-rnj3%}29Q&Ko-iDvQc z{p{ev`^x;*jMcX2<+~k~V!7N=o#YMuPflYl@Iqyl#nMskE5CPgNUVMRB3GW7{jgb;f8UZ^9BT@IuJ~*6X5?eP|B%FD!ZKAWGO= z;BFO-p5RGCxAUe%s%UaYeN>NWqkA=`qj27J-3jLCu*o!!fC*eMKX}?|pvDC4VPWe*baYR~bj`c2x8$@LdYxT0AYH)$URsKzax)Zxhik+8+z6Z&o1&3@i_U@Hk?rTc zi~OdYd88BwMIG#%XL(cwcgBq<;G*?k-b&hGI}2`Df_yd(0?yKLY= zZ(^A_vf*85zsUvz-kE=d8LG}RcmJ@B4U>5HdGjrh1sU2ESazkQpBod4wD7EPz6q%9co{V z8A2KFqeC?3v~ove;q+iBMT7-*$#=5vU8AE@nd6_;2(#dM)#{919lC44d~%*U%ZIuQK*If^A$OMduy6);J?r`{N6L26I$jqPdLXCy5D4+iCav z-@2d^y!+PSOz0_pzVJYRE4uV{tz^9g6WS_fv*LnWQD}t5=}r+Ql<{H+@?B9pFK@>M zf7rNue@aJ!8!}tpxic`xAGTjhPztbcL(0E*m9xJ3!4Y08&Kx)7#>?xl&JV2PU1!d% za6==$YB4_;;o}(hzp`j9HgPYidLZ7By7g>7I2*rHutb%CI=)^O>A-EFV<_k0UIx0+ zvM)sHv>)udcWIFRl`#qr6Mx8+6ATn@_C#y1IP7$6@&}hWSqi<9UMS>{^1)_FCNRuo zedE==5I;}v^JaqDy6NsGA9$feUd(M46Y6>Q$B%fSkvuI`SWi&G#_SOOp0#SG+-)Y@ z=AE%G^+F1*dY4|xvY_!D7EraG$fD0b`J@pGYI%ub)_bB@OzsOjS+L^nB=yyEJyH3w z)`*4aEZ~{87x=soFYW2A7#76xV*Wh55HA$bJ(LA~7e80U*Lb1dSnbtf-m>r8{L(+ z{*#_)(~@lWMMW&=;qk*JFO+`Rz(ui<1-pNDd#tB;ql$98qr4ik>AeyCa^We#CoCAx zIGeGYt`+QEheydd0z ze&|zgOUx!Lk9Z+Ss+ImIZzK;52fTzo3@ff?qO=*0HXIP)Kq4<#jLJfDd9h>y9K3G} zyxo|{LL;$JavYc^izWAC7FspOc;-gnz+&ZRd#g-XsE&7*#^nG%WA@9}6--ocerL`k ztoJLdNDHs4XQ7d_Fj$_B?Uhf>y!jujV_e2E3Ik2p+tRAJnhQG;_iw)Lz(Vw`wR}56db1NKTjp!Q`CS$}V9{)%07v$}@M1L67^C~)fj{l+|N0vBVKC5$Ex(mDng{0zW7LOW{NLDPa~bgk>}QP9vlVO9 zr;+%lzyBE@|5qOWl6mVGt1&lL!!9ZQb?fqn5wLxp{gba7s3Yr`@Mj%lJ-Wz*6_eJu zMZkkzW;TbZiYj(2dAKJd0-k+hX4^fdqST#B9y*ssfMDE>;WxLaNbCS>vCD=3`W_q0 z$HPT>Hhz9Zt#JES{9I!4{G*zIswjJY@F}PC2uO6w8sE)zkm1ll?#M-jKTw3lxCSrQQU0-$sgY;{yt}mCdF>NMpdwcq(u{- zUG%U;Xm1!TY`Z0_UVK#Q!k`Umm$FI`xNixj#V|=Z(+25Sh2(bnTfyMGiO+7h+Mu+_ zyKHZrw*mv@>Z}*hHi&8$k}G3r4H{49JLi_!pbE#3+>~)PK=C>0V_$89GMz$lwU64s zldD$;_h;Ckl&=nD;#X{7`y|)$dIK8-w>lIgKHC6Qp*qX0(i%xLFJn*3u!a4h5!W(e+#G4`}W%{#A|*|gE&`=aE-8x8GHzVQA4gYf_jhsPa!dfxUgy-QU*ccb9% zeT4W`+`Rx=r9|mrX?Cc50bN(y4xnb$QK?D3_UJ|}wMb+tfTOtC?!Cw!m8@llM6RL3 zwt=^bubmuF6RP_W#G%9TMFo6aaSljsnOyhdH;z!Aklp*G%K_0#B`cHnJ3?R4x15Y5 zM+DoV6J5j|!Leb=sV;RodZ+bE;B&VVEv(W(oUjik)_S0>pUzq@!=W1uUf49#Bs(X8uQ~bw>is?>u!wF7H$Gjx_R$hhuu^T5cR(Ol8>WEUl~I1H9C4eJ zhwC;)C(a$T2Ze`M2M_dN`j{d7w0yliJW+B#Y=t+s@VN5S4)Gnte*uyxZW%5-U9FetH z<(gGq_OP(&Q{X!rN7U-nSxtLv4@ckHJp3f-h)|61(=&n&uNPFCHNy{p$@5Vk5BvM=$bGldVMva5-^vBxM*72s)toR?_!BFaLI8aW zSKnWGDHKt8x#O^06yxbC&Y`HCmtP==4uZV<5R*bt4)0zmZs+js|KN7}&Gspdm*`NQ za%EaZ;WU(EC}^XD+dfA`-8I)uLlWcHt3=1q;R-LwT>^fdB=~ZH41F|LqVqHa1BaKj z6*)pRR)zHqry<(s%t~DqM=)T@4?8MNLruKzwmFQ>e<%cv+)HwE7`^|0Jp_&1s~NB# zy%)0&w|VC<^$u{_YM?$QF$DEqoo$|Z-2rk+SF$`E@N?(477L?re-qcG8z|xac=5@V z_V9q$pKu7u9EmTshiANNJsrVlBwl^J-KcJNKNz+DIj456luzfD*FT@g!)n0L31pS)(Ia{#p53o7n6Q%21#erEGwmO z|MqUr1lVR^;JZM+vF74RRy8UyH0fR98)}BMQ!?S+)k;?_@-eB zB^UjtDn$pONR7PhnOIJmuU%f@Z;GGa5WW|hWeRHgzO+l`^Q&!pg*}P&-_k zT4fH|cYk#}*cyo1KlNnw51T`R(47exae=6*t!)9t#R6_$yL|eNS|CEytW{CVEFjgA zZ@K#W0MveF<(q{IEMWVMNPYI@07P{uIjp(C;xBJ8^}@B=xE8?G*9%oY6M!OB)oXGd zn?rRdYFXQg+i`*xGn~wUW}p{Z_cj0}GZZsdA2x&AI}EG8J`KR@n=rR0%?!}h%jWAl z0}$;(?sqp)GYC_VU%&lZ0Fs#W&S#agDTu9Hp4=#e*MF->#AUT9ti(zkBvp-| zw=(Sv-^3uKD_ZIxP-+Oz8ZM{i;`hg7qx9{|seC~}sL(QDr@Wmp?D?j0g+DC_q4^Ij z!#j+j)q8=wYk3f&98yu5Z$^WdeTLNnO_*M9v@Li{r9qC;i#>?~!B{VNbySjPTu)P=LGnSv>La!Id#yRv zT{(DtOPX~Kb_XNMn`?U4Pt(9aX4Xnsix8Cjgw4FAZvxVb%}ozrc_i_flCO2d1e$uw zbZ;&RLG6#^Uafv_0t{2m*#a!Tnl#OCHT*Dv;JP$RiFPcHt_$D0?_~fD(%8?C|Tz17`n`A|eT9C<|%>xE5kcgYnq zLs7+B;d=+S+dwO8-?v#|p-4i8FJJ#Ywp)t7dL3nlA}Cx(jY+WuYdI4c@A;vqcjMDm z`D3e_+GtatOrmE!&BQp!W>Gdt*#`W`?37T(_$eO3R~YX`~t z&T)Ht@%WQBUAVQ#9@@{w$LLL$NSqF^Dpr%{C&iPxi**VK}_a*d_Mz!f2+*dYoMX2QhEeus8EcdLvZU;Wn-{bw1!Vq#)ui2et2lhw5dL5gD$BSF; z*{^R0R~CnFPJJ7S3OgHPj+fekeT|@^^}SHU^ls+caNY*wPBqN2t_wx9-)!bAZyV^g zI)jprg`(ssc0vp8Tf;!@0d_aW7d6NKRI-mXWYRJwOKiaUMs(oEK^JT2ojC1tYzoG& zl2mEwT`M>}j(WvtS}4jCxULr(ZUyDv#81_Rh9dMny?mvy6~wfxTU)jekN?t%zNFa_ zf@v8X{*{=%QUook?pZ>H__UOl+b}&!{PxY(V3~u2#p%82|C-&PWN^ zLesZb1=BA&aE}&;;dk!AzEg*6VMzSKAa^0A zC(pd?iEnJ7y!>m!oxQlf&qX4U8g}sDr}+G}mvQ^TgMEVMus*WqrOoq;xc{wBTLW*~ zf#B5bZJ9;5ed^a>^94J|7FpGJX(R4WZQq?_C5(UdSu3Zn$NJ&Cb7#79>>+IYD&Iqx z-g@Qr`ZjntfPsK#p-Bg(*G1>f%--w(66q+fVE})>P%)EXJb(c&dT4S7!-(Txkc zr?`81qqx|UKKaY&NUw-l@btA8vM?2$AT|#Ej$OE>URNU=P{q;p%<`(_R9ST50s%`mGo0H=F&S!PE(*?peH`VUhRWwY(Nyx{dM38zsxH zQ3;B4LYtNJpKMm}LG;BZLh5esO*^*wpxe4TY4TQ1==a0&k`rA%=mGmnojJBU z$-1Is-BGeGDOtCatZVvz)QMB3P{xh;7Q+^wdv3Ix{da9k-u5OXhhy8=$fIc5p!A4+ zaqABrNH~yiBH>8FnZyH$ClZe&p2>BP_3+4gd1O63vfdt9kB_X^N7nOWXzxG$*3ui@ zAXnLc8Oy!R%+pN(G$M==XaeL2~0mCREYg8n(R4Rw#jgoY3=6!l( zg*wJh_1w0~8(FqUEap(G(bSa86W*u1(X%Bh&iv@JLQDE*@j2IfqZ2Xr=giq=g=`e{ zpXlB3M#}_U%O4e6qL*6y%hca^BajZb5D{vL)Xzs9-C^&8mY&kNGDX%BxnHyPdzg&z zu3u zqm0L%5uP7?(7v~(yIBKfsOJ@RRlyG*WYF(Y9v5eZmK>*blot`hzz zY2D^+*JAaMd%>+^4RQX6J8)}H07VbkcY40iD)2`SF6GY@b<#zz8W>c%G!ylyT%D2K zt%GVG*A89`VIsMzpQfKwwb305pI-%BCh8Ubbn!%kCR(Vv&mt|1iMV;bAD#(mqIwOx z?vel|Vw@3kRnJmK+t}t`;!2r_cD{5;%QJP*b;3iyMjCz0?7I?b=zc?r{l*wJ%Jy)PW<92&G1SVX?5nD4A9ohA?ZW10(CA-9n z8!Cr%8d5T99Ps;bXou)`S#-l21Be3D2>@jA<7F$)zQl=%>3B8l{zvhs}UC9{Lo+!u(NuKD(f!u79u0Z1xKLe&z9Dvs2gW z_LQv?9?rz=Tbh!toDO=Tcer>T?vKx{2cG1=p-*>J@6cxA=e8Rcy=T0lHw8EA{PxA| z8FG6|*Z0sBvXR$5#_tb`d;ZTboeTK zPNtfPkZJmb%M<(P3&JJ@KHiR>i+0XDWAv78Yb@0y8_h(+51(w?=Jbv}7&K@9sX#nl zkYtT})@Qn(?DgiU+DznB9`JjK^EdjIJek>-#BlrS&DQfTztab6AGooEm}ogOv3y?X zZ~Be4N%PE4_@m5 zdP2Sg_=t_SuKMhc+P#;w2+2smoHa^sK5pey%Dk0o$b7 zLwiK=d<=rC1dd3+`)B1km(%@F#r)y=AWbRQ**h)ytB)Vb*`wO2T0R+u7r57VhWnut zyWTF6X_SV@$o#<&1;4+0sc6Xbi8;S~QB&j;@i=j5s9Y1ou@Lt|h1D*?SA3*kx~Bd# z+n2s5^T3X}qbDU{sxkkvwky8qMeOv-!m>$VRJ?dWM3*lr+_<$<;fWZ$yFbtF!jLbb zXjdej6&(kwZd?2PcGHZG`d{zX@;-<>DwhW87n z{^pdJ-}Jsby2$)tZ$!D&p{^(Mi@r{8|LON%@qQL;q$p-cfoGhbF45zC5Vi23F6{~* zEZcstc?Z@9pq^S{BO?el4fD=_#7qra)|WX(2tZ81vx`eNdZWyM%m)W)g0S|tv!=d_ zH!AdcwfE>Ueh9<+v)cqb-jY+oMy(Xst#Bjf$SW^InJa`c1O#CJ%vS?~*RlSxhUwUL zj337N{dCEx!urd`DF2|@6gW96^MrdEexCd+x@wpL72=<}tv$R@=A%132geIS`-eMT z?^W>g-a9?@AIF1<>i*NF4?Gd2I4Sz)ehHv0-U|68o~YvZk*0_y33$r*>GCPt6QT8e z#|6wM!uI5#`)W>}s7`pD$(^L%^yM`VS05i@An*`=b@0Yd`nlcA0^1)9gnploF}cu7 zeZsYv!GwrEtE8BAKo|ko}@;=^O!@%uBl69SmpX!*cCeokgyQB6! zVQ;$c57eFZE8UQ4;f|7TZhx#el@D2p^Dj&Baz`s3e?NG8tq>C2edX(}DmRpTg*v=j zLIB+x%ppVqKcNh0$r-dv9HTxu9Ooy;lN57K1qnN4-Hmdua zQ2eFt&2rCVP|XY>g_HA~(A%)q_O7o}|LU&UhO=Nngc8~ruoY(JIH5gADM079D%xf~ zS2?@c35k_i6wdKcM}zDjPTv}5RQ}2+?y)r9FDu^c$ZT;&#aHex)3?e3GmDRs;pJ^y*P`PVHg6ks=f(`WJjUcYqH6XgaJ+D*AmN88LQ+^$o-P{yMrj06=xr_Sx3q7~|ea_n5wbpH=K z4O=WK6bj!+&CaoUo@4cs$8^^*-HT`E*#9weNWF>Ft4O_z)XPY{jnwN%y^qujNxhNO zD@nbR)JsXdmDFoVy_eLBNxhlWt4Y0^)XPb|oz&||y`QuTNV|cwD@eP8v`a|4g|ur( zyN7DP|2ut(FEUy^bC!Rb8LE`$o;kPK7x^8ZVKP0`454Z)r-U$kddAZ)2AQE#P78yN zy!J!O7JSRGKWK)sA3hYEpyrPh@4Z!Ay~-S^{@fn!rs~Q~V)i2x3^-=0KVH=J$3o+-ldzIeSMgDla96c6_a9@3XhKlY#b`I|- zltSSjIX7;&`m4id8uxFV-?48gj7>tKUdQTqeDCvz?@4{1v z(ojscVVccdHfowRutPW-&*yk|(@qNS{-BuaTpvRu*PE+6Re^)LJ_psO9o9#?AC%3^ zli;9|+2f0QCH2uks@~IE?i|G0VgE#Uo(>BBMtj(~hJyx%nc2~oG>~lC^5pP(4%%pQ z*QWa_6+NTv`?l^G2U+WVk2N@_f}T1`F^~0f(9Ky=etg#zk&pcX`8YK$YX4F8_Nd-e zv}Vcj-eG?(iqy?uDQ}cRv2RseJ?*%N$&&I@y)28yc!POAWy!oRQfTV^l%Ys>E=q`Z zTj8oHfnH}QYKKqeqOHr6W@tK0Kxagp-&~u(MVS-sx?k8Tj$$qBx zVR`AZ>NtO&joJ2Tt7n31RhGNj*zgc}K067D2kNW77FCGk$u1xYs~U6FK0(j`f^BwhDObF93-;&$(h zko8qn^p%zCJgTHPh+>~!y}IxT{c(4H{3{LIe)0PJfs`it^!Fj3O+z_o_}HO#3p5!YqZZI%OAh*W0`yIf(lI8A^0o`_g8VR#9^+OD(pF!ws3DC2QjaiNBab+ zLgk5WiH#PR7whv3L_JiY*;b0VR)~XoFNN35FINL3;C#g31ID+*yxE^$s=?;jZmZV6 zXCs=y6-}>=>d-s0#HX$exBJieb=zw~q3ZRmqBU%EW2JM;YCSFJDDP&T*~&)RXBLP$ znrp%0zDDo;8`-Ee^o>XVJ}s!P)LOP-8h)PiJ=iW)3&82!d?Ot;Dm)tVt0 zPRB`X^jKb~(czsoz)Uv*mtNLiSy3@}dBx7hEEK#}BrzN5z~G%S-P<=sRE7W+%N*fgFcID@YV?9PnsIk~e3m!dLxhYVa zjS}t+etTS`345w8oA>hcrW+_b_l*XeZc}l+;)MC*#^5)b#p*C1oWWVmVIw)tg%9_9 z)nG8LWaAQ3HYz#pb39vL4Q_mC+~B6iMxe01S`$=3%<0`JEk(Tk15!?zcd1aU$u}%F zg^kkkTJMMOQQ>yI)udC(Y?Q2XviQVWWmwWtyJQ}IpYm;LS>H(|nClmQ=cE|s*XydC z1z}3ClQp<{{x239Myj1Nzbk;I?4}~EGAv)Z+8thpC_?dr&PM}lScqy8(Ua7o01PaD zK4QHjGkHmiQ=A-3)7-aU5*@?q#niGZ_vJw4ZSKB)2^Nw#7s~#!M-J9qu=3C7W@7$3 z(sW)@9~k>)d{eePyEd4~KJ4<&1;7FZ;FkKEwNg{#x9IkX>Ww*bK!ETJ%x)TC&lR=r76P@pU98Xl3Y~r-bMJqF(oX=&OqN(E*gGh z+Ak}s1lQJnZK$#S57tu2B^&R$a8Vt9fZQfG6>xpM(pSTWi(t|1Evb3Rkouvvh8~6W zH-=^I*89qkSe(|cJBN#MY6idEw4%b0K}`0{Y%Y?RcuKl4gbL4euS*IQa1pgLa81Py zD(o*wv&=ZnMT|B@x$f;$XlU3ax9|+sFP|yO-PWYS81CgnW!o(0Q$aK;FFmD(i<+8C z99mkbaHu4$e`*yMWe*89mSR3#pA{&be-@9=cTj-6R~3qIf5OLc|6Z$>^*>gH*_(1! z1fIw3#^wTXEj3Vnn38cCx3k&QDr%n^46)Ta`VM0F%@Ij_rm7CxtGb(hY~UgtCbh~k zQ4J>J{yaC~=Z6-E)?$2#H(G6}o6kkbk4hZQzEK5}7V%T3XLHewqbC-HNvMHd^*Rrw zFs%PB$Z*}XO%-;uckV2-$Nfz=xwh%7D)g@kd=RI~MIsZPCAV3tLEFofjoE`(j&HqQ zuU4oA+2^!=SG@j@)&pxVn}=S)^mVxPzPy4uWTh(>U$~6-0khpVYrE7yYt7g7;)U2g zxNRQo-l7Jwn%7y|S8-7G$G|m@mZ^cI&4Q4MIUJ;8y!+;j*Z=M-n1$3a-;L;d?A}^i zw~TevOoq-dwE_zS9^x#wXxL!j*(Oi5C)YBwk6plXQU|rr57<$8;66earpV zRJboI-;n(g<7KvUiw_g?*#)iNx^K9MMlXM2T&fDbkHyWFc40fErNqI1sv0al+nr-K zi2Hl1DEE518eH4a@F{U}0J?Gf#G%Gtht^%AD^U+W=%edzRV8JastoBX_#IM*wQ=KIdnyqz-qE z%NW)K1R#mpECtUpb=WME!SPBAKuBwS^^51~(3UbGaQyrLl&!PAdXk$480zVTmdy)5 z)z9WM^|oukl6Z4dQ~W;lY#ZSB0k9Jy8vsuq(~YW!G#xp3354hM^XOHvEeE z79H>xckyB2cN%O0km`?fe%s$_g0rhs&Sd=nM8W$#8}I*u2G_S zF`X;Pwk>SH@Mzf8O1XsbV{}C`VMzTSJ{u*aQF$-hv@8F{`+&cF>l}0(pLCOpst5B7 zxFSaXpS&l>CFe!Xn_L&UZW1me+(@`;K78PIaa90f&_1r%az_i!c%H~AJ`jMC6EA#F z-m48rHiL8VL;xz0z7Y zoUR?4^}&JOsy3L5;eq&QJ?r)1_JqU6x>>mG%Jkke*#P8Ul+9#dx*WK?FK$w~J}~nd zKAlMlKZ)rz1JH}A zUgdkrhOqrdZd;@ap08oT&giLz@Hk>nP~Q%(_n3V8`R#_F5uKNwZXST9xXQK_9x?=m z!Wpy;^C9?tToE5&2-R03KU`A8d|*wtb#*iZor%s`d&MyySsWCYzT6Nf+YGJe{l@#* zLQlyvxc%~BO06yC`~2b;6AS7MVcX)DKSE#pM_XgG*43@fe*Vi4%AKW{AMap!E?Vkv z{7KvG3U6rCwTw5yFm1KuRh!< zm-*=0!9_0)%BPpA>BECbFT#ReaZ$nU4A+THdT_m5=Ga?2zK%d<$K(sTfbjcXZFoNK zn+vu*(t)B|yX2(se5nbmmbn+{KypQ;y7(s^ecSEzxTy_m#GH>5WBQ*oW7RSVXKlFV zeqtQz$K$IlE>^44f-k51cU}F;MRW6dmFuw{Px1?9Ax+G8?L5A#(A)HSPhj9*+8TpJ zQ;dxJ3_jWj-`V`(I}%PL97#Bncp&ja;*rENNe3jI{6j|soso1%(kV&DB%PCdK=KL6 zMhek0#*(wOuTM9OzibRL&X6Tx(GQw!K~gvKpO z5kpeC8pZW%oC30Wg1_!mHFAn0llgd~7#13mwg~4@kyNt>v&6c|=s$a&RIt;$EJf!F zagWkT38Ni9vv&(B;`e8!!f722L91AAew}|)H(8^gzk`N91e07wO-6D2!)DyOWH3xLTuD55Mn&f!iFgvP=1-oa}on zS73xFMj>HDu>ak#L@Toinsv)YB5o+~{&xFfs%m6!aktKQieM4+7M3cP6+;GS9s&}q zz|AGfNP_(E#9zopZ#gU56ohGSPNLbmgzj8kR_NMKIjVe5JI27(HmQpfe*IU)#!_WvBq?kgr)m#us=S6zN`1tG<;T2fj|8#qh!H(!L%QI^caq3J z^YLJtF>jtDL83ciRL|M4E;xxDj7&l-Kj43M40dv!Je0q_T5WWb$kqF3f9wF;4meH5 z(if{6hndlQ4U}q(_gX><-(Hh+aP8AcVrMu)rxbs523nCCAKCBT)l58-c#2M7sP4qy zg(qwM@6j&0fGnd$x$P?rsC$dtSJLhDl{0A+nzE|zfE*~2TJ2nIkw0Nh8g8weq6~SB zR24z`_wu}@yO`Xgdu7&!TLjR&IIes74L&D#DT&7*dPlx2cS5+HhS6P0Kl*2Tc_uAzGL65P!T) z3c#Egoke*_Ki(z>U`~qOq&(ysZ&Ly=CqKX?euypPNxu@v_*0(MQNCvs_a;4rC4Q(b z33 zX;bjuU%Vb^CYvONWirxC?6iFHHdmR<4BRa6$NE%mhWwFXT8RU_L9>Vw$Gv^tjth9(Db)$9iH@*wrFrBqMgpxp~u zvR7MtuOd-T`pu^~^=m;O5t}d}OI6@5oq2!Q7vUxEqIMB^Ei8j+Y{b9WmtnZ;UIgIu zs)2OIkQ;t+k{LCl^OW+UsO@)US;J0fwVyEMt!_$mW-kS9WI-GDRI>S@wNv)XLw7D= zu@mmllI8z>dcFi?k!*ar{jMCbf$^~a)aG>SB%xng((^nVQBN-@60UKrA~Al=HGC?N zLb=SU22~5i9NW*vumIvp-!Lpt%BKIj_JD&M~W&bZvuHz$5ij<3ZhP{!vHZrD&+YX~o91j~3A9Wtlkl zd2l|P^OeV{CI81yqC|^GX#ZNEbgoaGut!d`Kl8KH4h1O)FCL6G=8bS92z!?c?TPxQ zi$=6IOpgT~72SYRK*l5Knf9kqlQft)H_zK)IXI`mq01e67h=kioZSo@jSvTry7{Ll zJ@6|fQz#n}U6Mb}3L;LpuM!~R90w$Bz0ki2KyR?D`w_c4&@-w5x?bA?pc0Y|B~j%o zSnImVMtrHD0WtWBu2Qr?D$C7hAzp3z{t7Lh?dTGzPir&X7f>PgOR*gKD!~Qtz#V%* zAk-eoPti{R7CKIt9#VVcX1BS8D-DB4+)Cg(I7)!@ejQawiHX-zTGOZ-{{D;0$W!AA zChuOD>(;E*^E*o;XQ^tb*bUj!xse=dxXYQ}Gp!hu7zUrA;O7;}6=dNatWDb&4MT>* zkk=+|sx`J*FLxxo z`*$VMVNa*5gmjzuKJf2295Zdd5KO#VaN%uQ!;N2YyLC6~UHwluzShPy4tYHU zHyJ_;ne3m)`g&)5A2jvP?PpO_OmHL%U|-j1w!49=7#UtN4A^t8$s%`o-53ZCp)q*s zRX?qsNl^6#$!2M70I&j5!cG;JVFBbwhwT0p?8 zOPnhdn1d{fToy79N^b~B&U)r`&)9DQCDLB3jm)|Q;pQ^n_)cdqhcxZHuXQkm2dcxsF^uTrTizn!joJvu8*=<1+a> z9Z3J}<$7Cou)b}ZdNhNR@@sS1zXM3TEBG5q$AQ{K;~ToW{_YfxEx(qjgOpIpZ)&o{ z7Y}Utf6FELcU%CL5e&JdALd^uAJaB9CkBwy>`JWDZhc%#<=^j0`%*&as~4dsmyP{UueLloVCX=nSmJ7Ua9qZcZ#zBMa zk$~D$$J#cyyOzoaVl@3x9CrIG?iCkZcSF`c`@Ydx>M)<0ztDVgCT5A`hNVD_ zj^lSz&{qu4-#gb9eqC{QX>{j6bgGxuWg7Nx@@He*6tvbF-QMkdQD82Vx7I_ax~W&R z?LF+6zH58ugfvIYbazl~9-2VkdOhb#act)-i2?I;8*W?BJ`8$QJbzi>2s#c#2{yCv zhNJ7c?ou}c^LT^+GjY+-l!xEOdBgxS@zLUxw{bE9;deAzRehDAN>$f@gsod0l#3{M zdBem(cj45CskjQ-_By=Bq?ltX{mpq2VNU`KnOPpzi&uIz4>K=gJr9JII`rI@jTx?Y zNKIj*v3YR~9plgWn{g{Lj7?yNFREX<2vp0caU82kLX(%mjS@yY@78pe=S6S*=!t62 zdw-9`_fj-tKXQiS4S#2{(NQ%(>D%}+{w>*%DF_8c_GvmJ)p6q6<*YteFY}0KbQA|g zWA(gi^s$w#{|a6@e$Z~SKV3@a5~cxnRMzz0ebS(_KiH5%`Td!Rx-V1o>H67WeX>{ieJII`~L9tu-!iLuXuck8v0$#5NMh~QswGkDk(-qsm?Bqdq zu`QkFv978$DiJgt>Kd}zAE4n<>@WSm9}QHvOu}HjJ>uL}kR072kKEi(H|8xrnou=g zCaK>kRE*j4)s42ia3Odh*5FRvff9Z?@kPPgE;ttmx-8>f|FM4m&q~6hzjj2AQSC5O zXV)x>!w#35FV+qP%`n+6Jp0!#p)us|nCv;tiC&kNC@(;z5(0by_ox z3DYZM3}K3ypZZn#*T0^fLwV&_!;O$^O^V=J(cRr6GX@9UQW!2+{;E9g1AuLI?57QS z%75#kVleYc((*ivU}1FFxM!qIc&Vv1HXzGLiAl0{VU*4v15Q;Ing;^hjAdK~J4*tK zgx8Fkj0Ob#qT&^? zd5_s4lhOJmeBgyzyXD6|9OOZsaescsV>U5VAJZN!!^J7_@E6LkQA1NZc)8ji z=Z2W0psJpG&vX;`Qhxl{-IpoJrfk=x*Q`{B^P9zE`f0u5#(3`PIH6>rlT8_k^hF-RwpMQBD-@#4o|AaV*5>tiHZ z)YqtGv0{`<+iqB>@*%H672mW;Td6;Njv< z@(deq??w6kL-GCK(~S(}tL*%$o;z1?HK~50fsK4T^}P~n4w}{q>0L-LG}LajI8;hDytjhb$eO;~edX~qho*x1`%Flt$Hb}gB#ZuRG5HBNHjdxk~E)S&#yZ|ZxV zB+uM&fjQG$OF$e)hDGL-xWY*V^}TkIXYIJanrW^LAdV};0+J`NC6Q|fhy&wZg392O zvToPDvQ0VBZSqa+XPEYdNGf25$F2CQ9p~^$Gv)AFGo+JSH_x0$8Y61cJ{(tdHPc1D zkzbKmTfxkb5$8s2$}4X)JMK7jbbJn~j$j&}-5W+>hwJ4TnWPyaT}x*faK${6kF zwc0EVu}68VZ!TxzUwUm!;}UCy^*>Dw=Fc$9nd((Mv7otcO?ufLe*>BN{gW3rP_mn~ zSGKcVdI|2X@8=Rl3J?nJ-!W21tDky|ryGX>T;B#~QSrs{)0(Q&8<-~Ge`X}582wk< z8g}SDvX(zf7hwmj088qTC>i5n9HOZ6PCwCR^##R}$Il9WM=m#N!e8I)3vbkHRT-U5 zVKzj;49EI$Kc=L~#*ixX!hG9TPVu6@$d>i@4x+O}gp3O!^9l^_dY0#w6ML~Sg`as? z3bSd70nwIVKN6?H`3%uc1+xCO6t=o-W+B_!WD00~^k(?3wW%tPR|;;aN%8ekokJ9> z9TV6Y(&6to&z#^^TdIrd;^v1Sz#6bg#gt>1g7j-#D(wzWM!QGYiatwd^2;0b@ODIo z`5y#(cpmDu^snirU|2|2{!|!>8TYHa=+%a<Ik?9#XqQ`Uo*ttfR`+{QxsE-?()ltEj6tMhxr;H#wIJ{bGFK4Sya*1;?+M zmSv0i7?stVTO5M2#b3{fM9hTb;VQQ6 zil|dkj0=v|S%9nS{))yRpT8qiSY=*KMpc*{N4NKOWeFlYf0RAe@L5s(i~w|HAT#CW zf2bUjcoguRaSTuVXJWrc9Ld&$MrdhtDIG<$abDd<^=%i53ywG&r&Nz!_PIhoFHLa$ zJ^V0kd@Ql&`J8nu%Y#20hv^LkwU1K#Ks)Rv9CMp`4jVsF|KOg1@e8BBFT46aRzGS( zwLcH5*$`fT_RQW6Ot%Tzw6EtF1&87&S8aTIB>PFBb>@&rM$c2xdh5|cjA_vJGH=-k zRe0@UN4H)GXMJ@v0;-#n!rBFL*aBC>Qt_Bnl8%tjOk&GSXB2%cy?pL|@ekOVQEa32 zJ!mviH3|)&jYIV3yH2AwONdtDTw|0s2$FsA&ct&uO?p3UDV8=EkDD5FNEUT-E}7(6 z_+Vz3u3dad&#=_~4zInxvTe1_=9pny7DD~gfC%L#rv^_x=Fp^m{0;r=HdH!D8RD10 zq1=vlkz63c)tpb6Xi|YZtHM2g70=H#G$ljNkD;Va;nV9e|2Ab-$Zy5aJQs7rkjV>n z*rfNWX|JRHV}e(^s~;WELZfK%o$Iwh?PR)zmh;b(Rvk%gjG7euPFb<-3O-cjgSQ@2 zT`cWC2c4P!9#HB+E!J|p(7o(vF;9(^L~Jcs(*n=*Z`r*>JKjlAh%VuoFQ6P!yTw3& zf}9Am=zP+X{RcOxSe6Dm1KNv30H~cLP|2(<<-2Tw9FmtC#wg5-7t_zoK1J=LcPOI& zok_2=vmc%IO>ETb(SM#{D(j^b#0Dp;cy(NhgbkGV*OR z;q;eGzJgAs9CYfG!Tb z?jFiF!RC9_{IJfd_;tQ^?aCL7*Ge*@S6fOR0ZaeD^;C8awIdR2p&?V4{8vU2)y$

rEejp~Tvc~#!;<_p3&HtA0h|(Ajfw)eImG{V{PM3yf`_Q!b%vlZ26Q%N5Y=$;32%0 zKwXiv(AiEG6t=D|ue-ZjiVc5jza_{lKV675IDVYYjL)`pa7zoKcUs_~vTZZO*el;X z6w}v8?%kW2qvB?g9s#A1(aYN5y|wI@Vjmr0*(vOnMmjBkkl=Bw#9QigAPt?BmbWcP zT5#e-mh?KN`{%`>2rtP;R!`?5Cjo3=v3h)C=A9nNPI;zXSGer&g$4JhGn&rjwwTF}SZHFYa>bD;)i?YF=fPL&4uMejQkTaSw!^vAb9 z)QQm#$;l|gcR$j)Z>p2A5!xA#i<5#kM-f{8)odDd)<1s0+3xt*`E9)^B98l}FJgvo z7IzJhPoaar^0{05M3pTA1_MWRmw1Qz7y2o9AN6h&PD+rtEdp=uwjPp4q%86C#v{Q+ z-QTCGWGz1GI_dX|7Vs?vkZVC%dxbe^`IsZ0POF)}bAFC^GEEidQ9gitpTq9^3QZ*) z;)%WnYY0Q$tWx)-gm~*R+~CFW6sfo6=CDZuhkDy0y(sH05|>a1iQHp8nRgbvvywbp zSUOrWme7SI?VSWLBE05AWC4eommybnqDXC`41biwqT@873BuiKmjaEp5;Y!<88)zm zv^w~^$T9xT|CHnYhc2+zhAe+eF%p}YB@X<4&e?%dt9 z{H?uHZ&>^0ql+ZllY5^eR0$=`QQF>ONj|1OrTSl)m59FM&yvyO+rBogXQq!7e39FU zzHcN(`8Eri>F2eu$??!iyvSnlzW)%>kN|pRWn^-o7s)_82g&*%%EhZjE%MF5N|BV9(x_5*dg9nTw@9i+A z-0y@Mgx?uS8>^l&=Pf8Kbt+AXSj?e9M!}`i13nX&x~%r)BX9P*yz{rcwnc1$+Zs^` zajcwgXxJU%tHU(NOecFKMyI1_gbdKJ6G0NKWaq`y4!rJf^GXuk9+LqIjv6^=n+^(j~99^TH3V zKImV8He~XRU1hzl`1SL7j^Lk4<%7jm88RCXIzDfp#%U-?5`02aqb#x&j-b89OTYN_ zUBv7qm1oS$*(>Ta%U?Ay-}q)l1=oS+{^=+ryO}&tZsy-x3h#Ox6r-mry zL)GgxAtKK{k+A`H^?Mq)+&P$?-sMsB!13VvtWYz4d^cY8{P&j-9F62!=H_pSBy<#7 z_di~|qJc^GV(W_#DpHz=l@8g>8y34y;U4N^Xfk2x7qJNvRiT8tsAT)kF<~*GL>KV| zEE#u7{X`eJ1x^_-rD42}_#M``JEdWwkK7&SIJj7k^ca>-OS)Zrf=bmcX8&WvDq(2x zH64^Y?dMrK`UQPv?W(!63i*M3bTvho^~;7}vY-maJrPw8rGy&Ekq-@);Oy$Rq?%RY z@ax5(PH$sBd9%ZJI!18c_7}!DyJI|M+;cQfCG{PoL$WLL-2SXETxLV0OFqrhKZ@ec z{SEDvXuKLxO5}K;BmxsZn_Y33Wb)RtuUPlqCvAq9>{zE~7#@z->0HX(d2ZV+YVhPW zc;|7c#$60KjMrzHUp&0oB@OU4p`=bgzB&9@ju!4 zYS`D)7D7B zV_zhHyhT$>VkvKxB{7)MK)cFaGc1nEDoZ2Q;tMgtCwKq*gm3rAj!RP0$(8-8ug-Sn zH@MW>mGV;IVXd%(S^l@P8zw?VY~N;MN#ouupL{WNWQ_xFgTT+@M}-V@$Zx_#HYIFY z_NZ6$7um1VYXB`Z*!xXxuGe@PSl%srlGLcNPeTZ&xrX1wm|yor*k1@K)@j@!wJqbT z%f}TN5;U^9zWM#SG`ZaEE>rkxU!^B--bL|qqD_b2LL6X z7cVJH=X0H|CO+cvP^NzB$q@2NC|=v)58ay&M94qO^Y|gKjFMN&6uH1SpUilgMkC+e z1l8cx{67U=Het8pimw_c0aJ2t6tq+OMJWcQU#G5>9y|gcFVA1Rlj`Wji?zigr?4sF zwE@>@+At$=ss0{2)Z+gF&-yGlUx1W?smF>=JYVt2Itr8+6q)`ZQH7e0Iw8K^c|9gl zAb3Jxv#XYV=;x?WT#z$6cWsgfrA*XPF)t(or7$Y|woG9239frov`Yvu*xDftS^dn= zQFYKF{H0RlF{4jmpjR$`?5Ogqgga6zZ_rD6u`<~if&5EsT1^W#-eAdujORMyHzOqO zjB|WDb!0!wN(BuGq7i?`w035}n<5;8-NEyV&cx8OCRdHL-jqXMtGdTk4DfTlyDREd zE_N!aQVzklr5CdH**?XS8fIl^tL%xETXB6o6{-^a`xKQP*-D_@ z8x~>A4;>e~cWNffy6!nQkyH}Oi79M(unOG7;b41#-5XkaWr>=g646tXZz|Fn-PeT8 zRovL#D%dNb9=Nwnny=|#nwhJiSJSG;RpU;Xc+cVrM!O37xdRvV33OJ&w*txJ{Gx{Q zvLj(1i95XUFv`4-!O?GdpA>Na@rq7-SDksI2$SZOoM021d8dGb=ardIQJqP2N>5%a z{&+$CRHb!$*6L4!9(1)Qkz``3iBcz6P#5Gsu2X=akBV|0i90dN5O8A_SrabymDo`F zT+<4Em)x)@et(Md1#cMcw)duexYxp&>{jf0C}~yfs%TY2A8(2x19NT?i8DUB=2|77 zLVJaLm-#MWy2oiZJ8%A?E1MIIzxW&?3ue6wJ_G&el_iR<&ujb?L3f=u1#bAIvrpGO z?h#Bbl_{K(Cm6YLsS(rJ)!46n$-~3;g&e<-G@H_YTjg0;4g8%r437+d>;3x*Csah2 zC3UH1inEus!cANdS$wL&r0Ty4Xyxr<9#X&fY;+#?8+RP{d}p_J(jV&h3`B%#_1}{n z5L5u&YK}hfW!3-=ZGw?Z&7HU15dCURatV5^5hd{fW=Y6NK$O*(8cwx39j@nFp5(X5 zRwhda0FMUCcN4Q{aa}(J#fTk7Xp_H2J4C$)O=%QSts{t zCq>VAH$HeXWt<((DxA3_2&)7VF<%b91((-8CC&U-bi{CenSrd$a#UsFr%Mr?PuEr3 zNU(V}A@>ckXHC@X{O9jqv{2x2buipw=Xu9YDvx@1-_4eD_36-&g{w*1Gh7{oE}7wz z^qWFU|N6hufneAbFB>bRB2j2mN}6IChPeLxW~)zc%?IlLeP5N_H=uhbC;7eRuC_lccRZj&@e`ex zB@p3X>!3ho69s`b zAKt2S$;=ZGIn{4CX~`HNA2+y%(B=jv%<F()M80qM+MP+_F4GgKt>K289SX%aTrP2*XEx!@j-;!-M;XU3R*x=ir+&eVf6eA z;yc-NmhD}E+@PBagivp>ZIiM7%l|1i2@-Nag%4*Nn(yyfCw85bPIo)sE+ zuq`9MErnFx<*cDuw8Fb(hHfr@W@erje~UIlkkZ^%5ifsAKc$AL2FPUa=Cn;Dkp`!t0zB+T z3J1r$WlEFF*&p`HGLDKZZD--fg&64lloR7Pei}g@@g&bqVfUb`ost4`qxj> z-%25odE)2vnU0GXG9?Tj$p+J+cmnrS(cpEt*vB|iMr+vxg|s)@{AU_|HPhu^zp~!} z0DePaL2nHr?Cv^YPCerQr;`ZE$Oy}Tu?&`6cNe6D*sX&D{zlG#9{BOzo%RktxXDshNnS~rOcKQkZ4#(q;ZTk4o%|c#KsF67{eD&rV;Wn?n#=NS%-QM4&lPK+2i`#~8AjEWYB!3XE!Ted&Xo;)P+(K+ZkX?4tq%fFT%{g%io*RgzprC z8F451hFj`}A>w=t`dm^dBft8+(lLGY#i34Cq-kD;eisnRgpJ_ItPz)#?y5bki0$#u zPhfAR!B6VHaGLz}iST+4?lm|jdAX1CAwR;Q+m(KinvhcUOT0@NLj93}@v*(P?H-V}e%|CDAD{xu`gs>X?_$6Y4)^q%R0C9Y6h7aU0_*{Wf=$oMfi;*HCMRmK-si^<(l8jt4E&-D%p{@rw z^ZL)lZTIq6`7_}HcWA~0_-;~9WYY1vmNBYbJ@J_fPICK#ha)x;6Yof6x&@DyCN@$N z@5p4jg@}hEJ~AEe$Z5JYE$ql^x`pCtAf6432MQi}qInuf@vkM~g_>PwD=Sc)rw1(df@Mas)D|5NLu4W8aHX@fE0o+UOzbBAb* zBDMjPBU4la7q%boq_O^EE|+*Z|FTVq6utnG>V^RInkZA)at%UZ5s%Uc`A(IlwhU8XtkDKPTjSR;u{ zSDiuiDVDQomGE~*k27E^eYsK6u9Q=H3pg=6lM?!iCNrfv4r_-bv5q z>S3lEKYy1Tre9T)PO;39KQZMxoe9Rrd(hJ2fC*~8r9x0GF(8nNskWI4yKhS6N??@^ zYO0$b%=~7FGQPGm^^_RAl8b6+?v)WVRNo0ptX2G_nJ2kG(mcLP<^U>)9+|K8Ab3(Z zL#z%mWxXC(EK++c17`-!qO>w)9pX-zZ{5{4HRq!ikRtk9SaK+z?vE4cUM)NlJLeYe znem*RCMB=T^f%?_hlxE12H8)RdRh}AWP{T+VDu*M2T3pB%>84OMd7(drkCpsO#OaP zyqo<{mE`BXz@qeeCCZy-Tqy!wp4qE)lZO7Vg2*#-QwTL|Chc6BkMMxNuDK&!BHEd9 zG7)TG1NYWt=<~thSNkmSt0o*^`a>1vKVNPr9yUEtPSMwuL)DEL$*ix<-|tmWuv|>} zt7>*L#1^LpL;f&Vl9DAZJRQ{1N#nll!0u`kxZmC~!}GGE{cNQRs3{4(`pZcmNSz_> z*5A{Hb+|<8aeT{c9SL(}vxVvKT7{2<^!vwac4NThD`UtPPDTsg9Nbs8R1vyOoK{F9 z_37K&&G1S4v7y0VO{V)$QF)~lLw!>c;aOc_zGj>Z5#(F+WfkX@e8#jDcU%LE# zbSb5Ft&sU9y;6d3l*!hT%u|X@p|MIyiaUMONk8S2PF=AGEUggCCRLLQT+>=7fV%0u zr(k=oUac=!XOsM>IvZbyX1g?P1+daDo?6Hb)u9LUpV zfkzfo2elrb^he_`0u_dD989Ov<9OFgi9bx51b=i2wEw!3VvcvotHDq7<{rT$PlCiU zq$5HfDjHR068bS4Ch%-cqy8Q^0I2Q$5^8%N_7UGy@*0mfiyY^iqUm&dwT*ohDPyf% zx&vi>8HPNEHOhhJ8-EuV`7`CIjh3mSNN&NSg`}ZJ~U`neE62X4m zSu~vzcI}@;Nh-rA+rEe9cmawf{;bQt0EI;Lf=0(?U%KHI6&EE-&^V(6#{i3PImPHK z$dQ65;zJvJ;u!`akjciMEI?BAjg z8A=HjLw8$w!K@}Z_%90w;|R@tL}jt*&6_Kc_@DMu4iWk_+!+|ttc|+Ve$p7mzxXcR4WD%KUw-KaOH8ErtMd0+j=_V-FNNVG@oY@2UsA4FSiE6F zFUqSHph<+d0%Fr>u25ios^oe!TcbdvJ0?SXb(Ptt<#K-8D&FtkKt5TWB2ABIIpk?> zc01H>Z_amF?>dHOAuRfhku>;UB-?vmC|mP(Ozo&NQi|Xh*5>c|MtzIaP)g`e?u`WZ z3NJ>{K!z@N0x<&i6tjn8_k60?iB1{Go5gxGXC#fm1Sb^m#3Yi$Iqy!oJ?Dm7(f#I^ zjB%q<^#0G`0;?3W?_p1&lI^ zBl?`bTEeq;il@Uy9Fkrt^1;iGv#uF_w)8$FZSVaBI-hDayw5)O+?QbZjaihT7ol-LFLibG_M@Dr%&l;m^13#ZKR8I;i)kFWkz??{miVue&@UhM@?=bU1`Y zPk~%C8Hegiq##Uo@i3Ixv&;|~4vl2D)l1O@b3Ri-4Cm!pRmpA}s(mJ>FIO$4U;Ag( zzh7Mv$TiXihzaBT9uKi9cO&eb=;{8lu3=nzwz%{eOZ1{Bt?pJxJrT~Hh{yn?y={aE zW>vyKc1#IIwSmq5@N&B>DdCcR9{63)3@h#WaHr;15R^zftqN&C3b@U8k(txfPfn)W zq{TqGc?f}w=gGW=cZSyzbQ1Id`#!`y^Bz?o1xpVsp|QVaZtpfzES_h5P40vMo`xA+ zv+_Ic)FAOBaLG7i>B!gmZimK`B({r1YNw0>w3z_DrToSMdg~rWe{Rk8lkyZ7H)+aG z_u2G`;y~8m@L@~eGJz7tb4NGzT7PdBbWGn1Z2yqS45p<_DO8bBrIbmgB$p*3 zOCgt-Cl#kJq{JGqzb^;g6Yl1%Rtcv%&j@+f?RW23?>eurm4}~*z8Tm~wk!2CXy5P- zjY>6NF-OWWS?3j20@FsE z!?5SFv8_oXuh<`t$IHNq(VX3l&$ivFX+@bztse`kVs7(Vlo3TF8bY7{w zJ(6C1tmibU|FltZit?(77McT_6Uy??M%CNbVOc1xge8w!xEuVJJlLYkIq{U@$f07-x~hHYyq(CQKyND zadQ~5VOkE;8U8205+47hpO)F9^Lz?@qRX|HNfU(S?PB-Qu1mt0q?o;t%n&lY?2o*m zS%LZ;HjMwFiSlo9K?n5G2$vBiXi-C{*yW8bJ{7aPIgmD} z-;G%?3>M)R903LgWjtXjBP;KZzylDI;HX*&8+KS@tFG0!}ERs$poo)G$ zXB_9*Wsr=K{y@K6lG*PshbqHjr0cgLH45rw&CyX#7is zd4Hh>Lxd!K3?9BJ1!$!G!C6YYOUvhnc1<;W^=qf(!t@EF);cLq<5Z5eZtF3hL)c+S z{bH|31v&_wQD^YO;!447XgimX!A41Rce~k-wXST~f$0boA|DCHq%%?~WaLN>~&encpK>)P7A!$Vss(VG#g;*<{kH`TdJamuBtwBUGA1 z!3qh1zA1&ETVl>?KJ1ri6@Y-1M~48NJ`qEWf0YKYNazbsN?w}oa=jm0RUt7qV9RB0 zfo-cOFr-#s--R^}Nh1lB7$Jd^ErtrAo(N}buCFC4ZmTHbR)Xv5rdK+2LHM>jB!wtz zx49T=c$@BlN1D@xFUKDM!fc254&U0*KK3I9){lJm zMWyCaJxJaM;qwR4=L5L!@v{#M*AGVR2jldEN&3Mw{a}`UFn2##xF0Ol4_4~GClVm} ze;z|zr-$CiAs6xLZCl(d;&WHvEW@Y2rv=pRf1kgnU&`vVs#sKXFS^K{>yKc{)6bY* zcNkDmC`ubU);_N;Lco(@o=oQ*K|feK1rJ;@6NyJ28*3)>?3#F1A}+BXO>mF`opp!K zl#f;s!F+wb<`+6^?CQFkpE&S8-$KkozT_7 z{=7|n?8%d4HIOWH19Nfm@S{1e4;y}ygJ(WxGf@fC++>JhKlPA3Og_N#bPeddDzFzu zG%1?eNMI3PDhMlZS9}U4{h>@_mBz9dU=`&eoN@JM?a0eZ?7<6p58uS5%T4MFMoFrZ zGmfQ*eBkZQN7mQ$8P~w2RA2n~JRB|uC58W@>JGx;yK3P@!Z%*@6#u)(X|U7YErxex z(9%z?L+{UhWFzp)TKHDmaDzpI@Lh_-{G!Ok>W^6{Ft`*unt^5|s#Wfnopr}7$GD}avB`6!0z&wq^>h=w?cCQVPWQJ$pbAPXsK8Tb z`Ons`kB*W_Gz8y>tG%e!ASDl8D&|F~SNnWZ=_C z_=@m6RI~1||7L6?3uAl(=WA{%Vew02uDx@Uh5U3!shMF#EIWWLj*}n&sFkFoFytjEJH8H48b#IEiBnql)qKeR9x%{B6a1F|62d<&_mX^6O|h;A-#Nh*#E_i**4B}9KsBtnv}ooQXA7BOkeRA>oz)Tr0B;O!UcDowK+D- zm~HUAYdrf6A^uj}jwRbzv7w`s5zR&V- zC5;oC9K0oUSI7{s{zoBnPc95@coN@Y1`y9TsbKVg8*9~Fxt7D_zjLcw7Q=hf1RZ}P z`s=+L2evSG(O0?8IT?_WfB?>3%ZI*@--CaYx+kLX>Ck z9Wum;r8bR1qDgqu zrDtfp9EQ$i9sqcIAQM?HaF&I8FWf6e?%iW6YYIG)Li zac&15cWHL>ks)-1(z2JG0_+DTuIG*YtC#sg0c9o#7Ta>YQgEd5Bq8aEPzWQOF6_GM1*Z?d$rdbdcO~xZ}ho6)gIlJ9h#) z{)#9ivwaH@8=bxXUh*{^+&daErXeI}1t&dfqQh-BbiMJ>CG($E zvF_b2(QZj};I(@k7A&le4V~DLr)5G1m26n0foj6Khm~#Ov!+1L+_*_MKnvqNxvo>7 z#T3|C&umq0)yBHS0!PVdrXU&?aeCz^9Zd4HElF0=6v{=NZd_2(#Zo-Nn?f#|Eb4Zx zjDA{8hzU%Z@T@CvMaRFK&Ro0H1bFWHsj~dg!BR4e;)tTYDk4|7VdTePqR+cDoPJYKU>3!A*)Yq9OBF`Sku){}77#J2p3 zQxBLj1|L1^efQ-wF&mI1Hz4`QUX`Eu-5OY-#rHR3DkkuJecO@b)f!k_PQOp29-426 z@P{4Y>KLKZjDQK50GGF^nemJo78-HgARf&(fI8p)#8D0V{E6Mox33t0Ytdobg18GkJv*YUWI&kOjxfzKFFI`F-%@V&3_y|M7Uv+%vO@V&S2y}9tcyYRie z@V&qAy}|Ik!|=Vu@V&?Iy~+L`y}axfe%p-yp?;N{PZ&fqH~g%(MqEXA*p2c{8s=oj zi#jSP|MT1CWR(B%z8UewbE|Lc{=8jK9IhWLVvn2j!1oZAaHF!cgEfGrhbLVBy~SQmNhBILW~EYWp>1x+u6Cc0cNKAVYB| zfpQ5G1)a-PIiV=e44v$%NDdc;yl+!3QQ8y$<{zagJ)%(K-LPMB2L&RAm|qAjl~|nn z%@=KvNt+~Le%Xeah$3`+(*$w1rzCJPDH)&lq(IjJ(uKP#r9sp*a#{O93R-(YmX^9S z=s)<%t-gf<7<+2Fy1Eo7ZX&+gsX+m;cmm~?iWFRL^XxPJN`}3?PDj{ZNch0?KCXfLi9q_n$&E7tbA?<+W~1feleQzZob?p^C6NV8C8O(&t3QB^l$B|sp zj3Eq-6t69tlmORT1*+T!3;}OnWO9dvXUrD*2`%&yTj+-%8PUlrlS%oXXUy=uhf=y$ zs2y|^!(Oml;Tz4{ zlhuz*UBd~m*Jq?u=EHPT$fqfnGBM=GVGrEoetv4I`jWXa&;iN9tnynlXPV}uq?hN1 zA^9SIFR9^s6Z^Sn>1$t*EbaP=yL!IKb*16cLsT-vTS{I1?y&@mDJf#gI7|k@;G>yv z=g&=|y9eds`;g2yHW_M*HGLGWsc!m&WIO8Jn<7I-S%%tzS<;k0?|ANsnKhdEHr114 zh5YhL!!22hWpMwA`Y-1I3Jm46taGNWfkYGs*TN_u%43+(X}T7s9fn_D@t`36xozX; zk`={q0t|uVA zXCS_(Ain1yzE>DNo>7Q968^pmvQUdfyFXl#sb&Dh)O>-ZN2wrujL;EN4gd2l2tL2# z>zKH;`f1G}6bM;n=)6)E@qt;skWGRA9cy9is*;|GV?4-@wkY!!$5Vk&ZP9MM1l2m0 zoHHiz6vXSZ++`Asp!M;r>GNL{=aRtH+cOZl{pdqz9Z1RfBKwKyBSE#%S~(V(Sj90-{0I*vxHCW z32)U_lK$r%frWGDniJmk8tOpS&iJm+LuPP>^v#QIp#uyp{j{oKGkDnA;IL+?4m2#M zwhWk=L$~niv!O~l!1XnE_mxZL;F)Q2sX~^9 zPqCGh4jo|G$~mK2X91IM*&c0*(1p002hMOU`|sRh663ozidll9_|~Y&E4qtwkAF`# zsvp;Z%d_s>5uYr;zxY;q{d*nI>5uaK@YVukBirw?80$c^5PwMi4-3$#tDtNW(*aJt zUFzp{NVk$0t-0V zBqHQgs|BG*9*nnG)MessAvRuuIh6CQK5IeHhBsFGIk+E~L5kRg7pItY0IyG^V&?_^ z++lxnyN(aCOSa9WO&L1y<584nd8ZlFPm+zCgh>CxpX1kFExxz`)u?NZ-`BdS0}I#g z(D#ywkJSa1+duc#?lptrJuI5-OGxmBo!WA)^uJ>XcIZq5-7|v~+7j2-cIqzPtFDiz ztfj3B!Dya?7tKIa|C?7~u@1q^ebWPM;f zSd~N3L^W(Si>Amb!~a>wknw(w8}p{%5w*wc!B+#&xp}NEYCRoPnO|&uoMHe^!|DFcU zGUG*QC{NQ=s)L#oje%lau`LwwPXfcl|GK~N;#@52btaC@8N<5~8dpa#1w2Xb9%o9S zI+E+;2~~t+OZsisj`*3t%DWjuU59_?-T1DjwI)!0hNLU{gABf@!AWA z5#Q{rY}>rX6!JxFMkWrD5zZZ}BRn<%Ccd@bntjN~pP59Q(e)vPgpQ%_0DRw0XZ~7Y z3cN~;7_9`vKeg5npPn;?(bhcr3Y11^ld82fQPj;Ui_3ZtBPdHWBon@OX#4O!=l-}#c)yggiF#cX;d|~SW_5KMsO}bwfBM?!-~2!zxFNqd^xH2q z{54U{V-A@19@Tq20CD6bi%3hk|nT*DrLVP(uV5CKlkqEwt^V;0NFkBp(-(5=L6$aP!QNH;N33AJy!-fypIShzU)Nc9%?i4tlJ~Kl)mmJCgRaKCf)p(f z?UWf*LGozst@PbCS}^zQSl!V&H2%R<(eW#qz&@ZeAysMx;qIR$)`V*U9Ls*G8)gON zir>6cg)|{1Qqz8$p%n_7h9!?__%v(x490oT1{=Z!Cd9*<)tOtq#Fg*LA+^wFJ(sHF3S4)WGval;?br zC5+a(9k?*12K}!4IhI*lg5}2+dFC87C>G`q$s}7sL`cjkt95E1iez(1lykO^j~NfC zf+ez7MYjbw&iCj!zfuLL==Vu4v4DJ;hf7|ZR0W-Goe7mw7Er3VJbWuj6^JX!GK~UJ z&SSdpg7KLM(V~t$Cxnsg*Vnsmxhlx=@`tdtnM3@Tzpq>^5xT#t)()rt*T0I*tcrvK zP);FVyOQFj3JdYo4%=tG~exDzGY3s7dw*j#9 z+B2@=R+Yu`HG0*K`EDm-y`t;9;wJw)-lMqFCz^)?z>>!x>WeH9!(Sh&5UkySJ)b?~)j>tL@GXP6E5RMEIrw@C-%#IGa#^J;h{p{af3d|K zx?X7b9~YMaV*j%IZ<+2eH1P0f)VLII#z62rOLvGluUF)7R|>*94&Mk|>%O@5f^|IM zk6*Zf?aVdnL8=tY3tIPg-f@G>7Y~nCT1x|d{YWLA1OgN9Z#|Ch`*>lct1E!Y3hi&V z*1^zV+5MV8cX*svpgI?#@kfvFSC4o-;Pr&pBVNz=dCZ-98t`qC8;HvHM;teog90XI zZ+%TSARdXMag*gh16F9BFm!{_&edew$MP_RdDv1|-5};9U#v}+JZy9SGN!h~4ZeOZ zH&7{(1wUiclCnWp=q(BO>U>cOf+8Wfr_B|rA8Poo`yc^P+K=z*-FF3@_$wFp>=cJ6 zKI{JRSyzy~H1;MmL>vZR4Al>FBR!JenhGBg1(Ry?rT`%~z*@zIUtSdgw}S`Y3Xt8P z`hnU^*k%FXXqihM+TaFU-xL}GXZT?kd4=Y(RJ0!Nj?C#-yznmKl&Vm)8%#KNWYP@R zLm}7pxNC88tpaU{rBF#i+>@FtX1?>q!x~dhR^C zVKG|&+7Ekg+!6)*=hUS)4!eTr+^*I%Hr5k-wlqLA$RW$bX4D-f7V zn9HWbKx6c(&*oFEFz0sTedT}z^r&lPM>M-ao$!t`9q*;!MfWn^ykRu{o=xh!r~-Ry zv3FH=hbx#S-k)bHl!Nq!#-rJtt`MoUZg4179-5*Dj+0x^{c_nus?I1t;~~EThmIln z7<3l*h9SM^SMYFzF!>K+I7tpXb*T_Cn*u( zwASOhM^Cr{{d#9W+*2Yr|6&^azReZ7wvLYlWUIo0Z+m*PXtGDC0b}IqidC2v21&8=&>tDrwxatW}4R%sUR7ZlG95mUg*?sY3xvaqgX0t`G;t{kK&#Ai!6} zC6vu=F*YojmqprZJgB`sCorwaQg9M>7|cY`?&%XJ?GP+@s3u`;Xx z9d~NK+x}4%x|SQl@vm@)CW=Ry!@2 zpq<+^dcbYbHjLHVb!@BMU|Lh--jhmAu(sX1inG%V<~N<(WN=#pw(MQc*(2Z%l?S9< z^qVzc2+5~4+@X9@Zu;9Rb=c~6sJLOdI}p3cM(<9jL!SQQyNs_02hS(GeMMD=?#zR4 zSD3g%?#8~}#&c@ml>YI8QLH=6F$_x#;#5K2%CzM0DR(HOXSvrD5TWPORUhVVcfh=5 zCKMj3Ec#N!in9j$HYop-PmxP`FZ5oD4mzb8yvAh_qZV|P6($%@aMu5y-b;8r=P@ePlEcznd;Cmvt%_>0G9JbvTx{g97}3#G^vbgy05-ryz$ zu}vPfAFEw~uRP%E&xnyB#y>)*f$}g>(-kO#h%EQZ{T~Q~K zU4eKp-RYev;zhrhyjvn&K}3AIzPeHg-Wr|Tq!r`}{WsViHS!@Yewypiesfn~Kks(n z<_99EO=j%#7Df8@G%WGiOa%43!tJMeTp(E5CF%BN6-Z1x__pDa3!Dh>_4Gcb0+!#I zyw|3=fa@iq@|9&om@+agkt}h62)QtwuO_Ns!enr-E!PF|H}v(EYpFr5S4a8@KNpC3 zI=J;8DxS&M1sc5C@4kDk4vB4{zIp3iU|QqhlBNm` zSn##sJl_S`$GY9S~S! z-QS(;0(4C;nf7Pe(0bOq$@`QGsO~zsslQSOSi!X9SQ*lf(wOB@IbC2sbDsTUn+tHw z##TBJNRYAdlc9JdcdZpm3_+%@d+lr*B@T$!J}0?;S-Loa6;R1-7G~PN|rre;=R*# zG1hv|n;SJ}x&q@-!dtT@J=n4NlyoIN509T3vWFt#JJk@)yoId)tO#Z6LNBzClLk|4>NY zr_QAV_N7|{l2AOAn=B7cmDGk8!~AlbD4rFfSTv`nv_SEi*z1r7u5df1uh&di3-TT6 z<39aFeD8fNpK7BfhzEA0m-D-U=et@yu1rmEQkj=1K>W;B{YY;9GtGZ+7mv$$JV6lS zv+&Ka1d_>a#I`22y-FZld}&rkULl_hBHX>=ahiET;#mfw3mCkkiHhTLFn zcV~dyWi7C@e$$&M><*!QY>zHIL~*xy<85vy_eI^er`qj!kMuWM-hF)SH!W~n^L)wX zDs(>MvxL(qXBb~tg)M8+~LiPzi%?iBYiWUEWJbAfe|-8_Ijl{c$O5- z+8%QUOVX>=E0?Ijz*Tc2`5vUt<;nZfYKRaT3&BR*9*}0c;pavkB6R%7*e9;z0TBdE z|8wcei@qc~so^jBTpqmd&#^wR^nh~e&qHBOGSJzC_{(|^pbtJgN@0P$jbN5AG6=?CWeWQl_<$Jr&##nJsbE}UV zqM_?i9YuR8@lXBvdv6-~eZgzRq<>+VrCzt2CM=V0>t{IKvBoSl{oh%S|r?U67BB9g}p z8Nj>Qt#S7p4K827*gP~DU^%z@$7BZ$?gy}sWoa?sW6NkfA(94Z$G0w9Dvj<>92dIc zNQ3F|ELA5_2H0^Z-4QpWLBgwR=`1&*pwe2hwRL9h&&-MC%&Nz+B;TRR>3{%X+r+h%4*YN4S zWGW>0?HM92XF!73+HYRgRG3T)h&jy40A)wI(nb|@eqSTs_$MF8-NDBCU78B>98T*l z-u3~O6D{7YqEyhg*Wzxj@PX&0gbt<=3Y^}!HYnEv)@x7t;5_%yD&F(uOF|y(*LWgx!DbJ;&~p=Vjvqml+NF zuYI6^{ylS}HbWnHYEv;2^_2pp7yLMKm3+YZNgjQ01r_RE%q8<1`GA_N%?1q;HIvMIqoz`1>2}#b3Lk z_U-q9xd=Aa52|FiqF3oQul!$I|KHze@pi)75pQR_AK?82??-q)YkpX+--Y~s=Sz-L zu2(4_zwQH}0nP1EREP~DfU-DOF6Q>{V_jtEa?Z^d7iU1>>{L(20WzpPERUO7%7D5( zu|uyfEQ zzDv?gFfaq>j~V-PF1x^Mryt67OU$6~kjn_~v@aPF!R|r1&RAZu_ z4$XzS%1<&}Aq-v5tz`x>aPEC?v@5hfvoH_dYX;)O{Ab0lx-PEem$U1oZp3+f>El8& z56u9pHaGg9;|2#TQXOTR&7j*QD@ZZX4az_B*V9g#!MMwoct(~R)Y)HRb0?btafq5^ z`5x7}w~Ck&mzx31?3}$TgSf(M`UL|CGZVGf==h0>PWADUiE^!{K2y) zUYIWW+UkcE?b6AnaCTWH^OkpB5RqBhaMl%#kItV)=XY#(Yh1s<6e78UWPZ4Nfwz;k zprErUaBc5M|D@yv&-KTPs#Q%P`8wC5<-a^Z*gbODx&ae-tN4EPwjxhBNE#Q~Q(*$% zBrl$>_VR?7#E=K68%&^Va#z%-fF~4fOeom3*95v7%#Gg6dVpk8&jeSx31|(M-M4t^ z0h8(EE$Ji^n6X%)+3?N-xE#74c`Y*m%ksk6^A2}q} zTsDTv!w28`6nH>xrT^i?aAS~{dB6II4H~aANqZLs;i2wP_j42O;Jzosro_M)28~zL znxwb`YeRIIDz`D5svFtbY~a2an|-=k+?&PR!EavRGHsd$&P$oS=O4R42Rbf;WJcBb z6x*$CpxEo_F+w&5+Y#jdT5b@hCw*|%(HNS31j;bKbcOL8-t}@+W7ziy*~=5v*c#(S zeLlwUP(&);bDb-6Ao-=IF^JOluIiX{fukc`wXe&KL5udL_taw-kbENk@wKoC>>a*=)$Xt;6shFGIB1o0}}sfsj(SCQ*Ezh*mw{j((PmR?gh zeA%O`Qp*_v_vTdeAb+Z~JyiUP;0!;-H>lNH(gBZ82(tVUv-gT_5SF&zlo{qe#Y zUKa@May!8OO$XM^pU74G>m z4l9jyAz_Be+jOfla9-&?zG_w%hE`bjUvqYbhzkX()yyP-^-_dolFk4@g7G#{B*;{(Df6ZgF=ybBPu_Rvq&CEyy7P`ux;lBEt(6+W9aC|^4o7f&*CPLYY>1E)BP&#`<_M!1H{J)2s6bWIGTwVU==iU1 zUwk`MAir&>zF>(Xw0%FK*lVl|uC;2@A6BCCZEj1wt55(s(X_;VwId8oJUptwEDzF2 zg|q6j4ls9fHMvz#7C4GVwvNp>fatNi&Er=jLHbSWWcw2b7$V-55UjybtM)MIphI{OD+dMR`W7)~?19+P`&fNm0lMr@ zsRkF?gKONr-7NY_h>vsG6aDO=y5nxM)^`G($pR}lNh(Jd{BiD{>OJyHS9r9 zLF1maraDOKx~ktsa+jx4cEBbLFmL5Q>n>{#9fr%pB|J2NX^(D|_B}fw48>NC+|&RN zi1;aR+zyU@O1qIiqyfeIwg~Jsw}U4ud-eL)X@N6;#BP&~b|BG_GaI-?3%cIw-}7;{ z14mTTKkw0k1?=Oh>^?4eQ5!}-S4(}+w1ep$qVlAN4v62{6?MDW4idG!WQ>t~oYs-P z>WUql+2H(vOIsI8FE7jIKV%2kxgXzN*Xe?=^{I;w4%h*xk6FIoMFQIs9$oJlcCfW1 zRrK{F3C!~nE2GcY!JaocvwA=DKweeYanw~XmQoWdK|I<$T>?F%pDXY`@n z?=q#w(;gC4d-Z0%8o>(oYv&55chLBuw_{O)R_7Kg){>b*C5imV+%uDaG z2ijr(!k6&wuka18`Ki&076~{%KQqq2gw#sk8`qQ zP_|)>^~tn{LAQqeeLiH64gGjw%Otu!sn+Twkl`C^idnn114K)wI-YSLgY=~Sz5J~X zi@73dn{1KabqBcrxJy%0jtnzqDm|l@96&9&llLA5Q0mAU>)q)9mr33B^gRG9uBR>< z-*W)>4)s0b1^}YrA5~n69H76jh)L82KrL`Rr}+g3pdCB8X?3Cz#6Q0JLjI!z7%42t z|N7Dp6mz*A37a}X;9SVDIb}nbKGS$KLD&&`)wf3VUN?ZDqvlQJOHurN>;0 zD>Tni9U;O!OeZNsAFfa9-}|-45x7!VG{?vFU}u#_SIlEa(4Qe2*?Q^0pnSw`bpXl8N-+qHM)#iH~e>-8tg zS~i5IUrN~nhxFj*GybzTl%1jBBICCHI(>Mt?BZ!b4QGgXnKOIBQV+D6AIQgQI>QTZ z<9;VTJ(zb=aVZOT21!eed-8Q8nCl*@e|-eytJ%S=DnlgbKy}FbPG=a6QOagU_s{59 zmM_WV0z{qUeaD`XAYHgw>lCXCydfp;8{DD?ERU&6^TttrQM>RW>y92M*EaI0i@HGZ zgW(HDhmrsCrIj;KZi@k!IJjOqAms|98(*!i@79M`wPLTwSGj^{e}jYWM*V;Gl7Ig^ zLm({C`ORAva?`@T`$Fzs$aTMYi{xM4g3s&tJ$d||J$_H0#Qc1T^->pbO|ZG7uBr(< zPKQK`mbgHs`K#3hmoy<>_UQAlFV3)o@4}02Wi2rB=t#f#+!;#k_n7tG(t-$it?b4V z&S0@YDSPdGEvU3~y_ALcU35mOXhwh*v`Qa!k3oEntEfO#@Tn$n?K${Xe;dl>qeEi|#6Cc0$_{PUS9v@gM5-YcOJA?LDve6WWKG2<2T$uMd zFU~av)fHHkGsI1?Ju2qX2Sw`MRoPwW`eK_)f#`hv{Lzwv&|lY|ca#5O>jKs-VB3i) zqOx}Af1WX3|5p!qT*KoY9vAVriN{qu?&5J7kK1@$$KyUeFW~bAKCj^O&QFQQcguVo z7uPA4}R@s_t)KUf;iVO zosD1r%^OJN8wdm@+23}`z1r_H5^lZ7aTap6_)$4ow(S2rLrwW>CwxA~=X*RK!1Dz> zpTP4CJRiaH6+EB8^Bp`N!t*6OpThGkJRigJH9Vig^F2Ht#PdZwpUg-(&mP!s3&s1_ zn!Nm^4I#qk-dnfXf(WW#U!BzfcPj|)KVl1(?@HO9hUx+<(N%p)%oYeyO4(KVy1+GK zM)(=TfWnHL(HLcR91^ z$d5~}luU)S*udPH$>cZN4S@EXX)tD)Ep+X0{$S){0IjZMi7I%jQu>Tjkklo+QUjo zn-MoB3RF@L6}xac0A~pC)z7Ja`Tg&o?hvm0dA3Xc`i{I)RO?0CFO01(wsxnX;eURI zF#d}x=Qxi(C!Vy0g65>F;Z+m}+bCP~?6xiNa-S5*J5Par=H@HHUu=Q4cTg_#5Cuxf z9V^bW+X3TzPxu!!Z%JgACE9ji$gx3fO(g}YZw%FETG~Ot#+(Y*9166rdwf^j7u9uc z2?d`!DL_Yd*|y&fZf_>OGQUTGe@r0 zM89>(6xg}*7glO(4`p>#IRQ-+5S&>Pel^Y>g3$cG)KXyePb<&5MpQS)mg+ax{%c3P zo$-Ev_Y=Gy;r$Hnhj>55`!U|n@o|8U6MP)u;|w2%_&CMKF+R@mIDp3qJdWUT29HB{ zoWkQ69_R2lh{s7hj+V1{aQ}L34Fdhc7Z?qOkhV5deBU!`nB#S@mGL!#`R}5o*)i5| z?0)xg>ogx%^GIvlC%qU0XXb@l;R$14Wh4Kwp8B& zScuiEdwH#gpCWts?dNz9WDR~K?ZRv7WFV@4S}|W>4RIY`vo(>u8InWuNkTRdBsng0 zx`Yh5(=(ev~zzWSb zGWIRP3BIt?5j#SqS& zYVkG|p+WnKd5Ilo5zal!Yi*gOLd|sb=`MdeC=G02(^^4;451aZn3o+CJoNMkxkZK1 zorT+_P9YpbvU4XD5+%-U(wVY@v;^{&JEst?8GPBOyU891>`Hgku2Mm<)WbF^)*dpL zvN9Th3XYMoLa|v0XAar3lvq(0_y4BNBA4wZQsJX^eVlNuJ=pT~rPclX7pL$zhQ~QP z4&reVkE3{;#p5s@r|~$B$9a4nz~>2k9>M1sd>+E*DSRHo`yX=25ah?i-+sJcy9L`2 zQgy3NaXG^Hn)dH1WyXK}SmLiA&+uqv=iRV_5Vp@Q+~UTtt%169{GJ_XtWq+Tb~j$s zTmO=4?=(Y=p?u><6;~g72-p*1BLv1^`7-c~gv7 z_k`zeHU^SGeVpnT;tfY?t#XWv7uS+9^RlHw(HKTieO1cl2!<^d<^!vYq0&sn=4ufz9G4>d96@zT13JHAH4UQ9t4$xIqPUC9QFtCk z1606#xiD)79in|{<~209&3)9JALZ9=lQb^hL+JW1)u&$;*n!01TC2=v8iaLc>^p+; zcK}KH;P$o1o;d$NF0%>w*`IgMJ7ZoSwFUD?>Ys z3~pJ|=ZvpgKpmPl^&|~ORa-B9_-+9od%tGyJwpRdihi1Nnk7hw&qR~Y(m>Yv-DCUh zmXLgzq+35mgJt!Xn9sklgcMKu`EInXxX=4G@3Xa9oGZI?b

DD_ELJ{+upo3=G4- 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 Date: Wed, 19 Aug 2026 20:52:31 -0700 Subject: [PATCH 03/16] remove utf-8 declaration and sort imports --- pyproject.toml | 6 +++++- src/tatc_app/celery/router.py | 6 ++---- src/tatc_app/celery/schemas.py | 1 - src/tatc_app/celeryconfig.py | 1 - src/tatc_app/celestrak/router.py | 4 +--- src/tatc_app/cesium/router.py | 1 - src/tatc_app/coverage/router.py | 9 ++++----- src/tatc_app/coverage/schemas.py | 3 +-- src/tatc_app/coverage/tasks.py | 12 +++++------- src/tatc_app/generation/router.py | 7 +++---- src/tatc_app/generation/schemas.py | 3 +-- src/tatc_app/generation/tasks.py | 7 +++---- src/tatc_app/generation/utils.py | 9 ++++----- src/tatc_app/latency/router.py | 11 +++++------ src/tatc_app/latency/schemas.py | 5 ++--- src/tatc_app/latency/tasks.py | 12 +++++------- src/tatc_app/main.py | 25 ++++++++++++------------- src/tatc_app/overflight/router.py | 7 +++---- src/tatc_app/overflight/schemas.py | 1 - src/tatc_app/overflight/tasks.py | 5 ++--- src/tatc_app/tracking/router.py | 11 +++++------ src/tatc_app/tracking/schemas.py | 3 +-- src/tatc_app/tracking/tasks.py | 5 ++--- src/tatc_app/utils/db.py | 1 - src/tatc_app/utils/schemas.py | 1 - src/tatc_app/utils/tasks.py | 3 +-- src/tatc_app/utils/users.py | 4 +--- src/tatc_app/worker.py | 1 - 28 files changed, 68 insertions(+), 96 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ebae789..3202861 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ tatc_app = ["resources/*.zip"] dev = [ "black >= 24.2", "httpx", + "isort", "pylint", "pylint-pydantic", "pytest" @@ -62,4 +63,7 @@ docs = [ ] [tool.setuptools.dynamic] -version = {attr = "tatc_app.__version__"} \ No newline at end of file +version = {attr = "tatc_app.__version__"} + +[tool.isort] +profile = "black" \ No newline at end of file diff --git a/src/tatc_app/celery/router.py b/src/tatc_app/celery/router.py index ef01642..92b64e9 100644 --- a/src/tatc_app/celery/router.py +++ b/src/tatc_app/celery/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specification for celery endpoints. @@ -7,12 +6,11 @@ from uuid import UUID -from fastapi import APIRouter, HTTPException from celery.result import GroupResult +from fastapi import APIRouter, HTTPException -from .schemas import CeleryResultStatus, CeleryResultProgress from ..worker import app as celery_app - +from .schemas import CeleryResultProgress, CeleryResultStatus router = APIRouter() diff --git a/src/tatc_app/celery/schemas.py b/src/tatc_app/celery/schemas.py index e4b9e02..202713a 100644 --- a/src/tatc_app/celery/schemas.py +++ b/src/tatc_app/celery/schemas.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Schema specifications for celery endpoints. diff --git a/src/tatc_app/celeryconfig.py b/src/tatc_app/celeryconfig.py index 9b0e8f3..f5b41c9 100644 --- a/src/tatc_app/celeryconfig.py +++ b/src/tatc_app/celeryconfig.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Celery configuration file. diff --git a/src/tatc_app/celestrak/router.py b/src/tatc_app/celestrak/router.py index d750931..4736fcb 100644 --- a/src/tatc_app/celestrak/router.py +++ b/src/tatc_app/celestrak/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specifications for celestrak endpoints. @@ -6,10 +5,9 @@ """ +import aiohttp from fastapi import APIRouter from fastapi.responses import PlainTextResponse -import aiohttp - router = APIRouter() diff --git a/src/tatc_app/cesium/router.py b/src/tatc_app/cesium/router.py index 9392681..df8e435 100644 --- a/src/tatc_app/cesium/router.py +++ b/src/tatc_app/cesium/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specifications for cesium endpoints. diff --git a/src/tatc_app/coverage/router.py b/src/tatc_app/coverage/router.py index 6d62884..747fa6b 100644 --- a/src/tatc_app/coverage/router.py +++ b/src/tatc_app/coverage/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specifications for coverage analysis endpoints. @@ -7,16 +6,16 @@ from uuid import UUID -from celery import group, chain +from celery import chain, group from celery.result import GroupResult from fastapi import APIRouter, HTTPException -from .schemas import CoverageAnalysisRequest, CoverageAnalysisResult -from .tasks import run_coverage_analysis_task, grid_coverage_analysis_task -from ..generation.utils import generate_points, generate_cells from ..celery.schemas import CeleryTask +from ..generation.utils import generate_cells, generate_points from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app +from .schemas import CoverageAnalysisRequest, CoverageAnalysisResult +from .tasks import grid_coverage_analysis_task, run_coverage_analysis_task router = APIRouter() diff --git a/src/tatc_app/coverage/schemas.py b/src/tatc_app/coverage/schemas.py index a54cf45..f2bccb5 100644 --- a/src/tatc_app/coverage/schemas.py +++ b/src/tatc_app/coverage/schemas.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Schema specifications for coverage analysis endpoints. @@ -13,7 +12,7 @@ from pydantic.alias_generators import to_camel from tatc.schemas import Point, Satellite, TrainConstellation, WalkerConstellation -from ..generation.schemas import PointGenerator, Cell, CellGenerator +from ..generation.schemas import Cell, CellGenerator, PointGenerator class CoverageAnalysisRequest(BaseModel): diff --git a/src/tatc_app/coverage/tasks.py b/src/tatc_app/coverage/tasks.py index 6a8496c..cca395c 100644 --- a/src/tatc_app/coverage/tasks.py +++ b/src/tatc_app/coverage/tasks.py @@ -1,25 +1,23 @@ -# -*- coding: utf-8 -*- """ Task specifications for coverage analysis endpoints. @author: Paul T. Grogan """ -from datetime import datetime import json +from datetime import datetime import geopandas as gpd - -from tatc.schemas import Point, Satellite from tatc.analysis.coverage import ( - collect_multi_observations, aggregate_observations, - reduce_observations, + collect_multi_observations, grid_observations, + reduce_observations, ) +from tatc.schemas import Point, Satellite -from .schemas import CoverageAnalysisResult from ..worker import app +from .schemas import CoverageAnalysisResult @app.task diff --git a/src/tatc_app/generation/router.py b/src/tatc_app/generation/router.py index e211907..9b7efd5 100644 --- a/src/tatc_app/generation/router.py +++ b/src/tatc_app/generation/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specifications for generation endpoints. @@ -11,15 +10,15 @@ from geojson_pydantic import FeatureCollection from .schemas import ( - PointGenerator, - PointGeneratorMethod, CellGenerator, CellGeneratorMethod, + PointGenerator, + PointGeneratorMethod, ) from .tasks import ( + generate_equally_spaced_cells_task, generate_equally_spaced_points_task, generate_fibonacci_lattice_points_task, - generate_equally_spaced_cells_task, ) router = APIRouter() diff --git a/src/tatc_app/generation/schemas.py b/src/tatc_app/generation/schemas.py index 817dd14..848af5c 100644 --- a/src/tatc_app/generation/schemas.py +++ b/src/tatc_app/generation/schemas.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Schema specifications for generation endpoints. @@ -11,7 +10,7 @@ from typing import Annotated, Optional, Union from geojson_pydantic import Polygon -from pydantic import BaseModel, ConfigDict, Field, model_validator, StringConstraints +from pydantic import BaseModel, ConfigDict, Field, StringConstraints, model_validator from pydantic.alias_generators import to_camel from shapely.geometry import box, mapping diff --git a/src/tatc_app/generation/tasks.py b/src/tatc_app/generation/tasks.py index 841f721..33a62c6 100644 --- a/src/tatc_app/generation/tasks.py +++ b/src/tatc_app/generation/tasks.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Task specifications for generation endpoints. @@ -11,14 +10,14 @@ import geopandas as gpd from shapely.geometry import shape +from tatc.generation.cells import generate_cells_uniform_spacing from tatc.generation.points import ( - generate_points_uniform_spacing, generate_points_fibonacci_lattice, + generate_points_uniform_spacing, ) -from tatc.generation.cells import generate_cells_uniform_spacing -from .schemas import KnownShape from ..worker import app +from .schemas import KnownShape @lru_cache(maxsize=None) diff --git a/src/tatc_app/generation/utils.py b/src/tatc_app/generation/utils.py index acfe697..acf1e86 100644 --- a/src/tatc_app/generation/utils.py +++ b/src/tatc_app/generation/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Utility functions for generation endpoints. @@ -6,22 +5,22 @@ """ import json -from typing import Union, List +from typing import List, Union import geopandas as gpd from tatc.schemas import Point from .schemas import ( - PointGenerator, - PointGeneratorMethod, Cell, CellGenerator, CellGeneratorMethod, + PointGenerator, + PointGeneratorMethod, ) from .tasks import ( + generate_equally_spaced_cells_task, generate_equally_spaced_points_task, generate_fibonacci_lattice_points_task, - generate_equally_spaced_cells_task, ) diff --git a/src/tatc_app/latency/router.py b/src/tatc_app/latency/router.py index 6702112..a4df8f9 100644 --- a/src/tatc_app/latency/router.py +++ b/src/tatc_app/latency/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specifications for latency analysis endpoints. @@ -11,16 +10,16 @@ from celery.result import GroupResult from fastapi import APIRouter, HTTPException +from ..celery.schemas import CeleryTask +from ..generation.utils import generate_cells, generate_points +from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app +from .schemas import LatencyAnalysisRequest, LatencyAnalysisResult from .tasks import ( collect_downlinks_task, - run_latency_analysis_task, grid_latency_analysis_task, + run_latency_analysis_task, ) -from ..celery.schemas import CeleryTask -from ..utils.tasks import merge_feature_collections_task -from .schemas import LatencyAnalysisRequest, LatencyAnalysisResult -from ..generation.utils import generate_points, generate_cells router = APIRouter() diff --git a/src/tatc_app/latency/schemas.py b/src/tatc_app/latency/schemas.py index 006904f..7c3d06c 100644 --- a/src/tatc_app/latency/schemas.py +++ b/src/tatc_app/latency/schemas.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Schema specifications for latency analysis endpoints. @@ -11,7 +10,6 @@ from geojson_pydantic import FeatureCollection from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel - from tatc.schemas import ( GroundStation, Point, @@ -19,10 +17,11 @@ TrainConstellation, WalkerConstellation, ) + from ..generation.schemas import ( - PointGenerator, Cell, CellGenerator, + PointGenerator, ) diff --git a/src/tatc_app/latency/tasks.py b/src/tatc_app/latency/tasks.py index 5a5f38c..26ffacf 100644 --- a/src/tatc_app/latency/tasks.py +++ b/src/tatc_app/latency/tasks.py @@ -1,26 +1,24 @@ -# -*- coding: utf-8 -*- """ Task specifications for latency analysis endpoints. @author: Paul T. Grogan """ -from datetime import datetime import json +from datetime import datetime import geopandas as gpd - -from tatc.schemas import Point, GroundStation, Satellite +from tatc.analysis.coverage import collect_multi_observations from tatc.analysis.latency import ( collect_downlinks, compute_latencies, - reduce_latencies, grid_latencies, + reduce_latencies, ) -from tatc.analysis.coverage import collect_multi_observations +from tatc.schemas import GroundStation, Point, Satellite -from .schemas import LatencyAnalysisResult from ..worker import app +from .schemas import LatencyAnalysisResult @app.task diff --git a/src/tatc_app/main.py b/src/tatc_app/main.py index 6992bee..92e93f7 100644 --- a/src/tatc_app/main.py +++ b/src/tatc_app/main.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ TAT-C application configuration. @@ -7,33 +6,33 @@ import os - from contextlib import asynccontextmanager + from dotenv import load_dotenv -from fastapi import FastAPI, Depends +from fastapi import Depends, FastAPI from fastapi.middleware.gzip import GZipMiddleware from fastapi.staticfiles import StaticFiles from msgpack_asgi import MessagePackMiddleware from tatc_app import __version__ +from tatc_app.celery.router import router as celery_router +from tatc_app.celestrak.router import router as celestrak_router +from tatc_app.cesium.router import get_cesium_router +from tatc_app.coverage.router import router as coverage_router +from tatc_app.generation.router import router as generation_router +from tatc_app.latency.router import router as latency_router +from tatc_app.overflight.router import router as overflight_router +from tatc_app.tracking.router import router as tracking_router from tatc_app.utils.db import create_db_and_tables from tatc_app.utils.schemas import UserCreate, UserRead, UserUpdate from tatc_app.utils.users import ( cookie_backend, - jwt_backend, + create_user, current_active_user, current_superuser, - create_user, fastapi_users, + jwt_backend, ) -from tatc_app.celery.router import router as celery_router -from tatc_app.celestrak.router import router as celestrak_router -from tatc_app.cesium.router import get_cesium_router -from tatc_app.generation.router import router as generation_router -from tatc_app.overflight.router import router as overflight_router -from tatc_app.tracking.router import router as tracking_router -from tatc_app.coverage.router import router as coverage_router -from tatc_app.latency.router import router as latency_router # Load environment variables from the .env file load_dotenv() diff --git a/src/tatc_app/overflight/router.py b/src/tatc_app/overflight/router.py index a337edb..422aa83 100644 --- a/src/tatc_app/overflight/router.py +++ b/src/tatc_app/overflight/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specifications for overflight analysis endpoints. @@ -13,12 +12,12 @@ from fastapi import APIRouter, HTTPException from geojson_pydantic import FeatureCollection -from .schemas import OverflightAnalysisRequest -from .tasks import collect_observations_task, aggregate_observations_task -from ..generation.utils import generate_points from ..celery.schemas import CeleryTask +from ..generation.utils import generate_points from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app +from .schemas import OverflightAnalysisRequest +from .tasks import aggregate_observations_task, collect_observations_task router = APIRouter() diff --git a/src/tatc_app/overflight/schemas.py b/src/tatc_app/overflight/schemas.py index c84ae47..610092b 100644 --- a/src/tatc_app/overflight/schemas.py +++ b/src/tatc_app/overflight/schemas.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Schema specifications for overflight analysis endpoints. diff --git a/src/tatc_app/overflight/tasks.py b/src/tatc_app/overflight/tasks.py index 887d8df..59b56f0 100644 --- a/src/tatc_app/overflight/tasks.py +++ b/src/tatc_app/overflight/tasks.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Task specifications for overflight analysis endpoints. @@ -6,12 +5,12 @@ """ -from datetime import datetime import json +from datetime import datetime import geopandas as gpd +from tatc.analysis.coverage import aggregate_observations, collect_observations from tatc.schemas import Instrument, Point, Satellite -from tatc.analysis.coverage import collect_observations, aggregate_observations from ..worker import app diff --git a/src/tatc_app/tracking/router.py b/src/tatc_app/tracking/router.py index 3ace33e..8d2355c 100644 --- a/src/tatc_app/tracking/router.py +++ b/src/tatc_app/tracking/router.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Router specifications for tracking analysis endpoints. @@ -8,19 +7,19 @@ from datetime import timezone from uuid import UUID +import numpy as np +import pandas as pd from celery import chain, group from celery.result import GroupResult from fastapi import APIRouter, HTTPException from geojson_pydantic import FeatureCollection -import numpy as np -import pandas as pd -from .schemas import OrbitTrackAnalysisRequest, GroundTrackAnalysisRequest -from .tasks import collect_orbit_track_task, collect_ground_track_task -from ..generation.schemas import TimeGenerator from ..celery.schemas import CeleryTask +from ..generation.schemas import TimeGenerator from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app +from .schemas import GroundTrackAnalysisRequest, OrbitTrackAnalysisRequest +from .tasks import collect_ground_track_task, collect_orbit_track_task router = APIRouter() diff --git a/src/tatc_app/tracking/schemas.py b/src/tatc_app/tracking/schemas.py index 54eac3b..64ce199 100644 --- a/src/tatc_app/tracking/schemas.py +++ b/src/tatc_app/tracking/schemas.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Schema specifications for tracking analysis endpoints. @@ -13,7 +12,7 @@ from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel from shapely.geometry import box, mapping -from tatc.schemas import Satellite, TrainConstellation, WalkerConstellation, Instrument +from tatc.schemas import Instrument, Satellite, TrainConstellation, WalkerConstellation from ..generation.schemas import TimeGenerator diff --git a/src/tatc_app/tracking/tasks.py b/src/tatc_app/tracking/tasks.py index f08a094..f2c538e 100644 --- a/src/tatc_app/tracking/tasks.py +++ b/src/tatc_app/tracking/tasks.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Task specifications for tracking analysis endpoints. @@ -9,8 +8,8 @@ from datetime import datetime from shapely.geometry import shape -from tatc.analysis.track import collect_orbit_track, collect_ground_track -from tatc.schemas import Satellite, Instrument +from tatc.analysis.track import collect_ground_track, collect_orbit_track +from tatc.schemas import Instrument, Satellite from ..worker import app diff --git a/src/tatc_app/utils/db.py b/src/tatc_app/utils/db.py index 1456a2e..53a0820 100644 --- a/src/tatc_app/utils/db.py +++ b/src/tatc_app/utils/db.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Database objects for FastAPI Users authentication/authorization. diff --git a/src/tatc_app/utils/schemas.py b/src/tatc_app/utils/schemas.py index e8c2bd0..a2735e3 100644 --- a/src/tatc_app/utils/schemas.py +++ b/src/tatc_app/utils/schemas.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ Schema specifications for general utilities. diff --git a/src/tatc_app/utils/tasks.py b/src/tatc_app/utils/tasks.py index 91c052e..e8d9f8e 100644 --- a/src/tatc_app/utils/tasks.py +++ b/src/tatc_app/utils/tasks.py @@ -1,12 +1,11 @@ -# -*- coding: utf-8 -*- """ Task specifications for general utilities. @author: Paul T. Grogan """ -from typing import Union from itertools import chain +from typing import Union from geojson_pydantic import FeatureCollection diff --git a/src/tatc_app/utils/users.py b/src/tatc_app/utils/users.py index b4fa59c..afc5e99 100644 --- a/src/tatc_app/utils/users.py +++ b/src/tatc_app/utils/users.py @@ -1,14 +1,13 @@ -# -*- coding: utf-8 -*- """ Configuration for FastAPI Users authentication/authorization system. @author: Paul T. Grogan """ +import contextlib import os import uuid from typing import Optional -import contextlib from fastapi import Depends, Request from fastapi_users import BaseUserManager, FastAPIUsers, UUIDIDMixin @@ -24,7 +23,6 @@ from .db import User, get_async_session, get_user_db from .schemas import UserCreate - SECRET = os.getenv("TATC_SECRET", "change me") LOGIN_LIFETIME = int(os.getenv("TATC_LOGIN_LIFETIME_SECONDS", 7200)) diff --git a/src/tatc_app/worker.py b/src/tatc_app/worker.py index bfaa4b1..10fb6c0 100644 --- a/src/tatc_app/worker.py +++ b/src/tatc_app/worker.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ TAT-C worker configuration. From ff38479b3d14980d1d5953df57cf4c9bb7f5dc7b Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Wed, 19 Aug 2026 23:00:53 -0700 Subject: [PATCH 04/16] add adapters to match new tatc interface --- src/tatc_app/coverage/router.py | 3 +- src/tatc_app/coverage/schemas.py | 5 +- src/tatc_app/latency/router.py | 5 +- src/tatc_app/latency/schemas.py | 11 +- src/tatc_app/overflight/router.py | 3 +- src/tatc_app/overflight/schemas.py | 11 +- src/tatc_app/satellites.py | 163 +++++++++++++++++++++++++++++ src/tatc_app/tracking/router.py | 5 +- src/tatc_app/tracking/schemas.py | 5 +- tests/test_satellites.py | 69 ++++++++++++ 10 files changed, 254 insertions(+), 26 deletions(-) create mode 100644 src/tatc_app/satellites.py create mode 100644 tests/test_satellites.py diff --git a/src/tatc_app/coverage/router.py b/src/tatc_app/coverage/router.py index 747fa6b..64a0959 100644 --- a/src/tatc_app/coverage/router.py +++ b/src/tatc_app/coverage/router.py @@ -12,6 +12,7 @@ from ..celery.schemas import CeleryTask from ..generation.utils import generate_cells, generate_points +from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app from .schemas import CoverageAnalysisRequest, CoverageAnalysisResult @@ -38,7 +39,7 @@ async def enqueue_coverage_analysis(request: CoverageAnalysisRequest): [ satellite.model_dump_json() for constellation in request.satellites - for satellite in constellation.generate_members() + for satellite in generate_members(constellation) ], request.start.isoformat(), request.end.isoformat(), diff --git a/src/tatc_app/coverage/schemas.py b/src/tatc_app/coverage/schemas.py index f2bccb5..30f5000 100644 --- a/src/tatc_app/coverage/schemas.py +++ b/src/tatc_app/coverage/schemas.py @@ -10,9 +10,10 @@ from geojson_pydantic import FeatureCollection from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from tatc.schemas import Point, Satellite, TrainConstellation, WalkerConstellation +from tatc.schemas import Point from ..generation.schemas import Cell, CellGenerator, PointGenerator +from ..satellites import SpaceSystemInput class CoverageAnalysisRequest(BaseModel): @@ -23,7 +24,7 @@ class CoverageAnalysisRequest(BaseModel): model_config = ConfigDict( from_attributes=True, populate_by_name=True, alias_generator=to_camel ) - satellites: List[Union[Satellite, TrainConstellation, WalkerConstellation]] = Field( + satellites: List[SpaceSystemInput] = Field( ..., description="Satellites from which to observe." ) start: datetime = Field( diff --git a/src/tatc_app/latency/router.py b/src/tatc_app/latency/router.py index a4df8f9..52a981e 100644 --- a/src/tatc_app/latency/router.py +++ b/src/tatc_app/latency/router.py @@ -12,6 +12,7 @@ from ..celery.schemas import CeleryTask from ..generation.utils import generate_cells, generate_points +from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app from .schemas import LatencyAnalysisRequest, LatencyAnalysisResult @@ -44,7 +45,7 @@ async def enqueue_latency_analysis(request: LatencyAnalysisRequest): request.end.isoformat(), ) for constellation in request.satellites - for satellite in constellation.generate_members() + for satellite in generate_members(constellation) ), merge_feature_collections_task.s(), group( @@ -53,7 +54,7 @@ async def enqueue_latency_analysis(request: LatencyAnalysisRequest): [ satellite.model_dump_json() for constellation in request.satellites - for satellite in constellation.generate_members() + for satellite in generate_members(constellation) ], request.start.isoformat(), request.end.isoformat(), diff --git a/src/tatc_app/latency/schemas.py b/src/tatc_app/latency/schemas.py index 7c3d06c..7a6c2ec 100644 --- a/src/tatc_app/latency/schemas.py +++ b/src/tatc_app/latency/schemas.py @@ -10,19 +10,14 @@ from geojson_pydantic import FeatureCollection from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from tatc.schemas import ( - GroundStation, - Point, - Satellite, - TrainConstellation, - WalkerConstellation, -) +from tatc.schemas import GroundStation, Point from ..generation.schemas import ( Cell, CellGenerator, PointGenerator, ) +from ..satellites import SpaceSystemInput class LatencyAnalysisRequest(BaseModel): @@ -42,7 +37,7 @@ class LatencyAnalysisRequest(BaseModel): stations: List[GroundStation] = Field( ..., description="Stations to which observations can be downlinked" ) - satellites: List[Union[Satellite, TrainConstellation, WalkerConstellation]] = Field( + satellites: List[SpaceSystemInput] = Field( ..., description="Satellite from which to observe." ) start: datetime = Field( diff --git a/src/tatc_app/overflight/router.py b/src/tatc_app/overflight/router.py index 422aa83..3ff2588 100644 --- a/src/tatc_app/overflight/router.py +++ b/src/tatc_app/overflight/router.py @@ -14,6 +14,7 @@ from ..celery.schemas import CeleryTask from ..generation.utils import generate_points +from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app from .schemas import OverflightAnalysisRequest @@ -48,7 +49,7 @@ async def enqueue_overflight_analysis(request: OverflightAnalysisRequest): request.omit_solar, ) for point in generate_points(request.points) # FIXME - for satellite in request.satellite.generate_members() + for satellite in generate_members(request.satellite) ), merge_feature_collections_task.s(), aggregate_observations_task.s(), diff --git a/src/tatc_app/overflight/schemas.py b/src/tatc_app/overflight/schemas.py index 610092b..004b39f 100644 --- a/src/tatc_app/overflight/schemas.py +++ b/src/tatc_app/overflight/schemas.py @@ -10,15 +10,10 @@ from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel -from tatc.schemas import ( - Instrument, - Point, - Satellite, - TrainConstellation, - WalkerConstellation, -) +from tatc.schemas import Instrument, Point from ..generation.schemas import PointGenerator +from ..satellites import SpaceSystemInput class OverflightAnalysisRequest(BaseModel): @@ -32,7 +27,7 @@ class OverflightAnalysisRequest(BaseModel): points: Union[List[Point], PointGenerator] = Field( ..., description="Points from which to collect observations." ) - satellite: Union[Satellite, TrainConstellation, WalkerConstellation] = Field( + satellite: SpaceSystemInput = Field( ..., description="Satellite from which to observe." ) instrument: Union[int, Instrument] = Field( diff --git a/src/tatc_app/satellites.py b/src/tatc_app/satellites.py new file mode 100644 index 0000000..b6239c3 --- /dev/null +++ b/src/tatc_app/satellites.py @@ -0,0 +1,163 @@ +""" +Shared schemas and utilities to accept satellite/constellation requests that +specify their orbit as two line elements (TLE), as commonly distributed by +sources such as Celestrak. + +tatc's own schemas no longer accept raw TLE lines directly: orbits +propagated from TLEs are represented as a `GeneralPerturbationsOrbit`, whose +wire format is a structured list of orbital elements rather than the two raw +TLE lines a client would naturally have on hand. Since it isn't reasonable +to ask a client to perform that conversion itself, `TwoLineElements` is +accepted here as an additional orbit variant and converted into a +`GeneralPerturbationsOrbit` on the backend, via `generate_members`, before +any tatc analysis code sees it. + +@author: Paul T. Grogan +""" + +from typing import List, Literal, Union + +from pydantic import BaseModel, ConfigDict, Field, field_validator +from tatc.schemas import ( + CircularOrbit, + GeneralPerturbationsOrbit, + GeosynchronousOrbit, + KeplerianOrbit, + MolniyaOrbit, + Satellite, + SunSynchronousOrbit, + TrainConstellation, + TundraOrbit, + WalkerConstellation, +) + + +class TwoLineElements(BaseModel): + """ + Orbit specified as two line elements (TLE). + """ + + type: Literal["tle"] = "tle" + tle: List[str] = Field( + ..., + min_length=2, + max_length=2, + description="Two line element (TLE) lines.", + examples=[ + [ + "1 25544U 98067A 21156.30527927 .00003432 00000-0 70541-4 0 9993", + "2 25544 51.6455 41.4969 0003508 68.0432 78.3395 15.48957534286754", + ] + ], + ) + + @field_validator("tle") + @classmethod + def valid_tle(cls, tle: List[str]) -> List[str]: + """ + Validates the TLE lines can be parsed into a `GeneralPerturbationsOrbit`. + """ + GeneralPerturbationsOrbit.from_tle(tle) + return tle + + +# orbit types accepted from a client, including tatc's native orbit types +# (passed through as-is) in addition to `TwoLineElements`. +OrbitInput = Union[ + CircularOrbit, + GeneralPerturbationsOrbit, + GeosynchronousOrbit, + KeplerianOrbit, + MolniyaOrbit, + SunSynchronousOrbit, + TundraOrbit, + TwoLineElements, +] + + +class SatelliteInput(Satellite): + """ + A `Satellite` request that may specify its orbit as two line elements. + """ + + # accepts a native tatc `Satellite` instance directly, not only a + # dict/JSON payload, since it is otherwise a stricter (sub)type + model_config = ConfigDict(from_attributes=True) + + orbit: OrbitInput + + +class TrainConstellationInput(TrainConstellation): + """ + A `TrainConstellation` request that may specify its orbit as two line + elements. + """ + + model_config = ConfigDict(from_attributes=True) + + orbit: OrbitInput + + +class WalkerConstellationInput(WalkerConstellation): + """ + A `WalkerConstellation` request that may specify its orbit as two line + elements. + """ + + model_config = ConfigDict(from_attributes=True) + + orbit: OrbitInput + + +SpaceSystemInput = Union[ + SatelliteInput, TrainConstellationInput, WalkerConstellationInput +] + +_TATC_TYPES = { + SatelliteInput: Satellite, + TrainConstellationInput: TrainConstellation, + WalkerConstellationInput: WalkerConstellation, +} + + +def to_tatc_satellite( + satellite: SpaceSystemInput, +) -> Union[Satellite, TrainConstellation, WalkerConstellation]: + """ + Converts a satellite/constellation request into the corresponding tatc + schema, resolving a `TwoLineElements` orbit into a + `GeneralPerturbationsOrbit` along the way. + + Args: + satellite (SpaceSystemInput): the requested satellite or constellation. + + Returns: + Union[Satellite, TrainConstellation, WalkerConstellation]: the + equivalent tatc satellite or constellation. + """ + orbit = ( + GeneralPerturbationsOrbit.from_tle(satellite.orbit.tle) + if isinstance(satellite.orbit, TwoLineElements) + else satellite.orbit + ) + tatc_type = _TATC_TYPES[type(satellite)] + return tatc_type(**satellite.model_dump(exclude={"orbit", "type"}), orbit=orbit) + + +def generate_members(satellite: SpaceSystemInput) -> List[Satellite]: + """ + Expands a satellite/constellation request into its member satellites, + resolving a `TwoLineElements` orbit into a `GeneralPerturbationsOrbit` + along the way. A plain satellite (not a constellation) is treated as its + own sole member. + + Args: + satellite (SpaceSystemInput): the requested satellite or constellation. + + Returns: + List[Satellite]: the member satellites. + """ + converted = to_tatc_satellite(satellite) + if isinstance(converted, Satellite): + return [converted] + return converted.generate_members() diff --git a/src/tatc_app/tracking/router.py b/src/tatc_app/tracking/router.py index 8d2355c..86522e8 100644 --- a/src/tatc_app/tracking/router.py +++ b/src/tatc_app/tracking/router.py @@ -16,6 +16,7 @@ from ..celery.schemas import CeleryTask from ..generation.schemas import TimeGenerator +from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task from ..worker import app as celery_app from .schemas import GroundTrackAnalysisRequest, OrbitTrackAnalysisRequest @@ -59,7 +60,7 @@ async def enqueue_orbit_track_analysis(request: OrbitTrackAnalysisRequest): request.model_dump().get("mask", None), ) for times in np.array_split(times, max(1, len(times) // 100)) - for satellite in request.satellite.generate_members() + for satellite in generate_members(request.satellite) ), merge_feature_collections_task.s(), )() @@ -130,7 +131,7 @@ async def enqueue_ground_track_analysis(request: GroundTrackAnalysisRequest): request.model_dump().get("mask", None), ) for times in np.array_split(times, max(1, len(times) // 100)) - for satellite in request.satellite.generate_members() + for satellite in generate_members(request.satellite) ), merge_feature_collections_task.s(), )() diff --git a/src/tatc_app/tracking/schemas.py b/src/tatc_app/tracking/schemas.py index 64ce199..489220e 100644 --- a/src/tatc_app/tracking/schemas.py +++ b/src/tatc_app/tracking/schemas.py @@ -12,9 +12,10 @@ from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel from shapely.geometry import box, mapping -from tatc.schemas import Instrument, Satellite, TrainConstellation, WalkerConstellation +from tatc.schemas import Instrument from ..generation.schemas import TimeGenerator +from ..satellites import SpaceSystemInput class OrbitTrackAnalysisRequest(BaseModel): @@ -25,7 +26,7 @@ class OrbitTrackAnalysisRequest(BaseModel): model_config = ConfigDict( from_attributes=True, populate_by_name=True, alias_generator=to_camel ) - satellite: Union[Satellite, TrainConstellation, WalkerConstellation] = Field( + satellite: SpaceSystemInput = Field( ..., description="Satellite from which to observe." ) instrument: Optional[Union[int, Instrument]] = Field( diff --git a/tests/test_satellites.py b/tests/test_satellites.py new file mode 100644 index 0000000..3ae6160 --- /dev/null +++ b/tests/test_satellites.py @@ -0,0 +1,69 @@ +import unittest + +from pydantic import ValidationError +from tatc.schemas import CircularOrbit, GeneralPerturbationsOrbit, Instrument, Satellite + +from tatc_app.satellites import SatelliteInput, generate_members, to_tatc_satellite + +TLE = [ + "1 25544U 98067A 22171.11255782 .00008307 00000+0 15444-3 0 9992", + "2 25544 51.6448 322.0970 0003980 282.3738 231.6559 15.49798078345636", +] + + +class TwoLineElementsInputTestCase(unittest.TestCase): + def test_tle_orbit_resolves_to_general_perturbations_orbit(self): + satellite = SatelliteInput.model_validate( + { + "name": "Test", + "orbit": {"type": "tle", "tle": TLE}, + "instruments": [{"name": "Test"}], + } + ) + resolved = to_tatc_satellite(satellite) + self.assertIsInstance(resolved, Satellite) + self.assertIsInstance(resolved.orbit, GeneralPerturbationsOrbit) + + def test_generate_members_treats_a_satellite_as_its_own_sole_member(self): + satellite = SatelliteInput.model_validate( + { + "name": "Test", + "orbit": {"type": "tle", "tle": TLE}, + "instruments": [{"name": "Test"}], + } + ) + members = generate_members(satellite) + self.assertEqual(len(members), 1) + self.assertIsInstance(members[0], Satellite) + self.assertIsInstance(members[0].orbit, GeneralPerturbationsOrbit) + + def test_native_orbit_passes_through_unchanged(self): + satellite = SatelliteInput.model_validate( + { + "name": "Test", + "orbit": CircularOrbit(mean_altitude=500e3), + "instruments": [Instrument(name="Test")], + } + ) + resolved = to_tatc_satellite(satellite) + self.assertIsInstance(resolved.orbit, CircularOrbit) + + def test_native_satellite_instance_validates_directly(self): + # mirrors how requests are constructed from native tatc objects + # elsewhere in the test suite, not only from JSON payloads + orbit = GeneralPerturbationsOrbit.from_tle(TLE) + satellite = Satellite( + name="Test", orbit=orbit, instruments=[Instrument(name="Test")] + ) + parsed = SatelliteInput.model_validate(satellite) + self.assertIsInstance(parsed.orbit, GeneralPerturbationsOrbit) + + def test_malformed_tle_is_rejected(self): + with self.assertRaises(ValidationError): + SatelliteInput.model_validate( + { + "name": "Test", + "orbit": {"type": "tle", "tle": ["not", "a tle"]}, + "instruments": [{"name": "Test"}], + } + ) From 3e630e52e43afaa541dfff9820acd7d68617e992 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Wed, 19 Aug 2026 23:15:56 -0700 Subject: [PATCH 05/16] align frontend with updated orbit schemas --- src/static/design.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/static/design.js b/src/static/design.js index 118dccc..67240cd 100644 --- a/src/static/design.js +++ b/src/static/design.js @@ -1,3 +1,8 @@ +// mean Earth radius (meters), matching tatc.constants.EARTH_MEAN_RADIUS; +// used to convert a user-facing altitude into a Keplerian orbit's +// semimajor_axis (semimajor_axis = EARTH_MEAN_RADIUS + altitude) +const EARTH_MEAN_RADIUS = 6371008.771415059; + $(document).ready(function() { // bind event handler to change observer frame $("#display-observer").change(function() { @@ -42,7 +47,7 @@ $(document).ready(function() { return { type: "circular", epoch: $("#orbit-circular-epoch").datetimepicker('viewDate').toISOString(), - altitude: $("#orbit-circular-altitude").val()*1000, + mean_altitude: $("#orbit-circular-altitude").val()*1000, inclination: $("#orbit-circular-inclination").val(), right_ascension_ascending_node: $("#orbit-circular-raan").val(), true_anomaly: $("#orbit-circular-ta").val() @@ -53,14 +58,14 @@ $(document).ready(function() { epoch: $("#orbit-sso-epoch").datetimepicker('viewDate').toISOString(), equator_crossing_time: $("#orbit-sso-ect").datetimepicker('viewDate').format("HH:mm"), equator_crossing_ascending: $("#orbit-sso-direction").val()=="asc", - altitude: $("#orbit-sso-altitude").val()*1000, + mean_altitude: $("#orbit-sso-altitude").val()*1000, true_anomaly: $("#orbit-sso-ta").val() } } else if($("#satellite-orbit").val()=="keplerian") { return { type: "keplerian", epoch: $("#orbit-keplerian-epoch").datetimepicker('viewDate').toISOString(), - altitude: $("#orbit-keplerian-altitude").val()*1000, + semimajor_axis: $("#orbit-keplerian-altitude").val()*1000 + EARTH_MEAN_RADIUS, inclination: $("#orbit-keplerian-inclination").val(), eccentricity: $("#orbit-keplerian-eccentricity").val(), perigee_argument: $("#orbit-keplerian-pa").val(), @@ -137,7 +142,7 @@ $(document).ready(function() { var listener = $("#orbit-circular-epoch").off("change.datetimepicker"); $("#orbit-circular-epoch").datetimepicker('date', satellite.orbit.epoch); $("#orbit-circular-epoch").on("change.datetimepicker", listener); - $("#orbit-circular-altitude").val(satellite.orbit.altitude/1000); + $("#orbit-circular-altitude").val(satellite.orbit.mean_altitude/1000); $("#orbit-circular-inclination").val(satellite.orbit.inclination); $("#orbit-circular-raan").val(satellite.orbit.right_ascension_ascending_node); $("#orbit-circular-ta").val(satellite.orbit.true_anomaly); @@ -147,13 +152,13 @@ $(document).ready(function() { $("#orbit-sso-epoch").on("change.datetimepicker", listener); $("#orbit-sso-ect").datetimepicker('date', satellite.orbit.equator_crossing_time); $("#orbit-sso-direction").val(satellite.orbit.equator_crossing_ascending?"asc":"desc"); - $("#orbit-sso-altitude").val(satellite.orbit.altitude/1000); + $("#orbit-sso-altitude").val(satellite.orbit.mean_altitude/1000); $("#orbit-sso-ta").val(satellite.orbit.true_anomaly); } else if(satellite.orbit.type == "keplerian") { var listener = $("#orbit-keplerian-epoch").off("change.datetimepicker"); $("#orbit-keplerian-epoch").datetimepicker('date', satellite.orbit.epoch); $("#orbit-keplerian-epoch").on("change.datetimepicker", listener); - $("#orbit-keplerian-altitude").val(satellite.orbit.altitude/1000); + $("#orbit-keplerian-altitude").val((satellite.orbit.semimajor_axis - EARTH_MEAN_RADIUS)/1000); $("#orbit-keplerian-inclination").val(satellite.orbit.inclination); $("#orbit-keplerian-eccentricity").val(satellite.orbit.eccentricity); $("#orbit-keplerian-pa").val(satellite.orbit.perigee_argument); @@ -419,7 +424,7 @@ $(document).ready(function() { name: "New Satellite", orbit: { type: "circular", - altitude: 400000, + mean_altitude: 400000, inclination: 0, true_anomaly: 0, right_ascension_ascending_node: 0, @@ -688,7 +693,7 @@ $(document).ready(function() { }); $(".orbit-circular-group").change(function() { var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.altitude = +$("#orbit-circular-altitude").val()*1000; + satellite.orbit.mean_altitude = +$("#orbit-circular-altitude").val()*1000; satellite.orbit.inclination = +$("#orbit-circular-inclination").val(); satellite.orbit.right_ascension_ascending_node = +$("#orbit-circular-raan").val(); satellite.orbit.true_anomaly = +$("#orbit-circular-ta").val(); @@ -707,7 +712,7 @@ $(document).ready(function() { $(".orbit-sso-group").change(function() { var satellite = $("#satellites option:selected").data("satellite"); satellite.orbit.equator_crossing_ascending = $("#orbit-sso-direction").val()=="asc"; - satellite.orbit.altitude = +$("#orbit-sso-altitude").val()*1000; + satellite.orbit.mean_altitude = +$("#orbit-sso-altitude").val()*1000; satellite.orbit.true_anomaly = +$("#orbit-sso-ta").val(); $("#orbit-data").prop("disabled", true); }); @@ -718,7 +723,7 @@ $(document).ready(function() { }); $(".orbit-keplerian-group").change(function() { var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.altitude = +$("#orbit-keplerian-altitude").val()*1000; + satellite.orbit.semimajor_axis = +$("#orbit-keplerian-altitude").val()*1000 + EARTH_MEAN_RADIUS; satellite.orbit.inclination = +$("#orbit-keplerian-inclination").val(); satellite.orbit.eccentricity = +$("#orbit-keplerian-eccentricity").val(); satellite.orbit.perigee_argument = +$("#orbit-keplerian-pa").val(); From ba3f374aaf9570e3e0b0d83e715dbbfc552a0ad6 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 21 Aug 2026 07:18:51 -0700 Subject: [PATCH 06/16] add error handling when celery task fails --- src/tatc_app/coverage/router.py | 15 ++++++++++++++- src/tatc_app/latency/router.py | 15 ++++++++++++++- src/tatc_app/overflight/router.py | 15 +++++++++++++-- src/tatc_app/tracking/router.py | 25 +++++++++++++++++++++++-- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/tatc_app/coverage/router.py b/src/tatc_app/coverage/router.py index 64a0959..a910799 100644 --- a/src/tatc_app/coverage/router.py +++ b/src/tatc_app/coverage/router.py @@ -4,6 +4,7 @@ @author: Paul T. Grogan """ +import logging from uuid import UUID from celery import chain, group @@ -18,6 +19,8 @@ from .schemas import CoverageAnalysisRequest, CoverageAnalysisResult from .tasks import grid_coverage_analysis_task, run_coverage_analysis_task +logger = logging.getLogger(__name__) + router = APIRouter() @@ -83,4 +86,14 @@ async def retrieve_coverage_analysis(task_id: UUID): raise HTTPException(status_code=404, detail="Task not found.") if not task.ready(): raise HTTPException(status_code=409, detail="Results not ready.") - return CoverageAnalysisResult.model_validate_json(task.get()) + try: + result = task.get() + except Exception as exc: + logger.error( + "Coverage analysis task %s failed: %s\n%s", + task_id, + exc, + task.traceback, + ) + raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc + return CoverageAnalysisResult.model_validate_json(result) diff --git a/src/tatc_app/latency/router.py b/src/tatc_app/latency/router.py index 52a981e..e0d0f66 100644 --- a/src/tatc_app/latency/router.py +++ b/src/tatc_app/latency/router.py @@ -4,6 +4,7 @@ @author: Paul T. Grogan """ +import logging from uuid import UUID from celery import chain, group @@ -22,6 +23,8 @@ run_latency_analysis_task, ) +logger = logging.getLogger(__name__) + router = APIRouter() @@ -98,4 +101,14 @@ async def retrieve_latency_analysis(task_id: UUID): raise HTTPException(status_code=404, detail="Task not found.") if not task.ready(): raise HTTPException(status_code=409, detail="Results not ready.") - return LatencyAnalysisResult.model_validate_json(task.get()) + try: + result = task.get() + except Exception as exc: + logger.error( + "Latency analysis task %s failed: %s\n%s", + task_id, + exc, + task.traceback, + ) + raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc + return LatencyAnalysisResult.model_validate_json(result) diff --git a/src/tatc_app/overflight/router.py b/src/tatc_app/overflight/router.py index 3ff2588..63dad5e 100644 --- a/src/tatc_app/overflight/router.py +++ b/src/tatc_app/overflight/router.py @@ -4,7 +4,7 @@ @author: Paul T. Grogan """ - +import logging from uuid import UUID from celery import chain, group @@ -20,6 +20,8 @@ from .schemas import OverflightAnalysisRequest from .tasks import aggregate_observations_task, collect_observations_task +logger = logging.getLogger(__name__) + router = APIRouter() @@ -84,5 +86,14 @@ async def retrieve_overflight_anlaysis(task_id: UUID): raise HTTPException(status_code=404, detail="Task not found.") if not task.ready(): raise HTTPException(status_code=409, detail="Results not ready.") - results = task.get() + try: + results = task.get() + except Exception as exc: + logger.error( + "Overflight analysis task %s failed: %s\n%s", + task_id, + exc, + task.traceback, + ) + raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return FeatureCollection.model_validate_json(results) diff --git a/src/tatc_app/tracking/router.py b/src/tatc_app/tracking/router.py index 86522e8..142b0ec 100644 --- a/src/tatc_app/tracking/router.py +++ b/src/tatc_app/tracking/router.py @@ -4,6 +4,7 @@ @author: Paul T. Grogan """ +import logging from datetime import timezone from uuid import UUID @@ -22,6 +23,8 @@ from .schemas import GroundTrackAnalysisRequest, OrbitTrackAnalysisRequest from .tasks import collect_ground_track_task, collect_orbit_track_task +logger = logging.getLogger(__name__) + router = APIRouter() @@ -92,7 +95,16 @@ async def retrieve_orbit_track_analysis(task_id: UUID): raise HTTPException(status_code=404, detail="Task not found.") if not task.ready(): raise HTTPException(status_code=409, detail="Results not ready.") - results = task.get() + try: + results = task.get() + except Exception as exc: + logger.error( + "Orbit track analysis task %s failed: %s\n%s", + task_id, + exc, + task.traceback, + ) + raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return FeatureCollection.model_validate_json(results) @@ -163,5 +175,14 @@ async def retrieve_ground_track_progress(task_id: UUID): raise HTTPException(status_code=404, detail="Task not found.") if not task.ready(): raise HTTPException(status_code=409, detail="Results not ready.") - results = task.get() + try: + results = task.get() + except Exception as exc: + logger.error( + "Ground track analysis task %s failed: %s\n%s", + task_id, + exc, + task.traceback, + ) + raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return FeatureCollection.model_validate_json(results) From 42c5ce31b0e56a72ebf15473eae9ceb1dad00bc6 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 21 Aug 2026 07:41:25 -0700 Subject: [PATCH 07/16] add more logging of subtasks in chord --- src/tatc_app/celery/utils.py | 47 +++++++++++++++++++++++++++++++ src/tatc_app/coverage/router.py | 8 ++---- src/tatc_app/latency/router.py | 8 ++---- src/tatc_app/overflight/router.py | 8 ++---- src/tatc_app/tracking/router.py | 15 ++-------- 5 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 src/tatc_app/celery/utils.py diff --git a/src/tatc_app/celery/utils.py b/src/tatc_app/celery/utils.py new file mode 100644 index 0000000..67df676 --- /dev/null +++ b/src/tatc_app/celery/utils.py @@ -0,0 +1,47 @@ +""" +Shared utilities for debugging failed Celery tasks. + +@author: Paul T. Grogan +""" + +import logging + +from celery.result import AsyncResult, GroupResult + + +def log_task_failure( + logger: logging.Logger, label: str, task_id: str, task: AsyncResult +) -> None: + """ + Logs debug information about a failed Celery task. + + A chain whose `group` step fails typically surfaces only a generic, + detail-free `ChordError` on the chain's own result, since the + original member's exception is not always reconstructable once it + has been serialized through the result backend (e.g. a + `pydantic_core.ValidationError`, which loses its structured error + list entirely). Each group member still has its own stored + traceback, unaffected by that join failure, so it is logged + separately here to recover the real error. + + Args: + logger (logging.Logger): Logger to write to. + label (str): Human-readable task label (e.g. "Orbit track analysis"). + task_id (str): Unique task identifier, for correlating log lines. + task (AsyncResult): The failed task result. + """ + logger.error( + "%s task %s failed: %s\n%s", label, task_id, task.result, task.traceback + ) + parent = getattr(task, "parent", None) + if isinstance(parent, GroupResult): + for child in parent.results: + if child.failed(): + logger.error( + "%s task %s: group member %s failed: %s\n%s", + label, + task_id, + child.id, + child.result, + child.traceback, + ) diff --git a/src/tatc_app/coverage/router.py b/src/tatc_app/coverage/router.py index a910799..8dfc943 100644 --- a/src/tatc_app/coverage/router.py +++ b/src/tatc_app/coverage/router.py @@ -12,6 +12,7 @@ from fastapi import APIRouter, HTTPException from ..celery.schemas import CeleryTask +from ..celery.utils import log_task_failure from ..generation.utils import generate_cells, generate_points from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task @@ -89,11 +90,6 @@ async def retrieve_coverage_analysis(task_id: UUID): try: result = task.get() except Exception as exc: - logger.error( - "Coverage analysis task %s failed: %s\n%s", - task_id, - exc, - task.traceback, - ) + log_task_failure(logger, "Coverage analysis", str(task_id), task) raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return CoverageAnalysisResult.model_validate_json(result) diff --git a/src/tatc_app/latency/router.py b/src/tatc_app/latency/router.py index e0d0f66..4926e24 100644 --- a/src/tatc_app/latency/router.py +++ b/src/tatc_app/latency/router.py @@ -12,6 +12,7 @@ from fastapi import APIRouter, HTTPException from ..celery.schemas import CeleryTask +from ..celery.utils import log_task_failure from ..generation.utils import generate_cells, generate_points from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task @@ -104,11 +105,6 @@ async def retrieve_latency_analysis(task_id: UUID): try: result = task.get() except Exception as exc: - logger.error( - "Latency analysis task %s failed: %s\n%s", - task_id, - exc, - task.traceback, - ) + log_task_failure(logger, "Latency analysis", str(task_id), task) raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return LatencyAnalysisResult.model_validate_json(result) diff --git a/src/tatc_app/overflight/router.py b/src/tatc_app/overflight/router.py index 63dad5e..6dcc04c 100644 --- a/src/tatc_app/overflight/router.py +++ b/src/tatc_app/overflight/router.py @@ -13,6 +13,7 @@ from geojson_pydantic import FeatureCollection from ..celery.schemas import CeleryTask +from ..celery.utils import log_task_failure from ..generation.utils import generate_points from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task @@ -89,11 +90,6 @@ async def retrieve_overflight_anlaysis(task_id: UUID): try: results = task.get() except Exception as exc: - logger.error( - "Overflight analysis task %s failed: %s\n%s", - task_id, - exc, - task.traceback, - ) + log_task_failure(logger, "Overflight analysis", str(task_id), task) raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return FeatureCollection.model_validate_json(results) diff --git a/src/tatc_app/tracking/router.py b/src/tatc_app/tracking/router.py index 142b0ec..add9df4 100644 --- a/src/tatc_app/tracking/router.py +++ b/src/tatc_app/tracking/router.py @@ -16,6 +16,7 @@ from geojson_pydantic import FeatureCollection from ..celery.schemas import CeleryTask +from ..celery.utils import log_task_failure from ..generation.schemas import TimeGenerator from ..satellites import generate_members from ..utils.tasks import merge_feature_collections_task @@ -98,12 +99,7 @@ async def retrieve_orbit_track_analysis(task_id: UUID): try: results = task.get() except Exception as exc: - logger.error( - "Orbit track analysis task %s failed: %s\n%s", - task_id, - exc, - task.traceback, - ) + log_task_failure(logger, "Orbit track analysis", str(task_id), task) raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return FeatureCollection.model_validate_json(results) @@ -178,11 +174,6 @@ async def retrieve_ground_track_progress(task_id: UUID): try: results = task.get() except Exception as exc: - logger.error( - "Ground track analysis task %s failed: %s\n%s", - task_id, - exc, - task.traceback, - ) + log_task_failure(logger, "Ground track analysis", str(task_id), task) raise HTTPException(status_code=500, detail=f"Task failed: {exc}") from exc return FeatureCollection.model_validate_json(results) From c7438cf7b799c96bef3ac30183f3a1c7fe14fabc Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 21 Aug 2026 12:28:23 -0700 Subject: [PATCH 08/16] bump to version 3.11 --- Dockerfile | 2 +- pyproject.toml | 2 +- readthedocs.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5cecf95..b64394e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # This block defines the TAT-C runtime container using the appropriate # base Python environment. -FROM python:3.10 AS tatc_runtime +FROM python:3.11 AS tatc_runtime WORKDIR /var/tatc-app COPY pyproject.toml pyproject.toml diff --git a/pyproject.toml b/pyproject.toml index 3202861..2d28556 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ authors = [ {name = "Paul T. Grogan", email = "paul.grogan@asu.edu"} ] readme = "README.md" -requires-python = ">=3.9, <3.11" +requires-python = ">=3.11" license = {text = "BSD License"} classifiers = [ "Programming Language :: Python :: 3", diff --git a/readthedocs.yml b/readthedocs.yml index 1794586..cb42aa9 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -9,7 +9,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.10" + python: "3.11" # Build documentation in the docs/ directory with Sphinx sphinx: From 7400c904d49231cb72656df7feacfe9f11602dd3 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 21 Aug 2026 20:43:00 -0700 Subject: [PATCH 09/16] update ca certs --- Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Dockerfile b/Dockerfile index b64394e..b35f4b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,11 @@ FROM python:3.11 AS tatc_runtime +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && update-ca-certificates \ + && rm -rf /var/lib/apt/lists/* + WORKDIR /var/tatc-app COPY pyproject.toml pyproject.toml COPY src src From b40c5f656bf9769b4decc8655f063cbb7869eb27 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 21 Aug 2026 21:10:55 -0700 Subject: [PATCH 10/16] update worker ssl config --- src/tatc_app/worker.py | 61 +++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/src/tatc_app/worker.py b/src/tatc_app/worker.py index 10fb6c0..ecef46c 100644 --- a/src/tatc_app/worker.py +++ b/src/tatc_app/worker.py @@ -15,37 +15,49 @@ # parse the broker connection broker_string = os.getenv("TATC_BROKER", "amqp://localhost:5672//") -if "amqps://" in broker_string: - broker_ssl_option = os.getenv("TATC_BROKER_SSL_CERT_REQS", "NONE") +if broker_string.startswith("amqps://"): + broker_ssl_option = os.getenv( + "TATC_BROKER_SSL_CERT_REQS", + "REQUIRED", + ).upper() broker_ssl_config = { - "keyfile": os.getenv("TATC_BROKER_SSL_KEYFILE", None), - "certfile": os.getenv("TATC_BROKER_SSL_CERTFILE", None), - "ca_certs": os.getenv("TATC_BROKER_SSL_CA_CERTS", None), - "cert_reqs": ( - ssl.CERT_REQUIRED - if broker_ssl_option == "REQUIRED" - else ssl.CERT_OPTIONAL if broker_ssl_option == "OPTIONAL" else ssl.CERT_NONE - ), + "server_hostname": None, + "cert_reqs": { + "REQUIRED": ssl.CERT_REQUIRED, + "OPTIONAL": ssl.CERT_OPTIONAL, + "NONE": ssl.CERT_NONE, + }[broker_ssl_option], } + # Optional custom CA/client certificates + if value := os.getenv("TATC_BROKER_SSL_KEYFILE"): + broker_ssl_config["keyfile"] = value + if value := os.getenv("TATC_BROKER_SSL_CERTFILE"): + broker_ssl_config["certfile"] = value + if value := os.getenv("TATC_BROKER_SSL_CA_CERTS"): + broker_ssl_config["ca_certs"] = value else: broker_ssl_config = False # parse the backend connection backend_string = os.getenv("TATC_BACKEND", "redis://localhost:6379/") -if "rediss://" in backend_string: - backend_ssl_option = os.getenv("TATC_BACKEND_SSL_CERT_REQS", "NONE") +if backend_string.startswith("rediss://"): + backend_ssl_option = os.getenv( + "TATC_BACKEND_SSL_CERT_REQS", + "REQUIRED", + ).upper() backend_ssl_config = { - "ssl_keyfile": os.getenv("TATC_BACKEND_SSL_KEYFILE", None), - "ssl_certfile": os.getenv("TATC_BACKEND_SSL_CERTFILE", None), - "ssl_ca_certs": os.getenv("TATC_BACKEND_SSL_CA_CERTS", None), - "ssl_cert_reqs": ( - ssl.CERT_REQUIRED - if backend_ssl_option == "REQUIRED" - else ( - ssl.CERT_OPTIONAL if backend_ssl_option == "OPTIONAL" else ssl.CERT_NONE - ) - ), + "ssl_cert_reqs": { + "REQUIRED": ssl.CERT_REQUIRED, + "OPTIONAL": ssl.CERT_OPTIONAL, + "NONE": ssl.CERT_NONE, + }[backend_ssl_option], } + if value := os.getenv("TATC_BACKEND_SSL_KEYFILE"): + backend_ssl_config["ssl_keyfile"] = value + if value := os.getenv("TATC_BACKEND_SSL_CERTFILE"): + backend_ssl_config["ssl_certfile"] = value + if value := os.getenv("TATC_BACKEND_SSL_CA_CERTS"): + backend_ssl_config["ssl_ca_certs"] = value else: backend_ssl_config = False @@ -67,3 +79,8 @@ ) app.config_from_object("tatc_app.celeryconfig") + +app.conf.update( + broker_use_ssl=broker_ssl_config, + redis_backend_use_ssl=backend_ssl_config, +) From 326dfabc7be601ca3a65e86c92aaad6384e0debc Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Fri, 4 Sep 2026 16:04:18 +0000 Subject: [PATCH 11/16] split dev and prod compose files --- docker-compose.yml => compose.dev.yml | 0 compose.server.yml | 116 ++++++++++++++++++++++++++ compose.worker.yml | 11 +++ rabbitmq.conf | 15 ++++ 4 files changed, 142 insertions(+) rename docker-compose.yml => compose.dev.yml (100%) create mode 100644 compose.server.yml create mode 100644 compose.worker.yml create mode 100644 rabbitmq.conf diff --git a/docker-compose.yml b/compose.dev.yml similarity index 100% rename from docker-compose.yml rename to compose.dev.yml diff --git a/compose.server.yml b/compose.server.yml new file mode 100644 index 0000000..3b57e14 --- /dev/null +++ b/compose.server.yml @@ -0,0 +1,116 @@ +services: + traefik: + image: traefik:v3 + container_name: tatc-reverse-proxy + ports: + - "80:80" + - "443:443" + - "5671:5671" + - "6380:6380" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - letsencrypt:/letsencrypt + command: + - --log.level=INFO + - --providers.docker=true + - --providers.docker.exposedByDefault=false + - --entrypoints.web.address=:80 + - --entrypoints.web.http.redirections.entrypoint.to=websecure + - --entryPoints.web.http.redirections.entrypoint.scheme=https + - --entrypoints.websecure.address=:443 + - --entrypoints.amqps.address=:5671 + - --entrypoints.rediss.address=:6380 + - --entrypoints.websecure.asDefault=true + - --entrypoints.websecure.http.tls.certresolver=le + - --certificatesresolvers.le.acme.tlschallenge=true + # - --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory + - --certificatesresolvers.le.acme.email=${ACME_EMAIL} + - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json + labels: + - traefik.enable=false + server: + build: + context: . + target: tatc_server + container_name: tatc-server + restart: unless-stopped + environment: + TATC_BROKER: amqp://${BROKER_USER}:${BROKER_PASSWORD}@broker:5672// + TATC_BACKEND: redis://${BACKEND_USER}:${BACKEND_PASSWORD}@backend:6379/ + TATC_LOGIN_LIFETIME_SECONDS: 7200 + TATC_SECRET: ${TATC_SECRET} + TATC_ADMIN_EMAIL: ${TATC_ADMIN_EMAIL} + TATC_ADMIN_PASSWORD: ${TATC_ADMIN_PASSWORD} + TATC_CESIUM_TOKEN: ${TATC_CESIUM_TOKEN} + expose: + - "8000" + labels: + - traefik.enable=true + - traefik.http.routers.server.rule=Host(`${TATC_DOMAIN}`) + - traefik.http.routers.server.entrypoints=websecure + - traefik.http.routers.server.tls=true + - traefik.http.routers.server.tls.certresolver=le + - traefik.http.services.server.loadbalancer.server.port=8000 + depends_on: + worker: + condition: service_started + worker: + build: + context: . + target: tatc_worker + container_name: tatc-worker + restart: unless-stopped + environment: + TATC_BROKER: amqp://${BROKER_USER}:${BROKER_PASSWORD}@broker:5672// + TATC_BACKEND: redis://${BACKEND_USER}:${BACKEND_PASSWORD}@backend:6379/ + depends_on: + broker: + condition: service_started + backend: + condition: service_started + broker: + image: rabbitmq:4 + container_name: tatc-broker + restart: unless-stopped + environment: + RABBITMQ_DEFAULT_USER: ${BROKER_USER} + RABBITMQ_DEFAULT_PASS: ${BROKER_PASSWORD} + volumes: + - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro + - rabbitmq-data:/var/lib/rabbitmq + expose: + - "5672" + labels: + - "traefik.enable=true" + - "traefik.tcp.routers.broker.rule=HostSNI(`${TATC_DOMAIN}`)" + - "traefik.tcp.routers.broker.entrypoints=amqps" + - "traefik.tcp.routers.broker.tls=true" + - "traefik.tcp.routers.broker.tls.certresolver=le" + - "traefik.tcp.services.broker.loadbalancer.server.port=5672" + backend: + image: redis:7 + container_name: tatc-backend + restart: unless-stopped + command: + - redis-server + - --aclfile + - /etc/redis/users.acl + volumes: + - ./redis.acl:/etc/redis/users.acl:ro + - redis-data:/data + expose: + - "6379" + labels: + - "traefik.enable=true" + - "traefik.tcp.routers.backend.rule=HostSNI(`${TATC_DOMAIN}`)" + - "traefik.tcp.routers.backend.entrypoints=rediss" + - "traefik.tcp.routers.backend.tls=true" + - "traefik.tcp.routers.backend.tls.certresolver=le" + - "traefik.tcp.services.backend.loadbalancer.server.port=6379" +volumes: + letsencrypt: + name: letsencrypt + rabbitmq-data: + name: tatc-rabbitmq-data + redis-data: + name: tatc-redis-data diff --git a/compose.worker.yml b/compose.worker.yml new file mode 100644 index 0000000..63317fc --- /dev/null +++ b/compose.worker.yml @@ -0,0 +1,11 @@ +services: + worker: + build: + context: . + target: tatc_worker + container_name: tatc-worker + restart: unless-stopped + environment: + TATC_BROKER: amqps://${BROKER_USER}:${BROKER_PASSWORD}@${TATC_DOMAIN}:5671// + TATC_BACKEND: rediss://${BACKEND_USER}:${BACKEND_PASSWORD}@${TATC_DOMAIN}:6380/ + diff --git a/rabbitmq.conf b/rabbitmq.conf new file mode 100644 index 0000000..21649f2 --- /dev/null +++ b/rabbitmq.conf @@ -0,0 +1,15 @@ +# rabbitmq.conf +# +# RabbitMQ is only accessible on the internal Docker network. +# TLS is terminated by Traefik, so RabbitMQ itself listens for +# ordinary AMQP on port 5672. + +listeners.tcp.default = 5672 + +# Keep the built-in guest account restricted to localhost. +# This is RabbitMQ's default, but making it explicit documents +# the desired security policy. +loopback_users.guest = true + +deprecated_features.permit.transient_nonexcl_queues = true +deprecated_features.permit.global_qos = true From b1361457d1ed0c4df168d13e7c108178a91fb2ba Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 4 Sep 2026 10:06:19 -0700 Subject: [PATCH 12/16] improve project documentation and build files --- Dockerfile | 26 +++++- README.md | 193 ++++++++++++++++++++++++++++++++++++--------- compose.dev.yml | 11 ++- compose.server.yml | 7 +- pyproject.toml | 2 +- redis.acl | 2 + 6 files changed, 195 insertions(+), 46 deletions(-) create mode 100644 redis.acl diff --git a/Dockerfile b/Dockerfile index b35f4b2..83070b8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # This block defines the TAT-C runtime container using the appropriate # base Python environment. -FROM python:3.11 AS tatc_runtime +FROM python:3.12-slim-bookworm AS tatc_runtime RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates \ @@ -9,9 +9,29 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* WORKDIR /var/tatc-app + +# Install dependencies first, in their own layer, so they stay cached +# across rebuilds that only change application source. pyproject.toml's +# dynamic version is read from tatc_app.__version__, so that one file has +# to be present for this install to resolve metadata; the rest of `src` +# (copied below) is not needed yet and is intentionally left out here. COPY pyproject.toml pyproject.toml +COPY src/tatc_app/__init__.py src/tatc_app/__init__.py +RUN python -m pip install --no-cache-dir . + +# Now install the application itself. Dependencies are already satisfied, +# so this only rebuilds and installs the local tatc-app package. COPY src src -RUN python -m pip install . +RUN python -m pip install --no-cache-dir . + +# Run as a dedicated non-root user. The data directory is created (and +# owned by that user) here so its ownership is propagated to the +# `tatc-data` volume the first time it is mounted over that path. +RUN groupadd --system tatc \ + && useradd --system --gid tatc --no-create-home --shell /usr/sbin/nologin tatc \ + && mkdir -p /var/tatc-app/data \ + && chown -R tatc:tatc /var/tatc-app +USER tatc # This block defines the TAT-C server container. Using the TAT-C runtime # container, it installs and starts the server application. @@ -34,4 +54,4 @@ WORKDIR /var/tatc-app ENV TATC_BROKER=amqp://guest:guest@broker:5672// ENV TATC_BACKEND=redis://backend:6379/ -CMD ["celery", "-A", "tatc_app.worker", "worker", "--uid=nobody", "--gid=nogroup"] +CMD ["celery", "-A", "tatc_app.worker", "worker"] diff --git a/README.md b/README.md index 618b829..a677060 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ The web application is configured to support the RabbitMQ Broker and Redis Backe ## Configuration +For the Manual Docker Containers and Python development methods (see +[Development](#development) below), the web application is configured with +environment variables, typically set in a `.env` file in the project root +directory. (The Docker Compose development method and the Deployment compose +files set these environment variables directly instead — see those sections +for details.) + ### Cesium Access Token and Assets The client-side Cesium geospatial visualization requires an access token @@ -24,63 +31,70 @@ from . After creating an account, you *must* add the Asset "Blue Marble Next Generation July, 2004" from the Asset Depot (ID 3845) to the account assets to enable visualization. -Paste the access token in a new file named `.env` (in the `app/` directory) -with the following format: +Set `TATC_CESIUM_TOKEN` in the `.env` file to the access token: ``` TATC_CESIUM_TOKEN=your alphanumeric access token here ``` -The `.env` file is read by the web application to connect to your account. - -### Broker and Backend Connection Strings - -Unless installing via the "Docker Compose" method below, identify the protocol, -credentials (if required), domain name/URL, and port number to connect the broker -and backend components in the `.env` file. - -The default values (below) assume the broker and backend run locally. -``` -TATC_BROKER = amqp://guest:guest@broker:5672// -TATC_BACKEND = redis://backend:6379/ -``` -### Other Environment Variables +### Environment Variables -The web application references the following environment variables, typically loaded from a `.env` file. +The web application references the following environment variables. Unless +installing via the "Docker Compose" method, you must set `TATC_BROKER` and +`TATC_BACKEND` to identify the protocol, credentials (if required), domain +name/URL, and port number of the broker and backend components. - * `TATC_BROKER`: broker connection string (default: `amqps://guest:guest@broker:5671//`) - * `TATC_BACKEND`: backend connection string (default: `redis://backend:6379/`) + * `TATC_BROKER`: broker connection string (default: `amqp://guest:guest@broker:5672//`, assuming a local broker) + * `TATC_BACKEND`: backend connection string (default: `redis://backend:6379/`, assuming a local backend) + * `TATC_DATABASE_URL`: server user-account database connection string (default: `sqlite+aiosqlite:///data.db`, + a SQLite file in the working directory); the Docker Compose methods below override this to store the + file in the `tatc-data` volume so accounts persist across container restarts * `TATC_LOGIN_LIFETIME_SECONDS`: time until reauthentication required (default: `7200` seconds) * `TATC_SECRET`: cryptographic security secret phrase (default: `change me`) * `TATC_ADMIN_EMAIL`: administrator account email (default: `admin@example.com`) * `TATC_ADMIN_PASSWORD`: administrator account password (default: `admin`) * `TATC_CESIUM_TOKEN`: Cesium access token -## Installation and Usage +## Development + +This section covers running TAT-C locally from source, for development and +testing. For running a publicly-accessible instance, see +[Deployment](#deployment) below instead. Due to the architectural complexity and dependencies for the parallel task-queuing system (Celery), we strongly recommended using Docker containers -to install and run TAT-C. +to install and run TAT-C, either via Docker Compose (recommended) or manually +built containers. A pure-Python setup is also available for tighter +edit/reload cycles on the server or worker code. -### Method 1: Docker Compose (Recommended) +### Docker Compose (Recommended) Docker Compose can build and operate all four application components (server, worker, broker, and backend) locally from one command. It is suitable for individual workstation use because it does not rely on network access between components. +The `compose.dev.yml` file is intended for **local development only**: it +runs the broker and backend without authentication or TLS and exposes their +ports directly on the host. Do not use it to deploy a publicly-accessible +instance; see [Deployment](#deployment) below for that. + From the project root directory (`/`), build and run the Docker compose file which provides the server, worker, broker, and backend components: ```shell -docker-compose up +docker compose -f compose.dev.yml up ``` -By default, the client-side GUI is available at . +By default, the client-side GUI is available at . The +server's user-account database is stored in the `tatc-data` Docker volume, so +accounts persist across `docker compose down` / `up` (though not the broker's +or backend's in-flight data, which are not persisted in this file — see +[Environment Variables](#environment-variables) above and +[Deployment](#deployment) below for the persisted production equivalents). +### Manual Docker Containers -### Method 2: Docker Containers - -Docker containers allow the four components (server, worker, broker, and backend) -to run across multiple hosts. Individual containers can be combined with other -services such as reverse proxies to secure connections over the Internet. +Individual Docker containers can be built and run without Compose, for +example to test a single component in isolation or to run components across +multiple hosts by hand. The broker and backend services can use the third-party Docker images [rabbitmq](https://hub.docker.com/_/rabbitmq) and @@ -111,14 +125,15 @@ docker run -it --env-file=.env tatc_worker ``` The worker will connect to the broker and wait for new tasks to process. -### Method 3: Python +### Python -To use Pythond directly for the server and worker, the broker and backend -components must be running already running (e.g., see Docker Container). +To use Python directly for the server and worker, the broker and backend +components must already be running (e.g., see Manual Docker Containers above). Specify the connection strings for both in the `.env` file as described above. -Next, install the additional web application dependencies by installing tatc -with the optional `app` dependency flag from the [TAT-C repository](https://github.com/code-lab-org/tatc): +This requires Python 3.11 or later. Install the web application and its +dependencies, including [TAT-C](https://github.com/code-lab-org/tatc), from +the project root: ```shell pip install -e . ``` @@ -140,10 +155,6 @@ that Celery does not currently support concurrency on Windows. Try using the celery -A tatc_app.worker worker --loglevel=INFO --pool=solo ``` -## Development Tools - -Development tools are applicable when working with the source code. - ### Documentation Generate documentation from the `docs` directory using the command: @@ -151,13 +162,117 @@ Generate documentation from the `docs` directory using the command: make html ``` +### Testing + +Install the `dev` optional dependencies and run the test suite from the +project root: +```shell +pip install -e ".[dev]" +pytest +``` + ### Code Style -This project uses the black code style, applied from the project root: +This project uses the black code style and isort import ordering, applied +from the project root: ```shell black . +isort . ``` +## Deployment + +Production deployments should use `compose.server.yml` and `compose.worker.yml` +instead of `compose.dev.yml`. Unlike the development file, these: + * terminate TLS at a [Traefik](https://traefik.io/traefik/) reverse proxy so the + GUI, broker, and backend are only reachable over HTTPS/AMQPS/TLS-Redis; + * require authenticated broker and backend connections (no `guest` account or + unauthenticated Redis access); and + * persist RabbitMQ, Redis, and the server's user-account database in named + Docker volumes across restarts. + +`compose.server.yml` runs the reverse proxy, server, worker, broker, and +backend on a single host and is suitable for most deployments. +`compose.worker.yml` runs an additional worker-only instance (for example, +on a separate machine) that connects to the broker and backend already +started by `compose.server.yml`. + +Before running `compose.server.yml`, point the `TATC_DOMAIN` DNS record at +the server host and ensure ports 80, 443, 5671, and 6380 are reachable from +the Internet — Traefik uses the TLS-ALPN-01 challenge on port 443 to issue +Let's Encrypt certificates, and certificate issuance will fail otherwise. + +Unlike `compose.dev.yml`, none of the environment variables below have +usable defaults — deployment will fail to start (or start insecurely) if +they are not set. Provide them via a `.env` file in the same directory as +the relevant compose file. + +### Server Deployment + +Run `docker compose -f compose.server.yml up` on the host that will serve +the GUI/API, broker, and backend. It requires: + + * `TATC_DOMAIN`: public domain name used to route and issue TLS certificates + for the GUI/API (HTTPS), broker (AMQPS), and backend (TLS Redis) + * `ACME_EMAIL`: contact email used when requesting Let's Encrypt TLS + certificates + * `BROKER_USER` / `BROKER_PASSWORD`: credentials for the RabbitMQ broker; + `compose.server.yml` creates this account via `RABBITMQ_DEFAULT_USER` / + `RABBITMQ_DEFAULT_PASS` and uses it to build the server's `TATC_BROKER` + connection string + * `BACKEND_USER` / `BACKEND_PASSWORD`: credentials for the Redis backend; + these must match an enabled user in `redis.acl` (see below) and are used + to build the server's `TATC_BACKEND` connection string + * `TATC_SECRET`: cryptographic secret used to sign session/authentication + tokens — set this to a long, random value + * `TATC_ADMIN_EMAIL` / `TATC_ADMIN_PASSWORD`: initial administrator account + credentials + * `TATC_CESIUM_TOKEN`: Cesium access token (see + [Cesium Access Token and Assets](#cesium-access-token-and-assets) above) + +The server's user-account database is stored in the `tatc-data` Docker +volume; `compose.server.yml` sets `TATC_DATABASE_URL` to place it there +automatically, so it persists across restarts without further configuration. + +A `redis.acl` file must also exist alongside `compose.server.yml` — see +[Redis ACL File](#redis-acl-file) below. + +### Worker Deployment + +Run `docker compose -f compose.worker.yml up` on each additional host that +should process tasks for a broker/backend already started by +`compose.server.yml`. It requires only the connection credentials — not +`TATC_SECRET`, `TATC_ADMIN_EMAIL`/`TATC_ADMIN_PASSWORD`, `TATC_CESIUM_TOKEN`, +or `ACME_EMAIL`, none of which the worker uses: + + * `TATC_DOMAIN`: same public domain name as the server deployment, used to + reach the broker (AMQPS) and backend (TLS Redis) through Traefik + * `BROKER_USER` / `BROKER_PASSWORD`: same broker credentials as the server + deployment + * `BACKEND_USER` / `BACKEND_PASSWORD`: same backend credentials as the + server deployment + +### Redis ACL File + +The Redis backend in `compose.server.yml` is started with `--aclfile` pointing +at a `redis.acl` file (mounted read-only from the project root), so a +`redis.acl` file must exist alongside `compose.server.yml` before deployment. +This file must define a user whose name and password match `BACKEND_USER` +and `BACKEND_PASSWORD` above. A placeholder `redis.acl` is included as a +template: +``` +user default off +user username on >password ~* &* +@all -@admin -@dangerous +``` +Replace `username` and `password` with the actual `BACKEND_USER` and +`BACKEND_PASSWORD` values before deploying. Treat `redis.acl` as a secret +once populated with real credentials — avoid committing a version containing +production passwords to version control. + +## License + +This project is distributed under the [BSD 3-Clause License](LICENSE). + ## Contact Paul T. Grogan diff --git a/compose.dev.yml b/compose.dev.yml index 075fc28..847f464 100644 --- a/compose.dev.yml +++ b/compose.dev.yml @@ -13,6 +13,9 @@ services: TATC_BROKER: amqp://guest:guest@broker:5672// TATC_BACKEND: redis://backend:6379/ TATC_CESIUM_TOKEN: ${TATC_CESIUM_TOKEN} + TATC_DATABASE_URL: sqlite+aiosqlite:///data/data.db + volumes: + - tatc-data:/var/tatc-app/data worker: build: context: . @@ -25,9 +28,13 @@ services: TATC_BACKEND: redis://backend:6379/ broker: image: rabbitmq:3 - ports: + ports: - "5672:5672" + volumes: + - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro backend: image: redis:6 - ports: + ports: - "6379:6379" +volumes: + tatc-data: diff --git a/compose.server.yml b/compose.server.yml index 3b57e14..62753fd 100644 --- a/compose.server.yml +++ b/compose.server.yml @@ -42,7 +42,10 @@ services: TATC_ADMIN_EMAIL: ${TATC_ADMIN_EMAIL} TATC_ADMIN_PASSWORD: ${TATC_ADMIN_PASSWORD} TATC_CESIUM_TOKEN: ${TATC_CESIUM_TOKEN} - expose: + TATC_DATABASE_URL: sqlite+aiosqlite:///data/data.db + volumes: + - tatc-data:/var/tatc-app/data + expose: - "8000" labels: - traefik.enable=true @@ -114,3 +117,5 @@ volumes: name: tatc-rabbitmq-data redis-data: name: tatc-redis-data + tatc-data: + name: tatc-data diff --git a/pyproject.toml b/pyproject.toml index 2d28556..b71c5cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ "aiofiles", "aiohttp", "aiosqlite", - "celery[librabbitmq,redis]", + "celery[redis]", "fastapi >= 0.110.0", "fastapi-users[sqlalchemy]", "geojson-pydantic", diff --git a/redis.acl b/redis.acl new file mode 100644 index 0000000..e1492e7 --- /dev/null +++ b/redis.acl @@ -0,0 +1,2 @@ +user default off +user username on >password ~* &* +@all -@admin -@dangerous From ceffb00cf82b4aafb3370f3dc57fbcf17737f8f1 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 4 Sep 2026 10:33:01 -0700 Subject: [PATCH 13/16] refactor to split up large design.js file --- src/static/design.js | 853 ++++++++------------------------------- src/static/index.html | 2 + src/static/orbit.js | 173 ++++++++ src/static/satellites.js | 346 ++++++++++++++++ 4 files changed, 696 insertions(+), 678 deletions(-) create mode 100644 src/static/orbit.js create mode 100644 src/static/satellites.js diff --git a/src/static/design.js b/src/static/design.js index 67240cd..2664088 100644 --- a/src/static/design.js +++ b/src/static/design.js @@ -1,409 +1,201 @@ -// mean Earth radius (meters), matching tatc.constants.EARTH_MEAN_RADIUS; -// used to convert a user-facing altitude into a Keplerian orbit's -// semimajor_axis (semimajor_axis = EARTH_MEAN_RADIUS + altitude) -const EARTH_MEAN_RADIUS = 6371008.771415059; +// Design tab: orbit-track computation and Cesium visualization. -$(document).ready(function() { - // bind event handler to change observer frame - $("#display-observer").change(function() { - if($(this).val() == "inertial") { - viewer.scene.postUpdate.addEventListener(icrf); - } else { - viewer.scene.postUpdate.removeEventListener(icrf); - } - }); - - $('#display-start').datetimepicker({ - timeZone: "UTC", - defaultDate: moment.now(), - icons: { - time: 'far fa-clock' - } - }); - $("#display-duration").val(60); - $("#display-step").val(30); - - // function simulate an inertial frame - function icrf(scene, time) { - if (scene.mode !== Cesium.SceneMode.SCENE3D) { - return; - } - var icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time); - if (Cesium.defined(icrfToFixed)) { - var camera = viewer.camera; - var offset = Cesium.Cartesian3.clone(camera.position); - var transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed); - camera.lookAtTransform(transform, offset); - } +function icrf(scene, time) { + if (scene.mode !== Cesium.SceneMode.SCENE3D) { + return; } - - function getOrbit() { - if($("#satellite-orbit").val()=="tle") { - return { - type: "tle", - tle: $("#orbit-tle").val().split("\n") - } - } else if($("#satellite-orbit").val()=="circular") { - return { - type: "circular", - epoch: $("#orbit-circular-epoch").datetimepicker('viewDate').toISOString(), - mean_altitude: $("#orbit-circular-altitude").val()*1000, - inclination: $("#orbit-circular-inclination").val(), - right_ascension_ascending_node: $("#orbit-circular-raan").val(), - true_anomaly: $("#orbit-circular-ta").val() - } - } else if($("#satellite-orbit").val()=="sso") { - return { - type: "sso", - epoch: $("#orbit-sso-epoch").datetimepicker('viewDate').toISOString(), - equator_crossing_time: $("#orbit-sso-ect").datetimepicker('viewDate').format("HH:mm"), - equator_crossing_ascending: $("#orbit-sso-direction").val()=="asc", - mean_altitude: $("#orbit-sso-altitude").val()*1000, - true_anomaly: $("#orbit-sso-ta").val() - } - } else if($("#satellite-orbit").val()=="keplerian") { - return { - type: "keplerian", - epoch: $("#orbit-keplerian-epoch").datetimepicker('viewDate').toISOString(), - semimajor_axis: $("#orbit-keplerian-altitude").val()*1000 + EARTH_MEAN_RADIUS, - inclination: $("#orbit-keplerian-inclination").val(), - eccentricity: $("#orbit-keplerian-eccentricity").val(), - perigee_argument: $("#orbit-keplerian-pa").val(), - right_ascension_ascending_node: $("#orbit-keplerian-raan").val(), - true_anomaly: $("#orbit-keplerian-ta").val() - } - } + var icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time); + if (Cesium.defined(icrfToFixed)) { + var camera = viewer.camera; + var offset = Cesium.Cartesian3.clone(camera.position); + var transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed); + camera.lookAtTransform(transform, offset); } +} - function queryCelestrak() { - var query = $("#celestrak-name").val(); - if(query.length > 2) { - $("#celestrak-objects").val([]); - $("#celestrak-objects").change(); - $("#celestrak-tle").val(""); - $.ajax({ - url: "celestrak/tle?name=" + query, - type: "GET", - crossDomain: true, - success: function(response) { - var lines = response.split(/\r?\n/); - if(lines.length >= 3) { - $("#celestrak-objects").empty(); - for(var i = 0; i < lines.length - 2; i += 3) { - $("#celestrak-objects").append( - $('") - .data("instrument", instrument) - .text(instrument.name); - if(instrument===$("#satellites option:selected").data("instrument")) { - option.attr("selected", "selected"); - } - $("#instruments").append(option); - changeInstruments(); - }); - } else { - $(".satellite-group").hide(); } - } + ); +}; - function changeInstruments() { - const instrument = $("#instruments option:selected").data("instrument"); - $("#instrument-copy").prop("disabled", instrument?false:true); - $("#instrument-delete").prop("disabled", (instrument?false:true) || $("#instruments option").length <= 1); - if(instrument) { - $(".instrument-group").show(); - $("#instrument-name").val(instrument.name); - $("#instrument-field").val(instrument.field_of_regard); - $("#instrument-access").val(instrument.min_access_time); - $("#instrument-target-sunlit").val( - instrument.req_target_sunlit?"sunlit": - (instrument.req_target_sunlit===false?"eclipse":"none") - ); - $("#instrument-self-sunlit").val( - instrument.req_self_sunlit?"sunlit": - (instrument.req_self_sunlit===false?"eclipse":"none") - ); - $("#satellites option:selected").data("instrument", instrument); - } else { - $(".instrument-group").hide(); +// entity group holding the drawn orbit tracks; assigned once the Cesium +// viewer (from index.js) is ready, so processOrbitTrack/clearOrbitTrack +// (declared here at top level) can both reference it +var orbitTrack; +function processOrbitTrack(option) { + var start = $('#display-start').datetimepicker('viewDate').toISOString(); + var end = $('#display-start').datetimepicker('viewDate').clone().add($("#display-duration").val(), "minutes").toISOString(); + var satellites = {}; + _.forEach(option.data("features"), function(feature) { + var satellite = feature.properties.satellite; + if(!satellites.hasOwnProperty(satellite)) { + satellites[satellite] = { + position: new Cesium.SampledPositionProperty(), + radius: new Cesium.SampledProperty(Number), + visibility: new Cesium.SampledProperty(Cesium.Color) + }; + satellites[satellite].position.setInterpolationOptions({ + interpolationDegree: 2, + interpolationAlgorithm: Cesium.LagrangePolynomialApproximation + }); } + satellites[satellite].position.addSample( + Cesium.JulianDate.fromIso8601(feature.properties.time), + Cesium.Cartesian3.fromDegrees( + feature.geometry.coordinates[0], + feature.geometry.coordinates[1], + feature.geometry.coordinates[2] + ) + ); + satellites[satellite].radius.addSample( + Cesium.JulianDate.fromIso8601(feature.properties.time), + feature.properties.swath_width/2 + ); + satellites[satellite].visibility.addSample( + Cesium.JulianDate.fromIso8601(feature.properties.time), + Cesium.Color.fromCssColorString(option.data("color")).withAlpha(feature.properties.valid_obs*0.5) + ); + }); + for(var satellite in satellites) { + viewer.entities.add({ + parent: orbitTrack, + availability: new Cesium.TimeIntervalCollection([ + new Cesium.TimeInterval({ + start: Cesium.JulianDate.fromIso8601(start), + stop: Cesium.JulianDate.fromIso8601(end) + }) + ]), + position: satellites[satellite].position, + orientation: new Cesium.VelocityOrientationProperty(satellites[satellite].position), + point: { + pixelSize: 8, + color: Cesium.Color.fromCssColorString(option.data("color")) + }, + path: { + leadTime: $("#display-path").is(":checked") ? $("#display-duration").val()*60 : 0, + trailTime: $("#display-path").is(":checked") ? $("#display-duration").val()*60 : 0, + material: new Cesium.ColorMaterialProperty(Cesium.Color.fromCssColorString(option.data("color"))) + }, + ellipse: { + semiMajorAxis: satellites[satellite].radius, + semiMinorAxis: satellites[satellite].radius, + height: 0, + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, + material: new Cesium.ColorMaterialProperty(satellites[satellite].visibility), + outline: true, + outlineColor: Cesium.Color.BLACK + } + }); } + viewer.clock.startTime = Cesium.JulianDate.fromIso8601(start); + viewer.clock.currentTime = Cesium.JulianDate.fromIso8601(start); + viewer.clock.stopTime = Cesium.JulianDate.fromIso8601(end); + viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; + viewer.timeline.zoomTo( + Cesium.JulianDate.fromIso8601(start), + Cesium.JulianDate.fromIso8601(end) + ); +} +function clearOrbitTrack() { + clearEntities(orbitTrack); +} - $('#orbit-circular-epoch').datetimepicker({ - timeZone: "UTC", - defaultDate: moment.now(), - icons: { - time: 'far fa-clock' - } - }); - $('#orbit-sso-epoch').datetimepicker({ - timeZone: "UTC", - defaultDate: moment.now(), - icons: { - time: 'far fa-clock' +$(document).ready(function() { + orbitTrack = viewer.entities.add(new Cesium.Entity()); + + $("#display-observer").change(function() { + if($(this).val() == "inertial") { + viewer.scene.postUpdate.addEventListener(icrf); + } else { + viewer.scene.postUpdate.removeEventListener(icrf); } }); - $('#orbit-sso-ect').datetimepicker({ - timeZone: "UTC", - defaultDate: moment.now(), - format: 'LT' - }); - $('#orbit-keplerian-epoch').datetimepicker({ + + $('#display-start').datetimepicker({ timeZone: "UTC", defaultDate: moment.now(), icons: { time: 'far fa-clock' } }); - - function getSunlitState(value) { - if(value=="sunlit") { - return true; - } else if(value=="eclipse") { - return false; - } else { - return null; - } - } - - function collectOrbitTrack() { - clearOrbitTrack(); - $("#orbit-analyze").prop("disabled", true); - $("#orbit-analyze .spinner-border").show(); - $("#satellites > option").each(function() { - const option = $(this); - $.ajax({ - url: "/analyze/orbit-track", - type: "POST", - contentType: "application/json", - dataType: "json", - data: JSON.stringify({ - satellite: option.data("satellite"), - instrument: option.data("instrument"), - times: { - start: $('#display-start').datetimepicker('viewDate').toISOString(), - end: $('#display-start').datetimepicker('viewDate').clone().add( - $("#display-duration").val(), "minutes").toISOString(), - delta: parseInt($("#display-step").val()) - } - }), - success: function(response) { - checkOrbitTrack(response.task_id, option); - if(response.group_id) { - checkProgress(response.group_id, option); - } - } - }); - }); - }; - - function checkProgress(groupId, option) { - $.get( - "/tasks/"+groupId+"/progress", - function(progress) { - if(progress.task_count == progress.completed_count) { - $("#orbit-progress").hide(); - $("#orbit-progress .progress-bar").css('width', "0%"); - $("#orbit-progress .progress-bar").prop('aria-valuenow', 0); - } else { - $("#orbit-progress").show(); - var percent = Math.round(100*(progress.completed_count/progress.task_count)); - $("#orbit-progress .progress-bar").css('width', percent + "%"); - $("#orbit-progress .progress-bar").prop('aria-valuenow', percent); - setTimeout( - function() { - checkProgress(groupId); - }, 1000 - ); - } - } - ); - }; - function checkOrbitTrack(taskId, option) { - $.get( - "/tasks/"+taskId+"/status", - function(status) { - if(status.ready) { - $.get( - "/analyze/orbit-track/"+taskId, - function(results) { - option.data("features", results.features); - $("#orbit-analyze .spinner-border").hide(); - $("#orbit-analyze").prop("disabled", false); - $("#orbit-data").prop("disabled", false); - $("#orbit-data-json").prop("disabled", false); - $("#orbit-data-csv").prop("disabled", false); - processOrbitTrack(option); - } - ); - } else { - setTimeout( - function() { - checkOrbitTrack(taskId, option); - }, 1000 - ); - } - } - ); - }; - - var orbitTrack = viewer.entities.add(new Cesium.Entity()); - function processOrbitTrack(option) { - var start = $('#display-start').datetimepicker('viewDate').toISOString(); - var end = $('#display-start').datetimepicker('viewDate').clone().add($("#display-duration").val(), "minutes").toISOString(); - var satellites = {}; - _.forEach(option.data("features"), function(feature) { - var satellite = feature.properties.satellite; - if(!satellites.hasOwnProperty(satellite)) { - satellites[satellite] = { - position: new Cesium.SampledPositionProperty(), - radius: new Cesium.SampledProperty(Number), - visibility: new Cesium.SampledProperty(Cesium.Color) - }; - satellites[satellite].position.setInterpolationOptions({ - interpolationDegree: 2, - interpolationAlgorithm: Cesium.LagrangePolynomialApproximation - }); - } - satellites[satellite].position.addSample( - Cesium.JulianDate.fromIso8601(feature.properties.time), - Cesium.Cartesian3.fromDegrees( - feature.geometry.coordinates[0], - feature.geometry.coordinates[1], - feature.geometry.coordinates[2] - ) - ); - satellites[satellite].radius.addSample( - Cesium.JulianDate.fromIso8601(feature.properties.time), - feature.properties.swath_width/2 - ); - satellites[satellite].visibility.addSample( - Cesium.JulianDate.fromIso8601(feature.properties.time), - Cesium.Color.fromCssColorString(option.data("color")).withAlpha(feature.properties.valid_obs*0.5) - ); - }); - for(var satellite in satellites) { - viewer.entities.add({ - parent: orbitTrack, - availability: new Cesium.TimeIntervalCollection([ - new Cesium.TimeInterval({ - start: Cesium.JulianDate.fromIso8601(start), - stop: Cesium.JulianDate.fromIso8601(end) - }) - ]), - position: satellites[satellite].position, - orientation: new Cesium.VelocityOrientationProperty(satellites[satellite].position), - point: { - pixelSize: 8, - color: Cesium.Color.fromCssColorString(option.data("color")) - }, - path: { - leadTime: $("#display-path").is(":checked") ? $("#display-duration").val()*60 : 0, - trailTime: $("#display-path").is(":checked") ? $("#display-duration").val()*60 : 0, - material: new Cesium.ColorMaterialProperty(Cesium.Color.fromCssColorString(option.data("color"))) - }, - ellipse: { - semiMajorAxis: satellites[satellite].radius, - semiMinorAxis: satellites[satellite].radius, - height: 0, - heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, - material: new Cesium.ColorMaterialProperty(satellites[satellite].visibility), - outline: true, - outlineColor: Cesium.Color.BLACK - } - }); - } - viewer.clock.startTime = Cesium.JulianDate.fromIso8601(start); - viewer.clock.currentTime = Cesium.JulianDate.fromIso8601(start); - viewer.clock.stopTime = Cesium.JulianDate.fromIso8601(end); - viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; - viewer.timeline.zoomTo( - Cesium.JulianDate.fromIso8601(start), - Cesium.JulianDate.fromIso8601(end) - ); - } - function clearOrbitTrack() { - clearEntities(orbitTrack); - } + $("#display-duration").val(60); + $("#display-step").val(30); $("#display-path").change(function() { _.forEach(viewer.entities.values, function(entity) { @@ -416,64 +208,6 @@ $(document).ready(function() { $("#display-lighting").change(function() { viewer.scene.globe.enableLighting = $("#display-lighting").is(":checked"); }); - $("#satellites").dblclick(function() { - $("#satellite-dialog").modal('show'); - }); - $("#satellite-add").click(function() { - const satellite = { - name: "New Satellite", - orbit: { - type: "circular", - mean_altitude: 400000, - inclination: 0, - true_anomaly: 0, - right_ascension_ascending_node: 0, - epoch: $("#display-start").datetimepicker("viewDate").toISOString() - }, - instruments: [ - { - name: "Default", - field_of_regard: 180, - min_access_time: 0, - req_target_sunlit: null, - req_self_sunlit: null - } - ] - }; - $("#satellites").append( - $("") - .data("satellite", satellite) - .data("instrument", satellite.instruments[0]) - .data("color", "#ff0000") - .text(satellite.name) - .attr("selected", "selected") - ); - changeSatellite(); - }); - $("#satellite-copy").click(function() { - const selected = $("#satellites option:selected"); - const satellite = $.extend(true, {}, selected.data("satellite")); - satellite.name += " (Copy)" - $("#satellites").append( - $("") - .data("satellite", satellite) - .data("instrument", satellite.instruments[0]) - .data("color", selected.data("color")) - .text(satellite.name) - .attr("selected", "selected") - ); - changeSatellite(); - }); - $("#satellite-delete").click(function() { - if(confirm("Delete satellite " + $("#satellites :selected").data("satellite").name + "?")) { - const index = $("#satellites").prop("selectedIndex"); - $("#satellites :selected").remove(); - if($("#satellites option").length > 0) { - $("#satellites").prop("selectedIndex", Math.min(index, $("#satellites option").length - 1)); - } - changeSatellite(); - } - }); var orbitTable; $("#orbit-dialog").on("show.bs.modal", function() { @@ -589,245 +323,8 @@ $(document).ready(function() { $("#orbit-data-csv").attr("download", "orbit.csv"); }); - $("#satellite-name").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.name = $("#satellite-name").val(); - $("#satellites option:selected").text($("#satellite-name").val()); - $("#orbit-data").prop("disabled", true); - }); - $("#satellite-color").change(function() { - $("#satellites option:selected").data("color", $("#satellite-color").val()); - }); - $("#satellite-type").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - if($("#satellite-type").val()=="train") { - satellite.type = "train"; - satellite.number_satellites = +$("#train-count").val(); - satellite.interval = +$("#train-interval").val()*60; - $(".constellation-train-group").show(); - } else { - delete satellite.interval; - $(".constellation-train-group").hide(); - } - if($("#satellite-type").val()=="walker") { - satellite.type = "walker"; - satellite.number_satellites = +$("#walker-count").val(); - satellite.number_planes = +$("#walker-planes").val(); - satellite.configuration = $("#walker-config").val(); - satellite.relative_spacing = +$("#walker-spacing").val(); - $(".constellation-walker-group").show(); - } else { - delete satellite.number_planes; - delete satellite.configuration; - delete satellite.relative_spacing; - $(".constellation-walker-group").hide(); - } - if($("#satellite-type").val()=="satellite") { - delete satellite.type; - delete satellite.number_planes; - } - $("#orbit-data").prop("disabled", true); - }); - $("#train-count").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.number_satellites = +$("#train-count").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#train-interval").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.interval = +$("#train-interval").val()*60; - $("#orbit-data").prop("disabled", true); - }); - $("#walker-count").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.number_satellites = +$("#walker-count").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#walker-planes").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.number_planes = +$("#walker-planes").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#walker-config").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.configuration = $("#walker-config").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#walker-spacing").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.relative_spacing = +$("#walker-spacing").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#satellite-orbit").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - $("#satellite-orbit").val()=="tle" ? $(".orbit-tle-group").show() : $(".orbit-tle-group").hide(); - $("#satellite-orbit").val()=="circular" ? $(".orbit-circular-group").show() : $(".orbit-circular-group").hide(); - $("#satellite-orbit").val()=="sso" ? $(".orbit-sso-group").show() : $(".orbit-sso-group").hide(); - $("#satellite-orbit").val()=="keplerian" ? $(".orbit-keplerian-group").show() : $(".orbit-keplerian-group").hide(); - satellite.orbit = getOrbit(); - $("#orbit-data").prop("disabled", true); - }); - $("#celestrak-dialog").on("shown.bs.modal", queryCelestrak); - $("#celestrak-name").change(queryCelestrak); - $("#celestrak-objects").change(function() { - if($("#celestrak-objects option:selected").length > 0) { - $("#celestrak-tle").val($("#celestrak-objects option:selected").data("tle")); - $("#celestrak-tle-ok").prop('disabled', false); - } else { - $("#celestrak-tle-ok").prop('disabled', true); - } - }); - $("#celestrak-tle-ok").click(function() { - $("#orbit-tle").val($("#celestrak-tle").val()); - $("#orbit-tle").change(); - }) - $("#orbit-tle").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.tle = $("#orbit-tle").val().split("\n"); - $("#orbit-data").prop("disabled", true); - }); - $("#orbit-circular-epoch").on("change.datetimepicker", function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.epoch = $("#orbit-circular-epoch").datetimepicker("viewDate").toISOString(); - $("#orbit-data").prop("disabled", true); - }); - $(".orbit-circular-group").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.mean_altitude = +$("#orbit-circular-altitude").val()*1000; - satellite.orbit.inclination = +$("#orbit-circular-inclination").val(); - satellite.orbit.right_ascension_ascending_node = +$("#orbit-circular-raan").val(); - satellite.orbit.true_anomaly = +$("#orbit-circular-ta").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#orbit-sso-epoch").on("change.datetimepicker", function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.epoch = $("#orbit-sso-epoch").datetimepicker("viewDate").toISOString(); - $("#orbit-data").prop("disabled", true); - }); - $("#orbit-sso-ect").on("change.datetimepicker", function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.equator_crossing_time = $("#orbit-sso-ect").datetimepicker("viewDate").format("HH:mm"); - $("#orbit-data").prop("disabled", true); - }); - $(".orbit-sso-group").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.equator_crossing_ascending = $("#orbit-sso-direction").val()=="asc"; - satellite.orbit.mean_altitude = +$("#orbit-sso-altitude").val()*1000; - satellite.orbit.true_anomaly = +$("#orbit-sso-ta").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#orbit-keplerian-epoch").on("change.datetimepicker", function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.epoch = $("#orbit-keplerian-epoch").datetimepicker("viewDate").toISOString(); - $("#orbit-data").prop("disabled", true); - }); - $(".orbit-keplerian-group").change(function() { - var satellite = $("#satellites option:selected").data("satellite"); - satellite.orbit.semimajor_axis = +$("#orbit-keplerian-altitude").val()*1000 + EARTH_MEAN_RADIUS; - satellite.orbit.inclination = +$("#orbit-keplerian-inclination").val(); - satellite.orbit.eccentricity = +$("#orbit-keplerian-eccentricity").val(); - satellite.orbit.perigee_argument = +$("#orbit-keplerian-pa").val(); - satellite.orbit.right_ascension_ascending_node = +$("#orbit-keplerian-raan").val(); - satellite.orbit.true_anomaly = +$("#orbit-keplerian-ta").val(); - $("#orbit-data").prop("disabled", true); - }); - $("#instrument-add").click(function() { - const satellite = $("#satellites option:selected").data("satellite"); - const instrument = { - name: "New Instrument", - field_of_regard: 180, - min_access_time: 0, - req_target_sunlit: null, - req_self_sunlit: null - }; - satellite.instruments.push(instrument); - $("#satellites option:selected").data("instrument", instrument); - $("#instruments").append( - $("") - .data("instrument", instrument) - .text(instrument.name) - .attr("selected", "selected") - ); - changeInstruments(); - $("#orbit-data").prop("disabled", true); - }); - $("#instrument-copy").click(function() { - const satellite = $("#satellites option:selected").data("satellite"); - const selected = $("#instruments option:selected"); - const instrument = $.extend({}, selected.data("instrument")); - instrument.name += " (Copy)"; - satellite.instruments.push(instrument); - $("#satellites option:selected").data("instrument", instrument); - $("#instruments").append( - $("") - .data("instrument", instrument) - .text(instrument.name) - .attr("selected", "selected") - ); - changeInstruments(); - $("#orbit-data").prop("disabled", true); - }); - $("#instrument-delete").click(function() { - if(confirm("Delete instrument " + $("#instruments :selected").data("instrument").name + "?")) { - const index = $("#instruments").prop("selectedIndex"); - $("#instruments :selected").remove(); - $("#instruments").prop("selectedIndex", Math.min(index, $("#instruments option").length - 1)); - changeInstruments(); - $("#orbit-data").prop("disabled", true); - } - }); - $("#instrument-name").change(function() { - var instrument = $("#instruments option:selected").data("instrument"); - instrument.name = $("#instrument-name").val(); - $("#instruments option:selected").text($("#instrument-name").val()); - $("#orbit-data").prop("disabled", true); - }); - $(".instrument-group").change(function() { - var instrument = $("#instruments option:selected").data("instrument"); - instrument.field_of_regard = +$("#instrument-field").val(); - instrument.min_access_time = +$("#instrument-access").val(); - instrument.req_self_sunlit = getSunlitState($("#instrument-self-sunlit").val()); - instrument.req_target_sunlit = getSunlitState($("#instrument-target-sunlit").val()); - $("#orbit-data").prop("disabled", true); - }); - $("#orbit-analyze").click(collectOrbitTrack); $("#satellite-dialog").on('hidden.bs.modal', collectOrbitTrack); - $("#nav-design-tab").on("show.bs.tab", changeSatellite); $("#nav-design-tab").on("show.bs.tab", collectOrbitTrack); $("#nav-design-tab").on("hide.bs.tab", clearOrbitTrack); - - // load initial data - var satellites = [ - { - name: "International Space Station", - orbit: { - type: "tle", - tle: [ - "1 25544U 98067A 21156.30527927 .00003432 00000-0 70541-4 0 9993", - "2 25544 51.6455 41.4969 0003508 68.0432 78.3395 15.48957534286754" - ] - }, - instruments: [ - { - name: "Default", - field_of_regard: 180, - min_access_time: 0, - req_target_sunlit: null, - req_self_sunlit: null - } - ] - } - ]; - satellites.forEach(function(satellite) { - $("#satellites").append( - $("") - .data("satellite", satellite) - .data("instrument", satellite.instruments[0]) - .data("color", "#ff0000") - .text(satellite.name) - ); - }); - $("#satellites").change(changeSatellite); - $("#instruments").change(changeInstruments); }); diff --git a/src/static/index.html b/src/static/index.html index b2fd87f..b6ca7a8 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -827,6 +827,8 @@

+ + diff --git a/src/static/orbit.js b/src/static/orbit.js new file mode 100644 index 0000000..7a41699 --- /dev/null +++ b/src/static/orbit.js @@ -0,0 +1,173 @@ +// Design tab: orbit configuration form (orbit type fields, Celestrak TLE search). + +// mean Earth radius (meters), matching tatc.constants.EARTH_MEAN_RADIUS; +// used to convert a user-facing altitude into a Keplerian orbit's +// semimajor_axis (semimajor_axis = EARTH_MEAN_RADIUS + altitude) +const EARTH_MEAN_RADIUS = 6371008.771415059; + +function getOrbit() { + if($("#satellite-orbit").val()=="tle") { + return { + type: "tle", + tle: $("#orbit-tle").val().split("\n") + } + } else if($("#satellite-orbit").val()=="circular") { + return { + type: "circular", + epoch: $("#orbit-circular-epoch").datetimepicker('viewDate').toISOString(), + mean_altitude: $("#orbit-circular-altitude").val()*1000, + inclination: $("#orbit-circular-inclination").val(), + right_ascension_ascending_node: $("#orbit-circular-raan").val(), + true_anomaly: $("#orbit-circular-ta").val() + } + } else if($("#satellite-orbit").val()=="sso") { + return { + type: "sso", + epoch: $("#orbit-sso-epoch").datetimepicker('viewDate').toISOString(), + equator_crossing_time: $("#orbit-sso-ect").datetimepicker('viewDate').format("HH:mm"), + equator_crossing_ascending: $("#orbit-sso-direction").val()=="asc", + mean_altitude: $("#orbit-sso-altitude").val()*1000, + true_anomaly: $("#orbit-sso-ta").val() + } + } else if($("#satellite-orbit").val()=="keplerian") { + return { + type: "keplerian", + epoch: $("#orbit-keplerian-epoch").datetimepicker('viewDate').toISOString(), + semimajor_axis: $("#orbit-keplerian-altitude").val()*1000 + EARTH_MEAN_RADIUS, + inclination: $("#orbit-keplerian-inclination").val(), + eccentricity: $("#orbit-keplerian-eccentricity").val(), + perigee_argument: $("#orbit-keplerian-pa").val(), + right_ascension_ascending_node: $("#orbit-keplerian-raan").val(), + true_anomaly: $("#orbit-keplerian-ta").val() + } + } +} + +function queryCelestrak() { + var query = $("#celestrak-name").val(); + if(query.length > 2) { + $("#celestrak-objects").val([]); + $("#celestrak-objects").change(); + $("#celestrak-tle").val(""); + $.ajax({ + url: "celestrak/tle?name=" + query, + type: "GET", + crossDomain: true, + success: function(response) { + var lines = response.split(/\r?\n/); + if(lines.length >= 3) { + $("#celestrak-objects").empty(); + for(var i = 0; i < lines.length - 2; i += 3) { + $("#celestrak-objects").append( + $('") + .data("instrument", instrument) + .text(instrument.name); + if(instrument===$("#satellites option:selected").data("instrument")) { + option.attr("selected", "selected"); + } + $("#instruments").append(option); + changeInstruments(); + }); + } else { + $(".satellite-group").hide(); + } +} + +function changeInstruments() { + const instrument = $("#instruments option:selected").data("instrument"); + $("#instrument-copy").prop("disabled", instrument?false:true); + $("#instrument-delete").prop("disabled", (instrument?false:true) || $("#instruments option").length <= 1); + if(instrument) { + $(".instrument-group").show(); + $("#instrument-name").val(instrument.name); + $("#instrument-field").val(instrument.field_of_regard); + $("#instrument-access").val(instrument.min_access_time); + $("#instrument-target-sunlit").val( + instrument.req_target_sunlit?"sunlit": + (instrument.req_target_sunlit===false?"eclipse":"none") + ); + $("#instrument-self-sunlit").val( + instrument.req_self_sunlit?"sunlit": + (instrument.req_self_sunlit===false?"eclipse":"none") + ); + $("#satellites option:selected").data("instrument", instrument); + } else { + $(".instrument-group").hide(); + } +} + +function getSunlitState(value) { + if(value=="sunlit") { + return true; + } else if(value=="eclipse") { + return false; + } else { + return null; + } +} + +$(document).ready(function() { + $("#satellites").dblclick(function() { + $("#satellite-dialog").modal('show'); + }); + $("#satellite-add").click(function() { + const satellite = { + name: "New Satellite", + orbit: { + type: "circular", + mean_altitude: 400000, + inclination: 0, + true_anomaly: 0, + right_ascension_ascending_node: 0, + epoch: $("#display-start").datetimepicker("viewDate").toISOString() + }, + instruments: [ + { + name: "Default", + field_of_regard: 180, + min_access_time: 0, + req_target_sunlit: null, + req_self_sunlit: null + } + ] + }; + $("#satellites").append( + $("") + .data("satellite", satellite) + .data("instrument", satellite.instruments[0]) + .data("color", "#ff0000") + .text(satellite.name) + .attr("selected", "selected") + ); + changeSatellite(); + }); + $("#satellite-copy").click(function() { + const selected = $("#satellites option:selected"); + const satellite = $.extend(true, {}, selected.data("satellite")); + satellite.name += " (Copy)" + $("#satellites").append( + $("") + .data("satellite", satellite) + .data("instrument", satellite.instruments[0]) + .data("color", selected.data("color")) + .text(satellite.name) + .attr("selected", "selected") + ); + changeSatellite(); + }); + $("#satellite-delete").click(function() { + if(confirm("Delete satellite " + $("#satellites :selected").data("satellite").name + "?")) { + const index = $("#satellites").prop("selectedIndex"); + $("#satellites :selected").remove(); + if($("#satellites option").length > 0) { + $("#satellites").prop("selectedIndex", Math.min(index, $("#satellites option").length - 1)); + } + changeSatellite(); + } + }); + + $("#satellite-name").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + satellite.name = $("#satellite-name").val(); + $("#satellites option:selected").text($("#satellite-name").val()); + $("#orbit-data").prop("disabled", true); + }); + $("#satellite-color").change(function() { + $("#satellites option:selected").data("color", $("#satellite-color").val()); + }); + $("#satellite-type").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + if($("#satellite-type").val()=="train") { + satellite.type = "train"; + satellite.number_satellites = +$("#train-count").val(); + satellite.interval = +$("#train-interval").val()*60; + $(".constellation-train-group").show(); + } else { + delete satellite.interval; + $(".constellation-train-group").hide(); + } + if($("#satellite-type").val()=="walker") { + satellite.type = "walker"; + satellite.number_satellites = +$("#walker-count").val(); + satellite.number_planes = +$("#walker-planes").val(); + satellite.configuration = $("#walker-config").val(); + satellite.relative_spacing = +$("#walker-spacing").val(); + $(".constellation-walker-group").show(); + } else { + delete satellite.number_planes; + delete satellite.configuration; + delete satellite.relative_spacing; + $(".constellation-walker-group").hide(); + } + if($("#satellite-type").val()=="satellite") { + delete satellite.type; + delete satellite.number_planes; + } + $("#orbit-data").prop("disabled", true); + }); + $("#train-count").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + satellite.number_satellites = +$("#train-count").val(); + $("#orbit-data").prop("disabled", true); + }); + $("#train-interval").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + satellite.interval = +$("#train-interval").val()*60; + $("#orbit-data").prop("disabled", true); + }); + $("#walker-count").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + satellite.number_satellites = +$("#walker-count").val(); + $("#orbit-data").prop("disabled", true); + }); + $("#walker-planes").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + satellite.number_planes = +$("#walker-planes").val(); + $("#orbit-data").prop("disabled", true); + }); + $("#walker-config").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + satellite.configuration = $("#walker-config").val(); + $("#orbit-data").prop("disabled", true); + }); + $("#walker-spacing").change(function() { + var satellite = $("#satellites option:selected").data("satellite"); + satellite.relative_spacing = +$("#walker-spacing").val(); + $("#orbit-data").prop("disabled", true); + }); + + $("#instrument-add").click(function() { + const satellite = $("#satellites option:selected").data("satellite"); + const instrument = { + name: "New Instrument", + field_of_regard: 180, + min_access_time: 0, + req_target_sunlit: null, + req_self_sunlit: null + }; + satellite.instruments.push(instrument); + $("#satellites option:selected").data("instrument", instrument); + $("#instruments").append( + $("") + .data("instrument", instrument) + .text(instrument.name) + .attr("selected", "selected") + ); + changeInstruments(); + $("#orbit-data").prop("disabled", true); + }); + $("#instrument-copy").click(function() { + const satellite = $("#satellites option:selected").data("satellite"); + const selected = $("#instruments option:selected"); + const instrument = $.extend({}, selected.data("instrument")); + instrument.name += " (Copy)"; + satellite.instruments.push(instrument); + $("#satellites option:selected").data("instrument", instrument); + $("#instruments").append( + $("") + .data("instrument", instrument) + .text(instrument.name) + .attr("selected", "selected") + ); + changeInstruments(); + $("#orbit-data").prop("disabled", true); + }); + $("#instrument-delete").click(function() { + if(confirm("Delete instrument " + $("#instruments :selected").data("instrument").name + "?")) { + const index = $("#instruments").prop("selectedIndex"); + $("#instruments :selected").remove(); + $("#instruments").prop("selectedIndex", Math.min(index, $("#instruments option").length - 1)); + changeInstruments(); + $("#orbit-data").prop("disabled", true); + } + }); + $("#instrument-name").change(function() { + var instrument = $("#instruments option:selected").data("instrument"); + instrument.name = $("#instrument-name").val(); + $("#instruments option:selected").text($("#instrument-name").val()); + $("#orbit-data").prop("disabled", true); + }); + $(".instrument-group").change(function() { + var instrument = $("#instruments option:selected").data("instrument"); + instrument.field_of_regard = +$("#instrument-field").val(); + instrument.min_access_time = +$("#instrument-access").val(); + instrument.req_self_sunlit = getSunlitState($("#instrument-self-sunlit").val()); + instrument.req_target_sunlit = getSunlitState($("#instrument-target-sunlit").val()); + $("#orbit-data").prop("disabled", true); + }); + + $("#nav-design-tab").on("show.bs.tab", changeSatellite); + + // load initial data + var satellites = [ + { + name: "International Space Station", + orbit: { + type: "tle", + tle: [ + "1 25544U 98067A 21156.30527927 .00003432 00000-0 70541-4 0 9993", + "2 25544 51.6455 41.4969 0003508 68.0432 78.3395 15.48957534286754" + ] + }, + instruments: [ + { + name: "Default", + field_of_regard: 180, + min_access_time: 0, + req_target_sunlit: null, + req_self_sunlit: null + } + ] + } + ]; + satellites.forEach(function(satellite) { + $("#satellites").append( + $("") + .data("satellite", satellite) + .data("instrument", satellite.instruments[0]) + .data("color", "#ff0000") + .text(satellite.name) + ); + }); + $("#satellites").change(changeSatellite); + $("#instruments").change(changeInstruments); +}); From c0b60342fea39cd5eb4b2c3434bf4f72db1a44e6 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 4 Sep 2026 10:33:15 -0700 Subject: [PATCH 14/16] change login input from text to email type --- src/static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/index.html b/src/static/index.html index b6ca7a8..91d29c5 100644 --- a/src/static/index.html +++ b/src/static/index.html @@ -297,7 +297,7 @@
- +
From fd074839703b87c3e7957e84668617de4a1c935b Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 4 Sep 2026 10:43:51 -0700 Subject: [PATCH 15/16] bump verison number --- src/tatc_app/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tatc_app/__init__.py b/src/tatc_app/__init__.py index f5fe964..ff1068c 100644 --- a/src/tatc_app/__init__.py +++ b/src/tatc_app/__init__.py @@ -1 +1 @@ -__version__ = "1.0" \ No newline at end of file +__version__ = "1.1.0" \ No newline at end of file From f2cdd562588c6571420e0a3c1d1e64113f71f795 Mon Sep 17 00:00:00 2001 From: Paul Grogan Date: Fri, 4 Sep 2026 20:32:36 -0700 Subject: [PATCH 16/16] use ghcr image for deployment --- .github/workflows/ghcr-push-image.yml | 55 +++++++++++++++++++++++++++ README.md | 7 ++++ compose.server.yml | 8 +--- compose.worker.yml | 4 +- 4 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/ghcr-push-image.yml diff --git a/.github/workflows/ghcr-push-image.yml b/.github/workflows/ghcr-push-image.yml new file mode 100644 index 0000000..9dcb503 --- /dev/null +++ b/.github/workflows/ghcr-push-image.yml @@ -0,0 +1,55 @@ +name: Build and push GHCR images + +on: + push: + branches: + - main + workflow_dispatch: + +env: + SERVER_IMAGE: ghcr.io/code-lab-org/tatc-server + WORKER_IMAGE: ghcr.io/code-lab-org/tatc-worker + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push the server image + uses: docker/build-push-action@v6 + with: + context: . + target: tatc_server + push: true + tags: | + ${{ env.SERVER_IMAGE }}:${{ github.sha }} + ${{ env.SERVER_IMAGE }}:latest + cache-from: type=gha,scope=tatc-server + cache-to: type=gha,mode=max,scope=tatc-server + + - name: Build and push the worker image + uses: docker/build-push-action@v6 + with: + context: . + target: tatc_worker + push: true + tags: | + ${{ env.WORKER_IMAGE }}:${{ github.sha }} + ${{ env.WORKER_IMAGE }}:latest + cache-from: type=gha,scope=tatc-worker + cache-to: type=gha,mode=max,scope=tatc-worker diff --git a/README.md b/README.md index a677060..137fcc3 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,13 @@ the GUI/API, broker, and backend. It requires: * `TATC_CESIUM_TOKEN`: Cesium access token (see [Cesium Access Token and Assets](#cesium-access-token-and-assets) above) +`compose.server.yml` and `compose.worker.yml` pull the `tatc-server` and +`tatc-worker` images from GHCR rather than building them locally. Set +`TATC_SERVER_IMAGE_TAG` / `TATC_WORKER_IMAGE_TAG` to a commit SHA (as pushed by the +[Build and push GHCR images](.github/workflows/ghcr-push-image.yml) +workflow on merge to `main`) to pin the deployed version; both default to +`latest` if unset. + The server's user-account database is stored in the `tatc-data` Docker volume; `compose.server.yml` sets `TATC_DATABASE_URL` to place it there automatically, so it persists across restarts without further configuration. diff --git a/compose.server.yml b/compose.server.yml index 62753fd..8380fad 100644 --- a/compose.server.yml +++ b/compose.server.yml @@ -29,9 +29,7 @@ services: labels: - traefik.enable=false server: - build: - context: . - target: tatc_server + image: ghcr.io/code-lab-org/tatc-server:${TATC_SERVER_IMAGE_TAG:-latest} container_name: tatc-server restart: unless-stopped environment: @@ -58,9 +56,7 @@ services: worker: condition: service_started worker: - build: - context: . - target: tatc_worker + image: ghcr.io/code-lab-org/tatc-worker:${TATC_WORKER_IMAGE_TAG:-latest} container_name: tatc-worker restart: unless-stopped environment: diff --git a/compose.worker.yml b/compose.worker.yml index 63317fc..0233890 100644 --- a/compose.worker.yml +++ b/compose.worker.yml @@ -1,8 +1,6 @@ services: worker: - build: - context: . - target: tatc_worker + image: ghcr.io/code-lab-org/tatc-worker:${TATC_WORKER_IMAGE_TAG:-latest} container_name: tatc-worker restart: unless-stopped environment: