From 8a6c103f7d7b5032b207d6b26f69c08b57a59c21 Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Thu, 29 Aug 2024 16:53:13 +0200 Subject: [PATCH 01/12] splitting bytes --- .gitignore | 5 ++ blender_asset_tracer/blendfile/__init__.py | 49 ++++++++++++++--- .../trace/modifier_walkers.py | 54 +++++++++++++++++++ 3 files changed, 102 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 7f0097a..b392931 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,8 @@ __pycache__ /build/ /docs/_build + +# envs + +/.env +/.venv \ No newline at end of file diff --git a/blender_asset_tracer/blendfile/__init__.py b/blender_asset_tracer/blendfile/__init__.py index 3894b16..1dc99ae 100644 --- a/blender_asset_tracer/blendfile/__init__.py +++ b/blender_asset_tracer/blendfile/__init__.py @@ -127,9 +127,7 @@ class BlendFile: self.blocks = [] # type: BFBList """BlendFileBlocks of this file, in disk order.""" - self.code_index = collections.defaultdict( - list - ) # type: typing.Dict[bytes, BFBList] + self.code_index = collections.defaultdict(list) # type: typing.Dict[bytes, BFBList] self.structs = [] # type: typing.List[dna.Struct] self.sdna_index_from_id = {} # type: typing.Dict[bytes, int] self.block_from_addr = {} # type: typing.Dict[int, BlendFileBlock] @@ -352,9 +350,25 @@ class BlendFile: else: dna_size = dna_type.size * dna_name.array_size - field = dna.Field(dna_type, dna_name, dna_size, dna_offset) - dna_struct.append_field(field) - dna_offset += dna_size + if dna_name.name_only == b"bakes": + array_count = 3 # Total elements in the array + item_size = 48 # Size of each item in the array + dna_size = ( + item_size * array_count + ) # Total size occupied by the array + + # Create a single field for the entire array + field = dna.Field(dna_type, dna_name, dna_size, dna_offset) + dna_struct.append_field(field) + dna_offset += ( + dna_size # Increment offset by the total size of the array + ) + + else: + # For other fields, proceed as usual + field = dna.Field(dna_type, dna_name, dna_size, dna_offset) + dna_struct.append_field(field) + dna_offset += dna_size def abspath(self, relpath: bpathlib.BlendPath) -> bpathlib.BlendPath: """Construct an absolute path from a blendfile-relative path.""" @@ -796,6 +810,29 @@ class BlendFileBlock: continue yield dereferenced + def iter_bakes(self, array_size: int) -> typing.Iterator["BlendFileBlock"]: + """Iterate over an array of NodesModifierBake pointers with known size.""" + path = ( + b"bakes" # Assuming 'bakes' is the DNA field name for the array of pointers + ) + if array_size == 0: + return + + array = self.get_pointer(path) + assert array and array.code == b"DATA", "Expected DATA block, got {}".format( + array.code.decode() + ) + + file_offset = array.file_offset + ps = self.bfile.header.pointer_size + + for i in range(array_size): + address = self.bfile.read_pointer_at(file_offset + ps * i) + if address: + dereferenced = self.bfile.dereference_pointer(address) + if dereferenced: + yield dereferenced + def __getitem__(self, path: dna.FieldPath): return self.get(path) diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index 12a0468..3ce2b73 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -22,12 +22,18 @@ The modifier_xxx() functions all yield result.BlockUsage objects for external files used by the modifiers. """ + +import struct import logging import typing +from blender_asset_tracer.blendfile import iterators +from blender_asset_tracer.blendfile.dna import Struct from blender_asset_tracer import blendfile, bpathlib, cdefs from . import result +import ctypes + log = logging.getLogger(__name__) modifier_handlers = {} # type: typing.Dict[int, typing.Callable] @@ -317,3 +323,51 @@ def modifier_cloth( yield from _walk_point_cache( ctx, block_name, modifier.bfile, pointcache, cdefs.PTCACHE_EXT ) + + +def split_bytes_array(raw_data: bytes, item_size: int) -> typing.Iterator[bytes]: + for i in range(0, len(raw_data), item_size): + data_part = raw_data[i : i + item_size] + yield data_part + + +def bytes_to_struct(data_bytes: bytes, struct_type: Struct): + """Convert raw bytes into a struct based on the provided Struct definition.""" + struct_instance = {} + + for field in struct_type.fields: + start = field.offset + end = start + field.size + field_data = data_bytes[start:end] + + value = field_data.hex() + + struct_instance[field.name.name_only] = value + + return struct_instance + + +@mod_handler(cdefs.eModifierType_Nodes) +def modifier_nodes( + ctx: ModifierContext, modifier: blendfile.BlendFileBlock, block_name: bytes +) -> typing.Iterator[result.BlockUsage]: + bake_directory = modifier.get_pointer(b"simulation_bake_directory") + # print(bake_directory) + + bakes_ptr = modifier.get(b"bakes") + bakes_num = modifier.get(b"bakes_num") + bakes = modifier.get_pointer(b"bakes") + raw_bakes = bakes.raw_data() + + dna_type = bakes.dna_type + print(list(bakes.values())) + + bakes_split = split_bytes_array(raw_bakes, dna_type.size) + + for bake_bytes in bakes_split: + bake_struct = bytes_to_struct(bake_bytes, dna_type) + print(bake_struct) + + # yield bake_struct + + quit() -- 2.30.2 From cc70b13113874e17472ece3a5a7a0dfe04d3fa2b Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Fri, 30 Aug 2024 01:08:03 +0200 Subject: [PATCH 02/12] parsing byte array works --- blender_asset_tracer/blendfile/__init__.py | 59 +++++++++++++------ .../trace/modifier_walkers.py | 45 ++++++++------ 2 files changed, 68 insertions(+), 36 deletions(-) diff --git a/blender_asset_tracer/blendfile/__init__.py b/blender_asset_tracer/blendfile/__init__.py index 1dc99ae..2866631 100644 --- a/blender_asset_tracer/blendfile/__init__.py +++ b/blender_asset_tracer/blendfile/__init__.py @@ -166,6 +166,7 @@ class BlendFile: break if block.code == b"DNA1": + # for i in range(block.count): self.decode_structs(block) else: self.fileobj.seek(block.size, os.SEEK_CUR) @@ -350,25 +351,10 @@ class BlendFile: else: dna_size = dna_type.size * dna_name.array_size - if dna_name.name_only == b"bakes": - array_count = 3 # Total elements in the array - item_size = 48 # Size of each item in the array - dna_size = ( - item_size * array_count - ) # Total size occupied by the array - - # Create a single field for the entire array - field = dna.Field(dna_type, dna_name, dna_size, dna_offset) - dna_struct.append_field(field) - dna_offset += ( - dna_size # Increment offset by the total size of the array - ) - - else: - # For other fields, proceed as usual - field = dna.Field(dna_type, dna_name, dna_size, dna_offset) - dna_struct.append_field(field) - dna_offset += dna_size + # For other fields, proceed as usual + field = dna.Field(dna_type, dna_name, dna_size, dna_offset) + dna_struct.append_field(field) + dna_offset += dna_size def abspath(self, relpath: bpathlib.BlendPath) -> bpathlib.BlendPath: """Construct an absolute path from a blendfile-relative path.""" @@ -486,6 +472,12 @@ class BlendFileBlock: self.addr_old = blockheader[2] self.sdna_index = blockheader[3] self.count = blockheader[4] + + # if self.count > 1: + # self.size = self.size // self.count + # if self.count > 1: + # print(self.count) + # print("size is 144") self.file_offset = bfile.fileobj.tell() def __repr__(self) -> str: @@ -774,6 +766,35 @@ class BlendFileBlock: continue yield dereferenced + def iter_array_from_pointer( + self, path: dna.FieldPath, array_size: int + ) -> typing.Iterator["BlendFileBlock"]: + """Dereference pointers from an array field. + + :param path: The array-of-pointers field. + :param array_size: Number of items in the array. If None, the + on-disk size of the DNA field is divided by the pointer size to + obtain the array size. + """ + if array_size == 0: + return + + array = self.get_pointer(path) + array_ptr = self.get(path) + + assert array_ptr is not None + + item_size = array.size // array_size + + for i in range(array_size): + print(i) + address = array_ptr + (item_size * i) + print(address) + if address == 0: + continue + dereferenced = self.bfile.dereference_pointer(address) + yield dereferenced + def iter_fixed_array_of_pointers( self, path: dna.FieldPath ) -> typing.Iterator["BlendFileBlock"]: diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index 3ce2b73..b6dbc92 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -27,7 +27,7 @@ import struct import logging import typing from blender_asset_tracer.blendfile import iterators -from blender_asset_tracer.blendfile.dna import Struct +from blender_asset_tracer.blendfile.dna import Struct, Field, Name from blender_asset_tracer import blendfile, bpathlib, cdefs from . import result @@ -325,13 +325,18 @@ def modifier_cloth( ) -def split_bytes_array(raw_data: bytes, item_size: int) -> typing.Iterator[bytes]: +def split_bytes_array(block: blendfile.BlendFileBlock) -> typing.Iterator[bytes]: + """Split a bytes array into parts based on the Struct definition.""" + raw_data = block.raw_data() + item_size = block.dna_type.size for i in range(0, len(raw_data), item_size): data_part = raw_data[i : i + item_size] yield data_part -def bytes_to_struct(data_bytes: bytes, struct_type: Struct): +def bytes_to_struct( + data_bytes: bytes, struct_type: Struct, block: blendfile.BlendFileBlock +) -> dict: """Convert raw bytes into a struct based on the provided Struct definition.""" struct_instance = {} @@ -340,9 +345,16 @@ def bytes_to_struct(data_bytes: bytes, struct_type: Struct): end = start + field.size field_data = data_bytes[start:end] - value = field_data.hex() + if field.name.name_only == b"directory": + directory_pointer = int.from_bytes(field_data, "little") + directory = block.bfile.dereference_pointer(directory_pointer).as_string() + struct_instance["directory"] = directory - struct_instance[field.name.name_only] = value + if field.name.name_only == b"flag": + flag_bin = bin(int.from_bytes(field_data, "little")) + flag_bin_padded = flag_bin[2:].zfill(2) + use_custom_directory = flag_bin_padded[0] + struct_instance["use_custom_directory"] = use_custom_directory return struct_instance @@ -352,22 +364,21 @@ def modifier_nodes( ctx: ModifierContext, modifier: blendfile.BlendFileBlock, block_name: bytes ) -> typing.Iterator[result.BlockUsage]: bake_directory = modifier.get_pointer(b"simulation_bake_directory") - # print(bake_directory) - - bakes_ptr = modifier.get(b"bakes") - bakes_num = modifier.get(b"bakes_num") + bake_directory = bake_directory.as_string() bakes = modifier.get_pointer(b"bakes") - raw_bakes = bakes.raw_data() dna_type = bakes.dna_type - print(list(bakes.values())) - - bakes_split = split_bytes_array(raw_bakes, dna_type.size) + bakes_split = split_bytes_array(bakes) for bake_bytes in bakes_split: - bake_struct = bytes_to_struct(bake_bytes, dna_type) - print(bake_struct) + bake_struct = bytes_to_struct(bake_bytes, dna_type, modifier) + if bake_struct["use_custom_directory"] == "1": + directory = bake_struct["directory"] + else: + directory = bake_directory - # yield bake_struct + print(directory) - quit() + # yield from _walk_point_cache( + # ctx, block_name, modifier.bfile, pointcache, cdefs.PTCACHE_EXT + # ) -- 2.30.2 From 9d4b2159baca447f527d5e84defd5063723d17c2 Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Fri, 30 Aug 2024 01:12:10 +0200 Subject: [PATCH 03/12] undid changes on __init__.py --- blender_asset_tracer/blendfile/__init__.py | 60 ---------------------- 1 file changed, 60 deletions(-) diff --git a/blender_asset_tracer/blendfile/__init__.py b/blender_asset_tracer/blendfile/__init__.py index 2866631..998d8c0 100644 --- a/blender_asset_tracer/blendfile/__init__.py +++ b/blender_asset_tracer/blendfile/__init__.py @@ -166,7 +166,6 @@ class BlendFile: break if block.code == b"DNA1": - # for i in range(block.count): self.decode_structs(block) else: self.fileobj.seek(block.size, os.SEEK_CUR) @@ -351,7 +350,6 @@ class BlendFile: else: dna_size = dna_type.size * dna_name.array_size - # For other fields, proceed as usual field = dna.Field(dna_type, dna_name, dna_size, dna_offset) dna_struct.append_field(field) dna_offset += dna_size @@ -472,12 +470,6 @@ class BlendFileBlock: self.addr_old = blockheader[2] self.sdna_index = blockheader[3] self.count = blockheader[4] - - # if self.count > 1: - # self.size = self.size // self.count - # if self.count > 1: - # print(self.count) - # print("size is 144") self.file_offset = bfile.fileobj.tell() def __repr__(self) -> str: @@ -766,35 +758,6 @@ class BlendFileBlock: continue yield dereferenced - def iter_array_from_pointer( - self, path: dna.FieldPath, array_size: int - ) -> typing.Iterator["BlendFileBlock"]: - """Dereference pointers from an array field. - - :param path: The array-of-pointers field. - :param array_size: Number of items in the array. If None, the - on-disk size of the DNA field is divided by the pointer size to - obtain the array size. - """ - if array_size == 0: - return - - array = self.get_pointer(path) - array_ptr = self.get(path) - - assert array_ptr is not None - - item_size = array.size // array_size - - for i in range(array_size): - print(i) - address = array_ptr + (item_size * i) - print(address) - if address == 0: - continue - dereferenced = self.bfile.dereference_pointer(address) - yield dereferenced - def iter_fixed_array_of_pointers( self, path: dna.FieldPath ) -> typing.Iterator["BlendFileBlock"]: @@ -831,29 +794,6 @@ class BlendFileBlock: continue yield dereferenced - def iter_bakes(self, array_size: int) -> typing.Iterator["BlendFileBlock"]: - """Iterate over an array of NodesModifierBake pointers with known size.""" - path = ( - b"bakes" # Assuming 'bakes' is the DNA field name for the array of pointers - ) - if array_size == 0: - return - - array = self.get_pointer(path) - assert array and array.code == b"DATA", "Expected DATA block, got {}".format( - array.code.decode() - ) - - file_offset = array.file_offset - ps = self.bfile.header.pointer_size - - for i in range(array_size): - address = self.bfile.read_pointer_at(file_offset + ps * i) - if address: - dereferenced = self.bfile.dereference_pointer(address) - if dereferenced: - yield dereferenced - def __getitem__(self, path: dna.FieldPath): return self.get(path) -- 2.30.2 From 4e28a6f85437fb0df12c1b1de7f05d7fd7f5db36 Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Fri, 30 Aug 2024 01:13:48 +0200 Subject: [PATCH 04/12] removed unecessary imports --- blender_asset_tracer/trace/modifier_walkers.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index b6dbc92..c221923 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -23,17 +23,12 @@ The modifier_xxx() functions all yield result.BlockUsage objects for external files used by the modifiers. """ -import struct import logging import typing -from blender_asset_tracer.blendfile import iterators -from blender_asset_tracer.blendfile.dna import Struct, Field, Name - +from blender_asset_tracer.blendfile.dna import Struct from blender_asset_tracer import blendfile, bpathlib, cdefs from . import result -import ctypes - log = logging.getLogger(__name__) modifier_handlers = {} # type: typing.Dict[int, typing.Callable] -- 2.30.2 From f58d511304a87977c84110d27dc35fd1c2ffccc7 Mon Sep 17 00:00:00 2001 From: Jonas Dichelle Date: Fri, 30 Aug 2024 14:47:51 +0200 Subject: [PATCH 05/12] updated syntax highlighting, removed dead links --- README.md | 126 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 1b4f74a..02ee213 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ # Blender Asset Tracer BAT🦇 -Script to manage assets with Blender. - -Blender Asset Tracer, a.k.a. BAT🦇, is the replacement of -[BAM](https://developer.blender.org/diffusion/BAM/) and -[blender-file](https://developer.blender.org/source/blender-file/) +Blender Asset Tracer, a.k.a. BAT🦇 is a script to manage assets with Blender. Development is driven by choices explained in [T54125](https://developer.blender.org/T54125). @@ -13,18 +9,28 @@ Development is driven by choices explained in [T54125](https://developer.blender The `cli.py` wrapper at the root of the project can be used to directly access the command line tools, without requiring any setup involving `venv` and so on: -``` +```bash python3 path/to/repo/cli.py list path/to/blendfile.blend ``` ## Setting up development environment -``` +```bash python3.9 -m venv .venv +``` +```bash . ./.venv/bin/activate +``` +```bash pip install -U pip +``` +```bash pip install poetry black +``` +```bash poetry install +``` +```bash mypy --install-types ``` @@ -34,14 +40,18 @@ mypy --install-types BAT Pack supports uploading to S3-compatible storage. This requires a credentials file in `~/.aws/credentials`. Replace the all-capital words to suit your situation. - [ENDPOINT] - aws_access_key_id = YOUR_ACCESS_KEY_ID - aws_secret_access_key = YOUR_SECRET +```ini +[ENDPOINT] +aws_access_key_id = YOUR_ACCESS_KEY_ID +aws_secret_access_key = YOUR_SECRET +``` You can then send a BAT Pack to the storage using a target `s3:/ENDPOINT/bucketname/path-in-bucket`, for example: - bat pack my_blendfile.blend s3:/storage.service.cloud/jobs/awesome_work +```bash +bat pack my_blendfile.blend s3:/storage.service.cloud/jobs/awesome_work +``` This will upload the blend file and its dependencies to `awesome_work/my_blendfile.blend` in the `jobs` bucket. @@ -76,49 +86,51 @@ Mypy likes to see the return type of `__init__` methods explicitly declared as ` BAT can be used as a Python library to inspect the contents of blend files, without having to open Blender itself. Here is an example showing how to determine the render engine used: - #!/usr/bin/env python3.7 - import json - import sys - from pathlib import Path +```python +#!/usr/bin/env python3.7 +import json +import sys +from pathlib import Path - from blender_asset_tracer import blendfile - from blender_asset_tracer.blendfile import iterators +from blender_asset_tracer import blendfile +from blender_asset_tracer.blendfile import iterators - if len(sys.argv) != 2: - print(f'Usage: {sys.argv[0]} somefile.blend', file=sys.stderr) - sys.exit(1) +if len(sys.argv) != 2: + print(f'Usage: {sys.argv[0]} somefile.blend', file=sys.stderr) + sys.exit(1) - bf_path = Path(sys.argv[1]) - bf = blendfile.open_cached(bf_path) +bf_path = Path(sys.argv[1]) +bf = blendfile.open_cached(bf_path) - # Get the first window manager (there is probably exactly one). - window_managers = bf.find_blocks_from_code(b'WM') - assert window_managers, 'The Blend file has no window manager' - window_manager = window_managers[0] +# Get the first window manager (there is probably exactly one). +window_managers = bf.find_blocks_from_code(b'WM') +assert window_managers, 'The Blend file has no window manager' +window_manager = window_managers[0] - # Get the scene from the first window. - windows = window_manager.get_pointer((b'windows', b'first')) - for window in iterators.listbase(windows): - scene = window.get_pointer(b'scene') - break +# Get the scene from the first window. +windows = window_manager.get_pointer((b'windows', b'first')) +for window in iterators.listbase(windows): + scene = window.get_pointer(b'scene') + break - # BAT can only return simple values, so it can't return the embedded - # struct 'r'. 'r.engine' is a simple string, though. - engine = scene[b'r', b'engine'].decode('utf8') - xsch = scene[b'r', b'xsch'] - ysch = scene[b'r', b'ysch'] - size = scene[b'r', b'size'] / 100.0 +# BAT can only return simple values, so it can't return the embedded +# struct 'r'. 'r.engine' is a simple string, though. +engine = scene[b'r', b'engine'].decode('utf8') +xsch = scene[b'r', b'xsch'] +ysch = scene[b'r', b'ysch'] +size = scene[b'r', b'size'] / 100.0 - render_info = { - 'engine': engine, - 'frame_pixels': { - 'x': int(xsch * size), - 'y': int(ysch * size), - }, - } +render_info = { + 'engine': engine, + 'frame_pixels': { + 'x': int(xsch * size), + 'y': int(ysch * size), + }, +} - json.dump(render_info, sys.stdout, indent=4, sort_keys=True) - print() +json.dump(render_info, sys.stdout, indent=4, sort_keys=True) +print() +``` To understand the naming of the properties, look at Blender's `DNA_xxxx.h` files with struct definitions. It is those names that are accessed via `blender_asset_tracer.blendfile`. The @@ -155,23 +167,29 @@ As password, use the token itself, including the `pypi-` prefix. See https://pypi.org/help/#apitoken for help using API tokens to publish. This is what I have in `~/.pypirc`: -``` +```ini [distutils] -index-servers = - bat +index-servers = bat # Use `twine upload -r bat` to upload with this token. [bat] - repository = https://upload.pypi.org/legacy/ - username = __token__ - password = pypi-abc-123-blablabla +repository = https://upload.pypi.org/legacy/ +username = __token__ +password = pypi-abc-123-blablabla ``` -``` +```bash . ./.venv/bin/activate +``` +```bash pip install twine - +``` +```bash poetry build +``` +```bash twine check dist/blender_asset_tracer-1.18.tar.gz dist/blender_asset_tracer-1.18-*.whl +``` +```bash twine upload -r bat dist/blender_asset_tracer-1.18.tar.gz dist/blender_asset_tracer-1.18-*.whl ``` -- 2.30.2 From 7edf7549c32995fbc762b7657e22b7d44a0a057d Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Mon, 2 Sep 2024 21:55:14 +0200 Subject: [PATCH 06/12] added dynamic array iterator and using on geo nodes bakes --- blender_asset_tracer/blendfile/iterators.py | 25 ++++++ .../trace/modifier_walkers.py | 77 +++++++------------ 2 files changed, 54 insertions(+), 48 deletions(-) diff --git a/blender_asset_tracer/blendfile/iterators.py b/blender_asset_tracer/blendfile/iterators.py index 21849a6..d713a0b 100644 --- a/blender_asset_tracer/blendfile/iterators.py +++ b/blender_asset_tracer/blendfile/iterators.py @@ -70,3 +70,28 @@ def modifiers(object_block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]: # 'ob->modifiers[...]' mods = object_block.get_pointer((b"modifiers", b"first")) yield from listbase(mods, next_path=(b"modifier", b"next")) + + +def copy_block(block: BlendFileBlock) -> BlendFileBlock: + """Create a new BlendFileBlock instance with the same slot data as the provided block.""" + if not isinstance(block, BlendFileBlock): + raise ValueError("The existing_block must be an instance of BlendFileBlock") + + new_block = BlendFileBlock(block.bfile) + + for slot in BlendFileBlock.__slots__: + setattr(new_block, slot, getattr(block, slot)) + + return new_block + + +def dynamic_array(block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]: + """Generator, yields all blocks in a block that is a dynamic array.""" + offset = block.file_offset + for i in range(block.count): + new_block = copy_block(block) + new_block.file_offset = offset + new_block.size = block.dna_type.size // block.count + + yield new_block + offset += block.dna_type.size diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index c221923..bfd72e0 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -25,7 +25,6 @@ files used by the modifiers. import logging import typing -from blender_asset_tracer.blendfile.dna import Struct from blender_asset_tracer import blendfile, bpathlib, cdefs from . import result @@ -320,60 +319,42 @@ def modifier_cloth( ) -def split_bytes_array(block: blendfile.BlendFileBlock) -> typing.Iterator[bytes]: - """Split a bytes array into parts based on the Struct definition.""" - raw_data = block.raw_data() - item_size = block.dna_type.size - for i in range(0, len(raw_data), item_size): - data_part = raw_data[i : i + item_size] - yield data_part - - -def bytes_to_struct( - data_bytes: bytes, struct_type: Struct, block: blendfile.BlendFileBlock -) -> dict: - """Convert raw bytes into a struct based on the provided Struct definition.""" - struct_instance = {} - - for field in struct_type.fields: - start = field.offset - end = start + field.size - field_data = data_bytes[start:end] - - if field.name.name_only == b"directory": - directory_pointer = int.from_bytes(field_data, "little") - directory = block.bfile.dereference_pointer(directory_pointer).as_string() - struct_instance["directory"] = directory - - if field.name.name_only == b"flag": - flag_bin = bin(int.from_bytes(field_data, "little")) - flag_bin_padded = flag_bin[2:].zfill(2) - use_custom_directory = flag_bin_padded[0] - struct_instance["use_custom_directory"] = use_custom_directory - - return struct_instance - - @mod_handler(cdefs.eModifierType_Nodes) def modifier_nodes( ctx: ModifierContext, modifier: blendfile.BlendFileBlock, block_name: bytes ) -> typing.Iterator[result.BlockUsage]: - bake_directory = modifier.get_pointer(b"simulation_bake_directory") - bake_directory = bake_directory.as_string() + mod_directory_ptr, mod_directory_field = modifier.get( + b"simulation_bake_directory", return_field=True + ) + bakes = modifier.get_pointer(b"bakes") - dna_type = bakes.dna_type - bakes_split = split_bytes_array(bakes) + for bake_idx, bake in enumerate(blendfile.iterators.dynamic_array(bakes)): + bake_directory_ptr, bake_directory_field = bake.get( + b"directory", return_field=True + ) - for bake_bytes in bakes_split: - bake_struct = bytes_to_struct(bake_bytes, dna_type, modifier) - if bake_struct["use_custom_directory"] == "1": - directory = bake_struct["directory"] + flag = bake.get(b"flag") + flag_bin = bin(flag) + flag_bin_padded = flag_bin[2:].zfill(2) + use_custom_directory = flag_bin_padded[0] == "1" + + if use_custom_directory: + directory_ptr = bake_directory_ptr + field = bake_directory_field else: - directory = bake_directory + directory_ptr = mod_directory_ptr + field = mod_directory_field - print(directory) + if directory_ptr == 0: + continue + directory = bake.bfile.dereference_pointer(directory_ptr) + if not directory: + continue - # yield from _walk_point_cache( - # ctx, block_name, modifier.bfile, pointcache, cdefs.PTCACHE_EXT - # ) + bpath = bytes(directory.as_string(), "utf-8") + bake_block_name = block_name + b".bakes[%d]" % bake_idx + + yield result.BlockUsage( + modifier, bpath, block_name=bake_block_name, path_full_field=field + ) -- 2.30.2 From 1c0514d086e7bcb9b98d562ce6ebefae80c4abf3 Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Mon, 2 Sep 2024 21:59:05 +0200 Subject: [PATCH 07/12] undid readme changes --- README.md | 126 +++++++++++++++++++++++------------------------------- 1 file changed, 54 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 02ee213..1b4f74a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Blender Asset Tracer BAT🦇 -Blender Asset Tracer, a.k.a. BAT🦇 is a script to manage assets with Blender. +Script to manage assets with Blender. + +Blender Asset Tracer, a.k.a. BAT🦇, is the replacement of +[BAM](https://developer.blender.org/diffusion/BAM/) and +[blender-file](https://developer.blender.org/source/blender-file/) Development is driven by choices explained in [T54125](https://developer.blender.org/T54125). @@ -9,28 +13,18 @@ Development is driven by choices explained in [T54125](https://developer.blender The `cli.py` wrapper at the root of the project can be used to directly access the command line tools, without requiring any setup involving `venv` and so on: -```bash +``` python3 path/to/repo/cli.py list path/to/blendfile.blend ``` ## Setting up development environment -```bash +``` python3.9 -m venv .venv -``` -```bash . ./.venv/bin/activate -``` -```bash pip install -U pip -``` -```bash pip install poetry black -``` -```bash poetry install -``` -```bash mypy --install-types ``` @@ -40,18 +34,14 @@ mypy --install-types BAT Pack supports uploading to S3-compatible storage. This requires a credentials file in `~/.aws/credentials`. Replace the all-capital words to suit your situation. -```ini -[ENDPOINT] -aws_access_key_id = YOUR_ACCESS_KEY_ID -aws_secret_access_key = YOUR_SECRET -``` + [ENDPOINT] + aws_access_key_id = YOUR_ACCESS_KEY_ID + aws_secret_access_key = YOUR_SECRET You can then send a BAT Pack to the storage using a target `s3:/ENDPOINT/bucketname/path-in-bucket`, for example: -```bash -bat pack my_blendfile.blend s3:/storage.service.cloud/jobs/awesome_work -``` + bat pack my_blendfile.blend s3:/storage.service.cloud/jobs/awesome_work This will upload the blend file and its dependencies to `awesome_work/my_blendfile.blend` in the `jobs` bucket. @@ -86,51 +76,49 @@ Mypy likes to see the return type of `__init__` methods explicitly declared as ` BAT can be used as a Python library to inspect the contents of blend files, without having to open Blender itself. Here is an example showing how to determine the render engine used: -```python -#!/usr/bin/env python3.7 -import json -import sys -from pathlib import Path + #!/usr/bin/env python3.7 + import json + import sys + from pathlib import Path -from blender_asset_tracer import blendfile -from blender_asset_tracer.blendfile import iterators + from blender_asset_tracer import blendfile + from blender_asset_tracer.blendfile import iterators -if len(sys.argv) != 2: - print(f'Usage: {sys.argv[0]} somefile.blend', file=sys.stderr) - sys.exit(1) + if len(sys.argv) != 2: + print(f'Usage: {sys.argv[0]} somefile.blend', file=sys.stderr) + sys.exit(1) -bf_path = Path(sys.argv[1]) -bf = blendfile.open_cached(bf_path) + bf_path = Path(sys.argv[1]) + bf = blendfile.open_cached(bf_path) -# Get the first window manager (there is probably exactly one). -window_managers = bf.find_blocks_from_code(b'WM') -assert window_managers, 'The Blend file has no window manager' -window_manager = window_managers[0] + # Get the first window manager (there is probably exactly one). + window_managers = bf.find_blocks_from_code(b'WM') + assert window_managers, 'The Blend file has no window manager' + window_manager = window_managers[0] -# Get the scene from the first window. -windows = window_manager.get_pointer((b'windows', b'first')) -for window in iterators.listbase(windows): - scene = window.get_pointer(b'scene') - break + # Get the scene from the first window. + windows = window_manager.get_pointer((b'windows', b'first')) + for window in iterators.listbase(windows): + scene = window.get_pointer(b'scene') + break -# BAT can only return simple values, so it can't return the embedded -# struct 'r'. 'r.engine' is a simple string, though. -engine = scene[b'r', b'engine'].decode('utf8') -xsch = scene[b'r', b'xsch'] -ysch = scene[b'r', b'ysch'] -size = scene[b'r', b'size'] / 100.0 + # BAT can only return simple values, so it can't return the embedded + # struct 'r'. 'r.engine' is a simple string, though. + engine = scene[b'r', b'engine'].decode('utf8') + xsch = scene[b'r', b'xsch'] + ysch = scene[b'r', b'ysch'] + size = scene[b'r', b'size'] / 100.0 -render_info = { - 'engine': engine, - 'frame_pixels': { - 'x': int(xsch * size), - 'y': int(ysch * size), - }, -} + render_info = { + 'engine': engine, + 'frame_pixels': { + 'x': int(xsch * size), + 'y': int(ysch * size), + }, + } -json.dump(render_info, sys.stdout, indent=4, sort_keys=True) -print() -``` + json.dump(render_info, sys.stdout, indent=4, sort_keys=True) + print() To understand the naming of the properties, look at Blender's `DNA_xxxx.h` files with struct definitions. It is those names that are accessed via `blender_asset_tracer.blendfile`. The @@ -167,29 +155,23 @@ As password, use the token itself, including the `pypi-` prefix. See https://pypi.org/help/#apitoken for help using API tokens to publish. This is what I have in `~/.pypirc`: -```ini +``` [distutils] -index-servers = bat +index-servers = + bat # Use `twine upload -r bat` to upload with this token. [bat] -repository = https://upload.pypi.org/legacy/ -username = __token__ -password = pypi-abc-123-blablabla + repository = https://upload.pypi.org/legacy/ + username = __token__ + password = pypi-abc-123-blablabla ``` -```bash +``` . ./.venv/bin/activate -``` -```bash pip install twine -``` -```bash + poetry build -``` -```bash twine check dist/blender_asset_tracer-1.18.tar.gz dist/blender_asset_tracer-1.18-*.whl -``` -```bash twine upload -r bat dist/blender_asset_tracer-1.18.tar.gz dist/blender_asset_tracer-1.18-*.whl ``` -- 2.30.2 From 98efbc5e658de8ea6ba885dbda2660ceeaf1625d Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Mon, 2 Sep 2024 22:00:51 +0200 Subject: [PATCH 08/12] updated formatting, reverted readme --- .gitignore | 7 +------ blender_asset_tracer/trace/modifier_walkers.py | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index b392931..07b1e33 100644 --- a/.gitignore +++ b/.gitignore @@ -10,9 +10,4 @@ __pycache__ /dist/ /build/ -/docs/_build - -# envs - -/.env -/.venv \ No newline at end of file +/docs/_build \ No newline at end of file diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index bfd72e0..f274870 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -25,6 +25,7 @@ files used by the modifiers. import logging import typing + from blender_asset_tracer import blendfile, bpathlib, cdefs from . import result -- 2.30.2 From 3a6be5c90bccdaa113f870d0a7290d697a5ff60b Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Mon, 2 Sep 2024 23:09:11 +0200 Subject: [PATCH 09/12] added envs to gitignore, made geo nodes cache sequence --- .gitignore | 5 ++++- blender_asset_tracer/trace/modifier_walkers.py | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 07b1e33..d3f5cf1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,7 @@ __pycache__ /dist/ /build/ -/docs/_build \ No newline at end of file +/docs/_build + +/.env +/.venv \ No newline at end of file diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index dce2d3c..54eb52c 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -390,5 +390,9 @@ def modifier_nodes( bake_block_name = block_name + b".bakes[%d]" % bake_idx yield result.BlockUsage( - modifier, bpath, block_name=bake_block_name, path_full_field=field + modifier, + bpath, + block_name=bake_block_name, + path_full_field=field, + is_sequence=True, ) -- 2.30.2 From 6160c422b08017b76f80710270ca8e496efab1a6 Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Tue, 3 Sep 2024 00:19:52 +0200 Subject: [PATCH 10/12] using correct block to rewrite files --- blender_asset_tracer/trace/modifier_walkers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index 54eb52c..159ca19 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -376,9 +376,11 @@ def modifier_nodes( if use_custom_directory: directory_ptr = bake_directory_ptr field = bake_directory_field + block = bake else: directory_ptr = mod_directory_ptr field = mod_directory_field + block = modifier if directory_ptr == 0: continue @@ -390,7 +392,7 @@ def modifier_nodes( bake_block_name = block_name + b".bakes[%d]" % bake_idx yield result.BlockUsage( - modifier, + block, bpath, block_name=bake_block_name, path_full_field=field, -- 2.30.2 From 0f904d03c5746dd13c46ef22ef4b4ad72f562a8f Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Thu, 5 Sep 2024 13:26:50 +0200 Subject: [PATCH 11/12] fixing issues for PR --- .gitignore | 5 +-- blender_asset_tracer/blendfile/__init__.py | 4 ++- blender_asset_tracer/blendfile/iterators.py | 31 +++++++++---------- blender_asset_tracer/cdefs.py | 5 ++- .../trace/modifier_walkers.py | 6 ++-- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index d3f5cf1..07b1e33 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,4 @@ __pycache__ /dist/ /build/ -/docs/_build - -/.env -/.venv \ No newline at end of file +/docs/_build \ No newline at end of file diff --git a/blender_asset_tracer/blendfile/__init__.py b/blender_asset_tracer/blendfile/__init__.py index 998d8c0..3894b16 100644 --- a/blender_asset_tracer/blendfile/__init__.py +++ b/blender_asset_tracer/blendfile/__init__.py @@ -127,7 +127,9 @@ class BlendFile: self.blocks = [] # type: BFBList """BlendFileBlocks of this file, in disk order.""" - self.code_index = collections.defaultdict(list) # type: typing.Dict[bytes, BFBList] + self.code_index = collections.defaultdict( + list + ) # type: typing.Dict[bytes, BFBList] self.structs = [] # type: typing.List[dna.Struct] self.sdna_index_from_id = {} # type: typing.Dict[bytes, int] self.block_from_addr = {} # type: typing.Dict[int, BlendFileBlock] diff --git a/blender_asset_tracer/blendfile/iterators.py b/blender_asset_tracer/blendfile/iterators.py index d713a0b..b587f1c 100644 --- a/blender_asset_tracer/blendfile/iterators.py +++ b/blender_asset_tracer/blendfile/iterators.py @@ -20,6 +20,7 @@ # (c) 2014, Blender Foundation - Campbell Barton # (c) 2018, Blender Foundation - Sybren A. Stüvel import typing +import copy from blender_asset_tracer import cdefs from . import BlendFileBlock @@ -72,26 +73,22 @@ def modifiers(object_block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]: yield from listbase(mods, next_path=(b"modifier", b"next")) -def copy_block(block: BlendFileBlock) -> BlendFileBlock: - """Create a new BlendFileBlock instance with the same slot data as the provided block.""" - if not isinstance(block, BlendFileBlock): - raise ValueError("The existing_block must be an instance of BlendFileBlock") - - new_block = BlendFileBlock(block.bfile) - - for slot in BlendFileBlock.__slots__: - setattr(new_block, slot, getattr(block, slot)) - - return new_block - - def dynamic_array(block: BlendFileBlock) -> typing.Iterator[BlendFileBlock]: - """Generator, yields all blocks in a block that is a dynamic array.""" + """ + Generator that yields each element of a dynamic array as a separate block. + + Dynamic arrays are multiple contiguous elements accessed via a single pointer. + BAT interprets these as a single data block, making it hard to access individual elements. + This function divides the array into individual blocks by creating modified copies of the original block. + """ + offset = block.file_offset + element_size = block.dna_type.size + for i in range(block.count): - new_block = copy_block(block) + new_block = copy.copy(block) new_block.file_offset = offset - new_block.size = block.dna_type.size // block.count + new_block.size = element_size yield new_block - offset += block.dna_type.size + offset += element_size diff --git a/blender_asset_tracer/cdefs.py b/blender_asset_tracer/cdefs.py index c5b7fd1..72d03c0 100644 --- a/blender_asset_tracer/cdefs.py +++ b/blender_asset_tracer/cdefs.py @@ -52,6 +52,9 @@ eModifierType_MeshSequenceCache = 52 eModifierType_Fluid = 56 eModifierType_Nodes = 57 +# NodesModifierBakeFlag +NODES_MODIFIER_BAKE_CUSTOM_PATH = 1 << 1 + # DNA_particle_types.h PART_DRAW_OB = 7 PART_DRAW_GR = 8 @@ -101,4 +104,4 @@ PTCACHE_PATH = b"blendcache_" # BKE_node.h SH_NODE_TEX_IMAGE = 143 -CMP_NODE_R_LAYERS = 221 +CMP_NODE_R_LAYERS = 221 \ No newline at end of file diff --git a/blender_asset_tracer/trace/modifier_walkers.py b/blender_asset_tracer/trace/modifier_walkers.py index 159ca19..3f1f701 100644 --- a/blender_asset_tracer/trace/modifier_walkers.py +++ b/blender_asset_tracer/trace/modifier_walkers.py @@ -369,9 +369,7 @@ def modifier_nodes( ) flag = bake.get(b"flag") - flag_bin = bin(flag) - flag_bin_padded = flag_bin[2:].zfill(2) - use_custom_directory = flag_bin_padded[0] == "1" + use_custom_directory = bool(flag & cdefs.NODES_MODIFIER_BAKE_CUSTOM_PATH) if use_custom_directory: directory_ptr = bake_directory_ptr @@ -382,7 +380,7 @@ def modifier_nodes( field = mod_directory_field block = modifier - if directory_ptr == 0: + if not directory_ptr: continue directory = bake.bfile.dereference_pointer(directory_ptr) if not directory: -- 2.30.2 From 79a13120160acd4da345114eccfbc98aad8ec59e Mon Sep 17 00:00:00 2001 From: jonasdichelle Date: Thu, 5 Sep 2024 14:22:05 +0200 Subject: [PATCH 12/12] added dynamic array test --- .../multiple_geometry_nodes_bakes.blend | Bin 0 -> 406302 bytes tests/test_blendfile_loading.py | 23 ++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/blendfiles/multiple_geometry_nodes_bakes.blend diff --git a/tests/blendfiles/multiple_geometry_nodes_bakes.blend b/tests/blendfiles/multiple_geometry_nodes_bakes.blend new file mode 100644 index 0000000000000000000000000000000000000000..cb977c1018e41367a18e721c0ba6020a9a7a6882 GIT binary patch literal 406302 zcmeEv34C2uo&QT)Ab>(e)KDtC($WpO?@N-Gq&wYc3oW1|Y5LlRrb$UsX#LMfM8S?A z;$Cqfu2kGW(P0$Yu&6~raf7-}Tt*Qc2WN0pM!o;v_nh;6_ug~weeb@PG-=Dd`J9~f z_dDmeoaJ}Ux%btsT)cYG;&qd*n>ls*IteaIrBb(_a^D@!4HA&2%(xfCU*D8%%_6bH zXT#$48_K&|AuwMb0_roa0nfR1|dQop+vs znJ{63GjZZX=fVpwbjFSyt8koq?zxfhuYUEbor^EN*Z~~s2JHFgpC4I1PFw6U^J~{S zZ@BeC&aC-$PG->xXV$zLXU>9Jr*6qAr>b_jQ(3c2xrLdfQl`dPP`$*dS#*grTgoh2 zwnoJPH@|YRGjh~KXT*qTdhEK7mH5b!Bb7`b7s?iL2Hzp)Ns}fyD09ID7dZ3h&v$0c zp6kq=tKFPAa|(u0wyLU1mGhP-j(mP5lL^3ial{Gd!(WwIE?g+R%2Sr`@V)6Xrq59Ipss1trj;B9yp4ltanp;bf6A08 zicjDb`b>X0=n%$4$Q-&gkPb9K{%{vgoT0`9j0+f_;lpvPh?DMxBfJggO)myF;JoFD zXQ1lDJVjphw+;-Z{HcE{c7E8Ids&y#MYM-*=FFM7Fw-z@fbWdcA3uJ)nqL^FkA8-^ zo^kk?^D(B{>F5Vxbz+IS06z2q`OtUh0(2N-0r~>+pxe+Xq=C-Gix;c04Z4GQBb`pG@ecK_ zT)9$>DJTy-7_&LXU|v9bP!4?%dBBM=9OW?wBOmPq&M*g_Ll=M(59Y9%(XGlXmHZE@*?MFM%E;zQCKGRVLd4@XR z(B>uUwm54qZ&b8%{WVzfhx{;xfe(-u#x(S0$meJ|(2Bm)Uu!7f8GXTMXY81<0f%v< zKkFeb@D2KcF%07z+@+UZs(86!!v+;!y?V8pAGucW`hXuXVuW&oIsZdv**6BtN8bg_ z{pHSk^?A;O(c_(oV<$KZ=E)c}SJpArHO@ujq|c9@;GBP+f4$$=dND>oeqMPZjCln8 z2mKs#KF^);U*S zeYG=vir6WV-rqV9C4Y>enCGDbSm)89EnNFC4fDdW(EkTo{+JuFmZ1Fl>Z9L7#&8!; zn56n1`j%R=PP{mmr*%N@we_{mDEVU!;93%MDjnp{Fnz3-DF2PK<~oyQZF02c+bF!~ zhsUe@vHqGnN8~(jfpRrf8E4w$8H&$X+k@tb<0m>ZC(m@IT|7-Wj1L!%xvV2Zy??A*#E~}e33J8>J(+efmayo!Ap$y<7SBsd6}H?zVB<{e1cqpssk z{%P4OpE75b;u-evCr_H}%oh315(j_WnDNe7;U(R;3+1dE>w+;CDR<$hG3v|~JU?f4 z>1)s^`EzW?J}}n!=;yEnu^z=7zZT>`WKc5`ycs`J=UtA;r#RU-Jcix{Ez!+ zwgZ2rEtuz=cfQ|t$G*?l(PNz{<0t3bq={417>so{cnSM&$~ZTFf~*hhy}*&9M>*%r znd*!jJ6hcfz`6ns_1bMg9O;lhY)p*bVb1RBVR5Vj+5acaUgnHT*8ggK4!PlM5&W4n zbGkEmf{dn3)%M?L zfy1~@Jn&ytJJ&g{ZocY|=-03*E}S~a88vN^3UfaJd*zfr*78W_UN3x%IT-(uhw~)N z2|V-RnGk%eyI~{3_J&TKFKd@X{;yVNLXaEy3O>DB`r$dVra0%058CUa)A|e%yo7ug z%wHhqa2GjKX3cbF$#}7_uErTZf3`D!j+Q6N!Hv1Vk88xViyVvr=ZmZ-UB1$pebqW= z`c;=Y=g*trjFh{17)#I|oZE3+K>w#r7iQxl4f_prpotE+uugyvU4uT2mphW<#BO1k zf%3tR<6-~joSAZ0*;=Qi&r8dG@5RpiSu#$HyV#j1^ZYpJchgoab7rnt;as@9*12%@ zENAk#NzTIAG9FwsRjn09o$p!i$((Y|j7drckV9Mt`O~h)nHk0fuY+9=eetF-jIn9U zmMyCPV+_DK=+v1DbNd+sC41C!yvQGNfxRBK7Kc3HMyF*Aytm$yR zGf~caF}7x^GtM%Zk0;6afc1ac+vh#~9OFtDzCvkzkw4ZoxHEvh4~M#DPm(()$@;IL zEY6uF{ngx;r;I3j$Qkw??0?u@7-MPwD;<#ef-vw$$hbdJ#(!^G+%V-oX+x8fsegmB ze%sB?x~(@kmx`;r;!Tlm-WqN9VP6ok=Q-%y$%*{q^8TDT?!GN-K=gas_>(W1qW0pr z{<=u)Kjvv2F!w;xvaXbMf809la+LqHORjRNF6(e=H(sY)-Nx&k1?xH^-P{#h)S3_X zK_Gv%#uZ&mi%uu!fAQ8|BQG2+Ho;`M?=?owd*%J1DRRyx4rc&UE}o+He)ygi?0=jK zunfvyc;Q&*oVk6we*pPIey}~Uhr@g4@DaxxggngkVGen)F)>bI{kK%wby2ea7rQ@> zl>U3(%&CgE*joXQ=ZTvzeVXDwc|LybET<|{qipcp`LDpiuCx1eF>%Nr@`HVk{eIZ} zaM*i59QQz=2Vwg@OanaTD#)LAN#|89b{16CimP)LR@XUIHB03Dy5^|48DbY55B6V} zY%UP{AN_g$-1(}1Po6l*88>^TGgZ!iXJ2utGk*PYXUu##ho2;O+80)W0^bfLO-sk$SC zy#?qJ&X=%%i1`Az5k}pmIOrGJiM1!&J6Q6^{0zGq@9*F)KIc*J6#N72m|wvM%%vF5 z!6&SdFt)cCXUFf@z4f-n1fjRet z`6vgOA`h}hn@~5xcrRprWv!Aw^a1;e*q?!&&h;$jFzhRp;sEQNr=YuoC4bNZx}lSp z|Hyyn1ol|HdoJEM(ji~Ku#63ZIC#f*c!1k3!}?0~fg5@RUB&oM9e}>&>;EXrGJuEf zqYaQh^tE>J3Z+A@dChB-?o(gj!$GgXyF&dRedF@iZgnslw0?$QXTp z^~S7IUAJ864|N$j0i5$?{a3qaxmp8GmwoLi(`8(kBJbr-m3{3Qaz|KfnTzF)Yav&= zc)7EB!`05FZ8tb8Uwgf?;;QSM6&rUb91CS_sn?jb&S0(ozzd9@7&F21&6_u?u@Gx# z@B;U0FqU#0L>y}@=q%o`!PtfVgSh~@j5x}GzrYO#*`vQSf*F|Vl7ZD*QYALIGz#F&Dy2xAU(1iFfGK8}OV^L-NN zF4myvCvjj=27PESZ+W&WtC3dQtfJL^2>$1gbpxFzSEE5Gt1Lw`7qyG#v5kY zI?=0DBKtaVO!NAHq5dH3&GUwd8}i3EhdBuIBF3I#&Vc}1EDYza!8-qg{Jp$Dc+pbP z2hoLEaW#wdHwV0B!gy)xLRcB%Kpx5yX6e#p4)f?Uk8${v6Z{n-^X2lMi8tR469;`e zpY4E;Jjfs8FxDj7w{KVT5%-bMzq!AJ{)%}E{T%6#JLW3bP)NrdfU?NLJixt!C|$x_ z3Vj=_{%`XIaq=WntH%cD0(2siar469kcK`7c;c|jK^{!YZr$qazV3QwOLnVTPaw~m z&vNt^3I0{`K53ooB}U;7tJ|A~a9ACf_tEz;2SmxrPS0om*=6&^2dn=>Z^;|_;B^>( zkY2l_QohSqrN)NZ#lf+`h6SD|ybZDzyY2SdmHb=Vb~$j@$Tvi;kTaPj(#L?y>n@Q# zzs%F;i5EV~G46$77?9(no0FnP!FO!vms*kINSYAspkj?s`k z#(g-*zrCX~*Y7F&Yg<~K&TCqnHW>?GBcl%Dr!KNy`rdq$VLE)~!S|*U7t$erto;VV zVg48_`FnW~#T)XEy!4i1Uew$Q{1_WxV=h}&>)dktTXOP;4%qVFwX@ZM{HY7D!&xuu zqHm{r+l6}Ryy-R!adGeS#Uy{)f8dkN7o>qVNT)-b>ExR?4`HUWEc4;7T(#19>+QEW zx4i9^oDN*u-r;meKfl&9|5NtxSBX8v_IYsuf0)j(Uic{QjU&u-;$lA5b%QbXqt3w^ z{~>?U@0F{UH{=<8TNZ?8em+?2k#XI}IRG;LryW^mcZB@cuD#T!Q+7SJj9EX^Sw6~V zdGvpb!-L_l1{|#MAAA81D1R^Cm`2`t^Oy$Ts}oH3!V>OE`3?u=PQPu}wazY)J?46E zzh`*EhRbp~O5CiIao}eisF!tn(^=MrWjf@KemEEobIxGNpL`=9qI{MkZ==c~on^>> z%A}#OF(Ch&Zho`#&#%A1w+}$s!@u%1oAiEz>^*S*$y+yZGtJvhwu5P0 zqt3yUzn3Qn=i^yezFnSi%E1e>P4-pU?{B;P?ate7e}~V#^|srco8P?8dHoGt&UM%C zaWFPqC1>!ejdCtghrMah1NgOzf@=-RQk554=trd^AN#o2r+u-G|CASbW&4Hlz2)t) z-uNQnb$eTz$Ui7|TMrP2E?j^8UXhKS|A9+8JzqioN*|VDUs8YXmTh5K#_2O1KGU%O zj`)jl{YU#Byzue_arR$3oqV%l>~e@RZMooED*N`Z<*^2A+}xz*dW`$G+1iPpy;??r~63h$UdtC_Q%pT(f z@^E*DuougFP!lG}Zz|&3m@)Q}aOR9T7-a`*|0jxX-gGa|k%A~uS$T2i3wvQ0jw+9Q=CQ2pGk^J|3!M!+^zXpDUf%1xW1+}jzEQ;WA7r_0 z+cx!`Xxsyb!+Qg;hat26I3x1j7jKh25sWDq15g+CBajbWLmcBD?x*8k62=O|Q3h=S zO&E(nE7EaqdB)sKtltlSzRs23XTbR?;IIz{ANLnwqvPHp;_&%<8nDk$?sCarDQ!d^ z%HmEW^@MWw#u=sz2HRgJbN}j^Mb4simpYg2l;1zPVoq)hfBoxUulhImiGGf@lh@FV zqj5eAS>W9U$Q)}?)CV2F{W8cMa$q~4gU}V+H^X~5^l^rS@L2iQ3j9J&%YUw_2m7C> zk9Ss~1E>>q!$C)sFX2lhj5u_Y`3R$ZkgM%`)8fe8hG*QygY>ApLiJ$ms$6@GGyn4I z&A6fOe}J!e=L>xb{T#AJ8f6Zic^!Bj=DcO1!o7WgI z0vSPGe7_NSm`|WHNC#X#9l)J4v;nfjdo$?AaOmIgdG7|}-m%~)@BZ=^F5l=ZSaFro zA>hOu4Bnz2U_8bg06$EAkU98{dwkFj^h596Pw+Mjj%koJstc;H>Sa!u{pVX4&Zr`&gkb3-cisZ=UeCN7YkHi{J7_~c^E%#7^=saxXjqNYGZTjs>as1<%=oz`eF(fDBJMI1!|m( z@`tL?HI+L2_v>E@K9v7K`!?GByFZ}##PokSj>B*<{<3S{uJ9b*p?${7O`Pd}aVDtt zZ2DjAGtRoo=X|dU?VbDFYG1pCiX4Z}C^J;CbmAu*cu{ho`iaL^=A6rcu4*@&3n5J$ z^11+1Nyjv-!}|XTZA-42N(r6z^yr1D)aw?7)xW4_L(Lw^;P}=RHIAS9&uX0LzINM4 zj2nEoeq?-IwslLkeP!d`Y&(-m@_YZT*QM!yXusFd{@U*>RO4~i_q5-zZ?9UvX8uL{ zT-PdEPr519b;{#I%gQiH3t{Fdlgz(L^v@oK?EAmNioQK>)OcBz{$I|xVi@SAzu%0T z+neWAt8w4*2}eKk_B%Iv`Ns6}pD$D6^zUw%qmm$xw1i0itwtW{bM*SWd)RtKuPW^M z2e@*Hv!3oD{`r`A$aF!gZTC@v(d=b+!r;j^zl~Yv3A;Pq-US z@x!qk;aHCN7{B2Z9YTHMB}n~0Y~XZ=* z4OXT-Kd4gU+CA^o2WCi%JA`s?Xi6hx!}i3Br}KK&@&>1KmDN0{Q|(c zzHiE;&kn2eb9EZ($r|PNKDx*k*OAEoV^7vu=fG?DrNADp$@ykZN7j(k(4n#|GVHX} zxRXaHmrCVZ$pbHW40!JY41BQS25%?>q?iBqWok~U==q?}CrqjSvdwzVI*`?VAv}j? z98mQaDre_cyxDK_l4t5`wMw2jU$4;s z;>z=ivJok`XnBqkS$g}7Ri%N}sgUNF)G%LKPM+U4@-)7Ur`Y)Rty+%zw#1WX`MDcH z*ARv3E$@twr;#7!Nj(03+NJxYEKzj+bEbbXPN;C7^Pm!I?|%ub$dG<$|Li(ti1a2I zGV=CM;Kd38ebjz5v`#hZWH9Qq@;~bSX~Xq3{>+$4wI)0~TKk3Y?VDCw|FrRPj^Y@9 zf$)TM+hx6RnL5;?`nQBQCvlE4*}1ukb6kU&>$)T6Jit-zFPHEuUy1QiucI*LX1=HA zs3)sdDSoBDuh$|uzrxH>#%DVU`J@^2V2&dGCq4+OdWO~P=)xf`z=Q2 zyK8h3`vBuC818#{p>=+jBlYS zI=bvat^4IM`@r@&rS*aBt-&!3>ul=K=$L&#R8u`0*QZj;L^Wuyy(K2R0Z(mQzbL!4 zad%566Z+BjnC%6zYVD3LMmv;#kLi2#ZOHUnw0+)ti}vk&#w)H{r{*TqFI%M2%l!}f z+a^h3z562g%YA^paufAIA4u0N5%tktXS>Khz#kBJ(*I_{TYT8OySb&axpi_!wk6xt zS--h$kDu;>vA)7f?+$y|{*-Ai+fO-?uKsO*SW60}4Oa!yW$#vV!M=~|RX*F#_Okss zY=*A>ZGQ>!6aH%obj$W-^tlS!zfY1#*QpW?lN8LCjjQTA+uB+>_I7k;chOFn1u_J zrl8*yOe#60q33cnu6IA8{oy|_`$j+3e$TCXUTEn3`H--EQn%u=lrhy+Qu;3%AM+b_ zHQ6elvY@AF39%jAck4FoQiXi~u;SF~yR`T$N4Q=CM|>!Y=Y~`Ka4bi-^h1UZfqJzC z!gjJ8;TjAa@#)%7pC69p2-j`kh>vi0o#byP%Mq^Ez%>}(h4a_Pa)e7iZ0HNXb-)x; z>*cigEJwHo14n!)i|2+@{BSHsxNZYSd>RV>cc>uw$#R72HE<2aC)`~p`QccOaA~8z z#7DRX%lvRGN4N$9M|>`vpPwv8xNZYSd@fwM8Yy!0nR0|1I|82N3BT6B6EEA{8v)Pq zgzq-+#LIf4;8~vV&lz~)O`CetmY$J*mM47XX)`VwJmg;#Jj)aQb^}kmY z2A+7??x^}%p78e=c;Y3zJr1#cmM475tOtmf^+v(7JmJ?Gc;Y4f-4XP&JmI?yJn>R~ zQSdBJc=DHc+3qlSoab=e!@aVe4V}tvAs+UhUdoaE!CF5Ykh@se$HDGcyUYy3 zS^W?!hG0c^eO2$3x2krHpEO6E3lR?&Tac$Z zt1)=E50)MohOe_u!<)03)bFi0v4{Iln@ZK*e%DO`D`z$I1N&evk+Yg3vab&py%$XW zT_L;!|LjLY>s0K6p$Xo!@}E~LzEnJ?_b=$%c#4g0Z_<1ElTq zGmHFk&B@cqFDFl8a66>M7xU<4@O5WvnA8SFEe_2pS0;Kh9T6`r%e212HBUbeAZ!nrKdM) zJ%!$jo_?il@envE;aH_j^sAn6J4{avv?^_?S6GRyyw~XI<2)nQ`|w@2nf=!F{`rJ( z>5=9>(OB!=zbSC|ajl;Rz8OSmptUrcw zY5(8-bde6y)$>j>ZW#J(JT6@w+Z(r(EGmWef)Ki78pzS5Z+O}*2#;@a{B)5H($)Pg zO&964vAA@}0l?O__MMHbOq=$ac74~kWkY5NrOc8|nK2kGj1x2B8q0>=Az z=xXce!~sWBwxh%@_TPUGIbih2Yo52_0^uV={B)5H($(-DO&964(YbVWbT;lR;XuTL z@K-_?#zX((>Y;Z$@s|n4_7C&ZMLI}V=DnIO(raUI>1x~ExodYHW@Q;S3|+U{m6-T~ zi1e`JO(*;5A|0eFyE1cbdg>g zl}p#w_H4GJb8k!O#C_>+j`KB35543361(y|@gt}D=^`DZtJly)dTms7dz)Ia9s2DA ztfo4oleLsM++Y2Fj`OfZmv@|BYFC~ozW;PTU8I9__1vN5MS5*iHeK7YZ9B7_+4jA5 z!5H!BA@cIlwLAt67TNStKV77QbalU9(?xm-N8hHarFq+S8SWc9w->)m99uwMD_Cg^ zzv4_kU8I9_b$vk7MS5+NHeG#LO`R4(SA}Q(y2P$LPyEPmKV77QbTxcX(?xo1R5o2( zn_G6;W#Y!~enI!IMG*iiBhtf?_n+mbi*%5#%!f2xq}Rq_)76*N)NO_?e;w|;EU(nY zem0%$r;BuuuHJ4<7wNSTYq~HJ?&|Y8s=WYRa>XI`Q}IeaU8I9_^?X> zJ6~Rat~GY$dE!T2<)@2ukgo2JXu3$Rjmn*uv#m{SeKS;^mvIB@!|{PROxG$e3&wu- zpW~;CbdavDk7~L|uZ`H2m!7{$n!ZxCA>*NU{#s^No+rNPTt8i;gLE}~Ow&brZB$EE z)~s5*x^7K>?A+`XJ1z0tri=92hy(KK z!$Ru41?Y-e=i6;Uyy7B1U8I9_Wj?LxBE2>aS6=3rsD5Xon9H(LZ{geH4kq*+8`mCml^yUCfAcQWt$G)|(l+En4q3iv2B_)Kj&?<{4v?fYh5)Zc!09W}+SJWsr0x}Pr6LArWAr{zU@ZB!w2ZE5b< z)gl6uW4_|Hf4@|KuBmqAdE!TA_~{}Yq^tWLO&964QH9Xek?oW>cD5D2A9cQ=>n>j< zuDquC((_05&+^knI!IU7y_zo4Yhw$c3xme4w)Wy=1-z#lx;|)EV&c;y(!-KB&GFMk zI!IT;=QUlV*T%7?cE#el4HyPF&bMv8M&7Kl%f*R*tiXMM^Wq>eWh&OIMDf`j)n)9mS6tsnll+&^5}gJWqU6 zm7gxsLArVkU8L7W<Uf0y|D!H{%poWe;w{PKiZ#>H+JOhe!55p>FWMhO&964k-2oK7w$@+ z#>M!l(0SR-AL9lKhW5YHPZ#MRU0wHUx=62$(4|W+GfFx4BF=Bi`4`r`2bo~`7h3Ur z(M|96(?vQ+SHr()x=62$%R|?0IjC$>UCb^NGyXneYOd9<$2h7w=j`jT^kTZ?_>Ve&kL+U8I9_bsyApkzN}I=5z0AerL90yIm%3 zywH07<#7>7x&0sZ(?vQ+SJxp;7wNT8lde`=(Q7GHQX1<*W2Z#jXE@ugJWqVnNBwk> z4${@oqv;~OHY(DEo7nj7K*z3D?x%}%kgm)_nl937 zV#Xy`>T*xXvp;*Q@Nx^ThWb@Y6*)NLT6+O&964QIW3Q*VP+Uv`fT~-*48vQRm1N z@lmBV-R-A~bdauILl^0_QIjsChfQrQZSAFsY+V7m)O&Vz10v!TpZ3#5I!IT~qgr01 z*G5CS^eSpgV`rmXB7S^k0s9N@1IB%he8x`~=^$O*U)6MxUK_8UF1x@kPdsbr^4clhv3+JKo{QSj{8(R%G@fcph8)y_+VH7v90gFiPKBpJc^;_CM;Ui*%5#)Y*uahu+ zZ+%0(kpkh0!+yF*2kGiM&wS^=$jwFgageUkuG@gFe=b1RNp|IV;`_hpr;Buuu7;VKF4AkG3ewfNy}4;etGw)M7tI?7 zU7HKg<^7&yUSyKF=?Onwq=R&&R+|20zX@hT2EP6Qwx_&6<4$!|=aqzM3 z@II$_BXe}SdKYWon}u-2xBYabOnK531xGvu=&Fx9ihwTcZ-AcXB}||76zd;((oYxZ zAYD0phTdG<1Paj=cNFo;3vvpRmyjI$+5cTXUDUfAUFN$l)K43+cm9(1V6%-S-1h=b z&~?!0A>yD*KQaoMi3?@oKAXO8(Pii$UA_FCjp=7LUN2oGUt|-cX!A!4(1mXa$9*cE z^3z2+NLLOI>B}YPfS0bmoG^o~eFf;c*s42U^vKgLUFy5{=DR{qi0q*X-LDS+zL0)_ zXl2b6@^PEXR+^97wBTpsI_mS)ceL_yYJ0RQ=p$a(72q%VN&cqK*Zk%8oLG&;UvzPq zV+Mz}Xw&h+U-Fau?M|ETWLbKg>yM(mV###0v<)6}k9FQc{yF_M{3L(V7a09DdW^Do zE?bUap`}^A@gj$ja?KhyGm2aKX+-_-U(7T0^)~wbfU@6FkiX<7`P)6(=&#{BD_*sD z{W5U)I(;2*P{v%gg?y#Y^kc~mEKmOKzHVpZu8#Wa^KvnJMe$qHpCwOA;g7VGzeArpI6KQy-JWXpymyEC zUFhvA_Na3M@I!sy+I-KN-?wh~u>O4ye)rn`zC6FT&F@}&sz`l8HlT2a?HX|}kwcZc zPTHv2h1ogtnE(6M>G678e$IT)JDt+Md6+&q{I?JHnD1II`xpQ3fst-Sk3@)v-=uTjRG#?>cFOa?#&I20q}$-aq(f zKfu6;-?#RrmH*y+XLgMF&aCkXQ>tHn{+rbIs+Wz?ejz;DXO{RoZ%c#UnN{B_H}cEL zbC}T+qc4Tp(_i`S9*KXqUoAZIRD%8x_Wck2g>nMQubi45Onol@Pc2WDINtqS|1|Q; z$Qk)o7TKON2jyw-c)ctb%Me+LQvgdzWmH+pfRC5dd z%gNKokMbm7+Q?ac!RDb<>PC^@E+s!VuI0H;7zN(q44(454a}2==kkm*A9=mb4a*(p zh8s?MdbA`jt2KA3hYU{*k)Kw0+b|_d6pWB3vVb?Le|j*Oo{4tmu%^m?cXZ@=W^*`~sUgP>L^>1eVX4ZB5U6OA8J_&v6 z_j36A8l5t|;rEt@iaSzPRR((CGKc)@x9$mM-@^Fmax*WV7Pj6>rT(%{uiLg;zd25R z<;D|(hvP{)3}4qfWIVys55G^6nj^Sm{g(6X-ySdS_eu5(-@rfn@%|PG*Kgjm@{gPK z+u!v1y~6l5o?_$6D)e}9_yYg95rt=&=l39@%7mpK3Hdz>wSF`5qdW;qebMpHiwxdj z<_DzU_h#Pl2twZx1vw%P`ajwz3+{g6VV_`}`8t>XwLI^T!uTzDnN{R>AC8obDT8B~ zpzrMu?-eNf@j?@gH?90*MxL8=f2c6Nji=c7_=}A^&xt3`1D`5w+*`IhxE`M?gtFhC zDm)?G`Dh4XUB2Q2o>xA4qOynSAAZ#QUS&r%y}oI8%dXDSn$(c;-PV;W$+FmZ#nN?q z{#VcM81HcJmG!+@#$E6e^C{eurX48PpCcn$NKzKVG73IGKv3o=qKUn-`DE#&tK`0Rq8tg zIsYYQ{`!%TKgjbue|e*xzsBFJeg0lC@Z-tNUj`4yyYv|$^I_N8MHDb+tbUXOFnjEFbhm6y2x@Jz^fr{*ssznnau)cTP&a@KTVj=>Y<>)g`*+v^eR zC+QUgbvq0%<%zx!wjR-=0U=)^7~h~Gz^UZ<$)jW6u*QM*bN$oEFDK9M8hM8G(}8ZJ z)Td7}gB4Srqow1)*^ghIXGs4nlL<%5QpxjEC#XD){BrXAzLBSqv(2Z0jz`I}P&@qc zJTrBpEFeBGq(b#gCC^Wvpz<{G%gOU8BTpk|&A0RGQmM~8;_?vjZ>soyNxai!yc>*? z=R?{{(MD&S`6inl#`28+cjE3$y{8OLaw7JV&_ChOHw%xqC#n5jU<69I@&n=W>^1g$ z!w>bkXl?rk)OwY^fcEP%{uLqXl@e;;x|QwE-J|<~rXvdF<;xduoS|MJ>1@N1aqg>J zQ2-I?Sgkb3f#kj7OWz57!1uV%{vW#c=z0KT=pbF)PiwkJuZ`EHtJJUEfv$_?zBK51 zWds2s(}UfdTzu1y{dAEI(nY-^y*WS=u<6<^H-g$q_&hx5I>XTAuS2FWL(ouvM&4M( zPyKX}4$?(n(p&!SulV){ZMqtpI-9S{5~{Gj%=6yaCxkAHNmq)z=mP`aV=9czEpg;$ zE?qc>;5hKO@F+|jHlP=|;6;aW>n1Y}=f>qDW?VMowMP6;G7f)Njl(*Qa~nM_|6LM> znFey)djNyiVK0*WIPYU%2~ z1M!6CYkSwf{_2*y7I5-7_!oSNTYr_y-tkKnM#u!N{4?SGy!R(&UN?TQ=3_I3{haN$ z`$JT#@oUmG8`hX#wB6DcRW45YZ)E+|Z3@y?`=D`vtup(2-FZ*#%NV_+p0aq_=r7}g zwW3NUwD7${Il#l|Nh&758v$j9s6{} zy9038r^LGM00{|c9Q3qX$`QUr!YKaMU+%$t?|bIF^{k99K_YKGx$BVZyNT1!>EB(c zJ`dV*MtSu=9=h}3Eq5$ecz*ERP1U2nxv}b=-~3hOHyy5jplrg<>ZNz}Q~~n)OI}`; z9{a|iTA5X9D8dhKZv5U7paPspnpLuZK=?7of`#@#q z=xsD<*JEX1Z zY53mjs=xF9u6giJix(++7hJirYRK?=t9F0!8pXTMylV3U-+rjAy85y&sQhatzpHBH z-@kb9n(sZ+13drsj09CbT`Sw*0{Nv_R zGdr*T!a>1t@H4}2uUc|=?V(5a{30VbGP)Hf{{OSrYyNpDjhp6`mlr;MxU2d{tL9gy zzVVlXfBNmM2e10!HxE9sN~_2=B2WztO?dFX>HE9rE9 z>#FwmTNhiOLcL|FjMS+6d~e3ZrQ4zFMhV7KrhSiN{$yKC7;&9u@F4Dc$}hQHotvhf zdP(RAq3kn(;Q2Vu%Nu&lek%8g&AqPP9Gk`*d&Af9Hs10XCEnM+Ja|7y*=0t4IeGRP zJu!0D_1|BseIvg<%Tw+@D0$)@Uzh58z+Z|yZx*;ab>n>hy|ODyogS3u>x?}A=~A_C zQ(=4`k`f}z)^Ahq?L4zi`-M;(`1q|GOS#{@e^Z1!jr?-*H2poapB8G|QOJ*4ucB|l zbxWOv&*SvIFPdkDid6X?El;GK2v2UjHS(i8Nn6^;S;h6(D8U_z4*p<&?d>c6weI&1 zURHP0?X%1{OsH_5lg&pCdie;u-3OTEX86T{3r&-EJP`5BCFbK*(k zAMZ8N56thl-}pe;DCP2xAHcg!P`(*>tp^y~N3Yke@~q+9yb~jolc$kiPM*)0^_r3M zU{jlKK8W8o_kLr1nB%KtPM$`7Ie9*7E@L$eCpZ$vxULZ+WM zeomf7emQwQXXI(*tSO#ZmumQslAn%`*72^}9{H#w+-KPG129dVk7zF^PsW*Vvgs*# zo+ffJ_o7lK3&y90epFnvJh2vn+b3AU@-*_JJV|HT$eHoM@}tJv zZ%Tvm$@7n?&lv4;TmIm2&_B~7gZBzt3Zg@hXSYyHc-|}c^?`kvAk?ksL%t{KUcvhR zc%t&gpFDH0d*5aSQ}fx^SAVI!rE=`Q-u)mD4Ee^!2mX9xQ}v%d{4DnVQ*ZkDp6cPx zZaVbF^{;yfdz1A7UnMa6AKQp~1*yvg*LwuM?2SzdAMmCHR}TL0Wi=BPp3&3%+}|^R z-}t>BS53b69|z~YYx5x~d+3hm-<)}1^&2XGdFXDmp|ZYd>w{HK@2URtXP!MMI1Uc^ z$(u4mGCL2QKI!@zX+zB=PxmbR;agg(?i;(}E2*CMePPMZzkl%Av70JiJ8W%rs^{|A zXT9&Hhj0Drw3=D>p7-$YU%0d9M?ZRF?Sj2iA9}^FM%JD`v|F_S?U1Ic=glvysJ>&) zTMnN8{JJ6H<`@E|5FMl~BI5N5wFNXgv&s}Q!lICJ59O|kbd+>tlhyU%7gRlDDeFr!F z@nwhp{PVUN!hP-w|Cs-su7@7HyliiE^V)rfklyEe1!f=XTIs_wP30c$ccqPenl|IL zTgK)|a<3rAyc0Z-+$%`#6(sixitFTR-76rxN5Fdp#KQXqyg$JA@%jEezX!V9|+zYAwtIEOaAS|jPX$UTRS{~kX07k00J@7#kQyjS2& zEB~p!A6)SobFaYoN2NmH-4tT();J}A!~DZuvgy@am+H20VcaQQh8 z`rgx7y=Kv3{EVr753jyeepjr1TedaZ-rVG^E;79Ax>m(Eyr;86-b=vyIj<83zfl|> zzJKIZkKSLJ_dkrUOS=Cz{la}Op+}Ngo^-h-b*Ow~VY<|h1>1lT@%``8-}mv-g`#}_ z=**P+{!s*q(Bz6=`RSs3NEh{vax9-#n66^pta`?Lw+M9g%J0p9o?Rjs`e-!YpA6|% z$W~9Ux&M|n-_tqrA1+;KDZ%`22olJhgjD*dWl8d)o0`b8n}6yEzR&NG-|O01vqp$4Jutqo-GOc#i_d{a z^n3z-sr!Lu-pUC5HZkJn{Y4D0zCJiN>2&{u8q< z>-@MH4=R48zuOpESrLhcN9*<2f$!WqH+Vlw-UBx4HKN@2#zxDe*Wp4?G3?o z*>)i`ZS1jEn|-&mvCF*pykRl#j_HTrucOa3o^G`0(I`F7&`;lM*3HKE{*dj4_G~uQ zr&-2j)#WC*|L@w4MSnVgG}E4Qt$j~IvVAAvgMIR>y?<-%Q|*;vWX)cu}oep;Rt-r$M<{kz}E*X!V-&qE&+-M>q0 zyC}O`L#t}#pS~Z)G>#9tQSvO*4!=D0 z{jlE+)n5!bq2+1hmy_qmj698;HQ&O%fA^4D1MHUqcN*q$J#F6)W1RVxEc8C7EWX`+ z&O1{#%J=WEo{o|y#@nl8tc_YvYiQQQ`(b*8enQLB$S)_)PZ)U`Icts_d-ubz7J`eC zr@w#t?}wex@-*_JJgL!XBWK13%g@(8xxNis5B<)Z(Rte)mgdbr7Q*Q#^?69KZNd6h z-48SHydM_!-I>c@_o|GIKk|Oq`yZ*S?>_g?(~s%z&V1?HudlxHS8u62%!=Zou%JtQwt{zi0 z=h<7(hRV&as(RoRpZc%r|9J1nL(+yr*S~W9!qaZJQhxec*!j@etde_LyxBBRsZ@+XFc@q^4*zxfA>u0 z$8Q~XXvd$*Yt9V$?#%i=^5d6({6XdRITLgA?7!lc>W6>(-b&K5=0}%3@RA!}o1z?uRA!!;<@9#r5*_b*a?tvT@4a zdHJf?cNEql7shdV>^g7#i>WfMVJl)&l-cPFP;y zG<(jmA>4en6F$RsX~fgt_pf^=yynbGIDD@NXJRvE%&3BoZ;!#R7?Mt1d8T1p7(y#; zwH#(!Nkv7MG`H-Gc{L{wUY9Q{)Uj@9EyIK9<2wo?O#^nlO715}xa%wYyjxebI-4;0 zlC8cDhv@jx@(%}_xG?eU_sKu~P~I;v!T4Lmhtt}?Z(U7KbqS8Sa(K|J`gMy}FIv1# z6$<=&nOe66k|Pt6bz3-VrX&lNaKy$_S zH1eUG;T|Ytax#Goy)O}xTqvop>yGuEjjdZ6+x1pQp~@ojgR<=FeoGU_q@h$R|@=cMhYTUUl!~T&x_+5eF^1A}jvexC2{|N_P z1RTiyrT}a+m)_vGAbH3ahrEINU4hNzWv8lo&or41SV&1kgAeU9+G4U>fXJo_Zf^C0ZcYrHNDLb?t9w7$gB!}R*F_Z0s+ z5oCKGwvXl6zFq^*vS?qk{1jn5UY7044|ft_OrPyzd)U6Tp^NQC`)qhotpXMJnq&b}M~-u{Uj^1hb_K6v{l+6Ufx;Z%Ne>khV^ zZDrfhRy?H1)y?{*-R;-)mx}62^882p4$Gjd^aXUY5oJ1_EWys9WB1!#_c;30-yNjOk)p|};C5NWEpauf1#7``NPp}F2 z%TlA||KnfXi@CHK;a7bA4JxeXd`XCSMn$9#L^4Qo4O9O*;O@o`p#2bEit8BYIY1u1 z|MQhd`|+8NiCdmQ8SgW-;{)p5-R`gJciO6r+5v9X3%4z#kN&+~0NJ0vAZ!Qz^z@9{ zv*|Ho9p%P4(g%v`2U+O{Ve<>>KOhwnAAXb-^~3RT!{krU*X?unp#EprtV3|m8<+lS z$h(@XAn`2@fWKkRDkf3L4|g%hU;I$Btt&1rT^{2h_39H+80FI+*{a{w`;zvlmz-a0 zz3hF@o$9xM?7Gr-`}Okh;r!$CR?$n?4EB@LOM~xd>19Krmp1G3#KUxwV}T!xdP)Aq z)l2GCKE1qOs^WU*)1rVFpVEi*c-dX9*ZODso0Cf41a z7oAi+gpm=u#x1Qw9z2*gd{6q*y8iTM{q4x3+vexvqt^N`s;pq_fqqKQkdClTY^@A`T@7;OhM7(Fdtos3H^Kchm$>nZtb>#1Iw zXnY7m-VNe&U+8lpIM4beszIsreg5?e3g&}rmUWc3Ku*sL9_pDFhZ}bFN;k-j7t*ut zWIWU?i}k;FJtKc@J#*!xWko&XzT-V{_3TT<>De{VGmjye(=&tTXz5vRqGz!*%&!-= zz6DW0elWer-?)0leeHYW>e>Cp>DdnGnI3#pqjP#@@Ek2YOPhVfAg7X)AO~#yVmw%q zdPe@n)w6DMZu0rKdiLew^sEJX=Gm~#>6yWEwDhbY(X*hEM5a)$Y(EGvW5{sssD-r|5G)ouB;A&jDM`j0d40?+uciHvEOWwJg+G=|Vur zIa}4Wm8aoeN^18z_gDS?()(3dqGta;m6CUDtC?PT+Qw>@hwUY2Q3_9PY%pi8rRs`0 z;>)8endBZZL>2R)ZrFYh9P%3@$>c9|Ma#m~6-mnJgf07JlF9SN4@wyJ6PGB@b?S4- z@-?4O=aG`79+YvX7qk&i&_~Wq-Z5`lMfd{op@dIugFpVYUZY zHQur^6Sj!{0b_;Z#AxJ0aLp!@UsR6-hs5_OiZf{IiX}(DQD9kDf-0E zcxJZ#R=VvwH{{0V>hcn9eCjbr*Ty?j&yIg(rt7V`J@nb0{_>w$aH1dqJtxQ}TzebmBXJz|$o$w)b-pcvd#IX4hv+*G`Q0r+aX3kucX$63ji_pVjX^ zpj{bBrQH4@;V}B_cO!_XYl4w_e=5m?3u=U;*4{#rqQFeKQ+J`mp)txAE=#Lh-cdVt+o6 zb6OCxUCj~>lZP$mS{XwR$o?bm(QJ%>ljP8+c3sVuEvfC3r%s&~nja(4JGA(UztI=# z_lS(=LifXZf8%JrEfoGrrFYGNdwP#$IHzden{S8Fa-`9>!;C`*!n8m`_VqvL3S#%R zwOG0c>!pinUcav`Pv8>{Bpi4#aiC0pok!j89_Cp&1jjG^U9wArIa{}G#a@-XPv(w2 z=6$R@tV3Dv(^ZZA0sE1A)ShpO*|{oi;lX=uk8_{R2LKubpX7B_9g%z8@O=eL1Z0QN z8&)=M+9)YVCqZAmZ~uS4_wf$=^y1ZV?D6JvUI>P}s?(3^c^m5cfa|Jr(b_)_Ja>s!k;XDm$AFpg2d0q0k^++`%V}H0*RwTx5aaTs}TE=Y+-qMY-TO`Z3_I9Bd;#$a!N7*gmcR2{B>Ooy*?k~x1@wF9H zhtZp>v4j9^7Wndn+AU{)_Ulz}uu~YudZtfy%VEoIG4r^+UWL?M+l8_T`dTC0^=hwk z!=cIb&X?i0H#%Q_GO=5ffaCoGf5Ti5nsy8M8)dgV{n1@UmowFGdw6%W-D32@)&tb+ z>V8oEx@G)!o2v)5-O`=dEkPkhriAGLdG80J-9rAxwp+~m%B9#XyW3N8-ZInQkoYlo zSg~Mkvf}+5RsA6Sjl^y#m9L52QYz;XxP$`<2L_e{>emqZeBR>S;|*`WJul}uZ_yvk z2}cvOkCOA29H->G<#EeyG4r^+UiB|7D4U>f+b#BaOZsQYx1V$DFBkxS!(0%Mb_@9% zWw*pWZ!vmd>j7%+54)u|v0H*dj7$mB0rovV5bYN7H@4kk-sdmgZmDZ&+1m<##rrv`#`N@e6T78Uz9x1{shmsT5)LFB7+4PY?3P^B?ph|7 zq<+z%lzU>ozjQ9%G4a_7h)3NMJIk#yECf8pDV)c=-O_#iY9H-pr6;jl$ix^v_#5VeptM`a-#*(dMlWnVK+SGn56WM+tgzkE zkk~CjAx5Tz=>U1}2cq3V{>HXj%r{|5v0K_&vwb;miL_hx`AO^Vm>Of#PYsOS;`SMm z;gxBz@2>*~(g4%BR(ZJX(!S+*zx(_Aa6Z7+f zb6vO}oSK5?K(6{ZDUp0R2;Pf}{s{Yac z+;Hf$fBoPC4T;@i>t~)g_#5VeAhcV^-zd99AdN2Ldt#%b-^(|8Ve0{EcKdoz{<>v_ z?UvreZqclY^*>Ap$a_Bm+AZX7Y`bN={`P+HcFUs1_8r;Q)YRGjhQyCW+AVL1kE4{5 zsvo3(me?(&Fb^=vc}uCBOW+a?Bpet>4xE&H2U)G(-L+f)aDSAbp_8D`rsF*^u3`K2 zyrtK&Tg*IeuUGwx3$B@hzHPVI=Pmanc1sZoQ`~wL-$5pSqwJR0=PgDrY&}5ZUEL4L zUlUi@Zb^S5dA~*TD$f7n^Z?&MCVykwEz?W3TiP41$M?kg|My#NiNl)G%V@jh7XxFr zxP68V_R2K5C&sx=`{0q6KX#ZrO#Flc2?r7m#NmMZJ+aiVRPL4d;JBRs_gmcYDXLD4 zRo*B1yd|t|52S^sr0*bm&<)-_v7>U{@+-@3G4r^+UWMJ_UdE$rg1&9H*ze`1dXsx% zK4r=qvFB^XgFrlQA%COnme}v*8@;gg05!Y)EhvB8vch&tLt?iCg&3Jax!Zmafafjb zZ*058{MK>t=PgT`TkxZ!r9b{H5f7eQJ>jDe)OO3S_4qg3qt*Rg*I=GYoTzm5w~P{e z2?r7moX8x&t*kD7Pb^2MyOzl%mHb}5#=tcZ@#VE!+$&5h?)m|{#m(}EK*KTeyOX|# z@w}xtyTykhA|l^Ge#Wv}%sg(dSFyNoWlY%w{V==bV)Oeguae(yS)14`5wZwNw%4hQ z2g}lKA%FX9w-~*!^#C=;(F460&GY*$iQN(uVq^;CZu>z1+AZCNzp?F>C8eIXz;2nc zD4X4d%VMRRxypDEgId3IpVTY?Su$}%}`@t?1NTVDRy;UG7Yl!OBb2NDiM zb3jcq$CTZ2YII|fgZargjDIDax2QP|$naoo?ylWbQlI~g5)5<_jJziX+r_+xZ@#(K z$KRd&y=AwUdE8#FLh9}UL-A2kf_|9Y;{Dyp?!;~pzQujO-!K=1r`by69}>HzRK5=8IZ~-@PT&#_Bpi4#a=>G^jB$@S+_j9$ll<@H zr+l`63&oH>`mfd3JaeKYmUv|rLiQN*erJOuL2r?X%rt^upEy)a>?k)t@9K=LjK0K zTdpkCZduyixVdOs#oOpeyX9@(QvDxR^H2J}6T78U)+TmKshmsT5)LFB7+4Nyy9K|? zlIn76cGog)T7J7FeBO1T?fhuFl$&9pH-tLw;8X;}BypY%}r7}0MTT10z0+(yQMd=TMA0w zEl`{uz-}RbW7{ozO14{?w{4gATT-*!<`x%h=A*B=y*1c|zNI8~OW*jHKqnkXI51Eg zI7=!zw!VY>@>D9{D=wIyjKkQj!lBH<2p{nsWHrYTXaMXMR;B#XzJqMv8S|ku5xFNe z%(7d|JZ`U7vAA$&K*dK%3Hr9(g5PiPeh0ZLv0K6f5s?P|hPhyIzL!t_M%gW~f4{}( zg{=puIgTFa#i(n){?D*khv1$!t|75oftB@Yw<`6hj=B-T2uIdVH}ns@-*zC&LZe^_22GF&CSJ2Ec9^xbv2B%Wg6A zxV>KWFD@vXpl{nP_Ib;biQVGUrTh`DL2N$=MZ1Okjj~%}pSKvju=M~nyZtRFf8Dae z=Plid-4YaHWQr|+#)AN~TgczocFTK8wp(_$bT;p5*&A$2%oP97;sJWMCwvrw+HN^5 zv0F;zZF1gHD(4cogaZi&29g6qlY3$(mfi9a%Wg6AxV>KWFD|0jtA*^A^e>ZpV)6Sc z*Qd50#6Y`+{Oz;dV)Vk+1Jv9fc1v$!w*-Y4nPSVI@gM;07VpQind$MNbHtUnVQ%wrE)HTOE{2lU|>0*RYqlABJ`d`5W7Axw}-mWo>h7)AlK=8n?AJZ{1sp z{o)QQeo|8Jwc`C8#axg|pOx4xrSdhgTT10z0+(HU_YbKX*6*)3)sx7VxvWw#9fRdP?vR?z4;^fk-{A!xUdzkRk_ zj9%D!fSTRDuKJUt1bw|2jeak`JF#1WLX1oa(*g3_4@A3#{Ecn594ystS>M#&xGOtl zZMJboM=8fGo?~1;DXI5a@qUh~F+DvZv0F;zYht&Q%DDtC;XuNHf#ramz}kbF;Uq-D35dE8#F_Ltq#kk~C@ zf`~{fZoP`{Ad|m+wp)x|*m{75_J`flo7gQ8G7n2GP7l=Yw;2A$wp$LDZnx}i+10tI zz47|6md8lbCT>WF-hAk=OuPasXR^WmQp#Fz$F|=I54mrIQHxocO4bViQ~?0 z>Arrono~*5QT+~b+Ok{BJZ`U7A$9jY9@bHKf_|a*Tkc8h7R|a?|BG9%!fqjd`)s!u zy|DEF&35}+Q2v^%!rv21e=B*vMe{1o|KjvO{eFw#Z*05eyCvH#JF|`LB^|UF$|LQT z_s3yP>1DLta>2mZEpDG-gS|2>_V-(W!`t`lFyrW}!J65EzWRyX(pL^9@CgSJ4h#$j zhNBwuUcOsn*yxz=p4bzQuk?NE*Tuw;JND|7=zC&PcjVkBus$0A@h2XCJhX1m5b^sh zx(Vk0Al(xaI>3{D{@uwjmfd3JaeKY$XE0?G^liJv{tj~LKazW5K4r=q(ekF;T|WrK zdt&5ol-&~hJIF>aY&}5DZeI_|U$?BV-O`ZQEkPkhrWB_Kuv^IA*mlcLO1E3u+B&!Q z!Eo^pEgl|xz!N?SL2b8;9T>YM*nY1}6T8J7+q`3nmq*@kkef+L!hwVX2?wG%pr)Bv zb_;$C67Rv_J#w)XDy^}}wkNDAIesxY+HQ%Q_%tZ$F;3wu#cuJnb#UyKjI=>J{a!x# zqWLSlt;_G+@@`1(iH*1H7Bi3A>s9dB<+I|Wqy&B2Zn3{7wl=X_T=o|Xfxlrc2uQny z{Ef0(Vt-G}=!LBZsJTDvmhQxE2?{YXB}@m{_xwP)_gjiRZ~1k}c1vsHj%<2aTicEj zZ5MY~@spDJpcU`us2bDL6BE0oRK6zXEv0fUflD}$aA06Lpr)B>^Im?gYIiM@OG@QC zZ*kYWZh3#mo|mKTmY4bg?HJ}K;}p*0)NaYW&r;Q|cFV<<-D2i(d%fCUc1w3+x7hlb zCk}lLb3qW=E#z;X?G~dKwjQ8nx38=IBq>2(FGi!^%kNF>mY@(LQ^ItBJof|9ZXthT zpSL_$vfa|QwKLm#G`=VHAwOyT9n*Hpa zfrJBbIB-nf6AMlYE-7k$a-+#TF_#x|-ZIs)Tg*IeuUGw>qFgftefzw{z9;rvVz;>L zFBr1tYsQ0sv|GsED7z*0Ju#yfwjQ8nx3dN1uUl65o>=!0TZZY$?y&0mFJ+bb@ZV3u8GKF%t{U89(Tgczo zcFP$h+b!F7@7!GCt1YVik#@_6gXHyRind$k4~*RsY`9mJiQSUeEkO-QQW6d%9Oy3& zsA)#M-=g={HC}fuf zY&}5DZeI_|U$?CAJ+a=zZV3u8G9^q0$a_B!?H2O4klnI$T`ILl1e*R`wK{KU5p=G6 z{kX$oOV`!4wX|fLI-A>C)6>FAl%DpH(m^93(-}S9(T^+`H^YfrFkU&xFD*sczU>kY zlSlg7l}cWct)4Ztsnk9he3||x8LY$LSl;&6)Gp1o?aX$z?@h06+mh`_i#XdhUn7FG zOBNshsDSjI_U@PBJnv{f#n61T+v3HaKC|--n|`$QWK#&?7sO%B1lQkB&jq@F)9-Km zEkszY>#Pn9A&*}-mslVympy<<%%gw{Per3mG0@C{9$E!wKVi8$u3Jd zj@HYQq*tO2Z#|6DC%zNQ$GEmnNa8qfs^UwKM)rqbPH8FKr|WTtKCx(dFqTTOeJq!+ zeNB6tTCyE3>_CLjzWb#j_TK|SfK3D1F;Cnn2*`7iDRJiV?~mi?t_F9V-KYQQd-eQt z;GMzyQ#jvP_AY;Vrun@?F#g>?ZEp@d;rz=&JbY_5TdM+q}O}(zb}RpPBdmbwXHqe6#MbU0C8{{x<(*sE7FPIsL1O zZ?JKvhm=PnbhhoR-_f0hCUGA4xMUCG7fxI+-!dpRkp&8*N;-wCs z>zCIiQ$OX!_H7nArIPZ*s}sY;72-j7`VYRl%t-a9P8m;7vg9G%2Iz( zZ;!;uk48ZXdQ+($^Ls#P8JqCH$M@fm?)90j%1Ido=kb{iKV#CpKGWfMnSA&u)NkVS zGbSB=8ewq_9-rx%YS0B@xd!c)!r)t&eJ9Dehhx&NwwArQ#Q)FUyTC}6o%emkhs+JB z2ldS8VYzKd&az`EJ2SgnQqg0{B`L1O$C|q$huSc;)!o(I#qO>u)uX3-5P@_a!WxDh zDuR@SBSnoMj_tq>WGD~EmXeLd00H6zwqZLPBX%|rj95ql2ud8whGOOS|9{_i@2#3% za%Or)8j0PzQ}>*6&pG$pbH4Mv&v)-3@#3HS%$vKq$Qub?dcM}+_5SAjgW0sdJJ=q+ zUX42|Kl_=V{Y3ZqFL&Tu>)#!p#uKC@;86Fw?bq*ri`pkmB-y-=U`}m~`?!7`{{%~) z_-L>9IXZdm|BOBNCxEdpGzTtDdS z-r}?0zoAR>clH!oi}yr!gX?Dn->I+Oc+ZcGzTtZ&U-NH#cifMAk=Ad_>SOmQHiqpi{5XmKHAQxEteSIyrBlUi``_W+lGm@m>WZ-3z;`zrJ7ApL6Br$5!O3FZ=rS8msv$-w^gR!OcE^ zQt$a{!p+$~TIHe6{u#yTYyZ<< z7Mbe(=<4gcUHJU9 z|2yee(zCNa8u;hz#}cpqvDNE)2ipgGv&nLNkF5Eh|Dk_y^^Gg|{N8$e@fZGz@%g`g z*K;TS`oZJ#pPN4Q`^A4;`TJ}5JmBheq_t#$o@2|;hz3?vb7j0jUdSmX>M^4xA z`Mo{i=l<U*@*Ne7qAC`Fk|NFPBt7!Ry4;)Sgch4ez?vsE2`?@-h_BmhLsh8if3Qsjp|7*fi z%uebOzJ2jb!BfFc!BfrRI-dH(aJ097_sdn?^)A}J>8SU?;3Mu6JWanm{6gCPFH@R< zS07o0r<$i#c#_@tGgx~+^O=IDjpQHJ;c0zV?~My+d%0-)>Phm;Z+_JqFXfk-kOy?V z^41of#FrKyT72n?|2X*4;#bf9c<@Pe-T0Hqm*(~TS}bRGC*=IW z!+-S2H$K(XGtf(?(>tApSN=rk8D8((cN>4}e17lef1>|Ozx=(w1$^nzPnzyt`Q;c# z?bDjqFSbuVjJ8u;JzhClB?~h-~J2ki6>&su>!j=8X za-K@w>DET!h0>N{@eBp>zu##emkby z+REma|6E^b{auz{&O^b#?;vT{j)K`W4ywx~9G}#_p#Q*rB?Q0xwC_VXfT~8j6 z`}}M$o*&-%P|tps!&S}O-CnPJ)hb-oJQZAheM3c}=XH6c;HcngBk96A-ul>Nap#M5 z&P!aheRbKu)$#do_5S7I@NVoxuU*1bP3_9{#@kons^+QS>YI9Bwo-o`t_qF{uBvju zTjihI9vt4CW~y4o^`h;ow}PveZk`WUH$M5pRrQXp8}Iwwtv|V=NjRs{%U`_;S2a%s zSHIV7T3&e_u8Ln>hpY8RU6en%X!{zE_$%wr?-ze{30F0>E7w=QW)-ep%y}xfTB%H? z3s?5*OTWdEo2q`vQ|Mlc+H`es+ z?(ELmH?@8|^zHv%Q*dXA|MBn#KmU%|AA8_()3YTv{a-O}rEjnKtbKjYFDmTzHW72*F4?HzP7(;!coE1#($9eHurBm>?4!e z(crLhcYnQT`+B1Iko!q5Ub}>=n%b4?jjvyYtD2`fg{y+2f~&LtFyLw(Z~f56R~~!U znTxis2i|YE+IasZe_M0gy}tYnt8i8Gbf<7ta8z)$@n;fWCEluMee{Ac(=OV+#&N&l z>cvaAs;OPMzWUFv!d1=Fox)YYQNh*OpG$m|c&i@v^xz2os&aRKy=eP-;{ArJvrD+D zsa?5V`Nmbas(HFoxGFd*xGH(5;H@6^iP3mxaNQ*NTuf}JN#|^ zW&7%{-o2hv{WSLcvfrmaXtzJbDynnvUrSo=yZ)!Mi9f=BulM(%=X$+I>GbSB34Y<- zId895f4%%e&wXe#9zM4?y^xlFz1PV9ne&V9W2yAePd%0M_Wf^sH0DtG@Sa*b|N7Lo ze4yft)F4zh+N-bg|FZw{Z~hJ|J^Nh5U8t-5Qh0~TZ}PI|z3+2_qv_!V98ba;6>-yI z%5<)+*L(g3XU=%wYu^%hW0QqD@A=W@_TT4kNV9u;`TZ#Qv-hKu*XiTSGRnYbD-Om# z%y<}U*MEWb`d5EiFTlK4?cR~|_1CkXs`toG{XL)Wulyg%M76K_)qW$NTm7D`(YHE= zU+t@YwXf$?zprF}RbKC)_QHGJ@oBxE-yde2@s0h#eB)?&xEM_jhZ}npjeP8A@F;?U5j;o&QPB(^w?R}noJlr6@?Cy}`XN!$_ zhM4`X-bbGA^&FQXQa6J6x`i^gnd|ub&ow4jZ0DQS@x^5-&l=Hq33k}&VD}iO8f>`OR# zu>&M*rOhKX&p{JKAJ6-7crUr_Po$T z`qY;)}YKl|rye#d*e`1~Hbdg;x9 z&mURy7h50i?fK33{Z`=fmkXc&<28Jq^IQ9L<8|ga@%cS}k?4M5Tj6uZ8M?&hw}a9- zC9fnOc+RaaSoG@eZ}+M3dBR1(Nj0whS^0+vp9@Yd@p-MxgSlS$wiZt8UzYg0@cE1X zEYEW%oh${V#b59E5~(GEPJKPtE=IH`xOVaHu zyrYE^nf{6o|1>ZoJJjyA54}ygYR3pj*`s8U*M2;7OQmDlcx%wIjju`>-qzqI~YyZ%kCzB(f0MMH}{^hZt0P4T8}OD-pS-1&P+UY8B?&P zcIA5IJKH_1JzMki8X4tnWVW#>0j2<`HfjM@_4+U|3zy2tT9rGv-lH&kEFxfDLuSLgocUw(WQP6{px zPU?vTKb3!&@X4j{QLFOcuCG4P!ik*bit#>3;p4MUhO)>^4EO75hM0WaA7%Z=-V)AE z?cCFX$&skkU~vfH@-22o4o$v2`+w3$9mG; z{k`!`fBBJh;YNMlZI_?@=@4#y?M>;)dB?-}rxI=+xFb|=lmXCw&#G{9mh-xfBi4t1 zxASqo+gE=WS{}LNO=~v3_;n*4C%<^j)f!ixY;lBn)7)>rgWx0%=3gp2R~Pm^=We{K zg%dkMCH^ja{^C!jBUCD_&b~SE_qQcp|Blt`bHl~PvlsX%_sM_%UqF`D4ClkeU3dA) zU-(5E&Y!qjblyArZ+9&-tx=y78?szw68X5aDxHiw~|{?$h-pIye8> zcir0u8ee{QyHAbJ6D|r)&Ngx%Cj8XHpY!+WN0V_C+~xJ6?dx%G?!96-xnD}n&;C?> zYFapoJ@2+f!gE0cPXh4FRSUQyY&aqqG^AUUHv#6x548K#_&njF;G~{d`?K;7lX1g*!lh?b zEzJYDzWl*eI4S&GaB}u91)g4i_(eT;FWSBx&wcj%ednd;Z#%bb>eXjDa6<7bIZt2A z^S9uq;Atc2e!*Ei;bEdrmwaTc%7eRJ`N0l6p%N&#C^)Gn7yMNIVWLl$#`jv42Y0>k zp%zYLTPQxfJb!=vU;X4(8OKZZC|TsSm(w_&GRoQGLCenGoifPxWd8f&+L1-VP4_N^ z5sl^bWs!UF{C&&06MNR^Jl1c^>-WLSB3DWl`TA8^q~^Ew@Wzuduj`|{sORoQ+t+yR zx94x~t*cRN>N#KP*Ox!s?qMm#Yo1<9C3)ldTL4o4R2#Jbt0wYcViqoi*;mzuW z@X4j{vA#O@KY!yrt8h|qQE*aEEcmJX!-P*Rg^ya52Y0>lhg&#txXfg{%k%fKWcbX~ zFpRpE=WpFF&)b2`Bc9(LEhSmG{ANtSUdYf=_Ay2WIEq8whKk^iN@WRbT2{+%gD%{lk7LGW3`h4N0 zS-U%Uqw}gF9AIN=}`?E%KQBSXnwy$yA zZ%?tm-W-3ubjYYV*7fBNwQwTLSMyXtaN{Xf08;>TmI!?v;at?y>!R)J(W!K=2+J&A8i51$B=TK%A==SSLxe4dJ>KbuBv{)Tjek6>2=ZeHIDo3DYo&!@<6;q zOf|>4-gtHuu4y3T~o}fHv-s1!>gjdS_BEdS?J4%+CGSvEyK;T?pxwh#lGi+ylDzR0D}X5g zs*PHJRlPn;%)+HGTdVTLuV?pYjk|Kx0+5B-MBoJ{_2hz|%0EoZ!lf`VA2Oy^{6oFuLj~Mr4)iP1HvjGx&1zqJ*0gW=gnGUHz5N zbGDnp%s8%R)79&mr`X-dHGa;czy3#$Zxe1V>&4H?#~*{MLoSP+P=nd zzdgl%wGo0Z9WrW;b-gif;Y2vT=Bb3>##5{SrT}Oo5&Am9xu~btMcdcQ-EU8^vqrmh zw*;a_^t<>|F`DaerTX2!i!wGBZC_)#^c1U^c(B(iH(R)RmmZZL zi21uvKM}z7ub)hHB2 zUp=RJ&kR0YU)QT()9d4__SIh`(WK@mQXM_Y^Z)DpRr~6%l)d$wCJ1(U24)PR zI)by_U$w9PddZ;Ib4nm?1mF^Q)9SR|U$w9PDh5|Qr?C>I)vzqjCHSrPSM966S4x1$ zYr$W=cfnu9=34Ks+E;%Sw7#BG{na?Dzw+Q(@2}cdf1k}D`1PDx*Mh$~7TJYA_1VB* zwy*xU<-dAPtwZ%!%Cl~NYM}n!&UND}TaQY?`Oh8y^jGMZ@AM?Ds`tT8`QJ>up}P8e zw$onujc39Wyyih=`upr!y(o=wNcqz3M}0SR=JB47>8Vb)57l{YvVAaI^sn|#dw*5q z{5s0&`6Rt>?TPAoO^<$ey;Hs8`aAvH+E`!AcdB<*-}-xPtzMM2@6_#Q<(;1W3m&iD zsoO{AogVAHQ$1h(tIq4alLX(F{>CpjhT#|E19I*jQ=j+p*Usj>v~JtHwf7Y7bQyHL zoskEVy79MPcysso{!8!p*1Lg|yNVmyeS`Z6CznQ%YDVd#J1#+%4r`EPIj=&R5UdEopee~T~#EGOmP_mTHp{rvy)hTfGY-r9VIRnK^i8y|Vkhu{A!2z_&RG@CDan}-Aa?hNPK zv(a>+j{wZZgZ_NEwK$y)d;RHP=Y_{V)!Q8H49APn?r1pcZH@mLrsy`vHT1}DAwWOvb5CK4)H45v+l=yy0?9`#3y;nBQL zs<+wZV@TIO)tkDLI2(?)hkegoQ+_zv9vnv5?NvwPogtHxT}0I=YudN{j&|CoWmQVFl+(dtzt;?K z9`ncGd~Y_H#$;_aT`{q$y%-JWz0G|Vd@$SIKkd&Z6DDiEn9K%ytoCdPH~`R&hGtn+>M>y-oG1^|`6n zIvj2FHV1Pe!N+9B%CN9JP4L&J5*-f?xAW3p@=}xja=bI?PnYxkDjw_t1)bvga4z`i zFZGn}TThOMvl$TI=h3|WX>W5f8|~>io72<&Xw0j!mL8dI_iqjd2kjd7YHqwy`hK_F z(c#dLqJ&nYKiHbTaP_fk+FR2Bu(9X?C{sGuqVs%>OqB%y-7JIf1T<}7)plGl2ivbl zWcO7(+A*NL@J?p#<_iG8zJ3Jjx^C|e#(ONA7M0gKnyL_>*k1VVS+hAnHWa3!Qh#U3*8P#?VA0#!n$U7S+&f|!=b2^K2<ukU) zvR4jbLS~Z%%j)!CZ&o1Znl7CCb1+Ws%my*19<7Tu^|HOq?fuc=4qYy0LqIgIn@5^^ zZZ5$SVC}f}7bm?;#RPUU{gcyMh88#JGuH9^(5SRi%7|UmA1)7v0bEgizCV}_`!_)& z{Os^(P@me(N4JK$QePLXl7NkV-g7dVt4PW59;->>XtFc(2GGP)PgQFjGP^UHPdj&= zT?|Htoib10Xnfr5V1EetD#Jg7lx;6($HQmFH!AVTNZ^y3MWjC28$zeA`uAGTEAb3OSRf77 z>7PcDidi;UE~=3G9-!+|u1vwJsAr~wo(heD%z>Oh*MU2yLNI|7Jk`N7sBnJ(hTa6A z2IJ%%woO@hf1%*mfO_Kg>Gt7hyHf!4LeS^E0S%6a{UGm5+~g313CnU|jLQ`SJ2>hM zj^{m?2?+8`S0fRYA+CcHU$gD*aJaKI*gg=$ay&eQ^dC*dyXXp)@*9kYha?P#PxHz3 zZ8js!)F~7uIG|42JWS?etVzc=w?qWTd)Z_qmyN&=Rm=?S0I^=|d2lmxMmRfwTGS*& zwl~@_y*6_08&UTn4WbsU8wy)O&L_*62pJ?pq!Db;n-4|rnS3)pal;$GOp|b`qaMWP_!>jdn!&macIG{koI}>S=Z&bJzL~PY zaxs~YVGXti+xx@5HXW0gI8=1cG) z_X9WKYT$iy4LWJB0BA*waL#?)bxFJra2XSugu)dPoEgU!&nu{ok+mi6er;`cy|~fB z_cu4YMMA0UbhejxQMk|H$rPZ737#{M-cUbV5FWrPuIyKuO@_O>qwSFil;Kk-61;SH z+MmpJ*bzYX;b^gB6{hS+Xb`;oh$3!9LB61Q?A(N2y58#Tet5f$SFOen&frB zVx5F09l|7MyYMA?a`kf!I$rYLipe=a#!+?!F%~NwUf-%^mo~F6IN3N zU1;Tr-020J!N7YnBnpPZ6K|)11QsEo{A@TK!ubR}H@Nv>F|uZQulfb&R0T!#a|;DM z$bF(kxQ-u~m|o*=V;!g53vbT58Gl5wSab7l@H9Ii4Y1A~5jHtrZBsD7#C#PJ*Yp6_*);o;vC&pwYGfj+QO_;Oi8BFS3Y?sd=WK525s0kTIOt^ricn4n$>GGZ zZ6yOgwFq<*M6(a#;610O$ieWT$mH9@FzlS{3eof6KV=FJ{*ec1936eyN5&b9#NNW4v{kk+aYH_P?$*e1Vb%yV@S~>(x^GZK=7`=A40&^ zV0<8iKOIRt80_sOxzV7OAg@z)sHEb-XeK>dKVHMR!O2>VCQ*+&0~ia{LisbFXzt9# zF)SF2PcP9;L`TlU46kR^RdY{$IdfiT2s%(z_yhPdzb|NXbR@M>kR?%#!68K78!t&5 z)T;*zdRXgg0i)p%ocr_$R62`B%m6^)VkcLcF+V$#BQcq*g6m|-YJV~HhsW^$l4elE z?2L}Zr+OU8MT)_3K9pHvYMou|)BFAeAz2vbnzbl{={x{Ih~rw+^KLuUL!uWw$+*+m zpdL{$8cz|)=3>-W%MOin8(z<=($#@Cf0k(pl>hC(+Xk*BuciRzj z*iFtgW)E+)d&&*5cf*sK$jtds^X=u~l(y2FW?JP@pjoaB5JUBBx?xWHKAPlO0hEZT zO3jkszPhs^P}muP93bbT6NzEL7Nde03ndS);A{Jb4|w>Vw^HrzTe4So~C3!R2-Y*KyD3ewO{e{f{FkZLiuPv1|J z`kb@2N2yZ^A+R!aufb?F$ej^7QZ)C>%4y%dvqO%iD1)ld%OD69mCjLHTpmgwEY!4p zD8hKe@*{7~5Bg4RE+%_yvc4CU9Sj5AA02HicO{qwI7zpO?kQivHCRY1K$AxceH$87 z)0G*FVgZ=hsNQ5NpxIzAzQRD}L3sOW-EvLiBE>3rbpbK~MA@Wn0b2`$C#)I!LF+r= zSsJI5*5;zCFd1dQ5U||a5@WSLnC%z`?;cKW!XL?kapJ2G9E8L|W=<+xonBfam2^9W zvqCNB=E{Z21L#LDNw*kgTnqTgnQ`cBj@0)m+!;y`oK__f50N zj}@`$TXWXr0$b*D78BGNvAyF(To5bNDKN(F@Yx;JGu(2cER5?`#8bst!b;yKaQ zU_58Sj9%Q-I)PZNT&4xOi)OnP@GK^Xwv#=kwgXYyGikuU8Dq4}**f7b;Ghc8#}5)T zsz^&7FS}Ybw8n@`N9gZQz+EsB#?WYO24aJRQ33^u;b6tbX5pmGFh>Csj$SEL${|x) zu+wZ7xWi2#>QzbVcu)Joojq}Zh^vFWkZUCeuU6(6=;-q$t$1ANYvp!r_U^-^CVKtm z-MiHqrcLy{U$11cv|1K?Pt3~f*hBB3=V3eUi&g8kwBq!(f|Oo;Gq#r6r$H4xlV>cBZ2Tx=BYgn(X!{w}x?g33)p?Vh?A&MR%6iM3;Yu6-&%0XTLjrpI< z?qC;#j7q8Vsi1+z`E5myy2@5+Zx(8U4O+0s#jZ4ntts#ByzPP57?cUT!R`Ax?A~gf>D#)(ek6_HJ}oYeZZ8 z0+d;EPja!JDpk}mywebIN*Y&o#7(GXe}KiMheg&`t)SKV)@Oz46gw`27_AZv2P?Wg z+<^luQyH{Zw;AcKts#}@hfdf+TXMQ)$dlWq84}!NTT{3kvyqxyBVKQ&J}NHjR@1!8 zxCV@iHYg8_{Q@beo}u2=2)OS?Gwl17;96b0)z}3ZP@3b% zaFp11cQoH0p2B!ej)C+@`-#HaQiu9+KH$YN!PMM0DlcBqL25`4a`W| z@5kmH8_t!=^`p8+f>k0E0a>m*o$O>5;%SeBzT{|ViQDKW`tK>ZI~$?7ZT5FixJJH7 zma4=Z#vLXFX~Q5#h&XC4shu7$SOyuM?=yVF9C;~al7$74fYefNAWkn-81aaHYI6#w z7UPH>5zmW~434eZHtS==D@^+23t-rsc)c?1)y;G+U*-IYyeT^#Eju`m-J#X>DV8QK_w418N#~N2Si28&z|quv^UVf2C?bIQC)Yurg9Yul?W7l8f%?RsH|gL2!4z;$#INn2$>un4$^ z61?SeW1V70m)+alN3+?IOKewQU{Pq%5xJNo2N1ZWn_=GQ9IA*h&c02sJbPIowD6Og zkP#_PvpDqD?9Eb$$J12Dn&Zksg_am4v0vFs!mNxG&h{^osI#0)k0?!xav_3O&Z~*k zt?iE3H9u(Tt=s{1AuLFRWceo8iWB_CQRmGlhFLPNBy_rv%}>A`3E4C7m4FZ`B~J;G zn{iK8cQMOu5osBRvVNx^n}P1^PnrBl$PG)|@3bT3FR|jVC0TQ3iplShxLWA;_JMHw z&3zblCAMxd0wqF5Rcay4&WZNCv?kgtvMu+~OheOUzjSuiN#ifply7y?S^tFD=$-0k zd&28$1||pjK$PDYAyPorvdq!AA7it|79~Y0Hc>=mWC-W#R_eW*o0<1*;bRu0=_dGx zYIzES+;*Dc#c0gncy*0zUwd`4=?TM7lg2@`NnZyRa%gQzY8x9D%xoD}Y-<*caFKx4 zSblGC1WT9NwKR~0ljAih1?1HLg*e8h;&x%!c#L_wISw5>BqkD@z7*3JnN_B5h*d|5 zb=f<@N{7@7(+$fHqn9Z_awefCNS7Z9KQcCI)l3)#!Vii>*~W)5@I4d4KXv-f3PDpBp{QArAz{>kH#W#C%2vxC-Gsy z%4wV2S{}0L{cDCUbw@kNt+1+zq?{U>O0cmu||Jcs#KI!UG>wgU-@X$%^7Aob!D>BDzCI|O0xY* zo*tTfnvfVN1CY00?}RaekodV3Kfr~QCPK_|=|~pud1ILS@0PVwZ!YhV zu=&FQ4`h><9$UUp`&WDWh!EGoZR`>>p5n>v%m&>aF)S$y(itO}Mf!qVh!?&3!c~DA zDnqs{PNPfz9&5uu9^!Hg05hm%To9Sib1(gidE{U`QLDJhGjNIq90jc@>@>$&IrcTm zfRmmyG=99Eev^$qV}6F1QX{oBJcfDDa`6U{Vi!!tq2kztWyKAHLCbSSTs&(hg@qKd z-hGRkVENnuP9{E>?)DcbN{C1TK@a|Xl8fuc0&DsG&(#D06lierZ3FCucN$f zkyvbLI<_V!dPQCAHD?!sCCoUk1iTm6?`mGJRUX7(kB};F@`AT(LT`Ra<`5H@jua%F z6t?YYsPO(UB*rVD#7*VUb(^fhPds?g{i{M{rt8-#CC7e4gI3o9X*sMovst;G3Amll zqI1z$wx!1I8XsD)#M$7o}b(Lu3eSfi!Iq1nqloJkrP3zhJ>>$nUOy@v#+C?qBfZ_!tYyX4s5F%83&QvDnjvuePzU|6ukl z8jJe^6^N}0>}E}f@oe4-QI=C5&`_W&WeD3TEadj0MeK5O#4sM5&@)>es1^=NOBO!N; z#@Q?pT$-)|+ljfgSS|YCOmyR9tF*~Gf`P1M6N0Uo%VWQ9x(We1F>?qo@>J-Mvn**Q zrjrK)2%>Z_$BJ(HWxv&|hPfkpRU_;K8xOl`Iw3bW&UF&kn zivR;R#Sr_Yd9LuW#Ft~pnMSN+YI>;ENp@}sm1Ce9G6#_y!ig)@?@0N=Z+Z{B>klVe za8?Kq@~1=716Z_&qq11Kj2Es#!8UgR-%YFf@?wo;l;BFO`N>QoGOtx0S!k7Od6Vjm z#!#|X;3#M?$(!O^xq_E>m=&iPvgoFYouvL2yk@kl6lXV4qPnmE6}9NHGLOUR4z)bNo$A16xv zIPVL=QU`;b0gg@_vcQ&{89K^Ti_h6?Di&`D_paoYd1ftSpsxnWc`Bt&1qU3XU&2Wr zm{00#TA}Ceqot#p@GUSyznqOV^>$K;MF-OzfCK~!D5I;V$isPtuV`e2t$aYD(=vce z4;xQL%wD4^k1UL3Qjy4O|6|F*??K~oS*NY_{bKO0Yc(2V94=j}2pchf3u(Kl!&1r7 zsZ)UEaHRkT$eldz1k6}=H@PPZw@)!&4kTa?XGpj`?4XUUaVG4F` z8l-GEmTfv(HYLKlQO7gyBz8&pM4k^d>?wZL z9A^d*lpjIo=5h*`-|!XPW`!(P`hrw&ynvImp|b83jtu2v<-FZ1BmM)@rj=4rgShH` z8ho{i@6sxo?+tdBT`FFoTOx_Co1YG3K)0lFd$ITJIn@O~=M)!wz=!!rR;WAT2|3!8 zJ0Un#5rj39hRPo=iiYq=jvT^3)Aw#o zpD~y5ek9q4B|AuhD2vkeE_4A0y}+AlWEnuJ8zqvDi~LnN|-j2!D5^AY$Zdtj!P@ogT}3;p02lW(v{b3jLwB01o}8 z`bi!l^g=jBSYy@Np+l$_Slu zR_n6TY_%{oFSop}k?Uh%q0p#I?&&nCR-aoOuQ|qU*0eFy=!GBG$O@HN$JOXCdOtGa z|HNS=gu3L_Xu(}4>9!B$ebFi6;0fHr;uP&3pe<2Z5-2_ilO3PHKuX(|{~?^w;BZf7 zy!|6Y6i!7o7<}ho)-RK5dW424!d=VceM?d%QYSlT6K+pRCk~pOL;~%K#1OgPqbOI7 zLkWTetyh4p8hZ8g=F*#3%5gpJ_;g?Bj6%1QN~W}RfSAHvx*W1Nn%1|N?Vhe)Ls~XK zBmpQ%6?RPy%|Q?JtW0Vk5*LC_*c~;}xTOJWdbdqE@aVh*E1tGZr|j61i z0M5c^@@ zg+h&`gAQoSX*HheXqp66QuLM$)e9a9j%u-I!QH=oAJg9p1dD#@*!wfGx}~f%Z~=6d zQ$X+1%W-r}>M&IR_M5cVM}?sbYQ?h1uNbN}=bR5977lvFNQjp;h3)&`K$XUDR*J0X zZQB983fZCKq0(5eoYi*j*{>W#r*lhZysS=$4WYxlk!AYYj5i21gl3xCnfLyj*5=&Y zZj<%IJP%P`pXNbyVlG?~GMijw;+@xTWOk#fG50W05pl%9l;^EYP4dH7+eFL11=a@Vt_S_N2^%qL(vTA?PHV~Y#Zj&@frKACShs4Q42u7gF^Bu$a=NCO15|4NrHhQsG! zdQC@0=!u1!LTz&CB!@V&8Fwlr0;Q|_RwB&Q({Z|k!++2e{sKlqs*z-NiQH50;n*5w(#iWuig#KvLdC{3HR)**Wj z#_mz`eE@~5d~yvue#fKl2tTJlxX>lcyRbBRAh8`XK{}$ZoGkuww-kXaaK#pmE0OmYHwJuXt}B6<3fH7dMX*fugxJwBrVum z#gh`38@nvh>MMhjz;=h_JRH@K$QJlNmj_H$$_-RmCLmAH!`uXDHoGVD#tdf6a(Kxo zSq1BILlaggBqga@b0F~Y$7?0QHLp|>u3xLQONp5qgVA=KOIs;2owZ1`;-;1ZX!&M* z3->2WM-FHUlbLNvgckzi5pg}t5w~~jP*aCN7C7Uu!*FwOu>dXXIGy?gSF2MjqOMZW zo84TY8J%_XQ4Od7%#0UTyS04(J1l-%w*HE@-4Wn)Uc2dxm^)!0p31a6Sfbbrua1Ku zK|utWtOM376i4E%GELAANx&`-#D?QXp1G0hN1Rp=Z-z~(;54*t!Y!hznTyR$&^wT) zjCEMEblApa2!Ejpl2%!ji zCL|lYD&jq3k;|h%r%@`Ke@kAq;V}dH;w+NTmfaiOVe}VbHQaAV7IVD4!ED4sXiFTh zB{=`QtB!(M^F8CAcTEL>*i4)&nc=+#c>$R$;*BnW)!ls z+QyNM-XslN7a9w`L~uKzINkYOBEm`4fQ$;arn z?BP1xCo!IxkgA%nc&rM$nX-5(kH3=-oU0+Vb%Z5Uf?5{4i+)f2Yp_(-Y^xHXmQczw zD?#CKur)k1R!T~lHYJG+(p#32k`PP)Btu-g!S2D6AE!0qLQRWpU@%&nn03w%q=e5J zYMgp)AP%3>c-=V%)#MJYS4XLY@N155y&$+odaK!1QsR&fD0rHchzV25b4<`FMI*6Q z1<^4h8tPcloS2d@@Pqjj$CLT=G=R;{FdQ|?^HkQY22-ZRv>K;$E^JmgJ$U_MM<|Ii zhIBm;8D?uZxelKZTE;D;oC7b(U}v^15QI&b!JEMc>vEhj8iEps-Fk%gG|on^24iDQ zbEM?{>QGHmv&oLD1(SPLMYT|eh_pv(4h>4=BMD6}s6CN2!3k=wx***b6!5}ni83B7 zmPH*U(k{40OepjxV|#7gB(#xTxO~BDOSzkN)>!&C!k*r=Lk}1WA1<7^Zo+x=c8+^H zKt9IekfT8w@~)Cm&GItKXL~Q00w==`wbe?4_4X8nLh|BaSXY@Q7Ss8*G6+V+#CFA) z7CN8aqrA&-DE=pdXvVHExOAS=z@Y$&#SHS_*8shy5m0e3XYqww41cQHB;a{DXVfto zZO=}pIzy*mJg(I(Fb#uVU{)9C$k(i;Pn$Oc}9Z;fHUG*p|0tAj0lDCNf+tvuC|*J{)_-9SnMujyFogX?mYPh15a_ z1uj>SZaI=_{-sG_e5}G-nGC`K4s zC!h!LmD(F{+os0o=UmX3#i~FO14`4l8#0c#J=QQAW+uALOv?l#W^&R3z8}$L+X=H) zM|j>y-=jOJ2UU`VF6O|@9cn8uL1X_3W{xpS)!&uHlTXQ516p*Q&?HtZZ;YU-NT^x> z^^YRSI+9>KK*;!%$nGjOL=tkqndStUL8+~H>(`dFsdmbP9nu-e^^TcMDXqtF>6Sws^0WJ7&s%%nhw_4XUc2LX zsoK7e3r6ZSU8$QF=yWT<;=?AY-4piekfz>SUnBJd88SQe8cEYE6NGHbR9L!5CO;Z!X>37T10RJN z!MyIE7e_8?rxo_Y0URR6Oh8@Cg#9oj&4M9j%skL3rrxuFXseJ2srn0c*$!uB>&-S~ z3WD!-a#^M*lh`eGBFs5LrJbA%?~Qt1_c}T51KhIpMDKb}`WLQ}&@7f74zdje;$HQFb zqrqNr)%mKDN8vTlco>Oxv~{(0J4GQ`$pq2Ju#f?^e+^d?m?PH=WirIzAT?24x}U4r z6kSjyReY^2uB3{ux5Xr7BM`SHERFM!)a8Nj*=&{+xr!-?=lBWHH%ZO{xj&NE5lDzx z0H;Cy7p|hE4xq9AkdT}Rdgfo+e6!|agROAIhb_H|J4Iqv%}gn9tdr7HHfeZL*(9Xb zQs{f+U+_hfjifn1ZSc(Ik?<&vtq*(2iZ0nhEbH(HGm1l7Zb5joWTc?It$`#l+qXFR<%|x^R66U0)gTRUG9ai9R7ENSAR?k{ z#hz@k4ZX|T-XVcQt3-ZqDghpRhCh0!T+^TmIs#}mDCJ<)z&v0=*bKthUxUpT$uYM| zK}iGzXNJfG!&t26%7o<;q>+|~kqx6jH7n#XdT@xy zOnC+i+aq|CjZ$e$(hiYvTvx>k&{ao+wUHFq*ZN)QGVn`*p){3^&k)F`37=#CZXSgW zQLQtjH)8$6rxcDr-atMzB0)YBUu-RXSizn=aai5pv{GVk$sm>LO#=HobQ&a~k?Vzd zr`#IE1Sry4@HD;%=TC%{`M@eJMssMj=Y9>px#$AX;a5L}zD9G4>= z!aZkpJyFb0)*#~25Z!umI#d)4h9;LN0XL-?*zJva7{s3-!f-GMyqr!|Z6a9HQJ#2= zoi7fIGJzjljV^ODGo0XpqwO7E?Hv>29jT0nn_JmZZxAYT#vz?R@A!J}_;HrWS_?w5 z>lomPeo!8qOmDH-9J}=zFQv0m^12R9Ldf`5Dsa|`g_UX{Hm{Sxrc3z<36siVcrx7f zS>ZSh2|J2VjvQ=aelGhruAm_MyngL%>H86z1QW)bh)#^3CDV({fki$#E5&$ptDn6um8yG%_`6zQ&6b z&5$fL@D$Qe-~z5h7+rOGFZUM7i0LBn4cd@_KJ%_&t}(%AmA3G#WpA~Qk+cj2m2?9I z^;tj8rYlTLYrCPs^i-`k16MM6CWYWNi{oOvAzYqy?7nf{DcBC8NM&)THAMDVb@|u` zhsv^~eYwb(kvO>{1fxEML`Is0C4KB|UWnYMWKycl!&PynEr!GF>a!A!C6HOu=OCJ6 zc|k`H(+B0Nn9Idhc*(NaaXMN$aT!iqtz`2~YyFySx5 zR_TMvoO@s@bkrgbQiXy)hsq>~JbNyJ8zfm)+2m&ZO`6Ab<_8ZDnQ|tG?RExnM6Qnp zJd0%z%OuSyXo0hckq%pA3ILpDo*AJiVHZ5H`$7Vpf^d#$3s~gU8unQ??6z*^I;ipJ z=1E9QCn$k3g-cna0AR6m{q|l{vRc75$h1ttAsHVTT{@OAC2^G#_z6mGU8Hl8zoCU4 zw1vm}R)}OL#kIE<&b*P{djyow2o#x@CFY|N;{4+4Pdk$(w6wEniXsL#xfLMp1~}(< zVamoU@yj?YzqF9$td3%U$2QH(HaHzmZ?#v_jOXUg=~!KWwNEiAw5`c{e7&sTXOPyS zn-Pl2kd)!j!W~Za|k9CLApdVf_gb6 z0PgviRLyn?XzTgL5Da{VD}2Qrt$fT4tS~Sh>iYJWR|u=2l#Ok!BV2m=6gSp5#KJaJ zuxhYaQ$s;+BbK95fy9+!?7kIo@i%wn5rHA^`LN@qqhW(iWY>G2ux*&{K59!|(DEvy#Eu@tAU#f@5`P8nLRc!*6jKt`QL; z+v4#!J7~q%_C9u}gt6TT)}C$YPQ^wUhtKf2bAY%0r-^KM6Iv@ZidYGKJfJC*-ZGdT zr69}UWZOAusJ;!D4b)+l9h|Nfc@Bs@(~*zG@aU5UV6#kM;m|m(l`ciQ4K0-+-h!1Q zDm4G%+#CiJc-2s+Q=iA-ZpJECQl4O-Usy4(l6zX`7fzxshuma8~$wY7sV=hy22klMVJcqEaa81FK);TC5)`#Fdp8dI1!#@oDk2H6S>}2(yBoEgjA-C z_>9;%{HgLYk;Vb=Cx|dG+nO6>v(-Y)3xxv4U>CvKDNcry7ORr4*91aKvq-|7E67j4 z2~7uEOEE6Ox!)XY$jqLpfZ&)muQN?UL`5sEEhfj&tw`BunaJ$^{ry%DYlhV>WRi#`RUk{{)aH2AV;NvvD! zw8ZsRcyKNN+bjSb%uq>!g@eQN2d`8e!(v8~{ZEb+?H& zkp|p!N{sn5ik)+u22s^KK={45I4tF1T1YHV4vj$%D<_&*Y0qP2(o?lqgjU24VVxy^ z;YppuUw}J&=2^5q?nQoqQB~@n(4V50$`#UkwYl)wP+Mc9z3GnhBHIyMu2Q07YHe(P z>T^N9#p>f{9!bdnvM*+&6CtwNL z2ofBb6}twYu{d(P5R)mO;TA@TOm+KIg;0^m^8;!IQy^7{Qu2{xz^Qa-^kfwpq=>9P z9MLMz+IoRtvJXq7o15ylK3NuNP!h*qpfcgdZP%?ZPb9Jd)xnGU3q4Zw;D-=TBms*H zpcqSe)bXr%0jUD5n?l1Nv8H`S>|@L85L)_R4R~jn=a?Zaa6FRLGX-N`*tJjAm)29N z`#~sKGl-^^?TCLA9mp&Hphs+34;ViZ50{f_L>M#~57ot07ECG(lyJUY&+FszX;Cm( zyj?C zT&P^u3I%Mo%LUjOKY4GPmMc)V>`GqLaF=hsy}zVDSfEwr8DFTi&l~#vCBf5z6|!up z7>26QI2vYcnY?r^i({`QFlfb-My!`&5iPFUHRZnp{1VC>zQJ;(@JR@m&DTDooF$Az z2A^>T0*+@~SaH*}4^zR>gn?n|WE+O{PzZ-_qbzXnwqQu~FK~@iTcMu^-*Vs|o@wr* z_IA9{zC;>sZh%^wG?)+(%SKRfjrw%b&IqScj7<(!?6?Ii2iA;+%4oJxPVtL3m;$#- z1r8?}iO^*UGZ3M!bXOQfLy3hjVh0uPoGlJ|5%E+Jezo#JRGVz##Q*@rnM@$Lp-t`G zn&2wNw~>f_Y&w_eh%SY5+bHHML*2?R)q3#Ve}VzN>&kGFLUh$v5SZlxBkT zsT7ujK{t+eawh8tZVfIGzK{Tulq&u5RAPY1{9I?~2Z+e53ai-Z$n^h(>u3v!*G06h z#dW#lQZLSsIKDLSDm_elL@+UK@8oLl>dpnq&t#B4B z5<{d%xL(lyEuCFrmF*q0RT^{*G2k-2hheM#_!GkTNVsfGhX@qw$uqcbU8==*Z7z6c zeda_2^V3o@bG8^oyS9pB6)F)3NIq~77=pU^Xo4e8nnDBjy294#U9nOC4#eUlZ&JpT zD?iJt$h`7=Q!73EbTV17@Qj;5pur`zMS^Rf%@+(&AyCFQ4Rjhoj9qB+4>0*L0jPrT zCu?*C8k>lw9fmNJDh>xGyshC5D4&Yz*9jq`IKQJ}h-Q62f?T83QY0~-MwWuLoPu`1 z-A!h4O9E2eilNN6)65>bL30gjDur~LjIaBpg?JLq)Syt0iHf-ha-rzWkseXob<(J~ z@%@qIR4117p=rGpUoDeKH=ZqQa7*T- zwl~=r9Ca`m_E>)&&S=3Ww*u#w&En#;rw{7BB z{qjS%sMV)A*qbBeI(BZ~v2s}`n`FgW`e|AtvJ?-8co7NL%I%3&9XUnvZ zdKK6!L3)(1yF4@A)ljm+Vis@MCbSgp3739JFq=;!0`Ol=**eGT8}zpcd|9Oo3FnQmDl#$cPUT z@|bx50Sm(afqw%1-GY|&c4c%i`jFhrABT_98G%)H+G2VD(lYh-Xesax8zpq3qxL5N^5v&gf5uIc9sT{!Ys(4hL&>`(W zB$?(hVO-#C1;e)$hwXTi$t%ju`(jxY_Zen~7p~HE#$(e~6i1H+7h8#7m8iXP#N(O; zM{`bfNGMezh)^&x5b>Rl|3Lr4WK3(+A6^mo&c+jG2cb)y?w`(yAehlCtJ!nR zo<8H@rusJOsV85k&tpO8_qdz-F7E$ek~IZbOVdEa4&*I7cyZ16S`fe|JA#*iIpE9W z{CFXiV72-3>U=A?`2q2T?F_`s+QCMcCK718iLREW_GjLw*aHF;=!J#});yd5c>0L> zK%ZsxS1Y1-Q6dPeBdH?V*)Jfz6cKvZLmaHMjEA8#bTZUS5#U)53S|_Vb(<&!s!`uL z(8n7jK_3luG!3!SmNOk!T`Prs9O`=*2x!?RT%jom5m*g$+9<0rUCj|%E0U?$Eek`g z@YYrRT+`2WJ8YcbUs(!A|i7oLSt#0pF_$TxjT0fl zT}^4b(+E(cjR-zODo;KOZq=v1J%Owb32t4&Q%5Rs)|Grpib1TLeWK5t4W+E+w0+n_ znxY5_7%qS=(^onPILhW<%Nidt5KxUyXh?_1^f{opA8*`?Cd5~lNM(Ipk+pdZkggo? z^_{(z1|{>q34@P95oESW|FwAdJjjLO=(##eN2NH`U{=od=E=pK4uo|$W*CYNWq#dyWGGUl!*1f|)2YmGW zSe(B0gMWf8P!=UngsycPSPB*R2HPs@D*l4*$T1>(tek>G$X$uD2H^?>SICq+XH9*Tr(u(c+kz0a5Sof4Ocz!S zs0hVM`|};Vh0qO0+8{;tw8D3EaDYe;%wU5GSxCwuF(3MVmLbOHPV`j#fpR=T0Z|MG z*?iBb!iC9&%lk`ktgaAz^TJ6UbMV2cN*BqO=?P}gTCPm@iWTeo zUSv___)FRHpo#l3w(AM#O`8UphrI1^TqG_5l1^WXqHEovaOH>_X8T-IsbmZZUTqa+ zUbDWjigpUGP-&QxHVsgu6N8nE0r3)H1yoXt3XvdQIcatiysXHEiXp=eK>iN~hi?tS z!iEWy^ZC44q=U1Km^z;2`tny!f{9||%qGeq|5!j+m#K~KuB?HIEJDG=Z$;~4dte5bAU^P`OLP*FYDoHq6LMJg-OhOParW?|vRBXYawtle^YpfZag;4LT<2c6 z%2wr@e2Nh}LmM9afTC6x5@6m;=0RUV%Mtu72!9qx;E?@Syg(LV7Uj4rD-2;We~RTJ z=b#bo?1|T}@rH#_zY4YGo#rCAi;yV|sgVRyGr=N8%6xDfpK=m81fnQ?MQdY;=m?+> zsTNsM&tm38sF6!>J+m`-OoPaJ2_~le%}Hw}rDbE#s2Ayl<&g+3x`8jN*k?-_){dok zfc7TnIU^{>50#OeI8!1MRYXH=nxAnG*s~T{#j!w%nzYL29OkU=+WO{70pH{lPXR}5 zE@iUCXRIb$e1HR#Ee5FLMV55ew9--;;sD_&BFLzW0Xj10l88^-mY_AX2;MDOuXF3R zI=3>;akSEFtv)MCy8WnR^;uD}UT5`Ls#DL(cWfCEtP;U)v_%aE(iWjJTCe5NonL%T z2OdM!7GcxWH_xturePH{&#i)$r*;c(YZ^~POALpgRZIL(${Wm}x}#d>-%%U53c~$N zmxqw}wtly?*&pq80IYX7t~FR<^n{cseT+_Z!r^boCmd|tSfB3<8@dK2md8NVTL>$a+i4Wue zBS_7D40+e9!TDr@EwXS;+O2RdZ(Umugj^!R zEx1&|xt4(=_(RMH!9GPgEE;(uEgf+uzDxJ%>9we@MD!vaK9k_Nl>jNhkK+A|_1W5Y z;n5~~u9OIhHDzYr@6;3kY z-3q6wDv@Qgcll%{a~HHIgWtk7LqjmX>({cX z4o36IV4{SCLR!?sWF|z2*0h%pc``>0bgCZ(oDu7OD3#Q5YZPlJwn#cPZE<-VRGNbh%`EP-$s1 zAgD5B>9Ju*m7YCrMJkLsPM0OhneJ3-9PjprYt>l62eevdMts6HgCR~w+o^qLDN&yK z7Z(5o7if3nmgWfTe75Ugi$_zDGd^PM`%3dsaUTkaWmFDv4*pP@dFA|G8qyPonQ430d-*oC&V7)707I!2vaZa{Pnx}%jM$rM*XIJ^7^~s~>Nn5_V z0v_yUgaov#jX|-AMbfxmYfd5}S4ppI3-^JJpNKBdwAinT9EHIPUODjq7&U?U_w>O z@n5}0PWdZk9y!yZnHa)kvE#j8!Wr2+ThfYK$^D}!pOnS~VM#<48p*~x8xcvdzcgn8 zdjil%vNK)Fd4$AuJO@(IUv#WgL4bfY4cR_Dj&uY^0g)6|an3)1nIMMOrSv2akWALEcO5%snSP^^% z^MQ3Ot21alpXM}1v@*K^p*{)UPPrwtm1^)*a`;&(+x2dcNB05PM*jX1P;qx`-SuMY z1?%1fbM&&r;>XqjD{^e!22gRKNT}xkTI^Hr69ZH$5uu7Y2qDS5mX|*GTUh^qzS!?= zla*5W?~aP(oO@?E=EddTNUcKqF^GWP>cOH1?xN9O+-qdIKF$am4yMJ8x~$N{;8=V=1NQS{M(h)k!+(%o_ zPKX}HlU6<}=y6%g1MwgIC%u5SJLd@yM#RksjLaK+GDsayn8(u_|X5BPXBG#i1Gl%4?=Ebblb z02aVn@30=p(nn#7*CTJ8K@&3wtdYl?Qx3&Onjf`;wZp|=#He?7#hc0uujn`wDL@@4 zTyAuAIGWOqiF)-$8z8Q8ev}3dVuYoY1EEuO8;XnOH7Mz{)HiX198g{ZFym($v0Aw; zUknJ_N&m8WD4kPSMRS0ro5nhb#L?lc=JQ!IAf;EQPbKXHE0>=yv}d~VySO9o5@JYF zXNbQ#7Xa|d9@8lhH`d8Y2NG}FDXf9sR%FO>bS~lP&g}rznBY!vLg+dD$>}wtDlfVa zyQduQ0D|f{U9jd%I|WhCkndy%5O(FA!!n6RAxX-rRz-U1YDvS?Rh8xurgcrrwpdZ) zt8)5{`uK%8h)RFD<;oApe z>^*U-qdW4gBp}(10l%w@0J>Im6G6|rH9{x|J6|qidC3Oaaq!4so3bDS#dgcu&6It# zD^Re}u2NNLHhZFq@T)B@G4Nsf*H)pt59N-Z#Q}mq>+NMtO^rmDN<3b^S+}TsaRaj3 znJ3ypH%c)~y`_veg>GLDkcN(?^&$+hs3*e;MFWaKKwCCZ9VVNg;ZNP{e6Wi%v)rsg z`@ZgS%|W;}@?z+GOt!5KXPWSS#cD?PitUKM!I*G8avjo{4X`v(1Di61ZvgW|UUo)| zW}sfF3!_LcYK(_8fcXhr+hA~mvsg|SLKLz23kKDU`(85k~V)mWT0y;r}4wR|L`nbc)gV9D=pq!KjAZpOn zzLKUN&_5qHsl2(jgqSL$B1D*v8pOgSNnUPosvYmpT%j4k=E2L3k1yr~Hzia`2%dmk zaIKi{H;D?QSU!YPB8=H4am@J6fqXgRNTOhV$9IQ+bGu6tu}GF+^=_ zp_#xz)Jtf)J)2cNqLV3}BT?$r(x4P@Uofj{^(+LV1Jc z9P16p322i8q=OkWUB{B@^skoL$AEKXZmY|TjBXuGV(>9vxd*(-!sdv-h$j`bp7fjA zE}lDhdR%sKgPrM9(~VLT!+;N?!^sm%W1{bBFZP+#+;81d(3noR!*$4E!$4CoWP+HO zB_NJFs9mKC#O*3M68w{Koo+iVTGpFEf>L~r;|I#yTt68BED z|4#Lziuj}>Zb+hwgJ^5f1c@^J4k(S&HhUFI=%kOoOI@5=s%+*`iv;lpM1((=z0}9BLj;DD&Ykcw@ z<4{pWk+plj^tQnQ*o0n#F*gmk=VTY@Un_{9A_UOV5Lris(rSDH{j{^S{|J9Vm*vrgg3sRDQ|d$a{}F3TMR3kN%Z^21>6APmp>Fnd6Nm;g|8 zT4!}5ptaF@bc$koVh7ZBb;LTn@WfTEw30RxyAZmtD|@j^y9~c~yqHFPU$n_U@ojN! z3SbumKR$t(@%Z#T()iv?$^q5`Spfl#Ox1G?D<@%<>{0S%aw}7b--e(}q$Fs_665TY+Qk#1ThtH2-!|4wvza9x7JM>@-Jg z^c9#sYeXz(d=`Bn#8xIavVsJK-C3dLWmeJD;M>*CUw*fQpl$5UW|wofSVjBh?1*@DzsjIvU42Jx&>nFjIffBoZ(`v5ePz|TAYtOeTX}z-$`7ov(0tJUx;Xq4qP$7&+uTH9hV^meqdO42*63hY_wm)C9g<{gpuLsuV^Bx!JHD&LJa zYT(y*6So0q0J*drMC6lu&J1gj(;x&CoJLKYStIjA%}kY4sZQGnA5zWP4kLXQ2$E&+ zXG}5ofsw|oH67+X&Fdjw>4O)V7B(GN4Szc;l^@p}iT=R2fgWLv*ZI6GDNe3cEn+*e zWbfIMcRZaKY7}A;*;D)jA7{#p&M-?y3LjjkN)%I%+>B>dPA^DdHFPgc&fUbV{yqc( zrbm^0Vglv?J9?e+bp=g6Hl@8K zHUfKRWrY+UgdNNp8&5$03j=usfohC(I5E0?Fxl;$=2h?7Fh9VN5a*dfQ}9eFGQ_55(5D+C;|}{8IuD}a${0~1NF={b7W6105e&WG~PRyBTts6 zZm8SnnYJO9MCa{d`oJ&u^z}Q=_A7Nwn?;}EAq${NEfg8faC5SzlXlHc{<=7V$OrEL z_@n|=YT`fcpr$00EdKJg#m1ccDO*{vF4LYB`l|De!O9E$?pct8v zILsT&JR?wSBSZyF0o*nGm%pA9tmlD_!NTF`Jr1Rmx8+p{jYZe63o509NOeUVP|_!M zlmMsT*Qr$cXeo(1q`MIFtUM^l&+vJD75Hq86O0S5DZgo6`-$><&J^*^W|Q0{U}{3{qRa`i1FCF3w3 zDKnk|#0q3Q=4c%nHc3&vV*+vUod$ld`S-ei`9zn3#-2=dRa3tA=+An3e*J2lw{8nN zuj}MBIhO=ChSuW*ewbjYM9-@PA4`CUx`c#~W;pQW*e8%|M& z?QwM$*M};6**p~%V7$bO4ljQW9p0+glcJJb<8M~1co5BYa(g|xls`sVxlWa}Nz?hYxi};9NqVyk zEenA}(Jk1m%jkvs8uals~l@s_lTYsK5w4<}XyC4HGW|N?J~M>z?`bn4+Pq29cNA!D@(%@dEmVgB!UQKf}4|BTCrB?UTu@ z-rbqO%J}$W)Q;VFaHp-91yw5yI=U?pLRW-GGy{*t*St2n$nxKfAL^3=9s>zDnc{*i{!B_a#Qh+HL%r_C!&N9ZY<2ZuxvVA&@i z4IgvU40!~x8_c_P^Px_aGz=Hffw+!hkd1A21sw>4Yi4LT?{=KS{X!K)aHP#cAmlt% zBs)Q3bKnMJX?H^Zc_I%(y~b%JZdD?bWcwrCjdW*-QLr+oD6&e>w#v4hBZI{4EtPtd zw*E9Z)-nU~G(~}~*0Q!OH)T+8$IodBv<@;E)5$!;BChJ1{ohw6Osi zh!^CeL?I|T9a>r0l%y9T<(|=)rfeQ+KW&i83aL~(lcqu{a-uusWnk4!Fe!`Kri2#rfpM$TFbnMD+i8JHsZIg;y=2PLZ9B2I z-8n1%v-60oGBCY}jLugytr6|81e!MaZhTs&x!sIJ^;D{Br+a7D9_cbPjyUgQkvHyf zQ30JZXsGyNYIV31L4yDkB8hk$2<{$4TVj#FEpspDmSHVcwQxUIDrdDVz!u8K)}+?( zi^qpQCWJ;%ZRe0i{JKr1vq&zJo(d~nuqJ9Il}V#mnYG#~XZ}@UTPAL}qnNpmSGl@11Oe?>n`_ML33>#d`2szbabm z+rwM!-?h**8_+tP`S5~W8sj;H5*A0JFBb47&)u>Lpt(|5kko;{dQ?9BoIA}R&bgOv(9Bg%UUgSPI;TxD zvekP*C-W7OXtw=I*d*|6s{B-|N^B-xE!Z{KR0Ru{-3l!yQdQdLBr>pcZA=sF)MQJh z8F*{XhZ@O&lEUqJO#Dv9C8d~jwzhuQfQ4#D!KzbovH8Lf5|#{;uSl9biKN##lKK>? zOqp0cw%epvGfGVo1y}O>P^3cDlKtbI(mu(W0FdIf4gp6=s+(I!6nb-`@ zM65P8N%hm)4#Uo|S}&CgtA%LA8PIB3sn%CZQ7OfDq^r2^0OPIO=W2N<;#8J3Llo_(V-W{41X|ur#wD|xt z2G&pmt=E&XSG7A+ItVlMV&NU(re!G-4F!3dPYwzW%zwfhV?|t@3 zg75qPe_r@J*)wa_tm$n{IVf5t+cSINN-4J6V`qx2QKVH%SoE3(TEf;8RrQD(HAM-K zIq7ES<#$M6T%f>ca*TDJK#H`*}b4Gq!jH$=Y%mI4{PJnffK55-ECH)Xzut}otJtRQ+ zsja1{7PH6}#XD}`>wqvleBpnH$5dnem0o?0PCddQ|>WV_Y)@y$EKp;B|_dgkcaw)&^x=JNydca*$&%=2U;kES^Uyf z7~_7V4oxhpG;Pt(<~)6P41;3s_jCBi-HSka>FP-vRFrluI!qZJ+bZI(Srn`rB?vudPmW)ut zfet+(D7z_B{AnKFysT~_&eLqGUUN7Jl5W7#lNH7Gr%u^uU8g3Y6p}h0O7wFj$)L4E z!ZTpXb}F`ATboQzX%8uRsg;9AkEj~4Z`tI*L#xWhO&(r0uFS-7Y%e^07GBI%j70Ri zPQ0};FFdIxhww78^rAXR#Pg`4(z@7QC$2tm;Sm;diafxg3$NDl&B4DD9o?E?7}LgK z-|!H9bO?=z&~T#|g=YcOfN2tnjU9!wYwUK!ihT4AZ40MS`X5puXY9Ri$OI2!K@Ko#MN2!e+^{P|HIw^>$9lBaYFa$Mk;5!3 zyaf@Ksyq7X(Z@{cE_jG7^xv?MR;x>HVb7wKcxYnt`Ig4GnJ;QVx*wS zm5EnGb;(K9DDHaWtHYcEs-8Q`F2HMZSTp#Vc~s5m>?+3uevFP2OE|^pv#|PV8sjg4 z+7ZsIm0uUGWl^uVggXnWkXa+gwM+wTub|k1u_glYX|v?Z*m#a?E%5D9@PkXgWhZR#zte z$-3hjT|y7{l!CPIQjk%Pbj~a!$LFo6 zf4od-+cTV&;k=R&>iO+7O1dSPN;h4a2+w4-zkVi5V}2)ypFZ^u2>3qSPHTtLwV8FM z2(tOCvYdSKy`v1_Y0kKlvz*@9I?;F}w18|N@S_jE5)$u^NW<=DX4DY6pk$;cGsdGt zB2(7Pp;ecDyMwv&)aqzIJ?D*+aF;|=XlpOw#ahitY`8H88X8GXJdVpKOE1-u=u4;t zRT`Q^L2)pf18$}om{%K)Wl0i}=hlbxXqM$i5nm&Db%tDx`ZL>`)W#|gTE$(I>MVY$|Qh%+MEBysYyr!qy+z+8wU-?0}>B^{XNnOLuHu7tc9CJ;j{)dm~>U7CUPKaYU~$6vn~>%8Le8N9js;0(70hL zKpAXi5fc3@BRqt{Z5Gxp4Kr+0i5~^g&nR(EhWVCGy3zaCr*^JCep0=_|9Gg~JJ1-f z>jx~QXLFjH!!!0Z4iW4^T-|h*N!gtTO7k zC;di|5qLhbwqYt4s*HFDXNYY`346NcL=>A*PU-gpl%ovXvDN=TQ`U;^SjR7|vtqkf z;w*;DDNN-;~fV?5{<|0u8T8*UVQPa*e!9q6#K=BSZ$h z12bKxlI=+=m3Z@fjRn>a?6;L%op__T)cJ6X=3RUmEjTrt0n!jB27gThbcBKounu3% zPr}gIVN?#sKizH}Cwm`O)JndzIQpWJBt^&5wt8opa;a|ikGS{3i6m6m!N z|LiGRm+T}dybBP{l)Q%0)-2R8-aYcpUa?6}5*?M$tEAdo(GI^->m~ZxobrR0zAX$- z$woDYoDi2})=Mv5>lvMK$cDqS+6%*-o2)U+Apc4y-2#sfN2`r6Q>bV>78hztva!j^ zmCnt-GL^%cCFhC_hX%cT?W*e&kMi3b)T)!;rlzL(pSp;wj8y84nZB@Nuit6WoYbrM z%v<>6nwix}$9e!egd87al_r}9D7{C`GGdqTpllm1;k?1P?eb52g~&gKW)9?$W+}~V zPjN_2Q!X_K=A`kiPwbE=0Bx=N4S1`0erwGhclAb5!)a+Wt7kk$*hP!+=vNBeEN7jE*U9z{FB*XaQaa%g4eGR zvb^xO_ItHKwB2m`5f1At;jLzc8Ev_!oI|s^9BZawEtffZO+8*@MNJ^b(eEbcClBm3 zGrEPaCWiN}V>)|D?D|W^>Eoh8oIH=avY|aYJ>bbTk-gr{s$EtH)gN6TdBfFw>quF| z`O3|`Lv~wP)!EAsroZ!vNm5Y!`k(tvaM>Ir$>ck;1P7fxdUD&ZwXjsm+D+B3rSX#- z_7-GxG$blay;W0F&+BvMBesR2vUXExvCT~#4?Ba{E!3BVyTXw?nk%)(`|wV^(Qnwj zq~5d_(^PpYo15W|u2->bjG_88O}Gv|GL2$WsQ=t@`n!9cwhDXOy zXEt#eh1+_%vP|A!YT!uz0=xT-XFV)stk;vEZwu^Bv9d(pLTQ|lVKTGPa8AY6L?RIF09Ds{ zj~suDAEBbnFtM(qMuk~NZPZ0N1xjTx2^Ilcgqc=Y+Xh-PQJEQo{8hq8Cm2)MKG83< zPHX0JAN#|uz6rsq>QM*9@`i<NuSro}y=}({Sfa>W|RfN~(>4Su0~88o;=M`&2V;nx**RAXWE5Je#Mc-6}`~eG>_lCiRVwU zh4XTjuXbUo1#jpY9tD%8$e#B|c%+ABh>5f%R^fd|>hJb@g}zEpS98$PSS8BZ!y!LQ z&}75T1+XN@QvJ$CV}^|j`jrlQHbp-)V^qJtVT(^Ph6f1DC}pJIDczN3Om)|I;@2bA z?(C|s7m%Y zcD=eKYbE*vQqhvkuM}rV79quV2sJlB$2f*Yz&xmClz)&cO2ioE_kK=hg4V#*+J9@x zIInxaVRC4kJWem|CJ3%HdJfWs(Qt$HdPX@%I>M;iYiSdCPjXyzemr80q`L8QYZ+`u zGg;>6s2ki++J*i zWml!2Wm1`3DO-SJ(V4jN>Sk`XCgeGZb7SllTaH6qEyYkGorHIG!-jLx(@h;QvO-UW zVBlFSZnO=y);dg=(Oi|znoMMU8v65Y&VNQ}$2K$%iP~N%9YUoYZNZDCuA0kNvRJI~ zp5h`((7gL74k@?^EX8&zjUo|dl^em49PeEWE!X#>FiQV`fS|070 z%QShI#t-``SF;Y~(Pu?5K`tquT*kVlj)Yj9F}{f6%vPdzx|+PX!nVj=73v627^Mrn zyvQ)Ed4?y9w%>9$kCi+-+rXr_RJYX{tJuF~qV6pd=#;|Pdx9%l(9l@1a8xZfo+%;y zK=IHD-QRUXY7VU;8>qyi>#BW@V5ri5h#Of6Gph))h^~N|=Tr%!Hft73)rjeXr#DwI zXlwJ=>P}oTQwN7j)0h(0oTxZs23N+eqSd=xj&l1Ea+8{^1=-eW4Z4aV@&?Au5jt)) zb-Zf0(ZZ(R!b@(OH^vgWSMFmd$yR@c&^eD|-9gyiFpQs+A8cKAL@}G9Wf#n2#-UK^ z=Z~^?8e`&MN{RlV(vB5H0*2aShq75t%1~)jV>3ly>H-F9;v zUO54`tUa}?1@8$ z`Ao3C6oD{B*c}`GpO^;VXCWdo>iInd2&^U(VEAW+2d^W zjT80sH4T$8X`ZF>&jt|pRHMWqpDGUV_zo=WRkMT={jP9=fu^eIM3y0rtva+Y|5Tn7 zb(qVk!IC?h&}34 z6C{@~hkepi->qf6xv3*jGoiAoot7k4GXI)eGh$?t7IhycF&RI+(XX|mRB&$z&tNaL?eLcr?8k6k4)l{~kXA`9kC*i~T zm2qJY?3>AGZg6Q>Y_t(VgX|FQCi`AagO9m0)_D>$RxN{USQ^SQ%1yAp#!kamlM7iA zjj(B04d-~8nS7Pl3+mRXdoPho?vyag7S4b;Nsc;UUen;{?#GDIuv;9V^$7~bN>V_V zqC|u)Ss`T{d*akOz5b{XoQz^0iur!ld2%@lq;j@nn_Q`$mad&<9et($^`abFiTy-f z+~|{hmMBZKWwNF#IbNellJOmI`5=}pIpGte*E$mv|5Iy8eH_M39*c^Su<|d*U z6hWiNF#mG&)Jm_Ct2BkfQ2mm0DL*e)J2wu*XgLuoA3VBhuzGw|05*M`v9Jcpc8}4<2q=YreY7BClu5-eXOE_b(b&an(%0>#>TZUEGHqv<0FnbabOvfHda-oEr z616#TTMm`Bh0&Hvm41k=O$W4qE$HF0%2l;?^37W%(87;7jA5n1en6W}{uzw6oCY_t z^V*h!wT!kLMzLeauf+e2lP_6|)F|5}ZHu>*67OjtQTI@5OAhoeDnAuSe!@m ztZ&OXtml8@xVfM8|IAM#Qe1~+~rLQFb?ZlT2Ym3n}@gQ;?)eToLUFJ=9F33CTGn& zV|2o#l3Bg(JH-P-GT2X~qT~310PVcma2it+izZE*oL^@3oj%k*WQd9+R2yKj*^5*F zLs0I{c422@(;}IjRjGJoQf5CxY*kZL&ReUb&9)FiAdYB`ouX7m~X_G0wdI4T$|n48?h`bL&fqnKnno+6)Kqq^cf(PVj%-u#;}8hMa6 z3>9U*{V=66W7mUEWAtiTa;+1!d|v%7`E1k?h0FRFQA3kT)^b|_p&ZCf~5 zHn*U~(e&*p8?v7kN0C%kaDO2h97%FW@yozy7k#i4(=0KV2V_|W>x5|Jb8?$3HfZX- zmcM7q4NOY{<;+mtLk(BkakO&7{5#IpLH`~1nqv?yzW*07Xvz8aF=)x18v`{Vf99!g z>6&u9ZJySlw#}Cto>vmCA(1T{TZhnsAy;&XjVU(FtuZBSv9u1RO-Z?dRWaLT!*ERj zwQ_D9NGq1y0AeNC8uF^Od+Q)t^F%AXxS3Si))HEvIG9!}s9`yQ;rrS(b5+)I*M*vo zqIDX|^kmkwl88=R!$6DDY{gc=tLwFMjcdn5<@`H7bn0u4;t+0 zHn3%*?b5$ts;IA9I8#4x8@;->W_iO{|Is^(q3LfV4&f14JC*Y{JUf;8+34T0#L9=i z;R+|bwSK!c%hNZ*HZ8L@SO;Wner4mQ<~}Z( znfbU`1jK3vHJc{pg0<5v)t0C6O5LI#+kB*zyzvuU`M8>CI+mkN!?HT|S#5t!nj=w$ zP-rNf{rR-8uuK6j^-K<(#i)MjFNYRRrgCW32joy};g>^E| z&Y=$BI80p*CF)>uh~p=alX}%Mhgw=Qt#%GN)*PZ=t>utP$iWel>tz3-DD-gpeHPyoJ+vNBiGGVw)9Ydv9(k-51hdi3o zn69V|UaAR?^;FMI`ZpB|6(f9vS_+pEJrOP$z9Q#v+eAKAkhSSFBD`^ukTatQ39 zGFj1&H0Ea2sA`SXxV6TR4%aG&6_LuCgImX?k~nB%-^pNOM%ZZDikt1O z)lBzcvgCihnPX+37-yOpa~qps1}_dvEx zS|d;EF*_NzthTXrhm_=NHAE&IHE}~5^fysp@MaHWjSSLxM~-dfVA8!+9!0vzNI)xw zFE3>d4xVsa(gJNBzu zJNRy}HN6ei+|JOvpnO9s=#7aGd}vbqg?p67p%qP%w+(p~8-E1Gyo9l6A*ce54>}Il%3;`$!L5jXMb(NNYOPv| zFvW5!X3duU36@q)k;b&8plDIq%0oGCcDOL-l(6UwYg3r(qIp%POcozgo7*53&5i2k zT8AQz7IYiahcIiM<&z>77HqcUlevs}e?t@JXV|`s1MrJtW943CEV>kJLDn{;Rx`ZD z>be~2$a(Xt*_8KZN+n@1r`!kE)$;Q)p{`iO;qz)LIcymRXeUQ4f?n+&2Wd1LevBpd z5R-g8Fi9n|Sc6oXv1)$(q7T6DxkMQ&L`0Qa@*EWsR1_)GUeD9Bdjl zBV=YvogeTj<(C1?I*eE6{k*9Pt10CPkJcNVscmrOU-MpM&MTyS=xvhWj87w z4vG+*ozygHsbytZBMfGbOM_XRDTa+o)v^r+zR}4xlM`7aAGgZc3nTVykwY)>ue?WY zL-@f%U*xzkJk|2XvZ>KRF~g+Cmxd*@d*xYZnNSaReQo4cK2N_i&lR1}Su5JeTwXns z-*b=yOCN4N#D_T&G&O8Lvt}lppc6CG>Xh268w*{IB`dN59SOgFqgzo~q87Ue2Smw@ zVOGBpB_o|9RnniDi0hjt##S42I1HR5%xzM=k0}-U%@5=Av-jA+C)Zb@M7$z3Y&NFh z)IO|E-rM*Ilxo6PTyMi#>bXeNh_cEAn@^s$jZFN!xkLCdWKQTbF60FP<~PlBFLoj) zOUSnM1Xnb^o0tUM?39L`yj2jya-1~N=75Q(d#npL``~HQ=FPEn;LutYQ$`!1pK-OL z_wsHw4Ggg*?#yFK*z3o3tMge8VSg^?NKwnlpGNL3Xpv!j5#9Ik(njTwtyVQfOPL%e z!U{Y3*1n?kagK-N0w>2ok!dpszgDp`v*9YRmA{hOMjiS|CQ;%_7S^$dWS-Q@K_}L8 zi5!R?vQWKL+%ZL&B1xJXn}^Ezdf?QI(Kr-asNVKK3InZVYurk(N8(In=M}QH)tQV2 zy_q@tk&R|$&w2W;HrIbmv*&5kO(n8MXPP`p3-kz_qqTVE2##Ij6u0f{w;-ZfeliV~ zfLKf$C6mj*odRF)bHYLCrfrbiLNbqxa-1k`9dUFjzGKXhQ&sQlZfkzqX33TBJJ^;T za3s%r7(snnkRxqe^+Hqmw#oy=G>6mI@HQe8_xL4TE@Fjclk%jzmJB&!bu7YeoJ^0| za@?&8(T$WfxcmNr6QMc=mRp}tGSxK4y+)4IQhqT=`xMNNY;!5sBNGOuIBW1~gDyR@ z9jHqtQwIZDwAS$x#?Q5%Iu#!)G!b$ySPE@mQiNS4L4L?iK+)7SJZY9Ih zL;qF@eAA8vBxpH-t4s0ka{GcGG1vEi#uQxwVU9(9`P$fOzU4P2#rh)B0JjX=?g8kW~yw^4h!BGsqIJN zruuQ*pP-ql{SOVre(X@Uq1_)lb$~?&Ai}wO4voVYdf6eoVC2R{$CbxS&6=4ChEj9a zO=G4?kKweSvbt{@EwRmMUZZtgq!E`{7bGHk><}i*PCvJD43DEnbgS;+&QVN5cjziB zhFgZm>cz-4OQ^Ety|kZk&_+?jMwTk#lX(O<@)zHlstEn*H#=Nt;WUe%r z`O4+bU56K0-1tL6>aYeM;IIbY4kDX(j%=YyO;=mogpgP<+4D@+-Z3ZDVtX7gBqnR& z^AI(YV>;IYc{IUqCdS0X8pn@`3M_WjXd%@G$ATP6@_Bk5qtWs#%8VQfA!Pkl%vz`) z%Zz1tRrA8i>KQan&iVPHP$AV0Q1vZUH=}mWct(YrR^v}vSurP!;n6`aVEDr6R82o@ zvMw3JuXppZnEGccSJjKYr6f(Sm8g8I8_^-G+}b)==gw&B^XI6-@Z#1SrHs>G9n*0Xq0q87ryJ+7LWJf(?G zR(o)2q3S=8Unm?*Z!?{6hSxb2F@Mlp(F)s)MKKOLR#;HG{k|H51n!>t@7-oh2n)O^DCugu7G*exlfDC*?!4n7xt1 zek|}!onj{IYRy!_R=IbL%imkAR!0kbWA&<0GpZ(!(~})kg(!ruZbzd;RM*|qO5IJh zjdNc(xTu2EF~mf7iNadd(l5L5vpEG=Uc*5<%7sg`LOQCz$PjwS(8)~=! z$zDHa`ppn0$878YbLdaX2yfMWJjNx?!_|3j)$@2MuzIdkJl;F=8Z($DMs4peOk|{% zwfd3Fsayw}iRF;c2ZgGv95Olz4klWJT5g(0`N)l~7W@AbXVo^>ge8Z*m;V z##$#u4b+uEU%^#CWxS-uahn!9etyz2bb;qHy@t2MwYzlO#IVcp6A9&DjxWm|1m_Tk zqKwNSsN8Z06}1cK2NEGN(9OxQ%hJLVlexxRPtwrj`r?2-%W;;*rj{C_*Za*x^^V@5 zitC|x$LOhk<6zpTO4}Hx-Kgk~8fN8^bluq8xK*3&^ur!TS84027iQ^EV`$}I)jXyu zE|jbnj3EwE6~jWaRH-lUM|K!er4tds_Z6%HrqRE~RIX#OsO4?lPsdS zSbsWy&KSGO&p055us61_WshUzW1~aPIkERzI&;*r!KXx~tVh#BhDr2h(=TgsWlDYX ztTjZAU=hL$#}rGWJ@L8+_x@P)o5zsgE#tXFsxBmS(nV4qwfcr3T%|U%#-Vvl-pX(= z-F|a{3O#SmTy7dO@yw-#p0Z>clL&2<6i?%-!n`}*(W1BpNjlYOd&RpzcMhQ80={-P(+^B`RY>#Hol0#f>HHMQ&s?n$`sIxC#~M7{ zb9!^sop@WE^n?K4if!UFqEz$*AsS#?kZnLz-_(MhRb=do0<(pq*HEwCDFNE`h9Si&uMDyoN@|#~WghQca^Q6XbogWw2 z{5cbA^)8*iZLTT5w_{*cOn0kGkmKQ?c`+@YKc~ED<`DLra(snBgz;jj8;xd7ro=TR z!TdR8{5o^e(e5E+#el zE9S&7dK+a@qZ&v{S4&KS+wrezRN3gj1un(^bof8x^xr}4z~2t8n;QfwTxb4w!+s+6 z=UpE+AavzZwA7WRd-3j(`1{!3NwUD-&8?JjmRp+FCs1g^-D+$N?wfQscN69g{9oXf zd>Kcx}gXn ze6xscra0rK5W?drasm0n`JaZj8`MF>y*=`KbzItUIkrKBwu+QDxVy-Y&TbNJ`cE1$ zH<(#cXA!$4gf_`S-IQ-sKSVC;>N~xqyB#y)@T@ftV_?ygf+#RvMsbBy;dy$3#@R0wmJ^3}u9gcaW zTOBC>1}J>DGPTP5NdBx8aSbwoO6y(9p(0pKiWl&8?i)gU-erPMgATz`D64R92&P~f z9^8bx%BgdZaeYVy;icM>#%{rHTAFGuH zs15nBxlHP=;G19-H9{$WoY?*1ZVKK_uSU`;*Dd(eEy<_`44}j^xc1@iT_%4yVXlO( z{}tdw{`TS9CzzyqNZArE{y)zDK0$>Wj@ux3mh&ARWb*nT)w#ui?C`s5)hy(;hdykGJj=l^Q(Jjetc-1F(1EJlNn--nz_ zlXn&A;n)W8Kb;;#SgL=$=xtIaF@@B$#eo=OR&T1mtxbw`w~(IYiFhSN|GkT9o0shE z>Y>#mr=k15GRcq9CCTk+PxAF{V3|oQCz)M!W)gLVf26Miy~+UocOW&rh|S}q?D0JB z!(nf51jKg|qzb;P@JW4IcNU?j7$+Q63D*u&)qH^!!ouRMBr1I6@_N1npt8$&w zC(nfyQXfcXE`Ha1T>y@d<48V1{`Q#5Si?^OczPSQYh)p%S7p=E}k*F7@3}~>JEv5J9 zh0NjPTrcX^AWWT=Z@~iMsoeM!I<177nsLkXR3ldJz0`Hin?>3_CI6QPlhR8FU#XJZ z&aNVFip%UOn_7Z$S^t(>sZN1!QohP0`(G_%34Mg}^&7Z8&ATao0sV&m*Dd_s#kZUF zI+Ki|TCeiy1#NLq;kpH^RjbC8oQ;IFs5EQCwYCe~I!*y=KB2GLthytiAfy*U&A4@4 zJ9vvQ7lU>{edAhSZLkhdJzp2BhiQHO<{N+ekl$I$Ul$iIClk}tuF(8$U^$XOW(JuV zd@IzB#7*Hkx1rmBILe%Iov?R?qL^%iZDUNEfK8#c16@E@cs2vw;P1}22k42P&EeYu zY>BL`@ZBDC0bSwiWxOf3HN3sSHeg$Lw*%V~$_}6pAr*oyKw<1i_&ecGe)_`Kk60AK zw=?wqe0Ko@;NBHC#bY48R8MvTyMsNzp2Rc{`d-9#5GfdppN@RHfUcN_;Io7jl;Xe4 z;+Q79v>OVB0nKejfW5&;(mskfl;dwS{>PB&3gnL^x;if z!DHZGxIa!FKLMUZ##7*FTFf)la*cXVQq$F6JPGdx_$H~jtey^XZ$N(&yhY1-oA1BDJNS9m;@!!;$M=0` z^8W$&5E-g3AAygl%b(D~GRXSW_)FYpxPK1Ef4~<&{=TI3rJyVAUr|%mrS)|Iird%F zz5(BY?`V&5& zki9_orxIT&*At%2!4_c4pbE-(w^g9FJAw2}biL${d`Z)*DeSHB-y3WL zw#CnOVEbSn3wsBn71Bo)(nrbPzSLs+d(ychGIoS_C(M08Kg{YAc1FJPx<7t*3HGC$ z_9M^sBhQpq``V0TSNMIN6}o}J{_u2iyFuHXJl!KW!0n0Ofxsch=f#1hrlN;5wLN^-TF`xpB1>-;^r~x0%1(#yBRq)DUA1QWbZ>7 z_YJDa`)b0f4#QI3rrmz{>A{H64s-z;=akp`<3Ar+2Y~L%cS}Rc9f*B$Fpct`2LCjZ zH3j}^ljGb}zSHnK-TX!Ts-x2>-|6_7j-NV<*=X?9Aw} zGvV({_^O*bQ%gI!W{Y>Bn}@7Jz8F>d7gHc!h4yu|2pDU2VWh08k^@}pM!l4 z_F8v&Fc~ljoJt(<)cLjc>-@20UuL3K9`uwZ;UPBzOC9c#?Vqk>ug3Ip##d zy&-6Xruvq0H{yO1xH)Kor-^WyESy_{X6j-y_Gau+dw1^EU>q~U$+AAk?RN8n@d3HTIzM!G%+{{dfsFQI*f->(@QEk1N;g8g62}J@Ifk-a(N(~Ds=gv02G1@ZbhlZ zt{Aif?ZH}LZLkjL0M-TT!Mi>cZxOT9j;W*E2C1XzC(~|2{C5HhyE8l+fsMf?&^Ap4 zt_yy;;(xQ$G0b<>7LP#xh}_^<*FANt>jAxI>NvM~N^_p$-4>}6+?M#+3K_k?*2K9t z*aq_=(zCUt)91~$gz+Qx?Qq*3^A4a7*b(dmtuN>Yb_VZ}AN~360tSFx!9e(SY#;lq+gt(M|QcwnlLLbI=I2Zx;1|z{JP!2|eF`xpB1;3LouthK9uiad=CdlfFr>ouo(JL;AqUpfMYR#MSPFrdptM+ zoCr<=|41!zCsQv@f$vo8r%}$Qr%trFjLJa&m+(CUoS8a_+&zgleG+Zjmk|=6sg87V zXCdQk@-NM*hEdj?gP(J$8{Yk7TfdzL&(hQ>^dF}n=M?MD&QG06c&B1N)$A9*qrPET z>NF&0$ASw}o!mvpzW`heE&rzYH^{F%H4;lB6aU*s2CU7(8jts3)Zh?Ml>P-6gGl}P!#PdjZTk0%#d+Ka= zN9r7RC+_M?6pyZ7(*{$)w0Ze2;WEGWAF+16nq9g z2mb+IfG@#U;A`*=_!fKzz6U>mAHh%HXYdR775oN%2mb|sfIq=sz~vRX0Hi=3NP~P( zkcYM)k2wM6B2b)%RtK!0uW8SBE!@`z>wpemU9cWlA9Ms8 z6m$Vy!DgTv=nh{G!kb8W_r$(A*aB<`ttYGS^~js8u=fI6gWg~pur1gQY;SQ(xgC&$ zZkpO&;&#Nm6X=V5Hs#b0zMbVU`rQ$E9R0s_4}Gr6}nRVbf;C6;XW}4+)(Vpz;G}k?=rV{-lf!)%i%6`BT3IF z(x-M&o_7WFgOnR>c0Y!X!My^E1>^EAXS})GRr0OEJ|0YfcOv0*c8qsOR5~V+o_)Z+ zc@y1!V1MKu0PlfdGMECY@i*1{U1|QL1DFPVI;a6Nz)Ua;)PjTH|CzW+zWVvuc~_Ai z^wWeh2h0WapaC2V8bK5OG#6>+I}aQJ=I34M7VupN4h4sS!@&`GE9q+#f0es)M-sP1 z&=-TF@)oegWL%Go{_ZsRPKUk(zh?lImt>v^ zZISh_S{;mcXHlPyvvkn!Q!mcRi~Qb*R#fJcJ2&)y9^a)Vx4%1|?*+(OX7bQm@x2Il zh4C|zj|^_2M#(>A1npwnE(zr<=eq)EJ##7Umx0T{6?r!^rbKzFxZFbhmJIrRa1~f# zaaY=IjonlRD~Zq5pfBdr^KL_m_owo|(&Bu3f`+clXm>#KdK~Fw)UQ4f+({Wle!WcX z44$5MR~+88#C2Pn4~ed}dpC7beti0`gEj_tt(Cow!ly~`Q<|^O(;8cT?}_7d1AcC_ zINh6|`MPy_-hE-%3KxAIyf+ip4d9l%`_Z3A@lCs1al4K9-41f|R^dHBdlhegbdy?h zu(p8jPH-2v8{7l#1^0pb!2^V${Oyb;FfS3#x528Md{W==PmBM9@G1<2mtr?0WEfT^NGLbmDV##uV0V98HS}g#p=k) z=PklJl6L(z>HRl&2m8Bx-vi3u_xUbMJ&r8RMV$M9a#Y>@5c)@y*T>+KyeB9Fxkqi} zN$N$?E?$*`_@Bb}Y3va>_gUW4?sLBX$(xL>lJOj#FM;$1UqSzxe*PQqE!Zpw(6t5b zJLunoAK?2DYz*&D*nb8c(dH^&eu?GCANowv{XI0vOrzP|5Oe|BPf@?{o4Kn#rQPqO z@4v>Ea(_Vo6Z{2OD53sh*EG%C0Ho8;xcs#ATParny)exlRQfq2Fh{`t8#0uC#p&mb z=EtW(*ABl+QZJw>i{@ROT>JEkZmo2Gw>DS@bV#fJe95hwKFY0^e%Y;$AFqd3d`Tyr z!&k(61LzxqPK4c=FgF4lW7gVh6X=_QF3_TMbj7?G?%l+Lj2@sT*c@yDwgk(V|80f8 z9hndH;;T8<)_i+|ZNRo*JFq?20XcoZj$kLy7i>ZN`lVlSJ0q)q`c=0J7yxz!1Idfs z;MpDQL0;_%_Ck(y^n>^g#?KH?0!p!$rC)PHF%JX7)9u`d^lIk2$+6z=H-1am?hXG) z_|j4`k&4RBM90X>Ay7aql4m@+y@6qQJyZUso zYXAp>M$nXgpIxK(sps!g&p&X@=?@vdOWeG)=As|DLrC9zEqp%;40*-1XqJ=5T>#9THLP#*Ml3=1qd&lfFtSoaa;&EOWoxfN&}zK!_b4($5m(p4ve8pVvE8_iC8}VjrgZCAnIjj1XSHV9qzs6T_TMceYf6X}V-0Ot#26z*^ zML3<=d3rnjt^0TSGWQN`;ta~`UDEp=_4Iw*KL9h+-?7*Cz56izgZl`44Bscj>r?O< z_&oii`w#d6dkO4)|i$N9fZ^ySiw6(z6nAhRk0jvww11rdzPg7~Pe!lOs z)t{+OcEn9>WdreW=f)4+7(N+(dmcLtaVwC{;oCa+llkUf z?l#P~BdaH7?a4-SEb*O7o=Jz_mAGj>bO*FM!Cl~Pi{GE<4qOlr_C5IloI%h9D1G@p2Pe+cmcc!UIH(}_X_;4<`)L95zfBk#OnNX@OplJFqZkq8~K?)Yu`8F zdn>;vcpFF)+65>t{tf+|Fzk2X9m}qL0q6phm+ysc?-K^SrpX!xUAy`p3QgsX?@NWPOhPKi~`az64)E`>4rkO$HQ zzRu?tFg_G0zgQ1~Ld+RxMW7h8EBM2;FF3}nRj_ujcELKqIt3kq4h8FyKfXP$3;(;! zX%>+iTQLSQas=JtIi~c{ey+M6eCvab1)bamU?TnfhS)oS&V;iO__$S?8BYqde$d=B z#k?`)HX+`njCq^FFWp!d($W?4W?)i!-Jn~+TBLt{>f`#9$@-Lu-~ZEku_t|r<~ll4 z(F1$;f{wxZ@bn;zjBVllf(>X#E#*bBXj8PDZSkx159jLG6>G_x8}|0deTsN&OIT^Q*zHiziF{YwI|qGm z+Y#&p`htE1orAS=CXdJEld#C3PDE$(|1Y#MN$ zF~QF{KHO9`uP`oa?z0!=G6)PNZuC!-h2%x$iB8sJbz#>znctpgb90N%qcAT(PEA-( zq~k25yvm>r1;a28Ck*Le24Wup_QpPv?+7gQ@-_RQAd+u zGG{?XwqEqKc9dIIN>9>{@_h4Py__&b`5wE%LH;zDxg5O<3wLvvtPjr`pC;(lrhEcy853 zo5-fc_YG0|kJ>~pQlUEL&s$7K*0PkZD>bBdi-N6Nw9%G%>E|Rfh@;L8sNK%QJPXto z^bR=jn`j4Z<*)Kq^}_dCD)*h~e>b!Cdb~TRV4JWlt+~IOO;|6JKXrWPfVq|*oDa2p zXU<7F)T8*mOLadhE7@-zZ2p*=BBROL`gZ?IKPlHtSZ5ITc?H`Cy)Dgo?hwMA4;J9I z5FCok!@%L-h=LM#B=J~;`(khu*n)762FHM7!ExYt@D*dsQ}hidz;hxv3H$?`42tPX zPJ!oCa2hzBG%Nv{)186)ncytKKAZ13;9O9eUMKi4wL@@TL7$*wSUzv%^><6#%oo)y z=Dx_d0Kdz?h1f6Rdoj2K=&avzg;}s8{liYJ>Pt3{eSiKN`J_HmeafYl=bX(!PMVXi z(j#g=^>V_v0$d5S_j(n4E5X$TeVNO&xA91Qdv{J~<-{GcG3>hp z*AxsOgtWUBf7;J79iH3OXfLG)1lK|L=NJYC`JA-t0yKBJz97%qduLAL(X&I}4f^iE zc-#t1PQbcAGWVcv?nYR<1~(LNUW77|?)od{&^IFcCek#Uepmi(CLQWGZUKJ&LtB9V z)`C5W^X{ZUaqvz}<$dV&)RJQx10^<4$mw$=`)OB+`%d4eln~ zdn_+^5AH2^!`+8{U*$)5bh6y z4>gvPW9u{iK7zkT@&6d~fAM`BJOOkztUDUnJkSNOUl}}EP>Qco?4_2cn!8+(Dq}8C z2CWR5&W|&XM%Givy&yFd{-L-H4f%%!PZtcgvU&!dW%LQp@_nvg1mo2R_(s4toOzS{ zr`_}51?0R4ULsB}lRvLuezjn4WVCay6^sm47mNyChyF&vk#5^K&(?Bp!nZFc96wC` z=-y(U_jbXs;NN`TLC(A2J!ESRruCfkiSJ|o0Q!gEBk(c!1bm8|uLGs4ll!c|@27sg z#<;PUPF%hyxW;{nzpubD=5t^3{RThZ68?AK`-0KI52Rr%J4o95x}CiKk+6OOT4!op zdN02s*Z{3o7tj@5yw{IUbUznNbicqC@&AgsJO00B4*HwS`0Y(S^ZO#`;EB(F!5?5? zFowHeBXCvS;@mN^CgD%A{sK5KmmC|c1G)g69qB_~G!Xe}XFBs46e3qn#eAff(Bd;SeHUJxfPM|Z`2y9&VjN8P*)jojMW{PjN zo%H0C>!yX$iC0k%t4MnlanN{)8M$40`#jKOX)GK~H21pk8iX zIFYtK5&A^v+UJ*^PHE-rGX9hgTbc~?r>RM}ux25g;`Bbq+XsL9;Lqy@l-HZFlFS2L zfT!;l&~#l7ZVGe>;psj4=VnG>E(fDY!x+95 zU@RC1DnS((4<>+#U=r8|>`NMZ=BwRK4)(J;z&SAJ?Fy#^J>xX^I;gsM0Q?7n$w24m zr@&hcG%t+eG8OwYFdftopBZ2#m<4K~9Ry~BIxq*!1@)i-91I#k6THoZ>>*%2gs>KI zvRP-i=3_q)EC2_9RWzW5d=D+0O1tE20{#vMnv)#?{YbC~ECxq`qroxYSa2LT9-IJ9 zESyGP^P@Y7uynruAAC;+r+~hkqSn1G)wNTRt^V*dzNdpF;0$mkd}kr!Y;X=Zx3D@m zk2ozYtU)ew3BtGlECUyUi@?Q&GYF}r+f1Wfg8Oo?0$f@+i~1bkr`FoSE36M52o7SN z#ux!EBmB$36}VqXcvm5JW#P==YW!V8ylg%|+qu#ViS zqy5yy?MnONj+kh_qjyTDyz7|L9`9}{oC`%}ouiby24y@{)3!Egha7#V-m|vga}1i2Sv5Ps%?ej2~wR zi0>VR$uQ=(io55Le7yvajJs%&4CXJ$x~p(u=-lGmhRpisPb0c`pv-NBJcgN41jg(?NFo0`<{NTTzAxfLzv{ojYuo+gIQ&%>{wcBjL9?G4+kN~_i|yN5yiO10 z`}}x_IIJS52h2&k9>bETt;}y;9CY?p^Y)W!E-5dG{vWD>O#ht3vs^?cgtU+-wE>hvkCNH>BEw9p-qv|1#|_Qf%nL*ZhX6g9-t@K9DjS0 z_AQ97>eH5d_Y0zVi{>!sfT8sQTZ7(U8?Y_@wgcNEV+YU&^NwIApuFr0tsmx|`4H~etuB3e+*bVHSdBg1i_5^!@LCEpzOsz$i2ZP}m z0!olsN_hT^jXz&gmeJaqIUe+3U^sjuz~01ZBp3yB-lLqf=@+ zmj>f9mj#uX%Y&+n=I>Vo<1<$V6Ear?6EiD=NyKL#MOi#W+?b+3S~9J+nt+IiueBHx6-sJv~0TW!cBR0 zcd)*@oA!M-?faf!9{!`Xtin$2C+hC=A>`kDumCIshXUPQ(7BJpFdv?|7kN?L?BtH1 zz8#rS9o0UJFHfDrP<_!EE}aQIhgA4_N7*1_F*u62_9RY6XYNCvdmr(;kNEjHuJn_~ zSRQIGCeIyf`NEk3zCDyz1?@PibU$_JKE}?E-SL_J?gZRU1Ug@%wbM!D)ju*1ux=C& z_vVmy3OE(4AbzLuJsm7D*{lOI?cA9eo%RsF)|d)QdNbd5^rhaO5v*$Ao^od)Lv>hs zk28V?=?~@K-`9-x3C<=iccveT{hmXZdGsUxj5K?ygndTvF#WI(`#jRK6r2w(Ag{EK zA)T~z*~^f1A-D)=9=0c8U7UF&PN#IEYST~AZ(ouL+;YN_p6p`etU%tS7S^NWs*mSo zCg(9mGjCUYyFARJEBIast^zB;)!-U%Ew~O`4{kvIjbIsd-F;7)bti?zYTN?)J_tkX9WLZ4JG%#D@(7#yc4;%;P)=#?ax+A$ND(q zul)CScjG>rG~5Hvz2H7@KX?H8IgF<#Wu6H0ia8hYUj_X^@DM!nEZ&?qf-aqa#+pYm zPtuNk-aHE5EumXw@D$^(4^w+RkK$iz>aFPKBUTe)~k#r78 zYhHgANn=Ml_pgjjEGdj=U%~4_6)){8+>&`V%wJ!xwfCYrt34L!le2p)+Fwb#$I06# zNY7;4dsz8A7X&8%dDeak=Y`@A>v0_zh`xUSW$_U*dXdf-!N-`D=1)xS8~9_-2$_q5H_a@)>t~s_ zf(=cc&nK1R=T_co-){u}Ak-hsOUzZEv$>3fDbO!U7ym!O0MAr?i9cT~M0&9a6)Z@Oi0ripUE7eba z9lRIz8}A3}SU4YqcHeI=OMMv1)cTk+zQ|dZaMvRaI(xl7_V*~4cQNZ6c1P@e-A8e` zZ4mNrNxj_=v-U5Wse_#`cei@@aaa#OVJ}7HuDVSf#(g8gk?!Rt?L1_R}btx!RAGu#&O>Q_btIzU=?}Y3wN!3mW5@cIQ63!IV1Qi=wb2r zJlMMEKS6K!w*lLN?eMcbPtk58oZZPM|O72h<1d%(p+-1%Cs;uEcjB*bVFs z_5gbV)!%lE8+#G&LGbA;<<`g@j2ksG%#*+CL;JfSMg3g~{H36*NbOyDsJ@kXU>Jt_ zg;I3L`vzaK=Mv>}$_*pj{mF;n_!~id_XZ=uDEyTZpV37hyD`YGz&;lHIKGuuPrhQ# z;N?_78;_p}U?OJS%b3LXJKFf)%Tc}cd9X6|bu90ejN-yxHrSW2_xm5?BRR~O;5)$5 zBVE)doWWB3bcXm-cObH)`{txgST{9BYh6#DNL;t0ZKy0%KUJ@$Agj9Q+jyLq3Xj~U z@$JiPW-nWHj=QYLt^qTOzDJtEWL}E@S@0@-(b!QL{J{9a92DMza2HP%eL*FV?Ah?w zfzI3p_I)xsO?c=2EwAMN5Y!j_6!tI9>9xj#$p_6D8u6<;m^!m_7yHspxHXff^Y|VD z)&-hhu?maxUvW`h>DdqpIo6`AfINtjDnr!QfjYsWSar-TvgDoRWg{yK>Jo|EEd_Bwa z{_ZHkI2s%Sjs?eoE$`=bFFplDad*Sdr#}X{s_|<-3{TqB;ja&c65GpPvlSHkDiw>&qObxx$x=8SOQ$| z7ya#@!5MM`XYmM^pEq@LgV+~&EAOx1Y-?|tBc$Cqp^S6+o(Hr~eHin?-huLk8EavX z^7GYXKBeq#%2AnAN^c7CB25alty@Yw&o7d`Lb?m(b2?SbU;hq4;4Z*jdVytx^AYrq z!G)MFD#}Y;T$G>EcFzMc8ejl}OJ`oNpvJ0`C^Y7fb5r^_?OuNU8RcI6hr zyw!Nt3iH|XNRO|zQRsIU);P!Ht&{TW7y0w;UhcOeS7W5+o3m^`Ogde? zSJoj+e-sz-=?sd>OXJnLVSS0*)9xqgL-O3q9mu{D+(o|V9FafsqC8N1)=T*{O61?i z<9|B;cBh?(U!Qsu<&*N?=M}qyt>U~rY10`DALk8P`1AEwuQ1ReTo1U~KF8E4A$P;n z-K6Ip(4TPkqfbJ6l*n6O2WAj%>vJ_apQ^mwDCNh(Y})_7pTANWY#i3*tek_Hw?}h3 ztwBao_Jes%LhE8*uY7*}Z_c$1DcH1Cebo80gF*JJO_#6@Dh__Gt2KdiAKl5*w$EO5 zO>JZG$>aR<|Ls|ududPif&YuMHuo1r=WRA?QE#+1(m2x1`ZLv=2dEGK1gpSQRrJeAZgAIF%nX4SpA9?5>8$m`)cJ=Pw;wL* zW##b*=0}0n8;|k*SJBq=w$a;*=eWmJ?9aMCtB+Z!-e|F_5 z`Y(UpLuX^QNqv}FFL=6W+tf4kx6cyZbCkFG{4Id)dKCpa7t%X5mRD8QA)R%M<zUxIw{`l}+1_x-4|Nq*la=yjQ| z@%Ih*wn(Q2`=!3a{5|-gs6S)$E`;OnrTTl<{x1EGgz*#j8Toc{c{S^bG@uo7Yit#svO9igr!?iCZ=Et_^Yf3p3XNiNECN+!0eF>|{P^;r2l> zJz4R$mFufI0*b%5@TNgLAv^Sa1u^9+cVw zo-GM?tKza$uVU?U3?=@94{oQuOWB4A)w}Nj8-?4l@<~xq>QG6@SpW?AaVO45< zMr!3PFRGGnnlEvlrg#GLD|AK7rL_;Y17*?&>*t+!M+FB6YN#IugQya>N-p5?-EMhet+Y(zm>Dj zqz@`SAk~3*52n5i0ex8Sm+&nGI^$KwcPL>=-#Co#aO@+9@7~}j&S#9I%tjR-NZsOG z4(_9Y<}}h@jKN$1zjU5`d1*-{I2PKtn5LJP*u!G3S&5t~+{S|m$esu~@+y<|Cbbrx z1bv_4sb=37^L}6xd#y?5`=+P%$G_kAtRdZ;-zlD+TF87d+6z4pdGx--lRY28pMt#_ zTuuiy)p%JyWB)ps$ymgh9^}`689;ZnXY!o|YVmszm|Z-}WYuAw1LlHy+#A5bpb<0` z*OJfCp2tDd6}9=<&;rJ|z%>`wF`jWpj&RF}$02;@BS&Sh0RK8CyO8gpz`s+ZdGQ?l zw{wRTw{wRV&t-nh*>>_*YhvZI=5vxIz3>spI}*Q(z+#|$Jc{qp&=>J?mCEcG?3#C| zE>6MySnS%PJdXU_%wD!ix#Nk`3E)Kh_2s22`8x?d?GyZi@5#_rwx?h|6`WSwNEtA; z;%5o=Gr*bPEO2&l6Y*zVkDqgkn=MbC4CX;&%}AI_iw`l{&%B&PE~L&cUYNR|_)x~l z`L;eR0Y2r=jm1Zjrj|0~Uuj=Nz4U%Iqzux$=oQJhshIZ?DC?Wy0CyH28}mswgf;;?Z?@y+^+?BC zAE-X~ZfN(I>=T&ZE9{iJ*W$u^fu!v#+VD1vJKEd0mh!qEJWzaM>Yw;q1>b|kCs}zt zgt;THkLm5hhv9j|WS$(>=~Im7QRF>Vd@6OC^Bb5S2Tvg9Nxn~kr@=GWp9Rl>=fMl$ z#p2UK|D5kFKHbvtGV;~`TwA=v+Vi8>Ujf}o=c{}*Cw;B>4D!eC(TlEk##ZC@dhwaa zV6KF0=}zA)J`4HUzmfTDi}Rbs=h*j#qI1nnbIuD==Y{E63XK;6i0|9Q=M%>HjGN~( zZn9T^{2uV~VkKcjbkUY!*Znf)Uif>r_(DvoZ@fc{pBtD9yia^Sz^qy0SUA-VKE(b} z@x_!^z&Sid8|q6x;@K~_gt&;d96s;%N%0D!eOi1eUv&S)m+|H8uHwt>`=8<~?0ake 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 literal 0 HcmV?d00001 diff --git a/tests/test_blendfile_loading.py b/tests/test_blendfile_loading.py index 914c071..1e71ab8 100644 --- a/tests/test_blendfile_loading.py +++ b/tests/test_blendfile_loading.py @@ -279,6 +279,29 @@ class ArrayTest(AbstractBlendFileTest): self.assertEqual(name, tex.id_name) +class DynamicArrayTest(AbstractBlendFileTest): + def test_dynamic_array_of_bakes(self): + self.bf = blendfile.BlendFile(self.blendfiles / "multiple_geometry_nodes_bakes.blend") + obj = self.bf.code_index[b"OB"][0] + assert isinstance(obj, blendfile.BlendFileBlock) + modifier = obj.get_pointer((b"modifiers", b"first")) + assert isinstance(modifier, blendfile.BlendFileBlock) + bakes = modifier.get_pointer(b"bakes") + + bake_count = bakes.count + self.assertEqual(3, bake_count) + + for i, bake in enumerate(blendfile.iterators.dynamic_array(bakes)): + if i == 0: + frame_start = 37 + if i == 1: + frame_start = 5 + if i == 2: + frame_start = 12 + + self.assertEqual(frame_start, bake.get(b"frame_start")) + + class CompressionRecognitionTest(AbstractBlendFileTest): def _find_compression_type(self, filename: str) -> magic_compression.Compression: path = self.blendfiles / filename -- 2.30.2