From 39084ca663d2c8d49fd22f0eae00e98d5d44bac3 Mon Sep 17 00:00:00 2001 From: Lysandre Debut Date: Fri, 7 May 2021 14:08:40 +0200 Subject: [PATCH] Add the ImageClassificationPipeline (#11598) * Add the ImageClassificationPipeline * Code review Co-authored-by: patrickvonplaten * Have `load_image` at the module level Co-authored-by: patrickvonplaten --- .github/workflows/model-templates.yml | 1 + docs/source/main_classes/pipelines.rst | 8 ++ docs/source/model_doc/auto.rst | 7 + src/transformers/__init__.py | 4 + src/transformers/feature_extraction_utils.py | 2 +- .../models/auto/feature_extraction_auto.py | 59 ++++---- .../processing_speech_to_text.py | 2 +- .../models/wav2vec2/processing_wav2vec2.py | 2 +- src/transformers/pipelines/__init__.py | 122 +++++++++++++---- src/transformers/pipelines/base.py | 22 ++- .../pipelines/image_classification.py | 129 ++++++++++++++++++ src/transformers/utils/dummy_pt_objects.py | 9 ++ tests/fixtures/coco.jpg | Bin 0 -> 88476 bytes tests/fixtures/preprocessor_config.json | 3 + tests/test_feature_extraction_auto.py | 17 +-- tests/test_pipelines_image_classification.py | 115 ++++++++++++++++ 16 files changed, 428 insertions(+), 74 deletions(-) create mode 100644 src/transformers/pipelines/image_classification.py create mode 100644 tests/fixtures/coco.jpg create mode 100644 tests/fixtures/preprocessor_config.json create mode 100644 tests/test_pipelines_image_classification.py diff --git a/.github/workflows/model-templates.yml b/.github/workflows/model-templates.yml index 9c5e5a6d1c..ab0f7a9aad 100644 --- a/.github/workflows/model-templates.yml +++ b/.github/workflows/model-templates.yml @@ -37,6 +37,7 @@ jobs: - name: Install dependencies run: | pip install --upgrade pip + sudo apt -y update && sudo apt install -y libsndfile1-dev pip install .[dev] - name: Create model files run: | diff --git a/docs/source/main_classes/pipelines.rst b/docs/source/main_classes/pipelines.rst index df003f490b..df87ddd306 100644 --- a/docs/source/main_classes/pipelines.rst +++ b/docs/source/main_classes/pipelines.rst @@ -36,6 +36,7 @@ There are two categories of pipeline abstractions to be aware about: - :class:`~transformers.ZeroShotClassificationPipeline` - :class:`~transformers.Text2TextGenerationPipeline` - :class:`~transformers.TableQuestionAnsweringPipeline` + - :class:`~transformers.ImageClassificationPipeline` The pipeline abstraction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -79,6 +80,13 @@ FillMaskPipeline :special-members: __call__ :members: +ImageClassificationPipeline +======================================================================================================================= + +.. autoclass:: transformers.ImageClassificationPipeline + :special-members: __call__ + :members: + NerPipeline ======================================================================================================================= diff --git a/docs/source/model_doc/auto.rst b/docs/source/model_doc/auto.rst index e0e76c7795..e6aa9ad57e 100644 --- a/docs/source/model_doc/auto.rst +++ b/docs/source/model_doc/auto.rst @@ -128,6 +128,13 @@ AutoModelForTableQuestionAnswering :members: +AutoModelForImageClassification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: transformers.AutoModelForImageClassification + :members: + + TFAutoModel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/transformers/__init__.py b/src/transformers/__init__.py index b1de18192c..3e5fb363b7 100755 --- a/src/transformers/__init__.py +++ b/src/transformers/__init__.py @@ -244,6 +244,7 @@ _import_structure = { "CsvPipelineDataFormat", "FeatureExtractionPipeline", "FillMaskPipeline", + "ImageClassificationPipeline", "JsonPipelineDataFormat", "NerPipeline", "PipedPipelineDataFormat", @@ -483,6 +484,7 @@ if is_torch_available(): "MODEL_WITH_LM_HEAD_MAPPING", "AutoModel", "AutoModelForCausalLM", + "AutoModelForImageClassification", "AutoModelForMaskedLM", "AutoModelForMultipleChoice", "AutoModelForNextSentencePrediction", @@ -1640,6 +1642,7 @@ if TYPE_CHECKING: CsvPipelineDataFormat, FeatureExtractionPipeline, FillMaskPipeline, + ImageClassificationPipeline, JsonPipelineDataFormat, NerPipeline, PipedPipelineDataFormat, @@ -1845,6 +1848,7 @@ if TYPE_CHECKING: MODEL_WITH_LM_HEAD_MAPPING, AutoModel, AutoModelForCausalLM, + AutoModelForImageClassification, AutoModelForMaskedLM, AutoModelForMultipleChoice, AutoModelForNextSentencePrediction, diff --git a/src/transformers/feature_extraction_utils.py b/src/transformers/feature_extraction_utils.py index f7bf49c400..430666b04f 100644 --- a/src/transformers/feature_extraction_utils.py +++ b/src/transformers/feature_extraction_utils.py @@ -226,7 +226,7 @@ class FeatureExtractionMixin: :func:`~transformers.feature_extraction_utils.FeatureExtractionMixin.save_pretrained` method, e.g., ``./my_model_directory/``. - a path or url to a saved feature extractor JSON `file`, e.g., - ``./my_model_directory/feature_extraction_config.json``. + ``./my_model_directory/preprocessor_config.json``. cache_dir (:obj:`str` or :obj:`os.PathLike`, `optional`): Path to a directory in which a downloaded pretrained model feature extractor should be cached if the standard cache should not be used. diff --git a/src/transformers/models/auto/feature_extraction_auto.py b/src/transformers/models/auto/feature_extraction_auto.py index 496e4d5b74..6c6a3a7051 100644 --- a/src/transformers/models/auto/feature_extraction_auto.py +++ b/src/transformers/models/auto/feature_extraction_auto.py @@ -14,34 +14,26 @@ # limitations under the License. """ AutoFeatureExtractor class. """ +import os from collections import OrderedDict +from transformers import DeiTFeatureExtractor, Speech2TextFeatureExtractor, ViTFeatureExtractor + +from ... import DeiTConfig, PretrainedConfig, Speech2TextConfig, ViTConfig, Wav2Vec2Config from ...feature_extraction_utils import FeatureExtractionMixin -from ...file_utils import is_speech_available, is_vision_available -from ..wav2vec2.feature_extraction_wav2vec2 import Wav2Vec2FeatureExtractor -from .configuration_auto import replace_list_option_in_docstrings - - -if is_speech_available(): - from ..speech_to_text.feature_extraction_speech_to_text import Speech2TextFeatureExtractor -else: - Speech2TextFeatureExtractor = None - -if is_vision_available(): - from ..deit.feature_extraction_deit import DeiTFeatureExtractor - from ..vit.feature_extraction_vit import ViTFeatureExtractor -else: - DeiTFeatureExtractor = None - ViTFeatureExtractor = None - # Build the list of all feature extractors +from ...file_utils import FEATURE_EXTRACTOR_NAME +from ..wav2vec2.feature_extraction_wav2vec2 import Wav2Vec2FeatureExtractor +from .configuration_auto import AutoConfig, replace_list_option_in_docstrings + + FEATURE_EXTRACTOR_MAPPING = OrderedDict( [ - ("deit", DeiTFeatureExtractor), - ("s2t", Speech2TextFeatureExtractor), - ("vit", ViTFeatureExtractor), - ("wav2vec2", Wav2Vec2FeatureExtractor), + (DeiTConfig, DeiTFeatureExtractor), + (Speech2TextConfig, Speech2TextFeatureExtractor), + (ViTConfig, ViTFeatureExtractor), + (Wav2Vec2Config, Wav2Vec2FeatureExtractor), ] ) @@ -89,7 +81,7 @@ class AutoFeatureExtractor: :func:`~transformers.feature_extraction_utils.FeatureExtractionMixin.save_pretrained` method, e.g., ``./my_model_directory/``. - a path or url to a saved feature extractor JSON `file`, e.g., - ``./my_model_directory/feature_extraction_config.json``. + ``./my_model_directory/preprocessor_config.json``. cache_dir (:obj:`str` or :obj:`os.PathLike`, `optional`): Path to a directory in which a downloaded pretrained model feature extractor should be cached if the standard cache should not be used. @@ -134,20 +126,29 @@ class AutoFeatureExtractor: >>> feature_extractor = AutoFeatureExtractor.from_pretrained('./test/saved_model/') """ + config = kwargs.pop("config", None) + kwargs["_from_auto"] = True + + is_feature_extraction_file = os.path.isfile(pretrained_model_name_or_path) + is_directory = os.path.isdir(pretrained_model_name_or_path) and os.path.exists( + os.path.join(pretrained_model_name_or_path, FEATURE_EXTRACTOR_NAME) + ) + + if not is_feature_extraction_file and not is_directory: + if not isinstance(config, PretrainedConfig): + config = AutoConfig.from_pretrained(pretrained_model_name_or_path, **kwargs) + kwargs["_from_auto"] = True config_dict, _ = FeatureExtractionMixin.get_feature_extractor_dict(pretrained_model_name_or_path, **kwargs) - if "feature_extractor_type" in config_dict: + if type(config) in FEATURE_EXTRACTOR_MAPPING.keys(): + return FEATURE_EXTRACTOR_MAPPING[type(config)].from_dict(config_dict, **kwargs) + elif "feature_extractor_type" in config_dict: feature_extractor_class = feature_extractor_class_from_name(config_dict["feature_extractor_type"]) return feature_extractor_class.from_dict(config_dict, **kwargs) - else: - # Fallback: use pattern matching on the string. - for pattern, feature_extractor_class in FEATURE_EXTRACTOR_MAPPING.items(): - if pattern in str(pretrained_model_name_or_path): - return feature_extractor_class.from_dict(config_dict, **kwargs) raise ValueError( f"Unrecognized model in {pretrained_model_name_or_path}. Should have a `feature_extractor_type` key in " - "its feature_extraction_config.json, or contain one of the following strings " + f"its {FEATURE_EXTRACTOR_NAME}, or contain one of the following strings " f"in its name: {', '.join(FEATURE_EXTRACTOR_MAPPING.keys())}" ) diff --git a/src/transformers/models/speech_to_text/processing_speech_to_text.py b/src/transformers/models/speech_to_text/processing_speech_to_text.py index af79e9c64a..4f46217562 100644 --- a/src/transformers/models/speech_to_text/processing_speech_to_text.py +++ b/src/transformers/models/speech_to_text/processing_speech_to_text.py @@ -97,7 +97,7 @@ class Speech2TextProcessor: :meth:`~transformers.PreTrainedFeatureExtractor.save_pretrained` method, e.g., ``./my_model_directory/``. - a path or url to a saved feature extractor JSON `file`, e.g., - ``./my_model_directory/feature_extraction_config.json``. + ``./my_model_directory/preprocessor_config.json``. **kwargs Additional keyword arguments passed along to both :class:`~transformers.PreTrainedFeatureExtractor` and :class:`~transformers.PreTrainedTokenizer` diff --git a/src/transformers/models/wav2vec2/processing_wav2vec2.py b/src/transformers/models/wav2vec2/processing_wav2vec2.py index bafbcdebbc..04f9233fdf 100644 --- a/src/transformers/models/wav2vec2/processing_wav2vec2.py +++ b/src/transformers/models/wav2vec2/processing_wav2vec2.py @@ -96,7 +96,7 @@ class Wav2Vec2Processor: :meth:`~transformers.SequenceFeatureExtractor.save_pretrained` method, e.g., ``./my_model_directory/``. - a path or url to a saved feature extractor JSON `file`, e.g., - ``./my_model_directory/feature_extraction_config.json``. + ``./my_model_directory/preprocessor_config.json``. **kwargs Additional keyword arguments passed along to both :class:`~transformers.SequenceFeatureExtractor` and :class:`~transformers.PreTrainedTokenizer` diff --git a/src/transformers/pipelines/__init__.py b/src/transformers/pipelines/__init__.py index e16e96654e..09b8e58a91 100755 --- a/src/transformers/pipelines/__init__.py +++ b/src/transformers/pipelines/__init__.py @@ -20,9 +20,12 @@ import warnings from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union from ..configuration_utils import PretrainedConfig +from ..feature_extraction_utils import PreTrainedFeatureExtractor from ..file_utils import is_tf_available, is_torch_available from ..modelcard import ModelCard -from ..models.auto.tokenization_auto import AutoTokenizer +from ..models.auto.configuration_auto import AutoConfig +from ..models.auto.feature_extraction_auto import FEATURE_EXTRACTOR_MAPPING, AutoFeatureExtractor +from ..models.auto.tokenization_auto import TOKENIZER_MAPPING, AutoTokenizer from ..tokenization_utils import PreTrainedTokenizer from ..utils import logging from .automatic_speech_recognition import AutomaticSpeechRecognitionPipeline @@ -40,6 +43,7 @@ from .base import ( from .conversational import Conversation, ConversationalPipeline from .feature_extraction import FeatureExtractionPipeline from .fill_mask import FillMaskPipeline +from .image_classification import ImageClassificationPipeline from .question_answering import QuestionAnsweringArgumentHandler, QuestionAnsweringPipeline from .table_question_answering import TableQuestionAnsweringArgumentHandler, TableQuestionAnsweringPipeline from .text2text_generation import SummarizationPipeline, Text2TextGenerationPipeline, TranslationPipeline @@ -79,6 +83,7 @@ if is_torch_available(): MODEL_FOR_TOKEN_CLASSIFICATION_MAPPING, AutoModel, AutoModelForCausalLM, + AutoModelForImageClassification, AutoModelForMaskedLM, AutoModelForQuestionAnswering, AutoModelForSeq2SeqLM, @@ -198,6 +203,12 @@ SUPPORTED_TASKS = { "pt": AutoModelForCausalLM if is_torch_available() else None, "default": {"model": {"pt": "microsoft/DialoGPT-medium", "tf": "microsoft/DialoGPT-medium"}}, }, + "image-classification": { + "impl": ImageClassificationPipeline, + "tf": None, + "pt": AutoModelForImageClassification if is_torch_available() else None, + "default": {"model": {"pt": "google/vit-base-patch16-224"}}, + }, } @@ -252,6 +263,7 @@ def pipeline( model: Optional = None, config: Optional[Union[str, PretrainedConfig]] = None, tokenizer: Optional[Union[str, PreTrainedTokenizer]] = None, + feature_extractor: Optional[Union[str, PreTrainedFeatureExtractor]] = None, framework: Optional[str] = None, revision: Optional[str] = None, use_fast: bool = True, @@ -309,6 +321,18 @@ def pipeline( :obj:`model` is not specified or not a string, then the default tokenizer for :obj:`config` is loaded (if it is a string). However, if :obj:`config` is also not given or not a string, then the default tokenizer for the given :obj:`task` will be loaded. + feature_extractor (:obj:`str` or :obj:`~transformers.PreTrainedFeatureExtractor`, `optional`): + The feature extractor that will be used by the pipeline to encode data for the model. This can be a model + identifier or an actual pretrained feature extractor inheriting from + :class:`~transformers.PreTrainedFeatureExtractor`. + + Feature extractors are used for non-NLP models, such as Speech or Vision models as well as multi-modal + models. Multi-modal models will also require a tokenizer to be passed. + + If not provided, the default feature extractor for the given :obj:`model` will be loaded (if it is a + string). If :obj:`model` is not specified or not a string, then the default feature extractor for + :obj:`config` is loaded (if it is a string). However, if :obj:`config` is also not given or not a string, + then the default feature extractor for the given :obj:`task` will be loaded. framework (:obj:`str`, `optional`): The framework to use, either :obj:`"pt"` for PyTorch or :obj:`"tf"` for TensorFlow. The specified framework must be installed. @@ -359,19 +383,7 @@ def pipeline( # At that point framework might still be undetermined model = get_default_model(targeted_task, framework, task_options) - # Try to infer tokenizer from model or config name (if provided as str) - if tokenizer is None: - if isinstance(model, str): - tokenizer = model - elif isinstance(config, str): - tokenizer = config - else: - # Impossible to guest what is the right tokenizer here - raise Exception( - "Impossible to guess which tokenizer to use. " - "Please provided a PreTrainedTokenizer class or a path/identifier to a pretrained tokenizer." - ) - + model_name = model if isinstance(model, str) else None modelcard = None # Try to infer modelcard from model or config name (if provided as str) if isinstance(model, str): @@ -388,19 +400,6 @@ def pipeline( # Retrieve use_auth_token and add it to model_kwargs to be used in .from_pretrained model_kwargs["use_auth_token"] = model_kwargs.get("use_auth_token", use_auth_token) - # Instantiate tokenizer if needed - if isinstance(tokenizer, (str, tuple)): - if isinstance(tokenizer, tuple): - # For tuple we have (tokenizer name, {kwargs}) - use_fast = tokenizer[1].pop("use_fast", use_fast) - tokenizer = AutoTokenizer.from_pretrained( - tokenizer[0], use_fast=use_fast, revision=revision, _from_pipeline=task, **tokenizer[1] - ) - else: - tokenizer = AutoTokenizer.from_pretrained( - tokenizer, revision=revision, use_fast=use_fast, _from_pipeline=task, **model_kwargs - ) - # Instantiate config if needed if isinstance(config, str): config = AutoConfig.from_pretrained(config, revision=revision, _from_pipeline=task, **model_kwargs) @@ -434,6 +433,61 @@ def pipeline( model, config=config, revision=revision, _from_pipeline=task, **model_kwargs ) + model_config = model.config + + load_tokenizer = type(model_config) in TOKENIZER_MAPPING + load_feature_extractor = type(model_config) in FEATURE_EXTRACTOR_MAPPING + + if load_tokenizer: + # Try to infer tokenizer from model or config name (if provided as str) + if tokenizer is None: + if isinstance(model_name, str): + tokenizer = model_name + elif isinstance(config, str): + tokenizer = config + else: + # Impossible to guess what is the right tokenizer here + raise Exception( + "Impossible to guess which tokenizer to use. " + "Please provide a PreTrainedTokenizer class or a path/identifier to a pretrained tokenizer." + ) + + # Instantiate tokenizer if needed + if isinstance(tokenizer, (str, tuple)): + if isinstance(tokenizer, tuple): + # For tuple we have (tokenizer name, {kwargs}) + use_fast = tokenizer[1].pop("use_fast", use_fast) + tokenizer_identifier = tokenizer[0] + tokenizer_kwargs = tokenizer[1] + else: + tokenizer_identifier = tokenizer + tokenizer_kwargs = model_kwargs + + tokenizer = AutoTokenizer.from_pretrained( + tokenizer_identifier, revision=revision, use_fast=use_fast, _from_pipeline=task, **tokenizer_kwargs + ) + + if load_feature_extractor: + # Try to infer feature extractor from model or config name (if provided as str) + if feature_extractor is None: + if isinstance(model_name, str): + feature_extractor = model_name + elif isinstance(config, str): + feature_extractor = config + else: + # Impossible to guess what is the right feature_extractor here + raise Exception( + "Impossible to guess which feature extractor to use. " + "Please provide a PreTrainedFeatureExtractor class or a path/identifier " + "to a pretrained feature extractor." + ) + + # Instantiate feature_extractor if needed + if isinstance(feature_extractor, (str, tuple)): + feature_extractor = AutoFeatureExtractor.from_pretrained( + feature_extractor, revision=revision, _from_pipeline=task, **model_kwargs + ) + if task == "translation" and model.config.task_specific_params: for key in model.config.task_specific_params: if key.startswith("translation"): @@ -444,4 +498,16 @@ def pipeline( ) break - return task_class(model=model, tokenizer=tokenizer, modelcard=modelcard, framework=framework, task=task, **kwargs) + if tokenizer is not None: + kwargs["tokenizer"] = tokenizer + + if feature_extractor is not None: + kwargs["feature_extractor"] = feature_extractor + + return task_class( + model=model, + modelcard=modelcard, + framework=framework, + task=task, + **kwargs, + ) diff --git a/src/transformers/pipelines/base.py b/src/transformers/pipelines/base.py index 63ddd79971..05bf389b8a 100644 --- a/src/transformers/pipelines/base.py +++ b/src/transformers/pipelines/base.py @@ -23,6 +23,7 @@ from contextlib import contextmanager from os.path import abspath, exists from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union +from ..feature_extraction_utils import PreTrainedFeatureExtractor from ..file_utils import add_end_docstrings, is_tf_available, is_torch_available from ..modelcard import ModelCard from ..tokenization_utils import PreTrainedTokenizer, TruncationStrategy @@ -522,7 +523,8 @@ class Pipeline(_ScikitCompat): def __init__( self, model: Union["PreTrainedModel", "TFPreTrainedModel"], - tokenizer: PreTrainedTokenizer, + tokenizer: Optional[PreTrainedTokenizer] = None, + feature_extractor: Optional[PreTrainedFeatureExtractor] = None, modelcard: Optional[ModelCard] = None, framework: Optional[str] = None, task: str = "", @@ -537,6 +539,7 @@ class Pipeline(_ScikitCompat): self.task = task self.model = model self.tokenizer = tokenizer + self.feature_extractor = feature_extractor self.modelcard = modelcard self.framework = framework self.device = device if framework == "tf" else torch.device("cpu" if device < 0 else f"cuda:{device}") @@ -565,7 +568,13 @@ class Pipeline(_ScikitCompat): os.makedirs(save_directory, exist_ok=True) self.model.save_pretrained(save_directory) - self.tokenizer.save_pretrained(save_directory) + + if self.tokenizer is not None: + self.tokenizer.save_pretrained(save_directory) + + if self.feature_extractor is not None: + self.feature_extractor.save_pretrained(save_directory) + if self.modelcard is not None: self.modelcard.save_pretrained(save_directory) @@ -630,7 +639,14 @@ class Pipeline(_ScikitCompat): The list of models supported by the pipeline, or a dictionary with model class values. """ if not isinstance(supported_models, list): # Create from a model mapping - supported_models = [item[1].__name__ for item in supported_models.items()] + supported_models_names = [] + for config, model in supported_models.items(): + # Mapping can now contain tuples of models for the same configuration. + if isinstance(model, tuple): + supported_models_names.extend([_model.__name__ for _model in model]) + else: + supported_models_names.append(model.__name__) + supported_models = supported_models_names if self.model.__class__.__name__ not in supported_models: raise PipelineException( self.task, diff --git a/src/transformers/pipelines/image_classification.py b/src/transformers/pipelines/image_classification.py new file mode 100644 index 0000000000..eb0410f322 --- /dev/null +++ b/src/transformers/pipelines/image_classification.py @@ -0,0 +1,129 @@ +import os +from typing import TYPE_CHECKING, List, Optional, Union + +import requests + +from ..feature_extraction_utils import PreTrainedFeatureExtractor +from ..file_utils import add_end_docstrings, is_torch_available, is_vision_available, requires_backends +from ..utils import logging +from .base import PIPELINE_INIT_ARGS, Pipeline + + +if TYPE_CHECKING: + from ..modeling_tf_utils import TFPreTrainedModel + from ..modeling_utils import PreTrainedModel + +if is_vision_available(): + from PIL import Image + +if is_torch_available(): + import torch + + from ..models.auto.modeling_auto import MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING + +logger = logging.get_logger(__name__) + + +@add_end_docstrings(PIPELINE_INIT_ARGS) +class ImageClassificationPipeline(Pipeline): + """ + Image classification pipeline using any :obj:`AutoModelForImageClassification`. This pipeline predicts the class of + an image. + + This image classification pipeline can currently be loaded from :func:`~transformers.pipeline` using the following + task identifier: :obj:`"image-classification"`. + + See the list of available models on `huggingface.co/models + `__. + """ + + def __init__( + self, + model: Union["PreTrainedModel", "TFPreTrainedModel"], + feature_extractor: PreTrainedFeatureExtractor, + framework: Optional[str] = None, + **kwargs + ): + super().__init__(model, feature_extractor=feature_extractor, framework=framework, **kwargs) + + if self.framework == "tf": + raise ValueError(f"The {self.__class__} is only available in PyTorch.") + + requires_backends(self, "vision") + + self.check_model_type(MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING) + + self.feature_extractor = feature_extractor + + @staticmethod + def load_image(image: Union[str, "Image.Image"]): + if isinstance(image, str): + if image.startswith("http://") or image.startswith("https://"): + # We need to actually check for a real protocol, otherwise it's impossible to use a local file + # like http_huggingface_co.png + return Image.open(requests.get(image, stream=True).raw) + elif os.path.isfile(image): + return Image.open(image) + elif isinstance(image, Image.Image): + return image + + raise ValueError( + "Incorrect format used for image. Should be an url linking to an image, a local path, or a PIL image." + ) + + def __call__(self, images: Union[str, List[str], "Image", List["Image"]], top_k=5): + """ + Assign labels to the image(s) passed as inputs. + + Args: + images (:obj:`str`, :obj:`List[str]`, :obj:`PIL.Image` or :obj:`List[PIL.Image]`): + The pipeline handles three types of images: + + - A string containing a http link pointing to an image + - A string containing a local path to an image + - An image loaded in PIL directly + + The pipeline accepts either a single image or a batch of images, which must then be passed as a string. + Images in a batch must all be in the same format: all as http links, all as local paths, or all as PIL + images. + top_k (:obj:`int`, `optional`, defaults to 5): + The number of top labels that will be returned by the pipeline. + + Return: + A dictionary or a list of dictionaries containing result. If the input is a single image, will return a + dictionary, if the input is a list of several images, will return a list of dictionaries corresponding to + the images. + + The dictionaries contain the following keys: + + - **label** (:obj:`str`) -- The label identified by the model. + - **score** (:obj:`int`) -- The score attributed by the model for that label. + """ + is_batched = isinstance(images, list) + + if not is_batched: + images = [images] + + images = [self.load_image(image) for image in images] + + with torch.no_grad(): + inputs = self.feature_extractor(images=images, return_tensors="pt") + outputs = self.model(**inputs) + + probs = outputs.logits.softmax(-1) + scores, ids = probs.topk(top_k) + + scores = scores.tolist() + ids = ids.tolist() + + if not is_batched: + scores, ids = scores[0], ids[0] + labels = [{"score": score, "label": self.model.config.id2label[_id]} for score, _id in zip(scores, ids)] + else: + labels = [] + for scores, ids in zip(scores, ids): + labels.append( + [{"score": score, "label": self.model.config.id2label[_id]} for score, _id in zip(scores, ids)] + ) + + return labels diff --git a/src/transformers/utils/dummy_pt_objects.py b/src/transformers/utils/dummy_pt_objects.py index b4b160dbe3..158c7f7381 100644 --- a/src/transformers/utils/dummy_pt_objects.py +++ b/src/transformers/utils/dummy_pt_objects.py @@ -376,6 +376,15 @@ class AutoModelForCausalLM: requires_backends(self, ["torch"]) +class AutoModelForImageClassification: + def __init__(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + @classmethod + def from_pretrained(self, *args, **kwargs): + requires_backends(self, ["torch"]) + + class AutoModelForMaskedLM: def __init__(self, *args, **kwargs): requires_backends(self, ["torch"]) diff --git a/tests/fixtures/coco.jpg b/tests/fixtures/coco.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d32344928e34e22bbf03227e8852c079ff095627 GIT binary patch literal 88476 zcmb5Vbx<7L7X>)DySv-q3?AIw2X`5q;10pvg1hVB?k>UI?F;S%O#*>r`R#6P?f$u^ ztGc@SzIt`5?tR_&o_F5A&41qk*h+GWasU_@7=XgZ1^BlEkOm;aBOoHcBO)RoA|W9n zqhh0?qM)GSV`8CW6X6pR6X6pQl2R~Gk&@Ao6B1IhQPVLpu>e^}sMxvKnYkF4S(yJf z2@Dbv5-Kt(9x5sxGbte{^Z#%B8v)=T!+eL;hl8O7z~aEb;lTVG1CRj#uyFtL_WuDK zJPa%X01@fKNc>^=|JVR9AEV*_Z3EEZKAy1QumJ#=r+&YQv8b>$0n;s~nyggl&~B(L zfiiT{VTrbGa&dYhdr=~z4294@B{R+dY556vn{R2Wp*68;olj3*DDc0ypM_WkE-Y>r zv9(@)i8epvW4>l;S{eY)<|7OhV$ucIe_F2*8@{YW;-C0Piykf_%sS#Hz=3E||MUs1 zFPR{LR7y4P*8KbS>%!7x%76q?3cMMZ6`-LQqf)+HuHMyjeCe$`{UeWpz=k}rC5sd# zMsqd)iUntPy6yRrv;*n{m8;p`gC0kn5x)X{7 zcC=8|^b8I$+ZextMT}HfN~0W1lL#S2+^o336tc)3f5ZC#Tm>Zfa~_M}_{vYZvs@kq<#v##z&AP-(Q zONb^H)@TxwN583R44KiSdF_(Fpr_@soh=zWdV$DRELxh7870xb%lc zYrWLc)*L&b^-=DSe~s2NyX_C!Zsh`+AnuCDVtN2ci;c}|usSZ4b&u~_f7jKS)hnj5 zpRbo-e3IQd4hF%h0Y%Uk_KL(CIeYHTe9f=@jiYMWrTG@qyA9)5d=o*GUL4J@?hr!1 z)?TBi2-BAxqVi%bXC;{w%XCZ%>r#S5iM zlzcXrmw6&Mo>`1CmCU!S8gf_xXU_-_sLDhpiFDcAX<&%RGA zxIa&v)Ll7#lAX58A9TGZ6v7Xu-j3+dFe>*gON0ztRwH97&=s$IM{sRCl1yxCwe_Fz53?LrXkQkeUJ)gw+5Zz3B?BCe3ElhJ( zWoT|98p~{d0P?^=V|r?)uuL zT3rKEIvH&xdXi}(%$Z%@wy;r7%YB=>|6>hkD>EN)K!D7lw?G(IkICRixo9yw zs-Npo@Vc^BNErD}ZeO$Y+e9pU6D*b_@n_f!^g_by87oK;^Jz~CH9ptQ%RWN^VfhwAOWOH`=Ol%Q@VX z8{5~A-dE0B8JJYz!RGuyC7m#`kehXB_`%?cWQE(|F5D#cX2)ZK*P2nRSPQPN3`LL7 z=6e-6^EWNG8{_)j1`Um)b>wZ@!aG|{8ZGCcm`p=mcF?bgwscSK)2AHpXym+TFf}nD zoj6!sk8CfnpKiKhK$8G{`sB9Q6Vy#m&Z}8}{YA0>6!!U1ihf)FT5LWC0{EYshVDsbLoqmxH-^PIA3jM<`s0HPLnF*qZj(?)SWy24c{?o zR5s0?yTdyUK0zpT>!qS0exHdfRqM3wuydV{x34g>b+GlsTgYp3;p+Z6#!uwpl!vz6 zohR)gOe9D6aq*knpObSw_l}pJV!4JntCMR{+(zTratNG5X{=*6n}kX&DH3m+68sPw zzdDsPH@AOU@w?*0BzQ)cWE+1vG|V*r9Zo2Bx2MQP#mRY=(c_fbYhMPaS4CGoCImPA zIX>?iFWI#>yV9$o0R2d!{Tujus=5UrSz|4q(WG{z|CrbKW(E7}xfRPdhOY(+iU}e^ zoaf)K>nHz{J?gD7*{JX_gXWtyeo~7?@>*Q&V&!8>XU2iww7apq64DK8Y6Mg^)W}QD zN*$Gr^v8Jxc4@Ev%3roRi+61yf4V&i<_%u+Fx3*}=b<}~Z0`GPdqYHaAJOgWRdIer zT^Pm-j#b2;ZW|+ZW~H2Dl{pELG!rfp(%TP`?eq0_du1g_dfZZG{O{97;|9^?I%*As z-G7u2b`7hlc0r3eVsfq&enblW%8gYSBV}TFW?hTAA-^}n!me(eH^mSQwW9~QYH>QM za^Q?(i`0;5;@q$?(a@jXZ->&+py8G;$n>)_*i~jW-00ioT>F(0aWvtIe}fS zcBrL2@uFe0TbA(r#B;E6BipuEQPtcNr{d#3fZ5T{TYdU6fb*NLBRO)a?CbykIT>O6E?DJTH+-vpw?`QSC z09N`%To+DxG{cP&(|aOvgV1k>U@a_})jOp#@mwJNyaQA2HYtr>y6hI&;c1HV=#qA$ z+u3s8K(Dbtu`;_mJkcYFNaRmH{Y0)9P^Z-|nVd!0IltvYO{3uc7w zf4g*;Jij)`DShbi*wd?`vEn@ z+YDudp>mIL4soShU_Sx@otJipuPKa!DyEsV5;lZ343(wU92$a2^B5Gyc7lJ)rpJpR z`|@B+j-EX7S9=@6@b+_VexI??x-PuhQ9H~9ev#V;zx^i>A?tphT%93ur)23g{loRg zI|d5Oh>-0V-3-SfrIzmIn$la9y z0*f9{Le;04xD0cs5~Xm>_+=Y8bz;_{rH0zyPZ-iKp7>Mj6AyLMtH(eX(|kd3!Y9eX zBANd(pM_72*tZ(ZD=2*~s6_V9{WTi398(U=r~fm^Zh0UVy{;aTx5g+et7UZE1|tvY zpRH$xo`Oh zomdI@$wq<;9!&FKdyN(xg&N{Mdz}ABd=_JvQmF9>%K)!Hwzf~(Gq;v;&yjmifs|ZP z7@BnrYg|OBiYLDfEyLG!X%J}Sr5T%78Pd2os&i&KO1Y-lJTBbQh4!AXyGz5K6=N%0 z8z`(389Wzlq&?0}MA9g`Eqy%0|oDCH=mR$2>(5^b-K zn$9dDR1^Oj4=_U-uyH2rocF>ksJ$*}GD*E_aCp{g2 zCiFAg+MN*k8tO^K*xS-76?nD+K?S_5K4PtEB&BouCAux)Vetkv8$fZ19WuLkY)=OH zM`$c`-K!gZO-Dj4|LO-)oQ?}eWh*Yqx~i*j+gw_)BUhH0!ICY-{qtX@ofYAit)QsP zmt&iE#MH+8eRt?mB`up$do-_+>y;$^{*2~=b(IeYziYiLP^XeVcRYffAx%h?kJpN+ zBtKlZl7g6^d705lxZm2r(9148ULw|1T0f8-TQ_Z&yTA?yjugnwiGto=XR{&8(I*dE zPFa>2M|@XbVBe~I&d2k6I7mQhz^w79bs@E}uIV?$&1A)Hc^MeP?v89NGVe@z`9+3A zW#{!h)!>hra1CvRX;MWZs{@lK0ilP8M|uECLvi}LwqlASHTC6Ocm6*A9&PsSH<>3d z+;#l%E8O+CXRdt@DL3A_d;G;PaFwcGdysj1GM&1bv&SRbYg$#7K&^Y=L{_n7^MBq) zQVQo|bGn^3$1BNh>V>BpYxeigj@QsYXYbc_frVtsJnCM!@Z0A$1%!Buq(Y0$pCt*^ zIKly%wGN3KEwq}b$bN|oBtnG+9MJ_>rBJ_I|2_=VCT7MH`}y7PJHnR=sXya&?keg{ z<1+C?c)hMTSGW|rOHQr}SNbNpa;}?mpKwmwcKcYKV5?$(4Tw&|WR%zh?4@a*X=1ck0czE&6B-_*}hbvvRtW(#mj4R*X~Fhc&%k3(|uX6>GiNWhw+? z9irlKc$JKxrJNWXVrc8FGG_t07(>c(^-kczdPDm;QTy0#IDY6imzo=;#uEQIGnePn z%;%cU+^R0q4{v@uAA|meYTZrzMBhlUUC~W#C{NCMc2J3IDy-1##D{BVxSlPI>;o(q zf-4z&SpDPmok8T94sN9FbeMboI_sAdr)8E}=X^WxvbrXr=>NnYK&Xd(zYs!45Zc6znI-K=!{ALuxaDVlU zGrO&o`hTj-@E^Z)*>KS64{Ym?G*qk`!KxkIvu{|QYvIY$b81N`E#I>Y%`w5aiK1nx@wwy2XE> zv*>>SX2HUk=h;20%qHR7& z46>B-W=e0@h%+3Zk_wUEul9H+Ou?2u)r(tXq5GWhyF0tcGb)K72)-1?vIwyilSf^t zxJ_#q>eOB~(vBwP{0~q?WpN4#j+n*3S`1@#ze~dRVAarWVGNO#L~6w!6RATKd~LF3 z0_l4ssJkWstZj{FxM&|0AD~0UoQFqTp#`f3X0Q2(nzK^;-**dDMseQE$vUfK*xeSq zka5@7x;b*|y?qA|69RRULAI_wx?SKx%tLl3z)n$Cd7njWjQl27Pz+6Ia|}f6Yq9+;F++}4gU7)4GgL-8jsu5v+p&XzqV>B5Z1aW9@2#xT>7BdM z&CleSVB+}S8IV@VG$W^s%PTXNmP@Pi<~1fK=WT7RrWPL-;FPWxsAuSx9@xv{^N}-} z^ropyj%G%g+-p0V*3S$@u z2hqno7eKSD_hE`s7BWMi>v(OstXbV8B{tK$Y${!B=ofTWMS^ISj3L2eo8f$+rIDnp z`*uF&z*i8m)FZe@CSP4g9^?%Ai)z_c-@Qvp|$zSz7m6*?Jwpe_N{0T z>CA%cHG89{mpaeCv;~>aCk{NFA<}TdI;lSRP;@a6p8lH0n+>RG^a84zPtUno z&CrOOTQM|8z=yMLs1`)RN8P4=ow@&6R+s7ubqv5a#TXUzc}LA-M1Oj`q!H3ua@HgW zR~bgZBUh0sl1o{FPC87(#k{ktQXQp#`#s8jUZ<~_35RpK+#7Lg5!uaZN56&8>>TlE zjOfpLlZ}jQ`?@ZU+X|C!H>yLT-?dw)c~9}DW+a}H_0pbmd<B2p^alp8{Y!m%p-46K9@6l}cITve2Zesz3RU zvQpq1$s1wO%MH>*2iy6N2G}WtmHzBT-1Clbf>4U3PeaPLjGp1FFt4=1?Acwodm}^) z*uI7{@vYDzG^FP*`yyHBc-Eof^ZE?wzUQOC(QC;ywZCX)+3aT(m$drCRGkSq(WIfdSup9oTq7-x1O}m=gcb&f zbiT#i0SYP_mCKlN?wHH-jB3y5L53du#EisM*qbUFyq+co_4&?(g`&)&lc*<78QbXF zR3rlm-`0(2Y_X43=7XE(hp1d*d_xk7YD42!d-(L=M2FdGC=C|bE`#Z3?ESY|7#E2% zEj{;i8FZr&okd5-G*jh2+~q6N0|Pomnzg*b=t~9J-uyQW7b5hT5B!H!(q7m zpV$&DqW^oF-?ws&H!CpK`VkrlvE&|T_5&7=e`aviX)u?dv58T^Kwsx}Iw;0Tmx>s_ z&&f_SoQ0c*R?6i4&19 zHZcI3n7QqY5c*-$Ha~VB?DVJ6Sy_c(IbnFG+gNfgk-6cB85y}TRn9Pde}S-P(Roxn z66VnHp8P$Vp#5xF$KQ$DFKylh-PYf{ZPNK{i9@SYSJOoWG{}h=l~pJ(-R0SQnli8( zrouavk?JxwW8_H7n!c-iYvsOP2Nqn?j20eSlj`?$dSH{2Ti4*2(Pr+LlvT&J?loQZPz=X;Py}n=4aoBSG$+6Gg&sNC~GM8v7M~l70BjfVmxVZHD zGP*hn{k>CNSV4p@Dxgoy$ul?}!~)OBou&6Cd8!{Ru$FR^*158|wpqW|oYxUGq83>F z1~uLak=KS)J}8PUb*taR>b6v{;-JpD?O?CPx^E+FeY=Vw<>vN?6r;}f0ieyIHt7*S z()4wCNNQjwhHb|%at3Je@JB$%{{RS~C1Z44XB4w4r~K#>G{Xh9<9cqFJ)fApEE89} zDg}6E5$hmB+s&B`Ex&GHc^YKv!NX;^Rdg7=8>{!6O?b^24K}EjR zH!*DM4Aqu^nbfA6=uRz;vF1M|59azji!?Ea6MLv#miQK^HXaEwLLpdX$Pp7HxrZLy z)5ENwn9-XibNfO-evB8B<|p4gOLML_t9l=_zciFyW<)kJ3CS{zgu$O4a&89Z>kED~ z)o4}19qIM5Q5(8PkkJrl6go`DHGR}NFJ2wEXwwToLr>K9c=VezmTide_RxmmEJ_68 z!si6HYMaPbJZ?-{;(9z<^kM#x@Fy+D)X53qHm{Jm(v&5M5KAkry47(hGMrc(m+yig zz^qDBUahLk`<9ww^A&K$`u)&9iYJWMH{9HFG}K(jM&}mP-a}w(({uO}0Pl{*IS@A| zAFpRBd6i=z?uF^^l3R;(AL(#F$i8+qRS_s9P|zL;$ke4UZKCo9Rc&@C}L7LRn@21s4P zq0VfxT<#}Lh?Uf7MK z*~@Jjgw05J+!on+mJmxz815&UQ}JTgJk?CA1b5MVg5k+SylQXQ-G2c4%UW-5VW;oA zmuLd?XIJFfIKSL|J%w(@RIyYOL=P0Yh*=x9PMY?qP!g-0@%JE1UXtA&WT8#mm<;ZN z(#CG$xa7$5rMBrgFn;eZ zgqwvT*&J8XtH>J499OBHLkewuc& zn>z6F&9A$K_=tS&MxS4D8gra)*pVq*KyT%n(16ebmM-K z5%+!F7*BiMHSe|2{L*r>mNZ9JYlk@cmAGS1;qTxsl_U1uB{AuV{#+nIhA!`=@WH3Z zQA3$qH7=czO2?xuZpm~lXNT7yym5;_wfn6)*x;hhT8n`eLgy&<+9MkGx&RP@Hn6otQ%A|G!W92X< zXL&oxrJw?v5(c0zNrv8mwSonjB@M|9A%nMw=cq76V?6ZXj}K<>u7wXB#ac2sv7U7^ zaPkjdH~0C^uW#EqQzW5{UXEHubf`NsvC8QZfaQIlaMr_~0a_1`?nziOeyvf8y4c|3FA z`g!&2PSTJ50uvt|K7xB5()SOr;=!|nhOgEOU8y<`mi(zA^OOchw`HG`KbjwoVG+)R z+NHtG7gK0c>3-RVQPwDsq>MRN7b!nboM0esDZc#Rm5B8lqL-tm4lIkSLD1^g8v)g1 z%Cc!!OWhb**B5jI@YZt*C+0zEbbnc<_{0u|h5j_TJCZWOPD}@wi%!Dvei?(+;ey8r zk6kOXvTE<%9t=VlKp~2~k@H#r2-==|E4 z1T9=x2_4%bvdt6dbZ3B+y2N@om5j{}n`_Gu&7}sdP{I(#5M>rEj_dVwnoL1LyizY+ z$bR;hXMul!mLZ#S|0u~7^leY+7VAUj>@7csuwIex5)&|y+Bt^DdYk^q`fwrmej<;qrOw zexCo50%>af57_zJiy7gU5=Rh>r5{+~Vc72KWHp#SgzeU2V3sfLy~>D?d zBSE=#>-wT4zyZo6AKcPP(3dOxB7l>{y@ExurMq)T%{or=Kkwq?hC$z+f&mdmXm}sw`4< zo&vGa=b3(UayBdz{v_SNgkH?i^&KwBe4U?PcddceT9}2K5P`Te3N3S$x~FNu1K+6M zM4x-4p3Q^uVl18LCkc!>9Wt!G2 zs}8a0;m|z!aZaT4#C$F!S@&6# zW@A(pPsy>Cw?I{Vo9T@@!=D)(QabJ7s|Bg2?x;7t4rm~2CnGDHYzqrZUBkyZvW)Y3 ze(fcXl_!%(f;%p4Gm7WzTYdA{o4)SAI^$VFbCOE0P&acJL?Yl_FPVh3JnCs*=*}1z z_xRp(RAXFSIV}8P>^mVI`MAgkm)}UHRz}>6EjqvE7+g~8eMu`7o;JIwf^34~p9y&d zBh*%r9RiXw4=_e6LIyP|g~%h`szCK zm(3aOQTLsLuTt{fHW$gif;C<~H8ZSeAhIG2=P3=3%`3zCUS{WBnIUa&hC<}7YL(?E zj7AX+^x>=LLb5L7;-KDySS%)?hG+Lbo!r-IeW=lmtlCA=R}r7xHmZN0&Q-J$ZBzqt z9uCoCF44v1K$eusz7v9(*2+ZjPDze4UZ}EJgxMq(=(6bzC2|lS))(@uG0y5@+!qux zkJ$mIu6nIbhF|x3x40+Z7KQtqo63)FlGCJfmy6^RVJGvqiPo_SFS+3a!x@Qh8tbrZ zkj7Dx@74a`DBs==$RzJ;m zE@Hqt=wx&MWgQZXRP~bKaMy?6SZwOEhQQvINsD_n7zAxDH(6nqmem=N?f|Q@+I3+& zxn+jgt?Sp+9bXXw7=mF(Pxomj_}Iy~o1e|VKOfD-SjVeyrZTp~e{`V%4;y(5n-T_K zN1=o1Y!j)&P67NE{xahV|LwWK7FO=1BcOqM*z3kt?4qj~pq5lnwHvT+F8dt^M5i=k zXmo-+9Q6<`$EE_@$WEl=?jG*JH7y(kyH0-f-lNQIZIQjHVaX;1^Iz0fX^bo4E(5f7 z4+!{9#j4`NCx-;|WipJK&>RzBFh>vJg-3+Y?KakxhocF_L-#+xu?a@OkcnC~pZ7cKg(i*Okx?Wa;JeV+ zt)=c;YI6q-xJlI2uzk|tPZ5o9^!in;)_MU>2>oC(2JvHdnT(mk`224XWc;?egHkbQ z4sPdNU1U#`miFsni8tv#08Tv7^)Kg6R#rCFwnHO|E_bgDcz(#7gD!zi!230T9@Y#y z8sb0y1;5xkUI#wd9_`IMzy5P%WT4< ziJvHdRt=x=9x$3Hl)spn#)a-hXi;LH=x2VOpky$8AD)`j59bIh*zEPk+-uHPIk2Z% z87@F?4jue_UH!wTIC{sD2ga8BH|eQ4N&Z}@gA;6_A<)@P~neroV~FA(kN*QYSybeA@9Xh17Pr zK=H`uQE~|yO8RUqLu?F(Xm*NtRbQv$M?z%trvaS)nsv7MYb>-Wba+isSPx23n0)lKuAYwOHHfv`Z%eGB1!dJx80(Lp3FcP0z+J1O(M>aA}Xx*`PAef}gz`-nyGrzqhcAlV{0%oQ{v#KtxT znKh*q^r>la3eu}N)H{|Ppyr<$eP&V%Db&SO4F^aHdrp0R_ROefCVO+sft;uBIdlep z0u^j`8zOrUbWrsHItwfs=JfFs^&`EKyo#D<{G%vokzM2SSx&LWgCGVsWH?wq1x}JI z1v3ArR#fWzb}8Hc(z8#}AAmKbeRQ2UN~y<1+)|3YH*GLkd_~p*gL{kWHBlV zv=b*0j8tDf^bkUSyLM;QC%-IrQZAG=<-L4zD$lXl4rudWqZBtS&6bD%os+Hhl?$G$=mx1&al>s2()S%+!24fHvP^rcF!}6 z6D$5OuCo(2p6Tor)=tFpZOnv=n zTw+FKlk}ZmQH#Z|KMTu+4!^9N62}_%U--5b)G*q;_Bbt44*5v~W%Hkl-ad9wR;nI^ z{d?Y(4AeCQLD^Iibr6WFjIq^I^EDd&wZd-Gy1}s6_xRi3saL$k z_o5Qg;MPNN^81gXhE~^#_=w%zQ554OIkZzK&n+9B=?VlA3^`@FZ-c;rSn4+YRn~+f zf{y}&7&gkTlL`-XItCLj$&RWAlG=lXEBY1}>5xmZzaLG>Eorm`To&uu_vfX`LBfFO zx0+JAi2CrP`$1k3O()7uXd!fdNT%v|+_V!SL3*(rwwJ*r)KiM8>-fo$|2~4qcBFsRgfc-evrmL^mj~k!_3pi7e*eu^ z@>kMDSS9w(cH>%PozqV=G@tc|eeFCJR!TN_v^k-o@LJQm(><#E?O%hUMQ?CM=s#B8={ZuGAONk}~ z$OACW4v~~DT0Y%*-U|m#zbcx^;+5;S)e(en^Myjhx}!mM^EB-;!7b^TZ=EWsKMM8# z0R&c?I-!@G8P5{6yM&+jIAq9ds_P9L}hN-~f z`0_2rDYT8WRb85^T9^T)uVg1z2!Cy?-VR3J<{~<$wiT~_F!baZ5?aBd<*az>nzH`h zV5+<*s?<^ww}5cTr?1M4HK*57SRPa&XRP;h+z+ET9)KS?ekzQ&=cho>X{kzJjzHpa zRDEAUb29Stu-s{(YS*`ttLB=%_ATECt10~3Oe-Mg7A)}&ZQ<%VSnATb*H`sZFL>fl zrUGUbiEEp--lP0}Q`sPG!b)y`)@`Qoeakn#^0m7vhXD-k|qG~7nm z1Hn=J&eFl(aN>{5CAUQzQnvp%>4boZL5QjhGs~Nqp{)MEcw4oFRZ$ugIiDfW2gEJ$ z=7XcT-Z{+YRTv?`8BJO%te38zub*XK(P|CFQ_;v+3OMzmMXmG@`iXS^0r*zHZ*jqN zwJn^(X6e7-@V;N-4#t+y{2s{udM_$QbmZ?3#HVM>5kz)#IR-ld)7C3k-gvI@6P z@(|LFl@B-Vb8_;7U{bM1NF-s(bYxiJN3!Lb&C)yZDlgjvp6NOU*;g;Ln|q+b9WF(s zi=RWkCg8#HD}5Ep7TnF&|5$m<`#2?lREy&Z$x3dN!ZM11WZX_=yx6O&bo%=pcEVo5 zwS(;vOmigoYmU}tys2rotweP+aGG`^2*a)B;MJmOCx_V^WbTF`8c|g#>>@TMV#urRN@S^ABdma3Q z_xJgguH{K-N7x(DApd--x}Y$LvDu}PKeG#P`+zlk9 z`ID$9zk!+BJrFf}BAW^VgE0VLyKFj)7YJ}Y%dRr_6jH@9t2o;sR z&(1EYdCe#GjlRva;(ii~bh1FCXf}XoUpUFp_zF%E=aIDSoHx+$Bf>|LhYUy?d?o85 z-?9>LV+xl{xK2W#fyCJ?r~(VVVAu$7nuoNnPuFBSM9OJ2IfHn|-mJ*KhLZ@bLN)f( zj6BGyYVzG+hJHPb>Z^SFeS=i$!9Dwp4Kir_4l{;5d-{aV$p%AevA%J zY<`N86DI90sxl45q|ivOC)v&o_pTj30aiAqHw=6A^E<-mX@2tf1Fv!Ha+hh}xTfnP zFC6JtPQncVaq$yV1*kS-0n4QJztb^czpswEK4)*Ai5n(-jlp8s$pWI>3dCw>j|dSY zT^{_9Fr6Nf$5g$*(mdV++kbi{xU6*~_k!yp=W>KciUFY}w&TV4<;pi&sH@wU%WgUS zm;Qp`K+Y9g4Z1)JIaH9jni3}5a0o|FDmA3=4YxUp2A+evIu``8DQW{bvyZds~n ztI7dRs3Pb{-6cjub_RUs?WH z)OIPgC7#@?y|SM95AdO4pvU>2is1wQ(=hyBfPuxqrpD!>;f9mIlhmZO_&?PPA7*hF zBKLCxsU=+Flr^vZAC8=|kuA1!RR1Y&zq0Zh{6LAlj;hDic@F4X8atdv{~inq7fjcb zwR|YdC`#L(3<#isixaV&xVH@-9>zK%M;*5un^$NrFX-2gV#lQ;9kn)i5Pp)}Jk*Wn zjfNK_s7gx{r#}4|z+i1tk0Y}_EeM~ct+7^Ocz3Jcf)PbjmBziCF><&v-Mb6SU@*G6kdzMUh z!i-$JWyf!eG8ySI$NUCXEzI(`9d@NXpDVZ(?mS99Js4$`NWZ!YrgI{j5ZH!4u#Ro` zPsih<&K8A@jbD|3PRv?=>V+u}{W2wh$bAHvNel*{M?oWKMK?SN%ay!?!%e6(}^GF<5^3` z&0Fex&yFmarfe@tp7CD|fKS}k3Kd*7ovmoC(<~$<$Nt_y*D!)VAnu_%3#$Q^0`<6$KHX92FuET3x&l zb8;Y2tMG@09>Lq|4z1VAK}t{pJvg`uqkWxTAii_^&k#W5^xj?npYhXo^&$4BHohX5RS^BdTIfV51P zJv&DkoCsT3&Gairbr}j%#U;Ye_;4NTU z$tcJ9A;+d-3kTmPMmz&`>?>h=+?8)#I_2F4MT39b6efZc`xrbIHqBXUE@ zrzpj{)cxolHVzSiHq^{_Z3$5~nmYRy`14Tr0}bD{n_p|%(}O>G&%kQI#1}mUngz1h zuA%s)<2hIn7i(zqmB5&6aB))_CDW32CCSvB3~(#3z&n zXGidNF{n+L3!lEE>qQS;Y)ouSTx7JA-4_%U4|RhjOHP`l3SD{8Xrgqd&c?qpC|Ct7 zF6S00q=Ag(-o_HAITfq-@GD~#TOn&&%+=P{jgKuheTHAQzH!eF{v>!d$w1NDumMr= zE*V^SDhjHmB~nBTvy5WUpclWCNGF$EHlxnUFmEA!YOjmf4I-?*8`GVP9eq%B!9L#v z0xC9T9r6&vzvTL0w6lb7Oa3*_E`Wh>I(+Xf? z_j4N<@{~>Uf>wwS9f(xGsoXV+#p_|5p>4pl@YAMjm zf^|~7(poF+HSF^UCOfIkLkZaEKP}_`0FR#j5$I}1o~|&+xry4zMtnl64_g+8wje28 zErDI8^Bey43!*RpX#?txpit@3C6`H=)m?OH3{SBjrRlIGp zu%z~Mo@b&RT!(?C3JH~Lh8J3QG#ls5I=|G4gc%9~c~l2k!cnfc{B!S|SPfH5yMd_$sN`njXR0+N4CyQk;H+#I?m3@;=#*>Fw_)D6%;Yt$<<5p$5)Lvg`CJ#&?;Y$oDZkKSTM8-ZUKCaB z4#pg$yopeasrLAhJ<-y@ncRVC`!b8*L0L}k0b+R+A%Dh$S)%A4!U3sO+38}3af4p! zvJpe|gsEbVgEN^<`n1F3VzB?EVunj<3FvgyugrF=%N=8({JqT`1^jM;I&qX1KTE;o z{uon%qLs477~-*Q{;sff(XV%gk|frw@t6xE5XI&0xe;>(*X)%@5F7eP9F~s-$B_>q z$VNf8ni}EYrbqIGxSuC;rrU+R?*R8z0Sh!U&x&pxTaW-eqLnf zbs1|Fovq@7Es{s=RJ-W|NBQ6)GNCCXTQWaymWL`CoP+}*AHFPbk^QO2! zIq`PYfH54yjO?k-A7a(BSrm|~H`Pi})VqSYAYCHm4mIbR`Z7;;`0FmimGR#?xsmc_xB+nQIo#aud~U^8`e8I6HH`EoANjI4TYz2;@C9y}p2OYi`De)6w zYp?*hysEs+#cLU{v1%xgL~xg;C6eneM_gCvXPNc5_KAp#mP3J<#ar^KZDMnblx8~1 zHv9_0Wqi*_FnI@Ryl&!p)s)_Eg9MMRN3fy$P6k2xHz3;_7&R_#x@cr<+>%Q zAZ0u%>`2EL=(<@FwNpoj&Oc_N>ZMLw$*o|l+1r-rS70eeaNgk=qv zO<8CAk>z)nUr36N=`u25^4=EN}?-K?+d>X7MXWmeS zh)cmG!-Q97*UI8Fk!RJKUh;jc}qo;i18>l!2l4JL#v7_MYNI35FJa|Fy+aaXbMI#rCaic{QAic6$TPuR=Cfg74bx?BA*&$X05xV1&L)6A@?b{_w;p(O}<-h}>TtcSLRk9X@ zu`TfAqdKocm5x#_BwS3^6cRufwVzS&isq#p-@E72;xQ^f2lPdzHKm>@{N%r9$L7aMag!4;~)MN9H(s<=rl%>%l7Vcpv7pTUY^ zc5rrvY{it9Zv3dzx)qQ?AajNR*bFZ&%r#QcL};e~^`4nVvP9S!LHN@yA*}sK5*1%5}7X3T1&o5P5)@kK`&YpibfI3c*i~rRE;wr zrYXb3T@L9W%HBpDL&0y;kko0oyt`R+snV_XL_z>B@!QL&O2KKD?kN^8$E|K@9FSr7 z`Ib#V{sFFQfoZR7rkwP~BCo)AY&sm#bVVJvN1c&R2u(WvYYugyeg;NspN|`1oJ41s zb@Wd7ff)|fbQwYhHU!{b*BFG&HF5*?otF`k)LV*nbEZ>s?8K@u%(=^UeA--RHn`#~ zT`ustlF2`otZ4b>?joa-+$_}8~r9=|-!x;XX)C1uT zi<7L5Q|QBWQ_{OqoWgd~02QC+sZ{5j&F9>^-esc5<6D_h1U`d-+HtaC396QcUMP^I zR^(5&?!DF>t=v&5{71>UPg zKqU{LRA}{31{R_k(x#;MQN(cn01%>-RjP(c+p^FNg;qw_s;CA1R$>~ki5_S6vet;YZO&7fK;VWiv`DkxOh= z7qsA$hY!&-;+`9+F;V;@f#5uNX@2V$v=Dxa3qUe5$LrBzamM(#UMyc;S0Q4!=%Zin zq9Da-JF8lTdEsD_pjVe2cU6>dnC`qyg=T@>LuNV{UugdTDPAZGE&DGV{{Z4vk=cA= zcDj~@NT$ogzKirxiNnv8m4qttvZN}gmMb2Btotb zca#UTca*88bwOQl%Bh}&1z8=8eHDVC;&xRBwi3UgS_#xaX)>^SY#XbDi5aTG0)+k7h2lPnKUMm2 zy%YxzML<33ebqHzH3w86049g30JN1PNmDae>bPNp1{2wMIu~Ef0gcr;u^TK*cg0b% z07IiNf$~x5?%fqJod-JWF*0ZXSV@rNTpO7~MeeB*s~%-Qac}sAd};`f{ECle;pVbW zVpM6e@Pp)|2y6CmR>S@#P=knem5Kn~5QT3rrpgc1NRK3QD=037Us2CqTc~hX17R_jhw_h_?or!JiPtw7aj8!GmYn-G7uLbN`q(qKC0WEkg$Qd%`6Y_eN)9fgEw z5O90;BV{;?scGePN-q)hS5`p;Kv+2ZCh-|~CKEl2a1X+#56w;*i$Ow_?ypbsg(3au zwEp%&U5B+*Fh9x)q^&%{>FO5TxAQ^SrB?b;RY6`KL}OGWPSiv8qOkG{FZ`;4sq^KU z%0cp7)>lF}zN)9^RpNAPRj1@uzG~I#u6YR}KKHVR4=t2lh+h7SS)mlNu4&6V1%=kt zHO`~hWI9uy!xt39jxmzCl=xca)|Cz2I}yZs>+iyXvY|jwlb5=qrJBXiq>TtXvcdYP zYh$XAAgO5+s5WEsXh5x0#A-y!5!nnO#0kW*oHC!mECI|i z-n#myVR5L?_)5&tBC;#;PHrDds$%<^DxfC2p<%kAh()|2OdWMjsh+D&%Fq`@RYI>- zDo_mwPpX9kOM0v<^eP96)k6>~4rY~8T}+|zR?1@jiz$j|wE)tHgJnu5X$qXKWn!GA zURtULnzVONDt0R16&znxAkiHPg>sH2`TN^@mL#2(OgU1eIKt}`8>+|bv6{!4cNSm~ z@=$Rx$D)R~80@Oq7;m~VO*;Fu_hq+0Sn@nJ9_2qC+VZ!W8BcX3z$>@O94&E#(YdTD zb}PM8I<0)xs4>x*4`W`X*H+DLh+=`F%0b;6UJipm7+`72yrLniLCzqnq53ZuV`NP-*;B%zNk6t36Qe~Xz)N98v>=P25h{3);nk}PxN<&= z2()_jQ7*%xxq`enlVgAYsE^%e5Ju>5_(jZg z$yj*Ko~M@l@6Pb26%m4=)l@)9s0P&BssoHzsqpOzW=L$8-4CoJVH;B{3E)NByS4QD|9~&l)926*;Enbbk|xZ z$RgUcaIry~r$5C4s&F}@^995Vei)1Bi(6V)+$d;seyCCasOqtCXhwlYhrXcw(a*I>gEXKP93aV>6o2=YI2GLY8>0o}Sxz3riCdIlc3@zOb5Oo~<$DmK| zWrlnq3|3CzdrVDX!zFPXE?ra6Lr4xkG($@Chy>@_=-F$;=UR4~BbRO~Y9K`F0udS0K(bs!r;{LwU6gqpz$2a=%jQrq&4 zl@)neM!F%I*G6biLv_=qBQY8&3uMz8-A=od+(LV-kO5T-z|mT-49#I-7{pRRFcwU> zcQT7H0OtPy>UwoXMMl(ssn57x%Zx2&DlL?%4qAFI5dQ$xej~jVJr;wqt|Qc_;ee&? z&Q?AnW%GAcV)$Z-q>Q(X%9lRCmK{ zRYnp4)1r#R%qxIJNK)Dz_g(fxwka4>F6Upr@QHa1t($VFeNZg}w?$C{bvxY9T2SW=`reuwa5;DNmAJMa{*F)$W&OH>C1D}*;JQ2?4{5Snyo4F?xeWF$iUWaR$Q!_ld8)nk%cpAp$it9kI_-ClTuFKqMcDL z$}a@OAz17pe}$E}j_|J5H%K2fhHp}JD-;&jbs$mSB9?eKmY((OcP3XM7FqcfQwuR(yG$#mr~pix9n83$IT1XQ^`n0N}|zGM=h2YW>`dl z%MFO+K#$ord_z%Us@%$Fsntu`Q(V@A8UaK}mmR;l^-|_W-3p&{J5QpjmWo@y@SvPd zzd)vGzUo>pK`0ODQNrPeo#l85JHoi$_gOsFW0RtwvOhEdzu`dmzYBC(or(VdAgeBS z;c6j)xb^6^8>dL6q@#$;>D3TwQT#SRo@yA`arlb-T{K2&PhAl)5u))5+@tK8F>kkZ zqndLLslXAWr)GzI)EuVtTt=S=IJ}`jyw7gv8e`{A0Bo$S%E3jE=StORszLHrzJWS?sIXiV(=Z5&EwKqE zQ-)&DDh1PQ({AX7WU;CF%9{_WmbAwEsYl)WPc>L*)n>2d-4}5TGSr~#Ix9f1Mgi+u ztSkTxdj9|jSkk~z7VG+~Eb!m_iY(!gXrI+M{wPmB2-kNZK0Eg6Q9fl*`YbKgX%afnXAgodJzlxaJss6-q6>r}M(CMZ=l`>Yl4L1D~dWPZG*a2(0Ls7!KIyL`FlovLo7Jib49ULZ@~9 zVo?C{ry)o|0AWU)wpuMpF;%C1lU&^qnJ7;BAlyfXOuZAF;2*@MCPgRv=$z*_A6?PI zb5sf0AMAUb)cn>Kigi=92XqAsv>Pb+NB7l0zt8*82Rw9W&@LwvQ@Rd=1x$}-W9FE^ z&|KRCX8!;w)2_R9RikfT!nzSKvQlp4g|v42ClfXvK?;4Ntk9b=K?C(rF7lhh7Q2u! zd-PeeKV`jeg#+TbP%h&LH~vg1I@oGd6FZndFdQP2H&(=cL1#4BBY~qIgmh9R&vo2% z37B|p4XKDjF>WdtTt|$o0x?()-M*-nS)lfy{{Vzv=4ytxMp4&v*#7{N{VCEj#392Z zo1jZ{#e`@SHXztVLehdwDznHP_E_8DDU#vYPbe~|x*&~;F;p?x3JfNIq6&uH29w+? z(P}iRA>$LBRg|5jNXp0)GAO0b4|_!iL}x5hx`RkrYv!xU7M@5$yw_j;s5QPHs_K4= zB}o3j{nl!m%7zR?PG5Df7Z zo8fPgn@7kjEV=n0%bTJ{VD6{}_x@4J1ZlVOoil`ZqUWL|+&y4597bGjZ7L6~X(*dvd^<7HLbXL~OxkUaXBwVM(Cd=}*6Jl2)yVr=2+tx!EvUt5E@D=j#mgyJdz;3Xgg`>=@)#$2gs>0e0SL&qcV81t2xzeEraR>vtceEs#r&HNJ zp}#Uw z;ue4|I;>9+OQIH-oZ|_u7Q&p6YH~Fkv*acYgvZT5-C>NMB=h+N8E+&ITKJ|K01`F28l`&O$ z0aS9ikHey>xnE`jo$_C38~*@`ps#hB6)Vs#+9HKzp+wtQP%OMR)GV$YkZux3h!tII zt-!i6?@@m$)D)QIeZ$&$D?vEh5 z^E;JGS$QY+PJ?b!`K1)&q^j&cRMIsHJ;~~!SCAU=jgZAt77Ek4&Sa?A`{@nW`$e^mTUi`gzQ&b2VBPfoXt7Ksk<4XkZL`U58 z2=(P9Nh_k8g^88npO-2oaLCk}h5n(e@Q0M{AH?R!=u;hTBWPP??HC{$IB0t+f6A*+ z+q%#y{S_5%in85nVYDT@-Oz*6|%s z_E3~eIouIOxQJX%AmM^s;z4rI2!U1nslwRktUqKa5RWRlU9hT`Pz@CZ9(GyCGol!( z?Fz_qYZ@TH(`s}J=)TJ-@W}b7V0Y#YP;+^!=N~0)c^`5DJf+|Ar1S63svha*-T3#{BeGmXF6HD71`n~d)4EB^r2EkBw9XZ>3lEvP&yWf4XFsy8v! zUPpCPSy$(MmEl~eUunby>?*yV`Yst8xP`>T3E~k#zR~OlWjsd*EQ|paa6H$HEAoh< z$|tIqI}=-2UDQ;pICAcq;7ocWZtG>IbzX3z-6!0lDX4OtSJi!2<>lUq-61}|5l7v! zu?R?ss_S$+D-O!j^;&W(qQ9E5^5t-@s^yvO^;e$D?AT9rlM7MyyjQw(QYz&>(+S!Y z=iH`M1`kyNp&U2vi(c`#9EKZ%H&ECUU-DT+Zo4e8)FK?6ixo8r@`T&nfyxE>1b*nL zQFS&#TuJm^4^>7rL2Mp{QQSe%U9VLfqew&1Z%9|?d#(9=KB(qzWqDMUKs{9>(NWF| z#(h;@RY~VS19vOz%#F|&?$zLLqN4E1t4LlT6$@S2W@zF%1RN*;zR$rYL+M0AyUn(2I98JsAGleSu03{BX z>Ze6@l&Ey_tobMpos{&BU;aDV*Mnna`Se%@*F;iovmWh1r&}sC$3-wg#l)94Sh|i5 zPA$L^)9Ac0pqiuYI7b@D#^LHNs7F8*fd2rso?EJ{!X5avShz07`AyUg2Na&m?YK{9 zHZcktC-qpc;^FJNe3MVJad+kLmBT;j7;^)OqeWI=ADL!*0?)-BL1uf3kt(e!i@*Va-a%>mK-KGuvFzm)l#cB$zrc%h)k`>-D(@S zRA_W{t9+Deba26s!iD>yP9k*GA8EvB8@`A{IBlYw4T-B^Vj;iyh)%-BkVnRefEJ37 zvsz0##$nySLjD!GXDoM=D=QGK%Mlq* zyJb<&78hasQBQLUZWeV^GzP#P~6D)P6v z5@7SUxn&gPZby&{#u1MW$jrH72HG2}6PE47a|KXBgEPv7H2N#gPEmw+RGCl*xN&iK zg}XS>TpqX{II^vy}M>i zd~vv}KLOLN79J0@XW|j3nvMfl#se+OBp~AKFzN9xwTL}bxH;QnaVi@fyeO(Pa<+08_-`e~=2~DoUYu zIukzS)XJ*AxJZD=R96 zltAS(ML_8XQ~_opSAoC!ulAYfp7FzI!Y>Fh&TUo#((34FhFme`ohDjzQNlPs#4q$=EcCtWI=!750a+ZZ^R^>YtbfgLKz_ zrQ!zhTOjsQ^Oii8AVCXNmyp$B)pT0(B1oN(AN5>P&%$|PY41y{^$E;$Ihd^)FATS; zC7dQs;8{y}Y@)9X!)!|{LGDzN-&NoX!9{5DR*qI2v_)#I?$g|&mlc&}qWdz`9Mw>> z30Y~%%ND-vc~pf=B}`FLLaM^kfNK|pj5{cv`f8fYOv5cFElD10i0Ei>c3eV00ae^G z*9_TApPB@FCc&JIjr#Rc9?;pBWvQ(0gP8UgYD;ubUe@r(ga-9ki^IHBjmrPT04ERu z00II50|WyB0RaI30000101+WEK~Z6Gfsvu`vBA;d@em;Y+5iXv0RRC%A+IqRc(c!% zibs3$c#1hglD!jTHuApdGkG;0tF#-)3x*f0u$pOA75>0dE=wPL%pngwo_*%wm8Do0 zxtO-iqaCq&? z;DTjV7MG-%;KrOYn#1dUk<)DVMSbtuW4Rlu%iowTYU~2S_7cj~Eh<`k3Ou+@($%)? z!>BUsu~l@5$I(zaths8Z8{!bxG->RIuH_2FCbnBhePkRe$@QpxXu*qru`aHGE7d4L z6k7gk^)fT~%P;|)75@O^2~cq^q7hQY(G{7K5Mv>vt7w@$WeAL;i1{a0Etd%z^SObj zFk3QeJ9uLwq_P%K9gO2)LI~8e8D%k91gNQdLA5)A5M2qCuE-2^Z39t9C0W%K6j~gY z8uow%U1K%fmSoG2Y2qauNG!WGiFZ=ry*J<3f|1FsXI6YnEPyXvSKd%)%Xr{k2d<#j zDTg_KBOhwbTOttO5X{3|`L1J7suJKf8qWu;NUo522ER4tIcTSeeEaXDDPY#j+S8bY zmK+93_3fCTewFOFN9yX_mX9cS3;iT&9^8v&%rCF*C#RUw#;RTOLuk=#9*{+$G%RX~ zr1+02ktHd59Od?gMXIY~v+f~%R8rOFTtq&QTpd_ad_Ab${-q3x@~(QodNo^w=s{{Sv$h${a8%bFZcR|gK5)x=IyaLH(0)hShWD%7`P+TAj$zN zqnS--{{Td7N*kCZZIBvch9*_&0m%%*1RkfBe8uNoZ%*@7m#T~ck)}ai5*F%)?x;)B z$*T3TLls@Y;r@4t2G2)XvNn@LCVV956Bg@ypNIt^texN5rBtfbbpyj%SbcwAEM(5`xY&L*U}Ec3U=X+j(NmM^70b28G$~{Y77XP zb-!4sWZAEalvHf7c;$XBAru3H95?>UY=*W8bv?;luL$UK{{SN!DCjNe(~rbM5L_{QIN~7&;?vpBE5kYX6MyF&EpT)FY;vEk;(+K+1SujI1{tehQ#tXaX* z@Xh{p00q04A0G`y2HgXeeXb%tB=ka$+4Poqi)hK6gdLnnPMz>dtcl27wTyR!WDvDy zU!BAi8-`SNmu4n5yX8z>cIF%}m)$nZ<3jQWWqcJc)x}DFt{YbSzV@5~mQ$3nO%X?U zu7WYPr4j!C(O>>7(hjjxDBLRITA3vU2?_^HQ#xe|*ddt^19gT_7?)=V8?to|Nk|E) zjhXWXkWmB);R%!t2IUn00KtI{hH06FrJ~pdr3-aOc}@b%W%z)6z8dWYUKHaGc!&yV z&&&vFh}SG?WW%-%cRv3Bviw2itYdv)UWwK8{{Um6CqE&srS;6a4Q*Z=xNf^lqh=d1 z;GO=|x&xBbt_Od|<^=^T%-1KW)xT(lnYq@@VsE`@E61P5`36s7-%md<$elN#k0h|Y zt>DXd`-Ny)XPYmt?kFs#R1j5XtwAj<(ZdW^#PD#iGA$ zd4uC_VwxvDyurg(}QUH4hOr6-s(yoj-Ju!$w*Nd~i zz6y#Mgbj~(n2Un+mae0xcx9?3!tD&oN|uZTna`(*m1+ue4!cGjY1`U6oS6=ns0niF zUbSP;UEVsmruQdVw0@C}B_tULFBI2O^m8djk=m_);HF5}E+Un7iv^X}9pTh8blfyA z-eSNix)Y6tT+y0#l+5rzxSTO9QJnt(@jK3Ra~YFa5!K1k;a7CKIC^ybk=25sl*+65FbP;sU+YsIt;-yEz4n675cKGI#d(&% zs`|jZoN_)cHWn1;WxIIkRaKZQ6bijQ&XH9pm$SNh-h0b}Zc@gId0|nFtDFr-VtVPu=kj35)G)m@RGoa2r;YhGhD%+v!T+GtrUr)~S;wr8n1(@qm zSw~uqj<5-JKA_*-#Zi>Ac+TRHR?CxB@9hvU3|=}IH}fj4-U~9}$4yFmPTdRf@e>sY z><<+Xno4u%mWsB9hlxPuMPr-b=BzrKug-o!SvK<*c3_C<6hbAEs+{a zpIYmj=jRdRmp8J958NfqZS_|jw**%Kwr{eZ9DZdiNL`%W+I9yqZf#?L@6*5g50P=z zy7^ZXH*^*sw?7fpS>1d7;8m94_x;M?<6Fb=bH&wmOY&bEGCD%3iBaPF!zwBnika0{m5-{Gz}HS+JF5D`T|hfqH0=c}IquxQkHlR|U4U`L z{pMvZ*76gbnI()_YIoBIOkbp`6}4tqlMfg!0suP40qc%wJmwk>1KrncHU-X5DNyLtgO*~sWr47CvS9bxkF`+4GvhMW z&|D-#HA-sBiD=AHT5HOCL2oH)SQ}=;xodY;K3mC*Z!ix$%J;+@r*LAnK~~I0_PE@N zQ9%{BlE*M_3>NM;+Lar)b3nJ1b|xPp+Orf2)P6)94tv1}y;k4JdiB(2QL3mEZ%3pM zO8b^FpWjJ~)wct(y?S+nrb%m7iOuJ%?$19)OId6@PEn`_sfJ>VoLyQ~-g0A@vb zHVa&d*A_pBS8D<^J+G!}ELhGKHK*3$F$CXT{=GSaB`rEL>-WD%Yd~VG&$nrd6eC?c z{nQg_yOniZV~@Y6tvaFyPhZU3^}O`o;!+G-R~}*%yNk#Z+@^$SAc-AATooSr&Di-2AlUzlKHM?>$l-i5~BzuczGzP~WGQQjyQGiDHC z0CyWb;&HXfiBlY%aV&6ON102%w-TzCUY9bod#WvkUe*xbFKy0FdQJ3E-duWgj%ES4 z3v81Yc$L((WKxb2@T^3`jY}5l2J|*106UQ;lw;OWeFXIp+|Wu1fo=(K)D^u>4xuD8 zGSRPDfu^N{Yn|#eh@7axevNioX|As_=N{=@>l?`7iU%=U=IoGhIEi1J9_= zudmvKC<||U!&;}OJjI%iTT&NYaATv)xFv(D+;H~vgMp4t96y8K5M0e}+mYNMQk(pX z$8cNX3tP31KEAN&iA!*IjsgJcoM`;T&5;X>>1Xb29hOfHk(gnTi^tv=ilIZ%)BN{> zHFk3W9qc9ZYpGcC!i@_2_hfIN4Y%iV(S%j@D^D4f$i#=U>!YN`wh z&vi--K3jLga*b@sr#QO3D# z$FmXi6QZO?5MdYT0D`y%*?%~gfH1zry!(Ym+H5^lYWGnPC!nhOU(6dcF=6OEcUU2e)|V@4UUR=aJ7z zkD2wnJwH)RV}?Hw05~1>9l};|gBOa~?F!cS%ig~bw2QL;0E7UePAJY`?2%a5e@|!^ zLz`!Vs?4stwqzM@s_qymTo>~!v$ck?svew1;Az0$tQtdKV-r~3QK)-McZ2O3=DM6f z21dIbqJ^;V_>NinkZmRPGcd56E+KF`4q&$Gjb($T`RxH>zO#{gpxx5?r9!J)lz(PG zbWhtTYQw7ln-0j^CHlZ@2*fFA))?c=8PK}u(Rxc=PNcGQaWhfQ8~*?v%;aOFY@BqK z;P3wc8`zhDVgt;slIk7PHr0eN&Z++Z75>bKDY6B2LdlfIB?;t8#mm}aw8Oy-vSyAI z_4$D?)(pJ!*Bh1!0_K|I46&H1iO5@{p6qvlmCr z!HaF!uIy;qv#vfR-3IWjhX*%VLHLaEVWM8My=g`W&JKlP>^PeuH&}PSzWrjfyxeZ-*1aMP7prb*>Gz4B7EN^~ zO^{*u{YA}Qmz#BkYwvyfpVn-xz_539C>lLl*MsXcaC9fn<`ghaK8Tyz_E*fWscEGe z19BpdxiFPgmfG{j+(B7uGf(Hu%c`Yf#&63~<{8PTt(T#^{klc#vv;xvlU=hA*-hgY z8kbkY6@+fr@hET~T+VzrnysAZh?*nKdq&!y1~`f?4keoeJk&*ZqsG`UtvPs=PV=hV z3aD3DT*zD(h58Y8S>|J3#KW^Pj!AQk&g>M){{V!`v{En;TkM!$I7LQIpUHZw{ZeJ- z45kv>DVz(t4IDY#RPLrzP}SJriC(znY!4!7mj@{6!#UHalsMUtUP4= zY9m%n+zfg@vly_$Li*t9RImb-EnH-y#Cc8)mt}OHCt@7}fKw%MCE@M!q$$vGDCZeE zXqLz|+O+H5=4IN^CEWsZpMLP&J%a1+ijD_*Ddj%3(mk4gqxa?=nktumJijmll^idU zE(=(vw_k{BuTIlAc6|4GverVm!uyhj!&p^5QOZM;XU#B0Tb8Wc1x<#oe=_Jk@z!hs zs$_#E&I38`)9Wj$hG?B0*S_aR4MF-MU@j4(+gbg5%zgpC+DCABTzWvECX!GUvL(ew zef-L}y0Z~cGuF2$peF$oXvx-IbUPyeE`$cM`a{-b>$;W!AHo$qj;5p=LW|-KmoUZ% zn&-6E@in;i-1$nHa}(Sl2O-2wdgW;G79((jI@T`E`=UP>b2>R83dI7r9rF=Q(Jv#` zGIHOm`$`GQy4DLnI;ly?2X}9+vb6EdT$ru%{#0Z)TuuRBk65GZXF6AJi!spJ&|OThlcM4v3+~7D2FJ_a z%Luk0#|!ZqvOeeD7-H);+c3`*QJ2ASwj0H;IfqCC!0{S89;p)mbtDnLA~nKT?|lS3 ztSvI>*A*J{S=q042GqB!B&>`Lb%M(F?ktv4`^?1EyG%JR!zmab@=6^+FFJ?|=4iP_ z#^tB}IH?q3IgyvsiAh|_Ml~EL_lqhSZi}FXESRA|#YHhEo?i9L84Fa}@j4-7w|M3} zf{Se3cJ}s})!)Ir;GnUh$}a20^V$*{fESk2$2sJc(_MvEuk{z6icwkHpUuiz!xR<6 zNc#7wktI??zCIgw0WAnZ`%}^_XaxeroaOHkH_XHY0$k&q0v zS1Vihi1YV!jO2W%v}3#&MZXWyXIcYS!~+N*7|nbs1n)#0EGNS z5lY1esMJvfji-D?7gU)%Jot^0KaG95*G`_%iXoRVC5h?jp0SjrIKGU$AFR&>`1|&t zu;s$%Q1$1E>NX+j2uq$N@EBPdl_>F(#d(+I;XJ= zy@nu2u{t9=j6}Oi$9NZW2&~iv-9XX~1a2j!Qw&4FER;dix`|fe`oy+96DDScxFwV@ zG0^V;sg8=l<%7%v2DbC_Es6-+31fD6vfrne4q7^y6u0AvVM#7eeSPl=+e0J(uAKPk z8Mnlu8^Y@~?==w^iQV~%RF-LM{0?!^A~kbr`jv_z%6Muq!9g$Zs+s8lOc!(^w4*R;yOb?jw4myYK;WrNMrP?~#W&1|W0h8bu1oAZh z0FwwSsT{uYM>TI$h4<8ObF{@i^0MA0rvO99BTQsL>SS9UrgtQPysnmw+gL-4rLIy;hs zb@Zx*hTU)XDjVc0KKYm-b>`V<PC)b984nW#4WkR3gziHt|OpZ5F?-xt=GA%!q|Bs%mARXgAdP6(Ja&aWnx=gh-}L* zo9nc$e;-J!cZBJx$A$Ivj;z`R@*hWd9Acj@1Ff~*45SO)2A%o7(PPqM%^$hU6sc0D z2Uo{f7jG<=9y#jAe-jbL#kH>yu`L|3yF~%0m7PUhE5zhG9u@b*U`y8(4K_V4+J~t0 zCOfUmXKY!%_L*{X(D4D{?*RJ3)3Zj+14@t-UBTi6w{Y#6%t6VdV3(8FGep{~B8Oza# zR=1CcMr@hFP-!1|W1Y@c71WN%2x^w5@plxnGlJl%_F`pQyDr}|E-2j$RJ8U*lP0}# z6fHev<&3|&SPQvEO}b9{BKpSE{7Nbe%x2QAu>#)V8zuJW8*hkHCOFR$nrvYXdoYTZ z(~`?s?y6prlIpp~i>Xibe z)#?X}{YGgiO&&epdEj;>bb~U`Dli}TORH-)%o+*6Fk(<^ceD2?b>$%GE-!SaF-o~~ z-VXl&ziKR?9FX;(e6eo)ykiJ8EqeR z8Su=}IiKkpb@Pc-x{FbadKERBF~({u_Cui`HHd+lu8>Cs!FdbSxs}*K!Pa5`ZliFU z02=cWq*?(O$5L2ved2g~#J|*DsoDc7&k0QYLl?Tb)?%a>-IV=KpGn}|)Cc+=qF}AE*%d&ZyLqYa7YX)D`pvJX;DbhZ;l#mUuE!U6vIRsU2EK%cl z*Q^RV2SLxVzpd{U1~_A?f8?q1mr{|5rB>yRVAgnrRLfN?2-%;XnV4*A*WdPCvU)Cu zyrdTM%JbF>L=0US@rg>pe3j{$i?UHj1OkqA8^jl57OV~|dt|6H;%pwJW>punDDj=V zqWvMN>Rz7XGVnUklwTY8ezOa5X|I~fOG%G+A2SIu*Hh*&cIQTnsbmJ=b6}jcETMqi zbefbD)|;5uWl%yesmNPd;#{{~M)TeqSClKO%+ad&M6g$(#G>*J4gAZ4g~gJg*=GJ* zW}$YoesKrCcE_|2B|0Waol1S864LucTb6Ff+G1WXW@KKV(ag63yhJ+9lSj-ke%X(D ziyQv{i;P_x=-`IivxURj6rpa;8sg#^xzbnLl_Qdh#dk}fjz~p^5}bMe06WX1?dEb9 z=={q-SOi72Rfv0W;$++SUVA{%!_Zf=1BM!?7JuZSyh>{ls}Gdlm^+kq9}#uDGsH`3+SXAQiyEv6qTZa3SOHdE zlU|}C*0s~(6=T1L-`wJ*cj1Vubabm+2tg>BvACJU<1)Ew@IwgI3Pq_?w?i##kD)Za(>jg4v zn;G6tyU(;#1!~`7R3s(ms%-eFe6@PS7-WOe40R|_2(V04TFD;p?f~Og9kE^t+kbtc z&!HrOaTe=QV;i5E0LVZ$znR}G1f-wQsH2_KQH#7J zp-v9Dd&bRIlBxD)(T?oGt97}Vznn_&+{-2#AsJX$aPb7m&q=-|_-bxhF@e@qCN~?g zD5;q!Hb_bUunXm2(5#DR%to!H4#&SwGa@K7=fUd=coOhp&wR`@FeT=XKKSo&B6L7~ zLz{B|=Rg}W-JS>M7$qg=0jXTJ)_ChOOg0qDTj1@`=?aUZqOQS5J-S7-yM$H$0GCs1 zb>3M|j6C8`a%tCMItv|_iv|_rV zX4`w#d5*P@Bw_5aN-K6ko{+i}Bd_1?933a(N<<2<@a+nYjV_nj3nLS3yHpNY&yy|p zEPk;u>Kn=WsY`9uiCwLI20bmw?-U?yW4OA3nNoN(<^$l4wU1UGPtlh!`t8NgIk2g0 zuJ{s&4f<+eHbZevx&Z(w44h?z>DFGGm3xat;$t@p7Z-`{f8YiH3Sl8;%~n%UQZ~v; z!1tDbSC_AkPia83uqO<-{>s&K6M*&Hv!2SIR-k~OE$A7qWA`huNLsVeIxf6Sb(w$- z@vTZru@Kjc%cFhw-Vd3j{{YK|xoT&pul`nqfD$>0?U)quseP;taqTh6QP-r{%U4d_ ze$;j5Xys6ESw{)@g7t5Na4U6B+^7*DbN4{R1M48HVF)jwVulF;1yCq*e{7&*O0R_AEOrwcldthr(QWJ7{=h(i*5(Y6l2&g zh=kEwFR$h~gVe@L*6xXsOgzwO+9wJr?)34Qk5y{nyR*js0OUZo1$s<}(RrEH^Tegd zHCU!LwHUt9zEmHGB~Zi)YP}`gS?Mp+(i1?{4@&HPahL)Mh?B7oj+DXXc)7Eo@3Y^PK3uVVQ)BgZBORQCr-u@<~LR-Q+ zLrGGE<)#h%kb42vEcW!} zmcebleG>+Xu$k~ZAvJtkgCX}!8+I5gFk5&ze=sha%mrQTCDQS+wS$h8(g#wIpdT8izH{yC0eL6`hQ2(+Fz;c;U!P9#0MV88@4)BC zOfCDRs*k~B;(|eeiF9l6Pwi}vZL?ckov=s;bTpYkNAxnG9ueVEjM6!Eh z<^)G_Y3VWVVAlL{#=~f~({<}CgRrkj*n{^|U88DK#LFHaSIPXv$W0@Ts}*7`_}oM= zLCJ2Oe&#KHi4Wl^14>R}<0jb(^8?iDo;!OJVS9x*^7*O4M47C=>flr$XbV2({A>tixGye&!tHvXA6}X3Cq*%-(OT7{_g9fmrOp4s4ZGRLhIbUb8G6_?b8KsH?eBt?|33l)y<%Z&DvCWpeGB=&g3R)h^S z)p(S-L7<{-9m^<++X3bd=YY&P+oV`qUq^_2yTaOpy&HIn&(izC13RJj=3M*-_w|*O zYpai!a7uD@-$6xtO%|0)FDxlt4dw@j-$=&sjbAsMz<{e6ZdR8qTN$obE%Y-j*~m8d zd&{^ib#W59?&_DcAvCIoE1?zO+LsNZLw9el*WOnI z4H{Yc{bnGgep7xh`%(Odofy&T{{SjcWs%1V{yw!XgO6aW(_S{3bPKR6fVG4KA zG}T-nx|B<`Xzkut%L45R^!-kp?!pJv{mcZyC0S>*Iu)R18Qn`QSsDpBo$r4V*{L{o zh3lY*nk|C(Zod<$s3r8J!(wv%u249 z?FCuM&w7;7{IKR7;^ynCs6kkDfERaBKZx1yf%%Hbj;asD<`1&vMcjAw{7Th5%)+*w zfp4Mo?F7M-)OeIQ-h#7StL=}NH!cKMkm8O#<^6-CXP=MN65#Y6+lNV2zV~wds)ZaZ z>gO{cJ=OE~GW)IL3vk_afDod9TfX|R>e>rw-TBTtW+jXw<@a3r1ki6;Oy2T-F}Jh^ zb1sFk&WiPPhsj$xQ@`(Tr=IE0{FIV*K3D7lj2tiXltx=fxxmYF^!?oOq?kH46YaZRo|^o^KR;v7G5 zFG0ZNF`wUQw66jG044lKXPynK)!JolfeOWR{r8qb(bjCr`C}=3IH(%^_V&05L6^+_oj6-1S-WTF$AQ^EU2s#0D_#$~KZru96sDz-`~!q9L42Ne{18+E|`l&tL5LBc;bO? zNPrWX2I4d%jHkW%?@Y-qtl*+qj^Gw`BG77VTJAl*BV$aIZC<$h(i=%&)c81EJEqlt*%aQ_$+(I@T7=%+@*@R)ya~+D`S=!D^;$W%K z6+z%HS(mtP9bg_)cIV!1&2YvMt`;n9nGEvsj?h*khOv!yfWgrnFUjxgDJ*DRz8<-Q z1`bY{{M@Jh-ox4d0Ao3v7moh`k4SB~hf-Si{z@0f8@y%g!7F7OK*!pPVeM5Nx!k;7 zjH2O~b|1+Lf6>}i%oMeWX;A6Vc}(X?81$6$ygjd>-|fY=rE*#O77g5qkJsLj4zXOe zc0Y2tZu$H`?6%^Jy@QC#Q@byAX)m_VVjilD(%t#{=?O7l>A0;xb9TI)Wj7k6J)PNf z9oEfz548}3p4?GVw61R*=WVkXcnS{8RlN$X_{I7}Cf?$^4>y^br9S|^9bZh$=J-3V zKjaKxAGCje5mAE`XR*Fmm67VhUOG(v;5@yY^GB@9G$^Mf{LCtXYy}bQc4>6!F)$HJ zn%$p|Sxf-vanJTCjx;&H{37*0vU8KwUehjI(YLo=+{gHcYTEw*Se3I{o{YY-`>}E@ zdOfr433oMR&NT=t<>jY&oQdkgAK1*9h2bV$VQGT;%uqWIGKTxjwd*OBxUa3=11_9P z*WN617BoF29-aEcy&hS6TxUHa>mLZOsAII~iDG8W4aJpmt-uU$ZRoHyl`OlmS}Aj=U3m3A~d1JslMM!zR|6H zpd;k%i<=6!?jXlVnVSYH2mZ$q@*n}hs;Cj8rTjZX*Od@o1~<}Nx>H}n=l0Bg!E7_3ta_)Oh023)P68z}nli#o1!w;snFQN0& z0TUayPBHcEEZsd04*vjv>jHp=%Okq;`B!xk&0d4xfy<4O{dk(eG7BF|>m4IbSNw)E zU&!$pc62%02hYS()i<5v@3h=XP~>>Q&-a*Kg_{k&j`IrwY$kumTD7}?d%L>+#ho6S zuykG_%%cDqgH{DtxMXMkI5>*BT9?yY zdP+U4Lha@A7TV&6XZ=@bm0SdNz~7JTU_=}$+`O&-0Jx0|l;B%mdX)7Y&r$iLiDdmG5(cawH8{~sfG5L zS00cNql%4Kq97LVh6`{^)C%Q}Yoc$M_!cb|%gXB!SVdx~Gc$YOxn1JQQ(o|uxd}x# z=2R^cHu1sJae+lB8C6%~m_rdjOgd&!u)Unqht51_q&bRh+tU^_`oRs-_J#VW+^k?G zNWzv?%^&t7Y#k%>3yq4|2(f&fj?frgLf$rgd;`ieLu4*;a4NG(fYZBmBW#E zq99*>W8LG=p#@6pR2dvMA*w*oW z+}y)+me-S^*no_e|WZqM+QI}e*L8(jvtV|oJ2HA z9|@Z+-e$s5g>_@yiDzw^9KVcqit6J{=F?~9T#W)ALl1wMa+K-bFZmfgs7vgBEH6#( zH~@#gycIhkDJoIpW0%l<`olN~2D+#s=15!I>Dv8Y z5$mQbUk_3PUtFqJn(g1TEvb~r&adJc7plG2!`r+>TKd<8KLi`r@Gima{d~Y&YKh6s zODtm69yRIG1s+h$SA*^$R|w7RZLjWUPy-yq91VKL^8EVrl`IdXcY9U-VAl4hJ379t zaTXT|S{vWz)(pBBUoYViV^Hihzu&9^`eQstp?pm1avgBX?KntTk?eIvcLi0ZgHUpy zFKQl}xcA$*JX59f+GnB9YMpD35WStQ9%%D&>@}mcV7|AuSlOg1+gU^1J$+#b&&25Y zJ};S;t3bv$Den_GfZdic_e8ITg1VEQ^uCZ=iD$yvkEU} zOPDsLv23Nl+246|tFv_ujTzNkK~Sk%d}B@!veonVGSI2=zsSdfp}xcQh6`-BZm+kr zL9o;n*DvdZ=5*@V66ar2^~5C^z?YY~s_i+6!OiEET#i6#)X{*iSUO9na6Ygwh2eb< z?4+j`p6-Df;?A!;@70Rl&a<38=ZL#8WuISqM`N6haedxb;}ZJ&27a;IY2Pq!y4OBs zJn0UldF@|w5L*_XLo4m=1>Rv@G~CD`1i$R-Qs7&)F_zzWfv&TcK;QW-mid9MFTcSU zmumKYx&iCfRa>Ilw(t4ccd#gRm;li=4!~PynCMrWf2L4B+p?boXlT>`Z&?O}(@G`yrWpm4GeFWc3J)s9N zFvVnV;X7Q%+-0;p{-8GlmClPuvYOYB9pAWM30i8j&f?m36io|gua3~CW4^s1W2UTc z)9=h#^=BD~0k=Ap0SUBULu5Cu&k$;Rvmm7QmO1QjGUxPLm~x?&`i=%_WBGjgz%1jC zA(bre%jO#oC5}#XN4{A=(qo@*nT9tCrrOV5mEvLTkQCYNrLS1Fbhh>F#`}LI9Bor? z-}Yf0yI_?-x1X-jt=zb2E0x>2--2i`PBc8dK45^i7Fv{h8cKG@rq^n)MDk(GQ!L(=ywGN3#F|sBT`D-l8_}4nF5Sn2ZlHa{c(1 zxQ)|R>ErlBF?}{N$@oA}QDuCq+&y8I^aXh1@1`bw!&s%A-^OD!aKhZS+WW)^3uLRU zhd%F$h#3|@{y(#bg`sKb{gsX(Rc_pS?d{ek4N3-ZbJOow@<+rgbq2i5wr}H}%|^Tm zY0Z6q+PWiznh!4C*y%ABYaxfp(EGThaFj(;?z^`N)wgBa@YQ?qxY@Sz+=Ja}F-5@qW71faZ*Ol{ zf{-{JW!8sdRoICR5KpZ`+s2xw?$g>DZD$7#gWl=<%Yn9I8ZN-+BPtI;%8wf5`%n?p zSsCiH9`NDP(BJtsF8VPGdE1qW=E~Ku5r&6t{{Rs*r5U4{aKhQQj_WB<2F9Mw$LbWM z+!bE0ZqeAZR}(YshVA=C!?{{UY7;4W|)>(}|;%pUe`e2&FY+rk5BtF#rRrKbly-u+-36~j{9<$)-H=dMp)n?n z1HzA%61|iTm(%fnuuC$_d&v9i2B{3YE&ECXqh9m%?8}vHcU4Dc97|)DV^`SxPQd50 z>CbtPpeb~6_k&B|4LUp@mOh|Ja9>H7WVxgYmqkNd95*%eT->ZIdqS@v4Affq&(aYB z_QYVOjy3p$%nP})o(X?33b5MQi?Pg~T*{S>Dw%1M8?psbjSX)*m}tcLUJo?^S1R9G zqP_DL1x>p3eeJ10#GZZwxw!T`iSopG)-qmt)OP5@gZ+fxe_TOtF9Z%-$a3_K_ZKL{ zICD^Q_wg5oMqG zvkg7u^q4@myH0;kq(O9PzVpf=Y8_Jz z`rn|-8`D5x`~&6j9|pH*I-k#pk*@EnZ{+++%T%v=s7ky8XyC=Z`2PTsq*+QGPv68L z4eaan{7MCumb`r{(jAl+ql*r`p;{?W=b>?xyo=QOd$DW0HvnkwziD8!3Lg|otJ(t? zK9?yS8OPUlV{{hTUbI2#qlrcRVmJd!4tmgV{L51fD6>tr@n33N?PO-Ro`uu~z3r=E zdX0==2UuAEX~SXq`*16?>om8oXeNr*dyD)`a&{xzyvZ*R+u!C_gm-onyjT0yIGDhB z`o|bXRt0gNm}##fM~)&A(~&FN?=k8_PWuSacxsoQtVLZ8V6?I6)^NXqGQxJ4EeN@= zJ66e*y%zHh%iLL6R-im$TW${qC26>ZZ_G1k3dSK=(8z?ilDUSe;CPLh@z#~?Utj$N!`<6!c zj*wuR=$HqAZm;j&WihlizcADt2f_W~YuQ#f@%Wi_&^f7zF02n*+wTy3?nhVO>)Kc? zle&Up{- zZ&;@Q1`aLS_50FQT^GRib^Q{Sn=&8S`ISX(ty9?QzliX(3QI9$Qn$78d&~r@I39uQ zd5VW3f!G})q!u)Ec$X)jygGU3$r?mrBg$#`AoC6m{{YL(WMo0DDeLmg6dU)o?+0h) zH(oyb!B3EwZ>cG|vkKCU+}Vw}t>g0zZx)n*88rx+65z~lZsZ-ae}wm^;yIhem;OP* z!PQn}%Laf!SSJH8Me}g7pPZ^| zDAAUAVf4%nver$Ge@5n}&DRdsr{*gZy6PzCb%`tyolM!%XP0iT^A+IN+)mxN$M!4} zV^z;-sa%NTv{-1`y7h-|7^S#Qq{oO@($7nPwzw$TwKKVyb?f-}m#0-caATD2>isbb zLd^i=@%#5}_ht^71LyM8qB2z88P#~gk? zF@#k36_3dJ$8J%9(Eie*P|Oair|Mpo1p}+6-jH`CwG`h}_^6i!N~5P=yv`pjF1>G$ z%*mvD;13^r?g5nizi9iZccZrfs$X*h!s54g>h=3`8LAD+^8&l#?)m)wr!_#syy*6+ zMTJ)k)<2{RI6alZ<)_YlWv$G3)!_cb#+Dcy2%h0zhu>L-3f$f3`a*{k7msL%d*I-D z`GnV1x|=F1IOgs=1yx!P2=CHo5(KX;{>jqFJAS%54K}po{mZ2N#W$W({X-j0P-j7Ey@mJ6w z>5sQCkS|busfQb2P!SN%KvB1p^NlV8FMUHnm2$9~uyYGRRTk8B`}X&kS-`ElvlUK( zb4Z#gEe*kk`Z-Edab0%eU{0m#yM5ve8Oz`4CHz_N1?wxAtXSu+d`5-_y1D{<%5Jz1 zMgIK4ikQLF@!g1T^3VCtc|6bpd!P{{YA%&W~`|edaCSJGBir zdwmc2GYN_>o6+}(Onb$A1^WC%MlHKMzn>Fa-L(32i#Jo>yac$ssI+;-&sFv8Hv7ZA zNCD%&wAJoF`2EVU!OPLFz2YvfKR2g{s?f8JIz-FdrRP14yi5YC&M{s;y=9bYAYr2| z538g{b0N3i@)96HOdg$kd%(kfz&@PA%I_)j8QVwI{?uu120r>Hw4xvHAj#9i`IX4=xVvhmklD!UW?mh2Fcw=}>IGrBS`TCtap*#a zH(jMgT-PN`jl+1eyr;=atwR=c40MBVxPtc$+*hQq@RB(1UH<@4r=}^Lr>xe{A%eve2d-+7e=bHF?+ueY#olh;ea;ylq;L!$P;A(M5{7x%=&Olq&G%;`%5#Qb7( z>HLT}3d;N4j>zjjei?Btx!pt4-4@{6`G)swUEf=Py{xa=D#i+@<{Y>P^vCKi5sSUQ zd`qFc2d-O7=mXaA^2~NY`~1qa();l%I>jmLnBFB79!{{nWhvnIdGQ> zPX7Q_QH}w0l>v&+i1OLE6|G&@N#(oDi~6`gwXL6E%LafWggHr)2nOM3KTvam|3o=6N%MkF@*9)^PR&<5CN)TUzpKL zw-*wiv}doF3!wXrz_B$eRlNJes)yi4>de}xd;Y&rD-^k$>eKJ6&vA4Yegmuuo#A!% zp%05O>`QHBa@h?R&Mq7p>3H!KQ|oMgf-^ys>QJqlyn9W#ONu-36U<_teP`)F0Qr;? zrw8g;^%9US4L{jf%GIw|%zdKO-tY4*U}}Xs{kc}5fT9X3fcx?792KCU=4V_suQ{7; zuP7@s{o1r`mz4 zHaW+lK2=+arT$DYRJvUGy-MciH9A2%r*IoeUfn17SyP64#1J1BDL0$RxFEGXRV#E{ ziww9I!R8jX{ zK(-s|YnVd-MPyxffZvx~%Dl1ATZQH~F1Uj0-FwYbQKqgo2C)wE%UN@-tP0KBzOv}| zM!iS-92I)0U^okzH1uVIP8zq@{zOrFX}_4OnB@73j`za)L9yfKF3X#Gz~(u5#I(0M z{ljgs_4$O>hVXZ86;ZOhZ}l1qXcxUE0iMW{%T&t6n*GbBH?P#G#^%GRk4_SYVFdA) z0WinCnN+qP9Cp{^@9O5*$?kv15cv`KCVQF0wBe=H9G%rZ_Kr}|>6?P*RC~DTH+GG> zbXlokploHl$B{Jjg-aA))P+4ZU=$;yWfKa!XuadJjg)_Rh1*XSP51!q&uPf|63Evs zV*rl3N{y9+`G|#5`(`(qA9LKb8Q*D8iksE>A&-M@-)=nPmaZ(S&|A+D zDeH&t#M3@s@(kqAYpiuytM%MgGzz~T?8FYY_vQ-}zw}2jWCzzj*?^SMpS$^mOByW7 zwYaHsO1LHuxQ@If@`hOVn_FcdJ^uiajkH|+%V#{EoJV@SVq>vdy-Th}@hB^fj-;>y zLOhY_A9dQn#V+##^Li4*R%)FpF%<=lA(2@Ix)th7<$&xET;pH|rQ> zvXS{qRwzr&uwFY;Bo{2A(9e`r$Y8URzqAf>k?luFPe-lu?Suh$_cfgG0nE z4y$Zzodm^oIE7c5d%@+rpu?hRJ0^IP+PaoXlGpYvy%MGPfHA8}J^akuZeM*Pm!{@! zK9Q)0T+5!fH@vdp-7_%(iMfO^&%6gGQI@v0LbUG~?^5^;!GXWTE^P;?6HGM}627pq z;4(0|YE|Sx9`8Po!b()zA>8t`% z&I5bh$`Z>`_#j~7X^S%cK4akPD}NrOySj>ek3HjG1-s7ih*UmkGu->BO=!tWe#uKc z!%&+gSI>FWXRK(%o0d#tn|PEB5XHKDumbPCW+zZxLi&!KA&YP^Z93{W_P+a1?Di_h zWjagU(yWckyuikHC;*mX=HnQmXq;$;Uqt-Hbn4bucjd$ZmgCVp)Uls<>%T}NfBD6a z{{R{*38rI@Gd%QDFxXJt&KBAnb((y-+~Y*k-duiQC#6T@#}f=8ctw0>RL(xbeyjqO zET1Yd+6Uz(UnXGRdzP5blBId`Ey^k0UN9?;%y`9X!jf@662h5Hj>CaJLGu zYYB&H+ZAEvXO&P|%nk<G4t?Fh=Tf#(g#vE~R)43#LeIdhiL^V_+jEzTZ z5BV1T>oa??1XN+H$1fEq(Q>VuGoE0MW>W-;!MBR*+94CEZlzD5@%M1Gc*ibf&0E$P zpe*1Xy3`~@0o8r}%ZdwK--8!eu$C9c_G~JEu^6kj;%6%V04@mRG}ZIg2U|^Dn%zLJbMHv<&;e~@iDU&OmFs~^BT zOQ61B;BDp(4_Re2)yu?XZeW^v#jDw=(aF4sdh9YYv;vlDW~i?mbI{gk-d zNA_P-1@%AiOoChH<*!JNzIPGmzPXoT$9{Z4T7>DpF`rLQ%LhQFh`Ia!00?ZXbsDIC z#!>qJ0F$#pgQrLoYpq_Dj$^&ks5EtPdg7s?wz78p#10XR*B(8gfL1WfXmVW#-`q}o z&<=a=tPs(wSffiiVRX)PT(?|h#ZY$w<~7?|h|DJ=tU@p=+cVY#nJ%$&zV{Uu1-)kY z%hC#Twl}`>q($YqO4kk&qpkz5C|e|AhhSb$_05L(WL_Z|aQz%>Hnkd$;Ifp*{ zMAu?oG0el)5PHp|#5+w*{$iwYDu7b;t05TJ;LNaEdsn16M>ltCf8-QvRaUR=CEWw0 zZ+quW_CKD`W%?nQm16aehjCWI{B>Q%8usA3-fJQ2NbE8^`uHsxJY9<_mJV zmEUf>K-t_{pmr)0kL0u7PU(Uy;gpBtP{I!b&* zf#tbXLUlsXHNBPMc!>r5{{Uwg@TnrR7rLG;^A4>!UrYG|d=jg7ip)XDWoz0WPn_%j z00eL!QY_1;zxfS*X4?yY$RNf_xU!>$4G96&ESpGr{;tEAdh04O+LQ4j$ zBbe&!qI30tzAcC6^8+Ph;f}b9vYdYte-08YvJSN?ej{tG)DEhbTg8KCmJCxt$$s2S zIeCmWzWR?ziI=O0D~!8g^MxUpKvMA+Ig9f*lz-qjm^=Rf;N0mKH9O`p zvD4q;17S`VSK>1Z^K$Noc2@ZCr~!p~TZ>S<(n=Z#`^WC&aZANqJOJByuyog&rgW^P|(t*WQA0pG$})=vT?#w#2BL0H+b&v>*DMpEzYWrdxx@iB2^ zs~sJhx|VPlE4r?vQaNt~n6D=Dr+B2pS{^4eJ4;BAE#A9ssTaw=*GmLJ6#QfE)Ie9CI`F z^whs_Qp4*rDyBKw7IB|Man$zsot}^u_|vClMPRl8JW7PN4e9;MWo_aoRP-aV&Co&c z2Unvg*n4It*mL2x&v=+!`$1}+Mj%^5IaWHu8AsEekhO{0;iv=6dWelB zcABT6EI71Q?OofN?92c@ZFSnea*nARPw@AG2-#hC+`K>#ED!*{B&&0MSC8aCpyf^Z znhcJh=pNo~S(OFg2V`UPTxQXe=^FLE$IV0FE@}Fu`GNBU632dH*Hb!ZEy+XPFzeTT z@f)hgUSJLyh3h&>5Aj??i5CpJw{m=-Z30T07^njHt=v_g)EIm8mV~jy>lu6 zSrm@7DF97bSKxrCzDOMAg~QOC@#_;5TgEzB`-XVDjv*B4p_uQObZKixk!E^Kv{kVT zT3SX~SPvm7#(ToSAzVzyt#2>{yJUDuQMIk^R&X}AGXSMsI!s=Cbd)ZGf&yPour*st zoK-^bR#>^F!Z-!NdybGs^{mA?b+QhQVPHV%&k?}G%tgU&uwMq^MR{>iw^eac<4nM( z5H2a}I`(#{*4Al+jVDn~9}}9+z++LFq5$>`Ys^?Y;eVQnU2csBnYIbC%QSR^ETc%4 zX)Nr8wd~AoWzJfPp!mM(BC>T=6bgFJs+hQI6U88CMe8iRltNHzdd0?7(Uz9}(${>s z%X&^;ZLQ8_P9XD);_)-70?G8z+srQuF|*V$Ka^-MyO>S2WrdLC1I$|VF(0<@+=|&} z#6@(y^P-*+_7b$NbNQ^ZRke6_9%$$wG8? zlf!>mYjE1Z;Qs)ORQgtSpCndd(NB?l{6k%?!G5BzQ&lk?`x%I}=2=wiiEYcJxaD^g z-h04T?sjuLik%?lu`f4ZmqSkzCl86HNKwbE>QU<-TyH7plNRu2bk`ACH_Sg(=MYvq zBT9gHA;Z5J9bh-oE?y<#D}2-xBZo+|*x!#?RXQvw?=;0bu;y54DCXJsly6~PJVCKp z+P4p1NV7rWzGb#d5tGl|K!O2X#3)RwaDWWeD8alvB`W38SH2|=VaZ6K2GAHH0^U22T&kA|P}AMer-lzu4-(Q{mAq6I z{!6~hpr@|gS#}AF@DhX+@ZTJt>P_OT*Iw$9=?zpfuDo4cV`KTIftj|C<4pQIrWG$bQ^(w z`+12RlYOdYY@JHP!n(JNGmnhbN@pz{aRqO|{R9>4%1H~Y`pi?Z;TqWv@sk!|If}R{ z{{WC0!kmlZ2vKQ&w9Ffm(F%t4?_=DQ=Lc$obkiezTP+Z0c-#u>9br2MSwL*t&&0M% z9HQ2&@yD5qm^kOm8`aZlm_7rO(ja69crvk04UZ(us=kbG_Z4s%K&`i&z>I28u-rr> z+;Bx$8{Dz+JHxbG44`HsMlmSOe9OaIa9}Ix4cU&&aL&5Tn0vvn_lvZA!7Lv2EY@A) zBgoWq8wW^fb<*N=iI8~QU@#e68zE7W*%+9@T>u;PmZJlZ;^}M7A-$^?Rgi`$XtHm` zUk@Bi3T?tIyw^^+hXTO>Uch3L0a4cYS4ZmrQUk(Ry7rSLP%M`Ux+$4D!YD);>50y@z{!L z(zyE=na|A|ihK<^p&O+^_@X0Ig9?WxZBV zXtE7zp-w%Ja%wrVM-*$?P`s>^J!Y3a(RvfG9$;&z#L2zN6Tesx%-2LA!|KA#tm;ZO zgO(!=SZxDTK-sEXsvn3P$UPzlB)?^nC%fGF&I0ONholGu8SUvZHLk2D*swDfPT_D% zvbh%(&Jev4*!BmAKEMEN$g-gmYItEulDjdInK%R*qAou6cueeq&4xCI|iXZwAsH(mhIyLO;hTy)x*tYt=xFQ ztO<;S-4$<`V`=GVMHpiL0Ab4^Y8w#+kAhT=sNwhwG=R;z6^EN%Da!PE*gbApnTr6# zD`DRhf9sGJ;goOp!yz_tc%E70p~FR&d6|~mDV^oopT7XX?JMe&vIqmWO(kq00UR34 z_R*eo`i7oxwmT{@G6B)+YpHSy9G*cRmU8mUN6-ObgOSNf#X8gl-vEpsDo5dKMNa1)mTff08T}G_Ev;w1?$%J)m zZp-WHK<>41xB(A0%VSI{^|uA)rx-578Q8AiXJ4SqT)&RRlG)VqhP(4mkTI|I=z1H$ z80&)+ot|t8zC+dNOg)z#WKR6dXk|TpebIflQ0OU6cbHrbc1QNm=Zn9vO96;2`Td(cxoq|zPBk>6pyG#r zDx*SO!D$M&${`pu1LM{p^x39&`Z%q1yvAi8ly=1P>Yj!r9H7#n?FNXAJoCBsXxJO{C?G1z#xgNuXcVRxh)V8* zzUJj?b$xT}=cj+R5Wuf!->bHHS?$B8D*Gu3WM&7iCd3!6G*Bs{bRaKX{!=ytR>jT2 zysoo?bSCm&zx!7;seb-P`+9Qc`~4s4I7i(k^Qh@OCoI4R*13Nk%(P9Rl@1`k!*DDTcw>|{jW1sNi*9*Z{s|HJ?t5di@K00RL50RaF2000000096I5Fs%^ zAW>oe+5iXv0|5a)5FfTTC$8iB!rKwu?Vrmm$v)li^^_ZTp6qxFk^YkQyHkL} zX$cO`kpz}LxZmZr{Ffory1kwbG4X5LW!!_ye%++phdqz#?RM(W>K~F4hQooRDNkV` zj;GG7m+u(!h18cbuaHHnkerUZn{7H_5szNT_cI$T$wRVi!Yuogapk)R@(R?C*J2K( z?qjYUWG7-584TbF)EP3fZo@p`hRAK>8yVfFlBu#cgp=~i$F0`HYy-CMgIFevJzhrx z+$Vvu+=OCcMKJEq&TQw5w=a9(autQin4u5Y_1OkBHbi>^GG)mU>~z3w%h_^qJFt1{ zosf8ZhFI^BK7g~)gYDcAc0$P;3tgEp-?xy%KHub;hkBGewYCA=oMo0-Ws}3)Sr!uQ znJc$;L#StX$z}AO+XOeS1F5zSQmK@`Jw}abZo}&pfxl9rt3kPc{dyiId z3kpbj$wzm^o7iA=`5Soo&hWzwyXy52hUsAT1d*LGw$j;-#K{~Jk({M$Pi9GuajzS1 z25jYvcn9s;$AZC2Zq3xkJ8U`0XQuGpHu&AIU-s9lILWv0&oj7i zw%m(&-@(S)ZclyNJG(9Si?3w6$?*+kS}hB0{4>GeaJzTz^V@fwhTX!IB)VjONU@^EQ)<)RXd+&$U7$u7@37|oxCcv0N3GDouPH@-nVNDYaJW)q_E zjMJ-3#_C?42sWc2av#=^V%4nrlI&sMNDbCG1r`3r5b z@G|vn*VsQN=vikB{Ap=zw|>FAZM(;Jcbs=5%(pm0F#iB&fW2jSq2;*0#R;kXe@St-pe6hTFz)Y0eunj-=k<%X+@1lvyuYYzjtRVhOETEHwB8O+@@4rX_DS*+?nXqLzH`3kLoJ9kj<`HLI6Z}( z@UGe1H&YWV*fG7jFC~4Q_I;h6=eo7Wx0c^;Z}!M1hHUCEUf*w#FkS3Tx}VZjs z@RPfD<(wO_W{Kd-wU^kA?xlk2-lP^HvNlhI6R0pOAAst~B!rBe$4t)sgLpRg-U0Rr zdxvtwyF4lC`4%jM_7|64qlNNr5)UkWg&PI7=_trBGX6{U#C5k$puSxNpNDoG@%6!G zF|xZghat9LKhg)tiacxv!a9=uifz*YB)YQBts({w&J&O9@t3&j4QBEn)=TPOf^dlT z($dI5mhegXkJ=hpkfh>P!h39SzkvqcG9!-&mxJ*+NG52=dNz-o8Qrk7i|mKX3uk8y z?n5Q}xo0~Vw6SL0oEIa>p02koZZ?)e3z!_W@^>X{KX-XH%$RKFvU{7iQSlweYjc6) zEW3+XJK!g&w}I7LUhgq_}RCv0y^Q2 zJ3t;=0q$y;cP)f1v>BEN;9$$!qd&=GA*I-mEe`nJbMQE9g85{ZS9Ufb>gwTL^lW^{ zM+1adeni^WF3Dw%az78e4flYOOp~i-Te8+yi#R*kVlbam&MGXkt00kqxZQk#EV%5n zvg*q$vOS34i)@l_NW}Xyh9EuJbVi`*7|pXw9I?UG+YPc^9`5H*zjU2jb#ECxazQZ= zS#C?Xczq4Gl0M$uZLP#i#31U<5+~bOS5oz*p%X}UZ{hC&+`66!<0X$25|WT}GhRTEvEKl)$qTL!!Q#uiF7Nh9<+|FI@v_4a&5>o6W%gpph{4<^ z%Xv22c<#o|8hOE%MsOKyymnqgZ1*vNKG@mAyb{SRli2ChEygjw)Q2I9Q$oGnY_Q8J z^~Txzy1&RRM*xl>Zals9Ths6V{{L9PHfq4Yk&Yf6jz%3F3XU#8LXa+LQ8yScx&dS6t-)ujAzx6Gn*WktH-hfko|EG@JQXJ_YJIb`@MM&r9h69_ul6_aj5(WpYZn{ecqSsqG4m)g)ntTHCi3Zwgm|Di>x zfmdD{3!zeV}V$_i$$JTc2ep2X?9LajZo5JSGvTbZ63mtbP|v6 zE&7#pi7~g@YYws3>T~jqR#%;@phH`xh`asG1z`573?+l!rycynd`h)Ew@qM6+;utSy(m zuk5b)lf4PJ34c8PJ!gU-pJN$M94an7Y2X>8+^cSk;$FH z*rT&PjJ69VXgPFe!}i1tcjrSbRKRzlMq6t*5MW$+uA zQJS-_>F5{cdO#zA^d9e0Wuc@9Be(k`3kD7r!7q=iJ;ZLATd3x)vI+^@;+{E8WEYhj z3`|BS3MetGv?+{k&oM=^CJOprSr@5-urPXZv$D93idK+fU$%y!hiDCn0Ofjk` z4azKJ?F~+q^HRV<^>UdCU_-dUKlzzdi`Zzruq7+~>V0EPrg&rmG!fB8e=l^R zm#9Z^3^)w!gI4P5!idUZ5k2NF?q%~sKK0GIxM=7xseaP1Cb?JEEaLsDrLmsAuCF24 z$`VL4-+rI3PCB(mg&yD|l_P(eA2xa~?}lxdNWv-<24;F&WS1!wxv2it zoIg`v*#yrh6$-10X8qtsNs!gMCaSHodq3X>s(r~=5me<^LBQ&dWT-#-THHI`j)SsM zRCpc_oP<2dHVtL#l17#OcaE2YqKRUC%*!q{D2Jvq>HCelq#H3cpUa1c6E7QZj%(?7 z-g5<{`&GqZODrm3Nh;xKH5A|Z%yg4o10CpRg*`=P%%r?W@Z1?HJk4=YlDhQDw8QOf z+?RE05TU-EGFNw$sJajLRG8ELw1@HY6xWa^;C=**7mrb~vnS!-RntR;UA8e#E6=b$ zImwLa&NwKA+IehjpllI^Q5_UkV}l~S#A)pLRZi}l4Yt6Cj-3&0Mt-q%%S@%@R4WXP|H5C z-Um&bm2VzFVbR91j2BkVZ1j#>zz%uV$aazoT+gLArIRH-pJZSIhZ(Zu_%|du*7F1lV76yk*Td3W==or0XCpn?gZGD-Y( zYOxPZ0uublEmwW^VFf>|<~=)X#`}KgR|791>c&;iJ|ltwScds9@N0)d_nTnAK!6L5 zFWQKDhF(gs|6+chM=d*q6tE-be#1j9n@Fm*I2d8V5R*D-b;f=yYTeTc#n3SLlh(4l zy0diwi7-5ekd}R(MC$!;a?aQ1iikJZp=%OOz}ZGPOgbV%loO zH~0rqu+z+Z!wzqp=&*%koVA6Ht&3->DN}3i$kQJKufGRtkZXoAbN_ho0eK*kCwD>@ zsebMzq?5KEvua7KR zptg(g$0N_kqd?mFY2BV6YY73>|J2k$zPSy^;f?oI6rErZnJGffDT`D6vh|Fw;1_-U zKYuL~q0Nj^`rP$L$5c2(pyk*I-$6{JM9azr+W+hKkl-5}m(!`C6Zt-mp&ugPDeRI#K^ z1TG}pmaBb~U^KI+2bK%Ef|NGclLOspb;-lh()){_@Nu8H6Kc=0*orQ>KWO4cES_lL z&?u`W%zl!Zev__E1a`weFQtTf=u3EKv}hlox^07a|Ft0Pc=IXPxsshO7#&Tdl;AKF(z$WW@?W-caCdUbHyf+UZI*fqJ?F18-evx0YhIN9XtJX6@u_6xVE0ixceJcKGuP~C!A~tT*OolKB?w|QR?dMgorNYxO9&HT3eT_yG$*%IHatNTh)Re#Nk^P)p;ew?Sg!APuNy1LkzCRfaVxX@5|Et696jZ%$s z6&dOoh-ZRI?ca~GmTMFYC%Vdtrby~{+JJbi5NHA|&P{&>djKd1hire7(`{tFs%ely zFAvd@h|`$N>~kYYAEiPqXG|_?w5@)hR5ctkT(lHh#Jak8f+}x~xv(~n1}&N5gYQnH z)2h+g1ShHI2mE>kaNg0wi%rrrzwzvy)$qbagZNb75K+lri}Cj1Qli>~aHvNwgCZBr z?S^$#r5`G*7PE;ax5bw{Bsb}h+ql*W?Wx+ydJ3Q4%*LpLXZjRAoOBGi<$^N&)I00#AtF z#VjI{Kd=te4pDr24xftiTBXqhhR#qBN_p7xqp1P-!dkh}$08}=S`sGXktZ3Kmzmv| z^~XOa^Wm&*MF3>|xv7(TvO^~Ek2nGAK@G0n#wRvQ8J#McQc>d2A!@Nghq)KOuM3;p z#pFV$WClM|%DbS6SCMYEq|Dc-C$}y(oxkS}g17Vp4^cy2eY`$MuHTlzX7P{88;e7H zxe>B+=WPCDDtGI8AIX%QCYV3R=v064_@r^uG(MlhLbUPyKkXGGnJOc!yvk*)kPxT^`sj+ZE}!&s}*IT0uE28w;s zkUN+Cg4PTu-aCma$#8sm`gE~Zb+XW7liHxVc<$? z(jB!PLTbK`CO1s9qf!&%^(34;p5#AMb{b&SDuLIX3snt`m2ES$<+mpX&J7v!i`ZbB zmf){98*-{R#A*n2<(h)szreM&RdlS9n)_W9AEOqpM{<=Ew*G$_O4Fx8KkG)yzcK(~ zK`4+3b^3*FRWLti3R+jp=Jmqo8dA3PU^dVMS6*Ytbi7N5plP)mu^0PUz)Qn*K0R%22ZG1BX`!0VjExL;fP> zVG)U9b;+YrLEQ(Mg1v%0fRg5N{#b{ZTZQeKK&@q#Yy!J(VD`Q!PHgq(#ZrQJPe$$V znxZ|!9Oc6gS_yI-D?e6D#T8cEICEE6DTcg(eXSiWtdByu+dM*k3>CNuZv^gY^)F%5bgI7{)K!>dMM$!#5TH6O`Id=Ph;_W*xwZRgvkE?!EF zm+_`t85t5TFEBF{Y-Lcqo=+mW{a0eV_$dCqu^g7`-f;>U+>4bEt_|Nb(+yr3jb2(Bl_fF*V-?QvALnn_RoBOSJ$(b zE1yx44_H~9w6A6Ty@qi^dDG&qeU#nf@hw;ho)LeA+dMid&X*!?bG3R|#~xni>ZOO> z-lD;tq~yABv2G*l7dpc{^T95v8MZ>{N%%$%KHoEYXHD2q6C!naLiDUCiGJ zU~pj-8%pO%f~e7vF#N8j1zAf;l(OljIY{goP=Pd;hVory=K`xs_^;i>!3*C2N+v1UA86h?VFe;vrVD47>nj~Oee0k{8nUn%@Eks z1kd`b0T04 zBObLp>xywxu;eww&Z6--3>jQKkGjq7>|8$+e~UB`y{`!OeG)7n^pPJ0i}9^65?u3| zRmlx#BN!y;1@rROp;W~l6*pZ1yD4#TK$$uRjBoF5gC+2Iu6(QWueX9!PCv;srwnU% zy2_GLvq5B}r&{cs{C!%u61u^qGHt2bP&GiOv~GB1+>@Ew{1$RsuzWk6GCE{v7KhF# zG=h%GaQkl!+}IP#9FZ_=to@4h{e-FA0HuC4mMpxr*uRk1g@`d5h-giI0uT3VRI7-z z4i2v3y6H6m?HkIv3*;&<3U zO$1K#(woQUlw{rC{dwxhS@Ge=;9=3g-$e^60ZVQX8`zxGHXar>lhr3F62l&nsX2P+ zl`xbGaClz?eks8e$!Rz#b}ri+c`S+NUpN8JLgKdu`6oiQxbGs!TKfKZ2RMkr)Qpl~ zW{_xVsX(EIj+d#xfv^GdHVVF~jLnjWo;k;EIb849XViCjc6IlHATA&xg{Gc3?6C=n zCg~M#KhMGxp`^xLF4!k?tGDJGyT@z>--N&7EY8nvKYD&s3haY>cWJ?<mj)~dl@ z@wA7PPx@(I8(?dn!2~@rucakBan%bV-A#SufDU7Ob0}6@sgWBhjfD8D%n8DwT>#Ar zZ!R(W2Ryu$)b?FuXVdO?ZxqbW4#wKSyh z{ZV|SzL~Td3&CgZ!@KS|>%dO#n_b@?9fwkVH5HfIh~62K%nc-2M{k2ONfq7J|Ui z-q;F=w_4R;@tD(N?rZ5@S0aeNHGW1r7=91S9YWrX<`OFyp|NyuaVyksov;5qBy+C$ zI0ti7h@QJdvN_*Qqqr*D*lGIougl;L&;fmv;YpI4-Tk9J+&flqlgz?E0;ZMQoWJg6 z>2)>T&s>W~M;|@xToOw{2qhK@&1ZPr2n!y^SuzaOQFUtV5Q@jgrK`f);(eu2x(s|3 zTQT0cNEAnAOB*;t)ns%cS9iD_iTllu)@<3<`9e`nICyS8owlf_U%!J5?B*m|;ccFV z(A#2>I~6WZ;d|qtt7G9*;!gO+TR&lxv>(F4EddmwY_QKYI+zLomD5|k`abb!Zq91` z{ud=C6o5po+)00urFka`isc2|UYaF6I zV4WM%dEqapK|l+{NS3VJW7ogb2~nGIj9vSLK{(bA`4rrQtz6oMz;%&|wMPIcChXX1 z7W_55a5R2L%HKy+&1&gzMTm2Cq~A>1{$D%7$mAGPzS-l{KrQp`-ignBGD-8r{(eo% zNeXIWKsse2uEd-Jlk?9M@|NNBvjep_5Oh4@QRc)183wD$e*yxa)zASZi8oqx>teqA zY98hM-}+!S1~v*j^Lvo9r=7m^7F>ozSp) zbi3J!)faC1rgH=anR@Wx_Xy%@D(iFSKO2Ko0&tBykd3nf|LpUm*G;yp{#8ZG}Ha&6`x8f8BKqpPd_)1wQak62I5ukx`-2fZ`}h?n0=x<|5O%eDmvK{s|eB zr}1E2O+ligaYG7HveW;}(^sV)lxxzyzlJ~a?;hS7h^Ma&nR=@}%s|q&u0+32zPbwR zDv?C8!Hh%3S$2sz9rJ+}3w2$ype*L#gc*X?c)_Kb$4ze+4JX6s>98*xFUEPu*CF7F zHTRBmPt)&YwxhONc-GkQC(unQYbvf%VLrIY?-LU}X}Zgh&ETt;L$-|m5)BsquoV2k zzmcCusH!a`=;m1Ekf(nI$g%ATWs@3m;;Lmh^L0B{8vbmIp|)Yeft;R4bxT=6hYzB zZbz}P{S!EDHa|Zh2DLEHOrAOxZ_w>^6=>5~85OUC5sm?(*+%Dz~xY^n$8gfr)FzjIYD{Zl^mLI=90yG+jSncdeiJ`?*ZR^^_3 zwuaW52cxyJsQ~!($4YhLO1fal88?Vc*A3Mpi=^scE7DTHn(j3FoM>W~3Kg6h4(%-- zt_)Zr7ekDeXmU|a_e8nx_&@yUZ@6-P6~^>Qq!l@q+EEIP;l!IKUqbbKS8^l3bJrzb zKI-qro1j#}2v_1X9RBzj#-%rWj!Fgv)fe70KEF!TnP%@3nA<27<4UFfVIhr+2Izg= z43xolY!4JvMptkoT}Q7TMeY3_Z_)s@^!9O{k6iy|orHJy-kWP-aEZS#xp@1wm-4#W zwO@-NkBX2AP6ICvM5l{+*F&UtOmmMHESM?;n47LBf;0#Ft?Zc+vRiebaTqBp%(YU^{89M7zLcBV4E}*S@e78gbebnLysjPjMD?+J)kcDx=Z45(BA4HAUgrZw?X9l7;6&=*(&@czKB~#Q~O_of#0y_gk~mKr#JkZ8(J{a3axgD$Aoz zcBtHJZfk%XwUDb%jnSi_1I8Vtf6x;_{{WJi5u^WdD#Oxq)Ej|dO?5Ol3n1Q8yO?*$ z88za|{_@%b4J2Md&##b0;m>!S|-`)G%Lef?QIJs0jm)&Vb^VGEVZ?D3E+A;RTJcwbD6B2+;c2Z&13 z*jxfNvnM8ZM0FdNbOc;heRPS;cP`lvuA~R~E=Y%UMQs>iW(UlW0o<-X{#(~b9R#=N zBb|PhdcEip2F~8dXxWC~h>!@6^xDU*7h1Eq6y6CbxUUF5DT6fX<%42Ayw@0faE72W z`zR37l=_eRc0XwHiG!t?Tcp%r^liZnFNl+H$)0QMOg4;ko;_{#`Be`GQ*mfnlhyZH z9`hLo}&D@sLh7MSnjuJWS8QhZk`2)fz7XlLai@6 zj4mkM-ue(Wt7M%WJ$!kk6mY|dH0RYm==a*OQNw;ggJ&QZpq0%aiSov~bB*;q4aAtq z4mg@fMAv(&q`i&awqE2L;;KOJS{f~rQ{>cAB-7fGa(6oyEi5%E2>RIuOfuWix8Z1~ z48r|1yGIW3N3{iQ+Lmwwc*%$|841Hxg2YKyt)+%4n66ao>$<&bq2eY1niXhbkc?yz zDq6;(2@KL*>ebhfkp-kdu(=++SWbsrq*5e|DzA1j>0wqsW#e|bnC)1XIPMf__$c9u zh+Cc!Uogy3RO~rKA1i33SuiJ1U-{OkM$IEO^Lt8LJ=flSa1v_p-k<2R# z<{>}DF<0GSjbaj3?);d$1F?4!c>l&B6sw2IRBO40A+XK5-B!95I7OyqCA4ugTyfwQ zV5)5aaDNZcqomw~4>1#sHu*z42kRRSIZG@pPy1|UrGl~FH$YFtt+FycxzU?Vn_Zgz zh7i{vetSW!l_Kr|&z?SO3n$a~TbN71pDG_)PtC@TfjMrZyu3E5d@pr$EeN~JtKHR^<-83RL zZzU>r<|aSW|3-e{A)2!`R?KDJmpL5bjbr=#BEnO;KbMi^}SidHP_Z0gpC zvI?D)E}eucAo2G7IeFRBNQRN7x1Ws!Xh_j_0 z;o3a`BJ~Fo-`j@wWm=bcsE@+}1O~g|OyjfU$DP%F+ErM$Mp0otI%bB2fi+rA@UqTe z98!5nMj+|%2K&ryOzB8TWx=Im0gj1WzRpd4LHQF1Eq16Hoirhac&^hUPM2r1P&8Tk zdA8J&y~%Lb<*Y~xOTLZ`=uZA(f83V;xZyKea+A%%mV^MYWT8QQ(eSa1Vac!>NAB}J zq@2j>FP&!r@}x=w1#2lgPo}Nf_B&Hi2hNrl5%%eTjs6!R(o8ImzU;s0Oj#81wgG8} z2R!>90Ic;z8`k%T=1>$t6I5&^S@;U)vC)&jg_0yC&LBOl`b*LALw6?|NJy(LQ8`xBmBWjNKr!<8nOTn=3d%O$^W|1 zM}_w)IYoO#I7MxX-#mAnu4NY_J%KgJr6{K} zYe1nI*Ckrj_+GvmEf1OeL^)!f(7VWk~na_dY&6VPpWYa$^Q=)+-W{jJ3K8W_=klLHYAQUiC z7qi0x?t0^E45$jEhmiPZhaz66_|IaGdK;eI(Kl_$?gZ zSq2&>svGLVfjk0PSDppOL>pF)cI&9Kd4OQ~!)94&Wc&L`vhEv4g02KJdl-B)T=CX(?g?WR>;&=Es!H7&Rsm_a%J?qW9XJUG<(OEl#b28#s zW<r-AS2BOgFYrkv%hN&SFT{V`(co#6cnI z;76=vL7_U0ZYx!436>#BFyLFCOe*4ewV9(_jP`3Uf4YH{tEG?n250@58n2WL7o+_R zIWxX$#r*(fKSfFgpSr8+mFMZ*%r5rVY@ku5a@$n|i; zU%i~d~e!5R(q;Z^Qut(wF=cK1+;FyEPIKToz~74L+=Y3 zwNp=+CviP%H&AgaklQYaSZ5M7eQ1N7(UmW|@Rn>-;LQ{!|Lm?N?j{Ku6015Db-+{b zI6kZB^dshe6lbl)^n<&?hd(*rB8wr$S3i%3fcjnB4WJtKCm(){0VA_xdrWgeTrKqX z;v9jUaly!|@z6JAd=Ck^nA^$!eM?Z&CC=yFdbh_5Wh;?hka^BO9`sr12kd!tZUDh? zVSeL?har6(5qF#0KwXbs#yftj{a~bm}?e#VT zxQ>FinD4gd-2@!z=1c=l?`|~}cMp@jh>)sD*KcQLpfGF?Qh?6lz1Gz`XnZ|IXqlv+ z`$(qP6P}`3L8w+!kr!emO0x?kq*y_{#00tE4xq(>7NB`I|MBD{-jrw-fSt3p@x`;oF{U8?%ASS7bJga%FDio&#EOm0aeSTwve7&W>h`sKmR z(Fdin4j8L>sQ2TOsUIGu5FaO>$z&Kt{PZ#0QbX#3L z;oK}&Ql$p2YBGDeQ1*DZJ*r(7o_tv&4KKrZN9;fUnCT~y(+$Kwu^eTT+kC0ol-&-X z`>-XzU(Z5^6o2@Ggr%CQYXuadkvoDXRKs6ci!tgYLO1eKux@-5x>+#ln z&4t@*A`)tvaSME{g=SCI&wL+R9|Y&Ukv#giPSt;@rL>D1xCB5hT}wB=S(ouy?@rsj z;T*)y!{_`{I0+Q`EBaUO0T)7zly&*Zem7c$2eOoq_6k}4hTHqu%LAa+;$>+#`^`${ z%@O=cI{JMdlg_7wAZTjKQL(}AjVZBAR@X37;g@_O6%yY_s!RoMNjXO!sOf{i4u^NkNn|uKj!cONANgHHd8E6<~+Hs4a9s1s1 zmkZC7up&^%f*Z6(I$H@tiLxP3jmic`aBM<^ zRWl)!$KiD?Db5cQEOKZhZVQ4|_ynSbSHSJ2a)^x{yhme+U!6CZhLyT!;Gv;m?d9-8(~U5wSvd)c^*4&Ag%q-eZx}P)n(rY z@iZiJ_ApMJJKe{*OuGvXINB{r|w-*(50+2#yFm3v>&y^61&=Y6i*q8SQp zmFZeMjhMP449Vugb(Vl^Lit-YM(LB?W{36}kv~fFV4ARo3kw}p>l+D)mQ~vs{{t>M z9E$5p6}#U4XAyH}inY%RFaH`FfS6r5WApd&>+Uhg=<0`G%1v7Fv@19APAQ(_jemt# zZVjv0EoJ`ES*MdX2saZiZfwKB7t|hH9-fmF5!*Vu2mY^S>p|sTR%03;+mnu(gYU{b zMhR`JIqnG%57b?Oix{U)&BPYblcNGs^Q3x>;mQoqS>>jlI25>1_zfJj3l(eX!#wM&ePO zRNNl_e?4q=c`F+CAns6Fb62ZkG!(bH8o00V-$zfofBpp1W6?$ZJIy>bAY^7q!1Xhm zi=yjXxj=;o^1R``o4#dxVuG_1^F6k!qKFn99?6iL{p>fm#q{EA;Jt$mdJl8tWkg9L zRfLdphKZbc?Of!^VHjs;u14;rCd?4cmX^cIJ$`B8PSkd^>v9+`laQuzVz{=&vpDZW zZN!z%psY+mR7L!tAHoJNZ+S@{StfY6ZT#U#{L4dkP*w84CgVXgR3-=~9aOe5#k49$ zm#y#rou%Sfz*SA4Qp7B#UOsXo*3IBxh8a_z0Mh)o*O-kJjUp=pqX*b50rLm{ zetX6<$1k9Y6U$Z&_1-g&2ff*rOD8YAYuvrqj7@mtAU!wAtR}rhbJV6 z-|=NDREUI8oQDoKySvu)fIO54Ds&(HH*RB4#BB4s&i??7yl^V;K-2;snutUd(JRAA zsCUhwn9YP9(L=vWouxJrr0h;0+{ei{mJcuC)oO@) z>m}4&VS&|g^1yqAz|pBDyHigazu$)!hl54FbkXcFFalsTkDU8jZL)^PI!M0x49Qk= z4Ur?8hcgc>;+f^ZuG*u;9H70P=wbF0-oJviXY_pl=jN!|;Ac9R*O5ySJKMMY2M#?5 zv_>&*AC{vrXg4AY&MKkyTH?RZ=)o6&k08pru@u=QLXNL`$(x7xu4@H0D(MLjT3Uw9+m3jhl9~;lW#?cW#C3MDeETM3VZCnrQp=FJFar zT_-wQxQ##47&etg-OkJX@hoiLfsJ2&JtAh>o(NRzhpS_=t;9LM$NacT(=syu{XbwO zdIy8zzjOUA2A4}B@52=L7_wMStE~6{uOGE$6^7X2c@BlAcW%ZH7^wb;J}<(MSD})P zWk$C!j{gIqngq+~VK>B!SH!-J`hIq~aN(hflI0($*U#~=>x9biT7yTk#A`V4?FEi| zw&Iq(nqhl=LP^CojlrZ3+gYPPrIxO7>lejZua0j^&({8Wva{h6jwb#G`14|^!LjtR zr|IU_#l^O+6-WlVQN zRnOG@8W5K_R{HIBKN1Li_Kyg2G(e#xp3z+n-QHEET8o>U%j}7c+CcZ)0wT7DxNaBd zHd`1WtU*t!@OE@)PcGA}kj=t~xrm}HS+NVLsU-cCIQ_A5fj7YNTT|bpWyCH}-Wicj zJJ@PezQA&Fna`8+d;! zCI5Q^?W;Er0k*ef>$ZLg%=zm!7t=C z#EA^y8_6e>%8=~gUmBw+=Dy?q^xJ0ve!;+}}qI#tRWk9rp#1IrxWl zQV>sP#yPzVeS088VXO&kc+cKm)F{F4K*Y{lgjGYjj~ChZ-J3SIHc=P*1TCX|`?^){ zsCN-ov-51w-?mwIr}E^&tn`!xrB62M{bnJx>6L?FU*X8*^I9uSCJ0eOFpL`7{A~|% z4pX6zk!)#>?nX&dYT{j3^ph&nL(Eo11mBrJnHZVrtE^k#niQJBTa=rHI@A9p{^2F{ zi5e=0PFCl^a3oK=H$9t>O{D{m-(qD_t&p4|ORqjmHN+C^x10Vg>5?C zY=4Nk|Jr6d{Dr<4h2rE;f-QVYI?t+LoO4#;Ig`kiR&Qj`zcMMz*V+KVG?h+gpO6=Q zs_6O3#zzli~=u#j(?pH9^a^{jEJ3zt2Xm&70G7RNCC4|sguQ19k44@bfShj2dYv~A}L$1I_i4u`$xjnBHXqZ>oi zWMlI-L{5BUrO*qTzL~jS?W9s|p50Gs1ZNB;_hyn82u!F;1wEYVK|nHq3rP#LxnzT>ZB2SbUTaxo9iCbE- zBW*E9`27*abxUI#&37*a=+mxbn=QHYa)r=?VXL6*#!xK{YdoFJ@T{20xtsQTaLE&m z3zkQW-y80Z#n*S**2E8_Fl^T>6sPL?h#^$jp2Mv9xV1HT5NDiL-w}gndEAsk#OGv> zpD>KQVBmkEjG6s_{W`pn*v)PF5ZO~aAL*ar>9d7UA5K1^UXaNDyOL2ZD7PVdQS@#! z5)Gxi*)Tl-Iq^8R(XEQuQ{uKDPQKAsm(Z!EGhDnZu5I=g0ET?AB7TFDZCe2-c{fC2 zpGuoVOo#I8X6m6Nv6BKHM#0GxR=3iND~nd1OB*J<9WDH0!m~&8;Q3# z-94@D?TgItb2=jVVW=}AI00FTa0QDv@Y;#1C#azQFG02@LpakjXBuGySN zilRwh(rD)xdGK!zvzXL0jI}5~ziwTeBD-3;FyA}A0;j!kUYAO{8y&SvPpDojo*Mn* z-Q3Orjedg-izpbddL#kQ7`dbHYx1-0=o|kBH}n35pB~OyqrY4zyA!5@*P|ESuFHc- zf>8F&4xAbv*XJX5*jmm83Aa)VEK%RAUt%g#B#3v+3fJAOHhZjp{JBiR8EPM5o!ntct4vYCNq;j(hrm=a>DD!ehgO6iR$gq_r1Xl}e13hqY z2tG*)(D|58+=E`C4psy)RI3=4iAWsVbiyMl!<)^SRQBIqT-;GU=NUiL*gU(;m#aLt zk}ykD{;kR5;8BM)g4#qCXcoviqqfA}xsH5li7ux)38DzNS$Jan{Jr^hKnVFxjTcgz z#G%BZ%1l;jh)?W6g1n0*y-8olu;^1NCY&|-S^fg zIQl;gELNMhdhM>pj6#qxRz`>aZSyQw?jZ5@g5?+M7mh%xD4~UkDszI;sdP)()SK1B zYTk2EoXarN6vDpu}+rew5;xRXgfS1+fQ=;R5Cc?UX_SlT~tY^D)vXKrm zOmrP*{YME)%kl}=OISW-56*o5Y_(a;`{^;hZ_q7Xiol7wtsc9+{*!J_f;BwdFKVNR zqqOI4WK=C4xvLtT%-*dyP2y@2Rcu%pJu1nEKmNAC^kYz{Zi68KnmnWb?%DCqtVo`~ zm#XE9?@1NYyGm$-pyt-b+0z5wS3FW#d?w_*8PUOeJIzFzdlnbsqfWSC&x38;QX zjelF18V}~zzgzBqq&Xr%h^#@!cQ8^y{F)4S)CYA#EU(4%2mrbS0nPsA??cq70#(@SeW5YL2~YTRxW!WI>E%7u8xG8$ak%E)pYP+o2MayFmNtiQP!cX;+}AD3Mj zg?=AEE`iTt@!zA; z(k3VHll(qfkA>!!o-GrDd>yOpy}vb~!gfKjFdhNZr)s@J5ntp6a2>&|71UFw_}kkiX@alx+t>A7rNIs(E7@$#30?P|GcHS5T;^C|>br02<79Hp!KRzD zRl8P>FcRkaAbK|25T5S0)A;%P{ZD1G>A3q&f=oP?t*h&A_rSlPqk${{ES3Sx@tE^^ zX`hFX4YC>7jhtOHUBR4)QdnCT++fLoB%f=~`c>?21y^f4DEk&sf4RxH;&Q#8jJ|eM?wSI`mKw4$^yWAaR%OeS;Bf7#xWE*s!Dm=ED#|B|L72%>ATT8Y-PWWp7z3}LqC z?hRgWHKg-7v8S{5tKI^+$<$P{-%Ru~-0x^NklkJ2t>XnRlaPgt7W+&yB6Sr+Hn{=Ihx>xuYN!soSh>vO8Z*VD6Ll@Zs`Tdsu^k zc4x0O=Y9dUc6pzQ3 zYyAlQdX9%Xkd4iO(9|iE?K<@a-dgbVqTX?1VaMdBvwUPx-K#c)PV zSuKiF;1$iTt~_1>K}h`e^YxueyLWS?=RcMA#64B*E>ZHlZKqQ>`QU}!w78&p?Du3L z38M$C0I=!lCn;>1^rFVB#)|Z+cOzkv7lBdZ)F?$k;39AlRkr70b*b-BW+jhr)(U#n zcEdEw%6*ah+y@6n@qv zwPta|q~$Mg2$OwU^~qB_)D0g1r?NmPk(7kArK$?xk*{E+A5Q)L^b@>In6%gh@lT!?Obm>ue=GX zNNa!M7}c?O@;xFCQCZeo{^NC9JH&(-P*$M56`rZOEV=2@z*)FD`z}YL%++k9w z@ztk>alTZUMbj<33pEtp8dhd2!j;9lC~hUR_f8YSjR%>Hyk{6a{KDEM^M&TMMVhgg z5;iDjWt7iyW4pzgxKGBX;4aK z0bW5v^*3kRDjghJ^{bw(Rg6wgjd(RVueFl6WIbX|hbJ)$07&JqEV9OS=2Q|riEr!Gta&HH+%!X(T0V}-!E2{o(~9&H&j;`shpGMRg6oQeNPBM90tGP z00`SoIpoDZKV3qp-_x9a{$d)~4XpKBV$pA6dxWB&zmJ*Jk8PIZbasl0T8Uw22!)sm zLR}Om7ar$YUcX^?p;C$GFYpW{Kl11c-#I6@0Zws&<%-+T@2OC2o$JggXX9ZN6@9|{ z^~G~+Lr$)r=$PJ0#kZP>=R$4VVBW<|WdY{r2Bv!~j#F0YK5#m`eHJAh3)Gcnkk>Nk zcwZ%6t0DM?eoB5FYw#t%^v>ta{d9#u7p!Pp01}mRpAgX0b6 zsu{$mVLB!%Gz)r~z+aSWPT)Q^HsHXyt&LNt8G!dq;r`TokdYk%LN;reor-*w1wg{% zOjZ|EI)D`#&39HPxU1_IyR}tp&0=zOgAtuJXSxm|A=Aor@P(sECxzi>)?T9=SMB=- zD^k~!4TzMOP)PJPQGDdB)3<=MaYx4hSmqn!=&tCw_$|;{D#mM3QHfnRUqn?P`hS9=x_0htZ18(m82fMjqlD`B(dx zpP(JM1=l{K%2~H3QJxby^dn2sXpn7L(GW;5O5QPeTsD`)Z?$`)dRNv}#OZ+@1TOAp zsOyRse$^ZUA#qEt{<+;qX1u(0W`jj+6nuZ7n0UEJ;Im68Y>#=+CWVyJ-4AHC*yR24 zK}bQ2BY+#+Z0&~wAxp0Vu;)KF1W04KQa1F{tj!vQXqp-$&U3Qqc5288)l1oNBv*kR zn-?Q|JCc7@*03YH?e~!0Lk9T-|aDe{97oPQf;MZ4ux?iGZM@OIIsg zTNu2#E^43%Q|fFu5@=ArDm#iIl(QSPJHYN(-Wj39#vN{~ey8d7jjnKwTw>fPRBcrl zUFh8szD@>ss=~vUHpH6}vz(55Yp~{)vnum^az z{{onknf(V>W=c1V)TvNBa@W&C-6jnnHrFEwwy1Cq~Jwo1M%?|sx$F7?;qr*Ct~P|l_4*q?)=k0ORDnrv1s37 zwI*#dWVmKvGa4OX@m|~Z;&e%EyWOacn_JLVY^d{+I$>vH9)q7-R%qJ$Uhc_J8Sz6^ z#3B|=?{L*~j5LFQL3w++d8JgtW^RKvVZ9n<*#ef4e;A+LorGKB`FwJ;zErJMqeg)zm$j6-yX^9zh#luc*xU0GU4)d~i8alY8-2gbL>GCv%+OE|?i z=q;Zoq`{wk(?ZyM;Jc{lIcgjA`(6$>&PASg@gZ)Tfu0h7z89U_T^91_q$Y=T_nN9X zKl{4R$@8$E?YC3wwKv$RSZ&r%yJD;B$Q-;@{jL5b(UJ0#Y}h#J>!L+sGN_5V^3Bnn zkf_>J2*l0Z8qKMJxttR&5!%KEfIZmh6cnnqa|PNfY$y5R^n~WOh26Z_)KU7%|eOU zYol9iHU-P@EGiX0B%|xGpvp+!mps^y>0BfB!trx~h?EOr7$58X-db#h4_6x(_=uTY z6EH@@V-cPJeQ-{6X=>$7SSwkVY1_ZwW+YYMG9vZ9bp^{8R~5fiXMU4M)vwk_ym_ka zT~cQ7X^`!WKf7!_BcA3X@&-9(Ew*`l2R>hg#m?xuPf*NxYxT;b6xUOypgDIUd3o7Ah=e!8P}DYhN*rohfH zWl(y;uUBli2zpT0*Zz-dPOz}+Ll%-0kgW_Wo%z(7` zRqrRN6=Py;8O7X#rFK3zp6l1XwBKcu;lRON`lDc@8?n$|0ui;UK4BGMmdU-mg zY!-CoR0Q6qFmjfg_jyqgZyL6PlvuszO>E$%dPc zr4B9P5_q>C83you8MPA)2_FrV*e-|0nKt3)9zVthCsDi&yaG|Dds?)IR6YowQf2Dz zyqw{cG>t9n@M&C&7&a2mQnfkHn(Wzrn&;kPaT7v9`t^GGm#y#;Osc#EeE`Jz)USfQ z;ghluq9xJBruwY_>-#)WntNuVjDlQ zvplJ7ZYTj#fF1Ru(MvlqXA4u2s?tR+iRTg|S~lT8`VNkA?QN%9sA24rk~e6-F9VKX z`WGvDW7G5lYvGm_texH<-wjdlrusx6rdsyLwZy!7?yI7K-4@m6>7Q zH_TM7ULUCF>DMZg3RK9Zv9@AIOlr+z-M2SZO1BQ_Lcmqx*Zcq4^$}lQcGSn7Y(NWI zpb^%~t4OiRnYBdzEU2o52#${uq37Z}Vo0>$5uYIIANei~h^dW=S?ct-dD}$!?>gC^M?iuJ`;yQ<=M26 zV~iyl?^*yRg5mc6xvk-oMbHw^GwcD1xRAHpm6gbnEW>JE>&tM;=jiB%%=phkl<25c zc(WmV0rLi@EgABp>)HK{$JL2nWaMgpKR^C`6|~Rwgk25V3u=UOur)_R4XspPT6|2?K(-o)tHJem zNR^W8{yWbw+Z?dc=wk^Q3-355BC-7gNGJx9gu_|3uyMVi05L4-cpoVyQzvjEDeZ9t zG`6_Zp(J+B&DF$SG&3#82Mc~%Tr0OK1N}>oO{X$NlS_^(=NeMie zfnub-j22#(9234yr@^Y(P0FpmykDI5#|$91sBlcmJh%S7;0kdZat+R4kDY8z>V8ZwWM#{EWR@}e}q~pY?LIGYkyjB5~ zLxGz(CwBu_Zq3U=wQ0Td{nnjn77FFsxqF{9S zY-o@{RtHX?%WW~p%vtL2oT3#nUf^QCA^+qt=e+EABiod~uYRn8Z2P^tjE_i4x2>u2Bi5g|y z!f$FMe%Z!2ddG*copR9sE#3Jn*cx+IoKj|Zuj2t4e9Nv@JCo>C z0#@GsQJ`RW7oIUtzsvEN*O6EG^yO3BPlq{_NUs&xDjw_Y)&P>Oxbomz_c<=3-1fBa zz=$y1_kDk>oMEK(1vy_M3{QUZ?Y_uZXr`?7+KhnD>+2fCCK|{PP?EGpmGWmXi0$Y_Rp*aV zvv%^x#GO?g^~Ock-AtpmbRW{%T?3F}9tNqAxHm$5RmFR0^SEYaA z^5wuOsr4oDhW6$?Uw_DcWU82Q1(48co-{X(F?*8|dZ}QHz9VMe0W>2}(P-qz zTja$pgt@LGL0*-Dfzcr56EIWCyJ`egmG>TB;iVR&RE}-i<_6PbD`_m~HV{dH>@VBW zRI@%Yl*%QC4SN+HPDoN(T;@r_Gf=!RrVW65+ei5XvRt?!bN4e$1E}cS)(Q$#R7H$Z8oOo%)*-IbW^8ZWb4Vqx_vK^3?mzI7dRbp2u zTi0|!2nfbw(DFiOcf5R}mr(KZzhp3$x8Vg<*Q2ADbKE8{EN zK5!*&o=`!9Oqdn);00a96EHH)HJ&2ql17L{p z*Bd(LXCxn481~6ps@e+V;V0L(7`Ngl$lZ6j_-QTG3>mier?SB=ex;XamD@5iea2+% zRhF2Oi`S2yI3jXP5JB;sYsGh4n2JxIiA8gYbZv@Lhe4&{qL<)I+l_po7^T2hvaKob=ha9c&3Q2EkVsu{-&T7ZGzcG<9@6uHEM`ys_NS zwSl~&OY4y}h2nXSWPPl|n0RNaa%ecd_H+6rm(^NB7`NA$?7=+{fLu(m_x|8H9T70d zm9BXP&#Qyi?PHBA=i3~|q^-lHD{gWqeyZTEdOJbFzR8n?icWZ7Kw9$m7|aAYeS2ZA zk4qj9B$$oH)e3{}1yp$Ir-sYJ8sLtu2dvDhMYPs9OZczGMJvig$zu6Ya)0D3`Gh#- z>kEoa#frD!_IyrtHq6*$`JGnHMpl-u0*muqck0oyqF1HA-&&`}Hs^iqxNM_*y>-KabnowCeM`YV$ z}Eyy>zwTS4ubvappfyw2F3t(c6YGhf4A4mgBImWjA*i?I64*Mr?F>CauSw79Vg}ew*irO5 z&t3D;vMwe}jIuOvg1KB1c`P(1dOakoUn3V_ZL|uht97Vqp`kshio*rZR~->-Ogq_h zwK#5Cbi!5H`mVP2l4LSeW-@Mu5J}O}B4H4V&85t)W%V2%96oItfkrJKxsUr06N(n^tN6dq(PsO&_u zw2fvRdijiJ!rn%Qt>tq$roX5GoCJK$w>7x5lxE1qf9YIOZ^{cz`%1}&;wX^3j&Pkw znS#4V*-|uWFm$>38YhUbgN=klmc(Epy=*>UM9kY}P*g7;oBdZ>`q)m{B75%mr;PNp z0{7HRvK_4|ZgcM8_S<4L9MskYIn@^q$bXV6MV38b3G)t2IFKKS+Qo$$&k z%pBu{tz*Nbyeamv#uA_x8M~e4l|H2pG)s)tRKpiKQ-RPp-JPYECcI=s-QEPg82&DG z76Q|MWZ#P~#g_(M@XCyY7i?@nZosr3KR!Ktic;FxUN$McMHB`tao$~#Sa*1j5}JJ0 zxhrI=*5_L{B&iw^*3a$O%jL_pmc;UIo-lLyL^z{OkbRiS?xN8nBc=}!tl&9Y&;Jb#X0@gtivhN1VSNI{HI!EY@% zLd>m;4Wq2>AyyEHOXcbeF4^pUEHy5Z3WtT6RaN;O(8}?uSP&H}zq;+C3}6f6 zdp){=<|I;Lg}6v%C!HL=%pZ+ySCj7hX zYnu>CgDIO7ts#zkq8mhbsiY#vHH2r0@%&OUS52u`9JvIlEFk45lVqJZGJU2ImoQ$} zW-Za`gO$j-mlQ=eQnpY)>G;HnIBt!36$&Kt@%hM-vMTg7ZCHCbrD12UlP1{=D-~Rm z4JB1i2vmDJ=KuH`8u4L_KeYBctW+FMmH7 zfUE2mOK}!F{hm@shQ)>|Da{A5*;wB*+WhhIE-9MJOrZLn+S#+39Bf;Y`}*17shsA+ z5Zy(GJb7#wsroJIRAs;?5eW-?@WGCs@+V2#U=CkMol%3XyH!DG0W6>H8!~v z`sm4FrPzm-*-uC>$JmveD#5Z!7?>5O*U4gdn zY-%Z`_eg3@Zc-&L4MaCsbiExo)a2|`u~&s1`=N|%(}X?Q!?Aeiu1J=X0(Z>|yO8iXP${+r$u(24^ z3QO#lw9~VTP)8z5J;XD)>7f`Q0hb5i=cD5N8UC3?AYWUyN0x*pG5APkvdAgRmrvsl zxFsvRj?!fKVV5sO_rCfpQbkF`3jwBL;(NBd%7z!v_a~Ec7;kh-Gr@R)XUyC2Q$ndk zoPX?TZJTiw>4mh~>Alj>gnoFZr1WbG@@oATV zxE#e^l>E^Xq@`hvcny*R469ou81wh89eX>IO)(8*#k<4s|5yo;>P8vD%Xf$;PMr>x zCd2!zbAjr-&;xB!;P`H*Qk433cpc9pN-ZmMbpYd~a$9?Yb@37%{7I~9g(#BQQ26gr zvH%sv`Q;?<6ohf%A|qb(Yx1gNZ;PE%uExcBUK!PM;erBWU;Jk0@k>)aOOuJ<8i9dM zbcvm~wnp6pr{#y4(F)fE-W2So;j=JVWsx!9ynF7IS>t3r#GuCbL|;B;oAfxkGI4uS zdO`}hElpgZJ|b!gyaL6Bm1IjUVPB`&Sc+xV1jhgxpiey|j)AqaKg>^uan)!VJ;F^s z_J7cw+cdrDVgAGG#+sx1Q#&@B{hy=5))>-Yki@9me&UJ?bPCJqtaoqaRLfT(3=0mr z4jC4610W_9?P{$9LoT4pi(v0I>t>=_y#>PLbH-9gcHVp z6v|e5-|>7rZKQ{iCEmb6|3SaVSIxr6Z z=8ER+BYzZrg4Pz&=AdEdQ{b=sl|6$M<{lcg__?E7=p86hgC5VAoEUkbKNHt*uc{%h1n?*Z zluRZ0=@w+4k(LQj%MkYp9>ZecCH1GK z!nsIz8~wWEm^aVQ+T=GTT2d;vI!UoSXtw4iq`_UWgCDhtkB<=aw}lD=BX?wCN)+cD zcL|eF@8AfwR%7|=8}ghV_{HYSqJ13Vfddb5W5dEx|9{t65sn`PR?g&$$XzSziExx8 z*h_bAX|U^m=-w(j={%kFytu1r#vtikJJvr?WK6J?M>zj~H~-lW@Gz^0!Q zedkg9<%@#(JQk!Rvp4*I0UmizK`J2?3jCTs%@;djj7iSl*+|MyecTOW z{1|MRz3}BzWJ{k>eAOA=iB#2AHN22K*eDB4hbzJc=r7Z@73Q`J(Sei?X`=bE$}jh511_! z!1LIv1&U`UcOosW__azG^ZjTLF;DJ@KovT=3Mt1P?ApFwydKLdY+~f~UO!f-`-USG z-C}TsTliDgqVW(d29MJQZ*g8nlc=^WL;GO#7#%@yaPf8%o_w`*JjEOAUlA*zZ&SEm90LlW!gm29x+ zdm6LqYZ@;pSYNto=h+j6Il$OWB+mQY6#7g-^xAK@s&4=`{Z*`Ds(foyC;HpnJK`UEZH>2MP_cCEXn{Zd) zK!?@iI>jaB;Ve44s#xZyj*G=^P=>{^lbnqu$hD@l0&eR{FuH3S&1J||^CS_f3(own zkiDQgnmU^ca;Ws|8$lCEWCw&HZyCr_?*3H+Z3JlLU(btl(QQJw+l_flG=(H(v&61< z#_rPfXAIiC*PJnLUmHx^piROnFb4@13WIE5?vWa<9m|2y01|@+8Z30GewoV`n#uRb zK4mOW-Nl3Xo5Kc1j*7;WuC&0JrA>cAoT=5)`_#xyc@sWv$-dWHQ-Hc;PM5vL%DtZJso+h`ZThCriN=cf$>sgjZ)D=3rP8D;3uvFTa`KzZ;jB zB^Caj;C!{-RHTN5>KAA9dgW$OmFs1SvJhG(?8F-64pL<5cB0PvU#>GnXji4vA~v!f zhW$I&U>f^nEToaTY+rqC4tPkr{mSM9>*&RVv=p8JhWQ?T28axQGIGH z+m#=pK>^sztFqq3mkdL-_1OIi{#Z-^ zPy>)~-QYy>Ipm?>&LEsDt4TRLm%KO-{&g8NN!Lu7NoWK|!`L)mifjd;GxytXwsv~k zqv=n3k2IXz6}wHMigwZ^m{{6=n_-2%)_r~X`PQ7bV6uy73qHZ&Fm==3)+-X##d6sc z7YjznCi=?#bS*Pw7?tYJRraT-HNVV~q=+hnZxp9qjo!Tt68`$i+0vb-MEQ6_*c#H1 zF)3QgRD1`!?V2L0{g3lRZD(%+cC;U_eUNkiK-Q>I`u7`0h7Id&5eNbYEX}aozvVi_ zKo?!wN*X;ZRKMSJ&hpn`s(qokUG=o)Bi)Y|gp@92H#gRZsRbXu!V7V!2q}zZezn=v z3|Y)RkW5b2c<9^qx|N7Flu0?&^fdrqp_nr?;p3tkJKoLLt;^z~;jQjtIB<0^IO6wb z;q?`RAS>UZ(czYbVOfz5mg;KVPk#dKyrrHlls#?!$!uwrFx~kRb`7ji0OSI~ny**WIz;aZogvtkCKXnLIO^HzcB%8=z@6er!>f9tHnQ zuy`gttI;kn*N>wB@La(T%9VINCr>qG$yiC${pl=zxWH8#-Je%#l&Q7D?<$n5$ZUN& zn%K*$^>%)il8d)4`br*cunXx*T!tk!ny5`!M(eOx zIc$Dy0RTDYM=(ETe_hrXs)`O0f{-TGX|SwveiUzndnQnupt7S|MBWl&m|Uvx{`h|N z0?J6dQla>3+51!LDcnLk7D@+NMmVqPF3;bU&o5kKo-xE8iLnD*h9@K)r}p-qSZ%41 z{cGuJhZ~$&jyLtPaswJNlxXu+#gr#JuJq}%0wkMbf2;c{lvj_EQ9}FkwS6+ogNe`Y z`iXf_@PwIRobg4Bif!3nAmGFvb7ogCO|<^Z;udcf5xvrP{L&Tqn5*KVf4HelnHPH- z$5s!YIqTAX`ZWpxRBfCd5Yr-BrE1-Jq>&9G*^ow~wnDvOOLLxaRR>cQz zHW6ilJcvuL)||)vspRz4ui!Iz(SJ1i&Swf`6Os^JlhO@NY()JYhL325$7h#(XtrK? zDAMcORtNi@8sBaF7>2Tqlv`_tI$S|Dtl{;V$KtLUYTf9eOrRVy2@i&oEYG z9q1Ld*N$)M>A5FhK}~?)v7K0PEWl0`Em|Mg3-5;DUNeAym7^9E1y9DXRDtfQ@4uh| zE(X~{_os|k_|h?$qU3Lo0~a|uv9sp|_Gb??uV}GhvG*&g)aS9&71gU~=zguKRj z=kH}XF1zm*Q_RkP@0!sT$6^c?@k|zYPNk1%%WUW+m-KHIu+=O#Yx zqLx>b0Xmet6#s}t#1Xawdos{Ts#kmFD6j_qPQ!p z8vpGo*!`)O_466w#{o)J08kM0x#PG$zu^(ynehJH6c`abEqn9UgX0vdN~|bDwe^-u zB%nOA^%rPknl#uPCUWRmN7c5=?c6Chd|II3bZZSgstR+y?sVRcyf@KiX$tEwHjo%Ljj1jTxKV!cxNZb@)hBhF z$+gOJDw{O=fR5v@jUZ;uo+)17^Q_iQ%j5E_mo8UDo)qIMA$E$>uZG>?n`mBDNs=&iB}+F3XWH3)zGDpeL4fS(<92nm=FSM_BZ~y*0tF*s@*A|4OYlYzAE)X$aNFs>yLfnJ|<1J7HP0uf5-(b zRuptyl=rvZn%EtQX6Mtix2pKB?^_S(U#>BO#7xdN+-mFVr-s*M^z+tEAd@3~)apBG zEP|;oV_AHSt9$$UoSXw0vfrD34R#`9f(5pF9yr%O9bkxl{~jX*_+JRV)mbcFNrIR( z@7r$nzXybj-7*&bgswCT^?!cB*g9N%o7WY=t9}I9sSB(>i)WE=7DpX&H1vTIMvNy; zka#N;Wd+dGn>#`grZ&Nl+ozJN$#?E;{x;ZEmt}k#<{Vo8Ca=C^_#3#rpPMTcy0P0j ztZzm{;Xudi*docBu2&>~DDx=C2rV4FPvO%{=46XB%`Xi_CNtElRmwC+b zy_=2%TJlUJX9d@<4Z=$au(;nc;reDLoC}8h?r#Acq=kqmYZ_`8jjIY6tlHY!7kZh= z*2^fEKMGLJy#-YDh-%vay!Ei3@VlHp%k{4$sM{Xtd~s?h z&7|_;Z!Z7vvgW8OWWL?s@dq#nw_k z-Gm%fceJa{omvq=;kc@~Ga$myf4?*J7r3>eEv2vc@wr;q`EXdF4Sb&CL7lRR)sT$U z4Y7?*R(U_#Y2hIVSf`-bpGP5?4}SOH4$YFny57VN#ES#M9~@3=X6+>ke)AXkKpQWz zQ<7W00P~HUDs=^#RF%dqMj!2Uem@e`7?bUGZ!Av`qgV| z!c|zxO~b`J{sf&F!+YMB+ptYoi4bA%aom4k`)AUTWET~2`|pW-i=a>YC;EaT7)mj= z?)uW@xJFs6#rk`%Z|w@2%G@fvKJp@>HzRX@V?PKgTV2b*{;2;8u-{yMZn35H>%3jo z)6AXX+W}za1#`|9^O!*o!784?;K(aI=4YIe}fnRPb z$M>HAo@)pfF%F9iI;nz#& z_TTg;D+woe!j?BRJzTBTd%m>GF#{N$zusmeJxdZVn!K>EHB0}f2)soqH{Kpt!5%Nx z6M?QPU2b6Z_pBK?&bxv}HJ8!wSa)%uQ;(kl*HrB_TwJ}9Ud`Jp0`kwo_B>hcxjD(T6IlLz3lyE1Z1i6a$0cFp zx!;S%(>Gx?qP8jD>GI83am;R6rdGFOY2r^79l?4L=*tpRWFGIQhPvwbD;-SKBk4?m ztdz=VsW(-Cc$$7O+oRMS^*&TpZ*x= z_qryB+B;2$W=iE6&ND*L=les2Fv) zn~^%sJmbK3z7rC{`kYVgNcpVGZgGLvxqA_3!I*jYY5M_rndHOL-&AI_p6NLMe~%_H z|8&_VmHm4qpM5Xj2mbglQ3L5*`sYPIbsK}TM?`x5fbU)FqYnn15M9tN6&K%KsZNto zj1K1hvq#1ITo2#gscK%#zCE>jYQzR~6m2dW56A08ATT_)3c$A-~PPX8ES9VpU6CyvboqtA;|PH;~UET`(Tf?Q?GWkm3DyoI@{(MIZse;^Io927w`NfB=sk|9gv0le3e}Qz#Qo(|&>TeqC$&NX0 z5&w3wiZ&2@&;Odo&}@DA&S=!Q+A}sIPnAU}O1WNQw-|o!D7Kf6YRJFBFnifAlh_Rb z1kBck#zA=axKm+{`=gXNvnLn+d6ZdZr)Ie&%$N+#TC%T*X5HYh&RL{eRMzk7v}IP3 zt%jw_VKefxTXNT+Jtf+d^)k6vF&=5Uy0nI@Q73njHrvBqvyU6;#=J0P`v&5{!a^~u z?5eku(yyOyUy}@0M%M-^18fE_uKfj6%+-1Bu~EB3U7)6xo6diJ4pHSRsT`aslM(!9 zziR$|Q4`1O>--AxXYu&;9Y^_bv46!oz1-Wzm2Cb38;994k3;b?-~IxglVElISWFv-jRCEQtJFiL3wlpj;{Bf8qh)a5ox*sB97_HBdP%xpklFF{zVP>?u^C!?@ zZ--k^4r7}T=l}kkieW78 z_!xEoLj9yleynE8!>2X~F&UZfeIV+#hN?nS(Ssjv=nQ56J|gp++Ee-7?Ba$5s^t3@ zt(vEhKucbzh}?n^hhRImNap_1;^fbl4<$b+{4QL8d4$mr=t^Qy-S^aFV(qr`Eq4{t zB%iJ^hBEHRQZ|rLBX&#obB9Fx@N=g-Q>_%$5!Bw(zU@An^0PbTrei6OgEW0YA-!US zwVVFj6d60o7{M~|k)C_eQ5~o=>4Ip>j0fv@?JSYE&9Qe1$Ix(5&)=3 zc`MssaJSX&VFLx9u5@kT_Pn$M|5w(Vl<$-1w3yeKwI_EeO++Dw-i1jFf7RQE8U2Sg z$_O=w${Va@{w#{X!#kWfzo$;cUdL-AiOht&gryg$DhibJqo-TIsZ%Jqlid>gUHoD( zXe2x+NsWE|>G$1J4g6VZuq(F~Z3u##LkltAy17C(I~GF%qCaD1jBD^CO$YBY?q1Lz z5q<%w*S)Qb<8yvQ_|s-a5f|+X`TZwIBKqDm?tHz-O066L;;8W_Vh9be;^+~-9%!|_ zEy>0_aNPg0{Lqc5+M%(WvC52W@azu0{h(i0!Z`i@h1KX}r@8;$j6uV6yKXr;RPp}% zkcz}AVs~qZN_M)o=-DmYR!zmn0pR?p@6L|#BhFU@<9Po95B~f03Ja3K7qi?y;OQb{ z!8o6tUDS!4Jn#pRZMODwn_mJ%#rv=2h<+d4`JH9(@!!tjl9nnX~@>g ztVMdd1vZEnKMR>MjOKLn59kG|ShF-ayY4v!eUEsI9OteVbLQVtK!mYA?r?5j{M9dG z0+gIvIK5wh7b=tAdza?@P7^BuUJC!=&1RI>iR2N%?z6|2!{PLm~tBQwI9amSKU* zM?YR)H33I?PM)HSp>??yI)kyHW5<7ib!Qu@H3p~iVzO=c(gRjJcyq7#0;%_5t$KWm z@~KHIiI9glR%aC0Whk(68@Ls&-g5pBQU#jOituV`ZN0VV!%^9QzLfnu%0KlQ;+I?9 z^GjuwUAA07r9i3CK}X2Vp4qcy*DxWsyo(DBBvDN>-~JV}0UKOrpE?TQj-C~n5-d`& zrbqk*?ztcv%&W_FZfpNu6Hq?3&HHbmJ9bc#lWk-3nK%Cuhe7^LzdcLMBuxw8SI6-U zyo}*R=|5}T^)j#zpMHg9LxoxN9<6b91_XPgr+FX56E0Liau;@()og=XNq>RJ{<>J& zI<4d|fCy{e7XEb*A(Dvm+$FtO`NuL9A(o`H0^Q-02q=2~sjflZ)a32RjR90tTY7=9 zzJ{o6SCo5p6)1{%x*$WTCi+7rD9rvoA7_oS1!$OAI$5ym1Z}x;A8t4O3TmXTap0izhU+ z`cB*42|XU5JqB9?K?$-qMBiR@sRBVqB;~q)4ibQ~UECrXhrfEQ(~@8=M$C!3wn}J>AW}X zLuO>vi|ye8CLktds!ZA&fp^7|WLQpekj_5>Ee^ru& z1-8H7v@BMfM)#HMl$4g@XCUHqrbplR*FMwE1~wUudj*k8$FB^@I8RvPiset;MYF6? z%Q^R<<~l61A~8|q%FS1Al%pkd-I4{ij#7xte*yaL{8>gt5UBO{{ST~`Z=P{nf9-l0 z--Iw`?(ePa;^?t2IIgtX(aZ@?i~ciK2i7=&ly7$=<$52$8(rkucZ1LGYWB~5Iu~ZJ z@}g#b?i^C|LCCMy<%LuCL+BK@{{@T|bLsD~KjQ|jg#sG8e}f7j#C-OC{{W0-MXI|) zZ~27?Xq5E2K7l-C7pDqUQ{MMGd%}=H2wqM2pVnxt1Yc2VzFU`(9PFS{dVoB>u@(kX zrFXxBe}gD#0v($f`j}yKAhb?SKYtjlLJbpollsYwNCEE7KfJ7pi$Qyn=NUkwOljNk zG-TmOC_)pSJRiMviiF8P915Pss_3~Ff`%xE2bCzjZyl0~m=|Cm+Vq-0>l>gX2wqxh zw{L22I1G^$7o*OORkemaMXm%}W75aaH@6c7XsM;f-F)-TB#}V51lmm#hpl6z38EAP zU29$*UyMQk?A)|Kd51uFruwN9XO}8b=#~=Q-B9?Z#SQVuJc?Nqj>8vqnLusOV5 zzA@y$NOnE({^PS&SXJoGr_Ll;ybEkcD!viItE!+^=dYgdh5**4ljY_-U;)wK2-efa z$%%t6C19Wf!+Pn~JQ4&XK!i6s^KJ-Zc_A7gmD!{vIK&W25RgSq7oVft!m(l)>=i`~ zuRfbX>>Az!v_Eg7jC%nqWONf^w_RWm2e7I+$W?pI&NkXIWCWG0L_g2>27sWEd0p@4 z{{S&a4Buj!4}$*O5Fer(K10?(0>z}~U-$0{5&=*+4ujSLcx?RT0puy`Ia-LXGGOwD zUyM{7*1qvjG!Fdl{{S(fTPyuIhi&pcOse#MBdnlKoqL);c%aeg0z*N2FU5T0$Iz;; zMdN;Xn#8JBihL8p$Ho`9FbohbeZ1a7%HLxTWD^Ul8 zg|O(@Wu_p#3OV&WS*=|p0u@J4=36}aIUqz!LL}(qHeR~(i3Bv*2uDEUjd=0p;Sopx zhXLxEIHPa{?!`hGr97qj-&v=*QDUfvxO1*Cm6v45pi6fJo_Cw$V02=TI!4bI#wsJR zB_X2hfcLUuup?T;B_B6n_QIg2flBZ%pDsT*r}tvA$-&e4CKVGD6#xNM)aR6U#$P~? zfU?bS&7U~wRbFrpB;t4Tjn@{zdGm|UOt_$;`?%~DUkmrIoOr_O0(h@q^O4E~RDqy6 zJpQtEEu(JDEOn>)#EYd+W4*dDU9Q<6eqC<=0QU$&szW*GC;Q|v7SJscbT#_G5KT=+ zy`uQ@kU_y!MD2tNFf<{fzMqbI#&HOQl2YrgCw{QFf)u+NkUyMS?+hj0v=T($c!0!4 zzy}+5R!(v|1wh=|;kQCFg9NC^kl#rGDbBG#xbzW}jz5xFtQ{Mu6gmV@Cve(?@(<2FM#7u9odQ8;ROe;>{`*rHcgynt#5AF;}gQ3v&b0?-#2M=UXlbQ<-G zs20hH2=~SS7W9wvi1HG{_{R3Im(AWJUi3J0vgySF#h1el{bq_10kp*5rmxW;N}2;2&1#h0YE>(B6d8=bm?p2JAG#0vq9%8;fYA0)(*F0r)c2Ysw0rZ_Yfs9mZp7r^@2n zMVRnlSRvjNDp(D^F*Szvht1;-Dy0R}_Hm1(I%&BSv>jd^b&f3p0fsRcoX)lh$~gdv z14iok2i~wTTM*RamWB6*3E3^#thgANZ&KT=Pxaot#t5B zE(H}GDD&3r@4OFe(013!&$AjpouADMzZ=0&cu4#{GVt1C2>F_~))H!{*c`+*U@C-y z2^=??dDgP4R_bEJwG}Q_DCyX5eWnpv^&w4j+53(sER@o=FHc}%M+C;S)4u8C|Ix!F33cPaG z_v1J4oqjiG7JIme( zw4es86G3}*jCW#Z*UA3?oG=S2i4Q~#{NvNlOAGGxkEy7kFEqY5_l%6V82LN+$Hyu} zS9Ch~xL`$v7*B4T2<>cZCmJRC#TyYuh55*C8YDLx!t;P0wSRb=04P%XVFg@tG)cYW z8Gxpqd~<=mfI2vI^7zKcKt_%z&~!9-#7UF@SCHm=z<>&275*}qksDYKt$6R=9RR3| z5IW)dnADb4FrA_N<3}n0A@_;+CEy0tRUS_nPL)ss`O(4?UyLl`3xMzI9KUj;UyHmr z8Cz(5ANg^wFvn;6Fe^%KH1TX7e+FC!i>LF$N0{~+%>~eoQ(tcNlw^jo0NOh%*0nP6 zWqS7Lc`Qf1w}=e+!9vr$yJn}Ei@iH?0C{L$xbGcJr)f5cv1bTr=HY!&0+6!Kcct!= zjE4|(sXIFs3UN#s0HlvZX?;=-URnVKP666*jf&zMNZSzDo!trM4IEnR3~PE8qC8?cZ_k_}u9GYrrs0%`aHsv_c?48wc@pdX?{{O2A7 z8j332x9>rq-a4oO5>`qXY=Q=^_xa-rDPCZ+2u4(q-NS%aVT0hp0VwLjd44I+BVXnd zNz#EDU7z;&z@lIRm6SR}(snbfm7uni(LD^VWgIzLU2VErSAg@QoLH?SMR+O&oA3@- zLKrA`NyzMZ#YL(HU_c$B9Kz)uRM{TiTK@nuc)$`CoB^>rGL5AOsiz_F-&oNA-u|8= zr1CQgR1_Np?`8%Lnm1#>;+t+n$J>zy0*;Rm%}3bX4xXNuoFoVsO2&9|LLuU{`|INY zM6J@V#p|qrRo2{nt^8s{qFU4XGjs!Ng+1|v#$ZEHVMlo765W;gXNM9s8>92*1w+VD ze)6i~*Gmqp<%Giqx7 z@gOP=$Al^?#58l>Os#4b7oE-V&N?*$4QW~U>nysZC8v$?h{6FKGDmI+aG3#PzWC#; z7pOoW9yxzlwZa$NDVre(kkfG{#+{oO96jbN{upTiby|a&w9bb zTeEV&Vqd(X+K#RqAOq_h#s@p+4*+xqg(vS?n!uPCQ%1I*l{vvf1QhXT?~*Fdf?{eJ zB9c;pu{-|&?iSBVW8MHMuy&jATTTY4Vt}c2bUipb)J>37*nmlIc3i!YD_tQW$qHyo zg3wklVgU#RAg4}B7<9zZY(45*@s*0%G}=Wci5(p86ZA;UBoe8x)G!Lfu+_GtYt95r z2ViE8HeeuWRM(?__ZXNk8==S6AT=Q%dVW24$+8b^P5CBT&kzwh8-FvL0tq6u@;+Z5 z)+$U_VI3Obm(FP!NLqu$b(ek~Yp8m-APu#;8|1_Y$P#Ju z^MJLtMFXS-iL0so;G?2J4QL^!P`tdji7}~A@=WC!tBsvhDlrg*7Al1ihBsIdv1KW6 z${i;C<8Cyh+^1#sS=Irt2G#_eN#=cIw7`h0DS6@Fa}q5O3*nK5h_YgXZ50!VMAJJj z&Mz!-+Q z%RsinsplYS8@L0|X!-nR=z#{g3m*EyE8HEPP4s4 z{xOPlg1>c(^*7EgED*~#NL1O!95+w3L!8M~7fJ=?z*~Z}O(2V*6^92nEW{NihT26X zI~%Mr?$*Vofm*yhLsJzGU?5J>pa;Tb?ACy$%@CGpvshly1X8+dPP;MR;RFPV9z8p* z^1p^yUsWR5yr%eZdWMqiSwU)whbh5~T|yTTDYIfmm`FSnYkN^BO^JK&9AYK{@*??@ z4NOQBo;63Fa70Ln+~-+XEom~zqpW~G5rx;z{{V~$3kc|bAB-hZFA9Es@Tj5R<#=Iu_<34aul$hEbs{I0C`*{{YNrgeWGQRxcFL(D?I;41URg&?0CFtWhOkuMBTe z;&lDsIF%N++}!xafQz&TaAJIZ@D*Lea(;6`+^JL6!u*=|hHMD4K=tngSh#RO>k=DC zplP|;wCh;Zs302$IF*&irjBa5`A=AB4p3~K2Rh%@4BkS4RmoRE)rWWma<7dwTVvL- zjz+>keo>^Grc;~{1czNH-JSwm0>B|^aAYMeV=VIX@sp|ynleL%;sAnLWKiEcCM9Wx zmj<)3Sf3LX@hG4w#@%_=^1O`T2X3B2-ta*NAUk`VGlL~644ba_&6z-3;e6rc6f^_D z%{r?~UoQSSz2-&TbhDLY51| z>R&iFdsGN|`p1HoRgwPQavA`NwkFcp6}!TxMU;RMT}6hrI^zkXPypJg#}i-90)(LQ zA8*$}bAZYzy%dsZFv6*jMAO8ZC%iy`UBLwO zc;_}vK!h88@w`w%$*IHH#uCV5!l^H2iNcraAd?=8CtH-9{0 zggjVHKR5sonmB8$7@;K~H@)JNXe3p*jzw64lLgWMK>d7SZO;Q|pzo{;v>-%y{W!-< z+w0x{f&<4VoT^dLCR#%T;7^0RfK&k#F((8$z2_x+N!9?=i#%YWtx=+XxQLi^2q)iI zs|t0Y?Sd0RcW*s=##V zH|>rH+zB3y^kNjO+67bFfQld*XqEr%AJoeB*!!3f>lT zyc@zrtUF37t8JJwB3fQmmp3|5u0NdO82{{Y0q zk5N{QbzS&|33;I#>+1wmj-eOKaI|SfMIB~~7VJpb)8jsQBA=YJ6LM+sM<6I=QdpLoEqSF<1|Y9qH75H#Jmd%>}J17qmy!~pT^`p0CdI-~J~Sc|cw z@q|Q`B6!L!$n7SxRtdnM{pX?=B=d(@Q`>Ln4FYf?Pi82KL0b8yJ34hktH6izoGx^A zr{4O-P_Ut~GWRQj&Mfyp#fM#KKu8M8RzmLxO=uv41Q|fLhE3s=s9=x+0a&_U-bQ6W z_7Vw5iE^iouI&I~mxF3}%8f#3NtGaKg&$nvW!jZ?iU!TFFF9er)Cfdbv_WfZ!I4Z@ zB_YC!lZ6g6ZpmmoDAwP{#t4vwFjsT54X-W)5+Sn%+B+uO&bqkNkx&ZHhJPj_6x(Ro zcOND)H8OMqc<^7|amG}tI~rL#z~!qNJO2R81$9_9`dlUmf^PgAO>BxH{jkndO$9o* z;w~$Y;_W?a5d~GIlK`+n2{{0yP;B{p;^k_OLe&DH)l`@xQZfZ~4YQ}`CDVXtIv+Sx zOIkWDI!llj0kxZ;e-iOANq9sLAQgPo!h<4c6zEzE*ZjHS3qC?l51c7sZm2xa!f*@C zL$`Vx(bg#znrMD;Xj>}n`ZCdY>RcgmUbOV(*=|fHIG8C5J``c9UgFCfOZPZTpEW#6!_~JE_AV zPnE%o(x#MZS`D~g7`4b@KGF12*Rf~6vW dD!r!jL|k;)+RD&?7RM8+?_izR8h3A5|JjPH6sQ0I literal 0 HcmV?d00001 diff --git a/tests/fixtures/preprocessor_config.json b/tests/fixtures/preprocessor_config.json new file mode 100644 index 0000000000..cf0c5dce6c --- /dev/null +++ b/tests/fixtures/preprocessor_config.json @@ -0,0 +1,3 @@ +{ + "feature_extractor_type": "Wav2Vec2FeatureExtractor" +} \ No newline at end of file diff --git a/tests/test_feature_extraction_auto.py b/tests/test_feature_extraction_auto.py index 71ee32c230..7502e84224 100644 --- a/tests/test_feature_extraction_auto.py +++ b/tests/test_feature_extraction_auto.py @@ -16,9 +16,10 @@ import os import unittest -from transformers import FEATURE_EXTRACTOR_MAPPING, AutoFeatureExtractor, Wav2Vec2FeatureExtractor +from transformers import AutoFeatureExtractor, Wav2Vec2FeatureExtractor +SAMPLE_FEATURE_EXTRACTION_CONFIG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures") SAMPLE_FEATURE_EXTRACTION_CONFIG = os.path.join( os.path.dirname(os.path.abspath(__file__)), "fixtures/dummy_feature_extractor_config.json" ) @@ -29,16 +30,10 @@ class AutoFeatureExtractorTest(unittest.TestCase): config = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base-960h") self.assertIsInstance(config, Wav2Vec2FeatureExtractor) + def test_feature_extractor_from_local_directory(self): + config = AutoFeatureExtractor.from_pretrained(SAMPLE_FEATURE_EXTRACTION_CONFIG_DIR) + self.assertIsInstance(config, Wav2Vec2FeatureExtractor) + def test_feature_extractor_from_local_file(self): config = AutoFeatureExtractor.from_pretrained(SAMPLE_FEATURE_EXTRACTION_CONFIG) self.assertIsInstance(config, Wav2Vec2FeatureExtractor) - - def test_pattern_matching_fallback(self): - """ - In cases where config.json doesn't include a model_type, - perform a few safety checks on the config mapping's order. - """ - # no key string should be included in a later key string (typical failure case) - keys = list(FEATURE_EXTRACTOR_MAPPING.keys()) - for i, key in enumerate(keys): - self.assertFalse(any(key in later_key for later_key in keys[i + 1 :])) diff --git a/tests/test_pipelines_image_classification.py b/tests/test_pipelines_image_classification.py new file mode 100644 index 0000000000..32b1317461 --- /dev/null +++ b/tests/test_pipelines_image_classification.py @@ -0,0 +1,115 @@ +# Copyright 2021 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +from transformers import ( + AutoFeatureExtractor, + AutoModelForImageClassification, + PreTrainedTokenizer, + is_vision_available, +) +from transformers.pipelines import ImageClassificationPipeline, pipeline +from transformers.testing_utils import require_torch, require_vision + + +if is_vision_available(): + from PIL import Image +else: + + class Image: + @staticmethod + def open(*args, **kwargs): + pass + + +@require_vision +@require_torch +class ImageClassificationPipelineTests(unittest.TestCase): + pipeline_task = "image-classification" + small_models = ["lysandre/tiny-vit-random"] # Models tested without the @slow decorator + valid_inputs = [ + {"images": "http://images.cocodataset.org/val2017/000000039769.jpg"}, + { + "images": [ + "http://images.cocodataset.org/val2017/000000039769.jpg", + "http://images.cocodataset.org/val2017/000000039769.jpg", + ] + }, + {"images": "tests/fixtures/coco.jpg"}, + {"images": ["tests/fixtures/coco.jpg", "tests/fixtures/coco.jpg"]}, + {"images": Image.open("tests/fixtures/coco.jpg")}, + {"images": [Image.open("tests/fixtures/coco.jpg"), Image.open("tests/fixtures/coco.jpg")]}, + {"images": [Image.open("tests/fixtures/coco.jpg"), "tests/fixtures/coco.jpg"]}, + ] + + def test_small_model_from_factory(self): + for small_model in self.small_models: + + image_classifier = pipeline("image-classification", model=small_model) + + for valid_input in self.valid_inputs: + output = image_classifier(**valid_input) + top_k = valid_input.get("top_k", 5) + + def assert_valid_pipeline_output(pipeline_output): + self.assertTrue(isinstance(pipeline_output, list)) + self.assertEqual(len(pipeline_output), top_k) + for label_result in pipeline_output: + self.assertTrue(isinstance(label_result, dict)) + self.assertIn("label", label_result) + self.assertIn("score", label_result) + + if isinstance(valid_input["images"], list): + self.assertEqual(len(valid_input["images"]), len(output)) + for individual_output in output: + assert_valid_pipeline_output(individual_output) + else: + assert_valid_pipeline_output(output) + + def test_small_model_from_pipeline(self): + for small_model in self.small_models: + + model = AutoModelForImageClassification.from_pretrained(small_model) + feature_extractor = AutoFeatureExtractor.from_pretrained(small_model) + image_classifier = ImageClassificationPipeline(model=model, feature_extractor=feature_extractor) + + for valid_input in self.valid_inputs: + output = image_classifier(**valid_input) + top_k = valid_input.get("top_k", 5) + + def assert_valid_pipeline_output(pipeline_output): + self.assertTrue(isinstance(pipeline_output, list)) + self.assertEqual(len(pipeline_output), top_k) + for label_result in pipeline_output: + self.assertTrue(isinstance(label_result, dict)) + self.assertIn("label", label_result) + self.assertIn("score", label_result) + + if isinstance(valid_input["images"], list): + # When images are batched, pipeline output is a list of lists of dictionaries + self.assertEqual(len(valid_input["images"]), len(output)) + for individual_output in output: + assert_valid_pipeline_output(individual_output) + else: + # When images are batched, pipeline output is a list of dictionaries + assert_valid_pipeline_output(output) + + def test_custom_tokenizer(self): + tokenizer = PreTrainedTokenizer() + + # Assert that the pipeline can be initialized with a feature extractor that is not in any mapping + image_classifier = pipeline("image-classification", model=self.small_models[0], tokenizer=tokenizer) + + self.assertIs(image_classifier.tokenizer, tokenizer)