From 594c64139b0595eb61d6538649da666ebf435418 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Mon, 26 Feb 2024 18:22:07 +0800 Subject: [PATCH 01/38] fix: blob showcnt --- filescan.py | 180 ------------------------------------ woc/detect.py | 18 ++-- woc/local.pyi | 4 +- woc/local.pyx | 15 +-- woc/tch.pyx | 2 +- woc/wocprofile.default.json | 9 +- 6 files changed, 27 insertions(+), 201 deletions(-) delete mode 100644 filescan.py diff --git a/filescan.py b/filescan.py deleted file mode 100644 index 36af8ee..0000000 --- a/filescan.py +++ /dev/null @@ -1,180 +0,0 @@ -import os -import re -import logging -from typing import Optional, Set, Union, Dict, Tuple - -_basemap_pat = re.compile(r'^(\w+)2(\w+)Full(\w+)(?:.(\d+))?.tch$') -def parse_basemap_path(fname: str): - """ - Parse basemap filename into (src, dst, ver, idx) - >>> parse_basemap_path('c2fFullR.3.tch') - ('c', 'f', 'R', '3') - >>> parse_basemap_path('c2fFullR.tch') - ('c', 'f', 'R', None) - """ - m = _basemap_pat.match(fname) - if not m or len(m.groups()) != 4: - raise ValueError(f'Invalid path: {fname}') - return m.groups() - -_sha1map_pat = re.compile(r'^([\w\.]+)_(\d+).(\w+)$') -def parse_sha1map_path(fname: str): - """ - Parse sha1map (sha1o/sha1c/blob) filename into (name, idx, ext) - >>> parse_sha1map_path('commit_0.tch') - ('commit', '0', 'tch') - >>> parse_sha1map_path('blob_0.idx') - ('blob', '0', 'idx') - >>> parse_sha1map_path('sha1.blob_0.bin') - ('sha1.blob', '0', 'bin') - """ - m = _sha1map_pat.match(fname) - if not m or len(m.groups()) != 3: - raise ValueError(f'Invalid path: {fname}') - return m.groups() - -_short_name_to_full = { - 'a': 'author', - 'A': 'author_dealised', - 'b': 'blob', - 'c': 'commit', - 'cc': 'child_commit', - 'f': 'file', - 'fa': 'first_author', - 't': 'tree', - 'h': 'head', - 'p': 'project', - 'P': 'project_deforked', - 'pc': 'parent_commit', - 'r': 'root_commit', - 'ta': 'time_author', - 'tac': 'time_author_commit', - 'trp': 'torvalds_path', - 'dat': 'colon_seperated_data', - 'tch': 'compressed_data', - 'bin': 'binary_data', - 'idx': 'binary_index' -} - -# match (name)Full(ver).(idx).tch - -_full_name_to_short = {v: k for k, v in _short_name_to_full.items()} - -##### module configuration variables ##### - -# default config values -DEFAULT_BASE_PATH = '/woc' -DEFAULT_STORES = { - 'OSCAR_ALL_BLOBS': 'All.blobs', - 'OSCAR_ALL_SHA1C': 'All.sha1c', - 'OSCAR_ALL_SHA1O': 'All.sha1o', - 'OSCAR_BASEMAPS': 'basemaps', -} - -# tokyo cabinet store paths -PATHS: Dict[Tuple[str, str], Tuple[str, int, Optional[str]]] = {} - -# prefixes used by World of Code to identify source project platforms -# See Project.to_url() for more details -# Prefixes have been deprecated by replacing them with the string resembling -# actual URL -URL_PREFIXES = { - b'bitbucket.org': b'bitbucket.org', - b'gitlab.com': b'gitlab.com', - b'android.googlesource.com': b'android.googlesource.com', - b'bioconductor.org': b'bioconductor.org', - b'drupal.com': b'git.drupal.org', - b'git.eclipse.org': b'git.eclipse.org', - b'git.kernel.org': b'git.kernel.org', - b'git.postgresql.org': b'git.postgresql.org', - b'git.savannah.gnu.org': b'git.savannah.gnu.org', - b'git.zx2c4.com': b'git.zx2c4.com', - b'gitlab.gnome.org': b'gitlab.gnome.org', - b'kde.org': b'anongit.kde.org', - b'repo.or.cz': b'repo.or.cz', - b'salsa.debian.org': b'salsa.debian.org', - b'sourceforge.net': b'git.code.sf.net/p' -} -IGNORED_AUTHORS = ( - b'GitHub Merge Button ' -) - -def set_config( - base_path: str = DEFAULT_BASE_PATH, - stores: Optional[Dict[str, str]] = None, - url_prefixes: Optional[Dict[bytes, bytes]] = None, - ignored_authors: Optional[Tuple[bytes]] = None - ): - """Set the configuration for the Oscar module. - :param base_path: path to the woc directory - :param stores: a dictionary of store names (OSCAR_ALL_BLOBS, OSCAR_ALL_SHA1C, OSCAR_ALL_SHA1O, OSCAR_BASEMAPS) - to their relative paths in the woc directory - :param url_prefixes: a BYTES dictionary of url prefixes to their full urls (e.g. b'bitbucket.org' -> b'bitbucket.org') - :param ignored_authors: a BYTES tuple of authors to ignore (e.g. b'GitHub Merge Button ' - """ - - global PATHS, IGNORED_AUTHORS, URL_PREFIXES - - if not os.path.exists(base_path): - raise ValueError(f'Oscar failed to locate {base_path},' - 'please call set_config("/path/to/woc")') - - if stores is None: - stores = {k: os.path.join(base_path, v) for k, v in DEFAULT_STORES.items()} - - # Scan the woc data directory - for store_name, store_path in stores.items(): - for f in os.listdir(store_path): - try: - if store_name == 'OSCAR_BASEMAPS': - src, dst, ver, idx = parse_basemap_path(f) - k = (src, dst) - prefix_len = int(idx).bit_length() if idx else 0 - if k in PATHS: - _, _predix_len, _ver = PATHS[k][0], PATHS[k][1], PATHS[k][2] - if _ver > ver or (_ver == ver and _predix_len >= prefix_len): - continue - PATHS[k] = ( - os.path.join(store_path, - f.replace(idx, '{key}') if idx else f - ), prefix_len, ver) - pass - elif store_name in ('OSCAR_ALL_BLOBS', 'OSCAR_ALL_SHA1C', 'OSCAR_ALL_SHA1O'): - name, idx, ext = parse_sha1map_path(f) - try: - src = _full_name_to_short[name.replace('sha1.','')] - except KeyError: - raise ValueError(f'Invalid file type: {name}') - k = (src, ext) - prefix_len = int(idx).bit_length() if idx else 0 - if k in PATHS: - _, _predix_len = PATHS[k][0], PATHS[k][1] - if _predix_len >= prefix_len: - continue - PATHS[k] = ( - os.path.join(store_path, - f.replace(idx, '{key}') if idx else f - ), prefix_len, None) - else: - raise ValueError(f'Invalid store name: {store_name}, expected one of {DEFAULT_STORES.keys()}') - - except ValueError as e: - logging.warning(f'Cannot parse {f}: {repr(e)} ') - - print(f'Loaded {len(PATHS.keys())} maps: ' - f'{[_short_name_to_full[x[0]] + "->" + _short_name_to_full[x[1]] + ":" + str(PATHS[x]) for x in PATHS.keys()]}') - - if url_prefixes is not None: - URL_PREFIXES = url_prefixes - - if ignored_authors is not None: - IGNORED_AUTHORS = ignored_authors - -# run set_config on import -set_config() - -if __name__ == '__main__': - import doctest - doctest.testmod() - - print(PATHS) \ No newline at end of file diff --git a/woc/detect.py b/woc/detect.py index 1d6bb97..ca47a6d 100644 --- a/woc/detect.py +++ b/woc/detect.py @@ -9,7 +9,7 @@ import logging import argparse import re -from typing import Dict, Iterable, Tuple, Optional +from typing import Iterable, Tuple, Optional from functools import cmp_to_key DEFAULT_PROFILE = os.path.join(os.path.dirname(__file__), 'wocprofile.default.json') @@ -129,6 +129,7 @@ def detect_profile( paths: Iterable[str], version: Optional[str] = None, preset_path: str = DEFAULT_PROFILE, + check_missing: bool = True ): _maps, _objs = {}, {} @@ -203,7 +204,7 @@ def _handle_obj(name, idx, ext): continue _logger.warning(f'Unrecognized file: {f}') - # transform maps and objs + # transform maps _ls_maps = {} for k, v in _maps.items(): _to_drop = [] @@ -214,7 +215,7 @@ def _handle_obj(name, idx, ext): _ls[kkk] = vvv # see if we can find the None in _ls _nones = [i for i, x in enumerate(_ls) if x is None] - if _nones: + if _nones and check_missing: _logger.warning(f'Cannot find shards {", ".join(map(str, _nones))} in map {k} ver {ver}, skipping') _logger.warning(f"Got: {vv['shards']}") _to_drop.append(ver) @@ -224,12 +225,15 @@ def _handle_obj(name, idx, ext): del v[ver] # move latest maps to the front of the list - _ls_maps[k] = [v for k, v in sorted( + if len(v) == 0: + continue + _ls_maps[k] = [vv for _, vv in sorted( v.items(), key=cmp_to_key(lambda x, y: compare_woc_version(x[0], y[0])), reverse=True )] + # transform objects _ls_objs = {} for k, v in _objs.items(): # convert shards to list @@ -238,7 +242,7 @@ def _handle_obj(name, idx, ext): _ls[kk] = vv # see if we can find the None in _ls _nones = [i for i, x in enumerate(_ls) if x is None] - if _nones: + if _nones and check_missing: _logger.warning(f'Cannot find shards {", ".join(map(str, _nones))} in obj {k}, skipping') _logger.warning(f"Got: {v['shards']}") else: @@ -259,7 +263,7 @@ def _handle_obj(name, idx, ext): parser.add_argument('--version', type=str, default=None, help='woc mapping version') parser.add_argument('--preset', type=str, default=DEFAULT_PROFILE, help='path to preset profile') parser.add_argument('--output', type=str, default=None, help='path to output profile') - +parser.add_argument('--no-skip-missing', dest='check_missing', action='store_false', help='do not check missing shards') if __name__ == '__main__': import doctest @@ -267,7 +271,7 @@ def _handle_obj(name, idx, ext): args = parser.parse_args() - res = detect_profile(args.paths, args.version, args.preset) + res = detect_profile(args.paths, args.version, args.preset, args.check_missing) if args.output: with open(args.output, 'w') as f: json.dump(res, f, indent=2) diff --git a/woc/local.pyi b/woc/local.pyi index 993c8dd..0346213 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -13,12 +13,12 @@ class WocMapsLocal(WocMapsBase): self, map_name: str, key: Union[bytes, str], - ): + ) -> (list[str] | tuple[str, str, str] | list[tuple[str, str, str]]): ... def show_content( self, obj: WocObjectsWithContent, key: Union[bytes, str], - ): + ) -> (list[tuple[str, str, str]] | str): ... \ No newline at end of file diff --git a/woc/local.pyx b/woc/local.pyx index cb81db0..16a9575 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -1,4 +1,4 @@ -# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False +# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True # SPDX-License-Identifier: GPL-3.0-or-later # @authors: Runzhi He # @date: 2024-01-17 @@ -206,10 +206,10 @@ class WocMapsLocal(WocMapsBase): if v and v != b'EMPTY'] elif out_dtype == 's': # type: list[str] return value.decode('utf-8').split(';') - elif out_dtype == 'r': # type: list[str] - data = decomp(value) - return [author.decode('utf-8') for author in (data.split(b';') if data else []) - if author not in self.config['ignoredAuthors']] + elif out_dtype == 'r': # type: list[str, int] + _hex = value[:20].hex() + _len = unber(value[20:])[0] + return (_hex, _len) elif out_dtype == 'hhwww': raise NotImplemented raise ValueError(f'Unsupported dtype: {out_dtype}') @@ -298,7 +298,7 @@ class WocMapsLocal(WocMapsBase): def show_content( self, - obj: Literal['tree', 'blob', 'commit', 'tkns', 'tag', 'bdiff'], + obj: str, key: Union[bytes, str], ): """Eqivalent to showCnt in WoC perl API @@ -325,13 +325,14 @@ class WocMapsLocal(WocMapsBase): ) return decomp_or_raw(v).decode('utf-8') elif obj == 'blob': - _map_obj = self.config['objects']['blob.tch'] + _map_obj = self.config['objects']['sha1.blob.tch'] v = get_from_tch(key, shards=_map_obj['shards'], sharding_bits=_map_obj['sharding_bits'], use_fnv_keys=False ) offset, length = unber(v) + _map_obj = self.config['objects']['blob.bin'] shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) _out_bin = self._read_file_with_offset( _map_obj['shards'][shard], diff --git a/woc/tch.pyx b/woc/tch.pyx index 43e1122..92db74d 100644 --- a/woc/tch.pyx +++ b/woc/tch.pyx @@ -1,4 +1,4 @@ -# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False +# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True # SPDX-License-Identifier: GPL-3.0-or-later # @authors: Runzhi He diff --git a/woc/wocprofile.default.json b/woc/wocprofile.default.json index aa3b548..118c943 100644 --- a/woc/wocprofile.default.json +++ b/woc/wocprofile.default.json @@ -24,11 +24,12 @@ }, "dtypes": { "h": "hex", - "s": "string", - "cs": "compressed_string", - "sh": "string_hex", + "s": "str", + "cs": "[compressed]str", + "sh": "str_hex", "hhwww": "hex_hex_url", - "cs3": "compressed_3_strings" + "r": "hex_berint", + "cs3": "[compressed]str_str_str" }, "sites": { "bitbucket.org": "bitbucket.org", From 978eed9cb8da35d8d261c61880ee022f1209121d Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Mon, 3 Jun 2024 19:06:58 +0800 Subject: [PATCH 02/38] perf: fix hexstrify takes too long --- woc/local.pyx | 34 +++++++++++++++++++++++++--------- woc/tch.pxd | 2 +- woc/tch.pyx | 2 +- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/woc/local.pyx b/woc/local.pyx index 16a9575..7903884 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -1,12 +1,14 @@ -# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True +# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True, linetrace=True # SPDX-License-Identifier: GPL-3.0-or-later # @authors: Runzhi He # @date: 2024-01-17 import os import json +import logging +import time from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t -from typing import Tuple, Dict, Iterable, List, Union, Literal +from typing import Tuple, Dict, Iterable, List, Union, Literal, Optional import zlib try: @@ -16,7 +18,9 @@ except ImportError or AssertionError: raise ImportError('python-lzf is required to decompress LZF-compressed data: `pip install python-lzf`') from .base import WocMapsBase, WocKeyError, WocObjectsWithContent, WocSupportedProfileVersions -from .tch cimport fnvhash, get_from_tch, get_shard +from .tch cimport get_from_tch, get_shard, fnvhash + +logger = logging.getLogger(__name__) cdef unber(bytes buf): r""" Perl BER unpacking. @@ -135,8 +139,8 @@ def slice20(bytes raw_data): class WocMapsLocal(WocMapsBase): def __init__(self, - profile_path: str | Iterable[str] | None = None, - version: str | Iterable[str] | None = None + profile_path: Union[str, Iterable[str], None] = None, + version: Union[str, Iterable[str], None] = None ) -> None: # load profile if profile_path is None: @@ -231,30 +235,42 @@ class WocMapsLocal(WocMapsBase): else: raise KeyError(f'Invalid map name: {map_name}, ' f'expect one of {", ".join(self.config["maps"].keys())}') + + start_time = time.time_ns() + logger.debug(f"start get_values: {map_name} {key}") if _map["dtypes"][0] == 'h': if isinstance(key, str): _hex = key key = bytes.fromhex(key) else: - _hex = bytes.hex(key) + _hex = bytes(key).hex() else: assert isinstance(key, str), "key must be a string for non-hash keys" - _hex = bytes(fnvhash(key.encode('utf-8'))).hex() + _hex = hex(fnvhash(key.encode('utf-8')))[2:] key = key.encode('utf-8') + logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() + if "larges" in _map and _hex in _map["larges"]: _bytes = self._read_large(_map["larges"][_hex], _map["dtypes"][0]) + logger.debug(f"read large: {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() else: # use fnv hash as shading idx if key is not a git sha _bytes = get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() - return self._decode_value(_bytes, _map["dtypes"][1]) + _ret = self._decode_value(_bytes, _map["dtypes"][1]) + logger.debug(f"decode value: {(time.time_ns() - start_time) / 1e6:.2f}ms") + return _ret @staticmethod def _decode_tree( value: bytes - ) -> list[tuple[str, str, str]]: + ) -> List[Tuple[str, str, str]]: """ Decode a tree binary object into tuples Reference: https://stackoverflow.com/questions/14790681/ diff --git a/woc/tch.pxd b/woc/tch.pxd index 6b74a64..66de590 100644 --- a/woc/tch.pxd +++ b/woc/tch.pxd @@ -1,4 +1,4 @@ -# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False +# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True, linetrace=True from libc.stdint cimport uint8_t, uint32_t diff --git a/woc/tch.pyx b/woc/tch.pyx index 92db74d..103a273 100644 --- a/woc/tch.pyx +++ b/woc/tch.pyx @@ -1,4 +1,4 @@ -# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True +# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True, linetrace=True # SPDX-License-Identifier: GPL-3.0-or-later # @authors: Runzhi He From b35eea5c23c56190f29f21e700e593bff5834177 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 4 Jun 2024 02:05:27 +0800 Subject: [PATCH 03/38] chore: enable line profiling --- setup.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 3061936..f402482 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,16 @@ +# distutils: define_macros=CYTHON_TRACE_NOGIL=1 + import os from setuptools import setup, Extension, find_packages from Cython.Build import cythonize +# Thanks to @tryptofame for proposing an updated snippet +from Cython.Compiler.Options import get_directive_defaults +directive_defaults = get_directive_defaults() + +directive_defaults['linetrace'] = True +directive_defaults['binding'] = True + ROOT = os.path.abspath(os.path.dirname(__file__)) PACKAGE_ROOT = os.path.join(ROOT, "woc") TCH_ROOT = os.path.join(ROOT, "lib") @@ -15,7 +24,8 @@ sources=[ os.path.join(PACKAGE_ROOT, 'local.pyx'), ], - extra_compile_args=['-std=gnu11'] + extra_compile_args=['-std=gnu11'], + define_macros=[('CYTHON_TRACE', '1')], ), Extension( 'woc.tch', @@ -28,13 +38,14 @@ os.path.join(TCH_ROOT, 'tcutil.c'), os.path.join(TCH_ROOT, 'md5.c') ], - extra_compile_args=['-std=gnu11'] + extra_compile_args=['-std=gnu11'], + define_macros=[('CYTHON_TRACE', '1')], ), ] setup( name="python-woc", - ext_modules=cythonize(ext_modules), + ext_modules=cythonize(ext_modules, emit_linenums=True,), packages=PACKAGES, package_data={"": ["*.pyx", "*.pxd", "*.pxi"]}, include_package_data=True, From 223cb44929d09a9062507156679fabbfab50b3eb Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 4 Jun 2024 02:06:15 +0800 Subject: [PATCH 04/38] feat: add timer logs --- woc/local.pyx | 55 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/woc/local.pyx b/woc/local.pyx index 7903884..3c84bdd 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -9,7 +9,7 @@ import logging import time from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t from typing import Tuple, Dict, Iterable, List, Union, Literal, Optional -import zlib +import gzip try: import lzf @@ -160,12 +160,12 @@ class WocMapsLocal(WocMapsBase): break else: raise FileNotFoundError("No wocprofile.json found in the following paths: {}, " - "run `python3 -m woc detect` to generate".format(profile_path)) + "run `python3 -m woc.detect` to generate".format(profile_path)) # check profile assert self.config["wocSchemaVersion"] in WocSupportedProfileVersions, \ "Unsupported wocprofile version: {}".format(self.config["wocSchemaVersion"]) - assert self.config["maps"], "Run `python3 -m woc detect` to scan data files and generate wocprofile.json" + assert self.config["maps"], "Run `python3 -m woc.detect` to scan data files and generate wocprofile.json" @staticmethod def _read_large(path: str, dtype: str) -> bytes: @@ -176,8 +176,8 @@ class WocMapsLocal(WocMapsBase): return f.read() else: # use zlib to decompress - with open(path, 'rb') as f: - _uncompressed = zlib.decompress(f.read()) + with gzip.open(path, 'rb') as f: + _uncompressed = f.read() # find first 256 bytes for b'\n', don't scan the whole document _idx = _uncompressed[:256].find(b'\n') if _idx > 0: @@ -209,7 +209,9 @@ class WocMapsLocal(WocMapsBase): for v in data.split(b';') if v and v != b'EMPTY'] elif out_dtype == 's': # type: list[str] - return value.decode('utf-8').split(';') + print(value[:100]) + return [v.decode('utf-8') + for v in value.split(b';')] elif out_dtype == 'r': # type: list[str, int] _hex = value[:20].hex() _len = unber(value[20:])[0] @@ -237,7 +239,7 @@ class WocMapsLocal(WocMapsBase): f'expect one of {", ".join(self.config["maps"].keys())}') start_time = time.time_ns() - logger.debug(f"start get_values: {map_name} {key}") + logger.debug(f"get_values: {map_name} {key}") if _map["dtypes"][0] == 'h': if isinstance(key, str): @@ -252,19 +254,25 @@ class WocMapsLocal(WocMapsBase): logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() + + decode_dtype = _map["dtypes"][1] if "larges" in _map and _hex in _map["larges"]: - _bytes = self._read_large(_map["larges"][_hex], _map["dtypes"][0]) + _bytes = self._read_large(_map["larges"][_hex], _map["dtypes"][1]) logger.debug(f"read large: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() + + # compress string data is not compressed in larges + if decode_dtype == 'cs': + decode_dtype = 's' else: # use fnv hash as shading idx if key is not a git sha _bytes = get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - _ret = self._decode_value(_bytes, _map["dtypes"][1]) - logger.debug(f"decode value: {(time.time_ns() - start_time) / 1e6:.2f}ms") + _ret = self._decode_value(_bytes, decode_dtype) + logger.debug(f"decode value: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret @staticmethod @@ -321,9 +329,16 @@ class WocMapsLocal(WocMapsBase): >>> show_content('tree', '7a374e58c5b9dec5f7508391246c48b73c40d200') # doctest: +SKIP ... """ + start_time = time.time_ns() + logger.debug(f"show_content: {obj} {key}") + + if isinstance(key, str): key = bytes.fromhex(key) + logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() + if obj == 'tree': _map_obj = self.config['objects']['tree.tch'] v = get_from_tch(key, @@ -331,7 +346,12 @@ class WocMapsLocal(WocMapsBase): sharding_bits=_map_obj['sharding_bits'], use_fnv_keys=False ) - return self._decode_tree(decomp_or_raw(v)) + logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() + _ret = self._decode_tree(decomp_or_raw(v)) + logger.debug(f"decode tree: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") + return _ret + elif obj == 'commit': _map_obj = self.config['objects']['commit.tch'] v = get_from_tch(key, @@ -339,7 +359,9 @@ class WocMapsLocal(WocMapsBase): sharding_bits=_map_obj['sharding_bits'], use_fnv_keys=False ) + logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") return decomp_or_raw(v).decode('utf-8') + elif obj == 'blob': _map_obj = self.config['objects']['sha1.blob.tch'] v = get_from_tch(key, @@ -347,6 +369,9 @@ class WocMapsLocal(WocMapsBase): sharding_bits=_map_obj['sharding_bits'], use_fnv_keys=False ) + logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() + offset, length = unber(v) _map_obj = self.config['objects']['blob.bin'] shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) @@ -355,7 +380,13 @@ class WocMapsLocal(WocMapsBase): offset, length ) - return decomp_or_raw(_out_bin).decode('utf-8') + logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() + + _ret = decomp_or_raw(_out_bin).decode('utf-8') + logger.debug(f"decode blob: len={len(_ret)} {(time.time_ns() - start_time) / 1e6:.2f}ms") + return _ret + elif obj == 'tkns': raise NotImplemented elif obj == 'tag': From 1eeebcc549705cb2c9bbdaf81ac5c1426e12cc72 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 4 Jun 2024 02:14:32 +0800 Subject: [PATCH 05/38] chore: add file exists check --- woc/tch.pyx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/woc/tch.pyx b/woc/tch.pyx index 103a273..ba5ee3f 100644 --- a/woc/tch.pyx +++ b/woc/tch.pyx @@ -7,6 +7,7 @@ from libc.stdint cimport uint8_t, uint32_t, uint64_t from libc.stdlib cimport free from threading import Lock +import os from .base import WocKeyError @@ -141,6 +142,10 @@ cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys): return prefix cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys): + # not 100% necessary but there are cases where some tchs are miserably missing + _shard = get_shard(key, sharding_bits, use_fnv_keys) + _path = shards[_shard] + assert _path and os.path.exists(_path), f"shard {_shard} not found at {_path}" return _get_tch( shards[get_shard(key, sharding_bits, use_fnv_keys)].encode('utf-8') )[key] From f962bdced3a955c083159bbefdc9069089ddc874 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 4 Jun 2024 03:51:16 +0800 Subject: [PATCH 06/38] feat: detect encoding when utf8 fails --- requirements.txt | 3 ++- woc/local.pyx | 25 ++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7a33918..1f60442 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ python-lzf -typing \ No newline at end of file +typing +chardet \ No newline at end of file diff --git a/woc/local.pyx b/woc/local.pyx index 3c84bdd..aed065c 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -136,6 +136,14 @@ def slice20(bytes raw_data): return () return tuple(raw_data[i:i + 20] for i in range(0, len(raw_data), 20)) +def decode_str(bytes raw_data): + """ Decode raw_data, detect the encoding if utf-8 fails """ + try: + return raw_data.decode('utf-8') + except UnicodeDecodeError: + import chardet # should be rarely used + _encoding = chardet.detect(raw_data)['encoding'] + return raw_data.decode(_encoding, errors='replace') class WocMapsLocal(WocMapsBase): def __init__(self, @@ -194,23 +202,22 @@ class WocMapsLocal(WocMapsBase): elif out_dtype == 'sh': # type: tuple[str, str, str] buf0 = value[0:len(value)-21] cmt_sha = value[(len(value)-20):len(value)] - (Time, Author) = buf0.decode('utf-8').split(";") + (Time, Author) = decode_str(buf0).split(";") return (Time, Author, cmt_sha.hex()) elif out_dtype == 'cs3': # type: list[tuple[str, str, str]] data = decomp(value) - _splited = data.decode('utf-8').split(";") + _splited = decode_str(data).split(";") return [ (_splited[i],_splited[i+1],_splited[i+2]) for i in range(0, len(_splited), 3) ] elif out_dtype == 'cs': # type: list[str] data = decomp(value) - return [v.decode('utf-8') + return [decode_str(v) for v in data.split(b';') if v and v != b'EMPTY'] elif out_dtype == 's': # type: list[str] - print(value[:100]) - return [v.decode('utf-8') + return [decode_str(v) for v in value.split(b';')] elif out_dtype == 'r': # type: list[str, int] _hex = value[:20].hex() @@ -296,10 +303,10 @@ class WocMapsLocal(WocMapsBase): i = 0 while i < len(value): if value[i] == 0x20: - _file_buf.append(_curr_buf.decode('utf-8')) + _file_buf.append(decode_str(_curr_buf)) _curr_buf = bytes() elif value[i] == 0x00: - _file_buf.append(_curr_buf.decode('utf-8')) + _file_buf.append(decode_str(_curr_buf)) # take next 20 bytes as a hash _curr_buf = value[i+1:i+21] _file_buf.append(_curr_buf.hex()) @@ -360,7 +367,7 @@ class WocMapsLocal(WocMapsBase): use_fnv_keys=False ) logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") - return decomp_or_raw(v).decode('utf-8') + return decode_str(decomp_or_raw(v)) elif obj == 'blob': _map_obj = self.config['objects']['sha1.blob.tch'] @@ -383,7 +390,7 @@ class WocMapsLocal(WocMapsBase): logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - _ret = decomp_or_raw(_out_bin).decode('utf-8') + _ret = decode_str(decomp_or_raw(_out_bin)) logger.debug(f"decode blob: len={len(_ret)} {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret From 0fa7f7c48c4376e37d264bf4843112f22d1bfc22 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 4 Jun 2024 03:51:51 +0800 Subject: [PATCH 07/38] feat: add perl-like shell api --- woc/get_values.py | 41 ++++++++++++++++ woc/show_content.py | 111 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 woc/get_values.py create mode 100644 woc/show_content.py diff --git a/woc/get_values.py b/woc/get_values.py new file mode 100644 index 0000000..77c481d --- /dev/null +++ b/woc/get_values.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: GPL-3.0-or-later +# @authors: Runzhi He +# @date: 2024-05-27 + +from typing import Iterable +from .local import WocMapsLocal + +def format_map(key: str, map_objs: Iterable) -> str: + return key + ';' + ';'.join(map(str, map_objs)) + +if __name__ == '__main__': + import argparse + import sys + import os + import logging + + parser = argparse.ArgumentParser(description='Get record of various maps') + parser.add_argument('type', type=str, help='The type of the object') + # key is taken from stdin + parser.add_argument('key', type=str, help='The key of the object', nargs='?') + args = parser.parse_args() + if not args.key: + args.key = sys.stdin.readline() + args.key = args.key.strip() + + woc = WocMapsLocal() + for line in sys.stdin: + try: + key = line.strip() + obj = woc.get_values(args.type, args.key) + print(format_map(args.key, obj)) + except BrokenPipeError: + # ref: https://docs.python.org/3/library/signal.html#note-on-sigpipe + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + sys.exit(1) # Python exits with error code 1 on EPIPE + except Exception as e: + logging.error(f'Error in {key}: {e}', exc_info=True) + continue \ No newline at end of file diff --git a/woc/show_content.py b/woc/show_content.py new file mode 100644 index 0000000..34221b3 --- /dev/null +++ b/woc/show_content.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: GPL-3.0-or-later +# @authors: Runzhi He +# @date: 2024-05-27 + +from .local import WocMapsLocal + +def format_tree(tree_objs: list) -> str: + _out = '' + for line in tree_objs: + _out += f'{line[0]};{line[2]};{line[1]}\n' + return _out + +def format_commit(sha: str, cmt: str, format: int = 0): + if format == 3: # raw + return cmt + + if format == 7: # commit sha; base64(raw) + import base64 + _b64 = base64.b64encode(cmt.encode()).decode() + # mock linux's base64, add newline every 76 characters + _b64 = '\\n'.join([_b64[i:i+76] for i in range(0, len(_b64), 76)]) + '\\n' + return sha + ';' + _b64 + + lines = cmt.split('\n') + tree_sha = lines[0][5:] + + if lines[1].startswith('parent'): + parent_sha = lines[1][7:] + else: + # insert a dummy line + lines.insert(1, '') + parent_sha = '' + + author_idx = lines[2].find('>') + author = lines[2][7:author_idx+1] + author_time = lines[2][author_idx+2:] + author_timestamp = author_time.split(' ')[0] + author_timezone = author_time.split(' ')[1] + + committer_idx = lines[3].find('>') + committer = lines[3][10:committer_idx+1] + committer_time = lines[3][committer_idx+2:] + committer_timestamp = committer_time.split(' ')[0] + committer_timezone = committer_time.split(' ')[1] + + commit_msg = '\\n'.join(lines[5:]) + if commit_msg.endswith('\\n'): # strip + commit_msg = commit_msg[:-2] + + if format == 0: # commit SHA;tree SHA;parent commit SHA;author;committer;author timestamp;commit timestamp + return ';'.join([sha, tree_sha, parent_sha, author, committer, author_timestamp, committer_timestamp]) + + elif format == 1: # commit SHA;author timestamp;author + return ';'.join([sha, author_timestamp, author]) + + elif format == 2: # commit SHA;author;author timestamp; author timezone;commit message + return ';'.join([sha, author, author_timestamp, author_timezone, commit_msg]) + + elif format == 4: # commit SHA;author + return ';'.join([sha, author]) + + elif format == 5: # commit SHA; parent commit SHA + return ';'.join([sha, parent_sha]) + + elif format == 6: # commit SHA;author timestamp;author timezone;author;tree sha;parent sha + return ';'.join([sha, author_timestamp, author_timezone, author, tree_sha, parent_sha]) + + elif format == 8: # commit sha; author timestamp; commit timestamp; author; committer; parent sha + return ';'.join([sha, author_timestamp, committer_timestamp, author, committer, parent_sha]) + + elif format == 9: # commit sha; tree sha; parent sha; author; committer; author timestamp; commit timestamp; author timezone; committer timezone; commit message + return ';'.join([sha, tree_sha, parent_sha, author, committer, author_timestamp, committer_timestamp, author_timezone, committer_timezone, commit_msg]) + + else: + raise ValueError(f'Invalid format {format}') + + +if __name__ == '__main__': + import argparse + import logging + import sys + import os + + parser = argparse.ArgumentParser(description='See the Content of Git Object', usage='echo | %(prog)s type (format)') + parser.add_argument('type', type=str, help='The type of the object') + parser.add_argument('format', type=int, help='The format of the object', default=0, nargs='?') + args = parser.parse_args() + + woc = WocMapsLocal() + for line in sys.stdin: + try: + key = line.strip() + obj = woc.show_content(args.type, key) + if args.type == 'commit': + print(format_commit(key, obj, args.format)) + elif args.type == 'tree': + print(format_tree(obj)) + elif args.type == 'blob': + print(obj) + else: + raise ValueError(f'Invalid object type {args.type}') + except BrokenPipeError: + # ref: https://docs.python.org/3/library/signal.html#note-on-sigpipe + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + sys.exit(1) # Python exits with error code 1 on EPIPE + except Exception as e: + logging.error(f'Error in {key}: {e}', exc_info=True) + continue \ No newline at end of file From 5b1baf6e5c6c94ff2e5670316a23acae7c278199 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 5 Jun 2024 02:00:15 +0800 Subject: [PATCH 08/38] refactor: decouple woc.tch and woc.local Now woc.tch is nothing but a tokyocabinet driver. Our lives will be easier when switching to another db. --- woc/base.py | 17 +--- woc/local.pxd | 11 ++ woc/local.pyi | 12 ++- woc/local.pyx | 272 ++++++++++++++++++++++++++++++-------------------- woc/tch.pxd | 17 +++- woc/tch.pyi | 52 +++++++++- woc/tch.pyx | 163 ++++++++++++++---------------- 7 files changed, 325 insertions(+), 219 deletions(-) create mode 100644 woc/local.pxd diff --git a/woc/base.py b/woc/base.py index 08ff74d..663e2dd 100644 --- a/woc/base.py +++ b/woc/base.py @@ -1,5 +1,4 @@ -import os -from typing import Tuple, Union, Literal +from typing import Union, Literal WocObjectsWithContent = Literal['tree', 'blob', 'commit', 'tkns', 'tag', 'bdiff'] WocSupportedProfileVersions = (1, ) @@ -22,20 +21,6 @@ def show_content( key: Union[bytes, str], ): raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") - - -class WocKeyError(KeyError): - def __init__(self, - key: bytes, - file_path: str, - ) -> None: - try: - _decoded_key = key.decode('utf-8') - except UnicodeDecodeError: - _decoded_key = key.hex() - _filename = os.path.basename(file_path) - self.message = f"{_decoded_key} in {_filename}" - super().__init__(self.message) \ No newline at end of file diff --git a/woc/local.pxd b/woc/local.pxd new file mode 100644 index 0000000..56af550 --- /dev/null +++ b/woc/local.pxd @@ -0,0 +1,11 @@ +# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True, linetrace=True + +from libc.stdint cimport uint32_t, uint8_t + +# Make utility functions accessible from Python -> easier testing +cpdef uint32_t fnvhash(bytes data) +cpdef unber(bytes buf) +cpdef (int, int) lzf_length(bytes raw_data) +cpdef get_tch(char *path) +cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys) +cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys) \ No newline at end of file diff --git a/woc/local.pyi b/woc/local.pyi index 0346213..ca0c456 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -1,4 +1,4 @@ -from typing import Iterable, Union +from typing import Iterable, Union, Tuple, List from .base import WocMapsBase, WocObjectsWithContent @@ -21,4 +21,12 @@ class WocMapsLocal(WocMapsBase): obj: WocObjectsWithContent, key: Union[bytes, str], ) -> (list[tuple[str, str, str]] | str): - ... \ No newline at end of file + ... + +# Make utility functions accessible from Python -> easier testing +def fnvhash(data: bytes) -> int: ... +def unber(buf: bytes) -> bytes: ... +def lzf_length(raw_data: bytes) -> Tuple[int, int]: ... +def get_tch(path: str): ... +def get_shard(key: bytes, sharding_bits: int, use_fnv_keys: bool) -> int: ... +def get_from_tch(key: bytes, shards: List[bytes], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... \ No newline at end of file diff --git a/woc/local.pyx b/woc/local.pyx index aed065c..2ce2b22 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -8,6 +8,7 @@ import json import logging import time from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t +from threading import Lock from typing import Tuple, Dict, Iterable, List, Union, Literal, Optional import gzip @@ -17,12 +18,29 @@ try: except ImportError or AssertionError: raise ImportError('python-lzf is required to decompress LZF-compressed data: `pip install python-lzf`') -from .base import WocMapsBase, WocKeyError, WocObjectsWithContent, WocSupportedProfileVersions -from .tch cimport get_from_tch, get_shard, fnvhash +from .base import WocMapsBase, WocObjectsWithContent, WocSupportedProfileVersions +from .tch cimport TCHashDB logger = logging.getLogger(__name__) + +### Utility functions ### -cdef unber(bytes buf): +cpdef uint32_t fnvhash(bytes data): + """ + Returns the 32 bit FNV-1a hash value for the given data. + >>> hex(fnvhash('foo')) + '0xa9f37ed7' + """ + # PY: 5.8usec Cy: 66.8ns + cdef: + uint32_t hval = 0x811c9dc5 + uint8_t b + for b in data: + hval ^= b + hval *= 0x01000193 + return hval + +cpdef unber(bytes buf): r""" Perl BER unpacking. BER is a way to pack several variable-length ints into one binary string. Here we do the reverse. @@ -56,7 +74,7 @@ cdef unber(bytes buf): acc = 0 return res -cdef (int, int) lzf_length(bytes raw_data): +cpdef (int, int) lzf_length(bytes raw_data): r""" Get length of uncompressed data from a header of Compress::LZF output. Check Compress::LZF sources for the definition of this bit magic (namely, LZF.xs, decompress_sv) @@ -145,6 +163,140 @@ def decode_str(bytes raw_data): _encoding = chardet.detect(raw_data)['encoding'] return raw_data.decode(_encoding, errors='replace') + +### TCH helpers ### + +# Pool of open TokyoCabinet databases to save few milliseconds on opening +cdef dict _TCH_POOL = {} # type: Dict[str, TCHashDB] +TCH_LOCK = Lock() + +cpdef get_tch(char *path): + """ Cache Hash() objects """ + if path in _TCH_POOL: + return _TCH_POOL[path] + try: + TCH_LOCK.acquire() + # in multithreading environment this can cause race condition, + # so we need a lock + if path not in _TCH_POOL: + # open database in read-only mode and allow concurrent access + _TCH_POOL[path] = TCHashDB(path, ro=True) + finally: + TCH_LOCK.release() + return _TCH_POOL[path] + +cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys): + """ Get shard id """ + cdef uint8_t p + if use_fnv_keys: + p = fnvhash(key) + else: + p = key[0] + cdef uint8_t prefix = p & (2**sharding_bits - 1) + return prefix + +cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys): + # not 100% necessary but there are cases where some tchs are miserably missing + _shard = get_shard(key, sharding_bits, use_fnv_keys) + _path = shards[_shard] + assert _path and os.path.exists(_path), f"shard {_shard} not found at {_path}" + return get_tch( + shards[get_shard(key, sharding_bits, use_fnv_keys)].encode('utf-8') + )[key] + +### deserializers ### + +def decode_value( + value: bytes, + out_dtype: str +): + if out_dtype == 'h': # type: list[str] + return [value[i:i + 20].hex() for i in range(0, len(value), 20)] + elif out_dtype == 'sh': # type: tuple[str, str, str] + buf0 = value[0:len(value)-21] + cmt_sha = value[(len(value)-20):len(value)] + (Time, Author) = decode_str(buf0).split(";") + return (Time, Author, cmt_sha.hex()) + elif out_dtype == 'cs3': # type: list[tuple[str, str, str]] + data = decomp(value) + _splited = decode_str(data).split(";") + return [ + (_splited[i],_splited[i+1],_splited[i+2]) + for i in range(0, len(_splited), 3) + ] + elif out_dtype == 'cs': # type: list[str] + data = decomp(value) + return [decode_str(v) + for v in data.split(b';') + if v and v != b'EMPTY'] + elif out_dtype == 's': # type: list[str] + return [decode_str(v) + for v in value.split(b';')] + elif out_dtype == 'r': # type: list[str, int] + _hex = value[:20].hex() + _len = unber(value[20:])[0] + return (_hex, _len) + elif out_dtype == 'hhwww': + raise NotImplemented + raise ValueError(f'Unsupported dtype: {out_dtype}') + + +def decode_tree( + value: bytes +) -> List[Tuple[str, str, str]]: + """ + Decode a tree binary object into tuples + Reference: https://stackoverflow.com/questions/14790681/ + mode (ASCII encoded decimal) + SPACE (\0x20) + filename + NULL (\x00) + 20-byte binary hash + """ + _out_buf = [] + _file_buf = [] + _curr_buf = bytes() + + # TODO: current impl is not efficient, need to optimize + i = 0 + while i < len(value): + if value[i] == 0x20: + _file_buf.append(decode_str(_curr_buf)) + _curr_buf = bytes() + elif value[i] == 0x00: + _file_buf.append(decode_str(_curr_buf)) + # take next 20 bytes as a hash + _curr_buf = value[i+1:i+21] + _file_buf.append(_curr_buf.hex()) + _out_buf.append(tuple(_file_buf)) + # clear buffers + _file_buf = [] + _curr_buf = bytes() + i += 20 + else: + _curr_buf += bytes([value[i]]) + i += 1 + + return _out_buf + + +def read_large(path: str, dtype: str) -> bytes: + """Read a *.large.* and return its content""" + if dtype == 'h': + with open(path, 'rb') as f: + f.seek(20) # 160 bits of SHA1 + return f.read() + else: + # use zlib to decompress + with gzip.open(path, 'rb') as f: + _uncompressed = f.read() + # find first 256 bytes for b'\n', don't scan the whole document + _idx = _uncompressed[:256].find(b'\n') + if _idx > 0: + return _uncompressed[_idx+1:] # a2f + return _uncompressed # b2tac + + class WocMapsLocal(WocMapsBase): def __init__(self, profile_path: Union[str, Iterable[str], None] = None, @@ -175,58 +327,6 @@ class WocMapsLocal(WocMapsBase): "Unsupported wocprofile version: {}".format(self.config["wocSchemaVersion"]) assert self.config["maps"], "Run `python3 -m woc.detect` to scan data files and generate wocprofile.json" - @staticmethod - def _read_large(path: str, dtype: str) -> bytes: - """Read a *.large.* and return its content""" - if dtype == 'h': - with open(path, 'rb') as f: - f.seek(20) # 160 bits of SHA1 - return f.read() - else: - # use zlib to decompress - with gzip.open(path, 'rb') as f: - _uncompressed = f.read() - # find first 256 bytes for b'\n', don't scan the whole document - _idx = _uncompressed[:256].find(b'\n') - if _idx > 0: - return _uncompressed[_idx+1:] # a2f - return _uncompressed # b2tac - - def _decode_value( - self, - value: bytes, - out_dtype: str - ): - if out_dtype == 'h': # type: list[str] - return [value[i:i + 20].hex() for i in range(0, len(value), 20)] - elif out_dtype == 'sh': # type: tuple[str, str, str] - buf0 = value[0:len(value)-21] - cmt_sha = value[(len(value)-20):len(value)] - (Time, Author) = decode_str(buf0).split(";") - return (Time, Author, cmt_sha.hex()) - elif out_dtype == 'cs3': # type: list[tuple[str, str, str]] - data = decomp(value) - _splited = decode_str(data).split(";") - return [ - (_splited[i],_splited[i+1],_splited[i+2]) - for i in range(0, len(_splited), 3) - ] - elif out_dtype == 'cs': # type: list[str] - data = decomp(value) - return [decode_str(v) - for v in data.split(b';') - if v and v != b'EMPTY'] - elif out_dtype == 's': # type: list[str] - return [decode_str(v) - for v in value.split(b';')] - elif out_dtype == 'r': # type: list[str, int] - _hex = value[:20].hex() - _len = unber(value[20:])[0] - return (_hex, _len) - elif out_dtype == 'hhwww': - raise NotImplemented - raise ValueError(f'Unsupported dtype: {out_dtype}') - def get_values( self, map_name: str, @@ -265,7 +365,7 @@ class WocMapsLocal(WocMapsBase): decode_dtype = _map["dtypes"][1] if "larges" in _map and _hex in _map["larges"]: - _bytes = self._read_large(_map["larges"][_hex], _map["dtypes"][1]) + _bytes = read_large(_map["larges"][_hex], _map["dtypes"][1]) logger.debug(f"read large: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() @@ -278,55 +378,10 @@ class WocMapsLocal(WocMapsBase): logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - _ret = self._decode_value(_bytes, decode_dtype) + _ret = decode_value(_bytes, decode_dtype) logger.debug(f"decode value: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret - @staticmethod - def _decode_tree( - value: bytes - ) -> List[Tuple[str, str, str]]: - """ - Decode a tree binary object into tuples - Reference: https://stackoverflow.com/questions/14790681/ - mode (ASCII encoded decimal) - SPACE (\0x20) - filename - NULL (\x00) - 20-byte binary hash - """ - _out_buf = [] - _file_buf = [] - _curr_buf = bytes() - - # TODO: current impl is not efficient, need to optimize - i = 0 - while i < len(value): - if value[i] == 0x20: - _file_buf.append(decode_str(_curr_buf)) - _curr_buf = bytes() - elif value[i] == 0x00: - _file_buf.append(decode_str(_curr_buf)) - # take next 20 bytes as a hash - _curr_buf = value[i+1:i+21] - _file_buf.append(_curr_buf.hex()) - _out_buf.append(tuple(_file_buf)) - # clear buffers - _file_buf = [] - _curr_buf = bytes() - i += 20 - else: - _curr_buf += bytes([value[i]]) - i += 1 - - return _out_buf - - @staticmethod - def _read_file_with_offset(file_path, offset, length): - with open(file_path, "rb") as f: - f.seek(offset) - return f.read(length) - def show_content( self, obj: str, @@ -355,7 +410,7 @@ class WocMapsLocal(WocMapsBase): ) logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - _ret = self._decode_tree(decomp_or_raw(v)) + _ret = decode_tree(decomp_or_raw(v)) logger.debug(f"decode tree: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret @@ -382,11 +437,10 @@ class WocMapsLocal(WocMapsBase): offset, length = unber(v) _map_obj = self.config['objects']['blob.bin'] shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) - _out_bin = self._read_file_with_offset( - _map_obj['shards'][shard], - offset, - length - ) + + with open(_map_obj['shards'][shard], "rb") as f: + f.seek(offset) + _out_bin = f.read(length) logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() diff --git a/woc/tch.pxd b/woc/tch.pxd index 66de590..267f4c7 100644 --- a/woc/tch.pxd +++ b/woc/tch.pxd @@ -1,7 +1,16 @@ # cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False, profile=True, linetrace=True -from libc.stdint cimport uint8_t, uint32_t +cdef extern from 'tchdb.h': + ctypedef struct TCHDB: # type of structure for a hash database + pass -cdef uint32_t fnvhash(bytes data) -cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys) -cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys) \ No newline at end of file +cdef class TCHashDB: + cdef TCHDB* _db + cdef bytes filename + + """Object representing a Tokyocabinet Hash table""" + cpdef bytes get(self, bytes key) + cpdef void put(self, bytes key, bytes value) except * + cpdef void delete(self, bytes key) except * + cpdef void drop(self) except * + cpdef void close(self) except * \ No newline at end of file diff --git a/woc/tch.pyi b/woc/tch.pyi index a33c82c..afdc5e4 100644 --- a/woc/tch.pyi +++ b/woc/tch.pyi @@ -1,2 +1,50 @@ -def get_shard(key: bytes, sharding_bits: int, use_fnv_keys: bool) -> int: ... -def get_from_tch(key: bytes, shards: list[str], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... \ No newline at end of file +from typing import Iterator + +class TCHashDB: + """Object representing a TokyoCabinet Hash table""" + + def __init__(self, path: bytes, ro: bool = False) -> None: + """ + Create a new TokyoCabinet hash table object. + :path: *encoded* path to the database file + :ro: if True, open in lock-free read-only mode; if False, lock and open in write mode (create if not exists) + """ + ... + + def __iter__(self) -> 'Iterator[bytes]': + ... + + def get(self, key: bytes) -> bytes: + """Get a record, raise KeyError if not found""" + ... + + def put(self, key: bytes, value: bytes) -> None: + """Upsert a record""" + ... + + def delete(self, key: bytes) -> None: + """Delete a record from the database""" + ... + + def drop(self) -> None: + """Delete all records in the database""" + ... + + def close(self) -> None: + """Close the database""" + ... + + def __getitem__(self, key: bytes) -> bytes: + ... + + def __setitem__(self, key: bytes, value: bytes) -> None: + ... + + def __delitem__(self, key: bytes) -> None: + ... + + def __len__(self) -> int: + ... + + def __del__(self) -> None: + ... \ No newline at end of file diff --git a/woc/tch.pyx b/woc/tch.pyx index ba5ee3f..5c47aad 100644 --- a/woc/tch.pyx +++ b/woc/tch.pyx @@ -6,10 +6,6 @@ from libc.stdint cimport uint8_t, uint32_t, uint64_t from libc.stdlib cimport free -from threading import Lock -import os - -from .base import WocKeyError cdef extern from 'Python.h': object PyBytes_FromStringAndSize(char *s, Py_ssize_t len) @@ -19,51 +15,45 @@ cdef extern from 'tchdb.h': pass cdef enum: # enumeration for open modes - HDBOREADER = 1 << 0, # open as a reader - HDBONOLCK = 1 << 4, # open without locking - - const char *tchdberrmsg(int ecode) - TCHDB *tchdbnew() - int tchdbecode(TCHDB *hdb) + HDBOREADER = 1 << 0, # open as a reader + HDBOWRITER = 1 << 1, # open as a writer + HDBOCREAT = 1 << 2, # writer creating + HDBOTRUNC = 1 << 3, # writer truncating + HDBONOLCK = 1 << 4, # open without locking + + const char *tchdberrmsg(int ecode) # Get the message string corresponding to an error code + TCHDB *tchdbnew() # Create a hash database object + int tchdbecode(TCHDB *hdb) # Set the error code of a hash database object bint tchdbopen(TCHDB *hdb, const char *path, int omode) - bint tchdbclose(TCHDB *hdb) + bint tchdbclose(TCHDB *hdb) # Close a hash database object + void tchdbdel(TCHDB *hdb) # Delete a hash database object void *tchdbget(TCHDB *hdb, const void *kbuf, int ksiz, int *sp) - bint tchdbiterinit(TCHDB *hdb) - void *tchdbiternext(TCHDB *hdb, int *sp) - -cdef uint32_t fnvhash(bytes data): - """ - Returns the 32 bit FNV-1a hash value for the given data. - >>> hex(fnvhash('foo')) - '0xa9f37ed7' - """ - # PY: 5.8usec Cy: 66.8ns - cdef: - uint32_t hval = 0x811c9dc5 - uint8_t b - for b in data: - hval ^= b - hval *= 0x01000193 - return hval - - -cdef class Hash: + bint tchdbiterinit(TCHDB *hdb) # Initialize the iterator of a hash database object + void *tchdbiternext(TCHDB *hdb, int *sp) # Get the next key of the iterator of a hash database object + bint tchdbput(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz) # Store a new record into a hash database object + bint tchdbout(TCHDB *hdb, const void *kbuf, int ksiz) # Remove a record of a hash database object + uint64_t tchdbrnum(TCHDB *hdb) # Get the number of records of a hash database object + bint tchdbvanish(TCHDB *hdb) # Remove all records of a hash database object + +cdef class TCHashDB: """Object representing a Tokyocabinet Hash table""" - cdef TCHDB* _db - cdef bytes filename - def __cinit__(self, char *path, nolock=True): - cdef int mode = HDBOREADER - if nolock: + def __cinit__(self, char *path, bint ro=False): + cdef int mode = 0 + if not ro: # write mode: create if not exists + mode |= HDBOWRITER + mode |= HDBOCREAT + else: # read mode: disable locks + mode |= HDBOREADER mode |= HDBONOLCK + self._db = tchdbnew() self.filename = path if self._db is NULL: raise MemoryError() cdef bint result = tchdbopen(self._db, path, mode) if not result: - raise IOError('Failed to open .tch file "%s": ' % self.filename - + self._error()) + raise IOError(f'Failed to open "{self.filename.decode("latin1")}": ' + self._error()) def _error(self): cdef int code = tchdbecode(self._db) @@ -77,8 +67,7 @@ cdef class Hash: int sp bytes key if not result: - raise IOError('Failed to iterate .tch file "%s": ' % self.filename - + self._error()) + raise IOError(f'Failed to iterate "{self.filename.decode("latin1")}": ' + self._error()) while True: buf = tchdbiternext(self._db, &sp) if buf is NULL: @@ -87,7 +76,7 @@ cdef class Hash: free(buf) yield key - cdef bytes read(self, bytes key): + cpdef bytes get(self, bytes key): cdef: char *k = key char *buf @@ -95,57 +84,59 @@ cdef class Hash: int ksize=len(key) buf = tchdbget(self._db, k, ksize, &sp) if buf is NULL: - raise WocKeyError(key, self.filename.decode('utf-8')) + raise KeyError(f'Key "{key.decode("latin1")}" not found in "{self.filename.decode("latin1")}"') cdef bytes value = PyBytes_FromStringAndSize(buf, sp) free(buf) return value - def __getitem__(self, bytes key): - return self.read(key) + cpdef void put(self, bytes key, bytes value) except *: + cdef: + char *k = key + int ksize = len(key) + char *v = value + int vsize = len(value) + bint result + result = tchdbput(self._db, k, ksize, v, vsize) + if not result: + raise IOError(f'Failed to put "{key.decode("latin1")}" in "{self.filename.decode("latin1")}": ' + self._error()) - def __del__(self): + cpdef void delete(self, bytes key) except *: + cdef: + char *k = key + int ksize = len(key) + bint result + result = tchdbout(self._db, k, ksize) + if not result: + raise IOError(f'Failed to delete "{key.decode("latin1")}" in "{self.filename.decode("latin1")}": ' + self._error()) + + cpdef void drop(self) except *: + cdef: + bint result + result = tchdbvanish(self._db) + if not result: + raise IOError(f'Failed to drop all records in "{self.filename.decode("latin1")}": ' + self._error()) + + cpdef void close(self) except *: cdef bint result = tchdbclose(self._db) if not result: - raise IOError('Failed to close .tch "%s": ' % self.filename - + self._error()) + raise IOError(f'Failed to close "{self.filename.decode("latin1")}": ' + self._error()) + + def __getitem__(self, bytes key): + return self.get(key) + + def __setitem__(self, bytes key, bytes value): + self.put(key, value) + + def __delitem__(self, bytes key): + self.delete(key) + + def __len__(self): + return tchdbrnum(self._db) + + def __del__(self): + self.close() def __dealloc__(self): - free(self._db) - - -# Pool of open TokyoCabinet databases to save few milliseconds on opening -cdef dict _TCH_POOL = {} # type: Dict[str, Hash] -TCH_LOCK = Lock() - -cdef _get_tch(char *path): - """ Cache Hash() objects """ - if path in _TCH_POOL: - return _TCH_POOL[path] - try: - TCH_LOCK.acquire() - # in multithreading environment this can cause race condition, - # so we need a lock - if path not in _TCH_POOL: - _TCH_POOL[path] = Hash(path) - finally: - TCH_LOCK.release() - return _TCH_POOL[path] - -cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys): - """ Get shard id """ - cdef uint8_t p - if use_fnv_keys: - p = fnvhash(key) - else: - p = key[0] - cdef uint8_t prefix = p & (2**sharding_bits - 1) - return prefix - -cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys): - # not 100% necessary but there are cases where some tchs are miserably missing - _shard = get_shard(key, sharding_bits, use_fnv_keys) - _path = shards[_shard] - assert _path and os.path.exists(_path), f"shard {_shard} not found at {_path}" - return _get_tch( - shards[get_shard(key, sharding_bits, use_fnv_keys)].encode('utf-8') - )[key] + if self._db is not NULL: + tchdbdel(self._db) + self._db = NULL \ No newline at end of file From e56c4bcd5f7e2c67a411a3d65d2990fe5fb4ff58 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 5 Jun 2024 02:01:03 +0800 Subject: [PATCH 09/38] test: add tests for woc.tch also add pytest config to pyproject.toml --- pyproject.toml | 9 ++++++- tests/test_tch.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tests/test_tch.py diff --git a/pyproject.toml b/pyproject.toml index 2820f39..ec663da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,4 +6,11 @@ version_variable = ['oscar.pyx:__version__', 'docs/conf.py:release'] # wheel build is performed by manylinux, so just skip it build_command = '' # remove_dist deletes all pre-existing files in dist/, including built by manylinux -remove_dist = false \ No newline at end of file +remove_dist = false + +[tool.pytest.ini_options] +minversion = "6.0" +addopts = "-ra -q" +testpaths = [ + "tests", +] \ No newline at end of file diff --git a/tests/test_tch.py b/tests/test_tch.py new file mode 100644 index 0000000..d6b9cdf --- /dev/null +++ b/tests/test_tch.py @@ -0,0 +1,68 @@ +import pytest + +# Import the TCHashDB class +from woc.tch import TCHashDB + +@pytest.fixture +def db(tmp_path): + """Fixture to create and return a TCHashDB instance""" + path = tmp_path / "test_db.tch" + db = TCHashDB(path=bytes(str(path), 'utf-8')) + yield db + db.drop() + db.close() + +def test_put_and_get(db): + key = b'key1' + value = b'value1' + db.put(key, value) + assert db.get(key) == value + +def test_get_nonexistent_key(db): + with pytest.raises(KeyError): + db.get(b'nonexistent_key') + +def test_delete(db): + key = b'key2' + value = b'value2' + db.put(key, value) + db.delete(key) + with pytest.raises(KeyError): + db.get(key) + +def test_drop(db): + db.put(b'key3', b'value3') + db.put(b'key4', b'value4') + db.drop() + assert len(db) == 0 + +def test_len(db): + db.put(b'key5', b'value5') + db.put(b'key6', b'value6') + assert len(db) == 2 + +def test_iter(db): + keys = [b'key7', b'key8', b'key9'] + for key in keys: + db.put(key, b'value') + assert set(db) == set(keys) + +def test_getitem(db): + key = b'key10' + value = b'value10' + db[key] = value + assert db[key] == value + +def test_setitem(db): + key = b'key11' + value = b'value11' + db[key] = value + assert db.get(key) == value + +def test_delitem(db): + key = b'key12' + value = b'value12' + db[key] = value + del db[key] + with pytest.raises(KeyError): + db.get(key) \ No newline at end of file From c0a3757169f55771823e1dee05a24ffaa6487537 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 5 Jun 2024 02:01:55 +0800 Subject: [PATCH 10/38] test: fixture generation -> py3 --- tests/fixtures/{blob_127.bin => __init__.py} | 0 tests/fixtures/a2cFullR.1.tch | Bin 0 -> 600896 bytes tests/fixtures/a2fFullR.1.tch | Bin 0 -> 549696 bytes .../{sha1.blob_3.tch => b2cFullR.1.tch} | Bin 528752 -> 528768 bytes ...e.3f2eca18f1bc0f3117748e2cea9251e5182db2f7 | Bin 0 -> 180 bytes .../{sha1.blob_125.tch => b2fFullR.1.tch} | Bin 528752 -> 528752 bytes tests/fixtures/b2faFullU.1.tch | Bin 0 -> 528800 bytes tests/fixtures/b2tacFullU.1.tch | Bin 0 -> 528832 bytes tests/fixtures/blob_0.bin | Bin 0 -> 9396 bytes tests/fixtures/blob_125.bin | Bin 383 -> 0 bytes tests/fixtures/blob_3.bin | Bin 42 -> 0 bytes tests/fixtures/blob_35.bin | Bin 1496 -> 0 bytes tests/fixtures/blob_70.bin | Bin 867 -> 0 bytes .../{sha1.blob_70.tch => c2bFullR.0.tch} | Bin 528752 -> 528768 bytes tests/fixtures/c2datFullU.0.tch | Bin 0 -> 528880 bytes .../{sha1.blob_35.tch => c2fFullR.0.tch} | Bin 528752 -> 528752 bytes tests/fixtures/c2pFullU.0.tch | Bin 0 -> 528896 bytes tests/fixtures/c2rFullR.0.tch | Bin 0 -> 528768 bytes tests/fixtures/commit_0.tch | Bin 914256 -> 0 bytes .../fixtures/{commit_114.tch => commit_1.tch} | Bin 528944 -> 528944 bytes tests/fixtures/commit_127.tch | 0 tests/fixtures/create_fixtures.py | 345 +++++++++++------ .../{commit_99.tch => f2aFullR.1.tch} | Bin 528928 -> 528896 bytes .../{commit_28.tch => p2aFullR.1.tch} | Bin 529440 -> 530368 bytes tests/fixtures/p2cFullR.1.tch | Bin 0 -> 617872 bytes tests/fixtures/sha1.blob.tch | Bin 0 -> 528832 bytes tests/fixtures/sha1.blob_127.tch | 0 tests/fixtures/tree_0.tch | Bin 1335136 -> 528848 bytes tests/fixtures/tree_127.tch | 0 tests/fixtures/tree_84.tch | Bin 528960 -> 0 bytes tests/integration_test.py | 116 ------ tests/local_test.env | 7 - tests/test_profile.json | 357 ++++++++++++++++++ tests/unit_test.py | 209 ---------- tests/unit_test_cy.pyx | 41 -- 35 files changed, 581 insertions(+), 494 deletions(-) rename tests/fixtures/{blob_127.bin => __init__.py} (100%) create mode 100644 tests/fixtures/a2cFullR.1.tch create mode 100644 tests/fixtures/a2fFullR.1.tch rename tests/fixtures/{sha1.blob_3.tch => b2cFullR.1.tch} (99%) create mode 100644 tests/fixtures/b2cFullR.31.tch.large.3f2eca18f1bc0f3117748e2cea9251e5182db2f7 rename tests/fixtures/{sha1.blob_125.tch => b2fFullR.1.tch} (99%) create mode 100644 tests/fixtures/b2faFullU.1.tch create mode 100644 tests/fixtures/b2tacFullU.1.tch create mode 100644 tests/fixtures/blob_0.bin delete mode 100644 tests/fixtures/blob_125.bin delete mode 100644 tests/fixtures/blob_3.bin delete mode 100644 tests/fixtures/blob_35.bin delete mode 100644 tests/fixtures/blob_70.bin rename tests/fixtures/{sha1.blob_70.tch => c2bFullR.0.tch} (99%) create mode 100644 tests/fixtures/c2datFullU.0.tch rename tests/fixtures/{sha1.blob_35.tch => c2fFullR.0.tch} (99%) create mode 100644 tests/fixtures/c2pFullU.0.tch create mode 100644 tests/fixtures/c2rFullR.0.tch delete mode 100644 tests/fixtures/commit_0.tch rename tests/fixtures/{commit_114.tch => commit_1.tch} (99%) delete mode 100644 tests/fixtures/commit_127.tch mode change 100755 => 100644 tests/fixtures/create_fixtures.py rename tests/fixtures/{commit_99.tch => f2aFullR.1.tch} (99%) rename tests/fixtures/{commit_28.tch => p2aFullR.1.tch} (99%) create mode 100644 tests/fixtures/p2cFullR.1.tch create mode 100644 tests/fixtures/sha1.blob.tch delete mode 100644 tests/fixtures/sha1.blob_127.tch delete mode 100644 tests/fixtures/tree_127.tch delete mode 100644 tests/fixtures/tree_84.tch delete mode 100755 tests/integration_test.py delete mode 100644 tests/local_test.env create mode 100644 tests/test_profile.json delete mode 100755 tests/unit_test.py delete mode 100644 tests/unit_test_cy.pyx diff --git a/tests/fixtures/blob_127.bin b/tests/fixtures/__init__.py similarity index 100% rename from tests/fixtures/blob_127.bin rename to tests/fixtures/__init__.py diff --git a/tests/fixtures/a2cFullR.1.tch b/tests/fixtures/a2cFullR.1.tch new file mode 100644 index 0000000000000000000000000000000000000000..284a9a9307bb685d6283053587ca5e5cf948d35e GIT binary patch literal 600896 zcmeF%_g4te|3C2d(B6CRy|gr>B(z0QQCb?bNrPyoDQTBPLy{sbl%}*5mG&TMXrNT+ z`#$gQ`JVIn6F%pAp7)1)?(3fW!@ZAR?!B*jPkI>!n)2(N*L5>-KDkdpR{nsxg2Fz6 z|4~T(8}028{lA$5=EW009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2>kC8V7~dkZ%&vI1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= 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ⅇKhbpkua$fWH`tw$xu?JUkMW}??kWPn(<(&??xvle%YPMJFV_<0Qqn3I z-pz^p|5KfzrwiCfCCB$GX>2GJY6#IwQfSXagQ>UG_9S@9? ze!W4MakjCndbiAw_gbC8m2?!ixd1C&%HI5GU(Ya+r2d`QftTGFi!4&j_<2 z^f{gBXNXtQ?%@9Ztl4FI=apS;;8LCT)A>XM>U$i=mK&Y}Bt;bUjY~e3 zSF%BOsEA$g7Yv?PB{{mCrHkuO?-{_5zXY(;U*w)}UJQQyFwoj_P04tku}CQb1b&`{ zxR3R*0QUC7!?0W5n9Jm7{g@ae*r&h>yvzxbh|ga4mal?Cqdysj#S7;$;|(LgBr z3u&KU!G5Q(EW$9pq+k8^TVIRCg5|Hdm54bYt$R(A@G40JS3mj zj6)`-w;N;e?zCeM5ED`GMp>WRd-7?|@|$axk12Rwl%eqy=GdRy7QYBKY7TQ|>9^I8 z*%__3q{pBCh;7GOc0$tLHF{cIZdD==Tk4=F2m2%-@<-li1E7u8*^G_Ac;BEtpKlm6 zo7gG?s+6QUHjsPq0AZkF;ws(~-;-)Kh8Qe0fMuFnXDy&(=6qSbD9ljKw_Y< z)&biLL9>&qs#MYZu|kx%pv9oleM%OSPX63B5eHiE5zUiAj|+XtY(YzeKQ1 z_B(p|bgrQ5)g5OB0)m>Q0%O00`YM-b3)rCWovr8Gl-Vd;rzR_Kxf9wiualtzY@8aq z9HK`xx9@9USL}^LgyEqn6$bG0NI=B|SCHm2L_oA#A~~Td>K9?0pkMkys2$Pst@7$+ zQ>&psbVk_irbcL@`~vW=MAWGLq06B`vGcn1s&V&gLv=p!xIm%S)f=HwJ5Um4MS7{K zH{}Hv9^?Z2v$QrTKqcj=bAS@{PjI1w>x7lDTsQMh!;hG1 z&nT{VJdB}<7NUULIyeDqn@J1SaAH^O=>li`R~yWB;ZlzyzV(l;j<5Rhy(;3%3q0yhIw5euSa`s*$N36cS(jsA*M(MZ{&@ zo=c(zQ`)VEg^^S&z$4Rb=mx{$zN?}h>cS$c_9d)}nnUpoJW8!&j} z57-hdovJUY`D>zDWZBnzIK~ql=G5yDV-xH+er=*>zZgPMiDrbeGvDX=9EhTdfVX4sqUFsrB0y*VoyvxCJX4~VyKcgwmRU%>H#~rK z7%#($gQ}va9sG?L!}GKgo2g}LL`o9BYwe=r%B3oIql5GKblKs)JijA|H*%utS}%G! zlrX$mLQS4blP^0&>fECBPwH3FhLTg@6-a7I+(=h&XYHdEcYhmKYMQrV<^ZQ2GH*yBKQ@%i646H@jXa}C z#$K#DQbRiwMt0^{9#|ONDcqw|^=G~on^ha14CSM|#BT9h?_Hy58&k8#Neg^9=KgBS z@5_BAlD4Cpo>YmyA3LK>72^g`?$Ig)rKF>+0so>Y_pn7y5HWX#gFZR9kz=E}Wr!D> z!>Z4e_6~(en&+QZuAozP@Ab@N0UHI#r^aH3=$m^}M8P zoPNrNV0sK4YB^!;Hg(WXR3M~^oiIHo>6Q%tOW`Nc@J6K1AIe$>_s-ovfWbf4Cu?QTqAsM@Sm1Go5kxzX5I8N*We9^C z2yLX?*tB}gSzS4+`y20!TC5qe(-x%NV!M3~^YfI@H&S;Y zuKAQkv?f$yF%_iaeyo#)5fVO@KWiC4pjk%z$N4^8HJ^8z~IQ|TS$@jP@)Ge%W3tE(>A4=xL1A1VvdQ{^ZkRPdzu4ARO@#q3}CGPnhEldy7 z98G!Jmc*sG_p1H_b!A+!7baI|FM|e(@j#{5Z+Z>`ZR``L824#IBr6b4PgSMqZI#2T zG5=7W-#ttmdnwoo&RM1LAljOtf&u$zhEM7BLycoIfpVq_onaMCLRAaBThh3alu{$O z4g;ou$R1?(Fhow±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 Z35jacVufgPGuem&NPHfx00000001X*lLG(% literal 0 HcmV?d00001 diff --git a/tests/fixtures/a2fFullR.1.tch b/tests/fixtures/a2fFullR.1.tch new file mode 100644 index 0000000000000000000000000000000000000000..9a7a25fbca220b7e6bb972a5d0dd9a551f7eec7a GIT binary patch literal 549696 zcmeF&hksl3{XhE8IT{}FiW86Qqv37Imb_ypKJrSO#ExS-38WC6Bk5R@trZPB4(m9~ zFv@5dEu}pPtCS6;P$;bu$}BCV-_k|LM|KFSK%s*IrQDCh@80|U6Yk?aUOXN;mSSNY zJuU3ymt1`A$dkrY@&5pZu@?^k-gu@dbD0-@e=uBKmUAycSn{ z`SXAM4|oaz2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<;Qvzss}}x0wL91u2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV= z5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHaf zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/sha1.blob_3.tch b/tests/fixtures/b2cFullR.1.tch similarity index 99% rename from tests/fixtures/sha1.blob_3.tch rename to tests/fixtures/b2cFullR.1.tch index e1c1e13c64f7b4788a8b8f9a080f06dd5bce8b66..20b9606b02ca8855c3b2d7c2a451d7532a5fa736 100644 GIT binary patch delta 112 zcmeycNTFe|!UPM(hDOU)OUA91OvT3SIUiVom~DH`2lgupjR~y@jI9YwTN9WM>~T2p zmH`U57(_%^|0Vk@Ibo6Pxh8Oa=S0`z@&6q&pRDf`%M!1Mku8z#mJKictYja^57WcI F003^BCcOXv delta 100 zcmZoztngux!UPM(f=0_$OUA91OvT2H39Si?TN9XkfUKjO<-zGU~Wxd*_y!Gu+refTLvg#VG!YB l{g>>sjxcQV7pN@Q4+QZOP4^sl90e;#Z+yDRo diff --git a/tests/fixtures/b2faFullU.1.tch b/tests/fixtures/b2faFullU.1.tch new file mode 100644 index 0000000000000000000000000000000000000000..2a5b3eeb4a5ad0b79bfd52a40a29f86bbba3089e GIT binary patch literal 528800 zcmeIuJxT*n6b8@;3X(>IpoIj23kWk}kueez#X|fe5U>#>Bq_!e0h0kOErXRS(85x1 z8D=52R`!lC3T6*;Uh&@hF5Kcfozd~#dF7zHAD<06#jqOeL}6Gg%$>z7rRhR8`@IW= z=hfvbH~-$b1z!RL2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlykZXa`eXi>(Pk;ac0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5Xhy#?DM~Nsj>9kJ9(MadPlGAr|IM2 z`&HVC!|gB#wxXz3tGAN=O+2ogj(WpnT-ohrv6)PU)j>aL)IZ*)YuD?ym*vUEL-`{4 J+T3fe`~Zl}DntMP literal 0 HcmV?d00001 diff --git a/tests/fixtures/b2tacFullU.1.tch b/tests/fixtures/b2tacFullU.1.tch new file mode 100644 index 0000000000000000000000000000000000000000..dcc5a7755b876a61e891c9ebcea5831363caca19 GIT binary patch literal 528832 zcmeIuJxT*X7zW@K6eLzc4v-UsO#XJ)h$M=I_=lKYlHCMCihwbNrKP1Ou(9+IcIGl( z!6?x{?vQ7S`Q{xMhWF`C&L6K!C%xm*)u3Al<;p=CLLpjP+sm|AY%TBp_9*(;-(BYR z|6F_ENPqwV0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXzTA=u}(e;%lK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFY^1>aYgKzMD&FpVXBThtBs+V*d3}C4{k&Ur zMp3ATN~M~nNz&@f^83-WbUDe!vuWwDw~X!C!?--iXGg6;y*EtK&}{ZX94Cz|aoiZzs@2-C5h}ygm%sA|9L+70 literal 0 HcmV?d00001 diff --git a/tests/fixtures/blob_0.bin b/tests/fixtures/blob_0.bin new file mode 100644 index 0000000000000000000000000000000000000000..83006f89cb0df196cf7cb9109b3d0144a780ccfc GIT binary patch literal 9396 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 X#?+I0n43Ws+6!PBcQxFC71#d-%4*y3 literal 0 HcmV?d00001 diff --git a/tests/fixtures/blob_125.bin b/tests/fixtures/blob_125.bin deleted file mode 100644 index 6e4a5b3f29efda7a7530dc9fcc44c8ee90d3a7ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 zcmWN|%Sz)=90%ausO2oYfFQc@H=99GV!bT}M3N?{1~n;ds&v=WlfTJvl5-?EQDm4G zn75d<58`XoH_>nZeY`h;WwWv6MR>S&V#L=zhEw+jvuKJ3C&WfC!e~0U4P2nz@xzJF zmd*3;vU^WuCAGrIAv_XPEU3guzkkLUT>bo3uE;bq*mL)>xqEzy5r3f^qgrIYrNV_G z%_~7h3Og-$SLT+`#U*}i`!7_!X+@9~o~bOPF_ge)2#nXjRf0rTrj(1?5OA=u;6@hE zB?_I$M@b2@_j{5m=tr0g{(3G2sfv(jQ5U4l;oN5;<0_RZg*5h4hv&I|Mb_XrYHO7; zyVo@tLGfb#Z*H|HvG9M{YJC25wqk#LH-Qs+aHG%*;vfnq7)E2Pc1E)xy!vs~4JPq8 j7)=SnKg%t_Jb($XuaOa_v<`9LDQiVFY;!wdre diff --git a/tests/fixtures/blob_35.bin b/tests/fixtures/blob_35.bin deleted file mode 100644 index d8edeecb4c6d48f3003f4befba16e96cd3c30685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1496 zcmWlWUuYav7{%|*>~4~2Vrr6_{sH^VWYf*xUDH-+BMmc~Y~xCj*6t=Xtu=FZ<|cd1 z?968FOwz5kOiL*$h*T&d6ij~r(q98?);!{z%v5HWAQXg7G>iTjx-^<~5 zzQfO-Y@DPHHA_tH3Q2wCG02_7!!a&d!tn_3|XFLq*giJ86u?* zVYOSk0Ec2=(fN7eDfb1i)maokrhx%AO~RP+QsXkk;1>xnZ74RqZz2iV`EX~me?c2!tLP(?s%~#g7X6Z) z0H3H2B*F=&q%>wl^Wxp=AVg?iX)cCYMo|zlnGnV0v z%Ms{dgsA5uxZo}m{2*c&%nrCXtF?$p(ABFE-@^`rpSs#52JZZ-P}FYSI4c$La{cie z;Ms6QfZ6KJnCmTIhaL&H#T$^LPFoRSk*aqg-&~}`!=72JzzX%_LrpejMZyMvEc`6k z@s?5Bcm)a};!+1n=|B8}Al%GjigF*7xv)_~Jfazo3aKHEo~$1-psl88N3 zhzB-x7U3L%?vDCM#qLQN3Le3h=>?@i+|>-xuQNYLZ#SBB7h$6?dZqg$vS2B5Nxh>z zEj^W=oCtfvk%mQ5S#dp!89M&E_Am_cheo6l@i7;+pdRgzn9J-rM`IRYrbo-^XN=s9 zPdS?DYV3NGqj-4g%L~R<(ZeghqAMqU6da#Nx0q**{@M;LAubbd^dI%u=v7IU^Tl{x z0IW%(&D^f&d#|IpRdEc)^cgN}(ifrQi??L(@dA_aGN$(EEv18t{n{q2U%(5>2dJRl z5h}?$!a8^jdAoW1b3~QfcvZxXsil!zJA@b)CQu480!vkoYH#p{jXZKmN7jZOL+&;?r-Z<=?XLx5e+C3veg-g3hs*97G;%E!L^lZC)UD?sQ1LHTkati zzX%tbtR&=Jz{@UGat%ew24qHjI3rDFr?Nc{HO}Sqscb%bAfpJd9{F9(`VrAEb}J?I zG#rb{axw{X9Q}cYzmidkqqb1_E%pr>R<6hVG8;~%7UHQ`P)M3?DWzVIdRrggu`|VE d14g0Rp1wYQpEqkw4skIviBHX1x|$Rm`9G=-)ItCN diff --git a/tests/fixtures/blob_70.bin b/tests/fixtures/blob_70.bin deleted file mode 100644 index 70d8d07f09460e89a76fa0a289d240f12a429161..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 867 zcmWO4O>Y}T9Dwn$*Du9}R#6d+;x_rOQ&_wBB?(1J6Ky(aVuFhk8?R{~DzeAB0GR80LPiUhDllT)>ifi;5Ss?MsFHRWXQmsY^3uIV*J!qn zD$r`~HI9r%1v=gK-Ns%ommAzmmT~|n#feMx*&?b87P6;Q1kB_5{Py7GtVIJ;Fkj-u zgl52(%MOLTLj#EK!^jh`{}JJ~2WMkujv)wr{4+dK);GBp;gsWXyB{l!MbD?aq;(s+ z`-hF12&7i72}-O|c~;Lblk$M-^T#MR`1~>n<=7Lt)*+|Vflg?SCu~ll!sR}733GIf zQ;!5DmCVF8UQlYL=gz)JgaTGx8cXR1TlKolP{Z889S~VSv}N zH=zo5s3dR$zlxDkY;uWjU$9^|wAlGKgU7QSH5)58&|7K>QFR+l@H-E$$I5cD=lSqN zy@I=n;8fy#_W1a?{&ug|IZuO03WtQNJNUcVc5!v^)l-D@zfu>U+{rL*I-y0MzV<@j zB9iDm5z^?7-_kjA+IJYA1fav8iTU&V%DLKSsf{-`Z`B{B64hY!n~P-V(7GgINF1l` z5_OaotJJpjc_Ce0t8LWQes~?DIRF0h$Nv#n;0Q&{tI3LBToN1_oAz?47UajMk&oDVuF9d*OD8x NbtvFh;Oj&=_dm$73{U_7 diff --git a/tests/fixtures/sha1.blob_70.tch b/tests/fixtures/c2bFullR.0.tch similarity index 99% rename from tests/fixtures/sha1.blob_70.tch rename to tests/fixtures/c2bFullR.0.tch index 2e46abf37fbbcf0bb959413b06530f3940bf18e2..a4cfea605825c33018badaa5465caa4200b18e56 100644 GIT binary patch delta 109 zcmeycNTFe|!UPM(hDOU)OU719rdCVlt(GjpPd6sCTx<7v$^yi!+kKw06@)sR=wpBa zE(Q^iC+j=KvcxN5WJ{#GWy4E9E7=F~v;Ir=S#rW6*>g?c{LYE4$K(GyX2SF^FaQ8; CJtV0B delta 93 zcmZoztngux!UPM(f=0_$OU719rdCVlt(GjpPunl-W(8ul?H6{l7ldw1Xt`!^!iWJ1 kxEVy4-Bx`l{J10X=zdpq<3kZP1vhmroM326hA9Ek0C5r@$p8QV diff --git a/tests/fixtures/c2datFullU.0.tch b/tests/fixtures/c2datFullU.0.tch new file mode 100644 index 0000000000000000000000000000000000000000..db8a4236e38c3c56f6375e46705d788e13cd64ef GIT binary patch literal 528880 zcmeIuPfJxn7zf}hvd`BuG|ODEasixyv*?O9G$)R_MJ{GJreUc6{2SUnwsDAEUzBY*455fs QU4-11i`>-dX2QSqHzJTYPyhe` literal 0 HcmV?d00001 diff --git a/tests/fixtures/sha1.blob_35.tch b/tests/fixtures/c2fFullR.0.tch similarity index 99% rename from tests/fixtures/sha1.blob_35.tch rename to tests/fixtures/c2fFullR.0.tch index 8c3d3d2d4b640fd0fb9c765b071a466488a62595..98281be7a1105f8bce690a7a38a4f52f0ac2b0dd 100644 GIT binary patch delta 84 zcmeycNa4dGg@zW!7N!>FEi4^hHYRu+Z}0fR0>rG_JHD_Lgc_XaV}Jq{1`)0&>pR7= g#4BQCOQgGH!%IIa*$4771i3o8_`2%lrhpUz0E$2yhyVZp delta 84 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

5S=a^rmb4!nw{?Qo#6Y6dfUa5AGrc<{w<>f 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 delta 278 zcmXZXy-LGS7=YnM+X`82=X{fkA}1$5Cr64^#LXd2j(UE+G{Gj(Hg&B-z#H%aG87z* z2-)yTIJ??zCU&+J9^Q~2k5J9_IOM#pPild@hIg&}o+EH$WmCN<1oT7THK$0_S@cb3ES^lOoPX5Q+;NLO4@#Ds1$O^O2F*7^o#Re#kyNEBvc P1Qm;HfEu Dict[int, str] - prefixes = defaultdict(list) - for sha in shas: - key = binascii.unhexlify(sha) - prefixes[ord(key[0]) & max_prefix].append(key) - return prefixes - - -def create_fixture(shas, input_path, key_length=7, num_records=1000): - # type: (Iterable[str], str, int) -> None - """ Create fixtures for local testing. - Object type is implicitly given in input_fmask - just copy the data, object - structure is not relevant for fixture preparation purposes - - Special cases to handle: - - create a placeholder for max prefix to make key length calculation work - - prefix 0 .tch should contain num_records - - the same prefix 0 .tch should contain a predefined key: value, - b'test_key' -> b'\x00\x01\x02\x03' - - """ - max_prefix = 2**key_length - 1 - prefixes = shas2prefixes(shas, max_prefix) - output_path = input_path.rsplit('/', 1)[-1] - - # - create a placeholder for max prefix to make key length calculation work - with open(output_path.format(key=max_prefix), 'wb') as _: - pass - # - prefix 0 .tch should contain num_records - get enough keys - db = tch.Hash(input_path.format(key=0), tch.HDBOREADER | tch.HDBONOLCK) - # -1 is to reserve a record for the predefined key: value - prefixes[0].extend(db.fwmkeys('')[:num_records-len(prefixes[0]) - 1]) +def encode_value( + value, + dtype: str +) -> bytes: + if dtype == 'h': # type: list[str] + return b''.join(bytes.fromhex(v) for v in value) + elif dtype == 'sh': # type: tuple[str, str, str] + Time, Author, cmt_sha = value + buf0 = f"{Time};{Author}".encode() + cmt_sha_bytes = bytes.fromhex(cmt_sha) + return buf0 + cmt_sha_bytes + elif dtype == 'cs3': # type: list[tuple[str, str, str]] + _joined = ';'.join(f"{t[0]};{t[1]};{t[2]}" for t in value) + data = _joined.encode + return lzf.compress(data) + elif dtype == 'cs': # type: list[str] + _joined = ';'.join(v.encode() for v in value if v) + return lzf.compress(_joined.encode()) + elif dtype == 's': # type: list[str] + return b';'.join(v.encode() for v in value) + elif dtype == 'r': # type: list[str, int] + _hex, _len = value + return bytes.fromhex(_hex) + ber(_len) + elif dtype == 'hhwww': + raise NotImplemented + raise ValueError(f'Unsupported dtype: {dtype}') + +def write_to_tch(key: bytes, value: bytes, shards: List[str], sharding_bits: int, use_fnv_keys: bool): + shard = get_shard(key, sharding_bits, use_fnv_keys) + _path = shards[shard] + db = TCHashDB(_path.encode()) + db[key] = value db.close() - for prefix, keys in prefixes.items(): - db = tch.Hash(output_path.format(key=prefix), - tch.HDBOCREAT | tch.HDBOWRITER) - data_db = tch.Hash(input_path.format(key=prefix), - tch.HDBOREADER | tch.HDBONOLCK) - for key in keys: - db.put(key, data_db[key]) - - # prefix 0 .tch should contain a predefined key: value - if not prefix: - db.put(b'test_key', b'\x00\x01\x02\x03') - db.close() - data_db.close() - - -def create_blob_fixture(shas, key_length=7): - max_prefix = 2**key_length - 1 - prefixes = shas2prefixes(shas, max_prefix) - - blob_content = b'*.egg-info/\ndist/\nbuild/\n*.pyc\n*.mo\n*.gz\n' - - offset_input_path = '/fast/All.sha1o/sha1.blob_{key}.tch' - offset_output_path = offset_input_path.rsplit('/', 1)[-1] - data_input_path = '/da4_data/All.blobs/blob_{key}.bin' - data_output_path = data_input_path.rsplit('/', 1)[-1] - - with open(offset_output_path.format(key=max_prefix), 'wb') as _: - pass - with open(data_output_path.format(key=max_prefix), 'wb') as _: - pass - - for prefix, keys in prefixes.items(): - offset_out = tch.Hash(offset_output_path.format(key=prefix), - tch.HDBOCREAT | tch.HDBOWRITER) - data_out = open(data_output_path.format(key=prefix), 'wb') - offset_in = tch.Hash(offset_input_path.format(key=prefix), - tch.HDBOREADER | tch.HDBONOLCK) - data_in = open(data_input_path.format(key=prefix), 'rb') - - pos = 0 - for key in keys: - offset, length = unber(offset_in[key]) - data_in.seek(offset, 0) - blob_data = data_in.read(length) - data_out.write(blob_data) - offset_out.put(key, ber(pos, length)) - pos += length - - data_out.close() - offset_out.close() - - -def main(): - # only 83d22195edc1473673f1bf35307aea6edf3c37e3 is actually used: - create_blob_fixture([u'234a57538f15d72f00603bf086b465b0f2cda7b5', - u'83d22195edc1473673f1bf35307aea6edf3c37e3', - u'fda94b84122f6f36473ca3573794a8f2c4f4a58c', - u'46aaf071f1b859c5bf452733c2583c70d92cd0c8']) - create_fixture([u'd4ddbae978c9ec2dc3b7b3497c2086ecf7be7d9d'], - '/fast/All.sha1c/tree_{key}.tch') - create_fixture([u'f2a7fcdc51450ab03cb364415f14e634fa69b62c', - u'e38126dbca6572912013621d2aa9e6f7c50f36bc', - u'1cc6f4418dcc09f64dcbb0410fec76ceaa5034ab'], - '/fast/All.sha1c/commit_{key}.tch') - +def write_large(path: str, key: bytes, value: bytes, dtype: str): + if dtype == 'h': + with open(path, 'wb') as f: + f.write(key) + f.write(value[:160]) + else: + # use zlib to decompress + with gzip.open(path, 'wb') as f: + f.write(key) + f.write(b'\n') + # run a fast scan to find idx of 3rd ';' in value + idx = 0 + for _ in range(3): + idx = value.find(b';', idx + 1) + f.write(value[:idx]) + +class WocMapsCopier(WocMapsLocal): + def __init__(self, config1, config2): + super().__init__(config1) + with open(config2) as f: + self.config2 = json.load(f) + + def get_values_raw(self, map_name, key): + if map_name in self.config["maps"]: + _map = self.config["maps"][map_name][0] + elif map_name in self.config["objects"]: + _map = self.config["objects"][map_name] + else: + raise KeyError(f'Invalid map name: {map_name}, ' + f'expect one of {", ".join(self.config["maps"].keys())}') + + if _map["dtypes"][0] == 'h': + if isinstance(key, str): + _hex = key + key = bytes.fromhex(key) + else: + _hex = bytes(key).hex() + else: + assert isinstance(key, str), "key must be a string for non-hash keys" + _hex = hex(fnvhash(key.encode('utf-8')))[2:] + key = key.encode('utf-8') + + if "larges" in _map and _hex in _map["larges"]: + print('reading large', _map["larges"][_hex], 'key', key, 'type', _map["dtypes"][1]) + return read_large(_map["larges"][_hex], _map["dtypes"][1]) + else: + print('reading from tch', key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + return get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + + def show_content_raw( + self, + obj: str, + key: Union[bytes, str], + ): + if isinstance(key, str): + key = bytes.fromhex(key) + + if obj == 'tree': + _map_obj = self.config['objects']['tree.tch'] + print('reading from tch', key, _map_obj['shards'], _map_obj['sharding_bits']) + v = get_from_tch(key, + shards=_map_obj['shards'], + sharding_bits=_map_obj['sharding_bits'], + use_fnv_keys=False + ) + return v + + elif obj == 'commit': + _map_obj = self.config['objects']['commit.tch'] + print('reading from tch', key, _map_obj['shards'], _map_obj['sharding_bits']) + v = get_from_tch(key, + shards=_map_obj['shards'], + sharding_bits=_map_obj['sharding_bits'], + use_fnv_keys=False + ) + return v + + elif obj == 'blob': + _map_obj = self.config['objects']['sha1.blob.tch'] + print('reading from tch', key, _map_obj['shards'], _map_obj['sharding_bits']) + v = get_from_tch(key, + shards=_map_obj['shards'], + sharding_bits=_map_obj['sharding_bits'], + use_fnv_keys=False + ) + + offset, length = unber(v) + print('reading from blob', _map_obj['shards'][0], offset, length) + _map_obj = self.config['objects']['blob.bin'] + shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) + with open(_map_obj['shards'][shard], "rb") as f: + f.seek(offset) + _out_bin = f.read(length) + return (v, _out_bin) + + else: + raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') + + + def copy_values(self, map_name, key): + """One large file can only contain one record""" + value = self.get_values_raw(map_name, key) + + if map_name in self.config2["maps"]: + _map = self.config2["maps"][map_name][0] + elif map_name in self.config2["objects"]: + _map = self.config2["objects"][map_name] + else: + raise KeyError(f'Invalid map name: {map_name}, ' + f'expect one of {", ".join(self.config2["maps"].keys())}') + + if _map["dtypes"][0] == 'h': + if isinstance(key, str): + _hex = key + key = bytes.fromhex(key) + else: + _hex = bytes(key).hex() + else: + assert isinstance(key, str), "key must be a string for non-hash keys" + _hex = hex(fnvhash(key.encode('utf-8')))[2:] + key = key.encode('utf-8') + + if "larges" in _map and _hex in _map["larges"]: + print('writing large', _map["larges"][_hex], 'key', key, 'dtype', _map["dtypes"][1]) + return write_large(_map["larges"][_hex], key, value, _map["dtypes"][1]) + else: + # use fnv hash as shading idx if key is not a git sha + print('writing to tch', key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + return write_to_tch(key, value, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + + def copy_content(self, obj: str, key: Union[bytes, str]): + """One blob shard can only contain one record""" + value = self.show_content_raw(obj, key) + + if obj == 'tree': + _map_obj = self.config2['objects']['tree.tch'] + print('writing to tch', key, _map_obj["shards"], _map_obj["sharding_bits"]) + write_to_tch(key.encode(), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + + elif obj == 'commit': + _map_obj = self.config2['objects']['commit.tch'] + print('writing to tch', key, _map_obj["shards"], _map_obj["sharding_bits"]) + write_to_tch(key.encode(), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + + elif obj == 'blob': + _map_obj = self.config2['objects']['sha1.blob.tch'] + _idx, _v = value + offset, length = unber(_idx) + _idx = ber(0, length) + print('writing to tch', key, _map_obj["shards"], _map_obj["sharding_bits"]) + write_to_tch(key.encode(), _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + _map_obj = self.config2['objects']['blob.bin'] + print('writing to file', _map_obj['shards'][0], length) + with open(_map_obj['shards'][0], "ab") as f: + f.write(_v) + + else: + raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') + if __name__ == '__main__': - main() + cp = WocMapsCopier('./wocprofile.json', './tests/test_profile.json') + cp.copy_values('c2p', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('c2dat', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('b2tac', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_values('p2a', 'ArtiiQ_PocketMine-MP') + cp.copy_values('b2c', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_values('b2c', '3f2eca18f1bc0f3117748e2cea9251e5182db2f7') # large + cp.copy_values('a2c', 'Audris Mockus ') + # cp.copy_values('c2cc', 'e4af89166a17785c1d741b8b1d5775f3223f510f') # null + cp.copy_values('a2f', 'Audris Mockus ') + cp.copy_values('c2f', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('c2b', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('p2c', 'ArtiiQ_PocketMine-MP') + cp.copy_values('f2a', 'youtube-statistics-analysis.pdf') + cp.copy_values('b2f', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_content('tree', 'f1b66dcca490b5c4455af319bc961a34f69c72c2') + cp.copy_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') diff --git a/tests/fixtures/commit_99.tch b/tests/fixtures/f2aFullR.1.tch similarity index 99% rename from tests/fixtures/commit_99.tch rename to tests/fixtures/f2aFullR.1.tch index 6cd197acc0a802ed0e28ff51ba24b732dc2c2600..557795c8a5ccf60020a6051a350fbb2348dbe901 100644 GIT binary patch delta 329 zcmZ3mM4@4c!UPLOhK-iljvEtP=!^wyHZO6MDX2e@$p8iH4Dw$XEAvZBN|RD`i%Swq zGK)(xlZ$l|^Ad9^i!+P$3R2PzP3CtjO)1JOR`AVF&Mqxhut`kd6L%;r$<|9vDYdiq z(hJd3@X0LBSFp({$x&dJF)=iENY72o%+X8E&$Y8oNzKcw%1F#BNX%BSNl{>Bb2M}) z%g-s+d%)lzn39{AUYt~^U}J1(WMOG)V5Yr5P{g6MIJKx)FE76+wIHWbFFms)qclk& KgfZ6+>TCe@Y;jcp delta 271 zcmXZXJxatt6ae6jMgy@>P&+lR5DS$h*?CDO7(@?XYwNs8CK}xQ5NEgD-6Fl-Kw%Lq zEyTu76!8i+g5VWwMew`9H=e@v6fU^|_tE*`ALj8@FFVzw1#E9P1;{~)aK z$>=Ta{4+Z%ug2G8>*HNDSFkMCx9`4xUKWF==UYcNNmDhzs@ILlI! z4lzF?B*hXQpN)05v9+E^!WMVH#BiM6LhElqWD=$h>F$yq@{LrR>KC2oyqGo|K z98*76Lx_jM+UOPsrv>HxZc-Kd;4v05-$mrG<9V)Y!>U>2TC309c*(vP)OFQpC@aW4 IUfO@NUmMp_Y5)KL diff --git a/tests/fixtures/commit_28.tch b/tests/fixtures/p2aFullR.1.tch similarity index 99% rename from tests/fixtures/commit_28.tch rename to tests/fixtures/p2aFullR.1.tch index 1e407ad9e62244fd50e0ead5b9b722a6dd6401b1..a876a5c3d09cc729b824aff5c4230d7038173b16 100644 GIT binary patch delta 1726 zcmXw)TWlN06^3Uo6m_9!n{`qf3F=vjw4@YXkd!Qm;hI=cmL)r;%*JXYJ3yo1?r?X= z-JQ)|L{SOCtz*Q_L)sdJlRosqHbLW}Zi1jlo1!Qfa|^$Xx_RH z?E(Im0~}!f`M)zWxC4i8!>=vz!_U6+_{Q*^otao~y!PVF;fzJYE2TXV@wQS)wa&(WvizI}P4b#bIEE1|F4H&lxXTcsj3ezaZ3S}ZS1aqGjlB@!!6?hz8c5RZNhhEVp*HEDV!6D? zgjbX2ouKDos6kG&0 zqAIE%rgaZ@<$xfkM`RZ{OqfYsJi84QGq5cq?8S$Ck-Lbq23Ub^!hlM-Y{5y;*VGgf zD=CZibhw4F8IpYr39!_|K%Lr?Zg38U0@#OZBQzv_ZJkWbb5LP?Jhh$(H3S=S9Bhmd z4!ls)Na_6yM*_GigdGgC?*S{@m;TIe)-Ue7{Sj}ogv7w_88400SL)vKllA`c;o2n- zyS?_RP)D9t6U57*i@hjykSRq_fLBdA^?-e@1c;Q|#%vLx4=J2wfZbd7fKXILKTd zyG&iQO}+j8CX$|(ZoyB5Cbjh3n_!oTZ}EXgAWW1B<$7ba_9+)o>F1){LfW%TIGNhq zXl!p^USC~poV~Ory*uH!dwaf#v8z*qWv+8uWcdlug^73v!d`$6#Bs0%f0rO}Vw)KK zQvDF7c~xuX?|k`L{z{+vxzCH`aye!SjI)eAa@7oJ7n7L1AIEF6AEm**I+>lj@u$3! zKvdr+F1){!WWv3Nns{Tb?5}w=bm2_R3Nc)@uqH{IHk-Z1xJQ{d_jkSpbBv#4LS7^t zA9Zq*Q8Ka3X*IWBxX8+ZN>E(=Y*fv8WbH3(*;YI=Bgi82Q{t z{&_C6rYTPy;~$APr!@|v{FNxF|AC*In~PN5qf|W(6QgPyJ00Tqrw;hn89$!?;YhXO zw~%u>`z>`uR4uZLTf4ux3y*1~gMQ*CobO~`;O7b@$(|*GZ@OgqWyb$S@Vm%>UEY{q zlqwwUscA5OPyBi+FmaO@zD+E=eKxztxHPw?GhzLEXShI@&JQLIg!7<#l5y0UEyXXE p@c6?IuDx;p`*$C_G=PfZ(50o*r;DnCc5}A`ZIas6|9?OL{1-q&E#v?I delta 790 zcmXxiNsrrP00!Wp3nN?s5*n(is`P!FqnYu(pf2;-NgUfVUg9jCIn~Q&$Eg#0yk)sW zJ#j+t6Uq(20V;&J_JojH_zmUWBSIX>0bc3R`vczh)erE+xA1H620VKCx%ujg(Y+gc zH}`Js-QIium(jh$cmF(p`t#HG-b{DDeRc3(?i?Kbe*3|%f1xkmeDL?h>mSj_@7h1U zv)S)oe*@|gV@UdRgkzqkg#b%IOvg+pgtRZRH~m}X+3BH z`0xdPaQ60yKTL|GN)vc|cChS4N_OqR%9nO8%G?DkB6bu+Yz6#=K$o-xZiXhIH1 zMWWWCq6M0=1l@U*s8P5v`m!>0#7v&>@;n``RIhL7V?F|#nia`xTZshhHMD(Qj1o@r z%F{&^vF)gIz%Gy7e7I`FXH(Je5g&w-N43%tOWG1A@fW_4j}c7HQ2wpStDnHyaTglioe<#4@SI2Zd>JOd9L z?b>i1Yhq*h)Rlpd()My4pN?fK@O}1K+RwY{py0H5o+TGb=Pq0Hn?Aj;dR!5N&LaXo l3a3U*JpbvlCx3qU@`ylD1miTr6>L) diff --git a/tests/fixtures/p2cFullR.1.tch b/tests/fixtures/p2cFullR.1.tch new file mode 100644 index 0000000000000000000000000000000000000000..5566dc9e32b313b4ad9c8705e7d3cf34d95028d9 GIT binary patch literal 617872 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 H00000fD%p* literal 0 HcmV?d00001 diff --git a/tests/fixtures/sha1.blob.tch b/tests/fixtures/sha1.blob.tch new file mode 100644 index 0000000000000000000000000000000000000000..9512afedc5d8eba17c8266b5abb2dd9d05e6247f GIT binary patch literal 528832 zcmeI&KT88K7zg0`2b6AtgQKI9TzZ$@#YuD#1V!iOPEp?eV= zo-BEj@OueQ*34e+UmwqJ`>q}Z?m^QoP3@fZ>sBI-U=uQ z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF>@0BlwsQ*&2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfWW^IIP)*=-@Jv35FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5;&zY61zIL)gn#uqRQRq HJrA*OXhbAF literal 0 HcmV?d00001 diff --git a/tests/fixtures/sha1.blob_127.tch b/tests/fixtures/sha1.blob_127.tch deleted file mode 100644 index e69de29..0000000 diff --git a/tests/fixtures/tree_0.tch b/tests/fixtures/tree_0.tch index 808e0e5c3039c8c526d138af8119173c1d71ec76..2e9f90117d1d94b250e8df63a482804d7ccbf96d 100644 GIT binary patch delta 1055 zcmaE`FYv-*g$V}Sj0_NPL6Bpk^-{*o0y1Z~M~Tre7@p~1V?qVvcAqDVEQ2Va+i=vM z_zBI0415e4K52$YW@ahL$%!VG21%yLCMKq)iD|}$mPyH$W`>EzCTV7t$>v7MMhu1q z24*HE3PG-pF21gMxhV{+|B`){oUlmtToX9IbE50<`2UWXP({i4rA5W5dIc$I4EN76 bNABM$!p)hVdG*)j<81kY0>Ygz2S8{5xDsD5 literal 1335136 zcmeF4cOX^o8^EuvkaCbnu9=oliDXksC6P+Y-YX+%p;S~#X_C5{Mn#39)U~A)MT?Mj zN@+*xcZK5jH7@Qr=ibLZ?m6%KKI8M8bKd8D-!sfSjQox9dRDqlbL`9pDk&&VQBzVH zh->%9{%7m=Z&l4SBjQqpTGm4F~`MAOHk_01yBIKmZ5;0csQ2_MO@qKz?@wcI0$dio=E7>b@Ln zrMf-%i#311ULXJjfB+Bx0zd!=FdKo$J=pPh-+k=Z3YG!^N)uRmfYK5{9yJJ@xl0YH zAQK1x0U*#qU@|N9?(6Wm0hECN5C8%|fLa8+DR7S@J3saMfX@6rGoH5kI0zELaIPG7Eu2Dsav- zORT|9Ab=$ThqhtKTCf!eFdu;>vOVVy2#x0rnJ)@BoWi7@P_WfpQ#9nF{aTW1kFt{eNIH_>SKgm^VK5fx&|S?g0TH zKsJFdsbp7$iWnvEx&fnxgV{g;2mk>ffNBE21!1g<>HvXpm?a?Ci*HP7Tm!CxQ%1b_g&2t+2)OEc&N0zd$Z1bn#|D^E?E%2@tT z@|Ze51=vuMC&&Ta@5j%=@hjjgIplMd<2N_PIBf8I(Q5O zfB+DnF@XW_j025{V@qA`hW^{TN0f2KziwjG@kM_eb>#LYdKW5tQ@i`R!+7cMPxlrw zZs`UkV9&VGrLAWwcWA4xD{a#Tz%ktw8`zIs0^8N$xW;buz;Yk}1ZY8^v95b9u|wcG z+C3pC1p+{zw**AVd~Ub=cyA>$U;QR+xJENy)WPEoZ-D_l3E=P2Q#TKDBxDJ`esJ5RM?9MG4OU3J4=Ne%zvk@@XgEdZOi#hlU1h7URDGF;A)5hLg`LxjkT7Uo$pdNv& z)_DZ#X#mNLPQXKxI=OuO1nS7`DjtOoyDEYGKmZ5;0U!VbfIxc!p9j*mk8ZEKtKauh zx+;PFKmZ8zg}{ZJzO;fi{UNXuhrVlTfBb>A=p#^!g75dCj|z${x{YGn7|b-WI0kd5 z5AJAkFkT-NLFTtH`hW|XpoqY4h%-&2aa@A&t`#%|2+Du}5cm&){jdMC3w8hjniBAO zMN@U44CMsgK(2%G2!VM(00;m9AOHk_01yBIK!COcRt#Z``Op!ewB<%kZ4-L&zJw5X zM+!AV0kVMr5C8%|0EGnHPodB#FbN2>BT&Ww@8)agPM?2re(ZBoXb1#=Kqmx*syo>U zyMO=?00I;w&{Rx8VRRNX9Nr~D=Lmp$MkTO-Kt0c9Ok|983hEI8$v^-I00AHX1b_fq z2{fIfzGX`p@OfD3Q)5gGtM@UcU*HuG=!(F>N$4FbP8UV5ZC&wf+rO|E_ocP9f&V}N z2mk>f00ihoU~F>dnkT>Sd_U}EOah}&_#Rj^lD^JMn;g~h5&ga23hx%ASP(g#d%FFE10Vn_hC?ue%P1|$8axV%Y(8#2dJT0v8sWX#nE90 zxyJ%l>s^O;AYm$WG8mi-Uw#5ph{0G25ipU1Yj}4k$8G4YwC6JO|9k%F!IPfbKn?m4 zu#BdkZqVF9z;$%z*CZFnH<|trF%#?j*kF1v0Dx`;mJFlsF?n2tzWV6~9u(7sfPV&E z)PhnVfEofKD0rtCYG8mNWD~fwo$RViQSoySQ@DxKis;_Y^#{5yXVlWon;F$J#`4P) z)(03XpiJV;t(#2ZC=J~#O{JkSPz3}iOu(|3!U93u9|BiU_S`Ilg*gZ;)PVW#{zh7m zNyg#baf-X$T`4-szDQ#GSWm8{4@V{F^XUV=k6L%YJ2?AD4w_+sz?eH&uo7$}hd|6P za%w>xAOHk_06GX;K=`md{=^n-uoejPjljDreQU?et)l6CA2&0zr-tu& zNz{8C00KY&2w;^!Z8cUc zXI#6d!Fy!-9b9i|+KvrAE6`S7zX5>&AOHk_0EGwypQ4Z;5Q7;4oD%5k^Nzu{w=r}4 zP}9&=CDfG87_ti#`*!~FjOtrE#-K(WFRBLtQ|gcfspJwce@1Ri^6Ld2CBH7z#5RHW zli0Q&tOo)>pzj1$AL+U6m|H#9!D@{Y4D1_LV*+*q0U!VbC`I4}H;mIM#S-KI0U*$k zK=hZ6+pxu01mqhS%b%ly*ys-@?_@0QSodc2e%g58(ak$)vr)Ky-5Hg995&9e&TNN$ zv?rhp@4=%zbUJF(MBw^BNBmS#eQN;3lqz6BC=dVwG$kMtMN@U43n1d9Ael~6b)XCg00Alx*q{$%94cT1kqk`WD|{n^fujqqF)M+UBdF6Cu7dlkX>v%_ zqWs%vIfJQle6@%B3EuJ59tZp;lYrwVGAm-V+7c?97owW|JD=sL^nGKKEQ|)J6SJ>A z?qnzIVpsxCY0yV9EIe=w2mk>f00g=vFdV)i(Jdb+L?3|*lKmTNpwFX@77b&dF-u3! zdbhQ>pJU42X@lB800;m9AOHmDM?e+cjZHuJpqXL>JmGl}im^nqAju{)TL-oQ0U!Vb z&_&=;CA#bZYk)v!1O(w*#hqbcnth9|GL5Trb#(CM|El-6`QLq5-Sd_T_nTpr1=!t@ zK*5!c+yB4S(8q6&{=Xb%+D`w$Ox|MK*ZOhjU&}roj%~(Z{eKAPWE6}8=@Rcj7U0!(Qiy-B+(YIF(3N# ze%cZNZJiOgD-6d;XI$v9Z|x>}Xr+u!d=X{jfE4r)5W#3)iynet2@vQ%fuAzaNB5s1 zNI)Y27EU;}(HNIzn8_OYw9<*qyGxQ;C^?^3Z5inPy%=Isd z3GT@`C{7txl#3on0s=swJpuoF?YH1J5C8&wArSGXFRh>r5C8%|poPHhCw(I!9nrUT z(CQxnoo?n3|JB0guL^j#CN={HRs#Vb00d}2fQy0qKN{d;Xcc7`T}$dJD77!TDuMk# zfbj@C-%A~zyzWy+E>@(Ts>X_?U?&g&0zd!=^o2kO2i(WdTW&%jy={U0`WNf00byYU`8fo<@Hxu3LWnI3cS-_tEt!iE4=@jdT>E95C8%|00;m9AOHk_0L2I> zzo(cex(GUSjV@}LODUb7Q+Mg%yC2LI3>@zDK+3Eq#IsUH4zuxRG=IInFq%i;4-fzX zKmZ5;0U*#{0tI-;6Z^}M-tFzRyN+RWH)Zs;8}tJKAOHk_0OJuz7}a^7v=#;L5m#X8 z+_tWwVAjx831jW&Hs~D}#_}HB-aJ%=*q}Q?U>y(u0zd!=00Hz6Frm>J}Q)WyJ86)7>L1Sc{F@8^7cT5-6cUKB!KmZ5;0U*#H0+k#3)0*~eew_ggN}s)`Gr_IU-GYFSk#DW2Y}vUF-VNs$-jg_>SAnTZ6LyyASpN0U*$O z0z+WltM||tyoKg%bUK)@1D$q(RX~7Q2#hJFoTrPkx|hZFz58+~1p+{Td;;%s$*&7F z8H2#Za>nq3S-l96hPkKy#9pU}yw)sf(KmhdwGSOk7c?>%204sn15C8&h z^CyhvFZcrl&`ux^#%pK~5yRP6QNVC6fkSjApp;B!1L&y!6ULr#q9ZC$O(gJ1HZFTqzL|AH3ZN%Pv)a?Yuy{(L$Cv(j0A2+YFRH=N1w3F>rB;AKD7 z3&Qb`qjXIcO6W;o8V25#pHoFoLZBNh1O%1gI*OK9kZXsk5Vm4g#ejL;s$g=Xh245r zS+RATVV5*^EFbk0JGO$QlqX;{h_cs&gYa!_$_EJ}5`!*b#85Dkp$VLR$0+Xrq-q9Y^LNO2k0vI8X#7^5jLN*B_V0vNZw?5>5s*1Gb-V1knRh0nW zmLQv#5slxMOSWNDs;C##wcw5LO|-7zKnV~40zd#o1hn9KjiP9v!xXz>blAb{R$PVW zG?@Jm0RMX+P&|P##@ju(NmlWvQ)E@6TBTwF)kK3}AOHj~LSR%szNdr{7r{&*z!U^B zM?-$a6oICqlM8Zt7M{?{pe#~bLMO8`_Nkts%m=M0^Rk4e^b}K-E!n#V#Mz$C{tLZ2|Rx01yBI^dX?zL?6AN^}hr%C$Zp+%l^9`t$Pfv zpw%+43kdX|z*RcE1G|t79l31(34#P500e+QM*^C)9k*c%2mk>f00byUU>TL4KcJkY z%poZ!jye3KwU=dF*c>Z8qVcygXdM^O*M9=VC|FCXh3i)T0|^pE#C7 zCLE4)TQ3_ybszu)fB+Bx0ziOn1fucS%zdVPqZ=|%3c=RQ#dGMOE`tzX_`nOITUdUga82`00e*l z5C8%cA>ffl5iua77X+U0!#JxKxS%Q!00KY&2=s!$$HHDz?qk)G{e5f*%@~$|T|C3O z29EWU0Dn$D1weBk00e*l5C8%gAmFNtjd`AHn)I`C3VdH1wMX)Blzaz^)__8U>32TR z+E>sA1b_e#00KY&2vC+l1g!H?7AQ!g8UfyyR1-~c!N)QB&IyWxz<|K(O!S_ORR%C_ z#K0lR&?aW`bvy>gQ2G04vlKh(V`#YG97PFioIv|yr&@>lIwLPo6cgr!r9Q>H3*Z0{ z00KY&2mk>f00g=uP||K5O>29X)flEgeHiugX@-FXjsO85Ky?C*WmH!I3YeUL z_NO(p1p+_-2mpb;5EvNImsZdQ2mk@J5ja_nHjDmik5~PF_rV_Y69~D4ej6FV!V^~+ z!3*#K2mk>_A~28+-^peqe!cbO=Xl!8z5Tyk4I}8I_y6ta?{)^0zDKmb+@L)W00KaO zSqU7fV^+_>Zy*2!fB-fKWZduB&OwrlF_!7sQ>Xz1uuT9j4(BSiBM8<50TdAUKs_54 zU#FgIMwYxD-q*{>;RWBAjDT@9lQ|6Tb|8@Vro$#`H$G>f)-;AO%!&oZZ447ka0Cbd z0U!VbfB+Bx0zd!=00AHX1n5p6s(|h$fB`@N2mk>f00e-*{}G7V|9?AR69~|VfJ+UH z6oDEbfC2(M`6w^~#U_}xeh=^z8Q(y@cM-*o^ue_B+&(mdCKMxZSOM+_pcqUL1O$Kp zRS0YgqKa4$3ItF?pkxo_Oqp!ZdB1*vf;uQ?El8pSft|{o$D9(f$&pbA-{~U<6UFPi z97Nx^Q{16`3bd>3rvM5!58FY$K<6Li*JXs7p+n)=WrR2~vk&JBY3qHx9CMyC;cscn z8MO6}!02xB!Hv4~J%+X9>8rngWT7?I3A`T-#~;>X2=-H#z?xX<$d4Tk=N@&)f>cTn z@ZL=cDIkL>2{cj8>%l zyvVgRM6mO?ZmlF&0@MQn=pt|{23_`mH9&xp1o$3OQW_3ddzZ5Eur6&CM(&GRe209} zcALAed*fC2hQ+MyY3Fxtfx}LU3KNm*}Euf<>1a8PM*Rj|aM$Fu% z=omA5-_dt(PB>RO5`irs00e*ldI%_ALys+B2@t>%fh8ZYWGyyq6|KgGoy}IJY{HJM zU?~s)0=*+p^SpQU`&yd?BlGfo^$*$s0U*HG1h~&KwtwxtBl2{d*St5R<97SH@EZs) z0|7UbJfnmr)(7<9x`3v5fGzzaaQoWt^ELfKmZ5;0U*$O0#Cm5z6~R^;Qr1C zUND9a!zlb-6ULwdUH}355HLJKAHDR@+O(G*T0tiez!m{()&8&J)6-*}QhI6!-9Ugg z1Qg(&YTAGXEkFPW00AHX1b_h35qOTG_rEe7{Qq+}r5DduWqYAN1%T6IY1WhuESq{DhI6$3>9zZDaTY0zd$V+u4iUK{FSK0RbQY1b_e#=$e39 zW7lQcqMhetUAKS|AV5BW@=0)fkxvV1GBSaw@Lgbr2rut`hHwM3PT;xd*QZoZp{#Cg zCVCGmW)CG-fDf^Ejo+T=U45tx1Q>w;M>ZpP0X_f$AOHmVPvA3rXQuxUsU#s^ zlCtAKDw)}>*eKFkb2!`w)h#0^1Oh++2rwFfSBDtQBk-py0%sp}RYLxL!}HzOow29; zawr7?KmZ5;0U*#D0)t_E+8bO*{DDy^Lv_VOK0m-!ik zCngVOFq&orteEKi?=*u7ihuwR00KY&2mk>fz+?mh-!PfO;4Tng5CS`f!Mq29gc95U z0zd!=00AJ-CjvzHzF42QF>9lb8uZT{%bznV{T9CmD$+j&%oqVD3ctIKks03V;d#f- zd|%SZyZn}pfn&WhRk54t&`NvIMp|iNK0Q-I$@BT%R`TjWEg;Ze0xJ5H8%K9$ z%eS4K?S*}PAutni_`YE4b(@OvUN>Rd2Dipj_xi!KV8QVo37B2#u?i|H@Rp*|EHDZP z00AHX1jr;H-|ib9IYDGLf@(m3Oai+K$*hR6YMgH|W-ypbHi0GL^dAq3Cz5S0>MHJ= zN`HQ+g8~Kt0VX4m^@}x;0muXbKmZ6( zoC*9vkt zQM=AEPKX1w8H4{{u)%n;XG%~52mk>f00e*l^$67b=%4J{UE~4%lM1bY01yBI z=p-=YBs%Q^tAGFy00KY&2%w!nsx-Fe0LMQ=JK+}l7HDCcGd3tQmX)P&|2Ja=6ubcf zK!BnImK~?4I1mN|fB+Eal)#RGki&Nh26h60P6!Nc_pZ%OieVQJ00KbZ4}lM5v;lD+ z1@F3~ji>0)l1k<~+L}}#w?aq6z>2;S5R!mnxUcM>9S{HlKmaWS)@P!{60idZkWb(= zJak9l5nk}VX@n=k&Y>I!B`*w z1b_e#00O8aFg6>NW`R*afME$t8S-y^!1{6T-TW^5uYK=ZQ@=$n+-`?;-W8Fn~h#?x|0yfcy zK=I-J>m4u>&Z({_4sADf?5Yl6NafP#y^Qqs z6Ycs-4x!ybun!0T0U!VbfB<;}v_{ZBzvIjy&sM0#xCAT(TaH5+3as7rMCo@Q-i^?c zOhzbIg!daWLKwjZAOHk_01yBIK!Cvsh}AH-gWw(z00Mm?Z~~r_>XBRJ{T{181t0(f zfWRLDr?lulU(P6@aLHm6Prwf#(0>AIzxpo&Bme;*00e*l5C8)7A#gsCK6*hb5C8(b zC!h-N@aa7?XaNLJNPuvwbEA$WbiN<<0s&eRxH|y*bI7l5(3%?U^;I(Q`$uR`8#Dp| zAOHk_02T?1K*4ilSmXva0|9yvcos_!t)P=q1U{bYy(BSh?2kKp?=`dl0_Y;3dktOo zFq1XbY;X-^rg(#|K!8#N7PY>kqFJ7J%0H?2C;xuKFCYK}fB+Bx0$3zqumOu!GnUOW zySRsivAhItfI!~~{BG)dTY9!sk%svPdh!R|KmZK{8V^v`igDaC zGh-7_tYvKfXzAUCJ+#yYx_|(B2v`-O#}>3&k~$7@GPK49>;eKn00^Lwz#{nGTbE%O zs0Mv%mvEo}2%wn2f}JQf4om|AKmZ7!kN^T}#wd&mx=c!Yf-ZZgX-#c3HKl`WdJ-uA zNKfscn_dJW#QHz3_y0sM>#47|_AK>vfClUmI4|4(^9KvwKk36e@?*bY!85QC2mk>f z00e*l5MVX}6+!6pc<>PB$SM0ve*2sLN`UsA5%4eWY%lBs0*psMs~=<3bOc@3>DBPw zY{ol4!6P6*CV_exDqW8v$uxkBYDSf0RDvo%00;m9AOHk_01%)tfhh-RtdIigh^HtZ z1Vqq;K;B5oJAnZ039Mm*=OJiM9W(*~AOHlgN8qC-ZTkzByVzp{76Snwz_1#Pe7J{c^AL|3=-gHhkgx%VFQza01%)vfhKjhcG5Wnpq@zxB#nV{jY&dH zbvMnpD0?iORi>;wssjK8KmbDo?!np{hN1`}Z!YNgc&=Pa<^H%Wow!`fh{3!kI z=h<>xb4(sL4dUOTCn55oT0(EAm%9(nX7ALWW|hKoZpv5uhzCCM zT0>VldE*w_dezOJRJM)NeM5%mP5nx{0dIb^^8D83{{Wm|0&5`Q;A=&`k%#r^ z+^fgVUJM^FefY%9b;wco(+M*Ss##^&W*O_v!p}s?8=Qo9$;v*~+MFt`!}IH@^^}X} z39@Vkdb$$`M#v7)6TX#7c8}K->|)t*_ewi21#cT0+}*_L#4iGRAJ^a6C1hO@e&O&>p1L;ZxB{NGpL{sMMApDb z4-Z%rBpnao(&U-tkZ1NSYGPV$LK}Yt2PYpV2Y1qejZ4eeP^DBh*Fbjq$k)=`oR;67 zgltz=3Y3+YHABx}j;X+~;=j+o zd2x}>XqK7v3ykcsm~(96rWm<%oR?)06W~zL>dsw6TDIRRKYp-O1h7ZWUe| znHIbAYQT^;k8VAy{=~ZS*|Rifma7CQaZe9#r&S7WRxY?2JG1vjDN`CZ51Kk9=(J9} z)PRC5fp$Z^eQa@Cj3VVcHog&X{k-p{r}=b6O9i$C1YIs)cPF3bO9S2!Nmq7^PMJ7l z^ryR1-<-W2wEIx9);@wPtDloQ{-(AgawytZd=1}{pkpR09{Cb-*kzK{Roa06`Cnk% zw%Nj8gZ~-p=_`kW^}}Q`HYl0a{d}6)DgO^|YFF$|ox_>4&S|nF52wntTXBo0_L=`8 zwJ|bje)b!eKM8)mG(X<;TxLA(4!Qg-Be?ZuRa{FajB4EUpq}RydrnnJJN_a*pA?cp z0)+4fxQr@lnqaIm>+gE*+N?1NQ zNObSLkJ39nj_k;P?yb8Gk;NmVzCMr--27_mls9U_WLjH8tTlTmW3-(Xo zn0v1s{~nKjEf2jr!dZ$T7OF$+`Li@@f2mtYxAHf$$^JOa&(-Uz{MYj@&V_%;t>O~u z$p7X=w_!Q^f-G)LF(|z+9UGAQK(+nx@1`QR;wG|xllH!0GmlKDJ~>HZ>rG^uhCh=T(YBlf7tqo(!iQ{h;?D%{Av9opZ@$joXvvbH&@tYgWb5BLBeqZZZ2nC_U~$T>Her4 zp_NCno@H#lFTZ2&8zYfVM+pXEf39ZDm%@x&_l~C<9uT=}U9#RkC&nst+V~DJ-*W|A-8ncS1pa*(G0I z!sEcOKNmc$#dFQ7?o^F9G&W}N;b(EUTx}L>f&pji1rI+>5NG^3dlL8FTN`hyomn${ zg~D;^ElW}evh1V_-UMaKaHQr}gDPRj?jG39S^^$Tx!>{6DzKeT>j-dW49-&45%OHu|;F-sBg=HKC0IC z=6YDp`;6nVoa5yuu8-X%wkD?+*>VZB@{g=eNOP)Ekma28Wyuw_H)jS7(BkRHzlZCg z8vEIzkL-oN>tb9}w61$LO&By&zYTZ`|ATFtgK&aLthn9V+_^jiYX~};j~y#HA}@Xr ze%>j6${zn=$%cEixTX^X43ckKOg7v)G+h&?NiP5X9{+FEuKLeXe>BSPM#(MrHFvKk zINQz-v=eU5$KDPbF;sEUVBt-Ki?hXVY~B@DElT{+J{=n~UcVt*=cj0eVc7=hw5oJ} zA?^DF$G_=V+=-of%h$vm)#8}5Z;9-IO%_9A4!7}c`Co9aZM%hkvhSI)*bMhF-osn= zC~uwoLPAQZQ~s1a{u|_@_N^31uupv_D7kE&OxpIFLO5G;`TK2AUbJlw2kV)baTg3X zvk2Y)_|Ut@j#hK~AX4o9=;K>NbO&?g0~_m$Z1!p@r1^%7 zv9NBkS$xhRS*2Y*z)Eyf+UdE5} zQn?0aW@~?>w|VVgtDP4IsU%)2*>gYXGpD`yX2*PY&$o!j_&xso!}bCYbol^@LasSvtnoSM2&)7qRheT7n>B!`o?otu@D zwhXfKql>N7@n7rpK1j>WI_kvfH}m-AHZ29)+I}^k|APXPix=;Edw2x@ug8T?R*v@3 zh&xeIeeCaqn3b!8hnJI&qZ>)D?%B9d`?96t!$tQLyK)H(uN(A9-%yDl$L8f_<&T#_ z#82rZ6x_=Dk-FLAX>p=)O}XkM7orrKw~dn%sdR?cy{~l(Z0v_7d|Bz9@vYq2WIGo@ zio@E<+fHR7UK$z6b0=SA!_9?;W}ffw^6gXEn=nwBD9!HV;NRiRWf>t4V5@F8lDD#Y&9#?1y7@50hLbZ#I>zW|70K z#IHcE+uzdim*76^w7llKtiesQ8l?wkh?4ByK3;ZKI_D5?DFdH@_Z;fErc11I2qNwq z7<(v^q+Htoc{G!4w57HF-DLw}9Ua8%pDi9SvX+47vbFND^Ko*s!@D4E{?=BdV_ci& zYnz(vDm}Jf|BtDOL|L4jq!WvStF|n1vave+=l&~Rmjjjdxwg?tOCD-uf@|HVu7i zDX&_WEliZEq<#j+aA5ailH_b5 zSDeoSw=ZUF3x(I0J-Z)x+gnF#`;{QVY@EGhHQo@JFqlRCvBS)}PxeRi%)5BztxXKq zW1=LRhnJg`u8Y9sUt`O2hH;nj>U!%PR2P(3E&fbq}yH{Jx1;nc0M@VdndKadvtT&<~YZs#W(Uu&OH8z zpu_6!>n53uv%%X7e4H^^uY%oNILsu>*mcxC!SEX@S+blSzCPBz_VzZCNcz@P?R`=? zzc*A*#0?57Yxo_rZ4|+1fTxw0m8+|rtCP1L8=~<L)#fyGXF!ik>r@i>#K@oKlv~A^o`^2t!9zNIq13}O8hf!*H>nn z1$=$^a8Yrl?A8%8UJ#{N>>O-K6Uw8WZReYDtd{urLG}m9)7O!wL9qlWR&OT~x(Fq9XD8J}z~myQ;H@{7d)FoEc({vnh6wXI_zxHgzX^Z-TpbO)9p0B&2 zC9L+&cj)2#oN88SoQGsOVw7&|8>q*}V}0ZN&$k%~&&F~N*j3FYWl)8e69` zz4rFXS*4=&r%Qtho!A|}5ZyWaz3sfbJPfWO(Gz%bPvRCSUmE0>%(^z@nbo*dS<;+3 zi;tboB_t}jOvHuf^KVhPsIl=MH_aL%2<4S<;?Nb$jKA)G?I6YOT2Mt;xo51%R+0ztj!2=EWYm3 zjRg3eO;{3B)LvbzT&(GJNkf0Z>Fj(X7GE!IJR*AHqlo8|ci!>yWG4+hcYJ2KqpLAd zhsDPpZ;kA&|8&UD?YMRVQYCR}drI6CsViwjJgcvhEnX5yVvDpGFz`zGZVwyX&C4uo z=4O7^CrGldwDNMYvL22UB;~!W<*xC#zt!^Tac#VNkkN17jo(=OoTP^f`FZ1p2M~^a zo;xyXT~^oz>Bw29!XKT;PGni-W}uF|JnA~kFL%Hi|EYoJcjXyL8Xp|Jhv0x)?NBHX z>!5mK)w`7eKitLev0@vy39jCikFc$Fb+X3CBQ>8Fnb;QIC%##_LQ=Q%1dmYCI@h-D zxAlL){(n0JceCQemS)WPw&KuI@#0*$fT~jBnG2qI;cXc}yY&Ie&QIU0ifFuTS-NNe z@2uQQ8&lKwnrPzq{^eiw@5gaD1ql-Zi0A8-iUK%pdzPF3n^6m%KYLgGfTvpoo=j<4 z;<`?P7=PWl-FPV09Qht+csZ2)QO#Ko{YSGNHSolB$e^G2&a^C+t9x;uUn49}G+;qx z;i{U}{42Tso#hbwYLRaqXNL%szj>B9DnGMh{-s@$J>jT>vfYS{rgxu>%8Pn6cE3uy z`RV9Op#|sDCKR9MiQn-$wrI|HS+%2o)8mj&!}DgEv!w~SUi|vp=Mu+Pq z6fM>zBn588O9|p6A5NX}YTrWtBS)vZ>wVQ*{)pGzh?F7yU5D9@Je_O8dp+`_=zNLv zLl-!{N4@3`9Mj6VUVA%|Crc>(oU(oj>(I%*>SjOp-Hf+yS547)AnQe< zzfD6`lmbU`|IJECDaO*!bw2OezRcHIeRFK(?Nz}8$_mF3|K_BzU#_ejCa|>HZ=XX1 z>o@=NerrSD{L4wxhIvV>t;o=_P|CZZk-YBx5~(Qj_BrW#Ew@24Ge49R5gl${3`u;o zL-WaaqBL7`PO6=ZtO!2Tpfy9s!0nTGe0}INy|w1YIY}ugi@Pn}09iL@Y}8@dr#Oe- z(p%PfyX}ZgyP;i;ll+&j78Y5*lFv&F*D`+{`OYz9$;f4FXp~-xGA$n)6jj9b9w1>hfsC@$-V8k4$}eBlNohN8$jH#KzWq6)%Iho?-Xp zLkO%7@?Q_~@cG2!7jk)6hlEuZ!F`(2^jW(x@1&&DG4q`&2TyNIQfQa3;>LdSylP?* z%^f4Q!SSF;II&V=S2e2~sjs&2@y4%2EYAkLy?G+D1b@Wve962pHHTpp#w`i0B(kt} z=~DX#Yx9pByyAgB7=2K{VSXx6lGW4KNyiZR{8%n6oM+*(gGPL>rtK6xSOMv6rgH4rFW|MLNQZB45iC7AKZnD}(h!5EOeqaD{ zKXk?H*F&pWC3SU3J?oF<`rFOM99!sd;NY?chUT(0Zwt;fgCu1R`Nk>0(}6PAYwnkz0&q%?Es4?mjRE%T{4ZIc1)n> zmiQ{45vm?w{5$HLO;Bwv?!%9F1UbD_QfGHIyf*Lsyccq-(zX;{F8*{pQeEb2Yi_J3 zi9FIxG8ulwdCwdPM==o{79N(s@OwmQ*5=&Ur6o63j9VGby*^R>s{pV5%*iVY)*31& z5=Q>bjZ-&_i7$OPy*f*FqoMqxPrr`bxn@n2X7RGqm&RFXUqasJ*_I;Olb^f@3sir) zg3Vdt=D@Ixv!s)ob7v1h+=C%s!#1b$ymkFqeK7yh;m_VdL=nOayflZGle@Q*4So-@ z|ErkSt}V;9JskfoZ285@@l#%JKTApuoV~4NkauO9t)s0A*9GlvthOn5b~I~fm>fZp z&DF!o)<#yKV$SuvvqmA(CIjcB7ZtJ>q|THgrbxzkSR|p1exwn-pV&g5d@{wooq@24mRqg5~vtK)7b&M#_Vmk>x0|^(;t|`zRa&K3Y ztFK1Di^gMfd}B$;1t~9=mX~7Fi$IwkQUc1}Jfn|gYVqVsZ1PzWrJdyDrI2kR zJ(9C6Bd^y>8$u`0vB zO5;zYlhMx0UQ$}1aCM3B8)U)8ov|^YBVSG1=8+RaY~b+xldtPYAY+K*V)rciuvlL` z`t4Gy$ZxVMBh(4gTJ!boh*O5fsjpu?M!(p96lZv~eit<#6Dy9{3U zb!pWH7NylLBD2Npg#P5~c6*R**7lYji&w|x?%F^0;#%M0F$UNDNy+gv3FP6Z;MFme zi*wgqPRe<{_WZ~~s|P^@=|7o#iS~JcS5q}hCJp8fWsROw9lXHjK*ZHiM3XKuZ}CVzar{*+z9MZ{5T zKDJg~`ZEONvIdRFIvwW~$+uyMN9S5D0BEX&VtsK%ur1({BYxx8O@9)B*jh%NKm7Ow|R#nrf( zx{Y{uWZBy%ajy>kQsG6EC6~#~dcAV(;Z;QG)--?mT!GtlNm-BY5Jn6MS+sW|vM#4O zd~=$wi$lIFbLMd>%A7D{ul$ZOzCxipN!qo98FD{yPWC?qO#Ka1Y&KM~Rq(ER zO8ck8_$QD`}-y=Q1+?OvvKb+l9Rz9hzPIXl6vy6+YH8#2Iq?q?)?T@khSI zR|~AVyoc9rxK6#-=u2w1tUliyI02t!LQ3%seRG$_w74cd-C^;=T@)pvjb805pKA1= z@pXs!v>_D_&)LnKX5=H=$TjNaFNLT!z# zZd8I%oj=#W7rPQUz69ipZX5q^LTx?YC#TC+ABK(E%^w;OFf`Sg{loYU6KYK^JiI$@ z4UB2LzG_*SUB!0i1MGes^8w3(8eUo1yfp*n>JK)W%b9nyB5yN6jx<}AM#>1bUtK%7QYU3B+h)u3k%E^O1%?-`x7apW`|46w+4U@|1a@}J2=1y}B8G=G zN{OVEKjNuTU6s!FR;yh`aMgL$lhIDW^F!|P#jX&^t|u&uTpajYDyen0EH1op#=7l; zb1WQu51zB;cz$We%BGgtvU^CXjlB1W(8dabYH7JcVU70cB2e4KnD@8K+@t;g1mIP%5oanAY4 zY2Tx-UQE-C<1pfA>9M5@BzKW!(&PostjRS>9CqaN&Lo?Ob$g!-pKWTI>B8dX7UPDP zs>eG^?k!4{mb`Exrp!U>v(>ugflYsA(h}A`&nm{>d%SqsB5jRWtx%=vL5B#=oPRoP zQu<<#=o9tp?-0FrE9BU|E8MfFNo&jS9R!)SZrer-@iRW|`*^EiQRGRxFUMR5W*wCq zUqg^@h&Rf~ie`nG-@&#R|9pw+adhH9|antQ% zX1s#g1VeoDRN4;Ya*mDVrbek18z&5N3o@9#Ltn2!pk*q}0J)u&Q1*MNSZHlP@rhp_ zvNIl>IPBXxm8Pw|1JQ|Cw#e7XuEuBT%BJP@3j*g>3WgJ9*#1nVZ53GSAIVYSb=X7s zv!>_uobxKeLM23(z~-4W${Oqzkf&P!X014HKE zF4mLoOf%baDd0s|{g{(oKUYoHA%wE|woIiR8b0pj%~OX0-r2}qsJk<}_Ory$3GJrRSZBqk8@}eP z+3lmZ&0x{O(U0#e+T1#oCQRyw0~ek?vsPHB(NgTQ=Xx$qjtG~sT++3GG?%snF+BX* zVoXN#WwfD4mrpr{r4qX_)a}ayO+hSm9pY{b^TW!(%IZHmlpJG z)|Y#Q=KK6!s%|dT_gj+mnx*;H=7RjT{+D!r^JV_P46d8jr$3uW1$`X18{z+!$Z~Z< z^@+bXxV7(pHP0YL)>R_$+RIMe-^x{Q!oB9#6NPsDui7EufoUui4iTpZxoiO6A2nZ}3y|$r(9B`?={B z(wb7c^(>DOUsmcby|n6my55`ov7#HVh%`)T>wkCNnqyJ7dZneJ-mBfJMZ)%PoHJ^B z)BoQ0o*sON{n$PYxeaIchj1VE@Wbo>U;lf1-@U0HBfZvIhz+d@Iy}|8)`I16yZ+a` ze17mozl_iRFMnNhxX@&~NZl;0t^a-YPRqSud7#q5giXAI{Bn<04!O66)D4lw|F)!* zd1+dx(mgIUE-Ay=QV-5McpVgZ&ek>opi_$MR`!~{Aur?3gz~^Ac44lU{mi9I{!9P} zOu6&cD8RY;`?8wlobPzews>SM`_pwNwhY!g?YfiN*1}j9>ZNe0mw1l; zS(nAuXz|gK?YADO>$Yhf%I`)z%8Q#8uunNVT0ds+oMAKbc8%5=+p+7G_>MCq&RJdf z?DCD!$XNqjULbHS>AI#5tJtLs7X^7Gd)2H_iM;TZIlxN***L8O`m?w4JUt7EG znx}@x12%?UvwC<^0(`bjhSUT zTuo}s$>-N)zOSj+6I1bh3b|eP7JHLZmgBQGh+h>B;3(OyI;2`ZrnT#KZ0Wj@(Qm58 zzk08K{Oq2KW8XMb5VBSX^ZXfZyCJK;MzNVX`doN3A@+)qHJ@Dg(`?n&uKVTbAlFMX zlBVRnvpjx>=fbk+T(*@2opxRK%kL6P%PaK@k340wZyd_1dp6x+WV^203Xxv=a)H>~ z^euCFe#RbAZA9|-Og8M$b?e~~v32IguBmD4H#y@Xa)OCM)syn&n^(b%kgyax=cYZ} zgKkm#b8ye@%XZJFo=BZAf5c_ekEGi;6W~A9>2}ZBVO#VCKUSMXwtH8N*klhtKmWO89ueKauiEQoHlLU4h${(3` zFIZ^S{tuErcw;6Xzu=LR$m&H}B0Gb;x;mV*VS74znapVa)Z6E8e=!kKA{uB*8K@## zyj&Y)FYbOF<+0A}5ZBU?zvg}xXdQEJ);`~DmtTye;1#EdEWjhqPkayfm$^A!HL(h; zW+x4~gSU3xE&k#{`MJEmXQ2qnsNcJbWv*a{D56|UH<&IOW!X< zudt|zei2PHcxgRqlv!|dmw%ts<>#2IT_|oKT%M!K6?({gk>>n2^{4)J`O`>Q&wq#2 zDy^$$6+Nw<={Xz~`m)57W7Lz}x@$|_3M+5A>?KOeZkKZ3P{r$skht+Zwq@}Zin|#YJ5wAsAo6j6lScsFkBK|D9W$CO0*%tmzS~aOY z@!|G0bA|UDdGgV{o|A~jH7}iYGOT_@D)P~jK*EG0RW_)bMV>wDDP%-Pk$7NKe1z(SMB<}GARj{rAICL9v|nx z*Su=xI9K38oaBXv&*$YOG~$zwaW9_l8v8q2y=BBb9$E7(S~~Z+_i^*lQqwr?PA}(D zu%Fe|$>R!6wf$tr34R@dvz=osI=$HM{hURIf37)Ipe31ZP#v4m_w|I*!G47g`pxuf=M)*Zjo@k3R_9<>5nWph&0?iZMq&r+lBXWtA>zf`sJU?hu z+=x^*j$XI>bW%`d=6w2-nWJc0a6c;HU*BZL)kuzpKzVMjD;` zNf4ZoQ|s$;0z|~#$*Cs{nJTJpCZ}EW^Y03Qq|EncaWQM&1eY9`BY5H2mF-@}t-ITUF_u=t?ZR`F1 ztq^dR5RT^)=H=!I^Ir6-<(RjUC*$p(6#|)-q$870rpD~(!?K5?rhGeEw`69;J&m(? zS)IL-7yqsi+;Tl1pIzfQQO4gnK>YLaS-0F*OOdMV;kIjcpH0~(KHC*~YO?0%&st~w zNKbnH;KoPNGJzKMlWnkJnrmaE7}JB`-NLJx<`KKGEzq~f>n(U7!z9-vd7ORd_c*Kk`x{{}_oOW=Y z&*htQCGY%MCeW+;vrHhoZ~op{#7N!um1mbdn0X*{DzQd%;~43P)@6dwji2}F1O}Wp z)5tyL&dpDBSATc9!!m(DC(8sn#yX=~)(K)bf1Rt6klom@}3*X_+G7`Chv zunR1`vZKV{h!H`r>a|y6)OA(`f?(F%mURMw=Zi+Hn?KH(Uvb)v*#V<0CN5{o%a+q_ zopi9073gG{AnPit+n;5E)L6rWxw;ZBx3H;yWVvgZukO|f zPQ6Z!{xVSRTXy0!tyKY^vL?P`+Ztr}XU?H)*`#}X7fw9P6|x@u)Bg9M6-5_42s(ck z3U*EkKBx99CGvKO!0l_R&8x2Lf3@OY+F~Vz%(`Ex_+1)5%85&4s)}7OU$nN&!H#Lm zHRN#3P9o2TnepS#MZYpG*gnoRe?dS?+M<5`*momqPnA;j7q0Oy!fgCXBI4Rs3XrQx z_CK~B4ZKxjuqq?pbGb>@74f{ zy60DXQZp9cBB=dAWuTep4}9B7!N>DQ_1;xTOxU?-R-K@_P{>C0Ed?zr1>T5wn(qo0 zNxa8$OVgDc(~B>NujIecJox`5;HCFoL~qB8GVQrCoMZMH$5$uISOOo_jI&$IeM^>{`zw zp7Ph+nMQKt#9XA4yMe}4X5ReaVlh9liCE&o<(ST&R2HqCP+Cuy0Wdh<5+tA_?vtEq1b4(?m87 zKAj!4b)xB6SB2fL72JR2ivC$A5a3jO-V*Tfz2+Da8mHm_>VRQ^5hK)U}SdQhO*p7R`KM@_5DhnHv^IcCB8 zUB|#9fF)XHB_O()~en7#3Vw%)fM;L6dhFcMa;b; zrP7z?#&wvVNXh2*oHF6u9zK?e)KnA4ckDH@1>3R_#|$^p<8KyKikl`2PdZjtemU}L zO2_#L*$CG?XNxLu{(MQ(ex_I?*g3AR_?L~`O7aNeH(nR~icplRw{t+lmVzn74%rAE z;T}|2R1>;nLiouvi-PhiR)>&q(~N zW|>90bB; zyh2Xy_~t1H1EhNY`Dkh7JHN(w50bgz`l>Phm}zdu1%ku7M6EQfOl4eV=~1f*Q9lGuIkG+jFdZ|TtaZ|kO|z`w!6kraiPDh<{Woz zmaM773z_5E-EnKw-5s}&Nq5|S)LSWe!+GM*&-?3jl@A+#LbfNW*+r!Q;tI}6xkK>K3(7ZQdMYQG*0$4yS z%k7Ksr~`Z{mx zl85m(zg;(7np0M{LOq($wuT_N)A0KKs)YZs_ulbT|NsC0v1j5u?RjjGjAUf*5R#R> z_smKudy9-{ppNXVl1&F0g(R}cPDY_f8U3Ed5$})2`~7;q-tW)v`~CLM>72S;3g>wq zx99zKz29!ZL@KcYlPcOq%d#n-_75VQE;QlB7oe?QxWwc!y^+x+k9|_&ABfwRoF;M$ z>aML9HXp;gRuHaYHfmD{9HnNxv;&w z(^vI?SI@py9Xzzr0FvlBO~0s#r8OF3Tl%X6VU!_U!`s9ybdpm0+tKFZ5l4C?Ejn3> z5UoWbwNG{(e2}=UWy&`tnWrV<#up5b1<)|h<5v3bIrz2!tV3WeF!?e!x$ zCSnCg{Q6-Gq*fM?`xQF3ud96+>fU(CX;sG5^{`}=9ZpAXVP)Y7k=sN|t@IuVx7Fdy zJmv3bn?uop12@|~ekmkE0kuS~B|pE(Ix_VW_M&$)9Wd1h+mSYb8K4nY^5(mv^?A1C zvio?6XEI_=pOpkpU-~ycvkA6l23s}(CyqtrspAqUtZmUjFkUDm6_{q&0d9){7^(ne zDiMe9d8cIW&EWD!x|2Q|TS}oDB*Yd^NZeJYYZG|O{$-TyL8VUPTJ*!MBQ^$L3CR7L z9ymF0iJ=`|xzFOY%GYBjw~p8dQ1(~KmA0KUZ%zz9?I&XAp+R=%lA`_I5i45)ywNyT zzwXoZ-esn*RIA|%3e_Vc!rh_4BcQ9;XZlJF2O-VLqL1!GH*9(MM_PU$w@^M7tEsW$ zQ45WYT>jZw0p3LhPa8H-+%7Z9Z~Fw$-YE}}FAiC93(@QgE9NOGf>eFAs1nQ!k>K1Q z0jG@qDen`Uz|{O0?X}3rV4ufc2q&1*7IUjCF#=7)E2CySo==SDK%6z-W!jB{J+L!3 zkOE$coxu-DWy|J-qV#`{6SG?i`ucA7oXtzX!;zgSpt@*{3lp8x^H;U$V_~# zYxPbNQDK9lZMU@J3`rTjf9KZlfON|z5V~61euZ&~&BxA)@Ln|DbjF+M&K;lN6dBvg( zSvWHc9$jRaRNrt;b`hVBY8OM|y+PYlox;>rw@DLnK<`|jZS?%DXj z<08Et6uQ5E|Bz#h$^Lb40;LnJmvsA*Ll_!%`zXeLDUSeq0EI|7ePo<9w3a=VHw)k#j9xT||FOFtWcV8YshqUryaYz}#TfT&9k|vSUwYMnYdw}&(U44#; zw;8LjZ$zc(($q%paPhZ1yZyhKi;>SzA;eureIcVb2xi>8H%uXmpTEiB3S`$|jilut zrjN;npoO?I%1T^{m(={RdfDn&hvvxl>0@m#^re->0WLC$=X@mN`ZEy}u^@wn+(-MJ ze@78mu8XS@T=-I1tm)jh@^`ou&UyRv@daFdrryEt0hR)SLK1n69fl4B4hQrxgkAm` z8IQHBo9C=&XA_^1@(=o$FyuuGJ-=&JB)(T=F-^pCLn7k#moIhln~c%Sm%fz6$ys8NZcdLXAJUGi{koHL#| z2*a3?B*=vY(0YiF-9JcM)pn(@d1M#19x|kba7u9KUxr(lAzmuqcU0$e4abP- z-kEhp@YAosLmDz z75{sT~i;fJih;JaGK0Vo(@*yDhU39AI=dcyl-&%C&TU3r4 zYz-*HITFHDmrJwkJ@7rGFoqMTY>?XV=xqK)j}GPxoh(&?(@nLUxl-Lt!BgQ}o8p~^ z7?O~KILXQU%BA!3nmqk&11FlhiY}Vo;Nx8Ar`p^Rh{Lu^C+_RTHKBs(nG(fZ=1!m+ z-9{D%+Y{V!On=Fx`-3tGmEc&b?!4E@kcVMUU~^$*%tQ{%gj|=nsf&{dd&%Veo4c$i;5CbVvCnbofj=-?pi%o{f+U&H=NselekQVI|+DFzdoCk*4CeMZoS;rUPvkahOJMFr3TSEH~m+t6} z(0%~Cy5QB8a2~I!R#9&$le>FE$V%IJOK4kj0f&IG;L^nwkVDV)6EOA%kF%}sAk}Xs zMBGE+avev_x_Ktb*>pUB|EKTv>)NVc@j+IG6!eLpnH1xMAP&t)K?cfIOQSJbNjN=PGV#5 zdxW;NWDNc>lhVU1h}W~w%4}wCt2?t+j>Rt)k^f1^kNvov`ymQrU&$_mg~$oa`fg&D z*bnDeBme&EMd?98Gzl4f4#%SWnU~@YiD)G&l#l**-VgoudLg`_;wL<1`qH28_#)+L zMR8pLX!9RmFP%`zdst^QR4q^+Cl+Lj3?>Ia9P|%fFUjUvD{>L^fc2#ttnb4aa$J3l zQ1)Ffoz%UF3bVJO2>pf2UDKWe1+Mand)G_7FmbMl+%P3KhuI9vykdP@LU+R6J7MQH z&7H^>a3REl1imI*H&la7*ULq6bWG5-O)|e$yd6m?LB4@awz40 zALN}-#uBPv^S8(e8UOW&B71SE+PKe0;9?j%$sER#z&+c0L4A^r9lC4lM>%z>DiY5% zS&u-NF&)9}^{q|Bhd>YJdNno?3%rEbe4|2Ji;V2{`LoDPMEjyC8=mUrXY~1WI;O?b zD6UI_id+9>4`Vw(QYzPvjfy#{gFdHxkbtD&MxRSEf?<10kpl2y%e|a(mtC0kDYXH; zaX9muQ<4dS0b|=CaDdqYvs_pi+0RFxkWtOfo65^Ocb?7CL81l>(82&tBK`TIwTqVp zj)+!`WnztRA|iKp5d&+NB|@AT9y#MJnu+CYE|F{W(!gaTz}qVm7gq@uz}B$v1Q;(^ zTP6gt=XLKKl1gAOLa<m?K~;EX6% zW-vOyrJa3PfIITF4UTJK@Cgf3yeqsJFgollx??9TLmCh{&rEZcX2#VODw=5Az@0df zM-GKCO3h(g+nAeMID)wwV5G(kg3_l-**v;c{nS;H^e$g=H3g{PtPmUe6|}9zKkzGL zG15|tHN`T1yQul#MIoiyCi$h4V2I4tZl6gvFt(1uB0PPIZTh-fCu z0DWZhQxY(!iXEeH)cyzvGI42`y!w_g&$ zH^dHY$OdhwUpyg>T10-5HWEJ{cUVrIf1_4yhc=Y91&rTBDxfDxC)YhY_x*CdXpx|u zr6Bwa21pcw`7L1l%hBouQiLU=FD`xR_#51~@u*%n7iRsv`c5MJj2OvO3ydWnYtwB20=^D?2H6Y@7Ldlj5FcF9X%}#t55faOW zgO*RM_KfVwxiLoFdMEJe1Gn|8U$CwjSb+;vUeE8ds8E&J%Ag%E#3KMG?krRgPWgz_^2af_; z3C_3L)*o|{!t~GPWq#D5Y$gu+g^UchKr0|KSfM`c^~sW;cLPuKAsV;Q?c>33XP#M$NE6|Tc80t^_sSKH_m!|D9$9|yc~2xwgF3O*O6Zb zCSKASeD;|Xb>3VpqK_!}y5a|%28xJ!8SvgkY85zP z8#N{I;A?#(e*cq`g(& z*ZS^+Y_tG`V*O6Zn~T*<!aQh-bzP=KkOXZ*-Wnm>-*co<1hc z8Tx^Bz%2Kp`k&7re?=1(1A@uDEBC*gefZ=O;}Sx?lP{P&{^%Y}_}lz}muZjBs=zcK zUJd21TXe!@{CsL1hCG%31Nj4CA+g4mpN&f8Jk*pXpdq3mk1)*l%_rd%xGuS*c30;- zM-t_~WJ#U!yiNFr`2)m^uFrZbJb5?OUY&bQ``{AkQ!~3j9=~-ov+V=|Xpf-VW<*^Z z;mzSWOcchcw3T;^wP!HQw$FAjfuOe+b%wIxw0zBl&xl)VGCpX|69x!*Bt@7zj3~Lr79%6p(|~@$k+@Gh6d0V>6{r^Vfru&$I5LG8O0; zxn;e!EF(CQDzzF{AAkU1JgEDY?#4oHP}*Kh$~-CEexI_%^YlH`T_Qjl0&UmWgm`LH zbgG?B5aNwbkB=zpt?l2*;QCe0z>f?r-GBhR2us*wPJ^_2qNxp`RL!$X}sw37Mz8n^Mm2l&{Ai4wk!oA5kFKWIooGOIbG?dA&t5=1 z8{GQY2^s*Rt`9`B>riS_Og*wyHQ-tbzkKrTo(`dd%6N8R7j=IRu6j+WnAlS}aC0*A z8Qb30L$4TFeiUJGlr;lo07H;^aHY!S#+|JPFld0lxV=w1{=uUo(gvk+lr7B~((Jgq z_#kw?BrNXc#qx_!JCuwBJ0shcW{z(=KbTuk0!pX(@nSFA^_9zLiB^>4@eT{s*U1KfCcE@xfo_ z4E(G3Ak^qXb-%A@!S zNwSis;x&C-Ifc0G?ppQJiwVuQw_*l{po(+R_?0hSo$k##^~?=+7LH|}T{rmCl!0e7 z+bIJ;MLo?mpQA$f6qetFXeDkH-@!rEgYU!)fcRj9{fAfW45*Zj_o|GE=)b0ez54vNFtk@CWQfImQ@9{_sU6C()4})=x_N!&ABpvTxu>gOUm~9Okbp!Z^fif zA@#>!f7I<{i#gWaRjUjyNYC>bW!43)VXFT7_(681q}LjA zbZ6CRHff&;4(PYIqh0w2elR?{Nr^W6g=C8y>Z_~0eWH^&Hw2UKxcQT19pndBgfG9wX(@v#Cg=&6 zGvTgxjB~~Bb4h>64+4;dmX9S?jh|llf56vUpJUSaV75@_1g;7gZvX^pYFv{zw$C_~ z47xC%2v^)tbt{Hj@3^FZdnV?3PkgGUK!N5nOtgD?_XUJu{|S8XNU_}I+deIG>P%lc znzQ3a+g&UR58#7MQtzh8kF_efoTEsGnHM|HFrffH&g?(L2QTx$PTf*x)iYCNsP5O1 z=wh2XSH6u80t-iu!bm4N1ouL3gr{|`umlPM)V;bd$kPp}-87${P;)AqF zdY1XT=omg)rF977lavgcY^|W!-N6T63F{^-p&VuBZW{>p6uy@*@{WQD{v)xosure@ zZO`U`HkUeq`f~UR2g_2@pW%bhL-4`6m7mgsa7koj=Wp;qNb^ptA$T%lL5TZMAtBrn z)e@-;bcRa!ETQbhvAN&d8Um5y1Z3J}gvxGt8u*4Bimt#imWMsci%40PS zXF?`JS^^o-pUedso!7GjnwB^+9B zWr^NtTtf$WrM+~>n}9P+S+Ki?yKxL80M<9 z=FdSVYM(V+OEcUZ(KP?4N`rv;r@n?B!^CRjiw5qgSC6f7wuhLpJ^c^lpI%K_?jy{s z=`pGrWE?P$m|E5JfGqvUKmBz-n%dC&?^ul9!g#Do46%7@A|5h+`}@&;+s`FV&V660 z7SAr7*_2#gOHM-f#)9~6{wdkjP1(yHIEoP?9(sN?N6W`*@}>>~nZN1h!ee>GTGmE8 z{p2y-8x^b143N*-U{K?3T~KqS=*yV+G`gHmqjk@|k~v`}$t5;Z?fzgOVEizP(I0x#l_nn^?)K6-H@5HC0NNl~VuyD1{>@rLl#1x zaYb0Hk8rD(i3L(i$^etKlHSLYO%3(=XeIDn?6c3T zhnLfDujeGfk-I4B<)4aX#DFx0U_n-PekReFd`QrKF?kqr_vd+5z#(~7!M_j10A3eO zM*E(}d{UydZ2T;od_6df>;Q3>MnXNNZlQEiH`_@mPfb`Wq~MbDKBf6bc~*dYc~}~8 zBIbI{If@a0jPcr8EfTE{cvycZO{lE+M!fUF3y3)p zsxv8{Zm3C~YPmHx8mI8n^d5Yx_sVy3FQR~K9Bo#_pwy`;{PE-8 zTv=NDoTgT{CqU-1fCHZYxlMXg4i}SYv{p8>Wn8^!B5+*06%GH}JS*T9!=vd-t>fV# z-^_C0Y=#XTv>k+7O7o|AR>(z_UnIjrKXbqR{74cyG&-~-fA(0zP1ZpX#P=<5?q5l? za@b0=g5JDE<}jg*0hFFZr4jRGzj0o^zcv=rbvGRT@I)(w0@`KQKS_r#q|}yc{75aX zLdp@SAK~}r%e{t@ZLPTzX$8gS8h&t!^rJ$YnSDax7lM;a-lUDnpw|3(I{dcQ{B@)i zFchDa!GE>VS_EooJiw@Eq0*3jAHI_u3EYT+0y9(-Pnt(i1|(z+4jHb)ce zysXZCnqFwrt9M^IJk3K(Qa?G-3!Jw|?j#IRtT?dGBU*M6t+eo)$~h|yblSc=7@)nL z)0t6<60)5R{|q=J=K>VQyNOnZ=3F!@AkSZrhfgE$m5yo7xuZ32wwxMU*xUE6;C zUps$^<6N?{yu_cUKyw8a`=;ZSsKxN*K|}-z#Q(Je7&znr9z6iW|I-Js{`P}1pzM)|_RbOzUK0<-Nfx`&4hb<&SX&*8`KpLVk_eSUh! zP1cN3rI{}#*Z)cYV?7<#|K8I#B<^M-oLMN$c@ozC>I)1_Pq*9X-*EbF@$1Cj*t<-R zI}?$+4r5^QQ327HYhm&Hi@|{XtwK+J~kn9RG7qH!^9$+9cjpk>n#YChqtn84r*Hy#09`8mh5#Vt1WhIes?sAjeW^ z=f~w2JG*bb@jn<`5Wz+KrwH8FSq5GmR}#4@yj$3x6|1c#%aO){pEBq>^>|7^#It)U z?qp{x_|K)jX^3y~&h)cy-6eF3NvdB`xpO=nz!%|ovff)6e4K8z!woqbi7)$V9yf^P zu=4f}=T7c`x@8yKiK&m9lIqKMI| z5RBMhrN>s=9@uxs3T&*a;>(uk5VOFKOr?l=o~5Difx%gSPWU3|(6+1a?0_4lJk2g> zmE1M6uHI~Aj~MEnE@FZ(=MLH{aS`m&`x)8GK>I7Q7s0|9f@0!k77BdzQxt;QNpT}8X5Jglyv_ZZG66bvJ+Y-929uJtuA$)T+L=$j)er_*8)lIEjRoK==jJ6C zMmv&?y!+`Zo8=sU%dRilBGs4GeiO-&C1pk&}%8Z~wudE*N0>bMV)8 z8~j}b%zRw( zIW=fj?lgNS01U}JED?j4WVF4G9UpK|wp?v@KqVddlSiY~RzG7>2e; zEI1aBKE?dG2P?0qm-k*Ae@T<;kq8g5Ew~0J&<$|#_IQi|3w)?;Z6EU#C#kwJn;{%= z41F65rbmMwf(17)!x$O4K=l0(D0psUx5WcWDHuFTH4gQ;C86)9l_-Z7a2~U+dIS;$ zWCZ9jPIxT-ALePm30C8cdDi8|(0P|_bkF#vGZhH&!d#ic*{!~L65(;L8 z{Q?SRl@F1D9s&iAKyL2LWGa9~>BzR8t`}_JM&eneiuOSqoZ(||1rQ6SmzN!dw$TjO z%+6l&Sa#2ptjj=;@_ou>hHlSGa~xSVh(H8wPg!`ltXNCGDE;EUYCKb&38Ir!Fn^iLYR60mEzo z+ZkTwRnKSKKjO=AB@f_?7Ki6BHA*yo+k$YY0L}vLD=mzxeSRnkwy)gIbV~F2zJq6j zD~(qG<@eZ0-$kXhFvV%epO?8S2qsu6?M`IofUnoSKe`-i4G4 zyN}IJkS~CJAIn6(?p(I}q0 zVsqh8%3X8S!}!NOvn1U1Kz4=7*uE1Kwu(|SF{CgJ{U1EBovEu(cG6JR9Hq0G+m&4Y zkwvPp{VoZ)o7NRS7+|G4d}?@LlZ`OVk}&c|{wU{1;>U)U%H0&&>SV}F`Gn-PF6r$N z!!^d2;rt(#5#fb5-ud)#zB?jyp$R-}_ZrIprcn5Kzjr`X_hn<;xp=N6m2sXU2xc^J z$;So8K;oHBYfxw+>WRgEB+5Ikg(YgWlpLucXhnh=@FPLt`y{8Uio}LRAd4x_?W$iiF)dE7xo0l`1O(mLan@c)Q?ZJb3Y!rX%xT; zHnGu5NrRt3?;uv60*a09ea*R+Z{xa3yr{1q1z-7C8%*vnyE5al+(ny?RDY4+pMad&XH}P|}G$W;Zdx1^Cj{b?4=ps1QG| zXUvUPW@TSnXp7)V2lB>DO%O3;#UaWt=PH+seEz6k1Wit_BPV!GZ2 zQcj+h;N;f0F^`-cZ2&9pXj4%t#jfF9O&r4(5>I`rbfWB_eY0T07^d@aMy3tTf4Q#e zsnJ&n%KcGdN%q<0s@GmxP)^Uf=HOoA?L9H*v6DPHxD5{Xk@H32EEaP-nK)K$w$b>p zaq!cp01U?H-Q-bu?bpdKE}+0j6(;%>Jf?J=o)3&11c#xzl`4~Wr)D=W70>1It!D`F zb2=heU<#-vZcfrCfmjStgIG#ip5WISa@J!#p14}07I5aRTvA1#(>YeT&w1@8(^|gD zWj|~0{2)j_e7C<09VqkjO8e9*u$b;Of;R5oz96~yJ`~hC3ZT}B1W>G4JSNn!!dsTP zPgD7PH|7hd`i7w2(KDOQ*&Puie0?GJ5FR&S91atVq-x-2*H&-vFatzd0kF5^L1k%_ zVGk5-?z&mUJ6W|roVBfH1_7Zg`-u9cH&0qqlqWAJpGrB_8Nr>Q>W}<+L>zOy`cgt^v{wy)^4JK4bYb0Cfy4q zR;RwNl-iOJI`_;K?}(m7ca%p+@AjOm18L^=7$v6U7H7&05)fv>#fhycQb-{p0|7c* z8Z||~Ic8i9YGld9A$&hmkqO>BZ1tS11KiToJtgr`1H{Qs*_3ES$KvLzXW?P~2i(T;|O%1e!JCM(X&{GM%QN4p31HEu6b>-rgW3(AK z^b_&2(?G@um7Jigc-3C#RcT%5!k)q8sNG~Nt)xX1hYp-v z2A3xlz@O?RP?3Y_zn$;C8sbWwy?bl04W(c#Z%zy&iD@etZ4g+t8~GIUC9A^l`j@Xo z!o0#XA6|amT8H`$iwA;=XIn0WG(`FN*&2>w)@s9HO)o*^v+XyTb^l`DNs1LnhmE|t ztgZVpUX!)f;HZ0^UDAUUI3r65C|*jSR^yavR1{`&u+qVFm0OixZa4GRIms!pj7p9H z1khur-`%8k>%N#~WcLn*%vCD$9YO&EY<~nxsU=;2PGhCe5;o@Ba>jJ8{f*yNaCpim zfggonDjI7Fhz}QiSvpI^pAdWIZh{w^#D@74({Ln?huptg<8ji1<9k_1 zHr`y`uGs`_?xwgD<`r>eUv|v;$Sv(+3k_bkvz(#BwU%@~w(v2nrup6- z<0gi!_|Z_1A2yerKi9(9FNsb0sXM=!M(<^wb!ku-C|y9x0vu;OFJKLOi>abp(wIpm zF?iRs9K|Pjr>Bez7`{Sz@3#64;a4fO29Dx0CpsODSHi(@mJKPuar$If=SPJZp#pvE zORVilZZNr$J?%mR6}|cHB30{&7xEkSs!mBpE`(B`RB7fspjRL{tMAXahGP2Ar7U3Z zh7-Q6D>3^^dFhrZ4>Lucoio!&yNmYnO*7h4<~-*gdL?^lvRUqS)enYx5LW9q5o4q#`M2ez(+S@+ zxYvgpsB54I%OFk_lX&{Re^->80e+L0e(0vto+$aR+{_luZGoBDHO_FFR<`oAqN{dV7aXM7insbqDM z_G9T6Hf5}h$G|V-r`t|jdFiRQ(A6HIf75kpt+tb%V{s{zQv(~TcJk66^`7YTv`eH7 zjS-_1I)$(e&Z*s(E%mSFr3Vi{1%(9HrsN83bf38ODU-V6+{(E6Z-`4jeB0?4Y3WEd z<`;44=tB=MWBG8j&h;;pKkd2g?(yY=E&LDS(zo@>r(`d==OjZ$%904toH4H%DPGr{ zZTk)ERehp@recbXSL@?4plRabAUtTmroOFL{uA zp1|v^?mwOoXvjk4;RWGoI+(nQrh|!{#a3rLd|%dlhh3D<)Hg=+pKW}E`hN_Ys2D+A%@j+eJkaXA?P1!zJF!nHJNiv%7ina zIJx>V06>X5e$!KQtH@XQ_^PDM4955=grFjFwstaga)pHfy^o5hY=>%K$2Xe!3uXeo zQPQfO_YETh!w(?M>fWDgoe9aG9?hFQT^xF;j7d9WKZY$0Wcfc;^j|&7@zF>vJ9WvN z7#IDR;I3)5AW;Yyg{G-|_F>6M3w>@%HlLc6t1!ycEQHjD;P*Qg6~fH0yrLE(4q(%* zqQ>DNPC5H*{0I2!*0*tM?Z#a?+W2Q1$^uF%;?=|;NB&JdWn?1zF>N^(TrIOP{l|*b z*OKg^6mSL_XD3&i9k_nfUD5az%ZI6+qoR?Gls?+SFFeO~`D-(->m8^AWG`PqT5I|h zAIrVH`4sb@Pw9~Aw*HL!s*QWs~s{?0yO(i`u!&FN947PW;>eJsxS(#)JKcVI&J z+dg4i4$-?lmW2V|%!`w(M|H%eBBgqe{PmX=Kh;Xt!ATo$R)w$FkPm(XEnD3uJL`TA z0apfDH{5QkMJ#!`YgT@U1l+8oyMM}GS6pK$EIsCn@+PrcEk?}x2-me^0b6>P{*U-; z@4WFoeye)DbD6J$P^7P`LH^oiZE>=V zWp3_H?tOQH+4MnmGW4`P{`%K_!r5jXtU(XeDm&kkP}{O4p1&Ye{NSJzJ{13AMc>I2 zQUW}Dn$UV$jtb>D&5=qawn!g)U;J?&fBoq@j)z=+PVM5AqgM+Sa}f%63;mG%^?gb+ zdlQvpG>v=3D+HPMB4Gkz&3pW{6RzR)hO(}p08jQ#wuRI3ZG8QWGyNRb*E8R`>GW^4<9!0f7I3X903Jl90;IC8eMtGZCaS$w8W;deu zM{$fEJU_OdzlI*tCye;xI^o0cYxu<KLPV%<2l`z?_A?C!)IMO;b!dMwLND8`Rfio z3esWx88hcbf|rYB(PAdENACYI{&h&7Fm#u{hEB&_n6;HNt4XHr%ES3C$fBdD-p~mK z9{#jX7@-UUBY@~D0O=E5j|aKb)CbS%Ygs>hAWag`-@B!e|7HG*y#tN5;OtU;UxM=e zmNs5u**W-#q55JuP zlxmf^$+n_Pe@QtxqQqn7OQ<Y|(=IQQJthPbvr*SdIOwj6n zd_&fDpRlJ1OKSK#iWJuVG|0<9ESbmnUoC!Y`W;><+{}j5L!iIcfaY6#^pw%Z=HZ;% zm?6T%Lmo-e93oBWNPF-9kNg*^;g&5&zO7_mxHd$u7o>N1muLv}UHdp^?RoO}Ka)** z5(k*TF(zlpzd_18#_=JTCYLJnkFplG^=!x7g-i<8nGmYR4NW=jQrQOatCk0|7MFs2 zS(|06Ij3J$zSsIZ*^*V+qqQ$<5oKnX^xwsI_qA&kRK;8;R`$e|fLZr*g>2H* zu?WX->o8ounmdrOt$FAk-**H;T!;$Et?YWQ7g&@Z0bOP`HB0hw3AgV=-or_KlXlVl(5G#;SSUSE$sgA{+t%)+OTpxxCA;F(+GAs zN&s?MH)?!{X8K=FjC?}%n3yQHMX5QUcVFFqKh}Sa(LJNiVb)uCl+wVB_1v!By_mc_ zJ=xLtc8;EJ7;lT@kRutm{_ z3EqEl9Q{}8JNfF3CLws1dVHv7o3VM}9GuU^K1R?g8;O{@!1H9 z!@n|&w%sf5Yshucux62={Xw8Sd_(R_RVR>hC^Hj!HtHM!}>keL0=|YgT zp=%(g_E(3|f1$iHE;_{L{)%vS0nylXBb&gH^Njv4c0Bf9ly?G$ly_?W7)C=6Y45C$ z`ek`1;*9a%IE{t|DpE(%pHw)u@+|UHU-LSwhzSf0ErV^D>_02;1mm}WAiNt?1xYA+ z&J)MxVl|KCWYnZqAqUdGEbx>+G=QtA{J&V>2|c91vzhR(O{D+h1)cyFZ57Jgh`wuO zrnYPLP0I=YpbOXFp*zVRKWp%8WD=a*jbBTGoyK1ks*Vi^p0Y#i ztz-T!e~T6GbrZjT>xDBK&L2CEB=E=Q;`08;LjXQ%h0`aWwx*58PoJrY{``obT^tky zj6c-KaXzztV_AIp6dC;G=Bqr5lzd;tkZJ@mY!qpp8Gr9;G(}>E);cc7DUG8C`-zHe zo~~&CZ0+RF#Te}zOgRiHz0U3udlF30sSv!A3HPbaK$GqzN{2%}=FS@&5F;=kxAi)O z3x&LhIJS-t_r)PF1;1ICL@}YlFIY(Z&{t$95Ufs*9LGJkd?|jJ4*Q;s z(by`pY^%l?PjCJojpOe@C#(eWc7fFU%|wrHyQ`%5^(sHOG8h0p0=9RaBt#J&vQq3Ey_Jl2zBGT%ECp)_ ziQL&iD>si1Jfpzw!k2QDz9URbXGFtM`(!7pbGNZsszdxI=m>Yr(E>9>x2cE7;!Iv)fVBtXsq*me*ASpITs>L{G*Q%cV@& znb>VW&%F2hB<@GbH+MYb<{fVBD;2r^wK2QtThZf_oey6&1o|DFB@xhDjd*Q#@e^Dc zd7OhKMZFaadDh|t#-5{ixwI5dhhS5~6#vlP8KmEhV*Ai6Psy*W6!(LRz*x>FhHdig zEWjfC%6c(k;qH03j8^0WnLH(%85-Z6`cBA48==aZQqSg|*`}1|tl`lsruFa7--0eF z2uKg2Ymr8(MXK5#OCXMJ;jd#xVsB>jKt*_oL;}OJ@BSlv5Q4}z-@d0r9D^(2fMM(pik^1dmG_k>F(&a1&w)eY731Vsg} zf^X&Rcy2I$YmDu zeP<}=0Pq}DXkQ$z*YH_+*QfKUmN}eOVQOb6rvyYDo49^NA$1lp)LXwmpZ6RX_siNH z%F#(gL3P?SSj~-$k1gQ)WK7seZ;HJ>QwP~Oex+;x1UF(e0ZUk^Q}8U}s6o7i#_Jl z6K*`7CINHwQ~K_{FA;&-2mavmIo8B$b&>vzch6=<_ovqvZY3fJ1MeQ#Q(S7m@wzPH z`zWSSiC*;%`_1h{gcr~(E5UTnc@Lkjj#RKLs(=XMD=|#~GJI?7vyPhiiyp*`!9{wh zu5>(-qHFfZ<9GM5nGpE`CWQDlq3`+8CEHtC5~_qYwBd7XVJ~%I42mdGX_s>1N zBph3EgRYsrP#xzme@|XWL~!6ZmjY1P^U?V8yHZ-EK0=03aw67J>xKWvY~e5R_jwKB zKF=pUx^WWtY*g1zD1THYr~D7__m2Qk5)LH{(al0SyZn4|dqp|_WB-r82b(@-Kf8FM zt7F}E4G$rz&pBW5Y(Q@9{{a5}oO$^|XAqfaUKLuV*sU;6`3?)xzn{Mc{IQo^O4M42 z8)hEzXc;ZMZ@M2M^kY}>Z~z~4nRYrve#zeh&l`C@-xLzX?s2Y=QJM8jpc$=f-dzOz z34f22AnU-@_~H(Sx#Aa-ba~TPZr7UL5;<>=lpr8~|KQ6!&(R8T9ifZ)A9%tTp0K8K z)$K@-b--DpA!u#3$f?rMI?+3cfkgzMjNh3JumbCECBx~j;q#TZGcB&Hb$)PA96hyl z-v5rjhYB)VO?o9~mOq!)I)SOK@v5rUu&!WtHgGt9zb#JwJ^&x6d-O`6h)gXo24U(& z5pCpPrC&V;ekni2@3&C3pV9TbFh@Xx!Dse@p~5@-m$XBw$0k+3Gz2p2(e;JDqU#|) zqw8;gbo~t|6HC+PM@y=UA4)76ABP!t+tc|yqmg4`sQ{C?>i}iK>z7&7{YbgET~1Fu zWKykY1(UfI!Jr~nuygzuaQzh!u3tnP>33~7;ZZypI*3lLbG=J+q7n07gzGK0)430W z>l@d$;Chpv!S$vfT>tvlaJ}rpPvLs&kH3cNuRuNpa0*OzUVNHQCz7}6tL~jRyrV;Y z^o#8HNkm-F$mNewjo6$Hzn$a`dB{3D`5*9;{_}m}`}nC}_(@kx9<|$eU!(G!uBLD9 zWyTKSJVEB@iZd=H@kqt`pO8+D{H5!A9`>z;j*OBY;K5QlMk;c z4}tW@C+BE>%y53!G5xFUhhpH=Nq{x0^hI3#o&Ni(8P^+q+6ry=wl#md{qVDX7ZR8m zgy&p!gVBQDIfd2@-J@aOu}08L5xZuSB*X~G4Y!im*~nx9?DNsxj{tDg-lq2i zPHvy@E`?T7{DUI=O}~q^-z;kuW%m5>q1MPS`UNPBv=`SO_PYRRC{n6sDscRE;xP&X zk>f`$9W56|?mQgU?lKC&+)aM?UAv2nA9JMaM^PE>>ZwdwX7pn1mvNxF-)(ODyV_m6 zGfq6hZqSP5ZLq04Px*j6ET8|;ev|3n(C)Hv@x&WK`4aSi9*Hw3rgiRb>Ei^!b%(8X z7pflP@AO*Dvcs_9w6zL`mNkYIhadjZLw|}9BX_rS)x>l9(gYX2zapv6J?JlSXM03r zdlw3?K=EZ11w5Lsp5ZOrm)HIm+g*6>DsdQne~9{48y!7SZ?GXxufYDmy2Ibp?gAXr z?(%VuA^Tao3)|n??(%L9ZcaEwUKKwp-B5IDhem>_S`^vu zK|Ob;jvp|X4sUnaKdSmwy$hbC0(W3%lgPbt;n!1`E=_B~EbLA*abs5F&J< zBKrPD*^M^a#}o`zi@OHXVf8MEqQ6}4!op0ra4N3oyf^I``jVpyyjb1Gm3NmNpxnIa zA|kDu5A|5P;B?wo-1zRie0CB1Yyo@eWE2i2}$ck3?Y^i*##LNgc+I@6AwkGCU=c z%t!7zoFyK#jnSf+T6yBXaB}GJr~35EKEK^{_(i!3C|#PbAoa^mU$&1?WAodhJIs?- zt^#gKIt2bVi~j!pUoKsmxgre%N2q&c-iPltSZI=w;g|nQ{lB#I_$K#{rQwNR1^c%q zo+LQjk!9M?q=jUH1L_CSp-Qw|w}{%t3F&SG9iW?ftgqB*;6tkd5=pq6`K$Z`_`O;F zoJqsNO{WWZ4wz;a-T5Snp`-gjN%74=CQbEo{VDADmjUfU`Cil)Poy!1=s(%Vq`jnn zKE@Pf=VPk8i9;fK=^6M+`wp~xTq?qhQ@@&&N( zr-l$B6JzHe_;hUYiYmplQddIw+~;E>nYo9~H`_;0d918D9prnWu&_^;%rF}FB!2wI ze34Ho<4?TEPREqv9_1P>%f@l{4IKHQXQ@Ip73srQY|_mys6+sTUkPIx?;{v6+?*V2 z%(j}YvHw5z-aDS^|Nk35wv@_w+4I;t$=-WMAtfuDW3NaeqewPURvlX;%HDev5+Nfq zn-m!#TrcAk*G={QeBPh;=lcGx>(@W$9Cf>O&hvGip7+=NaUTw6G?-PyuqDse5w5XhDKh`Qhx{ zk0DgpH#1cTE%)K9^zU;;$o@{QNUfJ9h6E7|8=acMY->V|O^Vmge23R0|F?5RsMmLM zMS!|i>Y&&;PCUHgP1rLmrFvSW?rs=8+D?@)wZ)HYk&zKVD3OzRfZ_4>xi*#4BdXH+ ziZFU9c_~>Cl}4X`osMxTohF#^=;d8Jq9_)%mxBT))9~KCA!7ZdrurkNx76B zF_LvC2u%qPD7D~pV#=Tw?ZCoF|t)Bk**RYqd-EH>GY4{ibq9zk)9 z6RMemiBv9%felO%m>YwYw}wAL6euQb)Gl0l6LqEo;ax~8xgQ>~=J5S2Zhl#pdU5Vc z|4%PHQZgDv5!NtT42PYPV3;+5zweiymm~&55i^I^X#g#U?IZ7RoSTVHg0q zhAbRy#lxTlb1-aiw<}!Q{n}k(Kyp9Tl_2oL?-V2(u^t^BBC{JFVg}5T=PfyYnZF`Y z4eMc_?Z>X}x8dC9%F{@V1{YCp2RXO8H?wW_h&HQ~|}Qul&b>zeVglv{c@ z)r$11+FkBNB2|?WVpTgP+z&t+4o7{%a#?kc>bDJ(&F825Q?b|)Kf*%*PvK36XpZLX zJK@*J&1c(672BLP|3l;@pV(;Q9Q6gaIljbKz5bGzb@$db{wjI70-Sh4qkZeSNh0Ov zhZ@Il(E9c2khoK-7pM;p2vVI9ysDQyWMX)^_jrd9pf57Y@;XM_Z z9Equu>ASeoxEILR{ty*>MigbH9<#gsq$Ym>#TSDe^3o5epVuqvbS9;&y5R7lKRjM) zYqHIAU)ThOha5#-Hrzpym(Z~8XJ1N{+g;_S&a62=>xUlu;MJ{o?u3UF9339wup1sC z^&L1OJR}1AAioX|LEURZCU0j9s!NErKlL@!+Ak|Q?&N}VD)>Q?2cSnJht#7DLw>ATm*zlaR>o=LyX-t-(Bqb8S}$Y| z@WETEXz4c@%0TLpFqD}!jhs5K!k?ml`XE*VS;?1&m!l=?HTM^q+gpwWL(H!=A{$Y*z~sFeCW@_Bts;oI&(7 zIh^slf6(b>Ux_eGd@ZW8!e^8HcLeGG?D}iyGmn<#uVzo%&6<-aw+pfzIn=~z;jysM~qDp9E=0;&kbXgkYGp;x^$SG*LjCmyo9{{d!t$&x)@y<^R<_oDF>dq! z6@rv^B@tf(L-ooA?A)~sj#f|niaE`{N|5r*&@u(CQawsMH!xAb(snZ)u&4z!Nk0_$ zz!3`ksa-MO5b%Gr{u+8qry!JhQ~6AFQ$l{<{PDXkSSi&-5IZj=U>>XG!Z`v1Z@d$) zHdcd9LrYF&HdHD8HGY&Ux=UK2xn|(}s+6*R2i)sih*1O*r-}zckLbUyvH;zzJN)P% z%9%BwhFBZUd(6LAjINOL%E#F%Srjmd*AdE1g#UOdlJ4q&06hau)$|i(TjCnZzs-*V zQ*JgaJ2>?>^k~AgrQky$(`xIn#q7sw?B$umR--?pfk!Lv zn~>Gl&}BV~V0FeAa!d20qt6%3NPOVJy8GL+ zCtAl*-L7zYQe!&WTfv=7xIiK+`cv2Cv}al(HN1TRGLJAxW%X-i5OjN>nVR4-Y6!Eu zX(#;vl~-+r8wux(Hah7JnWPWHhZr3H<|=8#F8xG^sK?AOkUf|`!wmTrciyiQ^2JFA zzP@KQ`=cwxMOsaEE=7@7;1E;PGkD;; zMZTGkkVps0Rf{MQzx0JhlF`}a&mqtL;+xrdKi84(2h=BgM)A~qmUWAeU_+m5$<6}{ z6C=X1tG?#pk9TBl;NWQD1TNv)lU3w6S#o zw*=sbfv2SoYd1h2mMVB8a;*GVcTEj~9?QYR3=W24xPt$p#S=?ua>>+cc`fuo6#Fq9 zI{rC(@L%kAlkE^8mxrLClg;Mpi^oG2Hxettd}w2KT)IF1H0dCp@A2bdtZPXd#HU?H zTvKzN_sLK{(Czu>`Ek}!I;#%fC{kNWH>tKoYkxHCwh@f~L;N^)KMJ05%J4_Vd(|vy zN)Bh;IF)!0@Z+de=9a3LD-^C%N~%Xo7Eg#I$2>a3kLy>Av|OEAo;o%aT0Dxaz{m>c zMEUFdIL6e4C|DhO0^0ow*{KKTrlVK7^A6v`q?Gz@-C?EB`qs^;L|l)HibXn}aeyCh zmr`EH^D8MSg7(=fo=V^6x)3eMkNP z2ZCRA3UZ$cS6A(eZ60R6eE1sOFZ%uL3*NF|z5T4Q zNc$@3fFEbR_}hx70K+lQcSIy!n1gbzXT!lp31mImpR^nWw>$N$^E{`Eo=%^;k-2<2 zW!1D5WIy0$a2qF(7=IN!F-g;qVd3o};8e$mCqAz32YO--_;J`>u4}poIsuI&$|GeZ ziCT0|6Gf2xb;uhPt@)eI`e&u4!ueYXO=m31Xa5yH&MfTFU}#9HRwpr6)yc>lm4wv8 z1U3wKHP)uuGQnpsFl|NEWm+2dhQmkhfFDQ7LH7hIwx3x;T~=+KSJFgE_A@smf2~NO zV7PJS_OS4vQZyl+f~>tps{sg*!CY)(7!9-vbK4GkME)*s&&u1D%?+ z38)=wpTZL-k;V*0WS$~*V&G|4wW*SWIEtGC@lr-}6(-U#+w=>l;hykeE^AwyD%f6T zwmG0`b=@>>BI{J@6N!s8COB58sw~3@8cbsYCle>QwKzRMq?pzF;&h@>1{qsX9TlQa ztLw;gPE_vy}gwkpYYNLJjIvlX= zf4g}FUGO=Jbi!#B62*ov7BM!2)uCi;Ong_uTDK=X4a--@N9iixUKNmM+>O@R25-@n zE$gS(-)``edCq#DT^g!8nR55x{#}LSecV@%m4o$Y`5_lfItN3=s zkp%wI(*L{Pz-5$MDYjaM7=f%dZ6PVaEqA8g zb``;=O8KbX%Ii2q{sZ-cMxEbPoBElmrs;FkdQ(&o-o|JT7Ywlsm(fUZ!M-%MkjpmVZB5#}_|8 zB8zq5Qb^%llc<%aLy>Z|TnD3dpp)OIbo&RTUqAVXX1YOyD*3#`th(ceiN^q1e@xUb z4oW^=;}_Tkpw9|+7+z#wl4)ww@vV@&m=olnMR|Sc4c)@G zU=oBH`pav*%xBxgs=N1VPXnRcfgjr4*&sw5VNC-Rtz?-e0$8dGc7VTR4&c;`MeUlR ztY0{+P1gGPV%=)p=uLzrDtPu9X93|G{g|v68&mv}1~YSCIHfyvJV zL*X+Itg4xUg$B!@wX>LEZ0A*)~i<=LuPc+I?jOa zRThjLI11i_Mr=eFw5xaJ3jwQC=0otrs;msqHlI^7(1D=DyLUB`8*r~1&Y$9~+OOXD0L12X5nCQ#+9qX) zWy_!ujtQu9%LOMLAnyWqlCTGg)_LJ7(gU)K<(xHlC^6B{p1!*RQqh47R^YE3f}1JF z`Y`hs?#J6!-r*d{RCjjj+j0K%{!#+5o5u42l+f0w_N+M>-q21`=)#$v%@Yn28rYRU z$h8CJ_*_l(?8=GGE>FusiwKhpIzmH`X*@10uHj#gF_q_sxWK>lbgawEv`kg)@X%Di zu;5oa3A!z2%ko0Q5839+&8N`Yq$B8Sakh$NVC6v4Ez)vef5PGVHh8dH1Pox|gsxM-xt&uO>{TkK={j}WtMT0eJ3 z>)`a_X7Pj5aDu<3?}X9m>5CN_=LM=Zc=S)l@z)79svXdGzEp>EcgWsIE9(hW?!9Oz zRmfzWd1&G-3H*clPG(Fl$?hPz#ZNUljSXLT<5)^Bo%$Vp`PcQG91~xi)X#TQ>bl%} z-{jCvGW#Ca390Xdn!LTN1JAP$4`jyoqAx{C zg*q~abDgO^P2QswHvKQjI|*GC6jrroX_Nrz6sA6I1`XMph`(Q7OWHjG(2a1xq%}fJIw~b<-VZ zooPpnW3x-+)sHgrpg(ZTALN}2YvQcgo#$3Y{i~R^m}hz6<{gm#0DFlUm0B{ERH4Hk z_+D>8bgx&8y6IUD{i1Ek6~tJ%s)FM?>zs0@a#8Q7&9D;SeV!3 z4sN_ST{PlgKA==35NEJ*d)11DzCV%INjqt~FWA30buT|eg@U2W?A>ZEJNM^|cD@j+ zC(6fd_CO3ZEf5^oAIfr-^a{zuON$G-9E}R@x2se)ys9{ zzBPv<>meO&a^?Ng;cwGiwbDq8^CuEB0H#waEq`K@j|0`uqV}==?Xgo0gL@<Ga?LRF)vG$LSMB?R$B$>jvE9n*2cRpinct+ZoKhtOFWw% z?MgfW9hKCD0L5f+Y5GX|Rmlv#hrpMVeS8Bw0^ih8>^g)1+lnjHqn+Za+?VN}XGxXU zWp81PBP4b#LVln{=nooCKet=7W6z8cv1^j`SmPW{yKjJOEAk9?B7`SYJcws zoy%!IlS}^OFn{HC`%;kPvtYZEZYS>FbG42@3Aa6afWH#TK7LP3f|Xnbcfq#}Aub>h z$pdanIuu@ReLBG1MO!r_IA*ah3g`Lr1sWM?cvcSb^6x)3?fb?c5D?FHp+Mf$7gh~9 zyu5J{|MV%!u@0_ns`OetF(svHh4SL}u3!#aPEmE>p>b^G%PT=81v~@v)uY zb1PdjGq8b;5wLTLPi4%S9HaH|TkUAk#V#Pez6hSx*4M3^;NWk0p#18)DMlLGGG4E( zg7ME$9FfvqB0nGs1pg}@M7^miLr>*nVYmwJ?BcphMEMfw z@Y87I2Rg{doyRBhR1SGf{jM!e`YINOr)WY=lg0r)?zp!X+D-d{IMuJvVcuH~s_?>N zp!WZ-@^K`0inVZ5e6!yui#A?dFP_9Hv3quakF%f~6yrUYP^r@1LU~u018iMcM#UvUC6D_KtJvyj_88-= zsq`#=)m%l^t`cSSA|d;?1Z48@_xHT9yEaHnKLNK^Z<7PJnu z+;KwlU>sw|dQeZU(GQB;>OPA<;}708{DI3007OU}+v4?zm&ToSvaZ_np?=$31xteV zZC5n4tn!fLcN~wys{IJvMB&!h#eq9IRS6K6uU(T4yu_NMY5OQzuSfne{peiNi=Bns z!{wIz@6onfNZ?Pkym;0Sg3yD@&YeD$zrnNG9FvE*SHO1OkMF;33hS0%&+-D z1U+@nJ_Yy);378VvKcf^ojs-%Yk6!S)Ux`*$HTb1)P4Nc4DH+ODKZ16IT->)cR>QF z9R`rb2}I^9gPQ?m@sXfK|Urfa^2a%GbIr8SL!(4fi~9c^QY_I{ifEM>2qWx&qo=WNv!uxwZyN zlt&E%W7rvi`Xz0x2dF;hY4diGIRF7{3*4TO7r{JF6@}5k#SDTJuRW#S%yR*XT_JiZoRP`?wsN zbD&f11J<>1F0cOckiwrx-N2iVk1fAdip*v zXQDxqia0XZPh&6GZyO_jMcyNZ%BT}}M6ZMlx=Gz1>?KcRW8wt)$Z;;3B4eHO)76ip z&raD*d`T|5gZLTjr%S%l9i=`-VKyJo^o5W1HQtoc)kDDioa1qpq-wF_^;CDAbYjJG z;0|Yq5Dc`8n8<{nVQ2>omtykSJ=+TJg;hVVCvl!CXf-OkOa-{y~9^G6X zBQl(HG{NH;hRBH1$Wj3fAsMC~lXo6JvkT45;Sno) zLc^VgfbUl4fv_ApB`n&`bNZA&YP`zuohwd{A}W~cXpymgP@O=2KN71^zOLRX=)2mO z4i-VZs_tD_t_U2dD%exM{=#+zehyj%usZLTnL{udK%9Cd*qkV+yzNSrSzPD>gXz;N zh2Z_g?_5{F(xu?@qCP}ZhWIaR7Qc?JBz9=u{zA-Vo@Xi1Ca zOMiU63(;3NPWQa6J}HATy5qWHCf`-Q9>FV~LL%}Nl3?@=Lrs_zoLnG7b* zrmE|Brl~}uoK3IyM#7a}^~P`B&Oz+v1oX!OgJ8z3#&IzWJD}2(8igWJna1 zz?cx?$nF=3BfDR!Xvu#Rm9Q+fP~7WLpr#aa-pNe>EPm!ctMqt*>a3P~W{&557!5weQsbf~?X89$0`f9!f=}}*(sBw62diTOfsYqe zPrQm*B-NlQiOa?K7CU{)lXbtxWC1j3k}2c4>NweF@srxu3&FE3($g2u?k;4LC~`eP zeMbCA&rCsVSN8XYO7h|CS@bO{q7u09;lxVhf*!$7J3(!`e?V`xfr>z^K)$L7~!+X-^Lcz}!Yp`bw3{1f`9GCmUGh5F6h zyh!Xaz@yF5#14~09lW`2co^c*M_4_0-ueOJikl<*Jzp!+#N6Y$JXoA1@}8s zh}L?kkYnq9O@dX2_*EEyee!kdsJ{+ZXlk)mQ)6zx;D;7#L!(MTsEntFt&0b;2bKvtO z-rIPqm&w@Fn>PLBhnUXP)pP8?G#Oy{;mdg1a~)f(jwk7wt)@0IlGN)DCnP=&BQ+2; zP^Yt0kP4q5(<8$ph&A4ws+#VhCiR8+j>(xujYpaT*6AuvlN%7ZD$n<%`%_hEmOKVV zya8?@g0|*CNV;ubC0#z4kVv|ZsjL9ZoUi8tW(=>X1CsI!3Cks>9QgrX*brVP+%vn*p zuhW~+vieG0x2|j6UML=c9K2G8$iI3xl2xOaj>S3|`Znz+-UmYOC3Z z6ZstNyQT}B^VDW)ryMqy`2UuW_=ep;_KUh>i{@4?qI2cT25lF~#$G}qbW=oRV_a4! z8tP(+=XdEH-nwy%r%wbKI6i0+OcY`fI2e!!Y}2BW1r1|Vi^2vp zogg^SCfW>?pYX>h0tnt1V-dR;)mAKIC1<;)?(?>8t?V!_i3Sja)@XPIk1cLc=vz?V zI_Xd9$1%8@kO&U>B>=s&5smJhri>vHuJl-}I86?fe5JtO5hD7`xpc>1u=;bwDL!^Gj zN+c%D8dLRj8*)l&1hvyIOlg}}kukhO^~pnia4>Sczxq4q;16`2B{>k@PA_uHM*4l})lm+Nn$kiEQidOsrZCD567 zd+KHd>uCzEoX^+sLM%9WhryO)=rblESVEMHcP6IA%gdaF@EA~6UYltvvZqOLrbf9y_DR@jw|pdjDdxo%aq zupK=lgR=NAH2HWDIW1cj{&8#k^iQ3J-N&%|_aYJ{p%L7{_Dbx<_;`1(V#ImX@Vf@X zt0MLy5}!pKKPEHtoXp-F%X3V+gQYxz#ELiMIxB>3*q=k^L72tit zUTsOa6HeUAn(H*PH4`(H=hnWw7b=K6FfFwXe97Brs4y>EBevp67MhSVPW{;X-OjX> zkPw`f-s21#a)mk++Pr)9eVJPolaIt$XBXAT@BnfuUPWvVm4ciJlv;^VTd~X4dt-M{ zjafBN$4h;hEBULc>Wfz%T}p6>NErng_>QdLhOi7^@GI_$?|B4Cp~#f|g)P9F=%h+H z@(2bWn>3Lx_WHvtEm=IKFykZ#I6~Vezmgd($l&}Uuh@a&lb)Dl1AbX+^POC*b2YwX zP*$Y_=dsyct?;!Pnv=~oQVHbvCRS;(Tn&HyJpQ|R#n#xV66GsvDlb};bEOqOiO?~y z&Lhv`|5x*hL%wz&C)PcaG~6m^CW1Q``-YOTZ}&9buMhjj^NLASzC3!{-HutsI@YW~ zn?UH1x#oM|H2z~=v4mP07Tep&8(m?zN-Ykk-cH2DGsx5UKaf}KLBSpxdYeCvu9m!N zws}nUqd}PWkGx_4a((i3GU_!iYe;OV7nC% zRs@^5x~2%spW^+(XY^wXXaW2#t=O{9S>iDw3=x#fQ2!uHl?k6(Tw!+%X#A(NVqmU~CDEM?9N-3q3RkZ)xW@A0BEOV<; zm%Ij9uJy^od4Q}O((APn-$_5ncX`tm50$tQh`-#0Z&%DOP2-qIIuFJ`@%5P7ckLFm2}!$ z%=_ygV|LbWRpM7LKeDTBED)6f0xJ=tLmqPrd%$ei+jB71SvB zVsTS&bTmwpi1XPSgCqCDmzi1n@B$UgI(Il9^>Iwz$~RB7h5zmSa1UP!PlP)}5FO%k zS)4uh3=NtHWc}y$_u?=_gwVNt$TF34PSF55`_Zq6w2Z2VZBakZg4Z+6c$}1ssgRq zXpj?ldfUuIS#{(PBxMc9DLT7oNMz#}Jj_g3P!b_pc0 z_u@kAYX#^{eRnH|)s)cdVyz37cR^zBr(dG-E`t74J?>;vak)!6eE!_EO$MvO#NK%m zYxnPiE7f|cDlBY#DXoI>>~nw7F2TiN!79e=Mw0bL)^WTH8?a%ot|Px!@`PKAxH!@t>^S zk#-5iy%foR%r5b^Zzi+5X6|uZ{j8mYNP*FOG^*l3y998AU4rodrDp&f;g?`LOzFV@ zg51FLrSOx&8DbY6aHq&N-LSiIY)@(!z)QUW6F%Lt6!EbPke51lF{mW(FZv|_?n1dcFFknfH(LBmAdJwCzJM`gV9_Y4y-JLqsr)3+YWbgoY? zSLJ$?jM0=IlvLC1s0n{-nE)W&ow`jK=nY~;51TYqK3^$NO;sO;SWAMI2_PWFoNURB zbJg9qXP$?I3YI|mfZ+!h_zTO#J{S1msL^FT3`qq7%1>=(Er{Z@5k|FP)?4Fjg$tc( z2sxQO!-S|2hH62dUu`n3HIqj)?XhhRE0ERxD~1VR1S%^1?db#6JT?g8Sfr^Z{ldp9 zdpuw}P)<|sFC`Rp)>)tx{brek1#jL=N7XN;w{tere_jl_W1XFA7 zXiO>ERZ0BWFd>j1)aPgNU{zqfor)VvrIptrsde8lu|om=aq+XFMo?3PQ|F#r#!^Qa? z(@YLnVe;UwzK6-6f&E1X^2o#A#`EO1YbFPkoNn{Q3qUK*AS>U;Tjg~|cZ-@0<`}T~ zY`-L02{aP<}k-PZz&Sb4E#O_R^r_4doh_Z^y&k=J8)-s~wBsb{gycKgzYOq@FC8M7I| z^s;&{={yg5kg)G6i4nMyEbJBwgluAr|(Q1-w=diD6QM#&=F8{``@Ro&_{ zIzLK&Ikb=`NA9^?Yw7$HPmT~v8h@iY1W)!jIB#BiHVxGe6;2K z0+I7_{5_FO{2QpJ={Y^AG2o6S)&_8KI$&m`_7%g^cN&1r^f|cJhesICIL&wevz`AB z1NjW}^S{M}kcPjl_sm;e=PsP}Xb}CP5KR5@&Cl_+gq@w0E2!8+iIwwmg1x1&jGL|f z>`HeYz0V)@1?MmtEkq5J_|=hQ-r;XI%v!u3Z6UFM_1f4}IjV{d#XtfE0}@k$`Pt66 zkPUF1^MCOEIkQVm#xPj0ZVU(iE{@VWyqam)_moLsId$iT2A^}5R22-}%F5Qr0Q4BI z2KvyISL;($D%}>Uqz{Uboni+ik5~>42Cha1j!xjHD5=h<{Vg}u6Y+$x3wRyJCpT~L z+!)4S0KIFic$E>&M6azCO)i|$ob75LZNKJ)phw67o-7}mwl%kJ&Qa286AQ#%Q?a4E z3J#O44V=u+!7Kq2?p}77tRo4%EV-?i8Gtc%FXq*bWWn0b%H+lwBZwVU(_L*LhvzPz zg02qVT<_9LiI%UT!*qZeeVT^|^r3^W3`nZJjLedthv04u0VK zl#%2!d9w?7#+wGC-EOS8U0Tp#6qtArpoTurJsvCnnyxM-Xe**YQ$}wH2Sm}}^|TSE zC7`(ut58#8QZVxM*<>}p3zO@ouGzUcAcC10LA;=S8aLcGge#rd3~hO?7Uicd)gi>O z;5NHdl8uBA@J;ahgB-t}qDb$?TQl+g*VyLXo&gURD=P_7Y7$_K$!4Q*TUzf0+k*z% zTHGfE5z_n!T2gB;I^m2tB%L<+tifHkym6egN0{Sl1h5xIAHg?fV(n-m4hQ%$I6~tP zmW#>XI_WM~3k@klSivYea<~oL>5PG+HKhD&2z}Z2%Qgz!ZM48mfl?8TXyPh5h%Jl` z#nypZ1Q=iU;7nu{Se}L%J-8-l?Dxj#iX(y!)z;7gmII(^Q+Rfnoh&mfSABeUgzm+o zzIG>YwNOlq#Djs$xz;a7YLkO8g#eFrWzSCv3^?5gS~Pn{TL*C(z()OgM52BR^_+Y4 zw};NyTcyA-JBWZJd;sdLvca%Ug@Lr?*I%IAh1QvNw2R=V&(Q_$WF#R5%pdb3$BmbM zx^>ad_r=imGG$wc^xh=U$OQHRK##rEM9CTWoM{UM&#Z3X&8d$iYRLVx_xMvk0`BM6 zXb|{}ZZ^%d?Qr2W>ib{Q$5F&c%^DHN9eu_O{N9+^fU0Q7FZltf3o4h?6eKk+DX7Su zu{MS%B}Ro35K(8aF38Eh5wng(D_9|Y`R`;m;PqX`FCl)fsrvo&BdG~1;Z-MrQwX}l zyxad#-iKVfexlOr8e^+B-fS?R|IL~e+R^=U@AZWtYX71$Eha)^nQ>KJXs%`4E{D&( zKkzXQk9md7b4H_?20uY20eq+?3`IQJgP_ARjM8uKoQcr>r2JEU(aMO7iMa+4eK z+0OZQ%5!dz7A?2=V+&R=o-N;ZlfEhJN5jck$P0W>AJjb98m$+;BpQcu=d?Z6Eg{;c zv6uz_WB7+BV~$p0tEEdTbgt{`&(r!Vp2W!h_xK0W)15kume&g$Sx1P2RzC%l-|W>m zz&}_v`rzIG^8iaii1DsT5seSpTd115~5g zfe$rzhCAk_0(&h^cnD2Fb9FF^(J%8FWRQ6cjCHGys}I$jS_W`l1v&yNp^=Y`4-pU* z__$;v^~P>CJ-oS}psmrLbWQyKL_mOgY{`A?kUj8cih+4d;G$ekYrP(u0ve@5!KDHG zRr_6vVGz_~tKJY&OrZjs0GDN_XdSG*EXIr;jj8nNr@D8Er+7|}>yA%T;>oI3G!+uVmux&${SA*H&THKrBgR{sZDTaN)G;L+9 z*ns-dmmoChvC`1|q0QWIZ0a;CMsAyifRKXwrox|CMUlzsxXXAH(&dtI4ET_UPaC z%MN1)O6w)}7zX&!Vk2fyZ1mem29RO+Ue{&lqWPF~8e^%t?%DYq539tgfnA0{`Zu8r zfFi&0?QXoh&6nTt#SIni9gn!q*@$Eq2Cl4UFAhiOlQb*6>0Xup((3AO_LE_t`;9nS z;*XgO)psg|-)^*}0?hMLU8OWS_T@`Yz)S{92C#ktSZY+$>`@Fk&|1q>RlJijC&X4FO!=AXr2HUw z!;oK7403xELz`Di+LWtASCLViJj*qEj=*>~&niRT3_$c9bJt}I#CZIt!NU6-5+j!g z2y+gojGQA+>z1R1JbGEJ(!&JsEwXhosQfjG0jiaGYWS;*dUS>C=k-V2rxQ(6vg?vT zhJgb(LON}Lkl52sa~!Rm-Z{yeDv;;--aIFWm@&!3?uvPu>;d#PG})?l!gm4~n;8YKBAzwpn_bMV^lnBI`#hN|(x&!|YCPN#LzIPT*tw>RUc zFNUfISp;~jd>-+QF8Dq=eHdq5eDiKS<}D@7N)MB#@6>(4+FPZc56p9(k4|@F#-96- zRc|?pmcqyM<{PdLa=~{Wn|=gh?fOYQlgnj9l5E{bZu1KW##5W;I26A5=l!JrH|3#4 zFPBqqvpBS)N9LsInmIv+3gFg%-B0?2tKn7kcQqS}%bRj9ngaR*zp6bv>?i$09$LVq z%{-;6?yU{C^@Q>}&TO%ZXj1(E)`Gp(M3~{BCk0}s=C%~67Sez>x`)0E;C`$@{$OuE z3NkFxk8b#03EvvM(AnQq*_SzS5Csq^rDY$>!Rsf+T`dLt;)`JOiYc6|?j)PeoTL~36i*i;iuu5u|UA**tW|MYcF z_>xQ;H{O*iwDo&^(dDY2H&Er^X2Y=i8Vq^Jw&w{Igq5sl;6hMF8x`_UIdp^M`U+k6LCf7+tY2=^~Ew2iE_O^N)8CIdPGSC?_LlZ;I)lPO{Y>U#{9; ze-y0`2B!q&aJ*%LUld8dr>N>~s64#>f0%#B^y}k zw&gE6+3&FR%^&mo7EaU>dX#xnAo6_Y}$REhu{u3_q}V zP)rpgOs8ufaI0Ny>#+atH~J!Q{&Pd_+}CJ+pOobu!{Gbh0@!nXTpj;6|6gWHAc+Hs zoUp0u-?<2Hh zu<9J%rSOVD3XkhFiqL?W;=7TD@yFE)v*wHvum+G6o-`2oA#?8eryNh>ticw~C#lTj zTeBF4DLfO_FKfc)86NR1S3lb02NYjcDwjSGsqidF@M+5@ZS!l6epggQqh%Uz8ZUsM zsyVw99s%UxMI+|(b(51(ann;}loe=p&MvU}$#i2RqH0RuFGtT~*!`tagprNC-1Cvu#fh@OrrEHQX&q8vH zxaT8B$d%RAefP|LfVxnI1$AU=0WEcINJ*ph+!HP1bFA7A~J6agL~PFe_MBO5)% zQyzWa?n6=_U_5f|Ld9}&AnFQ9y1sH5x3`AjuB^;+33^Uq~85y9wm%>V1vwS@UWzGl0o}1rR7AxW-%YumMIT>KVXYt5hFq zX$pQ*9c+zE9K|<*cc{1B+&(w0->wA=p71(-Z3gqMe{gXYfN3oEM2*XoGgB(twz{nl zo`=}F`<~jz8t5fZuzvsk;X5|YPaO0%?$RaoA8_{6K47RNwH17w?*k=gct3D{M0=vT zu%dQjmvN&4=VVvGc1h!F`pjQW+)f>{l-d&Qkk3ZQ?d24JL~zyFs&7$PLQ3!W&sUw& zjZ{>=%~G=GD1iK$aI^bu25Jd#GV%kim=MuYn>&T-Ewi|#!A{THJM3W5@8~wAz}GxQ zXEnFmw)|k(RN8_mx33fpgH>E%prB`ZgoT%l5s#Z_sUp+ao0|4RG|>Tb-yv(-C zw@wQ-TAEE3y|d~(cCqvs)dk*wHnZgl}1nLC-n3;|rP=1Z`k zuhMJs)+c#W=f?JhXHQ4Ro$~P zCZI#0{Gprame1;rxsQBD*+YICk+^h`G1k2%$eT9id|GH<3iF=1PY9Syv?6h-Kj!8t z?D;aRL5cc8G|L0Tj=3)hNH^n8x$(*Q_L>bDES=0J0RLtf^$&BO*XsG@?$?*2TqgN_ zJEdK8a;8y!@I8CyY*PvHyxqIMxS0SQ_KQ57&yV+=;PbojHf7oS{}10^;FDnZ_k1nY z*+Se?4RR;DWN$YUeHaJ*;eP+m_ZRcX^#}9kKb-aq2o3gGVMtn#9H__FB8juRLdiFr z=5rL@QTrN&XT zL*A9^eXY>zl{EEbmP2$OAI~ymzrw`?@eYcOF?etqEV4u^ptVas6kx-3=;LPwmnVQ$JEa-$=X&yzuD?KvK z;sanvqP8(Xk87jw#-Q? ze&VpL--S;>kC>&_D($tahEso#+&n6Ls|S9b$03 z1I;Cq$BeHM*27`H$)7@zLxJ0Z0aOuJJ93`9BbZaWpr_Rc8PyqYu{Q!gitKk#sCPuM z75h%6Lq4Fa`k9m}wo!zKR(4)N+^WITCPrr`(_sUIeTYF!l8M!?GB$UdTmqBpOG{H< z&;6XTmi%VQDhc@o>|-zmD_Bi|@QVfHcDf&1D`U1t)0g`>;;V()!5M2G!w48cWp>;C z#(6B;$KTj(&)-5kC+Dy|vuh#+L#U1_w`wfdD_~Ux5nqj(8<*b;|9se-f3j)}Uhy-M zrIUN@R_6a^2-OITJyg$0FY8otS>cDV(~amFkxgKZ@~*beU>)GKRu38)ye7QmyiQ#* zFp{7+d-cIi3>A~_?_;QBJ_F*gcM2%DiYs|TA2Zy8eA6$FtliwfbmmF_Mhq1aL_nHw zkx%#LH){fgc9A})Yy$$;cU^k?SSgs?{|k7|$;T$lcrHlTjd7N?Nwvk4)R7c2`jfBx z{XCTvmMeYVnw+nh#T(I=(QH@kU#xwAul(cu=IxW|(Y}kc*Hde(XFY^QNOheUFYfbN zc+?Ltw=O@RYn`vNq`#ICE_ksb=U>8el+0q)xlIxxcWuu)cW_)zlk;x;Q7E>%@J%tu z_21Q}K?eIcUVgd0dH&T2ChCFH-Y3Q}p~K19NIZA#+D_!^u3Xa?(m3TmF~T-^XN{~{ z6uZwr7e(L>zA2|CBlZs!8@Q7@XDf?Gy@m5B-kT<#b1b2M@NGczXTLz%dOCd4h*9=p z+gT<)+D~HhOQDlhG#E~{)^H<7kSP+(-KMcgYfCaB61JMDbz-Ut?!JVe`^j?EjDg7k3HnQy;+&bsll7qD9+j9TG19@&p7mB68aE&vMCY!^u^;vD`<`?t?xVKzHp) z&dY*{?<{6@_d6>yFTLMf69qvZ#HlI|=t$RfYrh%GQR30eQkSRtEnb!|9K1gSRlhcH zJ1~5b!A?wXu8!GUsb?{pc|Gk^aR^~h6+N2m4KRq7h9EXw6L9_?&Y# z)*~cZ)bH|BTz6*9VjjVJhpgzw^zcZU2Eg}DfX*n zC9xM9!CHEHR8UO}1{_>ze3PJ6u##B&=&kXiv6YK&Hyo?{v5de}EC&N4Cka!a<~`oi zQtfX4Y5nf4RBMz|vdLX1;Za(OmS3Hj<@d3k1n`BU zsNT?F*|;fRjN2m}4%5~biu{4~hykKB>Is2C=rl?#UCFtXGxrOebOykj0Vh{G6PN{% z?Zb|z^C@S;-jxqmq--<|YnWZ}M}ld2-TON|)vVi#{B|Tfn1*SevNf)QutJgq{Ef}5 zpsj2xz^0YA`iZ4ky0`l7%;$`qkGq#(ippZLF?_9sBot@8qMV)tXbXB@QpEt`!1f&+ zcpm!FDbnOkFKus1WX}BNxJaES2d6~DaXua%n2C*%tufrj4CVktpQV@n{8(<~+cA6Y z>u)~XWPNj?6`>?01>(Gi7NkSu&%f)}mD*at9|uPWnV%Fx;=E^o2)kvxb{4&RQF$m6 zgw=QQOdaP!6)iTHLFxpzwb>0Jb;$2LcH=Wg*rq<#nt^jQt(SZ$!vV%Dj;oXD#gnwl zFLnBYxTUOei^E=ledx3#7!Gh7M^Fi-2tc(;RmNi`W;ZbvFFxb`o+`l0Zc_zTCzv?U zhDtgBGqhQyw^gt%f2TKenuCqM;XYY=8bOa{Wouw;7zG4~5a*cr@oZnsYH#9DW{pql z!y*U4+yDsXEP;+o`Yz#<&)v7_)31++V~9I{vgN6w-tpGKfR{7HFdRm|%f{5S*`GW$ ztc>H(k-|46YHP^?Ku%s(6(bs*hAm))qg7M%%n4dlmR&l{4)Cv@jW)_tagkXnWq#lJ zxi-^aQyLUJ?;*6r2m$2t|mU=QdD8Tk{Rj z85|eux1gK6;u(?{y~VtT#=vi&gmQEeczD39S^UoHyv`82X{Zn*fI_?DWR!C3C6Y>$u?4o0 zRk?Yn8o!*da?i5dbX7{;Bzv%j#-e~>v1865ai6>ISxK{bxx$Bh0zCTn(3mVhr=`y- zyP~3yzVZHs702TX>(RF8AcT?q3dHNZyYSlT(|KF<#m+JI`)}w5gEIEfSUy-Zw3cgQ z{pwC@?Ji`F`fUURd zGYtCMh1wQ2(J!&@S5;;)hQjy2m`oIOuCUkX6B;FLO5mH^q>_zs3;1RDTM&$)fMK8` z@bm=h=|IQ?8}Bj{l~XP;c#&Wn3C0HH4Tw;@8q_wg;VLPL-l!I~QeYT|Fv23B@7+gT z)UJ#Px_!E7hpD~MXZ-q7?KgTR#zOG+h5J%(l)0eM8V(w?x})S(b#O9a!xhjyoJ<`Z zjm-e#O4D?$BFuZe)nXss*2uk@CZ2-t(`-Y4=PjMEsF$NYe6NzkA*0xICW1v@U`#B1 z5KGfOfCBv$txnYy7cXAlv(h7ye0{}kEFj*pVi}T(1)fyTu1EHV3lOPArk;+&cwq~p z{sjKeKqO=-(}QdxORw^nLtx@4;B($(VP(uwC= z3Zvf#Re3S3g#))X}Xc ztjg~bWpe=T%ub3EOPTzPd{Kl+q&M%)@^iQM&T~}cd43E+oJip74G^Y*CI-y5d&b&C zdQff6cX8v7UZ5b(BRcwngBsE;&dEa>de8hx*!=g0X{Rb>wzJev(VaXgz|T)_h;Yz= zrXE@x)UeB^oE*PS!rO%!zMSQ7MG3h6V1m@77IKt4qqJT>NI*WJi0KnL#$%>r&n;Pu@xpKX%SMW^;CwETjZXiYwoGO| z_U$z)dfCOpiIj6z?IOv|^^ZhM-{%J1oY!k#%i=>OQigeIKE7(!wB0|vxz-q+*j$Z@ z@)*v5vAdG81!2x#M^Xv~*o~Eccij{z!ICR9GuiO&GSE7_ladD_)Ls|eId}O2jMCH_ zUu!tDi&1QPmn_+jq-?=}WMUR0S6&iOP=p?2Fa+jlne@K-IOCPVk&x6{2)u70i-b( zj`4>umvFq?cq1{(ZN0AWVC|0+DS?}fie?SC-?i+OIQnVA@B{jsz%26MnKaJ)!+7sLc- zXK^9$=V>xp9-(^-7{#H1!Iwoe5sF+Zvy7gXN>*MWLKR`o<*Lg#=!Ehrgqe|GNE=n4<%ilsst1z z;{wEa`j?TE2$gs=xU~9JB;_#S^iEJzEy~$)^~6eba|sLahtCmA%&#LU8@So}O!BJi zRiCYwbc%|s`(?kHN6;6DNXiW}3iLYxb)}ISX`G8M=$=T`KLLrw{RHj58A&NEZ3`BE znXR9;_|&?DvVQz~PC~8Jk4Q>jb(^uVWaC||-t?A+82TJEjYGQ=u0+3^NeTT)CS@aw zMzp22Laer+E^*LLP|Bd11*$WRP1QWY#YDF&!G_@j=uyodR@IuDl=f-Dn z_axL8h_jlcNWy+3VSO2Xy4Dl-{Id{LKp!ZM+!n|0IsU~Tn_Ov)egHP{alg9^J#X|LX7S2B*K^P(cYxGJflZN z=XYxFME)zEG%oLPcyw?Og}QaNtXJK$$oK{S`WaElSy=f{~jN)ybGW>+LW0*^y9D)B;SFA zJ{(@(36E_&h{$be2so*`W_=Q^WDs@=#)$0%LS1lLbF_B^`&&`{sBYhxf{%GvP)GNo zulgr=hGf9lf3Ou67pm%Acw`-K8IH@$70pBnb9AhMXPM>h5{f>_*$DqE-)8?qk{;}I zC;N^sHr{)DL@aQAK+~(-rsXxq#h!H1%_4~itJM)W3o6JrNJfxw-ZFHUVUVE{@s_hy zt>|7N*HC{Z5Jn<=wyb?ZCvq{gh&T_!SG4^oLH7S5yYe#}D)5+;$;&g>ZED?r}pI&Dgw?=mY<`b%8 zIoxqx(V1;YEuSo}c_azO2Z8QmNmhWo`NfSYl+|u)Fq~Dghg(^Rx{DdEhynWC?LfwW z1u$^Moj7?-Nt-28sS)RF9&adAVIIZ;0ud?tC_vOdh%ZRXTfwU@K;=fj^D9pDuFBxa zhOodPDy%Q4@hWIDxXIa0$s1#Q@s}~fca?xKp_m)f(*e#aMpAj9(ZsbT!to6aZ8z#; zh$vxnpr_h-chm>JvL{%ovLbAdhXQizA!CmU0kPb#J}}nZQQj~Vh+@RF!D~`-H7WW! z<5S$cS-1MW9318EfTO$(z}g%9q{xYR1T-0 zQ_WyH8F%AcSV0-S931%UZEFQw31XWn1u#aS6p0KF3Ym+gGF4B&8#CvkH9$MPy@|^% z11Kd2^xS1=w(za(AZ{G{c0)yf`&w637+9IKKkVBB1~pICE>h{F;nqILU2P}7ln|It z4<2YP&PFa~W?;=AbD++L1vjkt4#myS8TYE=Ya^U*wPf|;K z6oK7U7PD9T1zxjZwaCHPK^&q6q=XNhlQzdMz_?^+5hS+8obN;^y-x?k062aL;WJwP z>}!T>=I2rR7}!3C3L-&@6gv>fPA?SCwZz_;@ZyBgqqJAa4BP2QkRn41+}iOS4fr}X zPUvtl_!YG+sq59`2sjfuA{*NQydHUwbJX8siPNolY02I$g)4?Su0Dq`VK{-#Y(pDK z8=&e$+$QQt9e9h-&Y9w6pHQ!yX~}&sB4rC$q!Gm~j-gKm&qU8KF(^ahT1;&bU}Wmn zbD+~n23`@&8B4bADX2DkgM71F00Yi}?rdV{XigswJhWV0=Ixb=l<@MjQTi~bztd;& z76Bfnz)xr9Tfm$%8J(dtGX?GVY{hl^Knj`N^lb1$!uhZysqmsxBt5!jM~I}GS;&WP z6uZMcFrKK+G1cInQYPZo7s?v@#^)Wp4)H%GfN)MQF{WPKs7lcHOBS=;PBg%YXj{BKA zQ^5GJMe7P(%vDGAV)@7H0Fqs4-Y34qWIxeLFRlKtn(Os9Ew}VUf*@Fn+@{{`X9h{bQ&f)d1EB=mw zxrEr}d+Y&JfwNs=fZU*9;9V@uTLUz8EPmofdW7wb30N^}h7(^p=ey3JaB^~Tn(2fq zs*7(fNDuJs(gQop&?HRj=;m%Z)^mzV{XsnhZ2B-`6i-X(bwH_(?&4JWr0p$!))ndS z_s$=~-97hF#}h#D2}d18&gq5;r>M756sz$WOmQ2KW;Nvbw&%x4&%?V6V++=nBO&{C zH@~Nwhwa+`U4D#Piyg*s;ymRp!CaS(wvDe8nimTk>f1wwTUejJRITJfE3KI*T|Oh0 zmUQokALFaYcf9gcU21o`DpP;ysVLi`hUh={V{kdODP>6ZEs~dC!FyU3FHFPrw);Qj z$2cqg9+vGN5;=<(&lh3qz?qg-xhvAzTvx%&D+SQVBcW_ns4gGzD~BODGC8`eZ7>h??!GwMN>Kw zZXU|__&-MfkE;LUO0_yQL~T7yf8||rQFzE}Va~$+H20x}%w#d6A?n zlU(zGG&xime}1o>TA9|nF0>Uig<5YWYS}vHJk|g`dar#A@MUY3t2*(ayYl0u<>|J} z%7IIVx-C&Yt&kQz6DDY9Ec;lqSwU6I%d>iLuL&CWwG&+BI=1=(8L!DWGDRt>pRoPv}IFtL+nc-U7!>-FvuR0@J%Ykw`7lkKVIJ}>#n z#EhUaxgco(TZpLN^$1)0kM^_so8DEiBi_-e^_eUA*yTH#=E*R$zeZJr4hT8#+^Ov# zj2)fBL}8jqTYb+|qljU=JNkf#(UNR`3`5&&{Y~k`MnVf@JTB?KUemg^sZ?T+37~)mBbkqC@bNc+*Wr(BBKG4BrwBy~n6YSKJFJ)JjJKYasl|dA=chRZ~ zwi3_a@b!_0JzBLO(f72zWA~eGo{i+$VqcYaoAJ z&<^~hpnYnu1`-v5C}@vQ5i$5mCWo1)r&ei7y8f!icP8g|1?@`o2U5Jh=z(PYeGer1 zUr6!xiy-Ta`vi&IKUQvYzs53V|9pm_lyl*LUH(l$d%}*mqC<1t|t?>pQcY2czx zYk-&$v`a7@V?>j21SU=rGPY|@(2}KZls<7C0idt!KJ0FH#{kVmj*r~pCRvMxt3G#y zsL&%jSoQXMAb(TPp3V08SaGFfI>r)kj$jUe1e8|WUzyYNDnRmWm zdni}Vrkz*Ln`Lw#Meo!8^7n5vLH?wl-46Ule%S=s@obn8%T&xz+~|Y%*Oj+A)30)s z5rZS5ot@jD``bl^yxcS|b(1G0xgjscGRGly$RweY%$+qkz(Efk){g z)P$7_0&azWR|VM!64;C0-CSn#8WjrJ>I z;jO*y{Oyn1*##-Xa5$%4cNe4_m!fKII@dMqt+vZh%aa2C)pqtWzL4N+qfO$;x^Idv zeOdp+TOK{Vhfi6M_;jzIy-AcTKksZ-8q4=%hF%Ico>8m$|MTtTdYtLFg}9 z?v&O7Jatk4Z_NF9u}+jY$54Kh@+6n>C)Ur(bsh2j@yN@+|Ja<4{0p!@tM|CCtU=uH z?082&_IY{3<)NbQA8qN!(+ZFS%YR-Ec;lXTsc)poG!CB?w-`#aUE=%7^&fcFb1C}f zqMN2uoq!P$4!^tJXY5cikU9Pz)B|ET?}`3c{vpwy+20lYNdnO)BW(b`oKx`cPOMYm z(GBT$l~eyj^hfne(Vx`Uza#o1%uOP(5PQro=(7nwy^?Ad&~_K>U}un8`mN|MLE0~R z;~@=tt{LUe7J z&}p*qUgjkeJN6`hL-5%%Jd>4@RAKv|Q#ufU(_2;hWs9C!&rN~K`0Tv7KSN{rFS@@K zeT_s9X{{o9>(Y3Pp^Cffp+P8zBnLm&{V^{6k?zmx@9F-w#Lv4JniACF(kCW2L_XMT z;VP&5Q{5l*C%V7dV+fOm17N`!OO0-E`rD=`v3=a_9*27B=m^-k1KnRvg2XVhxR|o< zec{)Zjd@9}D>cUJR{mKe znWjLKBNg8|Vjdoj>IlZ!$wE8CIB_bT_AjXLi|bBHhKQb%604QDhS2@lF{@{iF&v*+ z=J+bYGYf5f+9G4VUjqIQ>i&SA=>Gb_Z{)9af2d%uCb${+#_;ka*X0Pu2PEke9v7-{ zs!#^BLFkuu9dL1?Bxfj8W){osDbcblJ9~dv_sgCGghH2n3PePXvMRXcn*o+;r=w zdO(;0#F-_U6(Us$O?&jRxZB+esK8FCJ|h5yUj0%(4gu8*2ua}ezmf!=+mi%Bex~2-cCqmHw zYf0eDe?=15jE6kW_x1tfPTggd-W7|1g;{4f-P>+&KkfVH@!kKXe5U`|eE>BMX`G6% z0$c0AO!1~E9;roOra z9?k#DoBj_yV^s1h^?HkFi>2!l~e&h|iO9sfqp(C6+2yumtOu`E3gP5`_79lQi(2(lVmMUO;MBqc%H%UKCfd^;2*MJTXBgc z`IzP3+At};Z!w`OJ`*lIfXt&w!d<_}oZY3SaCUIzyIby~=B`L3P>b;UJeqr(-maRP z9cz^;WM-e0K6nMYOT9j<{j~-vyjb%~Iebz2lKam`i(BCHdU4#^)&A}m;ND=7PR>!8 z_c(?#6P=H-;?qQVhu6;v*;?hD`))|UyzYudMo$2WOqeE4t8~?oJR0RF4J%8|B3ZFQ zzp3}$H~8P}utywab}cs-r#o2Z<`Q#KTnJ{NUM(-1al21FiBShWFx*F`#rX330) z4y*SF;}hmd|O{6SpMxnb!oYD7KRGO9{0*9w;w6}mr*sg0Q($D+G(2b#M%l` zf`5v1 zcWG+AJCV*5r=8g*+5YGh8|?azB6^k2x=F1jTPNE`yz>MIB80nUi7XB%Rx7AMt9OSx ze|P+#Ol({RrOk^MSDkAZc4MO>fKEc-&D;F`%2CPppO@VS3166ysO?g$CUU?lehSi2 zyidjsjRc*GWl`dWv-m0CLIhOWFiL`1HBvG9x-OQclg?*dw+$AxeKkgjqmZiKP~fIV z62^$*Lwmkuafg=rA^}p8S5Sn|X85m)=#i>l%OFv0zh}I-(_SwmNQFPUkUeaw-z%c8 z0AzT2pN;UI*Bm*gcgdpgkqpVLH-jKxmK*w2RL%BkyA)4?$IHHoe2s6DgH6PV=A6i= zn$HR5Z+nluFVV%H+L?J^vJuNTM+s`Ab`i6^T>0OMs=+{^f6DdRP)|_(R7rH^hFLp2 zYz&TQzqQ-#p$B?PWJppC{MNaZ-xhA10aR*KPm&=h)8Dk;YJilf6tPSr9mQ;Ec@bNN z0F{E6xJgY7Izsa+2c-3UbIbgcl)yvk{f@<;EvtM*L=OfgKs!p(0}^hM7N77o+(bwF zWX>keep&&r=8#b}$7n}8SU+ARxRx33F&_3ha9XHB3cPpr+Hd^X42_FIMvOL_Nq$SBG>cx#rWE}VVF9`XH9RE@7rZr)8&lFe&W%MRYh zFfn4R`x^G(wjLCRs?6QRr}+FfrQgNt*~UWVDRB*%paG{Ic$UTRY-svIW6mah@nftj zS~i*APl0Pn&%GY{zlf@7rbnK?p#NqF6;f4c9&?|5!6jotVmYfcTBP=rc*AYv@r%^w z65KhdR~z`y{Eg*jY#hlozW3;UcjyqO8^x|bx8)03=S2(PgLP7T_L8kZ(%oEcv{Sy4 zGF*tZm+)Gej8B$7C3-X>&ye$qMpz2&)V<~xU#y0L&(I!BsU z(}k>@iD$j43xRBYl9C+zN?lsXw}1lG`dA5z!}W`A$<6P@1{R-Qjqcok8=KXU@8=#r z?eb-zuNsx*r6}gP)7{ec;aO3n|98zV+-j>1TVl)4>?@eM04*nuSsj6whcp(y)ibF! zSSrFzvKO{H=|ms#9*g#|Ps;goe)^Hzh|2SuHo;4c&JF3$S}UFlKAt@~zxZ40=-i+3 z8+|9IBVSrMTt^ol1_la)vO&AkeAl9Y&?M{)2_>>~fju!7bd-W>r8uy15BTZ%W?t;- zGa3};tnO0&3S(+E@l*%(Dag+QLUghFYgfuExh0U4RmCgl*pXLSp zd;6usixuM}jw!&Pa>ZSj1ra@G@ zx+TZTL~DQUU`ni>;}BtPPdOt$?qOXwA-m+kb#(6dO}}(jdZdiOjjTr!7;5o)EcXH~ zlchdHzTvx%&2Z#XaDIG41Y!TElDwjBab@bv;JF&;m5UXU?0-w|l1<8!8I0baPc?Q8 zt=Q!OZ|iEu)Q|l@4~ak3YQo(o3!QG%A`e4cm;D3Pf6O4i>)ic>-6pa&NTb)B)OjV} zq)Pu4>k=(8Eua_>C8M~rL1A3dkyJMjWkBy@l!H>vY+;s4w%~LP%8mD~e%D^IF-sbIt!ptT2Z2!zak)|bokGy-vi@_+> zAq^v$Qg+*%BlC$gU_wtj?6G{|HTf%@7n`0dttbg{59!%a5ngyzbUSCT7VMfcVBt5* zmPwff*5S2>hcJAB(#YK4rDv5ImSjaoaZC@C)6G!hU=Jh5>cg1szmKbdI+>C*_Vrw?10%58Vs@Ey7nuaSEq}$0EBCZ`3?rC4vTeK+c;@`z8ZeMuue#j4Jkw))__T}l2`F5%; z?FU^~8`ayF>|+9LO^+X)kA9dSQo6k7?awSYoa=$nDH|m$gbxE%L zUcS}I5IFk|$E<**MGxdp)h`(ziyy4uu&&kR%S*WXEY*+^zKaiTb4`{2+%a z^33f*;i>0IU9X^BFFh}fy-4_Q9d=OY^M~RW+A5DZNN}Bjq=$PVm_!qKY2}atasN&ikh+nEtnXQLD^6i|IbFXT0FgRcPf<^ACfYo zNJGo0Yv&9*brPKDeyM)p5L1x6Z04yLLy~v-PPOi!!8$n`Vg&-KUx1;`XHQ^w=4se^ zQF=KvDOtAZX{UhoZDE?d_>gbfnJo|fDiD^A92U|vhW+xO^ zL%ATyr+|;)N7oIUcC5T6YO@us?e|$F;$*uCRGYh-k);PW@kD;)E?1J;CMfWY8tcY9hq;Bl2~76~(?djG+GzO~Qy*f`py zC}-Xl-eutnh^ys|9^R!|^Z!~V>sNrJS_{>aTa}=m*Su^T*V3b0BsvzY13;?Pcwa<& z_Yd0p&Y9YJZH=zh=$}{P6TaPQxa__1p72{w3Lqcc{*-DBGCQAfjknI9rkd0T<5idt(YS2t zKGkZmPqlJ>8sq)2Ae;6ywv_vm`3S7`Iw|h1(A5_Bd3)b3)jFz7KY&xUpssPXkyaef zfKzRJmhmvv3Vr{L?&|QUY-`FpG_y@IROzP`=Jn~w3?pMh;JnFz3xD_BF9cFl0(|R+>(qO)ojEMO&%)_0VC@x^9zTab8ub#tzb1eZPWN zfxBw@&|%LXHuB1g8$!k#-TaoOgDMB_4kwtJkB~bQ03x3Q?~r{JF|N2v(y-#wZl2Zt z3QXTcwD;u!7VV$XIkB(cmv^zHaUH~F<%I!vcMhE`tgr>T-~ zr9G$PZ_E4W-9ApVg%H8StIBHN(x+~G<`%vJ1|5a5BHYSqx|W1WWsgeIYCm(YaSsx0 zM31r~_}L*T6(Cm|Yb-vbSMC|wKpFj&&&+p;w^{#*;I#k#3gX275LX<=UGp_R9ObDl^&@JGr$7 z0_qz@p48sf`k?FpmkMkHvc~X5qcf&NFw9PLx3jS_&TNTr9HM6bf$}~L=+_d)66?zA zcvQ}(>vVO7DB46_;K9G`?n9jP%`wRHevdz54wb)N5TrhkKw{!Fo5Nx0lZ<{&FAN?jje9NVP1}pq;Ws-Y!est(hCzT0wZ0@ z@0uY3|C%@XmNpsB;)0rwYp!)chbsfMyG?-R5B{jhz!{x>AR3*vjr&bm# z@8<6_L{1pH43Vj%GZ5j@L9KqTS>lCbsF1RD?=5wrjv0_5D*HhZ0Y9OL)c3#}10Z(u zn0mfUC-Wnruk}-k-t>j9>;a@V>X#Ie6c|lQI;-|_AbcK&L;HzwtuyE65wXX}R0t~| z!+XBohn(s&t7s0%&46#8W>Iacm~^1BT~X+C$nK?DLOFk0G5o&)O5Ikkd@t4YpNkC-P*eIU?F$umC8 z5!K)`PhNa9)HlQ-vi4|RPkE$Y?CDXC2cerF-vF(#j`asc1T}VIc75Y;`%L|7Wg*jfLG+h-hPBnGwqP!X5>S$34Ed=2e|+>@9?%dnA!)(c^C_Mh*hKqBAzxGvUT=uVS+P zlqAwr_YtJzvcPvy*BZ>FV=AHOWUIH7YE6Dkemr$O`YuUCQ|@vdg@NAQ;F_i@hC=r<8rS1(`y`R0 z%mTSggi@cR1~VpCoOAd~4a%mtq zw1T-&HEsr#E%a$Xly_7(R_2+#v~tiR^;4E;Kdt<~%o0IwD^rIvoL1sktq(sl)VxJs z!0a;)DWjK%*#9L_qy(mwYf7MXT}n7XA9C*NnB)5R=C{#686;7(ea;_)Xf>389aqNm zJwHuX{!%#DslLDYm#_GlO{%HBxe$G9hg?v8Jis>o(nX0X<)IHrss zir6s0u=4T1JLuK-3C4v*!+I}IDVpRpod`r=N-(Va7nl-36ahLgx1f|{y^EFoo@O*z zij(tg=a>$HHMcKpun`kjM@BX}+hWq8nQRIS^6!C4K*p`AUTUP+r-wUi>y-fI2Z7e` zDDWj`85scH4S}DX)_U$nP+S`(`@p4wZ)68XkEDwHu875*S@8TeU)o696K!BNY3|s* zM-`FUg9S8J<>a>rbL)~r`8A)~@Z9~#W4F^lxyuwmF@-+Z8$PL9x@f}p#s;Ohrs^hb ztr*19lKdA@<@9sFuZW_3*wQ?Y#4n&fCXK-NYCRi^rN8(6-qEmp9umlvjHHmi(AV9@ zGCa#@V4UG(_jp45vl4?F+@YK6XLm3Y6p3H#fw6r)IX=ReffS^LatZ_Xcw-(4+b&h|A^R`?Eh9fbzJ(bu{9 zG@%W&9T(2EpCgq{Zj<5oSiEpZUso6@eU~ZT+{R1m2CYFLxlc?)kq=T|7ovRQtWsu_ zo_~Ey)CKe&vQ;iIo&$ZID0@8qx4St$mL6pa3ph8G*)v+^|CIFkd-}ScR>A$DzD^b{ zyVwJFy312<^0_rucUvNeI^wXt?hmTq{<8u*xbi`&reavI$9Pq3qEPOVe$~|{#>XN# za}EyZU+e1(`%F`nMa_7xv=F+Sk*BPr-*CY}>g)QS=-0yYftZ@b{|3GLyc9aoEowBDLjbY|P}R`E6;7T7sWp3J7{G+SFc?r`iQxy;+9 zHp_m*Vf(iPcF^aKOCvHLi8Z~t-;(M#{4D0o=tyJbU+e2&7N{<}U2uO#V264xRaEgK z-sD|pnLBd2I-GBNbOZlPUZQX6!a6juNycUrhUdd%y8* zE!F5n>~}%X36X6*8!tL|c8k>^{^qw1;|Uk#Yu&8#GXuxP!W$`lv`1UrC-?O~SIkd; zl{hw(9)Z)=fcb@(nEFgh-BJEVar!s*u#)MJ59ecIl~eLRGRx|>88 zaIvvpFxn_HYY}(p-YD%nqB*xs@m-{dP{&0Qj zzG$jw#;o>mLgQh(uWD`Y5Yd-^QV!zI;$1*^=JsHStK#X0M9JDJ&y6MjtQ;f}FJ2VB z)!VVKKKA-E#`G<&tB=qRr*;0a90U+%EqOUWHKKTo({iK~?yVL!^UN1SSs=HwUk)QsCA`kZP5VLxo-k98mz0v$u51 zF6eB*HxQ4EjJdp{B3FN1L7uznU%kMw(Cx8mGL+!-*r7lvR4t57IOUu`4FkA1ivsDD zX9+?VjxFUCoQce8hW42qTb<=3rdN=mKsQ6geu8db7)FgwsMqCQVzXBH>?3Yrm!Ly#VBjY$AaB9ZcP|(eYypAV z`t%glsxGkQpVt&JEqp6n zV9)6DAi7S`mx-b5*67a*J@!;BU^(4i7<(Bj8Q1_?n>?*zF=n46`CwH(N9AXjQ!{hO z$WN`&7est{Ft?5xd(j-V>={Vf^On8HPuck4af^lCx98bR?_ufNLri?`xgjVCYtWgW z>Z(+W;XeVi)De;jYm}tj-cpc7^EOtEFwite=!sR=z zdTRGdMMU*i;~xvvbRX1th#J?%N?NOucgsZcGwu^N%p+BkfsBPaf z6U+e#V%m}I9r(^d+lu0{Y=h4)Z=~MaJ6C_`Q_vyAfvCP6%QbZIUrF&_Pj}zIh||it zC*|IlhCE))Ozm7jCm$!I7}kxKI4c(WNaVOmLWFHLTBsI6{6R&(YZ-tLQ(aG^cs7Q$ zLLHKYC(Gkla`Wt~Q@&CdHulDbHm3A4z{R<~YC1LjN>g`d6sC8IIa$q;IWQ(PFbLTK z{Gmzpn$DbEgV&^6gUS&jLSZw_{G=d^0n=eubB3txIxg0V21wt2d5&d)Iq!2p=2I}T zAH4sa_JVAgfUn!nDPOlHc{CAA880d)b2oC`F#$h=s3xXn;1cF#CmzMv8C1;W;wXP# z8Abm)_Hpdst9z}1i3Y{y&p4TG6DUehoUF>#JY8!lGLFKyiy4`KlefM^jJaNk4^W>$ zi7x7$G$qoz1s>|CU)X%rys2y*>WRKQgmGba)M zM6~Dr6gh*nuPr$B7Axe zON9#|u0r+Ax+Fjk75wVp?c9;~Vv%rw2P3K>19^S^(C=||feV%HnM2&U>#Y|^@PO<% zmr%B&eh)>$oeq?Z69dT_dPQP%9JN983Wdl-c0zVL&7i2HvHL8X_dCu|eq|+#N(FaZ z`(BWcf6fc?2H^$y836oaFNl;B1kkH=Bodsx37jPLt#u=Fb-cYy-L-cs?Ec;?{^JSp zBLc`tb{=d6)@Ky&s(c82-<~mW>h>Lfe9%99WPkWaeRW4r={_j^u|NE0Fe$RH?iY|$ z4)D9{1OJ3IpjgqFw)CBR#0dlA%<4Z6N#C_*yuXFXvuQF)>4HB!?>g~(J@t?K>V6MN z)fsxr`yrwR{sc{-nR%4Uo)KYSvoS($t_Xb6+}V;{|0wl>p5<&@$!8cAk&xVf10+?6 ziO#ei_;C8{mtHLNs*1`B%QgD{2}qi;75#i^e(?$R%N9e4(ks}U=z{(K0g?jiG#S;C z=7me1c9*!x^2qb10`Bx4#M1~lQQyfZm#|wE3ajq%wh|-yDC@ny@&f^B`%U!T-UnaK zJvmh$5U>@P_-5+7>3=IAJ@*?x3h>h`XF!El*t5YjZ|N1Fl;7{`0U-TVE#2P%r1Epr zcvJcVQHwjOH%ttNrnk#)y*mU*DM{>xC#$vN8$z}iUHYxY`@V3&{!M_C(D~lkTN<`- zVqAi0UE8FqVaKEf{}hl?>Um0DH0RSGO*?y+UE+FDUJ^tzCzRO6J!aVX1_wDNOP*+Qp>5ESV$IpZ{)6(Sm{1^>hS%wRQtz zPk&|nb5M#T@P30zGu}KfHcLHm#cR>NjMDLOe(5bX^Lym^3+}&`iF^&-08~K8Ie)Ttl%9&%o0`M-HgI<^dC!UxA0_N51zNI`JM~TBqr-!wX1Uq%1g7uyeahu|{D!(d&i;tBv&! zUT1c^kx`s4xq)Cc{y5n?RlDqasaKGC>$ytCZ{&T8LpTH-v`+_2ZZz=DgNncXykju` zjj>_Ih^pyKX64OAr4mE^yo<(_>qu>n8DNbol_UEs6S5v+o*rkGxR#iv^7_d3Od61k z9@1!sMSt`qR)Oj!7~G53#5P1~dk)-R#b9|??pG*q_pRzkz~lq`3wig{6r5r-B318lZ#+k>MlcM4ZvgYuF^h^pkg^o1>k6L9f{ z`B}V2i3Vyfe>sr$ybCLdC%lyV8Fk^gcFqERtidg|Xz)0emI24r_Ym`?Tg3(s*R#Fy zESY6 z&iazw!(C~Q!XC9GZ~gRJwml|a`%OjpE7&l-8bybqf06d|io1LAWT%Z$iYji*&=4!( zgk!Y+2Wd}6rDuUf=tfMbf-`Qt&o$E-0^O&evLv~3$ zpP#NwNy1go%}t%{9VAtN`!-qS>Rz3ulpkiDvT?ll26;wYVJfKRj;6AE*~dfV{1MoT z#az#)II4`d8y6Z!mX<(iPYFWQZBGp8bAID7AXH(B!y#H~8Q5-OdsQUzh_nZw{771K zD-~`WI|FYTVsOgxQR#ROXQfv{HFUO@(FN{eh+Vx)X>}^F=c2sD5khj9Yvkh$$6`%xw-gUd(+ zVMq@sS3SkPPR&cwt7O%5xdh{?BBAK;Ap`-9f2eS`s)I#CTHY?DrEG3PH+QDC0x9kR zDXp^Vv!tFG(WR-8njBbAoEO4==TrBJZHZ#s?C-RlojrfNDR)R~kkK zwgUQKtm`T%Ny=~u^yCYd^au&U{k7mS`-{OX;9Jpsrq{N(qJo_roxygB)$iZkx{E{* zvaC>E$wDfNuny11L=QEG8)vM#YsqWrc7r#z0Bh8jM4u%5xL!TsCHPi#o}FBfCTe#v zXsQZ~l-wd_;EOEaREwnANrXG=L>{w8tl>5R62hp`5+c+vS~e3%ob>mi{wc=u`=}#F zvIxq~y*QjL&-azPK=#)C$_cHGe22Qiec=u@;OndV@TqJUdy?~KOh1#eS&S18Au{54s3h7dw%FKw+7_}%+U=+CV(~u{7%w2 z0b)r*KeT|>njNOnN?Lev@bKvsi@k(9XZ_(jAt-N;mo4LNXwHn@?#v9=N1zcf;SP#3 zZhsDH$7@cq?TuG(!(sSE&50&OBpS&Fa#O6@u8*{SeX#0$PDl=GwyiQyavzOILx6Pp z@oo?8%bjsrY&BPpyX0Emf3ynHDj-2`Y4#kLrh1Mt=q5?*X3hwaWSDaF@f$~o`M`>8 z)^Sj|6GAE{6(Tf}tt(eCehdyo$3^BK0**oE!wJ;xOj0*}=`6yTYq7!=>l@9R*wisn z0bfO!ykMYqXEoIVv{pF%b`dL~#yc*uo>w-bB`q1}nGjW*BjqfUm4lshav47ju?mPtq87V$8GV5(bM(R#-i!c#S zH*SL*n%oz_=F=*jnsp6F-C3K)uu|U}cNFR=VdkKChXi<#R!;tDmU(bXh&#aHJWey3 zHh;zbzHko6uvqzk=Vf3qa9m*uFH2B&M+nsf$oo{>+`FYsY z|3efyBAB#PmI7oZK36OEKFQD%Ec|cK|I<7fm%Vl6_0~q=f_igVpiA6RDdg0j>i>r$ zGsE%)uoq9*2Z?cWtm*rG6`DP?KbFsoto9-L^rmxad!JG#)~iVl-wB>Vg0>*-RGGmk^d14u9|@$)JnVH%A_NB76S(f^+?ML&H-m4sXT zMnSF7$dBYS(K~lMpSX4f20lHmazz)^_-Q1Ry`jql8-@#JP}{tzOu9tr~B3;^vvria>uY)4@%c zGX1__U}kHxP&Sd2PiV|1p;a}+Shzv>z;3($F=#$;;(~pgOGLi*9&4Z3L{Q$Td1*Os zB*?-FPf+}oA7s{j;$|vCm&Sz9Lpv;Ao4ewQ>F=rkb)M92v^J4h9S!k|2!6IYbkZ_# zikI)lJUO?GkBWWmGr3K+Mb5_c*00t#9;+OlCk673Z(Ys)`qb~K1F1$IO7%{bg4B&2KXq#&md|^iCm9pDS~6?a{n!YowM#qi>Z0PCk2H5i(04K7Gm7Ol!Zygq8qrQs{9fHWbNGLIMH;59_Al;30cZx^|NQjiQggBH4 zf`9_johl*?l1hluqBMA3Vi4E%i?zSCe*0YeoWInI>r$B4ndiCh=MD_xzlA5Ezrm9Y zi6UTc;E`42cX(1BVor68C%4ff>l`mSMSsbUy1uA!!?J@c6v z0bWPSj-PPSvb60Zn3%>aBT>hy4Rph$9CNP!0w)2#Z&z)#-{aSB8n-^Y5cz^`iE){jcp8yKm!CKg5AGIm1ph>Bv=Fk&aF)lNK~<4uy)mZ<8zh%nx@u@`=2D zyi~R%iY9x5-(@*tXafy$y=)W#7g7HRE>eSV(Gqau5t7!bdva?tOAKkQs)SVf`O94J zd84{InVVXJSt3@FTnxPhiD!CDdbaNFMl{_omcCria8RHs1N;e`JZ#c|-Y;Qxym47@ z{XF_yeHi+T1C9JwF(%QmgT(X+Ad_W9F^YVIa&Cw+;`1)gRSJjNuZYBSV`|_tY<`&{ zLxilIiw|qKS-BL_ea`L_pagmwvmD67-p#66ZoFjEsT;Vh8GH~7cwC;!0PMS)V{P~} ztTh;C*#UjX;Zx(Em=81({tQ6OYG*V?WNFUl94Owosmtk)+$6?MDCyq4W=em+dy*LJx=zj_*>HZK<(t&`|1Q}HbtT6o;A*N6%YgJs2 z)1IV+0F=^K(C!Y*>ms3gKC2A=!msb9?^JaFC|UmmP=+I4H8uvz8MNK9g;XAku)SY= zqjd}@0nUPUUnRn)yS7VlX)lKDiyUL$dYsrmq;Yc7apVm4iNza=?Jj**+HOMJg644R^urtJi_#1Yp7{odVqyh$h#+D?G0~ zv$t5Z!Z=FyIKHJhaooLRbkvz+2I5KCw@Ke-?NF=5%--@)XM`xSEmx-n znS*%pC^qCbUXb0RgvT{N;!TH5{_TwFCAQ>z4rlt}{539RI4D51CjN6k88vf($F1;r zsE_#T_{5=GPTr9nJdk#4#Qu8d|A4@9C78l)_;rQnF&T*6++uz+!Sx6JkIM>p5{tmH zXY5m)5oL^mdbIf!%DPi}M?Rd9b4!w4Lvn9cUtbR|^2FEs@Zj&~g>-B@kE2xOG$@rV zuU1B9>fm}Rcn_5BAo7(Lg*Uc!DM+GiC0n~5zkSXrfI&6@t|~v>sl*t=JVjwn8Q=ZB zylq>i<6q7c>qqPx1E^RYy1_`&0_qp9ngmk}hRn}8{5$!|gRatnsi>I=LUaMo67OQB zIeNgrWFs0(2UB+!7jp+wPq2vEqSmSWrAv}{kic4w?s7tWUmTU546w+5Z0CBK|q{%6vmT3o;8D?juZPRQEOdF1j)#c{es^cssc zN73K+f5caF=&cw*8#*ExKQ^VXM_v@ZC-zIevg63RJuOuJXG{|5=M+g~TceqTS^mZU z(N|DW@tBZ9?BhHOeg5S2CK=TG;D`KCzOsq2fs)2#55I6@tm>DSp4aOA@2MUSd@%_? zLD@{Cn$HevZSQ@QJ%2E?=Nco*uLJ)t{2$qgd2#}2H`5=wP!jhQKh_8=ctm^3|Iz>X ziSvCm%rLU$2K&gXjO_M(%ti?RhdrksN49&cv6R}FI7O`Q-3$?93;1!qGL*MG=!YI= z1NL4SU6Ir-4K0*fpy4Fl>yPr4WsfGZL1p8z%cD>7wdt1pu@bvKE;YQZJ=QG#jeO-> z>nSK|R&Fo8a6hS*Gr^_1Kh<>kIA1y2rWmXDQ!Hs+&vL>mIQN3G46oYh&<{ZOm9QKS z<0fAZziO%1w7;PIYy8|_{2$cUKWSZ5t_)E=v-{-HT!!7c8SCW24}t*=WJY?4`vT-U+*0(|~23 zJ8|CL2~SC=P%;#K-dRXuP%on*0+t)viYv6V9#}5l$Zi@G5ODIlbCKv|zW#v$N% zmP1oY`iX7NeEV^ME`=qJN-#OB*{cEUV+Z+KH&JK61;%69S1jHkY_^7)0ke%OE7g(& zlaAd^0+u%vbs|OLllk^ifnvriy^n;joN92${tf>JfciR@^Lt%8S~*v|x@YiOPzMdk zgQEZsNx(!)8Oez;k(|kB_*;>CX>;3MQ|e>B_BR0@bBKUtJBHGnE@+IO2y59n;YWf@ zxjG_-;G5?tV42~ZZ7yeS=&%$nfi$ItC~F14V>mm;NU@U=ek%CAp*Q$Olgc$qB4b+O%A@hC59DP>8o12+#?zEOt)gbs+04te#61|l ze~_?z%;)9-UKC3!ll(qG zc5k0*-2Vap$KI7o=ST*W32g(+S>N~*=3>1ugc$tf?^c&tF|7Rw;kWCbuX1+YM(c7K z(L5NYM}5}+)c^4j^+Jy~zw1cy6RG$+rfzjKdi#vW{M}1+;?&!M>l?7ahF+rT5fM!> zL$hD`yT9n2I6DyT;BTaeMcL}9D)k{Ine&dF-iiO?Tu}in2DX$bN}Ff!95a3G$Juc7 zcB5aO2V__wiM_id4hPonb#4&mK>HqD|XutS*_J%@cV(vcuf9rYt+dUxdnTY2B@@cWi5On&$nN=NEL75otEOzbX zL`@3j|J$EO)Uet@WeRHkw;jfGHOPf`mkN7?{LBdt&JQ*+`Wr0uT=za18M&tNE>vE5 zEMG5%;qGAV=4S5d2D1Ww`}VLx235eYHzHQRzy0=rw67wb2bc$+bQVGprx`fGMoH6C zKUxp5*i0L9!Jf>hMmqR(pn#p&qad0S3a>F)w!Z{mh4?OT2uMl=j>mCQaBy7W;ei>u zxEOnaGVg0;YkSW$uyGmn$ZF=j3`@iF5GZ)jDt8E zYdcV0APUgN+QmKV9EEt|f;(WT?o)Fs-%$ibNdr(rf(p;^n?I(Y!Z0T)wWc-2iSYV` zqJ#ldMJoCDcG?5)Uq7MYV%Xcb2$NWaN0B-nCE2(@tO9ei=~d~iv}Sz_%rnn?%I-7_ zm_(8Xm8A}V5W`x~qM@IvT#X(!lrYRic)~!io)VO&yOgYxxd^-H($H#9G@sI~8f zUYlTGYi?mbLJZL>*BZ7{n3S>>9zxM_22d%d-ke4ZQb43)@AEKuT~+u6b6;GIk$YWK zLNkYm!Qx0((t!qff?l+}g^ley=`yp5`wG(Z%x@486ZoauQN?}ujT6}SQjD#k$7?JN_KZr3~} zXW70~{zL-t-i2!ei3m_(1?-8T<5ZNd(+6ToX>EROHK-fITRjF9F-XRCFgako_5sc_ z32jFaA3l7_TU3_BI~(PvSVZ~}mBPZL65o|!TMN(mD%QF!R4u=9s=nhS!7;bhD;2Pi zF44JVUEx;$Z72H~sv}Ub2ZZ)aZj{!ZG1rQ!l@aik z2<#D$eIm&!&}n;2^MRm(_mbH5S8Eod52RB)6&hK{Pp^Miu4gzX#io*@OoX_?RDidv z#!@S4u5YyWU%>m;S9YlTNp=pkA@YEC>otp(Ge0yOWjZm*{N7%f>Ihx(8$AqtVK^V) zvQQ-4rYJpR`4XrxZ*=#G=8yOwT08DxJ{6;e;A7+i6M@P9KfLc|q`dXvGlO0}Q%o?{{i`qt==py zQxG56p&$!nj`}^%h1>cr(X)cy4tsrPaWS~*A!$b;ULz5KG1qZ11&7{{bmIGVW7UunmN&)2(E{>u6cXv zS*JKtC^jQ#??!a9lmY$fj7__@`#!sT8GfnRatrC=bHj7T(BV1IS8{vqRxR^6GVY>f zcl;rf^%_4o+%>rf1pQRHTBrc+p z-l^R%PEOpqu+l^h2Kq*b%0Uyb$|>u(O0fbn3!=4lA|irszi6dBG)&Pcfb3jV)|qlr zYL)_mGxh{e7W+&FurOPg4!T*yfIt*n!};^RuA|m*u*mc58khN@`S92yztmgLHM^&1 zuQ+s;mR<#tD#*QW&q+c+hueY`xSN#Tf~sl4d`Vq)jRNYIlun?7_J%f2=;WvTgdCQh z#O9)_bY_o4PC*BN$)v`EZ1}EeU%?At$Zty9y{I&x7aUd8goL26hQ$X|=BO@Qx2g+12E8Y5hui0O7T{8QxdCn zV$VCe9p4k^FusPn9xM+hc_}pKth5gV5S>-5IUd99%ZPb=7J|KF4iSc~wbQGFV-L+2&f7=%fpJo)8f9P{oW?~88jtcc2UUBUQaC>41ZYmWET z^%{emOEQ9)#`Va|m8<@vNYmS+zwWEnYHwVEZ#~}-pV(v{doldkmxVU>lz%+UDepNQ z*^RaKw>M`J@|(Y2crSD51V7M;$oV#L5qcHz-~6GFoP2}&@@7!G;jhml`qrIw91=QQ z(u=AI=j+t_QIUE6Km0sgku>JiyMvzWV?DYTCbnYx)Za7nzx+IU5zhnc_ee(eyX>;E zi@x^hX1s0L49eJBlX$D=ttWBV(ux{j`;fT>xYR+q%#u?Ex+7PoB`rQgVJv;a^k)!v z<@BQ?Lzv$Fyc7i!-46(Dy44u&%pKoX5Hn->&UXwhf_7AK1hXN4Y)S4pT%Ph0ool&^ zMNsLZ+J6D+kFdPqGIx8SyDL?6c0@+8^HqyxGKlzrtL}f)^44HV{(UxHkX85HZk99G zS5FcYRZG7^%bR@F_ZJr&Ep&J8QC`p>XD16PsJ!s2(_ulgv8$P0&Q|eyAS&!5Tu=j%qR3MQbZee);M1d zY0FRzdqNyOnNf$(+n)dk5FT7Guk{<3?lUDo#w_K)xHvU6{*k!q)V(1#ZmM~pPm?Z@HfSee{s7L7*B{uBS|^*u}bZAtY+fA#n32dH{Igw`-jT>^UqiOAu?i zCR0^jZ^`}T-k`Bi9)L~Cu3~Ya>k-X{7;R#7_AKJwU{zxe%2jkHID+^Hc{7(rs*-C< zf4w*SIeZx9bZsMjqtV^gbiSD2Rzc79SmND(fe&unugx%$H!UA~K?Xa%DCo*(C^?*l z4+IV&rRfZ2rI5tR@XI=u+UpCc3KA$-Uv(AE5^k zNni){cA|a-3K<8RF|wlH>QaY6NX}{aU<(Mea^LBGx%-KotE`|Hi~X{Ltvvo|_|P|W zHn^y_jJ6%McVKYLRN8d02J%?W&P z&q3cEjL*Eu_e`T19VJcg5uX6;G<Zo`g$hO(>eL33kn?{S|rCb!7nh7Zs^A)%ca zDS;%Yhb?}HdM_W_R5$zxJtXimrWC~(t=#O%%)p}M$c@%7x%>-yK&~|!*bVDC>s$8m zYrzF{fInV?_!smLxiifqtentQAz&x%xTSXIUGrA;zoG|EP8e^Z8oi#W5>?H69g#kU zS>=i&^w3~xxiZc6afvjfjf-eg_fEGKN!ls&K=|Q22PrLT3Clpp@V3ZH8;P}~q*LgD zjg_P%vEG=Q=oPBlEe)c52WKE_mSTqStm<9%9;aycOy3^jv4g9_pJNBQ zJ5RT=17}7&sJd_zhRu5vw-~t**a6LdSzA3<=ysN)sqpnLm>i?R@Z|p#cK9}nVO;zC zd4=+r{OiRp0|qZO-yHQi9$^PSr~J7L6^fCy#%;^nt)V#Tcs*N;2WJNmI{?4I4qo8b z4sydm>;U`*JB%Ei9mIgmyevDgkT5}n#q`_a0yWlyXJ&TwM>25=JvRlt)Y#BLlSu!1 z={x)9M=Lmwu>-VX`c_fjej#0pTJ2ohI9vC~T}bl=iu=*o0gEVK>nm}A^9$&96iQ84 z^F+Swd$`z1ucP8l0_>`@4WWNj##c0=Z9BcxI*L=+;fi-d*DdO=47Y79&!yczGxxZE zuJ;%_K!1ZB8rQ+ALj$y6?~7$hxuKWe;ygUJex--U{x)0jY;19X1~HC zT=y66x5aZ2v-sfGpM3XO2tg6D9~qvdojLGjSC^5Ql8fP4(sjK3-|C0|v;A{kzF9%F z3!-pxZ2e&UBeU$y>e|J-9H#$0y!rd!*aqLtNr=dRL(s&pOW2XhFI zHggkZ_qDTOS+AhM?O*m)XeF1`!%`l6rnO$dFVDLCV^T|m>))L4s~SQIpDxW9 zh|SoA-Vxqvoxo!gRXhFagRlQH#GgU^MKi9SA>U{f?2PkJ3?5tRx!zu#yE1ns;h`t{ z&@okNedjaIUhsDzE2Bul{0HQ7xG1vEFgW2VtBjEs5&V2|tz7F!gDFLn|DU>&=Yuwn; zetX8U5~w>O=4eO${5T-yVHgd`{QejgfB5YjHgckf7R>&7T4cwY<|2{jO`gT~og4Wg zOH!Bg9%I=ltV+*cs%Jot`o7)b!3>=CI-K0>)y zdNsGf+cPU6V zs;P_Q8Zoh3>C47d<2MNTB^3bcwfC8hXZbkvB?4lwfGqJ@;6(#?R5mkq6QKm+P+)f7 zq68b>q){!Rn3!E0DE=6JY0cTl?F&^{I%ut5sbouGpXxscsH^E_c z5ae`FF<#LviN})vv43?=!GjV1<;_`f0%|+k!UN|T|tTiQG0-l$iFG}=E9lswTiL)4`1nR zroHJ8_K)d1r9f3+<<8V~)qE!ZkZ!hoIjNz2rI311FJNZuVhKwC+-P3;+)v^4yW|@$ zBi#Eu=HuPI%7cAj8vNhcbR}PO)tcGNG%iW%sW$zG3xa)v2+5&aEx`uanu8{7$3>&EZs8I~9%O`RWS`zk(4Hu6*g-Z+RHIDZjir?Pzv}Od{I)C$lAfe5dzic3%ew@Ex_1@5lvBr zlQ=(H&^RUndg$Dp>?A${1>Zc18i|-c4haT2Q+Mm5xA&o{FsPpNEhlXMS5(Bm`3m(qrp2f9RRV0S$^rk4fh?rq4A z|Fk#1RwZ9!iuXkR|3 z@T!81zkME`nh}V}3~shL+B6;md;@vfKuQ`(c9!Oq!Bx9O;-pf3aK70f<{Oyz^!O~q zAbZ<8L$3aFg=ek^w&ax0PK?icVh(HG!>V8az&uKs8sd z3rnN#8QgQGPvLz&%w<6|E9IwzqSOUpx5V&bniIf5^z&SJ{=bNM7g+jDIA2Ye~tm*jb-Ej?ayzL~COtdjj{10aq$XH|zn+RSangA4~uG1neiN z$>2W@!ugv#Dmwy|bSb8T zjFpAtXr9LMWxm4etU8-GWfvPnoW@GBTZiQVgyR37aeweYbX()_22~ z)R94$1`JwfFqQ+JhEw)-si{q|W>d#&J$WtiCWDh6F;KxXVT~effh|FoS@bdkRxIN; zmd3}JS%`ru@~8RI&|qCM|GH`KF^)M1TdSftjn_1Fy)Ci}SR5t^ts>;e*x*q9s*Uz& zZ(^Mb=gF;Gjm3voLJ=^I?Kkqm`|!vUeWAB!GTNw1nj_b@t4+J7W3 zrsO2eRtZJwXC%eb|Bvu{eyUE znUfpg^j%~3fZ19`l)WDlwXtcrlWr!9hc`lp!y6%Ro#b|0c|@9l{r+R=Wv}a2L}oX3 z4{-ip#Y>A!;uDCsQjpBQtawhJbLpbA&{eaB2GoNSp(HTjVXMA-2l-qT7NceqYIezd zNM#QwYIHwvgGa@{Lrgx^FYe&5-Yy}4J+Z5y(M6mHg#+Rf9vN%K^C2Z%{o);5e&Nnk z;mL_`U^HZrR{P8-bwG6C%^!-$A38NaGtvpnPn|}3vls2QKo;!uU5$yK^2)x~&?$AH zQCe?__qvBl2jM+@$sIZIQF;~rBbcubU|%f1>3+LJW$%K&x^tfCWy?qLM)1F(F7)4! z|32_aGr{B2<={RE5B;LgNE-)}_b0wTynjGsO2Ym2^hxd5sk^U*w9BabmVf>I{bRG( z4`D)}Xh1TEIh$qJv-_m8t-9QuvHX_oJ;7qPHKHn=|dhfy5hydzQIU*10y zr81;#x*~e1FiTm7-_j6At;n6?-iP%^XZn`On@z;>MGS z4H8K{?vhdkRyNqaE+aE4Il6z~>N2n3k#r~uKqON;vu5p;gr0i*TlbHF35>IpW$kaT z=dSo|kk*oUJzHT$Y(eemh~I(F;}r@-Y$2^0?NVd`j-hz;e3;MR4b8ANI0EjoSz5b+ zTfC!-Ib`L_ymL&MB6_orH6P^}^hgNp zdrg8$;z4bd-E$AbXYB+x+^*okX(&vsKV*5^|bdS*=(P-n11RoG7?go%nCz1;M4alS> z(55v&>PidCwdSE$KM<_WU-$3YzIV=gPVnuK;HTH2n`~%>Sj2@pKjm?D1*q=0033O! z?ekejx3x1KcdJPLW#2s)^6E9^CD-Z*9IvVpvak+=i=1GvA_Iz>v9*Jd8^G`5`1QTW zXfC-D)Lbw5sv(!J1!&R!s!L{$WfR}|?cmp+b^9(E? zGk03YTj3p`<%DqNiuM7V&=MH?G}aLE*)7^}A@2bWf-j*5+prbzP~3E()?6a_2kk0y zjGy%+x4k2FJq*PSj5h&wmqH}2T@MY2zs=mxFVJy#kG#3Jp#`Tx2T3FI1Ai?opr&-5 z+%F-5D&$smeS+i}8tD;_@WWO4Px^P^w3K4U(m7{XE!Nn5+Xkhn zU!`-5-4PmJzCVF0-pW+JJb+=I=cgrqXto)LQ9{GV>9hJ8BQ8W}0=W7#$wF94N{vOw zDdE<@dWnm#E+8A^r_pI)xPe}&N|&2ZFL^4g3GmF9s(W?)O&%+&QR`jb7nkTK-?^PS zZ2hibHz10t|5z6nlKMTsk*V9x+tn}Q`M7>@c74niVi{iS4>oyd^2*0QW@pm0eLAC& zD1z=}8OG!s>ysYEFr4A`ACa#i=?J(U|M~PX{F|P%%;RMkN?n&CJm&Mw>+5Ij7Tjl- zXJkw-H4Y!vq)|yzMuVC;2IvQlb5w8CK9Cb-Z@+weV-$dPJ2WXA*kA2|A84iP*L;&H zO#5&@7*t+_?op0J9-D2*s>2c`KFoA{B@C7>;PSD^{`hhh9)^BclxBUPnY&K9K9Ha` zO=h_i*1p0={R)3hPUqAzECO)3o?*&t5I)mF5#*+yB2r}S!bbGV)l2LL&;!FI`;>pz zu{L0JBgFqvs-GeXSb21?48L!rDdN8B^Z~sua>;&C;O+ES>fim{0dJmA-|p)5DMavB4tGfjPme-Mr`ULXjUT zP6leZJ&3JkJdZe*y#tb-AV1R#3^x_6pb#0(+Ksb!f@6R?G!vg39s*ij+1XUTUc&84)~M>m9a0=x3R?)xQc1?I z$S3)B_UKYp1W3gCr;&Xy@3~)I_TIDe)92byHR9XB{=gf?F4o4z+fdecRg3$Nw?tJ4y%_5B0=}wa$7Pco$mqxqWOPBz z8Tir4w1ONQpYqb>iY?vZ-{T$a$bNtbtXBpJS9ZN*Vk*xkBKV2shpk(1a7VVn1w36A z!c$+7pVRUcG_c zOuWEzE0W(tq(H9Zs8H_D^gWY_&mU5A_3Sgdo~3zhH@B0Qsn+r<;g=SD!T74N8jY=t zc+BiYgNyj*Q_K#xm}7f@+Uiozr!Q?9546YZpD4P0+JQ*d|9yRr5KU|hY9O}@ua9D_ z1no9G-2<-ff6@2!gvETc;?VXqyQ=6Qg48Hj|Du8Q-_iFhO$+lUx$bbX-Z!KPPyWv1 zH#-TYFCJ!Aidg}A)?e441d*~E&IJbHD2-1*_v zEjZ-V8uTW1&2HM?(x~#5hh9N&8c~G?+G%}H4Vv-xl=YPb24cMGk{)E0Fe^{k(HgV| zq!SjctKQQe&U>@bp?1Bwf5}Bs z(Gb?*-DV=p{frY~>>Ah3pCQ0>QS7Bq?ZV+r}J9Qq?sZA#q_&fTZ z^Y+cw9M9dQ9{yI&fwc@0lf3S*mN3@Gc*$SO5F^o+_!Ao!n;aDfjsO1#NGr z6D4`b+MTQ{lK;#bfaYmurBQ@ZWi^_y@}qw>6~5;kbjlk5ECtgUj5Xa}X@8_Lp}IXA z0C}-}kQe-y`W}%<=>KXBK*)QbCZDcO*wE;u-dDIJPiiJL>7DYiDg21{%TG9iCHdvq zMQ1AvziEjcrZSO1#(Ght!&W(Fbg_oy8Bj)izJ|H>-xmRR#kb`c6WpR#cba0K|Y9glV z31Yu77Ikv6JFw#IBfqcA<#2n$I^(B303g;vWHAEHklfBjsp>VO^U((AE zieAW_YtRO{!bs%{$c0IUe zgZhBJA)c$)WHZ?b%(wOk`p7Dw(MHyjC=4j3#-QDi4#;da?S98Y@kk_nS_!}B%%?qX z-kXzXbl_@i%yWH<;D`Pq+S#(cxuK1FV_Njoa9X%D;Kwx8{zLo6tp##wJ>n}VhKdg4 zI^ajjK{X5)%oZ@`8D@n^xsuRIkva-n0%+5Blfm0NDd_yOGr!4Z3UQ)n57HBGdFHVg zp)+}FyWb!?=~_Jvx(i6$f!#AOa3@F4M3ZCoYLlE>E+hBj+E%-*UjVLBX69DlD{_xK zp7cw}{A!8Wp7F;4FXk8hy3k1^m`DVmin_!zlXC49O>=g{er&6@q`?F>IGF4~zC(oi zJe51FR#lZj#x(fO9F$z%+xyPTLO&gJPDrR>vmX zM`f`Rm*LbG?2TPq*{mQ>s3SRygS<*+uyY=u&upEC6`M|h-S(-S%x;x3LeA9txI`z^p9N;oI=ec$h=95jHTT#Iqc@ZbJ`J0R zH!%0X;%HXz15@-4K)GK%9^EH1mh=793Y6!i{Zl9EuW)Kq*8^RFs4%dE6+(*pP$G9< zIV8Av;>UOLt|$rc%Lg5F=CEQQu|aKpqsv7L17n|5d&U&0?-NNAUeu zch1i~{fDeOX(Z`B>kZpM_o-X$_Jxxy2O}{s`OCgg8x5u` z|7#xLn&MQc7ZHDS1vVc0hw@x3cfY{NpLu|4@!V0G>8j`jg~a)wsVEA}TTc}UZI5#RB>;o-2H}eLlwQ$9#eOCYrJY;2 zC-@w}Hi}&YTnYE)EMs(CTV}RySvusbn<;gTB7|r*z@O&IH~DL$i4wsuQ7OqR_h(gE z#4m+dfg7P1DM&~B`?>OWgDMx-oo;^SBB!SXTWTBzj)zy=r;K3-lJ zrOh!N=>mNC00?Ao5|7cP{ov|SJoiCG!blcufVn0v1!@VCfGLkY}osS=kbl#6fv z@Y_xXKQj(12@3&PBjAPJ0(V25#&)2KT&yTGR2p0lFu`PaH)}^w!UVc-uTF4MVD^abRAYxPzOHgnz!G(d{4_Ui<};u>%aOotuW$ zbjCb@m&s=CG_9(?OQ*VvB+t(8q01`g^Xxvpa*5TU9?XWP9uu1Z+J=kb>oev1-XS@pK9qve&DxlRfgkZU zu8tzn(6R*>rihmox88_ezc7$BLZKA_{^)j&#%89>K)JtH*4i7s)oiaxl&OHO717nt zcj1!9$?)@}CEr|Emb640U_-3)BbW^%4wsIT;h~ss=BoN#LiK13o2Hlt8Dsl#?HcWl zxXhQ7!{Stcp&3@Tw*hv8EbWF~zfZYPech~Zy$r-YeH6&SW^ZZzUfnRHvbkfv_Y5!e zF$OF6k#cjN+%z)trq)9?uI3Y_0Z2O^lpXR3e{5TzRPtKj%jg&m6+>^n zyR~x?ikHu=`51~j&%9)qIXkrm16tOMs3b#xmL-Ggz8e?F>y=!JM`9j|?|uU6>vMO|8N@tfO<@p>7{vdxD3{TokAJLqife7Buk3)*;6X%N1#RV2VAK(_Su+kp-M%!LPP z*?m{*H(HqJku2E!&|A++XOVE%Q=@u<`eGN;!au1_{KHsyIx8^6&kCq3$UA2i#L6oS zJ!8w(sZ=<|XAN!$w0m^bV2U5%eMaUSQp%FrP_mI9o074aay&GLccOz#c<96mBXz^$ z`b~or)w)MBUJ1N%+>Pi*DSj*B4Ch(CBhQ& zD7p3q_YLMBmpkkQ_$sO%X7zT_ zb&-B#9p~fJfAVktZN1%M(=PrFxh%aqO2h@~Z;xqGHfm2)<%5qly{GrggR_`XZf4W`?ySgiI>zfT(T$FDQ@&Qj)c+6Y z?daG0V*TjD14nNs3BG7tkb&Vzzdh000g%@#_Rx+ZN72HNA1fBjK>;$V6b(pV{I1a- z$nC6P#h|+V9`OIm?f%npJD{%kZR=aBCk{`qB&99H#b$c=b?qF@=13sseDuf!uPjrw z_QH?MZEA)6IFEzC$%% z4K*};_+z;p+zQ$Kkazn(qql>0lXy4s)!PYS>)r9eixrsS=P0Xx{fA+Gh%UK2;1Bh7 zUw@8cf*52!O=(^GWI}>a?OeIgX3pz&YSP931Njeb1;(8UJ+~sW!>yaoA%CxUwfzPHbnSf|{$rOkK4^Y-(!doJzgPd$$wJP6C+o!2k)bqY*YKl7m^ zXD!ze=S^l6{g!|ETm8Cy^K}&;0|ZOS1}!qUTq|kgHpjGo@-NlfPpm(g(n~3KaWL>v zFA6VxyZ`Al|HA*`2bDukSEebEpxu`yH-`Gi0rk`TOA9`>sSw#rF;}X(^_`YjR_Kin zu0Q#gk}Lcgu|?gb9NgFRtVtCIFnm68obWH#w;mNeFPq(EvTVNBSNBwXaBu7CFZ>Ig zld!=;GozK<(APr7?Hs&{D8h)J{7Xvo3}=E<94yRqf47``X5mI5#sdWZV$^>}8rNem z*1hayAJ$fv;PQ&;>}mcb%_c2qSk$3gcV`!mRj0Z#MY#>+B98kSpjvHj({;<%GnyW} zGkY+-uKaGtwLTQgQUkqd#-?tfB0w}plpWyzl(YT^7%?6Z-I5(6n?4DVJ1_xW1Ga;_ zAKN40NoDn)wNB8LwOzZxc8xd^PVm$#U>d^c+^73T4MVhz(X5{O68E23Wkq8!TE zE9215NKG`AT`2Lp#1n16h| z>_ozgZj!TDsNoLME23*4y}~G?r{H*nMYm*Qk?FO>a6{0S<-CI*_o%inQOrMjJBtgi3=wP4o;NaCQCSWc5( z-^6m}aeq5{i}|fmC!$~%Dw9h#^4)fvdhYos8fHP}$IyYo2AX3nS1_<5K;^bmQ=!je zXzjWIGoyJ$;GbGA`3t?`Qrd@gbD2GQ&j@47_(lV@|FtT*pY#fl%H79M{3u8Bx&HeI z9&x)D7114jaB8YGv_mtYDafzOM?O71x6Ry(Gx)d{zBg8! zs>geHPcb0C?t1G}ebf#=0vt#-wo>6yJswa_-M9(pkIx8?*wB2^@{7ty+Gji=L2R6I z_IMQXwS!le+fhph7zab;eNK@e?TjnkUerR~#?rBukjVF4O&(#?osb~*z;22H3){uk z6;_*@xz;;3WKwpB9v&@P_kj^147bqu#di;E#OQr))DPbd@*Fr?v?Kru4Ffuf?{d=F z+n>B_7&BG3qU}+^wMODAkf1-M+H3Pg#a?Ok?F2*Wdx{}2;^RoIRS2rJHuCLkyTe}f zjZ-dn`#i8pG>nf#Myy~(fc+hjJG*mY){@T}&p3(s$lV){89F$9?gz^Lo&-5A<-PyA zQr`M87&SE#SZ45NmAp_Ic$fS63CWfw^pKhHYkXuGA{33!MZnm!EN8&o^#UH zeovW(b-7^bh|bC+L_L+I$xvLG32j zuF-S%VfPah8x`T|FYy4+Q4lxUXgUbUggmaD--;TDxP-45mChZHR&5U_{Q`cd9ON1} z!zzKZw0*J@E~7Kij^CRnD5X5a+9DPZ{ddr2Gj+S2&~z=4>F03aTcV*i_6AxUj#jX5 z*v=i!->!XleEX}yhklzz7G_$*dQq_djtuy;JV^|FPn*7GuH)X-;qLwx$L}Q^b}ZNG z1Ikl37Yc@<3)%y&FX(L-1criR^Fs_l+hE5b*+G!5Um=9=O;$R@x*yIxs6W$C13e-; z41nMC_4XW)9hS4dE$ltMZ7u+3X7?Yt(w0ljNi}Gdnu8T4QM;1Bo>V})B1L44L_i353dJQ$-I1hmQ&9H;mVRFC9`yp>eM zU){gNwyVNz&k=69UHBp5+)_SuT3`Jae!|>6TrrY7Qdl|WGJ0#qXlwAHgt`K}YJ}Gsp7l|ufT)$tdTP`8j#53QG5X1Gw10XD zCGGUp4dWB3y^c)li*yqj^>6tJYi(|RV6qO>xZ8{S#F@Bh6>gBMcfxNFKyvTz$oPbx zYu2@NPbxM+n<X7++J<8eeQ!w zJx>f5W_^4&!Vpwj{L~KpGe04;z^g^BkmON*RFNsqQv3%}1vRw>+an3Jnn0cnWqfBD zHRX%!^nOd>Z^k}`#}ewNzB7&QU;|@%QaU0+PlQ7`C(owBZB9w3CF&(sd+J?d*qY52 zU&ZO{35SqIo)Q-QEk7Yxka2lkWowW5rO=}eEH*{5f}-YTNzlD72PiV1FWf8__tv1W zrYV#^^QhQaWT9RbAuNLKiK0c)FUZ72`sB7>su7*Hh=W+*$&9WMEQlHjnDwKag`muG%}o{t^kZ7R&X!lU(12o69feSw~{bD2&h3-8jV z5F55p#LrI$ja0F z#?1WZUR>LK6$mCLy;p0W&U)NA@TUIP{05jgD*DHULW?UF$zkf(8G1H*lWgeKhw|@k zNgW#sp~4;_R$p+oJp{)4#RZe*zkCNU8{Z!j92n%|ophhCpEY`t;5ixI8$5HlQnX(5 zSXh)w%KGU|PU`JNQ@R&RJqq*RD2TY>KMjS*^63KCKI43haT5=d)X`=d>(L25WhnI1 z&M)vLJilXf@tcz`20B`-ZGX$r@YM&drG3_Au4$X`+^lCWvD%(rZeV?KIDDIda*5^c z5Zs*i6$6c!!llleldJ1zPJ~5&Kyb9_9^Y2b~|LjEeoM zDM8q*6wV5$VE%%=85m{q&<$msjNmgoC3wg+R5CA8gQ&Zc{>^h z6O6b-VSk-1|6%{bhi?w{Q!8Vb1YmLXfnwBG7G`>fmxRRg`Tjvp56Ihh5#K+kPaemI zw7$n#FZ5xhEuDSg*m^y2!xOh*GB@=&zg$$@P}I%M+Rfd}T>Jo^I@&=x9KAJ$UEaxy zhTaRoj2>X{>(#17;ejz5v5-iC)j#HtmOKfyy`~*`c@*a-yp)F9Ikq0PV7LX5vWx^| z4%bFa1L4l@$!@i-E_2b*PkP1JF384X!=H zGw;5Y3*>?CBO)a+amb5xet)K?ws&&2cew|yJG$G(*9wy$GfLbjwV+4n7EEeytzWf(if*h1M_?5eRANhqb1EZI^a zgce4HHiWWd`(2~7Jn!du-p})XpXdF({WHl-GjrePbzR4KoX2sVv8|*N77135n~>~I z8roV=Z&nKT^MH8&O$iUPI6tG=CSz{J!pfeH`*tJlfj8#z!h&&iXg5geAiLDg zG49V4mjoZ0YShn5PiNPF56yw~1?^yq(H>__M%0E@*I zj156UUKhPCu_$-kNbt}cPoXcNzJL5Pi-(c~zzaNohsQ&Hby*dJ!IERj}e^5A7Kz&Juk}i7l{Hc@Sg@hj=rxQM{3K3s!?By362JHy1C3#3{ z9$#VZ4v*$@+Xc9#Q-LQSv3GQCKMKGAr3|=k@t{7sFzy!U%cE{a?VC5-|=h zU$3A*NUaT3ig8J6dScOE>ueGd#wB(NLtF?ZK%)r7tsH_>W{|Nr4-&|pnLLnlrV|AR zC_fw8FBtNowcQoEKZ~Yj)sy4K@f${6fqPoP??}7?12y~Mfnu}& zv5ol|APOOj;2Luv6x5i@MQs;;J(ldn8S%Rb=b~Dd-XeTBOfbQIK@dYR)8{W^FP^4^ zq_G~YyDaBDa!Z^5>GB7#=@{uktxdDfa-=cm!tNlt4Q&n`{Teg_)X9PfFON8P7-4tn zX&pnL2FCgI$Vfrwo&y)70>IVazyx`@heKyr7v^xqboV#*%kbR{Ga`8#LX`r(DxaDE zmY!1A2NMcuG=>z+GAOVpt39d8zI8yEshE`#+%Rr)6d({igM-kJ-?+Xk&D!(}d}iv) zsTB#UrRy)p5ogs!SbU)&^p&_p+VvGj7pU-RlG{}2ONP4ygaHW}>n<$G4DH748gmO- zbsjU6)l`n^HB>xVz8_o@QY^;9S8yG6;d6o%cJRfma#Xx`4*sZrxn&O(*r3TRv`kR` z{=y>gO~zNFw%Hy*sy#{NVl;gt?;-@O!H&j`^6?3Wl9!E5TCePpVc`BOe9=29?d-hH z7Xpa@1@Ker5}U3WF}=V3)`eI9Nao0UJ+5m(NAi3=3r-?vI4saUsBoyCcWII_ZdVMG zo2bFfYs$hoU07YP=qW5+J<*^E7SezzDfBsoOLQ3%Y<|pDlBdFC2p4%LLMd=~$R(Ji_mC2mRu}_Gh9Rx^%-AYHx z65;`l@r{Jc4Nmu~0)%F@rE}&Aejx5Rfp!GwSD`0IRT!g1R~N64Y#Qb~)OXXLAjt+- zk;@wG>E#MqFE2#elH44oJ)s(&+M5R|?92vbX$`H0g2D@R8xY=c#YQH;gBSHT9(@Ch(HYT zD16;Z+@t9rrxfi0H5dDr827`S9i`wdk(g*$3(K*1L+(tkTSr;P6_$pp){=Fi+;@rU zU%?3*IKh1#u}9Eqm*ZS5Cpuyp1#%UhErOPbycSwcTEG_XhxUP*LUJtW&AY3(POCMoX^_M2L5;(3MW_@6fun3(I#c5_V*JK`3a z@=W(#Lp8BC71px3fmzq&*KcQQ^IYVxdU*S-!G4bPj}Nn!w-F5Sv2$SiCt8U46&bGj zMMi&3^>Ln|voo3uj^DBq9Vol9xAE9-{RG-cyy|O)(sQf!q?L9LQ|7#@L|SqZ34UIr zhPeqA6N1LdL2D`vR>+ufWz*v)>;eTk{P?q0wDE#GShrv;j6WcEAxxL1k7J_Dqq{0! z4$l{N&Fw_*WCY8F)7%H;hlU!-r0n@SO}o-B2d(2CkL%1~JP5M5GoWRGxgD`vK~Pu_ zbgq1w#6-z1T#=ncy40@Fv!T20HC}{I8xs~zY{M-L!lgFYpzC_v5!{ot8(&9vUuQX! zRPr7dz^#h`!tqcOH1rJC6|KJA;CfZ1y>Q;QEoqr)S32H+$3jO#+eC-h5@GqR7Y1W0 zr*VJx<9XNimr#Fu`D2_OhZP3n69`%Gc<#;=yL|QW6e?kixnJm`m-{umHib3H1B>zt zQa{ZMdAh{z<>Z#SRVYZNq4qIhz+#yH22Ph9+?_zkd&dTDsKh&G$d;WVdGE})`|DOd z950WLmkSoy9MOT$XKRMZfbbVKQ;cV`o%XYfp6Rr|juT|{^@bjO=xqGFFg-eJ)w4sx zaFw1FFKLN9!AI0pV$tqfUH+s&tXHnJlm=s#x$lJZb?!(%FhHt35krC$(OBdI0!eIe zAaUDta`pF@c6IlF80ZS)sAl@_Di4&>(^I%u*p5CdWFt^ZQFx+JZfIFpoDJo{!c=xT3Oj_YBeWeSIRJy#jq5y)|%>-Jy7 zlS4~Sc<~TzCFN`u{o`j8SGsLy8&hQQ!aV-pC$~eB{7%IUEMxbWj|?s`t;8sjj7{+` z7uUF#jr{NH;IIED!Vxb*{yp5Bjo}UH(vdcymD&%*$rxiyEGX6YJ{f1yEt^ zVs_`(FkE`fUIy~+zIU&tsv7p;_&HpO{pz8?+5E-Ok;li2btWnLpT3wU_3LNG@%!%EnjjxXI`>tUzTw#jnQQU=dcLbRwm_a3h${Q_ZFYht8+3xTLkIi2j{H^ z-3gSU;FS-GIj~g0xJSEQyfW@OBc*cYg;fP!n9my>9*V)b1#WFx#&m+-ujj8EXukg@ zQi`GU$yL*2NP+kr!1oFJ{s=)}URnPRD7lo|w1_vM{4v%d_Zf6o^K8`G%UfINB{vd$ z9b#7KakSEyz%ZBXG8kd3kbAH$qk)}U0m+9%@`BWEJMT0+u@HKx_saDPhj)24-aP(- z1Iux2JHHD%$#?JTt`QcI_)bOn`u*$m9&^0lxFzOyyz9*!&s?yzU;4wegWGC`p*bsX z*dtjjw4mrs=;b9j)Q%a(Qo*wakqw1h~D3qq)67`Y!C*c3v%Jy`2#w6aG9WzxsR&4nuV=S5DgTN^G z7(cVU=g;oh{;`DhS~~Ag+zhajU3-2%eMrO zaUldq{CmzP>eU(Y5kd2$EIRV>Ipy^;WL4Mt!5eUZbPb$Ett>diAy?}T~^mTmpWCWD8h4FMqugec1HEN(4E3hX0+oRfs&;;|Dd+dsFg3ssMxkL zs#LVHs(-|lRLTblqjeIYo$=Ol1VlPghuw*o*sNINK8rT%ACn)rlIc$W?1N+XdysY* z@NFk9M9v^JNTRFH`kwaG`)d00?Hc^DjIkOZbKxXrE+9uXxT#gKc6vZ0{CY2QnZXmf z>KnJ_LFPhf433K}G<5+!h5Aq;Yn`yO&4p&iOh-`IgY{1UD~bL{O?rn9UdA}TSV&n| zIPMl_aT&R+xASLe@^H7u4i%xEHRkaE^-EfHj1rS}7T|tur6yLlv58r8Ox24C>t^N=)^(kTuTk%zOofj z2V+A9~l336m#kZG^@Q5$Fr6yKf<|sV-$ZkYJ}}Wugv}b{k^&Cz?Z=JT z;vZ`8WYQEG>{>oE~1l0v-;nwP2$W}uFy zyK*V*?kmd90hIIDDeAayTaIe$`(rfV9`QAq}DKh0|L&#rR>_Idj{aoCoi<Qj`yEJc^nTn=q(HqI9G3|+eHUQZWz@C@9lytNJEc4Eqr zqw3C|Zf7XpXI+vr#=koIFZs$md87V*)}xJ26Za`mkyp2h4)Ja7`kk*l`7My&?h=;5 z)kxKb1BJ*!ezHha%0?-C-D#3%<^dNAdQ0$+_wmr|8{MWW^C}ZiN5=%OFeCQu^rFQ=FZ>kqPrx@AF0z(r&doo+TRU~eOTXbblYtVzKo6bega;}k1Aw2CH zTe0#feiU8>W;QYU*EBW=!bqNk>O7*Hv5cM^fPFL<;_31oV$@1xb zxSY83A>$olXIoqRXw3hkbY-El-GFhDMD=b_cB7O2LZqem`RVP$wT8swh6g?Gc$xDE zzv#-#xrI+?A_X2Nld&ZQv7C`m?GFC1 zO;^&Sv@|T<&E88BQ~6->!Q+sqaiNIc>B@)HDQS<&^ffF(>6)TwFU8d_Wy^zW@jG3~ zB~62zShN&hz5AHm#GgK_p($AFH@Z?oN5(>qyk%V4R1yS!(3PO)kD{84TNc|y)Y@g=SA3S%pFjOgx>5$o zub^x;#O3ApJXfJ2{nG1`Vv_$zSIUkWjVGDKjj7Ssyw28KWb<=hP6apY@6nYGwZeO8 z>I+^U_So5=OLFs2u%t-TZ*(QEWnU$wj!q5E1$z~TKQp`Y8o>ap%>N8sNv2|2Wb?=^ zDrm#&bRCy-@k0)wnLp@C7=6nNd!9nja_5W*)4q;|6X)h@27aQLzosh%e$kciU(l5R zY>5CVd@*xlh4(i ztt9A;p6t0DHi0PTvig@~r7q_-Ss55xdf(0IrGB?QmpYzm->$H=H+XOEUtFb9-}+uO zgWnKrU;H*FH%4`5dtj-`52}*s>A~@HV-=DBlJ86Ycx9@M|IYi^(D^FQi_hZ+>fl$4J`8sG6iGwlY!! zKhV8FN!3uo>_g?89NowJya$Gbgf!zH=Te>&T%UuxlpM^XVus*MF~4i>0}FY?z1gw?Y>II8Rr zuf>=0B)>KL5?+MDLd(F#lmC=#Tr1{=K)iCJ(EP8hBb z9g!?Oc9!Cj~IC1`&z=nb{EQB0v0&_>c z7Ydwnm{tys;2G+wK0ZUs3VrXgX7YV5@OA&W-JU}E6d64KZ6tNvg zAT%Y1-Mxh9PGBp$ui@QZaCNykk$@9`f{`9*++H=Y6*f=k z{OQ*qhnPDMP(fYUl_;5&nO7h7*INf@V(m!hAq5%m2dM!vDA(___c6i4{M{xsr@ZDM zc^@Xmk+WIqXTCoP&^4g29E?Q~E6_oUSTn=iBLQ@hZ=7DVM-NDsYngn1nl4Bu(NKfa z5}s!CMbv}x0X7=6gwGBPRZ&fn2 z-~XFmG_y*yzL{si9Yf2=ezB%TrR?l;_pnv!F z|M9$;i`i{i+vD27Hv|LCF+sj)4-`bvd>6||B3z5bWqrQ7Ya~sPkImcu$H&`BSOSB6 z!BRb!Mn%J1qO{^`q(&W(d!JXL-j^gt0cp$)2B&|=mJylP>`I4HLWf(qS?o(KeX2!L zZ{u~Dd{H5wp6%@fl>cBw1Olr+accF!Yn6$ukH&jz&#IXjXWVjC+I^yyKp{g4W^MQ* zWss6^mdEb+Xf1X}3mFIDespkG(hfH=0)-?W;F*IkF2U|jV73m*1C5pT1VOm2`icbO zU%=U&B1<)7utzXiTJtgFuVOiLGLv&c7R!T|uMkiI;G;CvnC2 zAd}z|Q=7J@4i?OBCT&ii&tA|RKLbD7zMMZEJ6*Q_0q9XDC?JgmgB`D)Tk2=^zkNn! zB;~#0t@*fOTTWtbBIhKxM^VPf1%nA9wg3RMRTB+)il0EL(a8mxLR=aUV(?1XnJ6Ho zoTd4kuqZb#j8hPC7NWPJ{@xq2L&BTM!t8OKBT?sM_6y;~X#9fEetsw`Q26u)7q4?a zztTXLWJst$#dLsN(FK!>@4E0}oZz;a17W~8uVYfB`wiV1NAGEW7vJR4pnfrsgYXgW zxCyx9PHtez4K!#ZAEErrGs@y}cYoe$mCeNzM8YltLK5Lg{) zpcr?_#w&@$nY?ncaGW%kmiZwA;!qP!;oDIb@n2A2jhiXVs%1NeyCQM?+`1?)pFos5 z8cH~(qV<7EVU_7lGia+G&U*OJ>%DD0G*0#QH%?bq%75XN z`~=i~#8u;9u*@C)Q!UN@oi}dh$oPf z4w$3mM=bsaLenOB3Rgcxeh9t$mCBppO07kLK|%puniAtdl);2Y@QX3287aTGurkeH zu)}QCeC53EE2?n=Z5+Dr>7i9amGNMpbNc9 zXsqmdmgA?uZx!RL+pp*#; zy2z^>fNu&5hr0aux$nEY@56p8z`u{^l?zoH!r_ETtTil90&wm5iQ}bI%15I6NOm1? zEN*;x-N+8d57{C;SV4V`WbnLZ)Ta9q?amM6Z@!9nv`JpK$012k!C)aZ^U=zD_4#VD z&h8mznB`RaeDMS+i~Nt}j}7*73gq+hb@ByD0qY!zW3-x@L9=*hbDBC@;+W*>HO-K4fZE9NN`6^J=xgG zeT-%m*7nkcq(G5O=*OFyfJ(>KWZr}u!wKHqj+bxGmlPMBGLA`p#Vq{eIe_x?@&FPU z;zx2rLmbt0+HwAxg~;^2^{lZrc`Q}hPka3K`pw^7zu^62$Z@YJ6l|lG6y>8`y-svE ztzQvm$a?&9KCm>}jVLVwI~GwrBpJ9OaI{45U9YdtmZ4?wVm!aPwok{K zvwgAV(Uv9MIngT=E(CIfA)j`mUdziw$(w|aBlRShrxqgtmf1pj4i zIN(RMF63D9xm)+?M$dlTd|JN9bL~a%O5Ja@;fDWVZTPb6(mh@@+iAN(hc-!$bW>EHzCB*eTI1@|qlCuUQja3+)ls2$vEvt->zmt`5{(nqxP@d0O%NV+|J1$>o zkJ_5*xnc$Sf!~7ae=0cW5+;GAdw2*o&3Mki!_FA9kSF2agKAHHiNTze44aPha-D-J zS+;N$boK8C)qhEF(D@yvf}kSy3nqomSL>IEb{AKAR}}PJy7n;tWbLuetnK{pH~q?U zXDJ1Rik&VSHWwviDJdj{lyYXw{*K<@_bv0Iq`hhH@dxLRGj}yT3!aieNOAb!|F+m5 zP@=Zl;^i*!f>KObUgO(SNjnEXJ#%}fqia>B&aFy`vBxJ1=hk1p0BmC&3vXlUjFfzS+g{Ir$vj{-eT2 zx;5IaZ^wg%xswLa8E>fpqEBEs8MD^dm0QalGAU1~Xde$SJs}I4KZ1<&{J>kv;1pD> z)@{KHpL8Otc2A926Uc=~owT(~oXy~J*3-MD@I{%t%{EHmYAM_)_ognbip z2;+9{cKyzUzkz2+_Wq-?>_*qa^J6cs3>>3l^CJxm`h4lUlr$=2rd`vCWxC3jUf%lc#Q2}WkO|J!A|YrMJ}0(x2scz` zqdpd?^!>zm#``q2!#cgo1-mku{Ngx)rjpF`@1Gc&=l=^Zq_br^zKMJy4X)vnSW2RV zNflQ+r-lkm&WztD7YyFibQK}z68;x}qhi_>y zqGc$<#n)plMV23Jt-PPBB-$iS{@rncI|z#l+t4dkR^PR~WBWmOtftW=^ldj@lt>RF z^I-eE*U{<5Lt%|M?MyjR|3d8GA4 z`%MFz0?3K_YF{++4VaXY3)9TM#h)oSf93Y(SZE2)c_9v?k41PR0*R=GB3x%_FI;m+ zXCSxsm?>j!K2vI^(+9jbA5bx)L1R%<3?MYNh^>{jFZ;FP4_cdvTHWBgq)T@BOdGQ| zei!*6&}2>vQ>X+RS3m9g>ir^(7N{0jCS-+CT&$U&1=PVl7=q zvRCJ9HIJRSx929a_DLfGxu8Z2tmNZP5gX$Wn|3?Fu<>aOQ)U#u9|00BR${^@l-*Pu zZSeiTl`C|^uyLsW&b?MLoFJtWaRwI<8*5m?dn|puRK9eN;oFx|N8WA1JB)gPn%2%wIVmsBzf|yZCUl9+dkMTBmBdRzZUTXjACh=FMzAh^VvB#U44Mj{fe<_hX9y>eyz)>kuEbev>MacD3#^tK3ohV=Dcrx4IdL{{W5`m$ z8_vtqj}^$TYN(Z;e%PFz3;0~%hQbNKq}tC)5k?(1!VVALw(Z*!HSk*MOOp_ZkC#7c zAH3S150AcGb>)+kek4)+&DNf0;2!AwP)|xUUO0=uk!VX~Z1$4`s$=zzae*=+pJUW4 ziG7OEMUrsn74z23oyj5I0UJ<+dID>2)$4G)AgM240R^ozDwtfgEbg{N^lN`?sU}Bt zx+g_Yy0#3H`)v^fE+y*Xa7o-vRIb7-2bt(2*FK%)V^q8QQt)OZei&C_d2XOP#<=^S zJfO+*uk&mBo@p7K60ZuiA8vV@VtE=bPUR2$0#3vMzRni#Ejih%p9@WxI`}WPa$Gr~ zi`UXh1T%*)fx@TAF@8=VXjf#VvouUCtn*F}PmoQW-RL)YL%ULl)mFw!lM*>ToF%MU zjpCDr?)J3I^r(2p*lL+6K7HFHLw?mpX z?s!pBz*Ge`^T88E@?sPkZhpN65hb$$p;FOwjU7M|1R4g!)WN(g;}e1<2J|Cv3cP9WN}D7Pk)$t|U3Ur!e`& zl)rP}!Tdd!cMG>tH3=dx;m*47si)PY)Y6S^2vo9ts7b*<&w`}3cA&i#G2pqyD+8dobkwTx0G&OD^gJ@kj3Gluzr zU-JGiCC_ z?k^>Bw1j7#O_w|DKt=WsWrJPf{&Q!-+D6!v-A770uZPm!ZZE{^|2@fP=TAbI4q~oG zKq+PclJ6DtTmgvu!kf^!oQY;f;Qg#y)FoJ zT*e9Uea~gv$QY{l=a0UBcvJ&5GDZ9RgM=9U8!n1~v`r&*+bph(Mx3(4$j z&uiUUm7E+m6kEM>4Yx;*Byz_0f;cB8I2R`FJk%j%|>HQ(EhXmzZCtG`+kElp zLVU*;_F>W;D0H78}2wvKc>kfa==J0Mt8{6#Ba!ZpS+T=EHMI`?^y0$)c@2Jawx- zH*f3Vo}Z$vT6<*3IS{0@(EF)$E9jyTspD2--62VoY~b0@O{1ee-tr;Vec$7ZL^15jxb(8~>glE+hJaH)M5*N6$Ma{r*|8p`$?|7{YIYxKoBT z@w7Y6*e{b2vh1GRYs>T!Nd+I8{kwnHG0CbIBf->Gz<+oB)c&Eb&I~}hlKWi`=e$sp zo)Jm0OUsbUmxcN&lbQ~B90Ahd(?tC;@Q$8x$<8oscU--e&dPdZz_l^_&hXz?#A%E& z{cHcO8OxUvvlab;16f)e9Ho$u&QJvJFF|{%t!?(h@}{$r)W)@}vdrflH#tVI8A;C+?ebfE`aG;!ol{EV19 z#8QFh`n!GC^NV$Km6Eb_xuy|;Ih`ZV9XEcQ0BIn97_0WnMT?AsOtx4!M2+Sbs=299Av@^8GJx0BX;Zp1u$`aX>QC5VGfi%ErFbT@ZiR=Z^o zb303T!7})VAkKy9FZ{dXh#3x$)e-%>xiodiCsZfPF33$;bh#$njK<%dK%DtQd~aTS z%HRGn#9qHF+smK8)S!ib1jKkjJiqL_m&Q$c_KTT{ELJ3D*@mo)?rFA+2cg333oX*+ z77HG-A#d(p;)^iTU~xqh5D<-|=0x|d7&8RMiSEP&_f;D2?7wSUbt<1(Qx;1==zW*N zt-#|U*r?3(PcqW`%VI-QA4FcTSPlW(^R|0efT?jtl-_C&@w2XvuN(Tb@ z!@c{LayW!O<+iFHj49}T&GmfEH;d{HDHUkulHgpRMiuc>4=4ZjqQL4$&oFY6;FVyR zq&@B9NA`ki{+k|d@m1gGrzuTxYNaQ_(Ys=#Lr18=*oi;&a7?KjQ`+>SNxQ#<;+{)f zW1_gBNHdABL;f8>ob9%Im+3Fuy97kscRgGT-xKe834PD|`SsVdoIS^?eaBuSzWvn0 zJ=nE3CNq*-HA76gG}I?jHLLmBGLRhoH1BfE5~i!Hg^~~CxCEBPOLWXJkhcC|-W8R% zP8hjE#+@(A8uy-jHrD9y{k31_U38LBCmILotUijwF>vT?nRjiOy`ia(#>&0fvSv&z)culPLllWq=gZ0s9GDUqnFT&c z2#LPp?+6I@_FT;i%q-dayLET5Ht?dD67%5GJFZ5`RyhCi9Wh2m zsm)Q2Bf1JH*021}ZtLNIC0uW3qGd^$EUchMgXU7s_T~JH6Z@xv|IXLj_yyFPF}PsU zRhz!2ru&|#9nqFoeGsm)z5r}C?A2eA6HTFTT?E$ z?hLa$F|g)NX4aO(rhpX1i9xQ;VyvcmP)V*sU;X~k727ltblyDTG|Rr*9yk%cKSWcz z#t4HGW5}XwA_`_>vJ+Kd68E8(;7Q*lQ{&0qU9tvI3kGr}Woq1W*N-o(ng0E>NSDS2 z74DDm@(TjS6l61jqyrZ8b=b$}i-pOvv33#2FW;`+P}RoC{gwg=B0IA)AG+=dlnyQ_ zDXlKbp1X5=`x1f2UwCvY|A7WyP~AMxaKQ8KIZBM+B3(AY3SAMbRs$p;dvxZNa4YD|9)>;q# zyky1j|62aT&Ix}tIQYs3E>_JKq)(Fy@tD~759U8YuWcCAp0nL2|EeNj@b%KB?9H?4 z-}4`>=fW-@AH==7gL)bM@n(&$gPY3X{}=L~L)*az>SM`tkmsFZ_OlzhXw8%Z$j!`T ziV3xcgtD94TgYz-_unJHYnXIy*&Ph=bR4TOHA{S|Y9ZtW>HGx&e!w@3*OiAZ>Q1GL zaoGJs44Md_Z)lixT&@9_BBE|wqItIHI{E?0Q9BZGJoO90QI)Jsfd6YJx21tF+KJP zImbZg@d?_WEVn_AU-OEvp^L-H;%2ggdBer?ndW!_?tjH{-^L4W)7&jkAU_P>)yYD3 z6zH{^G4iiwa?Dd{7O5f$)S?pbprm8HZkB*aqi?a40gV$z~?i=1dUQxaqbuoWe5`jXB)D7$9 z9^(SPt8GZU>-;|IUiL$p5F6E#3FF*SK($Kh4v28)*GxBh#zzd_rF$Pemg(XzBUr)C zg@283jA1160COkNF$^$;4!T~ne?4f2$?~!DbK-Zi+t{lJ6n2o0zyoJHxH&8FoxsI| zbi;S_IPoQeqUFJ3`aEOQ$z(AR*Zf2f zrr>*%V1s;|6XC_Q5_iM=s-sr9LSz}?P(F4@$%#NAK^o|f!Nz#P-&P%Bloc2ZPL-J% zl=ISTJS{6wCs0aK1fg8Ke7quJ+TqsgcFfXmZ06`Ln;tz$fu;zudPLVG14!{ePk|vY z*e^j7<})-s60k_kMsa7qc?cz~YbRHy0A2!e6Xt>Z_-U9uA$FA;`;0%&9V$wm{!oz_ zp)m_Fw0V3lU&Khm{NfkKG{ks}ZH5p@NU^1f=^Y(w9cQ zwiIsOnR4EN<2+u1C|C9Z?dfRtnDXr>V=lloyfrp2tT%gg=Mf3W!62vRwKq@;jCz`@ z(0Uomenk6FGwF+5dSqaO2Z2^*oIDKfJRh^VVn&wf_3+?Su3!a!p7HZG{2qS8@1>Dc z_>TC4P#v{a-u-z7sin7+>seH+i?>Q6rJiu%^ET9a7~!ooOV+2+<_+JL>LAeDdaE=d zlA%2b52m>lnqQZxD>iRmaJRgW?8G)cix>V;8$lC5ZRFM2;b*1{^N#t)8w<(~cD=g1 z^iHx#oD$;-%*UWKBJh~?pO!`_w@V}Or~Y|mM6B#rWh4gfBjr2Pna*e&|EfYSY=SQ# zs#o>e&&mjs!_{xDgLY49QtN_+)1&v@&9)6_<|N00%7`!8{VFV%Fu&q`!eR04d3B0s zkacXEVmmk9@OxE+2ku`E>|LtO+UZ?fw0826N5xY{Pe2Y3t0M7v@DB9c)p^>szI1%m z@_VDp^nZdi7$XU~Zeib21C+IU6} zzR%OTiq~?tF%!V+Iop2+czqOs8=Ip$=ZTvg>F(?;VrYUR@-Nk)vxJH_;Drr&?-sLO--i zs}L&kw!hH7jR)!NSYu-l_QfAQC`A@j#x87ri-$h{1s)7!K7pO@HxFEXWHjJ@uW~?J zg&DL1`vVWI-QiYjRk|gc+H1$cHod^WR3+y44|vdvTfRl9_hX#YTC6p4k+rB=PUqY2 zcyK|=?3==Y(k~@F$CPF=kNReXzG20Sl5gQblrs?!T3UX#w~ak|XmDowY9#xfzsj~nrR(BsLFFr~`VjW70HOJbGgn-pqx{|tagsKm#nKJ_fjpuA3?QWVp?biT z!K%%)jsax|M~(S|VQC=&tVnnNv|muqc>rc~D?y29I2LW1Q(&Im4T@gL9|v*;DGFkP zN>D_17H672RAe!GUZLi(iY4qEn6mM)hSP4Cxh(!f&Q$gqNBg81*}7U4OafS$m~!kjx)QkMpmP9s!X@z14ixX$$GK z!xI^*Lz7D)KEh9fN|k9!-tJG|@cjp*_o8WOeNnIU2wy@qm6F~9E;;D*ou5e0r+m`l zhQ1HxXA_9&G6kedc?F}Eh9?vv zY@!%^_pTBsc5MSarWJ7w)(xqSy%OEkBYTgphiSb!HBRXbaNa3^^AuuaW&8J4K8sjo zEH1skB0poHGz3r}i4OpJNzPKR2j8Wseqp?E^NhpuIx5GYRPXu%@X<*8F@fVyF3jk4 z*co@l%_gCLn&O=yir$V?V~{{0y@loMV7rqA6!$|rdZjj|eMT;+9G6&PME=Bb`{57~ zIV$~li=~8emlG$KE;61`=o0-M%jLjI$B&JQX2Flk=nmv_T_udpKiwO-jpfP#mWzJ@ zk5KE=o2Gb`)}#oUpR~i~HW`ar5wV=mO~}vn9c-KHzQ0bmGY7@&x!?YQu)<+ipE5B0 z8SM?As0sW$urlaFP}5^`<&PIoQ2*ug_vs#D;5I<6_BSYww%5@Zg#g z9^)9951yxw=;E>wP12-9IZM16lb4ms3!_Nh(l$AV2zw*$XCET8AE^C=gI{5to&#Q4 zGgh5;2l`xacJb`~VMXD16H@o@au$JvVuJyzIqx@#x?c)aHzPIq8lW!X} ztec^Oau(eE;_XSHSo`@TkBc5NK#sJ92Zav9VKcOr^fm5lTEu2Xt$V7roTX&&7HzeNibL^kt?xtuzbbyc8$|IHF;VjC%J40 zQ4Z~<)qcq;%ZgWB25_|i`Z}#GncGaK-JAG)Lirvtdt3TX^6*ZikAZc5bP2#8pU% z>YQC(~n?p8>_yF+Rpx^{AxN?GHEMC1K`Fad! zOIw;jQYXTm3B*xg^tg~{;Zdd+su?!}<0~#AosYas**wdr7tq}#`dzf+a)jw@Ec5yX zm4{Z7QAPdE4WvS2-YVP}GnSvV^5}l?SH*T7e;IF=AoqGCgpbocfnfi1=#LGWU zMxJ%-u{pz;)v=@TCr;u0ezwyDT4nhSMJ)&Jf;U{GsSf*VW75?<-%b4McA8*&-D;;P zfMYUO;cT@EW7ht%ds6Yvjs?b-Qw4=N#BQ21cPcoZ^XPP>BCj@oxx}T0{-SjB@6)wf zZ2u*>3e>r0dwEeq%r9thkCr<{q61wWjyrYve_LWtXSLe-D(2^Ua@{rs)<*JEm#pS| zY3NcBejw98u49Oe;gZD*H3`C(b{6Z3e0_8KtmS1hSim@W2?rSiz8 zb8GsxO;Y$Y34CQ*hdc;0qP)_ewI~|9)u_JmJpI8knPjVQf9${oH5p!wult4wRI-0c zozbut;&o9z;|@I(fweBI?_OfD;xh{ZwLEzkFsS;Wk)vfx%9|k(TsfT*>VxN;B9Etun}}y_|akCSri^ATr+6i_q@9n zpV8+q7!q+D-Ng*}-mQk~I1`x6;@!mE`*|7Nvj@{Q-yK9M9H$xtJr4lP|m#83Vf!NRaBM;oZPrEUqe=^`KQtbN!iwIm$C z{?(5@7d(Z^5ETf{ksx#!U;+P1ElMDff=ptHf%^EPvPa-@x6&E;uuUhP7r~D`Pp(B1 zNF*qMXxtAB|8{fU19~1-5ndnC0H--~#Iu$lPVhuYYq&3*^bQkqRXUQi50<^#~glFn|Z&a&V zwsS=lPL#%HL)czKTO#IfguMulg3H?9|-V){KRQdqvTIl>X_ zcG+sj?2VmE!uFT>(m{`#*jjQTeSz^q7BJn4UF3@NN$b^+sQ$X)!pASuz22Nl0t)&9 zasmlJE-nhkeBKvO%xsv~NGEZU?%B1bvK7v|cuU9?X~e&e8u?SCjkMjO032%%S6tH1 zr0cN`imrMvJ!o2Hc^t^Jp+M)SZ~^rbYW_;rps@3ZZx1|k&&MFTH-AfPq+qGFv2(RL zyZN}dhpi5c92baPSc(7~wh)rU6&(n4+S9rz0{oI`h@5q?tmF-0s`dj(uL#iY5+s~) zX0h+}GO4n&cCDqbqHb52+~#Yb2%`8drp6#gopEqn+48{sPqnORZwjq1uOd!{BvZ%{ z)ztjaL^U;FBZHLs&i2|jr(MZb819zbtMw974mhQ4F}2DYRWgbSWD(qpoKjFd_-N;s zuc<^f@;iV;7O6)$hrMQczs1$@muaTKNK9|+BdbS;yXulin4c%Tw>Lrw;w^E)q)wjb zuy_i1Onmd^nb6k<56ZZvSXN37TV{?#f-WZ{0l}y^I(X2jg{-vYSu4}6&QHAjjhYNb z*80TXg2UK38iuYFrv882y#-iQTi?b#bmyjXNa>W2Zt3pskWK-Ek;XtkLIH75Qbke$ z=@7vp6j90n1q2BNQB>kv1A_QGdXDFNpXYtQ>+`zKakz9lduH#w*7~piegAH*+f90w zbTlWQMjj4bJs^fe;qYQaNILRBXELTQ7idSWq!E>$hBdo6F*$HVfNhrV0%}dA0qAhS z^8jslQnqKs1-W-(g*YqTs`^M?kctDK1&*AQBtl)c{A4vM)9(4UTtZMfGHxk#;$flp z?bx)O3r}%EMgh!|m)T7okE&D$fBH&?hP` zbm-g89^tuud{^%rOc_-=oRo7i#L?WWamL?9g=Zzmty2ISy|4;!L_$-ax_mhOxwRB)40n3xvWoY37-eO1h zE3*C~rGcW&nh_(WDB0aX9M&DZ`x4}*rn1b1GoBFH~Z=3#e+wdn%in7 zG{J+5X0)1JY5jac&11fd7N3dG^x05#HBZ_$qxIWBXImF>oc=xQ-mH%4h4W;Up&Yx6 zR%}BJg;sk4zZ9}1c0t$K{+v8Mpn`$_#91|r!wp?^kr5NlPbus3-h97|%}~6@SrtA! zg})>mSa8|VuU^xt!fJtEa7W+YInU?w_b2H=mA5ePz@_MmKF@q zu>34y@w_8KRViUlr|z`q6@445Ro(u;I{^;gS*K*4T!eg&;@UZN^t<2pN;4|1!7wLa zJ@gLSF$x+SwVN^eCrjb76-~(`ekaA|!fa45z3+JkpJGpyI>hRcejDr1Kz){5m|#F$ z0oonBUETnjIy4$YHxq~>Xk}DBFM}PwRe0KP0N{Fl=8mSHInJ(0ogEWv^rAcWnQD7U z-VIzJRZ~GgwgOlEJ9B48v9K4ea1vTW@CQM_#{vHdEy|V!QJK|#cAN?L%G#Z_wnoR8 z;zvcI2+*SJXDEvVuF5O=jLVe4xz7=^NhZDyB|~9M?3cF?W{CC-z7SDk_jJv`ocZiS zbyDj+5J$1>>X!f=V7<>)jlD?m+-q{i2%S$EnPKOjJ=oJP4OPp(mJ69PN~BY!EgaRI zaCRXCtRePo=IFVzN8cMH_;6-_UabjL3zPL57NSDJNx>Qb_$VB<;UZ|}sL?KS^ua5k zm88i}#muvM%rNh-xz+2m^*=F3pB^p^3+hVit!O^8ZZXv%w1D$k0m(uCojFR$jj4r) zobh|<^8`7KjpmG+u-T$%q6M-w0bzz?hstwX!xC(bWDeehuD;uWZec+M z;a;Aq_55N=xAoyXK~u*F?F1JQ9xU6th~JT-;X^J<>!%*Pc1yAofBMvW>SYz{wae_Y z&X1tSvAwsf#Pv^2N)z>3jYULg-*gc{9NvbF8b`9)eitvZ!!0|1>mb!R&IM*I_9p}|@au=39}`9uO9(rBlK!l4gWC%v zBk_9OhvG3eoRI&4zphRH1vW-~`pQJ-2U+D$vM0<`rC}F-v7P(}{yKKrnomcMebXP! zJIxmre6H`!$`--DY$wkjzu$C1*I4y>d>5S%OJ+ z{xcqX8_mMuZsHD>l&{Ax-#g@Fwyd^wLH+jrCDkwdb^DYDI|jRBZD~1mA+2SJn1Kp@ zCm%eT@ky6JZ!}9nbZM3}`9qbk!7K1$&p2|5!|?^-zuIU%Y}!#K1hYKQZwck9S72bf zxJuO2{n%)h{@+v{{H?tX#~|n_&n%(k=eZ|@Pq{b~b?xy;6fpFc`Lp4jKEYbss!&vO$g zQGb$v4eNMFJ>d1AdG3PNJtoA-A2Uo2X+2^i<@Y+6ZSXk4Qwk^P^aFoX^ zw$6~??zND&?R9-rPZI-VLJ1Y0<)6|o0vmxuZi}tF82>l!I$O%j>tDyUYEvxPG8ZUt z!ziLIPyZu#9R=)=#9w-Fxo34%>mttaJCrAN1noIwrI%&=i_K z+Up}XQ!-n(_vi=sU?~Q8i4Y>}M-I^tc4lpx>uMgVyU6uO={!52>X>%1$FpKCo)oEt z8S-0q9T=bYmZIqXB?W?+{amtzs$<=YW<11b;NqBHpxR&Zp!qJAhpF5fICE&kiw)mR zx^R&{R@Gs@|K+cE&ZOG+=-?On$m&7*Or!gbWPaBP;=|C#?qe%(G? zG}atvQO8KZne-7Zf4}4qkl!=x=GXlK2#vxF{mz4iN0hv)Fqtq7C>B;b7?qI~@#p|P z!1M3;Ut*>5rG#Ui&%S6*%s;nKRT)8R49wH}DU#Gs}^}1wbGdVP^e^LC; z-7kM1U&m4Q?5tJYdg#S_VcqP9tIAI-3;-?t-^AC^ZpYWHBnby$MR$PF=iLd)l z^PuT=;_HOvm>%)NvN8kZunOEMM>)oc%s`|V+@HbWuLA50|1`kvH$-R}bj||>{jo{= zz`0|Hp3e>^OYl|K8i^+{=9O~y95BC5u+#eoNaz5pfy_?>Ut*sepN+!fC#3F6HpKc< zBsA?dvF{fNc5h%AY&3L#kzl90oFJMnY@4a&eV}*@n(G4$8D#REGj)^5b?5Fn>*iZmRl> zI*c*WaBwAUSRy~9%n73>2$L4gKze9Wx(10I>FBGI})1m7YTM# z7#DXfFuw_~gK5(n|5<_^G^52U*!&ZBkA~AT)QW(0GrnJzO|5&RjEcg=hJ=Pc9SD z=G&mRxz+w6zYd|H^qmR~JTQs93Bt@gPgRVcOsAGM+;5+W>c8sryZk!U{ksIeg+d2~ zz?(~oW_T%#GCW!0;pG^k?aaF-nEy$Boj$tiME?T*c?1?LW~}!jYVt%;>mkypf%`Th z&Zk6)Dq{s-zo~_^~Ey3}#9HI~sK>y{V``yyT5ThK4|~?I%4?@UsUl1fNy5!gvzgd4B)F@m4oof6Yohk%%nt8-jF%a>Qr#zaV z#j$#IW7WB2A3D_|U4bx6$P1G)@>u$H0YSI(U-{1?*jP0FnvII!{0=@PfmC1M<+XNA zU9h&QXSa=eKg0dy@*;wrjQ~EeOC!Y@;0rHR8UK3b@rn%WUQE*C$pSH8u-VZe?m$I9 z)E0`Gt*4MY@z;2ynrF!>OgLV<0~K}jgWe2|heW+uzBZ6xdx=3yk=evZ?g)Yn!!iK= zjruR4qE4-lh2J!_my$9~F1-axH2^!U`te(Q1p6K&6m|5~f%?H$BRwBGDV@l4==I;| z4D8$;yZ`S#x%+CHFM(J?KE#k>?mUArexk(et?&n8mTSM`ODLw*Zaugj9M1BLl)&!X ziBsxCgJ0af^CikD*iQxvyixZ)=OG*4)H)XTPM3T?U!qq~1fnC|thvvV2_3m{XLN(2 z{_qZ8g03;mR3Mz=n5tR|qt5bZLNC&|*d1sn4xv>C_^Ep39SQ+!wE3#_^T-z>^O2iku8VZo%QO z07P*=-P^|}yF6zbNRm^+P7+7Tq0gEXt^!cPfIaQuX71&76c)(5aVaN0C@;~TS+TCx zD})u(_ihVPAKI~O8G;U=kC2*MFlgPo1u30^;FRoFdn~qc4mhaF#G9Z*xB`gdQG{af z8&GI!2SK*20f|2*QOrjI+Xzn6S~?UVFN(YZg~5;O=jMVI@4(YQXTl$alMHDRbz#m4 zt7~tq$Km42zKT=oKf8<~mxiZ9TtcWiLUo&g8`mTry&_5AOtDZdN0AGo*s`(F@TK4h z>;urs+fJ1rnQR`%Z#81F#Tl2#s`+P7_?`$!cqRnoxa69ZbV66vom9=_=hWHLemozo;O3ULo~=Ne2J5X z6IOZUERdO)nkHH(>?P>+q?pPX`gaQs}2n*j!e(U2&ME^JYep!7`tq2zXGmpuI(I;T7U( z80;46>TduL`2d=(n;kSMbzUdK|FMee90B*wH1V11_K?yP3EJz?U#W{9P_X zzURZKLzL3Pi9;N89^aH6C0yF_NAeTsfxuT2AZT&%{Lj3)dOduSZ z0CRQQhzG-kF4W^WlquF9Y`a@cU=dE#N?g#jE&BJ>S{|Pa8^pt8xCoPiy(H$rUJr(8 z5a%FDjqm<3N_Q$f!?Uow6;j{oi|_f!?N z={RQ|);UH6Z==_Xu^T zgreq!?BBKN$!r>K;Fv{5Rk}r05~FA(VXjk{eGv6TQ~9SfZrpH`W$KsZizg-Zm*FT{ zMfe%&a9E-*$!ovH0OsTDCwv@<<{VjS5{g=-C$T!P0PH$|J&0WaO1Q$((-if-@8j!g z4sYZ2bTyT{7^Eonb|6_t`6Sk5D1s!WmNhvjn(={5t9G=2lp^@O`1xtvNVpqhe=E4UjGsUKrp!4@I&fzV_UF@fvsjX5*`&bG!XGAXf*Oh-EkLq9$?t3vxE>%m@a) zqFAyHvx0sc5)Sf--9dUh%#jRx={XHvzZM2|F>{{vTIaE;88D5b8*-Q&?={3TM?S5a z4ESG^%pv@cM`5+ykkd7A#4r<4jMbJ(Iu|lpk<-UDH@@4DyY?dfXkfBDr`XJ3o!hF< z9Nf>oR$%klNQLv9p4!aGx4-O2mJ_p@SE3Stqb#k|? zhKdt412(~SLr!Cot7-Mo&?Rq(FWZIs;--vYI@4}L&M4{X>1W0d@NhnMUXJn<;h@Z# z0pt$wfq!bqr9Nm4Pf|tnym-yz+y3p|QIY7^Ht{jA5M?S>pQOAmQJ&yXl-6kvKN>!a?IuWLEq-?-P?)WJ`iG+~1Ge%7+54)-ZhI?MWP%&nA4Gl^269 zrf9cQ0$bR94300)kEYv)T$ZCOS5*wOYwP^CmYc|5w%pA3)g%eRhdCukT8<4e-(-eG z`V|G8{lxJj=I_}3=br{jQB?9xiYFFTSJw1$A`T+hzW3Z@X+Y0SmfEPs#Iu`8KjKI# zMpMGEP26-iz*+5YtCi#F@haUul}1=3;Z)i@CmV_Bw+0?81`{nkLtS;)h&rd=L;0Jy zi(T)&T|EkNyCFu2Y_iem>!~ZlaPuB&zs$L6yTmGxAvjgSp=EOCuc#X=9euqmw;l`0!ZG^GpCFhgF?pcK^Q7OZoK7t>^NL-nGplDK zV#Pd!;AHx%u3j;Mo%u&wZ@RvKoVzUV%~EEqqw>wC} zy5n|Vg7xz~Yy=L9{mn*E$N3YL*T>@pqf!W}-~4Cuo%i#W8$`Qs%Xv2JTEETS!{w{t z%|vvC|2c2@%R?Wg5A7lGJ|Cku`!7YrMvqwl9oH^z**Z6zDz%7E>lpzX>wE2l0T|=U zum8*8&KEfA>YFUZrRJ|SaOp5jr?0vYgBa%j*Wu1|zYTXrI_v`!5E$y3m?GbyF7`hE zAQq?77Es{)0{(xN?cDuo_x{?+Q-~COwnB9J%;CAY2h}mRh#3#1Q2r0{6s|aavY#36 zvkzJ0m1UwfFdm-Eu>XId4gRA%g{IDY;Y!E+fuoA#H`^ulIga4~}3hTSi3&@`;#)VlM4qqGdePvUc+-=-WcSpXPQ>-_7 zx4i!|UiUxL+heu{Fg<+(_bP1_j9nOBa6Hgal7hnI!uIud4fTQRLRc?v^L)vDU1WUh zEZb>$ZFh``Je^kVf1F`*G0ku>3=>t|%I)F^ZEoUS@Dc6%H$6VFwL9dS{6U1A&`&F@ ztHlM;Uk`x%|B_)6Oqd~SavJl}28;PHmne0_sw2iZ(x3GB(+1^=ot&!5nqk6ETpF89 z=O}G)e>`*Vu3~$&>tF;9RV%AlspX&dt;1aZ#WVL`)8iw#f66F1`b)k2AQqZap=3w} zgJfCDvZgp$UWE_b-OM;^fWWqUYKnvHF_9noK-m zy_TMx2d*)8HC;N~j%DcLd(lT!Um7IwFIXa(u4Y3I$X+}qv`oCL6)(L=Sa{kSe~an{ zyo6OsLIMt?>Ha~!P9Z|Up0Jzi?S-NKYfN{;`n!qGD?YvLF=T>$4PwVu%-FBZp zTo~0`EZCHSL}ycW9aZjA|L(%TBI&fniSC=b&);6EKz7KkMH}5nl7cWbYVR6CyE&#b-cJ-n)0sQ4TZ;z?Eqx@qK>9es<*CaMf(k`*{A1T zJ|haG(WYq9Mv({t{csQMk{dG7@&(3izs{w1VUf0dStxvjk`+u07y##FZng0HV>*6q z6_~X$9@0oS?K+Mk0)Ga#f}Bj49%vjg>&T%trzVp6;5GQZf)a(#kGk9Tu4 zrhbWXpRRn{H$t*jX>N8Ti))maD)V19NBP{3VJmdY-s#Gt&doe^C1m=&s3217XZS8w ze1rFw=u56Al6V8nQeN_Nn%#jh?_9TTrQPcX{1xhmv(ZP5&rZ6$N%}}a;GAd{2w$_m{p}L&Jo*-kl_c&qEdHH8D);%b@yFb) zthdyOhwv9kv#_${*pl|^FTzxPO^o|=PHf3Lw}-DiI*Mlfw9 zNw(F;8GTS+(SW@a;f{=nUb{^YTX(rRx&v#m#S0;uZOC2sedMJ-^ zZ&Qc;<%I`i6;tmz$xQkj7wahIH#j4}1ou}8jGqCdf2F{k#Pd!6)nisgGF!(rO9+(p?Fe%LMSp~Evp;z@e&GlWEVg>Wgy^j z{>bG!FYaw*(bsG_!Q9ERQFxs6I}(iC`_tOSL81$3tYQo+u8U7yhPZKlL~?6hJth+> zkzF6kT3pTJq#<50&42VKJn3CF=goneR)xdIcu(=Hacx#n-nst+Pa1ErN}+KwG;gEm zl?4gb+%18^%kjH-(l@;3+39@MeF5%ss-jwp-M61JI)P5gp8jH^M33ecL4y9*0|JPe zB13*x-orpW!Lwg~!F*)Cp$Y?U+_1ma-I5B2i1prQpM8`WZCKauLDF z`8CkJ6D;Si4Wjo=&~(wi%G&6UQe>+&mlFTXWrxUix576(3E5`1U(Rx+M*GsZWac z>;a#YWxu$h2fHzQT6+1^s*UzY31?PYo~g_P2KPQ`MIhoJGuL(0m2jUUesoiS^5%fQl;CD(!T7Ax`}-@ntAoZY_pN_Nvl(;&qu+{M*lrZ+k{Ur z?3~pbM8XR3s?k!&jSd~ZX$-_(lD06@m&bM;A{7K=i_hi*u4r6$6}d{aZ-er3WNpOj zGjZog?o>ES;Fv1Sz($WCe7}n(pyR>0$3NgnO*)Wzou!+-C)R8zJ-Gu8Rh`EO_J<#V zs=atUT8$V4i4+x_tw;UcZM*Lmg0CM94&@vNqKVrfovAr~w-zl8qz3$lw6S$?Vhbp> zh@k%a(ROYMB{420Q}<6bvtK&+{1YZZmDyNzZ!4E8E1fbd`rdt|>Riurl~ZCip_)a( zZncyo%T_wqALoT~sh!9il7{A9bDyH?uOm<2hittV#C(cirQk19Cvo=IDXkNq@bl~=HVSNsD)W`_u&^Ub$synd{35Ci;2E@u64cE zhTG$v0P1PE?3s`=|I7P#uUempG|n8S#B9TR#Q4N@V=?AB(f?roj{dj%cVJg=-v*w( zl}}h6_mg^fy>@Z;7-K?G>qUzHvkkm%>fQSbqent7CBx&cZ4J-d?!KXdVWQ|7PY77jq2#%TY-9(|p!lqL z+D>O;T5CseN25r@U}CLeP-Q%pjk_0I7!R7^^;Fgrce)|2iazu1@ZIwVdMG40Vi@U` zSuw|{t*ouZ-%mc;Gtc<`FYAlrad~#PuT1N%ibkKqx9KED1$Bg^?XNEuZr;tSn%VGo zud2#mdr*lvFW4~hr}YIaIBg|4V|}5Z*zQ*OIr?|?TxY?8dbhrK++B8b^HLW#?LFw2 z!I_?L+NCp!d-X+oSwzmQoNT_bH=gGPw`d;WT{>#LTVGUvk~zh9!#k$<>$iSS-sEZ5 zo|BaSsrmx?MSTGZ8$nu-8wkUjuC}XVuYH&2MxrZQF32Jg;r1H5@m_hsYI@b8x=2H; zS^7rKOiBU!<}eRf0_~O;sErRU(&I{-exW^suH^8+p}7#C;{0A-Yzd$8qhwqA@Ud{r zfZbuie1-I-)X(LG_U*Tq_){f@WyN%eH+r%OW|$5DdOHu6KX8Jx1<|4thX1;}nE2~_ z1Jp~eO^gr+rNjQEBa&TylAmNAhW#inf-Qxsgf0afX6SHvV0g3H#q#)w+Fp6V@1sC( zI?16PckPOX^(*3g*W8Hd!ASj|DK9z$A*zMjbvb+F= z?2f?uJ-dMUz#}1-nlA;fCZVztE%V4X=*Ba;zPM^&d2Gm^JhOc%tvyTMwCqyIY&Ix4 z=^T{JjbTbsd0Kr;u9QZCG9&M`U$%HklI#AcF6e_t#gbVgjwMd@pMUYf^lDlX-N29P zBA1|81dlXo>++e?5&33B%)0U^1^=MBcxXm-db5&dQM5GJQg>K(&XJLDVz;_DYEDAK z`}AU$%eerZ+(w)hJh2>y{nf>ScPv@gXYr4aov1*E&z+e|Qxf+7Qe6yQzl|;GfN6t| ztHRS|9a5>SBRsyZx`;=-7i7-DICK(ofu1^ocV72!IrqNmVzq^_jbX{7BUf&tGVSx| zIHkL>+#gmK{B3m4U#n>>y*{5Kv|iJ6rq!!@Uk&@_}ay7>)cE(D>}m= zil_tMKHb3F(!TgW(^Yc{GYbXN*efqqj#(5EznH8SzAwIjeOY7&m$&!~uso6|d1CctvEid+KvZdD6 zmSS%lEs3t430?hKiNi>sDv02OnW+C)DvaIr$IkEFS9gB~>%qI=zdjfdz6lx9HiR0p zt44YC>~iU|%DwgA{w&Qm0YmyXAKQQ`Nw*aLl1#mn=*Kw?QD9-+522ZT&xrl%mitz4 zwVTxYkMv&GLcXoGilX5$+c9X{3rlJJ5ATc#treA);^M!&b{v*=e*-IO<=M^2JOF)q zK-g{nkX>XcF`)D6A+s8?1sP`K0ajIX2SwK_IAkYn5|=I!<#EI${jqD1dZ2&9_4kfFbSFZ&j){R2D>bpm>m;KVQkS_Jpbd9J zFdeHPnQ)UQG-)kE^o&YX@-_TxV!?^We{$)*&W)6+yk~dcwRr`otAJ+6hJ92v>9vNKPy?y@ma$QX6GGCyD$U9_}z#j%R8r z9rg^y3+t^jyYRqM^HApngznbOcMgj>BAS&3xu_WqZvp@h^l$QGn{p9=yZ7D_y2f?Uy@s8jw8S=`2T~hK2G6RnyE@ zS`iCIZB;N0@!N~7z?O^-ll12hR?35B7lb!H3@(@0a#A^7UPr8FENlUNA2-0E2LQNB z&<6Z{=4%<^rn{cf-iAuVNRwRUTgr(z!8?(XT$Jgr%uYHOcUjX(7ZMe|eQ*@Fa;wb+ z4OofRf@X4@M|4;1H6CQp$vWC?9@iW#9@-scy6JXbp?O)@Fn8JoazRhC%o>}4<$iCR zcT+dQd-mk+`*606+6?4m#om!pZGBL22QH|rC*iVISh#f$@0vumCt-Y0+xZFdWUtv*j6>$UFa>|6JYek5u#s+nW1#HCOmTEpr!LSx@{#Su$|*^YV~%fT$%{$r8J_Akbz zG=|E+a7(l~e6L6FEU0{8Os3K4RJap0CF4IhXRUuoxA{%DpVq2@b?x$_r% zy~5psf?@ZLoXALSVHnk1mJhpAXqmjAhcCVR7U=i8vHJs=#`|jUAi{~(}Ld_Aotf~f{lFR*Yg!p;0j3tcj7yOKorgUY!MwTIH zs*Z~%fywaOmFGgO;y;*d+w-ag?b+!?=~uU?IjLLnlRs-slw(XU}XG>TD<9pI*x(#p=`Hh_&Rj@_NL=#K`jCK9yX1z9^E%I?hz9$EIhnmIv(Dc zjt_>)UK>joOi;00yp^gUp!~6bd=bfkVd$hZ#AXP1WsOjZWu^F`+g!K<0i5`hYD#!o z(pWGs87p-_s_!%G23EbAuW0E8;4)>^#%UN=B6)W+t0SPq`<%S9RHx+z4|IKFzO8tl zNklsq#ChO-&#ZP+Iu4zcepnit7xF|hYmg)uqp7h}ZVmP8G!Lh;-$quKK^m$i^Zg!{ zW48{CzK#{EtK>}6xw~(+9)W6om~~_p)>g1Gr)Uogk&@*M7exOwTL(zLao0k&Y7^h# zoR1=1Tid#2R0~jO*YF_y?;^T&T3LB;j1BK#9bl_GfYsP%3>TtrNeH_@V8q zc^is=?(v6{9PO$<;24gG6VMq`k3MZGjT~>?2Flh&O3%77*=D2_fTeAK`4$~L&GqHH z6E%(f*=(nKn9R!^v-c7X9on65*Oi}9UX`d=V#29bsDGP^^~Gaz5l$)HTCfwE!2wAe zJL%HY`b_af$GKth3wH7RG}takEx7k?dUSl$Mf`BiV)8EzjME=)TqB*9eaN#Nk&vGO zIYo{O%oVnO(UVFte2l;u6xVu2@ttqMo~o1%ElLy2(|S2B>#t`>z9DrlJ9FU}`wzYa z35ZDW)aWXZe`lw2l~YXOnB+9^7@;yHl9yAAU3_N>UZ8?GV&&(Y>2Z8Tg5pQS;Msk< z(>XeXCi!0}QE9rMfy&w7ru>blT8_|_-$YUUN@I<}UjUjI; zQS1sz{$I}DgsxN#PY>G$r2E3`pGDz56dmu5#QCT5_vZ3*@uvx%YQyZtJxAR-Dvx+L zF(Wxx_E40tn-dF#MP>)gIt?cCQMpnl$SrX355f<_HQ~E+c$A=vJYV}tMA_?#qz@s) zV>r{orQc=(@0-Mv8?3FS92_OM zS>TLB_($^VO!j9cUkYrTxbjx0Lf1h065UJbxK{?8`y?%CZt3+?a0Mx619 zRvfrDAR_W~)2W7}O`6HzNO#pQ=F{%}w$+LY*+$1s4-c5R;wB2#VUqO!)BEWmml_?V zP+{3jczWL90o4iz|U(fJkrVvax7g9cs7RqKb$8K-Sz z$39(YWF*K={14@;A-S22)s@xs)P;OqVd@)~qC>+?@nt};{%LEfR=)hUIWChWuO0r(Tbzk52Y~~(c5V~AH2M{o ze1UCt$b3}8b?Vzk1fSf67yj{W(*NIB>!I(I?%Lh^1^64h5%~4qSO`0PccQU_wh3`^ z&9TlJp}Thr(1YoD1qTD)>9!|?{(j~%2p{J#9HXibB!2t0k=%5aY{+w>L zxXW0CC)@`Nt{y?W`)2F61ek0wQOJEL%!{-Iv1DYc`}n3ejV(YTb3din+7 z%WG9i`}Ja%Wh)7|2rtNZiBEj%%|LoSS(iZ@kiHXph^D+q4Tvo=jFpsJk5lXG#cAbR z?KN~*TW=WJiL<4tU&FFK+#PK#HU61tuXSTi%qNlsG;-U z(~D6P)Re#t>}c-sY4^n5@H5c7>k$8s8alWhHUdvv2dY~(J+Gz992|E)94dou$e;tO zf1?-Mb_qVQdsc3xUmsaaDDAtJV%I6cD$Batthq-&q9%G;f=jWQ!FDd;i7!@u%GhF#KrNXf4IsoIJWl$Ier<^diJ*$;lR@`A4(HE9FvA zm($y4WfL0r$PRMMHw$4O{Ha+Z?Yx>LT6d2QHQ!mIP50svJO~&2hZGDc(Qv;y%F&(l zrXxep6%wD71EUJy@NE`PF^xTURp)1kn2K3>#kZIrxUc)7aDFJkeA8?bNu=-#CHrN= z9`fJ4UB!FN8c;-kD8Z;9&dRZ^7ST6S1c<6O zYEVk?DT&Uo2&JNL;B6(Cl9GJJ$rK*h6*}*BQKy%;eFjU)c6&9|%OZJq=;zSX_Uy04U?RbY z`ws&!TVHJmU^@9Iu9o=?ibQ~Jn-r2>8 zJsh{M+3RWpe8Qqth|nj*DB7fz&w2(IQxd53L9?^l}ZJz*m9RdN!Efed!6SRTa^WS6We$@ic2fQOUuJAp$k~fHIcSiCL9` z5G^$)$NNk6R46KO$08^J!(-rDCdJ5^AZh%@B&P239Qi^hYzZv1ivxv!1+veME#{!n zNHMP-Nw4S%y0G{_I|oG~0lx@!f1C@KSi;f1bTlyi!ljP*GKPv*;0tj~g^U9i`K7KBz$(*m8*J_BS zmt;Zy7WhrR&WZ1&6-zeXX4e~=pJmGc^b*HxXiKzc#C%fLTHN5EbhyY}8=a>Lbx2V> zL;qkeG#aHnZi4tZbXuQxor{S+*1bt%SojdU;806OE1CmQ0>#smM~hlYuHJ&o&O5=d z7w)*G)&qQmWBCN-XlwavNo#xbx$1lVYW;&PKucZ}OTb+%OcbJixPjE$vkJ zoYzpcuvwIpcyAuno}r_#bCt*m13SFcZ%}vNjnIy+^Wgc$%hrpOB-o(^0a}6=+xjGa z64clzV;6n%Q;YU-{1V}F&rgL<&#a(7@)aoFQ>EpTvSn%7V}~q8P?Rbo_%?7x#g~9%ikg*dQI$$Bm_Wh93l_r4mWO%qIgd-q&~IJ#WGfV;#AgDG=S%0l^Z=H;3vQL?v#gZLg- zt@D3Iu*1CI9PpQvuSo4Lj-$#zj_v1H&FSzr*)*X@Z#-YXQPBYQsA=qS%11UK_4cEi z&Sr6twncz_JNQ>9P3&`(GwDV(e%EEb^Fe?WJ}ZpE~3 zznX~Vkj=uwkWaF6(>{+r;7VprD@T14MR3uBU0tB_tHPcC;2Y?W9{D95q25HSm$^oJ z0|f{W4(NyEd%^YD&{;}wCbjJ(;+cquC}r&^H{&Ca1B3nB!FI6Q5WO(gX(6p z2|w;jOB)W@is)QqAlC)x8E>!y?6n}w@L8>Ih?=Z?*E-}e zWJVk|(kk&ilSG90&RL@{K~~sy)}{kc?4bu2;B9)C5$t>0X;I)zBj53L<>zpn`=mNZ zQRFE+hamsZ5DIF1~l0HOIet8eKIbm6Q8J9@K%s`nWQjPzeEDuV7pHCK&v91Lfp`PH-?7XGh2!b zsvO!~r2SKv7qP~~1+oxYj9z{&K46%IJxzGPs_py@$1Wz!5YduKhP!??9KlBH3)n3HZ6UZcds|7kb$8CTuylH)AfyyoC%FVdE_d}9Z2k%TZbt{!BUOM z;h>1*cKIyW=ya%IjUa(a@#tuw(*=23m^&j#xdazuxQyk?{M(xLPTr&rRP0iRQM-tcP`)Tcr=$C{zwq%dlbY#^81 zeh<7MCddkKG=efSHjdmP&c;6LeH21{{lJC80|o9Jw_rbs#XaKQ#?q7(F5R^V9X9Z$ zLmvki6X3W)SmGOntf)3qZCAZv1LqH}3K@W?g#Li>S<5oq1%b~3W#e)#Lu{{)Igq^p zO&OTzsmsuDcAje*8bl768)hjdn&KRtE~+h~i1@)#crOpN#vbBJl&nGBpXdpqXfDSB zPCs7U?~e#vh|+T@bxc9D^s0W%hf7Z0icmQumJj$MZp9KYfhw9YrpT z@95KJLyv~YSMo(;irJ;Zhn|h-Bj8MK;ZD8*J|KyV$I4Os*-&54r{$0C1#(hSs4sQ0 z-3+_W2k?Vl#6a9JhA~oSz@s#ULq~{ZE1j!F9(SJIeLmbhG}QEj0wQ3yXfUS^DkF+~ zUY^hEsi2j?K575BS`@(nhV3x7@Q@%UB|z2;|A5>GV!0N3_+zKChpi9?M_3lxf8hfL zGr+D|Ynpg+WPtXp#l7KzZ`aL&@#{Ch<>bN)6BSY7fpUFtY{`b$2)&d=8}DY8JbF>) zH-p|=0ArL7I9QPoVSFH1k|)3W(L?^ z!cmlbK>4tHhUnkB_kIBV-UU3wP<&<_G4I2TTsgy&#_2#9VPNt!e)oLA_y$y?I|N@a z%Bhsc#@Vh`;IE$|Ov{L#W1}->$F>2AC0=Zx0`l?$Syx1_Y-Nha4y)@H@vEueiSzK@ zC16Jp3E}HIfsq&h)7;?V5dBMxu?{Oq!9xDdX9CxJ4i{RHO#+k_j$x2jm{W+7D5Mvm zk>Ji?Jnm*3Pgv1d5r}is`4Z4P`JqW*T047@Up^cu56#Dxn=8@G(X&ujS(ZH~g_W)G)e;vS=KA9GDJ5t_Osdg;=87y8y~ z*v6^`p&_lh(1Ww?*R=C&$Oz=CbxQMx%{ukx-vjvHvY?=k{VkC*?YW zBYmgXk88GaF6vWrvp2VifS zj8@@~N1c5Wmv>1Qt1_eY01hZdz^cIM40I_Am+7_t_4=k}VdZ&!s%PS>>}ufq0jG;+ z-F-q~MnB5YS*^OBAZY?-7Z?sYuV%`|rW2S7P?A?naA@El(a8PdDN+TZf}0^(&vqs| zZJ{CT$g#V{^fY4isR{QM5a*W5dZ_MTbr{5tRc0P5Y_7%(|`k$3*<^bv#8vh0OtZF$3u zs(;7#lm{~f;Po<0SPugye=!9MKfH+at!^kt_Y z3(5yuF)mTVWxM=3Re-NkgVA_fY(Nr&!x~0?6EUyJi<44g%(nBSSa#%>=%p=8JAUP8 zao>&VJX?Ox<~t`w=!58wgBfAl&rL;>I_Y-mm|Bfh{E^a=_7n|%3}Rrn5AEkhT=+8d z7}m>)$3}gco}Y!7@iQgZwb{<1irRvW7K=F%FH)Q-;rKLW=}S-lVjF$OxxBolbW6rS zjC+~&D;xW*miESDyXd=fbhlFm>;hiP+sK<8CCn`*uv>lt{=IGY#q{KKr($sPD;q}Y znTfHtn@E!A1#lXB?hF2d7urvg-3?gyVA)PSRhD7vXTqQAP6FgfRY5s5(Fe^fk+fV1jK;e zUr~Z~PxqNKch1Z^_cL$*W7E}T?PBk}_6pDQU9?E9&r5ws>#tV=>izl@Pjy$tf)3)o zJ3G3>6Rt2@kkNR4+n$hiUj1op9LX>HM2=Fy-E+g*Oj*Z#Ie01F43=GsSqFg@i`;Wh zxjJQKt)w9scm2?ULG1mM<%S_2vw*O2scbWmthI;7F4@kI{o@(?zn6^x-KS` z$nzv7~7BvKdNPohG}D4&Am}Ij#DzKVGPMnLRu)Ee!E^6<_v!Ed!}QfN8S->AE>Lg zwM7CF1D+L(U-kpmbp&wudH{9R7pTfi>*dEK#&5i(*81ywq6w9+_l5tRNZ5@dpBgT@ ziIfHFhYDJih^(1lddVC(P7WdIP=03}9?qDLaaw9UW5>wjX_|#RzdtYF+Nvy;F`#q1 zb;*v~OpDoCPNX)D5d78;>w&t^!xmsxy*+H~*cqVXt-7)tyz_+5g}iSgaSqeGp(*DB zSU=)DVy3#2yDh>PdL6sDV`R^9{B~V7i?#&Agw1FUR9u4B~{iFW(~IpJ;FgSx8vShr^SA5$!tc4KCD}be_aVLTNHb?>IV6d`%xc*_>)zbB`h$(A()+ZtzdG{4AHaayI3ySFahM5K zrPFCEJ&wO@H2?075ZJ$^l83{W{7D(cWbl>HSR2Xuw|!b9%P#<5kF^?- z;AC(YB-sTs!1Hg(Sjs;jlwzK2otUBU-anXlj}IfK_9juIA7(Uv7dri|NZa?j4rN!v zet!B}zvUf;n)H%<+yH-bpLJOs;i$ETACK&RRL|h%sX}EWWM!y%E%c0+sfrr`byngZ z^b9W;s%*^f7i4+et|e=l_4W9r%si2zFibE?RHMjOKb;EFyl zm&4zYV+Ag^#!MIpqa@$Y*w41HAz6RZ&EN#!y>2xs7P>t=l7IAmv=g(*WD8ah(LOkx zanjB&NU|nO{ayz3YlX#QvHtmgv4+aqp(l1P+2>@@7MK3RnfX9@l6;t2vfG2#p`HW2t(5{W>3oT-hk zon?#th_9NYqmf05?Qb2>l-i%Ul8E86Phe0i3Bzf^!WudSL9ybMi`^NPIi(Pb%w?zGPb6oM2? zJ6tWSt-L+l?0iuH&=2!OuZ-z=NS_!^{DB-!luLu`MdJzL*?72lwuVEt12Fv2%&}$? z1Nh|$;pL(8ap)p69zTwQXJ`e)&wJvu{uR1s!V<$fjwu(^v-t!}(Re&KPVPt^D5$?? ziaW#2;BxIJb?9A;s6vvz3Fc1eyt{wDVEP9*u#;llcTdOjoT7dp6wXR^cY(aLp*43u zK4W)oyJ40h?e##jA6k~oP2R}TB3<<5X@V#B;TM%9fCd5|=vEn+J(1Dhw6`+RLf(#* zQ}%xO>Js0dN+Vte7V$85$r8b#++1;9;KFj zSaZVkKyS1@MYN#4$)rJeW_Q>!jp1_s zulD&=8F#|1oL_U?rM`RoPDcb`%Uhokuq_)-VxhFxiZS%?^G3k`p?_S1CP3ACfaOMU zTk1f;2h(YV#7AJ?$FB-TciZ%6nnqqz8e>nN0)6{dxD5I?JQeYbt1Y6W2UeO1+}1=7 zO)SQt=mWV?hKQ%WQ5m=Qvjv$89a9b$Nl|uzf0P^5Cf4Iuj_h`KosVWFsR>aD>Z@1A zv;=?ikLP_H^zN{pG~3;w_1^9>c~ea_(*^#QpLnW&$3K3WcC+C0XU!K1X)272g)mOF zu}iGK3Lwd;stko4ifG2q--zz;W`>^M^f-S|0M(b}qwA7T2D%(qrRJmKcp7>8r9c`% z@8|7r2RruFwNw8N?YpLnqDO^{bq@0;x3#*H=vk=R0YjU+m9G=r6Z&gBmG++8=%4YA z=UJM*(23-$I>y7G9qq}9SBTnJ-LI~E#4S1MD7mPXyq|uOP1QR)%$Gc}FG*6+VT=tw zebI06iyYbORglA4Er{ zDX~4sWbV`4T!s#*soRbNkJEO4iH?X*?__|@aNqzG(i_EP~54LnS($o>hU z(~WsxNEBU{n8%>?VpcfKT4Tubrz9yVoC(^f*;b=#laJ6yIL*UEO^`~+=GOrvNw{FA zJ;x1(zgrG=4qS)-48Q8Khgtn|>$)T%#eoSHq+@=ldd1RyDfy51RnMWy3}Hh$zGAw1 z?zwBHFDcxv;_DL!7a?$%@6hi^mm|$uSIM@~ntwNS0f%WG zbSHoFm^T#X-DFTLK_8M>%DuHnJ#H|_n+q-$8aLROXyiQ!nf{e7Zi4d<2g2pqaogu` z?qLa5yfiRY!@)a5YHHO;YwrpqDrt@EE?NtXqk*^QG5`GU5UjY^|FLKZU+&cHv%R*# zzTce^YmZpwcQbOn|D$LrSp{j$Bdd+{xuP%n+UrCTKfx}hM~o#{iOuD*e_e45B+&Ky z>?a&~ykq8qS}4mya>1^!TJbq zFeZTgwGo~3z=-Y>TG(W3F{Rm~c|;LKEX^PI?G4K1H_la7K-IYuK7ynzV&a9LvQ91B zLpX8&GNMP_7bHG1Y`vsynL6zEfgsic=D&ayHmUyH4tDiu{&~}p<%A#Z_uiLwef#oC zTh$6YDlwcZE)&4HGWn>X(3u65ws}b7D`v^viMn5x$D?%)vbPfyP}ZuXxak$Uo>h0M z!rL#;4f%)VU~6MUtBjqfsbeo|<``!41o-q$9YS*2xkEXP$Dz#zdhwf|3u5GK1;0gE zIyD|F2TQX)9C?DYGKqF(jFni}Em>c@t%T}ti|PIJ<>#NB?fd@$%k#0b%=?z{S#HIZ+~`Q#P~XIiZdDI{>{Nuld=Ogjn8X>B#+j^0#{bpYsFWZ;`)6GgCd>%O}tAZ9?zZ?3ZX*?qB!;72E<@ZCJ>I z>+e|W1U4Bzy`*~<=p4mZLCJv;Ab0|Wfl6wc#r9jJjjBVEkFD9h;?cAa_55j{_RNQA zrN#s^erf*PW<@SvdGtqOgWvaQpLpDJB#OgObY=FO{MYa2*&bXADM0by14W31F0u%W z>>F`g*>__(+8N z!S7Djg~1RMFEuD@fP~Bz=sA3Bz#b}$@XNCD?<{~JxRCb8Cv;eKqboFuy|&BA!zRz8mKC>%SRYb?+fPE1#! z<>w$h=jDl^&jYlJg=dRVe8BX-15Ajapasw%gWPOC>KCnB#}Inmx8qs3uX7YwqV4Tu zAHo5B#3%3S`qC~Csi-WPNO6*v`&ctCD1R|T0AFMe6cD<8_Dy=uXy^m)uH!^k%Q<42 z1%9pXMz%tiY}*H2t6|n&0g4G(i@d5+@w?YS4Q%IbgXDystmd_y=jo-T^JBfB(6M&- z(g{7YpXuBZ9<~k~bys!2D>V1*?XcEk)qrZsBid1HS_lSc7nUg$ECuxQh}3XW7;X zX-Ivp;)~6QX@7NGtsmEotI~}(O}tu|2ry1bH#=K8NHl!ov&;2!+jH59grl%Cq3seK z%&3!lF3A=aXn4nG;M2V{GMD_@-=d2h%7&;M`9T{V$JZ}p3_5K0p<;uyeeedVvX3m^ zI$*>#^g%NxK9+IN2)z|>dXb_jY8C0e{to<%dpPH~->!(1GhzS3Pzk zz4CZ`Vb4pVTZ?z#hD@0L!SDN3PCnSuOwf+w+D_DQS*)zIC*2Sw`$K;>z=~DY;hH-w z?UWmNV(n$NIGkvp)#qf|gRQ_Oa6;M7=zb~il`6ZEQfsOqswTWHf=pslIjv`^bxK3X zH_#WBQo4$(D`k37f`L}3&@|7np{I5h#m%Pb5qJ@!>HsGncF#|%tLEATWdFDOTd$7Q z&?ZF|EFry^)dAnnBS6;bfztZT(6%$@K{PPW7rS1Qk25;xt{rm{b%lVOrl286p zHe8?1rU;%du)yV%_6C5%J-z|Zx&ZAZrd4HuvGKxgiixux3SA{RxR_{CnPcy@c#fPm+%X3J1VjQ3#k7TnA=@(xJTw zD~*l$DCya7*OhRk6kpo5{A;HM9-NmH19HJUJoi@caYL_c&5s(SnjH1~#4zsW|A{S| zN`w;5t(e8;hPCsF>|Lo|*4qWo-pF>o5=bW56y$sSy|M;&9>s%|Or3<*!w~qVQ+S+= zuZ zGPLvU6%Ia1vI*b+aDP@hUTyZ=I;4MOyGD-pX_BHY4#Mu&{dwg%B;JB2v%GXtx9X$p zSLPU9o9O>>_vekonNlN*28UPKJd>>tnNEDk>J$AJ-k*`Csb5*PlDj+%4w;YD3e|=3 zU7yF^pScq+U7Zebws4=$f58+Vd*$ts^OXMs?$6r&>j_i8kiuBGBRfVG>~E|+PL%caEwlY&p&|+0SMBzpB%2I&|T*9%*wTi^O0eJok=>> z3L}cSV5$xW&=2GXz~H)xpI@ngk`Z1UI&xft_1pVJg{+2y3S!B41>UhkP<PvXW5`D(>**Xrq*vOF}f%em{+QAyqsT%6qa+!?B?U!eoXswK7{!z<`@_`h8MXRIrr0n#kmS+;T#x4H_4wCkFl>u@b@SXg>FtcY=&oGx?%vk>+O`Wai z_FH8@1YP?~yvF@q@1D++?3*rcHkFH|tbkTZkiZiof$%|IfN~^B1XK;p8qBR3mM$`W zc^gs~4|+v=C@=UFG`;m{(7!R_j3!0NV+OzIcdbT-2s8nQQV1mFYEKv%axOIfQTWLx zLm||u!3cLuU0@A8XuST`Vp%L+huU46^Vx=<-L`)hyWY5L}c1$me~2LPeSN>|UbCTjH4tVl@ z;_Zh>T#{9{+lj_ozNaE8EA}m-FlHyVMMvpt{z~feREh zs7A=hiK(id-zV7ENM&hqgqCBT-?$VgJKcaVhQnBK7JA-qmcgXdfBZ0`Y_7e=CRGkx za`hl9w=PsXN-bk|lGM)pQCzpN^%479IJ=FnAGV#v1%g^GbLM}Pl_#PMIj7mT_P8aS zw`gE;I4*S~w{boQg))Xl@&1;%U;gXNofn&tb3)n8vl&t=u{YP!>g<5+ATjxCs85UBZLS${C@18saN(F8R&sC#k#k-NrQ!FD(Ks&t6tO0_n}^ zTH!8BW;Sf>oQ~GrK;KoiBtOW?pHOd!#XqgT%owe{lG1mfxEPVW@~REZ8FfvZdhO_; z2V&OLhRfr%-@-l=zOKi~?NGq=^|)xM4!w=hXmd&L{l>`ZhhV6ok-0wIIFE_ko!R^G z8>4?FMG}wpc}~_(?o@XqzZWBZV2V$fI}!g!ecn*fmg1&BpV}3<=f**!cW7tt9ReF( z*x>Nr^?7PDgF)_a9_55fCA_#h`Q2R`{g zl1G4Nh1=QtAT9ygy_VzLt$w&J2#A)r=#|017WRR_#JBcpxLrU=q~*`=M>8lyiR7Hs}yF-tJj22iXyRWyK#MfCPxM_O4(R4e{udxjeY=`ap zHEu#v=W9$mF?P;Los{P+%ZrYtWF|QnH!0bc=GyD4Ce56#mp551yC4)1J^->NEUp-7 z{gA#`#f((suIBHO=y3ZIjNhg_7#FFmCEshR zF#Gy8GB#^aq2O+5(C+*%2m4Fa$|$|WWl^c!u)Aj>zG$B6TFn3DV82OR!USLIq*bgB zHs*aiQjl<{w_<-96hKb6qUt9se>qNjQ3(&Ou9p6|9ZZ9m40V-Mz)oM7h|}qblzD`$ z6kTenL=Efrt0IdS8QkyUz&BSp2WwF`T3DXz+{}p==wEYGSNlyISo(K3v%#60-{!U1xvrPPXL%x}gbiF{d*Z;@D+->wQ*zTBFGk`|wYshj zT2`M2ul*DUuI1nH4)D><=y)OZtk+a7!mPl)W?vkb7G@gqu=+gm)?qi1dK}J;?)p1{ z;57dM-plExW};iG5dOLTv04 z^dnqgumz*}{G}LlgKX6V)|7>c?>jgzYY?_xAXCxd{Bbb;uw64{8n?O#rM;-1ru^>i z(>6TW4Zgr{o^AFGd8Vusgk$S2oQ~q{PfzvT8tV3YUYG`vqbqy@EYbS&$ja{A-U8Rpf0LuSv;FZ^e;Ei z3@S>_D;hpjs(A0MZJPhmfGNae>Y2IaE)XhB5~tGJVJv$vn^G9Y0Wv@5Srz{df)ddl@9i z#MGM`59Y#=_q|0tHI!>VYm7b{FaF;iud(vzw0d&~gPPf#>q;epv2Bg*%vZ9(a;<%N z^k0YT19|j+B3$21%W-Y*aIq<)W{tmFM<-ic{oVdw7Op>(-+$$O+=%dnR7CEh^w&sp zeF>@kaD6^@B;R+!m}fEI$V`z}Pf7BqeBMF0j^0}Ma`IHe2Z|->>>$xb^ZSD#Yam=R zV0TX?agwi*)5TsYPf4DmXc;Ug73f9dOu;=EvF0I|x40R+eR-&|%Br1X{8^DH(;>4N zoCk{7`Mpb_W<^YTELUAhcPv*mUPX4SAAsrk?MLif8503Zrl}kE<7fEf&ZQrzTl`Y_ zAB@=dp3CF8`hCzUl|476*%H+oJf({BKOtgAxwnf;mMY~32b?x|a+9IvN$dH{e_g~5 z_99Y6auL=CevJ{|L1nv&z=YNR8zXk)#A`^SY=F`>DYKls>O{|k*T(*GNbFNM(m+r}4e z;{TV7FP#TuSdfoT5F(S1vQqCN!`}Qz8R>&B+U?ZRlRW>Wr~cDCsUzamakI207z1hY z`n?5Qed@Kh@3Vo_iVuHpV2L~m)em;^hqjVjk+R$E!Jj9&@cAJPE0A@lfLd74#>v~p z4?w*!V@sK1m*_a`1L-oBC%o|Zr|~5m%>t58{LKGgFohYe;=rxo8Vuf6_P#Lf3}aKX zNH(ol*{4==Pmh&ygbKByRB^35MJydaTbkYQ`USGUjM6W{;|xN=7No@8&Ft_+FxFZG zV=biFam$EQ#b$A})%LHsebZasnkfKB0`o-9gIA9&RZ@R_IGg$6%!1VNR+><6*Ry3f z&!2~0L3e3nQ&E*rakkQr^^LgCbK2ydaBd|_0*qz^P-i$Hf5-g(t&kO*gclLxWLbFy zrbX;`;hc)vptb2@2WIMk6EL3fQ~+7_nef;^BN1~8{dkYbO`&Ek90v=_Tg(>z7-ke; zkqm6OJg7PR9Zy!OkS9iI(lXmzy8?~FkLTrQWeezDkRgfbPNDF5+7q`>aXbOhy{CTM z)eEs;a`v(IadLwx4mv5Sq9|5F24u_KoO*;d-RW}S+KR1&KZkQ6*3e%}=FS7o229i{ z8oJufR7*@K-+!szi?4#fafG4+xcIfm`(M+`IL+svUj4>e7$ZH}ayKjo#gI4^oQ@zJ8lneT9Sr7$=v%wiUo3t<6CzENh8ddl}* znb08WD&4EX$k7idV1mH`Yz85S``GBKL(4hR<2N&2>Zzoq{wT{xL=%E-B8vP_3$fw# zmJoVkNoFIuFsbNQt+AU=0rCQA3gmY@nIBmfDo?#qN?3Z7tlJgD%8neN53sX_EnM5; zFFCP@KCFGupAhG~B7B>%D zJ9r$l_C~#gt)3@Im*9T$>FakchZ!#Tp^2>sEDSvS?Y!ZFkaG;bP>g&!<@K!dINa-+ z{#%H1z$+q1^79l~I06^B7*yu}G&GEqq*-S3hhJrp%k}y&J|G_#gLx~OGK%hr)wV0F zG-Nl#ao;hKNu1oeb(X9(%BGnY-xmWVgI58dg%bgOk@zqql#uX@q1rk;rRPBwEs6)z z@_>6m7aj>HTaX>{J~wgXNbqyV%W{NYWzaZ#Go~ES;rG5DryT3ta-vP7oiEGcOYz$+ z3DJWY(_=E~MUr~_2hJ6)FCXsu6~^L??EJ1$OZfyBr|HnY<@2#U;-an~qe0Z&^*?WV zajetO{K5wF-WFd_8(j#usH0-)#lYp~pqSh`f#3i z9Ly$`4J7WOO5UxVDT^&z5sHhBOkbgQ2f8ay$n%P8=VzYa zk2;F)=?dUr9OnSAMY!6cp^Z%dzwpo}gEz*N{9kAJB@Y1YoY3vt4L8@6HI|sGnM>js zI_**#?pT5&+}ohS?x3hmJ;fQ5h073u%sTYgJJx?w#^339i#2$CZ-WXHb1}D}Pw$%K zA;s?Z3ai&@hi(U4J0P%gL1BHAI|{6VhrW>47@jl!enrjo_86E3{UoptWfa+Lo)2#q z*_xT3jlS++afXi=8y7lf_TvNCA6Z3$G>5I15LE>j6M*Z9p6!gg#7GV$`48#|kHYN7=Z+y;fu9D?LRncEfKzg3(?7dO zeaQ&2^ibm&&earC+2F-~U}-8>FY&;zq&?G-hKaS#%w#-eu&$a5*FaCpQWug{*yO#+ zs2o4xqh_@0u;fNJ`Q;(@eRbZduy5Vd_8pExbi)JE+EmLHmw_u0wzBU^G=d(An7OmH z=FU$RKdv2cbACnv$F%{#6>zlF1sY16FX&bV+cKH@)|Hx8r6sCS0$Aco4VJi4Ip4z= zaP;xXst22*yc)_wrS=H~Sf`(R>yMG!FMT`gPH}E$K8SYv6vifv;y$o6>Ou&Xo}Era z9?1>WlWm&MmYDnHNlsubjd#*c7=+ZBNWXt%o8{pbYj~FUq!-}ZvPa_jJ9z*G){pcZ zmmD9e#t*AivBZI97k(g<8L_Aq+e0#k1nHR98xf2oSy6ojl$MD!XhJ?*Jp*Hahru0% zEhBt$<-HVC4u|M9((19;s$m&l-Bp@T7=Nig(Jv2iWO(qC_NqjfIe%?6ooKx-VxWlP+{9_s0=l#({{LPin z^4EuLi|m09PVBtqyvFYxXym7BfCWuu4bf!>GV=2|wPz_QhuzLPL8IRev1eL<`>6kjb|fe7Ez*_squ;%!cM_Ym6)`t$jQP9z zT&=qDw3f(gHkDn^A2A!;Lm_Z&ecUWnso6PCsBB$bZ@9)p^Bsy`P(lnvwZarJU@+c? z+ukq9#7?dy^UsvVe;l@SyLSXUkh=N&F-2X_3lR5-GY@z${_GkP( zm_GpjWeWi;_cH~1+>d9)=rNkt#OKQ?7sV(B4tQA@0{tHM0tDZ%E+ZnH#kjKrJ!|zZ ziR=!!7Et^3ih$daS;fODaL-;URGMgGeVVMp_Z)s9Z9}NM>3KVC?A@1ADQUUpL^c_S zGOKTWMonk-gD??I#D}Me5euJ%wkD>&xVl}#3+Z}mUPw?DrM0|Lj(y`9&T}xPu&LE{gu6|Qdpzba0k6?j|W#wbu`CXmq^tKvLeIP>aW^J)(EZTxOCQ?Iu5SIH#9 z)ADNj*{;g7*MZLiCLCXHr;tO?;O9UdCRV$V;wbx94|6A~oSwA5$3`~!+HYJuZDf4P zfmgeEyP*7}I38&At@fiH+-}|BS@hb-#E@DLb=gqu4ug+~ib- zi{XdnV&6tf9jntHVm?>sf;$q&RKl_XlI+O{pSIXUthhkZ0vqQ^r{*kJMI}Rj(rT#JS96aG>BWF*IJ* zA)PH1o-@0f<+3)X(blfM2PuWYIhYu+fV|`@P`KFQB90io?<~b_Nd$$U;U9)=;F9lb z-M{{UJ|YJXc^%)Oy{|UolYLfNwO)&S<HkMtRJgaj)mbI3L9BX zWRB?2Xb@ol^8qFm4^KdWg~dH%F(iHCiqQjJ+rWB&@FG>V%5+mo== zfxZhBj<<8}6sXt?YkNS-deV1yc91uJf-clQ4Fs?&Nh0Ucp`OSyD$WuWbIJb=%j$Cs zHQ$G93FB8w&ZaC;8%;VnkP+@*0hm8KKkoko`u(ZI$mfbeYfZ`{?&rQe?|pQ(KrC70 z&5Qhl>%j)7&7AFQd|@;+`pVkzZ&bpr9(9Q=r6$mlnqxUDg5qrEpkPM`kD2A~)44FwoDGgCZaRiDD6X&Lig3{|RJs+b0cmXl;A>683n8s>BBN7sS= z22KyCs4(TGw~ni%c?d5}OIfSDA~LG@%pUL>mgaOO#)0(|en-er`K{j;_#?nuL*D zwYqh#1^>elAX8zra(A%9V4Oe{koq`L`YeN_2^I7(4c7=p8gO)a49WZ36z@VRQ*@UC z4|NPb8`JpXs2H|7@f{=wD+Y;#gkn$-VVTZxDV5=LviBh z8Cp$4-(Q6fk}$+Q*eWv44R_$pxO7Dm?3_f<11c?SD~ zjMqpGTwM=agbEG-fT=)z_pF_ii=SLorEmxVrQ$X%@)m=U=~=6bo*qu_zCN(|M+KDJ6*+TjX%8iOUrU$;dxe9MDII|G zzzAv{-Be}CWi;x3G^ZuQcw?nIE$`Vc@Y2`Qr_yRerE-U@iu;DO`pix;j~ig((focq z!t$101U#>vDnF&%U89?GEb+p3vuId%$U!^;#49HUcK}_4ooju5F@KEo4$)c~Mc*i4 zd5_83li2_0^Qnzs(fqy(^jN(tP7+sC7ne58)a(y>f71DBYY9fCq;F>*aHE+5%-KzJ z(tbUHzR$fcgwZskZ}Zh_%y})!GabHU@vq@6{d-Rt01#lcz|v7M8>V<`$Zjp{IxQg3 zRfHupBu7`QzY`$aem;l_Vs_ie^ctU>?zkyFa>D=V7pv7}B-;@yZyQG^fO`lMs6DMf zl@o(cg(s;l82m$1d*~Dr@y{-xx?v!xm*X+MIaN5IDwbh1UfJzzuUt`CCb@uFEZ(!b0j|bD5!sU4tnsGU63U8#_nan1a z$fY}R|9U%+3V{5di_b3)k7FRzc#PGSib(GBj~MjoBqsl70VhINWUm0oef@#+x^r0% zzJ3w!b_6=I)<827TMNI(^|gOhQpkEyPr1b_X>{spgsT@wEMcOSrcidj4tehJ1-ARL z10kI6*-*qC&V1N+oljgqmwbDAkMe03v#s8_^G1gP0fL$zU)j~e#s$#PYX%(}mNoHr zt%bPn8{pD}ytfy~z-GDZJ5Db=k{Xb-TF#GX((WiAF0iMgi3RZYSQwV)AXU*}*B+E$ zwd3=Qtg+~;o+DBMyx4aVYcLBA=UcR}h~+*zQpqWOB4MN&yb}*l2kpQ|;#M@Do97tw z=Ar1gA&o4x@mu_Ciapph4Ix_F@U5APA?%@Vw|b4Ko0%BF!2)cxkq-ElU8mJdcUu~> zr)_P+g6~l}Y7T74Vc)2&$+L0>L7AT4=spFj+wT5)_}d1G9~WTe(XczTuUHMDF8XQe z<%o8Ujb>kD9QRqg@uy-@nXw~Gn9y1$^jJ!#@0G&(Y30ZRRd8q7{`m&`>2mR5(I%p= zwKz3d1`qXRv~AtF9<_qk^N0Bsa7XT)OYun$lPAeVa&<$2V)8`6VK7SsvQ7laO?Gfm z?45T@K}cppuJ{2%7;EXuv-=j?!MF6Pcu^?9L%$wCmPaA+&)k{!A9mQ?K(M^bq)D*Y zwY2C3%}l@?cK5a9gmxWMI0_2-!V{8pX5^=97)09JKsOcB_ON7!loKy}SP9zYwDPtd zS*pxgh(5yd0&sWE8v4SuU=Eht&=;!W38Kt4ErX}^G`cpk1$7BQ&%g#cU{c251HrZX z#s?w~Jp6jf*G`_WdhA2Z2Rmb%W==c|Kv1!s2Ij;Zc`^NNPCNqb&wBc3P(Bxmvl7Kg zU}p!iKQ}lB)X`aeBxJZtboKFJW%?%96vt^FL5v?2z!bpBjfK+BTqVP|nr+h4>peR; zH$upInNS?K02CF%31#%A`;qJfef#>};??!6FVhy$RfmDV2+zXG)&{ilZ(Q-aJpx@H zEZvNj>bZ92jvbQ^7Y;7lBR$s=(ALATwt_##vjgP;=!D4b z1o&KK=PZyS*|eqJc=%%&Vl)QuDMA~pkIs^xI{w4u+RyLSmiT2K-&r!3k(xFNZGjYf za4j4>0b}YOOG|aBZgiT`7d~gg_;dW)0pVI`JVP+YD1z30G&iTRO8Rk)Jib?Q<4E(@ zygFfUMgY${gaJZ-I{V2%YMwQo&LAz6d)I~4xSpaFfLMoD-6v>Sd-?`Ku$Hn1-mO^Y`*SxJ0aIj-X(Rkcm3SrvtU&O^u5sQwA8QZLZDn(E_3+iT z1Ncf?J2wy5kCewn1!5(07OCn2#S)8ed>-O(2?DnVKG@Y^;{wlytY7G!zWX{a%}(~@ z&AcLH;-U%=s>m<62Yu)<>cyPWp4)yzapoyOfCKu;mqVdFN?}|id#uW zu><0tgQM>ryN2$(@vLOKD~Uy&+5N<-J7Sxx0`HKV_!?S97Dh_KP?GF*inY(`*XK1V zxY=qDeXty!IV3wHXuP<3z_dTxoah=KYN0=mAJ#+ig~IGb8Ud0Gp@ZOLvH`eJcLx~3 z5MN-a@~bZ~eII3D?bo9EW(!1-+-%syQqLQ>YGEH97K#{uOCam_Q14aAF=0DK^6DXy z3-^qYfn_{|e_kK?rQAhDNigL~%?5|t(IA$7Bm&386CqD)2g4o7Ru2AQ|A~}rnc&S9 zw?n%?jTsV-hp|#x&a6M@Iwd_pF0wyiYTaYNsygxb4$ z1>|3C``053M$<}xj6fc;QV5suq`qZ2i$W}aZ+RJxF8Qm4?*AMBBZ8bY2kP!U{`~di z$>vyeKoDF8_V6zZa6UBGy*GySe0F-ZU)Vps^FmdQ=J1~ka5lYVH_h)RxGUaB$ly31 zvC25BZS^Mu9MYO4>oITq3Zu!SSGm^a1)PS9t-l-K>iH>=qKr%7MBl#sqBTf7D(fQnU2MCePTZ97V6<49V>Y1~^0~x9@jMyPVwRGyL2&8sqeXA? z3%r!ou)(na3?bb|y?pRvq%!6MKWdwJ3W_1xZ7cwz{kibx zNm?B(oQGN@?c~{tcAS}we+9sZYb-h|K3=`s(M}wAoO=OZ+4E*q`!5sQe+Gbo37i6THI%Ej3~xYL;al3Jk#*CXB=d|H9! zTVQ?0y2^0m$)Jzd=CgH@TbrksIFkej&^RVYegaotN3bmm;0(fK>CYGcu(ff%aa1}| zENhD)F9<+6gmCahTsBnkJ z7h8Rue9JAC)Kus_i6%UTkI}lgA_bwZ{08sCS*B(k1Aw?5Pj`kQDCh%tH-6*66rb0oOD|-ycz?zN|<*q;IJ8h_Ibthp` z{t17tPY;;K;CMK3M1nM?{e_#xGyO*oh&R)D(Aqm;bn5cu;LSK5_GsK=5P`{XE&<ehx3n}^aWoG!-ANBbwOU@(}tI)pE|s_N0k5JMgMGtXs|udSm1j5x>`m- zJfkR0d$Fb09vpsWB>J*o6lh@rOO)>&3uin6V_i)z*(+mh$$dRo!8w}uRU+SJ^h(t#*4i>gvp2pO)5M?&;}v0e!h>%U6WLzvIV213{tcRh>k_Vq zw*|Lhs1xKyES5Dv_sAyS23Nhcdh`h>fbK5^=0l(XM?O_*T6>J{bPJ#GnaEG}?Ja(K~MIl$(#XEW~& zj;d(K9IXs6d)Yb%Hjbc<677Ra!f~OpNB;5VTv^G1LwKz$P`$13?O?KIUK|e}-no5j z$*5%r#O?gFHD9jPGA5S7gX?RK``PWWm;-DHG@Pg_{^S0=iNU$}-XuLKEpaO60bpa? z!nFB^+WN(NFR6s%@?x-zPd;&~h$HTb?F`^WU%zlFC|#GsaVJ>sJ&{!Z z$_p6Hv{ei|k6RaKjZcjh<_taA}^8I-oia{q}qxB7kv- z?3&mzUhiS^DDfxUjTQD!+3CgRn=E_%S|wE#7&%$Fb8qTc(Mhv=MtH(Iino_mAaOVx ziD3HK%@x{RP(fcQR3nd`JKZp@N7#>l_5~W3lgY_l1w27u3fIl&x3Zb8NM#0xYC8W| zT}s+H1kyq{I~Kq1ueN+u)aUq}w|Ff_g}>3(S(yqW!OOpQ>~8KddDh(u=%S3cbw!U{ zu;Y=u_#@!N!Zdw*=>@uVmQ8(k!}^u!!%Hggq$>@90GZK3-&jc%=JrIs|I@201R~=c z68fOGSVlX!-OQz!LJuT(Fj~2f4Xu+LmW+410>b({W{WZ(@PV}5vJRqG!Ox$k3X585 z*o=ld>9Dg432^N9bWNt<0mAX--_9se=~kJWkCh3qe!=u*F+JOXrH@qiw&co)8Q~s! zPHHN--tM5gitX9HBzRYUcOi=7^(e{cW{j8&ztCCAgPyG~Dl4h*<91BWg6U^*#AZT_ zK36yzhB#=;!UrK$=b)z_gon;B<4`q=y}xkP_x$NNB+qY+&tRHE_TM<=kQ)NKc7ok+ zPiY4H;6ifD;D$q_ir-%oM#GBgyG&N$m*0rlGs#3DIpKqr_n~r9(n~t0vRI4o>arhN zJR5eg)ehb7Rz|OW>RyR9-M*f}qS}4aj#=x>4!}VE>{cQ!zs6T?vbg$mD)kaGx4#UP zdY{j)Zl!to(YtJRBu^q!`23fh24s1fPTogy?6rq0maPh;@6px3?j~N6)65s|)=rN> zvas_(_#X=GEQ5Pq_*&%zBe&DgI`>`jkj(#1v#}Gse?5cxNe3oY>uHNXJ}3N2yer17 zX0l46W@@(Iy#f6(b#EV+ixx%z0^qh+)RS?o=X_!(Z|)1M`mRxZjfGL+eHkObWn<(D zgL0;QiOn%H+>?a#L&I8(Cm-8_T~nR=9|t=Gqv;`p;l^6whc}8C=G113_KYoci=6n< zAN`N&wPq56Sa*OUUQMql)S$-#`PnLi{V=5cyNla4Ck+U zZHCo6@{av|^=fmMRZnZTs6yXi-hW%KjcAKqk{xvnHYn*C&iGn+Ha8Y0985I?Ks_e# zvmPsg`1myA=82w<@G=*CpXQ5rpHYf`5h=u`qN%DaXt)P8^MQSH`nYpxiLumvm6}oz zeY@29l>+PrkXG&0Z14c;AP4?)n6#72N$3r>G+B6B!3k-7 zU>60o-s7%sn_ubHN~Xne!fB#*=RG zyQ`u4W&fbMRLd@$eo`PtapP2M*h{r#J$-VVg6~K@n9prz$gVfJ;5w;CPKcvj=+f5b zSQSCF>qx{Ae=7&D)6*ArG_ka!JMm-jJHG~pTy=_ql((A5gS+Zie-7MVUx{J%I~?-p zsmf1Kn*m+E%*kiQ)c1#P|GJ}f0VL_CURH*h<^OQ^)?rnyTlesyB?M$4-Q6w(q@|JW zRFp314gu+q5|M5MBm|@clnx0g1u2m(m2O1fdx!Y5?Fw?__e;QCM6P;oq%w zIRst7d`F0`N@qmg!vGGOZxnz#ZYupHz^>Us55R=%Jr}_*)*Trhs$oE4!}~={`b6Dg z9tA-hB0yRm$)qV z0K{=&Ff0ZK-@K|n$Wb-v(rH-}RA8_eI$AaVlWz691<`i-$Q$a-ZLnb+S= zeM`t8zjibPCPOBy+bQ)O&brQ7c&l2{u^fHH-EIO6LLmKy7%(@vtQ~Lg_qw4v&Rj?c zlGkHmChT#LB+_w+sJ4X_Ih~FISaN7=x|_($rf^R6p1O=f?A!ZmpUIdIkF2ZoZ4Jp? z@cvZyN=7Y$1=yG1o+@AOM!&kY!d#$Ep0Xo?sW+hvWR~q;P`;AUet*hFHr)A)RgE#I9)3yyJp@gWO5fHPYqHRlz~Pc!35Ogsp)uPyYI51mlhY%;p>B z=(7B{mM5K(dqDSm(!^3@MJ;5%>-t3fLOyMd%C5kofAs#hhFh=zatSO7=#XvimnHhU zUN7~Yz;VFa_BB!eetuuvg}w{;HNCwI>bfV6n~jhMP8bNDYga=qU$;*gPYpOO$bj>n zh_?8#G+xtE>AfN=iRINPIWYmzV*i_Cgfi@8gv!>ox-J0Z+7K_uAIusZyh+`CBekwj7pH$O1$d$GkHg78*ruWeGeBmjtx3{r zJ30vwuNpYKREmpUBCi}uudY9$)312uOdlZulds(jQUn^_l(Zdeoodafg3#I?q#iSD}xK+BL+e6yXAE7mVI%`)w z_tDpA-BkcwcMI;wN`%}5yxE+LH4sjJ$%pBdurFRQc_mjx4&W~V6<=fqU~HEfT*1v6 zn_s={0~w8P$aJ`1B_duU)Rb{cI{L~u1El&fo9cLU^_lp>60`n8)6NVZPhkvEA55Sw z7u=EQ{i&4*rLn^+LFs;-notB}i}m*EZ}&sr16qfltV9rv?=W>4d?=|sFnRWrhkexO zmIDveO62~7HZL5KNgtdk!x9Cox;Gm!BlJeWlmkrOB+mI6+ksE2~nay&aFgZRU~Q9?x}H5&oneo8dGk@+dg18w-V_H zpUHaqp|5U03#I&u*`qDQycobdo`y(VMpIVkNPDnnZvG0gQ5L~$rT?mwbzLqwk7yV8 za-5@uODRUpUQr!;QuX`ZpJQa*-nFHrOu$T$%@Aszx{U-aG3^#@)qIb&TID-T`GkqO z_+tm~Do294jfkj$B~@$^lb+^I2T)wC5#MV*kaVO%x?naE*u+ETF*EtehVR-uv7~d< z7y3(Nr|$BEKEB|=CPXLMe7%6gYlAg)L-Kb5su}UmjYcTH;0SclTC<8&iDPjx2(r$R zumD;a$`jp6&NM~Nx1H5_SotxmkC`?)R|Bb!bSuY3Bj(ENV)NBKmACE3U$VDmQ8$lO z^#Y$eH5yqcru2DdmZbS9ML4io$q^SNdszayw*E?}bZs*HZK}C(Y&S_#Sh75Xv=KN2 zWy>aE@(2KfFjFHJ5LT^qeaH5kO-AoZ!whd9 zjud`Q{5VMZCn?OxhvrIJS%j%dw?)w#ZMP*nvGY*RT}mE{<+~JX33WZ$cvM6-m))Dc^c*ef|7`=uC+B4A=nGQT#yz+H}o@NMFx+CzkL;+Jz$n&b?#yUr2Kv{ zMSm4*Vim8*BH9&iwyP4~u|II;VsaorSt;AUH6rg(6%r8TIn5-(VgVc1QUNbN@BD&kTAAyPyrV>`@7lqK1)fvGmu3S9rTiCI!^=GIy-S* z7m7@hD9IH2Ze^{L@Sf@QEiyyjbzrPLvsPE_TT_F0BBymDT`f^pBrhn#5X%(5Fw)W% zTkr3p=t*%KDaPJyF!N53x&e1;txom|?DC986(gZ2SEVG*t%?9!aUKm zTNi`MdOssS@havF&@~ar14%*HoI|i%XbT34aAw+)SuuBgZ5Pll5v{Xob*r1f9Y?zJ=(3+Yt_ds zR>|@$bri|cdYMKr{fH;O=s){*|C5`Momj!3(E6*&aV0OAS5+22>0P*H8`D&xjF>tK zViXxDl(6g@Ufcq%*Hi!5y?Epu7tNJGvIjqAf?J*=fCWa<|L6QIyJXs%J|(5l8~fB~ zY2RLtjs2*5?H}~F)DG~Tz3<5-`^h9Y@4%VU!Hh=%<5whrTD$#RwqZm%xcFIfD%HU~b#pU%nYEo+# z14BnZJa8->jc08)40i7%(0hzuwbQ5z59=rm%lXHXS=!c~G&Yjg=Z21J31?@&@~Apt zmewrttnL!URFp_PK68(R!m75XrAe#hi2_GRPMh=vYu?H7gU)_ z(!ZHXe=02oc7=awv21gy=u&@K-0H_hAM}_+S{nCp6&n%jcHD&{{stRlqUX&?K*U_0 zMhP!;^P69v(ja-Mr}%GX=vhs8>zW#W6cElx%Dlg% z27PiLM|lA+_xnd&IO)Hj>1s`eo^Rm3tVRVn%f**>bMQ)aOJ`QAHT0zN)OL*gO5gr_ z^z~>mBVL@bRy3E~+NTYxC!%)ib)bx2(AU4=-}?M|cnTd6*e>1^9qjMfS@tyL_)rDSPmaSJFU_{-*nzuhRe9oijEKwiAKke+Bs2CByjOGvPdr}e zJG|dKrMv%qZr%w8W?_;}f8p=piBoG`PgxM$*YF1CJPW|MtN-v(5F7 zL_36lIlqNs&wH76wc^()d`6_Y)BE zi)aTiC=l`|(GCC*k_+xU@czU%f0sL6>@EiSHRB+`)@Ilv16N(J^_@yc+&)&AuRgO} zop6rVKxj2EOHd+d>ze>evxeqEzZLATs0zVRX^+!?$OAq^tp@FB-PVk%(>%#+&;ZC* z?**`JP%{%`{1$v(M{!SRn9SIt)kDy6W#PxX&<92bp1HJwag)#N=fz^Y7YCrP?^j-rpxb=Tg5#e zJBZ_o*G=VP>NDL9Y(jW_DsJwbqq<(HNgHLPf{6P{Eh!B{RMN^U&k^W z)0;H#PAF*5f0KB{8Iz&i^Mi7RC%(>FHC;h zLYJ1)(V9L8NM=Ctjs}bQv0^TaEwzVaDMm{^5++Z-xr_w8;(@oV;m{9&yq)-|Tl07*C7%BmPr%HwM#nWum>Xi~WNOJFXG6n(@8g$A1R0)F0)+ zUFtu)D=(;KeDzUp@lC*J;|%`+y&wFs8+ljZGdIo{#DVmNBs1U7_)lU1MVg=U_{Z{{5&#ExJkgX_PB|J?l4thw8A>B~MkXL%Id zlN9L$r(|HlKC_Y?Xu*hjmST>BLLgj5db?3&UgnlC@I&LVn4VRVP2P`UJD+q;YO>5BNRdJw{1(Tb58d;JwO zW0Zb`ARTeV&Mby(s8tbS+>i22Lj$|RtGR#pLeV8ZrB9iPol8{|T-qjHIiYX^Sq?AG z(4{Vkh6$n;DjUy!3;f|U9xm?IdqwBy5}P@n?A`exrAF{d!Ae=_ zoj|6mnZ105v^c}bZwSo+Xz3)l&=XAUN*l25B+&FSqUA{|J4=;!b+Ohdw1n%kiq$u{ z>7Uu?j+hJL@2gXNLOGjoYYIji>htw$Xz4WI9t)x@`rOv@`*qHJ+7b=}WrSxAzOYfl2QV>xQNm?74M0nua$2w&OjGXN@ z!GDC7V5Lk8QLa-~jj&$t+?~>0%$a)+tcO7jaQ_5af&~`ksPM2s!ta}neJ{I*z+Hb4 zM7%1nHiZA&>u7dAg_iV4wL$D?q&|E2xnFb~zDZ;^a9jfZTu^L@_t)4G3^fvT7Yl%v zigpg0BIm*6VrjF9t{9rpd=Vey{sm}hle43x)&u@?%`2^N!9jFJ!CG^Ri_j7e>{>&Q zwbR|9B%TBHrvdI}b5xOM(2`3U{09$AMFCYaq=(~Qih`+Rd>{a{M5tzHVybU$2>J!I zl;TNs0b2^0w4sj>zm;s$PR@qc^@)sHKMdBB@@TKY9>A6wT~>BvaAvw@cVBvkGFe7v zw;AR9j4g5Kus32aQr&Ac%4d{nyYpF~TBsek5RYQ}D7&wkfvgVrU^5U{^|r6TeMn14 zck>HUQvSE;G4VI{$$P$felcIzqj{{Yc|d5C_=E1{_I&pgWWm*& zz(a5>^L0k=CEODkLDz*N$SMC0r*Ov6Dgk^``pOm_w+QD_;X?#1+HM=D@30c z(sz0+WZbB7xOk}XZ`_z1J)Y}vPoL!rj}1#=m{iL}3oWHw?vE!`w}@W=Olkik4&^_u zp$D3y68O#G??$;`VQeG44op=huU)L6OI)z#vn$HTVQ`olpIA4q82`9SdtO89H5o;+ zaJFm^ethJrzRPNh{Q&LotcD^V8hj-ox}Ly1dCfz)&U++1nfMY=Ly4d@)D|@G%NmNH z4Xjq%8j#!K0*mx-U%w1wqv%u1%z$F9?>+Te^O@8XqxWlA?8c9 zEf48*0C5C;V;bRymjvfDO%Po}{Hw6O(Ye*#wx3irZ#A!t zS-xz>kEz>9XGIo)u7lc_bK|Xw2A>sMh9hs(?Uq^K1pO9G^LIsdiBOV|Pley?#VkRe zJX?k8ee>x|Xp!X@u1bE9P%(NaM}c!Kn!=Xey>|Po$dcKG-gwR+_E9#UTaiKpZV<6x z?dy4w)$Sk2ua0=zHu#{c0?Vp}a;p0N&UuloF~=sks$|hhUT3oVqE=Zf6R}V9ry|?V z=vD2VDiYv|0ax-g38WT;U%z@@WNlDFz6V^D^!+TvtU@8f<5`vt?*T2ch55*&{Oep< zbNy_OCJE;yOksmre=4#I;K!t~(fw0|2xu8CY7WY5gN)6i@@GXh2TbpMoywH6^bO<0 z%}t-Rm+}#L85pNUme;of3_+^iBMd~tdiO!=)rIOf-3zlwgQKfc}si+&?!C zP(R1@`O%-&XZ$~}&(kn{(DLm2>+%eex=8(C1)7>?ZGHUS*)4M?NH2$x+4Y^t3`{sa z5P}1UjpT>ypDk3U@nc%Wu{bsJ$}fe#ybd%V7pR{Uc#&y++KrPUJ`L6t9IEp#;h9}}<{!WV!(3%AZKic%q%Y!rLJ%R$OcYXRGgcNw~|1v~Y zp2Qa^qJFC+op?vlH3o`T`Jz~odTF5uVD4DV^a0#DG~HFKLQC&GIhfl<7B%A&3E48K1|=KqoXXq_G%@X{rr zs#ECH;l2FlAFLNi{^d!a6wYCDia75-ZW<$$eNu7SJ<>PFszO+$COmMm~?Y$M# zy6Nm0?!}3T@b3Nm=edG6+@1ozyE5(Ol*%2%zCXI8g+drNB>JA#brZQ?DJDBNO!Z9*7wtJQcxMp)!BlJQ44g}}6}O@7eK;_FwO=1MYSh}(Mo z_rHZxPUSKzVL9=w&Kp;(ZuMagXxxvyTkDANGhDJ70V&+hLUX{Avf5CRM(EKSwq1v| zdVdkUQy1^c6!%))n5n3{3_TJiOPC=v3@VqQ#$3O#k@|t7w^$g-`;xo|nc@?QKfonq zdtigt_o}s{Sjs4ZQQulUW1@J^&I?3{Fyl%nDT4^siWP23d0;8m4=pY;&~{juHUf3> z94;xLI6N>YJ#|q3KW{xzC^hC<-X?0qq`uc4!{*uUo3-F(-32}}3)xY~tbBDFDf||&Ti*gX{izIz2V6gKqsAXiF@)jW__X-j}mC_V;Q}`(j;3YuS zGIz<@Dizd|v%d?c#TgdkdN6H?0|VKKS|)?BFnA{v6A3*(??BLU_vr_&k1%Jg*7X~1 z&5ysOU1L=Qa*3Bnv11^hY4lxSbE=b8c@g46x=fmIB&J&JD*2Ki>R2Y zC?X*8Gz#Oc9K0of_DY11)z{Ooz7tn(mA5%Q=|ke>XGFUYyi;3_>#w=WrNZ5oK1)%0 zPfDBl<*|7hYNk=|4WGt(JX1N0Y&z{beYkV&EUH>o^3ADp+v zvRwRC7n3bPZ{OT(T~As&6Uz`R3##6I)Uca;DeohCdyDF8y{tLl2>pgw#!|cvL$aW_ zC>mX>w7EoFaOus#5){$k;xHworb1Og5R1)B(EDU}Gttlg2+@!}>XmjChxSOG_dMiL;Jn~|)Q53RH4x7OBpKX#BeI<#d8iW4v8GX)eG9{3*f237iTy zk-wq4cy@$(RoaJWdQzrSfwB1oP^A`TRf*~X;k?NNT`EOWHck)&VOu;qD*%%CJ2eVl z;N2eYiSA2nIj!AWND(mIJ5Gk4)Z(|na7!QUGDwSGZhkB>^kAV(qy2ni`sZfD`P)bw z?88lP_H1M`%l9+{jFdwWPb&Ry;O{xFTSJ!=7#RtBy51WY51BBi^87`!0i;Cyb#PB> z7_>ehfw1F{JQ)qLW2XDnoZ8jh)S2hi*QAuNdi|jN$4`F77Y&OqK^=?#sLwtaRAyv( zZ;!jlz9ESLr-KkwtpW@$tf<--9fu9UT-_VSWfqq^o0tn+%7cg?wRDMQb!U~^&GYXr_X1gm16fJ-iUhJ|Cz|VXaNp#o@=S)?2~=7j@@CF zV%oZA9JL{G|XvG8rb=Bzh3L^r=j{gb+zTrIU>tDVq`{$85!2bT+>?FeA7?(EH1(Ei(zZ7W`1NOw7ry^}HU44Il0gVU4 zun{ulacH@-8da@l6r(k`0lzn#JDg=4qn(#JyL0fK=M(?zbBfU`{ZH(PPej_cb?U%E z6g(3%3Eu{bYx~C&Z`|!x$$Y4PZeLt4Oahk53g;QhrxM2J`TF?s0NS9=zMNz#Js{s! zfVBkND`>z^mk~+C8?e%oS!7krK%q-ZVwTJo?29A$RC2{a4J%yi_RDr!??_rQzp3w=ecA;uQ))U>t^Dj8P23n_~ z_rXzK?q$%Ny1GLG30H1&+cZm;p(}+#3g%eSANxfVK2mW^pUcWjn%LnFI3J36$wrL+ zZNGRXzn-+`yw;ee@WLML-h9KznADJa81gx4$O(7H#rSCL_l=Cz8t#|kZk7N2AzbfBn>c;0y0Zdqd)@SYHV=PFQMW>afO2xt^9eD3{aTwnN z;ERt@z5k~8nv1OPAQoNQ|Jv-M+02yA%NA_g!0zC`&`$o9_&PrfCdg0t<#-y^7}>Xb zIh`t?A1KgvlKZlzqRl*s`ROf&15MUqhxH5R zc{`aT+dKXidBAtIDZ8uLt2^h5B>&cVJIS~g&%+kos2eEmpOD|s!s-SqI}dFqDNxZ! z^!voP5z&+pT1^`7nL#{aF0_*>3Dxnmyejv2iaz;Q3dKPlWqrN>b32K(y^Jj%QH>>z zVQ=|R$4i&xjVBP~nOH|hploPqXJrd|o{QqQ?W9fT_;Ge`slchIG?SKT9Hasx!+O+D zV*Nr|Jq7Y4)RqDAXaOs>za+rSNeN`4J1uIzal>)ckz{_<8hHfl*#1tt_-|{gHGWNi zc|i#Tbzc7!%ij=!3$0~yGD*4eck0k(}R z*k5iiKxW(yjVn_&_3pTJBAY<9)f9`rY9{|yTb+Fhuu-o53BdM0udV)l0_>OK>N5iD zKNnZ$G2ML(B74Kwrffp`XnO9)XNMiY2`>%B!gi9{!2E`p`RwDmfb1HVj-w9HolTM<$Y%BCnNJq7?>CtkEio=Bj{tm~Kf-p6(>JVkx4 zg)MjozOGhfgPn}llMbY>Lx&@G3zQLe=Y0jw=&nW>tYQ2bOvF|0N@Kt+=wxNl0ocR? z9(u;H@sBfOWa))8?DAu*GX>5JwV)B;ABi7rzk*0Z9f|L$`3I&z5Xm1>hg;XZHQPDa z$|NO|w6wF=H8(%r(9^<7GBeN}V;Lwc1bii19=76q06{#(QJ_wZ>b9n2_2aNDU`mTS z+@uz^V1yW3O;@sw?}erOqMp|Q|0F$IU0YK_I}nz%O^C>A{enJb4S43)V+G_f0}arZ z2zc9S2mJsI$XA91y*8LH5|_A{y^d(%GnDd}?P{7`^O-**uyGCe2OMu&kL}bw5=7&8 z+=BnZ_0u7uKI(*92No;fTL_55_G1?znVk19R->0;`SY0GS$@EW9!&7dt!P zV_(YiLbLK4?r0ay16mS$j@B>8PBbTGab%1wsm2^+6c|Z*ggFo0`|)I&V8#&`VS$hn zz{friGJAlyT|)WZHBfRw{Oy-wVcJ%};v8^O?#!KIwYoAs@v@_zB&|#=J1;-}`X6lM zFyP{uUozziT#EkqWNWTrbnXW)Q>qlHnW2l5m92r@@$25|hbg$QDob^|(6)C;!00)EQX(1U27xj|!_L7?D`xcYKwp5w<9Mi3|EIj=rA@ z^aFtJ?Lh&#sp?9sX5Q_6;wf=i`vsM?=Iw7oS0f*e`S^tXFptjVYaerF0Ls!k}O*(OZ zi2JQ^P(E}IR}qY)&>gY&8g`4^k(ST;J5L+S#A{iDc^FC$0*T zg;^xqNL3prB5}bkFgF4j0!P_0O<=qT8~^*p(ljkNA#`O-R34w66i@+qR)w%}1x4pbKyZCNjD9R@J%faps%cnX!5ZH`17$XHjFmp!J0Nz_Y2Jl{XU0(E z5I{a#1wIU_@=BOG6uFr^z?I<#HYt;Ds5{#3Z3M%iv+k~#%+)8qiP(T_*nZJ$c~${P z#Z~PLZAGloG{JH-N-81hdA1urw0}tBH8WOzcoRPkON*oiJm0!{=7xf9;N6;Lc3u;+ z=3C$4(ck=_lbb~>d6mk5b!zu?as5{}6uh>MlO5YBgrPV?<+m5gACJC~-Eg$~n-3;( zOb(9b8l#0<_Ng~Wq_RkUlaz5`I{XAKP4j=U-Er^1{5)ZLNnDJAICa|di_;-^#??_m zGr$x^Z&kAfnRYqSc4?pdD6<9w`~d%RV3(a)lc})&laL(euR;6fAwNl1k-;3w7N&d~ z@5WN!Zif!dAA-@Odu#xA1B7FDCkt{NPj~RMJ3m-y3RVr0xaT4Z*Lq&qMt%CnvoNTpJL2hQ+_*%}e*1B+MD2>aP?kgWTe{Q!$2 z#hNl)Z%vf~0=kaf=zLhfjY%y-_2N{>tnq?3OYP^sX)eC&s-uN9H?;=b3`u3oY?waa zdvamnY^y^)+Va8pJOb3Ekx+H17gFsS#XzpKGKb;ga#Sgb0wI3QV|8g-H8@B;jcvOQ zPMTvPugY>yYPPo{38jt_7HIWStH4#euFT6kQ#4DH-$)et8pN7Y?M;Ab4e;5rq8JmL z1dn833@KmbYi#K?t=CD&d-Ljv5X`ys^bR0BMNle|9mImI@8w-G67}KUkX2F7O{J&O zq40vUW6`&uBE$y0woDC-TBS2)cIhB5A1K;iC4Z5eN(Wux02}O`3yM(M$ZU=^eh5k@GdC*;p`5r{A}F zZ>S?q95@1&V~54{ZYzSWUlCE3q!-8HJVA^^_DC4!prQL%N^1C-!45LRo z?lsJ*Wf8Fb3N|T;JsGK;+{7r{qfpW=-s_-oYWkX1^c6}ySa!G}blq2_e<1D1$-sVr zd;A|<`O+{CR|2-{A@;IMH$YI*4(UO}EQaE>DmO?64Atj#P`&Pq!bOxN-iJ5zK~Xe+ zmw42x21}#5v?MbD;D^RL(Kz1=ROzu|z-mq;ui6jh8Q9dp^caVUJ7M&U8wvvCZ9p4a za5lk66uSPCsrZ1JQ;bwt_gtV=`gMly5EFan>*V6wj#f6ZNYPhL05bu1L7%0!Od@7M zROHUqlujQ>M^AL8BoSD1raMA%ghsI{UCaCm=X{ct1D+J|`|`aC2D}2#x9H`sZe+;s zO7sati{RsDf~dp>j#lBJykKs|_wWQZPx5BGHp$G?Jn9E_k1fu4!Hl7~G8p^n{wlr9 zh2>y~)$_K;z^`@+sZzBN#Y9KgqK`tX&bCNfo4WmK(5| zS)QL%x@{+S#0wtDvzlzc*o$QqHR3z&@MyHj2Fo1IZ-7Gv3^-?AOdvEa??^7VcP=4_ zRzMI1hKf{@U1 z$o=_Eg3F3$K#={6%eWtCyjZ5^+ZSm8Yf1Zq2PFVtgMaLK4T7;fu*5Wcq#;C(+|8dvT8mR6oML23aH(ABE8}shWNbo9OZReetmdYBSadHF3 zAVM`IVI^QC5VYpAy2IRpKOcQqQ9p0Q-fNX*`4M<2&S*(d9xx#b3fat-GW}jvC!VY| zhVz>`2az*{*EYDvUFt>8Rjf!6rE1?<)X%6?Qh}nU3a=nP0`OYNmKaXs&462v}}rxW&FFnBCo2k0-6S>c7MA9)PIC0TI{^pu-Mg z*%)*c_j?kYFX|J?I?KU9x-SN0E#U@U4r<>>*q7oRp5wkLUtbo*53q_9U zjCN$8-`f>kQ z`GjmY51ky%R&GGFhU4xiN4>Hya8j;XfJRb0jLlN?flbfDUXWY47$vp^VlLt0?SsPO>Izy$=)Czr0?Vc=nZU>Z?IsPn8H zpK56wM&exEEe)PGyZ-Sq)@~Y}ChWC$Q3TWowh?f^DL7$L*``w{_P&`oBgi`JIzR$B z-cH;F++Hpk2W)+QKe{j{jDXD5Mg5S`i^XXO84XZ(18I1aIzaH0rLHj<1K8W-mUMw6 z>I=4q^)K1Q(0AYN_NR`+F~9%El4}rb%vS*3J{6cX znqsXU4t_>5W-}-&am$;HogG_%85oE0!Br6xQ3iRDc9~T$NSM?nR1}Knn2f!&7@L8? zCsZ-CwFTVDL1vvihW$2`ni7l<`);A-@sALsu5pmf8HR?xJib_2;$m!?$SR7RGcFbIkg6$KeP6(Yl$jw#RacZyN7Vy zsZsLHX!fL*yo2R;1)E}lfr|Dsd5evUnaN(fT~r3=MfsWASWVKi!#w)oXT6=B3428D z*F?NMg$*si?kKNCY3sD2RuA4Atlp#WeYx7moJvB4PCg8hO&bSaiDjzs!j8QYPeZM# z`J`XvjfRRL9IcRaio-PsS2jxY5{=d4@OqKiVe; zan{k1+S>w7qIN7U7Um#t|8lw#V2osZh;`1TIi7DX< zarO(lj+8jgEI&2h>WWkJ!LUo4Hw@mf=D_-AC1zng2cE}M{Tc?HsB-y==*u~4qePrK zN0_cFY9pzU|9@RMcQH|?UwI*VKk=F%{({W{foJ8W(SBXbn85>b}J| zj_kwnhPHwf>jl`!5~1z?US1973*~y!Z5b*r8t-=MPiacq}>ns^%|UaI-HPh zy8^1SlX+3;U9XNuVhPa{g4T+x|Ms|SwE6hOd9gShzag;ou{Rsva>Kn_7B`-Tp%tFb zi-`qv)!PCRqxnhQIB)`aa`F$`i_Yf7J3JG{DM_5)W5XX%spspNgBv{bp!1@Xyg8zY z0tivM>r3F${LVg&^>@?i9rr0VB^JJ<V_am;tO z;C)90l6LykPNIq+qvZ2>k!F3~n>t4JN!9wqa3|-jOegMS!n1i1eVdsW%m z92+XzgZo!DfNKTM!4?RR`ki&2d?%kbEhgC;k-UTyj^QzT97Wu%(0Q?i`5R6Vy762a zrGq+>&$kbVqp4SbLq>9OUhFXIW>QI(R(&v+{^^DLGlox6N(~cu3ff0|wGWdB9zZVF zru?`+FA#+1ZTn1sZ~|uR*t9L3fU~8>#Blu6w>J>~FFh^;NP&stp!;NGc-lg0N}w5e zCgbq?Nv{T*_hax&4|PFC81d)Ify9ev{V^KQaT47GT&@1}^4v??m+IH9*_qJ%_!f{E`hyeWo38dZ2-Zlr;YfJ)lDeZF|R2aZ+Zpu*c@$X*FqcR&ni*ziwD zsXCn)L;Xm=hogca+sh{7JD*+o$f-<4-@#g19xclJ#yIGra$hbAXN}LrE-bAS-0V&g z{_G?01Rcv%O;I%%op_>AiuO$KOWjMQ+w3?RfzKW91m%Jsiogeq*5y4*boefGr^mE8 z4|5h6j*fPMdV!rFathRUkXCW+J5uzSC>d1opCoAjq3G#O&>_nrkrq6jFA?R|4aDR- zxCLKZbRJteWMjP-%|D=CygRhF8oD770;J?}E-3PzA@_AGv#@L>}J1~b1<^9mSD+Qour^Y=V z2nW*S9HN9$d?Mi9s)cf??m7$<%)-E)OKZub!LlphIa6$+!Y{0f)l8qhep|~@Xc&i) zJ{br({p)@7a7?X*3Xz^N-#-lI!KP{cc_93&f~9ru(Om>okkr#%DK(KZ#A?eiL?EoWgo&)n#)5$$%~ZG^l;##riGuuc)rHGrgJ zUy%L|-RX<6=J=$9U=|qqI4O-_BN2<&)8cs9h#VPfvpR(MZa7h7+A3Fz5a_Ze4vIl~ z))C7nvT!o%m6*~S*C`S(qYB*AyFFrMq}AGz=_xLFJnT`8Vw-`=?3*GIEDM%2Wwb$E4Y#eX{RLEDehx2?R;|8dg)PJpSpm}j-qNm`gEXg?ZmZl=Pv zy*Zoz&i9eDE7b4SEaYTjL?fwPNP;;H8M;2`Zo|w~-ZExtik(N=)Q~8o>_eT4y%29K-mH(Ok z*VE?Q|EnJ?PW!U*jeb7g+q5-{=D-~+Af#LJ0$uXNWWXCIv?ey4$3>Isojelu@f${BNBHh{)It{;GZ6}pyy2xdftxtH&4?{DXyWxkCJb@RcUF; zR9tk@KmPmt+c@i>8cTjy?pM9!jWB$Ir*?&b+CQBqI_oUMdwvh(8GVf~AlWXKMsh@k zz5#zx!MJ1`!%T~c@OH@W*2LXg%?uqV@&|hXX@ir4l zQ_hP#zgDw-cY2t=%SaFNNZ*FmU}xMJHNbK;Z`<@BKmq(lJq5$8?YDEPN9VMc&nlI$#ovUa|d@P6B6nkb@;spU?Au5Z_cq=2FLH)ALXp$B-= zT+BaJDNH_1uOn`skzGj3PBRMVbAO7VOd|b=KQlHR^l*%}-|2}EMMI>y!XZ_>%Dnkkt_p= zAY9)cMKFFF;17q*@8(y@x-V09q@qP@8+iRxgm;%$(8=6`u=xr3>^d{6$$Yuc0bm5$ z)ZwNV_BFg7LtT#xpDzu0g&5=gWj6K6Ke0!Cv8nsdG%y+8xhvp{ zgX{VSYp@5mS|r}iB0H~gOssoKwwFcxj@Zei5=wdZ((_f}w&kLlbbr)TXFZ~Lf`8#s zA^qnsmDXkGc?0w>A7DWs0Zq4dO&qc&qr5T_>G$8vriYrNPwx}J$Hu|>D3aFVNPayO zvy!()`Xo3jT}`fs9^6f^|<5 z8-tLYOoj+TcBFR%R;Eh`9%fa*mxg&w@mLJnCOp6LVahyJ91FT}2)G|R0>WEUD@!{v zMX-L=ckWeHJojNXTh}_x2<5xauDl*cgdC;wS(8D?n82hlh5Go9L>=B3P_>rJyi5-b z{RU(*GLZuI$3Tj!gAuUF2vDDfwk#&r)}Vd<&#+e3i3IOLST7Aoa!>}*Q{_pHBXYvo zyI30v>R~x;SD>lJv?J^aM!|D_#2+FhC$3}AxecptWlk0d&inQ~OVe|<^>YHPMF4ux z1Mhw?Vrw7t^+W+-zku;f3%W#5X!&@=Aq+9*OP|A*@eEE=DD?SN5M@>n5!M!#S5c9d zWmcA#5fxKnu{JOQVW;OO)klyb(`q9>a@+e<@fF|wt10U^3LBiZjF4vPb?{rX2`c}d z%vvmR-NV)!aW4?=$B+S{P*@dtg`;%HPkstA*?T1UI*$%-bN5|(GUs=xcpUlKIBX=C zRA|7nb5lTyJs^faDTmp{{BE7m@kTF?rR<22h6I=`l=&j z-!0mmE}2+-I={cpZ>HbVKiA6*!oyTPU7u)Lzi;DP>SjOwM24rIL zXs2Ydg-4hgB0#Ekekp&ZW+}NZ=;z4q`NSHBS6HBh<^0%3G{*w}*d{ zI>)Wln$>?@G1YaU6p3!ap!e704?T7FB^&wEm?JMRE-`br%i2IG!Zl;_hWvFJ)N3Dl zfz7{XTwviBj+!bFLg>!8**e8kD>Q4HI)KdRg1fKsF9UEr$P}Ow>0Hkiu-?igWn$k+ z!mj%D*`YyY@*tCVrc_NJ-^lJrA`NV3Of9kulYFNRA@eFtd>6y}!camz?re2d3hXMC zbx9RM#F6eeXFB`i{uPMa)o=f#5nyo1BdG@GtH{a7AqVA}g455c>%Gd2eG_@2in)3p3AT?R*y!8lMb;)Z3 z(TbK2rU!)8jer=bqy6A|z;ozZ5G>OaMMt%D5q`vMB$1C7Csa;dh9!~L%rva=zU6+t zVCkqr?3DuE#%2_#oVo_A@A%L_1R`yEWgO`tx9Iz?`Yb_rQl+TEe7M2am&Vl?Z_mWJ z_1+iN3wocA90pT&qNNrG2Y+~(iOf=Ckkf4f({9`tCjj06yk%O)p!YMtUrt={3|k`p z!C&~^r_0LWW~aAi5_L$~cupd8fcU?9R{@l#CZAL>%wU>IEiO$gl{3ib1wbzHm(97N z%KMFbGBR*B*&O8B-=CW~)%-4h+4?y7(OqdpiE6D({$(s-HuoICiF5u^z@Fd%DPr)| z2vrucWw&1L64O^F1AU_?%(vX+C%6 zmS@8p5FGQ9-1V>d%Zb0%yN(Z;9>CaZ3*NHI`E=v0<&7<#ca8vmiFeY}bzVX)5cPY* zKwJY+*I}V<&0kpomOsfTPaS zdr3p{%M8DjK+rp=;B_?>pT0r{iPEnRv!rf_IxVunD*8*k`sM!&R-@XKZhWpKRiqde&mv-ib^cQ|2X3( z{*tEznbQ0=0?Bpf&h&y}n|BjknxG)wHKUdcQ5MEy%;44dS-(Ct8;eVH3^S_K^CAme*lVC4ZaNW z_*;~XoIO*_OE3M%H7|S2Llv)rp;c`?B85BdFN~i(ibR(9j9D!STym$1S5X|UU>Qvggi_Lc&2_LIQ7dr z%L0jP*^2)}aAE~I4I}D3%)$aI zxZT5QP51XS51WD+IErtjJXgHtuRh+_%oq6o$b0X2s{j6f{2V(wFMFP2XUm?M$tqdd z>p1q_B#xQvO-RQoGRmkl>=GG~ghU6KMMWs2?+a1Auio#g>vLW2>+}76fBn{q)%ZZq*-KrBp1XX;kP6b-9?xCQ+%XtNU!Fm0Tf-;e3D{n_-Y}4CSvSM1~ z*VA=GLA)ML{|yE0b&@?C%C)&xj`dX|`|%0e6Vq5(;8X4Z23SKPO4S%WnwKuUzStAHf+gm@nJoytZH{ z{yqHDb-$h=fl$7}L6w9$B+WF{t|yd-hK~w&1SEAkbbiMVzW1Bnl|{~@PTr?pW@NnV zA;v==>#{lR_^;xh%Px;cYDUV;x?DTE>sYdyO;1kt|1>JI*b17|I}-L(pw)O~k>%>5 zM~Il(_fZ*#(%m*|VDl01MCx%f)bC0kM0_qDOfWoP*OL%n*(P z{PU&JjqtFsx6eF`%*5DDaG1{x+(n^Se%D*kUvJpKkc#;D$#Y+oV!T@hcrtM=?oGn_ zs9wi4X86axx|dCF`-q9?v0B_mSjq3YE-LkW0%ZcI`yxvr>IhV0?SBr0Nwx!0}_-yc~-HnpNyX#T|CQy%@-2A}ZXU4$bX2DQY`Yu>9E zQN2|*4>mRTdY|&YX7JfjxWB%j5Xz~;5cc6Stac6$?ITb!Sp%{<@j~seztkHhx3o=i zPt?YLjT}5iaDC|+r0-RX|BwCG-={a!ras5L2G1vPp#LnQBTFRMCv}wYp#S2qGR||O zV1D+&i}^f@MH)>x=j*cH=)eA6y!wg4Ga3=ISdPA#~>ZIhec)ZFQ46am%DkH;I_vyNIo8}4Ush;N z-WsE+4jain;Ew{-PqW zEA;IlO&t1K$(%^9l}g>}BM<6i_ZuuF%xFy89aTE=3p{IIm|Wg6E!XcjQ|;*uJ%e$d zTvte>4CcbQc&jilAWRR>^GCg5!CQgsv73x>U&$o(D8dZinNFSI{i*xLe)%=j^RwuPW{hILsTbC(BOj^iqriQz z*M4E-6+)sM=o9X7C)3=#ayHG)t>ZMf{dNhaPXILQ%*Q+hQvuT<+S}=A!;gCPtM$M| z_)Tv}S8~FnZ}^ZJUxnjLlIvOi+Zz(I``uTD+{R#Cdsy7)-7i2adh3DgQw!1W-4}4O z2%BTHtEHn<{PHL*Dv*k6VRo7ODtVu2ePfppHIx>1-Br{AK^?apFHZa34I1;+`_PTLZjb|6FiL=?YmRy;#I%a0a)fYn>(Nlp+-Znumcl z?sZ>(DmYa8uL%yjCK+CAxn>gF#U^NL7>=^alP3r|Xutk5f*&n@fg96{-_r` z*D3Jo#0h7h#<1T}92)Ie+W+f{!%67If#UE1uS8hJSw^{JZh;bim$P!2E!RK&ONv7- z5yPmFyEu%w!qgG-xbMO>&6>8pD-Mw{n*MZ{%619ziB|y6MbUa_fX{IV@BHkgD`o#}sY!ORa(l}6@mP(++xWM6F*Ud>ZCyR=EK;Vw^kN_xo zt?^awtc@^7^={RzjtkaOrN$J`qdC8^p{%rkrv&2}g$llr!`OnC11>JGM+h*dqguYP zp>A#=UJYlO#yPbPe{y|A`DWXQ%;evwprHs?*cK>szLMyPcLCobGma?Kukiv2oOwJ4 z#qxtE*`_$e+TAoCGXTB|ij^ZEILm3VVai00*g`{hbWF3_1-{U*M zk@wJDS^Mh&^dnQ=9S`qXl9{TxoI3Pa_E?=x{~_mBF3*p1$a^^mWAM2_&@1;O!>vIl z(b$fNyw;!OkS~5lR#U`FGGVVcFO6 zfgOTs!otra8jUMXx~t2 zTGfle=K|k(6h8$p#4q_2hFhw0dHab5A>|FQ)a1a{M|%5!j6Dkvb65ohK`(^u7Q2A_7gJKtmokUprqn1gaZY^nky}s;!|pf=?po=+u16O71e4b|#2}M1WRx zFhk&eUs&;g>B)IP`)-zV-QmydZH-ErIhnu>;^^is;OY!1J$KPBcofB-t4-6jq{@F5 zG8nOn=D(qbiN*I%DV9c_Z)~u?{ebwHf3Tfs6*zzc-PmAird!V?VjjEkAHQnK z5>4@r)3SLF_D2R-yLz~QG)inO!l?L{f14 ztv|{2WczE0;)^RdC0f&;G|2;&d1%|#T%mHdH)Sx+IcrDEvf1|80Ke?#!p)N>u+^` z{ek?^aXggvBYJJZPJJ}Odzk#1qxpt}lu}Rq{`&j9JnesxKgy#}DbW@|l5=JwKwmI< zIQYD^y3zlDKk82VNgz6GjoFh`fQ{n`*{w*LtAYQ(AEmUq55r!ao{N(0^EZ@q6@&z|RPI=EVlxt&V{RP#Z}LY`KZJMZsr)!JY^&qOL(JD6#M`gM_k(`mmx4m-e}i9&0wRXwU#V>}NxDZA ziO54vF|ExnedG5d8y}c43aZPel&$jS8uo;G~clf0f||=$GIxm`I&*42aS%Igj-dwv@aZe zYcTv-7(=k*_UI(RTy8tCFxnRyYS9-w$R|nYF8_z~rR6l)N5{i7F@$g&M^!xnGRvCu zbnv5e^zMJ2LlDX?Jcw>)&b^yTq=&6^TgD+V*8=(Ny?SH!;c6Z2qn1a-#Dy$v+}(X# z+^uavHgz*0ZoC_7f@bUrVF4;}Jf4V|$5>kw#&0FS@*_FcS^R`V-Mb-sb>l7$B zQZi0 zh@#T`OeHfFCcIWkylHcOOI>BNoWeLMuk!m=A- zYI#CY%Tm=Fq(%5RT7ySB7mrq5Oy4z>P(vj_6?^CD=2^R#QnUcRyS<{DwM$?S{1m|d zOv~%$6+$aZw#=v8cU>so$@mMQIN+V|0(y|?yF=wQ4i|D)d!h@qY*_Pk*w(r9G|m(o z%}H%^95NQwSkd`B+f5X1oV#c#St;mrhY-a?uZ#59iQsCr1Kd#rx8){01j}{(Cs-dl z&<=yuItUoSD(OJbD}(PvYGGq+Q>uC2lXBGmmfl*IIs*Ab*))}O)Sp#jOKn< zqFdgCOGi3gVoWW>4*ggkTL`QVRKMw@yT|fIGFyY5$O~)&vE^w)O>ih)pcp zhEe475~CuH#{7>7?|Tuc;-3ut#-8-@b+hzladfqG{kFY40wJoGO2!(CMaYs)#zzjT zF6f*lg%)q4bRgb^PQZL!`LkvtMMc`FO8G~dd1?)z>Sic7gWn!U9-yZeg~rl@SG zqpku;grGNZ8z#;0<^w%Po_mCPCO)GVg|Wb3%pl)RJ&-5t_;9LNI$maChII;U z3=~GKs|?XFQj^CJ1~toIMiMKEl%+WMt4}n;s7^r|FPSLc-&pK-yf*dR&#~#;W|9Bl zW+qTltfCCzbmK3PmwVGAdF4~wa?0?R`Ux&J@ZZ~w5DFe>Id*0l&pW9R>B+l30(Zeb z#`EKJkXJOVHJ0qI$KnU0*1Ey*>gz#yluQJ`T~#730V!dfA(@M?49+vP1u%1Kq^HgQ+~$&MrkkTiB$v zVhnXR4WZV$2%5Vcq&h>?)$TVr#ISxZ&{gr&x&MmuArow&j!(1%kq*v&S&=tZ=i807`U(jwE*xWA1h1;{AW#h}y8oFi za9w(hJWN;4^uz4{`Dkz<5+S`D!7~g29ySOhDqU%=70_STl_db+RxdVA2`*DDaR)#?@UNa-ulpwy>1O!|`Stv4k? zD3Ko|yPW5WGO4-|H47r=KijixC#vY(xr}C`M|wN^xO+fCbD5v(N^Mmp@|>M0cvUy_ z>aNr~6ddQcwYQHRT!z}(1tK)iAZl9WLb2F%gCVPKN|ea4KNrm&4&FsV?w6;9uwQJS ziKrkMV~)A^@^LH*#th=zmY{bN_^5G)h}a|3`eMaTHCFOuFVfxA2rIsio~BVhstmar z+S$6DhNC*Axnih7|4`^z>seitvf?CwcHsEJ)o_X^jV%P9th_n16L75mIp_yJo8)ol z4f03QgE#J{jD{x`Rf%0geH-;oR*@%fr}^Q&)D?r?gSpw*2^2P?nZYDp5lC|@U~j3V zTma=sTUUb6>u%y1X#Qmk5Th&7b(cjC>9SEp;cA3*0ur4NU2MOWocW>$`)4*-AIa{& z-tm9JLs5*0&^xl2xLv-%7frcl_K9gg`bqeH#rC)KKflt?VX!!GT-|MbU0_-O_Q*}{ z&v{cxhs;-3HjtrRMpp_tln_9Mr7~-po%vP3)4SUlXU(*Y&#|Gk_uHcr zz^~+YVPxM1P9tV%ZJ*!ks*h={XjZnW&EZYj2Y*+}SUCd`_3!G2LX{Al6m_`AGODP1 zj<(kRruxnlp!q^-`c#FB#cim$^m#x>{**lPu|0ag{m9jH$pCZaq3rj<-ISm2i4&w5 zp&1KvfX8IRJ%mOvm(-&rmk3K@oe92DmcvSamp7nn{hw}|zWecm`!5i3nfMJk-_Y`O z>bULGJ2I?Vf-FkG`@8QTG}RK6rTTz64zBe;`LH?4~7n_{qtd0j{r#Pie)J(!E2<=-fCR#-8@UpG@&=msIP1pqqMz&AE0(!m%u?hOjw4^CLvgfyRhSji zck5fIjy4Pq+JKZzpF-Z5M_SA*FNr$6Yiy~TIDy%#QCHVk>{J{XII&umDlTN^xLuOu zq28@gH=jOeX(x_4`OxG^R@=;C5?Qq`+kTC@sYDUfa!%q6(dde*A>pU3v+2zsqi?T9 zeb4rF!p&ux`>5q;mgJW*@5v-tunL6#RDl;~Bvs5{Mk8UxYZ<=NJGn`J*1&Q3tDY;q<;ED%aH6wNpcJ<1%LFIB+L-*92^!>VRf+0z?xlmp$t*qDWRFI zzfmf|jm)kI-_|5<<--LCNO|6SXF6S@!Z|1whic`fWPKJ+$IvR$l)TiMut5;+&{%g% zK~RML{?vIF_MG+AI$sq(8MhY#lxP^~UMXm~6Tq@t3ZC9C1s}f>Sh+B{c9m&fn+f8) zkypD#bLXd0a6qlh&#OK4$&JRituxbY0*km)^508AlEa-*vkjX#Y8Z{hTu9P0&*jT6 z4oX4Uol@{)K%4wcBkwb}RM;zNwdE~v=y=W0>{wuuCmb7qXCZCwMs}1M4RhYSTk_#c zEK|n-3dZtdIjDoQ3qrBc%5u-E-T~5WJNs=io}f9PI(jyJKu_e8Dr1q8VUvyj453Z5ftX4TpkN*E!y$Ijmf1rQPB`B(kfl)hL&J=ZW zLQc}Y_a*bi_3^gq{fhAi{G5nd%5<^IXH8~d#-;lMo_OYrV(3R<6vvN8-0m3uGoIHe zJo(m39Cg=Kp%T84*h#gwJ28YjAV%r7ar~pFq?0gSGEcXs3EaxX*oy_my<0omBf%%D zwGUFj+X1q2=kwYm-z7ixx8=h)X1zhU1PP8oJJWhbFeGUY?MtX596b>eWsu2e z#5&_4#)X0tyCS{4L2We{U}NX#2J5B)CEE~Vi% zb)v#H(~wDvYW_ObaWK%92Lv44xSbk>6-N5Bd39;|yc$HpJavu!05}-x@|Al&eLwv; z%OxPtT4~sn`w_?`@3^`Dc|d-{JQf7&DKC)!5o=vY16ezD)t@cG!{}k{kDus-uHNpa zc_8F8&>FLC-<^TSkHo+G>eRJhd~IP2?hYtDM|2eVE;TxkOKC|`i%E!$?F)V<2A3V% zQbk$Y>J+d(Af#S!rt6dJ<4|@vpf;FQibZnoj@5Rv)^`xAP59lY|LTx+f$_tL_Dc*N z_innD9>51a-(4eT+M7*GLaeewyeOAQ^Y`B8JHBi(f>K`bRgkWj<&)vLebHDRd>@{+ zj)6EBc4c)2uw*pQKb8nNg#)uK%(FKcy|Z}nU+9iJ2&nd zgLj>#$e|Gt0crXHKhm~5rL-4M)?`&zjV!%eUGU4-VF4vx)j^4R?JNMFmQds-_BniEhX_@t(=QdEo<6hmt&J0!T+W$EF zpYQtqAAopL+#yJ^#n?(_;SIS($*jDBRm#F~d&=Ro{rmgF{`)oftxi!LCFVVhVE0b%yLFpq_4t(+%XVd8{h5E6SbJJ_?3!Pg!w`Dd?5zY9X!DZms)f#LdRMSWTe71GZxZefYrfDun?pq6Pj zzw4+K51{(GbYb1|xv!Q_aTxxoF{~~_Q@n%xuGcuPQWkQ`vIsCzBq@dhEN58eyU?tP zkiGma=j!Fj*3h^lQdek^WQOYb&R26aEjs z8pO2@?xlCt(a|$dvo*bRzZ-61X%_l`%yo(PdwSPpAm$PKk$K8k*+H)MO{Sa29x)1O zME)VYD_*jzEHdAxS3GNw#2eahzfATM=1HPG!kMR6nh9ujefl~?s1;5#XJj~ z^$Hg80|;tf$+he2sx7Iag$a&+GWH4!pd0EB()2?V3LB*LB55%nS~d(@Fo$S+K7_Ef zDu0)z@1%DTm0ov!K`@^l`bZ;l+nJj#cuBNzN1DEu-UXg(`5#NEWOPzB7`qWU#Yc)h z8A*(jpxJlhyVzL4_^v{+8}Ar#Yvu3ErC@)y-(G@INJfA;S#~?|Tx@{Y*$_lS^Rr{a zZ3!>P)6AoJsc{gXyxbWJ1Q{aKfauU{f&lib7Hc%FE-w zygV5Z>%ytc1F;`Nb@9o^&G>-znUONAGL({FPQtIeCJs;v4l{x|GxiO|w*amPAPOPqk%7=z))E~{zd`<>7JfS& z{~%5JA|PI-+Up*7-LJt_#?&jCbesQ;}smXvpt_H&Z@9p%~;FMei^3VLOA>OGgi5Xjq#aGR%t|!pF zxx*3P2M#3Y&gkqwQe|vR$M01vw12=Ar5z9Su4oNhl{nBR{9maLpDz4ryLfKx*mz{> z@NA-bEbfhTFj?b!>NJaf;hEYi$B#BjmgmkU7qf1^;Qm1$j`{KdAvvzF?dID#XiE+o z99r;6IM9c8kkHW#ABU`MubuDs0uiE zqVWJJdXTcVrOP@9TUnxbUEg(uR82<`CmW@2SI; zO&B!n6I$Y9@K0~4E;C0kbP0gKDLAcD)PjVYtH3if#L;f9V1alLE5%u(nNGoOhF4?OlvT_B9jM$t4Y5fhqUM% zN!GqD@)0l>=4*4gHG6Sd3KC90T!d=EmNc z(y?v=#|}dfFXWYxS#e5O6ZXyUa2|<@Z~BBCck4euwE_U!Zb8wgiuiiO) zRxt%5rla7({6TzRz{}-MA=tfeh~;yY>$JxLZxEjXc&kC}_c``Q0$n4wEH23y@)w;M zlRapkiBFU+mwewKc-MWq=uz34aa zPn*Hs>fr;Q4z$51?o*Uc?)+Y~!_ z!O}^J+9Ng*12LlAjWW8_RdK5{xQTJL(LVsQPLr>L4nMUsPX2RM_YAb`FGbyy^aqd- zq->>v_~f!5nJI1D`Zy`BuNiyOfwlFoMcuHS68x{ctwFBJj;Nb`929k9-BwEBc}_Me zGVxUZ<}8lsI+J7?DC+(bZ|k2#-LU)ZSS}^n=jsWgN}20~pU$#HsG->ZE_3US1N|-N zZ|Q^*!tWWgBU6jUcvgHY)2`|{oJ8uq-<^T;0PwM|s(F03|5jf=l$hTjh6k_lJj71l z%ns`p*Nxj@lY<@Pmjh84Z}sXpD@h7;Lw#&a>qRl50!j2Idi2aasLzj9=^`>U4?$x zYRzJHywAet(-9d)s#Cfz7BVdU2i##4$9=braU4U!PD6?!Y20CJ zP5#P{I5p`sR2uE&L$?26);S8~J_U-c?#)N50xME0J#0fzvj;!TI&WSoTc306$0reA zii?;n%zNC&#rJ*I$@i?|iKJBywT8QMe#FQ7SGPlWMgN<#&VQ9V4E(~IRvzpJ_w4W# z*nwYWsqT}93-F2PF-JH9uvSHC<0_9njGFOu{yyzg_;*v7)ZG{)mR!gs@D~nQFCXk%kS>dWW5ogb=O??_sPRbi~ng9e1DIC`{e*%0P*IRIH(cb zsZy>!J=F=*=vNb^n^#UQKlr6TcsrJ3ef3b%#VWDHlCEL=?70e<9{tV~f*Gc$qwVDm zT0kC!Xxv&ok*t}(v6iCcJXcj^N3?vDPFA5L={kALPguz6KW`&}&pHn24Q=4XG8E&G*u$}_;w*Wq&enll$(Z%*4@_TxAJ3=^j!0=;iN&Z6<^eQAEa^H=)Dw`8hP z^YRIOyv;o}*Xr?}+qnC3$^4GK@yGM6_qfJY3uq_p`U3H#=zLPmD(=!FKb>zzP;=E! zVaD||3D`~PLFw&LS3h)oUvJlhgEE#^FFT(>RvTt7J`(q>q<;Q?+j{#r9Kn;AI9MNH zqbrSfYB5t^2gdO`r`r#NAKJ%@E%}*pT*+ssdl6jI+pKF8XZO|=G0g`5IaNkp-H5vd z!%MS?ch0xHg4zErIZSc$Z+I+r)b6h*5byhP7}6YcJWE>X^nzimxPxNTP_+qRAEvZ= zU%>K@ev5Ou)0dn1s|v5Sm7F9Pzb;{D%JBB%kMp#@&u{VkBUXRakzRIpe=Rhv=n`Lp zsB_={-Sf0}_dK*;52xG@*)GxZqZY-_m~T@1ah?{wO4k?_q*BNnI2a)vP&qo7ZU-h_ z?fWfmw%cNFnbP8=o4q$`eD&2dcJ4CtV4ij%n}L*?I=*`IrguGVLdmc&g-ZO-^R%+= zE%=)|)Jl*SiHi-<+|O#lQ$aG$e{P=kCw_}`dql2Fx4C-f`X)54R?MBPl6Uks@16)h zAab3xv21df!RfUKyvSPzvyS2+!8HSqjlUYG{hTlUYrDnYAE-$^!AAK`d)x5XKO>Dn z(o}!+6VKlts44m4F1K?yFz8OiI6iyZq(d54>%TuxV^WcMsyeR!o_N9G+%;{|C-T`x zw+;qs-Mszn?#t4`pHCXI=BwP4lys}F{ytE9Iy9;@K+q%oS(bQ|LHLy0EouRee_^2Z z*LI7OO0nadIydR>$E=_VUk)8zEqTee?*`&twLY;v(1gY8Fo#nb^Mc&qBt`d+c8e*& zP@!^H?CxwcfzzgSpPrMym7xZ&#g8L3^rspD7j{zRv&;@XZ={(eE8m^^^n=}EzW+;4 zz6Q^Ec2)^TTdW~<;lWbSOm^39@h=8yy8+{WZMXP4GdFQ`)z{lc%GOy_buMS9Mn1in z|EUJtW4i(4zwldp4Q2alyTzS=@g2KG@&L}|wr> z1NGbsl>4Vcw?FY)!~x}VV0`$=z4-7y3zXCUX67OPcUUPN}tS zAYn%UrlfZqY7YZ88Y`I9`YQSj?X#?G(MOncyd2$pc4v9s?KCXf33{}tUPOLp^g%f) zWl$=3go23k^0`~Fb3y&*PaNVpe>lq+?yXg`fo8=(G5~T@4^4r=xXsO}doJUzbmbqp~d_^~jO zPGRl|kUNY+qBgYhj_<9>{Ke2b5MPCI9LJsXiZCXCEGlwNNz=^YnQ?n4V|iA13K2#h z{3`(pJPVduz+_J#@M*Gkk&aGqkYe?NBev4|mE%}9bJ*1*I| zoV>C8T-9#ldcI?I`}gBt=Bw1T$Y)bdR1b9X$g^#|&=H*6h=pAK1z+WuYXCEXi8SPH zg^gA~lfi=^?K8_5hzPT#9+J--z(FU}3)$YJI*!|e|)3}e3^n$QaI zh6BJl`DbnVv$#4LRea0%ufF(gIr5&~2~D5^5;XL3v6g;hy2nJRZoy$0w!8{ zIa=Ge!1Tf8O4AsptjCt6-9Ui!EbtDpcxdggAq_>S~@TuXjO&t-g)Q+wg{Pu!K@U&bn2 zh3Vk2addGE3L67X481mK+oTBh@tg4&a|Xk}NUj7n3t@X% zdpp2xLXn6Fbzl`5*I8oq`J9f^!i%S$`>5th&Rhlev@IJunB5Q#-pHI}tFEd3dhtw3 zsn027i>K3AuH9~C$MSNt3p+)zfeH90SaC`wEhx+d2L9Q`F6Zz+qLzEPvSRT4*N-^vw+bt?e+mGtWojxd(Z7x zJS(cW(^C$3IS5~nmovnX@NOP2M7dWF$MdzkE>X#Qn!4TC2To#!KbJej>ox1)dw@u$ zrK6i&_*vlgQQ^w>1=x=VC*1VqND7s@pJn9PLXQhR>}*|;wo1U!sO8Vj(WYy! zFDc+XhZu%G6mMrlYwRUHFaZOfy!+N`GD)0^3b$gf+FyHm*a0jXIiWtjVM72h@-nC6!cx`E7?bnu8-cydKD4zlr7= zfRQ3ZNb7UCh?^X*xBrdm?nDAKmmAAgIfb?1Ebb>wuRTfLf&TMx`b5PLl5+J6(%`YpZZ@8&5g z+$91^LbMJW>%V!E80+wKVNpEm2fv%_f6MR29AM%o&UPL?#t|~I=v|jx!{&Dci(qdy zS1(XrOB+k_TD~~>^TYREy5>AR8~?(*_wO=%?qJ^EFFXDhG^o25$(-zEHC#KT23@)2 z5d0r9ohDKa2EKcVWnihRP!m5dBN#&q<-AU=U;fY@2RH5UmN1G9?^|jaX!%8R`)Jl7 zDyN!mje=B-II)o}P0l8e^i6E(>TPcc=9BJ{cwxc-HI8YPnq$1SoD@AQ(%@9X=zOOw zhC-OY($g2Lt-RbEtfVczh zhr@Evu48!yd_?IyDmeGrPhbdzsSyr4VlYd0@Nl#S9S|(RG_{?lBuoKdpw=deErhf<#?j}5t+4JYbxy%X423ARi@TdW>^h+GC7!&gf17&YQ$fxfu{>%y<+O(w z3NajS(1O4RCJuZ=pRb(=WLF|N)fAUcY&JhdeeF7iP@K@#+Q-@wv=#sx3YaLsnDDU< z&@=QA9&5Yu!lC=Ma7tSchDa0(Y2&Mq15lqYaCz!P*IZ;Gdzjwavwi81pfNklA zL?~nd=ZM_g?A6@7qsK);aa@$T~ z=p?bgXO6;kK+Z<9`Lry>!}T7$H}@0AjEVVUG%)nCINnGf4|kX%S{0Z|_{{VqJ@Bdj zRiz0ZQWd7|T4QI-VO1P%{d-Xk=s_jDWV~CDI9bMSkY^4+&0JaXzhc**E zj&AXfz7Dn5mKbR*F5<(-SU%_AW>H>>F&K5@9WjZugl*}Dw1raugE^S$QjhoWbPWcQ zl2jEr=nb4z451qaPX?ZBQwOg9ponT0cZs;tc-c6`K_G?RZ!wPaB(K^12WIq8Nrq0te~p?iKg|px77mYX(0N%G0e;Pu*-HH$(KF7Rz|qq!&)0}tS< z0cj{=)$>dtHm(S?u|M9UZ46N{+8qoT^tA?nd0FOYe~rR^u7R=X&u6vLYbjp&V*qh% zUoS7Dl_bD3ve^!86Nya__Dr8&tg@kTPEy5CNMbqqAXVc5{||UwQ1Ni?LN3c>eR86R zCUW8q47C`8(GrTCgie*5_`MVpF|Dkfp2H^oWSA& z+;4qh?2WGu0j?dpRMyI)&7dgGf+3W}a5AopQSLo(enbrlgg%V+bWVd$27XU43C$Kxtcc zOxnPJGYqK{{=S?uWj=8J#q={~8=5gh zVi1IrFQFUK#oKa+Vd3TI%mTP|uU93|NX#=&3kQvwpQ@OnCZ@qq%fW8IDgZ`~{-W9h zM!>DLn5h8kt=GLKSy~LWB*dE)f%pRCXarJBX0c|areeo8%g+&aUb2|O5XlspEa2h- z*%z9cqbLf-21c%UYDZ9Oy7#Qcf{!pZLU=2V55mDR5N?eHYP;Anuzei7d|As`W!lvN zRB8NULA%})-DrwhMREhiS^{f%44pRSkQz{5@4-EI0k{2YX{qriD+cT(R%{Opp&G8Y zwH?wYP<0LprY$8wtXV(9HG%C}Z*8dW>nvuy?d$Bw%%Sd!xz{jmR{5vjIEL(EAUbKgx6Jq$w?x&oBu89C!I3-k#lcd6;jPZu%8UObK=^0BU)#P$G` zVuP01yxF{P(eU1(!FX#oVc|dwk>qZWOmS?X2*63OxM6sM&Aj+axs#&X`-gAX zr64}+v3NUHY?iL>HYLCfjRv>Kn+ydN8|pP&Z+siZW`#f@mgE~eD_C^cn-U$01yOIt z{DmzjXU*d`A@7II-nqy-O{4=8TOck0mfUHt8wRM4)aOTKwN!Dt@x+XkVMt@<4mSV_ z?49p`&O;xGvpU~yHxe$Ems3|`NLA2Zfm^KOq-BSAEyj(rLc{`I}yGNQvy_F*Y9-P`P31n{LoZ@TTOdh;NRn3)g5>Ps&W9i>St-CAQ<5WG z951J9;v&R)2~reE1SW~E!KB#6p~wJ*D?lQT9MT(?ekObSc4ss542C$|nJ~%+gM|V-pX#(-ICCZTiMG3FY98K= zdIQR{7(#h0f9t@9mjP8n{0CZWR2NeS?&k1m2H(xj_rnG2!18lIq|;nPTJI)pVBlLK z{T{V96>`0J7(na|b_k#-ax($%uEzanbPKZz@pIe?HBcZ(DN`N_JSi3tiJRR>a;6Q% z3m~3m%zumDhoO{s13>|W%CV{r%|pX|>W^PWc)tofTSweHdm&YSReg;I?Ya9hz~12)Z3R2 z0V@Jz%`Q_`$R?9{(tT*ERuE1Ojye~HF5+%hvIgsDI;q2E=UogwH%Z=S?`JW8^q$K* zb-!i@`(20q*I=GT1QA5`yivute-KAr^h+lhSRDUk|J#?vyYMS&Qp#6lE}-?oiwya;!sf!KtS@F%4GVb zouX>#XQn1}8lG1|d4Zc-&;XkCN9(&tx~FEeTOVhoPgo3A^-MRzJq1EROn?T|Izr$v zwD}1RUs_ZQ8Z^()**rg=uC%d(o`KeP%{h^L7w?|2=c|5llQa!_MTsXNu^F~!W5+?h zBK{HmRBWI|2|t|RR0!;JDl3SC5?bzP_f8Ktw-lw}&q$vrtFFv&J%nEu_JiC)Ij@SI=U z2cAn)(b}}q=eKFEF>p;kTMXjaoNqn=o`c<)uwYYhf_c*#d?ggmgE7{cXTJl_j@~JL z0n7KMZoZnPHLJ5S+FXtO{2h4Cpf-e+*cuH9QBoeRUyKSop58^Zj~q`LWpKrJWp`0H zQAV;|Gt9Vu&fFJ-J?Qnc6_u5>A@8Ur-X6vo>3n|G;0-EygHObb?iA=casV7F^HG3S z74`VqzSk-#WjMO{CRZ;;%TGdmnz`w}8K&R}@to}B$2;@Le{Hn}d38$SRVV`nq7Mf3 z!9PTp08Rq|bCBnO8N{CJyo-__TheH*se^tZc;8I>SZx4*36^nv{Y{(ZK$Ux)71ei- zr?$m{f8!f)oODx5HKuh#>b!FPgwQA6um{2Apo88w(>|e0%Jo@J;!9G7#00F!k1ySH zMEv%FV~tuTc6QP}N7_&`y}EINXRNYO6HsG%?LE`Jfy%d4N%##ExOmc>N*=mvZRjU4 z7^o_(yRVxM3G2OO)Qr-5#`XgFJPO z%-t4?aliA?Qep&p$+1)YnZ8z_>fzij{_rucz-Qji&*3^Map=VGLS9HL2Vma%a+uRE2S>Zt_ z&L2$pd|4>_)+kQA=|`n@<*6{(2xMx3Hd}@40Hxe9B8|5*28_)y*x@jRz&k3JKklU! zD0$I(ySpGEEiZjpmP0L8%2q7Cyj$pbSvoBR2hTEweUH8Dkca6+>mdQB-^lr%Wj335 zmB&|);y7*shSrXlsk!D%$!DqAXp6A7^5gaogip5lE(a9_ku zolb>}j3D&dsp2xk8z6+p`$DGKr`btGa(_~2fe(A&Q&7tO=k_N|@B+9vHNqJ(qhnwF z(m0$k0G{hjGDqTJSRiHt={V4PgL;B!JjfAYlJ=U43x%RpRp7BA9dOOgdo^JSeDt9pC(Sv1?B-NlIn=R@AGR-h9} ztaP%H7du9P{T}UUPl5YUy*YbwXS(O^LO2?-OIf@(i7Ba_nAFAv+R;bw^n8$@@uVB- z63~6m@m`JUzzvt}`J>yS%(u%`-I+lN`OcsV9Q1%r4&J+-#5*R>J^?-ueqpT6k&pTz zL`TmHAW5}ON1x1kQ3wXlqrw4?8(+T)H&#a9;l4EGQ~5D`xuwtlJCB`@jVN+uK)X zCRI$uq{^{`F34@JQst=4VW4^nY>GU9wxfxxJ%zReJTfWxwuLWs++>VBh$a=v0Fz_) z8F)TXStHM=jngVa##NH7Kucyeyj`fs)g8_a<^jw%+`j^$H@M7(n{&}D)OPI)j+K5h z9}_r)@sgMSRT_CBzL*m08E@3q!PkQ>FZxdVbtg3r zevQLMOvyt~Q-OxnMdxh_!xwB)liM0v-AAM9vS=ZyXW~O@e#&RS?HtQe>(v@wpD%jU1T1ex6or z(CSpmK#Nk01Y@!GG4>miVw;q$@4p>eu#-DqrmsJDOhR&tfWOK|+MZo?h@(ITkb8DyH-@k$W>vd9?#F4X}s`4~<)6=>0m?~4% zw?Ci#OTTfzb~pn$vKWCgpFfEoWOVYC>*+T~bO3!WsN@qgjYMD$G` z*(_(SoRcaFGgdt?c|sgFv3OY(w!aDFJ)Hibeh_Oc%8df!OhWfHlhs$+UpImOaUM1K zx$~c7`hui0Nw?ocZ#)w6)mj2uwM1G=c>pSb9qr5H7Pu6v&7`YEb@=hMwuZT3VBXO= zw7(17q!G^N6H~+0u+km*$QGUAQfop2UNx<^+YV-%XvXQF4zW>+zMPzGFr~KEIkil{ zgZmmteLrYuZU9q@cHO+ zNLGF-!8E8J^+M(AS6*5)VSC4Nkot#xCQWTZ>c`;NEq`6c$K0qc`iC+0H^1*QIacPv z*;BQWYE~wOyTp#?1W4RG^lhJ6IU8(+pVrmgLm-O%JT6znzV$h(}_ql&kW%V|pkpo?*X{lanFI6V!QOr<^>1N_pPdG))`4Z z(QB1{Ot;Iq5GqGXXL$icf`eW~(?m;NS5q1G*QVnrqct*>5WkySx#LC$uojB>a&AQJ z?{tR;aX05z@={%D*E)D}&eJNr^zQjlBWeAyG3NE#bz_6I^YMvIo+!c@-5q$|x2>+y zF^IwWO?4Rt-k5Ih1AAi%93rNc4c8wuk{$2N=~gHfGR7WPv8g?HR68npnB%)fl3Zgw z+ffz!Eve5bG1CG?Q}*YlYNj!`=`{Z|Z`uRw`S!4arwyF7Q>d1uPy1ZVtbkh1GG59C zSnxgg^e+UEKw!L=c$N=k2X>?;oP?sE-14N|u&-|6S*Qbr(7x%|b9OL|^nqtdb1Ho* zOzl(Me8!yRz5sIgm~Mm8jNI@e?UT__;%lp?-n~`?i`ZAwvDi5pnK+z-f+vo>vpczw zF*W`8`Himv$Uik5f6bdVko=;$nRK!mz1?ypcgu5ul0UfBnn~AE2Q*D>5Uwh&9s#gp zCZYH1uFqc%POxW+VZXShPK1E~@=MJh6p&s>5eD{r^r!+2YwhyNgPZrG6j@fU)tYOIO)Wc!=ZdKySLSijRxhH4AV__5_fB z<~rUNK>j<|acQA{vBJkS$^fGk^m~2#$>>j#ct5+234+9)3aDZ-PRqZd47TvZt$kVo zJiT0d0!Xo_M-kRkPM-25c**?E+p&@q96Oc84?FMQavekUuvDy)PsHfV=osZ0Kia4K z3^MwlEdMHiq=eKmnDL|MW@aynjFRT(K00yb&JZyg#`D#6?1nDHjtgg4dp}>NCm&)G zrucjpV)@l|e1eDHKi*^-8NEWhruWvjph?4h76bXsbu38#q3cwWP$>b)QvVyz43&Ia zp=_xiDg!>P5WFM)80IhXqykRHxClNSqa6QkJ4VP2HAIz5&Msv~MN4Av*Z69l&3p`_5%)=N)p;#uC4J@LfG(IQ-;srfQ72)_FE*^QihW=y)jA)fee`hCsz=L@K>a|vMr zGoR(3rqL(9lo+a8?W}*7%snuiykB4cZGEc!eAiZc1VK7sdSGl&1Et%|fG;qnU+7a| zN3~@Iz2lEA3l%oJ*AyFjXX&{82YsrSg6O#VP#Axj!ZulF1&U5%X-el0`qb`FW#>W1 z!_3doGly=GGw63r(To46Pu0_n`U0DcqdiOK{=jNxcHm6H5B&_tpVN))pQ=D z!1jIgUNXw^nQB&cn$f_4Rx~DDt{!Ut$luyS6K{2WwEA9W#6?L%BksvZDs`hwkssrSN zGlRyMT)q!lI)!{RGQ&#-QLH$7Ed*wvU1D0M;8pD?gC})zwkh&C?&7p4)XH?+5`q}cc22BfZWncBRKdN3o)U}96Il8nQ|A>9C`ZJgIEN=Pz zKjErX{+Xr~IRweSSZlf!d&yKmB7Bh1uYxey_(S~nJ_G^}x{pmXlHj-@uNieSZJhL?1&1CHj z-mS)a$RD|Ckmw0FC+XEE>WZbO1Z%2D-Sc zL~@hROQ+Z;^^e&^TWrNXc3yg^t>!nS`c3_5Z3fhzV^7jbb4O*`>C#(juUM3%=x|@N z093X(masi4+i?mQs{LyH8mt%lvf^n)j8g~4FCV-59L0sdFaGoZDUH8We{uokuB{W2 z4Jyw#X3N6my&2wg-99Qb{6gwXPIChrKIm}+MUa569b3h($!wgv%Fc$jkfnxIh_j$t z|M{`;p(~&n_!7lp^;Owf0Fm-}Og%e+q`52?s?^!8@@Vu{uiv*8NgcUr?uXS(YKG%> zw7If|nI*TC`KFp5uu;N%f$+9Nr=?I-siTuQL+>*&+?hN0q9zea4b#`-v=s|fZMoF{ zQhV_9}8MzOcYOw%(DkqJAhc_tp<=)LjKWQ8Clqo&A5RwVHVj#R|_Y^Ij+)VCC@%p1%WoGZivV$C))&j!N_`-OWs%n}b{KF0&58WC% zcwybK^eqN2_vIz>d)oXWFitdqAT|hH1sPlXki2xH(R|S(Gqr`65H_8YYm6r+9-4rk z@T-c>($UEkegw+*Zw`+nB5aUc-S#Wab&0Bq9D#Yuna~{GZNvJSlku4h>r$J| zH*1Grhn1ykK10JUVDF0T;H7e$Pza5?*IM4O!D73iut$>duXvsqEu(aI*JQ6>LM+i3 za12W=Vdmgv)3{IvQpCGUQ2-(H2<9`S$RQ##zayfx}{7r_&i)aib3XYHMa z9yY%4S*46k%rbY&_q;Y)I2trc23!Y!yE|(NDX99T)Ac?xzL2Dndw(P(H;A{$;rps+ zbsoyX)^`bFyxnUcEjIg}U;@7JOw0YJRq;^)Q+b1$Y#`~2B>dP)M}tYLIP9HO5ff4% zyG0}m5wL%-98SsRL@hY0pZE+KFMD!)g_}rSD2J5tOKvbVf17{Ci>y1Phx`OXGk>eY z%AEbR!^$dM&NO|RkB*v;MkxPTy3z%ki=#huSUE|z_#ci0;(I=@Rnd_K^EM?=U+zO>xpzFjr$m;~P-f{k`lKxJjtlxX9XK}r?p_|%GHse-2JaQr+jSG^wk> zd+S1b!T$QN%Tto-P|Q8d0uRDn*Gsv4j&YSVn(R^6EIhE!@bLT zK{6J4m#5U{!I#Jv+H;H5%hYW8{&)zkMrivV=*o~-s{M5$Y;&rG&u*04#^x0VByQ}y zl6Lp~*Rz`+4HHzudbn6!r}}b6mnqq&%o*K?Oj zJJj|~`~J#M7@dAT_W3|orNqoO0!q}tR^Y_LU;AEK{U?S(+^_oxWG)nR+!CW5KU%g9 z^JwfNFXbC|=NI5VY!CXOK6zZRjrw;U287~iR3)XzdSNq$YAGv4k#w9Ajl~V~1p=>_f*LN~YITfj7E8UwSl-39pG3*gIIIX&@?YBk zv&P6zVHLfPyIMfWh4=ow;m!Ucf-8w=j77O0YAw27`T&*TeE7Sy7Q)8c12_TOQY}yA z(U;_zm63_%t8EN)HmrlJ$Y3Ndj;pVuhpVlX0Q9n9V{83*&MBsIrTF5NH>yws?J=C%-)V(ty^0$c#+=LILC?hzEw#S;@%Ezgjf($_;6lLph2 zc`~?J(YS)xHcs9)u1J1p8kZl-cEhKkBzVWC9!^0jV&O`cR{UGpW&5HMe!BZ4?Q=@W`?V!d=cYnQ%0Fh^?& z<;(AwFWF{c?zS`#I)nLGW2k4)8R=QCA=kI>pEo0QL0piX3wV24(5*g=c{&}QBBN%e ziIL%p{KwT5%>c1>$9owm3l+T*-0%`tL;6q-kb8A3df%gIO#8l@M7I95_p*K}Z|L;+ z`&e=t4$TF*`54>s5>x{l?r!|DrCSRjBw7-j6U4&R!&`D=#vNI1rGS}GEgQqeR*G(gz89d3l#*1PnaNh~i zLihqziPa4#X#;cq>ag};jI*D)DvZBdDOh1^*Ye2~hY2j7tX@>VO1J|7cPQ>}p3ifb zP=2NVMGN-pmjnB-8X2G}Tf?l70}Wgl9zI;t`n~!zSw5j>iCQAt6=lP{(-%9Fbj8&~$eeq?E_~PW>EQKi%P0H3yo^a)tUEhI~_nhYx?EGLjEfv~W8C1k)lo00rTX@Rd6ZvCb7{t}_z_Q92iRPm%N> z(O+)oHyj3K8&JKfA?u+rYGIgGWa_}{D_*1;q~XzXPzxOzj}tt*v$&|#Y4Lss;}P># z`??MhLc<3D$A$~!T|2@y1To~tmFpSlr&Mu5F*|$I$X)LNOU!jN?oRv7WPn4M+pV$q z(<(d9gmSr&Ds!_fXuloTRnxIjg*+O|M2$zW?5YBNh)Au6iD}HNbHQmVc$^Utg}$NH zV_f1M)tVE@?-PigFe;*$Cop<(EEQeBeG;^$4A6C8Pi2j^H0-l1aqu&D8pWo@dHx=Ht`@mUl{W*L^2otri41l03+J(z~}g+TI+ z!?K~Sg4OnJRzZMVLE#9CO0;if?Y8YWzgYZgBf0nEY>8xJ39i1Pnmh1eS>-^yo;6Pe z>}f~K-_!=U9I00nzp?QIrPr`?nba&iyl$v%DHS?A$Gs_4#c;RsgFR5kVCwk!HfTbr zRISm-cogyQo%zQ%gf4xNuFbl!_sJaTzh6A+RAeKP{wb>@&LE(&Gl>huj(I{?Z30ss z!diOYD;2-s@#v_ZZb{gpEhXpn;k`F$aZT_eI%I1kpmyx$!;jjl_;>u%8#r+GbdZ@c zkjHaAYwDuu7R=OwQ#^sgTBh%&<@X+0Ubb0!>9*u`F)~wSHG$#_&(kO_HgMqWMuQ!=76YpEM)@FyozXac$p`82DK?^2iRoo48C!`Blm1yvJoreMGSbyHS#*?kqzz4 z|LOht4|p!kM6h``4$U=!d01+-L4E!<6Vp46+2K1s=U@K6l<#i8LU>*6Se!0p%5=qc zFC*rqF2VNjQ&#}jg6wX=c^X`oCs!T=bui2Tk#7lP@8(liiF!8>@?x=<% zE^kHyF~&Es)9>WFt4G{7Sv`B@nn(gp_X8njk7u=W=x^DYVns{gTW~V#ha;A)U5D(Y z#<=Eyn(80PcfTortHkV?2HkZ*Usf)XsowmE*mvM_rrC{0a8C{$L0HQl=Z}vfc%>g# zk$ia_#83XO=DUwOb{#;=a=xiAvulXV0o%|R1?r4nH`x2W1cJ-TX zs<$=x__3}Ry;v4M$E{}lO=9zZY`*(i@oh>)UOVdRoXvM7O|C}c$o(Psb3w}EY4Y}r>m^KA z%Nu0+87f|HvXSgmJ3;U+kWen`MMRZv7vqYeU{-Fs)}tILg#*9NftUJGz5b%7dTUcb z{1X&TTh8ulmGG1yA+wTZS5^0`7Xb~gA8ieukzpj2bz{U?^Lf`p+_1#K#zEEALO6FNgk5@7fnlJ@`?D;o2gxi zd6)5)C2N8@UF1RT6O%h|^t&Sryb(4oAQBIm8kDZ!xumXM&%JuW>pt^x5yn%CpENC3 zADz6bbD-P$7_J1j9xlG-*skK(SsZ(!6L>lU+VJFKm^8*hANLqYfH$)UHbYujXZs8gC#3y>3 ztLga7gm)xFNbuH&AxNd4=OSWN0cZ8z)|KJ%JxNPXFj@H8fa8k_SD{ZfCYSC>;E}BS zzNAHw`oF;H-I+=48vFBUPygi;@M+=*U$4ijYX5QVW=ypI8qR;9|5}XHrCvSBpeo$) z;7iQhQLhbi1?>O9T=}iMhnQPU96eu_vGUr z*MI#I&A+ez@(+$leo%jK?DE=n-<@@al9xRn?)`)MFXWKRXisG1oz`%+%m71dr5VRe z&%TRyDHTr3?v5shTYKY?@yNhYTkqK{(RZVlg5D+yn0J1zr@q8a=Vyj zm3+f>C?vi!=kMKre#l3e)`}2vv(<2xkerG0Ilr8F#_&nWe`~&cd7UV0Wh>g(?u}<_aU!uXB&! z!8?%n+NIv-xFQ3`VH+VMVH6)AJ9z;9lPw5&{e0ZKrqAgL1I^uMSa|h?GshcaXn=BI z4@G6g4(Y|cR{o+CK4eZb<#JkDicP+cmkFq<+z?;~7ibj>q=Veg9Q$&EUGAF>ni`EO zn(Jr~9H(mF!EthTaznUUaX{zOOwH3s-B~nPVdBk;2j~(`_sO6*a6O#@9T5R8;2%hf zm)4M6Lq-_b5YZkW4Jlk?G7Up<;P2SR?0i7A62Jbu^kF9P>IZM_lCU&qZ3#R1KDu)PF5Jj@y_xE5LVNsDU|-5MM! z^P;)6yeL*&KZL8bowsk86;y3Br)cDClyVoVi>8vE-8e6wnRNfEw+rt71p1pUu*EO| zHYzEWtk=bqsx9;{DWJ)?Z+XMty{Eg7*%b9&D<)MRrqfx39`k`$KS}UMy9^4W@wq`@ z)ayGUV?uhzmP_l%qs7n$Ydq=k^nVaI2rjR@rL_s;r+;N$pB|XznKD&&1-z7Y#1F4$ z01Jt&gr=knabz5MF@YaE71gOUN!j*2KN^gO{lH&@w;PQ9K!k05qLjZD(Rhc3-KBrURiax`CQV1ZwS*`Tgco`xC3 zmRu%dWz4;{CbL#tQU1klh#w&C0RtDA3jTVQEdVX%CT;vSM=Hr9JLvNnuL&$TCy|(_ zD13)Y3O-6-ppj`>Cl~Nn;RP)o zs;2&Drl@`;i0W3srgUR5_#2j`udnaUKyM_9P@J_=ZjD<0!u6zj4L8&_*Dh)iq&Kl% zw8cHo{}A&)FK9qBczSy{+u8WSW|=Lst0~88DNYS+kbej}ia9>Z_{Y2>mf(Z2nNFIF zc}Y}e3wm4SZm}^XKi!h5%?_ya#%NU9F(&xkRm8dy#zGhI{gxzu7xMw4SYyt5sNQTL zDE;CbQ()CUlLvz0VAvaSJGV6Dt*haF0;1K+B8Pe6U4oNgj4*cO6jn`dz?A^uKhYLo(6YxFKBZU;}T{*8_&S&Sopm;y&wpxs2uhi~`B@L)6Db z1K!CCA(IN6wS=P<)54wT(!9jI`+yX-#+8mzC_Lp+G3mgutueNX_>%CP-;Vm|{ip8( z`=g|NXVC0^f%WJd39{r2t*~hP2ezed^D`uEH8!u)g3-B&f1dZjsL;m2o>0(5MxE=6 z-xaiw*M7?sut|8W_-OaoCB?*bmmB62)y+?6x3=Wepo5qCw)Xw3b1&paGPtwX()`*k zkED?6on3Ug44j6CPI!7FPJ_xAmh&c#YfS##trd-zZ<^&Ba|IpYpmF$>Y%;H~XmF85 z{!|Ul!I$g@<`^~WZx;QQpY;waTcryRLo!vB5%!4C2qS^S@Db1l-GQ3?m7mpPQojvC zJY+F_=Po`H6U1SS#-;xQ)Px!S*M3&xx0X*Mx%K%a4&avMPPnV5d`ZCg(a)+&zH(M( zdD(`0n6d3bTvKojE-&|Q`dP;$bOdmD{5_qsRLPdR4P6{7`D=gnvktl0Tv#9~^pa0M z?wfciCP5?g8s9-b+urB;%BAa@v1sn7le%&!^dZ(wYtQ~o5ad>l{3CERjNqmA9PvYQ;BZi zO*&*Mdk0qT@r|j{Op-}%j{2h8EHLE6Jis~L?Dq-zovEVsHqtC4V3UT0EBEc7FXAo2 z9HZ{LQPnBoYHllHuD@tPrG-R<^-Y}sw#ZLLRrU!#Su>ZYkPbQRW$Z@<&pY~6Y{0{5 zG@ac20%6hERjgyP_&LrgQ;1ZX&JXYZ?0?W)%p;m<1#NwMrM&Dv!bW#&eokzePzE>7KIMW~K_a0+${-%`yT>|C4>u1b`U2k-bW)&j>V<A-#1_ec@dKhd@J-H`z)gmTO3QHp@ARj5+<$ed?if{njK}?j zQFR#%6<}0-JfFZc%tt(?ny;s>)!0%E+Y0RX8js61OaW8qZE=V^a5fI>aA6F?d)eh7 z+S_5^itJ-vteGrfBE(D)pJ?;vt^8iA<~54qgO!zDUr`I;3A_ogUnF&$1S`>AJg$%r zvh9f{X2Z~W>p5BBCf6%^kug6TRh^R}s|1L%l|zrg3Y6bHIhXgs5OiVwmyN2-+Yjrk zf@}O<`;JBzmmV$Q$P*9#W>nS0JS$GRo>EieFUywdM)>*Arbrwb#{4ac;}=%cfuEu{ zM7f`|++d0*Pq6VQaK>@6?_JL0_!`9lpN9Uzi`upu#X*iUGhv&VJD)~&B-$Xe`7GBf z8oj()xxEP7N)W}-)_1&oS>~;V1Z&WUOtYE?BYln*QbV;C`uAScB^E_q^Jm3 z^}d-~tW(Ms1YXo6D6Lz(tEb7~v?i4=f-M51c0t;T|p%QdbcAyZgyX%x7`%aCI_5 zF_Kg_35=tt^84aH?I(NKC6usUa;VB}G@dE3G(F2;ua~31yuZ zMw8kn7{dOU{Up+hUd6)|n9a59VE;Bf^DpxZI~{Lmv%kGxF?b_k4Mf;~jRa(-BWaT({c$6A%_sdmGXLd~63qSFy1I>k(>;`X)k7v!VBYqcQPc z%QMW}A8#OkZWJ525M9Z{Yt<9^`7xTbf-$JN18ePnp2zxGy4nC9HX)^bHp;|@rOloB z$_J&N#?$MC_l{g_H7akTx$c!a3Wkz)YytWX8{J+WD@)b1*m!d^@%h9c14n3Tv0!A5UQYD#nHdT9FI|Hf*{ksA*N+ z;Y~M8e1-iaVYj@Yh41X3NHGtybp*NO<{y@zx*PRI|E&^FlL(xiNeF&YUqN49O&fM5 z=^95?Eap`905&ySAj<9tx3#{o5R=eR5fM1T(@nt51-3~gY85m&aO44>%%+RhEB%jQ zV__&}d~48pvb99`djo^l)RP?V=L9~tiCL(h=5d|*h{HISgU05>vv)o1hVXQ?ljDN~ zN*yP2xjBQ%d5)fgawZMCIPQ|7vH7q8rOPi+jvERavV5KL{HciFpalchLWFP*Ngu%P zabvp!p`yQ)0Yo)}%=5DM{8Ao}a-WB3qah#CSwv&=V0s3M$mv7s;tijvHHvd{*;mK# zhH5(C>=b6XY<|#+F`6n(}qImHDksScX{JgEs zKpoqm!%m7mH>6kBeNy6I(f9U-J_fBmJ9mF4pk>yAEFQKUO%6EZ0NWm|I78O2o5tn6 z1e8Mnxv+MLkNw<10+kJAeZBUIy1WU z1KZ!&Z9NUB3&qECdUfLI6%^Nw{M1v91(MH|xr)MkICC+NI<=Q$341O(V*GqiG5t`c0j&99)8|7c2<1kO{1_N!x-i% zc<4ZNcEx$JSN*Y%JkXf>&~t@5E-P3pqcXnvb7mjjX};)-C`9RJI-s$Tkc|)t0VXYG zT+qGM?!4044gQj`NBbjg=X?8y{og=8rk()y&h)&#W<$=|-c^rT8v>o{Y-cbBYJb)< zc~YvebTMtMVywjYn;20owz?r_0Ist%G_Z+U@nvLXP!OVoB9+xlgma*w> zf0GsA#GvI~$gVnus>}D}Y}87CA2~qOv3x7h?*Yw8iTNSgIY(<{QI(zU zfU>f#zK)gxjNw>j!4*v;5hD3!A=hC)C;b^ly`9JI)OGirKlbA?S4qhDN+;UU}j0o9LCik;IPL&bgr52P9FPKUD{~RH75(uVtb$ zAK?eO%YL%=+kW{3R0j%3$eb_Bqxt&$2p0BY1{qh`d46PSPukq1Ih5c|aX=PGcUWSfT)r$BS=TYiA~;7pG4s*$Q+_07XiO&h zZ?Hqc6yc76K_Mj;N81$4R~xPrA!;BTl#_9v0tqUFlbg_q_zbf;Rp}GecSeR=$~{g2 zH0;+c{)=*%DQVvYz4J8k)Hx%X6V^6_YABY2dvo4W3mhj{s-4h>3(+|^f%Jsau*c&9 zD>0Mnw;ATO7+@|Rua|$Ou0$UBf&B99_#J=m)}*JUb+Mm~W|{;Rai)%am+jobAnlFN04(%s>0J>cT}R}dV_zoxt^p*A>@l>W7-8D z%AW*ZIMBZrJDfu<5xTH{%<>cJPg>0Sn|22 zPcLy1#3+|H;ubtN`rzH1y5E1^@ptPh0^zofWQkF!=$VNH<)S<5Jv_Iu;la0oa2pGF z1>iii!n@}mmnDiM532MNFMl~T#a)JIqFVMH1k!FGB@LvRnee-c5zv{{H0*NFvqSq> z${`@61s(VkkmP7MU$Q$sA?c!7IxwE>KLf}#0%%nq#M6dSsA)Wi2?q!wm)$Nd* zX#GE&ndl;|GMp#lzlfw)4?nz+UgLbIIs~P`1QJXFJiKjvb`L3zeQx-upWjPoch*+* z^YS3~*_m<}^Zqpe>;L5b&p^+*iitG2dHq?!mU1$V$r;V%t>MqPQHa)S->=8FPR!ma z1TGCe?wN}WBz`mubQvd)I%UYY+{6v)6-FNvV6xQGH9QKecDq+cm*|U%*2^@7;ILsf ztVd6;UQf6NBSh1PgUjdXGN7rz5V@$HphS?`H=}{aVCs$8|yOlfiWE}ZP z=$^C5&$hcLdU0stbjKrWB=egym1xLYJ!$lKA79ic-udlY%rE6%l4$Mj^Oe zAi@poZ+u`1xOWSiZ*1H%So_lG6Bqcg)U4nxxL)6`9XOwVg^6U(;5A7iH(sHyN)^W@ zRDP3%j%faN9)$p|C2xeiuYl)in67vS@v3cxmj}|_d=l@FE|L1m0k|-d1INzK#?{Fd zoa98iwx^0K4)KXZc$~SASSV+QjT!@nXL|<~B`rBt=>GXregOQT11}POEx<`apqF_5 z44f5n=fDVG%F9MnHdc8MyBO3B$NaZ?7xMX+=FX#=tw?7YFh zu^I_o3Nl+-y^zR9?3kXp{S1%G25eb;oZKws_`tD~(goEKzovXmf>VdF9@C1rJF8FV zfD_D}L#Y5KcW{Ck7SY2`+iFQdS5%B9+l6embTw_dn1BWmv6Syc+AV z@ZIE=qNmi+A6`hY_;2YO29_^#g{{{ID7JBE(5frdIUEc5@-KRzmr!~ibjzxGK1vx{ zkyznjb}K(|M~wlJy0ed5gnSFBM@`#NO^40;g)l= zUM@e>hW{xK%0nDmnf~)-sZeo>{O9@iMq%$Wv#O9W?WqOW`#a=S2MUX%i%F#qo$x?s$#@MYn193bLG!74@mVpK+ z=?ICg6+E@gK5hpEn_^#){b=gX_<7Ivp{suRlW|YUYiA3|N}_w`yd;r)e;H5q~EL))!DrKc~+`d%=iWQoangm-96~-7BfWE`XdD47Z7pSas|cvyhp%LWAxh@<+Mx~F zG3FwwwNnavcjZmmbU`%gt3B=;M2n_bx2-UAd8Qrb#7;C`9?!}yIPfYHg5;TlD~>S|^RADKKXln2^g1mW_0W-=j|+JmzPAG-_|{Zso@K2wMy40|zEU-b*MSQ&H|-Xmdsz;z zJ^XGfADdNOZ#ZQV5iWTO?%6{B{Y=uPO>wFUCVLa_A@K&QIW@v#c2n(JY1%q=)<-Kw z)VP_9txPmLu_Khb4J`RTxmL)N@DXSuHMfTdlb{!Eu@thi=dPnM9{igMRcp6G6{;%6 zl6Vq`%jY>s-si$^Vw#BEwqKzp>lJJ`g{pA5N~~e2yK>RfvA)NNVAsh)>Y;*Vu~Rn8{O2aa!RKosl=ZJia z-$hZd->6a9G?>3=5I6GSK==oF-uYZ{&Zoo%H7d0o*vi3vQKL>`nD4qy;^P9|=|sD- zUE5fz@Kf@aavv6;Kq>x9`KtHZ<*R3j3SlMj-P5<>p*|Ke8H?k9-czU(&F1LBjv&$Q0zO!YY)^F`Lx*N zh<4bdIMGv+(bK2Z3vGmu%)5S*R&$Wh;i-FX;bO4hb#|E@G`Ux$7D0(!@5Sg;jR%Xw_wpm#lUM5fD%Cm(2>v-~B$C+{jlNb9-eBlie! zS_L(5X{t}~IM4si`4t0P9&|YrJP^JxmU-!WVug1+=tp4h@Ye2dD0l?}eliPajO~;O zu(O|vHiby1k^YWXz8H98D9kQvIep)mp3}_cs0p8v#m)|U!>a6V>@-13Wv@1Ul^rMoD?Ua2YG{7Y;=Gy4 z8_bkSO8^|v(KP|`UQlNITE)(&ow3hw63%U}n2$R_Fp2Gg zWTHlRdcX?(3B()|%VvQpQWi4HF`T+`@XgI?3gS^t#4%SYi z!}uwbobzF5JYr^2u}_2@!;z(d8~1AzE0Efrr1wln7`RaN{@|sU(q)5iJx1)>-vE4K zzu|A%*?Q2yRlLD%5{Ar-!KW*6PZ;sLh?_d!@3-zSLj^#7I{?s{U&H1A0Q4R-_^>~_ zM{}W2vj6I5%%j%Gh%vAy!(agzx-eoOZX9~hk|=xg+VfNOJqAk8<0uRc)x7`4stM;; z+a$|*)HQBJ!2|qY8L3WmGox9tE1)0;vW7}x+B}4)u%sDGV1bOB>}qd0JfD&C~h1> zA3JYFkId81`8GE0d5R0t1Dvg&81Bio(F>_Z0j8a;U^X7aec-~e0%5MvL%Q13 z7>W^o5m(6ZL5YE9X|tDBBToQ5@GYRN_PS@oI;rAz^vea*i-1!BvWZ{#B;3F6A3wvBNSdU`Om+CJy|}>_d{8t zrElqR%8ymfC1QPW__72ClomjFv)=)CvO=O~LTqXq`eg^3;)h8upNit8!nOh6PM3Xf zXH;k!ejwXz(hru0W>*Wc56((G;o1Xtra*|GF}{VI#t&LzF}htyoPi^1{bYOK&W2?2 zJ_5z3Q{pe1P79FSd2&uSDf!h8?n zVSNM~ojIzs-jaEJN+XNyu;`hiv&5r>^5lTqY0P4>$L)kDU{+X}>9HMF;|I{Z$Oybs zpYAu0yg+ebc)H3L+=?KtVGt@yldht~4Z-fUK8xApLzMFkt>+7!Po>4Y*cL@}=p@-x zI_cDA~LhqWA^2s zV7=Ns8Rys9Q$zc}0&7-nby-P{_odqU9x#v3tgR7bY2M?I0s0cHfai{E{JNpvt96$% z_U|993Q}u?g=ZW*MGsI?iXb+Oe+NY5=j6NFTAe2AQoYbY<$3$yz{WCH81~cV5_2gu z7B7~Ax05Z<@Ei0Tle1w}l)|=LnRrI$lyh6k*9gV+SK{&pW~?2OC-OSQOOSzMcA8dDou|r2Fjy)S6pOgS0B(hsI{V0F@ZYW zDjqsJs1%rC>v!Jp?6Z1zi;&BvwC+MEWhPHIOFwrfU(20No)0W3z2{)yMemabhNa!H z9gHt@qA|)8fNLDX&08*Y2L*Z>HYD-Nci8(&noidv$)kZbsL^-h4;wg{W3hI6iE@vC zkX_eC)&eb%XhmdkoYc&Sr6Q9z?eVV6UA_XGBU71D;S?Twc(vQY>Y;#>`ui7CTG!y5 zc>6MUxf`I{n5Ac8+pN&QY;ljNJ<{Eez1Hzz9bi7-SvuRfyEwV~$O%AdStVlPYRPjV zPBEM1J!K{*5V68=0R`;uI{4`UcUN}OnT9pWj^ydj;l@K3*FS-BNUn_lM0Y4277{*U z=@xE|&?m1qDav0)9`AT%FJ3lqwdXM%O0HoLjVsDxi-B;1UsP~`4&Pa_9*~Vv4n!-wD-FWFJ|?Ln zvw7JN{ zIVIRz!90_$L|!m!2=ZNVa|%=G<$BGMN*=< z6ZNYiSq&c-RwG)e=?*;r9c_?NjPO-*u_l2m%y;wbWbZj(kIt6Z{aR;+CJUM>JlEP!L_4U)f31Ncth zr9+hzw1Hb_g^GpyFK|&$p5Sqz$q$2ob%ZOsIflEfoD{@VmDheGR5ZqPto~F5d)mbh zs)7eV#aIQ(Bb~9qb&B2X{&FR82v+< zTZPV9sk5v%WK7R~KocLv1l(UaLGreHxKfV#)WT2GD0;oxBjF`yYS4JwRtYdmwlpjU z5KM`{fR2mw7{`rDyi2lk#a5hyQFTc|l4xREOn+Yl(jGDq>{GvkSerpbd=MZ;uD+Na zq`!>D6t-q;NP-ecg@l63_j?-Scb;r!}Ygwbg}_@5^l((dcmV4Ve@uJN=E+Md&|8CIX$PsYngzVgx}uD z+bsYA%<-HVs4VPZ!s@C|$k|65l9NGSbOD47#z6tg^~Ue)9t^NJ9yzVZq3FvIV!Ipt(r*wRimh<@0%v0gg5;vuFv;-UDx;b`~4-|Iyuh!HJ;<~yg$xvyzb;X`J&{o zk?Jn-$#ykt#iv}V?J@G=J(&$M$IOSZLAzw1Bv#>oX_XZVC-VueUU<$s zVWygQ;8nQ;PErK|nAw&-QEYrZ8^w05w?wZIj||EUR)@f$PGh!KjZe_qXSEAPDH~ zwwO`^kKjFkku;ZC>MhXlxP`Ep{}^6$aW-Ke#_q4_Kp>XNO!=J0ksgDzFFWRBce6Vc zf(>uakr6~SWdKU^vOX;2a3yz&QKHi8Jh@WIMx?teqQi1V63S6!oQe$4p(cX$i@F5e z5+KEBhbIKH)Fi7;xtH_8Z9tfWe(8w&htjd<&o*1kc6dt!JW1IYt^C#7gr`g}&822y zKQ$#F)NxTjAw`gvg~$Yavu-TLjUVQ5N_XVYB#`+GOFIqOEdp;Jn{0n_7sQBS1(fh! zC++oQG#J~33R$KDi<@$*(S@2AYvJw%(v`Uj=`YfWzy|~Nbg#%<2qeTHS4R?9ODgt~ z7|ERY2I5E=AxD3-9hDW73*Gw-1~H(wuorV}*rI4lI?ziPwVuDnKVbjb08)V%KC9F5 zxMs9*IP1I_W4mGE6Uc5j!w4>But<&q-0a-;J6!LLH)B?;cnMQ?HdG3EOt?NneM4b; z{~VQ>qjG9U|0m*?#2m_}j~zL+#eb3VjMldN%#Szlqh0~>(W^1xoDKFP_J&+?CA#?J zn|Mj3=Kg@To{BPakvq3*Qp?7)cA zOA)*!;EsUzQP!HuvVvF^89p|$%&OIz+<56GG0Ox(BS&us9Yw_p0^6blj*p5Im(kx;;I1g zFN!t7Lg^@)D?bVVZ5mPk`ifGm%hTygw778JI^=mKJ(59^s_$Jt+m9w$Om3cbjJ!Cg6vD<6#&m(|m!6`GYziWv4agC&T7YsD zo%AWDPt)YBb=Fa>@(-SsWPP4v28N?B6r~jI4&d?Xv(pYw-e_rGJ5oetnV@}*r2Yq` zH26JGHSuQf@rp2pS6|mfzHrduDS?C#!GUQHbF))$w`>AN!`-glxv=OZufZxV1V&vX zWTP}-RKAzj6Us{i*-530WU3@hjdE zmVzy0m`1HrtJrQZ4`%KJn4S zNODjU3nq*qjKB-uGx08G9lh}HtzO{r09yRSX&<1^hrROx5B)tDZ+*pp_$Sa9z@N1w zEWGCP%zmd_n0QmZHDzCZzFTWX3GN`H*=Ng2f>{MjU#*|SH@3;R1D3uFO{9>lv4^uW>|QTE;C6BIgz!utpHELP=9ROHYEKAF zm-%rwLPo)V^y^aM?ghxesOk##LY&6B!i15fSu}Ta*^@VMtS84MY!<3k=x_upL^Mgg{Na|NaQ9>bw30c;)g67CNemJ6Ad6wGH*! zBZPPIN(;Xo^jI=f-U=SD_uq7)|GOQ14FRO}^`LhrldN&(_LI@~v<*C(Cibs_(dYF) zT|X8#ceFjqjget^(?CyGrouu##SfBsK>heP{G%vvX~&9IG)RT7uENyX7_PMqoAdtx zNAAUR)8A@_w?$gU!?;xZvgW$9OYVLgc>{!qnBQ1!`q%|5lh{@KkW{-Y?7ee89WWKY z2fL#2!ml9>`^YJ2>-a;*?t&wmJ0>I@mR^9LQ$bXMBxx{4lwn5>@#^z&o@C|;3RYJ-{YW30UD z|6+;bZ|z%!PzMXS@?t=W^Xs*6Qg^Mx!6zUOS~^~l9;&&25USkD;E?Hu3Py;ys*mJM zZUB~aVHNG^AEJh)hF8UD*+@k_E7*JmM88tGBA*|zN(_+F6ih1TX7gei^}swM$i zTjBzpykfkE$xTZV8~S+e(e+E;Do*n2&Om#=zh_@2m~C5rag}6DJ(nw zEHWjkW1M zOKD>PpY6v9e=0NU|H41&dzrZy-T@3!V&<#8ll^9ZMbdpgME~u;b3CRU|0u7$GIK*% zpqT=r&#AZ1pUHYey_h_wZ6yEw;!p#~^~|$KXFS&@*yg3pnZI^zh*@*|xH$5S$b8o_ zr)X|1^onAa%F7fbK5o8p9ZVL$BD57busN6kjKA5mVc_NO;m+SMHa+_6;ePihf0#aF zNa~YtynyPnpJqk1`U#-xb zOVLYc)qbzdv~9$Rsj*juW;rci0@Mg9UkIKaQw!LT4SM9^mT7Hc`4ixvfx_)jt0yy#xKDc1Y4}acGkCZA*U8@J4A) z1%VX0y!35QbBgdwuBW2(50Z4YDQ$+-ySIn4Qhnk>Uipp})!~oruUWHf{8`PqnE_ad zYhW@GSedx4TdjUhraO`@@Z&sqD?-7V^($cbo?|KYipwb)ox!cTyK6`Tl~|kamtq6p z74yX(%6{~zReY}UeS8U(;%B6S2sYL$p;BZ?`8Hjp+iVJ(iKgWyhrQ}9Smm|}@0d&} z1F-{l3h?S>cKp)#bx-JWRD*S#v@BX2)6#W-qzwZeygx!m(&!gbu(|&s|v72;_ zW3_JFBj5F;U`mIcgx=HN+PJ$zl=_%SU7DllG>>FIQO55G%iWqT8WBPg3xd1f>3wJU z0@3oa6Fpu6nWk6Fgx|4LBr*RF<&Zr<5YlO{nci!0X_1n{{Kj#SFb_EYt}u5hCAx5ysUJQ4tju6jTIXJo%>W3EO?RUz=>Q%-KjT z=IWI>irpV-uh|(uv0`a7XU-~p^?jdEtWymY5)j8w6c)5}1Dq5^(xx`oX6z)|u`lGd zJn?WW^54}FKMv4gk@WB{Hz;5%R=$!PFC;}e`?zcY}l<$=%*L1<6 zmJ5Db79=#v41Pu+?>Vo1gO8+Z0?;91mGY2Vg4fiYm?V9Gy(@hNUm2FByBT%DGRtKu zD(5rQFI1Hf^9+*2tqCQ3mMyr9)%-y{U!sx%N}W&Xnnt^L0ttv=ND3W;y8$TxG1AQtN^P87#l1rjGGMPUe4t~G%LuPHw2TT}Nswis|T3pN1 zZoO6=-4rejui5>0kWj~y8jgXg4Lt#h$FbfpPox@bgEDIjuux{{1SkrZ!?vFt=Bw4_ z!n`&e3{x67AO1PyQ3Y&$Z%>$&3uwh9^nuK4J*hUAVcL>f zu)Bip@#5KXB&#AQ1AnFz=DOOMcE~;9r25gR(WR7zxByWWBd8!FOCOb_qP`#mv4ON5 zU-GYW#g=C+seXESM28jvXTn6O-q=dO+5M`MV!bRaA#UUeS)o<<3U#w*HgeEA8uhjF zd$5P{^TdEllFel)52h1g+J-i)AzXCGtkdw# zZM+c70UHR7wT}>(uz|mFZ-0V%pb&rJqJh)uSB|*k;=}5KNE|j?3wdXlpNpH9=jD3aW#Q6%=U}hzg|WLRQ|cK4}5dJRG!`@C0(voll_*yKmq~YskX$F*> z+rDicuf`{#!2RIe5YM<0*RexLB0jKe*4*tbL3Lm2MDhKM(mRr|MB#Tj%>Pg}D@W*U zh;QU=HAhT}+6`W_9F?@R*!lcde>@HHWdexgS5_#AsPfdjgi<(;FvO(S^Xl;Ze>omb z&+ufv?{$%|DQ@AiEnY}m{S`R~;(&PgxAYYEvN>GaJmHf`B$08#5h04q_o3zZKj|sz z1VtH4Un{sh?CGmM7~P! z)xEAEX<{R|k-Oo@I_>a1qGp3x@bxDYztJo`Gx2hO(RPrUF6y7rQ&7^K6B4ggdi`*z zSV7^sD^lm(a{sQLf>)|3^5Nxnd*jd=DQ~OSMTUpi*8eklibE9r@~kwI+#Y^OI48ax zcYzSlZ0@VCyaFOW*c?s_;T_AS$_9ZeMOkjGV6_)KEa~p#q7Ku<0~Z^ zOWeD93isTAzOhf&)US&2;!}B5cHd;eK)?M&!gaM(8i7Jrn$SJxh6(4%0TE3b%{U~!Sz~C#T z4DuKlQtrtqMwr8!C&+?)tGl6Wl&sO$-%C{$?3Yu-1Q)W!_TJF^rlo2whf~Z$Dd*Pu z*K!KPRiJ74zNp|4t)3fRoOZS+$WLkOMyT#ZvM4Bvsd{ z8f7gua|`$BDUeAW_N%QnbK@jtr%e|K2}v~=%=X8otbd`W01nVofKZ#A*t7^(P+dUe zY3cQQUGh8eHLHNKzg6kh_t^A0-~hX%*a?nUUON;-z07|`Ro78J1N?MQ9ez;bqDc*t z>fvQ*>6y}GV0_U^7Q6Luyom+6r=64@zC<|CF~iJhaL(kl{|POxIM4*Xwh2P&}o7Yd>#`GY4OX z#ZE3Or%#|X%s+|yT1TThsNOvS7B?V&#oKbuY0QnwOn8v@wK!W)KP%`2>~06xVA|tt z=>rRqRQO(Rukbe%KvY?utBM`*{V(Tj(aqx;^vW-niFt<*pALU2WMa#CZ$EFVk7z3K zUQA1G&S0i34i<#vkqC|PZ}PT^xCHJZhZEng#N=I3Bt5xu^m^dhzn8Z~^)MlIBOvyx zuMYiVE<`U~b+ldf4{iIO^0qE}^_1DI4Xi(t7}@qdLv!R_mV*~4J^jz}w&aiN`eP82 z@+QQW*-&aQN^~P{7JTPzMc1i{t23onk5SRUlD$v$$lf*S`kTBhT4fCrO?lL4uRm7T zHT^^9E_~uUHP>BCBy`J@eF}13u8GECm$-$HN+{^KK=dKxv@u2Ha^jazx^wYJES*0= zZn4s$aS<*_=21lAcm-np(!Sk1wN({d`KF)}9v7Wxg2*lLQCCxzL08Q#!iKm*ZaLbJ~uTB4=*{b!a$y z5&%Y3;Ozp*B^yW8we<{H<8J02T5k#8DkPL0b0>Gu!c;1snj}0>Hx_1I(>he+k@T`!@r(I{DD?0XV-a0Kal}(Q545N4?0NRa+Wo zjQ2#nhUk8Uj)fu&>|>&6FK({8eTy7EpZN3_y;9enT1dPI&|%8iN=-ulcY9wu5$L}F z`$r3ykSX25lYF7ipX1f7yqfay2p6Oc>c~guYd`s~e}mo_xc5b1y$*BeBOd9vJyT%; zb*d1U9{uEIvC~mb7PynF@^Oi*L3fmuvLE}jcHK)D9F=OK$oW2r(>_}iGlyQ5tqHPo z`Cr*0TOvmA5$uo{_FBfqKy>DkT}aqhE5Ea8LVT3uM@HGX1XQ8 zfTKQIsllw;p635^S9kz0(vc5YISq&n3S7>e3Wla8e;^M;XttBL0UEjq1z5U08 zwS}uRI!t}jTB5Z#ydi;g>k1=+4dN{yi{a>M4{G}31iYVw=UqB}XJ9fBOX*?B^~a4D z(2orK+DU=_2Gpl)f&6Y+UTog0w5MP5g?{st8Ej~xqG*jjxc`S&8NbSXX)(%{dX)E6 zk7Xd1;a5?YpZb565AL_5=Ew1a9p>}1bFV)gH)-bmWB)IiV0MQ5#J9<$_{ikY5ACtG z84Hk!@BP2uwITjR{}1BKc#py6f`zS{g{zylg^w2u;<^&~EUTvY`m}WFQ;Cm=dp2>< zg>?iE9ZIF*=?HQJL^E+L-RL7uTp>IkSeY4=Q1r!lUlI66{}0qN^FWX@H(a_r&5L!} z8-p`Q-)px}y+G@Ec3>ep>W`f@JgYa|bY1x6EnD@Bn0Rd!fr>GoQq<>fh5r0Op3f2n zMCNwmW!z-uQ$-U|$EP-{0xa@VTEF|({Iq|9`K;&^Hac#$oxN0wH?N_I^#JodR0z)T zV^P1;ENq=2iWuR3a`%p<1%7~bkKdJ_7qvQ2A7neqd$OrV5|1|^40qM3tdNZZT+~P0 z!GRIo^G+ht`r*T`9GT6o`LCsDthv`BxNr$cUyT zsaz235SykZ0AGuo_ypJVXiPGkDf&zN!#fL?f_K(^18Uu02TXfU+j1T1PQ88-syA^s zz=|6t3)+)1xc)_J9RswzM1NpAUpuAH--7kJ84@@FHNowqH&|LeMZTCg!YPIuDM84> z`{)I%U?IOZ?E?0oQ7*ZVoKBN-gpTa|f-Z_&& zoIb9`-&V8KTQd#f?#lm{>-%- zI&{h}M}?kMdHtvJpFpD-{u?-bM|cBeGU5kvXcVjY*ue#~2OPe4@3jiI7vjdr_ng1O5MgH?0I81f`aJZd<5uN_5I_eT;Z%6PgCqXa>}VXs5sQ@14?p*IztAThmqf^WM< zJr>S(>h-^lBYyBN;D{lexajx+rI$SnXJGwgm8guIcx;ifAst3;TTSkR%&+-%{9rxJ z_Wp_@&2RTZ~(h$6qK!9w1UQa#%^tsRK2pYkKMnXBiX z9`oRTd`+CLA*=U@*y{fHfgiqFNCAkJODd>2_Yd$W-8vlQ@}qu=JDYxf##C{N;_TD) z2^r1v7s6Glzt>MEMpTI%9%@~aU(6vIN@p-~Nq=t#CZ|WVPbxsv1~HfC0+}YQOm7eR z)I!6@S{A@T+rRWH$YMzpEN*`BR98G+AbxssU9N`vB6yz=Sjc}zJ2Ei>1Yg@^nNqv( z@gH*C-)b9h^ro$z22=VSI!9lf-L)w}c;VG#l8cmCx1Z@Ak1Ga$@OMYrw;wzRj$e$~ z9*bQP`B2R}>q*~!>__=jxUF+Dev!v0TT9_&=i(#5&7wXZ6zlyYI0*ycz1?;CN~Zep z$}rZzm4^51jjfC&VEL5J+j~zS4tbHkI&LwxM!8;ZK6S(g6InZ2^wfd)hL2 z9swbwklXy}HtOlgc6IJobv0lxU1ryc} z%!iMFZ-7Q&mksjgegzSdzDEK(4;v5Uihq`T5ta{N6*HlR40arCpQXU&wv0(`TND^J znl7;>&b)I+LTjiMd_2M7b!^TawlMKe?FPoj-9&EqN~f51%pf5uc;C}?Mt9)P{0chD zNg0BRFVSLsY1kwkZgQ+_j??-z%tE zA~&-}`BSp5cp*fqineO*J8!3h5d!sY{q%Uo%o{Gf>!QayHC?O%$AJtJnyVniey4uw z&ev$m6U1}B`sPa+V)C;>)7&Qsz&-Q5KC18@&{i}0^5RKIUGZB}5&x;fk57b$1%0oN z76F(I6INT98zdvl$rn!_lPKqSe;Ic#K9COU0R(X$Zqh~_BI_Pd+a8&JWyF)#Xph45 z|3-b(qfD(Yt3LL@;7W}d|LkNGQ>&O7xc-m8Tzw$FFeCsY0CP~bV8$D*45`#IA>ksV z@(UaKV^rv#*;y3)s`Zt0|+09E7;0eRTvJ(N=XsFml*~SV} zed%xwyE}T6_0l(daNU8H10n4IucUia+Vpw|)eB6Xp1}v!!kSh6;O|1^=Iv;A0n!an zJ$8tRVl{QV!|3kl-t|~Fdk9qQ$LX7Ahx6YNKpxN@u*Fj{#cAQKm`MG-Y)sqRE;W)v zwUf|>AGbK!s(4RF<0Y)IhWqAMYF%byvJd4Sql=hK;5FSEQE&uLaLd<|=g#S|E6VX|zAkLw zHO&Sre++ESTYjiCq=C_x)^tmnwnWhlesn)iN3G6~S|%0CR{5~0P(g6xs@*%>H8`v7 z2H82A2Xu!yhOY}e&l(f zQ~eLpvf0glkYV`V9uunHR980eA|G$z=+eiAy0ZN@GYkKg->+<_-wbH*G}xl+mzRH* zVaLdZ~Sc)1!GiA)g+wfgvVT4<6)%ARWdVw=iCKNnGw%I)= zS$`i{_`m1(TZ`ULAkWASuKysvj>Iax-K?osap*=hjqQBTUVp&G%L}4RpG zD82i?vA^A@*7+lXKht|K^Ruu$CB7ea1AKgx1?=(;c-PEja3=c>;? z?C-PM^mQ(cLH=qNk4?15RN&N0K`$)+w7;oiDsymO2(*T^)@)?CDa3kcJpd1JR_a}w ziBPQPem5Qu4UBj(y@GymkC;k>A^u;xzo!~s)iAPkoer;XsJnRWNr~7nLDJ9rTjZOV zf*D=r6fNduGpUN;D{>BV)4%QKee>lcMYF-Bmz3#bOHZ6Hr?%+fh3)QdSVOBhoq(!L zV$mv3hGB0AgWGc7f5ZL`LhmPVe?P{C8;9AI;~#lZb0|v_+hrF zS=v2-B(K*O_J>s^yc*9B;U}0{^1QycR0tD7aPIRb&KI0@HzBUTwD6n?KJ8|EwWgYA zE-<)=3&OCpPW=Ozdh~IB71b{ z6sfG78{u|NbgUuhQh;9KSKbp_IY93WA{1su&Vrhb29|nw=7)pBj;8gPgmi02A3Ub#}5@bvNsSUSKP*tS3#B5>y zgCe!6YYVv&_B7A`2eG@um*o1i%QJfMskro|__l1a1+T^IuJIxIfy*6+SGue{zl=w} z3Pcjz#?t!zHGVSdf5CL}hu;FioQ}3QdpRQTO^bpuYvUTVj-|^ z4$gan)2|?OVkm%_kDJTpx-ZeUX5TuG>^&29k(hq^V{&;f?hVA|16e^(qn(&ySrxvd{W-5d>TJqT~G2Z_+ zf3Q!(q1^HD&#ObN^`vmL7p@uTFtY7CJAUa8wr@h#NL%r8IH4Bfqyd+Am#ZpK3k>k02x(+y%RDyyicM$MIL zKFUixnf5=eC-J$&r?3D>{fVr?q%?AgPIpuKq#x@E)BEh!R&LNSWC=&iz*6s*>Upn< z|G;`W(BD{P56Kx0j8?8Ew`dMX$j@aMw0sKTArtw1f8)qSMlZH8ex%>gl8?xu*aH?6_E&pF=W%6PnG$ki_iP+iBZOU#wGf<*;U`f?a`P8q z^HJWR6Tsu!tFm^dpg7kPx|@}Q2_dXM@uyN9=*DIO;W z>$W2F7WybW_>SOYtCmjek;DU`%Y7ykM;2B{$jUg+{$XJIOxc+$>b*mxoo#8aD3wBS zzExS;?jP8Ois!elFusk>9jce>SAJ(DCFD#50upwmRhESyKD~bA?6s7gyH~YU2krcNE%2%G6Cao`7qF#*8cZ)Y{v zY?YGdu|Oy-_O}WLOD|0D5|yU_4)G0sscKHC#<^qmMxy!wwQDX=deBt1mu!+i)o6ab z?mK*I$>>8^TkmGvzWkWVJ_5WjsLqeSL~X?2dO&;XSW2UY)far3t10y6Fu2CrKQz;3l)&2ART8-J?TEsMnDf_O9L z1JNb*oIG`E(Dbv5{biV*Wwx8g$WW|~Q^2)jg095jN$gJ~Z5-aFO*T)+XMIAkI>rIb z_Ku9M3PxcMmavIi1Lv4N4}UoF(+mm?*)e?=$K#*6ClKvxmtW3p1BcZ6nw1!J@KDki z3oDQYWElW-q*|Q0MOS{ytb$a$Sat1rPt#{7B-9wrgYE3?0K$L3N#IvaYhORB6r5oQ zzk?^CvI39xPOL@Z@ZJlMf>vk0Wseuu$AaXE-0QBKBxyzCvn1E79CfPv~5KZ_TPM5{D1d z*3;20*cyOH80wRs4&@Tg=xestNr0XYAb5qu;oTi^c@0jY2xelgrDu-ot3`-jG`d9M zA`XuD@L<{dINHL3NdS!TnrBvt;W3@6G=&4FVyb9PNR)v8JH(ke*3twZNt(Fu1!{V2 z24};N?t-ewRO~c3c*g^Eb7YCKRsYcnt8(gG|7+Lq29np%>fq~8H#;PT z08pUjFRY-_b=vgo!`iUaJ41KRZb>0=&S1E^c}+sP07HSZo?ap3_h-lx4vmSCRm8+h z#vpO{F+9DUEu#U>CqQI4317(Buu0BNQRAym;>^Awakw$P+}%8bod92UVZ2jedTZfD z))6slIiyLVT^vYUUK|i6mht)d9JMJ>ERW!Z*s{(*Ty3cU|BxHb!&#Yv-fh_U*e?he zA7OzwB~}dBIqN4$J%Gnq63bw3Uufba^0Kk8`9XZL!UhBe^q%{e zK8?O_-4-w(sZja6YI3=W9}|Ue33COwiMSp(tbQ~Z>}3S6{p z>vz5jvGzDGmykKfsW=+{H3A&Phq>B-NT;~kHv{`-iL%uPjxb}X$`I}429q)LA8e0*Do2LbPNJtu) z3!X^k2xW~|7$bCunv&S$4q~yT&5{eQ4N%-0$uQNN8O8PTZdx>_E_;$~b`zluIyZtN zRj;AMK++n<+v_7*!_iJY=BFThPZR@Ae%&DhaModfWB?Wf<$)X<6d3>)bZ@o;5sY@> zLS)4?zVT<-GL!uVFk6lSwYI18E_G6})N%o6EWnTz1HkUo+LC{~#WFUI*o|#7+tujv zi&%saxbkcr;rc+&Yonfln+$7H`H}Oue2zFuB^tcoa1@x8xxnlZfN=Qomva$jpWkH3 z;S50xL)ygJ>A>MAlpMDCC_r*D=7Xu^obTCk4FBAQ-nz>xhlzK`uEOPjkFPgRVO`LQ zybw8icjOGDLi^%8hy=hm@953)1l%%eRm2oTm$Eo5V1`SUeEu%-IoGwDIQDe3Z-Dbu zFQ1%Swr;8ZgcH_4S=r8D; zZ1zYR8V!nc_5jUCK#MXHU=i2py|b~WH*RC4?A>R1yrcp&WV^4rcp^F}uo8hy*2z*_ zHaJ{c692vlL_T7j1PPz#EKPxX{q}Y9r?9?S^Rrj#VUPze+VQ4?&S2ori;-LXB)=f4 zcB0-UF|fSEMp6p3;o%zS8q(Z+hk! zg?-yqQY$O9Q%#9Q6Pw^GQ5`B6_#+!%;1nmyTR)ViK0D+l`&t_TEG6!~S-eRS&a{Q; z<1(Vw7W79`Zm5}65P)wMQ(x6U1N<%3m&OSR-WI|vLrSc!jdHv$t-sE@`@+qJGgqC~ zY>v&bzj_T*3RClZlrMqc!2pwgB;+{{Z3@5-GmZ7A-ea6kOWM<+Un%6_tIQYI< zWJuh{`>dC1Uu#h)YxG=`C+I0^p$SLvdKL>FX?amytUPT+E$K^LI9fnP-i%O3Jp@Z; zK)??sVqr`+HJ;TbX?1#8aXVS5>h}Y~U0{!Yb5cgNcT;H;hKG#nrN=$9&R3720z)x? z653rXft`B^UtCs}C77cD>l#<+L4l!)!J|@sh%raMF_5Wr2a085d#tkhM_?%NHv&U4 zn}5W;{TZ$Yz>Qd-&!1f{aQ71L396sG>JrDK_9J`*X+7y}TA>x|(s?gqt=mF8)RVd{ zWCi{-i)`n2`^$Lq_Ov8q*%u)fnOJ@%5yZ3au-^U@*7FP28wl&sxYpfFRw@9bEF~k1 zA}{nzsXRpf6hG=87(ZTO)Il@hQLr8sd zrbVS8r{42>=R}V)Dm)NGuwa6byc>&wd@=A$^-72JyQO>M#`kYXH9_%?U!{-uLF>5z z(t4;D$?u9h%u*zEYF{79v$^X$-<7mW>k;`MqV>e0ujRj{^_Y`gE8ZAaeUMW{1i9S zGO}@jvcRzC`$TjDFy|H!xt=CO+KdaYy)r7BG1fZmi(q4o50wNeyOnH?cZsV%<4~|n zO6zjCGaqqycO3c`w4Tl;^!W_dgM+c*v`1DYydYn$;Pi^pJLd@po-FPA8-9hVDlVy~ z%#Heo;mhanwjuU*5jwYjqu&7$Z{lR|_5`CbFa8T)12n4ij7@j+)Dr`G|M9mY(__Ph zCyV}}H+YCP@UDHxYJd}iIQvZ&XNm-9fyO`d1}CthctkJ)@g?*yu7ARvI!wp|)m8hc zH)uQMbpAcB5IsSm2VQ}7>{e;N6Ur5aYPUCN+ZdbJay;17-ekVrIW|@`f^oK~{vY}# z2ig@PW-%2&;}M*F%sy5zekbx#draeEn@pV@dedt|qoRb1w6Nz7&Dq5EY(NUYJR z+kbYZ*xI!J09&X!((W4|nf=^XiFc=VJ| z*Mo1-b7CHA<|ncKh5aH@ZRF(t8NPunSSP_C1go59oKXFT{Zi7VZO^%^qAENIU&Y@N zh;Rtpp!kRV5*r;jnR)Nx>kk>ig^n~h1&>Fe3wM9oFAkrw1nztKCU34PV?8Blb+p1y zVfs;$y_dyu|8W2Kz}RiqS+6A9d-IawMhEoLiC5kliib=kCYGonMpjQ+0gL6S4B-?`e3eL~_#lbp6oQ96?K`slHyv)1sXL`d-m4Dt$-?v|S zOfshhyEYkY*L|nfp{(Uodi^T9`{hvl5U+Bc@D?0*Yx{BChq!4G4bT6Q{i1{3FDUqpsZ z{2krw+d^>OA04yRk!4-owy6D2_djUWr}<x(<^6w zw9#l`-0%jgqA>!!Vo_f^H__ki>Z@i|%0CIUKAER#lZa+xYc6tU4Ew*KuljfDC$Ss2 zC@$Rh^dB1B4Et&7ixoG+o*SPO;qFZ=<*PmYrV8wQ4 z_?j6GTqPV~7zv~6aCi#cv}}o7;SF*Bw0kA|x9Y1n(fbL-3nYMC#m^5gNK^`Xf0)UI zBK-qgj{-h&^?>vB_u7HmcT!q464hfGaGnf z;E^nQEDkC18#p@*&>j%Mg%X`JwgOa%9uZFV>g*kqahz4Wte0LTm9Zc}`@cq@bAzwF zkLt2z=2%@-Pv~U+`%Cv8?BVLjLHj>N-ZoYG5}M0%q^{G+2F%nQ70F!RJB{b#CQs($ zI>TX#1uEK(h1k=OD7@Xb@+Ij@N)N@11hrjn3nFK-pb3Iva zybBklY)jYRbk;e=-V*N!j;N+FunQ>n2nY`Ru<;_H-W73flqhMOO&a8;?$bKxp)6y^s`mXuhGvylt|?o-GE^N_mjpu)}t(@ zWwadBI(h0^!#7#dpK3z*e+6*1ga-mnE;2>8Z7#X$1>jG*YQ5r- zmbbUs0XTE*0h}|OR^cqUHrZWC4=g#hRSAg59rgEo0$K1*LV#9@+${N9+I@QGn8T`O zyl>-;nO)vj6fy-KWp%u4R%XQ)N|%$V^qzZXve5lx7vXHF4m7F0lbE43IZ9ulHnJkWbROx2Ko#@mGz*vYStC!zIzEys=CPXOr8jzGC@FpU?R#<6tHpcMdTe9%p zHA;j!8hmF4)`WQSZ^xQg`bSn5%GZ*YSp|1~aoYlY1ml>4cYOp^$RWp}=c=FQK|k_` zP=`cjFUEL=JE$W#_wk!`59Bu^ICncRtYpMIrTUg{5wrQ>YB!y#=rQRA1Rj;)gXmRT z(8P=18?;A1xYVPu(}ihT0+`?Wsvi2fMG)(&pA+D^7TNorEq|}nQv#6ix=ju0!>N+x zf)sl?m7B+I^!w~9^+c#7!2FeiuU<-dBk<8Z=f*orZCtR_Ljggt@4B?xZXZ+Z>S4;! z-8#hR#1#;)L5ODG)mbb)d!@B-0bU*>iHoN-7Jeq#(wVrjyz1C4Lt5S_H^QvT2mbId?2F~U&%4> z5pT0>4KK=+DtxsY8=mZ3p>*9osOnDth-bv4+H)K4j`o$OzPGSMI`m$}|2QfCU2=>8 zc^vVz#t&`=1QKbK<#*u4l2+0`%Q39FNmZoEg0)DzjN45uWTnZIR4D$A9OKh1$soge z549{#nnl;UB4IcC3z&a8I{!U#j5lMW%=1HcjJl|93Suf0W_gz2Nc@mv#OqJiwhhA9 zk7r(@PZ~~B;?Ch>`S-~&1XsW29I-z#aH2F`(v7ay=48&shaYkb9+MQ+x!P8rG>5lR zb>b&qIVmZEIM(lS42e)tem85Q&#D#*SH?OrzIJ&_v}QH8{hk`5;XSFk*#zBbJJxl{6aQv4#?(W-`**eCBu_W1Hse)3 zyWu+0H1b1@QK$C$whi{@3eh;Eyy=&-0bF`F5lx)CDhpYlbXH)^LqZkqMe&@>qieyl zimD~;$88C3|5KF(*#RnxCQs%dEPDrUP-H=Hu*gDtS7dSKmm&+ZKM`4|zJU<`T4eF) zS0am)J&^@)fXHGT!M>}qAUi;1(aw#H>f3-S3;hsB-~g4yH-zSn%%W(4nK}9k?h-zg z#)qxxNUdm}>mW}Tf0tZ~!lqef{fX2fZbxe2@jFrrjDw^W9kVR4oNv%QogvHMzmQrC zCTfaqS5}PlzlrZj(veUVC3Wfpui{;)g~wk=EilV&;f6q%V8-U=1G;?NOSoBNY&I+M&OBq7rhBA|>4lP79hk46VmB8ESTrfYu%El827V zAThXT9PM2}nXCcdzRkp)YRN4FA?7;IQBZni$oj2Zyu%PP(0=7d@LCz-iy0~O z(y#PJsAlY+@}*;on?JND+{8}zn$E?erHm^I=~$B7&qpac)R5ftHc`!7U#q>XpdJ~p zIPewCNBJwhG^F5t9Ot1}+}YCE5NExz;S`t+^LM@-zKfO;GrF7RDbqs)=*A;h80CbTC@-@b9`L-!~4E$+oF*Xl*We=lG9&-o}s+yuC^(2^^GhmNjP1`|5W zy`X3WITchpe3U!WN9h#ge2oQjbqR8v-)KCC6*q$i*8e_Vnq5nmz^pJ5@uf+I4+eYK zVx>7;TSu_(*?27WA25N|^F zosPmb=_6})F5*&`oYpc{bIDNGGi4jp%XjH0LBewvUEc)C(_$cwCX$v$-1N}bN7GTX zYTrRahH6feV8X7l}3~rpQ><#+l{% z|1@8X#MLN?yPA!t{)xsA@r00>dTgm2xPVZ6HF7Tqhd`v_QjwI+Cp!zOrBCBa3)FRO zg^Y1jC~p_Y!GLLHrc=KLOt<_6V0w?Q!r~liKY^U{d79WqGhg+%_!jraDd@+a_$mhj z)-;Zy_$oFIVEh8{fQuewD@Kl;q+)rvyz(IXex$-O__Qew zQdlkjp?swv8AyrJhwkuOFHWESZvm`P?eL{FFajk=KBv^z`^vJWx)5y9u7l|ngy}B` zYX2_4H2FD5c;2JPl*ExCis0MF!#OTmCE%4568?%Wt*{@>vdFB!V?N0BxQz6MZvXqa zg$BiZ0XQox>7OU4b-qK#2jDzZJto94bWjSIrx%R=m`I|^C=xOmPt#HLJw68`@4cwn zyPaiC2jM$#3v`wBro-{L&YURI_dEUNqm1(C{xO`xGlS$a=VAi$k=q%~+%_0`0~+80 zr`h!=h0q8JB-2G5%`RGm^ahw8J&JiF#r{W>J5Q241Ci;>5ZoFKlDeZR-%}8n2=O}94dykK|Q?TSp2CnE6ly$&*6 zSkv)4Yz_3cnXXx{n$A6z&A3hrXP~rlcY_c{yWd~v;CuPOgBjoKl%6nl&sD@0t(B*Z zgChtG3;CSdx#|bM5-d)F-Q7PoHd|IF373W1xG+8^hpdq4r^#BK2Y zC+hHQ454;Q2KssLg5gwMcjnP@?|b8>oCsJp&P~6CCuWLI7JSn%0pxxE{xI=DPUn9* zObou&P8;<51?$5}1aRL8Hy;Pr!Hz8pY|ps}N`qm-)>pUD?-v{k-%Hpk{F(4?Y^Hsx z>pITXDp-fDq~;k+D}-QeVgYUvVC~}7!8>gJ=xiX#1r~?(hmkWLSN@) zkRDR8LQ+=w^*@Zv7aP(;;)`JWfs^8{Fh+hLY$@d<&U&4erd{w2u~@#dH>O7Gn)p$c z+&{c}cOHN@n|1#qy00%A?jFTen86ktIQfV|rHKz`kBAJi!UZ12wgkJkiznQp2_H4> zCC?f)T}NLdrs#*-{1GX&;2-mnU;&0%lmr0U+?GZxdeOAkaOzSWmPd9?n^Du zckF)wB19<+O{|^pAps#oQNZTql3kENCfp_a(@HTcUs>r35)J(qN+T@cn_qo6q!#;I zW(-0MW)fHEoQQfWMGnf$JY2ct_gI~7DaUVJ*aRd=q<|!o{%(*5ptA_DdT@`N*0GEF zDKr`NQEKPI9X?QGfCw9yUEBjrNSYfOS#garar!wOdH~u z10;BWdIWB1?nG$3DFC21+;c9C<`i_ksjajR zHyG@5tai*7fVrZLF-lZuHypt=$SWY&3vI`^W2x_1dw#VKJJ4_~U~F!5C~*j0uy_xb zFAXC&4+9l~xrh1HOV!odtmk98BJXkVGOB=NKZ9kR#embF;YWDXRm{E`UuV&Bl^8s3 z-{A#~7kSZ$@3FGVBKzp!HS#S7nKALPBo;0M6R*ag>0%KYc;aPF<9{J{yhzv5DDxue z5vN=>$aM8*x;T2$nFx4JKkqv+tbOuQQouF;b3O}^5hnPZ*&*iWkJ;h&-PA%o*Ej;CCusM|KgLsxLB%B+`n9Dum^eARD8(PFoIip2MqnL8be>vh;&&U}|OI{$TvE1W9R*6VnDW0x9piCLyHnTl#oDupTD!GHYCcR69E9Y5r+N z2HwetD?jIXe1P-z!p9Yh{>Jp)>JZgDK}z{A0gt|?j~~kgByCZF-1%Kk&fgL{viI4f za2F%j(Jq1AdJN%tW2CU5Rx?x4fTOR`kM{KiNAx8yKm62P^s^rS>KE+q4Mr4>A}c6X zvgrGtkYDSyTe)-UPx^)5{T(=-rhHa^<~emXutE`dgRi*rX`TNsdVD?WHu0l;Q+MRa zaZcD{D1pa&bZURK4EHZ2KXaU?eLp)A&c7TB4r-j@$^GZ(@&7Yc8A!^<3CY5oAX`px zKR1|Q9c}i)7q0~jSVLaQKrQsjWt)uH{-bR$HlxqKbqs4FqwPKCOBN8M>K*ig$n_sL z2be#lml<-c>5u~Q2SC2sRE?o~DKGHu3Fzy8ice{g{PXdt(B1U}^&_t+U|vU`=AqE? z1A83Te8+Abqa3m>q4X@Sydwp|1USEY5`Eh< zGl=;<`6^%F`;3CF95%Ym2{4Uh@(h6uuRAjXwtD9}Z+|^<7vV8@9BO?;yRCvSzSF%eh{%;S&ZT?>R z|MO6i9H8k-&4ZKbk}Vsm1*nM+pZ9n^(HDYbP#Uv9$#tJok?-z>yeeG=)Fpcoh8i{z zPp=m;ZMv3R0sswvmGkuUpISV_lt4jTmy{f+jthxuU%Xt z3){HUmNi^DlnSM7i9xILN7VQ{`BToplFyIEGuT8O8fodhRn7dN9gG!Jd!oKI@*L`uJ;^(=|(MXZ_+K=?#52@{=^%tOY%1$T+xu?TkM0A zA08v=Wj-6d&PIA2D2h2K(r|%G;ZW035^gy_7-ziSJ6cH6$v+Lx{y?}Gn!_?yW0RSz}T2Bu2D{M z`N1TUw7P+l$w32tkKeWdS01^Vu%GY}xzBIrdT= z`wW@GTa%;>&?L(jgwVa8`5iDq#{0B$Td#|*9;vEMWqH-icj_U8FEiVkn_@#@SyvnC zPShb+hdkG^ghYAmo~U1H)km0{IJI5}?o~!yth#tXxN_Drb>u5!A4N{s;d}%1cYL{S zT{%wpnoq*jPoIZ8h0^BTx?@p)fG_t<-jrQDeqm3V3OoIYgOMMvU%2k~@9<^dZ}4RZ z*#7RnJ$L1++v}Kh^~qxyV+(19C&_BgMnOOLr~fvW)fL;i5s9grz+CMG+(+eP%W?v9E1QLlHcsNFKJMbW5xVmMi?}XqMsZbBD-e@*((YDu-~3) zj%-M*UP!on@OZ{`wPUJ{DcMQT&)>D*Hmvu z#d8AmS=(KE%q#A=+C@Lp`3Wy4=E;z$&N9sIt1j_Coeu|Hud(lFKK>kDt_(}K+38vO zAyb8oJ2d_LXSwT2korxKN!Q#2c0Ukcc-_!+NAF_{DUHBow-veYo6sWT(hDN^L^xSN zEJ8n6pUklQmgB;elNU zI`uj%tzoE3r%R73LiK{nJpr+V+Mf`#hQejThwN@B3o+$qZ;i(9ddlxP@C$;59qgZe zvivo2D4(Pu^|`or)YUoqUl8;qs;iO|bVtADrkso@utstmP&-}p7YMoq2$Rw8scBNRXmE6Ch-N}oz9JWCIFY*|9yqRCC5#BGh{oUR>K@Iqu zfDdR_75I^FSodX5_3$Z<%4e-yRHvM}N*%dU>YODCP zI}XU5TJSgg*;+&ZkCNzHqT<@D@|z1-5{VSm_>Mov@OFy#jyF2ys@RAX+CEo3j=gv4 z2mZ`Q0>E1$awcC?Wu7cZw;a(Z6w|0LqsrcCtvW*m;8 z0-_0*qTf*{Ogqteonn63A$`YOahizU>3etcJ?gxKJX$SS#gOXzT@Fv+-5t6*i=n;Z zTl(QnzK6t%3oVZ^tLry3xQw%WjB5a)oA;Y=ZSilQ9Ir7#hqZ*yhI^iSJu4m?~9cTbWx6YX70Tc$eI6{{hXn?~@WYxtq8j zog~4+_J2`IH_rTc_rja*=H2tdZ~CZz%6XK)`84RT|4EG=WaFvM+ncsUk|PIy(?=cK z>ZORIUQM@iDE9SkGZXFTuT=gG-yW#B@1vq_iUK6 z_VnioKG@0cW%uz+T6NJ;++vQ)jx5!fX6j)>)c=P zoy3z7R(xWd-Su6k?~BPEfE~%BpZN92+|x47Qg%BeXGgEtjr^d7fji(!{yF##G4Pkn z{RyBaP}6+VwNmv#!Kz=!iH|6e^n62(@7BLN=+1xWx7gyC*LQcuPz|{^hd~@T^vt9X zeDLRfi#N%R+-oJ*r#-;X6=tTq(QV||?m*<(=jQ|S3Vnw5y`-v!K%Qt(*UZQRT9h;y z|LmE`@B1e{Fj(1J@q?X^{;X#*@6PMd~ ziMIrO8YRaK{q{A!luuiA=28&3d1p~`v+53y%5N&G*2Qw)ONr0vx;*}GY=7#{#gAcJ z&*vx4A!d`=CG3rAFHpd`UhlpiNZ<8asa2{AEH=G|H_Vw)Tk|LSXS*LS)qF3b?X9zdod}1J6l+6m_ z0Qlg7U~9g*N%@v(W(6*NIbTF%H5~|tc5+Z)0j-v#J2nsg(3B`%Lb#;)aq)9G{;(y3 zt*;l(-th@0inD2(TO0bj<6*TMt}WT0=LGi0X9|-KH66Z;3cF6kaO!A z^|V5VFSS$C;rcT*6*3<`ma^VDO*??s z>(jn$$0b2Md4tFYw+lc&+XoRbM{>1dzq)TAX_v@m*7!X-MC%R{(InWAU_3S-IMx~b z)W9>oj)YcN9|sAl_x7=3iQH`82O9)f#M9!l1N%5E(ybYaCP>U2;_a0l?)+wd%`+)r z3^^o3J6Vq25Z%nLBya0fr_X9GJmhTd`aAguvh_p{RX=T7zZv#3s-N5?sAcV%+@I8| z-{#lcFI5{9D$4Ne6R@`wYi0aefzh#$S#(p0L+jMx1MQ`p@Ur z|Ea6T?{M}o<>a|58X?EVNF?&YbC!4$#5vCr+kRlxi&Qq&9EVjyY(>Stz7dVOE8>5P z`M=R2?2Nd#7+}#QX@TU)6pmRb$fKcml4&uVlNbIn;-0Z!Y$hc<+Iy5-!qxc587?xr7zDTWzoa{dAK6`UL_+QDhc3to6IQW#M3pb#1OQwx;n+-Fp3;B`$$g@UA zqy8YzS_>vx_qDOsr6-gK==_1{59!GDaJ!==zKGd=c zh+_OT^-$Kg+@b{}MK7H0=@yv~bjuS&Tx`7r0j5Ercp@LbHE~HgZ*s+PWmAnmC9Vr> z%Ac(I$#FLZSo5oGg47DI1FvHc_2ARzTNENEAlx`u>%@;(?yQ^j(kI^@y{{`fsir5c zI=~yA^Y~jmn%!N0P@ej8QsT#<*~=uGL=AnXm?JgJs$5Q=4|bp5U4OrwN6NNy+{Kqw zmb)0UJI$#n`20D`4Y&Sn%EH$LkjJ9xbnc@4Tfa{=RtGozJy!qHA9dsn+xyVJrzRJy zPFXHakC31;poU5g>vyxDN-d2({j(|A;sH7QmV458DrEF5rHC2-j5Ec5sX_YNaD-h$ z>eIKPsB=z5th%neKR&yfBR_G!C-OJXk~0jj|CVRTpvSW{O6)7KyR!?d%gGO%#q>MI zzjM09r7oP>pjSxZLZ=^q9ZraAE)wqhbI%gZ^?za$wY!9%uU*T({=g8=2Ah^h$O^hp zaA*dr9bG+Qd47$2ed@|j0maVj2k#FRGm-F$5MGZbM|n#`9y4FeJ4o8CGQuN8jLcRD&wR@ssQzQk6U; z*we`e7lHN%-n04KHDHs~MGty?u*NQ4X=7pj08&fAT+jtnxS$9p0wn1OA)pn2Pvv*> z0?jQtmz1Zrp1o*%mf}%ds0>}pSaCZCrdgHB6Toz2#7V3FAF>x zawTPv)j;yOih-7|suUS@bH_lGEQv4P-veC@FfwN~6R5#FW`|Q*JcacQ&-+rAKx#RX z9bN&3j|7@D`JrV2H~Q_nI=lnavZ7XZsIrnG56xnqg7mUby~O$x{2&Ao(*twD$dkGe zJh47ndx0?{LO`xvZ%{Kfeg=Pu-sW?WQ#tge5IC0*jZy%Es7~TJs}pi3GKTe`k;DFj z)F*8~dT~;xP)Lh{z6yA>D=lVgy?!~pGLmj}Z9lbneF_IiEkglW)nEe%A->#!FgNFy zXl3AOe{`P4ySFy)mtPKIb7~ov!H20JwK9o2ZLlDX zFd&Mn#o|Ix^25Eu?_xtRuL!EJyf%^3HaVo?gQx*(M4!gO)pe~QWn|^{QS9Psu3o1 zC-sS&+-H#94>Nx3BCrRSOFLGP@4s}ms&o7-a>&16KpUj?gnQz+sSqwWtcE*qT3nI6 z)Yj^N_RQx5%daZck6J!o2a(bUFAq=dC=w?xzYvTLAYj-_b+pAU`z4#C^s$65ZSw7p zBS0Eim@jXf+lE#Huwfp>zVY!LxzLbEr8L_3%Ya>92}mc0sX@B~S42sJ-fBNuZq?x* zKhRNHw$0gA2+~QC;vv3}D|Z#b-50Mp2P{>tY9C6<-QcqbW8Zsld2`)`kOI;v!Gl~e z0f>N*U~CjR7~qZ`A2&6#wLPxhRp#gCJY`q@a&Yh0Tt71y~1N-C2UXn{jUn&kJSS~ zI%%j(1cvaQZ+{1@INbE;Rq%OOk<{hbCDhFnEyrF}GeBCvQ<7ep!|pu?$< z`c*t2-bm9rFLY`44g>tu*F+Xuk83k)AX2uJ_QW!vUHy3hS%!96(Ve9apb;@{DnGJO-1{gE}i1a2y1b;rI}jGeE4q!P3eF%f1!; z&CDC?LQ;Vv5>_A}j|d40;`YFppwMiQ`1(wn$OY;$iF%=aq4vAub4b(H7ceg#GqfDA zl6m$mP3N#{u59w+`k8abKU#Bgfhd0sIqpCNM4)$l2;_beB$bI>F;nE%@V2C~@)*>! z$AKudE9K}=K&WQLe{IUU;BxFp2?abRyrA9XG{~ZOF95g_B73rLDl?gy&WeRHEV~h@ zd;JW^szw@s4GQ++j=RzbM3kns9+NzPV<>i5ePh4Gq2_UQ21My{ADu$@0W`wOPfba6 z+beH&AGYTJUy<~FZ3j`R@US3^5=cP=n2Jkok7=ha*T2=QnLIi5boP`y14yln@W=Y` z!AV20z9Be0HxCuyMSOsfap%LTmDdWmJ%K(XufEV@Kt|=`&rpNU2~Rj36b@1@%^jSG zk}YY4(=8#Dp>Gh%eTMfg0`goGRzcuHg88pvZUD_!4Qja+-SLYl&tKX%L@LHZ_9Gy5 z7zy6b-%A)TctYqdCh#g7VEXdD<>xR~!)n*I^Upkzsn^DDZG%X)1u_eixA>O3*{LnV zH$1ByesX7vwkO`RQFs#ZJhTaY|p664ZBpfa~UT;2oPk9J9+|IdN40PC_2KNt>9x{#uOtL`>mum0}u8u zErx+eF*rU9b3^~GzcPx|s-0OV9>fv8oC}+ff_x0NVc4= zqt{ZfM`2RX>?1$x`2{32{R@Q=gs5<0zz5jo@#lwfN|k})#*=h3qBm1$3_)b@m3wc< zo}k2Ub(lbYYTKBRH!L+`u;Ur&bo0pf+BMw5q`|J9P7xvxCE+5FZv3{D`2YR=d_~mu#wbN$nz#TAyr(2@@Ql@6J6diRG!rF0aS^_~%f5$zWi$C06O6^y1dATkC! zaOEwE(V!TgJed2mGmq`wK1X+W5?9^|k`9E+z@*V-0LK!FWAa9l650m6u_=39d%=ck z0^I94gAfG3Cu5;5^HV+wsL10tm`$=LUb|F6HI8KGxK~`q4cBS}7Bx<|d=)p1WqpJZ zXMP#dNc$Dig3&0!f_q(G!CKIOi(H8Y>g?5e>APkdXAI}r2GdED*a75zf# zE_<6-w1}Y~i^U9i1~hO-$)voURUC@Q4MAV06UjNgEfZ@vkJLpEffQOZBqQi7lnLD- zsZX9{w{<$UBHe8I56!GgEF&X9Y6B3K0${)*b>2ul-@T8LFBW>PBbh>yPJy)J*dbCU zc{jW}Is!P|C@awXF}q8-=}tENS(nzNI^rZ$*E&FsNe*m|kt zGmvHz<|R;EjR2l0XSne?&B{J01LS@0cpE*tUVjiodTEFYQHZ#Bc0*|?cld>#pG;9v z3%{0c3eFa*92`KbK+OnW5F8h-X@TmxXB8!tS100$MZHYdov3S+IxBWqU;4Axi8& zQp=Ksx(7LVh8Ro(*CpSWH*CzkmLpTLP>4J;?FVOIg3=*iUc$&(_+D|pM`S?Vr>M3z z_U4T6S+-{WgV&nh95YFW+K2ah^ik>YpFMePg~WN9Nwx$oJ6UaO3cN*r$k&XA((H*q zh#>qxsKmkUdi-%Np(3r8c;=|!d?J((!w=OQuYmVJ$_A|m&3qK|;mz1%2Z}3JO$HmE z=kp6PXk5ZP1NO)E?%jKVrPZJFSP^52$)4_yRj0bRch85AAK)7}ERQMWIhVr4HdT{+ zOIXDf3qtSsy`TA5ke{Wwq0YDARGwwH774*!u-yfEOc&ZTA4zfv9 zUET&g(LqxH;npAhdSnb zHx<=wp~kI_VXt7erny~im?P7n`N8M4OhsGvN@Z(NwhAq0XP_ValN%;C$-FpCixkyZ zSp76z(^>XmTFn;98Tu|RUMs46BkN+K+_qOZlprH=XfIFY{lBumB)?RzSr8T8b+fjP(CF3 zG9Qgy|3&Q*e$-f*+`43Zc)El%_c~>gaC=naFKU;EM|^dLV|)&JOWc>6RsU^+2qZK7 zLG9x42x-(Xe&T#5m5j>oeb4Pz-l;RXOCPQSUT(Wi<(t$>E&_cLWEUD#VNU)3Cg#brR5ENQL~C+ zER{*!Vz(~g-CytuUsrFmWZU6Z{Za>0(0&*=6}#4d{v3^p*Q+v-T-2!!=yK-o>foV3 zWL6XdYgt3;i&9&)u>HdyTBqO<=mln{9decct%DiLLdspBqE{z+`>J*x4R-|yGyciG z(vF4r8;M2g4w0$?M}S9K>i1`o-}fE+$-Z&|rhP5qW*!z~;W-j{t_P`_g_~J8|6pIS zCR6}p_sPRdDqW6Wk{G+wI&Nlv{I&?oFZLDBOGfnpfdDD(TY4x3VGXGTPVqC)I$-|B zzABsLE_?Oy-6F#51!|-?(0ShpK1*nYGVPGBTtZ);HXMx{?;$Z=eQDgcQ1UpF1Nt|J zUWJ16z00*c3B5kKho0qWo#?O(Wuh)!nSvLyn0(XsHfq+dPNzS}_w~pgJa8|M_&AiPQoxDqxsUP8qa-4Ik8Zd~n>0+r%UL1YKQH$Pn1P=Cu{rtmUipPo zm-mKdk!QDN#G(837Y-G|$g7%Kn&;Mplyv{*4EA-|!q5`5f>?Gmyne9Lx|I>N4w?fQ zA5O#1>a&0?pQ_hQS5+W-z)LT>#%xdg1q*SVfeSvHRu}rd zjDm1eCL9z+3foraX*PMXK4BJn>(udc#92{o@foNrY z0FIYCJgtKPZU!E~_pE@b@TBPAM}>I>_M;{IS;;lZv)Ak(+tcqHC(X=UgSukfPxt`m zi$kI<`e@v-_mIZ+CyUAY@v4m^k*Z*jVqcxD1*WQjUbp1TZ!D%b%DUnUsY6{AXBbJ& z9vC#IIaer5H2B71LN@~PS*|grmu7}0rBgYH3?Efq@dc&+U@?)y33#+O&^8gmwR+U? zec5}*FDpy^6Qy%X5cBgJi-~6tVlh#VMJt$Fci(McX}a9&De7~$aJG-g=YiY%E~f3u z>TTU82M~9&TT4~guIUu$|E{oo^qeXqu2$hV)>Hi&%t%ru{1ihrQOm6qm1-Bk`qYc= zimvOMSuX1=Y0|SJ`JDfdoG7ry86K8%{{J99ExWT$6O@PF46|r6v(;k?0??7 z`yZ5dFa(EXx_bUapu~+pZU%^`Ufp9e{Bfm{kDmh6(Ca6WFNJi zL!zsA1+bu;aoQ{D@l=|?OsdvcxdaMg38c>NVb>LVa!&#>qShCjy-jiIlQP_Ls$qiR zU+LZRug!C~+IiDKBg#d*<#rRtTQ;W}Q7T$j;GFHiABY#3I zZIccAeb$rK4=b{|{Ap?oZ75swCWhu=U{TSZ&w8}}Z{|64?>;Zk{4f^|t19El7f(Bp z$@2QN)D=nmCkb0@`}Mz>A0io*>|gf=ud6K0`}Vyfm(QBlJo;fLp7fi!q^1qjJotR8 z8POl8b(6jvvDVv0U*NiHD@pRzwOSb>jzJ}3Q|OxWc@KH|&1a-!WL+yakxMsc(SqNa zdJmlc&fEpJ6I=bhd2@YQG&huY`Pvw%!$2e%WvW-?PSs#Xd-=QiLQ^AH@C)O*rg@`8 zE%gb9MCHVyLd*MHL=24|jzEBzo)9g@-OC@{$AtGMzHqJ6&sFm@0FBgO>U)st#4Wn5;KNIU(`;THkMGA z?-zg#MoaAT^<8T^tJBvXM77%2{CxWMtqvt zS8r^EHeXENHoGfEZWZa<8j6564D4P=tjrI1Ub#R1Y3s9yBqt~L2>++dqub$C`KIJM z(<^+CGH9SU9?GTBD;}&Uw-WI=75ZxbFo%TQMFZ

Y%Q#l83!2fn0{{Z3DbbT~Er%EoZxOa>qd$9t2kag#` z|GOU5sBz8Uv~eom`k4bhi&a(b$W>|Dzs%!>J=5L{NBWz*WRzCrJR6%HG(CUk*F63y zJf7ReNWlNhV$Kj}7)}r04mnV3mJfqyMkX<8SV+ zryV{a0)`wFqa*1X4;3=b(C{!)vCZ9J=uG@skMyx29yoDV0!&Oq8t=WY$v>^_spEQc zHQDL=$%a=UxP_NF2uBEq1rV>nYCb>8&=0DX2e2+UUvV8A z0dii!1!>p;FA8Rr#l{}8Ivmllk2x@0ba56L3{pv<;{fq2g_@zcZI^x0jQTS4w|fE* z%OfC_Ajp(RVG^Mg5*&>8*RTNMS5sqcI>f5gK3mIwx*$lxMqm6a-vVwDK`cXu0k?() zI69i`oPGGuMH_8fre-$Wg3i=@?Qm zMD5$cTCG63Rd}T8&YkW0DJ}fQ=ZA57X!dQL)boBgUa?gH9aak~82*;e|4+#~;n{P* zU89WRrjVs3*V7r*5-)Ydq(A5LFAp6ldxv8_jAWM&KKS(Rf$%{(#IMfIcr`YG>iA5L z(Zx|T>o~VJmjSu|znIT&o1@M-wqP{zVEA(TMXiWh3`=X+L&o+Xkm}6n>9rfJG62YnaY^zH$E#QzB>;-UE3>GR~KfC{Jzzla@sr{O*T7S z^5|rePkB+}Mv=hKA8d69ow>NSra$JLp{=ypK!g~%CuBT=3nDm60m|dpRD&1QlT|LS z8K)}F$kd;D(zN?{{P^0%zxx*uzj~8|IG0IcUa=IKFUCA9W6e23JL-Y&N&mUung28z z-0>2`2Yu_rUsW{kEkvnv9#2S+Ihm=!$$96Y*^CrOFA24;Sp@VaMeiUP?KQmEp;<-U zqP>fkAgU8&!C-DJFDWVM>;aVAR`KL_@4eX|^>BELu6M;3j_U)N6`_mCGIYg+ypPs& zzNL^1UTDv8Rf=Hgl=(bI-pb!`dDq;Uy>Ad>=gscX*a za=~dyX;Cm?Y_eNKtEALA4BR6}axgf=1+tA@^3^VJN(gFcL$I+%>I^+@9D{d(`{bYt zoAK``uQF13qd&A9I8)EZJ78k=7~CU+w1$YKhW-#A4hvDVQ~*J-;NtgZIBeQ$G;3ZT zUk+I35|Mz2D(Kp8j4|hW02SuS#WL|VaLM+-gm7(nr2836709c@=n0e18WUbBQdGD^ zk&8^%T(psknK6;YtZ+)Aap73M0AI-RScX<&{=tj63orbsJlIMIn1HgLl-=J~*Y58N z+CPuc6aD(ar>au!+w4DngY*V-)dB9;i2u;|%WvbtMneV8umUCf|2->%&L@9kb8x&8mzy-wPl_Xt)SJW(b{Jv6=;$!!Bo zN|+%vX#`A?KTh^i7%>$C~GMehcnqrsw0vg?_y;t`Vkf&3+ zc!ru(A?@jR?Ow4+$k$pe|OIE=tLjf z@5W#7g}B*#Du==it)?xd%ql&0b4mR9vR_Z_Guz|JmxHI=;#nk5E8e(zRygjl@ZaDI z|I_ohf25VDzg8`3EYc7XDSP02(^aE|R-eDMX*aDz;~(J*dVh#7T;oEX3##S3`7)B# zvOAV>x$$%o^>=)sO@#41NmOnNuEih&PK1kX;Kt|Cy?^Eofad?Fjyr$p*`WH+2Zw1M zzQ5p^xd?wA)5-O*^qD5blfVrg9ZwH=muG zl9!Q!s7nZ^P#Lrc&@pA@yoQf|a8|Qmay^G_NviGfTD}P7cj1^X-a|u(X~!H_xlSYU zxI)>sX~RsjZCQr=@XQw!#>@s=_Qc8ZGI>-j5yy3c-*zxE(eQQ8*fa;;e?rX?Df2Yr1rq@+^xj*%xNNc}K zc@y~)7kr3-%Ae@-f1l3{=owvggm*J&^rj&`hS?>P@KamX2(RjwxJEf&0m83m5(mS&^ ztF91t<+AGF=Z{pE_3zwPo3sxt%}Mm{y5I2|X88}tbH8n9FKpX;${maAW$q(-H!$VX z(%yvA-|Geq(9zp`Jh(q=mM)iKe5T5duf1`CfjRkH!>zkZZy}~2Ga)FH0P{OzDcs}iD7Cbcbf;gwAGwiMm_7Vm{j}&P!<+w5%SAnO4GkKinSHYz z!39Ci9TbdE#km2?3RxmD6kO92jt+p4wUaFMy5x(nL3pRXKNiNjp3IeSSm%X&pz)q^ zjP|^@+E9}ek-)VR^x)->-=V7!cFJ2xqNSX9rG_=vW{Q(c8M6z?fC+gENG43CgA0bZ z0U9E}KBB{FtySSM!J+WDH<2S>P~5jGK{64{`w%{A}x*o`#5x*J3YQ+{)(-!WrBi!ei^Hg8xFZb06Z zI-?Ke_KdGwAofbF|5-@UCcz>e0ztSi0!?!VziMP)Cqux~6Qzm9@}Qz2q_kur`1-@F zCX>=Gw=F3nuT3+z^Mw>!T$Gzl|fGl1~1A;?>a2f{yoiK-n zSJMK=1-XJ`j>5EZEXvj;TlvWFZa96MKV)RyKWWSP5HOczH1AN=QX#l~Q8(a&M!N_| zGw#d_7#;FnE}q83qCf26YBMf&JHxL8C42Ld6TUmVXqcj~M~oys*rutw5X)P`*4i#N z(m1ambCVk2IF}2KNgCLay!W zmIJIcY}ZXUD2WLjD)-l~KRTJ1#f5%j>OiF39p&^isR1A(QTu`6TBPjhSIt-KyY4u>aJe)A z(kpOVqIzNiB;L)9eX{E{6VR3R{1TajY(EK7y1O_4j`_)s(q>mn-Qy}dycAo8SLLJf ziA`jBUO|3gSl$Xiu(lhYaY$j-d)-~pN+6*)AZ_40k((W2aM^g_!U(Wez|$y7hc0WC z{d*h{0q$)VL=|u37juV`K+@L$kn}O2L48;LvTNm)t@>+q^_f8g|E44iUqcpy&hG`6DI$T64nNcZegIqJpFzqXJ)6^0g5L);b#M zz+!;QXFXdR4%}xuGt*-JGAbl{P%8$3^>x?a2H^eA*r!Ru77wi!ewj`x_CBxtW)FlK zkr?270}=)S3pvB=P1y=e&ym??hA$%wC8Ogc`a%7HjNP!Lsc$P^hZ$|iPjv|GZvlD~Ux?3tom&jA$My_r^fqAUggG8P^H zkMoRzqHgo9N5`p+?#r^;2huo`;s|282jixJ0Ql+rmRH?T`HT2Vc67WLp>iq>kVXdX z9z>Kxl@(u$W=GLTI@~r$h|>wVm+tf&q;(_p3Klc8BFX>-C75fLM=)ho?2oc|(+A4% z6%_#>jT=0`mnaEH2K3xWPkXacHGdrHr5A6moz|2BX(U}rfQyO@0R}pIG1v9umlgXI zT;85avjJ(vNJ7Lct)cH44KMwgsr98{J5jtqRyRqY)VLc`4atyyZ?_0UIh1(glgX?> z;QVXh+nzeY6h^2|0{42R$WqaAa4TErJ1p{aclXl=U0Zhka@vnk#V3NJ_IbV+^#OlGZKc^AklG|D?V^H6V;Y($sHm3L*fn3l9v2#)udA>{?mSG{VXxclMgBtGSn z0X*LQkkHFTs7i9v03D6j-xUvPHD5{5%Q1N2+_vw4;4&lunMNRhBN@GKLv9T+AI79I z!{`r(G*3`MY9^t!j{rzyH#ppXGI1DI7u(NSS=j2T3E6b=Pa)m_tCQY0`uxmqL`vK) zdgPrXw{y`fAmpi6-*l2u^O1gZi;=b?mG}8ve&{0XQ{XyyQKX*9tMd@q&G%{7 zo5PsH7seo57vnw!zXZ?=hI8XeFsC(iG`7A{Nq;UpWWfaO4Q&~~M|!m8n^m~yZQkxT z^X3nRoY>3uf^Z>Htss0D0VfHh=6*ujw)IFkoJwE4O3Kl-)e$TLWq`xn77*jWv`hO0 z-97!dXduYZFYnna*2{OPp$>Tp5sBK8n&o`p_R&o8jii7Z&ePpA`SKLvVE&0VBCzH$ zAM=|1sv&(!fvJmFd6DE|ffY#UFoj40Y^NU~;YHOj+%j!51Nk_2G(L*}QcAR)0zQq8 zC?11lFNw@54(=Th4I?DUuYr`J*bLM=?mJA6?ScX8={2kKH(O1{5w;J4xr_7brbx2^ zgC2o6lt%%5o%n-Hx%Z)8qAf4rKuUYGRNG~s0lA@isZ2=qhPHl8(&+2)(~{JNiO-l! zG__&Fw7lh#>*4GP+9Dl47Rl&S?Q|~qu)1;VEJU3ov5E-5`EUSL@^DK1;=V68T;7_$ zz5a1w9qAYYQAiPz;!4`FsM~(1(7rUTzDXDNE1wE_ni)*xi8Fau|9%nC@F2lSi9#545^@wGl)T2`7} z?tR&YF5RJ26#^2hk*CsMy#+%gJpC(!O+4U-dbuD<)sEy;5k9izxykoF<;+=lNGh_h z`kq=eNF~`W1av*hxTtm-&fKLm6NY}M5w{cMkwxbb`dsT{F5)LHV<7fudoa>62V8&hmX zAIcP|dPzWp9rx#1_ya&-YMc_maXLo$i+J^^n2ZgDTTC|#vKa|pu#xTZ4R0=9VVZQm zWy-O%nY^qeOnwx?6c@Y%ZvzhIREthejdP##-TOAr=U|?w_;XE=LI5o$9HW_zY95jp zF1b{tJ7Q9wp?|5@y)7)h&5;t)*I9-5`$OugCe;5S@2tb3Y`6VCbc6DMGz{G#NOwv% z5)w1ONOz;a0Fp{Kq6{TcDguHatuz>jNDn9~2nr~o#nh@wG{GXR3+Aw+0FiA!x^AV8@L<7`krCPqL~cL| z9eCwfqR2%ijNYz!=`>hSBxT-{FS}#UT-=33V_M8%Mgb>RQ#`Y7o`*Hcj@3c<)?ibS zB1&ii^NuLsle}P$9z)vtgISe1fgTKAoTS_2;HBF?$opl!g6YUoj(eG|GD>;f*f*+p z8NA*dQRH_=$aKeH68ch&JcPM@>0OMA3*BfmX0vS+Fzc9n&TYVkQ&gYj{M&%ndlE0V zV#1SX4EHgE5V41~mp|y&staOj$sAt_e5yP7)w(SZ2jQb?@8mm+4FjgM)@9tN^7jl= z$HfSl{lqLso(_TwI6-_G76OkzUhAVfQ1)GVkhd5TNYXOS2{C4%64IZlgFD2<%Mmu?;r&81oA6q z^G;ULv686WRt%EI@GI|w2)D7hr(rl+RTI#xJ+&oOXn0sG;Ci`?k z-zPNI$@U?jiRt3gQ^wA5Lh_JtDWQeBjJ~(Rhmh!Bs8cI`{43#fVnhM&;oASeY$Q&@KXf2V{I@*A~8bcLBvqa}_D{ zsY0)d421shz%Bt6JOYnSo4vSrE*(;5XB>q2I{Lg^c#CTm0Kow4dOxjhs=X^t92one z>TJ9BxW^2XK_L)!jtX7?NfD*x&3h~!j_ifEGcJqGH;7;awRs6IVE8!BVTX}(rs7`9 zUk{HAvgH#kKEt$*kU~DVh~kGn0JQ|Ge0@`jE!dl3;I~~Fl z!%n@6L`)_Q_$cu3V(E0n3CRgAgZoK>zEC}KS|>#*1)HyNK?Ej#655J70k7_~%M%zo zBHZ?A$#91#9Uv<2#hYh}jKXoyChdU)DePAj*T%!iF-<(}g#b!#NSd}keuqR>5(~!d zQ14_ZZNg0K8dM%V+|x~1z{$=7a><2kD%G*7!d>nw86UYr=qUgm0gfQ>f1o+Q;z4j_ zcRmE3kI_(x|Jq!HNIz~n)ijKBp|W*yhv+G6di765_B5RexzdC@_tkY=F#)BFV++o; zyVx*W(z_#Ugaqv22#5@Iyt0UX<5x!>(we#+u2w#A=WG-o)Rlur)d6v8 z5%Zjr8?%U_6?tn+=;l)EvFl^vb^%X&L|%&ZwRBpevAE%PfB|d?7+lPu3bmW(IE%67 zk9L!{L78AUIzgGi9Q5w#vYs8DwpWGQoNyEIgG{zD ze_Xx((ei1SfYn`b=O`ukP~RBXW%RdmvxnmXv~xs3(VN!i8&9rljb_XY+r6~oL^(p) zHC(Vk9Fs3U^GOVTdtvKS*V!m3Ab0pe#@<+|)F3KPS>-Wa_^K%>auH1+3OY~8zPsO& zOdOf7$ z0L<6a;+H7W{o*(5PXso#bZJU)A)$$ zZau^elkFk7fziXKigA@=*N#5XPwgI@9S0THX*D{z3JNpNYq)HtsB;6h`}&|?JeAsM zE3vx>%6uz|tGT}{h9}=5z6B8gQ{`Vx4MhNmn6A8_cY@fOP-WYyw)pgljpJUM$PdrL z1Mj6p!WJNjTmwIOTI&2Rvx$x71jc+`8~0Csg_N-8ELWY-1jJXaBV7a09tIaF?}H9T ze{|_=!=9y7fF`p(oAab^7DYT{@ z?8jl)=!6r)cmM^B2Ylw2f@I*YAI?0K!o2u$mm2fC^^?IJywNOGA|(pWB0kqE(1kr# z?oJeo!Z`JQg8-sFLQXjU!VHtkxBlUPkdIbD#H|-7Rt$Z(!YH#oD3Q4jD81*H=Z#p4 zE{}Y%`?S%nmfO21d7s_c352sNJ?1sN6I~F=O8(X>=yqoRMG6!*&i;I%vPVG>pvz%s zeA%?Z`_s0~wifk6-g{4*a?zNacxT|=PH_J5`gL$^7tpwRz(oZ)!_FbW>fbPz9*9tmE zmM}TTtlo9Hs00-(ub*6@CID(3y_Kiy0sas0dgBDNsZ&qSO}i`L~#L7+>`UxG}K&1nS%(? zoo`-(Pb4;6j@L|=L9=rn;J;S>>ZrXE3nD}j{s?!LZN+DR$Fk`C?clvz18vJMFjr=j zI2H`=?VAZ6+B-$+0`t;OT+U|VR;5%CnXftEgk|!je`({ybOlo-Eg-j$WUVdub!E7s zO9iodeJWXVpbd%@nuY~3q~I_P@*Eo7#Tq%zc)seQ*xUN8N^TUDZP^&Eh=OLIrlx+- zmMww!#mz=Zz6Y-SUJe!`C`~L^CpRY)cz5VBSY9#~j#`)14QoWJk*f7LuA$fu90^%w z6y^X{R~eRceKPuLvt@biF9Ah;Ihb_c9SLpEg6qOn?WhXalk@$zf;8_<)`)lRF&IRn zxY>{_;aFfR){RY?0@CP?ip^N%a^MddV6Gpn-dSa?yoTZedmM_x7b}40pViI=ZVXXF z-MOk04L>Emf1P?B#qrJ3&=)YBe6jePTs2VaR>~gy6JLPdhW=za2a@m|M=4l|4wGB7NVd>HBoml?n}FYy-W;W zzwk2PedR!pbaayoteb3{DKT&_+Hdd7cekn>K<~7AXnMVAhj)lel#8){3mA8#1={t=d>IJc3{>z)Nqb_oK-o7LUSJ@Pl7w+ba3s z-#v<_hp#=ZN8f`yl6fMesTtxu(Qz1#wE0;+difB!fXXiuCI994%1Ynm)TrGD7o+n- zQp%;ph+ngZH2-FNMMFdwZT9<^h=b^=W}hcsSbGe%ovFc~aAyWTrR5fF8z=sE+gKPk zup4-6t?UwJ_KPKxOB;l>MAi)0Nnmnti1tJp0J${7x{x|H`#y1{d4CB~6S@cPCchDW zK?|-<(EfDaHueEyR{z1qRWq!ytN5KMRS3+~t-#9F8^I1rvzqIp+>x2nU@c0zh;qrF=!dkpp$ z!8Y?RgY6hFVxD$IPBFm_Cbcs5)Uj31XGG-1k6;VO128tP%SIW{o7GBAFPL2r7YkNr z>iQ+vUK1zeQ!%n=vbLpO2%_1X4=+j7_-4Teodl-VH=g+4k2#}GcB7fvFMg@R*oYa8 z!>Sk#NVuNEjR-#*k$5jkv*l?xc}6I+JGd)QWDBJ3tTzbeSTmUKcDFy{@-Y2y!LIw4 zAZ-NvNstB|iuiE$IXO0N%;m^#VDdC$ilE0VoGI%1`H!y4c@WWXOcZGN%Hs1aNT)xL zAaz-KMINcfmud&6k2A|-^Zyp4Sp^k(fasO3)~6;6muq4(@@^wdR&Zn=`ur56!-3AL z-DB-)Yy>BB736At-@Y?n?jQOdq}w#!NxY^rXJBkxzJ6tkx0>Xv_^F?QG~maavLLO7 z_!5t`ct>M=u*Avm$zv1;7^MsGfH({y@=%QnpG8>~iyCTOY97lTk8ESbJPgvtPPDfh zd3{1njFlHAMkrZd^O}@>3(~A63UlPa#*!12c+aQb#E4lnK<=qAS{ioT{N@X2TLQ-D z&rZ6F6D`!n*5)PgboI=#Y0a=XcUnM602c zm19s`SO+X^HsEU8T&~2s%UK^X8xVM2><;Uz5eYv>b9S7+i{|Y#z@5{l-a*;rK2^75 z?40W}si_Zs>-R01j{q-{KAwNZgRO4wXwiqa?!F6IAU60O&07GPGkBQ(4Q~F}Nmpri zHbt-BD{~G)v9rZRo+AIiO>kGlmfUD@tZw__YROC^Mt+w(rY{)E)qwd+r#oG82DWJ! z{g|n1D5RpN?!N{@caQK<{08%5^l{`9erVh}sh6y8lyu7tvenD@TI%SsyrTg$WgEqB zpyMO9lRRO%M9UnUANU#ur@E2%HtK6G|w$ z3R>LV-;QAL_0{okcLH_fkXb51S()^)uu`6x^eV}c&&ZB93xDt2jjNLji$5VG#c8o`CWoRi)T#Wu{Sgox zt^xLo;-9*V&15`8iv6WCEV}0)S_C#fQ>*^mkWlNl4GAS3Jsr$ILl8)2hr5O-dD*ph z^f!*ES8vez=M^9JwQR!i&CD0(Wj*BM`j0dc$C&Qo6;H1_F&R84Hkmu!N^aSj_MLjA z`OwOn(e`vNSLiw9nBV9sL%})fAJnS{LLLFo4>a9-r70`-YG12;2w|i6LB0B?hJ;cz z1gx$WIE=!9gM~Nm5G+S6ZL#eien`E-N{+Q3e6q+DYC>w5`>J_*jTSu#LbIs$nOCt) zp~8c0qZIM;M4jc4j+=D3A_<_f`nw~c;@;lPldel4!FLu0;!54bL#Bqqz;p4Pi3K_m zHg&bS6V;ucWF&j)Co;~E5v2A=>^l={3#hy?L5|{L8GrSxQH!F^j<52a8|gPDmeXH5 z67B=WS<|Qw+*bl`oWOq3Q?s^at69Wf5G=wc_312lC(?jRiLVdjFH8#$v00H{O&~Jw zp%Hft(Adv)9tguoIoZL7>;Rkf=bnYk2cCt)K%S3vM!a>Fp*lA|?GEJ|pNN(#$>4Mo z2-VsKMHFT-#mu>^JBrzyBoy2VWTojka??IjVnaQx~GY9;?b>do`vWB%CnIAkhjJ1E|Rv3)9V8| z&@9BIo9{AnB1p&k)w0m8e!#`YX)*RwgoO4dlpdC;+W;>bqD{Y__}Mx7`63`>s{HKp-Jlhto&pD@8)Otw5&4;D=c~0Xq@XI+{!Pi`vHNHY4NPz;Wak4Q zf=J#Od;cxijOIxt>CnfTV)1437(U-T3wQpBXCXVs-+LCuebLtGtPmACM!&+I?-H7r zwx;^&R}n?cn@=UiO|E2H{^HP;Y6yXR%8gv`E}%XjbqzCaygnYu8%}P|sd4v~G<$Zh zw;FiPf1tX^V*|!P*%G$_#+1_vNiSP+)#e(Adk{E4w4=p@UJeE|LHbOKiQUQFRRh}hTFT&Q@R z{d#5zW0d$i^o!wGw(@RN#xCu-Di(CR+(x?oDR=OWr2T7S!z^%>`_2UWGiO7`pO|3P z40rCzms=!ms~{JXn8L;~LaT(oF~OMs&e>2!;ZTS1H_nFa!k`XAaW(iPLtgdNiPq>F zboaTVQz#8Umm&?D-*7gJ4Zen8i&keSRwVYU)bRCpP9}jO+0GFG(548_Ps$~@kVCjZwQ4Uh7d!`B|Sqwhh!XA3s+f=>E~>yXNNMZY@dS#@^* z;0vj}O@C64+BBG2wJepDkY(bXK{w-a8&h0pTm4t(C+o(hxppkkkq}Y5%2~R2_>SOw z?l1F`lO7+Mg_>?#zv?I6V9`6_^x&Qx^2hvSp~;dyOR{_NcIXVSt7r`!~E{=%uoL2Ot#;PkGrzO>e$B3oFS1FE0XVS zs+~BTtuzcP2t1>tIItb#x)=maCK1U#IYx0w)@8(PC>YU$Fi`9 z&zo;&aY|EuB;t#t)p%pzTz+`$q;HU_X2+M)%o~dD7(BOA>eD_HfyZKl@z&o1c9y)t zWv|jQQIlUnnWz5UbKYrHZqZr%(@1`>!QbBRDM5W#SGN4_m8#p4mq?;+cU%6U!G8;7 zxGBC_xZNH-d+OY9CTvm?X0w0(M~}`wE`%Z*8z~-O&0NS79b?oZsbF^kFNf$(%0T$h z^ZqmMs=JpgPetgqqW?K%X(qg+dKFB`A>VJjE7Gd5B3+hICz0nD7qdEsW)s)1u>1q> z3OJQ`BSDh>$wd~sq%gWir&-TvCMBT+F%kB5umJLqw5cf{P1-f$9w^n`+ttgCs#9%- z3M}C7+7KW`7H|5r^kM6+a_h+@$w^N41LGowAA0rUHXe>xj=eZ5Lfu%?7Y0YCxg_~f z=l(@ZRvO?e6eE;(hr2D!XK9(DyI~RVzd`g1CW}gjrfYEi`Apxg=ViI$>VXl7Fkv;dW^ZJEOp!3BO8RJbAvxq z-FNRk+okjiO9kr`6dM!U`Uw7N6z5NzECs!jla>fxvCq=}2+r>JH;ve}zo0mN;$*#; z%DNvbcXGNmk*%^Hp{|*2lpAvR`{Yf<-^Jz>WQmRa+*nky5x4QEHT{s2m9V=PM#YIQ zz+H=#cFJz+RZ3$>0eB3E?dscvRqZj2>d`hg#EPHLm7$_;0B-__F6aex<*|W^tDn|a zr8&zey~3{xk!Fl3hxcL6$D{l4aQ#W_Kj)0OA!YtB&z;o$%F7{&J<~qq(f#<-e$&6j z4^&PKPoP)gSlN^NPWPMY>-Cu1yT^Z7f6jZ-Sl-oH*OBwECnKZxyAqy}1!f{gFhxYg zmp&#QT-KZ-mD70ai*<#Yeg7suP!z{cexDbWTCR}-JnM8~P74go1y|`T-l&1s0@nt7 zJk=Go!Leqp8j|ccJ5Fzy(YJALP!Mvzv)#o(c6_6b#D~VF?>GuaVR_thjk+hYhf_oQ z7|BEj_qKC%0;|OkzB)bmAIB0`;}6|a*LtdpWd2?D&Rd$HIPuq&nH3FhFEmXn zrhm9=g?qUEJP~A5)MXEk{G6wjpe8{x`t(MD6?Eu#XZw|y{-@R-jHCN)pRYxT$Uf%oIkX**UqY=F`y?5l_8G^WFjj$k45Cecn3bm)AmVt zV!v&JQtClku39MH-&}s;RQ~e0zf)_-R#Cw5HU?@NMHOX8`iT;X`me_dXK6jDR+(RUV?!Yy9aUm>M&=!$ASkp?(L#iZA`*IQrVpdpJQ3VPT(M$i+Zk zrfc_~EDz3i*1Hpz{ez@E9ejU!DeOV|DJ8k~CG12>eI|$Z-$~jF7^lMaw$F~c#U)tx zk(^$5VMiDXrsY4uvUPw|d^p-v!>s{s9z5E8i9-H$R9-1qD$}W|>Kp3mC_xzH3Mw+S zkwozHYn5EWeolt-j0WI)9H1BGxmv{wXG{&bKxF$DiT5+-l|1h6w-q#WOd#n76&p@r zYFw_8>sXquoR%GD96?AjlnDfyfm>y+hvQt3j*(KXkDKntJ+f*Ds?{f)>BTS{bHO^B zQ5)P>Qgd?M7mB_mNz&c4_cOhQ`HYh-*(!V4%bo!Z;XEvrJ%@;kD`H-=2WI))(RM4z zAnT)|0?$4Th_dzefhhDeWXADjvbntNpSm*Yhh3ydaP6qz^(7vo7!7|w_R=G|p+H}( zQQ%SU8L;@m2JM`k9KyALNpI>mUO4>b2Dg@^u%q`%;`N`3fIs#ZPIM>U+VG~ylvYF* z;j_pH`jjBU-bnD|DboU$e1#ql@)jnsu$S}M2rU3;pEuYghZ2F-sUG%DcHmsO9fJ8C zz%DLO|3dc3qk5HRb_--ZG52cdy3i25pM~IL)cqz6YW*TqHT5~BHf#5jM|2!P{PuSo zG_x7Nrp3IgMcl!M1K^YLtoUR)ms4VYFEU4KWM9hoE*ivAD^itAYR}r*5$+fERN#&V zB;j(vie8K>Tkghst)Gg&wEMUK1qw=fDB`d=@Uzu0GK3n?I)DQz-a(MQ8G(;+bDv8Y z7IYXOE}MBZ+f?_EB0m*!XN^@6cGpJ+sfkoS&o>RpKhYMYMX}N%d|Z4zJRy$Wju!z|_qP~Wt!AYf!YF}&iuoo4}Ou~i*8g=C{P z(l7>R>)Fh_F+ii}8ycr|TlufU2yquQk&K}6uakp~wuv!BKHOkDR*8*h7k=iQAyx)v z>szj3OnOszkf(=}JJ=ZFe~M$^>M$1ZXmbHW$E7iB(-^B@=&xbZ_VjKDH#_|%VV3Miza?7P6@%M8?{fqC zkCqHkv0JiFgJlYi?XARYve{GMS<|KU-VOcFpMxs)$`!dbtO01nZ7zVIB;NJGk z-c+FHE#$w|9w#GZ=Z4o1F(+pz!|?bU@m}34dGli>+9C)Jq1e3Fe?n{`YBh>uuqEa^ z&G(gPOM^*FL+DE6$k|Ib_;UiDXz*}@+Xifh-EqM!*B*mP%B9vIVQv8vZDOvp&JK4% z{eNqByZ~nYOgon6wjd|9R=g)0Rtait8I05?_6b7Om=3iLWQ?=dVPnUaE$F43>gGFL zXbv(t$cnxT-^Z^Um(bOc^n5uOE*Z~?RM8Mc=>8pZ#t?$+Qh?B89#6G)I)7WQSTd8( zO(gY4e>{gu%+IH~kG}2VdYtaS@O9z~tzeqSO{41O=^F(3r~PsB^vnIoG!8uub|Z(3 zjL(jbn=^NQ^v7@H6buobXBmvcri%5YOy!a7_gg&bkLTz@nJfe&j@d0smk#zk&j>3D zTl={`-bZjbap1bTqG14OTPRU!WWz=lxVHV$AEy%_gwB69;@-MHNUh^Z7TDD0r~FfY zT&;c0&$GsQIIJc01hH(10~`lT5_BWTqZxz>YDT4 z)F1z|5*d8TexpAwttX`>PTTG((iI@An3BuO2+~Et`|w+T{A#19?W|mIrr{2GCbyoL zz!iCv@lm>P>-z8ntZ}>Z{71?>1r7bZv*op#V37OPA1BMb-PEla^qIzF%S2G!A*WuN zwELg+$H5$B-;ZMKHtbSpE(LvO-v!cwcU)QCSXKVuL;p*jadKK~HdZfkMvkm{E=%b% zmHW9b3E=hmsX^{OtA3JjdwBwtkudq@E06I;&Ezab+ChW->>YM-!iKy#O9zrBHO#vv zetaC@&eXRCIR%8#=t(7>s%kaT*1HOcO8r1`3k?ntuwi+7IJmL?RfC)j#}FLZ^Yr{@ z4RUN5-9pm=`%vFqr<6K6SWzDh+xuS|Jx>1AU^acG z++7QVjjNatLZ!Cx#7l?wXLXLc<6+!ImgXai$$Rd1-k0@mZ%%8ez>#VS2biLR_W1Ph zl8OI(SV;e*T#w>z6_po_==^?roP4epo?UUrHll(sNO8wGTV1qyw1ns9Uz8 zzE3TC+lc;z7H_i7o1d>!{p`rpFMAn{tEKFl_8aE(;YncGk7~}nM=xB!dD0gk3mj> z9Lar+x0A1cJ>=1wDSZLgwhcsq_pP=SqSaHfIXQ>_!ObZUq+&uII)`K=w$e_jugUt~ zEip@6*1?xJ`Vru3kKWNY`+Nriq`isf%*&RCq08;U_PNL{{y`dQ_iQAfH|6q2(kn%g<+OD|C{WY=R#{?-yG?)u8%OxPI$)Qo@1-$yJYC zc30N0X-mJ?pg12lNK0Zv-54aU*Sr!del~3|18(4eHR$2iw|Do|H{ZkW$ug(x;~#jri^@Gr|kDO};#UzN@ui#sI% zBM}S)KN#M3w@%i zXxa?}_Z_&99afjXr`ptySJj$6`Y(8l>oPaTu@U!!3k~&w3(@C`;bk@#bx60SI@Qn{ zGRw2H$b4``I4mHMd%smco`qT*Gveo$VTqy_m0vZJQnc;#0DpO5|`6(vM zIN3Y$LP&+h(LMw7&4w#Qs0KLNz{z;zI0WYD|948v;nQXQ-d(AWZns?8Hl6PjSjKrN z_oKuVM6>!{ZghFgbXPH=Z#uzu`B8=1_Y%{7zr-w-uJ!cSpOU_kOF;9a4JUjcDrEaw+e;r zHlLb3v}3=;-*3kA5H;f2RE-lpNLB0`91Q9=L!|0*}mC3XqU*E$U0pU@o67P&8 z$u->!G!{&LaUlk-VfJ5Oc$clHXJ*nPjqA~q9^9n-vpDHv^8di_rhwgtVy(}=jgomB za7MzNo!TkF5;C`+P1Qb(qO)IVxf7F^-dZ5^G zUCkn5I|_LC9Xt_1Jxju!^Sdx5wuZg9_UpfD2^>y|k& z$&jE%?3e7L)>dNnhy6`zmZn;JcwIqx@G;~GZIg?JQekuZ&v($#=K-JZW&+47vHKK7 z6^z^Bbho_fRV@kW6+eu${-4aB4*L5w`AP3SOQdpPekEZqMx|!YNJGJi#$WsUf16ub zJ*>B;q$ve zOpezoJUhY!cVd{a zfZxcDtX#I3qDU@Ck&~29NsM#U+zeSHILwYJ{~|m3`zHLKrbh=&`2R|J#QVRH9zlBU z9mTr?{vEQ(&fuEZjk;8}YoE$&W4RWzid_Gce|KM#_83{IOR#wRW1zGXmt0B#jnMs9 z=eJCyRl1*9CMMKpKfRw=)xPL?I~Mzw{d0kdfvTOx1^F=ICy_#NX`xOp^J;%24liD# zmR}d(^Ij{O>74U<^PF)&;@W>;erscd!1m(y?dSJGS(J6Q$5#tkk6r&hzt!yag6@5O zk_(wfD)`lC0lu?Z;~L;gbGL5$DqV6oX<`Tq8DGi+S!m7gyK+H2?1V{tf7d*Mx=CJ&Cke zAs*k8N?Cbn8ylV$ZxEKe=`Lp{Why?lZ9 z%h{S&{P#Z%>{8NQGsZB#|4ThY;HL>A-1IrI$ZOa|cJ)~Vmmmu7$DL+8$2NkZc@{}- zOJ6~xnBz%_H-GovSPwD&lX?iXNU!GM>go}ogMeJajX58){!-_mok;4C;=0ZR7LzYZ z16xN?L)RFJg{f+2q>xL_ojLZ}$IRII37+R%N4tXY%d2+nPjC!X6;*Up71#ivrT})Kfs}paYK7Upheq?DRjjFgPlSTdMO9~Uoz%=&ov#TFlQSLt@hyPpEP_9g3 z&hyq{8i(0rB6jC@G~*mf9*3cG(jk|y)|^pm{dhIyYiWf~$*+a%!SLu@nlGec)oJE;>Z&fP6T7yTKK_V)k^we51*6tmUC13Yr9+vECzbDQyy z{67)+%DV+J+A)xZHdfkd2ez6#2-Y!O`-8w&IV02N^St8PZ36LTTc#~6igvvIKL~s; zFRd~>tM%rnkvB4=cFKLNHE~VzXMyi|jY{Yl7t0O9H&^86`7WQDhxA@VabknJ0iZnh zI?NDYF{vSp(9(R{xEj*9qiR9Sms;}XyFAyvn3f+#%!_^7{NfA7v@^S_u5?o<7J41H z3uxa8QVzVWt+P5q%E82Cw;EZ0gt^`O1L=zaF#4X3C0>P z9>?B=SEY%dOpY|VRKTclLs4QV4V+){ji*6j?y;-fs$PH8=z5sjQZENaxN_=}Ro~3H ziM4#)=Q)Z85ANsdVdLxP9_|8U!gAJo;XOk*@*nXqSN$q`t)7IVxc&^80K55DD&BBR zKSE$uUIpNy*OhHozp*Et<;fptIn8xBbQWLz zqT;>qXQ+ktQm8)ufr=My=j{Qz0B9D~P4hCjKVQk(ICt;7DeSBo6A>E249Sb*>gx#7 za9{#}#{Hhipuq?cnMsVyY#P^P!My=HG@bzS42&13vYv0hE8SG0X=J=UgL6w$y>E&U zjmwK|=j3hY8i5aBHj%`$f1cPIq9C@pXg7h0rCEIwjmwW^@9lIhTo`zJrzz$>Y$3Ec ztB=s%R5m_pmYyGt%Lj2~k%C17?U^xeS@I1?Uo_s&c(urq-+h~K2aU&z;o-yzgYg3o zIzyB|j$0x6)x}g^hraQ)hQtlCNv=ns~V$XINR7j75lf+rV&E=0n@JEcA+BsE;c-)OV zaMaq^W+4}WkJzNWy_*mDVilBxQ^+*AI0W0cz`5pqz=dx(E5OX1KcmRSplv#e5ewxS zn(iJS>HHy`Ms@(f_79)9RzqyP0u++--g2o-ChkOo(rJXd9g+=bSuW_bD=r({^G!_M&}L{W92Sg{-tu1+9?;VQ0wQC-T2 zACuycot!_vMYc*!D~gpF;~N?SXykqnpeonND3z;`P*N}5Kq+&k=sW-d*)@49u|_Duxe*$tfHW528X5-^k3=^CcQoDkb+dhYPitMVpSddheDh5Zz$ ztbUB=fAy)iUvWNVmD%`{9OjyqmCAhtrX8m*-QNkT+l=szMAMP6f3BG}#Psy=;T*v6 zaJK>djG>jVaNr3RlSxm~aqWv!<);JZnW91;%icl>9BQkL$j?@7+KreGRVUQ>u_uK| z-p?}gYN!21lSh;T!cl8qU82u^esxs=_c`QD#6z(zdJqKS1KQ`cGmsB|@p-&)CzHgb zsBk;J)S>+8amTLb;6H+tj8T9Xv0Al8^zca%>gFIxk!`?;YsB3)Eo_jkig1J72fl*L zne5Whkphw2DqHRMm73M=4k&hx_mS2>23sA9a~Mi$CqmkAg_F3|snp|W?Dhxm=y2W} zg$h0?tTIqoATuqDs6EnPh{{aVz@GKD1o^SL@Y! zcdbIWrM)TMSjoM6DJ82{RZSlMQm#7V$HlOuR9xbY)KM+43G3jVkb2b>=BiVr9EwEe}9RU-H(MFKBFb#&6@^ z0&ez@Kb`mP{5J1x5O^GEr^3QNk~OL!zIj*u{L($-PxIaawCFagiO-jqNex6Do?Fe} zNavpX{dw<9-WW)TwTF-u2zcw&0{Gj`#aaJg= zk5hKM%mb?*H)B+4m8@IfsIi)ZMyY3*fv;bV`OW`7>RFk5a-)bl&OTnEB5AwwDk3+6 z|7U#2v!RAvkFh>Z<4y!tsmIKwkEG~u@lpTc7dDwC%*30DAMtbn zuh9v=7h2()u;9~r5=#)u;+2UyQ>*zSYDk8Z%~_}OE-^3 zgR>4cIv|nO$=wBHp;!qH**M^s{5~7!t@b6-AU$@M`p@t= z!cPC%YuYpF`>D4W5L7F=d3T6b^;kZ{>g7gjB%FKWEs7i84x~@n+JI(C;SxaQM}MBM zGh{;9NzauXpQ&8P(tUZejr;hY5X2M#{*#!!W1oyeg<}K|q}m42x>@5O;8GZQ5m;Ld z6mJqdE`J50WJ6z-8M;y^3+k6Racn>_gp(cY4v@!K{=Qo0nZFKvJZ^bxmX-{6o3NHloI~=|Wm=X%-Kbj^mj+Z#bied2qgkgaW z73Y-oVR}HBbnBGL*=dGMtFg+^M_LOx@~W07&Tq6Bc)LOnAWkW92d~<}aJ;3sfn9aA zULbME8pRFqfWJB5z_5x^K=S)(b}SMr@2OQRsr0l@u%iOm_Q1Y~CwS+BLJRPx=%kWm zjSfM9m$G-gt#?h|)u>sOe}{Up0d%M66C-_drjHAW#7kJD*)DIKJq0F{`?-h*%bda$ z@)$%&X_IR0@p)#o3jJYVn7=Q+qY?afUq4S68;~b|Ic#bx#uvlcO>uMFvqeL_I{te; z!VcIqPJ0>&oGnuuj8z(+}(p$1wdV~leeBNbg5<5+xK12sbP;P86Dml4B1po`1r!uFD zBfN-XT=*Sza~{s|kbFfG3E=C37HU48a61H41W>cS9ICjY{v=7??<M^t zl9J5%P!lt8=yNByJqjMzc=?&#m&q&HB&VHjk+2G>oK26WL^01o^l)sHT|p!ZOdojb z;T3QagFBK^?)c5tItYBCW{UpqFTIp%oxnvx00vbHny<=~r@P%&|LYM9HmAmn78yA@* zK^3Q=@;)%x7p4Qixhpa;x1+PuwK&pWWbmASOUfc}0o6yM;A9BQ`C!p+VITo+M^f@;TbCTVsQr>$}A5Os)1b z-a9AHpx7~u^fl0!3xG98!8oDdt(6sn^uZENV?h>)w5h{SN}<~V+enmrgD3GNC&4u< zF7fCKRj}y7%kQ{8QmUqYfSij z{I|ADyeS@RbI8qqf#)%Ei?Z6$BR>*aHNZ+44BW<2q|0S03e zMML9R%vL~Yap$({2-*~-)yw8B1E{A4yai26_7%Nlq;)&Cj9>k2Bu$cb-JAMsJx_0e z)iP+k050ckxBWgE+@l=1RxporW&G%O=Rsu(cyEFs;ga=IW4=a1MP_?!q}|QlNB8Ir z@BASoysW*V(ulUVazf7tu#(K}SaW+HHY$4-j-GdrXN4qy*eWi$@Mc)PD08mslZ3WS z^3jWoUi@`lLLP_s)k%9TGW<;f;oCabtw(McOdQOc(t>tsdP>TWQigJ>scyMj=o?rB znmi0@&_Z8OA;x?{UjyRbtV=~9{vNO6*^*;*O6SO%Ql@k0L#-rn5`zy{BI5(Ok9*OV zQZH0ncxLJTQ?29{^3)wKC;{W^<;40{yk>L1+Bf?np9ixPns)?~>o1=9wXB7Wze-QgJ^~4rDbw=2cOg^6AYBc{4&S-dVGfFtf$Uq6>V<$X&%u~ zT)E?~zt6EYpgpqVLju0dEs#d_o0!LLDe$q+? z)Rdq3$P`<7{A{NP!qv||-E3(VvP%oD2M5$4Bg@<=doLd^*#Okz>-7;%i_A~Z7} z%#S-=c>-R^ykO{f3Q5LikG=66l#?7uDK&wBP4O@rFxeu8C|?z7k?zWw%R2SDQcC#m z4RS30m6Q_S@Mwya*%&a|g>o^y531AIIf;!N8=)`4^_Tk32qi_Yn70PxTT4_`OrICu zuvz@<`a$5w6f56t>27V0%nq}8*c^KiW!7@;uIcwV4T}9KRu5jqlO>l*UiMBC*onRC z-Xh6=8V?F3&44Pkk_$jnJ%T-+1du|^M7n@c~Z zPJrX8hoZ>Rn4~NjS`0K96TLU|Bp7vfqWF4J5!|DFC719ac!OvwZ83t?H1sS~d(^Pr!Etl+JeaVU9RAOV5W;N1Ly z$8BjP~F?sgL2%%&5}1ofu|rht*G9NExfRf zJ*&2anQ_ks+z`^!H`mZT4dVd*ixZqbx4)j^PiGV=_+5N~C72(Wv&a@Hz?hC~|JK`j zSA-k1AjW2W_K6G+1}>AL*;+}~e`5z7!_E!5O#!)ZJ<$s{4$nIC5>c3cOB@L^<8&^P z3GdrbCIT8sK14gnrxUPMHI=8$5!8S^PtfG_?KbGiJGvjhenT`q#8DuUrB9h0O(&ON zmwRcqswC2Q;^tAl{KHS!$;17-jV5SaM+ph5rkL72p$@NBqW}2dRB+1d`%BSaApt61 zfuVaG_Ph~+=6Av!$6IQe>sh#YJJ7_uhn{T<_a2z6gny0k$2b3as>`Y76!(ntPo7YW z^%PCp#tBQr@I5Q`S=ucf<(ikjctQac z3%S2hEu7b?v!p`tE$I+jR1fwjTiYT?--O)*gz9e6OnEs}?q=RRd16g2&Au;J4UMOV z#;gT4(~RXFb~iM#FE#`--e!zaIY;sk+^j)k-vR~`EJr{^><-;fuWJN$c|W0D;FUHZ zd{-w2N8f!P(pl^hpaem>6;O=-HgiZ-;96IMoz{w66zIFcTnH$qMe@yNv6&1Naa$pX zVGE}6qC=o#4s0H9zh~`}(2I;B2Am6gd0yOzdd&h_J2c6wFWic-M`H_P?LRh3adTLyz_a@8Ma;() z*Au15O{5V8G%;SSji6^A^aIc&!Vf53p#Ivg&qZR1Pp4+g1-An)4Qvfas8wDmyzFqJ zeJCa7)w%Q>=FpLD@VcNe)&b}!{nYy-CYK+2^#wgz%NCoAkt-Q zg>|gkdjisF>>A^xjS}7WN`u-UlY!EwKF?Wn$k!b>>;oI%+uP7{cTC$jFhM)CS?m)) zrh&qfk?7-g-p5DY(`@U8Ia}HAp|NSrnk@0~GEM56GT%O!deKk-| zW|WNB4mZ3DUSv2aa5ZNpS;9Nw5xZvg!aA}pR=QanzSQs;ZN=dD zFj&XhBfyJ1i%knSRah%C1X!pw6x|qVHV$F$Tj}>f3FCp9IZz7?cb&yv1h}g^p`l;& zPb$X{BSgpv*2#z<^JqLl=sa*`x-mT~^uF5aq~u~W>7^H0DvFe7JPz1Pa-Hih2D<(< zXqJu(H>Jy;B-Rp9J|K=xMF|}M#?jal!1g0V-MBqxtfoHunYnvj336kF0pNv%jsnl= zwVvdwk|b9feX!1aq+2Wb|JXb4c&zvT|6i9)$+&FFWoGX!nb~_qDI(o1|BrUBKD_a{g&5A7NrIK z;rH`+!_r#@(Br0apc-Vmmx|;0xAG+`vUe3i=~g2Yt)}zxOiwIwVSm?8xdhsHys>ehW(&d42e|^G5eD$Acs5CYq))NRs5Qzm-i+G`OXEC-O zt=zC97*{VIm3!k|&f$8xwws6wM6ZGhy{ItLzQrxSXgWt%$MFL7g1nLmlS1Kjq_s54pkz4KchY=& zn;Ugy<`m6KwXH|yLw=Jy5{*r849@SPMNA+T;IWhkcqe5H;Y7vmos~hUe0}P0Om0;7 zT^Z8^(5M1FMSnqCf1#{o>YK)QoAqki_|S`Lwq1#Tzs}kPmFyAnwMD{CL(;=Tu|tHU z%^6X%20AD2e6D6amOnx|F!7?6{^VE!Yk;y@V)(if{m*-N7}V1W>Voy|_7oslVu$s@kh8k#I~we39|i3J^i z<>=eF*t@`3AlfstI*zjUz(#Q!pVC1|LV{Z-puk_jkT-M!n$ONA?l4x!kKo{NBvz1; zZ>m8c#1*9}HpVc))%Fr$oVmn#TE>+jAS#3j9S9MyH3l#cz*xqj1}?8ezyq1vCnKME ziNw0=Eu%-mk(fa`zOThGAk5CMBBY|)a2Ce42aOFWSk7HgB?UShKx!zJBIFisCVTO1 z(E{ig;Wm4sx0nt6$8k6qKxD{6K9;_DmM^05n%pOOGCkmC)N+Q9Fz|Vbc4h`P5Sg>; zRSxLxJ?Vb^!OYNEHj)dA&yJ53@vN8cyd`xp&eS~l=^6GK-K9**aKHlZSBSdrKLvjF z26EB)A;jsAV#UU~SuWy*GRKCIBrzia?GI`$>OdeF;4FmKP^&Izq;Nq0flYi@wGh;? z;(b`sSp^e_Sis8GGf~pc{{yyUSKr|hDV%eC2H|F7-(UDoD8}kVP%Cf z_5~ozN7r%O%A8TT;LaaP{nkv*a@XjbNY!u$zM!x;o1_x+j&_a>+M|y;q z330&reB~M>RDM3lYDVota|1vRBMl1qaxv`T{Q$d*6@hTwJ2LFwnk=#aeA)Ls4BDD| zk8fZGVcHJFZ)!6}@wY}=Xzb$iscrzhiCwgv=zH`VQ>f!7Pdv4M#kI!&7R^jC8ZiO_ zlZU*2kSPN@Kc6d$d*YHZTc@&|2Q}AjYhtgO(}$*r`53s5;m=^1S=$*ITI(AF^&Rv& zl|+0QLD_IYO3D@odLWCn=}$dxv{j^a?IG!1aMtJV#MYw?a|;BRmK$I8Ejf$?gW59L6?nGVO|g>hPwOR+^z;; zZccA~wLD0kVFPXL3aEq=w!XwA(a3 zLF~uC{C_zZq_n_yp2IkXc+zJx(`J}bL;Lf5Z9ZZ@27qw@aO#4B^qxpg6!du}au$Qg zuQ>s8y5WXipfh~#$!>xa@Jr8bxOcj(&FYy8>xYlc8xOxw#bKTYcpqr`2hRu-ge8!i zHYnFeH$;v8J(Q5$x&KW&a2aJn(XcVJwywSoab9CX?qa+%@pRMSJkQ6pU|&Ld)cp>I zQgqjKJQ{XGnzPdwu~OL*BDE)Kb}I{Vs1gt*ZS4fYpmmEi1+jH));E7l1KdxfrpFRA*eAyMBqz$=d691&PZ z8BZ?4PdJ(?DRQc5+PpSuMwjp3g1NJkDkxb{G z8!;F6;2{&NFsz-e_&w|hYpY(ADz*s|vy!o7v%bs1nY?ro0Xw=%tUJ{)Tu7X@d08-P z#p@z}c@%IQ9I3g4Z!f5xErIDeB%&y{Desu|D<$3r1{C+HcW#fw1kjafcm}Lv-U#Oi zo>EOV1vtV~NG_(PROXPC`b7Nxa7GM&78!{El0vF7fzmACL_jd{o+<~@J6T(WY_(?d zXLqv9BtZ>Vk91t7?vmV)>RE+LV;Lw31sFG(YQ0Jhb=*KRGry;iSN-loH`%PI$z(nk zGiw3$FUcOKpT^9kL`Kq+k8EEAj#@IS^ZMOjk>q+SMuaTNo__!&?5_ zYiNg@efLkIm^XB;g4blEOlyE#1!k04gCmYm*(Sx6m3Q_X*Vr{{Nnh zFu7Q%8Z)pt-;iJb>LE=o_S;k%U}K<=R@7AzS5>?KT5>Njkiz?{fJS!To%We7|I0AH z)FY0N*5@Y8lNB%gNbkpDX)q5bK4z*|LvVz;OjS$@WT9h{XQv{zS!xXcI!L4kfIp;nAa&PfztkjMNgZ&*PHY$f{}`AU ztjI}C=I;*~s6%s8$~6jl$Uab2{Z{32P$e@d9Hc>ZAXn4O5Q(;*wda(qkjCd{665@E zhAjeE1^aq+)&zCd-1?VkB$fC0z3C1Hgu!&`zyjKX09kABT$rwWQ+CN2p3l>mL0A92 zq8s?L11jKrA&q~FRf6ujM-svH>aN6CnV)14Qg(^>v&FIS*Gbl9aUEw8!V*iP2Pu4q^68w);prSSax7Q#@D^wSxI4XJE1U>`FOHt$iP0$R$z=4b?^+7x* zDgD2ZX3rS7%*kff@L~WooC8)5Eg8Nq>2tBOIEJCaXr*aFIyapwNSy1Npmc{UK_~-c z#^O{-oVi`R8kOtlt);DO2iO9a8bBxDyl&n_!V-vjcuQ$ACPc zow4zJD>%6V^v!kTqhEDQAg6(d4*Gq{e2pd~&;90g=kC-;$(Q>x=wm|ig(jZp98%`R z?vvp0Cq$xksEVRUBa@VGOjvPnEZ)UvdnP@Y4ECJ_Mpn^H9^7}E8laHo3UgguRI zubs?mbZ`te79-B%y?IU$7wUpk%uCgZE52X(2c)v>knPX?bNu-7(1lb|_qHp&2K3cA zzDDP8&``gAr#}>%Jj*l$pJ=~=;qR$BGORr`ZF&7@gl+`OR!2wQp?`cepr(pH@{u*t zj_cnu&-wSs59hC%1rK{NUNcK8(z@h%(w=VeG1lKGKjbVJGk*mKdW2nh%bWQ{B06r# ze0*PiShARQw=*Qe2d&ley_vd6aMiGRQSR1Lzs+Adl^wQRB#xKjTHtXFqXNd7GKw-RcAPIc_gt-v_6EoJ zm)Gz+RFd(5StehBfr0(Piw&+qT{_*t>%i6=!%tC_&_>L+a=h>wcI~-N75~jh=c7ng zT&*Y`4ykI)QQ^ghf<|m6D(7kNdbL&lmOn$vd>z+e{?hwFIUMs!hDnF4`UCT99_0KPT-3^08Db#H+~EI$b2zTSyH0$V=c$GtT!&Z z2dadjqa6ry$9VP(1=j=CF?Jt~YQLeB#M2l6V3Oh}f2lupWki2?jcC0>Z=Bc#8CBTc zcN9dAst>fn4hfSvZ1L9=;_sQhu#Zx^98xsl#A+)8gpuskbt90nZ%>glUk*DYWviEk zFX+;Kranb{tgh>Le8>9Z%Z3{a29_x8jJ3(+UHN23bzKNUO?*jM&&Y@J2k`qJoE*>V zJH0uq>)MDoV)X;%D}^hC9jtPd(l*C0B^=guKgeGKW(Iz(uDhVB1ZsSWN9mjGLym-} z7c2k1d=@lmnzCEh?b0KKpICBu#|7rFqTaWna(~SDR`E$aqUPfrtVqmxP&%@sOijcd zL+!}u{c`QF=7Tzg@;zp{(5sXys75V`Jb;$BID1s{>G$>LRz|#T8t`f_#kXsq8LzYi zX3i1p$SP}sGlc3kja1dZN&J>B`JKVpcNdxCUYY^8se@#spB8=Oy2U;_hB4mc=S|B> zH~gcM&{F|J@qW=)w8)WILQ3M1Jb-)Y{A1N;3)?Q$z@P0UBk4dq1E6=xAFa*MVc%)) zkGsxYd&?LVSRVlS(U-sp^tFJ!#*}Z5a0*Pz}qv42}lr*tQ?Te+0&-pX3fmOL%FU~=JP%i=# z7iSO9kDBZ+ZJq`=_LiU)3!rVgjCq@9ITLkm6Z+nrrC-+nT-Xd`>GyxNm^D z5k$RM7#QI$K{2+I@W2Fz?9>e^NZ$uIP%rL=AJN_-07-P#n+0Hd-$CZe2|4{mbnz|e zW8dAw_K)ku32+ahTnvExpj?cGgXE7!Du8-1*upwvwRfYfL-BHmQ5G|+XNx)eA-_@O zt#j&pWwHpa-F-HKP)T9Qo79)ThWmsZ+sGB#maoY9amc<; zH8C^X0}V!d45~3H*clahfe(4!>>ln4(VGn%D!49;26gP*-~I*OjP~qsGY@GjVv_L7K^R-V7f|)F20SC9O12S1O*^`ZAJe^=iG8 zOz^%8c@BzWMGK5hRvwt9{#{{d_x;pGpIw4MysOkA6Lm?h6uz7ha?SfD7_A8&Plt>I`jg5MafAbJ8?_N10K7vf*cTi7b8IGx?`v$L^{dp?*iNP6 z%O9#a0Hjw^X-~RBTQOEeCabOG&WdJHxPwMeR?2kUloN2t0Mb?Yy7}DY4BiVUs6)~( zZHe-A243PIUITc&@8&m7f!vf0T>Bi=-!k=$C+gzU`4CDX!BeCExPD-z%waXkBnfzT zLa`4cMhiyWb|#?uc>N&h!Q(=n1fiPdSPpV?$9zZF&SQ?KAO1|Z!Japfk>~XEI3p^U zC<$%V0K<89ldTQ_)e^%o3QDD4=d$Vr>buz0Z_dYSr2co;53bb;8RR3+>WQhDo#E>f z`KtW2W56bPIDyA|)ghDs{gJ-akizZumMI3(xVyZ+SU+%yf+uo&L#AtT70DdQQ|vBG z^Z?VT|3&q~O+i;;@5WO)UCI2bg8c!h5R~jA(vs+!D~^1}x?6avyz!&+H@Zm71b}_) zKo|Na>xa_J=Z2$5fr0NEv>48@<)mc5Z?d4JIg6PO=3 zU{9M8=i+i0pYoT#@_<_p>7`ukHm%xG{cxxKA+{QK#m$LZzOmZ;FzpA03yeVhK(f!C zjtg#}Ldk|kWY!Uc-NP8WeW9g(9CTJJ=CuByYGhP#rf}m5!Q}P9tg^t@@0;N$ zst4(euk(1hG=jc0TE^kpziBQKT$%z$AXKAv#bvY>$+USEJD)*;TSiK@ZP1eMRHJ#w z=e*Cw&n^eE5TZ81;i%}95$4v4aAn0ZRxi|rJj2f-UEEuk}XD28r}kYemvbJ&+j(2LoT(-jL%D3J5s39!Se`HV4t3#FfAD)cdWN z2G#u8RZXt$)op5E$dOpd#MTA$g94%+ka&R-K@TVqE)TQ54~dDV<)<;^)S_dVW>nQ1 z1uq|z2o{bwnp(?GA)ecqqZJbzaM5o*gm94gzHF58CuM;8(Bxb2v|pTlv^{FIR)u|~ z{OFy(uM80X!!m&EkIMi+HbNktX@!4W2Y`>uM)*G{1IEE?B!Ic!&;#Ts7;U*Q!^d4w zl!$DcV^b#BS3U}kKc*V}pb7vgO2_ZZ0PY``0f-308b62-(qhdUd$%iZ6NI)eMg@6W zeW1N}SOv638e9#h=v&BEG~G-o4W^MeS?P0JTxz}QQ7;?hb;cPBJ2&msdPaW##SGZ7 zB7o&|@6=TI?5lfsY_?D%PJW_`y%UTOmws9V@az`>yaqhA1PioR8%=YW<(n=Ki&ly^ z9~1#JTR;&|fYP3cEfPZ!BzU2yUb@nv=pu?fjLsa4|EDzox1KF)b$J8L5&^nYFhG;$uD%>*g9pxi{Z)Rhd5ub+#g zA)0NHX^Iuq@XX*pK9A3>t*I|R+=-ng3>L)rcq$e-_8e8n@$=YK(ndr5je_@%h*6FE zdaE1yB~O5a@oRa?g(;*p!HstT;=rext1>oxQDG;a9-YUN%3Cuk3K63@MRpCL=x@kX z3x;5a=W(5w-i7p7UXYF~_LznMT14KWEC~1o5bw^%Gjl!o`f>ny7(iV z6IB>+>gNhwEX41sNZ|v~riTaeItgbs3%?wif`RJL25nHZRi!S@(Sa=2ZcnUN9{FNe z`>_udpQhC!!OWY(3w@3DN;AAlr~1)_fmu(!$s$8Z8e`x1FBR=^keFgDh=#395O&?-|O>u(6U7e zH9o>?FY{*e^jME=L~8qVcxF$ku$YBgCX@`+Z^e>6+c5;0;=~`F*$*405R$-8 z!;(ETEtR8*7SDM&g(W|O)O()^PwhoW0zV5&&W6M;p4riWohc9h=AXE!A0|AWIRTJ8 zcO`*tLMIRv^@$daMrr-a@{H+NX|(b0-^pOmtsS2;@`(p37W0k#}3xegbR?-IWCVMgAZyS>Zqu7%s;lwkQ-S z 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%0Af2Ec5pq)tLXHJ^$Ii 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π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%0Avimq2@^vFy+`)lv&9(*?#6a2b<-9lQ+uQZ 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 zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5ZHh~;e`!^MF|ifK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZ;J*}@eev&Gxk2GX&inbtU(UW<*grFQzwumnWZ~zN^EYO$hhouaWkp3e(v=y= zboKO}P6xy9wvT;#nv7?crYfRCp|3rksw+SLiN(vy!}TpkI~!BU;MYXc#e&k_c(VFt zUPtA%JIl|$-x?j?5o)eYH8v#L+9R2sU~<=R(blV}eba5()~fjE@!F5^%j3I4t%=%0 z&56kA>_D*dNJrb1q7S9PiK@ks2kCpuZ*D&<52E3qINY7-$(-uW24jc!UK;u_m%DAE xq^`g0Rmptbme=FS;%s{0OkbpLFle~D*uV6s^Z8U_PucXb>b|*>x3ho8{teV-Y^DGJ diff --git a/tests/integration_test.py b/tests/integration_test.py deleted file mode 100755 index 6604097..0000000 --- a/tests/integration_test.py +++ /dev/null @@ -1,116 +0,0 @@ -#!python3 -""" -Unit tests - only to check functions do what they are expected to do. -Please avoid checking the integrity of the dataset. -""" - -import unittest - -from oscar import * - - -class TestBlob(unittest.TestCase): - def test_commits_shas(self): - # setup.py from minicms - used in at least couple commits - blob = Blob('46aaf071f1b859c5bf452733c2583c70d92cd0c8') - self.assertGreater(len(blob.commit_shas), 1) - self.assertIsInstance(blob.commit_shas[0], (str, bytes)) - - -class TestTree(unittest.TestCase): - # there are no relations in this class, everything is covered by unit tests - pass - - -class TestCommit(unittest.TestCase): - def test_projects(self): - # a commit in numpy from Oct 2009 - present in over 3k projects - c = Commit('4fb4c64cae2ce1ba16082d918e94e845fa2c87f3') - self.assertGreater(len(c.project_names), 3000) - self.assertIsInstance(c.project_names[0], (str, bytes)) - self.assertTrue(any(pname.endswith(b'numpy') - for pname in c.project_names)) - - def test_children(self): - # minicms commit with two children - c = Commit('a443e1e76c39c7b1ad6f38967a75df667b9fed57') - self.assertGreater(len(c.child_shas), 1) - self.assertIsInstance(c.child_shas[0], (str, bytes)) - - def test_changed_files(self): - c = Commit('f2a7fcdc51450ab03cb364415f14e634fa69b62c') - # 3 files changed, 1 deleted - self.assertGreater(len(c.changed_file_names), 2) - self.assertIsInstance(c.changed_file_names[0], (str, bytes)) - - -class TestProject(unittest.TestCase): - def test_commits(self): - p = Project(b'user2589_minicms') - self.assertGreater(len(p.commit_shas), 30) - self.assertIsInstance(p.commit_shas[0], (str, bytes)) - - def test_commits_fp(self): - p = Project(b'user2589_minicms') - commits = set(c.bin_sha for c in p.commits_fp) - self.assertGreater(len(commits), 2) - self.assertLessEqual(len(commits), len(p.commit_shas)) - self.assertTrue(commits.issubset(p.commit_shas)) - - def test_in(self): - p = Project(b'user2589_minicms') - c = Commit('f2a7fcdc51450ab03cb364415f14e634fa69b62c') - self.assertIn(c, p) - self.assertIn(c.sha, p) - self.assertIn(c.bin_sha, p) - - def test_head(self): - self.assertEqual( - Project(b'user2589_minicms').head, - Commit('f2a7fcdc51450ab03cb364415f14e634fa69b62c')) - self.assertEqual( - Project('RoseTHERESA_SimpleCMS').head, - Commit('a47afa002ccfd3e23920f323b172f78c5c970250')) - - def test_tail(self): - self.assertEqual( - Project(b'user2589_minicms').tail, - binascii.unhexlify('1e971a073f40d74a1e72e07c682e1cba0bae159b')) - - def test_authors(self): - p = Project(b'user2589_minicms') - self.assertGreater(len(p.author_names), 1) - self.assertIsInstance(p.author_names[0], (str, bytes)) - - -class TestFile(unittest.TestCase): - def test_authors(self): - f = File(b'minicms/templates/minicms/tags/breadcrumbs.html') - self.assertGreater(len(f.author_names), 1) - self.assertIsInstance(f.author_names[0], (str, bytes)) - - def test_commits(self): - f = File(b'minicms/templates/minicms/tags/breadcrumbs.html') - self.assertGreater(len(f.commit_shas), 1) - self.assertIsInstance(f.commit_shas[0], (str, bytes)) - - -class TestAuthor(unittest.TestCase): - def test_commits(self): - a = Author(b'user2589 ') - self.assertGreater(len(a.commit_shas), 40) - self.assertIsInstance(a.commit_shas[0], (str, bytes)) - - def test_files(self): - a = Author(b'user2589 ') - self.assertGreater(len(a.file_names), 10) - self.assertIsInstance(a.file_names[0], (str, bytes)) - - def test_projects(self): - a = Author(b'user2589 ') - self.assertGreater(len(a.project_names), 10) - self.assertIsInstance(a.project_names[0], (str, bytes)) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/local_test.env b/tests/local_test.env deleted file mode 100644 index f72f48b..0000000 --- a/tests/local_test.env +++ /dev/null @@ -1,7 +0,0 @@ -# no shebang line because this file is only expected to be `source`-ed - -export OSCAR_TEST=1 -# it would be cool to set relative to `$(dirname $0)`, but it is sourced -export OSCAR_ALL_BLOBS="tests/fixtures" -export OSCAR_ALL_SHA1C="tests/fixtures" -export OSCAR_ALL_SHA1O="tests/fixtures" diff --git a/tests/test_profile.json b/tests/test_profile.json new file mode 100644 index 0000000..8553f17 --- /dev/null +++ b/tests/test_profile.json @@ -0,0 +1,357 @@ +{ + "wocSchemaVersion": 1, + "entities": { + "a": "author", + "A": "author_unalised", + "b": "blob", + "c": "commit", + "cc": "child_commit", + "f": "file", + "fa": "first_author", + "t": "tree", + "h": "head", + "p": "project", + "P": "project_deforked", + "pc": "parent_commit", + "r": "root_commit", + "ta": "time_author", + "tac": "time_author_commit", + "trp": "torvalds_path", + "dat": "colon_seperated_data", + "tch": "compressed_data", + "bin": "binary_data", + "idx": "binary_index" + }, + "dtypes": { + "h": "hex", + "s": "str", + "cs": "[compressed]str", + "sh": "str_hex", + "hhwww": "hex_hex_url", + "r": "hex_berint", + "cs3": "[compressed]str_str_str" + }, + "sites": { + "bitbucket.org": "bitbucket.org", + "gitlab.com": "gitlab.com", + "android.googlesource.com": "android.googlesource.com", + "bioconductor.org": "bioconductor.org", + "drupal.com": "git.drupal.org", + "git.eclipse.org": "git.eclipse.org", + "git.kernel.org": "git.kernel.org", + "git.postgresql.org": "git.postgresql.org", + "git.savannah.gnu.org": "git.savannah.gnu.org", + "git.zx2c4.com": "git.zx2c4.com", + "gitlab.gnome.org": "gitlab.gnome.org", + "kde.org": "anongit.kde.org", + "repo.or.cz": "repo.or.cz", + "salsa.debian.org": "salsa.debian.org", + "sourceforge.net": "git.code.sf.net/p" + }, + "ignoredAuthors": [ + "GitHub Merge Button " + ], + "maps": { + "c2p": [ + { + "version": "U", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/c2pFullU.0.tch", + "./tests/fixtures/c2pFullU.1.tch" + ], + "larges": {}, + "dtypes": [ + "h", + "cs" + ] + } + ], + "c2dat": [ + { + "version": "U", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/c2datFullU.0.tch", + "./tests/fixtures/c2datFullU.1.tch" + ], + "larges": {}, + "dtypes": [ + "h", + "s" + ] + } + ], + "b2tac": [ + { + "version": "U", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/b2tacFullU.0.tch", + "./tests/fixtures/b2tacFullU.1.tch" + ], + "larges": { + "a11777cc471a4344702741ab1c8a588998b1311a": "./tests/fixtures/b2tacFullU.1.tch.large.a11777cc471a4344702741ab1c8a588998b1311a" + }, + "dtypes": [ + "h", + "cs3" + ] + } + ], + "p2a": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/p2aFullR.0.tch", + "./tests/fixtures/p2aFullR.1.tch" + ], + "larges": {}, + "dtypes": [ + "s", + "cs" + ] + } + ], + "b2c": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/b2cFullR.0.tch", + "./tests/fixtures/b2cFullR.1.tch" + ], + "larges": { + "3f2eca18f1bc0f3117748e2cea9251e5182db2f7": "./tests/fixtures/b2cFullR.31.tch.large.3f2eca18f1bc0f3117748e2cea9251e5182db2f7" + }, + "dtypes": [ + "h", + "h" + ] + } + ], + "a2c": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/a2cFullR.0.tch", + "./tests/fixtures/a2cFullR.1.tch" + ], + "larges": {}, + "dtypes": [ + "s", + "h" + ] + } + ], + "c2cc": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + null, + null + ], + "larges": {}, + "dtypes": [ + "h", + "h" + ] + } + ], + "a2f": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/a2fFullR.0.tch", + "./tests/fixtures/a2fFullR.1.tch" + ], + "larges": { + }, + "dtypes": [ + "s", + "cs" + ] + } + ], + "c2f": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/c2fFullR.0.tch", + "./tests/fixtures/c2fFullR.1.tch" + ], + "larges": { + }, + "dtypes": [ + "h", + "cs" + ] + } + ], + "c2b": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/c2bFullR.0.tch", + "./tests/fixtures/c2bFullR.1.tch" + ], + "larges": { + }, + "dtypes": [ + "h", + "h" + ] + } + ], + "p2c": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/p2cFullR.0.tch", + "./tests/fixtures/p2cFullR.1.tch" + ], + "larges": {}, + "dtypes": [ + "s", + "h" + ] + } + ], + "f2a": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/f2aFullR.0.tch", + "./tests/fixtures/f2aFullR.1.tch" + ], + "larges": {}, + "dtypes": [ + "s", + "cs" + ] + } + ], + "b2f": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/b2fFullR.0.tch", + "./tests/fixtures/b2fFullR.1.tch" + ], + "larges": { + }, + "dtypes": [ + "h", + "cs" + ] + } + ], + "c2r": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/c2rFullR.0.tch", + "./tests/fixtures/c2rFullR.1.tch" + ], + "larges": {}, + "dtypes": [ + "h", + "r" + ] + } + ], + "b2fa": [ + { + "version": "U", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/b2faFullU.0.tch", + "./tests/fixtures/b2faFullU.1.tch" + ], + "larges": {}, + "dtypes": [ + "h", + "sh" + ] + } + ] + }, + "objects": { + "tree.tch": { + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/tree_0.tch", + "./tests/fixtures/tree_1.tch" + ] + }, + "commit.tch": { + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/commit_0.tch", + "./tests/fixtures/commit_1.tch" + ] + }, + "blob.idx": { + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/blob_0.idx", + "./tests/fixtures/blob_1.idx" + ] + }, + "blob.bin": { + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/blob_0.bin", + "./tests/fixtures/blob_1.bin" + ] + }, + "commit.bin": { + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/commit_0.bin", + "./tests/fixtures/commit_1.bin" + ] + }, + "commit.idx": { + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/commit_0.idx", + "./tests/fixtures/commit_1.idx" + ] + }, + "tree.idx": { + "sharding_bits": 0, + "shards": [ + "./tests/fixtures/tree_0.idx" + ] + }, + "tree.bin": { + "sharding_bits": 0, + "shards": [ + "./tests/fixtures/tree_0.bin" + ] + }, + "sha1.blob.tch": { + "sharding_bits": 0, + "shards": [ + "./tests/fixtures/sha1.blob.tch" + ] + }, + "sha1.commit.tch": { + "sharding_bits": 0, + "shards": [ + "./tests/fixtures/sha1.commit.tch" + ] + } + } + } \ No newline at end of file diff --git a/tests/unit_test.py b/tests/unit_test.py deleted file mode 100755 index 1a3d7a8..0000000 --- a/tests/unit_test.py +++ /dev/null @@ -1,209 +0,0 @@ -#!python3 - -# cython: language_level=3str -""" -Unit tests - only to check functions do what they are expected to do. -Please refrain from checking integrity of the dataset. -""" -from __future__ import unicode_literals - -# Cython caches compiled files, so even if the main file did change but the -# test suite didn't, it won't recompile. More details in this SO answer: -# https://stackoverflow.com/questions/42259741/ -import pyximport -pyximport.install( - # build_dir='build', - setup_args={"script_args": ["--force"]}, - inplace=True, - language_level='3str' -) - -from oscar import * -from unit_test_cy import * - - -class TestBasics(unittest.TestCase): - def test_commit_tz(self): - ctz = CommitTimezone(9, 30) - self.assertEqual(repr(ctz), '') - - def test_parse_commit_date(self): - cdate = parse_commit_date(b'1337145807', b'+1130') - # Things to consider: - # - unix time is always UTC - # - when datetime is rendered, it shows time in the specified timezone, - # at the given UTC time. - # - if no timezone is specified, the server timezone is used - # So, when the timezeon is specified, rendered time should be consistent - self.assertEqual(cdate.strftime('%Y-%m-%d %H:%M:%S %z'), - '2012-05-16 16:53:27 +1130') - cdate = parse_commit_date(b'1337145807', b'-1130') - self.assertEqual(cdate.strftime('%Y-%m-%d %H:%M:%S %z'), - '2012-05-15 17:53:27 -1130') - self.assertIsNone(parse_commit_date(b'3337145807', b'+1100')) - - -class TestHash(unittest.TestCase): - # libtokyocabinet is not thread-safe; you cannot have two open instances of - # the same DB. `unittest` runs multiple tests in threads, so if we use - # `.setUp` and multiple tests, it will fail with "threading error". - # Hence, monolitic test - def test_hash(self): - # setup - # key 114 is from the commit used by TestCommit below, which present - # in both test and production environment. - # just a reminder, PATHS[data_type] is a (path, key_length) tuple - db_path = PATHS['commit_random'][0].format(key=0).encode('ascii') - self.db = Hash(db_path) - - # reading a single key - k = b'test_key' - self.assertEqual(self.db[k], b'\x00\x01\x02\x03') - - # reading all keys - # create_fixtures.py adds more commits to this file to make it up to 1K - keys = list(self.db) - self.assertGreaterEqual(len(keys), 1000) - - -class TestBase(unittest.TestCase): - # there is nothing testable at this class right now - pass - - -class TestBlob(unittest.TestCase): - # GitObject: all, instantiate from str/bytes - def test_string_sha(self): - self.assertEqual(Blob.string_sha(b'Hello world!'), - u'6769dd60bdf536a83c9353272157893043e9f7d0') - - def test_file_sha(self): - self.assertEqual(Blob.file_sha('LICENSE'), - u'94a9ed024d3859793618152ea559a168bbcbb5e2') - - def test_len(self): - sha = u'83d22195edc1473673f1bf35307aea6edf3c37e3' - self.assertEqual(len(Blob(sha)), 42) - - def test_data(self): - # blob has a different .data implementation - sha = u'83d22195edc1473673f1bf35307aea6edf3c37e3' - self.assertEqual( - Blob(sha).data, b'*.egg-info/\ndist/\nbuild/\n*.pyc\n*.mo\n*.gz\n') - - -class TestTree(unittest.TestCase): - def test_data(self): - tree = Tree(u'd4ddbae978c9ec2dc3b7b3497c2086ecf7be7d9d') - self.assertEqual(tree.data, ( - b'100755 .gitignore' - b'\x00\x83\xd2!\x95\xed\xc1G6s\xf1\xbf50z\xean\xdf<7\xe3' - b'100644 COPYING' - b'\x00\xfd\xa9K\x84\x12/o6G<\xa3W7\x94\xa8\xf2\xc4\xf4\xa5\x8c' - b'100644 MANIFEST.in' - b'\x00\xb7$\x83\x15\x19\x90N+\xc2SsR;6\x8c]A\xdc6\x8e' - b'100644 README.rst' - b'\x00#JWS\x8f\x15\xd7/\x00`;\xf0\x86\xb4e\xb0\xf2\xcd\xa7\xb5' - b'40000 minicms' - b'\x00\x95H)\x88z\xf5\xd9\x07\x1a\xa9,Bq3\xca,\xdd\x08\x13\xcc' - b'100644 setup.py' - b'\x00F\xaa\xf0q\xf1\xb8Y\xc5\xbfE\'3\xc2X 1375321509 +1100\n' - b'committer Pavel Puchkin 1375321597 +1100\n' - b'\nLicense changed :P\n', data) - - def test_attrs(self): - c = Commit(u'e38126dbca6572912013621d2aa9e6f7c50f36bc') - self.assertTrue(c.author.startswith(b'Marat')) - self.assertTrue(c.committer.startswith(b'Marat')) - self.assertEqual(c.message, b'support no i18n') - parent_sha = b'ab124ab4baa42cd9f554b7bb038e19d4e3647957' - self.assertEqual(c.parent_shas, (binascii.unhexlify(parent_sha),)) - self.assertIsInstance(c.committed_at, datetime) - self.assertIsInstance(c.authored_at, datetime) - self.assertEqual(c.committed_at.strftime('%Y-%m-%d %H:%M:%S %z'), - '2012-05-19 01:14:08 +1100') - self.assertEqual(c.authored_at.strftime('%Y-%m-%d %H:%M:%S %z'), - '2012-05-19 01:14:08 +1100') - self.assertIsInstance(c.tree, Tree) - self.assertEqual(c.tree.sha, u'6845f55f47ddfdbe4628a83fdaba35fa4ae3c894') - self.assertRaises(AttributeError, lambda: c.arbitrary_attr) - self.assertIsNone(c.signature) - - c = Commit(u'1cc6f4418dcc09f64dcbb0410fec76ceaa5034ab') - self.assertIsInstance(c.signature, bytes) - self.assertGreater(len(c.signature), 450) # 454 for this commit - - -class TestProject(unittest.TestCase): - def test_url(self): - self.assertEqual(Project(b'testuser_test_proj').url, - b'https://github.com/testuser/test_proj') - self.assertEqual(Project(b'testuser_test_proj').url, - b'https://github.com/testuser/test_proj') - self.assertEqual(Project(b'sourceforge.net_tes_tproj').url, - b'https://git.code.sf.net/p/tes_tproj') - self.assertEqual(Project(b'drupal.com_testproj').url, - b'https://github.com/drupal.com/testproj') - - -class TestFile(unittest.TestCase): - # this class consists of relations only - nothing to unit test - pass - - -class TestAuthor(unittest.TestCase): - # this class consists of relations only - nothing to unit test - pass - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/unit_test_cy.pyx b/tests/unit_test_cy.pyx deleted file mode 100644 index 9c66aec..0000000 --- a/tests/unit_test_cy.pyx +++ /dev/null @@ -1,41 +0,0 @@ - -# cython: language_level=3str -""" -Unit tests - only to check functions do what they are expected to do. -Please refrain from checking integrity of the dataset. -""" - -import unittest - -cimport oscar - -class TestUtils(unittest.TestCase): - # ignored, as they're executed on import anyway: - # _latest_version - # _key_length - # _get_paths - - def test_unber(self): - self.assertEqual(oscar.unber(b'\x00\x83M'), [0, 461]) - self.assertEqual(oscar.unber(b'\x83M\x96\x14'), [461, 2836]) - self.assertEqual(oscar.unber(b'\x99a\x89\x12'), [3297, 1170]) - # test number exceeding 32-bit signed int - self.assertEqual(oscar.unber( - b'\x84\xb0\xfb\x82\xd93*'), [150581849267, 42]) - - def test_lzf_length(self): - self.assertEqual(oscar.lzf_length(b'\xc4\x9b'), (2, 283)) - self.assertEqual(oscar.lzf_length(b'\xc3\xa4'), (2, 228)) - self.assertEqual(oscar.lzf_length(b'\xc3\x8a'), (2, 202)) - self.assertEqual(oscar.lzf_length(b'\xca\x87'), (2, 647)) - self.assertEqual(oscar.lzf_length(b'\xe1\xaf\xa9'), (3, 7145)) - self.assertEqual(oscar.lzf_length(b'\xe0\xa7\x9c'), (3, 2524)) - # test extra bytes don't affect the result - self.assertEqual(oscar.lzf_length(b'\xc4\xa6\x1f100644'), (2, 294)) - - def test_decomp(self): - # TODO: test decomp() - pass - - def test_fnvhash(self): - self.assertEqual(hex(oscar.fnvhash(b'foo')), '0xa9f37ed7') From 8c703954bd19f205046e9e61c37f2b493030c2d4 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 5 Jun 2024 02:42:56 +0800 Subject: [PATCH 11/38] test: add test cases for woc.local --- tests/fixtures/blob_0.bin | Bin 9396 -> 867 bytes tests/fixtures/blob_1.bin | Bin 0 -> 8529 bytes tests/fixtures/{commit_1.tch => commit_0.tch} | Bin 528944 -> 528928 bytes tests/fixtures/create_fixtures.py | 34 ++++--- tests/fixtures/sha1.blob.tch | Bin 528832 -> 528800 bytes tests/fixtures/{tree_0.tch => tree_1.tch} | Bin 528848 -> 528816 bytes tests/test_local.py | 91 ++++++++++++++++++ 7 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 tests/fixtures/blob_1.bin rename tests/fixtures/{commit_1.tch => commit_0.tch} (99%) rename tests/fixtures/{tree_0.tch => tree_1.tch} (99%) create mode 100644 tests/test_local.py diff --git a/tests/fixtures/blob_0.bin b/tests/fixtures/blob_0.bin index 83006f89cb0df196cf7cb9109b3d0144a780ccfc..70d8d07f09460e89a76fa0a289d240f12a429161 100644 GIT binary patch delta 9 Qcmdnu`Iv2UpkgvJ02J*5asU7T literal 9396 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 X#?+I0n43Ws+6!PBcQxFC71#d-%4*y3 diff --git a/tests/fixtures/blob_1.bin b/tests/fixtures/blob_1.bin new file mode 100644 index 0000000000000000000000000000000000000000..31bd3c0a1409114f8bbb3453121e8b757ea3e0d6 GIT binary patch literal 8529 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 literal 0 HcmV?d00001 diff --git a/tests/fixtures/commit_1.tch b/tests/fixtures/commit_0.tch similarity index 99% rename from tests/fixtures/commit_1.tch rename to tests/fixtures/commit_0.tch index d0800452573548f47894301d73256d28d2a4c628..ea731db5b3d5916b227d8ee4c924f8d504eb12ab 100644 GIT binary patch delta 93 zcmdn6L}9@ag$Wjn3XPVnmW-{IOs$s8t(GiXEm_ldZcH#>YG1IE6^PlkFWAXm5UPBl pj{yoe8AMJqK3U%>mL*;hBU>WfEgN3?S;;<-e|otf$4(ZIDgeTe9UK4v delta 108 zcmZ3mL}9}cg$Wjn291`jmW-{IOs$s8t(GiXEm_ldwqMxI3dC&NFYIP72;G=qz+`@6 zIRg~1GH9G;Of^YNv#>NYGfOlyH@7fNHcT-$F-)>ZGE6ZwH#bc)HZn3!Gc`0wo1QGl Gu@eB89U%4q diff --git a/tests/fixtures/create_fixtures.py b/tests/fixtures/create_fixtures.py index 3454f00..c492fba 100644 --- a/tests/fixtures/create_fixtures.py +++ b/tests/fixtures/create_fixtures.py @@ -99,7 +99,7 @@ def get_values_raw(self, map_name, key): print('reading large', _map["larges"][_hex], 'key', key, 'type', _map["dtypes"][1]) return read_large(_map["larges"][_hex], _map["dtypes"][1]) else: - print('reading from tch', key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + print('reading from tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') return get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') def show_content_raw( @@ -112,7 +112,7 @@ def show_content_raw( if obj == 'tree': _map_obj = self.config['objects']['tree.tch'] - print('reading from tch', key, _map_obj['shards'], _map_obj['sharding_bits']) + print('reading from tch', key, _map_obj['sharding_bits']) v = get_from_tch(key, shards=_map_obj['shards'], sharding_bits=_map_obj['sharding_bits'], @@ -122,7 +122,7 @@ def show_content_raw( elif obj == 'commit': _map_obj = self.config['objects']['commit.tch'] - print('reading from tch', key, _map_obj['shards'], _map_obj['sharding_bits']) + print('reading from tch', key, _map_obj['sharding_bits']) v = get_from_tch(key, shards=_map_obj['shards'], sharding_bits=_map_obj['sharding_bits'], @@ -132,7 +132,7 @@ def show_content_raw( elif obj == 'blob': _map_obj = self.config['objects']['sha1.blob.tch'] - print('reading from tch', key, _map_obj['shards'], _map_obj['sharding_bits']) + print('reading from tch', key, _map_obj['sharding_bits']) v = get_from_tch(key, shards=_map_obj['shards'], sharding_bits=_map_obj['sharding_bits'], @@ -180,7 +180,7 @@ def copy_values(self, map_name, key): return write_large(_map["larges"][_hex], key, value, _map["dtypes"][1]) else: # use fnv hash as shading idx if key is not a git sha - print('writing to tch', key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + print('writing to tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') return write_to_tch(key, value, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') def copy_content(self, obj: str, key: Union[bytes, str]): @@ -189,24 +189,25 @@ def copy_content(self, obj: str, key: Union[bytes, str]): if obj == 'tree': _map_obj = self.config2['objects']['tree.tch'] - print('writing to tch', key, _map_obj["shards"], _map_obj["sharding_bits"]) - write_to_tch(key.encode(), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + print('writing to tch', key, _map_obj["sharding_bits"]) + write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) elif obj == 'commit': _map_obj = self.config2['objects']['commit.tch'] - print('writing to tch', key, _map_obj["shards"], _map_obj["sharding_bits"]) - write_to_tch(key.encode(), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + print('writing to tch', key ,_map_obj["sharding_bits"]) + write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) elif obj == 'blob': _map_obj = self.config2['objects']['sha1.blob.tch'] _idx, _v = value offset, length = unber(_idx) _idx = ber(0, length) - print('writing to tch', key, _map_obj["shards"], _map_obj["sharding_bits"]) - write_to_tch(key.encode(), _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + print('writing to tch', key, _map_obj["sharding_bits"]) + write_to_tch(bytes.fromhex(key), _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) _map_obj = self.config2['objects']['blob.bin'] - print('writing to file', _map_obj['shards'][0], length) - with open(_map_obj['shards'][0], "ab") as f: + shard = get_shard(bytes.fromhex(key), _map_obj['sharding_bits'], use_fnv_keys=False) + print('writing to file', _map_obj['shards'][shard], length) + with open(_map_obj['shards'][shard], "ab") as f: f.write(_v) else: @@ -214,6 +215,13 @@ def copy_content(self, obj: str, key: Union[bytes, str]): if __name__ == '__main__': + import glob + import os + + for f in glob.glob('./tests/fixtures/*.tch*') + glob.glob('./tests/fixtures/*.bin'): + print('removing', f) + os.remove(f) + cp = WocMapsCopier('./wocprofile.json', './tests/test_profile.json') cp.copy_values('c2p', 'e4af89166a17785c1d741b8b1d5775f3223f510f') cp.copy_values('c2dat', 'e4af89166a17785c1d741b8b1d5775f3223f510f') diff --git a/tests/fixtures/sha1.blob.tch b/tests/fixtures/sha1.blob.tch index 9512afedc5d8eba17c8266b5abb2dd9d05e6247f..b2366e0c4026a657da80b71725895a1432a17887 100644 GIT binary patch delta 151 zcmX@GSYg3pg$Wjn3mPq3Eg3f^6dP}!!Nw$^-k8vu0OWRbF^acu)MWxO&ozPbJ14pxkN@wO$#5tTrUXczFoJPF>fKg-DEzo1 Z^5}k7b>l-3HU&3zE}UR!ONJ={(g5xLE&Kog delta 186 zcmYkzAr8VY6oBEjBya`f9LRR<+xl*Rz*Hk>_eM`aLMnzN9D!sO+h7;eZo)NK!UVti z&G+bwp)c;14+%Tu8O3q=dTO!Wh;>S?b38k7(8+h6XD{~CWzRq7%XnjRE4E!oh^I;$ z3Wlt<(_tV`7%ieQKsCe|jjE8n-K@slzc*C~QPwJ|#sU&F(Lh;iO(j@OwQRAZR+42` H`Z3PF8MH1i diff --git a/tests/fixtures/tree_0.tch b/tests/fixtures/tree_1.tch similarity index 99% rename from tests/fixtures/tree_0.tch rename to tests/fixtures/tree_1.tch index 2e9f90117d1d94b250e8df63a482804d7ccbf96d..0129d7c7da55503186918f84100d5dc5657416c1 100644 GIT binary patch delta 83 zcmcbxSYg9rg$Wjn8yYQJEg833GU-2VuQ|!Kz2+qQ5%LZdc-yAv*ey>QYPQ#6djsgCdlCj06!TZ0ssI2 delta 120 zcmdn6SmDBAg$Wjn7aA>FEg833GU-2VOlVDD+?v3|0c34WVB}$L&v?wVJ>xO+5qGl_ zKN+Bak3qvH%`nN#EG0QP(Ztdq$u!x-#MCq~&DhW~DcRD@Fwxi~&CD{{+$h;-dXgZA K9}i3?hz0I diff --git a/tests/test_local.py b/tests/test_local.py new file mode 100644 index 0000000..3b42444 --- /dev/null +++ b/tests/test_local.py @@ -0,0 +1,91 @@ +import pytest +import os + +# Import the TCHashDB class +from woc.local import WocMapsLocal + +@pytest.fixture +def woc(): + _test_pr = os.path.join(os.path.dirname(__file__), 'test_profile.json') + woc = WocMapsLocal(_test_pr) + yield woc + +def test_c2p(woc): + res = woc.get_values('c2p', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + assert res[0] == 'W4D3_news' + +def test_c2dat(woc): + res = woc.get_values('c2dat', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + assert res[0] == '1410029988' + +def test_b2tac(woc): + res = woc.get_values('b2tac', '05fe634ca4c8386349ac519f899145c75fff4169') + assert res[0] == ('1410029988', 'Audris Mockus ', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + +def test_p2a(woc): + res = woc.get_values('p2a', 'ArtiiQ_PocketMine-MP') + assert res[0] == '0929hitoshi ' + +def test_b2c(woc): + res = woc.get_values('b2c', '05fe634ca4c8386349ac519f899145c75fff4169') + assert res[0] == 'e4af89166a17785c1d741b8b1d5775f3223f510f' + +def test_b2c_large(woc): + res = woc.get_values('b2c', '3f2eca18f1bc0f3117748e2cea9251e5182db2f7') + assert res[0] == '00003a69db53b45a67f76632f33a93691da77197' + +def test_a2c(woc): + res = woc.get_values('a2c', 'Audris Mockus ') + assert res[0] == '001ec7302de3b07f32669a1f1faed74585c8a8dc' + +def test_c2cc_null_filename(woc): # file name is null + with pytest.raises(AssertionError): + woc.get_values('c2cc', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + +def test_a2f(woc): + res = woc.get_values('a2f', 'Audris Mockus ') + assert res[0] == '.#analyze.sh' + +def test_c2f(woc): + res = woc.get_values('c2f', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + assert res[0] == 'README.md' + +def test_c2b(woc): + res = woc.get_values('c2b', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + assert res[0] == '05fe634ca4c8386349ac519f899145c75fff4169' + +def test_p2c(woc): + res = woc.get_values('p2c', 'ArtiiQ_PocketMine-MP') + assert res[0] == '0000000bab11354f9a759332065be5f066c3398f' + +def test_f2a(woc): + res = woc.get_values('f2a', 'youtube-statistics-analysis.pdf') + assert res[0] == 'Audris Mockus ' + +def test_b2f(woc): + res = woc.get_values('b2f', '05fe634ca4c8386349ac519f899145c75fff4169') + assert res[0] == 'README.md' + +def test_c2r(woc): + res = woc.get_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + assert res[0] == '9531fc286ef1f4753ca4be9a3bf76274b929cdeb' + +def test_b2fa(woc): + res = woc.get_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169') + assert res[0] == '1410029988' + +def test_tree(woc): + res = woc.show_content('tree', 'f1b66dcca490b5c4455af319bc961a34f69c72c2') + assert len(res) == 2 + +def test_commit(woc): + res = woc.show_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + assert len(res) == 222 + +def test_blob_1(woc): + res = woc.show_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') + assert len(res) == 14194 + +def test_blob_2(woc): + res = woc.show_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') + assert len(res) == 1236 \ No newline at end of file From cabcaa9b7fb002ef9f6aa771fd998a3087687d3a Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 5 Jun 2024 16:14:00 +0800 Subject: [PATCH 12/38] build: toolchain upgrade add poetry for dependencies, pytest for tests, ruff as linter --- poetry.lock | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 39 ++++++++--- setup.py | 5 +- 3 files changed, 205 insertions(+), 12 deletions(-) create mode 100644 poetry.lock diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..57d1520 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,173 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cython" +version = "0.29.37" +description = "The Cython compiler for writing C extensions for the Python language." +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "Cython-0.29.37-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2d621fe4cb50007446742134a890500b34e3f50abaf7993baaca02634af7e15"}, + {file = "Cython-0.29.37-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d94caf90ae9cb56116ca6d54cdcbccd3c4df6b0cb7233922b2233ee7fe81d05b"}, + {file = "Cython-0.29.37-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:852cd4378cbc9ade02f53709107ff9fdad55019a3a636e8a27663ba6cfce10b6"}, + {file = "Cython-0.29.37-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bbce388431a2608a81c8ab13cb14c50611473843ca766031b8b24bb1723faf79"}, + {file = "Cython-0.29.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4658499a41255431f6bbdca7e634e9c8d3a4c190bf24b4aa1646dac751d3da4d"}, + {file = "Cython-0.29.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:12192ab269e7185720f2d2f8894587bf1da4276db1b9b869e4622a093f18cae6"}, + {file = "Cython-0.29.37-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:9450e0766ab65947f8a2a36f9e59079fc879c3807ec936c61725a48c97741a52"}, + {file = "Cython-0.29.37-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:177481b0a7e003e5c49e2bf0dda1d6fe610c239f17642a5da9f18c2ad0c5f6b6"}, + {file = "Cython-0.29.37-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:b048354fd380278f2fa096e7526973beb6e0491a9d44d7e4e29df52612d25776"}, + {file = "Cython-0.29.37-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ea6d208be1906c5df25b674777d5905c6d8e9ef0b201b830849e0729ba08caba"}, + {file = "Cython-0.29.37-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:af03854571738307a5f30cc6b724081d72db12f907699e7fdfc04c12c839158e"}, + {file = "Cython-0.29.37-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c33508ede9172a6f6f99d5a6dadc7fee23c840423b411ef8b5a403c04e530297"}, + {file = "Cython-0.29.37-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8af5975ecfae254d8c0051204fca995dda8f93cf9f0bbf7571e3cda2b0cef4d"}, + {file = "Cython-0.29.37-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29415d8eb2fdc1ea518ca4810c50a2d062b387d4c9fbcfb3352346e93db22c6d"}, + {file = "Cython-0.29.37-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe0eaf6b1e9ee97c5ee7bfc943f00e36cf59d929db16886cb018352bff8208da"}, + {file = "Cython-0.29.37-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cc1b9ce2b73b9ee8c305e06173b35c7c202d4b82d084a0cd73dcedfd6d310aec"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2618af0b8df26d32ee4e8858d4ad8167546596762620aeade84954ae37194a0e"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ac910a28a2fd3d280faf3077b6fe63b97a4b93994ff05647581846f0e4b2f8d1"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:8bf38373773f967cfd793997a6fb96cf972d41a9fce987ace5767349d6f15572"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6cddb567dadb3aa3e280a8a35e5126030915ea744c2812206e9c194b8881475d"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:79ecfc48694e156402c05561e0adb0e25a6e9d35ac0b41693733a08219d38c58"}, + {file = "Cython-0.29.37-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:9a455347e20ddfad0c5dfee32a3e855ee96811269e5fd86be622ddc4cb326404"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:fa5b6a0f69bf1823c9fd038fa77a2568b78fda2de045a95b48a71dee4d0d578f"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a6164a05440dcd9daa760c6488bc91bdac1380c7b4b3aca38cf307ba66042d54"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:562f8f911dbd6f1a1b9be8f6cba097125700355688f613994ccd4406f220557a"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8c39c2f5a0fe29bb01de9b1fb449bf65bed6f192317c677f181732791c63fe28"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0a0a6d5972bb3b8c7363cf19a42a988bb0c0bb5ebd9c736c84eca85113ccfdbe"}, + {file = "Cython-0.29.37-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b82584836e9e7c0d6effee976595e5cd7fa88dbef3e96e900187983c1d4637d1"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:b6c48f1032b379135a5b4a31976d6c468e02490688acf9254c6c8ed27bd4cbd4"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3f87bef1808d255cf13be378c7ad27ae7c6db6df7732217d32428d1daf4109be"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:9e68bafeeb97d5a403fb1f7700bd4a55a1f8989824c323ae02ae8a4fcd88f6a1"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e14cd44c830e53cf9d7269c87a6bcc638bb065ec07e24990e338162c7001d3c3"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0544f7a3e4437b89b356baa15387494c18214e03f2ffaddada5a2c71c3dfd24b"}, + {file = "Cython-0.29.37-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2de3e729d25f041036e81e2f15683dd129f977dfb5b06267e30e8d7acec43225"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2ad634dc77a6a74022881826099eccac19c9b79153942cc82e754ffac2bec116"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e841a8b4f9ceefb2916e32dac4f28a895cd519e8ece71505144da1ee355c548a"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:6c672089fba6a8f6690b8d7924a58c04477771401ad101d53171a13405ee12cb"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0301d4739c6894e012f1d410052082fdda9e63888c815d9e23e0f7f82fff7d79"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:af8e7b4397620e2d18259a11f3bfa026eff9846657e397d02616962dd5dd035a"}, + {file = "Cython-0.29.37-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b225d5e2091c224d4ab328165fef224ba3919b3ed44bd9b3241416f523b4d51a"}, + {file = "Cython-0.29.37-py2.py3-none-any.whl", hash = "sha256:95f1d6a83ef2729e67b3fa7318c829ce5b07ac64c084cd6af11c228e0364662c"}, + {file = "Cython-0.29.37.tar.gz", hash = "sha256:f813d4a6dd94adee5d4ff266191d1d95bf6d4164a4facc535422c021b2504cfb"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "packaging" +version = "24.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pytest" +version = "8.2.2" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"}, + {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "python-lzf" +version = "0.2.4" +description = "C Extension for liblzf" +optional = false +python-versions = "*" +files = [ + {file = "python-lzf-0.2.4.tar.gz", hash = "sha256:d1420f1544e612ef1bb41ce0f1d14c2964b3444612f1468f85a886caff3615d1"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "93df5e9b8466f61c68b0ca3cfc52e28ee51bb427a47f19a55ab3dfffa23979eb" diff --git a/pyproject.toml b/pyproject.toml index ec663da..18e5b79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,36 @@ -[build-system] -requires = ["setuptools>=18.0", "wheel", "Cython"] +[tool.poetry] +name = "python-woc" +version = "0.1.0" +description = "Python interface for World of Code" +authors = ["Runzhi He ", "Marat "] +license = "GPL-3.0" +readme = "README.md" +packages = [ + { include = "woc" } +] +include = [ + { path = "woc/**/*.so", format = "wheel" }, + { path = "lib/*", format = "sdist" } +] + +[tool.poetry.build] +script = "setup.py" +generate-setup-file = false + +[tool.poetry.dependencies] +python = "^3.8" +python-lzf = "^0.2.4" +chardet = "^5.2.0" -[tool.semantic_release] -version_variable = ['oscar.pyx:__version__', 'docs/conf.py:release'] -# wheel build is performed by manylinux, so just skip it -build_command = '' -# remove_dist deletes all pre-existing files in dist/, including built by manylinux -remove_dist = false +[tool.poetry.group.dev.dependencies] +cython = "^0.29.0" +pytest = "^8.2.2" + +[build-system] +requires = ["poetry-core", "Cython>=0.29.0,<1.0.0", "setuptools>=42"] +build-backend = "poetry.core.masonry.api" [tool.pytest.ini_options] -minversion = "6.0" addopts = "-ra -q" testpaths = [ "tests", diff --git a/setup.py b/setup.py index f402482..c171a52 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,3 @@ -# distutils: define_macros=CYTHON_TRACE_NOGIL=1 - import os from setuptools import setup, Extension, find_packages from Cython.Build import cythonize @@ -45,8 +43,9 @@ setup( name="python-woc", - ext_modules=cythonize(ext_modules, emit_linenums=True,), + ext_modules=cythonize(ext_modules, emit_linenums=True), packages=PACKAGES, package_data={"": ["*.pyx", "*.pxd", "*.pxi"]}, include_package_data=True, + script_args=['build_ext', '--inplace'], ) \ No newline at end of file From eeb6349595237192a270714b56e05b615b4f2e02 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 5 Jun 2024 22:53:24 +0800 Subject: [PATCH 13/38] fix: test_tch with poetry --- tests/test_tch.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_tch.py b/tests/test_tch.py index d6b9cdf..6d89eaa 100644 --- a/tests/test_tch.py +++ b/tests/test_tch.py @@ -9,8 +9,6 @@ def db(tmp_path): path = tmp_path / "test_db.tch" db = TCHashDB(path=bytes(str(path), 'utf-8')) yield db - db.drop() - db.close() def test_put_and_get(db): key = b'key1' From d9fc436636dacd7530e2a8a6da563591f9b91cd9 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 6 Jun 2024 00:36:06 +0800 Subject: [PATCH 14/38] ci: add gh actions unit tests --- .../{release.yml => release.yml.bak} | 0 .github/workflows/test.yml | 38 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) rename .github/workflows/{release.yml => release.yml.bak} (100%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml.bak similarity index 100% rename from .github/workflows/release.yml rename to .github/workflows/release.yml.bak diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 59ffca2..6d7bda6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,33 +5,35 @@ on: [push, pull_request] jobs: test: name: Python ${{ matrix.python-version }} tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.8] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - - uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + - name: Install Poetry + run: | + PIPX_BIN_DIR=/usr/local/bin pipx install poetry + + - name: Set up Python + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + cache: poetry + cache-dependency-path: poetry.lock - - name: Cache pip - uses: actions/cache@v1 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }} - restore-keys: | - ${{ runner.os }}-pip- + - name: Set Poetry environment + run: | + poetry env use ${{ matrix.python-version }} - - name: Install dependencies (Python ${{ matrix.python-version }}) + - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install typing cython setuptools>=18.0 - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + poetry install - - name: Run tests on Python ${{ matrix.python-version }} - run: make test_local + - name: Run tests + run: | + poetry run pytest -v From b70703cd9f0a08db05a4abdc6391682ac0a22e0b Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 6 Jun 2024 03:38:21 +0800 Subject: [PATCH 15/38] test: add coverage --- poetry.lock | 87 +++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 11 ++++++- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 57d1520..d5e2610 100644 --- a/poetry.lock +++ b/poetry.lock @@ -22,6 +22,73 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coverage" +version = "7.5.3" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45"}, + {file = "coverage-7.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc"}, + {file = "coverage-7.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d"}, + {file = "coverage-7.5.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c"}, + {file = "coverage-7.5.3-cp310-cp310-win32.whl", hash = "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84"}, + {file = "coverage-7.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974"}, + {file = "coverage-7.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807"}, + {file = "coverage-7.5.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8"}, + {file = "coverage-7.5.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614"}, + {file = "coverage-7.5.3-cp311-cp311-win32.whl", hash = "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9"}, + {file = "coverage-7.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8"}, + {file = "coverage-7.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db"}, + {file = "coverage-7.5.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35"}, + {file = "coverage-7.5.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84"}, + {file = "coverage-7.5.3-cp312-cp312-win32.whl", hash = "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08"}, + {file = "coverage-7.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb"}, + {file = "coverage-7.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb"}, + {file = "coverage-7.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98"}, + {file = "coverage-7.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce"}, + {file = "coverage-7.5.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0"}, + {file = "coverage-7.5.3-cp38-cp38-win32.whl", hash = "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485"}, + {file = "coverage-7.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85"}, + {file = "coverage-7.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341"}, + {file = "coverage-7.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303"}, + {file = "coverage-7.5.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd"}, + {file = "coverage-7.5.3-cp39-cp39-win32.whl", hash = "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d"}, + {file = "coverage-7.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0"}, + {file = "coverage-7.5.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884"}, + {file = "coverage-7.5.3.tar.gz", hash = "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + [[package]] name = "cython" version = "0.29.37" @@ -146,6 +213,24 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + [[package]] name = "python-lzf" version = "0.2.4" @@ -170,4 +255,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "93df5e9b8466f61c68b0ca3cfc52e28ee51bb427a47f19a55ab3dfffa23979eb" +content-hash = "7e66d6888dd470fa3ba1d16024f43f6553410c3e8182d089e4c088e0c03d9e5c" diff --git a/pyproject.toml b/pyproject.toml index 18e5b79..63700c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,8 @@ chardet = "^5.2.0" [tool.poetry.group.dev.dependencies] cython = "^0.29.0" pytest = "^8.2.2" +pytest-cov = "^5.0.0" +coverage = {extras = ["toml"], version = "^7.5.3"} [build-system] requires = ["poetry-core", "Cython>=0.29.0,<1.0.0", "setuptools>=42"] @@ -34,4 +36,11 @@ build-backend = "poetry.core.masonry.api" addopts = "-ra -q" testpaths = [ "tests", -] \ No newline at end of file +] + +[tool.coverage.report] +show_missing = true +omit = [ "tests/*" ] + +[tool.coverage.run] +plugins = [ "Cython.Coverage" ] \ No newline at end of file From 4862c2dd38eb280d19fb950d1f5d173be6de8003 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 6 Jun 2024 03:39:17 +0800 Subject: [PATCH 16/38] fix: pyi compatibility with py38 --- woc/local.pyi | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/woc/local.pyi b/woc/local.pyi index ca0c456..615c9ad 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -1,4 +1,4 @@ -from typing import Iterable, Union, Tuple, List +from typing import Iterable, Union, Tuple, List, Dict from .base import WocMapsBase, WocObjectsWithContent @@ -13,14 +13,14 @@ class WocMapsLocal(WocMapsBase): self, map_name: str, key: Union[bytes, str], - ) -> (list[str] | tuple[str, str, str] | list[tuple[str, str, str]]): + ) -> Union[List[str], Tuple[str, str, str], List[Tuple[str, str, str]]]: ... def show_content( self, obj: WocObjectsWithContent, key: Union[bytes, str], - ) -> (list[tuple[str, str, str]] | str): + ) -> Union[List[Tuple[str, str, str]], str]: ... # Make utility functions accessible from Python -> easier testing @@ -29,4 +29,5 @@ def unber(buf: bytes) -> bytes: ... def lzf_length(raw_data: bytes) -> Tuple[int, int]: ... def get_tch(path: str): ... def get_shard(key: bytes, sharding_bits: int, use_fnv_keys: bool) -> int: ... -def get_from_tch(key: bytes, shards: List[bytes], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... \ No newline at end of file +def get_from_tch(key: bytes, shards: List[bytes], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... +def parse_commit(cmt: str) -> Dict[str, str]: ... \ No newline at end of file From e76a6fc35f6d39d2a0d0e397eebbb7ba13ad67da Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 6 Jun 2024 03:40:50 +0800 Subject: [PATCH 17/38] refactor: extract get_pos & parse_commit --- woc/base.py | 13 ++++++--- woc/local.pyx | 78 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/woc/base.py b/woc/base.py index 663e2dd..ae82246 100644 --- a/woc/base.py +++ b/woc/base.py @@ -1,4 +1,4 @@ -from typing import Union, Literal +from typing import Union, Literal, List, Tuple, Dict WocObjectsWithContent = Literal['tree', 'blob', 'commit', 'tkns', 'tag', 'bdiff'] WocSupportedProfileVersions = (1, ) @@ -12,15 +12,20 @@ def get_values( self, map_name: str, key: Union[bytes, str], - ): + ) -> Union[List[str], Tuple[str, str, str], List[Tuple[str, str, str]]]: raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") def show_content( self, obj: WocObjectsWithContent, key: Union[bytes, str], - ): + ) -> Union[List[Tuple[str, str, str]], Dict[str, str], str]: raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") - + def get_pos( + self, + obj: str, + key: bytes, + ) -> Tuple[int, int]: + raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") \ No newline at end of file diff --git a/woc/local.pyx b/woc/local.pyx index 2ce2b22..0bf7ed3 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -280,6 +280,49 @@ def decode_tree( return _out_buf +def parse_commit(cmt: str) -> Dict[str, str]: + """ + Parse commit objects into a dictionary + """ + lines = cmt.split('\n') + tree_sha = lines[0][5:] + + if lines[1].startswith('parent'): + parent_sha = lines[1][7:] + else: + # insert a dummy line + lines.insert(1, '') + parent_sha = '' + + author_idx = lines[2].find('>') + author = lines[2][7:author_idx+1] + author_time = lines[2][author_idx+2:] + author_timestamp = author_time.split(' ')[0] + author_timezone = author_time.split(' ')[1] + + committer_idx = lines[3].find('>') + committer = lines[3][10:committer_idx+1] + committer_time = lines[3][committer_idx+2:] + committer_timestamp = committer_time.split(' ')[0] + committer_timezone = committer_time.split(' ')[1] + + commit_msg = '\\n'.join(lines[5:]) + if commit_msg.endswith('\\n'): # strip + commit_msg = commit_msg[:-2] + + return dict( + tree=tree_sha, + parent=parent_sha, + author=author, + author_timestamp=author_timestamp, + author_timezone=author_timezone, + committer=committer, + committer_timestamp=committer_timestamp, + committer_timezone=committer_timezone, + message=commit_msg, + ) + + def read_large(path: str, dtype: str) -> bytes: """Read a *.large.* and return its content""" if dtype == 'h': @@ -382,6 +425,26 @@ class WocMapsLocal(WocMapsBase): logger.debug(f"decode value: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret + def get_pos( + self, + obj: str, + key: bytes, + ) -> Tuple[int, int]: + """ + Get offset and length of a stacked binary object, currently only support blob. + Move out this part because it's much cheaper than measuring the whole object. + """ + if obj == 'blob': + _map_obj = self.config['objects']['sha1.blob.tch'] + v = get_from_tch(key, + shards=_map_obj['shards'], + sharding_bits=_map_obj['sharding_bits'], + use_fnv_keys=False + ) + return unber(v) + else: + raise ValueError(f'Unsupported object type: {obj}, expected blob') + def show_content( self, obj: str, @@ -424,17 +487,16 @@ class WocMapsLocal(WocMapsBase): logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") return decode_str(decomp_or_raw(v)) + # # Don't decode commit here to be compatible with Perl API + # _ret = decode_commit(decomp_or_raw(v)) + # logger.debug(f"decode commit: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") + # return _ret + elif obj == 'blob': - _map_obj = self.config['objects']['sha1.blob.tch'] - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + offset, length = self.get_pos('blob', key) + logger.debug(f"get from tch: offset={offset} len={length} {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - offset, length = unber(v) _map_obj = self.config['objects']['blob.bin'] shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) From df5462df7d87295db335397bcb5a8bddda105259 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 6 Jun 2024 03:41:45 +0800 Subject: [PATCH 18/38] feat: add profile option to cli & add tests Now we can test cli in ci with a profile for fixtures --- tests/test_cli.py | 125 ++++++++++++++++++++++++++++++++++++++++++++ woc/get_values.py | 14 ++--- woc/show_content.py | 54 +++++++++---------- 3 files changed, 156 insertions(+), 37 deletions(-) create mode 100644 tests/test_cli.py diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..9021df9 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,125 @@ +import subprocess + +def run_show_content(commit_hash, *args): + result = subprocess.run( + ['python3', '-m', 'woc.show_content', *args, '-p', './tests/test_profile.json'], + capture_output=True, + text=True, + input=commit_hash + ) + return result.returncode, result.stdout.strip(), result.stderr.strip() + +def run_get_values(input_str, *args): + result = subprocess.run( + ['python3', '-m', 'woc.get_values', *args, '-p', './tests/test_profile.json'], + capture_output=True, + text=True, + input=input_str + ) + return result.returncode, result.stdout.strip(), result.stderr.strip() + +def test_cli_commit(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;f1b66dcca490b5c4455af319bc961a34f69c72c2;c19ff598808b181f1ab2383ff0214520cb3ec659;Audris Mockus ;Audris Mockus ;1410029988;1410029988' + assert run_show_content(commit_hash, 'commit')[1] == expected_output + +def test_cli_commit_1(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;1410029988;Audris Mockus ' + assert run_show_content(commit_hash, 'commit', '1')[1] == expected_output + +def test_cli_commit_2(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;Audris Mockus ;1410029988;-0400;News for Sep 5' + print(run_show_content(commit_hash, 'commit', '2')) + assert run_show_content(commit_hash, 'commit', '2')[1] == expected_output + +def test_cli_commit_3(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = """tree f1b66dcca490b5c4455af319bc961a34f69c72c2 +parent c19ff598808b181f1ab2383ff0214520cb3ec659 +author Audris Mockus 1410029988 -0400 +committer Audris Mockus 1410029988 -0400 + +News for Sep 5""" + assert run_show_content(commit_hash, 'commit', '3')[1] == expected_output + +def test_cli_commit_4(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;Audris Mockus ' + assert run_show_content(commit_hash, 'commit', '4')[1] == expected_output + +def test_cli_commit_5(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;c19ff598808b181f1ab2383ff0214520cb3ec659' + assert run_show_content(commit_hash, 'commit', '5')[1] == expected_output + +def test_cli_commit_6(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output_end = 'c19ff598808b181f1ab2383ff0214520cb3ec659' + assert run_show_content(commit_hash, 'commit', '6')[1].endswith(expected_output_end), run_show_content(commit_hash, 'commit', '6') + +def test_cli_commit_7(): + commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output_end = 'QHV0ay5lZHU+IDE0MTAwMjk5ODggLTA0MDAKCk5ld3MgZm9yIFNlcCA1\\n' + assert run_show_content(commit_hash, 'commit', '7')[1].endswith(expected_output_end) + +def test_cli_tree(): + tree_hash = 'f1b66dcca490b5c4455af319bc961a34f69c72c2' + expected_output = '100644;05fe634ca4c8386349ac519f899145c75fff4169;README.md\n100644;dfcd0359bfb5140b096f69d5fad3c7066f101389;course.pdf' + assert run_show_content(tree_hash, 'tree')[1] == expected_output + +def test_cli_blob(): + blob_hash = '05fe634ca4c8386349ac519f899145c75fff4169' + expected_output_start = '# Syllabus for "Fundamentals of Digital Archeology"\n\n## News\n\n* Assignment1 due Monday Sep 8 before 2:30PM' + assert run_show_content(blob_hash, 'blob')[1].startswith(expected_output_start), run_show_content(blob_hash, 'blob') + +def test_cli_a2c(): + input_str = "Audris Mockus " + expected_output_start = 'Audris Mockus ;001ec7302de3b07f32669a1f1faed74585c8a8dc' + print(run_get_values(input_str, 'a2c')) + assert run_get_values(input_str, 'a2c')[1].startswith(expected_output_start), run_get_values(input_str, 'a2c') + +def test_cli_a2f(): + input_str = "Audris Mockus " + expected_output_start = 'Audris Mockus ;.#analyze.sh;.README.md.swp;.Rhistory;.bowerrc' + assert run_get_values(input_str, 'a2f')[1].startswith(expected_output_start), run_get_values(input_str, 'a2f') + +def test_cli_b2c(): + input_str = '05fe634ca4c8386349ac519f899145c75fff4169' + expected_output = '05fe634ca4c8386349ac519f899145c75fff4169;e4af89166a17785c1d741b8b1d5775f3223f510f' + assert run_get_values(input_str, 'b2c')[1] == expected_output + +def test_cli_c2b(): + input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;05fe634ca4c8386349ac519f899145c75fff4169' + assert run_get_values(input_str, 'c2b')[1] == expected_output + +def test_cli_c2cc(): # expect error + input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + assert run_get_values(input_str, 'c2cc')[2].endswith("shard 0 not found at None"), run_get_values(input_str, 'c2cc') + +def test_cli_c2f(): + input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;README.md' + assert run_get_values(input_str, 'c2f')[1] == expected_output + +def test_cli_c2p(): + input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output_start = 'e4af89166a17785c1d741b8b1d5775f3223f510f;W4D3_news;chumekaboom_news' + assert run_get_values(input_str, 'c2p')[1].startswith(expected_output_start), run_get_values(input_str, 'c2p') + +def test_cli_c2r(): + input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;9531fc286ef1f4753ca4be9a3bf76274b929cdeb;27' + assert run_get_values(input_str, 'c2r')[1] == expected_output + +def test_cli_p2a(): + input_str = 'ArtiiQ_PocketMine-MP' + expected_output_start = 'ArtiiQ_PocketMine-MP;0929hitoshi ;' + assert run_get_values(input_str, 'p2a')[1].startswith(expected_output_start), run_get_values(input_str, 'p2a') + +def test_cli_p2c(): + input_str = 'ArtiiQ_PocketMine-MP' + expected_output_start = 'ArtiiQ_PocketMine-MP;0000000bab11354f9a759332065be5f066c3398f' + assert run_get_values(input_str, 'p2c')[1].startswith(expected_output_start), run_get_values(input_str, 'p2c') \ No newline at end of file diff --git a/woc/get_values.py b/woc/get_values.py index 77c481d..c594e00 100644 --- a/woc/get_values.py +++ b/woc/get_values.py @@ -18,19 +18,15 @@ def format_map(key: str, map_objs: Iterable) -> str: parser = argparse.ArgumentParser(description='Get record of various maps') parser.add_argument('type', type=str, help='The type of the object') - # key is taken from stdin - parser.add_argument('key', type=str, help='The key of the object', nargs='?') + parser.add_argument('-p', '--profile', type=str, help='The path to the profile file', default=None) args = parser.parse_args() - if not args.key: - args.key = sys.stdin.readline() - args.key = args.key.strip() - - woc = WocMapsLocal() + + woc = WocMapsLocal(args.profile) for line in sys.stdin: try: key = line.strip() - obj = woc.get_values(args.type, args.key) - print(format_map(args.key, obj)) + obj = woc.get_values(args.type, key) + print(format_map(key, obj)) except BrokenPipeError: # ref: https://docs.python.org/3/library/signal.html#note-on-sigpipe devnull = os.open(os.devnull, os.O_WRONLY) diff --git a/woc/show_content.py b/woc/show_content.py index 34221b3..25cebbc 100644 --- a/woc/show_content.py +++ b/woc/show_content.py @@ -4,7 +4,7 @@ # @authors: Runzhi He # @date: 2024-05-27 -from .local import WocMapsLocal +from .local import WocMapsLocal, parse_commit def format_tree(tree_objs: list) -> str: _out = '' @@ -22,32 +22,29 @@ def format_commit(sha: str, cmt: str, format: int = 0): # mock linux's base64, add newline every 76 characters _b64 = '\\n'.join([_b64[i:i+76] for i in range(0, len(_b64), 76)]) + '\\n' return sha + ';' + _b64 - - lines = cmt.split('\n') - tree_sha = lines[0][5:] - - if lines[1].startswith('parent'): - parent_sha = lines[1][7:] - else: - # insert a dummy line - lines.insert(1, '') - parent_sha = '' - - author_idx = lines[2].find('>') - author = lines[2][7:author_idx+1] - author_time = lines[2][author_idx+2:] - author_timestamp = author_time.split(' ')[0] - author_timezone = author_time.split(' ')[1] - - committer_idx = lines[3].find('>') - committer = lines[3][10:committer_idx+1] - committer_time = lines[3][committer_idx+2:] - committer_timestamp = committer_time.split(' ')[0] - committer_timezone = committer_time.split(' ')[1] - - commit_msg = '\\n'.join(lines[5:]) - if commit_msg.endswith('\\n'): # strip - commit_msg = commit_msg[:-2] + + d = parse_commit(cmt) + # d = dict( + # tree=tree_sha, + # parent=parent_sha, + # author=author, + # author_timestamp=author_timestamp, + # author_timezone=author_timezone, + # committer=committer, + # committer_timestamp=committer_timestamp, + # committer_timezone=committer_timezone, + # message=commit_msg, + # ) + tree_sha = d['tree'] + parent_sha = d['parent'] + author = d['author'] + author_timestamp = d['author_timestamp'] + author_timezone = d['author_timezone'] + committer = d['committer'] + committer_timestamp = d['committer_timestamp'] + committer_timezone = d['committer_timezone'] + commit_msg = d['message'] + if format == 0: # commit SHA;tree SHA;parent commit SHA;author;committer;author timestamp;commit timestamp return ';'.join([sha, tree_sha, parent_sha, author, committer, author_timestamp, committer_timestamp]) @@ -86,9 +83,10 @@ def format_commit(sha: str, cmt: str, format: int = 0): parser = argparse.ArgumentParser(description='See the Content of Git Object', usage='echo | %(prog)s type (format)') parser.add_argument('type', type=str, help='The type of the object') parser.add_argument('format', type=int, help='The format of the object', default=0, nargs='?') + parser.add_argument('-p', '--profile', type=str, help='The path to the profile file', default=None) args = parser.parse_args() - woc = WocMapsLocal() + woc = WocMapsLocal(args.profile) for line in sys.stdin: try: key = line.strip() From edb8ebfe9d0e0f2cf35ffd4a8ec0e85d42b306cd Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 6 Jun 2024 22:32:46 +0800 Subject: [PATCH 19/38] refactor: extract apis & rework parsers in cython --- tests/fixtures/create_fixtures.py | 98 +---- tests/fixtures/create_fixtures.py.bak | 244 ++++++++++++ tests/test_local.py | 2 +- woc/base.py | 36 +- woc/local.pyi | 38 +- woc/local.pyx | 514 +++++++++++++++++++------- woc/show_content.py | 42 +-- woc/tch.pyx | 14 +- 8 files changed, 702 insertions(+), 286 deletions(-) create mode 100644 tests/fixtures/create_fixtures.py.bak diff --git a/tests/fixtures/create_fixtures.py b/tests/fixtures/create_fixtures.py index c492fba..cba5986 100644 --- a/tests/fixtures/create_fixtures.py +++ b/tests/fixtures/create_fixtures.py @@ -51,7 +51,6 @@ def write_to_tch(key: bytes, value: bytes, shards: List[str], sharding_bits: int _path = shards[shard] db = TCHashDB(_path.encode()) db[key] = value - db.close() def write_large(path: str, key: bytes, value: bytes, dtype: str): if dtype == 'h': @@ -75,86 +74,9 @@ def __init__(self, config1, config2): with open(config2) as f: self.config2 = json.load(f) - def get_values_raw(self, map_name, key): - if map_name in self.config["maps"]: - _map = self.config["maps"][map_name][0] - elif map_name in self.config["objects"]: - _map = self.config["objects"][map_name] - else: - raise KeyError(f'Invalid map name: {map_name}, ' - f'expect one of {", ".join(self.config["maps"].keys())}') - - if _map["dtypes"][0] == 'h': - if isinstance(key, str): - _hex = key - key = bytes.fromhex(key) - else: - _hex = bytes(key).hex() - else: - assert isinstance(key, str), "key must be a string for non-hash keys" - _hex = hex(fnvhash(key.encode('utf-8')))[2:] - key = key.encode('utf-8') - - if "larges" in _map and _hex in _map["larges"]: - print('reading large', _map["larges"][_hex], 'key', key, 'type', _map["dtypes"][1]) - return read_large(_map["larges"][_hex], _map["dtypes"][1]) - else: - print('reading from tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') - return get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') - - def show_content_raw( - self, - obj: str, - key: Union[bytes, str], - ): - if isinstance(key, str): - key = bytes.fromhex(key) - - if obj == 'tree': - _map_obj = self.config['objects']['tree.tch'] - print('reading from tch', key, _map_obj['sharding_bits']) - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - return v - - elif obj == 'commit': - _map_obj = self.config['objects']['commit.tch'] - print('reading from tch', key, _map_obj['sharding_bits']) - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - return v - - elif obj == 'blob': - _map_obj = self.config['objects']['sha1.blob.tch'] - print('reading from tch', key, _map_obj['sharding_bits']) - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - - offset, length = unber(v) - print('reading from blob', _map_obj['shards'][0], offset, length) - _map_obj = self.config['objects']['blob.bin'] - shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) - with open(_map_obj['shards'][shard], "rb") as f: - f.seek(offset) - _out_bin = f.read(length) - return (v, _out_bin) - - else: - raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') - - def copy_values(self, map_name, key): """One large file can only contain one record""" - value = self.get_values_raw(map_name, key) + value, _ = self._get_tch_bytes(map_name, key) if map_name in self.config2["maps"]: _map = self.config2["maps"][map_name][0] @@ -185,7 +107,7 @@ def copy_values(self, map_name, key): def copy_content(self, obj: str, key: Union[bytes, str]): """One blob shard can only contain one record""" - value = self.show_content_raw(obj, key) + value, _ = self._get_tch_bytes(obj, key) if obj == 'tree': _map_obj = self.config2['objects']['tree.tch'] @@ -198,14 +120,22 @@ def copy_content(self, obj: str, key: Union[bytes, str]): write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) elif obj == 'blob': + # read blob + key = bytes.fromhex(key) if isinstance(key, str) else key + offset, length = self._get_pos('blob', key) + _map_obj = self.config['objects']['blob.bin'] + shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) + with open(_map_obj['shards'][shard], "rb") as f: + f.seek(offset) + _v = f.read(length) + # write tch _map_obj = self.config2['objects']['sha1.blob.tch'] - _idx, _v = value - offset, length = unber(_idx) _idx = ber(0, length) print('writing to tch', key, _map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + write_to_tch(key, _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + # write blob _map_obj = self.config2['objects']['blob.bin'] - shard = get_shard(bytes.fromhex(key), _map_obj['sharding_bits'], use_fnv_keys=False) + shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) print('writing to file', _map_obj['shards'][shard], length) with open(_map_obj['shards'][shard], "ab") as f: f.write(_v) diff --git a/tests/fixtures/create_fixtures.py.bak b/tests/fixtures/create_fixtures.py.bak new file mode 100644 index 0000000..16b9cdb --- /dev/null +++ b/tests/fixtures/create_fixtures.py.bak @@ -0,0 +1,244 @@ +from typing import List, Union +import gzip +import json +try: + import lzf + assert lzf.decompress +except ImportError or AssertionError: + raise ImportError('python-lzf is required to decompress LZF-compressed data: `pip install python-lzf`') + +from woc.tch import TCHashDB +from woc.local import * + +def ber(*numbers): + def gen(): + for num in numbers: + a = True + while a: + a, num = divmod(num, 128) + yield (a + 0x80 if a else num).to_bytes(1, 'big') + return b''.join(gen()) + +def encode_value( + value, + dtype: str +) -> bytes: + if dtype == 'h': # type: list[str] + return b''.join(bytes.fromhex(v) for v in value) + elif dtype == 'sh': # type: tuple[str, str, str] + Time, Author, cmt_sha = value + buf0 = f"{Time};{Author}".encode() + cmt_sha_bytes = bytes.fromhex(cmt_sha) + return buf0 + cmt_sha_bytes + elif dtype == 'cs3': # type: list[tuple[str, str, str]] + _joined = ';'.join(f"{t[0]};{t[1]};{t[2]}" for t in value) + data = _joined.encode + return lzf.compress(data) + elif dtype == 'cs': # type: list[str] + _joined = ';'.join(v.encode() for v in value if v) + return lzf.compress(_joined.encode()) + elif dtype == 's': # type: list[str] + return b';'.join(v.encode() for v in value) + elif dtype == 'r': # type: list[str, int] + _hex, _len = value + return bytes.fromhex(_hex) + ber(_len) + elif dtype == 'hhwww': + raise NotImplemented + raise ValueError(f'Unsupported dtype: {dtype}') + +def write_to_tch(key: bytes, value: bytes, shards: List[str], sharding_bits: int, use_fnv_keys: bool): + shard = get_shard(key, sharding_bits, use_fnv_keys) + _path = shards[shard] + db = TCHashDB(_path.encode()) + db[key] = value + +def write_large(path: str, key: bytes, value: bytes, dtype: str): + if dtype == 'h': + with open(path, 'wb') as f: + f.write(key) + f.write(value[:160]) + else: + # use zlib to decompress + with gzip.open(path, 'wb') as f: + f.write(key) + f.write(b'\n') + # run a fast scan to find idx of 3rd ';' in value + idx = 0 + for _ in range(3): + idx = value.find(b';', idx + 1) + f.write(value[:idx]) + +class WocMapsCopier(WocMapsLocal): + def __init__(self, config1, config2): + super().__init__(config1) + with open(config2) as f: + self.config2 = json.load(f) + + def get_values_raw(self, map_name, key): + if map_name in self.config["maps"]: + _map = self.config["maps"][map_name][0] + elif map_name in self.config["objects"]: + _map = self.config["objects"][map_name] + else: + raise KeyError(f'Invalid map name: {map_name}, ' + f'expect one of {", ".join(self.config["maps"].keys())}') + + if _map["dtypes"][0] == 'h': + if isinstance(key, str): + _hex = key + key = bytes.fromhex(key) + else: + _hex = bytes(key).hex() + else: + assert isinstance(key, str), "key must be a string for non-hash keys" + _hex = hex(fnvhash(key.encode('utf-8')))[2:] + key = key.encode('utf-8') + + if "larges" in _map and _hex in _map["larges"]: + print('reading large', _map["larges"][_hex], 'key', key, 'type', _map["dtypes"][1]) + return read_large(_map["larges"][_hex], _map["dtypes"][1]) + else: + print('reading from tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') + return get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + + def show_content_raw( + self, + obj: str, + key: Union[bytes, str], + ): + if isinstance(key, str): + key = bytes.fromhex(key) + + if obj == 'tree': + _map_obj = self.config['objects']['tree.tch'] + print('reading from tch', key, _map_obj['sharding_bits']) + v = get_from_tch(key, + shards=_map_obj['shards'], + sharding_bits=_map_obj['sharding_bits'], + use_fnv_keys=False + ) + return v + + elif obj == 'commit': + _map_obj = self.config['objects']['commit.tch'] + print('reading from tch', key, _map_obj['sharding_bits']) + v = get_from_tch(key, + shards=_map_obj['shards'], + sharding_bits=_map_obj['sharding_bits'], + use_fnv_keys=False + ) + return v + + elif obj == 'blob': + _map_obj = self.config['objects']['sha1.blob.tch'] + print('reading from tch', key, _map_obj['sharding_bits']) + v = get_from_tch(key, + shards=_map_obj['shards'], + sharding_bits=_map_obj['sharding_bits'], + use_fnv_keys=False + ) + + offset, length = unber(v) + print('reading from blob', _map_obj['shards'][0], offset, length) + _map_obj = self.config['objects']['blob.bin'] + shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) + with open(_map_obj['shards'][shard], "rb") as f: + f.seek(offset) + _out_bin = f.read(length) + return (v, _out_bin) + + else: + raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') + + + def copy_values(self, map_name, key): + """One large file can only contain one record""" + value = self.get_values_raw(map_name, key) + + if map_name in self.config2["maps"]: + _map = self.config2["maps"][map_name][0] + elif map_name in self.config2["objects"]: + _map = self.config2["objects"][map_name] + else: + raise KeyError(f'Invalid map name: {map_name}, ' + f'expect one of {", ".join(self.config2["maps"].keys())}') + + if _map["dtypes"][0] == 'h': + if isinstance(key, str): + _hex = key + key = bytes.fromhex(key) + else: + _hex = bytes(key).hex() + else: + assert isinstance(key, str), "key must be a string for non-hash keys" + _hex = hex(fnvhash(key.encode('utf-8')))[2:] + key = key.encode('utf-8') + + if "larges" in _map and _hex in _map["larges"]: + print('writing large', _map["larges"][_hex], 'key', key, 'dtype', _map["dtypes"][1]) + return write_large(_map["larges"][_hex], key, value, _map["dtypes"][1]) + else: + # use fnv hash as shading idx if key is not a git sha + print('writing to tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') + return write_to_tch(key, value, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + + def copy_content(self, obj: str, key: Union[bytes, str]): + """One blob shard can only contain one record""" + value = self.show_content_raw(obj, key) + + if obj == 'tree': + _map_obj = self.config2['objects']['tree.tch'] + print('writing to tch', key, _map_obj["sharding_bits"]) + write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) + + elif obj == 'commit': + _map_obj = self.config2['objects']['commit.tch'] + print('writing to tch', key ,_map_obj["sharding_bits"]) + write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) + + elif obj == 'blob': + _map_obj = self.config2['objects']['sha1.blob.tch'] + _idx, _v = value + offset, length = unber(_idx) + _idx = ber(0, length) + print('writing to tch', key, _map_obj["sharding_bits"]) + write_to_tch(bytes.fromhex(key), _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + _map_obj = self.config2['objects']['blob.bin'] + shard = get_shard(bytes.fromhex(key), _map_obj['sharding_bits'], use_fnv_keys=False) + print('writing to file', _map_obj['shards'][shard], length) + with open(_map_obj['shards'][shard], "ab") as f: + f.write(_v) + + else: + raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') + + +if __name__ == '__main__': + import glob + import os + + for f in glob.glob('./tests/fixtures/*.tch*') + glob.glob('./tests/fixtures/*.bin'): + print('removing', f) + os.remove(f) + + cp = WocMapsCopier('./wocprofile.json', './tests/test_profile.json') + cp.copy_values('c2p', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('c2dat', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('b2tac', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_values('p2a', 'ArtiiQ_PocketMine-MP') + cp.copy_values('b2c', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_values('b2c', '3f2eca18f1bc0f3117748e2cea9251e5182db2f7') # large + cp.copy_values('a2c', 'Audris Mockus ') + # cp.copy_values('c2cc', 'e4af89166a17785c1d741b8b1d5775f3223f510f') # null + cp.copy_values('a2f', 'Audris Mockus ') + cp.copy_values('c2f', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('c2b', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('p2c', 'ArtiiQ_PocketMine-MP') + cp.copy_values('f2a', 'youtube-statistics-analysis.pdf') + cp.copy_values('b2f', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_content('tree', 'f1b66dcca490b5c4455af319bc961a34f69c72c2') + cp.copy_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + cp.copy_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') + cp.copy_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') diff --git a/tests/test_local.py b/tests/test_local.py index 3b42444..6d8d4ff 100644 --- a/tests/test_local.py +++ b/tests/test_local.py @@ -80,7 +80,7 @@ def test_tree(woc): def test_commit(woc): res = woc.show_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - assert len(res) == 222 + assert res[-1] == 'News for Sep 5' def test_blob_1(woc): res = woc.show_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') diff --git a/woc/base.py b/woc/base.py index ae82246..c050d63 100644 --- a/woc/base.py +++ b/woc/base.py @@ -7,25 +7,41 @@ class WocMapsBase: def __init__(self, *args, **kwargs): raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") - + def get_values( self, map_name: str, key: Union[bytes, str], ) -> Union[List[str], Tuple[str, str, str], List[Tuple[str, str, str]]]: + """Eqivalent to getValues in WoC Perl API + >>> self.get_values('P2c', 'user2589_minicms') + ['05cf84081b63cda822ee407e688269b494a642de', ...] + >>> self.get_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + ('9531fc286ef1f4753ca4be9a3bf76274b929cdeb', 27) + >>> self.get_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169') + ('1410029988', + 'Audris Mockus ', + 'e4af89166a17785c1d741b8b1d5775f3223f510f') + """ raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") def show_content( self, - obj: WocObjectsWithContent, + obj_name: WocObjectsWithContent, key: Union[bytes, str], - ) -> Union[List[Tuple[str, str, str]], Dict[str, str], str]: - raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") - - def get_pos( - self, - obj: str, - key: bytes, - ) -> Tuple[int, int]: + ) -> Union[List[Tuple[str, str, str]], str, Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]]: + """ + >>> self.show_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') + 'This is the content of the blob' + Eqivalent to showCnt in WoC perl API + >>> self.show_content('tree', '7a374e58c5b9dec5f7508391246c48b73c40d200') + [('100644', '.gitignore', '8e9e1...'), ...] + >>> self.show_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + ('f1b66dcca490b5c4455af319bc961a34f69c72c2', + ('c19ff598808b181f1ab2383ff0214520cb3ec659',), + ('Audris Mockus 1410029988', '1410029988', '-0400'), + ('Audris Mockus ', '1410029988', '-0400'), + 'News for Sep 5, 2014\\n') + """ raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") \ No newline at end of file diff --git a/woc/local.pyi b/woc/local.pyi index 615c9ad..7705837 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -1,4 +1,4 @@ -from typing import Iterable, Union, Tuple, List, Dict +from typing import Iterable, Union, Tuple, List from .base import WocMapsBase, WocObjectsWithContent @@ -8,26 +8,34 @@ class WocMapsLocal(WocMapsBase): version: str | Iterable[str] | None = None ) -> None: ... - - def get_values( - self, - map_name: str, - key: Union[bytes, str], - ) -> Union[List[str], Tuple[str, str, str], List[Tuple[str, str, str]]]: + + def _get_tch_bytes( + self, map_name: str, key: Union[bytes, str] + ) -> Tuple[bytes, str]: ... - - def show_content( - self, - obj: WocObjectsWithContent, - key: Union[bytes, str], - ) -> Union[List[Tuple[str, str, str]], str]: + + def _get_pos( + self, obj_name: str, key: Union[bytes, str], + ) -> Tuple[int, int]: + """ + Get offset and length of a stacked binary object, currently only support blob. + Extract this part because it's much cheaper than decode the content. + >>> self._get_pos('blob', bytes.fromhex('7a374e58c5b9dec5f7508391246c48b73c40d200')) + (0, 123) + """ ... -# Make utility functions accessible from Python -> easier testing +# The following functions are internal and should not be used by the user +# Exposing them here for testing purposes def fnvhash(data: bytes) -> int: ... def unber(buf: bytes) -> bytes: ... def lzf_length(raw_data: bytes) -> Tuple[int, int]: ... +def decomp(data: bytes) -> bytes: ... +def decomp_or_raw(data: bytes) -> bytes: ... def get_tch(path: str): ... def get_shard(key: bytes, sharding_bits: int, use_fnv_keys: bool) -> int: ... def get_from_tch(key: bytes, shards: List[bytes], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... -def parse_commit(cmt: str) -> Dict[str, str]: ... \ No newline at end of file +def decode_value(value: bytes, out_dtype: str): ... +def decode_tree(value: bytes) -> List[Tuple[str, str, str]]: ... +def decode_commit(commit_bin: bytes) -> Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]: ... +def decode_str(raw_data: str, encoding='utf-8'): ... diff --git a/woc/local.pyx b/woc/local.pyx index 0bf7ed3..a111881 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -8,6 +8,7 @@ import json import logging import time from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t +from libc.string cimport memchr, strstr, strchr, strlen, strncmp from threading import Lock from typing import Tuple, Dict, Iterable, List, Union, Literal, Optional import gzip @@ -22,6 +23,9 @@ from .base import WocMapsBase, WocObjectsWithContent, WocSupportedProfileVersion from .tch cimport TCHashDB logger = logging.getLogger(__name__) + +cdef extern from 'Python.h': + object PyBytes_FromStringAndSize(char *s, Py_ssize_t len) ### Utility functions ### @@ -154,10 +158,10 @@ def slice20(bytes raw_data): return () return tuple(raw_data[i:i + 20] for i in range(0, len(raw_data), 20)) -def decode_str(bytes raw_data): +def decode_str(bytes raw_data, str encoding='utf-8'): """ Decode raw_data, detect the encoding if utf-8 fails """ try: - return raw_data.decode('utf-8') + return raw_data.decode(encoding) except UnicodeDecodeError: import chardet # should be rarely used _encoding = chardet.detect(raw_data)['encoding'] @@ -240,88 +244,268 @@ def decode_value( raise NotImplemented raise ValueError(f'Unsupported dtype: {out_dtype}') - def decode_tree( value: bytes ) -> List[Tuple[str, str, str]]: """ Decode a tree binary object into tuples + Python: 4.77 µs, Cython: 280 ns Reference: https://stackoverflow.com/questions/14790681/ mode (ASCII encoded decimal) SPACE (\0x20) filename NULL (\x00) 20-byte binary hash + >>> decode_tree(b'100644 .gitignore\x00\x8e\x9e\x1f...') + [('100644', '.gitignore', '8e9e1...'), ...] """ - _out_buf = [] - _file_buf = [] - _curr_buf = bytes() - - # TODO: current impl is not efficient, need to optimize - i = 0 - while i < len(value): - if value[i] == 0x20: - _file_buf.append(decode_str(_curr_buf)) - _curr_buf = bytes() - elif value[i] == 0x00: - _file_buf.append(decode_str(_curr_buf)) - # take next 20 bytes as a hash - _curr_buf = value[i+1:i+21] - _file_buf.append(_curr_buf.hex()) - _out_buf.append(tuple(_file_buf)) - # clear buffers - _file_buf = [] - _curr_buf = bytes() - i += 20 - else: - _curr_buf += bytes([value[i]]) - i += 1 + files = [] - return _out_buf - - -def parse_commit(cmt: str) -> Dict[str, str]: + cdef: + const char* tree_cstr = value + const char* end = tree_cstr + len(value) + const char* pos = tree_cstr + const char* mode_start + const char* filename_start + const char* hash_start + uint8_t mode_len + uint16_t filename_len # git filenames can be 4096 chars long + + while pos < end: + mode_start = pos + pos = memchr(pos, b' ', end - pos) + if not pos: + raise ValueError('Invalid tree object: missing space after mode') + + mode_len = pos - mode_start + pos += 1 # Skip the space + + filename_start = pos + pos = memchr(pos, b'\x00', end - pos) + if not pos: + raise ValueError('Invalid tree object: missing null byte after filename') + + filename_len = pos - filename_start + pos += 1 # Skip the null byte + + if pos + 20 > end: + raise ValueError('Invalid tree object: missing or truncated hash') + + hash_start = pos + pos += 20 # Skip the 20-byte hash + + files.append(( + value[mode_start - tree_cstr:mode_start - tree_cstr + mode_len].decode('ascii'), + value[filename_start - tree_cstr:filename_start - tree_cstr + filename_len].decode('utf-8'), + value[hash_start - tree_cstr :hash_start - tree_cstr + 20].hex() + )) + + return files + +# def decode_tree( +# value: bytes +# ) -> List[Tuple[str, str, str]]: +# """ +# Decode a tree binary object into tuples +# Reference: https://stackoverflow.com/questions/14790681/ +# mode (ASCII encoded decimal) +# SPACE (\0x20) +# filename +# NULL (\x00) +# 20-byte binary hash +# """ +# _out_buf = [] +# _file_buf = [] +# _curr_buf = bytes() + +# # TODO: current impl is not efficient, need to optimize +# i = 0 +# while i < len(value): +# if value[i] == 0x20: +# _file_buf.append(decode_str(_curr_buf)) +# _curr_buf = bytes() +# elif value[i] == 0x00: +# _file_buf.append(decode_str(_curr_buf)) +# # take next 20 bytes as a hash +# _curr_buf = value[i+1:i+21] +# _file_buf.append(_curr_buf.hex()) +# _out_buf.append(tuple(_file_buf)) +# # clear buffers +# _file_buf = [] +# _curr_buf = bytes() +# i += 20 +# else: +# _curr_buf += bytes([value[i]]) +# i += 1 + +# return _out_buf + +cdef const char* strrchr2(const char* s, char c, const char* end): + """Like strrchr but with a limit""" + cdef const char* p = NULL + while s and s < end: + if s[0] == c: + p = s + s += 1 + return p + +def decode_commit( + commit_bin: bytes +) -> Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]: """ - Parse commit objects into a dictionary + Decode git commit objects into tuples + Python: 2.35 µs, Cython: 855 ns + Reference: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects + >>> decode_commit(b'tree f1b66dcca490b5c4455af319bc961a34f69c72c2\\n...') + ('f1b66dcca490b5c4455af319bc961a34f69c72c2', + ('c19ff598808b181f1ab2383ff0214520cb3ec659',), + ('Audris Mockus 1410029988', '1410029988', '-0400'), + ('Audris Mockus ', '1410029988', '-0400'), + 'News for Sep 5, 2014\n') """ - lines = cmt.split('\n') - tree_sha = lines[0][5:] - - if lines[1].startswith('parent'): - parent_sha = lines[1][7:] - else: - # insert a dummy line - lines.insert(1, '') - parent_sha = '' - - author_idx = lines[2].find('>') - author = lines[2][7:author_idx+1] - author_time = lines[2][author_idx+2:] - author_timestamp = author_time.split(' ')[0] - author_timezone = author_time.split(' ')[1] - - committer_idx = lines[3].find('>') - committer = lines[3][10:committer_idx+1] - committer_time = lines[3][committer_idx+2:] - committer_timestamp = committer_time.split(' ')[0] - committer_timezone = committer_time.split(' ')[1] - - commit_msg = '\\n'.join(lines[5:]) - if commit_msg.endswith('\\n'): # strip - commit_msg = commit_msg[:-2] - - return dict( - tree=tree_sha, - parent=parent_sha, - author=author, - author_timestamp=author_timestamp, - author_timezone=author_timezone, - committer=committer, - committer_timestamp=committer_timestamp, - committer_timezone=committer_timezone, - message=commit_msg, + cdef: + const char* cmt_cstr = commit_bin + const char* header + const char* full_msg + const char* line + const char* next_line + const char* key + const char* value + const char* timestamp + const char* timezone + bint is_reading_pgp = False + int header_len + int line_len + + _parent_shas = [] + _tree = '' + _author_bytes = b'' + _author_timestamp = '' + _author_timezone = '' + _committer_bytes = b'' + _committer_timestamp = '' + _committer_timezone = '' + _encoding = 'utf-8' + + if not cmt_cstr or cmt_cstr[0] == b'\0': + raise ValueError('Empty commit object') + + header = cmt_cstr + full_msg = strstr(cmt_cstr, b"\n\n") + if not full_msg: + raise ValueError('Invalid commit object: no \\n\\n') + + header_len = full_msg - header + full_msg += 2 # Skip the '\n\n' + + line = header + while line < header + header_len: + next_line = strchr(line, b'\n') + if not next_line: + next_line = header + header_len + line_len = next_line - line + + if line_len == 0: + line = next_line + 1 + continue + + key = line + value = strchr(line, b' ') + if not value or value >= next_line: + line = next_line + 1 + continue + value += 1 + + if strncmp(key, "tree ", 5) == 0: + _tree = (value[:line_len - 5]).decode('ascii') + elif strncmp(key, "parent ", 7) == 0: + _parent_shas.append(value[:line_len - 7].decode('ascii')) + elif strncmp(key, "author ", 7) == 0: + timezone = strrchr2(value, b' ', next_line) + if not timezone: + continue + timestamp = strrchr2(value, b' ', timezone - 1) + if not timestamp: + continue + _author_bytes = value[:timestamp - value] + _author_timestamp = (value[timestamp - value + 1: timezone - value]).decode('ascii') + _author_timezone = (value[timezone - value + 1: next_line - value]).decode('ascii') + elif strncmp(key, "committer ", 10) == 0: + timezone = strrchr2(value, b' ', next_line) + if not timezone: + continue + timestamp = strrchr2(value, b' ', timezone - 1) + if not timestamp: + continue + _committer_bytes = value[:timestamp - value] + _committer_timestamp = (value[timestamp - value + 1: timezone - value]).decode('ascii') + _committer_timezone = (value[timezone - value + 1: next_line - value]).decode('ascii') + elif strncmp(key, "gpgsig", 6) == 0: + is_reading_pgp = True + elif is_reading_pgp and strncmp(line, "-----END PGP SIGNATURE-----", 27) == 0: + is_reading_pgp = False + elif strncmp(key, "encoding", 8) == 0: + _encoding = value[:line_len - 8].decode('ascii') + + line = next_line + 1 + + _author = decode_str(_author_bytes, _encoding) + _committer = decode_str(_committer_bytes, _encoding) + _message = decode_str(full_msg, _encoding) + + return ( + _tree, + tuple(_parent_shas), + (_author, _author_timestamp, _author_timezone), + (_committer, _committer_timestamp, _committer_timezone), + _message, ) +# def decode_commit(cmt: bytes): +# """ +# Decode git commit objects into tuples +# """ +# cmt = decode_str(cmt) +# if cmt.strip() == '': +# raise ValueError('Empty commit object') +# try: +# header, full_msg = cmt.split('\n\n', 1) +# except ValueError: +# raise ValueError('Invalid commit object: no \\n\\n') + +# tree = '' +# parent = [] +# author, author_timestamp, author_timezone = '', '', '' +# committer, committer_timestamp, committer_timezone = '', '', '' +# encoding = 'utf-8' +# # parse the header +# _is_reading_pgp = False +# for line in header.split('\n'): +# line = line.strip() +# if line.startswith('tree'): +# tree = line[5:] +# elif line.startswith('parent'): # merge commits have multiple parents +# parent.append(line[7:]) +# elif line.startswith('author'): +# # res['author'], res['author_timestamp'], res['author_timezone'] = line[7:].rsplit(' ', 2) +# author, timestamp, timezone = line[7:].rsplit(' ', 2) +# elif line.startswith('committer'): +# # res['committer'], res['committer_timestamp'], res['committer_timezone'] = line[10:].rsplit(' ', 2) +# committer, timestamp, timezone = line[10:].rsplit(' ', 2) +# elif line.startswith('gpgsig'): +# _is_reading_pgp = True +# elif _is_reading_pgp and line.strip() == '-----END PGP SIGNATURE-----': +# _is_reading_pgp = False +# elif line.startswith('encoding'): +# encoding = line[8:] + +# return ( +# tree, +# tuple(parent), +# (author, author_timestamp, author_timezone), +# (committer, committer_timestamp, committer_timezone), +# full_msg, +# ) def read_large(path: str, dtype: str) -> bytes: """Read a *.large.* and return its content""" @@ -370,16 +554,21 @@ class WocMapsLocal(WocMapsBase): "Unsupported wocprofile version: {}".format(self.config["wocSchemaVersion"]) assert self.config["maps"], "Run `python3 -m woc.detect` to scan data files and generate wocprofile.json" - def get_values( - self, - map_name: str, - key: Union[bytes, str], - ): - """Eqivalent to getValues in WoC Perl API - >>> get_values('P2c', 'user2589_minicms') # doctest: +SKIP - ... + def _get_tch_bytes( + self, map_name, key + ) -> Tuple[bytes, str]: """ - + Get value (in bytes) from tch maps, return bytes and dtype + """ + # translate obj_name to map_name + if map_name == 'tree': + map_name = 'tree.tch' + elif map_name == 'commit': + map_name = 'commit.tch' + elif map_name == 'blob': + map_name = 'sha1.blob.tch' + + # find dtype object if map_name in self.config["maps"]: _map = self.config["maps"][map_name][0] elif map_name in self.config["objects"]: @@ -387,11 +576,14 @@ class WocMapsLocal(WocMapsBase): else: raise KeyError(f'Invalid map name: {map_name}, ' f'expect one of {", ".join(self.config["maps"].keys())}') + + in_dtype = _map["dtypes"][0] if "dtypes" in _map else "h" + out_dtype = _map["dtypes"][1] if "dtypes" in _map else "c?" # c? means maybe compressed start_time = time.time_ns() - logger.debug(f"get_values: {map_name} {key}") + logger.debug(f"get from tch: {map_name} {key}") - if _map["dtypes"][0] == 'h': + if in_dtype == 'h': if isinstance(key, str): _hex = key key = bytes.fromhex(key) @@ -404,97 +596,135 @@ class WocMapsLocal(WocMapsBase): logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - - decode_dtype = _map["dtypes"][1] if "larges" in _map and _hex in _map["larges"]: - _bytes = read_large(_map["larges"][_hex], _map["dtypes"][1]) + _bytes = read_large(_map["larges"][_hex], out_dtype) logger.debug(f"read large: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() # compress string data is not compressed in larges - if decode_dtype == 'cs': - decode_dtype = 's' + if out_dtype == 'cs': + out_dtype = 's' else: # use fnv hash as shading idx if key is not a git sha - _bytes = get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') + _bytes = get_from_tch(key, _map["shards"], _map["sharding_bits"], in_dtype != 'h') logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") - start_time = time.time_ns() - _ret = decode_value(_bytes, decode_dtype) - logger.debug(f"decode value: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") - return _ret + return _bytes, out_dtype - def get_pos( + def get_values( + self, + map_name: str, + key: Union[bytes, str], + ): + """Eqivalent to getValues in WoC Perl API + >>> self.get_values('P2c', 'user2589_minicms') + ['05cf84081b63cda822ee407e688269b494a642de', ...] + """ + _bytes, decode_dtype = self._get_tch_bytes(map_name, key) + start_time = time.time_ns() + _decoded = decode_value(_bytes, decode_dtype) + logger.debug(f"decode: {(time.time_ns() - start_time) / 1e6:.2f}ms") + return _decoded + + def _get_pos( self, obj: str, - key: bytes, + key: Union[bytes, str] ) -> Tuple[int, int]: """ Get offset and length of a stacked binary object, currently only support blob. - Move out this part because it's much cheaper than measuring the whole object. + Move out this part because it's much cheaper than decode the content. + >>> self._get_pos('blob', bytes.fromhex('7a374e58c5b9dec5f7508391246c48b73c40d200')) + (0, 123) """ if obj == 'blob': - _map_obj = self.config['objects']['sha1.blob.tch'] - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - return unber(v) + r_res = unber(self._get_tch_bytes('blob', key)[0]) + assert len(r_res) == 2, f"Invalid (offset, length) pair: {r_res}" + return r_res[0], r_res[1] else: raise ValueError(f'Unsupported object type: {obj}, expected blob') + # def _show_content_bytes( + # self, + # obj_name: str, + # key: Union[bytes, str], + # ): + # start_time = time.time_ns() + # logger.debug(f"show_content: {obj_name} {key}") + + # if isinstance(key, str): + # key = bytes.fromhex(key) + + # logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # start_time = time.time_ns() + + # if obj_name == 'tree': + # _map_obj = self.config['objects']['tree.tch'] + # v = get_from_tch(key, + # shards=_map_obj['shards'], + # sharding_bits=_map_obj['sharding_bits'], + # use_fnv_keys=False + # ) + # logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # return decomp_or_raw(v) + + # elif obj_name == 'commit': + # _map_obj = self.config['objects']['commit.tch'] + # v = get_from_tch(key, + # shards=_map_obj['shards'], + # sharding_bits=_map_obj['sharding_bits'], + # use_fnv_keys=False + # ) + # logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # return decomp_or_raw(v) + + # elif obj_name == 'blob': + # offset, length = self._get_pos('blob', key) + # logger.debug(f"get from tch: offset={offset} len={length} {(time.time_ns() - start_time) / 1e6:.2f}ms") + # start_time = time.time_ns() + + # _map_obj = self.config['objects']['blob.bin'] + # shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) + + # with open(_map_obj['shards'][shard], "rb") as f: + # f.seek(offset) + # _out_bin = f.read(length) + # logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # start_time = time.time_ns() + + # return decomp_or_raw(_out_bin) + + # else: + # raise ValueError(f'Unsupported object type: {obj_name}') + def show_content( self, - obj: str, + obj_name: str, key: Union[bytes, str], ): - """Eqivalent to showCnt in WoC perl API - >>> show_content('tree', '7a374e58c5b9dec5f7508391246c48b73c40d200') # doctest: +SKIP - ... """ - start_time = time.time_ns() - logger.debug(f"show_content: {obj} {key}") - - - if isinstance(key, str): - key = bytes.fromhex(key) - - logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") + Eqivalent to showCnt in WoC perl API + >>> self.show_content('tree', '7a374e58c5b9dec5f7508391246c48b73c40d200') + [('100644', '.gitignore', '8e9e1...'), ...] + """ start_time = time.time_ns() - if obj == 'tree': - _map_obj = self.config['objects']['tree.tch'] - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") - start_time = time.time_ns() - _ret = decode_tree(decomp_or_raw(v)) + if obj_name == 'tree': + _ret = decode_tree(decomp_or_raw(self._get_tch_bytes(obj_name, key)[0])) logger.debug(f"decode tree: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret - elif obj == 'commit': - _map_obj = self.config['objects']['commit.tch'] - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") - return decode_str(decomp_or_raw(v)) + elif obj_name == 'commit': + _ret = decode_commit(decomp_or_raw(self._get_tch_bytes(obj_name, key)[0])) + logger.debug(f"decode commit: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") + return _ret - # # Don't decode commit here to be compatible with Perl API - # _ret = decode_commit(decomp_or_raw(v)) - # logger.debug(f"decode commit: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") - # return _ret + elif obj_name == 'blob': + key = bytes.fromhex(key) if isinstance(key, str) else key - elif obj == 'blob': - offset, length = self.get_pos('blob', key) - logger.debug(f"get from tch: offset={offset} len={length} {(time.time_ns() - start_time) / 1e6:.2f}ms") + offset, length = self._get_pos('blob', key) + logger.debug(f"pos: offset={offset} len={length} {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() _map_obj = self.config['objects']['blob.bin'] @@ -506,15 +736,13 @@ class WocMapsLocal(WocMapsBase): logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - _ret = decode_str(decomp_or_raw(_out_bin)) - logger.debug(f"decode blob: len={len(_ret)} {(time.time_ns() - start_time) / 1e6:.2f}ms") - return _ret + return decode_str(decomp_or_raw(_out_bin)) - elif obj == 'tkns': + elif obj_name == 'tkns': raise NotImplemented - elif obj == 'tag': + elif obj_name == 'tag': raise NotImplemented - elif obj == 'bdiff': + elif obj_name == 'bdiff': raise NotImplemented else: - raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit, tkns, tag, bdiff') \ No newline at end of file + raise ValueError(f'Unsupported object type: {obj_name}, expected one of tree, blob, commit, tkns, tag, bdiff') \ No newline at end of file diff --git a/woc/show_content.py b/woc/show_content.py index 25cebbc..aa11fc7 100644 --- a/woc/show_content.py +++ b/woc/show_content.py @@ -4,7 +4,7 @@ # @authors: Runzhi He # @date: 2024-05-27 -from .local import WocMapsLocal, parse_commit +from .local import WocMapsLocal, decode_commit, decode_str, decomp_or_raw def format_tree(tree_objs: list) -> str: _out = '' @@ -12,38 +12,26 @@ def format_tree(tree_objs: list) -> str: _out += f'{line[0]};{line[2]};{line[1]}\n' return _out -def format_commit(sha: str, cmt: str, format: int = 0): +def format_commit(sha: str, cmt_bin: bytes, format: int = 0): if format == 3: # raw + cmt = decode_str(cmt_bin) return cmt if format == 7: # commit sha; base64(raw) import base64 - _b64 = base64.b64encode(cmt.encode()).decode() + _b64 = base64.b64encode(cmt_bin).decode() # mock linux's base64, add newline every 76 characters _b64 = '\\n'.join([_b64[i:i+76] for i in range(0, len(_b64), 76)]) + '\\n' return sha + ';' + _b64 - d = parse_commit(cmt) - # d = dict( - # tree=tree_sha, - # parent=parent_sha, - # author=author, - # author_timestamp=author_timestamp, - # author_timezone=author_timezone, - # committer=committer, - # committer_timestamp=committer_timestamp, - # committer_timezone=committer_timezone, - # message=commit_msg, - # ) - tree_sha = d['tree'] - parent_sha = d['parent'] - author = d['author'] - author_timestamp = d['author_timestamp'] - author_timezone = d['author_timezone'] - committer = d['committer'] - committer_timestamp = d['committer_timestamp'] - committer_timezone = d['committer_timezone'] - commit_msg = d['message'] + ( + tree_sha, + parents, + (author, author_timestamp, author_timezone), + (committer, committer_timestamp, committer_timezone), + commit_msg, + ) = decode_commit(cmt_bin) + parent_sha = parents[0] # only the first parent if format == 0: # commit SHA;tree SHA;parent commit SHA;author;committer;author timestamp;commit timestamp @@ -90,12 +78,14 @@ def format_commit(sha: str, cmt: str, format: int = 0): for line in sys.stdin: try: key = line.strip() - obj = woc.show_content(args.type, key) if args.type == 'commit': - print(format_commit(key, obj, args.format)) + obj_bin = decomp_or_raw(woc._get_tch_bytes(args.type, key)[0]) + print(format_commit(key, obj_bin, args.format)) elif args.type == 'tree': + obj = woc.show_content(args.type, key) print(format_tree(obj)) elif args.type == 'blob': + obj = woc.show_content(args.type, key) print(obj) else: raise ValueError(f'Invalid object type {args.type}') diff --git a/woc/tch.pyx b/woc/tch.pyx index 5c47aad..db923e0 100644 --- a/woc/tch.pyx +++ b/woc/tch.pyx @@ -53,7 +53,7 @@ cdef class TCHashDB: raise MemoryError() cdef bint result = tchdbopen(self._db, path, mode) if not result: - raise IOError(f'Failed to open "{self.filename.decode("latin1")}": ' + self._error()) + raise IOError(f'Failed to open {self.filename.decode("latin1")}: ' + self._error()) def _error(self): cdef int code = tchdbecode(self._db) @@ -67,7 +67,7 @@ cdef class TCHashDB: int sp bytes key if not result: - raise IOError(f'Failed to iterate "{self.filename.decode("latin1")}": ' + self._error()) + raise IOError(f'Failed to iterate {self.filename.decode("latin1")}: ' + self._error()) while True: buf = tchdbiternext(self._db, &sp) if buf is NULL: @@ -84,7 +84,7 @@ cdef class TCHashDB: int ksize=len(key) buf = tchdbget(self._db, k, ksize, &sp) if buf is NULL: - raise KeyError(f'Key "{key.decode("latin1")}" not found in "{self.filename.decode("latin1")}"') + raise KeyError(f'Key {key.hex()} not found in {self.filename.decode("latin1")}') cdef bytes value = PyBytes_FromStringAndSize(buf, sp) free(buf) return value @@ -98,7 +98,7 @@ cdef class TCHashDB: bint result result = tchdbput(self._db, k, ksize, v, vsize) if not result: - raise IOError(f'Failed to put "{key.decode("latin1")}" in "{self.filename.decode("latin1")}": ' + self._error()) + raise IOError(f'Failed to put {key.hex()} in {self.filename.decode("latin1")}: ' + self._error()) cpdef void delete(self, bytes key) except *: cdef: @@ -107,19 +107,19 @@ cdef class TCHashDB: bint result result = tchdbout(self._db, k, ksize) if not result: - raise IOError(f'Failed to delete "{key.decode("latin1")}" in "{self.filename.decode("latin1")}": ' + self._error()) + raise IOError(f'Failed to delete {key.hex()} in {self.filename.decode("latin1")}: ' + self._error()) cpdef void drop(self) except *: cdef: bint result result = tchdbvanish(self._db) if not result: - raise IOError(f'Failed to drop all records in "{self.filename.decode("latin1")}": ' + self._error()) + raise IOError(f'Failed to drop all records in {self.filename.decode("latin1")}: ' + self._error()) cpdef void close(self) except *: cdef bint result = tchdbclose(self._db) if not result: - raise IOError(f'Failed to close "{self.filename.decode("latin1")}": ' + self._error()) + raise IOError(f'Failed to close {self.filename.decode("latin1")}: ' + self._error()) def __getitem__(self, bytes key): return self.get(key) From f0bd65ae9204c69512cb59e4c4c83dadaa9c4c98 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Fri, 7 Jun 2024 00:16:49 +0800 Subject: [PATCH 20/38] feat: add objects api --- woc/objects.py | 367 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 woc/objects.py diff --git a/woc/objects.py b/woc/objects.py new file mode 100644 index 0000000..7489d18 --- /dev/null +++ b/woc/objects.py @@ -0,0 +1,367 @@ +import re +from typing import Union, Optional, List, Tuple, Set, Generator +from functools import cached_property, lru_cache +from datetime import datetime, timezone, timedelta + +from .base import WocMapsBase +from .local import fnvhash + +_global_woc: Optional[WocMapsBase] = None + +def init_woc(woc: WocMapsBase): + global _global_woc + _global_woc = woc + +@lru_cache(maxsize=None) +def parse_timezone_offset(offset_str): + """ + Parse a timezone offset string in the format '+HHMM' or '-HHMM' into a timezone object. + """ + match = re.match(r'([+-])(\d{2})(\d{2})', offset_str) + if not match: + raise ValueError(f"Invalid timezone offset format: {offset_str}") + sign, hours, minutes = match.groups() + hours, minutes = int(hours), int(minutes) + offset = timedelta(hours=hours, minutes=minutes) + + if sign == '-': + offset = -offset + + return timezone(offset) + + +class _WocObject: + woc: WocMapsBase # WocMap instance + key: str # Key of the object + + def __init__( + self, + *args, + woc: Optional[WocMapsBase] = None, + **kwargs, + ): + self.woc = woc or _global_woc + assert self.woc is not None, "WocMaps not initialized: call init_woc() or supply a woc argument" + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.key})" + + def __str__(self) -> str: + return self.key + + def __eq__(self, value: object) -> bool: + if not isinstance(value, self.__class__): + return False + return self.key == value.key + + def hash(self) -> str: + return hex(hash(self))[2:] + + def get_list_values(self, map_name: str): + try: + return self.woc.get_values(map_name, self.key) + except KeyError: + return [] + + +class _GitObject(_WocObject): + """ Base class for SHA1-indexed Git objects (commit, tree, blob) """ + def __init__( + self, + key: str, + *args, + woc: Optional[WocMapsBase] = None, + **kwargs, + ): + super().__init__(*args, woc=woc, **kwargs) + assert len(key) == 40, "SHA1 hash must be 40 characters long" + self.key = key + + @cached_property + def data(self): + obj = self.__class__.__name__.lower() + return self.woc.show_content(obj, self.key) + + def __hash__(self): + return int(self.key, 16) + + def hash(self) -> str: + return self.key + + +class _NamedObject(_WocObject): + """ Base class for objects indexed by a string key""" + def __init__( + self, + key: str, + *args, + woc: Optional[WocMapsBase] = None, + **kwargs, + ): + super().__init__(*args, woc=woc, **kwargs) + self.key = key + + def __hash__(self): + return fnvhash(self.key.encode()) + + +class Author(_NamedObject): + @cached_property + def _username_email(self) -> Tuple[str, str]: + _splited = self.key.split(' <', 1) + if len(_splited) == 1: + return _splited[0], '' + return _splited[0], _splited[1][:-1] + + @property + def name(self) -> str: + return self._username_email[0] + + @property + def email(self) -> str: + return self._username_email[1] + + @cached_property + def blobs(self) -> 'List[Blob]': + return [Blob(b) for b in self.get_list_values('a2b')] + + @cached_property + def commits(self) -> 'List[Commit]': + return [Commit(c) for c in self.get_list_values('a2c')] + + @cached_property + def files(self) -> 'List[File]': + return [File(f) for f in self.get_list_values('a2f')] + + @cached_property + def projects(self) -> 'List[Project]': + return [Project(p) for p in self.get_list_values('a2p')] + + +class UniqueAuthor(Author): + pass + + +class Blob(_GitObject): + @cached_property + def _pos(self) -> Tuple[int, int]: + return self.woc.get_pos('blob', self.key) + + def __len__(self) -> int: + return self._pos[1] + + @cached_property + def commits(self) -> 'List[Commit]': + return [Commit(sha) for sha in self.get_list_values('b2c')] + + @cached_property + def first_author(self) -> 'Tuple[datetime, Author, Commit]': + """ + Returns the timestamp, author, and commit of the first author. + >>> woc.get_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169')) + (datetime.datetime(2014, 9, 7, 2, 59, 48), Author(Audris Mockus ), Commit(e4af89166a17785c1d741b8b1d5775f3223f510f)) + """ + _out = self.woc.get_values('b2fa', self.key) + _date = datetime.fromtimestamp(int(_out[0])) + _author = Author(_out[1]) + _commit = Commit(_out[2]) + return _date, _author, _commit + + @cached_property + def time_author_commits(self) -> 'List[Tuple[datetime, Author, Commit]]': + _out = self.get_list_values('b2tac') + return [(datetime.fromtimestamp(int(d[0])), Author(d[1]), Commit(d[2])) for d in _out] + + @cached_property + def files(self) -> 'List[File]': + return [File(f) for f in self.get_list_values('b2f')] + + @cached_property + def projects_unique(self) -> 'List[UpstreamProject]': + return [UpstreamProject(p) for p in self.get_list_values('b2P')] + + +class Commit(_GitObject): + @cached_property + def data_obj(self): + _ret = {} + (_ret['tree'], + _ret['parent'], + (_ret['author'], _ret['author_timestamp'], _ret['author_timezone']), + (_ret['committer'], _ret['committer_timestamp'], _ret['committer_timezone']), + _ret['message'], + ) = self.data + return _ret + + @property + def author(self) -> Author: + return Author(self.data_obj['author']) + + @property + def authored_at(self) -> datetime: + tz = parse_timezone_offset(self.data_obj['author_timezone']) + return datetime.fromtimestamp(int(self.data_obj['author_timestamp']), tz) + + @property + def committer(self) -> Author: + return Author(self.data_obj['committer']) + + @property + def committed_at(self) -> datetime: + tz = parse_timezone_offset(self.data_obj['committer_timezone']) + return datetime.fromtimestamp(int(self.data_obj['committer_timestamp']), tz) + + @property + def full_message(self) -> str: + """Full message of the commit""" + return self.data_obj['message'] + + @property + def message(self) -> str: + """Short message of the commit""" + return self.data_obj['message'].split('\n', 1)[0] + + @cached_property + def tree(self) -> 'Tree': + return Tree(self.data_obj['tree']) + + @property + def parents(self) -> List['Commit']: + return [Commit(p) for p in self.data_obj['parent']] + + @cached_property + def projects(self) -> List['Project']: + """Projects associated with this commit""" + return [Project(p) for p in self.get_list_values('c2p')] + + @cached_property + def children(self) -> List['Commit']: + """Children of this commit""" + return [Commit(c) for c in self.get_list_values('c2cc')] + + @cached_property + def files(self) -> List['File']: + """Files changed in this commit""" + return [File(f) for f in self.get_list_values('c2f')] + + @cached_property + def blobs(self) -> List['Blob']: + """Blobs changed in this commit""" + return [Blob(b) for b in self.get_list_values('c2b')] + + @cached_property + def time_author(self) -> Tuple[datetime, Author]: + """Timestamp and author of the commit""" + res = self.woc.get_values('c2ta', self.key) + return datetime.fromtimestamp(int(res[0])), Author(res[1]) + + @cached_property + def root(self) -> 'Tuple[Commit, int]': + """Root commit of the project""" + sha, dis = self.woc.get_values('c2r', self.key) + return Commit(sha), int(dis) + + +class File(_NamedObject): + @property + def path(self) -> str: + return self.key + + @property + def name(self) -> str: + return self.key.split('/')[-1] + + @cached_property + def authors(self) -> List[Author]: + return [Author(a) for a in self.get_list_values('f2a')] + + @cached_property + def blobs(self) -> List[Blob]: + return [Blob(b) for b in self.get_list_values('f2b')] + + @cached_property + def commits(self) -> List[Commit]: + return [Commit(c) for c in self.get_list_values('f2c')] + + +class Tree(_GitObject): + @cached_property + def data(self) -> str: + return self.woc.show_content('tree', self.key) + + @cached_property + def _file_names(self) -> Set[str]: + return set(l[1] for l in self.data) + + @cached_property + def _blob_shas(self) -> Set[str]: + return set(l[2] for l in self.data) + + @property + def files(self) -> str: + return [File(f) for f in self._file_names] + + @property + def blobs(self) -> str: + return [Blob(b) for b in self._blob_shas] + + def traverse(self) -> 'Generator[Tuple[File, Blob], None, None]': + for mode, fname, sha in self.data: + # trees are always 40000: + # https://stackoverflow.com/questions/1071241 + if mode != '40000': + yield File(fname), Blob(sha) + else: + for _mode, _fname, _sha in Tree(sha).traverse(): + yield File(fname + '/' + _fname), Blob(_sha) + + def __contains__(self, item: Union[str, File, Blob]) -> bool: + if isinstance(item, str): + return item in self._file_names or item in self._blob_shas + if isinstance(item, File): + return item.text in self._file_names + if isinstance(item, Blob): + return item.hex in self._blob_shas + return False + + def __str__(self) -> str: + return '\n'.join([''.join(l) for l in self.data]) + + def __len__(self) -> int: + return len(self.data) + + +class Project(_NamedObject): + @property + def platform(self) -> str: + raise NotImplemented + + @property + def url(self) -> str: + raise NotImplemented + + @cached_property + def authors(self) -> 'List[Author]': + return [Author(a) for a in self.get_list_values('p2a')] + + @cached_property + def commits(self) -> 'List[Commit]': + return [Commit(c) for c in self.get_list_values('p2c')] + + @cached_property + def upstream_projects(self) -> 'List[UpstreamProject]': + return [UpstreamProject(p) for p in self.get_list_values('p2P')] + + +class UpstreamProject(Project): + @cached_property + def unique_authors(self) -> 'List[Author]': + return [UniqueAuthor(a) for a in self.get_list_values('P2A')] + + @cached_property + def commits(self) -> 'List[Commit]': + return [Commit(c) for c in self.get_list_values('P2c')] + + @cached_property + def projects(self) -> 'List[Project]': + return [Project(p) for p in self.get_list_values('P2p')] \ No newline at end of file From ade23abe151993df07c1e81363b5f3af43059eb5 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Fri, 7 Jun 2024 00:17:09 +0800 Subject: [PATCH 21/38] test: add tests for objects api --- tests/fixtures/c2taFullR.0.tch | Bin 0 -> 528784 bytes tests/fixtures/create_fixtures.py | 1 + tests/test_objects.py | 199 ++++++++++++++++++++++++++++++ tests/test_profile.json | 15 +++ 4 files changed, 215 insertions(+) create mode 100644 tests/fixtures/c2taFullR.0.tch create mode 100644 tests/test_objects.py diff --git a/tests/fixtures/c2taFullR.0.tch b/tests/fixtures/c2taFullR.0.tch new file mode 100644 index 0000000000000000000000000000000000000000..9ff541df4c2ae86eb79c9b3f7f66ca3063a24ad0 GIT binary patch literal 528784 zcmeIuF-ikL6b9fG3`iOY1T7@6*x7^~vB;`uG^J<|0yb%aNfA>7Oa`>H6hXX+*YF_T zzym}W6;h=azA0wjKaUw6UvGNx*v&hG^YPWFR}IbLuneJ^Ev@yG7K^oX_p@i&TWurd z_V2m$KuLfA0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oP8)P=8w4)+9iH009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PJ^)fsfa}ktu&p@-bG;ZS8 q?&') + commits = author.commits + assert all(isinstance(c, Commit) for c in commits) + assert commits[0].key == '001ec7302de3b07f32669a1f1faed74585c8a8dc' + +def test_author_files(woc): + author = Author('Audris Mockus ') + files = author.files + assert all(isinstance(f, File) for f in files) + assert files[0].key == '.#analyze.sh' + +def test_author_name_email(woc): + author = Author('Audris Mockus ') + assert author.name == 'Audris Mockus' + assert author.email == 'audris@utk.edu' + +def test_blob_data(woc): + blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + res = blob.data + assert len(res) == 14194 + +def test_blob_commits(woc): + blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + commits = blob.commits + assert all(isinstance(c, Commit) for c in commits) + assert commits[0].key == 'e4af89166a17785c1d741b8b1d5775f3223f510f' + +def test_blob_commits_large(woc): + blob = Blob('3f2eca18f1bc0f3117748e2cea9251e5182db2f7') + commits = blob.commits + assert all(isinstance(c, Commit) for c in commits) + assert commits[0].key == '00003a69db53b45a67f76632f33a93691da77197' + +def test_blob_first_author(woc): + blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + date, author, commit = blob.first_author + assert isinstance(date, datetime) + assert isinstance(author, Author) + assert isinstance(commit, Commit) + assert date.timestamp() == 1410029988 + assert date.tzinfo is None # naive datetime + assert author.key == 'Audris Mockus ' + assert commit.key == 'e4af89166a17785c1d741b8b1d5775f3223f510f' + +def test_blob_time_author_commits(woc): + blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + date, author, commit = blob.time_author_commits[0] + assert isinstance(date, datetime) + assert isinstance(author, Author) + assert isinstance(commit, Commit) + assert date.timestamp() == 1410029988 + assert date.tzinfo is None # naive datetime + assert author.key == 'Audris Mockus ' + assert commit.key == 'e4af89166a17785c1d741b8b1d5775f3223f510f' + +def test_blob_files(woc): + blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + files = blob.files + assert all(isinstance(f, File) for f in files) + assert files[0].key == 'README.md' + +def test_commit_author(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + author = commit.author + assert isinstance(author, Author) + assert author.key == 'Audris Mockus ' + +def test_commit_authored_at(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + authored_at = commit.authored_at + assert isinstance(authored_at, datetime) + assert authored_at.timestamp() == 1410029988 + assert authored_at.tzinfo is not None # aware datetime + +def test_commit_committer(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + committer = commit.committer + assert isinstance(committer, Author) + assert committer.key == 'Audris Mockus ' + +def test_commit_committed_at(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + committed_at = commit.committed_at + assert isinstance(committed_at, datetime) + assert committed_at.timestamp() == 1410029988 + assert committed_at.tzinfo is not None # aware datetime + +def test_commit_full_message(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + full_message = commit.full_message + assert full_message == 'News for Sep 5' + +def test_commit_message(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + message = commit.message + assert message == 'News for Sep 5' + +def test_commit_tree(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + tree = commit.tree + assert isinstance(tree, Tree) + assert tree.key == 'f1b66dcca490b5c4455af319bc961a34f69c72c2' + +def test_commit_parents(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + parents = commit.parents + assert all(isinstance(p, Commit) for p in parents) + assert parents[0].key == 'c19ff598808b181f1ab2383ff0214520cb3ec659' + +def test_commit_projects(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + projects = commit.projects + assert all(isinstance(p, Project) for p in projects) + assert projects[0].key == 'W4D3_news' + +def test_commit_children_null_filename(woc): + with pytest.raises(AssertionError): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + children = commit.children + +def test_commit_files(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + files = commit.files + assert all(isinstance(f, File) for f in files) + assert files[0].key == 'README.md' + +def test_commit_blobs(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + blobs = commit.blobs + assert blobs[0].key == '05fe634ca4c8386349ac519f899145c75fff4169' + assert all(isinstance(b, Blob) for b in blobs) + +def test_commit_time_author(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + time_author = commit.time_author + assert isinstance(time_author[0], datetime) + assert isinstance(time_author[1], Author) + assert time_author[0].timestamp() == 1410029988 + assert time_author[0].tzinfo is None # naive datetime + +def test_commit_root(woc): + commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + root, distance = commit.root + assert isinstance(root, Commit) + assert root.key == '9531fc286ef1f4753ca4be9a3bf76274b929cdeb' + assert distance == 27 + +def test_file_authors(woc): + file = File('youtube-statistics-analysis.pdf') + authors = file.authors + assert all(isinstance(a, Author) for a in authors) + assert authors[0].key == 'Audris Mockus ' + +def test_tree_files(woc): + tree = Tree('f1b66dcca490b5c4455af319bc961a34f69c72c2') + files = tree.files + assert all(isinstance(f, File) for f in files) + assert set(files) == set((File('README.md'), File('course.pdf'))), str(files) + +def test_tree_blobs(woc): + tree = Tree('f1b66dcca490b5c4455af319bc961a34f69c72c2') + blobs = tree.blobs + assert all(isinstance(b, Blob) for b in blobs) + assert Blob('05fe634ca4c8386349ac519f899145c75fff4169') in blobs + +def test_tree_traverse(woc): + tree = Tree('f1b66dcca490b5c4455af319bc961a34f69c72c2') + traverse = list(tree.traverse()) + assert all(isinstance(t[0], File) for t in traverse) + assert all(isinstance(t[1], Blob) for t in traverse) + assert traverse[0][0].key == 'README.md' + +def test_project_authors(woc): + project = Project('ArtiiQ_PocketMine-MP') + authors = project.authors + assert all(isinstance(a, Author) for a in authors) + assert authors[0].key == '0929hitoshi ' + +def test_project_commits(woc): + project = Project('ArtiiQ_PocketMine-MP') + commits = project.commits + assert all(isinstance(c, Commit) for c in commits) + assert commits[0].key == '0000000bab11354f9a759332065be5f066c3398f' \ No newline at end of file diff --git a/tests/test_profile.json b/tests/test_profile.json index 8553f17..65dc739 100644 --- a/tests/test_profile.json +++ b/tests/test_profile.json @@ -82,6 +82,21 @@ ] } ], + "c2ta": [ + { + "version": "R", + "sharding_bits": 1, + "shards": [ + "./tests/fixtures/c2taFullR.0.tch", + "./tests/fixtures/c2taFullR.1.tch" + ], + "larges": {}, + "dtypes": [ + "h", + "s" + ] + } + ], "b2tac": [ { "version": "U", From f69d242b03d624b3fd3db1d50eb79511eda19b62 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Fri, 7 Jun 2024 03:46:57 +0800 Subject: [PATCH 22/38] feat: port util methods from oscar.py Traversing project commits and trees now made easier --- tests/fixtures/commit_0.tch | Bin 528928 -> 530096 bytes tests/fixtures/commit_1.tch | Bin 0 -> 529936 bytes tests/fixtures/create_fixtures.py | 23 +- tests/fixtures/p2cFullR.1.tch | Bin 617872 -> 618032 bytes tests/fixtures/tree_0.tch | Bin 0 -> 529552 bytes tests/fixtures/tree_1.tch | Bin 528816 -> 529616 bytes tests/test_objects.py | 71 +++++- woc/objects.py | 398 ++++++++++++++++++++++++++---- 8 files changed, 439 insertions(+), 53 deletions(-) create mode 100644 tests/fixtures/commit_1.tch create mode 100644 tests/fixtures/tree_0.tch diff --git a/tests/fixtures/commit_0.tch b/tests/fixtures/commit_0.tch index ea731db5b3d5916b227d8ee4c924f8d504eb12ab..83081413587ff596d58b7334b7c6c3b7cce5b712 100644 GIT binary patch delta 1267 zcmaKqOK2oT7{_Op%_cS^x=S`75xdAq4V$g5?yBw%**HDPq|-B*nY?B)89b!AySmf! zp6;GkJPdnr1rcNs_ToXo!+LPpAZ8D_2zm$#lD&8k7UNOelZXq82gf`>K`bchEBI4< zzwcKce+nLc4nBa~<;dB3IB|RS%h_o0wdmBH$A?3MedW>P!(n+cI{(jmJ-5H};nbbu zLE?CjI6fSPV^Lv{9C}l~7rQ!g(m$%4zZe;cj6aG>_nkMg!jIqGomU^YcmMcvvHh9) z%{!B!&lnIb%OQ>;A}C9c3e;g1QA`nB;!V}060w-g9FZtogZiu%0%$7;DW-`qZ!tx+ zWG0J(B})P{EycoAVu+|C?t@mqe1sJh%zgDjBo-TaC77wzeb%V-W?V1a zZJ9Gxy*dvBEF)Q!!Oj(M17Zj{aQ$-C3qy7y>!X~*XgCW>b*~1(-Pp4cn}#%CVZfb| z9!*{Vk445$`q2lq>(A5grxQl!$zkT+FH=vR{`&0ekN8t!2TPWTF_IA?lp?4S5y}=+ zn1Elk2ttx#s){2Mk)!|JKmR}dLlF_u|C>PiH$jxMzaZQUaXxdtQ zEopa+gt4$5PszI_Udpyb-{@$Xy=)lTLaI^h)%*Dn<+J%hbBlH$5A8})=RnI`bx6qw z)|gw>YcS&qxT2>+U`n9t(Wml%}a}N$a}Dhv{a_q?1ZI_lGNYq`C1d_H%kqlx|MR^@rvM=Ts^T- z;DA@nCM#RoZZW5?#BaKC+g;iA`D{oEOTAvO>J^uk)6+1uE|n{(y;7kArTRiKyRPBQ2E6_q>8r$-0HT^1W$kQNTz?(<@Qv5 zCErGP+6Zy4D^m{m?oz64G!sm&=eOEhy#gQiGpjTqXyw{UnKljF^hYYMIw8eB{rfOe&Um% diff --git a/tests/fixtures/commit_1.tch b/tests/fixtures/commit_1.tch new file mode 100644 index 0000000000000000000000000000000000000000..2db11b6e72baaec7f5184260320f0e2b6b233c97 GIT binary patch literal 529936 zcmeI&J&fFF83*u$3wOEU5(N~(35qe&9YTa89@{e>N6Betzc+iyes4ai^Nc;av)S*= zWH;NO&|QHLLQqm6kPrePBpM1Rj=KO7P*a6#Xenr@!jfdsm56SopPSdOElbb;=jUqc+`CmSR%(~St68m9Iq`|()bri5XD6Rud*$Vwa~DoOKO6e&i}e!^I3+-U z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oN~t0_Pte^8m^x zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjY$t-##lV_Uky2@oJafB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oN|10&n?8=@`5vB@!S&fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7j<3LzA0O5J#)!2wS`_BhupMUg zI4a_#nG}`ne7D@}2U)F~6nWCArE#@PYTa(T8x~pFX_rwqOuKO&M_D6_<4z?Xob9h} z?FNGf-Wp2>BJkAZkhM52EC2#^>SnA!&4KJi(9+z{pIxh*urAanw_c~CH~L) zf{8ZYN37 zM$mXOJIwz)err(d_8tT`w>tL+4}xp?duOXdgZ}-?WifajIO-$ViW+!HYg{g^Kt;MDJ zv7rmqOO>D!>^&In47XatBdyll@Z61Je`@sZ$o%khy1G_PW*)}7Q+useF*!BW8VhfB zXUo}aWO8$BZN0shtyahHEZ$8j!A31#TRn((CnwU@_}EO^Sh>A7G8n&`RL7e)=59Zl zI~ZNNxX_tT`^#%{2M4v@PVHc!K0gZ4|NW~3+|&i5vhgF$#BolWmwX>K!utvhnGWiM83=QMNzU9PBLL+AH?9 z_p39_$#{EYJgiSGY(1<5?fdQK_~__TBWi^kqOXL57qMrZY4za3t$1lPNRa-;J2m!BHDHTt(Rzc^P}+Ai{b z8O)EhMsJQ?-YAax_r?0;D@XfNC(i%qF zd(qF$xX}%hqTY_vB#h&Btr0e(Ms_%yaW&8L!zPa!aUK@!qkcYY+_F~h9)1Iw)gmdL z4`5mp?RHXTX_-Y)QIwss-A(_md5)4Ot^E)4{K|IJ`Fe2bR37A;Mey3|{a|ma^WVAt EH-8U!SO5S3 literal 0 HcmV?d00001 diff --git a/tests/fixtures/create_fixtures.py b/tests/fixtures/create_fixtures.py index 054e3ae..c269156 100644 --- a/tests/fixtures/create_fixtures.py +++ b/tests/fixtures/create_fixtures.py @@ -112,12 +112,12 @@ def copy_content(self, obj: str, key: Union[bytes, str]): if obj == 'tree': _map_obj = self.config2['objects']['tree.tch'] print('writing to tch', key, _map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) + write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) elif obj == 'commit': _map_obj = self.config2['objects']['commit.tch'] print('writing to tch', key ,_map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) + write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) elif obj == 'blob': # read blob @@ -174,3 +174,22 @@ def copy_content(self, obj: str, key: Union[bytes, str]): cp.copy_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') cp.copy_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') cp.copy_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') + # woc-hack_thebridge + cp.copy_values('p2c', 'woc-hack_thebridge') + cp.copy_content('commit', '0d8228bb25ce89c7e731c7410bc8c5a4e2636e52') + cp.copy_content('commit', '34a8662a4f31dacb923e39ae6792f6fc4476a939') + cp.copy_content('commit', '898d5a21241aaf16acf92566aa34103d06cf2ac6') + cp.copy_content('commit', '91f4da4c173e41ffbf0d9ecbe2f07f3a3296933c') + cp.copy_content('commit', 'ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7') + cp.copy_content('commit', 'f249b14a111279faa8d65c29ecf46bb6ce59a139') + cp.copy_content('tree', '706aa4dedb560358bff21c3120a0b09532d3484d') + cp.copy_content('tree', '3ccf6f8320740a1afec68b38b3b9ba46cedef368') + cp.copy_content('tree' ,'e5798457aebae7c84eff7b80b50c3a938cc4cb63') + cp.copy_content('tree', '836f04d5b374033b1608269e2f3aaabae263a0db') + cp.copy_content('tree', 'f54cb5527226aa2096307c08e15c62248b98f763') + cp.copy_content('tree', 'da65e1401d11a955686b8a49e46b9a457f3febab') + cp.copy_content('tree', 'a28f1558be9867d35cc1fa17477565c08786cf83') + cp.copy_content('tree', '4db2ad30097924cbe5da9c0f2c49350fdc19c3a4') + cp.copy_content('tree', '1cf86145b4a9492ebbe0fa640638504946315ca6') + cp.copy_content('tree', '29a422c19251aeaeb907175e9b3219a9bed6c616') + cp.copy_content('tree', '51968a7a4e67fd2696ffd5ccc041560a4d804f5d') diff --git a/tests/fixtures/p2cFullR.1.tch b/tests/fixtures/p2cFullR.1.tch index 5566dc9e32b313b4ad9c8705e7d3cf34d95028d9..079c4e867f65573747548482504a534043519b03 100644 GIT binary patch delta 227 zcmbPmTXn-7)d>b%ObifUkk@F{YQ@-U#nfuWyw!@O%9`osw8p^JK*p_sOw1CE30o5w z+xNCR2y$$95abMqsXyTe)ycrYAXHJFpRAjan4BG7l98HJl$nyA%G;!|TlHM$@#lue z9l1{&UGgY7FUVv?nwG!et<#h2EZ3z^`u4}AY^7yqZydo7dkzd2aL)6sr8S T;#!R6n=jeh&P6V?ggFZUwv1Uv delta 62 zcmdmRM|Hw&)d>b%j0_MkA-B=0)rzszimBC#d8-vmm33o6YXale1g0=m6kWEEXcFhbTx!fyLth8n|b;h)bEsK?mdE4fgcir8YE2s^j z%z~oKL@jiUz$97P7nhlHG>4g1W`zx%krX6|<%dwqY;L4bU!)Jpp7+Z+=Y4q(zu$At zg2V&0^TPKP-&;O6z92moiQaifES4Tz_Vn#qUAU0e_3p;*FRy0y@0#TdyEI<*gDC+5 z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjYijX-97uc@ji0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PJs(fvNSqu(Zkq2oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5V(c~!u8j1IME0YAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjZBD}jmi*Hv6$2@oJafB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAkZrXrq}n%+Da23 zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+0D~N&CJXK!0G?9!48&0=$PH+Ap zmVI}}$o=a>&vYISSL}?{O~{&`JLCTR+(_l(;J~1-W|qV^)jd2d*s%9Zw4v_IcV*ep zaF7))ElVYm$@tRLqUv~ZS$Ro3Xn1A#!d+`i4;8hX9XTsh6W{&9^9NVd-QMS^L`i2b zA!E$%#kn7D&Wn81d3JGV>VtVRV@2;?%H1BmBLB35i51~g`shE~UYfdnNAt`BM}I53 z+WhBJcdh(sc;yr0vf9o)vV2PD)0dO0|0{pNnpIEFE&b!xH5U%=-yND!n4VuZ@3DXK z=WlyII-vHJ&rTfKFmz(xk@)ePvBNe$R93Mn@5hRDxzFA6%a*In zpE3D-^X%q=;M=tITi-dBlL$ZCZ|DD?|6EW0fkEc@D~_@I6oc-|Q(RRQsj3aWn3KJ! zW9Zwf=MA2}a$VE5+`XgsE$i9h;@G~gXE8X)JeBru2fyd_p8MFnWz+7ChLa5=hO}p$ z9(b~_sCGz2pU9iBx^aCI)g{HrobefvC6A_R-uqzef&O1d6Q2**z9^$+`^NEE$@r5s z<;i&E#fw-SNi9zW!{#g;>)7Y;hn6lyy*`^%62Cc7zIohnY1mjt&p-rVw9 Z!Pc!i`i*>i{iIQwcYV_~q9<_I_!n*eNAmyx literal 0 HcmV?d00001 diff --git a/tests/fixtures/tree_1.tch b/tests/fixtures/tree_1.tch index 0129d7c7da55503186918f84100d5dc5657416c1..4b67e5b10ae0457553ea2fea547883236fb78a2c 100644 GIT binary patch delta 900 zcmdn6SmDA-g$V{+>T*{fsCuxG1)h63~bxYgRh&C{J%w3CI$)&@(Sr0 zCHX}~sd**w^~I@0WtqvT41v?Ss{GRbs!jWU^~?b_$1pD62LIRwZKm@4AL@FDClMYv$8*UoIdx$}xDCUc<6jIGHGH{|VPXIT3P4xI!(1-&BhhusN>9Dr z4}PVvSp;~x8OAJwISE9cSPkPbF^Kql_1PL!q_#?7nn4Z6!Lx4WefU!9kMAA@_ z1~g^lz') commits = author.commits @@ -180,11 +184,10 @@ def test_tree_blobs(woc): assert Blob('05fe634ca4c8386349ac519f899145c75fff4169') in blobs def test_tree_traverse(woc): - tree = Tree('f1b66dcca490b5c4455af319bc961a34f69c72c2') + tree = Tree('706aa4dedb560358bff21c3120a0b09532d3484d') traverse = list(tree.traverse()) assert all(isinstance(t[0], File) for t in traverse) assert all(isinstance(t[1], Blob) for t in traverse) - assert traverse[0][0].key == 'README.md' def test_project_authors(woc): project = Project('ArtiiQ_PocketMine-MP') @@ -196,4 +199,62 @@ def test_project_commits(woc): project = Project('ArtiiQ_PocketMine-MP') commits = project.commits assert all(isinstance(c, Commit) for c in commits) - assert commits[0].key == '0000000bab11354f9a759332065be5f066c3398f' \ No newline at end of file + assert commits[0].key == '0000000bab11354f9a759332065be5f066c3398f' + +def test_project_url(woc): + project = Project('ArtiiQ_PocketMine-MP') + assert project.url == 'https://github.com/ArtiiQ/PocketMine-MP' + project = Project('sourceforge.net_peazip') # <- How does sourceforge repos looks like in woc? + assert project.url == 'https://git.code.sf.net/p/peazip' + project = Project("gitlab.com_openRGB_openRGB") + assert project.url == 'https://gitlab.com/openRGB/openRGB' + +def test_project_head(woc): + project = Project('woc-hack_thebridge') + head = project.head + assert isinstance(head, Commit) + assert head.key == 'f249b14a111279faa8d65c29ecf46bb6ce59a139' + +def test_project_tail(woc): + project = Project('woc-hack_thebridge') + tail = project.tail + assert isinstance(tail, Commit) + assert tail.key == 'ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7' + +def test_project_earliest(woc): + project = Project('woc-hack_thebridge') + earliest = project.earliest_commit + assert isinstance(earliest, Commit) + assert earliest.key == 'ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7' + +def test_project_latest(woc): + project = Project('woc-hack_thebridge') + latest = project.latest_commit + assert isinstance(latest, Commit) + assert latest.key == 'f249b14a111279faa8d65c29ecf46bb6ce59a139' + +def test_project_walk(woc): + project = Project('woc-hack_thebridge') + commits = list(project.commits_fp()) + assert all(isinstance(c, Commit) for c in commits) + assert len(commits) == 6 + +def test_commit_compare(woc): + c1 = Commit('91f4da4c173e41ffbf0d9ecbe2f07f3a3296933c') + c2 = Commit('ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7') + + # We can't test fuzz matching because blob storage is broken :( + diff = list(c1.compare(c2, threshold=1)) + modified_files = set(f[0].key for f in diff if f[0] is not None) | \ + set(f[1].key for f in diff if f[1] is not None) + assert all(len(d) == 4 for d in diff) + assert all(isinstance(d[0], File) for d in diff if d[0] is not None) + assert all(isinstance(d[1], File) for d in diff if d[1] is not None) + assert all(isinstance(d[2], Blob) for d in diff if d[2] is not None) + assert all(isinstance(d[3], Blob) for d in diff if d[3] is not None) + assert modified_files == { + 'README.md', 'woc_service/requirements.txt', 'woc_service/app.py', + 'woc_service/static/.keep', 'woc_service/oscar.py' + } + + \ No newline at end of file diff --git a/woc/objects.py b/woc/objects.py index 7489d18..48ee206 100644 --- a/woc/objects.py +++ b/woc/objects.py @@ -1,17 +1,23 @@ import re -from typing import Union, Optional, List, Tuple, Set, Generator +import warnings +import difflib +from typing import Union, Optional, List, Tuple, Set, Generator, Dict from functools import cached_property, lru_cache from datetime import datetime, timezone, timedelta +from logging import getLogger from .base import WocMapsBase from .local import fnvhash _global_woc: Optional[WocMapsBase] = None +logger = getLogger(__name__) +DAY_Z = datetime.fromtimestamp(0, tz=None) -def init_woc(woc: WocMapsBase): +def init_woc_objects(woc: WocMapsBase): global _global_woc _global_woc = woc + @lru_cache(maxsize=None) def parse_timezone_offset(offset_str): """ @@ -31,6 +37,7 @@ def parse_timezone_offset(offset_str): class _WocObject: + ident: str # Identifier of the object woc: WocMapsBase # WocMap instance key: str # Key of the object @@ -41,7 +48,8 @@ def __init__( **kwargs, ): self.woc = woc or _global_woc - assert self.woc is not None, "WocMaps not initialized: call init_woc() or supply a woc argument" + assert self.woc is not None, \ + "WocMaps not initialized: call init_woc_objects() or supply a woc keyword argument" def __repr__(self) -> str: return f"{self.__class__.__name__}({self.key})" @@ -54,10 +62,11 @@ def __eq__(self, value: object) -> bool: return False return self.key == value.key + @property def hash(self) -> str: return hex(hash(self))[2:] - def get_list_values(self, map_name: str): + def _get_list_values(self, map_name: str): try: return self.woc.get_values(map_name, self.key) except KeyError: @@ -85,6 +94,7 @@ def data(self): def __hash__(self): return int(self.key, 16) + @property def hash(self) -> str: return self.key @@ -106,6 +116,7 @@ def __hash__(self): class Author(_NamedObject): + ident = 'a' @cached_property def _username_email(self) -> Tuple[str, str]: _splited = self.key.split(' <', 1) @@ -123,26 +134,28 @@ def email(self) -> str: @cached_property def blobs(self) -> 'List[Blob]': - return [Blob(b) for b in self.get_list_values('a2b')] + return [Blob(b) for b in self._get_list_values('a2b')] @cached_property def commits(self) -> 'List[Commit]': - return [Commit(c) for c in self.get_list_values('a2c')] + return [Commit(c) for c in self._get_list_values('a2c')] @cached_property def files(self) -> 'List[File]': - return [File(f) for f in self.get_list_values('a2f')] + return [File(f) for f in self._get_list_values('a2f')] @cached_property def projects(self) -> 'List[Project]': - return [Project(p) for p in self.get_list_values('a2p')] + return [Project(p) for p in self._get_list_values('a2p')] class UniqueAuthor(Author): + ident = 'A' pass class Blob(_GitObject): + ident = 'b' @cached_property def _pos(self) -> Tuple[int, int]: return self.woc.get_pos('blob', self.key) @@ -150,9 +163,12 @@ def _pos(self) -> Tuple[int, int]: def __len__(self) -> int: return self._pos[1] + def __str__(self) -> str: + return self.data + @cached_property def commits(self) -> 'List[Commit]': - return [Commit(sha) for sha in self.get_list_values('b2c')] + return [Commit(sha) for sha in self._get_list_values('b2c')] @cached_property def first_author(self) -> 'Tuple[datetime, Author, Commit]': @@ -169,19 +185,20 @@ def first_author(self) -> 'Tuple[datetime, Author, Commit]': @cached_property def time_author_commits(self) -> 'List[Tuple[datetime, Author, Commit]]': - _out = self.get_list_values('b2tac') + _out = self._get_list_values('b2tac') return [(datetime.fromtimestamp(int(d[0])), Author(d[1]), Commit(d[2])) for d in _out] @cached_property def files(self) -> 'List[File]': - return [File(f) for f in self.get_list_values('b2f')] + return [File(f) for f in self._get_list_values('b2f')] @cached_property - def projects_unique(self) -> 'List[UpstreamProject]': - return [UpstreamProject(p) for p in self.get_list_values('b2P')] + def projects_unique(self) -> 'List[RootProject]': + return [RootProject(p) for p in self._get_list_values('b2P')] class Commit(_GitObject): + ident = 'c' @cached_property def data_obj(self): _ret = {} @@ -225,6 +242,10 @@ def message(self) -> str: def tree(self) -> 'Tree': return Tree(self.data_obj['tree']) + @property + def _parent_shas(self) -> List[str]: + return self.data_obj['parent'] + @property def parents(self) -> List['Commit']: return [Commit(p) for p in self.data_obj['parent']] @@ -232,22 +253,43 @@ def parents(self) -> List['Commit']: @cached_property def projects(self) -> List['Project']: """Projects associated with this commit""" - return [Project(p) for p in self.get_list_values('c2p')] + return [Project(p) for p in self._get_list_values('c2p')] @cached_property def children(self) -> List['Commit']: """Children of this commit""" - return [Commit(c) for c in self.get_list_values('c2cc')] + return [Commit(c) for c in self._get_list_values('c2cc')] + + @cached_property + def _file_names(self) -> List[str]: + return self._get_list_values('c2f') + + @cached_property + def _file_set(self) -> Set[str]: + return set(self._file_names) @cached_property def files(self) -> List['File']: """Files changed in this commit""" - return [File(f) for f in self.get_list_values('c2f')] + return [File(f) for f in self._file_names] + + @cached_property + def _blob_shas(self) -> List[str]: + return self._get_list_values('c2b') + + @cached_property + def _blob_set(self) -> Set[str]: + return set(self._blob_shas) @cached_property def blobs(self) -> List['Blob']: - """Blobs changed in this commit""" - return [Blob(b) for b in self.get_list_values('c2b')] + """ + Blobs changed in this commit. + This relation is known to miss every first file in all trees. + Consider using Commit.tree.blobs as a slower but more accurate + alternative. + """ + return [Blob(b) for b in self._get_list_values('c2b')] @cached_property def time_author(self) -> Tuple[datetime, Author]: @@ -260,9 +302,113 @@ def root(self) -> 'Tuple[Commit, int]': """Root commit of the project""" sha, dis = self.woc.get_values('c2r', self.key) return Commit(sha), int(dis) + + def compare( + self, + parent: Union['Commit', str], + threshold=0.5 + ) -> Generator[Tuple[Optional['File'], Optional['File'], Optional['Blob'], Optional['Blob']], None, None]: + """ Compare two Commits. + + Args: + parent (Commit): another commit to compare to. + Expected order is `diff = child_commit - parent_commit` + + Yields: + Tuple[Optional[str], Optional[str], Optional[str], Optional[str]]: + 4-tuples: `(old_path, new_path, old_sha, new_sha)` + + Examples: + - a new file 'setup.py' was created: + `(None, 'setup.py', None, 'file_sha')` + - an existing 'setup.py' was deleted: + `('setup.py', None, 'old_file_sha', None)` + - setup.py.old was renamed to setup.py, content unchanged: + `('setup.py.old', 'setup.py', 'file_sha', 'file_sha')` + - setup.py was edited: + `('setup.py', 'setup.py', 'old_file_sha', 'new_file_sha')` + - setup.py.old was edited and renamed to setup.py: + `('setup.py.old', 'setup.py', 'old_file_sha', 'new_file_sha')` + + Detecting the last one is computationally expensive. You can adjust this + behaviour by passing the `threshold` parameter, which is 0.5 by default. + It means that if roughly 50% of the file content is the same, + it is considered a match. `threshold=1` means that only exact + matches are considered, effectively disabling this comparison. + If threshold is set to 0, any pair of deleted and added file will be + considered renamed and edited; this last case doesn't make much sense so + don't set it too low. + """ + if isinstance(parent, str): + parent = Commit(parent) + if not isinstance(parent, Commit): + raise TypeError("parent must be a Commit or a commit hash") + + # # filename: (blob sha before, blob sha after) + # new_files = self.tree._file_blob_map + # new_paths = self.tree._file_set + # old_files = parent.tree._file_blob_map + # old_paths = parent.tree._file_set + + # !!! We really need to traverse the trees ### + new_files: Dict[File, Blob] = {} + for f, b in self.tree.traverse(): + new_files[f] = b + old_files: Dict[File, Blob] = {} + for f, b in parent.tree.traverse(): + old_files[f] = b + + # unchanged_paths + for f in new_files.keys() & old_files.keys(): + if new_files[f] != old_files[f]: + # i.e. Blob sha Changed! + yield f, f, old_files[f], new_files[f] + + added_paths: Set[File] = new_files.keys() - old_files.keys() + deleted_paths: Set[File] = old_files.keys() - new_files.keys() + + if threshold >= 1: # i.e. only exact matches are considered + for f in added_paths: # add + yield None, f, None, new_files[f] + for f in deleted_paths: + yield f, None, old_files[f], None + return + + if parent.hash not in self._parent_shas: + warnings.warn("Comparing non-adjacent commits might be " + "computationally expensive. Proceed with caution.") + + # search for matches + sm = difflib.SequenceMatcher() + # for each added blob, try to find a match in deleted blobs + # if there is a match, signal a rename and remove from deleted + # if there is no match, signal a new file + # unused deleted blobs are indeed deleted + for added_file, added_blob in new_files.items(): + sm.set_seq1(added_blob.data) + matched = False + for deleted_file, deleted_blob in old_files.items(): + sm.set_seq2(deleted_blob.data) + # use quick checks first (lower bound by length diff) + if sm.real_quick_ratio() > threshold \ + and sm.quick_ratio() > threshold \ + and sm.ratio() > threshold: + yield deleted_file, added_file, deleted_blob, added_blob + del(old_files[deleted_file]) + matched = True + break + if not matched: # this is a new file + yield None, added_file, None, added_blob + + for deleted_file, deleted_blob in old_files.items(): + yield deleted_file, None, deleted_blob, None + + def __sub__(self, parent: 'Commit'): + return self.compare(parent) class File(_NamedObject): + ident = 'f' @property def path(self) -> str: return self.key @@ -273,47 +419,66 @@ def name(self) -> str: @cached_property def authors(self) -> List[Author]: - return [Author(a) for a in self.get_list_values('f2a')] + return [Author(a) for a in self._get_list_values('f2a')] @cached_property def blobs(self) -> List[Blob]: - return [Blob(b) for b in self.get_list_values('f2b')] + return [Blob(b) for b in self._get_list_values('f2b')] @cached_property def commits(self) -> List[Commit]: - return [Commit(c) for c in self.get_list_values('f2c')] + return [Commit(c) for c in self._get_list_values('f2c')] class Tree(_GitObject): + ident = 't' + @cached_property def data(self) -> str: return self.woc.show_content('tree', self.key) - @cached_property - def _file_names(self) -> Set[str]: - return set(l[1] for l in self.data) + @property + def _file_names(self) -> List[str]: + return [l[1] for l in self.data] @cached_property - def _blob_shas(self) -> Set[str]: - return set(l[2] for l in self.data) + def _file_set(self) -> Set[str]: + return set(l[1] for l in self.data) @property - def files(self) -> str: + def files(self) -> List['File']: return [File(f) for f in self._file_names] @property - def blobs(self) -> str: + def _blob_shas(self) -> List[str]: + return [l[2] for l in self.data] + + @cached_property + def _blob_set(self) -> Set[str]: + return set(l[2] for l in self.data) + + @property + def blobs(self) -> List['Blob']: return [Blob(b) for b in self._blob_shas] - def traverse(self) -> 'Generator[Tuple[File, Blob], None, None]': + @cached_property + def _file_blob_map(self) -> Dict[str, str]: + return {l[1]: l[2] for l in self.data} + + def _traverse(self) -> 'Generator[Tuple[str, str], None, None]': for mode, fname, sha in self.data: # trees are always 40000: # https://stackoverflow.com/questions/1071241 if mode != '40000': - yield File(fname), Blob(sha) + yield fname, sha else: - for _mode, _fname, _sha in Tree(sha).traverse(): - yield File(fname + '/' + _fname), Blob(_sha) + logger.debug(f"traverse: into {fname} ({sha})") + for _fname, _sha in Tree(sha)._traverse(): + yield fname + '/' + _fname, _sha + + def traverse(self) -> 'Generator[Tuple[File, Blob], None, None]': + for fname, sha in self._traverse(): + yield File(fname), Blob(sha) def __contains__(self, item: Union[str, File, Blob]) -> bool: if isinstance(item, str): @@ -325,43 +490,184 @@ def __contains__(self, item: Union[str, File, Blob]) -> bool: return False def __str__(self) -> str: - return '\n'.join([''.join(l) for l in self.data]) + return '\n'.join([' '.join(l) for l in self.data]) def __len__(self) -> int: return len(self.data) + + def __iter__(self) -> 'Generator[Tuple[File, Blob], None, None]': + for l in self.data: + yield File(l[1]), Blob(l[2]) class Project(_NamedObject): - @property - def platform(self) -> str: - raise NotImplemented - + ident = 'p' + + @cached_property + def _platform_repo(self) -> str: + URL_PREFIXES = self.woc.config["sites"] + prefix, body = self.key.split('_', 1) + if prefix == 'sourceforge.net': + platform = URL_PREFIXES[prefix] + elif prefix in URL_PREFIXES and '_' in body: + platform = URL_PREFIXES[prefix] + body = body.replace('_', '/', 1) + else: + platform = 'github.com' + body = self.key.replace('_', '/', 1) + return platform, body + @property def url(self) -> str: - raise NotImplemented + """ Get the URL for a given project URI + >>> Project('CS340-19_lectures').url + 'http://github.com/CS340-19/lectures' + """ + platform, body = self._platform_repo + URL_PREFIXES = self.woc.config["sites"] + if platform in URL_PREFIXES: + return f"https://{URL_PREFIXES[platform]}/{body}" + return f"https://{platform}/{body}" @cached_property def authors(self) -> 'List[Author]': - return [Author(a) for a in self.get_list_values('p2a')] + return [Author(a) for a in self._get_list_values(f'{self.ident}2a')] + + @cached_property + def _commit_shas(self) -> 'List[str]': + return self._get_list_values(f'{self.ident}2c') + + @cached_property + def _commit_set(self) -> 'Set[str]': + return self._commit_map.keys() + + @cached_property + def _commit_map(self) -> 'Dict[str, Commit]': + return {c.hash: c for c in self.commits} @cached_property def commits(self) -> 'List[Commit]': - return [Commit(c) for c in self.get_list_values('p2c')] + return [Commit(c) for c in self._commit_shas] @cached_property - def upstream_projects(self) -> 'List[UpstreamProject]': - return [UpstreamProject(p) for p in self.get_list_values('p2P')] + def root_projects(self) -> 'List[RootProject]': + return [RootProject(p) for p in self._get_list_values(f'{self.ident}2P')] + + def __contains__(self, item: Union[str, Commit]) -> bool: + if isinstance(item, str): + return item in self._commit_set + elif isinstance(item, Commit): + return item.hash in self._commit_set + return False + @cached_property + def head(self) -> 'Commit': + """ Get the HEAD commit of the repository + + >>> Project('user2589_minicms').head + Commit(f2a7fcdc51450ab03cb364415f14e634fa69b62c) + >>> Project('RoseTHERESA_SimpleCMS').head + Commit(a47afa002ccfd3e23920f323b172f78c5c970250) + """ + # Sometimes (very rarely) commit dates are wrong, so the latest commit + # is not actually the head. The magic below is to account for this + parents = set().union(*(c._parent_shas for c in self.commits)) + heads = [self._commit_map[c] for c in self._commit_set - parents] + + # it is possible that there is more than one head. + # E.g. it happens when HEAD is moved manually (git reset) + # and continued with a separate chain of commits. + # in this case, let's just use the latest one + # actually, storing refs would make it much simpler + _heads_sorted = sorted(heads, key=lambda c: c.authored_at or DAY_Z, reverse=True) + if len(_heads_sorted) == 0: + raise ValueError("No head commit found") + return _heads_sorted[0] + + @cached_property + def tail(self) -> 'Commit': + """ Get the first commit SHA by following first parents + + >>> Project(b'user2589_minicms').tail + Commit(1e971a073f40d74a1e72e07c682e1cba0bae159b) + """ + pts = set(c._parent_shas[0] for c in self.commits if c._parent_shas) + for c in self.commits: + if c.hash in pts and not c._parent_shas: + return c + + @cached_property + def earliest_commit(self) -> 'Commit': + """Get the earliest commit of the repository""" + return min(self.commits, key=lambda c: c.authored_at or DAY_Z) + + @cached_property + def latest_commit(self) -> 'Commit': + """Get the latest commit of the repository""" + return max(self.commits, key=lambda c: c.authored_at or DAY_Z) + + def commits_fp(self) -> Generator['Commit', None, None]: + """ Get a commit chain by following only the first parent, to mimic + https://git-scm.com/docs/git-log#git-log---first-parent . + Thus, you only get a small subset of the full commit tree: + + >>> p = Project(b'user2589_minicms') + >>> set(c.sha for c in p.commits_fp).issubset(p.commit_shas) + True + + In scenarios where branches are not important, it can save a lot + of computing. + + Yields: + Commit: binary commit shas, following first parent only, + from the latest to the earliest. + """ + # Simplified version of self.head(): + # - slightly less precise, + # - 20% faster + # + # out of 500 randomly sampled projects, 493 had the same head. + # In the remaining 7: + # 2 had the same commit chain length, + # 3 had one more commit + # 1 had two more commits + # 1 had three more commits + # Execution time: + # simplified version (argmax): ~153 seconds + # self.head(): ~190 seconds + + # at this point we know all commits are in the dataset + # (validated in __iter___) + commit = self.latest_commit + + while commit: + # no point try-except: the truth value of a list is len(list) + first_parent = commit._parent_shas and commit._parent_shas[0] + yield commit + if not first_parent: + break + commit = self._commit_map.get(first_parent, Commit(first_parent)) + + def __iter__(self) -> 'Generator[Commit, None, None]': + for c in self.commits: + try: + if c.author in self.woc.config['ignoredAuthors']: + continue + yield c + except KeyError: + pass + +class RootProject(Project): + ident = 'P' -class UpstreamProject(Project): @cached_property def unique_authors(self) -> 'List[Author]': - return [UniqueAuthor(a) for a in self.get_list_values('P2A')] + return [UniqueAuthor(a) for a in self._get_list_values(f'{self.ident}2A')] @cached_property def commits(self) -> 'List[Commit]': - return [Commit(c) for c in self.get_list_values('P2c')] + return [Commit(c) for c in self._get_list_values(f'{self.ident}2C')] @cached_property def projects(self) -> 'List[Project]': - return [Project(p) for p in self.get_list_values('P2p')] \ No newline at end of file + return [Project(p) for p in self._get_list_values(f'{self.ident}2p')] \ No newline at end of file From 30477c606a54cd977b76398d13b9e98638df8800 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Sun, 9 Jun 2024 05:00:20 +0800 Subject: [PATCH 23/38] feat: get_values support for (o)bb2cf & c2fbb TODO: remove the quirk for bb2cf once upstream fixes --- woc/detect.py | 4 +--- woc/local.pyx | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/woc/detect.py b/woc/detect.py index ca47a6d..2f0de93 100644 --- a/woc/detect.py +++ b/woc/detect.py @@ -115,9 +115,7 @@ def infer_dtype(map_name: str) -> Tuple[str, str]: if ent_all in ('b2baddate', 'b2manyp'): dtype_in, dtype_out = 's', 'h' if ent_all in ('c2fbb', 'obb2cf', 'bb2cf'): - dtype_in, dtype_out = 'h', 'cs' - if ent_all in ('c2fbb', 'obb2cf', 'bb2cf'): - dtype_in, dtype_out = 'h', 'cs' + dtype_in, dtype_out = 'h', 'cs3' if ent_all in ('c2dat',): dtype_in, dtype_out = 'h', 's' if ent_all in ('b2tac',): diff --git a/woc/local.pyx b/woc/local.pyx index a111881..17260d5 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -200,6 +200,7 @@ cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys): return prefix cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys): + """DEPRECATED""" # not 100% necessary but there are cases where some tchs are miserably missing _shard = get_shard(key, sharding_bits, use_fnv_keys) _path = shards[_shard] @@ -585,21 +586,21 @@ class WocMapsLocal(WocMapsBase): if in_dtype == 'h': if isinstance(key, str): - _hex = key + hex_str = key key = bytes.fromhex(key) else: - _hex = bytes(key).hex() + hex_str = bytes(key).hex() else: assert isinstance(key, str), "key must be a string for non-hash keys" - _hex = hex(fnvhash(key.encode('utf-8')))[2:] + hex_str = hex(fnvhash(key.encode('utf-8')))[2:] key = key.encode('utf-8') - logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") + logger.debug(f"hash: hex={hex_str} in {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() - if "larges" in _map and _hex in _map["larges"]: - _bytes = read_large(_map["larges"][_hex], out_dtype) - logger.debug(f"read large: {(time.time_ns() - start_time) / 1e6:.2f}ms") + if "larges" in _map and hex_str in _map["larges"]: + _bytes = read_large(_map["larges"][hex_str], out_dtype) + logger.debug(f"read large: file={_map['larges'][hex_str]} in {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() # compress string data is not compressed in larges @@ -607,8 +608,20 @@ class WocMapsLocal(WocMapsBase): out_dtype = 's' else: # use fnv hash as shading idx if key is not a git sha - _bytes = get_from_tch(key, _map["shards"], _map["sharding_bits"], in_dtype != 'h') - logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + _shard = get_shard(key, _map["sharding_bits"], in_dtype != 'h') + _path = _map["shards"][_shard] + assert _path, f"shard {_shard} not found at {_path}" + + _tch = get_tch(_path.encode('utf-8')) + + # TODO: remove bb2cf quirk after fixing tch keys + # bb2cf: keys are stored as hex strings in tch db + if map_name == 'bb2cf': + key = key.hex().encode('ascii') + + _bytes = _tch[key] + + logger.debug(f"get from tch: shard={_shard} db={_path} in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _bytes, out_dtype @@ -624,7 +637,7 @@ class WocMapsLocal(WocMapsBase): _bytes, decode_dtype = self._get_tch_bytes(map_name, key) start_time = time.time_ns() _decoded = decode_value(_bytes, decode_dtype) - logger.debug(f"decode: {(time.time_ns() - start_time) / 1e6:.2f}ms") + logger.debug(f"decode: in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _decoded def _get_pos( @@ -712,19 +725,19 @@ class WocMapsLocal(WocMapsBase): if obj_name == 'tree': _ret = decode_tree(decomp_or_raw(self._get_tch_bytes(obj_name, key)[0])) - logger.debug(f"decode tree: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") + logger.debug(f"decode tree: len={len(_ret)} in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret elif obj_name == 'commit': _ret = decode_commit(decomp_or_raw(self._get_tch_bytes(obj_name, key)[0])) - logger.debug(f"decode commit: {len(_ret)}items {(time.time_ns() - start_time) / 1e6:.2f}ms") + logger.debug(f"decode commit: len={len(_ret)}items in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret elif obj_name == 'blob': key = bytes.fromhex(key) if isinstance(key, str) else key offset, length = self._get_pos('blob', key) - logger.debug(f"pos: offset={offset} len={length} {(time.time_ns() - start_time) / 1e6:.2f}ms") + logger.debug(f"decode pos: offset={offset} len={length} in {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() _map_obj = self.config['objects']['blob.bin'] @@ -733,7 +746,7 @@ class WocMapsLocal(WocMapsBase): with open(_map_obj['shards'][shard], "rb") as f: f.seek(offset) _out_bin = f.read(length) - logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") + logger.debug(f"read blob: in {(time.time_ns() - start_time) / 1e6:.2f}ms") start_time = time.time_ns() return decode_str(decomp_or_raw(_out_bin)) From 86bc8df81b36618fb0128cbb8a17e5df7126ed11 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Sun, 9 Jun 2024 05:26:44 +0800 Subject: [PATCH 24/38] feat: add c2fbb, (o)bb2cf and other maps to oop api --- woc/objects.py | 71 +++++++++++++++++++++++++++++++++---- woc/wocprofile.default.json | 5 ++- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/woc/objects.py b/woc/objects.py index 48ee206..6dcd453 100644 --- a/woc/objects.py +++ b/woc/objects.py @@ -67,6 +67,7 @@ def hash(self) -> str: return hex(hash(self))[2:] def _get_list_values(self, map_name: str): + """ A thin wrapper around WocMapsBase.get_values to handle KeyError """ try: return self.woc.get_values(map_name, self.key) except KeyError: @@ -134,24 +135,45 @@ def email(self) -> str: @cached_property def blobs(self) -> 'List[Blob]': - return [Blob(b) for b in self._get_list_values('a2b')] + return [Blob(b) for b in self._get_list_values(f'{self.ident}2b')] @cached_property def commits(self) -> 'List[Commit]': - return [Commit(c) for c in self._get_list_values('a2c')] + return [Commit(c) for c in self._get_list_values(f'{self.ident}2c')] @cached_property def files(self) -> 'List[File]': - return [File(f) for f in self._get_list_values('a2f')] + return [File(f) for f in self._get_list_values(f'{self.ident}2f')] @cached_property def projects(self) -> 'List[Project]': - return [Project(p) for p in self._get_list_values('a2p')] + return [Project(p) for p in self._get_list_values(f'{self.ident}2p')] + + @cached_property + def unique_authors(self) -> List['UniqueAuthor']: + return [UniqueAuthor(a) for a in self._get_list_values(f'{self.ident}2A')] + + @property + def authors(self): + raise NotImplementedError("Author object does not have authors method") + + @cached_property + def first_blobs(self) -> List['Blob']: + return [Blob(b) for b in self._get_list_values(f'{self.ident}2fb')] class UniqueAuthor(Author): ident = 'A' - pass + + @property + def unique_authors(self) -> 'List[Author]': + raise NotImplementedError("UniqueAuthor object does not have unique_authors method") + + @cached_property + def authors(self) -> 'List[Author]': + return [Author(a) for a in self._get_list_values(f'{self.ident}2a')] + + class Blob(_GitObject): @@ -195,7 +217,20 @@ def files(self) -> 'List[File]': @cached_property def projects_unique(self) -> 'List[RootProject]': return [RootProject(p) for p in self._get_list_values('b2P')] - + + @cached_property + def changed_from(self) -> 'List[Tuple[Blob, Commit, File]]': + return [ + (Blob(b), Commit(c), File(f)) + for b, c, f in self._get_list_values('bb2cf') + ] + + @cached_property + def changed_to(self) -> 'List[Tuple[Blob, Commit, File]]': + return [ + (Blob(b), Commit(c), File(f)) + for b, c, f in self._get_list_values('obb2cf') + ] class Commit(_GitObject): ident = 'c' @@ -248,6 +283,7 @@ def _parent_shas(self) -> List[str]: @property def parents(self) -> List['Commit']: + """Parent commits of this commit""" return [Commit(p) for p in self.data_obj['parent']] @cached_property @@ -255,6 +291,11 @@ def projects(self) -> List['Project']: """Projects associated with this commit""" return [Project(p) for p in self._get_list_values('c2p')] + @cached_property + def root_projects(self) -> List['RootProject']: + """Root projects associated with this commit""" + return [RootProject(p) for p in self._get_list_values('c2P')] + @cached_property def children(self) -> List['Commit']: """Children of this commit""" @@ -303,6 +344,14 @@ def root(self) -> 'Tuple[Commit, int]': sha, dis = self.woc.get_values('c2r', self.key) return Commit(sha), int(dis) + @cached_property + def changeset(self) -> 'List[Tuple[File, Blob, Blob]]': + """Returns changed files, their new and old blobs""" + return [ + (File(f), Blob(new), Blob(old)) + for f, new, old in self._get_list_values('c2fbb') + ] + def compare( self, parent: Union['Commit', str], @@ -656,6 +705,10 @@ def __iter__(self) -> 'Generator[Commit, None, None]': yield c except KeyError: pass + + @property + def projects(self) -> List['Project']: + raise NotImplementedError("Project object does not have projects method") class RootProject(Project): ident = 'P' @@ -670,4 +723,8 @@ def commits(self) -> 'List[Commit]': @cached_property def projects(self) -> 'List[Project]': - return [Project(p) for p in self._get_list_values(f'{self.ident}2p')] \ No newline at end of file + return [Project(p) for p in self._get_list_values(f'{self.ident}2p')] + + @property + def root_projects(self) -> List['RootProject']: + raise NotImplementedError("RootProject object does not have root_projects method") \ No newline at end of file diff --git a/woc/wocprofile.default.json b/woc/wocprofile.default.json index 118c943..e58780b 100644 --- a/woc/wocprofile.default.json +++ b/woc/wocprofile.default.json @@ -20,7 +20,10 @@ "dat": "colon_seperated_data", "tch": "compressed_data", "bin": "binary_data", - "idx": "binary_index" + "idx": "binary_index", + "bb": "new_blob", + "obb": "old_blob", + "fb": "first_blob" }, "dtypes": { "h": "hex", From 8b8410b308777b96d975613c0eaf57e84f2596d0 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Sun, 9 Jun 2024 21:46:51 +0800 Subject: [PATCH 25/38] refactor: TCHashDB(path) from bytes to str Makes no sense but confusion --- tests/fixtures/create_fixtures.py | 3 +- tests/fixtures/create_fixtures.py.bak | 244 -------------------------- tests/test_tch.py | 22 ++- woc/local.pxd | 4 +- woc/local.pyi | 2 +- woc/local.pyx | 92 ++++++---- woc/tch.pxd | 2 +- woc/tch.pyi | 4 +- woc/tch.pyx | 27 +-- 9 files changed, 97 insertions(+), 303 deletions(-) delete mode 100644 tests/fixtures/create_fixtures.py.bak diff --git a/tests/fixtures/create_fixtures.py b/tests/fixtures/create_fixtures.py index c269156..16262a5 100644 --- a/tests/fixtures/create_fixtures.py +++ b/tests/fixtures/create_fixtures.py @@ -49,8 +49,9 @@ def encode_value( def write_to_tch(key: bytes, value: bytes, shards: List[str], sharding_bits: int, use_fnv_keys: bool): shard = get_shard(key, sharding_bits, use_fnv_keys) _path = shards[shard] - db = TCHashDB(_path.encode()) + db = TCHashDB(_path) db[key] = value + db.close() def write_large(path: str, key: bytes, value: bytes, dtype: str): if dtype == 'h': diff --git a/tests/fixtures/create_fixtures.py.bak b/tests/fixtures/create_fixtures.py.bak deleted file mode 100644 index 16b9cdb..0000000 --- a/tests/fixtures/create_fixtures.py.bak +++ /dev/null @@ -1,244 +0,0 @@ -from typing import List, Union -import gzip -import json -try: - import lzf - assert lzf.decompress -except ImportError or AssertionError: - raise ImportError('python-lzf is required to decompress LZF-compressed data: `pip install python-lzf`') - -from woc.tch import TCHashDB -from woc.local import * - -def ber(*numbers): - def gen(): - for num in numbers: - a = True - while a: - a, num = divmod(num, 128) - yield (a + 0x80 if a else num).to_bytes(1, 'big') - return b''.join(gen()) - -def encode_value( - value, - dtype: str -) -> bytes: - if dtype == 'h': # type: list[str] - return b''.join(bytes.fromhex(v) for v in value) - elif dtype == 'sh': # type: tuple[str, str, str] - Time, Author, cmt_sha = value - buf0 = f"{Time};{Author}".encode() - cmt_sha_bytes = bytes.fromhex(cmt_sha) - return buf0 + cmt_sha_bytes - elif dtype == 'cs3': # type: list[tuple[str, str, str]] - _joined = ';'.join(f"{t[0]};{t[1]};{t[2]}" for t in value) - data = _joined.encode - return lzf.compress(data) - elif dtype == 'cs': # type: list[str] - _joined = ';'.join(v.encode() for v in value if v) - return lzf.compress(_joined.encode()) - elif dtype == 's': # type: list[str] - return b';'.join(v.encode() for v in value) - elif dtype == 'r': # type: list[str, int] - _hex, _len = value - return bytes.fromhex(_hex) + ber(_len) - elif dtype == 'hhwww': - raise NotImplemented - raise ValueError(f'Unsupported dtype: {dtype}') - -def write_to_tch(key: bytes, value: bytes, shards: List[str], sharding_bits: int, use_fnv_keys: bool): - shard = get_shard(key, sharding_bits, use_fnv_keys) - _path = shards[shard] - db = TCHashDB(_path.encode()) - db[key] = value - -def write_large(path: str, key: bytes, value: bytes, dtype: str): - if dtype == 'h': - with open(path, 'wb') as f: - f.write(key) - f.write(value[:160]) - else: - # use zlib to decompress - with gzip.open(path, 'wb') as f: - f.write(key) - f.write(b'\n') - # run a fast scan to find idx of 3rd ';' in value - idx = 0 - for _ in range(3): - idx = value.find(b';', idx + 1) - f.write(value[:idx]) - -class WocMapsCopier(WocMapsLocal): - def __init__(self, config1, config2): - super().__init__(config1) - with open(config2) as f: - self.config2 = json.load(f) - - def get_values_raw(self, map_name, key): - if map_name in self.config["maps"]: - _map = self.config["maps"][map_name][0] - elif map_name in self.config["objects"]: - _map = self.config["objects"][map_name] - else: - raise KeyError(f'Invalid map name: {map_name}, ' - f'expect one of {", ".join(self.config["maps"].keys())}') - - if _map["dtypes"][0] == 'h': - if isinstance(key, str): - _hex = key - key = bytes.fromhex(key) - else: - _hex = bytes(key).hex() - else: - assert isinstance(key, str), "key must be a string for non-hash keys" - _hex = hex(fnvhash(key.encode('utf-8')))[2:] - key = key.encode('utf-8') - - if "larges" in _map and _hex in _map["larges"]: - print('reading large', _map["larges"][_hex], 'key', key, 'type', _map["dtypes"][1]) - return read_large(_map["larges"][_hex], _map["dtypes"][1]) - else: - print('reading from tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') - return get_from_tch(key, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') - - def show_content_raw( - self, - obj: str, - key: Union[bytes, str], - ): - if isinstance(key, str): - key = bytes.fromhex(key) - - if obj == 'tree': - _map_obj = self.config['objects']['tree.tch'] - print('reading from tch', key, _map_obj['sharding_bits']) - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - return v - - elif obj == 'commit': - _map_obj = self.config['objects']['commit.tch'] - print('reading from tch', key, _map_obj['sharding_bits']) - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - return v - - elif obj == 'blob': - _map_obj = self.config['objects']['sha1.blob.tch'] - print('reading from tch', key, _map_obj['sharding_bits']) - v = get_from_tch(key, - shards=_map_obj['shards'], - sharding_bits=_map_obj['sharding_bits'], - use_fnv_keys=False - ) - - offset, length = unber(v) - print('reading from blob', _map_obj['shards'][0], offset, length) - _map_obj = self.config['objects']['blob.bin'] - shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) - with open(_map_obj['shards'][shard], "rb") as f: - f.seek(offset) - _out_bin = f.read(length) - return (v, _out_bin) - - else: - raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') - - - def copy_values(self, map_name, key): - """One large file can only contain one record""" - value = self.get_values_raw(map_name, key) - - if map_name in self.config2["maps"]: - _map = self.config2["maps"][map_name][0] - elif map_name in self.config2["objects"]: - _map = self.config2["objects"][map_name] - else: - raise KeyError(f'Invalid map name: {map_name}, ' - f'expect one of {", ".join(self.config2["maps"].keys())}') - - if _map["dtypes"][0] == 'h': - if isinstance(key, str): - _hex = key - key = bytes.fromhex(key) - else: - _hex = bytes(key).hex() - else: - assert isinstance(key, str), "key must be a string for non-hash keys" - _hex = hex(fnvhash(key.encode('utf-8')))[2:] - key = key.encode('utf-8') - - if "larges" in _map and _hex in _map["larges"]: - print('writing large', _map["larges"][_hex], 'key', key, 'dtype', _map["dtypes"][1]) - return write_large(_map["larges"][_hex], key, value, _map["dtypes"][1]) - else: - # use fnv hash as shading idx if key is not a git sha - print('writing to tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') - return write_to_tch(key, value, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') - - def copy_content(self, obj: str, key: Union[bytes, str]): - """One blob shard can only contain one record""" - value = self.show_content_raw(obj, key) - - if obj == 'tree': - _map_obj = self.config2['objects']['tree.tch'] - print('writing to tch', key, _map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) - - elif obj == 'commit': - _map_obj = self.config2['objects']['commit.tch'] - print('writing to tch', key ,_map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=True) - - elif obj == 'blob': - _map_obj = self.config2['objects']['sha1.blob.tch'] - _idx, _v = value - offset, length = unber(_idx) - _idx = ber(0, length) - print('writing to tch', key, _map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) - _map_obj = self.config2['objects']['blob.bin'] - shard = get_shard(bytes.fromhex(key), _map_obj['sharding_bits'], use_fnv_keys=False) - print('writing to file', _map_obj['shards'][shard], length) - with open(_map_obj['shards'][shard], "ab") as f: - f.write(_v) - - else: - raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') - - -if __name__ == '__main__': - import glob - import os - - for f in glob.glob('./tests/fixtures/*.tch*') + glob.glob('./tests/fixtures/*.bin'): - print('removing', f) - os.remove(f) - - cp = WocMapsCopier('./wocprofile.json', './tests/test_profile.json') - cp.copy_values('c2p', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('c2dat', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('b2tac', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_values('p2a', 'ArtiiQ_PocketMine-MP') - cp.copy_values('b2c', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_values('b2c', '3f2eca18f1bc0f3117748e2cea9251e5182db2f7') # large - cp.copy_values('a2c', 'Audris Mockus ') - # cp.copy_values('c2cc', 'e4af89166a17785c1d741b8b1d5775f3223f510f') # null - cp.copy_values('a2f', 'Audris Mockus ') - cp.copy_values('c2f', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('c2b', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('p2c', 'ArtiiQ_PocketMine-MP') - cp.copy_values('f2a', 'youtube-statistics-analysis.pdf') - cp.copy_values('b2f', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_content('tree', 'f1b66dcca490b5c4455af319bc961a34f69c72c2') - cp.copy_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') diff --git a/tests/test_tch.py b/tests/test_tch.py index 6d89eaa..373cc56 100644 --- a/tests/test_tch.py +++ b/tests/test_tch.py @@ -7,7 +7,7 @@ def db(tmp_path): """Fixture to create and return a TCHashDB instance""" path = tmp_path / "test_db.tch" - db = TCHashDB(path=bytes(str(path), 'utf-8')) + db = TCHashDB(path=str(path)) yield db def test_put_and_get(db): @@ -63,4 +63,22 @@ def test_delitem(db): db[key] = value del db[key] with pytest.raises(KeyError): - db.get(key) \ No newline at end of file + db.get(key) + +def test_open(tmp_path): + """Test that two TCHashDB instances can be opened concurrently""" + path = tmp_path / "test_db.tch" + db = TCHashDB(path=str(path), ro=False) + db[b'key'] = b'value' + # The following should yield no error + db.close() + db = TCHashDB(path=str(path), ro=True) + assert db[b'key'] == b'value' + # can't write to a read-only db + with pytest.raises(OSError): + db[b'key'] = b'value' + # tch does not allow opening a db in the same process + # ref: lib/tchdb.c#L370 + with pytest.raises(OSError): + db2 = TCHashDB(path=str(path), ro=True) + \ No newline at end of file diff --git a/woc/local.pxd b/woc/local.pxd index 56af550..ca8388a 100644 --- a/woc/local.pxd +++ b/woc/local.pxd @@ -6,6 +6,6 @@ from libc.stdint cimport uint32_t, uint8_t cpdef uint32_t fnvhash(bytes data) cpdef unber(bytes buf) cpdef (int, int) lzf_length(bytes raw_data) -cpdef get_tch(char *path) +cpdef get_tch(str path) cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys) -cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys) \ No newline at end of file +# cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys) \ No newline at end of file diff --git a/woc/local.pyi b/woc/local.pyi index 7705837..6079045 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -34,7 +34,7 @@ def decomp(data: bytes) -> bytes: ... def decomp_or_raw(data: bytes) -> bytes: ... def get_tch(path: str): ... def get_shard(key: bytes, sharding_bits: int, use_fnv_keys: bool) -> int: ... -def get_from_tch(key: bytes, shards: List[bytes], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... +# def get_from_tch(key: bytes, shards: List[bytes], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... def decode_value(value: bytes, out_dtype: str): ... def decode_tree(value: bytes) -> List[Tuple[str, str, str]]: ... def decode_commit(commit_bin: bytes) -> Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]: ... diff --git a/woc/local.pyx b/woc/local.pyx index 17260d5..471646c 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -22,8 +22,6 @@ except ImportError or AssertionError: from .base import WocMapsBase, WocObjectsWithContent, WocSupportedProfileVersions from .tch cimport TCHashDB -logger = logging.getLogger(__name__) - cdef extern from 'Python.h': object PyBytes_FromStringAndSize(char *s, Py_ssize_t len) @@ -174,7 +172,7 @@ def decode_str(bytes raw_data, str encoding='utf-8'): cdef dict _TCH_POOL = {} # type: Dict[str, TCHashDB] TCH_LOCK = Lock() -cpdef get_tch(char *path): +cpdef TCHashDB get_tch(str path): """ Cache Hash() objects """ if path in _TCH_POOL: return _TCH_POOL[path] @@ -199,15 +197,15 @@ cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys): cdef uint8_t prefix = p & (2**sharding_bits - 1) return prefix -cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys): - """DEPRECATED""" - # not 100% necessary but there are cases where some tchs are miserably missing - _shard = get_shard(key, sharding_bits, use_fnv_keys) - _path = shards[_shard] - assert _path and os.path.exists(_path), f"shard {_shard} not found at {_path}" - return get_tch( - shards[get_shard(key, sharding_bits, use_fnv_keys)].encode('utf-8') - )[key] +# cpdef bytes get_from_tch(bytes key, list shards, int sharding_bits, bint use_fnv_keys): +# """DEPRECATED""" +# # not 100% necessary but there are cases where some tchs are miserably missing +# _shard = get_shard(key, sharding_bits, use_fnv_keys) +# _path = shards[_shard] +# assert _path and os.path.exists(_path), f"shard {_shard} not found at {_path}" +# return get_tch( +# shards[get_shard(key, sharding_bits, use_fnv_keys)].encode('utf-8') +# )[key] ### deserializers ### @@ -530,6 +528,11 @@ class WocMapsLocal(WocMapsBase): profile_path: Union[str, Iterable[str], None] = None, version: Union[str, Iterable[str], None] = None ) -> None: + # init logger + self._logger = logging.getLogger(__name__) + # cache logger level + self._is_debug_enabled = self._logger.isEnabledFor(logging.DEBUG) + # load profile if profile_path is None: profile_path = ( @@ -554,7 +557,7 @@ class WocMapsLocal(WocMapsBase): assert self.config["wocSchemaVersion"] in WocSupportedProfileVersions, \ "Unsupported wocprofile version: {}".format(self.config["wocSchemaVersion"]) assert self.config["maps"], "Run `python3 -m woc.detect` to scan data files and generate wocprofile.json" - + def _get_tch_bytes( self, map_name, key ) -> Tuple[bytes, str]: @@ -581,8 +584,9 @@ class WocMapsLocal(WocMapsBase): in_dtype = _map["dtypes"][0] if "dtypes" in _map else "h" out_dtype = _map["dtypes"][1] if "dtypes" in _map else "c?" # c? means maybe compressed - start_time = time.time_ns() - logger.debug(f"get from tch: {map_name} {key}") + if self._is_debug_enabled: + start_time = time.time_ns() + self._logger.debug(f"get from tch: {map_name} {key}") if in_dtype == 'h': if isinstance(key, str): @@ -595,13 +599,17 @@ class WocMapsLocal(WocMapsBase): hex_str = hex(fnvhash(key.encode('utf-8')))[2:] key = key.encode('utf-8') - logger.debug(f"hash: hex={hex_str} in {(time.time_ns() - start_time) / 1e6:.2f}ms") - start_time = time.time_ns() + if self._is_debug_enabled: + self._logger.debug(f"hash: hex={hex_str} in {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() if "larges" in _map and hex_str in _map["larges"]: _bytes = read_large(_map["larges"][hex_str], out_dtype) - logger.debug(f"read large: file={_map['larges'][hex_str]} in {(time.time_ns() - start_time) / 1e6:.2f}ms") - start_time = time.time_ns() + + if self._is_debug_enabled: + self._logger.debug(f"read large: file={_map['larges'][hex_str]} " + f"in {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() # compress string data is not compressed in larges if out_dtype == 'cs': @@ -612,7 +620,7 @@ class WocMapsLocal(WocMapsBase): _path = _map["shards"][_shard] assert _path, f"shard {_shard} not found at {_path}" - _tch = get_tch(_path.encode('utf-8')) + _tch = get_tch(_path) # TODO: remove bb2cf quirk after fixing tch keys # bb2cf: keys are stored as hex strings in tch db @@ -621,7 +629,9 @@ class WocMapsLocal(WocMapsBase): _bytes = _tch[key] - logger.debug(f"get from tch: shard={_shard} db={_path} in {(time.time_ns() - start_time) / 1e6:.2f}ms") + if self._is_debug_enabled: + self._logger.debug(f"get from tch: shard={_shard} db={_path} " + f"in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _bytes, out_dtype @@ -635,9 +645,14 @@ class WocMapsLocal(WocMapsBase): ['05cf84081b63cda822ee407e688269b494a642de', ...] """ _bytes, decode_dtype = self._get_tch_bytes(map_name, key) - start_time = time.time_ns() + + if self._is_debug_enabled: + start_time = time.time_ns() + _decoded = decode_value(_bytes, decode_dtype) - logger.debug(f"decode: in {(time.time_ns() - start_time) / 1e6:.2f}ms") + + if self._is_debug_enabled: + self._logger.debug(f"decode: in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _decoded def _get_pos( @@ -664,12 +679,12 @@ class WocMapsLocal(WocMapsBase): # key: Union[bytes, str], # ): # start_time = time.time_ns() - # logger.debug(f"show_content: {obj_name} {key}") + # self._logger.debug(f"show_content: {obj_name} {key}") # if isinstance(key, str): # key = bytes.fromhex(key) - # logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # self._logger.debug(f"hash: {(time.time_ns() - start_time) / 1e6:.2f}ms") # start_time = time.time_ns() # if obj_name == 'tree': @@ -679,7 +694,7 @@ class WocMapsLocal(WocMapsBase): # sharding_bits=_map_obj['sharding_bits'], # use_fnv_keys=False # ) - # logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # self._logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") # return decomp_or_raw(v) # elif obj_name == 'commit': @@ -689,12 +704,12 @@ class WocMapsLocal(WocMapsBase): # sharding_bits=_map_obj['sharding_bits'], # use_fnv_keys=False # ) - # logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # self._logger.debug(f"get from tch: {(time.time_ns() - start_time) / 1e6:.2f}ms") # return decomp_or_raw(v) # elif obj_name == 'blob': # offset, length = self._get_pos('blob', key) - # logger.debug(f"get from tch: offset={offset} len={length} {(time.time_ns() - start_time) / 1e6:.2f}ms") + # self._logger.debug(f"get from tch: offset={offset} len={length} {(time.time_ns() - start_time) / 1e6:.2f}ms") # start_time = time.time_ns() # _map_obj = self.config['objects']['blob.bin'] @@ -703,7 +718,7 @@ class WocMapsLocal(WocMapsBase): # with open(_map_obj['shards'][shard], "rb") as f: # f.seek(offset) # _out_bin = f.read(length) - # logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") + # self._logger.debug(f"read blob: {(time.time_ns() - start_time) / 1e6:.2f}ms") # start_time = time.time_ns() # return decomp_or_raw(_out_bin) @@ -721,24 +736,27 @@ class WocMapsLocal(WocMapsBase): >>> self.show_content('tree', '7a374e58c5b9dec5f7508391246c48b73c40d200') [('100644', '.gitignore', '8e9e1...'), ...] """ - start_time = time.time_ns() + if self._is_debug_enabled: + start_time = time.time_ns() if obj_name == 'tree': _ret = decode_tree(decomp_or_raw(self._get_tch_bytes(obj_name, key)[0])) - logger.debug(f"decode tree: len={len(_ret)} in {(time.time_ns() - start_time) / 1e6:.2f}ms") + if self._is_debug_enabled: + self._logger.debug(f"decode tree: len={len(_ret)} in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret elif obj_name == 'commit': _ret = decode_commit(decomp_or_raw(self._get_tch_bytes(obj_name, key)[0])) - logger.debug(f"decode commit: len={len(_ret)}items in {(time.time_ns() - start_time) / 1e6:.2f}ms") + if self._is_debug_enabled: + self._logger.debug(f"decode commit: len={len(_ret)}items in {(time.time_ns() - start_time) / 1e6:.2f}ms") return _ret elif obj_name == 'blob': key = bytes.fromhex(key) if isinstance(key, str) else key - offset, length = self._get_pos('blob', key) - logger.debug(f"decode pos: offset={offset} len={length} in {(time.time_ns() - start_time) / 1e6:.2f}ms") - start_time = time.time_ns() + if self._is_debug_enabled: + self._logger.debug(f"decode pos: offset={offset} len={length} in {(time.time_ns() - start_time) / 1e6:.2f}ms") + start_time = time.time_ns() _map_obj = self.config['objects']['blob.bin'] shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) @@ -746,8 +764,8 @@ class WocMapsLocal(WocMapsBase): with open(_map_obj['shards'][shard], "rb") as f: f.seek(offset) _out_bin = f.read(length) - logger.debug(f"read blob: in {(time.time_ns() - start_time) / 1e6:.2f}ms") - start_time = time.time_ns() + if self._is_debug_enabled: + self._logger.debug(f"read blob: in {(time.time_ns() - start_time) / 1e6:.2f}ms") return decode_str(decomp_or_raw(_out_bin)) diff --git a/woc/tch.pxd b/woc/tch.pxd index 267f4c7..7178b0c 100644 --- a/woc/tch.pxd +++ b/woc/tch.pxd @@ -6,7 +6,7 @@ cdef extern from 'tchdb.h': cdef class TCHashDB: cdef TCHDB* _db - cdef bytes filename + cdef str filename """Object representing a Tokyocabinet Hash table""" cpdef bytes get(self, bytes key) diff --git a/woc/tch.pyi b/woc/tch.pyi index afdc5e4..2783a7b 100644 --- a/woc/tch.pyi +++ b/woc/tch.pyi @@ -3,10 +3,10 @@ from typing import Iterator class TCHashDB: """Object representing a TokyoCabinet Hash table""" - def __init__(self, path: bytes, ro: bool = False) -> None: + def __init__(self, path: str, ro: bool = False) -> None: """ Create a new TokyoCabinet hash table object. - :path: *encoded* path to the database file + :path: path to the database file :ro: if True, open in lock-free read-only mode; if False, lock and open in write mode (create if not exists) """ ... diff --git a/woc/tch.pyx b/woc/tch.pyx index db923e0..df65714 100644 --- a/woc/tch.pyx +++ b/woc/tch.pyx @@ -38,7 +38,11 @@ cdef extern from 'tchdb.h': cdef class TCHashDB: """Object representing a Tokyocabinet Hash table""" - def __cinit__(self, char *path, bint ro=False): + def __cinit__(self, str path, bint ro=False): + self.filename = path + _encoded = path.encode() + cdef char* dbpath = _encoded + cdef int mode = 0 if not ro: # write mode: create if not exists mode |= HDBOWRITER @@ -48,12 +52,11 @@ cdef class TCHashDB: mode |= HDBONOLCK self._db = tchdbnew() - self.filename = path if self._db is NULL: raise MemoryError() - cdef bint result = tchdbopen(self._db, path, mode) + cdef bint result = tchdbopen(self._db, dbpath, mode) if not result: - raise IOError(f'Failed to open {self.filename.decode("latin1")}: ' + self._error()) + raise IOError(f'Failed to open {self.filename}: ' + self._error()) def _error(self): cdef int code = tchdbecode(self._db) @@ -67,7 +70,7 @@ cdef class TCHashDB: int sp bytes key if not result: - raise IOError(f'Failed to iterate {self.filename.decode("latin1")}: ' + self._error()) + raise IOError(f'Failed to iterate {self.filename}: ' + self._error()) while True: buf = tchdbiternext(self._db, &sp) if buf is NULL: @@ -84,7 +87,7 @@ cdef class TCHashDB: int ksize=len(key) buf = tchdbget(self._db, k, ksize, &sp) if buf is NULL: - raise KeyError(f'Key {key.hex()} not found in {self.filename.decode("latin1")}') + raise KeyError(f'Key {key.hex()} not found in {self.filename}') cdef bytes value = PyBytes_FromStringAndSize(buf, sp) free(buf) return value @@ -98,7 +101,7 @@ cdef class TCHashDB: bint result result = tchdbput(self._db, k, ksize, v, vsize) if not result: - raise IOError(f'Failed to put {key.hex()} in {self.filename.decode("latin1")}: ' + self._error()) + raise IOError(f'Failed to put {key.hex()} in {self.filename}: ' + self._error()) cpdef void delete(self, bytes key) except *: cdef: @@ -107,19 +110,19 @@ cdef class TCHashDB: bint result result = tchdbout(self._db, k, ksize) if not result: - raise IOError(f'Failed to delete {key.hex()} in {self.filename.decode("latin1")}: ' + self._error()) + raise IOError(f'Failed to delete {key.hex()} in {self.filename}: ' + self._error()) cpdef void drop(self) except *: cdef: bint result result = tchdbvanish(self._db) if not result: - raise IOError(f'Failed to drop all records in {self.filename.decode("latin1")}: ' + self._error()) + raise IOError(f'Failed to drop all records in {self.filename}: ' + self._error()) cpdef void close(self) except *: cdef bint result = tchdbclose(self._db) if not result: - raise IOError(f'Failed to close {self.filename.decode("latin1")}: ' + self._error()) + raise IOError(f'Failed to close {self.filename}: ' + self._error()) def __getitem__(self, bytes key): return self.get(key) @@ -137,6 +140,4 @@ cdef class TCHashDB: self.close() def __dealloc__(self): - if self._db is not NULL: - tchdbdel(self._db) - self._db = NULL \ No newline at end of file + free(self._db) # it should never be null \ No newline at end of file From 790b845633e9f3822f90cc3357ee78d5b47ba2a6 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Sun, 9 Jun 2024 21:52:35 +0800 Subject: [PATCH 26/38] feat: count the number of keys The impl is surprisingly easy, now we know how many projects/commits/authors stored in WoC --- tests/test_local.py | 10 +++++++++- woc/local.pyi | 8 ++++++++ woc/local.pyx | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/tests/test_local.py b/tests/test_local.py index 6d8d4ff..691b60d 100644 --- a/tests/test_local.py +++ b/tests/test_local.py @@ -88,4 +88,12 @@ def test_blob_1(woc): def test_blob_2(woc): res = woc.show_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') - assert len(res) == 1236 \ No newline at end of file + assert len(res) == 1236 + +def test_count(woc): + res = woc.count('blob') + assert res == 2 + res = woc.count('tree') + assert res == 12 + res = woc.count('commit') + assert res == 7 diff --git a/woc/local.pyi b/woc/local.pyi index 6079045..108def6 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -25,6 +25,14 @@ class WocMapsLocal(WocMapsBase): """ ... + def count( + self, map_name: str + ) -> int: + """ + Count the number of keys in a map (# of larges + # of tch keys) + """ + ... + # The following functions are internal and should not be used by the user # Exposing them here for testing purposes def fnvhash(data: bytes) -> int: ... diff --git a/woc/local.pyx b/woc/local.pyx index 471646c..f7d4f3e 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -776,4 +776,39 @@ class WocMapsLocal(WocMapsBase): elif obj_name == 'bdiff': raise NotImplemented else: - raise ValueError(f'Unsupported object type: {obj_name}, expected one of tree, blob, commit, tkns, tag, bdiff') \ No newline at end of file + raise ValueError(f'Unsupported object type: {obj_name}, expected one of tree, blob, commit, tkns, tag, bdiff') + + def count( + self, map_name + ) -> int: + """ + Count the number of keys in a map (# of larges + # of tch keys) + """ + # translate obj_name to map_name + if map_name == 'tree': + map_name = 'tree.tch' + elif map_name == 'commit': + map_name = 'commit.tch' + elif map_name == 'blob': + map_name = 'sha1.blob.tch' + + if self._is_debug_enabled: + start_time = time.time_ns() + + if map_name in self.config["maps"]: + _map = self.config["maps"][map_name][0] + elif map_name in self.config["objects"]: + _map = self.config["objects"][map_name] + else: + raise KeyError(f'Invalid map name: {map_name}, ' + f'expect one of {", ".join(self.config["maps"].keys())}') + + _count = len(_map["larges"]) if "larges" in _map else 0 + for _shard in _map["shards"]: + _tch = get_tch(_shard) + _count += len(_tch) + + if self._is_debug_enabled: + self._logger.debug(f'count: len={_count} shards={len(_map["shards"])} ' + f'larges={len(_map["larges"])} in {(time.time_ns() - start_time) / 1e6:.2f}ms') + return _count \ No newline at end of file From bffcd9b05827905a7aebc56d35072e6921f4fd3c Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 11 Jun 2024 04:41:51 +0800 Subject: [PATCH 27/38] docs: add pdoc and ruff --- docs/DataFormat.md | 2 - docs/contributing.md | 164 ++++++++++++ docs/quickstart.md | 46 ++++ docs/tutorial.md | 4 +- poetry.lock | 188 ++++++++++++- pyproject.toml | 86 +++++- woc/__init__.py | 16 +- woc/base.py | 39 ++- woc/detect.py | 45 ++-- woc/get_values.py | 6 +- woc/local.pyi | 25 +- woc/local.pyx | 63 ++--- woc/objects.py | 610 +++++++++++++++++++++++-------------------- woc/show_content.py | 3 +- woc/tch.pyi | 37 ++- 15 files changed, 960 insertions(+), 374 deletions(-) create mode 100644 docs/contributing.md create mode 100644 docs/quickstart.md diff --git a/docs/DataFormat.md b/docs/DataFormat.md index 3a25ac6..653e8e4 100644 --- a/docs/DataFormat.md +++ b/docs/DataFormat.md @@ -1,5 +1,3 @@ - - ## Git objects ### Sequential access: diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..7227959 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,164 @@ + +Starting version 1.3, `oscar` is compiled from Cython, a language closely +resembling Python but with optional strong typing to improve performance. +Building Cython packages requires few extra build steps, as explained below. + +In addition, automation in this project relies on few assumptions which you are +expected to follow. Below you can find their brief description and the motivation +behind. + + +## How to contribute + +All the development is done on feature branches, which are then merged to `master` +via pull requests. Every pull request triggers unit testing, every merge triggers +a release. + +To generate release notes, we use `conventional commits `_, +a convention to commit messages. In a nutshell, it means commit messages should +be prefixed with one of: + +- **fix:** in case the change fixes a problem without changing any interfaces. + Example commit message: `fix: missing clickhouse-driver dependency (closes #123)`. +- **feat:** the change implements a new feature, without affecting existing + interfaces. Example: `feat: implement author timeline`. +- other prefixes, e.g. `chore:`, `refactor:`, `docs:`, `test:`, `ci:`, etc. + - these will not be included in release notes and will not trigger a new + release without new features or fixes added, unless contain breaking changes + (see below). + +In case of breaking changes, commit message should include an exclamation mark +before the semicolon, or contain **BREAKING CHANGE** in the footer, e.g.: + + `feat!: drop support for deprectated parameters` + +`fix`, `chore`, `docs` commits will produce patch versions, `feat` will result +in a minor version bump, and in case of breaking changes the major version will +be incremented. As a consequence, **you must never change version number manually**. + +Not following these procedures might take your pull request extra time to +review and in some cases will require rewriting the commit history. + + +## About Cython + +The reason to use Cython was primarily Python 3 support. WoC data is stored +in tokyocabinet (.tch) files, note natively supported by Python. +`libtokyocabinet` binding, `python-tokyocabinet`, is a C extension supporting +Python 2 only, and lack of development activity suggests updating it for Py 3 +is hardly considered. So, our options to interface `libtokyocabinet` were: + +- cffi (C Foreign Functions Interface) - perhaps, the simplest option, + but it does not support conditional definitions (`#IFDEF`), that are + actively used in tokyocabinet headers +- C extension, adapting existing `python-tokyocabinet` code for Python 3. + It is rather hard to support and even harder to debug; a single + attempt was scrapped after making a silently failing extension. +- `SWIG `_ (and its successor, `CLIF `_), + a Google project to generate C/C++ library bindings + for pretty much any language. Since this library provides 1:1 interface + to the library methods, Python clients had to be aware of the returned + C structures used by libtokyocabinet, which too inconvenient. +- Cython, a weird mix of Python and C. It allows writing Python interfaces, + while simultaneously using C functions. This makes it the ideal option + for our purposes, providing a Python `.tch` file handler working + with `libtokyocabinet` C structures under the hood. + +Cython came a clear winner in this comparison, also helping to speed up +some utility functions along the way (e.g. `fnvhash`, a pure Python version +of which was previously used). + +## Compiling and packaging + +To compile oscar locally, run: +`python setup.py build_ext --inplace`. To explicitly specify python version, +replace `pyhon`, with the appropriate version, e.g. `python2`. +There shorter alias for this command, `make build`, will always use the default +Python. + +If you are building for several Python versions in a row without changing the +code (e.g. to check if it compiles at all), make sure you clean up first by +running `make clean`. +Compilation is cached when possible, and will be omitted if the input hasn't +changed - the compiler is not aware that the resulting `.so` file exposes +different interfaces. You will get a lot of angry messages about missing +interfaces and symbols when import with the same Python version which "compiled" +this `.so` just a second ago in this case. + +Packaging is slightly more complicated than just compiling since oscar needs to +support at least Python 2.7 and 3.6 simultaneously, meaning we need to package +multiple binaries. Fortunately, `PEP 513 `_ +offers support for such packages. Building is done via `manylinux `_, +a special Docker image, and is automated via GitHub action. + +To build package locally, + +- clone the corresponding GitHub action repository, + `git clone git@github.com:user2589/python-wheels-manylinux-build.git`, +- check out the desired tag if necessary, e.g. `git checkout v0.3.4` +- build Docker image: `docker build -t python-wheels-manylinux-build .` +- run the image: `make build_manylinux` + + +## Testing + +Every push to oscar repository is automatically tested; on top, you might want +to test locally before making a commit to avoid awkward followup fixes and a +bunch of angry emails from GitHub actions bot telling how you broke the build. +Unit tests are tedious to write, but will save a lot of your time in the long run. +First thing to know about unit tests, please DO write them - future you will be +grateful. Second, there are a couple things about testing Cython code against a +remote dataset. + +To run tests locally, `make test_local`. +WoC files are only available on UTK servers only, so to make local testing +possible, there is a small subset of the data in `tests/fixtures`. Changing +oscar paths to point at these fixtures requires setting some environment +variables, stored in `tests/local_test.env`. +To tests locally, + +- set environment variables, `source tests/local_test.env` +- clean up previously compiled binaries to avoid Py2/3 compatibility issues: `make clean` +- run the test script: `PYTHONPATH=. python tests/unit_test.py`. + Don't forget to replace `python` with a specific version if testing + against non-default Python) + +`make test_local` is a shortcut for this, except it will always use the default +Python and thus doesn't need to clean. + +Unit tests for Cython functions (i.e., defined with `cdef`) are stored in a +separate `.pyx` file, which is imported from the regular `.py` test suite. +Cython code can only be accessed from Cython files, which cannot executed as a +Python script. Thus, we have to store them separately - see `tests/unit_test.py` +and `tests/unit_test_cy.pyx` as an example of how it is organized. + +To avoid manual compilation with `cythonize`, Cython tests are compiled with +`pyximport`, an in-place JIT compiler. Thus, at the beginning of every test suite, +install `pyximport`: + +```python +import pyximport +pyximport.install( + # build_dir='build', + setup_args={"script_args": ["--force"]}, + inplace=True, + language_level='3str' +) +``` + +To tell `pyximport` where to find sources and libraries for the main module, +there is a special file `oscar.pyxbld`. It is important to keep it consistent +with the `Extension` parameters in `setup.py`. If you can `make build` but unit +tests fail to compile it, this is the first place to check. + +Cython functions being tested should be exposed in `oscar.pxd` - +a Cython equivalent of a header file. If tests cannot find some function that is +defined in oscar, check it is included there. Hopefully, the list of tested +functions will grow bigger with your help. + +Finally, unit and integration tests can also be run on real data. On one of UTK +servers (preferably, `da4`), clone the repository and run `make test`. If the +result is different from your local run, perhaps it's time to update fixtures +and/or tests. + + diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 0000000..4f4846c --- /dev/null +++ b/docs/quickstart.md @@ -0,0 +1,46 @@ +## Install + +### From PyPI + +```bash +python3 -m pip install python-woc +``` + +### From Source + +```bash +git clone https://github.com/ssc-oscar/python-woc.git +python3 -m pip install . +``` + +## Generate Profiles + +```bash +python3 woc.detect /path/to/woc/1 /path/to/woc/2 ... > wocprofile.json +``` + +## CLI + +```bash +echo some_key | echo python3 -m woc.get_values some_map +``` + +## Python API + +```python +from woc.local import WocMapsLocal +woc = WocMapsLocal() # by default it uses ./wocprofile.json, ~/.wocprofile.json, /etc/wocprofile.json +v1 = woc.get_values('some_map', 'some_key') +v2 = woc.show_content('some_commit', 'some_sha') +``` + +## Python OOP API + +```python +from woc.local import WocMapsLocal +from woc.objects import Commit, init_woc_objects +woc = WocMapsLocal() +init_woc_objects(woc) +c = Commit('some_sha') +c.tree +``` diff --git a/docs/tutorial.md b/docs/tutorial.md index e67a901..8c95e40 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -1,8 +1,6 @@ -# Tutorial basics for Hackathon -------- ## List of relevant directories ### da0 Server -#### .{0-31}.tch files in `/data/basemaps/`: +#### `.{0-31}.tch` files in `/data/basemaps/`: (.s) signifies that there are either .s or .gz versions of these files in gz/ subfolder, which can be opened with Python gzip module or Unix zcat. da0 is the only server with these .s/.gz files Keys for identifying letters: diff --git a/poetry.lock b/poetry.lock index d5e2610..e5d64a8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,20 @@ # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +[[package]] +name = "astunparse" +version = "1.6.3" +description = "An AST unparser for Python" +optional = false +python-versions = "*" +files = [ + {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"}, + {file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"}, +] + +[package.dependencies] +six = ">=1.6.1,<2.0" +wheel = ">=0.23.0,<1.0" + [[package]] name = "chardet" version = "5.2.0" @@ -165,6 +180,92 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + [[package]] name = "packaging" version = "24.0" @@ -176,6 +277,26 @@ files = [ {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] +[[package]] +name = "pdoc" +version = "14.5.0" +description = "API Documentation for Python Projects" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pdoc-14.5.0-py3-none-any.whl", hash = "sha256:9a8a84e19662610c0620fbe9f2e4174e3b090f8b601ed46348786ebb7517c508"}, + {file = "pdoc-14.5.0.tar.gz", hash = "sha256:79f534dc8a6494638dd6056b78e17a654df7ed34cc92646553ce3a7ba5a4fa4a"}, +] + +[package.dependencies] +astunparse = {version = "*", markers = "python_version < \"3.9\""} +Jinja2 = ">=2.11.0" +MarkupSafe = "*" +pygments = ">=2.12.0" + +[package.extras] +dev = ["hypothesis", "mypy", "pdoc-pyo3-sample-library (==1.0.11)", "pygments (>=2.14.0)", "pytest", "pytest-cov", "pytest-timeout", "ruff", "tox", "types-pygments"] + [[package]] name = "pluggy" version = "1.5.0" @@ -191,6 +312,20 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + [[package]] name = "pytest" version = "8.2.2" @@ -241,6 +376,43 @@ files = [ {file = "python-lzf-0.2.4.tar.gz", hash = "sha256:d1420f1544e612ef1bb41ce0f1d14c2964b3444612f1468f85a886caff3615d1"}, ] +[[package]] +name = "ruff" +version = "0.4.8" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"}, + {file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"}, + {file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"}, + {file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"}, + {file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"}, + {file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + [[package]] name = "tomli" version = "2.0.1" @@ -252,7 +424,21 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "wheel" +version = "0.43.0" +description = "A built-package format for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "wheel-0.43.0-py3-none-any.whl", hash = "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81"}, + {file = "wheel-0.43.0.tar.gz", hash = "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85"}, +] + +[package.extras] +test = ["pytest (>=6.0.0)", "setuptools (>=65)"] + [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "7e66d6888dd470fa3ba1d16024f43f6553410c3e8182d089e4c088e0c03d9e5c" +content-hash = "0bfbbf897129d063080303ece80f0a156b953618f1bee862b89e438cfa97b541" diff --git a/pyproject.toml b/pyproject.toml index 63700c9..fb2b522 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,11 +27,22 @@ cython = "^0.29.0" pytest = "^8.2.2" pytest-cov = "^5.0.0" coverage = {extras = ["toml"], version = "^7.5.3"} +# bandit = "^1.7.8" +# docformatter = "^1.7.5" +ruff = "^0.4.6" # <- ruff is powerful enough to be the only linter +# sphinx = "^7.1.2" +# sphinx-rtd-theme = "^1.0.0" +# sphinx-autobuild = "^2021.3.14" +# sphinx-pyproject = "^0.3.0" +# sphinx-autodoc-typehints = "^1.25.3" +pdoc = "^14.5.0" # <- drop sphinx, too many deps and rst is not fun [build-system] requires = ["poetry-core", "Cython>=0.29.0,<1.0.0", "setuptools>=42"] build-backend = "poetry.core.masonry.api" +### Test and coverage ### + [tool.pytest.ini_options] addopts = "-ra -q" testpaths = [ @@ -43,4 +54,77 @@ show_missing = true omit = [ "tests/*" ] [tool.coverage.run] -plugins = [ "Cython.Coverage" ] \ No newline at end of file +plugins = [ "Cython.Coverage" ] + +### Documentation ### + +# [tool.sphinx-autobuild] +# watch = ["woc", "docs"] + + +### Formatting and linting ### + +# [tool.docformatter] +# recursive = true +# wrap-summaries = 88 +# wrap-descriptions = 88 +# style = 'sphinx' +# blank = true + +[tool.ruff] +target-version = "py38" +line-length = 90 +extend-exclude = [ + "__pycache__", + "build", + "dist", +] + +[tool.ruff.lint] +# rules ref: https://docs.astral.sh/ruff +extend-select = [ + "C4", + "D201", + "D204", + "D205", + "D206", + "D210", + "D211", + "D213", + "D300", + "D419", + "E", + "F", + "G010", + "I001", + "INP001", + "N805", + "PERF101", + "PERF102", + "PERF401", + "PERF402", + "PGH004", + "PGH005", + "PIE794", + "PIE796", + "PIE807", + "PIE810", + "RUF015", + "RUF100", +] +# disable line length check, as ruff format already handles that +ignore = ["E203", "E501", "E741"] + +[tool.ruff.lint.per-file-ignores] +# loose checks for test files +"tests/**/*.py" = [ + "S101", + "ARG", + "FBT", + "PLR2004", + "S311", + "D", + "F405", + "F403", + "F841" +] \ No newline at end of file diff --git a/woc/__init__.py b/woc/__init__.py index 63c62bd..7e98ab6 100644 --- a/woc/__init__.py +++ b/woc/__init__.py @@ -2,4 +2,18 @@ # SPDX-License-Identifier: GPL-3.0-or-later # @authors: Runzhi He -# @date: 2024-01-17 \ No newline at end of file +# @date: 2024-01-17 + +""" +.. include:: ../README.md +# QuickStart +.. include:: ../docs/quickstart.md +# World of Code Tutorial +.. include:: ../docs/tutorial.md +# World of Code DataFormat +.. include:: ../docs/DataFormat.md +# Contributing +.. include:: ../docs/contributing.md +""" # noqa: D205 + +__all__ = ["local", "tch", "detect", "objects"] \ No newline at end of file diff --git a/woc/base.py b/woc/base.py index c050d63..5c98e6e 100644 --- a/woc/base.py +++ b/woc/base.py @@ -1,7 +1,10 @@ -from typing import Union, Literal, List, Tuple, Dict +from typing import List, Literal, Tuple, Union WocObjectsWithContent = Literal['tree', 'blob', 'commit', 'tkns', 'tag', 'bdiff'] +"""WoC objects stored in stacked binary files.""" + WocSupportedProfileVersions = (1, ) +"""Profile versions supported by the current python-woc.""" class WocMapsBase: @@ -13,7 +16,14 @@ def get_values( map_name: str, key: Union[bytes, str], ) -> Union[List[str], Tuple[str, str, str], List[Tuple[str, str, str]]]: - """Eqivalent to getValues in WoC Perl API + """ + Eqivalent to getValues in WoC Perl API. + + :param map_name: The name of the map, e.g. 'c2p', 'c2r', 'P2c' + :param key: The key of the object. For git objects, it is the SHA-1 hash of the object + (in bytes or hex string). For other objects like Author, it is the name of the object. + :return: The value of the object. Can be a list of strings, a tuple of strings, or a list of tuples of strings. Please refer to the documentation for details. + >>> self.get_values('P2c', 'user2589_minicms') ['05cf84081b63cda822ee407e688269b494a642de', ...] >>> self.get_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') @@ -23,7 +33,7 @@ def get_values( 'Audris Mockus ', 'e4af89166a17785c1d741b8b1d5775f3223f510f') """ - raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") + raise NotImplementedError("WocMapsBase is an abstract class") def show_content( self, @@ -31,6 +41,12 @@ def show_content( key: Union[bytes, str], ) -> Union[List[Tuple[str, str, str]], str, Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]]: """ + Eqivalent to showCnt in WoC Perl API. + + :param obj_name: The name of the object, e.g. 'blob', 'tree', 'commit' + :param key: The key of the object. It is the SHA-1 hash of the object (in bytes or hex string). + :return: The content of the object. Can be a list of tuples of strings, a string, or a tuple of strings. + >>> self.show_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') 'This is the content of the blob' Eqivalent to showCnt in WoC perl API @@ -43,5 +59,18 @@ def show_content( ('Audris Mockus ', '1410029988', '-0400'), 'News for Sep 5, 2014\\n') """ - raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") - \ No newline at end of file + raise NotImplementedError("WocMapsBase is an abstract class") + + def count( + self, map_name: str + ) -> int: + """ + Count the number of keys in a map. + + :param map_name: The name of the mapping / object, e.g. 'c2p', 'c2r', 'commit'. + :return: The number of keys in the tch databases plus the number of large files. + + >>> self.count('c2r') + 12345 + """ + raise NotImplementedError("WocMapsBase is an abstract class") diff --git a/woc/detect.py b/woc/detect.py index 2f0de93..48e4f54 100644 --- a/woc/detect.py +++ b/woc/detect.py @@ -4,23 +4,25 @@ # @authors: Runzhi He # @date: 2024-01-17 -import os +import argparse import json import logging -import argparse +import os import re -from typing import Iterable, Tuple, Optional from functools import cmp_to_key +from typing import Iterable, Optional, Tuple -DEFAULT_PROFILE = os.path.join(os.path.dirname(__file__), 'wocprofile.default.json') +_default_profile = os.path.join(os.path.dirname(__file__), 'wocprofile.default.json') _logger = logging.getLogger(__name__) _logger.setLevel(logging.INFO) MAP_REGEX = r"^(\w+)2(\w+)Full(\w+)(?:.(\d+))?.tch$" +"""Filename regex for basemap files""" _map_pat = re.compile(MAP_REGEX) def parse_map_fname(fname: str): """ - Parse basemap filename into (src, dst, ver, idx) + Parse basemap filename into (src, dst, ver, idx). + >>> parse_map_fname('c2fFullR.3.tch') ('c', 'f', 'R', '3') >>> parse_map_fname('c2fFullR.tch') @@ -32,10 +34,12 @@ def parse_map_fname(fname: str): return m.groups() LARGE_REGEX = r"^(\w+)2(\w+)Full(\w+)(?:.(\d+))?.tch.large.([0-9a-f]+)$" +"""Filename regex for large basemap files""" _large_pat = re.compile(LARGE_REGEX) def parse_large_fname(fname: str): """ - Parse basemap filename into (src, dst, ver, idx, hash) + Parse basemap filename into (src, dst, ver, idx, hash). + >>> parse_large_fname('A2cFullU.15.tch.large.59016a4f') ('A', 'c', 'U', '15', '59016a4f') """ @@ -45,10 +49,12 @@ def parse_large_fname(fname: str): return m.groups() OBJ_REGEX = r"^([\w\.]+)_(\d+).(idx|bin|tch)$" +"""Filename regex for object files""" _obj_pat = re.compile(OBJ_REGEX) def parse_obj_fname(fname: str): """ - Parse sha1map (sha1o/sha1c/blob) filename into (name, idx, ext) + Parse sha1map (sha1o/sha1c/blob) filename into (name, idx, ext). + >>> parse_obj_fname('commit_0.tch') ('commit', '0', 'tch') >>> parse_obj_fname('blob_0.idx') @@ -63,7 +69,8 @@ def parse_obj_fname(fname: str): def compare_woc_version(ver1: str, ver2: str): """ - Compare two woc version strings (A < Z < AA) + Compare two woc version strings (A < Z < AA). + >>> compare_woc_version('S', 'T') > 0 False >>> compare_woc_version('AA', 'U') > 0 @@ -75,7 +82,8 @@ def compare_woc_version(ver1: str, ver2: str): def infer_dtype(map_name: str) -> Tuple[str, str]: """ - Infer the data types from the map's name (entity -> entity) + Infer the data types from the map's name (entity -> entity). + Should be bug-to-bug compatible with: https://github.com/ssc-oscar/lookup/blob/7289885/getValues.perl#L34 >>> infer_dtype('c2f') @@ -126,10 +134,13 @@ def infer_dtype(map_name: str) -> Tuple[str, str]: def detect_profile( paths: Iterable[str], version: Optional[str] = None, - preset_path: str = DEFAULT_PROFILE, + preset_path: Optional[str] = None, check_missing: bool = True ): _maps, _objs = {}, {} + + if not preset_path: + preset_path = _default_profile def _handle_map(src, dst, ver, idx, hash): if version and ver != version: @@ -256,17 +267,17 @@ def _handle_obj(name, idx, ext): res["objects"] = _ls_objs return res -parser = argparse.ArgumentParser(description='Detect woc profile') -parser.add_argument('paths', metavar='PATH', type=str, nargs='+', help='path to woc directory') -parser.add_argument('--version', type=str, default=None, help='woc mapping version') -parser.add_argument('--preset', type=str, default=DEFAULT_PROFILE, help='path to preset profile') -parser.add_argument('--output', type=str, default=None, help='path to output profile') -parser.add_argument('--no-skip-missing', dest='check_missing', action='store_false', help='do not check missing shards') - if __name__ == '__main__': import doctest doctest.testmod() + parser = argparse.ArgumentParser(description='Detect woc profile') + parser.add_argument('paths', metavar='PATH', type=str, nargs='+', help='path to woc directory') + parser.add_argument('--version', type=str, default=None, help='woc mapping version') + parser.add_argument('--preset', type=str, default=_default_profile, help='path to preset profile') + parser.add_argument('--output', type=str, default=None, help='path to output profile') + parser.add_argument('--no-skip-missing', dest='check_missing', action='store_false', help='do not check missing shards') + args = parser.parse_args() res = detect_profile(args.paths, args.version, args.preset, args.check_missing) diff --git a/woc/get_values.py b/woc/get_values.py index c594e00..2b62a11 100644 --- a/woc/get_values.py +++ b/woc/get_values.py @@ -5,16 +5,18 @@ # @date: 2024-05-27 from typing import Iterable + from .local import WocMapsLocal + def format_map(key: str, map_objs: Iterable) -> str: return key + ';' + ';'.join(map(str, map_objs)) if __name__ == '__main__': import argparse - import sys - import os import logging + import os + import sys parser = argparse.ArgumentParser(description='Get record of various maps') parser.add_argument('type', type=str, help='The type of the object') diff --git a/woc/local.pyi b/woc/local.pyi index 108def6..9d73b3e 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -1,12 +1,20 @@ -from typing import Iterable, Union, Tuple, List +from typing import Iterable, List, Tuple, Union -from .base import WocMapsBase, WocObjectsWithContent +from .base import WocMapsBase class WocMapsLocal(WocMapsBase): def __init__(self, - profile_path: str | Iterable[str] | None = None, - version: str | Iterable[str] | None = None + profile_path: Union[str, Iterable[str], None] = None, + version: Union[str, Iterable[str], None] = None ) -> None: + """ + Initialize local WoC maps with a profile. + + :param profile_path: path to the woc profile. + if not provided, use `./wocprofile.json`, `~/.wocprofile.json`, `/etc/wocprofile.json`. + :param version: version of the profile, default to the latest version. + **NOT IMPLEMENTED YET** + """ ... def _get_tch_bytes( @@ -19,20 +27,13 @@ class WocMapsLocal(WocMapsBase): ) -> Tuple[int, int]: """ Get offset and length of a stacked binary object, currently only support blob. + Extract this part because it's much cheaper than decode the content. >>> self._get_pos('blob', bytes.fromhex('7a374e58c5b9dec5f7508391246c48b73c40d200')) (0, 123) """ ... - def count( - self, map_name: str - ) -> int: - """ - Count the number of keys in a map (# of larges + # of tch keys) - """ - ... - # The following functions are internal and should not be used by the user # Exposing them here for testing purposes def fnvhash(data: bytes) -> int: ... diff --git a/woc/local.pyx b/woc/local.pyx index f7d4f3e..17c1676 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -49,11 +49,8 @@ cpdef unber(bytes buf): Format definition: from http://perldoc.perl.org/functions/pack.html (see "w" template description) - Args: - buf (bytes): a binary string with packed values - - Returns: - str: a list of unpacked values + :param buf: a binary string with packed values + :return: a list of unpacked values >>> unber(b'\x00\x83M') [0, 461] @@ -77,16 +74,14 @@ cpdef unber(bytes buf): return res cpdef (int, int) lzf_length(bytes raw_data): - r""" Get length of uncompressed data from a header of Compress::LZF - output. Check Compress::LZF sources for the definition of this bit magic - (namely, LZF.xs, decompress_sv) - https://metacpan.org/source/MLEHMANN/Compress-LZF-3.8/LZF.xs - - Args: - raw_data (bytes): data compressed with Perl Compress::LZF + r""" Get length of uncompressed data from a header of Compress::LZF output. + + Check Compress::LZF sources for the definition of this bit magic: + (namely, LZF.xs, decompress_sv) + https://metacpan.org/source/MLEHMANN/Compress-LZF-3.8/LZF.xs - Returns: - Tuple[int, int]: (header_size, uncompressed_content_length) in bytes + :param raw_data: data compressed with Perl `Compress::LZF` + :return: (header_size, uncompressed_content_length) in bytes >>> lzf_length(b'\xc4\x9b') (2, 283) @@ -122,15 +117,13 @@ cpdef (int, int) lzf_length(bytes raw_data): def decomp(bytes raw_data): # type: (bytes) -> bytes - """ lzf wrapper to handle perl tweaks in Compress::LZF + """lzf wrapper to handle perl tweaks in `Compress::LZF` + This function extracts uncompressed size header and then does usual lzf decompression. - Args: - raw_data (bytes): data compressed with Perl Compress::LZF - - Returns: - str: unpacked data + :param raw_data: data compressed with Perl `Compress::LZF` + :return: unpacked data """ if not raw_data: return b'' @@ -173,7 +166,7 @@ cdef dict _TCH_POOL = {} # type: Dict[str, TCHashDB] TCH_LOCK = Lock() cpdef TCHashDB get_tch(str path): - """ Cache Hash() objects """ + """ Cache TCHashDB objects """ if path in _TCH_POOL: return _TCH_POOL[path] try: @@ -213,6 +206,9 @@ def decode_value( value: bytes, out_dtype: str ): + """ + Decode values from tch maps. + """ if out_dtype == 'h': # type: list[str] return [value[i:i + 20].hex() for i in range(0, len(value), 20)] elif out_dtype == 'sh': # type: tuple[str, str, str] @@ -247,15 +243,12 @@ def decode_tree( value: bytes ) -> List[Tuple[str, str, str]]: """ - Decode a tree binary object into tuples + Decode a tree binary object into tuples. + Python: 4.77 µs, Cython: 280 ns Reference: https://stackoverflow.com/questions/14790681/ - mode (ASCII encoded decimal) - SPACE (\0x20) - filename - NULL (\x00) - 20-byte binary hash - >>> decode_tree(b'100644 .gitignore\x00\x8e\x9e\x1f...') + + >>> decode_tree(b'100644 .gitignore\\x00\\x8e\\x9e\\x1f...') [('100644', '.gitignore', '8e9e1...'), ...] """ files = [] @@ -352,15 +345,17 @@ def decode_commit( commit_bin: bytes ) -> Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]: """ - Decode git commit objects into tuples + Decode git commit objects into tuples. + Python: 2.35 µs, Cython: 855 ns Reference: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects + >>> decode_commit(b'tree f1b66dcca490b5c4455af319bc961a34f69c72c2\\n...') ('f1b66dcca490b5c4455af319bc961a34f69c72c2', - ('c19ff598808b181f1ab2383ff0214520cb3ec659',), - ('Audris Mockus 1410029988', '1410029988', '-0400'), - ('Audris Mockus ', '1410029988', '-0400'), - 'News for Sep 5, 2014\n') + ('c19ff598808b181f1ab2383ff0214520cb3ec659',), + ('Audris Mockus 1410029988', '1410029988', '-0400'), + ('Audris Mockus ', '1410029988', '-0400'), + 'News for Sep 5, 2014\\n') """ cdef: const char* cmt_cstr = commit_bin @@ -640,7 +635,7 @@ class WocMapsLocal(WocMapsBase): map_name: str, key: Union[bytes, str], ): - """Eqivalent to getValues in WoC Perl API + """Eqivalent to getValues in WoC Perl API. >>> self.get_values('P2c', 'user2589_minicms') ['05cf84081b63cda822ee407e688269b494a642de', ...] """ diff --git a/woc/objects.py b/woc/objects.py index 6dcd453..3ac7595 100644 --- a/woc/objects.py +++ b/woc/objects.py @@ -1,81 +1,95 @@ +import difflib import re import warnings -import difflib -from typing import Union, Optional, List, Tuple, Set, Generator, Dict +from datetime import datetime, timedelta, timezone from functools import cached_property, lru_cache -from datetime import datetime, timezone, timedelta from logging import getLogger +from typing import Dict, Generator, List, Optional, Set, Tuple, Union from .base import WocMapsBase from .local import fnvhash _global_woc: Optional[WocMapsBase] = None -logger = getLogger(__name__) -DAY_Z = datetime.fromtimestamp(0, tz=None) +_logger = getLogger(__name__) +_DAY_Z = datetime.fromtimestamp(0, tz=None) + def init_woc_objects(woc: WocMapsBase): + """ + Stores wocMaps object globally so you don't have to pass it around. + + :param woc: a wocMaps object. + """ global _global_woc _global_woc = woc @lru_cache(maxsize=None) -def parse_timezone_offset(offset_str): +def parse_timezone_offset(offset_str: str) -> timezone: """ Parse a timezone offset string in the format '+HHMM' or '-HHMM' into a timezone object. + + >>> parse_timezone_offset('+0530') + timezone(timedelta(seconds=19800)) """ - match = re.match(r'([+-])(\d{2})(\d{2})', offset_str) + match = re.match(r"([+-])(\d{2})(\d{2})", offset_str) if not match: raise ValueError(f"Invalid timezone offset format: {offset_str}") sign, hours, minutes = match.groups() hours, minutes = int(hours), int(minutes) offset = timedelta(hours=hours, minutes=minutes) - - if sign == '-': + + if sign == "-": offset = -offset - + return timezone(offset) - + class _WocObject: - ident: str # Identifier of the object - woc: WocMapsBase # WocMap instance - key: str # Key of the object - + _ident: str + """Identifier of the object""" + woc: WocMapsBase + """WocMap instance""" + key: str + """Key of the object""" + def __init__( - self, + self, *args, woc: Optional[WocMapsBase] = None, **kwargs, ): self.woc = woc or _global_woc - assert self.woc is not None, \ - "WocMaps not initialized: call init_woc_objects() or supply a woc keyword argument" - + assert ( + self.woc is not None + ), "WocMaps not initialized: call init_woc_objects() or supply a woc keyword argument" + def __repr__(self) -> str: return f"{self.__class__.__name__}({self.key})" - + def __str__(self) -> str: return self.key - + def __eq__(self, value: object) -> bool: if not isinstance(value, self.__class__): return False return self.key == value.key - + @property def hash(self) -> str: return hex(hash(self))[2:] - + def _get_list_values(self, map_name: str): - """ A thin wrapper around WocMapsBase.get_values to handle KeyError """ + """A thin wrapper around WocMapsBase.get_values to handle KeyError""" try: return self.woc.get_values(map_name, self.key) except KeyError: return [] - - + + class _GitObject(_WocObject): - """ Base class for SHA1-indexed Git objects (commit, tree, blob) """ + """Base class for SHA1-indexed Git objects (commit, tree, blob)""" + def __init__( self, key: str, @@ -86,22 +100,23 @@ def __init__( super().__init__(*args, woc=woc, **kwargs) assert len(key) == 40, "SHA1 hash must be 40 characters long" self.key = key - + @cached_property def data(self): obj = self.__class__.__name__.lower() return self.woc.show_content(obj, self.key) - + def __hash__(self): return int(self.key, 16) - + @property def hash(self) -> str: return self.key class _NamedObject(_WocObject): - """ Base class for objects indexed by a string key""" + """Base class for objects indexed by a string key""" + def __init__( self, key: str, @@ -111,273 +126,280 @@ def __init__( ): super().__init__(*args, woc=woc, **kwargs) self.key = key - + def __hash__(self): return fnvhash(self.key.encode()) - - + + class Author(_NamedObject): - ident = 'a' + _ident = "a" + @cached_property def _username_email(self) -> Tuple[str, str]: - _splited = self.key.split(' <', 1) + _splited = self.key.split(" <", 1) if len(_splited) == 1: - return _splited[0], '' + return _splited[0], "" return _splited[0], _splited[1][:-1] - + @property def name(self) -> str: return self._username_email[0] - + @property def email(self) -> str: return self._username_email[1] - + @cached_property - def blobs(self) -> 'List[Blob]': - return [Blob(b) for b in self._get_list_values(f'{self.ident}2b')] - + def blobs(self) -> "List[Blob]": + return [Blob(b) for b in self._get_list_values(f"{self._ident}2b")] + @cached_property - def commits(self) -> 'List[Commit]': - return [Commit(c) for c in self._get_list_values(f'{self.ident}2c')] - + def commits(self) -> "List[Commit]": + return [Commit(c) for c in self._get_list_values(f"{self._ident}2c")] + @cached_property - def files(self) -> 'List[File]': - return [File(f) for f in self._get_list_values(f'{self.ident}2f')] - + def files(self) -> "List[File]": + return [File(f) for f in self._get_list_values(f"{self._ident}2f")] + @cached_property - def projects(self) -> 'List[Project]': - return [Project(p) for p in self._get_list_values(f'{self.ident}2p')] - + def projects(self) -> "List[Project]": + return [Project(p) for p in self._get_list_values(f"{self._ident}2p")] + @cached_property - def unique_authors(self) -> List['UniqueAuthor']: - return [UniqueAuthor(a) for a in self._get_list_values(f'{self.ident}2A')] - + def unique_authors(self) -> List["UniqueAuthor"]: + return [UniqueAuthor(a) for a in self._get_list_values(f"{self._ident}2A")] + @property def authors(self): raise NotImplementedError("Author object does not have authors method") - + @cached_property - def first_blobs(self) -> List['Blob']: - return [Blob(b) for b in self._get_list_values(f'{self.ident}2fb')] + def first_blobs(self) -> List["Blob"]: + return [Blob(b) for b in self._get_list_values(f"{self._ident}2fb")] class UniqueAuthor(Author): - ident = 'A' - + _ident = "A" + @property - def unique_authors(self) -> 'List[Author]': - raise NotImplementedError("UniqueAuthor object does not have unique_authors method") - + def unique_authors(self) -> "List[Author]": + raise NotImplementedError( + "UniqueAuthor object does not have unique_authors method" + ) + @cached_property - def authors(self) -> 'List[Author]': - return [Author(a) for a in self._get_list_values(f'{self.ident}2a')] - - + def authors(self) -> "List[Author]": + return [Author(a) for a in self._get_list_values(f"{self._ident}2a")] class Blob(_GitObject): - ident = 'b' + _ident = "b" + @cached_property def _pos(self) -> Tuple[int, int]: - return self.woc.get_pos('blob', self.key) - + return self.woc.get_pos("blob", self.key) + def __len__(self) -> int: return self._pos[1] - + def __str__(self) -> str: return self.data - + @cached_property - def commits(self) -> 'List[Commit]': - return [Commit(sha) for sha in self._get_list_values('b2c')] - + def commits(self) -> "List[Commit]": + return [Commit(sha) for sha in self._get_list_values("b2c")] + @cached_property - def first_author(self) -> 'Tuple[datetime, Author, Commit]': - """ + def first_author(self) -> "Tuple[datetime, Author, Commit]": + """ Returns the timestamp, author, and commit of the first author. + >>> woc.get_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169')) (datetime.datetime(2014, 9, 7, 2, 59, 48), Author(Audris Mockus ), Commit(e4af89166a17785c1d741b8b1d5775f3223f510f)) """ - _out = self.woc.get_values('b2fa', self.key) + _out = self.woc.get_values("b2fa", self.key) _date = datetime.fromtimestamp(int(_out[0])) _author = Author(_out[1]) _commit = Commit(_out[2]) return _date, _author, _commit - + @cached_property - def time_author_commits(self) -> 'List[Tuple[datetime, Author, Commit]]': - _out = self._get_list_values('b2tac') - return [(datetime.fromtimestamp(int(d[0])), Author(d[1]), Commit(d[2])) for d in _out] - + def time_author_commits(self) -> "List[Tuple[datetime, Author, Commit]]": + _out = self._get_list_values("b2tac") + return [ + (datetime.fromtimestamp(int(d[0])), Author(d[1]), Commit(d[2])) for d in _out + ] + @cached_property - def files(self) -> 'List[File]': - return [File(f) for f in self._get_list_values('b2f')] - + def files(self) -> "List[File]": + return [File(f) for f in self._get_list_values("b2f")] + @cached_property - def projects_unique(self) -> 'List[RootProject]': - return [RootProject(p) for p in self._get_list_values('b2P')] - + def projects_unique(self) -> "List[RootProject]": + return [RootProject(p) for p in self._get_list_values("b2P")] + @cached_property - def changed_from(self) -> 'List[Tuple[Blob, Commit, File]]': + def changed_from(self) -> "List[Tuple[Blob, Commit, File]]": return [ - (Blob(b), Commit(c), File(f)) - for b, c, f in self._get_list_values('bb2cf') + (Blob(b), Commit(c), File(f)) for b, c, f in self._get_list_values("bb2cf") ] - + @cached_property - def changed_to(self) -> 'List[Tuple[Blob, Commit, File]]': + def changed_to(self) -> "List[Tuple[Blob, Commit, File]]": return [ - (Blob(b), Commit(c), File(f)) - for b, c, f in self._get_list_values('obb2cf') + (Blob(b), Commit(c), File(f)) for b, c, f in self._get_list_values("obb2cf") ] + class Commit(_GitObject): - ident = 'c' + _ident = "c" + @cached_property def data_obj(self): _ret = {} - (_ret['tree'], - _ret['parent'], - (_ret['author'], _ret['author_timestamp'], _ret['author_timezone']), - (_ret['committer'], _ret['committer_timestamp'], _ret['committer_timezone']), - _ret['message'], + ( + _ret["tree"], + _ret["parent"], + (_ret["author"], _ret["author_timestamp"], _ret["author_timezone"]), + (_ret["committer"], _ret["committer_timestamp"], _ret["committer_timezone"]), + _ret["message"], ) = self.data return _ret - + @property def author(self) -> Author: - return Author(self.data_obj['author']) - + return Author(self.data_obj["author"]) + @property def authored_at(self) -> datetime: - tz = parse_timezone_offset(self.data_obj['author_timezone']) - return datetime.fromtimestamp(int(self.data_obj['author_timestamp']), tz) - + tz = parse_timezone_offset(self.data_obj["author_timezone"]) + return datetime.fromtimestamp(int(self.data_obj["author_timestamp"]), tz) + @property def committer(self) -> Author: - return Author(self.data_obj['committer']) - + return Author(self.data_obj["committer"]) + @property def committed_at(self) -> datetime: - tz = parse_timezone_offset(self.data_obj['committer_timezone']) - return datetime.fromtimestamp(int(self.data_obj['committer_timestamp']), tz) - + tz = parse_timezone_offset(self.data_obj["committer_timezone"]) + return datetime.fromtimestamp(int(self.data_obj["committer_timestamp"]), tz) + @property def full_message(self) -> str: """Full message of the commit""" - return self.data_obj['message'] - + return self.data_obj["message"] + @property def message(self) -> str: """Short message of the commit""" - return self.data_obj['message'].split('\n', 1)[0] - + return self.data_obj["message"].split("\n", 1)[0] + @cached_property - def tree(self) -> 'Tree': - return Tree(self.data_obj['tree']) - + def tree(self) -> "Tree": + return Tree(self.data_obj["tree"]) + @property def _parent_shas(self) -> List[str]: - return self.data_obj['parent'] - + return self.data_obj["parent"] + @property - def parents(self) -> List['Commit']: + def parents(self) -> List["Commit"]: """Parent commits of this commit""" - return [Commit(p) for p in self.data_obj['parent']] - + return [Commit(p) for p in self.data_obj["parent"]] + @cached_property - def projects(self) -> List['Project']: + def projects(self) -> List["Project"]: """Projects associated with this commit""" - return [Project(p) for p in self._get_list_values('c2p')] - + return [Project(p) for p in self._get_list_values("c2p")] + @cached_property - def root_projects(self) -> List['RootProject']: + def root_projects(self) -> List["RootProject"]: """Root projects associated with this commit""" - return [RootProject(p) for p in self._get_list_values('c2P')] - + return [RootProject(p) for p in self._get_list_values("c2P")] + @cached_property - def children(self) -> List['Commit']: + def children(self) -> List["Commit"]: """Children of this commit""" - return [Commit(c) for c in self._get_list_values('c2cc')] - + return [Commit(c) for c in self._get_list_values("c2cc")] + @cached_property def _file_names(self) -> List[str]: - return self._get_list_values('c2f') - + return self._get_list_values("c2f") + @cached_property def _file_set(self) -> Set[str]: return set(self._file_names) - + @cached_property - def files(self) -> List['File']: + def files(self) -> List["File"]: """Files changed in this commit""" return [File(f) for f in self._file_names] - + @cached_property def _blob_shas(self) -> List[str]: - return self._get_list_values('c2b') - + return self._get_list_values("c2b") + @cached_property def _blob_set(self) -> Set[str]: return set(self._blob_shas) - + @cached_property - def blobs(self) -> List['Blob']: + def blobs(self) -> List["Blob"]: """ Blobs changed in this commit. + This relation is known to miss every first file in all trees. Consider using Commit.tree.blobs as a slower but more accurate alternative. """ - return [Blob(b) for b in self._get_list_values('c2b')] - + return [Blob(b) for b in self._get_list_values("c2b")] + @cached_property def time_author(self) -> Tuple[datetime, Author]: """Timestamp and author of the commit""" - res = self.woc.get_values('c2ta', self.key) + res = self.woc.get_values("c2ta", self.key) return datetime.fromtimestamp(int(res[0])), Author(res[1]) - + @cached_property - def root(self) -> 'Tuple[Commit, int]': + def root(self) -> "Tuple[Commit, int]": """Root commit of the project""" - sha, dis = self.woc.get_values('c2r', self.key) + sha, dis = self.woc.get_values("c2r", self.key) return Commit(sha), int(dis) - + @cached_property - def changeset(self) -> 'List[Tuple[File, Blob, Blob]]': + def changeset(self) -> "List[Tuple[File, Blob, Blob]]": """Returns changed files, their new and old blobs""" return [ (File(f), Blob(new), Blob(old)) - for f, new, old in self._get_list_values('c2fbb') + for f, new, old in self._get_list_values("c2fbb") ] - + def compare( - self, - parent: Union['Commit', str], - threshold=0.5 - ) -> Generator[Tuple[Optional['File'], Optional['File'], Optional['Blob'], Optional['Blob']], None, None]: - """ Compare two Commits. - - Args: - parent (Commit): another commit to compare to. + self, parent: Union["Commit", str], threshold=0.5 + ) -> Generator[ + Tuple[Optional["File"], Optional["File"], Optional["Blob"], Optional["Blob"]], + None, + None, + ]: + """ + Compare two Commits. + + :param parent: another commit to compare to. Expected order is `diff = child_commit - parent_commit` - Yields: - Tuple[Optional[str], Optional[str], Optional[str], Optional[str]]: - 4-tuples: `(old_path, new_path, old_sha, new_sha)` - - Examples: - - a new file 'setup.py' was created: - `(None, 'setup.py', None, 'file_sha')` - - an existing 'setup.py' was deleted: - `('setup.py', None, 'old_file_sha', None)` - - setup.py.old was renamed to setup.py, content unchanged: - `('setup.py.old', 'setup.py', 'file_sha', 'file_sha')` - - setup.py was edited: - `('setup.py', 'setup.py', 'old_file_sha', 'new_file_sha')` - - setup.py.old was edited and renamed to setup.py: - `('setup.py.old', 'setup.py', 'old_file_sha', 'new_file_sha')` + :return: a generator of 4-tuples `(old_path, new_path, old_sha, new_sha)` + + Examples: + - a new file 'setup.py' was created: + `(None, 'setup.py', None, 'file_sha')` + - an existing 'setup.py' was deleted: + `('setup.py', None, 'old_file_sha', None)` + - setup.py.old was renamed to setup.py, content unchanged: + `('setup.py.old', 'setup.py', 'file_sha', 'file_sha')` + - setup.py was edited: + `('setup.py', 'setup.py', 'old_file_sha', 'new_file_sha')` + - setup.py.old was edited and renamed to setup.py: + `('setup.py.old', 'setup.py', 'old_file_sha', 'new_file_sha')` Detecting the last one is computationally expensive. You can adjust this behaviour by passing the `threshold` parameter, which is 0.5 by default. @@ -398,7 +420,7 @@ def compare( # new_paths = self.tree._file_set # old_files = parent.tree._file_blob_map # old_paths = parent.tree._file_set - + # !!! We really need to traverse the trees ### new_files: Dict[File, Blob] = {} for f, b in self.tree.traverse(): @@ -412,7 +434,7 @@ def compare( if new_files[f] != old_files[f]: # i.e. Blob sha Changed! yield f, f, old_files[f], new_files[f] - + added_paths: Set[File] = new_files.keys() - old_files.keys() deleted_paths: Set[File] = old_files.keys() - new_files.keys() @@ -422,10 +444,12 @@ def compare( for f in deleted_paths: yield f, None, old_files[f], None return - + if parent.hash not in self._parent_shas: - warnings.warn("Comparing non-adjacent commits might be " - "computationally expensive. Proceed with caution.") + warnings.warn( + "Comparing non-adjacent commits might be " + "computationally expensive. Proceed with caution." + ) # search for matches sm = difflib.SequenceMatcher() @@ -439,11 +463,13 @@ def compare( for deleted_file, deleted_blob in old_files.items(): sm.set_seq2(deleted_blob.data) # use quick checks first (lower bound by length diff) - if sm.real_quick_ratio() > threshold \ - and sm.quick_ratio() > threshold \ - and sm.ratio() > threshold: + if ( + sm.real_quick_ratio() > threshold + and sm.quick_ratio() > threshold + and sm.ratio() > threshold + ): yield deleted_file, added_file, deleted_blob, added_blob - del(old_files[deleted_file]) + del old_files[deleted_file] matched = True break if not matched: # this is a new file @@ -451,84 +477,85 @@ def compare( for deleted_file, deleted_blob in old_files.items(): yield deleted_file, None, deleted_blob, None - - def __sub__(self, parent: 'Commit'): + + def __sub__(self, parent: "Commit"): return self.compare(parent) - + class File(_NamedObject): - ident = 'f' + _ident = "f" + @property def path(self) -> str: return self.key - + @property def name(self) -> str: - return self.key.split('/')[-1] - + return self.key.split("/")[-1] + @cached_property def authors(self) -> List[Author]: - return [Author(a) for a in self._get_list_values('f2a')] - + return [Author(a) for a in self._get_list_values("f2a")] + @cached_property def blobs(self) -> List[Blob]: - return [Blob(b) for b in self._get_list_values('f2b')] - + return [Blob(b) for b in self._get_list_values("f2b")] + @cached_property def commits(self) -> List[Commit]: - return [Commit(c) for c in self._get_list_values('f2c')] - - + return [Commit(c) for c in self._get_list_values("f2c")] + + class Tree(_GitObject): - ident = 't' - + _ident = "t" + @cached_property def data(self) -> str: - return self.woc.show_content('tree', self.key) - + return self.woc.show_content("tree", self.key) + @property def _file_names(self) -> List[str]: return [l[1] for l in self.data] - + @cached_property def _file_set(self) -> Set[str]: - return set(l[1] for l in self.data) - + return {l[1] for l in self.data} + @property - def files(self) -> List['File']: + def files(self) -> List["File"]: return [File(f) for f in self._file_names] - + @property def _blob_shas(self) -> List[str]: return [l[2] for l in self.data] - + @cached_property def _blob_set(self) -> Set[str]: - return set(l[2] for l in self.data) - + return {l[2] for l in self.data} + @property - def blobs(self) -> List['Blob']: + def blobs(self) -> List["Blob"]: return [Blob(b) for b in self._blob_shas] - + @cached_property def _file_blob_map(self) -> Dict[str, str]: return {l[1]: l[2] for l in self.data} - - def _traverse(self) -> 'Generator[Tuple[str, str], None, None]': + + def _traverse(self) -> "Generator[Tuple[str, str], None, None]": for mode, fname, sha in self.data: # trees are always 40000: # https://stackoverflow.com/questions/1071241 - if mode != '40000': + if mode != "40000": yield fname, sha else: - logger.debug(f"traverse: into {fname} ({sha})") + _logger.debug(f"traverse: into {fname} ({sha})") for _fname, _sha in Tree(sha)._traverse(): - yield fname + '/' + _fname, _sha - - def traverse(self) -> 'Generator[Tuple[File, Blob], None, None]': + yield fname + "/" + _fname, _sha + + def traverse(self) -> "Generator[Tuple[File, Blob], None, None]": for fname, sha in self._traverse(): yield File(fname), Blob(sha) - + def __contains__(self, item: Union[str, File, Blob]) -> bool: if isinstance(item, str): return item in self._file_names or item in self._blob_shas @@ -537,38 +564,40 @@ def __contains__(self, item: Union[str, File, Blob]) -> bool: if isinstance(item, Blob): return item.hex in self._blob_shas return False - + def __str__(self) -> str: - return '\n'.join([' '.join(l) for l in self.data]) - + return "\n".join([" ".join(l) for l in self.data]) + def __len__(self) -> int: return len(self.data) - - def __iter__(self) -> 'Generator[Tuple[File, Blob], None, None]': + + def __iter__(self) -> "Generator[Tuple[File, Blob], None, None]": for l in self.data: yield File(l[1]), Blob(l[2]) class Project(_NamedObject): - ident = 'p' - + _ident = "p" + @cached_property def _platform_repo(self) -> str: URL_PREFIXES = self.woc.config["sites"] - prefix, body = self.key.split('_', 1) - if prefix == 'sourceforge.net': + prefix, body = self.key.split("_", 1) + if prefix == "sourceforge.net": platform = URL_PREFIXES[prefix] - elif prefix in URL_PREFIXES and '_' in body: + elif prefix in URL_PREFIXES and "_" in body: platform = URL_PREFIXES[prefix] - body = body.replace('_', '/', 1) + body = body.replace("_", "/", 1) else: - platform = 'github.com' - body = self.key.replace('_', '/', 1) + platform = "github.com" + body = self.key.replace("_", "/", 1) return platform, body @property def url(self) -> str: - """ Get the URL for a given project URI + """ + Get the URL for a given project URI. + >>> Project('CS340-19_lectures').url 'http://github.com/CS340-19/lectures' """ @@ -577,41 +606,42 @@ def url(self) -> str: if platform in URL_PREFIXES: return f"https://{URL_PREFIXES[platform]}/{body}" return f"https://{platform}/{body}" - + @cached_property - def authors(self) -> 'List[Author]': - return [Author(a) for a in self._get_list_values(f'{self.ident}2a')] - + def authors(self) -> "List[Author]": + return [Author(a) for a in self._get_list_values(f"{self._ident}2a")] + @cached_property - def _commit_shas(self) -> 'List[str]': - return self._get_list_values(f'{self.ident}2c') - + def _commit_shas(self) -> "List[str]": + return self._get_list_values(f"{self._ident}2c") + @cached_property - def _commit_set(self) -> 'Set[str]': + def _commit_set(self) -> "Set[str]": return self._commit_map.keys() - + @cached_property - def _commit_map(self) -> 'Dict[str, Commit]': + def _commit_map(self) -> "Dict[str, Commit]": return {c.hash: c for c in self.commits} - + @cached_property - def commits(self) -> 'List[Commit]': + def commits(self) -> "List[Commit]": return [Commit(c) for c in self._commit_shas] - + @cached_property - def root_projects(self) -> 'List[RootProject]': - return [RootProject(p) for p in self._get_list_values(f'{self.ident}2P')] - + def root_projects(self) -> "List[RootProject]": + return [RootProject(p) for p in self._get_list_values(f"{self._ident}2P")] + def __contains__(self, item: Union[str, Commit]) -> bool: if isinstance(item, str): return item in self._commit_set elif isinstance(item, Commit): return item.hash in self._commit_set return False - + @cached_property - def head(self) -> 'Commit': - """ Get the HEAD commit of the repository + def head(self) -> "Commit": + """ + Get the HEAD commit of the repository. >>> Project('user2589_minicms').head Commit(f2a7fcdc51450ab03cb364415f14e634fa69b62c) @@ -628,37 +658,40 @@ def head(self) -> 'Commit': # and continued with a separate chain of commits. # in this case, let's just use the latest one # actually, storing refs would make it much simpler - _heads_sorted = sorted(heads, key=lambda c: c.authored_at or DAY_Z, reverse=True) + _heads_sorted = sorted(heads, key=lambda c: c.authored_at or _DAY_Z, reverse=True) if len(_heads_sorted) == 0: raise ValueError("No head commit found") return _heads_sorted[0] @cached_property - def tail(self) -> 'Commit': - """ Get the first commit SHA by following first parents + def tail(self) -> "Commit": + """ + Get the first commit SHA by following first parents. >>> Project(b'user2589_minicms').tail Commit(1e971a073f40d74a1e72e07c682e1cba0bae159b) """ - pts = set(c._parent_shas[0] for c in self.commits if c._parent_shas) + pts = {c._parent_shas[0] for c in self.commits if c._parent_shas} for c in self.commits: if c.hash in pts and not c._parent_shas: return c - + @cached_property - def earliest_commit(self) -> 'Commit': + def earliest_commit(self) -> "Commit": """Get the earliest commit of the repository""" - return min(self.commits, key=lambda c: c.authored_at or DAY_Z) - + return min(self.commits, key=lambda c: c.authored_at or _DAY_Z) + @cached_property - def latest_commit(self) -> 'Commit': + def latest_commit(self) -> "Commit": """Get the latest commit of the repository""" - return max(self.commits, key=lambda c: c.authored_at or DAY_Z) - - def commits_fp(self) -> Generator['Commit', None, None]: - """ Get a commit chain by following only the first parent, to mimic - https://git-scm.com/docs/git-log#git-log---first-parent . - Thus, you only get a small subset of the full commit tree: + return max(self.commits, key=lambda c: c.authored_at or _DAY_Z) + + def commits_fp(self) -> Generator["Commit", None, None]: + """ + Get a commit chain by following only the first parent. + + Mimic https://git-scm.com/docs/git-log#git-log---first-parent. + Thus, you only get a small subset of the full commit tree. >>> p = Project(b'user2589_minicms') >>> set(c.sha for c in p.commits_fp).issubset(p.commit_shas) @@ -696,35 +729,36 @@ def commits_fp(self) -> Generator['Commit', None, None]: if not first_parent: break commit = self._commit_map.get(first_parent, Commit(first_parent)) - - def __iter__(self) -> 'Generator[Commit, None, None]': + + def __iter__(self) -> "Generator[Commit, None, None]": for c in self.commits: try: - if c.author in self.woc.config['ignoredAuthors']: + if c.author in self.woc.config["ignoredAuthors"]: continue yield c except KeyError: pass - + @property - def projects(self) -> List['Project']: + def projects(self) -> List["Project"]: raise NotImplementedError("Project object does not have projects method") - + + class RootProject(Project): - ident = 'P' - + _ident = "P" + @cached_property - def unique_authors(self) -> 'List[Author]': - return [UniqueAuthor(a) for a in self._get_list_values(f'{self.ident}2A')] - + def unique_authors(self) -> "List[Author]": + return [UniqueAuthor(a) for a in self._get_list_values(f"{self._ident}2A")] + @cached_property - def commits(self) -> 'List[Commit]': - return [Commit(c) for c in self._get_list_values(f'{self.ident}2C')] - + def commits(self) -> "List[Commit]": + return [Commit(c) for c in self._get_list_values(f"{self._ident}2C")] + @cached_property - def projects(self) -> 'List[Project]': - return [Project(p) for p in self._get_list_values(f'{self.ident}2p')] - + def projects(self) -> "List[Project]": + return [Project(p) for p in self._get_list_values(f"{self._ident}2p")] + @property - def root_projects(self) -> List['RootProject']: - raise NotImplementedError("RootProject object does not have root_projects method") \ No newline at end of file + def root_projects(self) -> List["RootProject"]: + raise NotImplementedError("RootProject object does not have root_projects method") diff --git a/woc/show_content.py b/woc/show_content.py index aa11fc7..6920879 100644 --- a/woc/show_content.py +++ b/woc/show_content.py @@ -6,6 +6,7 @@ from .local import WocMapsLocal, decode_commit, decode_str, decomp_or_raw + def format_tree(tree_objs: list) -> str: _out = '' for line in tree_objs: @@ -65,8 +66,8 @@ def format_commit(sha: str, cmt_bin: bytes, format: int = 0): if __name__ == '__main__': import argparse import logging - import sys import os + import sys parser = argparse.ArgumentParser(description='See the Content of Git Object', usage='echo | %(prog)s type (format)') parser.add_argument('type', type=str, help='The type of the object') diff --git a/woc/tch.pyi b/woc/tch.pyi index 2783a7b..1e5d7d9 100644 --- a/woc/tch.pyi +++ b/woc/tch.pyi @@ -6,8 +6,10 @@ class TCHashDB: def __init__(self, path: str, ro: bool = False) -> None: """ Create a new TokyoCabinet hash table object. - :path: path to the database file - :ro: if True, open in lock-free read-only mode; if False, lock and open in write mode (create if not exists) + + :param path: path to the database file + :param ro: if True, open in lock-free read-only mode; if False, lock and open in write mode (create if not exists) + :raises OSError: if the database cannot be opened """ ... @@ -15,23 +17,44 @@ class TCHashDB: ... def get(self, key: bytes) -> bytes: - """Get a record, raise KeyError if not found""" + """ + Get a record. + + :raises KeyError: if the key is not found + :raises OSError: if the operation fails + """ ... def put(self, key: bytes, value: bytes) -> None: - """Upsert a record""" + """ + Upsert a record. + + :raises OSError: if the operation fails + """ ... def delete(self, key: bytes) -> None: - """Delete a record from the database""" + """ + Delete a record from the database. + + :raises OSError: if the operation fails + """ ... def drop(self) -> None: - """Delete all records in the database""" + """ + Delete all records in the database. + + :raises OSError: if the operation fails + """ ... def close(self) -> None: - """Close the database""" + """ + Close the database. + + :raises OSError: if the operation fails + """ ... def __getitem__(self, key: bytes) -> bytes: From a2d8bc53c1651793c3a7b69c580b861ab46b26a3 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 11 Jun 2024 18:35:14 +0800 Subject: [PATCH 28/38] build: add pre-commit config run tests and linters on commit :) also exports requirements.txt from poetry --- .pre-commit-config.yaml | 44 ++++++++++ poetry.lock | 179 +++++++++++++++++++++++++++++++++++++++- pyproject.toml | 17 ++-- requirements.txt | 51 +++++++++++- 4 files changed, 280 insertions(+), 11 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3b4c9af --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,44 @@ +ci: + skip: [pytest] + +default_language_version: + python: python3.8 + +repos: + # general checks (see here: https://pre-commit.com/hooks.html) + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-yaml + args: [--allow-multiple-documents] + - id: end-of-file-fixer + - id: trailing-whitespace + + # ruff: linting + formatting + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.4 + hooks: + - id: ruff + args: ["--fix"] + - id: ruff-format + + # pytest: testing + - repo: local + hooks: + - id: pytest + name: pytest + entry: poetry run pytest + language: system + types: [python] + pass_filenames: false + + # # skip poetry check for now, it's large and slow + # # poetry: check lock and generate requirements.txt + # - repo: https://github.com/python-poetry/poetry + # rev: 1.8.3 + # hooks: + # - id: poetry-check + # args: ["--lock"] + # - id: poetry-export + # args: ["-f", "requirements.txt", "--with", "build", "--output", "requirements.txt"] + # verbose: true diff --git a/poetry.lock b/poetry.lock index e5d64a8..7d72c48 100644 --- a/poetry.lock +++ b/poetry.lock @@ -15,6 +15,17 @@ files = [ six = ">=1.6.1,<2.0" wheel = ">=0.23.0,<1.0" +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + [[package]] name = "chardet" version = "5.2.0" @@ -155,6 +166,17 @@ files = [ {file = "Cython-0.29.37.tar.gz", hash = "sha256:f813d4a6dd94adee5d4ff266191d1d95bf6d4164a4facc535422c021b2504cfb"}, ] +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + [[package]] name = "exceptiongroup" version = "1.2.1" @@ -169,6 +191,36 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "filelock" +version = "3.14.0" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, + {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + +[[package]] +name = "identify" +version = "2.5.36" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, + {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, +] + +[package.extras] +license = ["ukkonen"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -266,6 +318,17 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + [[package]] name = "packaging" version = "24.0" @@ -297,6 +360,22 @@ pygments = ">=2.12.0" [package.extras] dev = ["hypothesis", "mypy", "pdoc-pyo3-sample-library (==1.0.11)", "pygments (>=2.14.0)", "pytest", "pytest-cov", "pytest-timeout", "ruff", "tox", "types-pygments"] +[[package]] +name = "platformdirs" +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + [[package]] name = "pluggy" version = "1.5.0" @@ -312,6 +391,24 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pre-commit" +version = "3.5.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, + {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + [[package]] name = "pygments" version = "2.18.0" @@ -376,6 +473,66 @@ files = [ {file = "python-lzf-0.2.4.tar.gz", hash = "sha256:d1420f1544e612ef1bb41ce0f1d14c2964b3444612f1468f85a886caff3615d1"}, ] +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + [[package]] name = "ruff" version = "0.4.8" @@ -424,6 +581,26 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "virtualenv" +version = "20.26.2" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + [[package]] name = "wheel" version = "0.43.0" @@ -441,4 +618,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "0bfbbf897129d063080303ece80f0a156b953618f1bee862b89e438cfa97b541" +content-hash = "71fb85c62d3733be0f2918e966ca1c00909a75677f744cbc161f19bb9856463e" diff --git a/pyproject.toml b/pyproject.toml index fb2b522..cd109c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,20 +22,23 @@ python = "^3.8" python-lzf = "^0.2.4" chardet = "^5.2.0" -[tool.poetry.group.dev.dependencies] +[tool.poetry.group.build.dependencies] cython = "^0.29.0" + +[tool.poetry.group.dev.dependencies] pytest = "^8.2.2" pytest-cov = "^5.0.0" coverage = {extras = ["toml"], version = "^7.5.3"} # bandit = "^1.7.8" # docformatter = "^1.7.5" -ruff = "^0.4.6" # <- ruff is powerful enough to be the only linter +ruff = "^0.4.4" # <- ruff is powerful enough to be the only linter # sphinx = "^7.1.2" # sphinx-rtd-theme = "^1.0.0" # sphinx-autobuild = "^2021.3.14" # sphinx-pyproject = "^0.3.0" # sphinx-autodoc-typehints = "^1.25.3" pdoc = "^14.5.0" # <- drop sphinx, too many deps and rst is not fun +pre-commit = "^3.5" [build-system] requires = ["poetry-core", "Cython>=0.29.0,<1.0.0", "setuptools>=42"] @@ -118,13 +121,13 @@ ignore = ["E203", "E501", "E741"] [tool.ruff.lint.per-file-ignores] # loose checks for test files "tests/**/*.py" = [ - "S101", - "ARG", + "S101", + "ARG", "FBT", - "PLR2004", - "S311", + "PLR2004", + "S311", "D", "F405", "F403", "F841" -] \ No newline at end of file +] diff --git a/requirements.txt b/requirements.txt index 1f60442..0a648d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,48 @@ -python-lzf -typing -chardet \ No newline at end of file +chardet==5.2.0 ; python_version >= "3.8" and python_version < "4.0" \ + --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \ + --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970 +cython==0.29.37 ; python_version >= "3.8" and python_version < "4.0" \ + --hash=sha256:0301d4739c6894e012f1d410052082fdda9e63888c815d9e23e0f7f82fff7d79 \ + --hash=sha256:0544f7a3e4437b89b356baa15387494c18214e03f2ffaddada5a2c71c3dfd24b \ + --hash=sha256:0a0a6d5972bb3b8c7363cf19a42a988bb0c0bb5ebd9c736c84eca85113ccfdbe \ + --hash=sha256:12192ab269e7185720f2d2f8894587bf1da4276db1b9b869e4622a093f18cae6 \ + --hash=sha256:177481b0a7e003e5c49e2bf0dda1d6fe610c239f17642a5da9f18c2ad0c5f6b6 \ + --hash=sha256:2618af0b8df26d32ee4e8858d4ad8167546596762620aeade84954ae37194a0e \ + --hash=sha256:29415d8eb2fdc1ea518ca4810c50a2d062b387d4c9fbcfb3352346e93db22c6d \ + --hash=sha256:2ad634dc77a6a74022881826099eccac19c9b79153942cc82e754ffac2bec116 \ + --hash=sha256:2de3e729d25f041036e81e2f15683dd129f977dfb5b06267e30e8d7acec43225 \ + --hash=sha256:3f87bef1808d255cf13be378c7ad27ae7c6db6df7732217d32428d1daf4109be \ + --hash=sha256:4658499a41255431f6bbdca7e634e9c8d3a4c190bf24b4aa1646dac751d3da4d \ + --hash=sha256:562f8f911dbd6f1a1b9be8f6cba097125700355688f613994ccd4406f220557a \ + --hash=sha256:6c672089fba6a8f6690b8d7924a58c04477771401ad101d53171a13405ee12cb \ + --hash=sha256:6cddb567dadb3aa3e280a8a35e5126030915ea744c2812206e9c194b8881475d \ + --hash=sha256:79ecfc48694e156402c05561e0adb0e25a6e9d35ac0b41693733a08219d38c58 \ + --hash=sha256:852cd4378cbc9ade02f53709107ff9fdad55019a3a636e8a27663ba6cfce10b6 \ + --hash=sha256:8bf38373773f967cfd793997a6fb96cf972d41a9fce987ace5767349d6f15572 \ + --hash=sha256:8c39c2f5a0fe29bb01de9b1fb449bf65bed6f192317c677f181732791c63fe28 \ + --hash=sha256:9450e0766ab65947f8a2a36f9e59079fc879c3807ec936c61725a48c97741a52 \ + --hash=sha256:95f1d6a83ef2729e67b3fa7318c829ce5b07ac64c084cd6af11c228e0364662c \ + --hash=sha256:9a455347e20ddfad0c5dfee32a3e855ee96811269e5fd86be622ddc4cb326404 \ + --hash=sha256:9e68bafeeb97d5a403fb1f7700bd4a55a1f8989824c323ae02ae8a4fcd88f6a1 \ + --hash=sha256:a6164a05440dcd9daa760c6488bc91bdac1380c7b4b3aca38cf307ba66042d54 \ + --hash=sha256:ac910a28a2fd3d280faf3077b6fe63b97a4b93994ff05647581846f0e4b2f8d1 \ + --hash=sha256:af03854571738307a5f30cc6b724081d72db12f907699e7fdfc04c12c839158e \ + --hash=sha256:af8e7b4397620e2d18259a11f3bfa026eff9846657e397d02616962dd5dd035a \ + --hash=sha256:b048354fd380278f2fa096e7526973beb6e0491a9d44d7e4e29df52612d25776 \ + --hash=sha256:b225d5e2091c224d4ab328165fef224ba3919b3ed44bd9b3241416f523b4d51a \ + --hash=sha256:b6c48f1032b379135a5b4a31976d6c468e02490688acf9254c6c8ed27bd4cbd4 \ + --hash=sha256:b82584836e9e7c0d6effee976595e5cd7fa88dbef3e96e900187983c1d4637d1 \ + --hash=sha256:bbce388431a2608a81c8ab13cb14c50611473843ca766031b8b24bb1723faf79 \ + --hash=sha256:c33508ede9172a6f6f99d5a6dadc7fee23c840423b411ef8b5a403c04e530297 \ + --hash=sha256:cc1b9ce2b73b9ee8c305e06173b35c7c202d4b82d084a0cd73dcedfd6d310aec \ + --hash=sha256:d94caf90ae9cb56116ca6d54cdcbccd3c4df6b0cb7233922b2233ee7fe81d05b \ + --hash=sha256:e14cd44c830e53cf9d7269c87a6bcc638bb065ec07e24990e338162c7001d3c3 \ + --hash=sha256:e841a8b4f9ceefb2916e32dac4f28a895cd519e8ece71505144da1ee355c548a \ + --hash=sha256:e8af5975ecfae254d8c0051204fca995dda8f93cf9f0bbf7571e3cda2b0cef4d \ + --hash=sha256:ea6d208be1906c5df25b674777d5905c6d8e9ef0b201b830849e0729ba08caba \ + --hash=sha256:f2d621fe4cb50007446742134a890500b34e3f50abaf7993baaca02634af7e15 \ + --hash=sha256:f813d4a6dd94adee5d4ff266191d1d95bf6d4164a4facc535422c021b2504cfb \ + --hash=sha256:fa5b6a0f69bf1823c9fd038fa77a2568b78fda2de045a95b48a71dee4d0d578f \ + --hash=sha256:fe0eaf6b1e9ee97c5ee7bfc943f00e36cf59d929db16886cb018352bff8208da +python-lzf==0.2.4 ; python_version >= "3.8" and python_version < "4.0" \ + --hash=sha256:d1420f1544e612ef1bb41ce0f1d14c2964b3444612f1468f85a886caff3615d1 From 888b099e7234a21fe25e5bdf58fa6ed437097ceb Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 11 Jun 2024 18:46:03 +0800 Subject: [PATCH 29/38] style: format sources --- .pre-commit-config.yaml | 9 -- setup.py | 48 +++--- tests/fixtures/create_fixtures.py | 256 +++++++++++++++++------------- tests/test_cli.py | 185 ++++++++++++++------- tests/test_local.py | 111 ++++++++----- tests/test_objects.py | 243 ++++++++++++++++------------ tests/test_profile.json | 2 +- tests/test_tch.py | 52 +++--- woc/__init__.py | 4 +- woc/base.py | 28 ++-- woc/detect.py | 201 +++++++++++++---------- woc/get_values.py | 21 +-- woc/local.pyi | 26 +-- woc/local.pyx | 58 +++---- woc/objects.py | 6 +- woc/show_content.py | 131 ++++++++++----- woc/tch.pxd | 2 +- woc/tch.pyi | 33 ++-- woc/tch.pyx | 12 +- 19 files changed, 844 insertions(+), 584 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3b4c9af..688f5d9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,15 +5,6 @@ default_language_version: python: python3.8 repos: - # general checks (see here: https://pre-commit.com/hooks.html) - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 - hooks: - - id: check-yaml - args: [--allow-multiple-documents] - - id: end-of-file-fixer - - id: trailing-whitespace - # ruff: linting + formatting - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.4.4 diff --git a/setup.py b/setup.py index c171a52..ea88c27 100644 --- a/setup.py +++ b/setup.py @@ -1,13 +1,15 @@ import os -from setuptools import setup, Extension, find_packages + from Cython.Build import cythonize # Thanks to @tryptofame for proposing an updated snippet from Cython.Compiler.Options import get_directive_defaults +from setuptools import Extension, find_packages, setup + directive_defaults = get_directive_defaults() -directive_defaults['linetrace'] = True -directive_defaults['binding'] = True +directive_defaults["linetrace"] = True +directive_defaults["binding"] = True ROOT = os.path.abspath(os.path.dirname(__file__)) PACKAGE_ROOT = os.path.join(ROOT, "woc") @@ -16,28 +18,28 @@ ext_modules = [ Extension( - 'woc.local', - libraries=['bz2', 'z'], - include_dirs=['lib'], + "woc.local", + libraries=["bz2", "z"], + include_dirs=["lib"], sources=[ - os.path.join(PACKAGE_ROOT, 'local.pyx'), - ], - extra_compile_args=['-std=gnu11'], - define_macros=[('CYTHON_TRACE', '1')], + os.path.join(PACKAGE_ROOT, "local.pyx"), + ], + extra_compile_args=["-std=gnu11"], + define_macros=[("CYTHON_TRACE", "1")], ), Extension( - 'woc.tch', - libraries=['bz2', 'z'], - include_dirs=['lib'], + "woc.tch", + libraries=["bz2", "z"], + include_dirs=["lib"], sources=[ - os.path.join(PACKAGE_ROOT, 'tch.pyx'), - os.path.join(TCH_ROOT, 'tchdb.c'), - os.path.join(TCH_ROOT, 'myconf.c'), - os.path.join(TCH_ROOT, 'tcutil.c'), - os.path.join(TCH_ROOT, 'md5.c') - ], - extra_compile_args=['-std=gnu11'], - define_macros=[('CYTHON_TRACE', '1')], + os.path.join(PACKAGE_ROOT, "tch.pyx"), + os.path.join(TCH_ROOT, "tchdb.c"), + os.path.join(TCH_ROOT, "myconf.c"), + os.path.join(TCH_ROOT, "tcutil.c"), + os.path.join(TCH_ROOT, "md5.c"), + ], + extra_compile_args=["-std=gnu11"], + define_macros=[("CYTHON_TRACE", "1")], ), ] @@ -47,5 +49,5 @@ packages=PACKAGES, package_data={"": ["*.pyx", "*.pxd", "*.pxi"]}, include_package_data=True, - script_args=['build_ext', '--inplace'], -) \ No newline at end of file + script_args=["build_ext", "--inplace"], +) diff --git a/tests/fixtures/create_fixtures.py b/tests/fixtures/create_fixtures.py index 16262a5..874f99a 100644 --- a/tests/fixtures/create_fixtures.py +++ b/tests/fixtures/create_fixtures.py @@ -1,14 +1,19 @@ -from typing import List, Union import gzip import json +from typing import List, Union + try: import lzf + assert lzf.decompress except ImportError or AssertionError: - raise ImportError('python-lzf is required to decompress LZF-compressed data: `pip install python-lzf`') + raise ImportError( + "python-lzf is required to decompress LZF-compressed data: `pip install python-lzf`" + ) -from woc.tch import TCHashDB from woc.local import * +from woc.tch import TCHashDB + def ber(*numbers): def gen(): @@ -16,59 +21,63 @@ def gen(): a = True while a: a, num = divmod(num, 128) - yield (a + 0x80 if a else num).to_bytes(1, 'big') - return b''.join(gen()) - -def encode_value( - value, - dtype: str -) -> bytes: - if dtype == 'h': # type: list[str] - return b''.join(bytes.fromhex(v) for v in value) - elif dtype == 'sh': # type: tuple[str, str, str] + yield (a + 0x80 if a else num).to_bytes(1, "big") + + return b"".join(gen()) + + +def encode_value(value, dtype: str) -> bytes: + if dtype == "h": # type: list[str] + return b"".join(bytes.fromhex(v) for v in value) + elif dtype == "sh": # type: tuple[str, str, str] Time, Author, cmt_sha = value buf0 = f"{Time};{Author}".encode() cmt_sha_bytes = bytes.fromhex(cmt_sha) return buf0 + cmt_sha_bytes - elif dtype == 'cs3': # type: list[tuple[str, str, str]] - _joined = ';'.join(f"{t[0]};{t[1]};{t[2]}" for t in value) + elif dtype == "cs3": # type: list[tuple[str, str, str]] + _joined = ";".join(f"{t[0]};{t[1]};{t[2]}" for t in value) data = _joined.encode return lzf.compress(data) - elif dtype == 'cs': # type: list[str] - _joined = ';'.join(v.encode() for v in value if v) + elif dtype == "cs": # type: list[str] + _joined = ";".join(v.encode() for v in value if v) return lzf.compress(_joined.encode()) - elif dtype == 's': # type: list[str] - return b';'.join(v.encode() for v in value) - elif dtype == 'r': # type: list[str, int] + elif dtype == "s": # type: list[str] + return b";".join(v.encode() for v in value) + elif dtype == "r": # type: list[str, int] _hex, _len = value return bytes.fromhex(_hex) + ber(_len) - elif dtype == 'hhwww': - raise NotImplemented - raise ValueError(f'Unsupported dtype: {dtype}') + elif dtype == "hhwww": + raise NotImplementedError + raise ValueError(f"Unsupported dtype: {dtype}") -def write_to_tch(key: bytes, value: bytes, shards: List[str], sharding_bits: int, use_fnv_keys: bool): + +def write_to_tch( + key: bytes, value: bytes, shards: List[str], sharding_bits: int, use_fnv_keys: bool +): shard = get_shard(key, sharding_bits, use_fnv_keys) _path = shards[shard] db = TCHashDB(_path) db[key] = value db.close() + def write_large(path: str, key: bytes, value: bytes, dtype: str): - if dtype == 'h': - with open(path, 'wb') as f: + if dtype == "h": + with open(path, "wb") as f: f.write(key) f.write(value[:160]) else: # use zlib to decompress - with gzip.open(path, 'wb') as f: + with gzip.open(path, "wb") as f: f.write(key) - f.write(b'\n') + f.write(b"\n") # run a fast scan to find idx of 3rd ';' in value idx = 0 for _ in range(3): - idx = value.find(b';', idx + 1) + idx = value.find(b";", idx + 1) f.write(value[:idx]) + class WocMapsCopier(WocMapsLocal): def __init__(self, config1, config2): super().__init__(config1) @@ -84,10 +93,12 @@ def copy_values(self, map_name, key): elif map_name in self.config2["objects"]: _map = self.config2["objects"][map_name] else: - raise KeyError(f'Invalid map name: {map_name}, ' - f'expect one of {", ".join(self.config2["maps"].keys())}') - - if _map["dtypes"][0] == 'h': + raise KeyError( + f'Invalid map name: {map_name}, ' + f'expect one of {", ".join(self.config2["maps"].keys())}' + ) + + if _map["dtypes"][0] == "h": if isinstance(key, str): _hex = key key = bytes.fromhex(key) @@ -95,102 +106,135 @@ def copy_values(self, map_name, key): _hex = bytes(key).hex() else: assert isinstance(key, str), "key must be a string for non-hash keys" - _hex = hex(fnvhash(key.encode('utf-8')))[2:] - key = key.encode('utf-8') + _hex = hex(fnvhash(key.encode("utf-8")))[2:] + key = key.encode("utf-8") if "larges" in _map and _hex in _map["larges"]: - print('writing large', _map["larges"][_hex], 'key', key, 'dtype', _map["dtypes"][1]) + print( + "writing large", + _map["larges"][_hex], + "key", + key, + "dtype", + _map["dtypes"][1], + ) return write_large(_map["larges"][_hex], key, value, _map["dtypes"][1]) else: # use fnv hash as shading idx if key is not a git sha - print('writing to tch', key, _map["sharding_bits"], _map["dtypes"][0] != 'h') - return write_to_tch(key, value, _map["shards"], _map["sharding_bits"], _map["dtypes"][0] != 'h') - + print("writing to tch", key, _map["sharding_bits"], _map["dtypes"][0] != "h") + return write_to_tch( + key, + value, + _map["shards"], + _map["sharding_bits"], + _map["dtypes"][0] != "h", + ) + def copy_content(self, obj: str, key: Union[bytes, str]): """One blob shard can only contain one record""" value, _ = self._get_tch_bytes(obj, key) - if obj == 'tree': - _map_obj = self.config2['objects']['tree.tch'] - print('writing to tch', key, _map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) - - elif obj == 'commit': - _map_obj = self.config2['objects']['commit.tch'] - print('writing to tch', key ,_map_obj["sharding_bits"]) - write_to_tch(bytes.fromhex(key), value, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) - - elif obj == 'blob': + if obj == "tree": + _map_obj = self.config2["objects"]["tree.tch"] + print("writing to tch", key, _map_obj["sharding_bits"]) + write_to_tch( + bytes.fromhex(key), + value, + _map_obj["shards"], + _map_obj["sharding_bits"], + use_fnv_keys=False, + ) + + elif obj == "commit": + _map_obj = self.config2["objects"]["commit.tch"] + print("writing to tch", key, _map_obj["sharding_bits"]) + write_to_tch( + bytes.fromhex(key), + value, + _map_obj["shards"], + _map_obj["sharding_bits"], + use_fnv_keys=False, + ) + + elif obj == "blob": # read blob key = bytes.fromhex(key) if isinstance(key, str) else key - offset, length = self._get_pos('blob', key) - _map_obj = self.config['objects']['blob.bin'] - shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) - with open(_map_obj['shards'][shard], "rb") as f: + offset, length = self._get_pos("blob", key) + _map_obj = self.config["objects"]["blob.bin"] + shard = get_shard(key, _map_obj["sharding_bits"], use_fnv_keys=False) + with open(_map_obj["shards"][shard], "rb") as f: f.seek(offset) _v = f.read(length) # write tch - _map_obj = self.config2['objects']['sha1.blob.tch'] + _map_obj = self.config2["objects"]["sha1.blob.tch"] _idx = ber(0, length) - print('writing to tch', key, _map_obj["sharding_bits"]) - write_to_tch(key, _idx, _map_obj['shards'], _map_obj['sharding_bits'], use_fnv_keys=False) + print("writing to tch", key, _map_obj["sharding_bits"]) + write_to_tch( + key, + _idx, + _map_obj["shards"], + _map_obj["sharding_bits"], + use_fnv_keys=False, + ) # write blob - _map_obj = self.config2['objects']['blob.bin'] - shard = get_shard(key, _map_obj['sharding_bits'], use_fnv_keys=False) - print('writing to file', _map_obj['shards'][shard], length) - with open(_map_obj['shards'][shard], "ab") as f: + _map_obj = self.config2["objects"]["blob.bin"] + shard = get_shard(key, _map_obj["sharding_bits"], use_fnv_keys=False) + print("writing to file", _map_obj["shards"][shard], length) + with open(_map_obj["shards"][shard], "ab") as f: f.write(_v) - + else: - raise ValueError(f'Unsupported object type: {obj}, expected one of tree, blob, commit') - + raise ValueError( + f"Unsupported object type: {obj}, expected one of tree, blob, commit" + ) + -if __name__ == '__main__': +if __name__ == "__main__": import glob import os - for f in glob.glob('./tests/fixtures/*.tch*') + glob.glob('./tests/fixtures/*.bin'): - print('removing', f) + for f in glob.glob("./tests/fixtures/*.tch*") + glob.glob("./tests/fixtures/*.bin"): + print("removing", f) os.remove(f) - cp = WocMapsCopier('./wocprofile.json', './tests/test_profile.json') - cp.copy_values('c2p', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('c2dat', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('c2ta', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('b2tac', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_values('p2a', 'ArtiiQ_PocketMine-MP') - cp.copy_values('b2c', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_values('b2c', '3f2eca18f1bc0f3117748e2cea9251e5182db2f7') # large - cp.copy_values('a2c', 'Audris Mockus ') + cp = WocMapsCopier("./wocprofile.json", "./tests/test_profile.json") + cp.copy_values("c2p", "e4af89166a17785c1d741b8b1d5775f3223f510f") + cp.copy_values("c2dat", "e4af89166a17785c1d741b8b1d5775f3223f510f") + cp.copy_values("c2ta", "e4af89166a17785c1d741b8b1d5775f3223f510f") + cp.copy_values("b2tac", "05fe634ca4c8386349ac519f899145c75fff4169") + cp.copy_values("p2a", "ArtiiQ_PocketMine-MP") + cp.copy_values("b2c", "05fe634ca4c8386349ac519f899145c75fff4169") + cp.copy_values("b2c", "3f2eca18f1bc0f3117748e2cea9251e5182db2f7") # large + cp.copy_values("a2c", "Audris Mockus ") # cp.copy_values('c2cc', 'e4af89166a17785c1d741b8b1d5775f3223f510f') # null - cp.copy_values('a2f', 'Audris Mockus ') - cp.copy_values('c2f', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('c2b', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('p2c', 'ArtiiQ_PocketMine-MP') - cp.copy_values('f2a', 'youtube-statistics-analysis.pdf') - cp.copy_values('b2f', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_content('tree', 'f1b66dcca490b5c4455af319bc961a34f69c72c2') - cp.copy_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - cp.copy_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') - cp.copy_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') + cp.copy_values("a2f", "Audris Mockus ") + cp.copy_values("c2f", "e4af89166a17785c1d741b8b1d5775f3223f510f") + cp.copy_values("c2b", "e4af89166a17785c1d741b8b1d5775f3223f510f") + cp.copy_values("p2c", "ArtiiQ_PocketMine-MP") + cp.copy_values("f2a", "youtube-statistics-analysis.pdf") + cp.copy_values("b2f", "05fe634ca4c8386349ac519f899145c75fff4169") + cp.copy_values("c2r", "e4af89166a17785c1d741b8b1d5775f3223f510f") + cp.copy_values("b2fa", "05fe634ca4c8386349ac519f899145c75fff4169") + cp.copy_content("tree", "f1b66dcca490b5c4455af319bc961a34f69c72c2") + cp.copy_content("commit", "e4af89166a17785c1d741b8b1d5775f3223f510f") + cp.copy_content("blob", "05fe634ca4c8386349ac519f899145c75fff4169") + cp.copy_content("blob", "46aaf071f1b859c5bf452733c2583c70d92cd0c8") # woc-hack_thebridge - cp.copy_values('p2c', 'woc-hack_thebridge') - cp.copy_content('commit', '0d8228bb25ce89c7e731c7410bc8c5a4e2636e52') - cp.copy_content('commit', '34a8662a4f31dacb923e39ae6792f6fc4476a939') - cp.copy_content('commit', '898d5a21241aaf16acf92566aa34103d06cf2ac6') - cp.copy_content('commit', '91f4da4c173e41ffbf0d9ecbe2f07f3a3296933c') - cp.copy_content('commit', 'ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7') - cp.copy_content('commit', 'f249b14a111279faa8d65c29ecf46bb6ce59a139') - cp.copy_content('tree', '706aa4dedb560358bff21c3120a0b09532d3484d') - cp.copy_content('tree', '3ccf6f8320740a1afec68b38b3b9ba46cedef368') - cp.copy_content('tree' ,'e5798457aebae7c84eff7b80b50c3a938cc4cb63') - cp.copy_content('tree', '836f04d5b374033b1608269e2f3aaabae263a0db') - cp.copy_content('tree', 'f54cb5527226aa2096307c08e15c62248b98f763') - cp.copy_content('tree', 'da65e1401d11a955686b8a49e46b9a457f3febab') - cp.copy_content('tree', 'a28f1558be9867d35cc1fa17477565c08786cf83') - cp.copy_content('tree', '4db2ad30097924cbe5da9c0f2c49350fdc19c3a4') - cp.copy_content('tree', '1cf86145b4a9492ebbe0fa640638504946315ca6') - cp.copy_content('tree', '29a422c19251aeaeb907175e9b3219a9bed6c616') - cp.copy_content('tree', '51968a7a4e67fd2696ffd5ccc041560a4d804f5d') + cp.copy_values("p2c", "woc-hack_thebridge") + cp.copy_content("commit", "0d8228bb25ce89c7e731c7410bc8c5a4e2636e52") + cp.copy_content("commit", "34a8662a4f31dacb923e39ae6792f6fc4476a939") + cp.copy_content("commit", "898d5a21241aaf16acf92566aa34103d06cf2ac6") + cp.copy_content("commit", "91f4da4c173e41ffbf0d9ecbe2f07f3a3296933c") + cp.copy_content("commit", "ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7") + cp.copy_content("commit", "f249b14a111279faa8d65c29ecf46bb6ce59a139") + cp.copy_content("tree", "706aa4dedb560358bff21c3120a0b09532d3484d") + cp.copy_content("tree", "3ccf6f8320740a1afec68b38b3b9ba46cedef368") + cp.copy_content("tree", "e5798457aebae7c84eff7b80b50c3a938cc4cb63") + cp.copy_content("tree", "836f04d5b374033b1608269e2f3aaabae263a0db") + cp.copy_content("tree", "f54cb5527226aa2096307c08e15c62248b98f763") + cp.copy_content("tree", "da65e1401d11a955686b8a49e46b9a457f3febab") + cp.copy_content("tree", "a28f1558be9867d35cc1fa17477565c08786cf83") + cp.copy_content("tree", "4db2ad30097924cbe5da9c0f2c49350fdc19c3a4") + cp.copy_content("tree", "1cf86145b4a9492ebbe0fa640638504946315ca6") + cp.copy_content("tree", "29a422c19251aeaeb907175e9b3219a9bed6c616") + cp.copy_content("tree", "51968a7a4e67fd2696ffd5ccc041560a4d804f5d") diff --git a/tests/test_cli.py b/tests/test_cli.py index 9021df9..03468e2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,125 +1,188 @@ import subprocess + def run_show_content(commit_hash, *args): result = subprocess.run( - ['python3', '-m', 'woc.show_content', *args, '-p', './tests/test_profile.json'], + ["python3", "-m", "woc.show_content", *args, "-p", "./tests/test_profile.json"], capture_output=True, text=True, - input=commit_hash + input=commit_hash, ) return result.returncode, result.stdout.strip(), result.stderr.strip() + def run_get_values(input_str, *args): result = subprocess.run( - ['python3', '-m', 'woc.get_values', *args, '-p', './tests/test_profile.json'], + ["python3", "-m", "woc.get_values", *args, "-p", "./tests/test_profile.json"], capture_output=True, text=True, - input=input_str + input=input_str, ) return result.returncode, result.stdout.strip(), result.stderr.strip() + def test_cli_commit(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;f1b66dcca490b5c4455af319bc961a34f69c72c2;c19ff598808b181f1ab2383ff0214520cb3ec659;Audris Mockus ;Audris Mockus ;1410029988;1410029988' - assert run_show_content(commit_hash, 'commit')[1] == expected_output + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = ( + "e4af89166a17785c1d741b8b1d5775f3223f510f;" + "f1b66dcca490b5c4455af319bc961a34f69c72c2;" + "c19ff598808b181f1ab2383ff0214520cb3ec659;" + "Audris Mockus ;" + "Audris Mockus ;1410029988;1410029988" + ) + actual_output = run_show_content(commit_hash, "commit") + assert actual_output[1] == expected_output, actual_output + def test_cli_commit_1(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;1410029988;Audris Mockus ' - assert run_show_content(commit_hash, 'commit', '1')[1] == expected_output + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = ( + "e4af89166a17785c1d741b8b1d5775f3223f510f;1410029988;" + "Audris Mockus " + ) + actual_output = run_show_content(commit_hash, "commit", "1") + assert actual_output[1] == expected_output, actual_output + def test_cli_commit_2(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;Audris Mockus ;1410029988;-0400;News for Sep 5' - print(run_show_content(commit_hash, 'commit', '2')) - assert run_show_content(commit_hash, 'commit', '2')[1] == expected_output + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = ( + "e4af89166a17785c1d741b8b1d5775f3223f510f;Audris Mockus ;" + "1410029988;-0400;News for Sep 5" + ) + actual_output = run_show_content(commit_hash, "commit", "2") + assert actual_output[1] == expected_output, actual_output + def test_cli_commit_3(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" expected_output = """tree f1b66dcca490b5c4455af319bc961a34f69c72c2 parent c19ff598808b181f1ab2383ff0214520cb3ec659 author Audris Mockus 1410029988 -0400 committer Audris Mockus 1410029988 -0400 News for Sep 5""" - assert run_show_content(commit_hash, 'commit', '3')[1] == expected_output + actual_output = run_show_content(commit_hash, "commit", "3") + assert actual_output[1] == expected_output, actual_output + def test_cli_commit_4(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;Audris Mockus ' - assert run_show_content(commit_hash, 'commit', '4')[1] == expected_output + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = ( + "e4af89166a17785c1d741b8b1d5775f3223f510f;Audris Mockus " + ) + actual_output = run_show_content(commit_hash, "commit", "4") + assert actual_output[1] == expected_output, actual_output + def test_cli_commit_5(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;c19ff598808b181f1ab2383ff0214520cb3ec659' - assert run_show_content(commit_hash, 'commit', '5')[1] == expected_output + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = "e4af89166a17785c1d741b8b1d5775f3223f510f;c19ff598808b181f1ab2383ff0214520cb3ec659" + actual_output = run_show_content(commit_hash, "commit", "5") + assert actual_output[1] == expected_output, actual_output + def test_cli_commit_6(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output_end = 'c19ff598808b181f1ab2383ff0214520cb3ec659' - assert run_show_content(commit_hash, 'commit', '6')[1].endswith(expected_output_end), run_show_content(commit_hash, 'commit', '6') + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output_end = "c19ff598808b181f1ab2383ff0214520cb3ec659" + actual_output = run_show_content(commit_hash, "commit", "6") + assert actual_output[1].endswith(expected_output_end), actual_output + def test_cli_commit_7(): - commit_hash = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output_end = 'QHV0ay5lZHU+IDE0MTAwMjk5ODggLTA0MDAKCk5ld3MgZm9yIFNlcCA1\\n' - assert run_show_content(commit_hash, 'commit', '7')[1].endswith(expected_output_end) + commit_hash = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output_end = "QHV0ay5lZHU+IDE0MTAwMjk5ODggLTA0MDAKCk5ld3MgZm9yIFNlcCA1\\n" + actual_output = run_show_content(commit_hash, "commit", "7") + assert actual_output[1].endswith(expected_output_end), actual_output + def test_cli_tree(): - tree_hash = 'f1b66dcca490b5c4455af319bc961a34f69c72c2' - expected_output = '100644;05fe634ca4c8386349ac519f899145c75fff4169;README.md\n100644;dfcd0359bfb5140b096f69d5fad3c7066f101389;course.pdf' - assert run_show_content(tree_hash, 'tree')[1] == expected_output + tree_hash = "f1b66dcca490b5c4455af319bc961a34f69c72c2" + expected_output = "100644;05fe634ca4c8386349ac519f899145c75fff4169;README.md\n100644;dfcd0359bfb5140b096f69d5fad3c7066f101389;course.pdf" + actual_output = run_show_content(tree_hash, "tree") + assert actual_output[1] == expected_output, actual_output + def test_cli_blob(): - blob_hash = '05fe634ca4c8386349ac519f899145c75fff4169' + blob_hash = "05fe634ca4c8386349ac519f899145c75fff4169" expected_output_start = '# Syllabus for "Fundamentals of Digital Archeology"\n\n## News\n\n* Assignment1 due Monday Sep 8 before 2:30PM' - assert run_show_content(blob_hash, 'blob')[1].startswith(expected_output_start), run_show_content(blob_hash, 'blob') + actual_output = run_show_content(blob_hash, "blob") + assert actual_output[1].startswith(expected_output_start), actual_output + def test_cli_a2c(): input_str = "Audris Mockus " - expected_output_start = 'Audris Mockus ;001ec7302de3b07f32669a1f1faed74585c8a8dc' - print(run_get_values(input_str, 'a2c')) - assert run_get_values(input_str, 'a2c')[1].startswith(expected_output_start), run_get_values(input_str, 'a2c') + expected_output_start = ( + "Audris Mockus ;001ec7302de3b07f32669a1f1faed74585c8a8dc" + ) + actual_output = run_get_values(input_str, "a2c") + assert actual_output[1].startswith(expected_output_start), actual_output + def test_cli_a2f(): input_str = "Audris Mockus " - expected_output_start = 'Audris Mockus ;.#analyze.sh;.README.md.swp;.Rhistory;.bowerrc' - assert run_get_values(input_str, 'a2f')[1].startswith(expected_output_start), run_get_values(input_str, 'a2f') + expected_output_start = ( + "Audris Mockus ;.#analyze.sh;.README.md.swp;.Rhistory;.bowerrc" + ) + actual_output = run_get_values(input_str, "a2f") + assert actual_output[1].startswith(expected_output_start), actual_output + def test_cli_b2c(): - input_str = '05fe634ca4c8386349ac519f899145c75fff4169' - expected_output = '05fe634ca4c8386349ac519f899145c75fff4169;e4af89166a17785c1d741b8b1d5775f3223f510f' - assert run_get_values(input_str, 'b2c')[1] == expected_output + input_str = "05fe634ca4c8386349ac519f899145c75fff4169" + expected_output = "05fe634ca4c8386349ac519f899145c75fff4169;e4af89166a17785c1d741b8b1d5775f3223f510f" + actual_output = run_get_values(input_str, "b2c") + assert actual_output[1] == expected_output, actual_output + def test_cli_c2b(): - input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;05fe634ca4c8386349ac519f899145c75fff4169' - assert run_get_values(input_str, 'c2b')[1] == expected_output + input_str = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = "e4af89166a17785c1d741b8b1d5775f3223f510f;05fe634ca4c8386349ac519f899145c75fff4169" + actual_output = run_get_values(input_str, "c2b") + assert actual_output[1] == expected_output, actual_output + def test_cli_c2cc(): # expect error - input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - assert run_get_values(input_str, 'c2cc')[2].endswith("shard 0 not found at None"), run_get_values(input_str, 'c2cc') + input_str = "e4af89166a17785c1d741b8b1d5775f3223f510f" + actual_output = run_get_values(input_str, "c2cc") + assert actual_output[2].endswith("shard 0 not found at None"), actual_output + def test_cli_c2f(): - input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;README.md' - assert run_get_values(input_str, 'c2f')[1] == expected_output + input_str = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = "e4af89166a17785c1d741b8b1d5775f3223f510f;README.md" + assert run_get_values(input_str, "c2f")[1] == expected_output + def test_cli_c2p(): - input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output_start = 'e4af89166a17785c1d741b8b1d5775f3223f510f;W4D3_news;chumekaboom_news' - assert run_get_values(input_str, 'c2p')[1].startswith(expected_output_start), run_get_values(input_str, 'c2p') + input_str = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output_start = ( + "e4af89166a17785c1d741b8b1d5775f3223f510f;W4D3_news;chumekaboom_news" + ) + actual_output = run_get_values(input_str, "c2p") + assert actual_output[1].startswith(expected_output_start), actual_output + def test_cli_c2r(): - input_str = 'e4af89166a17785c1d741b8b1d5775f3223f510f' - expected_output = 'e4af89166a17785c1d741b8b1d5775f3223f510f;9531fc286ef1f4753ca4be9a3bf76274b929cdeb;27' - assert run_get_values(input_str, 'c2r')[1] == expected_output + input_str = "e4af89166a17785c1d741b8b1d5775f3223f510f" + expected_output = "e4af89166a17785c1d741b8b1d5775f3223f510f;9531fc286ef1f4753ca4be9a3bf76274b929cdeb;27" + actual_output = run_get_values(input_str, "c2r") + assert actual_output[1] == expected_output, actual_output + def test_cli_p2a(): - input_str = 'ArtiiQ_PocketMine-MP' - expected_output_start = 'ArtiiQ_PocketMine-MP;0929hitoshi ;' - assert run_get_values(input_str, 'p2a')[1].startswith(expected_output_start), run_get_values(input_str, 'p2a') + input_str = "ArtiiQ_PocketMine-MP" + expected_output_start = ( + "ArtiiQ_PocketMine-MP;0929hitoshi ;" + ) + actual_output = run_get_values(input_str, "p2a") + assert actual_output[1].startswith(expected_output_start), actual_output + def test_cli_p2c(): - input_str = 'ArtiiQ_PocketMine-MP' - expected_output_start = 'ArtiiQ_PocketMine-MP;0000000bab11354f9a759332065be5f066c3398f' - assert run_get_values(input_str, 'p2c')[1].startswith(expected_output_start), run_get_values(input_str, 'p2c') \ No newline at end of file + input_str = "ArtiiQ_PocketMine-MP" + expected_output_start = ( + "ArtiiQ_PocketMine-MP;0000000bab11354f9a759332065be5f066c3398f" + ) + actual_output = run_get_values(input_str, "p2c") + assert actual_output[1].startswith(expected_output_start), actual_output diff --git a/tests/test_local.py b/tests/test_local.py index 691b60d..1c91586 100644 --- a/tests/test_local.py +++ b/tests/test_local.py @@ -1,99 +1,126 @@ -import pytest import os +import pytest + # Import the TCHashDB class from woc.local import WocMapsLocal + @pytest.fixture def woc(): - _test_pr = os.path.join(os.path.dirname(__file__), 'test_profile.json') + _test_pr = os.path.join(os.path.dirname(__file__), "test_profile.json") woc = WocMapsLocal(_test_pr) yield woc + def test_c2p(woc): - res = woc.get_values('c2p', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - assert res[0] == 'W4D3_news' + res = woc.get_values("c2p", "e4af89166a17785c1d741b8b1d5775f3223f510f") + assert res[0] == "W4D3_news" + def test_c2dat(woc): - res = woc.get_values('c2dat', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - assert res[0] == '1410029988' + res = woc.get_values("c2dat", "e4af89166a17785c1d741b8b1d5775f3223f510f") + assert res[0] == "1410029988" + def test_b2tac(woc): - res = woc.get_values('b2tac', '05fe634ca4c8386349ac519f899145c75fff4169') - assert res[0] == ('1410029988', 'Audris Mockus ', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + res = woc.get_values("b2tac", "05fe634ca4c8386349ac519f899145c75fff4169") + assert res[0] == ( + "1410029988", + "Audris Mockus ", + "e4af89166a17785c1d741b8b1d5775f3223f510f", + ) + def test_p2a(woc): - res = woc.get_values('p2a', 'ArtiiQ_PocketMine-MP') - assert res[0] == '0929hitoshi ' + res = woc.get_values("p2a", "ArtiiQ_PocketMine-MP") + assert res[0] == "0929hitoshi " + def test_b2c(woc): - res = woc.get_values('b2c', '05fe634ca4c8386349ac519f899145c75fff4169') - assert res[0] == 'e4af89166a17785c1d741b8b1d5775f3223f510f' + res = woc.get_values("b2c", "05fe634ca4c8386349ac519f899145c75fff4169") + assert res[0] == "e4af89166a17785c1d741b8b1d5775f3223f510f" + def test_b2c_large(woc): - res = woc.get_values('b2c', '3f2eca18f1bc0f3117748e2cea9251e5182db2f7') - assert res[0] == '00003a69db53b45a67f76632f33a93691da77197' + res = woc.get_values("b2c", "3f2eca18f1bc0f3117748e2cea9251e5182db2f7") + assert res[0] == "00003a69db53b45a67f76632f33a93691da77197" + def test_a2c(woc): - res = woc.get_values('a2c', 'Audris Mockus ') - assert res[0] == '001ec7302de3b07f32669a1f1faed74585c8a8dc' + res = woc.get_values("a2c", "Audris Mockus ") + assert res[0] == "001ec7302de3b07f32669a1f1faed74585c8a8dc" + def test_c2cc_null_filename(woc): # file name is null with pytest.raises(AssertionError): - woc.get_values('c2cc', 'e4af89166a17785c1d741b8b1d5775f3223f510f') + woc.get_values("c2cc", "e4af89166a17785c1d741b8b1d5775f3223f510f") + def test_a2f(woc): - res = woc.get_values('a2f', 'Audris Mockus ') - assert res[0] == '.#analyze.sh' + res = woc.get_values("a2f", "Audris Mockus ") + assert res[0] == ".#analyze.sh" + def test_c2f(woc): - res = woc.get_values('c2f', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - assert res[0] == 'README.md' + res = woc.get_values("c2f", "e4af89166a17785c1d741b8b1d5775f3223f510f") + assert res[0] == "README.md" + def test_c2b(woc): - res = woc.get_values('c2b', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - assert res[0] == '05fe634ca4c8386349ac519f899145c75fff4169' + res = woc.get_values("c2b", "e4af89166a17785c1d741b8b1d5775f3223f510f") + assert res[0] == "05fe634ca4c8386349ac519f899145c75fff4169" + def test_p2c(woc): - res = woc.get_values('p2c', 'ArtiiQ_PocketMine-MP') - assert res[0] == '0000000bab11354f9a759332065be5f066c3398f' + res = woc.get_values("p2c", "ArtiiQ_PocketMine-MP") + assert res[0] == "0000000bab11354f9a759332065be5f066c3398f" + def test_f2a(woc): - res = woc.get_values('f2a', 'youtube-statistics-analysis.pdf') - assert res[0] == 'Audris Mockus ' + res = woc.get_values("f2a", "youtube-statistics-analysis.pdf") + assert res[0] == "Audris Mockus " + def test_b2f(woc): - res = woc.get_values('b2f', '05fe634ca4c8386349ac519f899145c75fff4169') - assert res[0] == 'README.md' + res = woc.get_values("b2f", "05fe634ca4c8386349ac519f899145c75fff4169") + assert res[0] == "README.md" + def test_c2r(woc): - res = woc.get_values('c2r', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - assert res[0] == '9531fc286ef1f4753ca4be9a3bf76274b929cdeb' + res = woc.get_values("c2r", "e4af89166a17785c1d741b8b1d5775f3223f510f") + assert res[0] == "9531fc286ef1f4753ca4be9a3bf76274b929cdeb" + def test_b2fa(woc): - res = woc.get_values('b2fa', '05fe634ca4c8386349ac519f899145c75fff4169') - assert res[0] == '1410029988' + res = woc.get_values("b2fa", "05fe634ca4c8386349ac519f899145c75fff4169") + assert res[0] == "1410029988" + def test_tree(woc): - res = woc.show_content('tree', 'f1b66dcca490b5c4455af319bc961a34f69c72c2') - assert len(res) == 2 + res = woc.show_content("tree", "f1b66dcca490b5c4455af319bc961a34f69c72c2") + assert len(res) == 2 + def test_commit(woc): - res = woc.show_content('commit', 'e4af89166a17785c1d741b8b1d5775f3223f510f') - assert res[-1] == 'News for Sep 5' + res = woc.show_content("commit", "e4af89166a17785c1d741b8b1d5775f3223f510f") + assert res[-1] == "News for Sep 5" + def test_blob_1(woc): - res = woc.show_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') + res = woc.show_content("blob", "05fe634ca4c8386349ac519f899145c75fff4169") assert len(res) == 14194 + def test_blob_2(woc): - res = woc.show_content('blob', '46aaf071f1b859c5bf452733c2583c70d92cd0c8') + res = woc.show_content("blob", "46aaf071f1b859c5bf452733c2583c70d92cd0c8") assert len(res) == 1236 + def test_count(woc): - res = woc.count('blob') + res = woc.count("blob") assert res == 2 - res = woc.count('tree') + res = woc.count("tree") assert res == 12 - res = woc.count('commit') + res = woc.count("commit") assert res == 7 diff --git a/tests/test_objects.py b/tests/test_objects.py index 24014f5..4ef1b4f 100644 --- a/tests/test_objects.py +++ b/tests/test_objects.py @@ -1,260 +1,305 @@ -import pytest import os +import pytest + # Import the TCHashDB class from woc.local import WocMapsLocal from woc.objects import * + @pytest.fixture def woc(): - _test_pr = os.path.join(os.path.dirname(__file__), 'test_profile.json') + _test_pr = os.path.join(os.path.dirname(__file__), "test_profile.json") woc = WocMapsLocal(_test_pr) init_woc_objects(woc) yield woc + def test_equal(woc): - assert Author('1') == Author('1') - assert Blob('05fe634ca4c8386349ac519f899145c75fff4169') == Blob('05fe634ca4c8386349ac519f899145c75fff4169') - assert Author('1') != Project('2') - + assert Author("1") == Author("1") + assert Blob("05fe634ca4c8386349ac519f899145c75fff4169") == Blob( + "05fe634ca4c8386349ac519f899145c75fff4169" + ) + assert Author("1") != Project("2") + + def test_author_commits(woc): - author = Author('Audris Mockus ') + author = Author("Audris Mockus ") commits = author.commits assert all(isinstance(c, Commit) for c in commits) - assert commits[0].key == '001ec7302de3b07f32669a1f1faed74585c8a8dc' + assert commits[0].key == "001ec7302de3b07f32669a1f1faed74585c8a8dc" + def test_author_files(woc): - author = Author('Audris Mockus ') + author = Author("Audris Mockus ") files = author.files assert all(isinstance(f, File) for f in files) - assert files[0].key == '.#analyze.sh' - + assert files[0].key == ".#analyze.sh" + + def test_author_name_email(woc): - author = Author('Audris Mockus ') - assert author.name == 'Audris Mockus' - assert author.email == 'audris@utk.edu' - + author = Author("Audris Mockus ") + assert author.name == "Audris Mockus" + assert author.email == "audris@utk.edu" + + def test_blob_data(woc): - blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + blob = Blob("05fe634ca4c8386349ac519f899145c75fff4169") res = blob.data assert len(res) == 14194 + def test_blob_commits(woc): - blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + blob = Blob("05fe634ca4c8386349ac519f899145c75fff4169") commits = blob.commits assert all(isinstance(c, Commit) for c in commits) - assert commits[0].key == 'e4af89166a17785c1d741b8b1d5775f3223f510f' - + assert commits[0].key == "e4af89166a17785c1d741b8b1d5775f3223f510f" + + def test_blob_commits_large(woc): - blob = Blob('3f2eca18f1bc0f3117748e2cea9251e5182db2f7') + blob = Blob("3f2eca18f1bc0f3117748e2cea9251e5182db2f7") commits = blob.commits assert all(isinstance(c, Commit) for c in commits) - assert commits[0].key == '00003a69db53b45a67f76632f33a93691da77197' + assert commits[0].key == "00003a69db53b45a67f76632f33a93691da77197" + def test_blob_first_author(woc): - blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + blob = Blob("05fe634ca4c8386349ac519f899145c75fff4169") date, author, commit = blob.first_author assert isinstance(date, datetime) assert isinstance(author, Author) assert isinstance(commit, Commit) assert date.timestamp() == 1410029988 - assert date.tzinfo is None # naive datetime - assert author.key == 'Audris Mockus ' - assert commit.key == 'e4af89166a17785c1d741b8b1d5775f3223f510f' - + assert date.tzinfo is None # naive datetime + assert author.key == "Audris Mockus " + assert commit.key == "e4af89166a17785c1d741b8b1d5775f3223f510f" + + def test_blob_time_author_commits(woc): - blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + blob = Blob("05fe634ca4c8386349ac519f899145c75fff4169") date, author, commit = blob.time_author_commits[0] assert isinstance(date, datetime) assert isinstance(author, Author) assert isinstance(commit, Commit) assert date.timestamp() == 1410029988 - assert date.tzinfo is None # naive datetime - assert author.key == 'Audris Mockus ' - assert commit.key == 'e4af89166a17785c1d741b8b1d5775f3223f510f' + assert date.tzinfo is None # naive datetime + assert author.key == "Audris Mockus " + assert commit.key == "e4af89166a17785c1d741b8b1d5775f3223f510f" + def test_blob_files(woc): - blob = Blob('05fe634ca4c8386349ac519f899145c75fff4169') + blob = Blob("05fe634ca4c8386349ac519f899145c75fff4169") files = blob.files assert all(isinstance(f, File) for f in files) - assert files[0].key == 'README.md' + assert files[0].key == "README.md" + def test_commit_author(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") author = commit.author assert isinstance(author, Author) - assert author.key == 'Audris Mockus ' + assert author.key == "Audris Mockus " + def test_commit_authored_at(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") authored_at = commit.authored_at assert isinstance(authored_at, datetime) assert authored_at.timestamp() == 1410029988 assert authored_at.tzinfo is not None # aware datetime + def test_commit_committer(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") committer = commit.committer assert isinstance(committer, Author) - assert committer.key == 'Audris Mockus ' + assert committer.key == "Audris Mockus " + def test_commit_committed_at(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") committed_at = commit.committed_at assert isinstance(committed_at, datetime) assert committed_at.timestamp() == 1410029988 assert committed_at.tzinfo is not None # aware datetime + def test_commit_full_message(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") full_message = commit.full_message - assert full_message == 'News for Sep 5' + assert full_message == "News for Sep 5" + def test_commit_message(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") message = commit.message - assert message == 'News for Sep 5' + assert message == "News for Sep 5" + def test_commit_tree(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") tree = commit.tree assert isinstance(tree, Tree) - assert tree.key == 'f1b66dcca490b5c4455af319bc961a34f69c72c2' + assert tree.key == "f1b66dcca490b5c4455af319bc961a34f69c72c2" + def test_commit_parents(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") parents = commit.parents assert all(isinstance(p, Commit) for p in parents) - assert parents[0].key == 'c19ff598808b181f1ab2383ff0214520cb3ec659' + assert parents[0].key == "c19ff598808b181f1ab2383ff0214520cb3ec659" + def test_commit_projects(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") projects = commit.projects assert all(isinstance(p, Project) for p in projects) - assert projects[0].key == 'W4D3_news' + assert projects[0].key == "W4D3_news" + def test_commit_children_null_filename(woc): with pytest.raises(AssertionError): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") children = commit.children + def test_commit_files(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") files = commit.files assert all(isinstance(f, File) for f in files) - assert files[0].key == 'README.md' + assert files[0].key == "README.md" + def test_commit_blobs(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") blobs = commit.blobs - assert blobs[0].key == '05fe634ca4c8386349ac519f899145c75fff4169' + assert blobs[0].key == "05fe634ca4c8386349ac519f899145c75fff4169" assert all(isinstance(b, Blob) for b in blobs) + def test_commit_time_author(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") time_author = commit.time_author assert isinstance(time_author[0], datetime) assert isinstance(time_author[1], Author) assert time_author[0].timestamp() == 1410029988 assert time_author[0].tzinfo is None # naive datetime + def test_commit_root(woc): - commit = Commit('e4af89166a17785c1d741b8b1d5775f3223f510f') + commit = Commit("e4af89166a17785c1d741b8b1d5775f3223f510f") root, distance = commit.root assert isinstance(root, Commit) - assert root.key == '9531fc286ef1f4753ca4be9a3bf76274b929cdeb' + assert root.key == "9531fc286ef1f4753ca4be9a3bf76274b929cdeb" assert distance == 27 + def test_file_authors(woc): - file = File('youtube-statistics-analysis.pdf') + file = File("youtube-statistics-analysis.pdf") authors = file.authors assert all(isinstance(a, Author) for a in authors) - assert authors[0].key == 'Audris Mockus ' + assert authors[0].key == "Audris Mockus " + def test_tree_files(woc): - tree = Tree('f1b66dcca490b5c4455af319bc961a34f69c72c2') + tree = Tree("f1b66dcca490b5c4455af319bc961a34f69c72c2") files = tree.files assert all(isinstance(f, File) for f in files) - assert set(files) == set((File('README.md'), File('course.pdf'))), str(files) + assert set(files) == {File("README.md"), File("course.pdf")}, str(files) + def test_tree_blobs(woc): - tree = Tree('f1b66dcca490b5c4455af319bc961a34f69c72c2') + tree = Tree("f1b66dcca490b5c4455af319bc961a34f69c72c2") blobs = tree.blobs assert all(isinstance(b, Blob) for b in blobs) - assert Blob('05fe634ca4c8386349ac519f899145c75fff4169') in blobs + assert Blob("05fe634ca4c8386349ac519f899145c75fff4169") in blobs + def test_tree_traverse(woc): - tree = Tree('706aa4dedb560358bff21c3120a0b09532d3484d') + tree = Tree("706aa4dedb560358bff21c3120a0b09532d3484d") traverse = list(tree.traverse()) assert all(isinstance(t[0], File) for t in traverse) assert all(isinstance(t[1], Blob) for t in traverse) - + + def test_project_authors(woc): - project = Project('ArtiiQ_PocketMine-MP') + project = Project("ArtiiQ_PocketMine-MP") authors = project.authors assert all(isinstance(a, Author) for a in authors) - assert authors[0].key == '0929hitoshi ' - + assert authors[0].key == "0929hitoshi " + + def test_project_commits(woc): - project = Project('ArtiiQ_PocketMine-MP') + project = Project("ArtiiQ_PocketMine-MP") commits = project.commits assert all(isinstance(c, Commit) for c in commits) - assert commits[0].key == '0000000bab11354f9a759332065be5f066c3398f' - + assert commits[0].key == "0000000bab11354f9a759332065be5f066c3398f" + + def test_project_url(woc): - project = Project('ArtiiQ_PocketMine-MP') - assert project.url == 'https://github.com/ArtiiQ/PocketMine-MP' - project = Project('sourceforge.net_peazip') # <- How does sourceforge repos looks like in woc? - assert project.url == 'https://git.code.sf.net/p/peazip' + project = Project("ArtiiQ_PocketMine-MP") + assert project.url == "https://github.com/ArtiiQ/PocketMine-MP" + project = Project( + "sourceforge.net_peazip" + ) # <- How does sourceforge repos looks like in woc? + assert project.url == "https://git.code.sf.net/p/peazip" project = Project("gitlab.com_openRGB_openRGB") - assert project.url == 'https://gitlab.com/openRGB/openRGB' - + assert project.url == "https://gitlab.com/openRGB/openRGB" + + def test_project_head(woc): - project = Project('woc-hack_thebridge') + project = Project("woc-hack_thebridge") head = project.head assert isinstance(head, Commit) - assert head.key == 'f249b14a111279faa8d65c29ecf46bb6ce59a139' - + assert head.key == "f249b14a111279faa8d65c29ecf46bb6ce59a139" + + def test_project_tail(woc): - project = Project('woc-hack_thebridge') + project = Project("woc-hack_thebridge") tail = project.tail assert isinstance(tail, Commit) - assert tail.key == 'ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7' - + assert tail.key == "ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7" + + def test_project_earliest(woc): - project = Project('woc-hack_thebridge') + project = Project("woc-hack_thebridge") earliest = project.earliest_commit assert isinstance(earliest, Commit) - assert earliest.key == 'ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7' - + assert earliest.key == "ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7" + + def test_project_latest(woc): - project = Project('woc-hack_thebridge') + project = Project("woc-hack_thebridge") latest = project.latest_commit assert isinstance(latest, Commit) - assert latest.key == 'f249b14a111279faa8d65c29ecf46bb6ce59a139' - + assert latest.key == "f249b14a111279faa8d65c29ecf46bb6ce59a139" + + def test_project_walk(woc): - project = Project('woc-hack_thebridge') + project = Project("woc-hack_thebridge") commits = list(project.commits_fp()) assert all(isinstance(c, Commit) for c in commits) assert len(commits) == 6 - + + def test_commit_compare(woc): - c1 = Commit('91f4da4c173e41ffbf0d9ecbe2f07f3a3296933c') - c2 = Commit('ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7') - + c1 = Commit("91f4da4c173e41ffbf0d9ecbe2f07f3a3296933c") + c2 = Commit("ae6e15fa4d8d4d454977ddbb4e97e922ddecebf7") + # We can't test fuzz matching because blob storage is broken :( diff = list(c1.compare(c2, threshold=1)) - modified_files = set(f[0].key for f in diff if f[0] is not None) | \ - set(f[1].key for f in diff if f[1] is not None) + modified_files = {f[0].key for f in diff if f[0] is not None} | { + f[1].key for f in diff if f[1] is not None + } assert all(len(d) == 4 for d in diff) assert all(isinstance(d[0], File) for d in diff if d[0] is not None) assert all(isinstance(d[1], File) for d in diff if d[1] is not None) assert all(isinstance(d[2], Blob) for d in diff if d[2] is not None) assert all(isinstance(d[3], Blob) for d in diff if d[3] is not None) assert modified_files == { - 'README.md', 'woc_service/requirements.txt', 'woc_service/app.py', - 'woc_service/static/.keep', 'woc_service/oscar.py' + "README.md", + "woc_service/requirements.txt", + "woc_service/app.py", + "woc_service/static/.keep", + "woc_service/oscar.py", } - - \ No newline at end of file diff --git a/tests/test_profile.json b/tests/test_profile.json index 65dc739..ac02ed9 100644 --- a/tests/test_profile.json +++ b/tests/test_profile.json @@ -369,4 +369,4 @@ ] } } - } \ No newline at end of file + } diff --git a/tests/test_tch.py b/tests/test_tch.py index 373cc56..4e0163d 100644 --- a/tests/test_tch.py +++ b/tests/test_tch.py @@ -3,6 +3,7 @@ # Import the TCHashDB class from woc.tch import TCHashDB + @pytest.fixture def db(tmp_path): """Fixture to create and return a TCHashDB instance""" @@ -10,75 +11,84 @@ def db(tmp_path): db = TCHashDB(path=str(path)) yield db + def test_put_and_get(db): - key = b'key1' - value = b'value1' + key = b"key1" + value = b"value1" db.put(key, value) assert db.get(key) == value + def test_get_nonexistent_key(db): with pytest.raises(KeyError): - db.get(b'nonexistent_key') + db.get(b"nonexistent_key") + def test_delete(db): - key = b'key2' - value = b'value2' + key = b"key2" + value = b"value2" db.put(key, value) db.delete(key) with pytest.raises(KeyError): db.get(key) + def test_drop(db): - db.put(b'key3', b'value3') - db.put(b'key4', b'value4') + db.put(b"key3", b"value3") + db.put(b"key4", b"value4") db.drop() assert len(db) == 0 + def test_len(db): - db.put(b'key5', b'value5') - db.put(b'key6', b'value6') + db.put(b"key5", b"value5") + db.put(b"key6", b"value6") assert len(db) == 2 + def test_iter(db): - keys = [b'key7', b'key8', b'key9'] + keys = [b"key7", b"key8", b"key9"] for key in keys: - db.put(key, b'value') + db.put(key, b"value") assert set(db) == set(keys) + def test_getitem(db): - key = b'key10' - value = b'value10' + key = b"key10" + value = b"value10" db[key] = value assert db[key] == value + def test_setitem(db): - key = b'key11' - value = b'value11' + key = b"key11" + value = b"value11" db[key] = value assert db.get(key) == value + def test_delitem(db): - key = b'key12' - value = b'value12' + key = b"key12" + value = b"value12" db[key] = value del db[key] with pytest.raises(KeyError): db.get(key) + def test_open(tmp_path): """Test that two TCHashDB instances can be opened concurrently""" path = tmp_path / "test_db.tch" db = TCHashDB(path=str(path), ro=False) - db[b'key'] = b'value' + db[b"key"] = b"value" # The following should yield no error db.close() db = TCHashDB(path=str(path), ro=True) - assert db[b'key'] == b'value' + assert db[b"key"] == b"value" # can't write to a read-only db with pytest.raises(OSError): - db[b'key'] = b'value' + db[b"key"] = b"value" # tch does not allow opening a db in the same process # ref: lib/tchdb.c#L370 with pytest.raises(OSError): db2 = TCHashDB(path=str(path), ro=True) - \ No newline at end of file diff --git a/woc/__init__.py b/woc/__init__.py index 7e98ab6..4308200 100644 --- a/woc/__init__.py +++ b/woc/__init__.py @@ -14,6 +14,6 @@ .. include:: ../docs/DataFormat.md # Contributing .. include:: ../docs/contributing.md -""" # noqa: D205 +""" # noqa: D205 -__all__ = ["local", "tch", "detect", "objects"] \ No newline at end of file +__all__ = ["local", "tch", "detect", "objects"] diff --git a/woc/base.py b/woc/base.py index 5c98e6e..6eb2a33 100644 --- a/woc/base.py +++ b/woc/base.py @@ -1,16 +1,18 @@ from typing import List, Literal, Tuple, Union -WocObjectsWithContent = Literal['tree', 'blob', 'commit', 'tkns', 'tag', 'bdiff'] +WocObjectsWithContent = Literal["tree", "blob", "commit", "tkns", "tag", "bdiff"] """WoC objects stored in stacked binary files.""" -WocSupportedProfileVersions = (1, ) +WocSupportedProfileVersions = (1,) """Profile versions supported by the current python-woc.""" class WocMapsBase: def __init__(self, *args, **kwargs): - raise NotImplementedError("WocMapsBase is an abstract class, use WoCMapsLocal instead") - + raise NotImplementedError( + "WocMapsBase is an abstract class, use WoCMapsLocal instead" + ) + def get_values( self, map_name: str, @@ -39,14 +41,18 @@ def show_content( self, obj_name: WocObjectsWithContent, key: Union[bytes, str], - ) -> Union[List[Tuple[str, str, str]], str, Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]]: + ) -> Union[ + List[Tuple[str, str, str]], + str, + Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str], + ]: """ Eqivalent to showCnt in WoC Perl API. :param obj_name: The name of the object, e.g. 'blob', 'tree', 'commit' :param key: The key of the object. It is the SHA-1 hash of the object (in bytes or hex string). :return: The content of the object. Can be a list of tuples of strings, a string, or a tuple of strings. - + >>> self.show_content('blob', '05fe634ca4c8386349ac519f899145c75fff4169') 'This is the content of the blob' Eqivalent to showCnt in WoC perl API @@ -60,17 +66,15 @@ def show_content( 'News for Sep 5, 2014\\n') """ raise NotImplementedError("WocMapsBase is an abstract class") - - def count( - self, map_name: str - ) -> int: + + def count(self, map_name: str) -> int: """ Count the number of keys in a map. :param map_name: The name of the mapping / object, e.g. 'c2p', 'c2r', 'commit'. :return: The number of keys in the tch databases plus the number of large files. - + >>> self.count('c2r') 12345 - """ + """ raise NotImplementedError("WocMapsBase is an abstract class") diff --git a/woc/detect.py b/woc/detect.py index 48e4f54..b0daf16 100644 --- a/woc/detect.py +++ b/woc/detect.py @@ -12,13 +12,15 @@ from functools import cmp_to_key from typing import Iterable, Optional, Tuple -_default_profile = os.path.join(os.path.dirname(__file__), 'wocprofile.default.json') +_default_profile = os.path.join(os.path.dirname(__file__), "wocprofile.default.json") _logger = logging.getLogger(__name__) _logger.setLevel(logging.INFO) MAP_REGEX = r"^(\w+)2(\w+)Full(\w+)(?:.(\d+))?.tch$" """Filename regex for basemap files""" _map_pat = re.compile(MAP_REGEX) + + def parse_map_fname(fname: str): """ Parse basemap filename into (src, dst, ver, idx). @@ -33,9 +35,12 @@ def parse_map_fname(fname: str): return None return m.groups() + LARGE_REGEX = r"^(\w+)2(\w+)Full(\w+)(?:.(\d+))?.tch.large.([0-9a-f]+)$" """Filename regex for large basemap files""" _large_pat = re.compile(LARGE_REGEX) + + def parse_large_fname(fname: str): """ Parse basemap filename into (src, dst, ver, idx, hash). @@ -48,9 +53,12 @@ def parse_large_fname(fname: str): return None return m.groups() + OBJ_REGEX = r"^([\w\.]+)_(\d+).(idx|bin|tch)$" """Filename regex for object files""" _obj_pat = re.compile(OBJ_REGEX) + + def parse_obj_fname(fname: str): """ Parse sha1map (sha1o/sha1c/blob) filename into (name, idx, ext). @@ -67,6 +75,7 @@ def parse_obj_fname(fname: str): return None return m.groups() + def compare_woc_version(ver1: str, ver2: str): """ Compare two woc version strings (A < Z < AA). @@ -80,6 +89,7 @@ def compare_woc_version(ver1: str, ver2: str): return len(ver1) - len(ver2) return ord(ver1[0]) - ord(ver2[0]) + def infer_dtype(map_name: str) -> Tuple[str, str]: """ Infer the data types from the map's name (entity -> entity). @@ -92,107 +102,113 @@ def infer_dtype(map_name: str) -> Tuple[str, str]: ('h', 'cs3') """ ent_all = map_name.lower() - ent_in, ent_out = ent_all.split('2') - - dtype_in, dtype_out = 'h', 'h' - - if ent_in in ('a', 'f', 'p'): - dtype_in = 's' - if ent_out in ('a', 'f', 'p'): - dtype_out = 'cs' - if ent_in in ('c','b','w','ob','td'): - dtype_in = 'h' - if ent_out in ('c','b','cc', 'pc','ob','td'): - dtype_out = 'h' - if ent_all == 'b2fa': - dtype_out = 'sh' - if ent_out in ('ta',): - dtype_out = 's' - if ent_all in ('b2tk', 'td2f'): - dtype_out = 's' - if ent_all in ('c2h', 'c2r'): - dtype_out = 'r' - if ent_in in ('ps', 'pf', 'pfs'): - dtype_in = 's' - if ent_out in ('ps', 'pf', 'pfs'): - dtype_out = 's' - if ent_out in ('rhp',): - dtype_out = 'hhwww' - if ent_all in ('p2p', 'a2a'): - dtype_in, dtype_out = 's', 'cs' - if ent_all in ('b2baddate', 'b2manyp'): - dtype_in, dtype_out = 's', 'h' - if ent_all in ('c2fbb', 'obb2cf', 'bb2cf'): - dtype_in, dtype_out = 'h', 'cs3' - if ent_all in ('c2dat',): - dtype_in, dtype_out = 'h', 's' - if ent_all in ('b2tac',): - dtype_in, dtype_out = 'h', 'cs3' + ent_in, ent_out = ent_all.split("2") + + dtype_in, dtype_out = "h", "h" + + if ent_in in ("a", "f", "p"): + dtype_in = "s" + if ent_out in ("a", "f", "p"): + dtype_out = "cs" + if ent_in in ("c", "b", "w", "ob", "td"): + dtype_in = "h" + if ent_out in ("c", "b", "cc", "pc", "ob", "td"): + dtype_out = "h" + if ent_all == "b2fa": + dtype_out = "sh" + if ent_out in ("ta",): + dtype_out = "s" + if ent_all in ("b2tk", "td2f"): + dtype_out = "s" + if ent_all in ("c2h", "c2r"): + dtype_out = "r" + if ent_in in ("ps", "pf", "pfs"): + dtype_in = "s" + if ent_out in ("ps", "pf", "pfs"): + dtype_out = "s" + if ent_out in ("rhp",): + dtype_out = "hhwww" + if ent_all in ("p2p", "a2a"): + dtype_in, dtype_out = "s", "cs" + if ent_all in ("b2baddate", "b2manyp"): + dtype_in, dtype_out = "s", "h" + if ent_all in ("c2fbb", "obb2cf", "bb2cf"): + dtype_in, dtype_out = "h", "cs3" + if ent_all in ("c2dat",): + dtype_in, dtype_out = "h", "s" + if ent_all in ("b2tac",): + dtype_in, dtype_out = "h", "cs3" return dtype_in, dtype_out + def detect_profile( paths: Iterable[str], version: Optional[str] = None, preset_path: Optional[str] = None, - check_missing: bool = True + check_missing: bool = True, ): _maps, _objs = {}, {} - + if not preset_path: preset_path = _default_profile def _handle_map(src, dst, ver, idx, hash): if version and ver != version: - logging.info(f'Found map {f} with version {ver}, expected {version}') + logging.info(f"Found map {f} with version {ver}, expected {version}") return - _map_name = f'{src}2{dst}' + _map_name = f"{src}2{dst}" if idx is None: idx = "0" - prefix_len = int(idx).bit_length() + prefix_len = int(idx).bit_length() - _map = (_maps - .setdefault(_map_name, {}) - .setdefault(ver, { + _map = _maps.setdefault(_map_name, {}).setdefault( + ver, + { "version": ver, "sharding_bits": prefix_len, "shards": {}, "larges": {}, "dtypes": infer_dtype(_map_name), - }) + }, ) if not hash: - logging.debug(f'Found map {f} with hash {hash} idx {idx}') + logging.debug(f"Found map {f} with hash {hash} idx {idx}") _map["shards"][int(idx)] = os.path.join(root, f) else: - logging.debug(f'Found large map {f} with hash {hash} idx {idx}') + logging.debug(f"Found large map {f} with hash {hash} idx {idx}") _map["larges"][hash] = os.path.join(root, f) _map["sharding_bits"] = max(_map["sharding_bits"], prefix_len) - def _handle_obj(name, idx, ext): _map_name = f"{name}.{ext}" prefix_len = int(idx).bit_length() if idx else 0 - _obj = (_objs - .setdefault(_map_name, { + _obj = _objs.setdefault( + _map_name, + { "sharding_bits": prefix_len, "shards": {}, - }) + }, ) - logging.debug(f'Found obj {f} idx {idx}') + logging.debug(f"Found obj {f} idx {idx}") _obj["shards"][int(idx)] = os.path.join(root, f) _obj["sharding_bits"] = max(_obj["sharding_bits"], prefix_len) - for path in paths: # walk the directory for all files for root, _, files in os.walk(path): # only consider .tch, .idx, .bin files - files = [f for f in files if '.tch' in f or (not f.startswith('pack') and f.endswith('.idx')) or f.endswith('.bin')] + files = [ + f + for f in files + if ".tch" in f + or (not f.startswith("pack") and f.endswith(".idx")) + or f.endswith(".bin") + ] for idx, f in enumerate(files): if idx % 1000 == 0: - _logger.info(f'Processing {f} in {path}, {idx+1}/{len(files)}') + _logger.info(f"Processing {f} in {path}, {idx+1}/{len(files)}") _r = parse_map_fname(f) if _r: @@ -205,84 +221,101 @@ def _handle_obj(name, idx, ext): src, dst, ver, idx, hash = _r _handle_map(src, dst, ver, idx, hash) continue - + _r = parse_obj_fname(f) if _r: name, idx, ext = _r _handle_obj(name, idx, ext) continue - _logger.warning(f'Unrecognized file: {f}') + _logger.warning(f"Unrecognized file: {f}") - # transform maps + # transform maps _ls_maps = {} for k, v in _maps.items(): _to_drop = [] for ver, vv in v.items(): # convert shards to list - _ls = [None] * 2**vv['sharding_bits'] - for kkk, vvv in vv['shards'].items(): + _ls = [None] * 2 ** vv["sharding_bits"] + for kkk, vvv in vv["shards"].items(): _ls[kkk] = vvv # see if we can find the None in _ls _nones = [i for i, x in enumerate(_ls) if x is None] if _nones and check_missing: - _logger.warning(f'Cannot find shards {", ".join(map(str, _nones))} in map {k} ver {ver}, skipping') + _logger.warning( + f'Cannot find shards {", ".join(map(str, _nones))} in map {k} ver {ver}, skipping' + ) _logger.warning(f"Got: {vv['shards']}") _to_drop.append(ver) else: - vv['shards'] = _ls + vv["shards"] = _ls for ver in _to_drop: del v[ver] # move latest maps to the front of the list if len(v) == 0: continue - _ls_maps[k] = [vv for _, vv in sorted( - v.items(), - key=cmp_to_key(lambda x, y: compare_woc_version(x[0], y[0])), - reverse=True - )] + _ls_maps[k] = [ + vv + for _, vv in sorted( + v.items(), + key=cmp_to_key(lambda x, y: compare_woc_version(x[0], y[0])), + reverse=True, + ) + ] # transform objects _ls_objs = {} for k, v in _objs.items(): # convert shards to list - _ls = [None] * 2**v['sharding_bits'] - for kk, vv in v['shards'].items(): + _ls = [None] * 2 ** v["sharding_bits"] + for kk, vv in v["shards"].items(): _ls[kk] = vv # see if we can find the None in _ls _nones = [i for i, x in enumerate(_ls) if x is None] if _nones and check_missing: - _logger.warning(f'Cannot find shards {", ".join(map(str, _nones))} in obj {k}, skipping') + _logger.warning( + f'Cannot find shards {", ".join(map(str, _nones))} in obj {k}, skipping' + ) _logger.warning(f"Got: {v['shards']}") else: - v['shards'] = _ls + v["shards"] = _ls _ls_objs[k] = v - # load the preset profile - with open(preset_path, 'r') as f: + with open(preset_path, "r") as f: res = json.load(f) res["maps"] = _ls_maps res["objects"] = _ls_objs return res -if __name__ == '__main__': + +if __name__ == "__main__": import doctest + doctest.testmod() - parser = argparse.ArgumentParser(description='Detect woc profile') - parser.add_argument('paths', metavar='PATH', type=str, nargs='+', help='path to woc directory') - parser.add_argument('--version', type=str, default=None, help='woc mapping version') - parser.add_argument('--preset', type=str, default=_default_profile, help='path to preset profile') - parser.add_argument('--output', type=str, default=None, help='path to output profile') - parser.add_argument('--no-skip-missing', dest='check_missing', action='store_false', help='do not check missing shards') + parser = argparse.ArgumentParser(description="Detect woc profile") + parser.add_argument( + "paths", metavar="PATH", type=str, nargs="+", help="path to woc directory" + ) + parser.add_argument("--version", type=str, default=None, help="woc mapping version") + parser.add_argument( + "--preset", type=str, default=_default_profile, help="path to preset profile" + ) + parser.add_argument("--output", type=str, default=None, help="path to output profile") + parser.add_argument( + "--no-skip-missing", + dest="check_missing", + action="store_false", + help="do not check missing shards", + ) args = parser.parse_args() - + res = detect_profile(args.paths, args.version, args.preset, args.check_missing) if args.output: - with open(args.output, 'w') as f: + with open(args.output, "w") as f: json.dump(res, f, indent=2) else: - print(json.dumps(res, indent=2)) \ No newline at end of file + print(json.dumps(res, indent=2)) diff --git a/woc/get_values.py b/woc/get_values.py index 2b62a11..a8d90f7 100644 --- a/woc/get_values.py +++ b/woc/get_values.py @@ -10,19 +10,22 @@ def format_map(key: str, map_objs: Iterable) -> str: - return key + ';' + ';'.join(map(str, map_objs)) + return key + ";" + ";".join(map(str, map_objs)) -if __name__ == '__main__': + +if __name__ == "__main__": import argparse import logging import os import sys - parser = argparse.ArgumentParser(description='Get record of various maps') - parser.add_argument('type', type=str, help='The type of the object') - parser.add_argument('-p', '--profile', type=str, help='The path to the profile file', default=None) + parser = argparse.ArgumentParser(description="Get record of various maps") + parser.add_argument("type", type=str, help="The type of the object") + parser.add_argument( + "-p", "--profile", type=str, help="The path to the profile file", default=None + ) args = parser.parse_args() - + woc = WocMapsLocal(args.profile) for line in sys.stdin: try: @@ -33,7 +36,7 @@ def format_map(key: str, map_objs: Iterable) -> str: # ref: https://docs.python.org/3/library/signal.html#note-on-sigpipe devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) - sys.exit(1) # Python exits with error code 1 on EPIPE + sys.exit(1) # Python exits with error code 1 on EPIPE except Exception as e: - logging.error(f'Error in {key}: {e}', exc_info=True) - continue \ No newline at end of file + logging.error(f"Error in {key}: {e}", exc_info=True) + continue diff --git a/woc/local.pyi b/woc/local.pyi index 9d73b3e..83f5a5a 100644 --- a/woc/local.pyi +++ b/woc/local.pyi @@ -3,10 +3,11 @@ from typing import Iterable, List, Tuple, Union from .base import WocMapsBase class WocMapsLocal(WocMapsBase): - def __init__(self, - profile_path: Union[str, Iterable[str], None] = None, - version: Union[str, Iterable[str], None] = None - ) -> None: + def __init__( + self, + profile_path: Union[str, Iterable[str], None] = None, + version: Union[str, Iterable[str], None] = None, + ) -> None: """ Initialize local WoC maps with a profile. @@ -16,14 +17,14 @@ class WocMapsLocal(WocMapsBase): **NOT IMPLEMENTED YET** """ ... - + def _get_tch_bytes( self, map_name: str, key: Union[bytes, str] - ) -> Tuple[bytes, str]: - ... - + ) -> Tuple[bytes, str]: ... def _get_pos( - self, obj_name: str, key: Union[bytes, str], + self, + obj_name: str, + key: Union[bytes, str], ) -> Tuple[int, int]: """ Get offset and length of a stacked binary object, currently only support blob. @@ -43,8 +44,11 @@ def decomp(data: bytes) -> bytes: ... def decomp_or_raw(data: bytes) -> bytes: ... def get_tch(path: str): ... def get_shard(key: bytes, sharding_bits: int, use_fnv_keys: bool) -> int: ... + # def get_from_tch(key: bytes, shards: List[bytes], sharding_bits: int, use_fnv_keys: bool) -> bytes: ... def decode_value(value: bytes, out_dtype: str): ... def decode_tree(value: bytes) -> List[Tuple[str, str, str]]: ... -def decode_commit(commit_bin: bytes) -> Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]: ... -def decode_str(raw_data: str, encoding='utf-8'): ... +def decode_commit( + commit_bin: bytes, +) -> Tuple[str, Tuple[str, str, str], Tuple[str, str, str], str]: ... +def decode_str(raw_data: str, encoding="utf-8"): ... diff --git a/woc/local.pyx b/woc/local.pyx index 17c1676..c57c49c 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -24,7 +24,7 @@ from .tch cimport TCHashDB cdef extern from 'Python.h': object PyBytes_FromStringAndSize(char *s, Py_ssize_t len) - + ### Utility functions ### cpdef uint32_t fnvhash(bytes data): @@ -37,7 +37,7 @@ cpdef uint32_t fnvhash(bytes data): cdef: uint32_t hval = 0x811c9dc5 uint8_t b - for b in data: + for b in data: hval ^= b hval *= 0x01000193 return hval @@ -63,19 +63,19 @@ cpdef unber(bytes buf): cdef: list res = [] # blob_offset sizes are getting close to 32-bit integer max - uint64_t acc = 0 + uint64_t acc = 0 uint8_t b for b in buf: acc = (acc << 7) + (b & 0x7f) if not b & 0x80: res.append(acc) - acc = 0 + acc = 0 return res cpdef (int, int) lzf_length(bytes raw_data): - r""" Get length of uncompressed data from a header of Compress::LZF output. - + r""" Get length of uncompressed data from a header of Compress::LZF output. + Check Compress::LZF sources for the definition of this bit magic: (namely, LZF.xs, decompress_sv) https://metacpan.org/source/MLEHMANN/Compress-LZF-3.8/LZF.xs @@ -175,7 +175,7 @@ cpdef TCHashDB get_tch(str path): # so we need a lock if path not in _TCH_POOL: # open database in read-only mode and allow concurrent access - _TCH_POOL[path] = TCHashDB(path, ro=True) + _TCH_POOL[path] = TCHashDB(path, ro=True) finally: TCH_LOCK.release() return _TCH_POOL[path] @@ -184,7 +184,7 @@ cpdef uint8_t get_shard(bytes key, uint8_t sharding_bits, bint use_fnv_keys): """ Get shard id """ cdef uint8_t p if use_fnv_keys: - p = fnvhash(key) + p = fnvhash(key) else: p = key[0] cdef uint8_t prefix = p & (2**sharding_bits - 1) @@ -215,19 +215,19 @@ def decode_value( buf0 = value[0:len(value)-21] cmt_sha = value[(len(value)-20):len(value)] (Time, Author) = decode_str(buf0).split(";") - return (Time, Author, cmt_sha.hex()) + return (Time, Author, cmt_sha.hex()) elif out_dtype == 'cs3': # type: list[tuple[str, str, str]] data = decomp(value) _splited = decode_str(data).split(";") return [ (_splited[i],_splited[i+1],_splited[i+2]) for i in range(0, len(_splited), 3) - ] + ] elif out_dtype == 'cs': # type: list[str] data = decomp(value) return [decode_str(v) for v in data.split(b';') - if v and v != b'EMPTY'] + if v and v != b'EMPTY'] elif out_dtype == 's': # type: list[str] return [decode_str(v) for v in value.split(b';')] @@ -247,7 +247,7 @@ def decode_tree( Python: 4.77 µs, Cython: 280 ns Reference: https://stackoverflow.com/questions/14790681/ - + >>> decode_tree(b'100644 .gitignore\\x00\\x8e\\x9e\\x1f...') [('100644', '.gitignore', '8e9e1...'), ...] """ @@ -268,7 +268,7 @@ def decode_tree( pos = memchr(pos, b' ', end - pos) if not pos: raise ValueError('Invalid tree object: missing space after mode') - + mode_len = pos - mode_start pos += 1 # Skip the space @@ -309,7 +309,7 @@ def decode_tree( # _out_buf = [] # _file_buf = [] # _curr_buf = bytes() - + # # TODO: current impl is not efficient, need to optimize # i = 0 # while i < len(value): @@ -370,7 +370,7 @@ def decode_commit( bint is_reading_pgp = False int header_len int line_len - + _parent_shas = [] _tree = '' _author_bytes = b'' @@ -452,7 +452,7 @@ def decode_commit( tuple(_parent_shas), (_author, _author_timestamp, _author_timezone), (_committer, _committer_timestamp, _committer_timezone), - _message, + _message, ) # def decode_commit(cmt: bytes): @@ -492,17 +492,17 @@ def decode_commit( # _is_reading_pgp = False # elif line.startswith('encoding'): # encoding = line[8:] - + # return ( # tree, # tuple(parent), # (author, author_timestamp, author_timezone), # (committer, committer_timestamp, committer_timezone), -# full_msg, +# full_msg, # ) def read_large(path: str, dtype: str) -> bytes: - """Read a *.large.* and return its content""" + """Read a *.large.* and return its content""" if dtype == 'h': with open(path, 'rb') as f: f.seek(20) # 160 bits of SHA1 @@ -519,7 +519,7 @@ def read_large(path: str, dtype: str) -> bytes: class WocMapsLocal(WocMapsBase): - def __init__(self, + def __init__(self, profile_path: Union[str, Iterable[str], None] = None, version: Union[str, Iterable[str], None] = None ) -> None: @@ -552,7 +552,7 @@ class WocMapsLocal(WocMapsBase): assert self.config["wocSchemaVersion"] in WocSupportedProfileVersions, \ "Unsupported wocprofile version: {}".format(self.config["wocSchemaVersion"]) assert self.config["maps"], "Run `python3 -m woc.detect` to scan data files and generate wocprofile.json" - + def _get_tch_bytes( self, map_name, key ) -> Tuple[bytes, str]: @@ -575,14 +575,14 @@ class WocMapsLocal(WocMapsBase): else: raise KeyError(f'Invalid map name: {map_name}, ' f'expect one of {", ".join(self.config["maps"].keys())}') - + in_dtype = _map["dtypes"][0] if "dtypes" in _map else "h" out_dtype = _map["dtypes"][1] if "dtypes" in _map else "c?" # c? means maybe compressed if self._is_debug_enabled: start_time = time.time_ns() self._logger.debug(f"get from tch: {map_name} {key}") - + if in_dtype == 'h': if isinstance(key, str): hex_str = key @@ -600,7 +600,7 @@ class WocMapsLocal(WocMapsBase): if "larges" in _map and hex_str in _map["larges"]: _bytes = read_large(_map["larges"][hex_str], out_dtype) - + if self._is_debug_enabled: self._logger.debug(f"read large: file={_map['larges'][hex_str]} " f"in {(time.time_ns() - start_time) / 1e6:.2f}ms") @@ -614,7 +614,7 @@ class WocMapsLocal(WocMapsBase): _shard = get_shard(key, _map["sharding_bits"], in_dtype != 'h') _path = _map["shards"][_shard] assert _path, f"shard {_shard} not found at {_path}" - + _tch = get_tch(_path) # TODO: remove bb2cf quirk after fixing tch keys @@ -684,7 +684,7 @@ class WocMapsLocal(WocMapsBase): # if obj_name == 'tree': # _map_obj = self.config['objects']['tree.tch'] - # v = get_from_tch(key, + # v = get_from_tch(key, # shards=_map_obj['shards'], # sharding_bits=_map_obj['sharding_bits'], # use_fnv_keys=False @@ -694,7 +694,7 @@ class WocMapsLocal(WocMapsBase): # elif obj_name == 'commit': # _map_obj = self.config['objects']['commit.tch'] - # v = get_from_tch(key, + # v = get_from_tch(key, # shards=_map_obj['shards'], # sharding_bits=_map_obj['sharding_bits'], # use_fnv_keys=False @@ -797,7 +797,7 @@ class WocMapsLocal(WocMapsBase): else: raise KeyError(f'Invalid map name: {map_name}, ' f'expect one of {", ".join(self.config["maps"].keys())}') - + _count = len(_map["larges"]) if "larges" in _map else 0 for _shard in _map["shards"]: _tch = get_tch(_shard) @@ -806,4 +806,4 @@ class WocMapsLocal(WocMapsBase): if self._is_debug_enabled: self._logger.debug(f'count: len={_count} shards={len(_map["shards"])} ' f'larges={len(_map["larges"])} in {(time.time_ns() - start_time) / 1e6:.2f}ms') - return _count \ No newline at end of file + return _count diff --git a/woc/objects.py b/woc/objects.py index 3ac7595..93e8682 100644 --- a/woc/objects.py +++ b/woc/objects.py @@ -17,7 +17,7 @@ def init_woc_objects(woc: WocMapsBase): """ Stores wocMaps object globally so you don't have to pass it around. - + :param woc: a wocMaps object. """ global _global_woc @@ -28,7 +28,7 @@ def init_woc_objects(woc: WocMapsBase): def parse_timezone_offset(offset_str: str) -> timezone: """ Parse a timezone offset string in the format '+HHMM' or '-HHMM' into a timezone object. - + >>> parse_timezone_offset('+0530') timezone(timedelta(seconds=19800)) """ @@ -689,7 +689,7 @@ def latest_commit(self) -> "Commit": def commits_fp(self) -> Generator["Commit", None, None]: """ Get a commit chain by following only the first parent. - + Mimic https://git-scm.com/docs/git-log#git-log---first-parent. Thus, you only get a small subset of the full commit tree. diff --git a/woc/show_content.py b/woc/show_content.py index 6920879..58f03d2 100644 --- a/woc/show_content.py +++ b/woc/show_content.py @@ -8,93 +8,138 @@ def format_tree(tree_objs: list) -> str: - _out = '' + _out = "" for line in tree_objs: - _out += f'{line[0]};{line[2]};{line[1]}\n' + _out += f"{line[0]};{line[2]};{line[1]}\n" return _out -def format_commit(sha: str, cmt_bin: bytes, format: int = 0): - if format == 3: # raw + +def format_commit(sha: str, cmt_bin: bytes, format: int = 0): + if format == 3: # raw cmt = decode_str(cmt_bin) return cmt - - if format == 7: # commit sha; base64(raw) + + if format == 7: # commit sha; base64(raw) import base64 + _b64 = base64.b64encode(cmt_bin).decode() # mock linux's base64, add newline every 76 characters - _b64 = '\\n'.join([_b64[i:i+76] for i in range(0, len(_b64), 76)]) + '\\n' - return sha + ';' + _b64 - + _b64 = "\\n".join([_b64[i : i + 76] for i in range(0, len(_b64), 76)]) + "\\n" + return sha + ";" + _b64 + ( tree_sha, parents, (author, author_timestamp, author_timezone), (committer, committer_timestamp, committer_timezone), - commit_msg, + commit_msg, ) = decode_commit(cmt_bin) parent_sha = parents[0] # only the first parent - - if format == 0: # commit SHA;tree SHA;parent commit SHA;author;committer;author timestamp;commit timestamp - return ';'.join([sha, tree_sha, parent_sha, author, committer, author_timestamp, committer_timestamp]) - - elif format == 1: # commit SHA;author timestamp;author - return ';'.join([sha, author_timestamp, author]) + if ( + format == 0 + ): # commit SHA;tree SHA;parent commit SHA;author;committer;author timestamp;commit timestamp + return ";".join( + [ + sha, + tree_sha, + parent_sha, + author, + committer, + author_timestamp, + committer_timestamp, + ] + ) - elif format == 2: # commit SHA;author;author timestamp; author timezone;commit message - return ';'.join([sha, author, author_timestamp, author_timezone, commit_msg]) - - elif format == 4: # commit SHA;author - return ';'.join([sha, author]) + elif format == 1: # commit SHA;author timestamp;author + return ";".join([sha, author_timestamp, author]) - elif format == 5: # commit SHA; parent commit SHA - return ';'.join([sha, parent_sha]) + elif ( + format == 2 + ): # commit SHA;author;author timestamp; author timezone;commit message + return ";".join([sha, author, author_timestamp, author_timezone, commit_msg]) - elif format == 6: # commit SHA;author timestamp;author timezone;author;tree sha;parent sha - return ';'.join([sha, author_timestamp, author_timezone, author, tree_sha, parent_sha]) + elif format == 4: # commit SHA;author + return ";".join([sha, author]) - elif format == 8: # commit sha; author timestamp; commit timestamp; author; committer; parent sha - return ';'.join([sha, author_timestamp, committer_timestamp, author, committer, parent_sha]) + elif format == 5: # commit SHA; parent commit SHA + return ";".join([sha, parent_sha]) - elif format == 9: # commit sha; tree sha; parent sha; author; committer; author timestamp; commit timestamp; author timezone; committer timezone; commit message - return ';'.join([sha, tree_sha, parent_sha, author, committer, author_timestamp, committer_timestamp, author_timezone, committer_timezone, commit_msg]) + elif ( + format == 6 + ): # commit SHA;author timestamp;author timezone;author;tree sha;parent sha + return ";".join( + [sha, author_timestamp, author_timezone, author, tree_sha, parent_sha] + ) + + elif ( + format == 8 + ): # commit sha; author timestamp; commit timestamp; author; committer; parent sha + return ";".join( + [sha, author_timestamp, committer_timestamp, author, committer, parent_sha] + ) + + elif ( + format == 9 + ): # commit sha; tree sha; parent sha; author; committer; author timestamp; commit timestamp; author timezone; committer timezone; commit message + return ";".join( + [ + sha, + tree_sha, + parent_sha, + author, + committer, + author_timestamp, + committer_timestamp, + author_timezone, + committer_timezone, + commit_msg, + ] + ) else: - raise ValueError(f'Invalid format {format}') - + raise ValueError(f"Invalid format {format}") + -if __name__ == '__main__': +if __name__ == "__main__": import argparse import logging import os import sys - parser = argparse.ArgumentParser(description='See the Content of Git Object', usage='echo | %(prog)s type (format)') - parser.add_argument('type', type=str, help='The type of the object') - parser.add_argument('format', type=int, help='The format of the object', default=0, nargs='?') - parser.add_argument('-p', '--profile', type=str, help='The path to the profile file', default=None) + parser = argparse.ArgumentParser( + description="See the Content of Git Object", + usage="echo | %(prog)s type (format)", + ) + parser.add_argument("type", type=str, help="The type of the object") + parser.add_argument( + "format", type=int, help="The format of the object", default=0, nargs="?" + ) + parser.add_argument( + "-p", "--profile", type=str, help="The path to the profile file", default=None + ) args = parser.parse_args() woc = WocMapsLocal(args.profile) for line in sys.stdin: try: key = line.strip() - if args.type == 'commit': + if args.type == "commit": obj_bin = decomp_or_raw(woc._get_tch_bytes(args.type, key)[0]) print(format_commit(key, obj_bin, args.format)) - elif args.type == 'tree': + elif args.type == "tree": obj = woc.show_content(args.type, key) print(format_tree(obj)) - elif args.type == 'blob': + elif args.type == "blob": obj = woc.show_content(args.type, key) print(obj) else: - raise ValueError(f'Invalid object type {args.type}') + raise ValueError(f"Invalid object type {args.type}") except BrokenPipeError: # ref: https://docs.python.org/3/library/signal.html#note-on-sigpipe devnull = os.open(os.devnull, os.O_WRONLY) os.dup2(devnull, sys.stdout.fileno()) - sys.exit(1) # Python exits with error code 1 on EPIPE + sys.exit(1) # Python exits with error code 1 on EPIPE except Exception as e: - logging.error(f'Error in {key}: {e}', exc_info=True) - continue \ No newline at end of file + logging.error(f"Error in {key}: {e}", exc_info=True) + continue diff --git a/woc/tch.pxd b/woc/tch.pxd index 7178b0c..0170251 100644 --- a/woc/tch.pxd +++ b/woc/tch.pxd @@ -13,4 +13,4 @@ cdef class TCHashDB: cpdef void put(self, bytes key, bytes value) except * cpdef void delete(self, bytes key) except * cpdef void drop(self) except * - cpdef void close(self) except * \ No newline at end of file + cpdef void close(self) except * diff --git a/woc/tch.pyi b/woc/tch.pyi index 1e5d7d9..c2ea3fa 100644 --- a/woc/tch.pyi +++ b/woc/tch.pyi @@ -13,13 +13,11 @@ class TCHashDB: """ ... - def __iter__(self) -> 'Iterator[bytes]': - ... - + def __iter__(self) -> "Iterator[bytes]": ... def get(self, key: bytes) -> bytes: """ Get a record. - + :raises KeyError: if the key is not found :raises OSError: if the operation fails """ @@ -28,7 +26,7 @@ class TCHashDB: def put(self, key: bytes, value: bytes) -> None: """ Upsert a record. - + :raises OSError: if the operation fails """ ... @@ -36,7 +34,7 @@ class TCHashDB: def delete(self, key: bytes) -> None: """ Delete a record from the database. - + :raises OSError: if the operation fails """ ... @@ -44,7 +42,7 @@ class TCHashDB: def drop(self) -> None: """ Delete all records in the database. - + :raises OSError: if the operation fails """ ... @@ -52,22 +50,13 @@ class TCHashDB: def close(self) -> None: """ Close the database. - + :raises OSError: if the operation fails """ ... - def __getitem__(self, key: bytes) -> bytes: - ... - - def __setitem__(self, key: bytes, value: bytes) -> None: - ... - - def __delitem__(self, key: bytes) -> None: - ... - - def __len__(self) -> int: - ... - - def __del__(self) -> None: - ... \ No newline at end of file + def __getitem__(self, key: bytes) -> bytes: ... + def __setitem__(self, key: bytes, value: bytes) -> None: ... + def __delitem__(self, key: bytes) -> None: ... + def __len__(self) -> int: ... + def __del__(self) -> None: ... diff --git a/woc/tch.pyx b/woc/tch.pyx index df65714..bc0792a 100644 --- a/woc/tch.pyx +++ b/woc/tch.pyx @@ -17,7 +17,7 @@ cdef extern from 'tchdb.h': cdef enum: # enumeration for open modes HDBOREADER = 1 << 0, # open as a reader HDBOWRITER = 1 << 1, # open as a writer - HDBOCREAT = 1 << 2, # writer creating + HDBOCREAT = 1 << 2, # writer creating HDBOTRUNC = 1 << 3, # writer truncating HDBONOLCK = 1 << 4, # open without locking @@ -41,7 +41,7 @@ cdef class TCHashDB: def __cinit__(self, str path, bint ro=False): self.filename = path _encoded = path.encode() - cdef char* dbpath = _encoded + cdef char* dbpath = _encoded cdef int mode = 0 if not ro: # write mode: create if not exists @@ -75,20 +75,20 @@ cdef class TCHashDB: buf = tchdbiternext(self._db, &sp) if buf is NULL: break - key = PyBytes_FromStringAndSize(buf, sp) + key = PyBytes_FromStringAndSize(buf, sp) free(buf) yield key cpdef bytes get(self, bytes key): cdef: - char *k = key + char *k = key char *buf int sp int ksize=len(key) buf = tchdbget(self._db, k, ksize, &sp) if buf is NULL: raise KeyError(f'Key {key.hex()} not found in {self.filename}') - cdef bytes value = PyBytes_FromStringAndSize(buf, sp) + cdef bytes value = PyBytes_FromStringAndSize(buf, sp) free(buf) return value @@ -140,4 +140,4 @@ cdef class TCHashDB: self.close() def __dealloc__(self): - free(self._db) # it should never be null \ No newline at end of file + free(self._db) # it should never be null From 8be2466ebe96f5b2ae320f1437f986390067eb51 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 11 Jun 2024 18:59:13 +0800 Subject: [PATCH 30/38] chore: cleanup unused assets --- MANIFEST.in | 1 - Makefile | 33 - docs/_static/custom.css | 18 - docs/conf.py | 163 ---- docs/contribute.rst | 168 ---- docs/index.rst | 95 -- oscar.pxd | 8 - oscar.pyx | 1888 --------------------------------------- oscar.pyxbld | 16 - poetry.lock | 2 +- setup.py.bak | 51 -- 11 files changed, 1 insertion(+), 2442 deletions(-) delete mode 100644 MANIFEST.in delete mode 100644 Makefile delete mode 100644 docs/_static/custom.css delete mode 100644 docs/conf.py delete mode 100644 docs/contribute.rst delete mode 100644 docs/index.rst delete mode 100644 oscar.pxd delete mode 100644 oscar.pyx delete mode 100644 oscar.pyxbld delete mode 100644 setup.py.bak diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index f9bd145..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include requirements.txt diff --git a/Makefile b/Makefile deleted file mode 100644 index cc8b6a4..0000000 --- a/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -SHELL := /bin/bash - -.PHONY: build -build: - python setup.py build_ext --inplace - -# test ground for github action, requires building local image from -# https://github.com/RalfG/python-wheels-manylinux-build -.PHONY: build_manylinux -build_manylinux: - docker run --rm -e PLAT=manylinux2010_x86_64 -v `pwd`:/github/workspace/ python-wheels-manylinux-build "cp27-cp27m cp36-cp36m" "cython setuptools>=18.0" "bzip2-devel zlib-devel" - -.PHONY: test -test: - $(MAKE) build - PYTHONPATH=. python tests/unit_test.py - PYTHONPATH=. python tests/integration_test.py - -.PHONY: test_local -test_local: - bash -c "source tests/local_test.env; PYTHONPATH=. python tests/unit_test.py" - -.PHONY: clean -clean: - rm -rf oscar.egg-info dist build docs/build ~/.pyxbld/* *.c tests/*.c *.so tests/*.so - find -name "*.pyxbldc" -delete - find -name "*.pyo" -delete - find -name "*.pyc" -delete - find -name __pycache__ -delete - -.PHONY: html -html: - PYTHONPATH=. OSCAR_TEST=1 sphinx-build -M html "docs" "docs/build" diff --git a/docs/_static/custom.css b/docs/_static/custom.css deleted file mode 100644 index 94d2983..0000000 --- a/docs/_static/custom.css +++ /dev/null @@ -1,18 +0,0 @@ -/* This file intentionally left blank. */ - -div.sphinxsidebarwrapper { - position:fixed; -} - -div.document { - width: 940px; - margin: 30px auto 0 30px; -} - -.py.class { - margin: 2em 0; -} - -.py.method { - margin: 1em 0; -} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 006864b..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. - -import os -import sys -sys.path.insert(0, os.path.abspath('..')) - - -# -- Project information ----------------------------------------------------- - -project = u'oscar' -author = u'Marat (@cmu.edu)' -copyright = u'2018, ' + author - -# The full version, including alpha/beta/rc tags -release = u'1.3.3' -# The short X.Y version -version = u'.'.join(release.split(u'.', 3)[:2]) - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - # 'sphinx.ext.autosummary', - 'sphinx.ext.autodoc', - 'sphinx.ext.githubpages', - 'sphinx.ext.napoleon', - 'sphinx.ext.viewcode', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path . -exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -# htmlhelp_basename = 'oscardoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -# latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -# } - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -# latex_documents = [ -# (master_doc, 'oscar.tex', u'oscar Documentation', -# u'Marat (@cmu.edu)', 'manual'), -# ] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -# man_pages = [ -# (master_doc, 'oscar', u'oscar Documentation', -# [author], 1) -# ] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -# texinfo_documents = [ -# (master_doc, 'oscar', u'oscar Documentation', -# author, 'oscar', 'One line description of project.', -# 'Miscellaneous'), -# ] - - -# -- Extension configuration ------------------------------------------------- diff --git a/docs/contribute.rst b/docs/contribute.rst deleted file mode 100644 index 2f42175..0000000 --- a/docs/contribute.rst +++ /dev/null @@ -1,168 +0,0 @@ - -Starting version 1.3, `oscar` is compiled from Cython, a language closely -resembling Python but with optional strong typing to improve performance. -Building Cython packages requires few extra build steps, as explained below. - -In addition, automation in this project relies on few assumptions which you are -expected to follow. Below you can find their brief description and the motivation -behind. - - -How to contribute ------------------ - -All the development is done on feature branches, which are then merged to `master` -via pull requests. Every pull request triggers unit testing, every merge triggers -a release. - -To generate release notes, we use `conventional commits `_, -a convention to commit messages. In a nutshell, it means commit messages should -be prefixed with one of: - -- **fix:** in case the change fixes a problem without changing any interfaces. - Example commit message: `fix: missing clickhouse-driver dependency (closes #123)`. -- **feat:** the change implements a new feature, without affecting existing - interfaces. Example: `feat: implement author timeline`. -- other prefixes, e.g. `chore:`, `refactor:`, `docs:`, `test:`, `ci:`, etc. - - these will not be included in release notes and will not trigger a new - release without new features or fixes added, unless contain breaking changes - (see below). - -In case of breaking changes, commit message should include an exclamation mark -before the semicolon, or contain **BREAKING CHANGE** in the footer, e.g.: - - `feat!: drop support for deprectated parameters` - -`fix`, `chore`, `docs` commits will produce patch versions, `feat` will result -in a minor version bump, and in case of breaking changes the major version will -be incremented. As a consequence, **you must never change version number manually**. - -Not following these procedures might take your pull request extra time to -review and in some cases will require rewriting the commit history. - - -About Cython ------------- - -The reason to use Cython was primarily Python 3 support. WoC data is stored -in tokyocabinet (.tch) files, note natively supported by Python. -`libtokyocabinet` binding, `python-tokyocabinet`, is a C extension supporting -Python 2 only, and lack of development activity suggests updating it for Py 3 -is hardly considered. So, our options to interface `libtokyocabinet` were: - -- cffi (C Foreign Functions Interface) - perhaps, the simplest option, - but it does not support conditional definitions (`#IFDEF`), that are - actively used in tokyocabinet headers -- C extension, adapting existing `python-tokyocabinet` code for Python 3. - It is rather hard to support and even harder to debug; a single - attempt was scrapped after making a silently failing extension. -- `SWIG `_ (and its successor, `CLIF `_), - a Google project to generate C/C++ library bindings - for pretty much any language. Since this library provides 1:1 interface - to the library methods, Python clients had to be aware of the returned - C structures used by libtokyocabinet, which too inconvenient. -- Cython, a weird mix of Python and C. It allows writing Python interfaces, - while simultaneously using C functions. This makes it the ideal option - for our purposes, providing a Python `.tch` file handler working - with `libtokyocabinet` C structures under the hood. - -Cython came a clear winner in this comparison, also helping to speed up -some utility functions along the way (e.g. `fnvhash`, a pure Python version -of which was previously used). - -Compiling and packaging ------------------------ - -To compile oscar locally, run: -`python setup.py build_ext --inplace`. To explicitly specify python version, -replace `pyhon`, with the appropriate version, e.g. `python2`. -There shorter alias for this command, `make build`, will always use the default -Python. - -If you are building for several Python versions in a row without changing the -code (e.g. to check if it compiles at all), make sure you clean up first by -running `make clean`. -Compilation is cached when possible, and will be omitted if the input hasn't -changed - the compiler is not aware that the resulting `.so` file exposes -different interfaces. You will get a lot of angry messages about missing -interfaces and symbols when import with the same Python version which "compiled" -this `.so` just a second ago in this case. - -Packaging is slightly more complicated than just compiling since oscar needs to -support at least Python 2.7 and 3.6 simultaneously, meaning we need to package -multiple binaries. Fortunately, `PEP 513 `_ -offers support for such packages. Building is done via `manylinux `_, -a special Docker image, and is automated via GitHub action. - -To build package locally, - -#. clone the corresponding GitHub action repository, - `git clone git@github.com:user2589/python-wheels-manylinux-build.git`, -#. check out the desired tag if necessary, e.g. `git checkout v0.3.4` -#. build Docker image: `docker build -t python-wheels-manylinux-build .` -#. run the image: `make build_manylinux` - - -Testing -------- - -Every push to oscar repository is automatically tested; on top, you might want -to test locally before making a commit to avoid awkward followup fixes and a -bunch of angry emails from GitHub actions bot telling how you broke the build. -Unit tests are tedious to write, but will save a lot of your time in the long run. -First thing to know about unit tests, please DO write them - future you will be -grateful. Second, there are a couple things about testing Cython code against a -remote dataset. - -To run tests locally, `make test_local`. -WoC files are only available on UTK servers only, so to make local testing -possible, there is a small subset of the data in `tests/fixtures`. Changing -oscar paths to point at these fixtures requires setting some environment -variables, stored in `tests/local_test.env`. -To tests locally, - -#. set environment variables, `source tests/local_test.env` -#. clean up previously compiled binaries to avoid Py2/3 compatibility issues: `make clean` -#. run the test script: `PYTHONPATH=. python tests/unit_test.py`. - Don't forget to replace `python` with a specific version if testing - against non-default Python) - -`make test_local` is a shortcut for this, except it will always use the default -Python and thus doesn't need to clean. - -Unit tests for Cython functions (i.e., defined with `cdef`) are stored in a -separate `.pyx` file, which is imported from the regular `.py` test suite. -Cython code can only be accessed from Cython files, which cannot executed as a -Python script. Thus, we have to store them separately - see `tests/unit_test.py` -and `tests/unit_test_cy.pyx` as an example of how it is organized. - -To avoid manual compilation with `cythonize`, Cython tests are compiled with -`pyximport`, an in-place JIT compiler. Thus, at the beginning of every test suite, -install `pyximport`: - -.. code-block:: python - - import pyximport - pyximport.install( - # build_dir='build', - setup_args={"script_args": ["--force"]}, - inplace=True, - language_level='3str' - ) - -To tell `pyximport` where to find sources and libraries for the main module, -there is a special file `oscar.pyxbld`. It is important to keep it consistent -with the `Extension` parameters in `setup.py`. If you can `make build` but unit -tests fail to compile it, this is the first place to check. - -Cython functions being tested should be exposed in `oscar.pxd` - -a Cython equivalent of a header file. If tests cannot find some function that is -defined in oscar, check it is included there. Hopefully, the list of tested -functions will grow bigger with your help. - -Finally, unit and integration tests can also be run on real data. On one of UTK -servers (preferably, `da4`), clone the repository and run `make test`. If the -result is different from your local run, perhaps it's time to update fixtures -and/or tests. - - diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 0a6aead..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,95 +0,0 @@ -.. oscar documentation master file, created by - sphinx-quickstart on Mon May 28 14:28:44 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Reference -=========== - -.. toctree:: - :maxdepth: 2 - - contribute - - -This module provides interface to the objects: - -- :py:class:`.Project` - represents a repository -- :py:class:`.Commit` - represents a commit in a repository -- :py:class:`.Tree` - represents a directory and its content. Each `Commit` has a root tree. -- :py:class:`.File` - represents a file path, including all parent directories/trees -- :py:class:`.Blob` - Binary Large OBject, represents a file content. -- :py:class:`.Author` - represents a combination of author name and email. - -`Commit`, `Tree` and `Blob` are a straightforward representation of -objects used by Git internally. -It will be helpful to read `Chapter 2 `_ -of `Pro Git book `_ (free and Open Source) -for better understanding of these objects. - -Common methods --------------- -.. py:module:: oscar - -All objects have a unique key. -For git objects (`Commit`, `Tree`, `Blob`) -it is the object SHA hash; -for `Project` it is the project URI; -for `File` it is the filename; -for `Author` it is the author name and email. -Objects of the same type and having the same key will be considered equivalent: - - >>> sha = 'f2a7fcdc51450ab03cb364415f14e634fa69b62c' - >>> Commit(sha) == Commit(sha) - True - -It is possible to iterate all objects of a given type using `.all()` - -.. automethod:: _Base.all - - E.g. to iterate all repositories of user2589 on github: - - >>> for project in Project.all(): - ... print project.uri - -GitObject methods ------------------ - -These methods are shared by `Commit`, `Tree`, `Blob`. - -All git objects are instantiated by a 40-byte hex string SHA or a 20-byte binary SHA. -In most cases you will use hex form, the latter way is needed only fore relatively -rare cases you need to interface with binary data. - - >>> Commit('f2a7fcdc51450ab03cb364415f14e634fa69b62c') - >>> Commit(b'\xf2\xa7\xfc\xdcQE\n\xb0<\xb3dA_\x14\xe64\xfai\xb6,') - -Whatever form of SHA was used to instantiate the object, it will have properties: - -- `sha` - 40-byte hex string -- `bin_sha` - 20 bytes binary string - -All git objects, when coerced to `str`, will return their internal representation. -It is mostly important for `Blob` to access the file content. - - -Class reference ---------------- - -.. autoclass:: Project - :members: commit_shas, commits, head, tail, commits_fp - -.. autoclass:: Commit - :members: parents, project_names, projects, child_shas, children, blob_shas, blobs - -.. autoclass:: Tree - :members: traverse, files, blob_shas, blobs - -.. autoclass:: File - :members: commit_shas, commits - -.. autoclass:: Blob - :members: data, commit_shas, commits - -.. autoclass:: Author - :members: commit_shas, commits diff --git a/oscar.pxd b/oscar.pxd deleted file mode 100644 index 5d3449d..0000000 --- a/oscar.pxd +++ /dev/null @@ -1,8 +0,0 @@ - -# cython: language_level=3str -from libc.stdint cimport uint32_t - -# we need this header file for unit tests. -cdef unber(bytes buf) -cdef (int, int) lzf_length(bytes raw_data) -cdef uint32_t fnvhash(bytes data) diff --git a/oscar.pyx b/oscar.pyx deleted file mode 100644 index 30bbf2e..0000000 --- a/oscar.pyx +++ /dev/null @@ -1,1888 +0,0 @@ - -# cython: language_level=3str, wraparound=False, boundscheck=False, nonecheck=False - -import binascii -from datetime import datetime, timedelta, tzinfo, timezone -import difflib -from functools import wraps -import hashlib -import os -import re -from threading import Lock -import time -from typing import Dict, Tuple, Optional, Union -import warnings -import mmap - -from libc.stdint cimport uint8_t, uint32_t, uint64_t -from libc.stdlib cimport free - -# if throws "module 'lzf' has no attribute 'decompress'", -# `pip uninstall lzf && pip install python-lzf` -import lzf -if not hasattr(lzf, 'decompress'): - raise ImportError('python-lzf is required to run Oscar; ' - 'please install it with `pip uninstall lzf && pip install python-lzf`') - -__version__ = '2.2.1' -__author__ = 'marat@cmu.edu' -__license__ = 'GPL v3' - -_basemap_pat = re.compile(r'^(\w+)2(\w+)Full(\w+)(?:.(\d+))?.tch$') -def parse_basemap_path(fname: str): - """ - Parse basemap filename into (src, dst, ver, idx) - >>> parse_basemap_path('c2fFullR.3.tch') - ('c', 'f', 'R', '3') - >>> parse_basemap_path('c2fFullR.tch') - ('c', 'f', 'R', None) - """ - m = _basemap_pat.match(fname) - if not m or len(m.groups()) != 4: - raise ValueError(f'Invalid path: {fname}') - return m.groups() - -_sha1map_pat = re.compile(r'^([\w\.]+)_(\d+).(\w+)$') -def parse_sha1map_path(fname: str): - """ - Parse sha1map (sha1o/sha1c/blob) filename into (name, idx, ext) - >>> parse_sha1map_path('commit_0.tch') - ('commit', '0', 'tch') - >>> parse_sha1map_path('blob_0.idx') - ('blob', '0', 'idx') - >>> parse_sha1map_path('sha1.blob_0.bin') - ('sha1.blob', '0', 'bin') - """ - m = _sha1map_pat.match(fname) - if not m or len(m.groups()) != 3: - raise ValueError(f'Invalid path: {fname}') - return m.groups() - -# identities and their shortcut -_short_name_to_full = { - 'a': 'author', - 'A': 'author_dealised', - 'b': 'blob', - 'c': 'commit', - 'cc': 'child_commit', - 'f': 'file', - 'fa': 'first_author', - 't': 'tree', - 'h': 'head', - 'p': 'project', - 'P': 'project_deforked', - 'pc': 'parent_commit', - 'r': 'root_commit', - 'ta': 'time_author', - 'tac': 'time_author_commit', - 'trp': 'torvalds_path', - 'dat': 'colon_seperated_data', - 'tch': 'compressed_data', - 'bin': 'binary_data', - 'idx': 'binary_index' -} -_full_name_to_short = {v: k for k, v in _short_name_to_full.items()} - -##### module configuration variables ##### - -# default config values -DEFAULT_BASE_PATH = '/woc' -DEFAULT_STORES = { - 'OSCAR_ALL_BLOBS': 'All.blobs', - 'OSCAR_ALL_SHA1C': 'All.sha1c', - 'OSCAR_ALL_SHA1O': 'All.sha1o', - 'OSCAR_BASEMAPS': 'basemaps', -} - -# tokyo cabinet store paths -PATHS: Dict[Tuple[str, str], Tuple[str, int, Optional[str]]] = {} - -# prefixes used by World of Code to identify source project platforms -# See Project.to_url() for more details -# Prefixes have been deprecated by replacing them with the string resembling -# actual URL -URL_PREFIXES = { - b'bitbucket.org': b'bitbucket.org', - b'gitlab.com': b'gitlab.com', - b'android.googlesource.com': b'android.googlesource.com', - b'bioconductor.org': b'bioconductor.org', - b'drupal.com': b'git.drupal.org', - b'git.eclipse.org': b'git.eclipse.org', - b'git.kernel.org': b'git.kernel.org', - b'git.postgresql.org': b'git.postgresql.org', - b'git.savannah.gnu.org': b'git.savannah.gnu.org', - b'git.zx2c4.com': b'git.zx2c4.com', - b'gitlab.gnome.org': b'gitlab.gnome.org', - b'kde.org': b'anongit.kde.org', - b'repo.or.cz': b'repo.or.cz', - b'salsa.debian.org': b'salsa.debian.org', - b'sourceforge.net': b'git.code.sf.net/p' -} -IGNORED_AUTHORS = ( - b'GitHub Merge Button ' -) - -def set_config( - base_path: str = DEFAULT_BASE_PATH, - stores: Optional[Dict[str, str]] = None, - url_prefixes: Optional[Dict[bytes, bytes]] = None, - ignored_authors: Optional[Tuple[bytes]] = None - ): - """Set the configuration for the Oscar module. - :param base_path: path to the woc directory - :param stores: a dictionary of store names (OSCAR_ALL_BLOBS, OSCAR_ALL_SHA1C, OSCAR_ALL_SHA1O, OSCAR_BASEMAPS) - to their relative paths in the woc directory - :param url_prefixes: a BYTES dictionary of url prefixes to their full urls (e.g. b'bitbucket.org' -> b'bitbucket.org') - :param ignored_authors: a BYTES tuple of authors to ignore (e.g. b'GitHub Merge Button ' - """ - - global PATHS, IGNORED_AUTHORS, URL_PREFIXES - - # add support for environment variables - if os.environ.get('OSCAR_BASE_PATH'): - base_path = os.environ['OSCAR_BASE_PATH'] - - for store_name in DEFAULT_STORES.keys(): - if os.environ.get(store_name): - if stores is None: - stores = {} - stores[store_name] = os.environ[store_name] - - if stores is None: - if not os.path.exists(base_path): - raise FileNotFoundError(base_path) - stores = {k: os.path.join(base_path, v) for k, v in DEFAULT_STORES.items()} - - # Scan the woc data directory - for store_name, store_path in stores.items(): - if not os.path.exists(store_path): - raise FileNotFoundError(f'{store_name}: {store_path}') - - for f in os.listdir(store_path): - try: - if store_name == 'OSCAR_BASEMAPS': - src, dst, ver, idx = parse_basemap_path(f) - k = (src, dst) - prefix_len = int(idx).bit_length() if idx else 0 - if k in PATHS: - _, _predix_len, _ver = PATHS[k][0], PATHS[k][1], PATHS[k][2] - assert _ver is not None, "Should not be here; check store type" - if _ver > ver or (_ver == ver and _predix_len >= prefix_len): - continue - PATHS[k] = ( - os.path.join(store_path, - f.replace(idx, '{key}') if idx else f - ), prefix_len, ver) - pass - elif store_name in ('OSCAR_ALL_BLOBS', 'OSCAR_ALL_SHA1C', 'OSCAR_ALL_SHA1O'): - name, idx, ext = parse_sha1map_path(f) - try: - src = _full_name_to_short[name.replace('sha1.','')] - except KeyError: - raise ValueError(f'Invalid file type: {name}') - k = (src, ext) - prefix_len = int(idx).bit_length() if idx else 0 - if k in PATHS: - _, _predix_len = PATHS[k][0], PATHS[k][1] - if _predix_len >= prefix_len: - continue - PATHS[k] = ( - os.path.join(store_path, - f.replace(idx, '{key}') if idx else f - ), prefix_len, None) - else: - raise ValueError(f'Invalid store name: {store_name}, expected one of {DEFAULT_STORES.keys()}') - - except ValueError as e: - warnings.warn(f'Cannot parse {f}: {repr(e)} ') - - print(f'Loaded {len(PATHS.keys())} maps: ' + \ - str([_short_name_to_full[x[0]] + "->" + _short_name_to_full[x[1]] + \ - ":" + PATHS[x][0].format(key=2**PATHS[x][1]-1) for x in PATHS.keys()]) - ) - - if url_prefixes is not None: - URL_PREFIXES = url_prefixes - - if ignored_authors is not None: - IGNORED_AUTHORS = ignored_authors - -# run set_config on import -try: - set_config() -except FileNotFoundError as e: - warnings.warn("Oscar failed to locate /woc. Call oscar.set_config('/path/to/woc') first.") - -### polyfill for @cached_property ### - -def cached_property(func): - """ Classic memoize with @property on top""" - @wraps(func) - def wrapper(self): - key = '_' + func.__name__ - if not hasattr(self, key): - setattr(self, key, func(self)) - return getattr(self, key) - return property(wrapper) - -class ObjectNotFound(KeyError): - pass - - -cdef unber(bytes buf): - r""" Perl BER unpacking. - BER is a way to pack several variable-length ints into one - binary string. Here we do the reverse. - Format definition: from http://perldoc.perl.org/functions/pack.html - (see "w" template description) - - Args: - buf (bytes): a binary string with packed values - - Returns: - str: a list of unpacked values - - >>> unber(b'\x00\x83M') - [0, 461] - >>> unber(b'\x83M\x96\x14') - [461, 2836] - >>> unber(b'\x99a\x89\x12') - [3297, 1170] - """ - # PY: 262ns, Cy: 78ns - cdef: - list res = [] - # blob_offset sizes are getting close to 32-bit integer max - uint64_t acc = 0 - uint8_t b - - for b in buf: - acc = (acc << 7) + (b & 0x7f) - if not b & 0x80: - res.append(acc) - acc = 0 - return res - - -cdef (int, int) lzf_length(bytes raw_data): - r""" Get length of uncompressed data from a header of Compress::LZF - output. Check Compress::LZF sources for the definition of this bit magic - (namely, LZF.xs, decompress_sv) - https://metacpan.org/source/MLEHMANN/Compress-LZF-3.8/LZF.xs - - Args: - raw_data (bytes): data compressed with Perl Compress::LZF - - Returns: - Tuple[int, int]: (header_size, uncompressed_content_length) in bytes - - >>> lzf_length(b'\xc4\x9b') - (2, 283) - >>> lzf_length(b'\xc3\xa4') - (2, 228) - >>> lzf_length(b'\xc3\x8a') - (2, 202) - >>> lzf_length(b'\xca\x87') - (2, 647) - >>> lzf_length(b'\xe1\xaf\xa9') - (3, 7145) - >>> lzf_length(b'\xe0\xa7\x9c') - (3, 2524) - """ - # PY:725us, Cy:194usec - cdef: - # compressed size, header length, uncompressed size - uint32_t csize=len(raw_data), start=1, usize - # first byte, mask, buffer iterator placeholder - uint8_t lower=raw_data[0], mask=0x80, b - - while mask and csize > start and (lower & mask): - mask >>= 1 + (mask == 0x80) - start += 1 - if not mask or csize < start: - raise ValueError('LZF compressed data header is corrupted') - usize = lower & (mask - 1) - for b in raw_data[1:start]: - usize = (usize << 6) + (b & 0x3f) - if not usize: - raise ValueError('LZF compressed data header is corrupted') - return start, usize - - -def decomp(bytes raw_data): - # type: (bytes) -> bytes - """ lzf wrapper to handle perl tweaks in Compress::LZF - This function extracts uncompressed size header - and then does usual lzf decompression. - - Args: - raw_data (bytes): data compressed with Perl Compress::LZF - - Returns: - str: unpacked data - """ - if not raw_data: - return b'' - if raw_data[0] == 0: - return raw_data[1:] - start, usize = lzf_length(raw_data) - # while it is tempting to include liblzf and link statically, there is - # zero advantage comparing to just using python-lzf - return lzf.decompress(raw_data[start:], usize) - - -cdef uint32_t fnvhash(bytes data): - """ - Returns the 32 bit FNV-1a hash value for the given data. - >>> hex(fnvhash('foo')) - '0xa9f37ed7' - """ - # PY: 5.8usec Cy: 66.8ns - cdef: - uint32_t hval = 0x811c9dc5 - uint8_t b - for b in data: - hval ^= b - hval *= 0x01000193 - return hval - - -def slice20(bytes raw_data): - """ Slice raw_data into 20-byte chunks and hex encode each of them - It returns tuple in order to be cacheable - """ - if raw_data is None: - return () - return tuple(raw_data[i:i + 20] for i in range(0, len(raw_data), 20)) - - -class CommitTimezone(tzinfo): - # TODO: replace with datetime.timezone once Py2 support is ended - # a lightweight version of pytz._FixedOffset - def __init__(self, hours, minutes): - self.offset = timedelta(hours=hours, minutes=minutes) - - def utcoffset(self, dt): - return self.offset - - def tzname(self, dt): - return 'fixed' - - def dst(self, dt): - # daylight saving time - no info - return timedelta(0) - - def __repr__(self): - h, m = divmod(self.offset.seconds // 60, 60) - return "" % (h, m) - - -DAY_Z = datetime.fromtimestamp(0, CommitTimezone(0, 0)) - - -def parse_commit_date(bytes timestamp, bytes tz): - """ Parse date string of authored_at/commited_at - - git log time is in the original timezone - gitpython - same as git log (also, it has the correct timezone) - unix timestamps (used internally by commit objects) are in UTC - datetime.fromtimestamp without a timezone will convert it to host tz - github api is in UTC (this is what trailing 'Z' means) - - Args: - timestamp (str): Commit.authored_at or Commit.commited_at, - e.g. '1337145807 +1100' - tz (str): timezone - Returns: - Optional[datetime.datetime]: UTC datetime - - >>> parse_commit_date(b'1337145807', b'+1130') - datetime.datetime(2012, 5, 16, 16, 23, 27, tzinfo=) - >>> parse_commit_date(b'3337145807', b'+1100') is None - True - """ - cdef: - int sign = -1 if tz.startswith(b'-') else 1 - uint32_t ts - int hours, minutes - uint8_t tz_len = len(tz) - try: - ts = int(timestamp) - hours = sign * int(tz[tz_len-4:tz_len-2]) - minutes = sign * int(tz[tz_len-2:]) - dt = datetime.fromtimestamp(ts, CommitTimezone(hours, minutes)) - except (ValueError, OverflowError): - # i.e. if timestamp or timezone is invalid - return None - - # timestamp is in the future - if ts > time.time(): - return None - - return dt - -cdef extern from 'Python.h': - object PyBytes_FromStringAndSize(char *s, Py_ssize_t len) - - -cdef extern from 'tchdb.h': - ctypedef struct TCHDB: # type of structure for a hash database - pass - - cdef enum: # enumeration for open modes - HDBOREADER = 1 << 0, # open as a reader - HDBONOLCK = 1 << 4, # open without locking - - const char *tchdberrmsg(int ecode) - TCHDB *tchdbnew() - int tchdbecode(TCHDB *hdb) - bint tchdbopen(TCHDB *hdb, const char *path, int omode) - bint tchdbclose(TCHDB *hdb) - void *tchdbget(TCHDB *hdb, const void *kbuf, int ksiz, int *sp) - bint tchdbiterinit(TCHDB *hdb) - void *tchdbiternext(TCHDB *hdb, int *sp) - - -cdef class Hash: - """Object representing a Tokyocabinet Hash table""" - cdef TCHDB* _db - cdef bytes filename - - def __cinit__(self, char *path, nolock=True): - cdef int mode = HDBOREADER - if nolock: - mode |= HDBONOLCK - self._db = tchdbnew() - self.filename = path - if self._db is NULL: - raise MemoryError() - cdef bint result = tchdbopen(self._db, path, mode) - if not result: - raise IOError('Failed to open .tch file "%s": ' % self.filename - + self._error()) - - def _error(self): - cdef int code = tchdbecode(self._db) - cdef bytes msg = tchdberrmsg(code) - return msg.decode('ascii') - - def __iter__(self): - cdef: - bint result = tchdbiterinit(self._db) - char *buf - int sp - bytes key - if not result: - raise IOError('Failed to iterate .tch file "%s": ' % self.filename - + self._error()) - while True: - buf = tchdbiternext(self._db, &sp) - if buf is NULL: - break - key = PyBytes_FromStringAndSize(buf, sp) - free(buf) - yield key - - cdef bytes read(self, bytes key): - cdef: - char *k = key - char *buf - int sp - int ksize=len(key) - buf = tchdbget(self._db, k, ksize, &sp) - if buf is NULL: - raise ObjectNotFound(key) - cdef bytes value = PyBytes_FromStringAndSize(buf, sp) - free(buf) - return value - - def __getitem__(self, bytes key): - return self.read(key) - - def __del__(self): - cdef bint result = tchdbclose(self._db) - if not result: - raise IOError('Failed to close .tch "%s": ' % self.filename - + self._error()) - - def __dealloc__(self): - free(self._db) - - -# Pool of open TokyoCabinet databases to save few milliseconds on opening -cdef dict _TCH_POOL = {} # type: Dict[str, Hash] -TCH_LOCK = Lock() - -def _get_tch(char *path): - """ Cache Hash() objects """ - if path in _TCH_POOL: - return _TCH_POOL[path] - try: - TCH_LOCK.acquire() - # in multithreading environment this can cause race condition, - # so we need a lock - if path not in _TCH_POOL: - _TCH_POOL[path] = Hash(path) - finally: - TCH_LOCK.release() - return _TCH_POOL[path] - -def _get_value( - key: bytes, - dtype: Tuple[str, str], - use_fnv_keys = False -) -> bytes: - """Read value (in BYTES) from tch""" - try: - path_tmpl, prefix_length = PATHS[dtype][0], PATHS[dtype][1] - except KeyError as e: - raise KeyError(f'Invalid dtype: {dtype}, expected one of {PATHS.keys()}') from e - - cdef uint8_t p - if use_fnv_keys: - p = fnvhash(key) - else: - p = key[0] - cdef uint8_t prefix = p & (2**prefix_length - 1) - - path_b = path_tmpl.format(key=prefix).encode('ascii') - - return _get_tch(path_b)[key] - -GIT_DTYPES = ('c', 'cc', 'pc', 'r', 'b', 'h', 't') - -def _decode_value( - value: bytes, - out_dtype: str -): - if out_dtype in GIT_DTYPES: - return tuple( - value[i:i + 20].hex() for i in range(0, len(value), 20)) # type: Tuple[str, ...] - elif out_dtype == 'fa': - buf0 = value[0:len(value)-21] - cmt_sha = value[(len(value)-20):len(value)] - (Time, Author) = buf0.decode('utf-8').split(";") - return (Time, Author, cmt_sha.hex()) # type: Tuple[str, str, str] - elif out_dtype == 'tac': - data = decomp(value) - _splited = data.decode('utf-8').split(";") - return tuple( - (_splited[i],_splited[i+1],_splited[i+2]) - for i in range(0, len(_splited), 3) - ) # type: Tuple[Tuple[str, str, str], ...] - elif out_dtype == 'ta': - (Time, Author) = value.decode('utf-8').split(";") - return (Time, Author) # type: Tuple[str, str] - elif out_dtype in ('p', 'P'): - data = decomp(value) - return tuple(project_name.decode('utf-8') - for project_name in data.split(b';') - if project_name and project_name != b'EMPTY') # type: Tuple[str, ...] - elif out_dtype == 'f': - data = decomp(value) - return tuple(file_name.decode('utf-8') - for file_name in (data.split(b";") if data else []) - if file_name and file_name != b'EMPTY') # type: Tuple[str, ...] - elif out_dtype == 'dat': - return tuple(value.decode('utf-8').split(';')) # type: Tuple[str, ...] - elif out_dtype in ('a', 'A'): - data = decomp(value) - return tuple(author.decode('utf-8') for author in (data.split(b';') if data else []) - if author not in IGNORED_AUTHORS) # type: Tuple[str, ...] - raise ValueError(f'Unsupported dtype: {out_dtype}') - -def get_values( - dtype: Union[Tuple[str, str], str], - key: Union[bytes, str], -): - """Eqivalent to getValues in WoC Perl API - >>> get_values('P2c', 'user2589_minicms') # doctest: +SKIP - ... - >>> get_values(('P','c'),'user2589_minicms'): # doctest: +SKIP - ... - """ - # transform dtype -> (src, dst) - if isinstance(dtype, str): - try: - dtype = tuple(dtype.split('2')) - except ValueError as e: - raise ValueError(f'Invalid dtype: {dtype}, expected one of' - f'{list(lambda x: x[0] + "2" + x[1] for x in PATHS.keys())}') from e - - # use fnv hash as shading idx if key is not a git object - _use_fnv_keys = False if dtype[0] in GIT_DTYPES else True - if isinstance(key, str): - # unhexlify if key is a hex string - key = bytes.fromhex(key) \ - if len(key) == 40 and dtype[0] in GIT_DTYPES \ - else key.encode('utf-8') - - _out_raw = _get_value(key, dtype, use_fnv_keys=_use_fnv_keys) - return _decode_value(_out_raw, dtype[1]) - -def _decode_tree( - value: bytes -) -> Tuple[Tuple[str, str, str], ...]: - # Format description: https://stackoverflow.com/questions/14790681/ - # mode (ASCII encoded decimal) - # SPACE (\0x20) - # filename - # NULL (\x00) - # 20-byte binary hash - _out_buf = [] - _file_buf = [] - _curr_buf = bytes() - - # inefficient, but works - i = 0 - while i < len(value): - if value[i] == 0x20: - _file_buf.append(_curr_buf.decode('utf-8')) - _curr_buf = bytes() - elif value[i] == 0x00: - _file_buf.append(_curr_buf.decode('utf-8')) - # take next 20 bytes as a hash - _curr_buf = value[i+1:i+21] - _file_buf.append(_curr_buf.hex()) - _out_buf.append(tuple(_file_buf)) - # clear buffers - _file_buf = [] - _curr_buf = bytes() - i += 20 - else: - _curr_buf += bytes([value[i]]) - i += 1 - - return tuple(_out_buf) - -def _decode_content( - value: bytes, - dtype: Tuple[str, str] -): - if dtype == ('c', 'tch'): - return decomp(value).decode('utf-8') - elif dtype == ('t', 'tch'): - return _decode_tree(decomp(value)) - raise ValueError(f'Unsupported dtype: {dtype}') - -_file_obj_pool = {} -def read_file_with_offset(file_path, offset, length): - _f = _file_obj_pool.setdefault(file_path, open(file_path, "rb")) - with mmap.mmap(_f.fileno(), length=0, access=mmap.ACCESS_READ) as _m: - _m.seek(offset) - return _m.read(length) - -def _get_predix( - key: bytes, - dtype: Tuple[str, str], - use_fnv_keys = False -): - """Calculate prefix (in BYTES) from tch""" - try: - path_tmpl, prefix_length = PATHS[dtype][0], PATHS[dtype][1] - except KeyError as e: - raise KeyError(f'Invalid dtype: {dtype}, expected one of {PATHS.keys()}') from e - - cdef uint8_t p - if use_fnv_keys: - p = fnvhash(key) - else: - p = key[0] - prefix = p & (2**prefix_length - 1) - return prefix - -def show_content( - in_dtype: str, - key: Union[bytes, str], -): - """Eqivalent to showCnt in WoC perl API - >>> show_content('tree', '7a374e58c5b9dec5f7508391246c48b73c40d200') # doctest: +SKIP - ... - """ - dtype = (_full_name_to_short[in_dtype], 'tch') - if isinstance(key, str): - key = bytes.fromhex(key) - _out_raw = _get_value(key, dtype, use_fnv_keys=False) - if in_dtype in ('commit', 'tree'): - return _decode_content(_out_raw, dtype) - elif in_dtype == 'blob': - offset, length = unber(_out_raw) - _prefix = _get_predix(key, ('b', 'bin'), use_fnv_keys=False) - _path = PATHS[('b', 'bin')][0].format(key=_prefix) - _out_bin = read_file_with_offset(_path, offset, length) - return decomp(_out_bin).decode('utf-8') - else: - raise ValueError(f'Unsupported dtype: {in_dtype}, expected one of ("commit", "blob", "tree")') - -class _Base(object): - type = 'oscar_base' # type: str - key = b'!Err!' # type: bytes - # fnv keys are used for non-git objects, such as files, projects and authors - use_fnv_keys = True # type: bool - _keys_registry_dtype = ('Err', 'Err') # type: Tuple[str, str] - - def __init__(self, key): - self.key = key - - def __repr__(self): - return '<%s: %s>' % (self.type.capitalize(), self) - - def __hash__(self): - return hash(self.key) - - def __eq__(self, other): - return isinstance(other, type(self)) \ - and self.type == other.type \ - and self.key == other.key - - def __ne__(self, other): - return not self == other - - def __str__(self): - return (binascii.hexlify(self.key).decode('ascii') - if isinstance(self.key, bytes) else self.key) - - def resolve_path(self, dtype: Tuple[str, str]): - """ Get path to a file using data type and object key (for sharding) - """ - path, prefix_length = PATHS[dtype][0], PATHS[dtype][1] - - cdef uint8_t p - if self.use_fnv_keys: - p = fnvhash(self.key) - else: - p = self.key[0] - cdef uint8_t prefix = p & (2**prefix_length - 1) - return path.format(key=prefix) - - def read_tch(self, dtype: Tuple[str, str]): - return _get_value( - self.key, - dtype, - use_fnv_keys=self.use_fnv_keys - ) - - @classmethod - def all_keys(cls): - """ Iterate keys of all objects of the given type - This might be useful to get a list of all projects, or a list of - all file names. - - Yields: - bytes: objects key - """ - if not cls._keys_registry_dtype: - raise NotImplemented - - base_path, prefix_length = PATHS[cls._keys_registry_dtype][:2] - for file_prefix in range(2 ** prefix_length): - for key in _get_tch( - base_path.format(key=file_prefix).encode('ascii')): - yield key - - @classmethod - def all(cls): - for key in cls.all_keys(): - yield cls(key) - - -class GitObject(_Base): - use_fnv_keys = False - - @classmethod - def all(cls): - """ Iterate ALL objects of this type (all projects, all times) """ - base_idx_path, prefix_length = PATHS[cls.type,'idx'][:2] - base_bin_path, prefix_length = PATHS[cls.type,'bin'][:2] - for key in range(2**prefix_length): - idx_path = base_idx_path.format(key=key) - bin_path = base_bin_path.format(key=key) - datafile = open(bin_path, "rb") - for line in open(idx_path): - chunks = line.strip().split(";") - offset, comp_length, sha = chunks[1:4] - if len(chunks) > 4: # cls.type == "blob": - # usually, it's true for blobs; - # however, some blobs follow common pattern - sha = chunks[4] - - obj = cls(sha) - # obj.data = decomp(datafile.read(int(comp_length))) - - yield obj - datafile.close() - - def __init__(self, sha): - if isinstance(sha, str) and len(sha) == 40: - self.sha = sha - self.bin_sha = binascii.unhexlify(sha) - elif isinstance(sha, bytes) and len(sha) == 20: - self.bin_sha = sha - self.sha = binascii.hexlify(sha).decode('ascii') - else: - raise ValueError('Invalid SHA1 hash: %s' % sha) - super(GitObject, self).__init__(self.bin_sha) - - @cached_property - def data(self): - # type: () -> bytes - if self.type not in ('commit', 'tree'): - raise NotImplementedError - # default implementation will only work for commits and trees - return decomp(self.read_tch((_full_name_to_short[self.type], 'tch'))) - - @classmethod - def string_sha(cls, data): - # type: (bytes) -> str - """Manually compute blob sha from its content passed as `data`. - The main use case for this method is to identify source of a file. - - Blob SHA is computed from a string: - "blob " - - # https://gist.github.com/masak/2415865 - Commit SHAs are computed in a similar way - "commit " - - note that commit content includes committed/authored date - - Args: - data (bytes): content of the GitObject to get hash for - - Returns: - str: 40-byte hex SHA1 hash - """ - sha1 = hashlib.sha1() - sha1.update(b'%s %d\x00' % (cls.type.encode('ascii'), len(data))) - sha1.update(data) - return sha1.hexdigest() - - @classmethod - def file_sha(cls, path): - buffsize = 1024 ** 2 - size = os.stat(path).st_size - with open(path, 'rb') as fh: - sha1 = hashlib.sha1() - sha1.update(b'%s %d\x00' % (cls.type.encode('ascii'), size)) - while True: - data = fh.read(min(size, buffsize)) - if not data: - return sha1.hexdigest() - sha1.update(data) - - -class Blob(GitObject): - type = 'blob' - - def __len__(self): - _, length = self.position - return length - - @cached_property - def position(self): - # type: () -> (int, int) - """ Get offset and length of the blob data in the storage """ - value = self.read_tch(('b', 'tch')) - if value is None: # empty read -> value not found - raise ObjectNotFound('Blob data not found (bad sha?)') - return unber(value) - - @cached_property - def data(self): - """ Content of the blob """ - offset, length = self.position - # no caching here to stay thread-safe - with open(self.resolve_path(('b','bin')), 'rb') as fh: - fh.seek(offset) - return decomp(fh.read(length)) - - @cached_property - def commit_shas(self): - """ SHAs of Commits in which this blob have been - introduced or modified. - - **NOTE: commits removing this blob are not included** - """ - return slice20(self.read_tch(('b','c'))) - - @property - def commits(self): - """ Commits where this blob has been added or changed - - **NOTE: commits removing this blob are not included** - """ - return (Commit(bin_sha) for bin_sha in self.commit_shas) - - @cached_property - def first_author(self): - """ get time, first author and first commit for the blob - """ - buf = self.read_tch(('b','fa')) - buf0 = buf [0:len(buf)-21] - cmt_sha = buf [(len(buf)-20):len(buf)] - (Time, Author) = buf0 .decode('ascii') .split(";") - return (Time, Author, cmt_sha .hex()) - - - -class Tree(GitObject): - """ A representation of git tree object, basically - a directory. - - Trees are iterable. Each element of the iteration is a 3-tuple: - `(mode, filename, sha)` - - - `mode` is an ASCII decimal **string** similar to file mode - in Unix systems. Subtrees always have mode "40000" - - `filename` is a string filename, not including directories - - `sha` is a 40 bytes hex string representing file content Blob SHA - - .. Note:: iteration is not recursive. - For a recursive walk, use Tree.traverse() or Tree.files - - Both files and blobs can be checked for membership, - either by their id (filename or SHA) or a corresponding object: - - >>> tree = Tree("d4ddbae978c9ec2dc3b7b3497c2086ecf7be7d9d") - >>> '.gitignore' in tree - True - >>> File('.keep') in tree - False - >>> '83d22195edc1473673f1bf35307aea6edf3c37e3' in tree - True - >>> Blob('83d22195edc1473673f1bf35307aea6edf3c37e3') in tree - True - - `len(tree)` returns the number of files under the tree, including files in - subtrees but not the subtrees themselves: - - >>> len(Tree("d4ddbae978c9ec2dc3b7b3497c2086ecf7be7d9d")) - 16 - """ - - type = 'tree' - - def __iter__(self): - """ Unpack binary tree structures, yielding 3-tuples of - (mode (ASCII decimal), filename, sha (40 bytes hex)) - - Format description: https://stackoverflow.com/questions/14790681/ - mode (ASCII encoded decimal) - SPACE (\0x20) - filename - NULL (\x00) - 20-byte binary hash - >>> len(list(Tree("d4ddbae978c9ec2dc3b7b3497c2086ecf7be7d9d"))) - 6 - >>> all(len(line) == 3 - ... for line in Tree("954829887af5d9071aa92c427133ca2cdd0813cc")) - True - """ - # unfortunately, Py2 cython doesn't know how to instantiate bytes from - # memoryviews. TODO: reuse libgit2 git_tree__parse_raw - data = self.data - - i = 0 - while i < len(data): - # mode - start = i - while i < len(data) and data[i] != 32: # 32 is space - i += 1 - mode = data[start:i] - i += 1 - # file name - start = i - while i < len(data) and data[i] != 0: - i += 1 - fname = data[start:i] - # sha - start = i + 1 - i += 21 - yield mode, fname, data[start:i] - - def __len__(self): - return len(self.files) - - def __contains__(self, item): - if isinstance(item, File): - return item.key in self.files - elif isinstance(item, Blob): - return item.bin_sha in self.blob_shas - elif isinstance(item, str) and len(item) == 40: - item = binascii.unhexlify(item) - elif not isinstance(item, bytes): - return False - - return item in self.blob_shas or item in self.files - - def traverse(self): - """ Recursively traverse the tree - This will generate 3-tuples of the same format as direct tree - iteration, but will recursively include subtrees content. - - Yields: - Tuple[bytes, bytes, bytes]: (mode, filename, blob/tree sha) - - >>> c = Commit(u'1e971a073f40d74a1e72e07c682e1cba0bae159b') - >>> len(list(c.tree.traverse())) - 8 - >>> c = Commit(u'e38126dbca6572912013621d2aa9e6f7c50f36bc') - >>> len(list(c.tree.traverse())) - 36 - """ - for mode, fname, sha in self: - yield mode, fname, sha - # trees are always 40000: - # https://stackoverflow.com/questions/1071241 - if mode == b'40000': - for mode2, fname2, sha2 in Tree(sha).traverse(): - yield mode2, fname + b'/' + fname2, sha2 - - def __str__(self): - """ - >>> print(Tree('954829887af5d9071aa92c427133ca2cdd0813cc')) - 100644 __init__.py ff1f7925b77129b31938e76b5661f0a2c4500556 - 100644 admin.py d05d461b48a8a5b5a9d1ea62b3815e089f3eb79b - 100644 models.py d1d952ee766d616eae5bfbd040c684007a424364 - 40000 templates 7ff5e4c9bd3ce6ab500b754831d231022b58f689 - 40000 templatetags e5e994b0be2c9ce6af6f753275e7d8c29ccf75ce - 100644 urls.py e9cb0c23a7f6683911305efff91dcabadb938794 - 100644 utils.py 2cfbd298f18a75d1f0f51c2f6a1f2fcdf41a9559 - 100644 views.py 973a78a1fe9e69d4d3b25c92b3889f7e91142439 - """ - return b'\n'.join(b' '.join((mode, fname, binascii.hexlify(sha))) - for mode, fname, sha in self).decode('ascii') - - @cached_property - def files(self): - """ A dict of all files and their content/blob sha under this tree. - It includes recursive files (i.e. files in subdirectories). - It does NOT include subdirectories themselves. - """ - return {fname: sha for mode, fname, sha in self if mode != b'40000'} - - @property - def blob_shas(self): - """A tuple of all file content shas, including files in subdirectories - """ - return tuple(self.files.values()) - - @property - def blobs(self): - """ A generator of Blob objects with file content. - It does include files in subdirectories. - - >>> tuple(Tree('d20520ef8c1537a42628b72d481b8174c0a1de84').blobs - ... ) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - (, ..., - ) - """ - return (Blob(sha) for sha in self.blob_shas) - - -class Commit(GitObject): - """ A git commit object. - - Commits have some special properties. - Most of object properties provided by this project are lazy, i.e. they are - computed when you access them for the first time. - The following `Commit` properties will be instantiated all at once on the - first access to *any* of them. - - - :data:`tree`: root `Tree` of the commit - - :data:`parent_shas`: tuple of parent commit sha hashes - - :data:`message`: str, first line of the commit message - - :data:`full_message`: str, full commit message - - :data:`author`: str, Name - - :data:`authored_at`: str, unix_epoch+timezone - - :data:`committer`: str, Name - - :data:`committed_at`: str, unix_epoch+timezone - """ - type = 'commit' - encoding = 'utf8' - - def __getattr__(self, attr): - """ Mimic special properties: - tree: root Tree of the commit - parent_shas: tuple of parent commit sha hashes - message: str, first line of the commit message - full_message: str, full commit message - author: str, Name - authored_at: timezone-aware datetime or None (if invalid) - committer: str, Name - committed_at: timezone-aware datetime or None (if invalid) - signature: str or None, PGP signature - - - Commit: https://github.com/user2589/minicms/commit/e38126db - >>> c = Commit('e38126dbca6572912013621d2aa9e6f7c50f36bc') - >>> c.author.startswith(b'Marat') - True - >>> c.authored_at - datetime.datetime(2012, 5, 19, 1, 14, 8, tzinfo=) - >>> c.tree.sha - '6845f55f47ddfdbe4628a83fdaba35fa4ae3c894' - >>> len(c.parent_shas) - 1 - >>> c.parent_shas[0] - 'ab124ab4baa42cd9f554b7bb038e19d4e3647957' - >>> c.committed_at - datetime.datetime(2012, 5, 19, 1, 14, 8, tzinfo=) - """ - # using libgit2 commit_parse would be a bit faster, but would require - # to face internal git structures with manual memory management. - # The probability of introducing bugs and memory leaks isn't worth it - - attrs = ('tree', 'parent_shas', 'message', 'full_message', 'author', - 'committer', 'authored_at', 'committed_at', 'signature') - if attr not in attrs: - raise AttributeError( - '\'%s\'has no attribute \'%s\'' % (self.__class__.__name__, attr)) - - for a in attrs: - setattr(self, a, None) - self._parse() - return getattr(self, attr) - - # def _parse2(self): - # # TODO: port to Cython - # # Py: 22.6usec, Cy: - # cdef: - # const unsigned char[:] data = self.data - # uint32_t data_len = len(self.data) - # uint32_t start, end, sol, eol = 101 - # list parent_shas = [] - # bytes timestamp, timezone - # # fields come in this exact order: - # # tree, parent, author, committer, [gpgsig], [encoding] - # if data[0:5] != b'tree ': raise ValueError('Malformed commit') - # self.tree = Tree(binascii.unhexlify(data[5:5+40])) - # - # if data[45:45+8] != b'\nparent ': raise ValueError('Malformed commit') - # parent_shas.append(binascii.unhexlify(data[53:53+40])) - # - # if data[93:93+8] != b'\nauthor ': raise ValueError('Malformed commit') - # # eol is initialized at 101 already - # while data[eol] != b'\n': eol += 1 - # end = eol - 1 - # start = end - # while data[start] != b' ': start -= 1 - # timezone = data[start+1:end] - # end = start-1 - # start = end - # while data[start] != b' ': start -= 1 - # timestamp = data[start+1:end] - # self.authored_at = parse_commit_date(timestamp, timezone) - # self.author = bytes(data[101:start-1]) - # - # sol = eol - # eol += 1 - # if data[sol:sol+11] != b'\ncommitter ': raise ValueError('Malformed commit') - # while data[eol] != b'\n': eol += 1 - # end = eol - 1 - # start = end - # while data[start] != b' ': start -= 1 - # timezone = data[start+1:end] - # end = start-1 - # start = end - # while data[start] != b' ': start -= 1 - # timestamp = data[start+1:end] - # self.committed_at = parse_commit_date(timestamp, timezone) - # self.committer = bytes(data[101:start-1]) - # - # - # for field, field_len in ((b'tree', 5), (b'parent', 7)): - # for field, field_len in ((b'author', 7), (b'committer', 10)): - # - # - # self.header = bytes(data[0:i]) - # start = i - # self.header, self.full_message = self.data.split(b'\n\n', 1) - # self.message = self.full_message.split(b'\n', 1)[0] - # cdef list parent_shas = [] - # cdef bytes signature = None - # cdef bint reading_signature = False - # for line in self.header.split(b'\n'): - # if reading_signature: - # # examples: - # # 1cc6f4418dcc09f64dcbb0410fec76ceaa5034ab - # # cbbc685c45bdff4da5ea0984f1dd3a73486b4556 - # signature += line - # if line.strip() == b'-----END PGP SIGNATURE-----': - # self.signature = signature - # reading_signature = False - # continue - # - # if line.startswith(b' '): # mergetag object, not supported (yet?) - # # example: c1313c68c7f784efaf700fbfb771065840fc260a - # continue - # - # line = line.strip() - # if not line: # sometimes there is an empty line after gpgsig - # continue - # try: - # key, value = line.split(b' ', 1) - # except ValueError: - # raise ValueError('Unexpected header in commit ' + self.sha) - # # fields come in this exact order: - # # tree, parent, author, committer, [gpgsig], [encoding] - # if key == b'tree': - # # value is bytes holding hex values -> need to decode - # self.tree = Tree(binascii.unhexlify(value)) - # elif key == b'parent': # multiple parents possible - # parent_shas.append(binascii.unhexlify(value)) - # elif key == b'author': - # # author name can have arbitrary number of spaces while - # # timestamp is guaranteed to have one, so rsplit - # self.author, timestamp, timezone = value.rsplit(b' ', 2) - # self.authored_at = parse_commit_date(timestamp, timezone) - # elif key == b'committer': - # # same logic as author - # self.committer, timestamp, timezone = value.rsplit(b' ', 2) - # self.committed_at = parse_commit_date(timestamp, timezone) - # elif key == b'gpgsig': - # signature = value - # reading_signature = True - # elif key == b'encoding': - # self.encoding = value.decode('ascii') - # self.parent_shas = tuple(parent_shas) - - def _parse(self): - try: - self.header, self.full_message = self.data.split(b'\n\n', 1) - except ValueError: # Sometimes self.data == b'' - raise ObjectNotFound('Failed to parse output ' + str(self.data)) - self.message = self.full_message.split(b'\n', 1)[0] - cdef list parent_shas = [] - cdef bytes signature = None - cdef bint reading_signature = False - for line in self.header.split(b'\n'): - if reading_signature: - # examples: - # 1cc6f4418dcc09f64dcbb0410fec76ceaa5034ab - # cbbc685c45bdff4da5ea0984f1dd3a73486b4556 - signature += line - if line.strip() == b'-----END PGP SIGNATURE-----': - self.signature = signature - reading_signature = False - continue - - if line.startswith(b' '): # mergetag object, not supported (yet?) - # example: c1313c68c7f784efaf700fbfb771065840fc260a - continue - - line = line.strip() - if not line: # sometimes there is an empty line after gpgsig - continue - try: - key, value = line.split(b' ', 1) - except ValueError: - raise ValueError('Unexpected header in commit ' + self.sha) - # fields come in this exact order: - # tree, parent, author, committer, [gpgsig], [encoding] - if key == b'tree': - # value is bytes holding hex values -> need to decode - self.tree = Tree(binascii.unhexlify(value)) - elif key == b'parent': # multiple parents possible - parent_shas.append(binascii.unhexlify(value)) - elif key == b'author': - # author name can have arbitrary number of spaces while - # timestamp is guaranteed to have one, so rsplit - self.author, timestamp, timezone = value.rsplit(b' ', 2) - self.authored_at = parse_commit_date(timestamp, timezone) - elif key == b'committer': - # same logic as author - self.committer, timestamp, timezone = value.rsplit(b' ', 2) - self.committed_at = parse_commit_date(timestamp, timezone) - elif key == b'gpgsig': - signature = value - reading_signature = True - elif key == b'encoding': - self.encoding = value.decode('ascii') - self.parent_shas = tuple(parent_shas) - - def __sub__(self, parent, threshold=0.5): - """ Compare two Commits. - - Args: - parent (Commit): another commit to compare to. - Expected order is `diff = child_commit - parent_commit` - - Yields: - Tuple[Optional[str], Optional[str], Optional[str], Optional[str]]: - 4-tuples: `(old_path, new_path, old_sha, new_sha)` - - Examples: - - a new file 'setup.py' was created: - `(None, 'setup.py', None, 'file_sha')` - - an existing 'setup.py' was deleted: - `('setup.py', None, 'old_file_sha', None)` - - setup.py.old was renamed to setup.py, content unchanged: - `('setup.py.old', 'setup.py', 'file_sha', 'file_sha')` - - setup.py was edited: - `('setup.py', 'setup.py', 'old_file_sha', 'new_file_sha')` - - setup.py.old was edited and renamed to setup.py: - `('setup.py.old', 'setup.py', 'old_file_sha', 'new_file_sha')` - - Detecting the last one is computationally expensive. You can adjust this - behaviour by passing the `threshold` parameter, which is 0.5 by default. - It means that if roughly 50% of the file content is the same, - it is considered a match. `threshold=1` means that only exact - matches are considered, effectively disabling this comparison. - If threshold is set to 0, any pair of deleted and added file will be - considered renamed and edited; this last case doesn't make much sense so - don't set it too low. - """ - if parent.sha not in self.parent_shas: - warnings.warn("Comparing non-adjacent commits might be " - "computationally expensive. Proceed with caution.") - - # filename: (blob sha before, blob sha after) - new_files = self.tree.files - new_paths = set(new_files.keys()) - old_files = parent.tree.files - old_paths = set(old_files.keys()) - - # unchanged_paths - for fname in new_paths.intersection(old_paths): - if new_files[fname] != old_files[fname]: - # i.e. the Blob sha is the same - yield fname, fname, old_files[fname], new_files[fname] - - added_paths = new_paths - old_paths - deleted_paths = old_paths - new_paths - - if threshold >= 1: # i.e. only exact matches are considered - for fname in added_paths: - yield None, fname, None, new_files[fname] - for fname in deleted_paths: - yield fname, None, old_files[fname], None - return - - # search for matches - sm = difflib.SequenceMatcher() - added_blobs = {f: Blob(new_files[f]) for f in added_paths} - deleted_blobs = {f: Blob(old_files[f]) for f in deleted_paths} - # for each added blob, try to find a match in deleted blobs - # if there is a match, signal a rename and remove from deleted - # if there is no match, signal a new file - # unused deleted blobs are indeed deleted - for added_fname, added_blob in added_blobs.items(): - sm.set_seq1(added_blob) - matched = False - for deleted_fname, deleted_blob in deleted_blobs.items(): - sm.set_seq2(deleted_blob) - # use quick checks first (lower bound by length diff) - if sm.real_quick_ratio() > threshold \ - and sm.quick_ratio() > threshold \ - and sm.ratio() > threshold: - yield deleted_fname, added_fname, deleted_blob, added_blob - del(deleted_blobs[deleted_fname]) - matched = True - break - if not matched: # this is a new file - yield None, added_fname, None, added_blob - - for deleted_fname, deleted_blob in deleted_blobs.items(): - yield deleted_fname, None, deleted_blob, None - - @property - def parents(self): - """ A generator of parent commits. - If you only need hashes (and not `Commit` objects), - use `.parent_sha` instead - - Commit: https://github.com/user2589/minicms/commit/e38126db - >>> c = Commit('e38126dbca6572912013621d2aa9e6f7c50f36bc') - >>> tuple(c.parents) - (,) - """ - return (Commit(sha) for sha in self.parent_shas) - - @cached_property - def project_names(self): - # type: () -> tuple - """ URIs of projects including this commit. - This property can be used to find all forks of a project - by its first commit. - - Commit: https://github.com/user2589/minicms/commit/f2a7fcdc - >>> c = Commit('f2a7fcdc51450ab03cb364415f14e634fa69b62c') - >>> isinstance(c.project_names, tuple) - True - >>> len(c.project_names) > 0 - True - >>> 'user2589_minicms' in c.project_names - True - """ - data = decomp(self.read_tch(('c','p'))) - return tuple(project_name for project_name in data.split(b';') - if project_name and project_name != 'EMPTY') - - @property - def projects(self): - """ A generator of `Project` s, in which this commit is included. - """ - return (Project(uri) for uri in self.project_names) - - @cached_property - def child_shas(self): - """ Children commit binary sha hashes. - Basically, this is a reverse parent_shas - - Commit: https://github.com/user2589/minicms/commit/1e971a07 - >>> Commit('1e971a073f40d74a1e72e07c682e1cba0bae159b').child_shas - ('9bd02434b834979bb69d0b752a403228f2e385e8',) - """ - return slice20(self.read_tch(('c','cc'))) - - @property - def children(self): - """ A generator of children `Commit` objects - - Commit: https://github.com/user2589/minicms/commit/1e971a07 - >>> tuple(Commit('1e971a073f40d74a1e72e07c682e1cba0bae159b').children) - (,) - """ - return (Commit(sha) for sha in self.child_shas) - - @cached_property - def blob_shas(self): - """ SHA hashes of all blobs in the commit - - >>> Commit('af0048f4aac8f4760bf9b816e01524d7fb20a3fc').blob_shas - ... # doctest: +NORMALIZE_WHITESPACE - ('b2f49ffef1c8d7ce83a004b34035f917713e2766', - 'c92011c5ccc32a9248bd929a6e56f846ac5b8072', - 'bf3c2d2df2ef710f995b590ac3e2c851b592c871') - """ - return self.tree.blob_shas - - @cached_property - def changed_file_names(self): - data = decomp(self.read_tch(('c','f'))) - return tuple((data and data.split(b';')) or []) - - def files_changed(self): - return (File(filename) for filename in self.changed_file_names) - - @property - def blob_shas_rel(self): - """ - This relation is known to miss every first file in all trees. - Consider using Commit.tree.blobs as a slower but more accurate - alternative. - - When this relation passes the test, please replace blob_sha with it - It should be faster but as of now it is not accurate - """ - # still true as of Sep 2020 - warnings.warn( - 'This relation is known to miss every first file in all trees. ' - 'Consider using Commit.tree.blobs as a slower but more accurate ' - 'alternative', DeprecationWarning) - return slice20(self.read_tch(('c','b'))) - - @property - def blobs(self): - """ A generator of `Blob` objects included in this commit - - >>> tuple(Commit('af0048f4aac8f4760bf9b816e01524d7fb20a3fc').blobs) - ... # doctest: +NORMALIZE_WHITESPACE - (, - , - ) - """ - return (Blob(bin_sha) for bin_sha in self.blob_shas) - - @cached_property - def attributes(self): - """ pre-parsed from the commit commit binary sha hashes.uthor Time, Author time zone, author, tree, parents (colon separated) - >>> oscar.Commit("80b4ca99f8605903d8ac6bd921ebedfdfecdd660").attributes - ['1432848535', '-0400', 'Robert Lefebvre ', '8a08c812a15051605da7c594b970cad57ec07e3b', 'd24664ccf959bd6e5bacb8ad2c0ceebcdcc8551c'] - """ - return self.read_tch(('c','dat')).decode('ascii').split(";") - - @cached_property - def files(self): - data = decomp(self.read_tch(('c','f'))) - return tuple(file_name - for file_name in (data and data.split(b";")) or [] - if file_name and file_name != 'EMPTY') - - -class Tag(GitObject): - """ Tag doesn't have any functionality associated. - You can't really do anything useful with it yet - """ - type = 'tag' - - -class Project(_Base): - """ - Projects are iterable: - - >>> for commit in Project('user2589_minicms'): # doctest: +SKIP - ... print(commit.sha) - - Commits can be checked for membership in a project, either by their SHA - hash or by a Commit object itself: - - Commit: https://github.com/user2589/minicms/commit/e38126db - >>> sha = 'e38126dbca6572912013621d2aa9e6f7c50f36bc' - >>> sha in Project('user2589_minicms') - True - >>> Commit(sha) in Project('user2589_minicms') - True - """ - - type = 'project' - _keys_registry_dtype = 'p2c' - - def __init__(self, uri): - if isinstance(uri, str): - uri = uri.encode('ascii') - self.uri = uri - super(Project, self).__init__(uri) - - def __iter__(self): - """ Generator of all commits in the project. - Order of commits is not guaranteed - - >>> commits = tuple(Project(b'user2589_minicms')) - >>> len(commits) > 60 - True - >>> isinstance(commits[0], Commit) - True - """ - for sha in self.commit_shas: - try: - c = Commit(sha) - author = c.author - except ObjectNotFound: - continue - if author not in IGNORED_AUTHORS: - yield c - - def __contains__(self, item): - if isinstance(item, Commit): - key = item.key - elif isinstance(item, bytes) and len(item) == 20: - key = item - elif isinstance(item, str) and len(item) == 40: - key = binascii.unhexlify(item) - else: - return False - return key in self.commit_shas - - @cached_property - def commit_shas(self): - """ SHA1 of all commits in the project - - >>> Project(b'user2589_django-currencies').commit_shas - ... # doctest: +NORMALIZE_WHITESPACE - ('2dbcd43f077f2b5511cc107d63a0b9539a6aa2a7', - '7572fc070c44f85e2a540f9a5a05a95d1dd2662d') - """ - return slice20(self.read_tch(('p','c'))) - - @property - def commits(self): - """ A generator of all Commit objects in the project. - It has the same effect as iterating a `Project` instance itself, - with some additional validation of commit dates. - - >>> tuple(Project('user2589_django-currencies').commits) - ... # doctest: +NORMALIZE_WHITESPACE - (, - ) - """ - commits = tuple(c for c in self) - tails = tuple(c for c in commits - if not c.parent_shas and c.authored_at is not None) - if tails: - min_date = min(c.authored_at for c in tails) - else: # i.e. if all tails have invalid date - min_date = DAY_Z - - for c in commits: - if c.authored_at and c.authored_at < min_date: - c.authored_at = None - yield c - - @cached_property - def head(self): - """ Get the HEAD commit of the repository - - >>> Project('user2589_minicms').head - - >>> Project('RoseTHERESA_SimpleCMS').head - - """ - # Sometimes (very rarely) commit dates are wrong, so the latest commit - # is not actually the head. The magic below is to account for this - commits = {c.sha: c for c in self.commits} - parents = set().union(*(c.parent_shas for c in commits.values())) - heads = set(commits.keys()) - parents - - # it is possible that there is more than one head. - # E.g. it happens when HEAD is moved manually (git reset) - # and continued with a separate chain of commits. - # in this case, let's just use the latest one - # actually, storing refs would make it much simpler - return sorted((commits[sha] for sha in heads), - key=lambda c: c.authored_at or DAY_Z)[len(commits)-1] - - @cached_property - def tail(self): - """ Get the first commit SHA by following first parents - - >>> Project(b'user2589_minicms').tail - '1e971a073f40d74a1e72e07c682e1cba0bae159b' - """ - commits = {c.bin_sha: c for c in self.commits} - pts = set(c.parent_shas[0] for c in commits.values() if c.parent_shas) - for bin_sha, c in commits.items(): - if bin_sha in pts and not c.parent_shas: - return bin_sha - - @property - def commits_fp(self): - """ Get a commit chain by following only the first parent, to mimic - https://git-scm.com/docs/git-log#git-log---first-parent . - Thus, you only get a small subset of the full commit tree: - - >>> p = Project(b'user2589_minicms') - >>> set(c.sha for c in p.commits_fp).issubset(p.commit_shas) - True - - In scenarios where branches are not important, it can save a lot - of computing. - - Yields: - Commit: binary commit shas, following first parent only, - from the latest to the earliest. - """ - # Simplified version of self.head(): - # - slightly less precise, - # - 20% faster - # - # out of 500 randomly sampled projects, 493 had the same head. - # In the remaining 7: - # 2 had the same commit chain length, - # 3 had one more commit - # 1 had two more commits - # 1 had three more commits - # Execution time: - # simplified version (argmax): ~153 seconds - # self.head(): ~190 seconds - - # at this point we know all commits are in the dataset - # (validated in __iter___) - result = [] - commits = {c.sha: c for c in self.commits} - commit = max(commits.values(), key=lambda c: c.authored_at or DAY_Z) - - while commit: - try: # here there is no guarantee commit is in the dataset - first_parent = commit.parent_shas and commit.parent_shas[0] - except ObjectNotFound: - break - - yield commit - - if not first_parent: - break - - commit = commits.get(first_parent, Commit(first_parent)) - - @cached_property - def url(self): - """ Get the URL for a given project URI - >>> Project('CS340-19_lectures').url - 'http://github.com/CS340-19/lectures' - """ - prefix, body = self.uri.split(b'_', 1) - if prefix == b'sourceforge.net': - platform = URL_PREFIXES[prefix] - elif prefix in URL_PREFIXES and b'_' in body: - platform = URL_PREFIXES[prefix] - body = body.replace(b'_', b'/', 1) - else: - platform = b'github.com' - body = self.uri.replace(b'_', b'/', 1) - return b'/'.join((b'https:/', platform, body)) - - @cached_property - def author_names(self): - data = decomp(self.read_tch(('p','a'))) - return tuple(author_name - for author_name in (data and data.split(b';')) or [] - if author_name and author_name != 'EMPTY') - - -class File(_Base): - """ - Files are initialized with a path, starting from a commit root tree: - - >>> File(b'.gitignore') # doctest: +SKIP - >>> File(b'docs/Index.rst') # doctest: +SKIP - """ - type = 'file' - _keys_registry_dtype = 'f2c' - - def __init__(self, path): - if isinstance(path, str): - path = path.encode('utf8') - self.path = path - super(File, self).__init__(path) - - """ - deprecated due to current lack of use cases - @cached_property - def author_names(self): - data = decomp(self.read_tch('file_authors')) - return tuple(author for author in (data and data.split(b';')) - if author not in IGNORED_AUTHORS) - """ - - @cached_property - def commit_shas(self): - """ SHA1 of all commits changing this file - - **NOTE: this relation considers only diff with the first parent, - which substantially limits its application** - - >>> commits = File('minicms/templatetags/minicms_tags.py').commit_shas - >>> len(commits) > 0 - True - >>> isinstance(commits, tuple) - True - >>> isinstance(commits[0], str) - True - >>> len(commits[0]) == 40 - True - """ - return slice20(self.read_tch(('f','c'))) - - @property - def commits(self): - """ All commits changing the file - - .. note: this relation considers only diff with the first parent, - which substantially limits its application - - >>> cs = tuple(File('minicms/templatetags/minicms_tags.py').commits) - >>> len(cs) > 0 - True - >>> isinstance(cs[0], Commit) - True - """ - for sha in self.commit_shas: - c = Commit(sha) - try: - author = c.author - except ObjectNotFound: - continue - if author not in IGNORED_AUTHORS: - yield c - - @cached_property - def author_names(self): - data = decomp(self.read_tch(('f','a'))) - return tuple(author_name - for author_name in (data and data.split(b';')) or [] - if author_name and author_name != 'EMPTY') - - def __str__(self): - return super(File, self).__str__().rstrip("\n\r") - - -class Author(_Base): - """ - Authors are initialized with a combination of name and email, as they - appear in git configuration. - - >>> Author('John Doe ') # doctest: +SKIP - - At this point we don't have a relation to map all aliases of the same - author, so keep in mind this object represents an alias, not a person. - """ - type = 'author' - _keys_registry_dtype = 'a2c' - - def __init__(self, full_email): - if isinstance(full_email, str): - full_email = full_email.encode('utf8') - self.full_email = full_email - super(Author, self).__init__(full_email) - - @cached_property - def commit_shas(self): - """ SHA1 of all commits authored by the Author - - >>> commits = Author('user2589 ').commit_shas - >>> len(commits) > 50 - True - >>> isinstance(commits, tuple) - True - >>> isinstance(commits[0], str) - True - >>> len(commits[0]) == 40 - True - """ - return slice20(self.read_tch(('a','c'))) - - @property - def commits(self): - """ A generator of all Commit objects authored by the Author - - >>> commits = tuple( - ... Author('user2589 ').commits) - >>> len(commits) > 40 - True - >>> isinstance(commits[0], Commit) - True - """ - return (Commit(sha) for sha in self.commit_shas) - - @cached_property - def file_names(self): - data = decomp(self.read_tch(('a','f'))) - return tuple(fname for fname in (data and data.split(b';'))) - - @cached_property - def project_names(self): - """ URIs of projects where author has committed to - A generator of all Commit objects authored by the Author - """ - data = decomp(self.read_tch(('a','p'))) - return tuple(project_name - for project_name in (data and data.split(b';')) - if project_name and project_name != b'EMPTY') - - # This relation went MIA as of Sep 6 2020 - # @cached_property - # def torvald(self): - # data = decomp(self.read_tch('author_trpath')) - # return tuple(path for path in (data and data.split(";"))) - -# temporary data for local test -# TODO: remove once commit parse -# -# c = Commit("1cc6f4418dcc09f64dcbb0410fec76ceaa5034ab") -# c._data = b'tree 0a2def6627be9bf2f3c7c2a84eb1e2feb0e7c03e\n' \ -# b'parent d55f5fb86e5892dd1673a9c6cf5e3fdff8c5d93b\n' \ -# b'author AlecGoldstein123 <34690976+AlecGoldstein123@users.noreply.github.com> 1513882101 -0500\n' \ -# b'committer GitHub 1513882101 -0500\n' \ -# b'gpgsig -----BEGIN PGP SIGNATURE-----\n' \ -# b' \n' \ -# b' wsBcBAABCAAQBQJaPAH1CRBK7hj4Ov3rIwAAdHIIACYBs+bTOv7clJSYr9NT0gbX\n' \ -# b' zb4XeJJADvDISZUJChwebEENDue5+GX+dX03ILptRizVVnASwNZR30DENeJNcOpw\n' \ -# b' WqXKho+AV0H0C91x8CIbICnDjdgGdcyKFBCWQ8lBV6BjiRwGXFKJU6dyt480lzs8\n' \ -# b' Eu2PqpTg59Xr/msd4vTrQofSoRwu8kW8KXBWou6G1f9KVCoOXWvhRmiLngFupyPV\n' \ -# b' 0jbNLOe6IQ37xrvvSULCiBmemeYfAJSUywMPIPFyUpzZc2+jKDOcxJeKrRxzmQM0\n' \ -# b' XKeHQIqKSQOVPB/SB7i2Pnxf/UBObaa4kiFoDGHp5IjolgMC+4pFuF2mOE5pbcQ=\n' \ -# b' =cWKt\n' \ -# b' -----END PGP SIGNATURE-----\n' \ -# b' \n\n' \ -# b'Add files via upload' diff --git a/oscar.pyxbld b/oscar.pyxbld deleted file mode 100644 index 6605060..0000000 --- a/oscar.pyxbld +++ /dev/null @@ -1,16 +0,0 @@ - -# this file is needed for oscar.pyx to be compiled by tests/unit_test.py -# because pyximport.install() doesn't take libraries argument - -def make_ext(modname, pyxfilename): - from distutils.extension import Extension - return Extension( - name=modname, libraries=['bz2', 'z'], include_dirs=['lib'], - sources=[pyxfilename, - 'lib/tchdb.c', 'lib/myconf.c', 'lib/tcutil.c', 'lib/md5.c'], - extra_compile_args=['-std=gnu11'] - ) - - -def make_setup_args(): - return {"script_args": ["--force"]} diff --git a/poetry.lock b/poetry.lock index 7d72c48..aa51cc1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -618,4 +618,4 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "71fb85c62d3733be0f2918e966ca1c00909a75677f744cbc161f19bb9856463e" +content-hash = "c814018ea216521755e7c6cb1dc2278192f919166580a2ee24133fa4e99f2ee2" diff --git a/setup.py.bak b/setup.py.bak deleted file mode 100644 index 8d80e99..0000000 --- a/setup.py.bak +++ /dev/null @@ -1,51 +0,0 @@ - -# cython: language_level=3str -import re -from setuptools import Extension, setup - -# IMPORTANT: update oscar.pyxbld if changing any of the Extension parameters -extensions = [ - Extension( - 'oscar', libraries=['bz2', 'z'], include_dirs=['lib'], - sources=['oscar.pyx', - 'lib/tchdb.c', 'lib/myconf.c', 'lib/tcutil.c', 'lib/md5.c'], extra_compile_args=['-std=gnu11'] - ), -] - -head = open('oscar.pyx').read(2048) -pattern = r"""__%s__\s*=\s*['"]([^'"]*)['"]""" -kwargs = {keyword: re.search(pattern % keyword, head).group(1) - for keyword in ('version', 'author', 'license')} - -requirements = [ - line.strip() - for line in open('requirements.txt') - if line.strip() and not line.strip().startswith('#')] - -# options reference: https://docs.python.org/2/distutils/ -# see also: https://packaging.python.org/tutorials/distributing-packages/ -setup( - name='oscar', - description='A Python interface to OSCAR data', - long_description=open('README.md').read(), - long_description_content_type='text/markdown', - classifiers=[ # full list: https://pypi.org/classifiers/ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Science/Research', - 'Programming Language :: Cython', - 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', - 'Operating System :: POSIX :: Linux', - 'Topic :: Scientific/Engineering' - ], - # since setuptools 18.0 it is possible to pass Cython sources to extensions - # without `cythonize` - # https://stackoverflow.com/questions/37471313 - setup_requires=['setuptools>=18.0', 'cython'], - python_requires='>2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4', - # py_modules=['oscar.timeline'], - ext_modules=extensions, - author_email=kwargs['author'], - url='https://github.com/ssc-oscar/oscar.py', - install_requires=requirements, - **kwargs -) From 66f7baa910c99ee6d903e0c417b22167abb5739b Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Tue, 11 Jun 2024 19:34:49 +0800 Subject: [PATCH 31/38] feat: expose WocMaps.maps / objects --- woc/base.py | 7 ++++++- woc/local.pyx | 16 ++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/woc/base.py b/woc/base.py index 6eb2a33..0477c25 100644 --- a/woc/base.py +++ b/woc/base.py @@ -1,4 +1,4 @@ -from typing import List, Literal, Tuple, Union +from typing import Iterable, List, Literal, Tuple, Union WocObjectsWithContent = Literal["tree", "blob", "commit", "tkns", "tag", "bdiff"] """WoC objects stored in stacked binary files.""" @@ -8,6 +8,11 @@ class WocMapsBase: + maps: Iterable[str] + """List of basemaps available in the WoC database.""" + objects: Iterable[str] + """List of objects available in the WoC database.""" + def __init__(self, *args, **kwargs): raise NotImplementedError( "WocMapsBase is an abstract class, use WoCMapsLocal instead" diff --git a/woc/local.pyx b/woc/local.pyx index c57c49c..f42c578 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -553,6 +553,10 @@ class WocMapsLocal(WocMapsBase): "Unsupported wocprofile version: {}".format(self.config["wocSchemaVersion"]) assert self.config["maps"], "Run `python3 -m woc.detect` to scan data files and generate wocprofile.json" + # store name of maps and objects + self.maps = set(self.config["maps"].keys()) + self.objects = set(self.config["objects"].keys()) + def _get_tch_bytes( self, map_name, key ) -> Tuple[bytes, str]: @@ -568,13 +572,13 @@ class WocMapsLocal(WocMapsBase): map_name = 'sha1.blob.tch' # find dtype object - if map_name in self.config["maps"]: + if map_name in self.maps: _map = self.config["maps"][map_name][0] - elif map_name in self.config["objects"]: + elif map_name in self.objects: _map = self.config["objects"][map_name] else: raise KeyError(f'Invalid map name: {map_name}, ' - f'expect one of {", ".join(self.config["maps"].keys())}') + f'expected one of {", ".join(self.maps | self.objects)}') in_dtype = _map["dtypes"][0] if "dtypes" in _map else "h" out_dtype = _map["dtypes"][1] if "dtypes" in _map else "c?" # c? means maybe compressed @@ -790,13 +794,13 @@ class WocMapsLocal(WocMapsBase): if self._is_debug_enabled: start_time = time.time_ns() - if map_name in self.config["maps"]: + if map_name in self.maps: _map = self.config["maps"][map_name][0] - elif map_name in self.config["objects"]: + elif map_name in self.objects: _map = self.config["objects"][map_name] else: raise KeyError(f'Invalid map name: {map_name}, ' - f'expect one of {", ".join(self.config["maps"].keys())}') + f'expect one of {", ".join(self.maps | self.objects)}') _count = len(_map["larges"]) if "larges" in _map else 0 for _shard in _map["shards"]: From a2038ad04671845f8e6c50c83e9f05101c239ddc Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 12 Jun 2024 01:14:24 +0800 Subject: [PATCH 32/38] docs: update README --- README.md | 138 +++++++++++++++++++++++++++++++++----- docs/assets/woc-large.png | Bin 0 -> 8692 bytes docs/assets/woc-micro.png | Bin 0 -> 15612 bytes docs/assets/woc-small.png | Bin 0 -> 11496 bytes docs/quickstart.md | 46 ------------- woc/__init__.py | 2 - 6 files changed, 122 insertions(+), 64 deletions(-) create mode 100644 docs/assets/woc-large.png create mode 100644 docs/assets/woc-micro.png create mode 100644 docs/assets/woc-small.png delete mode 100644 docs/quickstart.md diff --git a/README.md b/README.md index eb8b0f1..ac115e9 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,132 @@ -# Python interface for OSCAR data +# python-woc +**python-woc** is the python interface to the World of Code (WoC) data. +It precedes the [oscar.py](https://ssc-oscar.github.io/oscar.py) project and is hundreds of times faster than the invoking [lookup](https://github.com/ssc-oscar/lookup) scripts via subprocess. -This is a convenience library to access World of Code data -(WoC; it was referred internally as oscar while development, hence the name). -Since everything is stored in local files it won't work unless you have access -to one of the WoC servers. +## Requirements -### Installation +- Linux with a GNU toolchain (only tested on x86_64, Ubuntu / CentOS) -Normally it is preinstalled on WoC servers. To install manually, -e.g. to a virtual environment not using system packages, just use: +- Python 3.8 or later -```shell -python3 setup.py build_ext -python3 setup.py install --user +## Install python-woc + +### From PyPI + +The latest version of `python-woc` is available on PyPI and can be installed using `pip`: + +```bash +pip3 install python-woc +``` + +### From Source + +To try out latest features, you may install python-woc from source: + +```bash +git clone https://github.com/ssc-oscar/python-woc.git +cd python-woc +python3 -m pip install -r requirements.txt +python3 +``` + +## Generate Profiles + +One of the major improvents packed in python-woc is profile. Profiles tell the driver what versions of what maps are available, decoupling the driver from the folder structure of the data. It grants the driver the ability to work with multiple versions of WoC, on a different machine, or even on the cloud. + +Profiles are generated using the `woc.detect` script. The script takes a list of directories, scans for matched filenames, and generates a profile: + +```bash +python3 woc.detect /path/to/woc/1 /path/to/woc/2 ... > wocprofile.json +``` + +By default, python-woc looks for `wocprofile.json`, `~/.wocprofile.json`, and `/etc/wocprofile.json` for the profile. + +## Use CLI + +python-woc's CLI is a drop-in replacement for the `getValues` and `showCnt` perl scripts. We expect existing scripts to be work just well with the following: + +```bash +alias getValues='python3 -m woc.get_values' +alias showCnt='python3 -m woc.show_content' ``` -Installing from sources requires extra tools to compile (cython, -manylinux docker image etc), but still possible. Refer to the -[Build page](https://ssc-oscar.github.io/oscar.py) in the reference. +The usage is the same as the original scripts, and the output should be identical: + +```bash +# echo some_key | echo python3 -m woc.get_values some_map +> echo e4af89166a17785c1d741b8b1d5775f3223f510f | showCnt commit 3 +tree f1b66dcca490b5c4455af319bc961a34f69c72c2 +parent c19ff598808b181f1ab2383ff0214520cb3ec659 +author Audris Mockus 1410029988 -0400 +committer Audris Mockus 1410029988 -0400 + +News for Sep 5 +``` -### Reference +You may find more examples in the [lookup](https://github.com/ssc-oscar/lookup#ov-readme) repository. +If you find any incompatibilities, please [submit an issue report](https://github.com/ssc-oscar/python-woc/issues/new). -Please see for the full reference. +## Use Python API + +The python API is designed to get rid of the overhead of invoking the perl scripts via subprocess. It is also more native to python and provides a more intuitive interface. + +With a `wocprofile.json`, you can create a `WocMapsLocal` object and access the maps in the file system: + +```python +>>> from woc.local import WocMapsLocal +>>> woc = WocMapsLocal() +>>> woc.maps +{'p2c', 'a2b', 'c2ta', 'a2c', 'c2h', 'b2tac', 'a2p', 'a2f', 'c2pc', 'c2dat', 'b2c', 'P2p', 'P2c', 'c2b', 'f2b', 'b2f', 'c2p', 'P2A', 'b2fa', 'c2f', 'p2P', 'f2a', 'p2a', 'c2cc', 'f2c', 'c2r', 'b2P'} +``` + +To query the maps, you can use the `get_values` method: + +```python +>>> woc.get_values("b2fa", "05fe634ca4c8386349ac519f899145c75fff4169") +('1410029988', 'Audris Mockus ', 'e4af89166a17785c1d741b8b1d5775f3223f510f') +>>> woc.get_values("c2b", "e4af89166a17785c1d741b8b1d5775f3223f510f") +['05fe634ca4c8386349ac519f899145c75fff4169'] +>>> woc.get_values("b2tac", "05fe634ca4c8386349ac519f899145c75fff4169") +[('1410029988', 'Audris Mockus ', 'e4af89166a17785c1d741b8b1d5775f3223f510f')] +``` + +Use `show_content` to get the content of a blob, a commit, or a tree: + +```python +>>> woc.show_content("tree", "f1b66dcca490b5c4455af319bc961a34f69c72c2") +[('100644', 'README.md', '05fe634ca4c8386349ac519f899145c75fff4169'), ('100644', 'course.pdf', 'dfcd0359bfb5140b096f69d5fad3c7066f101389')] +>>> woc.show_content("commit", "e4af89166a17785c1d741b8b1d5775f3223f510f") +('f1b66dcca490b5c4455af319bc961a34f69c72c2', ('c19ff598808b181f1ab2383ff0214520cb3ec659',), ('Audris Mockus ', '1410029988', '-0400'), ('Audris Mockus ', '1410029988', '-0400'), 'News for Sep 5') +>>> woc.show_content("blob", "05fe634ca4c8386349ac519f899145c75fff4169") +'# Syllabus for "Fundamentals of Digital Archeology"\n\n## News\n\n* ...' +``` + +Note that the function yields different types for different maps. Please refer to the [documentation](https://ssc-oscar.github.io/python-woc) for details. + +## Use Python Objects API + +The objects API provides a more intuitive way to access the WoC data. +Note that the objects API is not a replacement to [oscar.py](https://ssc-oscar.github.io/oscar.py) even looks pretty much like the same: many of the methods have their signatures changed and refactored to be more consistent, intuitive and performant. Query results are cached, so you can access the same object multiple times without additional overhead. + +Call `init_woc_objects` to initialize the objects API with a WoC instance: + +```python +from woc.local import WocMapsLocal +from woc.objects import init_woc_objects +woc = WocMapsLocal() +init_woc_objects(woc) +``` + +To get the tree of a commit: + +```python +from woc.objects import Commit +>>> c1 = Commit("91f4da4c173e41ffbf0d9ecbe2f07f3a3296933c") +>>> c1.tree +Tree(836f04d5b374033b1608269e2f3aaabae263a0db) +>>> c1.projects[0].url +'https://github.com/woc-hack/thebridge' +``` +For more, check `woc.objects` in the documentation. diff --git a/docs/assets/woc-large.png b/docs/assets/woc-large.png new file mode 100644 index 0000000000000000000000000000000000000000..5c79b0cf0928c440918b802cfcc9131199f3b550 GIT binary patch literal 8692 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éh)XR{i`Zs+ zAZ^1RQvP1@Ss))@!Ec0CEGwOYXvsX(nAYvqs=M$1v6z1bKD93XXRKG~!qe`mhLQ=v&7IEdopok)m>!#<64IeVn|Bih78jyp@#zjLb)T^o17D5d}#@e~kY|*D0A1(rWi=_MdbxrrQ&speqH;>yv-$GGQ-*bkqa9=5ISSB2CU2Xvi}%_O8A%Sf60YcoTmMlN;qr%>!rWp{xSIf kP!j(anfU)GiC}Vubx~6B61wa^GzSqvT~Dn>#X9u=0432B>Hq)$ literal 0 HcmV?d00001 diff --git a/docs/assets/woc-micro.png b/docs/assets/woc-micro.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ee4b6bff3be587e9b064d38d7311d53f3e0e50 GIT binary patch literal 15612 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 H!O#Bzu7yZ} literal 0 HcmV?d00001 diff --git a/docs/assets/woc-small.png b/docs/assets/woc-small.png new file mode 100644 index 0000000000000000000000000000000000000000..02cfa334bcf81043ad095f948c7696b8cca2525b GIT binary patch literal 11496 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 O0000 wocprofile.json -``` - -## CLI - -```bash -echo some_key | echo python3 -m woc.get_values some_map -``` - -## Python API - -```python -from woc.local import WocMapsLocal -woc = WocMapsLocal() # by default it uses ./wocprofile.json, ~/.wocprofile.json, /etc/wocprofile.json -v1 = woc.get_values('some_map', 'some_key') -v2 = woc.show_content('some_commit', 'some_sha') -``` - -## Python OOP API - -```python -from woc.local import WocMapsLocal -from woc.objects import Commit, init_woc_objects -woc = WocMapsLocal() -init_woc_objects(woc) -c = Commit('some_sha') -c.tree -``` diff --git a/woc/__init__.py b/woc/__init__.py index 4308200..0a4da0d 100644 --- a/woc/__init__.py +++ b/woc/__init__.py @@ -6,8 +6,6 @@ """ .. include:: ../README.md -# QuickStart -.. include:: ../docs/quickstart.md # World of Code Tutorial .. include:: ../docs/tutorial.md # World of Code DataFormat From 88b5289cb2d58f6212d5475a0df5e1bcac4136e0 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 12 Jun 2024 02:37:49 +0800 Subject: [PATCH 33/38] fix: handle decompress returns None --- woc/local.pyx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/woc/local.pyx b/woc/local.pyx index f42c578..66a725b 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -132,7 +132,18 @@ def decomp(bytes raw_data): start, usize = lzf_length(raw_data) # while it is tempting to include liblzf and link statically, there is # zero advantage comparing to just using python-lzf - return lzf.decompress(raw_data[start:], usize) + _ret = lzf.decompress(raw_data[start:], usize) + + # NOTE: lzf.decompress may return None if it fails + # e.g. blob b0c0dca2eca2160ec81ff10bec565c790e6b2e97, version R + if _ret is not None: + return _ret + # This case should be exetremely rare and indicates a corrupted file + logging.error(f"Failed to decompress: {len(raw_data) - start} bytes of compressed data " + f"does not fit into {usize} bytes") + raise ValueError(f"Failed to decompress: {len(raw_data) - start} bytes of compressed data " + f"does not fit into {usize} bytes") + def decomp_or_raw(bytes raw_data): """ Try to decompress raw_data, return raw_data if it fails""" @@ -156,7 +167,10 @@ def decode_str(bytes raw_data, str encoding='utf-8'): except UnicodeDecodeError: import chardet # should be rarely used _encoding = chardet.detect(raw_data)['encoding'] - return raw_data.decode(_encoding, errors='replace') + _ret = raw_data.decode(_encoding, errors='replace') + if len(_ret) == 0: + logging.error(f"Failed to decode: {raw_data[:20]}... with encoding {_encoding}") + return _ret ### TCH helpers ### From e11982bb1cf8b45c7196ffd258aaca026ef6b54f Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 12 Jun 2024 02:47:14 +0800 Subject: [PATCH 34/38] style: add conventional commits checker --- .pre-commit-config.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 688f5d9..da257d7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,6 +23,14 @@ repos: types: [python] pass_filenames: false + # enforce conventional commit messages + - repo: https://github.com/compilerla/conventional-pre-commit + rev: v3.2.0 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] + args: [] + # # skip poetry check for now, it's large and slow # # poetry: check lock and generate requirements.txt # - repo: https://github.com/python-poetry/poetry From 808eb5174bf15293ded1b50e493c0f3d77514d3c Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Wed, 12 Jun 2024 20:56:39 +0800 Subject: [PATCH 35/38] revert: remove bb2cf quirk Upstream has fixed, check https://github.com/ssc-oscar/lookup/issues/ --- woc/local.pyx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/woc/local.pyx b/woc/local.pyx index 66a725b..663db8e 100644 --- a/woc/local.pyx +++ b/woc/local.pyx @@ -634,12 +634,6 @@ class WocMapsLocal(WocMapsBase): assert _path, f"shard {_shard} not found at {_path}" _tch = get_tch(_path) - - # TODO: remove bb2cf quirk after fixing tch keys - # bb2cf: keys are stored as hex strings in tch db - if map_name == 'bb2cf': - key = key.hex().encode('ascii') - _bytes = _tch[key] if self._is_debug_enabled: From 4c2bb5a93c5d3cd4f5e96b22e456adeb580acb2c Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 13 Jun 2024 03:09:59 +0800 Subject: [PATCH 36/38] docs: update contributing.md --- docs/.gitignore | 2 + docs/contributing.md | 100 +++++++++++++++++++++++++++++++++++-------- woc/__init__.py | 2 + 3 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 docs/.gitignore diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..dcaab9e --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +*.html +*.js \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md index 7227959..daf857c 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,20 +1,9 @@ -Starting version 1.3, `oscar` is compiled from Cython, a language closely -resembling Python but with optional strong typing to improve performance. -Building Cython packages requires few extra build steps, as explained below. +## How to Commit -In addition, automation in this project relies on few assumptions which you are -expected to follow. Below you can find their brief description and the motivation -behind. +We follow the standard "fork-and-pull" Git workflow. All the development is done on feature branches, which are then merged to `master` via pull requests. Pull requires are unit tested and linted automatically. - -## How to contribute - -All the development is done on feature branches, which are then merged to `master` -via pull requests. Every pull request triggers unit testing, every merge triggers -a release. - -To generate release notes, we use `conventional commits `_, +To generate release notes, we use [conventional commits](https://www.conventionalcommits.org), a convention to commit messages. In a nutshell, it means commit messages should be prefixed with one of: @@ -39,6 +28,81 @@ be incremented. As a consequence, **you must never change version number manuall Not following these procedures might take your pull request extra time to review and in some cases will require rewriting the commit history. +## How to ... + +### Setup dev environment + +To make sure everyone is on the same page, we use [poetry](https://python-poetry.org) +to manage dependencies and virtual environments. +If you don't have it installed yet, please follow the [installation guide](https://python-poetry.org/docs/#installation). + +After installing poetry, create an virtual environment and install all dependencies: + +```bash +poetry shell # activate the virtual environment +poetry install # install all dependencies +``` + +The `poetry install` command builds `python-woc` from source as well. + +### Install pre-commit hooks + +Pre-commit hooks ensure that all code is formatted, linted, and tested before pushed to GitHub. +This "fail fast, fail early" approach saves time and effort for all of us. +` + +```bash +pre-commit install # install linter and unit tests to pre-commit hooks +pre-commit install --hook-type commit-msg # install the conventional commits checker +``` + +### Compile changes to Cython code + +```bash +python3 setup.py +``` + +### Lint + +```bash +ruff format # format all Python code +ruff check # lint all Python code +ruff check --fix # fix all linting issues +``` + +### Test + +```bash +pytest # run all unit tests +pytest -k test_name # run a specific test +pytest --cov # run all tests and check coverage +``` + +### Add or delete a dependency + +```bash +poetry add package_name # add a new dependency +# or +nano pyproject.toml # add a new dependency manually +poetry lock --no-update # update the lock file +``` + +```bash +poetry check --lock +poetry export -f requirements.txt --with build --output requirements.txt +``` + +### Build and publish to PyPI + +```bash +poetry build +``` + +### Publish to PyPI + +```bash +poetry publish --build +``` ## About Cython @@ -71,10 +135,8 @@ of which was previously used). ## Compiling and packaging To compile oscar locally, run: -`python setup.py build_ext --inplace`. To explicitly specify python version, -replace `pyhon`, with the appropriate version, e.g. `python2`. -There shorter alias for this command, `make build`, will always use the default -Python. +`python setup.py`. To explicitly specify python version, +replace `python`, with the appropriate version, e.g. `python3.8`. If you are building for several Python versions in a row without changing the code (e.g. to check if it compiles at all), make sure you clean up first by @@ -88,7 +150,7 @@ this `.so` just a second ago in this case. Packaging is slightly more complicated than just compiling since oscar needs to support at least Python 2.7 and 3.6 simultaneously, meaning we need to package multiple binaries. Fortunately, `PEP 513 `_ -offers support for such packages. Building is done via `manylinux `_, +offers support for such packages. Building is done via [manylinux](https://github.com/pypa/manylinux), a special Docker image, and is automated via GitHub action. To build package locally, diff --git a/woc/__init__.py b/woc/__init__.py index 0a4da0d..33fa6a4 100644 --- a/woc/__init__.py +++ b/woc/__init__.py @@ -5,7 +5,9 @@ # @date: 2024-01-17 """ +# Quickstart .. include:: ../README.md +:start-after: # python-woc # World of Code Tutorial .. include:: ../docs/tutorial.md # World of Code DataFormat From 44305bfc0d56d48e01a1bfe059bed07c8fb11b58 Mon Sep 17 00:00:00 2001 From: 12f23eddde <12f23eddde@gmail.com> Date: Thu, 13 Jun 2024 03:31:06 +0800 Subject: [PATCH 37/38] docs: add favicon, drop large images --- docs/assets/woc-large.png | Bin 8692 -> 0 bytes docs/assets/woc-micro.png | Bin 15612 -> 0 bytes docs/assets/woc-small.png | Bin 11496 -> 0 bytes docs/favicon.ico | Bin 0 -> 15086 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/assets/woc-large.png delete mode 100644 docs/assets/woc-micro.png delete mode 100644 docs/assets/woc-small.png create mode 100644 docs/favicon.ico diff --git a/docs/assets/woc-large.png b/docs/assets/woc-large.png deleted file mode 100644 index 5c79b0cf0928c440918b802cfcc9131199f3b550..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8692 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éh)XR{i`Zs+ zAZ^1RQvP1@Ss))@!Ec0CEGwOYXvsX(nAYvqs=M$1v6z1bKD93XXRKG~!qe`mhLQ=v&7IEdopok)m>!#<64IeVn|Bih78jyp@#zjLb)T^o17D5d}#@e~kY|*D0A1(rWi=_MdbxrrQ&speqH;>yv-$GGQ-*bkqa9=5ISSB2CU2Xvi}%_O8A%Sf60YcoTmMlN;qr%>!rWp{xSIf kP!j(anfU)GiC}Vubx~6B61wa^GzSqvT~Dn>#X9u=0432B>Hq)$ diff --git a/docs/assets/woc-micro.png b/docs/assets/woc-micro.png deleted file mode 100644 index e7ee4b6bff3be587e9b064d38d7311d53f3e0e50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15612 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 H!O#Bzu7yZ} diff --git a/docs/assets/woc-small.png b/docs/assets/woc-small.png deleted file mode 100644 index 02cfa334bcf81043ad095f948c7696b8cca2525b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11496 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 Date: Thu, 13 Jun 2024 03:31:54 +0800 Subject: [PATCH 38/38] ci: add build wheel pipeline --- .github/workflows/build-wheel.yml | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/build-wheel.yml diff --git a/.github/workflows/build-wheel.yml b/.github/workflows/build-wheel.yml new file mode 100644 index 0000000..8518c43 --- /dev/null +++ b/.github/workflows/build-wheel.yml @@ -0,0 +1,51 @@ +name: Run unit tests on every push + +on: [push] + +jobs: + build: + name: Build wheels for Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + if: github.ref_name == github.event.repository.default_branch + + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10", "3.11"] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Poetry + run: | + PIPX_BIN_DIR=/usr/local/bin pipx install poetry + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: poetry + cache-dependency-path: poetry.lock + + - name: Set Poetry environment + run: | + poetry env use ${{ matrix.python-version }} + + - name: Install dependencies + run: | + poetry install + + - name: Build wheels + run: | + poetry build + + - name: Upload wheels + uses: actions/upload-artifact@v2 + with: + path: dist/*.whl + + - name: Upload source distribution + uses: actions/upload-artifact@v2 + if: matrix.python-version == '3.8' + with: + path: dist/*.tar.gz