diff --git a/examples/case_e/models.yml b/examples/case_e/models.yml index 7efab02..b677d2a 100644 --- a/examples/case_e/models.yml +++ b/examples/case_e/models.yml @@ -1,12 +1,12 @@ - ALM: path: models/gulia-wiemer.ALM.italy.10yr.2010-01-01.xml forecast_unit: 10 - use_db: True + store_db: True - MPS04: path: models/meletti.MPS04.italy.10yr.2010-01-01.xml forecast_unit: 10 - use_db: True + store_db: True - TripleS-CPTI: path: models/zechar.TripleS-CPTI.italy.10yr.2010-01-01.xml forecast_unit: 10 - use_db: True \ No newline at end of file + store_db: True \ No newline at end of file diff --git a/examples/case_f/pymock/setup.cfg b/examples/case_f/pymock/setup.cfg index 992334a..c2bb462 100644 --- a/examples/case_f/pymock/setup.cfg +++ b/examples/case_f/pymock/setup.cfg @@ -14,8 +14,8 @@ url = https://git.gfz-potsdam.de/csep/it_experiment/models/pymock packages = pymock install_requires = - numpy==1.23.4 - matplotlib==3.4.3 + numpy + matplotlib python_requires = >=3.7 zip_safe = no diff --git a/floatcsep/__init__.py b/floatcsep/__init__.py index a1760de..a0d9de5 100644 --- a/floatcsep/__init__.py +++ b/floatcsep/__init__.py @@ -7,4 +7,4 @@ from floatcsep import model from floatcsep import readers -__version__ = '0.1.3' +__version__ = "0.1.4" diff --git a/floatcsep/accessors.py b/floatcsep/accessors.py index f1f4f8c..c62948a 100644 --- a/floatcsep/accessors.py +++ b/floatcsep/accessors.py @@ -14,25 +14,32 @@ TIMEOUT = 180 -def query_gcmt(start_time, end_time, min_magnitude=5.0, - max_depth=None, - catalog_id=None, - min_latitude=None, max_latitude=None, - min_longitude=None, max_longitude=None): - - eventlist = _query_gcmt(start_time=start_time, - end_time=end_time, - min_magnitude=min_magnitude, - min_latitude=min_latitude, - max_latitude=max_latitude, - min_longitude=min_longitude, - max_longitude=max_longitude, - max_depth=max_depth) - - catalog = CSEPCatalog(data=eventlist, - name='gCMT', - catalog_id=catalog_id, - date_accessed=utc_now_datetime()) +def query_gcmt( + start_time, + end_time, + min_magnitude=5.0, + max_depth=None, + catalog_id=None, + min_latitude=None, + max_latitude=None, + min_longitude=None, + max_longitude=None, +): + + eventlist = _query_gcmt( + start_time=start_time, + end_time=end_time, + min_magnitude=min_magnitude, + min_latitude=min_latitude, + max_latitude=max_latitude, + min_longitude=min_longitude, + max_longitude=max_longitude, + max_depth=max_depth, + ) + + catalog = CSEPCatalog( + data=eventlist, name="gCMT", catalog_id=catalog_id, date_accessed=utc_now_datetime() + ) return catalog @@ -51,9 +58,9 @@ def from_zenodo(record_id, folder, force=False): """ # Grab the urls and filenames and checksums - r = requests.get(f"https://zenodo.org/api/records/{record_id}") - download_urls = [f['links']['self'] for f in r.json()['files']] - filenames = [(f['key'], f['checksum']) for f in r.json()['files']] + r = requests.get(f"https://zenodo.org/api/records/{record_id}", timeout=3) + download_urls = [f["links"]["self"] for f in r.json()["files"]] + filenames = [(f["key"], f["checksum"]) for f in r.json()["files"]] # Download and verify checksums for (fname, checksum), url in zip(filenames, download_urls): @@ -61,15 +68,13 @@ def from_zenodo(record_id, folder, force=False): if os.path.exists(full_path): value, digest = _check_hash(full_path, checksum) if value != digest: - print( - f"Checksum is different: re-downloading {fname}" - f" from Zenodo...") + print(f"Checksum is different: re-downloading {fname}" f" from Zenodo...") _download_file(url, full_path) elif force: print(f"Re-downloading {fname} from Zenodo...") _download_file(url, full_path) else: - print(f'Found file {fname}. Checksum OK.') + print(f"Found file {fname}. Checksum OK.") else: print(f"Downloading {fname} from Zenodo...") @@ -96,24 +101,31 @@ def from_git(url, path, branch=None, depth=1, **kwargs): the pygit repository """ - kwargs.update({'depth': depth}) + kwargs.update({"depth": depth}) git.refresh() try: repo = git.Repo(path) except (git.NoSuchPathError, git.InvalidGitRepositoryError): repo = git.Repo.clone_from(url, path, branch=branch, **kwargs) - git_dir = os.path.join(path, '.git') + git_dir = os.path.join(path, ".git") if os.path.isdir(git_dir): shutil.rmtree(git_dir) return repo -def _query_gcmt(start_time, end_time, min_magnitude=3.50, - min_latitude=None, max_latitude=None, - min_longitude=None, max_longitude=None, - max_depth=1000, extra_gcmt_params=None): +def _query_gcmt( + start_time, + end_time, + min_magnitude=3.50, + min_latitude=None, + max_latitude=None, + min_longitude=None, + max_longitude=None, + max_depth=1000, + extra_gcmt_params=None, +): """ Return GCMT eventlist from IRIS web service. For details see "https://service.iris.edu/fdsnws/event/1/" @@ -134,38 +146,44 @@ def _query_gcmt(start_time, end_time, min_magnitude=3.50, """ extra_gcmt_params = extra_gcmt_params or {} - eventlist = gcmt_search(minmagnitude=min_magnitude, - minlatitude=min_latitude, - maxlatitude=max_latitude, - minlongitude=min_longitude, - maxlongitude=max_longitude, - starttime=start_time.isoformat(), - endtime=end_time.isoformat(), - maxdepth=max_depth, **extra_gcmt_params) + eventlist = gcmt_search( + minmagnitude=min_magnitude, + minlatitude=min_latitude, + maxlatitude=max_latitude, + minlongitude=min_longitude, + maxlongitude=max_longitude, + starttime=start_time.isoformat(), + endtime=end_time.isoformat(), + maxdepth=max_depth, + **extra_gcmt_params, + ) return eventlist -def gcmt_search(format='text', - starttime=None, - endtime=None, - updatedafter=None, - minlatitude=None, - maxlatitude=None, - minlongitude=None, - maxlongitude=None, - latitude=None, - longitude=None, - maxradius=None, - catalog='GCMT', - contributor=None, - maxdepth=1000, - maxmagnitude=10.0, - mindepth=-100, - minmagnitude=0, - offset=1, - orderby='time-asc', - host=None, - verbose=False): + +def gcmt_search( + format="text", + starttime=None, + endtime=None, + updatedafter=None, + minlatitude=None, + maxlatitude=None, + minlongitude=None, + maxlongitude=None, + latitude=None, + longitude=None, + maxradius=None, + catalog="GCMT", + contributor=None, + maxdepth=1000, + maxmagnitude=10.0, + mindepth=-100, + minmagnitude=0, + offset=1, + orderby="time-asc", + host=None, + verbose=False, +): """Search the IRIS database for events matching input criteria. This search function is a wrapper around the ComCat Web API described here: https://service.iris.edu/fdsnws/event/1/ @@ -225,16 +243,16 @@ def gcmt_search(format='text', for key, value in inputargs.items(): if value is True: - newargs[key] = 'true' + newargs[key] = "true" continue if value is False: - newargs[key] = 'false' + newargs[key] = "false" continue if value is None: continue newargs[key] = value - del newargs['verbose'] + del newargs["verbose"] events = _search_gcmt(**newargs) @@ -249,11 +267,11 @@ def _search_gcmt(**_newargs): paramstr = urlencode(_newargs) url = HOST_CATALOG + paramstr fh = request.urlopen(url, timeout=TIMEOUT) - data = fh.read().decode('utf8').split('\n') + data = fh.read().decode("utf8").split("\n") fh.close() eventlist = [] for line in data[1:]: - line_ = line.split('|') + line_ = line.split("|") if len(line_) != 1: id_ = line_[0] time_ = datetime.fromisoformat(line_[1]) @@ -280,47 +298,47 @@ def _download_file(url: str, filename: str) -> None: progress_bar_length = 72 block_size = 1024 - r = requests.get(url, stream=True) - total_size = r.headers.get('content-length', False) + r = requests.get(url, timeout=3, stream=True) + total_size = r.headers.get("content-length", False) if not total_size: with requests.head(url) as h: try: - total_size = int(h.headers.get('Content-Length', 0)) + total_size = int(h.headers.get("Content-Length", 0)) except TypeError: total_size = 0 else: total_size = int(total_size) download_size = 0 if total_size: - print( - f'Downloading file with size of {total_size / block_size:.3f} kB') + print(f"Downloading file with size of {total_size / block_size:.3f} kB") else: - print(f'Downloading file with unknown size') - with open(filename, 'wb') as f: + print(f"Downloading file with unknown size") + with open(filename, "wb") as f: for data in r.iter_content(chunk_size=block_size): download_size += len(data) f.write(data) if total_size: - progress = int( - progress_bar_length * download_size / total_size) + progress = int(progress_bar_length * download_size / total_size) sys.stdout.write( - '\r[{}{}] {:.1f}%'.format('█' * progress, '.' * - (progress_bar_length - progress), - 100 * download_size / total_size) + "\r[{}{}] {:.1f}%".format( + "█" * progress, + "." * (progress_bar_length - progress), + 100 * download_size / total_size, + ) ) sys.stdout.flush() - sys.stdout.write('\n') + sys.stdout.write("\n") def _check_hash(filename, checksum): """ Checks if existing file hash matches checksum from url """ - algorithm, value = checksum.split(':') + algorithm, value = checksum.split(":") if not os.path.exists(filename): - return value, 'invalid' + return value, "invalid" h = hashlib.new(algorithm) - with open(filename, 'rb') as f: + with open(filename, "rb") as f: while True: data = f.read(4096) if not data: diff --git a/floatcsep/artifacts/new_zealand_csep_testing.csv b/floatcsep/artifacts/new_zealand_csep_testing.csv deleted file mode 100644 index e051005..0000000 --- a/floatcsep/artifacts/new_zealand_csep_testing.csv +++ /dev/null @@ -1,6343 +0,0 @@ -165.7,165.8,-46.2,-46.1,0,40 -165.8,165.9,-46.3,-46.2,0,40 -165.8,165.9,-46.2,-46.1,0,40 -165.8,165.9,-46.1,-46,0,40 -165.8,165.9,-46,-45.9,0,40 -165.8,165.9,-45.9,-45.8,0,40 -165.8,165.9,-45.8,-45.7,0,40 -165.8,165.9,-45.7,-45.6,0,40 -165.8,165.9,-45.6,-45.5,0,40 -165.9,166,-46.4,-46.3,0,40 -165.9,166,-46.3,-46.2,0,40 -165.9,166,-46.2,-46.1,0,40 -165.9,166,-46.1,-46,0,40 -165.9,166,-46,-45.9,0,40 -165.9,166,-45.9,-45.8,0,40 -165.9,166,-45.8,-45.7,0,40 -165.9,166,-45.7,-45.6,0,40 -165.9,166,-45.6,-45.5,0,40 -165.9,166,-45.5,-45.4,0,40 -166,166.1,-46.5,-46.4,0,40 -166,166.1,-46.4,-46.3,0,40 -166,166.1,-46.3,-46.2,0,40 -166,166.1,-46.2,-46.1,0,40 -166,166.1,-46.1,-46,0,40 -166,166.1,-46,-45.9,0,40 -166,166.1,-45.9,-45.8,0,40 -166,166.1,-45.8,-45.7,0,40 -166,166.1,-45.7,-45.6,0,40 -166,166.1,-45.6,-45.5,0,40 -166,166.1,-45.5,-45.4,0,40 -166,166.1,-45.4,-45.3,0,40 -166.1,166.2,-46.6,-46.5,0,40 -166.1,166.2,-46.5,-46.4,0,40 -166.1,166.2,-46.4,-46.3,0,40 -166.1,166.2,-46.3,-46.2,0,40 -166.1,166.2,-46.2,-46.1,0,40 -166.1,166.2,-46.1,-46,0,40 -166.1,166.2,-46,-45.9,0,40 -166.1,166.2,-45.9,-45.8,0,40 -166.1,166.2,-45.8,-45.7,0,40 -166.1,166.2,-45.7,-45.6,0,40 -166.1,166.2,-45.6,-45.5,0,40 -166.1,166.2,-45.5,-45.4,0,40 -166.1,166.2,-45.4,-45.3,0,40 -166.1,166.2,-45.3,-45.2,0,40 -166.2,166.3,-46.7,-46.6,0,40 -166.2,166.3,-46.6,-46.5,0,40 -166.2,166.3,-46.5,-46.4,0,40 -166.2,166.3,-46.4,-46.3,0,40 -166.2,166.3,-46.3,-46.2,0,40 -166.2,166.3,-46.2,-46.1,0,40 -166.2,166.3,-46.1,-46,0,40 -166.2,166.3,-46,-45.9,0,40 -166.2,166.3,-45.9,-45.8,0,40 -166.2,166.3,-45.8,-45.7,0,40 -166.2,166.3,-45.7,-45.6,0,40 -166.2,166.3,-45.6,-45.5,0,40 -166.2,166.3,-45.5,-45.4,0,40 -166.2,166.3,-45.4,-45.3,0,40 -166.2,166.3,-45.3,-45.2,0,40 -166.2,166.3,-45.2,-45.1,0,40 -166.3,166.4,-46.9,-46.8,0,40 -166.3,166.4,-46.8,-46.7,0,40 -166.3,166.4,-46.7,-46.6,0,40 -166.3,166.4,-46.6,-46.5,0,40 -166.3,166.4,-46.5,-46.4,0,40 -166.3,166.4,-46.4,-46.3,0,40 -166.3,166.4,-46.3,-46.2,0,40 -166.3,166.4,-46.2,-46.1,0,40 -166.3,166.4,-46.1,-46,0,40 -166.3,166.4,-46,-45.9,0,40 -166.3,166.4,-45.9,-45.8,0,40 -166.3,166.4,-45.8,-45.7,0,40 -166.3,166.4,-45.7,-45.6,0,40 -166.3,166.4,-45.6,-45.5,0,40 -166.3,166.4,-45.5,-45.4,0,40 -166.3,166.4,-45.4,-45.3,0,40 -166.3,166.4,-45.3,-45.2,0,40 -166.3,166.4,-45.2,-45.1,0,40 -166.3,166.4,-45.1,-45,0,40 -166.4,166.5,-47,-46.9,0,40 -166.4,166.5,-46.9,-46.8,0,40 -166.4,166.5,-46.8,-46.7,0,40 -166.4,166.5,-46.7,-46.6,0,40 -166.4,166.5,-46.6,-46.5,0,40 -166.4,166.5,-46.5,-46.4,0,40 -166.4,166.5,-46.4,-46.3,0,40 -166.4,166.5,-46.3,-46.2,0,40 -166.4,166.5,-46.2,-46.1,0,40 -166.4,166.5,-46.1,-46,0,40 -166.4,166.5,-46,-45.9,0,40 -166.4,166.5,-45.9,-45.8,0,40 -166.4,166.5,-45.8,-45.7,0,40 -166.4,166.5,-45.7,-45.6,0,40 -166.4,166.5,-45.6,-45.5,0,40 -166.4,166.5,-45.5,-45.4,0,40 -166.4,166.5,-45.4,-45.3,0,40 -166.4,166.5,-45.3,-45.2,0,40 -166.4,166.5,-45.2,-45.1,0,40 -166.4,166.5,-45.1,-45,0,40 -166.4,166.5,-45,-44.9,0,40 -166.5,166.6,-47.1,-47,0,40 -166.5,166.6,-47,-46.9,0,40 -166.5,166.6,-46.9,-46.8,0,40 -166.5,166.6,-46.8,-46.7,0,40 -166.5,166.6,-46.7,-46.6,0,40 -166.5,166.6,-46.6,-46.5,0,40 -166.5,166.6,-46.5,-46.4,0,40 -166.5,166.6,-46.4,-46.3,0,40 -166.5,166.6,-46.3,-46.2,0,40 -166.5,166.6,-46.2,-46.1,0,40 -166.5,166.6,-46.1,-46,0,40 -166.5,166.6,-46,-45.9,0,40 -166.5,166.6,-45.9,-45.8,0,40 -166.5,166.6,-45.8,-45.7,0,40 -166.5,166.6,-45.7,-45.6,0,40 -166.5,166.6,-45.6,-45.5,0,40 -166.5,166.6,-45.5,-45.4,0,40 -166.5,166.6,-45.4,-45.3,0,40 -166.5,166.6,-45.3,-45.2,0,40 -166.5,166.6,-45.2,-45.1,0,40 -166.5,166.6,-45.1,-45,0,40 -166.5,166.6,-45,-44.9,0,40 -166.5,166.6,-44.9,-44.8,0,40 -166.6,166.7,-47.2,-47.1,0,40 -166.6,166.7,-47.1,-47,0,40 -166.6,166.7,-47,-46.9,0,40 -166.6,166.7,-46.9,-46.8,0,40 -166.6,166.7,-46.8,-46.7,0,40 -166.6,166.7,-46.7,-46.6,0,40 -166.6,166.7,-46.6,-46.5,0,40 -166.6,166.7,-46.5,-46.4,0,40 -166.6,166.7,-46.4,-46.3,0,40 -166.6,166.7,-46.3,-46.2,0,40 -166.6,166.7,-46.2,-46.1,0,40 -166.6,166.7,-46.1,-46,0,40 -166.6,166.7,-46,-45.9,0,40 -166.6,166.7,-45.9,-45.8,0,40 -166.6,166.7,-45.8,-45.7,0,40 -166.6,166.7,-45.7,-45.6,0,40 -166.6,166.7,-45.6,-45.5,0,40 -166.6,166.7,-45.5,-45.4,0,40 -166.6,166.7,-45.4,-45.3,0,40 -166.6,166.7,-45.3,-45.2,0,40 -166.6,166.7,-45.2,-45.1,0,40 -166.6,166.7,-45.1,-45,0,40 -166.6,166.7,-45,-44.9,0,40 -166.6,166.7,-44.9,-44.8,0,40 -166.6,166.7,-44.8,-44.7,0,40 -166.7,166.8,-47.3,-47.2,0,40 -166.7,166.8,-47.2,-47.1,0,40 -166.7,166.8,-47.1,-47,0,40 -166.7,166.8,-47,-46.9,0,40 -166.7,166.8,-46.9,-46.8,0,40 -166.7,166.8,-46.8,-46.7,0,40 -166.7,166.8,-46.7,-46.6,0,40 -166.7,166.8,-46.6,-46.5,0,40 -166.7,166.8,-46.5,-46.4,0,40 -166.7,166.8,-46.4,-46.3,0,40 -166.7,166.8,-46.3,-46.2,0,40 -166.7,166.8,-46.2,-46.1,0,40 -166.7,166.8,-46.1,-46,0,40 -166.7,166.8,-46,-45.9,0,40 -166.7,166.8,-45.9,-45.8,0,40 -166.7,166.8,-45.8,-45.7,0,40 -166.7,166.8,-45.7,-45.6,0,40 -166.7,166.8,-45.6,-45.5,0,40 -166.7,166.8,-45.5,-45.4,0,40 -166.7,166.8,-45.4,-45.3,0,40 -166.7,166.8,-45.3,-45.2,0,40 -166.7,166.8,-45.2,-45.1,0,40 -166.7,166.8,-45.1,-45,0,40 -166.7,166.8,-45,-44.9,0,40 -166.7,166.8,-44.9,-44.8,0,40 -166.7,166.8,-44.8,-44.7,0,40 -166.7,166.8,-44.7,-44.6,0,40 -166.8,166.9,-47.4,-47.3,0,40 -166.8,166.9,-47.3,-47.2,0,40 -166.8,166.9,-47.2,-47.1,0,40 -166.8,166.9,-47.1,-47,0,40 -166.8,166.9,-47,-46.9,0,40 -166.8,166.9,-46.9,-46.8,0,40 -166.8,166.9,-46.8,-46.7,0,40 -166.8,166.9,-46.7,-46.6,0,40 -166.8,166.9,-46.6,-46.5,0,40 -166.8,166.9,-46.5,-46.4,0,40 -166.8,166.9,-46.4,-46.3,0,40 -166.8,166.9,-46.3,-46.2,0,40 -166.8,166.9,-46.2,-46.1,0,40 -166.8,166.9,-46.1,-46,0,40 -166.8,166.9,-46,-45.9,0,40 -166.8,166.9,-45.9,-45.8,0,40 -166.8,166.9,-45.8,-45.7,0,40 -166.8,166.9,-45.7,-45.6,0,40 -166.8,166.9,-45.6,-45.5,0,40 -166.8,166.9,-45.5,-45.4,0,40 -166.8,166.9,-45.4,-45.3,0,40 -166.8,166.9,-45.3,-45.2,0,40 -166.8,166.9,-45.2,-45.1,0,40 -166.8,166.9,-45.1,-45,0,40 -166.8,166.9,-45,-44.9,0,40 -166.8,166.9,-44.9,-44.8,0,40 -166.8,166.9,-44.8,-44.7,0,40 -166.8,166.9,-44.7,-44.6,0,40 -166.8,166.9,-44.6,-44.5,0,40 -166.9,167,-47.6,-47.5,0,40 -166.9,167,-47.5,-47.4,0,40 -166.9,167,-47.4,-47.3,0,40 -166.9,167,-47.3,-47.2,0,40 -166.9,167,-47.2,-47.1,0,40 -166.9,167,-47.1,-47,0,40 -166.9,167,-47,-46.9,0,40 -166.9,167,-46.9,-46.8,0,40 -166.9,167,-46.8,-46.7,0,40 -166.9,167,-46.7,-46.6,0,40 -166.9,167,-46.6,-46.5,0,40 -166.9,167,-46.5,-46.4,0,40 -166.9,167,-46.4,-46.3,0,40 -166.9,167,-46.3,-46.2,0,40 -166.9,167,-46.2,-46.1,0,40 -166.9,167,-46.1,-46,0,40 -166.9,167,-46,-45.9,0,40 -166.9,167,-45.9,-45.8,0,40 -166.9,167,-45.8,-45.7,0,40 -166.9,167,-45.7,-45.6,0,40 -166.9,167,-45.6,-45.5,0,40 -166.9,167,-45.5,-45.4,0,40 -166.9,167,-45.4,-45.3,0,40 -166.9,167,-45.3,-45.2,0,40 -166.9,167,-45.2,-45.1,0,40 -166.9,167,-45.1,-45,0,40 -166.9,167,-45,-44.9,0,40 -166.9,167,-44.9,-44.8,0,40 -166.9,167,-44.8,-44.7,0,40 -166.9,167,-44.7,-44.6,0,40 -166.9,167,-44.6,-44.5,0,40 -167,167.1,-47.6,-47.5,0,40 -167,167.1,-47.5,-47.4,0,40 -167,167.1,-47.4,-47.3,0,40 -167,167.1,-47.3,-47.2,0,40 -167,167.1,-47.2,-47.1,0,40 -167,167.1,-47.1,-47,0,40 -167,167.1,-47,-46.9,0,40 -167,167.1,-46.9,-46.8,0,40 -167,167.1,-46.8,-46.7,0,40 -167,167.1,-46.7,-46.6,0,40 -167,167.1,-46.6,-46.5,0,40 -167,167.1,-46.5,-46.4,0,40 -167,167.1,-46.4,-46.3,0,40 -167,167.1,-46.3,-46.2,0,40 -167,167.1,-46.2,-46.1,0,40 -167,167.1,-46.1,-46,0,40 -167,167.1,-46,-45.9,0,40 -167,167.1,-45.9,-45.8,0,40 -167,167.1,-45.8,-45.7,0,40 -167,167.1,-45.7,-45.6,0,40 -167,167.1,-45.6,-45.5,0,40 -167,167.1,-45.5,-45.4,0,40 -167,167.1,-45.4,-45.3,0,40 -167,167.1,-45.3,-45.2,0,40 -167,167.1,-45.2,-45.1,0,40 -167,167.1,-45.1,-45,0,40 -167,167.1,-45,-44.9,0,40 -167,167.1,-44.9,-44.8,0,40 -167,167.1,-44.8,-44.7,0,40 -167,167.1,-44.7,-44.6,0,40 -167,167.1,-44.6,-44.5,0,40 -167,167.1,-44.5,-44.4,0,40 -167.1,167.2,-47.7,-47.6,0,40 -167.1,167.2,-47.6,-47.5,0,40 -167.1,167.2,-47.5,-47.4,0,40 -167.1,167.2,-47.4,-47.3,0,40 -167.1,167.2,-47.3,-47.2,0,40 -167.1,167.2,-47.2,-47.1,0,40 -167.1,167.2,-47.1,-47,0,40 -167.1,167.2,-47,-46.9,0,40 -167.1,167.2,-46.9,-46.8,0,40 -167.1,167.2,-46.8,-46.7,0,40 -167.1,167.2,-46.7,-46.6,0,40 -167.1,167.2,-46.6,-46.5,0,40 -167.1,167.2,-46.5,-46.4,0,40 -167.1,167.2,-46.4,-46.3,0,40 -167.1,167.2,-46.3,-46.2,0,40 -167.1,167.2,-46.2,-46.1,0,40 -167.1,167.2,-46.1,-46,0,40 -167.1,167.2,-46,-45.9,0,40 -167.1,167.2,-45.9,-45.8,0,40 -167.1,167.2,-45.8,-45.7,0,40 -167.1,167.2,-45.7,-45.6,0,40 -167.1,167.2,-45.6,-45.5,0,40 -167.1,167.2,-45.5,-45.4,0,40 -167.1,167.2,-45.4,-45.3,0,40 -167.1,167.2,-45.3,-45.2,0,40 -167.1,167.2,-45.2,-45.1,0,40 -167.1,167.2,-45.1,-45,0,40 -167.1,167.2,-45,-44.9,0,40 -167.1,167.2,-44.9,-44.8,0,40 -167.1,167.2,-44.8,-44.7,0,40 -167.1,167.2,-44.7,-44.6,0,40 -167.1,167.2,-44.6,-44.5,0,40 -167.1,167.2,-44.5,-44.4,0,40 -167.1,167.2,-44.4,-44.3,0,40 -167.2,167.3,-47.7,-47.6,0,40 -167.2,167.3,-47.6,-47.5,0,40 -167.2,167.3,-47.5,-47.4,0,40 -167.2,167.3,-47.4,-47.3,0,40 -167.2,167.3,-47.3,-47.2,0,40 -167.2,167.3,-47.2,-47.1,0,40 -167.2,167.3,-47.1,-47,0,40 -167.2,167.3,-47,-46.9,0,40 -167.2,167.3,-46.9,-46.8,0,40 -167.2,167.3,-46.8,-46.7,0,40 -167.2,167.3,-46.7,-46.6,0,40 -167.2,167.3,-46.6,-46.5,0,40 -167.2,167.3,-46.5,-46.4,0,40 -167.2,167.3,-46.4,-46.3,0,40 -167.2,167.3,-46.3,-46.2,0,40 -167.2,167.3,-46.2,-46.1,0,40 -167.2,167.3,-46.1,-46,0,40 -167.2,167.3,-46,-45.9,0,40 -167.2,167.3,-45.9,-45.8,0,40 -167.2,167.3,-45.8,-45.7,0,40 -167.2,167.3,-45.7,-45.6,0,40 -167.2,167.3,-45.6,-45.5,0,40 -167.2,167.3,-45.5,-45.4,0,40 -167.2,167.3,-45.4,-45.3,0,40 -167.2,167.3,-45.3,-45.2,0,40 -167.2,167.3,-45.2,-45.1,0,40 -167.2,167.3,-45.1,-45,0,40 -167.2,167.3,-45,-44.9,0,40 -167.2,167.3,-44.9,-44.8,0,40 -167.2,167.3,-44.8,-44.7,0,40 -167.2,167.3,-44.7,-44.6,0,40 -167.2,167.3,-44.6,-44.5,0,40 -167.2,167.3,-44.5,-44.4,0,40 -167.2,167.3,-44.4,-44.3,0,40 -167.2,167.3,-44.3,-44.2,0,40 -167.3,167.4,-47.8,-47.7,0,40 -167.3,167.4,-47.7,-47.6,0,40 -167.3,167.4,-47.6,-47.5,0,40 -167.3,167.4,-47.5,-47.4,0,40 -167.3,167.4,-47.4,-47.3,0,40 -167.3,167.4,-47.3,-47.2,0,40 -167.3,167.4,-47.2,-47.1,0,40 -167.3,167.4,-47.1,-47,0,40 -167.3,167.4,-47,-46.9,0,40 -167.3,167.4,-46.9,-46.8,0,40 -167.3,167.4,-46.8,-46.7,0,40 -167.3,167.4,-46.7,-46.6,0,40 -167.3,167.4,-46.6,-46.5,0,40 -167.3,167.4,-46.5,-46.4,0,40 -167.3,167.4,-46.4,-46.3,0,40 -167.3,167.4,-46.3,-46.2,0,40 -167.3,167.4,-46.2,-46.1,0,40 -167.3,167.4,-46.1,-46,0,40 -167.3,167.4,-46,-45.9,0,40 -167.3,167.4,-45.9,-45.8,0,40 -167.3,167.4,-45.8,-45.7,0,40 -167.3,167.4,-45.7,-45.6,0,40 -167.3,167.4,-45.6,-45.5,0,40 -167.3,167.4,-45.5,-45.4,0,40 -167.3,167.4,-45.4,-45.3,0,40 -167.3,167.4,-45.3,-45.2,0,40 -167.3,167.4,-45.2,-45.1,0,40 -167.3,167.4,-45.1,-45,0,40 -167.3,167.4,-45,-44.9,0,40 -167.3,167.4,-44.9,-44.8,0,40 -167.3,167.4,-44.8,-44.7,0,40 -167.3,167.4,-44.7,-44.6,0,40 -167.3,167.4,-44.6,-44.5,0,40 -167.3,167.4,-44.5,-44.4,0,40 -167.3,167.4,-44.4,-44.3,0,40 -167.3,167.4,-44.3,-44.2,0,40 -167.3,167.4,-44.2,-44.1,0,40 -167.4,167.5,-47.8,-47.7,0,40 -167.4,167.5,-47.7,-47.6,0,40 -167.4,167.5,-47.6,-47.5,0,40 -167.4,167.5,-47.5,-47.4,0,40 -167.4,167.5,-47.4,-47.3,0,40 -167.4,167.5,-47.3,-47.2,0,40 -167.4,167.5,-47.2,-47.1,0,40 -167.4,167.5,-47.1,-47,0,40 -167.4,167.5,-47,-46.9,0,40 -167.4,167.5,-46.9,-46.8,0,40 -167.4,167.5,-46.8,-46.7,0,40 -167.4,167.5,-46.7,-46.6,0,40 -167.4,167.5,-46.6,-46.5,0,40 -167.4,167.5,-46.5,-46.4,0,40 -167.4,167.5,-46.4,-46.3,0,40 -167.4,167.5,-46.3,-46.2,0,40 -167.4,167.5,-46.2,-46.1,0,40 -167.4,167.5,-46.1,-46,0,40 -167.4,167.5,-46,-45.9,0,40 -167.4,167.5,-45.9,-45.8,0,40 -167.4,167.5,-45.8,-45.7,0,40 -167.4,167.5,-45.7,-45.6,0,40 -167.4,167.5,-45.6,-45.5,0,40 -167.4,167.5,-45.5,-45.4,0,40 -167.4,167.5,-45.4,-45.3,0,40 -167.4,167.5,-45.3,-45.2,0,40 -167.4,167.5,-45.2,-45.1,0,40 -167.4,167.5,-45.1,-45,0,40 -167.4,167.5,-45,-44.9,0,40 -167.4,167.5,-44.9,-44.8,0,40 -167.4,167.5,-44.8,-44.7,0,40 -167.4,167.5,-44.7,-44.6,0,40 -167.4,167.5,-44.6,-44.5,0,40 -167.4,167.5,-44.5,-44.4,0,40 -167.4,167.5,-44.4,-44.3,0,40 -167.4,167.5,-44.3,-44.2,0,40 -167.4,167.5,-44.2,-44.1,0,40 -167.4,167.5,-44.1,-44,0,40 -167.5,167.6,-47.8,-47.7,0,40 -167.5,167.6,-47.7,-47.6,0,40 -167.5,167.6,-47.6,-47.5,0,40 -167.5,167.6,-47.5,-47.4,0,40 -167.5,167.6,-47.4,-47.3,0,40 -167.5,167.6,-47.3,-47.2,0,40 -167.5,167.6,-47.2,-47.1,0,40 -167.5,167.6,-47.1,-47,0,40 -167.5,167.6,-47,-46.9,0,40 -167.5,167.6,-46.9,-46.8,0,40 -167.5,167.6,-46.8,-46.7,0,40 -167.5,167.6,-46.7,-46.6,0,40 -167.5,167.6,-46.6,-46.5,0,40 -167.5,167.6,-46.5,-46.4,0,40 -167.5,167.6,-46.4,-46.3,0,40 -167.5,167.6,-46.3,-46.2,0,40 -167.5,167.6,-46.2,-46.1,0,40 -167.5,167.6,-46.1,-46,0,40 -167.5,167.6,-46,-45.9,0,40 -167.5,167.6,-45.9,-45.8,0,40 -167.5,167.6,-45.8,-45.7,0,40 -167.5,167.6,-45.7,-45.6,0,40 -167.5,167.6,-45.6,-45.5,0,40 -167.5,167.6,-45.5,-45.4,0,40 -167.5,167.6,-45.4,-45.3,0,40 -167.5,167.6,-45.3,-45.2,0,40 -167.5,167.6,-45.2,-45.1,0,40 -167.5,167.6,-45.1,-45,0,40 -167.5,167.6,-45,-44.9,0,40 -167.5,167.6,-44.9,-44.8,0,40 -167.5,167.6,-44.8,-44.7,0,40 -167.5,167.6,-44.7,-44.6,0,40 -167.5,167.6,-44.6,-44.5,0,40 -167.5,167.6,-44.5,-44.4,0,40 -167.5,167.6,-44.4,-44.3,0,40 -167.5,167.6,-44.3,-44.2,0,40 -167.5,167.6,-44.2,-44.1,0,40 -167.5,167.6,-44.1,-44,0,40 -167.5,167.6,-44,-43.9,0,40 -167.6,167.7,-47.8,-47.7,0,40 -167.6,167.7,-47.7,-47.6,0,40 -167.6,167.7,-47.6,-47.5,0,40 -167.6,167.7,-47.5,-47.4,0,40 -167.6,167.7,-47.4,-47.3,0,40 -167.6,167.7,-47.3,-47.2,0,40 -167.6,167.7,-47.2,-47.1,0,40 -167.6,167.7,-47.1,-47,0,40 -167.6,167.7,-47,-46.9,0,40 -167.6,167.7,-46.9,-46.8,0,40 -167.6,167.7,-46.8,-46.7,0,40 -167.6,167.7,-46.7,-46.6,0,40 -167.6,167.7,-46.6,-46.5,0,40 -167.6,167.7,-46.5,-46.4,0,40 -167.6,167.7,-46.4,-46.3,0,40 -167.6,167.7,-46.3,-46.2,0,40 -167.6,167.7,-46.2,-46.1,0,40 -167.6,167.7,-46.1,-46,0,40 -167.6,167.7,-46,-45.9,0,40 -167.6,167.7,-45.9,-45.8,0,40 -167.6,167.7,-45.8,-45.7,0,40 -167.6,167.7,-45.7,-45.6,0,40 -167.6,167.7,-45.6,-45.5,0,40 -167.6,167.7,-45.5,-45.4,0,40 -167.6,167.7,-45.4,-45.3,0,40 -167.6,167.7,-45.3,-45.2,0,40 -167.6,167.7,-45.2,-45.1,0,40 -167.6,167.7,-45.1,-45,0,40 -167.6,167.7,-45,-44.9,0,40 -167.6,167.7,-44.9,-44.8,0,40 -167.6,167.7,-44.8,-44.7,0,40 -167.6,167.7,-44.7,-44.6,0,40 -167.6,167.7,-44.6,-44.5,0,40 -167.6,167.7,-44.5,-44.4,0,40 -167.6,167.7,-44.4,-44.3,0,40 -167.6,167.7,-44.3,-44.2,0,40 -167.6,167.7,-44.2,-44.1,0,40 -167.6,167.7,-44.1,-44,0,40 -167.6,167.7,-44,-43.9,0,40 -167.6,167.7,-43.9,-43.8,0,40 -167.7,167.8,-47.8,-47.7,0,40 -167.7,167.8,-47.7,-47.6,0,40 -167.7,167.8,-47.6,-47.5,0,40 -167.7,167.8,-47.5,-47.4,0,40 -167.7,167.8,-47.4,-47.3,0,40 -167.7,167.8,-47.3,-47.2,0,40 -167.7,167.8,-47.2,-47.1,0,40 -167.7,167.8,-47.1,-47,0,40 -167.7,167.8,-47,-46.9,0,40 -167.7,167.8,-46.9,-46.8,0,40 -167.7,167.8,-46.8,-46.7,0,40 -167.7,167.8,-46.7,-46.6,0,40 -167.7,167.8,-46.6,-46.5,0,40 -167.7,167.8,-46.5,-46.4,0,40 -167.7,167.8,-46.4,-46.3,0,40 -167.7,167.8,-46.3,-46.2,0,40 -167.7,167.8,-46.2,-46.1,0,40 -167.7,167.8,-46.1,-46,0,40 -167.7,167.8,-46,-45.9,0,40 -167.7,167.8,-45.9,-45.8,0,40 -167.7,167.8,-45.8,-45.7,0,40 -167.7,167.8,-45.7,-45.6,0,40 -167.7,167.8,-45.6,-45.5,0,40 -167.7,167.8,-45.5,-45.4,0,40 -167.7,167.8,-45.4,-45.3,0,40 -167.7,167.8,-45.3,-45.2,0,40 -167.7,167.8,-45.2,-45.1,0,40 -167.7,167.8,-45.1,-45,0,40 -167.7,167.8,-45,-44.9,0,40 -167.7,167.8,-44.9,-44.8,0,40 -167.7,167.8,-44.8,-44.7,0,40 -167.7,167.8,-44.7,-44.6,0,40 -167.7,167.8,-44.6,-44.5,0,40 -167.7,167.8,-44.5,-44.4,0,40 -167.7,167.8,-44.4,-44.3,0,40 -167.7,167.8,-44.3,-44.2,0,40 -167.7,167.8,-44.2,-44.1,0,40 -167.7,167.8,-44.1,-44,0,40 -167.7,167.8,-44,-43.9,0,40 -167.7,167.8,-43.9,-43.8,0,40 -167.7,167.8,-43.8,-43.7,0,40 -167.8,167.9,-47.8,-47.7,0,40 -167.8,167.9,-47.7,-47.6,0,40 -167.8,167.9,-47.6,-47.5,0,40 -167.8,167.9,-47.5,-47.4,0,40 -167.8,167.9,-47.4,-47.3,0,40 -167.8,167.9,-47.3,-47.2,0,40 -167.8,167.9,-47.2,-47.1,0,40 -167.8,167.9,-47.1,-47,0,40 -167.8,167.9,-47,-46.9,0,40 -167.8,167.9,-46.9,-46.8,0,40 -167.8,167.9,-46.8,-46.7,0,40 -167.8,167.9,-46.7,-46.6,0,40 -167.8,167.9,-46.6,-46.5,0,40 -167.8,167.9,-46.5,-46.4,0,40 -167.8,167.9,-46.4,-46.3,0,40 -167.8,167.9,-46.3,-46.2,0,40 -167.8,167.9,-46.2,-46.1,0,40 -167.8,167.9,-46.1,-46,0,40 -167.8,167.9,-46,-45.9,0,40 -167.8,167.9,-45.9,-45.8,0,40 -167.8,167.9,-45.8,-45.7,0,40 -167.8,167.9,-45.7,-45.6,0,40 -167.8,167.9,-45.6,-45.5,0,40 -167.8,167.9,-45.5,-45.4,0,40 -167.8,167.9,-45.4,-45.3,0,40 -167.8,167.9,-45.3,-45.2,0,40 -167.8,167.9,-45.2,-45.1,0,40 -167.8,167.9,-45.1,-45,0,40 -167.8,167.9,-45,-44.9,0,40 -167.8,167.9,-44.9,-44.8,0,40 -167.8,167.9,-44.8,-44.7,0,40 -167.8,167.9,-44.7,-44.6,0,40 -167.8,167.9,-44.6,-44.5,0,40 -167.8,167.9,-44.5,-44.4,0,40 -167.8,167.9,-44.4,-44.3,0,40 -167.8,167.9,-44.3,-44.2,0,40 -167.8,167.9,-44.2,-44.1,0,40 -167.8,167.9,-44.1,-44,0,40 -167.8,167.9,-44,-43.9,0,40 -167.8,167.9,-43.9,-43.8,0,40 -167.8,167.9,-43.8,-43.7,0,40 -167.8,167.9,-43.7,-43.6,0,40 -167.9,168,-47.7,-47.6,0,40 -167.9,168,-47.6,-47.5,0,40 -167.9,168,-47.5,-47.4,0,40 -167.9,168,-47.4,-47.3,0,40 -167.9,168,-47.3,-47.2,0,40 -167.9,168,-47.2,-47.1,0,40 -167.9,168,-47.1,-47,0,40 -167.9,168,-47,-46.9,0,40 -167.9,168,-46.9,-46.8,0,40 -167.9,168,-46.8,-46.7,0,40 -167.9,168,-46.7,-46.6,0,40 -167.9,168,-46.6,-46.5,0,40 -167.9,168,-46.5,-46.4,0,40 -167.9,168,-46.4,-46.3,0,40 -167.9,168,-46.3,-46.2,0,40 -167.9,168,-46.2,-46.1,0,40 -167.9,168,-46.1,-46,0,40 -167.9,168,-46,-45.9,0,40 -167.9,168,-45.9,-45.8,0,40 -167.9,168,-45.8,-45.7,0,40 -167.9,168,-45.7,-45.6,0,40 -167.9,168,-45.6,-45.5,0,40 -167.9,168,-45.5,-45.4,0,40 -167.9,168,-45.4,-45.3,0,40 -167.9,168,-45.3,-45.2,0,40 -167.9,168,-45.2,-45.1,0,40 -167.9,168,-45.1,-45,0,40 -167.9,168,-45,-44.9,0,40 -167.9,168,-44.9,-44.8,0,40 -167.9,168,-44.8,-44.7,0,40 -167.9,168,-44.7,-44.6,0,40 -167.9,168,-44.6,-44.5,0,40 -167.9,168,-44.5,-44.4,0,40 -167.9,168,-44.4,-44.3,0,40 -167.9,168,-44.3,-44.2,0,40 -167.9,168,-44.2,-44.1,0,40 -167.9,168,-44.1,-44,0,40 -167.9,168,-44,-43.9,0,40 -167.9,168,-43.9,-43.8,0,40 -167.9,168,-43.8,-43.7,0,40 -167.9,168,-43.7,-43.6,0,40 -168,168.1,-47.7,-47.6,0,40 -168,168.1,-47.6,-47.5,0,40 -168,168.1,-47.5,-47.4,0,40 -168,168.1,-47.4,-47.3,0,40 -168,168.1,-47.3,-47.2,0,40 -168,168.1,-47.2,-47.1,0,40 -168,168.1,-47.1,-47,0,40 -168,168.1,-47,-46.9,0,40 -168,168.1,-46.9,-46.8,0,40 -168,168.1,-46.8,-46.7,0,40 -168,168.1,-46.7,-46.6,0,40 -168,168.1,-46.6,-46.5,0,40 -168,168.1,-46.5,-46.4,0,40 -168,168.1,-46.4,-46.3,0,40 -168,168.1,-46.3,-46.2,0,40 -168,168.1,-46.2,-46.1,0,40 -168,168.1,-46.1,-46,0,40 -168,168.1,-46,-45.9,0,40 -168,168.1,-45.9,-45.8,0,40 -168,168.1,-45.8,-45.7,0,40 -168,168.1,-45.7,-45.6,0,40 -168,168.1,-45.6,-45.5,0,40 -168,168.1,-45.5,-45.4,0,40 -168,168.1,-45.4,-45.3,0,40 -168,168.1,-45.3,-45.2,0,40 -168,168.1,-45.2,-45.1,0,40 -168,168.1,-45.1,-45,0,40 -168,168.1,-45,-44.9,0,40 -168,168.1,-44.9,-44.8,0,40 -168,168.1,-44.8,-44.7,0,40 -168,168.1,-44.7,-44.6,0,40 -168,168.1,-44.6,-44.5,0,40 -168,168.1,-44.5,-44.4,0,40 -168,168.1,-44.4,-44.3,0,40 -168,168.1,-44.3,-44.2,0,40 -168,168.1,-44.2,-44.1,0,40 -168,168.1,-44.1,-44,0,40 -168,168.1,-44,-43.9,0,40 -168,168.1,-43.9,-43.8,0,40 -168,168.1,-43.8,-43.7,0,40 -168,168.1,-43.7,-43.6,0,40 -168,168.1,-43.6,-43.5,0,40 -168.1,168.2,-47.7,-47.6,0,40 -168.1,168.2,-47.6,-47.5,0,40 -168.1,168.2,-47.5,-47.4,0,40 -168.1,168.2,-47.4,-47.3,0,40 -168.1,168.2,-47.3,-47.2,0,40 -168.1,168.2,-47.2,-47.1,0,40 -168.1,168.2,-47.1,-47,0,40 -168.1,168.2,-47,-46.9,0,40 -168.1,168.2,-46.9,-46.8,0,40 -168.1,168.2,-46.8,-46.7,0,40 -168.1,168.2,-46.7,-46.6,0,40 -168.1,168.2,-46.6,-46.5,0,40 -168.1,168.2,-46.5,-46.4,0,40 -168.1,168.2,-46.4,-46.3,0,40 -168.1,168.2,-46.3,-46.2,0,40 -168.1,168.2,-46.2,-46.1,0,40 -168.1,168.2,-46.1,-46,0,40 -168.1,168.2,-46,-45.9,0,40 -168.1,168.2,-45.9,-45.8,0,40 -168.1,168.2,-45.8,-45.7,0,40 -168.1,168.2,-45.7,-45.6,0,40 -168.1,168.2,-45.6,-45.5,0,40 -168.1,168.2,-45.5,-45.4,0,40 -168.1,168.2,-45.4,-45.3,0,40 -168.1,168.2,-45.3,-45.2,0,40 -168.1,168.2,-45.2,-45.1,0,40 -168.1,168.2,-45.1,-45,0,40 -168.1,168.2,-45,-44.9,0,40 -168.1,168.2,-44.9,-44.8,0,40 -168.1,168.2,-44.8,-44.7,0,40 -168.1,168.2,-44.7,-44.6,0,40 -168.1,168.2,-44.6,-44.5,0,40 -168.1,168.2,-44.5,-44.4,0,40 -168.1,168.2,-44.4,-44.3,0,40 -168.1,168.2,-44.3,-44.2,0,40 -168.1,168.2,-44.2,-44.1,0,40 -168.1,168.2,-44.1,-44,0,40 -168.1,168.2,-44,-43.9,0,40 -168.1,168.2,-43.9,-43.8,0,40 -168.1,168.2,-43.8,-43.7,0,40 -168.1,168.2,-43.7,-43.6,0,40 -168.1,168.2,-43.6,-43.5,0,40 -168.1,168.2,-43.5,-43.4,0,40 -168.2,168.3,-47.6,-47.5,0,40 -168.2,168.3,-47.5,-47.4,0,40 -168.2,168.3,-47.4,-47.3,0,40 -168.2,168.3,-47.3,-47.2,0,40 -168.2,168.3,-47.2,-47.1,0,40 -168.2,168.3,-47.1,-47,0,40 -168.2,168.3,-47,-46.9,0,40 -168.2,168.3,-46.9,-46.8,0,40 -168.2,168.3,-46.8,-46.7,0,40 -168.2,168.3,-46.7,-46.6,0,40 -168.2,168.3,-46.6,-46.5,0,40 -168.2,168.3,-46.5,-46.4,0,40 -168.2,168.3,-46.4,-46.3,0,40 -168.2,168.3,-46.3,-46.2,0,40 -168.2,168.3,-46.2,-46.1,0,40 -168.2,168.3,-46.1,-46,0,40 -168.2,168.3,-46,-45.9,0,40 -168.2,168.3,-45.9,-45.8,0,40 -168.2,168.3,-45.8,-45.7,0,40 -168.2,168.3,-45.7,-45.6,0,40 -168.2,168.3,-45.6,-45.5,0,40 -168.2,168.3,-45.5,-45.4,0,40 -168.2,168.3,-45.4,-45.3,0,40 -168.2,168.3,-45.3,-45.2,0,40 -168.2,168.3,-45.2,-45.1,0,40 -168.2,168.3,-45.1,-45,0,40 -168.2,168.3,-45,-44.9,0,40 -168.2,168.3,-44.9,-44.8,0,40 -168.2,168.3,-44.8,-44.7,0,40 -168.2,168.3,-44.7,-44.6,0,40 -168.2,168.3,-44.6,-44.5,0,40 -168.2,168.3,-44.5,-44.4,0,40 -168.2,168.3,-44.4,-44.3,0,40 -168.2,168.3,-44.3,-44.2,0,40 -168.2,168.3,-44.2,-44.1,0,40 -168.2,168.3,-44.1,-44,0,40 -168.2,168.3,-44,-43.9,0,40 -168.2,168.3,-43.9,-43.8,0,40 -168.2,168.3,-43.8,-43.7,0,40 -168.2,168.3,-43.7,-43.6,0,40 -168.2,168.3,-43.6,-43.5,0,40 -168.2,168.3,-43.5,-43.4,0,40 -168.2,168.3,-43.4,-43.3,0,40 -168.3,168.4,-47.6,-47.5,0,40 -168.3,168.4,-47.5,-47.4,0,40 -168.3,168.4,-47.4,-47.3,0,40 -168.3,168.4,-47.3,-47.2,0,40 -168.3,168.4,-47.2,-47.1,0,40 -168.3,168.4,-47.1,-47,0,40 -168.3,168.4,-47,-46.9,0,40 -168.3,168.4,-46.9,-46.8,0,40 -168.3,168.4,-46.8,-46.7,0,40 -168.3,168.4,-46.7,-46.6,0,40 -168.3,168.4,-46.6,-46.5,0,40 -168.3,168.4,-46.5,-46.4,0,40 -168.3,168.4,-46.4,-46.3,0,40 -168.3,168.4,-46.3,-46.2,0,40 -168.3,168.4,-46.2,-46.1,0,40 -168.3,168.4,-46.1,-46,0,40 -168.3,168.4,-46,-45.9,0,40 -168.3,168.4,-45.9,-45.8,0,40 -168.3,168.4,-45.8,-45.7,0,40 -168.3,168.4,-45.7,-45.6,0,40 -168.3,168.4,-45.6,-45.5,0,40 -168.3,168.4,-45.5,-45.4,0,40 -168.3,168.4,-45.4,-45.3,0,40 -168.3,168.4,-45.3,-45.2,0,40 -168.3,168.4,-45.2,-45.1,0,40 -168.3,168.4,-45.1,-45,0,40 -168.3,168.4,-45,-44.9,0,40 -168.3,168.4,-44.9,-44.8,0,40 -168.3,168.4,-44.8,-44.7,0,40 -168.3,168.4,-44.7,-44.6,0,40 -168.3,168.4,-44.6,-44.5,0,40 -168.3,168.4,-44.5,-44.4,0,40 -168.3,168.4,-44.4,-44.3,0,40 -168.3,168.4,-44.3,-44.2,0,40 -168.3,168.4,-44.2,-44.1,0,40 -168.3,168.4,-44.1,-44,0,40 -168.3,168.4,-44,-43.9,0,40 -168.3,168.4,-43.9,-43.8,0,40 -168.3,168.4,-43.8,-43.7,0,40 -168.3,168.4,-43.7,-43.6,0,40 -168.3,168.4,-43.6,-43.5,0,40 -168.3,168.4,-43.5,-43.4,0,40 -168.3,168.4,-43.4,-43.3,0,40 -168.3,168.4,-43.3,-43.2,0,40 -168.4,168.5,-47.5,-47.4,0,40 -168.4,168.5,-47.4,-47.3,0,40 -168.4,168.5,-47.3,-47.2,0,40 -168.4,168.5,-47.2,-47.1,0,40 -168.4,168.5,-47.1,-47,0,40 -168.4,168.5,-47,-46.9,0,40 -168.4,168.5,-46.9,-46.8,0,40 -168.4,168.5,-46.8,-46.7,0,40 -168.4,168.5,-46.7,-46.6,0,40 -168.4,168.5,-46.6,-46.5,0,40 -168.4,168.5,-46.5,-46.4,0,40 -168.4,168.5,-46.4,-46.3,0,40 -168.4,168.5,-46.3,-46.2,0,40 -168.4,168.5,-46.2,-46.1,0,40 -168.4,168.5,-46.1,-46,0,40 -168.4,168.5,-46,-45.9,0,40 -168.4,168.5,-45.9,-45.8,0,40 -168.4,168.5,-45.8,-45.7,0,40 -168.4,168.5,-45.7,-45.6,0,40 -168.4,168.5,-45.6,-45.5,0,40 -168.4,168.5,-45.5,-45.4,0,40 -168.4,168.5,-45.4,-45.3,0,40 -168.4,168.5,-45.3,-45.2,0,40 -168.4,168.5,-45.2,-45.1,0,40 -168.4,168.5,-45.1,-45,0,40 -168.4,168.5,-45,-44.9,0,40 -168.4,168.5,-44.9,-44.8,0,40 -168.4,168.5,-44.8,-44.7,0,40 -168.4,168.5,-44.7,-44.6,0,40 -168.4,168.5,-44.6,-44.5,0,40 -168.4,168.5,-44.5,-44.4,0,40 -168.4,168.5,-44.4,-44.3,0,40 -168.4,168.5,-44.3,-44.2,0,40 -168.4,168.5,-44.2,-44.1,0,40 -168.4,168.5,-44.1,-44,0,40 -168.4,168.5,-44,-43.9,0,40 -168.4,168.5,-43.9,-43.8,0,40 -168.4,168.5,-43.8,-43.7,0,40 -168.4,168.5,-43.7,-43.6,0,40 -168.4,168.5,-43.6,-43.5,0,40 -168.4,168.5,-43.5,-43.4,0,40 -168.4,168.5,-43.4,-43.3,0,40 -168.4,168.5,-43.3,-43.2,0,40 -168.4,168.5,-43.2,-43.1,0,40 -168.5,168.6,-47.5,-47.4,0,40 -168.5,168.6,-47.4,-47.3,0,40 -168.5,168.6,-47.3,-47.2,0,40 -168.5,168.6,-47.2,-47.1,0,40 -168.5,168.6,-47.1,-47,0,40 -168.5,168.6,-47,-46.9,0,40 -168.5,168.6,-46.9,-46.8,0,40 -168.5,168.6,-46.8,-46.7,0,40 -168.5,168.6,-46.7,-46.6,0,40 -168.5,168.6,-46.6,-46.5,0,40 -168.5,168.6,-46.5,-46.4,0,40 -168.5,168.6,-46.4,-46.3,0,40 -168.5,168.6,-46.3,-46.2,0,40 -168.5,168.6,-46.2,-46.1,0,40 -168.5,168.6,-46.1,-46,0,40 -168.5,168.6,-46,-45.9,0,40 -168.5,168.6,-45.9,-45.8,0,40 -168.5,168.6,-45.8,-45.7,0,40 -168.5,168.6,-45.7,-45.6,0,40 -168.5,168.6,-45.6,-45.5,0,40 -168.5,168.6,-45.5,-45.4,0,40 -168.5,168.6,-45.4,-45.3,0,40 -168.5,168.6,-45.3,-45.2,0,40 -168.5,168.6,-45.2,-45.1,0,40 -168.5,168.6,-45.1,-45,0,40 -168.5,168.6,-45,-44.9,0,40 -168.5,168.6,-44.9,-44.8,0,40 -168.5,168.6,-44.8,-44.7,0,40 -168.5,168.6,-44.7,-44.6,0,40 -168.5,168.6,-44.6,-44.5,0,40 -168.5,168.6,-44.5,-44.4,0,40 -168.5,168.6,-44.4,-44.3,0,40 -168.5,168.6,-44.3,-44.2,0,40 -168.5,168.6,-44.2,-44.1,0,40 -168.5,168.6,-44.1,-44,0,40 -168.5,168.6,-44,-43.9,0,40 -168.5,168.6,-43.9,-43.8,0,40 -168.5,168.6,-43.8,-43.7,0,40 -168.5,168.6,-43.7,-43.6,0,40 -168.5,168.6,-43.6,-43.5,0,40 -168.5,168.6,-43.5,-43.4,0,40 -168.5,168.6,-43.4,-43.3,0,40 -168.5,168.6,-43.3,-43.2,0,40 -168.5,168.6,-43.2,-43.1,0,40 -168.5,168.6,-43.1,-43,0,40 -168.6,168.7,-47.4,-47.3,0,40 -168.6,168.7,-47.3,-47.2,0,40 -168.6,168.7,-47.2,-47.1,0,40 -168.6,168.7,-47.1,-47,0,40 -168.6,168.7,-47,-46.9,0,40 -168.6,168.7,-46.9,-46.8,0,40 -168.6,168.7,-46.8,-46.7,0,40 -168.6,168.7,-46.7,-46.6,0,40 -168.6,168.7,-46.6,-46.5,0,40 -168.6,168.7,-46.5,-46.4,0,40 -168.6,168.7,-46.4,-46.3,0,40 -168.6,168.7,-46.3,-46.2,0,40 -168.6,168.7,-46.2,-46.1,0,40 -168.6,168.7,-46.1,-46,0,40 -168.6,168.7,-46,-45.9,0,40 -168.6,168.7,-45.9,-45.8,0,40 -168.6,168.7,-45.8,-45.7,0,40 -168.6,168.7,-45.7,-45.6,0,40 -168.6,168.7,-45.6,-45.5,0,40 -168.6,168.7,-45.5,-45.4,0,40 -168.6,168.7,-45.4,-45.3,0,40 -168.6,168.7,-45.3,-45.2,0,40 -168.6,168.7,-45.2,-45.1,0,40 -168.6,168.7,-45.1,-45,0,40 -168.6,168.7,-45,-44.9,0,40 -168.6,168.7,-44.9,-44.8,0,40 -168.6,168.7,-44.8,-44.7,0,40 -168.6,168.7,-44.7,-44.6,0,40 -168.6,168.7,-44.6,-44.5,0,40 -168.6,168.7,-44.5,-44.4,0,40 -168.6,168.7,-44.4,-44.3,0,40 -168.6,168.7,-44.3,-44.2,0,40 -168.6,168.7,-44.2,-44.1,0,40 -168.6,168.7,-44.1,-44,0,40 -168.6,168.7,-44,-43.9,0,40 -168.6,168.7,-43.9,-43.8,0,40 -168.6,168.7,-43.8,-43.7,0,40 -168.6,168.7,-43.7,-43.6,0,40 -168.6,168.7,-43.6,-43.5,0,40 -168.6,168.7,-43.5,-43.4,0,40 -168.6,168.7,-43.4,-43.3,0,40 -168.6,168.7,-43.3,-43.2,0,40 -168.6,168.7,-43.2,-43.1,0,40 -168.6,168.7,-43.1,-43,0,40 -168.7,168.8,-47.3,-47.2,0,40 -168.7,168.8,-47.2,-47.1,0,40 -168.7,168.8,-47.1,-47,0,40 -168.7,168.8,-47,-46.9,0,40 -168.7,168.8,-46.9,-46.8,0,40 -168.7,168.8,-46.8,-46.7,0,40 -168.7,168.8,-46.7,-46.6,0,40 -168.7,168.8,-46.6,-46.5,0,40 -168.7,168.8,-46.5,-46.4,0,40 -168.7,168.8,-46.4,-46.3,0,40 -168.7,168.8,-46.3,-46.2,0,40 -168.7,168.8,-46.2,-46.1,0,40 -168.7,168.8,-46.1,-46,0,40 -168.7,168.8,-46,-45.9,0,40 -168.7,168.8,-45.9,-45.8,0,40 -168.7,168.8,-45.8,-45.7,0,40 -168.7,168.8,-45.7,-45.6,0,40 -168.7,168.8,-45.6,-45.5,0,40 -168.7,168.8,-45.5,-45.4,0,40 -168.7,168.8,-45.4,-45.3,0,40 -168.7,168.8,-45.3,-45.2,0,40 -168.7,168.8,-45.2,-45.1,0,40 -168.7,168.8,-45.1,-45,0,40 -168.7,168.8,-45,-44.9,0,40 -168.7,168.8,-44.9,-44.8,0,40 -168.7,168.8,-44.8,-44.7,0,40 -168.7,168.8,-44.7,-44.6,0,40 -168.7,168.8,-44.6,-44.5,0,40 -168.7,168.8,-44.5,-44.4,0,40 -168.7,168.8,-44.4,-44.3,0,40 -168.7,168.8,-44.3,-44.2,0,40 -168.7,168.8,-44.2,-44.1,0,40 -168.7,168.8,-44.1,-44,0,40 -168.7,168.8,-44,-43.9,0,40 -168.7,168.8,-43.9,-43.8,0,40 -168.7,168.8,-43.8,-43.7,0,40 -168.7,168.8,-43.7,-43.6,0,40 -168.7,168.8,-43.6,-43.5,0,40 -168.7,168.8,-43.5,-43.4,0,40 -168.7,168.8,-43.4,-43.3,0,40 -168.7,168.8,-43.3,-43.2,0,40 -168.7,168.8,-43.2,-43.1,0,40 -168.7,168.8,-43.1,-43,0,40 -168.7,168.8,-43,-42.9,0,40 -168.8,168.9,-47.2,-47.1,0,40 -168.8,168.9,-47.1,-47,0,40 -168.8,168.9,-47,-46.9,0,40 -168.8,168.9,-46.9,-46.8,0,40 -168.8,168.9,-46.8,-46.7,0,40 -168.8,168.9,-46.7,-46.6,0,40 -168.8,168.9,-46.6,-46.5,0,40 -168.8,168.9,-46.5,-46.4,0,40 -168.8,168.9,-46.4,-46.3,0,40 -168.8,168.9,-46.3,-46.2,0,40 -168.8,168.9,-46.2,-46.1,0,40 -168.8,168.9,-46.1,-46,0,40 -168.8,168.9,-46,-45.9,0,40 -168.8,168.9,-45.9,-45.8,0,40 -168.8,168.9,-45.8,-45.7,0,40 -168.8,168.9,-45.7,-45.6,0,40 -168.8,168.9,-45.6,-45.5,0,40 -168.8,168.9,-45.5,-45.4,0,40 -168.8,168.9,-45.4,-45.3,0,40 -168.8,168.9,-45.3,-45.2,0,40 -168.8,168.9,-45.2,-45.1,0,40 -168.8,168.9,-45.1,-45,0,40 -168.8,168.9,-45,-44.9,0,40 -168.8,168.9,-44.9,-44.8,0,40 -168.8,168.9,-44.8,-44.7,0,40 -168.8,168.9,-44.7,-44.6,0,40 -168.8,168.9,-44.6,-44.5,0,40 -168.8,168.9,-44.5,-44.4,0,40 -168.8,168.9,-44.4,-44.3,0,40 -168.8,168.9,-44.3,-44.2,0,40 -168.8,168.9,-44.2,-44.1,0,40 -168.8,168.9,-44.1,-44,0,40 -168.8,168.9,-44,-43.9,0,40 -168.8,168.9,-43.9,-43.8,0,40 -168.8,168.9,-43.8,-43.7,0,40 -168.8,168.9,-43.7,-43.6,0,40 -168.8,168.9,-43.6,-43.5,0,40 -168.8,168.9,-43.5,-43.4,0,40 -168.8,168.9,-43.4,-43.3,0,40 -168.8,168.9,-43.3,-43.2,0,40 -168.8,168.9,-43.2,-43.1,0,40 -168.8,168.9,-43.1,-43,0,40 -168.8,168.9,-43,-42.9,0,40 -168.8,168.9,-42.9,-42.8,0,40 -168.9,169,-47.1,-47,0,40 -168.9,169,-47,-46.9,0,40 -168.9,169,-46.9,-46.8,0,40 -168.9,169,-46.8,-46.7,0,40 -168.9,169,-46.7,-46.6,0,40 -168.9,169,-46.6,-46.5,0,40 -168.9,169,-46.5,-46.4,0,40 -168.9,169,-46.4,-46.3,0,40 -168.9,169,-46.3,-46.2,0,40 -168.9,169,-46.2,-46.1,0,40 -168.9,169,-46.1,-46,0,40 -168.9,169,-46,-45.9,0,40 -168.9,169,-45.9,-45.8,0,40 -168.9,169,-45.8,-45.7,0,40 -168.9,169,-45.7,-45.6,0,40 -168.9,169,-45.6,-45.5,0,40 -168.9,169,-45.5,-45.4,0,40 -168.9,169,-45.4,-45.3,0,40 -168.9,169,-45.3,-45.2,0,40 -168.9,169,-45.2,-45.1,0,40 -168.9,169,-45.1,-45,0,40 -168.9,169,-45,-44.9,0,40 -168.9,169,-44.9,-44.8,0,40 -168.9,169,-44.8,-44.7,0,40 -168.9,169,-44.7,-44.6,0,40 -168.9,169,-44.6,-44.5,0,40 -168.9,169,-44.5,-44.4,0,40 -168.9,169,-44.4,-44.3,0,40 -168.9,169,-44.3,-44.2,0,40 -168.9,169,-44.2,-44.1,0,40 -168.9,169,-44.1,-44,0,40 -168.9,169,-44,-43.9,0,40 -168.9,169,-43.9,-43.8,0,40 -168.9,169,-43.8,-43.7,0,40 -168.9,169,-43.7,-43.6,0,40 -168.9,169,-43.6,-43.5,0,40 -168.9,169,-43.5,-43.4,0,40 -168.9,169,-43.4,-43.3,0,40 -168.9,169,-43.3,-43.2,0,40 -168.9,169,-43.2,-43.1,0,40 -168.9,169,-43.1,-43,0,40 -168.9,169,-43,-42.9,0,40 -168.9,169,-42.9,-42.8,0,40 -168.9,169,-42.8,-42.7,0,40 -169,169.1,-47.1,-47,0,40 -169,169.1,-47,-46.9,0,40 -169,169.1,-46.9,-46.8,0,40 -169,169.1,-46.8,-46.7,0,40 -169,169.1,-46.7,-46.6,0,40 -169,169.1,-46.6,-46.5,0,40 -169,169.1,-46.5,-46.4,0,40 -169,169.1,-46.4,-46.3,0,40 -169,169.1,-46.3,-46.2,0,40 -169,169.1,-46.2,-46.1,0,40 -169,169.1,-46.1,-46,0,40 -169,169.1,-46,-45.9,0,40 -169,169.1,-45.9,-45.8,0,40 -169,169.1,-45.8,-45.7,0,40 -169,169.1,-45.7,-45.6,0,40 -169,169.1,-45.6,-45.5,0,40 -169,169.1,-45.5,-45.4,0,40 -169,169.1,-45.4,-45.3,0,40 -169,169.1,-45.3,-45.2,0,40 -169,169.1,-45.2,-45.1,0,40 -169,169.1,-45.1,-45,0,40 -169,169.1,-45,-44.9,0,40 -169,169.1,-44.9,-44.8,0,40 -169,169.1,-44.8,-44.7,0,40 -169,169.1,-44.7,-44.6,0,40 -169,169.1,-44.6,-44.5,0,40 -169,169.1,-44.5,-44.4,0,40 -169,169.1,-44.4,-44.3,0,40 -169,169.1,-44.3,-44.2,0,40 -169,169.1,-44.2,-44.1,0,40 -169,169.1,-44.1,-44,0,40 -169,169.1,-44,-43.9,0,40 -169,169.1,-43.9,-43.8,0,40 -169,169.1,-43.8,-43.7,0,40 -169,169.1,-43.7,-43.6,0,40 -169,169.1,-43.6,-43.5,0,40 -169,169.1,-43.5,-43.4,0,40 -169,169.1,-43.4,-43.3,0,40 -169,169.1,-43.3,-43.2,0,40 -169,169.1,-43.2,-43.1,0,40 -169,169.1,-43.1,-43,0,40 -169,169.1,-43,-42.9,0,40 -169,169.1,-42.9,-42.8,0,40 -169,169.1,-42.8,-42.7,0,40 -169,169.1,-42.7,-42.6,0,40 -169.1,169.2,-47.1,-47,0,40 -169.1,169.2,-47,-46.9,0,40 -169.1,169.2,-46.9,-46.8,0,40 -169.1,169.2,-46.8,-46.7,0,40 -169.1,169.2,-46.7,-46.6,0,40 -169.1,169.2,-46.6,-46.5,0,40 -169.1,169.2,-46.5,-46.4,0,40 -169.1,169.2,-46.4,-46.3,0,40 -169.1,169.2,-46.3,-46.2,0,40 -169.1,169.2,-46.2,-46.1,0,40 -169.1,169.2,-46.1,-46,0,40 -169.1,169.2,-46,-45.9,0,40 -169.1,169.2,-45.9,-45.8,0,40 -169.1,169.2,-45.8,-45.7,0,40 -169.1,169.2,-45.7,-45.6,0,40 -169.1,169.2,-45.6,-45.5,0,40 -169.1,169.2,-45.5,-45.4,0,40 -169.1,169.2,-45.4,-45.3,0,40 -169.1,169.2,-45.3,-45.2,0,40 -169.1,169.2,-45.2,-45.1,0,40 -169.1,169.2,-45.1,-45,0,40 -169.1,169.2,-45,-44.9,0,40 -169.1,169.2,-44.9,-44.8,0,40 -169.1,169.2,-44.8,-44.7,0,40 -169.1,169.2,-44.7,-44.6,0,40 -169.1,169.2,-44.6,-44.5,0,40 -169.1,169.2,-44.5,-44.4,0,40 -169.1,169.2,-44.4,-44.3,0,40 -169.1,169.2,-44.3,-44.2,0,40 -169.1,169.2,-44.2,-44.1,0,40 -169.1,169.2,-44.1,-44,0,40 -169.1,169.2,-44,-43.9,0,40 -169.1,169.2,-43.9,-43.8,0,40 -169.1,169.2,-43.8,-43.7,0,40 -169.1,169.2,-43.7,-43.6,0,40 -169.1,169.2,-43.6,-43.5,0,40 -169.1,169.2,-43.5,-43.4,0,40 -169.1,169.2,-43.4,-43.3,0,40 -169.1,169.2,-43.3,-43.2,0,40 -169.1,169.2,-43.2,-43.1,0,40 -169.1,169.2,-43.1,-43,0,40 -169.1,169.2,-43,-42.9,0,40 -169.1,169.2,-42.9,-42.8,0,40 -169.1,169.2,-42.8,-42.7,0,40 -169.1,169.2,-42.7,-42.6,0,40 -169.1,169.2,-42.6,-42.5,0,40 -169.2,169.3,-47.1,-47,0,40 -169.2,169.3,-47,-46.9,0,40 -169.2,169.3,-46.9,-46.8,0,40 -169.2,169.3,-46.8,-46.7,0,40 -169.2,169.3,-46.7,-46.6,0,40 -169.2,169.3,-46.6,-46.5,0,40 -169.2,169.3,-46.5,-46.4,0,40 -169.2,169.3,-46.4,-46.3,0,40 -169.2,169.3,-46.3,-46.2,0,40 -169.2,169.3,-46.2,-46.1,0,40 -169.2,169.3,-46.1,-46,0,40 -169.2,169.3,-46,-45.9,0,40 -169.2,169.3,-45.9,-45.8,0,40 -169.2,169.3,-45.8,-45.7,0,40 -169.2,169.3,-45.7,-45.6,0,40 -169.2,169.3,-45.6,-45.5,0,40 -169.2,169.3,-45.5,-45.4,0,40 -169.2,169.3,-45.4,-45.3,0,40 -169.2,169.3,-45.3,-45.2,0,40 -169.2,169.3,-45.2,-45.1,0,40 -169.2,169.3,-45.1,-45,0,40 -169.2,169.3,-45,-44.9,0,40 -169.2,169.3,-44.9,-44.8,0,40 -169.2,169.3,-44.8,-44.7,0,40 -169.2,169.3,-44.7,-44.6,0,40 -169.2,169.3,-44.6,-44.5,0,40 -169.2,169.3,-44.5,-44.4,0,40 -169.2,169.3,-44.4,-44.3,0,40 -169.2,169.3,-44.3,-44.2,0,40 -169.2,169.3,-44.2,-44.1,0,40 -169.2,169.3,-44.1,-44,0,40 -169.2,169.3,-44,-43.9,0,40 -169.2,169.3,-43.9,-43.8,0,40 -169.2,169.3,-43.8,-43.7,0,40 -169.2,169.3,-43.7,-43.6,0,40 -169.2,169.3,-43.6,-43.5,0,40 -169.2,169.3,-43.5,-43.4,0,40 -169.2,169.3,-43.4,-43.3,0,40 -169.2,169.3,-43.3,-43.2,0,40 -169.2,169.3,-43.2,-43.1,0,40 -169.2,169.3,-43.1,-43,0,40 -169.2,169.3,-43,-42.9,0,40 -169.2,169.3,-42.9,-42.8,0,40 -169.2,169.3,-42.8,-42.7,0,40 -169.2,169.3,-42.7,-42.6,0,40 -169.2,169.3,-42.6,-42.5,0,40 -169.2,169.3,-42.5,-42.4,0,40 -169.3,169.4,-47.1,-47,0,40 -169.3,169.4,-47,-46.9,0,40 -169.3,169.4,-46.9,-46.8,0,40 -169.3,169.4,-46.8,-46.7,0,40 -169.3,169.4,-46.7,-46.6,0,40 -169.3,169.4,-46.6,-46.5,0,40 -169.3,169.4,-46.5,-46.4,0,40 -169.3,169.4,-46.4,-46.3,0,40 -169.3,169.4,-46.3,-46.2,0,40 -169.3,169.4,-46.2,-46.1,0,40 -169.3,169.4,-46.1,-46,0,40 -169.3,169.4,-46,-45.9,0,40 -169.3,169.4,-45.9,-45.8,0,40 -169.3,169.4,-45.8,-45.7,0,40 -169.3,169.4,-45.7,-45.6,0,40 -169.3,169.4,-45.6,-45.5,0,40 -169.3,169.4,-45.5,-45.4,0,40 -169.3,169.4,-45.4,-45.3,0,40 -169.3,169.4,-45.3,-45.2,0,40 -169.3,169.4,-45.2,-45.1,0,40 -169.3,169.4,-45.1,-45,0,40 -169.3,169.4,-45,-44.9,0,40 -169.3,169.4,-44.9,-44.8,0,40 -169.3,169.4,-44.8,-44.7,0,40 -169.3,169.4,-44.7,-44.6,0,40 -169.3,169.4,-44.6,-44.5,0,40 -169.3,169.4,-44.5,-44.4,0,40 -169.3,169.4,-44.4,-44.3,0,40 -169.3,169.4,-44.3,-44.2,0,40 -169.3,169.4,-44.2,-44.1,0,40 -169.3,169.4,-44.1,-44,0,40 -169.3,169.4,-44,-43.9,0,40 -169.3,169.4,-43.9,-43.8,0,40 -169.3,169.4,-43.8,-43.7,0,40 -169.3,169.4,-43.7,-43.6,0,40 -169.3,169.4,-43.6,-43.5,0,40 -169.3,169.4,-43.5,-43.4,0,40 -169.3,169.4,-43.4,-43.3,0,40 -169.3,169.4,-43.3,-43.2,0,40 -169.3,169.4,-43.2,-43.1,0,40 -169.3,169.4,-43.1,-43,0,40 -169.3,169.4,-43,-42.9,0,40 -169.3,169.4,-42.9,-42.8,0,40 -169.3,169.4,-42.8,-42.7,0,40 -169.3,169.4,-42.7,-42.6,0,40 -169.3,169.4,-42.6,-42.5,0,40 -169.3,169.4,-42.5,-42.4,0,40 -169.4,169.5,-47.1,-47,0,40 -169.4,169.5,-47,-46.9,0,40 -169.4,169.5,-46.9,-46.8,0,40 -169.4,169.5,-46.8,-46.7,0,40 -169.4,169.5,-46.7,-46.6,0,40 -169.4,169.5,-46.6,-46.5,0,40 -169.4,169.5,-46.5,-46.4,0,40 -169.4,169.5,-46.4,-46.3,0,40 -169.4,169.5,-46.3,-46.2,0,40 -169.4,169.5,-46.2,-46.1,0,40 -169.4,169.5,-46.1,-46,0,40 -169.4,169.5,-46,-45.9,0,40 -169.4,169.5,-45.9,-45.8,0,40 -169.4,169.5,-45.8,-45.7,0,40 -169.4,169.5,-45.7,-45.6,0,40 -169.4,169.5,-45.6,-45.5,0,40 -169.4,169.5,-45.5,-45.4,0,40 -169.4,169.5,-45.4,-45.3,0,40 -169.4,169.5,-45.3,-45.2,0,40 -169.4,169.5,-45.2,-45.1,0,40 -169.4,169.5,-45.1,-45,0,40 -169.4,169.5,-45,-44.9,0,40 -169.4,169.5,-44.9,-44.8,0,40 -169.4,169.5,-44.8,-44.7,0,40 -169.4,169.5,-44.7,-44.6,0,40 -169.4,169.5,-44.6,-44.5,0,40 -169.4,169.5,-44.5,-44.4,0,40 -169.4,169.5,-44.4,-44.3,0,40 -169.4,169.5,-44.3,-44.2,0,40 -169.4,169.5,-44.2,-44.1,0,40 -169.4,169.5,-44.1,-44,0,40 -169.4,169.5,-44,-43.9,0,40 -169.4,169.5,-43.9,-43.8,0,40 -169.4,169.5,-43.8,-43.7,0,40 -169.4,169.5,-43.7,-43.6,0,40 -169.4,169.5,-43.6,-43.5,0,40 -169.4,169.5,-43.5,-43.4,0,40 -169.4,169.5,-43.4,-43.3,0,40 -169.4,169.5,-43.3,-43.2,0,40 -169.4,169.5,-43.2,-43.1,0,40 -169.4,169.5,-43.1,-43,0,40 -169.4,169.5,-43,-42.9,0,40 -169.4,169.5,-42.9,-42.8,0,40 -169.4,169.5,-42.8,-42.7,0,40 -169.4,169.5,-42.7,-42.6,0,40 -169.4,169.5,-42.6,-42.5,0,40 -169.4,169.5,-42.5,-42.4,0,40 -169.4,169.5,-42.4,-42.3,0,40 -169.5,169.6,-47.1,-47,0,40 -169.5,169.6,-47,-46.9,0,40 -169.5,169.6,-46.9,-46.8,0,40 -169.5,169.6,-46.8,-46.7,0,40 -169.5,169.6,-46.7,-46.6,0,40 -169.5,169.6,-46.6,-46.5,0,40 -169.5,169.6,-46.5,-46.4,0,40 -169.5,169.6,-46.4,-46.3,0,40 -169.5,169.6,-46.3,-46.2,0,40 -169.5,169.6,-46.2,-46.1,0,40 -169.5,169.6,-46.1,-46,0,40 -169.5,169.6,-46,-45.9,0,40 -169.5,169.6,-45.9,-45.8,0,40 -169.5,169.6,-45.8,-45.7,0,40 -169.5,169.6,-45.7,-45.6,0,40 -169.5,169.6,-45.6,-45.5,0,40 -169.5,169.6,-45.5,-45.4,0,40 -169.5,169.6,-45.4,-45.3,0,40 -169.5,169.6,-45.3,-45.2,0,40 -169.5,169.6,-45.2,-45.1,0,40 -169.5,169.6,-45.1,-45,0,40 -169.5,169.6,-45,-44.9,0,40 -169.5,169.6,-44.9,-44.8,0,40 -169.5,169.6,-44.8,-44.7,0,40 -169.5,169.6,-44.7,-44.6,0,40 -169.5,169.6,-44.6,-44.5,0,40 -169.5,169.6,-44.5,-44.4,0,40 -169.5,169.6,-44.4,-44.3,0,40 -169.5,169.6,-44.3,-44.2,0,40 -169.5,169.6,-44.2,-44.1,0,40 -169.5,169.6,-44.1,-44,0,40 -169.5,169.6,-44,-43.9,0,40 -169.5,169.6,-43.9,-43.8,0,40 -169.5,169.6,-43.8,-43.7,0,40 -169.5,169.6,-43.7,-43.6,0,40 -169.5,169.6,-43.6,-43.5,0,40 -169.5,169.6,-43.5,-43.4,0,40 -169.5,169.6,-43.4,-43.3,0,40 -169.5,169.6,-43.3,-43.2,0,40 -169.5,169.6,-43.2,-43.1,0,40 -169.5,169.6,-43.1,-43,0,40 -169.5,169.6,-43,-42.9,0,40 -169.5,169.6,-42.9,-42.8,0,40 -169.5,169.6,-42.8,-42.7,0,40 -169.5,169.6,-42.7,-42.6,0,40 -169.5,169.6,-42.6,-42.5,0,40 -169.5,169.6,-42.5,-42.4,0,40 -169.5,169.6,-42.4,-42.3,0,40 -169.5,169.6,-42.3,-42.2,0,40 -169.6,169.7,-47.1,-47,0,40 -169.6,169.7,-47,-46.9,0,40 -169.6,169.7,-46.9,-46.8,0,40 -169.6,169.7,-46.8,-46.7,0,40 -169.6,169.7,-46.7,-46.6,0,40 -169.6,169.7,-46.6,-46.5,0,40 -169.6,169.7,-46.5,-46.4,0,40 -169.6,169.7,-46.4,-46.3,0,40 -169.6,169.7,-46.3,-46.2,0,40 -169.6,169.7,-46.2,-46.1,0,40 -169.6,169.7,-46.1,-46,0,40 -169.6,169.7,-46,-45.9,0,40 -169.6,169.7,-45.9,-45.8,0,40 -169.6,169.7,-45.8,-45.7,0,40 -169.6,169.7,-45.7,-45.6,0,40 -169.6,169.7,-45.6,-45.5,0,40 -169.6,169.7,-45.5,-45.4,0,40 -169.6,169.7,-45.4,-45.3,0,40 -169.6,169.7,-45.3,-45.2,0,40 -169.6,169.7,-45.2,-45.1,0,40 -169.6,169.7,-45.1,-45,0,40 -169.6,169.7,-45,-44.9,0,40 -169.6,169.7,-44.9,-44.8,0,40 -169.6,169.7,-44.8,-44.7,0,40 -169.6,169.7,-44.7,-44.6,0,40 -169.6,169.7,-44.6,-44.5,0,40 -169.6,169.7,-44.5,-44.4,0,40 -169.6,169.7,-44.4,-44.3,0,40 -169.6,169.7,-44.3,-44.2,0,40 -169.6,169.7,-44.2,-44.1,0,40 -169.6,169.7,-44.1,-44,0,40 -169.6,169.7,-44,-43.9,0,40 -169.6,169.7,-43.9,-43.8,0,40 -169.6,169.7,-43.8,-43.7,0,40 -169.6,169.7,-43.7,-43.6,0,40 -169.6,169.7,-43.6,-43.5,0,40 -169.6,169.7,-43.5,-43.4,0,40 -169.6,169.7,-43.4,-43.3,0,40 -169.6,169.7,-43.3,-43.2,0,40 -169.6,169.7,-43.2,-43.1,0,40 -169.6,169.7,-43.1,-43,0,40 -169.6,169.7,-43,-42.9,0,40 -169.6,169.7,-42.9,-42.8,0,40 -169.6,169.7,-42.8,-42.7,0,40 -169.6,169.7,-42.7,-42.6,0,40 -169.6,169.7,-42.6,-42.5,0,40 -169.6,169.7,-42.5,-42.4,0,40 -169.6,169.7,-42.4,-42.3,0,40 -169.6,169.7,-42.3,-42.2,0,40 -169.6,169.7,-42.2,-42.1,0,40 -169.7,169.8,-47,-46.9,0,40 -169.7,169.8,-46.9,-46.8,0,40 -169.7,169.8,-46.8,-46.7,0,40 -169.7,169.8,-46.7,-46.6,0,40 -169.7,169.8,-46.6,-46.5,0,40 -169.7,169.8,-46.5,-46.4,0,40 -169.7,169.8,-46.4,-46.3,0,40 -169.7,169.8,-46.3,-46.2,0,40 -169.7,169.8,-46.2,-46.1,0,40 -169.7,169.8,-46.1,-46,0,40 -169.7,169.8,-46,-45.9,0,40 -169.7,169.8,-45.9,-45.8,0,40 -169.7,169.8,-45.8,-45.7,0,40 -169.7,169.8,-45.7,-45.6,0,40 -169.7,169.8,-45.6,-45.5,0,40 -169.7,169.8,-45.5,-45.4,0,40 -169.7,169.8,-45.4,-45.3,0,40 -169.7,169.8,-45.3,-45.2,0,40 -169.7,169.8,-45.2,-45.1,0,40 -169.7,169.8,-45.1,-45,0,40 -169.7,169.8,-45,-44.9,0,40 -169.7,169.8,-44.9,-44.8,0,40 -169.7,169.8,-44.8,-44.7,0,40 -169.7,169.8,-44.7,-44.6,0,40 -169.7,169.8,-44.6,-44.5,0,40 -169.7,169.8,-44.5,-44.4,0,40 -169.7,169.8,-44.4,-44.3,0,40 -169.7,169.8,-44.3,-44.2,0,40 -169.7,169.8,-44.2,-44.1,0,40 -169.7,169.8,-44.1,-44,0,40 -169.7,169.8,-44,-43.9,0,40 -169.7,169.8,-43.9,-43.8,0,40 -169.7,169.8,-43.8,-43.7,0,40 -169.7,169.8,-43.7,-43.6,0,40 -169.7,169.8,-43.6,-43.5,0,40 -169.7,169.8,-43.5,-43.4,0,40 -169.7,169.8,-43.4,-43.3,0,40 -169.7,169.8,-43.3,-43.2,0,40 -169.7,169.8,-43.2,-43.1,0,40 -169.7,169.8,-43.1,-43,0,40 -169.7,169.8,-43,-42.9,0,40 -169.7,169.8,-42.9,-42.8,0,40 -169.7,169.8,-42.8,-42.7,0,40 -169.7,169.8,-42.7,-42.6,0,40 -169.7,169.8,-42.6,-42.5,0,40 -169.7,169.8,-42.5,-42.4,0,40 -169.7,169.8,-42.4,-42.3,0,40 -169.7,169.8,-42.3,-42.2,0,40 -169.7,169.8,-42.2,-42.1,0,40 -169.7,169.8,-42.1,-42,0,40 -169.8,169.9,-47,-46.9,0,40 -169.8,169.9,-46.9,-46.8,0,40 -169.8,169.9,-46.8,-46.7,0,40 -169.8,169.9,-46.7,-46.6,0,40 -169.8,169.9,-46.6,-46.5,0,40 -169.8,169.9,-46.5,-46.4,0,40 -169.8,169.9,-46.4,-46.3,0,40 -169.8,169.9,-46.3,-46.2,0,40 -169.8,169.9,-46.2,-46.1,0,40 -169.8,169.9,-46.1,-46,0,40 -169.8,169.9,-46,-45.9,0,40 -169.8,169.9,-45.9,-45.8,0,40 -169.8,169.9,-45.8,-45.7,0,40 -169.8,169.9,-45.7,-45.6,0,40 -169.8,169.9,-45.6,-45.5,0,40 -169.8,169.9,-45.5,-45.4,0,40 -169.8,169.9,-45.4,-45.3,0,40 -169.8,169.9,-45.3,-45.2,0,40 -169.8,169.9,-45.2,-45.1,0,40 -169.8,169.9,-45.1,-45,0,40 -169.8,169.9,-45,-44.9,0,40 -169.8,169.9,-44.9,-44.8,0,40 -169.8,169.9,-44.8,-44.7,0,40 -169.8,169.9,-44.7,-44.6,0,40 -169.8,169.9,-44.6,-44.5,0,40 -169.8,169.9,-44.5,-44.4,0,40 -169.8,169.9,-44.4,-44.3,0,40 -169.8,169.9,-44.3,-44.2,0,40 -169.8,169.9,-44.2,-44.1,0,40 -169.8,169.9,-44.1,-44,0,40 -169.8,169.9,-44,-43.9,0,40 -169.8,169.9,-43.9,-43.8,0,40 -169.8,169.9,-43.8,-43.7,0,40 -169.8,169.9,-43.7,-43.6,0,40 -169.8,169.9,-43.6,-43.5,0,40 -169.8,169.9,-43.5,-43.4,0,40 -169.8,169.9,-43.4,-43.3,0,40 -169.8,169.9,-43.3,-43.2,0,40 -169.8,169.9,-43.2,-43.1,0,40 -169.8,169.9,-43.1,-43,0,40 -169.8,169.9,-43,-42.9,0,40 -169.8,169.9,-42.9,-42.8,0,40 -169.8,169.9,-42.8,-42.7,0,40 -169.8,169.9,-42.7,-42.6,0,40 -169.8,169.9,-42.6,-42.5,0,40 -169.8,169.9,-42.5,-42.4,0,40 -169.8,169.9,-42.4,-42.3,0,40 -169.8,169.9,-42.3,-42.2,0,40 -169.8,169.9,-42.2,-42.1,0,40 -169.8,169.9,-42.1,-42,0,40 -169.8,169.9,-42,-41.9,0,40 -169.9,170,-47,-46.9,0,40 -169.9,170,-46.9,-46.8,0,40 -169.9,170,-46.8,-46.7,0,40 -169.9,170,-46.7,-46.6,0,40 -169.9,170,-46.6,-46.5,0,40 -169.9,170,-46.5,-46.4,0,40 -169.9,170,-46.4,-46.3,0,40 -169.9,170,-46.3,-46.2,0,40 -169.9,170,-46.2,-46.1,0,40 -169.9,170,-46.1,-46,0,40 -169.9,170,-46,-45.9,0,40 -169.9,170,-45.9,-45.8,0,40 -169.9,170,-45.8,-45.7,0,40 -169.9,170,-45.7,-45.6,0,40 -169.9,170,-45.6,-45.5,0,40 -169.9,170,-45.5,-45.4,0,40 -169.9,170,-45.4,-45.3,0,40 -169.9,170,-45.3,-45.2,0,40 -169.9,170,-45.2,-45.1,0,40 -169.9,170,-45.1,-45,0,40 -169.9,170,-45,-44.9,0,40 -169.9,170,-44.9,-44.8,0,40 -169.9,170,-44.8,-44.7,0,40 -169.9,170,-44.7,-44.6,0,40 -169.9,170,-44.6,-44.5,0,40 -169.9,170,-44.5,-44.4,0,40 -169.9,170,-44.4,-44.3,0,40 -169.9,170,-44.3,-44.2,0,40 -169.9,170,-44.2,-44.1,0,40 -169.9,170,-44.1,-44,0,40 -169.9,170,-44,-43.9,0,40 -169.9,170,-43.9,-43.8,0,40 -169.9,170,-43.8,-43.7,0,40 -169.9,170,-43.7,-43.6,0,40 -169.9,170,-43.6,-43.5,0,40 -169.9,170,-43.5,-43.4,0,40 -169.9,170,-43.4,-43.3,0,40 -169.9,170,-43.3,-43.2,0,40 -169.9,170,-43.2,-43.1,0,40 -169.9,170,-43.1,-43,0,40 -169.9,170,-43,-42.9,0,40 -169.9,170,-42.9,-42.8,0,40 -169.9,170,-42.8,-42.7,0,40 -169.9,170,-42.7,-42.6,0,40 -169.9,170,-42.6,-42.5,0,40 -169.9,170,-42.5,-42.4,0,40 -169.9,170,-42.4,-42.3,0,40 -169.9,170,-42.3,-42.2,0,40 -169.9,170,-42.2,-42.1,0,40 -169.9,170,-42.1,-42,0,40 -169.9,170,-42,-41.9,0,40 -169.9,170,-41.9,-41.8,0,40 -170,170.1,-46.9,-46.8,0,40 -170,170.1,-46.8,-46.7,0,40 -170,170.1,-46.7,-46.6,0,40 -170,170.1,-46.6,-46.5,0,40 -170,170.1,-46.5,-46.4,0,40 -170,170.1,-46.4,-46.3,0,40 -170,170.1,-46.3,-46.2,0,40 -170,170.1,-46.2,-46.1,0,40 -170,170.1,-46.1,-46,0,40 -170,170.1,-46,-45.9,0,40 -170,170.1,-45.9,-45.8,0,40 -170,170.1,-45.8,-45.7,0,40 -170,170.1,-45.7,-45.6,0,40 -170,170.1,-45.6,-45.5,0,40 -170,170.1,-45.5,-45.4,0,40 -170,170.1,-45.4,-45.3,0,40 -170,170.1,-45.3,-45.2,0,40 -170,170.1,-45.2,-45.1,0,40 -170,170.1,-45.1,-45,0,40 -170,170.1,-45,-44.9,0,40 -170,170.1,-44.9,-44.8,0,40 -170,170.1,-44.8,-44.7,0,40 -170,170.1,-44.7,-44.6,0,40 -170,170.1,-44.6,-44.5,0,40 -170,170.1,-44.5,-44.4,0,40 -170,170.1,-44.4,-44.3,0,40 -170,170.1,-44.3,-44.2,0,40 -170,170.1,-44.2,-44.1,0,40 -170,170.1,-44.1,-44,0,40 -170,170.1,-44,-43.9,0,40 -170,170.1,-43.9,-43.8,0,40 -170,170.1,-43.8,-43.7,0,40 -170,170.1,-43.7,-43.6,0,40 -170,170.1,-43.6,-43.5,0,40 -170,170.1,-43.5,-43.4,0,40 -170,170.1,-43.4,-43.3,0,40 -170,170.1,-43.3,-43.2,0,40 -170,170.1,-43.2,-43.1,0,40 -170,170.1,-43.1,-43,0,40 -170,170.1,-43,-42.9,0,40 -170,170.1,-42.9,-42.8,0,40 -170,170.1,-42.8,-42.7,0,40 -170,170.1,-42.7,-42.6,0,40 -170,170.1,-42.6,-42.5,0,40 -170,170.1,-42.5,-42.4,0,40 -170,170.1,-42.4,-42.3,0,40 -170,170.1,-42.3,-42.2,0,40 -170,170.1,-42.2,-42.1,0,40 -170,170.1,-42.1,-42,0,40 -170,170.1,-42,-41.9,0,40 -170,170.1,-41.9,-41.8,0,40 -170,170.1,-41.8,-41.7,0,40 -170.1,170.2,-46.9,-46.8,0,40 -170.1,170.2,-46.8,-46.7,0,40 -170.1,170.2,-46.7,-46.6,0,40 -170.1,170.2,-46.6,-46.5,0,40 -170.1,170.2,-46.5,-46.4,0,40 -170.1,170.2,-46.4,-46.3,0,40 -170.1,170.2,-46.3,-46.2,0,40 -170.1,170.2,-46.2,-46.1,0,40 -170.1,170.2,-46.1,-46,0,40 -170.1,170.2,-46,-45.9,0,40 -170.1,170.2,-45.9,-45.8,0,40 -170.1,170.2,-45.8,-45.7,0,40 -170.1,170.2,-45.7,-45.6,0,40 -170.1,170.2,-45.6,-45.5,0,40 -170.1,170.2,-45.5,-45.4,0,40 -170.1,170.2,-45.4,-45.3,0,40 -170.1,170.2,-45.3,-45.2,0,40 -170.1,170.2,-45.2,-45.1,0,40 -170.1,170.2,-45.1,-45,0,40 -170.1,170.2,-45,-44.9,0,40 -170.1,170.2,-44.9,-44.8,0,40 -170.1,170.2,-44.8,-44.7,0,40 -170.1,170.2,-44.7,-44.6,0,40 -170.1,170.2,-44.6,-44.5,0,40 -170.1,170.2,-44.5,-44.4,0,40 -170.1,170.2,-44.4,-44.3,0,40 -170.1,170.2,-44.3,-44.2,0,40 -170.1,170.2,-44.2,-44.1,0,40 -170.1,170.2,-44.1,-44,0,40 -170.1,170.2,-44,-43.9,0,40 -170.1,170.2,-43.9,-43.8,0,40 -170.1,170.2,-43.8,-43.7,0,40 -170.1,170.2,-43.7,-43.6,0,40 -170.1,170.2,-43.6,-43.5,0,40 -170.1,170.2,-43.5,-43.4,0,40 -170.1,170.2,-43.4,-43.3,0,40 -170.1,170.2,-43.3,-43.2,0,40 -170.1,170.2,-43.2,-43.1,0,40 -170.1,170.2,-43.1,-43,0,40 -170.1,170.2,-43,-42.9,0,40 -170.1,170.2,-42.9,-42.8,0,40 -170.1,170.2,-42.8,-42.7,0,40 -170.1,170.2,-42.7,-42.6,0,40 -170.1,170.2,-42.6,-42.5,0,40 -170.1,170.2,-42.5,-42.4,0,40 -170.1,170.2,-42.4,-42.3,0,40 -170.1,170.2,-42.3,-42.2,0,40 -170.1,170.2,-42.2,-42.1,0,40 -170.1,170.2,-42.1,-42,0,40 -170.1,170.2,-42,-41.9,0,40 -170.1,170.2,-41.9,-41.8,0,40 -170.1,170.2,-41.8,-41.7,0,40 -170.2,170.3,-46.8,-46.7,0,40 -170.2,170.3,-46.7,-46.6,0,40 -170.2,170.3,-46.6,-46.5,0,40 -170.2,170.3,-46.5,-46.4,0,40 -170.2,170.3,-46.4,-46.3,0,40 -170.2,170.3,-46.3,-46.2,0,40 -170.2,170.3,-46.2,-46.1,0,40 -170.2,170.3,-46.1,-46,0,40 -170.2,170.3,-46,-45.9,0,40 -170.2,170.3,-45.9,-45.8,0,40 -170.2,170.3,-45.8,-45.7,0,40 -170.2,170.3,-45.7,-45.6,0,40 -170.2,170.3,-45.6,-45.5,0,40 -170.2,170.3,-45.5,-45.4,0,40 -170.2,170.3,-45.4,-45.3,0,40 -170.2,170.3,-45.3,-45.2,0,40 -170.2,170.3,-45.2,-45.1,0,40 -170.2,170.3,-45.1,-45,0,40 -170.2,170.3,-45,-44.9,0,40 -170.2,170.3,-44.9,-44.8,0,40 -170.2,170.3,-44.8,-44.7,0,40 -170.2,170.3,-44.7,-44.6,0,40 -170.2,170.3,-44.6,-44.5,0,40 -170.2,170.3,-44.5,-44.4,0,40 -170.2,170.3,-44.4,-44.3,0,40 -170.2,170.3,-44.3,-44.2,0,40 -170.2,170.3,-44.2,-44.1,0,40 -170.2,170.3,-44.1,-44,0,40 -170.2,170.3,-44,-43.9,0,40 -170.2,170.3,-43.9,-43.8,0,40 -170.2,170.3,-43.8,-43.7,0,40 -170.2,170.3,-43.7,-43.6,0,40 -170.2,170.3,-43.6,-43.5,0,40 -170.2,170.3,-43.5,-43.4,0,40 -170.2,170.3,-43.4,-43.3,0,40 -170.2,170.3,-43.3,-43.2,0,40 -170.2,170.3,-43.2,-43.1,0,40 -170.2,170.3,-43.1,-43,0,40 -170.2,170.3,-43,-42.9,0,40 -170.2,170.3,-42.9,-42.8,0,40 -170.2,170.3,-42.8,-42.7,0,40 -170.2,170.3,-42.7,-42.6,0,40 -170.2,170.3,-42.6,-42.5,0,40 -170.2,170.3,-42.5,-42.4,0,40 -170.2,170.3,-42.4,-42.3,0,40 -170.2,170.3,-42.3,-42.2,0,40 -170.2,170.3,-42.2,-42.1,0,40 -170.2,170.3,-42.1,-42,0,40 -170.2,170.3,-42,-41.9,0,40 -170.2,170.3,-41.9,-41.8,0,40 -170.2,170.3,-41.8,-41.7,0,40 -170.2,170.3,-41.7,-41.6,0,40 -170.3,170.4,-46.8,-46.7,0,40 -170.3,170.4,-46.7,-46.6,0,40 -170.3,170.4,-46.6,-46.5,0,40 -170.3,170.4,-46.5,-46.4,0,40 -170.3,170.4,-46.4,-46.3,0,40 -170.3,170.4,-46.3,-46.2,0,40 -170.3,170.4,-46.2,-46.1,0,40 -170.3,170.4,-46.1,-46,0,40 -170.3,170.4,-46,-45.9,0,40 -170.3,170.4,-45.9,-45.8,0,40 -170.3,170.4,-45.8,-45.7,0,40 -170.3,170.4,-45.7,-45.6,0,40 -170.3,170.4,-45.6,-45.5,0,40 -170.3,170.4,-45.5,-45.4,0,40 -170.3,170.4,-45.4,-45.3,0,40 -170.3,170.4,-45.3,-45.2,0,40 -170.3,170.4,-45.2,-45.1,0,40 -170.3,170.4,-45.1,-45,0,40 -170.3,170.4,-45,-44.9,0,40 -170.3,170.4,-44.9,-44.8,0,40 -170.3,170.4,-44.8,-44.7,0,40 -170.3,170.4,-44.7,-44.6,0,40 -170.3,170.4,-44.6,-44.5,0,40 -170.3,170.4,-44.5,-44.4,0,40 -170.3,170.4,-44.4,-44.3,0,40 -170.3,170.4,-44.3,-44.2,0,40 -170.3,170.4,-44.2,-44.1,0,40 -170.3,170.4,-44.1,-44,0,40 -170.3,170.4,-44,-43.9,0,40 -170.3,170.4,-43.9,-43.8,0,40 -170.3,170.4,-43.8,-43.7,0,40 -170.3,170.4,-43.7,-43.6,0,40 -170.3,170.4,-43.6,-43.5,0,40 -170.3,170.4,-43.5,-43.4,0,40 -170.3,170.4,-43.4,-43.3,0,40 -170.3,170.4,-43.3,-43.2,0,40 -170.3,170.4,-43.2,-43.1,0,40 -170.3,170.4,-43.1,-43,0,40 -170.3,170.4,-43,-42.9,0,40 -170.3,170.4,-42.9,-42.8,0,40 -170.3,170.4,-42.8,-42.7,0,40 -170.3,170.4,-42.7,-42.6,0,40 -170.3,170.4,-42.6,-42.5,0,40 -170.3,170.4,-42.5,-42.4,0,40 -170.3,170.4,-42.4,-42.3,0,40 -170.3,170.4,-42.3,-42.2,0,40 -170.3,170.4,-42.2,-42.1,0,40 -170.3,170.4,-42.1,-42,0,40 -170.3,170.4,-42,-41.9,0,40 -170.3,170.4,-41.9,-41.8,0,40 -170.3,170.4,-41.8,-41.7,0,40 -170.3,170.4,-41.7,-41.6,0,40 -170.3,170.4,-41.6,-41.5,0,40 -170.4,170.5,-46.7,-46.6,0,40 -170.4,170.5,-46.6,-46.5,0,40 -170.4,170.5,-46.5,-46.4,0,40 -170.4,170.5,-46.4,-46.3,0,40 -170.4,170.5,-46.3,-46.2,0,40 -170.4,170.5,-46.2,-46.1,0,40 -170.4,170.5,-46.1,-46,0,40 -170.4,170.5,-46,-45.9,0,40 -170.4,170.5,-45.9,-45.8,0,40 -170.4,170.5,-45.8,-45.7,0,40 -170.4,170.5,-45.7,-45.6,0,40 -170.4,170.5,-45.6,-45.5,0,40 -170.4,170.5,-45.5,-45.4,0,40 -170.4,170.5,-45.4,-45.3,0,40 -170.4,170.5,-45.3,-45.2,0,40 -170.4,170.5,-45.2,-45.1,0,40 -170.4,170.5,-45.1,-45,0,40 -170.4,170.5,-45,-44.9,0,40 -170.4,170.5,-44.9,-44.8,0,40 -170.4,170.5,-44.8,-44.7,0,40 -170.4,170.5,-44.7,-44.6,0,40 -170.4,170.5,-44.6,-44.5,0,40 -170.4,170.5,-44.5,-44.4,0,40 -170.4,170.5,-44.4,-44.3,0,40 -170.4,170.5,-44.3,-44.2,0,40 -170.4,170.5,-44.2,-44.1,0,40 -170.4,170.5,-44.1,-44,0,40 -170.4,170.5,-44,-43.9,0,40 -170.4,170.5,-43.9,-43.8,0,40 -170.4,170.5,-43.8,-43.7,0,40 -170.4,170.5,-43.7,-43.6,0,40 -170.4,170.5,-43.6,-43.5,0,40 -170.4,170.5,-43.5,-43.4,0,40 -170.4,170.5,-43.4,-43.3,0,40 -170.4,170.5,-43.3,-43.2,0,40 -170.4,170.5,-43.2,-43.1,0,40 -170.4,170.5,-43.1,-43,0,40 -170.4,170.5,-43,-42.9,0,40 -170.4,170.5,-42.9,-42.8,0,40 -170.4,170.5,-42.8,-42.7,0,40 -170.4,170.5,-42.7,-42.6,0,40 -170.4,170.5,-42.6,-42.5,0,40 -170.4,170.5,-42.5,-42.4,0,40 -170.4,170.5,-42.4,-42.3,0,40 -170.4,170.5,-42.3,-42.2,0,40 -170.4,170.5,-42.2,-42.1,0,40 -170.4,170.5,-42.1,-42,0,40 -170.4,170.5,-42,-41.9,0,40 -170.4,170.5,-41.9,-41.8,0,40 -170.4,170.5,-41.8,-41.7,0,40 -170.4,170.5,-41.7,-41.6,0,40 -170.4,170.5,-41.6,-41.5,0,40 -170.4,170.5,-41.5,-41.4,0,40 -170.5,170.6,-46.7,-46.6,0,40 -170.5,170.6,-46.6,-46.5,0,40 -170.5,170.6,-46.5,-46.4,0,40 -170.5,170.6,-46.4,-46.3,0,40 -170.5,170.6,-46.3,-46.2,0,40 -170.5,170.6,-46.2,-46.1,0,40 -170.5,170.6,-46.1,-46,0,40 -170.5,170.6,-46,-45.9,0,40 -170.5,170.6,-45.9,-45.8,0,40 -170.5,170.6,-45.8,-45.7,0,40 -170.5,170.6,-45.7,-45.6,0,40 -170.5,170.6,-45.6,-45.5,0,40 -170.5,170.6,-45.5,-45.4,0,40 -170.5,170.6,-45.4,-45.3,0,40 -170.5,170.6,-45.3,-45.2,0,40 -170.5,170.6,-45.2,-45.1,0,40 -170.5,170.6,-45.1,-45,0,40 -170.5,170.6,-45,-44.9,0,40 -170.5,170.6,-44.9,-44.8,0,40 -170.5,170.6,-44.8,-44.7,0,40 -170.5,170.6,-44.7,-44.6,0,40 -170.5,170.6,-44.6,-44.5,0,40 -170.5,170.6,-44.5,-44.4,0,40 -170.5,170.6,-44.4,-44.3,0,40 -170.5,170.6,-44.3,-44.2,0,40 -170.5,170.6,-44.2,-44.1,0,40 -170.5,170.6,-44.1,-44,0,40 -170.5,170.6,-44,-43.9,0,40 -170.5,170.6,-43.9,-43.8,0,40 -170.5,170.6,-43.8,-43.7,0,40 -170.5,170.6,-43.7,-43.6,0,40 -170.5,170.6,-43.6,-43.5,0,40 -170.5,170.6,-43.5,-43.4,0,40 -170.5,170.6,-43.4,-43.3,0,40 -170.5,170.6,-43.3,-43.2,0,40 -170.5,170.6,-43.2,-43.1,0,40 -170.5,170.6,-43.1,-43,0,40 -170.5,170.6,-43,-42.9,0,40 -170.5,170.6,-42.9,-42.8,0,40 -170.5,170.6,-42.8,-42.7,0,40 -170.5,170.6,-42.7,-42.6,0,40 -170.5,170.6,-42.6,-42.5,0,40 -170.5,170.6,-42.5,-42.4,0,40 -170.5,170.6,-42.4,-42.3,0,40 -170.5,170.6,-42.3,-42.2,0,40 -170.5,170.6,-42.2,-42.1,0,40 -170.5,170.6,-42.1,-42,0,40 -170.5,170.6,-42,-41.9,0,40 -170.5,170.6,-41.9,-41.8,0,40 -170.5,170.6,-41.8,-41.7,0,40 -170.5,170.6,-41.7,-41.6,0,40 -170.5,170.6,-41.6,-41.5,0,40 -170.5,170.6,-41.5,-41.4,0,40 -170.5,170.6,-41.4,-41.3,0,40 -170.6,170.7,-46.6,-46.5,0,40 -170.6,170.7,-46.5,-46.4,0,40 -170.6,170.7,-46.4,-46.3,0,40 -170.6,170.7,-46.3,-46.2,0,40 -170.6,170.7,-46.2,-46.1,0,40 -170.6,170.7,-46.1,-46,0,40 -170.6,170.7,-46,-45.9,0,40 -170.6,170.7,-45.9,-45.8,0,40 -170.6,170.7,-45.8,-45.7,0,40 -170.6,170.7,-45.7,-45.6,0,40 -170.6,170.7,-45.6,-45.5,0,40 -170.6,170.7,-45.5,-45.4,0,40 -170.6,170.7,-45.4,-45.3,0,40 -170.6,170.7,-45.3,-45.2,0,40 -170.6,170.7,-45.2,-45.1,0,40 -170.6,170.7,-45.1,-45,0,40 -170.6,170.7,-45,-44.9,0,40 -170.6,170.7,-44.9,-44.8,0,40 -170.6,170.7,-44.8,-44.7,0,40 -170.6,170.7,-44.7,-44.6,0,40 -170.6,170.7,-44.6,-44.5,0,40 -170.6,170.7,-44.5,-44.4,0,40 -170.6,170.7,-44.4,-44.3,0,40 -170.6,170.7,-44.3,-44.2,0,40 -170.6,170.7,-44.2,-44.1,0,40 -170.6,170.7,-44.1,-44,0,40 -170.6,170.7,-44,-43.9,0,40 -170.6,170.7,-43.9,-43.8,0,40 -170.6,170.7,-43.8,-43.7,0,40 -170.6,170.7,-43.7,-43.6,0,40 -170.6,170.7,-43.6,-43.5,0,40 -170.6,170.7,-43.5,-43.4,0,40 -170.6,170.7,-43.4,-43.3,0,40 -170.6,170.7,-43.3,-43.2,0,40 -170.6,170.7,-43.2,-43.1,0,40 -170.6,170.7,-43.1,-43,0,40 -170.6,170.7,-43,-42.9,0,40 -170.6,170.7,-42.9,-42.8,0,40 -170.6,170.7,-42.8,-42.7,0,40 -170.6,170.7,-42.7,-42.6,0,40 -170.6,170.7,-42.6,-42.5,0,40 -170.6,170.7,-42.5,-42.4,0,40 -170.6,170.7,-42.4,-42.3,0,40 -170.6,170.7,-42.3,-42.2,0,40 -170.6,170.7,-42.2,-42.1,0,40 -170.6,170.7,-42.1,-42,0,40 -170.6,170.7,-42,-41.9,0,40 -170.6,170.7,-41.9,-41.8,0,40 -170.6,170.7,-41.8,-41.7,0,40 -170.6,170.7,-41.7,-41.6,0,40 -170.6,170.7,-41.6,-41.5,0,40 -170.6,170.7,-41.5,-41.4,0,40 -170.6,170.7,-41.4,-41.3,0,40 -170.6,170.7,-41.3,-41.2,0,40 -170.7,170.8,-46.6,-46.5,0,40 -170.7,170.8,-46.5,-46.4,0,40 -170.7,170.8,-46.4,-46.3,0,40 -170.7,170.8,-46.3,-46.2,0,40 -170.7,170.8,-46.2,-46.1,0,40 -170.7,170.8,-46.1,-46,0,40 -170.7,170.8,-46,-45.9,0,40 -170.7,170.8,-45.9,-45.8,0,40 -170.7,170.8,-45.8,-45.7,0,40 -170.7,170.8,-45.7,-45.6,0,40 -170.7,170.8,-45.6,-45.5,0,40 -170.7,170.8,-45.5,-45.4,0,40 -170.7,170.8,-45.4,-45.3,0,40 -170.7,170.8,-45.3,-45.2,0,40 -170.7,170.8,-45.2,-45.1,0,40 -170.7,170.8,-45.1,-45,0,40 -170.7,170.8,-45,-44.9,0,40 -170.7,170.8,-44.9,-44.8,0,40 -170.7,170.8,-44.8,-44.7,0,40 -170.7,170.8,-44.7,-44.6,0,40 -170.7,170.8,-44.6,-44.5,0,40 -170.7,170.8,-44.5,-44.4,0,40 -170.7,170.8,-44.4,-44.3,0,40 -170.7,170.8,-44.3,-44.2,0,40 -170.7,170.8,-44.2,-44.1,0,40 -170.7,170.8,-44.1,-44,0,40 -170.7,170.8,-44,-43.9,0,40 -170.7,170.8,-43.9,-43.8,0,40 -170.7,170.8,-43.8,-43.7,0,40 -170.7,170.8,-43.7,-43.6,0,40 -170.7,170.8,-43.6,-43.5,0,40 -170.7,170.8,-43.5,-43.4,0,40 -170.7,170.8,-43.4,-43.3,0,40 -170.7,170.8,-43.3,-43.2,0,40 -170.7,170.8,-43.2,-43.1,0,40 -170.7,170.8,-43.1,-43,0,40 -170.7,170.8,-43,-42.9,0,40 -170.7,170.8,-42.9,-42.8,0,40 -170.7,170.8,-42.8,-42.7,0,40 -170.7,170.8,-42.7,-42.6,0,40 -170.7,170.8,-42.6,-42.5,0,40 -170.7,170.8,-42.5,-42.4,0,40 -170.7,170.8,-42.4,-42.3,0,40 -170.7,170.8,-42.3,-42.2,0,40 -170.7,170.8,-42.2,-42.1,0,40 -170.7,170.8,-42.1,-42,0,40 -170.7,170.8,-42,-41.9,0,40 -170.7,170.8,-41.9,-41.8,0,40 -170.7,170.8,-41.8,-41.7,0,40 -170.7,170.8,-41.7,-41.6,0,40 -170.7,170.8,-41.6,-41.5,0,40 -170.7,170.8,-41.5,-41.4,0,40 -170.7,170.8,-41.4,-41.3,0,40 -170.7,170.8,-41.3,-41.2,0,40 -170.7,170.8,-41.2,-41.1,0,40 -170.8,170.9,-46.5,-46.4,0,40 -170.8,170.9,-46.4,-46.3,0,40 -170.8,170.9,-46.3,-46.2,0,40 -170.8,170.9,-46.2,-46.1,0,40 -170.8,170.9,-46.1,-46,0,40 -170.8,170.9,-46,-45.9,0,40 -170.8,170.9,-45.9,-45.8,0,40 -170.8,170.9,-45.8,-45.7,0,40 -170.8,170.9,-45.7,-45.6,0,40 -170.8,170.9,-45.6,-45.5,0,40 -170.8,170.9,-45.5,-45.4,0,40 -170.8,170.9,-45.4,-45.3,0,40 -170.8,170.9,-45.3,-45.2,0,40 -170.8,170.9,-45.2,-45.1,0,40 -170.8,170.9,-45.1,-45,0,40 -170.8,170.9,-45,-44.9,0,40 -170.8,170.9,-44.9,-44.8,0,40 -170.8,170.9,-44.8,-44.7,0,40 -170.8,170.9,-44.7,-44.6,0,40 -170.8,170.9,-44.6,-44.5,0,40 -170.8,170.9,-44.5,-44.4,0,40 -170.8,170.9,-44.4,-44.3,0,40 -170.8,170.9,-44.3,-44.2,0,40 -170.8,170.9,-44.2,-44.1,0,40 -170.8,170.9,-44.1,-44,0,40 -170.8,170.9,-44,-43.9,0,40 -170.8,170.9,-43.9,-43.8,0,40 -170.8,170.9,-43.8,-43.7,0,40 -170.8,170.9,-43.7,-43.6,0,40 -170.8,170.9,-43.6,-43.5,0,40 -170.8,170.9,-43.5,-43.4,0,40 -170.8,170.9,-43.4,-43.3,0,40 -170.8,170.9,-43.3,-43.2,0,40 -170.8,170.9,-43.2,-43.1,0,40 -170.8,170.9,-43.1,-43,0,40 -170.8,170.9,-43,-42.9,0,40 -170.8,170.9,-42.9,-42.8,0,40 -170.8,170.9,-42.8,-42.7,0,40 -170.8,170.9,-42.7,-42.6,0,40 -170.8,170.9,-42.6,-42.5,0,40 -170.8,170.9,-42.5,-42.4,0,40 -170.8,170.9,-42.4,-42.3,0,40 -170.8,170.9,-42.3,-42.2,0,40 -170.8,170.9,-42.2,-42.1,0,40 -170.8,170.9,-42.1,-42,0,40 -170.8,170.9,-42,-41.9,0,40 -170.8,170.9,-41.9,-41.8,0,40 -170.8,170.9,-41.8,-41.7,0,40 -170.8,170.9,-41.7,-41.6,0,40 -170.8,170.9,-41.6,-41.5,0,40 -170.8,170.9,-41.5,-41.4,0,40 -170.8,170.9,-41.4,-41.3,0,40 -170.8,170.9,-41.3,-41.2,0,40 -170.8,170.9,-41.2,-41.1,0,40 -170.9,171,-46.4,-46.3,0,40 -170.9,171,-46.3,-46.2,0,40 -170.9,171,-46.2,-46.1,0,40 -170.9,171,-46.1,-46,0,40 -170.9,171,-46,-45.9,0,40 -170.9,171,-45.9,-45.8,0,40 -170.9,171,-45.8,-45.7,0,40 -170.9,171,-45.7,-45.6,0,40 -170.9,171,-45.6,-45.5,0,40 -170.9,171,-45.5,-45.4,0,40 -170.9,171,-45.4,-45.3,0,40 -170.9,171,-45.3,-45.2,0,40 -170.9,171,-45.2,-45.1,0,40 -170.9,171,-45.1,-45,0,40 -170.9,171,-45,-44.9,0,40 -170.9,171,-44.9,-44.8,0,40 -170.9,171,-44.8,-44.7,0,40 -170.9,171,-44.7,-44.6,0,40 -170.9,171,-44.6,-44.5,0,40 -170.9,171,-44.5,-44.4,0,40 -170.9,171,-44.4,-44.3,0,40 -170.9,171,-44.3,-44.2,0,40 -170.9,171,-44.2,-44.1,0,40 -170.9,171,-44.1,-44,0,40 -170.9,171,-44,-43.9,0,40 -170.9,171,-43.9,-43.8,0,40 -170.9,171,-43.8,-43.7,0,40 -170.9,171,-43.7,-43.6,0,40 -170.9,171,-43.6,-43.5,0,40 -170.9,171,-43.5,-43.4,0,40 -170.9,171,-43.4,-43.3,0,40 -170.9,171,-43.3,-43.2,0,40 -170.9,171,-43.2,-43.1,0,40 -170.9,171,-43.1,-43,0,40 -170.9,171,-43,-42.9,0,40 -170.9,171,-42.9,-42.8,0,40 -170.9,171,-42.8,-42.7,0,40 -170.9,171,-42.7,-42.6,0,40 -170.9,171,-42.6,-42.5,0,40 -170.9,171,-42.5,-42.4,0,40 -170.9,171,-42.4,-42.3,0,40 -170.9,171,-42.3,-42.2,0,40 -170.9,171,-42.2,-42.1,0,40 -170.9,171,-42.1,-42,0,40 -170.9,171,-42,-41.9,0,40 -170.9,171,-41.9,-41.8,0,40 -170.9,171,-41.8,-41.7,0,40 -170.9,171,-41.7,-41.6,0,40 -170.9,171,-41.6,-41.5,0,40 -170.9,171,-41.5,-41.4,0,40 -170.9,171,-41.4,-41.3,0,40 -170.9,171,-41.3,-41.2,0,40 -170.9,171,-41.2,-41.1,0,40 -170.9,171,-41.1,-41,0,40 -171,171.1,-46.4,-46.3,0,40 -171,171.1,-46.3,-46.2,0,40 -171,171.1,-46.2,-46.1,0,40 -171,171.1,-46.1,-46,0,40 -171,171.1,-46,-45.9,0,40 -171,171.1,-45.9,-45.8,0,40 -171,171.1,-45.8,-45.7,0,40 -171,171.1,-45.7,-45.6,0,40 -171,171.1,-45.6,-45.5,0,40 -171,171.1,-45.5,-45.4,0,40 -171,171.1,-45.4,-45.3,0,40 -171,171.1,-45.3,-45.2,0,40 -171,171.1,-45.2,-45.1,0,40 -171,171.1,-45.1,-45,0,40 -171,171.1,-45,-44.9,0,40 -171,171.1,-44.9,-44.8,0,40 -171,171.1,-44.8,-44.7,0,40 -171,171.1,-44.7,-44.6,0,40 -171,171.1,-44.6,-44.5,0,40 -171,171.1,-44.5,-44.4,0,40 -171,171.1,-44.4,-44.3,0,40 -171,171.1,-44.3,-44.2,0,40 -171,171.1,-44.2,-44.1,0,40 -171,171.1,-44.1,-44,0,40 -171,171.1,-44,-43.9,0,40 -171,171.1,-43.9,-43.8,0,40 -171,171.1,-43.8,-43.7,0,40 -171,171.1,-43.7,-43.6,0,40 -171,171.1,-43.6,-43.5,0,40 -171,171.1,-43.5,-43.4,0,40 -171,171.1,-43.4,-43.3,0,40 -171,171.1,-43.3,-43.2,0,40 -171,171.1,-43.2,-43.1,0,40 -171,171.1,-43.1,-43,0,40 -171,171.1,-43,-42.9,0,40 -171,171.1,-42.9,-42.8,0,40 -171,171.1,-42.8,-42.7,0,40 -171,171.1,-42.7,-42.6,0,40 -171,171.1,-42.6,-42.5,0,40 -171,171.1,-42.5,-42.4,0,40 -171,171.1,-42.4,-42.3,0,40 -171,171.1,-42.3,-42.2,0,40 -171,171.1,-42.2,-42.1,0,40 -171,171.1,-42.1,-42,0,40 -171,171.1,-42,-41.9,0,40 -171,171.1,-41.9,-41.8,0,40 -171,171.1,-41.8,-41.7,0,40 -171,171.1,-41.7,-41.6,0,40 -171,171.1,-41.6,-41.5,0,40 -171,171.1,-41.5,-41.4,0,40 -171,171.1,-41.4,-41.3,0,40 -171,171.1,-41.3,-41.2,0,40 -171,171.1,-41.2,-41.1,0,40 -171,171.1,-41.1,-41,0,40 -171,171.1,-41,-40.9,0,40 -171.1,171.2,-46.3,-46.2,0,40 -171.1,171.2,-46.2,-46.1,0,40 -171.1,171.2,-46.1,-46,0,40 -171.1,171.2,-46,-45.9,0,40 -171.1,171.2,-45.9,-45.8,0,40 -171.1,171.2,-45.8,-45.7,0,40 -171.1,171.2,-45.7,-45.6,0,40 -171.1,171.2,-45.6,-45.5,0,40 -171.1,171.2,-45.5,-45.4,0,40 -171.1,171.2,-45.4,-45.3,0,40 -171.1,171.2,-45.3,-45.2,0,40 -171.1,171.2,-45.2,-45.1,0,40 -171.1,171.2,-45.1,-45,0,40 -171.1,171.2,-45,-44.9,0,40 -171.1,171.2,-44.9,-44.8,0,40 -171.1,171.2,-44.8,-44.7,0,40 -171.1,171.2,-44.7,-44.6,0,40 -171.1,171.2,-44.6,-44.5,0,40 -171.1,171.2,-44.5,-44.4,0,40 -171.1,171.2,-44.4,-44.3,0,40 -171.1,171.2,-44.3,-44.2,0,40 -171.1,171.2,-44.2,-44.1,0,40 -171.1,171.2,-44.1,-44,0,40 -171.1,171.2,-44,-43.9,0,40 -171.1,171.2,-43.9,-43.8,0,40 -171.1,171.2,-43.8,-43.7,0,40 -171.1,171.2,-43.7,-43.6,0,40 -171.1,171.2,-43.6,-43.5,0,40 -171.1,171.2,-43.5,-43.4,0,40 -171.1,171.2,-43.4,-43.3,0,40 -171.1,171.2,-43.3,-43.2,0,40 -171.1,171.2,-43.2,-43.1,0,40 -171.1,171.2,-43.1,-43,0,40 -171.1,171.2,-43,-42.9,0,40 -171.1,171.2,-42.9,-42.8,0,40 -171.1,171.2,-42.8,-42.7,0,40 -171.1,171.2,-42.7,-42.6,0,40 -171.1,171.2,-42.6,-42.5,0,40 -171.1,171.2,-42.5,-42.4,0,40 -171.1,171.2,-42.4,-42.3,0,40 -171.1,171.2,-42.3,-42.2,0,40 -171.1,171.2,-42.2,-42.1,0,40 -171.1,171.2,-42.1,-42,0,40 -171.1,171.2,-42,-41.9,0,40 -171.1,171.2,-41.9,-41.8,0,40 -171.1,171.2,-41.8,-41.7,0,40 -171.1,171.2,-41.7,-41.6,0,40 -171.1,171.2,-41.6,-41.5,0,40 -171.1,171.2,-41.5,-41.4,0,40 -171.1,171.2,-41.4,-41.3,0,40 -171.1,171.2,-41.3,-41.2,0,40 -171.1,171.2,-41.2,-41.1,0,40 -171.1,171.2,-41.1,-41,0,40 -171.1,171.2,-41,-40.9,0,40 -171.1,171.2,-40.9,-40.8,0,40 -171.2,171.3,-46.2,-46.1,0,40 -171.2,171.3,-46.1,-46,0,40 -171.2,171.3,-46,-45.9,0,40 -171.2,171.3,-45.9,-45.8,0,40 -171.2,171.3,-45.8,-45.7,0,40 -171.2,171.3,-45.7,-45.6,0,40 -171.2,171.3,-45.6,-45.5,0,40 -171.2,171.3,-45.5,-45.4,0,40 -171.2,171.3,-45.4,-45.3,0,40 -171.2,171.3,-45.3,-45.2,0,40 -171.2,171.3,-45.2,-45.1,0,40 -171.2,171.3,-45.1,-45,0,40 -171.2,171.3,-45,-44.9,0,40 -171.2,171.3,-44.9,-44.8,0,40 -171.2,171.3,-44.8,-44.7,0,40 -171.2,171.3,-44.7,-44.6,0,40 -171.2,171.3,-44.6,-44.5,0,40 -171.2,171.3,-44.5,-44.4,0,40 -171.2,171.3,-44.4,-44.3,0,40 -171.2,171.3,-44.3,-44.2,0,40 -171.2,171.3,-44.2,-44.1,0,40 -171.2,171.3,-44.1,-44,0,40 -171.2,171.3,-44,-43.9,0,40 -171.2,171.3,-43.9,-43.8,0,40 -171.2,171.3,-43.8,-43.7,0,40 -171.2,171.3,-43.7,-43.6,0,40 -171.2,171.3,-43.6,-43.5,0,40 -171.2,171.3,-43.5,-43.4,0,40 -171.2,171.3,-43.4,-43.3,0,40 -171.2,171.3,-43.3,-43.2,0,40 -171.2,171.3,-43.2,-43.1,0,40 -171.2,171.3,-43.1,-43,0,40 -171.2,171.3,-43,-42.9,0,40 -171.2,171.3,-42.9,-42.8,0,40 -171.2,171.3,-42.8,-42.7,0,40 -171.2,171.3,-42.7,-42.6,0,40 -171.2,171.3,-42.6,-42.5,0,40 -171.2,171.3,-42.5,-42.4,0,40 -171.2,171.3,-42.4,-42.3,0,40 -171.2,171.3,-42.3,-42.2,0,40 -171.2,171.3,-42.2,-42.1,0,40 -171.2,171.3,-42.1,-42,0,40 -171.2,171.3,-42,-41.9,0,40 -171.2,171.3,-41.9,-41.8,0,40 -171.2,171.3,-41.8,-41.7,0,40 -171.2,171.3,-41.7,-41.6,0,40 -171.2,171.3,-41.6,-41.5,0,40 -171.2,171.3,-41.5,-41.4,0,40 -171.2,171.3,-41.4,-41.3,0,40 -171.2,171.3,-41.3,-41.2,0,40 -171.2,171.3,-41.2,-41.1,0,40 -171.2,171.3,-41.1,-41,0,40 -171.2,171.3,-41,-40.9,0,40 -171.2,171.3,-40.9,-40.8,0,40 -171.2,171.3,-40.8,-40.7,0,40 -171.3,171.4,-46.1,-46,0,40 -171.3,171.4,-46,-45.9,0,40 -171.3,171.4,-45.9,-45.8,0,40 -171.3,171.4,-45.8,-45.7,0,40 -171.3,171.4,-45.7,-45.6,0,40 -171.3,171.4,-45.6,-45.5,0,40 -171.3,171.4,-45.5,-45.4,0,40 -171.3,171.4,-45.4,-45.3,0,40 -171.3,171.4,-45.3,-45.2,0,40 -171.3,171.4,-45.2,-45.1,0,40 -171.3,171.4,-45.1,-45,0,40 -171.3,171.4,-45,-44.9,0,40 -171.3,171.4,-44.9,-44.8,0,40 -171.3,171.4,-44.8,-44.7,0,40 -171.3,171.4,-44.7,-44.6,0,40 -171.3,171.4,-44.6,-44.5,0,40 -171.3,171.4,-44.5,-44.4,0,40 -171.3,171.4,-44.4,-44.3,0,40 -171.3,171.4,-44.3,-44.2,0,40 -171.3,171.4,-44.2,-44.1,0,40 -171.3,171.4,-44.1,-44,0,40 -171.3,171.4,-44,-43.9,0,40 -171.3,171.4,-43.9,-43.8,0,40 -171.3,171.4,-43.8,-43.7,0,40 -171.3,171.4,-43.7,-43.6,0,40 -171.3,171.4,-43.6,-43.5,0,40 -171.3,171.4,-43.5,-43.4,0,40 -171.3,171.4,-43.4,-43.3,0,40 -171.3,171.4,-43.3,-43.2,0,40 -171.3,171.4,-43.2,-43.1,0,40 -171.3,171.4,-43.1,-43,0,40 -171.3,171.4,-43,-42.9,0,40 -171.3,171.4,-42.9,-42.8,0,40 -171.3,171.4,-42.8,-42.7,0,40 -171.3,171.4,-42.7,-42.6,0,40 -171.3,171.4,-42.6,-42.5,0,40 -171.3,171.4,-42.5,-42.4,0,40 -171.3,171.4,-42.4,-42.3,0,40 -171.3,171.4,-42.3,-42.2,0,40 -171.3,171.4,-42.2,-42.1,0,40 -171.3,171.4,-42.1,-42,0,40 -171.3,171.4,-42,-41.9,0,40 -171.3,171.4,-41.9,-41.8,0,40 -171.3,171.4,-41.8,-41.7,0,40 -171.3,171.4,-41.7,-41.6,0,40 -171.3,171.4,-41.6,-41.5,0,40 -171.3,171.4,-41.5,-41.4,0,40 -171.3,171.4,-41.4,-41.3,0,40 -171.3,171.4,-41.3,-41.2,0,40 -171.3,171.4,-41.2,-41.1,0,40 -171.3,171.4,-41.1,-41,0,40 -171.3,171.4,-41,-40.9,0,40 -171.3,171.4,-40.9,-40.8,0,40 -171.3,171.4,-40.8,-40.7,0,40 -171.3,171.4,-40.7,-40.6,0,40 -171.4,171.5,-46,-45.9,0,40 -171.4,171.5,-45.9,-45.8,0,40 -171.4,171.5,-45.8,-45.7,0,40 -171.4,171.5,-45.7,-45.6,0,40 -171.4,171.5,-45.6,-45.5,0,40 -171.4,171.5,-45.5,-45.4,0,40 -171.4,171.5,-45.4,-45.3,0,40 -171.4,171.5,-45.3,-45.2,0,40 -171.4,171.5,-45.2,-45.1,0,40 -171.4,171.5,-45.1,-45,0,40 -171.4,171.5,-45,-44.9,0,40 -171.4,171.5,-44.9,-44.8,0,40 -171.4,171.5,-44.8,-44.7,0,40 -171.4,171.5,-44.7,-44.6,0,40 -171.4,171.5,-44.6,-44.5,0,40 -171.4,171.5,-44.5,-44.4,0,40 -171.4,171.5,-44.4,-44.3,0,40 -171.4,171.5,-44.3,-44.2,0,40 -171.4,171.5,-44.2,-44.1,0,40 -171.4,171.5,-44.1,-44,0,40 -171.4,171.5,-44,-43.9,0,40 -171.4,171.5,-43.9,-43.8,0,40 -171.4,171.5,-43.8,-43.7,0,40 -171.4,171.5,-43.7,-43.6,0,40 -171.4,171.5,-43.6,-43.5,0,40 -171.4,171.5,-43.5,-43.4,0,40 -171.4,171.5,-43.4,-43.3,0,40 -171.4,171.5,-43.3,-43.2,0,40 -171.4,171.5,-43.2,-43.1,0,40 -171.4,171.5,-43.1,-43,0,40 -171.4,171.5,-43,-42.9,0,40 -171.4,171.5,-42.9,-42.8,0,40 -171.4,171.5,-42.8,-42.7,0,40 -171.4,171.5,-42.7,-42.6,0,40 -171.4,171.5,-42.6,-42.5,0,40 -171.4,171.5,-42.5,-42.4,0,40 -171.4,171.5,-42.4,-42.3,0,40 -171.4,171.5,-42.3,-42.2,0,40 -171.4,171.5,-42.2,-42.1,0,40 -171.4,171.5,-42.1,-42,0,40 -171.4,171.5,-42,-41.9,0,40 -171.4,171.5,-41.9,-41.8,0,40 -171.4,171.5,-41.8,-41.7,0,40 -171.4,171.5,-41.7,-41.6,0,40 -171.4,171.5,-41.6,-41.5,0,40 -171.4,171.5,-41.5,-41.4,0,40 -171.4,171.5,-41.4,-41.3,0,40 -171.4,171.5,-41.3,-41.2,0,40 -171.4,171.5,-41.2,-41.1,0,40 -171.4,171.5,-41.1,-41,0,40 -171.4,171.5,-41,-40.9,0,40 -171.4,171.5,-40.9,-40.8,0,40 -171.4,171.5,-40.8,-40.7,0,40 -171.4,171.5,-40.7,-40.6,0,40 -171.4,171.5,-40.6,-40.5,0,40 -171.5,171.6,-45.7,-45.6,0,40 -171.5,171.6,-45.6,-45.5,0,40 -171.5,171.6,-45.5,-45.4,0,40 -171.5,171.6,-45.4,-45.3,0,40 -171.5,171.6,-45.3,-45.2,0,40 -171.5,171.6,-45.2,-45.1,0,40 -171.5,171.6,-45.1,-45,0,40 -171.5,171.6,-45,-44.9,0,40 -171.5,171.6,-44.9,-44.8,0,40 -171.5,171.6,-44.8,-44.7,0,40 -171.5,171.6,-44.7,-44.6,0,40 -171.5,171.6,-44.6,-44.5,0,40 -171.5,171.6,-44.5,-44.4,0,40 -171.5,171.6,-44.4,-44.3,0,40 -171.5,171.6,-44.3,-44.2,0,40 -171.5,171.6,-44.2,-44.1,0,40 -171.5,171.6,-44.1,-44,0,40 -171.5,171.6,-44,-43.9,0,40 -171.5,171.6,-43.9,-43.8,0,40 -171.5,171.6,-43.8,-43.7,0,40 -171.5,171.6,-43.7,-43.6,0,40 -171.5,171.6,-43.6,-43.5,0,40 -171.5,171.6,-43.5,-43.4,0,40 -171.5,171.6,-43.4,-43.3,0,40 -171.5,171.6,-43.3,-43.2,0,40 -171.5,171.6,-43.2,-43.1,0,40 -171.5,171.6,-43.1,-43,0,40 -171.5,171.6,-43,-42.9,0,40 -171.5,171.6,-42.9,-42.8,0,40 -171.5,171.6,-42.8,-42.7,0,40 -171.5,171.6,-42.7,-42.6,0,40 -171.5,171.6,-42.6,-42.5,0,40 -171.5,171.6,-42.5,-42.4,0,40 -171.5,171.6,-42.4,-42.3,0,40 -171.5,171.6,-42.3,-42.2,0,40 -171.5,171.6,-42.2,-42.1,0,40 -171.5,171.6,-42.1,-42,0,40 -171.5,171.6,-42,-41.9,0,40 -171.5,171.6,-41.9,-41.8,0,40 -171.5,171.6,-41.8,-41.7,0,40 -171.5,171.6,-41.7,-41.6,0,40 -171.5,171.6,-41.6,-41.5,0,40 -171.5,171.6,-41.5,-41.4,0,40 -171.5,171.6,-41.4,-41.3,0,40 -171.5,171.6,-41.3,-41.2,0,40 -171.5,171.6,-41.2,-41.1,0,40 -171.5,171.6,-41.1,-41,0,40 -171.5,171.6,-41,-40.9,0,40 -171.5,171.6,-40.9,-40.8,0,40 -171.5,171.6,-40.8,-40.7,0,40 -171.5,171.6,-40.7,-40.6,0,40 -171.5,171.6,-40.6,-40.5,0,40 -171.5,171.6,-40.5,-40.4,0,40 -171.6,171.7,-45.4,-45.3,0,40 -171.6,171.7,-45.3,-45.2,0,40 -171.6,171.7,-45.2,-45.1,0,40 -171.6,171.7,-45.1,-45,0,40 -171.6,171.7,-45,-44.9,0,40 -171.6,171.7,-44.9,-44.8,0,40 -171.6,171.7,-44.8,-44.7,0,40 -171.6,171.7,-44.7,-44.6,0,40 -171.6,171.7,-44.6,-44.5,0,40 -171.6,171.7,-44.5,-44.4,0,40 -171.6,171.7,-44.4,-44.3,0,40 -171.6,171.7,-44.3,-44.2,0,40 -171.6,171.7,-44.2,-44.1,0,40 -171.6,171.7,-44.1,-44,0,40 -171.6,171.7,-44,-43.9,0,40 -171.6,171.7,-43.9,-43.8,0,40 -171.6,171.7,-43.8,-43.7,0,40 -171.6,171.7,-43.7,-43.6,0,40 -171.6,171.7,-43.6,-43.5,0,40 -171.6,171.7,-43.5,-43.4,0,40 -171.6,171.7,-43.4,-43.3,0,40 -171.6,171.7,-43.3,-43.2,0,40 -171.6,171.7,-43.2,-43.1,0,40 -171.6,171.7,-43.1,-43,0,40 -171.6,171.7,-43,-42.9,0,40 -171.6,171.7,-42.9,-42.8,0,40 -171.6,171.7,-42.8,-42.7,0,40 -171.6,171.7,-42.7,-42.6,0,40 -171.6,171.7,-42.6,-42.5,0,40 -171.6,171.7,-42.5,-42.4,0,40 -171.6,171.7,-42.4,-42.3,0,40 -171.6,171.7,-42.3,-42.2,0,40 -171.6,171.7,-42.2,-42.1,0,40 -171.6,171.7,-42.1,-42,0,40 -171.6,171.7,-42,-41.9,0,40 -171.6,171.7,-41.9,-41.8,0,40 -171.6,171.7,-41.8,-41.7,0,40 -171.6,171.7,-41.7,-41.6,0,40 -171.6,171.7,-41.6,-41.5,0,40 -171.6,171.7,-41.5,-41.4,0,40 -171.6,171.7,-41.4,-41.3,0,40 -171.6,171.7,-41.3,-41.2,0,40 -171.6,171.7,-41.2,-41.1,0,40 -171.6,171.7,-41.1,-41,0,40 -171.6,171.7,-41,-40.9,0,40 -171.6,171.7,-40.9,-40.8,0,40 -171.6,171.7,-40.8,-40.7,0,40 -171.6,171.7,-40.7,-40.6,0,40 -171.6,171.7,-40.6,-40.5,0,40 -171.6,171.7,-40.5,-40.4,0,40 -171.7,171.8,-45.2,-45.1,0,40 -171.7,171.8,-45.1,-45,0,40 -171.7,171.8,-45,-44.9,0,40 -171.7,171.8,-44.9,-44.8,0,40 -171.7,171.8,-44.8,-44.7,0,40 -171.7,171.8,-44.7,-44.6,0,40 -171.7,171.8,-44.6,-44.5,0,40 -171.7,171.8,-44.5,-44.4,0,40 -171.7,171.8,-44.4,-44.3,0,40 -171.7,171.8,-44.3,-44.2,0,40 -171.7,171.8,-44.2,-44.1,0,40 -171.7,171.8,-44.1,-44,0,40 -171.7,171.8,-44,-43.9,0,40 -171.7,171.8,-43.9,-43.8,0,40 -171.7,171.8,-43.8,-43.7,0,40 -171.7,171.8,-43.7,-43.6,0,40 -171.7,171.8,-43.6,-43.5,0,40 -171.7,171.8,-43.5,-43.4,0,40 -171.7,171.8,-43.4,-43.3,0,40 -171.7,171.8,-43.3,-43.2,0,40 -171.7,171.8,-43.2,-43.1,0,40 -171.7,171.8,-43.1,-43,0,40 -171.7,171.8,-43,-42.9,0,40 -171.7,171.8,-42.9,-42.8,0,40 -171.7,171.8,-42.8,-42.7,0,40 -171.7,171.8,-42.7,-42.6,0,40 -171.7,171.8,-42.6,-42.5,0,40 -171.7,171.8,-42.5,-42.4,0,40 -171.7,171.8,-42.4,-42.3,0,40 -171.7,171.8,-42.3,-42.2,0,40 -171.7,171.8,-42.2,-42.1,0,40 -171.7,171.8,-42.1,-42,0,40 -171.7,171.8,-42,-41.9,0,40 -171.7,171.8,-41.9,-41.8,0,40 -171.7,171.8,-41.8,-41.7,0,40 -171.7,171.8,-41.7,-41.6,0,40 -171.7,171.8,-41.6,-41.5,0,40 -171.7,171.8,-41.5,-41.4,0,40 -171.7,171.8,-41.4,-41.3,0,40 -171.7,171.8,-41.3,-41.2,0,40 -171.7,171.8,-41.2,-41.1,0,40 -171.7,171.8,-41.1,-41,0,40 -171.7,171.8,-41,-40.9,0,40 -171.7,171.8,-40.9,-40.8,0,40 -171.7,171.8,-40.8,-40.7,0,40 -171.7,171.8,-40.7,-40.6,0,40 -171.7,171.8,-40.6,-40.5,0,40 -171.7,171.8,-40.5,-40.4,0,40 -171.7,171.8,-40.4,-40.3,0,40 -171.8,171.9,-45,-44.9,0,40 -171.8,171.9,-44.9,-44.8,0,40 -171.8,171.9,-44.8,-44.7,0,40 -171.8,171.9,-44.7,-44.6,0,40 -171.8,171.9,-44.6,-44.5,0,40 -171.8,171.9,-44.5,-44.4,0,40 -171.8,171.9,-44.4,-44.3,0,40 -171.8,171.9,-44.3,-44.2,0,40 -171.8,171.9,-44.2,-44.1,0,40 -171.8,171.9,-44.1,-44,0,40 -171.8,171.9,-44,-43.9,0,40 -171.8,171.9,-43.9,-43.8,0,40 -171.8,171.9,-43.8,-43.7,0,40 -171.8,171.9,-43.7,-43.6,0,40 -171.8,171.9,-43.6,-43.5,0,40 -171.8,171.9,-43.5,-43.4,0,40 -171.8,171.9,-43.4,-43.3,0,40 -171.8,171.9,-43.3,-43.2,0,40 -171.8,171.9,-43.2,-43.1,0,40 -171.8,171.9,-43.1,-43,0,40 -171.8,171.9,-43,-42.9,0,40 -171.8,171.9,-42.9,-42.8,0,40 -171.8,171.9,-42.8,-42.7,0,40 -171.8,171.9,-42.7,-42.6,0,40 -171.8,171.9,-42.6,-42.5,0,40 -171.8,171.9,-42.5,-42.4,0,40 -171.8,171.9,-42.4,-42.3,0,40 -171.8,171.9,-42.3,-42.2,0,40 -171.8,171.9,-42.2,-42.1,0,40 -171.8,171.9,-42.1,-42,0,40 -171.8,171.9,-42,-41.9,0,40 -171.8,171.9,-41.9,-41.8,0,40 -171.8,171.9,-41.8,-41.7,0,40 -171.8,171.9,-41.7,-41.6,0,40 -171.8,171.9,-41.6,-41.5,0,40 -171.8,171.9,-41.5,-41.4,0,40 -171.8,171.9,-41.4,-41.3,0,40 -171.8,171.9,-41.3,-41.2,0,40 -171.8,171.9,-41.2,-41.1,0,40 -171.8,171.9,-41.1,-41,0,40 -171.8,171.9,-41,-40.9,0,40 -171.8,171.9,-40.9,-40.8,0,40 -171.8,171.9,-40.8,-40.7,0,40 -171.8,171.9,-40.7,-40.6,0,40 -171.8,171.9,-40.6,-40.5,0,40 -171.8,171.9,-40.5,-40.4,0,40 -171.8,171.9,-40.4,-40.3,0,40 -171.8,171.9,-40.3,-40.2,0,40 -171.9,172,-44.5,-44.4,0,40 -171.9,172,-44.4,-44.3,0,40 -171.9,172,-44.3,-44.2,0,40 -171.9,172,-44.2,-44.1,0,40 -171.9,172,-44.1,-44,0,40 -171.9,172,-44,-43.9,0,40 -171.9,172,-43.9,-43.8,0,40 -171.9,172,-43.8,-43.7,0,40 -171.9,172,-43.7,-43.6,0,40 -171.9,172,-43.6,-43.5,0,40 -171.9,172,-43.5,-43.4,0,40 -171.9,172,-43.4,-43.3,0,40 -171.9,172,-43.3,-43.2,0,40 -171.9,172,-43.2,-43.1,0,40 -171.9,172,-43.1,-43,0,40 -171.9,172,-43,-42.9,0,40 -171.9,172,-42.9,-42.8,0,40 -171.9,172,-42.8,-42.7,0,40 -171.9,172,-42.7,-42.6,0,40 -171.9,172,-42.6,-42.5,0,40 -171.9,172,-42.5,-42.4,0,40 -171.9,172,-42.4,-42.3,0,40 -171.9,172,-42.3,-42.2,0,40 -171.9,172,-42.2,-42.1,0,40 -171.9,172,-42.1,-42,0,40 -171.9,172,-42,-41.9,0,40 -171.9,172,-41.9,-41.8,0,40 -171.9,172,-41.8,-41.7,0,40 -171.9,172,-41.7,-41.6,0,40 -171.9,172,-41.6,-41.5,0,40 -171.9,172,-41.5,-41.4,0,40 -171.9,172,-41.4,-41.3,0,40 -171.9,172,-41.3,-41.2,0,40 -171.9,172,-41.2,-41.1,0,40 -171.9,172,-41.1,-41,0,40 -171.9,172,-41,-40.9,0,40 -171.9,172,-40.9,-40.8,0,40 -171.9,172,-40.8,-40.7,0,40 -171.9,172,-40.7,-40.6,0,40 -171.9,172,-40.6,-40.5,0,40 -171.9,172,-40.5,-40.4,0,40 -171.9,172,-40.4,-40.3,0,40 -171.9,172,-40.3,-40.2,0,40 -171.9,172,-40.2,-40.1,0,40 -172,172.1,-44.5,-44.4,0,40 -172,172.1,-44.4,-44.3,0,40 -172,172.1,-44.3,-44.2,0,40 -172,172.1,-44.2,-44.1,0,40 -172,172.1,-44.1,-44,0,40 -172,172.1,-44,-43.9,0,40 -172,172.1,-43.9,-43.8,0,40 -172,172.1,-43.8,-43.7,0,40 -172,172.1,-43.7,-43.6,0,40 -172,172.1,-43.6,-43.5,0,40 -172,172.1,-43.5,-43.4,0,40 -172,172.1,-43.4,-43.3,0,40 -172,172.1,-43.3,-43.2,0,40 -172,172.1,-43.2,-43.1,0,40 -172,172.1,-43.1,-43,0,40 -172,172.1,-43,-42.9,0,40 -172,172.1,-42.9,-42.8,0,40 -172,172.1,-42.8,-42.7,0,40 -172,172.1,-42.7,-42.6,0,40 -172,172.1,-42.6,-42.5,0,40 -172,172.1,-42.5,-42.4,0,40 -172,172.1,-42.4,-42.3,0,40 -172,172.1,-42.3,-42.2,0,40 -172,172.1,-42.2,-42.1,0,40 -172,172.1,-42.1,-42,0,40 -172,172.1,-42,-41.9,0,40 -172,172.1,-41.9,-41.8,0,40 -172,172.1,-41.8,-41.7,0,40 -172,172.1,-41.7,-41.6,0,40 -172,172.1,-41.6,-41.5,0,40 -172,172.1,-41.5,-41.4,0,40 -172,172.1,-41.4,-41.3,0,40 -172,172.1,-41.3,-41.2,0,40 -172,172.1,-41.2,-41.1,0,40 -172,172.1,-41.1,-41,0,40 -172,172.1,-41,-40.9,0,40 -172,172.1,-40.9,-40.8,0,40 -172,172.1,-40.8,-40.7,0,40 -172,172.1,-40.7,-40.6,0,40 -172,172.1,-40.6,-40.5,0,40 -172,172.1,-40.5,-40.4,0,40 -172,172.1,-40.4,-40.3,0,40 -172,172.1,-40.3,-40.2,0,40 -172,172.1,-40.2,-40.1,0,40 -172,172.1,-40.1,-40,0,40 -172.1,172.2,-44.5,-44.4,0,40 -172.1,172.2,-44.4,-44.3,0,40 -172.1,172.2,-44.3,-44.2,0,40 -172.1,172.2,-44.2,-44.1,0,40 -172.1,172.2,-44.1,-44,0,40 -172.1,172.2,-44,-43.9,0,40 -172.1,172.2,-43.9,-43.8,0,40 -172.1,172.2,-43.8,-43.7,0,40 -172.1,172.2,-43.7,-43.6,0,40 -172.1,172.2,-43.6,-43.5,0,40 -172.1,172.2,-43.5,-43.4,0,40 -172.1,172.2,-43.4,-43.3,0,40 -172.1,172.2,-43.3,-43.2,0,40 -172.1,172.2,-43.2,-43.1,0,40 -172.1,172.2,-43.1,-43,0,40 -172.1,172.2,-43,-42.9,0,40 -172.1,172.2,-42.9,-42.8,0,40 -172.1,172.2,-42.8,-42.7,0,40 -172.1,172.2,-42.7,-42.6,0,40 -172.1,172.2,-42.6,-42.5,0,40 -172.1,172.2,-42.5,-42.4,0,40 -172.1,172.2,-42.4,-42.3,0,40 -172.1,172.2,-42.3,-42.2,0,40 -172.1,172.2,-42.2,-42.1,0,40 -172.1,172.2,-42.1,-42,0,40 -172.1,172.2,-42,-41.9,0,40 -172.1,172.2,-41.9,-41.8,0,40 -172.1,172.2,-41.8,-41.7,0,40 -172.1,172.2,-41.7,-41.6,0,40 -172.1,172.2,-41.6,-41.5,0,40 -172.1,172.2,-41.5,-41.4,0,40 -172.1,172.2,-41.4,-41.3,0,40 -172.1,172.2,-41.3,-41.2,0,40 -172.1,172.2,-41.2,-41.1,0,40 -172.1,172.2,-41.1,-41,0,40 -172.1,172.2,-41,-40.9,0,40 -172.1,172.2,-40.9,-40.8,0,40 -172.1,172.2,-40.8,-40.7,0,40 -172.1,172.2,-40.7,-40.6,0,40 -172.1,172.2,-40.6,-40.5,0,40 -172.1,172.2,-40.5,-40.4,0,40 -172.1,172.2,-40.4,-40.3,0,40 -172.1,172.2,-40.3,-40.2,0,40 -172.1,172.2,-40.2,-40.1,0,40 -172.1,172.2,-40.1,-40,0,40 -172.1,172.2,-40,-39.9,0,40 -172.2,172.3,-44.4,-44.3,0,40 -172.2,172.3,-44.3,-44.2,0,40 -172.2,172.3,-44.2,-44.1,0,40 -172.2,172.3,-44.1,-44,0,40 -172.2,172.3,-44,-43.9,0,40 -172.2,172.3,-43.9,-43.8,0,40 -172.2,172.3,-43.8,-43.7,0,40 -172.2,172.3,-43.7,-43.6,0,40 -172.2,172.3,-43.6,-43.5,0,40 -172.2,172.3,-43.5,-43.4,0,40 -172.2,172.3,-43.4,-43.3,0,40 -172.2,172.3,-43.3,-43.2,0,40 -172.2,172.3,-43.2,-43.1,0,40 -172.2,172.3,-43.1,-43,0,40 -172.2,172.3,-43,-42.9,0,40 -172.2,172.3,-42.9,-42.8,0,40 -172.2,172.3,-42.8,-42.7,0,40 -172.2,172.3,-42.7,-42.6,0,40 -172.2,172.3,-42.6,-42.5,0,40 -172.2,172.3,-42.5,-42.4,0,40 -172.2,172.3,-42.4,-42.3,0,40 -172.2,172.3,-42.3,-42.2,0,40 -172.2,172.3,-42.2,-42.1,0,40 -172.2,172.3,-42.1,-42,0,40 -172.2,172.3,-42,-41.9,0,40 -172.2,172.3,-41.9,-41.8,0,40 -172.2,172.3,-41.8,-41.7,0,40 -172.2,172.3,-41.7,-41.6,0,40 -172.2,172.3,-41.6,-41.5,0,40 -172.2,172.3,-41.5,-41.4,0,40 -172.2,172.3,-41.4,-41.3,0,40 -172.2,172.3,-41.3,-41.2,0,40 -172.2,172.3,-41.2,-41.1,0,40 -172.2,172.3,-41.1,-41,0,40 -172.2,172.3,-41,-40.9,0,40 -172.2,172.3,-40.9,-40.8,0,40 -172.2,172.3,-40.8,-40.7,0,40 -172.2,172.3,-40.7,-40.6,0,40 -172.2,172.3,-40.6,-40.5,0,40 -172.2,172.3,-40.5,-40.4,0,40 -172.2,172.3,-40.4,-40.3,0,40 -172.2,172.3,-40.3,-40.2,0,40 -172.2,172.3,-40.2,-40.1,0,40 -172.2,172.3,-40.1,-40,0,40 -172.2,172.3,-40,-39.9,0,40 -172.2,172.3,-39.9,-39.8,0,40 -172.2,172.3,-34.8,-34.7,0,40 -172.2,172.3,-34.7,-34.6,0,40 -172.2,172.3,-34.6,-34.5,0,40 -172.2,172.3,-34.5,-34.4,0,40 -172.2,172.3,-34.4,-34.3,0,40 -172.3,172.4,-44.4,-44.3,0,40 -172.3,172.4,-44.3,-44.2,0,40 -172.3,172.4,-44.2,-44.1,0,40 -172.3,172.4,-44.1,-44,0,40 -172.3,172.4,-44,-43.9,0,40 -172.3,172.4,-43.9,-43.8,0,40 -172.3,172.4,-43.8,-43.7,0,40 -172.3,172.4,-43.7,-43.6,0,40 -172.3,172.4,-43.6,-43.5,0,40 -172.3,172.4,-43.5,-43.4,0,40 -172.3,172.4,-43.4,-43.3,0,40 -172.3,172.4,-43.3,-43.2,0,40 -172.3,172.4,-43.2,-43.1,0,40 -172.3,172.4,-43.1,-43,0,40 -172.3,172.4,-43,-42.9,0,40 -172.3,172.4,-42.9,-42.8,0,40 -172.3,172.4,-42.8,-42.7,0,40 -172.3,172.4,-42.7,-42.6,0,40 -172.3,172.4,-42.6,-42.5,0,40 -172.3,172.4,-42.5,-42.4,0,40 -172.3,172.4,-42.4,-42.3,0,40 -172.3,172.4,-42.3,-42.2,0,40 -172.3,172.4,-42.2,-42.1,0,40 -172.3,172.4,-42.1,-42,0,40 -172.3,172.4,-42,-41.9,0,40 -172.3,172.4,-41.9,-41.8,0,40 -172.3,172.4,-41.8,-41.7,0,40 -172.3,172.4,-41.7,-41.6,0,40 -172.3,172.4,-41.6,-41.5,0,40 -172.3,172.4,-41.5,-41.4,0,40 -172.3,172.4,-41.4,-41.3,0,40 -172.3,172.4,-41.3,-41.2,0,40 -172.3,172.4,-41.2,-41.1,0,40 -172.3,172.4,-41.1,-41,0,40 -172.3,172.4,-41,-40.9,0,40 -172.3,172.4,-40.9,-40.8,0,40 -172.3,172.4,-40.8,-40.7,0,40 -172.3,172.4,-40.7,-40.6,0,40 -172.3,172.4,-40.6,-40.5,0,40 -172.3,172.4,-40.5,-40.4,0,40 -172.3,172.4,-40.4,-40.3,0,40 -172.3,172.4,-40.3,-40.2,0,40 -172.3,172.4,-40.2,-40.1,0,40 -172.3,172.4,-40.1,-40,0,40 -172.3,172.4,-40,-39.9,0,40 -172.3,172.4,-39.9,-39.8,0,40 -172.3,172.4,-34.9,-34.8,0,40 -172.3,172.4,-34.8,-34.7,0,40 -172.3,172.4,-34.7,-34.6,0,40 -172.3,172.4,-34.6,-34.5,0,40 -172.3,172.4,-34.5,-34.4,0,40 -172.3,172.4,-34.4,-34.3,0,40 -172.3,172.4,-34.3,-34.2,0,40 -172.3,172.4,-34.2,-34.1,0,40 -172.4,172.5,-44.4,-44.3,0,40 -172.4,172.5,-44.3,-44.2,0,40 -172.4,172.5,-44.2,-44.1,0,40 -172.4,172.5,-44.1,-44,0,40 -172.4,172.5,-44,-43.9,0,40 -172.4,172.5,-43.9,-43.8,0,40 -172.4,172.5,-43.8,-43.7,0,40 -172.4,172.5,-43.7,-43.6,0,40 -172.4,172.5,-43.6,-43.5,0,40 -172.4,172.5,-43.5,-43.4,0,40 -172.4,172.5,-43.4,-43.3,0,40 -172.4,172.5,-43.3,-43.2,0,40 -172.4,172.5,-43.2,-43.1,0,40 -172.4,172.5,-43.1,-43,0,40 -172.4,172.5,-43,-42.9,0,40 -172.4,172.5,-42.9,-42.8,0,40 -172.4,172.5,-42.8,-42.7,0,40 -172.4,172.5,-42.7,-42.6,0,40 -172.4,172.5,-42.6,-42.5,0,40 -172.4,172.5,-42.5,-42.4,0,40 -172.4,172.5,-42.4,-42.3,0,40 -172.4,172.5,-42.3,-42.2,0,40 -172.4,172.5,-42.2,-42.1,0,40 -172.4,172.5,-42.1,-42,0,40 -172.4,172.5,-42,-41.9,0,40 -172.4,172.5,-41.9,-41.8,0,40 -172.4,172.5,-41.8,-41.7,0,40 -172.4,172.5,-41.7,-41.6,0,40 -172.4,172.5,-41.6,-41.5,0,40 -172.4,172.5,-41.5,-41.4,0,40 -172.4,172.5,-41.4,-41.3,0,40 -172.4,172.5,-41.3,-41.2,0,40 -172.4,172.5,-41.2,-41.1,0,40 -172.4,172.5,-41.1,-41,0,40 -172.4,172.5,-41,-40.9,0,40 -172.4,172.5,-40.9,-40.8,0,40 -172.4,172.5,-40.8,-40.7,0,40 -172.4,172.5,-40.7,-40.6,0,40 -172.4,172.5,-40.6,-40.5,0,40 -172.4,172.5,-40.5,-40.4,0,40 -172.4,172.5,-40.4,-40.3,0,40 -172.4,172.5,-40.3,-40.2,0,40 -172.4,172.5,-40.2,-40.1,0,40 -172.4,172.5,-40.1,-40,0,40 -172.4,172.5,-40,-39.9,0,40 -172.4,172.5,-39.9,-39.8,0,40 -172.4,172.5,-39.8,-39.7,0,40 -172.4,172.5,-35.1,-35,0,40 -172.4,172.5,-35,-34.9,0,40 -172.4,172.5,-34.9,-34.8,0,40 -172.4,172.5,-34.8,-34.7,0,40 -172.4,172.5,-34.7,-34.6,0,40 -172.4,172.5,-34.6,-34.5,0,40 -172.4,172.5,-34.5,-34.4,0,40 -172.4,172.5,-34.4,-34.3,0,40 -172.4,172.5,-34.3,-34.2,0,40 -172.4,172.5,-34.2,-34.1,0,40 -172.4,172.5,-34.1,-34,0,40 -172.5,172.6,-44.3,-44.2,0,40 -172.5,172.6,-44.2,-44.1,0,40 -172.5,172.6,-44.1,-44,0,40 -172.5,172.6,-44,-43.9,0,40 -172.5,172.6,-43.9,-43.8,0,40 -172.5,172.6,-43.8,-43.7,0,40 -172.5,172.6,-43.7,-43.6,0,40 -172.5,172.6,-43.6,-43.5,0,40 -172.5,172.6,-43.5,-43.4,0,40 -172.5,172.6,-43.4,-43.3,0,40 -172.5,172.6,-43.3,-43.2,0,40 -172.5,172.6,-43.2,-43.1,0,40 -172.5,172.6,-43.1,-43,0,40 -172.5,172.6,-43,-42.9,0,40 -172.5,172.6,-42.9,-42.8,0,40 -172.5,172.6,-42.8,-42.7,0,40 -172.5,172.6,-42.7,-42.6,0,40 -172.5,172.6,-42.6,-42.5,0,40 -172.5,172.6,-42.5,-42.4,0,40 -172.5,172.6,-42.4,-42.3,0,40 -172.5,172.6,-42.3,-42.2,0,40 -172.5,172.6,-42.2,-42.1,0,40 -172.5,172.6,-42.1,-42,0,40 -172.5,172.6,-42,-41.9,0,40 -172.5,172.6,-41.9,-41.8,0,40 -172.5,172.6,-41.8,-41.7,0,40 -172.5,172.6,-41.7,-41.6,0,40 -172.5,172.6,-41.6,-41.5,0,40 -172.5,172.6,-41.5,-41.4,0,40 -172.5,172.6,-41.4,-41.3,0,40 -172.5,172.6,-41.3,-41.2,0,40 -172.5,172.6,-41.2,-41.1,0,40 -172.5,172.6,-41.1,-41,0,40 -172.5,172.6,-41,-40.9,0,40 -172.5,172.6,-40.9,-40.8,0,40 -172.5,172.6,-40.8,-40.7,0,40 -172.5,172.6,-40.7,-40.6,0,40 -172.5,172.6,-40.6,-40.5,0,40 -172.5,172.6,-40.5,-40.4,0,40 -172.5,172.6,-40.4,-40.3,0,40 -172.5,172.6,-40.3,-40.2,0,40 -172.5,172.6,-40.2,-40.1,0,40 -172.5,172.6,-40.1,-40,0,40 -172.5,172.6,-40,-39.9,0,40 -172.5,172.6,-39.9,-39.8,0,40 -172.5,172.6,-39.8,-39.7,0,40 -172.5,172.6,-39.7,-39.6,0,40 -172.5,172.6,-35.5,-35.4,0,40 -172.5,172.6,-35.4,-35.3,0,40 -172.5,172.6,-35.3,-35.2,0,40 -172.5,172.6,-35.2,-35.1,0,40 -172.5,172.6,-35.1,-35,0,40 -172.5,172.6,-35,-34.9,0,40 -172.5,172.6,-34.9,-34.8,0,40 -172.5,172.6,-34.8,-34.7,0,40 -172.5,172.6,-34.7,-34.6,0,40 -172.5,172.6,-34.6,-34.5,0,40 -172.5,172.6,-34.5,-34.4,0,40 -172.5,172.6,-34.4,-34.3,0,40 -172.5,172.6,-34.3,-34.2,0,40 -172.5,172.6,-34.2,-34.1,0,40 -172.5,172.6,-34.1,-34,0,40 -172.6,172.7,-44.3,-44.2,0,40 -172.6,172.7,-44.2,-44.1,0,40 -172.6,172.7,-44.1,-44,0,40 -172.6,172.7,-44,-43.9,0,40 -172.6,172.7,-43.9,-43.8,0,40 -172.6,172.7,-43.8,-43.7,0,40 -172.6,172.7,-43.7,-43.6,0,40 -172.6,172.7,-43.6,-43.5,0,40 -172.6,172.7,-43.5,-43.4,0,40 -172.6,172.7,-43.4,-43.3,0,40 -172.6,172.7,-43.3,-43.2,0,40 -172.6,172.7,-43.2,-43.1,0,40 -172.6,172.7,-43.1,-43,0,40 -172.6,172.7,-43,-42.9,0,40 -172.6,172.7,-42.9,-42.8,0,40 -172.6,172.7,-42.8,-42.7,0,40 -172.6,172.7,-42.7,-42.6,0,40 -172.6,172.7,-42.6,-42.5,0,40 -172.6,172.7,-42.5,-42.4,0,40 -172.6,172.7,-42.4,-42.3,0,40 -172.6,172.7,-42.3,-42.2,0,40 -172.6,172.7,-42.2,-42.1,0,40 -172.6,172.7,-42.1,-42,0,40 -172.6,172.7,-42,-41.9,0,40 -172.6,172.7,-41.9,-41.8,0,40 -172.6,172.7,-41.8,-41.7,0,40 -172.6,172.7,-41.7,-41.6,0,40 -172.6,172.7,-41.6,-41.5,0,40 -172.6,172.7,-41.5,-41.4,0,40 -172.6,172.7,-41.4,-41.3,0,40 -172.6,172.7,-41.3,-41.2,0,40 -172.6,172.7,-41.2,-41.1,0,40 -172.6,172.7,-41.1,-41,0,40 -172.6,172.7,-41,-40.9,0,40 -172.6,172.7,-40.9,-40.8,0,40 -172.6,172.7,-40.8,-40.7,0,40 -172.6,172.7,-40.7,-40.6,0,40 -172.6,172.7,-40.6,-40.5,0,40 -172.6,172.7,-40.5,-40.4,0,40 -172.6,172.7,-40.4,-40.3,0,40 -172.6,172.7,-40.3,-40.2,0,40 -172.6,172.7,-40.2,-40.1,0,40 -172.6,172.7,-40.1,-40,0,40 -172.6,172.7,-40,-39.9,0,40 -172.6,172.7,-39.9,-39.8,0,40 -172.6,172.7,-39.8,-39.7,0,40 -172.6,172.7,-39.7,-39.6,0,40 -172.6,172.7,-39.6,-39.5,0,40 -172.6,172.7,-35.6,-35.5,0,40 -172.6,172.7,-35.5,-35.4,0,40 -172.6,172.7,-35.4,-35.3,0,40 -172.6,172.7,-35.3,-35.2,0,40 -172.6,172.7,-35.2,-35.1,0,40 -172.6,172.7,-35.1,-35,0,40 -172.6,172.7,-35,-34.9,0,40 -172.6,172.7,-34.9,-34.8,0,40 -172.6,172.7,-34.8,-34.7,0,40 -172.6,172.7,-34.7,-34.6,0,40 -172.6,172.7,-34.6,-34.5,0,40 -172.6,172.7,-34.5,-34.4,0,40 -172.6,172.7,-34.4,-34.3,0,40 -172.6,172.7,-34.3,-34.2,0,40 -172.6,172.7,-34.2,-34.1,0,40 -172.6,172.7,-34.1,-34,0,40 -172.6,172.7,-34,-33.9,0,40 -172.7,172.8,-44.4,-44.3,0,40 -172.7,172.8,-44.3,-44.2,0,40 -172.7,172.8,-44.2,-44.1,0,40 -172.7,172.8,-44.1,-44,0,40 -172.7,172.8,-44,-43.9,0,40 -172.7,172.8,-43.9,-43.8,0,40 -172.7,172.8,-43.8,-43.7,0,40 -172.7,172.8,-43.7,-43.6,0,40 -172.7,172.8,-43.6,-43.5,0,40 -172.7,172.8,-43.5,-43.4,0,40 -172.7,172.8,-43.4,-43.3,0,40 -172.7,172.8,-43.3,-43.2,0,40 -172.7,172.8,-43.2,-43.1,0,40 -172.7,172.8,-43.1,-43,0,40 -172.7,172.8,-43,-42.9,0,40 -172.7,172.8,-42.9,-42.8,0,40 -172.7,172.8,-42.8,-42.7,0,40 -172.7,172.8,-42.7,-42.6,0,40 -172.7,172.8,-42.6,-42.5,0,40 -172.7,172.8,-42.5,-42.4,0,40 -172.7,172.8,-42.4,-42.3,0,40 -172.7,172.8,-42.3,-42.2,0,40 -172.7,172.8,-42.2,-42.1,0,40 -172.7,172.8,-42.1,-42,0,40 -172.7,172.8,-42,-41.9,0,40 -172.7,172.8,-41.9,-41.8,0,40 -172.7,172.8,-41.8,-41.7,0,40 -172.7,172.8,-41.7,-41.6,0,40 -172.7,172.8,-41.6,-41.5,0,40 -172.7,172.8,-41.5,-41.4,0,40 -172.7,172.8,-41.4,-41.3,0,40 -172.7,172.8,-41.3,-41.2,0,40 -172.7,172.8,-41.2,-41.1,0,40 -172.7,172.8,-41.1,-41,0,40 -172.7,172.8,-41,-40.9,0,40 -172.7,172.8,-40.9,-40.8,0,40 -172.7,172.8,-40.8,-40.7,0,40 -172.7,172.8,-40.7,-40.6,0,40 -172.7,172.8,-40.6,-40.5,0,40 -172.7,172.8,-40.5,-40.4,0,40 -172.7,172.8,-40.4,-40.3,0,40 -172.7,172.8,-40.3,-40.2,0,40 -172.7,172.8,-40.2,-40.1,0,40 -172.7,172.8,-40.1,-40,0,40 -172.7,172.8,-40,-39.9,0,40 -172.7,172.8,-39.9,-39.8,0,40 -172.7,172.8,-39.8,-39.7,0,40 -172.7,172.8,-39.7,-39.6,0,40 -172.7,172.8,-39.6,-39.5,0,40 -172.7,172.8,-39.5,-39.4,0,40 -172.7,172.8,-35.7,-35.6,0,40 -172.7,172.8,-35.6,-35.5,0,40 -172.7,172.8,-35.5,-35.4,0,40 -172.7,172.8,-35.4,-35.3,0,40 -172.7,172.8,-35.3,-35.2,0,40 -172.7,172.8,-35.2,-35.1,0,40 -172.7,172.8,-35.1,-35,0,40 -172.7,172.8,-35,-34.9,0,40 -172.7,172.8,-34.9,-34.8,0,40 -172.7,172.8,-34.8,-34.7,0,40 -172.7,172.8,-34.7,-34.6,0,40 -172.7,172.8,-34.6,-34.5,0,40 -172.7,172.8,-34.5,-34.4,0,40 -172.7,172.8,-34.4,-34.3,0,40 -172.7,172.8,-34.3,-34.2,0,40 -172.7,172.8,-34.2,-34.1,0,40 -172.7,172.8,-34.1,-34,0,40 -172.7,172.8,-34,-33.9,0,40 -172.8,172.9,-44.4,-44.3,0,40 -172.8,172.9,-44.3,-44.2,0,40 -172.8,172.9,-44.2,-44.1,0,40 -172.8,172.9,-44.1,-44,0,40 -172.8,172.9,-44,-43.9,0,40 -172.8,172.9,-43.9,-43.8,0,40 -172.8,172.9,-43.8,-43.7,0,40 -172.8,172.9,-43.7,-43.6,0,40 -172.8,172.9,-43.6,-43.5,0,40 -172.8,172.9,-43.5,-43.4,0,40 -172.8,172.9,-43.4,-43.3,0,40 -172.8,172.9,-43.3,-43.2,0,40 -172.8,172.9,-43.2,-43.1,0,40 -172.8,172.9,-43.1,-43,0,40 -172.8,172.9,-43,-42.9,0,40 -172.8,172.9,-42.9,-42.8,0,40 -172.8,172.9,-42.8,-42.7,0,40 -172.8,172.9,-42.7,-42.6,0,40 -172.8,172.9,-42.6,-42.5,0,40 -172.8,172.9,-42.5,-42.4,0,40 -172.8,172.9,-42.4,-42.3,0,40 -172.8,172.9,-42.3,-42.2,0,40 -172.8,172.9,-42.2,-42.1,0,40 -172.8,172.9,-42.1,-42,0,40 -172.8,172.9,-42,-41.9,0,40 -172.8,172.9,-41.9,-41.8,0,40 -172.8,172.9,-41.8,-41.7,0,40 -172.8,172.9,-41.7,-41.6,0,40 -172.8,172.9,-41.6,-41.5,0,40 -172.8,172.9,-41.5,-41.4,0,40 -172.8,172.9,-41.4,-41.3,0,40 -172.8,172.9,-41.3,-41.2,0,40 -172.8,172.9,-41.2,-41.1,0,40 -172.8,172.9,-41.1,-41,0,40 -172.8,172.9,-41,-40.9,0,40 -172.8,172.9,-40.9,-40.8,0,40 -172.8,172.9,-40.8,-40.7,0,40 -172.8,172.9,-40.7,-40.6,0,40 -172.8,172.9,-40.6,-40.5,0,40 -172.8,172.9,-40.5,-40.4,0,40 -172.8,172.9,-40.4,-40.3,0,40 -172.8,172.9,-40.3,-40.2,0,40 -172.8,172.9,-40.2,-40.1,0,40 -172.8,172.9,-40.1,-40,0,40 -172.8,172.9,-40,-39.9,0,40 -172.8,172.9,-39.9,-39.8,0,40 -172.8,172.9,-39.8,-39.7,0,40 -172.8,172.9,-39.7,-39.6,0,40 -172.8,172.9,-39.6,-39.5,0,40 -172.8,172.9,-39.5,-39.4,0,40 -172.8,172.9,-39.4,-39.3,0,40 -172.8,172.9,-35.8,-35.7,0,40 -172.8,172.9,-35.7,-35.6,0,40 -172.8,172.9,-35.6,-35.5,0,40 -172.8,172.9,-35.5,-35.4,0,40 -172.8,172.9,-35.4,-35.3,0,40 -172.8,172.9,-35.3,-35.2,0,40 -172.8,172.9,-35.2,-35.1,0,40 -172.8,172.9,-35.1,-35,0,40 -172.8,172.9,-35,-34.9,0,40 -172.8,172.9,-34.9,-34.8,0,40 -172.8,172.9,-34.8,-34.7,0,40 -172.8,172.9,-34.7,-34.6,0,40 -172.8,172.9,-34.6,-34.5,0,40 -172.8,172.9,-34.5,-34.4,0,40 -172.8,172.9,-34.4,-34.3,0,40 -172.8,172.9,-34.3,-34.2,0,40 -172.8,172.9,-34.2,-34.1,0,40 -172.8,172.9,-34.1,-34,0,40 -172.8,172.9,-34,-33.9,0,40 -172.9,173,-44.4,-44.3,0,40 -172.9,173,-44.3,-44.2,0,40 -172.9,173,-44.2,-44.1,0,40 -172.9,173,-44.1,-44,0,40 -172.9,173,-44,-43.9,0,40 -172.9,173,-43.9,-43.8,0,40 -172.9,173,-43.8,-43.7,0,40 -172.9,173,-43.7,-43.6,0,40 -172.9,173,-43.6,-43.5,0,40 -172.9,173,-43.5,-43.4,0,40 -172.9,173,-43.4,-43.3,0,40 -172.9,173,-43.3,-43.2,0,40 -172.9,173,-43.2,-43.1,0,40 -172.9,173,-43.1,-43,0,40 -172.9,173,-43,-42.9,0,40 -172.9,173,-42.9,-42.8,0,40 -172.9,173,-42.8,-42.7,0,40 -172.9,173,-42.7,-42.6,0,40 -172.9,173,-42.6,-42.5,0,40 -172.9,173,-42.5,-42.4,0,40 -172.9,173,-42.4,-42.3,0,40 -172.9,173,-42.3,-42.2,0,40 -172.9,173,-42.2,-42.1,0,40 -172.9,173,-42.1,-42,0,40 -172.9,173,-42,-41.9,0,40 -172.9,173,-41.9,-41.8,0,40 -172.9,173,-41.8,-41.7,0,40 -172.9,173,-41.7,-41.6,0,40 -172.9,173,-41.6,-41.5,0,40 -172.9,173,-41.5,-41.4,0,40 -172.9,173,-41.4,-41.3,0,40 -172.9,173,-41.3,-41.2,0,40 -172.9,173,-41.2,-41.1,0,40 -172.9,173,-41.1,-41,0,40 -172.9,173,-41,-40.9,0,40 -172.9,173,-40.9,-40.8,0,40 -172.9,173,-40.8,-40.7,0,40 -172.9,173,-40.7,-40.6,0,40 -172.9,173,-40.6,-40.5,0,40 -172.9,173,-40.5,-40.4,0,40 -172.9,173,-40.4,-40.3,0,40 -172.9,173,-40.3,-40.2,0,40 -172.9,173,-40.2,-40.1,0,40 -172.9,173,-40.1,-40,0,40 -172.9,173,-40,-39.9,0,40 -172.9,173,-39.9,-39.8,0,40 -172.9,173,-39.8,-39.7,0,40 -172.9,173,-39.7,-39.6,0,40 -172.9,173,-39.6,-39.5,0,40 -172.9,173,-39.5,-39.4,0,40 -172.9,173,-39.4,-39.3,0,40 -172.9,173,-39.3,-39.2,0,40 -172.9,173,-35.9,-35.8,0,40 -172.9,173,-35.8,-35.7,0,40 -172.9,173,-35.7,-35.6,0,40 -172.9,173,-35.6,-35.5,0,40 -172.9,173,-35.5,-35.4,0,40 -172.9,173,-35.4,-35.3,0,40 -172.9,173,-35.3,-35.2,0,40 -172.9,173,-35.2,-35.1,0,40 -172.9,173,-35.1,-35,0,40 -172.9,173,-35,-34.9,0,40 -172.9,173,-34.9,-34.8,0,40 -172.9,173,-34.8,-34.7,0,40 -172.9,173,-34.7,-34.6,0,40 -172.9,173,-34.6,-34.5,0,40 -172.9,173,-34.5,-34.4,0,40 -172.9,173,-34.4,-34.3,0,40 -172.9,173,-34.3,-34.2,0,40 -172.9,173,-34.2,-34.1,0,40 -172.9,173,-34.1,-34,0,40 -172.9,173,-34,-33.9,0,40 -173,173.1,-44.4,-44.3,0,40 -173,173.1,-44.3,-44.2,0,40 -173,173.1,-44.2,-44.1,0,40 -173,173.1,-44.1,-44,0,40 -173,173.1,-44,-43.9,0,40 -173,173.1,-43.9,-43.8,0,40 -173,173.1,-43.8,-43.7,0,40 -173,173.1,-43.7,-43.6,0,40 -173,173.1,-43.6,-43.5,0,40 -173,173.1,-43.5,-43.4,0,40 -173,173.1,-43.4,-43.3,0,40 -173,173.1,-43.3,-43.2,0,40 -173,173.1,-43.2,-43.1,0,40 -173,173.1,-43.1,-43,0,40 -173,173.1,-43,-42.9,0,40 -173,173.1,-42.9,-42.8,0,40 -173,173.1,-42.8,-42.7,0,40 -173,173.1,-42.7,-42.6,0,40 -173,173.1,-42.6,-42.5,0,40 -173,173.1,-42.5,-42.4,0,40 -173,173.1,-42.4,-42.3,0,40 -173,173.1,-42.3,-42.2,0,40 -173,173.1,-42.2,-42.1,0,40 -173,173.1,-42.1,-42,0,40 -173,173.1,-42,-41.9,0,40 -173,173.1,-41.9,-41.8,0,40 -173,173.1,-41.8,-41.7,0,40 -173,173.1,-41.7,-41.6,0,40 -173,173.1,-41.6,-41.5,0,40 -173,173.1,-41.5,-41.4,0,40 -173,173.1,-41.4,-41.3,0,40 -173,173.1,-41.3,-41.2,0,40 -173,173.1,-41.2,-41.1,0,40 -173,173.1,-41.1,-41,0,40 -173,173.1,-41,-40.9,0,40 -173,173.1,-40.9,-40.8,0,40 -173,173.1,-40.8,-40.7,0,40 -173,173.1,-40.7,-40.6,0,40 -173,173.1,-40.6,-40.5,0,40 -173,173.1,-40.5,-40.4,0,40 -173,173.1,-40.4,-40.3,0,40 -173,173.1,-40.3,-40.2,0,40 -173,173.1,-40.2,-40.1,0,40 -173,173.1,-40.1,-40,0,40 -173,173.1,-40,-39.9,0,40 -173,173.1,-39.9,-39.8,0,40 -173,173.1,-39.8,-39.7,0,40 -173,173.1,-39.7,-39.6,0,40 -173,173.1,-39.6,-39.5,0,40 -173,173.1,-39.5,-39.4,0,40 -173,173.1,-39.4,-39.3,0,40 -173,173.1,-39.3,-39.2,0,40 -173,173.1,-36,-35.9,0,40 -173,173.1,-35.9,-35.8,0,40 -173,173.1,-35.8,-35.7,0,40 -173,173.1,-35.7,-35.6,0,40 -173,173.1,-35.6,-35.5,0,40 -173,173.1,-35.5,-35.4,0,40 -173,173.1,-35.4,-35.3,0,40 -173,173.1,-35.3,-35.2,0,40 -173,173.1,-35.2,-35.1,0,40 -173,173.1,-35.1,-35,0,40 -173,173.1,-35,-34.9,0,40 -173,173.1,-34.9,-34.8,0,40 -173,173.1,-34.8,-34.7,0,40 -173,173.1,-34.7,-34.6,0,40 -173,173.1,-34.6,-34.5,0,40 -173,173.1,-34.5,-34.4,0,40 -173,173.1,-34.4,-34.3,0,40 -173,173.1,-34.3,-34.2,0,40 -173,173.1,-34.2,-34.1,0,40 -173,173.1,-34.1,-34,0,40 -173,173.1,-34,-33.9,0,40 -173.1,173.2,-44.4,-44.3,0,40 -173.1,173.2,-44.3,-44.2,0,40 -173.1,173.2,-44.2,-44.1,0,40 -173.1,173.2,-44.1,-44,0,40 -173.1,173.2,-44,-43.9,0,40 -173.1,173.2,-43.9,-43.8,0,40 -173.1,173.2,-43.8,-43.7,0,40 -173.1,173.2,-43.7,-43.6,0,40 -173.1,173.2,-43.6,-43.5,0,40 -173.1,173.2,-43.5,-43.4,0,40 -173.1,173.2,-43.4,-43.3,0,40 -173.1,173.2,-43.3,-43.2,0,40 -173.1,173.2,-43.2,-43.1,0,40 -173.1,173.2,-43.1,-43,0,40 -173.1,173.2,-43,-42.9,0,40 -173.1,173.2,-42.9,-42.8,0,40 -173.1,173.2,-42.8,-42.7,0,40 -173.1,173.2,-42.7,-42.6,0,40 -173.1,173.2,-42.6,-42.5,0,40 -173.1,173.2,-42.5,-42.4,0,40 -173.1,173.2,-42.4,-42.3,0,40 -173.1,173.2,-42.3,-42.2,0,40 -173.1,173.2,-42.2,-42.1,0,40 -173.1,173.2,-42.1,-42,0,40 -173.1,173.2,-42,-41.9,0,40 -173.1,173.2,-41.9,-41.8,0,40 -173.1,173.2,-41.8,-41.7,0,40 -173.1,173.2,-41.7,-41.6,0,40 -173.1,173.2,-41.6,-41.5,0,40 -173.1,173.2,-41.5,-41.4,0,40 -173.1,173.2,-41.4,-41.3,0,40 -173.1,173.2,-41.3,-41.2,0,40 -173.1,173.2,-41.2,-41.1,0,40 -173.1,173.2,-41.1,-41,0,40 -173.1,173.2,-41,-40.9,0,40 -173.1,173.2,-40.9,-40.8,0,40 -173.1,173.2,-40.8,-40.7,0,40 -173.1,173.2,-40.7,-40.6,0,40 -173.1,173.2,-40.6,-40.5,0,40 -173.1,173.2,-40.5,-40.4,0,40 -173.1,173.2,-40.4,-40.3,0,40 -173.1,173.2,-40.3,-40.2,0,40 -173.1,173.2,-40.2,-40.1,0,40 -173.1,173.2,-40.1,-40,0,40 -173.1,173.2,-40,-39.9,0,40 -173.1,173.2,-39.9,-39.8,0,40 -173.1,173.2,-39.8,-39.7,0,40 -173.1,173.2,-39.7,-39.6,0,40 -173.1,173.2,-39.6,-39.5,0,40 -173.1,173.2,-39.5,-39.4,0,40 -173.1,173.2,-39.4,-39.3,0,40 -173.1,173.2,-39.3,-39.2,0,40 -173.1,173.2,-39.2,-39.1,0,40 -173.1,173.2,-36.2,-36.1,0,40 -173.1,173.2,-36.1,-36,0,40 -173.1,173.2,-36,-35.9,0,40 -173.1,173.2,-35.9,-35.8,0,40 -173.1,173.2,-35.8,-35.7,0,40 -173.1,173.2,-35.7,-35.6,0,40 -173.1,173.2,-35.6,-35.5,0,40 -173.1,173.2,-35.5,-35.4,0,40 -173.1,173.2,-35.4,-35.3,0,40 -173.1,173.2,-35.3,-35.2,0,40 -173.1,173.2,-35.2,-35.1,0,40 -173.1,173.2,-35.1,-35,0,40 -173.1,173.2,-35,-34.9,0,40 -173.1,173.2,-34.9,-34.8,0,40 -173.1,173.2,-34.8,-34.7,0,40 -173.1,173.2,-34.7,-34.6,0,40 -173.1,173.2,-34.6,-34.5,0,40 -173.1,173.2,-34.5,-34.4,0,40 -173.1,173.2,-34.4,-34.3,0,40 -173.1,173.2,-34.3,-34.2,0,40 -173.1,173.2,-34.2,-34.1,0,40 -173.1,173.2,-34.1,-34,0,40 -173.1,173.2,-34,-33.9,0,40 -173.2,173.3,-44.3,-44.2,0,40 -173.2,173.3,-44.2,-44.1,0,40 -173.2,173.3,-44.1,-44,0,40 -173.2,173.3,-44,-43.9,0,40 -173.2,173.3,-43.9,-43.8,0,40 -173.2,173.3,-43.8,-43.7,0,40 -173.2,173.3,-43.7,-43.6,0,40 -173.2,173.3,-43.6,-43.5,0,40 -173.2,173.3,-43.5,-43.4,0,40 -173.2,173.3,-43.4,-43.3,0,40 -173.2,173.3,-43.3,-43.2,0,40 -173.2,173.3,-43.2,-43.1,0,40 -173.2,173.3,-43.1,-43,0,40 -173.2,173.3,-43,-42.9,0,40 -173.2,173.3,-42.9,-42.8,0,40 -173.2,173.3,-42.8,-42.7,0,40 -173.2,173.3,-42.7,-42.6,0,40 -173.2,173.3,-42.6,-42.5,0,40 -173.2,173.3,-42.5,-42.4,0,40 -173.2,173.3,-42.4,-42.3,0,40 -173.2,173.3,-42.3,-42.2,0,40 -173.2,173.3,-42.2,-42.1,0,40 -173.2,173.3,-42.1,-42,0,40 -173.2,173.3,-42,-41.9,0,40 -173.2,173.3,-41.9,-41.8,0,40 -173.2,173.3,-41.8,-41.7,0,40 -173.2,173.3,-41.7,-41.6,0,40 -173.2,173.3,-41.6,-41.5,0,40 -173.2,173.3,-41.5,-41.4,0,40 -173.2,173.3,-41.4,-41.3,0,40 -173.2,173.3,-41.3,-41.2,0,40 -173.2,173.3,-41.2,-41.1,0,40 -173.2,173.3,-41.1,-41,0,40 -173.2,173.3,-41,-40.9,0,40 -173.2,173.3,-40.9,-40.8,0,40 -173.2,173.3,-40.8,-40.7,0,40 -173.2,173.3,-40.7,-40.6,0,40 -173.2,173.3,-40.6,-40.5,0,40 -173.2,173.3,-40.5,-40.4,0,40 -173.2,173.3,-40.4,-40.3,0,40 -173.2,173.3,-40.3,-40.2,0,40 -173.2,173.3,-40.2,-40.1,0,40 -173.2,173.3,-40.1,-40,0,40 -173.2,173.3,-40,-39.9,0,40 -173.2,173.3,-39.9,-39.8,0,40 -173.2,173.3,-39.8,-39.7,0,40 -173.2,173.3,-39.7,-39.6,0,40 -173.2,173.3,-39.6,-39.5,0,40 -173.2,173.3,-39.5,-39.4,0,40 -173.2,173.3,-39.4,-39.3,0,40 -173.2,173.3,-39.3,-39.2,0,40 -173.2,173.3,-39.2,-39.1,0,40 -173.2,173.3,-39.1,-39,0,40 -173.2,173.3,-36.3,-36.2,0,40 -173.2,173.3,-36.2,-36.1,0,40 -173.2,173.3,-36.1,-36,0,40 -173.2,173.3,-36,-35.9,0,40 -173.2,173.3,-35.9,-35.8,0,40 -173.2,173.3,-35.8,-35.7,0,40 -173.2,173.3,-35.7,-35.6,0,40 -173.2,173.3,-35.6,-35.5,0,40 -173.2,173.3,-35.5,-35.4,0,40 -173.2,173.3,-35.4,-35.3,0,40 -173.2,173.3,-35.3,-35.2,0,40 -173.2,173.3,-35.2,-35.1,0,40 -173.2,173.3,-35.1,-35,0,40 -173.2,173.3,-35,-34.9,0,40 -173.2,173.3,-34.9,-34.8,0,40 -173.2,173.3,-34.8,-34.7,0,40 -173.2,173.3,-34.7,-34.6,0,40 -173.2,173.3,-34.6,-34.5,0,40 -173.2,173.3,-34.5,-34.4,0,40 -173.2,173.3,-34.4,-34.3,0,40 -173.2,173.3,-34.3,-34.2,0,40 -173.2,173.3,-34.2,-34.1,0,40 -173.2,173.3,-34.1,-34,0,40 -173.3,173.4,-44.3,-44.2,0,40 -173.3,173.4,-44.2,-44.1,0,40 -173.3,173.4,-44.1,-44,0,40 -173.3,173.4,-44,-43.9,0,40 -173.3,173.4,-43.9,-43.8,0,40 -173.3,173.4,-43.8,-43.7,0,40 -173.3,173.4,-43.7,-43.6,0,40 -173.3,173.4,-43.6,-43.5,0,40 -173.3,173.4,-43.5,-43.4,0,40 -173.3,173.4,-43.4,-43.3,0,40 -173.3,173.4,-43.3,-43.2,0,40 -173.3,173.4,-43.2,-43.1,0,40 -173.3,173.4,-43.1,-43,0,40 -173.3,173.4,-43,-42.9,0,40 -173.3,173.4,-42.9,-42.8,0,40 -173.3,173.4,-42.8,-42.7,0,40 -173.3,173.4,-42.7,-42.6,0,40 -173.3,173.4,-42.6,-42.5,0,40 -173.3,173.4,-42.5,-42.4,0,40 -173.3,173.4,-42.4,-42.3,0,40 -173.3,173.4,-42.3,-42.2,0,40 -173.3,173.4,-42.2,-42.1,0,40 -173.3,173.4,-42.1,-42,0,40 -173.3,173.4,-42,-41.9,0,40 -173.3,173.4,-41.9,-41.8,0,40 -173.3,173.4,-41.8,-41.7,0,40 -173.3,173.4,-41.7,-41.6,0,40 -173.3,173.4,-41.6,-41.5,0,40 -173.3,173.4,-41.5,-41.4,0,40 -173.3,173.4,-41.4,-41.3,0,40 -173.3,173.4,-41.3,-41.2,0,40 -173.3,173.4,-41.2,-41.1,0,40 -173.3,173.4,-41.1,-41,0,40 -173.3,173.4,-41,-40.9,0,40 -173.3,173.4,-40.9,-40.8,0,40 -173.3,173.4,-40.8,-40.7,0,40 -173.3,173.4,-40.7,-40.6,0,40 -173.3,173.4,-40.6,-40.5,0,40 -173.3,173.4,-40.5,-40.4,0,40 -173.3,173.4,-40.4,-40.3,0,40 -173.3,173.4,-40.3,-40.2,0,40 -173.3,173.4,-40.2,-40.1,0,40 -173.3,173.4,-40.1,-40,0,40 -173.3,173.4,-40,-39.9,0,40 -173.3,173.4,-39.9,-39.8,0,40 -173.3,173.4,-39.8,-39.7,0,40 -173.3,173.4,-39.7,-39.6,0,40 -173.3,173.4,-39.6,-39.5,0,40 -173.3,173.4,-39.5,-39.4,0,40 -173.3,173.4,-39.4,-39.3,0,40 -173.3,173.4,-39.3,-39.2,0,40 -173.3,173.4,-39.2,-39.1,0,40 -173.3,173.4,-39.1,-39,0,40 -173.3,173.4,-39,-38.9,0,40 -173.3,173.4,-36.4,-36.3,0,40 -173.3,173.4,-36.3,-36.2,0,40 -173.3,173.4,-36.2,-36.1,0,40 -173.3,173.4,-36.1,-36,0,40 -173.3,173.4,-36,-35.9,0,40 -173.3,173.4,-35.9,-35.8,0,40 -173.3,173.4,-35.8,-35.7,0,40 -173.3,173.4,-35.7,-35.6,0,40 -173.3,173.4,-35.6,-35.5,0,40 -173.3,173.4,-35.5,-35.4,0,40 -173.3,173.4,-35.4,-35.3,0,40 -173.3,173.4,-35.3,-35.2,0,40 -173.3,173.4,-35.2,-35.1,0,40 -173.3,173.4,-35.1,-35,0,40 -173.3,173.4,-35,-34.9,0,40 -173.3,173.4,-34.9,-34.8,0,40 -173.3,173.4,-34.8,-34.7,0,40 -173.3,173.4,-34.7,-34.6,0,40 -173.3,173.4,-34.6,-34.5,0,40 -173.3,173.4,-34.5,-34.4,0,40 -173.3,173.4,-34.4,-34.3,0,40 -173.3,173.4,-34.3,-34.2,0,40 -173.3,173.4,-34.2,-34.1,0,40 -173.4,173.5,-44.2,-44.1,0,40 -173.4,173.5,-44.1,-44,0,40 -173.4,173.5,-44,-43.9,0,40 -173.4,173.5,-43.9,-43.8,0,40 -173.4,173.5,-43.8,-43.7,0,40 -173.4,173.5,-43.7,-43.6,0,40 -173.4,173.5,-43.6,-43.5,0,40 -173.4,173.5,-43.5,-43.4,0,40 -173.4,173.5,-43.4,-43.3,0,40 -173.4,173.5,-43.3,-43.2,0,40 -173.4,173.5,-43.2,-43.1,0,40 -173.4,173.5,-43.1,-43,0,40 -173.4,173.5,-43,-42.9,0,40 -173.4,173.5,-42.9,-42.8,0,40 -173.4,173.5,-42.8,-42.7,0,40 -173.4,173.5,-42.7,-42.6,0,40 -173.4,173.5,-42.6,-42.5,0,40 -173.4,173.5,-42.5,-42.4,0,40 -173.4,173.5,-42.4,-42.3,0,40 -173.4,173.5,-42.3,-42.2,0,40 -173.4,173.5,-42.2,-42.1,0,40 -173.4,173.5,-42.1,-42,0,40 -173.4,173.5,-42,-41.9,0,40 -173.4,173.5,-41.9,-41.8,0,40 -173.4,173.5,-41.8,-41.7,0,40 -173.4,173.5,-41.7,-41.6,0,40 -173.4,173.5,-41.6,-41.5,0,40 -173.4,173.5,-41.5,-41.4,0,40 -173.4,173.5,-41.4,-41.3,0,40 -173.4,173.5,-41.3,-41.2,0,40 -173.4,173.5,-41.2,-41.1,0,40 -173.4,173.5,-41.1,-41,0,40 -173.4,173.5,-41,-40.9,0,40 -173.4,173.5,-40.9,-40.8,0,40 -173.4,173.5,-40.8,-40.7,0,40 -173.4,173.5,-40.7,-40.6,0,40 -173.4,173.5,-40.6,-40.5,0,40 -173.4,173.5,-40.5,-40.4,0,40 -173.4,173.5,-40.4,-40.3,0,40 -173.4,173.5,-40.3,-40.2,0,40 -173.4,173.5,-40.2,-40.1,0,40 -173.4,173.5,-40.1,-40,0,40 -173.4,173.5,-40,-39.9,0,40 -173.4,173.5,-39.9,-39.8,0,40 -173.4,173.5,-39.8,-39.7,0,40 -173.4,173.5,-39.7,-39.6,0,40 -173.4,173.5,-39.6,-39.5,0,40 -173.4,173.5,-39.5,-39.4,0,40 -173.4,173.5,-39.4,-39.3,0,40 -173.4,173.5,-39.3,-39.2,0,40 -173.4,173.5,-39.2,-39.1,0,40 -173.4,173.5,-39.1,-39,0,40 -173.4,173.5,-39,-38.9,0,40 -173.4,173.5,-38.9,-38.8,0,40 -173.4,173.5,-36.5,-36.4,0,40 -173.4,173.5,-36.4,-36.3,0,40 -173.4,173.5,-36.3,-36.2,0,40 -173.4,173.5,-36.2,-36.1,0,40 -173.4,173.5,-36.1,-36,0,40 -173.4,173.5,-36,-35.9,0,40 -173.4,173.5,-35.9,-35.8,0,40 -173.4,173.5,-35.8,-35.7,0,40 -173.4,173.5,-35.7,-35.6,0,40 -173.4,173.5,-35.6,-35.5,0,40 -173.4,173.5,-35.5,-35.4,0,40 -173.4,173.5,-35.4,-35.3,0,40 -173.4,173.5,-35.3,-35.2,0,40 -173.4,173.5,-35.2,-35.1,0,40 -173.4,173.5,-35.1,-35,0,40 -173.4,173.5,-35,-34.9,0,40 -173.4,173.5,-34.9,-34.8,0,40 -173.4,173.5,-34.8,-34.7,0,40 -173.4,173.5,-34.7,-34.6,0,40 -173.4,173.5,-34.6,-34.5,0,40 -173.4,173.5,-34.5,-34.4,0,40 -173.4,173.5,-34.4,-34.3,0,40 -173.4,173.5,-34.3,-34.2,0,40 -173.4,173.5,-34.2,-34.1,0,40 -173.5,173.6,-44.1,-44,0,40 -173.5,173.6,-44,-43.9,0,40 -173.5,173.6,-43.9,-43.8,0,40 -173.5,173.6,-43.8,-43.7,0,40 -173.5,173.6,-43.7,-43.6,0,40 -173.5,173.6,-43.6,-43.5,0,40 -173.5,173.6,-43.5,-43.4,0,40 -173.5,173.6,-43.4,-43.3,0,40 -173.5,173.6,-43.3,-43.2,0,40 -173.5,173.6,-43.2,-43.1,0,40 -173.5,173.6,-43.1,-43,0,40 -173.5,173.6,-43,-42.9,0,40 -173.5,173.6,-42.9,-42.8,0,40 -173.5,173.6,-42.8,-42.7,0,40 -173.5,173.6,-42.7,-42.6,0,40 -173.5,173.6,-42.6,-42.5,0,40 -173.5,173.6,-42.5,-42.4,0,40 -173.5,173.6,-42.4,-42.3,0,40 -173.5,173.6,-42.3,-42.2,0,40 -173.5,173.6,-42.2,-42.1,0,40 -173.5,173.6,-42.1,-42,0,40 -173.5,173.6,-42,-41.9,0,40 -173.5,173.6,-41.9,-41.8,0,40 -173.5,173.6,-41.8,-41.7,0,40 -173.5,173.6,-41.7,-41.6,0,40 -173.5,173.6,-41.6,-41.5,0,40 -173.5,173.6,-41.5,-41.4,0,40 -173.5,173.6,-41.4,-41.3,0,40 -173.5,173.6,-41.3,-41.2,0,40 -173.5,173.6,-41.2,-41.1,0,40 -173.5,173.6,-41.1,-41,0,40 -173.5,173.6,-41,-40.9,0,40 -173.5,173.6,-40.9,-40.8,0,40 -173.5,173.6,-40.8,-40.7,0,40 -173.5,173.6,-40.7,-40.6,0,40 -173.5,173.6,-40.6,-40.5,0,40 -173.5,173.6,-40.5,-40.4,0,40 -173.5,173.6,-40.4,-40.3,0,40 -173.5,173.6,-40.3,-40.2,0,40 -173.5,173.6,-40.2,-40.1,0,40 -173.5,173.6,-40.1,-40,0,40 -173.5,173.6,-40,-39.9,0,40 -173.5,173.6,-39.9,-39.8,0,40 -173.5,173.6,-39.8,-39.7,0,40 -173.5,173.6,-39.7,-39.6,0,40 -173.5,173.6,-39.6,-39.5,0,40 -173.5,173.6,-39.5,-39.4,0,40 -173.5,173.6,-39.4,-39.3,0,40 -173.5,173.6,-39.3,-39.2,0,40 -173.5,173.6,-39.2,-39.1,0,40 -173.5,173.6,-39.1,-39,0,40 -173.5,173.6,-39,-38.9,0,40 -173.5,173.6,-38.9,-38.8,0,40 -173.5,173.6,-38.8,-38.7,0,40 -173.5,173.6,-38.7,-38.6,0,40 -173.5,173.6,-36.6,-36.5,0,40 -173.5,173.6,-36.5,-36.4,0,40 -173.5,173.6,-36.4,-36.3,0,40 -173.5,173.6,-36.3,-36.2,0,40 -173.5,173.6,-36.2,-36.1,0,40 -173.5,173.6,-36.1,-36,0,40 -173.5,173.6,-36,-35.9,0,40 -173.5,173.6,-35.9,-35.8,0,40 -173.5,173.6,-35.8,-35.7,0,40 -173.5,173.6,-35.7,-35.6,0,40 -173.5,173.6,-35.6,-35.5,0,40 -173.5,173.6,-35.5,-35.4,0,40 -173.5,173.6,-35.4,-35.3,0,40 -173.5,173.6,-35.3,-35.2,0,40 -173.5,173.6,-35.2,-35.1,0,40 -173.5,173.6,-35.1,-35,0,40 -173.5,173.6,-35,-34.9,0,40 -173.5,173.6,-34.9,-34.8,0,40 -173.5,173.6,-34.8,-34.7,0,40 -173.5,173.6,-34.7,-34.6,0,40 -173.5,173.6,-34.6,-34.5,0,40 -173.5,173.6,-34.5,-34.4,0,40 -173.5,173.6,-34.4,-34.3,0,40 -173.5,173.6,-34.3,-34.2,0,40 -173.6,173.7,-43.9,-43.8,0,40 -173.6,173.7,-43.8,-43.7,0,40 -173.6,173.7,-43.7,-43.6,0,40 -173.6,173.7,-43.6,-43.5,0,40 -173.6,173.7,-43.5,-43.4,0,40 -173.6,173.7,-43.4,-43.3,0,40 -173.6,173.7,-43.3,-43.2,0,40 -173.6,173.7,-43.2,-43.1,0,40 -173.6,173.7,-43.1,-43,0,40 -173.6,173.7,-43,-42.9,0,40 -173.6,173.7,-42.9,-42.8,0,40 -173.6,173.7,-42.8,-42.7,0,40 -173.6,173.7,-42.7,-42.6,0,40 -173.6,173.7,-42.6,-42.5,0,40 -173.6,173.7,-42.5,-42.4,0,40 -173.6,173.7,-42.4,-42.3,0,40 -173.6,173.7,-42.3,-42.2,0,40 -173.6,173.7,-42.2,-42.1,0,40 -173.6,173.7,-42.1,-42,0,40 -173.6,173.7,-42,-41.9,0,40 -173.6,173.7,-41.9,-41.8,0,40 -173.6,173.7,-41.8,-41.7,0,40 -173.6,173.7,-41.7,-41.6,0,40 -173.6,173.7,-41.6,-41.5,0,40 -173.6,173.7,-41.5,-41.4,0,40 -173.6,173.7,-41.4,-41.3,0,40 -173.6,173.7,-41.3,-41.2,0,40 -173.6,173.7,-41.2,-41.1,0,40 -173.6,173.7,-41.1,-41,0,40 -173.6,173.7,-41,-40.9,0,40 -173.6,173.7,-40.9,-40.8,0,40 -173.6,173.7,-40.8,-40.7,0,40 -173.6,173.7,-40.7,-40.6,0,40 -173.6,173.7,-40.6,-40.5,0,40 -173.6,173.7,-40.5,-40.4,0,40 -173.6,173.7,-40.4,-40.3,0,40 -173.6,173.7,-40.3,-40.2,0,40 -173.6,173.7,-40.2,-40.1,0,40 -173.6,173.7,-40.1,-40,0,40 -173.6,173.7,-40,-39.9,0,40 -173.6,173.7,-39.9,-39.8,0,40 -173.6,173.7,-39.8,-39.7,0,40 -173.6,173.7,-39.7,-39.6,0,40 -173.6,173.7,-39.6,-39.5,0,40 -173.6,173.7,-39.5,-39.4,0,40 -173.6,173.7,-39.4,-39.3,0,40 -173.6,173.7,-39.3,-39.2,0,40 -173.6,173.7,-39.2,-39.1,0,40 -173.6,173.7,-39.1,-39,0,40 -173.6,173.7,-39,-38.9,0,40 -173.6,173.7,-38.9,-38.8,0,40 -173.6,173.7,-38.8,-38.7,0,40 -173.6,173.7,-38.7,-38.6,0,40 -173.6,173.7,-38.6,-38.5,0,40 -173.6,173.7,-36.7,-36.6,0,40 -173.6,173.7,-36.6,-36.5,0,40 -173.6,173.7,-36.5,-36.4,0,40 -173.6,173.7,-36.4,-36.3,0,40 -173.6,173.7,-36.3,-36.2,0,40 -173.6,173.7,-36.2,-36.1,0,40 -173.6,173.7,-36.1,-36,0,40 -173.6,173.7,-36,-35.9,0,40 -173.6,173.7,-35.9,-35.8,0,40 -173.6,173.7,-35.8,-35.7,0,40 -173.6,173.7,-35.7,-35.6,0,40 -173.6,173.7,-35.6,-35.5,0,40 -173.6,173.7,-35.5,-35.4,0,40 -173.6,173.7,-35.4,-35.3,0,40 -173.6,173.7,-35.3,-35.2,0,40 -173.6,173.7,-35.2,-35.1,0,40 -173.6,173.7,-35.1,-35,0,40 -173.6,173.7,-35,-34.9,0,40 -173.6,173.7,-34.9,-34.8,0,40 -173.6,173.7,-34.8,-34.7,0,40 -173.6,173.7,-34.7,-34.6,0,40 -173.6,173.7,-34.6,-34.5,0,40 -173.6,173.7,-34.5,-34.4,0,40 -173.6,173.7,-34.4,-34.3,0,40 -173.7,173.8,-43.8,-43.7,0,40 -173.7,173.8,-43.7,-43.6,0,40 -173.7,173.8,-43.4,-43.3,0,40 -173.7,173.8,-43.3,-43.2,0,40 -173.7,173.8,-43.2,-43.1,0,40 -173.7,173.8,-43.1,-43,0,40 -173.7,173.8,-43,-42.9,0,40 -173.7,173.8,-42.9,-42.8,0,40 -173.7,173.8,-42.8,-42.7,0,40 -173.7,173.8,-42.7,-42.6,0,40 -173.7,173.8,-42.6,-42.5,0,40 -173.7,173.8,-42.5,-42.4,0,40 -173.7,173.8,-42.4,-42.3,0,40 -173.7,173.8,-42.3,-42.2,0,40 -173.7,173.8,-42.2,-42.1,0,40 -173.7,173.8,-42.1,-42,0,40 -173.7,173.8,-42,-41.9,0,40 -173.7,173.8,-41.9,-41.8,0,40 -173.7,173.8,-41.8,-41.7,0,40 -173.7,173.8,-41.7,-41.6,0,40 -173.7,173.8,-41.6,-41.5,0,40 -173.7,173.8,-41.5,-41.4,0,40 -173.7,173.8,-41.4,-41.3,0,40 -173.7,173.8,-41.3,-41.2,0,40 -173.7,173.8,-41.2,-41.1,0,40 -173.7,173.8,-41.1,-41,0,40 -173.7,173.8,-41,-40.9,0,40 -173.7,173.8,-40.9,-40.8,0,40 -173.7,173.8,-40.8,-40.7,0,40 -173.7,173.8,-40.7,-40.6,0,40 -173.7,173.8,-40.6,-40.5,0,40 -173.7,173.8,-40.5,-40.4,0,40 -173.7,173.8,-40.4,-40.3,0,40 -173.7,173.8,-40.3,-40.2,0,40 -173.7,173.8,-40.2,-40.1,0,40 -173.7,173.8,-40.1,-40,0,40 -173.7,173.8,-40,-39.9,0,40 -173.7,173.8,-39.9,-39.8,0,40 -173.7,173.8,-39.8,-39.7,0,40 -173.7,173.8,-39.7,-39.6,0,40 -173.7,173.8,-39.6,-39.5,0,40 -173.7,173.8,-39.5,-39.4,0,40 -173.7,173.8,-39.4,-39.3,0,40 -173.7,173.8,-39.3,-39.2,0,40 -173.7,173.8,-39.2,-39.1,0,40 -173.7,173.8,-39.1,-39,0,40 -173.7,173.8,-39,-38.9,0,40 -173.7,173.8,-38.9,-38.8,0,40 -173.7,173.8,-38.8,-38.7,0,40 -173.7,173.8,-38.7,-38.6,0,40 -173.7,173.8,-38.6,-38.5,0,40 -173.7,173.8,-38.5,-38.4,0,40 -173.7,173.8,-38.4,-38.3,0,40 -173.7,173.8,-36.9,-36.8,0,40 -173.7,173.8,-36.8,-36.7,0,40 -173.7,173.8,-36.7,-36.6,0,40 -173.7,173.8,-36.6,-36.5,0,40 -173.7,173.8,-36.5,-36.4,0,40 -173.7,173.8,-36.4,-36.3,0,40 -173.7,173.8,-36.3,-36.2,0,40 -173.7,173.8,-36.2,-36.1,0,40 -173.7,173.8,-36.1,-36,0,40 -173.7,173.8,-36,-35.9,0,40 -173.7,173.8,-35.9,-35.8,0,40 -173.7,173.8,-35.8,-35.7,0,40 -173.7,173.8,-35.7,-35.6,0,40 -173.7,173.8,-35.6,-35.5,0,40 -173.7,173.8,-35.5,-35.4,0,40 -173.7,173.8,-35.4,-35.3,0,40 -173.7,173.8,-35.3,-35.2,0,40 -173.7,173.8,-35.2,-35.1,0,40 -173.7,173.8,-35.1,-35,0,40 -173.7,173.8,-35,-34.9,0,40 -173.7,173.8,-34.9,-34.8,0,40 -173.7,173.8,-34.8,-34.7,0,40 -173.7,173.8,-34.7,-34.6,0,40 -173.7,173.8,-34.6,-34.5,0,40 -173.7,173.8,-34.5,-34.4,0,40 -173.7,173.8,-34.4,-34.3,0,40 -173.8,173.9,-43.2,-43.1,0,40 -173.8,173.9,-43.1,-43,0,40 -173.8,173.9,-43,-42.9,0,40 -173.8,173.9,-42.9,-42.8,0,40 -173.8,173.9,-42.8,-42.7,0,40 -173.8,173.9,-42.7,-42.6,0,40 -173.8,173.9,-42.6,-42.5,0,40 -173.8,173.9,-42.5,-42.4,0,40 -173.8,173.9,-42.4,-42.3,0,40 -173.8,173.9,-42.3,-42.2,0,40 -173.8,173.9,-42.2,-42.1,0,40 -173.8,173.9,-42.1,-42,0,40 -173.8,173.9,-42,-41.9,0,40 -173.8,173.9,-41.9,-41.8,0,40 -173.8,173.9,-41.8,-41.7,0,40 -173.8,173.9,-41.7,-41.6,0,40 -173.8,173.9,-41.6,-41.5,0,40 -173.8,173.9,-41.5,-41.4,0,40 -173.8,173.9,-41.4,-41.3,0,40 -173.8,173.9,-41.3,-41.2,0,40 -173.8,173.9,-41.2,-41.1,0,40 -173.8,173.9,-41.1,-41,0,40 -173.8,173.9,-41,-40.9,0,40 -173.8,173.9,-40.9,-40.8,0,40 -173.8,173.9,-40.8,-40.7,0,40 -173.8,173.9,-40.7,-40.6,0,40 -173.8,173.9,-40.6,-40.5,0,40 -173.8,173.9,-40.5,-40.4,0,40 -173.8,173.9,-40.4,-40.3,0,40 -173.8,173.9,-40.3,-40.2,0,40 -173.8,173.9,-40.2,-40.1,0,40 -173.8,173.9,-40.1,-40,0,40 -173.8,173.9,-40,-39.9,0,40 -173.8,173.9,-39.9,-39.8,0,40 -173.8,173.9,-39.8,-39.7,0,40 -173.8,173.9,-39.7,-39.6,0,40 -173.8,173.9,-39.6,-39.5,0,40 -173.8,173.9,-39.5,-39.4,0,40 -173.8,173.9,-39.4,-39.3,0,40 -173.8,173.9,-39.3,-39.2,0,40 -173.8,173.9,-39.2,-39.1,0,40 -173.8,173.9,-39.1,-39,0,40 -173.8,173.9,-39,-38.9,0,40 -173.8,173.9,-38.9,-38.8,0,40 -173.8,173.9,-38.8,-38.7,0,40 -173.8,173.9,-38.7,-38.6,0,40 -173.8,173.9,-38.6,-38.5,0,40 -173.8,173.9,-38.5,-38.4,0,40 -173.8,173.9,-38.4,-38.3,0,40 -173.8,173.9,-38.3,-38.2,0,40 -173.8,173.9,-38.2,-38.1,0,40 -173.8,173.9,-37,-36.9,0,40 -173.8,173.9,-36.9,-36.8,0,40 -173.8,173.9,-36.8,-36.7,0,40 -173.8,173.9,-36.7,-36.6,0,40 -173.8,173.9,-36.6,-36.5,0,40 -173.8,173.9,-36.5,-36.4,0,40 -173.8,173.9,-36.4,-36.3,0,40 -173.8,173.9,-36.3,-36.2,0,40 -173.8,173.9,-36.2,-36.1,0,40 -173.8,173.9,-36.1,-36,0,40 -173.8,173.9,-36,-35.9,0,40 -173.8,173.9,-35.9,-35.8,0,40 -173.8,173.9,-35.8,-35.7,0,40 -173.8,173.9,-35.7,-35.6,0,40 -173.8,173.9,-35.6,-35.5,0,40 -173.8,173.9,-35.5,-35.4,0,40 -173.8,173.9,-35.4,-35.3,0,40 -173.8,173.9,-35.3,-35.2,0,40 -173.8,173.9,-35.2,-35.1,0,40 -173.8,173.9,-35.1,-35,0,40 -173.8,173.9,-35,-34.9,0,40 -173.8,173.9,-34.9,-34.8,0,40 -173.8,173.9,-34.8,-34.7,0,40 -173.8,173.9,-34.7,-34.6,0,40 -173.8,173.9,-34.6,-34.5,0,40 -173.8,173.9,-34.5,-34.4,0,40 -173.9,174,-43.1,-43,0,40 -173.9,174,-43,-42.9,0,40 -173.9,174,-42.9,-42.8,0,40 -173.9,174,-42.8,-42.7,0,40 -173.9,174,-42.7,-42.6,0,40 -173.9,174,-42.6,-42.5,0,40 -173.9,174,-42.5,-42.4,0,40 -173.9,174,-42.4,-42.3,0,40 -173.9,174,-42.3,-42.2,0,40 -173.9,174,-42.2,-42.1,0,40 -173.9,174,-42.1,-42,0,40 -173.9,174,-42,-41.9,0,40 -173.9,174,-41.9,-41.8,0,40 -173.9,174,-41.8,-41.7,0,40 -173.9,174,-41.7,-41.6,0,40 -173.9,174,-41.6,-41.5,0,40 -173.9,174,-41.5,-41.4,0,40 -173.9,174,-41.4,-41.3,0,40 -173.9,174,-41.3,-41.2,0,40 -173.9,174,-41.2,-41.1,0,40 -173.9,174,-41.1,-41,0,40 -173.9,174,-41,-40.9,0,40 -173.9,174,-40.9,-40.8,0,40 -173.9,174,-40.8,-40.7,0,40 -173.9,174,-40.7,-40.6,0,40 -173.9,174,-40.6,-40.5,0,40 -173.9,174,-40.5,-40.4,0,40 -173.9,174,-40.4,-40.3,0,40 -173.9,174,-40.3,-40.2,0,40 -173.9,174,-40.2,-40.1,0,40 -173.9,174,-40.1,-40,0,40 -173.9,174,-40,-39.9,0,40 -173.9,174,-39.9,-39.8,0,40 -173.9,174,-39.8,-39.7,0,40 -173.9,174,-39.7,-39.6,0,40 -173.9,174,-39.6,-39.5,0,40 -173.9,174,-39.5,-39.4,0,40 -173.9,174,-39.4,-39.3,0,40 -173.9,174,-39.3,-39.2,0,40 -173.9,174,-39.2,-39.1,0,40 -173.9,174,-39.1,-39,0,40 -173.9,174,-39,-38.9,0,40 -173.9,174,-38.9,-38.8,0,40 -173.9,174,-38.8,-38.7,0,40 -173.9,174,-38.7,-38.6,0,40 -173.9,174,-38.6,-38.5,0,40 -173.9,174,-38.5,-38.4,0,40 -173.9,174,-38.4,-38.3,0,40 -173.9,174,-38.3,-38.2,0,40 -173.9,174,-38.2,-38.1,0,40 -173.9,174,-38.1,-38,0,40 -173.9,174,-38,-37.9,0,40 -173.9,174,-37.2,-37.1,0,40 -173.9,174,-37.1,-37,0,40 -173.9,174,-37,-36.9,0,40 -173.9,174,-36.9,-36.8,0,40 -173.9,174,-36.8,-36.7,0,40 -173.9,174,-36.7,-36.6,0,40 -173.9,174,-36.6,-36.5,0,40 -173.9,174,-36.5,-36.4,0,40 -173.9,174,-36.4,-36.3,0,40 -173.9,174,-36.3,-36.2,0,40 -173.9,174,-36.2,-36.1,0,40 -173.9,174,-36.1,-36,0,40 -173.9,174,-36,-35.9,0,40 -173.9,174,-35.9,-35.8,0,40 -173.9,174,-35.8,-35.7,0,40 -173.9,174,-35.7,-35.6,0,40 -173.9,174,-35.6,-35.5,0,40 -173.9,174,-35.5,-35.4,0,40 -173.9,174,-35.4,-35.3,0,40 -173.9,174,-35.3,-35.2,0,40 -173.9,174,-35.2,-35.1,0,40 -173.9,174,-35.1,-35,0,40 -173.9,174,-35,-34.9,0,40 -173.9,174,-34.9,-34.8,0,40 -173.9,174,-34.8,-34.7,0,40 -173.9,174,-34.7,-34.6,0,40 -173.9,174,-34.6,-34.5,0,40 -173.9,174,-34.5,-34.4,0,40 -174,174.1,-43,-42.9,0,40 -174,174.1,-42.9,-42.8,0,40 -174,174.1,-42.8,-42.7,0,40 -174,174.1,-42.7,-42.6,0,40 -174,174.1,-42.6,-42.5,0,40 -174,174.1,-42.5,-42.4,0,40 -174,174.1,-42.4,-42.3,0,40 -174,174.1,-42.3,-42.2,0,40 -174,174.1,-42.2,-42.1,0,40 -174,174.1,-42.1,-42,0,40 -174,174.1,-42,-41.9,0,40 -174,174.1,-41.9,-41.8,0,40 -174,174.1,-41.8,-41.7,0,40 -174,174.1,-41.7,-41.6,0,40 -174,174.1,-41.6,-41.5,0,40 -174,174.1,-41.5,-41.4,0,40 -174,174.1,-41.4,-41.3,0,40 -174,174.1,-41.3,-41.2,0,40 -174,174.1,-41.2,-41.1,0,40 -174,174.1,-41.1,-41,0,40 -174,174.1,-41,-40.9,0,40 -174,174.1,-40.9,-40.8,0,40 -174,174.1,-40.8,-40.7,0,40 -174,174.1,-40.7,-40.6,0,40 -174,174.1,-40.6,-40.5,0,40 -174,174.1,-40.5,-40.4,0,40 -174,174.1,-40.4,-40.3,0,40 -174,174.1,-40.3,-40.2,0,40 -174,174.1,-40.2,-40.1,0,40 -174,174.1,-40.1,-40,0,40 -174,174.1,-40,-39.9,0,40 -174,174.1,-39.9,-39.8,0,40 -174,174.1,-39.8,-39.7,0,40 -174,174.1,-39.7,-39.6,0,40 -174,174.1,-39.6,-39.5,0,40 -174,174.1,-39.5,-39.4,0,40 -174,174.1,-39.4,-39.3,0,40 -174,174.1,-39.3,-39.2,0,40 -174,174.1,-39.2,-39.1,0,40 -174,174.1,-39.1,-39,0,40 -174,174.1,-39,-38.9,0,40 -174,174.1,-38.9,-38.8,0,40 -174,174.1,-38.8,-38.7,0,40 -174,174.1,-38.7,-38.6,0,40 -174,174.1,-38.6,-38.5,0,40 -174,174.1,-38.5,-38.4,0,40 -174,174.1,-38.4,-38.3,0,40 -174,174.1,-38.3,-38.2,0,40 -174,174.1,-38.2,-38.1,0,40 -174,174.1,-38.1,-38,0,40 -174,174.1,-38,-37.9,0,40 -174,174.1,-37.9,-37.8,0,40 -174,174.1,-37.8,-37.7,0,40 -174,174.1,-37.5,-37.4,0,40 -174,174.1,-37.4,-37.3,0,40 -174,174.1,-37.3,-37.2,0,40 -174,174.1,-37.2,-37.1,0,40 -174,174.1,-37.1,-37,0,40 -174,174.1,-37,-36.9,0,40 -174,174.1,-36.9,-36.8,0,40 -174,174.1,-36.8,-36.7,0,40 -174,174.1,-36.7,-36.6,0,40 -174,174.1,-36.6,-36.5,0,40 -174,174.1,-36.5,-36.4,0,40 -174,174.1,-36.4,-36.3,0,40 -174,174.1,-36.3,-36.2,0,40 -174,174.1,-36.2,-36.1,0,40 -174,174.1,-36.1,-36,0,40 -174,174.1,-36,-35.9,0,40 -174,174.1,-35.9,-35.8,0,40 -174,174.1,-35.8,-35.7,0,40 -174,174.1,-35.7,-35.6,0,40 -174,174.1,-35.6,-35.5,0,40 -174,174.1,-35.5,-35.4,0,40 -174,174.1,-35.4,-35.3,0,40 -174,174.1,-35.3,-35.2,0,40 -174,174.1,-35.2,-35.1,0,40 -174,174.1,-35.1,-35,0,40 -174,174.1,-35,-34.9,0,40 -174,174.1,-34.9,-34.8,0,40 -174,174.1,-34.8,-34.7,0,40 -174,174.1,-34.7,-34.6,0,40 -174,174.1,-34.6,-34.5,0,40 -174.1,174.2,-42.9,-42.8,0,40 -174.1,174.2,-42.8,-42.7,0,40 -174.1,174.2,-42.7,-42.6,0,40 -174.1,174.2,-42.6,-42.5,0,40 -174.1,174.2,-42.5,-42.4,0,40 -174.1,174.2,-42.4,-42.3,0,40 -174.1,174.2,-42.3,-42.2,0,40 -174.1,174.2,-42.2,-42.1,0,40 -174.1,174.2,-42.1,-42,0,40 -174.1,174.2,-42,-41.9,0,40 -174.1,174.2,-41.9,-41.8,0,40 -174.1,174.2,-41.8,-41.7,0,40 -174.1,174.2,-41.7,-41.6,0,40 -174.1,174.2,-41.6,-41.5,0,40 -174.1,174.2,-41.5,-41.4,0,40 -174.1,174.2,-41.4,-41.3,0,40 -174.1,174.2,-41.3,-41.2,0,40 -174.1,174.2,-41.2,-41.1,0,40 -174.1,174.2,-41.1,-41,0,40 -174.1,174.2,-41,-40.9,0,40 -174.1,174.2,-40.9,-40.8,0,40 -174.1,174.2,-40.8,-40.7,0,40 -174.1,174.2,-40.7,-40.6,0,40 -174.1,174.2,-40.6,-40.5,0,40 -174.1,174.2,-40.5,-40.4,0,40 -174.1,174.2,-40.4,-40.3,0,40 -174.1,174.2,-40.3,-40.2,0,40 -174.1,174.2,-40.2,-40.1,0,40 -174.1,174.2,-40.1,-40,0,40 -174.1,174.2,-40,-39.9,0,40 -174.1,174.2,-39.9,-39.8,0,40 -174.1,174.2,-39.8,-39.7,0,40 -174.1,174.2,-39.7,-39.6,0,40 -174.1,174.2,-39.6,-39.5,0,40 -174.1,174.2,-39.5,-39.4,0,40 -174.1,174.2,-39.4,-39.3,0,40 -174.1,174.2,-39.3,-39.2,0,40 -174.1,174.2,-39.2,-39.1,0,40 -174.1,174.2,-39.1,-39,0,40 -174.1,174.2,-39,-38.9,0,40 -174.1,174.2,-38.9,-38.8,0,40 -174.1,174.2,-38.8,-38.7,0,40 -174.1,174.2,-38.7,-38.6,0,40 -174.1,174.2,-38.6,-38.5,0,40 -174.1,174.2,-38.5,-38.4,0,40 -174.1,174.2,-38.4,-38.3,0,40 -174.1,174.2,-38.3,-38.2,0,40 -174.1,174.2,-38.2,-38.1,0,40 -174.1,174.2,-38.1,-38,0,40 -174.1,174.2,-38,-37.9,0,40 -174.1,174.2,-37.9,-37.8,0,40 -174.1,174.2,-37.8,-37.7,0,40 -174.1,174.2,-37.7,-37.6,0,40 -174.1,174.2,-37.6,-37.5,0,40 -174.1,174.2,-37.5,-37.4,0,40 -174.1,174.2,-37.4,-37.3,0,40 -174.1,174.2,-37.3,-37.2,0,40 -174.1,174.2,-37.2,-37.1,0,40 -174.1,174.2,-37.1,-37,0,40 -174.1,174.2,-37,-36.9,0,40 -174.1,174.2,-36.9,-36.8,0,40 -174.1,174.2,-36.8,-36.7,0,40 -174.1,174.2,-36.7,-36.6,0,40 -174.1,174.2,-36.6,-36.5,0,40 -174.1,174.2,-36.5,-36.4,0,40 -174.1,174.2,-36.4,-36.3,0,40 -174.1,174.2,-36.3,-36.2,0,40 -174.1,174.2,-36.2,-36.1,0,40 -174.1,174.2,-36.1,-36,0,40 -174.1,174.2,-36,-35.9,0,40 -174.1,174.2,-35.9,-35.8,0,40 -174.1,174.2,-35.8,-35.7,0,40 -174.1,174.2,-35.7,-35.6,0,40 -174.1,174.2,-35.6,-35.5,0,40 -174.1,174.2,-35.5,-35.4,0,40 -174.1,174.2,-35.4,-35.3,0,40 -174.1,174.2,-35.3,-35.2,0,40 -174.1,174.2,-35.2,-35.1,0,40 -174.1,174.2,-35.1,-35,0,40 -174.1,174.2,-35,-34.9,0,40 -174.1,174.2,-34.9,-34.8,0,40 -174.1,174.2,-34.8,-34.7,0,40 -174.1,174.2,-34.7,-34.6,0,40 -174.1,174.2,-34.6,-34.5,0,40 -174.2,174.3,-42.8,-42.7,0,40 -174.2,174.3,-42.7,-42.6,0,40 -174.2,174.3,-42.6,-42.5,0,40 -174.2,174.3,-42.5,-42.4,0,40 -174.2,174.3,-42.4,-42.3,0,40 -174.2,174.3,-42.3,-42.2,0,40 -174.2,174.3,-42.2,-42.1,0,40 -174.2,174.3,-42.1,-42,0,40 -174.2,174.3,-42,-41.9,0,40 -174.2,174.3,-41.9,-41.8,0,40 -174.2,174.3,-41.8,-41.7,0,40 -174.2,174.3,-41.7,-41.6,0,40 -174.2,174.3,-41.6,-41.5,0,40 -174.2,174.3,-41.5,-41.4,0,40 -174.2,174.3,-41.4,-41.3,0,40 -174.2,174.3,-41.3,-41.2,0,40 -174.2,174.3,-41.2,-41.1,0,40 -174.2,174.3,-41.1,-41,0,40 -174.2,174.3,-41,-40.9,0,40 -174.2,174.3,-40.9,-40.8,0,40 -174.2,174.3,-40.8,-40.7,0,40 -174.2,174.3,-40.7,-40.6,0,40 -174.2,174.3,-40.6,-40.5,0,40 -174.2,174.3,-40.5,-40.4,0,40 -174.2,174.3,-40.4,-40.3,0,40 -174.2,174.3,-40.3,-40.2,0,40 -174.2,174.3,-40.2,-40.1,0,40 -174.2,174.3,-40.1,-40,0,40 -174.2,174.3,-40,-39.9,0,40 -174.2,174.3,-39.9,-39.8,0,40 -174.2,174.3,-39.8,-39.7,0,40 -174.2,174.3,-39.7,-39.6,0,40 -174.2,174.3,-39.6,-39.5,0,40 -174.2,174.3,-39.5,-39.4,0,40 -174.2,174.3,-39.4,-39.3,0,40 -174.2,174.3,-39.3,-39.2,0,40 -174.2,174.3,-39.2,-39.1,0,40 -174.2,174.3,-39.1,-39,0,40 -174.2,174.3,-39,-38.9,0,40 -174.2,174.3,-38.9,-38.8,0,40 -174.2,174.3,-38.8,-38.7,0,40 -174.2,174.3,-38.7,-38.6,0,40 -174.2,174.3,-38.6,-38.5,0,40 -174.2,174.3,-38.5,-38.4,0,40 -174.2,174.3,-38.4,-38.3,0,40 -174.2,174.3,-38.3,-38.2,0,40 -174.2,174.3,-38.2,-38.1,0,40 -174.2,174.3,-38.1,-38,0,40 -174.2,174.3,-38,-37.9,0,40 -174.2,174.3,-37.9,-37.8,0,40 -174.2,174.3,-37.8,-37.7,0,40 -174.2,174.3,-37.7,-37.6,0,40 -174.2,174.3,-37.6,-37.5,0,40 -174.2,174.3,-37.5,-37.4,0,40 -174.2,174.3,-37.4,-37.3,0,40 -174.2,174.3,-37.3,-37.2,0,40 -174.2,174.3,-37.2,-37.1,0,40 -174.2,174.3,-37.1,-37,0,40 -174.2,174.3,-37,-36.9,0,40 -174.2,174.3,-36.9,-36.8,0,40 -174.2,174.3,-36.8,-36.7,0,40 -174.2,174.3,-36.7,-36.6,0,40 -174.2,174.3,-36.6,-36.5,0,40 -174.2,174.3,-36.5,-36.4,0,40 -174.2,174.3,-36.4,-36.3,0,40 -174.2,174.3,-36.3,-36.2,0,40 -174.2,174.3,-36.2,-36.1,0,40 -174.2,174.3,-36.1,-36,0,40 -174.2,174.3,-36,-35.9,0,40 -174.2,174.3,-35.9,-35.8,0,40 -174.2,174.3,-35.8,-35.7,0,40 -174.2,174.3,-35.7,-35.6,0,40 -174.2,174.3,-35.6,-35.5,0,40 -174.2,174.3,-35.5,-35.4,0,40 -174.2,174.3,-35.4,-35.3,0,40 -174.2,174.3,-35.3,-35.2,0,40 -174.2,174.3,-35.2,-35.1,0,40 -174.2,174.3,-35.1,-35,0,40 -174.2,174.3,-35,-34.9,0,40 -174.2,174.3,-34.9,-34.8,0,40 -174.2,174.3,-34.8,-34.7,0,40 -174.2,174.3,-34.7,-34.6,0,40 -174.3,174.4,-42.6,-42.5,0,40 -174.3,174.4,-42.5,-42.4,0,40 -174.3,174.4,-42.4,-42.3,0,40 -174.3,174.4,-42.3,-42.2,0,40 -174.3,174.4,-42.2,-42.1,0,40 -174.3,174.4,-42.1,-42,0,40 -174.3,174.4,-42,-41.9,0,40 -174.3,174.4,-41.9,-41.8,0,40 -174.3,174.4,-41.8,-41.7,0,40 -174.3,174.4,-41.7,-41.6,0,40 -174.3,174.4,-41.6,-41.5,0,40 -174.3,174.4,-41.5,-41.4,0,40 -174.3,174.4,-41.4,-41.3,0,40 -174.3,174.4,-41.3,-41.2,0,40 -174.3,174.4,-41.2,-41.1,0,40 -174.3,174.4,-41.1,-41,0,40 -174.3,174.4,-41,-40.9,0,40 -174.3,174.4,-40.9,-40.8,0,40 -174.3,174.4,-40.8,-40.7,0,40 -174.3,174.4,-40.7,-40.6,0,40 -174.3,174.4,-40.6,-40.5,0,40 -174.3,174.4,-40.5,-40.4,0,40 -174.3,174.4,-40.4,-40.3,0,40 -174.3,174.4,-40.3,-40.2,0,40 -174.3,174.4,-40.2,-40.1,0,40 -174.3,174.4,-40.1,-40,0,40 -174.3,174.4,-40,-39.9,0,40 -174.3,174.4,-39.9,-39.8,0,40 -174.3,174.4,-39.8,-39.7,0,40 -174.3,174.4,-39.7,-39.6,0,40 -174.3,174.4,-39.6,-39.5,0,40 -174.3,174.4,-39.5,-39.4,0,40 -174.3,174.4,-39.4,-39.3,0,40 -174.3,174.4,-39.3,-39.2,0,40 -174.3,174.4,-39.2,-39.1,0,40 -174.3,174.4,-39.1,-39,0,40 -174.3,174.4,-39,-38.9,0,40 -174.3,174.4,-38.9,-38.8,0,40 -174.3,174.4,-38.8,-38.7,0,40 -174.3,174.4,-38.7,-38.6,0,40 -174.3,174.4,-38.6,-38.5,0,40 -174.3,174.4,-38.5,-38.4,0,40 -174.3,174.4,-38.4,-38.3,0,40 -174.3,174.4,-38.3,-38.2,0,40 -174.3,174.4,-38.2,-38.1,0,40 -174.3,174.4,-38.1,-38,0,40 -174.3,174.4,-38,-37.9,0,40 -174.3,174.4,-37.9,-37.8,0,40 -174.3,174.4,-37.8,-37.7,0,40 -174.3,174.4,-37.7,-37.6,0,40 -174.3,174.4,-37.6,-37.5,0,40 -174.3,174.4,-37.5,-37.4,0,40 -174.3,174.4,-37.4,-37.3,0,40 -174.3,174.4,-37.3,-37.2,0,40 -174.3,174.4,-37.2,-37.1,0,40 -174.3,174.4,-37.1,-37,0,40 -174.3,174.4,-37,-36.9,0,40 -174.3,174.4,-36.9,-36.8,0,40 -174.3,174.4,-36.8,-36.7,0,40 -174.3,174.4,-36.7,-36.6,0,40 -174.3,174.4,-36.6,-36.5,0,40 -174.3,174.4,-36.5,-36.4,0,40 -174.3,174.4,-36.4,-36.3,0,40 -174.3,174.4,-36.3,-36.2,0,40 -174.3,174.4,-36.2,-36.1,0,40 -174.3,174.4,-36.1,-36,0,40 -174.3,174.4,-36,-35.9,0,40 -174.3,174.4,-35.9,-35.8,0,40 -174.3,174.4,-35.8,-35.7,0,40 -174.3,174.4,-35.7,-35.6,0,40 -174.3,174.4,-35.6,-35.5,0,40 -174.3,174.4,-35.5,-35.4,0,40 -174.3,174.4,-35.4,-35.3,0,40 -174.3,174.4,-35.3,-35.2,0,40 -174.3,174.4,-35.2,-35.1,0,40 -174.3,174.4,-35.1,-35,0,40 -174.3,174.4,-35,-34.9,0,40 -174.3,174.4,-34.9,-34.8,0,40 -174.3,174.4,-34.8,-34.7,0,40 -174.4,174.5,-42.5,-42.4,0,40 -174.4,174.5,-42.4,-42.3,0,40 -174.4,174.5,-42.3,-42.2,0,40 -174.4,174.5,-42.2,-42.1,0,40 -174.4,174.5,-42.1,-42,0,40 -174.4,174.5,-42,-41.9,0,40 -174.4,174.5,-41.9,-41.8,0,40 -174.4,174.5,-41.8,-41.7,0,40 -174.4,174.5,-41.7,-41.6,0,40 -174.4,174.5,-41.6,-41.5,0,40 -174.4,174.5,-41.5,-41.4,0,40 -174.4,174.5,-41.4,-41.3,0,40 -174.4,174.5,-41.3,-41.2,0,40 -174.4,174.5,-41.2,-41.1,0,40 -174.4,174.5,-41.1,-41,0,40 -174.4,174.5,-41,-40.9,0,40 -174.4,174.5,-40.9,-40.8,0,40 -174.4,174.5,-40.8,-40.7,0,40 -174.4,174.5,-40.7,-40.6,0,40 -174.4,174.5,-40.6,-40.5,0,40 -174.4,174.5,-40.5,-40.4,0,40 -174.4,174.5,-40.4,-40.3,0,40 -174.4,174.5,-40.3,-40.2,0,40 -174.4,174.5,-40.2,-40.1,0,40 -174.4,174.5,-40.1,-40,0,40 -174.4,174.5,-40,-39.9,0,40 -174.4,174.5,-39.9,-39.8,0,40 -174.4,174.5,-39.8,-39.7,0,40 -174.4,174.5,-39.7,-39.6,0,40 -174.4,174.5,-39.6,-39.5,0,40 -174.4,174.5,-39.5,-39.4,0,40 -174.4,174.5,-39.4,-39.3,0,40 -174.4,174.5,-39.3,-39.2,0,40 -174.4,174.5,-39.2,-39.1,0,40 -174.4,174.5,-39.1,-39,0,40 -174.4,174.5,-39,-38.9,0,40 -174.4,174.5,-38.9,-38.8,0,40 -174.4,174.5,-38.8,-38.7,0,40 -174.4,174.5,-38.7,-38.6,0,40 -174.4,174.5,-38.6,-38.5,0,40 -174.4,174.5,-38.5,-38.4,0,40 -174.4,174.5,-38.4,-38.3,0,40 -174.4,174.5,-38.3,-38.2,0,40 -174.4,174.5,-38.2,-38.1,0,40 -174.4,174.5,-38.1,-38,0,40 -174.4,174.5,-38,-37.9,0,40 -174.4,174.5,-37.9,-37.8,0,40 -174.4,174.5,-37.8,-37.7,0,40 -174.4,174.5,-37.7,-37.6,0,40 -174.4,174.5,-37.6,-37.5,0,40 -174.4,174.5,-37.5,-37.4,0,40 -174.4,174.5,-37.4,-37.3,0,40 -174.4,174.5,-37.3,-37.2,0,40 -174.4,174.5,-37.2,-37.1,0,40 -174.4,174.5,-37.1,-37,0,40 -174.4,174.5,-37,-36.9,0,40 -174.4,174.5,-36.9,-36.8,0,40 -174.4,174.5,-36.8,-36.7,0,40 -174.4,174.5,-36.7,-36.6,0,40 -174.4,174.5,-36.6,-36.5,0,40 -174.4,174.5,-36.5,-36.4,0,40 -174.4,174.5,-36.4,-36.3,0,40 -174.4,174.5,-36.3,-36.2,0,40 -174.4,174.5,-36.2,-36.1,0,40 -174.4,174.5,-36.1,-36,0,40 -174.4,174.5,-36,-35.9,0,40 -174.4,174.5,-35.9,-35.8,0,40 -174.4,174.5,-35.8,-35.7,0,40 -174.4,174.5,-35.7,-35.6,0,40 -174.4,174.5,-35.6,-35.5,0,40 -174.4,174.5,-35.5,-35.4,0,40 -174.4,174.5,-35.4,-35.3,0,40 -174.4,174.5,-35.3,-35.2,0,40 -174.4,174.5,-35.2,-35.1,0,40 -174.4,174.5,-35.1,-35,0,40 -174.4,174.5,-35,-34.9,0,40 -174.4,174.5,-34.9,-34.8,0,40 -174.5,174.6,-42.4,-42.3,0,40 -174.5,174.6,-42.3,-42.2,0,40 -174.5,174.6,-42.2,-42.1,0,40 -174.5,174.6,-42.1,-42,0,40 -174.5,174.6,-42,-41.9,0,40 -174.5,174.6,-41.9,-41.8,0,40 -174.5,174.6,-41.8,-41.7,0,40 -174.5,174.6,-41.7,-41.6,0,40 -174.5,174.6,-41.6,-41.5,0,40 -174.5,174.6,-41.5,-41.4,0,40 -174.5,174.6,-41.4,-41.3,0,40 -174.5,174.6,-41.3,-41.2,0,40 -174.5,174.6,-41.2,-41.1,0,40 -174.5,174.6,-41.1,-41,0,40 -174.5,174.6,-41,-40.9,0,40 -174.5,174.6,-40.9,-40.8,0,40 -174.5,174.6,-40.8,-40.7,0,40 -174.5,174.6,-40.7,-40.6,0,40 -174.5,174.6,-40.6,-40.5,0,40 -174.5,174.6,-40.5,-40.4,0,40 -174.5,174.6,-40.4,-40.3,0,40 -174.5,174.6,-40.3,-40.2,0,40 -174.5,174.6,-40.2,-40.1,0,40 -174.5,174.6,-40.1,-40,0,40 -174.5,174.6,-40,-39.9,0,40 -174.5,174.6,-39.9,-39.8,0,40 -174.5,174.6,-39.8,-39.7,0,40 -174.5,174.6,-39.7,-39.6,0,40 -174.5,174.6,-39.6,-39.5,0,40 -174.5,174.6,-39.5,-39.4,0,40 -174.5,174.6,-39.4,-39.3,0,40 -174.5,174.6,-39.3,-39.2,0,40 -174.5,174.6,-39.2,-39.1,0,40 -174.5,174.6,-39.1,-39,0,40 -174.5,174.6,-39,-38.9,0,40 -174.5,174.6,-38.9,-38.8,0,40 -174.5,174.6,-38.8,-38.7,0,40 -174.5,174.6,-38.7,-38.6,0,40 -174.5,174.6,-38.6,-38.5,0,40 -174.5,174.6,-38.5,-38.4,0,40 -174.5,174.6,-38.4,-38.3,0,40 -174.5,174.6,-38.3,-38.2,0,40 -174.5,174.6,-38.2,-38.1,0,40 -174.5,174.6,-38.1,-38,0,40 -174.5,174.6,-38,-37.9,0,40 -174.5,174.6,-37.9,-37.8,0,40 -174.5,174.6,-37.8,-37.7,0,40 -174.5,174.6,-37.7,-37.6,0,40 -174.5,174.6,-37.6,-37.5,0,40 -174.5,174.6,-37.5,-37.4,0,40 -174.5,174.6,-37.4,-37.3,0,40 -174.5,174.6,-37.3,-37.2,0,40 -174.5,174.6,-37.2,-37.1,0,40 -174.5,174.6,-37.1,-37,0,40 -174.5,174.6,-37,-36.9,0,40 -174.5,174.6,-36.9,-36.8,0,40 -174.5,174.6,-36.8,-36.7,0,40 -174.5,174.6,-36.7,-36.6,0,40 -174.5,174.6,-36.6,-36.5,0,40 -174.5,174.6,-36.5,-36.4,0,40 -174.5,174.6,-36.4,-36.3,0,40 -174.5,174.6,-36.3,-36.2,0,40 -174.5,174.6,-36.2,-36.1,0,40 -174.5,174.6,-36.1,-36,0,40 -174.5,174.6,-36,-35.9,0,40 -174.5,174.6,-35.9,-35.8,0,40 -174.5,174.6,-35.8,-35.7,0,40 -174.5,174.6,-35.7,-35.6,0,40 -174.5,174.6,-35.6,-35.5,0,40 -174.5,174.6,-35.5,-35.4,0,40 -174.5,174.6,-35.4,-35.3,0,40 -174.5,174.6,-35.3,-35.2,0,40 -174.5,174.6,-35.2,-35.1,0,40 -174.5,174.6,-35.1,-35,0,40 -174.5,174.6,-35,-34.9,0,40 -174.6,174.7,-42.3,-42.2,0,40 -174.6,174.7,-42.2,-42.1,0,40 -174.6,174.7,-42.1,-42,0,40 -174.6,174.7,-42,-41.9,0,40 -174.6,174.7,-41.9,-41.8,0,40 -174.6,174.7,-41.8,-41.7,0,40 -174.6,174.7,-41.7,-41.6,0,40 -174.6,174.7,-41.6,-41.5,0,40 -174.6,174.7,-41.5,-41.4,0,40 -174.6,174.7,-41.4,-41.3,0,40 -174.6,174.7,-41.3,-41.2,0,40 -174.6,174.7,-41.2,-41.1,0,40 -174.6,174.7,-41.1,-41,0,40 -174.6,174.7,-41,-40.9,0,40 -174.6,174.7,-40.9,-40.8,0,40 -174.6,174.7,-40.8,-40.7,0,40 -174.6,174.7,-40.7,-40.6,0,40 -174.6,174.7,-40.6,-40.5,0,40 -174.6,174.7,-40.5,-40.4,0,40 -174.6,174.7,-40.4,-40.3,0,40 -174.6,174.7,-40.3,-40.2,0,40 -174.6,174.7,-40.2,-40.1,0,40 -174.6,174.7,-40.1,-40,0,40 -174.6,174.7,-40,-39.9,0,40 -174.6,174.7,-39.9,-39.8,0,40 -174.6,174.7,-39.8,-39.7,0,40 -174.6,174.7,-39.7,-39.6,0,40 -174.6,174.7,-39.6,-39.5,0,40 -174.6,174.7,-39.5,-39.4,0,40 -174.6,174.7,-39.4,-39.3,0,40 -174.6,174.7,-39.3,-39.2,0,40 -174.6,174.7,-39.2,-39.1,0,40 -174.6,174.7,-39.1,-39,0,40 -174.6,174.7,-39,-38.9,0,40 -174.6,174.7,-38.9,-38.8,0,40 -174.6,174.7,-38.8,-38.7,0,40 -174.6,174.7,-38.7,-38.6,0,40 -174.6,174.7,-38.6,-38.5,0,40 -174.6,174.7,-38.5,-38.4,0,40 -174.6,174.7,-38.4,-38.3,0,40 -174.6,174.7,-38.3,-38.2,0,40 -174.6,174.7,-38.2,-38.1,0,40 -174.6,174.7,-38.1,-38,0,40 -174.6,174.7,-38,-37.9,0,40 -174.6,174.7,-37.9,-37.8,0,40 -174.6,174.7,-37.8,-37.7,0,40 -174.6,174.7,-37.7,-37.6,0,40 -174.6,174.7,-37.6,-37.5,0,40 -174.6,174.7,-37.5,-37.4,0,40 -174.6,174.7,-37.4,-37.3,0,40 -174.6,174.7,-37.3,-37.2,0,40 -174.6,174.7,-37.2,-37.1,0,40 -174.6,174.7,-37.1,-37,0,40 -174.6,174.7,-37,-36.9,0,40 -174.6,174.7,-36.9,-36.8,0,40 -174.6,174.7,-36.8,-36.7,0,40 -174.6,174.7,-36.7,-36.6,0,40 -174.6,174.7,-36.6,-36.5,0,40 -174.6,174.7,-36.5,-36.4,0,40 -174.6,174.7,-36.4,-36.3,0,40 -174.6,174.7,-36.3,-36.2,0,40 -174.6,174.7,-36.2,-36.1,0,40 -174.6,174.7,-36.1,-36,0,40 -174.6,174.7,-36,-35.9,0,40 -174.6,174.7,-35.9,-35.8,0,40 -174.6,174.7,-35.8,-35.7,0,40 -174.6,174.7,-35.7,-35.6,0,40 -174.6,174.7,-35.6,-35.5,0,40 -174.6,174.7,-35.5,-35.4,0,40 -174.6,174.7,-35.4,-35.3,0,40 -174.6,174.7,-35.3,-35.2,0,40 -174.6,174.7,-35.2,-35.1,0,40 -174.6,174.7,-35.1,-35,0,40 -174.7,174.8,-42.2,-42.1,0,40 -174.7,174.8,-42.1,-42,0,40 -174.7,174.8,-42,-41.9,0,40 -174.7,174.8,-41.9,-41.8,0,40 -174.7,174.8,-41.8,-41.7,0,40 -174.7,174.8,-41.7,-41.6,0,40 -174.7,174.8,-41.6,-41.5,0,40 -174.7,174.8,-41.5,-41.4,0,40 -174.7,174.8,-41.4,-41.3,0,40 -174.7,174.8,-41.3,-41.2,0,40 -174.7,174.8,-41.2,-41.1,0,40 -174.7,174.8,-41.1,-41,0,40 -174.7,174.8,-41,-40.9,0,40 -174.7,174.8,-40.9,-40.8,0,40 -174.7,174.8,-40.8,-40.7,0,40 -174.7,174.8,-40.7,-40.6,0,40 -174.7,174.8,-40.6,-40.5,0,40 -174.7,174.8,-40.5,-40.4,0,40 -174.7,174.8,-40.4,-40.3,0,40 -174.7,174.8,-40.3,-40.2,0,40 -174.7,174.8,-40.2,-40.1,0,40 -174.7,174.8,-40.1,-40,0,40 -174.7,174.8,-40,-39.9,0,40 -174.7,174.8,-39.9,-39.8,0,40 -174.7,174.8,-39.8,-39.7,0,40 -174.7,174.8,-39.7,-39.6,0,40 -174.7,174.8,-39.6,-39.5,0,40 -174.7,174.8,-39.5,-39.4,0,40 -174.7,174.8,-39.4,-39.3,0,40 -174.7,174.8,-39.3,-39.2,0,40 -174.7,174.8,-39.2,-39.1,0,40 -174.7,174.8,-39.1,-39,0,40 -174.7,174.8,-39,-38.9,0,40 -174.7,174.8,-38.9,-38.8,0,40 -174.7,174.8,-38.8,-38.7,0,40 -174.7,174.8,-38.7,-38.6,0,40 -174.7,174.8,-38.6,-38.5,0,40 -174.7,174.8,-38.5,-38.4,0,40 -174.7,174.8,-38.4,-38.3,0,40 -174.7,174.8,-38.3,-38.2,0,40 -174.7,174.8,-38.2,-38.1,0,40 -174.7,174.8,-38.1,-38,0,40 -174.7,174.8,-38,-37.9,0,40 -174.7,174.8,-37.9,-37.8,0,40 -174.7,174.8,-37.8,-37.7,0,40 -174.7,174.8,-37.7,-37.6,0,40 -174.7,174.8,-37.6,-37.5,0,40 -174.7,174.8,-37.5,-37.4,0,40 -174.7,174.8,-37.4,-37.3,0,40 -174.7,174.8,-37.3,-37.2,0,40 -174.7,174.8,-37.2,-37.1,0,40 -174.7,174.8,-37.1,-37,0,40 -174.7,174.8,-37,-36.9,0,40 -174.7,174.8,-36.9,-36.8,0,40 -174.7,174.8,-36.8,-36.7,0,40 -174.7,174.8,-36.7,-36.6,0,40 -174.7,174.8,-36.6,-36.5,0,40 -174.7,174.8,-36.5,-36.4,0,40 -174.7,174.8,-36.4,-36.3,0,40 -174.7,174.8,-36.3,-36.2,0,40 -174.7,174.8,-36.2,-36.1,0,40 -174.7,174.8,-36.1,-36,0,40 -174.7,174.8,-36,-35.9,0,40 -174.7,174.8,-35.9,-35.8,0,40 -174.7,174.8,-35.8,-35.7,0,40 -174.7,174.8,-35.7,-35.6,0,40 -174.7,174.8,-35.6,-35.5,0,40 -174.7,174.8,-35.5,-35.4,0,40 -174.7,174.8,-35.4,-35.3,0,40 -174.7,174.8,-35.3,-35.2,0,40 -174.7,174.8,-35.2,-35.1,0,40 -174.8,174.9,-42.2,-42.1,0,40 -174.8,174.9,-42.1,-42,0,40 -174.8,174.9,-42,-41.9,0,40 -174.8,174.9,-41.9,-41.8,0,40 -174.8,174.9,-41.8,-41.7,0,40 -174.8,174.9,-41.7,-41.6,0,40 -174.8,174.9,-41.6,-41.5,0,40 -174.8,174.9,-41.5,-41.4,0,40 -174.8,174.9,-41.4,-41.3,0,40 -174.8,174.9,-41.3,-41.2,0,40 -174.8,174.9,-41.2,-41.1,0,40 -174.8,174.9,-41.1,-41,0,40 -174.8,174.9,-41,-40.9,0,40 -174.8,174.9,-40.9,-40.8,0,40 -174.8,174.9,-40.8,-40.7,0,40 -174.8,174.9,-40.7,-40.6,0,40 -174.8,174.9,-40.6,-40.5,0,40 -174.8,174.9,-40.5,-40.4,0,40 -174.8,174.9,-40.4,-40.3,0,40 -174.8,174.9,-40.3,-40.2,0,40 -174.8,174.9,-40.2,-40.1,0,40 -174.8,174.9,-40.1,-40,0,40 -174.8,174.9,-40,-39.9,0,40 -174.8,174.9,-39.9,-39.8,0,40 -174.8,174.9,-39.8,-39.7,0,40 -174.8,174.9,-39.7,-39.6,0,40 -174.8,174.9,-39.6,-39.5,0,40 -174.8,174.9,-39.5,-39.4,0,40 -174.8,174.9,-39.4,-39.3,0,40 -174.8,174.9,-39.3,-39.2,0,40 -174.8,174.9,-39.2,-39.1,0,40 -174.8,174.9,-39.1,-39,0,40 -174.8,174.9,-39,-38.9,0,40 -174.8,174.9,-38.9,-38.8,0,40 -174.8,174.9,-38.8,-38.7,0,40 -174.8,174.9,-38.7,-38.6,0,40 -174.8,174.9,-38.6,-38.5,0,40 -174.8,174.9,-38.5,-38.4,0,40 -174.8,174.9,-38.4,-38.3,0,40 -174.8,174.9,-38.3,-38.2,0,40 -174.8,174.9,-38.2,-38.1,0,40 -174.8,174.9,-38.1,-38,0,40 -174.8,174.9,-38,-37.9,0,40 -174.8,174.9,-37.9,-37.8,0,40 -174.8,174.9,-37.8,-37.7,0,40 -174.8,174.9,-37.7,-37.6,0,40 -174.8,174.9,-37.6,-37.5,0,40 -174.8,174.9,-37.5,-37.4,0,40 -174.8,174.9,-37.4,-37.3,0,40 -174.8,174.9,-37.3,-37.2,0,40 -174.8,174.9,-37.2,-37.1,0,40 -174.8,174.9,-37.1,-37,0,40 -174.8,174.9,-37,-36.9,0,40 -174.8,174.9,-36.9,-36.8,0,40 -174.8,174.9,-36.8,-36.7,0,40 -174.8,174.9,-36.7,-36.6,0,40 -174.8,174.9,-36.6,-36.5,0,40 -174.8,174.9,-36.5,-36.4,0,40 -174.8,174.9,-36.4,-36.3,0,40 -174.8,174.9,-36.3,-36.2,0,40 -174.8,174.9,-36.2,-36.1,0,40 -174.8,174.9,-36.1,-36,0,40 -174.8,174.9,-36,-35.9,0,40 -174.8,174.9,-35.9,-35.8,0,40 -174.8,174.9,-35.8,-35.7,0,40 -174.8,174.9,-35.7,-35.6,0,40 -174.8,174.9,-35.6,-35.5,0,40 -174.8,174.9,-35.5,-35.4,0,40 -174.8,174.9,-35.4,-35.3,0,40 -174.8,174.9,-35.3,-35.2,0,40 -174.8,174.9,-35.2,-35.1,0,40 -174.9,175,-42.1,-42,0,40 -174.9,175,-42,-41.9,0,40 -174.9,175,-41.9,-41.8,0,40 -174.9,175,-41.8,-41.7,0,40 -174.9,175,-41.7,-41.6,0,40 -174.9,175,-41.6,-41.5,0,40 -174.9,175,-41.5,-41.4,0,40 -174.9,175,-41.4,-41.3,0,40 -174.9,175,-41.3,-41.2,0,40 -174.9,175,-41.2,-41.1,0,40 -174.9,175,-41.1,-41,0,40 -174.9,175,-41,-40.9,0,40 -174.9,175,-40.9,-40.8,0,40 -174.9,175,-40.8,-40.7,0,40 -174.9,175,-40.7,-40.6,0,40 -174.9,175,-40.6,-40.5,0,40 -174.9,175,-40.5,-40.4,0,40 -174.9,175,-40.4,-40.3,0,40 -174.9,175,-40.3,-40.2,0,40 -174.9,175,-40.2,-40.1,0,40 -174.9,175,-40.1,-40,0,40 -174.9,175,-40,-39.9,0,40 -174.9,175,-39.9,-39.8,0,40 -174.9,175,-39.8,-39.7,0,40 -174.9,175,-39.7,-39.6,0,40 -174.9,175,-39.6,-39.5,0,40 -174.9,175,-39.5,-39.4,0,40 -174.9,175,-39.4,-39.3,0,40 -174.9,175,-39.3,-39.2,0,40 -174.9,175,-39.2,-39.1,0,40 -174.9,175,-39.1,-39,0,40 -174.9,175,-39,-38.9,0,40 -174.9,175,-38.9,-38.8,0,40 -174.9,175,-38.8,-38.7,0,40 -174.9,175,-38.7,-38.6,0,40 -174.9,175,-38.6,-38.5,0,40 -174.9,175,-38.5,-38.4,0,40 -174.9,175,-38.4,-38.3,0,40 -174.9,175,-38.3,-38.2,0,40 -174.9,175,-38.2,-38.1,0,40 -174.9,175,-38.1,-38,0,40 -174.9,175,-38,-37.9,0,40 -174.9,175,-37.9,-37.8,0,40 -174.9,175,-37.8,-37.7,0,40 -174.9,175,-37.7,-37.6,0,40 -174.9,175,-37.6,-37.5,0,40 -174.9,175,-37.5,-37.4,0,40 -174.9,175,-37.4,-37.3,0,40 -174.9,175,-37.3,-37.2,0,40 -174.9,175,-37.2,-37.1,0,40 -174.9,175,-37.1,-37,0,40 -174.9,175,-37,-36.9,0,40 -174.9,175,-36.9,-36.8,0,40 -174.9,175,-36.8,-36.7,0,40 -174.9,175,-36.7,-36.6,0,40 -174.9,175,-36.6,-36.5,0,40 -174.9,175,-36.5,-36.4,0,40 -174.9,175,-36.4,-36.3,0,40 -174.9,175,-36.3,-36.2,0,40 -174.9,175,-36.2,-36.1,0,40 -174.9,175,-36.1,-36,0,40 -174.9,175,-36,-35.9,0,40 -174.9,175,-35.9,-35.8,0,40 -174.9,175,-35.8,-35.7,0,40 -174.9,175,-35.7,-35.6,0,40 -174.9,175,-35.6,-35.5,0,40 -174.9,175,-35.5,-35.4,0,40 -174.9,175,-35.4,-35.3,0,40 -174.9,175,-35.3,-35.2,0,40 -175,175.1,-42,-41.9,0,40 -175,175.1,-41.9,-41.8,0,40 -175,175.1,-41.8,-41.7,0,40 -175,175.1,-41.7,-41.6,0,40 -175,175.1,-41.6,-41.5,0,40 -175,175.1,-41.5,-41.4,0,40 -175,175.1,-41.4,-41.3,0,40 -175,175.1,-41.3,-41.2,0,40 -175,175.1,-41.2,-41.1,0,40 -175,175.1,-41.1,-41,0,40 -175,175.1,-41,-40.9,0,40 -175,175.1,-40.9,-40.8,0,40 -175,175.1,-40.8,-40.7,0,40 -175,175.1,-40.7,-40.6,0,40 -175,175.1,-40.6,-40.5,0,40 -175,175.1,-40.5,-40.4,0,40 -175,175.1,-40.4,-40.3,0,40 -175,175.1,-40.3,-40.2,0,40 -175,175.1,-40.2,-40.1,0,40 -175,175.1,-40.1,-40,0,40 -175,175.1,-40,-39.9,0,40 -175,175.1,-39.9,-39.8,0,40 -175,175.1,-39.8,-39.7,0,40 -175,175.1,-39.7,-39.6,0,40 -175,175.1,-39.6,-39.5,0,40 -175,175.1,-39.5,-39.4,0,40 -175,175.1,-39.4,-39.3,0,40 -175,175.1,-39.3,-39.2,0,40 -175,175.1,-39.2,-39.1,0,40 -175,175.1,-39.1,-39,0,40 -175,175.1,-39,-38.9,0,40 -175,175.1,-38.9,-38.8,0,40 -175,175.1,-38.8,-38.7,0,40 -175,175.1,-38.7,-38.6,0,40 -175,175.1,-38.6,-38.5,0,40 -175,175.1,-38.5,-38.4,0,40 -175,175.1,-38.4,-38.3,0,40 -175,175.1,-38.3,-38.2,0,40 -175,175.1,-38.2,-38.1,0,40 -175,175.1,-38.1,-38,0,40 -175,175.1,-38,-37.9,0,40 -175,175.1,-37.9,-37.8,0,40 -175,175.1,-37.8,-37.7,0,40 -175,175.1,-37.7,-37.6,0,40 -175,175.1,-37.6,-37.5,0,40 -175,175.1,-37.5,-37.4,0,40 -175,175.1,-37.4,-37.3,0,40 -175,175.1,-37.3,-37.2,0,40 -175,175.1,-37.2,-37.1,0,40 -175,175.1,-37.1,-37,0,40 -175,175.1,-37,-36.9,0,40 -175,175.1,-36.9,-36.8,0,40 -175,175.1,-36.8,-36.7,0,40 -175,175.1,-36.7,-36.6,0,40 -175,175.1,-36.6,-36.5,0,40 -175,175.1,-36.5,-36.4,0,40 -175,175.1,-36.4,-36.3,0,40 -175,175.1,-36.3,-36.2,0,40 -175,175.1,-36.2,-36.1,0,40 -175,175.1,-36.1,-36,0,40 -175,175.1,-36,-35.9,0,40 -175,175.1,-35.9,-35.8,0,40 -175,175.1,-35.8,-35.7,0,40 -175,175.1,-35.7,-35.6,0,40 -175,175.1,-35.6,-35.5,0,40 -175,175.1,-35.5,-35.4,0,40 -175,175.1,-35.4,-35.3,0,40 -175.1,175.2,-42.1,-42,0,40 -175.1,175.2,-42,-41.9,0,40 -175.1,175.2,-41.9,-41.8,0,40 -175.1,175.2,-41.8,-41.7,0,40 -175.1,175.2,-41.7,-41.6,0,40 -175.1,175.2,-41.6,-41.5,0,40 -175.1,175.2,-41.5,-41.4,0,40 -175.1,175.2,-41.4,-41.3,0,40 -175.1,175.2,-41.3,-41.2,0,40 -175.1,175.2,-41.2,-41.1,0,40 -175.1,175.2,-41.1,-41,0,40 -175.1,175.2,-41,-40.9,0,40 -175.1,175.2,-40.9,-40.8,0,40 -175.1,175.2,-40.8,-40.7,0,40 -175.1,175.2,-40.7,-40.6,0,40 -175.1,175.2,-40.6,-40.5,0,40 -175.1,175.2,-40.5,-40.4,0,40 -175.1,175.2,-40.4,-40.3,0,40 -175.1,175.2,-40.3,-40.2,0,40 -175.1,175.2,-40.2,-40.1,0,40 -175.1,175.2,-40.1,-40,0,40 -175.1,175.2,-40,-39.9,0,40 -175.1,175.2,-39.9,-39.8,0,40 -175.1,175.2,-39.8,-39.7,0,40 -175.1,175.2,-39.7,-39.6,0,40 -175.1,175.2,-39.6,-39.5,0,40 -175.1,175.2,-39.5,-39.4,0,40 -175.1,175.2,-39.4,-39.3,0,40 -175.1,175.2,-39.3,-39.2,0,40 -175.1,175.2,-39.2,-39.1,0,40 -175.1,175.2,-39.1,-39,0,40 -175.1,175.2,-39,-38.9,0,40 -175.1,175.2,-38.9,-38.8,0,40 -175.1,175.2,-38.8,-38.7,0,40 -175.1,175.2,-38.7,-38.6,0,40 -175.1,175.2,-38.6,-38.5,0,40 -175.1,175.2,-38.5,-38.4,0,40 -175.1,175.2,-38.4,-38.3,0,40 -175.1,175.2,-38.3,-38.2,0,40 -175.1,175.2,-38.2,-38.1,0,40 -175.1,175.2,-38.1,-38,0,40 -175.1,175.2,-38,-37.9,0,40 -175.1,175.2,-37.9,-37.8,0,40 -175.1,175.2,-37.8,-37.7,0,40 -175.1,175.2,-37.7,-37.6,0,40 -175.1,175.2,-37.6,-37.5,0,40 -175.1,175.2,-37.5,-37.4,0,40 -175.1,175.2,-37.4,-37.3,0,40 -175.1,175.2,-37.3,-37.2,0,40 -175.1,175.2,-37.2,-37.1,0,40 -175.1,175.2,-37.1,-37,0,40 -175.1,175.2,-37,-36.9,0,40 -175.1,175.2,-36.9,-36.8,0,40 -175.1,175.2,-36.8,-36.7,0,40 -175.1,175.2,-36.7,-36.6,0,40 -175.1,175.2,-36.6,-36.5,0,40 -175.1,175.2,-36.5,-36.4,0,40 -175.1,175.2,-36.4,-36.3,0,40 -175.1,175.2,-36.3,-36.2,0,40 -175.1,175.2,-36.2,-36.1,0,40 -175.1,175.2,-36.1,-36,0,40 -175.1,175.2,-36,-35.9,0,40 -175.1,175.2,-35.9,-35.8,0,40 -175.1,175.2,-35.8,-35.7,0,40 -175.1,175.2,-35.7,-35.6,0,40 -175.1,175.2,-35.6,-35.5,0,40 -175.1,175.2,-35.5,-35.4,0,40 -175.2,175.3,-42.1,-42,0,40 -175.2,175.3,-42,-41.9,0,40 -175.2,175.3,-41.9,-41.8,0,40 -175.2,175.3,-41.8,-41.7,0,40 -175.2,175.3,-41.7,-41.6,0,40 -175.2,175.3,-41.6,-41.5,0,40 -175.2,175.3,-41.5,-41.4,0,40 -175.2,175.3,-41.4,-41.3,0,40 -175.2,175.3,-41.3,-41.2,0,40 -175.2,175.3,-41.2,-41.1,0,40 -175.2,175.3,-41.1,-41,0,40 -175.2,175.3,-41,-40.9,0,40 -175.2,175.3,-40.9,-40.8,0,40 -175.2,175.3,-40.8,-40.7,0,40 -175.2,175.3,-40.7,-40.6,0,40 -175.2,175.3,-40.6,-40.5,0,40 -175.2,175.3,-40.5,-40.4,0,40 -175.2,175.3,-40.4,-40.3,0,40 -175.2,175.3,-40.3,-40.2,0,40 -175.2,175.3,-40.2,-40.1,0,40 -175.2,175.3,-40.1,-40,0,40 -175.2,175.3,-40,-39.9,0,40 -175.2,175.3,-39.9,-39.8,0,40 -175.2,175.3,-39.8,-39.7,0,40 -175.2,175.3,-39.7,-39.6,0,40 -175.2,175.3,-39.6,-39.5,0,40 -175.2,175.3,-39.5,-39.4,0,40 -175.2,175.3,-39.4,-39.3,0,40 -175.2,175.3,-39.3,-39.2,0,40 -175.2,175.3,-39.2,-39.1,0,40 -175.2,175.3,-39.1,-39,0,40 -175.2,175.3,-39,-38.9,0,40 -175.2,175.3,-38.9,-38.8,0,40 -175.2,175.3,-38.8,-38.7,0,40 -175.2,175.3,-38.7,-38.6,0,40 -175.2,175.3,-38.6,-38.5,0,40 -175.2,175.3,-38.5,-38.4,0,40 -175.2,175.3,-38.4,-38.3,0,40 -175.2,175.3,-38.3,-38.2,0,40 -175.2,175.3,-38.2,-38.1,0,40 -175.2,175.3,-38.1,-38,0,40 -175.2,175.3,-38,-37.9,0,40 -175.2,175.3,-37.9,-37.8,0,40 -175.2,175.3,-37.8,-37.7,0,40 -175.2,175.3,-37.7,-37.6,0,40 -175.2,175.3,-37.6,-37.5,0,40 -175.2,175.3,-37.5,-37.4,0,40 -175.2,175.3,-37.4,-37.3,0,40 -175.2,175.3,-37.3,-37.2,0,40 -175.2,175.3,-37.2,-37.1,0,40 -175.2,175.3,-37.1,-37,0,40 -175.2,175.3,-37,-36.9,0,40 -175.2,175.3,-36.9,-36.8,0,40 -175.2,175.3,-36.8,-36.7,0,40 -175.2,175.3,-36.7,-36.6,0,40 -175.2,175.3,-36.6,-36.5,0,40 -175.2,175.3,-36.5,-36.4,0,40 -175.2,175.3,-36.4,-36.3,0,40 -175.2,175.3,-36.3,-36.2,0,40 -175.2,175.3,-36.2,-36.1,0,40 -175.2,175.3,-36.1,-36,0,40 -175.2,175.3,-36,-35.9,0,40 -175.2,175.3,-35.9,-35.8,0,40 -175.2,175.3,-35.8,-35.7,0,40 -175.2,175.3,-35.7,-35.6,0,40 -175.2,175.3,-35.6,-35.5,0,40 -175.3,175.4,-42.1,-42,0,40 -175.3,175.4,-42,-41.9,0,40 -175.3,175.4,-41.9,-41.8,0,40 -175.3,175.4,-41.8,-41.7,0,40 -175.3,175.4,-41.7,-41.6,0,40 -175.3,175.4,-41.6,-41.5,0,40 -175.3,175.4,-41.5,-41.4,0,40 -175.3,175.4,-41.4,-41.3,0,40 -175.3,175.4,-41.3,-41.2,0,40 -175.3,175.4,-41.2,-41.1,0,40 -175.3,175.4,-41.1,-41,0,40 -175.3,175.4,-41,-40.9,0,40 -175.3,175.4,-40.9,-40.8,0,40 -175.3,175.4,-40.8,-40.7,0,40 -175.3,175.4,-40.7,-40.6,0,40 -175.3,175.4,-40.6,-40.5,0,40 -175.3,175.4,-40.5,-40.4,0,40 -175.3,175.4,-40.4,-40.3,0,40 -175.3,175.4,-40.3,-40.2,0,40 -175.3,175.4,-40.2,-40.1,0,40 -175.3,175.4,-40.1,-40,0,40 -175.3,175.4,-40,-39.9,0,40 -175.3,175.4,-39.9,-39.8,0,40 -175.3,175.4,-39.8,-39.7,0,40 -175.3,175.4,-39.7,-39.6,0,40 -175.3,175.4,-39.6,-39.5,0,40 -175.3,175.4,-39.5,-39.4,0,40 -175.3,175.4,-39.4,-39.3,0,40 -175.3,175.4,-39.3,-39.2,0,40 -175.3,175.4,-39.2,-39.1,0,40 -175.3,175.4,-39.1,-39,0,40 -175.3,175.4,-39,-38.9,0,40 -175.3,175.4,-38.9,-38.8,0,40 -175.3,175.4,-38.8,-38.7,0,40 -175.3,175.4,-38.7,-38.6,0,40 -175.3,175.4,-38.6,-38.5,0,40 -175.3,175.4,-38.5,-38.4,0,40 -175.3,175.4,-38.4,-38.3,0,40 -175.3,175.4,-38.3,-38.2,0,40 -175.3,175.4,-38.2,-38.1,0,40 -175.3,175.4,-38.1,-38,0,40 -175.3,175.4,-38,-37.9,0,40 -175.3,175.4,-37.9,-37.8,0,40 -175.3,175.4,-37.8,-37.7,0,40 -175.3,175.4,-37.7,-37.6,0,40 -175.3,175.4,-37.6,-37.5,0,40 -175.3,175.4,-37.5,-37.4,0,40 -175.3,175.4,-37.4,-37.3,0,40 -175.3,175.4,-37.3,-37.2,0,40 -175.3,175.4,-37.2,-37.1,0,40 -175.3,175.4,-37.1,-37,0,40 -175.3,175.4,-37,-36.9,0,40 -175.3,175.4,-36.9,-36.8,0,40 -175.3,175.4,-36.8,-36.7,0,40 -175.3,175.4,-36.7,-36.6,0,40 -175.3,175.4,-36.6,-36.5,0,40 -175.3,175.4,-36.5,-36.4,0,40 -175.3,175.4,-36.4,-36.3,0,40 -175.3,175.4,-36.3,-36.2,0,40 -175.3,175.4,-36.2,-36.1,0,40 -175.3,175.4,-36.1,-36,0,40 -175.3,175.4,-36,-35.9,0,40 -175.3,175.4,-35.9,-35.8,0,40 -175.3,175.4,-35.8,-35.7,0,40 -175.3,175.4,-35.7,-35.6,0,40 -175.3,175.4,-35.6,-35.5,0,40 -175.4,175.5,-42.1,-42,0,40 -175.4,175.5,-42,-41.9,0,40 -175.4,175.5,-41.9,-41.8,0,40 -175.4,175.5,-41.8,-41.7,0,40 -175.4,175.5,-41.7,-41.6,0,40 -175.4,175.5,-41.6,-41.5,0,40 -175.4,175.5,-41.5,-41.4,0,40 -175.4,175.5,-41.4,-41.3,0,40 -175.4,175.5,-41.3,-41.2,0,40 -175.4,175.5,-41.2,-41.1,0,40 -175.4,175.5,-41.1,-41,0,40 -175.4,175.5,-41,-40.9,0,40 -175.4,175.5,-40.9,-40.8,0,40 -175.4,175.5,-40.8,-40.7,0,40 -175.4,175.5,-40.7,-40.6,0,40 -175.4,175.5,-40.6,-40.5,0,40 -175.4,175.5,-40.5,-40.4,0,40 -175.4,175.5,-40.4,-40.3,0,40 -175.4,175.5,-40.3,-40.2,0,40 -175.4,175.5,-40.2,-40.1,0,40 -175.4,175.5,-40.1,-40,0,40 -175.4,175.5,-40,-39.9,0,40 -175.4,175.5,-39.9,-39.8,0,40 -175.4,175.5,-39.8,-39.7,0,40 -175.4,175.5,-39.7,-39.6,0,40 -175.4,175.5,-39.6,-39.5,0,40 -175.4,175.5,-39.5,-39.4,0,40 -175.4,175.5,-39.4,-39.3,0,40 -175.4,175.5,-39.3,-39.2,0,40 -175.4,175.5,-39.2,-39.1,0,40 -175.4,175.5,-39.1,-39,0,40 -175.4,175.5,-39,-38.9,0,40 -175.4,175.5,-38.9,-38.8,0,40 -175.4,175.5,-38.8,-38.7,0,40 -175.4,175.5,-38.7,-38.6,0,40 -175.4,175.5,-38.6,-38.5,0,40 -175.4,175.5,-38.5,-38.4,0,40 -175.4,175.5,-38.4,-38.3,0,40 -175.4,175.5,-38.3,-38.2,0,40 -175.4,175.5,-38.2,-38.1,0,40 -175.4,175.5,-38.1,-38,0,40 -175.4,175.5,-38,-37.9,0,40 -175.4,175.5,-37.9,-37.8,0,40 -175.4,175.5,-37.8,-37.7,0,40 -175.4,175.5,-37.7,-37.6,0,40 -175.4,175.5,-37.6,-37.5,0,40 -175.4,175.5,-37.5,-37.4,0,40 -175.4,175.5,-37.4,-37.3,0,40 -175.4,175.5,-37.3,-37.2,0,40 -175.4,175.5,-37.2,-37.1,0,40 -175.4,175.5,-37.1,-37,0,40 -175.4,175.5,-37,-36.9,0,40 -175.4,175.5,-36.9,-36.8,0,40 -175.4,175.5,-36.8,-36.7,0,40 -175.4,175.5,-36.7,-36.6,0,40 -175.4,175.5,-36.6,-36.5,0,40 -175.4,175.5,-36.5,-36.4,0,40 -175.4,175.5,-36.4,-36.3,0,40 -175.4,175.5,-36.3,-36.2,0,40 -175.4,175.5,-36.2,-36.1,0,40 -175.4,175.5,-36.1,-36,0,40 -175.4,175.5,-36,-35.9,0,40 -175.4,175.5,-35.9,-35.8,0,40 -175.4,175.5,-35.8,-35.7,0,40 -175.4,175.5,-35.7,-35.6,0,40 -175.5,175.6,-42,-41.9,0,40 -175.5,175.6,-41.9,-41.8,0,40 -175.5,175.6,-41.8,-41.7,0,40 -175.5,175.6,-41.7,-41.6,0,40 -175.5,175.6,-41.6,-41.5,0,40 -175.5,175.6,-41.5,-41.4,0,40 -175.5,175.6,-41.4,-41.3,0,40 -175.5,175.6,-41.3,-41.2,0,40 -175.5,175.6,-41.2,-41.1,0,40 -175.5,175.6,-41.1,-41,0,40 -175.5,175.6,-41,-40.9,0,40 -175.5,175.6,-40.9,-40.8,0,40 -175.5,175.6,-40.8,-40.7,0,40 -175.5,175.6,-40.7,-40.6,0,40 -175.5,175.6,-40.6,-40.5,0,40 -175.5,175.6,-40.5,-40.4,0,40 -175.5,175.6,-40.4,-40.3,0,40 -175.5,175.6,-40.3,-40.2,0,40 -175.5,175.6,-40.2,-40.1,0,40 -175.5,175.6,-40.1,-40,0,40 -175.5,175.6,-40,-39.9,0,40 -175.5,175.6,-39.9,-39.8,0,40 -175.5,175.6,-39.8,-39.7,0,40 -175.5,175.6,-39.7,-39.6,0,40 -175.5,175.6,-39.6,-39.5,0,40 -175.5,175.6,-39.5,-39.4,0,40 -175.5,175.6,-39.4,-39.3,0,40 -175.5,175.6,-39.3,-39.2,0,40 -175.5,175.6,-39.2,-39.1,0,40 -175.5,175.6,-39.1,-39,0,40 -175.5,175.6,-39,-38.9,0,40 -175.5,175.6,-38.9,-38.8,0,40 -175.5,175.6,-38.8,-38.7,0,40 -175.5,175.6,-38.7,-38.6,0,40 -175.5,175.6,-38.6,-38.5,0,40 -175.5,175.6,-38.5,-38.4,0,40 -175.5,175.6,-38.4,-38.3,0,40 -175.5,175.6,-38.3,-38.2,0,40 -175.5,175.6,-38.2,-38.1,0,40 -175.5,175.6,-38.1,-38,0,40 -175.5,175.6,-38,-37.9,0,40 -175.5,175.6,-37.9,-37.8,0,40 -175.5,175.6,-37.8,-37.7,0,40 -175.5,175.6,-37.7,-37.6,0,40 -175.5,175.6,-37.6,-37.5,0,40 -175.5,175.6,-37.5,-37.4,0,40 -175.5,175.6,-37.4,-37.3,0,40 -175.5,175.6,-37.3,-37.2,0,40 -175.5,175.6,-37.2,-37.1,0,40 -175.5,175.6,-37.1,-37,0,40 -175.5,175.6,-37,-36.9,0,40 -175.5,175.6,-36.9,-36.8,0,40 -175.5,175.6,-36.8,-36.7,0,40 -175.5,175.6,-36.7,-36.6,0,40 -175.5,175.6,-36.6,-36.5,0,40 -175.5,175.6,-36.5,-36.4,0,40 -175.5,175.6,-36.4,-36.3,0,40 -175.5,175.6,-36.3,-36.2,0,40 -175.5,175.6,-36.2,-36.1,0,40 -175.5,175.6,-36.1,-36,0,40 -175.5,175.6,-36,-35.9,0,40 -175.5,175.6,-35.9,-35.8,0,40 -175.5,175.6,-35.8,-35.7,0,40 -175.5,175.6,-35.7,-35.6,0,40 -175.6,175.7,-42,-41.9,0,40 -175.6,175.7,-41.9,-41.8,0,40 -175.6,175.7,-41.8,-41.7,0,40 -175.6,175.7,-41.7,-41.6,0,40 -175.6,175.7,-41.6,-41.5,0,40 -175.6,175.7,-41.5,-41.4,0,40 -175.6,175.7,-41.4,-41.3,0,40 -175.6,175.7,-41.3,-41.2,0,40 -175.6,175.7,-41.2,-41.1,0,40 -175.6,175.7,-41.1,-41,0,40 -175.6,175.7,-41,-40.9,0,40 -175.6,175.7,-40.9,-40.8,0,40 -175.6,175.7,-40.8,-40.7,0,40 -175.6,175.7,-40.7,-40.6,0,40 -175.6,175.7,-40.6,-40.5,0,40 -175.6,175.7,-40.5,-40.4,0,40 -175.6,175.7,-40.4,-40.3,0,40 -175.6,175.7,-40.3,-40.2,0,40 -175.6,175.7,-40.2,-40.1,0,40 -175.6,175.7,-40.1,-40,0,40 -175.6,175.7,-40,-39.9,0,40 -175.6,175.7,-39.9,-39.8,0,40 -175.6,175.7,-39.8,-39.7,0,40 -175.6,175.7,-39.7,-39.6,0,40 -175.6,175.7,-39.6,-39.5,0,40 -175.6,175.7,-39.5,-39.4,0,40 -175.6,175.7,-39.4,-39.3,0,40 -175.6,175.7,-39.3,-39.2,0,40 -175.6,175.7,-39.2,-39.1,0,40 -175.6,175.7,-39.1,-39,0,40 -175.6,175.7,-39,-38.9,0,40 -175.6,175.7,-38.9,-38.8,0,40 -175.6,175.7,-38.8,-38.7,0,40 -175.6,175.7,-38.7,-38.6,0,40 -175.6,175.7,-38.6,-38.5,0,40 -175.6,175.7,-38.5,-38.4,0,40 -175.6,175.7,-38.4,-38.3,0,40 -175.6,175.7,-38.3,-38.2,0,40 -175.6,175.7,-38.2,-38.1,0,40 -175.6,175.7,-38.1,-38,0,40 -175.6,175.7,-38,-37.9,0,40 -175.6,175.7,-37.9,-37.8,0,40 -175.6,175.7,-37.8,-37.7,0,40 -175.6,175.7,-37.7,-37.6,0,40 -175.6,175.7,-37.6,-37.5,0,40 -175.6,175.7,-37.5,-37.4,0,40 -175.6,175.7,-37.4,-37.3,0,40 -175.6,175.7,-37.3,-37.2,0,40 -175.6,175.7,-37.2,-37.1,0,40 -175.6,175.7,-37.1,-37,0,40 -175.6,175.7,-37,-36.9,0,40 -175.6,175.7,-36.9,-36.8,0,40 -175.6,175.7,-36.8,-36.7,0,40 -175.6,175.7,-36.7,-36.6,0,40 -175.6,175.7,-36.6,-36.5,0,40 -175.6,175.7,-36.5,-36.4,0,40 -175.6,175.7,-36.4,-36.3,0,40 -175.6,175.7,-36.3,-36.2,0,40 -175.6,175.7,-36.2,-36.1,0,40 -175.6,175.7,-36.1,-36,0,40 -175.6,175.7,-36,-35.9,0,40 -175.6,175.7,-35.9,-35.8,0,40 -175.6,175.7,-35.8,-35.7,0,40 -175.6,175.7,-35.7,-35.6,0,40 -175.7,175.8,-42,-41.9,0,40 -175.7,175.8,-41.9,-41.8,0,40 -175.7,175.8,-41.8,-41.7,0,40 -175.7,175.8,-41.7,-41.6,0,40 -175.7,175.8,-41.6,-41.5,0,40 -175.7,175.8,-41.5,-41.4,0,40 -175.7,175.8,-41.4,-41.3,0,40 -175.7,175.8,-41.3,-41.2,0,40 -175.7,175.8,-41.2,-41.1,0,40 -175.7,175.8,-41.1,-41,0,40 -175.7,175.8,-41,-40.9,0,40 -175.7,175.8,-40.9,-40.8,0,40 -175.7,175.8,-40.8,-40.7,0,40 -175.7,175.8,-40.7,-40.6,0,40 -175.7,175.8,-40.6,-40.5,0,40 -175.7,175.8,-40.5,-40.4,0,40 -175.7,175.8,-40.4,-40.3,0,40 -175.7,175.8,-40.3,-40.2,0,40 -175.7,175.8,-40.2,-40.1,0,40 -175.7,175.8,-40.1,-40,0,40 -175.7,175.8,-40,-39.9,0,40 -175.7,175.8,-39.9,-39.8,0,40 -175.7,175.8,-39.8,-39.7,0,40 -175.7,175.8,-39.7,-39.6,0,40 -175.7,175.8,-39.6,-39.5,0,40 -175.7,175.8,-39.5,-39.4,0,40 -175.7,175.8,-39.4,-39.3,0,40 -175.7,175.8,-39.3,-39.2,0,40 -175.7,175.8,-39.2,-39.1,0,40 -175.7,175.8,-39.1,-39,0,40 -175.7,175.8,-39,-38.9,0,40 -175.7,175.8,-38.9,-38.8,0,40 -175.7,175.8,-38.8,-38.7,0,40 -175.7,175.8,-38.7,-38.6,0,40 -175.7,175.8,-38.6,-38.5,0,40 -175.7,175.8,-38.5,-38.4,0,40 -175.7,175.8,-38.4,-38.3,0,40 -175.7,175.8,-38.3,-38.2,0,40 -175.7,175.8,-38.2,-38.1,0,40 -175.7,175.8,-38.1,-38,0,40 -175.7,175.8,-38,-37.9,0,40 -175.7,175.8,-37.9,-37.8,0,40 -175.7,175.8,-37.8,-37.7,0,40 -175.7,175.8,-37.7,-37.6,0,40 -175.7,175.8,-37.6,-37.5,0,40 -175.7,175.8,-37.5,-37.4,0,40 -175.7,175.8,-37.4,-37.3,0,40 -175.7,175.8,-37.3,-37.2,0,40 -175.7,175.8,-37.2,-37.1,0,40 -175.7,175.8,-37.1,-37,0,40 -175.7,175.8,-37,-36.9,0,40 -175.7,175.8,-36.9,-36.8,0,40 -175.7,175.8,-36.8,-36.7,0,40 -175.7,175.8,-36.7,-36.6,0,40 -175.7,175.8,-36.6,-36.5,0,40 -175.7,175.8,-36.5,-36.4,0,40 -175.7,175.8,-36.4,-36.3,0,40 -175.7,175.8,-36.3,-36.2,0,40 -175.7,175.8,-36.2,-36.1,0,40 -175.7,175.8,-36.1,-36,0,40 -175.7,175.8,-36,-35.9,0,40 -175.7,175.8,-35.9,-35.8,0,40 -175.7,175.8,-35.8,-35.7,0,40 -175.8,175.9,-41.9,-41.8,0,40 -175.8,175.9,-41.8,-41.7,0,40 -175.8,175.9,-41.7,-41.6,0,40 -175.8,175.9,-41.6,-41.5,0,40 -175.8,175.9,-41.5,-41.4,0,40 -175.8,175.9,-41.4,-41.3,0,40 -175.8,175.9,-41.3,-41.2,0,40 -175.8,175.9,-41.2,-41.1,0,40 -175.8,175.9,-41.1,-41,0,40 -175.8,175.9,-41,-40.9,0,40 -175.8,175.9,-40.9,-40.8,0,40 -175.8,175.9,-40.8,-40.7,0,40 -175.8,175.9,-40.7,-40.6,0,40 -175.8,175.9,-40.6,-40.5,0,40 -175.8,175.9,-40.5,-40.4,0,40 -175.8,175.9,-40.4,-40.3,0,40 -175.8,175.9,-40.3,-40.2,0,40 -175.8,175.9,-40.2,-40.1,0,40 -175.8,175.9,-40.1,-40,0,40 -175.8,175.9,-40,-39.9,0,40 -175.8,175.9,-39.9,-39.8,0,40 -175.8,175.9,-39.8,-39.7,0,40 -175.8,175.9,-39.7,-39.6,0,40 -175.8,175.9,-39.6,-39.5,0,40 -175.8,175.9,-39.5,-39.4,0,40 -175.8,175.9,-39.4,-39.3,0,40 -175.8,175.9,-39.3,-39.2,0,40 -175.8,175.9,-39.2,-39.1,0,40 -175.8,175.9,-39.1,-39,0,40 -175.8,175.9,-39,-38.9,0,40 -175.8,175.9,-38.9,-38.8,0,40 -175.8,175.9,-38.8,-38.7,0,40 -175.8,175.9,-38.7,-38.6,0,40 -175.8,175.9,-38.6,-38.5,0,40 -175.8,175.9,-38.5,-38.4,0,40 -175.8,175.9,-38.4,-38.3,0,40 -175.8,175.9,-38.3,-38.2,0,40 -175.8,175.9,-38.2,-38.1,0,40 -175.8,175.9,-38.1,-38,0,40 -175.8,175.9,-38,-37.9,0,40 -175.8,175.9,-37.9,-37.8,0,40 -175.8,175.9,-37.8,-37.7,0,40 -175.8,175.9,-37.7,-37.6,0,40 -175.8,175.9,-37.6,-37.5,0,40 -175.8,175.9,-37.5,-37.4,0,40 -175.8,175.9,-37.4,-37.3,0,40 -175.8,175.9,-37.3,-37.2,0,40 -175.8,175.9,-37.2,-37.1,0,40 -175.8,175.9,-37.1,-37,0,40 -175.8,175.9,-37,-36.9,0,40 -175.8,175.9,-36.9,-36.8,0,40 -175.8,175.9,-36.8,-36.7,0,40 -175.8,175.9,-36.7,-36.6,0,40 -175.8,175.9,-36.6,-36.5,0,40 -175.8,175.9,-36.5,-36.4,0,40 -175.8,175.9,-36.4,-36.3,0,40 -175.8,175.9,-36.3,-36.2,0,40 -175.8,175.9,-36.2,-36.1,0,40 -175.8,175.9,-36.1,-36,0,40 -175.8,175.9,-36,-35.9,0,40 -175.8,175.9,-35.9,-35.8,0,40 -175.9,176,-41.9,-41.8,0,40 -175.9,176,-41.8,-41.7,0,40 -175.9,176,-41.7,-41.6,0,40 -175.9,176,-41.6,-41.5,0,40 -175.9,176,-41.5,-41.4,0,40 -175.9,176,-41.4,-41.3,0,40 -175.9,176,-41.3,-41.2,0,40 -175.9,176,-41.2,-41.1,0,40 -175.9,176,-41.1,-41,0,40 -175.9,176,-41,-40.9,0,40 -175.9,176,-40.9,-40.8,0,40 -175.9,176,-40.8,-40.7,0,40 -175.9,176,-40.7,-40.6,0,40 -175.9,176,-40.6,-40.5,0,40 -175.9,176,-40.5,-40.4,0,40 -175.9,176,-40.4,-40.3,0,40 -175.9,176,-40.3,-40.2,0,40 -175.9,176,-40.2,-40.1,0,40 -175.9,176,-40.1,-40,0,40 -175.9,176,-40,-39.9,0,40 -175.9,176,-39.9,-39.8,0,40 -175.9,176,-39.8,-39.7,0,40 -175.9,176,-39.7,-39.6,0,40 -175.9,176,-39.6,-39.5,0,40 -175.9,176,-39.5,-39.4,0,40 -175.9,176,-39.4,-39.3,0,40 -175.9,176,-39.3,-39.2,0,40 -175.9,176,-39.2,-39.1,0,40 -175.9,176,-39.1,-39,0,40 -175.9,176,-39,-38.9,0,40 -175.9,176,-38.9,-38.8,0,40 -175.9,176,-38.8,-38.7,0,40 -175.9,176,-38.7,-38.6,0,40 -175.9,176,-38.6,-38.5,0,40 -175.9,176,-38.5,-38.4,0,40 -175.9,176,-38.4,-38.3,0,40 -175.9,176,-38.3,-38.2,0,40 -175.9,176,-38.2,-38.1,0,40 -175.9,176,-38.1,-38,0,40 -175.9,176,-38,-37.9,0,40 -175.9,176,-37.9,-37.8,0,40 -175.9,176,-37.8,-37.7,0,40 -175.9,176,-37.7,-37.6,0,40 -175.9,176,-37.6,-37.5,0,40 -175.9,176,-37.5,-37.4,0,40 -175.9,176,-37.4,-37.3,0,40 -175.9,176,-37.3,-37.2,0,40 -175.9,176,-37.2,-37.1,0,40 -175.9,176,-37.1,-37,0,40 -175.9,176,-37,-36.9,0,40 -175.9,176,-36.9,-36.8,0,40 -175.9,176,-36.8,-36.7,0,40 -175.9,176,-36.7,-36.6,0,40 -175.9,176,-36.6,-36.5,0,40 -175.9,176,-36.5,-36.4,0,40 -175.9,176,-36.4,-36.3,0,40 -175.9,176,-36.3,-36.2,0,40 -175.9,176,-36.2,-36.1,0,40 -175.9,176,-36.1,-36,0,40 -175.9,176,-36,-35.9,0,40 -176,176.1,-41.8,-41.7,0,40 -176,176.1,-41.7,-41.6,0,40 -176,176.1,-41.6,-41.5,0,40 -176,176.1,-41.5,-41.4,0,40 -176,176.1,-41.4,-41.3,0,40 -176,176.1,-41.3,-41.2,0,40 -176,176.1,-41.2,-41.1,0,40 -176,176.1,-41.1,-41,0,40 -176,176.1,-41,-40.9,0,40 -176,176.1,-40.9,-40.8,0,40 -176,176.1,-40.8,-40.7,0,40 -176,176.1,-40.7,-40.6,0,40 -176,176.1,-40.6,-40.5,0,40 -176,176.1,-40.5,-40.4,0,40 -176,176.1,-40.4,-40.3,0,40 -176,176.1,-40.3,-40.2,0,40 -176,176.1,-40.2,-40.1,0,40 -176,176.1,-40.1,-40,0,40 -176,176.1,-40,-39.9,0,40 -176,176.1,-39.9,-39.8,0,40 -176,176.1,-39.8,-39.7,0,40 -176,176.1,-39.7,-39.6,0,40 -176,176.1,-39.6,-39.5,0,40 -176,176.1,-39.5,-39.4,0,40 -176,176.1,-39.4,-39.3,0,40 -176,176.1,-39.3,-39.2,0,40 -176,176.1,-39.2,-39.1,0,40 -176,176.1,-39.1,-39,0,40 -176,176.1,-39,-38.9,0,40 -176,176.1,-38.9,-38.8,0,40 -176,176.1,-38.8,-38.7,0,40 -176,176.1,-38.7,-38.6,0,40 -176,176.1,-38.6,-38.5,0,40 -176,176.1,-38.5,-38.4,0,40 -176,176.1,-38.4,-38.3,0,40 -176,176.1,-38.3,-38.2,0,40 -176,176.1,-38.2,-38.1,0,40 -176,176.1,-38.1,-38,0,40 -176,176.1,-38,-37.9,0,40 -176,176.1,-37.9,-37.8,0,40 -176,176.1,-37.8,-37.7,0,40 -176,176.1,-37.7,-37.6,0,40 -176,176.1,-37.6,-37.5,0,40 -176,176.1,-37.5,-37.4,0,40 -176,176.1,-37.4,-37.3,0,40 -176,176.1,-37.3,-37.2,0,40 -176,176.1,-37.2,-37.1,0,40 -176,176.1,-37.1,-37,0,40 -176,176.1,-37,-36.9,0,40 -176,176.1,-36.9,-36.8,0,40 -176,176.1,-36.8,-36.7,0,40 -176,176.1,-36.7,-36.6,0,40 -176,176.1,-36.6,-36.5,0,40 -176,176.1,-36.5,-36.4,0,40 -176,176.1,-36.4,-36.3,0,40 -176,176.1,-36.3,-36.2,0,40 -176,176.1,-36.2,-36.1,0,40 -176,176.1,-36.1,-36,0,40 -176.1,176.2,-41.8,-41.7,0,40 -176.1,176.2,-41.7,-41.6,0,40 -176.1,176.2,-41.6,-41.5,0,40 -176.1,176.2,-41.5,-41.4,0,40 -176.1,176.2,-41.4,-41.3,0,40 -176.1,176.2,-41.3,-41.2,0,40 -176.1,176.2,-41.2,-41.1,0,40 -176.1,176.2,-41.1,-41,0,40 -176.1,176.2,-41,-40.9,0,40 -176.1,176.2,-40.9,-40.8,0,40 -176.1,176.2,-40.8,-40.7,0,40 -176.1,176.2,-40.7,-40.6,0,40 -176.1,176.2,-40.6,-40.5,0,40 -176.1,176.2,-40.5,-40.4,0,40 -176.1,176.2,-40.4,-40.3,0,40 -176.1,176.2,-40.3,-40.2,0,40 -176.1,176.2,-40.2,-40.1,0,40 -176.1,176.2,-40.1,-40,0,40 -176.1,176.2,-40,-39.9,0,40 -176.1,176.2,-39.9,-39.8,0,40 -176.1,176.2,-39.8,-39.7,0,40 -176.1,176.2,-39.7,-39.6,0,40 -176.1,176.2,-39.6,-39.5,0,40 -176.1,176.2,-39.5,-39.4,0,40 -176.1,176.2,-39.4,-39.3,0,40 -176.1,176.2,-39.3,-39.2,0,40 -176.1,176.2,-39.2,-39.1,0,40 -176.1,176.2,-39.1,-39,0,40 -176.1,176.2,-39,-38.9,0,40 -176.1,176.2,-38.9,-38.8,0,40 -176.1,176.2,-38.8,-38.7,0,40 -176.1,176.2,-38.7,-38.6,0,40 -176.1,176.2,-38.6,-38.5,0,40 -176.1,176.2,-38.5,-38.4,0,40 -176.1,176.2,-38.4,-38.3,0,40 -176.1,176.2,-38.3,-38.2,0,40 -176.1,176.2,-38.2,-38.1,0,40 -176.1,176.2,-38.1,-38,0,40 -176.1,176.2,-38,-37.9,0,40 -176.1,176.2,-37.9,-37.8,0,40 -176.1,176.2,-37.8,-37.7,0,40 -176.1,176.2,-37.7,-37.6,0,40 -176.1,176.2,-37.6,-37.5,0,40 -176.1,176.2,-37.5,-37.4,0,40 -176.1,176.2,-37.4,-37.3,0,40 -176.1,176.2,-37.3,-37.2,0,40 -176.1,176.2,-37.2,-37.1,0,40 -176.1,176.2,-37.1,-37,0,40 -176.1,176.2,-37,-36.9,0,40 -176.1,176.2,-36.9,-36.8,0,40 -176.1,176.2,-36.8,-36.7,0,40 -176.1,176.2,-36.7,-36.6,0,40 -176.1,176.2,-36.6,-36.5,0,40 -176.1,176.2,-36.5,-36.4,0,40 -176.1,176.2,-36.4,-36.3,0,40 -176.1,176.2,-36.3,-36.2,0,40 -176.2,176.3,-41.7,-41.6,0,40 -176.2,176.3,-41.6,-41.5,0,40 -176.2,176.3,-41.5,-41.4,0,40 -176.2,176.3,-41.4,-41.3,0,40 -176.2,176.3,-41.3,-41.2,0,40 -176.2,176.3,-41.2,-41.1,0,40 -176.2,176.3,-41.1,-41,0,40 -176.2,176.3,-41,-40.9,0,40 -176.2,176.3,-40.9,-40.8,0,40 -176.2,176.3,-40.8,-40.7,0,40 -176.2,176.3,-40.7,-40.6,0,40 -176.2,176.3,-40.6,-40.5,0,40 -176.2,176.3,-40.5,-40.4,0,40 -176.2,176.3,-40.4,-40.3,0,40 -176.2,176.3,-40.3,-40.2,0,40 -176.2,176.3,-40.2,-40.1,0,40 -176.2,176.3,-40.1,-40,0,40 -176.2,176.3,-40,-39.9,0,40 -176.2,176.3,-39.9,-39.8,0,40 -176.2,176.3,-39.8,-39.7,0,40 -176.2,176.3,-39.7,-39.6,0,40 -176.2,176.3,-39.6,-39.5,0,40 -176.2,176.3,-39.5,-39.4,0,40 -176.2,176.3,-39.4,-39.3,0,40 -176.2,176.3,-39.3,-39.2,0,40 -176.2,176.3,-39.2,-39.1,0,40 -176.2,176.3,-39.1,-39,0,40 -176.2,176.3,-39,-38.9,0,40 -176.2,176.3,-38.9,-38.8,0,40 -176.2,176.3,-38.8,-38.7,0,40 -176.2,176.3,-38.7,-38.6,0,40 -176.2,176.3,-38.6,-38.5,0,40 -176.2,176.3,-38.5,-38.4,0,40 -176.2,176.3,-38.4,-38.3,0,40 -176.2,176.3,-38.3,-38.2,0,40 -176.2,176.3,-38.2,-38.1,0,40 -176.2,176.3,-38.1,-38,0,40 -176.2,176.3,-38,-37.9,0,40 -176.2,176.3,-37.9,-37.8,0,40 -176.2,176.3,-37.8,-37.7,0,40 -176.2,176.3,-37.7,-37.6,0,40 -176.2,176.3,-37.6,-37.5,0,40 -176.2,176.3,-37.5,-37.4,0,40 -176.2,176.3,-37.4,-37.3,0,40 -176.2,176.3,-37.3,-37.2,0,40 -176.2,176.3,-37.2,-37.1,0,40 -176.2,176.3,-37.1,-37,0,40 -176.2,176.3,-37,-36.9,0,40 -176.2,176.3,-36.9,-36.8,0,40 -176.2,176.3,-36.8,-36.7,0,40 -176.2,176.3,-36.7,-36.6,0,40 -176.2,176.3,-36.6,-36.5,0,40 -176.2,176.3,-36.5,-36.4,0,40 -176.2,176.3,-36.4,-36.3,0,40 -176.3,176.4,-41.6,-41.5,0,40 -176.3,176.4,-41.5,-41.4,0,40 -176.3,176.4,-41.4,-41.3,0,40 -176.3,176.4,-41.3,-41.2,0,40 -176.3,176.4,-41.2,-41.1,0,40 -176.3,176.4,-41.1,-41,0,40 -176.3,176.4,-41,-40.9,0,40 -176.3,176.4,-40.9,-40.8,0,40 -176.3,176.4,-40.8,-40.7,0,40 -176.3,176.4,-40.7,-40.6,0,40 -176.3,176.4,-40.6,-40.5,0,40 -176.3,176.4,-40.5,-40.4,0,40 -176.3,176.4,-40.4,-40.3,0,40 -176.3,176.4,-40.3,-40.2,0,40 -176.3,176.4,-40.2,-40.1,0,40 -176.3,176.4,-40.1,-40,0,40 -176.3,176.4,-40,-39.9,0,40 -176.3,176.4,-39.9,-39.8,0,40 -176.3,176.4,-39.8,-39.7,0,40 -176.3,176.4,-39.7,-39.6,0,40 -176.3,176.4,-39.6,-39.5,0,40 -176.3,176.4,-39.5,-39.4,0,40 -176.3,176.4,-39.4,-39.3,0,40 -176.3,176.4,-39.3,-39.2,0,40 -176.3,176.4,-39.2,-39.1,0,40 -176.3,176.4,-39.1,-39,0,40 -176.3,176.4,-39,-38.9,0,40 -176.3,176.4,-38.9,-38.8,0,40 -176.3,176.4,-38.8,-38.7,0,40 -176.3,176.4,-38.7,-38.6,0,40 -176.3,176.4,-38.6,-38.5,0,40 -176.3,176.4,-38.5,-38.4,0,40 -176.3,176.4,-38.4,-38.3,0,40 -176.3,176.4,-38.3,-38.2,0,40 -176.3,176.4,-38.2,-38.1,0,40 -176.3,176.4,-38.1,-38,0,40 -176.3,176.4,-38,-37.9,0,40 -176.3,176.4,-37.9,-37.8,0,40 -176.3,176.4,-37.8,-37.7,0,40 -176.3,176.4,-37.7,-37.6,0,40 -176.3,176.4,-37.6,-37.5,0,40 -176.3,176.4,-37.5,-37.4,0,40 -176.3,176.4,-37.4,-37.3,0,40 -176.3,176.4,-37.3,-37.2,0,40 -176.3,176.4,-37.2,-37.1,0,40 -176.3,176.4,-37.1,-37,0,40 -176.3,176.4,-37,-36.9,0,40 -176.3,176.4,-36.9,-36.8,0,40 -176.3,176.4,-36.8,-36.7,0,40 -176.3,176.4,-36.7,-36.6,0,40 -176.3,176.4,-36.6,-36.5,0,40 -176.4,176.5,-41.6,-41.5,0,40 -176.4,176.5,-41.5,-41.4,0,40 -176.4,176.5,-41.4,-41.3,0,40 -176.4,176.5,-41.3,-41.2,0,40 -176.4,176.5,-41.2,-41.1,0,40 -176.4,176.5,-41.1,-41,0,40 -176.4,176.5,-41,-40.9,0,40 -176.4,176.5,-40.9,-40.8,0,40 -176.4,176.5,-40.8,-40.7,0,40 -176.4,176.5,-40.7,-40.6,0,40 -176.4,176.5,-40.6,-40.5,0,40 -176.4,176.5,-40.5,-40.4,0,40 -176.4,176.5,-40.4,-40.3,0,40 -176.4,176.5,-40.3,-40.2,0,40 -176.4,176.5,-40.2,-40.1,0,40 -176.4,176.5,-40.1,-40,0,40 -176.4,176.5,-40,-39.9,0,40 -176.4,176.5,-39.9,-39.8,0,40 -176.4,176.5,-39.8,-39.7,0,40 -176.4,176.5,-39.7,-39.6,0,40 -176.4,176.5,-39.6,-39.5,0,40 -176.4,176.5,-39.5,-39.4,0,40 -176.4,176.5,-39.4,-39.3,0,40 -176.4,176.5,-39.3,-39.2,0,40 -176.4,176.5,-39.2,-39.1,0,40 -176.4,176.5,-39.1,-39,0,40 -176.4,176.5,-39,-38.9,0,40 -176.4,176.5,-38.9,-38.8,0,40 -176.4,176.5,-38.8,-38.7,0,40 -176.4,176.5,-38.7,-38.6,0,40 -176.4,176.5,-38.6,-38.5,0,40 -176.4,176.5,-38.5,-38.4,0,40 -176.4,176.5,-38.4,-38.3,0,40 -176.4,176.5,-38.3,-38.2,0,40 -176.4,176.5,-38.2,-38.1,0,40 -176.4,176.5,-38.1,-38,0,40 -176.4,176.5,-38,-37.9,0,40 -176.4,176.5,-37.9,-37.8,0,40 -176.4,176.5,-37.8,-37.7,0,40 -176.4,176.5,-37.7,-37.6,0,40 -176.4,176.5,-37.6,-37.5,0,40 -176.4,176.5,-37.5,-37.4,0,40 -176.4,176.5,-37.4,-37.3,0,40 -176.4,176.5,-37.3,-37.2,0,40 -176.4,176.5,-37.2,-37.1,0,40 -176.4,176.5,-37.1,-37,0,40 -176.4,176.5,-37,-36.9,0,40 -176.5,176.6,-41.5,-41.4,0,40 -176.5,176.6,-41.4,-41.3,0,40 -176.5,176.6,-41.3,-41.2,0,40 -176.5,176.6,-41.2,-41.1,0,40 -176.5,176.6,-41.1,-41,0,40 -176.5,176.6,-41,-40.9,0,40 -176.5,176.6,-40.9,-40.8,0,40 -176.5,176.6,-40.8,-40.7,0,40 -176.5,176.6,-40.7,-40.6,0,40 -176.5,176.6,-40.6,-40.5,0,40 -176.5,176.6,-40.5,-40.4,0,40 -176.5,176.6,-40.4,-40.3,0,40 -176.5,176.6,-40.3,-40.2,0,40 -176.5,176.6,-40.2,-40.1,0,40 -176.5,176.6,-40.1,-40,0,40 -176.5,176.6,-40,-39.9,0,40 -176.5,176.6,-39.9,-39.8,0,40 -176.5,176.6,-39.8,-39.7,0,40 -176.5,176.6,-39.7,-39.6,0,40 -176.5,176.6,-39.6,-39.5,0,40 -176.5,176.6,-39.5,-39.4,0,40 -176.5,176.6,-39.4,-39.3,0,40 -176.5,176.6,-39.3,-39.2,0,40 -176.5,176.6,-39.2,-39.1,0,40 -176.5,176.6,-39.1,-39,0,40 -176.5,176.6,-39,-38.9,0,40 -176.5,176.6,-38.9,-38.8,0,40 -176.5,176.6,-38.8,-38.7,0,40 -176.5,176.6,-38.7,-38.6,0,40 -176.5,176.6,-38.6,-38.5,0,40 -176.5,176.6,-38.5,-38.4,0,40 -176.5,176.6,-38.4,-38.3,0,40 -176.5,176.6,-38.3,-38.2,0,40 -176.5,176.6,-38.2,-38.1,0,40 -176.5,176.6,-38.1,-38,0,40 -176.5,176.6,-38,-37.9,0,40 -176.5,176.6,-37.9,-37.8,0,40 -176.5,176.6,-37.8,-37.7,0,40 -176.5,176.6,-37.7,-37.6,0,40 -176.5,176.6,-37.6,-37.5,0,40 -176.5,176.6,-37.5,-37.4,0,40 -176.5,176.6,-37.4,-37.3,0,40 -176.5,176.6,-37.3,-37.2,0,40 -176.6,176.7,-41.4,-41.3,0,40 -176.6,176.7,-41.3,-41.2,0,40 -176.6,176.7,-41.2,-41.1,0,40 -176.6,176.7,-41.1,-41,0,40 -176.6,176.7,-41,-40.9,0,40 -176.6,176.7,-40.9,-40.8,0,40 -176.6,176.7,-40.8,-40.7,0,40 -176.6,176.7,-40.7,-40.6,0,40 -176.6,176.7,-40.6,-40.5,0,40 -176.6,176.7,-40.5,-40.4,0,40 -176.6,176.7,-40.4,-40.3,0,40 -176.6,176.7,-40.3,-40.2,0,40 -176.6,176.7,-40.2,-40.1,0,40 -176.6,176.7,-40.1,-40,0,40 -176.6,176.7,-40,-39.9,0,40 -176.6,176.7,-39.9,-39.8,0,40 -176.6,176.7,-39.8,-39.7,0,40 -176.6,176.7,-39.7,-39.6,0,40 -176.6,176.7,-39.6,-39.5,0,40 -176.6,176.7,-39.5,-39.4,0,40 -176.6,176.7,-39.4,-39.3,0,40 -176.6,176.7,-39.3,-39.2,0,40 -176.6,176.7,-39.2,-39.1,0,40 -176.6,176.7,-39.1,-39,0,40 -176.6,176.7,-39,-38.9,0,40 -176.6,176.7,-38.9,-38.8,0,40 -176.6,176.7,-38.8,-38.7,0,40 -176.6,176.7,-38.7,-38.6,0,40 -176.6,176.7,-38.6,-38.5,0,40 -176.6,176.7,-38.5,-38.4,0,40 -176.6,176.7,-38.4,-38.3,0,40 -176.6,176.7,-38.3,-38.2,0,40 -176.6,176.7,-38.2,-38.1,0,40 -176.6,176.7,-38.1,-38,0,40 -176.6,176.7,-38,-37.9,0,40 -176.6,176.7,-37.9,-37.8,0,40 -176.6,176.7,-37.8,-37.7,0,40 -176.6,176.7,-37.7,-37.6,0,40 -176.6,176.7,-37.6,-37.5,0,40 -176.6,176.7,-37.5,-37.4,0,40 -176.6,176.7,-37.4,-37.3,0,40 -176.7,176.8,-41.3,-41.2,0,40 -176.7,176.8,-41.2,-41.1,0,40 -176.7,176.8,-41.1,-41,0,40 -176.7,176.8,-41,-40.9,0,40 -176.7,176.8,-40.9,-40.8,0,40 -176.7,176.8,-40.8,-40.7,0,40 -176.7,176.8,-40.7,-40.6,0,40 -176.7,176.8,-40.6,-40.5,0,40 -176.7,176.8,-40.5,-40.4,0,40 -176.7,176.8,-40.4,-40.3,0,40 -176.7,176.8,-40.3,-40.2,0,40 -176.7,176.8,-40.2,-40.1,0,40 -176.7,176.8,-40.1,-40,0,40 -176.7,176.8,-40,-39.9,0,40 -176.7,176.8,-39.9,-39.8,0,40 -176.7,176.8,-39.8,-39.7,0,40 -176.7,176.8,-39.7,-39.6,0,40 -176.7,176.8,-39.6,-39.5,0,40 -176.7,176.8,-39.5,-39.4,0,40 -176.7,176.8,-39.4,-39.3,0,40 -176.7,176.8,-39.3,-39.2,0,40 -176.7,176.8,-39.2,-39.1,0,40 -176.7,176.8,-39.1,-39,0,40 -176.7,176.8,-39,-38.9,0,40 -176.7,176.8,-38.9,-38.8,0,40 -176.7,176.8,-38.8,-38.7,0,40 -176.7,176.8,-38.7,-38.6,0,40 -176.7,176.8,-38.6,-38.5,0,40 -176.7,176.8,-38.5,-38.4,0,40 -176.7,176.8,-38.4,-38.3,0,40 -176.7,176.8,-38.3,-38.2,0,40 -176.7,176.8,-38.2,-38.1,0,40 -176.7,176.8,-38.1,-38,0,40 -176.7,176.8,-38,-37.9,0,40 -176.7,176.8,-37.9,-37.8,0,40 -176.7,176.8,-37.8,-37.7,0,40 -176.7,176.8,-37.7,-37.6,0,40 -176.7,176.8,-37.6,-37.5,0,40 -176.7,176.8,-37.5,-37.4,0,40 -176.7,176.8,-37.4,-37.3,0,40 -176.8,176.9,-41.2,-41.1,0,40 -176.8,176.9,-41.1,-41,0,40 -176.8,176.9,-41,-40.9,0,40 -176.8,176.9,-40.9,-40.8,0,40 -176.8,176.9,-40.8,-40.7,0,40 -176.8,176.9,-40.7,-40.6,0,40 -176.8,176.9,-40.6,-40.5,0,40 -176.8,176.9,-40.5,-40.4,0,40 -176.8,176.9,-40.4,-40.3,0,40 -176.8,176.9,-40.3,-40.2,0,40 -176.8,176.9,-40.2,-40.1,0,40 -176.8,176.9,-40.1,-40,0,40 -176.8,176.9,-40,-39.9,0,40 -176.8,176.9,-39.9,-39.8,0,40 -176.8,176.9,-39.8,-39.7,0,40 -176.8,176.9,-39.7,-39.6,0,40 -176.8,176.9,-39.6,-39.5,0,40 -176.8,176.9,-39.5,-39.4,0,40 -176.8,176.9,-39.4,-39.3,0,40 -176.8,176.9,-39.3,-39.2,0,40 -176.8,176.9,-39.2,-39.1,0,40 -176.8,176.9,-39.1,-39,0,40 -176.8,176.9,-39,-38.9,0,40 -176.8,176.9,-38.9,-38.8,0,40 -176.8,176.9,-38.8,-38.7,0,40 -176.8,176.9,-38.7,-38.6,0,40 -176.8,176.9,-38.6,-38.5,0,40 -176.8,176.9,-38.5,-38.4,0,40 -176.8,176.9,-38.4,-38.3,0,40 -176.8,176.9,-38.3,-38.2,0,40 -176.8,176.9,-38.2,-38.1,0,40 -176.8,176.9,-38.1,-38,0,40 -176.8,176.9,-38,-37.9,0,40 -176.8,176.9,-37.9,-37.8,0,40 -176.8,176.9,-37.8,-37.7,0,40 -176.8,176.9,-37.7,-37.6,0,40 -176.8,176.9,-37.6,-37.5,0,40 -176.8,176.9,-37.5,-37.4,0,40 -176.8,176.9,-37.4,-37.3,0,40 -176.9,177,-41,-40.9,0,40 -176.9,177,-40.9,-40.8,0,40 -176.9,177,-40.8,-40.7,0,40 -176.9,177,-40.7,-40.6,0,40 -176.9,177,-40.6,-40.5,0,40 -176.9,177,-40.5,-40.4,0,40 -176.9,177,-40.4,-40.3,0,40 -176.9,177,-40.3,-40.2,0,40 -176.9,177,-40.2,-40.1,0,40 -176.9,177,-40.1,-40,0,40 -176.9,177,-40,-39.9,0,40 -176.9,177,-39.9,-39.8,0,40 -176.9,177,-39.8,-39.7,0,40 -176.9,177,-39.7,-39.6,0,40 -176.9,177,-39.6,-39.5,0,40 -176.9,177,-39.5,-39.4,0,40 -176.9,177,-39.4,-39.3,0,40 -176.9,177,-39.3,-39.2,0,40 -176.9,177,-39.2,-39.1,0,40 -176.9,177,-39.1,-39,0,40 -176.9,177,-39,-38.9,0,40 -176.9,177,-38.9,-38.8,0,40 -176.9,177,-38.8,-38.7,0,40 -176.9,177,-38.7,-38.6,0,40 -176.9,177,-38.6,-38.5,0,40 -176.9,177,-38.5,-38.4,0,40 -176.9,177,-38.4,-38.3,0,40 -176.9,177,-38.3,-38.2,0,40 -176.9,177,-38.2,-38.1,0,40 -176.9,177,-38.1,-38,0,40 -176.9,177,-38,-37.9,0,40 -176.9,177,-37.9,-37.8,0,40 -176.9,177,-37.8,-37.7,0,40 -176.9,177,-37.7,-37.6,0,40 -176.9,177,-37.6,-37.5,0,40 -176.9,177,-37.5,-37.4,0,40 -177,177.1,-40.9,-40.8,0,40 -177,177.1,-40.8,-40.7,0,40 -177,177.1,-40.7,-40.6,0,40 -177,177.1,-40.6,-40.5,0,40 -177,177.1,-40.5,-40.4,0,40 -177,177.1,-40.4,-40.3,0,40 -177,177.1,-40.3,-40.2,0,40 -177,177.1,-40.2,-40.1,0,40 -177,177.1,-40.1,-40,0,40 -177,177.1,-40,-39.9,0,40 -177,177.1,-39.9,-39.8,0,40 -177,177.1,-39.8,-39.7,0,40 -177,177.1,-39.7,-39.6,0,40 -177,177.1,-39.6,-39.5,0,40 -177,177.1,-39.5,-39.4,0,40 -177,177.1,-39.4,-39.3,0,40 -177,177.1,-39.3,-39.2,0,40 -177,177.1,-39.2,-39.1,0,40 -177,177.1,-39.1,-39,0,40 -177,177.1,-39,-38.9,0,40 -177,177.1,-38.9,-38.8,0,40 -177,177.1,-38.8,-38.7,0,40 -177,177.1,-38.7,-38.6,0,40 -177,177.1,-38.6,-38.5,0,40 -177,177.1,-38.5,-38.4,0,40 -177,177.1,-38.4,-38.3,0,40 -177,177.1,-38.3,-38.2,0,40 -177,177.1,-38.2,-38.1,0,40 -177,177.1,-38.1,-38,0,40 -177,177.1,-38,-37.9,0,40 -177,177.1,-37.9,-37.8,0,40 -177,177.1,-37.8,-37.7,0,40 -177,177.1,-37.7,-37.6,0,40 -177,177.1,-37.6,-37.5,0,40 -177,177.1,-37.5,-37.4,0,40 -177.1,177.2,-40.7,-40.6,0,40 -177.1,177.2,-40.6,-40.5,0,40 -177.1,177.2,-40.5,-40.4,0,40 -177.1,177.2,-40.4,-40.3,0,40 -177.1,177.2,-40.3,-40.2,0,40 -177.1,177.2,-40.2,-40.1,0,40 -177.1,177.2,-40.1,-40,0,40 -177.1,177.2,-40,-39.9,0,40 -177.1,177.2,-39.9,-39.8,0,40 -177.1,177.2,-39.8,-39.7,0,40 -177.1,177.2,-39.7,-39.6,0,40 -177.1,177.2,-39.6,-39.5,0,40 -177.1,177.2,-39.5,-39.4,0,40 -177.1,177.2,-39.4,-39.3,0,40 -177.1,177.2,-39.3,-39.2,0,40 -177.1,177.2,-39.2,-39.1,0,40 -177.1,177.2,-39.1,-39,0,40 -177.1,177.2,-39,-38.9,0,40 -177.1,177.2,-38.9,-38.8,0,40 -177.1,177.2,-38.8,-38.7,0,40 -177.1,177.2,-38.7,-38.6,0,40 -177.1,177.2,-38.6,-38.5,0,40 -177.1,177.2,-38.5,-38.4,0,40 -177.1,177.2,-38.4,-38.3,0,40 -177.1,177.2,-38.3,-38.2,0,40 -177.1,177.2,-38.2,-38.1,0,40 -177.1,177.2,-38.1,-38,0,40 -177.1,177.2,-38,-37.9,0,40 -177.1,177.2,-37.9,-37.8,0,40 -177.1,177.2,-37.8,-37.7,0,40 -177.1,177.2,-37.7,-37.6,0,40 -177.1,177.2,-37.6,-37.5,0,40 -177.1,177.2,-37.5,-37.4,0,40 -177.2,177.3,-40.6,-40.5,0,40 -177.2,177.3,-40.5,-40.4,0,40 -177.2,177.3,-40.4,-40.3,0,40 -177.2,177.3,-40.3,-40.2,0,40 -177.2,177.3,-40.2,-40.1,0,40 -177.2,177.3,-40.1,-40,0,40 -177.2,177.3,-40,-39.9,0,40 -177.2,177.3,-39.9,-39.8,0,40 -177.2,177.3,-39.8,-39.7,0,40 -177.2,177.3,-39.7,-39.6,0,40 -177.2,177.3,-39.6,-39.5,0,40 -177.2,177.3,-39.5,-39.4,0,40 -177.2,177.3,-39.4,-39.3,0,40 -177.2,177.3,-39.3,-39.2,0,40 -177.2,177.3,-39.2,-39.1,0,40 -177.2,177.3,-39.1,-39,0,40 -177.2,177.3,-39,-38.9,0,40 -177.2,177.3,-38.9,-38.8,0,40 -177.2,177.3,-38.8,-38.7,0,40 -177.2,177.3,-38.7,-38.6,0,40 -177.2,177.3,-38.6,-38.5,0,40 -177.2,177.3,-38.5,-38.4,0,40 -177.2,177.3,-38.4,-38.3,0,40 -177.2,177.3,-38.3,-38.2,0,40 -177.2,177.3,-38.2,-38.1,0,40 -177.2,177.3,-38.1,-38,0,40 -177.2,177.3,-38,-37.9,0,40 -177.2,177.3,-37.9,-37.8,0,40 -177.2,177.3,-37.8,-37.7,0,40 -177.2,177.3,-37.7,-37.6,0,40 -177.2,177.3,-37.6,-37.5,0,40 -177.2,177.3,-37.5,-37.4,0,40 -177.2,177.3,-37.4,-37.3,0,40 -177.3,177.4,-40.4,-40.3,0,40 -177.3,177.4,-40.3,-40.2,0,40 -177.3,177.4,-40.2,-40.1,0,40 -177.3,177.4,-40.1,-40,0,40 -177.3,177.4,-40,-39.9,0,40 -177.3,177.4,-39.9,-39.8,0,40 -177.3,177.4,-39.8,-39.7,0,40 -177.3,177.4,-39.7,-39.6,0,40 -177.3,177.4,-39.6,-39.5,0,40 -177.3,177.4,-39.5,-39.4,0,40 -177.3,177.4,-39.4,-39.3,0,40 -177.3,177.4,-39.3,-39.2,0,40 -177.3,177.4,-39.2,-39.1,0,40 -177.3,177.4,-39.1,-39,0,40 -177.3,177.4,-39,-38.9,0,40 -177.3,177.4,-38.9,-38.8,0,40 -177.3,177.4,-38.8,-38.7,0,40 -177.3,177.4,-38.7,-38.6,0,40 -177.3,177.4,-38.6,-38.5,0,40 -177.3,177.4,-38.5,-38.4,0,40 -177.3,177.4,-38.4,-38.3,0,40 -177.3,177.4,-38.3,-38.2,0,40 -177.3,177.4,-38.2,-38.1,0,40 -177.3,177.4,-38.1,-38,0,40 -177.3,177.4,-38,-37.9,0,40 -177.3,177.4,-37.9,-37.8,0,40 -177.3,177.4,-37.8,-37.7,0,40 -177.3,177.4,-37.7,-37.6,0,40 -177.3,177.4,-37.6,-37.5,0,40 -177.3,177.4,-37.5,-37.4,0,40 -177.3,177.4,-37.4,-37.3,0,40 -177.4,177.5,-40.3,-40.2,0,40 -177.4,177.5,-40.2,-40.1,0,40 -177.4,177.5,-40.1,-40,0,40 -177.4,177.5,-40,-39.9,0,40 -177.4,177.5,-39.9,-39.8,0,40 -177.4,177.5,-39.8,-39.7,0,40 -177.4,177.5,-39.7,-39.6,0,40 -177.4,177.5,-39.6,-39.5,0,40 -177.4,177.5,-39.5,-39.4,0,40 -177.4,177.5,-39.4,-39.3,0,40 -177.4,177.5,-39.3,-39.2,0,40 -177.4,177.5,-39.2,-39.1,0,40 -177.4,177.5,-39.1,-39,0,40 -177.4,177.5,-39,-38.9,0,40 -177.4,177.5,-38.9,-38.8,0,40 -177.4,177.5,-38.8,-38.7,0,40 -177.4,177.5,-38.7,-38.6,0,40 -177.4,177.5,-38.6,-38.5,0,40 -177.4,177.5,-38.5,-38.4,0,40 -177.4,177.5,-38.4,-38.3,0,40 -177.4,177.5,-38.3,-38.2,0,40 -177.4,177.5,-38.2,-38.1,0,40 -177.4,177.5,-38.1,-38,0,40 -177.4,177.5,-38,-37.9,0,40 -177.4,177.5,-37.9,-37.8,0,40 -177.4,177.5,-37.8,-37.7,0,40 -177.4,177.5,-37.7,-37.6,0,40 -177.4,177.5,-37.6,-37.5,0,40 -177.4,177.5,-37.5,-37.4,0,40 -177.4,177.5,-37.4,-37.3,0,40 -177.5,177.6,-40.1,-40,0,40 -177.5,177.6,-40,-39.9,0,40 -177.5,177.6,-39.9,-39.8,0,40 -177.5,177.6,-39.8,-39.7,0,40 -177.5,177.6,-39.7,-39.6,0,40 -177.5,177.6,-39.6,-39.5,0,40 -177.5,177.6,-39.5,-39.4,0,40 -177.5,177.6,-39.4,-39.3,0,40 -177.5,177.6,-39.3,-39.2,0,40 -177.5,177.6,-39.2,-39.1,0,40 -177.5,177.6,-39.1,-39,0,40 -177.5,177.6,-39,-38.9,0,40 -177.5,177.6,-38.9,-38.8,0,40 -177.5,177.6,-38.8,-38.7,0,40 -177.5,177.6,-38.7,-38.6,0,40 -177.5,177.6,-38.6,-38.5,0,40 -177.5,177.6,-38.5,-38.4,0,40 -177.5,177.6,-38.4,-38.3,0,40 -177.5,177.6,-38.3,-38.2,0,40 -177.5,177.6,-38.2,-38.1,0,40 -177.5,177.6,-38.1,-38,0,40 -177.5,177.6,-38,-37.9,0,40 -177.5,177.6,-37.9,-37.8,0,40 -177.5,177.6,-37.8,-37.7,0,40 -177.5,177.6,-37.7,-37.6,0,40 -177.5,177.6,-37.6,-37.5,0,40 -177.5,177.6,-37.5,-37.4,0,40 -177.5,177.6,-37.4,-37.3,0,40 -177.5,177.6,-37.3,-37.2,0,40 -177.6,177.7,-40,-39.9,0,40 -177.6,177.7,-39.9,-39.8,0,40 -177.6,177.7,-39.8,-39.7,0,40 -177.6,177.7,-39.7,-39.6,0,40 -177.6,177.7,-39.6,-39.5,0,40 -177.6,177.7,-39.5,-39.4,0,40 -177.6,177.7,-39.4,-39.3,0,40 -177.6,177.7,-39.3,-39.2,0,40 -177.6,177.7,-39.2,-39.1,0,40 -177.6,177.7,-39.1,-39,0,40 -177.6,177.7,-39,-38.9,0,40 -177.6,177.7,-38.9,-38.8,0,40 -177.6,177.7,-38.8,-38.7,0,40 -177.6,177.7,-38.7,-38.6,0,40 -177.6,177.7,-38.6,-38.5,0,40 -177.6,177.7,-38.5,-38.4,0,40 -177.6,177.7,-38.4,-38.3,0,40 -177.6,177.7,-38.3,-38.2,0,40 -177.6,177.7,-38.2,-38.1,0,40 -177.6,177.7,-38.1,-38,0,40 -177.6,177.7,-38,-37.9,0,40 -177.6,177.7,-37.9,-37.8,0,40 -177.6,177.7,-37.8,-37.7,0,40 -177.6,177.7,-37.7,-37.6,0,40 -177.6,177.7,-37.6,-37.5,0,40 -177.6,177.7,-37.5,-37.4,0,40 -177.6,177.7,-37.4,-37.3,0,40 -177.6,177.7,-37.3,-37.2,0,40 -177.7,177.8,-39.8,-39.7,0,40 -177.7,177.8,-39.7,-39.6,0,40 -177.7,177.8,-39.6,-39.5,0,40 -177.7,177.8,-39.5,-39.4,0,40 -177.7,177.8,-39.4,-39.3,0,40 -177.7,177.8,-39.3,-39.2,0,40 -177.7,177.8,-39.2,-39.1,0,40 -177.7,177.8,-39.1,-39,0,40 -177.7,177.8,-39,-38.9,0,40 -177.7,177.8,-38.9,-38.8,0,40 -177.7,177.8,-38.8,-38.7,0,40 -177.7,177.8,-38.7,-38.6,0,40 -177.7,177.8,-38.6,-38.5,0,40 -177.7,177.8,-38.5,-38.4,0,40 -177.7,177.8,-38.4,-38.3,0,40 -177.7,177.8,-38.3,-38.2,0,40 -177.7,177.8,-38.2,-38.1,0,40 -177.7,177.8,-38.1,-38,0,40 -177.7,177.8,-38,-37.9,0,40 -177.7,177.8,-37.9,-37.8,0,40 -177.7,177.8,-37.8,-37.7,0,40 -177.7,177.8,-37.7,-37.6,0,40 -177.7,177.8,-37.6,-37.5,0,40 -177.7,177.8,-37.5,-37.4,0,40 -177.7,177.8,-37.4,-37.3,0,40 -177.7,177.8,-37.3,-37.2,0,40 -177.8,177.9,-39.7,-39.6,0,40 -177.8,177.9,-39.6,-39.5,0,40 -177.8,177.9,-39.5,-39.4,0,40 -177.8,177.9,-39.4,-39.3,0,40 -177.8,177.9,-39.3,-39.2,0,40 -177.8,177.9,-39.2,-39.1,0,40 -177.8,177.9,-39.1,-39,0,40 -177.8,177.9,-39,-38.9,0,40 -177.8,177.9,-38.9,-38.8,0,40 -177.8,177.9,-38.8,-38.7,0,40 -177.8,177.9,-38.7,-38.6,0,40 -177.8,177.9,-38.6,-38.5,0,40 -177.8,177.9,-38.5,-38.4,0,40 -177.8,177.9,-38.4,-38.3,0,40 -177.8,177.9,-38.3,-38.2,0,40 -177.8,177.9,-38.2,-38.1,0,40 -177.8,177.9,-38.1,-38,0,40 -177.8,177.9,-38,-37.9,0,40 -177.8,177.9,-37.9,-37.8,0,40 -177.8,177.9,-37.8,-37.7,0,40 -177.8,177.9,-37.7,-37.6,0,40 -177.8,177.9,-37.6,-37.5,0,40 -177.8,177.9,-37.5,-37.4,0,40 -177.8,177.9,-37.4,-37.3,0,40 -177.8,177.9,-37.3,-37.2,0,40 -177.8,177.9,-37.2,-37.1,0,40 -177.9,178,-39.7,-39.6,0,40 -177.9,178,-39.6,-39.5,0,40 -177.9,178,-39.5,-39.4,0,40 -177.9,178,-39.4,-39.3,0,40 -177.9,178,-39.3,-39.2,0,40 -177.9,178,-39.2,-39.1,0,40 -177.9,178,-39.1,-39,0,40 -177.9,178,-39,-38.9,0,40 -177.9,178,-38.9,-38.8,0,40 -177.9,178,-38.8,-38.7,0,40 -177.9,178,-38.7,-38.6,0,40 -177.9,178,-38.6,-38.5,0,40 -177.9,178,-38.5,-38.4,0,40 -177.9,178,-38.4,-38.3,0,40 -177.9,178,-38.3,-38.2,0,40 -177.9,178,-38.2,-38.1,0,40 -177.9,178,-38.1,-38,0,40 -177.9,178,-38,-37.9,0,40 -177.9,178,-37.9,-37.8,0,40 -177.9,178,-37.8,-37.7,0,40 -177.9,178,-37.7,-37.6,0,40 -177.9,178,-37.6,-37.5,0,40 -177.9,178,-37.5,-37.4,0,40 -177.9,178,-37.4,-37.3,0,40 -177.9,178,-37.3,-37.2,0,40 -177.9,178,-37.2,-37.1,0,40 -178,178.1,-39.7,-39.6,0,40 -178,178.1,-39.6,-39.5,0,40 -178,178.1,-39.5,-39.4,0,40 -178,178.1,-39.4,-39.3,0,40 -178,178.1,-39.3,-39.2,0,40 -178,178.1,-39.2,-39.1,0,40 -178,178.1,-39.1,-39,0,40 -178,178.1,-39,-38.9,0,40 -178,178.1,-38.9,-38.8,0,40 -178,178.1,-38.8,-38.7,0,40 -178,178.1,-38.7,-38.6,0,40 -178,178.1,-38.6,-38.5,0,40 -178,178.1,-38.5,-38.4,0,40 -178,178.1,-38.4,-38.3,0,40 -178,178.1,-38.3,-38.2,0,40 -178,178.1,-38.2,-38.1,0,40 -178,178.1,-38.1,-38,0,40 -178,178.1,-38,-37.9,0,40 -178,178.1,-37.9,-37.8,0,40 -178,178.1,-37.8,-37.7,0,40 -178,178.1,-37.7,-37.6,0,40 -178,178.1,-37.6,-37.5,0,40 -178,178.1,-37.5,-37.4,0,40 -178,178.1,-37.4,-37.3,0,40 -178,178.1,-37.3,-37.2,0,40 -178,178.1,-37.2,-37.1,0,40 -178.1,178.2,-39.7,-39.6,0,40 -178.1,178.2,-39.6,-39.5,0,40 -178.1,178.2,-39.5,-39.4,0,40 -178.1,178.2,-39.4,-39.3,0,40 -178.1,178.2,-39.3,-39.2,0,40 -178.1,178.2,-39.2,-39.1,0,40 -178.1,178.2,-39.1,-39,0,40 -178.1,178.2,-39,-38.9,0,40 -178.1,178.2,-38.9,-38.8,0,40 -178.1,178.2,-38.8,-38.7,0,40 -178.1,178.2,-38.7,-38.6,0,40 -178.1,178.2,-38.6,-38.5,0,40 -178.1,178.2,-38.5,-38.4,0,40 -178.1,178.2,-38.4,-38.3,0,40 -178.1,178.2,-38.3,-38.2,0,40 -178.1,178.2,-38.2,-38.1,0,40 -178.1,178.2,-38.1,-38,0,40 -178.1,178.2,-38,-37.9,0,40 -178.1,178.2,-37.9,-37.8,0,40 -178.1,178.2,-37.8,-37.7,0,40 -178.1,178.2,-37.7,-37.6,0,40 -178.1,178.2,-37.6,-37.5,0,40 -178.1,178.2,-37.5,-37.4,0,40 -178.1,178.2,-37.4,-37.3,0,40 -178.1,178.2,-37.3,-37.2,0,40 -178.1,178.2,-37.2,-37.1,0,40 -178.1,178.2,-37.1,-37,0,40 -178.2,178.3,-39.7,-39.6,0,40 -178.2,178.3,-39.6,-39.5,0,40 -178.2,178.3,-39.5,-39.4,0,40 -178.2,178.3,-39.4,-39.3,0,40 -178.2,178.3,-39.3,-39.2,0,40 -178.2,178.3,-39.2,-39.1,0,40 -178.2,178.3,-39.1,-39,0,40 -178.2,178.3,-39,-38.9,0,40 -178.2,178.3,-38.9,-38.8,0,40 -178.2,178.3,-38.8,-38.7,0,40 -178.2,178.3,-38.7,-38.6,0,40 -178.2,178.3,-38.6,-38.5,0,40 -178.2,178.3,-38.5,-38.4,0,40 -178.2,178.3,-38.4,-38.3,0,40 -178.2,178.3,-38.3,-38.2,0,40 -178.2,178.3,-38.2,-38.1,0,40 -178.2,178.3,-38.1,-38,0,40 -178.2,178.3,-38,-37.9,0,40 -178.2,178.3,-37.9,-37.8,0,40 -178.2,178.3,-37.8,-37.7,0,40 -178.2,178.3,-37.7,-37.6,0,40 -178.2,178.3,-37.6,-37.5,0,40 -178.2,178.3,-37.5,-37.4,0,40 -178.2,178.3,-37.4,-37.3,0,40 -178.2,178.3,-37.3,-37.2,0,40 -178.2,178.3,-37.2,-37.1,0,40 -178.3,178.4,-39.7,-39.6,0,40 -178.3,178.4,-39.6,-39.5,0,40 -178.3,178.4,-39.5,-39.4,0,40 -178.3,178.4,-39.4,-39.3,0,40 -178.3,178.4,-39.3,-39.2,0,40 -178.3,178.4,-39.2,-39.1,0,40 -178.3,178.4,-39.1,-39,0,40 -178.3,178.4,-39,-38.9,0,40 -178.3,178.4,-38.9,-38.8,0,40 -178.3,178.4,-38.8,-38.7,0,40 -178.3,178.4,-38.7,-38.6,0,40 -178.3,178.4,-38.6,-38.5,0,40 -178.3,178.4,-38.5,-38.4,0,40 -178.3,178.4,-38.4,-38.3,0,40 -178.3,178.4,-38.3,-38.2,0,40 -178.3,178.4,-38.2,-38.1,0,40 -178.3,178.4,-38.1,-38,0,40 -178.3,178.4,-38,-37.9,0,40 -178.3,178.4,-37.9,-37.8,0,40 -178.3,178.4,-37.8,-37.7,0,40 -178.3,178.4,-37.7,-37.6,0,40 -178.3,178.4,-37.6,-37.5,0,40 -178.3,178.4,-37.5,-37.4,0,40 -178.3,178.4,-37.4,-37.3,0,40 -178.3,178.4,-37.3,-37.2,0,40 -178.3,178.4,-37.2,-37.1,0,40 -178.4,178.5,-39.5,-39.4,0,40 -178.4,178.5,-39.4,-39.3,0,40 -178.4,178.5,-39.3,-39.2,0,40 -178.4,178.5,-39.2,-39.1,0,40 -178.4,178.5,-39.1,-39,0,40 -178.4,178.5,-39,-38.9,0,40 -178.4,178.5,-38.9,-38.8,0,40 -178.4,178.5,-38.8,-38.7,0,40 -178.4,178.5,-38.7,-38.6,0,40 -178.4,178.5,-38.6,-38.5,0,40 -178.4,178.5,-38.5,-38.4,0,40 -178.4,178.5,-38.4,-38.3,0,40 -178.4,178.5,-38.3,-38.2,0,40 -178.4,178.5,-38.2,-38.1,0,40 -178.4,178.5,-38.1,-38,0,40 -178.4,178.5,-38,-37.9,0,40 -178.4,178.5,-37.9,-37.8,0,40 -178.4,178.5,-37.8,-37.7,0,40 -178.4,178.5,-37.7,-37.6,0,40 -178.4,178.5,-37.6,-37.5,0,40 -178.4,178.5,-37.5,-37.4,0,40 -178.4,178.5,-37.4,-37.3,0,40 -178.4,178.5,-37.3,-37.2,0,40 -178.4,178.5,-37.2,-37.1,0,40 -178.5,178.6,-39.4,-39.3,0,40 -178.5,178.6,-39.3,-39.2,0,40 -178.5,178.6,-39.2,-39.1,0,40 -178.5,178.6,-39.1,-39,0,40 -178.5,178.6,-39,-38.9,0,40 -178.5,178.6,-38.9,-38.8,0,40 -178.5,178.6,-38.8,-38.7,0,40 -178.5,178.6,-38.7,-38.6,0,40 -178.5,178.6,-38.6,-38.5,0,40 -178.5,178.6,-38.5,-38.4,0,40 -178.5,178.6,-38.4,-38.3,0,40 -178.5,178.6,-38.3,-38.2,0,40 -178.5,178.6,-38.2,-38.1,0,40 -178.5,178.6,-38.1,-38,0,40 -178.5,178.6,-38,-37.9,0,40 -178.5,178.6,-37.9,-37.8,0,40 -178.5,178.6,-37.8,-37.7,0,40 -178.5,178.6,-37.7,-37.6,0,40 -178.5,178.6,-37.6,-37.5,0,40 -178.5,178.6,-37.5,-37.4,0,40 -178.5,178.6,-37.4,-37.3,0,40 -178.5,178.6,-37.3,-37.2,0,40 -178.6,178.7,-39,-38.9,0,40 -178.6,178.7,-38.9,-38.8,0,40 -178.6,178.7,-38.8,-38.7,0,40 -178.6,178.7,-38.7,-38.6,0,40 -178.6,178.7,-38.6,-38.5,0,40 -178.6,178.7,-38.5,-38.4,0,40 -178.6,178.7,-38.4,-38.3,0,40 -178.6,178.7,-38.3,-38.2,0,40 -178.6,178.7,-38.2,-38.1,0,40 -178.6,178.7,-38.1,-38,0,40 -178.6,178.7,-38,-37.9,0,40 -178.6,178.7,-37.9,-37.8,0,40 -178.6,178.7,-37.8,-37.7,0,40 -178.6,178.7,-37.7,-37.6,0,40 -178.6,178.7,-37.6,-37.5,0,40 -178.6,178.7,-37.5,-37.4,0,40 -178.6,178.7,-37.4,-37.3,0,40 -178.6,178.7,-37.3,-37.2,0,40 -178.7,178.8,-38.9,-38.8,0,40 -178.7,178.8,-38.8,-38.7,0,40 -178.7,178.8,-38.7,-38.6,0,40 -178.7,178.8,-38.6,-38.5,0,40 -178.7,178.8,-38.5,-38.4,0,40 -178.7,178.8,-38.4,-38.3,0,40 -178.7,178.8,-38.3,-38.2,0,40 -178.7,178.8,-38.2,-38.1,0,40 -178.7,178.8,-38.1,-38,0,40 -178.7,178.8,-38,-37.9,0,40 -178.7,178.8,-37.9,-37.8,0,40 -178.7,178.8,-37.8,-37.7,0,40 -178.7,178.8,-37.7,-37.6,0,40 -178.7,178.8,-37.6,-37.5,0,40 -178.7,178.8,-37.5,-37.4,0,40 -178.7,178.8,-37.4,-37.3,0,40 -178.8,178.9,-38.8,-38.7,0,40 -178.8,178.9,-38.7,-38.6,0,40 -178.8,178.9,-38.6,-38.5,0,40 -178.8,178.9,-38.5,-38.4,0,40 -178.8,178.9,-38.4,-38.3,0,40 -178.8,178.9,-38.3,-38.2,0,40 -178.8,178.9,-38.2,-38.1,0,40 -178.8,178.9,-38.1,-38,0,40 -178.8,178.9,-38,-37.9,0,40 -178.8,178.9,-37.9,-37.8,0,40 -178.8,178.9,-37.8,-37.7,0,40 -178.8,178.9,-37.7,-37.6,0,40 -178.8,178.9,-37.6,-37.5,0,40 -178.8,178.9,-37.5,-37.4,0,40 -178.8,178.9,-37.4,-37.3,0,40 -178.9,179,-38.5,-38.4,0,40 -178.9,179,-38.4,-38.3,0,40 -178.9,179,-38.3,-38.2,0,40 -178.9,179,-38.2,-38.1,0,40 -178.9,179,-38.1,-38,0,40 -178.9,179,-38,-37.9,0,40 -178.9,179,-37.9,-37.8,0,40 -178.9,179,-37.8,-37.7,0,40 -178.9,179,-37.7,-37.6,0,40 -178.9,179,-37.6,-37.5,0,40 -178.9,179,-37.5,-37.4,0,40 -178.9,179,-37.4,-37.3,0,40 -179,179.1,-38.1,-38,0,40 -179,179.1,-38,-37.9,0,40 -179,179.1,-37.9,-37.8,0,40 -179,179.1,-37.8,-37.7,0,40 -179,179.1,-37.7,-37.6,0,40 -179,179.1,-37.6,-37.5,0,40 -179,179.1,-37.5,-37.4,0,40 -179.1,179.2,-37.7,-37.6,0,40 -179.1,179.2,-37.6,-37.5,0,40 diff --git a/floatcsep/artifacts/patterns.py b/floatcsep/artifacts/patterns.py deleted file mode 100644 index 4e74423..0000000 --- a/floatcsep/artifacts/patterns.py +++ /dev/null @@ -1,36 +0,0 @@ -from typing import List -from csep.core.forecasts import GriddedForecast as Forecast -from csep.core.catalogs import CSEPCatalog as Catalog - - -def consistency_test( - gridded_forecast: Forecast, - observed_catalog: Catalog): - pass - - -def comparative_test( - forecast: Forecast, - benchmark_forecast: Forecast, - observed_catalog: Catalog): - pass - - -def sequential_score( - gridded_forecasts: List[Forecast], - observed_catalogs: List[Catalog]): - pass - - -def sequential_relative_score( - gridded_forecasts: List[Forecast], - reference_forecasts: List[Forecast], - observed_catalogs: List[Catalog]): - pass - - -def vector_poisson_t_w_test( - forecasts: Forecast, - benchmark_forecast: List[Forecast], - catalog: Catalog): - pass diff --git a/floatcsep/cmd/main.py b/floatcsep/cmd/main.py index 92720d3..5429698 100644 --- a/floatcsep/cmd/main.py +++ b/floatcsep/cmd/main.py @@ -3,22 +3,23 @@ from floatcsep.utils import ExperimentComparison import logging import argparse -log = logging.getLogger('floatLogger') + +log = logging.getLogger("floatLogger") def stage(config, **_): - log.info(f'floatCSEP v{__version__} | Stage') + log.info(f"floatCSEP v{__version__} | Stage") exp = Experiment.from_yml(config) exp.stage_models() - log.info('Finalized') - log.debug('') + log.info("Finalized") + log.debug("") def run(config, **kwargs): - log.info(f'floatCSEP v{__version__} | Run') + log.info(f"floatCSEP v{__version__} | Run") exp = Experiment.from_yml(config, **kwargs) exp.stage_models() exp.set_tasks() @@ -28,13 +29,13 @@ def run(config, **kwargs): exp.generate_report() exp.make_repr() - log.info('Finalized') - log.debug(f'-------- END OF RUN --------') + log.info("Finalized") + log.debug(f"-------- END OF RUN --------") def plot(config, **kwargs): - log.info(f'floatCSEP v{__version__} | Plot') + log.info(f"floatCSEP v{__version__} | Plot") exp = Experiment.from_yml(config, **kwargs) exp.stage_models() @@ -43,49 +44,51 @@ def plot(config, **kwargs): exp.plot_forecasts() exp.generate_report() - log.info('Finalized\n') - log.debug('') + log.info("Finalized\n") + log.debug("") def reproduce(config, **kwargs): - log.info(f'floatCSEP v{__version__} | Reproduce') + log.info(f"floatCSEP v{__version__} | Reproduce") - reproduced_exp = Experiment.from_yml(config, reprdir='reproduced', - **kwargs) + reproduced_exp = Experiment.from_yml(config, reprdir="reproduced", **kwargs) reproduced_exp.stage_models() reproduced_exp.set_tasks() reproduced_exp.run() original_config = reproduced_exp.original_config - original_exp = Experiment.from_yml(original_config, - rundir=reproduced_exp.original_rundir) + original_exp = Experiment.from_yml(original_config, rundir=reproduced_exp.original_rundir) original_exp.stage_models() original_exp.set_tasks() comp = ExperimentComparison(original_exp, reproduced_exp) comp.compare_results() - log.info('Finalized') - log.debug('') + log.info("Finalized") + log.debug("") def floatcsep(): parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS) - parser.add_argument('func', type=str, choices=['run', 'stage', - 'plot', 'reproduce'], - help='Run a calculation') - parser.add_argument('config', type=str, - help='Experiment Configuration file') - parser.add_argument('-l', '--logging', action='store_true', default=False, - help="Don't log experiment") - parser.add_argument('-t', '--timestamp', action='store_true', - default=False, help="Timestamp results") + parser.add_argument( + "func", + type=str, + choices=["run", "stage", "plot", "reproduce"], + help="Run a calculation", + ) + parser.add_argument("config", type=str, help="Experiment Configuration file") + parser.add_argument( + "-l", "--logging", action="store_true", default=False, help="Don't log experiment" + ) + parser.add_argument( + "-t", "--timestamp", action="store_true", default=False, help="Timestamp results" + ) args = parser.parse_args() try: func = globals()[args.func] - args.__delattr__('func') + args.__delattr__("func") except AttributeError: - raise AttributeError('Function not implemented') + raise AttributeError("Function not implemented") func(**vars(args)) diff --git a/floatcsep/evaluation.py b/floatcsep/evaluation.py index 1f46616..e418c61 100644 --- a/floatcsep/evaluation.py +++ b/floatcsep/evaluation.py @@ -1,16 +1,16 @@ -import os import json -import numpy -from matplotlib import pyplot +import os from typing import Dict, Callable, Union, Sequence, List +import numpy from csep.core.catalogs import CSEPCatalog from csep.core.forecasts import GriddedForecast from csep.models import EvaluationResult +from matplotlib import pyplot from floatcsep.model import Model -from floatcsep.utils import parse_csep_func, timewindow2str from floatcsep.registry import PathTree +from floatcsep.utils import parse_csep_func, timewindow2str class Evaluation: @@ -31,37 +31,41 @@ class Evaluation: """ _TYPES = { - 'number_test': 'consistency', - 'spatial_test': 'consistency', - 'magnitude_test': 'consistency', - 'likelihood_test': 'consistency', - 'conditional_likelihood_test': 'consistency', - 'negative_binomial_number_test': 'consistency', - 'binary_spatial_test': 'consistency', - 'binomial_spatial_test': 'consistency', - 'brier_score': 'consistency', - 'binary_conditional_likelihood_test': 'consistency', - 'paired_t_test': 'comparative', - 'paired_ttest_point_process': 'comparative', - 'w_test': 'comparative', - 'binary_paired_t_test': 'comparative', - 'vector_poisson_t_w_test': 'batch', - 'sequential_likelihood': 'sequential', - 'sequential_information_gain': 'sequential_comparative' + "number_test": "consistency", + "spatial_test": "consistency", + "magnitude_test": "consistency", + "likelihood_test": "consistency", + "conditional_likelihood_test": "consistency", + "negative_binomial_number_test": "consistency", + "binary_spatial_test": "consistency", + "binomial_spatial_test": "consistency", + "brier_score": "consistency", + "binary_conditional_likelihood_test": "consistency", + "paired_t_test": "comparative", + "paired_ttest_point_process": "comparative", + "w_test": "comparative", + "binary_paired_t_test": "comparative", + "vector_poisson_t_w_test": "batch", + "sequential_likelihood": "sequential", + "sequential_information_gain": "sequential_comparative", } - def __init__(self, name: str, func: Union[str, Callable], - func_kwargs: Dict = None, - ref_model: (str, Model) = None, - plot_func: Callable = None, - plot_args: Sequence = None, - plot_kwargs: Dict = None, - markdown: str = '') -> None: + def __init__( + self, + name: str, + func: Union[str, Callable], + func_kwargs: Dict = None, + ref_model: (str, Model) = None, + plot_func: Callable = None, + plot_args: Sequence = None, + plot_kwargs: Dict = None, + markdown: str = "", + ) -> None: self.name = name self.func = parse_csep_func(func) - self.func_kwargs = func_kwargs or {} # todo set default args from exp? + self.func_kwargs = func_kwargs or {} self.ref_model = ref_model self.plot_func = None @@ -84,9 +88,10 @@ def type(self): @type.setter def type(self, type_list: Union[str, Sequence[str]]): if isinstance(type_list, Sequence): - if ('Comparative' in type_list) and (self.ref_model is None): - raise TypeError('A comparative-type test should have a' - ' reference model assigned') + if ("Comparative" in type_list) and (self.ref_model is None): + raise TypeError( + "A comparative-type test should have a" " reference model assigned" + ) self._type = type_list @@ -103,25 +108,28 @@ def parse_plots(self, plot_func, plot_args, plot_kwargs): plot_func = [{i: j} for i, j in plot_func.items()] if plot_args is not None or plot_kwargs is not None: - raise ValueError('If multiple plot functions are passed,' - 'each func should be a dictionary with ' - 'plot_args and plot_kwargs passed as ' - 'dictionaries beneath each func.') + raise ValueError( + "If multiple plot functions are passed," + "each func should be a dictionary with " + "plot_args and plot_kwargs passed as " + "dictionaries beneath each func." + ) func_names = [list(i.keys())[0] for i in plot_func] self.plot_func = [parse_csep_func(func) for func in func_names] - self.plot_args = [i[j].get('plot_args', {}) - for i, j in zip(plot_func, func_names)] - self.plot_kwargs = [i[j].get('plot_kwargs', {}) - for i, j in zip(plot_func, func_names)] - - - def prepare_args(self, - timewindow: Union[str, list], - catpath: Union[str, list], - model: Union[Model, Sequence[Model]], - ref_model: Union[Model, Sequence] = None, - region = None) -> tuple: + self.plot_args = [i[j].get("plot_args", {}) for i, j in zip(plot_func, func_names)] + self.plot_kwargs = [ + i[j].get("plot_kwargs", {}) for i, j in zip(plot_func, func_names) + ] + + def prepare_args( + self, + timewindow: Union[str, list], + catpath: Union[str, list], + model: Union[Model, Sequence[Model]], + ref_model: Union[Model, Sequence] = None, + region=None, + ) -> tuple: """ Prepares the positional argument for the Evaluation function. @@ -156,8 +164,7 @@ def prepare_args(self, test_args = (forecast, ref_forecast, catalog) elif isinstance(ref_model, list): # Args: (Fc, [RFc], Cat) - ref_forecasts = [i.get_forecast(timewindow, region) - for i in ref_model] + ref_forecasts = [i.get_forecast(timewindow, region) for i in ref_model] test_args = (forecast, ref_forecasts, catalog) else: # Args: (Fc, Cat) @@ -167,8 +174,8 @@ def prepare_args(self, @staticmethod def get_catalog( - catalog_path: Union[str, Sequence[str]], - forecast: Union[GriddedForecast, Sequence[GriddedForecast]] + catalog_path: Union[str, Sequence[str]], + forecast: Union[GriddedForecast, Sequence[GriddedForecast]], ) -> Union[CSEPCatalog, List[CSEPCatalog]]: """ @@ -185,25 +192,25 @@ def get_catalog( """ if isinstance(catalog_path, str): eval_cat = CSEPCatalog.load_json(catalog_path) - eval_cat.region = getattr(forecast, 'region') + eval_cat.region = getattr(forecast, "region") else: eval_cat = [CSEPCatalog.load_json(i) for i in catalog_path] - if (len(forecast) != len(eval_cat)) or (not isinstance(forecast, - Sequence)): - raise IndexError('Amount of passed catalogs and forecats must ' - 'be the same') + if (len(forecast) != len(eval_cat)) or (not isinstance(forecast, Sequence)): + raise IndexError("Amount of passed catalogs and forecats must " "be the same") for cat, fc in zip(eval_cat, forecast): - cat.region = getattr(fc, 'region', None) + cat.region = getattr(fc, "region", None) return eval_cat - def compute(self, - timewindow: Union[str, list], - catalog: str, - model: Model, - path: str, - ref_model: Union[Model, Sequence[Model]] = None, - region=None) -> None: + def compute( + self, + timewindow: Union[str, list], + catalog: str, + model: Model, + path: str, + ref_model: Union[Model, Sequence[Model]] = None, + region=None, + ) -> None: """ Runs the test, structuring the arguments according to the @@ -221,18 +228,15 @@ def compute(self, Returns: """ - test_args = self.prepare_args(timewindow, - catpath=catalog, - model=model, - ref_model=ref_model, - region=region) + test_args = self.prepare_args( + timewindow, catpath=catalog, model=model, ref_model=ref_model, region=region + ) evaluation_result = self.func(*test_args, **self.func_kwargs) self.write_result(evaluation_result, path) @staticmethod - def write_result(result: EvaluationResult, - path: str) -> None: + def write_result(result: EvaluationResult, path: str) -> None: """ Dumps a test result into a json file. """ @@ -247,11 +251,10 @@ def default(self, obj): return obj.tolist() return json.JSONEncoder.default(self, obj) - with open(path, 'w') as _file: + with open(path, "w") as _file: json.dump(result.to_dict(), _file, indent=4, cls=NumpyEncoder) - def read_results(self, window: str, models: List[Model], - tree: PathTree) -> List: + def read_results(self, window: str, models: List[Model], tree: PathTree) -> List: """ Reads an Evaluation result for a given time window and returns a list of the results for all tested models. @@ -264,19 +267,21 @@ def read_results(self, window: str, models: List[Model], wstr_ = window for i in models: - eval_path = tree(wstr_, 'evaluations', self, i.name) - with open(eval_path, 'r') as file_: + eval_path = tree(wstr_, "evaluations", self, i.name) + with open(eval_path, "r") as file_: model_eval = EvaluationResult.from_dict(json.load(file_)) test_results.append(model_eval) return test_results - def plot_results(self, - timewindow: Union[str, List], - models: List[Model], - tree: PathTree, - dpi: int = 300, - show: bool = False) -> None: + def plot_results( + self, + timewindow: Union[str, List], + models: List[Model], + tree: PathTree, + dpi: int = 300, + show: bool = False, + ) -> None: """ Plots all evaluation results @@ -289,46 +294,45 @@ def plot_results(self, if isinstance(timewindow, str): timewindow = [timewindow] - for func, fargs, fkwargs in zip(self.plot_func, self.plot_args, - self.plot_kwargs): - if self.type in ['consistency', 'comparative']: + for func, fargs, fkwargs in zip(self.plot_func, self.plot_args, self.plot_kwargs): + if self.type in ["consistency", "comparative"]: try: for time_str in timewindow: - fig_path = tree(time_str, 'figures', self.name) + fig_path = tree(time_str, "figures", self.name) results = self.read_results(time_str, models, tree) ax = func(results, plot_args=fargs, **fkwargs) - if 'code' in fargs: - exec(fargs['code']) + if "code" in fargs: + exec(fargs["code"]) pyplot.savefig(fig_path, dpi=dpi) if show: pyplot.show() except AttributeError as msg: - if self.type in ['consistency', 'comparative']: + if self.type in ["consistency", "comparative"]: for time_str in timewindow: results = self.read_results(time_str, models, tree) for result, model in zip(results, models): - fig_name = f'{self.name}_{model.name}' - - tree.paths[time_str]['figures'][fig_name] =\ - os.path.join(time_str, 'figures', fig_name) - fig_path = tree(time_str, 'figures', fig_name) - ax = func(result, plot_args=fargs, **fkwargs, - show=False) - if 'code' in fargs: - exec(fargs['code']) + fig_name = f"{self.name}_{model.name}" + + tree.paths[time_str]["figures"][fig_name] = os.path.join( + time_str, "figures", fig_name + ) + fig_path = tree(time_str, "figures", fig_name) + ax = func(result, plot_args=fargs, **fkwargs, show=False) + if "code" in fargs: + exec(fargs["code"]) pyplot.savefig(fig_path, dpi=dpi) if show: pyplot.show() - elif self.type in ['sequential', 'sequential_comparative', 'batch']: - fig_path = tree(timewindow[-1], 'figures', self.name) + elif self.type in ["sequential", "sequential_comparative", "batch"]: + fig_path = tree(timewindow[-1], "figures", self.name) results = self.read_results(timewindow[-1], models, tree) ax = func(results, plot_args=fargs, **fkwargs) - if 'code' in fargs: - exec(fargs['code']) + if "code" in fargs: + exec(fargs["code"]) pyplot.savefig(fig_path, dpi=dpi) if show: pyplot.show() @@ -339,21 +343,18 @@ def as_dict(self) -> dict: serialized and then parsed """ out = {} - included = ['model', 'ref_model', 'func_kwargs'] + included = ["model", "ref_model", "func_kwargs"] for k, v in self.__dict__.items(): if k in included and v: out[k] = v - func_str = f'{self.func.__module__}.{self.func.__name__}' + func_str = f"{self.func.__module__}.{self.func.__name__}" plot_func_str = [] for i, j, k in zip(self.plot_func, self.plot_args, self.plot_kwargs): - pfunc = {f'{i.__module__}.{i.__name__}': {'plot_args': j, - 'plot_kwargs': k}} + pfunc = {f"{i.__module__}.{i.__name__}": {"plot_args": j, "plot_kwargs": k}} plot_func_str.append(pfunc) - return {self.name: {**out, - 'func': func_str, - 'plot_func': plot_func_str}} + return {self.name: {**out, "func": func_str, "plot_func": plot_func_str}} def __str__(self): return ( @@ -369,6 +370,6 @@ def from_dict(cls, record): Parses a dictionary and re-instantiate an Evaluation object """ if len(record) != 1: - raise IndexError('A single test has not been passed') + raise IndexError("A single test has not been passed") name = next(iter(record)) return cls(name=name, **record[name]) diff --git a/floatcsep/experiment.py b/floatcsep/experiment.py index e8d312f..92212af 100644 --- a/floatcsep/experiment.py +++ b/floatcsep/experiment.py @@ -1,30 +1,36 @@ +import datetime +import json +import logging import os import shutil -import datetime +import warnings from os.path import join, abspath, relpath, dirname, isfile, split, exists +from typing import Union, List, Dict, Callable, Mapping, Sequence import csep import numpy import yaml -import json -import logging - -from typing import Union, List, Dict, Callable, Mapping, Sequence -from matplotlib import pyplot from cartopy import crs as ccrs - from csep.core.catalogs import CSEPCatalog from csep.utils.time_utils import decimal_year +from matplotlib import pyplot from floatcsep import report +from floatcsep.evaluation import Evaluation from floatcsep.logger import add_fhandler +from floatcsep.model import Model, ModelFactory, TimeDependentModel from floatcsep.registry import PathTree -from floatcsep.utils import NoAliasLoader, parse_csep_func, read_time_cfg, \ - read_region_cfg, Task, TaskGraph, timewindow2str, str2timewindow, \ - magnitude_vs_time -from floatcsep.model import Model -from floatcsep.evaluation import Evaluation -import warnings +from floatcsep.utils import ( + NoAliasLoader, + parse_csep_func, + read_time_cfg, + read_region_cfg, + Task, + TaskGraph, + timewindow2str, + str2timewindow, + magnitude_vs_time, +) numpy.seterr(all="ignore") warnings.filterwarnings("ignore") @@ -93,7 +99,7 @@ class Experiment: """ - ''' + """ Data management Model: @@ -107,20 +113,22 @@ class Experiment: - read forecast from file (TD) (does not make sense for TI (too much FS space) unless is already dropped to DB) - ''' - - def __init__(self, - name: str = None, - time_config: dict = None, - region_config: dict = None, - catalog: str = None, - models: str = None, - tests: str = None, - postproc_config: str = None, - default_test_kwargs: dict = None, - rundir: str = 'results', - report_hook: dict = None, - **kwargs) -> None: + """ + + def __init__( + self, + name: str = None, + time_config: dict = None, + region_config: dict = None, + catalog: str = None, + models: str = None, + tests: str = None, + postproc_config: str = None, + default_test_kwargs: dict = None, + rundir: str = "results", + report_hook: dict = None, + **kwargs, + ) -> None: # todo # - instantiate from full experiment register (ignoring test/models # config), or self-awareness functions? @@ -129,40 +137,42 @@ def __init__(self, # Or filter region? # Instantiate - workdir = abspath(kwargs.get('path', os.getcwd())) - if kwargs.get('timestamp', False): + workdir = abspath(kwargs.get("path", os.getcwd())) + if kwargs.get("timestamp", False): rundir = os.path.join( - rundir, - f'run_{datetime.datetime.utcnow().date().isoformat()}') + rundir, f"run_{datetime.datetime.utcnow().date().isoformat()}" + ) os.makedirs(os.path.join(workdir, rundir), exist_ok=True) - self.name = name if name else 'floatingExp' + self.name = name if name else "floatingExp" self.path = PathTree(workdir, rundir) - self.config_file = kwargs.get('config_file', None) - self.original_config = kwargs.get('original_config', None) - self.original_rundir = kwargs.get('original_rundir', None) + self.config_file = kwargs.get("config_file", None) + self.original_config = kwargs.get("original_config", None) + self.original_rundir = kwargs.get("original_rundir", None) self.rundir = rundir - self.seed = kwargs.get('seed', None) + self.seed = kwargs.get("seed", None) self.time_config = read_time_cfg(time_config, **kwargs) self.region_config = read_region_cfg(region_config, **kwargs) self.model_config = models if isinstance(models, str) else None self.test_config = tests if isinstance(tests, str) else None - logger = kwargs.get('logging', True) + logger = kwargs.get("logging", True) if logger: - filename = 'experiment.log' if logger is True else logger + filename = "experiment.log" if logger is True else logger self.path.logger = os.path.join(workdir, rundir, filename) - log.info(f'Logging at {self.path.logger}') + log.info(f"Logging at {self.path.logger}") add_fhandler(self.path.logger) - log.debug(f'-------- BEGIN OF RUN --------') - log.info(f'Setting up experiment {self.name}:') - log.info(f'\tStart: {self.start_date}') - log.info(f'\tEnd: {self.end_date}') - log.info(f'\tTime windows: {len(self.timewindows)}') - log.info(f'\tRegion: {self.region.name if self.region else None}') - log.info(f'\tMagnitude range: [{numpy.min(self.magnitudes)},' - f' {numpy.max(self.magnitudes)}]') + log.debug(f"-------- BEGIN OF RUN --------") + log.info(f"Setting up experiment {self.name}:") + log.info(f"\tStart: {self.start_date}") + log.info(f"\tEnd: {self.end_date}") + log.info(f"\tTime windows: {len(self.timewindows)}") + log.info(f"\tRegion: {self.region.name if self.region else None}") + log.info( + f"\tMagnitude range: [{numpy.min(self.magnitudes)}," + f" {numpy.max(self.magnitudes)}]" + ) self.catalog = None self.models = [] @@ -172,15 +182,16 @@ def __init__(self, self.default_test_kwargs = default_test_kwargs self.catalog = catalog - self.models = self.set_models(models or kwargs.get('model_config'), - kwargs.get('order', None)) - self.tests = self.set_tests(tests or kwargs.get('test_config')) + self.models = self.set_models( + models or kwargs.get("model_config"), kwargs.get("order", None) + ) + self.tests = self.set_tests(tests or kwargs.get("test_config")) self.tasks = [] self.task_graph = None self.report_hook = report_hook if report_hook else {} - self.force_rerun = kwargs.get('force_rerun', False) + self.force_rerun = kwargs.get("force_rerun", False) def __getattr__(self, item: str) -> object: """ @@ -198,20 +209,20 @@ def __getattr__(self, item: str) -> object: return self.region_config[item] except KeyError: raise AttributeError( - f"Experiment '{self.name}'" - f" has no attribute '{item}'") from None + f"Experiment '{self.name}'" f" has no attribute '{item}'" + ) from None def __dir__(self): """ Adds time and region configs keys to instance scope. """ - _dir = list(super().__dir__()) + list(self.time_config.keys()) + list( - self.region_config) + _dir = ( + list(super().__dir__()) + list(self.time_config.keys()) + list(self.region_config) + ) return sorted(_dir) - def set_models(self, model_config: Union[Dict, str, List], - order: List = None) -> List: + def set_models(self, model_config: Union[Dict, str, List], order: List = None) -> List: """ Parse the models' configuration file/dict. Instantiates all the models @@ -230,7 +241,7 @@ def set_models(self, model_config: Union[Dict, str, List], if isinstance(model_config, str): modelcfg_path = self.path.abs(model_config) _dir = self.path.absdir(model_config) - with open(modelcfg_path, 'r') as file_: + with open(modelcfg_path, "r") as file_: config_dict = yaml.load(file_, NoAliasLoader) elif isinstance(model_config, (dict, list)): config_dict = model_config @@ -238,53 +249,57 @@ def set_models(self, model_config: Union[Dict, str, List], elif model_config is None: return models else: - raise NotImplementedError(f'Load for model type' - f' {model_config.__class__}' - f'not implemented ') + raise NotImplementedError( + f"Load for model type" f" {model_config.__class__}" f"not implemented " + ) for element in config_dict: # Check if the model is unique or has multiple submodels - if not any('flavours' in i for i in element.values()): + if not any("flavours" in i for i in element.values()): name_ = next(iter(element)) - path_ = self.path.rel(_dir, element[name_]['path']) - model_i = {name_: {**element[name_], - 'model_path': path_, - 'workdir': self.path.workdir}} - model_i[name_].pop('path') - models.append(Model.from_dict(model_i)) + path_ = self.path.rel(_dir, element[name_]["path"]) + model_i = { + name_: {**element[name_], "model_path": path_, "workdir": self.path.workdir} + } + model_i[name_].pop("path") + models.append(ModelFactory.create_model(model_i)) else: - model_flavours = list(element.values())[0]['flavours'].items() + model_flavours = list(element.values())[0]["flavours"].items() for flav, flav_path in model_flavours: name_super = next(iter(element)) - path_super = element[name_super].get('path', '') + path_super = element[name_super].get("path", "") path_sub = self.path.rel(_dir, path_super, flav_path) # updates name of submodel - name_flav = f'{name_super}@{flav}' - model_ = {name_flav: {**element[name_super], - 'model_path': path_sub, - 'workdir': self.path.workdir}} - model_[name_flav].pop('path') - model_[name_flav].pop('flavours') - models.append(Model.from_dict(model_)) + name_flav = f"{name_super}@{flav}" + model_ = { + name_flav: { + **element[name_super], + "model_path": path_sub, + "workdir": self.path.workdir, + } + } + model_[name_flav].pop("path") + model_[name_flav].pop("flavours") + models.append(ModelFactory.create_model(model_)) # Checks if there is any repeated model. names_ = [i.name for i in models] if len(names_) != len(set(names_)): - reps = set( - [i for i in names_ if (sum([j == i for j in names_]) > 1)]) + reps = set([i for i in names_ if (sum([j == i for j in names_]) > 1)]) one = not bool(len(reps) - 1) - log.warning(f'Warning: Model{"s" * (not one)} {reps}' - f' {"is" * one + "are" * (not one)} repeated') - log.info(f'\tModels: {[i.name for i in models]}') - + log.warning( + f'Warning: Model{"s" * (not one)} {reps}' + f' {"is" * one + "are" * (not one)} repeated' + ) + log.info(f"\tModels: {[i.name for i in models]}") if order: models = [models[i] for i in order] return models def get_model(self, name: str) -> Model: - """ Returns a Model by its name string """ + """Returns a Model by its name string""" for model in self.models: if model.name == name: return model @@ -294,7 +309,7 @@ def stage_models(self) -> None: Stages all the experiment's models. See :meth:`floatcsep.model.Model.stage` """ - log.info('Staging models') + log.info("Staging models") for i in self.models: i.stage(self.timewindows) @@ -313,7 +328,7 @@ def set_tests(self, test_config: Union[str, Dict, List]) -> list: tests = [] if isinstance(test_config, str): - with open(self.path.abs(test_config), 'r') as config: + with open(self.path.abs(test_config), "r") as config: config_dict = yaml.load(config, NoAliasLoader) for eval_dict in config_dict: tests.append(Evaluation.from_dict(eval_dict)) @@ -321,7 +336,7 @@ def set_tests(self, test_config: Union[str, Dict, List]) -> list: for eval_dict in test_config: tests.append(Evaluation.from_dict(eval_dict)) - log.info(f'\tEvaluations: {[i.name for i in tests]}') + log.info(f"\tEvaluations: {[i.name for i in tests]}") return tests @@ -336,22 +351,24 @@ def catalog(self) -> CSEPCatalog: if callable(self._catalog): if isfile(self._catpath): return CSEPCatalog.load_json(self._catpath) - bounds = {'start_time': min([item for sublist in self.timewindows - for item in sublist]), - 'end_time': max([item for sublist in self.timewindows - for item in sublist]), - 'min_magnitude': self.magnitudes.min(), - 'max_depth': self.depths.max()} + bounds = { + "start_time": min([item for sublist in self.timewindows for item in sublist]), + "end_time": max([item for sublist in self.timewindows for item in sublist]), + "min_magnitude": self.magnitudes.min(), + "max_depth": self.depths.max(), + } if self.region: - bounds.update({i: j for i, j in - zip(['min_longitude', 'max_longitude', - 'min_latitude', 'max_latitude'], - self.region.get_bbox())}) - - catalog = self._catalog( - catalog_id='catalog', # todo name as run - **bounds - ) + bounds.update( + { + i: j + for i, j in zip( + ["min_longitude", "max_longitude", "min_latitude", "max_latitude"], + self.region.get_bbox(), + ) + } + ) + + catalog = self._catalog(catalog_id="catalog", **bounds) if self.region: catalog.filter_spatial(region=self.region, in_place=True) @@ -381,11 +398,9 @@ def catalog(self, cat: Union[Callable, CSEPCatalog, str]) -> None: else: # catalog can be a function self._catalog = parse_csep_func(cat) - self._catpath = self.path.abs('catalog.json') + self._catpath = self.path.abs("catalog.json") if isfile(self._catpath): - log.info(f"\tCatalog: stored " - f"'{self._catpath}' " - f"from '{cat}'") + log.info(f"\tCatalog: stored " f"'{self._catpath}' " f"from '{cat}'") else: log.info(f"\tCatalog: '{cat}'") @@ -407,10 +422,14 @@ def get_test_cat(self, tstring: str = None) -> CSEPCatalog: start = self.start_date end = self.end_date sub_cat = self.catalog.filter( - [f'origin_time < {end.timestamp() * 1000}', - f'origin_time >= {start.timestamp() * 1000}', - f'magnitude >= {self.mag_min}', - f'magnitude < {self.mag_max}'], in_place=False) + [ + f"origin_time < {end.timestamp() * 1000}", + f"origin_time >= {start.timestamp() * 1000}", + f"magnitude >= {self.mag_min}", + f"magnitude < {self.mag_max}", + ], + in_place=False, + ) if self.region: sub_cat.filter_spatial(region=self.region, in_place=True) @@ -429,22 +448,26 @@ def set_test_cat(self, tstring: str) -> None: """ "" - testcat_name = self.path(tstring, 'catalog') + testcat_name = self.path(tstring, "catalog") if not exists(testcat_name): log.debug( - f'Filtering catalog to testing sub-catalog and saving to ' - f'{testcat_name}') + f"Filtering catalog to testing sub-catalog and saving to " f"{testcat_name}" + ) start, end = str2timewindow(tstring) sub_cat = self.catalog.filter( - [f'origin_time < {end.timestamp() * 1000}', - f'origin_time >= {start.timestamp() * 1000}', - f'magnitude >= {self.mag_min}', - f'magnitude < {self.mag_max}'], in_place=False) + [ + f"origin_time < {end.timestamp() * 1000}", + f"origin_time >= {start.timestamp() * 1000}", + f"magnitude >= {self.mag_min}", + f"magnitude < {self.mag_max}", + ], + in_place=False, + ) if self.region: sub_cat.filter_spatial(region=self.region, in_place=True) sub_cat.write_json(filename=testcat_name) else: - log.debug(f'Using stored test sub-catalog from {testcat_name}') + log.debug(f"Using stored test sub-catalog from {testcat_name}") def set_input_cat(self, tstring: str, model: Model) -> None: """ @@ -460,9 +483,8 @@ def set_input_cat(self, tstring: str, model: Model) -> None: """ start, end = str2timewindow(tstring) - sub_cat = self.catalog.filter( - [f'origin_time < {start.timestamp() * 1000}']) - sub_cat.write_ascii(filename=model.path('input_cat')) + sub_cat = self.catalog.filter([f"origin_time < {start.timestamp() * 1000}"]) + sub_cat.write_ascii(filename=model.path("input_cat")) def set_tasks(self): """ @@ -496,9 +518,7 @@ def set_tasks(self): task_graph = TaskGraph() for time_i in tw_strings: # The method call Experiment.set_test_cat(time_i) is created lazily - task_i = Task(instance=self, - method='set_test_cat', - tstring=time_i) + task_i = Task(instance=self, method="set_test_cat", tstring=time_i) # An is added to the task graph task_graph.add(task_i) # the task will be executed later with Experiment.run() @@ -507,143 +527,132 @@ def set_tasks(self): # Set up the Forecasts creation for time_i in tw_strings: for model_j in self.models: - if model_j.model_class == 'td': - task_tj = Task(instance=self, - method='set_input_cat', - tstring=time_i, - model=model_j) + if isinstance(model_j, TimeDependentModel): + task_tj = Task( + instance=self, method="set_input_cat", tstring=time_i, model=model_j + ) task_graph.add(task=task_tj) # A catalog needs to have been filtered - task_ij = Task(instance=model_j, - method='create_forecast', - tstring=time_i, - force=self.force_rerun) + task_ij = Task( + instance=model_j, + method="create_forecast", + tstring=time_i, + force=self.force_rerun, + ) task_graph.add(task=task_ij) # A catalog needs to have been filtered - if model_j.model_class == 'td': - task_graph.add_dependency(task_ij, - dinst=self, - dmeth='set_input_cat', - dkw=(time_i, model_j)) - task_graph.add_dependency(task_ij, - dinst=self, - dmeth='set_test_cat', - dkw=time_i) + if isinstance(model_j, TimeDependentModel): + task_graph.add_dependency( + task_ij, dinst=self, dmeth="set_input_cat", dkw=(time_i, model_j) + ) + task_graph.add_dependency(task_ij, dinst=self, dmeth="set_test_cat", dkw=time_i) # Set up the Consistency Tests for test_k in self.tests: - if test_k.type == 'consistency': + if test_k.type == "consistency": for time_i in tw_strings: for model_j in self.models: task_ijk = Task( instance=test_k, - method='compute', + method="compute", timewindow=time_i, - catalog=self.path(time_i, 'catalog'), + catalog=self.path(time_i, "catalog"), model=model_j, region=self.region, - path=self.path(time_i, 'evaluations', - test_k, model_j)) + path=self.path(time_i, "evaluations", test_k, model_j), + ) task_graph.add(task_ijk) # the forecast needs to have been created - task_graph.add_dependency(task_ijk, - dinst=model_j, - dmeth='create_forecast', - dkw=time_i) + task_graph.add_dependency( + task_ijk, dinst=model_j, dmeth="create_forecast", dkw=time_i + ) # Set up the Comparative Tests - elif test_k.type == 'comparative': + elif test_k.type == "comparative": for time_i in tw_strings: for model_j in self.models: task_ik = Task( instance=test_k, - method='compute', + method="compute", timewindow=time_i, - catalog=self.path(time_i, 'catalog'), + catalog=self.path(time_i, "catalog"), model=model_j, ref_model=self.get_model(test_k.ref_model), region=self.region, - path=self.path(time_i, 'evaluations', test_k, - model_j) + path=self.path(time_i, "evaluations", test_k, model_j), ) task_graph.add(task_ik) - task_graph.add_dependency(task_ik, - dinst=model_j, - dmeth='create_forecast', - dkw=time_i) - task_graph.add_dependency(task_ik, - dinst=self.get_model( - test_k.ref_model), - dmeth='create_forecast', - dkw=time_i) + task_graph.add_dependency( + task_ik, dinst=model_j, dmeth="create_forecast", dkw=time_i + ) + task_graph.add_dependency( + task_ik, + dinst=self.get_model(test_k.ref_model), + dmeth="create_forecast", + dkw=time_i, + ) # Set up the Sequential Scores - elif test_k.type == 'sequential': + elif test_k.type == "sequential": for model_j in self.models: task_k = Task( instance=test_k, - method='compute', + method="compute", timewindow=tw_strings, - catalog=[self.path(i, 'catalog') - for i in tw_strings], + catalog=[self.path(i, "catalog") for i in tw_strings], model=model_j, region=self.region, - path=self.path(tw_strings[-1], 'evaluations', - test_k, model_j) + path=self.path(tw_strings[-1], "evaluations", test_k, model_j), ) task_graph.add(task_k) for tw_i in tw_strings: - task_graph.add_dependency(task_k, - dinst=model_j, - dmeth='create_forecast', - dkw=tw_i) + task_graph.add_dependency( + task_k, dinst=model_j, dmeth="create_forecast", dkw=tw_i + ) # Set up the Sequential_Comparative Scores - elif test_k.type == 'sequential_comparative': + elif test_k.type == "sequential_comparative": tw_strs = timewindow2str(self.timewindows) for model_j in self.models: task_k = Task( instance=test_k, - method='compute', + method="compute", timewindow=tw_strs, - catalog=[self.path(i, 'catalog') for i in tw_strs], + catalog=[self.path(i, "catalog") for i in tw_strs], model=model_j, ref_model=self.get_model(test_k.ref_model), region=self.region, - path=self.path(tw_strs[-1], 'evaluations', test_k, - model_j) + path=self.path(tw_strs[-1], "evaluations", test_k, model_j), ) task_graph.add(task_k) for tw_i in tw_strings: - task_graph.add_dependency(task_k, - dinst=model_j, - dmeth='create_forecast', - dkw=tw_i) - task_graph.add_dependency(task_k, - dinst=self.get_model( - test_k.ref_model), - dmeth='create_forecast', - dkw=tw_i) + task_graph.add_dependency( + task_k, dinst=model_j, dmeth="create_forecast", dkw=tw_i + ) + task_graph.add_dependency( + task_k, + dinst=self.get_model(test_k.ref_model), + dmeth="create_forecast", + dkw=tw_i, + ) # Set up the Batch comparative Scores - elif test_k.type == 'batch': + elif test_k.type == "batch": time_str = timewindow2str(self.timewindows[-1]) for model_j in self.models: task_k = Task( instance=test_k, - method='compute', + method="compute", timewindow=time_str, - catalog=self.path(time_str, 'catalog'), + catalog=self.path(time_str, "catalog"), ref_model=self.models, model=model_j, region=self.region, - path=self.path(time_str, 'evaluations', test_k, - model_j) + path=self.path(time_str, "evaluations", test_k, model_j), ) task_graph.add(task_k) for m_j in self.models: - task_graph.add_dependency(task_k, - dinst=m_j, - dmeth='create_forecast', - dkw=time_str) + task_graph.add_dependency( + task_k, dinst=m_j, dmeth="create_forecast", dkw=time_str + ) self.task_graph = task_graph @@ -658,13 +667,13 @@ def run(self) -> None: - Queuer? """ - log.info(f'Running {self.task_graph.ntasks} tasks') + log.info(f"Running {self.task_graph.ntasks} tasks") if self.seed: numpy.random.seed(self.seed) self.task_graph.run() - log.info(f'Calculation completed') + log.info(f"Calculation completed") def read_results(self, test: Evaluation, window: str) -> List: """ @@ -676,7 +685,7 @@ def read_results(self, test: Evaluation, window: str) -> List: def plot_results(self) -> None: """ - + Plots all evaluation results """ @@ -696,46 +705,43 @@ def plot_catalog(self, dpi: int = 300, show: bool = False) -> None: show: show in runtime """ - plot_args = {'basemap': 'ESRI_terrain', - 'figsize': (12, 8), - 'markersize': 8, - 'markercolor': 'black', - 'grid_fontsize': 16, - 'title': '', - 'legend': True, - } - plot_args.update(self.postproc_config.get('plot_catalog', {})) + plot_args = { + "basemap": "ESRI_terrain", + "figsize": (12, 8), + "markersize": 8, + "markercolor": "black", + "grid_fontsize": 16, + "title": "", + "legend": True, + } + plot_args.update(self.postproc_config.get("plot_catalog", {})) catalog = self.get_test_cat() if catalog.get_number_of_events() != 0: ax = catalog.plot(plot_args=plot_args, show=show) ax.get_figure().tight_layout() - ax.get_figure().savefig(self.path('catalog_figure'), - dpi=dpi) + ax.get_figure().savefig(self.path("catalog_figure"), dpi=dpi) ax2 = magnitude_vs_time(catalog) ax2.get_figure().tight_layout() - ax2.get_figure().savefig(self.path('magnitude_time'), - dpi=dpi) + ax2.get_figure().savefig(self.path("magnitude_time"), dpi=dpi) - if self.postproc_config.get('all_time_windows'): + if self.postproc_config.get("all_time_windows"): timewindow = self.timewindows for tw in timewindow: - catpath = self.path(tw, 'catalog') + catpath = self.path(tw, "catalog") catalog = CSEPCatalog.load_json(catpath) if catalog.get_number_of_events() != 0: ax = catalog.plot(plot_args=plot_args, show=show) ax.get_figure().tight_layout() - ax.get_figure().savefig(self.path(tw, 'figures', - 'catalog'), - dpi=dpi) + ax.get_figure().savefig(self.path(tw, "figures", "catalog"), dpi=dpi) ax2 = magnitude_vs_time(catalog) ax2.get_figure().tight_layout() - ax2.get_figure().savefig(self.path(tw, 'figures', - 'magnitude_time'), - dpi=dpi) + ax2.get_figure().savefig( + self.path(tw, "figures", "magnitude_time"), dpi=dpi + ) def plot_forecasts(self) -> None: """ @@ -744,32 +750,35 @@ def plot_forecasts(self) -> None: """ - plot_fc_config = self.postproc_config.get('plot_forecasts') + plot_fc_config = self.postproc_config.get("plot_forecasts") if plot_fc_config: log.info("Plotting forecasts") if plot_fc_config is True: plot_fc_config = {} try: - proj_ = plot_fc_config.get('projection') + proj_ = plot_fc_config.get("projection") if isinstance(proj_, dict): proj_name = list(proj_.keys())[0] proj_args = list(proj_.values())[0] else: proj_name = proj_ proj_args = {} - plot_fc_config['projection'] = getattr(ccrs, proj_name)( - **proj_args) + plot_fc_config["projection"] = getattr(ccrs, proj_name)(**proj_args) except (IndexError, KeyError, TypeError, AttributeError): - plot_fc_config['projection'] = ccrs.PlateCarree( - central_longitude=0.0) + plot_fc_config["projection"] = ccrs.PlateCarree(central_longitude=0.0) - cat = plot_fc_config.get('catalog') + cat = plot_fc_config.get("catalog") cat_args = {} if cat: - cat_args = {'markersize': 7, 'markercolor': 'black', - 'title': 'asd', 'grid': False, - 'legend': False, 'basemap': None, - 'region_border': False} + cat_args = { + "markersize": 7, + "markercolor": "black", + "title": "asd", + "grid": False, + "legend": False, + "basemap": None, + "region_border": False, + } if self.region: self.catalog.filter_spatial(self.region, in_place=True) if isinstance(cat, dict): @@ -779,35 +788,42 @@ def plot_forecasts(self) -> None: winstr = timewindow2str(window) for model in self.models: - fig_path = self.path(winstr, 'forecasts', model.name) + fig_path = self.path(winstr, "forecasts", model.name) start = decimal_year(window[0]) end = decimal_year(window[1]) - time = f'{round(end - start, 3)} years' - plot_args = {'region_border': False, - 'cmap': 'magma', - 'clabel': r'$\log_{10} N\left(M_w \in [{%.2f},' - r'\,{%.2f}]\right)$ per ' - r'$0.1^\circ\times 0.1^\circ $ per %s' % - (min(self.magnitudes), - max(self.magnitudes), time)} - if not self.region or self.region.name == 'global': + time = f"{round(end - start, 3)} years" + plot_args = { + "region_border": False, + "cmap": "magma", + "clabel": r"$\log_{10} N\left(M_w \in [{%.2f}," + r"\,{%.2f}]\right)$ per " + r"$0.1^\circ\times 0.1^\circ $ per %s" + % (min(self.magnitudes), max(self.magnitudes), time), + } + if not self.region or self.region.name == "global": set_global = True else: set_global = False plot_args.update(plot_fc_config) ax = model.get_forecast(winstr, self.region).plot( - set_global=set_global, plot_args=plot_args) + set_global=set_global, plot_args=plot_args + ) if self.region: bbox = self.region.get_bbox() dh = self.region.dh - extent = [bbox[0] - 3 * dh, bbox[1] + 3 * dh, - bbox[2] - 3 * dh, bbox[3] + 3 * dh] + extent = [ + bbox[0] - 3 * dh, + bbox[1] + 3 * dh, + bbox[2] - 3 * dh, + bbox[3] + 3 * dh, + ] else: extent = None if cat: - self.catalog.plot(ax=ax, set_global=set_global, - extent=extent, plot_args=cat_args) + self.catalog.plot( + ax=ax, set_global=set_global, extent=extent, plot_args=cat_args + ) pyplot.savefig(fig_path, dpi=300, facecolor=(0, 0, 0, 0)) @@ -826,36 +842,44 @@ def generate_report(self) -> None: def make_repr(self): - log.info('Creating reproducibility config file') - repr_config = self.path('config') + log.info("Creating reproducibility config file") + repr_config = self.path("config") # Dropping region to results folder if it is a file - region_path = self.region_config.get('path', None) + region_path = self.region_config.get("path", None) if region_path: if isfile(region_path) and region_path: - new_path = join(self.path.rundir, self.region_config['path']) + new_path = join(self.path.rundir, self.region_config["path"]) shutil.copy2(region_path, new_path) - self.region_config.pop('path') - self.region_config['region'] = self.path.rel(new_path) + self.region_config.pop("path") + self.region_config["region"] = self.path.rel(new_path) # Dropping catalog to results folder - target_cat = join(self.path.workdir, self.path.rundir, - split(self._catpath)[-1]) + target_cat = join(self.path.workdir, self.path.rundir, split(self._catpath)[-1]) if not exists(target_cat): shutil.copy2(self.path.abs(self._catpath), target_cat) self._catpath = self.path.rel(target_cat) relative_path = os.path.relpath( - self.path.workdir, os.path.join(self.path.workdir, - self.path.rundir)) + self.path.workdir, os.path.join(self.path.workdir, self.path.rundir) + ) self.path.workdir = relative_path self.to_yml(repr_config, extended=True) - def as_dict(self, exclude: Sequence = ('magnitudes', 'depths', - 'timewindows', 'filetree', - 'task_graph', 'tasks', - 'models', 'tests'), - extended: bool = False) -> dict: + def as_dict( + self, + exclude: Sequence = ( + "magnitudes", + "depths", + "timewindows", + "filetree", + "task_graph", + "tasks", + "models", + "tests", + ), + extended: bool = False, + ) -> dict: """ Converts an Experiment instance into a dictionary. @@ -870,15 +894,15 @@ def as_dict(self, exclude: Sequence = ('magnitudes', 'depths', def _get_value(x): # For each element type, transforms to desired string/output - if hasattr(x, 'as_dict'): + if hasattr(x, "as_dict"): # e.g. model, test, etc. o = x.as_dict() else: try: try: - o = getattr(x, '__name__') + o = getattr(x, "__name__") except AttributeError: - o = getattr(x, 'name') + o = getattr(x, "name") except AttributeError: if isinstance(x, numpy.ndarray): o = x.tolist() @@ -889,16 +913,18 @@ def _get_value(x): def iter_attr(val): # recursive iter through nested dicts/lists if isinstance(val, Mapping): - return {item: iter_attr(val_) for item, val_ in val.items() - if ((item not in exclude) and val_) or extended} + return { + item: iter_attr(val_) + for item, val_ in val.items() + if ((item not in exclude) and val_) or extended + } elif isinstance(val, Sequence) and not isinstance(val, str): return [iter_attr(i) for i in val] else: return _get_value(val) - listwalk = [(i, j) for i, j in self.__dict__.items() if - not i.startswith('_') and j] - listwalk.insert(6, ('catalog', self._catpath)) + listwalk = [(i, j) for i, j in self.__dict__.items() if not i.startswith("_") and j] + listwalk.insert(6, ("catalog", self._catpath)) dictwalk = {i: j for i, j in listwalk} # if self.model_config is None: @@ -930,14 +956,15 @@ class NoAliasDumper(yaml.Dumper): def ignore_aliases(self, data): return True - with open(filename, 'w') as f_: + with open(filename, "w") as f_: yaml.dump( - self.as_dict(**kwargs), f_, + self.as_dict(**kwargs), + f_, Dumper=NoAliasDumper, sort_keys=False, default_flow_style=False, indent=1, - width=70 + width=70, ) @classmethod @@ -957,31 +984,28 @@ def from_yml(cls, config_yml: str, reprdir=None, **kwargs): An :class:`~floatcsep.experiment.Experiment` class instance """ - log.info('Initializing experiment from .yml file') - with open(config_yml, 'r') as yml: + log.info("Initializing experiment from .yml file") + with open(config_yml, "r") as yml: # experiment configuration file _dict = yaml.load(yml, NoAliasLoader) _dir_yml = dirname(config_yml) # uses yml path and append if a rel/abs path is given in config. - _path = _dict.get('path', '') + _path = _dict.get("path", "") # Only ABSOLUTE PATH - _dict['path'] = abspath(join(_dir_yml, _dict.get('path', ''))) + _dict["path"] = abspath(join(_dir_yml, _dict.get("path", ""))) # replaces rundir case reproduce option is used if reprdir: - _dict['original_rundir'] = _dict.get('rundir', 'results') - _dict['rundir'] = relpath(join(_dir_yml, reprdir), - _dict['path']) - _dict['original_config'] = abspath(join(_dict['path'], - _dict['config_file'])) + _dict["original_rundir"] = _dict.get("rundir", "results") + _dict["rundir"] = relpath(join(_dir_yml, reprdir), _dict["path"]) + _dict["original_config"] = abspath(join(_dict["path"], _dict["config_file"])) else: - _dict['rundir'] = _dict.get('rundir', - kwargs.pop('rundir', 'results')) - _dict['config_file'] = relpath(config_yml, _dir_yml) - if 'logging' in _dict: - kwargs.pop('logging') + _dict["rundir"] = _dict.get("rundir", kwargs.pop("rundir", "results")) + _dict["config_file"] = relpath(config_yml, _dir_yml) + if "logging" in _dict: + kwargs.pop("logging") return cls(**_dict, **kwargs) diff --git a/floatcsep/extras.py b/floatcsep/extras.py index e5b18bf..506f5c0 100644 --- a/floatcsep/extras.py +++ b/floatcsep/extras.py @@ -2,8 +2,12 @@ import scipy.stats from matplotlib import pyplot from csep.models import EvaluationResult -from csep.core.poisson_evaluations import _simulate_catalog, paired_t_test, \ - w_test, _poisson_likelihood_test +from csep.core.poisson_evaluations import ( + _simulate_catalog, + paired_t_test, + w_test, + _poisson_likelihood_test, +) from csep.core.exceptions import CSEPCatalogException from typing import Sequence from csep.core.forecasts import GriddedForecast @@ -11,12 +15,13 @@ def binomial_spatial_test( - gridded_forecast: GriddedForecast, - observed_catalog: CSEPCatalog, - num_simulations=1000, - seed=None, - random_numbers=None, - verbose=False): + gridded_forecast: GriddedForecast, + observed_catalog: CSEPCatalog, + num_simulations=1000, + seed=None, + random_numbers=None, + verbose=False, +): """ Performs the binary spatial test on the Forecast using the Observed Catalogs. Note: The forecast and the observations should be scaled to the same time period before calling this function. This increases @@ -37,22 +42,25 @@ def binomial_spatial_test( # simply call likelihood test on catalog data and forecast qs, obs_ll, simulated_ll = _binomial_likelihood_test( - gridded_forecast.spatial_counts(), gridded_catalog_data, + gridded_forecast.spatial_counts(), + gridded_catalog_data, num_simulations=num_simulations, seed=seed, random_numbers=random_numbers, use_observed_counts=True, - verbose=verbose, normalize_likelihood=True) + verbose=verbose, + normalize_likelihood=True, + ) # populate result data structure result = EvaluationResult() result.test_distribution = simulated_ll - result.name = 'Binary S-Test' + result.name = "Binary S-Test" result.observed_statistic = obs_ll result.quantile = qs result.sim_name = gridded_forecast.name result.obs_name = observed_catalog.name - result.status = 'normal' + result.status = "normal" try: result.min_mw = numpy.min(gridded_forecast.magnitudes) except AttributeError: @@ -60,10 +68,13 @@ def binomial_spatial_test( return result -def binary_paired_t_test(forecast: GriddedForecast, - benchmark_forecast: GriddedForecast, - observed_catalog: CSEPCatalog, - alpha=0.05, scale=False): +def binary_paired_t_test( + forecast: GriddedForecast, + benchmark_forecast: GriddedForecast, + observed_catalog: CSEPCatalog, + alpha=0.05, + scale=False, +): """ Computes the binary t-test for gridded earthquake forecasts. @@ -85,16 +96,18 @@ def binary_paired_t_test(forecast: GriddedForecast, # needs some pre-processing to put the forecasts in the context that is required for the t-test. this is different # for cumulative forecasts (eg, multiple time-horizons) and static file-based forecasts. target_event_rate_forecast1p, n_fore1 = forecast.target_event_rates( - observed_catalog, scale=scale) + observed_catalog, scale=scale + ) target_event_rate_forecast2p, n_fore2 = benchmark_forecast.target_event_rates( - observed_catalog, scale=scale) + observed_catalog, scale=scale + ) target_event_rate_forecast1 = forecast.data.ravel()[ - numpy.unique(numpy.nonzero( - observed_catalog.spatial_magnitude_counts().ravel()))] + numpy.unique(numpy.nonzero(observed_catalog.spatial_magnitude_counts().ravel())) + ] target_event_rate_forecast2 = benchmark_forecast.data.ravel()[ - numpy.unique(numpy.nonzero( - observed_catalog.spatial_magnitude_counts().ravel()))] + numpy.unique(numpy.nonzero(observed_catalog.spatial_magnitude_counts().ravel())) + ] # call the primative version operating on ndarray out = _binary_t_test_ndarray( @@ -104,27 +117,28 @@ def binary_paired_t_test(forecast: GriddedForecast, n_fore1, n_fore2, observed_catalog, - alpha=alpha + alpha=alpha, ) # storing this for later result = EvaluationResult() - result.name = 'binary paired T-Test' - result.test_distribution = (out['ig_lower'], out['ig_upper']) - result.observed_statistic = out['information_gain'] - result.quantile = (out['t_statistic'], out['t_critical']) + result.name = "binary paired T-Test" + result.test_distribution = (out["ig_lower"], out["ig_upper"]) + result.observed_statistic = out["information_gain"] + result.quantile = (out["t_statistic"], out["t_critical"]) result.sim_name = (forecast.name, benchmark_forecast.name) result.obs_name = observed_catalog.name - result.status = 'normal' + result.status = "normal" result.min_mw = numpy.min(forecast.magnitudes) return result def sequential_likelihood( - gridded_forecasts: Sequence[GriddedForecast], - observed_catalogs: Sequence[CSEPCatalog], - seed: int = None, - random_numbers=None, ): + gridded_forecasts: Sequence[GriddedForecast], + observed_catalogs: Sequence[CSEPCatalog], + seed: int = None, + random_numbers=None, +): """ Performs the likelihood test on Gridded Forecast using an Observed Catalog. @@ -148,8 +162,7 @@ def sequential_likelihood( likelihoods = [] - for gridded_forecast, observed_catalog in zip(gridded_forecasts, - observed_catalogs): + for gridded_forecast, observed_catalog in zip(gridded_forecasts, observed_catalogs): try: _ = observed_catalog.region.magnitudes except CSEPCatalogException: @@ -159,34 +172,37 @@ def sequential_likelihood( # simply call likelihood test on catalog and forecast qs, obs_ll, simulated_ll = _poisson_likelihood_test( - gridded_forecast.data, gridded_catalog_data, + gridded_forecast.data, + gridded_catalog_data, num_simulations=1, seed=seed, random_numbers=random_numbers, use_observed_counts=False, - normalize_likelihood=False) + normalize_likelihood=False, + ) likelihoods.append(obs_ll) # populate result data structure result = EvaluationResult() result.test_distribution = numpy.arange(len(gridded_forecasts)) - result.name = 'Sequential Likelihood' + result.name = "Sequential Likelihood" result.observed_statistic = likelihoods result.quantile = 1 result.sim_name = gridded_forecast.name result.obs_name = observed_catalog.name - result.status = 'normal' + result.status = "normal" result.min_mw = numpy.min(gridded_forecast.magnitudes) return result def sequential_information_gain( - gridded_forecasts: Sequence[GriddedForecast], - benchmark_forecasts: Sequence[GriddedForecast], - observed_catalogs: Sequence[CSEPCatalog], - seed: int = None, - random_numbers: Sequence = None): + gridded_forecasts: Sequence[GriddedForecast], + benchmark_forecasts: Sequence[GriddedForecast], + observed_catalogs: Sequence[CSEPCatalog], + seed: int = None, + random_numbers: Sequence = None, +): """ Args: @@ -208,8 +224,8 @@ def sequential_information_gain( information_gains = [] for gridded_forecast, reference_forecast, observed_catalog in zip( - gridded_forecasts, benchmark_forecasts, - observed_catalogs): + gridded_forecasts, benchmark_forecasts, observed_catalogs + ): try: _ = observed_catalog.region.magnitudes except CSEPCatalogException: @@ -219,55 +235,60 @@ def sequential_information_gain( # simply call likelihood test on catalog and forecast qs, obs_ll, simulated_ll = _poisson_likelihood_test( - gridded_forecast.data, gridded_catalog_data, + gridded_forecast.data, + gridded_catalog_data, num_simulations=1, seed=seed, random_numbers=random_numbers, use_observed_counts=False, - normalize_likelihood=False) + normalize_likelihood=False, + ) qs, ref_ll, simulated_ll = _poisson_likelihood_test( - reference_forecast.data, gridded_catalog_data, + reference_forecast.data, + gridded_catalog_data, num_simulations=1, seed=seed, random_numbers=random_numbers, use_observed_counts=False, - normalize_likelihood=False) + normalize_likelihood=False, + ) information_gains.append(obs_ll - ref_ll) result = EvaluationResult() result.test_distribution = numpy.arange(len(gridded_forecasts)) - result.name = 'Sequential Likelihood' + result.name = "Sequential Likelihood" result.observed_statistic = information_gains result.quantile = 1 result.sim_name = gridded_forecast.name result.obs_name = observed_catalog.name - result.status = 'normal' + result.status = "normal" result.min_mw = numpy.min(gridded_forecast.magnitudes) return result def vector_poisson_t_w_test( - forecast: GriddedForecast, - benchmark_forecasts: Sequence[GriddedForecast], - catalog: CSEPCatalog): + forecast: GriddedForecast, + benchmark_forecasts: Sequence[GriddedForecast], + catalog: CSEPCatalog, +): """ - Computes Student's t-test for the information gain per earthquake over - a list of forecasts and w-test for normality + Computes Student's t-test for the information gain per earthquake over + a list of forecasts and w-test for normality - Uses all ref_forecasts to perform pair-wise t-tests against the - forecast provided to the function. + Uses all ref_forecasts to perform pair-wise t-tests against the + forecast provided to the function. - Args: - forecast (csep.GriddedForecast): forecast to evaluate - benchmark_forecasts (list of csep.GriddedForecast): list of forecasts to evaluate - catalog (csep.AbstractBaseCatalog): evaluation catalog filtered consistent with forecast - **kwargs: additional default arguments + Args: + forecast (csep.GriddedForecast): forecast to evaluate + benchmark_forecasts (list of csep.GriddedForecast): list of forecasts to evaluate + catalog (csep.AbstractBaseCatalog): evaluation catalog filtered consistent with forecast + **kwargs: additional default arguments - Returns: - results (list of csep.EvaluationResult): iterable of evaluation results + Returns: + results (list of csep.EvaluationResult): iterable of evaluation results """ results_t = [] results_w = [] @@ -276,15 +297,16 @@ def vector_poisson_t_w_test( results_t.append(paired_t_test(forecast, bmf_j, catalog)) results_w.append(w_test(forecast, bmf_j, catalog)) result = EvaluationResult() - result.name = 'Paired T-Test' - result.test_distribution = 'normal' + result.name = "Paired T-Test" + result.test_distribution = "normal" result.observed_statistic = [t.observed_statistic for t in results_t] result.quantile = ( [numpy.abs(t.quantile[0]) - t.quantile[1] for t in results_t], - [w.quantile for w in results_w]) + [w.quantile for w in results_w], + ) result.sim_name = forecast.name result.obs_name = catalog.name - result.status = 'normal' + result.status = "normal" result.min_mw = numpy.min(forecast.magnitudes) return result @@ -318,7 +340,7 @@ def p_series(lambd, niters=500): for p, o in zip(prob_success.ravel(), obs.ravel()): if o == 0: - brier.append(-2 * p ** 2) + brier.append(-2 * p**2) else: brier.append(-2 * (p - 1) ** 2) brier = numpy.sum(brier) @@ -331,10 +353,10 @@ def p_series(lambd, niters=500): brier /= n_dim result = EvaluationResult( - name='Brier score', + name="Brier score", observed_statistic=brier, test_distribution=[0], - sim_name=forecast.name + sim_name=forecast.name, ) return result @@ -356,17 +378,15 @@ def _nbd_number_test_ndarray(fore_cnt, obs_cnt, variance, epsilon=1e-6): var = variance mean = fore_cnt upsilon = 1.0 - ((var - mean) / var) - tau = (mean ** 2 / (var - mean)) + tau = mean**2 / (var - mean) - delta1 = 1.0 - scipy.stats.nbinom.cdf(obs_cnt - epsilon, tau, upsilon, - loc=0) + delta1 = 1.0 - scipy.stats.nbinom.cdf(obs_cnt - epsilon, tau, upsilon, loc=0) delta2 = scipy.stats.nbinom.cdf(obs_cnt + epsilon, tau, upsilon, loc=0) return delta1, delta2 -def negative_binomial_number_test(gridded_forecast, observed_catalog, - variance): +def negative_binomial_number_test(gridded_forecast, observed_catalog, variance): """ Computes "negative binomial N-Test" on a gridded forecast. @@ -399,17 +419,16 @@ def negative_binomial_number_test(gridded_forecast, observed_catalog, epsilon = 1e-6 # stores the actual result of the number test - delta1, delta2 = _nbd_number_test_ndarray(fore_cnt, obs_cnt, variance, - epsilon=epsilon) + delta1, delta2 = _nbd_number_test_ndarray(fore_cnt, obs_cnt, variance, epsilon=epsilon) # store results - result.test_distribution = ('negative_binomial', fore_cnt) - result.name = 'NBD N-Test' + result.test_distribution = ("negative_binomial", fore_cnt) + result.name = "NBD N-Test" result.observed_statistic = obs_cnt result.quantile = (delta1, delta2) result.sim_name = gridded_forecast.name result.obs_name = observed_catalog.name - result.status = 'normal' + result.status = "normal" result.min_mw = numpy.min(gridded_forecast.magnitudes) return result @@ -428,8 +447,7 @@ def binomial_joint_log_likelihood_ndarray(forecast, catalog): It has to be a either zero or positive integer only (No Floating Point) """ # First, we mask the forecast in cells where we could find log=0.0 singularities: - forecast_masked = numpy.ma.masked_where(forecast.ravel() <= 0.0, - forecast.ravel()) + forecast_masked = numpy.ma.masked_where(forecast.ravel() <= 0.0, forecast.ravel()) # Then, we compute the log-likelihood of observing one or more events given a Poisson distribution, i.e., 1 - Pr(0) target_idx = numpy.nonzero(catalog.ravel()) @@ -443,10 +461,16 @@ def binomial_joint_log_likelihood_ndarray(forecast, catalog): return sum(first_term.data + second_term.data) -def _binomial_likelihood_test(forecast_data, observed_data, - num_simulations=1000, random_numbers=None, - seed=None, use_observed_counts=True, - verbose=True, normalize_likelihood=False): +def _binomial_likelihood_test( + forecast_data, + observed_data, + num_simulations=1000, + random_numbers=None, + seed=None, + use_observed_counts=True, + verbose=True, + normalize_likelihood=False, +): """ Computes binary conditional-likelihood test from CSEP using an efficient simulation based approach. Args: @@ -467,8 +491,7 @@ def _binomial_likelihood_test(forecast_data, observed_data, numpy.random.seed(seed) # used to determine where simulated earthquake should be placed, by definition of cumsum these are sorted - sampling_weights = numpy.cumsum(forecast_data.ravel()) / numpy.sum( - forecast_data) + sampling_weights = numpy.cumsum(forecast_data.ravel()) / numpy.sum(forecast_data) # data structures to store results sim_fore = numpy.zeros(sampling_weights.shape) @@ -487,20 +510,20 @@ def _binomial_likelihood_test(forecast_data, observed_data, if use_observed_counts: num_events_to_simulate = int(n_obs) else: - num_events_to_simulate = int( - numpy.random.poisson(expected_forecast_count)) + num_events_to_simulate = int(numpy.random.poisson(expected_forecast_count)) if random_numbers is None: - sim_fore = _simulate_catalog(num_events_to_simulate, - sampling_weights, sim_fore) + sim_fore = _simulate_catalog(num_events_to_simulate, sampling_weights, sim_fore) else: - sim_fore = _simulate_catalog(num_events_to_simulate, - sampling_weights, sim_fore, - random_numbers=random_numbers[idx, :]) + sim_fore = _simulate_catalog( + num_events_to_simulate, + sampling_weights, + sim_fore, + random_numbers=random_numbers[idx, :], + ) # compute joint log-likelihood - current_ll = binomial_joint_log_likelihood_ndarray(forecast_data.data, - sim_fore) + current_ll = binomial_joint_log_likelihood_ndarray(forecast_data.data, sim_fore) # append to list of simulated log-likelihoods simulated_ll.append(current_ll) @@ -508,12 +531,11 @@ def _binomial_likelihood_test(forecast_data, observed_data, # just be verbose if verbose: if (idx + 1) % 100 == 0: - print(f'... {idx + 1} catalogs simulated.') + print(f"... {idx + 1} catalogs simulated.") target_idx = numpy.nonzero(observed_data.ravel()) # observed joint log-likelihood - obs_ll = binomial_joint_log_likelihood_ndarray(forecast_data.data, - observed_data) + obs_ll = binomial_joint_log_likelihood_ndarray(forecast_data.data, observed_data) # quantile score qs = numpy.sum(simulated_ll <= obs_ll) / num_simulations @@ -523,10 +545,13 @@ def _binomial_likelihood_test(forecast_data, observed_data, def binomial_conditional_likelihood_test( - gridded_forecast: GriddedForecast, - observed_catalog: CSEPCatalog, - num_simulations=1000, seed=None, - random_numbers=None, verbose=False): + gridded_forecast: GriddedForecast, + observed_catalog: CSEPCatalog, + num_simulations=1000, + seed=None, + random_numbers=None, + verbose=False, +): """ Performs the binary conditional likelihood test on Gridded Forecast using an Observed Catalog. @@ -557,31 +582,34 @@ def binomial_conditional_likelihood_test( gridded_catalog_data = observed_catalog.spatial_magnitude_counts() # simply call likelihood test on catalog data and forecast - qs, obs_ll, simulated_ll = _binomial_likelihood_test(gridded_forecast.data, - gridded_catalog_data, - num_simulations=num_simulations, - seed=seed, - random_numbers=random_numbers, - use_observed_counts=True, - verbose=verbose, - normalize_likelihood=False) + qs, obs_ll, simulated_ll = _binomial_likelihood_test( + gridded_forecast.data, + gridded_catalog_data, + num_simulations=num_simulations, + seed=seed, + random_numbers=random_numbers, + use_observed_counts=True, + verbose=verbose, + normalize_likelihood=False, + ) # populate result data structure result = EvaluationResult() result.test_distribution = simulated_ll - result.name = 'Binary CL-Test' + result.name = "Binary CL-Test" result.observed_statistic = obs_ll result.quantile = qs result.sim_name = gridded_forecast.name result.obs_name = observed_catalog.name - result.status = 'normal' + result.status = "normal" result.min_mw = numpy.min(gridded_forecast.magnitudes) return result -def _binary_t_test_ndarray(target_event_rates1, target_event_rates2, n_obs, - n_f1, n_f2, catalog, alpha=0.05): +def _binary_t_test_ndarray( + target_event_rates1, target_event_rates2, n_obs, n_f1, n_f2, catalog, alpha=0.05 +): """ Computes binary T test statistic by comparing two target event rate distributions. @@ -605,8 +633,9 @@ def _binary_t_test_ndarray(target_event_rates1, target_event_rates2, n_obs, """ # Some Pre Calculations - Because they are being used repeatedly. N_p = n_obs - N = len(numpy.unique(numpy.nonzero( - catalog.spatial_magnitude_counts().ravel()))) # Number of active bins + N = len( + numpy.unique(numpy.nonzero(catalog.spatial_magnitude_counts().ravel())) + ) # Number of active bins N1 = n_f1 N2 = n_f2 X1 = numpy.log(target_event_rates1) # Log of every element of Forecast 1 @@ -625,8 +654,9 @@ def _binary_t_test_ndarray(target_event_rates1, target_event_rates2, n_obs, # Obtaining the Critical Value of T from T distribution. df = N - 1 - t_critical = scipy.stats.t.ppf(1 - (alpha / 2), - df) # Assuming 2-Tail Distribution for 2 tail, divide 0.05/2. + t_critical = scipy.stats.t.ppf( + 1 - (alpha / 2), df + ) # Assuming 2-Tail Distribution for 2 tail, divide 0.05/2. # Computing Information Gain Interval. ig_lower = information_gain - (t_critical * forecast_std / numpy.sqrt(N)) @@ -634,11 +664,13 @@ def _binary_t_test_ndarray(target_event_rates1, target_event_rates2, n_obs, # If T value greater than T critical, Then both Lower and Upper Confidence Interval limits will be greater than Zero. # If above Happens, Then It means that Forecasting Model 1 is better than Forecasting Model 2. - return {'t_statistic': t_statistic, - 't_critical': t_critical, - 'information_gain': information_gain, - 'ig_lower': ig_lower, - 'ig_upper': ig_upper} + return { + "t_statistic": t_statistic, + "t_critical": t_critical, + "information_gain": information_gain, + "ig_lower": ig_lower, + "ig_upper": ig_upper, + } def log_likelihood_point_process(observation, forecast, cell_area): @@ -661,9 +693,14 @@ def log_likelihood_point_process(observation, forecast, cell_area): return ll[0] # To get a scalar value instead of array -def _standard_deviation(gridded_forecast1, gridded_forecast2, - gridded_observation1, gridded_observation2, cell_area1, - cell_area2): +def _standard_deviation( + gridded_forecast1, + gridded_forecast2, + gridded_observation1, + gridded_observation2, + cell_area1, + cell_area2, +): """ Calculate Variance using forecast 1 and forecast 2. But It is calculated using the forecast values corresponding to the non-zero observations. @@ -716,18 +753,18 @@ def _standard_deviation(gridded_forecast1, gridded_forecast2, X1 = numpy.log(target_fore1) X2 = numpy.log(target_fore2) first_term = (numpy.sum(numpy.power((X1 - X2), 2))) / (N_obs - 1) - second_term = numpy.power(numpy.sum(X1 - X2), 2) / ( - numpy.power(N_obs, 2) - N_obs) + second_term = numpy.power(numpy.sum(X1 - X2), 2) / (numpy.power(N_obs, 2) - N_obs) forecast_variance = first_term - second_term return forecast_variance def paired_ttest_point_process( - forecast: GriddedForecast, - benchmark_forecast: GriddedForecast, - observed_catalog: CSEPCatalog, - alpha=0.05): + forecast: GriddedForecast, + benchmark_forecast: GriddedForecast, + observed_catalog: CSEPCatalog, + alpha=0.05, +): """ Function for T test based on Point process LL. Works for comparing forecasts for different grids @@ -748,71 +785,81 @@ def paired_ttest_point_process( observed_catalog.region = forecast.region gridded_observation1 = forecast.region._get_spatial_magnitude_counts( - observed_catalog, mag_bins=forecast.magnitudes) + observed_catalog, mag_bins=forecast.magnitudes + ) cell_area1 = numpy.array(forecast.region.cell_area) - ll1 = log_likelihood_point_process(gridded_observation1, gridded_forecast1, - cell_area1) + ll1 = log_likelihood_point_process(gridded_observation1, gridded_forecast1, cell_area1) # Forecast 2 gridded_forecast2 = numpy.array(benchmark_forecast.data) gridded_observation2 = benchmark_forecast.region._get_spatial_magnitude_counts( - observed_catalog, - mag_bins=forecast.magnitudes) + observed_catalog, mag_bins=forecast.magnitudes + ) cell_area2 = numpy.array(benchmark_forecast.region.cell_area) - ll2 = log_likelihood_point_process(gridded_observation2, gridded_forecast2, - cell_area2) + ll2 = log_likelihood_point_process(gridded_observation2, gridded_forecast2, cell_area2) assert numpy.sum(gridded_observation1) == numpy.sum( - gridded_observation2), 'Sum of Gridded Catalog is not same' + gridded_observation2 + ), "Sum of Gridded Catalog is not same" N_obs = numpy.sum(gridded_observation1) information_gain = (ll1 - ll2) / N_obs - forecast_variance = _standard_deviation(gridded_forecast1, - gridded_forecast2, - gridded_observation1, - gridded_observation2, cell_area1, - cell_area2) + forecast_variance = _standard_deviation( + gridded_forecast1, + gridded_forecast2, + gridded_observation1, + gridded_observation2, + cell_area1, + cell_area2, + ) forecast_std = numpy.sqrt(forecast_variance) t_statistic = information_gain / (forecast_std / numpy.sqrt(N_obs)) # Obtaining the Critical Value of T from T distribution. df = N_obs - 1 - t_critical = scipy.stats.t.ppf(1 - (alpha / 2), - df) # Assuming 2-Tail Distribution for 2 tail, divide 0.05/2. + t_critical = scipy.stats.t.ppf( + 1 - (alpha / 2), df + ) # Assuming 2-Tail Distribution for 2 tail, divide 0.05/2. # Computing Information Gain Interval. - ig_lower = information_gain - ( - t_critical * forecast_std / numpy.sqrt(N_obs)) - ig_upper = information_gain + ( - t_critical * forecast_std / numpy.sqrt(N_obs)) + ig_lower = information_gain - (t_critical * forecast_std / numpy.sqrt(N_obs)) + ig_upper = information_gain + (t_critical * forecast_std / numpy.sqrt(N_obs)) # If T value greater than T critical, Then both Lower and Upper Confidence Interval limits will be greater than Zero. # If above Happens, Then It means that Forecasting Model 1 is better than Forecasting Model 2. - out = {'t_statistic': t_statistic, - 't_critical': t_critical, - 'information_gain': information_gain, - 'ig_lower': ig_lower, - 'ig_upper': ig_upper} + out = { + "t_statistic": t_statistic, + "t_critical": t_critical, + "information_gain": information_gain, + "ig_lower": ig_lower, + "ig_upper": ig_upper, + } result = EvaluationResult() - result.name = 'Paired T-Test' - result.test_distribution = (out['ig_lower'], out['ig_upper']) - result.observed_statistic = out['information_gain'] - result.quantile = (out['t_statistic'], out['t_critical']) + result.name = "Paired T-Test" + result.test_distribution = (out["ig_lower"], out["ig_upper"]) + result.observed_statistic = out["information_gain"] + result.quantile = (out["t_statistic"], out["t_critical"]) result.sim_name = (forecast.name, benchmark_forecast.name) result.obs_name = observed_catalog.name - result.status = 'normal' + result.status = "normal" result.min_mw = numpy.min(forecast.magnitudes) return result -def plot_negbinom_consistency_test(eval_results, normalize=False, axes=None, - one_sided_lower=False, variance=None, plot_args=None, - show=False): - """ Plots results from CSEP1 tests following the CSEP1 convention. +def plot_negbinom_consistency_test( + eval_results, + normalize=False, + axes=None, + one_sided_lower=False, + variance=None, + plot_args=None, + show=False, +): + """Plots results from CSEP1 tests following the CSEP1 convention. Note: All of the evaluations should be from the same type of evaluation, otherwise the results will not be comparable on the same figure. @@ -850,20 +897,20 @@ def plot_negbinom_consistency_test(eval_results, normalize=False, axes=None, # Parse plot arguments. More can be added here if plot_args is None: plot_args = {} - figsize = plot_args.get('figsize', None) - title = plot_args.get('title', results[0].name) - title_fontsize = plot_args.get('title_fontsize', None) - xlabel = plot_args.get('xlabel', '') - xlabel_fontsize = plot_args.get('xlabel_fontsize', None) - xticks_fontsize = plot_args.get('xticks_fontsize', None) - ylabel_fontsize = plot_args.get('ylabel_fontsize', None) - color = plot_args.get('color', 'black') - linewidth = plot_args.get('linewidth', None) - capsize = plot_args.get('capsize', 4) - hbars = plot_args.get('hbars', True) - tight_layout = plot_args.get('tight_layout', True) - percentile = plot_args.get('percentile', 95) - plot_mean = plot_args.get('mean', False) + figsize = plot_args.get("figsize", None) + title = plot_args.get("title", results[0].name) + title_fontsize = plot_args.get("title_fontsize", None) + xlabel = plot_args.get("xlabel", "") + xlabel_fontsize = plot_args.get("xlabel_fontsize", None) + xticks_fontsize = plot_args.get("xticks_fontsize", None) + ylabel_fontsize = plot_args.get("ylabel_fontsize", None) + color = plot_args.get("color", "black") + linewidth = plot_args.get("linewidth", None) + capsize = plot_args.get("capsize", 4) + hbars = plot_args.get("hbars", True) + tight_layout = plot_args.get("tight_layout", True) + percentile = plot_args.get("percentile", 95) + plot_mean = plot_args.get("mean", False) if axes is None: fig, ax = pyplot.subplots(figsize=figsize) @@ -878,21 +925,26 @@ def plot_negbinom_consistency_test(eval_results, normalize=False, axes=None, observed_statistic = res.observed_statistic mean = res.test_distribution[1] upsilon = 1.0 - ((var - mean) / var) - tau = (mean ** 2 / (var - mean)) - plow = scipy.stats.nbinom.ppf((1 - percentile / 100.) / 2., tau, - upsilon) - phigh = scipy.stats.nbinom.ppf(1 - (1 - percentile / 100.) / 2., - tau, upsilon) - - if not numpy.isinf( - observed_statistic): # Check if test result does not diverges + tau = mean**2 / (var - mean) + plow = scipy.stats.nbinom.ppf((1 - percentile / 100.0) / 2.0, tau, upsilon) + phigh = scipy.stats.nbinom.ppf(1 - (1 - percentile / 100.0) / 2.0, tau, upsilon) + + if not numpy.isinf(observed_statistic): # Check if test result does not diverges percentile_lims = numpy.array([[mean - plow, phigh - mean]]).T - ax.plot(observed_statistic, index, - _get_marker_style(observed_statistic, (plow, phigh), - one_sided_lower)) - ax.errorbar(mean, index, xerr=percentile_lims, - fmt='ko' * plot_mean, capsize=capsize, - linewidth=linewidth, ecolor=color) + ax.plot( + observed_statistic, + index, + _get_marker_style(observed_statistic, (plow, phigh), one_sided_lower), + ) + ax.errorbar( + mean, + index, + xerr=percentile_lims, + fmt="ko" * plot_mean, + capsize=capsize, + linewidth=linewidth, + ecolor=color, + ) # determine the limits to use xlims.append((plow, phigh, observed_statistic)) # we want to only extent the distribution where it falls outside of it in the acceptable tail @@ -901,35 +953,37 @@ def plot_negbinom_consistency_test(eval_results, normalize=False, axes=None, # draw dashed line to infinity xt = numpy.linspace(phigh, 99999, 100) yt = numpy.ones(100) * index - ax.plot(xt, yt, linestyle='--', linewidth=linewidth, - color=color) + ax.plot(xt, yt, linestyle="--", linewidth=linewidth, color=color) else: - print('Observed statistic diverges for forecast %s, index %i.' - ' Check for zero-valued bins within the forecast' % ( - res.sim_name, index)) - ax.barh(index, 99999, left=-10000, height=1, color=['red'], - alpha=0.5) + print( + "Observed statistic diverges for forecast %s, index %i." + " Check for zero-valued bins within the forecast" % (res.sim_name, index) + ) + ax.barh(index, 99999, left=-10000, height=1, color=["red"], alpha=0.5) try: ax.set_xlim(*_get_axis_limits(xlims)) except ValueError: - raise ValueError( - 'All EvaluationResults have infinite observed_statistics') + raise ValueError("All EvaluationResults have infinite observed_statistics") ax.set_yticks(numpy.arange(len(results))) - ax.set_yticklabels([res.sim_name for res in results], - fontsize=ylabel_fontsize) + ax.set_yticklabels([res.sim_name for res in results], fontsize=ylabel_fontsize) ax.set_ylim([-0.5, len(results) - 0.5]) if hbars: yTickPos = ax.get_yticks() if len(yTickPos) >= 2: - ax.barh(yTickPos, numpy.array([99999] * len(yTickPos)), - left=-10000, - height=(yTickPos[1] - yTickPos[0]), color=['w', 'gray'], - alpha=0.2, zorder=0) + ax.barh( + yTickPos, + numpy.array([99999] * len(yTickPos)), + left=-10000, + height=(yTickPos[1] - yTickPos[0]), + color=["w", "gray"], + alpha=0.2, + zorder=0, + ) ax.set_title(title, fontsize=title_fontsize) ax.set_xlabel(xlabel, fontsize=xlabel_fontsize) - ax.tick_params(axis='x', labelsize=xticks_fontsize) + ax.tick_params(axis="x", labelsize=xticks_fontsize) if tight_layout: ax.figure.tight_layout() fig.tight_layout() @@ -944,15 +998,15 @@ def _get_marker_style(obs_stat, p, one_sided_lower): """Returns matplotlib marker style as fmt string""" if obs_stat < p[0] or obs_stat > p[1]: # red circle - fmt = 'ro' + fmt = "ro" else: # green square - fmt = 'gs' + fmt = "gs" if one_sided_lower: if obs_stat < p[0]: - fmt = 'ro' + fmt = "ro" else: - fmt = 'gs' + fmt = "gs" return fmt @@ -962,4 +1016,3 @@ def _get_axis_limits(pnts, border=0.05): x_max = numpy.max(pnts) xd = (x_max - x_min) * border return (x_min - xd, x_max + xd) - diff --git a/floatcsep/logger.py b/floatcsep/logger.py index 7964b01..d198130 100644 --- a/floatcsep/logger.py +++ b/floatcsep/logger.py @@ -1,12 +1,13 @@ import logging.config -LOG_NAME = 'experiment.log' +LOG_NAME = "experiment.log" LOGGING_CONFIG = { "version": 1, "formatters": { "default": { - "format": '%(asctime)s %(levelname)s - %(message)s', - "datefmt": '%Y-%m-%d %H:%M:%S'}, + "format": "%(asctime)s %(levelname)s - %(message)s", + "datefmt": "%Y-%m-%d %H:%M:%S", + }, }, "handlers": { "console": { @@ -16,31 +17,23 @@ "stream": "ext://sys.stdout", } }, - 'loggers': { - 'floatLogger': { - 'level': 'DEBUG', - 'handlers': ['console'], - 'propagate': False - } - }, - 'root': { - 'level': 'INFO', - 'handlers': ['console']} + "loggers": {"floatLogger": {"level": "DEBUG", "handlers": ["console"], "propagate": False}}, + "root": {"level": "INFO", "handlers": ["console"]}, } def add_fhandler(filename): formatter = logging.Formatter( - fmt=LOGGING_CONFIG['formatters']['default']['format'], - datefmt=LOGGING_CONFIG['formatters']['default']['datefmt'] + fmt=LOGGING_CONFIG["formatters"]["default"]["format"], + datefmt=LOGGING_CONFIG["formatters"]["default"]["datefmt"], ) fhandler = logging.FileHandler(filename) fhandler.setFormatter(formatter) fhandler.setLevel(logging.DEBUG) - logging.getLogger('floatLogger').addHandler(fhandler) + logging.getLogger("floatLogger").addHandler(fhandler) logging.config.dictConfig(LOGGING_CONFIG) -logging.getLogger('numexpr').setLevel(logging.WARNING) -logging.getLogger('matplotlib').setLevel(logging.CRITICAL) +logging.getLogger("numexpr").setLevel(logging.WARNING) +logging.getLogger("matplotlib").setLevel(logging.CRITICAL) diff --git a/floatcsep/model.py b/floatcsep/model.py index 3a7b222..5ed875a 100644 --- a/floatcsep/model.py +++ b/floatcsep/model.py @@ -1,116 +1,64 @@ import json +import logging import os -import numpy -import csep -import git import subprocess -import logging - -from typing import List, Callable, Union, Mapping, Sequence +from abc import ABC, abstractmethod from datetime import datetime +from typing import List, Callable, Union, Mapping, Sequence +import csep +import git +import numpy from csep.core.forecasts import GriddedForecast, CatalogForecast from csep.utils.time_utils import decimal_year from floatcsep.accessors import from_zenodo, from_git -from floatcsep.readers import ForecastParsers, HDF5Serializer, check_format -from floatcsep.utils import timewindow2str, str2timewindow +from floatcsep.readers import ForecastParsers, HDF5Serializer from floatcsep.registry import ModelTree +from floatcsep.utils import timewindow2str, str2timewindow -log = logging.getLogger('floatLogger') +log = logging.getLogger("floatLogger") -class Model: +class Model(ABC): """ - - Class defining a forecast generating Model. Initializes a model source - either from filesystem or web repositories, contains information about - the Model's typology, and maps accordingly to a forecast generating - function. + The Model class represents a forecast generating system. It can represent a source code, a + collection or a single forecast, etc. A Model can be instantiated from either the filesystem + or host repositories. Args: name (str): Name of the model - model_path (str): Relative path of the model (file or runnable code) - to the Experiment's instance path - forecast_unit (float): Temporal unit of the forecast. Default to - years in time-independent models and days - in time-dependent - use_db (bool): Flag the use of a database for speed/memory purposes - func (str, ~collections.abc.Callable): Forecast generating function - (for code models) - func_kwargs (dict): Arguments to pass into `func` + model_path (str): Relative path of the model (file or code) to the work directory zenodo_id (int): Zenodo ID or record of the Model giturl (str): Link to a git repository repo_hash (str): Specific commit/branch/tag hash. authors (list[str]): Authors' names metadata doi: Digital Object Identifier metadata: - """ - ''' - Model characteristics: - Forecast: - Gridded - - Catalog - Updating: - Time-Independent - - Time-Dependent - Source: - File - - Code - Model typology: - - To implement in beta version: - - (grid - ti - file): e.g. CSEP1 style gridded forecasts - To implement in further versions: - - (grid - ti - code): e.g. smoothed-seismicity model - - (grid - td - code): e.g. EEPAS, STEP, Italy-NZ OEF models - - (cat - td - code): e.g. ETAS model code - - (cat - td - file): e.g OEF-ready Forecasts - - (grid - td - file): e.g OEF-ready Forecasts - - Get forecasts options: - - FILE - read from file, scale in runtime - - drop to db, scale from function in runtime - - CODE - run, read from file - - run, store in db, read from db - - ''' - - def __init__(self, name: str, model_path: str, - forecast_unit: float = 1, use_db: bool = False, - func: Union[str, Callable] = None, func_kwargs: dict = None, - zenodo_id: int = None, giturl: str = None, - repo_hash: str = None, authors: List[str] = None, - doi: str = None, **kwargs) -> None: - - # todo: - # - Instantiate from source code - - # Instantiate attributes + def __init__( + self, + name: str, + model_path: str, + zenodo_id: int = None, + giturl: str = None, + repo_hash: str = None, + authors: List[str] = None, + doi: str = None, + **kwargs, + ): + self.name = name + self.model_path = model_path self.zenodo_id = zenodo_id self.giturl = giturl self.repo_hash = repo_hash self.authors = authors self.doi = doi - self.forecast_unit = forecast_unit - self.func = func - self.func_kwargs = func_kwargs or {} - self.use_db = use_db - - self.path = ModelTree(kwargs.get('workdir', os.getcwd()), model_path) - # Set model temporal class - if self.func: - # Time-Dependent - self.model_class = 'td' - self.build = kwargs.get('build', 'docker') - self.run_prefix = '' - - else: - # Time-Independent - self.model_class = kwargs.get('model_class', 'ti') - - # Instantiate attributes to be filled in run-time + self.path = None self.forecasts = {} + self.__dict__.update(**kwargs) @property @@ -119,69 +67,32 @@ def dir(self) -> str: Returns: The directory containing the model source. """ - if os.path.isdir(self.path('path')): - return self.path('path') + if os.path.isdir(self.path("path")): + return self.path("path") else: - return os.path.dirname(self.path('path')) + return os.path.dirname(self.path("path")) + @abstractmethod def stage(self, timewindows=None) -> None: + """Prepares the stage for a model run. Can be""" + pass + + @abstractmethod + def get_forecast(self, tstring: str, region=None): + """Retrieves the forecast based on a time window.""" + pass + + @abstractmethod + def create_forecast(self, tstring: str, **kwargs) -> None: + """Creates a forecast based on the model's logic.""" + pass + + def get_source( + self, zenodo_id: int = None, giturl: str = None, force: bool = False, **kwargs + ) -> None: """ - Pre-steps to make the model runnable before integrating - - Get from filesystem, Zenodo or Git - - Pre-check model fileformat - - Initialize database - - Run model quality assurance (unit tests, runnable from floatcsep) - """ - self.get_source(self.zenodo_id, self.giturl, branch=self.repo_hash) - if self.use_db: - self.init_db() - - if self.model_class == 'td': - self.build_model() - self.path.build_tree(timewindows=timewindows, - model_class=self.model_class, - prefix=self.__dict__.get('prefix', self.name), - args_file=self.__dict__.get('args_file', None), - input_cat=self.__dict__.get('input_cat', None)) - - def build_model(self): - - if self.build == 'pip' or self.build == 'venv': - venv = os.path.join(self.path('path'), - self.__dict__.get('venv', 'venv')) - venvact = os.path.join(venv, 'bin', 'activate') - - if not os.path.exists(venv): - log.info(f'Building model {self.name} using pip') - subprocess.run(['python', '-m', 'venv', venv]) - log.info(f'\tVirtual environment created in {venv}') - build_cmd = f'source {venvact} && ' \ - f'pip install --upgrade pip && ' \ - f'pip install -e {self.path("path")}' - - cmd = ['bash', '-c', build_cmd] + Search, download or clone the model source in the filesystem, zenodo. - log.info(f'\tInstalling dependencies') - - process = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True) - for line in process.stdout: - log.info(f'\t{line[:-1]}') - process.wait() - log.info(f'\tEnvironment ready') - log.warning(f'\tNested environments is not fully supported. ' - f'Consider using docker instead') - - self.run_prefix = f'cd {self.path("path")} && source {venvact} && ' - - def get_source(self, zenodo_id: int = None, giturl: str = None, - force: bool = False, - **kwargs) -> None: - """ - - Search, download or clone the model source in the filesystem, zenodo and git, respectively. Identifies if the instance path points to a file or to its parent directory @@ -193,45 +104,133 @@ def get_source(self, zenodo_id: int = None, giturl: str = None, force (bool): Forces to re-query the model from a web repository **kwargs: see :func:`~floatcsep.utils.from_zenodo` and :func:`~floatcsep.utils.from_git` - - """ - if os.path.exists(self.path('path')) and not force: + if os.path.exists(self.path("path")) and not force: return os.makedirs(self.dir, exist_ok=True) if zenodo_id: - log.info(f'Retrieving model {self.name} from zenodo id: ' - f'{zenodo_id}') + log.info(f"Retrieving model {self.name} from zenodo id: " f"{zenodo_id}") try: - from_zenodo(zenodo_id, self.dir if self.path.fmt - else self.path('path'), force=force) + from_zenodo( + zenodo_id, + self.dir if self.path.fmt else self.path("path"), + force=force, + ) except (KeyError, TypeError) as msg: - raise KeyError(f'Zenodo identifier is not valid: {msg}') + raise KeyError(f"Zenodo identifier is not valid: {msg}") elif giturl: - log.info(f'Retrieving model {self.name} from git url: ' - f'{giturl}') + log.info(f"Retrieving model {self.name} from git url: " f"{giturl}") try: - from_git(giturl, self.dir if self.path.fmt - else self.path('path'), **kwargs) + from_git(giturl, self.dir if self.path.fmt else self.path("path"), **kwargs) except (git.NoSuchPathError, git.CommandError) as msg: - raise git.NoSuchPathError(f'git url was not found {msg}') + raise git.NoSuchPathError(f"git url was not found {msg}") else: - raise FileNotFoundError('Model has no path or identified') + raise FileNotFoundError("Model has no path or identified") - if not os.path.exists(self.dir) or not \ - os.path.exists(self.path('path')): + if not os.path.exists(self.dir) or not os.path.exists(self.path("path")): raise FileNotFoundError( f"Directory '{self.dir}' or file {self.path}' do not exist. " f"Please check the specified 'path' matches the repo " - f"structure") + f"structure" + ) - def init_db(self, dbpath: str = '', force: bool = False) -> None: + def as_dict(self, excluded=("name", "forecasts", "workdir")): """ - Initializes the database if `use_db` is True. If the model source is a - file, seralizes the forecast into a HDF5 file. If source is a + Returns: + Dictionary with relevant attributes. Model can be re-instantiated from this dict + """ + + def _get_value(x): + # For each element type, transforms to desired string/output + if hasattr(x, "as_dict"): + # e.g. model, evaluation, filetree, etc. + o = x.as_dict() + else: + try: + try: + o = getattr(x, "__name__") + except AttributeError: + o = getattr(x, "name") + except AttributeError: + if isinstance(x, numpy.ndarray): + o = x.tolist() + else: + o = x + return o + + def iter_attr(val): + # recursive iter through nested dicts/lists + if isinstance(val, Mapping): + return { + item: iter_attr(val_) + for item, val_ in val.items() + if ((item not in excluded) and val_) + } + elif isinstance(val, Sequence) and not isinstance(val, str): + return [iter_attr(i) for i in val] + else: + return _get_value(val) + + list_walk = [ + (i, j) for i, j in sorted(self.__dict__.items()) if not i.startswith("_") and j + ] + + dict_walk = {i: j for i, j in list_walk} + + return {self.name: iter_attr(dict_walk)} + + @classmethod + def from_dict(cls, record: dict, **kwargs): + """ + Returns a Model instance from a dictionary containing the required atrributes. Can be + used to quickly instantiate from a .yml file. + + Args: + record (dict): Contains the keywords from the ``__init__`` method. + + Note: + Must have either an explicit key `name`, or it must have + exactly one key with the model's name, whose values are + the remaining ``__init__`` keywords. + + Returns: + A Model instance + """ + + if "name" in record.keys(): + return cls(**record) + elif len(record) != 1: + raise IndexError("A single model has not been passed") + name = next(iter(record)) + return cls(name=name, **record[name], **kwargs) + + +class TimeIndependentModel(Model): + """ + A Model that does not change in time, commonly represented by static data. + + Args + name (str): The name of the model. + model_path (str): The path to the model data. + forecast_unit (float): The unit of time for the forecast. + store_db (bool): flag to indicate whether to store the model in a database. + """ + + def __init__(self, name: str, model_path: str, forecast_unit=1, store_db=False, **kwargs): + super().__init__(name, model_path, **kwargs) + self.forecast_unit = forecast_unit + self.store_db = store_db + + self.path = ModelTree(kwargs.get("workdir", os.getcwd()), model_path) + + def init_db(self, dbpath: str = "", force: bool = False) -> None: + """ + Initializes the database if `use_db` is True. + + If the model source is a file, serializes the forecast into a HDF5 file. If source is a generating function or code, creates an empty DB Args: @@ -239,81 +238,78 @@ def init_db(self, dbpath: str = '', force: bool = False) -> None: replaced with an `hdf5` extension force (bool): Forces the serialization even if the DB already exists - """ - # todo Think about distinction btwn 'TI' and 'Gridded' models. - - if self.model_class == 'ti': - parser = getattr(ForecastParsers, self.path.fmt) - rates, region, mag = parser(self.path('path')) - db_func = HDF5Serializer.grid2hdf5 - if not dbpath: - dbpath = self.path.path.replace(self.path.fmt, 'hdf5') - self.path.database = dbpath + parser = getattr(ForecastParsers, self.path.fmt) + rates, region, mag = parser(self.path("path")) + db_func = HDF5Serializer.grid2hdf5 - if not os.path.isfile(self.path.abs(dbpath)) or force: - log.info(f'Serializing model {self.name} into HDF5 format') - db_func(rates, region, mag, - hdf5_filename=self.path.abs(dbpath), - unit=self.forecast_unit) + if not dbpath: + dbpath = self.path.path.replace(self.path.fmt, "hdf5") + self.path.database = dbpath - else: - raise NotImplementedError('TD serialization not implemented') + if not os.path.isfile(self.path.abs(dbpath)) or force: + log.info(f"Serializing model {self.name} into HDF5 format") + db_func( + rates, + region, + mag, + hdf5_filename=self.path.abs(dbpath), + unit=self.forecast_unit, + ) def rm_db(self) -> None: - """ Clean up the generated HDF5 File""" + """Clean up the generated HDF5 File.""" + pass - if self.use_db: - if os.path.isfile(self.path) and self.fmt == 'hdf5': - os.remove(self.path) - else: - log.warning(f"The HDF5 file {self.path} does not exist") + def stage(self, timewindows: Union[str, List[datetime]] = None) -> None: + """ + Acquire the forecast data if it is not in the file system. + Sets internally the paths (or database pointers) to the forecast data. - def get_forecast(self, - tstring: Union[str, list] = None, - region=None - ) -> Union[GriddedForecast, CatalogForecast, - List[GriddedForecast], List[CatalogForecast]]: + Args: + timewindows (str, list): time_windows that the forecast data represents. - """ Wrapper that just returns a forecast, which should hide the - access method (db storage, ti_td, etc.) under the hood""" + """ + self.get_source(self.zenodo_id, self.giturl, branch=self.repo_hash) + if self.store_db: + self.init_db() - if self.model_class == 'ti': - if isinstance(tstring, str): - # If only one timewindow string is passed - try: - # If they are retrieved from the Evaluation class - return self.forecasts[tstring] - except KeyError: - # In case they are called from postprocess - self.create_forecast(tstring) - return self.forecasts[tstring] - else: - # If multiple timewindow strings are passed - forecasts = [] - for tw in tstring: - if tw in self.forecasts.keys(): - forecasts.append(self.forecasts[tw]) - if not forecasts: - raise KeyError( - f'Forecasts {*tstring,} have not been created yet') - return forecasts - - elif self.model_class == 'td': - if isinstance(tstring, str): - # If one time window string is passed - # default forecast naming - fc_path = self.path('forecasts', tstring) - # default forecasts folder - # A region must be given to the forecast - return csep.load_catalog_forecast(fc_path, region=region) + self.path.build_tree( + timewindows=timewindows, + model_class="ti", + prefix=self.__dict__.get("prefix", self.name), + ) - def create_forecast(self, tstring: str, - **kwargs) -> None: + def get_forecast( + self, tstring: Union[str, list] = None, region=None + ) -> Union[GriddedForecast, CatalogForecast, List[GriddedForecast], List[CatalogForecast]]: + """ + Wrapper that just returns a forecast when requested. """ - Creates a forecast from the model source and a given time window + if isinstance(tstring, str): + # If only one time_window string is passed + try: + # If they are retrieved from the Evaluation class + return self.forecasts[tstring] + except KeyError: + # In case they are called from postprocess + self.create_forecast(tstring) + return self.forecasts[tstring] + else: + # If multiple time_window strings are passed + forecasts = [] + for tw in tstring: + if tw in self.forecasts.keys(): + forecasts.append(self.forecasts[tw]) + if not forecasts: + raise KeyError(f"Forecasts {*tstring,} have not been created yet") + return forecasts + + def create_forecast(self, tstring: str, **kwargs) -> None: + """ + Creates a forecast from the model source and a given time window. Note: The argument `tstring` is formatted according to how the Experiment @@ -325,28 +321,14 @@ def create_forecast(self, tstring: str, tstring: String representing the start and end of the forecast, formatted as 'YY1-MM1-DD1_YY2-MM2-DD2'. **kwargs: - """ start_date, end_date = str2timewindow(tstring) - # Model src is a file - if self.model_class == 'ti': - self.forecast_from_file(start_date, end_date, **kwargs) - # Model src is a func or binary - else: - fc_path = self.path('forecasts', tstring) - if kwargs.get('force') or not os.path.exists(fc_path): - self.forecast_from_func(start_date, end_date, - **self.func_kwargs, - **kwargs) - else: - log.info(f'Forecast of {tstring} of model {self.name} already ' - f'exists') + self.forecast_from_file(start_date, end_date, **kwargs) - def forecast_from_file(self, start_date: datetime, end_date: datetime, - **kwargs) -> None: + def forecast_from_file(self, start_date: datetime, end_date: datetime, **kwargs) -> None: """ + Generates a forecast from a file, by parsing and scaling it to. - Generates a forecast from a file, by parsing and scaling it to the desired time window. H Args: @@ -354,19 +336,18 @@ def forecast_from_file(self, start_date: datetime, end_date: datetime, end_date (~datetime.datetime): End of the forecast **kwargs: Keyword arguments for :class:`csep.core.forecasts.GriddedForecast` - """ time_horizon = decimal_year(end_date) - decimal_year(start_date) tstring = timewindow2str([start_date, end_date]) - f_path = self.path('forecasts', tstring) + f_path = self.path("forecasts", tstring) f_parser = getattr(ForecastParsers, self.path.fmt) rates, region, mags = f_parser(f_path) forecast = GriddedForecast( - name=f'{self.name}', + name=f"{self.name}", data=rates, region=region, magnitudes=mags, @@ -381,27 +362,156 @@ def forecast_from_file(self, start_date: datetime, end_date: datetime, log.debug( f"Model {self.name}:\n" f"\tForecast expected count: {forecast.event_count:.2f}" - f" with scaling parameter: {time_horizon:.1f}") + f" with scaling parameter: {time_horizon:.1f}" + ) self.forecasts[tstring] = forecast - def forecast_from_func(self, start_date: datetime, end_date: datetime, - **kwargs) -> None: + +class TimeDependentModel(Model): + """ + Model that creates varying forecasts depending on a time window. Requires either a + collection of Forecasts or a function that returns a Forecast. + + """ + + def __init__( + self, + name: str, + model_path: str, + func: Union[str, Callable] = None, + func_kwargs: dict = None, + **kwargs, + ) -> None: + + super().__init__(name, model_path, **kwargs) + + self.func = func + self.func_kwargs = func_kwargs or {} + + self.path = ModelTree(kwargs.get("workdir", os.getcwd()), model_path) + self.build = kwargs.get("build", "docker") + self.run_prefix = "" + + def build_model(self): + + if self.build == "pip" or self.build == "venv": + venv = os.path.join(self.path("path"), self.__dict__.get("venv", "venv")) + venvact = os.path.join(venv, "bin", "activate") + + if not os.path.exists(venv): + log.info(f"Building model {self.name} using pip") + subprocess.run(["python", "-m", "venv", venv]) + log.info(f"\tVirtual environment created in {venv}") + build_cmd = ( + f"source {venvact} && " + f"pip install --upgrade pip && " + f'pip install {self.path("path")}' + ) + + cmd = ["bash", "-c", build_cmd] + + log.info("\tInstalling dependencies") + + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + ) + for line in process.stdout: + log.info(f"\t{line[:-1]}") + process.wait() + log.info("\tEnvironment ready") + log.warning( + "\tNested environments is not fully supported. " + "Consider using docker instead" + ) + + self.run_prefix = f'cd {self.path("path")} && source {venvact} && ' + + def stage(self, timewindows=None) -> None: + """ + Pre-steps to make the model runnable before integrating. + + - Get from filesystem, Zenodo or Git + - Pre-check model fileformat + - Initialize database + - Run model quality assurance (unit tests, runnable from floatcsep) + """ + self.get_source(self.zenodo_id, self.giturl, branch=self.repo_hash) + self.build_model() + self.path.build_tree( + timewindows=timewindows, + model_class="td", + prefix=self.__dict__.get("prefix", self.name), + args_file=self.__dict__.get("args_file", None), + input_cat=self.__dict__.get("input_cat", None), + ) + + def get_forecast( + self, tstring: Union[str, list] = None, region=None + ) -> Union[GriddedForecast, CatalogForecast, List[GriddedForecast], List[CatalogForecast]]: + """Wrapper that just returns a forecast, hiding the access method under the hood""" + + if isinstance(tstring, str): + # If one time window string is passed + fc_path = self.path("forecasts", tstring) + # A region must be given to the forecast + return csep.load_catalog_forecast(fc_path, region=region) + + else: + forecasts = [] + for t in tstring: + fc_path = self.path("forecasts", t) + # A region must be given to the forecast + forecasts.append(csep.load_catalog_forecast(fc_path, region=region)) + return forecasts + + def create_forecast(self, tstring: str, **kwargs) -> None: + """ + Creates a forecast from the model source and a given time window. + + Note: + The argument `tstring` is formatted according to how the Experiment + handles timewindows, specified in the functions + :func:'floatcsep.utils.timewindow2str` and + :func:'floatcsep.utils.str2timewindow` + + Args: + tstring: String representing the start and end of the forecast, + formatted as 'YY1-MM1-DD1_YY2-MM2-DD2'. + **kwargs: + """ + start_date, end_date = str2timewindow(tstring) + + # Model src is a func or binary + + fc_path = self.path("forecasts", tstring) + if kwargs.get("force") or not os.path.exists(fc_path): + self.forecast_from_func(start_date, end_date, **self.func_kwargs, **kwargs) + else: + log.info(f"Forecast of {tstring} of model {self.name} already " f"exists") + + def forecast_from_func(self, start_date: datetime, end_date: datetime, **kwargs) -> None: self.prepare_args(start_date, end_date, **kwargs) - log.info(f'Running {self.name} using {self.build}:' - f' {timewindow2str([start_date, end_date])}') + log.info( + f"Running {self.name} using {self.build}:" + f" {timewindow2str([start_date, end_date])}" + ) self.run_model() def prepare_args(self, start, end, **kwargs): - filepath = self.path('args_file') + filepath = self.path("args_file") fmt = os.path.splitext(filepath)[1] - if fmt == '.txt': + if fmt == ".txt": + def replace_arg(arg, val, fp): - with open(fp, 'r') as filearg_: + with open(fp, "r") as filearg_: lines = filearg_.readlines() pattern_exists = False @@ -412,107 +522,60 @@ def replace_arg(arg, val, fp): break # assume there's only one occurrence of the key if not pattern_exists: lines.append(f"{arg} = {val}\n") - with open(fp, 'w') as file: + with open(fp, "w") as file: file.writelines(lines) - replace_arg('start_date', start.isoformat(), filepath) - replace_arg('end_date', end.isoformat(), filepath) + replace_arg("start_date", start.isoformat(), filepath) + replace_arg("end_date", end.isoformat(), filepath) for i, j in kwargs.items(): replace_arg(i, j, filepath) - elif fmt == '.json': - with open(filepath, 'r') as file_: + elif fmt == ".json": + with open(filepath, "r") as file_: args = json.load(file_) - args['start_date'] = start.isoformat() - args['end_date'] = end.isoformat() + args["start_date"] = start.isoformat() + args["end_date"] = end.isoformat() args.update(kwargs) - with open(filepath, 'w') as file_: + with open(filepath, "w") as file_: json.dump(args, file_, indent=2) def run_model(self): - if self.build == 'pip' or self.build == 'venv': + if self.build == "pip" or self.build == "venv": run_func = f'{self.func} {self.path("args_file")}' - cmd = ['bash', '-c', f'{self.run_prefix} {run_func}'] - process = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - universal_newlines=True) + cmd = ["bash", "-c", f"{self.run_prefix} {run_func}"] + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + ) for line in process.stdout: - log.info(f'\t{line[:-1]}') + log.info(f"\t{line[:-1]}") process.wait() - def as_dict(self, excluded=('name', 'forecasts', 'workdir')): - """ - - Returns: - Dictionary with relevant attributes. Model can be reinstantiated - from this dict - - """ - - def _get_value(x): - # For each element type, transforms to desired string/output - if hasattr(x, 'as_dict'): - # e.g. model, evaluation, filetree, etc. - o = x.as_dict() - else: - try: - try: - o = getattr(x, '__name__') - except AttributeError: - o = getattr(x, 'name') - except AttributeError: - if isinstance(x, numpy.ndarray): - o = x.tolist() - else: - o = x - return o - - def iter_attr(val): - # recursive iter through nested dicts/lists - if isinstance(val, Mapping): - return {item: iter_attr(val_) for item, val_ in val.items() - if ((item not in excluded) and val_)} - elif isinstance(val, Sequence) and not isinstance(val, str): - return [iter_attr(i) for i in val] - else: - return _get_value(val) - listwalk = [(i, j) for i, j in sorted(self.__dict__.items()) if - not i.startswith('_') and j] +class ModelFactory: + @staticmethod + def create_model(model_cfg) -> Model: - dictwalk = {i: j for i, j in listwalk} - # if self.model_config is None: - # dictwalk['models'] = iter_attr(self.models) - # if self.test_config is None: - # dictwalk['tests'] = iter_attr(self.tests) + model_path = [*model_cfg.values()][0]['model_path'] + workdir = [*model_cfg.values()][0].get('workdir', '') + model_class = [*model_cfg.values()][0].get('class', '') - return {self.name: iter_attr(dictwalk)} + if model_class == 'ti': + return TimeIndependentModel.from_dict(model_cfg) - @classmethod - def from_dict(cls, record: dict, **kwargs): - """ - Returns a Model instance from a dictionary containing the required - atrributes. Can be used to quickly instantiate from a .yml file. + elif model_class == 'td': + return TimeDependentModel.from_dict(model_cfg) + if os.path.isfile(os.path.join(workdir, model_path)): + return TimeIndependentModel.from_dict(model_cfg) - Args: - record (dict): Contains the keywords from the ``__init__`` method. + elif "func" in [*model_cfg.values()][0]: + return TimeDependentModel.from_dict(model_cfg) - Note: - Must have either an explicit key `name`, or it must have - exactly one key with the model's name, whose values are - the remaining ``__init__`` keywords. - - Returns: - A Model instance - """ + else: + return TimeIndependentModel.from_dict(model_cfg) - if 'name' in record.keys(): - return cls(**record) - elif len(record) != 1: - raise IndexError('A single model has not been passed') - name = next(iter(record)) - return cls(name=name, **record[name], **kwargs) diff --git a/floatcsep/readers.py b/floatcsep/readers.py index d7527df..526a918 100644 --- a/floatcsep/readers.py +++ b/floatcsep/readers.py @@ -8,6 +8,7 @@ from csep.core.regions import QuadtreeGrid2D, CartesianGrid2D import time import logging + log = logging.getLogger(__name__) @@ -19,23 +20,20 @@ def dat(filename): all_polys = data[:, :4] all_poly_mask = data[:, -1] sorted_idx = numpy.sort( - numpy.unique(all_polys, return_index=True, axis=0)[1], - kind='stable') + numpy.unique(all_polys, return_index=True, axis=0)[1], kind="stable" + ) unique_poly = all_polys[sorted_idx] poly_mask = all_poly_mask[sorted_idx] all_mws = data[:, -4] - sorted_idx = numpy.sort(numpy.unique(all_mws, return_index=True)[1], - kind='stable') + sorted_idx = numpy.sort(numpy.unique(all_mws, return_index=True)[1], kind="stable") mws = all_mws[sorted_idx] - bboxes = [((i[0], i[2]), (i[0], i[3]), (i[1], i[3]), (i[1], i[2])) - for i in unique_poly] + bboxes = [((i[0], i[2]), (i[0], i[3]), (i[1], i[3]), (i[1], i[2])) for i in unique_poly] dh = float(unique_poly[0, 3] - unique_poly[0, 2]) n_mag_bins = len(mws) rates = data[:, -2].reshape(len(bboxes), n_mag_bins) - region = CartesianGrid2D( - [Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) + region = CartesianGrid2D([Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) return rates, region, mws @@ -49,73 +47,73 @@ def xml(filename, verbose=False): cells = [] cell_dim = {} for k, children in enumerate(list(root[0])): - if 'modelName' in children.tag: + if "modelName" in children.tag: name_xml = children.text - metadata['name'] = name_xml - elif 'author' in children.tag: + metadata["name"] = name_xml + elif "author" in children.tag: author_xml = children.text - metadata['author'] = author_xml - elif 'forecastStartDate' in children.tag: - start_date = children.text.replace('Z', '') - metadata['forecastStartDate'] = start_date - elif 'forecastEndDate' in children.tag: - end_date = children.text.replace('Z', '') - metadata['forecastEndDate'] = end_date - elif 'defaultMagBinDimension' in children.tag: + metadata["author"] = author_xml + elif "forecastStartDate" in children.tag: + start_date = children.text.replace("Z", "") + metadata["forecastStartDate"] = start_date + elif "forecastEndDate" in children.tag: + end_date = children.text.replace("Z", "") + metadata["forecastEndDate"] = end_date + elif "defaultMagBinDimension" in children.tag: m_bin_width = float(children.text) - metadata['defaultMagBinDimension'] = m_bin_width - elif 'lastMagBinOpen' in children.tag: + metadata["defaultMagBinDimension"] = m_bin_width + elif "lastMagBinOpen" in children.tag: lastmbin = float(children.text) - metadata['lastMagBinOpen'] = lastmbin - elif 'defaultCellDimension' in children.tag: + metadata["lastMagBinOpen"] = lastmbin + elif "defaultCellDimension" in children.tag: cell_dim = {i[0]: float(i[1]) for i in children.attrib.items()} - metadata['defaultCellDimension'] = cell_dim - elif 'depthLayer' in children.tag: + metadata["defaultCellDimension"] = cell_dim + elif "depthLayer" in children.tag: depth = {i[0]: float(i[1]) for i in root[0][k].attrib.items()} cells = root[0][k] - metadata['depthLayer'] = depth + metadata["depthLayer"] = depth if verbose: - log.debug(f'Forecast with metadata:\n{metadata}') + log.debug(f"Forecast with metadata:\n{metadata}") for cell in cells: cell_data = [] m_cell_bins = [] for i, m in enumerate(cell.iter()): if i == 0: - cell_data.extend([float(m.attrib['lon']), - float(m.attrib['lat'])]) + cell_data.extend([float(m.attrib["lon"]), float(m.attrib["lat"])]) else: cell_data.append(float(m.text)) - m_cell_bins.append(float(m.attrib['m'])) + m_cell_bins.append(float(m.attrib["m"])) data_ijm.append(cell_data) m_bins.append(m_cell_bins) try: data_ijm = numpy.array(data_ijm) m_bins = numpy.array(m_bins) except (TypeError, ValueError): - raise Exception('Data is not square') + raise Exception("Data is not square") magnitudes = m_bins[0, :] - rates = data_ijm[:, -len(magnitudes):] - all_polys = numpy.vstack((data_ijm[:, 0] - cell_dim['lonRange'] / 2., - data_ijm[:, 0] + cell_dim['lonRange'] / 2., - data_ijm[:, 1] - cell_dim['latRange'] / 2., - data_ijm[:, 1] + cell_dim[ - 'latRange'] / 2.)).T - bboxes = [((i[0], i[2]), (i[0], i[3]), (i[1], i[3]), (i[1], i[2])) - for i in all_polys] + rates = data_ijm[:, -len(magnitudes) :] + all_polys = numpy.vstack( + ( + data_ijm[:, 0] - cell_dim["lonRange"] / 2.0, + data_ijm[:, 0] + cell_dim["lonRange"] / 2.0, + data_ijm[:, 1] - cell_dim["latRange"] / 2.0, + data_ijm[:, 1] + cell_dim["latRange"] / 2.0, + ) + ).T + bboxes = [((i[0], i[2]), (i[0], i[3]), (i[1], i[3]), (i[1], i[2])) for i in all_polys] dh = float(all_polys[0, 3] - all_polys[0, 2]) poly_mask = numpy.ones(len(bboxes)) - region = CartesianGrid2D( - [Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) + region = CartesianGrid2D([Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) return rates, region, magnitudes @staticmethod def quadtree(filename): - with open(filename, 'r') as file_: - qt_header = file_.readline().split(',') + with open(filename, "r") as file_: + qt_header = file_.readline().split(",") formats = [str] for i in range(len(qt_header) - 1): formats.append(float) @@ -123,13 +121,11 @@ def quadtree(filename): qt_formats = {i: j for i, j in zip(qt_header, formats)} data = pandas.read_csv(filename, header=0, dtype=qt_formats) - quadkeys = numpy.array([i.encode('ascii', 'ignore') - for i in data.tile]) + quadkeys = numpy.array([i.encode("ascii", "ignore") for i in data.tile]) magnitudes = numpy.array(data.keys()[3:]).astype(float) rates = data[magnitudes.astype(str)].to_numpy() - region = QuadtreeGrid2D.from_quadkeys( - quadkeys.astype(str), magnitudes=magnitudes) + region = QuadtreeGrid2D.from_quadkeys(quadkeys.astype(str), magnitudes=magnitudes) region.get_cell_area() return rates, region, magnitudes @@ -139,102 +135,94 @@ def csv(filename): def is_mag(num): try: m = float(num) - if -1 < m < 12.: + if -1 < m < 12.0: return True else: return False except ValueError: return False - with open(filename, 'r') as file_: + with open(filename, "r") as file_: line = file_.readline() - if len(line.split(',')) > 3: - sep = ',' + if len(line.split(",")) > 3: + sep = "," else: - sep = ' ' + sep = " " - if 'tile' in line: + if "tile" in line: rates, region, magnitudes = ForecastParsers.quadtree(filename) return rates, region, magnitudes - data = pandas.read_csv(filename, header=0, sep=sep, escapechar='#', - skipinitialspace=True) + data = pandas.read_csv( + filename, header=0, sep=sep, escapechar="#", skipinitialspace=True + ) data.columns = [i.strip() for i in data.columns] magnitudes = numpy.array([float(i) for i in data.columns if is_mag(i)]) rates = data[[i for i in data.columns if is_mag(i)]].to_numpy() - all_polys = data[ - ['lon_min', 'lon_max', 'lat_min', 'lat_max']].to_numpy() - bboxes = [((i[0], i[2]), (i[0], i[3]), (i[1], i[3]), (i[1], i[2])) - for i in all_polys] + all_polys = data[["lon_min", "lon_max", "lat_min", "lat_max"]].to_numpy() + bboxes = [((i[0], i[2]), (i[0], i[3]), (i[1], i[3]), (i[1], i[2])) for i in all_polys] dh = float(all_polys[0, 3] - all_polys[0, 2]) try: - poly_mask = data['mask'] + poly_mask = data["mask"] except KeyError: poly_mask = numpy.ones(len(bboxes)) - region = CartesianGrid2D( - [Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) + region = CartesianGrid2D([Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) return rates, region, magnitudes @staticmethod - def hdf5(filename, group=''): + def hdf5(filename, group=""): start = time.process_time() - with h5py.File(filename, 'r') as db: - rates = db[f'{group}/rates'][:] - magnitudes = db[f'{group}/magnitudes'][:] + with h5py.File(filename, "r") as db: + rates = db[f"{group}/rates"][:] + magnitudes = db[f"{group}/magnitudes"][:] - if 'quadkeys' in db.keys(): + if "quadkeys" in db.keys(): region = QuadtreeGrid2D.from_quadkeys( - db[f'{group}/quadkeys'][:].astype(str), - magnitudes=magnitudes) + db[f"{group}/quadkeys"][:].astype(str), magnitudes=magnitudes + ) region.get_cell_area() else: - dh = db[f'{group}/dh'][:][0] - bboxes = db[f'{group}/bboxes'][:] - poly_mask = db[f'{group}/poly_mask'][:] - region = CartesianGrid2D( - [Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) + dh = db[f"{group}/dh"][:][0] + bboxes = db[f"{group}/bboxes"][:] + poly_mask = db[f"{group}/poly_mask"][:] + region = CartesianGrid2D([Polygon(bbox) for bbox in bboxes], dh, mask=poly_mask) - log.debug(f'Loading from hdf5 {filename} took:' - f' {time.process_time() - start:.2f}') + log.debug(f"Loading from hdf5 {filename} took:" f" {time.process_time() - start:.2f}") return rates, region, magnitudes class HDF5Serializer: @staticmethod - def grid2hdf5(rates, region, mag, grp='', hdf5_filename=None, - **kwargs): + def grid2hdf5(rates, region, mag, grp="", hdf5_filename=None, **kwargs): start = time.process_time() bboxes = numpy.array([i.points for i in region.polygons]) - with h5py.File(hdf5_filename, 'a') as hfile: - - hfile.require_dataset(f'{grp}/rates', shape=rates.shape, - dtype=float) - hfile[f'{grp}/rates'][:] = rates - hfile.require_dataset(f'{grp}/magnitudes', shape=mag.shape, - dtype=float) - hfile[f'{grp}/magnitudes'][:] = mag - hfile.require_dataset(f'{grp}/bboxes', shape=bboxes.shape, - dtype=float) - hfile[f'{grp}/bboxes'][:] = bboxes - hfile.require_dataset(f'{grp}/dh', shape=(1,), dtype=float) + with h5py.File(hdf5_filename, "a") as hfile: + + hfile.require_dataset(f"{grp}/rates", shape=rates.shape, dtype=float) + hfile[f"{grp}/rates"][:] = rates + hfile.require_dataset(f"{grp}/magnitudes", shape=mag.shape, dtype=float) + hfile[f"{grp}/magnitudes"][:] = mag + hfile.require_dataset(f"{grp}/bboxes", shape=bboxes.shape, dtype=float) + hfile[f"{grp}/bboxes"][:] = bboxes + hfile.require_dataset(f"{grp}/dh", shape=(1,), dtype=float) try: - hfile[f'{grp}/dh'][:] = region.dh + hfile[f"{grp}/dh"][:] = region.dh except AttributeError: - raise AttributeError('Quadtree can not be dropped to HDF5' - '(not needed, because file is already' - ' low sized') - hfile.require_dataset(f'{grp}/poly_mask', - shape=region.poly_mask.shape, - dtype=float) - hfile[f'{grp}/poly_mask'][:] = region.poly_mask + raise AttributeError( + "Quadtree can not be dropped to HDF5" + "(not needed, because file is already" + " low sized" + ) + hfile.require_dataset(f"{grp}/poly_mask", shape=region.poly_mask.shape, dtype=float) + hfile[f"{grp}/poly_mask"][:] = region.poly_mask if kwargs: for key, v in kwargs.items(): @@ -247,65 +235,66 @@ def grid2hdf5(rates, region, mag, grp='', hdf5_filename=None, else: shape = len(v) dtype = type(v[0]) - hfile.require_dataset(f'{grp}/{key}', shape=shape, - dtype=dtype) - hfile[f'{grp}/{key}'][:] = v + hfile.require_dataset(f"{grp}/{key}", shape=shape, dtype=dtype) + hfile[f"{grp}/{key}"][:] = v - log.debug(f'Storing to hdf5 {hdf5_filename} took:' - f'{time.process_time() - start:2f}') + log.debug(f"Storing to hdf5 {hdf5_filename} took:" f"{time.process_time() - start:2f}") def check_format(filename, fmt=None, func=None): if fmt is None: fmt = os.path.splitext(filename)[-1][1:] - if fmt == 'xml': + if fmt == "xml": max_lines = 40 bin_ = False - with open(filename, 'r') as f_: + with open(filename, "r") as f_: for i in range(max_lines): line_ = f_.readline() - if '' in line_: + if "" in line_: bin_ = True - error_msg = "File does not specify rates per magnitude bin." \ - " Example correct format:\n \n 1.0e-1\n" \ - "1.0e-1\n " + error_msg = ( + "File does not specify rates per magnitude bin." + " Example correct format:\n \n 1.0e-1\n" + "1.0e-1\n " + ) if not bin_: raise LookupError(error_msg) tree = eTree.parse(filename) root = tree.getroot() index = False - if 'forecastData' not in root[0].tag: - raise IndentationError('Attribute "forecastData" is not found at ' - 'the correct tree indentation level (1)"') + if "forecastData" not in root[0].tag: + raise IndentationError( + 'Attribute "forecastData" is not found at ' + 'the correct tree indentation level (1)"' + ) for i, j in enumerate(list(root[0])): - if 'depthLayer' in j.tag: + if "depthLayer" in j.tag: index = i if isinstance(index, int) and (index is not False): cell_keys = list(root[0][index][0].attrib.keys()) bin_ = root[0][index][0][0].attrib - if 'lat' not in cell_keys or 'lon' not in cell_keys: + if "lat" not in cell_keys or "lon" not in cell_keys: raise KeyError(error_msg) - if 'm' not in bin_: + if "m" not in bin_: raise KeyError(error_msg) else: - raise LookupError("Attribute 'depthLayer' not present in" - " 'forecastData' node") + raise LookupError("Attribute 'depthLayer' not present in" " 'forecastData' node") - elif fmt == 'csv': + elif fmt == "csv": pass - elif fmt == 'qtree': + elif fmt == "qtree": pass - elif fmt == 'dat': + elif fmt == "dat": pass - elif fmt == 'hdf5': + elif fmt == "hdf5": pass elif func: pass @@ -317,15 +306,15 @@ def serialize(): parser.add_argument("--filename", help="Model forecast name") args = parser.parse_args() - if args.format == 'quadtree': + if args.format == "quadtree": ForecastParsers.quadtree(args.filename) - if args.format == 'dat': + if args.format == "dat": ForecastParsers.dat(args.filename) - if args.format == 'csep' or args.format == 'csv': + if args.format == "csep" or args.format == "csv": ForecastParsers.csv(args.filename) - if args.format == 'xml': + if args.format == "xml": ForecastParsers.xml(args.filename) -if __name__ == '__main__': +if __name__ == "__main__": serialize() diff --git a/floatcsep/registry.py b/floatcsep/registry.py index ff5c0ec..8ece9b2 100644 --- a/floatcsep/registry.py +++ b/floatcsep/registry.py @@ -38,12 +38,12 @@ def _parse_arg(arg): return timewindow2str(arg) elif isinstance(arg, str): return arg - elif hasattr(arg, 'name'): + elif hasattr(arg, "name"): return arg.name - elif hasattr(arg, '__name__'): + elif hasattr(arg, "__name__"): return arg.__name__ else: - raise Exception('Arg is not found') + raise Exception("Arg is not found") def __eq__(self, other): return self.path == other @@ -55,16 +55,15 @@ def asdict(self): return dataclasses.asdict(self) def abs(self, *paths: Sequence[str]) -> str: - """ Gets the absolute path of a file, when it was defined relative to - the experiment working dir.""" - + """Gets the absolute path of a file, when it was defined relative to + the experiment working dir.""" _path = normpath(abspath(join(self.workdir, *paths))) _dir = dirname(_path) return _path def absdir(self, *paths: Sequence[str]) -> str: - """ Gets the absolute path of a file, when it was defined relative to - the experiment working dir.""" + """Gets the absolute path of a file, when it was defined relative to + the experiment working dir.""" _path = normpath(abspath(join(self.workdir, *paths))) _dir = dirname(_path) @@ -74,12 +73,9 @@ def fileexists(self, *args): file_abspath = self.__call__(*args) return exists(file_abspath) - def build_tree(self, - timewindows=None, - model_class='ti', - prefix=None, - args_file=None, - input_cat=None) -> None: + def build_tree( + self, timewindows=None, model_class="ti", prefix=None, args_file=None, input_cat=None + ) -> None: """ Creates the run directory, and reads the file structure inside @@ -88,8 +84,8 @@ def build_tree(self, timewindows (list(str)): List of time windows or strings. model_class (str): Time-indendent (ti) or time-dependent (td) prefix (str): prefix of the model forecast filenames if TD - args_file (str): input arguments path of the model if TD - input_cat (str): input catalog path of the model if TD + args_file (str, bool): input arguments path of the model if TD + input_cat (str, bool): input catalog path of the model if TD Returns: run_folder: Path to the run. @@ -102,34 +98,34 @@ def build_tree(self, if timewindows is None: return windows = timewindow2str(timewindows) - if model_class == 'ti': + if model_class == "ti": fname = self.database if self.database else self.path fc_files = {win: fname for win in windows} fc_exists = {win: exists(fc_files[win]) for win in windows} - elif model_class == 'td': - args = args_file if args_file else join('input', 'args.txt') + elif model_class == "td": + args = args_file if args_file else join("input", "args.txt") self.args_file = join(self.path, args) - input_cat = input_cat if input_cat else join('input', - 'catalog.csv') + input_cat = input_cat if input_cat else join("input", "catalog.csv") self.input_cat = join(self.path, input_cat) # grab names for creating directories - subfolders = ['input', 'forecasts'] - dirtree = {folder: self.abs(self.path, folder) for - folder in subfolders} + subfolders = ["input", "forecasts"] + dirtree = {folder: self.abs(self.path, folder) for folder in subfolders} # create directories if they don't exist for _, folder_ in dirtree.items(): os.makedirs(folder_, exist_ok=True) # set forecast names - fc_files = {win: join(dirtree['forecasts'], - f'{prefix}_{win}.csv') # todo other formats? - for win in windows} + fc_files = { + win: join(dirtree["forecasts"], f"{prefix}_{win}.csv") + for win in windows + } - fc_exists = {win: any(file for file in - list(os.listdir(dirtree['forecasts']))) - for win in windows} + fc_exists = { + win: any(file for file in list(os.listdir(dirtree["forecasts"]))) + for win in windows + } self.forecasts = fc_files self.inventory = fc_exists @@ -138,7 +134,7 @@ def build_tree(self, @dataclass class PathTree: workdir: str - rundir: str = 'results' + rundir: str = "results" paths: dict = field(default_factory=dict) result_exists: dict = field(default_factory=dict) @@ -155,12 +151,12 @@ def _parse_arg(arg): return timewindow2str(arg) elif isinstance(arg, str): return arg - elif hasattr(arg, 'name'): + elif hasattr(arg, "name"): return arg.name - elif hasattr(arg, '__name__'): + elif hasattr(arg, "__name__"): return arg.__name__ else: - raise Exception('Arg is not found') + raise Exception("Arg is not found") def __eq__(self, other): return self.workdir == other @@ -172,36 +168,33 @@ def asdict(self): return dataclasses.asdict(self) def abs(self, *paths: Sequence[str]) -> str: - """ Gets the absolute path of a file, when it was defined relative to - the experiment working dir.""" + """Gets the absolute path of a file, when it was defined relative to + the experiment working dir.""" _path = normpath(abspath(join(self.workdir, *paths))) return _path def rel(self, *paths: Sequence[str]) -> str: - """ Gets the relative path of a file, when it was defined relative to - the experiment working dir.""" + """Gets the relative path of a file, when it was defined relative to + the experiment working dir.""" - _abspath = normpath( - abspath(join(self.workdir, *paths))) + _abspath = normpath(abspath(join(self.workdir, *paths))) _relpath = relpath(_abspath, self.workdir) return _relpath def absdir(self, *paths: Sequence[str]) -> str: - """ Gets the absolute path of a file, when it was defined relative to - the experiment working dir.""" + """Gets the absolute path of a file, when it was defined relative to + the experiment working dir.""" - _path = normpath( - abspath(join(self.workdir, *paths))) + _path = normpath(abspath(join(self.workdir, *paths))) _dir = dirname(_path) return _dir def reldir(self, *paths: Sequence[str]) -> str: - """ Gets the absolute path of a file, when it was defined relative to - the experiment working dir.""" + """Gets the absolute path of a file, when it was defined relative to + the experiment working dir.""" - _path = normpath( - abspath(join(self.workdir, *paths))) + _path = normpath(abspath(join(self.workdir, *paths))) _dir = dirname(_path) _reldir = relpath(_dir, self.workdir) return _reldir @@ -211,10 +204,7 @@ def fileexists(self, *args): file_abspath = self.__call__(*args) return exists(file_abspath) - def build(self, - timewindows=None, - models=None, - tests=None) -> None: + def build(self, timewindows=None, models=None, tests=None) -> None: """ Creates the run directory, and reads the file structure inside @@ -245,10 +235,11 @@ def build(self, run_folder = self.rundir - subfolders = ['catalog', 'evaluations', 'figures', 'forecasts'] + subfolders = ["catalog", "evaluations", "figures", "forecasts"] dirtree = { - win: {folder: self.abs(run_folder, win, folder) - for folder in subfolders} for win in windows} + win: {folder: self.abs(run_folder, win, folder) for folder in subfolders} + for win in windows + } # create directories if they don't exist for tw, tw_folder in dirtree.items(): @@ -256,46 +247,53 @@ def build(self, os.makedirs(folder_, exist_ok=True) # Check existing files - files = {win: {name: list(os.listdir(path)) for name, path in - windir.items()} for win, windir in dirtree.items()} - - file_exists = {win: { - 'forecasts': False, - 'catalog': any(file for file in files[win]['catalog']), - 'evaluations': { - test: { - model: any(f'{test}_{model}.json' in file for file in - files[win]['evaluations']) - for model in models - } - for test in tests - } - } for win in windows} + files = { + win: {name: list(os.listdir(path)) for name, path in windir.items()} + for win, windir in dirtree.items() + } - target_paths = { - 'config': 'repr_config.yml', - 'catalog_figure': 'catalog', - 'magnitude_time': 'events', - **{win: { - 'catalog': join(win, 'catalog', 'test_catalog.json'), - 'evaluations': { + file_exists = { + win: { + "forecasts": False, + "catalog": any(file for file in files[win]["catalog"]), + "evaluations": { test: { - model: join(win, 'evaluations', - f'{test}_{model}.json') + model: any( + f"{test}_{model}.json" in file for file in files[win]["evaluations"] + ) for model in models } - for test in tests}, - 'figures': { - **{test: join(win, 'figures', f'{test}') - for test in tests}, - 'catalog': join(win, 'figures', 'catalog'), - 'magnitude_time': join(win, 'figures', - 'magnitude_time') + for test in tests }, - 'forecasts': {model: join(win, 'forecasts', f'{model}') - for model in models} - } for win in windows} + } + for win in windows + } + + target_paths = { + "config": "repr_config.yml", + "catalog_figure": "catalog", + "magnitude_time": "events", + **{ + win: { + "catalog": join(win, "catalog", "test_catalog.json"), + "evaluations": { + test: { + model: join(win, "evaluations", f"{test}_{model}.json") + for model in models + } + for test in tests + }, + "figures": { + **{test: join(win, "figures", f"{test}") for test in tests}, + "catalog": join(win, "figures", "catalog"), + "magnitude_time": join(win, "figures", "magnitude_time"), + }, + "forecasts": { + model: join(win, "forecasts", f"{model}") for model in models + }, + } + for win in windows + }, } self.paths = target_paths self.result_exists = file_exists - diff --git a/floatcsep/report.py b/floatcsep/report.py index 58f4c86..2d5d364 100644 --- a/floatcsep/report.py +++ b/floatcsep/report.py @@ -20,9 +20,7 @@ def generate_report(experiment, timewindow=-1): hooks = experiment.report_hook report = MarkdownReport() - report.add_title( - f"Experiment Report - {experiment.name}", hooks.get('title_text', '') - ) + report.add_title(f"Experiment Report - {experiment.name}", hooks.get("title_text", "")) report.add_heading("Objectives", level=2) @@ -32,8 +30,8 @@ def generate_report(experiment, timewindow=-1): f" M>{min(experiment.magnitudes)}.", ] - if hooks.get('objectives', None): - for i in hooks.get('objectives'): + if hooks.get("objectives", None): + for i in hooks.get("objectives"): objs.append(i) report.add_list(objs) @@ -45,24 +43,23 @@ def generate_report(experiment, timewindow=-1): experiment.plot_catalog() report.add_figure( f"Input catalog", - [experiment.path('catalog_figure'), - experiment.path('magnitude_time')], + [experiment.path("catalog_figure"), experiment.path("magnitude_time")], level=3, ncols=1, caption="Evaluation catalog from " - f"{experiment.start_date} until {experiment.end_date}. " - f"Earthquakes are filtered above Mw" - f" {min(experiment.magnitudes)}.", - add_ext=True + f"{experiment.start_date} until {experiment.end_date}. " + f"Earthquakes are filtered above Mw" + f" {min(experiment.magnitudes)}.", + add_ext=True, ) report.add_heading( "Results", level=2, text="The following tests are applied to each of the experiment's " - "forecasts. More information regarding the tests can be found " - "[here]" - "(https://docs.cseptesting.org/getting_started/theory.html)." + "forecasts. More information regarding the tests can be found " + "[here]" + "(https://docs.cseptesting.org/getting_started/theory.html).", ) test_names = [test.name for test in experiment.tests] @@ -70,28 +67,22 @@ def generate_report(experiment, timewindow=-1): # Include results from Experiment for test in experiment.tests: - fig_path = experiment.path(timestr, 'figures', test) - width = test.plot_args[0].get('figsize', [4])[0] * 96 + fig_path = experiment.path(timestr, "figures", test) + width = test.plot_args[0].get("figsize", [4])[0] * 96 report.add_figure( - f"{test.name}", - fig_path, - level=3, - caption=test.markdown, - add_ext=True, - width=width + f"{test.name}", fig_path, level=3, caption=test.markdown, add_ext=True, width=width ) for model in experiment.models: try: - fig_path = experiment.path(timestr, 'figures', - f'{test.name}_{model.name}') - width = test.plot_args[0].get('figsize', [4])[0] * 96 + fig_path = experiment.path(timestr, "figures", f"{test.name}_{model.name}") + width = test.plot_args[0].get("figsize", [4])[0] * 96 report.add_figure( f"{test.name}: {model.name}", fig_path, level=3, caption=test.markdown, add_ext=True, - width=width + width=width, ) except KeyError: pass diff --git a/floatcsep/utils.py b/floatcsep/utils.py index 903357c..73fbfb6 100644 --- a/floatcsep/utils.py +++ b/floatcsep/utils.py @@ -38,8 +38,8 @@ import floatcsep.extras import floatcsep.readers -_UNITS = ['years', 'months', 'weeks', 'days'] -_PD_FORMAT = ['YS', 'MS', 'W', 'D'] +_UNITS = ["years", "months", "weeks", "days"] +_PD_FORMAT = ["YS", "MS", "W", "D"] def parse_csep_func(func): @@ -63,33 +63,36 @@ def recgetattr(obj, attr, *args): def _getattr(obj_, attr_): return getattr(obj_, attr_, *args) - return functools.reduce(_getattr, [obj] + attr.split('.')) + return functools.reduce(_getattr, [obj] + attr.split(".")) if callable(func): return func elif func is None: return func else: - _target_modules = [csep, - csep.utils, - csep.utils.plots, - csep.core.regions, - floatcsep.utils, - floatcsep.accessors, - floatcsep.extras, - floatcsep.readers.HDF5Serializer, - floatcsep.readers.ForecastParsers] + _target_modules = [ + csep, + csep.utils, + csep.utils.plots, + csep.core.regions, + floatcsep.utils, + floatcsep.accessors, + floatcsep.extras, + floatcsep.readers.HDF5Serializer, + floatcsep.readers.ForecastParsers, + ] for module in _target_modules: try: return recgetattr(module, func) except AttributeError: pass raise AttributeError( - f'Evaluation/Plot/Region function {func} has not yet been' - f' implemented in floatcsep or pycsep') + f"Evaluation/Plot/Region function {func} has not yet been" + f" implemented in floatcsep or pycsep" + ) -def parse_timedelta_string(window, exp_class='ti'): +def parse_timedelta_string(window, exp_class="ti"): """ Parses a float or string representing the testing time window length @@ -113,19 +116,20 @@ def parse_timedelta_string(window, exp_class='ti'): if isinstance(window, str): try: - n, unit_ = [i for i in re.split(r'(\d+)', window) if i] - unit = [i for i in [j[:-1] for j in _UNITS] if i in unit_.lower()][ - 0] - return f'{n}-{unit}s' + n, unit_ = [i for i in re.split(r"(\d+)", window) if i] + unit = [i for i in [j[:-1] for j in _UNITS] if i in unit_.lower()][0] + return f"{n}-{unit}s" except (ValueError, IndexError): - raise ValueError('Time window is misspecified. ' - 'Try the amount followed by the time unit ' - '(e.g. 1 day, 1 months, 3 years)') + raise ValueError( + "Time window is misspecified. " + "Try the amount followed by the time unit " + "(e.g. 1 day, 1 months, 3 years)" + ) elif isinstance(window, float): n = window - unit = 'year' if exp_class == 'ti' else 'day' - return f'{n}-{unit}s' + unit = "year" if exp_class == "ti" else "day" + return f"{n}-{unit}s" def read_time_cfg(time_config, **kwargs): @@ -145,29 +149,28 @@ def read_time_cfg(time_config, **kwargs): windows to be evaluated """ - _attrs = ['start_date', 'end_date', 'intervals', 'horizon', 'offset', - 'growth', 'exp_class'] + _attrs = ["start_date", "end_date", "intervals", "horizon", "offset", "growth", "exp_class"] time_config = copy.deepcopy(time_config) if time_config is None: time_config = {} try: - experiment_class = time_config.get('exp_class', kwargs['exp_class']) + experiment_class = time_config.get("exp_class", kwargs["exp_class"]) except KeyError: - experiment_class = 'ti' - time_config['exp_class'] = experiment_class + experiment_class = "ti" + time_config["exp_class"] = experiment_class time_config.update({i: j for i, j in kwargs.items() if i in _attrs}) - if 'horizon' in time_config.keys(): - time_config['horizon'] = parse_timedelta_string(time_config['horizon']) - if 'offset' in time_config.keys(): - time_config['offset'] = parse_timedelta_string(time_config['offset']) + if "horizon" in time_config.keys(): + time_config["horizon"] = parse_timedelta_string(time_config["horizon"]) + if "offset" in time_config.keys(): + time_config["offset"] = parse_timedelta_string(time_config["offset"]) - if experiment_class == 'ti': - time_config['timewindows'] = timewindows_ti(**time_config) + if experiment_class == "ti": + time_config["timewindows"] = timewindows_ti(**time_config) return time_config - elif experiment_class == 'td': - time_config['timewindows'] = timewindows_td(**time_config) + elif experiment_class == "td": + time_config["timewindows"] = timewindows_td(**time_config) return time_config @@ -188,61 +191,58 @@ def read_region_cfg(region_config, **kwargs): """ region_config = copy.deepcopy(region_config) - _attrs = ['region', 'mag_min', 'mag_max', 'mag_bin', 'magnitudes', - 'depth_min', 'depth_max'] + _attrs = ["region", "mag_min", "mag_max", "mag_bin", "magnitudes", "depth_min", "depth_max"] if region_config is None: region_config = {} region_config.update({i: j for i, j in kwargs.items() if i in _attrs}) - dmin = region_config.get('depth_min', -2) - dmax = region_config.get('depth_max', 6000) + dmin = region_config.get("depth_min", -2) + dmax = region_config.get("depth_max", 6000) depths = cleaner_range(dmin, dmax, dmax - dmin) - magnitudes = region_config.get('magnitudes', None) + magnitudes = region_config.get("magnitudes", None) if magnitudes is None: - magmin = region_config['mag_min'] - magmax = region_config['mag_max'] - magbin = region_config['mag_bin'] + magmin = region_config["mag_min"] + magmax = region_config["mag_max"] + magbin = region_config["mag_bin"] magnitudes = cleaner_range(magmin, magmax, magbin) - region_data = region_config.get('region', None) + region_data = region_config.get("region", None) try: - region = parse_csep_func(region_data)(name=region_data, - magnitudes=magnitudes) \ - if region_data else None + region = ( + parse_csep_func(region_data)(name=region_data, magnitudes=magnitudes) + if region_data + else None + ) except AttributeError: if isinstance(region_data, str): - filename = os.path.join(kwargs.get('path', ''), region_data) - with open(filename, 'r') as file_: + filename = os.path.join(kwargs.get("path", ""), region_data) + with open(filename, "r") as file_: parsed_region = file_.readlines() try: - data = numpy.array([re.split(r'\s+|,', i.strip()) for i in - parsed_region], dtype=float) + data = numpy.array( + [re.split(r"\s+|,", i.strip()) for i in parsed_region], dtype=float + ) except ValueError: - data = numpy.array([re.split(r'\s+|,', i.strip()) for i in - parsed_region[1:]], dtype=float) - dh1 = scipy.stats.mode( - numpy.diff(numpy.unique(data[:, 0]))).mode - dh2 = scipy.stats.mode( - numpy.diff(numpy.unique(data[:, 1]))).mode + data = numpy.array( + [re.split(r"\s+|,", i.strip()) for i in parsed_region[1:]], dtype=float + ) + dh1 = scipy.stats.mode(numpy.diff(numpy.unique(data[:, 0]))).mode + dh2 = scipy.stats.mode(numpy.diff(numpy.unique(data[:, 1]))).mode dh = numpy.nanmin([dh1, dh2]) - region = CartesianGrid2D.from_origins(data, - name=region_data, - magnitudes=magnitudes, - dh=dh) - region_config.update({'path': region_data}) + region = CartesianGrid2D.from_origins( + data, name=region_data, magnitudes=magnitudes, dh=dh + ) + region_config.update({"path": region_data}) else: - region_data['magnitudes'] = magnitudes + region_data["magnitudes"] = magnitudes region = CartesianGrid2D.from_dict(region_data) - region_config.update({'depths': depths, - 'magnitudes': magnitudes, - 'region': region}) + region_config.update({"depths": depths, "magnitudes": magnitudes, "region": region}) return region_config -def timewindow2str(datetimes: Union[Sequence[datetime], - Sequence[Sequence[datetime]]]): +def timewindow2str(datetimes: Union[Sequence[datetime], Sequence[Sequence[datetime]]]): """ Converts a time window (list/tuple of datetimes) to a string that represents it. Can be a single timewindow or a list of time windows. @@ -253,10 +253,10 @@ def timewindow2str(datetimes: Union[Sequence[datetime], """ if isinstance(datetimes[0], datetime): - return '_'.join([j.date().isoformat() for j in datetimes]) + return "_".join([j.date().isoformat() for j in datetimes]) elif isinstance(datetimes[0], (list, tuple)): - return ['_'.join([j.date().isoformat() for j in i]) for i in datetimes] + return ["_".join([j.date().isoformat() for j in i]) for i in datetimes] def str2timewindow(tw_string: Union[str, Sequence[str]]): @@ -270,25 +270,20 @@ def str2timewindow(tw_string: Union[str, Sequence[str]]): """ if isinstance(tw_string, str): - start_date, end_date = [datetime.fromisoformat(i) for i in - tw_string.split('_')] + start_date, end_date = [datetime.fromisoformat(i) for i in tw_string.split("_")] return start_date, end_date elif isinstance(tw_string, (list, tuple)): datetimes = [] for twstr in tw_string: - start_date, end_date = [datetime.fromisoformat(i) for i in - twstr.split('_')] + start_date, end_date = [datetime.fromisoformat(i) for i in twstr.split("_")] datetimes.append([start_date, end_date]) return datetimes -def timewindows_ti(start_date=None, - end_date=None, - intervals=None, - horizon=None, - growth='incremental', - **_): +def timewindows_ti( + start_date=None, end_date=None, intervals=None, horizon=None, growth="incremental", **_ +): """ Creates the testing intervals for a time-independent experiment. @@ -319,37 +314,33 @@ def timewindows_ti(start_date=None, if (intervals is None) and (horizon is None): intervals = 1 elif horizon: - n, unit = horizon.split('-') - frequency = f'{n}{_PD_FORMAT[_UNITS.index(unit)]}' + n, unit = horizon.split("-") + frequency = f"{n}{_PD_FORMAT[_UNITS.index(unit)]}" periods = intervals + 1 if intervals else intervals try: - timelimits = pandas.date_range(start=start_date, - end=end_date, - periods=periods, - freq=frequency).to_pydatetime() + timelimits = pandas.date_range( + start=start_date, end=end_date, periods=periods, freq=frequency + ).to_pydatetime() except ValueError as e_: raise ValueError( - 'The following experiment parameters combinations are possible:\n' - ' (start_date, end_date)\n' - ' (start_date, end_date, intervals)\n' - ' (start_date, end_date, timewindow)\n' - ' (start_date, intervals, timewindow)\n') + "The following experiment parameters combinations are possible:\n" + " (start_date, end_date)\n" + " (start_date, end_date, intervals)\n" + " (start_date, end_date, timewindow)\n" + " (start_date, intervals, timewindow)\n" + ) - if growth == 'incremental': - return [(i, j) for i, j in zip(timelimits[:-1], - timelimits[1:])] + if growth == "incremental": + return [(i, j) for i, j in zip(timelimits[:-1], timelimits[1:])] - elif growth == 'cumulative': + elif growth == "cumulative": return [(timelimits[0], i) for i in timelimits[1:]] -def timewindows_td(start_date=None, - end_date=None, - timeintervals=None, - timehorizon=None, - timeoffset=None, - **_): +def timewindows_td( + start_date=None, end_date=None, timeintervals=None, timehorizon=None, timeoffset=None, **_ +): """ Creates the testing intervals for a time-dependent experiment. @@ -380,33 +371,38 @@ def timewindows_td(start_date=None, frequency = None if timehorizon: - n, unit = timehorizon.split('-') - frequency = f'{n}{_PD_FORMAT[_UNITS.index(unit)]}' + n, unit = timehorizon.split("-") + frequency = f"{n}{_PD_FORMAT[_UNITS.index(unit)]}" periods = timeintervals + 1 if timeintervals else timeintervals try: - offset = timeoffset.split('-') if timeoffset else None - start_offset = start_date + pandas.DateOffset( - **{offset[1]: float(offset[0])}) if offset else start_date - end_offset = end_date - pandas.DateOffset( - **{offset[1]: float(offset[0])}) if offset else start_date - - lower_limits = pandas.date_range(start=start_date, - end=end_offset, - periods=periods, - freq=frequency).to_pydatetime()[:-1] - upper_limits = pandas.date_range(start=start_offset, - end=end_date, - periods=periods, - freq=frequency).to_pydatetime()[:-1] + offset = timeoffset.split("-") if timeoffset else None + start_offset = ( + start_date + pandas.DateOffset(**{offset[1]: float(offset[0])}) + if offset + else start_date + ) + end_offset = ( + end_date - pandas.DateOffset(**{offset[1]: float(offset[0])}) + if offset + else start_date + ) + + lower_limits = pandas.date_range( + start=start_date, end=end_offset, periods=periods, freq=frequency + ).to_pydatetime()[:-1] + upper_limits = pandas.date_range( + start=start_offset, end=end_date, periods=periods, freq=frequency + ).to_pydatetime()[:-1] except ValueError as e_: raise ValueError( - 'The following experiment parameters combinations are possible:\n' - ' (start_date, end_date)\n' - ' (start_date, end_date, intervals)\n' - ' (start_date, end_date, timewindow)\n' - ' (start_date, intervals, timewindow)\n') + "The following experiment parameters combinations are possible:\n" + " (start_date, end_date)\n" + " (start_date, end_date, intervals)\n" + " (start_date, end_date, timewindow)\n" + " (start_date, intervals, timewindow)\n" + ) # if growth == 'incremental': # timewindows = [(i, j) for i, j in zip(timelimits[:-1], @@ -455,26 +451,25 @@ def sign_match(self, obj=None, met=None, kw_arg=None): """ - if self.obj == obj or obj == getattr(self.obj, 'name', None): + if self.obj == obj or obj == getattr(self.obj, "name", None): if met == self.method: if kw_arg in self.kwargs.values(): return True return False def __str__(self): - task_str = f'{self.__class__}\n\t' \ - f'Instance: {self.obj.__class__.__name__}\n' - a = getattr(self.obj, 'name', None) + task_str = f"{self.__class__}\n\t" f"Instance: {self.obj.__class__.__name__}\n" + a = getattr(self.obj, "name", None) if a: - task_str += f'\tName: {a}\n' - task_str += f'\tMethod: {self.method}\n' + task_str += f"\tName: {a}\n" + task_str += f"\tMethod: {self.method}\n" for i, j in self.kwargs.items(): - task_str += f'\t\t{i}: {j} \n' + task_str += f"\t\t{i}: {j} \n" return task_str[:-2] def run(self): - if hasattr(self.obj, 'store'): + if hasattr(self.obj, "store"): self.obj = self.obj.store output = getattr(self.obj, self.method)(**self.kwargs) @@ -504,7 +499,7 @@ def __init__(self): self.tasks = OrderedDict() self._ntasks = 0 - self.name = 'floatcsep.utils.TaskGraph' + self.name = "floatcsep.utils.TaskGraph" @property def ntasks(self): @@ -526,10 +521,7 @@ def add(self, task): self.tasks[task] = [] self.ntasks += 1 - def add_dependency(self, task, - dinst=None, - dmeth=None, - dkw=None): + def add_dependency(self, task, dinst=None, dmeth=None, dkw=None): """ Adds a dependency to a task already inserted to the TaskGraph. Searchs within the pre-added tasks a signature match by their name/instance, @@ -552,7 +544,6 @@ def add_dependency(self, task, self.tasks[task].extend(deps) def run(self): - """ Iterates through all the graph tasks and runs them. Returns: @@ -570,9 +561,9 @@ def check_exist(self): class MarkdownReport: - """ Class to generate a Markdown report from a study """ + """Class to generate a Markdown report from a study""" - def __init__(self, outname='report.md'): + def __init__(self, outname="report.md"): self.outname = outname self.toc = [] self.has_title = True @@ -580,13 +571,15 @@ def __init__(self, outname='report.md'): self.markdown = [] def add_introduction(self, adict): - """ Generate document header from dictionary """ - first = f"# CSEP Testing Results: {adict['simulation_name']} \n" \ - f"**Forecast Name:** {adict['forecast_name']} \n" \ - f"**Simulation Start Time:** {adict['origin_time']} \n" \ - f"**Evaluation Time:** {adict['evaluation_time']} \n" \ - f"**Catalog Source:** {adict['catalog_source']} \n" \ - f"**Number Simulations:** {adict['num_simulations']}\n" + """Generate document header from dictionary""" + first = ( + f"# CSEP Testing Results: {adict['simulation_name']} \n" + f"**Forecast Name:** {adict['forecast_name']} \n" + f"**Simulation Start Time:** {adict['origin_time']} \n" + f"**Evaluation Time:** {adict['evaluation_time']} \n" + f"**Catalog Source:** {adict['catalog_source']} \n" + f"**Number Simulations:** {adict['num_simulations']}\n" + ) # used to determine to place TOC at beginning of document or after # introduction. @@ -604,10 +597,19 @@ def add_text(self, text): text (list): lines to write Returns: """ - self.markdown.append(' '.join(text) + '\n\n') - - def add_figure(self, title, relative_filepaths, level=2, ncols=1, - add_ext=False, text='', caption='', width=None): + self.markdown.append(" ".join(text) + "\n\n") + + def add_figure( + self, + title, + relative_filepaths, + level=2, + ncols=1, + add_ext=False, + text="", + caption="", + width=None, + ): """ This function expects a list of filepaths. If you want the output stacked, select a value of ncols. ncols should be divisible by @@ -632,13 +634,12 @@ def add_figure(self, title, relative_filepaths, level=2, ncols=1, correct_paths = [] if add_ext: for fp in paths: - correct_paths.append(fp + '.png') + correct_paths.append(fp + ".png") else: correct_paths = paths # generate new lists with size ncols - formatted_paths = [correct_paths[i:i + ncols] for i in - range(0, len(paths), ncols)] + formatted_paths = [correct_paths[i : i + ncols] for i in range(0, len(paths), ncols)] # convert str into a list, where each potential row is an iter not str def build_header(_row): @@ -649,14 +650,14 @@ def build_header(_row): break top += " |" bottom += " --- |" - return top + '\n' + bottom + return top + "\n" + bottom - size_ = bool(width) * f'width={width}' + size_ = bool(width) * f"width={width}" def add_to_row(_row): if len(_row) == 1: return f'' - string = '| ' + string = "| " for item in _row: string = string + f'' return string @@ -664,23 +665,22 @@ def add_to_row(_row): level_string = f"{level * '#'}" result_cell = [] locator = title.lower().replace(" ", "_") - result_cell.append( - f'{level_string} {title} \n') - result_cell.append(f'{text}\n') + result_cell.append(f'{level_string} {title} \n') + result_cell.append(f"{text}\n") for i, row in enumerate(formatted_paths): if i == 0 and not is_single and ncols > 1: result_cell.append(build_header(row)) result_cell.append(add_to_row(row)) - result_cell.append('\n') - result_cell.append(f'{caption}') + result_cell.append("\n") + result_cell.append(f"{caption}") - self.markdown.append('\n'.join(result_cell) + '\n') + self.markdown.append("\n".join(result_cell) + "\n") # generate metadata for TOC self.toc.append((title, level, locator)) - def add_heading(self, title, level=1, text='', add_toc=True): + def add_heading(self, title, level=1, text="", add_toc=True): # multipying char simply repeats it if isinstance(text, str): text = [text] @@ -693,9 +693,8 @@ def add_heading(self, title, level=1, text='', add_toc=True): for item in list(text): cell.append(item) except Exception as ex: - raise RuntimeWarning( - "Unable to add document subhead, text must be iterable.") - self.markdown.append('\n'.join(cell) + '\n') + raise RuntimeWarning("Unable to add document subhead, text must be iterable.") + self.markdown.append("\n".join(cell) + "\n") # generate metadata for TOC if add_toc: @@ -705,24 +704,24 @@ def add_list(self, _list): cell = [] for item in _list: cell.append(f"* {item}") - self.markdown.append('\n'.join(cell) + '\n\n') + self.markdown.append("\n".join(cell) + "\n\n") def add_title(self, title, text): self.has_title = True self.add_heading(title, 1, text, add_toc=False) def table_of_contents(self): - """ generates table of contents based on contents of document. """ + """generates table of contents based on contents of document.""" if len(self.toc) == 0: return toc = ["# Table of Contents"] for i, elem in enumerate(self.toc): title, level, locator = elem - space = ' ' * (level - 1) + space = " " * (level - 1) toc.append(f"{space}1. [{title}](#{locator})") insert_loc = 1 if self.has_title else 0 - self.markdown.insert(insert_loc, '\n'.join(toc) + '\n\n') + self.markdown.insert(insert_loc, "\n".join(toc) + "\n\n") def add_table(self, data, use_header=True): """ @@ -734,37 +733,37 @@ def add_table(self, data, use_header=True): table (str): this can be added to subheading or other cell if desired. """ - table = ['
', f''] + table = ['
', f"
"] def make_header(row): header = [] - header.append('') + header.append("") for item in row: - header.append(f'') - header.append('') - return '\n'.join(header) + header.append(f"") + header.append("") + return "\n".join(header) def add_row(row): - table_row = [''] + table_row = [""] for item in row: table_row.append(f"") - table_row.append('') - return '\n'.join(table_row) + table_row.append("") + return "\n".join(table_row) for i, row in enumerate(data): if i == 0 and use_header: table.append(make_header(row)) else: table.append(add_row(row)) - table.append('
{item}
{item}
{item}
') - table.append('
') - table = '\n'.join(table) - self.markdown.append(table + '\n\n') + table.append("") + table.append("") + table = "\n".join(table) + self.markdown.append(table + "\n\n") def save(self, save_dir): output = list(itertools.chain.from_iterable(self.markdown)) full_md_fname = os.path.join(save_dir, self.outname) - with open(full_md_fname, 'w') as f: + with open(full_md_fname, "w") as f: f.writelines(output) @@ -777,9 +776,7 @@ def ignore_aliases(self): class ExperimentComparison: def __init__(self, original, reproduced, **kwargs): - """ - - """ + """ """ self.original = original self.reproduced = reproduced @@ -789,33 +786,30 @@ def __init__(self, original, reproduced, **kwargs): @staticmethod def obs_diff(obs_orig, obs_repr): - return numpy.abs(numpy.divide((numpy.array(obs_orig) - - numpy.array(obs_repr)), - numpy.array(obs_orig))) + return numpy.abs( + numpy.divide((numpy.array(obs_orig) - numpy.array(obs_repr)), numpy.array(obs_orig)) + ) @staticmethod def test_stat(test_orig, test_repr): if isinstance(test_orig[0], str): if not isinstance(test_orig[1], str): - stats = numpy.array([0, - numpy.divide((test_repr[1] - test_orig[1]), - test_orig[1]), 0, 0]) + stats = numpy.array( + [0, numpy.divide((test_repr[1] - test_orig[1]), test_orig[1]), 0, 0] + ) else: stats = None else: - stats_orig = numpy.array([numpy.mean(test_orig), - numpy.std(test_orig), - scipy.stats.skew(test_orig)]) - stats_repr = numpy.array([numpy.mean(test_repr), - numpy.std(test_repr), - scipy.stats.skew(test_repr)]) + stats_orig = numpy.array( + [numpy.mean(test_orig), numpy.std(test_orig), scipy.stats.skew(test_orig)] + ) + stats_repr = numpy.array( + [numpy.mean(test_repr), numpy.std(test_repr), scipy.stats.skew(test_repr)] + ) ks = scipy.stats.ks_2samp(test_orig, test_repr) - stats = [*numpy.divide( - numpy.abs(stats_repr - stats_orig), - stats_orig - ), ks.pvalue] + stats = [*numpy.divide(numpy.abs(stats_repr - stats_orig), stats_orig), ks.pvalue] return stats def get_results(self): @@ -832,35 +826,40 @@ def get_results(self): results = dict.fromkeys([i.name for i in tests_orig]) for test in tests_orig: - if test.type in ['consistency', 'comparative']: + if test.type in ["consistency", "comparative"]: results[test.name] = dict.fromkeys(win_orig) for tw in win_orig: results_orig = self.original.read_results(test, tw) results_repr = self.reproduced.read_results(test, tw) results[test.name][tw] = { models_orig[i]: { - 'observed_statistic': self.obs_diff( + "observed_statistic": self.obs_diff( results_orig[i].observed_statistic, - results_repr[i].observed_statistic), - 'test_statistic': self.test_stat( + results_repr[i].observed_statistic, + ), + "test_statistic": self.test_stat( results_orig[i].test_distribution, - results_repr[i].test_distribution) + results_repr[i].test_distribution, + ), } - for i in range(len(models_orig))} + for i in range(len(models_orig)) + } else: results_orig = self.original.read_results(test, win_orig[-1]) results_repr = self.reproduced.read_results(test, win_orig[-1]) results[test.name] = { models_orig[i]: { - 'observed_statistic': self.obs_diff( + "observed_statistic": self.obs_diff( results_orig[i].observed_statistic, - results_repr[i].observed_statistic), - 'test_statistic': self.test_stat( - results_orig[i].test_distribution, - results_repr[i].test_distribution) + results_repr[i].observed_statistic, + ), + "test_statistic": self.test_stat( + results_orig[i].test_distribution, results_repr[i].test_distribution + ), } - for i in range(len(models_orig))} + for i in range(len(models_orig)) + } return results @@ -886,35 +885,27 @@ def get_filecomp(self): results = dict.fromkeys([i.name for i in tests_orig]) for test in tests_orig: - if test.type in ['consistency', 'comparative']: + if test.type in ["consistency", "comparative"]: results[test.name] = dict.fromkeys(win_orig) for tw in win_orig: results[test.name][tw] = dict.fromkeys(models_orig) for model in models_orig: - orig_path = self.original.path( - tw, 'evaluations', test, model) - repr_path = self.reproduced.path( - tw, 'evaluations', test, model) - - results[test.name][tw][model] ={ - 'hash': ( - self.get_hash(orig_path) == - self.get_hash(repr_path)), - 'byte2byte': filecmp.cmp(orig_path, - repr_path)} + orig_path = self.original.path(tw, "evaluations", test, model) + repr_path = self.reproduced.path(tw, "evaluations", test, model) + + results[test.name][tw][model] = { + "hash": (self.get_hash(orig_path) == self.get_hash(repr_path)), + "byte2byte": filecmp.cmp(orig_path, repr_path), + } else: results[test.name] = dict.fromkeys(models_orig) for model in models_orig: - orig_path = self.original.path( - win_orig[-1], 'evaluations', test, model) - repr_path = self.reproduced.path( - win_orig[-1], 'evaluations', test, model) - results[test.name][model] ={ - 'hash': ( - self.get_hash(orig_path) == - self.get_hash(repr_path)), - 'byte2byte': filecmp.cmp(orig_path, - repr_path)} + orig_path = self.original.path(win_orig[-1], "evaluations", test, model) + repr_path = self.reproduced.path(win_orig[-1], "evaluations", test, model) + results[test.name][model] = { + "hash": (self.get_hash(orig_path) == self.get_hash(repr_path)), + "byte2byte": filecmp.cmp(orig_path, repr_path), + } return results def compare_results(self): @@ -927,13 +918,12 @@ def write_report(self): numerical = self.num_results data = self.file_comp - outname = os.path.join('reproducibility_report.md') - save_path = os.path.dirname(os.path.join(self.reproduced.path.workdir, - self.reproduced.path.rundir)) - report = MarkdownReport(outname=outname) - report.add_title( - f"Reproducibility Report - {self.original.name}", '' + outname = os.path.join("reproducibility_report.md") + save_path = os.path.dirname( + os.path.join(self.reproduced.path.workdir, self.reproduced.path.rundir) ) + report = MarkdownReport(outname=outname) + report.add_title(f"Reproducibility Report - {self.original.name}", "") report.add_heading("Objectives", level=2) objs = [ @@ -961,76 +951,92 @@ def write_report(self): if is_time: report.add_heading(num[0], level=2) for tw in res_keys: - rows = [[tw, - 'Score difference', - 'Test Mean diff.', - 'Test Std diff.', - 'Test Skew diff.', - 'KS-test p value', - 'Hash (SHA-256) equal', - 'Byte-to-byte equal']] - - for model_stat, model_file in zip(num[1][tw].items(), - dat[1][tw].items()): - obs = model_stat[1]['observed_statistic'] - test = model_stat[1]['test_statistic'] - rows.append([model_stat[0], obs, - *[f'{i:.1e}' for i in test[:-1]], - f'{test[-1]:.1e}', - model_file[1]['hash'], - model_file[1]['byte2byte']]) + rows = [ + [ + tw, + "Score difference", + "Test Mean diff.", + "Test Std diff.", + "Test Skew diff.", + "KS-test p value", + "Hash (SHA-256) equal", + "Byte-to-byte equal", + ] + ] + + for model_stat, model_file in zip(num[1][tw].items(), dat[1][tw].items()): + obs = model_stat[1]["observed_statistic"] + test = model_stat[1]["test_statistic"] + rows.append( + [ + model_stat[0], + obs, + *[f"{i:.1e}" for i in test[:-1]], + f"{test[-1]:.1e}", + model_file[1]["hash"], + model_file[1]["byte2byte"], + ] + ) report.add_table(rows) else: report.add_heading(num[0], level=2) - rows = [[tw, - 'Max Score difference', - 'Hash (SHA-256) equal', - 'Byte-to-byte equal']] - - for model_stat, model_file in zip(num[1].items(), - dat[1].items()): - obs = numpy.nanmax(model_stat[1]['observed_statistic']) - - rows.append([model_stat[0], f'{obs:.1e}', - model_file[1]['hash'], - model_file[1]['byte2byte']]) + rows = [ + [tw, "Max Score difference", "Hash (SHA-256) equal", "Byte-to-byte equal"] + ] + + for model_stat, model_file in zip(num[1].items(), dat[1].items()): + obs = numpy.nanmax(model_stat[1]["observed_statistic"]) + + rows.append( + [ + model_stat[0], + f"{obs:.1e}", + model_file[1]["hash"], + model_file[1]["byte2byte"], + ] + ) report.add_table(rows) report.table_of_contents() report.save(save_path) + + ####################### # Perhaps add to pycsep ####################### + def plot_sequential_likelihood(evaluation_results, plot_args=None): if plot_args is None: plot_args = {} - title = plot_args.get('title', None) - titlesize = plot_args.get('titlesize', None) - ylabel = plot_args.get('ylabel', None) - colors = plot_args.get('colors', [None] * len(evaluation_results)) - linestyles = plot_args.get('linestyles', [None] * len(evaluation_results)) - markers = plot_args.get('markers', [None] * len(evaluation_results)) - markersize = plot_args.get('markersize', 1) - linewidth = plot_args.get('linewidth', 0.5) - figsize = plot_args.get('figsize', (6, 4)) - timestrs = plot_args.get('timestrs', None) + title = plot_args.get("title", None) + titlesize = plot_args.get("titlesize", None) + ylabel = plot_args.get("ylabel", None) + colors = plot_args.get("colors", [None] * len(evaluation_results)) + linestyles = plot_args.get("linestyles", [None] * len(evaluation_results)) + markers = plot_args.get("markers", [None] * len(evaluation_results)) + markersize = plot_args.get("markersize", 1) + linewidth = plot_args.get("linewidth", 0.5) + figsize = plot_args.get("figsize", (6, 4)) + timestrs = plot_args.get("timestrs", None) if timestrs: - startyear = [date.fromisoformat(j.split('_')[0]) for j in - timestrs][0] - endyears = [date.fromisoformat(j.split('_')[1]) for j in - timestrs] + startyear = [date.fromisoformat(j.split("_")[0]) for j in timestrs][0] + endyears = [date.fromisoformat(j.split("_")[1]) for j in timestrs] years = [startyear] + endyears else: startyear = 0 - years = numpy.arange(0, len(evaluation_results[0].observed_statistic) - + 1) - - seaborn.set_style("white", - {"axes.facecolor": ".9", 'font.family': 'Ubuntu'}) - pyplot.rcParams.update({'xtick.bottom': True, 'axes.labelweight': 'bold', - 'xtick.labelsize': 8, 'ytick.labelsize': 8, - 'legend.fontsize': 9}) + years = numpy.arange(0, len(evaluation_results[0].observed_statistic) + 1) + + seaborn.set_style("white", {"axes.facecolor": ".9", "font.family": "Ubuntu"}) + pyplot.rcParams.update( + { + "xtick.bottom": True, + "axes.labelweight": "bold", + "xtick.labelsize": 8, + "ytick.labelsize": 8, + "legend.fontsize": 9, + } + ) if isinstance(colors, list): assert len(colors) == len(evaluation_results) @@ -1048,11 +1054,16 @@ def plot_sequential_likelihood(evaluation_results, plot_args=None): fig, ax = pyplot.subplots(figsize=figsize) for i, result in enumerate(evaluation_results): data = [0] + result.observed_statistic - ax.plot(years, data, color=colors[i], - linewidth=linewidth, linestyle=linestyles[i], - marker=markers[i], - markersize=markersize, - label=result.sim_name) + ax.plot( + years, + data, + color=colors[i], + linewidth=linewidth, + linestyle=linestyles[i], + marker=markers[i], + markersize=markersize, + label=result.sim_name, + ) ax.set_ylabel(ylabel) ax.set_xlim([startyear, None]) ax.set_title(title, fontsize=titlesize) @@ -1062,39 +1073,32 @@ def plot_sequential_likelihood(evaluation_results, plot_args=None): def magnitude_vs_time(catalog): - mag = catalog.data['magnitude'] - time = [datetime.fromtimestamp(i / 1000.) for i in - catalog.data['origin_time']] + mag = catalog.data["magnitude"] + time = [datetime.fromtimestamp(i / 1000.0) for i in catalog.data["origin_time"]] fig, ax = pyplot.subplots(figsize=(12, 4)) - ax.plot(time, mag, marker='o', linewidth=0, color='r', alpha=0.2) - ax.set_xlabel('Date', fontsize=16) - ax.set_ylabel('$M_w$', fontsize=16) - ax.set_title('Magnitude vs. Time', fontsize=18) + ax.plot(time, mag, marker="o", linewidth=0, color="r", alpha=0.2) + ax.set_xlabel("Date", fontsize=16) + ax.set_ylabel("$M_w$", fontsize=16) + ax.set_title("Magnitude vs. Time", fontsize=18) return ax -def plot_matrix_comparative_test(evaluation_results, - p=0.05, - order=True, - plot_args={}): - """ Produces matrix plot for comparative tests for all models +def plot_matrix_comparative_test(evaluation_results, p=0.05, order=True, plot_args={}): + """Produces matrix plot for comparative tests for all models - Args: - evaluation_results (list of result objects): paired t-test results - p (float): significance level - order (bool): columns/rows ordered by ranking + Args: + evaluation_results (list of result objects): paired t-test results + p (float): significance level + order (bool): columns/rows ordered by ranking - Returns: - ax (matplotlib.Axes): handle for figure + Returns: + ax (matplotlib.Axes): handle for figure """ names = [i.sim_name for i in evaluation_results] - t_value = numpy.array( - [Tw_i.observed_statistic for Tw_i in evaluation_results]) - t_quantile = numpy.array( - [Tw_i.quantile[0] for Tw_i in evaluation_results]) - w_quantile = numpy.array( - [Tw_i.quantile[1] for Tw_i in evaluation_results]) + t_value = numpy.array([Tw_i.observed_statistic for Tw_i in evaluation_results]) + t_quantile = numpy.array([Tw_i.quantile[0] for Tw_i in evaluation_results]) + w_quantile = numpy.array([Tw_i.quantile[1] for Tw_i in evaluation_results]) score = numpy.sum(t_value, axis=1) / t_value.shape[0] if order: @@ -1109,23 +1113,45 @@ def plot_matrix_comparative_test(evaluation_results, fig, ax = pyplot.subplots(1, 1, figsize=(7, 6)) cmap = seaborn.diverging_palette(220, 20, as_cmap=True) - seaborn.heatmap(data_t, vmin=-3, vmax=3, center=0, cmap=cmap, - ax=ax, cbar_kws={'pad': 0.01, 'shrink': 0.7, - 'label': 'Information Gain', - 'anchor': (0., 0.)}), - ax.set_yticklabels([names[i] for i in arg_ind], rotation='horizontal') - ax.set_xticklabels([names[i] for i in arg_ind], rotation='vertical') + seaborn.heatmap( + data_t, + vmin=-3, + vmax=3, + center=0, + cmap=cmap, + ax=ax, + cbar_kws={ + "pad": 0.01, + "shrink": 0.7, + "label": "Information Gain", + "anchor": (0.0, 0.0), + }, + ), + ax.set_yticklabels([names[i] for i in arg_ind], rotation="horizontal") + ax.set_xticklabels([names[i] for i in arg_ind], rotation="vertical") for n, i in enumerate(data_tq): for m, j in enumerate(i): if j > 0 and data_w[n, m] < p: - ax.scatter(n + 0.5, m + 0.5, marker='o', s=5, color='black') - - legend_elements = [Line2D([0], [0], marker='o', lw=0, - label=r'T and W significant', - markerfacecolor="black", markeredgecolor='black', - markersize=4)] - fig.legend(handles=legend_elements, loc='lower right', - bbox_to_anchor=(0.75, 0.0, 0.2, 0.2), handletextpad=0) + ax.scatter(n + 0.5, m + 0.5, marker="o", s=5, color="black") + + legend_elements = [ + Line2D( + [0], + [0], + marker="o", + lw=0, + label=r"T and W significant", + markerfacecolor="black", + markeredgecolor="black", + markersize=4, + ) + ] + fig.legend( + handles=legend_elements, + loc="lower right", + bbox_to_anchor=(0.75, 0.0, 0.2, 0.2), + handletextpad=0, + ) pyplot.tight_layout() @@ -1133,6 +1159,7 @@ def plot_matrix_comparative_test(evaluation_results, # Below needs refactoring ######################### + def forecast_mapping(forecast_gridded, target_grid, ncpu=None): """ Aggregates conventional forecast onto quadtree region @@ -1148,14 +1175,14 @@ def forecast_mapping(forecast_gridded, target_grid, ncpu=None): level than the other grid. """ from csep.core.forecasts import GriddedForecast + bounds_target = target_grid.bounds bounds = forecast_gridded.region.bounds data = forecast_gridded.data - data_mapped_bounds = _forecast_mapping_generic(bounds_target, bounds, data, - ncpu=ncpu) - target_forecast = GriddedForecast(data=data_mapped_bounds, - region=target_grid, - magnitudes=forecast_gridded.magnitudes) + data_mapped_bounds = _forecast_mapping_generic(bounds_target, bounds, data, ncpu=ncpu) + target_forecast = GriddedForecast( + data=data_mapped_bounds, region=target_grid, magnitudes=forecast_gridded.magnitudes + ) return target_forecast @@ -1179,11 +1206,15 @@ def plot_quadtree_forecast(qtree_forecast): # single-resolution grid ax = qtree_forecast.plot() else: - print('Multi-resolution grid detected.') - print('Currently, we do not offer utility to plot a forecast with ' - 'multi-resolution grid') - print('Therefore, forecast is being aggregated on a single-resolution ' - 'grid (L8) for plotting') + print("Multi-resolution grid detected.") + print( + "Currently, we do not offer utility to plot a forecast with " + "multi-resolution grid" + ) + print( + "Therefore, forecast is being aggregated on a single-resolution " + "grid (L8) for plotting" + ) single_res_grid_l8 = QuadtreeGrid2D.from_single_resolution(8) forecast_l8 = forecast_mapping(qtree_forecast, single_res_grid_l8) @@ -1202,8 +1233,8 @@ def plot_forecast_lowres(forecast, plot_args, k=4): """ - print('\tPlotting Forecast') - plot_args['title'] = forecast.name + print("\tPlotting Forecast") + plot_args["title"] = forecast.name region = forecast.region coords = region.origins() dataset = numpy.log10(forecast.spatial_counts(cartesian=True))[::k, ::k] @@ -1213,26 +1244,26 @@ def plot_forecast_lowres(forecast, plot_args, k=4): def quadtree_csv_loader(csv_fname): - """ Load quadtree forecasted stored as csv file - The format expects forecast as a comma separated file, in which first - column corresponds to quadtree grid cell (quadkey). - The second and thrid columns indicate depth range. - The corresponding enteries in the respective row are forecast rates - corresponding to the magnitude bins. - The first line of forecast is a header, and its format is listed here: - 'Quadkey', depth_min, depth_max, Mag_0, Mag_1, Mag_2, Mag_3 , .... - Quadkey is a string. Rest of the values are floats. - For the purposes of defining region objects quadkey is used. - We assume that the starting value of magnitude bins are provided in the - header. - Args: - csv_fname: file name of csep forecast in csv format - Returns: - rates, region, mws (np.ndarray, QuadtreeRegion2D, np.ndarray): - rates, region, and magnitude bins needed to define QuadTree models - """ + """Load quadtree forecasted stored as csv file + The format expects forecast as a comma separated file, in which first + column corresponds to quadtree grid cell (quadkey). + The second and thrid columns indicate depth range. + The corresponding enteries in the respective row are forecast rates + corresponding to the magnitude bins. + The first line of forecast is a header, and its format is listed here: + 'Quadkey', depth_min, depth_max, Mag_0, Mag_1, Mag_2, Mag_3 , .... + Quadkey is a string. Rest of the values are floats. + For the purposes of defining region objects quadkey is used. + We assume that the starting value of magnitude bins are provided in the + header. + Args: + csv_fname: file name of csep forecast in csv format + Returns: + rates, region, mws (np.ndarray, QuadtreeRegion2D, np.ndarray): + rates, region, and magnitude bins needed to define QuadTree models + """ - data = numpy.genfromtxt(csv_fname, dtype='str', delimiter=',') + data = numpy.genfromtxt(csv_fname, dtype="str", delimiter=",") quadkeys = data[1:, 0] mws = data[0, 3:].astype(float) rates = data[1:, 3:] @@ -1248,8 +1279,7 @@ def geographical_area_from_qk(quadk): Wrapper around function geographical_area_from_bounds """ bounds = tile_bounds(quadk) - return geographical_area_from_bounds(bounds[0], bounds[1], bounds[2], - bounds[3]) + return geographical_area_from_bounds(bounds[0], bounds[1], bounds[2], bounds[3]) def tile_bounds(quad_cell_id): @@ -1277,7 +1307,8 @@ def create_polygon(fg): Required for parallel processing """ return shapely.geometry.Polygon( - [(fg[0], fg[1]), (fg[2], fg[1]), (fg[2], fg[3]), (fg[0], fg[3])]) + [(fg[0], fg[1]), (fg[2], fg[1]), (fg[2], fg[3]), (fg[0], fg[3])] + ) def calc_cell_area(cell): @@ -1287,8 +1318,7 @@ def calc_cell_area(cell): return geographical_area_from_bounds(cell[0], cell[1], cell[2], cell[3]) -def _map_overlapping_cells(fcst_grid_poly, fcst_cell_area, fcst_rate_poly, - target_poly): # , +def _map_overlapping_cells(fcst_grid_poly, fcst_cell_area, fcst_rate_poly, target_poly): # , """ This functions work for Cells that do not directly conside with target polygon cells. This function uses 3 variables i.e. fcst_grid_poly, @@ -1316,12 +1346,13 @@ def _map_overlapping_cells(fcst_grid_poly, fcst_cell_area, fcst_rate_poly, if target_poly.intersects(fcst_grid_poly[j]): # overlaps intersect = target_poly.intersection(fcst_grid_poly[j]) - shared_area = geographical_area_from_bounds(intersect.bounds[0], - intersect.bounds[1], - intersect.bounds[2], - intersect.bounds[3]) - map_rate = map_rate + ( - fcst_rate_poly[j] * (shared_area / fcst_cell_area[j])) + shared_area = geographical_area_from_bounds( + intersect.bounds[0], + intersect.bounds[1], + intersect.bounds[2], + intersect.bounds[3], + ) + map_rate = map_rate + (fcst_rate_poly[j] * (shared_area / fcst_cell_area[j])) return map_rate @@ -1339,10 +1370,10 @@ def _map_exact_inside_cells(fcst_grid, fcst_rate, boundary): boundary cell 2 - Array of the corresponding cells that fall inside """ - c = numpy.logical_and(numpy.logical_and(fcst_grid[:, 0] >= boundary[0], - fcst_grid[:, 1] >= boundary[1]), - numpy.logical_and(fcst_grid[:, 2] <= boundary[2], - fcst_grid[:, 3] <= boundary[3])) + c = numpy.logical_and( + numpy.logical_and(fcst_grid[:, 0] >= boundary[0], fcst_grid[:, 1] >= boundary[1]), + numpy.logical_and(fcst_grid[:, 2] <= boundary[2], fcst_grid[:, 3] <= boundary[3]), + ) exact_cells = numpy.where(c == True) @@ -1382,7 +1413,7 @@ def _forecast_mapping_generic(target_grid, fcst_grid, fcst_rate, ncpu=None): pool = multiprocessing.Pool(ncpu) else: pool = multiprocessing.Pool(ncpu) # mp.cpu_count() - print('Number of CPUs :', ncpu) + print("Number of CPUs :", ncpu) func_exact = partial(_map_exact_inside_cells, fcst_grid, fcst_rate) exact_rate = pool.map(func_exact, [poly for poly in target_grid]) @@ -1418,11 +1449,11 @@ def _forecast_mapping_generic(target_grid, fcst_grid, fcst_rate, ncpu=None): # print('--2nd Step: Start Polygon mapping--') pool = multiprocessing.Pool(ncpu) - func_overlapping = partial(_map_overlapping_cells, fcst_grid_poly, - fcst_cell_area, fcst_rate_poly) + func_overlapping = partial( + _map_overlapping_cells, fcst_grid_poly, fcst_cell_area, fcst_rate_poly + ) # Uses above three Global Parameters - rate_tgt = pool.map(func_overlapping, [poly for poly in - target_grid_poly]) + rate_tgt = pool.map(func_overlapping, [poly for poly in target_grid_poly]) pool.close() zero_pad_len = numpy.shape(fcst_rate)[1] @@ -1470,7 +1501,7 @@ def _set_dockerfile(name): def _global_region(dh=0.1, name="global", magnitudes=None): - """ Creates a global region used for evaluating gridded models on the + """Creates a global region used for evaluating gridded models on the global scale. Modified from csep.core.regions.global_region @@ -1489,8 +1520,8 @@ def _global_region(dh=0.1, name="global", magnitudes=None): lats = numpy.arange(-90, 90, dh) coords = itertools.product(lons, lats) region = CartesianGrid2D( - [Polygon(bbox) for bbox in compute_vertices(coords, dh)], dh, - name=name) + [Polygon(bbox) for bbox in compute_vertices(coords, dh)], dh, name=name + ) if magnitudes is not None: region.magnitudes = magnitudes return region @@ -1504,30 +1535,38 @@ def _check_zero_bins(exp, catalog, test_date): zero_forecast = numpy.argwhere(forecast.spatial_counts()[bins] == 0) if zero_forecast: print(zero_forecast) - ax = catalog.plot(plot_args={'basemap': 'stock_img'}) - ax = forecast.plot(ax=ax, plot_args={'alpha': 0.8}) - ax.plot(catalog.get_longitudes()[zero_forecast.ravel()], - catalog.get_latitudes()[zero_forecast.ravel()], 'o', - markersize=10) - pyplot.savefig(f'{model.path}/{model.name}.png', dpi=300) + ax = catalog.plot(plot_args={"basemap": "stock_img"}) + ax = forecast.plot(ax=ax, plot_args={"alpha": 0.8}) + ax.plot( + catalog.get_longitudes()[zero_forecast.ravel()], + catalog.get_latitudes()[zero_forecast.ravel()], + "o", + markersize=10, + ) + pyplot.savefig(f"{model.path}/{model.name}.png", dpi=300) for model in exp.models: forecast = model.create_forecast(exp.start_date, test_date) catalog.filter_spatial(forecast.region) sbins = catalog.get_spatial_idx() mbins = catalog.get_mag_idx() zero_forecast = numpy.argwhere(forecast.data[sbins, mbins] == 0) - print('event', 'cell', sbins[zero_forecast], 'datum', - catalog.data[zero_forecast]) + print("event", "cell", sbins[zero_forecast], "datum", catalog.data[zero_forecast]) if zero_forecast: print(zero_forecast) - print('cellfc', forecast.get_longitudes()[sbins[zero_forecast]], - forecast.get_latitudes()[sbins[zero_forecast]]) - print('scounts', forecast.spatial_counts()[sbins[zero_forecast]]) - print('data', forecast.data[sbins[zero_forecast]]) + print( + "cellfc", + forecast.get_longitudes()[sbins[zero_forecast]], + forecast.get_latitudes()[sbins[zero_forecast]], + ) + print("scounts", forecast.spatial_counts()[sbins[zero_forecast]]) + print("data", forecast.data[sbins[zero_forecast]]) print(forecast.data[zero_forecast[0]]) - ax = catalog.plot(plot_args={'basemap': 'stock_img'}) - ax = forecast.plot(ax=ax, plot_args={'alpha': 0.8}) - ax.plot(catalog.get_longitudes()[zero_forecast.ravel()], - catalog.get_latitudes()[zero_forecast.ravel()], 'o', - markersize=10) - pyplot.savefig(f'{model.path}/{model.name}.png', dpi=300) + ax = catalog.plot(plot_args={"basemap": "stock_img"}) + ax = forecast.plot(ax=ax, plot_args={"alpha": 0.8}) + ax.plot( + catalog.get_longitudes()[zero_forecast.ravel()], + catalog.get_latitudes()[zero_forecast.ravel()], + "o", + markersize=10, + ) + pyplot.savefig(f"{model.path}/{model.name}.png", dpi=300) diff --git a/requirements_dev.txt b/requirements_dev.txt index 8fe2c51..9cc3cc8 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,18 +1,30 @@ numpy +cartopy dateparser docker flake8 +geos gitpython h5py matplotlib +mercantile mypy +obspy +pandas +pillow +pyblack pycsep +pydocstringformatter +pyproj pyshp -pytest-cov pytest +pytest-cov +pytest-asyncio pyyaml requests +scipy seaborn +shapely sphinx sphinx-autoapi sphinx-gallery diff --git a/setup.cfg b/setup.cfg index b758f59..7b03544 100644 --- a/setup.cfg +++ b/setup.cfg @@ -56,11 +56,14 @@ dev = obspy pandas pillow + pyblack pycsep + pydocstringformatter pyproj pyshp - pytest-cov pytest + pytest-cov + pytest-asyncio pyyaml requests scipy diff --git a/tests/artifacts/models/model_cfg.yml b/tests/artifacts/models/model_cfg.yml index 1793f19..bd7a493 100644 --- a/tests/artifacts/models/model_cfg.yml +++ b/tests/artifacts/models/model_cfg.yml @@ -1,6 +1,6 @@ - mock: path: model.csv - use_db: True + store_db: True - qtree: path: qtree zenodo_id: 6289795 diff --git a/tests/artifacts/models/td_model/forecasts/mock_2020-01-01_2020-01-02.csv b/tests/artifacts/models/td_model/forecasts/mock_2020-01-01_2020-01-02.csv new file mode 100644 index 0000000..fdddae6 --- /dev/null +++ b/tests/artifacts/models/td_model/forecasts/mock_2020-01-01_2020-01-02.csv @@ -0,0 +1,2 @@ +lon, lat, M, time_string, depth, catalog_id, event_id +1.0,1.0,5.0,2020-01-01T01:01:01.0,10.0,1,1 \ No newline at end of file diff --git a/tests/artifacts/models/td_model/forecasts/mock_2020-01-02_2020-01-03.csv b/tests/artifacts/models/td_model/forecasts/mock_2020-01-02_2020-01-03.csv new file mode 100644 index 0000000..f89633b --- /dev/null +++ b/tests/artifacts/models/td_model/forecasts/mock_2020-01-02_2020-01-03.csv @@ -0,0 +1,2 @@ +lon, lat, M, time_string, depth, catalog_id, event_id +1.0,1.0,5.0,2020-01-02T01:01:01.0,10.0,1,1 \ No newline at end of file diff --git a/tests/integration/test_model_interface.py b/tests/integration/test_model_interface.py index cf4ee00..af3c0fb 100644 --- a/tests/integration/test_model_interface.py +++ b/tests/integration/test_model_interface.py @@ -2,7 +2,7 @@ import numpy.testing from datetime import datetime from unittest import TestCase -from floatcsep.model import Model +from floatcsep.model import TimeIndependentModel class TestModelFromFile(TestCase): @@ -11,57 +11,54 @@ class TestModelFromFile(TestCase): def setUpClass(cls) -> None: path = os.path.dirname(__file__) cls._path = path - cls._dir = os.path.join(path, '../', 'artifacts', 'models') + cls._dir = os.path.join(path, "../", "artifacts", "models") cls._alm_fn = os.path.join( - path, '../../examples', - 'case_e', - 'models', - 'gulia-wiemer.ALM.italy.10yr.2010-01-01.xml' + path, + "../../examples", + "case_e", + "models", + "gulia-wiemer.ALM.italy.10yr.2010-01-01.xml", ) @staticmethod def init_model(name, path, **kwargs): - """ Make model without Registry """ - # model = Model.__new__(Model) - # Model.__init__.__wrapped__(self=model, name=name, - # path=path, **kwargs) - model = Model(name, path, **kwargs) - # ext = os.path.splitext(path)[-1][1:] - # model.fmt = ext - # model.dir = os.path.dirname(path) if ext else path + + model = TimeIndependentModel(name, path, **kwargs) return model def test_forecast_ti_from_csv(self): - """ Parses forecast from csv file """ - name = 'mock' - fname = os.path.join(self._dir, 'model.csv') + """Parses forecast from csv file""" + name = "mock" + fname = os.path.join(self._dir, "model.csv") model = self.init_model(name, fname) start = datetime(1900, 1, 1) end = datetime(2000, 1, 1) model.stage([[start, end]]) model.forecast_from_file(start, end) - numpy.testing.assert_almost_equal(440., model.forecasts[ - '1900-01-01_2000-01-01'].data.sum()) + numpy.testing.assert_almost_equal( + 440.0, model.forecasts["1900-01-01_2000-01-01"].data.sum() + ) def test_forecast_ti_from_xml(self): - """ Parses forecast from XML file """ + """Parses forecast from XML file""" - name = 'ALM' + name = "ALM" fname = self._alm_fn numpy.seterr(all="ignore") - model = Model(name, fname) + model = self.init_model(name, fname) start = datetime(1900, 1, 1) end = datetime(2000, 1, 1) model.stage([[start, end]]) model.forecast_from_file(start, end) - numpy.testing.assert_almost_equal(1618.5424321406535, model.forecasts[ - '1900-01-01_2000-01-01'].data.sum()) + numpy.testing.assert_almost_equal( + 1618.5424321406535, model.forecasts["1900-01-01_2000-01-01"].data.sum() + ) def test_forecast_ti_from_xml2hdf5(self): - """ reads from xml, drops to db, makes forecast from db """ - name = 'ALM' + """reads from xml, drops to db, makes forecast from db""" + name = "ALM" fname = self._alm_fn numpy.seterr(all="ignore") @@ -71,13 +68,14 @@ def test_forecast_ti_from_xml2hdf5(self): model.stage([[start, end]]) model.forecast_from_file(start, end) - numpy.testing.assert_almost_equal(1618.5424321406535, model.forecasts[ - '1900-01-01_2000-01-01'].data.sum()) + numpy.testing.assert_almost_equal( + 1618.5424321406535, model.forecasts["1900-01-01_2000-01-01"].data.sum() + ) def test_forecast_ti_from_hdf5(self): - """ reads from hdf5, scale in runtime """ - name = 'mock' - fname = os.path.join(self._dir, 'model_h5.hdf5') + """reads from hdf5, scale in runtime""" + name = "mock" + fname = os.path.join(self._dir, "model_h5.hdf5") model = self.init_model(name=name, path=fname, use_db=True) model.stage() @@ -85,13 +83,18 @@ def test_forecast_ti_from_hdf5(self): end = datetime(2023, 1, 1) model.stage([[start, end]]) model.forecast_from_file(start, end) - numpy.testing.assert_almost_equal(13.2, model.forecasts[ - '2020-01-01_2023-01-01'].data.sum()) + numpy.testing.assert_almost_equal( + 13.2, model.forecasts["2020-01-01_2023-01-01"].data.sum() + ) @classmethod def tearDownClass(cls) -> None: - alm_db = os.path.join(cls._path, '../../examples', 'case_e', - 'models', - 'gulia-wiemer.ALM.italy.10yr.2010-01-01.hdf5') + alm_db = os.path.join( + cls._path, + "../../examples", + "case_e", + "models", + "gulia-wiemer.ALM.italy.10yr.2010-01-01.hdf5", + ) if os.path.isfile(alm_db): os.remove(alm_db) diff --git a/tests/integration/test_data.py b/tests/qa/test_data.py similarity index 100% rename from tests/integration/test_data.py rename to tests/qa/test_data.py diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py index 1915036..014bc29 100644 --- a/tests/unit/test_model.py +++ b/tests/unit/test_model.py @@ -1,15 +1,16 @@ import os.path import tempfile +import json from datetime import datetime import csep.core.regions import numpy.testing from unittest import TestCase -from unittest.mock import patch +from unittest.mock import patch, MagicMock, mock_open import filecmp -from floatcsep.model import Model +from floatcsep.model import TimeIndependentModel, TimeDependentModel from floatcsep.utils import str2timewindow import shutil @@ -22,12 +23,6 @@ def setUpClass(cls) -> None: cls._path = path cls._dir = os.path.normpath( os.path.join(path, '../artifacts', 'models')) - cls._alm_fn = os.path.join( - path, '../../examples', - 'case_e', - 'models', - 'gulia-wiemer.ALM.italy.10yr.2010-01-01.xml' - ) @staticmethod def assertEqualModel(exp_a, exp_b): @@ -42,17 +37,15 @@ def assertEqualModel(exp_a, exp_b): if not (getattr(exp_a, i) == getattr(exp_b, i)): raise AssertionError('Models are not equal') + +class TestTimeIndependentModel(TestModel): + @staticmethod - def initmodel_noreg(name, path, **kwargs): + def init_model(name, path, **kwargs): """ Instantiates a model without using the @register deco, but mocks Model.Registry() attrs""" - ### Save for registry: - # model = Model.__new__(Model) - # Model.__init__.__wrapped__(self=model, name=name, - # path=path, **kwargs) - model = Model(name, path, **kwargs) - ext = os.path.splitext(path)[-1][1:] + model = TimeIndependentModel(name, path, **kwargs) return model @@ -62,36 +55,34 @@ def test_from_filesystem(self): fname = os.path.join(self._dir, 'model.csv') # Initialize without Registry - model = self.initmodel_noreg(name=name, path=fname) + model = self.init_model(name=name, path=fname) self.assertEqual(name, model.name) self.assertEqual(fname, model.path) - self.assertEqual('ti', model.model_class) self.assertEqual(1, model.forecast_unit) - def test_from_zenodo(self): + def test_zenodo(self): """ downloads model from zenodo, checks with test artifacts""" name = 'mock_zenodo' - filename_ = 'datapackage.json' + filename_ = 'dummy.txt' dir_ = os.path.join(tempfile.tempdir, 'mock') if os.path.isdir(dir_): shutil.rmtree(dir_) path_ = os.path.join(dir_, filename_) - zenodo_id = 7096870 + zenodo_id = 13117711 # Initialize from zenodo id - model_a = self.initmodel_noreg(name=name, path=path_, - zenodo_id=zenodo_id) + model_a = self.init_model(name=name, path=path_, + zenodo_id=zenodo_id) model_a.stage() # Initialize from the artifact files (same as downloaded) - dir_art = os.path.join(self._path, '../artifacts', 'models', - 'zenodo_test') + dir_art = os.path.join(self._path, '../artifacts', 'models', 'zenodo_test') path = os.path.join(dir_art, filename_) - model_b = self.initmodel_noreg(name=name, path=path, - zenodo_id=zenodo_id) + model_b = self.init_model(name=name, path=path, + zenodo_id=zenodo_id) model_b.stage() self.assertEqual(os.path.basename(model_a.path('path')), @@ -100,7 +91,7 @@ def test_from_zenodo(self): self.assertTrue(filecmp.cmp(model_a.path('path'), model_b.path('path'))) - def test_fail_zenodo(self): + def test_zenodo_fail(self): name = 'mock_zenodo' filename_ = 'model_notreal.csv' # File not found in repository dir_ = os.path.join(tempfile.tempdir, 'zenodo_notreal') @@ -109,45 +100,11 @@ def test_fail_zenodo(self): path_ = os.path.join(dir_, filename_) # Initialize from zenodo id - model = self.initmodel_noreg(name=name, path=path_, zenodo_id=4739912) + model = self.init_model(name=name, path=path_, zenodo_id=13117711) with self.assertRaises(FileNotFoundError): model.get_source(model.zenodo_id, model.giturl) - def test_from_git(self): - """ clones model from git, checks with test artifacts""" - name = 'mock_git' - _dir = 'git_template' - path_ = os.path.join(tempfile.tempdir, _dir) - giturl = 'https://git.gfz-potsdam.de/csep-group/' \ - 'rise_italy_experiment/models/template.git' - model_a = self.initmodel_noreg(name=name, path=path_, - giturl=giturl) - model_a.stage() - path = os.path.join(self._dir, 'template') - model_b = self.initmodel_noreg(name=name, path=path) - model_b.stage() - self.assertEqual(model_a.name, model_b.name) - dircmp = filecmp.dircmp(model_a.dir, model_b.dir).common - self.assertGreater(len(dircmp), 8) - shutil.rmtree(path_) - - def test_fail_git(self): - name = 'mock_git' - filename_ = 'attr.c' - dir_ = os.path.join(tempfile.tempdir, 'git_notreal') - if os.path.isdir(dir_): - shutil.rmtree(dir_) - path_ = os.path.join(dir_, filename_) - - # Initialize from git url - model = self.initmodel_noreg( - name=name, path=path_, - giturl='https://github.com/github/testrepo') - - with self.assertRaises(FileNotFoundError): - model.get_source(model.zenodo_id, model.giturl, branch='master') - def test_from_dict(self): """ test that '__init__' and 'from_dict' instantiates identical objets""" @@ -167,11 +124,11 @@ def test_from_dict(self): } # Has to be instantiated with registry - model_a = Model.from_dict(dict_) + model_a = TimeIndependentModel.from_dict(dict_) # Import from normal py dict structure py_dict = {'name': 'mock', **dict_['mock']} - model_b = Model.from_dict(py_dict) + model_b = TimeIndependentModel.from_dict(py_dict) self.assertEqual(name, model_a.name) self.assertEqual(fname, model_a.path.path) @@ -181,25 +138,18 @@ def test_from_dict(self): self.assertEqualModel(model_a, model_b) with self.assertRaises(IndexError): - Model.from_dict({'model': 1, 'no_name': 2}) + TimeIndependentModel.from_dict({'model': 1, 'no_name': 2}) with self.assertRaises(IndexError): - Model.from_dict({'model_1': {'name': 'quack'}, + TimeIndependentModel.from_dict({'model_1': {'name': 'quack'}, 'model_2': {'name': 'moo'}}) - @patch('floatcsep.model.Model.forecast_from_func') - @patch('floatcsep.model.Model.forecast_from_file') - def test_create_forecast(self, mock_file, mock_func): + @patch('floatcsep.model.TimeIndependentModel.forecast_from_file') + def test_create_forecast(self, mock_file): - model = self.initmodel_noreg('mock', 'mockfile.csv') + model = self.init_model('mock', 'mockfile.csv') model.create_forecast('2020-01-01_2021-01-01') self.assertTrue(mock_file.called) - model = self.initmodel_noreg('mock', 'mockbins', model_class='td') - - model.path.build_tree([str2timewindow('2020-01-01_2021-01-01')]) - model.create_forecast('2020-01-01_2021-01-01') - self.assertTrue(mock_func.called) - def test_forecast_from_file(self): """ reads from file, scale in runtime """ _rates = numpy.array([[1., 0.1], @@ -216,7 +166,7 @@ def forecast_(_): fname = os.path.join(self._dir, 'model.csv') with patch('floatcsep.readers.ForecastParsers.csv', forecast_): - model = self.initmodel_noreg(name, fname) + model = self.init_model(name, fname) start = datetime(1900, 1, 1) end = datetime(2000, 1, 1) model.path.build_tree([[start, end]]) @@ -224,37 +174,9 @@ def forecast_(_): numpy.testing.assert_almost_equal(220., model.forecasts[ '1900-01-01_2000-01-01'].data.sum()) - def test_argprep(self): - model_path = os.path.join(self._dir, 'td_model') - with open(os.path.join(model_path, 'input', 'args.txt'), 'w') as args: - args.write('start_date = foo\nend_date = bar') - - model = self.initmodel_noreg('a', - model_path, - func='func') - start = datetime(2000, 1, 1) - end = datetime(2000, 1, 2) - model.stage([[start, end]]) - model.prepare_args(start, end) - - with open(os.path.join(model_path, 'input', 'args.txt'), 'r') as args: - self.assertEqual(args.readline(), - f'start_date = {start.isoformat()}\n') - self.assertEqual(args.readline(), - f'end_date = {end.isoformat()}\n') - model.prepare_args(start, end, n_sims=400) - with open(os.path.join(model_path, 'input', 'args.txt'), 'r') as args: - self.assertEqual(args.readlines()[2], - f'n_sims = 400\n') - - model.prepare_args(start, end, n_sims=200) - with open(os.path.join(model_path, 'input', 'args.txt'), 'r') as args: - self.assertEqual(args.readlines()[2], - f'n_sims = 200\n') - def test_get_forecast(self): - model = self.initmodel_noreg('mock', 'mockfile.csv') + model = self.init_model('mock', 'mockfile.csv') model.forecasts = {'a': 1, 'moo': 1, 'cuack': 1} self.assertEqual(1, model.get_forecast('a')) @@ -276,7 +198,7 @@ def test_todict(self): 'zenodo_id': 'should not be accessed, bc filesystem exists', 'model_class': 'ti' } - model = self.initmodel_noreg(name='mock', **dict_) + model = self.init_model(name='mock', **dict_) model_dict = model.as_dict() eq = True @@ -298,3 +220,200 @@ def test_init_db(self): def test_rm_db(self): pass + + +class TestTimeDependentModel(TestModel): + + @staticmethod + def init_model(name, path, **kwargs): + """ Instantiates a model without using the @register deco, + but mocks Model.Registry() attrs""" + + model = TimeDependentModel(name, path, **kwargs) + + return model + + def test_from_git(self): + """ clones model from git, checks with test artifacts""" + name = 'mock_git' + _dir = 'git_template' + path_ = os.path.join(tempfile.tempdir, _dir) + giturl = 'https://git.gfz-potsdam.de/csep-group/' \ + 'rise_italy_experiment/models/template.git' + model_a = self.init_model(name=name, path=path_, giturl=giturl) + model_a.stage() + path = os.path.join(self._dir, 'template') + model_b = self.init_model(name=name, path=path) + model_b.stage() + self.assertEqual(model_a.name, model_b.name) + dircmp = filecmp.dircmp(model_a.dir, model_b.dir).common + self.assertGreater(len(dircmp), 8) + shutil.rmtree(path_) + + def test_fail_git(self): + name = 'mock_git' + filename_ = 'attr.c' + dir_ = os.path.join(tempfile.tempdir, 'git_notreal') + if os.path.isdir(dir_): + shutil.rmtree(dir_) + path_ = os.path.join(dir_, filename_) + + # Initialize from git url + model = self.init_model( + name=name, path=path_, + giturl='https://github.com/github/testrepo') + + with self.assertRaises(FileNotFoundError): + model.get_source(model.zenodo_id, model.giturl, branch='master') + + @patch('floatcsep.model.TimeDependentModel.forecast_from_func') + def test_create_forecast(self, mock_func): + + model = self.init_model('mock', 'mockbins', model_class='td') + + model.path.build_tree([str2timewindow('2020-01-01_2021-01-01')]) + model.create_forecast('2020-01-01_2021-01-01') + self.assertTrue(mock_func.called) + + @patch('csep.load_catalog_forecast') # Mocking the load_catalog_forecast function + def test_get_forecast_single(self, mock_load_forecast): + # Arrange + model_path = os.path.join(self._dir, 'td_model') + model = self.init_model(name='mock', path=model_path) + tstring = '2020-01-01_2020-01-02' # Example time window string + model.stage([str2timewindow(tstring)]) + + print(model.path) + region = 'TestRegion' + + # Mock the return value of load_catalog_forecast + mock_forecast = MagicMock() + mock_load_forecast.return_value = mock_forecast + + # Act + result = model.get_forecast(tstring=tstring, region=region) + + # Assert + mock_load_forecast.assert_called_once_with(model.path("forecasts", tstring), + region=region) + self.assertEqual(result, mock_forecast) + + @patch('csep.load_catalog_forecast') + def test_get_forecast_multiple(self, mock_load_forecast): + + model_path = os.path.join(self._dir, 'td_model') + model = self.init_model(name='mock', path=model_path) + tstrings = ['2020-01-01_2020-01-02', + '2020-01-02_2020-01-03'] # Example list of time window strings + region = 'TestRegion' + model.stage(str2timewindow(tstrings)) + # Mock the return values of load_catalog_forecast for each forecast + mock_forecast1 = MagicMock() + mock_forecast2 = MagicMock() + mock_load_forecast.side_effect = [mock_forecast1, mock_forecast2] + + # Act + result = model.get_forecast(tstring=tstrings, region=region) + + # Assert + self.assertEqual(len(result), 2) + mock_load_forecast.assert_any_call(model.path("forecasts", tstrings[0]), region=region) + mock_load_forecast.assert_any_call(model.path("forecasts", tstrings[1]), region=region) + self.assertEqual(result[0], mock_forecast1) + self.assertEqual(result[1], mock_forecast2) + + @patch('subprocess.run') # Mock subprocess.run + @patch('subprocess.Popen') # Mock subprocess.Popen + @patch('os.path.exists') # Mock os.path.exists + def test_build_model_creates_venv(self, mock_exists, mock_popen, mock_run): + # Arrange + model_path = '../artifacts/models/td_model' + model = self.init_model(name='TestModel', path=model_path, build='venv') + mock_exists.return_value = False # Simulate that the venv does not exist + + # Act + model.build_model() + + # Assert + mock_run.assert_called_once_with(["python", "-m", "venv", model.path("path") + "/venv"]) + mock_popen.assert_called_once() # Ensure Popen was called to install dependencies + self.assertIn(f'cd {os.path.abspath(model_path)} && source', model.run_prefix) + + @patch('subprocess.run') + @patch('subprocess.Popen') + @patch('os.path.exists') + def test_build_model_when_venv_exists(self, mock_exists, mock_popen, mock_run): + # Arrange + model_path = '../artifacts/models/td_model' + model = self.init_model(name='TestModel', path=model_path, build='venv') + mock_exists.return_value = True # Simulate that the venv already exists + + # Act + model.build_model() + + # Assert + mock_run.assert_not_called() + mock_popen.assert_not_called() + self.assertIn(f'cd {os.path.abspath(model_path)} && source', model.run_prefix) + + def test_argprep(self): + model_path = os.path.join(self._dir, 'td_model') + with open(os.path.join(model_path, 'input', 'args.txt'), 'w') as args: + args.write('start_date = foo\nend_date = bar') + + model = self.init_model('a', + model_path, + func='func') + start = datetime(2000, 1, 1) + end = datetime(2000, 1, 2) + model.stage([[start, end]]) + model.prepare_args(start, end) + + with open(os.path.join(model_path, 'input', 'args.txt'), 'r') as args: + self.assertEqual(args.readline(), + f'start_date = {start.isoformat()}\n') + self.assertEqual(args.readline(), + f'end_date = {end.isoformat()}\n') + model.prepare_args(start, end, n_sims=400) + with open(os.path.join(model_path, 'input', 'args.txt'), 'r') as args: + self.assertEqual(args.readlines()[2], + f'n_sims = 400\n') + + model.prepare_args(start, end, n_sims=200) + with open(os.path.join(model_path, 'input', 'args.txt'), 'r') as args: + self.assertEqual(args.readlines()[2], + f'n_sims = 200\n') + + @patch('floatcsep.model.open', new_callable=mock_open, read_data='{"key": "value"}') + @patch('json.dump') + def test_argprep_json(self, mock_json_dump, mock_file): + model = self.init_model(name='TestModel', path=os.path.join(self._dir, 'td_model')) + model.path = MagicMock(return_value='path/to/model/args.json') # Mock path method + start = MagicMock() + end = MagicMock() + start.isoformat.return_value = '2023-01-01' + end.isoformat.return_value = '2023-01-31' + + kwargs = {'key1': 'value1', 'key2': 'value2'} + + # Act + model.prepare_args(start, end, **kwargs) + + # Assert + # Check that the file was opened for reading + mock_file.assert_any_call('path/to/model/args.json', 'r') + + # Check that the file was opened for writing + mock_file.assert_any_call('path/to/model/args.json', 'w') + + # Check that the JSON data was updated correctly + expected_data = { + "key": "value", + "start_date": '2023-01-01', + "end_date": '2023-01-31', + "key1": 'value1', + "key2": 'value2' + } + + # Check that json.dump was called with the expected data + mock_json_dump.assert_called_with(expected_data, mock_file(), indent=2) diff --git a/tox.ini b/tox.ini index f7e71d0..83516ba 100644 --- a/tox.ini +++ b/tox.ini @@ -6,20 +6,22 @@ isolated_build = true requires = tox-conda [testenv] -setenv= +setenv = PYTHONPATH = {toxinidir} -conda_channels= +conda_channels = defaults conda-forge -conda_deps= +conda_deps = cartopy geos pycsep -deps= +deps = -r{toxinidir}/requirements_dev.txt -commands= +commands = pip install -e .[dev] pytest --basetemp={envtmpdir} +package = wheel +wheel_build_env = .pkg