diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..d3f2e7e969ff7f05a8f2b7e840ba56cf6078a9e3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.txt filter=lfs diff=lfs merge=lfs -text +*.gif filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6001e403779d845b4ffbf7b40030fe73dddd0116 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea + +.pth \ No newline at end of file diff --git a/README.md b/README.md index d69abd77ea7f147f1e074bf9d70354486e123baa..09987e4997af467217294891e791f16e8ebb7962 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,47 @@ ---- -title: Counterfactual World Models -emoji: 📊 -colorFrom: purple -colorTo: yellow -sdk: gradio -sdk_version: 4.44.0 -app_file: app.py -pinned: false -license: mit -short_description: Vision foundation model that unifies vision structures ---- - -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +
+

Understanding Physical Dynamics with Counterfactual World Modeling

+ +[**Rahul Venkatesh***](https://rahulvenkk.github.io/)1 · [**Honglin Chen***](https://web.stanford.edu/~honglinc/)1* · [**Kevin Feigelis***](https://neuroscience.stanford.edu/people/kevin-t-feigelis)1 · [**Daniel M. Bear**](https://twitter.com/recursus?lang=en)1 · [**Khaled Jedoui**](https://web.stanford.edu/~thekej/)1 · [**Klemen Kotar**](https://klemenkotar.github.io/)1 · [**Felix Binder**](https://ac.felixbinder.net/)2 · [**Wanhee Lee**](https://www.linkedin.com/in/wanhee-lee-31102820b/)1 · [**Sherry Liu**](https://neuroailab.github.io/cwm-physics/)1 · [**Kevin A. Smith**](https://www.mit.edu/~k2smith/)3 · [**Judith E. Fan**](https://cogtoolslab.github.io/)1 · [**Daniel L. K. Yamins**](https://stanford.edu/~yamins/)1 + +(* equal contribution) + +1Stanford    2UCSD    3MIT + + + + +Paper PDF +Project Page + + +
+ +This work presents the Counterfactual World Modeling (CWM) framework. CWM is capable of counterfactual prediction and extraction of vision structures useful for understanding physical dynamics. + +![](assets/cwm_teaser.gif) + +## 📣 News + +- 2024-06-01: Release [project page](https://neuroailab.github.io) and [codes](https://github.com/rahulvenkk/cwm_release.git) + +## 🔨 Installation + +``` +git clone https://github.com/rahulvenkk/cwm_release.git +pip install -e . +``` + +## ✨ Usage +To download and use a pre-trianed model run the following +``` +from cwm.model.model_factory import model_factory +model = model_factory.load_model('vitbase_8x8patch_3frames_1tube') +``` +This will automatically initialize the appropriate model class and download the specified weights to your `$CACHE` directory. + +## 🔄 Pre-training +To train the model run the following script + +``` +./scripts/pretrain/3frame_patch8x8_mr0.90_gpu.sh +``` diff --git a/assets/color_wheel.png b/assets/color_wheel.png new file mode 100644 index 0000000000000000000000000000000000000000..84cdae7bb397f27457ea8b65457847e79c1f716e Binary files /dev/null and b/assets/color_wheel.png differ diff --git a/assets/cwm_teaser.gif b/assets/cwm_teaser.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff0a7ff2592aebf693544f447058a3ff96e17c86 --- /dev/null +++ b/assets/cwm_teaser.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4fac6e545660c695f81f360a87f1060c44eea95f3ae7dbcf1fecbe2b097e3b6a +size 12896275 diff --git a/assets/desk_1.jpg b/assets/desk_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7e1c5fdea5cd0dcc0125e9125b3d4afe0defb51 --- /dev/null +++ b/assets/desk_1.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84a3bfdd40841e8d291b4eb638ecc29b99f054ae6d3ea51b4cdc3090741987c8 +size 4731808 diff --git a/assets/flow_test_videos/libby.mp4 b/assets/flow_test_videos/libby.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..d5086b20a9a14f6c3f14e7df3eec2a947ea7688b --- /dev/null +++ b/assets/flow_test_videos/libby.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d1887bc796d1883e8a63405398125476257572c0c8d7f1862bf309e422b4828 +size 671950 diff --git a/assets/flow_test_videos/weight_lifter.mp4 b/assets/flow_test_videos/weight_lifter.mp4 new file mode 100755 index 0000000000000000000000000000000000000000..12a2d354ee2e002c858d346e2731ad6c9168c02f --- /dev/null +++ b/assets/flow_test_videos/weight_lifter.mp4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:525988b314936079f904236c614e2f987ba64fd5c69f4f12dd5b6b9076311854 +size 1176790 diff --git a/cwm/__init__.py b/cwm/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/data/__init__.py b/cwm/data/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/data/dataset.py b/cwm/data/dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..0b4d0aafd109ce17f8a220f67fce80994f1145f8 --- /dev/null +++ b/cwm/data/dataset.py @@ -0,0 +1,453 @@ +import os +import decord +import numpy as np +import torch +from PIL import Image +from torch.utils.data import Dataset +from torchvision import transforms + + +class VideoMAE(torch.utils.data.Dataset): + """Load your own video classification dataset. + Parameters + ---------- + root : str, required. + Path to the root folder storing the dataset. + setting : str, required. + A text file describing the dataset, each line per video sample. + There are three items in each line: (1) video path; (2) video length and (3) video label. + train : bool, default True. + Whether to load the training or validation set. + test_mode : bool, default False. + Whether to perform evaluation on the test set. + Usually there is three-crop or ten-crop evaluation strategy involved. + name_pattern : str, default None. + The naming pattern of the decoded video frames. + For example, img_00012.jpg. + video_ext : str, default 'mp4'. + If video_loader is set to True, please specify the video format accordinly. + is_color : bool, default True. + Whether the loaded image is color or grayscale. + modality : str, default 'rgb'. + Input modalities, we support only rgb video frames for now. + Will add support for rgb difference image and optical flow image later. + num_segments : int, default 1. + Number of segments to evenly divide the video into clips. + A useful technique to obtain global video-level information. + Limin Wang, etal, Temporal Segment Networks: Towards Good Practices for Deep Action Recognition, ECCV 2016. + num_crop : int, default 1. + Number of crops for each image. default is 1. + Common choices are three crops and ten crops during evaluation. + new_length : int, default 1. + The length of input video clip. Default is a single image, but it can be multiple video frames. + For example, new_length=16 means we will extract a video clip of consecutive 16 frames. + new_step : int, default 1. + Temporal sampling rate. For example, new_step=1 means we will extract a video clip of consecutive frames. + new_step=2 means we will extract a video clip of every other frame. + temporal_jitter : bool, default False. + Whether to temporally jitter if new_step > 1. + video_loader : bool, default False. + Whether to use video loader to load data. + use_decord : bool, default True. + Whether to use Decord video loader to load data. Otherwise use mmcv video loader. + transform : function, default None. + A function that takes data and label and transforms them. + data_aug : str, default 'v1'. + Different types of data augmentation auto. Supports v1, v2, v3 and v4. + lazy_init : bool, default False. + If set to True, build a dataset instance without loading any dataset. + """ + + def __init__(self, + root, + setting, + train=True, + test_mode=False, + name_pattern='img_%05d.jpg', + video_ext='mp4', + is_color=True, + modality='rgb', + num_segments=1, + num_crop=1, + new_length=1, + new_step=1, + randomize_interframes=False, + transform=None, + temporal_jitter=False, + video_loader=False, + use_decord=False, + lazy_init=False, + is_video_dataset=True): + + super(VideoMAE, self).__init__() + self.root = root + self.setting = setting + self.train = train + self.test_mode = test_mode + self.is_color = is_color + self.modality = modality + self.num_segments = num_segments + self.num_crop = num_crop + self.new_length = new_length + + self.randomize_interframes = randomize_interframes + self._new_step = new_step # If randomize_interframes is True, then this is the max, otherwise it's just the skip + # self._skip_length = self.new_length * self.new_step # If randomize_interframes is True, then this isn't used, otherwise it's used as calculated + self.temporal_jitter = temporal_jitter + self.name_pattern = name_pattern + self.video_loader = video_loader + self.video_ext = video_ext + self.use_decord = use_decord + self.transform = transform + self.lazy_init = lazy_init + + if (not self.lazy_init) and is_video_dataset: + self.clips = self._make_dataset(root, setting) + if len(self.clips) == 0: + raise (RuntimeError("Found 0 video clips in subfolders of: " + root + "\n" + "Check your data directory (opt.data-dir).")) + + def __getitem__(self, index): + + directory, target = self.clips[index] + + if self.video_loader: + if '.' in directory.split('/')[-1]: + # data in the "setting" file already have extension, e.g., demo.mp4 + video_name = directory + else: + # data in the "setting" file do not have extension, e.g., demo + # So we need to provide extension (i.e., .mp4) to complete the file name. + video_name = '{}.{}'.format(directory, self.video_ext) + + try: + decord_vr = decord.VideoReader(video_name, num_threads=1) + except: + # return video_name + return (self.__getitem__(index + 1)) + duration = len(decord_vr) + + segment_indices, skip_offsets, new_step, skip_length = self._sample_train_indices(duration) + + images = self._video_TSN_decord_batch_loader(directory, decord_vr, duration, segment_indices, skip_offsets, + new_step, skip_length) + + process_data, mask = self.transform((images, None)) # T*C,H,W + process_data = process_data.view((self.new_length, 3) + process_data.size()[-2:]).transpose(0, + 1) # T*C,H,W -> T,C,H,W -> C,T,H,W + + return (process_data, mask) + + def __len__(self): + return len(self.clips) + + def _make_dataset(self, directory, setting): + if not os.path.exists(setting): + raise (RuntimeError("Setting file %s doesn't exist. Check opt.train-list and opt.val-list. " % (setting))) + clips = [] + with open(setting) as split_f: + data = split_f.readlines() + for line in data: + line_info = line.split(' ') + # line format: video_path, video_duration, video_label + if len(line_info) < 2: + raise (RuntimeError('Video input format is not correct, missing one or more element. %s' % line)) + elif len(line_info) > 2: + line_info = (' '.join(line_info[:-1]), line_info[-1]) # filename has spaces + clip_path = os.path.join(line_info[0]) + target = int(line_info[1]) + item = (clip_path, target) + clips.append(item) + # import torch_xla.core.xla_model as xm + # print = xm.master_print + # print("Dataset created. Number of clips: ", len(clips)) + return clips + + def _sample_train_indices(self, num_frames): + if self.randomize_interframes is False: + new_step = self._new_step + else: + new_step = np.random.randint(1, self._new_step + 1) + + skip_length = self.new_length * new_step + + average_duration = (num_frames - skip_length + 1) // self.num_segments + if average_duration > 0: + offsets = np.multiply(list(range(self.num_segments)), + average_duration) + offsets = offsets + np.random.randint(average_duration, + size=self.num_segments) + elif num_frames > max(self.num_segments, skip_length): + offsets = np.sort(np.random.randint( + num_frames - skip_length + 1, + size=self.num_segments)) + else: + offsets = np.zeros((self.num_segments,)) + + if self.temporal_jitter: + skip_offsets = np.random.randint( + new_step, size=skip_length // new_step) + else: + skip_offsets = np.zeros( + skip_length // new_step, dtype=int) + return offsets + 1, skip_offsets, new_step, skip_length + + def _video_TSN_decord_batch_loader(self, directory, video_reader, duration, indices, skip_offsets, new_step, + skip_length): + sampled_list = [] + frame_id_list = [] + for seg_ind in indices: + offset = int(seg_ind) + for i, _ in enumerate(range(0, skip_length, new_step)): + if offset + skip_offsets[i] <= duration: + frame_id = offset + skip_offsets[i] - 1 + else: + frame_id = offset - 1 + frame_id_list.append(frame_id) + if offset + new_step < duration: + offset += new_step + try: + video_data = video_reader.get_batch(frame_id_list).asnumpy() + sampled_list = [Image.fromarray(video_data[vid, :, :, :]).convert('RGB') for vid, _ in + enumerate(frame_id_list)] + except: + raise RuntimeError( + 'Error occured in reading frames {} from video {} of duration {}.'.format(frame_id_list, directory, + duration)) + return sampled_list + + +class ContextAndTargetVideoDataset(VideoMAE): + """ + A video dataset whose provided videos consist of (1) a "context" sequence of length Tc + and (2) a "target" sequence Tt. + + These two sequences have the same frame rate (specificiable in real units) but are + separated by a specified gap (which may vary for different examples.) + + The main use case is for training models to predict ahead by some variable amount, + given the context. + """ + + standard_fps = [12, 24, 30, 48, 60, 100] + + def __init__(self, + root, + setting, + train=True, + test_mode=False, + transform=None, + step_units='ms', + new_step=150, + start_frame=0, + context_length=2, + target_length=1, + channels_first=True, + generate_masks=True, + mask_generator=None, + context_target_gap=[400, 600], + normalize_timestamps=True, + default_fps=30, + min_fps=0.1, + seed=0, + *args, + **kwargs): + super(ContextAndTargetVideoDataset, self).__init__( + root=root, + setting=setting, + train=train, + test_mode=test_mode, + transform=transform, + new_length=context_length, + use_decord=True, + lazy_init=False, + video_loader=True, + *args, **kwargs) + + # breakpoint() + + self.context_length = self.new_length + self.target_length = target_length + + ## convert from fps and step size to frames + self._fps = None + self._min_fps = min_fps + self._default_fps = default_fps + self._step_units = step_units + self.new_step = new_step + + ## sampling for train and test + self._start_frame = start_frame + self.gap = context_target_gap + self.seed = seed + self.rng = np.random.RandomState(seed=seed) + + # breakpoint() + + ## output formatting + self._channels_first = channels_first + self._normalize_timestamps = normalize_timestamps + self._generate_masks = generate_masks + self.mask_generator = mask_generator + + + def _get_frames_per_t(self, t): + if self._step_units == 'frames' or (self._step_units is None): + return int(t) + + assert self._fps is not None + t_per_frame = 1 / self._fps + if self._step_units in ['ms', 'milliseconds']: + t_per_frame *= 1000.0 + + return max(int(np.round(t / t_per_frame)), 1) + + @property + def new_step(self): + if self._fps is None: + return None + else: + return self._get_frames_per_t(self._new_step) + + @new_step.setter + def new_step(self, v): + self._new_step = v + + @property + def gap(self): + if self._fps is None: + return [1, 2] + else: + gap = [self._get_frames_per_t(self._gap[0]), + self._get_frames_per_t(self._gap[1])] + gap[1] = max(gap[1], gap[0] + 1) + return gap + + @gap.setter + def gap(self, v): + if v is None: + v = self._new_step + if not isinstance(v, (list, tuple)): + v = [v, v] + self._gap = v + + def _get_video_name(self, directory): + if ''.join(['.', self.video_ext]) in directory.split('/')[-1]: + # data in the "setting" file has extension, e.g. demo.mpr + video_name = directory + else: + # data doesn't have an extension + video_name = '{}.{}'.format(directory, self.video_ext) + return video_name + + def _set_fps(self, reader): + """click fps to a standard""" + if self._step_units == 'frames' or self._step_units is None: + self._fps = None + else: + self._fps = None + fps = reader.get_avg_fps() + for st in self.standard_fps: + if (int(np.floor(fps)) == st) or (int(np.ceil(fps)) == st): + self._fps = st + if self._fps is None: + self._fps = int(np.round(fps)) + + if self._fps < self._min_fps: + self._fps = self._default_fps + + def _get_step_and_gap(self): + step = self.new_step + if self.randomize_interframes and self.train: + step = self.rng.randint(1, step + 1) + + if self.train: + gap = self.rng.randint(*self.gap) + else: + gap = sum(self.gap) // 2 + return (step, gap) + + def _sample_frames(self): + step, gap = self._get_step_and_gap() + + ## compute total length of sample + ## e.g. if context_length = 2, step = 1, gap = 10, target_length = 2: + ## total_length = 2 * 1 + 10 + (2 - 1) * 1 = 13 + ## so len(video) must be >= 13 + self._total_length = self.context_length * step + gap + (self.target_length - 1) * step + if self._total_length > (self._num_frames - self._start_frame): + if self.train: + return None + else: + raise ValueError( + "movie of length %d starting at fr=%d is too long for video of %d frames" % \ + (self._total_length, self._start_frame, self._num_frames)) + + ## sample the frames randomly (if training) or from the start frame (if test) + if self.train: + self.start_frame_now = self.rng.randint( + min(self._start_frame, self._num_frames - self._total_length), + self._num_frames - self._total_length + 1) + else: + self.start_frame_now = min(self._start_frame, self._num_frames - self._total_length) + + frames = [self.start_frame_now + i * step for i in range(self.context_length)] + frames += [frames[-1] + gap + i * step for i in range(self.target_length)] + + # breakpoint() + + return frames + + def _decode_frame_images(self, reader, frames): + try: + video_data = reader.get_batch(frames).asnumpy() + video_data = [Image.fromarray(video_data[t, :, :, :]).convert('RGB') + for t, _ in enumerate(frames)] + except: + raise RuntimeError( + "Error occurred in reading frames {} from video {} of duration {}".format( + frames, self.index, self._num_frames)) + return video_data + + def __getitem__(self, index): + + self.index = index + self.directory, target = self.clips[index] + + self.video_name = self._get_video_name(self.directory) + + ## build decord loader + try: + decord_vr = decord.VideoReader(self.video_name, num_threads=1) + self._set_fps(decord_vr) + except: + # return self.video_name + return (self.__getitem__(index + 1)) + + ## sample the video + self._num_frames = len(decord_vr) + self.frames = self._sample_frames() + if self.frames is None: + print("no movie of length %d for video idx=%d" % (self._total_length, self.index)) + return self.__getitem__(index + 1) + + ## decode to PIL.Image + image_list = self._decode_frame_images(decord_vr, self.frames) + + ## postproc to torch.Tensor and mask generation + if self.transform is None: + image_tensor = torch.stack([transforms.ToTensor()(img) for img in image_list], 0) + else: + image_tensor = self.transform((image_list, None)) + + image_tensor = image_tensor.view(self.context_length + self.target_length, 3, *image_tensor.shape[-2:]) + + ## VMAE expects [B,C,T,H,W] rather than [B,T,C,H,W] + if self._channels_first: + image_tensor = image_tensor.transpose(0, 1) + + if self._generate_masks and self.mask_generator is not None: + mask = self.mask_generator() + return image_tensor, mask.bool() + else: + return image_tensor diff --git a/cwm/data/dataset_utils.py b/cwm/data/dataset_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..db9057b48eee5df1c91ed00f86405f1b1a619f30 --- /dev/null +++ b/cwm/data/dataset_utils.py @@ -0,0 +1,73 @@ +from torchvision import transforms +from cwm.data.transforms import * +from cwm.data.dataset import ContextAndTargetVideoDataset +from timm.data.constants import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD +from cwm.data.masking_generator import RotatedTableMaskingGenerator + +class DataAugmentationForVideoMAE(object): + def __init__(self, augmentation_type, input_size, augmentation_scales): + + transform_list = [] + + self.scale = GroupScale(input_size) + transform_list.append(self.scale) + + if augmentation_type == 'multiscale': + self.train_augmentation = GroupMultiScaleCrop(input_size, list(augmentation_scales)) + elif augmentation_type == 'center': + self.train_augmentation = GroupCenterCrop(input_size) + + transform_list.extend([self.train_augmentation, Stack(roll=False), ToTorchFormatTensor(div=True)]) + + # Normalize input images + normalize = GroupNormalize(IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD) + transform_list.append(normalize) + + self.transform = transforms.Compose(transform_list) + + def __call__(self, images): + process_data, _ = self.transform(images) + return process_data + + def __repr__(self): + repr = "(DataAugmentationForVideoMAE,\n" + repr += " transform = %s,\n" % str(self.transform) + repr += ")" + return repr + + +def build_pretraining_dataset(args): + + dataset_list = [] + data_transform = DataAugmentationForVideoMAE(args.augmentation_type, args.input_size, args.augmentation_scales) + + mask_generator = RotatedTableMaskingGenerator( + input_size=args.mask_input_size, + mask_ratio=args.mask_ratio, + tube_length=args.tubelet_size, + batch_size=args.batch_size, + mask_type=args.mask_type + ) + + for data_path in [args.data_path] if args.data_path_list is None else args.data_path_list: + dataset = ContextAndTargetVideoDataset( + root=None, + setting=data_path, + video_ext='mp4', + is_color=True, + modality='rgb', + context_length=args.context_frames, + target_length=args.target_frames, + step_units=args.temporal_units, + new_step=args.sampling_rate, + context_target_gap=args.context_target_gap, + transform=data_transform, + randomize_interframes=False, + channels_first=True, + temporal_jitter=False, + train=True, + mask_generator=mask_generator, + ) + dataset_list.append(dataset) + dataset = torch.utils.data.ConcatDataset(dataset_list) + return dataset diff --git a/cwm/data/masking_generator.py b/cwm/data/masking_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..19fdf4b2444966a0b9517024f1bcf6cb18d3f125 --- /dev/null +++ b/cwm/data/masking_generator.py @@ -0,0 +1,86 @@ +import numpy as np +import torch + +def get_tubes(masks_per_frame, tube_length): + rp = torch.randperm(len(masks_per_frame)) + masks_per_frame = masks_per_frame[rp] + + tubes = [masks_per_frame] + for x in range(tube_length - 1): + masks_per_frame = masks_per_frame.clone() + rp = torch.randperm(len(masks_per_frame)) + masks_per_frame = masks_per_frame[rp] + tubes.append(masks_per_frame) + + tubes = torch.vstack(tubes) + + return tubes + +class RotatedTableMaskingGenerator: + def __init__(self, + input_size, + mask_ratio, + tube_length, + batch_size, + mask_type='rotated_table', + seed=None, + randomize_num_visible=False): + + self.batch_size = batch_size + + self.mask_ratio = mask_ratio + self.tube_length = tube_length + + self.frames, self.height, self.width = input_size + self.num_patches_per_frame = self.height * self.width + self.total_patches = self.frames * self.num_patches_per_frame + + self.seed = seed + self.randomize_num_visible = randomize_num_visible + + self.mask_type = mask_type + + def __repr__(self): + repr_str = "Inverted Table Mask: total patches {}, tube length {}, randomize num visible? {}, seed {}".format( + self.total_patches, self.tube_length, self.randomize_num_visible, self.seed + ) + return repr_str + + def __call__(self, m=None): + + if self.mask_type == 'rotated_table_magvit': + self.mask_ratio = np.random.uniform(low=0.0, high=1) + self.mask_ratio = np.cos(self.mask_ratio * np.pi / 2) + elif self.mask_type == 'rotated_table_maskvit': + self.mask_ratio = np.random.uniform(low=0.5, high=1) + + all_masks = [] + for b in range(self.batch_size): + + self.num_masks_per_frame = max(0, int(self.mask_ratio * self.num_patches_per_frame)) + self.total_masks = self.tube_length * self.num_masks_per_frame + + num_masks = self.num_masks_per_frame + + if self.randomize_num_visible: + assert "Randomize num visible Not implemented" + num_masks = self.rng.randint(low=num_masks, high=(self.num_patches_per_frame + 1)) + + if self.mask_ratio == 0: + mask_per_frame = torch.hstack([ + torch.zeros(self.num_patches_per_frame - num_masks), + ]) + else: + mask_per_frame = torch.hstack([ + torch.zeros(self.num_patches_per_frame - num_masks), + torch.ones(num_masks), + ]) + + tubes = get_tubes(mask_per_frame, self.tube_length) + top = torch.zeros(self.height * self.width).to(tubes.dtype) + + top = torch.tile(top, (self.frames - self.tube_length, 1)) + mask = torch.cat([top, tubes]) + mask = mask.flatten() + all_masks.append(mask) + return torch.stack(all_masks) diff --git a/cwm/data/transforms.py b/cwm/data/transforms.py new file mode 100644 index 0000000000000000000000000000000000000000..f16a7373a9e1d7abb1c91fd041827b380b5392ed --- /dev/null +++ b/cwm/data/transforms.py @@ -0,0 +1,206 @@ +import torch +import torchvision.transforms.functional as F +import warnings +import random +import numpy as np +import torchvision +from PIL import Image, ImageOps +import numbers + + +class GroupRandomCrop(object): + def __init__(self, size): + if isinstance(size, numbers.Number): + self.size = (int(size), int(size)) + else: + self.size = size + + def __call__(self, img_tuple): + img_group, label = img_tuple + + w, h = img_group[0].size + th, tw = self.size + + out_images = list() + + x1 = random.randint(0, w - tw) + y1 = random.randint(0, h - th) + + for img in img_group: + assert(img.size[0] == w and img.size[1] == h) + if w == tw and h == th: + out_images.append(img) + else: + out_images.append(img.crop((x1, y1, x1 + tw, y1 + th))) + + return (out_images, label) + + +class GroupCenterCrop(object): + def __init__(self, size): + self.worker = torchvision.transforms.CenterCrop(size) + + def __call__(self, img_tuple): + img_group, label = img_tuple + return ([self.worker(img) for img in img_group], label) + + +class GroupNormalize(object): + def __init__(self, mean, std): + self.mean = mean + self.std = std + + def __call__(self, tensor_tuple): + tensor, label = tensor_tuple + rep_mean = self.mean * (tensor.size()[0]//len(self.mean)) + rep_std = self.std * (tensor.size()[0]//len(self.std)) + + # TODO: make efficient + for t, m, s in zip(tensor, rep_mean, rep_std): + t.sub_(m).div_(s) + + return (tensor,label) + + +class GroupGrayScale(object): + def __init__(self, size): + self.worker = torchvision.transforms.Grayscale(size) + + def __call__(self, img_tuple): + img_group, label = img_tuple + return ([self.worker(img) for img in img_group], label) + + +class GroupScale(object): + """ Rescales the input PIL.Image to the given 'size'. + 'size' will be the size of the smaller edge. + For example, if height > width, then image will be + rescaled to (size * height / width, size) + size: size of the smaller edge + interpolation: Default: PIL.Image.BILINEAR + """ + + def __init__(self, size, interpolation=Image.BILINEAR): + self.worker = torchvision.transforms.Resize(size, interpolation) + + def __call__(self, img_tuple): + img_group, label = img_tuple + return ([self.worker(img) for img in img_group], label) + + +class GroupMultiScaleCrop(object): + + def __init__(self, input_size, scales=None, max_distort=1, fix_crop=True, more_fix_crop=True): + self.scales = scales if scales is not None else [1, 875, .75, .66] + self.max_distort = max_distort + self.fix_crop = fix_crop + self.more_fix_crop = more_fix_crop + self.input_size = input_size if not isinstance(input_size, int) else [input_size, input_size] + self.interpolation = Image.BILINEAR + + def __call__(self, img_tuple): + img_group, label = img_tuple + + im_size = img_group[0].size + + crop_w, crop_h, offset_w, offset_h = self._sample_crop_size(im_size) + crop_img_group = [img.crop((offset_w, offset_h, offset_w + crop_w, offset_h + crop_h)) for img in img_group] + ret_img_group = [img.resize((self.input_size[0], self.input_size[1]), self.interpolation) for img in crop_img_group] + return (ret_img_group, label) + + def _sample_crop_size(self, im_size): + image_w, image_h = im_size[0], im_size[1] + + # find a crop size + base_size = min(image_w, image_h) + crop_sizes = [int(base_size * x) for x in self.scales] + crop_h = [self.input_size[1] if abs(x - self.input_size[1]) < 3 else x for x in crop_sizes] + crop_w = [self.input_size[0] if abs(x - self.input_size[0]) < 3 else x for x in crop_sizes] + + pairs = [] + for i, h in enumerate(crop_h): + for j, w in enumerate(crop_w): + if abs(i - j) <= self.max_distort: + pairs.append((w, h)) + + crop_pair = random.choice(pairs) + if not self.fix_crop: + w_offset = random.randint(0, image_w - crop_pair[0]) + h_offset = random.randint(0, image_h - crop_pair[1]) + else: + w_offset, h_offset = self._sample_fix_offset(image_w, image_h, crop_pair[0], crop_pair[1]) + + return crop_pair[0], crop_pair[1], w_offset, h_offset + + def _sample_fix_offset(self, image_w, image_h, crop_w, crop_h): + offsets = self.fill_fix_offset(self.more_fix_crop, image_w, image_h, crop_w, crop_h) + return random.choice(offsets) + + @staticmethod + def fill_fix_offset(more_fix_crop, image_w, image_h, crop_w, crop_h): + w_step = (image_w - crop_w) // 4 + h_step = (image_h - crop_h) // 4 + + ret = list() + ret.append((0, 0)) # upper left + ret.append((4 * w_step, 0)) # upper right + ret.append((0, 4 * h_step)) # lower left + ret.append((4 * w_step, 4 * h_step)) # lower right + ret.append((2 * w_step, 2 * h_step)) # center + + if more_fix_crop: + ret.append((0, 2 * h_step)) # center left + ret.append((4 * w_step, 2 * h_step)) # center right + ret.append((2 * w_step, 4 * h_step)) # lower center + ret.append((2 * w_step, 0 * h_step)) # upper center + + ret.append((1 * w_step, 1 * h_step)) # upper left quarter + ret.append((3 * w_step, 1 * h_step)) # upper right quarter + ret.append((1 * w_step, 3 * h_step)) # lower left quarter + ret.append((3 * w_step, 3 * h_step)) # lower righ quarter + return ret + + +class Stack(object): + + def __init__(self, roll=False): + self.roll = roll + + def __call__(self, img_tuple): + img_group, label = img_tuple + + if img_group[0].mode == 'L': + return (np.concatenate([np.expand_dims(x, 2) for x in img_group], axis=2), label) + elif img_group[0].mode == 'RGB': + if self.roll: + return (np.concatenate([np.array(x)[:, :, ::-1] for x in img_group], axis=2), label) + else: + return (np.concatenate(img_group, axis=2), label) + + +class ToTorchFormatTensor(object): + """ Converts a PIL.Image (RGB) or numpy.ndarray (H x W x C) in the range [0, 255] + to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0] """ + def __init__(self, div=True): + self.div = div + + def __call__(self, pic_tuple): + pic, label = pic_tuple + + if isinstance(pic, np.ndarray): + # handle numpy array + img = torch.from_numpy(pic).permute(2, 0, 1).contiguous() + else: + # handle PIL Image + img = torch.ByteTensor(torch.ByteStorage.from_buffer(pic.tobytes())) + img = img.view(pic.size[1], pic.size[0], len(pic.mode)) + # put it from HWC to CHW format + # yikes, this transpose takes 80% of the loading time/CPU + img = img.transpose(0, 1).transpose(0, 2).contiguous() + return (img.float().div(255.) if self.div else img.float(), label) + + +class IdentityTransform(object): + + def __call__(self, data): + return data diff --git a/cwm/data/video_file_lists/kinetics_400_train_list.txt b/cwm/data/video_file_lists/kinetics_400_train_list.txt new file mode 100644 index 0000000000000000000000000000000000000000..35c95966b7313044367975e20aeb24c444e324e6 --- /dev/null +++ b/cwm/data/video_file_lists/kinetics_400_train_list.txt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65e14c0735b4c90c57022add2407a8524d246cc09b3d5a7e83b963ac3b231032 +size 19539143 diff --git a/cwm/data/video_file_lists/kinetics_400_train_list_sing.txt b/cwm/data/video_file_lists/kinetics_400_train_list_sing.txt new file mode 100644 index 0000000000000000000000000000000000000000..af8496578845cf64678d43290bec5fb4bf7f1b86 --- /dev/null +++ b/cwm/data/video_file_lists/kinetics_400_train_list_sing.txt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b18ccdce4616fb32a0aababc2342a640a11f7d73439f49358a16cc99e7eaed3 +size 1943 diff --git a/cwm/engine_for_pretraining.py b/cwm/engine_for_pretraining.py new file mode 100644 index 0000000000000000000000000000000000000000..854755c3eab5980335ff7d4abf4f8694b2e87400 --- /dev/null +++ b/cwm/engine_for_pretraining.py @@ -0,0 +1,92 @@ +import json +import os +import time +from typing import Iterable + +import torch +import torch.nn as nn +from timm.data.constants import (IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD) + +import utils + +from datetime import datetime + + +def train_one_epoch(model: torch.nn.Module, + data_loader: Iterable, + optimizer: torch.optim.Optimizer, + device: torch.device, + epoch: int, + loss_scaler, + start_steps=None, + lr_schedule_values=None, + wd_schedule_values=None, + global_rank=None, + args=None, + loss_func = nn.MSELoss(), + ): + + metric_logger = utils.MetricLogger(delimiter=" ") + + if args.eval: + model.eval() + else: + model.train() + metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value:.6f}')) + + header = f'Epoch [{epoch}]' + patch_size = model.module.encoder.patch_size[-2:] + tubelet_size = model.module.encoder.patch_size[0] + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, :, None, None, None] + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, :, None, None, None] + + for step, batch in enumerate(metric_logger.log_every(data_loader, args.print_freq, header)): + + # assign learning rate & weight decay for each iteration + it = start_steps + step # global training iteration + if (lr_schedule_values is not None or wd_schedule_values is not None) and (step % args.accum_iter == 0): + for i, param_group in enumerate(optimizer.param_groups): + if lr_schedule_values is not None: + param_group["lr"] = lr_schedule_values[it] * param_group["lr_scale"] + if wd_schedule_values is not None and param_group["weight_decay"] > 0: + param_group["weight_decay"] = wd_schedule_values[it] + + # prepare input + videos, bool_masked_pos = batch + videos = videos.to(device, non_blocking=True) + bool_masked_pos = bool_masked_pos.to(device, non_blocking=True).flatten(1) + + # prepare target + with torch.no_grad(): + unnorm_videos = videos * std + mean # in [0, 1] + videos_patch = utils.patchify(unnorm_videos, tubelet_size, patch_size) + B, _, C = videos_patch.shape + labels = videos_patch[bool_masked_pos].reshape(B, -1, C) + + # feedforward + with torch.cuda.amp.autocast(enabled=True): + outputs = model(videos, bool_masked_pos) + loss = loss_func(input=outputs, target=labels) + + loss_value = loss.item() + + # backward + is_second_order = hasattr(optimizer, 'is_second_order') and optimizer.is_second_order + loss /= args.accum_iter + loss_scaler(loss, optimizer, clip_grad=None, + parameters=model.parameters(), create_graph=is_second_order, + update_grad=(step + 1) % args.accum_iter == 0) + + torch.cuda.synchronize() + metric_logger.update(loss=loss_value) + + if (step + 1) % args.accum_iter == 0: + optimizer.zero_grad() + + lr = optimizer.param_groups[0]["lr"] + metric_logger.update(lr=lr) + + # gather the stats from all processes + metric_logger.synchronize_between_processes() + print("Averaged stats:", metric_logger) + return {k: meter.global_avg for k, meter in metric_logger.meters.items()} diff --git a/cwm/eval/Action_recognition/__init__.py b/cwm/eval/Action_recognition/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Flow/__init__.py b/cwm/eval/Flow/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Flow/create_spring_submission_parallel.sh b/cwm/eval/Flow/create_spring_submission_parallel.sh new file mode 100644 index 0000000000000000000000000000000000000000..91a1f8257f8af8acd01687fe019d745673c37884 --- /dev/null +++ b/cwm/eval/Flow/create_spring_submission_parallel.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Define the path to the dataset and the Python script +DATASET_PATH="/ccn2/dataset/Flows_Kinetics/SPRING/spring/test/" +SCRIPT_PATH="./create_spring_submission_unified.py" +SAVE_DATA_PATH=${1} +MODEL=${2} +# Counter for GPUs +GPU_COUNTER=0 + +# Number of GPUs available +NUM_GPUS=8 + +#kill session +tmux kill-session -t extraction + +tmux new-session -d -s "extraction" + +# Iterate through each folder in the dataset +for FOLDER in $(find $DATASET_PATH -mindepth 1 -maxdepth 1 -type d | sort); do + # Extract the folder name for the tmux session name + FOLDER_NAME=$(basename $FOLDER) + + # Create a new detached tmux session for each folder + tmux new-window -t extraction -n "$FOLDER" "ulimit -n 65535; CUDA_VISIBLE_DEVICES=$GPU_COUNTER python $SCRIPT_PATH --folder $FOLDER --gpu $GPU_COUNTER --save_data_path $SAVE_DATA_PATH --model $MODEL; echo 'Press Enter to continue...'; read -p ''" + # Increment the GPU counter and reset if it exceeds the number of GPUs + GPU_COUNTER=$((GPU_COUNTER + 1)) + if [ $GPU_COUNTER -ge $NUM_GPUS ]; then + GPU_COUNTER=0 + fi + + sleep 1 +done + +tmux attach-session -t extraction + diff --git a/cwm/eval/Flow/create_spring_submission_unified.py b/cwm/eval/Flow/create_spring_submission_unified.py new file mode 100644 index 0000000000000000000000000000000000000000..a6fb526cc175dd8d2f9a66f624ed2bd8ad46fec6 --- /dev/null +++ b/cwm/eval/Flow/create_spring_submission_unified.py @@ -0,0 +1,111 @@ + +import argparse + +# Parse command-line arguments +import importlib +import time + +parser = argparse.ArgumentParser(description='Process a folder with RAFT') +parser.add_argument('--folder', type=str, required=True, help='Folder to process') +parser.add_argument('--model', type=str, required=True, help='Model used to extract flow') +parser.add_argument('--save_data_path', type=str, required=True, help='where to save the data') +parser.add_argument('--gpu', type=int, default=0, help='GPU index to use') +args = parser.parse_args() +import os + +os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpu) +import torch +torch.cuda.set_device(0) + +import h5py + +def writeFlo5File(flow, filename): + with h5py.File(filename, "w") as f: + f.create_dataset("flow", data=flow, compression="gzip", compression_opts=5) + +if __name__ == '__main__': + module_name, class_name = args.model.rsplit(".", 1) + module = importlib.import_module(module_name) + + model = getattr(module, class_name) + model = model().cuda().eval() + + folder = args.folder.split('/')[-1] + + import os + import matplotlib.pyplot as plt + + import torch + import torchvision.transforms as transforms + + # import smurf # Assuming this is your custom inference module + + # Path for the dataset + dataset_path = '/ccn2/dataset/Flows_Kinetics/SPRING/spring/test/' + + save_data_path = args.save_data_path + + if not os.path.exists(save_data_path): + os.makedirs(save_data_path) + + resize_crop = transforms.Compose([ + transforms.ToTensor(), + ]) + + import numpy as np + + def l2norm(x): + return np.sqrt((x ** 2).sum(-1)) + + all_epe = [] + # Create a new HDF5 file + + TAG_FLOAT = 202021.25 + + # Iterate over each folder in the dataset directory + for dir in ['FW', 'BW']: + for stereo in ['left', 'right']: + files = sorted(os.listdir(os.path.join(dataset_path, folder, f'frame_{stereo}'))) + output_folder = os.path.join(save_data_path, folder) + output_folder = os.path.join(output_folder, f'flow_{dir}_{stereo}') + + if not os.path.exists(output_folder): + os.makedirs(output_folder) + + for ct_f in range(len(files) - 1): + # Read images + if dir == 'FW': + f1 = files[ct_f] + f2 = files[ct_f + 1] + else: + f2 = files[ct_f] + f1 = files[ct_f + 1] + t = time.time() + image1_path = os.path.join(dataset_path, folder, f'frame_{stereo}', f1) + image2_path = os.path.join(dataset_path, folder, f'frame_{stereo}', f2) + + idx = image1_path.split('/')[-1].split('.')[0].split('_')[-1] + flow_save_path = os.path.join(output_folder, f'flow_{dir}_{stereo}_' + idx + '.flo5') + + # if os.path.exists(flow_save_path): + # try: + # with h5py.File(flow_save_path, 'r+') as f: + # if f['flow'][:].shape[0] == 2: + # flow = f['flow'][:].transpose([1, 2, 0]) + # del f['flow'] + # f.create_dataset("flow", data=flow, compression="gzip", compression_opts=5) + # continue + # else: + # continue + # except: + # pass + + image1_ = plt.imread(image1_path) + image2_ = plt.imread(image2_path) + + image1 = resize_crop(image1_) + image2 = resize_crop(image2_) + + forward_flow = model.forward(image1, image2) + + writeFlo5File(forward_flow, flow_save_path) diff --git a/cwm/eval/Flow/flow_extraction_classes.py b/cwm/eval/Flow/flow_extraction_classes.py new file mode 100644 index 0000000000000000000000000000000000000000..f1923d72745b998cb144408f0eee763d9f6b360b --- /dev/null +++ b/cwm/eval/Flow/flow_extraction_classes.py @@ -0,0 +1,122 @@ +import torch +import torch.nn as nn + +import cwm.model.model_pretrain as vmae_tranformers +from . import flow_utils +from . import losses as bblosses + + +# Normal Resolution +def l2_norm(x): + return x.square().sum(-3, True).sqrt() + + + + +# x.shape +def get_occ_masks(flow_fwd, flow_bck, occ_thresh=0.5): + fwd_bck_cycle, _ = bblosses.backward_warp(img2=flow_bck, flow=flow_fwd) + flow_diff_fwd = flow_fwd + fwd_bck_cycle + + bck_fwd_cycle, _ = bblosses.backward_warp(img2=flow_fwd, flow=flow_bck) + flow_diff_bck = flow_bck + bck_fwd_cycle + + norm_fwd = l2_norm(flow_fwd) ** 2 + l2_norm(fwd_bck_cycle) ** 2 + norm_bck = l2_norm(flow_bck) ** 2 + l2_norm(bck_fwd_cycle) ** 2 + + occ_thresh_fwd = occ_thresh * norm_fwd + 0.5 + occ_thresh_bck = occ_thresh * norm_bck + 0.5 + + occ_mask_fwd = 1 - (l2_norm(flow_diff_fwd) ** 2 > occ_thresh_fwd).float() + occ_mask_bck = 1 - (l2_norm(flow_diff_bck) ** 2 > occ_thresh_bck).float() + + return occ_mask_fwd, occ_mask_bck + + +class ExtractFlow(nn.Module): + + def __init__(self): + super().__init__() + return + + def forward(self, img1, img2): + ''' + img1: first frame + img2: second frame + returns: flow map (h, w, 2) + ''' + +from cwm.data.masking_generator import RotatedTableMaskingGenerator + +class CWM(ExtractFlow): + def __init__(self, model_name, patch_size, weights_path): + super().__init__() + + self.patch_size = patch_size + model = getattr(vmae_tranformers, model_name) + vmae_8x8_full = model().cuda().eval().requires_grad_(False) + + VMAE_LOAD_PATH = weights_path + did_load = vmae_8x8_full.load_state_dict(torch.load(VMAE_LOAD_PATH)['model'], strict=False) + print(did_load, VMAE_LOAD_PATH) + + self.predictor = vmae_8x8_full + + self.mask_generator = RotatedTableMaskingGenerator( + input_size=(vmae_8x8_full.num_frames, 28, 28), + mask_ratio=0.0, + tube_length=1, + batch_size=1, + mask_type='rotated_table' + ) + + def forward(self, img1, img2): + ''' + img1: [3, 1024, 1024] + img1: [3, 1024, 1024] + both images are imagenet normalized + ''' + + with torch.no_grad(): + FF, _ = flow_utils.scaling_fixed_get_vmae_optical_flow_crop_batched_smoothed(self.predictor, + self.mask_generator, img1[None], + img2[None], + num_scales=2, + min_scale=224, + N_mask_samples=1) + + BF, _ = flow_utils.scaling_fixed_get_vmae_optical_flow_crop_batched_smoothed(self.predictor, + self.mask_generator, + img2[None], + img1[None], + num_scales=2, + min_scale=224, + N_mask_samples=1) + + # FF, _ = flow_utils.get_honglin_3frame_vmae_optical_flow_crop_batched(self.predictor, + # self.mask_generator, img1[None], + # img2[None], img2[None], + # neg_back_flow=True, num_scales=1, + # min_scale=224, N_mask_samples=1, + # mask_ratio=0.0) + # + # BF, _ = flow_utils.get_honglin_3frame_vmae_optical_flow_crop_batched(self.predictor, + # self.mask_generator, img2[None], + # img1[None], img1[None], + # neg_back_flow=True, num_scales=1, + # min_scale=224, N_mask_samples=1, + # mask_ratio=0.0) + + occ_mask = get_occ_masks(FF, BF)[0] + + FF = FF * occ_mask + + FF = FF[0] + + return FF#.cpu().numpy().transpose([1, 2, 0]) + + +class CWM_8x8(CWM): + def __init__(self): + super().__init__('vitb_8x8patch_3frames', 8, + '/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400/checkpoint-399.pth') diff --git a/cwm/eval/Flow/flow_utils.py b/cwm/eval/Flow/flow_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..ad37600b33e096c07939d9b797dd6a6db927abb7 --- /dev/null +++ b/cwm/eval/Flow/flow_utils.py @@ -0,0 +1,569 @@ +import random +import math +import numpy as np +import torch +import torch.nn.functional as F +from . import losses as bblosses +import kornia + +IMAGENET_DEFAULT_MEAN = (0.485, 0.456, 0.406) +IMAGENET_DEFAULT_STD = (0.229, 0.224, 0.225) + +def compute_optical_flow(embedding_tensor, mask_tensor, frame_size): + # Unroll the mask tensor and find the indices of the masked and unmasked values in the second frame + mask_unrolled = mask_tensor.view(-1) + + second_frame_unmask_indices = torch.where(mask_unrolled[frame_size ** 2:] == False)[0] + + # Divide the embedding tensor into two parts: corresponding to the first and the second frame + first_frame_embeddings = embedding_tensor[0, :frame_size ** 2, :] + second_frame_embeddings = embedding_tensor[0, frame_size ** 2:, :] + + # print(first_frame_embeddings.shape, second_frame_embeddings.shape, embedding_tensor.shape) + + # Compute the cosine similarity between the unmasked embeddings from the second frame and the embeddings from the first frame + dot_product = torch.matmul(second_frame_embeddings, first_frame_embeddings.T) + norms = torch.norm(second_frame_embeddings, dim=1)[:, None] * torch.norm(first_frame_embeddings, dim=1)[None, :] + cos_sim_matrix = dot_product / norms + + # Find the indices of pixels in the first frame that are most similar to each unmasked pixel in the second frame + first_frame_most_similar_indices = cos_sim_matrix.argmax(dim=-1) + + # Convert the 1D pixel indices into 2D coordinates + second_frame_y = second_frame_unmask_indices // frame_size + second_frame_x = second_frame_unmask_indices % frame_size + first_frame_y = first_frame_most_similar_indices // frame_size + first_frame_x = first_frame_most_similar_indices % frame_size + + # Compute the x and y displacements and convert them to float + displacements_x = (second_frame_x - first_frame_x).float() + displacements_y = (second_frame_y - first_frame_y).float() + + # Initialize optical flow tensor + optical_flow = torch.zeros((2, frame_size, frame_size), device=embedding_tensor.device) + + # Assign the computed displacements to the corresponding pixels in the optical flow tensor + optical_flow[0, second_frame_y, second_frame_x] = displacements_x + optical_flow[1, second_frame_y, second_frame_x] = displacements_y + + return optical_flow + + +def get_minimal_224_crops_new_batched(video_tensor, N): + B, T, C, H, W = video_tensor.shape + + # Calculate the number of crops needed in both the height and width dimensions + num_crops_h = math.ceil(H / 224) if H > 224 else 1 + num_crops_w = math.ceil(W / 224) if W > 224 else 1 + + # Calculate the step size for the height and width dimensions + step_size_h = 0 if H <= 224 else max(0, (H - 224) // (num_crops_h - 1)) + step_size_w = 0 if W <= 224 else max(0, (W - 224) // (num_crops_w - 1)) + + # Create a list to store the cropped tensors and their start positions + cropped_tensors = [] + crop_positions = [] + + # Iterate over the height and width dimensions, extract the 224x224 crops, and append to the cropped_tensors list + for i in range(num_crops_h): + for j in range(num_crops_w): + start_h = i * step_size_h + start_w = j * step_size_w + end_h = min(start_h + 224, H) + end_w = min(start_w + 224, W) + crop = video_tensor[:, :, :, start_h:end_h, start_w:end_w] + cropped_tensors.append(crop) + crop_positions.append((start_h, start_w)) + + D = len(cropped_tensors) + + # If N is greater than D, generate additional random crops + if N > D and H > 224 and W > 224: # check if H and W are greater than 224 + for _ in range(N - D): + start_h = random.randint(0, H - 224) + start_w = random.randint(0, W - 224) + crop = video_tensor[:, :, :, start_h:(start_h + 224), start_w:(start_w + 224)] + cropped_tensors.append(crop) + crop_positions.append((start_h, start_w)) + + # Reshape the cropped tensors to fit the required output shape (B, T, C, 224, 224) + cropped_tensors = [crop.reshape(B, T, C, 224, 224) for crop in cropped_tensors] + + return cropped_tensors, crop_positions + + +def create_weighted_mask_batched(h, w): + y_mask = np.linspace(0, 1, h) + y_mask = np.minimum(y_mask, 1 - y_mask) + x_mask = np.linspace(0, 1, w) + x_mask = np.minimum(x_mask, 1 - x_mask) + weighted_mask = np.outer(y_mask, x_mask) + return torch.from_numpy(weighted_mask).float() + + +def reconstruct_video_new_2_batched(cropped_tensors, crop_positions, original_shape): + B, T, C, H, W = original_shape + + # Initialize an empty tensor to store the reconstructed video + reconstructed_video = torch.zeros((B, T, C, H, W)).to(cropped_tensors[0].device) + + # Create a tensor to store the sum of weighted masks + weighted_masks_sum = torch.zeros((B, T, C, H, W)).to(cropped_tensors[0].device) + + # Create a weighted mask for the crops + weighted_mask = create_weighted_mask_batched(224, 224).to(cropped_tensors[0].device) + weighted_mask = weighted_mask[None, None, None, :, :] # Extend dimensions to match the cropped tensor. + + for idx, crop in enumerate(cropped_tensors): + start_h, start_w = crop_positions[idx] + + # Multiply the crop with the weighted mask + weighted_crop = crop * weighted_mask + + # Add the weighted crop to the corresponding location in the reconstructed_video tensor + reconstructed_video[:, :, :, start_h:(start_h + 224), start_w:(start_w + 224)] += weighted_crop + + # Update the weighted_masks_sum tensor + weighted_masks_sum[:, :, :, start_h:(start_h + 224), start_w:(start_w + 224)] += weighted_mask + + # Add a small epsilon value to avoid division by zero + epsilon = 1e-8 + + # Normalize the reconstructed video by dividing each pixel by its corresponding weighted_masks_sum value plus epsilon + reconstructed_video /= (weighted_masks_sum + epsilon) + + return reconstructed_video + + +def l2_norm(x): + return x.square().sum(-3, True).sqrt() + + +resize = lambda x, a: F.interpolate(x, [int(a * x.shape[-2]), int(a * x.shape[-1])], mode='bilinear', + align_corners=False) + +upsample = lambda x, H, W: F.interpolate(x, [int(H), int(W)], mode='bilinear', align_corners=False) + + +def get_occ_masks(flow_fwd, flow_bck, occ_thresh=0.5): + fwd_bck_cycle, _ = bblosses.backward_warp(img2=flow_bck, flow=flow_fwd) + flow_diff_fwd = flow_fwd + fwd_bck_cycle + + bck_fwd_cycle, _ = bblosses.backward_warp(img2=flow_fwd, flow=flow_bck) + flow_diff_bck = flow_bck + bck_fwd_cycle + + norm_fwd = l2_norm(flow_fwd) ** 2 + l2_norm(fwd_bck_cycle) ** 2 + norm_bck = l2_norm(flow_bck) ** 2 + l2_norm(bck_fwd_cycle) ** 2 + + occ_thresh_fwd = occ_thresh * norm_fwd + 0.5 + occ_thresh_bck = occ_thresh * norm_bck + 0.5 + + occ_mask_fwd = 1 - (l2_norm(flow_diff_fwd) ** 2 > occ_thresh_fwd).float() + occ_mask_bck = 1 - (l2_norm(flow_diff_bck) ** 2 > occ_thresh_bck).float() + + return occ_mask_fwd, occ_mask_bck + +def forward_backward_cycle_consistency(flow_fwd, flow_bck, niters=10): + # Make sure to be using axes-swapped, upsampled flows! + bck_flow_clone = flow_bck.clone().detach() + fwd_flow_clone = flow_fwd.clone().detach() + + for i in range(niters): + + fwd_bck_cycle_orig, _ = bblosses.backward_warp(img2=bck_flow_clone, flow=fwd_flow_clone) + flow_diff_fwd_orig = fwd_flow_clone + fwd_bck_cycle_orig + + fwd_flow_clone = fwd_flow_clone - flow_diff_fwd_orig/2 + + bck_fwd_cycle_orig, _ = bblosses.backward_warp(img2=fwd_flow_clone, flow=bck_flow_clone) + flow_diff_bck_orig = bck_flow_clone + bck_fwd_cycle_orig + + + bck_flow_clone = bck_flow_clone - flow_diff_bck_orig/2 + + return fwd_flow_clone, bck_flow_clone + +from PIL import Image +def resize_flow_map(flow_map, target_size): + """ + Resize a flow map to a target size while adjusting the flow vectors. + + Parameters: + flow_map (numpy.ndarray): Input flow map of shape (H, W, 2) where each pixel contains a (dx, dy) flow vector. + target_size (tuple): Target size (height, width) for the resized flow map. + + Returns: + numpy.ndarray: Resized and scaled flow map of shape (target_size[0], target_size[1], 2). + """ + # Get the original size + flow_map = flow_map[0].detach().cpu().numpy() + flow_map = flow_map.transpose(1, 2, 0) + original_size = flow_map.shape[:2] + + # Separate the flow map into two channels: dx and dy + flow_map_x = flow_map[:, :, 0] + flow_map_y = flow_map[:, :, 1] + + # Convert each flow channel to a PIL image for resizing + flow_map_x_img = Image.fromarray(flow_map_x) + flow_map_y_img = Image.fromarray(flow_map_y) + + # Resize both channels to the target size using bilinear interpolation + flow_map_x_resized = flow_map_x_img.resize(target_size, Image.BILINEAR) + flow_map_y_resized = flow_map_y_img.resize(target_size, Image.BILINEAR) + + # Convert resized PIL images back to NumPy arrays + flow_map_x_resized = np.array(flow_map_x_resized) + flow_map_y_resized = np.array(flow_map_y_resized) + + # Compute the scaling factor based on the size change + scale_factor = target_size[0] / original_size[0] # Scaling factor for both dx and dy + + # Scale the flow vectors (dx and dy) accordingly + flow_map_x_resized *= scale_factor + flow_map_y_resized *= scale_factor + + # Recombine the two channels into a resized flow map + flow_map_resized = np.stack([flow_map_x_resized, flow_map_y_resized], axis=-1) + + flow_map_resized = torch.from_numpy(flow_map_resized)[None].permute(0, 3, 1, 2) + + return flow_map_resized + +def get_vmae_optical_flow_crop_batched_smoothed(generator, + mask_generator, + img1, + img2, + neg_back_flow=True, + num_scales=1, + min_scale=400, + N_mask_samples=100, + mask_ratio=0.8, + smoothing_factor=1): + + ##### DEPRECATED + print('Deprecated. Please use scaling_fixed_get_vmae_optical_flow_crop_batched_smoothed') + + return scaling_fixed_get_vmae_optical_flow_crop_batched_smoothed(generator, + mask_generator, + img1, + img2, + neg_back_flow=neg_back_flow, + num_scales=num_scales, + min_scale=min_scale, + N_mask_samples=N_mask_samples, + mask_ratio=mask_ratio, + smoothing_factor=smoothing_factor) + + + +def average_crops(tensor, D): + C, H, W = tensor.shape + + # Create zero-filled tensors for the shifted crops + down_shifted = torch.zeros_like(tensor) + up_shifted = torch.zeros_like(tensor) + right_shifted = torch.zeros_like(tensor) + left_shifted = torch.zeros_like(tensor) + + # Shift the tensor and store the results in the zero-filled tensors + down_shifted[:, :H-D, :] = tensor[:, D:, :] + up_shifted[:, D:, :] = tensor[:, :H-D, :] + right_shifted[:, :, :W-D] = tensor[:, :, D:] + left_shifted[:, :, D:] = tensor[:, :, :W-D] + + # Average the tensor with its four crops + result = (tensor + down_shifted + up_shifted + right_shifted + left_shifted) / 5.0 + + return result + + +def scaling_fixed_get_vmae_optical_flow_crop_batched_smoothed(predictor, + mask_generator, + img1, + img2, + conditioning_img=None, + num_scales=1, + min_scale=400, + N_mask_samples=100, + smoothing_factor=1): + B = img1.shape[0] + assert len(img1.shape) == 4 + assert num_scales >= 1 + + # For scaling + h1 = img2.shape[-2] + w1 = img2.shape[-1] + + + alpha = (min_scale / img1.shape[-2]) ** (1 / (num_scales - 1)) if num_scales > 1 else 1 + + frame_size = 224 // predictor.patch_size[-1] + + patch_size = predictor.patch_size[-1] + + num_frames = predictor.num_frames + + all_fwd_flows_e2d = [] + + s_hs = [] + s_ws = [] + + for aidx in range(num_scales): + # print(aidx) + + # print('aidx: ', aidx) + + img1_scaled = F.interpolate(img1.clone(), [int((alpha ** aidx) * h1), int((alpha ** aidx) * w1)], + mode='bicubic', align_corners=True) + img2_scaled = F.interpolate(img2.clone(), [int((alpha ** aidx) * h1), int((alpha ** aidx) * w1)], + mode='bicubic', align_corners=True) + + if conditioning_img is not None: + conditioning_img_scaled = F.interpolate(conditioning_img.clone(), [int((alpha ** aidx) * h1), int((alpha ** aidx) * w1)], + mode='bilinear', align_corners=False) + + # print("img1_scaled", img1_scaled.shape, alpha, min_scale, num_scales) + + h2 = img2_scaled.shape[-2] + w2 = img2_scaled.shape[-1] + + s_h = h1 / h2 + s_w = w1 / w2 + + s_hs.append(s_h) + s_ws.append(s_w) + + if conditioning_img is not None: + video = torch.cat([conditioning_img_scaled.unsqueeze(1), img2_scaled.unsqueeze(1), img1_scaled.unsqueeze(1)], 1) + else: + video = torch.cat([img2_scaled.unsqueeze(1)]*(num_frames-1) + [img1_scaled.unsqueeze(1)], 1) + + # Should work, even if the incoming video is already 224x224 + crops1, c_pos1 = get_minimal_224_crops_new_batched(video, 1) + + num_crops = len(crops1) + + crop_flows_enc = [] + crop_flows_enc2dec = [] + N_samples = N_mask_samples + + crop = torch.cat(crops1, 0).cuda() + + optical_flows_enc2dec = torch.zeros(B * num_crops, 2, frame_size, frame_size).cuda() + mask_counts = torch.zeros(frame_size, frame_size).cuda() + + i = 0 + while i < N_samples or (mask_counts == 0).any().item(): + if i % 100 == 0: + pass # print(i) + + # This would be that every sample has the same mask. For now that's okay I think + mask = mask_generator().bool().cuda() + mask_2f = ~mask[0, (frame_size * frame_size)*(num_frames-1):] + mask_counts += mask_2f.reshape(frame_size, frame_size) + + with torch.cuda.amp.autocast(enabled=True): + + processed_x = crop.transpose(1, 2) + + encoder_out = predictor.encoder(processed_x.to(torch.float16), mask.repeat(B * num_crops, 1)) + encoder_to_decoder = predictor.encoder_to_decoder(encoder_out) + + encoder_to_decoder = encoder_to_decoder[:, (frame_size * frame_size)*(num_frames-2):, :] + flow_mask = mask[:, (frame_size * frame_size)*(num_frames-2):] + + optical_flow_e2d = [] + # one per batch element for now + for b in range(B * num_crops): + batch_flow = compute_optical_flow(encoder_to_decoder[b].unsqueeze(0), flow_mask, frame_size) + # optical_flow_e2d.append(batch_flow.unsqueeze(0)) + + optical_flow_e2d.append(average_crops(batch_flow, smoothing_factor).unsqueeze(0)) + + optical_flow_e2d = torch.cat(optical_flow_e2d, 0) + optical_flows_enc2dec += optical_flow_e2d + i += 1 + + optical_flows_enc2dec = optical_flows_enc2dec / mask_counts + + #other fucntion + # scale_factor_y = video.shape[-2] / 224 + # scale_factor_x = video.shape[-1] / 224 + # + # scaled_optical_flow = torch.zeros_like(optical_flows_enc2dec) + # scaled_optical_flow[:, 0, :, :] = optical_flows_enc2dec[:, 0, :, :] * scale_factor_x * s_w + # scaled_optical_flow[:, 1, :, :] = optical_flows_enc2dec[:, 1, :, :] * scale_factor_y * s_h + # + # # split the crops back up + # crop_flows_enc2dec = scaled_optical_flow.split(B, 0) + + ### + #Kevin's fn + crop_flows_enc2dec = optical_flows_enc2dec.split(B, 0) + + ### + + #Changed by Kevin + T1 = [F.interpolate(_, [int(224), int(224)], mode='bicubic', align_corners=True).unsqueeze(1).cpu() for _ in + crop_flows_enc2dec] + optical_flows_enc2dec_joined = reconstruct_video_new_2_batched(T1, c_pos1, ( + B, 1, 2, video.shape[-2], video.shape[-1])).squeeze(1) + + #other function + # optical_flows_enc2dec_joined = reconstruct_video_new_2_batched( + # [_.unsqueeze(1).repeat_interleave(patch_size, -1).repeat_interleave(patch_size, -2).cpu() for _ in + # crop_flows_enc2dec], c_pos1, (B, 1, 2, video.shape[-2], video.shape[-1])).squeeze(1) + # + all_fwd_flows_e2d.append(optical_flows_enc2dec_joined) + + #other function + # all_fwd_flows_e2d_new = [] + # + # for r in all_fwd_flows_e2d: + # new_r = upsample(r, all_fwd_flows_e2d[0].shape[-2], all_fwd_flows_e2d[0].shape[-1]) + # all_fwd_flows_e2d_new.append(new_r.unsqueeze(-1)) + # return_flow = torch.cat(all_fwd_flows_e2d_new, -1).mean(-1) + # + # + # return_flow = -return_flow + # all_fwd_flows_e2d_new = [-_ for _ in all_fwd_flows_e2d_new] + # + # return return_flow, all_fwd_flows_e2d_new + + #Kevin's method + all_fwd_flows_e2d_new = [] + + for ridx, r in enumerate(all_fwd_flows_e2d): + # print('ridx', ridx) + # print('sh', s_hs[ridx]) + # print('sw', s_ws[ridx]) + # print('scale_fac y', scale_ys[ridx]) + # print('scale_fac x', scale_xs[ridx]) + + _sh = s_hs[ridx] + _sw = s_ws[ridx] + _sfy = predictor.patch_size[-1] + _sfx = predictor.patch_size[-1] + + # plt.figure(figsize=(20, 20)) + + # plt.subplot(1,3,1) + # plt.imshow(f2rgb(-r).cpu().numpy()[0].transpose(1,2,0)) + + # plt.subplot(1,3,2) + new_r = F.interpolate(r, [int(all_fwd_flows_e2d[0].shape[-2]), int(all_fwd_flows_e2d[0].shape[-1])], mode='bicubic', align_corners=True) + # plt.imshow(f2rgb(-new_r).cpu().numpy()[0].transpose(1,2,0)) + + scaled_new_r = torch.zeros_like(new_r) + scaled_new_r[:, 0, :, :] = new_r[:, 0, :, :] * _sfx * _sw + scaled_new_r[:, 1, :, :] = new_r[:, 1, :, :] * _sfy * _sh + + # plt.subplot(1,3,3) + # plt.imshow(f2rgb(-scaled_new_r).cpu().numpy()[0].transpose(1,2,0)) + + # plt.show() + + all_fwd_flows_e2d_new.append(scaled_new_r.unsqueeze(-1)) + return_flow = torch.cat(all_fwd_flows_e2d_new, -1).mean(-1) + + return_flow = -return_flow + all_fwd_flows_e2d_new = [-_ for _ in all_fwd_flows_e2d_new] + + return return_flow , all_fwd_flows_e2d_new + +def extract_jacobians_and_flows(img1, img2, + flow_generator, + mask, + target_mask=None): + + IMAGE_SIZE = img1.shape[-2:] + + y = torch.cat([img2.unsqueeze(1), img1.unsqueeze(1)], 1) + + jacobians, flows, _ = flow_generator(y, mask, target_mask) + + # swap x,y flow dims + flows = torch.cat([flows[0, 1].unsqueeze(0), flows[0, 0].unsqueeze(0)]) + + # upsample to 224 + flows = flows.unsqueeze(0).repeat_interleave(IMAGE_SIZE[0] // flows.shape[-1], -1).repeat_interleave( + IMAGE_SIZE[0] // flows.shape[-1], -2) + + return jacobians, flows + +import matplotlib.pyplot as plt + +class FlowToRgb(object): + + def __init__(self, max_speed=1.0, from_image_coordinates=True, from_sampling_grid=False): + self.max_speed = max_speed + self.from_image_coordinates = from_image_coordinates + self.from_sampling_grid = from_sampling_grid + + def __call__(self, flow): + assert flow.size(-3) == 2, flow.shape + if self.from_sampling_grid: + flow_x, flow_y = torch.split(flow, [1, 1], dim=-3) + flow_y = -flow_y + elif not self.from_image_coordinates: + flow_x, flow_y = torch.split(flow, [1, 1], dim=-3) + else: + flow_h, flow_w = torch.split(flow, [1,1], dim=-3) + flow_x, flow_y = [flow_w, -flow_h] + + + # print("flow_x", flow_x[0, :, 0, 0], flow_y[0, :, 0, 0]) + angle = torch.atan2(flow_y, flow_x) # in radians from -pi to pi + speed = torch.sqrt(flow_x**2 + flow_y**2) / self.max_speed + + # print("angle", angle[0, :, 0, 0] * 180 / np.pi) + + hue = torch.fmod(angle, torch.tensor(2 * np.pi)) + sat = torch.ones_like(hue) + val = speed + + hsv = torch.cat([hue, sat, val], -3) + rgb = kornia.color.hsv_to_rgb(hsv) + return rgb + + def make_colorwheel(self): + """ + Generates a color wheel for optical flow visualization as presented in: + Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007) + """ + RY = 15 + YG = 6 + GC = 4 + CB = 11 + BM = 13 + MR = 6 + + ncols = RY + YG + GC + CB + BM + MR + colorwheel = np.zeros((ncols, 3)) + col = 0 + + # RY + colorwheel[0:RY, 0] = 255 + colorwheel[0:RY, 1] = np.floor(255 * np.arange(0, RY) / RY) + col += RY + # YG + colorwheel[col:col + YG, 0] = 255 - np.floor(255 * np.arange(0, YG) / YG) + colorwheel[col:col + YG, 1] = 255 + col += YG + # GC + colorwheel[col:col + GC, 1] = 255 + colorwheel[col:col + GC, 2] = np.floor(255 * np.arange(0, GC) / GC) + col += GC + # CB + colorwheel[col:col + CB, 1] = 255 - np.floor(255 * np.arange(0, CB) / CB) + colorwheel[col:col + CB, 2] = 255 + col += CB + # BM + colorwheel[col:col + BM, 2] = 255 + colorwheel[col:col + BM, 0] = np.floor(255 * np.arange(0, BM) / BM) + col += BM + # MR + colorwheel[col:col + MR, 2] = 255 - np.floor(255 * np.arange(0, MR) / MR) + colorwheel[col:col + MR, 0] = 255 + return colorwheel \ No newline at end of file diff --git a/cwm/eval/Flow/flow_utils_legacy.py b/cwm/eval/Flow/flow_utils_legacy.py new file mode 100644 index 0000000000000000000000000000000000000000..355590223e769fa77ba46ca22837662e8ea0304a --- /dev/null +++ b/cwm/eval/Flow/flow_utils_legacy.py @@ -0,0 +1,152 @@ +def scaling_fixed_get_vmae_optical_flow_crop_batched_smoothed(generator, + mask_generator, + img1, + img2, + neg_back_flow=True, + num_scales=1, + min_scale=400, + N_mask_samples=100, + mask_ratio=0.8, + smoothing_factor=1): + B = img1.shape[0] + assert len(img1.shape) == 4 + assert num_scales >= 1 + + # For scaling + h1 = img2.shape[-2] + w1 = img2.shape[-1] + assert min_scale < h1 and min_scale >= 360 # Below 360p, the flows look terrible + + if neg_back_flow is False: + print('WARNING: Not calculating negative backward flow') + + alpha = (min_scale / img1.shape[-2]) ** (1 / (num_scales - 1)) if num_scales > 1 else 1 + + frame_size = 224 // generator.patch_size[-1] + + all_fwd_flows_e2d = [] + + s_hs = [] + s_ws = [] + + for aidx in range(num_scales): + print(aidx) + + # print('aidx: ', aidx) + + img1_scaled = F.interpolate(img1.clone(), [int((alpha ** aidx) * h1), int((alpha ** aidx) * w1)], + mode='bicubic', align_corners=True) + img2_scaled = F.interpolate(img2.clone(), [int((alpha ** aidx) * h1), int((alpha ** aidx) * w1)], + mode='bicubic', align_corners=True) + + h2 = img2_scaled.shape[-2] + w2 = img2_scaled.shape[-1] + + s_h = h1 / h2 + s_w = w1 / w2 + + s_hs.append(s_h) + s_ws.append(s_w) + + # Because technically the compute_optical_flow function returns neg back flow + if neg_back_flow is True: + video = torch.cat([img2_scaled.unsqueeze(1), img1_scaled.unsqueeze(1)], 1) + else: + video = torch.cat([img1_scaled.unsqueeze(1), img2_scaled.unsqueeze(1)], 1) + + # Should work, even if the incoming video is already 224x224 + crops1, c_pos1 = get_minimal_224_crops_new_batched(video, 1) + + num_crops = len(crops1) + + crop_flows_enc = [] + crop_flows_enc2dec = [] + N_samples = N_mask_samples + + crop = torch.cat(crops1, 0).cuda() + + optical_flows_enc2dec = torch.zeros(B * num_crops, 2, frame_size, frame_size).cuda() + mask_counts = torch.zeros(frame_size, frame_size).cuda() + + i = 0 + while i < N_samples or (mask_counts == 0).any().item(): + if i % 100 == 0: + pass # print(i) + mask_generator.mask_ratio = mask_ratio + + # This would be that every sample has the same mask. For now that's okay I think + mask = mask_generator()[None] + mask_2f = ~mask[0, frame_size * frame_size:] + mask_counts += mask_2f.reshape(frame_size, frame_size) + + with torch.cuda.amp.autocast(enabled=True): + + processed_x = generator._preprocess(crop) + + encoder_out = generator.predictor.encoder(processed_x.to(torch.float16), mask.repeat(B * num_crops, 1)) + encoder_to_decoder = generator.predictor.encoder_to_decoder(encoder_out) + + optical_flow_e2d = [] + # one per batch element for now + for b in range(B * num_crops): + batch_flow = compute_optical_flow(encoder_to_decoder[b].unsqueeze(0), mask, frame_size) + optical_flow_e2d.append(average_crops(batch_flow, smoothing_factor).unsqueeze(0)) + + optical_flow_e2d = torch.cat(optical_flow_e2d, 0) + optical_flows_enc2dec += optical_flow_e2d + i += 1 + + optical_flows_enc2dec = optical_flows_enc2dec / mask_counts + + # split the crops back up + crop_flows_enc2dec = optical_flows_enc2dec.split(B, 0) + + T1 = [F.interpolate(_, [int(224), int(224)], mode='bicubic', align_corners=True).unsqueeze(1).cpu() for _ in + crop_flows_enc2dec] + + optical_flows_enc2dec_joined = reconstruct_video_new_2_batched(T1, c_pos1, ( + B, 1, 2, video.shape[-2], video.shape[-1])).squeeze(1) + + all_fwd_flows_e2d.append(optical_flows_enc2dec_joined) + + all_fwd_flows_e2d_new = [] + + for ridx, r in enumerate(all_fwd_flows_e2d): + # print('ridx', ridx) + # print('sh', s_hs[ridx]) + # print('sw', s_ws[ridx]) + # print('scale_fac y', scale_ys[ridx]) + # print('scale_fac x', scale_xs[ridx]) + + _sh = s_hs[ridx] + _sw = s_ws[ridx] + _sfy = generator.patch_size[-1] + _sfx = generator.patch_size[-1] + + # plt.figure(figsize=(20, 20)) + + # plt.subplot(1,3,1) + # plt.imshow(f2rgb(-r).cpu().numpy()[0].transpose(1,2,0)) + + # plt.subplot(1,3,2) + new_r = F.interpolate(r, [int(all_fwd_flows_e2d[0].shape[-2]), int(all_fwd_flows_e2d[0].shape[-1])], + mode='bicubic', align_corners=True) + # plt.imshow(f2rgb(-new_r).cpu().numpy()[0].transpose(1,2,0)) + + scaled_new_r = torch.zeros_like(new_r) + scaled_new_r[:, 0, :, :] = new_r[:, 0, :, :] * _sfx * _sw + scaled_new_r[:, 1, :, :] = new_r[:, 1, :, :] * _sfy * _sh + + # plt.subplot(1,3,3) + # plt.imshow(f2rgb(-scaled_new_r).cpu().numpy()[0].transpose(1,2,0)) + + # plt.show() + + all_fwd_flows_e2d_new.append(scaled_new_r.unsqueeze(-1)) + return_flow = torch.cat(all_fwd_flows_e2d_new, -1).mean(-1) + + if neg_back_flow is True: + return_flow = -return_flow + all_fwd_flows_e2d_new = [-_ for _ in all_fwd_flows_e2d_new] + + return return_flow, all_fwd_flows_e2d_new \ No newline at end of file diff --git a/cwm/eval/Flow/generator.py b/cwm/eval/Flow/generator.py new file mode 100644 index 0000000000000000000000000000000000000000..954ca3ad5ba3269bf4a58e75150155528b79a2f1 --- /dev/null +++ b/cwm/eval/Flow/generator.py @@ -0,0 +1,579 @@ +import kornia +import numpy as np +import torch +import torch.nn.functional as F +from einops import rearrange +from torch import nn + +import cwm.eval.Flow.masking_flow as masking + + +def boltzmann(x, beta=1, eps=1e-9): + if beta is None: + return x + x = torch.exp(x * beta) + return x / x.amax((-1,-2), keepdim=True).clamp(min=eps) + +IMAGENET_DEFAULT_MEAN = (0.485, 0.456, 0.406) +IMAGENET_DEFAULT_STD = (0.229, 0.224, 0.225) + +def imagenet_normalize(x, temporal_dim=1): + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(x.device)[None,None,:,None,None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(x.device)[None,None,:,None,None].to(x) + if temporal_dim == 2: + mean = mean.transpose(1,2) + std = std.transpose(1,2) + return (x - mean) / std + +def imagenet_unnormalize(x, temporal_dim=2): + device = x.device + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, None, :, None, None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, None, :, None, None].to(x) + if temporal_dim == 2: + mean = mean.transpose(1,2) + std = std.transpose(1,2) + x = x*std + mean + return x + + + +def coordinate_ims(batch_size, seq_length, imsize, normalize=True, dtype_out=torch.float32): + static = False + if seq_length == 0: + static = True + seq_length = 1 + B = batch_size + T = seq_length + H,W = imsize + ones = torch.ones([B,H,W,1], dtype=dtype_out) + if normalize: + h = torch.divide(torch.arange(H).to(ones), torch.tensor(H-1, dtype=dtype_out)) + h = 2.0 * ((h.view(1, H, 1, 1) * ones) - 0.5) + w = torch.divide(torch.arange(W).to(ones), torch.tensor(W-1, dtype=dtype_out)) + w = 2.0 * ((w.view(1, 1, W, 1) * ones) - 0.5) + else: + h = torch.arange(H).to(ones).view(1,H,1,1) * ones + w = torch.arange(W).to(ones).view(1,1,W,1) * ones + h = torch.stack([h]*T, 1) + w = torch.stack([w]*T, 1) + hw_ims = torch.cat([h,w], -1) + if static: + hw_ims = hw_ims[:,0] + return hw_ims + + +def get_distribution_centroid(dist, eps=1e-9, normalize=False): + + B,T,C,H,W = dist.shape + assert C == 1 + dist_sum = dist.sum((-2, -1), keepdim=True).clamp(min=eps) + dist = dist / dist_sum + + grid = coordinate_ims(B, T, [H,W], normalize=normalize).to(dist.device) + grid = grid.permute(0,1,4,2,3) + centroid = (grid * dist).sum((-2,-1)) + return centroid + + + +class FlowToRgb(object): + + def __init__(self, max_speed=1.0, from_image_coordinates=True, from_sampling_grid=False): + self.max_speed = max_speed + self.from_image_coordinates = from_image_coordinates + self.from_sampling_grid = from_sampling_grid + + def __call__(self, flow): + assert flow.size(-3) == 2, flow.shape + if self.from_sampling_grid: + flow_x, flow_y = torch.split(flow, [1, 1], dim=-3) + flow_y = -flow_y + elif not self.from_image_coordinates: + flow_x, flow_y = torch.split(flow, [1, 1], dim=-3) + else: + flow_h, flow_w = torch.split(flow, [1,1], dim=-3) + flow_x, flow_y = [flow_w, -flow_h] + + angle = torch.atan2(flow_y, flow_x) # in radians from -pi to pi + speed = torch.sqrt(flow_x**2 + flow_y**2) / self.max_speed + + hue = torch.fmod(angle, torch.tensor(2 * np.pi)) + sat = torch.ones_like(hue) + val = speed + + hsv = torch.cat([hue, sat, val], -3) + rgb = kornia.color.hsv_to_rgb(hsv) + return rgb + +class Patchify(nn.Module): + """Convert a set of images or a movie into patch vectors""" + + def __init__(self, + patch_size=(16, 16), + temporal_dim=1, + squeeze_channel_dim=True + ): + super().__init__() + self.set_patch_size(patch_size) + self.temporal_dim = temporal_dim + assert self.temporal_dim in [1, 2], self.temporal_dim + self._squeeze_channel_dim = squeeze_channel_dim + + @property + def num_patches(self): + if (self.T is None) or (self.H is None) or (self.W is None): + return None + else: + return (self.T // self.pt) * (self.H // self.ph) * (self.W // self.pw) + + def set_patch_size(self, patch_size): + self.patch_size = patch_size + if len(self.patch_size) == 2: + self.ph, self.pw = self.patch_size + self.pt = 1 + self._patches_are_3d = False + elif len(self.patch_size) == 3: + self.pt, self.ph, self.pw = self.patch_size + self._patches_are_3d = True + else: + raise ValueError("patch_size must be a 2- or 3-tuple, but is %s" % self.patch_size) + + self.shape_inp = self.rank_inp = self.H = self.W = self.T = None + self.D = self.C = self.E = self.embed_dim = None + + def _check_shape(self, x): + self.shape_inp = x.shape + self.rank_inp = len(self.shape_inp) + self.H, self.W = self.shape_inp[-2:] + assert (self.H % self.ph) == 0 and (self.W % self.pw) == 0, (self.shape_inp, self.patch_size) + if (self.rank_inp == 5) and self._patches_are_3d: + self.T = self.shape_inp[self.temporal_dim] + assert (self.T % self.pt) == 0, (self.T, self.pt) + elif self.rank_inp == 5: + self.T = self.shape_inp[self.temporal_dim] + else: + self.T = 1 + + def split_by_time(self, x): + shape = x.shape + assert shape[1] % self.T == 0, (shape, self.T) + return x.view(shape[0], self.T, shape[1] // self.T, *shape[2:]) + + def merge_by_time(self, x): + shape = x.shape + return x.view(shape[0], shape[1] * shape[2], *shape[3:]) + + def video_to_patches(self, x): + if self.rank_inp == 4: + assert self.pt == 1, (self.pt, x.shape) + x = rearrange(x, 'b c (h ph) (w pw) -> b (h w) (ph pw) c', ph=self.ph, pw=self.pw) + else: + assert self.rank_inp == 5, (x.shape, self.rank_inp, self.shape_inp) + dim_order = 'b (t pt) c (h ph) (w pw)' if self.temporal_dim == 1 else 'b c (t pt) (h ph) (w pw)' + x = rearrange(x, dim_order + ' -> b (t h w) (pt ph pw) c', pt=self.pt, ph=self.ph, pw=self.pw) + + self.N, self.D, self.C = x.shape[-3:] + self.embed_dim = self.E = self.D * self.C + return x + + def patches_to_video(self, x): + shape = x.shape + rank = len(shape) + if rank == 4: + B, _N, _D, _C = shape + else: + assert rank == 3, rank + B, _N, _E = shape + assert (_E % self.D == 0), (_E, self.D) + x = x.view(B, _N, self.D, -1) + + if _N < self.num_patches: + masked_patches = self.get_masked_patches( + x, + num_patches=(self.num_patches - _N), + mask_mode=self.mask_mode) + x = torch.cat([x, masked_patches], 1) + + x = rearrange( + x, + 'b (t h w) (pt ph pw) c -> b c (t pt) (h ph) (w pw)', + pt=self.pt, ph=self.ph, pw=self.pw, + t=(self.T // self.pt), h=(self.H // self.ph), w=(self.W // self.pw)) + + if self.rank_inp == 5 and (self.temporal_dim == 1): + x = x.transpose(1, 2) + elif self.rank_inp == 4: + assert x.shape[2] == 1, x.shape + x = x[:, :, 0] + return x + + @staticmethod + def get_masked_patches(x, num_patches, mask_mode='zeros'): + shape = x.shape + patches_shape = (shape[0], num_patches, *shape[2:]) + if mask_mode == 'zeros': + return torch.zeros(patches_shape).to(x.device).to(x.dtype).detach() + elif mask_mode == 'gray': + return 0.5 * torch.ones(patches_shape).to(x.device).to(x.dtype).detach() + else: + raise NotImplementedError("Haven't implemented mask_mode == %s" % mask_mode) + + def average_within_patches(self, z): + if len(z.shape) == 3: + z = rearrange(z, 'b n (d c) -> b n d c', c=self.C) + return z.mean(-2, True).repeat(1, 1, z.shape[-2], 1) + + def forward(self, x, to_video=False, mask_mode='zeros'): + if not to_video: + self._check_shape(x) + x = self.video_to_patches(x) + return x if not self._squeeze_channel_dim else x.view(x.size(0), self.N, -1) + + else: # x are patches + assert (self.shape_inp is not None) and (self.num_patches is not None) + self.mask_mode = mask_mode + x = self.patches_to_video(x) + return x + + +class DerivativeFlowGenerator(nn.Module): + """Estimate flow of a two-frame predictor using torch autograd""" + + def __init__(self, + predictor, + perturbation_patch_size=None, + aggregation_patch_size=None, + agg_power=None, + agg_channel_func=None, + num_samples=1, + leave_one_out_sampling=False, + average_jacobian=True, + confidence_thresh=None, + temporal_dim=2, + imagenet_normalize_inputs=True): + + super(DerivativeFlowGenerator, self).__init__() + + self.predictor = predictor + + self.patchify = Patchify(self.patch_size, temporal_dim=1, squeeze_channel_dim=True) + + self.set_temporal_dim(temporal_dim) + + self.imagenet_normalize_inputs = imagenet_normalize_inputs + + self.perturbation_patch_size = self._get_patch_size(perturbation_patch_size) or self.patch_size + self.aggregation_patch_size = self._get_patch_size(aggregation_patch_size) or self.patch_size + self.agg_patchify = Patchify(self.aggregation_patch_size, + temporal_dim=1, + squeeze_channel_dim=False) + self.agg_channel_func = agg_channel_func or (lambda x: F.relu(x).sum(-3, True)) + self.average_jacobian = average_jacobian + self.confidence_thresh = confidence_thresh + + self.num_samples = num_samples + self.leave_one_out_sampling = leave_one_out_sampling + self.agg_power = agg_power + self.t_dim = temporal_dim + + def _get_patch_size(self, p): + if p is None: + return None + elif isinstance(p, int): + return (1, p, p) + elif len(p) == 2: + return (1, p[0], p[1]) + else: + assert len(p) == 3, p + return (p[0], p[1], p[2]) + + def set_temporal_dim(self, t_dim): + if t_dim == 1: + self.predictor.t_dim = 1 + self.predictor.c_dim = 2 + elif t_dim == 2: + self.predictor.c_dim = 1 + self.predictor.t_dim = 2 + else: + raise ValueError("temporal_dim must be 1 or 2") + + @property + def c_dim(self): + if self.predictor is None: + return None + return self.predictor.c_dim + + @property + def patch_size(self): + if self.predictor is None: + return None + elif hasattr(self.predictor, 'patch_size'): + return self.predictor.patch_size + elif hasattr(self.predictor.encoder.patch_embed, 'proj'): + return self.predictor.encoder.patch_embed.proj.kernel_size + else: + return None + @property + def S(self): + return self.num_samples + + @property + def sequence_length(self): + if self.predictor is None: + return None + elif hasattr(self.predictor, 'sequence_length'): + return self.predictor.sequence_length + elif hasattr(self.predictor, 'num_frames'): + return self.predictor.num_frames + else: + return 2 + @property + def mask_shape(self): + if self.predictor is None: + return None + elif hasattr(self.predictor, 'mask_shape'): + return self.predictor.mask_shape + + assert self.patch_size is not None + pt, ph, pw = self.patch_size + return (self.sequence_length // pt, + self.inp_shape[-2] // ph, + self.inp_shape[-1] // pw) + + @property + def perturbation_mask_shape(self): + return ( + self.mask_shape[0], + self.inp_shape[-2] // self.perturbation_patch_size[-2], + self.inp_shape[-1] // self.perturbation_patch_size[-1] + ) + + + + @property + def p_mask_shape(self): + return self.perturbation_mask_shape + + @property + def aggregation_mask_shape(self): + return ( + 1, + self.inp_shape[-2] // self.aggregation_patch_size[-2], + self.inp_shape[-1] // self.aggregation_patch_size[-1] + ) + + @property + def a_mask_shape(self): + return self.aggregation_mask_shape + + def get_perturbation_input(self, x): + self.set_input(x) + y = torch.zeros((self.B, *self.p_mask_shape), dtype=x.dtype, device=x.device, requires_grad=True) + y = y.unsqueeze(2).repeat(1, 1, x.shape[2], 1, 1) + return y + + def pred_patches_to_video(self, y, x, mask): + """input at visible positions, preds at masked positions""" + B, C = y.shape[0], y.shape[-1] + self.patchify._check_shape(x) + self.patchify.D = np.prod(self.patch_size) + x = self.patchify(x) + y_out = torch.zeros_like(x) + x_vis = x[~mask] + + y_out[~mask] = x_vis.view(-1, C) + try: + y_out[mask] = y.view(-1, C) + except: + y_out[mask] = y.reshape(-1, C) + + return self.patchify(y_out, to_video=True) + + def set_image_size(self, *args, **kwargs): + assert self.predictor is not None, "Can't set the image size without a predictor" + if hasattr(self.predictor, 'set_image_size'): + self.predictor.set_image_size(*args, **kwargs) + else: + self.predictor.image_size = args[0] + + def predict(self, x=None, mask=None, forward_full=False): + if x is None: + x = self.x + if mask is None: + mask = self.generate_mask(x) + + self.set_image_size(x.shape[-2:]) + y = self.predictor( + self._preprocess(x), + mask if (x.size(0) == 1) else self.mask_rectangularizer(mask), forward_full=forward_full) + + y = self.pred_patches_to_video(y, x, mask=mask) + + frame = -1 % y.size(1) + y = y[:, frame:frame + 1] + + return y + + def _get_perturbation_func(self, x=None, mask=None): + + if (x is not None): + self.set_input(x, mask) + + def forward_mini_image(y): + y = y.repeat_interleave(self.perturbation_patch_size[-2], -2) + y = y.repeat_interleave(self.perturbation_patch_size[-1], -1) + x_pred = self.predict(self.x + y, self.mask) + x_pred = self.agg_patchify(x_pred).mean(-2).sum(-1).view(self.B, *self.a_mask_shape) + return x_pred[self.targets] + + return forward_mini_image + + def _postprocess_jacobian(self, jac): + _jac = torch.zeros((self.B, *self.a_mask_shape, *jac.shape[1:])).to(jac.device).to(jac.dtype) + _jac[self.targets] = jac + jac = self.agg_channel_func(_jac) + assert jac.size(-3) == 1, jac.shape + jac = jac.squeeze(-3)[..., 0, :, :] # derivative w.r.t. first frame and agg channels + jac = jac.view(self.B, self.a_mask_shape[-2], self.a_mask_shape[-1], + self.B, self.p_mask_shape[-2], self.p_mask_shape[-1]) + bs = torch.arange(0, self.B).long().to(jac.device) + jac = jac[bs, :, :, bs, :, :] # take diagonal + return jac + + def _confident_jacobian(self, jac): + if self.confidence_thresh is None: + return torch.ones_like(jac[:, None, ..., 0, 0]) + conf = (jac.amax((-2, -1)) > self.confidence_thresh).float()[:, None] + return conf + + def set_input(self, x, mask=None, timestamps=None): + shape = x.shape + if len(shape) == 4: + x = x.unsqueeze(1) + else: + assert len(shape) == 5, \ + "Input must be a movie of shape [B,T,C,H,W]" + \ + "or a single frame of shape [B,C,H,W]" + + self.inp_shape = x.shape + self.x = x + self.B = self.inp_shape[0] + self.T = self.inp_shape[1] + self.C = self.inp_shape[2] + if mask is not None: + self.mask = mask + + if timestamps is not None: + self.timestamps = timestamps + + def _preprocess(self, x): + if self.imagenet_normalize_inputs: + x = imagenet_normalize(x) + if self.t_dim != 1: + x = x.transpose(self.t_dim, self.c_dim) + return x + + def _jacobian_to_flows(self, jac): + if self.agg_power is None: + jac = (jac == jac.amax((-2, -1), True)).float() + else: + jac = torch.pow(jac, self.agg_power) + + jac = jac.view(self.B * np.prod(self.a_mask_shape[-2:]), 1, 1, *self.p_mask_shape[-2:]) + centroids = get_distribution_centroid(jac, normalize=False).view( + self.B, self.a_mask_shape[-2], self.a_mask_shape[-1], 2) + rescale = [self.a_mask_shape[-2] / self.p_mask_shape[-2], + self.a_mask_shape[-1] / self.p_mask_shape[-1]] + centroids = centroids * torch.tensor(rescale, device=centroids.device).view(1, 1, 1, 2) + + flows = centroids - \ + coordinate_ims(1, 0, self.a_mask_shape[-2:], normalize=False).to(jac.device) + flows = flows.permute(0, 3, 1, 2) + px_scale = torch.tensor(self.aggregation_patch_size[-2:]).float().to(flows.device).view(1, 2, 1, 1) + flows *= px_scale + + return flows + + def set_targets(self, targets=None, frame=-1): + frame = frame % self.mask_shape[0] + if targets is None: + targets = self.get_mask_image(self.mask)[:, frame:frame + 1] + else: + assert len(targets.shape) == 4, targets.shape + targets = targets[:, frame:frame + 1] + self.targets = ~masking.upsample_masks(~targets, self.a_mask_shape[-2:]) + + def _get_mask_partition(self, mask): + mask = self.get_mask_image(mask) + mask_list = masking.partition_masks( + mask[:, 1:], num_samples=self.S, leave_one_out=self.leave_one_out_sampling) + return [torch.cat([mask[:, 0:1].view(m.size(0), -1), m], -1) + for m in mask_list] + + def _compute_jacobian(self, y): + perturbation_func = self._get_perturbation_func() + jac = torch.autograd.functional.jacobian( + perturbation_func, + y, + vectorize=False) + jac = self._postprocess_jacobian(jac) + return jac + + def _upsample_mask(self, mask): + return masking.upsample_masks( + mask.view(mask.size(0), -1, *self.mask_shape[-2:]).float(), self.inp_shape[-2:]) + + def get_mask_image(self, mask, upsample=False, invert=False, shape=None): + if shape is None: + shape = self.mask_shape + mask = mask.view(-1, *shape) + if upsample: + mask = self._upsample_mask(mask) + if invert: + mask = 1 - mask + return mask + + def forward(self, x, mask, targets=None): + self.set_input(x, mask) + y = self.get_perturbation_input(x) + mask_list = self._get_mask_partition(mask) + + jacobian, flows, confident = [], [], [] + for s, mask_sample in enumerate(mask_list): + self.set_input(x, mask_sample) + self.set_targets(targets) + + import time + t1 = time.time() + jac = self._compute_jacobian(y) + conf_jac = masking.upsample_masks(self._confident_jacobian(jac), self.a_mask_shape[-2:]) + jacobian.append(jac) + confident.append(conf_jac) + if not self.average_jacobian: + flow = self._jacobian_to_flows(jac) * self.targets * conf_jac * \ + masking.upsample_masks(self.get_mask_image(self.mask)[:, 1:], self.a_mask_shape[-2:]) + flows.append(flow) + t2 = time.time() + print(t2 - t1) + + jacobian = torch.stack(jacobian, -1) + confident = torch.stack(confident, -1) + valid = torch.stack([masking.upsample_masks( + self.get_mask_image(m)[:, 1:], self.a_mask_shape[-2:]) for m in mask_list], -1) + valid = valid * confident + + if self.average_jacobian: + _valid = valid[:, 0].unsqueeze(-2).unsqueeze(-2) + jac = (jacobian * _valid.float()).sum(-1) / _valid.float().sum(-1).clamp(min=1) + flows = self._jacobian_to_flows(jac) * \ + masking.upsample_masks(_valid[:, None, ..., 0, 0, :].amax(-1).bool(), self.a_mask_shape[-2:]) + if targets is not None: + self.set_targets(targets) + flows *= self.targets + else: + flows = torch.stack(flows, -1) + flows = flows.sum(-1) / valid.float().sum(-1).clamp(min=1) + + valid = valid * (targets[:, -1:].unsqueeze(-1) if targets is not None else 1) + + return (jacobian, flows, valid) \ No newline at end of file diff --git a/cwm/eval/Flow/losses.py b/cwm/eval/Flow/losses.py new file mode 100644 index 0000000000000000000000000000000000000000..25ee0ea28deb584aba156b9d91264aab29dac8dd --- /dev/null +++ b/cwm/eval/Flow/losses.py @@ -0,0 +1,60 @@ +import torch +import torch.nn.functional as F +from torchvision import transforms + + +def sampling_grid(height, width): + H, W = height, width + grid = torch.stack([ + torch.arange(W).view(1, -1).repeat(H, 1), + torch.arange(H).view(-1, 1).repeat(1, W) + ], -1) + grid = grid.view(1, H, W, 2) + return grid + + +def normalize_sampling_grid(coords): + assert len(coords.shape) == 4, coords.shape + assert coords.size(-1) == 2, coords.shape + H, W = coords.shape[-3:-1] + xs, ys = coords.split([1, 1], -1) + xs = 2 * xs / (W - 1) - 1 + ys = 2 * ys / (H - 1) - 1 + return torch.cat([xs, ys], -1) + + +def backward_warp(img2, flow, do_mask=False): + """ + Grid sample from img2 using the flow from img1->img2 to get a prediction of img1. + + flow: [B,2,H',W'] in units of pixels at its current resolution. The two channels + should be (x,y) where larger y values correspond to lower parts of the image. + """ + + ## resize the flow to the image size. + ## since flow has units of pixels, its values need to be rescaled accordingly. + if list(img2.shape[-2:]) != list(flow.shape[-2:]): + scale = [img2.size(-1) / flow.size(-1), # x + img2.size(-2) / flow.size(-2)] # y + scale = torch.tensor(scale).view(1, 2, 1, 1).to(flow.device) + flow = scale * transforms.Resize(img2.shape[-2:])(flow) # defaults to bilinear + + B, C, H, W = img2.shape + + ## use flow to warp sampling grid + grid = sampling_grid(H, W).to(flow.device) + flow.permute(0, 2, 3, 1) + + ## put grid in normalized image coordinates + grid = normalize_sampling_grid(grid) + + ## backward warp, i.e. sample pixel (x,y) from (x+flow_x, y+flow_y) + img1_pred = F.grid_sample(img2, grid, align_corners=True) + + if do_mask: + mask = (grid[..., 0] > -1) & (grid[..., 0] < 1) & \ + (grid[..., 1] > -1) & (grid[..., 1] < 1) + mask = mask[:, None].to(img2.dtype) + return (img1_pred, mask) + + else: + return (img1_pred, torch.ones_like(grid[..., 0][:, None]).float()) diff --git a/cwm/eval/Flow/masking_flow.py b/cwm/eval/Flow/masking_flow.py new file mode 100644 index 0000000000000000000000000000000000000000..650250d7b8e741154435ff675a3b703bf6990847 --- /dev/null +++ b/cwm/eval/Flow/masking_flow.py @@ -0,0 +1,375 @@ +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +import torchvision.transforms as transforms + +def upsample_masks(masks, size, thresh=0.5): + shape = masks.shape + dtype = masks.dtype + h, w = shape[-2:] + H, W = size + if (H == h) and (W == w): + return masks + elif (H < h) and (W < w): + s = (h // H, w // W) + return masks[..., ::s[0], ::s[1]] + + masks = masks.unsqueeze(-2).unsqueeze(-1) + masks = masks.repeat(*([1] * (len(shape) - 2)), 1, H // h, 1, W // w) + if ((H % h) == 0) and ((W % w) == 0): + masks = masks.view(*shape[:-2], H, W) + else: + _H = np.prod(masks.shape[-4:-2]) + _W = np.prod(masks.shape[-2:]) + masks = transforms.Resize(size)(masks.view(-1, 1, _H, _W)) > thresh + masks = masks.view(*shape[:2], H, W).to(masks.dtype) + return masks + + + + +def partition_masks(masks, num_samples=2, leave_one_out=False): + B = masks.shape[0] + S = num_samples + masks = masks.view(B, -1) + partitioned = [torch.ones_like(masks) for _ in range(S)] + for b in range(B): + vis_inds = torch.where(~masks[b])[0] + vis_inds = vis_inds[torch.randperm(vis_inds.size(0))] + if leave_one_out: + for s in range(S): + partitioned[s][b][vis_inds] = 0 + partitioned[s][b][vis_inds[s::S]] = 1 + else: + for s in range(S): + partitioned[s][b][vis_inds[s::S]] = 0 + return partitioned + + +class RectangularizeMasks(nn.Module): + """Make sure all masks in a batch have same number of 1s and 0s""" + + def __init__(self, truncation_mode='min'): + super().__init__() + self._mode = truncation_mode + assert self._mode in ['min', 'max', 'mean', 'full', 'none', None], (self._mode) + + def set_mode(self, mode): + self._mode = mode + + def __call__(self, masks): + + if self._mode in ['none', None]: + return masks + + assert isinstance(masks, torch.Tensor), type(masks) + if self._mode == 'full': + return torch.ones_like(masks) + + shape = masks.shape + masks = masks.flatten(1) + B, N = masks.shape + num_masked = masks.float().sum(-1) + M = { + 'min': torch.amin, 'max': torch.amax, 'mean': torch.mean + }[self._mode](num_masked).long() + + num_changes = num_masked.long() - M + + for b in range(B): + nc = num_changes[b] + if nc > 0: + inds = torch.where(masks[b])[0] + inds = inds[torch.randperm(inds.size(0))[:nc].to(inds.device)] + masks[b, inds] = 0 + elif nc < 0: + inds = torch.where(~masks[b])[0] + inds = inds[torch.randperm(inds.size(0))[:-nc].to(inds.device)] + masks[b, inds] = 1 + if list(masks.shape) != list(shape): + masks = masks.view(*shape) + + return masks + + +class UniformMaskingGenerator(object): + def __init__(self, input_size, mask_ratio, seed=None, clumping_factor=1, randomize_num_visible=False): + self.frames = None + if len(input_size) == 3: + self.frames, self.height, self.width = input_size + elif len(input_size) == 2: + self.height, self.width = input_size + elif len(input_size) == 1 or isinstance(input_size, int): + self.height = self.width = input_size + + self.clumping_factor = clumping_factor + self.pad_h = self.height % self.c[0] + self.pad_w = self.width % self.c[1] + self.num_patches_per_frame = (self.height // self.c[0]) * (self.width // self.c[1]) + self.mask_ratio = mask_ratio + + self.rng = np.random.RandomState(seed=seed) + self.randomize_num_visible = randomize_num_visible + + @property + def num_masks_per_frame(self): + if not hasattr(self, '_num_masks_per_frame'): + self._num_masks_per_frame = int(self.mask_ratio * self.num_patches_per_frame) + return self._num_masks_per_frame + + @num_masks_per_frame.setter + def num_masks_per_frame(self, val): + self._num_masks_per_frame = val + self._mask_ratio = (val / self.num_patches_per_frame) + + @property + def c(self): + if isinstance(self.clumping_factor, int): + return (self.clumping_factor, self.clumping_factor) + else: + return self.clumping_factor[:2] + + @property + def mask_ratio(self): + return self._mask_ratio + + @mask_ratio.setter + def mask_ratio(self, val): + self._mask_ratio = val + self._num_masks_per_frame = int(self._mask_ratio * self.num_patches_per_frame) + + @property + def num_visible(self): + return self.num_patches_per_frame - self.num_masks_per_frame + + @num_visible.setter + def num_visible(self, val): + self.num_masks_per_frame = self.num_patches_per_frame - val + + def __repr__(self): + repr_str = "Mask: total patches per frame {}, mask patches per frame {}, mask ratio {}, random num num visible? {}".format( + self.num_patches_per_frame, self.num_masks_per_frame, self.mask_ratio, self.randomize_num_visible + ) + return repr_str + + def sample_mask_per_frame(self): + num_masks = self.num_masks_per_frame + if self.randomize_num_visible: + num_masks = self.rng.randint(low=num_masks, high=(self.num_patches_per_frame + 1)) + mask = np.hstack([ + np.zeros(self.num_patches_per_frame - num_masks), + np.ones(num_masks)]) + self.rng.shuffle(mask) + if max(*self.c) > 1: + mask = mask.reshape(self.height // self.c[0], + 1, + self.width // self.c[1], + 1) + mask = np.tile(mask, (1, self.c[0], 1, self.c[1])) + mask = mask.reshape((self.height - self.pad_h, self.width - self.pad_w)) + _pad_h = self.rng.choice(range(self.pad_h + 1)) + pad_h = (self.pad_h - _pad_h, _pad_h) + _pad_w = self.rng.choice(range(self.pad_w + 1)) + pad_w = (self.pad_w - _pad_w, _pad_w) + mask = np.pad(mask, + (pad_h, pad_w), + constant_values=1 + ).reshape((self.height, self.width)) + return mask + + def __call__(self, num_frames=None): + num_frames = (num_frames or self.frames) or 1 + masks = np.stack([self.sample_mask_per_frame() for _ in range(num_frames)]).flatten() + return masks + + +class TubeMaskingGenerator(UniformMaskingGenerator): + + def __call__(self, num_frames=None): + num_frames = (num_frames or self.frames) or 1 + masks = np.tile(self.sample_mask_per_frame(), (num_frames, 1)).flatten() + return masks + + +class RotatedTableMaskingGenerator(TubeMaskingGenerator): + + def __init__(self, tube_length=None, *args, **kwargs): + super(RotatedTableMaskingGenerator, self).__init__(*args, **kwargs) + self.tube_length = tube_length + + def __call__(self, num_frames=None): + num_frames = (num_frames or self.frames) or 2 + tube_length = self.tube_length or (num_frames - 1) + table_thickness = num_frames - tube_length + assert tube_length < num_frames, (tube_length, num_frames) + + tubes = super().__call__(num_frames=tube_length) + top = np.zeros(table_thickness * self.height * self.width).astype(tubes.dtype).flatten() + masks = np.concatenate([top, tubes], 0) + return masks + + +class PytorchMaskGeneratorWrapper(nn.Module): + """Pytorch wrapper for numpy masking generators""" + + def __init__(self, + mask_generator=TubeMaskingGenerator, + *args, **kwargs): + super().__init__() + self.mask_generator = mask_generator(*args, **kwargs) + + @property + def mask_ratio(self): + return self.mask_generator.mask_ratio + + @mask_ratio.setter + def mask_ratio(self, value): + self.mask_generator.mask_ratio = value + + def forward(self, device='cuda', dtype_out=torch.bool, **kwargs): + masks = self.mask_generator(**kwargs) + masks = torch.tensor(masks).to(device).to(dtype_out) + return masks + + +class MaskingGenerator(nn.Module): + """Pytorch base class for masking generators""" + + def __init__(self, + input_size, + mask_ratio, + seed=0, + visible_frames=0, + clumping_factor=1, + randomize_num_visible=False, + create_on_cpu=True, + always_batch=False): + super().__init__() + self.frames = None + + if len(input_size) == 3: + self.frames, self.height, self.width = input_size + elif len(input_size) == 2: + self.height, self.width = input_size + elif len(input_size) == 1 or isinstance(input_size, int): + self.height = self.width = input_size + + self.clumping_factor = clumping_factor + self.pad_h = self.height % self.c[0] + self.pad_w = self.width % self.c[1] + self.num_patches_per_frame = (self.height // self.c[0]) * (self.width // self.c[1]) + + self.mask_ratio = mask_ratio + self.visible_frames = visible_frames + self.always_batch = always_batch + self.create_on_cpu = create_on_cpu + + self.rng = np.random.RandomState(seed=seed) + self._set_torch_seed(seed) + + self.randomize_num_visible = randomize_num_visible + + @property + def num_masks_per_frame(self): + if not hasattr(self, '_num_masks_per_frame'): + self._num_masks_per_frame = int(self.mask_ratio * self.num_patches_per_frame) + return self._num_masks_per_frame + + @num_masks_per_frame.setter + def num_masks_per_frame(self, val): + self._num_masks_per_frame = val + self._mask_ratio = (val / self.num_patches_per_frame) + + @property + def c(self): + if isinstance(self.clumping_factor, int): + return (self.clumping_factor,) * 2 + else: + return self.clumping_factor[:2] + + @property + def mask_ratio(self): + return self._mask_ratio + + @mask_ratio.setter + def mask_ratio(self, val): + self._mask_ratio = val + self._num_masks_per_frame = int(self._mask_ratio * self.num_patches_per_frame) + + @property + def num_visible(self): + return self.num_patches_per_frame - self.num_masks_per_frame + + @num_visible.setter + def num_visible(self, val): + self.num_masks_per_frame = self.num_patches_per_frame - val + + def _set_torch_seed(self, seed): + self.seed = seed + torch.manual_seed(self.seed) + + def __repr__(self): + repr_str = ("Class: {}\nMask: total patches per mask {},\n" + \ + "mask patches per mask {}, visible patches per mask {}, mask ratio {:0.3f}\n" + \ + "randomize num visible? {}").format( + type(self).__name__, self.num_patches_per_frame, + self.num_masks_per_frame, self.num_visible, self.mask_ratio, + self.randomize_num_visible + ) + return repr_str + + def sample_mask_per_frame(self, *args, **kwargs): + num_masks = self.num_masks_per_frame + if self.randomize_num_visible: + num_masks = self.rng.randint(low=num_masks, high=(self.num_patches_per_frame + 1)) + + mask = torch.cat([ + torch.zeros([self.num_patches_per_frame - num_masks]), + torch.ones([num_masks])], 0).bool() + inds = torch.randperm(mask.size(0)).long() + mask = mask[inds] + + if max(*self.c) > 1: + mask = mask.view(self.height // self.c[0], + 1, + self.width // self.c[1], + 1) + mask = torch.tile(mask, (1, self.c[0], 1, self.c[1])) + mask = mask.reshape(self.height - self.pad_h, self.width - self.pad_w) + _pad_h = self.rng.choice(range(self.pad_h + 1)) + pad_h = (self.pad_h - _pad_h, _pad_h) + _pad_w = self.rng.choice(range(self.pad_w + 1)) + pad_w = (self.pad_w - _pad_w, _pad_w) + mask = F.pad(mask, + pad_w + pad_h, + mode='constant', + value=1) + mask = mask.reshape(self.height, self.width) + + return mask + + def forward(self, x=None, num_frames=None): + + num_frames = (num_frames or self.frames) or 1 + if isinstance(x, torch.Tensor): + batch_size = x.size(0) + masks = torch.stack([ + torch.cat([self.sample_mask_per_frame() for _ in range(num_frames)], 0).flatten() + for b in range(batch_size)], 0) + if not self.create_on_cpu: + masks = masks.to(x.device) + if batch_size == 1 and not self.always_batch: + masks = masks.squeeze(0) + else: + batch_size = 1 + masks = torch.cat([self.sample_mask_per_frame() for _ in range(num_frames)], 0).flatten() + if self.always_batch: + masks = masks[None] + + if self.visible_frames > 0: + vis = torch.zeros((batch_size, 1, self.height, self.width), dtype=torch.bool) + vis = vis.view(masks.shape).to(masks.device) + masks = torch.cat(([vis] * self.visible_frames) + [masks], -1) + + return masks diff --git a/cwm/eval/Flow/vis_utils.py b/cwm/eval/Flow/vis_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..e2767b1c3d84b9f4ed1382463106f9de96003f8c --- /dev/null +++ b/cwm/eval/Flow/vis_utils.py @@ -0,0 +1,150 @@ +import matplotlib.pyplot as plt +import numpy as np +import torch + + +def imshow(ims, ax=None, t=0, vmin=None, vmax=None, title=None, cmap=None, fontsize=20): + if ax is None: + fig, ax = plt.subplots(1,1) + with torch.no_grad(): + im = ims[t].float().cpu().numpy().transpose((1,2,0)) + if (vmin is not None) and (vmax is not None): + im =ax.imshow(im, vmin=vmin, vmax=vmax, cmap=(cmap or 'viridis')) + else: + im =ax.imshow(im) + + if title is not None: + ax.set_title(title, fontsize=fontsize) + + return (im, ax) + +def make_colorwheel(): + """ + Generates a color wheel for optical flow visualization as presented in: + Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007) + URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf + + Code follows the original C++ source code of Daniel Scharstein. + Code follows the the Matlab source code of Deqing Sun. + + Returns: + np.ndarray: Color wheel + """ + + RY = 15 + YG = 6 + GC = 4 + CB = 11 + BM = 13 + MR = 6 + + ncols = RY + YG + GC + CB + BM + MR + colorwheel = np.zeros((ncols, 3)) + col = 0 + + # RY + colorwheel[0:RY, 0] = 255 + colorwheel[0:RY, 1] = np.floor(255*np.arange(0,RY)/RY) + col = col+RY + # YG + colorwheel[col:col+YG, 0] = 255 - np.floor(255*np.arange(0,YG)/YG) + colorwheel[col:col+YG, 1] = 255 + col = col+YG + # GC + colorwheel[col:col+GC, 1] = 255 + colorwheel[col:col+GC, 2] = np.floor(255*np.arange(0,GC)/GC) + col = col+GC + # CB + colorwheel[col:col+CB, 1] = 255 - np.floor(255*np.arange(CB)/CB) + colorwheel[col:col+CB, 2] = 255 + col = col+CB + # BM + colorwheel[col:col+BM, 2] = 255 + colorwheel[col:col+BM, 0] = np.floor(255*np.arange(0,BM)/BM) + col = col+BM + # MR + colorwheel[col:col+MR, 2] = 255 - np.floor(255*np.arange(MR)/MR) + colorwheel[col:col+MR, 0] = 255 + return colorwheel + + +def flow_uv_to_colors(u, v, convert_to_bgr=False): + """ + Applies the flow color wheel to (possibly clipped) flow components u and v. + + According to the C++ source code of Daniel Scharstein + According to the Matlab source code of Deqing Sun + + Args: + u (np.ndarray): Input horizontal flow of shape [H,W] + v (np.ndarray): Input vertical flow of shape [H,W] + convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False. + + Returns: + np.ndarray: Flow visualization image of shape [H,W,3] + """ + flow_image = np.zeros((u.shape[0], u.shape[1], 3), np.uint8) + colorwheel = make_colorwheel() # shape [55x3] + ncols = colorwheel.shape[0] + rad = np.sqrt(np.square(u) + np.square(v)) + a = np.arctan2(-v, -u)/np.pi + fk = (a+1) / 2*(ncols-1) + k0 = np.floor(fk).astype(np.int32) + k1 = k0 + 1 + k1[k1 == ncols] = 0 + f = fk - k0 + for i in range(colorwheel.shape[1]): + tmp = colorwheel[:,i] + col0 = tmp[k0] / 255.0 + col1 = tmp[k1] / 255.0 + col = (1-f)*col0 + f*col1 + idx = (rad <= 1) + col[idx] = 1 - rad[idx] * (1-col[idx]) + col[~idx] = col[~idx] * 0.75 # out of range + # Note the 2-i => BGR instead of RGB + ch_idx = 2-i if convert_to_bgr else i + flow_image[:,:,ch_idx] = np.floor(255 * col) + return flow_image + + +def flow_to_image(flow_uv, clip_flow=None, convert_to_bgr=False): + """ + Expects a two dimensional flow image of shape. + + Args: + flow_uv (np.ndarray): Flow UV image of shape [H,W,2] + clip_flow (float, optional): Clip maximum of flow values. Defaults to None. + convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False. + + Returns: + np.ndarray: Flow visualization image of shape [H,W,3] + """ + assert flow_uv.ndim == 3, 'input flow must have three dimensions' + assert flow_uv.shape[2] == 2, 'input flow must have shape [H,W,2]' + if clip_flow is not None: + flow_uv = np.clip(flow_uv, 0, clip_flow) + u = flow_uv[:,:,0] + v = flow_uv[:,:,1] + rad = np.sqrt(np.square(u) + np.square(v)) + rad_max = np.max(rad) + epsilon = 1e-5 + u = u / (rad_max + epsilon) + v = v / (rad_max + epsilon) + return flow_uv_to_colors(u, v, convert_to_bgr) + +from decord import VideoReader, cpu +from PIL import Image +from torchvision import transforms +def get_video(video_name, num_frames=2, delta_time=4, frame=None): + decord_vr = VideoReader(video_name, num_threads=1, ctx=cpu(0)) + max_end_ind = len(decord_vr) - num_frames*delta_time - 1 + start_frame = frame if frame is not None else rng.randint(1, max_end_ind) + print("fps", decord_vr.get_avg_fps()) + print("start frame = %d" % start_frame) + frame_id_list = list(range(start_frame, start_frame + num_frames*delta_time, delta_time)) + video_data = decord_vr.get_batch(frame_id_list).asnumpy() + video_data = [Image.fromarray(video_data[t]).convert('RGB') for t, _ in enumerate(frame_id_list)] + return (torch.stack([transforms.ToTensor()(im) for im in video_data], 0), start_frame) + + + diff --git a/cwm/eval/IntPhys/__init__.py b/cwm/eval/IntPhys/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Physion/__init__.py b/cwm/eval/Physion/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Physion/feature_extractor.py b/cwm/eval/Physion/feature_extractor.py new file mode 100644 index 0000000000000000000000000000000000000000..e050ff61cf27102fb34093da708f4ad40a359b5e --- /dev/null +++ b/cwm/eval/Physion/feature_extractor.py @@ -0,0 +1,317 @@ +import numpy as np +from physion_evaluator.feature_extract_interface import PhysionFeatureExtractor +from physion_evaluator.utils import DataAugmentationForVideoMAE + +from torch.functional import F + +from cwm.eval.Flow.flow_utils import get_occ_masks + +from cwm.model.model_factory import model_factory +import torch + +def load_predictor( + model_func_, + load_path_, + **kwargs): + predictor = model_func_(**kwargs).eval().requires_grad_(False) + + did_load = predictor.load_state_dict( + torch.load(load_path_, map_location=torch.device("cpu"))['model']) + predictor._predictor_load_path = load_path_ + print(did_load, load_path_) + return predictor + + +class CWM(PhysionFeatureExtractor): + def __init__(self, model_name, aggregate_embeddings=False): + super().__init__() + + self.model = model_factory.load_model(model_name).cuda().half() + + self.num_frames = self.model.num_frames + + self.timestamps = np.arange(self.num_frames) + + ps = (224 // self.model.patch_size[1]) ** 2 + + self.bool_masked_pos = np.zeros([ps * self.num_frames]) + self.bool_masked_pos[ps * (self.num_frames - 1):] = 1 + + self.ps = ps + + self.aggregate_embeddings = aggregate_embeddings + + def transform(self): + + return DataAugmentationForVideoMAE( + imagenet_normalize=True, + rescale_size=224, + ), 150, 4 + + def fwd(self, videos): + bool_masked_pos = torch.tensor(self.bool_masked_pos).to(videos.device).unsqueeze(0).bool() + bool_masked_pos = torch.cat([bool_masked_pos] * videos.shape[0]) + x_encoded = self.model(videos.half(), bool_masked_pos, forward_full=True, + return_features=True) + return x_encoded + + def extract_features(self, videos, for_flow=False): + ''' + videos: [B, T, C, H, W], T is usually 4 and videos are normalized with imagenet norm + returns: [B, T, D] extracted features + ''' + + videos = videos.transpose(1, 2) + + all_features = [] + + # repeat the last frame of the video + videos = torch.cat([videos, videos[:, :, -1:]], dim=2) + + for x in range(0, 4, self.num_frames - 1): + vid = videos[:, :, x:x + self.num_frames, :, :] + all_features.append(self.fwd(vid)) + if self.aggregate_embeddings: + feats = all_features[-1].mean(dim=1, keepdim=True) + all_features[-1] = feats + # feats = feats.view(feats.shape[0], -1, self.model.num_patches_per_frame, feats.shape[-1]) + # feats = feats.mean(dim=2) + # all_features[-1] = feats + + x_encoded = torch.cat(all_features, dim=1) + + return x_encoded + + +class CWM_Keypoints(PhysionFeatureExtractor): + def __init__(self, model_name): + super().__init__() + + self.model = model_factory.load_model(model_name).cuda().half() + + self.frames = [[0, 1, 2], [1, 2, 3]] + + self.num_frames = self.model.num_frames + + self.ps = (224 // self.model.patch_size[1]) ** 2 + + self.bool_masked_pos = np.zeros([self.ps * self.num_frames]) + self.bool_masked_pos[self.ps * (self.num_frames - 1):] = 1 + + self.frame_gap = 150 + + self.num_frames_dataset = 4 + + self.res = 224 + + + def transform(self): + + return DataAugmentationForVideoMAE( + imagenet_normalize=True, + rescale_size=self.res, + ), self.frame_gap, self.num_frames_dataset + + def fwd(self, videos): + bool_masked_pos = torch.tensor(self.bool_masked_pos).to(videos.device).unsqueeze(0).bool() + bool_masked_pos = torch.cat([bool_masked_pos] * videos.shape[0]) + _, x_encoded = self.model(videos.half(), bool_masked_pos, forward_full=True, + return_features=True) + return x_encoded + + def extract_features(self, videos, segments=None): + ''' + videos: [B, T, C, H, W], T is usually 4 and videos are normalized with imagenet norm + returns: [B, T, D] extracted features + ''' + + videos = videos.transpose(1, 2) + + all_features = [] + + for x, arr in enumerate(self.frames): + + #use the downsampled videos for keypoints + vid = videos[:, :, arr, :, :].half() + frame0 = vid[:, :, 0] + frame1 = vid[:, :, 1] + frame2 = vid[:, :, 2] + + #extract features from the video frames frame0 and frame1 and include features at keypoint regions of frame2 + mask, choices, err_array, k_feat, keypoint_recon = self.model.get_keypoints(frame0, frame1, frame2, 10, 1) + + #reshape the features to [batch size, num_features] + k_feat = k_feat.view(k_feat.shape[0], -1) + + all_features.append(k_feat) + + x_encoded = torch.cat(all_features, dim=1) + + return x_encoded + + +class CWM_KeypointsFlow(PhysionFeatureExtractor): + def __init__(self, model_name): + super().__init__() + + self.model = model_factory.load_model(model_name).cuda().half() + + self.frames = [[0, 3, 6], [3, 6, 9], [6, 9, 9]] + + self.num_frames = self.model.num_frames + + self.timestamps = np.arange(self.num_frames) + + self.ps = (224 // self.model.patch_size[1]) ** 2 + + self.bool_masked_pos = np.zeros([self.ps * self.num_frames]) + self.bool_masked_pos[self.ps * (self.num_frames - 1):] = 1 + + self.frame_gap = 50 + + self.num_frames_dataset = 9 + + self.res = 512 + + def transform(self): + + return DataAugmentationForVideoMAE( + imagenet_normalize=True, + rescale_size=self.res, + ), self.frame_gap, self.num_frames_dataset + + def fwd(self, videos): + bool_masked_pos = torch.tensor(self.bool_masked_pos).to(videos.device).unsqueeze(0).bool() + bool_masked_pos = torch.cat([bool_masked_pos] * videos.shape[0]) + _, x_encoded = self.model(videos.half(), bool_masked_pos, forward_full=True, + return_features=True) + return x_encoded + + def get_forward_flow(self, videos): + + fid = 6 + + forward_flow = self.model.get_flow(videos[:, :, fid], videos[:, :, fid + 1], conditioning_img=videos[:, :, fid + 2], mode='cosine') + + backward_flow = self.model.get_flow(videos[:, :, fid + 1], videos[:, :, fid], conditioning_img=videos[:, :, fid - 1], mode='cosine') + + occlusion_mask = get_occ_masks(forward_flow, backward_flow)[0] + + forward_flow = forward_flow * occlusion_mask + + forward_flow = torch.stack([forward_flow, forward_flow, forward_flow], dim=1) + + forward_flow = forward_flow.to(videos.device) + + forward_flow = F.interpolate(forward_flow, size=(2, 224, 224), mode='nearest') + + return forward_flow + + def extract_features(self, videos, segments=None): + ''' + videos: [B, T, C, H, W], T is usually 4 and videos are normalized with imagenet norm + returns: [B, T, D] extracted features + Note: + For efficiency, the optical flow is computed and added for a single frame (300ms) as we found this to be sufficient + for capturing temporal dynamics in our experiments. This approach can be extended to multiple frames if needed, + depending on the complexity of the task. + ''' + + + #resize to 224 to get keypoints and features + videos_downsampled = F.interpolate(videos.flatten(0, 1), size=(224, 224), mode='bilinear', align_corners=False) + videos_downsampled = videos_downsampled.view(videos.shape[0], videos.shape[1], videos.shape[2], 224, 224) + + #for computing flow at higher resolution + videos_ = F.interpolate(videos.flatten(0, 1), size=(1024, 1024), mode='bilinear', align_corners=False) + videos = videos_.view(videos.shape[0], videos.shape[1], videos.shape[2], 1024, 1024) + + videos = videos.transpose(1, 2).half() + videos_downsampled = videos_downsampled.transpose(1, 2).half() + + # Get the forward flow for the frame at 300ms + forward_flow = self.get_forward_flow(videos) + + # Verify that there are no nans forward flow + assert not torch.isnan(forward_flow).any(), "Forward flow is nan" + + all_features = [] + + for x, arr in enumerate(self.frames): + + #use the downsampled videos for keypoints + vid = videos_downsampled[:, :, arr, :, :] + frame0 = vid[:, :, 0] + frame1 = vid[:, :, 1] + frame2 = vid[:, :, 2] + + #extract features from the video frames frame0 and frame1 and include features at keypoint regions of frame2 + mask, choices, err_array, k_feat, keypoint_recon = self.model.get_keypoints(frame0, frame1, frame2, 10, 1) + + #for the last set of frames only use features at keypoint regions of frame2 + if (x == 2): + k_feat = k_feat[:, -10:, :] + + #reshape the features to [batch size, num_features] + k_feat = k_feat.view(k_feat.shape[0], -1) + + choices_image_resolution = choices * self.model.patch_size[1] + + # At 300ms, add optical flow patches at the detected keypoint locations + # For the first frame (x == 0) + if x == 0: + # Extract the optical flow information from the forward flow matrix for the second channel (index 2) + flow_keyp = forward_flow[:, 2] + + # Initialize a result tensor to store the flow patches + # Tensor shape: [batch_size, 8x8 patch (flattened to 64) * 2 channels, 10 keypoints] + flow = torch.zeros(vid.shape[0], 8 * 8 * 2, 10).to(videos.device) + + # Patch size shift (since 8x8 patches are being extracted) + shift = 8 + + # Loop over each element in the batch to process individual video frames + for b in range(flow_keyp.size(0)): + # Extract the x and y coordinates of the keypoint locations for this batch element + x_indices = choices_image_resolution[b, :, 0] + y_indices = choices_image_resolution[b, :, 1] + + # For each keypoint (10 total keypoints in this case) + for ind in range(10): + # Extract the 8x8 patch of optical flow at each keypoint's (x, y) location + # Flatten the patch and assign it to the corresponding slice in the result tensor + flow[b, :, ind] = flow_keyp[b, :, y_indices[ind]:y_indices[ind] + shift, + x_indices[ind]:x_indices[ind] + shift].flatten() + + # Reshape the flow tensor for easier concatenation (flatten across all patches) + flow = flow.view(flow.shape[0], -1) + + # Concatenate the extracted optical flow features with the existing feature tensor (k_feat) + k_feat = torch.cat([k_feat, flow], dim=1) + + all_features.append(k_feat) + + x_encoded = torch.cat(all_features, dim=1) + + return x_encoded + + +class CWM_base_8x8_3frame(CWM): + def __init__(self,): + super().__init__('vitb_8x8patch_3frames') + +class CWM_base_8x8_3frame_mean_embed(CWM): + def __init__(self,): + super().__init__('vitb_8x8patch_3frames', aggregate_embeddings=True) + +# CWM* (keypoints only) 74.7 +class CWM_base_8x8_3frame_keypoints(CWM_Keypoints): + def __init__(self,): + super().__init__('vitb_8x8patch_3frames') + + +# CWM* (keypoints + Flow) 75.4 +class CWM_base_8x8_3frame_keypoints_flow(CWM_KeypointsFlow): + def __init__(self,): + super().__init__('vitb_8x8patch_3frames') + diff --git a/cwm/eval/Physion/flow_utils.py b/cwm/eval/Physion/flow_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..d7490805e601091e8c185dcc95fa047ce04ed331 --- /dev/null +++ b/cwm/eval/Physion/flow_utils.py @@ -0,0 +1,279 @@ + +import torch +import numpy as np +import random +import math + +def create_weighted_mask_batched(h, w): + y_mask = np.linspace(0, 1, h) + y_mask = np.minimum(y_mask, 1 - y_mask) + x_mask = np.linspace(0, 1, w) + x_mask = np.minimum(x_mask, 1 - x_mask) + weighted_mask = np.outer(y_mask, x_mask) + return torch.from_numpy(weighted_mask).float() + +def reconstruct_video_new_2_batched(cropped_tensors, crop_positions, original_shape): + B, T, C, H, W = original_shape + + # Initialize an empty tensor to store the reconstructed video + reconstructed_video = torch.zeros((B, T, C, H, W)).to(cropped_tensors[0].device) + + # Create a tensor to store the sum of weighted masks + weighted_masks_sum = torch.zeros((B, T, C, H, W)).to(cropped_tensors[0].device) + + # Create a weighted mask for the crops + weighted_mask = create_weighted_mask_batched(224, 224).to(cropped_tensors[0].device) + weighted_mask = weighted_mask[None, None, None, :, :] # Extend dimensions to match the cropped tensor. + + for idx, crop in enumerate(cropped_tensors): + start_h, start_w = crop_positions[idx] + + # Multiply the crop with the weighted mask + weighted_crop = crop * weighted_mask + + # Add the weighted crop to the corresponding location in the reconstructed_video tensor + reconstructed_video[:, :, :, start_h:(start_h + 224), start_w:(start_w + 224)] += weighted_crop + + # Update the weighted_masks_sum tensor + weighted_masks_sum[:, :, :, start_h:(start_h + 224), start_w:(start_w + 224)] += weighted_mask + + # Add a small epsilon value to avoid division by zero + epsilon = 1e-8 + + # Normalize the reconstructed video by dividing each pixel by its corresponding weighted_masks_sum value plus epsilon + reconstructed_video /= (weighted_masks_sum + epsilon) + + return reconstructed_video + +import torch.nn.functional as F + +resize = lambda x,a: F.interpolate(x, [int(a*x.shape[-2]), int(a*x.shape[-1])], mode='bilinear', align_corners=False) + +upsample = lambda x,H,W: F.interpolate(x, [int(H), int(W)], mode='bilinear', align_corners=False) + + + +# +def compute_optical_flow(embedding_tensor, mask_tensor, frame_size): + # Unroll the mask tensor and find the indices of the masked and unmasked values in the second frame + mask_unrolled = mask_tensor.view(-1) + + second_frame_unmask_indices = torch.where(mask_unrolled[frame_size**2:] == False)[0] + + # Divide the embedding tensor into two parts: corresponding to the first and the second frame + first_frame_embeddings = embedding_tensor[0, :frame_size**2, :] + second_frame_embeddings = embedding_tensor[0, frame_size**2:, :] + + # Compute the cosine similarity between the unmasked embeddings from the second frame and the embeddings from the first frame + dot_product = torch.matmul(second_frame_embeddings, first_frame_embeddings.T) + norms = torch.norm(second_frame_embeddings, dim=1)[:, None] * torch.norm(first_frame_embeddings, dim=1)[None, :] + cos_sim_matrix = dot_product / norms + + # Find the indices of pixels in the first frame that are most similar to each unmasked pixel in the second frame + first_frame_most_similar_indices = cos_sim_matrix.argmax(dim=-1) + + # Convert the 1D pixel indices into 2D coordinates + second_frame_y = second_frame_unmask_indices // frame_size + second_frame_x = second_frame_unmask_indices % frame_size + first_frame_y = first_frame_most_similar_indices // frame_size + first_frame_x = first_frame_most_similar_indices % frame_size + + # Compute the x and y displacements and convert them to float + displacements_x = (second_frame_x - first_frame_x).float() + displacements_y = (second_frame_y - first_frame_y).float() + + # Initialize optical flow tensor + optical_flow = torch.zeros((2, frame_size, frame_size), device=embedding_tensor.device) + + # Assign the computed displacements to the corresponding pixels in the optical flow tensor + optical_flow[0, second_frame_y, second_frame_x] = displacements_x + optical_flow[1, second_frame_y, second_frame_x] = displacements_y + + return optical_flow + +def get_minimal_224_crops_new_batched(video_tensor, N): + B, T, C, H, W = video_tensor.shape + + # Calculate the number of crops needed in both the height and width dimensions + num_crops_h = math.ceil(H / 224) if H > 224 else 1 + num_crops_w = math.ceil(W / 224) if W > 224 else 1 + + # Calculate the step size for the height and width dimensions + step_size_h = 0 if H <= 224 else max(0, (H - 224) // (num_crops_h - 1)) + step_size_w = 0 if W <= 224 else max(0, (W - 224) // (num_crops_w - 1)) + + # Create a list to store the cropped tensors and their start positions + cropped_tensors = [] + crop_positions = [] + + # Iterate over the height and width dimensions, extract the 224x224 crops, and append to the cropped_tensors list + for i in range(num_crops_h): + for j in range(num_crops_w): + start_h = i * step_size_h + start_w = j * step_size_w + end_h = min(start_h + 224, H) + end_w = min(start_w + 224, W) + crop = video_tensor[:, :, :, start_h:end_h, start_w:end_w] + cropped_tensors.append(crop) + crop_positions.append((start_h, start_w)) + + D = len(cropped_tensors) + + # If N is greater than D, generate additional random crops + if N > D and H > 224 and W > 224: # check if H and W are greater than 224 + for _ in range(N - D): + start_h = random.randint(0, H - 224) + start_w = random.randint(0, W - 224) + crop = video_tensor[:, :, :, start_h:(start_h + 224), start_w:(start_w + 224)] + cropped_tensors.append(crop) + crop_positions.append((start_h, start_w)) + + # Reshape the cropped tensors to fit the required output shape (B, T, C, 224, 224) + cropped_tensors = [crop.reshape(B, T, C, 224, 224) for crop in cropped_tensors] + + return cropped_tensors, crop_positions + +def get_honglin_3frame_vmae_optical_flow_crop_batched(generator, + mask_generator, + img1, + img2, + img3, + neg_back_flow=True, + num_scales=1, + min_scale=400, + N_mask_samples=100, + mask_ratio=0.8, + flow_frames='23'): + B = img1.shape[0] + assert len(img1.shape) == 4 + assert num_scales >= 1 + + # For scaling + h1 = img2.shape[-2] + w1 = img2.shape[-1] + assert min_scale < h1 + + if neg_back_flow is False: + print('WARNING: Not calculating negative backward flow') + + alpha = (min_scale / img1.shape[-2]) ** (1 / 4) + + frame_size = 224 // generator.patch_size[-1] + + patch_size = generator.patch_size[-1] + + all_fwd_flows_e2d = [] + + for aidx in range(num_scales): + + # print('aidx: ', aidx) + + img1_scaled = resize(img1.clone(), alpha ** aidx) + img2_scaled = resize(img2.clone(), alpha ** aidx) + img3_scaled = resize(img3.clone(), alpha ** aidx) + + h2 = img2_scaled.shape[-2] + w2 = img2_scaled.shape[-1] + + s_h = h1 / h2 + s_w = w1 / w2 + + # Because technically the compute_optical_flow function returns neg back flow + if neg_back_flow is True: + video = torch.cat([img3_scaled.unsqueeze(1), img2_scaled.unsqueeze(1), img1_scaled.unsqueeze(1)], 1) + else: + video = torch.cat([img1_scaled.unsqueeze(1), img2_scaled.unsqueeze(1), img3_scaled.unsqueeze(1)], 1) + + # Should work, even if the incoming video is already 224x224 + crops1, c_pos1 = get_minimal_224_crops_new_batched(video, 1) + + # print(len(crops1), crops1[0].shape) + + num_crops = len(crops1) + + crop_flows_enc = [] + crop_flows_enc2dec = [] + N_samples = N_mask_samples + + crop = torch.cat(crops1, 0).cuda() + # print(crop.shape) + + optical_flows_enc2dec = torch.zeros(B * num_crops, 2, frame_size, frame_size).cuda() + mask_counts = torch.zeros(frame_size, frame_size).cuda() + + i = 0 + while i < N_samples or (mask_counts == 0).any().item(): + if i % 100 == 0: + pass # print(i) + mask_generator.mask_ratio = mask_ratio + + # breakpoint() + # This would be that every sample has the same mask. For now that's okay I think + mask = mask_generator(num_frames=3)[None] + mask_2f = ~mask[0, frame_size * frame_size * 2:] + mask_counts += mask_2f.reshape(frame_size, frame_size) + + with torch.cuda.amp.autocast(enabled=True): + + processed_x = crop.transpose(1, 2) + + # print("crop", processed_x.max()) + + encoder_out = generator.encoder(processed_x.to(torch.float16), mask.repeat(B * num_crops, 1)) + encoder_to_decoder = generator.encoder_to_decoder(encoder_out) + # print(encoder_to_decoder.shape) + + if flow_frames == '23': + encoder_to_decoder = encoder_to_decoder[:, frame_size * frame_size:, :] + flow_mask = mask[:, frame_size * frame_size:] + # print(encoder_to_decoder.shape) + elif flow_frames == '12': + encoder_to_decoder = encoder_to_decoder[:, :frame_size * frame_size * 2, :] + # print(encoder_to_decoder.shape) + flow_mask = mask[:, :frame_size * frame_size * 2] + # print(mask.shape) + # print(flow_mask.shape) + # print() + + optical_flow_e2d = [] + # one per batch element for now + for b in range(B * num_crops): + batch_flow = compute_optical_flow(encoder_to_decoder[b].unsqueeze(0), flow_mask, frame_size) + optical_flow_e2d.append(batch_flow.unsqueeze(0)) + + optical_flow_e2d = torch.cat(optical_flow_e2d, 0) + optical_flows_enc2dec += optical_flow_e2d + i += 1 + + optical_flows_enc2dec = optical_flows_enc2dec / mask_counts + + scale_factor_y = video.shape[-2] / 224 + scale_factor_x = video.shape[-1] / 224 + + scaled_optical_flow = torch.zeros_like(optical_flows_enc2dec) + scaled_optical_flow[:, 0, :, :] = optical_flows_enc2dec[:, 0, :, :] * scale_factor_x * s_w + scaled_optical_flow[:, 1, :, :] = optical_flows_enc2dec[:, 1, :, :] * scale_factor_y * s_h + + # split the crops back up + crop_flows_enc2dec = scaled_optical_flow.split(B, 0) + # print(len(crop_flows_enc2dec)) + + optical_flows_enc2dec_joined = reconstruct_video_new_2_batched( + [_.unsqueeze(1).repeat_interleave(patch_size, -1).repeat_interleave(patch_size, -2).cpu() for _ in + crop_flows_enc2dec], c_pos1, (B, 1, 2, video.shape[-2], video.shape[-1])).squeeze(1) + + all_fwd_flows_e2d.append(optical_flows_enc2dec_joined) + + all_fwd_flows_e2d_new = [] + + for r in all_fwd_flows_e2d: + new_r = upsample(r, all_fwd_flows_e2d[0].shape[-2], all_fwd_flows_e2d[0].shape[-1]) + all_fwd_flows_e2d_new.append(new_r.unsqueeze(-1)) + return_flow = torch.cat(all_fwd_flows_e2d_new, -1).mean(-1) + + if neg_back_flow is True: + return_flow = -return_flow + all_fwd_flows_e2d_new = [-_ for _ in all_fwd_flows_e2d_new] + + return return_flow, all_fwd_flows_e2d_new + diff --git a/cwm/eval/Physion/run_eval.sh b/cwm/eval/Physion/run_eval.sh new file mode 100644 index 0000000000000000000000000000000000000000..3650eaf5ff7fbe035ab6dec72a266ef58c9dccfe --- /dev/null +++ b/cwm/eval/Physion/run_eval.sh @@ -0,0 +1,17 @@ +#physion_feature_extract \ +#--model_path /ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400/checkpoint-399.pth \ +#--data_root_path /ccn2/u/rmvenkat/data/testing_physion/regenerate_from_old_commit/ \ +#--model_class feature_extractor.CWM_base_8x8_3frame \ +#--gpu 1 \ +#--batch_size 8 \ +#--dir_for_saving /ccn2/u/rmvenkat/data/physion_release/ \ +#--mode ocp + +physion_train_readout \ +--train-path /ccn2/u/rmvenkat/data/physion_release/ocp/train_features.hdf5 \ +--test-path /ccn2/u/rmvenkat/data/physion_release/ocp/test_features.hdf5 \ +--model-name CWM_base_8x8_3frame \ +--train-scenario-indices /ccn2/u/rmvenkat/data/physion_release/ocp/train_json.json \ +--test-scenario-indices /ccn2/u/rmvenkat/data/physion_release/ocp/test_json.json \ +--test-scenario-map /ccn2/u/rmvenkat/data/physion_release/ocp/test_scenario_map.json \ +--save_path /ccn2/u/rmvenkat/data/physion_release/ \ No newline at end of file diff --git a/cwm/eval/Physion/run_eval_kfflow.sh b/cwm/eval/Physion/run_eval_kfflow.sh new file mode 100644 index 0000000000000000000000000000000000000000..9a1a547d962f2f9d8104008fc63c55c6e52866a8 --- /dev/null +++ b/cwm/eval/Physion/run_eval_kfflow.sh @@ -0,0 +1,18 @@ +#physion_feature_extract \ +#--model_path /ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400/checkpoint-399.pth \ +#--data_root_path /ccn2/u/rmvenkat/data/physion_mp4s/ \ +#--model_class feature_extractor.CWM_base_8x8_3frame_Keypoints_KFFlowPatched_noF1_cwm_50_occ_mask \ +#--gpu 1 \ +#--batch_size 8 \ +#--dir_for_saving /ccn2/u/rmvenkat/data/physion_release_kfflow/ \ +#--mode ocp + + +physion_train_readout \ +--train-path /ccn2/u/rmvenkat/data/physion_release_kfflow/ocp/train_features.hdf5 \ +--test-path /ccn2/u/rmvenkat/data/physion_release_kfflow/ocp/test_features.hdf5 \ +--model-name CWM_base_8x8_3frame_Keypoints_KFFlowPatched_noF1_cwm_50_occ_mask \ +--train-scenario-indices /ccn2/u/rmvenkat/data/physion_release_kfflow/ocp/train_json.json \ +--test-scenario-indices /ccn2/u/rmvenkat/data/physion_release_kfflow/ocp/test_json.json \ +--test-scenario-map /ccn2/u/rmvenkat/data/physion_release_kfflow/ocp/test_scenario_map.json \ +--save_path /ccn2/u/rmvenkat/data/physion_release_kfflow/ \ No newline at end of file diff --git a/cwm/eval/Physion/run_eval_mp4s.sh b/cwm/eval/Physion/run_eval_mp4s.sh new file mode 100644 index 0000000000000000000000000000000000000000..156f3c801b2d9eed159585732819c3206a42b2ac --- /dev/null +++ b/cwm/eval/Physion/run_eval_mp4s.sh @@ -0,0 +1,19 @@ +dir_for_saving=/ccn2/u/rmvenkat/data/physion_release/ +model_name=CWM_base_8x8_3frame + +physion_feature_extract \ +--data_root_path /ccn2/u/rmvenkat/data/download_test/physion_mp4s/ \ +--model_class feature_extractor.$model_name \ +--gpu 1 \ +--batch_size 8 \ +--dir_for_saving $dir_for_saving \ +--mode ocd + +physion_train_readout \ +--train-path ${dir_for_saving}ocd/train_features.hdf5 \ +--test-path ${dir_for_saving}ocd/test_features.hdf5 \ +--model-name $model_name \ +--train-scenario-indices ${dir_for_saving}ocd/train_json.json \ +--test-scenario-indices ${dir_for_saving}ocd/test_json.json \ +--test-scenario-map ${dir_for_saving}ocd/test_scenario_map.json \ +--save_path $dir_for_saving diff --git a/cwm/eval/Physion/run_eval_mp4s_keyp.sh b/cwm/eval/Physion/run_eval_mp4s_keyp.sh new file mode 100644 index 0000000000000000000000000000000000000000..58fea4eedbf9983a0f7ef29d077d2f1d03ce76cd --- /dev/null +++ b/cwm/eval/Physion/run_eval_mp4s_keyp.sh @@ -0,0 +1,17 @@ +#physion_feature_extract \ +#--model_path /ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400/checkpoint-399.pth \ +#--data_root_path /ccn2/u/rmvenkat/data/physion_mp4s/ \ +#--model_class feature_extractor_cleaned.CWM_base_8x8_3frame_keypoints \ +#--gpu 3 \ +#--batch_size 8 \ +#--dir_for_saving /ccn2/u/rmvenkat/data/physion_release_keyp/ \ +#--mode ocp + +physion_train_readout \ +--train-path /ccn2/u/rmvenkat/data/physion_release_keyp/ocp/train_features.hdf5 \ +--test-path /ccn2/u/rmvenkat/data/physion_release_keyp/ocp/test_features.hdf5 \ +--model-name CWM_base_8x8_3frame \ +--train-scenario-indices /ccn2/u/rmvenkat/data/physion_release_keyp/ocp/train_json.json \ +--test-scenario-indices /ccn2/u/rmvenkat/data/physion_release_keyp/ocp/test_json.json \ +--test-scenario-map /ccn2/u/rmvenkat/data/physion_release_keyp/ocp/test_scenario_map.json \ +--save_path /ccn2/u/rmvenkat/data/physion_release_keyp/ \ No newline at end of file diff --git a/cwm/eval/Physion/run_eval_mp4s_keyp_flow.sh b/cwm/eval/Physion/run_eval_mp4s_keyp_flow.sh new file mode 100644 index 0000000000000000000000000000000000000000..7c0016e7942e5dde6d9ab9b6f5accf50369c07c3 --- /dev/null +++ b/cwm/eval/Physion/run_eval_mp4s_keyp_flow.sh @@ -0,0 +1,17 @@ +#physion_feature_extract \ +#--model_path /ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400/checkpoint-399.pth \ +#--data_root_path /ccn2/u/rmvenkat/data/physion_mp4s/ \ +#--model_class feature_extractor_cleaned.CWM_base_8x8_3frame_keypoints_flow \ +#--gpu 7 \ +#--batch_size 8 \ +#--dir_for_saving /ccn2/u/rmvenkat/data/physion_release_keyp_flow/ \ +#--mode ocp + +physion_train_readout \ +--train-path /ccn2/u/rmvenkat/data/physion_release_keyp_flow/ocp/train_features.hdf5 \ +--test-path /ccn2/u/rmvenkat/data/physion_release_keyp_flow/ocp/test_features.hdf5 \ +--model-name CWM_base_8x8_3frame \ +--train-scenario-indices /ccn2/u/rmvenkat/data/physion_release_keyp_flow/ocp/train_json.json \ +--test-scenario-indices /ccn2/u/rmvenkat/data/physion_release_keyp_flow/ocp/test_json.json \ +--test-scenario-map /ccn2/u/rmvenkat/data/physion_release_keyp_flow/ocp/test_scenario_map.json \ +--save_path /ccn2/u/rmvenkat/data/physion_release_keyp_flow/ \ No newline at end of file diff --git a/cwm/eval/Segmentation/__init__.py b/cwm/eval/Segmentation/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Segmentation/archive/__init__.py b/cwm/eval/Segmentation/archive/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Segmentation/archive/common/__init__.py b/cwm/eval/Segmentation/archive/common/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Segmentation/archive/common/coco_loader_lsj.py b/cwm/eval/Segmentation/archive/common/coco_loader_lsj.py new file mode 100644 index 0000000000000000000000000000000000000000..7f3cfeec95cf641cd4a3b0671ed8abac063ebbe2 --- /dev/null +++ b/cwm/eval/Segmentation/archive/common/coco_loader_lsj.py @@ -0,0 +1,222 @@ +import detectron2.data.transforms as T +from detectron2 import model_zoo +from detectron2.config import LazyCall as L + +# Data using LSJ +image_size = 512 +dataloader = model_zoo.get_config("common/data/coco.py").dataloader +dataloader.train.mapper.augmentations = [ + L(T.RandomFlip)(horizontal=True), # flip first + L(T.ResizeScale)( + min_scale=0.1, max_scale=2.0, target_height=image_size, target_width=image_size + ), + L(T.FixedSizeCrop)(crop_size=(image_size, image_size), pad=False), +] +dataloader.train.mapper.image_format = "RGB" +dataloader.train.total_batch_size = 64 +dataloader.train.num_workers = 0 +# recompute boxes due to cropping +dataloader.train.mapper.recompute_boxes = True + +dataloader.test.mapper.augmentations = [ + L(T.ResizeShortestEdge)(short_edge_length=image_size, max_size=image_size), +] + + + + +import copy +import logging +import numpy as np +from typing import List, Optional, Union +import torch + +from detectron2.config import configurable + +from detectron2.data import detection_utils as utils +from detectron2.data import transforms as T + +""" +This file contains the default mapping that's applied to "dataset dicts". +""" + +__all__ = ["DatasetMapper"] + + +class DatasetMapper: + """ + A callable which takes a dataset dict in Detectron2 Dataset format, + and map it into a format used by the model. + + This is the default callable to be used to map your dataset dict into training data. + You may need to follow it to implement your own one for customized logic, + such as a different way to read or transform images. + See :doc:`/tutorials/data_loading` for details. + + The callable currently does the following: + + 1. Read the image from "file_name" + 2. Applies cropping/geometric transforms to the image and annotations + 3. Prepare data and annotations to Tensor and :class:`Instances` + """ + + @configurable + def __init__( + self, + is_train: bool, + *, + augmentations: List[Union[T.Augmentation, T.Transform]], + image_format: str, + use_instance_mask: bool = False, + use_keypoint: bool = False, + instance_mask_format: str = "polygon", + keypoint_hflip_indices: Optional[np.ndarray] = None, + precomputed_proposal_topk: Optional[int] = None, + recompute_boxes: bool = False, + ): + """ + NOTE: this interface is experimental. + + Args: + is_train: whether it's used in training or inference + augmentations: a list of augmentations or deterministic transforms to apply + image_format: an image format supported by :func:`detection_utils.read_image`. + use_instance_mask: whether to process instance segmentation annotations, if available + use_keypoint: whether to process keypoint annotations if available + instance_mask_format: one of "polygon" or "bitmask". Process instance segmentation + masks into this format. + keypoint_hflip_indices: see :func:`detection_utils.create_keypoint_hflip_indices` + precomputed_proposal_topk: if given, will load pre-computed + proposals from dataset_dict and keep the top k proposals for each image. + recompute_boxes: whether to overwrite bounding box annotations + by computing tight bounding boxes from instance mask annotations. + """ + if recompute_boxes: + assert use_instance_mask, "recompute_boxes requires instance masks" + # fmt: off + self.is_train = is_train + self.augmentations = T.AugmentationList(augmentations) + self.image_format = image_format + self.use_instance_mask = use_instance_mask + self.instance_mask_format = instance_mask_format + self.use_keypoint = use_keypoint + self.keypoint_hflip_indices = keypoint_hflip_indices + self.proposal_topk = precomputed_proposal_topk + self.recompute_boxes = recompute_boxes + # fmt: on + logger = logging.getLogger(__name__) + mode = "training" if is_train else "inference" + logger.info(f"[DatasetMapper] Augmentations used in {mode}: {augmentations}") + + @classmethod + def from_config(cls, cfg, is_train: bool = True): + augs = utils.build_augmentation(cfg, is_train) + if cfg.INPUT.CROP.ENABLED and is_train: + augs.insert(0, T.RandomCrop(cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE)) + recompute_boxes = cfg.MODEL.MASK_ON + else: + recompute_boxes = False + + ret = { + "is_train": is_train, + "augmentations": augs, + "image_format": cfg.INPUT.FORMAT, + "use_instance_mask": cfg.MODEL.MASK_ON, + "instance_mask_format": cfg.INPUT.MASK_FORMAT, + "use_keypoint": cfg.MODEL.KEYPOINT_ON, + "recompute_boxes": recompute_boxes, + } + + if cfg.MODEL.KEYPOINT_ON: + ret["keypoint_hflip_indices"] = utils.create_keypoint_hflip_indices(cfg.DATASETS.TRAIN) + + if cfg.MODEL.LOAD_PROPOSALS: + ret["precomputed_proposal_topk"] = ( + cfg.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TRAIN + if is_train + else cfg.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TEST + ) + return ret + + def _transform_annotations(self, dataset_dict, transforms, image_shape): + # USER: Modify this if you want to keep them for some reason. + for anno in dataset_dict["annotations"]: + if not self.use_instance_mask: + anno.pop("segmentation", None) + if not self.use_keypoint: + anno.pop("keypoints", None) + + # USER: Implement additional transformations if you have other types of data + annos = [ + utils.transform_instance_annotations( + obj, transforms, image_shape, keypoint_hflip_indices=self.keypoint_hflip_indices + ) + for obj in dataset_dict.pop("annotations") + if obj.get("iscrowd", 0) == 0 + ] + instances = utils.annotations_to_instances( + annos, image_shape, mask_format=self.instance_mask_format + ) + + # After transforms such as cropping are applied, the bounding box may no longer + # tightly bound the object. As an example, imagine a triangle object + # [(0,0), (2,0), (0,2)] cropped by a box [(1,0),(2,2)] (XYXY format). The tight + # bounding box of the cropped triangle should be [(1,0),(2,1)], which is not equal to + # the intersection of original bounding box and the cropping box. + if self.recompute_boxes: + instances.gt_boxes = instances.gt_masks.get_bounding_boxes() + dataset_dict["instances"] = utils.filter_empty_instances(instances) + + def __call__(self, dataset_dict): + """ + Args: + dataset_dict (dict): Metadata of one image, in Detectron2 Dataset format. + + Returns: + dict: a format that builtin models in detectron2 accept + """ + dataset_dict = copy.deepcopy(dataset_dict) # it will be modified by code below + # USER: Write your own image loading if it's not from a file + image = utils.read_image(dataset_dict["file_name"], format=self.image_format) + utils.check_image_size(dataset_dict, image) + + # USER: Remove if you don't do semantic/panoptic segmentation. + if "sem_seg_file_name" in dataset_dict: + sem_seg_gt = utils.read_image(dataset_dict.pop("sem_seg_file_name"), "L").squeeze(2) + else: + sem_seg_gt = None + + aug_input = T.AugInput(image, sem_seg=sem_seg_gt) + transforms = self.augmentations(aug_input) + image, sem_seg_gt = aug_input.image, aug_input.sem_seg + + image_shape = image.shape[:2] # h, w + # Pytorch's dataloader is efficient on torch.Tensor due to shared-memory, + # but not efficient on large generic data structures due to the use of pickle & mp.Queue. + # Therefore it's important to use torch.Tensor. + dataset_dict["image"] = torch.as_tensor(np.ascontiguousarray(image.transpose(2, 0, 1))) + if sem_seg_gt is not None: + dataset_dict["sem_seg"] = torch.as_tensor(sem_seg_gt.astype("long")) + + # USER: Remove if you don't use pre-computed proposals. + # Most users would not need this feature. + if self.proposal_topk is not None: + utils.transform_proposals( + dataset_dict, image_shape, transforms, proposal_topk=self.proposal_topk + ) + + if not self.is_train: + # USER: Modify this if you want to keep them for some reason. + dataset_dict.pop("annotations", None) + dataset_dict.pop("sem_seg_file_name", None) + return dataset_dict + + if "annotations" in dataset_dict: + self._transform_annotations(dataset_dict, transforms, image_shape) + + # Modified by Honglin Chen: change it to class-agnostic instance labels + dataset_dict['instances'].gt_classes *= 0 + return dataset_dict + + +dataloader.train.mapper._target_ = DatasetMapper diff --git a/cwm/eval/Segmentation/archive/common/convert_cwm_checkpoint_detectron_format.py b/cwm/eval/Segmentation/archive/common/convert_cwm_checkpoint_detectron_format.py new file mode 100644 index 0000000000000000000000000000000000000000..757d3201e9f241dd752e7cadb92c6bc1ef8d2a8d --- /dev/null +++ b/cwm/eval/Segmentation/archive/common/convert_cwm_checkpoint_detectron_format.py @@ -0,0 +1,19 @@ +import torch +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--input', type=str, help='The path to the checkpoint.') +parser.add_argument('--output', type=str, default=None, help='the output path of the checkpoint') +args = parser.parse_args() + +state_dict = torch.load(args.input, map_location='cpu')['model'] + +new_state_dict = {} +for k, v in state_dict.items(): + if 'encoder' in k and not 'decoder' in k: + new_k = 'backbone.net.model.' + k + new_state_dict[new_k] = v + +output_path = args.input.replace('.pth', '-encoder.pth') if args.output is None else args.output +torch.save(new_state_dict, output_path) +print('Save model to', output_path) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/common/convert_cwm_checkpoint_detectron_format_v2.py b/cwm/eval/Segmentation/archive/common/convert_cwm_checkpoint_detectron_format_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..6b58caf4024bea05862a34aa3c81331ed40099e2 --- /dev/null +++ b/cwm/eval/Segmentation/archive/common/convert_cwm_checkpoint_detectron_format_v2.py @@ -0,0 +1,54 @@ +import torch +import argparse +import sys +sys.path.append('../../../') +from model_utils import Block, _cfg, PatchEmbed, get_sinusoid_encoding_table + +parser = argparse.ArgumentParser() +parser.add_argument('--input', type=str, help='The path to the checkpoint.') +parser.add_argument('--output', type=str, default=None, help='the output path of the checkpoint') +args = parser.parse_args() + +state_dict = torch.load(args.input, map_location='cpu')['model'] +mae = True +# C = state_dict['encoder.patch_embed.proj.weight'].shape[0] +C = 768 +pos_embed = get_sinusoid_encoding_table(14*14, C) +cls_token = torch.zeros(1, 1, C) +pos_embed = torch.cat([cls_token, pos_embed], dim=1) + + +new_state_dict = {'backbone.net.pos_embed': pos_embed} +for k, v in state_dict.items(): + + if mae or ('encoder' in k and not 'decoder' in k or 'patch_embed' in k): + + if 'patch_embed.proj.weight' in k: + + if len(v.shape) == 5: + if v.shape[2] == 1: + v = v.squeeze(2) # (768, 3, 1, 16, 16) -> (768, 3, 16, 16) + else: + v = v[:, :, 0] + + old_k = k + k = k.replace('encoder.', 'backbone.net.') if not mae else 'backbone.net.'+k + + if 'attn' in k and '_bias' in k: + old_attn = '.'.join(old_k.split('.')[:-1]) + attn = '.'.join(k.split('.')[:-1]) + k = attn + '.qkv.bias' + if k in new_state_dict: + continue + + v = torch.cat([ + state_dict[old_attn + '.q_bias'], + state_dict[old_attn + '.k_bias'] if (old_attn + '.k_bias') in state_dict else torch.zeros_like(state_dict[old_attn + '.q_bias']), + state_dict[old_attn + '.v_bias'], + ], dim=0) + print(k, v.shape) + new_state_dict[k] = v + +output_path = args.input.replace('.pth', '-encoder.pth') if args.output is None else args.output +torch.save(new_state_dict, output_path) +print('Save model to', output_path) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/common/convert_dino_checkpoint_detectron_format.py b/cwm/eval/Segmentation/archive/common/convert_dino_checkpoint_detectron_format.py new file mode 100644 index 0000000000000000000000000000000000000000..477efc0c06657518571cf9ee5775ef2189592299 --- /dev/null +++ b/cwm/eval/Segmentation/archive/common/convert_dino_checkpoint_detectron_format.py @@ -0,0 +1,26 @@ +import torch +import argparse +import sys +sys.path.append('../../../') +from model_utils import Block, _cfg, PatchEmbed, get_sinusoid_encoding_table + +parser = argparse.ArgumentParser() +parser.add_argument('--input', type=str, help='The path to the checkpoint.') +parser.add_argument('--output', type=str, default=None, help='the output path of the checkpoint') +args = parser.parse_args() +breakpoint() +state_dict = torch.load(args.input, map_location='cpu') + +new_state_dict = {} + +for k, v in state_dict.items(): + if 'pos_embed' in k: + breakpoint() + else: + pass + k = 'backbone.net.' + k + new_state_dict[k] = v + +output_path = args.input.replace('.pth', '-encoder.pth') if args.output is None else args.output +torch.save(new_state_dict, output_path) +print('Save model to', output_path) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/competition.py b/cwm/eval/Segmentation/archive/competition.py new file mode 100644 index 0000000000000000000000000000000000000000..2143ee00f0f90f9e23c777dae4e1effaf805ef1c --- /dev/null +++ b/cwm/eval/Segmentation/archive/competition.py @@ -0,0 +1,673 @@ +import numpy as np +import torch +from torch import nn +from torchvision import transforms +import torch.nn.functional as F +from torch.distributions.categorical import Categorical + +from kornia.filters.kernels import (get_spatial_gradient_kernel2d, + normalize_kernel2d) + +def l2_normalize(x): + return F.normalize(x, p=2.0, dim=-1, eps=1e-6) + +def reduce_max(x, dim, keepdim=True): + return torch.max(x, dim=dim, keepdim=keepdim)[0] + +def coordinate_ims(batch_size, seq_length, imsize): + static = False + if seq_length == 0: + static = True + seq_length = 1 + B = batch_size + T = seq_length + H,W = imsize + ones = torch.ones([B,H,W,1], dtype=torch.float32) + h = torch.divide(torch.arange(H).to(ones), torch.tensor(H-1, dtype=torch.float32)) + h = 2.0 * ((h.view(1, H, 1, 1) * ones) - 0.5) + w = torch.divide(torch.arange(W).to(ones), torch.tensor(W-1, dtype=torch.float32)) + w = 2.0 * ((w.view(1, 1, W, 1) * ones) - 0.5) + h = torch.stack([h]*T, 1) + w = torch.stack([w]*T, 1) + hw_ims = torch.cat([h,w], -1) + if static: + hw_ims = hw_ims[:,0] + return hw_ims + +def dot_product_attention(queries, keys, normalize=True, eps=1e-8): + """ + Compute the normalized dot product between two PyTorch tensors + """ + B,N,D_q = queries.size() + _B,N_k,D_k = keys.size() + assert D_q == D_k, (queries.shape, keys.shape) + if normalize: + queries = F.normalize(queries, p=2.0, dim=-1, eps=eps) + keys = F.normalize(keys, p=2.0, dim=-1, eps=eps) + + outputs = torch.matmul(queries, torch.transpose(keys, 1, 2)) # [B, N, N_k] + attention = torch.transpose(outputs, 1, 2) # [B, N_k, N] + + return outputs + +def sample_image_inds_from_probs(probs, num_points, eps=1e-9): + + B,H,W = probs.shape + P = num_points + N = H*W + + probs = probs.reshape(B,N) + probs = torch.maximum(probs + eps, torch.tensor(0., device=probs.device)) / (probs.sum(dim=-1, keepdim=True) + eps) + dist = Categorical(probs=probs, validate_args=False) + + indices = dist.sample([P]).permute(1,0).to(torch.int32) # [B,P] + + indices_h = torch.minimum(torch.maximum(torch.div(indices, W, rounding_mode='floor'), torch.tensor(0)), torch.tensor(H-1)) + indices_w = torch.minimum(torch.maximum(torch.fmod(indices, W), torch.tensor(0)), torch.tensor(W-1)) + indices = torch.stack([indices_h, indices_w], dim=-1) # [B,P,2] + return indices + +def get_gradient_image(image, mode='sobel', order=1, normalize_kernel=True): + + B,C,H,W = list(image.size()) + + # prepare kernel + kernel = get_spatial_gradient_kernel2d(mode, order) + if normalize_kernel: + kernel = normalize_kernel2d(kernel) + tmp_kernel = kernel.to(image).detach() + tmp_kernel = tmp_kernel.unsqueeze(1).unsqueeze(1) + kernel_flip = tmp_kernel.flip(-3) + + # pad spatial dims of image + padding = [kernel.size(1) // 2, kernel.size(1) // 2, kernel.size(2) // 2, kernel.size(2) // 2] + out_channels = 3 if (order == 2) else 2 + padded_image = F.pad(image.reshape(B*C, 1, H, W), padding, 'replicate')[:, :, None] # [B*C,1,1,H+p,W+p] + gradient_image = F.conv3d(padded_image, kernel_flip, padding=0).view(B, C, out_channels, H, W) + return gradient_image + +def sample_coordinates_at_borders(image, num_points=16, mask=None, sum_edges=True, normalized_coordinates=True): + """ + Sample num_points in normalized (h,w) coordinates from the borders of the input image + """ + B,C,H,W = list(image.size()) + if mask is not None: + assert mask.shape[2:] == image.shape[2:], (mask.size(), image.size()) + else: + mask = torch.ones(size=(B,1,H,W)).to(image) + + gradient_image = get_gradient_image(image * mask, mode='sobel', order=1) # [B,C,2,H,W] + gradient_magnitude = torch.sqrt(torch.square(gradient_image).sum(dim=2)) + if sum_edges: + edges = gradient_magnitude.sum(1) # [B,H,W] + else: + edges = gradient_magnitude.max(1)[0] + + if mask is not None: + edges = edges * mask[:,0] + + coordinates = sample_image_inds_from_probs(edges, num_points=num_points) + if normalized_coordinates: + coordinates = coordinates.to(torch.float32) + coordinates /= torch.tensor([H-1,W-1], dtype=torch.float32)[None,None].to(coordinates.device) + coordinates = 2.0 * coordinates - 1.0 + return coordinates + +def index_into_images(images, indices, channels_last=False): + """ + index into an image at P points to get its values + + images: [B,C,H,W] + indices: [B,P,2] + """ + assert indices.size(-1) == 2, indices.size() + if channels_last: + images = images.permute(0,3,1,2) # [B,C,H,W] + B,C,H,W = images.shape + _,P,_ = indices.shape + inds_h, inds_w = list(indices.to(torch.long).permute(2,0,1)) # [B,P] each + inds_b = torch.arange(B, dtype=torch.long).unsqueeze(-1).expand(-1,P).to(indices) + inds = torch.stack([inds_b, inds_h, inds_w], 0).to(torch.long) + values = images.permute(0,2,3,1)[list(inds)] # [B,P,C] + return values + +def soft_index(images, indices, scale_by_imsize=True): + assert indices.shape[-1] == 2, indices.shape + B,C,H,W = images.shape + _,P,_ = indices.shape + + # h_inds, w_inds = indices.split([1,1], dim=-1) + h_inds, w_inds = list(indices.permute(2,0,1)) + if scale_by_imsize: + h_inds = (h_inds + 1.0) * torch.tensor(H).to(h_inds) * 0.5 + w_inds = (w_inds + 1.0) * torch.tensor(W).to(w_inds) * 0.5 + + h_inds = torch.maximum(torch.minimum(h_inds, torch.tensor(H-1).to(h_inds)), torch.tensor(0.).to(h_inds)) + w_inds = torch.maximum(torch.minimum(w_inds, torch.tensor(W-1).to(w_inds)), torch.tensor(0.).to(w_inds)) + + h_floor = torch.floor(h_inds) + w_floor = torch.floor(w_inds) + h_ceil = torch.ceil(h_inds) + w_ceil = torch.ceil(w_inds) + + bot_right_weight = (h_inds - h_floor) * (w_inds - w_floor) + bot_left_weight = (h_inds - h_floor) * (w_ceil - w_inds) + top_right_weight = (h_ceil - h_inds) * (w_inds - w_floor) + top_left_weight = (h_ceil - h_inds) * (w_ceil - w_inds) + + in_bounds = (bot_right_weight + bot_left_weight + top_right_weight + top_left_weight) > 0.95 + in_bounds = in_bounds.to(torch.float32) + + top_left_vals = index_into_images(images, torch.stack([h_floor, w_floor], -1)) + top_right_vals = index_into_images(images, torch.stack([h_floor, w_ceil], -1)) + bot_left_vals = index_into_images(images, torch.stack([h_ceil, w_floor], -1)) + bot_right_vals = index_into_images(images, torch.stack([h_ceil, w_ceil], -1)) + + im_vals = top_left_vals * top_left_weight[...,None] + im_vals += top_right_vals * top_right_weight[...,None] + im_vals += bot_left_vals * bot_left_weight[...,None] + im_vals += bot_right_vals * bot_right_weight[...,None] + + im_vals = im_vals.view(B,P,C) + + return im_vals + +def compute_compatibility(positions, plateau, phenotypes=None, availability=None, noise=0.1): + """ + Compute how well "fit" each agent is for the position it's at on the plateau, + according to its "phenotype" + + positions: [B,P,2] + plateau: [B,H,W,Q] + phenotypes: [B,P,D] or None + availability: [B,H,W,A] + """ + B,H,W,Q = plateau.shape + P = positions.shape[1] + if phenotypes is None: + phenotypes = soft_index(plateau, positions) + + if availability is not None: + assert list(availability.shape)[:-1] == list(plateau.shape)[:-1], (availability.shape, plateau.shape) + A = availability.size(-1) + assert P % A == 0, (P, A) + S = P // A # population size + print("computing availability -- needlessly?", [B,H,W,A,Q]) + plateau = availability[...,None] * plateau[...,None,:] # [B,H,W,A,Q] + plateau = plateau.view(B,H,W,A*Q) + + plateau_values = soft_index(plateau.permute(0,3,1,2), positions, scale_by_imsize=True) + if noise > 0: + plateau_values += noise * torch.rand(size=plateau_values.size(), dtype=torch.float32).to(plateau_values.device) + + if availability is not None: + plateau_values = l2_normalize(plateau_values.view(B, P, A, Q)) + inds = torch.tile(torch.eye(A)[None].expand(B,-1,-1), (1,S,1))[...,None] # [B,P,A,1] + plateau_values = torch.sum(plateau_values * inds.to(plateau_values), dim=-2) # [B,P,Q] + else: + plateau_values = l2_normalize(plateau_values) + + compatibility = torch.sum( + l2_normalize(phenotypes) * plateau_values, dim=-1, keepdim=True) # [B,P,1] + + return compatibility + +def compute_pairwise_overlaps(masks, masks_target=None, mask_thresh=None, eps=1e-6): + """Find overlaps between masks""" + B,N,P = masks.shape + if masks_target is None: + masks_target = masks + if mask_thresh is not None: + masks = (masks > mask_thresh).to(torch.float32) + masks_target = (masks_target > mask_thresh).to(torch.float32) + + ## union and intersection + overlaps = masks[...,None] * masks_target[...,None,:] # [B,N,P,P] + I = overlaps.sum(dim=1) + U = torch.maximum(masks[...,None], masks_target[...,None,:]).sum(dim=1) + iou = I / torch.maximum(U, torch.tensor(eps, dtype=torch.float32)) # [B,P,P] + + return iou + +def compete_agents(masks, fitnesses, alive, + mask_thresh=0.5, compete_thresh=0.2, + sticky_winners=True): + """ + Kill off agents (which mask dimensions are "alive") based on mask overlap and fitnesses of each + + args: + masks: [B,N,P] + fitnesses: [B,P,1] + alive: [B,P,1] + + returns: + still_alive: [B,P,1] + + """ + B,N,P = masks.shape + assert list(alive.shape) == [B,P,1], alive.shape + assert list(fitnesses.shape) == [B,P,1], fitnesses.shape + + ## find territorial disputes + overlaps = compute_pairwise_overlaps(masks, masks_target=None, mask_thresh=mask_thresh) + disputes = overlaps > compete_thresh # [B,P,P] + + ## agents don't fight themselves + disputes = torch.logical_and( + disputes, torch.logical_not( + torch.eye(P, dtype=torch.bool, device=disputes.device).unsqueeze(0).expand(B,-1,-1))) + + ## kill off the agents with lower fitness in each dispute + killed = torch.logical_and(disputes, fitnesses < torch.transpose(fitnesses, 1, 2)) + + ## once an agent wins, it always wins again + if sticky_winners: + winners = (alive > 0.5) + losers = torch.logical_not(winners) + + ## winners can't lose to last round's losers + winners_vs_losers = torch.logical_and(winners, torch.transpose(losers, 1, 2)) # [B,P,P] + killed = torch.logical_and(killed, torch.logical_not(winners_vs_losers)) + + ## losers can't overtake last round's winners + losers_vs_winners = torch.logical_and(losers, torch.transpose(winners, 1, 2)) + losers_vs_winners_disputes = torch.logical_and(losers_vs_winners, disputes) + killed = torch.logical_or(killed, losers_vs_winners_disputes) + + ## if an agent was killed by *any* competitor, it's dead + killed = torch.any(killed, dim=2, keepdim=True) + alive = torch.logical_not(killed).to(torch.float32) + + return alive + +def compute_distance_weighted_vectors(vector_map, positions, mask=None, beta=1.0, eps=1e-8): + """ + compute vectors whose values are a weighted mean of vector_map, where weights are given by distance. + """ + B,H,W,D = vector_map.shape + assert positions.size(-1) == 2, positions.size() + B,P,_ = positions.shape + N = H*W + + if mask is None: + mask = torch.ones_like(vector_map[...,0:1]).to(vector_map.device) + else: + assert list(mask.shape) == [B,H,W,1] + + hw_grid = coordinate_ims(B, 0, [H,W]).view(B, N, 2).to(vector_map.device) + delta_positions = hw_grid[:,None] - positions[:,:,None] # [B,P,N,2] + distances = torch.sqrt(delta_positions[...,0]**2 + delta_positions[...,1]**2 + eps) # [B,P,N] + + ## max distance is 2*sqrt(2) + inv_distances = (2.0 * np.sqrt(2.0)) / (distances + eps) + inv_distances = F.softmax(beta * inv_distances * mask.view(B, 1, N), dim=-1) # [B,P,N] + distance_weighted_vectors = torch.sum( + vector_map.view(B, 1, N, D) * inv_distances[...,None], dim=2, keepdim=False) # [B,P,D] + return distance_weighted_vectors + +def masks_from_phenotypes(plateau, phenotypes, normalize=True): + + B,H,W,Q = plateau.shape + N = H*W + masks = dot_product_attention( + queries=plateau.view(B,N,Q), + keys=phenotypes, + normalize=normalize) + masks = F.relu(masks) + return masks + +class Competition(nn.Module): + + def __init__( + self, + size=None, + num_masks=16, + num_competition_rounds=5, + mask_beta=10.0, + reduce_func=reduce_max, + stop_gradient=True, + stop_gradient_phenotypes=True, + normalization_func=l2_normalize, + sum_edges=True, + mask_thresh=0.5, + compete_thresh=0.2, + sticky_winners=True, + selection_strength=100.0, + homing_strength=10.0, + mask_dead_segments=True + ): + super().__init__() + self.num_masks = self.M = num_masks + self.num_competition_rounds = num_competition_rounds + self.mask_beta = mask_beta + self.reduce_func = reduce_func + self.normalization_func = normalization_func + + ## stop gradients + self.sg_func = lambda x: (x.detach() if stop_gradient else x) + self.sg_phenotypes_func = lambda x: (x.detach() if stop_gradient_phenotypes else x) + + ## agent sampling kwargs + self.sum_edges = sum_edges + + ## competition kwargs + self.mask_thresh = mask_thresh + self.compete_thresh = compete_thresh + self.sticky_winners = sticky_winners + self.selection_strength = selection_strength + self.homing_strength = homing_strength + self.mask_dead_segments = mask_dead_segments + + ## shapes + self.B = self.T = self.BT = self.N = self.Q = None + self.size = size # [H,W] + if self.size: + assert len(self.size) == 2, self.size + + def reshape_batch_time(self, x, merge=True): + + if merge: + self.is_temporal = True + B, T = x.size()[0:2] + if self.B: + assert (B == self.B), (B, self.B) + else: + self.B = B + + if self.T: + assert (T == self.T), (T, self.T) + else: + self.T = T + + assert B*T == (self.B * self.T), (B*T, self.B*self.T) + if self.BT is None: + self.BT = self.B * self.T + + return torch.reshape(x, [self.BT] + list(x.size())[2:]) + + else: # split + BT = x.size()[0] + assert self.B and self.T, (self.B, self.T) + if self.BT is not None: + assert BT == self.BT, (BT, self.BT) + else: + self.BT = BT + + return torch.reshape(x, [self.B, self.T] + list(x.size())[1:]) + + def process_plateau_input(self, plateau): + + shape = plateau.size() + if len(shape) == 5: + self.is_temporal = True + self.B, self.T, self.H, self.W, self.Q = shape + self.N = self.H * self.W + self.BT = self.B * self.T + plateau = self.reshape_batch_time(plateau) + elif (len(shape) == 4) and (self.size is None): + self.is_temporal = False + self.B, self.H, self.W, self.Q = shape + self.N = self.H * self.W + self.T = 1 + self.BT = self.B*self.T + elif (len(shape) == 4) and (self.size is not None): + self.is_temporal = True + self.B, self.T, self.N, self.Q = shape + self.BT = self.B * self.T + self.H, self.W = self.size + plateau = self.reshape_batch_time(plateau) + plateau = torch.reshape(plateau, [self.BT, self.H, self.W, self.Q]) + elif len(shape) == 3: + assert self.size is not None, \ + "You need to specify an image size to reshape the plateau of shape %s" % shape + self.is_temporal = False + self.B, self.N, self.Q = shape + self.T = 1 + self.BT = self.B + self.H, self.W = self.size + plateau = torch.reshape(plateau, [self.BT, self.H, self.W, self.Q]) + else: + raise ValueError("input plateau map with shape %s cannot be reshaped to [BT, H, W, Q]" % shape) + + return plateau + + def forward(self, + plateau, + agents=None, + alive=None, + phenotypes=None, + compete=True, + update_pointers=True, + yoke_phenotypes_to_agents=True, + noise=0.1 + ): + """ + Find the uniform regions within the plateau map + by competition between visual "indices." + + args: + plateau: [B,[T],H,W,Q] feature map with smooth "plateaus" + + returns: + masks: [B, [T], H, W, M] one mask in each of M channels + agents: [B, [T], M, 2] positions of agents in normalized coordinates + alive: [B, [T], M] binary vector indicating which masks are valid + phenotypes: [B, [T], M, Q] + unharvested: [B, [T], H, W] map of regions that weren't covered + + """ + + ## preprocess + plateau = self.process_plateau_input(plateau) # [BT,H,W,Q] + plateau = self.normalization_func(plateau) + + ## sample initial indices ("agents") from borders of the plateau map + if agents is None: + agents = sample_coordinates_at_borders( + plateau.permute(0,3,1,2), + num_points=self.M, + mask=None, + sum_edges=self.sum_edges) + else: + if self.is_temporal: + agents = agents.view(self.BT, *agents.shape[2:]) + + ## the agents have "phenotypes" depending on where they're situated on the plateau map + if phenotypes is None: + phenotypes = self.sg_phenotypes_func( + self.normalization_func( + soft_index(plateau.permute(0,3,1,2), + agents, scale_by_imsize=True))) + elif self.is_temporal: + phenotypes = phenotypes.view(self.BT, *phenotypes.shape[2:]) + + ## the "fitness" of an agent -- how likely it is to survive competition -- + ## is how well its phenotype matches the plateau vector at its current position + ## initially all of these agents are "alive" + if alive is None: + alive = torch.ones_like(agents[...,-1:]) # [BT,M,1] + fitnesses = compute_compatibility(agents, plateau, phenotypes, availability=None, noise=noise) + alive_mask = None + else: + if self.is_temporal: + alive = alive.view(self.BT, *alive.shape[2:]) + alive_mask = (alive > 0.5).float() + fitnesses = alive_mask + compute_compatibility(agents, plateau, phenotypes, availability=None, noise=noise) * (1 - alive_mask) + + alive_t = torch.transpose(alive, 1, 2) # [BT, 1, M] + + ## compute the masks at initialization + masks_pred = masks_from_phenotypes(plateau, phenotypes, normalize=True) + + ## find the "unharvested" regions of the plateau map not covered by agents + unharvested = torch.minimum(self.reduce_func(masks_pred, dim=-1, keepdim=True), torch.tensor(1.0)) + unharvested = 1.0 - unharvested.view(self.BT, self.H, self.W, 1) + + if alive_mask is not None: + new_agents = sample_coordinates_at_borders( + plateau.permute(0,3,1,2), num_points=self.M, + mask=unharvested.permute(0,3,1,2), + sum_edges=self.sum_edges) + agents = agents * alive_mask + new_agents * (1.0 - alive_mask) + + new_phenotypes = self.sg_phenotypes_func( + self.normalization_func( + soft_index(plateau.permute(0,3,1,2), + new_agents, scale_by_imsize=True))) + phenotypes = phenotypes * alive_mask + new_phenotypes * (1.0 - alive_mask) + + for r in range(self.num_competition_rounds): + # print("Evolution round {}".format(r+1)) + + ## compute the "availability" of the plateau map for each agent (i.e. where it can harvest from) + alive_t = torch.transpose(alive, 1, 2) # [BT, 1, M] + # availability = alive_t * masks_pred + (1.0 - alive_t) * unharvested.view(self.BT, self.N, 1) + # availability = availability.view(self.BT, self.H, self.W, self.M) + + ## update the fitnesses + if update_pointers and compete: + fitnesses = compute_compatibility( + positions=agents, + plateau=plateau, + phenotypes=phenotypes, + # availability=availability) + availability=None, + noise=noise + ) + + + ## kill agents that have wandered off the map + in_bounds = torch.all( + torch.logical_and(agents < 1.0, agents > -1.0), + dim=-1, keepdim=True) # [BT,M,1] + fitnesses *= in_bounds.to(fitnesses) + + ## break ties in fitness + fitnesses -= 0.001 * torch.arange(self.M, dtype=torch.float32)[None,:,None].expand(self.BT,-1,-1).to(fitnesses.device) + + ## recompute the masks (why?) + if yoke_phenotypes_to_agents: + occupied_regions = self.sg_phenotypes_func( + soft_index(plateau.permute(0,3,1,2), agents, scale_by_imsize=True)) + masks_pred = masks_from_phenotypes(plateau, occupied_regions, normalize=True) # [BT,N,M] + + ## have each pair of agents compete. + ## If their masks overlap, the winner is the one with higher fitness + if compete: + alive = compete_agents(masks_pred, fitnesses, alive, + mask_thresh=self.mask_thresh, + compete_thresh=self.compete_thresh, + sticky_winners=self.sticky_winners) + + alive *= in_bounds.to(alive) + alive_t = torch.transpose(alive, 1, 2) + + # print("Num alive masks", alive.sum(), "which ones --> ", np.where(alive[0,:,0].detach().cpu().numpy())) + if not yoke_phenotypes_to_agents: + masks_pred = masks_from_phenotypes(plateau, phenotypes, normalize=True) + + ## update which parts of the plateau are "unharvested" + unharvested = torch.minimum(self.reduce_func(masks_pred * alive_t, dim=-1, keepdim=True), + torch.tensor(1.0, dtype=torch.float32)) + unharvested = 1.0 - unharvested.view(self.BT, self.H, self.W, 1) + + + ## update phenotypes of the winners + if update_pointers: + if self.mask_thresh is not None: + winner_phenotypes = (masks_pred[...,None] > self.mask_thresh).to(plateau) + if self.selection_strength > 0: + winner_phenotypes = winner_phenotypes * plateau.view(self.BT, self.N, 1, self.Q) + winner_phenotypes = self.normalization_func(winner_phenotypes.mean(dim=1)) # [BT,M,Q] + phenotypes += (alive * winner_phenotypes) * self.selection_strength + + ## reinitialize losing agent positions + alive_mask = (alive > 0.5).to(torch.float32) + loser_agents = sample_coordinates_at_borders( + plateau.permute(0,3,1,2), num_points=self.M, + mask=unharvested.permute(0,3,1,2), + sum_edges=self.sum_edges) + agents = agents * alive_mask + loser_agents * (1.0 - alive_mask) + + + ## reinitialize loser agent phenotypes + loser_phenotypes = self.normalization_func( + compute_distance_weighted_vectors(plateau, agents, mask=unharvested, beta=self.homing_strength)) + phenotypes = alive_mask * phenotypes + (1.0 - alive_mask) * loser_phenotypes + phenotypes = self.normalization_func(phenotypes) + + ## that's it for this round! + # print("round %d" % r, alive.shape, torch.where(alive[0,:,0])) + + ## run a final competition between the surviving masks + if self.mask_beta is not None: + masks_pred = F.softmax( + self.mask_beta * masks_pred * alive_t - \ + self.mask_beta * (1.0 - alive_t), dim=-1) + if self.mask_dead_segments: + masks_pred *= alive_t + + masks_pred = masks_pred.view(self.BT,self.H,self.W,self.M) + if self.is_temporal: + masks_pred = self.reshape_batch_time(masks_pred, merge=False) + agents = self.reshape_batch_time(agents, merge=False) + alive = self.reshape_batch_time(alive, merge=False) + phenotypes = self.reshape_batch_time(phenotypes, merge=False) + unharvested = self.reshape_batch_time(unharvested, merge=False) + + return (masks_pred, agents, alive, phenotypes, unharvested) + + @staticmethod + def masks_to_segments(masks): + return masks.argmax(-1) + + @staticmethod + def flatten_plateau_with_masks(plateau, masks, alive, flatten_masks=True): + B,M,_ = alive.shape + Q = plateau.shape[-1] + if flatten_masks: + masks = F.one_hot((alive[...,None,None,:,0] * masks).argmax(-1), num_classes=M).float() + + flat_plateau = torch.zeros_like(plateau) + phenotypes = torch.zeros((B,M,Q), device=plateau.device).float() + for b in range(B): + m_inds = torch.where(alive[b,:,0])[0] + masks_b = masks[b,...,m_inds] + num_px = masks_b.sum((0,1)).clamp(min=1)[:,None] # [K,1] + phenos_b = torch.einsum('hwk,hwq->kq', masks_b, plateau[b]) / num_px # [K,Q] + flat_plateau_b = (masks_b[...,None] * phenos_b[None,None]).sum(-2) # [H,W,Q] + + phenotypes[b,m_inds,:] = phenos_b + flat_plateau[b] = flat_plateau_b + + _norm = lambda x: F.normalize(x, p=2, dim=-1) + return (_norm(flat_plateau), _norm(phenotypes)) + + @staticmethod + def plot_agents(agents, alive, size=[128,128]): + B,M,_ = alive.shape + agent_map = -1 * torch.ones((B,*size), device=alive.device, dtype=torch.long) + for b in range(B): + inds = torch.where(alive[b,:,0]) + for i in inds[0]: + pos = agents[b,i]*0.5 + 0.5 + pos = pos * torch.tensor(size, device=pos.device) + hmin, wmin = list(torch.floor(pos).long()) + hmax, wmax = list(torch.ceil(pos).long()) + agent_map[b,[hmin,hmin,hmax,hmax],[wmin,wmax,wmin,wmax]] = i + + return agent_map + +if __name__ == '__main__': + + Comp = Competition(num_masks=32, num_competition_rounds=5) + + left = torch.ones(size=(32,8)).unsqueeze(-1) * torch.tensor([1.,0.2,0.]) + middle = torch.ones(size=(32,16)).unsqueeze(-1) * torch.tensor([0.,1.,0.2]) + right = torch.ones(size=(32,8)).unsqueeze(-1) * torch.tensor([0.1,0.,1.]) + plateau = torch.cat([left, middle, right], dim=-2).unsqueeze(0) + masks, agents, alive, phenotypes, unharvested = Comp(plateau) + mask_inds = np.where(alive[0,:,0].numpy())[0] + print(np.argmax(masks[0,...], axis=-1)) + for ind in mask_inds: + print("num pixels in mask %d ---> %d" % (ind, (np.argmax(masks[0], -1) == ind).sum())) diff --git a/cwm/eval/Segmentation/archive/configs/__init__.py b/cwm/eval/Segmentation/archive/configs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Segmentation/archive/configs/mask_rcnn_cwm_vitdet_b_100ep.py b/cwm/eval/Segmentation/archive/configs/mask_rcnn_cwm_vitdet_b_100ep.py new file mode 100644 index 0000000000000000000000000000000000000000..34c89e7b446d7efd91c1940d35de782d9872c75a --- /dev/null +++ b/cwm/eval/Segmentation/archive/configs/mask_rcnn_cwm_vitdet_b_100ep.py @@ -0,0 +1,56 @@ +from functools import partial +from fvcore.common.param_scheduler import MultiStepParamScheduler + +from detectron2 import model_zoo +from detectron2.config import LazyCall as L +from detectron2.config import CfgNode, LazyConfig +from detectron2.solver import WarmupParamScheduler +from detectron2.modeling.backbone.vit import get_vit_lr_decay_rate + +from ..common.coco_loader_lsj import dataloader + + +# model = model_zoo.get_config("./models/mask_rcnn_cwm.py").model + +cfg_file = "./models/mask_rcnn_cwm.py" +model = LazyConfig.load(cfg_file).model + +# url = get_checkpoint_url(config_path) +# if "train" in cfg and "init_checkpoint" in cfg.train: +# cfg.train.init_checkpoint = url +# else: +# raise NotImplementedError + +# Initialization and trainer settings +train = model_zoo.get_config("common/train.py").train +train.amp.enabled = True +train.ddp.fp16_compression = True +train.init_checkpoint = ( + #"/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_no_clumping/checkpoint-799-encoder.pth" + './output/model_0004999.pth' +) +train.eval_period = 1e9 + +# Schedule +# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep +# train.max_iter = 184375 +# milestones = [163889, 177546] + +# 50 ep = 30730 iters * 96 images/iter / 118000 images/ep +train.max_iter = 61458 +milestones = [54629, 59182] + +lr_multiplier = L(WarmupParamScheduler)( + scheduler=L(MultiStepParamScheduler)( + values=[1.0, 0.1, 0.01], + milestones=milestones, + num_updates=train.max_iter, + ), + warmup_length=250 / train.max_iter, + warmup_factor=0.001, +) + +# Optimizer +optimizer = model_zoo.get_config("common/optim.py").AdamW +optimizer.params.lr_factor_func = partial(get_vit_lr_decay_rate, num_layers=12, lr_decay_rate=0.7) +optimizer.params.overrides = {"pos_embed": {"weight_decay": 0.0}} \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep.py b/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep.py new file mode 100644 index 0000000000000000000000000000000000000000..4937e3401476f9f7d2b06d86c0d05091ddd8fdf5 --- /dev/null +++ b/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep.py @@ -0,0 +1,59 @@ +from functools import partial +from fvcore.common.param_scheduler import MultiStepParamScheduler + +from detectron2 import model_zoo +from detectron2.config import LazyCall as L +from detectron2.solver import WarmupParamScheduler +from detectron2.modeling.backbone.vit import get_vit_lr_decay_rate +import os +from ..common.coco_loader_lsj import dataloader +from detectron2.data.datasets import register_coco_instances +from detectron2.config import CfgNode, LazyConfig +# model = model_zoo.get_config("common/models/mask_rcnn_vitdet.py").model +# model.backbone.square_pad = 512 # change input size to 512x512 + +cfg_file = "./models/mask_rcnn_vitdet_v2.py" +model = LazyConfig.load(cfg_file).model +model.backbone.square_pad = 512 # change input size to 512x512 + +# Initialization and trainer settings +train = model_zoo.get_config("common/train.py").train +train.amp.enabled = True +train.ddp.fp16_compression = True +train.init_checkpoint = ( + #"detectron2://ImageNetPretrained/MAE/mae_pretrain_vit_base.pth?matching_heuristics=True" + #"/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_16x16_no_clumping_mr0.98/checkpoint-799-encoder.pth" + "/ccn2/u/honglinc/cwm_checkpoints/mae_vitb/mae_pretrain_vit_base-encoder.pth" +) +train.output_dir = os.path.dirname(train.init_checkpoint) + "/coco_finetune_512_v3" + +root = os.path.expanduser(os.getenv("DETECTRON2_DATASETS", "datasets")) +register_coco_instances("cls_agnostic_coco", {}, + os.path.join(root, "coco/annotations/coco_cls_agnostic_instances_val2017.json"), + os.path.join(root, "coco/val2017") + ) +dataloader.test.dataset.names = 'cls_agnostic_coco' +# Schedule +# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep +# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep +# train.max_iter = 184375 +# milestones = [163889, 177546] + +# 50 ep = 30730 iters * 96 images/iter / 118000 images/ep +train.max_iter = 61458 +milestones = [54629, 59182] + +lr_multiplier = L(WarmupParamScheduler)( + scheduler=L(MultiStepParamScheduler)( + values=[1.0, 0.1, 0.01], + milestones=milestones, + num_updates=train.max_iter, + ), + warmup_length=250 / train.max_iter, + warmup_factor=0.001, +) + +# Optimizer +optimizer = model_zoo.get_config("common/optim.py").AdamW +optimizer.params.lr_factor_func = partial(get_vit_lr_decay_rate, num_layers=12, lr_decay_rate=0.7) +optimizer.params.overrides = {"pos_embed": {"weight_decay": 0.0}} \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep_dino.py b/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep_dino.py new file mode 100644 index 0000000000000000000000000000000000000000..d94d204e188e3631f31a81933d29fddb360abfaa --- /dev/null +++ b/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep_dino.py @@ -0,0 +1,56 @@ +from functools import partial +from fvcore.common.param_scheduler import MultiStepParamScheduler + +from detectron2 import model_zoo +from detectron2.config import LazyCall as L +from detectron2.config import CfgNode, LazyConfig +from detectron2.solver import WarmupParamScheduler + +from detectron2.modeling.backbone.vit import get_vit_lr_decay_rate +import os +from ..common.coco_loader_lsj import dataloader + +# model = model_zoo.get_config("common/models/mask_rcnn_vitdet.py").model +# model.backbone.square_pad = 512 # change input size to 512x512 + +cfg_file = "./models/mask_rcnn_cwm.py" +model = LazyConfig.load(cfg_file).model + +# Initialization and trainer settings +train = model_zoo.get_config("common/train.py").train +train.amp.enabled = True +train.ddp.fp16_compression = True +train.init_checkpoint = ( + '/home/honglinc/.cache/torch/hub/checkpoints/dinov2_vitb14_pretrain.pth' +) +train.output_dir = '/ccn2/u/honglinc/cwm_checkpoints/dinov2_coco_finetune_512' + +# model.backbone.net.window_size = 0 +# model.backbone.net.window_block_indexes = [] +# model.backbone.net.use_rel_pos = False +# model.backbone.net.drop_path_rate = 0. + +# Schedule +# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep +# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep +# train.max_iter = 184375 +# milestones = [163889, 177546] + +# 50 ep = 30730 iters * 96 images/iter / 118000 images/ep +train.max_iter = 61458 +milestones = [54629, 59182] + +lr_multiplier = L(WarmupParamScheduler)( + scheduler=L(MultiStepParamScheduler)( + values=[1.0, 0.1, 0.01], + milestones=milestones, + num_updates=train.max_iter, + ), + warmup_length=250 / train.max_iter, + warmup_factor=0.001, +) + +# Optimizer +optimizer = model_zoo.get_config("common/optim.py").AdamW +optimizer.params.lr_factor_func = partial(get_vit_lr_decay_rate, num_layers=12, lr_decay_rate=0.7) +optimizer.params.overrides = {"pos_embed": {"weight_decay": 0.0}} \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep_v2.py b/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..6686314dd0f7b4fee2412aa4accf04ea37faa015 --- /dev/null +++ b/cwm/eval/Segmentation/archive/configs/mask_rcnn_vitdet_b_100ep_v2.py @@ -0,0 +1,59 @@ +from functools import partial +from fvcore.common.param_scheduler import MultiStepParamScheduler + +from detectron2 import model_zoo +from detectron2.config import LazyCall as L +from detectron2.config import CfgNode, LazyConfig +from detectron2.solver import WarmupParamScheduler + +from detectron2.modeling.backbone.vit import get_vit_lr_decay_rate +import os +from ..common.coco_loader_lsj import dataloader +from detectron2.data.datasets import register_coco_instances +# model = model_zoo.get_config("common/models/mask_rcnn_vitdet.py").model +# model.backbone.square_pad = 512 # change input size to 512x512 + +cfg_file = "./models/mask_rcnn_cwm.py" +model = LazyConfig.load(cfg_file).model + +# Initialization and trainer settings +train = model_zoo.get_config("common/train.py").train +train.amp.enabled = True +train.ddp.fp16_compression = True +train.init_checkpoint = ( + # "detectron2://ImageNetPretrained/MAE/mae_pretrain_vit_base.pth?matching_heuristics=True" + '/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_16x16_no_clumping_mr0.90/checkpoint-799-encoder.pth' +) +train.output_dir = os.path.dirname(train.init_checkpoint) + "/coco_finetune_512_v3" +train.eval_period = 1e9 + +root = os.path.expanduser(os.getenv("DETECTRON2_DATASETS", "datasets")) +register_coco_instances("cls_agnostic_coco", {}, + os.path.join(root, "coco/annotations/coco_cls_agnostic_instances_val2017.json"), + os.path.join(root, "coco/val2017") + ) +dataloader.test.dataset.names = 'cls_agnostic_coco' +# Schedule +# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep +# 100 ep = 184375 iters * 64 images/iter / 118000 images/ep +# train.max_iter = 184375 +# milestones = [163889, 177546] + +# 50 ep = 30730 iters * 96 images/iter / 118000 images/ep +train.max_iter = 61458 +milestones = [54629, 59182] + +lr_multiplier = L(WarmupParamScheduler)( + scheduler=L(MultiStepParamScheduler)( + values=[1.0, 0.1, 0.01], + milestones=milestones, + num_updates=train.max_iter, + ), + warmup_length=250 / train.max_iter, + warmup_factor=0.001, +) + +# Optimizer +optimizer = model_zoo.get_config("common/optim.py").AdamW +optimizer.params.lr_factor_func = partial(get_vit_lr_decay_rate, num_layers=12, lr_decay_rate=0.7) +optimizer.params.overrides = {"pos_embed": {"weight_decay": 0.0}} \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/connected_component.py b/cwm/eval/Segmentation/archive/connected_component.py new file mode 100644 index 0000000000000000000000000000000000000000..fa89f784ae497a5f247138fa311b49207b246a17 --- /dev/null +++ b/cwm/eval/Segmentation/archive/connected_component.py @@ -0,0 +1,105 @@ +from kornia.contrib import connected_components +import torch +import pdb +import matplotlib.pyplot as plt +import time + +# def reorder_int_labels(x): +# _, y = torch.unique(x, return_inverse=True) +# y -= y.min() +# return y + +# def label_connected_component(labels, max_area=500, min_area=20, max_ccs=128, num_iterations=500): + +# assert len(labels.size()) == 2 + +# # per-label binary mask +# unique_labels = torch.unique(labels).reshape(-1, 1, 1) # [?, 1, 1] +# binary_masks = (labels.unsqueeze(0) == unique_labels).float() # [?, H, W] + +# # label connected components +# cc = connected_components(binary_masks.unsqueeze(1), num_iterations=num_iterations) # [?, 1, H, W] +# cc = reorder_int_labels(cc) +# bincount = torch.bincount(cc.long().flatten()) + +# # find all connected components (id, mask, area, valid) +# # cc_id = torch.nonzero(bincount) # [num_cc] +# cc_id = torch.argsort(bincount)[-max_ccs:] +# cc_mask = (cc == cc_id.reshape(1, -1, 1, 1)).sum(0) # [num_cc, H, W] +# cc_area = bincount[cc_id] # [num_cc] +# valid = (cc_area >= min_area) & (cc_area <= max_area) # [num_cc] +# valid = valid.reshape(-1, 1, 1) # [num_cc, 1, 1] + +# # final labels for connected component +# out = valid * cc_mask +# out = out.argmax(0) +# return out + +def reorder_int_labels(x): + _, y = torch.unique(x, return_inverse=True) + y -= y.min() + return y + + +def label_connected_component(labels, min_area=20, topk=256): + size = labels.size() + assert len(size) == 2 + max_area = size[0] * size[1] - 1 + + # per-label binary mask + unique_labels = torch.unique(labels).reshape(-1, 1, 1) # [?, 1, 1], where ? is the number of unique id + binary_masks = (labels.unsqueeze(0) == unique_labels).float() # [?, H, W] + + # label connected components + # cc is an integer tensor, each unique id represents a single connected component + cc = connected_components(binary_masks.unsqueeze(1), num_iterations=500) # [?, 1, H, W] + + # reorder indices in cc so that cc_area tensor below is a smaller + cc = reorder_int_labels(cc) + + # area of each connected components + cc_area = torch.bincount(cc.long().flatten().cpu()).cuda() # bincount on GPU is much slower + num_cc = cc_area.shape[0] + valid = (cc_area >= min_area) & (cc_area <= max_area) # [num_cc] + + if num_cc < topk: + selected_cc = torch.arange(num_cc).cuda() + else: + _, selected_cc = torch.topk(cc_area, k=topk) + valid = valid[selected_cc] + + # collapse the 0th dimension, since there is only matched one connected component (across 0th dimension) + cc_mask = (cc == selected_cc.reshape(1, -1, 1, 1)).sum(0) # [num_cc, H, W] + cc_mask = cc_mask * valid.reshape(-1, 1, 1) + out = cc_mask.argmax(0) + return out + + +# def reorder_int_labels(x): +# _, y = torch.unique(x, return_inverse=True) +# y -= y.min() +# return y + +# def label_connected_component(labels, max_area=500, min_area=20): + +# assert len(labels.size()) == 2 + +# # per-label binary mask +# unique_labels = torch.unique(labels).reshape(-1, 1, 1) # [?, 1, 1] +# binary_masks = (labels.unsqueeze(0) == unique_labels).float() # [?, H, W] + +# # label connected components +# cc = connected_components(binary_masks.unsqueeze(1)) # [?, 1, H, W] +# cc = reorder_int_labels(cc) +# bincount = torch.bincount(cc.long().flatten()) + +# # find all connected components (id, mask, area, valid) +# cc_id = torch.nonzero(bincount) # [num_cc] +# cc_mask = (cc == cc_id.reshape(1, -1, 1, 1)).sum(0) # [num_cc, H, W] +# cc_area = bincount[cc_id] # [num_cc] +# valid = (cc_area >= min_area) & (cc_area <= max_area) # [num_cc] +# valid = valid.reshape(-1, 1, 1) # [num_cc, 1, 1] + +# # final labels for connected component +# out = valid * cc_mask +# out = out.argmax(0) diff --git a/cwm/eval/Segmentation/archive/generate_zero_shot_segments.py b/cwm/eval/Segmentation/archive/generate_zero_shot_segments.py new file mode 100644 index 0000000000000000000000000000000000000000..cfe82fc0db281c732190b976bb90f6b5e70519a4 --- /dev/null +++ b/cwm/eval/Segmentation/archive/generate_zero_shot_segments.py @@ -0,0 +1,251 @@ +import torch +import os +import glob +import time +from torchvision.io import read_image +import matplotlib.pyplot as plt +from scipy import ndimage +from PIL import Image +import bbnet.trainval.validator as validator +import modeling_pretrain_cleaned as vmae_transformers +import modeling_pretrain as vmae_transformers_old +import positional_vmae as pos_transformers +import big_models as big_transformers +import bbnet.models.preprocessor as preprocessor +import bbnet.models.error as error_generator +from functools import partial +import bbnet.models.teachers as teachers +from tqdm import tqdm +from torch.nn import functional as F +import argparse +import sys +import numpy as np +import json +import pycocotools.mask as mask_util +sys.path.append('/ccn2/u/honglinc/CutLER') +sys.path.append('/ccn2/u/honglinc/CutLER/maskcut') +sys.path.append('/ccn2/u/honglinc/CutLER/third_party') +import dino +from maskcut import get_affinity_matrix, second_smallest_eigenvector, get_salient_areas, check_num_fg_corners, get_masked_affinity_matrix +from third_party.TokenCut.unsupervised_saliency_detection import utils, metric +from third_party.TokenCut.unsupervised_saliency_detection.object_discovery import detect_box +from crf import densecrf +#from maskcut import get_affinity_matrix, second_smallest_eigenvector, get_salient_areas, check_num_fg_corners +# DINO hyperparameters +vit_arch = 'base' +vit_feat = 'k' +patch_size = 8 +# DINO pre-trained model +url = "https://dl.fbaipublicfiles.com/dino/dino_vitbase8_pretrain/dino_vitbase8_pretrain.pth" +feat_dim = 768 +dino_backbone = dino.ViTFeat(url, feat_dim, vit_arch, vit_feat, patch_size) +dino_backbone = dino_backbone.eval().requires_grad_(False).cuda() + + +def get_dino_predominance(images, dims=[28, 28], current_mask=None, painting=None, img_size=[224, 224]): + input_dino = images + input_dino = input_dino - torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1).to(input_dino.device) + input_dino = input_dino / torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1).to(input_dino.device) + # input_dino = images.tensor + input_dino = torch.nn.functional.interpolate(input_dino, size=img_size, mode='bilinear') + features = dino_backbone(input_dino) + + predominence_map = [] + + for i in range(features.shape[0]): + feats = features[i] + if current_mask == None: + painting = torch.from_numpy(np.zeros(dims)) + painting = painting.to(feats) + else: + feats, painting = get_masked_affinity_matrix(painting, feats, current_mask, ps=dims[0]) + + A, D = get_affinity_matrix(feats, tau=0.15) + # get the second-smallest eigenvector + _, second_smallest_vec = second_smallest_eigenvector(A, D) + # get salient area + bipartition = get_salient_areas(second_smallest_vec) + + # check if we should reverse the partition based on: + # 1) peak of the 2nd smallest eigvec 2) object centric bias + seed = np.argmax(np.abs(second_smallest_vec)) + nc = check_num_fg_corners(bipartition, dims) + if nc >= 2: + reverse = True + else: + reverse = bipartition[seed] != 1 + if reverse: + second_smallest_vec = 1 - second_smallest_vec + second_smallest_vec = torch.tensor(second_smallest_vec).to(images.device).contiguous() + map = torch.nn.functional.interpolate(second_smallest_vec.reshape(1, 1, dims[0], dims[1]), size=img_size, + mode='bilinear') + map -= map.min() + map /= map.max() + predominence_map.append(map) + init_dist = torch.cat(predominence_map, dim=0).detach() + return init_dist, A, feats, painting + + + + +def interpolate_pos_encoding(pos_embed, n_frames, h, w): + N = pos_embed.shape[1] + if N == (h * w * n_frames): + return pos_embed + old_h = old_w = int((N / n_frames) ** 0.5) + patch_pos_embed = pos_embed.view(1, n_frames, old_h, old_w, -1).flatten(0, 1).permute(0, 3, 1, 2) + + patch_pos_embed = F.interpolate( + patch_pos_embed, + size=(h, w), + mode='bicubic', + ) + return patch_pos_embed.permute(0, 2, 3, 1).flatten(0, 2).unsqueeze(0) + + + +def vis_results(x, targets_dict, annotation, name): + img = x[0, 0].permute(1, 2, 0).cpu() + fig, axs = plt.subplots(1, 1+len(targets_dict), figsize=(3*len(targets_dict), 3)) + axs[0].imshow(img) + axs[0].set_title('Image') + + for i, v in enumerate(targets_list): + v = v[0, 0] # .cpu() + axs[1+i].imshow((v[..., None] * img) + (~v[..., None] * torch.ones_like(img))) + axs[1+i].set_title(f'Segment {i}', fontsize=10) + + for ax in axs: + ax.set_axis_off() + + plt.show() + plt.close() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser('Generate zero-shot segments from CWM model', add_help=False) + parser.add_argument('--input_pattern', default='/ccn2/u/honglinc/datasets/coco/images/val2017/*', nargs='+', type=str, help='Pattern for input images') + parser.add_argument('--output', default='./output.pt', type=str, help='output path for saving the results') + parser.add_argument('--num_iter', default=1, type=int, help='number of iterations') + parser.add_argument('--visualize', action='store_true', help='Visualize the results') + args = parser.parse_args() + + ## Prepare for the extraction + image_list = glob.glob(args.input_pattern) if isinstance(args.input_pattern, str) else args.input_pattern + thresh = 0.5 + visualize = args.visualize + save_dict = {} + image_size = [480, 480] + patch_size = 8 + dims = [int(s / patch_size) for s in image_size] + + ## Load pretrained model + default_model_dir = '/ccn2/u/honglinc/cwm_checkpoints/' + model_func = vmae_transformers.vitb_8x8patch_3frames + ckpt_path = 'ablation_3frame_no_clumping_mr0.90_extra_data_ep400' # the original IMU-conditioned 4x4 + label = '3 frame 8x8' + teacher_func = teachers.iteration_segment_teacher_with_filter + + teacher = teacher_func( + model_func=model_func, + model_path=teachers.get_load_path(os.path.join(default_model_dir, ckpt_path), model_checkpoint=-1), + visualization_mode=visualize, + initial_sampling_distribution_kwargs={'num_samples': 20, 'num_active_patches': 1, 'num_passive_patches': 1}, + ).requires_grad_(False).cuda() + + teacher.predictor.encoder.pos_embed = interpolate_pos_encoding( + teacher.predictor.encoder.pos_embed, 3, dims[0], dims[1]) + teacher.predictor.pos_embed = interpolate_pos_encoding( + teacher.predictor.pos_embed, 3, dims[0], dims[1]) + teacher.predictor.image_size = image_size + + ## Start extracting segments + start = time.time() + + + if os.path.exists(args.output): + print('Load partial results from: ', args.output) + save_dict = torch.load(args.output) + print('Length of existing dict: ', len(save_dict)) + + for image_path in image_list: + + # Prepare input + image_name = image_path.split('/')[-1] + + if image_name in save_dict: + continue + + image = read_image(image_path) + if image.shape[0] == 1: + image = image.expand(3, -1, -1) + + x = torch.stack([image] * 3, dim=0) + x = torch.nn.functional.interpolate(x.float(), size=image_size, mode='bicubic')[None] / 255. + _x = x.to(torch.float16).cuda() + + targets_list = [] + # extract segments iteratively + for n in range(args.num_iter): + + # Compute predominance map from dino + if n == 0: + predominance, _, feats, painting = get_dino_predominance(x[:, :, 0].cuda(), dims=dims, img_size=image_size) + else: + predominance, _, feats, painting = get_dino_predominance(x[:, :, 0].cuda(), + current_mask=current_mask.cuda(), + painting=painting, dims=dims, + img_size=image_size) + + if visualize: + plt.imshow(predominance[0, 0].cpu()) + plt.title(f'Predominance (max:{predominance[0, 0].max()})') + plt.show() + + # mask out segments that are already extracted + if n > 0: + for mask in targets_list: + predominance[0, 0][mask[0, 0].cuda()] = 0 + + + # extract segments given predominance map + with torch.cuda.amp.autocast(enabled=True): + targets = teacher(_x, sampling_distribution=predominance)[0] + if n == 0: + targets_list = [targets.cpu() >= thresh] + else: + ratio = targets.mean() + mask = targets.cpu() >= thresh + iou = 0 + match_idx = None + + for idx, existing_mask in enumerate(targets_list): + _iou = metric.IoU(mask[0, 0], existing_mask[0, 0]) + if _iou > iou: + iou = _iou + match_idx = idx + + # remove segments if it has large IoU + if iou > 0.2 or ratio <= 0.01: + mask = torch.zeros_like(mask) + # elif iou > 0.1: + # mask[0, 0][targets_list[match_idx][0, 0]] = 0 + + targets_list.append(mask) + + current_mask = F.interpolate(targets, size=dims, mode='bilinear') >= thresh + + vid_name = image_path + save_dict[image_name] = targets_list + if visualize: + vis_results(x, targets_list, None, vid_name.split('/')[-2] + '.png') + + if (len(save_dict) + 1) % 1 == 0: + total = len(image_list) + num_completed = len(save_dict) + avg_time = (time.time() - start) / num_completed + eta = (total - num_completed) * avg_time / 60. + print(f'{num_completed} / {total} completed, avg. time per image: {avg_time:.2f} sec, eta: {eta:.1f} mins') + torch.save(save_dict, args.output) + ## Save the results + torch.save(save_dict, args.output) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/generate_zero_shot_segments_parallel.sh b/cwm/eval/Segmentation/archive/generate_zero_shot_segments_parallel.sh new file mode 100644 index 0000000000000000000000000000000000000000..d62243711054d76330ca9d4305de3bed126d724f --- /dev/null +++ b/cwm/eval/Segmentation/archive/generate_zero_shot_segments_parallel.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +if [ $# -ne 5 ]; then + echo "Usage: $0 " + exit 1 +fi + +directory="$1" +pattern="$2" +N="$3" +num_iters="$4" +output_dir="$5" + +# Check if the directory exists +if [ ! -d "$directory" ]; then + echo "Error: Directory not found." + exit 1 +fi + +# Create the output directory if it doesn't exist +mkdir -p "$output_dir" + +# Get the list of files and subdirectories in the directory +contents=($(find "$directory" -type f -name "$pattern")) + +# Calculate the total number of items +num_items=${#contents[@]} + +# Calculate the approximate number of items in each list +items_per_list=$((num_items / N)) +remainder=$((num_items % N)) + +# Initialize variables +start_index=0 +background_pids=() + +# Split the items into N lists and execute the Python command in parallel +for ((i = 1; i <= N; i++)); do + end_index=$((start_index + items_per_list - 1)) + + # If there's a remainder, distribute the remaining items + if [ $i -le $remainder ]; then + end_index=$((end_index + 1)) + fi + + # Create a sublist from start_index to end_index + sublist=("${contents[@]:start_index:end_index - start_index + 1}") + + # Generate the output path + output_path="$output_dir/$i.pt" + + # Generate the Python command using the sublist, num_iters, and output_path + cuda_visible_devices=$((i - 1)) + cmd="CUDA_VISIBLE_DEVICES=$cuda_visible_devices python generate_zero_shot_segments.py --input_pattern ${sublist[*]} --num_iter $num_iters --output $output_path" + + # Execute the command in the background +# if [ $i -eq 3 ]; then +# eval "$cmd" & +# fi + eval "$cmd" & + + # Record the background process ID + background_pids+=($!) + + # Update the start_index for the next sublist + start_index=$((end_index + 1)) +done + +# Wait for all background processes to finish +for pid in "${background_pids[@]}"; do + wait "$pid" +done diff --git a/cwm/eval/Segmentation/archive/generate_zero_shot_segments_v2.py b/cwm/eval/Segmentation/archive/generate_zero_shot_segments_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..f25dafa58e42a86da3d826f24b0be7d936fb7600 --- /dev/null +++ b/cwm/eval/Segmentation/archive/generate_zero_shot_segments_v2.py @@ -0,0 +1,300 @@ +import torch +import os +import glob +import time +from torchvision.io import read_image +import matplotlib.pyplot as plt +from scipy import ndimage +from PIL import Image + +#import bbnet.trainval.validator as validator +import modeling_pretrain_cleaned as vmae_transformers +import modeling_pretrain as vmae_transformers_old +#import positional_vmae as pos_transformers +#import big_models as big_transformers +import bbnet.models.preprocessor as preprocessor +import bbnet.models.error as error_generator +from functools import partial +#import bbnet.models.teachers as teachers +from tqdm import tqdm +from torch.nn import functional as F +import argparse +import sys +import numpy as np +import json +import pycocotools.mask as mask_util +sys.path.append('/ccn2/u/honglinc/CutLER') +sys.path.append('/ccn2/u/honglinc/CutLER/maskcut') +sys.path.append('/ccn2/u/honglinc/CutLER/third_party') +import dino +import maskcut +# from maskcut import get_affinity_matrix, second_smallest_eigenvector, get_salient_areas, check_num_fg_corners, get_masked_affinity_matrix +from third_party.TokenCut.unsupervised_saliency_detection import utils, metric +from third_party.TokenCut.unsupervised_saliency_detection.object_discovery import detect_box +from crf import densecrf +#from maskcut import get_affinity_matrix, second_smallest_eigenvector, get_salient_areas, check_num_fg_corners +# DINO hyperparameters +vit_arch = 'base' +vit_feat = 'k' +patch_size = 8 +# DINO pre-trained model +url = "https://dl.fbaipublicfiles.com/dino/dino_vitbase8_pretrain/dino_vitbase8_pretrain.pth" +feat_dim = 768 +dino_backbone = dino.ViTFeat(url, feat_dim, vit_arch, vit_feat, patch_size) +dino_backbone = dino_backbone.eval().requires_grad_(False).cuda() + +def get_affinity_matrix(feats, tau, eps=1e-5): + # get affinity matrix via measuring patch-wise cosine similarity + feats = F.normalize(feats, p=2, dim=1) + A = (feats.permute(0, 2, 1) @ feats) + # convert the affinity matrix to a binary one. + A = A > tau + eps = torch.ones_like(A) * eps + A = torch.where(A.float() == 0, eps, A) + d_i = A.sum(-1) + D = torch.diag_embed(d_i) + return A, D + +def second_smallest_eigenvector(A, D): + # get the second smallest eigenvector from affinity matrix + _, eigenvectors = torch.lobpcg(D - A, B=D, k=2, largest=False) + second_smallest_vec = eigenvectors[:, :, 1] + return -second_smallest_vec + +def get_salient_areas(second_smallest_vec): + # get the area corresponding to salient objects. + avg = second_smallest_vec.mean(-1, keepdims=True) + bipartition = second_smallest_vec > avg + return bipartition + +def check_num_fg_corners(bipartition, dims): + # check number of corners belonging to the foreground + dims = [bipartition.shape[0]] + dims + bipartition_ = bipartition.reshape(dims) + top_l, top_r, bottom_l, bottom_r = bipartition_[:,0,0], bipartition_[:,0,-1], bipartition_[:,-1,0], bipartition_[:,-1,-1] + nc = top_l.int() + top_r.int() + bottom_l.int() + bottom_r.int() + return nc + +def get_dino_predominance(images, dims=[28, 28], current_mask=None, painting=None, img_size=[224, 224]): + input_dino = images + input_dino = input_dino - torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1).to(input_dino.device) + input_dino = input_dino / torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1).to(input_dino.device) + # input_dino = images.tensor + input_dino = torch.nn.functional.interpolate(input_dino, size=img_size, mode='bilinear') + feats = dino_backbone(input_dino) # [B, C, N] + B = feats.shape[0] + + predominence_map = [] + if current_mask == None: + painting = torch.from_numpy(np.zeros(dims)) + painting = painting.to(feats) + else: + feats, painting = get_masked_affinity_matrix(painting, feats, current_mask, ps=dims[0]) + + + + A, D = get_affinity_matrix(feats, tau=0.15) + # get the second-smallest eigenvector + + + #_second_smallest_vec = maskcut.second_smallest_eigenvector(A[10].cpu(), D[10].cpu()) + second_smallest_vec = second_smallest_eigenvector(A, D) + + # get salient area + bipartition = get_salient_areas(second_smallest_vec) + + # check if we should reverse the partition based on: + # 1) peak of the 2nd smallest eigvec 2) object centric bias + batch_inds = torch.arange(second_smallest_vec.shape[0]).to(second_smallest_vec).unsqueeze(0) + seed = torch.argmax(second_smallest_vec.abs(), dim=-1).unsqueeze(0) + seed = torch.cat([batch_inds, seed], dim=0).long() + + reverse = bipartition[list(seed)] !=1 + + nc = check_num_fg_corners(bipartition, dims) + reverse[nc >= 2] = True + second_smallest_vec[reverse] = 1 - second_smallest_vec[reverse] + + second_smallest_vec = torch.tensor(second_smallest_vec).to(images.device).contiguous() + map = torch.nn.functional.interpolate(second_smallest_vec.reshape(B, 1, dims[0], dims[1]), size=img_size, + mode='bicubic') + map -= map.min() + map /= map.max() + predominence_map.append(map) + init_dist = torch.cat(predominence_map, dim=0).detach().contiguous() + + return init_dist, A, feats, painting + + + + +def interpolate_pos_encoding(pos_embed, n_frames, h, w): + N = pos_embed.shape[1] + if N == (h * w * n_frames): + return pos_embed + old_h = old_w = int((N / n_frames) ** 0.5) + patch_pos_embed = pos_embed.view(1, n_frames, old_h, old_w, -1).flatten(0, 1).permute(0, 3, 1, 2) + + patch_pos_embed = F.interpolate( + patch_pos_embed, + size=(h, w), + mode='bicubic', + ) + return patch_pos_embed.permute(0, 2, 3, 1).flatten(0, 2).unsqueeze(0) + + + +def vis_results(x, targets_dict, predominance, annotation, name): + B = x.shape[0] + + fig, axs = plt.subplots(B, 2+len(targets_dict), figsize=(3*len(targets_dict), 2*B)) + + for b in range(B): + img = x[b, 0].permute(1, 2, 0).cpu() + axs[b, 0].imshow(img) + axs[b, 0].set_title('Image') + axs[b, 1].imshow(predominance[b, 0].cpu()) + axs[b, 1].set_title('Predominace') + + for i, v in enumerate(targets_list): + v = v[b, 0] # .cpu() + axs[b, 1+i].imshow((v[..., None] * img) + (~v[..., None] * torch.ones_like(img))) + axs[b, 1+i].set_title(f'Segment {i}', fontsize=10) + + for ax in axs: + for a in ax: + a.set_axis_off() + + plt.show() + plt.close() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser('Generate zero-shot segments from CWM model', add_help=False) + parser.add_argument('--input_pattern', default='/ccn2/u/honglinc/datasets/coco/images/val2017/*', nargs='+', type=str, help='Pattern for input images') + parser.add_argument('--output', default='./output.pt', type=str, help='output path for saving the results') + parser.add_argument('--num_iter', default=1, type=int, help='number of iterations') + parser.add_argument('--visualize', action='store_true', help='Visualize the results') + args = parser.parse_args() + + ## Prepare for the extraction + image_list = glob.glob(args.input_pattern) if isinstance(args.input_pattern, str) else args.input_pattern + thresh = 0.5 + visualize = args.visualize + save_dict = {} + image_size = [480, 480] + patch_size = 8 + dims = [int(s / patch_size) for s in image_size] + batch_size = 10 + + ## Load pretrained model + default_model_dir = '/ccn2/u/honglinc/cwm_checkpoints/' + model_func = vmae_transformers.vitb_8x8patch_3frames + ckpt_path = 'ablation_3frame_no_clumping_mr0.90_extra_data_ep400' # the original IMU-conditioned 4x4 + label = '3 frame 8x8' + teacher_func = teachers.iteration_segment_teacher_with_filter + + teacher = teacher_func( + model_func=model_func, + model_path=teachers.get_load_path(os.path.join(default_model_dir, ckpt_path), model_checkpoint=-1), + visualization_mode=visualize, + initial_sampling_distribution_kwargs={'num_samples': 20, 'num_active_patches': 1, 'num_passive_patches': 1}, + ).requires_grad_(False).cuda() + + teacher.predictor.encoder.pos_embed = interpolate_pos_encoding( + teacher.predictor.encoder.pos_embed, 3, dims[0], dims[1]) + teacher.predictor.pos_embed = interpolate_pos_encoding( + teacher.predictor.pos_embed, 3, dims[0], dims[1]) + teacher.predictor.image_size = image_size + + ## Start extracting segments + start = time.time() + batch = [] + image_names = [] + import pdb;pdb.set_trace() + for image_path in sorted(image_list): + + # Prepare input + image_name = image_path.split('/')[-1] + image = read_image(image_path) + if image.shape[0] == 1: + image = image.expand(3, -1, -1) + + x = torch.stack([image] * 3, dim=0) + x = torch.nn.functional.interpolate(x.float(), size=image_size, mode='bicubic')[None] / 255. + + print('length', len(batch)) + if len(batch) < batch_size: + batch.append(x) + image_names.append(image_name) + continue + else: + x = torch.cat(batch, dim=0) + batch = [] + image_names = [] + + _x = x.to(torch.float16).cuda() + + targets_list = [] + # extract segments iteratively + for n in range(args.num_iter): + + # Compute predominance map from dino + if n == 0: + predominance, _, feats, painting = get_dino_predominance(x[:, :, 0].cuda(), dims=dims, img_size=image_size) + else: + raise ValueError('Not implemented') + predominance, _, feats, painting = get_dino_predominance(x[:, :, 0].cuda(), + current_mask=current_mask.cuda(), + painting=painting, dims=dims, + img_size=image_size) + + # mask out segments that are already extracted + if n > 0: + for mask in targets_list: + predominance[0, 0][mask[0, 0].cuda()] = 0 + + + # extract segments given predominance map + with torch.cuda.amp.autocast(enabled=True): + targets = teacher(_x, sampling_distribution=predominance)[0] + print('targets.shape', targets.shape) + if n == 0: + targets_list = [targets.cpu() >= thresh] + else: + ratio = targets.mean() + mask = targets.cpu() >= thresh + iou = 0 + match_idx = None + + for idx, existing_mask in enumerate(targets_list): + _iou = metric.IoU(mask[0, 0], existing_mask[0, 0]) + if _iou > iou: + iou = _iou + match_idx = idx + + # remove segments if it has large IoU + if iou > 0.2 or ratio <= 0.01: + mask = torch.zeros_like(mask) + # elif iou > 0.1: + # mask[0, 0][targets_list[match_idx][0, 0]] = 0 + + targets_list.append(mask) + + current_mask = F.interpolate(targets, size=dims, mode='bilinear') >= thresh + + vid_name = image_path + save_dict[image_name] = targets_list + if visualize: + vis_results(x, targets_list, predominance, None, vid_name.split('/')[-2] + '.png') + + if (len(save_dict) + 1) % 1 == 0: + total = len(image_list) + num_completed = len(save_dict) + avg_time = (time.time() - start) / num_completed + eta = (total - num_completed) * avg_time / 60. + print(f'{num_completed} / {total} completed, avg. time per image: {avg_time:.2f} sec, eta: {eta:.1f} mins') + print('remove save') + #torch.save(save_dict, args.output) + ## Save the results + torch.save(save_dict, args.output) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/lazyconfig_train_net.py b/cwm/eval/Segmentation/archive/lazyconfig_train_net.py new file mode 100644 index 0000000000000000000000000000000000000000..75ead1f00a632f9e4e5587eaa9e0b6fc76985a61 --- /dev/null +++ b/cwm/eval/Segmentation/archive/lazyconfig_train_net.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# Copyright (c) Facebook, Inc. and its affiliates. +""" +Training script using the new "LazyConfig" python config files. + +This scripts reads a given python config file and runs the training or evaluation. +It can be used to train any models or dataset as long as they can be +instantiated by the recursive construction defined in the given config file. + +Besides lazy construction of models, dataloader, etc., this scripts expects a +few common configuration parameters currently defined in "configs/common/train.py". +To add more complicated training logic, you can easily add other configs +in the config file and implement a new train_net.py to handle them. +""" +import logging + +from detectron2.checkpoint import DetectionCheckpointer +from detectron2.config import LazyConfig, instantiate +from detectron2.engine import ( + AMPTrainer, + SimpleTrainer, + default_argument_parser, + default_setup, + default_writers, + hooks, + launch, +) +from detectron2.engine.defaults import create_ddp_model +from detectron2.evaluation import inference_on_dataset, print_csv_format +from detectron2.utils import comm +import warnings +warnings.filterwarnings("ignore") +logger = logging.getLogger("detectron2") + + +def do_test(cfg, model): + if "evaluator" in cfg.dataloader: + ret = inference_on_dataset( + model, instantiate(cfg.dataloader.test), instantiate(cfg.dataloader.evaluator) + ) + print_csv_format(ret) + return ret + + +def do_train(args, cfg): + """ + Args: + cfg: an object with the following attributes: + model: instantiate to a module + dataloader.{train,test}: instantiate to dataloaders + dataloader.evaluator: instantiate to evaluator for test set + optimizer: instantaite to an optimizer + lr_multiplier: instantiate to a fvcore scheduler + train: other misc config defined in `configs/common/train.py`, including: + output_dir (str) + init_checkpoint (str) + amp.enabled (bool) + max_iter (int) + eval_period, log_period (int) + device (str) + checkpointer (dict) + ddp (dict) + """ + model = instantiate(cfg.model) + logger = logging.getLogger("detectron2") + logger.info("Model:\n{}".format(model)) + model.to(cfg.train.device) + + cfg.optimizer.params.model = model + optim = instantiate(cfg.optimizer) + + train_loader = instantiate(cfg.dataloader.train) + + model = create_ddp_model(model, **cfg.train.ddp) + + trainer = (AMPTrainer if cfg.train.amp.enabled else SimpleTrainer)(model, train_loader, optim) + checkpointer = DetectionCheckpointer( + model, + cfg.train.output_dir, + trainer=trainer, + ) + trainer.register_hooks( + [ + hooks.IterationTimer(), + hooks.LRScheduler(scheduler=instantiate(cfg.lr_multiplier)), + hooks.PeriodicCheckpointer(checkpointer, **cfg.train.checkpointer) + if comm.is_main_process() + else None, + hooks.EvalHook(cfg.train.eval_period, lambda: do_test(cfg, model)), + hooks.PeriodicWriter( + default_writers(cfg.train.output_dir, cfg.train.max_iter), + period=cfg.train.log_period, + ) + if comm.is_main_process() + else None, + ] + ) + + checkpointer.resume_or_load(cfg.train.init_checkpoint, resume=args.resume) + if args.resume and checkpointer.has_checkpoint(): + # The checkpoint stores the training iteration that just finished, thus we start + # at the next iteration + start_iter = trainer.iter + 1 + else: + start_iter = 0 + trainer.train(start_iter, cfg.train.max_iter) + + +def main(args): + cfg = LazyConfig.load(args.config_file) + cfg = LazyConfig.apply_overrides(cfg, args.opts) + default_setup(cfg, args) + + if args.eval_only: + model = instantiate(cfg.model) + model.to(cfg.train.device) + model = create_ddp_model(model) + DetectionCheckpointer(model).load(cfg.train.init_checkpoint) + print(do_test(cfg, model)) + else: + do_train(args, cfg) + + +if __name__ == "__main__": + args = default_argument_parser().parse_args() + launch( + main, + args.num_gpus, + num_machines=args.num_machines, + machine_rank=args.machine_rank, + dist_url=args.dist_url, + args=(args,), + ) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/linear_probing.py b/cwm/eval/Segmentation/archive/linear_probing.py new file mode 100644 index 0000000000000000000000000000000000000000..02d343319bb5ce5f5547b676dd86f78206013d67 --- /dev/null +++ b/cwm/eval/Segmentation/archive/linear_probing.py @@ -0,0 +1,59 @@ +import os +import argparse +import sys +import torch +import warnings +warnings.filterwarnings("ignore") +torch.multiprocessing.set_sharing_strategy('file_system') +# Set environment variables +# os.environ['CUDA_VISIBLE_DEVICES'] = '2,3,4,5,6' +os.environ['OMP_NUM_THREADS'] = '1' +os.environ['DETECTRON2_DATASETS'] = '/ccn2/u/honglinc/datasets' + +# Add necessary path +MASK2FORMER_PATH = '/ccn2/u/honglinc/Mask2Former' +BBNET_PATH = '/home/honglinc/BBNet' +sys.path.append(os.path.join(BBNET_PATH, 'bbnet/models/VideoMAE-main/')) +sys.path.append(BBNET_PATH) +sys.path.append(MASK2FORMER_PATH) + +# BBNet import +import modeling_pretrain as vmae_tranformers +from evaluate_segmentation_readout_helper_v2 import CWMSegmentPredictorV2 + +import detectron2.utils.comm as comm +from detectron2.evaluation import verify_results +from train_net import setup, Trainer, DetectionCheckpointer +from detectron2.engine import default_argument_parser, launch + +def main(args): + cfg = setup(args) + + if args.eval_only: + model = Trainer.build_model(cfg) + DetectionCheckpointer(model, save_dir=cfg.OUTPUT_DIR).resume_or_load( + cfg.MODEL.WEIGHTS, resume=args.resume + ) + res = Trainer.test(cfg, model) + if cfg.TEST.AUG.ENABLED: + res.update(Trainer.test_with_TTA(cfg, model)) + if comm.is_main_process(): + verify_results(cfg, res) + return res + + trainer = Trainer(cfg) + trainer.resume_or_load(resume=args.resume) + return trainer.train() + + +if __name__ == "__main__": + args = default_argument_parser().parse_args() + print("Command Line Args:", args) + launch( + main, + args.num_gpus, + num_machines=args.num_machines, + machine_rank=args.machine_rank, + dist_url=args.dist_url, + args=(args,), + ) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/linear_probing_helper.py b/cwm/eval/Segmentation/archive/linear_probing_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..a89ecf7ba73ce15fa3b443feeb86dc645765ebad --- /dev/null +++ b/cwm/eval/Segmentation/archive/linear_probing_helper.py @@ -0,0 +1,535 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +from typing import Tuple + +import torch +from torch import nn +from torch.nn import functional as F +from torchvision.ops import batched_nms, masks_to_boxes +from detectron2.config import configurable +from detectron2.data import MetadataCatalog +from detectron2.modeling import META_ARCH_REGISTRY, build_backbone, build_sem_seg_head +from detectron2.modeling.backbone import Backbone +from detectron2.modeling.postprocessing import sem_seg_postprocess +from detectron2.structures import Boxes, ImageList, Instances, BitMasks +from detectron2.utils.memory import retry_if_cuda_oom +from mask2former.modeling.criterion import SetCriterion +from mask2former.modeling.matcher import HungarianMatcher +import modeling_pretrain as vmae_tranformers +import matplotlib.pyplot as plt +from detectron2.utils.visualizer import Visualizer +import os +from detectron2.data import DatasetCatalog, MetadataCatalog +from detectron2.data.datasets import register_coco_instances + +root = os.path.expanduser(os.getenv("DETECTRON2_DATASETS", "datasets")) +register_coco_instances("cls_agnostic_coco", {}, + os.path.join(root, "coco/annotations/coco_cls_agnostic_instances_val2017.json"), + os.path.join(root, "coco/val2017") + ) + + +@META_ARCH_REGISTRY.register() +class CWMSegmentPredictorV2(nn.Module): + """ + Main class for mask classification semantic segmentation architectures. + """ + + @configurable + def __init__( + self, + *, + criterion: nn.Module, + num_queries: int, + object_mask_threshold: float, + overlap_threshold: float, + metadata, + size_divisibility: int, + sem_seg_postprocess_before_inference: bool, + pixel_mean: Tuple[float], + pixel_std: Tuple[float], + # inference + semantic_on: bool, + panoptic_on: bool, + instance_on: bool, + test_topk_per_image: int, + output_dir: str, + ): + """ + Args: + backbone: a backbone module, must follow detectron2's backbone interface + sem_seg_head: a module that predicts semantic segmentation from backbone features + criterion: a module that defines the loss + num_queries: int, number of queries + object_mask_threshold: float, threshold to filter query based on classification score + for panoptic segmentation inference + overlap_threshold: overlap threshold used in general inference for panoptic segmentation + metadata: dataset meta, get `thing` and `stuff` category names for panoptic + segmentation inference + size_divisibility: Some backbones require the input height and width to be divisible by a + specific integer. We can use this to override such requirement. + sem_seg_postprocess_before_inference: whether to resize the prediction back + to original input size before semantic segmentation inference or after. + For high-resolution dataset like Mapillary, resizing predictions before + inference will cause OOM error. + pixel_mean, pixel_std: list or tuple with #channels element, representing + the per-channel mean and std to be used to normalize the input image + semantic_on: bool, whether to output semantic segmentation prediction + instance_on: bool, whether to output instance segmentation prediction + panoptic_on: bool, whether to output panoptic segmentation prediction + test_topk_per_image: int, instance segmentation parameter, keep topk instances per image + """ + super().__init__() + + self.criterion = criterion + self.num_queries = num_queries + self.overlap_threshold = overlap_threshold + self.object_mask_threshold = object_mask_threshold + self.metadata = metadata + if size_divisibility < 0: + # use backbone size_divisibility if not set + size_divisibility = self.backbone.size_divisibility + self.size_divisibility = size_divisibility + self.sem_seg_postprocess_before_inference = sem_seg_postprocess_before_inference + self.register_buffer("pixel_mean", torch.Tensor(pixel_mean).view(-1, 1, 1), False) + self.register_buffer("pixel_std", torch.Tensor(pixel_std).view(-1, 1, 1), False) + + # additional args + self.semantic_on = semantic_on + self.instance_on = instance_on + self.panoptic_on = panoptic_on + self.test_topk_per_image = test_topk_per_image + + if not self.semantic_on: + assert self.sem_seg_postprocess_before_inference + + # Load CWM predictor + self.output_dir = output_dir + if 'cwm' in output_dir: + model_func = vmae_tranformers.base_8x8patch_2frames_1tube_flash + predictor = model_func().cuda() + + load_path = '/ccn2/u/feigelis/model_checkpoints/kevin_checkpoints/' + \ + 'fulltrain_kinetics_8x8patch_rotated_table_distributed_with_ddp' + \ + '_copied_from_oldnode/checkpoint-3199.pth' + + did_load = predictor.load_state_dict(torch.load(load_path, map_location=torch.device("cpu"))['model']) + print('Load CWM pretrained predictor', did_load) + self.predictor = predictor.eval().requires_grad_(False) + self.num_patches = self.predictor.encoder.num_patches + self.patch_size = self.predictor.encoder.patch_size[-1] + self.mask_ratio = 0.99 + num_hidden_layers = 4 + hidden_dim = 1024 + input_dim = self.predictor.decoder.embed_dim + + decoder_layers = [torch.nn.Linear(input_dim, hidden_dim), torch.nn.ReLU()] + for i in range(num_hidden_layers): + decoder_layers.append(torch.nn.Linear(hidden_dim, hidden_dim)) + decoder_layers.append(torch.nn.ReLU()) + decoder_layers.append(torch.nn.Linear(hidden_dim, num_queries)) + + self.decoder = torch.nn.Sequential(*decoder_layers).cuda() + + @classmethod + def from_config(cls, cfg): + + # Loss parameters: + no_object_weight = cfg.MODEL.MASK_FORMER.NO_OBJECT_WEIGHT + + # loss weights + class_weight = cfg.MODEL.MASK_FORMER.CLASS_WEIGHT + dice_weight = cfg.MODEL.MASK_FORMER.DICE_WEIGHT + mask_weight = cfg.MODEL.MASK_FORMER.MASK_WEIGHT + + # building criterion + matcher = HungarianMatcher( + cost_class=class_weight, + cost_mask=mask_weight, + cost_dice=dice_weight, + num_points=cfg.MODEL.MASK_FORMER.TRAIN_NUM_POINTS, + ) + + weight_dict = {"loss_mask": mask_weight, "loss_dice": dice_weight} + + losses = ["masks"] + + criterion = SetCriterion( + num_classes=80, + matcher=matcher, + weight_dict=weight_dict, + eos_coef=no_object_weight, + losses=losses, + num_points=cfg.MODEL.MASK_FORMER.TRAIN_NUM_POINTS, + oversample_ratio=cfg.MODEL.MASK_FORMER.OVERSAMPLE_RATIO, + importance_sample_ratio=cfg.MODEL.MASK_FORMER.IMPORTANCE_SAMPLE_RATIO, + ) + + return { + "criterion": criterion, + "num_queries": cfg.MODEL.MASK_FORMER.NUM_OBJECT_QUERIES, + "object_mask_threshold": cfg.MODEL.MASK_FORMER.TEST.OBJECT_MASK_THRESHOLD, + "overlap_threshold": cfg.MODEL.MASK_FORMER.TEST.OVERLAP_THRESHOLD, + "metadata": MetadataCatalog.get(cfg.DATASETS.TRAIN[0]), + "size_divisibility": cfg.MODEL.MASK_FORMER.SIZE_DIVISIBILITY, + "sem_seg_postprocess_before_inference": ( + cfg.MODEL.MASK_FORMER.TEST.SEM_SEG_POSTPROCESSING_BEFORE_INFERENCE + or cfg.MODEL.MASK_FORMER.TEST.PANOPTIC_ON + or cfg.MODEL.MASK_FORMER.TEST.INSTANCE_ON + ), + "pixel_mean": cfg.MODEL.PIXEL_MEAN, + "pixel_std": cfg.MODEL.PIXEL_STD, + # inference + "semantic_on": cfg.MODEL.MASK_FORMER.TEST.SEMANTIC_ON, + "instance_on": cfg.MODEL.MASK_FORMER.TEST.INSTANCE_ON, + "panoptic_on": cfg.MODEL.MASK_FORMER.TEST.PANOPTIC_ON, + "test_topk_per_image": cfg.TEST.DETECTIONS_PER_IMAGE, + "output_dir": cfg.OUTPUT_DIR, + } + + @property + def device(self): + return self.pixel_mean.device + + def forward(self, batched_inputs): + """ + Args: + batched_inputs: a list, batched outputs of :class:`DatasetMapper`. + Each item in the list contains the inputs for one image. + For now, each item in the list is a dict that contains: + * "image": Tensor, image in (C, H, W) format. + * "instances": per-region ground truth + * Other information that's included in the original dicts, such as: + "height", "width" (int): the output resolution of the model (may be different + from input resolution), used in inference. + Returns: + list[dict]: + each dict has the results for one image. The dict contains the following keys: + + * "sem_seg": + A Tensor that represents the + per-pixel segmentation prediced by the head. + The prediction has shape KxHxW that represents the logits of + each class for each pixel. + * "panoptic_seg": + A tuple that represent panoptic output + panoptic_seg (Tensor): of shape (height, width) where the values are ids for each segment. + segments_info (list[dict]): Describe each segment in `panoptic_seg`. + Each dict contains keys "id", "category_id", "isthing". + """ + + images = [x["image"].to(self.device) for x in batched_inputs] + images = [(x - self.pixel_mean) / self.pixel_std for x in images] + images = ImageList.from_tensors(images, self.size_divisibility) + + ### + # image_size = images.image_sizes[0] + # processed_results = [] + # input_per_image = batched_inputs[0] + # height = input_per_image.get("height", image_size[0]) + # width = input_per_image.get("width", image_size[1]) + # + # gt_instances = [x["instances"] for x in batched_inputs] + # targets = [] + # for targets_per_image in gt_instances: + # # pad gt + # try: + # gt_masks = targets_per_image.gt_masks + # except: + # print('NO GT MASKS') + # gt_masks = torch.zeros(1, height, width) + # + # targets.append( + # { + # "labels": targets_per_image.gt_classes, + # "masks": gt_masks, + # } + # ) + # + # mask_cls_results = torch.ones(1, self.num_queries, 81)#.to(self.device) + # mask_pred_result = targets[0]['masks']#.to(self.device) + # + # processed_results.append({}) + # if self.instance_on: + # instance_r = retry_if_cuda_oom(self.instance_inference)(mask_cls_results[0], mask_pred_result) + # processed_results[-1]["instances"] = instance_r + # return processed_results + ### + + with torch.cuda.amp.autocast(enabled=True): + with torch.no_grad(): + if not self.training: + # resize to patch size + x = F.interpolate(images.tensor, size=(224, 224), mode="bilinear", align_corners=False) + x = x.to(torch.float16).unsqueeze(2).expand(-1, -1, 2, -1, -1) + else: + x = images.tensor.to(torch.float16).unsqueeze(2).expand(-1, -1, 2, -1, -1) + + # mask out the second frame + mask = torch.zeros([x.shape[0], self.num_patches]).to(x.device).bool() + mask[:, int(self.num_patches // 2):] = 1 + + # num_visibles = int((1 - self.mask_ratio) * int(self.num_patches // 2)) + 1 + # rand_idx = torch.randint(low=int(self.num_patches//2), high=self.num_patches, size=(x.shape[0], int(num_visibles))) + # for i in range(x.shape[0]): + # mask[i, rand_idx[i]] = 0 + + feature = self.predictor.encoder(x, mask=mask) + feature = self.predictor.encoder_to_decoder(feature) + # out = self.predictor(x, mask) + + logits = self.decoder(feature).float() + B, N, _ = logits.shape + pred_masks = logits.view(B, int(N ** 0.5), int(N ** 0.5), self.num_queries).permute(0, 3, 1, + 2) # [B, num_queries, H, W] + outputs = {"pred_masks": pred_masks} + + if self.training: + # mask classification target + if "instances" in batched_inputs[0]: + gt_instances = [x["instances"].to(self.device) for x in batched_inputs] + targets = self.prepare_targets(gt_instances, images) + else: + targets = None + + # bipartite matching-based loss + losses = self.criterion(outputs, targets) + + for k in list(losses.keys()): + if k in self.criterion.weight_dict: + losses[k] *= self.criterion.weight_dict[k] + else: + # remove this loss if not specified in `weight_dict` + losses.pop(k) + return losses + else: + # mask_cls_results = outputs["pred_logits"] + mask_cls_results = torch.ones(x.shape[0], self.num_queries, 81).to(self.device) + mask_pred_results = outputs["pred_masks"] + # upsample masks + mask_pred_results = F.interpolate( + mask_pred_results, + size=(images.tensor.shape[-2], images.tensor.shape[-1]), + mode="bilinear", + align_corners=False, + ) + + # if "instances" in batched_inputs[0]: + # gt_instances = [x["instances"].to(self.device) for x in batched_inputs] + # targets = self.prepare_targets(gt_instances, images) + # else: + # targets = None + + del outputs + + processed_results = [] + for mask_cls_result, mask_pred_result, input_per_image, image_size in zip( + mask_cls_results, mask_pred_results, batched_inputs, images.image_sizes + ): + height = input_per_image.get("height", image_size[0]) + width = input_per_image.get("width", image_size[1]) + processed_results.append({}) + + if self.sem_seg_postprocess_before_inference: + mask_pred_result = retry_if_cuda_oom(sem_seg_postprocess)( + mask_pred_result, image_size, height, width + ) + mask_cls_result = mask_cls_result.to(mask_pred_result) + + # semantic segmentation inference + if self.semantic_on: + r = retry_if_cuda_oom(self.semantic_inference)(mask_cls_result, mask_pred_result) + if not self.sem_seg_postprocess_before_inference: + r = retry_if_cuda_oom(sem_seg_postprocess)(r, image_size, height, width) + processed_results[-1]["sem_seg"] = r + + # panoptic segmentation inference + if self.panoptic_on: + panoptic_r = retry_if_cuda_oom(self.panoptic_inference)(mask_cls_result, mask_pred_result) + processed_results[-1]["panoptic_seg"] = panoptic_r + + # instance segmentation inference + if self.instance_on: + instance_r, nms_idx = retry_if_cuda_oom(self.instance_inference)(mask_cls_result, mask_pred_result) + processed_results[-1]["instances"] = instance_r + + # Visualization + ''' + + rgb_image = F.interpolate(images.tensor.float(), size=(height, width), mode='bilinear') + visualizer = Visualizer(rgb_image.cpu().detach()[0].permute(1,2,0)) + visualizer = visualizer.draw_instance_predictions(instance_r) + + recon = torch.zeros(1, self.num_patches, self.patch_size ** 2 * 3) + recon[mask] = out.float().cpu().detach() + recon = self.unpatchify(recon[:, int(self.num_patches // 2):]) + recon = recon[0].permute(1, 2, 0).float().clamp(0, 1) + # fig, axs = plt.subplots(1, 7, figsize=(20, 3)) + # + # axs[0].imshow(images.tensor.float()[0].permute(1, 2, 0).cpu().detach()) + # axs[1].imshow(images.tensor.float()[0].permute(1, 2, 0).cpu().detach()) + # # axs[1].imshow(batched_inputs[0]['instances'].gt_masks.argmax(0)) + # axs[2].imshow(recon) + # axs[3].imshow(feature[0].view(28, 28, -1)[..., 0:3].cpu().detach().float()) + # axs[4].imshow(feature[0].view(28, 28, -1)[..., 100:103].cpu().detach().float()) + # axs[5].imshow(feature[0].view(28, 28, -1)[..., 200:203].cpu().detach().float()) + # axs[6].imshow(visualizer.get_image()) + file_name = batched_inputs[0]['file_name'].split('/')[-1].split('.jpg')[0] + # for a in axs: + # a.set_axis_off() + fig, axs = plt.subplots(1, 2, figsize=(16, 6)) + axs[0].imshow(images.tensor.float()[0].permute(1, 2, 0).cpu().detach()) + axs[1].imshow(visualizer.get_image()) + plt.savefig(f"/ccn2/u/honglinc/temp/{file_name}.png", bbox_inches='tight') + + fig, axs = plt.subplots(10, 10, figsize=(10, 10)) + for a in axs: + for _a in a: + _a.set_axis_off() + + for i in range(mask_pred_result.shape[0]): + # print(mask_pred_result.shape, height, width) + mask_area_ratio = mask_pred_result[i].sigmoid().float().flatten().sum() / (height * width) + axs[i // 10, i % 10].imshow(mask_pred_result[i].cpu().detach() > 0) + nms = 1 if i in nms_idx else -1 + axs[i // 10, i % 10].set_title(f'{mask_area_ratio.item():.2f}, {nms}', fontsize=11) + plt.savefig(f"/ccn2/u/honglinc/temp/{file_name}_mask.png", bbox_inches='tight') + ''' + + return processed_results + + def prepare_targets(self, targets, images): + h_pad, w_pad = images.tensor.shape[-2:] + new_targets = [] + for targets_per_image in targets: + # pad gt + gt_masks = targets_per_image.gt_masks + padded_masks = torch.zeros((gt_masks.shape[0], h_pad, w_pad), dtype=gt_masks.dtype, device=gt_masks.device) + padded_masks[:, : gt_masks.shape[1], : gt_masks.shape[2]] = gt_masks + new_targets.append( + { + "labels": targets_per_image.gt_classes, + "masks": padded_masks, + } + ) + return new_targets + + def semantic_inference(self, mask_cls, mask_pred): + mask_cls = F.softmax(mask_cls, dim=-1)[..., :-1] + mask_pred = mask_pred.sigmoid() + semseg = torch.einsum("qc,qhw->chw", mask_cls, mask_pred) + return semseg + + def panoptic_inference(self, mask_cls, mask_pred): + scores, labels = F.softmax(mask_cls, dim=-1).max(-1) + mask_pred = mask_pred.sigmoid() + + keep = labels.ne(self.sem_seg_head.num_classes) & (scores > self.object_mask_threshold) + cur_scores = scores[keep] + cur_classes = labels[keep] + cur_masks = mask_pred[keep] + cur_mask_cls = mask_cls[keep] + cur_mask_cls = cur_mask_cls[:, :-1] + + cur_prob_masks = cur_scores.view(-1, 1, 1) * cur_masks + + h, w = cur_masks.shape[-2:] + panoptic_seg = torch.zeros((h, w), dtype=torch.int32, device=cur_masks.device) + segments_info = [] + + current_segment_id = 0 + + if cur_masks.shape[0] == 0: + # We didn't detect any mask :( + return panoptic_seg, segments_info + else: + # take argmax + cur_mask_ids = cur_prob_masks.argmax(0) + stuff_memory_list = {} + for k in range(cur_classes.shape[0]): + pred_class = cur_classes[k].item() + isthing = pred_class in self.metadata.thing_dataset_id_to_contiguous_id.values() + mask_area = (cur_mask_ids == k).sum().item() + original_area = (cur_masks[k] >= 0.5).sum().item() + mask = (cur_mask_ids == k) & (cur_masks[k] >= 0.5) + + if mask_area > 0 and original_area > 0 and mask.sum().item() > 0: + if mask_area / original_area < self.overlap_threshold: + continue + + # merge stuff regions + if not isthing: + if int(pred_class) in stuff_memory_list.keys(): + panoptic_seg[mask] = stuff_memory_list[int(pred_class)] + continue + else: + stuff_memory_list[int(pred_class)] = current_segment_id + 1 + + current_segment_id += 1 + panoptic_seg[mask] = current_segment_id + + segments_info.append( + { + "id": current_segment_id, + "isthing": bool(isthing), + "category_id": int(pred_class), + } + ) + + return panoptic_seg, segments_info + + def instance_inference(self, mask_cls, mask_pred): + # mask_pred is already processed to have the same shape as original input + image_size = mask_pred.shape[-2:] + + mask_area_ratio = (mask_pred > 0).float().flatten(1, 2).sum(1) / (image_size[0] * image_size[1]) + mask_area_filter = (mask_area_ratio > 0.01) & (mask_area_ratio < 0.9) + mask_pred = mask_pred[mask_area_filter] + original_idx = torch.arange(mask_area_filter.shape[0])[mask_area_filter] + try: + box = masks_to_boxes(mask_pred > 0) + scores = (mask_pred.sigmoid().flatten(1) * (mask_pred > 0).flatten(1)).sum(1) / ( + (mask_pred > 0).flatten(1).sum(1) + 1e-6) + nms_idx = batched_nms(box, scores, torch.zeros(box.shape[0]).long(), 0.3) + + mask_pred = mask_pred[nms_idx] + box = box[nms_idx] + + except Exception as e: + import pdb; + pdb.set_trace() + print(e, mask_pred.shape, mask_area_filter.sum()) + box = torch.zeros(mask_pred.shape[0], 4).to(mask_pred) + + nms_idx = original_idx[nms_idx] + mask_pred = mask_pred.cpu() + + result = Instances(image_size) + # mask (before sigmoid) + result.pred_masks = (mask_pred > 0).float() + result.pred_boxes = Boxes(box.cpu()) + # Uncomment the following to get boxes from masks (this is slow) + # result.pred_boxes = BitMasks(mask_pred > 0).get_bounding_boxes() + + # calculate average mask prob + mask_scores_per_image = (mask_pred.sigmoid().flatten(1) * result.pred_masks.flatten(1)).sum(1) / ( + result.pred_masks.flatten(1).sum(1) + 1e-6) + scores_per_image = torch.ones(mask_pred.size(0)).to(mask_pred.device) + labels_per_image = torch.zeros(mask_pred.size(0)).to(mask_pred.device) + + result.scores = scores_per_image * mask_scores_per_image + result.pred_classes = labels_per_image + return result, nms_idx + + def unpatchify(self, x): + """ + x: (N, L, patch_size**2 *3) + imgs: (N, 3, H, W) + """ + p = self.patch_size + h = w = int(x.shape[1] ** .5) + assert h * w == x.shape[1] + + x = x.reshape(shape=(x.shape[0], h, w, p, p, 3)) + x = torch.einsum('nhwpqc->nchpwq', x) + imgs = x.reshape(shape=(x.shape[0], 3, h * p, h * p)) + return imgs \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/merge_results_into_json.py b/cwm/eval/Segmentation/archive/merge_results_into_json.py new file mode 100644 index 0000000000000000000000000000000000000000..7fe9fb52cb1e8572e49d7c31bf9908362ea047db --- /dev/null +++ b/cwm/eval/Segmentation/archive/merge_results_into_json.py @@ -0,0 +1,186 @@ +import os +import json +import glob +import torch +import datetime +import argparse +import torch.nn.functional as F +import numpy as np +import pycocotools.mask as mask_util +def create_image_info(image_id, file_name, image_size, + date_captured=datetime.datetime.utcnow().isoformat(' '), + license_id=1, coco_url="", flickr_url=""): + """Return image_info in COCO style + Args: + image_id: the image ID + file_name: the file name of each image + image_size: image size in the format of (width, height) + date_captured: the date this image info is created + license: license of this image + coco_url: url to COCO images if there is any + flickr_url: url to flickr if there is any + """ + image_info = { + "id": image_id, + "file_name": file_name, + "width": image_size[0], + "height": image_size[1], + "date_captured": date_captured, + "license": license_id, + "coco_url": coco_url, + "flickr_url": flickr_url + } + return image_info + + +def create_annotation_info(annotation_id, image_id, category_info, binary_mask, + image_size=None, bounding_box=None): + """Return annotation info in COCO style + Args: + annotation_id: the annotation ID + image_id: the image ID + category_info: the information on categories + binary_mask: a 2D binary numpy array where '1's represent the object + file_name: the file name of each image + image_size: image size in the format of (width, height) + bounding_box: the bounding box for detection task. If bounding_box is not provided, + we will generate one according to the binary mask. + """ + upper = np.max(binary_mask) + lower = np.min(binary_mask) + thresh = upper / 2.0 + binary_mask[binary_mask > thresh] = upper + binary_mask[binary_mask <= thresh] = lower + if image_size is not None: + binary_mask = resize_binary_mask(binary_mask.astype(np.uint8), image_size) + + binary_mask_encoded = mask_util.encode(np.asfortranarray(binary_mask.astype(np.uint8))) + + area = mask_util.area(binary_mask_encoded) + if area < 1: + return None + + if bounding_box is None: + bounding_box = mask_util.toBbox(binary_mask_encoded) + + rle = mask_util.encode(np.array(binary_mask[...,None], order="F", dtype="uint8"))[0] + rle['counts'] = rle['counts'].decode('ascii') + segmentation = rle + + annotation_info = { + "id": annotation_id, + "image_id": image_id, + "category_id": category_info["id"], + "iscrowd": 0, + "area": area.tolist(), + "bbox": bounding_box.tolist(), + "segmentation": segmentation, + "width": binary_mask.shape[1], + "height": binary_mask.shape[0], + } + + return annotation_info + +# necessay info used for coco style annotations +INFO = { + "description": "ImageNet-1K: pseudo-masks with MaskCut", + "url": "https://github.com/facebookresearch/CutLER", + "version": "1.0", + "year": 2023, + "contributor": "Xudong Wang", + "date_created": datetime.datetime.utcnow().isoformat(' ') +} + +LICENSES = [ + { + "id": 1, + "name": "Apache License", + "url": "https://github.com/facebookresearch/CutLER/blob/main/LICENSE" + } +] + +# only one class, i.e. foreground +CATEGORIES = [ + { + 'id': 1, + 'name': 'fg', + 'supercategory': 'fg', + }, +] + +convert = lambda text: int(text) if text.isdigit() else text.lower() +natrual_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] + +output = { + "info": INFO, + "licenses": LICENSES, + "categories": CATEGORIES, + "images": [], + "annotations": []} + +category_info = { + "is_crowd": 0, + "id": 1 +} + +if __name__ == "__main__": + + parser = argparse.ArgumentParser('Merge pytorch results file into json') + + parser.add_argument('--base-dir', type=str, + default='annotations/', + help='Dir to the generated annotation .pt files with CWM') + parser.add_argument('--save-path', type=str, default="coco_train_fixsize480_N3.json", + help='Path to save the merged annotation file') + args = parser.parse_args() + + file_list = glob.glob(os.path.join(args.base_dir, '*', '*')) + + ann_file = '/ccn2/u/honglinc/datasets/coco/annotations/instances_train2017.json' + with open(ann_file, 'r') as file: + gt_json = json.load(file) + + image_id, segmentation_id = 1, 1 + image_names = [] + for file_name in file_list: + print('processing file name', file_name) + + data = torch.load(file_name) + + for img_name, mask_list in data.items(): + + for img in gt_json['images']: + if img['file_name'] == img_name: + height = img['height'] + width = img['width'] + break + + flag = img_name not in image_names + if flag: + image_info = create_image_info( + image_id, img_name, (height, width, 3)) + output["images"].append(image_info) + image_names.append(img_name) + + + for mask in mask_list: + # create coco-style annotation info + + if mask.sum() == 0: + continue + pseudo_mask = F.interpolate(mask.float(), size=(height, width), mode='bicubic') > 0.5 + pseudo_mask = pseudo_mask[0,0].numpy() + annotation_info = create_annotation_info( + segmentation_id, image_id, category_info, pseudo_mask.astype(np.uint8), None) + if annotation_info is not None: + output["annotations"].append(annotation_info) + segmentation_id += 1 + if flag: + image_id += 1 + print(image_id, segmentation_id) + + # save annotations + with open(args.save_path, 'w') as output_json_file: + json.dump(output, output_json_file) + print(f'dumping {args.save_path}') + print("Done: {} images; {} anns.".format(len(output['images']), len(output['annotations']))) diff --git a/cwm/eval/Segmentation/archive/models/__init__.py b/cwm/eval/Segmentation/archive/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/eval/Segmentation/archive/models/mask_rcnn_cwm.py b/cwm/eval/Segmentation/archive/models/mask_rcnn_cwm.py new file mode 100644 index 0000000000000000000000000000000000000000..203a1fe7a38bf816e7616ace6d57d8583e88c7e1 --- /dev/null +++ b/cwm/eval/Segmentation/archive/models/mask_rcnn_cwm.py @@ -0,0 +1,261 @@ +from functools import partial +import torch.nn as nn +from detectron2.config import LazyCall as L +from detectron2.modeling import ViT +from detectron2.modeling import SimpleFeaturePyramid as BaseSimpleFeaturePyramid +from detectron2.modeling.backbone.fpn import LastLevelMaxPool +from detectron2.layers import CNNBlockBase, Conv2d, get_norm +import sys +sys.path.append('../../') +from modeling_pretrain_cleaned import PretrainVisionTransformer +from detectron2.modeling.backbone.fpn import _assert_strides_are_log2_contiguous +from models.mask_rcnn_fpn_v2 import model, constants +from detectron2.modeling.backbone import Backbone +import torch +import math +import torch.nn.functional as F +import time + +model.pixel_mean = constants['imagenet_rgb256_mean'] +model.pixel_std = constants['imagenet_rgb256_std'] +model.input_format = "RGB" + +class ViT(Backbone): + def __init__(self, + img_size=224, + encoder_embed_dim=768, + encoder_depth=12, + encoder_num_heads=12, + encoder_num_classes=0, + decoder_embed_dim=384, + decoder_num_heads=16, + decoder_depth=8, + mlp_ratio=4, + qkv_bias=True, + k_bias=True, + norm_layer=partial(nn.LayerNorm, eps=1e-6), + patch_size=(8, 8), + num_frames=3, + tubelet_size=1, + use_flash_attention=True, + return_detectron_format=True, + out_feature='last_feat' + ): + super().__init__() + self.model = PretrainVisionTransformer( # Single-scale ViT backbone + img_size=img_size, + encoder_embed_dim=encoder_embed_dim, + encoder_depth=encoder_depth, + encoder_num_heads=encoder_num_heads, + encoder_num_classes=encoder_num_classes, + decoder_embed_dim=decoder_embed_dim, + decoder_num_heads=decoder_num_heads, + decoder_depth=decoder_depth, + mlp_ratio=mlp_ratio, + qkv_bias=qkv_bias, + k_bias=k_bias, + norm_layer=norm_layer, + patch_size=patch_size, + num_frames=num_frames, + tubelet_size=tubelet_size, + use_flash_attention=use_flash_attention, + return_detectron_format=return_detectron_format, + out_feature=out_feature + ) + self._out_features = [out_feature] + self._out_feature_channels = {out_feature: encoder_embed_dim * 2} + self._out_feature_strides = {out_feature: patch_size[0]} + self.patch_hw = 512 // patch_size[0] + self.num_frames = num_frames + pos_embed = self.get_abs_pos(self.model.encoder.pos_embed, num_frames, [self.patch_hw, self.patch_hw]) + self.model.encoder.pos_embed = pos_embed[:, 0:self.patch_hw**2 * (self.num_frames - 1), :] + + def forward(self, x): + B = x.shape[0] + x = x.unsqueeze(2).expand(-1, -1, self.num_frames-1, -1, -1) + mask = torch.zeros(B, self.patch_hw**2 * (self.num_frames - 1), dtype=torch.bool).to(x.device) + return self.model(x, mask) + + def get_abs_pos(self, abs_pos, num_frames, hw): + """ + Calculate absolute positional embeddings. If needed, resize embeddings and remove cls_token + dimension for the original embeddings. + Args: + abs_pos (Tensor): absolute positional embeddings with (1, num_position, C). + has_cls_token (bool): If true, has 1 embedding in abs_pos for cls token. + hw (Tuple): size of input image tokens. + + Returns: + Absolute positional embeddings after processing with shape (1, H, W, C) + """ + + h, w = hw + + xy_num = abs_pos.shape[1] // num_frames + size = int(math.sqrt(xy_num)) + assert size * size * num_frames == abs_pos.shape[1] + abs_pos = abs_pos.view(num_frames, xy_num, -1) + + if size != h or size != w: + new_abs_pos = torch.nn.functional.interpolate( + abs_pos.reshape(num_frames, size, size, -1).permute(0, 3, 1, 2), + size=(h, w), + mode="bicubic", + align_corners=False, + ) + + return new_abs_pos.permute(0, 2, 3, 1).flatten(0, 2).unsqueeze(0) + else: + return abs_pos + + +class SimpleFeaturePyramid(BaseSimpleFeaturePyramid): + """ + This module implements SimpleFeaturePyramid in :paper:`vitdet`. + It creates pyramid features built on top of the input feature map. + """ + + def __init__( + self, + net, + in_feature, + out_channels, + scale_factors, + top_block=None, + norm="LN", + square_pad=0, + ): + """ + Args: + net (Backbone): module representing the subnetwork backbone. + Must be a subclass of :class:`Backbone`. + in_feature (str): names of the input feature maps coming + from the net. + out_channels (int): number of channels in the output feature maps. + scale_factors (list[float]): list of scaling factors to upsample or downsample + the input features for creating pyramid features. + top_block (nn.Module or None): if provided, an extra operation will + be performed on the output of the last (smallest resolution) + pyramid output, and the result will extend the result list. The top_block + further downsamples the feature map. It must have an attribute + "num_levels", meaning the number of extra pyramid levels added by + this block, and "in_feature", which is a string representing + its input feature (e.g., p5). + norm (str): the normalization to use. + square_pad (int): If > 0, require input images to be padded to specific square size. + """ + super(BaseSimpleFeaturePyramid, self).__init__() + assert isinstance(net, Backbone) + + self.scale_factors = scale_factors + + input_shapes = net.output_shape() + strides = [int(input_shapes[in_feature].stride / scale) for scale in scale_factors] + _assert_strides_are_log2_contiguous(strides) + + dim = input_shapes[in_feature].channels + self.stages = [] + use_bias = norm == "" + for idx, scale in enumerate(scale_factors): + out_dim = dim + if scale == 4.0: + layers = [ + nn.ConvTranspose2d(dim, dim // 2, kernel_size=2, stride=2), + get_norm(norm, dim // 2), + nn.GELU(), + nn.ConvTranspose2d(dim // 2, dim // 4, kernel_size=2, stride=2), + ] + out_dim = dim // 4 + elif scale == 2.0: + layers = [nn.ConvTranspose2d(dim, dim // 2, kernel_size=2, stride=2)] + out_dim = dim // 2 + elif scale == 1.0: + layers = [] + elif scale == 0.5: + layers = [nn.MaxPool2d(kernel_size=2, stride=2)] + elif scale == 0.25: + layers = [nn.MaxPool2d(kernel_size=4, stride=4)] + else: + raise NotImplementedError(f"scale_factor={scale} is not supported yet.") + + layers.extend( + [ + Conv2d( + out_dim, + out_channels, + kernel_size=1, + bias=use_bias, + norm=get_norm(norm, out_channels), + ), + Conv2d( + out_channels, + out_channels, + kernel_size=3, + padding=1, + bias=use_bias, + norm=get_norm(norm, out_channels), + ), + ] + ) + layers = nn.Sequential(*layers) + + stage = int(math.log2(strides[idx])) + self.add_module(f"simfp_{stage}", layers) + self.stages.append(layers) + + self.net = net + self.in_feature = in_feature + self.top_block = top_block + # Return feature names are "p", like ["p2", "p3", ..., "p6"] + self._out_feature_strides = {"p{}".format(int(math.log2(s))): s for s in strides} + # top block output feature maps. + if self.top_block is not None: + for s in range(stage, stage + self.top_block.num_levels): + self._out_feature_strides["p{}".format(s + 1)] = 2 ** (s + 1) + + self._out_features = list(self._out_feature_strides.keys()) + self._out_feature_channels = {k: out_channels for k in self._out_features} + self._size_divisibility = strides[-1] + self._square_pad = square_pad + + +# Base +embed_dim, depth, num_heads, dp = 768, 12, 12, 0.1 +# Creates Simple Feature Pyramid from ViT backbone +model.backbone = L(SimpleFeaturePyramid)( + net=L(ViT)( + img_size=224, + encoder_embed_dim=768, + encoder_depth=12, + encoder_num_heads=12, + encoder_num_classes=0, + decoder_embed_dim=384, + decoder_num_heads=16, + decoder_depth=8, + mlp_ratio=4, + qkv_bias=True, + k_bias=True, + norm_layer=partial(nn.LayerNorm, eps=1e-6), + patch_size=(16, 16), #(8, 8), + num_frames=3, + tubelet_size=1, + return_detectron_format=True, + use_flash_attention=True, + out_feature='last_feat' + ), + in_feature="${.net.out_feature}", + out_channels=256, + scale_factors=(4.0, 2.0, 1.0, 0.5, 0.25), + top_block=L(LastLevelMaxPool)(), + norm="LN", + square_pad=512, +) + +model.roi_heads.box_head.conv_norm = model.roi_heads.mask_head.conv_norm = "LN" + +# 2conv in RPN: +model.proposal_generator.head.conv_dims = [-1, -1] + +# 4conv1fc box head +model.roi_heads.box_head.conv_dims = [256, 256, 256, 256] +model.roi_heads.box_head.fc_dims = [1024] \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/models/mask_rcnn_fpn.py b/cwm/eval/Segmentation/archive/models/mask_rcnn_fpn.py new file mode 100644 index 0000000000000000000000000000000000000000..0e82d4b10987e102e466e4d4ce1116627e22a698 --- /dev/null +++ b/cwm/eval/Segmentation/archive/models/mask_rcnn_fpn.py @@ -0,0 +1,103 @@ +from detectron2.config import LazyCall as L +from detectron2.layers import ShapeSpec +from detectron2.modeling.meta_arch import GeneralizedRCNN +from detectron2.modeling.anchor_generator import DefaultAnchorGenerator +from detectron2.modeling.backbone.fpn import LastLevelMaxPool +from detectron2.modeling.backbone import BasicStem, FPN, ResNet +from detectron2.modeling.box_regression import Box2BoxTransform +from detectron2.modeling.matcher import Matcher +from detectron2.modeling.poolers import ROIPooler +from detectron2.modeling.proposal_generator import RPN, StandardRPNHead +from detectron2.modeling.roi_heads import ( + StandardROIHeads, + FastRCNNOutputLayers, + MaskRCNNConvUpsampleHead, + FastRCNNConvFCHead, +) + +constants = dict( + imagenet_rgb256_mean=[123.675, 116.28, 103.53], + imagenet_rgb256_std=[58.395, 57.12, 57.375], + imagenet_bgr256_mean=[103.530, 116.280, 123.675], + # When using pre-trained models in Detectron1 or any MSRA models, + # std has been absorbed into its conv1 weights, so the std needs to be set 1. + # Otherwise, you can use [57.375, 57.120, 58.395] (ImageNet std) + imagenet_bgr256_std=[1.0, 1.0, 1.0], +) + +model = L(GeneralizedRCNN)( + backbone=L(FPN)( + bottom_up=L(ResNet)( + stem=L(BasicStem)(in_channels=3, out_channels=64, norm="FrozenBN"), + stages=L(ResNet.make_default_stages)( + depth=50, + stride_in_1x1=True, + norm="FrozenBN", + ), + out_features=["res2", "res3", "res4", "res5"], + ), + in_features="${.bottom_up.out_features}", + out_channels=256, + top_block=L(LastLevelMaxPool)(), + ), + proposal_generator=L(RPN)( + in_features=["p2", "p3", "p4", "p5", "p6"], + head=L(StandardRPNHead)(in_channels=256, num_anchors=3), + anchor_generator=L(DefaultAnchorGenerator)( + sizes=[[32], [64], [128], [256], [512]], + aspect_ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64], + offset=0.0, + ), + anchor_matcher=L(Matcher)( + thresholds=[0.3, 0.7], labels=[0, -1, 1], allow_low_quality_matches=True + ), + box2box_transform=L(Box2BoxTransform)(weights=[1.0, 1.0, 1.0, 1.0]), + batch_size_per_image=256, + positive_fraction=0.5, + pre_nms_topk=(2000, 1000), + post_nms_topk=(1000, 1000), + nms_thresh=0.7, + ), + roi_heads=L(StandardROIHeads)( + num_classes=2, + batch_size_per_image=512, + positive_fraction=0.25, + proposal_matcher=L(Matcher)( + thresholds=[0.5], labels=[0, 1], allow_low_quality_matches=False + ), + box_in_features=["p2", "p3", "p4", "p5"], + box_pooler=L(ROIPooler)( + output_size=7, + scales=(1.0 / 4, 1.0 / 8, 1.0 / 16, 1.0 / 32), + sampling_ratio=0, + pooler_type="ROIAlignV2", + ), + box_head=L(FastRCNNConvFCHead)( + input_shape=ShapeSpec(channels=256, height=7, width=7), + conv_dims=[], + fc_dims=[1024, 1024], + ), + box_predictor=L(FastRCNNOutputLayers)( + input_shape=ShapeSpec(channels=1024), + test_score_thresh=0.05, + box2box_transform=L(Box2BoxTransform)(weights=(10, 10, 5, 5)), + num_classes="${..num_classes}", + ), + mask_in_features=["p2", "p3", "p4", "p5"], + mask_pooler=L(ROIPooler)( + output_size=14, + scales=(1.0 / 4, 1.0 / 8, 1.0 / 16, 1.0 / 32), + sampling_ratio=0, + pooler_type="ROIAlignV2", + ), + mask_head=L(MaskRCNNConvUpsampleHead)( + input_shape=ShapeSpec(channels=256, width=14, height=14), + num_classes="${..num_classes}", + conv_dims=[256, 256, 256, 256, 256], + ), + ), + pixel_mean=constants['imagenet_bgr256_mean'], + pixel_std=constants['imagenet_bgr256_std'], + input_format="BGR", +) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/models/mask_rcnn_fpn_v2.py b/cwm/eval/Segmentation/archive/models/mask_rcnn_fpn_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..31bd382cf93a1f29a6064d5f55e83743d0c92bb2 --- /dev/null +++ b/cwm/eval/Segmentation/archive/models/mask_rcnn_fpn_v2.py @@ -0,0 +1,106 @@ +from detectron2.config import LazyCall as L +from detectron2.layers import ShapeSpec +from detectron2.modeling.meta_arch import GeneralizedRCNN +from detectron2.modeling.anchor_generator import DefaultAnchorGenerator +from detectron2.modeling.backbone.fpn import LastLevelMaxPool +from detectron2.modeling.backbone import BasicStem, FPN, ResNet +from detectron2.modeling.box_regression import Box2BoxTransform +from detectron2.modeling.matcher import Matcher +from detectron2.modeling.poolers import ROIPooler +from detectron2.modeling.proposal_generator import RPN, StandardRPNHead +from detectron2.modeling.roi_heads import ( + StandardROIHeads, + FastRCNNOutputLayers, + MaskRCNNConvUpsampleHead, + FastRCNNConvFCHead, +) +import sys +sys.path.append('/ccn2/u/honglinc/CutLER/cutler') +from modeling.roi_heads import CustomStandardROIHeads + +constants = dict( + imagenet_rgb256_mean=[123.675, 116.28, 103.53], + imagenet_rgb256_std=[58.395, 57.12, 57.375], + imagenet_bgr256_mean=[103.530, 116.280, 123.675], + # When using pre-trained models in Detectron1 or any MSRA models, + # std has been absorbed into its conv1 weights, so the std needs to be set 1. + # Otherwise, you can use [57.375, 57.120, 58.395] (ImageNet std) + imagenet_bgr256_std=[1.0, 1.0, 1.0], +) + +model = L(GeneralizedRCNN)( + backbone=L(FPN)( + bottom_up=L(ResNet)( + stem=L(BasicStem)(in_channels=3, out_channels=64, norm="FrozenBN"), + stages=L(ResNet.make_default_stages)( + depth=50, + stride_in_1x1=True, + norm="FrozenBN", + ), + out_features=["res2", "res3", "res4", "res5"], + ), + in_features="${.bottom_up.out_features}", + out_channels=256, + top_block=L(LastLevelMaxPool)(), + ), + proposal_generator=L(RPN)( + in_features=["p2", "p3", "p4", "p5", "p6"], + head=L(StandardRPNHead)(in_channels=256, num_anchors=3), + anchor_generator=L(DefaultAnchorGenerator)( + sizes=[[32], [64], [128], [256], [512]], + aspect_ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64], + offset=0.0, + ), + anchor_matcher=L(Matcher)( + thresholds=[0.3, 0.7], labels=[0, -1, 1], allow_low_quality_matches=True + ), + box2box_transform=L(Box2BoxTransform)(weights=[1.0, 1.0, 1.0, 1.0]), + batch_size_per_image=256, + positive_fraction=0.5, + pre_nms_topk=(2000, 1000), + post_nms_topk=(1000, 1000), + nms_thresh=0.7, + ), + roi_heads=L(CustomStandardROIHeads)( + num_classes=1, + batch_size_per_image=512, + positive_fraction=0.25, + proposal_matcher=L(Matcher)( + thresholds=[0.5], labels=[0, 1], allow_low_quality_matches=False + ), + box_in_features=["p2", "p3", "p4", "p5"], + box_pooler=L(ROIPooler)( + output_size=7, + scales=(1.0 / 4, 1.0 / 8, 1.0 / 16, 1.0 / 32), + sampling_ratio=0, + pooler_type="ROIAlignV2", + ), + box_head=L(FastRCNNConvFCHead)( + input_shape=ShapeSpec(channels=256, height=7, width=7), + conv_dims=[], + fc_dims=[1024, 1024], + ), + box_predictor=L(FastRCNNOutputLayers)( + input_shape=ShapeSpec(channels=1024), + test_score_thresh=0.05, + box2box_transform=L(Box2BoxTransform)(weights=(10, 10, 5, 5)), + num_classes="${..num_classes}", + ), + mask_in_features=["p2", "p3", "p4", "p5"], + mask_pooler=L(ROIPooler)( + output_size=14, + scales=(1.0 / 4, 1.0 / 8, 1.0 / 16, 1.0 / 32), + sampling_ratio=0, + pooler_type="ROIAlignV2", + ), + mask_head=L(MaskRCNNConvUpsampleHead)( + input_shape=ShapeSpec(channels=256, width=14, height=14), + num_classes="${..num_classes}", + conv_dims=[256, 256, 256, 256, 256], + ), + ), + pixel_mean=constants['imagenet_bgr256_mean'], + pixel_std=constants['imagenet_bgr256_std'], + input_format="BGR", +) \ No newline at end of file diff --git a/cwm/eval/Segmentation/archive/models/mask_rcnn_vitdet_v2.py b/cwm/eval/Segmentation/archive/models/mask_rcnn_vitdet_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..f1ec2fafecb980a03b1f70d5e8d45ceb6064bc72 --- /dev/null +++ b/cwm/eval/Segmentation/archive/models/mask_rcnn_vitdet_v2.py @@ -0,0 +1,57 @@ +from functools import partial +import torch.nn as nn +from detectron2.config import LazyCall as L +from detectron2.modeling import ViT, SimpleFeaturePyramid +from detectron2.modeling.backbone.fpn import LastLevelMaxPool +from models.mask_rcnn_fpn_v2 import model, constants + +model.pixel_mean = constants['imagenet_rgb256_mean'] +model.pixel_std = constants['imagenet_rgb256_std'] +model.input_format = "RGB" + +# Base +embed_dim, depth, num_heads, dp = 768, 12, 12, 0.1 +# Creates Simple Feature Pyramid from ViT backbone +model.backbone = L(SimpleFeaturePyramid)( + net=L(ViT)( # Single-scale ViT backbone + img_size=1024, + patch_size=16, + embed_dim=embed_dim, + depth=depth, + num_heads=num_heads, + drop_path_rate=dp, + window_size=14, + mlp_ratio=4, + qkv_bias=True, + norm_layer=partial(nn.LayerNorm, eps=1e-6), + window_block_indexes=[ + # 2, 5, 8 11 for global attention + 0, + 1, + 3, + 4, + 6, + 7, + 9, + 10, + ], + residual_block_indexes=[], + use_rel_pos=True, + out_feature="last_feat", + ), + in_feature="${.net.out_feature}", + out_channels=256, + scale_factors=(4.0, 2.0, 1.0, 0.5), + top_block=L(LastLevelMaxPool)(), + norm="LN", + square_pad=512, +) + +model.roi_heads.box_head.conv_norm = model.roi_heads.mask_head.conv_norm = "LN" + +# 2conv in RPN: +model.proposal_generator.head.conv_dims = [-1, -1] + +# 4conv1fc box head +model.roi_heads.box_head.conv_dims = [256, 256, 256, 256] +model.roi_heads.box_head.fc_dims = [1024] \ No newline at end of file diff --git a/cwm/eval/Segmentation/extract_segment.py b/cwm/eval/Segmentation/extract_segment.py new file mode 100644 index 0000000000000000000000000000000000000000..732703901401b889c7b619128273802d733ba82d --- /dev/null +++ b/cwm/eval/Segmentation/extract_segment.py @@ -0,0 +1,36 @@ +import torch +from torch import nn +import cwm.eval.Segmentation.utils as utils +from external.raft_interface import RAFTInterface + +class SegmentExtractor(nn.Module): + def __init__(self, num_segments=1, iters=4, motion_range=4): + self.num_segments = num_segments + self.iters = iters + self.motion_range = motion_range + self.flow_interface = RAFTInterface() + + def get_sampling_dist(self, x, model): + pass + + def forward(self, x, model, sampling_dist=None): + """ + x: [B, 3, H, W] a batch of imagenet-normalized image tensor + model: a pre-trained CWM model + """ + if not sampling_dist: + sampling_dist = self.get_sampling_dist(x, model) + + ## Step 1: sample initial moving and static locations from the distribution + moving_pos = utils.sample_positions_from_dist(num=1, dist=sampling_dist) # [B, num, 2] + static_pos = utils.sample_positions_from_dist(num=1, dist=(1-sampling_dist)) # [B, num, 2] + movement = torch.randint(-self.motion_range, self.motion_range, (B, 1, 2)) # [B, 1, 2] + + ## Step 2: compute initial flow maps + pred = model.get_counterfactual(x, mask, moving_pos=moving_pos, static_pos=static_pos, movement=movement) + flow = self.flow_interface(x[:, :, 0], pred) + + ## Step 3: iterate to add more moving and static motions + + + diff --git a/cwm/eval/Segmentation/utils.py b/cwm/eval/Segmentation/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..d5bdef535d8d2563c353fbe0da843bc0ac84f1f6 --- /dev/null +++ b/cwm/eval/Segmentation/utils.py @@ -0,0 +1,3 @@ +import torch + + diff --git a/cwm/eval/__init__.py b/cwm/eval/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/model/keypoint_utils.py b/cwm/model/keypoint_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..608fd20b50f2e7659b778e6f45eb2f0bd7a20d23 --- /dev/null +++ b/cwm/model/keypoint_utils.py @@ -0,0 +1,186 @@ +from einops import rearrange + +import torch + +import numpy as np + +from torchvision import transforms + +def unpatchify(labels, norm=True): + # Define the input tensor + B = labels.shape[0] # batch size + N_patches = int(np.sqrt(labels.shape[1])) # number of patches along each dimension + patch_size = int(np.sqrt(labels.shape[2] / 3)) # patch size along each dimension + channels = 3 # number of channels + + rec_imgs = rearrange(labels, 'b n (p c) -> b n p c', c=3) + # Notice: To visualize the reconstruction video, we add the predict and the original mean and var of each patch. + rec_imgs = rearrange(rec_imgs, + 'b (t h w) (p0 p1 p2) c -> b c (t p0) (h p1) (w p2)', + p0=1, + p1=patch_size, + p2=patch_size, + h=N_patches, + w=N_patches) + if norm: + MEAN = torch.from_numpy(np.array((0.485, 0.456, 0.406))[None, :, None, None, None]).cuda().half() + STD = torch.from_numpy(np.array((0.229, 0.224, 0.225))[None, :, None, None, None]).cuda().half() + + rec_imgs = (rec_imgs - MEAN) / STD + + return rec_imgs + +def upsample_masks(masks, size, thresh=0.5): + shape = masks.shape + dtype = masks.dtype + h, w = shape[-2:] + H, W = size + if (H == h) and (W == w): + return masks + elif (H < h) and (W < w): + s = (h // H, w // W) + return masks[..., ::s[0], ::s[1]] + + masks = masks.unsqueeze(-2).unsqueeze(-1) + masks = masks.repeat(*([1] * (len(shape) - 2)), 1, H // h, 1, W // w) + if ((H % h) == 0) and ((W % w) == 0): + masks = masks.view(*shape[:-2], H, W) + else: + _H = np.prod(masks.shape[-4:-2]) + _W = np.prod(masks.shape[-2:]) + masks = transforms.Resize(size)(masks.view(-1, 1, _H, _W)) > thresh + masks = masks.view(*shape[:2], H, W).to(masks.dtype) + return masks + +def get_keypoints_batch(model, x, + n_samples, + n_rounds, + frac=0.25, + mask=None, + pool='avg', + ): + """x = image pair tensor + n_samples = number of potential candidates to look at on each round + (produces one new unmasked per round) + n_rounds = total number of unmasked patches + frac = how often to do random sampling vs error-based sampling + mask = initial mask + + """ + # .half() + + + B = x.shape[0] + + IMAGE_SIZE = [224, 224] + predictor = model + patch_size = predictor.patch_size[-1] + num_frames = predictor.num_frames + patch_num = IMAGE_SIZE[0] // patch_size + # this is setup for getting per-patch error + if pool == 'avg': + pool_op = torch.nn.AvgPool2d(patch_size, stride=patch_size) + elif pool == 'max': + pool_op = torch.nn.MaxPool2d(patch_size, stride=patch_size) + + # initiazing rng + rng = np.random.RandomState(seed=0) + + n_patches = patch_num * patch_num + + # initializing mask at the fully masked state + mshape = num_frames * patch_num * patch_num + mshape_masked = (num_frames - 1) * patch_num * patch_num + + if mask is None: + mask = torch.ones([B, mshape], dtype=torch.bool) + mask[:, :mshape_masked] = False + + err_array = [] + choices = [] + + # flows = [] + for round_num in range(n_rounds): + # print(round_num) + # get the current prediction with current state of the mask + # .... produces out_flow b/c it's with head-motion condition + out = unpatchify(predictor(x, mask, forward_full=True)) + + # print(out.shape) + keypoint_recon = out.clone() + # flow = teacher.predict_flow(out) + # flows.append(flow) + + # get the error map + err_mat = (out[:, :, 0] - x[:, :, -1]).abs().mean(1) + # pool it to patch-size + pooled_err = pool_op(err_mat[:, None]) + # flatten the rror + flat_pooled_error = pooled_err.flatten(1, 3) + # set error to be zero where the mask is unmasked so it doesn't interfere + flat_pooled_error[mask[:, -n_patches:] == False] = 0 + # sort patches by where the error is highest + err_sort = torch.argsort(flat_pooled_error, -1) + new_mask = mask.clone().detach() + errors = [] + tries = [] + err_choices = 0 + + # look at various candidates to reveal in the next round + for sample_num in range(n_samples): + # if sample_num % 10 == 0: + # print("%d/%d" % (sample_num, n_samples)) + # either randomly sample + + err_choices += 1 + new_try = (num_frames - 1) * n_patches + err_sort[:, -1 * err_choices] + tries.append(new_try) + + for k in range(B): + new_mask[k, new_try[k]] = False + + reshaped_new_mask = upsample_masks( + new_mask.view(B, num_frames, IMAGE_SIZE[1] // patch_size, IMAGE_SIZE[1] // patch_size)[:, (num_frames - 1):], + IMAGE_SIZE)[:, 0] + + # print(reshaped_new_mask.sum()) + out = unpatchify(predictor(x, new_mask, forward_full=True)) + + abs_error = (out[:, :, 0] - x[:, :, -1]).abs().sum(1).cpu() + + masked_abs_error = abs_error * reshaped_new_mask + error = masked_abs_error.flatten(1, 2).sum(-1) + errors.append(error) + + # take the best one + for k in range(B): + new_mask[k, new_try[k]] = True + + errors = torch.stack(errors, 1) + tries = torch.stack(tries, 1) + best_ind = torch.argmin(errors, dim=-1) + best = torch.tensor([tries[k, best_ind[k]] for k in range(B)]) + choices.append(best) + err_array.append(errors) + # print(best) + for k in range(B): + mask[k, best[k]] = False + + feat = predictor(x, mask, forward_full=True, return_features=True) + + feat = feat#[:, :784*2] + + choices = torch.stack(choices, 1) + + #get x y coordinates of the keypoints + + choices = choices % mshape_masked + choices_x = choices % (patch_num) + choices_y = choices // (patch_num) + choices = torch.stack([choices_x, choices_y], 2) + + out = unpatchify(predictor(x, mask, forward_full=True), norm=False) + + keypoint_recon = out[0, :, 0].permute(1, 2, 0).detach().cpu().numpy() * 255 + + return mask, choices, err_array, feat, keypoint_recon.astype('uint8') \ No newline at end of file diff --git a/cwm/model/model_factory.py b/cwm/model/model_factory.py new file mode 100644 index 0000000000000000000000000000000000000000..e27a8ed96c5b22c81a7153baa2f5f7f7bab490ad --- /dev/null +++ b/cwm/model/model_factory.py @@ -0,0 +1,93 @@ +""" +Model Factory for loading a checkpoint from gcloud, then initializing the model and the configuration +""" +import os +import requests +import torch +import tqdm + +from cwm.model import model_pretrain + +GCLOUD_BUCKET_NAME = "stanford_neuroai_models" +GCLOUD_URL_NAME = "https://storage.googleapis.com/stanford_neuroai_models" +CACHE_PATH = f"{os.getenv('CACHE')}/stanford_neuroai_models" if os.getenv('CACHE') is not None else ".cache/stanford_neuroai_models" +_model_catalogue ={ + "vitb_8x8patch_3frames": { + "path": "cwm/3frame_cwm_8x8.pth", + "init_fn": model_pretrain.vitb_8x8patch_3frames, + }, + "vitb_4x4patch_2frames": { + "path": "cwm/2frame_cwm_4x4.pth", + "init_fn": model_pretrain.vitb_4x4patch_2frames, + }, + + "vitb_8x8patch_2frames": { + "path": "cwm/2frame_cwm_8x8.pth", + "init_fn": model_pretrain.vitb_8x8patch_2frames, + }, + +} + + +class ModelFactory: + + def __init__(self, bucket_name: str = GCLOUD_BUCKET_NAME): + self.bucket_name = bucket_name + + def get_catalog(self): + """ + Get the list of available models + """ + # Initialize the storage client + return _model_catalogue.keys() + + def load_model(self, model_name: str, force_download=False): + """ + Load the model given the name + + Args: + model_name: str + Name of the model to load + force_download: bool (optional) + Whether to force the download of the freshest weights from gcloud + + Returns: + model: torch.nn.Module + Model initialized from the checkpoint + """ + # Find cache dir, use a directory inside of it as the checkpoint path + checkpoint_path = os.path.join(CACHE_PATH, _model_catalogue[model_name]["path"]) + # Make checkpoint directory if it does not exist + os.makedirs(os.path.dirname(checkpoint_path), exist_ok=True) + # Construct gcloud url + gcloud_url = os.path.join(GCLOUD_URL_NAME, _model_catalogue[model_name]['path']) + # Download the model from google cloud using requests (with tqdm timer) + response = requests.get(gcloud_url, stream=True) + total_size_in_bytes= int(response.headers.get('content-length', 0)) + block_size = 1024 # 1 Kibibyte + + # If force_download is true or the model has not yet been downloaded, grab it from gcloud + if force_download or not os.path.exists(checkpoint_path): + progress_bar = tqdm.tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True) + + print(f"Saving model to cache: {CACHE_PATH}") + with open(checkpoint_path, 'wb') as file: + for data in response.iter_content(block_size): + progress_bar.update(len(data)) + file.write(data) + + # Initialize the model and the configuration from the checkpoint + print("checkpoint_path", checkpoint_path) + ckpt = torch.load(checkpoint_path, map_location="cpu") + + # Initialize the model from the specified initialization function + model = _model_catalogue[model_name]["init_fn"]() + + + # Load the model from the checkpoint + model.load_state_dict(ckpt['model'], strict=True) + print('Model loaded successfully') + + return model + +model_factory = ModelFactory() \ No newline at end of file diff --git a/cwm/model/model_pretrain.py b/cwm/model/model_pretrain.py new file mode 100644 index 0000000000000000000000000000000000000000..199902c49b575b64ee986dc2efa7eaea15c07739 --- /dev/null +++ b/cwm/model/model_pretrain.py @@ -0,0 +1,827 @@ +from functools import partial +import torch +import torch.nn as nn +from timm.models.layers import trunc_normal_ as __call_trunc_normal_ + +from cwm.data.masking_generator import RotatedTableMaskingGenerator +from cwm.model.model_utils import Block, _cfg, PatchEmbed, get_sinusoid_encoding_table +import cwm.eval.Flow.masking_flow as masking +import cwm.utils as utils +# from external.raft_interface import RAFTInterface +import cwm.eval.Flow.generator as generator +import matplotlib.pyplot as plt +import torch.nn.functional as F +from cwm.eval.Flow import flow_utils +import cwm.model.keypoint_utils as keypoint_utils + +def trunc_normal_(tensor, mean=0., std=1.): + __call_trunc_normal_(tensor, mean=mean, std=std, a=-std, b=std) + + +def interpolate_pos_encoding(pos_embed, n_frames, h, w): + N = pos_embed.shape[1] + if N == (h * w * n_frames): + return pos_embed + old_h = old_w = int((N / n_frames) ** 0.5) + patch_pos_embed = pos_embed.view(1, n_frames, old_h, old_w, -1).flatten(0, 1).permute(0, 3, 1, 2) + + patch_pos_embed = F.interpolate( + patch_pos_embed, + size=(h, w), + mode='bilinear', + ) + return patch_pos_embed.permute(0, 2, 3, 1).flatten(0, 2).unsqueeze(0) + + +class PretrainVisionTransformerEncoder(nn.Module): + """ Vision Transformer with support for patch or hybrid CNN input stage + """ + + def __init__(self, img_size=224, patch_size=(16, 16), in_chans=3, num_classes=0, embed_dim=768, depth=12, + num_heads=12, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop_rate=0., attn_drop_rate=0., + drop_path_rate=0., norm_layer=nn.LayerNorm, init_values=None, tubelet_size=2, + num_frames=16, block_func=Block, k_bias=False, use_learnable_pos_emb=False, block_kwargs={}): + super().__init__() + self.num_classes = num_classes + self.num_features = self.embed_dim = embed_dim # num_features for consistency with other models + self.patch_size = (tubelet_size,) + patch_size + self.pt, self.ph, self.pw = self.patch_size + self.h = int(img_size / self.ph) + self.w = int(img_size / self.pw) + self.hw = self.h * self.w + self.dims = [self.h, self.w] + + self.patch_embed = PatchEmbed( + img_size=img_size, + patch_size=patch_size, + in_chans=in_chans, + embed_dim=embed_dim, + tubelet_size=tubelet_size, + num_frames=num_frames + ) + num_patches = self.patch_embed.num_patches + + self.num_patches = num_patches + self.num_frames = num_frames + + if use_learnable_pos_emb: + self.use_learnable_pos_emb = True + self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim)) + trunc_normal_(self.pos_embed, std=.02) + else: + # sine-cosine positional embeddings + self.use_learnable_pos_emb = False + self.pos_embed = get_sinusoid_encoding_table(num_patches, embed_dim) + + dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay rule + self.blocks = nn.ModuleList([ + block_func( + dim=embed_dim, in_dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, + qkv_bias=qkv_bias, qk_scale=qk_scale, drop=drop_rate, attn_drop=attn_drop_rate, + drop_path=dpr[i], norm_layer=norm_layer, init_values=init_values, **block_kwargs, k_bias=k_bias, + xla_flash=True) + for i in range(depth)]) + self.norm = norm_layer(embed_dim) + self.head = nn.Linear(embed_dim, num_classes) if num_classes > 0 else nn.Identity() + + self.apply(self._init_weights) + + def _init_weights(self, m): + if isinstance(m, nn.Linear): + nn.init.xavier_uniform_(m.weight) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm): + nn.init.constant_(m.bias, 0) + nn.init.constant_(m.weight, 1.0) + + def get_num_layers(self): + return len(self.blocks) + + @torch.jit.ignore + def no_weight_decay(self): + return {'pos_embed', 'cls_token'} + + def get_classifier(self): + return self.head + + def reset_classifier(self, num_classes, global_pool=''): + self.num_classes = num_classes + self.head = nn.Linear(self.embed_dim, num_classes) if num_classes > 0 else nn.Identity() + + def _get_pos_embed(self): + return self.pos_embed + + def forward_block(self, x, idx): + return self.blocks[idx](x) + + def forward_features(self, x, mask, move_pos=None, static_pos=None, movement=None, res=1): + + T = x.shape[2] + + x = embed = self.patch_embed(x) + pos_embed = self._get_pos_embed().type_as(x).to(x.device).clone() + + if not self.use_learnable_pos_emb: + pos_embed = pos_embed.detach() + + if res != 1: + print("res") + p0 = self.patch_size[-2] + p1 = self.patch_size[-1] + pos_embed = interpolate_pos_encoding(self.pos_embed, T, int(224 // p0 * res), int(224 // p1 * res)) + + x = x + pos_embed + B, _, C = x.shape + x_vis = x[~mask].reshape(B, -1, C) # ~mask means visible + + if move_pos is not None: + h, w = self.h, self.w + first_frame_emb = embed[:, :self.hw].view(B, h, w, C) # [B, h, w, C] + last_frame_pos_emb = pos_embed[:, -self.hw:].view(1, h, w, C).expand(B, -1, -1, -1) # [B, h, w, C] + denominator = torch.tensor([self.h, self.w]).view(1, 1, 2).to(x.device) + + new_pos = move_pos + movement # [B, P, 2] + move_pos = move_pos / denominator * 2 - 1 + new_pos = (new_pos / denominator).clamp(0, 1) * 2 - 1 # handle special case where new_pos is out of bounds + static_pos = static_pos / denominator * 2 - 1 + + moving_emb = utils.sample_embedding(first_frame_emb, move_pos, mode='nearest') # [B, P, C] + moving_pos_emb = utils.sample_embedding(last_frame_pos_emb, new_pos, mode='nearest') # [B, P, C] + + static_emb = utils.sample_embedding(first_frame_emb, static_pos, mode='nearest') # [B, P, C] + static_pos_emb = utils.sample_embedding(last_frame_pos_emb, static_pos, mode='nearest') # [B, P, C] + + x_vis = torch.cat([x_vis, moving_emb + moving_pos_emb, static_emb + static_pos_emb], dim=1) + + # assert B == 1, "Only support batch size 1 for now" + # for (px, py) in move_patches: + # idx = px * self.w + py + # dx, dy = delta + # nx, ny = px + dx, py + dy + # new_idx = nx * self.w + ny + (self.patch_embed.num_frames - 1) * (self.h * self.w) + # + # emb = embed[:, idx] + # pos_emb = pos_embed[:, new_idx] + # emb = emb + pos_emb + # x_vis = torch.cat([x_vis, emb[None]], 1) + + # if static_patches is not None: + # for (px, py) in static_patches: + # idx = px * self.w + py + # new_idx = px * self.w + py + (self.patch_embed.num_frames - 1) * (self.h * self.w) + # emb = embed[:, idx] + # pos_emb = pos_embed[:, new_idx] + # emb = emb + pos_emb + # x_vis = torch.cat([x_vis, emb[None]], 1) + + for blk in self.blocks: + x_vis = blk(x_vis) + + x_vis = self.norm(x_vis) + return x_vis + + def _set_inputs(self, *args, **kwargs): + pass + + def forward(self, x, mask, move_pos=None, static_pos=None, movement=None, res=1): + + self._set_inputs(x, mask) + x = self.forward_features(x, mask, move_pos, static_pos, movement, res=res) + x = self.head(x) + return x + + +class PretrainVisionTransformerDecoder(nn.Module): + """ Vision Transformer with support for patch or hybrid CNN input stage + """ + + def __init__(self, patch_size=(16, 16), num_classes=768, embed_dim=768, depth=12, + num_heads=12, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop_rate=0., attn_drop_rate=0., + drop_path_rate=0., norm_layer=nn.LayerNorm, init_values=None, block_func=Block, block_kwargs={}, + k_bias=False + ): + super().__init__() + + self.num_classes = num_classes + + self.num_features = self.embed_dim = embed_dim # num_features for consistency with other models + self.patch_size = patch_size + + dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay rule + self.blocks = nn.ModuleList([ + block_func( + dim=embed_dim, in_dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, + qk_scale=qk_scale, drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer, + init_values=init_values, **block_kwargs, k_bias=k_bias, + xla_flash=True) + for i in range(depth)]) + self.norm = norm_layer(embed_dim) + self.head = nn.Linear(embed_dim, num_classes) if num_classes > 0 else nn.Identity() + + self.apply(self._init_weights) + + def _init_weights(self, m): + if isinstance(m, nn.Linear): + nn.init.xavier_uniform_(m.weight) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm): + nn.init.constant_(m.bias, 0) + nn.init.constant_(m.weight, 1.0) + + def get_num_layers(self): + return len(self.blocks) + + @torch.jit.ignore + def no_weight_decay(self): + return {'pos_embed', 'cls_token'} + + def get_classifier(self): + return self.head + + def reset_classifier(self, num_classes, global_pool=''): + self.num_classes = num_classes + self.head = nn.Linear(self.embed_dim, num_classes) if num_classes > 0 else nn.Identity() + + def forward_block(self, x, idx): + return self.blocks[idx](x) + + def get_last_tokens(self, x, return_token_num): + if return_token_num > 0: + return self.head(self.norm(x[:, -return_token_num:])) + elif return_token_num == 0: + return self.head(self.norm(x))[:, x.size(1):] + else: + return self.head(self.norm(x)) + + def forward(self, x, return_token_num): + for blk in self.blocks: + x = blk(x) + + if return_token_num > 0: + x = self.head(self.norm(x[:, -return_token_num:])) # only return the mask tokens predict pixels + else: + x = self.head(self.norm(x)) + + return x + + +class PretrainVisionTransformer(nn.Module): + """ Vision Transformer with support for patch or hybrid CNN input stage + """ + default_input_kwargs = {'unnormalize': True} + + def __init__(self, + img_size=224, + patch_size=(16, 16), + encoder_func=PretrainVisionTransformerEncoder, + encoder_in_chans=3, + encoder_num_classes=0, + encoder_embed_dim=768, + encoder_depth=12, + encoder_num_heads=12, + encoder_block_func=Block, + encoder_block_kwargs={}, + decoder_num_classes=None, + # For pretraining this parameter isn't relevant but must be set according to tube&patch size + decoder_embed_dim=512, + decoder_depth=8, + decoder_num_heads=8, + decoder_block_func=Block, + decoder_block_kwargs={}, + mlp_ratio=4., + qkv_bias=False, + k_bias=False, + qk_scale=None, + num_frames=16, + drop_rate=0., + attn_drop_rate=0., + drop_path_rate=0., + norm_layer=nn.LayerNorm, + init_values=0., + tubelet_size=2, + use_flash_attention=False, + use_learnable_pos_emb=False, + **kwargs + ): + super().__init__() + + encoder_block_kwargs.update({'flash_attention': use_flash_attention}) + decoder_block_kwargs.update({'flash_attention': use_flash_attention}) + + self.tubelet_size = tubelet_size + num_classes = 3 * tubelet_size * ( + patch_size[0] * patch_size[1]) if decoder_num_classes is None else decoder_num_classes + + self.encoder = encoder_func( + img_size=img_size, + patch_size=patch_size, + in_chans=encoder_in_chans, + num_classes=encoder_num_classes, + embed_dim=encoder_embed_dim, + depth=encoder_depth, + num_heads=encoder_num_heads, + mlp_ratio=mlp_ratio, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + drop_rate=drop_rate, + attn_drop_rate=attn_drop_rate, + drop_path_rate=drop_path_rate, + norm_layer=norm_layer, + init_values=init_values, + tubelet_size=tubelet_size, + num_frames=num_frames, + block_func=encoder_block_func, + block_kwargs=encoder_block_kwargs, + use_learnable_pos_emb=use_learnable_pos_emb, + k_bias=k_bias, + **kwargs) + + self.decoder = PretrainVisionTransformerDecoder( + patch_size=patch_size, + num_classes=num_classes, + embed_dim=decoder_embed_dim, + depth=decoder_depth, + num_heads=decoder_num_heads, + mlp_ratio=mlp_ratio, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + drop_rate=drop_rate, + attn_drop_rate=attn_drop_rate, + drop_path_rate=drop_path_rate, + norm_layer=norm_layer, + init_values=init_values, + block_func=decoder_block_func, + k_bias=k_bias, + block_kwargs=decoder_block_kwargs) + + self.encoder_to_decoder = nn.Linear(encoder_embed_dim, decoder_embed_dim, bias=k_bias) + + self.mask_token = nn.Parameter(torch.zeros(1, 1, decoder_embed_dim)) + trunc_normal_(self.mask_token, std=.02) + + if use_learnable_pos_emb: + self.use_learnable_pos_emb = True + self.pos_embed = nn.Parameter(torch.zeros(self.encoder.num_patches, decoder_embed_dim)) + trunc_normal_(self.pos_embed, std=.02) + else: + self.use_learnable_pos_emb = False + self.pos_embed = get_sinusoid_encoding_table(self.encoder.num_patches, decoder_embed_dim) + + self.num_frames = num_frames + self.num_patches = self.encoder.num_patches + + if self.num_frames is not None: + self.num_patches_per_frame = self.num_patches // self.num_frames + else: + self.num_patches_per_frame = self.num_patches + + self.patch_size = self.encoder.patch_size + + if isinstance(img_size, int): + self.image_size = (img_size, img_size) + else: + assert hasattr(img_size, '__len__'), img_size + self.image_size = img_size + + # self.flow_interface = RAFTInterface() + + @property + def mask_size(self): + return (self.num_frames // self.patch_size[0], + self.image_size[-2] // self.patch_size[-2], + self.image_size[-1] // self.patch_size[-1]) + + def _init_weights(self, m): + if isinstance(m, nn.Linear): + nn.init.xavier_uniform_(m.weight) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm): + nn.init.constant_(m.bias, 0) + nn.init.constant_(m.weight, 1.0) + + def get_num_layers(self): + return len(self.blocks) + + @torch.jit.ignore + def no_weight_decay(self): + return {'pos_embed', 'cls_token', 'mask_token'} + + def adjust_input_resolution(self, H, W): + if self.image_size == [H, W]: + return + + patch_size = self.encoder.patch_size[-2:] + self.image_size = [H, W] + self.encoder.h = int(H / self.encoder.ph) + self.encoder.w = int(W / self.encoder.pw) + self.encoder.hw = self.encoder.h * self.encoder.w + self.encoder.dims = [self.encoder.h, self.encoder.w] + dims = [int(s / p) for s, p in zip(self.image_size, patch_size)] + self.encoder.pos_embed = utils.interpolate_pos_encoding(self.encoder.pos_embed, 3, dims[0], dims[1]) + print('pos_embed', self.encoder.pos_embed.shape) + self.pos_embed = utils.interpolate_pos_encoding(self.pos_embed, 3, dims[0], dims[1]) + + def forward(self, x, mask, forward_full=False, return_features=False, res=1, *args, **kwargs): + + _, _, T, _, _ = x.shape + self.device = x.device + + num_patches_per_frame = (x.shape[-1] // self.encoder.patch_size[1]) ** 2 + + x_vis = self.encoder(x, mask, res=res, *args, **kwargs) + + if return_features: + return x_vis + + x_vis = self.encoder_to_decoder(x_vis) # [B, N_vis, C_d] + B, N, C = x_vis.shape + + # add pos embedding + # if res != 1: + # p0 = self.patch_size[-2] + # p1 = self.patch_size[-1] + # pos_embed = interpolate_pos_encoding(self.pos_embed.unsqueeze(0), T, int(224 // p0 * res), int(224 // p1 * res)) + # else: + # pos_embed = self.pos_embed.unsqueeze(0) + + expand_pos_embed = self.pos_embed.expand(B, -1, -1).type_as(x).to(x.device).clone() + + if not self.use_learnable_pos_emb: + expand_pos_embed = expand_pos_embed.detach() + + pos_emd_vis = expand_pos_embed[~mask].reshape(B, -1, C) + pos_emd_mask = expand_pos_embed[mask].reshape(B, -1, C) + + nctx = num_patches_per_frame * (self.num_frames - 1) + + x_vis = x_vis + pos_emd_vis + + x_full = torch.cat([x_vis, self.mask_token + pos_emd_mask], dim=1) # [B, N, C_d] + + if forward_full: + x_full = torch.cat([x_vis, self.mask_token + expand_pos_embed[:, nctx:]], dim=1) # [B, N, C_d] + x_all = self.decoder(x_full, num_patches_per_frame) + x = x_all + else: + x = self.decoder(x_full, pos_emd_mask.shape[1]) # [B, N_mask, 3 * 16 * 16] + + return x + + def get_counterfactual(self, x, move_patches): + ''' + :param x: input tensor [1, C, T, H, W]: support only batch size 1 for now + :param move_patches: torch tensor [N, 4] sized array where each row contains patch motion [x1, y1, x2, y2] in pixel coordinates + :return: + ''' + B, _, T, H, H = x.shape + + mask = torch.ones(B, self.encoder.hw * self.encoder.num_frames).to(x.device).bool() + mask[:, :self.encoder.hw * (self.encoder.num_frames - 1)] = False + + move_patches = (move_patches/H)*self.encoder.h + move_patches = move_patches.to(torch.int64) + + for x1, y1, x2, y2 in move_patches: + idx2 = x2*self.encoder.w + y2 + (self.encoder.num_frames - 1) * (self.encoder.h * self.encoder.w) + mask[:, idx2] = False + im_x1 = x1*self.encoder.ph + im_y1 = y1*self.encoder.pw + im_x2 = x2*self.encoder.ph + im_y2 = y2*self.encoder.pw + x[:, :, -1, im_x2:im_x2+self.encoder.ph, im_y2:im_y2+self.encoder.pw] = x[:, :, -2, im_x1:im_x1+self.encoder.ph, im_y1:im_y1+self.encoder.pw] + + prediction = self.forward(x, mask, forward_full=True) + + prediction = utils.unpatchify_cwm( + prediction, + patch_size=self.encoder.patch_size[-1], + ) # reshape the output to an image + + return prediction + + + def get_directional_counterfactual(self, x, mask=None, move_pos=None, static_pos=None, movement=None, max_movement=None): + B, _, T, _, _ = x.shape + + if mask is None: # default mask: all visible but the last frame + mask = torch.ones(B, self.encoder.hw * self.encoder.num_frames).to(x.device).bool() + mask[:, :self.encoder.hw * (self.encoder.num_frames - 1)] = False + + if movement is None: # generate random motion if movement is not specified + assert max_movement is not None and move_pos is not None + movement = torch.randint(-max_movement, max_movement, move_pos.shape).to(x.device) # [B, num_samples, 2] + + x_vis = self.encoder(x, mask, move_pos=move_pos, static_pos=static_pos, movement=movement) # [B, N_vis, C_e] + x_vis = self.encoder_to_decoder(x_vis) # [B, N_vis, C_d] + B, N, C = x_vis.shape + expand_pos_embed = self.pos_embed.expand(B, -1, -1).type_as(x).to(x.device).clone().detach() + pos_emd_vis = expand_pos_embed[~mask].reshape(B, -1, C) + + if move_pos is not None: + h, w = self.encoder.h, self.encoder.w + last_frame_pos_emb = expand_pos_embed[:, -(h * w):].view(B, h, w, C) # [B, h, w, C] + + # compute new locations of the moved patche, snormalize positions to range [-1, 1] + new_pos = move_pos + movement # [B, P, 2] + denominator = torch.tensor([h, w]).view(1, 1, 2).to(x.device) + new_pos = (new_pos / denominator).clamp(0, 1) * 2 - 1 + static_pos = static_pos / denominator * 2 - 1 + + # sample the position embeddings of the moved and static patches + moving_pos_emb = utils.sample_embedding(last_frame_pos_emb, new_pos, mode='nearest') # [B, P, C] + static_pos_emb = utils.sample_embedding(last_frame_pos_emb, static_pos, mode='nearest') # [B, P, C] + + # concatenate with the position embeddings to the visible patches + pos_emd_vis = torch.cat([pos_emd_vis, moving_pos_emb, static_pos_emb], dim=1) + + # assert B == 1, "Only support batch size 1 for now" + # offset = (self.encoder.patch_embed.num_frames - 1) * (self.encoder.h * self.encoder.w) + # for (px, py) in move_patches: + # dx, dy = delta + # nx, ny = px + dx, py + dy + # new_idx = nx * self.encoder.w + ny + offset + # pos_emb = expand_pos_embed[:, new_idx] + # pos_emd_vis = torch.cat([pos_emd_vis, pos_emb[None]], 1) + # + # if static_patches is not None: + # for (px, py) in static_patches: + # new_idx = px * self.encoder.w + py + offset + # pos_emb = expand_pos_embed[:, new_idx] + # pos_emd_vis = torch.cat([pos_emd_vis, pos_emb[None]], 1) + + pos_emd_mask = expand_pos_embed[mask].reshape(B, -1, C) + x_vis = x_vis + pos_emd_vis + x_full = torch.cat([x_vis, self.mask_token + pos_emd_mask], dim=1) # [B, N, C_d] + x = self.decoder(x_full, pos_emd_mask.shape[1]) # [B, N_mask, 3 * 16 * 16] + + prediction = utils.unpatchify_cwm( + x, + patch_size=self.encoder.patch_size[-1], + mask=mask[:, -self.encoder.hw:] + ) # reshape the output to an image + + return prediction + + + @torch.no_grad() + def get_segment(self, x, mask=None, sampling_dist=None, num_segments=1, num_iters=4, num_samples=4, max_movement=4, + vis=True): + B, C, T, H, W = x.shape + N = num_samples + patch_size = self.encoder.patch_size[-1] + + self.adjust_input_resolution(H, W) + + # ## Step 0: define the sampling distribution for moving and static locations + # if sampling_dist is None: + # sampling_dist = utils.get_dino_predominance(x[:, :, 0], dims=self.encoder.dims, img_size=self.image_size)[0] + # sampling_dist = F.interpolate(sampling_dist, self.encoder.dims, mode='bilinear', align_corners=False) + # sampling_dist = sampling_dist.squeeze(1) ** 4 + # + # if vis: + # print('sampling_dist', sampling_dist.shape) + # plt.imshow(sampling_dist[0].cpu().numpy()) + # plt.title(f'Sampling distribution (max:{sampling_dist.max():.3f})') + # plt.show() + + ## Step 1: sample initial moving and static locations from the distribution + init_move_pos, init_static_pos, init_flow_mag, max_score = None, None, None, 0 + + # Sample multiple positions for each segment and select the one with consistent outputs + for _ in range(N): + # sample one moving position per example in the batch + move_pos = utils.sample_positions_from_dist(size=[1, 1], dist=sampling_dist).repeat(N, 1, 1) # [BN, 1, 2] + + # each move position has N static positions and movement directions + static_pos = utils.sample_positions_from_dist(size=[B * N, 1], dist=-sampling_dist) # [BN, 1, 2] + + ## compute initial flow maps + _x = x.repeat(N, 1, 1, 1, 1) # [BN, C, T, H, W] + pred = self.get_directional_counterfactual(_x, move_pos=move_pos, static_pos=static_pos, max_movement=max_movement) + flow, flow_mag = self.flow_interface(_x[:, :, 0].float(), pred.clamp(0, 1).float(), return_magnitude=True) + flow_mag = flow_mag.view(B, N, H, W) + scores = flow_mag.flatten(2, 3).std(dim=1).mean(-1) # [B, N] + print('scores', scores, flow_mag.shape) + if scores.mean(-1) > max_score: + init_move_pos, init_static_pos, init_flow_mag, max_score = move_pos, static_pos, flow_mag, scores + + # visualize samples + if vis: + fig, axs = plt.subplots(1, num_samples, figsize=(2 * num_samples, 2 * num_samples)) + + for i in range(num_samples): + move = move_pos[i, 0].cpu() + static = static_pos[i, 0].cpu() + flow_rgb = utils.flow_to_rgb(flow[i].cpu().permute(1, 2, 0)) + axs[i].imshow(flow_rgb) + axs[i].scatter(move[1] * patch_size, move[0] * patch_size, color='green', s=20) + axs[i].set_axis_off() + axs[i].scatter(static[1] * patch_size, static[0] * patch_size, color='red', s=20) + fig.subplots_adjust(wspace=0.01, hspace=0.01) # Change these values to adjust space + + plt.show() + plt.close() + + ## Step 2: iteratively add more moving and static locations to refine the segment + prev_flow_mag = init_flow_mag + prev_move_pos = init_move_pos + prev_static_pos = init_static_pos + npos_per_iter = 1 + for it in range(num_iters): + print('Iteration', it) + sampling_dist = F.interpolate(prev_flow_mag, size=self.encoder.dims, mode='bilinear').mean(1) + # sample one moving position per example in the batch + move_pos = utils.sample_positions_from_dist(size=[1, npos_per_iter], dist=sampling_dist).repeat(N, 1, 1) + move_pos = torch.cat([prev_move_pos, move_pos], dim=1) + + # each move position has N static positions and movement directions + static_pos = utils.sample_positions_from_dist(size=[B * N, npos_per_iter], + dist=-sampling_dist) # [BN, 1, 2] + static_pos = torch.cat([prev_static_pos, static_pos], dim=1) + + pred = self.get_directional_counterfactual(_x, move_pos=move_pos, static_pos=static_pos, max_movement=max_movement) + flow, flow_mag = self.flow_interface(_x[:, :, 0].float(), pred.clamp(0, 1).float(), return_magnitude=True) + flow_mag = flow_mag.view(B, N, H, W) + scores = flow_mag.flatten(2, 3).std(dim=1).mean(-1) # [B, N] + print('scores', scores, flow_mag.shape) + if scores.mean(-1) > max_score: + init_move_pos, init_static_pos, init_flow_mag, max_score = move_pos, static_pos, flow_mag, scores + + # visualize samples + if vis: + fig, axs = plt.subplots(1, num_samples, figsize=(2 * num_samples, 2 * num_samples)) + + for i in range(num_samples): + flow_rgb = utils.flow_to_rgb(flow[i].cpu().permute(1, 2, 0)) + + axs[i].imshow(flow_rgb) + axs[i].set_axis_off() + for k in range(move_pos.shape[1]): + move = move_pos[i, k].cpu() + static = static_pos[i, k].cpu() + axs[i].scatter(move[1] * patch_size, move[0] * patch_size, color='green', s=20) + axs[i].scatter(static[1] * patch_size, static[0] * patch_size, color='red', s=20) + fig.subplots_adjust(wspace=0.01, hspace=0.01) # Change these values to adjust space + + plt.show() + plt.close() + + ## Step 3: iterate to add more moving and static motions + return None + + @torch.no_grad() + def get_flow(self, img1, img2, conditioning_img=None, mode='jacobian', perturbation_patch_size=8, aggregation_patch_size=8, mask_ratio=0.0, num_scales=1, num_mask_samples=1): + ''' + :param img1: input image 1 [B, C, H, W] + :param img2: input image 2 [B, C, H, W] + :param mode: which flow extraction method to use: 'jacobian' or 'optical_flow + :param mask_ratio: what frame2 mask ratio to use when extracting flow + :return: forward flow [B, 2, H, W] + ''' + + + + if mode == 'jacobian': + frame_size = 224 // self.patch_size[-1] + DFG = generator.DerivativeFlowGenerator( + predictor=self, + perturbation_patch_size=perturbation_patch_size, + aggregation_patch_size=aggregation_patch_size, + agg_power=None, + agg_channel_func=lambda x: F.relu(x.sum(-3, True)), + num_samples=5, + average_jacobian=False, + leave_one_out_sampling=False, + imagenet_normalize_inputs=False, + temporal_dim=2, + confidence_thresh=None + ).to(img1.device) + + maskgen_uniform = masking.PytorchMaskGeneratorWrapper( + mask_generator=masking.RotatedTableMaskingGenerator, + input_size=(self.num_frames, frame_size, frame_size), + mask_ratio=mask_ratio + ).to(img1.device) + + + jac_fwd, forward_flow = flow_utils.extract_jacobians_and_flows(img1, img2, + DFG, + maskgen_uniform()[None]) + + else: + frame_size = 224 // self.patch_size[-1] + mask_generator = RotatedTableMaskingGenerator( + input_size=(self.num_frames, frame_size, frame_size), + mask_ratio=mask_ratio, + tube_length=1, + batch_size=1, + mask_type='rotated_table' + ) + + forward_flow, _ = flow_utils.scaling_fixed_get_vmae_optical_flow_crop_batched_smoothed(self, mask_generator, img1, img2, conditioning_img=conditioning_img, num_scales=num_scales, N_mask_samples=num_mask_samples) + + return forward_flow + + @torch.no_grad() + def get_keypoints(self, img1, img2, img3=None, num_keypoints=10, samples_per_keypoint=1): + ''' + :param img1: input image 1 [B, C, H, W] imagenet normalized + :param img2: input image 2 [B, C, H, W] imagenet normalized + :param num_keypoints: number of keypoints to extract + :param samples_per_keypoint: number of samples per keypoint + ''' + if self.num_frames == 2: + x = torch.stack([img1, img2], dim=2) + else: + if img3 is None: + x = torch.stack([img1, img1, img2], dim=2) + else: + x = torch.stack([img1, img2, img3], dim=2) + + mask, choices, err_array, feat, keypoint_recon = keypoint_utils.get_keypoints_batch(self, x, samples_per_keypoint, num_keypoints) + + return mask, choices, err_array, feat, keypoint_recon + +def pretrain_vit_base_224_scaffold(img_size=224, **kwargs): + model = PretrainVisionTransformer( + img_size=img_size, + encoder_embed_dim=768, + encoder_depth=12, + encoder_num_heads=12, + encoder_num_classes=0, + decoder_embed_dim=512, + decoder_num_heads=16, + decoder_depth=8, + mlp_ratio=4, + qkv_bias=True, + k_bias=True, + norm_layer=partial(nn.LayerNorm, eps=1e-6), + **kwargs) + model.default_cfg = _cfg() + return model + + +def pretrain_videomae_base_224_scaffold(**kwargs): + model = PretrainVisionTransformer( + img_size=224, + encoder_embed_dim=768, + encoder_depth=12, + encoder_num_heads=12, + encoder_num_classes=0, + decoder_embed_dim=384, + decoder_num_heads=6, + decoder_depth=4, + mlp_ratio=4, + qkv_bias=True, + norm_layer=partial(nn.LayerNorm, eps=1e-6), + **kwargs) + model.default_cfg = _cfg() + return model + + +def vitb_8x8patch_3frames(**kwargs): + model = pretrain_vit_base_224_scaffold( + patch_size=(8, 8), + num_frames=3, + tubelet_size=1, + use_flash_attention=True, + **kwargs) + return model + + +def vitb_8x8patch_2frames(**kwargs): + model = pretrain_vit_base_224_scaffold( + patch_size=(8, 8), + num_frames=2, + tubelet_size=1, + use_flash_attention=True, + **kwargs) + return model + +def vitb_8x8patch_2frames_vmae(**kwargs): + model = pretrain_videomae_base_224_scaffold( + patch_size=(8, 8), + num_frames=2, + tubelet_size=1, + use_flash_attention=True, + **kwargs) + return model + +def vitb_4x4patch_2frames(**kwargs): + model = pretrain_videomae_base_224_scaffold( + patch_size=(4, 4), + num_frames=2, + tubelet_size=1, + **kwargs) + return model + +# def base_8x8patch_2frames_1tube(**kwargs): +# model = pretrain_videomae_base_224_scaffold( +# patch_size=(8, 8), +# num_frames=2, +# tubelet_size=1, +# **kwargs) +# return model diff --git a/cwm/model/model_utils.py b/cwm/model/model_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..5b7af6bcea77d9ca902998a76f69449bd1309896 --- /dev/null +++ b/cwm/model/model_utils.py @@ -0,0 +1,188 @@ +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from timm.models.layers import drop_path, to_2tuple + + +def _cfg(url='', **kwargs): + return { + 'url': url, + 'num_classes': 400, 'input_size': (3, 224, 224), 'pool_size': None, + 'crop_pct': .9, 'interpolation': 'bicubic', + 'mean': (0.5, 0.5, 0.5), 'std': (0.5, 0.5, 0.5), + **kwargs + } + + +class DropPath(nn.Module): + """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks). + """ + def __init__(self, drop_prob=None): + super(DropPath, self).__init__() + self.drop_prob = drop_prob + + def forward(self, x): + return drop_path(x, self.drop_prob, self.training) + + def extra_repr(self) -> str: + return 'p={}'.format(self.drop_prob) + + +class Mlp(nn.Module): + def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.): + super().__init__() + out_features = out_features or in_features + hidden_features = hidden_features or in_features + self.fc1 = nn.Linear(in_features, hidden_features) + self.act = act_layer() + self.fc2 = nn.Linear(hidden_features, out_features) + self.drop = nn.Dropout(drop) + + def forward(self, x): + x = self.fc1(x) + x = self.act(x) + # x = self.drop(x) + # commit this for the orignal BERT implement + x = self.fc2(x) + x = self.drop(x) + return x + + +class Attention(nn.Module): + def __init__( + self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., + proj_drop=0., attn_head_dim=None, flash_attention=False, k_bias=False, legacy=True, xla_flash=False): + super().__init__() + self.num_heads = num_heads + head_dim = dim // num_heads + if attn_head_dim is not None: + head_dim = attn_head_dim + all_head_dim = head_dim * self.num_heads + self.scale = qk_scale or head_dim ** -0.5 + self.legacy = legacy + + self.xla_flash = xla_flash + self.qkv = nn.Linear(dim, all_head_dim * 3, bias=False) + + if qkv_bias: + self.q_bias = nn.Parameter(torch.zeros(all_head_dim)) + self.v_bias = nn.Parameter(torch.zeros(all_head_dim)) + if k_bias: + self.k_bias = nn.Parameter(torch.zeros(all_head_dim)) + else: + self.k_bias = None + else: + self.q_bias = None + self.v_bias = None + self.k_bias = None + + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(all_head_dim, dim) + self.proj_drop = nn.Dropout(proj_drop) + + def forward(self, x): + B, N, C = x.shape + qkv_bias = None + if self.q_bias is not None: + if self.k_bias is not None: + qkv_bias = torch.cat((self.q_bias, self.k_bias, self.v_bias)) + else: + qkv_bias = torch.cat((self.q_bias, torch.zeros_like(self.v_bias, requires_grad=False), self.v_bias)) + + qkv = F.linear(input=x, weight=self.qkv.weight, bias=qkv_bias) + qkv = qkv.reshape(B, N, 3, self.num_heads, -1).permute(2, 0, 3, 1, 4) + q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple) + + x = F.scaled_dot_product_attention(q, k, v, dropout_p=self.attn_drop.p) + x = x.transpose(1, 2).reshape(B, N, -1) + x = self.proj(x) + x = self.proj_drop(x) + return x + + +class Block(nn.Module): + + def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0., + drop_path=0., init_values=None, act_layer=nn.GELU, norm_layer=nn.LayerNorm, + attn_head_dim=None, in_dim=None, flash_attention=False, k_bias=False, legacy=False, xla_flash=False): + super().__init__() + self.norm1 = norm_layer(dim) + + self.attn = Attention( + dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, + attn_drop=attn_drop, proj_drop=drop, attn_head_dim=attn_head_dim, flash_attention=flash_attention, k_bias=k_bias, legacy=legacy, xla_flash=xla_flash) + # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here + self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() + self.norm2 = norm_layer(dim) + mlp_hidden_dim = int(dim * mlp_ratio) + self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop) + + if (init_values or 0) > 0: + self.gamma_1 = nn.Parameter(init_values * torch.ones((dim)),requires_grad=True) + self.gamma_2 = nn.Parameter(init_values * torch.ones((dim)),requires_grad=True) + else: + self.gamma_1, self.gamma_2 = None, None + + def forward(self, x): + if self.gamma_1 is None: + x = x + self.drop_path(self.attn(self.norm1(x))) + x = x + self.drop_path(self.mlp(self.norm2(x))) + else: + x = x + self.drop_path(self.gamma_1 * self.attn(self.norm1(x))) + x = x + self.drop_path(self.gamma_2 * self.mlp(self.norm2(x))) + return x + + +class PatchEmbed(nn.Module): + """ Image to Patch Embedding + """ + def __init__(self, img_size=224, patch_size=(16, 16), in_chans=3, embed_dim=768, num_frames=16, tubelet_size=2): + super().__init__() + img_size = to_2tuple(img_size) + + self.tubelet_size = int(tubelet_size) + if num_frames is not None: + self.num_frames = int(num_frames) + self.num_patches = (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0]) * (num_frames // self.tubelet_size) + else: + self.num_frames = None + self.num_patches = None + self.img_size = img_size + self.patch_size = patch_size + self.embed_dim = embed_dim + + self.proj = nn.Conv3d(in_channels=in_chans, out_channels=embed_dim, + kernel_size = (self.tubelet_size, patch_size[0],patch_size[1]), + stride=(self.tubelet_size, patch_size[0], patch_size[1])) + + def forward(self, x, **kwargs): + # B, C, T, H, W = x.shape + # FIXME look at relaxing size constraints + # assert H == self.img_size[0] and W == self.img_size[1], \ + # f"Input image size ({H}*{W}) doesn't match model ({self.img_size[0]}*{self.img_size[1]})." + x = self.proj(x).flatten(2).transpose(1, 2) + return x + +# sin-cos position encoding +# https://github.com/jadore801120/attention-is-all-you-need-pytorch/blob/master/transformer/Models.py#L31 +def get_sinusoid_encoding_table(positions, + d_hid, + apply_sinusoid=True): + ''' Sinusoid position encoding table ''' + # TODO: make it with torch instead of numpy + def get_position_angle_vec(position): + return [position / np.power(10000, 2 * (hid_j // 2) / d_hid) for hid_j in range(d_hid)] + + if isinstance(positions, int): + sinusoid_table = np.array([get_position_angle_vec(pos_i) for pos_i in range(positions)]) + else: + assert hasattr(positions, '__len__') + sinusoid_table = np.array([get_position_angle_vec(pos_i) for pos_i in positions]) + if apply_sinusoid: + sinusoid_table[:, 0::2] = np.sin(sinusoid_table[:, 0::2]) # dim 2i + sinusoid_table[:, 1::2] = np.cos(sinusoid_table[:, 1::2]) # dim 2i+1 + + return torch.FloatTensor(sinusoid_table).unsqueeze(0) + + diff --git a/cwm/optim_factory.py b/cwm/optim_factory.py new file mode 100644 index 0000000000000000000000000000000000000000..921a6cfad87667d817b0a9c8b1e5cefa3cccd18f --- /dev/null +++ b/cwm/optim_factory.py @@ -0,0 +1,183 @@ +import torch +from torch import optim as optim + +from timm.optim.adafactor import Adafactor +from timm.optim.adahessian import Adahessian +from timm.optim.adamp import AdamP +from timm.optim.lookahead import Lookahead +from timm.optim.nadam import Nadam +# from timm.optim.novograd import NovoGrad +# from timm.optim.nvnovograd import NvNovoGrad +from timm.optim.radam import RAdam +from timm.optim.rmsprop_tf import RMSpropTF +from timm.optim.sgdp import SGDP + +import json + +if torch.cuda.device_count() > 0: + use_tpu = False +else: + import torch_xla.core.xla_model as xm + print = xm.master_print + use_tpu = True + +try: + from apex.optimizers import FusedNovoGrad, FusedAdam, FusedLAMB, FusedSGD + has_apex = True +except ImportError: + has_apex = False + + +def get_num_layer_for_vit(var_name, num_max_layer): + if var_name in ("cls_token", "mask_token", "pos_embed"): + return 0 + elif var_name.startswith("patch_embed"): + return 0 + elif var_name.startswith("rel_pos_bias"): + return num_max_layer - 1 + elif var_name.startswith("blocks"): + layer_id = int(var_name.split('.')[1]) + return layer_id + 1 + else: + return num_max_layer - 1 + + +class LayerDecayValueAssigner(object): + def __init__(self, values): + self.values = values + + def get_scale(self, layer_id): + return self.values[layer_id] + + def get_layer_id(self, var_name): + return get_num_layer_for_vit(var_name, len(self.values)) + + +def get_parameter_groups(model, weight_decay=1e-5, skip_list=(), get_num_layer=None, get_layer_scale=None): + parameter_group_names = {} + parameter_group_vars = {} + all_names = [] + for name, param in model.named_parameters(): + if not param.requires_grad: + continue # frozen weights + if len(param.shape) == 1 or name.endswith(".bias") or name in skip_list: + group_name = "no_decay" + this_weight_decay = 0. + else: + group_name = "decay" + this_weight_decay = weight_decay + if get_num_layer is not None: + layer_id = get_num_layer(name) + group_name = "layer_%d_%s" % (layer_id, group_name) + else: + layer_id = None + + if group_name not in parameter_group_names: + if get_layer_scale is not None: + scale = get_layer_scale(layer_id) + else: + scale = 1. + + parameter_group_names[group_name] = { + "weight_decay": this_weight_decay, + "params": [], + "lr_scale": scale + } + parameter_group_vars[group_name] = { + "weight_decay": this_weight_decay, + "params": [], + "lr_scale": scale + } + + parameter_group_vars[group_name]["params"].append(param) + parameter_group_names[group_name]["params"].append(name) + + all_names.append(name) + # print("Param groups = %s" % json.dumps(parameter_group_names, indent=2)) + + return list(parameter_group_vars.values()) + + +def create_optimizer(args, model, get_num_layer=None, get_layer_scale=None, filter_bias_and_bn=True, skip_list=None): + opt_lower = args.opt.lower() + weight_decay = args.weight_decay + if weight_decay and filter_bias_and_bn: + skip = {} + if skip_list is not None: + skip = skip_list + elif hasattr(model, 'no_weight_decay'): + skip = model.no_weight_decay() + parameters = get_parameter_groups(model, weight_decay, skip, get_num_layer, get_layer_scale) + weight_decay = 0. + else: + parameters = model.parameters() + + if 'fused' in opt_lower: + assert has_apex and torch.cuda.is_available(), 'APEX and CUDA required for fused optimizers' + + opt_args = dict(lr=args.lr, weight_decay=weight_decay) + if hasattr(args, 'opt_eps') and args.opt_eps is not None: + opt_args['eps'] = args.opt_eps + if hasattr(args, 'opt_betas') and args.opt_betas is not None: + opt_args['betas'] = args.opt_betas + + opt_split = opt_lower.split('_') + opt_lower = opt_split[-1] + if opt_lower == 'sgd' or opt_lower == 'nesterov': + opt_args.pop('eps', None) + optimizer = optim.SGD(parameters, momentum=args.momentum, nesterov=True, **opt_args) + elif opt_lower == 'momentum': + opt_args.pop('eps', None) + optimizer = optim.SGD(parameters, momentum=args.momentum, nesterov=False, **opt_args) + elif opt_lower == 'adam': + optimizer = optim.Adam(parameters, **opt_args) + elif opt_lower == 'adamw': + optimizer = optim.AdamW(parameters, **opt_args) + elif opt_lower == 'nadam': + optimizer = Nadam(parameters, **opt_args) + elif opt_lower == 'radam': + optimizer = RAdam(parameters, **opt_args) + elif opt_lower == 'adamp': + optimizer = AdamP(parameters, wd_ratio=0.01, nesterov=True, **opt_args) + elif opt_lower == 'sgdp': + optimizer = SGDP(parameters, momentum=args.momentum, nesterov=True, **opt_args) + elif opt_lower == 'adadelta': + optimizer = optim.Adadelta(parameters, **opt_args) + elif opt_lower == 'adafactor': + if not args.lr: + opt_args['lr'] = None + optimizer = Adafactor(parameters, **opt_args) + elif opt_lower == 'adahessian': + optimizer = Adahessian(parameters, **opt_args) + elif opt_lower == 'rmsprop': + optimizer = optim.RMSprop(parameters, alpha=0.9, momentum=args.momentum, **opt_args) + elif opt_lower == 'rmsproptf': + optimizer = RMSpropTF(parameters, alpha=0.9, momentum=args.momentum, **opt_args) + # elif opt_lower == 'novograd': + # optimizer = NovoGrad(parameters, **opt_args) + # elif opt_lower == 'nvnovograd': + # optimizer = NvNovoGrad(parameters, **opt_args) + elif opt_lower == 'fusedsgd': + opt_args.pop('eps', None) + optimizer = FusedSGD(parameters, momentum=args.momentum, nesterov=True, **opt_args) + elif opt_lower == 'fusedmomentum': + opt_args.pop('eps', None) + optimizer = FusedSGD(parameters, momentum=args.momentum, nesterov=False, **opt_args) + elif opt_lower == 'fusedadam': + optimizer = FusedAdam(parameters, adam_w_mode=False, **opt_args) + elif opt_lower == 'fusedadamw': + optimizer = FusedAdam(parameters, adam_w_mode=True, **opt_args) + elif opt_lower == 'fusedlamb': + optimizer = FusedLAMB(parameters, **opt_args) + elif opt_lower == 'fusednovograd': + opt_args.setdefault('betas', (0.95, 0.98)) + optimizer = FusedNovoGrad(parameters, **opt_args) + else: + assert False and "Invalid optimizer" + raise ValueError + + if len(opt_split) > 1: + if opt_split[0] == 'lookahead': + optimizer = Lookahead(optimizer) + + return optimizer diff --git a/cwm/raft_core/__init__.py b/cwm/raft_core/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/raft_core/corr.py b/cwm/raft_core/corr.py new file mode 100644 index 0000000000000000000000000000000000000000..32e847bb1f63c81e7ea88a4f173e0e96f5fad5fc --- /dev/null +++ b/cwm/raft_core/corr.py @@ -0,0 +1,91 @@ +import torch +import torch.nn.functional as F +from .utils.utils import bilinear_sampler, coords_grid + +try: + import alt_cuda_corr +except: + # alt_cuda_corr is not compiled + pass + + +class CorrBlock: + def __init__(self, fmap1, fmap2, num_levels=4, radius=4): + self.num_levels = num_levels + self.radius = radius + self.corr_pyramid = [] + + # all pairs correlation + corr = CorrBlock.corr(fmap1, fmap2) + + batch, h1, w1, dim, h2, w2 = corr.shape + corr = corr.reshape(batch*h1*w1, dim, h2, w2) + + self.corr_pyramid.append(corr) + for i in range(self.num_levels-1): + corr = F.avg_pool2d(corr, 2, stride=2) + self.corr_pyramid.append(corr) + + def __call__(self, coords): + r = self.radius + coords = coords.permute(0, 2, 3, 1) + batch, h1, w1, _ = coords.shape + + out_pyramid = [] + for i in range(self.num_levels): + corr = self.corr_pyramid[i] + dx = torch.linspace(-r, r, 2*r+1, device=coords.device) + dy = torch.linspace(-r, r, 2*r+1, device=coords.device) + delta = torch.stack(torch.meshgrid(dy, dx), axis=-1) + + centroid_lvl = coords.reshape(batch*h1*w1, 1, 1, 2) / 2**i + delta_lvl = delta.view(1, 2*r+1, 2*r+1, 2) + coords_lvl = centroid_lvl + delta_lvl + + corr = bilinear_sampler(corr, coords_lvl) + corr = corr.view(batch, h1, w1, -1) + out_pyramid.append(corr) + + out = torch.cat(out_pyramid, dim=-1) + return out.permute(0, 3, 1, 2).contiguous().float() + + @staticmethod + def corr(fmap1, fmap2): + batch, dim, ht, wd = fmap1.shape + fmap1 = fmap1.view(batch, dim, ht*wd) + fmap2 = fmap2.view(batch, dim, ht*wd) + + corr = torch.matmul(fmap1.transpose(1,2), fmap2) + corr = corr.view(batch, ht, wd, 1, ht, wd) + return corr / torch.sqrt(torch.tensor(dim).float()) + + +class AlternateCorrBlock: + def __init__(self, fmap1, fmap2, num_levels=4, radius=4): + self.num_levels = num_levels + self.radius = radius + + self.pyramid = [(fmap1, fmap2)] + for i in range(self.num_levels): + fmap1 = F.avg_pool2d(fmap1, 2, stride=2) + fmap2 = F.avg_pool2d(fmap2, 2, stride=2) + self.pyramid.append((fmap1, fmap2)) + + def __call__(self, coords): + coords = coords.permute(0, 2, 3, 1) + B, H, W, _ = coords.shape + dim = self.pyramid[0][0].shape[1] + + corr_list = [] + for i in range(self.num_levels): + r = self.radius + fmap1_i = self.pyramid[0][0].permute(0, 2, 3, 1).contiguous() + fmap2_i = self.pyramid[i][1].permute(0, 2, 3, 1).contiguous() + + coords_i = (coords / 2**i).reshape(B, 1, H, W, 2).contiguous() + corr, = alt_cuda_corr.forward(fmap1_i, fmap2_i, coords_i, r) + corr_list.append(corr.squeeze(1)) + + corr = torch.stack(corr_list, dim=1) + corr = corr.reshape(B, -1, H, W) + return corr / torch.sqrt(torch.tensor(dim).float()) diff --git a/cwm/raft_core/datasets.py b/cwm/raft_core/datasets.py new file mode 100644 index 0000000000000000000000000000000000000000..3411fdacfb900024005e8997d07c600e963a95ca --- /dev/null +++ b/cwm/raft_core/datasets.py @@ -0,0 +1,235 @@ +# Data loading based on https://github.com/NVIDIA/flownet2-pytorch + +import numpy as np +import torch +import torch.utils.data as data +import torch.nn.functional as F + +import os +import math +import random +from glob import glob +import os.path as osp + +from utils import frame_utils +from utils.augmentor import FlowAugmentor, SparseFlowAugmentor + + +class FlowDataset(data.Dataset): + def __init__(self, aug_params=None, sparse=False): + self.augmentor = None + self.sparse = sparse + if aug_params is not None: + if sparse: + self.augmentor = SparseFlowAugmentor(**aug_params) + else: + self.augmentor = FlowAugmentor(**aug_params) + + self.is_test = False + self.init_seed = False + self.flow_list = [] + self.image_list = [] + self.extra_info = [] + + def __getitem__(self, index): + + if self.is_test: + img1 = frame_utils.read_gen(self.image_list[index][0]) + img2 = frame_utils.read_gen(self.image_list[index][1]) + img1 = np.array(img1).astype(np.uint8)[..., :3] + img2 = np.array(img2).astype(np.uint8)[..., :3] + img1 = torch.from_numpy(img1).permute(2, 0, 1).float() + img2 = torch.from_numpy(img2).permute(2, 0, 1).float() + return img1, img2, self.extra_info[index] + + if not self.init_seed: + worker_info = torch.utils.data.get_worker_info() + if worker_info is not None: + torch.manual_seed(worker_info.id) + np.random.seed(worker_info.id) + random.seed(worker_info.id) + self.init_seed = True + + index = index % len(self.image_list) + valid = None + if self.sparse: + flow, valid = frame_utils.readFlowKITTI(self.flow_list[index]) + else: + flow = frame_utils.read_gen(self.flow_list[index]) + + img1 = frame_utils.read_gen(self.image_list[index][0]) + img2 = frame_utils.read_gen(self.image_list[index][1]) + + flow = np.array(flow).astype(np.float32) + img1 = np.array(img1).astype(np.uint8) + img2 = np.array(img2).astype(np.uint8) + + # grayscale images + if len(img1.shape) == 2: + img1 = np.tile(img1[...,None], (1, 1, 3)) + img2 = np.tile(img2[...,None], (1, 1, 3)) + else: + img1 = img1[..., :3] + img2 = img2[..., :3] + + if self.augmentor is not None: + if self.sparse: + img1, img2, flow, valid = self.augmentor(img1, img2, flow, valid) + else: + img1, img2, flow = self.augmentor(img1, img2, flow) + + img1 = torch.from_numpy(img1).permute(2, 0, 1).float() + img2 = torch.from_numpy(img2).permute(2, 0, 1).float() + flow = torch.from_numpy(flow).permute(2, 0, 1).float() + + if valid is not None: + valid = torch.from_numpy(valid) + else: + valid = (flow[0].abs() < 1000) & (flow[1].abs() < 1000) + + return img1, img2, flow, valid.float() + + + def __rmul__(self, v): + self.flow_list = v * self.flow_list + self.image_list = v * self.image_list + return self + + def __len__(self): + return len(self.image_list) + + +class MpiSintel(FlowDataset): + def __init__(self, aug_params=None, split='training', root='datasets/Sintel', dstype='clean'): + super(MpiSintel, self).__init__(aug_params) + flow_root = osp.join(root, split, 'flow') + image_root = osp.join(root, split, dstype) + + if split == 'test': + self.is_test = True + + for scene in os.listdir(image_root): + image_list = sorted(glob(osp.join(image_root, scene, '*.png'))) + for i in range(len(image_list)-1): + self.image_list += [ [image_list[i], image_list[i+1]] ] + self.extra_info += [ (scene, i) ] # scene and frame_id + + if split != 'test': + self.flow_list += sorted(glob(osp.join(flow_root, scene, '*.flo'))) + + +class FlyingChairs(FlowDataset): + def __init__(self, aug_params=None, split='train', root='datasets/FlyingChairs_release/data'): + super(FlyingChairs, self).__init__(aug_params) + + images = sorted(glob(osp.join(root, '*.ppm'))) + flows = sorted(glob(osp.join(root, '*.flo'))) + assert (len(images)//2 == len(flows)) + + split_list = np.loadtxt('chairs_split.txt', dtype=np.int32) + for i in range(len(flows)): + xid = split_list[i] + if (split=='training' and xid==1) or (split=='validation' and xid==2): + self.flow_list += [ flows[i] ] + self.image_list += [ [images[2*i], images[2*i+1]] ] + + +class FlyingThings3D(FlowDataset): + def __init__(self, aug_params=None, root='datasets/FlyingThings3D', dstype='frames_cleanpass'): + super(FlyingThings3D, self).__init__(aug_params) + + for cam in ['left']: + for direction in ['into_future', 'into_past']: + image_dirs = sorted(glob(osp.join(root, dstype, 'TRAIN/*/*'))) + image_dirs = sorted([osp.join(f, cam) for f in image_dirs]) + + flow_dirs = sorted(glob(osp.join(root, 'optical_flow/TRAIN/*/*'))) + flow_dirs = sorted([osp.join(f, direction, cam) for f in flow_dirs]) + + for idir, fdir in zip(image_dirs, flow_dirs): + images = sorted(glob(osp.join(idir, '*.png')) ) + flows = sorted(glob(osp.join(fdir, '*.pfm')) ) + for i in range(len(flows)-1): + if direction == 'into_future': + self.image_list += [ [images[i], images[i+1]] ] + self.flow_list += [ flows[i] ] + elif direction == 'into_past': + self.image_list += [ [images[i+1], images[i]] ] + self.flow_list += [ flows[i+1] ] + + +class KITTI(FlowDataset): + def __init__(self, aug_params=None, split='training', root='datasets/KITTI'): + super(KITTI, self).__init__(aug_params, sparse=True) + if split == 'testing': + self.is_test = True + + root = osp.join(root, split) + images1 = sorted(glob(osp.join(root, 'image_2/*_10.png'))) + images2 = sorted(glob(osp.join(root, 'image_2/*_11.png'))) + + for img1, img2 in zip(images1, images2): + frame_id = img1.split('/')[-1] + self.extra_info += [ [frame_id] ] + self.image_list += [ [img1, img2] ] + + if split == 'training': + self.flow_list = sorted(glob(osp.join(root, 'flow_occ/*_10.png'))) + + +class HD1K(FlowDataset): + def __init__(self, aug_params=None, root='datasets/HD1k'): + super(HD1K, self).__init__(aug_params, sparse=True) + + seq_ix = 0 + while 1: + flows = sorted(glob(os.path.join(root, 'hd1k_flow_gt', 'flow_occ/%06d_*.png' % seq_ix))) + images = sorted(glob(os.path.join(root, 'hd1k_input', 'image_2/%06d_*.png' % seq_ix))) + + if len(flows) == 0: + break + + for i in range(len(flows)-1): + self.flow_list += [flows[i]] + self.image_list += [ [images[i], images[i+1]] ] + + seq_ix += 1 + + +def fetch_dataloader(args, TRAIN_DS='C+T+K+S+H'): + """ Create the data loader for the corresponding trainign set """ + + if args.stage == 'chairs': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.1, 'max_scale': 1.0, 'do_flip': True} + train_dataset = FlyingChairs(aug_params, split='training') + + elif args.stage == 'things': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.4, 'max_scale': 0.8, 'do_flip': True} + clean_dataset = FlyingThings3D(aug_params, dstype='frames_cleanpass') + final_dataset = FlyingThings3D(aug_params, dstype='frames_finalpass') + train_dataset = clean_dataset + final_dataset + + elif args.stage == 'sintel': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.2, 'max_scale': 0.6, 'do_flip': True} + things = FlyingThings3D(aug_params, dstype='frames_cleanpass') + sintel_clean = MpiSintel(aug_params, split='training', dstype='clean') + sintel_final = MpiSintel(aug_params, split='training', dstype='final') + + if TRAIN_DS == 'C+T+K+S+H': + kitti = KITTI({'crop_size': args.image_size, 'min_scale': -0.3, 'max_scale': 0.5, 'do_flip': True}) + hd1k = HD1K({'crop_size': args.image_size, 'min_scale': -0.5, 'max_scale': 0.2, 'do_flip': True}) + train_dataset = 100*sintel_clean + 100*sintel_final + 200*kitti + 5*hd1k + things + + elif TRAIN_DS == 'C+T+K/S': + train_dataset = 100*sintel_clean + 100*sintel_final + things + + elif args.stage == 'kitti': + aug_params = {'crop_size': args.image_size, 'min_scale': -0.2, 'max_scale': 0.4, 'do_flip': False} + train_dataset = KITTI(aug_params, split='training') + + train_loader = data.DataLoader(train_dataset, batch_size=args.batch_size, + pin_memory=False, shuffle=True, num_workers=4, drop_last=True) + + print('Training with %d image pairs' % len(train_dataset)) + return train_loader + diff --git a/cwm/raft_core/extractor.py b/cwm/raft_core/extractor.py new file mode 100644 index 0000000000000000000000000000000000000000..9a9c759d1243d4694e8656c2f6f8a37e53edd009 --- /dev/null +++ b/cwm/raft_core/extractor.py @@ -0,0 +1,267 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class ResidualBlock(nn.Module): + def __init__(self, in_planes, planes, norm_fn='group', stride=1): + super(ResidualBlock, self).__init__() + + self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, padding=1, stride=stride) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, padding=1) + self.relu = nn.ReLU(inplace=True) + + num_groups = planes // 8 + + if norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + self.norm2 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + if not stride == 1: + self.norm3 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + + elif norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(planes) + self.norm2 = nn.BatchNorm2d(planes) + if not stride == 1: + self.norm3 = nn.BatchNorm2d(planes) + + elif norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(planes) + self.norm2 = nn.InstanceNorm2d(planes) + if not stride == 1: + self.norm3 = nn.InstanceNorm2d(planes) + + elif norm_fn == 'none': + self.norm1 = nn.Sequential() + self.norm2 = nn.Sequential() + if not stride == 1: + self.norm3 = nn.Sequential() + + if stride == 1: + self.downsample = None + + else: + self.downsample = nn.Sequential( + nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride), self.norm3) + + + def forward(self, x): + y = x + y = self.relu(self.norm1(self.conv1(y))) + y = self.relu(self.norm2(self.conv2(y))) + + if self.downsample is not None: + x = self.downsample(x) + + return self.relu(x+y) + + + +class BottleneckBlock(nn.Module): + def __init__(self, in_planes, planes, norm_fn='group', stride=1): + super(BottleneckBlock, self).__init__() + + self.conv1 = nn.Conv2d(in_planes, planes//4, kernel_size=1, padding=0) + self.conv2 = nn.Conv2d(planes//4, planes//4, kernel_size=3, padding=1, stride=stride) + self.conv3 = nn.Conv2d(planes//4, planes, kernel_size=1, padding=0) + self.relu = nn.ReLU(inplace=True) + + num_groups = planes // 8 + + if norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=num_groups, num_channels=planes//4) + self.norm2 = nn.GroupNorm(num_groups=num_groups, num_channels=planes//4) + self.norm3 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + if not stride == 1: + self.norm4 = nn.GroupNorm(num_groups=num_groups, num_channels=planes) + + elif norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(planes//4) + self.norm2 = nn.BatchNorm2d(planes//4) + self.norm3 = nn.BatchNorm2d(planes) + if not stride == 1: + self.norm4 = nn.BatchNorm2d(planes) + + elif norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(planes//4) + self.norm2 = nn.InstanceNorm2d(planes//4) + self.norm3 = nn.InstanceNorm2d(planes) + if not stride == 1: + self.norm4 = nn.InstanceNorm2d(planes) + + elif norm_fn == 'none': + self.norm1 = nn.Sequential() + self.norm2 = nn.Sequential() + self.norm3 = nn.Sequential() + if not stride == 1: + self.norm4 = nn.Sequential() + + if stride == 1: + self.downsample = None + + else: + self.downsample = nn.Sequential( + nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride), self.norm4) + + + def forward(self, x): + y = x + y = self.relu(self.norm1(self.conv1(y))) + y = self.relu(self.norm2(self.conv2(y))) + y = self.relu(self.norm3(self.conv3(y))) + + if self.downsample is not None: + x = self.downsample(x) + + return self.relu(x+y) + +class BasicEncoder(nn.Module): + def __init__(self, output_dim=128, norm_fn='batch', dropout=0.0): + super(BasicEncoder, self).__init__() + self.norm_fn = norm_fn + + if self.norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=8, num_channels=64) + + elif self.norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(64) + + elif self.norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(64) + + elif self.norm_fn == 'none': + self.norm1 = nn.Sequential() + + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3) + self.relu1 = nn.ReLU(inplace=True) + + self.in_planes = 64 + self.layer1 = self._make_layer(64, stride=1) + self.layer2 = self._make_layer(96, stride=2) + self.layer3 = self._make_layer(128, stride=2) + + # output convolution + self.conv2 = nn.Conv2d(128, output_dim, kernel_size=1) + + self.dropout = None + if dropout > 0: + self.dropout = nn.Dropout2d(p=dropout) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, (nn.BatchNorm2d, nn.InstanceNorm2d, nn.GroupNorm)): + if m.weight is not None: + nn.init.constant_(m.weight, 1) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def _make_layer(self, dim, stride=1): + layer1 = ResidualBlock(self.in_planes, dim, self.norm_fn, stride=stride) + layer2 = ResidualBlock(dim, dim, self.norm_fn, stride=1) + layers = (layer1, layer2) + + self.in_planes = dim + return nn.Sequential(*layers) + + + def forward(self, x): + + # if input is list, combine batch dimension + is_list = isinstance(x, tuple) or isinstance(x, list) + if is_list: + batch_dim = x[0].shape[0] + x = torch.cat(x, dim=0) + + x = self.conv1(x) + x = self.norm1(x) + x = self.relu1(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + + x = self.conv2(x) + + if self.training and self.dropout is not None: + x = self.dropout(x) + + if is_list: + x = torch.split(x, [batch_dim, batch_dim], dim=0) + + return x + + +class SmallEncoder(nn.Module): + def __init__(self, output_dim=128, norm_fn='batch', dropout=0.0): + super(SmallEncoder, self).__init__() + self.norm_fn = norm_fn + + if self.norm_fn == 'group': + self.norm1 = nn.GroupNorm(num_groups=8, num_channels=32) + + elif self.norm_fn == 'batch': + self.norm1 = nn.BatchNorm2d(32) + + elif self.norm_fn == 'instance': + self.norm1 = nn.InstanceNorm2d(32) + + elif self.norm_fn == 'none': + self.norm1 = nn.Sequential() + + self.conv1 = nn.Conv2d(3, 32, kernel_size=7, stride=2, padding=3) + self.relu1 = nn.ReLU(inplace=True) + + self.in_planes = 32 + self.layer1 = self._make_layer(32, stride=1) + self.layer2 = self._make_layer(64, stride=2) + self.layer3 = self._make_layer(96, stride=2) + + self.dropout = None + if dropout > 0: + self.dropout = nn.Dropout2d(p=dropout) + + self.conv2 = nn.Conv2d(96, output_dim, kernel_size=1) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, (nn.BatchNorm2d, nn.InstanceNorm2d, nn.GroupNorm)): + if m.weight is not None: + nn.init.constant_(m.weight, 1) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def _make_layer(self, dim, stride=1): + layer1 = BottleneckBlock(self.in_planes, dim, self.norm_fn, stride=stride) + layer2 = BottleneckBlock(dim, dim, self.norm_fn, stride=1) + layers = (layer1, layer2) + + self.in_planes = dim + return nn.Sequential(*layers) + + + def forward(self, x): + + # if input is list, combine batch dimension + is_list = isinstance(x, tuple) or isinstance(x, list) + if is_list: + batch_dim = x[0].shape[0] + x = torch.cat(x, dim=0) + + x = self.conv1(x) + x = self.norm1(x) + x = self.relu1(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.conv2(x) + + if self.training and self.dropout is not None: + x = self.dropout(x) + + if is_list: + x = torch.split(x, [batch_dim, batch_dim], dim=0) + + return x diff --git a/cwm/raft_core/raft-kitti.pth b/cwm/raft_core/raft-kitti.pth new file mode 100644 index 0000000000000000000000000000000000000000..c4ded38c16a8db5a3409d2714051124843511b82 --- /dev/null +++ b/cwm/raft_core/raft-kitti.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9d170362415e1a27bd8402ee966a3ddf0d60df9b2df2c0b4949f5ced490a9e6 +size 21108000 diff --git a/cwm/raft_core/raft-sintel.pth b/cwm/raft_core/raft-sintel.pth new file mode 100644 index 0000000000000000000000000000000000000000..054ab495809cac00bb9290514ae141e034f8332c --- /dev/null +++ b/cwm/raft_core/raft-sintel.pth @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90630d2e7d488a0d3ccb5e8194524850c4c05c732ea4ff99799822c7fa5c5cbf +size 21108000 diff --git a/cwm/raft_core/raft.py b/cwm/raft_core/raft.py new file mode 100644 index 0000000000000000000000000000000000000000..72195a2ab3a277fed9545fe9bd6edeae9c5d25b5 --- /dev/null +++ b/cwm/raft_core/raft.py @@ -0,0 +1,268 @@ +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +from .update import BasicUpdateBlock, SmallUpdateBlock +from .extractor import BasicEncoder, SmallEncoder +from .corr import CorrBlock, AlternateCorrBlock +from .utils.utils import bilinear_sampler, coords_grid, upflow8 + +import argparse +from pathlib import Path + +try: + autocast = torch.cuda.amp.autocast +except: + # dummy autocast for PyTorch < 1.6 + class autocast: + def __init__(self, enabled): + pass + def __enter__(self): + pass + def __exit__(self, *args): + pass + +class Dummy: + def __init__(self, enabled): + pass + def __enter__(self): + pass + def __exit__(self, *args): + pass + +def get_args(cmd=None): + parser = argparse.ArgumentParser() + parser.add_argument('--corr_levels', type=int, default=4) + parser.add_argument('--corr_radius', type=int, default=4) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--mixed_precision', action='store_true') + parser.add_argument('--small', action='store_true') + parser.add_argument('--gpus', type=int, nargs='+', default=[0]) + + if cmd is None: + args = parser.parse_args() + else: + args = parser.parse_args(cmd) + return args + +def load_raft_model(load_path, + ignore_prefix=None, + multiframe=False, + scale_inputs=False, + **kwargs): + + path = Path(load_path) if load_path else None + + args = get_args("") + for k,v in kwargs.items(): + args.__setattr__(k,v) + args.multiframe = multiframe + args.scale_inputs = scale_inputs + + model = RAFT(args) + + if load_path is not None: + weight_dict = torch.load(load_path, map_location=torch.device("cpu")) + new_dict = dict() + for k in weight_dict.keys(): + if 'module' in k: + new_dict[k.replace('module.', '')] = weight_dict[k] + else: + new_dict[k] = weight_dict[k] + + if ignore_prefix is not None: + new_dict_1 = dict() + for k, v in new_dict.items(): + new_dict_1[k.replace(ignore_prefix, '')] = v + new_dict = new_dict_1 + + did_load = model.load_state_dict(new_dict, strict=False) + print(did_load, type(model).__name__, load_path) + else: + print("created a new %s with %d parameters" % ( + type(model).__name__, + sum([v.numel() for v in model.parameters()]))) + + return model + +def get_raft_flow(x, raft_model, iters=24, backward=False, t_dim=1): + assert len(x.shape) == 5, x.shape + assert x.shape[t_dim] >= 2, x.shape + x = x * 255.0 + inds = torch.tensor([0,1]).to(x.device) + x1, x2 = torch.index_select(x, t_dim, inds).unbind(t_dim) + if backward: + flow = raft_model(x2, x1, test_mode=True, iters=iters)[-1] + else: + flow = raft_model(x1, x2, test_mode=True, iters=iters)[-1] + + return flow + +class RAFT(nn.Module): + def __init__(self, args): + super(RAFT, self).__init__() + self.args = args + self.multiframe = self.args.multiframe + self.scale_inputs = self.args.scale_inputs + + if args.small: + self.hidden_dim = hdim = 96 + self.context_dim = cdim = 64 + args.corr_levels = 4 + args.corr_radius = 3 + + else: + self.hidden_dim = hdim = 128 + self.context_dim = cdim = 128 + args.corr_levels = 4 + args.corr_radius = 4 + + if 'dropout' not in self.args: + self.args.dropout = 0 + + if 'alternate_corr' not in self.args: + self.args.alternate_corr = False + + # feature network, context network, and update block + if args.small: + self.fnet = SmallEncoder(output_dim=128, norm_fn='instance', dropout=args.dropout) + self.cnet = SmallEncoder(output_dim=hdim+cdim, norm_fn='none', dropout=args.dropout) + self.update_block = SmallUpdateBlock(self.args, hidden_dim=hdim) + + else: + self.fnet = BasicEncoder(output_dim=256, norm_fn='instance', dropout=args.dropout) + self.cnet = BasicEncoder(output_dim=hdim+cdim, norm_fn='batch', dropout=args.dropout) + self.update_block = BasicUpdateBlock(self.args, hidden_dim=hdim) + + def freeze_bn(self): + for m in self.modules(): + if isinstance(m, nn.BatchNorm2d): + m.eval() + + def initialize_flow(self, img): + """ Flow is represented as difference between two coordinate grids flow = coords1 - coords0""" + N, C, H, W = img.shape + coords0 = coords_grid(N, H//8, W//8, device=img.device, dtype=img.dtype) + coords1 = coords_grid(N, H//8, W//8, device=img.device, dtype=img.dtype) + + # optical flow computed as difference: flow = coords1 - coords0 + return coords0, coords1 + + def upsample_flow(self, flow, mask): + """ Upsample flow field [H/8, W/8, 2] -> [H, W, 2] using convex combination """ + N, _, H, W = flow.shape + mask = mask.view(N, 1, 9, 8, 8, H, W) + mask = torch.softmax(mask, dim=2) + + up_flow = F.unfold(8 * flow, [3,3], padding=1) + up_flow = up_flow.view(N, 2, 9, 1, 1, H, W) + + up_flow = torch.sum(mask * up_flow, dim=2) + up_flow = up_flow.permute(0, 1, 4, 2, 5, 3) + return up_flow.reshape(N, 2, 8*H, 8*W) + + @property + def iters(self): + if getattr(self, '_iters', None) is None: + return None + return self._iters + @iters.setter + def iters(self, value=None): + self._iters = value + + def _forward_two_images( + self, + image1, image2, + iters=24, flow_init=None, + upsample=True, test_mode=True, **kwargs): + """ Estimate optical flow between pair of frames """ + if self.iters is not None: + iters = self.iters + + image1 = 2 * (image1 / 255.0) - 1.0 + image2 = 2 * (image2 / 255.0) - 1.0 + + image1 = image1.contiguous() + image2 = image2.contiguous() + + hdim = self.hidden_dim + cdim = self.context_dim + + # run the feature network + decorator = autocast(enabled=True) if \ + (self.args.mixed_precision or (image1.dtype in [torch.float16, torch.bfloat16])) \ + else Dummy(enabled=False) + with decorator: + fmap1, fmap2 = self.fnet([image1, image2]) + + fmap1 = fmap1.float() + fmap2 = fmap2.float() + if self.args.alternate_corr: + corr_fn = AlternateCorrBlock(fmap1, fmap2, radius=self.args.corr_radius) + else: + corr_fn = CorrBlock(fmap1, fmap2, radius=self.args.corr_radius) + + # run the context network + # with autocast(enabled=self.args.mixed_precision): + with decorator: + cnet = self.cnet(image1) + net, inp = torch.split(cnet, [hdim, cdim], dim=1) + net = torch.tanh(net) + inp = torch.relu(inp) + + coords0, coords1 = self.initialize_flow(image1) + + if flow_init is not None: + coords1 = coords1 + flow_init + + flow_predictions = [] + for itr in range(iters): + coords1 = coords1.detach() + corr = corr_fn(coords1) # index correlation volume + + flow = coords1 - coords0 + # with autocast(enabled=self.args.mixed_precision): + with decorator: + net, up_mask, delta_flow, motion_features = self.update_block(net, inp, corr, flow) + + + # F(t+1) = F(t) + \Delta(t) + coords1 = coords1 + delta_flow + + # upsample predictions + if up_mask is None: + flow_up = upflow8(coords1 - coords0) + else: + flow_up = self.upsample_flow(coords1 - coords0, up_mask) + + flow_predictions.append(flow_up) + + if test_mode: + return coords1 - coords0, flow_up, motion_features + + return flow_predictions, motion_features + + def forward(self, *args, **kwargs): + + if not self.multiframe: + return self._forward_two_images(*args, **kwargs) + x = (args[0] * 255.0) if self.scale_inputs else args[0] + assert len(x.shape) == 5, x.shape + assert x.shape[1] >= 2, x.shape + num_frames = x.size(1) + flows = [] + motion_features = [] + backward = kwargs.get('backward', False) + for t in range(num_frames-1): + x1, x2 = torch.index_select( + x, 1, torch.tensor([t,t+1]).to(x.device)).unbind(1) + _args = (x2, x1) if backward else (x1, x2) + _, flow, features = self._forward_two_images(*_args, *args[1:], **kwargs) + + flows.insert(0, flow) if backward else flows.append(flow) + motion_features.append(features) + + + return torch.stack(flows, 1), torch.stack(motion_features, 1) + diff --git a/cwm/raft_core/update.py b/cwm/raft_core/update.py new file mode 100644 index 0000000000000000000000000000000000000000..5fb35a80ac3b3505d876919242b14aac7a766c57 --- /dev/null +++ b/cwm/raft_core/update.py @@ -0,0 +1,139 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class FlowHead(nn.Module): + def __init__(self, input_dim=128, hidden_dim=256): + super(FlowHead, self).__init__() + self.conv1 = nn.Conv2d(input_dim, hidden_dim, 3, padding=1) + self.conv2 = nn.Conv2d(hidden_dim, 2, 3, padding=1) + self.relu = nn.ReLU(inplace=True) + + def forward(self, x): + return self.conv2(self.relu(self.conv1(x))) + +class ConvGRU(nn.Module): + def __init__(self, hidden_dim=128, input_dim=192+128): + super(ConvGRU, self).__init__() + self.convz = nn.Conv2d(hidden_dim+input_dim, hidden_dim, 3, padding=1) + self.convr = nn.Conv2d(hidden_dim+input_dim, hidden_dim, 3, padding=1) + self.convq = nn.Conv2d(hidden_dim+input_dim, hidden_dim, 3, padding=1) + + def forward(self, h, x): + hx = torch.cat([h, x], dim=1) + + z = torch.sigmoid(self.convz(hx)) + r = torch.sigmoid(self.convr(hx)) + q = torch.tanh(self.convq(torch.cat([r*h, x], dim=1))) + + h = (1-z) * h + z * q + return h + +class SepConvGRU(nn.Module): + def __init__(self, hidden_dim=128, input_dim=192+128): + super(SepConvGRU, self).__init__() + self.convz1 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (1,5), padding=(0,2)) + self.convr1 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (1,5), padding=(0,2)) + self.convq1 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (1,5), padding=(0,2)) + + self.convz2 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (5,1), padding=(2,0)) + self.convr2 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (5,1), padding=(2,0)) + self.convq2 = nn.Conv2d(hidden_dim+input_dim, hidden_dim, (5,1), padding=(2,0)) + + + def forward(self, h, x): + # horizontal + hx = torch.cat([h, x], dim=1) + z = torch.sigmoid(self.convz1(hx)) + r = torch.sigmoid(self.convr1(hx)) + q = torch.tanh(self.convq1(torch.cat([r*h, x], dim=1))) + h = (1-z) * h + z * q + + # vertical + hx = torch.cat([h, x], dim=1) + z = torch.sigmoid(self.convz2(hx)) + r = torch.sigmoid(self.convr2(hx)) + q = torch.tanh(self.convq2(torch.cat([r*h, x], dim=1))) + h = (1-z) * h + z * q + + return h + +class SmallMotionEncoder(nn.Module): + def __init__(self, args): + super(SmallMotionEncoder, self).__init__() + cor_planes = args.corr_levels * (2*args.corr_radius + 1)**2 + self.convc1 = nn.Conv2d(cor_planes, 96, 1, padding=0) + self.convf1 = nn.Conv2d(2, 64, 7, padding=3) + self.convf2 = nn.Conv2d(64, 32, 3, padding=1) + self.conv = nn.Conv2d(128, 80, 3, padding=1) + + def forward(self, flow, corr): + cor = F.relu(self.convc1(corr)) + flo = F.relu(self.convf1(flow)) + flo = F.relu(self.convf2(flo)) + cor_flo = torch.cat([cor, flo], dim=1) + out = F.relu(self.conv(cor_flo)) + return torch.cat([out, flow], dim=1) + +class BasicMotionEncoder(nn.Module): + def __init__(self, args): + super(BasicMotionEncoder, self).__init__() + cor_planes = args.corr_levels * (2*args.corr_radius + 1)**2 + self.convc1 = nn.Conv2d(cor_planes, 256, 1, padding=0) + self.convc2 = nn.Conv2d(256, 192, 3, padding=1) + self.convf1 = nn.Conv2d(2, 128, 7, padding=3) + self.convf2 = nn.Conv2d(128, 64, 3, padding=1) + self.conv = nn.Conv2d(64+192, 128-2, 3, padding=1) + + def forward(self, flow, corr): + cor = F.relu(self.convc1(corr)) + cor = F.relu(self.convc2(cor)) + flo = F.relu(self.convf1(flow)) + flo = F.relu(self.convf2(flo)) + + cor_flo = torch.cat([cor, flo], dim=1) + out = F.relu(self.conv(cor_flo)) + return torch.cat([out, flow], dim=1) + +class SmallUpdateBlock(nn.Module): + def __init__(self, args, hidden_dim=96): + super(SmallUpdateBlock, self).__init__() + self.encoder = SmallMotionEncoder(args) + self.gru = ConvGRU(hidden_dim=hidden_dim, input_dim=82+64) + self.flow_head = FlowHead(hidden_dim, hidden_dim=128) + + def forward(self, net, inp, corr, flow): + motion_features = self.encoder(flow, corr) + inp = torch.cat([inp, motion_features], dim=1) + net = self.gru(net, inp) + delta_flow = self.flow_head(net) + + return net, None, delta_flow + +class BasicUpdateBlock(nn.Module): + def __init__(self, args, hidden_dim=128, input_dim=128): + super(BasicUpdateBlock, self).__init__() + self.args = args + self.encoder = BasicMotionEncoder(args) + self.gru = SepConvGRU(hidden_dim=hidden_dim, input_dim=128+hidden_dim) + self.flow_head = FlowHead(hidden_dim, hidden_dim=256) + + self.mask = nn.Sequential( + nn.Conv2d(128, 256, 3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d(256, 64*9, 1, padding=0)) + + def forward(self, net, inp, corr, flow, upsample=True): + motion_features = self.encoder(flow, corr) + inp = torch.cat([inp, motion_features], dim=1) + + net = self.gru(net, inp) + delta_flow = self.flow_head(net) + + # scale mask to balence gradients + mask = .25 * self.mask(net) + return net, mask, delta_flow, motion_features + + + diff --git a/cwm/raft_core/utils/__init__.py b/cwm/raft_core/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/cwm/raft_core/utils/augmentor.py b/cwm/raft_core/utils/augmentor.py new file mode 100644 index 0000000000000000000000000000000000000000..e81c4f2b5c16c31c0ae236d744f299d430228a04 --- /dev/null +++ b/cwm/raft_core/utils/augmentor.py @@ -0,0 +1,246 @@ +import numpy as np +import random +import math +from PIL import Image + +import cv2 +cv2.setNumThreads(0) +cv2.ocl.setUseOpenCL(False) + +import torch +from torchvision.transforms import ColorJitter +import torch.nn.functional as F + + +class FlowAugmentor: + def __init__(self, crop_size, min_scale=-0.2, max_scale=0.5, do_flip=True): + + # spatial augmentation params + self.crop_size = crop_size + self.min_scale = min_scale + self.max_scale = max_scale + self.spatial_aug_prob = 0.8 + self.stretch_prob = 0.8 + self.max_stretch = 0.2 + + # flip augmentation params + self.do_flip = do_flip + self.h_flip_prob = 0.5 + self.v_flip_prob = 0.1 + + # photometric augmentation params + self.photo_aug = ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4, hue=0.5/3.14) + self.asymmetric_color_aug_prob = 0.2 + self.eraser_aug_prob = 0.5 + + def color_transform(self, img1, img2): + """ Photometric augmentation """ + + # asymmetric + if np.random.rand() < self.asymmetric_color_aug_prob: + img1 = np.array(self.photo_aug(Image.fromarray(img1)), dtype=np.uint8) + img2 = np.array(self.photo_aug(Image.fromarray(img2)), dtype=np.uint8) + + # symmetric + else: + image_stack = np.concatenate([img1, img2], axis=0) + image_stack = np.array(self.photo_aug(Image.fromarray(image_stack)), dtype=np.uint8) + img1, img2 = np.split(image_stack, 2, axis=0) + + return img1, img2 + + def eraser_transform(self, img1, img2, bounds=[50, 100]): + """ Occlusion augmentation """ + + ht, wd = img1.shape[:2] + if np.random.rand() < self.eraser_aug_prob: + mean_color = np.mean(img2.reshape(-1, 3), axis=0) + for _ in range(np.random.randint(1, 3)): + x0 = np.random.randint(0, wd) + y0 = np.random.randint(0, ht) + dx = np.random.randint(bounds[0], bounds[1]) + dy = np.random.randint(bounds[0], bounds[1]) + img2[y0:y0+dy, x0:x0+dx, :] = mean_color + + return img1, img2 + + def spatial_transform(self, img1, img2, flow): + # randomly sample scale + ht, wd = img1.shape[:2] + min_scale = np.maximum( + (self.crop_size[0] + 8) / float(ht), + (self.crop_size[1] + 8) / float(wd)) + + scale = 2 ** np.random.uniform(self.min_scale, self.max_scale) + scale_x = scale + scale_y = scale + if np.random.rand() < self.stretch_prob: + scale_x *= 2 ** np.random.uniform(-self.max_stretch, self.max_stretch) + scale_y *= 2 ** np.random.uniform(-self.max_stretch, self.max_stretch) + + scale_x = np.clip(scale_x, min_scale, None) + scale_y = np.clip(scale_y, min_scale, None) + + if np.random.rand() < self.spatial_aug_prob: + # rescale the images + img1 = cv2.resize(img1, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + img2 = cv2.resize(img2, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + flow = cv2.resize(flow, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + flow = flow * [scale_x, scale_y] + + if self.do_flip: + if np.random.rand() < self.h_flip_prob: # h-flip + img1 = img1[:, ::-1] + img2 = img2[:, ::-1] + flow = flow[:, ::-1] * [-1.0, 1.0] + + if np.random.rand() < self.v_flip_prob: # v-flip + img1 = img1[::-1, :] + img2 = img2[::-1, :] + flow = flow[::-1, :] * [1.0, -1.0] + + y0 = np.random.randint(0, img1.shape[0] - self.crop_size[0]) + x0 = np.random.randint(0, img1.shape[1] - self.crop_size[1]) + + img1 = img1[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + img2 = img2[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + flow = flow[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + + return img1, img2, flow + + def __call__(self, img1, img2, flow): + img1, img2 = self.color_transform(img1, img2) + img1, img2 = self.eraser_transform(img1, img2) + img1, img2, flow = self.spatial_transform(img1, img2, flow) + + img1 = np.ascontiguousarray(img1) + img2 = np.ascontiguousarray(img2) + flow = np.ascontiguousarray(flow) + + return img1, img2, flow + +class SparseFlowAugmentor: + def __init__(self, crop_size, min_scale=-0.2, max_scale=0.5, do_flip=False): + # spatial augmentation params + self.crop_size = crop_size + self.min_scale = min_scale + self.max_scale = max_scale + self.spatial_aug_prob = 0.8 + self.stretch_prob = 0.8 + self.max_stretch = 0.2 + + # flip augmentation params + self.do_flip = do_flip + self.h_flip_prob = 0.5 + self.v_flip_prob = 0.1 + + # photometric augmentation params + self.photo_aug = ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.3/3.14) + self.asymmetric_color_aug_prob = 0.2 + self.eraser_aug_prob = 0.5 + + def color_transform(self, img1, img2): + image_stack = np.concatenate([img1, img2], axis=0) + image_stack = np.array(self.photo_aug(Image.fromarray(image_stack)), dtype=np.uint8) + img1, img2 = np.split(image_stack, 2, axis=0) + return img1, img2 + + def eraser_transform(self, img1, img2): + ht, wd = img1.shape[:2] + if np.random.rand() < self.eraser_aug_prob: + mean_color = np.mean(img2.reshape(-1, 3), axis=0) + for _ in range(np.random.randint(1, 3)): + x0 = np.random.randint(0, wd) + y0 = np.random.randint(0, ht) + dx = np.random.randint(50, 100) + dy = np.random.randint(50, 100) + img2[y0:y0+dy, x0:x0+dx, :] = mean_color + + return img1, img2 + + def resize_sparse_flow_map(self, flow, valid, fx=1.0, fy=1.0): + ht, wd = flow.shape[:2] + coords = np.meshgrid(np.arange(wd), np.arange(ht)) + coords = np.stack(coords, axis=-1) + + coords = coords.reshape(-1, 2).astype(np.float32) + flow = flow.reshape(-1, 2).astype(np.float32) + valid = valid.reshape(-1).astype(np.float32) + + coords0 = coords[valid>=1] + flow0 = flow[valid>=1] + + ht1 = int(round(ht * fy)) + wd1 = int(round(wd * fx)) + + coords1 = coords0 * [fx, fy] + flow1 = flow0 * [fx, fy] + + xx = np.round(coords1[:,0]).astype(np.int32) + yy = np.round(coords1[:,1]).astype(np.int32) + + v = (xx > 0) & (xx < wd1) & (yy > 0) & (yy < ht1) + xx = xx[v] + yy = yy[v] + flow1 = flow1[v] + + flow_img = np.zeros([ht1, wd1, 2], dtype=np.float32) + valid_img = np.zeros([ht1, wd1], dtype=np.int32) + + flow_img[yy, xx] = flow1 + valid_img[yy, xx] = 1 + + return flow_img, valid_img + + def spatial_transform(self, img1, img2, flow, valid): + # randomly sample scale + + ht, wd = img1.shape[:2] + min_scale = np.maximum( + (self.crop_size[0] + 1) / float(ht), + (self.crop_size[1] + 1) / float(wd)) + + scale = 2 ** np.random.uniform(self.min_scale, self.max_scale) + scale_x = np.clip(scale, min_scale, None) + scale_y = np.clip(scale, min_scale, None) + + if np.random.rand() < self.spatial_aug_prob: + # rescale the images + img1 = cv2.resize(img1, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + img2 = cv2.resize(img2, None, fx=scale_x, fy=scale_y, interpolation=cv2.INTER_LINEAR) + flow, valid = self.resize_sparse_flow_map(flow, valid, fx=scale_x, fy=scale_y) + + if self.do_flip: + if np.random.rand() < 0.5: # h-flip + img1 = img1[:, ::-1] + img2 = img2[:, ::-1] + flow = flow[:, ::-1] * [-1.0, 1.0] + valid = valid[:, ::-1] + + margin_y = 20 + margin_x = 50 + + y0 = np.random.randint(0, img1.shape[0] - self.crop_size[0] + margin_y) + x0 = np.random.randint(-margin_x, img1.shape[1] - self.crop_size[1] + margin_x) + + y0 = np.clip(y0, 0, img1.shape[0] - self.crop_size[0]) + x0 = np.clip(x0, 0, img1.shape[1] - self.crop_size[1]) + + img1 = img1[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + img2 = img2[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + flow = flow[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + valid = valid[y0:y0+self.crop_size[0], x0:x0+self.crop_size[1]] + return img1, img2, flow, valid + + + def __call__(self, img1, img2, flow, valid): + img1, img2 = self.color_transform(img1, img2) + img1, img2 = self.eraser_transform(img1, img2) + img1, img2, flow, valid = self.spatial_transform(img1, img2, flow, valid) + + img1 = np.ascontiguousarray(img1) + img2 = np.ascontiguousarray(img2) + flow = np.ascontiguousarray(flow) + valid = np.ascontiguousarray(valid) + + return img1, img2, flow, valid diff --git a/cwm/raft_core/utils/flow_viz.py b/cwm/raft_core/utils/flow_viz.py new file mode 100644 index 0000000000000000000000000000000000000000..dcee65e89b91b07ee0496aeb4c7e7436abf99641 --- /dev/null +++ b/cwm/raft_core/utils/flow_viz.py @@ -0,0 +1,132 @@ +# Flow visualization code used from https://github.com/tomrunia/OpticalFlow_Visualization + + +# MIT License +# +# Copyright (c) 2018 Tom Runia +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to conditions. +# +# Author: Tom Runia +# Date Created: 2018-08-03 + +import numpy as np + +def make_colorwheel(): + """ + Generates a color wheel for optical flow visualization as presented in: + Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007) + URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf + + Code follows the original C++ source code of Daniel Scharstein. + Code follows the the Matlab source code of Deqing Sun. + + Returns: + np.ndarray: Color wheel + """ + + RY = 15 + YG = 6 + GC = 4 + CB = 11 + BM = 13 + MR = 6 + + ncols = RY + YG + GC + CB + BM + MR + colorwheel = np.zeros((ncols, 3)) + col = 0 + + # RY + colorwheel[0:RY, 0] = 255 + colorwheel[0:RY, 1] = np.floor(255*np.arange(0,RY)/RY) + col = col+RY + # YG + colorwheel[col:col+YG, 0] = 255 - np.floor(255*np.arange(0,YG)/YG) + colorwheel[col:col+YG, 1] = 255 + col = col+YG + # GC + colorwheel[col:col+GC, 1] = 255 + colorwheel[col:col+GC, 2] = np.floor(255*np.arange(0,GC)/GC) + col = col+GC + # CB + colorwheel[col:col+CB, 1] = 255 - np.floor(255*np.arange(CB)/CB) + colorwheel[col:col+CB, 2] = 255 + col = col+CB + # BM + colorwheel[col:col+BM, 2] = 255 + colorwheel[col:col+BM, 0] = np.floor(255*np.arange(0,BM)/BM) + col = col+BM + # MR + colorwheel[col:col+MR, 2] = 255 - np.floor(255*np.arange(MR)/MR) + colorwheel[col:col+MR, 0] = 255 + return colorwheel + + +def flow_uv_to_colors(u, v, convert_to_bgr=False): + """ + Applies the flow color wheel to (possibly clipped) flow components u and v. + + According to the C++ source code of Daniel Scharstein + According to the Matlab source code of Deqing Sun + + Args: + u (np.ndarray): Input horizontal flow of shape [H,W] + v (np.ndarray): Input vertical flow of shape [H,W] + convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False. + + Returns: + np.ndarray: Flow visualization image of shape [H,W,3] + """ + flow_image = np.zeros((u.shape[0], u.shape[1], 3), np.uint8) + colorwheel = make_colorwheel() # shape [55x3] + ncols = colorwheel.shape[0] + rad = np.sqrt(np.square(u) + np.square(v)) + a = np.arctan2(-v, -u)/np.pi + fk = (a+1) / 2*(ncols-1) + k0 = np.floor(fk).astype(np.int32) + k1 = k0 + 1 + k1[k1 == ncols] = 0 + f = fk - k0 + for i in range(colorwheel.shape[1]): + tmp = colorwheel[:,i] + col0 = tmp[k0] / 255.0 + col1 = tmp[k1] / 255.0 + col = (1-f)*col0 + f*col1 + idx = (rad <= 1) + col[idx] = 1 - rad[idx] * (1-col[idx]) + col[~idx] = col[~idx] * 0.75 # out of range + # Note the 2-i => BGR instead of RGB + ch_idx = 2-i if convert_to_bgr else i + flow_image[:,:,ch_idx] = np.floor(255 * col) + return flow_image + + +def flow_to_image(flow_uv, clip_flow=None, convert_to_bgr=False): + """ + Expects a two dimensional flow image of shape. + + Args: + flow_uv (np.ndarray): Flow UV image of shape [H,W,2] + clip_flow (float, optional): Clip maximum of flow values. Defaults to None. + convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False. + + Returns: + np.ndarray: Flow visualization image of shape [H,W,3] + """ + assert flow_uv.ndim == 3, 'input flow must have three dimensions' + assert flow_uv.shape[2] == 2, 'input flow must have shape [H,W,2]' + if clip_flow is not None: + flow_uv = np.clip(flow_uv, 0, clip_flow) + u = flow_uv[:,:,0] + v = flow_uv[:,:,1] + rad = np.sqrt(np.square(u) + np.square(v)) + rad_max = np.max(rad) + epsilon = 1e-5 + u = u / (rad_max + epsilon) + v = v / (rad_max + epsilon) + return flow_uv_to_colors(u, v, convert_to_bgr) \ No newline at end of file diff --git a/cwm/raft_core/utils/frame_utils.py b/cwm/raft_core/utils/frame_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..6c491135efaffc25bd61ec3ecde99d236f5deb12 --- /dev/null +++ b/cwm/raft_core/utils/frame_utils.py @@ -0,0 +1,137 @@ +import numpy as np +from PIL import Image +from os.path import * +import re + +import cv2 +cv2.setNumThreads(0) +cv2.ocl.setUseOpenCL(False) + +TAG_CHAR = np.array([202021.25], np.float32) + +def readFlow(fn): + """ Read .flo file in Middlebury format""" + # Code adapted from: + # http://stackoverflow.com/questions/28013200/reading-middlebury-flow-files-with-python-bytes-array-numpy + + # WARNING: this will work on little-endian architectures (eg Intel x86) only! + # print 'fn = %s'%(fn) + with open(fn, 'rb') as f: + magic = np.fromfile(f, np.float32, count=1) + if 202021.25 != magic: + print('Magic number incorrect. Invalid .flo file') + return None + else: + w = np.fromfile(f, np.int32, count=1) + h = np.fromfile(f, np.int32, count=1) + # print 'Reading %d x %d flo file\n' % (w, h) + data = np.fromfile(f, np.float32, count=2*int(w)*int(h)) + # Reshape data into 3D array (columns, rows, bands) + # The reshape here is for visualization, the original code is (w,h,2) + return np.resize(data, (int(h), int(w), 2)) + +def readPFM(file): + file = open(file, 'rb') + + color = None + width = None + height = None + scale = None + endian = None + + header = file.readline().rstrip() + if header == b'PF': + color = True + elif header == b'Pf': + color = False + else: + raise Exception('Not a PFM file.') + + dim_match = re.match(rb'^(\d+)\s(\d+)\s$', file.readline()) + if dim_match: + width, height = map(int, dim_match.groups()) + else: + raise Exception('Malformed PFM header.') + + scale = float(file.readline().rstrip()) + if scale < 0: # little-endian + endian = '<' + scale = -scale + else: + endian = '>' # big-endian + + data = np.fromfile(file, endian + 'f') + shape = (height, width, 3) if color else (height, width) + + data = np.reshape(data, shape) + data = np.flipud(data) + return data + +def writeFlow(filename,uv,v=None): + """ Write optical flow to file. + + If v is None, uv is assumed to contain both u and v channels, + stacked in depth. + Original code by Deqing Sun, adapted from Daniel Scharstein. + """ + nBands = 2 + + if v is None: + assert(uv.ndim == 3) + assert(uv.shape[2] == 2) + u = uv[:,:,0] + v = uv[:,:,1] + else: + u = uv + + assert(u.shape == v.shape) + height,width = u.shape + f = open(filename,'wb') + # write the header + f.write(TAG_CHAR) + np.array(width).astype(np.int32).tofile(f) + np.array(height).astype(np.int32).tofile(f) + # arrange into matrix form + tmp = np.zeros((height, width*nBands)) + tmp[:,np.arange(width)*2] = u + tmp[:,np.arange(width)*2 + 1] = v + tmp.astype(np.float32).tofile(f) + f.close() + + +def readFlowKITTI(filename): + flow = cv2.imread(filename, cv2.IMREAD_ANYDEPTH|cv2.IMREAD_COLOR) + flow = flow[:,:,::-1].astype(np.float32) + flow, valid = flow[:, :, :2], flow[:, :, 2] + flow = (flow - 2**15) / 64.0 + return flow, valid + +def readDispKITTI(filename): + disp = cv2.imread(filename, cv2.IMREAD_ANYDEPTH) / 256.0 + valid = disp > 0.0 + flow = np.stack([-disp, np.zeros_like(disp)], -1) + return flow, valid + + +def writeFlowKITTI(filename, uv): + uv = 64.0 * uv + 2**15 + valid = np.ones([uv.shape[0], uv.shape[1], 1]) + uv = np.concatenate([uv, valid], axis=-1).astype(np.uint16) + cv2.imwrite(filename, uv[..., ::-1]) + + +def read_gen(file_name, pil=False): + ext = splitext(file_name)[-1] + if ext == '.png' or ext == '.jpeg' or ext == '.ppm' or ext == '.jpg': + return Image.open(file_name) + elif ext == '.bin' or ext == '.raw': + return np.load(file_name) + elif ext == '.flo': + return readFlow(file_name).astype(np.float32) + elif ext == '.pfm': + flow = readPFM(file_name).astype(np.float32) + if len(flow.shape) == 2: + return flow + else: + return flow[:, :, :-1] + return [] \ No newline at end of file diff --git a/cwm/raft_core/utils/utils.py b/cwm/raft_core/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..7d6db311b1857c204e52ce42715967712849e896 --- /dev/null +++ b/cwm/raft_core/utils/utils.py @@ -0,0 +1,90 @@ +import torch +import torch.nn.functional as F +import numpy as np +from scipy import interpolate + +MAX_DIM = 256 * 28 * 28 + + +class InputPadder: + """ Pads images such that dimensions are divisible by 8 """ + def __init__(self, dims, mode='sintel'): + self.ht, self.wd = dims[-2:] + pad_ht = (((self.ht // 8) + 1) * 8 - self.ht) % 8 + pad_wd = (((self.wd // 8) + 1) * 8 - self.wd) % 8 + if mode == 'sintel': + self._pad = [pad_wd//2, pad_wd - pad_wd//2, pad_ht//2, pad_ht - pad_ht//2] + else: + self._pad = [pad_wd//2, pad_wd - pad_wd//2, 0, pad_ht] + + def pad(self, *inputs): + return [F.pad(x, self._pad, mode='replicate') for x in inputs] + + def unpad(self,x): + ht, wd = x.shape[-2:] + c = [self._pad[2], ht-self._pad[3], self._pad[0], wd-self._pad[1]] + return x[..., c[0]:c[1], c[2]:c[3]] + +def forward_interpolate(flow): + flow = flow.detach().cpu().numpy() + dx, dy = flow[0], flow[1] + + ht, wd = dx.shape + x0, y0 = np.meshgrid(np.arange(wd), np.arange(ht)) + + x1 = x0 + dx + y1 = y0 + dy + + x1 = x1.reshape(-1) + y1 = y1.reshape(-1) + dx = dx.reshape(-1) + dy = dy.reshape(-1) + + valid = (x1 > 0) & (x1 < wd) & (y1 > 0) & (y1 < ht) + x1 = x1[valid] + y1 = y1[valid] + dx = dx[valid] + dy = dy[valid] + + flow_x = interpolate.griddata( + (x1, y1), dx, (x0, y0), method='nearest', fill_value=0) + + flow_y = interpolate.griddata( + (x1, y1), dy, (x0, y0), method='nearest', fill_value=0) + + flow = np.stack([flow_x, flow_y], axis=0) + return torch.from_numpy(flow).float() + + +def bilinear_sampler(img, coords, mode='bilinear', mask=False): + """ Wrapper for grid_sample, uses pixel coordinates """ + H, W = img.shape[-2:] + xgrid, ygrid = coords.split([1,1], dim=-1) + xgrid = 2*xgrid/(W-1) - 1 + ygrid = 2*ygrid/(H-1) - 1 + + grid = torch.cat([xgrid, ygrid], dim=-1).to(img.dtype) + if img.size(0) >= MAX_DIM: + split_size = img.size(0) // 2 + imgs, grids = torch.split(img, split_size, dim=0), torch.split(grid, split_size, dim=0) + img = torch.cat([F.grid_sample(imgs[i], grids[i], align_corners=True) + for i in range(len(imgs))], 0) + else: + img = F.grid_sample(img, grid, align_corners=True) + + if mask: + mask = (xgrid > -1) & (ygrid > -1) & (xgrid < 1) & (ygrid < 1) + return img, mask.to(img.dtype) + + return img + + +def coords_grid(batch, ht, wd, device, dtype=torch.float32): + coords = torch.meshgrid(torch.arange(ht, device=device), torch.arange(wd, device=device)) + coords = torch.stack(coords[::-1], dim=0).to(dtype) + return coords[None].repeat(batch, 1, 1, 1) + + +def upflow8(flow, mode='bilinear'): + new_size = (8 * flow.shape[2], 8 * flow.shape[3]) + return 8 * F.interpolate(flow, size=new_size, mode=mode, align_corners=True) diff --git a/cwm/run_pretraining.py b/cwm/run_pretraining.py new file mode 100644 index 0000000000000000000000000000000000000000..34345e7390d052fd242444987cc762e2a79e759c --- /dev/null +++ b/cwm/run_pretraining.py @@ -0,0 +1,242 @@ + +import argparse +import datetime +import numpy as np +import random +import time +import torch +import json +import os +from pathlib import Path +from optim_factory import create_optimizer +from torch.nn.parallel import DistributedDataParallel as DDP +from utils import NativeScalerWithGradNormCount as NativeScaler +import utils +from cwm.data.dataset_utils import build_pretraining_dataset +from cwm.model import model_pretrain +from engine_for_pretraining import train_one_epoch +import wandb +import torch.backends.cudnn as cudnn +np.random.seed(0) +random.seed(0) + +def get_args(): + parser = argparse.ArgumentParser('CWM pre-training script', add_help=False) + + # training parameters + parser.add_argument('--batch_size', default=64, type=int, help='per-GPU batch-size') + parser.add_argument('--epochs', default=800, type=int, help='number of training epochs') + parser.add_argument('--save_ckpt_freq', default=50, type=int, help='save checkpoint frequency') + parser.add_argument('--print_freq', default=1, type=int, help='frequency of printing training stats') + parser.add_argument('--accum_iter', default=1, type=int, help='number of steps to accumulate gradients') + parser.add_argument('--eval', action='store_true', help='evaluation mode') + parser.add_argument('--output_dir', default='', help='path where to save, empty for no saving') + parser.add_argument('--log_dir', default=None, help='path where to tensorboard log') + parser.add_argument('--device', default='cuda', help='device to use for training / testing') + parser.add_argument('--seed', default=0, type=int) + parser.add_argument('--val_after', default=50, type=int) + parser.add_argument('--resume', default='', help='resume from checkpoint') + parser.add_argument('--start_epoch', default=0, type=int, metavar='N', help='start epoch') + parser.add_argument('--use_wandb', action='store_true', help='use wandb for logging') + + # Model parameters + parser.add_argument('--model', default='vitb_8x8patch_3frames', type=str, help='Name of model to train') + parser.add_argument('--context_frames', type=int, default=2, help='number of frames model will see densely') + parser.add_argument('--target_frames', type=int, default=1, help='number of frames model will see sparsely') + parser.add_argument('--temporal_units', type=str, default='ms', help='the units in which time is defined') + parser.add_argument('--sampling_rate', type=int, default=150, help='temporal gap between context/target frames') + parser.add_argument('--context_target_gap', type=int, nargs='+', default=[150, 150], help='gap between context/target') + + # Masking and target parameters + parser.add_argument('--mask_type', default='rotated_table', type=str, help='masked strategy') + parser.add_argument('--mask_ratio', default=0.75, type=float, help='masking ratio') + parser.add_argument('--mask_kwargs', default='', type=json.loads, help='extra arguments for masking generator') + parser.add_argument('--drop_path', type=float, default=0.0, metavar='PCT', help='Drop path rate (default: 0.1)') + + # Optimizer parameters + parser.add_argument('--opt', default='adamw', type=str, metavar='OPTIMIZER', help='Optimizer (default:adamw)') + parser.add_argument('--opt_eps', default=1e-8, type=float, metavar='EPSILON', help='Optimizer epsilon') + parser.add_argument('--opt_betas', default=None, type=float, nargs='+', metavar='BETA', help='Optimizer Betas') + parser.add_argument('--momentum', type=float, default=0.9, metavar='M', help='SGD momentum (default: 0.9)') + parser.add_argument('--weight_decay', type=float, default=0.05, help='weight decay (default: 0.05)') + parser.add_argument('--weight_decay_end', type=float, default=0.05, help='Final value of the weight decay.') + parser.add_argument('--lr', type=float, default=1.5e-4, metavar='LR', help='learning rate (default: 1.5e-4)') + parser.add_argument('--warmup_lr', type=float, default=1e-6, metavar='LR', help='warmup learning rate') + parser.add_argument('--min_lr', type=float, default=0, metavar='LR', help='lower lr bound for cyclic schedulers)') + parser.add_argument('--warmup_epochs', type=int, default=40, metavar='N', help='epochs to warmup LR') + parser.add_argument('--warmup_steps', type=int, default=-1, metavar='N', help='steps to warmup LR') + + # Dataset parameters + parser.add_argument('--data_path', default='/path/to/list_kinetics-400', type=str, help='dataset path') + parser.add_argument('--data_path_list', type=str, nargs='+', default=None, help='[path1, path2, path3, ...]') + parser.add_argument('--num_workers', default=10, type=int) + + # Augmentation parameters + parser.add_argument('--augmentation_type', type=str, default='multiscale', choices=['multiscale', 'center', 'none']) + parser.add_argument('--augmentation_scales', type=float, nargs='+', default=[1.0, 0.875, 0.75, 0.66]) + + + # distributed training parameters + parser.add_argument('--world_size', default=1, type=int, help='number of distributed processes') + parser.add_argument('--local_rank', default=-1, type=int) + parser.add_argument('--dist_on_itp', action='store_true') + parser.add_argument('--dist_url', default='env://', help='url used to set up distributed training') + + return parser.parse_args() + + +# Assuming 'model' is your PyTorch model +def export_model_parameters(model): + with open('model_parameters.txt', 'w') as f: + for name, param in model.named_parameters(): + f.write(f"{name} {param.size()}\n") + + +def main(args): + ## Setup distributed training + utils.init_distributed_mode(args) + cudnn.benchmark = True + device = torch.device(args.device) + num_tasks = utils.get_world_size() + sampler_rank = global_rank = utils.get_rank() + world_size = utils.get_world_size() + + ## Fix the seed for reproducibility + seed = args.seed + utils.get_rank() + torch.manual_seed(seed) + np.random.seed(seed) + + ## Initialize model + model = getattr(model_pretrain, args.model)() + args.input_size = int(model.encoder.patch_embed.img_size[0]) + args.tubelet_size = model.patch_size[0] + + args.mask_input_size = ( + (args.context_frames + args.target_frames) // args.tubelet_size, + args.input_size // model.patch_size[-2], + args.input_size // model.patch_size[-1], + ) + + ## Prepare datasets + dataset_train = build_pretraining_dataset(args) + + sampler_train = torch.utils.data.DistributedSampler( + dataset_train, + num_replicas=num_tasks, + rank=sampler_rank, + shuffle=True, + drop_last=True + ) + + data_loader_train = torch.utils.data.DataLoader( + dataset_train, + sampler=sampler_train, + batch_size=args.batch_size, + num_workers=args.num_workers, + pin_memory=True, drop_last=True, + worker_init_fn=utils.seed_worker, + ) + + num_steps_per_epoch = len(dataset_train) // args.batch_size // num_tasks + + n_params, n_params_str = utils.get_model_num_parameters(model) + + total_batch_size = args.batch_size * world_size * args.accum_iter + + ## LR and warmup + export_model_parameters(model) + + model = DDP(model.to(device), device_ids=[args.gpu], find_unused_parameters=False) + + ## Optimizer, loss scaler + optimizer = create_optimizer(args, model.module) + loss_scaler = NativeScaler() + + ## LR scheduler, WD scheduler + args.lr = args.lr * total_batch_size / 256 + args.min_lr = args.min_lr * total_batch_size / 256 + args.warmup_lr = args.warmup_lr * total_batch_size / 256 + + lr_schedule_values = utils.cosine_scheduler( + args.lr, args.min_lr, args.epochs, num_steps_per_epoch, + warmup_epochs=args.warmup_epochs, warmup_steps=args.warmup_steps, + ) + + wd_schedule_values = utils.cosine_scheduler( + args.weight_decay, args.weight_decay_end, args.epochs, num_steps_per_epoch + ) + + ## Resume from checkpoint, if any + utils.auto_load_model(args=args, model=model, optimizer=optimizer, loss_scaler=loss_scaler) + + ## Print training arguments + print("world size: %d" % args.world_size) + print("model: %s" % args.model) + print("image size: %s" % str(args.input_size)) + print("patch size: %s" % str(model.module.encoder.patch_embed.patch_size[-2:])) + print("context frames: %s" % str(args.context_frames)) + print("target frames: %s" % str(args.target_frames)) + print("per-device batch size: %d" % total_batch_size) + print("total batch size: %d" % total_batch_size) + print("grad accumulation: %d" % args.accum_iter) + print("dataset length: %d" % len(dataset_train)) + print("steps per epoch: %d" % num_steps_per_epoch) + print("num parameters: %s" % n_params_str) + print("lr: %.8f" % args.lr) + + ## Setup logging + if args.use_wandb and utils.is_main_process(): + wandb.init(project="cwm", name=args.output_dir.split('/')[-1], config=args) + + + print(f'start training at epoch {args.start_epoch} for {args.epochs} epochs') + start_time = time.time() + + for epoch in range(args.start_epoch, args.epochs): + + if args.distributed: + data_loader_train.sampler.set_epoch(epoch) + + # Run one epoch + train_stats = train_one_epoch( + model, data_loader_train, optimizer, device, epoch, loss_scaler, + start_steps=epoch * num_steps_per_epoch, + lr_schedule_values=lr_schedule_values, + wd_schedule_values=wd_schedule_values, + args=args, + global_rank=global_rank, + ) + + # Save checkpoint + if args.output_dir and ((epoch + 1) % args.save_ckpt_freq == 0 or epoch + 1 == args.epochs): + utils.save_model(args=args, model=model, optimizer=optimizer, loss_scaler=loss_scaler, epoch=epoch) + + # Logging + start_time = time.time() + do_write = (global_rank == 0) if args.use_xla else utils.is_main_process() + if args.output_dir and do_write: + log_stats = { + **{f'train/{k}': v for k, v in train_stats.items()}, + 'epoch': epoch, + 'params': n_params, + 'epoch_time': time.time() - start_time + } + + with open(os.path.join(args.output_dir, "log.txt"), mode="a", encoding="utf-8") as f: + f.write(json.dumps(log_stats) + "\n") + + if args.use_wandb: + wandb.log(log_stats) + + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('Training time {}'.format(total_time_str)) + + +if __name__ == '__main__': + opts = get_args() + + if opts.output_dir: + Path(opts.output_dir).mkdir(parents=True, exist_ok=True) + + main(opts) diff --git a/cwm/utils.py b/cwm/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..be702f264e56f9de37a56f32ff08bd7241e7712b --- /dev/null +++ b/cwm/utils.py @@ -0,0 +1,733 @@ +import datetime +import io +import os +import random +import sys +import time +from collections import defaultdict, deque +from pathlib import Path + +import matplotlib +import numpy as np +import torch +import torch.distributed as dist +import torch.nn.functional as F +from einops import rearrange +from timm.data.constants import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD +from timm.utils import get_state_dict +from torch import inf + +# sys.path.append(os.path.join(os.environ['HOME'], '.cache/torch/CutLER')) +# sys.path.append(os.path.join(os.environ['HOME'], '.cache/torch/CutLER/maskcut')) +# sys.path.append(os.path.join(os.environ['HOME'], '.cache/torch/CutLER/third_party')) +# import dino +# from maskcut import get_affinity_matrix, second_smallest_eigenvector, get_salient_areas, check_num_fg_corners, get_masked_affinity_matrix +# +# #from maskcut import get_affinity_matrix, second_smallest_eigenvector, get_salient_areas, check_num_fg_corners +# # DINO hyperparameters +# global dino_backbone +# dino_backbone = None + +def patchify(x, tubelet_size, patch_size): + ''' + :param x: [B, C, T, H, W] + :param tubelet_size: 2 + :param patch_size: (8, 8) + :return: + ''' + videos_squeeze = rearrange(x, + 'b c (t p0) (h p1) (w p2) -> b (t h w) (p0 p1 p2) c', + p0=tubelet_size, + p1=patch_size[0], + p2=patch_size[1]) + + videos_patch = rearrange(videos_squeeze, 'b n p c -> b n (p c)') + + return videos_patch + +def imagenet_unnormalize(x, temporal_dim=2): + device = x.device + + if len(x.shape) == 3: + if x.shape[0] == 3: # "channel_first" + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[:, None, None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[:, None, None].to(x) + else: # channel_last + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, None, :].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, None, :].to(x) + elif len(x.shape) == 4: + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, :, None, None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, :, None, None].to(x) + elif len(x.shape) == 5: + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, None, :, None, None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, None, :, None, None].to(x) + + if temporal_dim == 2: + mean = mean.transpose(1,2) + std = std.transpose(1,2) + + return x * std + mean + +def imagenet_normalize(x, temporal_dim=2): + device = x.device + + if len(x.shape) == 3: + if x.shape[0] == 3: # "channel_first" + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[:, None, None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[:, None, None].to(x) + else: # channel_last + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, None, :].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, None, :].to(x) + elif len(x.shape) == 4: + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, :, None, None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, :, None, None].to(x) + elif len(x.shape) == 5: + mean = torch.as_tensor(IMAGENET_DEFAULT_MEAN).to(device)[None, None, :, None, None].to(x) + std = torch.as_tensor(IMAGENET_DEFAULT_STD).to(device)[None, None, :, None, None].to(x) + + if temporal_dim == 2: + mean = mean.transpose(1,2) + std = std.transpose(1,2) + + return (x - mean) / std + +def sinusoidal_embedding(x, n_freq=5, keep_ori=True): + """ + create sin embedding for 3d vectors + input: + x: *x3 + n_freq: number of raised frequency + """ + + shape = list(x.shape) + assert x.shape[-1] == 3, "expect the last dimension to have size 3" + x = x.reshape(-1, 3) + + embedded = [] + if keep_ori: + embedded.append(x) + emb_fns = [torch.sin, torch.cos] + freqs = 2. ** torch.linspace(0., n_freq - 1, steps=n_freq) + for freq in freqs: + for emb_fn in emb_fns: + embedded.append(emb_fn(freq * x)) + embedded = torch.cat(embedded, dim=-1) + C = embedded.shape[-1] + embedded = embedded.reshape(shape[:-1] + [C]) + return embedded + +class SmoothedValue(object): + """Track a series of values and provide access to smoothed values over a + window or the global series average. + """ + + def __init__(self, window_size=20, fmt=None): + if fmt is None: + fmt = "{median:.4f} ({global_avg:.4f})" + self.deque = deque(maxlen=window_size) + self.total = 0.0 + self.count = 0 + self.fmt = fmt + + def update(self, value, n=1): + self.deque.append(value) + self.count += n + self.total += value * n + + def synchronize_between_processes(self): + """ + Warning: does not synchronize the deque! + """ + if not is_dist_avail_and_initialized(): + return + t = torch.tensor([self.count, self.total], dtype=torch.float64, device='cuda') + dist.barrier() + dist.all_reduce(t) + t = t.tolist() + self.count = int(t[0]) + self.total = t[1] + + @property + def median(self): + d = torch.tensor(list(self.deque)) + return d.median().item() + + @property + def avg(self): + d = torch.tensor(list(self.deque), dtype=torch.float32) + return d.mean().item() + + @property + def global_avg(self): + return self.total / self.count + + @property + def max(self): + return max(self.deque) + + @property + def value(self): + return self.deque[-1] + + def __str__(self): + return self.fmt.format( + median=self.median, + avg=self.avg, + global_avg=self.global_avg, + max=self.max, + value=self.value) + + +class MetricLogger(object): + def __init__(self, delimiter="\t"): + self.meters = defaultdict(SmoothedValue) + self.delimiter = delimiter + + def update(self, **kwargs): + for k, v in kwargs.items(): + if v is None: + continue + if isinstance(v, torch.Tensor): + v = v.item() + assert isinstance(v, (float, int)) + self.meters[k].update(v) + + def update2(self, kwargs): + for k, v in kwargs.items(): + if v is None: + continue + if isinstance(v, torch.Tensor): + v = v.item() + assert isinstance(v, (float, int)) + self.meters[k].update(v) + + + def __getattr__(self, attr): + if attr in self.meters: + return self.meters[attr] + if attr in self.__dict__: + return self.__dict__[attr] + raise AttributeError("'{}' object has no attribute '{}'".format( + type(self).__name__, attr)) + + def __str__(self): + loss_str = [] + for name, meter in self.meters.items(): + loss_str.append( + "{}: {}".format(name, str(meter)) + ) + return self.delimiter.join(loss_str) + + def synchronize_between_processes(self): + for meter in self.meters.values(): + meter.synchronize_between_processes() + + def add_meter(self, name, meter): + self.meters[name] = meter + + def log_every(self, iterable, print_freq, header=None): + i = 0 + if not header: + header = '' + start_time = time.time() + end = time.time() + iter_time = SmoothedValue(fmt='{avg:.2f}') + data_time = SmoothedValue(fmt='{avg:.4f}') + space_fmt = ':' + str(len(str(len(iterable)))) + 'd' + log_msg = [ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}' + ] + if torch.cuda.is_available(): + log_msg.append('max mem: {memory:.0f}') + log_msg = self.delimiter.join(log_msg) + MB = 1024.0 * 1024.0 + for obj in iterable: + data_time.update(time.time() - end) + yield obj + iter_time.update(time.time() - end) + if i % print_freq == 0 or i == len(iterable) - 1: + eta_seconds = iter_time.global_avg * (len(iterable) - i) + eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) + if torch.cuda.is_available(): + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time), + memory=torch.cuda.max_memory_allocated() / MB)) + else: + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time))) + i += 1 + end = time.time() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('{} Total time: {} ({:.6f} s / it)'.format( + header, total_time_str, total_time / len(iterable))) + + + + + +def seed_worker(worker_id): + worker_seed = torch.initial_seed() % 2**32 + np.random.seed(worker_seed) + random.seed(worker_seed) + +def _load_checkpoint_for_ema(model_ema, checkpoint): + """ + Workaround for ModelEma._load_checkpoint to accept an already-loaded object + """ + mem_file = io.BytesIO() + torch.save(checkpoint, mem_file) + mem_file.seek(0) + model_ema._load_checkpoint(mem_file) + + +def setup_for_distributed(is_master): + """ + This function disables printing when not in master process + """ + import builtins as __builtin__ + builtin_print = __builtin__.print + + def print(*args, **kwargs): + force = kwargs.pop('force', False) + if is_master or force: + builtin_print(*args, **kwargs) + + __builtin__.print = print + + +def is_dist_avail_and_initialized(): + if not dist.is_available(): + return False + if not dist.is_initialized(): + return False + return True + + +def get_world_size(): + if not is_dist_avail_and_initialized(): + return 1 + return dist.get_world_size() + + +def get_rank(): + if not is_dist_avail_and_initialized(): + return 0 + return dist.get_rank() + + +def is_main_process(): + return get_rank() == 0 + + +def save_on_master(*args, **kwargs): + if is_main_process(): + torch.save(*args, **kwargs) + + +def init_distributed_mode(args): + args.distributed = True + args.rank = int(os.environ["RANK"]) + args.gpu = int(os.environ['LOCAL_RANK']) + args.world_size = int(os.environ['WORLD_SIZE']) + args.dist_backend = 'nccl' + torch.distributed.init_process_group( + backend=args.dist_backend, init_method=args.dist_url, world_size=args.world_size, rank=args.rank + ) + torch.distributed.barrier() + setup_for_distributed(args.rank == 0) + + +def load_state_dict(model, state_dict, prefix='', ignore_missing="relative_position_index"): + missing_keys = [] + unexpected_keys = [] + error_msgs = [] + metadata = getattr(state_dict, '_metadata', None) + state_dict = state_dict.copy() + if metadata is not None: + state_dict._metadata = metadata + + def load(module, prefix=''): + local_metadata = {} if metadata is None else metadata.get( + prefix[:-1], {}) + module._load_from_state_dict( + state_dict, prefix, local_metadata, True, missing_keys, unexpected_keys, error_msgs) + for name, child in module._modules.items(): + if child is not None: + load(child, prefix + name + '.') + + load(model, prefix=prefix) + + warn_missing_keys = [] + ignore_missing_keys = [] + for key in missing_keys: + keep_flag = True + for ignore_key in ignore_missing.split('|'): + if ignore_key in key: + keep_flag = False + break + if keep_flag: + warn_missing_keys.append(key) + else: + ignore_missing_keys.append(key) + + missing_keys = warn_missing_keys + + if len(missing_keys) > 0: + print("Weights of {} not initialized from pretrained model: {}".format( + model.__class__.__name__, missing_keys)) + if len(unexpected_keys) > 0: + print("Weights from pretrained model not used in {}: {}".format( + model.__class__.__name__, unexpected_keys)) + if len(ignore_missing_keys) > 0: + print("Ignored weights of {} not initialized from pretrained model: {}".format( + model.__class__.__name__, ignore_missing_keys)) + if len(error_msgs) > 0: + print('\n'.join(error_msgs)) + + +class NativeScalerWithGradNormCount: + state_dict_key = "amp_scaler" + + def __init__(self): + self._scaler = torch.cuda.amp.GradScaler() + + def __call__(self, loss, optimizer, clip_grad=None, parameters=None, create_graph=False, update_grad=True): + self._scaler.scale(loss).backward(create_graph=create_graph) + # breakpoint() + if update_grad: + if clip_grad is not None: + assert parameters is not None + self._scaler.unscale_(optimizer) # unscale the gradients of optimizer's assigned params in-place + norm = torch.nn.utils.clip_grad_norm_(parameters, clip_grad) + else: + self._scaler.unscale_(optimizer) + norm = get_grad_norm_(parameters) + self._scaler.step(optimizer) + self._scaler.update() + else: + norm = None + return norm + + def state_dict(self): + return self._scaler.state_dict() + + def load_state_dict(self, state_dict): + self._scaler.load_state_dict(state_dict) + + +def get_grad_norm_(parameters, norm_type: float = 2.0) -> torch.Tensor: + if isinstance(parameters, torch.Tensor): + parameters = [parameters] + parameters = [p for p in parameters if p.grad is not None] + norm_type = float(norm_type) + if len(parameters) == 0: + return torch.tensor(0.) + device = parameters[0].grad.device + if norm_type == inf: + total_norm = max(p.grad.detach().abs().max().to(device) for p in parameters) + else: + total_norm = torch.norm(torch.stack([torch.norm(p.grad.detach(), norm_type).to(device) for p in parameters]), norm_type) + return total_norm + + +def cosine_scheduler(base_value, final_value, epochs, niter_per_ep, warmup_epochs=0, + start_warmup_value=0, warmup_steps=-1): + warmup_schedule = np.array([]) + warmup_iters = warmup_epochs * niter_per_ep + if warmup_steps > 0: + warmup_iters = warmup_steps + if warmup_epochs > 0: + warmup_schedule = np.linspace(start_warmup_value, base_value, warmup_iters) + + iters = np.arange(epochs * niter_per_ep - warmup_iters) + iter_per_len = iters/len(iters) + schedule = final_value + 0.5 * (base_value - final_value) * (1 + np.cos(np.pi * iter_per_len)) + # schedule = np.array( + # [final_value + 0.5 * (base_value - final_value) * (1 + math.cos(math.pi * i / (len(iters)))) for i in iters]) + + schedule = np.concatenate((warmup_schedule, schedule)) + + assert len(schedule) == epochs * niter_per_ep + return schedule + + +def get_model_num_parameters(model): + + num_parameters = sum([v.numel() for v in model.parameters() if v.requires_grad]) + + human_readable_fn = lambda num: \ + f'{num / 1e9:.3f} B' if num >= 1e9 else f'{num / 1e6:.3f} M' \ + if num >= 1e6 else f'{num / 1e3:.3f} K' if num >= 1e3 else str(num) + num_parameters_str = human_readable_fn(num_parameters) + + return num_parameters, num_parameters_str + +def save_model(args, epoch, model, optimizer, loss_scaler, model_ema=None): + output_dir = Path(args.output_dir) + epoch_name = str(epoch) + if loss_scaler is not None: + checkpoint_paths = [output_dir / ('checkpoint-%s.pth' % epoch_name)] + for checkpoint_path in checkpoint_paths: + to_save = { + 'model': model.module.state_dict(), + 'optimizer': optimizer.state_dict(), + 'epoch': epoch, + 'scaler': loss_scaler.state_dict(), + 'args': args, + } + + if model_ema is not None: + to_save['model_ema'] = get_state_dict(model_ema) + + save_on_master(to_save, checkpoint_path) + else: + client_state = {'epoch': epoch} + if model_ema is not None: + client_state['model_ema'] = get_state_dict(model_ema) + model.save_checkpoint(save_dir=args.output_dir, tag="checkpoint-%s" % epoch_name, client_state=client_state) + + +def auto_load_model(args, model, optimizer, loss_scaler, model_ema=None, global_rank=None): + output_dir = Path(args.output_dir) + if loss_scaler is not None: + # torch.amp + if len(args.resume) == 0: + import glob + if global_rank is None: + all_checkpoints = glob.glob(os.path.join(output_dir, 'checkpoint-*.pth')) + else: + all_checkpoints = glob.glob(os.path.join(output_dir, f'checkpoint-*-rank-{global_rank}.pth')) + latest_ckpt = -1 + for ckpt in all_checkpoints: + if global_rank is None: + t = ckpt.split('-')[-1].split('.')[0] + else: + t = ckpt.split('checkpoint-')[1].split('-')[0] + if t.isdigit(): + latest_ckpt = max(int(t), latest_ckpt) + if latest_ckpt >= 0: + if global_rank is None: + args.resume = os.path.join(output_dir, 'checkpoint-%d.pth' % latest_ckpt) + else: + args.resume = os.path.join(output_dir, 'checkpoint-%d-rank-%d.pth' % (latest_ckpt, global_rank)) + if args.resume: + print("Auto resume checkpoint: %s" % args.resume) + + if args.resume: + if args.resume.startswith('https'): + checkpoint = torch.hub.load_state_dict_from_url( + args.resume, map_location='cpu', check_hash=True) + else: + checkpoint = torch.load(args.resume, map_location='cpu') + model.module.load_state_dict(checkpoint['model']) + print("Resume checkpoint %s" % args.resume) + if 'optimizer' in checkpoint and 'epoch' in checkpoint: + optimizer.load_state_dict(checkpoint['optimizer']) + args.start_epoch = checkpoint['epoch'] + 1 + if hasattr(args, 'model_ema') and args.model_ema: + _load_checkpoint_for_ema(model_ema, checkpoint['model_ema']) + if 'scaler' in checkpoint: + loss_scaler.load_state_dict(checkpoint['scaler']) + + else: + # deepspeed, only support '--auto_resume'. + import glob + all_checkpoints = glob.glob(os.path.join(output_dir, 'checkpoint-*')) + latest_ckpt = -1 + for ckpt in all_checkpoints: + t = ckpt.split('-')[-1].split('.')[0] + if t.isdigit(): + latest_ckpt = max(int(t), latest_ckpt) + if latest_ckpt >= 0: + args.resume = os.path.join(output_dir, 'checkpoint-%d' % latest_ckpt) + print("Auto resume checkpoint: %d" % latest_ckpt) + _, client_states = model.load_checkpoint(args.output_dir, tag='checkpoint-%d' % latest_ckpt) + args.start_epoch = client_states['epoch'] + 1 + if model_ema is not None: + if args.model_ema: + _load_checkpoint_for_ema(model_ema, client_states['model_ema']) + +def unpatchify(x, patch_size): + """ + x: (N, L, patch_size**2*3) + imgs: (N, 3, H, W) + """ + p = patch_size + h = w = int(x.shape[1] ** .5) + assert h * w == x.shape[1] + + x = x.reshape(shape=(x.shape[0], h, w, p, p, 3)) + x = torch.einsum('nhwpqc->nchpwq', x) + imgs = x.reshape(shape=(x.shape[0], 3, h * p, h * p)) + return imgs + +def unpatchify_cwm(x, patch_size, mask=None): + """ + x: (N, L, patch_size**2 *3) + imgs: (N, 3, H, W) + """ + if mask is not None: + h = w = int(mask.shape[1] ** .5) + recon = torch.zeros(x.shape[0], h*w, x.shape[-1]).to(x) + recon[mask] = x.flatten(0, 1) + else: + h = w = int(x.shape[1] ** .5) + recon = x + + p = patch_size + assert h * w == recon.shape[1] + + recon = recon.reshape(shape=(recon.shape[0], h, w, p, p, 3)) + recon = torch.einsum('nhwpqc->nchpwq', recon) + imgs = recon.reshape(shape=(recon.shape[0], 3, h * p, h * p)) + return imgs + + +def sample_embedding(embedding, pos, mode='bilinear'): + """ + Sample embedding tensor at specified positions + embedding: [B, H, W, C] + pos: [B, P, 2] (convention: first dim is row, second dim is column) + """ + embedding = embedding.permute(0, 3, 1, 2) # [B, C, H, W] + device = embedding.device + # grid_sampling assues first value to be column-dimension, second value to be row-dimension + pos = pos.flip(dims=(-1,)) + assert pos.min() >= -1 and pos.max() <= 1, "grid sampling expect to be in range [-1, 1]" + + return F.grid_sample(embedding, pos[:, None].to(device), mode=mode).squeeze(-2).permute(0, 2, 1) # [B, P, C] + + +def sample_positions_from_dist(size, dist): + """ + Samples positions from a given unnormalized probability distribution. + + Parameters: + num (int): The number of samples to draw for each distribution in the batch. + dist (torch.Tensor): A float tensor of shape [B, H, W] representing the unnormalized + probability distributions for B batches each of length N. + + Returns: + torch.Tensor: A tensor of shape [B, num] containing the sampled positions. + """ + assert dist.dim() == 3, "dist should be a 3D tensor with shape [B, H, W]." + assert len(size) == 2, "size should be a 2D tuple (batch_size, num_samples)" + B, H, W = dist.shape + + new_B, num_samples = size + + if dist.min() < 0: + dist -= dist.min() + + # Flatten the last two dimensions to make it [B, H*W] + flattened_dist = dist.view(B, -1) + + # Sample indices according to the normalized distribution + sampled_indices = torch.multinomial(flattened_dist, new_B * num_samples, replacement=True) + + # Convert the flattened indices back to 2D indices + sampled_row_indices = sampled_indices // W + sampled_col_indices = sampled_indices % W + + # Stack the row and column indices + samples = torch.stack((sampled_row_indices, sampled_col_indices), dim=-1) + samples = samples.view(new_B, num_samples, 2) + + return samples +# +# def get_dino_predominance(images, dims=[28, 28], current_mask=None, painting=None, img_size=[224, 224]): +# global dino_backbone +# if dino_backbone is None: +# vit_arch = 'base' +# vit_feat = 'k' +# patch_size = 8 +# # DINO pre-trained model +# url = "https://dl.fbaipublicfiles.com/dino/dino_vitbase8_pretrain/dino_vitbase8_pretrain.pth" +# feat_dim = 768 +# dino_backbone = dino.ViTFeat(url, feat_dim, vit_arch, vit_feat, patch_size) +# dino_backbone = dino_backbone.eval().requires_grad_(False).cuda() +# +# input_dino = images +# # input_dino = input_dino - torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1).to(input_dino.device) +# # input_dino = input_dino / torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1).to(input_dino.device) +# # input_dino = images.tensor +# input_dino = torch.nn.functional.interpolate(input_dino, size=img_size, mode='bilinear') +# features = dino_backbone(input_dino) +# +# predominence_map = [] +# +# for i in range(features.shape[0]): +# feats = features[i] +# if current_mask == None: +# painting = torch.from_numpy(np.zeros(dims)) +# painting = painting.to(feats) +# else: +# feats, painting = get_masked_affinity_matrix(painting, feats, current_mask, ps=dims[0]) +# +# A, D = get_affinity_matrix(feats, tau=0.15) +# # get the second-smallest eigenvector +# _, second_smallest_vec = second_smallest_eigenvector(A, D) +# # get salient area +# bipartition = get_salient_areas(second_smallest_vec) +# +# # check if we should reverse the partition based on: +# # 1) peak of the 2nd smallest eigvec 2) object centric bias +# seed = np.argmax(np.abs(second_smallest_vec)) +# nc = check_num_fg_corners(bipartition, dims) +# if nc >= 2: +# reverse = True +# else: +# reverse = bipartition[seed] != 1 +# if reverse: +# second_smallest_vec = 1 - second_smallest_vec +# second_smallest_vec = torch.tensor(second_smallest_vec).to(images.device).contiguous() +# map = torch.nn.functional.interpolate(second_smallest_vec.reshape(1, 1, dims[0], dims[1]), size=img_size, +# mode='bilinear') +# map -= map.min() +# map /= map.max() +# predominence_map.append(map) +# init_dist = torch.cat(predominence_map, dim=0).detach() +# return init_dist, A, feats, painting + + +def interpolate_pos_encoding(pos_embed, n_frames, h, w): + N = pos_embed.shape[1] + if N == (h * w * n_frames): + return pos_embed + old_h = old_w = int((N / n_frames) ** 0.5) + patch_pos_embed = pos_embed.view(1, n_frames, old_h, old_w, -1).flatten(0, 1).permute(0, 3, 1, 2) + + patch_pos_embed = F.interpolate( + patch_pos_embed, + size=(h, w), + mode='bicubic', + ) + return patch_pos_embed.permute(0, 2, 3, 1).flatten(0, 2).unsqueeze(0) + + +def flow_to_rgb(vec, flow_mag_range=None, white_bg=False): + height, width = vec.shape[:2] + scaling = 50. / (height**2 + width**2)**0.5 + direction = (np.arctan2(vec[..., 0], vec[..., 1]) + np.pi) / (2 * np.pi) + norm = np.linalg.norm(vec, axis=-1) + if flow_mag_range is None: + flow_mag_range = norm.min(), norm.max() + magnitude = np.clip((norm - flow_mag_range[0]) * scaling, 0., 1.) + if white_bg == True: + value = np.ones_like(direction) + hsv = np.stack([direction, magnitude, saturation], axis=-1) + else: + saturation = np.ones_like(direction) + hsv = np.stack([direction, saturation , magnitude], axis=-1) + rgb = matplotlib.colors.hsv_to_rgb(hsv) + return rgb \ No newline at end of file diff --git a/external/__init__.py b/external/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7154a9d18789f292b58f6c7683f1ddefaa871462 --- /dev/null +++ b/external/__init__.py @@ -0,0 +1,38 @@ +import os +import subprocess +import torch + +def setup_raft(): + print('RAFT is not installed. Auto-install RAFT to ~/.cache/torch/RAFT') + # Store the current working directory + initial_directory = os.getcwd() + os.makedirs(os.path.join(os.environ['HOME'], '.cache/torch/'), exist_ok=True) + os.chdir(os.path.join(os.environ['HOME'], '.cache/torch/')) + subprocess.run(['git', 'clone', 'https://github.com/princeton-vl/RAFT.git'], check=True) + os.chdir('RAFT') + subprocess.run(['./download_models.sh'], check=True) + # Change back to the initial directory + os.chdir(initial_directory) + +def setup_cutler(): + print('CUTLER is not installed. Auto-install CUTLER to ~/.cache/torch/CUTLER') + # Store the current working directory + initial_directory = os.getcwd() + os.makedirs(os.path.join(os.environ['HOME'], '.cache/torch/'), exist_ok=True) + os.chdir(os.path.join(os.environ['HOME'], '.cache/torch/')) + subprocess.run(['git', 'clone', '--recursive', 'https://github.com/facebookresearch/CutLER.git'], check=True) + subprocess.run(['git', 'clone', 'https://github.com/facebookresearch/detectron2.git'], check=True) + os.chdir('detectron2') + subprocess.run(['pip', 'install', '-e', '.'], check=True) + subprocess.run(['pip', 'install', 'git+https://github.com/cocodataset/panopticapi.git'], check=True) + subprocess.run(['pip', 'install', 'git+https://github.com/mcordts/cityscapesScripts.git'], check=True) + subprocess.run(['pip', 'install', 'git+https://github.com/lucasb-eyer/pydensecrf.git'], check=True) + + # Change back to the initial directory + os.chdir(initial_directory) + +if not os.path.isdir(os.path.join(os.environ['HOME'], '.cache/torch/', 'RAFT')): + setup_raft() + +if not os.path.isdir(os.path.join(os.environ['HOME'], '.cache/torch/', 'CutLER')): + setup_cutler() diff --git a/external/app.py b/external/app.py new file mode 100644 index 0000000000000000000000000000000000000000..d759404634be3798908bdd3718c25b4f6f6a8d30 --- /dev/null +++ b/external/app.py @@ -0,0 +1,71 @@ +import cv2 +import numpy as np +import gradio as gr + +from pydantic import BaseModel + + +# Points color and marker +color = (0, 255, 0) # Red color for all points +marker_type = 1 # Cross marker + +with gr.Blocks() as demo: + with gr.Row(): + gr.Markdown('''# Annotate Points!🚀 + Upload an image and click to annotate points on it. + ''') + + # Annotating points on an image + with gr.Tab(label='Image'): + with gr.Row():#.style(equal_height=True): + with gr.Column(): + # Input image + original_image = gr.State(value=None) # store original image without points + input_image = gr.Image(type="numpy", label="Upload Image") + + # Annotate points + selected_points = gr.State([]) # store points + with gr.Row(): + gr.Markdown('Click on the image to select points.') + undo_button = gr.Button('Undo point') + + # Show the image with the annotated points + with gr.Tab(label='Image+Points'): + output_image = gr.Image(type='numpy') + + + # Store the original image once uploaded + def store_img(img): + return img, [] # Reset selected points when a new image is uploaded + + + input_image.upload(store_img, [input_image], [original_image, selected_points]) + + + # Get points when clicked on the image + def get_point(img, sel_pix, evt: gr.SelectData): + sel_pix.append(evt.index) # Append the point's location (coordinates) + + # Draw points on the image + for point in sel_pix: + cv2.drawMarker(img, point, color, markerType=marker_type, markerSize=80, thickness=20) + return img if isinstance(img, np.ndarray) else np.array(img) + + + input_image.select(get_point, [input_image, selected_points], [input_image]) + + + # Undo the last selected point + def undo_points(orig_img, sel_pix): + temp = orig_img.copy() + if len(sel_pix) != 0: + sel_pix.pop() # Remove the last point + for point in sel_pix: + cv2.drawMarker(temp, point, color, markerType=marker_type, markerSize=20, thickness=5) + return temp if isinstance(temp, np.ndarray) else np.array(temp) + + + undo_button.click(undo_points, [original_image, selected_points], [input_image]) + + # Launch the app +demo.queue().launch(inbrowser=True) diff --git a/external/gradio_app.py b/external/gradio_app.py new file mode 100644 index 0000000000000000000000000000000000000000..d16e32280f9ffc352b9dc2dff80659bb7e901a3f --- /dev/null +++ b/external/gradio_app.py @@ -0,0 +1,82 @@ +import cv2 +import gradio as gr +import numpy as np + +# Global variable to store the list of arrows (start and end points) +arrows = [] +start_point = None + + +# Function to draw all arrows (including zero-length arrows) on the image +def draw_arrow(image, click_coords): + global start_point, arrows + + # Convert the image to a numpy array if it's not already + img_array = np.array(image, dtype=np.uint8) + + # Get the current point from the user (click coordinates as (x, y)) + current_point = (int(click_coords[0]), int(click_coords[1])) # Convert float coords to int + + # If start point is not set, set it as the current click position + if start_point is None: + start_point = current_point + return img_array # No arrow yet, just return the original image + + # If start point is already set, add an arrow (including zero-length ones) + end_point = current_point + arrows.append((start_point, end_point)) # Save the arrow + + # Reset start_point for the next arrow + start_point = None + + # Draw all arrows from the saved list + for arrow in arrows: + start, end = arrow + color = (0, 255, 0) # Green arrow + thickness = 3 + + # Draw the arrow (even if it's zero-length, i.e., start == end) + cv2.arrowedLine(img_array, start, end, color, thickness) + + return img_array + + +# Function to reset the canvas (clearing all arrows) +def reset_canvas(): + global arrows, start_point + arrows = [] + start_point = None + return load_image() # Return a fresh image + + +# Load an image for the user to interact with +def load_image(): + img = np.ones((400, 400, 3), dtype=np.uint8) * 255 # White background image + return img + + +# Define Gradio interface using Blocks +def interactive_arrow_interface(): + with gr.Blocks() as demo: + image_input = gr.Image(value=load_image(), interactive=True, + label="Click to specify the arrow's start and end points") + output_image = gr.Image(label="Image with Arrows") + reset_button = gr.Button("Reset") + + # Set up interaction: Handle click events with 'handle_click' + def handle_click(image, evt: gr.SelectData): + print(f"Click coordinates: {evt.index}") + # Pass click coordinates to draw_arrow function and update the image + updated_image = draw_arrow(image, (evt.index[0], evt.index[1])) + return updated_image + + image_input.select(handle_click, [image_input], output_image) + + # Set up the reset button to clear all arrows + reset_button.click(fn=reset_canvas, inputs=None, outputs=image_input) + + return demo + + +# Launch the interactive demo +interactive_arrow_interface().launch(inbrowser=True) diff --git a/external/raft_interface.py b/external/raft_interface.py new file mode 100644 index 0000000000000000000000000000000000000000..72f84450cd25e6150ad60dfc8732f36a6ede8148 --- /dev/null +++ b/external/raft_interface.py @@ -0,0 +1,65 @@ +import sys +import os +sys.path.insert(0, os.path.join(os.environ['HOME'], '.cache/torch', 'RAFT/core')) +from raft import RAFT +from utils import flow_viz +sys.path = sys.path[1:] # remove the first path to RAFT +import torch +from cwm.utils import imagenet_unnormalize +from torch import nn +import argparse + + +class Args: + model = os.path.join(os.environ['HOME'], '.cache/torch', 'RAFT/models/raft-sintel.pth') + small = False + path = None + mixed_precision = False + alternate_corr = False + + def __iter__(self): + for attr, value in self.__dict__.items(): + yield attr, value + +class RAFTInterface(nn.Module): + def __init__(self): + super().__init__() + args = Args() + model = torch.nn.DataParallel(RAFT(args)) + model.load_state_dict(torch.load(args.model, map_location=torch.device('cpu'))) + self.model = model.module + self.model.eval() + + for p in self.model.parameters(): + p.requires_grad = False + + @staticmethod + def prepare_inputs(x): + # make sure the input is in the correct format for RAFT + if x.max() <= 1.0 and x.min() >= 0.: # range(0, 1) + x = x * 255. + elif x.min() < 0: # imagenet normalized: + x = imagenet_unnormalize(x) + x = x * 255. + + return x + + def forward(self, x0, x1, return_magnitude=False): + # x0: imagenet-normalized image 0 [B, C, H, W] + # x1: imagenet-normalized image 1 [B, C, H, W] + + # ensure inputs in + x0 = self.prepare_inputs(x0) + x1 = self.prepare_inputs(x1) + with torch.no_grad(): + _, flow_up = self.model(x0, x1, iters=20, test_mode=True) + + if return_magnitude: + flow_magnitude = flow_up.norm(p=2, dim=1) # [B, H, W] + return flow_up, flow_magnitude + + return flow_up + + def viz(self, flow): + flow_rgb = flow_viz.flow_to_image(flow[0].permute(1,2,0).cpu().numpy()) + return flow_rgb \ No newline at end of file diff --git a/gradio_app_intervention.py b/gradio_app_intervention.py new file mode 100644 index 0000000000000000000000000000000000000000..9a5c3d8a7367d0b3854db219df1d6b508bd855e1 --- /dev/null +++ b/gradio_app_intervention.py @@ -0,0 +1,234 @@ +import cv2 +import numpy as np +import gradio as gr +import cwm.utils as utils + +# Points color and arrow properties +arrow_color = (0, 255, 0) # Green color for all arrows +dot_color = (0, 255, 0) # Green color for the dots at start and end +dot_color_fixed = (255, 0, 0) # Red color for zero-length vectors +thickness = 4 # Thickness of the arrow +tip_length = 0.3 # The length of the arrow tip relative to the arrow length +dot_radius = 10 # Radius for the dots +dot_thickness = -1 # Thickness for solid circle (-1 fills the circle) +from PIL import Image +import torch +#load model +from cwm.model.model_factory import model_factory + +from timm.data.constants import (IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD) + +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + +# Load CWM 3-frame model (automatically download pre-trained checkpoint) +model = model_factory.load_model('vitb_8x8patch_3frames').to(device) + +model.requires_grad_(False) +model.eval() + +model = model.to(torch.float16) + + +import matplotlib.pyplot as plt +from matplotlib.patches import FancyArrowPatch +from PIL import Image +import numpy as np + +def draw_arrows_matplotlib(img, selected_points, zero_length): + """ + Draw arrows on the image using matplotlib for better quality arrows and dots. + """ + fig, ax = plt.subplots() + ax.imshow(img) + + for i in range(0, len(selected_points), 2): + start_point = selected_points[i] + end_point = selected_points[i + 1] + + if start_point == end_point or zero_length: + # Draw a dot for zero-length vectors or if only one point is clicked + ax.scatter(start_point[0], start_point[1], color='red', s=100) # Red dot for zero-length vector + else: + # Draw arrows + arrow = FancyArrowPatch((start_point[0], start_point[1]), (end_point[0], end_point[1]), + color='green', linewidth=2, arrowstyle='->', mutation_scale=15) + ax.add_patch(arrow) + + # Optionally, draw a small circle (dot) at the start and end points + ax.scatter(start_point[0], start_point[1], color='green', s=100) # Green dot at start + ax.scatter(end_point[0], end_point[1], color='green', s=100) # Green dot at end + + # Save the image to a numpy array + fig.canvas.draw() + img_array = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) + img_array = img_array.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + plt.close(fig) + return img_array + + +with gr.Blocks() as demo: + with gr.Row(): + gr.Markdown('''# Generate interventions!🚀 + Upload an image and click to select the start and end points for arrows. Dots will be shown at the beginning and end of each arrow. You can also create zero-length vectors (just a dot) by enabling the toggle below. + ''') + + # Annotating arrows on an image + with gr.Tab(label='Image'): + with gr.Row(): + with gr.Column(): + # Input image + original_image = gr.State(value=None) # store original image without arrows + input_image = gr.Image(type="numpy", label="Upload Image") + + # Annotate arrows + selected_points = gr.State([]) # store points + zero_length_toggle = gr.Checkbox(label="Enable zero-length vectors", value=False) # Toggle for zero-length vectors + with gr.Row(): + gr.Markdown('Click on the image to select the start and end points for each arrow. If zero-length vectors are enabled, clicking once will draw a dot.') + undo_button = gr.Button('Undo last action') + clear_button = gr.Button('Clear All') + + # Run model button + run_model_button = gr.Button('Run Model') + + # Show the image with the annotated arrows + with gr.Tab(label='Intervention'): + output_image = gr.Image(type='numpy') + + def resize_to_square(img, size=512): + img = Image.fromarray(img) + img = img.resize((size, size)) + return np.array(img) + + # Store the original image and resize to square size once uploaded + def store_img(img): + resized_img = resize_to_square(img) # Resize the uploaded image to a square + print(f"Image uploaded with shape: {resized_img.shape}") + return resized_img, resized_img, [] + + input_image.upload(store_img, [input_image], [input_image, original_image, selected_points]) + + # Get points and draw arrows or zero-length vectors based on the toggle + def get_point(img, sel_pix, zero_length, evt: gr.SelectData): + sel_pix.append(evt.index) # Append the point's location (coordinates) + + # Zero-length vector case: Draw a single dot at the clicked point + if zero_length: + point = sel_pix[-1] # Last point clicked + cv2.circle(img, point, dot_radius, dot_color_fixed, dot_thickness) # Draw a dot at the point + sel_pix.append(evt.index) + else: + # Regular case: two clicks for an arrow + # Check if this is the first point (start point for the arrow) + if len(sel_pix) % 2 == 1: + # Draw a dot at the start point to give feedback + start_point = sel_pix[-1] # Last point is the start + cv2.circle(img, start_point, dot_radius, dot_color, dot_thickness) + + # Check if two points have been selected (start and end points for an arrow) + if len(sel_pix) % 2 == 0: + # Draw an arrow between the last two points + start_point = sel_pix[-2] # Second last point is the start + end_point = sel_pix[-1] # Last point is the end + + # Draw arrow + cv2.arrowedLine(img, start_point, end_point, arrow_color, thickness, tipLength=tip_length) + + # Draw a dot at the end point + cv2.circle(img, end_point, dot_radius, dot_color, dot_thickness) + + return img if isinstance(img, np.ndarray) else np.array(img) + + input_image.select(get_point, [input_image, selected_points, zero_length_toggle], [input_image]) + + # Undo the last selected action + def undo_arrows(orig_img, sel_pix, zero_length): + temp = orig_img.copy() + # if zero_length: + # # Undo the last zero-length vector (just the last dot) + # if len(sel_pix) >= 1: + # sel_pix.pop() # Remove the last point + # else: + if len(sel_pix) >= 2: + sel_pix.pop() # Remove the last end point + sel_pix.pop() # Remove the last start point + + # Redraw all remaining arrows and dots + for i in range(0, len(sel_pix), 2): + start_point = sel_pix[i] + end_point = sel_pix[i + 1] + if start_point == end_point: + # Zero-length vector: Draw a dot + color = dot_color_fixed + else: + cv2.arrowedLine(temp, start_point, end_point, arrow_color, thickness, tipLength=tip_length) + color = arrow_color + # Draw arrow + + # Draw dots at start and end points + cv2.circle(temp, start_point, dot_radius, color, dot_thickness) + cv2.circle(temp, end_point, dot_radius, color, dot_thickness) + + # If there is an odd number of points (e.g., only a start point), draw a dot for it + if len(sel_pix) == 1: + start_point = sel_pix[0] + cv2.circle(temp, start_point, dot_radius, dot_color, dot_thickness) + + return temp if isinstance(temp, np.ndarray) else np.array(temp) + + undo_button.click(undo_arrows, [original_image, selected_points, zero_length_toggle], [input_image]) + + # Clear all points and reset the image + def clear_all_points(orig_img, sel_pix): + sel_pix.clear() # Clear all points + return orig_img # Reset image to original + + clear_button.click(clear_all_points, [original_image, selected_points], [input_image]) + + # Dummy model function to simulate running a model + def run_model_on_points(points, input_image, original_image): + H = input_image.shape[0] + W = input_image.shape[1] + factor = 224/H + # Example: pretend the model processes points and returns a simple transformation on the image + points = torch.from_numpy(np.array(points).reshape(-1, 4)) * factor + + points = points[:, [1, 0, 3, 2]] + + print(points) + + img = Image.fromarray(original_image) + + img = img.resize((224, 224)) + + img = np.array(img) + + np.save("img.npy", original_image) + + img = torch.from_numpy(img).permute(2, 0, 1).float() / 255.0 + + img = img[None] + + # reshape image to [B, C, T, H, W], C = 3, T = 3 (3-frame model), H = W = 224 + x = img[:, :, None].expand(-1, -1, 3, -1, -1).to(torch.float16) + + # Imagenet-normalize the inputs (standardization) + x = utils.imagenet_normalize(x).to(device) + with torch.no_grad(): + counterfactual = model.get_counterfactual(x, points) + + counterfactual = counterfactual.squeeze() + + counterfactual = counterfactual.clamp(0, 1).permute(1,2,0).detach().cpu().numpy() + + # for i in range(0, len(points), 2): + # # Draw rectangles on the points as model output example + # cv2.rectangle(processed_image, points[i], points[i + 1], (255, 0, 0), 3) + return counterfactual + + # Run model when the button is clicked + run_model_button.click(run_model_on_points, [selected_points, input_image, original_image], [output_image]) + + # Launch the app +demo.queue().launch(inbrowser=True, share=True) diff --git a/gradio_app_intervention_better_circles.py b/gradio_app_intervention_better_circles.py new file mode 100644 index 0000000000000000000000000000000000000000..56dda3b5c19a29ce2825affeac7893caf50745de --- /dev/null +++ b/gradio_app_intervention_better_circles.py @@ -0,0 +1,289 @@ +import cv2 +import numpy as np +import gradio as gr +import cwm.utils as utils + +# Points color and arrow properties +arrow_color = (0, 255, 0) # Green color for all arrows +dot_color = (0, 255, 0) # Green color for the dots at start and end +dot_color_fixed = (255, 0, 0) # Red color for zero-length vectors +thickness = 3 # Thickness of the arrow +tip_length = 0.3 # The length of the arrow tip relative to the arrow length +dot_radius = 7 # Radius for the dots +dot_thickness = -1 # Thickness for solid circle (-1 fills the circle) +from PIL import Image +import torch +#load model +from cwm.model.model_factory import model_factory + +from timm.data.constants import (IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD) + +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + +# Load CWM 3-frame model (automatically download pre-trained checkpoint) +model = model_factory.load_model('vitb_8x8patch_3frames').to(device) + +model.requires_grad_(False) +model.eval() + +model = model.to(torch.float16) + + +import matplotlib.pyplot as plt +from matplotlib.patches import FancyArrowPatch +from PIL import Image +import numpy as np + +from torchvision import transforms + +def draw_arrows_matplotlib(img, selected_points, zero_length): + """ + Draw arrows on the image using matplotlib for better quality arrows and dots. + """ + fig, ax = plt.subplots() + ax.imshow(img) + + for i in range(0, len(selected_points), 2): + start_point = selected_points[i] + end_point = selected_points[i + 1] + + if start_point == end_point or zero_length: + # Draw a dot for zero-length vectors or if only one point is clicked + ax.scatter(start_point[0], start_point[1], color='red', s=100) # Red dot for zero-length vector + else: + # Draw arrows + arrow = FancyArrowPatch((start_point[0], start_point[1]), (end_point[0], end_point[1]), + color='green', linewidth=2, arrowstyle='->', mutation_scale=15) + ax.add_patch(arrow) + + # Optionally, draw a small circle (dot) at the start and end points + ax.scatter(start_point[0], start_point[1], color='green', s=100) # Green dot at start + ax.scatter(end_point[0], end_point[1], color='green', s=100) # Green dot at end + + # Save the image to a numpy array + fig.canvas.draw() + img_array = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) + img_array = img_array.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + plt.close(fig) + return img_array + +import os +# def load_preuploaded_images(): +# image_folder = "assets" +# images = [] +# for img_file in os.listdir(image_folder): +# img_path = os.path.join(image_folder, img_file) +# if img_file.endswith(('png', 'jpg', 'jpeg')): +# images.append(Image.open(img_path)) +# return images +# +# # Function to transfer image from gallery to the input image section + + +# +# preloaded_images = load_preuploaded_images() +# +# print("Preloaded images:", preloaded_images) +with gr.Blocks() as demo: + with gr.Row(): + gr.Markdown('''# Generate interventions!🚀 + Upload an image and click to select the start and end points for arrows. Dots will be shown at the beginning and end of each arrow. You can also create zero-length vectors (just a dot) by enabling the toggle below. + ''') + + # Annotating arrows on an image + with gr.Tab(label='Image'): + with gr.Row(): + with gr.Column(): + # Input image + original_image = gr.State(value=None) # store original image without arrows + input_image = gr.Image(type="numpy", label="Upload Image") + + # Annotate arrows + selected_points = gr.State([]) # store points + zero_length_toggle = gr.Checkbox(label="Select patches to be kept fixed", value=False) # Toggle for zero-length vectors + with gr.Row(): + gr.Markdown('Click on the image to select the start and end points for each arrow. If zero-length vectors are enabled, clicking once will draw a dot.') + undo_button = gr.Button('Undo last action') + clear_button = gr.Button('Clear All') + + # Run model button + run_model_button = gr.Button('Run Model') + + # Show the image with the annotated arrows + with gr.Tab(label='Intervention'): + output_image = gr.Image(type='numpy') + + # Store the original image and resize to square size once uploaded + def resize_to_square(img, size=448): + print("Resizing image to square") + img = Image.fromarray(img) + transform = transforms.Compose([ + transforms.Resize(size), + transforms.CenterCrop(size) + ]) + img = transform(img) # .transpose(1, 2, 0) + + return np.array(img) + + + def load_img(evt: gr.SelectData): + img_path = evt.value['image']['path'] + img = np.array(Image.open(img_path)) + # print(f"Image uploaded with shape: {input.shape}") + resized_img = resize_to_square(img) + return resized_img, resized_img, [] + + + def store_img(img): + resized_img = resize_to_square(img) # Resize the uploaded image to a square + print(f"Image uploaded with shape: {resized_img.shape}") + return resized_img, resized_img, [] + + + with gr.Row(): + with gr.Column(): + gallery = gr.Gallery( ["./assets/desk_1.jpg", "./assets/color_wheel.png", "./assets/desk_1.jpg", "./assets/desk_1.jpg", "./assets/desk_1.jpg"], columns=5, allow_preview=False, label="Select an example image to test") + # examples = gr.Examples( + # examples=[ + # ["./assets/desk_1.jpg", "./assets/desk_1.jpg"], + # ], + # inputs=[input_image, original_image], + # # fn=load_img, + # # outputs=[input_image, original_image], + # # cache_examples=True, + # # run_on_click=True, + # # label="Select an example image to test" + # ) + gallery.select(load_img, outputs=[input_image, original_image, selected_points]) + + input_image.upload(store_img, [input_image], [input_image, original_image, selected_points]) + + # Get points and draw arrows or zero-length vectors based on the toggle + def get_point(img, sel_pix, zero_length, evt: gr.SelectData): + sel_pix.append(evt.index) # Append the point's location (coordinates) + + # Zero-length vector case: Draw a single dot at the clicked point + if zero_length: + point = sel_pix[-1] # Last point clicked + cv2.circle(img, point, dot_radius, dot_color_fixed, dot_thickness, lineType=cv2.LINE_AA) # Draw a dot at the point + sel_pix.append(evt.index) + else: + # Regular case: two clicks for an arrow + # Check if this is the first point (start point for the arrow) + if len(sel_pix) % 2 == 1: + # Draw a dot at the start point to give feedback + start_point = sel_pix[-1] # Last point is the start + cv2.circle(img, start_point, dot_radius, dot_color, dot_thickness, lineType=cv2.LINE_AA) + + # Check if two points have been selected (start and end points for an arrow) + if len(sel_pix) % 2 == 0: + # Draw an arrow between the last two points + start_point = sel_pix[-2] # Second last point is the start + end_point = sel_pix[-1] # Last point is the end + + # Draw arrow + cv2.arrowedLine(img, start_point, end_point, arrow_color, thickness, tipLength=tip_length, line_type=cv2.LINE_AA) + + # Draw a dot at the end point + cv2.circle(img, end_point, dot_radius, dot_color, dot_thickness, lineType=cv2.LINE_AA) + + return img if isinstance(img, np.ndarray) else np.array(img) + + input_image.select(get_point, [input_image, selected_points, zero_length_toggle], [input_image]) + + # Undo the last selected action + def undo_arrows(orig_img, sel_pix, zero_length): + temp = orig_img.copy() + # if zero_length: + # # Undo the last zero-length vector (just the last dot) + # if len(sel_pix) >= 1: + # sel_pix.pop() # Remove the last point + # else: + if len(sel_pix) >= 2: + sel_pix.pop() # Remove the last end point + sel_pix.pop() # Remove the last start point + + # Redraw all remaining arrows and dots + for i in range(0, len(sel_pix), 2): + start_point = sel_pix[i] + end_point = sel_pix[i + 1] + if start_point == end_point: + # Zero-length vector: Draw a dot + color = dot_color_fixed + else: + cv2.arrowedLine(temp, start_point, end_point, arrow_color, thickness, tipLength=tip_length) + color = arrow_color + # Draw arrow + + # Draw dots at start and end points + cv2.circle(temp, start_point, dot_radius, color, dot_thickness) + cv2.circle(temp, end_point, dot_radius, color, dot_thickness) + + # If there is an odd number of points (e.g., only a start point), draw a dot for it + if len(sel_pix) == 1: + start_point = sel_pix[0] + cv2.circle(temp, start_point, dot_radius, dot_color, dot_thickness) + + return temp if isinstance(temp, np.ndarray) else np.array(temp) + + undo_button.click(undo_arrows, [original_image, selected_points, zero_length_toggle], [input_image]) + + + # Clear all points and reset the image + def clear_all_points(orig_img, sel_pix): + sel_pix.clear() # Clear all points + return orig_img # Reset image to original + + clear_button.click(clear_all_points, [original_image, selected_points], [input_image]) + + # Dummy model function to simulate running a model + def run_model_on_points(points, input_image, original_image): + H = input_image.shape[0] + W = input_image.shape[1] + factor = 224/H + # Example: pretend the model processes points and returns a simple transformation on the image + points = torch.from_numpy(np.array(points).reshape(-1, 4)) * factor + + points = points[:, [1, 0, 3, 2]] + + print(points) + + img = Image.fromarray(original_image) + + transform = transforms.Compose([ + transforms.Resize(224), + transforms.CenterCrop(224) + ]) + img = np.array(transform(img)) + + # np.save("img.npy", original_image) + + img = torch.from_numpy(img).permute(2, 0, 1).float() / 255.0 + + img = img[None] + + # reshape image to [B, C, T, H, W], C = 3, T = 3 (3-frame model), H = W = 224 + x = img[:, :, None].expand(-1, -1, 3, -1, -1).to(torch.float16) + + # Imagenet-normalize the inputs (standardization) + x = utils.imagenet_normalize(x).to(device) + with torch.no_grad(): + counterfactual = model.get_counterfactual(x, points) + + counterfactual = counterfactual.squeeze() + + counterfactual = counterfactual.clamp(0, 1).permute(1,2,0).detach().cpu().numpy() + + # for i in range(0, len(points), 2): + # # Draw rectangles on the points as model output example + # cv2.rectangle(processed_image, points[i], points[i + 1], (255, 0, 0), 3) + return counterfactual + + # Run model when the button is clicked + run_model_button.click(run_model_on_points, [selected_points, input_image, original_image], [output_image]) + + + + # Launch the app +demo.queue().launch(inbrowser=True, share=True) diff --git a/gradio_app_intervention_better_circles_pil.py b/gradio_app_intervention_better_circles_pil.py new file mode 100644 index 0000000000000000000000000000000000000000..c039ac03269c65285b9618431474b138daeb0af0 --- /dev/null +++ b/gradio_app_intervention_better_circles_pil.py @@ -0,0 +1,250 @@ +import cv2 +import numpy as np +import gradio as gr +import cwm.utils as utils + +# Points color and arrow properties +arrow_color = (0, 255, 0) # Green color for all arrows +dot_color = (0, 255, 0) # Green color for the dots at start and end +dot_color_fixed = (255, 0, 0) # Red color for zero-length vectors +thickness = 3 # Thickness of the arrow +tip_length = 0.3 # The length of the arrow tip relative to the arrow length +dot_radius = 7 # Radius for the dots +dot_thickness = -1 # Thickness for solid circle (-1 fills the circle) +from PIL import Image +import torch +#load model +from cwm.model.model_factory import model_factory + +from timm.data.constants import (IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD) + +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + +# Load CWM 3-frame model (automatically download pre-trained checkpoint) +model = model_factory.load_model('vitb_8x8patch_3frames').to(device) + +model.requires_grad_(False) +model.eval() + +model = model.to(torch.float16) + + +import matplotlib.pyplot as plt +from matplotlib.patches import FancyArrowPatch +from PIL import Image +import numpy as np + +def draw_arrows_matplotlib(img, selected_points, zero_length): + """ + Draw arrows on the image using matplotlib for better quality arrows and dots. + """ + fig, ax = plt.subplots() + ax.imshow(img) + + for i in range(0, len(selected_points), 2): + start_point = selected_points[i] + end_point = selected_points[i + 1] + + if start_point == end_point or zero_length: + # Draw a dot for zero-length vectors or if only one point is clicked + ax.scatter(start_point[0], start_point[1], color='red', s=100) # Red dot for zero-length vector + else: + # Draw arrows + arrow = FancyArrowPatch((start_point[0], start_point[1]), (end_point[0], end_point[1]), + color='green', linewidth=2, arrowstyle='->', mutation_scale=15) + ax.add_patch(arrow) + + # Optionally, draw a small circle (dot) at the start and end points + ax.scatter(start_point[0], start_point[1], color='green', s=100) # Green dot at start + ax.scatter(end_point[0], end_point[1], color='green', s=100) # Green dot at end + + # Save the image to a numpy array + fig.canvas.draw() + img_array = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) + img_array = img_array.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + plt.close(fig) + return img_array + +from PIL import ImageDraw +with gr.Blocks() as demo: + with gr.Row(): + gr.Markdown('''# Generate interventions!🚀 + Upload an image and click to select the start and end points for arrows. Dots will be shown at the beginning and end of each arrow. You can also create zero-length vectors (just a dot) by enabling the toggle below. + ''') + + # Annotating arrows on an image + with gr.Tab(label='Image'): + with gr.Row(): + with gr.Column(): + # Input image + original_image = gr.State(value=None) # store original image without arrows + input_image = gr.Image(type="numpy", label="Upload Image") + + # Annotate arrows + selected_points = gr.State([]) # store points + zero_length_toggle = gr.Checkbox(label="Select patches to be kept fixed", value=False) # Toggle for zero-length vectors + with gr.Row(): + gr.Markdown('Click on the image to select the start and end points for each arrow. If zero-length vectors are enabled, clicking once will draw a dot.') + undo_button = gr.Button('Undo last action') + clear_button = gr.Button('Clear All') + + # Run model button + run_model_button = gr.Button('Run Model') + + # Show the image with the annotated arrows + with gr.Tab(label='Intervention'): + output_image = gr.Image(type='numpy') + + def resize_to_square(img, size=512): + img = Image.fromarray(img) + img = img.resize((size, size)) + return np.array(img) + + # Store the original image and resize to square size once uploaded + def store_img(img): + resized_img = resize_to_square(img) # Resize the uploaded image to a square + print(f"Image uploaded with shape: {resized_img.shape}") + return resized_img, resized_img, [] + + input_image.upload(store_img, [input_image], [input_image, original_image, selected_points]) + + # Get points and draw arrows or zero-length vectors based on the toggle + def get_point(img, sel_pix, zero_length, evt: gr.SelectData): + sel_pix.append(evt.index) # Append the point's location (coordinates) + + pil_img = Image.fromarray(img) + draw = ImageDraw.Draw(pil_img) + # Zero-length vector case: Draw a single dot at the clicked point + if zero_length: + point = sel_pix[-1] # Last point clicked + draw.ellipse([point[0] - dot_radius, point[1] - dot_radius, + point[0] + dot_radius, point[1] + dot_radius], + fill=dot_color_fixed) + sel_pix.append(evt.index) + else: + # Regular case: two clicks for an arrow + # Check if this is the first point (start point for the arrow) + if len(sel_pix) % 2 == 1: + # Draw a dot at the start point to give feedback + start_point = sel_pix[-1] # Last point is the start + draw.ellipse([start_point[0] - dot_radius, start_point[1] - dot_radius, + start_point[0] + dot_radius, start_point[1] + dot_radius], + fill=dot_color) + + # Check if two points have been selected (start and end points for an arrow) + if len(sel_pix) % 2 == 0: + # Draw an arrow between the last two points + start_point = tuple(sel_pix[-2]) # Second last point is the start + end_point = tuple(sel_pix[-1]) # Last point is the end + + # Draw arrow + draw.line([start_point, end_point], fill=arrow_color, width=thickness) + + # Draw a dot at the end point + draw.ellipse([end_point[0] - dot_radius, end_point[1] - dot_radius, + end_point[0] + dot_radius, end_point[1] + dot_radius], + fill=dot_color) + + return np.array(pil_img) + + input_image.select(get_point, [input_image, selected_points, zero_length_toggle], [input_image]) + + # Undo the last selected action + def undo_arrows(orig_img, sel_pix, zero_length): + temp = orig_img.copy() + # if zero_length: + # # Undo the last zero-length vector (just the last dot) + # if len(sel_pix) >= 1: + # sel_pix.pop() # Remove the last point + # else: + pil_img = Image.fromarray(temp) + draw = ImageDraw.Draw(pil_img) + if len(sel_pix) >= 2: + sel_pix.pop() # Remove the last end point + sel_pix.pop() # Remove the last start point + + # Redraw all remaining arrows and dots + for i in range(0, len(sel_pix), 2): + start_point = sel_pix[i] + end_point = sel_pix[i + 1] + if start_point == end_point: + # Zero-length vector: Draw a dot + color = dot_color_fixed + else: + draw.line([tuple(start_point), tuple(end_point)], fill=arrow_color, width=thickness) + color = arrow_color + # Draw arrow + + # Draw dots at start and end points + draw.ellipse([start_point[0] - dot_radius, start_point[1] - dot_radius, + start_point[0] + dot_radius, start_point[1] + dot_radius], + fill=color) + draw.ellipse([end_point[0] - dot_radius, end_point[1] - dot_radius, + end_point[0] + dot_radius, end_point[1] + dot_radius], + fill=color) + + # If there is an odd number of points (e.g., only a start point), draw a dot for it + if len(sel_pix) == 1: + start_point = sel_pix[0] + draw.ellipse([start_point[0] - dot_radius, start_point[1] - dot_radius, + start_point[0] + dot_radius, start_point[1] + dot_radius], + fill=dot_color) + + return np.array(pil_img) + + undo_button.click(undo_arrows, [original_image, selected_points, zero_length_toggle], [input_image]) + + # Clear all points and reset the image + def clear_all_points(orig_img, sel_pix): + sel_pix.clear() # Clear all points + return orig_img # Reset image to original + + clear_button.click(clear_all_points, [original_image, selected_points], [input_image]) + + # Dummy model function to simulate running a model + def run_model_on_points(points, input_image, original_image): + H = input_image.shape[0] + W = input_image.shape[1] + factor = 224/H + # Example: pretend the model processes points and returns a simple transformation on the image + points = torch.from_numpy(np.array(points).reshape(-1, 4)) * factor + + points = points[:, [1, 0, 3, 2]] + + print(points) + + img = Image.fromarray(original_image) + + img = img.resize((224, 224)) + + img = np.array(img) + + np.save("img.npy", original_image) + + img = torch.from_numpy(img).permute(2, 0, 1).float() / 255.0 + + img = img[None] + + # reshape image to [B, C, T, H, W], C = 3, T = 3 (3-frame model), H = W = 224 + x = img[:, :, None].expand(-1, -1, 3, -1, -1).to(torch.float16) + + # Imagenet-normalize the inputs (standardization) + x = utils.imagenet_normalize(x).to(device) + with torch.no_grad(): + counterfactual = model.get_counterfactual(x, points) + + counterfactual = counterfactual.squeeze() + + counterfactual = counterfactual.clamp(0, 1).permute(1,2,0).detach().cpu().numpy() + + # for i in range(0, len(points), 2): + # # Draw rectangles on the points as model output example + # cv2.rectangle(processed_image, points[i], points[i + 1], (255, 0, 0), 3) + return counterfactual + + # Run model when the button is clicked + run_model_button.click(run_model_on_points, [selected_points, input_image, original_image], [output_image]) + + # Launch the app +demo.queue().launch(inbrowser=True, share=True) diff --git a/notebooks/visualize_counterfactual.ipynb b/notebooks/visualize_counterfactual.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..54a269c7e65ed69d3106bdb4a97c4481cfea5b29 --- /dev/null +++ b/notebooks/visualize_counterfactual.ipynb @@ -0,0 +1,188 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "e9210a69-b1b3-4495-a30e-0bb61fcd06c4", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.environ['CUDA_VISIBLE_DEVICES'] = '0' # specify which GPU to use\n", + "import torch\n", + "import cwm.utils as utils\n", + "from torchvision.io import read_image\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.patches as patches\n", + "from cwm.model.model_factory import model_factory\n", + "\n", + "%matplotlib inline\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "markdown", + "id": "6362414f-f6a6-4f3a-910e-55c599ff4943", + "metadata": {}, + "source": [ + "## Load Pre-trained CWM Model" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "078f6662-012a-4d46-b597-ea62b6fc9f1d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model loaded successfully\n" + ] + } + ], + "source": [ + "# Load CWM 3-frame model (automatically download pre-trained checkpoint)\n", + "model = model_factory.load_model('vitb_8x8patch_3frames').cuda() " + ] + }, + { + "cell_type": "markdown", + "id": "caa3a025-2eab-4b79-a57e-490b3bf8f282", + "metadata": {}, + "source": [ + "## Prepare model inputs" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "24d89320-905b-4ca2-87c5-dfa902dedd87", + "metadata": {}, + "outputs": [], + "source": [ + "# Load input image from an image path\n", + "img_path = '/ccn2/u/honglinc/bbnet_notebooks/jordon.jpeg' \n", + "\n", + "# normalized to the range [0, 1]\n", + "img = read_image(img_path)[:, :1480].cuda() / 255. \n", + "\n", + "# resize image to input resolution [224, 224]\n", + "img = torch.nn.functional.interpolate(img[None], size=224, mode='bicubic') \n", + "\n", + "# reshape image to [B, C, T, H, W], C = 3, T = 3 (3-frame model), H = W = 224\n", + "x = img[:, :, None].expand(-1, -1, 3, -1, -1).to(torch.float16) \n", + "\n", + "# Imagenet-normalize the inputs (standardization)\n", + "x = utils.imagenet_normalize(x)\n", + "\n", + "# Prepare masks for the 3-frame model: 28x28=784 patches per image, the first two are unmasked, last one is masked\n", + "bool_masked_pos = torch.ones(1, 784*3).to(x.device).bool()\n", + "bool_masked_pos[:, 0:784*2] = False\n", + "\n", + "# patch size\n", + "patch_size = model.encoder.patch_size[-1]" + ] + }, + { + "cell_type": "markdown", + "id": "99773a0d-a568-410a-82e2-d8d7a3de91ca", + "metadata": {}, + "source": [ + "## Generate counterfactual predictions" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "9accdceb-b5fc-4d94-a9ca-2589fb9d4e37", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([1, 784, 192]) torch.Size([1, 784]) torch.Size([1, 784, 192]) 28 28\n" + ] + } + ], + "source": [ + "move_patches=[[8, 11], [16, 12], [22, 4]] # Specify which patches to move\n", + "static_patches=[[10, 22], [4, 4]] # Specify which patches to hold still\n", + "delta = [-3, -1] # Specify the direction of motion\n", + "\n", + "# Model inference\n", + "with torch.cuda.amp.autocast(enabled=True):\n", + " output = model.get_counterfactual(x, bool_masked_pos, move_patches, static_patches, delta) # model reconstruction output\n", + " recon = utils.unpatchify_cwm(output, patch_size=patch_size, mask=bool_masked_pos[:, -784:]) # reshape the output to an image " + ] + }, + { + "cell_type": "markdown", + "id": "eed12ad9-a7c8-49c7-add2-d1ea8129aea6", + "metadata": {}, + "source": [ + "## Visualization" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "8b6983e6-5b76-4e93-a385-c03c9da80ed0", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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yzXXXMOv/MqvMJvNeMtb3sITn/hEPvrRj55lkJaylKUs5YvJf/tv/43LLruMxz/+8ef0/he84AX81m/9Fs9+9rP5qZ/6KT784Q/zmte8hs985jP85//8n7/s83jxi1/MxsYGv/ALv8Att9zC61//ev7Vv/pX/O7v/i4Ar3/963nxi1/MysoKP/dzPwfQ24XZbMbVV1/NnXfeyQtf+EIe8pCH8MEPfpBXvOIV3H333Wc1dV9//fVUVcUP//APU5Ylj370o3nHO97B93//9/P0pz+dH/iBH+jf+4UvfIHf//3f5znPeQ6XXnopx44d461vfStXX301f//3f88FF1wAqK279tpr+R//439w3XXX8ZKXvISdnR3e//7386lPfYqnPe1pD5pdesMb3sC3f/u3833f9300TcN//I//kec85zm8973v5ZnPfOaXfDw4d/vrveeaa67hiU98Iq997Wt7O/bCF76Q3/zN3+T5z38+P/7jP87NN9/Mb/zGb/DRj36Uv/qrvyLPcwD+r//r/+LVr341z3jGM3jGM57BRz7yEb7lW76Fpmke8Bzf//73c+2113LkyBFe8pKXcP755/OZz3yG9773vbzkJS/hhS98IXfddRfvf//7ecc73vGAx/v0pz/NVVddxdraGi9/+cvJ85y3vvWtPPnJT+4TibvlgdboUr4CkaUs5QHk+uuvF0D+9m//tn/tuc99rgDyS7/0S3ve+0/+yT+RxzzmMf3PN998swAyHA7ljjvu6F//8Ic/LID8xE/8RP/a1VdfLVdfffVZn//c5z5Xjh492v984sQJAeQXfuEXzun8//RP/1QA+dM//dM9nwXIu971rv61G264QQCx1spf//Vf96+/733vE0Cuv/76/rXZbHbW53zoQx8SQH77t3+7f+3FL36xGGPkox/9aP/aqVOnZP/+/QLIzTffLCIiOzs7sm/fPvmhH/qhPce85557ZH19/azXl7KUpSzli8nW1pYA8h3f8R3n9P6PfexjAsgLXvCCPa+/7GUvE0D+5E/+pH/t/vTv0aNH5bnPfW7/c2c7nva0p0mMsX/9J37iJ8Q5J5ubm/1rj3jEI+5T/7/qVa+S8Xgsn/vc5/a8/jM/8zPinJPbbrtNRBa2Zm1tTY4fP37WcQB50YtetOe1qqokhLDntZtvvlnKstxj2/7Df/gPAsjrXve6s47bXdcXs0vnattEzrYtTdPIIx/5SHnqU5+65/V73+v7ki/F/nY2/Wd+5mf2HOMv/uIvBJB3vvOde17/4z/+4z2vHz9+XIqikGc+85l7nvXP/uzPCrDnXO9tk733cumll8rRo0flzJkzez5n97Fe9KIXyf25rfe+98961rOkKAq56aab+tfuuusuWV1dlSc96Un9a1/KGl3KlydL6NRSviL5kR/5kT0/X3XVVXzhC184633PetazuPDCC/ufv/mbv5nHPvax/OEf/uFX/RzvT1ZWVrjuuuv6n6+88kr27dvHwx72sD3Zju773dc1HA7779u25dSpU1xxxRXs27ePj3zkI/3v/viP/5jHPe5xPOpRj+pf279/f1+S7uT9738/m5ub/It/8S84efJk/+Wc47GPfSx/+qd/+qBd91KWspT//WV7exugr8I+kHS6+Cd/8if3vP5TP/VTAF9RL8cP//AP74G5XHXVVYQQuPXWWx/wb9/97ndz1VVXsbGxsUc3Pu1pTyOEwP/8n/9zz/u/+7u/u4cxPZCUZYm16gaFEDh16hQrKytceeWVe/T47/3e73Hw4EFe/OIXn3WM3df1YMhu23LmzBm2tra46qqr9pzPlypfiv29Nxrh3e9+N+vr6zz96U/fc/8f85jHsLKy0tumD3zgAzRNw4tf/OI99+SlL33pA57fRz/6UW6++WZe+tKXntVH8+Xc3xAC//2//3ee9axncdlll/WvHzlyhO/93u/lL//yL/v90clXskaX8sVlCZ1aypctg8HgLIW+sbFxFm4T4Ou+7uvOeu2hD30o/+k//aev2vk9kFx00UVnKbH19XUuvvjis14D9lzXfD7nNa95Dddffz133nknItL/bmtrq//+1ltv5XGPe9xZn33FFVfs+fnGG28E4KlPfep9nuva2tq5XNJSlrKUpQALnbGzs3NO77/11lux1p6lm84//3z27dv3FTlcD3nIQ/b8vLGxAXCftuLecuONN/KJT3zifoOH48eP7/n50ksvPefzijHyhje8gTe/+c3cfPPNe/oLDxw40H9/0003ceWVV/6DsBq9973v5dWvfjUf+9jH9vTGfCUBzbna3yzLuOiii/a8duONN7K1tcXhw4fv89jd/e/Wx70/69ChQ/3zvj+56aabAHjkIx/5Rd93rnLixAlmsxlXXnnlWb972MMeRoyR22+/nUc84hH961/JGl3KF5dloLGUL1uccw/q8bqGvXvLbuX/YMr9nf/9vb773F784hdz/fXX89KXvpTHPe5xrK+vY4zhuuuu29OgeK7S/c073vEOzj///LN+v6TtW8pSlvKlyNraGhdccMFZTb8PJF+JQ3t/uvpcdOr9SYyRpz/96bz85S+/z98/9KEP3fPz7orAA8kv//Iv8/M///P84A/+IK961avYv38/1lpe+tKXfll6/P7kXG3bX/zFX/Dt3/7tPOlJT+LNb34zR44cIc9zrr/+et71rnc9aOdzf7K7wtNJjJHDhw/zzne+8z7/5lyrR//Y5StZo0v54rL0XpbyDyJdxn63fO5zn9vT4LyxsXGfsKt7Z9Ie7FL1lyPvec97eO5zn8uv//qv969VVcXm5uae9x09epTPf/7zZ/39vV+7/PLLATh8+DBPe9rTHvwTXspSlvJ/nFx77bW87W1v40Mf+tB9VlZ3y9GjR4kxcuONN/Kwhz2sf/3YsWNsbm5y9OjR/rWNjY2zdF3TNNx9991f9rnen16//PLLmUwmXxW9+J73vIenPOUpvP3tb9/z+ubmJgcPHtxzDh/+8Idp27ZvfL63fDG7dK627fd+7/cYDAa8733v20MYcv3115/T9dyfnIv9vT+5/PLL+cAHPsATnvCELxrEdevjxhtv3ANXOnHixANWBTr71zXW35+cq+0/dOgQo9GIz372s2f97oYbbsBaexZyYSlfPVn2aCzlH0R+//d/nzvvvLP/+W/+5m/48Ic/zLd927f1r11++eXccMMNeyjlPv7xj/NXf/VXe47VMWHc29D9Q4pz7qxMxxvf+MazMlTXXHMNH/rQh/jYxz7Wv3b69OmzskPXXHMNa2tr/PIv/zJt2571eUuavaUsZSlfqrz85S9nPB7zghe8gGPHjp31+5tuuqmnD33GM54BcBaL0+te9zqAPYxHl19++Vm9EW9729u+ourzeDy+T53+Pd/zPXzoQx/ife9731m/29zcxHv/ZX/mfenxd7/73XtsFWjfx8mTJ/mN3/iNs47R/f0Xs0vnatuccxhjzqKI//3f//0v6bruLedif+9Pvud7vocQAq961avO+p33vr/epz3taeR5zhvf+MY99/Te6+m+5NGPfjSXXnopr3/968+6f7uP1c30eCDb75zjW77lW/gv/+W/7KGQP3bsGO9617t44hOfuIQj/wPKsqKxlH8QueKKK3jiE5/Ij/7oj1LXNa9//es5cODAnnL4D/7gD/K6172Oa665hn/5L/8lx48f59/9u3/HIx7xiD2NW8PhkIc//OH87u/+Lg996EPZv38/j3zkIx80fOe5yLXXXss73vEO1tfXefjDH86HPvQhPvCBD+zB9YIa+t/5nd/h6U9/Oi9+8Yt7etuHPOQhnD59us/QrK2t8Za3vIXv//7v59GPfjTXXXcdhw4d4rbbbuMP/uAPeMITnnCfRm4pS1nKUu5PLr/8ct71rnfxz//5P+dhD3vYnsngH/zgB3n3u9/dz734pm/6Jp773Ofytre9jc3NTa6++mr+5m/+ht/6rd/iWc96Fk95ylP6477gBS/gR37kR/ju7/5unv70p/Pxj3+c973vfXuqAF+qPOYxj+Etb3kLr371q7niiis4fPgwT33qU/npn/5p/ut//a9ce+21PO95z+Mxj3kM0+mUT37yk7znPe/hlltu+bI/99prr+WXfumXeP7zn8/jH/94PvnJT/LOd75zT0Ye4Ad+4Af47d/+bX7yJ3+Sv/mbv+Gqq65iOp3ygQ98gB/7sR/jO77jO76oXTpX2/bMZz6T173udXzrt34r3/u938vx48d505vexBVXXMEnPvGJL/venov9vT+5+uqreeELX8hrXvMaPvaxj/Et3/It5HnOjTfeyLvf/W7e8IY38OxnP7ufo/Wa17yGa6+9lmc84xl89KMf5Y/+6I8e8PlYa3nLW97CP/tn/4xHPepRPP/5z+fIkSPccMMNfPrTn+6DzMc85jEA/PiP/zjXXHMNzrk9hC675dWvfjXvf//7eeITn8iP/diPkWUZb33rW6nrml/91V/9Eu/gUr4i+RqxXS3lfyG5P3rb8Xh81nt/4Rd+YQ/9XEev92u/9mvy67/+63LxxRdLWZZy1VVXycc//vGz/v53fud35LLLLpOiKORRj3qUvO9977tPCsAPfvCD8pjHPEaKonhAqtv7o7d9xCMecdZ7jx49Ks985jPPep17USOeOXNGnv/858vBgwdlZWVFrrnmGrnhhhvuk3Lwox/9qFx11VVSlqVcdNFF8prXvEb+7b/9twLIPffcc9a5XnPNNbK+vi6DwUAuv/xyed7znid/93d/d7/Xt5SlLGUpX0w+97nPyQ/90A/JJZdcIkVRyOrqqjzhCU+QN77xjVJVVf++tm3lla98pVx66aWS57lcfPHF8opXvGLPe0REQgjyr//1v5aDBw/KaDSSa665Rj7/+c/fL73tbtshct86+Z577pFnPvOZsrq6KsAeOtidnR15xSteIVdccYUURSEHDx6Uxz/+8fLa175WmqYRkb225r7k3jpcROltf+qnfkqOHDkiw+FQnvCEJ8iHPvSh+6Sjnc1m8nM/93P9vTn//PPl2c9+9h761C9ml87Vtr397W+Xr/u6r5OyLOXrv/7r5frrrz/Lrop8afS252J/78+md/K2t71NHvOYx8hwOJTV1VX5hm/4Bnn5y18ud911V/+eEIK88pWv7O/nk5/8ZPnUpz511rne1/MXEfnLv/xLefrTny6rq6syHo/lG7/xG+WNb3xj/3vvvbz4xS+WQ4cOiTFmzz25Lz/gIx/5iFxzzTWysrIio9FInvKUp8gHP/jBPe/5UtboUr48MSLLTpelfPXklltu4dJLL+XXfu3XeNnLXva1Pp1/NPLSl76Ut771rUwmkwe9qX4pS1nKUpaylKX9Xco/Bln2aCxlKV9lmc/ne34+deoU73jHO3jiE5+4DDKWspSlLGUpS1nK/7ay7NFYylK+yvK4xz2OJz/5yTzsYQ/j2LFjvP3tb2d7e5uf//mf/1qf2lKWspSlLGUpS1nKV02WgcZSlvJVlmc84xm85z3v4W1vexvGGB796Efz9re/nSc96Ulf61NbylKWspSlLGUpS/mqybJHYylLWcpSlrKUpSxlKUtZyoMuyx6NpSxlKUtZylKWspSlLGUpD7osA42lLGUpS1nKUpaylKUsZSkPuiwDjaUsZSlLWcpSlrKUpSxlKQ+6nHMz+KHDBzEGjLHY1NYRDeRZhrEWEwURiCLMphWN99RtiwACGGw/BZkYcdZgnWV1dQXnHNYZDKDvMEiMxChEHxEiUQRrDRiDNYaYzsFaiyDprwzGWn0t/d4Yo59ruitZnIOIjrdv25YQPE1TE0IkRhAxYC0Yi6Q/EQHpzrA7noAg9GdvFp/RfW60+ln9+aDnZE36K2uJPqYP0Gs0QJQIRtJL/QUsrkEW52DS9QPY9LkG0fskYDHppI1ew67TXTyjdHRZXJyerz5bY+jv9O5zMUb645x9jruObNIxubfI4kT0hvbrwBiDEPUZi7C7o0ike/KyOCXpX2Hx5u4Kuws1/brongd0z9T060m/18/pF8Ge09Zno+ferf+IROmPIXH33RWQuOeyF/dFf7+4XbvPwvTXq5eqa8Ug5M7inCVzDmLce38NGNHVuecUdn/srhPRe92dw653dWsXi4juR9LeienGGedweYG1qg+6tbb370HE988tRv1FUeS4dB0ipL3Y4IPeq8y5PXphsc92PdL0b0B1knOOEEJ/XVmW6SlFwTmra3n3ekrr3CDpvEzSI7vuT3+fWKwtAZFI8AHT7TWz2A273oale/bSP4jY/SSm37ek+7NY3yp3nzrDUs6W888/jLUWZw3BtxjAOdXdhk6f6tPbmU5p2kDdeGKvzzuKaYMhklnIHKyujrHO4TK3R2cH74kh6leMhBhwNtNzyBytbxERTDoHgBiDrvEsS9vdYAzY9HuJ3ULpFYraJt8SvKeuG5q2IQTde8aofRJjiRiidemzzMIemMWa7Y6ne8dijO7RTlNJZx7SHTGdbcKooZeUlVQngJD+cpe2TQZCkl216Z6BkZj+zGCtfmZM1wGG3Dh6K2otkvZBv3dkodPMnh3RPbPdsjt3urj2XrdL8hMWn3iv9++yFfdW+ella0z/a5F0J2RxN/Z+dmf7TNLfgkjsNDr3bpE16f52vkN3D/faUNUX3d/KntPtbEWna5I9S77Zbn1GOufuvXvPRRB0PfXu0x69Z3Y9fdP/35oABqwRMiM4Y8idwaX1pPZPMILqcr0lu9ym7lnBntXV2S5Jvlnau7vXqiRPISSb11+qcVhbkJUFLrNpi5jen1M/wBGD2u4QVZcboMhLdKsk2yCRGAJt6wkh0sZAWeRkzvV7WEcHpvthLTF2e8yQFTnOOeqm0rVkLbnLMVbdTWvTtfTPBt2r6Vl2NtMZS7dWbefOGZJfqzYshoBE0WvpfcTuS3b9l+62zj9UO6ZPfrGDkl4Sw8KKpWeJgTtPbPHF5JwDjYccPR9nLM6mQEMMEcdoNCTLnC7kKAQfuOOuE+zM5mxNZ/h+IVmMTZvGNxRFxqAoeMglFzMYlBRllhxvg8XS1i3BB9p5jY8BHz0uV4cks44QIxhweUZINxdryLOMPM8JEjEYnLULx4JuxYK0IT2QyGQyoaoqdnZ2mM8rvA/4YMCW4HKiM0R9hohxdFqw921jVCWflHe3a6x1YCBYDyE5G07vgzWW3Di9n84SGjVeuvicKvPWo4FGBJf1G7FT/Ka/mnR/jU1Olek3RvAhOY5Zb2BMtyptUtO986n/t2J7R9PtduDV0hBjUoLJmdT4T+hushqGpFhCf4LJ6EtS8LtUsU3KPdLfVyPoerGGIF4d3Bh75aFKs1PwoTfcsd/s0u14RHy6Hr13elyHcw5jkhLslfviGjCWKL3/nj574dZKlHQfdA1EiQTvCTHoRk9rQ0JIRj2ChIU52qXYTTJEkrRu931/TgAhQhQ13BIxRFZKR1lkDAcleI8R6Z+HQTBxEVlEs7h3i7i1vzAya4kI/j74IQzgxBCiBv3dVxBBXIbLC8rhKtlggMtysDkapNu0VvU+t21FjIEY1VHDGNbWVijLnKLMiTFQ1xXb21uqjAXKvEgOme33iDG6DtUI6XqMQCPCymhEWZY0da3rwjpG41Fajy2DMsdZS4yebpkYa5JCFnXmsGR5kdacvskS9f4mBS9RQDwxBJpqDkF/n9veUhJ2BZ0uKXEDGjqL6PoCgkDWWQxB7w8QOj1zb6dnKb1cdskFZNZSOEs9n2GMoSgKsrzAOoexGSbt5Vtuu4Pt6ZzNaUUbhIhFjENE9ZUlUOaOUZlx9OgFDIYDinKAtRZrus+oaOuaal7R+kDwgSzLyYuc0WjEZDYlxEhW5IhJAUPwlGVBOShxLlO9Y60GwIBvvXr70jmKaptmsxlVNWdzc5vtnR3quqZtAy7LcVlGsBkei8ciLk86617Od++jdrrLYp3rX4md3k861BgN7p21WOuIjTos1mggYIyhjSGt4RSkwJ5ERRSHTYGZRbBWbUmeWSQGmrpGgh5zWJTpXCwmy1RXGts7xpICq92BWdoknO3Q2879pHNaDbq/9b7u3krS51PMruQAEncbVnoPt7t7fbJQA0iRSAx+l9vW2Sb6O84u/S4xpDvfBRqLgMNY9Rs6vW+t1eRpd+/TacVokv6QlNjqVUevPxZ3Rd/ng9+jz2IMSIyEENK5xWRrVOfoWap9747VByPpg3ZbCiNCjscQsUQGmSF3lkFmGWSOzJB0aMBEwXR+G4vASJJjs3td9l5092GaCVZ/yiwCsSiRIEIbVadGrAa8NsMVY0bra7qXi5wohiAQxfR+UfCRECK+brEScAZG4zF55sgyi0nPuW0btne2qauKnckO+/atMxqNAKvPIvkqxhgyl9H6SIhCHSLrGxsMx2NOb57BWt1nw0FJljmKXL+sNYTgex/H2MWsrdbr2nbW6r4CMqupEmsECZ4YPKFpaeoK8QEbusBJbVefUNt1z6WLRHobJcBiD4YukdoFaabzkc7NNJ1zoPHK//unKY1liOOu2+/E2YzDh48wWttHWY4oyxXm0xnbW1v87nt+j5tuv4sbbr2bzVbwYjHk/XrJTGTf2HFg35D/z794NkcveQiXXnYJMUX6OY7N46eZbE3Y2Z4ynU6ZzmYcPHSQlfGYjY19bM93CCKMVlaofUvdtpzZmbC6tsrGxgZlmeEyS5FnOJsy+gLWaHaKAFY0qJlXc+qmZjKdcOstt3L8+Ek+/dkvcGarYmtacyp6Jk1gcx4w5RjBEmOAFA0nT0V/znIEIUgkdyVYQzSmd5LzIk95AmFlOKbIC8blkHpeIRIpixKbZYBhZzLRCJqYbJABZzDRYDHkNscawRkoBiVF5ijzjEd83SVkFna2TnNmc5uqavCtBobROEw+AJshLkvhacREr0rNWDKry0KVrzq0joiN6ux5XB+8Be/BRIyJmMz2BtLpHccCjlS9sYvgKHZKyhgNFIjYFM0ZiRTOakHJCd63mjn0njZ6DSyjahNV3C1BBC9dVQisdJ8R8aEhSkgKwNBbr2QIojOURaFBalH0BrbISw2ovUG6gClLfyRCjHVytiMxqOL2oUVEN2jbtNR1TdM07NQzYqiJfq73LOo5tCFota5bIyESxaY1tFDqLjqieJBAFjxWPFZaChcZZoa1gePyCw6wNsgZWFElbwyZ1Hq3JSJB0nEB58AajIQUvOilRWs0IEGIRGJs6bK5zlhCUOe5ip42RuoQmdaO1jtqX3D+0ctZ3X+QtY3DjFf3MVhZJQRLVuQMRgNOnT7BbDZh+8wmq6MRo+GAQ4cO4HJHljsOnrefwaBgOCg4c/I4d915J3/43v/GheddyIGNA6yt7MMaixHD3Le4PGc0HrNVzZnMK+64+x4uvfxyDp93HsdPnlRHUOCSiy9mbTxi3+qQwwcOMBqUGBpd58mZ74xuVdUYaxkMR2oARbASkbYiNjXNbEI7nzLfOkM92YboKTOD8TUmeEzrNXuLwcdWg2cjKYOXAqzklERjaEOg8YG6bfpKbV7kGOfw1vaGdyn3Lf/fX34loW3xdcVkexvnLGtra6ysrFIUJcVgRFU1bE9nvPeP3s/nbr6NT372C0zrlhANAYck59GJ58C+Fc47uI/nfPe1POQhF3P00kvwjccAwzxj6/RpJjs7nD51pq8SGONYWVnh8HnnMW8qTYRZNEkWAtP5jOFwyHhlhbIstPqRnAyXsqFGuvSM6R2/tm2pqprNM5vceeddnDp1mpu+cAubWxO2J1O2m8hO3bI5a/CuJBpH1JBWb05KCGmSLx3fuD6ZtXDVDVnmcFadmNFgQJ7nDMqStm6RKORZjnVqvabVnBCjXieyqzqsGVjjclwKNDIiw0HO2njIpQ+5kLIsIAZOnTjJdGfCmVOnMa7EuAKbF9gsJytKoiR3PGqCzllL5jKEmLLHYbEIpMtOLwIN9Sc02LA2JYc0H6nn2jtKmgTR77vgRO9KlGSpkr42ybnrqlsxemIMhNASki5XvSlJn8Q+INhdQejufAhekwoSU4JDdj07DTqyLMM6p5XftG6cK/SypX+AWklOSTLvfUKFBILXIEg/Q8/Xty1N09C2DVU1p23VgQ4+pOtZBJJaGe6qD3FR7N4lMWqSZSABYotEz8DpflkdlhxaX2E0KFgbFowKR5E5CgMSWqJviOm8YgxaQewixIRi2ZUZg1CrrUz+okErZSHqfZ63gTYITRCqJuDF4e2QjcPnMV5fZ9+h8xmurDIYrVCOVjU4x7C1ucO8qplsT1gdDxkNCvbt28dwOGA4LBkWGc4Zcms4feoEZ86c4bM3fIY8cxR5zsEDB1JAGTUpn2UUxYCdacV0XnP3ydNcePQoGwcPcWZrixADiHDw4Aar4zGHDuxjY98qw0FBnrl+72ZkRAn42DKdtxhjGY+GmBAgBkI1IzY10tb4aoZvapr5jHo2I/oW29QQAyZGiPosTVqncq//IqLvESFG8CHgvdqnzl+zHYrJnnvnxTkHGl93xdfhQiTzgcLl5FnB+UcuIB+skBUDVkb72N7c5FRZsDIaMRgMyIpCIyixGIpOhZI5yEpHUZasra1x+NAhLrnkKFVTg8DAZgxMxnZeMiwHhP0bRIHxeMzq6piDhw6yPdvGS6QYDGmCp/GB1e1tVlY10LCZQiTyXBd1ZqyWt43FYjGimXsrjsY3tL5lXs/Zt2+dU6fOsLp+kBOndzh5ZsJn7r6b4ztzZjJDihHRaOTaZVnU1iRF6/Lkhwo2K1KJepEJsN09QZByCFmBlAMyV2AwlIMB1mlWpzJarYndkrAJGgYp0ChwRrRMWTjylNnef/55rIxKTDjC9vaU+axie3PKtPbMmoA3OdFmiM012yyCiQHrHNZYnE1QAQxiApaIJWDEgViiyXBOsyy+bTAmarCRO1WqIeCMxWJSoKEBRxeYK0AhZTKM5k5AtFIWIyZGcqvvdw7aNilH72l7hRR3Ofwp0ACtHohgIymbGGl8jcSQMh6okUqKSgS8AZvnkDlCloG1GJchRYkRi80MRlT52dz2FReRVgPBrlQZVZHrZQjBe5oEeXBNRUiBhm9bhV14Tx1afAyI18pH7AIodmWQBFzMtEwvQRWMtCAeXCQ68Baq6MijxZhIYXNc7hhmGdbqGsH7hdHLVElYif0asAmVhO0yk5EQ3cKJMAYRQ4xQSaCNkSZEBpWj9ZZ5nTHIIhk1JswgFNiQUw5WdL8PM8arI/IiYzQcszoaMxoOWd+3mhSXYWVljeGwZGU0YG28wtrKKsfuuouNtQ1WhmMNYJNxnfsWl+UMRytk8wF5MWNrOmNjYz8HDx4mWkdVN9SNZ33fBhvrqxw5tJ/zDx1kPCwx0izKzigEpg2eaj7HWstoNCL4lugDvpoR55ZYGUIW8IXQOk8zNBADhQMbGkwISN30wZkXjzpikjKHKUhOOyAaS+sDddvS+FafjTHkZYGxlravkC7l/uTo0aNqXKs51WxG5jLW1lYZj1YoyoKyHLEzmXFqc4vRcEhRlGR5gYtaFTMmU5tgIBOFALosY3VtjUOHDnH0kqNUswpiZOAsZWYZlgWZsWR5TlGUCDYFGoeZNzUhBsQa2qSzJtMpw9GIldUVdRwTjGg0HJIlvWt7J3khMUbapmUymXLo4EE2t7Y5ePAwJ06e5uTpLW688xhmZ8aMKdiSYByyCwqmm9toUsFq9haTJWWsn9XBck3mUjUBYlkieY6UA4yLWGMoylIDFKDKppAcnXSQBRTYWFyWp2oGZASKYclgdcT+8y9kbWXEsCzYf/AM08mUE8dOULVC3apzaFyGK0qFB6EQF5sg0ZlzyWGPWkXvRL2glPVfwNX01LSi0knvu9J9pUAjVRm0cL+oPHaJKSMdZJX++XUOsg9tn4XuvkTSno/q5HfBY5e8gNgn0fqKQwoUOiQdxqSkkCW6DOMsxjmyvFSfQ7TKY4zBucUzjWHxOWqT1LHsAhvfNrRti29bimqu67Rt8K0nBA1EfHL827ZV+9kl+M6qeJuUIFQ/QoLDRA8WxDmiLfBkeHG0yX8wLqPIHY4cG3NEdC3F6LV6YIzau+4epC8BXFRnPkr6TAPOGK0Oi1D7iI/QeGFeB5pomMWcgYNMIsa3mOCxMWhC02WaeF2F4WDI6miV8XjAYFAwXl2lLArKMmdUZpRFzsqwZP+BDSY7232FziAMh4NFMGZ0vVqXY4uSbFCz03j27T/AwcOHcYMhTaO+wcaBQ+xbW+XI+Yc4uH+d0XBAkVsNdo0m3kP0tKFhXjUYYxgNBkjbENuGescSKkdoLLGE0Dj8wOJHGQSPaxskeIhB/0VAFkFGak5IwWjnG3VVsKiBRus1kLcp0Oiyxuco5xxoHD74EKqdHWabpzl05GLKwZD1gweZVZ4WiykLmuDZmU2Y1xV12xKNIRqFkBgDJqoKdFZLxN4Lm1ubTGdTrLVMZ3OF+uQFk50ddra3mM3mHD7vAs4/cgGnTp2gLAvG4wFkkTZ46sZTZBlZnhGiGhZjhJ3tbQTtBVkdDRkUJaPhSr8veiinQF4UZGVOuTJgY/8GROFxjxVOntzh2PHT/P/+y3v57O13s7k5ow0eby3BZAssYVpYoPjyriyucCLNJCteN20QIxgTmc2n1LairitGZUmR52AFsdKXs6KJBJLi6TIqNiaDEImo89lUc4SSQTnGuIaNA/t52BWX4aKhqWo++5nPcesd93DnsZOcns2I0RFNDimgcBgt+xlLCLHPrhnTEkwk2EjUp4dLpWwxhhDVWbNWK5oxKTbrsvT7mBa1Fk/6tZmUhnRZJBKkJwaQQNN4xeznrleOIaSNkpQaqXwb0RNwztB0ijAmXLAItKFX8E1S+MSYFKcGBJWZE4AqtmrQMoezGc44MpcxKIZkLqfIS3KXadXDgEiCBhmjzrzNCG2DlUiRlwxsjgyGrNl1fGzxvsG3La33zGYzsmZO42vmkxlRiwuqQA04Z4i+CzkMYjICmUY55BjroXAEIlXbcuaOHXITWc0jh9bHbIwHXLB/zLCwDHODkTlI0CpGggmRAmawtNFrcBj0vhp92hirxt4jKatoKYwjRxgBhTW0wdCWOVtnbmPzREsTLflgRDFa4eJLLycbDJF8QKCgLFe44PyjFLkG1bM24r3Hh8Dm5oTMGsrc8ciHXc5lRx/Kw1/4ME6dOM7m6VN84bOfxTct4j02CpKqmW3TEusGGyLSeELdUGYlTdXSzOZsntkkNwYObhCCp/UOGz2ZMzirRs3HhlrmeCocEKOnrqbUsxmnb7+DMNlBplPKEMgtFM5SmoiYSKgr3TMRYqtKOyAERw8taRLMojPTGswZWoE2GmxWKv7bac8LQAz+Pgz7UnZLVpRgFEgwGq+R5xnj4VD3qXMaCMiMet5w+tQZdiZTvECLxRuTEicpixoNTevZmUzZ2txiVs3JnCX4ltA0hBiYbG0x2d6imk/ZGB5g/8Y+ggjlYECeO9poMNGmgN0iOPJMcdwWo7ChBLEIrafIc03MWYUrad5KYTODomBYlKytrHLB+ecjAvX/u+We46e4654T/Mf3/nequ09gZgFPQSuWRlxymVNlBMU8qEPqEJNhzAKe08GNnDVaUQ2e7bYhc5GyFIqiJM9zJB9hrR57QoPHElICpgv+baoQ5JIpPIaIE4it4NpIzErKtQ0uuOB8Lr7MEkLgzKkz3HLHce64+yR3HjtBCCB1pOud0SqE2syuH9AYyDLFqe+GmDpxvRMUkh4DwVnpIwu3O1nOItGAaBVCj58qGwkOrbDKBbzSGEmBqmZ+2wAxaO9oNI4OVBSNJdrYVy0Ek4ojWl1vvRBFX/PB9pArn/p/fEo+dbCrrpetLMo+wCjyHOcyirzQfle7gL1Zp9UlOmiUCyARl5fYGMklUgatYHjvtffAe+q6oqkrvG+Yz+e0bUNsW6L3uyoz9HdPnJqlKrZ9MBsR2gBNBdNmSmaE0kb2jUtWBgWH1kaslo61gUKsrCMlGQUkLGC20vUCOoy1ZJk+07jLjmVdRcoYBpkhYvC5pXJQtUDVUp05weT0Se6+43aKwZhiNGZ9/2GK4YjBaJVyOKYcjDjv4EHE6UKZ+8C0mSDbkTK3rK+OycqDHLnoQi60F3H+kfOYT3aYz6bcdcdtKdg0+OBpmkjTTKi8MG88dfAEYyDLcalSuDVp2GiEcbRgC6zVPkcSMgQJBNPifYtvKlzQHrQYZtTTHdr5jJ2TJ/DzKb6a42KLlajQLwSHUBohSJOCxbZfSyTfXBC8KHyu688gBbsKxY5Y1/VGmn6vBB/79z6gjj5XZb6z5bGUDNcPsbIyxhpD2waMUWcMH2mrimoypZ7XNK2njYFgnFYA0mIQUrY3LezTpzbZ2tqhaRSjaqJQz+ZE32LE01RTJDZkuWV9fZUsdxr1OnWOYmYVfhIjeWYYDXJWVwYMSsVzhxApspRtiQlT0+kfVGNFI0QjtAQyY3AWciPkxpNJw+TMcerpFpmN1Eaz4kGClqPToWLU6NtmxSIrFAOkTFXUp4Z1LmU3Is44DEKIES+Ka4zOEKLHh8jct31Zm1T6VkWl0Kogel8tYOwQ7y3bk8AnPvkFbrrxLj7xkc9x5PBBVldWWBmvc/BIjhvvZ/LZm5E20orVZ4ekKoEqXGe058aAOrM2LhQVUZsQOzinSRFx1IUnogGBMRrLxeApjFHHTTSSRiK4rp8lWYRklGy6HmckwYhCn3ETEQ1eDFRt20ctMSSnrl2UuLuashCpO2sihhAsPZI2OfWNoe89AEMMQh1anPHpA4QdtpJN1hK+s5bcDchcrl9ZhnWKuY5Gm/gDWumhqyKgJXxbZGSZYWCHFHFIjJF6VGkWqfXUTUUMLbFtCKL9Hj5l0pwxGFHsqYjDiyPaDFsM8ECDUEvDZAZ31S03n7qL9cKxb1BwcG3AsLCsFBlDZ3E2EmXePUiCQXsqbLZ41ruqTzbtTwjkzmjWz4DNhOgsPgsUmaON0ESIpiWELe656ZPgCkw+YrzvPGR1g6oYEEdrZOWQ0Vj3dbCChAaJLfPZnI/8P/8PEhuqaptqPiU0NSu5YzwYsLIypFhZY161nDh+hnnlmVctofE0VUUzr1kbj4ltYJ7PWV9dZX1tlfFwROEydWEkoAAng/ct7XTCfPM09WwH8Q1bTUU12cHXNS60FDGSxUAuARu0AqS450BMz6nbj0EiHsFKpuuMgNf8St+wqO8PCsvPXIJbQAwBm6fmY4Hc5SlbuZT7kpiVZPmAcrzOaDBQBzIkPWP0pjdVw3QyZTqZUVdNagRXyEQbIz71IOR5yqZGYWd7h/lkqj0YqQcvNHMNOOqW2Lbk1rI6HoFReGCROSIFPgRa3yZ9JoyHA8YrK6yurlHVFSEopKXIczKXaQXY2EQIYPsKojZNdw6wvlY4R54q2/PplGo2o2laWufwQNtl9hQL1AcbMSVFYFeeLelkzSCn4MMlWJW1tF3G3Fpa6KuuM++TA0xfkemCJADPolqAdcx9IOzM+NhnPsfKrXewf98aBw8cYDwcUZYDbDlkdf8B8u0Z0vrU25muQRTAa1IQ0/UMhM5hSokZTeTR9zJ0/RLGpJ6+FJREduPVF8FGZzfs4tYh+FTxXeDcjUQlikiwxg4GHERteRO1Qt9ltyW9HmWXLUj/NrHr0xIW7XQmgYlJfQRdlSOqc+ehqpv+M5zt1ouiEay15GldZZlTMg2z6K9ZFEk7G5nWnHW4DDCWHMhy7ZnLywFtU2sFxLfJrwrUTYI0h4WjGV2J2NSH4bSxXwzUscXESCae6dRTVJ6TkxmrubCWC2ujgmFuWSkt66OCwhkGRUaINsGTzaKfLWqVTmyWyE7UPlrp+tkStByQLCXGioyZ1wr8vG2JfgfZmXFmuonJclw+ZGX9AOPVdQYEhhv7yMsR2aDUz4+azD156hTH77mTT5kIwdPMp/i6RoKnLBzloGQ4HDIaj2l9YHtnxrSZU6Wq5Pb2DqO1HYpyoDDAGMmdo8hyBoVCpnJjcaSkVFAfuKpmzCc7xFZ941BXNNMJsakxbYWLgVICuel6CSPBayVqFkOP4OgLd6SkpiElxfTlkNYUu++3GJS7YQEdtMaQWZtQMA9c2jjnQMMHfVjFYMhgvEIMgWp7C5uyRkhUiEHT4L02SIqgaQNZsFuASSU9dZI7DHv0QZu8bSRUtTqdBiR6IOIsDIZFzyhljdHGcHH4dBMzZ8kzR5nn5Il1pm2CZkJ6RULKCO9SxN1N77xrVNlYIqSspm/rVMGQtEWl2+fJMKWMPIvjd41exnYKvXOWWTi7nYKSiI8RHwOtj7Q+6HWl41tciia7YMMkJgFtvbLGEgSaRjh+cpvM7HDMnWI6rTmwf4OLL7pQM22uAOzifGy36LrmMZMUayriGzXY2rjVNdUr7h3RBtdOmcZ0nCgKQ9FmaE9IDeixKx3HgDHpeqxBUpOaEa2ZCNITB0RBN6R0zbOppBcDncbssJleFs+5Oych9s3NXdVEX1cYUMCgKyw9IzrjEFVJpmbuGBK7iJHU5GgpshF5VpBlhVZAnKMoihQUam+KSVkBrEnHlFT9cLgiJxOboAEO33p822IzS2gbNfSmVSY0uiZkNHsb7YLlAqO5i8REEQW8b5m1kZ3phKpwtIOCzBh86ciGGcNhrrhl2dUY3jnCvd5YVOG6qlOXvdjt9uZpfWdWn5sXRxsibVRWjq3JDpEccTNym+NCZDsrGazVFKNV8kwb9iwOHz2+qannE86cvov5bJvJ5DQxtDgTuejQAUxcIXcwzPaR5Q6bOayNPUY5+EBoW0aDAVVdYa324JRFoT1bxmBFG3QlRjyRyfYO8+0tpqdPEaopsamJ8wnNbIL4llGRYawmIUxi2xAjhLbt13xMzHvOWoLRPS2pRB0kaCCF9A33XWbTpJK0pu1Ud9hEnmHRjGWWnbOq/j9OjCtwCSddlAMQoa3mCrFI9zOESFsnuIgPPeOU9PpU0l7Q5mwjQlPVNHVDDBGnlDDKhBYXe8EZS55lagczTRxlTqvZIhbvO9io2qXhoKSDs7TG9FWMzgHsKsw9dFUNS8+2ZozBZtrvSIy0da1QzBhSBVxSb4I6wUYWtqZzLKFzthf5NhH6d3XVarWLWlE3EmmCT6w8mmnXrOiiMt31uew+vtor8AKxDRw7tcnm9oTTm1tMq4a11TU29m1QNZGA9ocFWDjdIv0xRaBraLd9tVxIYYg6nVb/uM8j9nY2OfcImK7PYGEvdgcbsssZ74KDPtBIwQYSCbgUoMUeyhNSEjXdVbqexUVFg14nSGpejrvzY3RBhSyCo+4autc6+KV0/R4k36KDmDnyLCPLMjLnemZQazXosFZ9p66hHUOqsGkFxzpwkmFwyTk1PWOabzNtmA6eiMX7gJjQPzCxRiE6YhC3IBfp6GEClug9lQ/U84Y6i7RZJPiCpsywkjMuLbnV5nGsVomTE6V5yo4wwXSkNQr9Ae01tN3KS0ljiyHLHcYKuVdygjZ6fGyZz6dEHI3LMbGFds7OsERsYCCttt52TfgSqKoZW6dPMtvZJDQ1oamQ4LHA/o01VlZWwBgGwzHOGbI8xzrtqwhRe2d827K6upb6h432eGSOIrM4BCQQQ0Noa0Jbs7N5mtlkh8n2Ji42iPe08xmhmiJty9AuCGCso4fmh9AoQ1bowghwqSIJ3T5LQXKCa4codIQUMQX70djESKVrxdq0hlLPlHMP3KtxztZruG+VosgZDEqiMdR+xtasYv/+ocKVvDrleI+EFiRgHeTJIW6CNi1rWUebZTJrcZlNUKrA/vU1fNNwYvsMRWZhWDLNSgpjMTEwGJaa3QgBk1uNBIdD4s6EECN5UTLMBwxciVghuoi3nqbVZjYf1RmyRjdEn/iOqeE5lUhJZaXWN8ybObWvE9Y6eWLGcG8K3U5i9KoYjcWYAjGWNpX0DKgzbBOzlJiUBfFIa3AxUIWWtu2yBAXReCKegSnJjCHLij77boNPm83SRn34XYTqMLRYbrjzJPbOk3zk019QrGgUyHItCdvOOQVjgi4gLN7HHhNrUzSMCRjJUoLQE7xu+uB2seKIxxg0yPPKFJVZdbJEUoUjBVU2pHsSTd8kiygu1EQ1OtYZnFNTFWOkrps+GPONx2QO4yxtanZDoI4dTlZxkyKR0LQYUeRuG9p+s/jUzKhxgGbyvG80uEisZp2R0MygeuHaeB7wfkqUqRqKUCUHxTIajsjznDLPFdaXZeQuIxqIRmmdEXBiCalHorRW4XU48mI1VXUM7byibT3TqiX6OcRWm7aDIF6ITUtoghrdEHDGMByWidkjQAsuNrRtxfHNU0ycUJeGlQsOMhyXFKVBnGadnDF4WprYYGKeMNE5Gen5RK/rRoCYlIuJPfwqcw6bJbXfCF3GeL0saFNj3vaJW9m++2Zu/vuPsP/8Cxmv72fj4CHW1jdYWd8g+IadnW2OHz/GsWN3UlUzYmgpMkOWwZkzx7E2I89KHv6IR7Kx/zwuuOxKViYztnambM4bhZKFin2H16lkjj3RkLlAlkWyPOJMg4nCdHuTna1TbG+d4lMf/wS+bjA+cnA0ZOAsAxPJM03wip/RSMBLABQ25+zCifASEcnS7wzGKfZ/7ucacBAJoWsxFSRaEJOogLX/Ks8M1mTkLqcsNXjNUyOo/RIa7/5Pk3K8inMKcZy3LaFtqCczxkVO4ZT2tesdI9HSeh+IKBSjyAZE7zVTnfSUxeDrJn21jIoBAUsdNxkUJYwivmnJnYMgukaCp2obXJGRZ04x21vbCqcIWt0obEY2HvUUzh1LXvJdVUdI0OqGTf1yTgP43U63b1uq+Zx6NiU0TbKnyanX0InOzTd0jl6C7kTfVwfUVulRO3RR53iLGIIY6gra1lHPp33gEEPo+yFiVDiOQoo6B88BKQGVIDzWOWqJzOeeE5sTTm7PKYuC4WAIaLJuezrDGEuWbNSiPZ6eorPrjwDN0Frb9SmgSc10PZ1D39/gVPXocV5JOpvfV9zT5/XpX1FIb08rLrpfJXbQLu2v8CEk20z/d10/YUh2S7qERPrPp4Rsd087tsSYmAslNeb2SIAU+KRWFf0xdP2GQgiGEKCuYn8sTVRanLGJStxRFhqcKxQrS+AC7fNwxuByhw+RIIa8LBN9eWKtStXYYaPMoL5pEN8iwdOGoOxNbQBfQ9SkY2YNmTMMSkf0Cn1t2jlVCBStQDOhyS1mnrEia7ihUtHGVPGx+a6eHZPpOu5YPtPm0WqT9EyZRkCsBh+OmlEGwxz2rZR07fjTqqFpA/O2ZnLmdqYnb+Oumz7NcOMgg7U19p9/Iav79rG2b4PV9VVyqZBmwom7bmO6s00zn6lfi+Gu2yzD0ZDxyioP/fqHs7K2zsrKOmIGZPmQze2KcTlg4DKOHDpATqSanOHAWsnGas6oAPFTqiYwn2wy3d5iurPNTZ/7LFubpzlz6jRHzz/MqMzJDbjocQhF4dLeVqi9SUFHCF5ZuKztgzPbJQ+B1utaDdL5QV2FMG0PYxIMz5EPNZntXCJYSv8+6IFGMShxKUKdTHaUOmtX3dFYcJkjzwucVYMbQmJLWuzp3im3KRoyHVsTFmu0BCsxKgsQlqLYJobAfLLDSrlBiIHpbEYxzMmKjEGRY6wQxTOdVrgMRuNCsaiiAUGRF6pqU4DQ3WjFXqYskbFJHSef2RkaCczahmgdYh3i0EwyXWOs9MFG8qIxmV5PlI6m1iIp49KlSSRq9cJpzhuJ0BqDD1A3AkYDAJMwnViHD53Tq46yZiIcISnNIIohdcbiE7WaM0JuEy649T1bRk91FvW+ATrHJPVHEC0Z2k/TiscaIc8kZW1QpRK1ItBx/UsUhVmJ4GnT9WopLsVtadZKyunuWhTaoBQxdP0XscvpYkXpbYnKve5jgq6Ryh0SNNOmyTUar4GG2pOupJ2MtKDZlSjENpB8/ARr6zYaPWPI7opgh5Pd3Rvi21YzWFEwJCUchOh9Ygcx5M6RpXK2cQ6TAo+O4cskJWWyDJSQL0HylK3M5A5HJG8jrdf7N8wV/40FkZosj5QI64OC8bDg4MENMqeB/HpxCatlxlrpKKoK52tcM2WjdFgT2Jltsz2bM2895XCYSu9ukVwnErrCqpG+itbzcovr3kg/Q0QUZoXtmiwht4ni0BrqNjCwLcxOMWt38PNTbJ4YkQ+GRK/9GlVd0c63kJCaAxNewuujwreWY6dOU3lLE4cEUQjMgYP7Ga2McM5y4tjdTLe3yIyQZZGm3uELn9+kNIIJgclki7ataJs5Pnimdc1sMqMocxgMWVlfJ7fgxFNPzmBCxAQPxqVAMEFzjMIoYqcbkN4gNyGgkEnb+QgJ0aO6SHuA9Ku0Dmscmc3JsgTPyzr9uJT7kyzPE6wU6rZJvRSxTwiRSDS6Pgx1Qhf2lGQbDIYYAwbNBA/KAUVepOq5A5chYhgMhmTWMZvOiVGo5nOyPEOizr2ICE6EvMwTlbmhDZ7WtzRtnZibwGUZNi70YMdc6JJu0OBykRXvbJMFQgypkVj/3trFCjG9qdEr7MLbPogw0uvYFLfQsSf2mf+0v8UYxGujsyUFxl0YE/VYILsSVl0jL8neSN9n4IOiDsBg81IDNy80k3kfUCgDX4LZxpCudxFs7L5PIqHvCYmJXr13SXqMSDq/FEB0DMIpJlnoc1ngzfvPMtDNCjBxV19bYmDsekMEpcQOKdBYQLokUZ3HPthQCFs6l5RAE9Hr7QIN6foHpaN0T3Yz/azQa1JFI9HU9llTveS+Cb2r+qSEal1pQjJzCvW11vT2yFpLlmc9I5pmstPsE+l8GE2yZBacCMEITRuRqOQka1lS0FZwoXPyDavjIcNhwf79awwLR5FbxplhJbOs5YYs1LjYUoSKsRNsDNSzCbN5TdV6Deat7sEGZeszRr0GMRokdo3h+uhMQl8YXe/6zv5eJveEMhfyzDEY5gyKjKYNzOYt+B3CdsOWtExOlxwvSvJBSdu2TCcTpjtbhNbrrJDUr2mM0NQVTdNyz913szav2B8MYguyLGNjfZ3cWXxdceqeu5lMthA/Zz7bYtt6XJwTmjm+rZlNtmnrmqau2NzeZjqrqFrPpPbYrGC8b42Bs2RGoJlT1zNCXWsi3WpPk6b8UEh0V5CIC2SIDx3qI2kJUfhdh9iwToOMrjJmrcKlsswl/13Xz94Zb/ct5xxo5EXRbQ12ZlNC22g5udd+qoyzPAPUyY+B1Nhs+s1vuvJWWszWZlijvETKuqGQkLxQmruyLJEYmM+mjPevEWJgXs8xWcQ4VbDGaqPYvJoyGBb40OBsmW6axea2Lw/uHd4HHRwJQ2Kjiv01tRKpQps2nHY7pREW92H4tWxrrI7likGpdBV6EvosC6RyVVz0HhAN3qvD72NLlpdYl6Ms72CwiiGWqBCS5ITovVXEhZeIlRTXxoSdRxCXKWQmRq0gdcpYFPYUvJ5HZp1mpqIk5xHA4KPXAVZi1dlP2W3tuuiCLeiwsiKqWLNEUadYdDBiwKdMm1lEzloK9iBRh/30peqUYROTKgkoNlSkLzd3dK0++D5wbBPDhrO2310d7rCDd4UYU39Rd/87BZQgMSlj0yWRDfSMGwsUMvi2SaXyiLP6974NWkEBIp7MKuMZkGgbC/KUVcrzvJ9Ngx3o5yeFnuwIxhmcGHIbEKOB++ogw0XBhojNhAHCmoGLNnL2rQ654MI1iqKkzAuO7N/HvtGAfaOCfDonzKfUZ04i1YS6mnHn/AxNNaOazjVLkpUK3UKINs3JMFEzJW6x7m0KOBwJJpLWXUwldGXx0cy+SEil1gxnhCaHgQ1sVzvM54H59CTROoJ1iNcsSl7kOnzNQGYHi1lkRvo1c2Zri8ZbvAwphmNcnrOW+rggcuyeu2ibBqInhorpZMbmyeO44BVfW89xWWpCdI6AYdJ65tYyGpQUB/ZTIhjfUlUTZaAKMTHXKZzCZZlWKJ1TRrMUhOrgz6D70qahZKZ7g+kDusJYikyrX2VWaLLFZokjXci6Zbw7W7OUPeJc6oORSNO0hFapaI01/dC8DlKyyNJ0/pfscS67ZuDMOQaDLtDQyoJYzT4XKQDJiy1EhKqqGK2MNanhU8+N7RJqGux01KKtb8hN0Wf9xaScu3RpLpuSEInVqM8gx96ptslB9UnX9YFC7zLYXfYpVZx3Od19r0Gvy3qNo+cRF065wRC97wNoa12qwqWEXefYmd32Pbl0CfrXOfkmBIRE0ZoVib0R2qbW6zKGLMt7x5vELCim45HqgggB9J4qwEChHd01L2ZupPva6XWS7jCdE5oCjV1rYHG/usCnCzA63ax2LhqFElvXUbqHnu7Xd3016HA3xfh3AcJuKBQpY590Z1+ZiOn7LihJTuOu4KMLVRDp18juQEODm5CG0Cltemj9LrbYjnI+VaKdVjfyQhvKsyxT5EP6fldOmW72VOZ0ZoslgPFY49koM5w4XBTyoEP7CuPYvzFkdWXEkSMH2bc+ZjwasLE6YrXIWM0zqCfEaka7c4Yw0ybnk5XCVmNVEbKo1MdG90RIe0STmfTBgwhpfabV0u2vfg+oj9It2jyhIqwrKItI0wYcgbqtaauKWTujjdpL40kBoUSFPDpHWZRkLiEijKGuG6rGc/LkCVofyYoRg9E6xmWsroxxBu31uKeibmf4esp0+zTSTqmnGdV0h6apmE+nKSGijeRtBFxOKxZvcwarG6wMcjID882TzOuaqg3kTvpqu0l6qK+aYiAkWF7yWzCd7tDz73zBbsaPBhlaoVUbblLCRq+5Q5I8kJxzoKGVW83e+sZjjWPfxsGUtbGaEbaOKDCZN8zbQHQO0qy0zORIFjW6ioKJQobhgsMXsX/feRgKfNAGZztcJS8H5NZy+CJDW0+pqm0IR3A2ZzhaBSB4ddCHg2GqpBSMhmOc1aFIKa5dZBET4WqPTQQdhtetwaCZIogUhdIoSRNp5oHQBIwHawPWRLwEukm+McS+ccb7JmV3nLI3YXAJLtVlt0hQCqQFTI95U6x2YrMSxT6GdA1ZOvdMHKIIAGrbeeMawYpoxteKVkqchTrU1BhcRGvMRo2vNSCEXhE3bVQ2DiMpWMgSW5hDRAfFSGImECLOKFVw/5qwy+FUKIkunEVQkbcpc2i1x6Bj5wrJfY9B6IxeTDhPFw3BJoMjER+VZMAHDcx0TTa9EsxjlxWCYLWprgohzUxJhtuAKWyiChFSUQcwSLSJThhiaHtmpo79osH08ADBYghKL5yC5cx2hlWzPVEa6iiI5FgfsPMKG70Gx4UlZjliM6wdUmYDiqzAxgbnIMtgnEEmgRWZsbEirA8yvvHSC1grc1byjFWEvJ2TV2fYyAKZFbyZYP0U4wW59TZi8JzyniI2iK/x8x18aPDBk9cz1qqKrGppq4ZQjMgHI9oiJxY5Mh5SJWUeIAXMDrI8GTQ1ogatpomJRCu0YtSBz4QgylzWmoArdO7HuBixPtCm2Zk0zBP5waSZ6pyOmcUWJTbLdX6LOLCOgcloJdJIQ1vPabKCttrBNw3W5gyKks35nNl8zp3HbyfLDOUg56YbPsWwzDm8fx1nIHOW4XjA0K6Ql2MuveJycBnB6vMfDQoOnneQkctxUVg7eAEn7ryVM/fcQR6EEFulUrZa7QltTZZqlFRGaZElI7cOEy0mWnKjrDGDUZnmtjiy1IvmjIDtMu6R0KqjUPmW5A4v5X7E2ZzWt7RtS900GImMyoJiMFQmvxhTxUuoW+2B04KbJSaWvcyY3uC6LKccDFlbX2e8sqoED5h+D6yOxxR5zvZ0SowxEVOkTKBLsI60N4qiVJ1uHWVZquMetW/PmoUuMV3OVUwPkwoxKHQmRoSgTp0xiYoyIETaoI3su/tNpKsIoFWN2AVUsUuiaRZYlBuVLnWmAyjVae2Cmi610P2/d2hNR8Ea9bBWE0rWJgYrlMEqGOmbt0UEaTVQ7wcC0jkridwkmgRdiz0Djo3dJG09j2C1YqQoBQh0TFELR9ikY0gKDPraVVfFoHOcU6CG9D8v5oF0PRrao9gdx4ioDUuJQEF7VvRr0b8iuyEpXZBDV52QPgDZU0nvvk9n3A/5S4mc7vddNUODki7I6LRER6erF+lsV5mgf5/CPQPihdYv7l3neDpnwem6zfMM1zmfxpAZQ+kcowxyiWyUkbXVIetFxqMuPMRa7ljJDYO2IouePLYMC0vmBGumxNkmMgu4MwaCpwoeM58hbY3MZ5i2wbWe8WSKn1bYuqW2GSYvMGWpIwayHDMYKJEL0CoeXYlq9mjLlGy0On+FlOgkBaKayQ+07RxrLIPcMNwY0tYtvg1M2pY6ROoYmVQ1PgptjLiixJkcCRFjS5xTOmdT6jwo7eeYcuLkccrBDJeXuLyk2p5TVxWnTx7DOigGltP33EaWOcpi0VtTlCXr6xusrK5x3sVfl6qbFpHIYFBy+Mh5jMsMGwMn77yVyuUEYzDiNbEWW7UpEpGmUb/XmAX0WSQRH3UJf5tIBDIKlykLmNGKhUvroVsjHXNV6CtzD2JFQ1kGOqozZcvoB6ugwUMIkdbHHvseJKZJ2poZcP2DVyhBURSsr68zHo8XU8ONwTiHzTKcyxitjJmK9lnEaLE2oyyG+NAs8KCZS9N/oSzL9FCS4VDNkqLDs69r96I0/c+arQhBM9QdhV2XAYuSRgUZ6Lvzu4xUUsRC6mvoS8mJZSboYokp626Mwi1iz+Jk+wxXagXHiMWLjmGyxi7YK0h4VUyf3RFSUcAYnIBYAZNmdUokGINN/NQdplGjJYOYBc5RjEb+xsZdVRzp71CXl+mbYKNgXbqDItpD0GVwkyJXeFeagwD9vwFP13BMVGXQNf0ZFIajSjsoC5Mssny74WvG2D6olBTQ9tnCrgrSZ5SkSyntwtSmTJCRtGy6pnldD9KVZpORUAIzkyJ7le5egcIJugy30U2ixje2qu9IzeamJUpL5uZagQo1w8KyOsy5dG2V9XLAwSOrjGzL0EbOz2YMxTBohUEIZLGmkAljibio8LDOaYo+JIy4MlLEFDgRPDZouduLx4inDk1PSV0HS2hzgm+wmSM4R8gzTSZYIVi9quhAF5pRw2skDUvsnnGCW+kyVKpnARuF3Fp1SERhGQ7BDgt8UJhYkIj4hnYWsS7D2oxQdJAYhXT4qmK+s42xA6zNaPOMutFhVARlbZNGOeKltpyKNeurK1AWNHVGXggiyvuflwOycgBOJxjHaGijp2kbjp86yfbODrOmoRSj0BNJCjStq2giCc9GZrQXJ+syhVmmk3GtNnfnmSWzKUPdGfkOliIGr+G8wjbvpaeWsld8jNSJ1cW3XmGDaYaR+sTa7B1CoPEtbfBKINEXbnfpBLQ65fKCtfUNRuMVumnUBkPWBb9ZxnC8Ql1XtE2rNss5CqvUlh0tapbl/VykrKMfdZ196jKv6ehieidXLbpBy/ZJx6RMdpYaS5t2AdWJccEg01dqoF87vf5OzqkYi+k3qqRGctPrO5xb1EU6HZZsU0cPngyWHjthkiR2tY9EH6uqoT8TYrILCJKmh6t9UIhLRB1kCaZ3bATZYzNEJNm19FlRk3gaN5m+6hwk9tdj9EOSee76MBaVrG5o5+5ABQP9YLgO95iCCysRo53nvdPlk88TOshTslF7bKbIwn7tsWGLxvNFz+IimOirG529634XF9/T2TToAwqzZyXQv6dLTEq31ljAt3S4aCJpMQZfWXJrKaxl4Awreca+MufitRXWBzkHB2usuMjQCUfKhtJE8hAo45wsePJQs+oynCSnPnh1Up3290hscbFCYkuUmhAaTGgp8QykJcaGLIaFzfZCdBniW1yWpeoGmLJQaJUxqkudw98LWqgICZ/W28JBNn3VCk2CG8E4wxBL5gx5NFhyfIg0XpPRypCoc0dIhBBCopAOLb6tqWYTfBBsVuGyUqnt24bQtkiIeAzTKmItVJkO/SxKDVxCSmBneU6eF+R5gRgock0CV01DbGs2JxO2ZzOmVUPpFPlClIRASAkEFlBShTu5RP+tDGVu15yaHMhSwLkodiRYlXN47wlEgrieLe2B5JwDjab17OxMOHXqVJozkKUEeXLNQ8A3Ov+gwyr6EMDqBMsYfGpE0ePlmU5FPXBgP2trKyliUgdCFX1GluWMVsZKfTvzxJjhTMGgNFSV4gC7m+acIc+0aakLNLqKRqelNAMii53Vbb1uc9q0EREkNUXXTYsPWsnpKNYC0HZvpVNe3W7VX8TocS6QwNxa9YiS4BVdNsb2sLGuvJVlLpV3U6Y4bYYoaPOT1QwWov5dZtSRsTEs+mGichR5AybXUrpm5DR0SToaSKOdjAYznYLTu6d0nNYFbHIqXV9ylt6RlJiwoEF6PD4kbGq6312TYSOJGi0mnwqFPUUJyUk1/ZwMl6WWzI7rWYQ2tr1y7nGvQTsIrO0qFvQY+G7QYa+8u4xd+s90ZeVdmNcQY8r0oZl7EX22KViypoPFxAV2OAV/anAWDosSAmgGQTGTASNJyYpAazRTZgRptUHTWmHoa/YPCy4shjxhbZVLDq7xiKNHkXZCaCZs33UjMp1jmopYV2Q2MHCBolBlMTA6gEgdg4zoIFhtsAzWUTWqvKN4SiMgASeeIkL0AaGmqsDjaGzOYDBE8pwwHuPzDJ9nzCTgM0NIMD5SsJtFh427gu+gxAQWXQe+jcmG2r6SNxBHbgxDB+MiowmBqvZMKqXJrqYT8ryALMf7GlPkZGWBtDVtMGw34LIxSrkRMSm5MSoyDB4TG2xsaL3n+PQ0g/wiisxSVQ1FGQgDrYA54xgVAwbjARBpZlMaX1HPdvj8TZ8lVjNoa7zJlAI7Ex36mfaUWAhGHYvMZWS5ZZwXFIWyDdnkgume8BgJqfqp/Tg2zYLwAjVaqseNUh5uGWjcn9RtYDKdc/r0FrkzuEFJUZRAouEGupkEdVvT+AYvafJx0kPSOTIGhYsUJRsHDrG6tq5wIYxWJYYjbJaDc4zX1gjbULUek+XkRU5uSmbzGeqYK/7dWKsNtYkm1plMnVj9aIDUV2a0MkKySaZLGKhN8k2jyQ5r8UGo61YbdqMQY8Kqo0mZvgugLwWY3klXynCnust2UMQUqCT9le9ip1FHRYk5+sRLXxkxYEXnhhjTFw8sURuNTY/9AxR6bI3ap0jsIZbdFPEQuyrFosFbH1HyikXryDaaPSiB7mth9xdBgsSYsvnJdu2CI3XvtiI90+Ki30VSo3t6b9eIbWQBhRalX/VR+gSrjyERiiTHuHc3pE849gP9OuKR3UFFMmJdNUYS+UsHaUsLJiXKpHNA+i/Z3bQu0FWpBNM71NYapHs01tINDQxd03uIBJug2FVkiFYyxqXj4LDgIcWQb95/gIv2r/H15+8nD3PwM7bO3Ek9n9JUMwpfkfmW3Fesj0ZK/SyGOoIXQ8gLoo2I8RRZQNCKUOU9NgTIlMzH0BCiI7ZCbCNWKoK1+KzAjIbELNOCdyaYQmnao8uhsASv68YYi8OCRGLjlUHQ2N5RtqDBc4zgFbFjncFadeqDCOMix3ul9Z1VNa33VG3Au4rgMkyCvNusILQVIoKPYJoWbAYm9WsaQ5aqlrFpaJsK0ERtkWtFI6SJ3G2jNNLWWgZlSTYsMQhVNWdSzWjmU+45dg/T7U2q6YS1Qa5Qd6JW0ztdgkb81iksVKsmA/IsS/AvTSs4Y7Bti42hhxd2tP9YhykGeGmUVdIogiacg20650DjrnuOc+zYPdx2221ceeWVrKyskGWO+XwGIbIxWCEKtI1PRV0WytTo8LEEYyMv9CGqYlclkGUO49TYr23so7AWKxBaMJnFFhniIsYJRe4IIcNHz3Q6oyhLslxx78bea7pqlxXpMZzaz9EppP5NXRCS+gciQusDVd0qk0KUVBXQPIiLC6XW50LSAtLnog6czpcQdVqNA3IEbV72QaNndbpTz0NAqwl2UeY2Rhe6Aq4i0XbwL6MPOQYdpGMtJk3V1ORRQHxIx3AEZzFicdH1V+66VJFUHbKKGGIyRBk6SkJokH4xChFrQ1LQbVLgBh06qYasy1phdN6ATedvRTe8SROsjW3xSYHq3tNsQQjaBOiMIdg064OgtL+p8U7PTA1FDEITvfZtpOxPK4EgWqHQaXgLhg9BdPAgGiwv6AdTUCqCD22K8GSRHWvp3yeSsozpcwRSs2E6ird9E7y1ICYjZg5pp7joGQZP4SOFhY1BxqOueAiPuOQIR8qWUirKMGHVn2bQbDK/45hO3JaagWxhS3AFxKzFRI8VD5Ih4pA8TzC5jOjGOkDKZLR2QFsEZtkaTXUS31bU9Rpnqk0m7UxhXGnMeLSaVa+8x9QB7dOfEQYFocipixwRJTuIXqEL1hiIbTJu2twOMQ3EgzYkB8cpy7lncc+tVUOWi2FgHSPnGBc5bQhUVZNgCZ7ZrKKd6yT04WiOywZk2YjxeD9ZMcSUJbnVwLmtKupqQl3taLUtOVKbZ04yne7Q+Mj5F1wENtCGSh0bAY9Hoic2VZp029JWOwp5C57NnS3apqKupxzet87aeMR5B/crw5jTOR+ZVdhUZk2Pbe1JD1JSIWCYt4ZotHKRURCNwxvHF07cw/Ezm3zu1ruUbtgYXvOM552ruv4/Sm6/405OnjjBXXfewZVXXMZoUFDkOW01x0dhPBypbQox1Uo1idHhZ0VSzyCizytVLU2qQNlE7WmcZbw61ko0UA5KiirHOUvT1FhnGAwHuFaHjM5mU8rBUDOGLk96eMHQ0lPPpgCga6zWpJOk80qVyV2VWEGbzud1lZJgKXedEiIiXbFhAQfDqD5V2lrNcupkZdPfhwVVa0qmGKtqJN2rDo7VhQ1dlSBdRWJt6i5OXw0d9GjxMZoBFU04xESUEo1mYrvp4pCawLtnwcJiSwrM1X1IfsWuCsiiD1EWQULszpLknewONEhsY6kqElMdZdc9t0hf2QiIJlNCwGUKLY7B61DHVGGie4ZqHHub1DeFp4pGCKG/513yr2eNQM4KKDTWEiTsCk76QGXRG3LvwKWrQml1LaNJ3f7GdFTlESce286x4ilNZGAaxrnhsocc4eihA1y0fx8XjzMGsaasp6ybUwxnp/B33YEQMeIZzDcpYkBsANPgMp0TEcQzazyTJrBy4DCD0QqnZjWSZZDniDWENlDlcya2oskbpqZip91hLnO8JwWnGXXUSkVdew0OczCjAhqNJneix2SCK1G6XTE04shT0GrFJfY5nyjEY+orzcDYfhCdoInFrhqf5ZaYGR2AWzhNXDSeNmqgWdVTfNIvTTXXieDDFQYr6+TlgLIck1l9rnWYKfS3mWkfEErIs5NbmmqGcRnVbMJ8soV4tU0IaZRDgOCJbUVsG+bbW8r0GjzHN2ti2+Driv3rq6yOhxw5uMGgKHSeCprkz7KMQVFqr6jNegIC39TKyGUsEUswCm1vJcd7S9MKt915itNbW9x17AR1q0xjj7r2hV9UR59zoHHi+HHOnNlUxz4vdF6AQGg9hIgZpqxRTM5dUkV9DbL7l4US1E2jm77LcBtrKMsCG8FIxKWp33mRE6MnRodI4oXGpCBgMeiNbrOaTiXRq5dOTUEX5XWd9qZ/TX+rP4cYab3XiJaEoezKxSJdvYR+x2J6zIjpjxdTaTeVsej+XVCO9RH1rowSCcfbQ0/oLi4FQ5CGf5GyPKqgTDSJ3m2XUiKRYsVU7pVukrmBhG+VrrSWYErd5lrcDRb3U0IKSixWAl0GqcMCSwo0Fuecsmmk6Fi0r0EJsuMu7GpaD9LxnHfBVDKg0WiJWrouCn1Pf52yoPnrAofIQsl2cyc6a6xJw5SpYhe7R/f7pNw7yMGuKCXBgRaNVYt2w122VtJNiSwylERcaCjEs2aF/YOctUHO0QNrPPK8Nb7+wIhDWYULAVMZ7MzjQsRVAWs9xuiwPJPARjGLBG91MnewhKAN8cVggM0Ltudela2DWVVR+8CsbamqQNtGmha2K8esyYECCQZpwVhLINJEsD6Q5YaVUcncC5VvmM4qbFFQjAaMyoH2Z4RdJATdapXuGS321h6WCqPOgjULpgxDYkEzOpgsA9o2Bfxt1IAxBGI9Q7wnOq8ZWGkpy3W67E1sK0Jb4dsKG9IeNZb5bE7TttQ+sLl5GmMto9FMg+SuwiYBGz2xVdpGCQ1WAjZG6mmFbxt8U9EMhoSipLA5g0wd3EFe6AA2q9Td3dV2bGZAypJBFQx1jIoDbiqCGBox3HrsNMc3t7n15Gba67vu2VL2yPHjJ9ja3GQ2m/eUwMYo3Jegei2ESNt61VHJ/vTZ707Ppax46uyjg2V2TafGGrKi6JmHsjwjK7SSEWLokx/a/G36hIh1iaIW2O18wm6b08ku/UPaP/fx6EMMtN6njHjXh7HHz198l2xvZ/1Mp0/p9Bs9050Yk+Alei5R6KF9izCD/kj3PvPuk3p9vusz+sFenf1KyZkOZCCIQrq646UqzG5Yk/ao7LK7yU7ttlWSdEz3d73CpqsMdko8MWOlc4ikRnbpAj3RJBXsggGrvej8ABJlddck3FUG9DIXa0hStWA3XKqrUvQVdXbZmt5GdZWRuOdYfa+MLKxOX23q/3aXD5De2w27C8kmGyPY0CpVamhwtOQmMs4Mh4Y5+0cZDz9/lUsOrXDRgRXOKyKu8TCJuKYik4jzjo5K2FntOY1iaXyrcDycDsvzkTOzloP7HQNXcvdsgmQGWxb4pqVpWmbzltncU7eR+Twymxnq2imdPlYTBmJSRc9TiiPHMCCnqXRo9E5b48qCwUgYr4ywxiGiNPhGhEGeoVOyPc6kOC5EOsDNbkij7Z99ulcGXaNpmKCzliZo31cMPlW2PLGdK60/otB+0WG2JCph8TXR18S2ppsBEgLU8xkhtERJvarBkzuFgIY2oSGI2BjwdUX0DaGeo7gYwVdzQtvi64pRkTNI/TV5rjOkLKTZKmmmCkZ9oxCTj0SaZ2NoovamVEHY8RV1gLkXbjt2mjNbO9x9fJMmzXt7IDnnQOPTn/qUOqLOcd6BQ+xbX9eGmdpjorIG+ag84o3XeQhiFxmjiE3wHH1wIjogPfrQM32EdMJllvcRfDbUpmok0lRzhdXkmfLUW3VuQhRMmkptU7d9N0l3t7PT6QbNvjRIdEjME0xHS5/q1Fsyo1mpqq3UKUiYWCNKWRjEawMhGjErBMISuonVmTIuIfSld120iYoOt0vfCcb5HhPXNU8TTWLUCqkiZMjQCeaKx7VpSjn9VEwbU1nUmDR4TZVXjAFCyqLZXCMfndedNpfCXTBgggYeJrEcmcScotNaBQkeZyWx73Sd1Cb1iGiGH9P1VwgmNZWZpDg9QaFeCFFr5BjQGQXp2vun15XjU1DYitDi0xrSL5v6J6LENEm7C16S8fJd+VvvpxoLVfpGomatgWiM9jd041iTy2GMhbTGjVFa4D6IIKF2jX4n6bhImiETIsbrmVgTyG1DUW+xYiOXrJY86vLzufT8gzz266+g9HOyZobbOQVtjfg5JZHMQkHUyoTLaMs1vHf41jIzc2o8E+853TbstC33THc4/8gGQ7vCp26+DckH2HLEDTfdzqzyNNEya+Y6HM+gezJmGOMU4heCUleKNmQ627K6Yvnmyy/m7hPHuefUcY6dPsFoPObAgYM89NL9DF2Or+YUhcE5rabRBfFp49kumsYgBMWLohBMEY8CElPfFQkKYQ2jfECgJEhk1LRUTcO0qtmeTWgjBLE0O1uUwzGHs6N4owapnm0S2hoXPW2dWkadU3i5U3zp7bNbuOv22zn//CNgIkEaRmWhM3pyR7UzpZnP2d7cghiwIozLgtJljPKcrDVkrWVoBqwOViiKPGUp0740eW/sq6rW+ThGqKLQCtQu5/RkzvHNCTfdfAeTWcWkbpjWniZAlUr3e53RpeyWG274LJmzlIVjY2Mfa2urmvRqlXIa56jalp3pVHVY3xi5SPx0q9JAz3DUtjrwyjpDR0laDkplYYqBPHOM2pEyC6VJ4L5tU3VEK+4+BGKjzeI6NG23U2wShp89lY7dfWedLpEOroRWFtrWU9W1Nh8ntrduqFYKn3YdL9nhLouNJp06HW1csk8WjBhC1yeof9w7Wl2PWlc56H6/JwnWvYzsGqgnaa8vLr5LLpl0XgrXSdS+mOTQLYK+rjldhBREdL9ncTLpXDoClT6U3AWdjtoc119HB9nqUACm7+tQW9UBF7rhpmo7dAp1SDM7umem1YqQnHn6a+uawkNqEo+7PiOmKnuXYJG0Dkk4+26mUz/Arz+3XQHf7tfZ9W9nAdOBjYEmBIWs5QVWAiZ4ZL5NhmfFeFZtyzi3HF4b8U1HD3DxwRWuvOB89g9z9pUWOz1D9FO83cQVSpHsMpilae7D1QM0otSppxrdN9Y6Tk8m7Mw9d29WXLzfMCoy/voLx7D5kGKwyi233cl0Vutci6j+VtvNFemuNKa1YkpC8NTzCeefd4B1M2C/GXHizBlObW2yNZswXhmx/+A+Hrqyj2E5wATLzuYZgvcMD+7XxvOo+yqGRHBEao62bhcNsj4vm55bpzeU2dAxLItEABAZ5JamDdQ+MKka2qqmmk9o6zl5OQBfUaYqQqh1qrf4GlLvZBs9O+jg2bppmU22GY3GWtUIkbZpGQ5LnDVkRphNdmjrChN8otG3hLoBUZhy0wS8FzCOrCgoS4VIZU6v0dcNTfBK9Z+IuKzNqCLMo3BmWrE5rTi1M+eW46eZVA07jWdrMqduPU2IiYXugcOIc6e3zXPW9+3j8OHDjMZDjAizaaU88Jkj1J7ZzpztzR2qptHBa8bsyjunHERypk3Ksm5PtpjNJ2A7FLLZk3UwQFbkDFbG0CZ6PdFp0c4o2xXG9cYclH5rocA7ddN9n87HJG5+K0DHQ51K6mgFo/KBaV3T+kiI6ohGLJIamq10qGtBolfMI5oRIhhMN8DOkio3QYMHEj6wK69GFFJiSMGSXWBzU3bJWANp2rLY5PwqMZYqqmhSM7YhmJgo32Ka1IEqrc6JNxr2WIRoO4WsLE8xDbbr6Nqi1fsYAr1h0nPupkV7PZbZHWgsZlAoVzM411Up9LJsOp9WForfdTNVRI1UxxFW2KR8U/an683onmlNo1k9BQzuykRqQBD9ouqijWCpSS6VCyWGnprU4uh0W9L/RNHZDiJRccoxICGSGdtXYKxNkKroAZ8MlsOGgAuBkWnYVxoOjwwPvegABweOi8dD9g1gjR1Wqh0K58iLMTYf0NQzZtMtmrZSZ9/knJhM2W5aJi5w9/Ez3HVsi615TROFWvSrCZ7N2Q6PHV3KkdF+Pnr35xisFKzuL7lpG2YVBONo4lCheGnolq77nGgDwXho1dhZabnw8CHs2pibZwV3bAnHzgSaMKYKI6Qt+PqNIwxXV8gRbr/t80w2N1kZDSidNhB2zErWOR2alvqAiLpOok3GENfjwW1KInSOYOf6FJnCK8u8ZFDmtCFSNZE2CKGecs8dN+JcibE5jW90DVjBOFW+YrQ6gvdY19FZG6ZnTlC3FZP5NhurawwHA9bGK1RpINowc+SmoLAZ68MxeeZ0ormx7MzmfOYLN3HhRReyvr6ukAgR2hi4+65jGGMZjcYU5UArtEXB6cmEzcmML9z9Bbarlu3Ksz2tiWLADZnbBo8gHX3mLoO7lL0yGBTsW1/j8KEDrK6sYK1lMpmAKKU3MTKfzdnc2qZpWmUFoss9dJ53ciITKYkF5rM5VV0pbt0uiE+MNRo4oIGHZiOVwtnHkEgAMkw2VAuWKml9Fb/LAO5qMt8rZz9rPVVNiIkodKqqa620Q9/XJ7uPkPzVzu20iRaWPkGmGXz6QXKdve5CAM3eupRI6SsxyaTuRiYk45X+2qRm484h1q9gFJ7UXa7pFW06j+Rq37vXwhoN2rtXjOy1632lGejmWqS8D50PYUx3H+Li/IGYWHUkwSaRlN3uAo3EB2vVEPQIA3UdUjYhnUPXp+HDItHW2avuq6v09BWHXfco9vdiUemI9woypEv2SdfQnprIo/S2qHtOfYV+cYqpym9wocE0c6yfc8BUHB7lXLS2woEcVoqM/SsjLlgr2V9a1jIYWsERNdEnhpoMrN43sTlbUZg2nlMnTrE1b9ia13z+tjs0WDBWexkwhHzA5YeEdWf49NRSDnLGruQzOzCrDHUYgMuJFtqoQb6xHSNaYjYTixhPLC3j8QZuZYWsWON4mHL3DKaVY73IcKHEjDYYrK0xKIec2JyyNZmSDVt1aCIc3L9OTqDwjVYT2qhw8pTYNWYB605eSL/Ou1ec1X4iypwicwxCJM8cTYh63bFGqpadkzVTq4Nw63mlazBdn65z0weZEgNVNSf4lno2w7ct9bxiY2OV0WDAvrUxRlqseOpqQrSW6DLWVlYZFAOGwyGFy4lYbrv7GId8YLwyxjmLb5XgZGtzG4uhLAYMyhHOZhgTOTWdszmvuO3YSXaqhq15y8lJRSsQTEZrcmKeQ5ZIkc7BNJ1zoFEOBqyvr3PkyBGKokCicpaPSkfmlN2mqRvm84rWp6mW6RwWmQlVLjbhlo0xVNWcuql1s3XZDnZlTQzYLCM3ICRcvmgkrc12ebIRJik/dcJ7rmSSujJpgfTBhknKYHd2YKHsYgQfAk2bGEoguafJ2PRFV/rsgZYqrUbC0WBStcCm5jyRkAyOXTydLrOTsr+qLDp4yUJJmHQ/o4hyw1vtM1koHqUG1HEXyeikZlPbWdWuwiKdOenwyqrmumY4FYWmdecXpStYJ3XfwatEncjOOkdJgUZK0MW+YiCpMTAdXvV2X8rVzNoCYiVxYcBCVEXfs0hBMuw2rZfYl6RNR/skkjp02aMYpA9A92aLJOh7jbULA8DinsW+qTAFiLFj44qdNU9GSCD1mYhETGzJpGXVNJxX5FyxNuCRB0v2lzmHBiVZbCmsJ4seazOwBY2FqQRON5ZqruVM6+DO7cDpquUMwp2nKu48VXHszA5NFFqjTkGQwHxec9HM4JqM27caVoynHgmnG2HeqnLwOK16iQ6JM9YhZMoPj1cGMhN1RsF4gzgac8+s4vgscGouZFmJlYJZyKjtABmsMl4bs3PzTRzbnrFPYJQ7hpljlFtym/qX0Int+pwDMTkN6mfovjW9Uk+OS1+61j6OLLMUxuAyQ+MFazxVE2h8YD7dxjqlFI2GhK+3arwxyRCjAbwRusm71WSbWTVja3oGFyPSjlkpSkxU8uU8cxQ2p7Q5w2KgWaHM4oOyiOxUU/KVFRrTEUYoDeItx09irWNtPbJvI6ewOVnMON3AyWnLTXefYtoE5kHwoswluXU0JiMmsosODriU+5bRcMD62hqHDx+iKAuQSNM0lInrXkRoEmOiT/CVXTn55OSiupGOAB2apqZt2z5brH/S/av62WUZxaCkqRvUbkQNYNMU3T5A3OU8SzqW6V9nl8F7ALttVL/7oNCpDjK16DrY87+FDRbpG993eeUpgSMLxsJd9lG6y3TpfnX3YJfj2lPMpYoAXVW+d3KTg2hiz0zVf3x3hompiv5wBjrOK6N2ojffpKoKnZ1f2N4OUBpJnxEXzrhJ165zoHa5AZKCRssuXS8pENhlOnbdYNvdQpOa19P9DSkgiOmcDNAN2AspcOjvW+czdKehRk9fi6qXFhDg7n7CnuBESDosBRlxAZvqvZI9wUw6bYnYEMj8nMLPODCInD8ouGSt4GDhGOUZa6MB60XG0GXkqcoUomHmDfMWJrXqt4gQnGFrHtipWm4+Nmez8mxVDZ89NqVqW0KEJkZMljPeP8RNI2ul5455ZISwlhuONYZZa/FisTZXtisTe9rVSAqmrPbbWOdwA0tVjJhlAwiG0w2croUmOFzIWA2OhhzJB4z27aeKljPThqycQ/Q4Imv7LLmzmMzgZd4zmBF1MSpSRPq9aUjwu12btBtzkDvbzxcxxpAHRZdUbaLlr7zuKzEEr5BKV2QgdkHaIFH9MolpbpOnmc9p6pr5bE5mA4QRa6NCA6LM0CZSJoiUZcFgUDIajfBtoG49k2oGRUkVAWuo65p5VXH61CYuy1hdWWONUmeKGOHkvOXUzpzbTmwyqT3TJjBpA9E4TJ58BWtSYjruWsX3L+ccaFzy0Cs4/8BBLrnwQpyBedVSxzkr5RpZnlFNayZ1xfZsRtuCbw3i0WnaafFb78mIDMqC0hhK66irQF0F2kZwWap2uC5g0J8z53AxZ7veVvya99hgcFnGcDjSiZGKl8KQuuCtWzjsKQuxKP1q5t70mzUN2bMKi0Ei0rT4eUs7azXbjbLCmATzck7ZPkSARF+oLCc+BVLQV0diapAWZeII0gUMeQLAWoWZKbl6z7IU44IlKyYGKpccYSKI0ZKeZiqCOufe4iRNVhNDsEG5zJNy04yQ3pPY58MSC1QMvSLtDK7LHF3JOZqYgsasZ+mgBYdXVqHMEE3UKgXpkaQsdYyRzGV0mZz0qeTWJoiXBpBdaSFxTpFh9ToE2pimZYvV4wZtj1e6yIT3tV2Jh94wWmv7qeLS/T4qlR+QeKQVQx+Dvq542rbPNEAEo1lqGxVS5MUTjOCN4NqUebdFgh4EPC0jU7NmZnzjEL7p/DWecOVFzE7cTrV1mtvvbLngIQ9huL7BbLhBHS1VK9x0193cdew4n7/lVk5sbeER8tGYGkMdhXu2phw5ehlHvvmRfP6Df8dkWlGFlGWzkK+t8IXTE441t3Hz1g6jEDkZBZ9rBaauKzwFUSwh+vRcA1ZqnYKMwVhPWTjWxyt4Ezk9mXD7HbfQ1tpHULgBxhaIWG74/K3MmsBlD384d/3J/+TjXziOb2eMs4yVsuCbHnoFq8OCldIwkECOIbNC3Tb42Kbn5zA4bdAzJpEhdAkC12Oic5PTpR6ddZQ5DHNBjCOIsDOvqKqapmmYTCqFhllHVpY6vZuWwXCEcZaqaXQdRDi9vUnTVLTtnJN1S9y3j0suvIiVfWvk1jLd3sHXLbH1NL7GRwveUIdau3uyjE/c9HmatmXWBorhCuVwhSCQ5RmTWUvYV1AyJDY5Z+KILRuZ2TG1VaipjyAeqtCmzHpHj7wrMbGUs+SyS4+yf/8GR46cp8NJmwYwDEcjyjynrWvm8znT6VRnU3ROeJdMgN6bVeiEVmhn0ylVNSNEnUBNMERCP/MopsRElueJJcbTNI0OacwceVGkGVOdM9tN/O6SVeypVC0cUHYFM7vihvTlg6dpWuq6WQwvTckgSefVHURYHK5z5mPq0esy7nsC2WSDtGKTogr1TpPtSCfRe/8GTEetHvthfh3Vefd5MWiAZbuJcYsL7qFqGjx04wa74GYR33XOewd1SvWdPmFk6GDKeiwJsT+uTfihe1OuYxxi03mrZ55OyyzYK1PQIpISiJ1vkvo5lLlIiJJmoXRJQrokXffdrtDi3hUNkR4iLqlCQRdcgDp1HWFJTFBoOmapLtnVBROL4/YN/MnnsAiOQF5ts0/mbGQN/6/z1rlgZcBD1jOKELC0UAusHsDbFbbCCpuiA0nvODXl+Mkdbrljk2OnTlG1Ld4aJM8IGE5uRgbr+xmsXwiXHMJPZ5zZPMOZzTO46LhwfJgbN2vM9j3cfGyL1RVhX3Bs24zKClWjLFP9ngFIUCrSfTASGQ0HHDl0hJmNTGc1Z+64izObO0ynDWtra9RuwHZt+Pztx6mj48IrHs7xueczd53kU7feg5VIbuHkrGZ9PGB9VJIbbYwuhyVNXRGaBkKN4lggL/JFwiDF3RJjnzRwRnuNMzHkA52ns8ZQm8VDZDrXPpSmDdQSiD7Q+kbJk4xJ1euIdS7xhGpCOwRP2zTMZ1NOhYa2XmHf2gr7960xLAsI+4le4ZtlPsCHyPFTp9neniprY4zcfnqCKwqaoFBSnGMyqyjLIftkxHmjglE5ZjgYszO37Dg4Xhsqb7UnJisgDT3tB/75fgDZA8o5BxprK2sMygGI0MaGIA0u4bGNRKrZjJ2dCWe2dlR5GBK8iJ42b2/JScWHoBusV2i7PlToS6EYS1mWRMnQYUX6WpSOJ1jwre8j4CzRey5a4BbHlP7fpHij0u4tokrw3ifO4zZlzGPKVCb6NGKP40vNF4BmORE9ZqeolJ1ocRadQtVr04NoUBHZPXOjy9j32YjdlRfTlXz1R7GS2pl10Fc/WTY51b3SFsGL/l7vjFIIdlhgLduKlkRNooNDlBo3wUwkwaxM1MJKTEYxBhKrCffxLPc2bevjM31DkqCUiMbEVPWSNJF3AR0Ro8OhYnp2XUCm5FApqyUdi4fSCSOiVQ5jMFZ7Q0VIRqIztiZR1kpfkRFSoLcrM6SKv1uPgjcdga4nGqeMWsFiEoTNhobDGVw4KHjUhRucN87YOXOalgw/3qBYW6Pad5hj+ZCPf+4uNidztiYVx86cYns65fTWjM2ZR5xjbVAyWlsndw4/uZ2dWU1++jQPuewSTp3Z4vO33oGJwmg45PJLH0LV1Bw/eQqbZfrlLKtrq8znNbP6DCKeiMFLRFJ1o69eIQxzwyAfsrE+BqLO0KlrhTs5l2I4nSK6vb3NzmSCK3JcPsDkI6o6EL02Nn/yC3exOsjYGBccWilYKTM2RqUyRpkCiY0awthB7iTBqvS5SccSl9ZsAthhnc6ndymhEMQQipzCWnxRkLtcHfgQqdpan6OBJnqwDo8hsxnWOgajIdZBFJ3BsbW5zedu+Bzr4yGDokgY2IzMZkyqKp2XIfSDrQbEQUnIPKcmpziwvsq+QxeSFQOd0ZGXhHKV2uZARshaJGsSq0fXH7XoHegakO+dkVzK2bK6usJwOMBZRwytOmEmOYoibG5usrO9zXQ66RtxO23cZcIBunkvNiWVovcE371/kfiynV3p0uwYbJaTpaFh1iVYrlnoPN+2KcjQmSp2dx+Efnrv5C6ao3fp/H4dRHzQHo2mbRPXvu5hZOFkmjQ/io5VqoPiQnptEdj0BZvU9d13rKS9GGPAyKLC0GXwd5nL/rP7S+lLBt3pa3JMix/CbqhV7J+BOlzd3uqOsSfQEHTiuOmCMOlhQ91j7f5KYgebMkjsQc6qW2AxkCwuYFMiHdtVCnikuxvp/0Yr80peYRYBnqR7LbtRBt15LQKE3YGFwL2obbuooruJfeyjdi79fdxFiatv0u8XYeWuIKZnvzI6fA9PHoURLQdLw5FBwUVrA/aXjoGJilYxjtYUVGbEtM25/bYzbE7mbE5m3HnyDFuTCSc3t6laAVcwWh3rvJnMUW+fAHKMZORlTuEhd1My4yjzggsPn8esmjOdzYhVRSxLYvSsr40oqwa2tvFeES7Gul43dm53t1EzW7C+vkI93aHyLds7E3zwuCyjLEvyTAdJb25usba2RjYcYcoBweVs7szJnaXMMm45tsmocKyUlvMPrDMeFIiNWBzWFWTOaH9mx1iZfASbktvGLAbZSYIIG5sIAtBeU2ctIZEXNZnD+8jcOVqvM0XqsKBFjsYQrSWIpNlRylyYZ45BWVLXFVub29x+251MtrYZDgqKzKZeI0uWtQQv1E0gL4YMhzmjcsikqphWLTtVzcahgxw4dJiNYqB6Ky9pyxFTU+DJqbMBIa/xVocABrPYW51uscgiYXAOcs6BxupolSIviBJofK2BRm6xVjfubDpje2eHre2d3glZDOtaZF12izEKgdndEJX+kq7M2OViMKJl8cRW5PtR6onxAaGpG30wmSMr8wQ/smkTLkRip+hQJz8p+L55HcXctt5roCExBRsQCDrdnNBTBYIoflYi1hbECMFHjMm0ehLVQe3zSqYDkqnBir2TZXuu8o7t5N5ORghBe0OM0SxMgqAFk7ImZlFGzkyWpobSM3JJuobOmen6cyOyMLQx4mzSmxhI0KTeChqj6KCkXBUuZnexOiWcrEnsQX1Elh7xLriUy7TnBcBhU7ChmYGuCT0mDDGYPtCI/X0T2qAKXbd3hzcOffOdQ+FB1tpEwdutsjSRPJrUrJfc7D3ZppQV64K9/j7rhFqdjK5OuxEwIaZND4PYcn5puWw84JEXHESaGdubp5C1fTBaw6xfxPZghZ0m8lc33sLxE2c4tbnNtJ7otRnDzAtZ4YgyYDQ+QDkoMfecYjqvCSdP8ohHfAO2LLjxttsJMZAVGZdddjmfvuEznDx1RgdfpqFhK8MRxkwwZ07pOYshRK9OCgaXAmqRQFaUDHPDxtqY01sTqrqibhsyp6XmDn7iMsfk/8/en/1akmXpndhvDzad+c4+x5AROWcyWVlFFslSsdTdgNASBEj9plc+6UX6E/RHCBAgqAEBgiA0BTb4ID0IkARJTYpDFVlFsnKIzMiI8IhwD5/ueGYb9qCHvbfZ8ShWVQjgW6UFPPz6vefasM1sDd/61rc2G7a7bUjw8xKdj+h8oBw2znH1xSsmheJ0OsI8OOZoWqLzgklZkGsRm9Ei1SzFRy5KXQo59HD48GRJD0qAiz1RyodgwkEYKqgzAPI8o2vDtOhutcc7ixSCrmtwSFxWoPIgcJFXBUJ4uq6hrms29YZPb1fMxyNGVcnx8TGT8YSqHNHUbUh0lUCP5yhZkhVjhM6R1rF5s+KomlOePmAyPUKq0GjfdaEXSAiFVx2oNrw38VnuG+f7Hi16tNm5wQb8dnt7m4zHlEWBlIKmCe99sm/OOe5ub1mtlmzjJO9Dp0m0sSG4j1YhgjgBfAhUK8VBUCFkIvb0DdhK6wByadXHickOeg9t14V9x2ZTpO+D5QTKpIAyBcrB8tInIMTA0ZpQPek6MwhfeD/0aPiEn4vD3ffgWkLsU56U/Mvb/YzhM84DNoBqSWqXfl+xKuB9D9oFECaqMn2tchGCfDnsqz/28Gw7F6vmMdHo/XZKNCBU7oXojx8Catcfq/8tF3OqAypyAJ6ib5IC5UWQW/ciJiwMszniXU6eIgCEYWDiwIwIvAB7IC3so1/qE4x431xMDnpf2vuYcN49MBYfhkhs658h91ckGsL3GVb4njvwXx7S0McMKIRjLC2nleLBRHNvWjKWggKPznOszNj7nK3P2ewln3xxybPX17y4vOXVckttDHVnyKucalRwuliQT08pigzzcoPwQRa/Kgvy3FJkOblSjPKch+dnPP/qKzZNDV2LNx3eWebTMYWWNNsVddfGOCfELyFeU33CrDJJrmEyrmh3azrTsdvvECJMMc8zTaZDD+9quWaz3SLzHFGUkOVsWkNZlHiR8fxqRSYcpXJkRYVF4zGMC0WuwzR0b4beDOc8xlh0FkCD1NOVnsYhAR3q0EpKvAqgXKFDdUMLSdO11K3HOxtoaNbG2EIGVo5yCK2RWUGuNb4o2G82tHVDU9esliOqomA8KsIa5xlKFVgLxsC9h8eMJjNGx6fsX76irpesGsdRPmF28YjF6RkOSd0a9nVH58Gg6VSO0yVO5jgBLg2siNmTEANYTm/r/urtGycai1lJphTCObbbfVBo0jm2E3T7PZ9+/GueP/+cy9tXtG2Dd55MZtTWxHKifgv1kFJFKk0MHJ3FIUmzcpJhsLjhStSQ5UstI7KkwjRO5+isxVkXZM+yvOddiv4xGEyajA+ucKEUZ72NWujhAbHW9bzekFh5vAjDB6UXYFXft+GM7yscztYIoYNuekI2+qMHMpCLiZcQA1IBEqXCuigV0CnTtdFpJazC98iQECI0tSaDLhJCI2N1RCBRpOawYLTDXmxyCwIEg256OkMpIMy49GFwCwNaEj7bhqTAh/kV6RyFkv0wGuUFWkgmuiAXGZpAZQvdXKkZUiCdxPoOCI2b6VgSibehkdvG61be09mwi6CAFT8tWhKS50z4vvPh2QjJbOjuSWQxiIlDRMG8jeZchIFyCVZKoooiNuUlCT8fRaa8M/FequDMvEf6lnHdMZWOb89HfO8o5/15Tu4ddjQhnx/RHV3wetfxL3/xKZ/d7rndGfadpDOSTs2Q1TRI5XUdWQ5GwOXdhtF4zcw5Tk5OuL1b8urVFePiM4SU/ODbH/Di+XMmZc7pxYz8qcS4jn1tcDQ4v2cxXTCqKqbjMbf7fRiimSgRKJSzKC3JspKLoyPmkynjouST6y95c3uLVwoDOOvJpEMVOZOjI3Yv17S7HfvrJblzjHONEipqygvyyQyL47p2XDDBN4pXn7zh3tkxs0nFOCvQwqNVrFO5IJyQS40SoHyk/sVgzEmPVx4bk14hZOA0A1Um+mAqVxJbZFirmU/yMJOjNez2NU1n2O5r6CxWN9S6xitJOR2zMzWuBWcMl5sV9u6GT198RV6U5HmJFBlFVTKezfnJe9/n4tET3vveD/jy+XOubm74sJyji4p17aiOKoI2uw1qby4IJDiV4fMSJzVOdKGfJBo3Z0yfdKRBblKmMda/3b6+TcejoOTSGXbbLc4YFD72ETZ8/vQzXnz1FTfX1xgThT9SDOxiEBgDdZyP6jMqAj3BfigdgkAlZbT70UbEwE9IGQb9SdHPSQAfZcWjD/IhSbDGhr6Hw3uagv0YzPZJQpKvjb1EgYofKhpN0wSKp3P0Yc1h8O6JlcpU/U36nXKomryVYEXgJUXM0DtMIYIAi4h+xJiExA/WEiH6gN+mNUlwb9xXQItFX0E4rFYkSm26/reqIvGz4XJiouFjwvA1/5Ti+H7/MfVIAZJGoIVinJfRxkiEPQDpIngnZWgMF3jSnPSvy81bEYC0znqciepSh/7CD89J6qUIvYbx/rhBBGdIgBmqHvGzfYLhk9wtw0Ue7I+DdQjGMt5AY8IkbdEyUpZ3j8Z8eFrx/lHFg9NpkCf3sHQ517uOX7y85svbl9xsO17d7NhbQeslfnoWKFjW0pgGY8Eu92QLy0QVZOMJ2+2Oq7sljy4uKLXk8cUppW8YjSvunSx4+ewL6vWKUmsknq5tqBZzpMsY5QpXe0yKPyToyNxI82zefecBVVnSrFfcXV+zWq1RUvVy4s1+S5UJqnJM00na1nBzc0NRZMwWc9pnL8mVRhQj1vsW6T17K1nbDLP3PH/1igfnxyymJTvbkIlAsxoVRVDLtIDUsScy9HH076oMz6eM83hSv4Xz4dnJ44T1QpVYm2FNSR2l23dNS911tNaya7swUNgGepJCMMoz6rKkaVqauma32ZJoc2VRUhQFeTlBZwV5OebhB1OO7j3i3e98n+OHd9wuV3zyxZeMpjP2jUesG1SekxUV0uugbIXASQ06B6Uiq8USNXsCbh8fM+sSSDAABX/Z9o0TDa00UoTqQdt2eGBUVkgEprPcXF+z2257rd+QyUclIs9Qso6WJRhU1b9gxqYp1UOIN5TKUpIg4tcC+jkQCXEQZCoLNAvvew4qHLx86Z/pGD5M4u1t4WHNOhkHP7zoPiIhwSAdJEA+OYeElBPf/xRQD7KAw1kM16hEUIJSIpTVw8c8tvP9Md5GnaJBTdllSp3FYHgQPsxE6LvYEpIV1sbhCfK5Q5lPxGsNI2yiARMBZQ6U22AUZSx7uwP0LaxRgJCsF726SBj7J9HIA5WRYeno1atAuXjuPjmOpPARp4s7jzdpbkVCdVyPDqXfTSXqlE0l2eRwONfvN6FCNjZt9c9cQpn62yX6vwWib7pLrfTCi3hoh3WGTBrGueTB8YSH52MeHo84mo6ohaQDrlvP1arm5c2GN3d7lo1DyCqaVg3CY6XAKoH3FoGl6zo2XYvqMhpjQtnVWFbrDZPphLPTE67fvI7DxlzPGfc+IDD7uqWua6wxAXEJLyVpKm+4B65PmE5PT8iU5s3lJbv9LgRoShPStagWJgVFWVIWBcJ7Ll9fMqpKzs9O+epyPSTUKgw1y5Wimh2jcFy/fMniTDPWJW9ur8mEJ1eC05NjJB7btcHQ4TGm6xt007tLRKP7py8GAAHBjM8NYVq9UwItMoxSoZkcaLVBiQCCOMC4Fu8lzopQMUHEBD8Of+yC67M+VB07Wmo2XN7ekU8W3N+3HB+dMJ8tuLhoWK63rDY7llfXZFlOVY1AxkAuRHdIoVAqzASKL/fw3PVgcDLk3wA2+hu6ZVmoYDlrMZ0B58ijVn7Xttze3rLb7kJ1uk8C4CBKHux5vDdpzpD3Az98UC0cavODT0kI30Cx8tFuSOnROuuPl4RQDu/oX7y7gy/qn/eDD6YEabgU/x87qyEqSO9K79tcTED8wXuVjtWbzlBVjJXlsM4+2kxz4B+HixgSGB8basXbV+cCPeowwSD5EXFge4WPdJnhcgQB5POCqPDohmQqBdpv3dO371eixQWFqTCwVQOarxGsfbApwom3EsZkV4Z7EZORw6QgPV8HCcPbNCo/JBH9fUv+PF5P/7V/K2nsr61fE9Ff22GSwcEx07+FdwjTUmSWiZY8Ol/w+GzCw6MRs2kRZvoYWK4Nr7uGzzc1L9Z7VjvDykVgRGWhjyD6UxnjDNPV1PUOraETofG77hqMM+QyzFzLygKV5zgpqa1j2xo6qfDW4yLwY5wHqXHIOABX4PtG9BgnSDhdLBBC8Ob6hs1mx75ukJHOG+SFw5DN0WSMNzUeuLl8w6gquTg/ZTQq8UDdNDghyYuC6XhENp6Bdyz3HacoOpmzur0KwwszQVmWCK3QXiJViF2t6YKQWx+TRieUbtVhT1BMjCEMcA1jiAVKaIyTZEqQd4rW2AhohJ4f14V427mQ1ChBkLIlJMLOWRpp8ELR+hrVOlTrubpdko3nnO1b5osTZkenyGJE3XU0neHu9o6iLJkd6cBpkJLO2BCLSYGWgZJlxUGS3z/+8bn9hm7p/69Ew/swbblpGrRSjPIC3Rn2xvDm1Rt2622YuOiSbrTAZwGVM43BSaBXigiOFmSv8JRHm+RSIhIuL7zkAlLj8iBnGwxCMFSCMssHStBgC9566fqSekSzhZcIEYNGOQQW/RYX17mA5KKDsbFJQepAk52+gVNEJCqGy8LFORhRsSglHvhoyEM2rpUK10BwfG2dDFFCbyLqlAyJc6H64eKNF7FPI5WfB2vX9+4JIfA6omveI/Ug2+jjonr8oKgUJ7eLKOsqEGQ6w5pQtlfExnNBkDT2sWghFEoFjyDDsg0vW5yz4aMTVfEcpSAkN87jMQd9ibFJylp8F6gRVjiI/Rjh0RhK0+ADEiXjfBRrekfWy+LCoDplLQIV54LQr/dgzOO5x5Q2IVOKdOmempDEGLtHl5LJWPPe42Pef3jM+2dz5sdn3NYt2+WGl7/6imcvb7i8XLOpDa0VASmXIfkOM0wkItPU3S6UzDvDXdviG0WzG9Q87tYbqsmEexcXfP7ZJ4CjbVratqXrWrzQgQLoapZ3a4QIiGJaZ6lUHPYTg4MoR/jw4UN22y1/9u//A3WUKHY2oDRCQOMMXkmqqmI2maKE4OlnT1ks5nyrKPj5x19gYu+VFBl5UTGdzTg6f0TX7Hi9/nPeyUrEaMLTX7xCeUeVKS4ePkIridvtwjPnQ8OcRvTBfxj06Hv7kJx/yDkDEVwQZZwTiqAV1ktyIRnnOdZ5Jp1j1zTsm5ZN02CNpe0smQsVtQ6JFYHm4kSiRwq8UOxaw257x+jTz9nWlvnijL/1t3/Cg0cPAcVHv/o1P//lR3zx9DPG4ylP3n0Xr0ODoHVRhEBKcp3RSkXjkyAEMcZM72Qa5vXb7S/b8izrqUTWGCSQa42zlnq/5+ryks1mjem6nn4yAEj00pkJFEvoPj5gF0EZT5JmXaTQevCxYvjZAciVQn8voMyHORlpKODb+4gR+gEYlaomHPiu9NEEfqWjhK/dYLticpH6AMXh70OPpHsP/UQ++XZCI2KiIaVCaU2Z5wFZ9w7TtUHZ9SDo7oP13jlHTy6TlfQ9MuoOjiXCosRPDOBdoqX1mFH6tBTgBnquF0NDebihQ4KRAP1ezdCDjv9Q3qOcR4uQdKRfTycpDtZS9M2Bvqf+IgRehYo31uNjn9+gBOV7CtVfHLwXz+8gWbRfm/Z92Nc6JEL+4GveivSS/z5MUBK4J6xBtlvGueakqvjeuw/58HzO46MRpfTsOsu+trxe3fB5Y/nVZs9yV9O0DlFUZHmJzvIAMtsO4Vq0tuAtruuoN7fgamrn2HtL7QwtlkJ6RK6RVQFFQY1g1Rlumy6wXFqLMFtmR01Yb5XRCUXrHdKLCMQoumaP9x4t4Pz0mHrf8IuPPububkXTGSazKbZrscagtUTnOfOjI8LYAcnzz59yNJ1SvPuEX3z0a+5WO1brFUUxZjw74sGjh0yOj2j3O5Z7S6cqbDbmy9e3VMoxLTXHJycUWUaeFdEfBgAwI/ZIxKdciOG+DYl4uhdDbBsqNp5chRZ9JwoaY2mtpWpaWmNpO8dysw0+3FhwYQ1IQApgbEhyjIeubnG+w/qaz758zs4IZmeP+fHf/tvcu/+AR+9+i6dPn/LJZ5/x5sULRuMJVVGSlWVQ+nIGJcLgxUxLjAqJxltYQbRMScTnm2Bg3zzR0JrNbsPd6g7rHHmWkSmN2e7YbbYsb27Zbra0bXsQpBG5xQKtdQgwIXLbJE5IkIGC1BkXVBu8jAyp8J9k0Or1sXLQ65nH//fc0fTzPsCOv4h/28iGqHFIZmIAr4RGE4Lcuq5p6pqmbuI5h2voIuqiYoLkcYiY5XsXxtRLIUGovpYQONcWj8W6lpACyygn60BIMqXJpWKUFTgsxnWDwQrcsiBHqnwY/CTEgITGJATPQbdzvM74wGulgtOI/D/no2phLLta7yKyLfpjBVAvGM/OBVTE42ldi4wMVhEzeOfAi9SEGINBYcF1CB+H4RCMcUiE6JGyJLFrO3NQlrYIL4i99QjvyZxHe4GJFADvwVuLdV1vYNNgERGzQ0+KSz19ozzx3ntiA5WMgaoLSiWR8+pS0zoC4fXg852KjisZDk+uHEo6Ku04yuF8JPng0X3WmxX/6s1nfHb3c2qR0ekRG+MQ0zm//wd/ly9evODmbsmbyw3WS6yTtM5hPGFCibeBOiQFZt9QIyh1hVWOVnZcL9fx85Ys10zGFV5AXhaU4zH7dRcQPCR3yw0Xp8f85Kc/4t9/9BFXt7fUTYu3Hc5bcqGYTCbM5gs+/fJLtpsd+84jZRn6MtxQafJIOutYN3s6Z2lXNT/7D3/O3/2D3+f0+B5HuSMzLbW1mNYzOZnznQ/f5xe/+AXbzZosL9lvG1Z6w6g64v7FOQ/vX6BGGbvdhqu7DUezMbnWyGKGdYFiKL1FCYWUtr8/Ic+OIIHwkZGSeq8itUSGJEFIECYY/UJ78JJMaBSGVjpq4dnt65AkmeA0rBIInaqzFmc7ZpMZT07Peee973F68ZCjk4d0jWR5uWU0mXDv7CHjn8548ugF3nl0pnn56jX7XU3bGcpxRaVAiQ7hO5yrEboCEd6lw+rnb5vB/+pNSc2+q1mulyBFmNhdFZj9nn3TsLq7i8NeLbZrgoS+V3EuUvIHUVxAa2SWBVqw1AFRdCZUUWWq7Ibjpj4BL8Qw50Ek1SQIYFr8Oo0gZgga/WFAyFBFSElI34cQpSQloeekbXe0TUfTdr2qkJSilycPQFU8bp8AxB4yIRFC9UpIh9mBNaYPGkTIBiJlKtAQJ2URRFKsoT4IaF30ASKxA0Sy64AbKiZhqnfseTuQnlVRjUtEqmD6ryf7xmBNQJ8Mpp6UYKcHkXbvg4hIEoJJyWRal6AWFSq3mXdkzpBhSYP67MGxSA3wxOp9vOYAMEVVRh/ijRyofWAFSxGUJcVBhT4glW9X4NP9d/F60oDDhB73gi3p8xEYO+xJERB7IBmOFbLneOYpkVOYqmQ88pyMFfcXE27uVnz14jWvVi0tGY0q2Tjw2Yy/8+Mf8vzlFXerLZv1htXqhuX1nqycIpQGnbHvwl3SWrJvwrDVUTHBCo3xkjev37AuCjazCcILqjwn1xmjomRSVGz2HU4qHIr1puNoPuU7337Ey2dfsl4tWa2WeN/hraFUgtl8xvHJCb/5/Dm73Z7VZg8yIy9ypMxDgC/AC4VxsG+Dmt9qs+ejj275ye/8DmeLGQ+OF7i6oV7VzOZzjiYjjhdznn72GfvtGqTHmBrTZpTjBU8eXPDewweIds9+v+Xm7oZ8PArz3Y5mmN2OrmsZxeRBeYcXkWatiJLx4eEIjdTgvCQNGAYVowhHaHSHcS7Jlccoh/KSppPUrWW3M1gs0ju8MEgZhsh6LN4KsqyimixYnN7jvQ+/x+n5A47O7tM0jrvbFUeLBe8+fMJiPOW9R4/o4vu83m1oupbdfovUGXhHlsO+trSmDvdcpKGj4W2SzmO6FtMNoyT+su0bJxrCB35p3TQhwEwDjGIWLfty6ICyJNxxcJHhtZUH6ipdZ2jbINeXkpKDfJ30tjg/fF/4g4YvkmEOWd3QjRFuWrDDPUwY9+eHHRMRB1xPofJA15n+JiTVJh+5Gb7/3bBvmRyWo0cYwtq4/jAxBwSGYXbh50GaNekvZ0rSub5o3OdKb5f7o2OMiItPHTqHaxKNW7+i/nBtD+hG/nBNDlNTHxI7H9bH+TgvA4/1FiE0oAZjGV1DuE4ZzsmLkFz6wbHi03oTUmKh+mPxtSdF4vsZID4a+J6P6+JyHtxfkeyrj69tuv6DknVqWPeeHp3vkauEbCZn1z+P6TlnaMI7OK6HSLcJQ41KKaiUYJIVvKwNry+X/PLVDa0sceUUrxRZkTPLC8ajHMQELTJu1zuWmzqea6j4SFwgVAmB7Qyd6jg6mtO1HULu6ZyjblqWqxXHs4rpdEJe5CgdKDm9fKaHpm1p2w48lEXBqCxpo0QmziGkYjwac3HvgldvXrFebcN7F69V+EFUQQhBZ0xosDUG27as1hvubm/w3jIuFF0DBsNoPGU6rqiKnPV6xWa9YlzqoGS1r1FZzngyZXF8ytXNazabPdvGIHctZZ4xKUua/R7btIwLhdCBtzu8V+n5Hd6yRGsLimnR0Uf400WEURDQTBQUSiJ8wKRsJ1E+No3GgMJIiZOBG660ZjwacXZyymJ+wmS8QKqCurasRI3xEussSmUcLY7o2pambajyHOk9Js8QWtDZDikcQlikcBHBPXgH/bDWv93+8s15jzGGfV2T51lUflKBdpECthT4RTR5SJmjZxA+9qeJPsC11tMaS9N2jKJ97J83BqCLGMweJgnpJ+Lg/4jBd/TiEgd7SrZefO0R6IUQkv21Jqoimr5C05soP7i3kHgkj/i1Z+gwcU3BeyIr9VSkSJWNNIpMqVgBHiq+qVcifT7huklWPqH34uvHFUPiNZx0+l68Tz2AOPja5MISRfJQsCPtK+BQ/iCZC/c7iEP6YZ19qK4LQuLTA3OpCtTfo0QtPfBLB/c3an4NgivQN5YPbv/g2TusqvX+hqGhPd2vr7/2PZjm+/UXMfs6VM0a/BNvxTQIT6EEIy0Z5Zr1Tcub6yW/ebWlFjmdHmEzjS4ypsejQPcUkirXYE2oKtjYD0noVUKE7NtahzWW0aygy3JqpQJI6z1ZkTOdjCirEWVZofveJBEvR7Df14yqCq0zyrLAtAXbdRBRsN6TV2OmkwknJye8evmK9XpDYwKrRB7IgCdGSdt2bDYburbDtg2r7ZLVchWBAE+mBFWumY5GjKuSMs/ZbrZsNxtKHdoDmrZF6oy8HFONZ9xuNqx3DattwygvyRVgPO2+w9U1ZaHQMtCOrPd4efCOiPAsxsgoPlep5hllqV16NgJdXAWuH0UWh+p6hdWGQCQO72HwWWE6lRNBgncyHnF6cszR4ojpdIrSGXXbIdY7sqyk6yxSahazI9quZVdvqdsa5xWTUYX1nqZzZCoN3jTgZQwxHcTeVyLt/ptgYN840eialq5paeqOyXiMzoqg2Z9rqqrk9OSYy+vr0B3vPZZQ1vGixHuBMYZChjJsrrIwJEU4lss1tzcrbm/WzOZTRJYFpCK8F8Fg+KBMJIXtX/Q0DM+j3zLoCe0IpeyYQPihbN0ruMRF87SYrgsPggpzGqxz1HVD3da0psYbizXQIvE+NISnoS0JvUmSgdaEN15K16seSQlIj5AeVEBiwsnHSNlLskyR5xmZVtimwxsfGnGiBUkyv87aaG8l2iu8b/E+OJxQ6UgPpYjBVYzHncMSqC9BCTHQ25QIM0CkV8EQ4mOTYgzkDHjvsNYgs/BZ7x2JN2Si/KPHg46VBqIaGB4pLN55jPVhwi4eKVwMnwUYg4vnnEVxgDAJO5YWGbxU5oN5E97QmSExQKv+3pKeG2/xJnCyhZIkeoEIg6lxXoQGTxGGhMrkeERAr6wPamgSGTjAkZbjXRdMhPAkBUkQZF1wTI6GwpWMnaBoBPubmtcvV3x+uWflazZyw37fAI4qt3z3Ox9w/8EF/+DvvMsf/9nP+LOf/SroaHuPsHGeiA9oYL3fIlzH+be/hRCw3e/IbOCNGus4OT3h3vkZZ8fnZFlOZ5PzdAjr2HcNr9684Y//7YbZ0RHz2ZTl6jbSqMDiOLk45ye/91P+23/833JzswSp2dsO7zsKmcdgwiGR1KsdL78MDejOdGy2G/67/+6fURYZJ/Mppm1o9zt+8qPvkRcVzXaN8AYlgsrcdr9Gyo5Kgy40WaH52c8+oukM1WTKm+UNZZHx4bvv8OzFF6yur/j+uw+YFjl5rgIyKeK9kD5SB2Vv+VRMN7wQdLGZVngwtou9OoGWJL2n1AqtIMsEpdK0nWW7ranbjg6P1wovNaic6XzO6dk5T568y+zonLyastsZ2m6DXO7x/pKuazC24975GcbAerXjyZMnjKqSPJd8+vRTvnrxgkxaMuXRKtAxQ69JGhonsSK8+0J+Per47Za2pm3Z7WvW6w2LxQyIjaNFzmg04vjoiNevLkOwFTSMwyMiZUxAAg1S48mwYDts27LfNyzXNa9vt4ynC0IryGEA+DXEPAZ+PopxDPLqQ0ryFj1oiL7jXwONxkGkIAcZi0SdddbSNjV1vWdf7yMYJrAyUhp6YCCd6tv9IoEWbHs58wMxxHgesd/QD5QPLWVQctQq9H3h+yG2MeKA3q8G3yeQ0V66/txTc31A2OmDcmtN3zieQq9QrYjN64j+9/uE6SCo7pvISWse0gDnIjXJxXggBkeB+ZDoUAe9fumeSDEEfpEaraVCyvBuqhD/JQYX3odBojICc9aYCBqkgP8g6Ujn69zwNxHLjM21HkKSlX43Phv0u3CxSZ0DZa63n6GvJ77CO2TbMBYl00wzkopu33JzteTjT16x7AQrl9NKgSo089MJTx4/5PTsgvtnxzx/9oyvnj3n08+/oqlbWl+jyxFKq0BTdB3OOu6dnaIFdG1NfbsPwghCcHRywtnFBSfnZ3gh2O12CJmHZ7KzXF3dYNqWcZmH9zHL8MBmt6NpOt47u+Di3n0++ODbfPrJ59zdrelai86Col/TRFYDEtNZ7m6X2LZhNspxpuX26pqf/fkvqEYjrq+uyZTm3sUF9x/eZzpbkOc5nTE0bRC6Wa63MYFXrNuW18sln33xZRAHsh1n0xm6sby+fsX+8hJ2O2aPH1CUGUWpaawB4UNlKw9xU2d9APS8D724Eeh0scrlbFC+DPHHUO3MoqKdUholNF1n2NcNSkqMdbTWY3zwyrP5lNPTYx49vMfJ8YxyFJvH2yWw4tmL1zRtQ9d2PHz0gDwvmZYVMs+REk5Oj/jqxVe8uXzDuNDslUf7LgjmuKCsitJ4oSCKR3yDPOObJxrOGZw3IByjcUlVlTgUWheU1YQHD5/w/NU1Ur3GRDlUISTCBWlAnWcU1lDgmChB7hyi6Vgtb3lzXfL5VzOOzqeoTFIWxV84exGtUzDmKShOqGYUnztEgvywBKnRLxkrpWTQH4rpfgDdfT+0xzto6zDJsW0sxoaARSkd1CV8UikJqY4xoWyYmHfEYDWhCTIFPxa8j3MWlMCI0KeipUYQJ3jbYEScsThjwnXJOC+EoOYhrQ2ZpogzI/AI5SEGx7ioqaw0SdOiR2A8UWIzzLBI6If0hj6mTxUHTxy8FIlPNhpdIVEuzimRri/pShfNmvNkMkxvzn2QzctE4CMGIyjx5L1DsXFwYJQGiPtwaTUD0ug9CMlYapDQ0uJkkB3ufGzyjHrXifoko/PqrIkONZUnQ6KWgk3rQl8CUmBN+Le1Nq5DwMQTJU+IRDnwEUcIjiskwwrvM2RWIIuMxncYYfHC07Q7aq9pM0mnSgRgcHz+5Wvu7tYsyjHvPLzg/OyEjz/7kqvbFa+ubuiRVxmfaSE4OT6mbRrubpds9g1N23F713Fzs6EsJrQGrBPgJXmWBVEAZ0GE2RGbxvBosSDLNFe3l6zdGtsYxtMJm/2Wj3/zG5omUgYjR9t5H7iaMSGTDna7PU294fTbH+Cd5ebqinbXsN63LNc1+yYMzOtEx2a94/LVNevNBm8dVVXSWcdmv+f18pL1ruaLF6+xoqIYZxSTKcfzEc52fPTpJ5i7W3JrOdcFM60ZKcHdbofBYbTE6jD4sfUNtrN468mlhoj02Oh9vXN9T4e1JsoeK7x3ockPhekapLGMtKRURaB2Ap0XdF4i3J7t8g3PPhXMzxrKyRGz/X3K0ZgsL9B6xPXNDdd3N+ybhjwPQho//8Wv0FLw+PF9Ls7v8c477/DDH/6A5y+e8/Tzz/nVb75gW7d0xiNEHoOIqFryW3nbv3zzoLViVJWMxiOKogDCIM6yLHn06BGvX1/y1avXQarcpWptsDFKCHIshRAcVTnTXFEKz931FbrQ5NOK8+MFeaaQue7zgwhr9FXRZO/TNgTF/uDz4auhOTj+RAjoZVMJ1ReG/pwQ/wb0vK7rMBjQmrf2SQTZvI88fg9O2PDbvXM8xFQZAvCU+wjRD8RLgX0YQCvwNoBn1tihWqwO+lF8qK57Fwa3ep+EN2IA3TfBRJpXYkQcrFG6/r764wl0q4jquIPUTb1FmRaxpyRJQx/22R0skRtEPJQALUDLkCSEMBWcGCY1J4XGOIov/OmFYAQSjZaCXCjKTGOFo3ZmWA/vD9SmDpkE6f4PCd3wB9L8i7TOMUsMcsZxajgEwExEtDz1fyTAcKhmhWvIBGSAco6urjFtG2IMDwiN0kVQrRSC1a7j6RdfcX19y3hUsFgsmE7GlOWIq9sVL9/chIZvI1E+A2/xSjKdjNnttpRlgdIa62G733O33lCOxtRti84yqqpiVxu0kmiVszGBCnh3t+TsZE5ZFnSmpTGWzq4BwXq95tmXz6ibNlC/dUaYpRZU2JQKA43B03Ud67Xh/vk7eNNxd3XFq1eXYVJ32zAaTYJyVV3TNJdcXl6xvLvDdA2z0ZS6Cf0e6/WSfb0PFZTOooqSWXWEzCqMs2zXO0RrKICF1kyUpARwltpZ2tbiqfBK0fkMb4Ocb9O1cejx2/YhJLfDc9uPHPAigiEhfvGZItOxAV4EGrNxoGxLvb7l9bPP2W22FOM509Mt49mCvBhhvWC1XrNab2iMIcs0WkuaZkeWBUD+5PiEexcXvPP4Ma9evuLZs+c8/eJLNrs9231D6ojy3lNkikL/9WnEN040vLeRrykpi5wsy2IQrMiKguPTM0aTCUpr+pKQ9z1KnGlFZiHHsygLpllOJSWmadjtttytl9Rdi4nTqUkvSW8oUoqeysHJsPI2taBP7Ic7Ndhy0QeZfcdoLGv1DsMH9LprOrrWYjoXG8oCtzU1pB9mci4FxSKhQQm3ilzRg+vBSWIugk10p+hg4omH8rRzoflc9vc1OA4iRcj7wAP04Unsi/I+GHpEGPiSzjJICh5a3YF6RdLaTqfgfN88J6QOhtzLuF+Bik38iYqSVBYivNMnl5mUZIj4h1iGE7GaoeKsiDC3AREqHcIn3q0b1saHyZwaQSYkmVT0pWURBt309Ddve4pPei6Sys9w11KTZDi280GxAULJ0zqH86lp/IALK0Ih5xA9Cv8KiaCMCQdK45WidVG2V4HrGjwOJwucyBEiqEbc3N1S73bc3N5y//59Hj06Yr3a4Izh9vaWxkRNeiljQhznBpQlWWwuNtbRNR3L9ZbJdB96MuLcEKX0EFyJoI7VWIdSYbDReDJit9/hGk81qWhMy1dffUWXJFaRkdYjemWyFNB0xtCYmqIcIXB4IfshYliHyhV5WdK5js1uw5urN7RtmBCvdYFH0FnLzWrDbt9xc7fhycP3KMoKlZWU4wlNveXy6oojPNMiZyYFUzyVc2yahs47WikxRYZVggaHbcPU1ZC5RrxPEGkfrndGzoTeDRnpCCmllj5Qs7QOSQhSYKWgsdC4oLhl2y3L61c4Msr9GuMN4+mcohpTViesVkturm+YzqaMxxXjUcWbN1d475hOJ5xfnHJxcc6TJw9ZLKZUuWa53HC32rDZt7RWYGJfSprt8tvtL9uC7GxRFJRFQZ5nMegM/RonJydMptMwjMxH4CkGvYIw0Vc5RyYki1HJvCyY5Jpuv2e33rC6W9G27RBcQ///tCU+fYqdUzCc4soedRZDMhBeJd/vLfULkoCMKPIBBwG4h7Zp6Ex4z4JFGzqn+vOKB/WuP3hfqUjkQno0PP5KH+Sn44p+HYNYRACynLUhaP5ala2nAMHQSzBoR4Uz/Frgn6xyqqBI8dYZ9T9L+39r3cUgD9yvH4NyW6KhhKU4WJ0k/iKiuo4Lv9unXzKtaaDuphqUSElTknuMZx+U+2SgPvtDGeqULH5Nbar/eri2w4giPSup4tEnHyk5SdSpeE49QePgGBw8h55QtU30LuEDt95ZA34YhSeEQCqNAeomTKLe7XesN1tOF3OOj+a0+wYhJKvVhm4TKhbOCAQW7wK7pShylFKIOHiuaTu22x3bWJ3QWlNVFdv9Ksys0UGIxTrHZrfj7OyIrMgZT6fk5R16v0cqSV03XF5eBgVAL/qheS767DQVHkJjvbeWUTUCZ8mygs12gzEdeZ4jpCQvcozpaNo92+2etqmRAoo8xzlPbVtulysgVB2mVUmWl5STGZYwfqCtWyZCMslzJlJQ4clsh+w6vOmoTYcTGq8Jg/iMwFsQzvZsBeEDzV8ePrv+4ImIz0mwVQKhBIJYUYh9zq11dDZOvGj3bO6uaNuOvFrTGI21ltEknMt2s2G9XiOUJss1Wabpmj1ZppiMx8wXc06Oj7g4O+NoNmc6HtO1Lde3d3BzF6onnqCOJVQcUPxXb9840ZC5ZCJHlGXGqMoCHYgWrxyyUNx/cp/TT4+ZHY2QX4L3XZiqKixKSBSKvDMsqoo/+ls/YTqfUo5LvlivmY6nHE8XFLpCygwjXLwBgAsBmRWQi9SAHIzeoN5An72nwDfiASGIjEmGlBkhdPR9yRMXgjEIga6Sgg7H3WrFtt7T2DAFO2mXexfQGIXuUR+XODQ+Ohrv8NYjZEAyw4DaYMUlQcXE4JEqqSI5vBiFJiTvMM5hbKgQhAs0IS3w9I2GAeUMwSuERsWEeqWKs3MmIk4iTriNayVD6RjEwAsVRKpWKBnL2FgYB1YgnesHp4USfvi+M6HELZFBCYrgIJWLsrYiR3nT00GCnRa9U5PehwGEHrRUWNcFfruODeIuNKo7CAoIxCZOJXrqq0h6zlIiYnnPxQZp7z1SZbEc6Xp9fIHE2pikaRn4zhakysBLcDLUyUSstkcUySTnHWxDGGgjCCVnB95aGiHYe8/t7S2FN9yvFGfdEuULlFc4pTBS00oJsqB2nv/w6y9Ybg2P7rXcPzsnzzKkgKfPX9C0Bq2LoCLlHVmu0SoYVemjEECW8/TZcyyO//LkiMViznwypbtZ0UmJz0PfkYwJ4ce/+ZT5dMx3v/NtbNvR7PZ88N77XF1f88knv0aYDCE0zstAS8IjbTCGQkhwoKQiL3Lu3btACrh+84ab5SV1s4dM8eT993nw+DEvX73g7m5H28CoCrM8Tk4XSNFhbAPFhE5IaqG498ETMJabl6/5+b/9Jb7ZcSHh7333O3zr7ATz2a+Ry4bOtOz3La/3Lb+53WBmc9RozOnZGXHYQBQt6BDeolLC4T3GBmdrvcU0bZA3FqGULSXM5wuEFKGySHjmlY7zb2KwZCzsjWN/+5TtjeDll79kPDtlNF5w8eA9hMw5W1Tk0iF9qKIcn9/DC0+rJX/6i58jfun46U9+wsXZBT/83g/4B3/0n/HmzRs++uhX/Jv/8O94+foNb94swyC4JPzw2+0vbNJZCq0Q44pRWaB1lGu0Di0V5+dnHB0dMZlOwtTuziKcRfgwRE95T07HVJf8rQ/e4fTkhOlszuttzWQx5d7pCXkWXWVE5OFgiOKAgQ1bH0cmxEYM308VcZ+IQqEPIu2jB+JFGCYpCJKWwaZb7m6D8ErTDtPuhzA1ou4xWRgSh5T4RD8gEjkv0UqB+LMo3BYqwkqHWTsiqOw4a/oAFZeSlUhP6tF0oqT40OORkop+/aKv8YgevYfYi3mQ7Ax5SQr1w9cC0QNt3tqBQnRwwYP8b4T94vst47wnpWSgQcmgGpXQ5QHEOpzrRcTjhsTA4QNlyAs6EXo4w3D4cE0B4LH9n7eG7L31Jx039oRJQWoS7yld8TMp2UgyxUliPgF0PRoeM96eOhsfKus8nbU0bYNSMKo0uWxRXYdvO3Q1wYuA+ndxkNwvf/MZ7z9+wKN7Z0xnk+BbO0N5dcuubtjXdUDqc818NuXm5ibQ1gJ+g7OOq9tbkJKr62um0ymPHz/i8vLPsQgQirKq8N6yXG+4ubtjMq7QWjGejkEIjo+O2G53PPviDaYzUVBIBVCLIFYkRKBn4wyZEmRZwdn5BblWdHXDs2dfstms0XlJNZ4ynS3CsLpmxXqzYr6YMR6VPHxwgek6mqbm1fUVjffsjOXh6TlFngOCV8++pNttmXnD9x8/4N35lMnNS8x2S11vWdU1103L082eZnyEL0ZkkxlaCbQSjIo8qJ55i4h0KulNqDA5F6nwQ2UxDVycVkUUG4rdqvFdCl9Da0LCUbcbbFezXl7x+uULposzRtM50+ML0AWlzlnMRhTliKKqWN7d0rUtL15cst3umc8nfPuD97l/8YDvfPhtfvTDH3F5ecnHn37Kbz59ypvLaz57+mUPRv512zdONHKp0FpgRZiJAKGkGWyWRBc5ushRZR6dcQxKIkLo2w7lPIUQjIuccZ6RZRllnjGuKo6PjijzHB2z0qEMPZga7x2OpL4RsZy3rDsD4BFfSuvjBFYfFDvS7I4QUAc+pRBRkiyhnsZS73d9iToZ8/48egMRCEkynTDJsYSX2zuLSw2eImarUvbGIljzVKKOgXtEi/pSq0hUHz80NMa18ZET61PTuxAHjsLH6kd4EZ0bEDNnD1CTiHkEGdmEIA2OwXkfeKw2Ka4LTI/sgLexUhH/cwT/02FpvGDTNeTOob1HuFim9SI06EaEzUe5T+ktxhmcD5SkcC2pCiIwAmrraK3FWoPFYH2Ht7ZPJKSNL63zfQKS1lZAcE6JEiBETCJdpNCEJEhG4ydIQ7LervgkpvBQ4o/0L29xXrDdN6x2ir33sUFL8aMP3+fV3vJs71BOsXeCnbXYKEt3t95zeXWD8p7ppAJrOT1e4IVks99zdbvEKxEMqFa9+EKiAlsgk5LtruaP/+Tf0HWGi4sLrm9XhAaTpO4S7nzXmdgc3lLkOYvZnNlkwma9Du9XHwwNl+6TY/MuUqoCArZcrRmVBffv3w/8z87hkRgDTW2QMqcazzi5lzMbLajKkpPFCHyLMTV117KYzzheLHCdJfOC+6enzHOL6HYs2pqp72B9w1hCZzua/ZYyG6Naz6axbNcG2zRcNZdBG1/C+SI07OUKSFUxJQNlwBo8hkxlFHkeXjMpQmKeKBkClIqVO+HRUX5YSYnzMHKE8rjz7A1g1nTbllfPOlQxRRdzCq1xrcEbkFKjtCbPJngvsKblF7/8hJuLFZtNTVkVjPKKD999n9FoxNXtDR/9+jdcXl2xWq3+Svv8N3krswwlQYrIuTcmoTtIIaiKkiLPybTGeRuq8z40VAoEwjmk8GQCFpMx81HFuMi53m4pM8XxfEZZ5OgDmtDBS9HDjknpqW/UjT/0XzvfpKzkSOhz9A1i+Lm1LgiRCGJQLMB5rLXs93uapsF0aZYF/b4GuYaDeD2dQ0L4LRFKlTgSrRRS9T+JY3gIDa1xHylY9jGR94fJQPQTvR98K4imR9jTvxMLIPzA97/XGxxxsG7iP3JNgjho9ZAuFNZ+qNMcIMRRMMUCnbC0TrA3HdZ5dEQOQvcK+Di9HBGoU8HTx+vzvlfMSnbXEYaqNs7SOouJ1FvnTOjTTEMVk+JUPM9EcQuXOJzrAGenbwxXFHzT0OCSmCPJYR/qSQwJZKiMtsazbQyb2rBtTWCinCx48mDPdGu42XtapWiBwmo2Jgxovb1b8jLXQW2vKjHOMp9N8MCubrhbLtmu13jvBhESfFRVCkDkfl+zWq+5vLzCA5PJhCLLaC10XUtWlDgvsdaxq2ukgsVswngyJs9zjhbzIKlvuih/L3AuCXtE0NbbMGsiPmvOe+6WS0ZlyWQ2pSgr9k0TFZQUXihUJimqEZPZnKP5hHFVspjPMF1L15W8J96lLDLGVcnxYkahMxRgZxNsJjjCcFpmzJRDtnswbRTOkVgn2NaOpWlptUDsVfTfksU0D75J+CAiIyATIuSVsZdDEgYQBlZ3oIUdSrYnYMF7h1CBwVBkga42KhwWSecEeefxzR2N2ePaGlVUqGLEKlOU4yluukALQV6NGI1KjDXcLXd89KtPOTk54uLshPF4xOnZPbJixOL4jOvrG+bzBTc3d2zWG/667ZsnGiKoeLjYnOh8UHPxMdtSeYYqMlSeDS+nEGGipvf4zqAjb7/SkkIrlJYUecZkNOJ4saDKc7QMgrYpkDsM8J23IWEQsSEZBqTPw6FZDQyoOPFaBrTS2tAnIGQIFZ21tK1B6xA0KRUCW2sM+31NvQ/ytocsyuEVToYyNbqFnySJunR+PilL9bXv+D2XjHqQDBM+GKIgpRipQM7i5RDUCw/C+qFkHY29l8nJpRcwGLBUWA92PJyD8LEacbCFZtOhHJvmf4RDBKeCS1o+Q9IS+INRUSFVM0Qwvo0IxlS1ewoRhqQ5Y/rfcalXQgXn6fFgwyR4FytCzg8649YLOkE/v8MA1nch0XCunw6PC0mG71Gc8HXyl510EQ1LAaXEORMkU4XEWA9eRmn5ND/CvZX8ipRcHjwT3ptgWJ1gvW9Y5pKdC/xfXeb8+Dsfcrxcw6trVFuw6jx+37LvFMZ5VruG/OYW1+65OFlQjSqO51PG0xnLdSx1Wkmmg/qLShwNknKHR+SabV3zL/7Vv+Tb3/qQ+/fv86uPP0UYg/AOFSt6SUqxM2FKdlmUnB4rpuMxo6IgU4p962MjnzoImoLD9t6FZkUpEEpxc3MLizkPHjzk6vKW7aYJkp8G9rsWpXPGs5LR9IT5dMGoyFmUGudqrG0RSvDwwX0e3r/PZ7/6BJ1lvHN+D3Fcoroto9U1xW6NuVmyILwjptlTjI9QjWPTwa1z7HcNm5slhRChuTs7Z1QIRllAY5UUjISibjtM14LvmE8zyjLHt4EKInphgcG+CBXmryR6RJ5lwV4IQestnfVsG8+m27Pfb3hzeUUxPqGanFNkOV3d0jaO8fwInefkeoSSOU1T88tf/HuuLu9YrXe8/+gBs8mEdx8+4Vvvf4vNfst0MuMXH/2SL599+ZeZ5r/xW6GzOPQ0Voedx6tgL6UQYWJunqG1jhz3aLsjCoxzSOHIhGA+HjEpC6pco7yl1JKj+TSAYCoo5B1EwMBBQJfekRj0Cn+If9N/lWLInp8f7W7CBZ3zGGtpui7MV5KBLup9aBjd70Ki0ZlBdWoI631/ZsHlDGz94FMiQOUDf9f7RCGmB728DBUKL9K5+R5w8S4Ezolu21+hZ1ClE+k0DhKNdFYHCUGiQvno0oKMb1yjKGQSXGZYmURLPgyyD3sSEtUo9WjIfrZJ2KeLv98JR2Mtm7Ylc2GWBtYG34bAy9S34jHORU2gwZeIBMB4j3Gxi897OkJgbbyLE9uH6s8hRblPDuK6iLhoh4nHAFge+B0RYp9EL0v7Geo8fkgyYmmsp+lZh+88m9qy3BtWdUdVFpyMSt6vLbfrmtmqZusktfOMreRN7dl0jrvlCoGlqXc8ODuhKkom0zFZnrGvGwSOrtkhhEfpQJnyhOqJ8x6pQl+RlILXb95wNJ0xjvRfs29ouo6irGLC7dnXe5SCo6MZk8kEKQTHxwt22w24IC4T7hM9nVFrhTNxTYToE42r6xvm0yknixnFaERW10itA71ZKpRWlEIwF4KLsxMmVcG00tiuw1nL4nSBVoJMKY5nMwqlKID8eI7fa47pOMkFI9fStjuUs2QigEoOy7YVXO87dnjMGrSW5FrSOqgyQakFhQqTx0stEDZgy9KF6lh4+kWvSjrEmm/HcBqPklCUOWl2jvGCznnKpmO13bDfL2l2K1QxRpVjcI7RdIHrOqaLE0bliPPTM15fX7FeLnn+7CtOTo5YLTd8/wffZTqdc37vPg8ePWa1WjGbzfnkN5/w8sVL/rrtGyca7XqL0hqd5/gu9mtIjXIe5wSF1OQoMieQrUU5wpyNGPTmmQ4vgoSs0OSFJsuygCbhybVCCY+OnE7nLQ6HUkV4AX0oScqUvH+tkhFeuvjKBegf4SVKlwQjE4PKpK/tAtq6XK6pRgVFkVEVBZIw8MnGEhZ+UAGwwiN1uA4ZDUnQN1e93bAJtU+hvg8Zu4yZfmqCCxOcQz+BRAYDnpr7vEE4CxjSnAtsaNbWToT5I8nYyNja5+N1+SHxcrEPEIJzkZKQbKhhqms/rM9C1wVUR3udTCtWBCRYRbjH47C0PRVKS43zAuMSC9ZRY+lkhvaKTd2ibKguOB8mW4YOjSxWdy1pOrMXHpcSlmQ8PTgn4gwRhacFYdFGYoPsQK/u1TubiKYgQiM9SeY5Qk+WkBiAIaTLLhw3JmKpuV0gQk+NC9Ogo+4XSV4wGTkviL8PRmhuG4PaGH55teEHDy54vJjw5W8+5nwy5cnvPkEdnVN7wYvVln/557/gy1eX3G5ht17Rre94fH6Ea2suX9yybR15NeI//6M/4Bc//3N2mzWF1mRRgSLPShwGazta29H5lmZtmZ+c8P477/LJJx9zfXPN7WqFi/fVCcG+bRDSY43nyZN3WcwmnCymLK9HVFnOPjbcWZdkjQVOhlKYV6G65HA44/nsyy9puvt8/wc/4Pj4Jd7B+b1zRrMx1bhkuVmFt1oVSOeQribvJMiGvJD89O//lO1yyfrVl/z4vSNOxhOezE94/dkNzXqHvFsyEZ7MCZ5/8SVFOWK6uODf3W34YtexyivuOk3tJQ1TaufZWMfuiysy6cilQwnHqMg5P5oyn04pK02uHE7AzgqKvEDi8N70CTdAao7VRYYicLHzhMJ6S6EkuZQUEqalxHjP2URSm45985Lnv3oGMkdlU07uv8tkfozdP2QyPaYoKt69/x7bzZaf/+mnPP3Na+azKY/un3Pv4QXj6Yi/+7t/wPe/+xPq/f6bmuq/cdvV69cUZc5oVEUKRYybffBNIr2kBF63lDY4c3rziFQ60CalDnQhpSmKkjzL0TJM8k1y2ClA7pHFfn7FEOQPX8R/9cEhJMj1UA0REXsEPBjnaLqO3a4myzVkGSLPIqruaZogU922h74mUhph6N3zHAS3ATDx/VoMNKmUZKjY85BmISUc3Vob1KZ8BIWco28YO8y7PH212KVLFmLoIYC+6uNcOr+wlk6KoJyZwLG3Ainb7z9cbTy3KAOfAjJ8EHjo1akO6IZpb0YE0GEvBPumifYogFOpijn8nj+gpaU0bgje+/321zmo/PWAYaSQHVbGv95v1Q/3iwNOOUyeXBA1+Xo/TZ/8+ZRsEBPH9FMXgbrIjHDgyLjcdgjX8NFXS57cP+b8ZML3vjMNFbTWUBuPkYouL/kXH33Jpy+v+GxzTb3dcusMx4s5UhmEaKibPR7Pvfun6Dw8NwKPVIIsD/MtjHOEcqOkaVu+/PIZxbfe5/T4hJ/85Mc8++oVXzx/GSrMArIsw7QdjQpA8Gw6ZTaZ8M6Th7S7Hc9yTRtjLNe/fz5UkZzBW4vKgwhO5yxfPH/O/YsLvv/973C3WpKXBdP5gtF0SjEasd3X5NYynkyYTUdkCky7Y5QpylHJycUpOAOmozKGcSY4HY3w6hS/r/B3l/jbK+42K9rVErIcipIVkiWwomLpMjZWUtceKTqU8GxbixQGScsoV1S55nhaMS01pdZMx0GBNNMS4UOyarwhaBgFpdNMq6BQKWWfiHprAs1KSrSQaAVlJZhmBZ2Fzisa19GaFcvnK25EhsjHTI/Omc6PaN/7FovzeyyePAEH6/WWf/fml/zqN0+DbO75KR98+C2OFgv+8A//iB/+8MesV2v+uu0bJxr/+l/9G8ajEbP5jNG4Ii9yRpMxI5WH9oTWQufAeGTqk/BRwlQQp94K0AqvFcVkxGQ+YyE9o8losETJkPvEWYzDeESQqxQCUtGbtLiHxja9/Onnh/zQt3ihkMrXvdIGSeHF0rUNJqLn/q09pvNKwE0iDA3b4TkIkYL5hDmFcwzNdelfEWX2gZbSNzYnExcNhYh62T3qwYCO9SgLYShMQLk5/HA4dxGbCw4MVdpHklSzUU0pnEEwjjLtyyc1kSgBmHi9HlK520dkMbYyIB19oiHifdXJjQnXJxpEyVhSohDXJ6kt+Ygy4YMUaDLsqdkuXGe8JhdPOp2bCz+zMXET6drSlcQPCR+ag32PKMSU66CpMtSKPGBj5ezguF7SOc2mE3x+vWRc5kgFo8UioBLOYtfXKKk4yRTff/c+x0dTPvryDavbO5rdNqqfhbk1u82OrrNs1xumkwnT8ShejEPKGCkIByq9b47WtNzcXrGYjvned7/L86++gmfPWK1bjIvPBQJjLTe3NyymE7JcM56MKMocqYagKiSDcQHDAxubBuOQSSXJtCbPc8ajMbP5DGcNp6fHCC3iAL3QnC6UQtow2VRJT1lklIViJDq86PDCcH82ZpJlyHbLxDtKKZFZjupqfNeBVPgsx5VjusbjfE7hRhS1wppQRfEuNPhvrYt9JaG/q3YOL2saB6NCMx9nVEqDUujYHyzTOy4CbUqpMJNBqqAKJ/qALklqyhineXIpwgRzKVEySDu7zgRUtPPs717iug1adZj9hnI0Q6gc7yxd27JarkOjb9vgBCyO5hyfHiNRjMrJf8Qq/3YD+JM//jdMpxOOjheMphPyPGdUllRaI2NDvXWh4mkjcJQ4zQk2F0ohomxjVlaMZ3OOHUymUyD5pMOjJnsebfhbUH5KLhh+5y07LA5sCYPvO0hXku0UB+mQi6pDQfkpCBv8hf2/tfk+ERgqLqJvY/ApYT4IYvtTYUg0Eo1SJPWkRAF6K2Ae/OxB0eFgqUScQ5W+N5ybgN6+vq2IFYN5nyhA4fsy3rMk345LFZsh8O57FOJ1p1/3gJEJeAzVjES1HZYtVRYOEo0E2B0cxxNp2SnuiN8TsWrm+8SD6B/iHg58VbqvbzV+p3v19YQk+Wz8IJJzsMjD/g/X+HA/ksZK1h28WjUU4xqZ55xNC7TwVJnAdTXSSRSS9+4dU1UVnamp4zwLAGMttatZLpcIKTg6CvMasky/9XzIxByBOMDRs1qv2e32uIXl3XffwSFZ72qWmw3WO7SUWBcovdvtlvEoSOhOxmOKPMM7Q+plSXZapHsmAvVVZzpWnEFnGUWZM5tNmc2nOG85Ol6g8gKpNbt9mIKttA5y+t6TKcm4yBgVGTkuiEUowVxrJlpzkksaYbHeYJzBeofB47MMl+W4rKT1ClvkqIkmM5rCSmxjgzy+t9RxMLB3ltpYyi5EXa3JGeXBDlkUpZRkYqBKE6lTQsngT1Wg8sZct+/pEOn98SBx5EoGdoUXSAMSS4MLPcEt1KtrMA2vM4mxHdV0AaYDG4RV1ss1Td3QWctoNKauW6wHj2I0mfLXbd840fjf/K//d1xcnPHuO495/713OT454sHj+9yfn1KqHLtqMVuDrV0v59pZcCooKjk8XikoMkyuGZ8dc//JQ+ztgmw8ji+ziOVN35dhJTaWQFPHR3jzUwP38B6lJqrwsrloa2Q0RMm4e5GMJ7HJU5DnQSpMeIFxjs507PebyIO1MTD1USc7qhH5vv2cgLjExz9GZynYFyJokB9iNArQXgaCmJfggtqRjKVt4+ygehTXIlW4lZAI4SOfNFKmEgof/63i99KYiRAc6YiuCGSUHQzvZwwjYwMb3uOEib8jUC4Z6WgUBUF9yidesBnKwio0KUkU1nicsDiRzpm+rwY81puwGF5E2tUBUoXAmMHIplKhdGl2iqCLWX6A5MK+hBv6OsJ7bPskZJAaDI52oN4Hjy59qKyB7ydgCxKqFJF8kZx/CPSFDDKGRvheJMB7Ses0y8bxp5+/4HZzx4vbKf+zP/pDurs7Lp9+xotXz5B5zvn77/Hf/92fYkcz/un/+4/5zW8+58VXLV7p0CAmNJvVls6sWG9rvvf9b3P/3jnWtXg6pLLg9+GsdQYovPOYpuajj37G+vaS/8X//H/JLz76GPGv/y2//uwz9nWD6RxSKYw1PH36G+azkpPTKYvjOePpCFSY/qmcD4+ndzhsQBBj0F0UBWVZMB6XTHXGyfExi9mc87NTqlLz8MEpN6slt6tlQDljmTpXkkJApizH84JJKbG3LxlZy6xSvLeYY+ua2xfPmDlLXhZkiyNuX79gs99RzWb40Yy6muJlSW4FJybHbTx57VivajrT0LmO1mmsCXNyCimRe8vNcsW4XDIuJY/vLYIe+qigazuUcujMo2RQpsozjdIZQsUZGilhTarQB82mDhveaynItafQgkkhWJQVTefZ7g23N1+wuZFs7p4zPTpjND3m5NGHOAdaC+p6x3p9x9NnX7Db1xwfH3NyfM18Pmc0Gn1TU/03bvuv/+v/PWdnJzx69Ij3vvUeR0dHPLh3j3snJ1RFTtdZOmNpjaU1MfGLGvAiIthCZ8g8x6uM0eyI8wcPyM/OUaMqWAIfaTMpgAVIAY9INipWAw5UAocEIEbfbyUEYqjM94lGAueCYmEIJKJvso6uteGPsRhjI7iQIvYhXfAHwEA8UvxISJTTqTnEQXAy/J0CGgh220ZKkouAUYr808yQtBZ9jOx8oGLB0EQd6Tz4FH4Sz1v2PqBP3vqMJwbgMVB/65xTkiSTH3ND8uEhDYbtgSoGv++IlC16yKx/l4V1EdCMn+sTs/C3O/ApKchTCZDxDpwZelkSYJaSjZRoePrkopev9gfXns4lHVgQG8x976eThH+6/6naFv6I/uepsoRS7K2HFp5e72mRrOoWcz5mlgumGtZXr+mcw5UVP/3e7yHHC6pS88XLN7y6uQ2zG7qObd3w1csXKCUpq4Ljs1NmsxnOhf5J50ygqPuwXjrTWGO4ub3lbnnHyfERf/gHf0A5mrBvDb/+5BPatkUqQbvbse9arq6umYzH+KMFs9mUItd0TU0Q6ZXxfSSCzR6lJVIoyqokyzR5ppmNK07OTjk9PeHm+oRcK07OTmmNpW47fNeipKDMczAtQsGkyjieVIxzTbNbkSnBWEsez6ZMlWImBZf1hnq3RLQ1uZL4qmIvFFaXtFlFrRRWC0aZYOFzSgP5dk9X77Ftjem2QfTHSbq6QYqO213HfJQzLjLOOs98DNNKMKsUmVLkMiQcqWdLaR2SJDlQqnqQIMY24XmzaBko+soFSedchbis89A4w253xXpzzfr6Ba9fPGM0PeL03mO0UIzynM2+Zrfds97s2e9bJtMJF/cuOD07ZT6b/RXWOWzfONH42dPP+eTFC/7Drz5mVATE6Ph4ygeP3uN0ccxiccS//+VHPH35inXrqI2nFS6go15gHNhM0yJ5fn3NyaP73JOaB0/eC8OwoiawcyBUKuG60BrgPWBRMkigtSaMXQ8FCtUjKNYNE8eTSpAnoQvgkL328rquscaTqYIsK5FK0VgXjaoAlYemIanwnQk0Eh8UkkId0kSHkBxIxEAOkBcfjYkQLpZjY4bvBV3EboTzOBsCY+kCHcU6h7E2NAMSGtVFVAdxzoaGckJJW8jQa5AAGSHAeZXcChDoIQMKIPCd6dcpE+G8jHU9UuuNCzQ1EepJIdFxWBmNuU2qD6H3wgsfkxrfK2wQlT3iEw+EkfUejxMHii3ReCNERHTC1n/t6WkLCrCEJMyaMDMjyC47BlQpfKWVimmD7HnZzjmSlLD3oWcEH1SBiPzXQZveI2MpWyjZG20pg1qV9SBlGC6pcGRxBkvg9drQmO4zvrjcc3O3o9v/c3743mP+3u/9PcafLOiaHdIZzumocvgvPnzEu5OCz+6f8POnn5HlBcdHxzTasml33NxtyJ9J9t2ae7/ze+g8BsAipkOxQVMAZZEzm05YzGdkuee9d++TZ7/H1fUr3piWpjVhdggOUZRs9g03yxXT6ZxRWZF5R2CYhv3qPEOpnFJrqtGIsqoYTyboXJLlklIJ5kcTJA2LcYa2Jau7JdZ0FFpTiNjsJg2lM5RScFYVfOt0xnyc8+bpNcezOadHx5ye5MhO8FCf89m/+hNWVzdkxrLramopWU1nbPMxm3zMvspQZBxRUZ1IOgN142jbhrZrWG9u2Dc1+3rHblfjTIeRno001J1j93LD86s940zx/sU5s1HOrByRVxIhQ9VMah2SK29JA7WMC4ISQhB45cR4Qkicl0hyFA4hHFJLMuUpMkFZBcWXtrtj/2bJ5lKzvX6FLiboasZ4csLxYsbk5FuUoylaZyx3NbvOobM1/+CbGuu/YdvHn37OF89e8POPPqb85yVlWbCYTXn/8RNOFnOOFnN+8euP+erVGxoTB1wJG+lCEi8lnffsOsPruyUXnYG85PTkBJ9nuCLrE4wU1KRso7eyfYR9kHQQQsWwDcBOClRdBHnSLwip8QRpUROnHmdZHhXmZJjxYwKoJZLcego2bZL/CIFdMMgOlfoD3wKWDig2BxTkXjbdB5uezi1VNKwLUuLGmP4aRAT1+itO9K0Y0Q/7F30C0FdLep8VA+wI7aQkQ8hU/T/MzpLK0kHNxbl+6BnOIeQgNT8EWyE4Tz7ISxEU9Yg1o5To9ElAOCMfGRM+Jon9vkiV7pR8ishGCIIuztvYPO7eegpSYurTdXCQoh3cizSDJFUIhBORXRGrBemZis6sr7x4hvNNKx0WEZynkxrrPZ/fNlxv98zeCLw75/17R9y/OCPTgeq9M5YHY8lkntP+6Lv8uzxDWMN+t0coRVWWZDqjrvd8/Mkn3NttOT87592LR4zKgvGoQq3X7JuG9W7HbDYjzzMUQRZ9u9synox4/4P3KMYT7lZLbm5v2Nd7BIGyu91uw4C8tmU0qpjHYXSvlzuccQjvyHSGVIoszxiNKsqyYDodo1VopJ6MSo6PFwjXMasylCnJbUOz3dJut8w0jKqCxXzGfnVLLuH+fMI7F6fMqoJXL55xVBWcTkZ862SBrGuaq0vayzfslssgRNNZrPfsRjMaXVJnI+xohCZjTklBhnHQ1Q2m3mPamu36ln1bs6t3bHZ7jDHsuo5277jZd1yt75hVmkmZ8ehsxnxccDStGOexf1T4ICsrxCAq4VKiGhTVhNJBXTFxVLxHa02WSyoh0E0Xzss6xrnAWM++2WFvn7G+fYVZ3iCLEbKYUEwXTKox48URs6MjdJax29a8sVfc3Sz5+z/+Ln/V9o0TjdvtlvVux81yiXKeTCkmo4Ll9YaTxRGnp2d89vwrLpd3dM5hIuItXAxEo0xpaw03yyWb/Z7OWY5mU6yQ7E3XvyiDIX0L/ulVDGwsSQovUGLQEiciTr1kX+JG+qHRixjA7nZ7cJHC08u6RrchksFMUMbbFCNBUgk5KFPG17qXi02fiecmejsSDFmqKXhCuS48J+EHJpb5k+yfF3FCdnQEOB+bvWLp3IpoLtOWyEHuQJEqkXFTYhRLjaFZJOBo8Xydi2pVMooJRxQl/ScGa0afQyfjls7Rh/WWMbGScQ2SoU6TaYPdHSZ39/c6vjxhyeJ5O/CE5KKncCVnnbx+/NM/OgffS8Hh8DzFG3HwQRObgEXvDKLji+em4rm5w+egd3mpMTCQwbxTbLuOtu749fNLJtMZHzQGk5coAaVy2N2OTijmwvHkeEFZjnhxeYnMcubTCeNRiTEty+2G9fKWWy3Zb9bgHVVZIBR463BOoryIb47CG49pWq7evKasxjx58oCToxn1fsd+v8MmRyYETdOy3ezQSnM0m/Pk4UOcecWuMSggq0p0phnlOaNqRFmVjMdjlBaoLChnlLlGOcsoz6DMuV4uUThGMqgCZVJSCkHpoVCCo1IzVlAKzyjPmVUVx5Mx7eoW1bbkTY3fb7D1FrykQVDrjG0xZq0r1qqgy0oQGYWoUE5ivaAsPV2X05mSXDvqpmbXFOTZFmMMpu1wvsU7w75psNbQtJb5tqb1nk54LDm5FhQKRCbJ4iyX9L67+O4n/91HTDHQCkM7Iz4dy9hSBb1zY0G6oJ7iLDTLN7hqj7cdSip0JpAsMKYOymrWoU2HbA/1+X+7HW536y1S7pDLYKuUUozKgrvbJUfzOacnxzx/9YqruxXG+oGWlAJrEXoP2s5wt16za2oMjvlkjNWKRiQYg4NAeQgfgw1IvRDRjvZ0pGTnhuyjD+Z9Cjfj3y7w6vd1HVF8QlUjViAGuEj2Fqc/hIg2OR3HD/Y6HT8h9n0Tdjp5fxD8Hki1Eyuavb12DmsTcOf7YwylG99TjJIv6d1ENMqHc7H84WsDg09L0GxMWsSwyEOSF/107zNc8Pd9tUAc3N/eN6SALFF/45qKg5/F34nes/9cuoa3Eo203ul8vQcfxUySlO0B8ij60/CDHx+ymr+w+XjOAayk98FDGjH4WsFBspGud1i8/l45AijZGYexHXXn+Op2R1mWnCwaSq+RWjDOQZgOX++YZoJ78zHbixNu9y1eSKTWrMYjls5wt1qxuVtSKk29XqNwTMcVynu8NZimiYp/Qdq9bWo26xV311fk5ZjHD+9xdrLAdDVNvSVZOmcsbd1Q72u0lBwvFrz/zhOaz56xrVtaB6oowgDAcUU1qqjKgvGoREWqUFVkjIog7DDOFarQONOSdTVFVzMaT5iMChbjkp0pySQcVyXjTFEqmBWaeZlzVObIeoddb6hvb7C7Pb7t8ELReknrYZ9V1Lqi1iVGVQiZU8gSicY6cJnClQrb5mTaU7YNRVOii5qu66jrGtd1eGtoTMO69RhnqDYtnQcnJKbUFFpS5jLQxIRAHT6hiervolCSIAjfxKRZSBETcUmmJFKG3l3tBEYF2l9T1xjT0G4Vsh0h2j1SghIOuhJvxkHSv23xztK2/wkH9rXC0CGRXgYKUWdZ3a25vPslwofg2IhAI7FZjlcK4VWYw4DH07GvDUssn3/xJY/feci72zUPJmOslJjdPnDT8QgnAqcbER86hxeBe24Bp5LB7d8s0uwESeSupcaO2HwdyC45nXF0bcPrl6/QSoW+k9kkJDUOMpUFVRkfS6gmTpqGsG8R5xdIgfUtoWIyTHQ1URkr2J5QPRHSg7fQT/TWgMJ5F4avCIGx4KJUbdsaTGPQNhiZoO4VjKi1tq9GKCkJg8aG6c3OWlDBqBgfeg6S1Q3+JvVphG8bF2lSyGgnfY9gQZiu2xtRFwv7UoVhZwQeZu/SksGVkPTaOxLpLbRMpO6GNFrHu1B+Tpl56sNwPnAxpSdyAcMCB1qZi4lReEJaTOxhAdEFAy9ErK6kbsckFBCscnQhMiZins57vDuQeoyb9+BtLFdDj1oF5SbT+xHnOkhoJRbpQaHxFBg0L3aGu599zJ/+5mN+98NHvHdxyu9/6wN+9cmnLJd3CCv58Ee/w9/90e/w43e/w+12w9VyydR63ry55OnTp3RXt1zdLfl5ljFaHPPkyT0+e/kU33V0rSDXJdJBt93wZn/F5vUt/2T/j/nDP/oj/uF/9p/z0x99h2kl2a6vaDqFcWHozna54k5n0Hb87R/+iN/70U/4P/0f/s9c3t7RFgV+nCMLzbisEC5Q/DLvgzHXCtU1jJxA1x0n4wkTLVm9eso4U0zLgkeLIyYqZyIzqkwjlMPpmtvba1bXhvv3H3M8GTHKNf/3f/J/w+9WHGdQSc10ntOqKTsruPaKq/KUVma0UmOyHI9Cpbks3iOkpSwVAsXp9F4fODTG0FnHvunYNx1103Bz+RrXbnHdjo+ev0T5MLTtdD5iPql4cv+Ei+OKqcpjFTFWgZLj9pYsBgGKQHMRUg8BpB8oIUIqCiHJtafMMo5cAF/WtaOu79iub3j17Ck+K9CLI47Pn1BNF4xmC0ajMXmcdv3b7S9um2gnlAs2HGtY1x2v7z4O+ISPVFMBFomTKgRLLjwz1rbURrIW8PmLZzx+5wHv7Zc8mTzBKw1tEMTwLs4rSoPixJAwWGP72C6g6Z5oCEkpSbLbkmgzI5iVlBub1lA3LS9fv0FLSVWWLKYTnAzTj6VUaJ3FfdCDTwmQkaLPGbCBsxJ6KyK2FFB/QeobDEBJCI5D2TvJpsb3KSZN3hGruGF+gulM368xJBsp1AkVFylVyi16MIb+az8E0XEdIX3Wxxwifrj/K3w20aiArzVJD5mNdfG8xUEyFStSThASjUAnIFWy305k4u2FEJP0oFVKRiJIE6/DEY+V+jLSdUWATsTP+diDkZq/07OTjsXXvu4H1/Zg2nCdNjmetDZ9MpIqIb7/vdSELpzAYRHCIzNB5zXWO/7k6TW/+uqOf/3LZ/zuBw9553zBTz94wBfPX7HdP8UieP/hQ/7O9/4ue+NZb/dc3iy5l8HLN1f84tc7mjdXvLm549dOcnR2xrcf3OOTj34F2w3s92TWkEmJsYbl1Rv2t1f8X/7Jf8Pv//0/4O//wT/kd37wIZ8Wku3VqxBHiSAhvrlb8Ua/Bmv58fe+y+9959v8N//4n/Dq6oat8WTjEXlVsjg76n2v8I5cKcpcI0zDVHeMaMlHGYaC1asbRmaPk4b37x0xHo8ZjcdwNEbiqYTg5u6Ga9fw4HjGUZkz0/Bn/6//D83tErfeMqqmjLIpbTnitjHcOs9ldRx9U0YjM5yQFFi0swGclA5ZakSVcTyronx8YOh0xlI3bRR6aFje3VHvtjT1nk9fbxDeoDCcTisWk4onD044m48ZlxmV8mg8Uni6tsa6OCdFZqEpXGWRxiiwiCAL7Q0IGdT65AB2jLMcOwHjYFOvqbs79lvHzeUniKwiH59wdO8xo+mC6fE5rqzI8vyvtdHfONHoTKgwSCFigAdCahrvg6HQWR9EdjbIhyKzoJ7kHcJBkeWM8xEXp2eUeUnXtvh2h84yRsqRCxuH+SZ0mH4QXbB/cgiwfSo9it4ACB8GzclULo7oghCagDNKtBKQe46OFmQ6TLIEhzFtlO0zGNOFIUNEqlIsQzth+x4NeRDISiWjwoNFR/TJp94BHyoEoX1BBEsnXTRE0Ou+O9PDbGEwUod0LlYzwv4EkGnZN42JqB4CHtuF0Lk3NiI5oi4aLxFtfXzQYn06GWPv4yRoEc/dx0fPu16FJK2JdV1v191hYpJ+nwMDKmV/rEQV8ILY+B4+E4yfCBr3KdFwdsCSXLgCGe9pCvREb2iDA5UHQA5AGop1mDk4F9YjyCKnhvuBFpPQyuiGw2djYotPA9tC2Va69GDGX/UChULK8Fp1Lj2jMnAxG8Ou7fjTz97w4rZm1yhG0lOUc8Za07Udy9dvuD+ecz4d8d7FKUe54PLqhCeTnJurK+r9jvz2lncfPOTJt7/Fpx/9O/KuJW+30O7AQ5YHyeagEgddu2V995p753Pq5oI3N+c8f3HDvu6YlQXzRcV0UdK5PUpXLKYF3//BE16+Knn+5g1eWySKqusoHGTeM8kLcq0oChgfT5lUFaeFRZo91u7Rs4xpUTCrKo6mOc5amv0OL3OKvODs9IIqK6hNy9l8SikEtjWcnlxANWWCYGUtOy94LQtufcGGjJWeYYSkEyJkoOnp9qmCQOSxQmps8gJyrVHKo3RGWYGxjulojG332K7GtY8wpqPtWly7566zbJ/f8XrZMK5yZpVmVuVMqpxRFvDO8F508RlwYQgcPoKyiXro+/MLwWVMrAkiCFXuyLSkLBR5A623NOtrbuuaZVZSzk6DSsr4t83gf9nWOh/vue/9EzFmhthXJvo3naDzJ/tqlEeQlyXVeERZjRCRhy5wKAmjTJDFgNYbG0iFkZ4AIsh56qw3A9YFRaZMDUCYjxSbkFNEpN77CKIEKVApA1Xq+OR46BGK8wG6zgQJ1shL9yQJ1eQBXJjBFO138GXRdgrZ+wMfn0/fN1oPyGeyp33iIIkzICzCip5/b22kBUU7nMbO9NWLVDWIlKKwRdAv3ZaDBOmtVCHK6vZJwtf8ycAYIErZEu+BGALyZPdF6q0hFVz6awv+bEis0pMwOBDfJzhhcWKSkd71eGN7noAQPQMhrUu/L/92rpL+7hvX028lv56+E5Oar6tUheMNPv2tneJ7/x2e9OEWeBnAD0hrI3BIauswtWHbtKjPX/HybsO6bql0QL3zPMPKAplV3D+ectZZ7h2fMlE5b+ZHzIViu69puw7dbJnrc+4fz/nhe495NSl59vIVuanxZo+qdyjhKcgoMIhmS7O+ZlFKHhyP2b5zj+fPnrPd7fBCcjovuXc6pZCWQlpKJfjwwQXHZcFqW7Nt9rhmy2QV7KhSgc+Si4yREExmY6ZVyZHb07kGS0dZKorxnDLLOF6MMdayv3tDmReMypL7R6eo3LKzmvliRh4nnNvxFOcVanxELTM6JEsnuM4z1kh2sqQTis5LuhCShCqCiMBqsk+E+DjMH5PkUqMzT56X2HFgs8xm8yBI1LW09Q5rGkxbY9stS2P55MU1l8s1ozxjMcqZlDmjImNclOhMkCvobBOfnQgkBKPTv2/DazjEg0IqlA9y3+NCkWtJmTny1tPZhnr1iut2z7IYsVqcMJnOKKu/vn/wGycaNspqufjkBrZRmIfghUBq1b8bYeKyDKiGc1FtNlA6tNSUeYkzjs1qQ7tdU5QlmRRIq0K2LftWMVxSjYo3LTXJ9QE/gzNPqjB4+v6CYBQCF9MlhAAYjUfkWUZVFkFWNsrVJjUjpROXP9K/4gvsRWxIljEwPnjJfUSdPAFVCU3KyegFnm1o3PZ4ERvIHXjC8XER1Y/SeCI1bUdjIqDf/2Ctw98u9lhIKXFJKUqkr1P/BeGY3ocMDoGXQRveeturRKQZAuHcg0lNDfnE5CsZ+LCmwVG+RXWL5WkUoT8lrqVP4JFPhpxY7gMfVZx8CgniNaYBPUnB7K3gHh+rOjGJIhnuZHTD3yJee3/uCZk6QKgOka/kGlLA2D+PBw7gLfFELyCGLyK2lRvfRQnLUKVrvQfb0V5uWO4NyIL3z+ecjiu01Nytt3j3mg8/nFNNRuTjEdo1nE8KxqbhtRasbu9YL5fcqwq+d/+C906PyE1H3t7StjExLYKcYFbAdJShaKnXN4wLxelizJMHZ6xXGxSWyaTiZDHm5HiC8B3SN2Qi4/H9IzLR0u6u8TpUwSrfUThP4T1TJLl0lNIzn2RUlWaqW6St8bIhm2QsRhWz0YRinLOta9p9jbEGgeJ4vgg0kbZhXBW4uqVuOkajGU6WSCPYdi03zvOVUOzEiEYU1LLExBxDuW5Q44h3X5KSjeTrBwWp9F8ug8zvdDzBtA22a5He0bQNm3rH6vaKZr9juV2ytzXVruV0UmIi6itFHLwkFQlMCCYg9Ml4FxJsIdSgYtU/k/SRgpSeIg5hLJBoCXVr8Jsd680Gg6Le7bH1hva3icZfupkIOgQLe9DQ3K94BFQiPTY1RA8oNiidofNQuWq6js12S7Pfk/soL+qyaBIGG5PmTkAEVNKxEv2yt1cDQzNUn0PPV6DNuwCouZSghmFmSgbtfqUkxABfRnBGpiE+HFCwonqfT0dzB8/aW4FqINAk8Mb3H0rIePpYXBsRaEBOhL44F31lCrYDJfjA7r8dScd9D+vwtts6iMRTeO3dUI3ok4ODa01+ZUAfQ/DkD+m3QxLQB/Pu4Pj97x2ugX/73NL5DRy7txIN8AdPQjiHr1cnDhOJtzY/rM9hEpESDaDvWxmOebBOKcmgz5+GK0ig68HhhqdluFfBxcW+TyStsexMh7hasdw3dM7z6HjGfFxRecWs7pjVHSfHBeNSczSZIWrDIi/J2kA53G53XN1eclRlPDhZ8OHj+4y0wOw2tF2LsQatHFopykIxL3O072i3d1Taczwteff+Cc3dFYVv8Upx72jCg9MZubQoOqQXPDheMFWKVbXj+sbQtjWVbSiVJotVxNwLRjiOypxRoRi7lg6DEZY8VyymQea8KHLWmy2buw1CQkbOfFyyFyOUUZSjEdhQbWjzEjNSCKHZd569dVw2lpWW7ISmFjkGEWd8pfgh3St/4KuG+4cIg3QVgiwL/gXAjkc4a7HO0tZ7urambXbc3lzSNntudmvqzlBmiqYr2XeOqQGlc0qlKfIMs7f4JLrTOyl38L4eEn+HM5N4EEHQRCtBriUCy74xNPsddb3Hy4xut8bM5lSj8V98xr+2feNEw9BEedUgAwgSb1MZGvASEUuWMivDzz3BoEtH5+But6Vpdvzzf/3HfP70S578+QPUquHs7IST0xPy2Yy8qhgdLRCZDk24Kkhk2iiZKkgTeiOCRTTyPqEXYSCdT7Qj57AIOuO4Wt2y3+8wpuXk+AitcvJcx9kJEtPFwYRVyXw+ZTweURQZvqmjYTVEsLofiheeizBzQXpB10aEs/+TmtOJZeyQnBlSY7IEqTFNjTWSxhps1+KMxbcmGFEZ1tELYhLiY/A/9F14B0iB9yoG5tGoeBluc6xKBIO4jfmLxHsdztH71L4SpmtGLeZUIelaE4bx4MFbUlN1eDRFuFdRblEAGtknI2HAjovKVuHRVn2Ln6frGsCHoTuxSqTUEAQQE5GkC0WkDiQurIoJghQCmxoDe6cZvpfstsDirQ/KS/ECJFE1RAiss/RN8/HZ9xC5/Q6hZUCune0rb+CQIos0g1QF8ghnkDIFvXkIdLSk1Z43jeX208/4k48dGZ55JTmqKk6mU/4L1/Do0QPefecxs7M5eQ67qzdcVE9wzTnXl5d8cLHg4Vjzv/pH/4gvnn7Cv/hn/08yEZPFLGPZOazO+MFPf0xZFaibL3n1Z/+WyWjCP/qD3+dn0yNu79aIXPHw/Uec3z/nrBBsnj/lkz97xaKace94wh8++n18VyNsR9k1tHcr2vWG65srbO3xnUTrDVldotyMuunAec7vnXJ8esri+JhOSNRuRzfVPPvyBftG8Z1JqOKobs+d23C7uub2zRVXy5p1Y7juPOvRnDrPWEGkG8pwr71DYvFkcU6C74cZtVH+MIAToc/J2fCuOREm1ooUjApHnkt8VuGdQFdjqtmC09NznLMY09LVa1wX0Lhn17f85ouvmFYZZ8dz3n9ynxwR5A8ziXVdFKEgsjI8hUy0ypj6ej9QGYBMxJk2+KB8kknOihF7B7X1XNZLll+94lXdfFNT/TduC4pIQWRCJbj3AEkPTcWx5y4CZEooBEHKvGkNq+0Oawy/MJ+yXC15+vQpN8s7zs7OOL84Z7o4ZjQac3xyDFqFl9o5jOnojA2THqRC6oxK5eHHifYieqXtMPQ3zv1x3gWuvHPs2471bkfddpweHZFnBWWZB/U5PEIrNIKyDEIPk+mYqioR230MfAfUUuB725bk31MSPCTF9IBK4HQHoZUeogkOJNj+pg7UXGfDILMoe5l2puSBBG+Ppov+e4kiJsRgU1OIHILyAZlPfQgB8Ho7XYxOrbfPPTUooFXxuvzglw6Tm2QT+kCe6BMOACk/+M1k2XvOewriif2LQ5wYT+Uw5I/nloCHCID0lKmkMHWYvACh93BIEEVMat5ag3gdg/hAsifhsz4xBQ7OL3W6BKWu+Ew6298mqTPQGfiKtTPsNo6b3SW/evaGTDqwHUezMSfzGf/gd/4W7z9+xA8++Bb3Hz7k7OSUo8mEZ8+esVze8eT+Md/78Q/5zg9/yIPzY55+8QXHpcSaFqUUi+M5CEmW53zwwYcIpahvX6ObFWeV5PF33uV+pajrhnI85vzhAxYnx5S2Zn+7YrXbczEf8fh4RlWNcG2NNw2uXtPsNjT7Hev1mkALsojtCtllWDUJfSJZjisci/MLHt6/j1QCfXvD2jRkeYkoc/beM57PKaRn03Zc36y5vLrh802Hs54sU9zsa/bGsXSCrqywWQ5W930yQgxzegYZoINKQrT5Ls1ZSeDHgSiBFAKpNPl0BkwAz9nDR1jbsduu8F2DMx31bs1mvcNeXjHNbziejXl0fkyRKbRQeOn6d8GajgSw5nmBkDIqUAYhJOMsIhBMI+1PoIWkmuTYcc7prGJXW5rOst5dsd684dYOVca/bPvGiYbwsYmkf9Y93pvQT+EFONUvo3A2ICEIrCQi9dDFYPxqW2Mvr1g3Dfr/m7GYzziaz5mfHDNbzHn3g/dYHB8zmk4YTcZhWJryEVUPyGWSkR2GAR28XGKQ8tNkYYGVJdMKk+swNDDLUEr16AOEZqVQNlLkKgxM0TrIyQofeMD9ARMKzmC8QmnswDAdIEUi9ix4KfsAeLCXri8JD2oayUoOCHuPYUQ06S3mZo+cxVJrNH6B/iQiB80HR0u4plDhjtPFo3E8PKSLFm3Yn4+0p35XkUqUAJeIcPWXnlCjUFUZGq8HhAsPqs/0QxO1IBlMBppeNKzBHwUKSj/oKDpIJ1ycqu77JvfeQURkwXuJEC4gzuk0YyKTjh8utj+9aNTjmruh2dOREho3/FwMCVRIEBOXtw33S8Z195LW5XhrkD7ocG+7htvaUf3sI+69vuTzV2/43e9+m2k55uH73+bq1VfsNksujo+YPLiPmEyYVmOO7m45mx3RbVfkWcb9d97FZBkUBffvP0CIMNn6/dNzXGdZff4Fk6YJz3dZsvCCct8ixY6xkGSzI968vsQXBffGY7xUmK7l5vIS0YZhkpP5HPIMygImY7zOaJWmwYaBY1Zwt2oomhuccTT1ns1mhdUjXD7i1XaHVwKbFdzt9rzYGL663rJxir1QrLWglhqDikM2w7p6ayNiFwAISJx4+q/D6nu8UDjpg4x0/BMMf6IGuv57QqY774OTkoEqGADlEulGSF2QlRNwLY2suKlBtC1aeCZVQSY1SupQEo8BgI1giHQ+VGKFwEsZ6DeRBiN8qNZ5HN4JpIIiHn/hPLmDRh1ilL/d3t4ioEMMyIZIOf740FYGa+2cH3yZEDSdA99y5YPi33K1xgvBYjHn+OSY09MzFvMF7773DvPFnNF4zGRc9ZO7pQ5KZGFKqg/UKpkEsyHRlyAGuUIgvMRpS2A5+Z4WLKLKXggOw7OpdOiNlKkvSop+zs/b2UP4Xl8t5oCm61OwHVcrJiERzUmx+rB0sZrtY2L0dhX47cC377Pw9Ch9YhqkUk2qjqc1SKc1+MkDXxr7Rt6K39NvJHrcgZHu+wP9UJXxJPDRHyQVw5Mi+s8e0o3oVR3TYhyEh8Ofg3MKONdBNUikJMP3ft0dAAxhyQcb0QPMB0lH70PiOia/16/rgc9NicuQ2qV9xVvVhxruQMhl6B3pI+MYYnrv2VlLYwwSixKW3WrHXWMofv0pl+stm6bjw8ePGBcF45NjirtbMtMwzhXVeESWZ9y/d4HpGt68PGe/25Bpxf2H99F5QVaUPHhwH+sdTdfSrO+wXYswkbJVZExGoSk7F2CbPViHloLV5o5caXSmyKUDBdtmj2mCdGyhNXlZMZpMg5KokrRCI/MM6+Fu06BWe3bymqbZsd1tuFlvOTkusU6gdw2FKkAobnZbXq9rXi53XHfBb2sh2MqMNgOrcmxWYGUWmRW+v294EAfqmm8/yv7tZys+Q+mVkQdR5GGVLtmSvBhBnoOzFHlJW+ww+z3eNLQ+Z1V7sqZDS8+41GRRhUtrQVJDc971vVaCOHdEy/4dCv3H4L0N2DKCXAjIIVcS6RV14+jEf8pEI/4no92IXXehoY7QYNYP5fMdQRtbYKTuEwKjQoP3dW1YNtc8v7ni81cvKfOcSVlw/+KCe/fO+f3V7/Dee+9xcXFBce8eMlfITKLKIsrNhWAg0KFcb6D6BjcxNItnekBVyrLAS9DWkOdRNtDT70MqhTQC6SWZzELioQMcJZxH+dRHFmXmUjB9YICkGqQLUyu7isY3qGIEGdTAI47Ih3B4G2922EswVoloHKsVh4lLCIADLQwhohxhcgCDdUm+QRkFKlVhUmUgoIHep/0fvBARrX9LhjY+9MYHpaxUmg50NYFMjiwZQZFentBES2rMjuuS/FOoUBEmX8aubu8iB977vpn80EC6mPg4H5WiojPxNlDSlNSB/+z9kDxE5ykiP1II+obJdP9ExLx7R+3TGsR1sPSoaGrmComGZVD+ij0ykv4GON+GJ9JLcAqPxPsKSwdYTOdYNh1+veXqT3/O0XTMg/MjLs4u+ODxEx5/+JibtqX2jvvfekIxW2BGY7LxnPH0iKP5KbfbhlJVfOvJdxgfL8gnI1RV0nWGtm4pnrzP1YsXfPLzXzKuZkyLiqIsyVuDWm3BeWbjMaN7xzz96NeYLEM9eIB1HtMavnz+FaO8YFRWHJ+eoidj5HxOm5c01rPeNtRK0DjH3WaF22xw7S1i3+C6Fts1vPPOe/hyxrPlimo2QeQ5N53m+crym8s9VhdYpeiUxgoV3mOhAy3SB0Qm4NMqjKsXgVfqScZSprcTLyXWx8ZYP4AFMr7vBsNhAiKidwjHFCilUZmOhh+qyRHYjtXdNUZ6rvbQrlsy6TgTGZMyp8gUufRgO4KwYKQFOshkePa8lrFfySGc7J1SG5N+hEALhRagc89cK4z76xvu/qZuQ4A6BMD+0Gw5TygxRaqACI3hMdxECEVrLcZamrrmdrniufC8ePWGqiyYjCoe3Lvg/OyMv/XjH/HuO485Ozvlwf0LRuMR5WiEVkEEwHVdoBdJgc6L3jP0NhffN2ZKAsUxBck6Cm8olaowwQgJSRgo5sLwS6VlpLnG/cU0VfTXnlBwwMseN0mzqUJQk/yiGNboIB1L0a/HBWqxD5Rd4VyUjKU/3teTuv7vFMSnClPvLw/uT0qo+n8c/F6/j0NXK4ZvRLudqi9vnT/geu5Vn/L0gZ1ICZCPv9WDTQfBevzHsM79cg//5vByD569XjTE9Wvhk1pXcsyHCyH6S+iTrQQmDglB8vHDQftmfj+cqyA1+SeQUPTJStp/30DuXajGidhXK0LDsPGernN4b8kzyWrfIXc1q/o3fHF5zavbJWQZjy7OeXx+SnY1QXd7RlWBKjKsd5xfnOFcx+Xr+yxvrtBa8c7D+1STKUU1ZnZ8ijGGpt1z++or9l2NqxtKAWjFJM8oBChrMLVFK02eZTxf3pJJRVkViEwibMd6fUe33+G6jtF4ymQy4ej0jOVux945Vl6QZSMsgsvulrubFdlyw+3NG6wLzBE1P6Zz0Gz3HBUZWijerBpe3u15frfnrg1rpITAqAIvFb4c4YQK3r9t++dneNccJCZGiiniPRQcUv8ZANr04fjcxAlpeELshQCdFShVhpkaE+jqmq6uqe9u6aRn1QBtQybBCUWRQa4loyJHSov0BmdaAmgd6GyhLyxI8SZ2i/Vx0KkxEQhRjDKNzyS5zNgrR9v+J0w0QlAXhsSF2D3QfpQNDdiCoCHvROpdSDzVEAyrLMcBrQeZZXQEnfkaiWwNqjV8uX1K8ewZ/+rXv+JsNmU+HvHg5Iz33nvCt95/l+9+7wdMZ3NmiwUyN8EAK9knOE5C5zuMt0ivgyG3ChQhs6tyqirDC8giou2cCUgjsZE6VQQAYw1N22JtTBCEwEWloXC94RGwnRnQytQS7z1CZkgRnII1PlYH6KsBaaAQQmC7Fm+jOpa1eGtRsWnbSxEz42Rh3PAgC98nPclQOTckTum6UnXbDyanR9EGA3Rg8iNfOA0S8gQKSqiQuKimMzgN78XBvgREdLa3qf6gGoFN/g88mBTg+dCYqAQYE8JF2xtmSBrpxPPqXaNISDU4Gxyu8KHHpY/1473yEXF0Ypg4j46itd7Fex1+IA88j1ZhlnmYxivD+sRpE0YYpAg/9y7dZxv6ZqJRz2RIYZwzKZRFoMiVBqGwxqCUwCvNzlncxlC3S/6P//T/wXe+9S7/1f/0f8SmmrIqtvxv/+n/lcl0xunJGf/Vf/k/oTh5wOP/3v8A9TIMtftnyy1nozHzkeCoGNO6mtpbirMLxrM533v0CCKK3ghBNhmjqxKT5XR5gckrfvg//B+H96Eq+PLzp9x5QfP4AzaNwXSW/est3esdjbjkz3/1MZvtHmslP/7J3+bk9ISXr19RlhlFmbFdbyi0YjaaUt67h8gyPn39Cnld4FBcr1su7xw7NQcdkgbnTJjaS0BORGTgSx36uIJAjsU5T9d1geaXnuA0INKE90AfBDA+NpsiQrKfHLJQEuUdwncR0QxKcMIl5wtKaITOKScKKQgghhxjTcPz5Zb1V28wJiiVzKucWZEzQ6CFR0VFGiFCIzHOQA+SxOfXOfAKQYGnA+EZFxrjwLihI+i329tbWsN+YnQfKkajl76XTIlLrfgh4NZZ3iPMVmiEEBgB13uP2O8RN1s+f3FFkWn+5N//gqP5lNlkzDuPHvDw4X0eP3rId777HebzGYvFnHI6QUmFbxpiCTlI6kZgBJkqExopBLnSzEYj/CQ8a1KJoTIXzyv07rk4/yYCHLFXghSERjvtI0oZzFg05EIMlTwf5JaFGFK0PsGGPjEOmT2hAV7G/dsQhchoI+OhD4LeGDT1tNL0gdhj12cO0c8cBFdv5yLDZ8XBMRKE+FYDRwrA07kfJgExaEsgpIznlsCklCD0vRLx+RiqDOJgR/GPG2haw1GHAHLIVHz/Kz1rwR/sO32qb6w/7BU8TFwSzcYP+2R47kXf7E//uymgHWh06RoPKinx3xKPjz7biST6I8mqKqoyxqGC3vG6brl9ccXnl7fslebb773DP/z9n/7/2PuzJ1uyLL0P++3BhzPGeKecKjNr6K5GV6vYBEiIoElmMBEwyWR6kMlketC/SpEEQRBNggQbBLqru6oy82beOeLGcEaf9t56WHtv97iV3Z0wwxvKqyJvxDl+/LjvYY3f+hbh4pyyMPzZn/1P/E+/+Yp6NuP//n/7vzKrCn7yx7/gt3/9Kw77HS+vb/hotqKq5rSqFNvNOJ588im+7zHO0e2P0i9Ga2brE6rlgnKxoKpq6qrGzJeUZcFnn37KN3/1V7x++R1//uuvOVufcLpacfAFL9/ds3v+jt8+f86mbdkpzec/+0PWZ+ccDj3BHwluYLe5Z76Y8ejyHH1+iSprdvuOw33D4Pb85tUt7zcNt42ms0vhBXIhbWt0P5CCXFbraJf57Lj7ieP4cFFOjIu8TdI6Dg9sM4lHB1wI1NaIHRocQ9MTQkAbi9EV1WKGtUIrbJVnONYcuoart1tc34D3nK9qVvOK1axkVVUUOlDoIDa797jmiItIEaM1VkuzQGkOKogRBqnzqI2mnBl8/Xfrph/uaOTf1MOfCGfK4JHohEgkGoFWAdGKJyCxXx+Fmg8xMuKFatN0A/uuY7c7sCgL3l/fcbfbcnN7x939jpOTU87OLzh/dMp8OWN9ekpRl9jCogobaU+z6yjY3TiBKnjBcqdo0CSsMgoo+ayODefEO5VTPR4fjRMDERMbrzHCVKOsGK8l0CtEaCW9EAdDxUWEG9O4ynlwIXq7xM+EfPG0HKVRX4rojAb3KLwnwjdBupI8+0DYpdRyTjNH5y31+MgCO6oLFSl8feo2nq8xXS8hpuaiE0HuG/Q7Y5VfSkI+jNfxjEwcPt9nWoITIyIkAz45c4kLPY7aBKMMSFMlJdHDkW5QTb6XzGY0LfpPcymCQGOCibC+OLMqOmy/q+8mc5h2zRS5KddzwdE4h286Xrx9h7aaf/3v/h2r5YxyPscBt/cb9oeOb1685OLklOXqlObqPRu/593dLawX+NkMdWzZbXZs7+5YqkBtNMvzS+7vNzRtx2EYqIuS0kit0rbpUX5H2xyp65ry5JT3x443t1uuXl/HbJBlvjph1xx5f3/Li7fXHI4tVTGjaVvarmOz3RDUAl0YDv2AsQXlYhn7GPQcu4F5OUfpgs3+jmYYhEo0ObopOxRGNpfkVJLmI6Q1p3JdEoDS0RhJBAUxxZa3ezYueGCwJINDTU6WwMAkKoxCK0siU9N2hsfgjaNXNa33vN92NMeenT3QLITSd1larPbi8DuPiulrcYqizElmlMpus0S/g5kUAP/++PAISY4yEWvZ4Yg6ajL36d+gBFaaCDRkz6vYAyrZCoHgocfRDJ7+/R2b3YG6Ktns9rx7f8vrt1fcbbacnp7y6NElF48vWSwWnK6WlJHnX1s7uacoF110OkOEj2oNJnY8fiDvyboBIjFHitJMMgf59ySzmY7JqF/CRD+JnAofDM/44QAj5Cc8lKH5ayf7Z9xkk7GeaK88N2nS4gSO3zuVhx/cUzpv8tFstE3GJxnZD790quujy+MfXlteHOXFw3sPk09D8lLU5IzpOKb7+N2xGN/N8OeY+chZOcJkGMPDz8dxViHxYY0XfhAZZ4STqonMHM8WFEReIGF8vnQk+8P7tGYALK1z9EPH1y/fErTmydPHXJzM0UXBEcVus2W4uePVzQ0XpycsqhrKim5/4O3VLXZ9ga+WLPSM5rjjsL0DN2C1pqhKQuvoXcfh0NLahkoZbFCYQ4vWO97vD8zDnCYo3u32vLi54/n1LaGcU56U4DT3h4ar9/c8v7rl2PcMVcX5oUHVDfvjEbwwiJqqoqhn2LqmHRzBd3THI1Vd44Pm2Dm6AVwQ6nKBT0dGzKBiy4KRBmY651NHdmrwPHSmx3On+2S639O8q0B2YFS0Q0IyVEyULbqQVaVAlXOUMoTB0/SeYWjpNw27pmdTWc5XFbPCsKwshVYYJcHVNN8glLmpebNHT4E1YtciiYa/6/jhjoYSAacx0RhLrEUFLuiI9RfWGyW1/ygfsH5iuKkQMf6SzVCEHOUPXjHoAh2g6z2977k/dLy6uuXX335HZf4V63nNcj7n4vScf/Cf/30++9Fn/Mn/4RecX5yyXC2ZLxZoI+mdQSVbWSLxzgmFbYFkOkIsjpbi7ChKfCw3NmAriy0NRSF1JYSAUwPOm4gPlecjyicViAar0BGGiM/0sW5DC9OxQK+U/Ji4SKTLuQgPHwLKgfYaHTtSex8iHj1G3aI1XthCOlN66duQnkd6W6iJh0yGGomQVvln6pz4hNdzkWlFCx4xLfyMd43sVgRouyF6vmMK0GdNELNbMSuSmICSA5ooDMeO4CLkAyHic+XkVBajtY5QlBAduBj58xKd8kHqeEQHjx00HS4qAR+L0BVKudwHQ3mNj42ohNWLTBOpCLHI36FCwEzqhAhSfGriVUMIDM6hjQJtxN+Oz+4jc1YEZonAUj6zRGaVFyQ92ntP43vUXc/meM+bq2/5f/0//x/87Cdf8tMvv+Sb3z7n5Vff8i//xb/kyy++5Je//CWvb295/fY1b6+/w9YlShd0refduze8ev2Sk9mSR+fn/PTLL/nqq+94f3PD/tiwPjllsVxSlAW39xveXV9z2O74+KOP+Kf/1T/h2zcbfvVX3/Ev/+xfcXl5yZMnT/jH//iPOb57zZvnX7M7HAg+sDxbSJTft+y2V1RVYLGo6LoBvSo4P79gs7nHOUfv4OT8gnI243/9zW/onDC9CV5do5Aosw+S4RPuf50ZewhkylCjLS4V2HqH1ml9jnCBMP0dCUoOyHxqpfFO4HgDoCJtbsoMApE+M3VD9qSggTYV1pTUpWVVzLGHI29ffkO3u2c4bvn46QmXJ0s+fXzJoghYLfUaOMm4qUL2rdSEGAg67jEDGOkbpFJn+t8f33fIvKesbdRNSsUxTLuN37HZsv6PMiMgfYqGeIK1Bq2N0FsbhVOBnfNsd0fUZs+Ld9eU9reU1nC2XrFerXjy5BF/8LMf88nHH/EP/8F/ysX5Oav1itXpqTBIKY13Pd57XNfFAmwwJjoiSpjxMn1avtXRUDY2BTaSk5yytckp+f4gR4LLSEYnRB38PTbw5HMBTxgc6DCBiqZxJjs1WdekfZbdm3TbYdS56e2p4Zts3vz+Bw5HKmKOMh41Zn3S/s6XZTTj02uZxIlooKnp2dP1EEa/ZfJ8yUBM/XpGp2pi6OfXVQ6CZYRAcjJjEGrK/iTU+CME/IHhn4y66RNN5Nk0SzTqd3FcZQ9E3oIUbE21iyrdfiRKyb5ryA6J8fJlvuvFBgFm8zneO/q+5S9++w0v371je9jxj/7zP+XZk0eYs3M22z1v3l3zq+cv+Lgb+PTZYxpdcdfDv/7112xVxdMmcPlE8fbVd7x8/hWffvKMk9WSR2dn3LYD282eF6/eUK9WFLMZTiuOhyP73Z5BOS4uL2Gx4s+/+pavf/MN/+b5G9T6MbOnM9rO827T8fzNLS/vDqAVZ8sT+gDHruP6/XtKq6hLy48+fcZiLs3+bm/v8YOj37c8+/gzytmCzmlcMKAKjJXO5qkNQgie0PWUJsYyIkQtr5nsaKT9O9bRjMxPKq/dhzGDMPL3MJYtuK7Lc2y1BiUwbO+EOdQ5yUQoY7CzFeVsyXJxRvf+muPmnrdXryO5S8ezixVnyzlPLtaczAoqayi1hjCQmnOaSMduTSQHMil7kR7O555rf9vxgx2NdPGssLNnEwchGYFZ0EyEBmTGJRnQBKtSCEttUgbCrKS0onEJT13QezgQuD86im7Pi13H6+Z/YL381zz+b/4ZT8/PuTw745d/74+5fHTJ5eNLLp4+QlcFlKJEjAJdSCM/ab2VpnmymaOSUkbuI/V/Cgx4H52AWJPiPhzcEHLkVUE0eFWMPESYVQhEl1EEp5WKDB8CLqjsaCT4lSPCSJRDYdOKxSTF2EnnZoMeey0lrzey3MSVOhoqSjFlpjBhVMKZvSKmHMTpmkRDppGveD1jjGR+9EgXCWTcce5wC8K/noRiroWI6foQCG7AKynAlW7uYoynLEtQ0mAvLSqZI5cLtNOGlHXqMyQu33sIgMuf17qUc53HIA5qVhY+RNaFODhxrWdnC6LRK+/nZ1OjMElqKPXeCBGzIz0UZSx1fLYRMw0KG6PcAR807RB4v93xr//iL9kej/zBz/6ARxdP+IOf3PHjL39KWVa8efeCX/zJz/l8/wn//F80nJ9dcHJyikLHSIxhfXIK2vDN82/5+LPP+ehHn/Pdy5cUZY02ltv7LZt9inuWLgABAABJREFUy2Z35O2bd+yPHeuTf0UzDKxOT1kul/zsZz/jxz/+Mf/9f//P6Z0wifzhH/4hRhuqYsbhcOBw2InBNghN8x/90R8xr2uULXj16i0KePzkI66ubmh7R98NOBcIQYujTqyRycxmKivq3BArCCQghAl0So3z46MTktbp6MzKOgyEGD0Oo4GjNCY13AuifRPkIvHkBy8U1kqlXSoQJ6M1s8UMW5egPuH+ZsbmpuDFzZHXN+/56+/e8/h0yXox4+mjM+Z1TWWVUD5qqd/Qg0PjsDpkw2iIY6DN7x2Nv/GIEf5cbyAvZoN16mAknaQUmfnOuwmxR1pz8aTUSTm1hZCaOIvSAY1gszsHzf2Bq13Dd9e3fP36Lcv5nP/mn/0Lnj15zKNHl/z853/I5aNLHj1+xOXlOXVVUddVhNTFdRVkrflUSxKkDo/Y3NGixICwhdR8hJCKBhFoizgZ02RBFnZpTEZLBibG+AN1ph7+mmoLxImJe0MlvREenDvq/snnp3MVJpNBNPwn5zwsGB8N9RQeFgMsUnQmSuGH9v4HMgPUdAGEdFPJKZg4cZNMxtTRkHP8w+tFSzI7OEnHTsYuGfLyx3R04jfIgOZx0znwNzoOeS6nYwHZ4VOTe5BrJT2iYrG7tBl9cI9RT02H5HcyQAGGbkABs6KkHwb6wTE0HcZo5tWM4BRd7/jNV885Pz+jGxx//J/8kk8+/5y72zvOHj8iWMv1/ZbTJ88oVifcd55Hzz5icXrGoA2DtjhT0mE4esW2d+jlmmW94JPVGaauwFje3rxntzvw7n7Lu/fvWF3d4E3JwQUW54/45Kd/gC/nvHi/4fZui/eBxfljPl+tUBqqukBraA57mt09y/MTLk6WPD4/w4fAYbfHaIvVhvX6hEPTcn/o2O32tF2CQcsgasMkiCGZH0LIQdU0N2Np+GTc8/iOdlVeZmm/Z1NtdEbkagprCplT52LAe4SNB4AIifTB00WYpQuK1dkF8/Up1WLJ/c17NrfXfP1mwwu94auXVzw+W7GaVzw+X7OsCurCUuqQ2w3I84ucFEZSMNrELMh/QEcje+QfHA8HMAn1MDn3d0SNvJr3ZATjJMEVH8eHAB5MMAyIge8dKOexbcO+f0tpNN8Wr3h8csLlySm+Czx9+oRnz57yyXZHvayp1jN0UWCsZT6v0cbIZPBQMIYH/30Y8U/sNMLxLZ2/fSBGB0ZFpkKYzDhRmE2yCxlP6yFeB5LRGaOkYl7jVeotIbUKOiSw2QhTSsIvCWQ/FTr5ucaF/CEkSeSlLOA8bfE1Jj8PFAxiOGs+WA+T99Vkzqf3M66VqByjo5HCK965zP4Ty3lJzRIDpFYVD2ctPcNkCSY9kJLLY6hgMiJTwR+5pRXRsUxy+MMNlB9r+noqBh9FdtZDeaRDfjfPeRxHkfkRRxujF8YITtwoRVUarAloO7DZHXl/d89qfcKsnHG2PuX07JS2bbi5uebxs0vKuuDRo8es1muqqma3PTD0TvqcaIvzgfZ44PLZE8qqYnV6SkDhXOBw7Gi6gcEF2t6x2e/59sUrFos5q5NTnjx5wmKxIITAy5cvqOYVj589pjRFVEyO3W6HDz3z+YzZbEZd15ydneGdY7PdElAURUFdz7i6ueNuu8cNPhsYuVjygyOtc5+heKM1NSr7v/nv6Wv5bx3ynCb5ppXJ9MiK0Vkd44lhNETjLAoRRWSoM5bZci1dnjvH/XGga4/07YHOwUnrUXbGalkwrw21ClSFolaKKogDM0ZL43f+7nD8/pgcuTYHHhqSilEuTA1Rom+SmvpkuZXjCcm6mxgKMZChgEjWoaOuGgK0vYPewaFh13aU1vDixSseX77l4uKMfdPx9Olj0U0fP2O5XHJ6so6NJA2FLSgkxIBOSK+pHPYBojOtjYnrMj1blJF+UjMxfZapbMyfEan00Mgf30vorJB1RDonyrMoB9N2fejOTP9OOi2tZpW/KOum75/W/F7SWyE+3NR4y3MexmtN9Y/68GITgzo9Q76XLHpGnZmvm5XCdACzVE8LZLzhAEQmqt/F6D/8bhiDt+rB++l70gD8zhSOOjVM5jtfQ2yOkUPrA7jWZPw/vMOHcy8kG+iI0tGaqiwx2qCVUKJu9wc2+wPrkxNmsxmnZ6eUSuOGgZvbez7+6CNWJyWPP/qY9ekZ9WzOsWnpncdHh733gUPXUxUVpqhYzhY4pemDp3Xxx3v2TYtXO16+fcu8qlmenvL4o4Hu2HN9v+Hm/T2z+Zyzs3OKweL9wOB72qZBKSgLw2o55zw2bT42Lfv9gdOTM8qqZlbOuD+07A4tfd8RvDiBkmkU1IpKdogWdMw0oOkfOPFTo+thBi/tnyRpkt2V91SYTGjcBDmgO8GfT3eYjus3EB0eADRFUVCUiqVzdN3A8diy3e7ZNx2b3ZHewWreE5SlWVQsKsuqMpRa+jxZFYF0wU3sK8gR7r/j+MGOhjHpVBUHI0WkU9M6FeWvibZ3GuxxZEPchFobTAiYRJ+l4o9PbEJj0F8rDUELltbKRhmCpxsCaoDbtuPd7hr76pr/6a+/oraWWVHy7PEZjy7P+elPv+Tjp8+4vLjgj//4jzg9OWGxXFCUkkZUStPHFvFD5Lz3AUxZYMoSU5QE5YhlqRB6ST37IMMXG3glC1UMGenlAQL5QJsE+EFoi6TzoqRzYhQjRP9XkUnXfaYN0zm6bpRGhQEUWG1ivYnCxcLXabYGGJ2bvPDFGw+ByLhEhFvpnIqWCJ4TKFH2vOM1QsCFIUdYtLYxW/NwnrWSeh2fjXBQOhpqBFIjGYXCh8j0neFh4NwgtI7RuCQEghbq4dGAJG7sEXol+1/crhFjLWNncxROmBSSElfRaFWK3HgrIEVy2dlK7DBaZSymdOMdcMMQoxzyM8R2v6l3AkRMrdYErdFemI+MGnBhvE+jNcYaqnpOXVesFnNOljWzqmC1KDlZzajqJYNXLE9PqB9dcvfuhuurt3z19V9RVpqzi0v+i//jP8L7QNN0fPvdC25v79hsj1zf3jMvSxZlwXevXlHUFeeXj9hsdmwPO95cXdMPA6aacXrxCD84nn/7kv/s7/99Hn1+yZc/+pz/9r/97/iv/3//NcZaPj//nB999gW//fVvuLl+z7fPv2WxKDk/P+Gf/tN/zMnZOYvlikPrePHiBX/+v/2v/H//P/9vnjx6zGHX8vzlK67ev6PvNUoXKG0Zhk7mcdIMTbJTRrD0mes/whhJHX6jUpw4ElNHY9pUTKlxL4z/xDXgFWWMGvW+j9kLNXYh1jLvssg9hEHqlUJBcKIyZsUKfVYxq8/wYc5me8/dzVu+ve8wdw2//e6a1bJkOS/58qNLzpZzztZzLhczUJ7BtegQaVJ9klP8/vgbDmPijlSpwDcpFSQDisrWlJrQx2btlAdXFI9KFp8agzvTDEGi9HZqYsIZK1htrdgTODrYe831yyv0izf867/8DVVpmZUFjy/OOD895UeffcJPvvicx5eP+OlPfsLF+Rnr1ZKyLiExT4XRABG4kMGYAmstxhaxJpHR2Uh1gIpc/5ERRsl6ZAxsjS5Esn2iDvIpkydPPDpzU0M1fS85SJJ8tLEwfzxlZPebfFf6KwX2otEcgty/9IJSWU6HnK1XAk2OH/+w/kC+Xo3TOzH4x2+dfv90RX1gOKU19eEeFCU6fmvUIRlN4BMkKq63qOfzcyf9ky7gk4E4CUpmnf3whhIZTHIW0/NmZzhIp3gfo9oxjIJS0nMmBcfyE+RpHKFt3li89+zalllVMZ/N0EpRlJbZrOKjj54wm5VYA6vVjGEI7O7vODs94en5GVdv3vDu5oavfvNbFvMFF5eX/PznPwdj6IeBb58/Z3N/zzAEBqc4tgNNe8/p6Rl1bSnnc+7u7rjdbHjx9i2u75mvVjzVH9N3Pd+9eMk/+E//lEeXl3z6yWf8z3/2r/jNX/yK3ebAZ599xk9+/CXfPv+K97fv+eblSy4vT7g4P+E/+9Nf8MWPPuOjJ4/5i7/8Fdfvb3nz7povfvyHnJ2ew+D47t2vePP2Hd4HiqKktgXbY4Pz0Ady5kBrM1ZnDMO4vuN+TaFmMZsTy5mKPQIersZxN4YHsdExk6YE1QExyB3fR/YoyRaPsi1lwXXQ9EOL8zCvZ6jLx8zmK5St2dzfc/P+mt3VAaP2PH9zx7I2LGeWz59ecL5ecHmy5GReY1SAMNC7Hpz0/zEJpvx3HD/Y0ZCOqnFIch45YiXzEGU3TGR2jsKPsJtkaopxpeIEREYFncQZqGguK0HFEQi4BF0N0McR1mgGwITAAY/1PbZ3NNeBd7sdr96/53S5ZrlY8Gf/y5/z9MljLs7PuXx0wunJCZdn0rujrCqq+QyNQ7cet2txuw637wmDAa/wXthvZPIH0rZUkGssSBEAM1K4emITP5VgGmkxjgvPpwUVF+TDTNGYARCnZcyMKJ9SZUlpjtEIHyP1+YUkuJKTkIUTI//5xEhTitiXItpVKvHCj5GwMUvzgXBOQtVHAZ2efRJJIS0BNaqfZEhKRC3EjEYci6ByhoMs1BPrWfKwkxFhskGpIk99CIEQnbjgBS6louOcrj+K3tEp0moSZcwQnKis8Wkb5HWenst7l+8zRKNRIGHymjWaqpSI5mw2Y1ZVVFVFXc8oy5JZXVFbjbWaWWXRStM2Lb/61V9zcXrCxekJJ/M1y+WKRb3A6IK+HXj13QsePXnKYrEAPPNFTTUrWZ+sqAvLzFquNzf4w56iLAlBUVfSZMwajTaW1bNnGKUplGa5WKACdH0vEDGlePzoEY8eP+b8/ILn5huU1tR1zUcfPeXRo7OJ42T55tdfcXV9hdIaYwucD7x6+5b3t3dstnu8nmGtxhQJ/kSslxEBJhA1wYzmTGNIBeBhfC3toTRDk0xGei851Smz9EB/x2KgVLsTraMoZxSpfkhDJFdwmSZZxf4oKoAtDAqLChWPLi6oygLvBva7DX7o6fDct3BwHd23VxI9qkt+9ukTlnXJvLKURmNUwCrZE7+v0fibD2mqFh2NzMohQSSVNmdgkt0ImZRD5O8IOUk9FCRCKSf44KOzl6urokE4uQkl3DMhCNmJClIDJH2ADK73HP3Arvcc3A1v7/e8vL7lr7/+jvVizrNHj3j6WHTTR88ec3q65uz8lNPTNWVRUBYWZSF0PV3T0TUDfevwPsI33ZhlTiUakR8kP5v6niUUwsRQfvjGOD5pDBVSxJ7kXJh8MBlQ8XevQtYtxOuo5ETkj0z2ZrzhfK9MjF6m3xnyKz6rtHTFyZfll0b3IuS/VNaT4/1PnI7fHaSoi9KDjPeVTleTa4cJTFOF8XWVnR/FtGlJ6gc1Xi9l6MM4L/Hv8bww+d50zgfXIDxwqBPz4jiG5L9T9ibJx8Ja6tjMbV6VzGc1swj3s9ZSlpbVck5RGIyBQlt87/jtb5/z6PyMy/MzllXN6WrNo/MLhqZlc3OLR3Fyfk5RWIyC+aymMJbVeoVS0Hctx7ahGzpMcyA4x8xolkWBQxG05+TxM0Bq9xbVHOWgMIa2adjtNnzx5Zd8/NHHnJ+f8OqFwSrNoqx4enHBo0fn0h/JGlRh+e7Va+7uNhyOLWVZobXixauXXL1/z+39Bm0rSgyFKcFYYWZyPsLFVZwKAadJcHVSGzt6CnEpGkYnIqSllGdZ9ksgERjlVTZd387nuU0BEZVtcC02SdJJclW0gZALuRWzosDM4NH5BXVRolHc393R9x27QdEfA/vO0bQ3rGY7Thd3fPLkjOW84nRZYVWBicyPDnAftED4vuPfi952FA95dORh0uaJkm3EnWXQURZcedMH8GFqhPmxUCkEVK7jkE95IAUSQeGU7HutpEewAmGZQeBN/dZhNlu+e/WG2haUxrJazPn42TMeP77kR58849mTJ3z28ad8/NEzVqslp2dQas9wbOi3R4Z9h2sGcJrgohILNgpEoe1NKTOlVDY2YDTgA1KkE9RU08UnS46GB6+T06Jih+04WioVn8bxj2MKxGhn7DeRmaSS5R6EWWHktc2CPSQBlBZ2Yg0IPNgkCarikyM4aRomBh6j8PchWdt57tWHAjxMkokpyhzSM8os+yCUjUZ2R6y/iHee0k1JsuqpUiLfs0Iii9kbmjxb/tdLwXumv42bNng/mSt5BiG/TcptIuiVOMNiD8d16hOWNwmLOPxqPEcrk52Mqi4oy4L1cs1yNmM+m1FXdRTmhVD0KiisRitP3w98991LusOR0A88+skjFvMV69UJhSlxg+Pd23ecnJ4xn8+py5KqFuabuiwEUwl0XUc/9Oy2W2bzBWVpqasSFzzGWFbLJaUtqK00rvTDkGsbtNZcXF5yenpKXdcUZUld1ZycnHBxccH5+algzpU0IHvz7i3bzSZDPrrB8fbqmpu7ezabPbYyVLVCZcrNkCFSqXYiZU6TA5/qmR6ut4fOxjgX4zmplkPDKKemBg8qG/ZKPG0JgOQapCBOZ4hVRknQ65BZbKxRhGAgBE5PVhit6JqGoe9p0Tjn6Iae0Dv2hy2VUcwKw3q54mytwFagFYUGwxAzjKPx8vvj4eGj7PmdrE9KMTLqmdw7IZDfy6EPlSXJBK0SaUkzTHaE+BL8WBcSRndlAjSK0c7A4IP0wRgch+6AYo9+e01tX1Aaw8ms5tmTJzy+vORnP/6CZ08e8cnHz/jsk2cCXVzMKauKtu1ojw1d29P3juD12LAtGc9JrsanSQ7H6BckKOC4B7LVQ34csraOOjdlTlJUPl8vj2WUr0nux/Efv2JiOP/OEfVQdDaSbuLBZ0cHT8GkOzYxeDdxbPKNjP0xxnURRmZGpR4Y9VNpkNXH9xj3f+NzTB2w9BXx9dEwzLcdVUIy9hOqf3yErNKTk/HBeaP9BYSpjEiR9PF+hKo2TC6cHi3pqYAxGmsMdVVQliVlUXCyXjKvZ8xmFcvFPPYXE4pvCU7FusrB8/r1W1zXw+A4++ILVssVl+cX4APN7sDu2FDXNYvlkjr2MgNFPauFJKTv6Lo22w9VVTMrC9Z1Ta8HXO9Yrk8wMYNYKHFwrDW4oafrWp49e8Ljxxcsl3OqoqAuK06XKy5Ozzg/ORn3iFa8u7pmtz+glY26JfD26i03N7fcb3aUM/DKgq0IsS7DB0F6JNKFcUwTmmfcVw8y6ajMEzDuu8lqUmkFp9BzXgajDfRgvzKuKVT+jnRJHfWTVkiDzxD3vjGYSnG6XmG16KNj0zEEJf2Ees+x82y3O+aV4aYu0Lbkwimq2ZxZJIcUMfPDgmA/2NFICtoYjXdRSCmJKrpU/KIgNTNL+EnZVFLnkGseVKrDUBAi2a12+EFgRWLsSDTK+zZ7bYYiGqegEzY6uOjJSWRbo9FBs3eBoAyhLFHeoV1gdmh5/te/Rf/VbzhfLqi0oVKas+WMk+WSTz96yp/87KecrdfcbrZsbncwaKEh9EKBqKOECsGI4sAzBIeLSkqnQj6kj4VMumasM4iCIjZygThefqK0fBib32kFZqS3DD5kKkYRkvK60eOiD5E2RSukoj3rvahSVWq2l7jDNEoV46JxIfbUGxezSkY4EHB5HglKnsWPRqB8VVqAktFQGoYQezRPCqG01qSeAn4YogMXcj8MQsBgUcqglEEHh/IBF6kpU++SJFNTStElzvngH0SEE3+49JqOglrnlARukOyTCh4lvg699xgvTgkZuhPIKTY1Po8PgzhLgDFlrjUqKkVhDKUtOF2fspjPuLg4oaxLrDWUylAoLT0fQohdqYVhRRuDLQoUA4nR7P31PXfvt3z27HMuL57w5WdfcnN/y+3dLYfdkX/75/+W+XLBP/kn/xfaruV+e8ev/vIvuXp/w7u3b/mDn/6Uqqr49sULHj1+zOnZOf/lf/mP2O933N7d8vK7F2zbFh0LoOezOb/8T/6U9XqNtZYf//jHOO/4N//m3/DlF1/wRz//OaUt+F/+l3/Jb3/zWz56eklVVcxmMza7HX0/sFis2e4PbHdHvnr+gl/96rdcXd8yX55xdnHG+eUZq9Wa1JNmXEshw11C6NKsxYiS7KcPnYq0r9K/UqzPg2v+bv3QKLuSzEuGpjiTsXN9pM01qoh1NgrVg4Q8ZIcY5SmMw5SO8qRgVT1mVhnu9wfebu/xrYHBU1Ur1osFp+s1/fyUgy2oKAlAERxd2IlSLb7fPPv9AdqUwiVvLc55YRkcfGzeGec9zXXwAp8yGmNM3LoTuN2EvzFnP3WUCxPHV2ktLGH58yLzfHhgAkYHKBadR+U8RENcqUA3BPQAu67l7f1zzF9/w//4r/6cuiyY1xVPHp1zfnrKjz//EV9+8TnzxYLXb694f30vWY3B4bwSXTo1YhI0xkU7M96nSsZ1vKccLJInzmM6+k8BfA7ljUa4GtuTJpM8GUJyOf/QcfudWUsmVXw3TEz8mDkaDegPjHI1qSmMJyTHaBpJfigOVDQCwwP2WhXUJAg0cQyyzoyMXimgxhjrGiPVE1QAI5JgdDflvp0a++Yk4hUf++uQnYcw9QOAsf4wF+VHWyLZU9lRSOOf9HbU3T72wXAhfVeEWUfa0qK0FIWlqipO12tmsxknqzV1XVJYgftppaNjMcLjEsOliY6GwtP0sLnfEQbHj3/0BaenZ1yeX2CM5fbujv/9n/33bPc7zi8v+S/+0X9B0zTc393z9TffsN3cc3t7w+nJmqoqMNawXi1ZLJZcnJ1zf3fP+6sbbjcb+q5n6HuqsmA+n/H55z/i4vyUZ08eoRCG0b5v+dkf/FQCVLbguxdf8/7mltmyout6Dvsj9/cbtDY8fvaYfvDc3G35+vlLfv3Vt1zf3lPPl5ydXXB2ccH69BSlpf/NOE8xa0oYdUqWNeGDdfrBeiRMgmUfOsrTzEjSTfk0MlIlr90wihzGuZfbcCgSrFxsZwjUlcWYBWVVYIxhu9tzfXPDMEh/qnKxZL6oWa0WlOcXsKg42hlt6NHOY7zH/oeGTp2cn1PVCxaLFcErnPP0Q8fQOmngdTwwuB7n++zhyWYQYe6diylFBZHKT1kRzsR0T9qpMnHyk5gYQtzJGQKTqPxSkUrMLvhobHsdU8hBAQYfAq0LMASU99zuj1gUBYpd03C9PXB/bNkeW5bzBU3v+PrtFTdtS+ed1OKpWAwOjDHuqZiNC02NkBz5X+xVHHwuFs/YPdLvMMI50gKJ6+dB9Dbk89LfEvtx44KWgZfxyBgBuaCwN6W7Fq9cnMBu/E6VEEpJWUR55tP3RQWkINMUE1kw1BTKFfLMZEcgzmtiVcpF31m6ygbzzmdhFl07VBidB2VSREGRjIkQxlqVMSQpSjcEF/Gy8bsQ9iHxjX2uzUh1GaOAiHMU53XslwGYxA6WBIyP54iSLIsSayzWWBbLIkZXSlbLJXVVsVrUGGuluM6M3a+lhkcLTV1M0WYhQywW1x6rpNdC2zXcDj1VPWOx6BkGz3a34XBoOO6PKK2oTIVRBQRF2/Ycjg2mKPjo44+oqgpFYGgOHDcb7t/f0LVdLNKGoWsjpMSzXM25uDylbQ8oLRSBi8UM7zxff/01N3d39EMrTn5UqKuyxM4XPHvylL7t2Wz3vHr1ls3+SOsc7rhDbzUY0NpQlhVlWY47x7nM9jkByZGx0Hm/TA2lcY/4GHlWCml+GXcMk8LyBLPzwYkkUcQ+K3F/5+I7nRHrsjBTY0miIQO+j45t3KdaacqqYr1eo4sKZy2ul/16ulywWsxZrxYsZ8JERanocDjlpFEgsRnd74/vPVan58zmcxbLFSAZqb7t6dqOoR8kmzQMuKHHuSEGPqQ7OxNdggIVC/LTBE/z8A+OaPCp3Hl0DMj4fL1Jdj++/6E5kbMgQcVGs4Gh6dl3A/eHls2hYXl1y/XdltfXdywWC/bHhldvr9kfO3rncEEaTD5Y/9lASUZPEokqy9TpE6ZnyneX5U2YXmLy/Iz9gia1aA+hOWnPMHEAksH/wXqe6LeQw77pHDW9je+ZjukNfq9V98FzpGy7yr1UHlj3avqpUbYnh2Hi0eXA5+TpR2N/+lyTf8Q2SGxj0Y7IzfoeuG0fPKP8jFMTJverPvg9yrZIVpLsLGFe15QxY14UBfPZjKospS5wuaQqS+bzGYW1WK0orB37ZKXMmRrr6FIBMkBZVELL76FtWwpjoCiYzRfM6hpjDPf393RuoGkbjNasViuM1gz9wHazYTGrqMpCsuqFJQRPczzSNg1d19K3HX3f0Xc9buhIELH1asnjx5dYq+n7jvv7O07XJ/R9z5s3r3n16hXd0PLFjz+T4I02PLq8pKxqPvnkE7bbHZvtluubW3bHhrYfGA5HtN0SjMEUJWVVUhRFHnoX+2hkdMY4gQ/W0Dj5E3uKh+d9uPYeQqfCw+n+3iMF9yfQvrQOEhtdtI/TejNaUZUl65M1tixAKfrYtPhktWA5n3GymrNYzrCFljrmoMVZ0cCkuejfdvxgR+Pi6UecnT3m8ZNPCUEz9D2H3R27zZ7mcODm/RVNs6XtBvp+iDhRRTCK1FHQR1ClVgGsRllN8EM2gHO0BYNkARRGGcmcRLiCGAMeH2lxU/V/KgIOIURucun3Ic3ppJC3d05oZ7Vi3zuM0lil2R979LHn7XbPX79+K7AdVdK4gcbF5mkKKUSORcweabYk8K/USD4azkEhBddRmKghT2xyJTKeNS2QVBgOyMPq3FhPkZRXTCuHSG8bXNzssR6AJMT0RN6IIaSme8B7UBqV6VzlvASBU0qK13EBbYp0VVLXdB03VfAeHTMfSksPg6ADRttcWhHvWDzqoONcGLSR+/IukQkgfUhiLYqPUDoTKWQVPhYgDXjlpb9HiIwPcU4IimHwcd3Y2EsybjYvhdu5hiogmH8CRgehulQKM0k/u8mYh5huN9rkeVLK0Qcfe3CIUSqZCIFGzeua+WzJfDbj4lwKvOd1RV0WMZoEKkKMZmVJiL08lBHiTZsigipR5Mo3m6Kg0FAbA8qx3W+4u7vnF7/4JWutGYYYVQqeq7fXLBcLiqKgtDVGlwwucLfZYquSP/nlH7O923LY7tm8v+L67TVvX70mFDVBabxStIND9R2da1ifLPjkk6dstu+Zz+acrNbMZyVXV+/5sz/7M/rQsljNpXGQhzA4LhcLTs/O+cOf/xGv313x9s0Vz5+/4uB6BgVts8fhaPqWsihYrlbUs5rey3g457FojBJ5gI9Op05uhprYVA+dDZ94vnU0CCMMSgHBhdx/Q2s5tw8D1SRFnjD+AtOIPVSU8A2p4MTRCD4SElg5p3cR167xXoEymMKwPimoF456viQghYSXZ+fM5xXzeYX24hDjB7qhheAYVB3r0n7vaPxNx/njp5ydn/Pk6VOKosJ7T3No2NxvOO4P3N3e0BwOtE1D0xxE8SuFc73IhQRLUypmsSbmca6rA5n7EaIlhcmSmX4IkYAU4AAi1fc005G+QeGjUeCD8OIbFR1j7wl9z9X9Fh0Cv3n+ir/66jvmsxlFUXJ/OLI9HOm8ir1WVLyXh0ZGMn8zbFRFLHd0nFP0m3xXU/cAySpPLKcR8aFiNmB6dhL6UW7G90codbpUdPWnRtXEOVHZsZiu+akXEMjZBEZDjO85++ExniP3MsK1PvyG8UQfn2cSsEte1uS6o4MxdarGTAthHMs8PzkIlgKRU+t08vtkeLP/FcZVRHqWiQOU7sNHVp1UT2itpbSG5XzOcjFnNqs5PTmJdMs1dVVhjBZEScyymAQvi9l5YT6Tc2TF+Fx0XtUzrAK0Zn84EnygKwvOzs+pZ9Kv4t31FTd3t9y8f8/Z6RmrxYLCWrx3bO43nJ1ITe3Z6YkEtLuOu9sbtps9h/2erpXAQd/1dMER3WzOTk/4+KNngKJtjzTHAxfnZxyOPf/uL/6C129fYq2mqv9LiqLC2ILPPvuMxWLFp5/+iK+/+Y5Xr1/z9uqGfdPS+0BzbPAoumGgqiuWYUVVlUJWFLxkyjORTngwbd/ncIzbJen2uA4mciXLkqmzT4ICJ5tquvLG4IDIp2izxJphHyb7H7H/gg+khrZlaTk7PWGxXDKbL4TMRmkeP7pkMZ+xmNcE1xHcwDB0KKw08rPJNvm7jx/saJw++pjHTz7m8x/9lNXJGYU1WANDL6w77XHP4BqGoeX27pbjsWG323N7e8fhcOD+9p72eBBv9NjQM9DHngYSFY5WdTJOlYBbgrZSIzB4lDYowFolacAozBJbg0MKSKXxl7C2jAItCvb475CDGGPRmvKgOzkr+CPBiIPifEyVuVYMKMArR3KGcjQpWYJIJkGlLjgmyO9Bxb4hHnAjRVqIMBBFFsox/C/RfU+EiajovLi8AD0Jf+zzokpRKxVMWs5ZAYiMjqMQorIMch/ZrlVx6aYocBgN6VG8xqIl35H6wmsjXT0SJZ6Mqx+jIW7ITCKyt4TO0ZHqQFJhOZTW5ntPRWwOUNphVCA4jcLFzekJTrIghYCPCL7HuRhZVh4VPILAHI/oVmGUFWchjNs2CY40WypIXZCQASUx7nA4huBYzWqqqmS1mLOcz6mqksVsSRXrg+ZlId3mjaKIgslocl2CVQptBRrYRccp3asPgd45WdPe07tAZaWvyr/9y19hrcEYRe8bynnJFz/5HF1otrstV++v2ey3lGXJz3/+h5ydn3Fz9579YY++VQxxn3jv+Pbr53jvOT9Zc7090AwDx76nLg1lJdGtLz7/jIuzNd988xU3N+/57Vd/xdff/JbjseXY7ChmBVVdsT49YbVecbpe81/9k38qewbFX/yz/4GvvvmOputpXU8fG1Udm5auHxiCZ71e0zjHernCWksRU9U+Rp+Tsy6N/CTLNEZ9xlqNkZox/u2RBpcqMkglTLK1DBEyV1gTS28S5C9kNqFx1STRrvEpmqztyJSHOBlKGWxtsVbofNfBksr4vJfgQ2EsWksH1r7vcV76j9iyQJsSZz1Dyob+/vje4+knP+Lx06d89vnnrNanWCtQy6HrccNA37Z0bUvfdey39xyPe/bbLZv7O47HI5v7e3b7HW3b0nYtzjuBXrphIm911k1GmcglH6GiYbQLBRYbJrIrJLEbBasa+z9A1kcBjcvGs8C6tC1RRQ0h0HnPVTOguz1aHem9Z/DSYDKCewTKGY/s1kRLNN0LESqUIWITvyfrCqZy/vuM9uQ8qA9fzrIRyMGZODCjUfzgm8bvH12Lsdrlw+946KzlL31wxoNnCPluHjzQaKCr5LfkU0ZjMTmLYbz/eF1BzKo8ziPKYvL8+WKj7pULKJIzlmBT5N+jQTp9hsmzJcclrRTvXXZAJgjgKF9E6i4Wc6qqYLmYSda0KFjN51RlQWkLqqrEGAmOpci8ck4cDqWxOlF8I/Wj0+EJnsENONfjg6dpWuqyYFaVvHl7JdcMnpOTNfWs5u/98R9R/fa33N7d8u7ta7b3d9RFxacff8RqMQfv8a5nGIQifb8/0HUtr168zFn2w35PCEEyLrZkNqspS8vl5TlaB25ubrm6vubVq9e0bUNzbLi6esNqueTy0QUfffQJ8/mM4OHnf/hzkc3rU/6b/+6f89uvn3O72XPoB7oY2e8Pe3bHI0PwnKzXdP1jVqslRaSmDl5YLHNSY7KGJj5intsHy1rxwGlO9nBalKnJsei1MGZbVWpKmsoa0nqMayvajcHHgGm+ZEApgzGasiox1mKLMpNgDM7nJqJ1VWXbse9TokBqeIKGXkE79Hg38HcdP9jRKKoy/hTMoiFVFgXBRfyf6/B+wPue9ekFzbFhvz9wfnbH8dhwf7+lbY4MXcdxt6N1Ha3r6JoGN/T0XUvXdbjB0fdDngmp5Yg04tK8ImcQUpSeyR7OhVIpS0KKSikkmi6zmXv+hgSHSWZnMlLif1SqRSB/X3ZcQsJ7RkGumBg5fuJrxqJx0kqUrEFisEogKkETJfzpKEilQ3VqThTGn+RFx9dzik6Nr5GdBsbVnr41jdXkvuMFkreRvBGYRHTGCNLkPZXucYRQjd+T5Hm6hkL5iMFVscg2eIJ35H0U0saZfl965JCjYykCF1LmIjusEwE+LayKn82d1KdDCmOjwclIpfGTr/CjcxwLx42G2axmMZtxul6zmNeSfp7Ncu1FaW1kqiBCohiFgxqNYTVRtlPjJTWLS+vSeU/vFPfbHWVhmc1Kmq6hrAo++uQZ3dAyu6tQOtAc9+x2Gz795GNWqwVPnz7hfnNHWZUM/YAxhrqu0VpT1xXL5ZKbQ4NyiIKaVywXM7SCqixZLpecnZ6x2205HvesV6egwFjFfD5jPp/R9R2H45HCGGb1Ah8CQ9/z/uaG9+9vGCIcMWlGIR0Y2B+PKGOo7u+xxjKrZSyTcE6R2LRb05pOczStvcgYZrI8x0+UuEAoQnRWolOt0uJIXAMxZJBy3ZPIa1Ah9y4gOfU6dZS2aGNR1mCspSorcUpiEEDYgmIvnRjB9t7HInjoh8g0N/QRkvqwxuT3x3jYoqQoS4qqpprN5XdbRt0UcMMQyQwGjodzuuZIs9+x2dzTHBu22w376GgcmyNd39P3HcfmKI5KLwXYbnAZbgnkiOHDYkg1ERyjWRw/EOW8zzI/rSaPIvf2iecZpVA6hkeUJidQBBArHeMffEOY/BMV1ijEHtzH6FyoB7f88H4fvibbNWVWJ29OPzw1/LMhHybvqYfvp79D3qrfd9EP7iwq4UTY8eD877uv6TiMRrpSk+cIig+/M+maUUOTdVn6PR9TdsQHb0z0dX5pmukIv3PONPf14SOpfGPpbx0j2Onl6MBEw1dpzayumM9rTtZLVrMZVVGwrOsYLDYCjdJ6EkyRe9LR0M11GSFVUMb79yFn3xJhjI/sgINzbHZ7bGyQ3HU988Wcp0+fsN/vKCsx0g/7PZv2jkePLlFnpzx7+oSrq3dx/DXGWMqiZDabUZUVRhnarhPIktEUpThKRVkwX8wY3Iq2bdhshUWx71uGoaOwhroqKcuSrm1RBLrWMKtrrC3oh4Gbmztubu/pBocw1Ef4vfc4HLv9HqUUVV1hrJEsUFWN7FMJMvk9S/d3V1faC5P1BA9kyRgsmKzXhNTMayxaQJO61+SYiI+sgNRUOdLxaosxFluWGCM02ak+uIg1iQm54nOtq9ihwQe6VP/lB4a+i3Wtf/vxgx0NWyiU6umHPT70OGcZQkx0KktRV4AsytP1E/BO+gvEKHs3DNHLkqZeh+bAoTly/e4du+2G+9tr3l1dsdvvYyt46SrsXJcHzRGjiyhMiFh5H3s1hCAZiBAYeifGXNwMKoLffTJqVCB4gUeI02KyQyG0lSE2ZomGdKwZ8T59L8JzPjhUSrsbLRFrpSPcI3WK1hhd430yaluUNhHao/N3JAPKKI13UlCsdcRYeoePcDLJBshEa23ywhaYlRr7QISJ0a3CSE2bFmBcgyoWhCmjcVFgqCS1lBJEugqSRYhRkkRwpeL4y6kJRZ46SKZMz7iGlI7Gk1O59sarAL6H4IS6LRlyRpSs0kaUaxDIXUoC47UwbumANwj23ujYMTM6UXFTOi013D6AH1xU1iMFsRsEGocCVWhxTeLG0kphdTIyITj5TqU8feixWlPZgvOTU9arNZfn59hCmr5XxlCisGihjdVSdxGiwTsEaaakVcAYixsGhmEAK86XkBAk12NUpB4ER+kDfeeoKsmW3G/umC9rfvn3f8Hlk1Nurt9z3O15+fIlr1685MvPP2E+X/AP/v5/yqvXL2nblmZ35PTkhJPlmsunTzk9WfP06SO+fnPNoBSPz8+4WJcs5zVWKbogMLMvP/8xXdfz26+/5uNPP6Xreq5vrnn67BGnp6dcXb2RaFU54/LRJaUtMMby6tVr3rx9iwslwWqUMaiArHk30DQwDJ626QjOc7Ja8ejyUlgzlGZIXb2JMKogmSyJYuvsaHjvH1BM6/i7DpJaFtEQa4mCpywKfBgY/IAa0XEMkd5Z/G0FzqOVJSDKBydZVR17oBhjmc/nFEVFYQt0WeaLtW2XO6aHIIXKISBZFudyBk5pzX5/oO179t2Bw3FP27Y/VFT/R3cIW81A23Z0/QDaCKQzssDo0mIrwZSvz84wSlMaTds0uDj2omsGjs2R/f7A/rDn+vqKw2HPdrvlzavXHPY7dtsdbdPQ973MYxIsE2f1Q9azMYgThUiig0zRKSZGSGTbcxEySCRF0THDm23SGOxS04w0o0OdaxmZOOZqYiT+jpETZcz3GNEp5gTEIFJyriYGfHqG7OSMhs/oWIz3M54zOj1/25EN82kAK/4rV/fTEx86HznwMD7rFMeeDbzJvaex/p1alzg2D2rFQnw2H88by3Ym7mQgOZBhHKj8niArJvc3efAMfSMVcIuO0irqlTiO3kc5EkPZxhphNFyvWK0WXJ6dsqgqSmOojBifRokelAzdWH+oVKxRi7qUOEaJWMWHEGtgQ4QYixWslcBM267nfXuDNZq6sDRdi7GGH3/2JfPFjLv7W7q+46vffMVXv/6KX/7yT1itLqirkmNzoO1avA/UdU1ZVvzBH/yM0pbMqpr/8c/+jO1uh3OOxXzOcrlkPp+jFZSlZL+dl7rhqqwpCsuzJ4+ib+p5/vw5ZWEpioKf/uQn9P2Rq+sbXrx6zdura5wupEeOiWtNSa3hbn+g63txdLxnvVpRPXokgSUUXds98B1ToEtlZyCu1xCz7smJy47+6GxmVEhi544BKq1jRWw2/NOHo7MTErFF7LkW59caizaGqqywRYktCqwtc5Ch63t8cALXjs5VFx06N0h5Az4wDANNlH/7456+bSMa4G8/frCj8d2vv2F7vWF/d2D/UcNiuWK1PqWoKoy1FK6MXrEYUqJ4hW7T4wU+pBQmFCzWhnq15MQ7zs7PGfqeoWs4HPZ0/UDbdDTHA23Tst9thdKv7djc39N1LW2EaQxDL3AS57LnlY7Mk6GnwkmDMhgthadpXn3uCzIVzuORCr4kixIFdEh5CnCRdSkoMT9G5oFAcB4X9kAJGIEzeQiqJ0ykq1EmRk19jlCM+bcY9Y944OjSZuEjkdl4LT+9+/S6EgMZJhkTMkYPAs71iIjTkJqFBbJTM3YzmQjyJITiIvROaCCVSfcoTkdWCT4q5ogBzEG8OI5Gy/2NtZjRMUkUWbF4XARvrOMIHh0zd+JYRqczpTy0QrlAisXYiONSXiBdBAFA6djIy2goyiKzcBS2YFZVQsMXoDt27PfiKA99B17jnOXmdkM/DBSl4nQ1o9AFFk2h5UcZnQ0IFVPRJmKYPUQjE9BS2zNmbeJ6Q0XH0sQ1JsLGDR7o2akDd7cblvMFoR/ojw377Y7Xr15x9e4d9/f3vHz5krPzC84uL3j95g13d3ecnZ3x/Pm3EALr5SlFVdP2jh9/8TnHpqHrW66vrtkWli9/9BMGL0GDY9dx+fgJ/6f/8z/mZHmKGwZO5nNud/cMTuZ5VtWcnJwyq2qc82x3+9jg2BKUBZVowV0Wji726gjec319TXM4oPCslguJHuXsIzmNnx2KEGLPjZB/FMS+GSFmvcYeNQniAtIZPSgpcEvLzXsp8pax9rJ3I62hNlbWxrLGaIvVFm2NRNlsKfcZa4ayKeQjI1n0nL0PHPYH+ralbRqJmnuH84798Ug/9PTDQD/0v8Oa9ftjPF5981uO23u6w4GnH3/CYrlifXIqOGxj0MbIGtEaU0hwph/AEZ1+RWT2K5jZinK2Yu0Gzi4e0/dCmdn9vSN939McjxwPR9q25XDY0xyPNMcj+92erms5xlqQwQ3iLAwyn5kxKBue6Z8PDFYfyDJ+asf6SV422yNTaFJyCBKcJxq2EwaklJXzKFI/IBX0GFjK11FZx8hrE+M76oBpRiP9NnWnRt31wUkfnJv+eKjvpu9GRymD2ydaMz3DB8Z8djImGYLkaIlhpxlpdLPL9fD5GY1oT2wK+8CpmkxOfozwIJCXnyve25htHfW1zjaHj7DQuEYm462jgVmUhXSQj0ZyYQvqupKCa6BrG/aHPU1z5H5zT/Cevu/Z7bYQHJW1mACqrCiNwHQT/X3SJzxYo/G+GR1P/+G7CumPlOCAIfXugK7vIBgoC47HI/v9nrY9st9tuLu95eb2hpv372mbI7/97W9Zn6yp6hnGWkLf8fy7F9zd3XM8HFgtVjy+eMTp+oSnT5+y2G7Z7gQSbKxkOdquo+sGtDacnJzw+ec/4snjp7hh4O2LV2x2O3zw1GUhvWmqisViyW5/4G6zkUbN1qJNJQGIaf1WfP5+GNju9uh3V+z3e0J0OGZ1HdcpHxwq/j8a8CFMFn/IkQFxdtMKT+MekoGU/066aXAumjqTQIbSGC2ZImvlGRNdsdYGrTRFUUqWVOkMRQ6kbFQQXewl6Hc8HOjaViClbcswDHmcB+doW3E43H9I6NTd1TVD0+G6AQZEmJ+dUs3m2LKkrOYUtsBYy6zQ8UGrkYFDezQmRmdKTCSWqupajOvg6ftOHtgFDocD7bFht93SNJLSvrm5oTkeOez27A73dH3H0Pc5utS2TcwKB/wQDX43TVOr2FlaouFjeikJ5WkaPG12lXdZNq4VMWoeF6CA+MdIFYFUHg5BIEGpgVzk9pZUzFgQN4UaiRAMkyiLGt1kQl6MyZD6PmiU6IkPCubSuia/mBc4KhaIZ2fCx/cmTE0pUzD9DkZnQww5DXrirOX+KMToX/Qc4q6SnhVjt+8MHYqOQn6k5Ghk9o+xwE0nYgAgNT9Kail9Vikx0XWsdVGKiEkF5xW2ENxiURjKShg46npGVRbMqhmFFUej2TfS1R3H8agJQSANx6ZBa9jtK2alkS7k2oqjkwqDkc2skxMU0siGjIvMDuR0HSYFq0wKNYmDEk8T49/RtR1926F8oD007DZb7u/vabsOYw27/Z6yqlmuV9mwb7uOu9t7uqZj8ZMT0BqlLednp1JbdX/LNogj5AkMbqDterquo6xnfLRaU6qC4B2rWYV6rdgddrL+g6TwtRJ+7sOhEdsgKjgfM2jZqUJFzHGgp2e/3+HdwHxWCle7UZTFjLSKxQ9TPIwaj8d0L4dseHgyux0jFtw7T9Aeb8Z1J8Hi2BEeg9IWjWQjjTXYUrq4F8ZitEXHbs5GW7wXI8UNQ96rgxOh7JxEz93g2O8kQt42Dc3xIBkP52i6liFmObyPvRx+f3zvcf/+Gj8MEd/tWCxX7M+2VPVMDLNSmGKKQnrFaG1RWlTfaNvKmhQogbxWzRYEn+BSPhtu4mh0HA5SnLrf79nc39M0R/a7Lfv9nr7v6ftB+tX0QsUphkvs1hwEJgejeJO9Pxr5In9l3Xo1nf8s7MXQmPzNeMWJ1kt03tFoT3shRngzLDfri7S/Ji5ECHEfTB2MqR4Yv/mhw/HQ01APzkr3M76fzh2v+eGzTb9vhMeO10/OxvQ1srNlInw1+VY5o88HR4hIienXJJ2cNHAY7170Y/p3NM5zTxFEl2ZYZ7qnyfsC45RrmpipSBFpYzR1VQlUqCxzj4tZXVNYK7K8KdFanJf9fofzTgzG5ohWin11oLIFGs2srPA6dXmJTzClbmfiTIbAxH1jDPdl40WCZwoJaEbF6z14ia/R9R1d1zEMA8fjkd1uy/v372nbhqIsuL27xYfA+aWlrCp67zg0Ddfvb7i/v+ezjwoG79DGsFouZVqCz3Cgpmk4Ng1N2wBQVhWnp6c8fvKY4BzaOeq7irbrI8GMl0g9khE9Hht5okgcJIGm2AsrjOPgXaD3HfvdDu9cHH8JXldFlYYj7+280GC0I7NRM3Xk447LTve4EJP+yAHWEMc2Qi1VsmmVwdpSCv6LkrIssMZgbWxNrDTGFFneuGEQ6BshOi4DzrXCztcP7PZ7uqalaRqa5jjKs5g163uB9fofEAT7wY7G7Zvn3F9Z3nxb8Ff/5n8WxiUVKOs5ZVVzcvpIOhQvFjx6dkE1m1PPVswXa8qqZj5bUFZzrCkxuozRQ+mbkagrg5JMgy0KlrZiuYTHjz+l9wO96yKURIyCIQz0w8DhcGCzEeF+c3NN23R0Tcv9/S1dI9ja3okH1jUtIYYsfehIK0H6WEj2ATUqnTzVLhZfeyXc6j4ukFQ84iPzSCxGV0oyO97LJPoEtwoOrYbk10iUOxrGLoS4EBSJiSILL68gUm1Gq3oU0zFj4WPvDKUjW4QSxqZE9yvfI1Fzm3p9pEiVCmjt03DgcaJ8EnVw9OxVUpDBZeiTCgEdNCYoesSwdEOQlB5y71mgOqnNSJ28AyLogx6bKiVGBBUpXrW2SHE2ETY3GqZZmahRUQ4hwZ6gwEjtQxgolDBGKU3ufLparijLAlOXzGoR3PNaCuNMzM5J0XZcH96zrhTzGnarkq655zgMtMHRdgLzG4aOofWsl0v0RYWrDIMqcEGBDgIfi2xXSfmrEOhzWWgEAUwEXBLuyWFJTBVKyQ7WBlFMaAyaEsvbl6/59V/+it47Lh9d8vOf/5zm2LLdbjg0R/70T/+Uoij55sVLtru/5Obde3791df87Gc/44uf/IyubWHocWXFk5//PZQxfPX8W66urri/v+fs7Iy6mjGbGT7++DE6BO6vX1P/5Ce0Q8/V23dcv7vixTff8Ytf/IJjN/Du6oamG3BBobVlGDraQXpUaFSc78SoFgQ+1DS4iLMdhlM++mgBRFKFmCUi74Opc5Fei52d1ajIR0MscU0HvJNC9B6HViXiMJcx5WyFctfWlLaitKVEyQu5DxXrvKRs2zNELP8wSPAkRTG3uzva9sjhuGW3PdAcRYh7Jz0fnOvG+440vFbpmBf8u7nK/2M9Nlevub9+y4uvfwMm9twxlrKqKcuSk9NTlqsVy8WSk9M1s/mS+fqE5XJNWdbM5nPKssLaAm1NDjDl5pDaRLptw3xRU89XSfgK+02M6oWIV2+7lr7r2e+PAhM+7Lm/vaNpjrTNkd12K9mP45GuT3C6CJMM0Pe9BMiCh8jKKLI/4iimWKbkPij1wKjXaY3HNa+VKPv00SmuP3U9T3JUmKkiaUGQTudinEyMUpWCA/J9k10HZDTZg3em7z8wzNPfhIwemJ45dQNGeJEE8Mh3Kvs4NSlTMDalVcSsgMZYgR+pKN9tpBcfe0CFnM3sh4Gm6+kHRzd4vJOeYYQP7yreU3IKk+6G0YmYBDElbiHS30gMA1BYU0hPpaJgMZ9RlqnQOWUvpMGdMEJFJ0THIF0IdLOSstDUVcHhuOfYHDk2DbvtTgK00XBcL1ex/q2Csoj2QjJKxvseHVXynkgMRjmmqsb3ApKx18bkImOlYBgcx0PD4XBgGHrubm958+oVL16+4MmTp/z4xz/h7u6e3WHPajjh6ccf4UJgu91zfXOHv98wWy6wRYHzjtlshjGG+XzOMUbVX758HTMmDWena4wxEZFgMUXBxfk5q9WKru94//6Gq+v3bLc7Ts/OOTYdu91OTAml6LuWYfA4L9kZMdgiyiBuv/bY4Poe5R24gaHrefb0aYSfqQiPlcBWovwPWsfL+DzWIVLiE/dL7G6D12mchd7dJyc3ZvSDMhRFiTEFVT3HmgJjCsqyyut5rLEh1/+5IPqpHxxN22U783jc0XUNu+0dh8Oetmk4HI6CSIqsmiHakqnvmNJGqNfV3x0E+8GOhgmA94TIRR6iAm+HgeF4wDUt26qiqCqu31XYosKWM0xZYW1JVc+ZzRZRsEtDlrKyLJcLrJVeA8ZKkcqsXpAK4xwIu4aPjAgR+qIpKKxnoUtsUbNcnbBerxl6wbkfDnv6rqdtWtpecGTH/YGulehSPxzpuz6e0+DcQB/aaQwnR8ZTfwQMhMRGg87N2tJ9CXZ1YMI5EoUMGSIkQjymtJmmbtNkifEja29MxalgSII44f10jDSMQTCVN0NSSCptkElE1JFYd+I9KslfiKzx8XGlDiHDybxwcCslzkIAgV55iW8MSupbROjoEaLlXdZuCb4k7yUvnkgxqHLkRAqw4hiG2BtFRVxieowwxJiARPfl+bVAo2IWoSwNRWGoS4n6lNZQ1jGdqDWzSqAVyopTZrSmshoTcbDGJLYNofMLOjAAi7lk7C4uL7nfbnCbDQOBwQ/sjg3F/Yaud9TVjFV0uExhI3tRiI3AYtwoFe47HyNriiHC74J3GBUjr8SIkwoyp4xGtfeerh1om5bDseH+sEdZw3yxpO06ympGUVW8fPWOoix5/OQp1+9vI0WhoSgLZrOap08f0buWX/3VX3CxXHJ5ccHl+Tk323vud1uef/eS/W7L0Pd88cUXaGVxg+f169cYAtr1lAsx2HZlzbv9FW/fvuMXv/wlaC91Wkrmq/cdKnisCnFLi1C2SuqcCmOw2lBYw3q+YFZWFMbi3RCjThAY4hoDdGzmqUcHLe/AQIReREEZ135ibAkEqfHRBYWpKGwVC+bKWNgtRYdWlWhdoBPrELEsVwnsyrkBHx2Mruvpup79bhvhTwPb3T1d1zD0e9p2EIdk8BlnLzVNIVIPqqz8sxz6/fG9h9BbK4J3hDCIy94pfHegN5ah2bG9raSD/awWjHJVU1YzbJF005yiqpjNF1RVTVXVLFcriQgaQ1EUWGup61mW70obnJNQmUPgCBiwlUEXHm1nlPWcZdexXp8xDFI8KTUeHW3bZEjC8XiUIFnX0bRt7BPQ0Rz2cV0N5IzDJLOgEGhUCsIksa6zfBXjWxMwCgwBqwJWSwClKKwY29E4VEogZj46uC7A7tjRDY4hGis+SEQbJpH+SXQ2EJP7IbkP8a303w+yjyqMZ02z5aNTMTk3vxdirZwYgybqYRszFKkbcoIdCZzEUpY1LmaTejfI9ymPSrUHqSmt9xBrMA0eq8AllZSfM4wPN3Gccol+dOJSZkLuW/4uC4u1RhrTRTlcldHRsDYyQUlAzMRCbRt1k9HSm2dqP4QAqrSwXFCWlv1hx/1W47yjH0TWHP2Ru/sNbnDUVYXzSwKStdeoiNB+6Pil2U3PloJ4Y2ZHnsuPXQyFJKWP5xEYBkfbSd8LFcTps8awnC+Y1TNsWeBCoO06Nrud1PtGBEBZ1yxWK2xRstvveX44cHlxyXw+xwM3tzdsNlvevbuiOR5xfuDJ48fSWNp7rq/fowMY5yOJUc3N+1v6tme/2zP0gwR6fDToBwcutYhQeR1mAiIlZC4pQ7qY1dRlSVkYQoQAC3Il6vDsgqVgaHgwZ2MocdxL8rvP4xdI2VaT+38YW0bnwlIUVdRJ8n7O8AchjUAhkFwnDkbXCQRqtz9ERFDHbr+h7xraZp8DJ33s9TRCkcUGU7m/msqZlr/r+OGORrqoc7kIiBCLj5SmOx4lwqg1OngwBmVKMWC1oSxnzBdLqmrG6vSC5WLGYjHj0eUjirLClhVVNaMsa/xKPiNCb8jwgdSdPBkaSgntZlFUhOA5Xa9jrUaIEVApEGw7Edz73Z7j/kBzFD715tBw2B/Z6zv6vom9IGRAU0ZCsJnRUFZxAUwcgCT5Eu2Y94OgqD5osSWqQTGtdhidiGR4ehKNYpLHU2hVErI+Tq6OiiCkSFC+H5Vs9EgIFfIGgNG4TQZXiltkruVB+mFkxy7OtURZ4we9z+f7fJ9SBK7VeC1iV0rRez51IojfGXGycX+lVHSMA8R7kmt5AtqPtLxMqN50hLtoQvTko9Mws5SlZb1aUMVU4nxRx06mQjOr0qaOtR2FJlPPJsM/oLEmQS08M2Mpy5LzszO8GzhstzjlBcLUd9xvd/SDY7VcZXrAmdEZeh2SccqYKg159Ih0vz42mhvd1uRlpehd8DIG3nt61+dCtW1zxBQly9UaczhQloLL3O4P1E46ll9d3xDwnF+cU5Uli8Wc8/MztvstXz9/xaNf/JLlasliPuPuuOPYtry7fs/QtRitWK/WeBfY3m+5unqHAU7mM2arBVVpmVczhn5gs9mgbQl9dDSQSI7zHYpYjJgMpyBZp8IYqqLMc3ayXDCvxFn0zsl8KxUdDYmu6di7JpczpfUdxnFLAjN1MpVoTgTrRSGtbUlZVFhTUJYzrBVKYmuFupmQIp/kPSsQRhchnC46fR3HpuH+7oa26zi0HbvdlqFvUf4YzRHZFzo1G03rwMcNwcRB+tvF83/Uh8psdhJ5TM6a6yUa3x13MbwtHb1jqBtlCpS2FGUtuqmesTo5ZbFYsVguubi4FAhCUbBYLKmqmmHuxKFQGm0LSWiTsmYCndPGiowxFUVVix5ZDzlgkxoH9l1H27Z0vUAxdrs9h+MhOh0tx+OBe2Po+5Y+QkIkUDPCW4jsQkapHM0XgglZO8nJ0MFT6IBVUKlAXRgKq6krS1WW2MJSlBXKWJQxeF3gUQxBcXW349h2HNsEmwjC25FMjOxskJFMifAmhDGEFh5O2uQIY4blA0dDTU7NccbYg8gElTPONsl0k4xxlQ10ozW2KCiKktlszqFp6Pqe/b4XmnyXWJOExEX2YIh04hKAk6RD1PE5ADlmKfLcQAw6RucvOQnG5Ay51pJ1kMxFLWNfFMxmVXRsBVefg5CJ/CUGqrRCCEqi9gwxuGiUxs5qqqrg9GSN846maSIE09FGOIx3ntlsFunWDUU5MU5JTsTocCSIdprl0bRMwcG0LuNu9IJ6MMQ6QicwpVR7J05VbFxbV0KKg9Q/bLZbyr4X8gNjqOqa1XqFNpr94cBhu+HJ4yfM53OUMRxi7cfd3b1k4RUUhXS6HvqO25tbVIBVNWN9epqdau8DfTdkQ1pIIYR4By/BUo3CqMS+paV3hNZYa2KResFyPmdWV5SFJdUaxsrdcXXH/SG1mWnkFJkVLq2hEDLD6bisYvbNGGwRMxZGHGZjC3EutPRvEuSHjnOW6ktk/rqhz/Zw03Q0Tcv9Ziv0v82R7faeoW9xw5R0RDIXOjLeTftxQHKowgcb+/uPH+xoDKrPRn5GHPjRoyWAciL4tPaRjcXhB4kQdMct/eY9KMPVi+c5nZsGS5uCsq6xZcVsuaKslxTljNlsRVVVVFXFyemaqhTsfDkzGGsoTIFE0InERSEydii8NxhdUVclVRVYrM5zOioM4sm6wdM1e/qh5dhsadojXSfUnKn+Y7vf0fcDfdsz9F3GTCcGhsR/jcpgjOlKGT0+JWKfqBCmQkp6SChcLoyNBkaM0KczlVKSSYiCUUXhFVJPDkQoKpSwdMbNX+jEwJMKih46b7lRVHR6cGIIaSPeSgieITZiVCoKJq0JBkKkvSM4oW6MfMtC1ysN7VSQ5n5KGbSxBK2ikegEaximQg6J+iuPY8gNgwxeoE9GM5svKUtLURhsXWG1wWKY2TJGIC3aik1gjZJmWCYRjUtWQHsXoys6K8zKWFRkiAqJbhIFkeLNei+RP2v4+NEj5rZgZgu+fv2aQ9sxeJ/p954/f057cUF/dsqluaT0sVFWrMFJvVFAisWTs6G1lSi3Mxgj3by7fhDeMUU2prz38oxKyBZmqxmzZc3QHnny6JzTRc12u2Wz2/Hu9St+9PmXHJuOf/sXv+Z+e4W2ii8+/5yPP/mIn/zkS/73P/9zUFCWJd++foV+8xrfDZyenfHRoyfw88A3X3/F++trSqXxNlBUht61HLqW/f6Os2eXnJydYbSlc57Ti3OeffKMb797wdX1W7zrxSAaHIUu0cYyryuslezFfFZQz2pWq7UYQBFKoOOcCJuQLGxbQOp4CgMeh8aOTjcB7wcG10WqWgUYYYBThrJcU5al1JOVNVrbCL0ZzZu0PyRiLjOktRWGqr6j6xq6vmO73bDb7TgeG4HEdD1d29O2neBplcK1LcH1mNCjihJlNK13Eon3RFa3eJ9BTZ7tA7vs98eDw+U6sNFIRSlSN/hU3KyU1IcpLw6B73pCgPa4pd/eorTmvbHRCFACpdJSTF5Uc+Hsn68oK9FT88Waqq6pZjOWqxVVLcWlVS2QO2sl+ojSuCCQX+c9zitCsHijsbMKUwfq5TnnUe73fRdZyHra44Guazjsd7Rdw9D3suaahq5t2O42qCBN1bQf0MFJZlF7CuWplKfSgUoHTirLuiq4XNScrubUVQy8RHmmbCHOly2ZnVyArfG25vnbG263O168fc/N/YbN/sDNZivldgQxihG10ffiUBmlRmRxdKhDnJfEEZu2mYII91CkFnBJU2oV5Xc0wKuqpC5LqrJEB5Hr1mpKK5CiqijE2VDS4DM5l/VyhbZCCvC//e//jjd3t7x99Yqu64XJLqSat5DvU6Eg1vPYaoa2QvogGXepwUpZCxOx8NpIwW1hLUUh3bdtNE5txPInTL84SOKI6MweBQQvRduMrEQSwCMH0cb6zLzixc7QitIUfPbsGcvZjLosef7tdzRO+ox1bYsbHCE4ulagm4V9IrrUGnyEACoEAjXtIg8pUj5+b7KnxLBWRN4N8DC4QeZRB07OTlmuV9xvt5yfn7Ocz9jc33E4tuxupIP34djw+uVrdocDxhZ88cUXXJyc8fj8ktffvQDvKGzBt69eYKw4Yuv1CavTNcvVEreYo5VmcNKAtSxr+uGGvm05HI6cPXnEcrHgk09/xGyx4uNPdnz66Y/45tvv+PbbF6L7qoru2GKDmO7iUEjAcrGYUdVVpnC3haW0xVhLE517pQKFSQFSCLgYGEtEMJAYWN2Q+qBEJEhEU0gdjgTgy2oWYZOp1kJlOFamcM+KQoIZ3jmaRnqQ7Pc7dvs9x6YVeFlC8rRdhKp7hqGN7QWcwEe1pu1GfTQ4H+2heDzQS3+3p/GDHY3RJpaClO9Ll0wL1xQqRwNCHGyfFHUMdTg8XRPpXo2l6xq0sRz2e2xRY2xJWc5l41Yl83klm7eqqWdS4FfX84xVs9GyzBgyFNPKLx0b0mjJf0UDQlPNFlhXYkpD0c8YhoFZK3UdwzAwO0qKre+d1HwMPU0rrznnGPo+Ohup+imMjW0kyCaUmcQ1EcdzEjMgSdz0/oPpy4voobnxIF0d4MGaSwLAu3yhtFCCjhjBBKlSMSsRw086BBJFLSm6GuFjEk2bdDFPDB7xEYjGUUjPE9J9j9kByVRE9ig/YU6ZtLM3KhmWltqUWKMprBRrW6OpZ8I2YaxGFwVGSdO7Ulmh/bNCcZmmP0W3smPoY2odJdm6GAnwIaBT46X0iMSeGTFdnDafwCuWDG7g/X6P2h/w+wMqDHGjeza7EqM1q5MVShUZOymGq883mFL2KHINkFZyjmSs4rlJxCfhFJworKJgPptRlaXsI0XsdXNOVVeUdcX7TcNhf+Bw2Isws5bSKEqrYy+OeXZer65u5LtdQFtLXdcsZhWffvIRjy7OCcHTtNKD4HA8MHRCcdf2Ay5APatYr5Z0bUvXtOw2W27fXxN8oIzUesbKHl8t5lmYz2Y2YpPn0VBLDmJ0nlOjsbT+lcgj6RIPQ0zrJmy2FMuKsSgc4gXWSEGwLQoxCI2lsJV0Qtc6F+unVDEElAcfay+cO9D1Lcf2QHM40Hcth92e/fEwFv86oSd1LhowcR0JhMKQoHFD3+XzQi6q0zGq9YFC+f3xvYfADKZlrSBGUXp/JL0QauMk8MjCOOAgpOCRfGbQrYy/Npimnegm0TdlPZNC87Kkngmmvp6JMVLYgno2E+arQvDTqQ4iGwdqdGKzQ6uEilkyI7Ley7qiqEq6rsU56Tk19B1D17LYVuAGlBswQ4cOA0XomVtFZWBdKWaFZl4oloVmWRjOqoLlvKC0hqI0styUwoUEbfQsTI+tSszMAidcnMw5XS14v9lzvzvw4s1b9scDx8MhpuBEjg9pDNP+IVdQZJ2QUhNj/YSmMOJQFFpFWQ5lhLhWpRTxl4VlPptRVxVlWdJ3g2RzjI5QsGjEx/0SnMt7ryjABUd7PLLb3rLb3HI87BgGl0kppsHlZD+ERBygNYWO31VWpOZoAlfRkpWI0fIyBkikR4XJWZUMgTI614/kPhWxM1uCoqQ6Sx0VepZ6ObAZs7KjBxcXu4xpVZWslgsGN3B/v2G337PfH2P0vud4VOzKHcZo9icrAjPJ2irpy5EhyvIlE3tvlEM5UBqS/RKy7UF8PiHwEIKVoiikGakxmNmcwhjqw5GiOLI5HOg7IfcJzqGinlzE/bRZzOmahr5teHd1JYHSEPjsM0NVVzx6/Fj0fBx/6ZnTsN/t6LoOrSL1vdLUsxl1PaPr+ljne2Sz2eCctEVYzOcYLbCk5WJOWRVUVcFsUVMWBVUtxfiJrh6inaPTvlbSUiHEgHDMsGZaorQ+Y7NnawuMNrFeSIITtpAAmLEFpqjyHhpJc+LsR9vPR5asYZDgeNscOex3dF0r9TrHhraTbIbzEvzNDY1TxkqJsyMAFs/Q98K6FoRyXr5Y58yVSmv3B+imfy9HIy+2Kc/e9yy6QFL2Uhj94bkajVIeFRR9xkkr+tYTaPC77QSPY8EYqXilRRnQVpqAVWXNan3KbLGkqucs5gvKqqSsxAvU1lKUZZx4TWELVEh0bh3OwTAgC7+oqEqDDYuc/hKvM9AOrQgjF9jtDhybAzf3V8In3PUcj0fc0OOHHuUcYXDyuwTlI50rgikNKQXlY8xmlBNKSbQ+RGVHyqElYz2l1pChCTGKJ5lVL7C12A8jxEWoQjRe4nOjFCHSkekojAPg9RipMIzgJjfkvrORtlYRYn2EQMgi/hdPUOJEeK/zfUpBuTCOERkdXLzdNL6FimQARkW8qmTJCmupior1fElVlczmcxZVIY2GCp0fSeChXnp+xL4GKqaoE5QmKfIQi5q895lSWBwNGS83eIIOBBOyYwrE3iaglSUmJSjrilVsGnTfNpjyXjoLdw3BedrQcX8PfddzcXmG1mJQS/8Hj+sdphAV4vshPk8ykkXJDENPQCI0ROGUiulTQzlrDLO6ZLVYMqtrmuaIAQpruDg9o3NnHNqG5//d/8jd3ZauaTg9XUqn2LrIPVIuLx4Je8fxyPOXL+i6XjDcpeVkvWS9mPHRRz9juVzy7bffcr+55/rqiu12h3PSC+TYDLTdwLquWK0WDH3H7m7D+3fXvH39BoJwoxdlTVUtKMqak5MldV1S1QVlJTUaSuuc5ZoKnYxNRtGHWKDmxXjHQ9v2ea6tjYQGusAWNdYUVOWMqlwIjaH1Qu+JsNE5CYfEjKEYgkMYJHIJDJ2wem03G/bNnrvdHcf7LUPXM7QdneuFGSWygAhEq5D+L97FOdQQpGeH6wdRnoOTbGG2cnRU9FILZCLs4vfH9x8SUPGRcz4GMhgDGCJK5Y8QIyIpI5uixcn214n4AUQOxzqZ3qXau302EEYSiniNGLmuKqkHWa5PmM2X1PWM1fqEsqooyoqqqiU6bgt05Le3tsjQOefHYmJTFlgKqlklDC/eRXiuR/mBbrPEd0d8c8D0R2xwzNTASW2ZV5YnJ3OWs5JlVVDrQKUCM+UpdGLS6uhdbGbYdfQOXK8ouoq6DCzKOcvHJwy6oFMl94eWzeHIv/vr3/Du6oq3b9/S7nfgPQaFiw3bOi/6AKXwKhaWo2JklsgWFPWyMZQ6UBqYF5bCKCpjWFQFVWFZzuesFnPqSoIXVWQRe7/dSWCEMM5fFPjBe6mFcY7ee/AtbdNy9f6Wq3eveX/9nuNhF9eHGjPp6ffkaCgH2qGM9MlRhZWApy0iTj/W7lQSBJUi5HJSiCs6OjENJT8rvTY1PH3SxSFBySIfmEp63mcdoFLQLEK9FQjcPDohVVGiliuKsmR/OFLeFQLV64Qqu3GOjVY471ifrFBaMZvV0uk6UscnEFByZkJ+JS76ZBPmsQMShFCBMlIDNJ/V1FWNtZahH2IPi5LZyQmrpmO5OnD97/6S5njEO0dhbax70CwWM1bLJYeLM25vbjjstrx885qmaen7nsVyxZPHj/nss08pCyFy2W2FPvf9+/fc3t4y9AO2KOgHh1JK9mdRoJRmu91xv7nn7u5OnCBrWC3XFGVFUZScnq6pqqibyiKu2amzxcg+qmDMMsQ3fexv4gN9Cj4rJbUUQYGyUkMZmxIWtozOawGkml4VqWw9ieBEAskjskFouEU3HQ8HNpt7tpt7qfXqW/phiMFSYsAtMlWlB9FC3U5QmWK9bTuG2HxRaNqjTRXlpzjPP0w3/WBHg2EQpW1MBCzGbRMmXux09EMYi5KRB5BgZADf4RkIYYjpOWGgSqwWRiVDNUK1gke5nqBa8b6coumPtEqz316jdAHKRONBOh2qVDRTSJdYayUCJXUgJbZUWFNijUCxBK8YCLFbl099HoA2tl/3zuOVRZczFifnlHPBZM864Rnu2lacjH5gOLbSydw5hvYgzeUyvVmMhrgxap6cN89AUnwhUjuIPRlPGDwoPwquJKS8giFkyjZI2QRpWhVCyGlYF7MUPua2FVBOpi9BryS6llLgkXkgXTitdy/N7qR7snxPGPrsYKbkodCxjou0jsVu1mqqIqaZFzMqaymMKIsUKZrp1LnUYK3HmJjWNYlBah7ZmxyhG7LwzTTC8deARLwTp72PEK8BMwoQ3+ODilmoJHQDLhVYmFgr4wIce4wK1Lbkk6dPWa8W1NZwdfWO4/GAcyoWwQ189dVXnJ2d8ujJI07XS0prsbaShoUqgNXRwQPv+mi0pCZ0EFysScExdI0YRFphBoexAhmbFQWLssYWM0LvCM6zuRPucBc8P/3sI9pnAwOK26v3tE3LuxdvOD3vWS5XnC2XvNpuePndt3g/iMOnFGdnZ1xenFEaaRq53ws0yFrL2fkp9/cbrLF88unnFEVJ0zR0u3vatsVYS3M4MCtK/uCLH3PspcONLipMLVkpqYHQ2ELlIlOPsPzktRyFWT/4nM3xQZy+wQcSpFPXRS6Yq6uZFMsZUWwiwOUZQKKvMvyyHgMBHRx9t2foO/btke1uJ87Xfo/rB4Ze+MUHJ839XD82bQsM4lQ4cTZCMJFGW5REP7iorDU+KJzXDN7Su0DvlPTYiCJT3F/wXSeRUvvDRfV/fEd0HhgjfvllojE3CdyELA/Tp0QOhgQTmYhlUkYrBXhynVSEOnxgWPge2uFAe9DsN7eRSld6SmkjsNGiLCMrT4UthBK+qmcRklXm14pcFCzRzlRIalSIP2CtwJSssZxWa5aF4WJRcrqoWFQF56ua0kiGwHctvm9wxwOua/GuY+gbXKSodEOsMRo8fXtAlzOKqzeo2QV2tmb95GO++Ogx1WLNT3/6JW/fvuPVyxd88+u/5rjf0u/3FEpGtIuwER+gc47eObp+EKMfqWNJTUxLY1mUlkVpOFnU1IVlXhTUViLGpYnZAAI0G1Qjsbtud8jN6VLm0cemYtJ8scEFGIDO2JyJuXn/jqY5Ym0ylkeIIpM1IFYZIlfw4HuCMxgdqGvLYrGIxqGlKsrYTG8a2BY4Teo6Lv5jDDLmanlxNIJSEbYUsqObosx5KcYIl1cqN2NTWkeil4n+9V4KrxXUZcnTx4+Y1RWKwO3dnUS325bjUXq/aK3Z7k5pu46LizMKa1DWRmM2JSimUC1yMDZuhrzHfO5lFqhLGxvMRShTUbCol5Jp8o799pBl96NHjzk7v0AZzdt3b2mOR96+ekXfNCyWC9pGaFeVUiwWC8qqYnCOuq6whTRJFcjQwND3EELOOtSzGR999BEA291OmjnHviRNe8Ray8effMyjQYK/uqiwZdyXpY1MlTFjk8PtMbOgxmAkKYjsY81H+js63EVpckF3GXtzWRshlpEEhRgoGVLBZgBbWLQWG2zoY73xfscu6qbD4UCXyCOaRhr/9p3Ya97jQ4LDpemKtRzByz3GYnhxGqU2VCCensEL3foQyYtihDkH4uWxJ8bj33D8cO0VkgIcB/nv/IIQRkagvJPTv2PUJnnFDwurFIkyNn1Mx6KDEGKfDJQY/3QCn9CSclZaS1Gb0rGxVsTMVjVlXYu3WgrncGFr6roWelCj5HPaELRBW4s2mq7rSCxYPhYNa22lMEsrjBHj19jYnC6AtgPKxckzsUAnRgSUUhh0Np6mExa8RHvUZKSy0EsRhPSTlWcUmHEMpxjzccSDpFcmHnG6rppOC/lRc3RIoudpYSUh+NCrl3mJ85SUuFIoYwR7qxWFtbmwqq5KjNURyypGdTWvKYyhiM9vEv5WRb5vFdPO0cFIEQSrIrZXKXzqnOliZi333RBhmOYPJhR9wUyinzH6lPuHxGePj6uVLF0VBXoizJpVFT44Tk6WHA9bQvAcDjFN6R3b7RZtDOWspi4tVDW2tsJalOYAxugcAbxLMa0HhpL3kgJGmUk0S8fog6eazzg2e5rDkfvbW8GSViUn6xPphRECu5s7joOjGzqaY4MxMboaI1vWliQInEC4AhjFdrvleGzYbndoYzg9PWO5vMEYy9npGqUCbdtivdC6GmNoW2mIuFguMTEyomyBKqQeBjzayJpJoL1pfYxKa5xo6GX9LBhibSQTiBKMsDUWrS1FORNYlBE2u5QpGfnstXS19Q7aFucdnetpdhvBth63bHd7mrbhuDvkLtJ922X+cSERiHOnyIW6CaubaBFVCn2F5P6q0bCN4VhBJyppqBQhiIkWMzeO+v3xvcdU5GVjaDTXctYhBcEkkkPMWIziLxltHx6juAzZ+EtZ33xduUDuHRVi0ChlP1Rcf6ku0RaFBMYiFW9R1RRliS0LbIyYS52SFAvrVPBstUAeNZSuo8AxK+BsXrKqCx6vZ5zMK2ZVwWpWYJQYyk4JfXPoLW7QeC8MQYOTfgtu6IXOsh/onYOuo+0HdKco+oF6tUb7c+rS8HRxQV0YFrWFZsv+fkZzf8881iQ4M2aWjl1H03Ycmoam6wkQi1h1JIPQzK2mtppVZSiNojIei0d7CeqEMPalEcpPz+HQZEhrqpd0XqiCE9uS1wKH3HnYbHfc3d3Sda1QtGsbi2+j6ZgdRpXXBYlRGE9qZiZyOUhzVyMF6KkYPVoJ0QENY90F8ncMcpPsmHHdhMmP4OGDD0LKMq7CD4wCcS68eljLFYg6ImZQ67rCuTnr9Yqua8l1QN7jfc9uJxCqsiyZz2tCXVGVNttleSeF/AXZAlQP9krUT2E0x8c9FR0vY9gfpMnl9n6DLYvI9jZDKQks3t/d0jXJGTqglPSvIASKsmA+n+ceQ5KBkV4Yh31soHk44L1juZBnNqbg7OxMGqHu9ywWc8k81SX9IA7ZYrGg8rGeSFthiYy2y5iyyJZXnlOIJC6T6ZPBMjEoEO3SBMG0QpdeVVLUbQthFUsrJ+m5REbgY82x91JQ3zZC4bvbbdlut7F/yDGzrfZDL8FfP+l/RsjzJZm6qJdIxENhMtfjJzJ6Jj2ril50JBcSwho99hn5W44f7mgoWbSpf0KYLnolbDHJEPYTnolsrMXFH0AYqZRCqyIXAo8bXiKDKsV3lSMEKQ0rjJWrDw5SoyKvRjrL4GHwhDCgjLBmOC+sIB0Kb0xEZClMUYqhQjRChDCLajbDFAW6KqkXC6q6jkwDJVU5Ezx1LATrmz7zqAfn0CHggkOFAaNkEwfvcUpDTHcXKsF4xLgOXujfHKPHmXBvQSNSKUZAkqGvdLIuY6OxrPzEhAlBPGNjjESIQwCV2FLUuG/COD8uiwYRhoURTz50LguI4IaYBfAoK0WzSVgGBMOukD4dZSx+q+fCBV5VUkRltI5c4JHX3BgG3xNUwBYG5RzKOTknUvpVGdcMZSHUoyih6fVRcsf+2rkYX8X1Jp2YRwMjGapaaZwf8BhKU0fjMzq/ygsczKtcJ+KjsSs4ZBGmziDRmcFR1gY9q9CXZwQ3UJUV3x3ekhgtttstgxvo+g6r4WS9ZjarI8zNYxED2CPUk957+rbDmJpcIuli104/YG0lqejBiXNlNLe7LbYumZ2veHN3w+uXr/jVv/0LLi4v+Ojjj/lP/vgXGKPZHvb0AxyanqBhdzzSecf2uGc+n/Mnf/In0hW86yX61Ry5etdydnLGr3/9a7777luWyyWff/4FP/7DP0QHA3iePD3n+v0th0PL2WIhlNUG9seDFL4uaqpIHKCUxUlvPrSRX5wLwjVOPCc60DpS2EgWMDmKYCop/Kcw6KQYrM6OhlZVijtH5R+3QDLeg6VvG2H42R/o2ob2cGB3f0fXSb+L1g2RDlO2nGy92PxMiaOZqKvjGQTlhfXGaIZhyPvMGCtMPj45IJ6gerQJFNrgGo/ShrqeSRG587ne7PfH33Ik3Mz3ZDOiqzy+rMYgzli7kaMMkslODu7Ee/GZbTDV/qVAxnidqRmiECMjRctTXVhw0PcNoGizE6TIXQJRKCvQBimAlnVdWBv7KRiW84rlrGJZFzyaBcracrYoeLIsOFlUPD6dM4/FvVZHM9EHdGEwqpKeNdrjW4MbOoFXDFKYOgxisHSuw9Pg9gfYddjZjiEolNF473j2+ZecfPyELz55ynkJu7tbDu+vuVwvmdUVs9UyQ0w2+x3b3Y7bu3u2u510uQ8I4YX3QszSdYS+Q7kjoRtwQ0fbdjE6O0Q+f7m/xCx50woDljTDFGNscC7aRBpbV+iqRJUV2/2B+82Gu9sbvJe6NrSKTmF0CFT4HWdDx02vlEDVwqBwXYPrLGGoCEMh46uRLkZKQaxRVUHQGWnBBaKsUKkLsycjQiDCeseMhlcBnwJ2MDol8Xeh+NXo5DBHzaeQZmzJMJyVBdYsY7F9oCoL6fjcdfT9wHa7jXWnLcZoTk5WPLo8z7ZHok2GCClNtxLGoOVoOyQD2UFdgPcMQyf9tgA8vHn9ltevXvPtt9/y+MkTPvnsEy4fP8EWNmZHwLkBHQJD29Ikea8NJ+s18+VSgkL9QGEtQ99xc9zz3fNveff2DfPZjKdPn/DlF1+wWq8w2nB2fsF3337L3eGGTz79hLouKeuSFy9f4YJjvpwxOCTTLBRe0c6NTJcKCUDHZ0+ZHu+JDJxi/6SseVkJ0Ykpioja0YTUJ0oJWY3SOpL5jJnRlCnom5ZjI7qp71qhvT4e2dy9p2uPHI8Huq7H+WS5PQj9ktBdcu86B6G9j+5/cv6i6Zgq3JK1joq1YkECr1pL5skYLQXsieY6ZTr+juOHOxpWE1TAKT+Rpx6he1RR2MriN0GPCz9GlD16hFxrnx0MgUblJyQ+IZkVPH6dJ9APQ3T61FiApuK/yEbPUJkwCMGsSkMf/xvkO8KgCQyE0OHSJCvomr0sgNjlXNvEsCSFpKk7czBaDCPAmEKw3GHAudhsyYvhKgs1ZW9Chu0krHBauCr2S3CpCdHUICKgI6tUilgkWjGlTFwkqdQoRcAl25PmQaWxTN5rnp/J+MQNrZUmRIfKx3N8FIIowbMbnRg0ZIyskT4VhdXU1kgtgtHoWBSnY/QqQZTKosg0so6CoGKnbmOlGF2RWUdUJAvWwOB6pr05UArnhzj/k8iOUrHRlMpp9YS3DhA3SILjNJF2MM2IrLHeSxdv42PTHZSkIdNsuji2NhoWaGpbcrpeY42l6wfuN7tYhOfpvGOz2/Lm3TsOzRE0zGvB9lLE4nDvBQaHEvpM54AJnzXS7C4AvXdRAQHO88mzj3l0eSmwgX3DfrMXoWZrqmrOy1dvKApLUZWcXpyxWK+4eHLJ/d0dm809z7/5lsdPHnN6eiKZiebI65ev+Pyzz1gsFmz2e7pBYF2DH9juN7x980JKqLSlazpubt5zPBxYz35EUc+wtqC5ek/Xd6PAS+MXIXiSxVV4N9YGiSCXOg0dC/fF8YysYrHvjoq46dRrBaMz/lT2XlT0PuAGR9f30jit7bjdbGIUrGHoenHiXM/QtZERpBcWuLR/QsxEJMMyDz4o5aX2SMVzPMKo5sZojFexo64PkrEJBmMq+d5hiMLb0TTHHEDwgdyk6/fH33DELG1qkAVRI4RR/mebPsJzk/Hw0FD6G30VuV52aOIF1fT9D6J6AVxKNz5QxCNxhop1cXLvCXIi613HZn2ub0WDKMUQ2fPC3qIXM8p5TVnMmYWShdZU9BReoYYWbwIOh4tBwRQYdGicLRhMSa8HGqc4dJ7u2OPaJrJdRQMeRVAepVp6pdnfvufKGI77A2VVslqvWCzmNJtbDrfv2d6848R45mpBMTORuCFgmy1Fu6Pu92gduxF7h3c9fnAMrdQ+DV1Hc9gxdB1d19J1fSxwdblwNTkGIUDXSqPb4Kf9HTymEN1TlyXBWDzQxgj54IacnfLO5c/pnOEaDXtBTfkYYNBCvBEUxg9YJGhYaLBa+pOoIAFQnzIaEKHJyUwPOeCVosJTFMcYDIuMgiqIqtNjUXhUiAKJietMJbsgZk1DmOwHDwTRvXVZcnoizewOh6MwEdFI0LSXzMa7dwIr00oxryvKQtg9SZnkicGQ6e1zoFMWtrEGqwzBe5RVzKqa9XrJcrkAJxTCQgXuabuew6FhfzhgrRjys/mcx9awXMw5Ho80TcNms2U2mzGra6yXvhz73Z6u6wTVYDRd17LdbvFuoDmu41x7nIe2bbm/u2O33XJ6esJiuaAsS7rYY01FRxPEoUk9lsUXlte9c3n6kuuV+1cojSnHfjQ21oAoY2JwQ0kNrYqoGzVmMYbYEC9Bn7q2Y3O/YR8zNH3X4mLG0fedkIi4QZyMB1mIibuhQsyuj/ZiiLJGfIwIaY/3EJJ9EcKkD5uUMAhFsWRnnddEurlM3az1VL59//HDHQ3DuNAmEaAU/UnGq5B06vTUeWHmBZpkK+NlxrjR9K903fGzPoYVBbsdxovk1KcfLxGFvFYj7pvEpCRSZhzc6XMmugWTKItSwZ8CZTLmVhfCXYzSFFWNw+OCFOoREtvAyO40jajLd/oYf1fjOEavIwRhuRnvWQRMjLPF1KucryNO2MVFlGm+suKNxnDESmbplH7ywP/uDIRALJhUmT9apG5qHiNFZ0VRYouSWWUprWZWRnrZ6FRkVqnECGQk/W8i5MlE4amVmkRPJpCTuILE23ex82q8doz+K1IEIiXsiU5GnP9od+RRDSGVGomjorUUFeeHT+Ms96D1+Lk0/LloTzQKCrDaMK8qAE7Wy9ysre0HhhBwXctmu8EHz3xeY9SJUOwWZvT9AjLfWhPckKMPovhjZEXLc5n0pD5wslpxslpxffdeQMworBaYRgiK2/uN0ERbw3y5QGnF5aNLurZhs7mn7zr8IE6bjXCA4B1VVVHXNVe3twxeuhmFEOi6lt3uXgQ9lqF3HI8HDsdDzNgJ73fvBhH6aekRnQzIRpAPMlc6nxD3nIQKc81VgpGURRGzTcI61jsfdeooOL0XBix8IAxOmnZG3vXjseH69n3uqxN8Cgj43EBMxQxT2v5Z7IUs3uKGic5Rfk9lqswUAfwwK6Hif402DPhI6CDywcXgTGb3SBjh3x9/y6EmDkNyBuNmno599A9k/pKi9eOb+byJVlIidz9wJUY5+/Auop4kLhj1O75GurRmIpOSTFPiZKSkdYp4JxmGVjhvpHOwCdRUzHRgZqBUHoMDPxCcwmFylVqW+EFEQ++h84rOSQ1i2w0MrdRqSOY0CLmHCijVojw47vFK0/UDj548xoaBAsf29obNzTWb62vOCkPhe0rjhflPBdzunnA4oJo9ZXQW3NDTNw2h73HHVsgUup7jdkPXpd5X4vAMfmTImWqDrlfiaATxENIzaiMTIMEGsRvaGBV23sdggbBQ5c/FDZ3KD5Ou1bEe0kSyEZ1o0b2MrlEx+I2PdP9xRWRY5MT4S/c+taM+yAZknR3P8V5l2HCy5VWyq7yf0NpPakvy2hudL4UwZs3qmhACy8U8Mug52ujQtW3LZiuw3/l8hmaFpqJI9MWTZZwcm5AHb9wURmuM1XjXA9KUcFbX1FXJcX+M9oRBaYtznqZpaJpGoIRaUVc1dV1xdrrm+uqa5nhkGAakkLvEpgxHYu+KYyd9IlrqqmKI0LmuEyeibVu62E/N+chWZk10qv1ofqX9Odkvo3MhTlyu0lKSnTBGHIzCVtnREOa4SJ6T5Uj6DBnq50NgGKSJ9PEguqlpGu7vpEN30zS4PtHQOmwOqoyooXTD4mjqvE6SY8Hk/ifTNLHJVf4nx0ZIDndybAMihUI2G5M/8h/W0YhcwKQ+ECiMtvigM94YHU35IU6SUgLzwYPvIBjwGhNKMVYM0hlXK4wpcrRd4n6RQjU+rIydvKaChth3wLlAaqTlXSqOlkHUSvCwIVb9+8FLxb1KYJRxkH0I2YgCYBgiJSYMQ09ahiEV7LQ2C6kDo0EecqpaWKCyhev7GPEIo2GSpBsKfIcioLXPTkYKeAnW0sZFK1FeFSMHwceIzuAik8eYJiNIdkSkpxT/BFINghin1thsNOsoUJQP4qVbSzWrKSvLbFZS1VaYN6yV1vOAdsTaFgVeGvIVCryTupbKlpKNUAqFIVXLFdZJqpkyjrlAjEJwBKS/h8AOlDAGq7i2VEDj8KEjOA2DZtCSkdLEiJ8H13tSLDqoSY1FkEiLG5ywgCmkEQ8WI5UzmZI3b0tFvDeFx0T8jMer2APBDVhfCK2uUpRaQ2G5PDsVvGc54831e3zf44Pnbnfg2HZ0fU//pOfkZM2JOaFUmiIyQYh9nJqASfPIEBtiYomFhwp16LEhUFvFzARK1eMOW55enrGsKg67I23vePHmHcvFkqW2zALUJyuc6/jNb/+Sd2/esd/u+Yf/8B+ivKfd7Hj0+DHPHj3lJz/+Gb1z7I8HtscdTd+Kk6bBGrDW8/z5C4wt+eyLn+CVQpcFq9M18/kSawscgT4M9KGXLGBQKC0YUYWiC4PIkUi5a9CUQYrylLFoW1AocZiI+8wrhEZbxavYMkomT9e1DEPHsdmz2+64v7/nsN/Tti2Hw0HgF0FYxRgki6SjUBa8bQoQuOw45B5CkJXFVGEkaAwBrLLZ4FS2krWkJDoaQsCqHq8cLnjpfWAGlOmhl2ZJKmYLxVnTaAvY39do/E1HpouVv6LuTaZicunUA2M/61jCQzsp6ZzsaKisgadFn0nZp4/KLSSDL5mO6W9p/5Wci2R8ah2zrfEGdLzP1JFYp0/HNV7GfhHrWcFpXXBWW54sK84WJeczy8IqKg3KOfpWIpOdc9nZcCjcIGwyXXNgaBua/ZH9vqE7tLT7g8ioIUVKFSjNoI8EbVD2hnp5y3x1wvl6we5qTlmW/K//4p9ze/WO7ftrXp6fc7Kc8+jylJPlnFlVcthv6Tuh3SzrGuc8+92ezWZDc2w4Ho50vadzsned97gQGIKMTz9Is0+XGurFcdbFLDc4M8bkebLeYwZHpzQOaEPg5vaObdOKYYnAY1wYjSkJaEdHL86cDgEbxJEolWQstAfbN9ihwrge7QdxwkJkioyR4HTkDu15TZGdR4GIRmdj+hMNZ4FfjdDx0V9OTnWY2DxpxUzWZjJk+9EYrWPPoo8+eiY0r5sN1+9vpO9P37PZbGibI33f0VxesF6teHRxHutQIvQ6LviEJkkbS+wxT1FKE8jN7YZFZTk/PWFWC8172zScnJ6gjaVzgbZruXr/HltXLBYLVusV69NTQDqFX9/c8u7t2xzMXK1PqOqawQ2s1yfYwuKc4/Xr15Ld0JrHTx4zm83YbDZ8+923gOLxo0csV0tOT9c8urxkvphjIymDoCIC/SAF3KPToeL+i7VVJgaZtTgSOjoZNnZvV9pOhUEMhJpMXeyci07FwGG/57DfsdlsOR720tR1vxdHKNYCJgliIsmAsgrfp54vfjIPTORQyOs47Q2XsxkjaxSJJl6pHLiX+RtywMsYjfEa63SG1mtG20Ng8PoHZdv/PRyNdLFRAIsx69N0iEefBW7yD5OYG0fDxwiE+C6yrROlX0hfFZKHln31MRSUahaAWMggb+uxTTzx3qTTo0QldDQqRbg8VDAhGxdx08ZH8N7nTaryCkzPFZVZCGNhsNH52iq5h5E6VbiUx74Wk456WYh86BuG6AQQixRDECdAkQrTkWsklqd4b0qFHDJTUTBNBcL0e7QyVJVAaoqioLLCCGK0wVQWa7VQ91mV3Vgdt6E1wrutFbEAX77W5EJdLZAQfO5aKWOYsOdhnGeZ2jz3Cf+eirYVKlJmyRikZ0khZq+S46nEIM+GgJLu6Pnc6DT6KIBNGg0p5ERHZzZGL8TwjOlFlcuVUTFl74hQhyDpRBtrkJzSnAaNNgW7w5G2PdK1HpzHD5722HBz+56uO6J1oC4rqqKgrqq81tKtBYQdInWuDzpgdKDQimo24/Lygu1+i/c99/d37PcNu92R7W6PMoZy6Hn65AmzeY1zA/v9LlLfOY5Nx3a357vvvmM2q5nXM968uQKt8Vpx+fiSciYdjo0xzGYzfvLTL6mrElsojLUMbuDtq5f8/9n7r2dZsiy9E/tt4e6hjroys7J0Vys0ZAMEODCj8c8kX/hMGv8D2oyR80IbzmCGIFQ3WqBEZ+a9ecWRIVxtwYe19va4WV3dVWZ4Q3rVyXNPnDgRHu57L/mt73v5SkSRulWDdZmYZ4p6dkqZZJwEXlnvkTG0fo1xIhjWeKH/9ThhgDNWSBkUsljU0uUeGXWkM3EeCCFyGo6CXx0H+tOBUUWpomLPc4iyhvICuTTW4grkQaucujNqAFJugqxVtQmGGhgIjlvnSNTwmlzeQZMhpaRUMAYZQ+sFqtg6x9Q4tWOuJjMgsx7f0dv+fYfs++J8PxGX4sxMfuKb6p8tNpmsBaRPsg/9VV6eo9+X9EaTEX28vn+uxmuxuWfvac5+pP5tqo/XoNfI0HHbOLarju26Y7tqaS14dH4gWuKcGbME6jFnRmWLzNZgnK+6TykGION8Q9OuyDExDQNxTkLTPAeF/0Ewo+DL3SiEE3Pg61/+ogZpb7/6kuPTE3HoubeGMPWsPOxaT7Pu6KwjppGpHzidhM//7uGJ/eHEOE1MU2COiZCEzCKRhS0q6/unZcAep3TPzhFM6XI6oSvFyOeLiSmKZkZ2jiRsEUKyYLRQp/fDYs8Kj4pH1/voMLic8FnU1Mvc1cZZ1s6ycpZGu/EhL0Qwn667rOuumowaBJbfldVYV2Ve/i5pHJERSK24NUUGUGxQebfS+eYscUlLMqJsjsYYtps1MQrl9jCMnGyvkDbpDJxOPQ8P0uVutBOyUrHEwl5ZI7yzMngpvoQwQ040jePq6oJ5mnh6fODt27eEkOjHifcfPmCdoe2EFdQ4yzTPWigKDEPP0/7AOM00bUc/iIZGKTZZa7nsRNNkGke891xeXvK9L76gaRpySkIbHSP96cSzm2t2ux2brWivZVTgOQojYEmsMVYLA6YqiTtXYPT2zD7byoZptXOh8bxcG+1CzHMghFlgusPANJaZwJFh6EU/JEbCJLAo8hmZDtR5C0oiq+t2MRpn8azGKNVXFdtS/q7M6RYbaYwyg2kcq4qLJkOr5D3eip4NRmBldf4jm9+aev13SDRKgqHG+uyD1DVuxfRWG5vKWOeZ4UWzsVRYONT55jPcfT0026+5jfL+amC/nFeZ17AlBaI4AYEyyUsVbutza3BeSSBlZYLSDazvL7AlXT1nGhXlBht9TM7BVYNjtFKPirdICzxSQVAFClY+xtl1rjkV54NjqHPSQDbGJUH5dnJnsoy6qDBVwRkuPrV8RlloXduy3m3pVh0Xm7VUMIwFn3Ux2mq4slLYGUSrQQaGkjoewGTFIcrJFSV1FOoJhmSc2vwFnmJ1Y0lcn0XPwlDneSTHFLhSo1m4KYN1UKvSaLCXo1pxvQYFErPAdeQx47w+LuulrCObtWt2Ns+Rc6z850ZaLKINkiQAzdngrReiMe/BeFzTcv/4yNEmcpwJMZNjYh5HHh5mhuHIuusImw1pvca17VLVNKaed8qCr0wa7BqbRMV3s+bFixccTwdOpz0P93ccThP7w8B+f8Q1jkxkt9vQdA3DeOT+/o5pmli1a6Y50o8TX379Fc9unvHq1Sse7u+FjcbC5fMbunWHM7JOWuf56e/9HmGeeLj/SNM0zNOJD+/f8Xu//3t874vvMfcHMtI5Sko/KWzCCjmMsleMs3RdJ7SebYOxDc44GuNVwwXwroZ0UtHM1ebEKAq3Uy8U03cP9xwPB8b+xNAf66yU0Noi3bpiOlLE6ACn1fmRGvbpDIUpWApN8nNK2mpUY42s9xJBSKV6KcpkHdyQzhk1OTHZCuTCGRrnoWkJXSMGX4cDc5aZre/E+n6H45NORvFTyH08SwuoNvw8QSk/fppslOAQzlKM88Tk/K31oU9yl/q8v/0+apiweNikPk8j1LJ2vJOOxrpr2a7kyxuhZM7BEIOBFAizYQrCHDWFAKpu7ruOnBNxnquWUtM0xK6DnAVCOEdCMgyTzEXEEJn03J0Tccl5mvj6l2IX5xB49/YtYRpprOUpReI0crPpyM9v6LwneUefM9Mw8HjsOfQD728fOA4TU4iErAFfzpUqPSHwrpRLJ9solXmLbVtM08jl8Z6m6+g04JynmfnUM+nch20abGPAeYwLZzGC+AvZ+6YmFzK0LJOODmi0q9GRaZRlauMtG+9YqVBgMjCnRCp03Oc3PpfCJ5/Q3srTznmBcv13WV8FfSDFCZRQx2g8YtWF61rWUnwlpigFtSy+Blu0iaQLvFp1ZAQ+dDieJFkKc52LGceBx0fRIunalrCTSrrMi7mCpK/nXk5ctKoSYZa4r9O5kGkcOO1nvnn7hqZdEWLmw8ePbLYbbtpGbb+lHwftqgic6tQPQp5hHadhZBg/ME4zvmm4vrpkd3GBtY4QI91qxbW1fPb558zzzMP9vQo7yiD15ovv8ezmhvVqLesrBKIyNYaYMK6VAB7tWlgnNLS+EViX8xTRzSVOM3X/FmbAysiUEnOY6U8nhmHg4f6uMmONvc7hlVneXFaEzPtUqHy1KYUpkZpgUtdRuf7Fdy3JpvxB0cswFXmztEEM5+6lJJE2C2TBO0vyntZLEdkp6oWMxp9LXvB3Hb8Dve2ZE9aMSDbOAnHJmiiYvHBGp6TwBlegB5Zchj6zQJpqIpFLMH/WntML+cmgXzEKRirqor4rVZ3z1mUdlNELWhIKa41WvpdEA32/quitn9FYeUw+vmw0yKJ1oJ+9gF1yzhCjDha7SnWZQ6SMxJ87uIh8ZlPPETWEZcAevaaaTOkiCElYSwrrU0aNWamyKoVrnJPCrhDIlwZQJgrdqG8ErhZS5HB6pB+fcNZw6Dpl73FstqvK9dx2nYjcocO4Sju7LHrJxjOJXnGV0xRJs1QNpn7STg88v7lhs1lxsdsI/sogAaVVPLIV/YiUywwGWOuICFwsltZyuW8ZYVYxmmjG5VwKHaH8ptAH2UUZcw5KCLDgbU3OtK2tQZ8kmHLEKImltVr1whHiLPMAVpiCsnqVxll2q4Y/+MkPuL9/5N279zzcP0kLNQTmlBnnQH7zlsuLCy53FyQjWNSubUnKsmRSEiV0YwikQu8udJY3V/z+T37MMB64vbvlf/v3/56XLz+n69b088j19oqb5y/IwMcPt/ynP/tP7I9PuMbzez/7Ga+/+AFf/OBH9Icjx+ORX/zNlzwdBuY5MM4TGHj96gX/6n/3LxnHgWkQte+v3nzFf/6rv+D51TO61YZVu2U69Ny/fc88n8A6ItAPI1NMZOtZrS/wrqWxjVJ2KhOHFThkUEYayWV1H0eEYz4l5iiDosPY8+Hje4a+pz/1hEnw5fM0V/7w0g0SBy37Lpa1bww5ZuFdVxY5yWczmUaTA5nPMQYKJlaG31z1NR5HERbKyrMuNq9UAEQxPWOYplCdkVRRjRQ3jCYXOm/lbENRij8XsP7u+NsPCcjMp0WbEgDkM/CU3hIpfOSaRJ5X5EqCt9hpauUvL0/6tTOoCQ3LOTQGFdUCUwglyuuUGbBcShwsQ6M1S8lL9daZyozonQwge5MJ88CQgQDTKJ8jxiAK9SEyhxmngdLF1ZW6klmZz8BYS7de0603bC4uOR6O7PcHPr7/SH/qGY8nRuXkJ06cTgPGGr5+81a6uTmzPxwkeG0boUklY5sGY2VG5Hga+Hj3wK++esv7xwOHKfAwzATbkIwnGCmEZJOki4HMkWRl5PGNx7tG2LjWa7rNls12y/ZyQ9d2rNYrFckTWMjD/SP7/YE3b94SUmLOmdlYsvV03QqXBE4SYhTmq5zFJ2rBrLVSxW2tYeUtjbVsDEIp7C3btmHTenarBrqG2VjmKSxwLO2wl/XyqVifdnNL0asmBOr3WDoRsqYKikG6t8YabBI1aVkmqcYOsv50Hxhb31O6yZE0LzFEjpnWO9xuy/e/9zmP+z2rruX29o55XmY2whx48/Yb8U2XO1J+IZ2NrqvUvVnPC5TtKmWMM/zgi+/xkx99nx//8IfcvX/P3e0tb9+84frZc3zb4RvHerPm8vqapm3ZHw781V/9FQ8PD1hn+elPf8rr730h7H1z4OnxkQ8fP7I/9SpQN/Kn/+yf8OrVK37v93/2SRz3zTfv+PM/+0987/PPWa1WxHmUa5gid3d3BIVKjWMgZ0vbrtnsBNKVs2isFT2mYp9TXubwanCdqfSz0yxzIOMwcP9wR9/3HA5Pcj2jaltE8U3a85YatL5QKZhmOCM4KLZFoUtnsLy6ws4K/mWNLQmRJrRnyUw1WfraMVFposmpJhsuZ1FzcjKDiaEqoZMhVjv4XzPRKC9oFoOd8wIrKknBJxehMhXUjyuPm3PY0nmlp2RkS0a3FKHEKZdn1y+jXQUNKivLzHm3JZ/VplSM7W/9dKakNfWjstQeND6tPymOsiSGZ7u9tLxq/qQfLeVPcf9n9/z8qn36WizDRDLDcdbWV4NV4WJ60tkU42Y0E9amSm0Q6zWpwXMi5UiehTnHRJ33cJYY5xoItl2Lsw5vGxrn8VZoF4sTzkSpmOVIP5wIIQruMSRSyIRprlm0d46YAqvOYz0YJ3ClQumnxReKaKHkoAuHV9LKk9H3RZ/ryybLyyVeru+S5J3/zmRTCWokYdVnJ6+MH4rBVVEvzFn18SwggVxZw8AIjpNcOwHb9YrL3Y6xHxlGmEaBJ0Qyp37EuQZjPdthBCMzOC4rfEJOToPZyGbTcbld8+PPXvHq5XNyThxOR54OB/ppIhtouo7PPn/Nar2iaRtCmBlHFfiZAi7Bfn/A7Ax2tcI1HSmf6PuRUTHRWMPT0yOdt9gf/xDvHMk57m8fOO6PhElmbVrXyAC5EVidt45kLDGBsx1tA6tNi283WNvgrcOrEKPsvbMZp0JZqXz40xyYp5kQZo79kXEaGKeeh4d7gX+Nk84qCSStaKBURruys9Swij0wle+9Fjooa6ds/EwpR9aBt8W/yDoqwWHWJJZiR/T3ZSGWv1LbtASzZxBMTC1b1DmqTxzLd8dvPMynlxnyMkB75pnK/q8e4dz41iRD/r7YiE+BVEZ/pw6i+pZ89vul9mLqfS6/X3D09bWW+Ki+Rv17pHjiTKZx0DlYN4ZtZ7lYOVZ2xudIGmfGSQLKeZ4ZJgkS5xBwjVZkDThvsbZoCBmM9TiFI3XrLb5ds7m4xvoVT497Ih+ZD3viNCksSUTl5lSEvYTNzRpEsyLMpOAhRU6nI/f38O7jR97fP3C7P3LXT/QhccpWhtWNFo/0qiaFcWQD1nspODlPNIKNCOPEmOA4z5zCKMQQ3aLUvd1s6TZbuvUW6zuOp5798chjPxEDeCdBsMsZ0ojR4phTIhsHrL1AolbOsPaOxlo6Z0QkkYQnIgJ+qSY3wtCoLIcVplu9rd5frX2n5b5X6GVWAdmSbOgaUbBxZQoyEaHnd9rlLfYhn6+/c++WltfP1Gq20KqKvROdjUCYLzgdT5BhGAft0MisxGkYsM6x2w1S4G0a1X9Q+5kXePp2s+HyYs0Pvv89Xj5/jrWGw1F805wT2Vp82/Lq9Wes1sq6iCQpx+OR0+mE9wLz814YFo0ReP00z8whEKJ0WPb7vXTZm+es12u897x7+w37/RPTOEES/+vatgbJuex147C+wbeJNlmaphMq+yTK3a4qaGuRXLGEotUi/jGEwDxNzCFwPO2luz4O7PdPjJNAo8gFwhapEH2N7MoJ1Qgiq3U6W0PFOCy26swG6bUp6yWf2boSH5+bmzNLyPLEJXav718SEVM80/K95nP66LkJ/U3H75ZoaPuyVNJjVt6k2krSj1ez9CWiL8qDhjLhX4I7/ZBn0Krz65n1uehihhKUnFWv9SvFJExHZqkqmrNKOzhyssWL6wJeLpy1Z0wR9eLLEJiofDqsttRDueIldinPVcYtk1WnD0PKot5pdIHlErywdFmonQtto+dcB8qttTJnYsBbU6sckhmrM63KjZZsnIYsEJJAV5xe4oStmXLUhA4ddFMiacI4V3vVn06kLPzk1kvbdF3U1p1nu1pXDxlVRXKeZ1Fl1e5QDDI07Wy5oYYYRqawY7tt6dYtzgiuKrJg8EnajtQgr2B3U17aldYkQpql4ZO04nwOa+HM3Go7s6Jh5K5rV0bWWEqzGIOUSc5L58A5YTVKhbhAu10GFT2SCkUiCywKuRet5rwug3GWzXrFs+trhmHAmMw4SWcqJTj2AxlLzLDZbUkGfNvQGVsrDDkJHWM0M1cXz/np97/gn/3DP6Zxhr4/8P72Ix/v74hYTNOwvtjwJ//oH9D3vdIEnhiGXqr6RsgMbj/cEucoKrerLTFmxmFi1nNedx37p0cII8fDEznBPM28++Yd+6cjDR2da1n5ltZZVo2jaxym3TBGGcrvuh3JbGjWloAnIyo5NstXyrJvLVbIF3JkzpFh7JmmiaenA6dTTz/03N5/JMwjYR6rCq0xRlXUhS6ZQg+sayRXm3S233MilKKANTJjgTiUrAn8eQogHVlNy6MGCCapfreSL+czw1+6p0pULu8rCXDWjlgVtsrFaKt2UKI6GqtV4V8ron931KM6wbOLVOjWi6NECxW1M18TvOKDa9lgedVvO2b1/KWYZWt3ojyu32uCcxbsFZtjzkOET9MXyudA7rd0vcTGewMrl9k0cLWyPN96Xl60XJqZPE/M44lhHMT2jiP9ODIHCcq89/i2JYVJ5vBWoiEFMsDqm4RvOnaXW7a7C9abLVfP7vjw4ZY5O8YAIR6ZkyhupyhEBjK0rSrXBtIkekjZGVIYub/7yNPDHb/48g13+xMfnk48RMNsHMGvSM6T1OZFjQect5XUxKqys7FGcO5z4HTc12HZphVmH6fQsPVqzfe/+D5/9Id/yGevP+P7P7K8f/+RN2+/4e7pRIpCoY0Tcg3mGRMDhkRnpJvtgYtW5i823rJpRIDQIgWhRMDEmRxmUgiSCGSkoOY0GSpDhTnXfVvmP6SOYervzwfAU4z13pc1kXKuUN1cqO+zMC5l6ypzYl1OZfQRodYvgW3x9waxd94uM2DrrsUZaJzjdDhCyvSnnizSaExzxPQDKWc2F1uwjna9RmZBtfiqCALvPS+f3/Cj73/OH/7sJ6xXDfM8c/vwwN3jI9k5XNey3u34wz+6YRh7hnGADCFEhn5kGmdSosK4nBPNsZhipax13rFetTw9PhLnma7xdI2I/3399dfc392L30xJCn2rNc5JEcc5hzGe7A3tesdMQ7IzTbvCGEdMOgORxbZbjcFMMoQcCTkzDALPOxwOHE8n+r7n7uEjYZp0Bko62cYuvmmhtM0Lm+ZZsqm1JbEY1QzZCik/j5BLaF3QMwX1sxSPsxbNhBQp6XpTfDkFScNZ96OA2EvCm8p6WSruS2ifc01yfxvX9Dt2NKhtvfOGASBKlOVyfJKKlX8aTBbnn75lZtV9L8835X3Kjjv7KBntpCAwm1oFkF/K5lqCAvkDRy1blqTIpLMLVBKVXN5ekqeS39SWVioTJ8scCmeVCt3Ecp1E3r3kI8KKpDdGSLJwQTo+6exSWQPRSCDi1qo/4SyrZkXTCD7XWRlKyikRZzH+cR4IORPIxGWKTuZmMhCC8vwbrF8ye8GLZ4EXGVSVvATphilksvCLCpY2wBwmnI1Y47h/GlThVdicZI4gKQ+7vIu1Ap0LcdT3NNgQMcfENx/gxc1LNusNTmdPMhCnIJh+dB0YEEYqV9dYuTYpWMrMQk6zdERcoRiFnJwEn8mREAYxk0ubFzziZWQeItbuyWgCwWail83qnV2cBEoUoGdUHrcoJjZCjoK/t84yk7Htiua6IyXYb44YHIf+xDRNhBA45hNTCJjWch0ucY3Dd2ucFZVRHZMkx5HnNxf87Pd+xN2H9+yf7nn3zVe02zXeWX7048/57LPn7LY7vv7yA2+/ecc3b9/zj//hn5AjrFYtxkLbtnz++qVAJA6P3Gw3dI2l7TxDPxJDog8j3//sFVe7LV9+/YYvPv+C168/43g4YZylH454n2law3a94vb2Aw93H/n888+wrqPzvlZSs+uYZxW/M8LNHXMixpnxNDCMA8ejOJ7D4ShiRUF+J3MeiWkasDnRIMu7Vu/0vs2W0r4T/HTMKmpEDe7PayKf9AvUaxaOBls3jySX1L3sZL/nAs+DIr4llcNYA4g5KpzTL90Vm9XJK0lEOZ1YuPHVaSQDMY1nRY/vjr/tyGf/JZeEoqwLyEYZwUoaUSpMQK2olEqvrqdvubflqfrb4hfKl4GzRlg+e/5ZGnMWQJb/fDuRKeltCQwKn38ZNTVKWJDmgbmP7Kd7wtgz9nvGQXQixlkqvrHMRkWhhz24A83c0aVM261x3uJsQ8iWFDIPh54pOcZosd2GZ68auu0lL16/5+nhga+//BseH+45HQ+kMGFdsfsFmorMu1nHqR952h+Zppk3d48c58zJeOa2JRjP7FqicSSMFKQsdY8SE3meGKdJo65ImAMpiNZAVQEfVadJh3TnfuKvjz2Pdw9cXV7x8tUrmrZjs9vxo5/8mIfHJ958846YBU7b2IQZLGae2CCQqZWzrCy01rB2OkdVEsYE5Mh0PEhn3Toutjt8u+Jyu+YwR6aYKyS5oAZkP1O/n9ed89l6KwxkMgepcGFjSKpXUBxaJuNCxLkMOB3w5ZPK9mLjyopGyUuk0JYUpWCMRCVt0+Cs47NXr9isNxhjOfYDc5iZ5kk7yxPOO+ZpxjrL1cWOxiuUHEneXY6suo6ry0v2+yfevzvw8f17+mHANZ4/+MPfJ2WIcSYT+fDhHW/evOF0PJJz5uXLF7x48UzPDYZhIOfE1dUlq9WKZ8+e8eVXX8sg+OUN666jaxv6fmAOEWMdL168ZNV27DZbISyxjs57DvcPDPsjNy9eYb3FG0e32pBMg22i+KaMCErrdTwNB6FGHkcOh0NlLjz1osY9z7NoWsTIOAw1UTxnYipw2QIBrzs+q+p3TTbP7NKZnMHSmdWaazYUHbblHmsxq64FiUFL0ToVK6LFW7ELkvlapYGmFLyqgUp1vZKNzC8ZNLaTdfoJm9rfcfzOiUa5QJ9kCVlOpGym8wtAOWdNNKphh5oMGEpr+fzCfev99LW+/Xjlcl4epfJMamZfaazQJEUv0rdebHEY9b/m7Dn57H/U+EZO92yDF6OhwWw++8tPDxU6yUZYjRSPWioVWGg6YTzw1rFqW1rvhEfa+SrgE4OopsbZyXCeJho5ZUyUTkRMiTQFTUQA1Z5Ihc1Dq3zlCi+D7ho/ncGRElnmFbImV9GIWI2Nn9yPxeCVhZ4V6SXXIqTAOBsOxxPrbiBnKwPVTs7PmFznU3Jh9NCzzCyzIcu60Y2GZhe45VyUNaoEIVm7RdJp0bWVxZg7U5czQWdzjDE0Hj2Xs/mfc92WuqaXBEcgBeokjGC0G2fZbtZkMqfjlimIocqzwq5mESLyzrJdr9g4GWYUPRgdjgyJeRLe7X5/4Olxz+PDI9fes9puePn8GlLmsD+QUmQaRvZPTxwPR4yF3XaHb6w4iZyFmakf2O/3WAcvXj5jePuBEINAKlpROX143PP6VaLtOra7HVeTYFJ3uwu6VmZK+lPPlM7u13J75NqnpOxZ4rhSCIzTIPobp6MkGsPI6SRBSowSXCwdp4DPmiCcQRGLxo6iEsSZVoOYz2Ydcg00FwpU6uvLP8+C1nNbVGbIsgIojYGs1NfFDp7ZEsFGI07hzNxUqZtStNDXLlctsZx3GQb/rqPx9xz10suCKx2Nkm98+sQFL18PUxIO+PU/WnoQ9XlnR9n+v3aLzh1TTVL0R90XFVKVZd2d/8kCYdCgIQtchxRJYSbMkXEcCENfBeliFLhqzKVjBhlJtKdpAmtxbaRpDdLREHa3bCxzTIzzDMNI065wbcdVt8bYhs3uQgVzxSYf9o/CwFdytCzzDQXdMM2Bfhjph5HTFBiyJRhPtJ5gPMFKNyPBwsBErrYhxVkgo6WznxI2ZzrvyFnq+NayDLcCOUaG04mPHz5w3O+Zp4ntxSXbiwusNfjG4xpPCjNg8N7hW48ziW2OtEbgUi0Zb4RpStTfdT2puU/zxDwO5NOR9ThgraNp1xilHjUa9CvUYOlmLbeamljWQkWpaBcbqerpBnCOnAubpSyIEJdubiWrMedvcAYDPI/D1CemKF34Uhi1gHGOzWZNylkC6ST3ogTSOWdOpx7vPev1inXXYQw0lYoe5nmuTH9p7jke9tzf38nAvu+4uLzg6XFPP/Y0vmMcevZPTxz2T3SrFZeXF2Cky130NWIMrFcrnLXsdju6rlWfLJ2ClDLTPJNTxjnHxcUF3lm6psGT8c6yWbX0xxNxDjhd67OSHZDBu4Zx6gkysMCUAikGDjq83Q89h/2ecRqlMKd7rcw2ZIVUWQNFZbveCq1KFxXtEl1qlFrAbTVGLEnD325UWH5XA9Gze3xua4qrK2usLAHEN6byhNLlOD9nzmxRzUJMPc8yQ/IptfhvPn431qlcFrq+eV6CUmtKYJcVK2KEslLhQyQrwlNZWYSKove3bH1RUzRxaS8VVQ17xhhRa3/6HPnbMhRdbmEpApQbnyTZyWjAqMGhPaNaVfqvDFrdZ/kb7baXgNwoJ3FhZCpVV6M3op6pmRdjmDM5WnJ2+HZVh3tcJ0ZwtVqx6hraxtN5mYWQwevi6hK2lSTFW1evhzVJUUmFqkxgKQXTeHrqmVMkpMgwSBW9H0cZUoqJYSpOLRPnqLR/FldmQspAZEZbsFmhA0LZG3OoiVlhEgNxBiFGSBHftEgDOhBCIqVACANTvKVt9jSNp101NG2jQ+gSDEedBSrUwSKS06lCZiIbCfayrkmDxSSPVRyxiMVpdTApn/U0EYPgjUeT8a4RdfOmpdzsHCLRJukkWK0cxYVvw3kjwnkqSpi1yhXnQpkXiCbjjCUavWYJdjtP121w5prASDKBae7JRmBuj7e3TKcjU3+i/annYrcltA0mGUy0xD7zV3/+Cz58/Z6f/fjHECPerMmTo92u+dmP/4j/z//0P/Hll1/xj//RP6XzQOx589WvuHn2jN/78U9Zr1f0Q8//9z/8W46HE9M48dXbD/zDf/TH/B/+j/+a/+G//38xjjPPnr1Qg3vi9u6ezz//PiHD5c0V1zfX/MHv/wFhDMRJOg9Px1kGUFeXjCFymiYZ7gyReT4RZ1Gh7Q97no5HTn3Pw+Md4zgyK71fqbqUpDRauXcS9FtClGQ6mSV6N2p4c1jmZzLihJ1S9skeXQJMY20BPaHhKcpxU5PWUleKMSKdUUsMYJ2nsZZ5DnXw/DwhMNUuKS2vsRW2l1MmmVwNfpkNM97UzxG1Cl2wyJ8w/H13/Nqx9E+LK1UbXpwk5X7KUWy3/L84y29NY5j64jWYW4pK1Qto3lpXXMkMWOqI5wFHDTMpA78g6yVp8rt00HMlfQjGEkIgBMM8TYx2po8wDwfi1DMPfcWNxyiV2ZSpgpUhJrKdyMbhusQKC9YL045rasLRT5F+PtJ0ic1my7Nn17z47AtyjHz2xff51c//mrdvvuav/uLPRPMiTPjGS5IhTpqY4dRPHPqB4zDRJ8NoHJNrGG1DME4GwDUpsWRJnlJgHnqd85horWgIdM6zUur13WaLU92CEGUGZRhHSa5SZJpmhqcH9neBb776itVmw2a34+UXXxCRubk09eQw05nExaphs/Js5gmfIy5Jt9SR8TESjK1D+2S93xFCPjLGhN9d0l4Guhcr+QwxIkUrJ0QXJS4q7EK6pCp8OYaaqJZ9HlOqA9nkTPCNsj0ZPYfMOM8S5JJVV0nWc/W75mwP6FqWyrUUWWMIYs/sUkk3xrJZr5Wkw+m6hvFx0qJk5Gn/xDxPTNMkXYWLHc+ursgmEHPm6fGBv/nSMA9Hbi63kCMhRC6uVmy3O1YrgTbd3d7z2evPiGEmzCPH44Fu1fH5568JMXI8nXjz5g2Hw55pmiFnnj1/zutXr4SQRIX4+n6oeyqmTNN2vHr9WshDQiTPkrC2Fn71i18wDAPrtuX4uOfj/RN3t7cY37DaXjIMI8M0MowTh/0Dw+nE037PNA2M40RUQpKkumxlhkFiQYRgJGViErrmYkusddWYlCjOGSvmwJVWXq0+gUFHABRdks9j3aWg+WkecPbHWYpbMWsckwvj4QKDqt8lYKtxfaZ0WBaE0XkakfQ8Cpz+t/VLvwPrlFYzqumDAkPKUPGD8lxNSigplWbXGqRKMJwoTEr105TKhtLakc+yQ+EiXe5J6Ybo/IRE2/ls7sMsjpylu1BoV+MnkCuo7E+VNjdDKpn60uCMi6XQj6+t3+pkFmapGug4T9e1NI1nteow3mOd52KzkfNUlgZjJUt3TlWzjfB2O29orZOrHg2usTLQZiQZsEY7FEA0WYMX8MaBs/jY0JqGiFz/GC50kC8yz2JEJBCUBGAc5qrZMIVRDHgIOu+hQ9hy06Vak5UWTUUUs0nVyWYUxmbKdRRWnbJuxhhIpyPW9kjxRhTHm84Lq5PeWmMtrvF43+FcQ9d2eCcc6t4VPLOg3LNB2u+aeCVnKsVuVuNslP42FRGobFSxVtqBSoKEs2KcjTF4K/ogpYyXCrQmlhp0WWOgd0uSzznStsLakK0kot5aLrY7Xj8LrNuOFLNc/xhIToY6T8cTb776msuLC7743ucouzdN2wKIoNHtB169eMY//tM/5S//6i+4u7/l8e49h6cHTqc9cxzBQtu1JCLWG3aXO8Zx4jSMnIZRqRlhnid+9TdfMcfAqxevsRjCHHkaJ6Y54NuOaZp5uH/k3ZuvWa9XXN9cEcZAfxr4+O6Ww/EBQ+Lw9MDHh0fe393zq7fv6YeZfgicRlFsHadBAqMQOA09IQmdpiv7PuWFhYW80OTOCUJSJjeBSyVjaKywoBlnaIxgt9umrWxW/Tgg7C22sns4TJ3XKWDCbBJZaY2XDq0k1bWabSHlyBSiMFwRidlWDDY2V8KCZBuFJxiyGvRs5P7K+TgNQBIESBgB96kRN1a6Tn9/zei/4aNU1sr9qrApNU7FOdfAYHla7Trr3/5651ktVfFnxffVSvRyDuUVyoMCFDa6ZJY7uFQuP3kBShgiCfVy3qWrEaOK182B0HqyakDUkFIr/4VJiZLUJvW3dsL6VskWdNYPwXhb32CblowkCsM0kzgJHbVvWa1WfPGTn7K+2PHqiy8IOXL38T33tx/I81RJO2KSans/zAxzYoww45hxTFiiEWHOrH6PrPOUKeBywOSIc4a2XXFzuWO7XvH8+pqL7ZZV17FerSiK349PTxyPJx6ennh8emKcBKbbrhpy8kxzwORA6A8w9Wy2O65uXnE8rpmHnvnhlhWZtYEtBhOAGGh0XdRrWu+BBvLGkEMg5J79/S3NPLN2nsNp4jhH+tlUhWjvnHTKnRXNAdVewEhwarKtortlFZTuQEpZhdsEVumTrUmDS7YGuymLnyrBqRg0txRFBVOjyYYgAqRrJMmutTKPkHSvOGvYbdZcX1/hnBOGJy1Y5pSZxpmn/MT79y1DL367a0SwtmlbhnHkw+1Hnl3v2G4u2Lx+Sd8PHI4Hvvrya24/3nI4HHRQHOlQWN2zRu2mBrpzCJz6E7/85S/p+x5rDM9ununvIof9nmmaOByOfPj4EWttpf13xrJuG+I08e7je/7myy8J08xPf+9nTEPPcDpw9+EdwxyYs+H2/pFxnkWJfpZC5DiNVUGds31bJMFKVyPpPSzzQ+V+GiM6U1VvQ5Er1jkRObaWHGaBwad4ZhMWu1AeM4ZlBkPj6lImq6ZPr2EtTunLFFheKvO9lOLIQqW+dFDLfEY1gGpKpQh3Dhf9bVvtv0NHI0HBFusbfNrmPcuAquUu9D1yMdL5H2iikTnDeBX/kAqd7AJJKoPUQHXWZxT3oAGm+eTqUC++WfAKWnlMZ8tmSZAkWdAblgV2VY2+KeetrUbtoBR1z3IlqmfQCqdz2qlYdewuNmKAGs9OE43KpqWZbHktk7MMxnlD62yhdxcBL2erOqM1lhgtgayQrSiVWmsFiWQtrfF6xQ0pd/XcZ13kxMQ4ToQ5MAwzIUTCHBkm4WR3k7TDFyMgDjfo5igtQcl4U1kEnIGMl2uiFcSixh6nSa5caecaSabQLoDPkmjYxtN2a7xvaNuWrutomoZV45SyVKBnRRehZCnBaEUpxprwGlsSgaxikWIcImJ4nTUiZK+f1RoDDowra8Eseotl0ZS1iu4TawTGFgNGmTVKDGSMpWtXXGx3GGO5fzrRM5ATGCtD+dM4cX93T5wCz65vaJsG7x2tJnQhRPrhCO45Lz57zX/88//I0J/YPz0yzQM5C72lMdCthE7QegnGh2mkHwfJ360YvjxNPD49MYXI//6f/XNa3/D0+Eip6lvXME4z+/2ex4cnaWlvV7JmppFD33PqT1iTmKeR/nhg//jA0/09h9PA/jBwGgNziEwpFFJYphgWvnwsVg1kWe8ZneeIkThFUmEyI5CN0OwlJ8mbM76yi1grGG6cxYx1dy68EyzG1J7Rc1enf16BPmd/MknzS7VxRvadzUgBwsgsVyy2TR1CrUzpVkj5bEYkl46cplflGvyWrenvjmLNS1eiOJMz+07xAUuGsXRAlgTg144z21VeI3/7JVkSh1xftXTsP538qO+Yz1+gdOPLy+on0Y+QcgniRVwsRle7c3WGJyvjWtZCkGItpbciRYMYlmps1mtR9r/zXhAACaYwM04T+XRkO1/Trjdcv3jJarPh8uaGN2+/IuXE8XhgikE6kerjQ8wMc2QKmTlB0AQjoklGgWAo5MTGiM0Rm4TNqXOWTdfwbLfl6mLH916/4urygs1qRdd1FGanVePZdy3OZOI84kzG6KxhzuCNBOgxBWwKrBvHzbMbduuG8Xjg/vjAKkOXIyuMFJ6yEqywDGFXWHg+W086hzUeDwJHXm8Zhpl+ijz1Ees8zjvatsE5T+M9TSvsXt65OoNQkwXF75fQoVSOY5IChLWZnN1CDGLVZum6TNbivVvWgzkLBM+WdWXWzGW9SLJZja0WLru2ZbfZQIb9fi/xXsoVRhX7yNPjEylG1us1lxc7OtXDmGNgfzyRshTFLi+v2B9ErK4fBvrTiTALi6A1RnSUvChoV/XsEJUZSyzk4+MTq9WK65trrq6ucM4zzbNAn4Dj4cB+v6+U6b4IOTrHPAce9wf2+4MKt86EMBHmkeG05/Fw4uk4cPe0Zw6BZGwtLlRoVKV9NXV+ImtSFDQRiSHq+ZeEQZ7vcsZZi4YAQiyiquHWSWdu8QyfWAh9Df1XjUsLHG+Jkchns74ZIWWoXXVTE41qv4BzfY1inUqSUeNuTXqXuewl8a4h8W9x/A4djaX9UxwtSaAjQIUPQa6CbpIJOWoaXgyikYX9bcMum01aeGWyrnxQMcTnVaHlsdKGNE47LBmtBMhrFWi1dXKOMScNIuSccuFuyCr3bg3gzhi2wnLBvJffWzXyVni+x0GGWa0xQlkaqfL0m82aly+ecXGxpWnVCJiETRPOOWEC8a1+7kwMEynOeGfBSiW01WHUFA3RCADJWkdRVzZJEGs5Z+HYzhliJqegFSOtppKYtfRqrcF3TuAdMeJbA6nlWVyu8hSfCQxIFVdjjPRDTwxC8fb4KBUF4bWOZGOxvkGIXSGEUB3hJ/Mb57ll1Siw2KxJi1Z6UkyibkskmUAyJ71tpn45K4rSbVvody2db/HrBucdeBEWbJzFO+2mpEjMnogkS9Mswo6rpsPaSDBG4HuIx161rWiJtLlqIDidv7DOiugaYJWjXyqJ4qxStvSDDNL5pmEOqKqmp/NbWDd87/PM/d0jjw9PjIMY3DhHDtPEMDzST3/NF5+/5ubyAtN5oZUENteXjCnwH//iz/ny7RtCmLl8/5z11TVfbLY8Pt5jLXz22SuevXxFjIk///P/zOHUk3Lmxz/8oTJSDRwenljvdlw+e87D/kDjG9puxbOXHeM08fXbt9w+3DNMA9fXFxhrubt/kj3gHT/92Y/4t//re477J67/xSW77YbPX79inia+evuO9/t7hkk6b9apMy1FAuR6xSRQBZuyrP0sMMlxHBmnkRBSXRe6WIRGN5QEsZEhWBqanCpDVLELUwwYTUZjSmCs3keLsRmsZdbW+DlznQhkirq4941WIzPJG7AeRyNaHkF50rMorJT1nRQ6kcpAptqZNM9VfTVOgQqvMFI4SWnBxX93/KYjLwl/dbYa7hfbo4/Vv8gLNKEkHubcKKFB5redaV6SwPKbUmgpR3Hfuf5BST84e/z8h+LQpfBWTrMit5PAYEcHzmYO48y6MbQus7EOa5WKM6MFFYFkmYWfQBJjZmY/Mpx6utUARihthdWnVFsLYUsmxkzfH3k8HDBty+dtx6sXL/ieNRz7E91mSz8MvPtyENYhjODeE4RsGZJhwjM7JzMZriFbGQBPSbqSpEieAzmOkGcuO8+qdWw7z4qIjzNmHrGhwwTLuW7EzW7D5WbFq+c3vLi55ng6cnt3J6J9SjuadA08u9jy7OaSH3z/M7y3TP2RX5qJ/HgPpyPdOJFMkq+klVtrK8eDrgZJHjUZcTkznY5SxbaeMRrGOXF738t9NMqeZaXD0TQNznspGDU6f+mdwqyc0MVqghBjlusYM3MQeFW9R9ZilczGIMmn946Ott7Dgp8X+HOZKyyLTouCGkR7tNhkQUqRMih+sd3Qtg0xBh4eHngCToN0WVJOPDw+cjwe6Yeez16/5ub6itfPr4jTQJpHHg9HnXWM/OKXv2KeZl5/9pqrq2ucteyfnjDG8OLFC56/fAnGiE7G4cA8R7a7HbvdjhQjb9++pW0aDvsj93ePdKsVbddxeXXNarXm7u6evh94fHri2fPnZGOYYuLp1GOBZ68+J2OIYRK7nyPeZi63Lf3pQL+/gxBFFck2opWVJEEodMXFhmekMy4FMGHZlC79pGQ4uQrAppSwk6yDVbdi1XYU/TWyaFhMs3T2U4rS+bKGnJ2afVPvn8mKBlJKaYnnotbUNfnQYfBzSJOxVhAAer8rXW/JQfPZQHqm2sylHlegf2cQXvVHv62Y7O/Q0dBtlpchSkmxNLivrB7pW1ThWRdvRPsACBTAYIwnJR2m1KqfOXtOzhQtrE8MORTGU6NJA3XQuDiVMuREocE1i/haSRCkjalcyfrO7uw5ZVPjRLXcGq1GaEfEatspGUPfeHzjhPlDaeUiEZONci3PzNPEql1VPLf12j41Qec/LFZBN8ZYHYTLYDNzVEdYElMDyQRAtdcV7gFI61yvQYGxC22ruLtsVTwKGTITpySlrJwTUW8tqPKGRbQSjCFagzUrCQqjaE4cT0cOWYTPCvStQNs8Z9Wgs6VUWRMMZ8wc+Yypqzhz6ndvDUHpeQUeph2lbCrbVYGSTW7ATlI5yg6cVUiWk0qSdJKU+m8ONfE02WOsdsBQ1Y4sm6yJEYOohhpr8S5hs8ElEIJGdN1mCVwsuCQrK5UyVdTtYbRK0mThbJ88u3UHYcs+JakohqwVuUh/PPH4+ABpxl5fkNoG4xoe9k9MYaIfBwZdZ7/61df88Eff5/XrV3z45h273Zbt5oL1xQX7w543H75hHCPWOnzTctl0XF5krnfXakAsT/sD1jpWqzU3N5d0XcvxtAMS8zwS046n/Z7b24+Mw8BmveJHP/gBrz//jPzqJe9vP/L4+Mjj4yM5zjy72tH+wU/4+d98LWwmKQtlcAZXVH5LOFZufa6hFobS7SuBhuzhUrmJ2h31pWiTskAnrMx8TfNMiJEpzFpREgfsEJiiqQJY4iTEDue6+IpwojVn8x6osFgSmuWIBCqF5MhSIJTFEQh1sykd26h7zgiMpcCpElo0yRAqlPO74zce6oCXeYySAHw7AakW8tO/P7NF5785X4NVm+fsCec+6TyZqYyE1YSVP1yKZ9UGQYW0LIyIqlZtjQY+0DlL1zraxmIaTzCWMWZGZRHKxmOtV1rkGh0LFFHPNSEV/zhPTGOPsYZp1Ylej+4To3DcaMU+hhiYhhOnY8fj4yNt27BZr7l+/pznL1/x/OVLHj++Z0iirpyQwljEMRtDMIZoPck6svMY45QSNoOVmUlvYdU0dNZzvWlonaVzFkeCOBOmgXFoICVGa4RFK4kSt/Wepm3ZrNcqxBs5nQ3rGhB4SkqcDgfefPk37C62mBTx1kLjMY3HTlTtqEDWGZesM54Z7bXX4F6spJG9HAJxkMTNREjzrJ0bK/bAGkEIBBELHZ0kFgVSZYxVf+L0vqPwtlShU5JoeC2mFDY8ZQGKSbUoJKE5f12ng741ZivrVSUCMtL1sWQwTkX4JIC1JuOtsAmGeVPhx3MIzGFWSFHgdDrx+PQEObFqLM4kHLkWs8IceHw6kGLkZgpsN1tWqxWnw57NdsVqs2G93XE6nfhwe8/heCRn2O12bDZb2qahbTudjUic+pFxCrTdzNXVJW234sWLFzStzHceDgf6QZgLh15mMr7/+ec06zVt7nh/e8vj0xNP+ye22zXP4xUhRvb9SD9O3D8dhKY+gXHu7JqVjb2shEJ+kM/XCyxdO2Pq3GzOpZgm+hvGOjCJGGTvSEdEqd6NJB3WWlrfVHtRlbttYYoyJVxWv5lqfFhmSM6ThCUBWf6dkc+ay2P5bBQAQRPlfJ5oyBt+ilD6u4/fETqFXNQa/ZcIv7TwtIxSB8DLc4AcIHsKuK0kFTlNcoWQwSnKkEzhf1ZNiG8fVl+nOuJcuKVkAQjvPZpoqAEt1QCneH9taXorG8zpAHRJMpyT1haNdA9cwYEbwER8tphsGGKi7RqaznM7B7kxKRONQHX8PDMOA21judp1SqxkcI1s6pQDKUe9Jq22bC0mB7l0MREKsMQIvasxWSr8uXSA/FIJq1lrqdplUppkE9Rra2t7XbpTKtqXo94vuW82S4vWG+muJOsw3sp9SpnGWCAyzifmaJBxldLak8StYBgL9MDUZEkf0zZ0MiXhQboJpnSXJLFsNAiOZB0+l8dDzmTFRpaVYk118eJgrawB72Qje+eqsrkLanitky1hxQmSwieJRmwaLCIwaJ0nGcH51yqGLvsi6NcYU5Vcp5QgSZfEuhJSB2yT8B66wZE3KzwQxxFjMhGBCOUUmYaexwdDmAdWKw8m4Vzm9uGB/cmzPqwYQ2SeI7/61Vf87Pd/j88//x53Hz5weXnJ5599QbSGMUycxhNptjTe4pxnt92xaleQ4HQ48HT/wP3TgYxhtQ48f37Ddrvm2bMrTqejdBfmwMfbO/7iL/+Sh7t7ri4vWK1a/uCnP2O7WfPnf/b/4+3XX/PxwwdevHjF82fX/Oj6mofDE/EuMp9GEeSLYNoOoZsuJRbKQq4/WivYYeENtrJ+nZcFHCaSQhytmiEyjFMQh57R+RcZVDdR74t1ouxuJNkgG2LObEwrQYTVSo8OAJbqUknYRTdFbb0JiLpxxCY10SbX50aSJq9Zii4aSMjHNJosp6qtUWxeVIG074bB/67j/Nos4KkS/peOeD5LFAqk6dPERIKJ6n6/Nce3JBlL5+MT31SSknpWS9LsCjvSmV22Cp+pVUs5Ae1QCAzUG3BGoLPrxtJ5i2sNyWbGlOhjwicppOCEACMTajC8fC61gykR55Fp6AFo2k4CWGdwjcMajzHgjBTKUpwY+iNYy+3tR1arDuccV9c3PHvxghevPuPNr35FmIN09BR+E/DM1hKMEb0M64RN0YjfcdrVM9nQesOua9l1jme7Dm8QmvGYyCkwTQND70hBmIXmIJoayXq69ZrL6ytWqw6vwXbx88MgdOpYmUk47Pc8PO15/uqFaP0YJLhvG2wv6IzsbBVdTTorWmnW9UIajTUcGZeTaIuMgwzWJyMQXTLJZqleKxVemCPnN6UknKXz5p3D2SVZKIWrsl6aJtYOSWGlqolGaMDobIh2SpxNJEU8lLimtLcEOizrIRWWQLPETVK0TTgL2/WKFCWuidPEMAkioKhcD/3A0+MjIUx0jWW76tisWvbHXobz+4Gn/RGAYZywvmG92RDmieubG56/eElCbPR+v6cfRqWvvWK33bK7uODm5obT6cT+cOD2wwMpJXwzst3t2G7WvHr9WoqkKfLuwwdub+/45pt3fPjwkauLC9brDa+eX9N6y5uvfsXhsGfoe25evKTtOtpuxe3jgYfHJz7c3hGC2GWbNda0SgOrMNlKKFKuKwuLVEkuqtHQrwyVbnqeo3TQjSWEpPNXKjGAFFBd6XKhyAm1GZgy30N9H3OWZCx2R4tk/PrsRaHxIZsKuZJkRdntKGgOpHN/xk5abFuM6bf2Tb99orFYTz0SxqU6XyBWvGDz/fK8auSXMo+hEO4lVbWTC5P0AlurOE79EOZso9QkwOvwk24s5xyb7VYHsDxNK5u1Tu8bI8ZYM0JKOwoI8ywhvm/qMHg5D2scWdDWCpcRpobkJpwmWU0E37Q0Tea4P0BOhNmQkyMbw5gFIziHmd3FhtXKs3KOkOa6qMS2FTSt0SDdKI2YBFoZ1XGoWG9H08jw+DiHSleb5lBT3CLY41PdBihtDtllMBJAWWdJ6VM+ZWOMcNDrMIwxRiFZMgBrrOHicoOxEizf3z8xjpFpiMq1bDA62O6sO6v0iVonKB2p9XVdyPtkrNOh7PJ58wIjKRQEYogNTYlPy/JDjEQu/zNRcJXWShMDGYpfhDaKITBweKjJgjViyL2zdCcZ7OuaA853uKZhvWlplMd9s+rqQJ44B/n83kj1KmvePSMCQtSETyjxrq42tM7iVRBwfzwSH+4IaSIRMRkO/YF+OgGJ68tLri8vSHFL10JYzcyzI+UW31r+y89/xX5/4Mc/+jHPb15wffWMf/vv/wN3D/e0zQ7XOlrvsRkaK8xmb795w+nUczr1zEHmZ/anO2Kaef7sin/+z/8RTdMwjhP/5//T/4W7+3uGcWAcek59z//8v/xv9KeRVy+fY5qGH//s9/nDP/kTfvh94bD/xa9+xb/6l/8d7z/c8t//D/8jHo9zRlnODDZbsCgsQekAjaHzAocKQaBQMcp3NydZn0nvX5buYrYqZuVbMJaIwXU7SFFb58LOk+ZBHAlGxRjRIolQIJ4HhW3bVkroYlgdirHWhDNm6Sw6I68XYqTQNGdT6ASTdjS+pdhLce5grBUjTsYbS0hB4DDfHb/xqHnD+c/lyKWqizLiFReqENrqKE2d3SrBlvzbKOW2VInL3IMpLIg1aRA7Khh8CTZcsQ/brRS1Gl8DYe/Vp+n71cSlVC1Bu64JUsTlhM0JayIhz5xS4pvjQEdi7aA1DaLDFyHHGihWX+ItxkkRxsSJOCae7maG0x7ftmwuLrHOY5zjNIyM4yRYe9Pg2hXvv/6aDz/4IS9evuR7n3/Gdr3hhz/8Id989SXONzKTETIxG0bjmY0lGsNoRHYwYnS2WuBHjoS3mY0z7DrH5abh5mJN66TLMU2zujER6jthdMZEtHhcu8I1QvXedJ0kdE3DertlDoHnr17JTEuMjAr9HUNijpmYZxhn1girlfGerGJwRpMJmSFRN2HO1kjOFMBEi/iSaR5xGZrs6CyMSuMdzii4y309p76lFP8QSLQs11zXxHnB0J7FLElnI621sq68o22FcMY3ns16JarpjRDROF1zOSasga5tcc5jGksIkxTScsTEZS2SpXjWeMNuu6JtPM6KyvdDlgJYSJFE4ng6MI49JgZuri6JV5eAYbNacXnhyK4lzDO/+vKNqm9nXr96xfX1M66ub/gv/+XnfPx4R38ceP7iBZvthovdBWTD/mnPYX/geDyxPx6Yp0wIkXF6wDrHy5fP+Yd/8keM08jhsOd//jf/hg8fP3J3d8/T456HhwfGaeRf/Ok/4bNXL3HdimebNY13fO973yfEzPE08PNffsnXb97x1z//G9kvxuCdr/erQotSkvkKK4lGCIFgoxZts3Y3NEZLVNthjVNkhddCuYwItE1HdEntvhSdQ5gJUQQRY0o6d2pora9EQSXJke4YYKy8b+ZTvaic1fZZjHbI5GOUGNHUGF66H7EmmstSWIomRWvNWk02fouu++8wo6G1mrJBoBpcjczUSC5ZllTedTATI5VILM5JMICxVTxOEoEOaySgKw7dFgpKs1QqnF5YGZT29bHVeq0YN3mPgp//tjNYzlESGa/BTWMddQC0JhqGGJes0Wn06ZwT2tskF7HxlpA863VHzjBNSQN3YfEQGAf0/YhxGdcYgXQhVXxbwuc60aOXSxOcpFWRxDJolKNUtgwL5VqhoVt6adr60mE9MWqpNqis85TQXSBkVrikazgvJWJFD+vPpfsiSUHTelbbNW0/kPJMmFT4plRP5AbXyqIkCFolyqi+Ssnk5X2chabxMvDtnWTVMRLRAaxQ4E4wpQI9M3VDpJRlgM7I8ysfuynDTRmjFGLJQhmKK61qPWUEQSCDvM5Y5inifMB6zxS8JrmeYd3JfI8xZE0e1m3Lul3RNl2tIJWqotGEagkwwHtL13oMHTEHtmHNHCcREpoDMRkdwOzx1mONo/Et4PDeYE2H9QlsYBwDj/sjx+NA15ywtuPxcc/xOJCz4/Lqks1qxXazwVkrWhuPTxxPPad+4DAFphAYpol57slJZm3meeZ0OvLwcM/hcFCKRUPTdlxd3zDOgdv7B56ePtK1Dau2Y5wSh8ORb969p13tOB1OYniz0L7K/0wRGq3JoqnBvj0zrIXi2ta82cBixM3yZfMydGr0f4X9ydiMwAZlvUSl1c2Szku3y50PV5paKSqVwWrLs9SzCnV3SQqMXXDdy/dcqgo1wM25DO/q/syLTdSc97uOxu9ylP1tfv1XtasgHrPaUoyujzqoW/yczrJ5oYB1VlmCclaYpihXO4W9CFGHq+yGMmRtWa/XAlHS55kCb0EDSjkdzXDkQ1TWo5whWWxKMh+QqB3oY4TZoDoxUggzOq9hs+gCOaOzlM6DLzTzElTGlBhTYJ68VK2d/P2pHxmmieOxJ2SDdS1hnCEG+v0TjcmEScQkV6s13XqD79ZMBGLMTDgCQoggcFf9KOSquWHJAs8xGWcyjkzXWDrvaJwhpyBdzzBJMJRRUd0a/ghbTww0ucU60ZnquhUZ2MXEFALjPLPve5kfbFdkC2EaedjvsSFBSKyNIyMq5ens64x7R/9VaN3lcBoSJQTehnFcbD1NzEwxM8Yyl7VUfsvryH/zpxTMpTBb/12SDTQOWWyGNWB19jLESIgRN8sam0PAO0ej2luF4CRFKepsNxtW6xVd2wk8KOvsG7mA15eqOVJso3FsNyvIiXmaCHGGWTpMKUbmnDgdj3QKdSrlwPVmS7va4PxMnGf6ceZw6rnsR9q2x/mWh4dHetXouNhdsLvYsVqtmCchJXh63HM4HtkfjkyTMBf2w6DXJfDHf/z7FK2Z29uPPD0+Mk4jvvGs1isuri4Y54m7h3tuP7zD61xhP87kbJjmKOfQ95rQSUGi/FtvBJYEdikQWMsSm+reTeerRovkVhMNqz5q6d6Lb7JmiVFJWeJjvdcxRsWzIF32gs4piYbqc5Q4oq6sc5ehsdiy1Mo+Wn6fVZ4BLYh9Aq06L8bU1rCB80T67zh+h0SDWtXOuguq2Fkx2MUxWqvG3qiKdQllG4xxdKtWpkGdxbdZYRGOrt0KdalvNJDMQn2GOAYRDrNaHU+aDLhl03un1R/JyqT9pDfMSBBbuhyhBuJgO8Fn2zNDcNbxEiOuQ5w4yeqt8xXFkTB4l2h95vrqAms9Qx+JQZKMkCPjNMtQ1dOB5DbYzrDyctNMjDgr1yam0rKSa2atxTjLNEWlpE3ymYwlJh1qdgLDSXXotIj9CDKXnIjzLMO1Dtksmr0aCoOVE0iPhTAtMwvZRgnAidqWF1WTMveS4oxrLZtux3EYSfSMY8CZpIW4pBcy12Uk11hx7ikqrEkeK12ExsJu03Hz7IarywusgWkcBd8YI4f9iZRkaO7x9EBOYLMlTNrmCwnXSvAaEpqlJ8Cp486SKhnRwaiBoC4LsiGhfPQpLcnm3INrlHggUU5403WS/JIJYcJaw8uba26un3G5s6w2a+GeDjMpBpyBppGEGANhmmk8uFWD9wbTgGktcxw5HhP9NJCMJMKH44kYMkMfaP0GckvXOjbdSpL4PBOz4XgY+dXffM3Dw5Gryz0f3j8wzgEay2effcaz6ys61/Lx/QfuHu+4+3jL0/HE/thzdzgxTBOnoefmcsMw9ByPR+7v73n37h3H44lxFDjeZrPm5vkL/uk/++d8+Pietx8+8O/+3f8qA6JZIAiNb1mt1jjbEkKmsZ45y0oQGyGlilS4rXOSoM6qfamQRiePZQs6lImxNKqD0uHpjKc1jhREr0LEDqUa7LJ0lJKxGN/KQGpMQvschZEkZ0lavPe1CjnPM957xbOLlkrWIFCKBZqaZ5ingGkcrnHMikTE8EkhoDRPcknGzygusQnXNDpjpfvmu1mN33iUhKJU3mp1Th8rTyhDkOW7FJ4WjLx0GdqaEJxDaLvVSui03dL1dkpX6awVdWr7KRzKFHVgI4O8pYO1kF9QC0LO2gpbienMPlvV0vAOk3VuT7gxSDlxwONTYMqJ6Bwt0LiG1giEzHur8xfaDbcGnMGapPj5yDiInTs+PUohBks/TkzzzKkfiTGDsTze3vLw4R2b3SXz6cBmu2G1WtGtN6y3l7TbnmMamHNgSALgShhmbTpKUakkS8Iw5U3Ck7A5YBJ0jWGtsyjTmIg5MI0TOUngJxpKXr50ZmsaB5q2xTvLatWx2mxpuhXON/TTxKkfaJ6eaNdbnn/+BfvTkcf7O95+/TVhnBnnidY6krEE3aNRzVDZvKZ6ZU3cQP2zJHHWOymsNB15t6EPiT4k9v2oMw0yo1HhJ7omCzwvZ/HFpXJR31pjLWm+L1AVZ63AokjkmCEaxnlaYiGdRbTG0GjXxxkhybHGcHV1xbNnz7i6EtKOTBbiDGVA8tbWro0BjBPYttttabygRUKcoM+VuTKlzOEQpFNiHcMwEZPh4gq2V88gJ/YP9/Rj4O5hDzmzP/TsHg68ffMNIQR2mx0vnj3n4vISaw37/YFpmPj48Zan/YH9QURdp3mmH3o+vP+G29sX/NN/+icYI+QFb77+in4YabuOq+srXr58yT/5Z/+Yu48f+OWXv+I//9l/Uk0j8U3OOpzv8H5FiJnGt8SoSBKtfuVyr7PA/USEV4pP1lpJXIwlmoJIKX8n98o7J5poVgrpS/djCdOtBLSSvFgEyl51O6JIDiiroreu2j6hUnYV6l8Ys0phTJKmXJON8nlKomEMC/1/jBIrl2RDbWkZiIcl3heipfhpQvMbjt8+0XBNNc5S6dNqdiNMP41zeJ17MN5jjMfZBqsq1sZIi0h+FuVrI3yQkhikWI27hLheY9NipaBxWgVGgu4MCkORL+/AmDLc3Uhl3Ii2BMiiqVWJHJcLjSZP0ShGdcn0pPI91+ppzpFobK2my402NNlJZXQlmgjTxcz+0JPniEkZo0Hi0/0e4owNM831BU0R9YlRAifjKkvWZIwKIcWqbIyRqrZgvEdsztikrWAN3m00KjKYq+PAeQmkU8IYCZQkCE9Yk2gSFLE0q3zJBpiTsvtYSwryuLddvXa2VHlz5mZ7QYcnDYlTfxKBwDzLmnCWOAshQC73H2iMcJzo1dbFncl4pnFm/7DnYrWlW63YXe5I3pEM3DwPlOGqUbG7OWbmQRiwjkMvVHxJWCHiPBNDYI5zuSyi6YKwTjnF62cVUFociyZcOuAi0LUoWg5lURg4zXNNllIOYCCGxKmfedye+PzzVwKzsjoUZrS9mlR0MUeM8VgvNJAr43G2I9zAoTtylz8KDM06LtZbdtsLdrsLXjx/Ttd1dF2nxAaGzncYZqxNtMbBHJj2R55v17imYXd9xdtffsUv5/9Cs2owGMI08+Xbrzkcjxz7nn0/YZ1nt7vge5+95vPXL+kPR1pveHa1w+YZZwJd2/BP/sk/YLvd8jdf/5Kf//znfPx4y+E4SRKPwdiGOcEQRjAzOcGcZO7J68xT1NY9Wu011td9IEOGDY21yqzGp51HYyq5g2tl2DQhw9nZCO5arrFCHkpyANjGYxvZKzF65uBJIRGQ80nKoNd6R5hHXDAKY8wEMviWsphtllVjvYjzzcNILOxG1koVOSdxCGr0QxYtkOwgOcGYZxzGdxjjSCYRm4Zsl07bd8enh1F4Q+GqF/NtFKcukJLSeZSBWod1jXbGFdPuyuOu2v8CO5XAzlTfVLlOavcz4V1S/7iwFlllajQItO48sanVTHU1JagDqZKLzVbbWsNHpVy1HpM6crOii2DSDGlmzpqBNPKzJ9F46Q47ByYLjXTMmTgLXIYoSa5JmcRc3gY3B3yItNOks6EGQiaOA8eHe/6qP9Ku17TrNftx5jTOzNmQmoZsHDkEUsyEDMZLhyWRVUFQYKWy1x2rdcf1zZZnlxs2F1vCOPDx7pGnx0fmOWiQI6l5NkLG4ZyX4k5ODCHSKOLCWcdpmmGW+cVD37M/HPnqm3f4bsXtYWC1XXHqe+6PR/w00MQZ3zhIAn20tauQiVpYFfthqHotRqr1pgR0JoMz+Nbz+vKSoMKEYxIfG2KqA+rTOBF0mHqeZ51Vkyp9CQgLrWqFwBipfS8YEukKiS+Hb0d7UYs8hkwMs6xb7fgbRINinCYOhwOvXr9kvepYrztl3BNIlFO63JRLUVcq2G3bcXkhFMPbvufOPSrLFezWGy6vrri6vGK9XrNer2h9JyQ31nNz9RxvDSZbSI44ZWY78ez6OdmAbxu++voN8y9/Sc6Rrm3JOfH27Zc8PD7xeDgyzBHvHLvthp/85Ad89tkrwjwKjNw64hxorOX64pJ/8Ef/gNV6xZs3X/OLn/+Cu7t7jseJkjyiNtuYWRAQWaC5xro6Yxk1CEc1tM6L22Bom1ZjuDKThxaozmBvxqoNApQ4BGMkgcOAMlRqZCYJjikTYLnS5uaQCFnWUymI+zRjY0l+5O+TUbuIxSSNsfTex5zOunV6HVJBkmjySq7QKqAikDCe5BswMhYQmQlmYWX9TcdvnWhst7tqzL1Kv2OzCsw5Ot/gfUk0Wh2elip9wdo3igskWy0BalVQ6cZKASilXIXaYpgrdbW31DZzkHuMK5bfSPupdCysBn21DqGVSVNi2tKZ0cVCvaRqQCgZJ7WqYAqbktWZE3O23PS9G+doG8961dH3ynwRlyxyGkeGHo4edpsNtgHrjFwDxPCWZ5c5lZpZIvY+66BBYWsSo1haXVmilvLhiriIzg4oPVc1mAKZzbVlltU4meWyLNUV0BF+e/YLZeDICJa+jaxXLdMsQn8mpeWiV0rjrKJUijXUhZ1LfzDLeceYGIeJoR/xtmGzFlpAnCW1Wt1Jma60fWNi7kbCHHCdE2aMEIU7e56Jc2CcR2VLECaQlBMuh9r2JOp1KvjtcugiLFXJ8vmzTraHpEEmAm/LwCmNWDw5WS4uDqxXHZuurdc4JulNlzUNpdKa8VisbbjcXQo8KiXp5jlJNDabHdvNlvVmoxhdr1VZo63wyFkNohqllAJDf+Ldu3fsjwdc57i8uKTxnmHs6ccT/XgihkjTbLm5vODZzRWbzYq3b77m8nJH4x1tK4KKm92Gy90W6yxv3n7D/d09+/1BoX6ykixCmhBjlm5b2WNmwcTXtVeCvLL21PHKQB6q3M6nlaDyGoaFbU7Kp9oRKevKLOXvbKTDqWswa+JtbUN2msSyVByxJcHXTp3JgqmOUYe+JdGQ4UGWeY5ie7S4oTGK7oEz5g5jZG7K6JipbcF6FgHBv9+Y/7d6bDabWgAr0CQQlh5n3RmdqD9LKJoKP7DO4X1TE5XaeThjw7PFJlYMf1Z9Hi2LGB3QLGuNwnaot5alAi4wh/Oa4vJd3tvUn4shLo9L5qFdPQy2XWOih+hIeSbmSHQOmxyGSHAJawVGKjMfAhnNynBWRP5QOFYxbyZGbIz4FGWYORvIQt8c7cQ+J1y3wq1WRN8RjaXtWja+w8bMcDpJZzxECqxDI7Bf+9TWClzLOMeow8OPTwf60yBBn1FaWwzZCGzaZWiTDGOHlJSdT76CJidjCByOJx73B+7v7rFNx5wdV8+vGaeB4zDg55k2R3prsQmMWGxg6cJk9Q2mXP6abJT4QtZHMS+Fxjz5ltY47ZZmpqkjhMA0TaojISyBQYNIEc/VBEd9UwgKec6ZmGKF8S4+SNfqWTqKobZjylyYrK3Fn6UkA9c5Z9abNWRhroqpzN0mgesZ5fQpXUCEAMZax2U2tN1K1qNeoO16zW63Y7e7YL1e0zaiI4J2El3TYlKsy26hvJeAPowj37x7x/F0xOTIzc01XdcSwsQ0jfT9kYSl67bc3FxyfX3JZr3i44cPXFzsZG50twPgcrdju16TDdx+vOX+/pH904ECC1/KBhoTJfVNWYL/Cp88i4vOnAmF1UlIZqBtmwXtU66ZLdpzC2NUjagMLHjhZU8Y/dlUJIgyomYExZILha78WYGHFzE/CZ/O7Ews9kveMyVRDS8Msg5b4zjMEuuVORPNMmWW1jbgBJGUKQX3hZnrNx2/daLxRz/7gxrEtE2DZFlzvV7eecopOtfWmzGHWbMlI6hNreLGHASOg2DTV21bHUTSQI+ciFax01krl8ZhrMflACbjGsHUYqTlLLPLVsmtsuBOvdfTKTMBi7HIxfhpSzsg1WjhQU41Ecopk0PGeYc1whxU6NYkUIzSGbCGbdfirj3TMEHOjPMgFzEbQpp4OkwcxyOrVcd2tWLTtXRa8SpIr4KVlBC8iCzJa+QQZFGlJSPNfhH6MkobKHXctJj1mrhkKm9GFvhSCAPO6JCSq8sdbxxBh5O0WacDZfLqMSVlzJFK3apb8eyZIeaIGwxmFIGpOcwyFA3knKSzhWgYFMMZ81w3R8xI9h4nvn73gctdj29XdCR8Y2t1RoIAafc5l3GdxXQtVxerWv1xSh2aogjFpSzDxEM/CNZzHJhH1QKxA3MU+r46LIVRErS8BBr6VXI3k3UCoFr7zJwypzwS5sQ0DdxcXvL65XOcF8hUignXFEYlYRMjyQC5ZNWO3cWlru8fY5xAPExWjHk2tcvhlJcdYI6yPqxJDDFysVpx+eyGv/nma75++w1/+V9+zhwSMSdiHPjZ7/2MV69e0nQNbgLGkYtVx6sXV/yLf/zHXD674NSf+L//X/9v/Ot//a/4B3/yx3z+6jXrzZrXn7/i8WnP/f0Df/lXfw14WteRrdIuy8KTc61VFMAtFeIQ4xnbEhT+8Xolz1rMq9Wq/lyek5JoaGQgpKBVPtlP2TqSUe7+LBCpAkfCGKFkTlm6dVphdb6p7+2sFZy7zaQQyLPwnaecZG+OgURmtqj9E00MMpAyTndhjoHWogY/MRkh/B7mIN1f53Aq7mVsh3VrgYlYyPNInue/10b/t3r8wc9+qkw7kiychelq43PFUJdEIieEuz5nUpylU54dVuGnQkQgrERN62uQYM4gCJPJCjnIdbAbY5UdTaqzC++8Jho1mS4Q5DOmGH2eOUuiKz2y+id5Wq7nYZyvcKiUHIEkjE05aNU0EEwWiJIJeJdpmgzTRI4B4iyfJ6muRXndGHFJYE2mBl1Ily8YUp8YhxNh7/AXV6wurnj5+few20uGCH/xyy+5fXgkhJ4YtYhmJLCTmUHpY6ecmafIw+OBvj+R+gPzcGI4HuiaRmEtnhCVBQqDaxqatqOZJoz3NDEwzyL6GmJgGEamaebpIJj+p/2Bj7d3hGz4+t07rl88J+XM/f2elsQK2KZMGzON8Tq/qfvb5iUIoxQ6l0JTDfQ11shhJk4jddLBGyFDaRyNX9X1KP9QyIre3xBC1WqYZ9HsGVSfa5omTqeTisPJ7EpKSd6zoitsnS/KusYK6yS6xorNTTHRnwYV6Z25uLygHwYhNVEthxTiMl+gcLWcTf355nkLRvWIkNePMepe9CKep9BDUtLgNpGCgOrGEFhbi191vPnVL7l7eODD7UfevHnDOPSsu4af/uTHvHz5nJubG6Z55vHpkWfXl3z22Wf8iz/9U6Zx4Hg88P/4N/8Lv//7P+P7P/g+//Jf/ktBMcTE3d0dD497/vrnP9cCdqtUuZKEWesogoypkMMoJXD1M59Qu8paPp+5KQtj1a3r84tvWtAxmlCVJEQJj5J2xpJJQqFcKTlZCsolXjMW3y0xsjOSCFpyHeJOMSqFrvirlGFOggZyRorwhTTIYBQR5MpH1kRF1v4coiSI1mFdh/UNpllhfQfaQEhTQ7L/FTsavkExqIVRB7K1eJxw0VuLiIcknC1VWou3LWIYoWSD1llitoSciGHG4nFmybxNzjrRL4Y7mUgs5e4MOUWFUEkFMYWFf946tNojzt5kJyB9UO0FvZh2KQqkFChJUq30uKJLkUFvqETaulkqv7XR4Wv5vNZmnHO0rWW7XQOZcZ6IWl0w2ZFzJMwzTwfhlnZA03TCXDPPRJKojuSGpF2ApbNCrQBkraglKVXXxgVJcHMxoUOJYMowOMjGIoPCNgTH4yVlNkmFDZUhxBgZKsxO7itSlc762Suvs1Z1MYaGhu3FFtc4ksmkcSIhjFGiQi7nIShdW4djzXkjJosjMikzTSOn3nD/8JErc8HKdNI50+6VL50BDFEpgaWQrSTKGQk2rTxSBsbXbacBa2Capesx9AK5CjHobEYmzEJHF2NknKfqdKZZWErEQCkUL5d5JdlcKQSmGHF2Zhg9x2HD1eUO3zR065bGFSYKh3OtwA2LpgdGudhVJ8Jo5yfm2iVIRozeNM/E/kSIgXEcCdORFEa+CjPrbsVqvebDx48cjj2nqWCeM3OEUz8wDAN/9Ie/z+PTPR/u3vHjL36Kt57b24/88sufcziKaupXb95hfccf/NEfc+pPfLh74O3X33A8njDZqjNLZOPL1a8FTDG0qcTjZ8lErnMZlULSGFXe1spQKbVkFvKAAmswpUKVhV5SUnNq905JASoUQZOaHBWKgqmVpZyzJmwCl7OKwzdZWIZwjsZKGOKyiILlJDAG3XzMaQZt5OWkw+7WMKsjyzEQrHRE4pyUCcmSo+CgrWlIArYRSsksugTfHX/7sWpLN6JAkpB1YooeSqkOyq+csRjVoyjOvxKFYIhRZr9SikplKmQUBfus/W68JtPimYrhSsuwZO0Sywkl7U5ZUzrmZT+UJNtozess0dDKaa7rFrXB+p7WSsPYqh8gE3IiJYfNkZANPquPsR5Pos0Rg9NhOLWSJuqc0AK5Mcigdi2savicpR4ilOs501nYrVo+e3HD5sVnTNlw6AdyEr2A4zBJd7B0aozYtZgjIWWGORBS4jRE4umgGheOrltjlSmQwlNpjECyppl8OHKaZk7jxOE0COOkb5jmWeCzx55+GDj1gwiWAWGC+7t76TJo8BsMDJP4IIerUOtkkkK9TL2/JucKnVsIAxYUQEkaKGSnuXTGF1RCse5idnRRGikylrWy0s533G2ZZymCnfqTwqxEXDYmSUimqcCwggbAVEr5RdFZ100pjuVcZwDGYaJtR8ZhYrNe0zSt0Bjrnmp8g/dNTTQkgbF1FjemVPGEQc9N6iyJFJLAw+ZZCjRhoj8eCdPIm68zXdvSNS1v3r1jmCbGeWaOkWwdcxQtjvXxxM2zZ6zWG54/f8H19TVN03D78SO3t7c8Pj7y9pt3XFxdsdps8V3HHBPHw4l337zneDyRIljrpTumiUVO1G5VoW8thecScy0JxvK9xE/1upryN9QidUnsll18/lrlj86YOPn0vTTIk9dNy3NcKdAZhG3KWFxJNFLEWvFxLkamcdREVuZvjMky26XddqHUdhi70NeKELB0PKYQMM5LHQNDoqi86Vc2Zyv/7z5++0TDm6UNbARWgAXHokeQVUfDKCtRwU4DoKxI4vhlYMVk4cnOtUeZNGDPhYem0oxVxINWczQeEQMYZWAmW40tbMFP6j2rGy6XVaF83/qaisO2GrBXdd7CAlLbWAYoLeeipEldFBajit0GbwyrriHGlu5kGWOUZACrQ6GR09ALO5FvWNtWFkyOIvwFyjsuEAvzrZtZIVVZsJImiT6ErHHdNGkZZjJZac2M3vYsmasseyt2UZWWrRU9DI0HKTmW1ma1pWYU5kGFDMjwlMEbz3q9xlhLPw2iFhvTEuSlqEG0DOuimhi+wMbKHlNHHGNimkaOxz3rbUvTCN+4KC+r/nJx3kaCXcxyzuU2WmV7yEiw6ruC7VadhTlw6jpSCkRVVA8hKmVvYA4BN+ogsH6WGLVCoDRe1pRQwKhRE6dj9LxiFuX2tu1oVytaZbJxvqXxnSjEZ0Np7IYYZdObREpirCMFgmMqvVxKkX48ioPte0K/J4w9p/0jIPtwCsXpSPArbCWSaBxPJ/7opz9ivWpwHn78wx9xOvb8x6//jK/efsnheCCT+XB7T8bxr/7Vv2JOibv7Jz58vGMaZ7wVfY9ijOUzO9nnedknZc+c01eTtRghfIASjHDWydR1WP9eVt6nD2S1BznXqZ/CHVvhMFlgAVntgq0tZss500Z55QVTr0QCRskTsgSNCYFZFSIJrBQuZGYIbPRkKzNaUW1LnCPRJqLJpCjQQbQrJkZMBn8V60bMYuS/O/72o1EorzVWfYw6ZbPgo4uzL5h3Z6gdwFSJ5Ms6kS52CoGEk0JIiQezOmyzYNZzdTTURSrfcv2qvidnsVG6wIqYFhoEml9LNPR1WIKUYmHEzAmkMGenxRn1qxgp5gWZvLAZmiwOP5JwWTWErCE77bCYuXwA9cFo4KR+IGetwJZOu1w7T6Jzht264+piy2wcV7std6uOzjt6Q4UEFf9rjBSyAjDFyBwDhkDoRzoLTevwrcx/znMUWnn9vDHLnEk/TkwhMUyBYz/UrlYIgRgifT8wzYFxmiusJObAcDjUgDxno/S0URJHV+yB0RhhSTIW06U3+uw+FXtdpyhySQhzXXs1EjXl2xI0YpQ6Xy5OhdiJ2J90N1Zdox0NYZ6MKTFPgb4fmOeZvh+0OCYogmii+Kfz4Dafn/GSQpX41ruGpulYrzZKvGNpmrYmGiUyziwJi41n+0PPN8VICNLxC3NgGgf5HNPIYf/I0PfMw6mew/54IoOyiBqwlpAS/TByOJ54+eIl6/WGm5trLnYX9H3PV199xbt371V878D9wyMX9w9cXV8xzYHjqefu/oFhGNUfqYBvOnNFdYuWItRSwMpn92+57+XWl8cWO1R2Tkmmzfnf5GVd1LVgk9h7U67pkmyUGLf8ot4jV6D98nmsxtJlUUlhVboj0cxSfFcCBn2VCpc0OIoSfVJ2tJCkUBHJhCiscOX9LMUPLdnR2eX5O4/fOtHY+cL/7aQaSiYYK+JUeQlMM5b+2H/ipCVgGzXzFg7spCxAOUlWu91M7DYrGeAzBp2VUd0KAwjDEdp+TWRBV2ngX9raMQTmeaCxMuRqsqlG5pMh7yAJj7NKrmnk9wLvcWeVF6PnnLRDIBoQjS0GRNuRJgEJG2eN2Q1dk8lrx/XVlv3jkWEOzElEZVJO7A8nEfHJEEOkaxrWK1/tkbON4PVtorEeklC8jjGQU5ROjJOgJJskuHhjRNVSV7PNgsFrTVcdonRDFnhWoUjLIZFMxjU6vOgMIU8YIiYHrTqjrf0g75GUftidb5jExW7NatUQ5l4cdZw5DTogbI12rLQ7ppUh8ftqhXOsyWTjLa0FEwPMQWAkxpJDIp4Z6KRJDCBzHGU/1ATT0Fp5XRl6D0gq0siac4bNyikOVri+c8qkNXUNCBuaUFz2w17xtYFhmqVCFmWDZgzeex3UXvHyxSsuLy+5eXbDbt2KDkxjiUmNgfFkLFPKgGgxeGOITMKYZE01OGGaVSBLKGzHcaTvT0xTT0hSHbRxxmRhCktZIXO2IaMCPcYBCeNmvnn3no8fPjDsD7x++ZLPP/uc//H/+f/m/u6Ru/t7YTWzwnzzzccHvrl95Jdfv5OB5zlIkOMscwTjRTgqJzXoCKc/mJr0LkZ6+b6oruoaTZms13xKqcIdK2FErSbKiqsJgpPgofLgkyAGir6JCGxJ1daq3bBIQp4Qzv2g2PyUI9aswBWyBi3l2kZsh1nhWxm27IeA16aGd428TowCbVUxtMOYCdEQ0WCIRLIO13XY9UaqR1bYSSJi/EOYiEpq8N3xtx+tQgoFfmiVX6R4dKNBrSTjwzAAy3qLKTFNE9MoWPmF3UvWRtc2bDZrdrutDJKXhBAdezMSUKaoRAYapGYgxXBWKS2D36bCuwylq1eSFFPjUErVsrxe+b0GFaZk3ZUO3eg8D3WOUIpmDlKALDApE2dMmPFkPLByFp9UrRuFBZustL3C6ubQBEvhJoWqtgyWj/tHHsj80juab74h4Pj47o7x4Qk7D3TqG4c5gPM1sA5aEJy9p3UOZxqIk2h/eEt2Dtu0XOxWXFw9o1tvwHccTif2pxOPT3vGcWR/7BnvHpTopBKvC4ykBJDWkjBEExnnSDaGdbfGp4xLiRhnQoI5Q0yhhBkVzl2FHHO55+VeSlCMtyRnidaqKFqmUHbXoLwEemdJSZlfNXYpTFWILjLf1jiLMx5SW6FVlcGq67jYrMlqi5OyY85TYAqzCOaNk8YvSxXeWkfbtbRty82zGy4ud1xfX7PbbWkaT9N4Kd5mSchldtTUNV6QHJLYhGqj5iAwNoF69UzjSN/3nE4nYtCuhkJ7U5g0IQPbNDqHJ3s5Z0GCfPP+I/f3D+SUudjt2O22/OIXv+Ljh4/85V//NZvtjrbt2F0/5/3tA+/vH+m6TkXxZo2vRJg2JfH7RuNJDTPrXaF+X3oR9bFa5dJiQRR4ZTzTNyrd70IWshS2zl7Nln0v9zingLUqPKtIGelyCp2+LddD4VBhEmh/ypCCQIYtKMQ/q9aJo2saVhhCmOnHIy6LwKQlE22Zu1HLoZ8jpiwaMyYTQfZq0+HaDtuusK7BFOkJZcGKYT4jxfjNx2+daJwrKSQKBVxk6E+ESYxI0gp1fxIVyCqtlgVrH2PSlrTeNCNVzKFpmOcogZmx4JcM71zWnbNAuQy2lNeRymdZFXIT0a2a6+NnwQ1ZsaKptswL7aCp/2HB5KKJinYYMgUeJhuuJCrFzIkRcjQus2pa5nYix0QcJ5I+L8YsmXc/0FmZcfEe6fhYi02xvldIQdd5rpSHtWtk0I4E1QjoCZOzXkM5db0WJbNOy2pTRH0JwutrKJ2bsVax7Yk6yJjRTpHV66hj4kYCW2cMu+22VjjmIBzrMWXROdEKn1VayEaNjTUiZlV0UDrf0DSedbdivV7jm0Y2bNVXMNVa+MraldXhy/ljkLYxbrEXohZYRdswQnULyxotVY0C5ctJIU3OYmxXK5LjHKo4VEYS7G7V0bQdbdNxfXPNdrNh3TUU1VcJWMokzhKkzCEw54xNiXkaiCkwp8A0z2I4Tj1hkkSj74XPfJ4n5jCRsvY7UsLmrMnnkvAXZxGywAW9FSXcFCO390+EIO3qj/d7TsPIZKyWf8UZllmhw1CY2IrjlPsWsy6yktzkJcE/F7s7P4xWPJN25er2O+t6SCE6Y7KtHapzAoPCbZ/O9qqcnjjmBf6SKnUfOdagkUKmkKWrKLsjknJQSInOaQnXtZBiOMvKQWssPnsajARwzjBbmGIWtjdrSUZYkJJxxJDV4SSc9zRNS+MbXNNJex9LmIT9JZev38KY/7d6yF6C0j1IWukdh0mrwQs1+DiNS1CRBTIwa8W4rM9i140Rxz1NE00jrrJtfK0fLqUmtTflF+X35wQSFDciSXQZ8qyPl9JgDWRlTxUhg/O0uiYm5+8L1GqzMeLbjCHbRgo5BTJiJCFxKUjSTcbnjEsZmwUK7Q04lzHJLDBmPUejtlJm48CZTIiBuT/xePuBfDgyZ8v+qRf2HxKb1mHmTAgy0IyBbC1FOiyUSqwxZOcl4c8wxYRvDZuLS15/73tcXD3DrzY8PO25f3rCvv9A35/wxyP2eGCeJ8ZhZI5xYWbUC1wQCUI1qpdbgzObM41CIr0tMOC0gJ00ATyLM7UIpn7RWdEfcQ6cYz5DYNRerCn/Pnvc8Kn/Ypm9KVEKisYgK1Tcyn00KK1oTjUxFahThix0qm1sCF2kaycZtA4JlAChaRq61Yqu67h5ds1ms2F7sRWGtgJDVD8OpibENXFOWeYgQpDZxlmYtPphICh0bRikizHPM9M0UWha9YooO2jZLaq1EiLG6mwCRpKnEPnw8Y7TaeBwOHJ3d8/h2Itwrm8xTot086xMk1Q7UHaSWH71Ixq3fPsoHY1vN6xKklggk2XWNRe/UO6nzdoZWWDB+dNde7YCoMxdZaP394xcIKe0xDFZZ0Jqd15rvibVfydFNpiMxiYWn6GzojjfYHBGBshjSoSchT0VYQFNiH8LbrFXyXls02KbFt/IdTbWM0+SVKYQROQy/fq1/PbxWycayRRKICv0WCkRppGnhz39aeBwGklGqGT74aib0artT2StgGcMOWoGrxUDYbwZ2ex2Qo3byKCM1ZsvUKUz46x0a7LRS04hC8AhMwU5JwmwLMIkxBK0AHUTyfC0PXu8bvFqTLJ+d0Y7KcgCKWw3KUdpy5VWlBoFZx04EW4LXQcxM0yTwsycVB7mwDEPrH2LMUZaxigmTluSxolKc6kKGzUqGeoMRswSuFYKX62SxFLVgVLUr8EZOVGpvs6H/pIkIBaDSUbOxhplZQAINZ0pji4lMXLlNWKUJtvlbled+DTPjHMURiOv7DAx0XjZDOtVi3fSol2vO1wj7B2rthVu+KYleSvaJToAXLoZRYPA62xNIEqbv1p8o5UAv1wfssJVtHpojXQzTQlkl4TaKW2mJdd127WtMpwJLCkkGXBzzuO8Z7PbyufxLZcX17SNp22tDM8kA6nAEIzOAMipjvNECoE4z8xjT5gn+nGgH4U/fDhKopHmKEZVk+2UiyhjMW5G4WxC4xmnSWIR74hR2Ny8leHHFOH+cc/D0wG+fisdCQypaaERUbKkSXbKMGkQYrLgUWXQ1tdBaZvLOkuq7VEcJvV+nO+0MkBnsqt+vR7qeHPWwTdKAl2EKdEdU+ianSYeC0Wk06DPpIhFB/xqFbpAO5ZzykYIcmOSqCTHRIpi7GMWsTUaS9M4Gm/ZuIYuCzylsYkxGYYIuWkIyL8bGpKDmaxtb3CNJBqt8zSrFcY4UjCMKRCD0JXmGHSO6bvjNx7FEedECpFxGHl8eKTvB46nnjLDN4dQQ/9zCtGazJ4Ff4aMd5ZT17PdbbHOacJREodcg5DzjoWeDmWWEc4CjqwFHky1xejrkDOVzNAgg8icB601Hq3Y7iXPWIpzUlDSkMUhe9kkUrakbGUGIRtMTkwx0OSES4YmWzpQKKzBpqBdUXnls5Rckm0juy7GQBhOjB8DvdqGfgbTrgSD33VYMvMMfYj6SkvgN+k522wwzonAbYpMKbEylu3lJa+/+D4vX3/OanfFx/sHNrd3ROc5Hg+0hz3usaU/nRjCHVMQGGydq8Dgs9jtxqkwX8rkGCWRMoZV09BZaI2QRaQkpBqfGKOzay4/G6EnLSKNqqpu6rue37dvGzVTi5PnN3Iha9GAMi2DyKa8qjHM+twa5JW1i6kCkugVmFZBaHVDUgiUiBuvViu61Yqr6yvarhUq2cUCCiGOybWbX2BZMciMaU0kppFxHJmmkf3+IN1a7fQvcw+5+gDnJEETjbNShMqV4reSrWAIMTHFyIcPtzy1e7quZRiEjWy7u8S3ItQoc4qRaZ4qmUdOStdq1JeV65hKXLkMbEsCx7cKYcueOh8EB+o9qcmJyViKvlKuQ/6VRZFPj/KaScllJJGUbqLEHVH3rNz1nKiaZMUXJmPr7HiM0mEgJrK1GGdovaXB0HpPZzLegHVCLT+lxIQjGkvAEa18jjmeXRfncU2Hazp8J3TrYJnyRIqBME9Cscx/xUSjsY22hjwmJ5Gez4lxjvRjYURIhCwTBqUVmNTAJ5NRKDLOtNLxDYALTPPIHHoeHzakOLFuX8hAMyIcM6dAIOAQhoDCEiBL0akmQWYKygik2H2BTVnInzrp4hi8dXjrRBXYIAPgxfDHdGZXbM1gjWatU4wqimMgO6W8FPn4EqA2BqzNzG6iaQVr301gAhCMjNFnMGMm9TM5W3y3rpVRS0DgZ/IZhaXAgdc5kpjPqkwWklQenNcB3FJFSVKJF6acqMOKCaywP5ERkTnnKowMwNgyPF/az5Jk1Uq8JjxyP0p7mNolEmGjzOVux6rrWK9XijFNdL6R2QRr8V4M43q9rolGo+q62DLULwF9tkk2tU6O5xQImsDiDEmV5nOUTkkJGEqLeo7CH78UFA0peZk3MQbjOqyTzdNZpc1VvD1A41Z1VRjb1N+TE42zrFZtbT2vdzu5f1boYI3JCntToz3GSnN46HvmSRxk3x8VM5mYx5FCsznpQJ1NRqsppfUr96XMC6ei9aLJdAgz5Lnk27iQRdDLSFBsG0nexFM5jG1wuRj/oNSTBqOwrBhEYFIjDYVIZYRVW/a/J9fWunVChetAKW6BBNFEhe8p7K7svyhPKIGgs9KNkX0pMyohC0c/xuK8ZyznkEQ0iRyJKSDJuZHRkTqrJV8TUS+ggCVzLnh9o+ulIWDlutEQQyAGHYmbI/Mw0axg7S3Xq44uQpOgTVEgi9ZzTK0wWa0aVr7DY3EzDHEkJAl6g/HEpNTgzmG8wQRZx/MwaTHmu2Hw33TItVn8QjoT0EspcTwcVDNHOrsa4SnTWTlK1bmkvhlSlIHlGLh/fCTEiHde9TeMJi/UgLMEdmeRKBVqYjQ40Z2iv6UY2/L78yQil9L5WVbxycBoPRZITNmJS4KjdgBLshCdJWRDpoEkukIuTdg00yZPMIlsLJtG9rtFMfgxgwlV78OeXTOsIVojM0dZGqDWW2xjcK1jfbGhX0e2XcPt/kRIYLwnG6FT7fsDcwr0OdLaROsMK98SbcuE5ek4cP94oFntedbtyNngfMt6sxHV9c2K65srhr6nW7fc3d5zPB4J81yvlW9lbvD6+oan08A0Smf4er3mYtXxerumzQmfAjlMzPPE4XSQ+cKcljkHskLmJCO0KthqnMU3ntS0eO+FUStp4GfEX37S5SjkKTUIP183VHICaxcyDaszRbIuLFHnNQorZ86LtkKtugOdbTBuxXWzEt0zhfQ2SvvsG09OkdNJZvxKca2ojffDwDxJl2JW4WH5WSBZuZxHYVDLpfh4NgCvBblCs5+ivEdJlAu82VetG0E0xKapIoNJC3oZh9XB/3GeSWHGOitJlD5ePkOK2svQWPSTpIclEai2oHTGFaK2JCBG46a6ZSmF36xdxxhLj67MgplajAbq55V7qN0WIzN9aOKbFb6ZUyRSig6LbzI1aUJgVkkqo0ETjZAFIjWbjGsszhu2rauJBgYl9bEk22CsA9/RGYdVSQHCRI6RZJxAoZ2X2NDK8PnshLgkGrm2Z8bnNx6/fUejKMbpXIVsBhFDmppJFk5UdihR5wGnSQZStZVbYyqDRVbODqNCVsPQ0zQNIcxSITVaOVS6rSLOl6Ny2iPt3gIHKcwxSyuSamg+rZDKBS8ZZeFQKo+hlYJSkyg8+aXqVDoClZY/l2CvaDvIIhWKWRlKbLxg/lvvBcuIToLoxpxCwAXLGGaMp+I1TXbYhDCKGItxy2hOKu2cpG03XUj1Y+ZcqRKFskyu4/K85bqIM5KEIWW59ikbEVXMy3Uo1eU6RFuZByjeUpzrWSXIF8fMtgafjTImeOdwTu5z1600KFXVVw3+F9h0cdylsqDBpzk3AMWAJ0hqBHSDYtWAQ23VW2Oxtq0JFUETshzJKcjKLe+RqdAe6aBppdAkVQl2NG2rwkGWGKJaikSIe8V0zpWaUIYWhTHkMPTEORLmyDwP6jyUXSXL2p+VCcubhZKvhC4UliW9BVKEPAtMcl64tTXxcsbgrRP2KqzOXhWEs6G2i8VyQs6Sa5qiUyPXXAZQS+aWdZ/rBiyJqj6XMmtSZ7p0yYhFqfv6/DBnr1wcRPle7nfx01nPNZO0AiRvHPSiCAY2U5Rsyx/XfZyzsn6hPPpZlH+hshFlnSsSMSv0KlnqzBEGchn+N8KuZvULSypV5vNaUBYWM5eEAUkESYWy0Cj297vjbz8KRAK1X5Al8NCgpQQOKWvQZ6WiWs0558ED1OhH/5nIDMNA4z1TmGkNUuDKy+77BMP/rfVbChrLf+tLL7/Pn/yj7tf6ome+KeX0yevIM87OuZ5B6fyVoNMqFNdpdxLEtzrZ7Vl0Elw2zEiBxDmZDTRWiocpKye/7pliUSxyfl4vZLQGazKORGdR7aOGwXsihma9oV2vwMDjviOMvdDCzj0pC1FkzBAi9OPE8XjicDhyeSN0vDLHKfCNMI6kOIvYai4zJmiBSa6INUJV3XrPumlpXcPldsfrm2uutzuuvMFMI2k8EceeYXCM80jIkxTwfg1qowBuo2NbRhIB50X0MduqXFDjDUpEYb69FkqSa9S2FvHJRRwZwFghmUg5YUJY4MxKwSsENQWCSzGGGFQrpnEyG2gF7j0HZYkaBkksgsBzU5Tkeg6BEKOwGCoEMZREJOisRVmTytZpzdKl+ITUQFEn54a6kjAUT1Ovk94zKyx/1sicbZLSPbUjlvPZ/l0IgEoR2paZl3LJtV347bB4uUemGoTqm37tefmTz1ZlEs6Sl/L7X9vr6l9qJ6rcJg1wSmyU9WtZHZ/Gs1l9XkwiM1ASm5jKe2YcJSYySoNbBh/KiwpjXsQSkQJ2sTfZFDshr2uiaJFlmyVhSzpHQqqoor/v+K0TjXmSAMCYWJ2p9w2Xl5d463j/7iNVSCZlspNNFg2ffLichbYymwAmYIzALEzOHA8nyIbT1Y6uaWi8I1nBjyUDeKuVeWnnSXsPVYYVGI3Jup6LUjZ1ey9ZfhYjkbK05ZKXINQ4hVBkYYgSEi8jRDBJ2Z1KWynLe1urw+Jl6NUgQ3hJ4DEmZ1rXQOtxpmXsInMcyXlcWpPAIYwMY8CMlst2w8Y2pDThk6e1LQKvtHjT4nIjA+DZCAQmRawXzmvjlNWKAgUoC1YC4mSyqC7nQnmmcCvXyP3CkLMIPoluigT2pZ1cHJgYWUvMpZVX2pQ1PZP1khLeWbCebiUqn3JtlZrWSYcMY3CNR0RhbH39rJ8pU0RlNblIkpVj1QmiDZck6y+FqJ8GdZSCn/WrDm8trXGiCu0cbbvWgDhyOBxk5iGFOk8k3bviuJLCqIR+NJOwPmK8dPycb/FGhreeHvcSZOdEP41M48Q0CJVs0mEyoQpOzMK1h8lLlwjUIKkRTHoesSRh1lRMb6qwJAPWVupGkxaDJ00LncVRxorWtiTdp32Kdf03atyMMeSY9HpHESZzwr5k1JkVukWDQeRAxOBbpROOpiRE4LyXxCZGchQ+x5KwStIaKausGnO9t0mDviRxfE0QMklp93RoXxW9BbKpVecSVRZc7VkCZkCG3IBkMj5ItygQid5IopETMWRSyDib8d6Ab3BekmSZBYsELbJMxjBGGEjCMAUMMTHnzBByhRdk0O5v5LA/Caxh1RKD6hzkYsy/HVp+d5RjnCaMKfS20gF1TmakQowy2JojYdZp/cJtbkq1uATdciwwFQ1QjOF0OkGGy4sLsX6NqU6/7BMF6y1V0zL/V6EgS7Isb6T/yZ/mGt8OVkx5mtq+dB7EfOu8lx8q/5GuddW10UJSMk6oYkuRBsOcvdBbxsSuNRjjaHyHSWIzrFPLnjK2mCUyFsXUZ0NjXB2AhoSJM00Kyl7kia3H+parFy95+b3v0a5WfHi85/H+jqfHez6+/4YwDfTjxKrJWBt52h+5vb3DWs+LF68hRBpjCEPP6emBh/s7YpD5tfFwIE8jNgV89f9gc8LmhMuZTdfRdit+/KMf85Mf/IBXN9dMD7ecHh443H9k2D9yOB4Yp4FJySGWznExVRIlWr3KFoFlmaalbVrmbKUbytn91wrf0tnQ/2rAKZ0yq9oTUtX33mnclHFBRf5UH0H8/LJwjFVGPFMKTjqnYEtlXbrbmUWNfEkktGMxL4rlcwjaVT5LZEulnsKMJUdJNKSQeZY4leVYAueaANWMYElY9XdL4UC7ONaK4G6KzDFJ8SAhOm7GKNLGkYIUu43RWKnxlWyn1qFL0q2JXylyCbOnPUvof93O1OuQlhSkapNR5gNNDfC/Vb2oe1T0Txb/VGZVawKSBQa9xK1LJJ+UEVXIl6LKHziCDotbkJjNOZq2wXsZsE85UIrEIRtCNkzZMANzFPLoYGDO0hWJGS24zhVZYJVwI8wjMcj5W+8qe9/fdfzWicYQe6yRF5XY1WhgnXCN5eJqR98PjJNoRkhMqJoMSCXRIKrg1pRqXRbcsxGYVYgT42jZH06Y3Q5rG2ySv3fWSHUvC5ZTDLItZUeySSKilyWA80446G1IJH2a0WEap23JlIUzuJT4U5CWnkC8lqFuomL1Y9ZugwErnMa14q5rM0W9KQkZ4gTVSZD+zXazJSahgMtJxL8cgSY7fLKEUyQ1gWxXbNeNJHZ5oHEeaxsad6ZPkFdMGEKYCGinIy95q3FFjXlxhtZYctLKD9r+zxljFx2IFKNQBBu3OJSMtFiz0NYVumCnSyiXoFcH9kt1Vyr/AZPB5aXj1KmivHMO21qMd/imA9uC8cL0k6UCnLNUJKc4Fz4w6Z7pECdZtC2sFUyisAitQLP9GGUdWutAh9BdsTzGEMMkkK4UCXNg1rbxPEcdshJxHAMSAFpZM5NWeaY5gFZcglagAdIcQa/TrOwcIUxLwJGWtrxRpoqUE2GOdVPL9aJS3GQdaqUMkGviWzouYg2DzE5QKmOKQDMi0Ch/7wjZ0I+DVsky8yzDmjEHgm0r3Mx6mXVKSfah0aHvMgqS9doYg0Aec2bOpu6J4jSSgRykTZxiUiOJYuslhyz4SqNrE3Uapc8hptksAWKOMCfNPzOcsdnN8yTX12ScOmBJ4mSNpjwLLjyX1Fl21qz2Iun1Q3G+xujcV5bXW606VquG1hpSjgzqf3zKTBlGk+mzMPOkEMmFhtWBiWKPyiC7c0JJaIwwkXSNwbYt2+cX7HY7VqsC2fvu+PYxz7MEWdZRCEgsEmh0q5bNZlUD+JhLl4sapJf4/CwsWiq1Boy1zPPMaEeOx1OFTzmFdZaO6hKcqAU+C/zPq4mfBGCUQKeGFZ8897xKWoOREh1hlo51Pk80PjmZ+kbLQLcm2pSEI2sVoqmB0H7OJAfeO1rjcCbJNc5id1ypfuaCXJeh6my0U29k/M9ZMPNIYz2tbTBdi+/WPNtd8Ic/+jHPX3/G6uqSkGbGaeQ//Id/x/tv3vL1l3/Dyhkaa1g3DZ1rIATm4wGMoc2JF5s1fuyZyez7I3kccePAOida73GrFW0rAm2+60QZ3jfcXF5z8/wl/91/96/5yQ9/yIvrK7755c853N/ydPuBhw/vuL+/5TgOHOeZWYeYS004oR0cvQAOZafyDbZpxEZYKxBL11BUz8t8ZQmsy60yuhiNXToZn4rCSjITUxbCEU0AktrRZU1lQhD4TtGCCtqVKMiOktvKTFyunfWFQSotwfBZMF0Waq7JRlnepq7Fukb1PeosUl3py+qUPxG/Is3aTzuMKSfxq3qN52ms1f4pCKRcYLOy56dZRDetUwpbTKXUF1eRqp9bkm/x4yWRL766UjGzdGrKh6qfX6+L0QSuXgHNL5IWteJZUSuXrmrKzNNEKYM57drYaifKPj9LzjD1mmcMWEOu8ydCbZ2d2DbrHb5taDcN3hqlj1ZkBoaRzJDhmJJoNJkMTnweRXfNyH6WYrtAgW0W4pxV6zBdw3p9zeXlBZvNhr/v+K0TjZikdWKSbou8VK6NNaxWXcUMpvgtpcCzDNHoxSxHUhuXDHWAaBgGVt2Kxkv1uCyGYlQLO9J5hagYzpLAlF/W+EvP1Z5VFMphzl9DMdtWs13IlXEmJREEE5qiAheidtz0LZYArOy4kuFbQ9t6Vq1jai1hSmQipMC2dbTe0DVw1Rh2reViLcqbGXC+wbqOpt1qR8IwDlGyWiRIrpugvmW5Q3qfUNVcNVymfEbtNxo1nyknrKLnS8W3NESzMWpo0zIboobIFiYoaR5oC5j6Go1T5exsWDetOOvGQ+fI1jAHI2JLcSZZmVLJWQSaYkrMcZKAv2xkda7Ot9oah0bOSJPAohadJAhRRaTz+5/JmgAE5hgrLelc2sghkWMSekGEyrRs/CnOMoA2BbIa6ynNYgAwOLGYQrtsZA/FGCRZ1zVXBtSKroXsCcnulLiOWoXhvIKyVFI+NeISjhsj97poqxg15rI4oAg3hVSgRHKNBZc7k86cnld2OCNUF2CSFo7VAX0LQ045v3JOteuVtKOQF1YNw9K1Oa/0amWpMqXpvSo6CHWDZTX+UTe6kY5ZTWay6FXIB7BalT0/zyzXpewZI3jzwsFWK9G2hK9gk0BzhHHGkw2EkAhJkiWXDDOZCcNUzjmrmzdLEm6MzK14Z2gah/WyJ7qmwTshSLjabTTRWPPd8bcfKZ0Dc+W/yaAdU0fXdQuzVCyhvWH5F5RKrWFZFrWCnbPQVgcRw5zmmaZpcK1WGhcHU32SrrKlYlqt8KfPoyzb8/cv58N58rA8t+z/+sY1eFre/NdSjbLeM/UayQ/LDAfGMyN0oH2UAHrtLN5YXJlh00qtAJrRQOSTUxR/ZeTvnVRnpNCEYWUtrXNsnGXrG65Wa774wY9wnSdrt/XNs2dsNxthxgJaI+Kqq7aVcVtlYVs7y+Qsa2s4zTN2mvDzjNU5q1Xbsdlu2ex2QrTg/v/s/cmPbVmy5of9VrO707j77aPJjMjm1WM1ZNWTAEEkIEIiIAgCwYkgTQTwv9FMGmkiQH+HBuKIEsABJRarWCyWXlW9Jt/LjMjobuPdaXazGg3M1trHI7PyxSNqVrERHvde9+Pn7MaWLbPPPvvMk13H8zcf8+rNR3z+85/z6SefcL3fEcczfdvQOCsDNWNkGLZ4/4Axk9y6AoxcPIxCHM41eTV6nzTx9V6oj1qtWOe6lOdk6gMr1KnLBuICDKUqHbt+SaxVAMJy/8XmQlyrH0tYyCq28fsS11jopE++1uuRP8xTWyy/b9Z456kVmPX/Zj2/8l6mJMr18tf7UOy+DJsjS4JVaUUIs8CW2FDpyaUns6yfwoxd74sG8eUZ1sWur7lQ1JJbmtdrXm/ak/tg9F7Vik9Z6eWz9P1qYlOpUQLHR43DCp2Tui2tn5Mv9qb6qEuTuG7ussVJsloU0JJxRANToVXrPjxnw5xVyrnGgutTK7M1rEVV2hxd10rvbNMIcO492+2G6+trttt/i4mG0c08x0CJro2WTKx1XF1dUYbHLYelXvAStZcCBNnGgKpOYZ3wplPW5mvLlAK37x+w2UMw+H1TlZVsUwILod5kDZqNEcRzmRaVnXQik0ZJAi4QJuU/lsYdZ6xOFi/GIo7DZFRppsy9QHWY5bS9dXiTdMiPoJ852YrSSjVZgvIQZeZFzoluMHgMO+eZ7hZcWuiJfPbmOdf7LTfXe66udmw3A/vNBrwjOcfsLK7fMDx7heu3nOfIP////Yq7R0s+GdJjEPQ9qOMxeq6aXqDGIzan1CdMdSrmYsFKoCqBuzVG1YWyoNFZhr+YHDBEfF4EuTGeod/wf/o//1+4eXZTneXl7JKirgDFqcoDOh4O/N//b/9X/sW//DP+/K9+w2+/fstM4RZDDvJcHAkacdpdN/Dy5StevHjFZz//mfR0RNGHF8QurJu61WYmpWnlJCXWoqSxLDMhirLXNI/M88w0zxweH4khEkMmLhFUCjFmKRFbK8h+zBd4e5YGQJDnb0tc7EqSZ58ICDlN/ozSpnJOK7c0RNnEswgdVP6vekl5brnksYIJGTDeUlSzZYMQRE4UuoSuVpxuiKXXxJBM0EZrwzwHfWYWaxPWQotV+WGDa5uaYYuWd0Hf5LqaxqucdcJ7J/d7iTXwKjhQUtuyOrjwUmWF8poUFf2R70uVSc0nl80souESWZ+xs+W+Qo6ZZJLOp9ASdcrSM4GAANZJY3lOJfdeeyhEJc/jG0OXpUdlzomHaRGVuCCNwzGrrzAytX3OEnRIFVXO1RF1Lol8f7Pdst/veXHznN1mw831FUPf4Z1QQasE5o/H7z1STJWrblXvP+coz9Farq6vKt02nCPVA6Wn+0IxzsJ6SCq4EBH1oXleuLu9xxoR/3h2cy0nkDNFZrT0BRRsTWwRkik9f/rmcgrUsDXrmiiRFxf7lr5s5cMXmqT65e/dDwGE1nz8IkORtWI9VquihRgfjSFZL2IPZG6nmdkLdcVnL30PyORhSwlsJK+XxM4QNeg0OdNr0mBJEGepuicY2g1ttHC45+s/+zOm+wM/++yXXN3s2dzsef7sucqhThBFPjOOI9PxwHQ88vbr3/J4+4HHwwP9Iqhw7GRuzXmeac4jJGERvLrpePniJS8//ojNi+f47RXts1d8/sd/l2cvX/HxTz+jbzu8s3zyd/6Yxw8v2FzdYF2D8x2H20fu7h85jzMpnasgS6k+R6T6aPAYZwgpkMKC73qc9+AajG9FUlarGoKCu0qjuogiBSxMWQU3ysDYRZMKTXLnmWmeROI8ROISaiBL5gkos/L5Bdkv/W8GntBdis2VIHP1v0+TjIy5oBiaChyhQbDVvqfye+X7Evxn/ewCfpmVwpqEjWJrT2ZRXlqTgmTdOuchlqb3iDUTxohYhtFEw8dmrQipoqQApMIqce4iNY6xgl9G76HNCIFXkw1jbZ2nIv3Jqd7zUv3IKBhfAndXQItMzkLfEoGVBCniNcmo9LYsaypF8SXKMAcyvpUqDdZKJTxLr6BVoSCjPa3OGxonfVZzStyPQaSqc1DlMAEWSs/0XADNnLHqL3OKIvdsDU3T0Pc922HDmzev2W42XO33dG2rvbVW+1x/v1++PH5woiHRkahHeecp8mPOWBmS1baEoSfrhOKgZTg5i7VcKLSWkokZ7e8V52yVYxZDZDyNOCy7YYvxRqhKmjzYDKK5J64sKJpfZjBY7IWOcV15NY3NmgSUIFtc4tMMclkWssqFSbldnYW+XQiJ6DQQTMWBZ1Fkqhw+cbSOQGNFVnPTGDbDwLbZcd19wrax3HSOfdvRNSVz1AdoM9EsRDOzGE8KifQAb66vaK6vufmTDR8eDtwdjnz13bc8PDxwf39XNZVDDJXbHUNcg/scKE+jOIaSkkhy7SWRSwljEx5obOEzGpxpaZuOprE87/f0bU/f9bRtx4sXL9hfX/9gswJZvIe7O371l3/Bh9sH5nkkOFeRbxOFghRsIk4IZzNOhLcLd8cHFpvY7/fcXC3A1iIAAQAASURBVF/RG5U4xlPKWTkmQkxkFublrA2EgVH5qGGZhQYVI+My1ZLzMhWFKlPpPab0v5DJSQhrJeEll3071eQisf6eyUI9KrM8M7mkGcJ7LpUAIwG+0YQ4kyXJ0CpFcZzos5NBdpYUhIdJsoqKpDXYyerpQNVhins0gpjphue9F7pjcjX5Tnkh5cicIgZxml4afMAYmsZfbCjy7aDvmY0kYjJEzFQKGgms6ocX7nmORcZZfEQqsyNsQV1FC5ykilTa9C1DGuWeO61iFRpU1vXYNCLr6FpfB7PJiD55TeMbsJAsAvWkDDHJhmEt/bBTIQFL54RuN01nFoTy5L1jjJEQldpmjPo+i8fjbUPfitJLN8ifTSPfa9uWru3Ybjc03tO2jQgoqI/lBzjyf5ePlGJtiqTSU4wK41m6rmUzDMQYmeZJN92oVT8uAn+t/ukNN7UAmOuKlVkNZ7xzXO22iqIiUcFF/mBABc1yBQa+n2dAyRfWpPp3HvUFAFYCM6HnJk0cWD+0+Ab954XUx0WiUpJzKliXFGVPxoH1ZJtYUmLKieOSuXKWxjga55TZGKX/OAkYVegpdU6Nuaicx0TK2sQcE02/o29bdpsNQ9/RNo6wzBwPB+YktFWRZ21o2k6Cv37LZtiy7EdyzrStzCc6fpvJ88JoW676HV125HYrIizWc71/xnbY0zcbdtsbdq9f8/wXf8zHn/+MfrvjvATGJWAxbJqWbnfFPmUODw+cxon+5hn9dkd3PsPxUJ6W0Hb07ytVZ00urZNhgzin3LFVAbBUlgogU6quKWXmWSi8ReEpJpGCl4F4a9/EEkT9Sbj+6SmDwpTIY62hrbSp1SLWRmyeWIrhMjG4tEe1KO1rMkb6Zes9UfsuFeAa8ym9qFQiVmS/zOTQKrfV88tFuGHtR6iVQevwrcXVSbxrZSCkIlKUCVHWtjUqdqL+IJHrGq9XVfxEuXEADu1LEkEfcqkY5hqTlNfmAkUZqoiHUNqK9LpkDAW4Iss1FsDQ5awCOA7nG+mHVOMoNC/XtfL5BrCSGBlpgsRYI70YrpH3wUhFbp50b5IZMVOIhJhlGKX2eGarc2WahmG7wTeepmtpvfRHd11H17b0XSeDHH1D4/3F3lTM5/tQx+8eP3xgXyroRwZ8daYSOFnwDX3XCjXEW2JIOnzFP3F+JpcMSJyc1WzaGYPVICaFyDxOUm2Iynk3RhtSJStz6jETpmaAghiok9Pnf9nkRwF2qOv9QjmklAvVWEMQabooD8s6lMYlvx81oHDGaICoC66wXWoGn/Am0NtMbw3PBseL/ZZXVzt++uY510PLq20L01Lv8TLLoKkpzIQUWHIgJs+cZk7zzJ7PuRpaXu5fcHcauT+d2e473r59y9cuMZ5HlmXmfA6qSCGbQ93otEnRmIv7gSLjxuGtIhdZ0NfWWjaq3mKNyOUNg6fvGj6+esF22LIdNiItp+o4MUe+Ht/9QZv6uH+J076B+7s7vv7tbzkHUerJJtcSo1H1p5ijNt5LcHyaRzg8YNuGl69e0W16rG/wxuDL88+ZZQ4q1Zo5jgfishDHhcM8iQLUMjOFhSUGplDk/ZI2UpuKRpMNJqLiBDLQrRLLcqEXJZUFzlUCk5zVOarKlV6/UA8EdYlZxAfEvkxtCEwyIOVJ450tkKsR+5XBho4cVOPtQk3psjpQdP1FgCBroFISjSSVH5WwI4s4QMrCCc4RQklYkpTbq/ywIlQY7enIFsyF/rsOwJPAT4NnlMpn1vMV+pYkxOZC0tYA+ZJCKQ9W+LNJlZlMXFEs9Ste+zGSgdb12MbjGo+xqpBikzS9Ad61+kwDRtFekwSZst7RDYMmSZautcwjjPOJkHWTtI45GWYMEZlW76ynsY6maRjant2woe86rm6u2O62DIoWOetwxuJb0WEv/F4DkmTVbf/H4/cdOalYiBEqWqUZZNlv2qah61tC7Hh4tDVAc07ArjVsRKu/JazSoAoVAcm5IsveOUJYaDQxr5XaywqunB0VtWalHlH2m8uAkBK4Vaa2JNK5gAVahUtF0nStZhYKSS4IbvnI371bF+dW8mEZaisBoSNbT0iBOcM5JhZniNYqLCLMg1JJyQqg1GutSRlyrro3F3aAM6L8tOk7NkPP0HXknBhPZ87LTDTQdi3DMEhlwcp0AtP1xGUhzIsEVK4hP94TziON79j2W3rX0loPCOWz312xGfa03YbN9prr56/4+LPPef76DcZ73r77QFgWSJn+5Qtcv2FrLP31M/rTif7qhn67pzsepVJWAJMaZNkaJBq9h79zp3N5hoViw4qE5yx9hqUpe5xYlrVyEbVpOKYywyLUBu5Y6aZlWzdP/MQq3bwmGALorjT0rAHRyj6gGk31s5ow1ghOfWzpm9OLXG2+VkdYX6vVXS4+U4qA6z2pc5cKCKZftadC389ZR5m4KOsY7XUsAzcTwSStAluyKxVhFMATAOhyL5X9pSQaZY/JOkOsLGEFzlRsplzxqpRlROI6abUrxXKRWK0cCBVdgUHras+U8w3Wyjyl6HK91qRxpG0aqcbkBCyoVrtW2S1N62lbGapHgrAYQtQmbgBjWYw0fsucKa9jBRp8K4MbSx/gdrdlt93Qd62Ax17oUt6t97x0L5eelh+yOf3wHo2SJVoJsrNS860qHeSU6LqWbDL78Yrj6USIJ5nUjGFJQQN7yeIF/ReVl+LoQ5SR9M5GxjmDiRyOD/TbDV3Ty2IyKsulvSK44tYke5SSm1HNaQmIir0YIwFw6VGqPEBFiFKOqlwihmVtVg1+zSBT1N6MTDSRJcqZ2yzNws4Y4UOmQDYL3mZcTrRh5rMXV3x0s+d/8u/9ks3QMHSebesxMRDnM8FHUpoZxxPLIioQMUzMs/QAGOO0Mdrw1//8v8E0W2j3vPz0cz7+6Cf8R/+L/x1TCNw9PPBf/9f/H779+mu++s1vOJweWeYZb5wmbNIXITZuZKJ1isxhpnEGZ2U6qmIb3OyvuN5seHNzzc2zPd4Z4jThfcKaRBoXlumOu8NbrPc6uwC+Ht/x0//X//YP2tQX/8l/wU+GN8zLzD/57/4J5/Es2s3WEedSEpYg1SAN9karNfMYcF2PbeH9t18xnQ6M5wOfvvqI1jrGw1El+QKn04mUJEmZllk2xySSpyknCEHUkKyRpu4k2uCNl+bIsIS1PyhbnRQRWZQHG0LUibcG2zQ01uKtpcNLszFIBU8t1fnSmOzXAKRIbGdYQqjO0flCT7SEKPQ7WNGVlLUJEw1ZNFm0Wh6OIVQ56Uq5yFmSSWAxgtpbHNO8iJO1oIM1JI3KFmM8vqUqZiwhSFUiZ8J4VlWZlhDlQhrv183Ce23yEURYnLVQh6osIWbt2UCCOuWSrOiQMYTGEGxiMZEln3EWeudwSRrVPJnGexrbMGyuCMCUEtE4EpmQMkPfY6xhItbmx+xbJLmIpHyWfjTn6boe7xtgIWUBMUL0QhNp20o18Sp565xj02/Z7fZc7a+4udqz6Xuu9jv2u530YthCyRJqndPGf2eDbq4a0ICWWH6QL/939khJkkahG4i/cMWHGZnIvhl6nLMcjydO5zPhdILCXS7oO0LX1ExW312D51Tq3obzeCanxOFwZBh6pbldwgdyFFS/VCMK6LOG5XXVYrIozUBJKjSBuvx9+WEN/EwJ2qCe2+VREpH13+W89LqMJlYF4cxeW50yMTfMOXJMC2ccjYG+aWSeUApCvdLA1JI0cFYQJlNphKUHoPTzhXkih0DjHD/7/DM++ulnfPrJR7y7v+fDwyPRGlUKssSYcdbROEvbeFzref7xT7h68Yr5kzN/GRaSa7k7jrzaXjO0HZ9+9DEZmTJ9mGa63Zbh+pqP/+iX7N+8ZvfyNbnpmJaF9/cPzOMEKbPZ7tm0Lf3uhqvXH5OdZw6JaVkYtjsejkdO5yPzMgmjw0oP0DBsaLuOfruDriday939fVWdCnouKeU6QypoL2oqFClNPOpw3QvEvMjc56yofREPMSXoFztLug6KjLM0jMdavTVGZpI13sk9bXytQlTgKlNp6pcJQwl81zRYQaUiuV0TA9Qei1IV6t/XioZ+U69tXSdJqxE5XyQWrEnQ2kMbpYpUkh4r6Hqp0JQEXBKxSI4yC6NxXs4L4KLPsly7wdbEhyx0YFMvb6U4rb19utrLPatLU8A+6VMWKWin1OLGOpzOCXNtT0wyPM96LxQo5whRe0usZdG+SRqP3kXCdBANJisJeeMb2tararzMtgtpIeSAsyWuDmQnUtXbbmC73bLb7nh2c80w9Oy2GzabAd9INb0kmQYBIZyxNUksfVklblEs5m88fjh1qsxLSKaqAyaTakaNFXWahoau6Vh8wJtZI4csSVhNforJ5tXp5VzRo0wkpYUQDNN0wrYWFxzey+/mC61mI1AMxhS5UDFUX8pPFGk6/dS8LmJSydCQvgNJj/UMSxZaUKOMMPdUb8Lojc+qHa2IK95hUsLFzBbYes+bqz2fvbzi1dWO/aan8Q5vLdk2xGyZiAQDEctkEguJkBNzgBgyISRyWhR9dYzhluxOMIzc3XZkb3lx+xH9bs/rV6/5+3/37/Hq5oathdPhjrzMXHe9DFs0Ih8bNei6OxwYl5nH8Sz8PmNEC10R+u3Q03uDTyfCUaa/h3EmID0aYQ61Sc1Yt26If4sjpcTD44MkKRpcikpoLuAfYCpfPTuDCH4lyAtxGRnPjoe7hq3v8NaxnM6KAAlCVOhDSyhaGnZVKkqJrBNJY1p7NxKrI7XqiFPOQq1KgSXOtcFb2DJCw/FNo03OZp1dYYpOiQY0+q1cNnY0qbXSX4GxFaVFg46ysQvdR2kUZr0GQ67OTl6qSBJZAvYS2OS1yfoynLqkAJS6gzSzm4qYiVIbtT8r64owRihrUpwQpO6yuVDAnCxLSBekiWjiflFy1h8WVL8iJjGqZr1Rpa6ICaE8HoyiNF3b0NqGxja0Q4NJiRjQRkLl/sYA2eKaRhR3MLimlaQzRQgTGAEPfCdlabJsHsLbF5nm0mjsnKPzbZ0QvNvs2fQDQ79hu+npGk/fd3StVyncXG+DyeWZRGkmz4hMoUo8o97ox+MPH2X/l4BGZFtXlF1FDbyn61pCDEyTU1sv95/66ot3BdbdqjyHGEX55jyOWCu0RWe7WiGWNzNF1E7PLwnVRAOT+jml6lcvQgObEnRp0FnO05S/V5RZzkuSFfnf02rGpe2s11l+UvxEpTRbQ84iKx7JLMkypchsDclK67cxThnR8kFFzTFfJhuafMQsQJ53jrbxxBCY5pHT6YhzhrZrCGHmdDzwcH9Ht9vR6pqSoMzp1G2nijhCifQYrj76hOg8E4Y0zTIj4+VrGUJrLW2MDPsrds9uePmzn9Ht9/i2q/1TbddLQ3FC+vd8g2kaht2eFBMvXp95/OQDOWVuvvyy+n5BpC3OW5pWKF79MEDXM+OYHx4YI8wJQrbaH5S1VzPXikTWJm+5ZxfBdC52IXtcoRiFC/pRmUBulcqUyVWMJ2rjeExJ+z6SIvoFnJXZVlgqdXc1R7Vds66eXKInc2Fr31sludiXnEyNw4Baabj8xRqY1zdJdQ3XGVzfSzpKdJgrJfgi0S7V7Mp3NLVPts4B05ii7qWIHcj+rNWKuiZ1DpoxNbmrClQX61Zme+gFqcJnzPKMLSoaYsRHeOdpG6k8+G4j/cshiqR0TsQlqSC/yhtrG41tRKjZ5sS0yKpt2oa2a/HOi7RzmskZnPUYk+g6T9c0OGdpvMe5Bu8bNsOGoR8YhoHdMNC2wkRqW3mtr7yyLAOhTar0b8i61tenX6jcf9PxwxMNnAZaEkxlDbajlgfKUKnWNfRtzzJHvJ0ql1rKTXpSxgI69MOKG88p4mqlKuiCzJzOB2xr8Z2jcW1F9ov3N5rdF8S3TCLHlkL0E2V+WTSXxlKaZI2gs0XH2OjizVmGA5lisJoQZasSvVo+NVYGnhifsDHSADfG8HLX8Q9/+QmfvrjiZjMQTAMYQjSQGpbsOQHRNEQbCcYxG6GJj/MkvPuYCaPouGfrmfNEtB7ymflt4v58pN1v+eTzX/KzP/6IP/mHf8Ldp59y5RLL/TtcWvj89SucaTG0hJxYUmSKgd++fcvD+cTbx4PMBTEZX3iIKeEtpHlkOb/n4eFACpE4ZUycMCkQjfQhpCSIbr7sdP6BR86Jx9MjMYfaFC0oOrLxad+iTQajuuI+Z7IVfmYKmXnMPOSMzxZvHWkW+eDSCF2nnCcvgbqwe0CdRdb+hlACZCDktRHXqZJUSEGaFcNMSAuJQGbBZE9OFhMEPcjZkbQROFcNP02iFUAyBm3SE0cjspm2lrBT8e2oE1Q5ZXFwXFQAFOnRVy8pKYWkePV1vZa+htJ4V9eFEYpQShLolmGSpKz8d0HaU5aeJd82FBqV0EWlihOMJeX4JNEISWh72WRcdrq1CZeUZMimJaTIkhcZEIkGjHGdHFvUMajNdxm7SI9UCmC6Bucahm1P5xq8bfCdIy9giaQ5aOO+YZkDGMe+3ZCd8Fx920kgkSJ5eQSX8U0j0pjWE+YTIcwyOReRt+2852Z/Jf0Vw8Bmt6PfDDy/fo4zTuXAc+2EskRIUTdSDRyNIedATBAQ3m6M0LROe87WabM/Hn/4KImwDgh6sgkaK0NT+6EnxMA4epYl6topq+D37Jim/q++JsQEBE6nsyYa0lu3KhXKK+1FEFPUgbKJkNYp0Vk38JrhFzvX79dE+zIhuti/KhJTgjj9M5dK6u9YjqZM61YmzARKM68lZZ1flTILhinDlCFaJ+CizdiYJZFKYKt0Zq5rLJFUDEI45c439F0nqpLnMw8Pd4DI0J/OR+7vbvnw9i2vug6ARmVpi06/0RlNVQ0Ow7PPf0b77BnN9Q3H+3tMhna3p+t7XNOy9579sxuuX77k2Scfg3WMi1CVMJbtbqd0bINve2zTYJuWzdWNKhka5tMZZz2/+eLXTMvIeTxhba4BXNM0dL2oW+Vui4kwTW85zZFxiYSsgiFRlJMqHag+55UqY4ytC12C81Kl0ASl7K3GiICGMTpETYxJhuzpHAytmJQ+B5MLGi2/m31T9zajNiQJr6kJZLHNlEtlzNb1sAoN5gu7XU2wJE6FglQGHlbaja6VsvIuh6cWKP7SdkvfiAAx6WJNlLlQZfL4RQ5euMhGUL3a45QK0mVWZF6rMOi9igZMNDKHQp+XCAit4FlV7Crr1KiSIkaGGVqLc0anljtaba5uu4Gm3zItgTRNzOeRJUamJZCtiNb0bpABkNbVRCOliDnLOfdDz9D3OGN5uLtnmRfCEtlutuLn2o7ddkvftey2OzabHV3Xs93sxG6dl0TIlLDCVOp3QUxSTMUNVVBipQ2uNLwfcvwtEo1yZFJauPho0Jy4DBYZth0xB+a543QaibkYSjFCNeSSsgHZOpnem2WypwyOsxzGSPIT0XiclaqGM4bkItYZGt8SA3VehMHgceSQFRtdh/sJBaqgtV4Xh6LIOSlLQa8rpoqerFNBMw7h1vklYlr5hJgtIl+d6fqGbet4dtXyd1/e8Kxv6L2Mfc9G+Ptdt6Htt2TjiBm6HYIgxcTp/Mj97XfM0ZDMkRAhTAsplJ1hIeLIFpo5ke2ZJd3z21/9NefjzPFw4rPPP8elmX3f8vVX94TTI9OmE85d07HZDoxTIB0ODBzJdsL0q+xaWhZSCMIfnWeWeWQ8HzgdHwhhlqA8xFoOjVmobDHFtYH3b3GklFmmBW+tDBXMM7VdPRllHGSCSZX2lrAUTlxEkAFrZmKIuMbh25YwR1IomzLVoZON0OWQoD3MgTksOphPm71Nxicv/Q/W0ZkOYwxjDsw5EHIQdhENhoYiCWdAprfbhDdJNdYVxcwyWduKT6KqcOkphhiJOVVJZiiCxJrc6v0WtQkN/i8qSAVxcdZiFSW9/HmpNlmtPogziUSLblaifOFMJudFzyHpM81452Rgn0lQ+s5TpvOtNIuaBrxVOtFCoQHJAD1JhoSZYjHJsOgKtV4n75gkzWqINKZUfAwpWVy5DzHh2gbfeRp/TeMauqYnZFGUOhlLbHqapsE2nilNnPLMOC3iIzAyXNE7komi1uGcTsGdWeIIJrHdDPzs88/ZdgM2w7dff4XTJHbTbenalk3f4/sG6xyNtcqTFeqcdHMkSDN1O1X+uHiRhM1Z5Va1V0CpMi5DnoMiyqVi9rdfV/+uHCUcKY2kYsuxykWWTRFj6PtepEKXhcPxLL5MQ6SVflR6KeR9rQbuFcUEQsqcxpHCpW66lsYLLY4SCq9LW8+zJApR98KLQDMrVqx7Zak0yIVxwWfPKzqs0VTJhda8QxHa+r48haDL/VJ6ns3iSp2KF4gBOnKUHq1TmvExc87SXNuUQa7CkcIEU9kBKepE70TtsWp9w9B17LcbwNFvBq5v9rStJ6XAh+++5vb2PYfjIy8LNRR19cbg2lYH2BnCYsmLPMth+5rh2QtefPJT3n/7Lcu84Jzj+tkz+u2GhUzTdTRDj2laSUKhSpfHLCIRjW8wjUwsPy+Bpmlpt5ZrY4jjTNcNfPjwTihJy8Lp/ICzRmZ1qZk4Z/Fdi82Wvm0Zl7NM2E6KWKcit3qZaFAf2gVJCTUL7cuIVdo1pgI6GEwSpNw7J0P94IKCJQF17QUwhQIrwh2Nk+pv6U9Qz1oslBKclwBaVBV1feS1qrTuXauRVUGQ+o4XAMCFvZYkuCbmpTqRVRTFlPWm8aJeh1XGQ9bXFuBMXq4VkLxWDJ3TuLFpcS6oyuQkgFmKax9DWfNIn1fSnqwUy3kUXkyJZXUv9ZIgGmOIJOl7UOl+7x1d20jFnywgmW9I1hGAOUbGeWacpzoUUmauGG02k2ub55GcpFLVNI6+G/j4ozfsNhuctdzvd8RFVEev91d0TUvXtlJttzLIuut6seumq32iSQGCNcOSZC2mFYRAwZqk/VaryJKu9xSexBj/puNvnWiUB5oyddAVKolWHkTJ3rquZZpmKT1BNcoyOOT7Eqgpp5q5xlSGiCWmacG6ke2mlwt3Wk3IRioL6oQLUirvpbin4UnW/WRXyoXnWjJc+VG9Fn25US5ibapFUEqjNyGa0r9isSmy6Rs+er7jZjuwcRCXI9Zc0bQtES/zHIwRJ6ROWa45MYfEHDLjkjieZ+I0E+eF5TxCTjhnCMmIOggekiMHw/HulqZp6YeeF9c7ptORb7/6ku+++S3h9MiVg91myzBs2IcrxnHk8e6O8fGBEAMehDcaIvPhLA3ps8gMLvPENJ44nw7EIJPIc1wH/CSdOpsKp/hveZSAFGMrwi+mYqrDqbSACzsCIIKzCRsDmAWTola51uduKI+zPOPVDgSULzMkhG+PJhqZgM0S5Dp1trFUEbSyULmiFElgpVK44shLI6k6rJRE5cUqJ7TsKnI2FY0p/Nl88TMur0NP3lzYZUFZavEz54vfr998Ysuos05mbYp94vxZzzHlsjGsim1kgzMeZz3eteAiVte7yCBncpLJ2lLx0kpJ2Swk26l0CxD9Pnn0qm5hPY21dXN0XSOUJu/xztP5jvM8a++IVK+yrtElPt3k5fqS9uws4mhTEm4sEWsSm75juxnY9D3bvsNhmPZ7vHE01rPpBkGnuh5arYgYVGNcJp8XcmdRQtG7VgG0grbXp5PRRD3V3qKYAvMswg7x+7OJfjzWIz/5A6D2Lj2B+U2maZxsuG2HGydSsiu/u2yt9RmxBlDl/dWGCg9+nmecs8zzDIgqC/qcTU71nC6lvXNdwRfr89Kn5XISue63l3lCvvh/vbYnf88X376kVem5PLlT8lkluMvGkHV+Ts6ZbC0xW+aUmBL01tAaS3YWuIxIJBjLZV1rwzqAdxbvrAZ8DX3fsd1uiSlwPh95PM2EsOAbj2/8OuQXHYanNCURqfCgfkX6+QzGG5q2B0SprxkG2s1W/I+TikJYFoB1CFkJsq2tX9I/KuCDweB8y7Dds7+eefXmY7795itub98T4oiIfRS0O1V6kjMSzDsrFMmaIF7GHr/nWKtYTzPCpOwCCeqKPy62IZ6+zOdgdTVr0qkxkcyZkmdgL+Vai91V356pc5su9+LL8yy/V+Mh6p/54iTWfaq878X3Lj57Dbf0+so60eA7F9ss73W5J+bL1XTxPmqH1jm8a2jblhSdgnGr6hwm1qbr3zndLEppNdGoQgDiHIyV/i+ns1JQBaemkcTYOUfTOOKykGIgLIv0mJqIJdQ+mkL5l31V96ZlURaEUIVLjDq0IqKwGzZshgFvHeylF4Wc2W92NE1D28j+KKCiVdVFL8mxXp8SpRXUKPYiwEpNq6q/i1X5LGjVbJomqaCFv3lv+sGJRkqpGnSVJzNGp7EWw5TMpmk8/dAR045xnNZueUVRWZL0C1j3O45YslR0boHQDWIameeF3WaAZDCNk2DCZHJYqytelSFS4drojbJaarPFaNVoSgmIKOiOs+jgu/L7Ynxts1GepSAKBvCGiuLkNNK1La1rcNOJF89e8Cc//zkc3xPHA48PH/CffMRud82ULSFmztOR07QwBymxpgQhJg7nUeT1jge++/Y9Ji1YIvffvcWS2Awt8yxF0M3ujOvP2O7EEg0mR1pv+MYn3n/3Df/l//P/wen+O0wYefdXVzy7ec7N1TNevXrJ+XTi7t17Qs7YxtHvt8zTzDQtvH/7gfN5Yhwn4jITl8AySYO6BMeWkGSRzOepOmqy+R/VowGwqDB7jPJVVkMsRmrA1knnSkPRJoPGWzKRHBZ8mnHZkRdJhkSiVwMIDeakkrFGE0m/SrKH0ndilEQjGzBRy/feQWokT50nMlTlNGuk6Uy02QX9zzGSQqpOuKBZxohOdZWZvdhfylZSAvrq0I1ZJW8vEognvRAX/y5/r45RY53SgyJvmmQgIhmsThhN6EaJOngjSX/pidD7RTYYHM61tI2oVNAIR5vjsV7bFBZKkj+rutqlNGKKgZCFitYo5zjYTNNYrLe0bc92s6Hrerp+wDQtpmnIaZEmO+OYHh7Jp5HpcSS4hPUzXd9LY9yiM3WUhjcvCzksZCPnkZMhhETbNwz7jlcvr9gMHR6hQHa+4bOPP8ZicYrqWrX56CQY9ErNsVbm/xQUMdkLRaIaIGQpV2MwjlWBZpmZponj8cjDwwPn8cz9/QfGUZKNH4/ff9SlYNZvJOVYrxmCzLFo21a59pHTeaxqdOXXo66XCoLJGz4JgoqPm6dJxSMCw9ATY4cZ+qrnX2Kist4L7SBp4HAJaJknF1IuZz2HApgVNLgAynUPK6+u39S91qy+RD5n9TUlGJX3V+oEitJnL34xe5ZoOWfL4xJEMMQYWnsxdJSsTeAaNCYVfMnis1ovAY41me12w/7mipevX3A+n5i/+4bb84Lttzx78ZztfkfbtxRxlozDOgnovHOYxhKcIRjD8XQSysg4Ek+TBFuNCFs464k5yM/DjAsBr5SRwXu8MYxmBQSsk4BwmWeR4c7gs2HY7rHG8vkv/g7393eM00hYzsQwAdLTKXKiI01csM6y6ToOfpRnXRuI1+f/FGSwa0BfntdFA3hRQEwK7JWnHaPc2xSVommLZVQLqeYk+4vMFytfdTZGTlTsJ0uV3yQRo1gnZFPtt8Zohif2WhKXdSjgZcLBxX5U4/WaDz8BA3V/ynDBMFg/SyxdaPwUeVy1+SefqoF72zR0bcdu2BE1QPbW6ryjxKL9MkHvcdbKe1l3SWMIoV8jSbmzomDoPcN2SzcMQvXrNpJg+KauXcg83t8zz5HTecYvCecC1hf54iD2p88gLIt8hVDnrRhDpeo9v7pht92w6we6ppUK+/MXklAYS+s0uVBwXNZfgzHre9Vk7CKxKBVco7OIHEYUOZMkW0uYmaeZw/HI48MDp/OJ29tbWcPz37w3/XB52++hoxmkKTPJwrDGV4fprKFtPGlo6YeWSOR0GuXnWRrOAIhlQyhOryC0EZ1AgEkBEy0sifl4wsaE32Rc53Qy77ooizaxyQmbRA436bC9i4RVbi5UB1wyf+Gbi5xerqVzIzQQDRCK03C2URnWhLMZxxmfR172lj6O3H71Bc/3LU3X4Lc73j2eOcd3tF0vH+4kl/TesGscHz48Mo0zeQ7SfL0ZOG534tTmkaZpSWHhNC7Ms3C6748T+APWd/S3Bw6HB8b5xF/++Z/ycPeBt998yXJ+wKQFM408Ppy52z1w8/IZTd+yv7niw90dx9OJt3cfOB5OnM8j9x8OzLM2eCPJQwqJaIsggDSsy2yZlrhoWa9tRbXlf8SREpRZFbqeV0PTR+EiFa23SUbSyfRa8E2D7wZ+8dOP8G3Hh/tH7h8C5ykRtVQo+YAO9MKIVK3O6CBF6XO4CFZKGdchiaXI1RocjmiyyA4jcym8zllpXIMNUsVw3mNcI6vMmFo5KRWyBEqHAqpqzeqiSqmyrLvSK3T5vfWOUBH7lMPFOwktMKcLVNQJr7qgNrZ4ZwMZmaRdBgNJYJKkPx1XnxEpYy14D8PQ0DWSaJ/HA/MyEaZRKnfOYlTrXHTAtTHQynuYJJtU7zus6yg0IuMc/banaVt2u2t8J9LFwSGS2c6xnGVTmOLCtAiyYuNCCjNpguV4kA3TooiUqkJZi/Wem5sbhn5L1wo65DqH7z2brhH5+5wViRWqpUlKpUziPazTuSBW/k7OOnhUAQ9SyVn1EBBjvpju+3g4MI0T4zRqQrEwns+ypmJkGk9VoODH4w8cmrgVBC4nkCqjeRK4yaRb6dVou1Zna8wlD5Y1kZ5wB2RPKr17eQ1uUoRgMkbpDc4ZQutF4U/R5pKsr+u6INyI/ZdArvzt4nProb9QglNbg0ou/EDm6S9eJrf673oeJXhcY8WabBiLVQn6nAzJGszSk/LMMUbaIPt001hclmsX9T55vzK0zRmlllijUpkdbdey2W3YbLe0Xcvj4YF0OtPsb7h5/oybl2949uI51jegAzxdziynE+e7O1FoWmbiMrOMI1/85V9zvH/kcHdXA9IZ+PQXP+PFx2/4yc8+JywT4/nE+7/6K0wW0GB7fYPrOlrf4J1QFc0SYFnI80xUfyhzjxz9sOH1Rx/zk88+Z55HDo+3nE8PjOdH6QOMkWWaaKcJ01iGvhFRCu8YQ/Gz6zNb5f3lSNms1bdKo9LoxFzy4EsyUh9vfXbGSNWo2ENSSlFJ9movhr6Zq8P1soiA5LXvr9hVAYpsDVpZqw8l4daFk8xKsakn98QcL+sOF0BfAd6evPziAo0Rip9ZkzFJSi7uZQmSc1kPWWaxGEPXNnSt9CMsQYL4ZRpVphiNBHKlEZbp7+WznRdFJ2v13lnpZWyHgabr2O6vaNoO6z1w0X+o4FGOiSUkwpJYlkgICcPMOqRHql6lz9h7qURc3dwwDBv6vmfYDHW+Utd6lb5f/YvX5MKANKQbajxsK+Bw+UAUNDFy7Rk0ThYVtBAiSwwcHo9M88w0TpzPZ5Z54TyeRXo5Rv3z3zJ1am0a0lNVQzNaIrywYTEAK8O/mrbBh4XiJTPr4ikTp81Flms0IDH6YL3JOJNxZEGoowSEOa8ZW764kbWcaGS4YHn/XBEfvR5FmZ5O3C3o79qsh0EbfnP9PVkgtubPlowHOgNX/UBHYHy8Jww3+Mbh2p5xycTDSDcncIlstfnXO9q2Icwn5mkSrXFV8BqGgcVBsLC0PTMwTiNLTISQGOcIzGDPzEECm0Diw90d58Mjh4d7cjhjc+IxIc3KKn3qjKVpW5aQOJ1G3t/f8vh4YDxPHB5kvkQMSRuzBAmOKoubEgQjdCljjDQOknDd5iJD+Nsd1hiiNjCKc/meSoUmIGWP9Ua7I6wkam3X0A09L3cDru1Jy8J4HpmXoE3ZunleDH8zST6golqrGSDOUJTjbRYlrnXAlcVar5x7MV6r/EZr1MkQwesgu4vRmVn5nDJHrlB5SiBhq80Vh17LqmXDYC1r53wpX6mGXdBcs6qDSBFPKAOm9mPI71SECVPPJZNEIlqRj+zWz1mpiIIQG5OwTvqqyJG4zIRpIoUZi8cap8258hlWH6T4AZEQdFYmuzbeErKen3W4psd3Hc2wwTYdOCdqUzorJ6lsYghR7TWQ41LvTYwR4x2mcXhf1lorfqlpeXZzw25zxabfcbXfYRsLjdBjSYm4zBSpXaPVXJOtbpLyoJwiRbbenALKlN4URT2zDEtKMTCOI+dRps/f3z8wjmfO5zPjPBFDZJlnQeMTSpn6PRS4H4/1uPDVFVBS9SnJWy9QpixNzGIDnqWRTbrIyF6G5iXRFt/wFAHM6k+q+LCqCNWMpXxeqRSYNbBcT3U9L6ObU/nemqA8fe4VFKtoRPnJ+rr60d+7R5eBXFnP33fXRehFqn9W5eQbUszMy8gYM97AxkGTC599Xc9WfZvF6OA9K9X+tlE6dUfbNTjvOI0L0SSGxrPdbLi+uqJvWzKGRdkDYVmYY+Th7pbxdCZOo1Atw8Jv/+zPOdzd83h3R9P1JGM4LDPGyayUTz/9mDTPLOcz7776ijTPNNlw8/oNw/6K/YuXgvQi/ZHLLI25IWY8hmwcZmix1rLd7Xn2/CUvX99xffMMiIRlJMzS7B6XhbQsWNvI7AFv1x6OXOKM36PYtOZ/anslhknkbGt1jIvnVd7DojZozIVoiQOnVess/aXWlp+vvinXZ28vqnfVKuv/V4sy619rspBrEiz/plKnv3+ldZ+7tELz5NerndbKRH3ppUpbaVBeafLVji8rhKYkvhpTRpnaXhJVmQG1NrWXfMWiQLhxGEQG3isVOunCzNbi246m62n6Ade0WOeJ4XLtiz+IMRF1f7qUqwZtEndCt3JWVBCbpqNtO54/e852u2Wz2cgg10b8VaHRhRC0WTvrfCd9ejnWONeyUuTqjl/2JpVWRuV4YygKncIemueZh4dHxnGS/ep8JixCFU3aIya+6im17t90/OBE48nI+hLopIzzOlJe5x0kMksMgMU2jmE3kK3hPM4yzTIm3ZwlwhE9Z2GrZA1CrNObhJZBPbjGsN0NNE2Hdy0mW0xULnwJAKPQZLx1hKQTMxNVscKClFcTVae+akFTSpbCxV+/L+pDKRZ0uWxcqmWVM2ae2Xcdr7Y9P3k20OREms68fQ++69nf3OC7HdZ43n74wP2dfHW9Z7vtefHqmuPxlhAC1nqcbXG24fWLF7JQTOY3ruHx4YHpwy15OSFKRxIMpTgSTOKb+1v+4l//GUsxpjDJlEfXMFrHvtsx3Lzg+YuPmM4jH94deff+wIcPt3z17bfMi4yqD6mR9MnClGaCgeA8MVkihjlbbNtgvMdky3675fp6x6tXr/FdC8gwvi/+k//iD9rUx/1LQJLKq/2GMSCDHmMiJ6mmkAw2RaksZKFPOQtDYxm8Z9M0vL7e0TYdvh0Y5oi3mZ+//oj5tLCMiwxVMxCtqUlx1uqEMYY2NpAzwViWRah4JktLss3SCN7mFosVu2ksuYGm9RJgxCg0HDIB2RhNMpjWY6NU18ogQ0xW1RMjG6IzykNNyh8uknsS0JSmbROlxB25oD2RwSx1wygS1LoFIV5Rg18djCgzRDJRryUis2GMSszmHEgsWBqpTmU9EQOZIF8mkm0kZUMMjvF4TzCWUxR1nRQjeZnJ2ZOyI8yzONWmxTUi3Wud8rGtwyWR5XPGcVwOLEEm9oYQcXNgOk+4IDN80jTRGGiNoW/lHKc5MB1PTOczy3Ki8Q2ucTS9cPG7fuDV69dsN1v2V1dshoG2bdkOG0x2mGzx1hByYI4LcZGZPy0d0zJLg75FN32L9Yo+GUtjvYARIWBsizFW5Z5luu94vGOeR6bpzOPhgWkaOR4fZQqwTv2t/tQK0GE18CEbvO++V8H68fh9R9loC81CkNWo6PyanBMS2UiVarfb4pxlmWfmedFZUQWUsBKgUagFZb8owaBRoQiRNB6KfLE1Wplfuc+YFQCDTE5W6SoXDablKjQhLzQHo+u0VP2BOr1c5KuLLGgu7/50iFhNTNa/VwpFfdklwGPq76Jg4jRb4jIypZnHOBFSxBvoDbRZaEzJCs0xR3ljazJdJw2p+/2OYTMwbDZ0Q0/TdbjG02BpXMOzm2uu9zt2Xct8ODJOM8fTCWcd0zjy7Vdf82f/8k959+135GXm2fWe692O3/6rPydOCxZ49uoVGHj/9p1MHHeGJv0JYZmJh0e+/LM/4/7b7zh+/S3Xrz/i2es3/KP/8D9i//w53WbD3f0jh+OBw8MjNmVa17Aftmxf3TDsNzy/ueLNJ5/gvOXdd1/Rtp64TBxDIMXIfDoztkeaBJthz9A2dI3DIgpGqoJRAZ3yv0KrM6oCaDArqGEMMfr64GssrZG0tVbmKHinQwPB2YacJSiVSuiquSnDgCeCJsnOye9d9mSoqVQwLOtaskYT94u1Vs4n6Zwx+fdKt1oXp6lJxsWtoODp5ZIuuy2eJBv6QTmLWIpNqb5XWQdZadupKBwmI3vD+SAxyyLDNlOMkIJQfy1EI4mFsY6mlUqkzDTSyoERKWDnLKfpzByDVM+XyGQDcQrYpHvTecRbR1to0yGwjGfm04nlfIZlqQpPTePpuo7NsOXV61dsNhuurq7ph4G27dhsthVYlKpHUtniSIwZm63qbUGa12fjfVMTTu8bYWGQ1P/InLdFKYKn05F5nhjHM8fDI9M0cni4lx7BOutFE9MVZ6lJc0lLzQ/Ymn5worEsi2yumnAYjBqpBu+GKuW1Zk+waTu56TkwjxMxJBkLrydaG1aKgzMZ42STFR1joUhZZ1Wz3mJshBzJ2ZCiJAhGOYhWx7Kb0sWftLSrWt/OCudziaH2nJTA7RLdudzY5ceS1OR4uYySNJzFhevdc376yWuedwYzn4l5IsSZeFq4nY6cW5kAfHf7jsPpkePpwDhZ5rkHM0mgahApQItML04Tfb9ls7niH/2H/zGHw5G/+ou/5Nd/9Sse7+6Jy1masHNgPI0sKZNDIiVppMtI3wc541OiTYmthe++/A0Pj4988Zuv+O1333F/PPF+XsjGkl1DsI38HcOZnmgy4WIDtNbR77a4puHh7pHH8cgUz9weHlgWoe044/jJ8OYHWpfB2Z5hN8h01HEmzkcsCY/MRPEGem/Zdw29c/RGhiH6NNNMZ4iJmGCaztC27IYe13kZCjfJtHrvHEtUTewoE26xBlqPdwabGtzSKD1IUGwpUzodkyKLqqAS1gq1IHmF6LMksVGpFcfxLE3MWFJVk5AABlVuabIE+GER7qjHki6KOdUZK0SzNvFpNcLoGsyKQCJJC7bIc60N9kkriJCIaiHJRF1jxZ9Lz0KKgt6bbMlBguBckCysyPfpDrGYQDJCc8hhJqeEN+C8wTWOTIvxDa4byNZirKiCeUWTw/nEMs+cp5lzFjWYlDPL4QRMTI8LTb/Bty2tFQpZNtReFZNg0/b0vqF9/ozNRkvOw1CrF/vdjrZR7XEvCQ5GkgeLAAwpRuHxKodABvC1Qq0wVDql86pkYm1ValuWhWkZWULgdD4wjSPjODEdz4SwCMd1Hgk6c0aogkbU5HRdkaOuLw9GB5/FuAYXPx6/90gxVmpfQWcL04EMOcmk4NJkLC+Abd/R6JDOeZoJUdBAp+veW1tRzsuZGLL5U/t0rLUMQ6eDxJJwx42ixq4EL1To2uCkYsiFQhAoO4A1+LxAbC+f/kqfufASl6h0Cc5qUqE/MyXhMGsSRAmAL35OARbkM4zpSM4Q8gLRMqeZUy5KcRZsACt0Z2OMqPE1jazJfqBvOtqmp217+l56rQyishbjxPvf/pbj2w/81ncczxPjNHE8nWmbVoLtELj97Zfcf3jP1W5H1zxjf7VjTgu4xLDZ8MlnnxCN4e3piDPIXKSc8dbT9QOf/ORTupj48ouviQ+PhK6nWRa6nOmMwYSZh2+/5Te/+hVuibTOs+sG+o9esH/5jO2f/EP80LN/9YKXP/0JkcR0PhHPZ+Y0ChAZFmKYcSlgSNjLhNNePsBy29dq9xPGcalwI0GuQZKCGO2F3zcKqmrjeXleCqlbHcIoyn1Z9qZSQU+JaZpqouG8UwZJSXKKLWRVxtP1o7b2NDleE5NyrAVE/b+eM6wUO/n9dUZIqURIt4/sNQllzOgQwaRrOSWrybStATYmo4r8arPy2fM4k4zBx0yKC+QkqmleJoxbY8nWk73HNZ02j3sJ0o0hTGeWeRLK0LIQtF3gfDzDeeZ8Wui6QZrAM0IVtqIKSsrYlNn0PUPb0njPMAz0XUffd7RNS9u27HRv6rqu7k2lb8JotVXUshapjGg5yqlqazb1VtM2rTBinNX+s0AIi5x7CBwOB6ZpZJwmxvOZEIVONs+T7E3TIoBjSqqImAX6MheJssbGtWfo32aiEbSZKpdEw0g3e64GnASltBaK/q7JDL6RQXAuMXaeGCLe+lqxcJoceN34hSMTa0lYNg+daO21pKjjriTRkM91RrLQgjoa5wTT9YmwhOqUnZONIeb0xAmvoZ3+6+Lu5SySos46Qgp6vWXxRkgLm77jxYvn7NKZbAPLbDgdZ5Y58DAe6Zoeawx3d++YwsgUJgyGZekxJtLtthjvZUaBB5sTyxww7cC2HfjF3/9HnM8jU255f3/ivBjMDDkYUoB5OmogifSoAdkZkW/LmWYBnyM9mbe//YL3d/d88eXXfHt/4LAEHqKMusd6FlpNNCwn40lGAlJPwhlD7z3tZsA3LeHugWk8kw4T07zw9ddf1qFGK1omTnGz2cr9TLnqfMcYeffuHc72NJsrUjoRgyGnEx5obRbkzBq2reNV37Hzji5H0iJzRuIkjj5mmOYRGzeiTNQ2+NZjpkWpbTLVO+ZEzNKQizHQiLN1OdP4RnXLo+i31wUmITbRiOJJFieYrSFai02Z2lWH9GLEZSYZKw3O1mOzlcY97ykzJ52RmSE5Z3yGxsgciwTrQD2jA8jU+VhrK8ot4YpQ21Ky1UVXW05l2FCuGxg5EkqqYSI6uwlnnCJUBluBMCdDt1ISeWY9h6T9FaTMglR00A2eHGm6VpCgxpOsB9di257kVA6272h8gzWZMJ+Zw8x4fmTUZ2KNZz5N2qg70m0X2q7DbzupRukmYzB4Y9kOG5y3XF1fc3V1xXa7Zb/fq9KKpXErRaD0skRSibBIYS0nJ02mbGn81hp/RJokJRCVpG+aZkKQoZCH04nzdObxcMvpdOZ0GlnOoiQl81yS+q+k72mVzqiRoQaYFp3JY2Suy+9SPH88Lo9UZpM4W5E7bKqbb04J4zyuVKz1Vrq2ofGCBM/TXMU+vAJq7jLRcEpbrCH/BfKsEsmQlSpHpWdi5ee2UGAo1cpiiwtFPd2ap8BXSSLKcRm8rduVIrrrP+v31gBwTThKAnNJxwGe2NiTnxmDt5nsLFMOxDkTFsOYZwwZZxKNKTMZFk00lPrb9Wz6gda38tWKmEPTStWbGAnzwuOHe5bzTBgXjicJgk6nkX4z0PU9z54/5/j+LdPDA263YTN0XF1fEUzEOmi2Pa9/8hEZy1988YWgy0otsdbSdT1vPv4Yczjz1jryOJKOJ3wMtGQ6K0nP6e6Or3/1K9w00xjLruvx9y+4fnjDL/7eH2P7hk13w/OPP2ZZZs4PdxzfvYUlMoeRHAMxLNgcpU/UgIr0ypPUx2kuHqvInq/PQRKB1cqszvnJOWPDGm+htlJ8kdjSaiHG6iwqBHjKqq6W9XXzsuCiTNluTCOvdU7bCdVmS6UjJt0fCsXwqXWWhNhcXGdJNgoVsGAlEqOYmijnWNS0CjQq+3NJNyR5X1XQUkL6BxFa1BqnGcp0+lx6nwyEeVlvuKoMlsq6aVrAkZwn+xbXDTidjdJ4L22EYWGJJ05H6ZUrtN5xGokJMCObYaZrO0zf6dBWW5W9vLHsNluc8+z2O66vr9nudmyHoVZKvHO1x6JczqWKK1lVMUMQEAyVvVeQQypS0odZwHZrDMtylqr6dOZ0PjGOE7d3t5zHM+M41kHGqdA+a9p2EStQaHeXVbZ1AOMPhb/+VtSpElg1ONBMt2a4GeIi1IlYmlEV/cZA41rabQ9AihnvDM4ZYLlATpyYq2koNTNbWbCpctql3VLmWcQA3jocDTZp9me0BO4dzhsG59YMLUOOuQ4sk88rRhyJKehNVEUtI8FhBpYoA/oykRSmyuG1xvDNt29hGXnTJa5ay4veM5+PnE4jp8Mjd2FhiQvjeCJmGSTXtn1VQrjG4puOc4jsdlf0XUfnepYp8+3b9/xX/9X/l6br6bc3/C//1/8p8/nMf/dP/jFfffEl795+y/khkNMCUZwvGRadBm0B7w0hBo7HA1/+9tc8HM68uz/yGDKz8bhuT/ID0Tac44oURPUQ1riqNJWWkYfDQXityyIzAci0Gf6z/9V/yLJETGsFsTceg8VZz8vXb3jx5hVvPvmYxktzr+96/sX/8Kdsr59xjpmhbdi4gbZPtCnQpcAzZ+mMfiET5z1BlA5tw2gSc54JU2J8uAUD8+kFb149Z7Pb8t//6V8AlpghhlVOLpeduSBEqCSeEZGBsuZMqi9D6FGJZIrEMfiL6nQ2hr5tJQCfgwwrIhN9IAVESS2KxLFpvCzgrAl3DTQCiaTIvpZHoc7GKIexRuwVyNZWJEiCflk5MS+KtkWt6mmzWKloIGiJoK6NPGsgp1mqG2apXNYYZtR/09hGdhOXkYkPBpDucGcbmu1WGri7lpQSU4gcxhNWZfZSSoRmATLjPHFaZk5zAD2X7FXZyokMcIqBFCyGjr4fuNls2O63tG3HMPQrGuRbGh10VPLIQgOAC6EBybfIKRORUnJMYb3+LI3bAVPRwqiKIA/zwrzMnMczt7cfmKaJaZp0Km8SOpQ2A1qVKDQWaRzVSth6/zUglhusU4ttgeZovPjEH49/83GppmL0oRvjFAKVPSnkQEqSzJXBk857QIRL2sYLyl747FA325wvenRqwicI8Er90MGbMSsaSaXnrr+3tn5jZJgXWVV20kVVolYeKEgDhZu+Umfk+5fJS+HzX37ZmgzJn9Y8pQXrB66fy3oPyyHKbI7khNacnCNMkUAiZETpBoOJWYMcR9v2bDZbun6D73q67Zbt9TW7qytcI2DOh3dvuX3/gS/+6kvieSIvkU8+/kSQ4Gkmp0jrHZ8+v+H04hlD47jZ73jz+iWfff4ThqFjnibmZWK/3+Gblptn1xynke/efsc3337LsN3g24Zhf8PuxQuef/IR7z7cck6Rx2lkazJD13D14hnPX7/g5UevOH77HQ2ZYfB8+903PJyPfPnr3/Dms5+wf/mcjz/7OZt+w9V2x8Y33L79jm++/A0Bq9RsERURIQmZS5AKn81kCQyLJWiwlnLmcjxKAUMqWGcEpV5LH5fPJ6/vUQLUSzstVSsjE6ezLXRfiZdCiBgTIQRi1CZ87+onOBQQM7YKU6QiGa6fUeTnS38ghpqUPJ0bUvZaqUQGnWZeuIEpJ103WfsYI0TZH2sQXqapx0u/uPaxlZbIjE6mR+jI1gm10W23+K7DNS3zkogpy7C8eMY5R991opJG5nw6cjqfOU8jGWXPODlX8RdWKpgpVcDreic9fyKB3uHbFudFVtsVmhulr1PjjXq3S3N2oszqkPk0GpNqB4PJCWNkjyqN2cs8c3cXmZeZ8Xzm7vaWcRo5j+fatF1mwmXd9y/bIIwRhlEZbFgGI5bB52WEQzEp63Rv+wHb0w9ONGwpz+XSrS42b4u6Rs2W1w70ErxTHZ6eGLn2HpQ0rqhXlZtdrkbm4Ik7L6ywy4FmGKMqEaIOVIJBUx5ZLkxYCfgKTJxrk5XB1v4Th8NVpFiaVbV5uCaYlpwjSzCqWBRxNCwpczyNHEIgnxM8Ru7vHpjGmWk868wMaWIzOWGQ4E82wJG+n0m9x/gGTANWtJiTTkKf5igDxroMrmW46vkP/qf/M569/oivv/6KP/3Tf8759MhyPmB1orLUjIq0qmEJifMUuH84cRhnxphYjCdYx4JlyYaQYLpQMoqyoiEsmBQA5ThqnbLXxnJnpUyYUiY4T24Mxlla37BMUlJ+uP9AJrDMI323oekG+v0VKSd86+F0xttEY6CPmc7Axhl2OdMSaXOiQUv0xGrwS06qQGVYpjPzuWM+PjJsr7C7LX3b6GyCWB38amYlk1Anrj06FDQwU7P3YtP54tcpZemS3l9sIli7NgLaXDXBU8o6YyJUpMAZSYSoa6IuopLKX3yrbOhWJSDVQatSW0Z7dKB+H7vO10gX7yZOWa4hpVBuqTj4DDlrv4dcgjYgGhonwUJIgRijTsCQjdRaiwuJ4CLORIKBmA3URnz59GVZSCkwjoK8ZDFa6edoPd42WOsZ+g3DZkPf9ex3G3Zdz64b6AZR6GhbKUFb5zAl6NEqBFD9FroOTHmOyuuVxnHhwIZYNlJpMi8b67IszNPMMknDdogL0zxxOBxYFgELJIHVTUE/2JQg1UpgWdguZdBUQTzLuUn3slWqRa66hz8UOfp38Sh7yxP6hqKyxf+XH9V9o2zsRnakyynJBdCvyHJmXdPlWdXgaf2+9HyVjXi18xUEVsS1nIUpe4z6mBLoo0pmeiI5A24NpCjBiVmvoyZYmLWBWP9eru0PBgWXicXlNWsQstIvxWIlBsla4RMk3DaCjDtbZD+3dF1Pu9nQb3dsr67otlustSzLLH4mRE6PDzTZ0vuGT16/JsTI/cMj47xgY5QhoTmTg8zdSDFqE61nGkeOx6M0PXtH13V8OByZx5HbD7fEnNld7cEYXNsx3Nyw3N6xzBPvH+65nmd2xtBtBnY31zx7+RIznjEhYL0nHQLz+cz9hw88e/NKKiTDhs3VNWEcefXJT/DOc3o8cJxHlpyrjywN2OutzWuicGEHxSZqIP3kGaxW+/ucQEk8S+xV3qvw5n+H1mKM+HNbZJwvn3nW6qvsH5ViR0G0c6VBFZuu/kxPNlef+1S0ZKVPKciS0eqfsFMkoRLwLl9cT9kMUynxl+8nypmV7brSjZx3tV+j0CGDsVikMd4tgcZ6nImqHGoUWJQ1G2MUUChFxllnRaR0Ub30bNsG5xs2m53QA9uO/UYqeLvNwKDAV9M0NK0M8LPeF3xAE5Wnz5CL9QymNo/HGCoFKnPRDK4JzjRNTONU1aBCWJinieNR9qYlLCu4emFEBpQa7i+SjrQ+gYvSW+YiXlc7urDqv/H44RWNGnDnFQ02YLxSC2LRes5KcSpBVdJEo0yotGQHRerR6KYrZesyeKYYmiQRxUCbglImMc1sDEYniscUtRFGl6ne1KKwkJH3qgiBQptGEw178WfJ/svXGpYZvGtIOTHNDdM0ksKMRxp6z9PCYT4xLSfuj3dMp1EG2pGlt8SAzUHYYRnikmQY1xho25Eht2yeXWFdD67DNwOxLHXbkrLjPAUe28DNzTX/8f/mf85XX3/Fl7/9km8Oj7z/9mvGFDHzGUPGG6dUH7kHU0g8jjMfHs+cQ2TMhqVpmK3nlGGOIls7l8E0Bml2DoG8nGnyjFF+f+M8rXPSgyN0R2xcg+LowTgpn9/f3XM6zsTlzIfvjrz96rd439EMA5tnz/HDlqZzcFpobGIgM5jA1iSubGaYAj4lGqDRQlR0Sw3i55hIRqaKn8cT2VpO93e8vr5h223YbVoeDzOn8Qy2Uztc0wVrgvQjYKU0WVQcbE1Xa4JRGuYwKp9MRObY62vzhZqUlcZnYyzZRCX9STM2OcukRgRFbZqWZBIRQ6MBw2rD68K+lJkuims5r4kGBrIx2meg68CAUf172YRCHVJkbAF+RcK49EvFrJri2Uizm1ZIGifyoF3TMoVFGp+1VyJnVXqzluxmfDS4BjEOZ/G+JVpLVnGGeZqY54nj4UguM2oa6evoNz1dt2XoN3z00cdcXV2xGTYy8dQ29NYTKVOdVdTBGPCu3pO1W4wqo12qE2UHjlEQoRgjS4zMQaoVISxM88j5JCXmw+HIdDoxnUdR0jJZVaVS/fwCaSTttaiboKFSNqs2fqFdKtIpFUNVhdMeNijVp4sg88fjd45LiqPGPZTqBChgUD24yhzX4Em+e5lkrOt4RfxMthIcmHyx5tbk1SmX3rgLBRhkbRkN0EsgljOUhnNjnUixl/0UI8m20rFWCmo5T7E1q7NcLq2i2Nt6zWhgWd5A12hcp8xf/v5Kc7kIDnVOSE4C1KSYyDFXdDSbhG8srRVhBJMtzjfsrq5p+w1t19Pv92xvnnH18hWb/Vbe9ySDfa2B6Xhks7/mxc01f++P/w7jOPH119/wxVdfQQwyAHQRwG76EDmfT2SgbRoec+L+4ZElBAZr6Iee0+nI7eORb775hmwMTdsJKt/2bF++ZPzrv2Y8n/nq7Vte/uxnPDcw7HfcvHzBm598iplHwukEi4CCYTzz/ttv+eizn2IwNP2GzZUEx3ZZ2Awbjo+P5HdvOU0yLf5SCar2aVwkFCXoq3tLjXP0WV1UAMqRLoJTo8GqvE4ra5VyVRJa1vehBItKs9NYqmRC8uzFFxKFnF7WhPQCrBX/cgKXe2KBSi4D2eLrylyMy2sDtM9Phi+WuQ8F1C1qf0VxsWY0CMArwO8lQECdxt00DSFG5iUxT4t8vpSUsdYQraNJ0KRM9i1oT0atwKSog+hmAcHmWeNLj3OevuvY7a8YNltev/6I/W5P3/VslIrZOL/O4jAG3ygIZmz1KdRK9loFKup0+tgkoYhRGvhjYFkmYpKE43Q8Cf1pnjkejozjyDzPVCUw8kqHsmb9XqFB5yw0MecZNr2qYwXG85na9L86ntXozNNzLLb2Nx1/i4F9ynWzhoAMJBEZOZ0HEDWTd5KJlfOralXqdUsHvFH98TiLEVrjSXndiJ1rBB3KgCr6uKbVsrZB6xOkBNbL8JTNdov1Tj4zawJsrCoz6XAURYJiXCjqPFKOymQCqjNCVYLAkFJcg5MkNKHOd+Qo6j0q3IN3hr4xdN7Su0jyHSEETstMyIKOmlkMK6CblnFEmsrLb4eBbD1zNPimwTpL6ywhBqZReKGPj/d89+E7vr295fOff8bP/97f43//n//n/Opf/yn/4p/+N/zmT/8HpuNJlMBShpR5mBNNO5ItHCKck+WMZTINi2mYXEMwnqjDcISlnonxjA0jdjnSOegaz7PdDT/72c95+eqVlMe9p/eeoRO1nHGe+Vd/+SvevX/PV998TQgBlw1hnFX1CJxZaHPLxls2+x3GNzQWOD1gpxOvrvdsUmATZtwyK+dVUAmTwURHGRXlLLicIQZc9uRx4vG7twybLe12T5MzLhkIhtxowJEsuQyQSAW1k8GJVX0jKqJj1gaobMQGTM46D0Zt0/ma9eckCBxOAv4QI75ZkUb5WEngpGHLCF2gcCutUYRGqmc5J5aUpcnLIOsrCu82mpXbanSA5DIvlYpFiOrMMtZ5CbKMJ4a59gwY7Yk3ttVVIHaZjZS3rckYk2hco5uNJkwGGitVFQGcHEZRqDHMtM7S4BgaoS80XccYFmJcOB8fCbrRPL95yabt2PQ9+5stwzCw2+1p2oGmadkMgzbIqSxxNkQKrfLCy2XI8woLJHWuKedKpSoNclEncB+PR87nM9M0MY4njqcHpmmqfRdZ9dtDWHT6qrKHcybmvNJsKAlmljJ/FEStcZZN3/Hs+XNizMzTzLv372UDd143U3EtRof7xWVa9dzL/vrj8W88cooiG30RjGQj4IPkDWojitgVBNbUhL1URS6pUbXuoOo7K3/ysqlakkQZvlkSl5zWILIM8OqHDc5JH2EN/nOp6oktVvQwp5XiVPIFymciiaj2ItaG0IJWXgSzJVAriUPSoWQhXCidXQa9F4nVapcJktCYYpiwYcbFhSZkfIrYvOBoaBvPtu9lzXYDV68/od/uaIcNw/UVu5trrl++EDBlWbApstnv2V+d6LuWeRp59/493333DfO8cH/3gWUaaduGvmlonMNjmMNC4xz77YbXr1+ILzmfxYdZw9C1ECPL+cTxwwdOfc/UD+yGgev9nut//9/n7nTk/v5eKoxpIUxnznEhLjNd67m+viYOPWZZODw+chpHvvv1r/n08894/cnHtLut2oWld55hu2eeZrLz3N5+4JCC7CkxVfoelAF48phzWp9T8VgFUDX13/osUgmfktpfxfKLhVabrXZb6FSsTBEBTYtvLJLj1ODRGC/vpSh6mZkUjQwNDE4TVLV9CVjLLLUC1KdSWlDmhp5FUc7TxEgXLiZLw7lNhSIvoLFIRacquEBJpvJ6vVmDPIP0qjjJ0eUcCgtBFoxAgbqnzfpscky0nZWAu22rBG0OQaoAMbLb7elfvGDoOm6ur+n7ge1uR9f1NE3LMGxofCP0fVO8j9C6yrMtwFLWp1uqXBUL0HMuQ6FjTJWOO82TKkLJ/jROIi4yTbP2kmYd6JiUAr36xUohy2WeXL74maVtGoah5/rqqtLgUyy9IEWp6sKv5EK3Wv3jaoV/+PjhczS0+brMj5D4Xx273tGs2Xs5sUvO6WVTmjh1JTo5q2ouok8vtiGJhjS9IpxzsgTeZfPQjDdlHaqicpnON3jfaLAonxky0rehTUUFtZLb5DTREN37darCer6SHZbLjHqThVcrTbiZEDJLBtc3tC7Ruw05OZZ5ZlwkwI4hS6VQV3iKSVSjTBJZ1ySUraRJWUJ0+p1bEzCTI2GeSDnz6A8kHMPuis9/+UdA4Hy84+7LX/MYAmFaVHELcrZMMXFcIrOxLBZmnFCnjKsULQnkhNplcsKnBZcDrUlsmoa+9Vz1Ddebnpvthu1+T9+09E1DaxMhLDhjeHZ1JWoht+8xfYcBxmkiLYKct62jaSytgZvtQLvZ8mw/8PgdTLczm9bQhYTPYg9o30HReZf/FKE3ghpawKO9NuOZ+XggY3SardjryhXV5MFICbk4rbKIysJ6WiIstl02D7Nu7DUiFFsu71G7mIon1mqaSVaGYWUNTLRMmo0hJZktUSgVhZKTs1X5zqS9G2uZU5ChVOV2jX5OcdhF7kOoGno/rNxDp9KtSSshMSd0msTFda9rRvibQhUSqpQGd5QNLddgDn0+BXlqnMXh8I2HThLp/WbLrh/Y9ht21xu6rmMYNngvJefG+7obx4ugsSLAXGzKF49M6F/qHGPQdRpqIjEvM6fjqSYa03zmfD7WEvSyLFW+KGlyWQLXS+zOqB1cfEM3WrsGcknWeIhKrarN/esGu1ba1gCxhBQ/NoP/mw+pOCSplCGWmHToXInU17sn/nzF+QuYYLVh+3vJKzLQsnLmyxpS5LUkHUVWsgZg+i7ONzjv6yAur30hUBISpeCyVlOKzG6prj859WIhmaogR76svkBpDK2VTgUaUhLp6bAslMFqZSr9E9pESVLU15m0QIrkMOOTqCr5mHApYWOUKo51OOPou4F+t+fq+YuaaLT7PcPVnm63Z5pHkRvXoZmu8aKoNC2M8cyHDx8IIfD4KBLQQ1ECM1qhKrO0QqRxjtY7kaZeFpZpknsZI2leONzecucbXIJpu6UfOna7LX3fM49nwnjmcPueW1UMO9w9MB0eScuMSQnvLNuhI6fA/f0dj7cfeLi95Wq3lWfa9TgyMQSuX75i/+4d07JwPjzKc0oFlb9IKta843uJhvoQ8qoiVF+r/kaVM8vriv1i1tC7vkd9i1WBqcRD4iRt/ayyN1X7zVn2pwsqFkkV/srr7Eo7zWnty8gpQpbqcrEp6h6U6p5q6vmWr9XEBWSTDcpqc3NC3iLm9R4UZk1drVkyuBRZxVLqNa9rqNyXUomxRofhOivVf+PwTvqJd5uezTDUOS9d1zH0g6hSOYd3jc7PglK2XP2CfGC6sAGpqBu9T1niPKXrxiBzKpYl1D1pnieOxyPLMjFNI9N8FulZVfe83A5zBVpKa4MmrTlXmzNlb0IZGTrnI8aofZyrH6nVLwmNLjzi+rxKX//fdPxw6lR5OClJMzMQchIetZFugO9/YpXp0+TCOdXNdzroTJMHqW3ojcqaWesgLEH6MthM40rQLyouANY1woV3VhpNfYPzrcxByFknJUqQqviTGumMcGFdzZBrM7q+svDpQ5BG8hhL0J5EvnYRXWYbAyGMjGnmFy8+Zmgb9qYh2hPn45H44T3THJljwgSRyW2d5TSeCFnoSss4M4+LSF/iwHih0ThL23ra1hJjQ+Mt85QweK6HG7pmi/NbPv3lG168esYvfvYpD1/8Fb/91a+4//Y7bpfInDK+6TkmyzQlzm3HnC0zltG1ROOIpqnOzucF4oyJM90ysrGZq8Fzc7URbfS+JY8Hjh8MLQbbdZim4cPDB8bxzOFw5NXrNzy/uaZroe08zlnu72+ZjyPz4Sz0OuuJOfCL1895/cmnfPzpG/70n/5jfv2vJzbxhBkjJowkKw7bmExMhtpLUZINYSjhsmi7x5wI85njh7fY8cTQDRy9weSoTWyOlHyJm/FO4YULCUt46qyK44gl4MwSrKScFJlHbVY49hmlVuj7Zqsr1iBlVCt9SnGOorBR0YJMNBFnrahh6PdSSSYwGJUsBm0yzCABhyiiWTIuy1cQr4tJEWukX4psaFuPsV6cuebWIRnmJRKWWK9XHKMmxJV+ZFjmqQYw1jay9BMyC8IYuqZVRYwkqOEiA+u2255u2HD14gXb3ZZ+6NnroK6uaVVzHtmUynkvWWbvIIIG5cSSKUGXUjQzOJerFGmchdsaF0E950l6Kh4epGpxPp9VMvDpdNNSvXJOFbcy4ieSPPdUkraq9lLdmfxbfYn1QkE7nkem5S3jeREqZSlpG+h72dBMXgMMZwwhyZyS0oD3Y6LxB46UpdKoUuclBEvmomHTGPX3JSxZ17VQLrxSki6qCBfBQs0hjan9EZeJplXqVAkMZaGr/K2TRlDvG0mwMxfrHWLpMSn6E7MoOqHJRqZUI7ICDxcNtlGAiIJoPvm6UJRJGhAKbz2sXPyqk78ChOX+yB+ZxiRsTtgwM+RIaxK9jXRhwS8S3OcEpt+y3e25evGaT3/xR3TbHb7roetoNj39bsP0cEdKiTlDNBacwzUN83lknGb+4i//ghQT59MZ6xu6viMsC84aWuc5zzPj4cjDh1vysuBypvOOx7tb4jxzvL8jnE+k8cxXf/mXfPfrL/DeM/Q9z1++4PM//iPC8QjTyO2Ht/zF8Z6v//UWa50EWnPALIHWe3bbLS/2e3pn+fW//Nd88ed/jmtb/oPXr7BdR7vZYJxjwPDqp59zPJ6wvuX4xV9jzQMxKJKfQCTBlUKU11kalwlB2c9KckJ9Tfn3xWsqDLEmzSuVT7u/9JlLaGaFPgR1HypiBREN7Is6mn6C0Z7GnGSiNYh4h9Wkr/aE5KRVB4iL+GdjLhreDTXZyDlW2h9IIhx1flhZf42XmM5aU0UMQkwsSyCkRdel3rWUVAnKEHV9ZCM0eUlKhJ5n88W5ZL0FWk2RvTLReoezDX3j2e33DJuBZzc39F1L17ZSFVdwqwg4xLBIf2IuCoG2Tviu1Zgka9bUz8+M06ziIjPTWWhP59OR4/HINJXkouxNpQKpsKUptNwCThgFDsph6p8V6CqT1CsYY5inhbBEprNM+I4pMU8T1nlROyusiNqyqwlISvXZrv1ff/j44YlG09YLNL6ViyDjjEjVumKkF3QSMhUlssavg/OMoYw8r2oeZWAYaNKiG382dVhWQVgygCkawutmL8N0kyjxxCwrKCSmIBrpyzJXB71MY61IOCdB1JKmiu7IwpL3nZdZ+32NJhqRFBdtLs80aaK3iexhzHA/ThwO70gPB9I04U2gMwlrZKaHiRaSxSSRi3VNhuVIGi3L6Raz2WFdBNNjLTjXEIMs8KEbOE+PktjMB5bpRJxHtt1r7BAYty94+ekvOJ4Wbj880LqISYGUZ1LuWLIjNT0xW2Ky4DoJioxHIsWEjwmTAibObJvMtrFc9Z5usHifyXkixTNxcaTlwBzPBGMFDUqRoXX0jcN4z8evPuY8nRjHM+NxZBknlhAI40K/2fHi9XO++OJLvn77lu/ef8zx/o5u6HDjhPEe6xuSF7pKTBr5GrULMgaHPGgFn3PCECAklvNBEpKtxZpE0znGErTbFU0JSQLpnE1dkGJn0hCdKjLCk8pEzEUJTexCppkrWlSQFFP+alVbP7GEKGhkQTUwNfgEQThMcWRxIZFIFqwVBa/VpUigYYzQqopMXgaZOm8dqe0FCUuZrm0FffReBi5aQ0iJGBZCDMwn4aLGlDEq0yn7ngTxMkJR6IahJGDOsoSoGufQtBbvDV3r6PuBbhi4uXlB07Yy9bTxeO/YNp6262mahk4buKXEXHMzkbzWjS4pLaWcFtkIgGSMAhVJgvrHEyEshLDwcH/HPE1M45lxPItO+DwLcJBEnSOlWIOtUmEojGIjcF/Fvgv4Zmrl78KlGxmilJGqpdGSkQwwVJ+kSdrlJhEv+fKKQCUSpZuz9MpcTpf/8Xh69H2vS81UmsVl5cEp7a6irurjjQZMAoCZisKWo1QrYA0ITfl+haMKkFbkbVfo0Drt0dJAIKYo9M1UAqxYhQSWeVHVw8g8TRfnIOdbeomKVHUqScIFfSVpAPAkebhIIApQmFLhuGtgWl5ziVRSGorlvG2ONGGmp1QxIzZMmDDTOE9nPdvNjpvnr3j20cd89JPPMG0HvmEC2k1Hv9sSLBjvOB8PGO9BgUfvG0zM3Fzf4J0jxsSHu3tSztze3zMHUUl6eDzwq1/9NQHDn/3LPxNeujEcD0fA0jQNz549A1au/DQG4jxhLPRfbzHnE3EcGe/uObx7K1SU8yTxSja4ZOj7jufPnvGzX3zOdjPQe8fhw3t++1e/4hf/6B/SXV/jho34paZje/Oclx99irGe28MD33y4v0jkBKxZq+krmCF3/WniwfpoVjuooR2QS4+XVlgvAz0NDE1JWMi1gip9D8We8womaWyVciYo1euJTVD2AAV4df9NtWKjMrRWhGHKeaYoPtV6J2IvRj63aRrZm1Q8JsdM2/VYJ7bgGqkOxpxY5pklBOI4EpG9+rLRXJIVBQCNio6YdZjdZV9x4xzeWYahZ9hsGIae3dWVDnXtaX2Ld5au8SrD3LDtB4lhE4Qw1/Vebrl3a//x7IpqqvwwZhH8kblJSYe4zizLwuP9PfM0Mo8j06TzlWbZt5L6gxL8F6ne8pmyBxVvBCJQtFYhStWpGJXE31oVy+ssLhBZ/CVcqCQ698RHViMt9ldsQ/3nhVX+weMHJxq+aesG6X2rBDDhSVsjU3JxZlVL4fLCJdHAaNNbCao0UICLzVdMVG9oKTdaSEZ07DPU9BAJbnJJFUupzSzkRZAElsQYF0KSab1RHXKcJ9HOj0nQ45yY0qRIUCYsgYLwL8u8PtBUGpyW+lDbPIMHj+UwL8zLSL5/xBxO+LQwWIPXhR5LspQKMiCSgSbP5DAS5hO2kYb5uJyIjSWllrCIqK93LUtcmMLC48Mtt7dv2V3veP3TT8jZYlzP1cuP2X+4w3Z/hR9niIkliqFFDMF6STRwYJVbLFNREMRC9NEdmV3fsOs8+02L64QbnEMm54UUJznHLJvncj5hjBU5N5NwznJzdU2+S8zjjDEe6xK+RZB2Z/Ftx/sPd4S7jG0sLowVwRWEw8uARiP37rJUWuZfizJS0ezJymVNpHkSR9NtMCSsM6SlOFGpTJCl3+D7yJIsqFjtWNcl2Yi9F2nA+nsFhUpZEQBTaTdrwKKqFiljkg57fDKpSd+sILRAjssFelDQ7VUVrEhpei9VsoICSXDlyHhBQhN0vVAE8B7bCXDgYhBVtDyRmGswXWlIei+SKXzfjIbCMkG1achGJjAbLN1gaRrHru/ohw3DsOHmWp1524uilLF03tbhRE6bnwuNA2PElxjpxwj6hDKCHBVHF1MZapeJSeZZHB8PzPPEMk/cfvjANI5M41loFaogVe5fSIs4zILKGQFGVNBEkiq9rvpsdCNbpy+XH6gfKwiSigilpBCaPus1MZHXFySqIFNrUIgEBxogshZcfjy+d7RtQ7n/tfpTKw92baq+TDSKikz9uS69GKt/ebpuC23ud4NAoFbUyv4BIvhRBBpSBhsc1i61yhC+l2iEGCp9ogRRBkGOY0xS5UprJaRcR6ksrr0VaxDGxf8FTM1V4lJcTEHHa4irf+j6J5NjwKWIC4skGSbjbMTGiAuR1jk6nWa8vbpmd/2M/bMXJOeIWGIM+K6nGTZ0WTjoTdvjfIv1jSCo1mGsY7/b0XUdxjoO55GM4TSOYCyuaQgx8eH2Hn7zJe/f3+O9Y39zLT061rHdX/Hy1Wu6YQvGiXJcFNls3zTkjKDTOdI3DXeHRw6PDzzcPciAYB0U3HcdYZr5+JOPGLYD3kjT+v27d0ynE24YsP1AMgbjPe1my/7mGTEEdjvxdwJOXKznspeU/YX1/l/c8voYftfM1uebKuKy2mpGZkuYXKpyxRai2nDZN0z92DVoXpMNqh3pSdXzy1JpNpocFSoUGXRYpvPuIplChU68DgWUjy4qTFLdhZQNfT8oku7wmmiEGEUMJ5UKjYJ+dd8tMWQJovXqyiw1FU0A8CnRtTIfY7vdsNkMDMOG/X6/JhqNzH7qvOxrzjkad9EDFVNVWr2Ukhb8vFR55LVBpc6DrudC2Z10fsXD3a1QocaRZZ6lIhk1EsklxpSekapAZ4uNmItEQkCu+veL/6/f0USlKK5ysd9kAcbKvSx9PDUGeGKiq4+5dBW/z1K/f/zgRONqc7U6t5xlEFHjsblusRTlX2niFuS4EJEwisgUDpjRbDMmdaYy/0KQlFhfK0ivoqjaxxAXeYgpJZYkWV9Bl6Wx1ZAWUccgZOZc5iBTIzObMibmSkPJxpCckUak8oj0YRSlERl6Jo4/xFkUQ4yhcY7zMjPNI//9X/yKLk/08yNv+p5903PdWeblgRQitulqJn+10ebbuIgsp7GcjzPxfEuyd4zDLf12x8N2T0wG6xradsPt7S0PhwPffvPf8s/++T/m5sVL/rP/w/+R3fUNTb/hzS/+PZJrePvtOz789a845Ttszoy2YTaex2yIeIKVgTU5GQnM8wIEOpfprGfoHH/3Fz9ht+nYdp7jdGIJC2GacdaQ4szxcMs8zoyj6KA752j6Htt7tlfXPH/1E+aYWbLjj168FlQkBk7HRw7nM9+8fQu2Zeg2bDZ7Ht8eON3d89onbDBS/cmmUvfmvAg1KoqcrTdGzViqajGV+RYJwkLGksaRFCKRQEhSGUkp0ZmyJF2tti3zJM2lutBXZ13sRymATqotWSsTMYrylLWOHKJu6DIQyXmH9TqkKksPTEEpUaS+8dK4LfQolP4UkU4Msd6+cXW6bpnqmqIoGjWtl0ZxkwkmYTSBDNEQggQq0XcswJISTiuMzracx4lTCHJvTcYYr/MdstislTVtvFZqjKFrOrquZ7NdnfXQb2kHrVh43VWywXcbvPUycdU2MqvAKZqVUu0GkQnO6k+yqYpLIqcpKOy5oD9L5PHxnvM4cf9w5DwdmMPEcRw1kU9M44TL4JXaeVmZSDmzhEKBU/FrI8nLksRzeStD3pyx2vdFTSCg7MelZ0uDOEW0jaLWXFCyiv+3F0h5+eblpp61XwygMU3dfH48fv/R94P+baVarFWNp6V92S9z/fll8p9VuKG8l6g6ZQ0c1mbWMs240I/kLXPlWcs8FR1Kerlf6rOue1ssScm6sZeqg5xBPeE1CdeflL+ldNGg+zt35vfYjAZlBeAwF4FuiT+//0ZZ+75sSniTaS00MdFjGJqWNy9fc/PqJW8++5yXn37K/vUb+v2eMcp9ixnwHU23Yec93jUsxxPxcCKeJrp+IBxGEpFPPvqU3X6Pb1u+fn/HFAKnENm+eEH77DnvpyATwB8O7F9+zPMXz/n8Fz/jj/7B3+fq5oZ+s+U8zcxLZImp9sWYLHNTmqGnz4k8T9x++xVvv/mGu/fv+erLrxiPZ87HM4e7e8KycHs48atf/5p+6AjzzHI4kn3D+HjAdwM0MovBupZ2aLl5+Yam6Xj99ju2X3wle0EN2EyN2ct6vkw+Ek8Tjd9Z7jlXqe2cpDn7ew9WsK1SWXBujZ+KjbKi3Bm0guCwvqnvItKuSem2kjzXoQNGGuBX+yjJu6XpBtqmpeuGSpGHjNW9qQDQIas6qLMsSyREqaL4tiPlzLgEGuMkaDeWxRimnFlyJhow3pGWVeWwdmWVCqY1dIMMehw2W7a7HU3TMHQdfduKKpT3OlRPFKGcb7TKogAnEhfmlAm5qLxZGu8rAEr1C4EQJEEbp5klSP/E4+HAOI0cDkdOpxPLPDONY/UPQeWdC0Fi3QfWRGOtgOk8kJRZgiSNRVjC6kDaCgwUOfR84S8Ma5Wz9mquNlagBtQTGC4AmQtfcelPyrnX5PlvOH646pTR06mUkFKa0huRBHEu5Ke1wUzPQhGcMg06aVBkk1QJYioSndLYl+JaEi4PoPS0ltHoUuqLVe0lpChBjLVIBzgQE0GHlFlrVdYTbMr6hSYaquZcszXFsITMJw8x13UK1kkQmw1LTDL1Gc/DOdHkTBcMjbEsUXj7MTkps6YgCgnO0LIIjuCEv04MtCmxYAg5M57eE5YD0+mBhCNnQ0qOh8dHTqczx3e3TA8PnD7c8Y//3/8lrz/5CW9++lPCeKZxnmfPn3O+e2DJojc+JcMpGyZkPkdW+duKYJjiVBI2S7n89sN7wrTBXF+x3e5JKXI3viXNgUTAhsSiG2ffdcpLNIQlME8L8xIYdntcv8MPHUalEo/HHZtxpr068+aTn9J2A3fHex7u37NYy5jlPvpc+oOQJLA6aIfQZ1Z0IWdJSXPO+FzQYC0NapNgDkUIxF40MmWyTmMuIgMUPuTFYaAq3CQTtbITgVCRz1IBIJeKRVanLb0brqDW2ibuslS2nLXQGQweTI+zIudsDaVbjbYdaHyL9602yTm5FrXR43gSx5cjzoN1XpKqrFWbGAgxcp7OMmXbS7/QnAIhi8Mv1Q9rHMaBsTLMrG09u6st1svAvVZVN6RxexDNcN9hG1tn5Dil5FnnVRK3oYhAGJNqE3k5VqEGQYaXWSiP5/HMvIiU7uFRtcGXhUl5rOcpENMo9hGkT4WUacrzzUk/V57iJSoj82AixqyNs3MShaFkDa0FnMHaix4OdceSdBRET79fuMPyiguq1AVCpP5Fvief9X2e62XYaIqf/fH4vcdlwnBJI1n3IKrfqBWjXNBbKgK5qj/Vd1aASYZ61fcrfQ8F0dXgsVa71Y7CRbWBi3PL9b1WmypDY2sipL9T/VMJWHOuvubJUf1iuR9Pg4Ly8YXfb/6QPZXPNqXqof/OStG0hqHt2DnLvnU8e/GCmxcv2T97Trfb02zET5AjKWalsRiycTjX0DQdfb9ht7siXJ24urohHSbOY+D2wz2nccY2DcdxxrQNu+cvePXJJ3TbLTc//UwGWlpLa3o2uy3PXtzQP3+OGXryZkuztdgMaZwwzoFz6uscrvXS+BsDV12HvX7O1fHA9U9/znKemE4jh9s7Do+PvP3uWwIzD8cj9w+P2JCITct0PNNsR3I/0RmPcRIUu6aj7QY22x1d3+ObtgZ566A0LmyGi++tNlqTkvKKkhzUPodKtlp/jMZHhqqmJoFlrMnjKvdd+swE1DCpVAGpFY2ck84DEZUz61azs2Wgn5U9zTpH1/Wa1K17k64KMplpOgs9Nyz4RuhUKWkvRYJ5Efnk8zjStAGvUrVLStLHWkFqodtb5DyaxtP4ht1uWwUXml72praX4a6N97Te47Xvw2niYK2V6oqKNZRVZclKi306Xwd9dlGV20IMnM5n5kUauGVuhTBnSv/fNI1VzSmGUs3MOL0vslFI4nLRIl+TxFWgISltUpCunDUwwklsruZg0+9PCqp3MMVTrpWsEjutvmWNgfmeL1Frre/8Q7elH5xoxCdOUTxQUSUgr6WiRCbldY5GyZDjskh3e4rypyYlJkmT1BIjUYdm2FwQzLIgi+qOeXIOuZyX3ucQgzabO0yU8zIpk72RAX3ooierVGWNC+pCF7pGrkjTE4ecLxAf5yDJA1qiqkNhOM4LLhmm6GiNYxFyPU12eONo0oy3hr5xdGmqC2bKgRwXWlUgySZzGu+YjMXQYEzLEhOn88J0OjNPM/PdibNtOPgP/NOY+OyPfklYRq72e0yKXF1f8+HqOafFEuI9U0icQ2YWvByw2JJ56cUZAyZp81+O3N/ekkNg6HpePHuByYn79B1RFw826EwT6LoWY602RkXmeWGcF7rNFdtuwPUdpABxxvc9wxLo5sA/+Id/QtsP/Lf/7J9C0zEbxykvdDnTkmmLLSWVUc0Go4lGziJPrFsZVnn1ZSmUADvH0piXpYIjRqTLRhZz0mdfQpKqwGHWxSt0K2l+zDGI0IBVyWYtTZZzQVWPyFKlM4Cx7oIIJI2/gpg7jLdYb3GuwVlP67xqcEtfReMadeBFR98RrSSpc1g4HA9MkzSQNR04n8GsyXWKC/M8czg9MuQF34j605wWIkn7j8Tdeu9xVmZmbPqOvut49vKapiQY/VBRlabxOrjTSR+KyaJ/7zzetRjndbBeU4GD0vdyiaiWv6ckSi7n85lpnnl4fOQ4nhmnkYeHB+W5zuTzpOvZYJ0qOV1Ag61VquPvgVzKd1KKpBAk0VCpwEUiVpKJWC/25Fyqvym9OGJ7VWErszoTfV3Wtb1WUgr6IwltSTxWH3PhbEzpAdC96Heu4MejHEV9Toxcq+UXSUbUPpxCdQR5XqWyUAKHInlcg7ysSXpSwCuXZCLWpOIyYqzAWglKTFZQ4ym6aC7OYW1IN09fV1ASNQDDGqCWdKG818XLntjJmmCoBSoCqXhkHeq2hiL58qeaKK+BLIgEd+McQ9+y71uebXqevXjB1fPn7G5u6HY7/DDI4NkoPlU0DKWvyVqPcw1dt2G73RP3Z/b7a87dA5M58vbdB3zXkp3jPC9sNhv2L1/yk1/+kmevXvHTEMnWkq3DpV4qWN4wpYVgDbbtcV2PcZ58PBGRpnM/tKJw2Thp0s+ZftjQPHvJdQi8mmbSvBDnhcPtHbfv3mH//M+4/e2vON2dOI4T3jhMNzKeR5rziBlmfNNjs9Wp6Q2+FSS97YdV6CYX21vR5pKcXiYV9dGXZLjYQfmuqg+SL+KSmpyqncWsggdrUmxU3dCo0l2JqUQCN2GyKqZhsVnB4izKh85YfKl8qLCByME2uKYVtTEv+5TTniShwUk1MMbAPE+cw5FpWhjniabNON9grFcWjPSRzMvC4XSiDYHGy74zxygshJxA+4O8l+qD955hGKSf5vlzuq6jaVu8Dm+1TvYcGShsq9JTkY4uIhBOq15Co5XqdqHQ1TpkRqsKUk0aJ2ngfnh85Hg+M00jh/u7CoLVIa4l0csVCpE5ajq/SpRGy+I0F886K7VsHQR7KZGb7OpnrFY0TJaCQHm/VcxiXb/m4t/rrB2Ku1NK1rriiyhFNbILj/G32ZN+cKLx7v2tVhhiDcqDZmhFmz7lwqVb5VjXRXSxuHTRGaTBVW5qXptUcq4XUh5SRhoiU84sMciTQm56KQulnMBmbE6iUmMAl3W6uJYF1+RPpUIzJHlIWnWqjtUo5SLpOI/Vmxu8oq8GaFwjU4VzJLuGlFty6rjNMIVME2HvW7zL+JTYdo7rwbLLvU65ToxhYcmJ0+O32F7QAZZZndOCYcGGTHOeOB+P5DmwtSpxmmbO33zBX96/5Tf/6l+wvXlO2w/sNld8OBz5ME58cw4s1hOdqw1SKSxYPIW61mDxODyW7faK59uBv/Pzn0qg2TR8/eUXHB4febi/xTvZHAO+IubLvOCahqbvoRnJzmIfb+lxtNmSzmd1uonb9++4u7/ny6+/5jdffsX++hlvfvI50wTv3j2yuIWdhWvTkPNZAnzbkNJCQJ61Q+ZqxJCVj+mFF6+OMsRMNgHjpV8nRWTKrLHkbImKGCxETPYYY1lC8fAW51CbD0gEa8jGY7KDYElmFocdIr5FyrEOjCkKNK4mtJ0TDjLGk73AQ8Ya+r6l8Z6maXFOEBnrpFFuiVo9yUJ3mk3GGFGNydoYby3kGInTwnKcCeMsyixuxjjLdrtb6YIYTEikMXJeHtAJfPgsA8x2w5au9Wy6lqv9jUzi3mzphxbnpUnaGoszQrdLyMwNWUYZg0gbGyNTeK1xYA1tK3SpJYcaNDnbEFIk5MB4HpmnhWWcOZwO0sB9OvN4OjItM8dlVMnQy6RPJD0t4A0SICLUqxKsxQiiNCTqV3KeGtClTAxR5ATnmcZb9V+ZWLj71rLEQJlcn7UZ0hWJbQtZe8/Uy0myo5SJlMDaQOHFp6zJMUK/xEDbtXXzshcDCNUDiT+6DEB/PH7n+O7tewptLZNrZeJyynu9j6BJwlo9qIno96oCK/VFv5lXtBjKRltoCFmTkig+2yBARqE85VR53PaiJ6S8ccyxfpbRcyGtWvg1Znjye5qo6AvWfDWLD7r43fVsLy6oBrt6HaxBa/kjY8B7khHln2g8yTdcvfyI18+v+PjlM65ePWdzdU2/v2K/f0a3u8F0Ax5HazxtzHgDVpuDHZau7VnaHtcN+P2O3LacU+Kf/es/xbUt/XbD3/n7/4BPfvpT/ugXv2Az9KQYaLuG7B3JWh6+uuX8eBTRh2XCNp6rVy+4+fRj+psbaC3jsjAtI7hEMzR0g8eOM3mcOX73HpYAIRLnmcZ7urZhuOpxwxuGl3ua+R+wHE/85V/8ii+/+Za7w4mHhwP91TNe+obx7p7kLO1uKwwNn9leX7PdX9Fvt4Qgik3ZrMqasVLuiu2Z8mTWRPiCyaFobqVhajdG/XaxSVcipozQc0sFwFitmhsFhKA1viY6jTM1iWgbqfwaa+kb2ZvatpVEovEYraLHlJiXQMyQrGXJCaJQdAtK7r2vQ+AOp5FpmlnmhWmMWDezHTZyXzTIM0vELpHp/MhEZvIi7e+s5Wq3o208fddys71m6Hv2261Qnpy8rtCfi+2mXAQNJG4talmrwlx5f6ncVHGRbFmi7PvL6UgIi1YsjszzxEmn0U/zzHkaKcNyrZOAP2cUgFRgMgq9VsY1KOWqTOi09uI89dlnFKidlVZf+meS9CIZg00JExCQE53nZMqwUAlUL0UrsDz5jPJBZS8se01U8MQgirAlAE8xVr9RK/QFLPsBe9MPTjQOh2N907JxRtWmr0kFFQu+kFbTB6/JQzGCEnDU94u5LsQ6sAillBSoHeGrJ1SLHsngy3uQswxRSxbrqdM5f99RNes1ay+PpIoO6bmXzvri0It95Mp1BWmEknKeEuVJGJaUmIBTSnRNh7eOPCW8kUFmjU80JtPaRNsaTDKMi0h65ogEc0rtsAZMSNi44EIih4zLFkjkCJGZnAMpjJzjwtJvyLOUIHdXVzxzA8dlES5+XCSzr1lXcUDiyITGJtdwOJ0ZxxFi5O27D4znI2GeaBuLT0YVmzLRZJaUaI3BY3BNo2i8F9pLOpK1ETDEyN2HD9w/3PP4cEdI8PB4xHQ7PtwfeTjOZL+QvaVrtQ8hiy3ELApRsViTZuCr+r0msOhElKwytZGaFEtfRenHySKDGVPdhC1or09B+VZFKChJrCE55c+TaFonEstFeQJRgcrK9XRNizQh2zXZtQacJztPskIxytaTjSUSmZM4m4KGuSxc1/M0a5JsaBsnicZ5Zh4nlmkmL5FkI8ZaFjsJ6meplQKPKDo5b2n7gaHt6JqGzjW0raPvGrbDnta3DF2L8xJMzSnUBtsSXK1Sv3LVxdUJbUrWhVAeJXAK86xKTIE5iCMdx5kwC9VuHM/EJbBM0m+xxMCSgzjNtQe++hkhvVE/HaUiyccJgmNLqbkormSqD8vFFxR/UH4fmcNhS3dQTk/sQH4vI8pkF0EcsslrzqHBq3zfFsCi+MWCvJdr0sjhMqn4Mcn4m4/Hw3HdNKEmGpeTvXMNqsveVDagi+C+2LT+INm16TppWbBWCTCromKROVYApCLY5fnr3lRpG2KUF6WsAqllpSuZau9W+dTFhle6hfzeSokwF9dTpHsvbpJRz1hwFL2YAjKtV5UvaHqm7qkpG6I1jGROOXMyhqXrsVdXDC9f0V9f0908w262ojblHMY5nJMATMQeUr1Xznl5z5RZQiJYQ2w8IXn67YZnr17z81/8gjev39Bh+fDFbzmPEzOJ7B3ZWR6+eWQ8njg+HshkbOO5/faa4/HA7vVruo/eYIzFWyeKXmNkTiMPX3/HePvA+7/6gjxLopGWuVZdQw4CxjWWj1+8ZLPb8vM/+iV+s+Xd/QNt12GtIUZRCHPWMntH20k4Zez6fJ8kuKyUuUtqefGexT6Lb5X8tKhvaihYzWb1FdWKioyzyqoal7EkfON01kNpXhY0X81TGCCahORqS7I3JeeJWqEw2rAfQmQOUfahnLV6IGpF4ziq5Vi6tiXGyDROTKNUocMSahI/G/mdovIXY8TERKuJw2YYBIhrGtrG0TaermvYdVvapmXoe6nWXJgrBZDX4L0yfzKyP1uLNU7nseneRCKnwLKU/glRh4pLkAF5i0zjPo9Cg5rnmdP5zBICcwiyL12st5yR3uOcK/BmuIjHK8qwLtBiBcXflL2gvCrXV2mcqxdW9qSsCZXB1srECurz5L3Wf63fME//eeFP8hNbLVF4Pf8fuDf94ETj7vYBkDJNWSwxhSf8tXJku2bj1QxyeepQKxYK++WUSSHVIWAxhVruan2jskyekmjE0iwehce9BjmiCBCtxXZoyU+kC4vmfrmZ1qrCRIK2aeqE3/KadXDJmrEVDWJMJpq5Uk2kKcnIORoDxpFwLJJy8RAjfd9jfWaeElOyjMkRu8zGw5VPcg4J3MNZSppLJCcr92VZ8BoM22WiDRkXDS1IYJSlYV7McGQ6BJbxwIfzmZtPf8nN/hk3ecPX77/l27t3nB9GJMfyogxr0ABZmhinkJhiZFwCv/r1lyzTmdPjIykEnMnsOktKUtUhLkQDwYBvIfuWwXnaYUu/3dMOWx6OM+fpiEMk3qZx5Nuvv+RwPHB8fOTh/oRrb3kMni+/fse7x4mzm4mdo8stQzQ02dI6T8wymyDmIjQgiV1Jdr0yUR3Cm41GBmKlkMlBkW+l9sW4SFDgPaSAyUpl0garbErgkLBFBSrH2kyWm16NyeA7I9KxxqmpW3abjShJKG2rrImCtsScCFgSlhAFmfdGmsUXdWz3dwdSSrRdT7dpMdZwd38vSFKG3WYgh0A4npkfj+RFByYB2RqmcNRKi2GcR4wxtL5h23cMfcezZy+4ub5mt9vRNZJUWG9wiN5/CpEQJ2KO/P/Z+49nW7IsvRP7beHuR1zxZIjMyMjMyqrKEgAKhQLQLGuwG93W1tbsMY3/Auec8G/pGcc0DjjghE2MQBrIVkB3QZVIGTriySuOcPe99+Jgrb3db2QUKmDWM4Rn3njv3XPvOS72XvL7vlXIrVLrg9e5EqnCRxTi570q0UUXrcLiyZNVlB0c7w6M5yN39zeMpwPTdObucFKOVxFctn2MYyoq4uC9DuV0wev3RDtoYOLGAs7ZlG3qlHKb8YEOeWwGthVKpBH4g0EDKLPJzZqYRRGIGkwWSeZ/1fZVye2SK6bfV9Fb8xaaHEuWRZ/eDHfO2WyFb/K21W1QizbV9hjM77s5Gn/98fbtW2qAhgXOKecWhCxOl4eFr/U9bQHLUrgS41sopCq3gLwGbCHosLlAMOL4MqciGyexrgUQ4+ZpUBfw+BBb1RFgmeCsds07DQLr59VBgOvOSxabrePrda4I4t90NOzM4u2WmSCr79eXneH+gSk47qVASrxIiesYma8fsf/hj7h4dM32+hFuc4H0W6gD+UR0bpZz5JRwIeBE710pME6Jw2lkdJ6829LvNjx7/31+/6c/5R/8yT/gYrPl7sVLfv7f/U/8+pe/4u3NG+girgvc35zIsw7v22y2+C5SNgPv/e7v8PSHH/LTf/QfM1xfMez3lHlkPhyZ71/z8//+n/Pyo0/51Z/9a+Q8Q0qUOelzCZ6ZQtz2XD5/Qvjf/iM++NGP+Ft/+2/x7Hvf59XtLWWzJcTI2RTtFMgrBH+BDxb+iRGxrVhVE89SE43K3yk1aKy32xIU67qVlfy1NzuicYjBeKjDHpX36axz7mPUZMc7YreMFtAE2bMZhhbULhLby94oIkyG6JiLEIuY7D3M08zxeLLic6HrerpB4Vc3b97YdXh2uy1SCvM4cToeSfOsUt22h04p6/1ZBdUeuNxfstvuePL0CZdXF+y2W4ZBpWdD8A2h6qDNQGpzkORhsO5NHlDEEVxUiLuPbe+XLDYseeZ4PDKdR+7ubjmfj8zTyPF4UFqAzcqq+25KSXlbDiVlB89or4tAmjMBx7ZXxAgG0XQmfd9qBdjmEvfgvJEqv22FDFGFRaSs7pSsvurlF2qptXXNKnyuri2R9vkO1woBggokSUuSDSlUuSKW7LZirSUb38Y1fetEQ9KsuLsacFHIJCIb3WbOoaPnEt6wSmrMbTifKAzEoUazSMXHTrpQDCMLWk1O4shASQVnwU/XDWr8kw4aqQvM1coMCkdxAZxJ7YrT0KNgsry1QiRALg07r/98yEOpldtagVy6GlnnGmBxfp6WqoTUypdKyZ4pzPnMfQqWPF3jcsKfZ67vhZ0XHkVhvynE4HAy0HcKobnynpQm5mmE08kkcSOBhLbLosrjOnDFmBcODmVizjBOHU+vd7z34w/54//4P+cvfvUr/uIXv+D/+f/6bzkcTqQ8ERT/odSJnHBSuAwD41R4k+4JvlDmiVQS0Tti33HxZAclmbGMRuZXhzwdj9yfJ168uaHrB/r9Y/phTwg959Md83hkPt5zvrsjzwk/JSbJjHPi/uNfcHc8UoKQQ8dZPLdncKJtXi9C9pUUn5hFSCKWXOizKVka78UFdeybvqMrmZAS0UdwqhiVJ+UVHUvBG8TGOc1rQ4RgSlGlKN5WKyKB4Hq865C+14C2SliWwpR1PoNIwvlJ12supHnGOcF7wUcVEphmOJczzoYUxT4Te01kchJKcvTiNVi9O5Gns1Y5j2eTUbU1K9rZE++RTiD6hq/dbTZ0m4F+MzB0O/quY7fZcHnV0/eRIaqsXwhRYV5WnZFJ0G64Y8oazOMjOStkSUqxGS+BKApiC7FTHGzKnM73jNOkX/NMTok0axs9p6T7XUZVAsurIC7oPc91z5lBLCJ0MfJ3//bfowhMU+IXP/9L5tOJMiWdUAyIr/0N8K3QsVSM18GVd4GZpDMuytycv6oTayI9dFEnk5tRdgQVkDA3EaN+XirK3ajFRskWKJg8IkVwZEQyKc2EuFUyf9E5KHi1M0t1WfkfxWWTLP62lvo/vEMhD/VZS6vKVn175+rcJsvOV/XB5U2WNdKSUbNp85xsboHG6dkcti+ZWCJBFOutSYaKFugUboORsCSKa537dSW2+kVc5U7Uopx15taFw8b7EVwjf9rvm/9p3Y/V0Ujilvg8+K+s70etkNa/G1qh84y5gCt8MY88i4H0+DFPfvq7XFxd47qOQgQXVEURLfgMG03Gcy5ILniB4ALdsGF7ccn1s+fsHj/mhw6+9/77PL664vmjx3z1+Rf88uVrfvm//BkvPvqYw80NHYUxJ8Y8cz7r7IsOT9ztIQTOpfDJ/S1fffQr4mbg3R//mOc/+iGn8cjNp5/w8b/4H/j1P/8zDi9eUl7f0osjiiMdT2rDveOQzpToePvFhpu7G67ffZc/+Nt/l0fvvMvFk6ds9zt812nwWbRYIVltWkqFl69eqTLk3a3Cc1meiT6p2hHlwdDPUAc8Ok+2+UjrNROiFkRC1KRCf0+oA/BCHDTRMCWpWlwtTtfyZHbY5UyZUxM0mKe5rqDWkS+iioN4nXo/ZKHvoQtRB+MVNNFJGclncpp1b6Sl8DKeziBaKHUiRsa2GU8hMPQ9w9Cz3Q50nSo/1QGuQz8wbIbGDdF8fCUxXXRA3myysMWgiVpE9o0b59A5Ol3XW+JWuDvc6Swvk5xNs/JIxnHUZzhPpDyRy8w8Ta2670M0hEwtGGiSGGOk32z4wz/4fUQc85z41c9/znQ6IfOEcwEfGtvjQbGgdVzqBm+FY0ERJnVApwX7TovpIaiUcGc8k7aIqF0r187bidkLVwvjxlU1e+ZEVORGlALhgxb1mtQxGpO3BK+ZnBoT/82ZxrdXnZIqA6mpZEEovlFwW7WonYS0zgtL7rRkcYs2fVmpTtVcLSwZk6vKUKtqZJFWaTYz3BJDPIbXr9mbyePaE/XtLKSdZyV+55ZZV7UBy4bXkxGpWetyc6tyjD7J9gNWCVIYkk2MVziN1r44z7D1wiHALgtdEHrvuMKxdY7Be+W7FBTnV4oG+8Hw52JtUOeQMlslGHOmSlL2kglk+iB0LhMlMXQwhVpZXUiqiiZwFOdJRYfGdZ3Bh5xY1cQz9BHJmoG7MBCKwxetpKWUGeeZOR9xp5Fwyux2Z7pu4Hi6I48n0vmAjBMlq6NUovfM4f6WuaCRvnekIhxzYR+9dkNKbqt8vbR1idUgQglRwdqkit2sFT/ryJlBDz5ocirKFdINDD46fITOhlRmUWNSK0VeAo6I9L0FAVUNq6AcO52PMKe8JBpJ8ffeS1OeSsk1Pf+mRFMKEhNlzgqDytkUswolOU00bGK08woLwDlccAwhIE4IQ6Sz17b9QDf0dJuBTU00tlv2e5X6a21k58wp2t4uWFXNlnM1KCJGqJdqDdTZoLC0NC+a4edp5DyOhlNOpMkMt8FQxCeEbIGMxUgm7VaV5JpRNtuw2+0Q5+mmTIiR2ftWca27c7UzVzZnCaKcM1tm6lg4mu0RtAq4aKSrLdGrdSb1t9rn9dOc1pKwoNCoi+26HLRK1QKf0MSDB+doAbM5BWeVBHHrFf/dsT7KunO+coIPvzy4r80e4OHfnVUW2wvV51hFr3prMYeuENlivazaKVsROK26KBikcLWuFocF627/0leXJcngYVL0ddtX184DFIP5sjU5/Zt+n7bu6z9l9UM1wbH38qoSNAP3aeYghbN3hMtLuqsr8IGULVbC2VR0sSTMUBA2HTs4R9cPbPcXPH72HIIj9B0//OADdv3ALkZ+9Ytf8/KTT/j0V79ivrmhjCOd95AmZJ7oXdEudIEwqYGPRTi9yUxp4u6LL3j89AlhnpFp5nw48OaLL7l98YLz67dszjNGtMLPMzF4oo/MJTPNhel+5sXnn3F3OjFs9/xW17G5vmbrvXJnjCPmdaFQSmbOidvbW+4PB07n86pa7x7c77rWGi/UfFNNNMRiHxHl/jnnCF1ofISuD4vpcSoM4mOnPECvw3LBYEmVo+S98lWLqJS6qaepZGotzuh7FlE5WY0P1PZLEUrIWjSaJoqpOZZiY2Rr0dMI4V3Qu9MFzxAjDiGGoEW1GOljx7B5mGhsdzv2+70W9ixZ0CVYlj8NilvqorXgf+0v6jBVHfaqclxzmklz4nBQmf7ZEoy5DnKdtTDopJDKTClJh1U6s8OIxn2rrL8WEDyOy/0F4hzzlOi6jjSOpLLyY994rF9Z2bD1NNh1x8epHal+yZnKZ00yqksSHnZsqx+qdmK9332LrQ154UuzfTVBqQyi5vXb2vtfOdGYI1TpTx8C4jziasBZCLkayWjYaFU/KMWgLEEXg2JCNZDvvCe5xMTMnM4q1+UUC1qMaJJdR+8CkUDKrnUxijxsZYFKpoUYCV3U1iHaWuuMnJvHuQ0Gyq5WqBxTmm0jLnjVoD1QfY8HaRxQBC8Ri8aWTYAj+kGDCSMBCxHnOqqeepoEcQEhkCRzR+GVL3A/4shsXObZLnO9CTzeBNx4gtM923KmD459P+A3jjk45rMjuJ7gOyanXIkkMOZC8h6i4/bFV6Rp4tNff8yvPvuUz158xcVFhJ0wpZmCYmWFotUQAuesg+7wnn4IuKgqO8EJMQqDQ1U1Ys/m6iklbMl+4DyOHA4HXr58oRWBlDgcXnLz5oU6zWLhl2S6oveB0BOKxxU4Hc/Q7/BxAAdjGsnjkevLAeeEeTrRO51tEGsbGKG42RyqxhPee0IfcJ0qT4i1sPFakUniSVmIfiB6oQ9CiFrVj70ndJ7Ye7p+AOdIpU5wdtD1Os8lC+KyyvMtpAvwHbgZoejgLUs0avUol4IfNfgpBSQCTsjniRICxQVOeW5TrHU+nMnweSWKd/tB52kMG4a+p+8CmyEy9Cr3t7+4oveR6IPK/aIBUJrPOOeJYSD4HiemgGUSvc4nsoO5VLUcQMB3AYVAzRaQaXlDJ5gmzndHVZJLmbvzkdM0cjceqcPLNl2vQVjKxEpma8ZxbbRNsKGtFVoA5xyUlHjz6hVh6CEEUp5VFloyxWWcK0Ta6PD6rvo+sko0RTRICBNBAGcdJJfJneg+cJ7iAiWqzG0wGNhaTULQWQn66B1JlD9Gsaq0c9YKAmdpiEJiPFImioxU+J8TT52h4oIzCW8HcbNIin93fOOxKvO0JA0sOXbrVxTeVDtl3gIpBxbUrApQgCYVMLuZCi2oJciWY6r+pwZkjlYAq/A3Dbyc+qYQCF1QKGODcNWzr4MkKw678poqBlvXg3O0AAzWq1ya+kwTRpGHiYasuilL0LFcbyujyZLY1L0CWk0twTE7eDWe+Op04PPjgVOM7Lcb+n5DOuo8pVIAu86ejc4WSZlxUkEQ5z27q2uGzZY/RFUWffA8vr5sU7t/8Yuf8eXPf8mXn3zEo65jEwKSRnzJ9B7e/d47SJo5396TjgcAdpsNL093jGnk8NknyAffYyuFY0owzaTzZJ0mCF1EZq2I7/qe66tLnjx5xJvjDffziRenW27PR25fzvyrfzHS7/dcPn3CxTvPsNYv0WvSFJ0WWY6nI5988glfffWVQlxzbnmGs3hDLMlYahW2PisXwilyxIngAqrqFwI+BgsuHd1usODXWWJHU/YSp9/LUlSyvHLRQlB/ZQT1Wl0staMs4JKCUkvRQilebVg6j2rTSkFSJqdZeQjOzs8JAU/oe7q+t7lKG/quYzP0DJ0WtjbDwKYftHC3gudg67LCEYUq8KEr09leKS0xqlyTjhCqclWm2DpTlExmPJ3UN82Zo6kYHg6HFo+F0CZxtO3c2dDBCkGqRT29XcWGPtsOsaLb5EYOt7f4EBRSlZLep3kGdLaXr1E7DykIdRNrEqE/EqJrqlTFSlbeY2vAP+j0LHt42bsVLizQivhSfVLLRpY9LlJJ4GaTrDCgc0WsYG9FF8yHUfnT/2smGrG2ob2HYNWcotVZD/g+mGa/UwiB2V/vDHbglom8OdcqQLbvazu24WiLM4KpKiKE4O0GC2RwQafsCs68jNMqpOG4tQpdtELddRTr+ZSVY6lVSfs4ClR0ty671QLQh1Mx9vpASw1oviaXWnKLQtoDKK5iNUFC0da3c6g8riZtOunTMSHcjdp29y4QS6SLWwbvEQ+lDwTRJM6LM9WqGZf0fFzxRAHVCJq4f/k59zevodtxvLvBHe8IcsHORdx+x+2pMGVhYlXVNYdXxNMVbyTkzpxtYEyBbtiyvXzE3/vT/4zMwDl53t685u7uhqvHX/H29jWHw4Hjy69IaSSVxDTNDWMaDJuacSQHKTi6XY+QcJLZekcfM71zbDaqhDW7gTmrrjZepfgEIfgesRaqnqNXAnlPIxBn0eGOM1Hld4ui6sEZhyFCiCSnCUIeM/st1kaMlKJGnKTwrKpp3SQQDMLkcqHk2aBBdQ1Ja+dqEgpIIbpCNO2sGL11FiDEyGbbE8OlGeue3X5P7KNVt2pVqLNBffWq1YG7vqPzCtXzNWBBCE4rV+IL2atrymVaKqJFeSspz7h5IbXPKZFF5YrTnMhzYhptsKEU5sOo91+wAZq5cVI8KLdI7O/FgmnnTFBhZShb8FWTC6uWGMdqSomPfvlz5Wt4T7o/QlKMtZfaX6nzCFZh48NiYuvSKP7dU6KQo4AlvsWSimgFiiIFnQZuhrhVqVRIQNDp5LUzGH2kpcEN/lUxst4CjhoIYglMUDyxw/he+v65TFTM9HfHNx8h1EFajipJXeWTNYDTnS7W2WikWuqSW2BLUpb77F3AeZ3BorC4Gn4v9t5VcQSvyaJW8T04DRIqBNfb9xe54/XzXO+DAl97ZUm2NYDwq8JWfZ82GLA6tdo5g7bwq9+rwdtvCg209EJ/v/5uVcohV9fP4XTgixdf8Zc//xl/9YufM+XMj3/4I7VxvobQJjAS6sBMxxwDJWWmOdGFgIsdl0+ekLPajcN5JI8jU0nIpqfses695+U8EmdhMwzsHz3i+uqKDz98h/l05PXnX/D2i6/IaSYGiKkwS2Y8HjgdDpwOR0Qg9AP94ydwfaWdh8OZDkcfA9dXj7h68pinz55y+iJzOiTyuRBK0a7yPEFO1OGsoRNi8EwUchbGc0bSxN39PV+9eMHt3R3TPNcwY3WH6zNYJXj1kSkuFedWhR6T8iVEjVGKBntlygoRr92PxYpbAqP8tiJi5P7K+dDCVzaoaS2cKxS3dqr1e50lPX1LkhQqGrqO4HdsNwN937O/2Fsy5CnOKWej7+micvaCU5EO5xSO2nWdBtrNjqq6n3bQ54ezIuwoRXkSadYhvKDIhZR03aQ5Kdk8JeZxMtlyJevXou9kw/KK2FBmg9YvjYOsPizZ4GjnmvgJuPZMLOY2E+CgFObzyC/+/M9xQbmJx9s7ctKZaeRlCLTY/m6qYva/2gWvGakPns5FfDQuhsXzYkI0lbdFsxurNWZJAvYsa8Ki16Txw6JSVWsnaks0+SvqJHNuPJ8K6lHuqjYLyjqB+RuOb51oeFPX0G5GjZ+8Kqw4be/pzALXAib9qllP/Xu9sIy3h1yJlXWGQetMOdNyNvhLVW3xgabMofCCxZivgxWc4hezqMSk1JsIKlFagwUMx0irMeBWhjZWYk1tJaHVbOrMhprsoJVY29fUBVIDPd2ter/EuAYVcpFNnC5J4WRtzX4SBu8YXGQXCjGARE+IGU9WfG7Jios3+VUnOgzGQC2c7m9J4ihhYJ7PhDwT3EDYRDa7DdN8olCYTfMc0aAuiwZEU1YMa2w8nMCUobgO3+959/s/QvyGKQXCsKXb7Cl4iAHfD7w9HZHJkaeR82lULL8FwIpa9/hOE8QOp5jGNLHzkU2ATRfYDr0qQLlMnkZt12oqrwGjpq0Ukx5txCpbW5p916pPIdsmyW3jWXZuqlZzKkzzpB2PzhEIpiyoq6V1KBANlkU3piuCpNJarhgsyjtnGuO6KcqsQUsIhY3viF7nWVR/EaIa481mw9Vuz2bYcHFxQehqsKKTV4MPhD5AURhcSYpDT8Hmujhn3ADlt0gICEVJ7s4SjSo5K0b8Tok0n/HJSGzOMVqiOM6JaZyYx4nz+dQgJXJODUqFk6bM5qoVK3XauQXtoHvHBg3WdoNrQdDqsAquACVn3rx6uQw4FI8ry1AqNZWh7dWHQ+5Wht3WjdoLLXp4b1Aq70lmWzoCpTpAJ1YcqVVrsXup8IRctKWvHVtpMJklvIOGy/dGaHSFUsx24VuFyijuukYlN+7Id8c3H94vXbKaaEgxkrStK+cUWlGD4KYQVp+JPasWZpljUliKiSvIsoZc+1yDLrCG2tW9XlrCWSeWPyT1i1Uksfyg2L5wq5+oQf/DwLQ5GQsQkQrVdQ+C28YLaNVUefB91u9cfd4qLFqi4EoqBfHCnGZubm/47PPP+eiTT9jt9nz4gw+t41J9sN1Db/pwTnkzxRUdcmuiG8P+gjSPzPPE6TTp8FDv8PsN/nJH2W04HY+4XIjbDfHxIy6ePeXy6WPOd5H72xvoLEms+9ip/P48zUzjjBs6us2W3dNnbJ89I3tP7u8IqRAE+qtrNo+u2T26IrzpYAwNFuuLswq+cjJKTogUw91rJX3KmXkS7g93vHn7luPppNyzVVq54t+vHsXyeqlRrNdud7OJzusXy9A2SUrM9mHpTjmWx1VawqFiGm00gRXkqHxYZ+gNS8BrA8x5ne0UQqAPUde7oIPvQqDvOq4uL9lsBy6vroiddmMKCjmOXf+ga5fnucVG0QoD2v+1NZfrvAixvURLeAQhz7PJzCrnQe2wqDx5Nr80T6oKNY5Ld2OaEdFuQS4a41X0Qw3q24qvibfYqIUav647yi2wNrtuWyRL5uWXXzYIWyliMfqi/oRzy+fUvefqv2vRSd9Xof91KOLiS1taJO2Mlntmf6/8slYMq0mkYB0xsfdcQE8VAOXd0klxFovr4MYF9lkwVcekqnxlVZz5645vnWjoDTcWQK1wuLScQNFQOXrf2sY5CTBrSyzWnbW0f/EeXxzRRTYuIiS7AcGIVrponXeNIxBDh9t5YjGp1EkDAScOihl+PEHAF8GVCfGaTAQJYBPHJUoFcmllugZIog8g1IxbCmXOLRiL1mpLJreKdyRWhHSbJ7JWNREPTkw+NXRWJEqqPQ3gVeXHuUh2HdllzhSOd4lOZnom0l643gQ220i/SfgsiC/MY2Yec+MgOFeIplBQJqF3QnRCkZkYIilEUhC224Gr509w7g1vjifOb+/o46Byq0nhScHB/fkOJzOdZGTYkQiUw4T0M+XuwH//z/9n3vneD3n67g+4nWbupsRZ4J333ucd/x7v/fD73B1vuL274X/4H/8585wZS9ZpHb4j9j0/+K0f0g89n/3qI5gmQs785PIR29ixDZGr/QUEx0lmDndvGU9HTncjyZDwmRHnBB9ECXM4VM9WcOLZX11x0c0cuonjWSd6u1KU2IiuxWCGMhVNpnA9s+isBS8zOZWWvKY5acfJZzUAWi5V7GgRUp6AQucDXdDOQ7/ZMvQ922FD123oYmSzjWz6jt4GDznb0F0Xl6qFGUnvvJHOpXUJwWkSXKskou32rkAM2tJvhrVkZIZi8y/wKk14nM+N/+PmiXE+cx6PTGdtsc/jzDgeSSWRfWhJc+dDu94KS/MYRt0CKNsUzFltQ3Cexl01a+kEujq1WxwTNINWVesCTiUoa2fEPgs3aaIuQFHBh2an2gA05UI4I+w7Sw7NQqJ9Lbu/TshekOSR4shOf89jOFa0otxw+CmBN7tRarqrogoSIvhIiDY7owiUhKPQxQrfUQ35Lgb6vsc5dc7RBaaSmHPW7qZqM39bU/0f4LGO3uwoOrsA8TZB90Fs3uyzxgxrnPESVPgQUCmTjVZBW4DgrCBQ9fg12QjOMQyOrtOgabY1qxXQh6oytjWoMY92R/W9/Sq4WUuh1rCrmF3Qy5QWIDX50tV9eLDdaoq06mTUc3p4Hx+kHyuVH9cqpd557u/u+ejXH/Hf/bP/L6f7Ax9+8AMe7a/oY0fKWpnHkm4xzlfoe7IImYmp2BycOiwNz3bTq9DHdObpT3+Hcrnn4CEdTvhS+P4779LHQHTw6xcvON/dcHd/zwGhBM+YZ8YYkWFLf/UYGbaM4tntr3jn4oLr95/zw7/1e6TziUGEdHcg3d7z5b/9S3IpvJkn7ueJc5411BkniswkcdohOR44HA+4LrLd79EBtROHwz2vbm/48tVLPvnsc97e3ek062oVrIL89WciFjw6YREPMPSIAGLBu0N5rNkUkIL9nPcLsbdYt6MVJmyReG8FNlNAdIINY1Ui8eXFBX3X0fc9wzAQzR5t+k79VDc0cZG+65YY3ZLsEHzzM1WAAYPI6trV4NQ/SMYNbmiQYm/vVbtyORemcdRZbTkxT6N2L+aZcZrIqTCnxDiNNgi62kdZCsL1FoiQFdFq97TmeLYXYSlU4PAtiK+FAHsWRVoxqe6u6uaaGIo9N2/km9pBUk6gGSJv6dPKFrT3b0TwdpMf5Dk1k6z2QNrbWffCin+5xrkP9r9bvsT4O2BzWOo5aoIUvMNHXQtdjIoqMgjZOCfmlJnT+Ru6ot98fPvJ4MhKH961YmS13MUIlggPKnCVhN0mIKJdCLA2nejCjDE2bWAwAqZo9qv3xgIKpxlWcF6VpaJlVkUsiajVAc0EVanSMuQa2OMa1iyAVntFKyGtepNSe6h1oIq+7/LAa9BVpDTDXzdTe65YkmGJRht4yPIzi0JIJbljuLhgkJ/AXRZi8UxG3o1epxXHCBTlEejliilWgHcF8ap+tZaQ0zklmY2HJxtVZJI+sL26otvsif1ep1uOI6/vCimpNOFpThRf2A4DRXSA0/H+nvF4oEwntl1kDJ4yj7y+e0UpM5NL3N695e5wS2cbt4AOnMmJOM9088Qmep7udgybLfvg+aPf/QmDc4SUmU9n5jQT80jueq1uyLlyikml4EUVt4JoYhXbWipanQm6YUSUle+ib8IALtiAyTRb5SbrudokUSmCWLdARKeG1sBZ0Ipz7Hoa/yhoy3jT9fTdQB97Nns15kPf0cWtzrDoPbHKOHexraEQFhUJZ+u9tq5rkNSCDsPXSqmtXlUsrpX7XLJJx9aAxSYhF60E3Z/uKWnW65tHUlLFjekspqgmKuEqZQmOHFDywlere51qD0wa1jfA0GLwXL2WavAWg6tfRtBvTkqNda2suNaaEpsATQtS6ie1yrA9f6seUFVc6snW6fLY+zoyTgqheqmqaFf3c6tmaZfMhYCNA11m9pgXrkoxTU3Le+XYuEIM2TppDudim1Bbg7icE6kknVFTihXDHoaM3x3LUSuUS/Bs9lxAXFFoq1UqxVSnaldCfVYl27ul2mmkcOc9IQa8WEekPQf3oINeF7jOI1AJVxFHNgiLnhfWHdNueJ0pUfdyfY8qiOBqhG8f0JKjmvDUgEOq96hv5+zal2+2YKAlS8t7LnFCvQhYvlmrvNC4HaJV8pIL0zjx+edf8Ozpc158+YLdB1XFzlu314qA1kF1Nlk69jrd2dk+8gAh4HtN5P124Ie/91Pe+f73+MGHP+T89oZ0POHHkdvXL7l5+ZLx1Rvm04FpmsnOU3ykhMDm4jHd9VPe+/BHXD9/l7jZmVKYp9tu2T95hOQLroaB8+s33MfIZy9fEM5ndjlzPh4pJk8aLTmYa3LotJCQ7MsZlOQ8nvniyy/55IvPubm95TyO6p9awWVJZl2tluMUGlUTuZXARluhRQuhJIUPlZIUIuwSzhdw2RIMe3RSw0+LB7zyY4VAcZ44aCe873t6I2BfXl4qGbvv6Lt+CS6dDvnrQmxxTawqenW1OCyhrza2brWyFFpX6xJbQ0UMxmW8i+WrdtVnjod7la/NqgRVoVNpTo3/l1NufKR1CrAs47L67LaiaRlCy5qgtcBbRaLCMI2A3tD0LZJdfme1f6nRnPnbRVr24b6rvpLWVV2fufuNLuT6wloihTMagbR/4zzBr2LVutZYBjbWCLQlfk5VDoNfOjExxibJLXa/JWuBvwrH6O/zNx7fPtEQaRjrqNE7wRaMIJR2/noy2Em0zLzpHNebqJmKWNbWoCWo0o33wW6MyeOi0qEVJ920zKMnieLhK5EUoARp2WUj66HcjhoIOXwzyh51Atj15GzdmrbxsaSDlmFWXXOx5ABkpY1eDzFoh5mQkjA0fYOEKJlc71muGuiCdnZKweXAXRL67JlQ7D3O0XnBRc2mp4Q9k0IoorwQv2C7U7NmICXjpTC4wtOhY1cyoQ88fnzF/tFT9s/e5+7+jpu7W+SrwvHUcTgJ0+FeMfbbC0D5KOfDgel4oIxHdl1kjB7SzOsvP+d0PuB6z83dG+6Pd3RSiJ6mUuFKwc+JeD7RR8ez/Z7HF5c8vbrmT/7eHxNzZr478MXHH3E4HPBnxzH2nMLETG0MQqrdNJxK4CLaLbON7Gx9dUGdqmpfh7b58EGDOikEJwS7V64kLHWDLDgz+jF0Jiun4gSpFHadBozOBfpNr6TsYcvQq+PdX10RQyTGQAyDVXUWyJViPaU5+Nr+XBuoBUCxGJ6UF9JnDd6rVJ2IavnXZKNCrKZ54jxOTPPI/f0b0qSyh/N0pIobpElAvPENKql1qb5g5PimC7KKwdSRlOZIv278qcG7wURyneAsptzUgnAz9LqUjdju2/UW+yxtVtSW3lLZaph3VyFytAqSKr4sQ6vau0umxn9FloRgeSbm0Lwj+KicLKmJB5VhTJ2vo1wxHWilvBnB+7lhf7tuaMZ+nid1vHNSPpFV4tSW8t3x1x5i/7c1Z/tXLOgSU7bTRGMRGfDOGUG6RYTtHauTrwTVajub8V+tiRY0OJ0hI76+n8I4neSmKvdgT0tVR1zjxOt/WAUry7ptRYaVnWjmYBXYrWOWdQK2/rPeO6nO7RvuKc37mX0RDbhi8JSiMxW+/OIrnj75nC+//JL33nmHi4sLxeC7VSJjeHEfA146uqHKkTrFgJu9DtuIOCFSePT0CZ1zbARuv/yK+1ev+PTP/5zjzWvu3rzi7uVrhdqWDC5ADEiIXD19xuV7H/D93/pt9u+8R9zumErWQKoL9Bd7goNHj664947xdOaTL79Abm7ZTBOPtx0imSiosqZlbJVfmC0YnlNSMrFznMaRz7/4go8+/pibuzvGSQVKFu2IZc1g+905hwsGyxVRJSh71qUWY1GbrZV/DbClFMQlKKoQWXmhwdWA0RHUjDZyc+0ybDZbuq5jt9vR98qxuLi8JMZI7DpVIjS1RkkJSnnYIavxnIgpotkATFehO8tATPfA9tfrMfhsps2b0QGbswkGJM7nM9M0cntzQ06zwaDq63Mj87tVhLskcTQbUItt9bxbLrFe6t9kWJuTk1bEqwRwfY5h2a8tNXy4h5ZZE8bPfJBk8OD8lqGD6/27wD5rslQ7/O7r591yFlmuPwSTvhZTMrP3l5oI6lt471Ru2OCGwZdWNOv7DoX1OsY8tgRjtj/rff02zunbczSoPlxAljZLqE45p/ZQg+nDZ6u26hpXmIveBq1aIr5l7xSstWRwJdP+nXNqxn2d7ddugrOAwQdP15mGvtPOgZJdM5FoSjIBAmY4PEVgqpYTIXioZeWqISzQCJ8WsyjUwoelXeiMKCyOec5fM+jaCdIgTRCXdd5B8PisQ8Z0BoAOrwnekY1YO4ZAkERH4Xia6MXxdhCwacR9su5OETZBGklJCUSKxSuxR3wg+MEQkUV1wUrifLxnyEJXEl4cz6TwfNvzX/xX/wW575iCZ/fuc7746gv+l3/5L/gf/uk/5fbFV/TnM7vOsQuFoczk4xtuX0WC37F3wo/feY7cf8FbDry9f0s3HbnMicuuo7iAuMiziydaKfGOKc+4w5GLZ+/xH/0n/yl/9Md/jw/ef5fjq9e8+ehjrq6vOZ8O3B7fcviz/4U39/dIdIxzYc7JuhOaDIskgsA4Ozado0enirq5kHKtmAhjUd6Cbu6OEB3BQ8pnJbAFzxAHQvAE37HpNnRdx353ifcd4MjlLSKK2+2HLdF3xLhBTNe8D1q1815xrsF7JfCXDGLT3+saqUtPHmJts3dkBy44pHho5+xtXxYLhjzjPDVlq3nWytd5VH3w83jmcHdrDjJTRjXgqcx4Z4ONJFGdmwt6EjoMr36W3TNZhR/mcOoelkqMRaekOyPDwZKwu7Y3gr6rSy0DkZIQ1IHqfnPEohYDhJmZhCOZnKFHoVelEtukCi+oYEOuCaQllk43t+5P6waSnf4eRYMjb/fUR6tCmxEUZ21mizlNXlBzVU/VOi9FmjHHD5r0RiV7OylIdkyiwyKP5zPVAUxZgxOfS5PHzU7lNr7raPy7jmqrXROy8G7l/iU3596C9VbZt6SglQhd614vVVqnQ6ygFW7qPlw6xfqeFQAF+pYxeBP70EnBiHUhreAjvspv15kfNRyjxS1LJ2712bKumtqVZJPKliXAe9AtbBtXlkzka3lKC5XaOlcmXQ2Q6uVXaFQpjuNx5PbuwIvXbxhTQio/qZa39cZBBt93xBpkrwIrheo6FWZAEQCbYUtE8KeR159+zuc/+xn/8z/5J7z+5FfcfPYpc8bmMXRcXF6yvbjg2Qc/4Hs//Vs8+cGPePJ7v88Rz/008ebuDSIzwSfmPBKjJ0iijKOeRS7kcWI6HPF+j5QEpzM5RkqMDNsNm82GzaZnnM74c0c8Dzy5vGaaAqfziU8+/YRf/upXHE5nplwozjV5GYA6jd5DmxlGKWgNSJjnuXXpa7HFuwBWfPTWbfUx0G86naMQO+VExI7ddmc+1TNPIyVrN2AzdNo19Qrj9SEQYoePHSFGhr5vVe0K15WUm61bElNV1gOasIKGPUv0rterkNC2B60oVGdzZIO9j+OZyfzT/eFOURSTdi5U0XBsSkzOCmcl58b9sKDROsm+JWlr9AambqjKVtZhtxpX87t1Ja62V+XYSTb5dePgLd2Hem1LsiEs3M82Vs87M+9inSjdesWKgZo4fr0lUONd+3vbeAa/Wu3d9mf7GdfeQregDR82v60FPYsTTbSizpxzKNckJb3e4+lkRRGna9PI33VNSzUaD0qJ33x8+4F9FQeOsv2XJ1Kvd/VwoVUk2/1oFVeW30VqorsYdsCEkvW9TYFAV0dpiUCFadWgweHa4qntuRqQ5SI4ipLKm3krLehxy7NZqjvNEUH1PIIFs/bwa5OmBYZlbdhLey9n71c1+wVLOCrkSgqQDFLiLR3AAhuFwoxZOMzCm+PEdtfRB5jniYiSv4NzFK+GP/gFFqTFEqe42mCVFMuYSkrkKVPOMzIlNi6y8ZFXn33B4+9/n3efv8Oj977HbrMhTSP9nLl/8wZ3umdwjs47hrBhu9uy3fSMhzOMI2E+s/WeKQTu8kxXEgq+82x9x6YfeOfikt1uz/WjKw5pgr7jvZ/8lB//zu/yzg9+wPbq0qRphUAh3t+QQubi8orL23te396SXCa5QjZcUXHBJn/bpilq1LxfMKmDVSdTdkRnrcQ40MdICI4iPd6Uzvq+I/hI9J3J83VcXOw0URYdiFiKypJGH1Ue16uSisLbYqsOVBW1YIRfXe7V+UtrpzcjY1DBaqiUBGiV/1zXGUiZzZAqMU4xvLlVisZxVILcNHI8Hax7AGWcNcEOmPyhLOeFKu6AVi2Ls0qW7cEFH7pUt+pmqltV2VzSeAs1zQgWzSy6K0rELojpJKz2TVUIQtozZblFi2JKsytrJyONu+Wr0hNL5av9rDSTgnnNBw6n/tmGna0OMVvgWIK5qsJRn48rRr7PiYRxRSRTB8iJ1CqTIxm8LchyGnqXC9/GmP+HejyAxFZnW3k41D++6f7pjVYpUfu11WuLK1g5U5H1b1NhTDUZaLAMW4b1ox+sXYM6VJKmLwpz1a7c+t3XEcWyD9brsK53aQGP2vrme00Nb9mntu7d+vdpCdbXrl7tllt8WJW5VNSB+tw5JbMxU4NULDhkK1R4s39xZetWtKNoicbIMk19vL3l/v6e1z//OZ/+q3/Ny49+zfmrzyl3d4SSEDpi6Og3O67ffY/LR494+sEPuHz2jOFizzSdtCAhAmmklJksMymdtfsxTpRpoqSZ/cWeNM8KEwk6EDalKvihz6z6kCTaGStJ5zoVEQ7nkcP5zGkc9fX6sNtyqNVot4qNnAW0ai976ezSlc+hcMtg+HgthFVRnq5XorbOn+jpYmS33at/Ac4UcnKU4Bi6Tt+nJRpe+R0WNDuxIbfNptb4RUNK3wodbrUSV6vUfFObZl4KddZZGwo4z6ocZZO8KwdjnmemeeJ0OraOhsKB1XeruuSi4lYQJa9TQ8S6N92D87IlvSBp2h6UNrukdhLb18qn1L3bZi5RVecqCsXXDbSkyy0WtVjPfEPbf6U5oaY6tY6Jm2964GbkN/8qNDtXk56Htq5eq2s/+5v+CUvctJhZIaWIDWIu1dboCadc7PdpyWX1T9/m+PeATk0WzLtGRnPtZOzifL2LeguC4fmq/rFmzfVm1pqdXmAR0QVV79aS+q2MYmGtLiWi4+NVUcTgGibHJdYtcQQmUwAaEKK+TJKkaYi1MYGGwW8tbjtXZ6cpohK4qq4FVd2oTvitvyOUB+SkVklCje56E+ujXNpjXmJ7dL5oiDHjKdkzj4k5zzy6vGKzCXC+ZSOm6BM6qvZx33XaVi3FmkiCyIyLkdgp0VRQ9Yzz7ZF0mjndnXWgGwP/5P/x3/IP//E/5v3v/Yg+B969esb137rgP/37/zHeCWk6cL6/Y7y/56uPPyafT6TziV++/jnp9pbx9g2XgO86bvIMMgMzU4bLYcP7+wueXz3i+Xvv83t/5w85eOguLvnDP/1HdFfXhP0eomO333Px7Bn4Ai8GTtPIO8/fJyd49dUrJCiFaWRCYiD0PdMxE3IhOM9cMi5PeAd9DOwGx9V2y5SEOcHQRZ27st+x7TTZ6Doz7DXbpyYMnug9241NJs/CfenIOZCz4EolFQudswni1bGIQ+aC83V41ULwzOZtQ8VO1k0sqmTk/TIPZp5HI8PpVNOUVWY2mdxsGjXRmKepBRCaeNlnudruDIjJG3ZdR04zOSshT6SQgYt+AIEpK+UeBxI65XJQLABxK2OunBXvBXGa/HpXCGKG3fZW9LFVlWtX0gdnxrjgbbOJFCUWCjqzRLzCHvG4IBaYqaCDR6wqaBDEuoFSlcb2TWXFWwCkkARzAktugXYP9GeyVYjXMK56iJgyh9n4LDVxEMBT5f88iiFOZWYsk7anA6i0tdMuqwWy2fC+VRIVp0n2Q9f+3fH1o+TUnlGp3AoLC5Z61gJFeHiIBQBLEFjhdw3uJApv+PqvVmUXoM3scCaNqL6pBhI1M9ZzaW7OnEpBCAXreNWCGcACPYY1Kfxr5y/Le4loIbDVSFfZ8jrYqOtpSTRWQc+DZMYg0zWRqvzLCltxjmmeGadRibmWQIdWNhZ8sM/xBuOQQshR1Y+Kvr92HD15PGs9MRXe/PpjvvrZX/HP/m//V06ffUK+fcsGYSuFuN0yS0fY7dg8ecoHf/CHXL/znKt33yNu96QArz79Nd12S9xt6cqEpJkxTaTzSTvVlyPz4UA5n3jv+++SrvbI4cj8+jXT/cyUC0kU6itTIRDYxJ6M067jpB2IMRVe391xOI+Ms85WWhcKq5BYHby3SB3Xjqh+bTZLRFAJ012M9F1HjDpJWzvk+pz0dZvP4j2bYbPMaxrPhOiREonG69SJ7FZ4AU1IyTAnHAqhwdZSyatEI/qm7IlosXXh3GrcNI0TKc2M51E5gClzOh3Nb01Mk31/nlf7I7c1uUrN2pqs8ytUMlnjv5QLQ+z0c2ftfi9lLTFoe91oC3S8FficBccth9e94NB7o8mGNEqAd8aDaV33Qh25WxOSB8IMtlcCLC+0BL+0BEYyVtCMLbFuh1tEHoBlXopbcYVrfOoqN3ARm3DtijA/V21H3dr6szknU7FV8ZpKvK5DadWKiOVQdsVW1NVkrSZRf7Nv+taJRmdTpCshTFgXJMQCbq+4Z1m9sqqi5KxTGp3zC1zDnL4rBbzJAdoHiNSHbtX/qKQkL2jWWzTAUFiSg6D4yTIX/Iq0ZKhYUlI5Tx2Eo8lKcZ5qxFPJUCEYq2tXh7LUFilCkkXeNucFy11K0hvvloeQJWNDPCzotzyLbA5SZ5CAKs5IllX2Wx++Z86qpf3rV/fcbzw/vdzj5xHSjBNv9xNtgTgIPpIc4FRGtaDE2owjCpAT4zTjnOfZ+9/j+ukzLp885Qkdl1eP6PsNr774ilQyKWfuh0GDtuDowwXD9SU/2T7m7vUrbl5+xYcfFqbjkXQ88NEv/go/Fp6yY8yQ5kjXbXl0+YSn777HT//gj3DDwM+/fMnv/f0/5p0ffMDl83c4zpnD7YHzPLIfBh7t9rz74W+x3V1wuDvw+MkNaZy42u6ZUuI4nlURKoP3iQ4lL0UXuH50yXa3RXJht9nxfLdj97wj4UkSwOB+xRsEDZXx1TzWaRKgu1rXCsJk8s2CcJ4Mv+s9MUbwnuIdM4prFe+p05SGbkC86n43uVaD9WQpnKZTq36M48yUZs7zyDSr9nfKiTSP1lbGCN51DK+ttTkvPI9VN7EUU2zqVMYQEVVMQ+WUHz1+wsV+z9AN3Nze8PLNK01wikCZIXjFAiclWTsXdB1ITQhM/hCnSaUrdIY79QjRCI+5OLwXHbgYo+4pKeQygugQxJx1eCZBBQjU/rWUzYx53Yka1MzZkieETFaxChT65HA6e6eGXrIUQrzo5wuCeOOViTmtVnRY8LE1QVS7Hoixsxa4dixkFVQq9EqzkBoqelNVmVPCO5N4LJW47h6Q5/EV89wYiN8df+2h91BY4mpYx8s1uDKOT435W+Bd2vpyqzeQ+j/RyPEBek2oRtzsvaPCXWrVsJTaiXr4i+7B86y+rtCqo3UdeLfs4/LQodeEKTdfuRS0jOlkgdCa/2FBXVWKs9dr2uFYltqDa23rUgwyY11OC5RzyRzPZ16+esXheGJOidht2pycysfyIppkiRYLpKiyoyuFPCXSmLi7u0VywufEy88+4auPf82LX/+C7fGeYZ7YR53VkL0j7q8J2z3ddsfLX/yaL375MXfzTPKR4gNz7Pn+j3/Eh7/92/j9lttXL/irf/Mvef35Z+Rp5Hq/JeSCywV3nrjeXvDsex9w2w3cbbbM00SZdJaA7zs22w273ZYxJVNm6kjzzO3NDT//+S94e3vLlDP9sFEIX10TXjsIofIfosqZhxDbnyFEGn4F15JcFW5xRs4NVn91Wsisj7BYbFIwG6odg1IrRE6l6ZNtkFr8qQvD2fMO1qGSokOKq/0bD2MrpI6zFrnGaWKaZ0sqFrJ2JWcr2Tu3/dN4g6XGf1assXMNMVA3pliyMAwbLi7Uh3cxcH+45+bmLT5osS6TbH0XnFeUQS1Qa9FALA6UJTB26pNqJ6k1qs0neueIK1i8FJhngxuVTJFlfyOoMIxru8OSnaVr6Go2IuqHK+831AdgxaoHG25x3w/smbMYtCYNxXzLojxX964mZ3X9lJJX+3oFvVo9e2n2IWPkgOa3HiSCzjX5akQevNe/6/j34mjUN64VlFp5Xd0fOyGDBC1PkUbMXGVa7WEiVhX1FlRXJ2GlgfpU688KrbWz3AR975a6fC3YEjBCrCnL+LhSw9DFk8tSwYTlHlbcpCxJJrks5+accUD9KnD5pmcgtAemQ7k8a0dUMX7a7HEtN9E31404F+H2NNOJp1wNSFAuSuXAVkUwvV2uBaLe2ybHilEpM5/PTPNEHwYuLi8pCCkn3nnvPa6urwkhcHx70ATMwkafA25QiBChY3expcyFeZyRKTNvj4zdDd51OCLXV09gd4UrwnbY0+12DNsLdpdXSD/QzSNXz9/h+p13iNsd83TH/fHM/eEed+m42l/T7S7ZXs5cPnnOzcuXbHYXPHn8hGOauR1PLOOgtEJQ1Ym6fqDbbJm8J3Q9m36LG7ZkArN4rUiVbEmj4ESVvdaKQTVYqY+irJ6qtnI1Ga5Wyzm/qFNRpQYhlEKZZ2ZmTVpKIU1TI2qP53PjaJzHkTnNnOeZ83gmGVk658kS7EW2tjb+vANs2quvFq4VBlSx3BPqImxGtxQ1uiEGYlSuUzM+blFa8a4SFM0euCWw0xk4NEiEq1UPFgeGKA5U56iYDLatecEv5HiRBlUoFbdFMY6GBmRFVDIQb4mVVYNxUMjWGXWtCkuBtSFvJutrAZ9CItcvLBj8r3cznFsshNS9tnxL/2rdza8f1SG1wK46o/b+tSVeP+w33uK7Y3XovZIlcaPezdUzb3fceIJrv77SgS+rxG6BGqwD/GWJrLHg9b9LgMiD33t4sg/XUvVrDZUt6+5LXWPyDe9D+yyQ5b3qml2fb0to7LO+fmp1360/wD3s/yzvuHxu9avTNHN7e8c4nplTYru6WcsarxXj+oL6Su3CzsznUe1gyfQIaRxJ1i33eaaTQldURdE5R4/yFvw0c3t7z3GaeHU4klxQKe7Nlqv9Bfn994l9JN/fc/PpJ7z86CPm05Fj39E5T+c9j7YXONcRdjoIV2efRJ0BEjyDDafruk45lRb8z9PE8Xjk9Zs3SgB3jth3hqUPJkGrylox6lC7EBXypH/2bRp2rVwjCvvVAXupPe7gl9ikBobLUnKrP5fqdvNhVsgoNY7STFjFOnJS6XPn7HNLk5Ut1iEvpjY0zfOSaEyzFsDSbJCo/GA9tjNz9Vz1c+vQt4rk0GJOeBBb1muoHaAQOy1oudWMtoc7aUmcnEGWUH/sKO136s/p6Cy3IGyK8mO9FYhqDKr8Kk8uHrFBflLhvVLhW6qapnzFOhuktIShJvxK4verBKTuj+V8653Ta3t4keoKVhtXqtdadTNa7LoCJzcfsuzm9npNMlh9hlvf1/ZRrSPUlpnUv36Dnfva8a0TDaqqi3hSnay4TgkFTTycA8ngFjiIICv9/KIyZbWatGKvN+EpJ7rRTX/eGdxiTEpWDYB4y+KddjdKwaS4VMmllBmxTogEM4hZSW0O8Dmrko1ohqapyoJTrVAvrWy7Jm9WW+yUoIRzKUSvw2dqhKYPvRjbX0nB9VyyKB414vHd0Az17GZVzkoZj24osR67lBrYCVlmDuOBriTuTwNu0xH6gEszLgs+C0y62VMR0jhr9VscM6KVii5wPp64O43ILPSXj3n32SM++fiXfPHyK/6P/6f/MxdPnxNj4O3NW5zzXF5esQlKOivBk5IO0NldXNNfP+PpxSMun7zD/atXfPXLX/LiMHGf4Pf/wZ/yvffe4/Hjx4S+5+NffczP/u3P+Or2nvd//Iz/6j/5r9m9/y5xv0f6DW+/fMXHL17x5uUbvv+e4/rJe3iJdFfP+cM/ec7bt3fcHM/8yZ/+KfFf/SuOf5lJ0y0uQNdHotN1M0+FudvQ9Rtks4d+h+s2BN9RiqPMAma0vOgAwOIcxfsF8pRtPQaWdrfBfApK8BfD8sagE76DD2asM3OaFfZThHOeSSUzpon784l5mphPZ/J5QlImzzoEiiI2rsaB96SixFGFEZXqnxWaFVT+WAMcHVwHRfeaddvAKmpdJDtNplwRZiNMkx2v377i9u4NHusU5pncOb3uXgg2DLIEh1SVJdFujUfMNDgjE1YOSjFpRU+ICkfyeP39Aq44xM0IRfXHCQgRnyquV/ejOCWedi4TXCGLVdFISwFQtMsJUJyqummaU7RD4TzBxQf2ph6tsCA02EEz1q3osDj4eqii1wJRU3ObWxZT29q1OFES+FCdnxYNClpxa/CaPCHijD+kJreSkL87/vojhHWX4mtBuVsHZxUS6xcohSyBrz7TpXO1fg9tLrgmu94CvXUyIzZgUZbzaFhqty5g0IIuaT9cOxqy/KyBycWCw3aR1ETEEiM7x5ZBt/NfpVvrEmkNSKwwUgORdUJQYT76K9a1K0tho1RIc3G4nDkcj3z62We8efuWw/HI5eUjC9RWd8jR7gGi83WmceTu7RvyaSaPqji06SPb7Yar7Ybjdsvj7YYrXximCX86Gf8MjueXFB8o3vP2cGTOhRA64maL63rmLOzHkYuc6UtmGM/w8iX9mzfE2tEQVbSbX9/y+sUbzpvPOZ7OnCflDcgQ6TY9z959zsXVJX3fI8eT3uNcuD/d8eb1a7788ktm62b0uwtVnwxB7bZXYYyu6yzRMGEQ7/ExNhJ2TWqratOip2pdJ3tAdd5DTRydyQQHH6ncAJypY+WEj0rA74dOUR05qUCHPd/jWYusKSfuD/eN05emiZwSaZqWdWRr8OHS17XmoIka2Cpd1u6q816yrp1ajFYOiu3PyusQ4TDpEMfb245hGJimkfPpxG63wTnooq+fqoU0q/iGandLbmuuohTU1BqMP9jMKov7alFQ8rL3fQgqlR8Dx1TV4xwVVVSSdsILjjkpmqUO8bV0qe1VKRY3YFBBZ/Ck5lvc8t+vFbvVdy38JmdytM03NSpK3bO1yGnwzlZUX9KY2gFt33dY4uUWU1MTPqnhbYWXfr0w8e8+/j0G9pmx9DqYqmLY6uV5G2SXS4actarqpW2gtQNf6yaLyBLQ24RfGgHH6YwMi5lKlbiiKLwI0EaYJSs+tgcUoip9pJyo2rs1KHHmcCy7oLbd22RV20lFWbCmQAWIEakt2ovBoWGpyeZSSbuC5ELsDBtpU7XFGem24sClZrdOq9+WoNSsGZdsGJTyAHQxBIrvyV444emB4GDXdeCTBm4bbaGWcVI4mhjO3dmGOI2UJLgc6L0G2q9efM6UhH63ZTN0OMmMpwOHmxuczaAY+h4XPJu4I9lGSibVK+Iow57uieNRCPztPHO4vSHmwkk6yn3i+tGeJz/4MX/3gx/x9Aff5/LpU7p3n5P7nlKENE/ErufR1SMeXzzi8vISFz0ikVSEqcD3fvI7DNsNv/iX/4LrJ0/5wYc/5OYv/422bV1m2PQmJ7vj+vFjhv2eadgxu57JdZySTghVw2gEL9dZBUKfTV0WZbXCa5fMm/Z3ypkxzcxJ51GklHUat4/MeWoqMyWpg57t/ZLo70kuypNINljQTCbWgahSy7pmhWxcE+cghA4Qg+ss1RrnVgFS2yrqsJZ2ra1dV7HgxWbJGOfBCXQekYQrYkontrfz3Ay79zZjRJZWeAgOF3o1gKKdM+edTa8VUtb7JkW5VUXU2W33Ow0unGecEvM0Mc4Tziu8quHDZTF0wabD6rXa/kfA5nCAq4g3nFeuytftWT3W2Pc1J6O+Bpporrk19bWHAhdqR5TzJTbcycyMM7ywg4g3h+yp0+S0wKhd3RCCBnfZhA5kWYffHd98VH5FnT3RQmwLnOt3VV7WurtVkcb2foV2VN8Eth68b5r0pSz1u7rVls96mFxWsQDQveC9zjAQyU3vZHH4y5c4U2mrrqZ9wsPrqd3KFpjY+1UJeGCR1ZTFhkmbcaPFuVrlrruoSvq2ZLk4PefVnXQrnmQRYZwmXr95w9u3N9zf31Pe+U3In3PLvnOrx1NkiSc2uw27vme73RC6Hh+CwlWKSkvEbmO2U0hocEjKbJ1j00XCMJBDIDm4m0by6cB0f8fl80dcbje88/gJvH3LjLATDYACKBE8a2HOC8RcGHCcgiduBt773vfZX1wAMI0j+ACl6GRqk7KNfY93ns1up/cvxKa8p1X52KRj67A77xeId9OyBpMHrjK49XtLh8l7i/5YCOJVdjelxDhPTAZvSkWFcMI5ME0qD1uhVwJk46XmUjiPZ4P0qv1pPsjiMUzkZhHAgCYrvUqC62+0jVI5qMt3bQPVmKrC/YoNd1YepHfqL9KsaJQQQPII5qkrP9c1lrLOoWpd42BdiuhbskHt1HsTgxFNcHRmh83msAW73W0ZhsDGe+7PM3mamWcdfdAibXmYhGmsvkxar5e6PD3XOiJ4Vh3VdWGg7pW1H6pv5lavL9dEjR8F2qw6LAZvK2sV05hfcTWTQCWcqxSyw69qF7UTqj5PbakWIL7N8e1Vp0SaoagZmsbj0r5XHXHJNpUVwFWSjjSCWvmaMa+Ou+GvlQbQXtPBN4Ko/qxl/tkCD1mKPfXmWzVIOw8Kv6idCg3coA7GczXZhqau4+r14lZtXmc3eSFxx0pur5lmy/z0dZXsM1ndpiuumbcLNdhYFqB3Hsqsk1NFcF7M2ICY5K1iZCPFCWeBrXgGy+SdU6yyx2tSM2UaNKxIm4yZxhmKw5fAbtfTec/tzWv87pKu18Qp54kpTRzv7wldx7Tfk3KyWRhG6HWO4oMuWOeg2xBi5GK35UdDz/H2jpe//pQ8nTmXwmW34+rZYy7ffcbj771H3Gxg02tSJMKcMjFE9rs9l9s93dCpk4+RkgszwuP3v0fXR379V3/B1eOnvCfCX/7sLzmnREk6s6Dvei4vL9ntL+n2e/ywh+zI2SFzbomjs83rXVCsMzV4UCOaVmRPJwWfHS7r3Iw5JyZTzJiSGh+HPu/JpAVdEb22XJiKdhrEKXFYN5/HtQCftkCzQfKWQFZUZq8G7o5W9WnGyRb2GketwJ3S1rG3GRS1oqlFjkIQCOKAYqRWj0pboYpm1ZIaflO8FhZEBMk6kd0760iu5uG41XnpxPTEVAf+pEzJGrDsfWQYtsSux795jUwzKWV8DA2nLrZn1fRaJdYKArViUAsPGgupca2K1etOxtpAr5OGr7++pAmrSs7KHopoclXv/wo2jUgNApcihrR7UqvbS8eyKrY4BBc1GVbI26ry/d3xjUe7NTXj5sGTsz/F7L60AKCCkxaoUYVKLdycGry0/L0+tyXGeNC5qGu1vqZQrCVgDMHroLKm5NROzbiJSwC4XNvawdV/1iBkBQVrN0KaX/GrtVykFmKliaAEH5Q7AVqQcA68J4SuSXyWXMmg9UaIYUZciwHmeeb27k6ndB+O1AGi9XA1YKj/rXGEwVVExxGrhOzQ028GVR10gYxnFkcsnk2oRNyC4KkY9M5r57aLkbnOb0gzeRqZzieid2w3G548fsz5xQVjyXRppjMb50qBrCgI56PO9HCOECPddsPz995ht9+D86Q5ETqFCaVZSdACdH2PhMhmu8VbklHnanlf5b7r5Hdbfw1Lb7EMLJVqalDslkdf1+fK2BRXO06q7jQbOX+aDd5UDOrlHdM46STtlJrqmWCxBWqjtUviTMrf1KhsXdVg88FakBpp10TEEAFm8xBZZMG/towbg1ZqYi8NIlbsdaRYJ12IXqgCQeshqbnBux3BfIFgMyxMrt63C5H6o624kFNmnrNKvs9Zaa4+sPOBrt/QDT3+9Q1CIuVs6l56jyohYOVBaLDZ+mxXr6ldEEtW+A3bLqxO0y3dLJHFn9YLqFagAnHX0LWKxNMHUW3Uw0SjPVOzGW2vthNenaMs61OoJPMlHv53Hd860UhJVXPIRTHtTlWlUtbArUneOhDvyCKklAjVQHpnMrMa1AQXkUiDhsw1wfCBzbCh63tiiMqKnxMpTdycDyDZWmOVAKWYdXBklwlBp17O80khJnQUyzKCMnp06JxlcDUYK+jMAG/EU0pp8JQQVy5L0VeIKwSidjTiUnV1pvDg/IK71PZoD3hKmkiSmElshh3RdLCdeFJKvHnzivN0ZE6jqi35mextEzlHtkQji/DicGY7bLjuenI+0HeBfreHc8b7wpAVsjOlxGkUkniyOFLSxRHI/M7v/B7eO372y1/xh7/3Uz748U/49Uc/Z7i8Jgw77u5v6DdbrvIjQhcIfSAzMWwviP2GzohZKWdtt86JeYzsr95luHjG5fd/ROg8oQtcP75ejGXXk52GYTmqkhOTDcZLAlnwxek97jXwTeeR4dEjut2Wv/+P/ks+//gXfP7RL/joo7/i1c0r3h5u2Gw6QvQcDke219dsY8fVk3d5fZg53030fsRJZioKayqlkL1WM3LJlCTNEB+nM6lk/XedCYNjnidSzpBtMomDMSsBvA/ReBSFUJNTgdhFTTLaHhacE30fKapUVQMfN+vj9h5XNEnoYq/rAaGkCQymFPoeKQrjiUbwViOphr6rmTSCl16dVl/xwMKcJzOYnhB6k3Uc6bteMaxWHnDOMdBZkOVJFqRL1KRWIVtCmY27YklWzoVCopRELomUlyCveNCBnBBjx7DZ4voBmSYmKbg0qoN0gcmSw1AseYAGiXTZt0AoeVQQACPnOZBgevQiBp9cjPtvJh1VXteSADPa9fnr90oz/KpMZQa7ValnrdHZrXdOuzo1sJx9wWfBSVoIw+KQEnTcQB6rb9D14WpI/N3xTcc810DK9OtF087yNQcOGBfQCg1lScgfHNbFaBUs8/Q+6MCzfhiIQdUBJ8Oqn8exBRRN2tzRCH5OPMGp6mFCF0btrliIQHXYDU5Fy5vsnF1LQmoV27XhYct/nTNoRlU1apelXQjvvc5bCJ4udi2QSaU0jbPY9y3JT/NJ5ZnTpLh9q3jXLKl2NN6+ecOrV6948/bNqkhSI8ulU1gDzb4fCEFlVkvWLm7YbIlexUrmYcup23ATttyOJ8Ip82jY4H1AOs8Rs8lRyPNMLpn57haGDXQ9837Lse+4AR45j3v0mO//7b9DCZHbr77kzUe/Yp4mQk5s9ltFSWRhnjNTKUwlc/n8Cc9+/EP+8O/+EbvHjwmbQQf1ZR1mdzwdOY9nnUdxdUXcbNjtLqgk8CoQUK+/PdQlc7Vnbv+0Z1BlYFU1sBZwa8di5nw6mV9KZptKk38VtFCZc2bOuSlEeVdl7xUyXgNTnFk7tyBTFGFSVgTVugaXwLINgXPOYKwrpoFbvd5+o4aCdh+U+GvJS7KtJg0d4p11YrzDscyd6ENsayhUSFTslnMxWfZcasdDIfjTnAyNkFoXrfIfk8Gi9ER1Vyo/v2fY7NnudsT4AuTMNM6aoDunUru1oGQJkDgN8ts2roVN55aES/T6fVjfn4WnVYu3C1+5/ozCbmuCBFVkhLaOtHNpctn2vlVO3bnlcZac23PytXZSNKaGKqNvRb5SoWBLslZ50CuNu7/2+NaJxlS0Yuu9PpyKEVxk0PQBWTGzLYpmaFpnwAyrpnVUnJhDDWB0nk2vmLwYO3IqTFqesMEjPOieeF9nRWiQoBlwxhUx/KWZcqeZmFZyglaHRZeUBOWWSG2t4bRN5xRjqdrf3irC9pARIzwHcGXRw7aWkxNri1qSVawN5Yh4F4iuIwxatfGdQmHwDjqHJB5gW53oAMOqtZOkMEnhbk7cjBObrtD1piqRCp2tmpxEv2zB6POpGtoQvSPlTOcjV9eXXF1fst9vOdzfMWUh9Gc8Qt93bHc7fFXG8J6C08QMe7RB8F0gOLVNUQRJcD6fKQZnEVGxzlIyaUyE6BhCgKDrKSB00VH6oAakOuRUDN/otFrVDVw8f8b+7jX7N5c8f/4+BRins05EVZCS8khMTq9WrKbTiXFOnKaZ+XxQQy2ilfaS8VkhSSUlxjQ32F+pFX4fbKJprvZDq9U1DlhXN73T5ch6naOAfXveik01CAI1UKiEN+0G6rqllRrcal970d+PPiySelLBQw5nXBKHwaOsCuTs/bzvlV/i1KCXEuiCzgxpw5tq27sGvK5qPlmilu1eFIVHWfGpqcLpznSkshQInO0jJ84Ik4EYohL7xTXlKE2CpNmUXJb7pLqZ9RyrUbfPk8XkrKu9y6RvMYPqVknGunuwGPwlPliChVIqbKz+rJjKjjoIdWRaaVOnWOfXqE3yuNZNXY4lmfA2mMmbUs3XOSLfHcuRLRnzpVbrxNaA7TtL0zS+K20tPbylDzy1Bf/6b0GV0kIIDMPAZqOd29olK0Vw07REi9D214Nhe1aNBhMQWZN7i9OhstR16loVmubcde9VuHHtSNQ1bD8B0Cq5y0W6phbjqPN8Fm6AzuzxZjEgdL1Bfhxigzx9UUVJJ0sw2O62QU/O5zPj+dwyHrfq8PzGrXa696NBZ0XA9Zr45Fxwux3x+jG79z/gRGS+u+foI/0w0A0DF1dbur5j0/dm9/Uz426PHwamzYbrd97h0ffeJzx6DDmx8553UuLi2VO2Fzs4n3DTRF+EPCfm84w/HIkl40vhyfff553vv8/l40e4vieVKmGhN3scR6Z5Vix/F4l912BPdT21jn+9/GpjbG3VQWjTVGdNZOaq6DTPq3kU+lrKCi9tMD9ZODm1m52KqjmlnI0HZlAYC6aXurateaeuo7T3ASvIPyhx1Pho3YF3qyW6NDekJRS67yrcz5bGOrGu693rem+VeFGlrWACJRX218fOutTZ3qsuc+uErOLPbJ3/YolXEVGomCXIWbRAlKWuU7ckTOKo0sPOJOu91/it3jalnlTHU59p3YnSfFK1K1Ltvr3B10UZljsiTRq5+jSx66rGqe0rWda+Ig2KQTwXn1bvgTcEUBU/AhC/PDelBetd1ZpcvcM1JlnkdL9uw/5dx7dONMacCKLBTMpJH4IsxLnKwVD8tCndVJa93YwG9XAOe7otePGiGPLoYdP3bDeaaExTQoe3OJtBoDj6LBMgOqvDFWvVWvgjSYMqUZUbnJnvmiEH10irAaeBfvAQbbc5zRY9NinTfj7YEDOcQwJQAiLa+qzD8DxYrqODbgRNDOaikxUlBFwlyHYKDSJ6istahesEmdAhzeg9dq2LokFWIjGVzM2c2Z1Gopu5HjZq7OeZLm7UWM9KblQOvG+OIzidyN0Fz2kcwTuePnvC9fUVu+2Ww90d/jzhu54ueHabgcuLS4JJuBICCeM6FEEnrQkhaoJTpJBmkFI43t7jgif2HRfbayQ6slejGjuPCwOx00Da4+k7j9tE1ZRXa0JJyVIHRxE1PLunT9m9fsTu6op33/uAXDL3d2+szaswozmpfrekDCnBPHG6u+M4zhzGxPn0hjTPpCRMJSt8qhSVvS25zbioia3Dsek6cpXvs6SqiDMD5FZWT6wtXgfdLJKTkpU0FqgzYbxWF2rNwlm1xHmV8ENUkckkOp1fJPYUEmUVzBpYudzaygW9t8E5XLaEwztVU/EOH7e6H7wzsrkHlDyIOMVDm9Fy8CCgkYINXlL5XEnCWDRxq4TnKv9b8CSpMyqcOb2MLzaR1rqHXswWVOUoM6Z1qnJeReauWPex7jnMWRY9OePCA6v2/yrRoGmj12DJjHCRFiDWBLGug+Vr6XDoT1lf1AlCrx1SrPtbwJXcyOtqd2wuiNQKokEBzIOHEHSCb9c1TPd3xzcfKeneyq6sAmtL+lY5f1V3qcRKYImOLPira9xXWJs599g5YghsNxuGzYYYI/OsmO4Us3J4mr2wt1YpwlUSq4INzry6wjnq54ip4HgLtvS1GBfeofPLOXnrusRQlXiWAEltj3v4PWfpVq2EmivWycQm22yFMe+cTo0OgRA9OY163t7jiqdJHLK+hRrInU8nzieddl/3Su0s4ljsiN0o5z2x69vsCTFIZhLwF5cMT5/x6Me/TfEDpzdvGXMh7PdsLi94/OH77C/3PL66ZLfROUj9MLC9uqLbbjmHiNtscJsNRyse7S4uGS4umO/vePTOM/LhHhlPhFGLUOf7I+7NW+ac2ErhvR99yDsf/oDLR9ec5sTpPLaLds5xOp8ZxxEfPaGL9rxowXxVMdO/68OrqnkimgzUSdnncSSnxJySQpxyYrKEQux36tDWZpRWCYMLWkgUp8l3KoVUMtu+1yAZb6IjC5yn2UIBQXkQRR6k58v6M9+zynmX9V7tqME/tYhl8HNnfkDW57v4EecwLp83CeD6cqGLUcUebOGLQB97KEJOSSXQ6761QnFNNHLOnCe9t6mUxjMQWGSadbdQhXfqua1FPiqnNvhI8IEYQuNVqC2xwkUN7DH/Z8lSm68B5qNdyxKck1Y4XIfrDxLB9q60gnEd+qmvWRKAs0SinonyKEvD7Ojdr8XTpbtPE2bUobkaZ2j9xjdb0yCAtcjRBUPt/K+YaHhxiA1icbZgqnIUIu1EAFKZrcoNvlOy2TzPOMvSYrEKbNS5G3rRCY/CoE6nE+ezEn5SEbyRdi/6DbgArgPDuRO9qU5loghdCHQxMPcBFwL9MLSbKTnTmW41XidMRq/Tn3UQoW8ZZJXcS/OMSpV6igWAOk8hN61sle/MSErMJZOmxHwaCcXZHJBZW5gCEiMubvD9gI+J2AU2Q4fkiTSdOZ/uSfOZkpMiZXzUyq1TjkfxE1NwSOzori94Od1xvD9zte/YBWHrhI1oa3sqQsoqS9pfDMxzYkqJwznx6PKC9955zjRO9F3gwx//kG4TOeeRM1hi1fHbv/2HbK+fsLt+ht9vKcFxmye6ciK6ic2204E85zO3L77k9uVLvvzlL3nz6g2H05mX04kuOza+57d/9/d493d/zHt/8Du8fvuS6XTg8/u37GKk73r6y8d0l5fE3ZbkdFhOlMym75gl82Y6Mh7PeBH6y0c8/eEP2V1f8vr+DWETQCZefP4R8zwSYiCfbziTmR+/w3h35PT2hi8++4TDOXFMkEsCCs7NLKZ7CTZrMuocdFE3d17BpcIQrZ2d+Z2f/Dbee+7e3nF7e8M8TkiZNcD3mlzgjRQaa2iaLSp2Cq2y6ovHprY6RxdCqxzoqMilk+ectl69c0QjtTmHkhBrAs/Qko4650HFFTQ5xFcFDE+aZjVSIsyzVdGSqqs4B5t+oO83xNgT8TqgazowjbOpmRQkBOvUeGpFswoHeDw5JVXuyKrQk4Ln7nAidAOxG6hE7+DDQkDDIEkC0XerAFI7Yb6qvhVBJLf2sO57oSShGPG3SDbjLmoDnFXLSlFn40KTGa6/rwZwwUQrmVjMTkyW3OncFeWFGK/MEqaa70g2yKIZaXX+Ee8j0UWIJi0sjq7vtBJpz/+hG/ruWB9iOvFLbOB+o1tRg+16VFJjfaal+jGn1f5gQXetBqovKhyOR46nU/u3Rlye7f5CHXFYRAOc9xYYahASq8SpJRI1mYSaaPjG5dC/B4OyWPJpswbSPJPaPIMZHQKpDr8W/apyTuVAaOCQmKeZ8XSyarWYgpPuslr4ciEw5Gzyq1GnOifjVlVYZCmWHNuNFYU4v33zltevXim52oRMlsn2bnkW9pxWT0Sv0XkNGEPk/R9+yOMnT3n//Q84vb1jOp2ROWmAEyMp6vt50cGgIXgtUBpSIBWBrsN1HWGcKOOJ4zjR7/b0fc/TTY+MJ5hGyvlImZXs+/R00rDMOzZPn7K/fsQ5JQ6nE/fHI/3QE2IkS+HVa4WKFRGOxyNumuljbwUog45a5yGbkEhOivMvWedTZRMTmaap3dsqFdu4ZXVxy/r+0QoTjetS6y4iBiMfeOeddwHH6XjmdDiS5qS2yC15Nm7h1PmaKdl71SKNs8+pP6cBtW2B6j3rLDQnViCpxRNduy2ZdquOtXUzHhR9jLBdJYHTnEyVszBb91BKaYNn+76njz2x6wkCTIlZRqbzkZR00J9+hm97rsIrKyk6m1BJ9SMpecbzyDhMqjZWYFFzpOZntpSX+VpqR5okIjWmqNBrLA6ucCSq0A9a4FoncF/vFlTO19rJNaim/ZJY/Fck1/SkNlRal1fQwkV9lvUNvAvN9gyDFRt81MTUaSIbTAY/dotgxN90fHvVKbFzqQba7mGrTLSqH+ZsXbv5wYHvLK4p0OHMyHoc0TZkwgcar6FSx101uM6mKOLBdyblCRLUgPqSCKXoe0bN3l0I0OkUSU2QA4Sgg9Q8FOfJzpvqgpFjTcUgC0w5M83aifDeE03mVLAKuE0hrtPGHVpxTTYILxabrehzC2RbIFKWCm1SQCG5Duoz2IiIFY+cLW6HwkxCwHeBOGzJ6cxpPvPmNFN6jx8io7U8i3P4EHVKK3p+XoQhBPbDwPXFBdN4pOt7thd7CJ5ZMiOZzkMcOvbX12wuLoixUx7DXMhpZBxHyjTx1f0Np9OR0/HIhsz9yxd88bO/4O71DVMpcLXn+PbAaSrcX1/y5N1rwjzCODK+ecurX/0VW6ALkXj9jEc/+ICLd97VZCMJU5k5HI6kkkjBBjeGQLi8hr5D9jseP33KeLzn/u0r7t58BSed+i5pJk0j59MByTNd9DjJlDKT5zqVu+DCMtBG26FNA8q+Vys8q0NM9MD2wzSPGqyX1CpC9ZeqwEAlXC21nOVTXK1CinEQnFY7DEHTsKhim8xbFai2MlX7e+V0/ALhW4h4YalomEFUg63dlHk27XZomOmSRImRXgmbvot0/YAvMJes3S2BuTpIq6zUspcgzEvdSI25vXcuGSnKTaoOuSZYzXA+uFu011RUoSqyuNWPrhD3q5a2qtQVTUS8aOXGq+H21M9rNZ/6RGjp58rRYzZgrZqOWxQ6sDkYHvCho5L9nRnMGIPytnwg+l6NuwsqG27lpZJLW3NfJ6J/dzw8rE+xVFpZO2j1sO7BErHgJvh2b2uFsiouhaaqZARypz4A71a+yeRLzWc5pxLY2QaV4ZwVwbRQpt10Teq9d/gYzdlr8ao5bYdBeZ1SAmswVHS9JxEmg89M06zwI5EWQGUrvFXbpDh33wZ/TgYnrXekSl7UVe1E9yYFXDbxFusCNRy7rFIHseCsFM7HI8fDgZIS9L0GvxUH7FbJ4BLH6veKGNzYYGVOdBL2Bfj33uV8dU2elHQdgscFz3kcdYbDOOFy0s5t10EIZKfsS7WCnt7mWkzUU1EkgyiRk1IMYtR10HcaxEdP2G3xXdQuQ5qVnxGCqjzlzOFw4HA8UnJmOo9ImCm98SWkPgvrXGQbZmfFqVpVLjZLaTaYlHaZlgBxiShX98xhHVFa0KnB5CqoteeUDepeskmor/xQDUR1z4jNQ1pvpIUTR41z1oEwS7KjvxKazwvGEfIrvlMdJuedX3WraW9aYXz1GoWCy8rDyqXYcN7Fd6lt1efrY0/sB1yBuTjEJXJR35SLSZ175X7UgLvYAqwdkCorrEG6t3kiC8+lxmUrj7S4n/oc7CYutqYs63xZ/nbt1uk0v9NMwBIoLHZr9byWZOdr3Rcni72o71u7iuLas9VCpRXB7LO8c3Rmk7zzdF31TZ40r6a4F6E4XdM1Bvmbjn+PRGNxu94yIS80ebZsmaUG3qFBjZxootBfDLiiDj7icFGhSg2/j0OckfpCpEIvvI+aiQanlX2Ntsmz4ecDlOSQ4nWBeE8Kiv0U59Sw1MwtBqYsFugABkSazqO1o7Ut5lA5zNpZKZYY9b1WMhxQJDGOOsgmOMd26Nn0XQtAU1KomSr0aHUS761rYlXfqJm8zkBQDgOut1aipyTbnEWVdDyBzg9ses0295tLzqczUx75+OWR09UW329hzvjkkC4yOE/MjtM54XMmIlztdrx7ecn7jx5xN3b0+w3DxSWpiyQKdyVxtYl0jy/YPrli6Ld45zi8fsk8jfhSePnlp7x88QX/4//nn/Lm7WvuD/f8Z3/6J5TDgU//1b+Fc2JzccGPf/wn/PqLL3jzxQvO7z2h3LxDf7xnOI28/OIr/vL//c8Yjnd4EdLlY37yD/6UH/zB3+Hxhz9gnBPj/YGP/+zPoCSevfeE/eNHDJeXbB6bgpGD9z/4gOAhT2fevvxcnfF8Yk6FuZy5ffOSsLng+tEl+92GOWdO09k2omFcbe2WbNKDjQxsUANfq3cesYBwPp3BWuaffPyRGZWANwK3F5V9rZAY5UoUou0jVRQLVI6AwvQCWFXeOZU99g5i1Qz33jqBVskXc5or0mcRj5JEPZK0NV9yoU4kT0XnUSyVEA0G5nnW2StCm5eBePqokLaLztHverb7HeN5UkGH0jM5mCzszqYr3jm/qMspOgzvnAYL5khLSXgfmiRjLgUX9EarTv9S8VoqHbRKXxcHNfyVMwbG27AfzbXiLCZvq10cb5dWycBUY4sgLi2etFRcu6OUJemIBIRClkQJ1uFCQLw6M6kJIAxdbIFT7LRT0/Wd4dM9u36vJPJceHu4Ic+JMuXW2vcxNN39745vPoJfCgM1qa8+SoO18rWf9zbfRQU7KjypCg94UzBqAQ9OleIcCmcL0XD4ts+WAVA688YCOnFK6nXWEQyW3CDG61o7aOdqlWMVONRAVQOlrlPelHYlzkzjiEixCdMdXdeB0wB4ntU3Oefou46+61Q0wqrowa4xxs7OQwtzNXatHUKS2o5igXKDfOiN0f8U/Q3JmfvbO27fvtXZC5uNwqhdVaxi+f0aNFvw4rJChKNxynAQnUD09JdbZOjIAsNuh+8CLjj6l3dMpxOn+3uYZ5xViOdJCdK56HuG4tn7QO8i4j3zlCjzBEkr+6XAJGZvYoConamu7yDo/TlPWlyb54mu67S4NE28efuWm5sbpmnikE9kYN7MD3gBUqQlGzUAXCDnlliBStbmBpKhdQzsPi+5YYXztCcBVN6YVayzmN0X3r56Azhy0W6yE5q0swZCZfE3KxhP5Z1Wu+dYkotaeXfOEa0Ti9fBr0uwbPvR+4WDg6JYnNPRBZhoSOU6ZIMwVw5BBSTNc2oiI5UEHYAYAl3nFIK92TNst8y5MIonnyamIkw2fRzjyJGcJnRfK06UlPS9syUaJahPzPr9KqYgNRlz3qzDklSowbAMzen9cxJMKasmCcs9ButAmrpWm1junRH26/139pZVPAS7n2swov5chew1vs1q67X43flGaK/d1RBUiKkqnQ3dYEigwn26b366PlxXJZvD3+ybvnWicXV52YxxVYpYy0PWBVXVbJRcag/C1QqrOYNcKEGMkK1qTIKnuNIMnS5GT0lF22ajYkTFVaKnVnzEqYpSToneO0rSNq8zInfsOgTFJeaULaUxg2K1sPF00goQok4HOJ9PTW2IDNl7yqhQLBccxQukucmdnvLMPCmHo+RispqCE20fKwTKW2tdeS7TOOu9Arxl0t5j0ocwbHqiSbPhtY3VdUObXHn/ZqTMEcKekcjryTO/KfzgcssmZrrOZi2Q2ZhE4FwE5zMuasdi47cMux3DcEmJHdkF8ijEmzPz+Sv+p5//3xmPZ+5v7pnPB5wTNpcbxpw5n0fmL14wZKEPF3zw7g+5f/OKX5S/4Hp3zbPn7/L3//6fIveFdBKS78ixRzYbpm7k0Xsf8J//l/87Pv4f/3/cvX5J3nVcD57LXsnklEyZZ776t/+G85vXvNl4TiEw9z3xnXf523/6D/ndv/OHPJ7eI+fC/fGe5198QIyR15990rCIaTwRhy1d5wiuqJqFsyQD0Y0lHvB4t2CeqRvZ1Y5dzfwtgShBF+OctJID4Ip2H4IjhtrJKPhBN6OvlUCnHAwfO01Ac27QiUWKVQe3OacdjTpVVP2O8SJMxnVNeiviKHlqbeCSRY26dQ9TKWAT5SXVwU3O9qEZpJZoFDKO5GCmZ5JALA7XD7iknaBsaijFFORwruGOlTSvRtNVSVz7Urtvil8IEmwAJ0KitIqLICscuVVnvEHAUPx38TTVpxrE6H0y8qpf45qh9Ryk1fM04LLuJvU+VCK8F5yLOGddVQmQI9GZZGWMxqeI9N3eOCdqAys01Hk1/KUUxknFCsZzNudrYhjDQLeJKu0bAmHTW/t6pbf/3fHguLi4bJ2JSnJuySlATfS9M9/idI9akl5/R4Mxaf23WGFN1J6J+bqgxa+SFRI8pzNtrkQNqh2IX9SDPFoJVH6E2AC3HrDKt815cY4VJh2mWWfylJwbuTbXxNxgiHVGQ+o6S5Kc8toMnlPmmWQFsmyVdOe8QkxglTgZMRxU8jPbPixZ5b29o3bbQ+hagCxFO8jBOe5vb3j96hU3d7cM2w2bzQZv/ENBkQsOhWs2RaOccdm6+klV+CRn8jSR5onxcOR4Oirc6PqazeUFw/6C3S4y9Hu2u8ECxEyZZubzmTTNTNOsYgpBDagrCiVK/kCWwjxPBEtsgvfqK7NBLyUz5ULcqppRE6kojhg7xpw5HG95c3vDm9sbbu5vSThFSwiKkECW4F9WfNZq/6B9TyiUZNLrZSmqrExWi2PrCy25fpC8qY3xrqYmGZnPtd5iUF7rNuhvaYHE1WKL+Tjv1QY1SG4FOkn79DpZW9fOEgdWeeg6rwonJtets5hqkFdsHkqVt6+dmCqq0gqA9X3tflSkkaBS8RnHVBwbAhI6cAXCbMWCTC7aMa8JhcaQ9gwqFAwacsE+EQG101kaTF4w+JJ5GB14uSAb6l2vJGn9eb2+1mtfXZ/eNu14UgVw0H0mpQb0C7HblI9sCbSn3WLs6tmQYjBElWgOxrkaNlvryNV1Ko1/KqjK4TxrF+fkJ4vzFfPdDwOb3ZbYaeG86wcdSvkt+IPfOtEYNpvFmFsFpyUagkKWvG+wAocSraXi0FxtsTjFj2EZl7H6hToobVVBxrgSs7YtffT1disEKjhwwSTcCgGvig3ThEPJOx5v2V0hTXML8nzpWkUlTZPJfxVymgEYx7Nh9QSSprCpmBpS9pQIKjBeTIdZqwPeByg0gmudBOqici18jORS8CWT0A0pJVNna3RxQ/Y67r7vNNGI3uOCBjExDto1KWoonYu4boNIYEa4n4VTWaTXxCecEx3Q5tWo7C62xCEypolu6Bk2W2LsyS6oJPA4MR3eMqZXvPnyS06HA4ebe5hHQvTsn18StnvEBcJ5Bt/hu4Gry8eUcdYqkE1off7e+1xcPSIOG60uFGEukHwg7i549oMPefWX/4bT4ZbiCp6MJyvvxQKG880Nx1cviaHwFjg6z+2XX/H9n/wYnGPY7tldXXP15BlPn78HKXN49QrmmYSonLGUBgHS/Vga8N811rBv1lxqxQ1W5hWrOtC6CFqpK1RxGNzyGbEZI0fpqu52xezbc42a2GTvm3HKedm4C3RVd1UzxuVhBasmGyIq01wnkmuhxAhrRbXTS1HSH06J9nbieINWCTQZZ8Qxa3RGxlMI+tyD14ALhYdo5S633noWmqNoNTpp5nLVGnbtvLEyQDsH+121rxXWUR+KlQzsIZX6OXbO+mtCVaKrylv1iVaIiLS7a7asVfAWJSrQawktyQyoqkokeAyv2tMNPaHriHHbJv+C4HK1gbbfqcmNN7UfDUo9gegCfex0pkgX8ZveIGIPoozvjtXRbzZa2DFuRav02i1z3mBSzTdpcUdSVa2pBbIqYiKGcXdtnbVZA1aZ1Pi4MM3a2XYW4GMJh6lbLAReUXlSDaSNU9H2s8JmQPdFZ4RiEWEezTdVxACQrcKqEtIF8V4rrkirTopJbFdlniQaTCNivsm3n42Vt+gURlW5UQrj0fKDw+GCJuIOIXqn33eCZG/Qp8LpeOLmzVs++/RT8jxzur7HB4sPgtMOD44+BAzgrBLeJhcuWQf+Sk6Us8Jz5XBHPtyTciJVJpR3hG6v8KZgPMxSyN2k997gU94HXAwqvx+8IhYsGUxZYZQBDawpKstfbUcRwQ/FfEGtImvnOafM8XTieDpyOp80IVRyCbPTpHGpJEtLMFj9KXbOVTVq4QussosHf18q3AIrWyityl7hmbVDaysGpCYFzm7PqlssiwqaUAvDBu1zWhxyGAeknrsIbS7FKgnQPVI7EgZvrwl8Uc4KlkcVdRIGo13Z72q5m4TygpwRMVojKsKid6SoapTTgq5zpSX+lfOSLcYSu42NEO+Wu1SvofolWHyqtG/VpAFqu0m+9tyqBLzUn188YHuOUm8CVXhk5Z9Wj1zPybLEtqDsFanxtA3Vdb4lG95rTKK+aaDrO0LsGDabBl2rAgPJUAj6XLPdY7d0pBymuOXpuo7OkD1dv6G1rv6G41snGtury7YQHN7aghPRRSN+qrZ+dkqQ1GxVJ2eCWBck4MRp69Kqyd2WRmTKs1Zhxmmij53iSlPiPE6cx8kyKYWqOG9cjugpRTWtUy6keWSeztpGdZE0z9quRhCDWwF0aWhBopxHIxRmRkuMYozmBDRrLjgkF06nZHyRxfkr2Valw7rO6ywO8cSg1chuq0FI7GxWQBBwpQVp03jGmaJB3w1KfhdZBa/Qh05JsiEyzYl5nrm/u0HKDJKafKtLM/fHCQmFzTDg44iXTLcNMHf0bPnjP/4Tbu7v+Itf/YI//vv/kEdPnxF8zzyPpGlifPmSj//i53z2s18y9B27/Y5Hjx8TTjOhi2yz471332N7ecn86R2n4kjdhovHz0nFcXH5nLd3b4njGbe/oPQDs/O8vL/n6s0tT17ecMqRGCL3PnK63nK663n94ise377i6u4N17/1u8Sug1LoLnZszxe8u9/wZNdzVzL/9M9/zleffc5Xn37J1fOnXD17l9hvuOwGXn72CZIcb96+5HQ6UkLApUw6nNkMPd3Y6TMtgSIeihHEnCNjLdqMDQ4CHyohVAPXIIHgPcPQW0VABw16B8ELLqozi9kRfFQ8sddqUucUeoVDDYxoF8x7aYbFudwqXalUdZJMqlrYopjykhUSVDlqeo41sNbESUTl+IKPpsqj1dRcZpXxrTMhCpSStAIkGZeiyftp966TjkflObHfst1dgcvEccaVoOTUaTS7WR2DBjFdiGpoTf6yao577yiu0wQmi02qF1N60yrJwoGpBs8UPHywLqEZwxgo82xJU8EXtTPeZfC1m7GcWzHVHVc83neA12QKNFGMuvF1RoY+yzxnQg/R5vwUKcyDzkZxwTNsNmx2O3zsuDvOyJyRMjGfz6rYU4sJ3hP6DfvtQNdFNpuNJa6F4+Gs1+cc3XarKnvet/b9d8c3H8Pl3v5WHT8PuoK+Euod1nlTB6vPxlTZgsFhkmLBCzSnjNPZObVzF83pllKYxolxnGw4m3bQqYpPURMXi75UJcd8XPAeUm7Fuppo4IC+axXWNI4tWWlhpgU63q2G5JbCLMpxyisBAQVQahmlj50mrRvXoBJ9r1XKvh/oh6EVBnLJLcHJ1lUBhQkrxVGoAwZLyaQ5cT4eeXNzw/yXf8n/5b/5b7i+2HO52/HO82c8fnTN86dPCQ6iU1nzR/sL9psNTx49xhfBZys3FkFyJowTzIl+PDHc3+PmiXx7T7q9I93cIY+f4foB32+I2y2u64jDBrfZ4lNGzuOqaZIQJ4RREx4czGnG2yC3GDuVOs1FURGi0qh+ninzpEqBRZO3LDpB+83bt7x5e8Pd/b2SuqVoMcF4nqwTjVYEWboZ2qldJRg1oF1X1r/WxWjfXFX7lx9zLZZqROwKc3HaxahIFB/iIuDjqpqQo86ZUS5ktC4viyyuWOQmNE5fNo7J0r1ZfFax6y+rLnEtODsxGI+NG6jruEqHZx3kYMnNvIKfWTCNVtv7AcTQAd2wwZdM7Eac94tUcMrt2p2vwii0jk2DSIsKEmjCpeiTYllGjfOXbKTCkqQ9yypFrvxj18QgSs5NgKIVMGuC4ZZ9XdfIWuFQVg/a+7J0XwrtPqoilmfYbBER+qxkcOcD/W6nhavgmXMhz0kLHoY6SPPcOiJd17PdDcQush02dm7C+XRCUOhoHDaEoKMKpmlaEpV/x/Ht5W3bZrB8TGwoDEUnizodwFVwJMtUnagSRSlCdkKwCcIlWZbnhZTmJYiYklV9EqkIxXvd+DbUrKQJSsCXolwH7yAaZt6qNyUlJE34YNi+PBGoCjhmRkXIxdpCQIwOiITQa+3Gabtp3Y5vKiE2CMkH32QnazWgKYW4QCASnKl4dIF+iIrR7qNWV51CwkrKzJ0NrMMpVMr3NEUUVxBXdAo5uuGCS4hLdMHa3Nn9Joncefo+0vktPgU4Qt9t6bodGc9mf82HP/4dnn3v++wvL3FDTxiVKOV8xvuM8xmJPY/ffZc/+pN/yMtffszxcM/N6cQpz3g0kMtpZjpnJBTC4Nldbri5mZnHE9N4ZH+x4enTR/z6q8958dlnPP71x2yffA8XA9l3XD19n3ye+OqXn5DuTuT7A5LOEAfC1Y6nP/kJb4eeTz7/mGePL9n2HY+fPOLtmxv+zb/6c/43/9k/pusj/SazvXjE9dOJH/7OTwmfDLx5/Yq3dzeWiCU6F4gExeebocJVWIolgL7g3SLNpxtc10AXNAEOTqfQ6l7w2p1Qc6SYxWbUNAkPVhHLUrGnJllouNmqh15KIZWErJ5l/apJgcOZaow222oKVNvTblXpKWWyNTo1A65VdWVVtMIKIEWVk7JkfJO5M4qoW4Kb4D3Z4BIu6CT2krJKJ3rfKkZtyE9LypfGuxr4snRozDGtMaPe+/ZavSJxpv5UrKvjaRLWVMUalNfkvD1PVx0ozaDqfTQYFB6d4pKBRT5y3dGo66BCqezjVJ0rFXIZmVLRjiUaKAYX2G0ucFJwkhTPGiNhszPuDlaW1PswVTWhrFNqfQjM9tybHOt3x28c05qDUfdLU4QSlUq2gGA26JCUwpTUb+hATbWZVQazoFwLZ9LOFQJVBzf6rAlCJfMWEbytG2q3LltAaGVYyQp3xPZpSalxSaL3rbLNCubRGbfPuc4gXtUnabfch8DSnfAtYPQGafB+qVwrt8Cw2fXnbI5FjFEnW9dOipFgc55Jc4/OEVoGDFITkZIhKfQ3RCVN393f87Of/YwhBLZ9xx/89HfJ53fZ+MD5/p48jeTTiX3fM3SR/bDBzxmXMr3XYYJD17Pt+6YKN00juWTiZqNY8SmRThN+s6XbXxAvLvB9Txg2ROcoXWDrBqrU6TRDkY603TBvN8g8cZsyU84UD9tOeaEhqPqf2teyXlbWqdIu5Hmaub2/5zyOTEnn8VRbVpPcymptNo4arC819NYhaFXvbz7c6i+1Or4ErBYkRuWY1nilBtb1Z0KTIXVNyhjnTCELG2BbURqZzNyS9pKLVfeXc2oJ0jpZonZSquwr7Rm0OlTt6haDG3nXAuyySlSWqdN6j0quiYZCusQgzE3lrQb4XkWFYljgq+Lq+IXq73SfOrCkY/m3CgKp/VgSHyzmU05XhUWpf7JnX9YJJOCWTpA6pkXZC6nPVBrsrPlHZz7eVUin3dfmKxclPDD4ohVSqp/FiQ0OzqTTiZizrm3zpM47um7Q9xwGYoyEGNlut219xhhaPD7aXJdShHgetdDvvMGjH3Lgvun49gP7JBthuTZ+xBaoym3pdGDFOyXL3nyBNBsR1QkStW0r2SFeF2jKy9AVxZUqVjF5G/jSyD/S1GrUNRdrTRk4WwwGUpQfEauiCNKIqMH0j2tXQznmCkvyztN3nZHPdXF627Q6CdakCU1xwlUFkZrB+rqIVZ4zep1PjPMUB90m2NwIRyUFj6ez8kC8PjAxZYOa0FTspriMNmXE2v0Z7zLRCckJ2TaiEyW6etHp650P1tVQ/ezd5pLd9hGpOIb9jkfvvMejZ+/Q7TZMkvGu4Mus90sFupDOsX/ymN/6gz8kH2fSV19yevmWMc30ptiRc2LOM+ILofds9hsohTyNTOcTm03P9aNL7v/qz3n74gWvvviS7188xfkthcDl42eU8xmZhHKcyPcn5Rj0PW674dEPPmRMiU8//YjrTtt/l/sdh9s7PvrlR/xH/6kj9h2x2zDsL7nIhfc//DGnaSSVwtv7WzVaNlU+WBWg1fqcB6qxKhacLiQvkSp5qcMkqyGPbkkurGlWyx84ByVUt+ygaIszUdVHrDqWs03QzsZryCRROJN3SwKqgXDNCFwbaJfNyBjFxwy2BjgUeWAEFiJiBmfSvgoMtWDcEo06v1wWZ7Y4N1WSK1glLHi6LpLniEuFYtyJGpBJKTozxrlmmLBqa6v6mbOqEp8L7Mgcd7ZfEazlu/xOO388jaBofLBFem+BvtWWsau/Y5oqztZAad7QznHVoVngD9g9wyp6Qi4zqRRcTHR9bAHgJvZ4KVCSDvPqOsLuEilaIS1p1GvPCp+ZpplpmpTI6gNzjZe/RXv6P9Sjyie3h9yCOWm+qQYF02xE7SIKuc3aPS5OFY8qnlqAVKEfxpFYSLxF17/Q1J0Q5SHkbBnCEm+pv8yl7SdvGHkP1iHQtZ5FicPBe0MguuZfYow6WNOKWTrILNJvhqZm1biT3pmMrn6/HsEv36uV1Vql9N4T+95OWZin0WRXIynGlmioHRVKnsnJ6ZymagtiJCdVtfriyy9xOdF7z/vPnnG93yuU6v6e8+HA8c0bbpwGIC5nOJ3hPNF5z6YfuNjteHz9iKHrGfqebB29brtBzmfK8Uza3BO3O7i+Js4TbrOhu7gkDD2EyOCrSXb0GVLwTEPHOPTMXWwTtQXYeBWBCT5QnEryU4Myu3/Oqu8FmNLM3eGgAVhRqfta6RdV6Gj2uhZoW6LRgmfsbq+rPfVpfUPSUZOG1esap2v80cXO5Psrh7ZegR4N+qQXY3wi9UtiRaganEpOJOtUSBFSUhEBkVVXoJ6yrL2DM3u8JFhVSardB6liILYvW0W/Jnf1/pQFldMSjWzXbZG6d23P4mjQoSod7b8h6VqZCUsu1E5Uv6RFXivVNXjy0qUPUf2LoNAqLUag8Dx748bZWHUm1mvpNyb1tftQf8qv/Je+2EyaVBEB1zq19f7VBVI7IVkKaZoQPKVTPlYtVHRdp09MhK7v6bqO3f6COU3LjA3r1M1JUTTznPCTFkh8iMu6/huOb51oHOeJijGPvvIbApPhRXEFl4xAM56ts6CELooYFWMweVkt9hSvUrdSCvM0mxHXh5Ck2PAQwDui70BM/anrqVhCVYIKpiQSW2bWxUDnHFvnEN+1gKM+y9Av7NFgCzEaYbC1HKE5qFpprYu1iCgky1LkKvGnRLsCzAgzGjBGZBay6ORQ5RV5gnRIgZxmYjar6C25EiXI1iBTCe5KkkcM8+tglswsM9ELQ0lsZeSdktiPhfjlHfvHF/SbS+TJlt/+nd/nex/8iP/uz/4l+82eH//B7zPsL/FdZNcHXr95TSqwvXrM5uKafrfnUM7cHV/y5Vc/4/OvfsnN67cwJmKJDG5L77eEaYL7M+Ijfrtle31N7zcwRl69OjO6PVw+53Q3c7y753R8hUxv8X7CO887777DxbZn/4MfMLvIm5e3vHOYSX7G947nP/kJ3eUjzrLh5rOPOX76Bbe/+pT3fqvj+TtPkcMb5rzlLMLu+ftsrp6w7fYEAo/219y8fK3YY++YxntSOuGjIydngikjTX60Qlycx5kiVckF1ykEyYcNsVNiVc4JV7SSOSdbK6VwPisRTpxoQCmafCfJTJKgzHgROlNeclLoQqCUxCyZru/NADqtLBpmmprUukYZw4uryAyroGq3cJ5HIyAvJGhHZ0ZoGTaXTfnJG1GWIrgi1CGMRTJRenxxjOOkChxO6PoN/Wam23QkMomsgy295TmhBvCO0AUNwkrG9WbcXMDN2rZW6UDFbQ+x4+wDrujcARwGH9P72VcZWYFYfIOudhLsuhPFaQVIq06eXBymdadCVBUGQIU9OiXpu0DwPcJIhaeI8VbmOYEEHDPH00GJkl1ksx+UW9X39Lstse/ZxL5Vgs6Ht5zOJ473B0LXE2PH/vKKOStB0RWtmqWkybpznv1uj+t7fNfxeLNT3oH/TnXqrzsmU0KpvCkwAGEyWUqXWrV0Gs/W/RXSPDWeVgtS3JKU1sGaKkc6W8VyCd08infvTU3MBx2wV/kaodNhY97pPJwYIl3Uan0IOmyvzs3QpFbR3GuxFY8GkdEEAdz6/NBEp5Hgfe2CSvNjDhOKqFVqS5paWOgdvsTGoWjBmMGEKNk4Z9qpr3K9KU2cx5HD4cA8T8QQuNjv2T15gnNwuL+nc7Dre377D36fP/z93+OP/+iPuLy8UpWweSbfvOF8e8Ov/upnfPGzn/PiVx/x1eefM51HpvPI9eU1fd+z6XsO9/c6hXua6Dcbhu2O95495/rxY56+9x5Xz57Qb7f0F3vCMKh8dOyaGlcfO7ouIH3ksg+4viOkxHQ8ck4zYb6g77QK3vmgw4ODb0T5ECLDZod0A3fTxJgLb+7uSQLFuhwaAtSKfKtXtwp6q6S3BOThv2uk+JCUXHPWdTCMxVz6apUw3mwHuq4nGNyy2rjKU0izwQZFn74qfer+KTbPg0r8p1DyjCB0nU1ut04fgCt+1cVgKai1/y5rtAbGyn16OFdEbO+14g2WRAAi+WGSYIWktv5leb9kSSPQhIiCW83EidLOB0RvpSFT9N+KytEQ3/OQK+hasl8haS1RF3TmaiuCOepwQpFF4cm50grmy70xZEMtKtQEx3w6ovmId67xSBvU2bproHxISUl5MLIkWV3X03mH7wO7/aXCezdbSk6keeZ4d8d5PHM8HKjzRba7vcEmlw6bA3IWnI8Mm17XWOwYDELlv4Vv+taJRs6iLTVJEFSf2olmPE05wb5ymsxIGUm2worMqTuv07kJjs1g5Oa+t09yi+oG2nHQh1KlB4NK8lFaO9hXdn2oBj8QvScAHfZQrF/VHqi1Eatsr05irsNllgrmWmpwXVWsFda1kWgSpW0R1upBpQMpvrHW0uuEaaFuItcqpfqtJUWtlWptbdMqI06EIIWuJDaS2QuE04SThAuFfE5It+H5975HGLYcU+b3/s7fZbjY4zc7hXHEQPGCix3OVJCq445T4fjVG37xL/4195++IJ1GrWZMSSWGPWQPcygUSXgn7IeOgHJG8vlIHvVLxhPTzWtuP/2EV92Wu9DBOPJbv/1DPIXH+y3udOTw5eeUVy948+XnvHjzFjlMpPOEm448fnzJ1c6TzjcUmfnqq8/58svP2T99Rn/9CCeOEHu2F5dcPHrMNJ14+vw598cDh/NJ+QQ5Paw6fv2wyouSd6UFKVbMa+3gec4LeRH7fhHmVHQ6tvfGfdBEI1MoLtsEbpsULjZwqOvISXDJCKNWfVpUSdD951BZzXoion2JUlUqRLuMDpbEeFUV0vNUo7VaSA3v2QYSeTVuYuu+yv0CD/b6en+Iq61z+ze2J1itY/ubVqCWoE07pJZMVeKuVWx8q6gq5MpbS7nvO+rE7JCSztPJdd8uLfUaSNb2cw3kqDvR1GSwc6ikfHDa7bRErAsdXeiIoVNFqD4qedSeDaacU1BVoDRPjOeReZxVN59EEUc8j4oHB7qoSkExBPqwxztP9AFCxIWgXZA2L+S745uOxm/AAm7zTaVJi9ZAzbriujgMM43dc294fQvYva4voHXmwPaUGY+weijBZmoE42fhncpQG/EyWsATQ53m7YzbWN+h+gra83btk7AO+6KGVztr3vnlLcoKglMWR7Ls1ZXJk6Ly2hYlLZ/Xor1V2FjDyCURKVnvR4iRx08ec311xfe//z7X+z3ee25u7/BFoVCXjx8h3vP27k6ThL5n2Ax0+ZIYI9/7SWG32/Psvff5/ouXjKcT58NREzKT4Hz14gU3N7d88fnnnMcRxglS5u7ujtv7O4YvdprIb3p831miYYNgB+2QxN2W+PiawQfkPLGP+ryyFELJKE5RBS1q1NF5T+eDogScCnjkpDMzjsdTU0uqAgIaJKrN0fu8ggy1BGOdKtKezZq7sfZL9bsPAniz/+IgF4fPxsnTZcB5nKkCG4i0rsSifIV1NGC2LkbOGS9ZYZ2G7XRA5711Dc0fuRVsqiZQVXloNbF6tSyXIrJd48IfUahTqZH1+t7Icv+qAVxSff2c2rlpiVxb5OtzMD/lasq2JB1fkytp319CbNeeb01MvHftfDzB4gKhjmTAebpuWOD0CCVHTdzqc5NCEWd6U/WMDHqPM0lclnXgtGPvXTBZbd8I2t4r3zX4aImmdjfrr2avaZMU5VuleWaeJ8bzmWkaSXMyhTFnMvB6v2sH1BtZ2LmFPlDj8Eof+JuOb59oJDGMacJ1M8F5ogSrfFQMqw2hQXGvXrCKjhrZYFWRruvwncdFz8V+p1hSq64E7+n7oV6rSQzqQw1Bq8r6QG0yaQjt4dV5GThHRHkLOWfwmboQaxCRivUKjHRqttU+96FXr4Q97VaYoS21redaklGhHwuJp5p97XKofGC2zaiTZYuUll1LvVLL3L0pPRcbylIH29QKhZSMF+XIbNLErghXAv7uqApA28B0mum2ju9/+GMOc+bF7T3/9f/+/8Bhnvj1F58RdxfgPXM64WKP74Ym0ShS6M7C/ccv+NcfvebCbYixw19uyccz8/lMDoXUFaa+kPJIJ8JlHwkkSAU53ZH//+z92ZNlWZbeh/32cIZ7fYgpI7MyK7OGrqqeCl2NBkAANCMhgUaZScKb/gP9UXrQg15klMlEo2SiSSYaaDJRg5kIAiQIEOiu7qquKWvKyMgYPNzvveecPSw9rLXPuR6Z1Z00o566TlVkeLhfv/cMe1jrW9/6vsNr8t1r3HzH9Jnw8i/Bv7xDcuGe0fU6AAEAAElEQVT21Usu+fd58s4j3rsYef3LZ9zeHkm//Jhf//JX/Mt/+a8gCfvdjg8++Crv/9432V18hS4s/OXPf8GPfvIjPvrpj/jAO7729Cl1tgaoi0uuHj2iknj/ow/59SefcGvqIOtkssd3vi6uz834yC3Ir1UsMbReCCrTvFByouSEGA+8oTbQAmRr2i6lcdpwtOoUih45x243UKbKUlRhrW08bhuUrKiW5DXjWRElp03tmgSpFHR08d5YLnUx7nFAVcjFqhuwqohg1CKjlGmFOqyLycoRrSr2IKbVj2uLNm03QFYAIq4c0nMeqyb4pg6CKuOIKcb4Lqxv5WNEir5fE02IMTIM47oQJuOQ5jxQiuroz/NCo1VarkFT9WmGoZJNZSdbL4TUDR12nq4fCbFnvxuJXhfz6CM+enwXmaeJlDPzPFP8givC5BdyyqS0cDpOujaWxumtTNOsi3UMxK43YYvAfn+l61tVuoc4QeLKh/syy/TfyCMvC41K16oEwYUVBKul3UMNxRr/O1qQ0oVI1wWjRURC1PE1WjO4c6zIXeNnu/OkxrX+vI3yh63p7bVt7Ll1v9CxUI3vKCJbItEOuyZoFEhn/geN0lHXCofks4BJWKsbzS3cosG110pFJXS+uYao+i2RUJdpowM3dNNtSUvT0x+GgW9/+9t8+NFX+eM/+iMeP7gmhsCLm1tqmpGUyKcjUyn89Be/RICriz0PLy8J3hEuLvjgySM++J1vaXP86cRyPHG6vdX+TlOR/PnPfsYnn3zCi/nE6eYNx9sD5TQRX74kPvvEtKj0enxUoMLHyNB1DMPAk4ePuHj0kIcffcj77zylDx1XMdD3HRlMYjcjGQM69PkOztP7iK9CxFHxpHnhdDpxd3u39mOo6h76DFrCZ8mFbI+TLZiV9Zvbtz//O+37LUTefq2ur80UmmJgtST0cJrWtbbRTdtc2BINC7ZbT0Q1+X9n0s5eQaK+iziUcphKA0dZk6w1sHcNybd4bD3zNoZ0YmwVAQvcgyZvjbrVLvs84D/fprd+ubNKAOcA2PnXZ5Wkds1n97zt1Y0SaDXB9TxbQlOlrvN7a6LHkiS98THqWu699js1CnCKQYUgVvM/Teoa4NhANBGTovWRQKCkYpYMDmdAtAS/gm8NWO/7gb7TSkMMHc0UUUxta0oztRTSPFOWhbQklmXmeLwzuetMdN36O6Hr8CHSDYOal1q/i/eBzmKaNWY4u/9/1fGlE40nY0DD9x19tJ6FvgX5OglakC1B0Z7gPL7Jqrm4VTO81x4NVzUjshkiNshdCDS98dBUAVCPiZbmrW6UNa3nKLUo79UGp4A2b6n0gU6w1mhnzeIm8sKK37w1cM//VtWbuv77PDt36OKu5yGrfK8gVK9a+c55lrKonJ84jqcTJSXKkrQpWAQw6g5CXuYGklKzXUOFnCdKTSx1JqSFLi88yAsXeB64js6McI7HxNe/9pRHT9/j5rjw7b/1R3ztO7+H7C7IPtA/eMzTj74GDj59/gw3z8h0Au8JfUc3Drx4fcfVxRXvfuWrvPP4PVJKfP+Hf8bTmglOGHLm8rQgrw78i//4/8SyTDz/2cfc3h65ePyYzw43lD6wf/KQ9775EcF5dmEg3RyhCoPr+ORXn3Jze8vpzWsOtzccPnvNf/S//l9ptj2feDxccvSBv/zZD/hX/+K/YPfwmn/yT/7nfPzrX3Dz2af87E+/Tx8HPvzGt5iKlj6Hy2supOK6kfe/fqD6S5Yy4P0PbXRspcq28DjkDPERFQmwYZZKxsXI5YMHOKe+F9Or13qOOekiY0iDOA0ClmVaKyGqFZ4oddb7FgIX+x39MBC8Jy86FqSUFYy576lhuQWySl1ayqvJKKyqGZoTKJJbcmUYVM++lKyu9fMEZCyMZ1v8gwVN4H0E0Z6Ndl3nR0N5pVRF+kIkwYoYiyX+a28Uspb7vfP0sSdYoj9e7IlDRw2OMHTENNDvd2tp3TmgOlwVuthbkqC+NNUCLaViutV/IorgY7cGcyXnNVkfx9H4zJ2ae+XKrt+pgWYUnE+2JniWbBWps51PakXmTJlO5HlRXvq8kI+zBrldNNOpihTou5H99Y5+2ON80OpWzQjQDTuVkQyR7CoBofOOsmiQ7BcbDF/A6f3tocfj6+sVAB26nugDXWeqaTQ+M2i13K3UilZh3xJLdy/gVirVFji1sduOtR7X9pAzdHWNjAzJXZ9eK1e3hKA1gIsCEvrbmxCFWz8LAycatVcDE2iBk/67YV+0ygTbGtaqFc7QUQxI0Z4xWSlWpVam02mtypXmKC2ySlnf3r3h4uKCR48f8Sd/50/49ne+xd/+3veItKbcXjetnHn94gVpnlnmGbzn5c0tP/7xT3n56TOm44m+izx69IgHDx/yzsMHDCHSP3hAniaC9zzeX3D9nW/x+yL8/X/yPyMdTqTjxPH1Dcs0cZqOPHv2CW9u3/D8s0+5vbtjmicOxyNlOlJfFT7+7LkyMP7ZP+Nqd8GuH3hwec3V5QW7ccduN9DFSN9F9vudur0HT7q9gzmTfESiBnHLmzfMN7fMt7fUJVFTJi+LrpnOa8X87Jm/lVpwNhrW57c9x/bjt15z/obng6JVp12gH3aEqMyQVF6RTF0omgISzq1UQbHnXKSYulNLvkGCp/M949CpSIFVQ5YlKWDWUDLOqUw6zmuRdaxsl+JWyhXOuLXoS6JXKnxxKoJRzSRjTczdFvBvA9nAXNkatM8B4FaF2GYPNIbGyrW16kaLI5tPhtIctb/WO08/jNpELRC7nn4w+lGL7URwVkX3MeJ9VEWvoEbURQBLetVDTSlUOWmrgJeKL40kD+Owo4sdQxw00ShVTV+9Ek18t9Veci5nSle6j6eU1zi3CSgsKZkamfZTYufQh4CPHSFG9heXuKBWEbnoZ8TYa6IR47p21MpGwStlrdr8dceXTjQu9zuaq2MXet1Qe39v/2vaxS7YAm6JhkNpT23w+KCNU+qboA9e/DaLnPdrFhqcKgaInJWIMYahewvsk3N9Y/uWq6zKH7TF1T5JdN55Czir0UncudqEBU3tOE80xDYfsODDiJoNzZCiKEsJog87ePKapDimuztqUqWsItaYVlWvf000RCjVIcVmtAilzCZDmujSQiiJvmZGCYyCuqx6RzcOPHz4iMdP3mG4vOLB46c8eu99XqVExuG6XgMd7xj3l/SHN8zdER97vNGoUq343cijj77K40dPORwOLD9QJ+iEgxjxnUqrvfjlpyxp4fZ24uLhEx699z79xTV+D/7ymo/+8A/xFTrf4ZOzDdqxf/qUYdcz7kZ6P9INez75xY8pHnwXVYo2q5Tk6zQzpUQ6HOmqcBkix1evOd3cUKaJ6nsInuwDxJ5uuODBg3e4vT1y9eYNPmiPQJPrg/soxnmJoy2SZyMc5xSJxgcKisKnqmod3sn67EQ2De4NSTKJRFepTs2rauxAKtOcWIxTXmu9hy7a0N7WWbdV0TZqlGzj3r19zs7EBVQdxpt8X4N4mofAFy/s2/ufVzOAVfmioRutEZ52qm+9n/eYCkhk149EZ2ILux19rwt6RYixGW2mFXFyPhC8qAGXj/hVNaXtae1cLdgzruravNjQraryviFGhmEg+kgtwm7Y46ODUKkSaDxrsUpJMZPR6k0xC3OPNbS8cYJV4pgmtbKKD6hKmY0bayBuTZJOlItfa1YaHI6cF0X5cvrcWPjtcf+42O9XQ82+s4qX+VQAa5KwVh7a3rQG7RaAayZxFqxvAd4ZHssaRVqws9Je26+1RyVtf2qvX//aAsd1b5H1bRG5v+zY0aofrs1f4WxObhvh2xz/tdnX/u2c0+ShIbe+rQFN3KAwT5OO+5zOGt4bv74wTRP7iz3jOPLknSc8efKEq6srKFnlNrueYIlUwLHME/M0IaUyn06cDie6YUdKKj96c3dgMvGKsesYY8fp7hYvcLG/o7+4IA4D+6sr3P4Clyun6wcsy8w8neivLri7u2X/8Jrbwx2naWKaZ6OJZGRZWE4Th9evORyOnA5HltPMdDqx3+0Yh0H7Oi3RCN6Dd/TDjq4fKEvCjyM1RE43N8yHO5UetqqLIvHeAu9GvNr++5u+WkdZW0PZxsDnDxuD0tSJzpNJp2h6iOgO5NYEoe0TSrMTi7XF2CiKaFtWTBFwzsRJikK2ORVSLkb/tDH0hVdyLxjbXtXi+/Yym0Jtb/DeIyESBPKqstSS68YQaTm68PZSqNNok8YF1qrLvRetpoLtPDaTO9C9JbjA2A9q2+AjXT/Q9yMxRETqGnhTFUj2K4og+KD7kg9nPXWisIG0yqYqE+GDgFOBpbPFRtcuH+m7AQmavA19ZxUNQbz5vZVKFu25KuZuX8r9NaT1wjjH2hYQndLvG2VM9yuvyWjwa69LqefriFVNqwBFpb7NMNR/yb3pSycaT5++Z1u5LbWiyk/REgDnHFmMNuV1MlDVtM9hjW4rchys+WZTEcCdJSpqWrx+mmrm65NY55+r7ddw5vBbimpYVyt3i1SkLOCEs+euT7Q1RVWozlsSFa0EvW1KoBzge6iDfZ1rUa51VTPAtCxrpltEwDK/jLBU7d6vtVoLUIV5MxCsLfQrdbMuTMko8w4vAw7rFfcJ0AU85oSvmasQuMxwMWVSKfQXI08+eJ9vfOMbPP3o61y+9zWefOWruIsH3D5/xqkI1auJYOx7Hr3zHss8U5fCcXeJH/YwDEy1MDx6wDf/nb/Dg37kxbNPSbHjIJ5BoFxfISkjJXPzcqI6T7j6Ct/9d/893v+db/Lhd/6YpXNkD1//3t9WKo44WCqOQIgDbuyInec6Om6f/5o3z5/R/dt/xc3Ll9y8fMHpk0/Jc6ZUz+hnhhr56b/+c3ap8AfvfpXnL15weP4p86sX1IfvIMFzVwrRB0K/4733PiLlzGk5Mgw7nDtSlonq1MMinPUrtKYr76smd6CvccoVTrkwDDtCHyjek5xnwVFSIjhH7yODzRHlpirdsC6zTnhvcnS1cJgOzHUA57i9PRkt0JOKqjrErk3PbSI7p3TBktUDQ1F7TXSdIVdNbs856Dpz/ZVNAjCEzjAjDRq8b3TEBvZsTqF66Igt5hqalk1n3sVIKpVlydSUlbZgm1+rTjrRYMbHwMXFnqHruewuGPrBlNxGht3AMPSE7ElLous6iuSV+dSqpapg5YFoi7kufsFQ2uI2LXjvWFHf2PUreuuM777f7zXZIRC7QZWjysw0K9VtXhZOhxPzPJNSNk6qJqohevrO07ugrqvjjhi19yxEx7IsLPNCMonT5XSk7w0lTRNzKrqYTyNDDyNeE0+EKp7pcGCZZ+7uXtN1HTF+6aX6b9zxzqNHtMbp1sNAPdsf/NlGaBNTimUBImdoqyOcNYIWa5rW/KMFkRsd4zxB2aoZX3ys29ZZwPP5n54lNaIgwKpytoIKm1AJNAR5o2u2pKMYjTll9RAo5ZyfbyBHaxJH1u83SpZKyutnK1jasib9jFwSwQcePHzAO0/f4frBAz0Hq3LOc6IzH52Hj55owNVoYqXw9a99k8ObN5zu7vj1L3/Jz5/9mo8/+ZRPnz0n4ogILz75hGWaqClxfXXJ5dUl3/qd3+H66pqri0v63cjuYs9VeMwHX/8IEWGeT6RcKAj9bqf3ohRePv+U158+59c/+jE//LO/4NWLV3z26jWvbg/aa2MU1uCgi95iHOHBxSX7ccfDx48ZLi/x48jzeebNp89JxyPZ6Cha9VFABMxw8V6o+/bgOE87xALS87zzixKNsyTVNaCujVeHYImG0wpHFae+CcXM27xf1c4UDCsqVlIyxpE15TRhSolclbaTU17fp3lEbY3psl0DOte0WNb6jxw4vzY3i+1POm/8uveEEEDUaG6TFd7oSvpeTfVqA6Lb2M9Z++JSTuby3gBht47Z7R5aL671xjUq1NiP9F3P5f6KIQ7a9xB7dvsd425kmj1LWgiho2LeZW7rI46d9u5pZctZmFm16m7Xv85he07OVQgNNKgas3jPblTaUgxK76tSyDUxzSdqSqRUmKbZVArzqkbXxY4Yg4kkRaNPC0Nn3w+BZZ5Z5onjUf3jqoOaE04qNSm1KhehG3a0vpHGYKg5cTrckdNMXuZ74/ivOr707rWWcdsauMI1Dd1kC2bs4XrcWqpr0moOkxdFA84kLdlUlMmtDTIKVaaizVmtbNwGdRveTpzK4trmoWKvi3K9jcIiVvqtxi+spqojLdGorH0m2zVujeOLcYDbfWgDtzVzl1KMr14V7dYcC2+a6bmqrGnVpUCDNlcJubabS9NY9s4qKiJIaMoHWipXfq9inq1UKRj6FQI9kSsXqXHH1dOHfOdPvksYe+6mExdDJEfH4gX6Hi/CUGQN5IKPXOyv4EFG3v2Am+cvGa+es+t3pLsjv/jz7/MpkcObO/auI7qO3f6aP/lf/I+4uz1w8/qG0ffErmfY7bl88oS433GII/iABI/3pqBUIUTV0K1xJOwCdIF6OZrs7vv88QcfkqeZMs2cPn3Ncjpxe7zjs1/8nOOrl/zy+TNu37zmeDoQHz/mdHPD4fVrQhgIQ8YN4GLEj5GSE/3VJRcPHqrvuM0NJwVByPh1fLdxZ1IQtFS2oEkzPlLFQQHnokoZG1HTi+XDQXuBLrqOec6q198p4t01GpFUplJxiyba1QWqU3stlUrUJj9NqEU9IWiJhJVL9SI0kXYYTcPRcndwhDXB1kayitPFpaFiOupoBn8qFqU9Gjr+/b2+o9YsG10kZN0g9rs9HkeaZiulmuKOKcBdXl0Zpckzjr3q5LvRerY8RQJDNzB0g8p7EqFARM1Aa2irNIi30S8Vl3UCNznGJluLJbPbnPUrWFBrXbmt2k+m9+Z4msllYUmTlvBtlek6Va7RBjt1UG70rRADkpPez7SQ80ROhbGPyDJDmvCiaFPNwnSoVtGo1EUTjaU7agNqLSoMYAlcmm5J80TNJ+Z8Yv5tQeM3HjFGWoVvK1efoa5NdKOt6bQqtr6wbf4K+piMtP2s1TCcyZ/qmmuNsWvw0Kp824xqJ1FLMzU7q5KvgWXrtZN75mStOtG+bh5R8lbFUFAaQ6NOtX23nr9vk5lue7CegAaZFqQ1rn2r+m9VGDlbYxoSrPfw6vKCr7z3lG9965u89957PLi+QkQYhgGPqru1xG9pKjyo/xA+4KLj4uoh43jJbn/Fe1/9kNN0RE4TvlZCqTx/8kvevHrJLz/+Occ3B17e3DJUGPqBrut48/IlyzSRTicGk/ftuki/39PvdrzzwQdcXF9xeXXFw8sHXPQ7Hj58woff+j2WaTZwMFFS4nh3q2tIyUyHO6bjkdevXhIn7TN59emn1BcvqCFw6ntOd28IbOtSE6/QGPqLgq8vF5Ctr/viksG9/EOcAqbOZNC1n7M1CsfV6wCqVTw8XfQ29jVor5U16PZnCXkqldz66arovuEDYqCuO1Nr0+nj7LSllSK2kWoTR0T7G12bV94SlvVS9c1EWk+snZu0qqPAWlHW8RrOfENWAQ/nTQFOpfBFhOQM7HKqghh6VQDdX15qhTtEhk6Ti74btr1HVDZ4bYw2rxW9NXWLgw0QFkvi23wS0bktteJqpXm3wZZ0qEKYztdoghEtds1FmO5OpJLUUDkne19H7HpiHLi48Nve1Kn8foxhTSTzckLKQsrKlKg540oiYmIZc2ZyVaWbxWmVrkKaTqaemGzMqBJZng+kZSbNJzY54r/6+PKJxrq0rUNiW4vhrPHTUJC27J1nktsqt37faOUWQOv/CqzUAyl1RYBW6UIR8MbfrspVUydya+hE1kQDBMkqwds8C6qI0bGAqgoa1RwSG6pUpa6qIGtFQ1h1yfVzDN3JeT3frlcpXQGC9YaUWikWuAQfbKMqa9VG3NmkDRbonm0MdZ2adj1nz2Vt6MLhuo5h2NNfBB48fcLj997lKB6JgbjbQRcpDlwMhBzUELGhc6gr5Djuubi8Zn9xzbi/oo8deZp49vHHRDpyquyGHfvdnsvrB3z0e7/H8TRz8+aWXafc92HYMdfCXAo3k8oRxvOqFAIugo9I11ODp8RA6QZkByH2PNzt8FXv4fTkDfPpxO3hhjjuuPn0E14cbynHW+ZakJyVA3w60c+TLrxhgGAKWjHSDTt2F1dKnWrl2EYBcl5PzTU60Lq3ruO7pXe0ioEhmd5tzrtNuUxl8FQuOafZDHVakL7d8yyC1qpRjmibNYaU1nXuaInWbUPD1nJvKmZ2X50FC2uSZPOtjZk1cTIvCr0CWqLh0GpgEDOmtFEXO7+i6s0BWVEhbZDte5VzbQup945u6AldJHYdl5eXhKiUs77vlEaE+cyIg4xVjII6g+Osj8mvJITKtr5UNMnXjKOuvSJOqpZybd1pwJiIVTtX5RTtkcglI+KhwjwnctE/TYDLh6CbUtC50YQo+m7QTScEcjpR0kJZCjkv1JKIRDUXLYlAU/yolEWpUwKKqFenevVJE8ggmnC0zaHmGWQzhPvt8cXHGqqs02XjeEMzDjM+Neo+v4Xq23EWX7Nq83O2b3FOQ9qSAc7nZgs+0dmczatD6XLt9GQNUFbnYEsktKdoe99NCrR8DsgDSEtad4RzCkNLrOqGOpia4/114fOu1PaflmRgAa3TarqgIMcw9Dx4+ICvfOU9ri4vdA2whtkYIv5Mw0C1GAyLN4VIvBD7QNdpcnJxdUnJiXR3h8tq3hdKZdcPTIcTPgSWtOB8JAvkeeGz559yfHPL4eaGMUS6ENgPA91upB935HnhwaPHpMePGMdRew/jwJOn72p1FM88TyzzzOF2SzQOb2443N3i+4766jV1nklpITtdh7pe17G+7/RaNHO1mFkpLl8wOr/w+PwI/Cte+wVJh2jsbcqD22eudEurPjQJXFUlcuqDUvJGbXVn9Lk29u+NCatCuCZqYfHKelLnFb1tbp1TBM+jx3ujUFgld1n/bMdG6fV4p9TXNtZj19F3/bo3ObsOb8BQFztKl6FUfLC9qe/ohp5u6LnYXxggpu+jokURLwp6l7L52vgVkGxJ1eYlgpzPJaeMlhU4aGh2q4SyUnkRbO6rgJIyIFRquBprZ15mcsmkYlYRqCFnZ1StELu1abspKnp7xrVAWUT3ppy1RcbQ9eDq2ptVFmtZcMGagh3VvGuU9eC0n6wkcpopeVavMzmvQP3m40snGjXZoPTbjfb4dXCWIi2x05OlVSksGD8b1EteyEAWt6rXFFMCEoTcVKBAKwI5kcqiAYMIuQq+ZgsmrGxWTUvZll2PW2diC8b1n/rAi18TZFyp6wtWlTbfXCatIbddW1Ezs8p9X40iOkBC0YktVRS5cSZ3bAMrBOVOktUWTewavU3U0oIvQT0D7J5vs84josiC9lUpinGXCuXxjv1XP+T3vvUNhqsLlm7H43ff5fLREz781rcpl1dkHPs+cMqO2RrQVQLSESTSu4H9cMnjh+/w/vsf8Mluz+sXL/n4xx/z4J13efjwMd/+9u/zB3/8x3z43T9g1+/p/MjY7bk73HGYjnz64lOev3jBaZo4nQpf+/o3eOfdd3G9JTTVg6jBX3WOpQoyQ54m5sMdy+lITSdNWvqB+XAEcQzXT/j6H1/j+S6X/8E/4uc/+gG/+OmP+LM//wtK1zGfZsJpJriI60fy7KkuEH3P5dUjqlSePHyXN7dHXt/dkpzgaiWKepJUhCzKMV63ZHGIeLKVhKsNBO89EU+qQikLnY+K1PcjDx8+pO865tORkip5UbQaqeSSVfdaVPPaBd2gightz2olWZXHtWSzaLitlb2AVE1YMk2NSoz04Yix8Sa9JcSV0tSlvOCiWwUJAnGtNgSpSh/0Hbthp3xRF7i4uKAfenbjjv3FBaHvEXGEUuj7gbEfcEXoBP3s4LVs2/V0vQbo3gUiEVe1q62GipMOJ55STtTiVCe5VFxRN+eUlMJUJNu8FpaVfxY2lNiBrxVf9Vp90bmd80YJKQYi+AC5LLAUbm40CKI6+hgJXc/u4qGiQsETu0DsojUcRm3OS5WaVZp6TglJCzmduDu+YplPlJw4SaGPgS4GLjrtjSlAKjMl63gKJtUdsiOXxGGekTTbQj4Rnfb89J2hTF9iMf+beqRpMRR3G/cK9mjSXWuhSRu3PFyrigCVmuuWmLu8Bvp5lcctK6VIjeP0tSLVjMy2ZmkNNDZDspyz0pjKWxWNt0NMYQXr2quAVXUKGk7gtmDK2V4iZ9UaAzRaMNj6gQStkJ6jqc7WmE0lcaNRyWpZ19ZB3cMNbeNiP/DhB1/he9/9Q/bjiKuiMs6+V0GWEDaBl+bRY4GV4KAL5KLl9FJhqbBkIRFsLa7w7ld4+O77PP2jP2YYR2LfMe5HlnnidDrwl//qv+b25UvePH/FFY6uFMLpxK9/+lNe/uqX/Oif/1dgMqC1gBtG/IOHfO1rH3J9fcnl1ZXxDGDcjQzjwG4/cv3wq1Tgo/q78OY1Li3EgPrkjAPLuOPf/uinLP/Nf8vPDnccRKBkGgmvJbJy/hy/YNy2e7IG7ueD4Qtf3L5sAibG/DijT6ma2BlTwjtwAW8qao8ePqCLkePdrSr9natIVUsy2pU0WdNSOYPBtnOwv23wmudD66U1I8B74GiLmTb/sUo16VxHdTq2nAXiwTtibD4N2kMBgXG3UwPLrmO/1x6a3X7P/mKvxnOxo1ZhGDLDMEBVhTk1uTQbBKtU97G3BCWimnSepvSJ6NocqsdJIHpHQGPhmrL2YK7JOmSqxWt+lT0XAzfaDRaMUt3Mp6v6mzgHMaqQQK2V9OKz9T51fU/XRy7313Shs8pFTzSDaXAm4lCoudGaEyXP5DRxPN4xH+/IaWEIjhgcnXeMfW8gHKQ6U4sjW7zjiUQppCVZf05GpKjAQ004J/R9MHz9r06m4b9PorFkS2qb9Cn3FsWUlDOuhjBbYF4NSaxNBtOOXIUsJtkqZ/xNWxzbAielWuNzWQdAEZRbSFtksQduVREb++t720Bv+C1g6Na2wCKNB245R60QtpKcWENvtaa66qrJzqKStU5wQUg10TiAlWpogteKhpXDiqCN5+eo80oLMwlePG1vkjN0aS29GcpQxZFwfOIqUQp9ntk54XHf8+jxOzz4xje5fvKEuYsbF7HrySHpdTmoXhf2pmwQEJbTiTevXxONV9+HyMNvfMS7X/saf/If/Ifsnz7iON/y//hP/xOm24nlMGtZbZmZDncs82QusYWXT56wf/SYr37vD3j89D2evPs+qVhYnAVXF9J05Mc/+Qte/uLnvHn+DI8qdXnvkUWlAysOfzGwf3DF3/2Tv8OD9z5i9/A90u4RDx49ZnzwhCIwzzPibolxIcaeuN/ZmuuJvSd0Du8Lrth4tpKnejvUM0DGuK+mKY531iRXDH3QxcJJq3J4fFRTthA7XIiaCGKLOEI1EpYqRYmi2hidiYKXTOuPyLWCLXzrxuW0YQxh5Zlrocjodc0dG8Cp+oT3Kn3bdT0Oj+vAOW0wC0EVxkIX6bxD3YcCF7u9yUl7Xdi7iARP3A34PoILdK6yq9n8AiyhRhOYpikuFZOv1g3IizP5VqhoiXkuM746AoHqCsUV5jJTarLNykr/rfJk8+7c28CERpGkawa1EGpdizvekoe+7+gHRcD6frDz8gzdAMEhAfU5wJqFUS+UeZmV654yOWlwueSZQKaWhZQXXX/OgPJGz1Hp7kBNdZ3LMUZcjOwuRlItTHlmXhIiquZGVcHOWtr69VejnX+Tj7ZRu1WhUI+G1OeUNtM62UClDWTZUP8WxK2OwGvi0IQdyvrKRsOtVYGxlXpUN1rUuXhIC+7vBZXr4dZzos3fe1UXWV/TfkJ7P/v5qj5Vz/bENnZErHhqCYbNR3eWrLcqyjn2rCCH9TwFZ19X9rsd19dXPH78mL7rcE4r/7UUJBRkldXl7No3rrquMyDV4XxFvFdH7hAR73ExqvdICAz9QLCEPyHMOBbnufzqV9k9eYd3Ppy5BEJK5Nev8Fd7rl9/wIel0PcjfT/y5tUNLz57yU9+/BN+/XHh5ThyeX0FFs+kZTFfFaHvOvAKDgy+0kfPwweX7K+vGC8vCQ8fkebJBGCU7hhatdhxb6b+xgSDlnRt40H/+uuSjLOxcPY9TSTVKNYj1iCsH+Cskh5ip036pnKnfRwKYKv8uKz+Pnoq9hm1gbeWpTstJsu60aDsLNqPrXrVNqx1RLVqj46zWnVcVK/qTs510G91jeAdXad9Ct78Gpx3DLv9KkU9jmaga0yKYGZyXRGGMasTdgiQ1xSbplq17iMmWKRUsrP5XiEtMy5oT16RSq669qtSWxN0P0vg2/O0Z7nVZzbAwhBze72Ym7tWCVWiVulbrvlVdJ1WY4Jf6YitT6XWQk6ZnNUfTMUbMrVkpKr0/pJmZQDQKlVtt1wLXgRnA1BMIjxG9vuRlLVX8VgW7TUtCUSbqIto7Pxlqu1fOtHI87ItP9Zxf152TSbXpVr2y/rz1BxGzxAd0CCq1LI20rTqRdMVbhu2lLJOgmrBiyYbG52gKYmwxoMNvZKV0mQv3MpwpVqJza3ZpzubJFVEe0ns9Wsp2jaR4jM02lf7XQe5ZJPxVSMXXKOD2e+JIcv4s+Epal/v0EDUGo+zrJgFYgGlOzNo0kZ2R8Lz3BWQjE8n3vPgx4F3n7zL1UcfcfXkMa/vJqJ3dM7Rh87Kbt4CYaG4qrrZ1qyc5om72zfEseeqi/Qu8PDb3+D973yH3/1H/5AXn/yKT3/1C/7Lf/p/4/TiDenmpIFqTpTTgcEa6mqtzMMAl5fkmOD3/5AHTx6T2esjyZl6OjK/fM5P//k/49d/8We8/PnP6JusXil0TrWbTynhHj/kwVe+wjc+/Abvffg1nn74lDvXMYwD/dVDpvmongo50w2Zvi9c7AabEAUC2u/grBNILNGgWqB4hkAZRWp14XQ6sT+XaFSvGysBHzp8VMMovJrr6DA0ZN2qZisiJFY7kQyiKiDOeikKAr5DKxNni7p4CyYcXV47mnBekwzfehrEBokoItVbr0H0gS4quh+CI+56Yt/Rx4CrEVcjFxeXiko6Tz/04AOLZDpz3XUh0qG0xBA8PrgGudIa9jAOMGfJcVuERaC4RBFhLgtBApGO4iuZzFLmDeF1WJ+WJxiSVw0aak3A3gLNUvScXCkEV7Qn0Xl8P9J1Hfu9KuXE2GmCZb4cfTdSKSRZrLfMqXeHYEo5yo8tOenCnmbm+UjXaZKYcwLZSAFtM2iJV3CO7IwCR7U+lsBu1xOyVmsXMg41vaxSViGJ3yYZf/WxzMuK2WweBi2JqCQz6WwgwdrYaLQ77Y84C+lF1i1jDQil9VCsXF+jzup/Gq13ow834ELHQjOVbYpxWyC2JQ3tcGeNtmffPfvv+e+tp8NapWnncH4+NMZBI0xuY0p//yy5WLMB/X6pRUEJF9afj+PAxX7P9fUVXYwUYyW0nhSnhg6IKPWknfGqklfBVGNM7CUgIUCMKyjUdyq92Y+jnUplmk/MtbJU4eLpe3TesQuRXcnIPHP89Bnucs/18cjV9QMuLq/YX1zy7Oe/4kd/+n1+8hd/wc3LV4QYmOZZA7YqvP7sM5bTiTQd6Q1Vrw4uHuzYX4x85b2nXB4fsr8+sXeB6XRCrLcKo4xpiC9rgC6f++/ZIW/9/DzJkC00d/d/5a3vsFUGWtKr0acm1i3pdmZ2HJQiFGJcm5HbWtreu1YxcMbfO+c1mLTLW3NFwRJImyfObSPV5KVdC2LbFtHGZm3zqdD3nZnOacN6cJ4YdQzELhJjhwtanRp2ewWAgzY9+xARccSo9N4YO2ovdCnrtfrmxWaj37XmeQUAteLmVsUqaHRG0ebvLhBrXAVQcslrpbAl+2vkaNuVqmy1pH69icqIqc0sVKsf7fp2+x3DsFMK+7Bf1RVDbH2d29olDdAvlXmelNqXzNerasLhqNSSlfpfywYm0NYke6ROValw4KTo/Y+B3dCpsTaF6VSpKK3XyVbJqWdrzV91fOlE40c/+9nZotWyIUNhqiIC+vBVex9MXceCi1LPuaKmOtUGJAYkO12+q4qvauIQW1OZ16TBSsOdbNq968Jog10VFaxJpc17p2Z5ta3M1UzJ8CbvhgES20QuRsVqgeUqC+ccQr9NRKlr8i+umeyp9rATbQoPsDpxalCZOXdbLtkmQfBWxdHmY3Eqqdm8QQzK1eurgdpKo5I45oVn8x2Pv/sdvvH7v88ffO+P6fcXFBcQCbgw4H1PqTN+6Bgv9pBUtm4qiU4qrvOEBxeEh5fExw/46MN/h8dP3+Xrv/O77K+u8M7zs//mT/k3/5//N7/88+9z9Yuf8nhOdEtRBLomajqxHwZtks7CVGZOy4l//Z/8H/n1H/w5v/74l/z+v/+P6caB+XDL9/+L/5znP/hznv2L/5Kr08RXU+Yy7LVvJmviJeje9OLmNfMvf8n/9dVLPvzuH/KV3/0OD7/6VfruISIXjEOvcomvX3OFp/ORZZn59NNP+NkvfsKvfv2Ml69vUaZeq1a1Ld1rMrJWkCo6mjQYcSYlF0VwosorVTRhxWt5uhsHfN+bgpqaTIZuYMkZvKpY+Khuz81hVKSSTxVfvSlWoIterbqPaU0a7ywRypXgPCF6cjYXYS9WurZFpAXmfc8wjuz2ex49fGqGPo7BmtOdOFwQ8NDHTjd7H4nDQBWYk4a6wQljpzSpvh+Ua52FRE8Ie3yo4LT3yLFRlkQqx+mk0oExUBcQcSCBGlSlLucFyRFyVv6wwxZ1nX++JTBOJ3Pwji54um5H2zxiRBuv+wzJQQ6QM7GLdGOP67XUvNtdEH2HDypA4FrFyHlLBAPzMpuBVyGImhIud2+Um1qy3rdScDVxOi5Ua7oriyaeodONvQ+9VglDoOt6akq4UnRDqIlyKhy7V4p05UzJE7VkvKpToCwxZ1KDv6VO/abj45/9FGhJrKyBd/teU1bSoIg1Qm/39G2hj3boHmRJvO0xbm2MbjUBaD1OGuNX23Y0uXwrLMR9LnHcAvrWn7UlM279+SZWoZ8hxRRtzhKbs3fbopumAmR7RwsCV4z5XoUE1sDQPk3Q3g6RyjzPGoT4qODisnC8u+PpO08ZrDrYx04BsSqGgDYO9/1KiogmVA6IOC7Ggd04WHLWPEzs/jlVZCsWSHvvGfqe/mKkC4ExeG6ffcLh7pZfP/tEqTK7HQ++/nX2jx4zXj9kfPwOw/6CcnvL5ZPHXFxf88E3vqmNvUX4+Q//kjcvPuPNp58ii/ZtvLl9w4kF8cJJHHcvb6iv33C1VF4ej0oN7XpiSCy1qAGoc9R8Dlbde8qfPxoedJ7pvp0Etq/P3lCD/cYukRXkraUqNdXGBs6p6EYMVsXwVokINHUqmsN0UHpQC4AxPn85Tcbbr+s5qeAAa8zU4jWp2qx9Hnxb+LWuZ5vpXWAYR4bdjoePHpuqX6QL3ryZvDlxeztXfZPYDwjOxoPGc7Hr6fvBeukU3EtdJnY9Ic5rs75W0m3PL8KcEr4ILpdNGctivIqQ0oQvkY5B4wANt88qhVgzutKMdZ+yyp3tw+pjAtJ11JSoOSEpqYz7oKpWsevpx5GuG9WHw/cgThVRXaDWTM7aIyFSTUbapKbv3miCURSkkpzJy2wVlLI2mzsRu6dBJXu7uO6txUSL6pTIUliWE4fDDbkU9WNJJ6Rk9f2wZ1nfAjX+quNLJxrLsnAPhTHU4byzvlLx+FYVXbNggdZJZmuZvUlTp2wPF43mN+qH/nZb6B3eynhlG8S+LYj2Rm0T2eYkDfa5X8JW9YRqycs5/7AdysmVVe3DY8ZoaNXkXMlEtovTzzfaCwjZGRVMnKk1sM08MHrJ+ql6Ga2ct+01awB6f1GyTwyBIjDNmeev3/D+cSJeXuG6AcQRu0SQYMGoLj597Dae72LqXnhc7Hj47nt843d/n34/cnX9gMsnT3EiTLd3/OL73+fFT37M6Ve/4vp4JJZCLJlFRCWOQ4Ba6RD2oiXtWAohV/Lr1xxffAppwnUeysJ0uuN4fENaJmpWh7Qq6o5dUUqaNjZmhiq4pZCeP+PZj3uOeeF7771DpZBrZuhHQtXkUREArbC9evWSn//iY97c3TLNs6I4DZlp/2vPc32KWOCyeWEUq5C59d7rz6KVctWoR9GwxrH0zjGOIy4EQt9Zs7GON+89SKVOkzWcGTfaQfTeaHY6osOZqVgMkRgitXM4L8Qo2ijnzXDIm5Z3jMTY0/e9BgMmVadNb4ocEcRoc0GVRfzGoQUhZeWNdtFcl0O0+2BzzRLoQm2YHm6VxxRqcKaoFGxO+HX+KB/bUUQrlc2R2PuAi7ZA2CboWrOf074lMZUu8GoUZmdRJjXyy8abLiXjayAXpxSoUPElELw1eONJRY2rckrqNF0ylIUIuFoo+YTkBDnhfMTXQpSFQlMB0TXKixBDT9/19P2oJe3qqLmu8t+lFlUUozJPJ1s/rZldWuO/W93UqztH2H97vH2ktKxB2L1VXNr8bOpJNDSLRidaX4gFv7YmnyORTZJjBbPc+Qpha/i58oCsSzv3Fuq3/rUu7fafLc58KxFx7Vrc2dctqZL1340Wte5/7TPceZLRLnS7lLf3vfOzPN9+FDhRwOB4OPD69SueP3/O+x98lXHwZ0Ip1idgYImaZSoKu26Rsu25wXldc/xZgiFbUNvWoiCVztbT4qCcJnU+zpmbT59zfHPD4XBkHHf0XY/vBwUQSiHXiu8iF0+e8Oir73P56BGPvvl1698QplLYP3zA5cMH9LWyzDM3N69gDLjOE8eRJSWKVMbHT7g+nRievuLjV2/g+afcPX+ucUIDHNcE4+2J+/m7/Zvu/ee/JduzFWgiOQ3UOa9gnA8hZ6pMPljAbuPImefD4Me1r67lpDowFEXHnmv7UXOVX5NgZAW2MLpb8AHnmk+DEgK8w4RSgipi+aDJ2mB7U1AVwi5o4hM9q8qh88ESJEuCxBLtlLWHJKgrd4ydIv60mFLnTUUsCXLaB2jrdV0WpVFbr0N7/5ZI1DbW2rC1SsraA4zuxb5xh9eEyABA1xINQYKnekfxjlKV7onJ3xcHaXFWYYn4IDjr4/PeejBKJi+TVUUygWqKhydqNpli30CwjKtF9yQ7Ve9UqKaLPbE3uXdLFlLV3uhcK1kEcbo3VVFWiZNK68pp6q+6+rmz1eY3H1860SglrZt821jFnSFCVp0SZ8pKsk0xzWTD/X6MFjCIbrjahKQLUXSbc+mWiaAUFQs414DLGs+9a4mK24JEWqHYztHKZFtvRuOwbwFMQ8TW66yy3tA1oXEtb6q0zU33LzEeo9K6WtCYfaFzjigOn0E8ihwb/1sQom9nKzTClPprbEmM8uus0/Xe5gg+dNTqmU6ZH/7lx1w/ehcZ9hAjVOj7Eb9UyBoUdz4yxEGfSy2wFFzr44g9X/367/DeVz8y/2iHVMfhxWe8fPYpf/rP/r9MP/0J9cVnKLagQf3RR5YQSN2eOs30pfCBC9S84AQux0h/OpJefkZYTsQh4mtGRMV/6TpKEeaqE1C8p/QePwSkFtJxYfSeHXB7+4bnf/lDfvbsE/7g3/+HSntJif1uj4jHSQYyQialmWef/pof/ODPeX3zitN80kTDt43gfJwZH9VpCFuB5vRefCUX5W6em1yVWtUorFfli+psOzBfC49jf3VN7HWCn9Ky8jW7GKEKiz/gyKtsYGhIlJk+CiblF7SBu+8G+r7HuUiIjn50muyEsDa4eR8QczUVEfq1+avoRi9ezRY7BbZqxSQaDfGx+GrJi3JjR5UqjkElgy2mQu9OJYs5aoujLknpZM4TvSDFI9kRul7RH+/NjdWc1AlUMelhFwihJ3RGR3Fule+LvbekUGUdHQHvItEr2uxxLO5AwnFYTqtaR6DicmBeFoKV2Ed3QQgdwas5YEmZZZooywmpCzVPSFB4oeQT5IzLGRUfzgiT0tucQ4gEp2jP2I/shj278YKb24M2tKcFcZkqhSUv6ILpyceDbqA43RRsDdGqr9LQPF8UsPz2aMfqxQSrCZ+CNGLqcW81SltQtu7AZ8GfCg22hJ41zlfH4roG9FuCYfsF94M77c3bEoLPw1iW1FiSsKKC6/vBGmHaN/R87n/ueU/HWpG5V5m5n1C197ZfO/sdVmBh/fe931IKVNdFuhh5/eoln/z61/zsJz/lW9/6js5PrxRXJ9qFJkbbXCkdKa0Gl8jmsRWdV3+GBtas6HM7F2f+BBq05eJIIrx5dcPpcMfdzWtuPnvOcjqxTCfG4YKu3+FCT02VdHvgcHvLUgvD44dcfvV9rp4+Zfzah7r+FOGRd1zePuXxmw94tBvJS+L1q5c8fu8J4+Uef3HJMk3kZYFx4PXpxLNXr/jVmwP84Id8/Ow5xZqB/T3q1PkXZ/84u7+bmd39atz94/wVrZKhf7cgelVJu/f8nfVoqAqTa83Y6FyIUZuiW3N1amaitSKuINVDSOt7Yc+1VF2vNFYS7aPwum53Xad/gvoKxejprMegb+qF5uGlQJUndL1+XRXwCmZp0OayJkmmGee8Uu9LIeUFXNBKgNM+xLTMus/VYiNXVvNcnDZ0N6A3GIW+mR226nNBAZ7qFbQqLTrzyhIIKyV/SzQ2wz6tQrRnHL0F43mheE8JninN2kuRErMrmnjNk7FOIj6OdP1AF3t8DKuH1XQ8ICUp0OUFVwt1OZqyatZm+lrxteDFmvqdt5gEhn6kH9Qgdzoe18rXUgq5VCbzbsNBOdWzUVS1B9Sfg+IGhp0xc37T8d/DBUopQet4ax8ElvnK2Tq1ZZTt9SI6MBuijqCKOhVT+RFY5SfPS9Qa7FXXrsdBiEpxQRDXXC3bguusrGPKD87hzhry3v4boDkdizQ7d7fya9dNBFkRdk1Ytt9fKWVum+QNHXMOhpaBO1QGT7Kio85kQl1bMKwc1RINUX3shug0hEA/YPvsWoUlVHJVc51/82//O2If+dmPf8LTd99nP15oidhpw2ryULtA3I+4onrwEqwnpDqc1/JdoFO+XyksJdMNPfurCx4+fcJnL3/N8eR5KYKEPaXrSY+f8NVvfJN/8O/9I/7L/+yf8urjn5Ne3cBkQZoDyZlynJhf3+J9B6Fj/+QDxveOPP/+j3jd93SdEENHN44MV5f8T//D/xA5HflX/8//O/LsM+px0gQle83kcyLPM8dwx6MH1zqxS6HMJxYpTIvn5s1LXt/ccKoLi1HoSrGkdN1kWSE8ddTcSm5NElcDRDMZ8mrgFkJWlGat8Ol4X7XN8Uwp43LFTYsl2kAIHJcTUoVhf2mLQ2XoGtrn8H2/lrW1iV2Tly50qq6B9lp0nbfKtkrfNeSqqe2o34ya1Q19T++Dadp7Q4CE2A/6O+IU3ciFZU5M84zSk0bGLjNGIRRPFNPFl5aIaVKmQUQloj0QSETppKIN14JKXThLxFNiIRAJ9EMkho7Hj58Yt9uCcNtwSjVHGqc9VIhQcsVVRd8OywQ5gavEzlGXwpwm+mqmRi4ye8fkHIfbN4zDnqHfs99dqJHe8ZZ0OuqiXTPZ6eyvZYGi/WapaGNfkkroAp1zjOLJrZ6TK6fjRJoKp5Js3ntShlyE0yx4bzQ4SauOexh2urbkTDHgxEnV0vwXBKq/PfQ4j8uqVAOv7GdrlVLnQZODFlZA+N47SD0HwGxPOkPzVunSNdBve2JgBTntPZtYAZaMNnoJ6xq/Qlfr/gHbHrK+tO0vZoK2Nn1j8dKa9LTPe+v67Rzc2TWvoPVaYmjA2f1b4pz5B5mfDqJN34dD5XQ8Ms8TTXa31GrGhh6CJ4SeVq4vqSOHhTJbU2nKKn5QlDbYqKQxbqIljcITTFIbp5Kb0/HI6XDg2ce/4Hi44+7uli5G+hh5+M77XD18xO7yCiSQlsycM8+ffcqbV695cTjRzwslJfqcCV0HwXHsIkfgkBL+4pLaOw67PUE80yIMXSVVT/YdznX0lz3vX17z3b/1R2Tn+bMf/pC76aQU2Rboy+du5+e/cQbI/tXHOhp0WLpt7LSv2r7S7lvbs1pVoNpzqgilasN4zmXdt3JR5U4cVnVwOAJd6DQQDlV9OIJf5cq9169jVOGQUh2dJS0qs2pAv2tbXlOd8tS6NWNrM7n+L5hpXfDOAD2Ht2pLFUdK+WxvWhDUhHYcdgzDaCqhZ31TaC9rlW3G+VYVb2Bj1ZjAAz5ob1xBgehpWnDuSBcCzkeuHzwkmq+Ox1kPiM6L9qzaulON5ihSKMtCTQuSktKwU2LJM27Rm+RC1J5MH/Bh0IRgGBFZWJaF0+mOPJ2QmvAlE52B2UmN91SBVb3KionAeOfoLDGTCnnJLD7hxHM4zQjgY2DOlVSKxim+gSRFxWJCMPNgUUZRY9VUXfb8lxjAXz7RsAVpWw8bZ/rzk2ibOnL/Lzlb8qS9X1tEBfFtINT1PTwbr66dRtNyBnPgNh6trudiCMFZDwf3P//eZbltUGw9KJwt6KwNThva0GQDz67YBnFDuxrmtfEXV4KOqnNJVUfqs/t6ftfOyTlnH7ztIc6tC0uj73jbdN68ueHZs0/4wQ/+gr7b0b/T01uwQ/Cqzxy8BnJzwYeKD2F9Di0bd84Zx9dr4/DQM+xHrh8/4PV+oPSBGYcb97j9JcN779E9eULte8QcN70PGsw6t94naepd4oih58Hjd0nTwgff+X1FjEVwMZKrNU9fPgDUG0OcIdrWaFirUHOlpEwyY8VWwco5UaVwOMzc3Lzm5s0bbZLDqvrC+txW6p7u+uttl1Ypo4F+pjThWh+E28bKWVDTjO5U5lUVU3zTuTZZaBcjKasWtZr+ZSiZPm7NzV0/aBOcc/jotJG8QhcVNQJVg4nRK4cTtLnSUPIWOHm8Jt823kspiCWuLliz6toiKgYAONMTN696o45VS1w8OobaaF8b59v4bNP8rJRdvDVoB7dWOJ1FaGp6qUld3w9roiGt69YQmrUy6vT1pVRL4AspzWhEn02fXO8pADUgoSmAgZSyXl8XOlKaSelEKQtStT9DlXpUgrvNwdbUXyt0aKl/N45q/mXoesnquFps3vkQVUgAR65GIPMgVZ+99wZpOMAFYwKjdBL5kqv53/jDwK4vCN3WSoScBWjnYL69rnlmaJ5hAFW1Pcbdf7f2WQoGnVctZP0c3ZRWLFjFJ+xfZ+nA2d9nZ+O2zKVVRmBLNNbXtFl7Fry2k932vC2R0V9za/DXkpltL5d7qHjrD3EWgHZd5PrqkuvrB1xeXim33szcGl1UfEuNPb4TVkoJ4LIZj571mJSiwhA1bcyJaAmG77rVDyQtC8vhyHI4kE8nZMkEPLtxzzCOXFxd0+8uCFFr7bVqxWueFuZ5YUlZaSKiNN+2X2QRppy5m2YeWJ9B7QfmCjUXZMkGeEZd92LHru949933ePfZp1zs90xpIZlM/9tD8HyMrY/5reM3DN0vftE6VM4T321MtGRtyybdPTA0mGR3tOqD7k8q8OGcVq40vqvUEBRkKYUuaKNw10dCp0wQH7xRpZw6SseOGO09nWFeLZ5z7Rs2psTCda+V91orJVel85ooTjPiW2+BgXnnFHipm7kl0q4xmM9JA8RXuIDzqQKyMlBwbo0R2nOrVSi5mGt3YOxHwtpJzQoClZLXuETOfHFaBT5bolGT7hPNM8OvPmqWeJVCKa2FoBKC9kOlZVLVJxMhUGGhimuCS7KJAogI3mkSOPQji19MTlr3puSSAn9e+0LF+iuziFo+2H3WsSQb6HeuyukwkPyvB8G+dKLhvTZLNmMRvcf+/uCmlae3wOscnVk5hB4wmctcjb9JIaAymeIN3xcB1683z7XJZYu+BpNmJuLtJkgL7u3F9gxXVOita/LWOKWXoOfaznNFm5xy9bxz+KJowFIVxV41y01RwIWwJWI2iFtnR6tbFFFX4NDZZtAyRKdUsIKn4pSrJ+332/lYrwqCkNUp2UHKiT6oI+SSJn7x85/yf/jf/+8Y/5cj+4sdYX+J7xWFWPKMD2rCVlEb+d0wsswnbUb1EXERMHWhKAweJAWcJD789jf45Oc/ZvnsOYwDuyfvcPH0Kzz52jc53R34v/yf/1PKz35MfzhwQSAHSGggWKtQxFO7jjDsGMYLfvd3v8u3f+fb/Lv/4B+oA2bJJIGf/OWP+e/+5b/mz//iJ3Dzmun1iZBVhWwW3SxEhDRV5lOmMClqj3q0lGUilYWPf/0xP/7Jj/j5xz+nJlULK9WpW7tUVFHG2UK3UeWqt8TQW5wnkMpCXdWMNJguKI8xmKKNJxBdh/Qju30iesfYR4ZxZH+xZ7CGL2JHJVFL4nQ4Mk8Ty7yAU4ftED196PRzl8VMKYUlVerocF2kN1RJOa/ZFgdLZGwMRq9VAvCknDmdThyzylXvLgYuLi7p+4GlqLJEdRlfe61IdCOOXgUejCdbAV89jsBgDXzOBfSmiCFQHVKFXBMuaVJeilCXjO8i/mK/Ciz0USUM9cGpRHXshjWhyCWtyWkpWUvOkslSVNIxq58HCHk+Mh9P5HnBifJUQ806J4No8ls1gMu5kmSiZrHzm5jTQZGiYHK7y2IL/5lKnctUD4RA13dc7Ebef+9dpuOReZp5fXNUFZ4iuN0e30Vi37M4XQOq7ZtVRJUCbemiLKpQJaZP7pwmqS1o+O3xxccKYrQdUNZgA0vYV+TfipTSOlnbb5xXNNEkuNFaMTDrXhC48uPvhZC65dQNvNiS0/XNOYegGrghroEZa0qEfQCtms5ZNeb8aImCmAzpWjn53G3aMot7odsKktS3Xg9NfEEDsML+4oJHDx/wR3/0t/g7f/fv8t3vfpcHDx7Q9QOlKkABDglx7S3T3rRKqCNxHDVoTZk8z5RlYb47shyPpNOJpeRV1GLoB6X0SGs+rkyHI9PxwHQ4MMSe/cM9/X7P5aOHxH7AhUiqQsWRpO3njlQqKQsli1ILqqMWsQRfyEvmcHvkxWeveHT9iH4YifsrjqcTsiz02THsRlXgCx2xGxjGka9/9HXevHnDV955yul0ZJkmqvv8M/rCB3fvZ1/0Q/nCl2izsv34jPnRglyw3obgFemwmEnswfsQ2O33IMLQd/S90p2GQf0oYhfp+o4lJfWBmWfSNKmkr6jKYD90q/lbyolmOFkKeANHgvUJ+qB+TqCAcfO6cU6rF52POB9JKXM4HFnmGecc425g2A10IWyyu6JzzofAOCqboIpVYOweOKeeGUPfWU+IlVXa/bM9TBk21c674gP4qjPIx87W3aBUuKIVdB8i/RioBmSllDb11ZJUVrhkUjLSuYFvtRSOhzvyPJkoiPlSSFWDwKhJ9VK0ZyMtM1IWSupBVEmq5kXnkzcAPqshp68bwF2lMY+E2Pdc7Pd89b33OB4nTqeJl69uyKmoS3hUd/Rhvyc5ZzR5pQNvnRfaj+PqfdtocLhglDO/gfq/6fjy8rbrmulV/kxEG1L85j2xDnj5fKLRaEnt6xaMt0AdWkNRY3xZ80+JeCtde1/WCdfK2V2wDzdZNn1bwVHaTmEL7Bkdq6VHzhIaJ9v3Wn7WNikczuv71Ko0hghQnTasnekhE/xGwxGxMmHbZOyz2irvHduyvqES6oCsE1FEaCzD1tTjnV9LoIgGwN6dqRP4wKkUXh+P/OrZJ/ziFx/z7rvvcPXt34WovHA3acNykqrnGKNyZMuIcxXvB5WB7QRR5inVVbrhAWG/5/2rR/yPf+97zMcDg4M3r1/w+vmn/OBf/tfMz58Tf/2Mi7s7ulwovnJTK0c8F1/7Ju/+/h/w4d/+21xe7IlScOlENI+U7Hpi6Ahe6PJMfX3Di+//Gx6Gjot54d03rxV1roWjNfmVnIlAJ0KXC25Z8CGwHwfeHG65ubvlL374I37+ySe8OtyRpJj/iaokOSe6kBjy0xw9AdWiBlSCNoJUfGyJp+C7npgTsWRi32lPgS/gtFdhGAJeRnLQ1DCnwsuXN/hwR0VVHpblpJWXlMlJ9a9j1IV8vx8pXtmhtZYNHSGsKiMl9lTxpCw4VLFKnLkfO6/O1iaTtywz03Ti5asXpJQUpfCPVDrQJCYdHieRnBeLa4LxMt0mhYxWQ7LMTPlEFXUEj67T6p9T1aUQVWVkHHoaL7j1JrigkpjNabkmXUxnZ3OlCnlRXf6ypC2pFy0Pp7SQykkflfMsWeW1T3e3ZqrXUB0tq4dxMG8bENRXYUkVHwohLJpIWSKspXWlECdLRglG/WzCEKawtxsvuNxf8uD6CV23J/Qnbg7aFzLnBTlooBX7nlwXas3a/GoBpPdu3axzMaEGKVRDt/KsvZj+rCHzt8fbx7Z2rwmBMzQOtqRAI/oV2W2R9gaFvVVlcA3c2no21KdG37eu6/Z5yrL9fT83/IJAsu0Vb+UFbntDpei2X3Vy/3fPcXIDiteXuO3tz/+93oeWdKyJWfuc9U7SXqY9aB3vfeU9vve9P+Lb3/42f/8f/H0+/OqHfPTh18B5pdysFfpGRzbQZg0QwJmvgTeZ1dIPiGysgjxNKxLcqoPebUmZx9GHCMPIEAfiOLK7vibudohznJZEbomhU7pmyoXqI/1uz+MnnqvrB+z2F6pmaQDmECJDiHQ+EPDa7zaOlDmTSyKlSjc4Q9m1gXyZE33Xsx/3XF1eEoOVm+U88HL3vtqq4/dHzL2bfv5cz1+wBtvbM2oxRYu59M2VgpZrJtQN1dfYTKmAXReRcSQYdbbkzLEoCCUIOWemZVGUvhSKqSWF4Oj7yG4/EmOLb7QpWT/fem1okv22bxiQ55xTQ13ndY+wQHWeE8fDiZcvXpByIgTPw8cP8Z0n9p2dt8ZSKWdNNnxcxXm2nF73ypwzi51/80wLMaxqkCpq4hmHUUHFKgRT5XJOxUH0e44gFXJmOR41RsuZlBT4U2C20e2Lyp/nRFrUINZ5Z4I7lXk6rntasNjY+6iS+GZq2aRrpVQN/GvFoc+s1GweVdB5vyZdIhswUUWfiY+e0Qx2rx88oOtH+nHi7jhxmhfmlKg5E0pmqZUpLWrN4FVWX6njzprBVQintSW0QLsBhZs7/G8+vnSisb6VLXAa6Na1zHmekZ8P+nNq0tpMXjdy1UYt8uun6GV4GwCW/VLVH8CqG+3zNFFpJW77Zec2VQQxeARLNli/pE3QbQW+N6vPEDGd0A0R0AY2e/uWCKwlPkuyaE0zDW3T152X7be7YPdCDOVswZbISt1RJWV3D7nwoKVHQY3Q9EzItTItCzc3N7x8+YLXr17qHhANSYtKk6qCyp01vmVxpqHdqeqBQFWRXYRK6CHES/qnX+Hd3UAInvz6FZ/85V+QDgemZ5+Qnj1j//I1Y1VFo8UJc9+T+pHHX/8G7/zON/nK73yT0EWomTorVYqKqQ4FVapwGZlOHJ9/wkRgLJX9PDGJSp42hLJRlDwCWRdFvDN30MrxdOIXv/o1L16/ZkpJGw3ZlvP2hBxtUWxDQZTy41BPBRM+8GelWBciPnbErsdHRZD0eRXEebrYQQy42ikfMyUOpwnxUGthTosuPjnjBTW7qkLfRUoZCEHli70FOC3RcK2htQoVD6ILQkv6nRPlfLqgfTC22OecmeeJ4+FAStobMF7s1LguBFzoNGdHKDlZhuwpXk20Gl9dTSc1mJ6WEyJaRYo+alTslOIVrXlzv9+vFCuRgFRHycKMNZRXrSqVClmaW31lmWZVrMmFvleTPYCSF9Iyk/LJnkmHOC1Dp3mx3i9diF1wxn/tdM6Z86rUQjHTTxHVy9KEXhvbg3cUZxKKaL+OawCCrWveKf1A5QgjLnT4mNV8DPMKKippW2pdy9Mt4GilaUFWpRRN6Cpiz1V7Zz3+t/K2v/GQNWA/SzKkBezrhD5bbbev3HnA/rbD7Ra3vbVWbF9/botd95AtWbCNgnVPeWuf+dzxVhKxXsK91zuc+/zvfl6i9/7vnF/D+enpX2fnub0cJ9B1HU+fPuU7v/u7fO973+OP//hvc311zcX+kiktmILtqkjTEo31AqTtWbZmR7eu33EYLJBVHw4pBYquwbUUMm5TuhEhOE8fI9IHunHHsN/jup4soj0g7WTsPJpEeuwH+q5n2O2VkoqigCLQ+UgfIn3o8DiCs74DH8BVC2TbTqEeT3VJ2oAcO8ZhJLQ14t5xL8D4/LP+3Gv/mtedJ4QOi6vaGNniJx8joUR82IRz9HJ1H1HefQCJzNNEztlc7DXBm+aJeVlUccjWS6mVrgsMuUMQ+iGu4HDr02nB6eo2bvFd63LyqvetFXhaEuS10XmeOBwP6l0RPMN+ZNiPxJw1+rJEY0laBvaeVf2wNgEiEYolAvMyK+VOhNX4zvb/EDSZ3O/2ayLsTFgoF6VK1Wpmt6LJy7LofcgpkS3REKlaNfEe8QaCzTMpLQCrGlet55UfHZ/BOWMiGEW4gW4rLbzYPbW4sep1B7uGavvReaLRRsDanG4U9mB9My4EZWFUTWQyUHAkk+pf5+o63EzqxZK11epPA1FdR/6HTDS2cd7kN0VRvqgDvZZKyZu2ckOBGi3JG0/PJOJXEz5vzpoeQcJZVcIWvVpapiyq1c+WybdKxdYcp7y01ugDphywZtuszbTtfZx9D2BVKMQkvVDUsm0QPiiK7tDSnAYzalPvUeJ3ey+daO3BWaAIWu4ymctgpnZNvaEFedgDX12NnVZ5HMqRb1ms+kvoYPOl0PDa6BxShDd3t3zy7FM+efYZfRwViRFh3HdmPFPwWSB4Bjfi+kLJQkmCd6ag4LTq0fWBEgsuaN8AJKY3L/in/9v/DS//9C948/2/5PpXvyDOC3HJ1Ktr5tjxLHoe/60/5L3vfIu//T/5D9hdXNINO04vX7OcJk6HgyaA3tMNe5Ve85HeKXUu5UryHbPAnUARoXigj+weXNO/85S4H0lU3ty94atS8L5TtYgAU575b//Nv+ZwSoTYqwqX3a9WGWt1AkersNk9bcil02Yy5x3RRYJTpaMuRhhHYnQU86KoCFkKQazZrWYkLzx/8RnTvDBNiy2alVo3459VLk9gSupALXlmtx/ousgwDNuGYX0v4Fiyqqb52JGk4Jxj3w9Ek7iVom7my5J5+fqGw92B41Fd2513vHz9ijkn+uPA8aSLIx7Gfo/zZhxYtYn88uoRyziQ+8B8e+T29pbXr18yn2acwH63JwxqrKSGQUJw8PjJYw2gSyEtlWXJ3M5HTscjy7LQRQy1KRyno6FombwoX3sYBpwvCBEXYMkTczpSU9KFxCVVjpI2n9ULRCSsfTTLohpiK0JjvRHOkouS7nRsidBVVb4LXdQEoa13qARtMHWKWuDueOQ0L7y4ucX2KZZadIx2mryDI5dCrUmTGlepRhEtOOXEWrCs+6azvhYH4klpRpa/fjH/m3vI+qcFXCugxIb2ro3Ra+aga7X+ytn9FQOgxNDidaeQjQ6ESY3L+iv29xYsnnX2qQJWO6czQArq+rutUrJdE2uW0XYsMXBrpTFIXTf+814Kzs5nTSDcxk53rtEjzu4dZ5UhLKT2jt0w8M6TJ/y9v/f3+If/7j/kb/3R93j3ybvgIEk2WdstoUOUgqIAQl356Nn2zuADYuah3kfG3Z7oPf0wkI9HypKUrnM6UXIhT0c9PxHzJhE675CuA++YlwXvjEufZqhWkcwJlkSZF7rQ4/qR4XJH/1Ar89l7pWoWrdhcXlzy5PFjhr7He61od91I8APOofRTm/clF1LRhvZShWEYjELq18Gwhf1yNhLOxslZTrglvOcvgntVLM7HTfu5UZVMMMQH9XMaxsF65iBYA7fzTvvEqtLhWjB7++ZG6bSn0woMl1p0HTYw2SYRVdRrSr2lBrouMI6qlOScApPNqyNXVQP14hAXtN8sqJdUDAFXlVKU0sKrm9e6N9n674Pj9ZtXLGWhvx2YFpMRxzH0e7wLaA+OJhGXV1csaSalnpubVxyPB25v3zAvE87B5cUF/TDgg2dZFu01ipEnjx4SnCYp86yViDQdVcEsLdTodS2uhWU6UXImJxV00TER8ONI6DsIUBdVPitFG8NbErFaIYSID9Z36AHvyPX8nstqHKjgU2UxNkOVokqYXi0IpMg639zba0UVjtOJlBfu7g6oTxSccqZ4j+8HJGtfVE66L4lVps4tJlaRJ6NnSWMmyP3x/NcdXzrRqFVVnlapQHTBU4UomwbOGmTDRpHaKhvboux9WBtHm18EvxGxE95e7M+Nlr6ocnKuLHX+8/sL/Pbu5/KI7Vj1m50j14wnqHui6KaxqQuxogXbotA+n3Vhb/9tSOi9h+ScIgaA4LcNwVBspFLte649eNyKzp9fzDo40GBKdZF1sMawNeTR7qZ3gEd6DUzVjKOsZc0+mtSwVE53R3LJOEn88off5/nPfsyzf/HP4dkLLm/faPDuHEs/cup6woOH/K3v/REXv/NNdh+8T5HANCWWOVPmCWpi7B3TokFlyRnGPW4YyJ0jXA5cvfcuZcpM84JPi6LDUllS4TRNLIfDNu4cZsoo+C6QS2FaFuY5katKJDS0ZbsHW7NZ+3sLTEz9i2B8RFPxCIFoZdjgAy52KD7gbD60JjXFAMCbyoeWdHU0m5FVe2atN2QdT7bw1IIrKsMXgjZsFwFf1UPJlwrOm0pHWJEMZ9KBtRaWeWY6TdzdHZinSYMSH8AJ0zThgifVgqre2tz2geq8eWioHndKM3dv3pCnE9PdgdPxwN3tLfNiyh+xVy5fcarBXTIO4e7qQnswqnA8zuRUqEWoJWkiVh2ltJLzCQx4QJJSqOaKrxmiNiBi42Doe0KI9F1PNenrceyQGpHqjAbQgp1si7U+J+916YtGyWr3OqWKr4Cr5KrWo40q6vFrgtdG0JwyvigFqxrypJWZSnbq+EML4AxsKG2MrP97a6Nw1syJV4NFWmD82+OLjm1vavex/aQlDLp3uPMgn4ayW+B+du/bVnM/92i0KgExmsMXoNfnfRnn52G/dvamZwnJetI2Ts7jSLkf/ENrqG3vKzY+Wb93jnCuVXzORq2TVaABuNe02irF6810jnG34/rBA772ta/z5PE7XOwvrPl7q84jmMmoBVSmj+2kIstCmmdde6pJNw87uq5TRTWnzcl+HIjBU1OmpFFNQ01RsMyz+gQYUilVKHlRkLJW5b5LhXlRc9AQTfKzbPunVO3hq+pX02FTzqkz8m438vjJI/phUJU4UJU8p8+6oAmUM18QVwtkrcDUqr2iPnrcmdjY+XEv2XBv/f1FUZuNi/Ul57GOvaAxGgCT6dc93odICMXkgvVCi1Xo5SwGAKyfrCqoa1mqotugGPbZ2NMTUQf4kile4yff9qZacb7iS8WFqs3GTqsHul82p25dc5d5ZjoeORwOTPOkn2lg7TzP4BxLynbezRjTKLwGGLlaWdLM7e0bUpp5c/OK6XTieLgzxUSIcaD4TM1wOh6UNRE8+0H9qByO43EiZzU91AqOfl1zouSkgE8piORVqbHUTPKCSMIFT80Jb07nIUa6vqeKihKkrItAFZiOE00WvqQCBrSB9mB07swzCix2KNayoGpYunhpPNmAhhYtF6d7Uy6mkmhxT66mOIapaklbz2wtrHJGtdsSzKZgdg5qxNhtse9fc/z38NHIWExK6/SHxuViOxFnxi8ihmRUe902aZw2G2g2XhsC8HbOb0dLYs71w600em9zOPv77WRjfWBWYXk7OTlvBm8bfpPTa9UanCOEDWS4V7Zy9+L39WjUCPsXWsJr3ftbkIFdkwjGt2pLuCFqtVqzoA2jdr+cP9+eto+xRKhU1a7JVBbTWA4+rNQrJ6KJhvMQOnwn+CJAUudpH+j7jpqzSsndHlhOB9LxNX/6//ov+Om/+pfkP/sBj4rjgXhmEeYQmbsdx3Hk4uEjfu/v/n3i03fg8pJXdxPUQqiV6AoxwNAHjscjyzST5oV6NSN1T6KDIXD13ju4mxP5cOIwLURRt9mUM6dpYjoetOpjjbraDFVNsi1zmmblW9q9rXaf2z1sd+5+oGGl36apbLzcRpvagnlnC2xcqXqaMHhTcWq/rzSeWs+ra5pstMlbpa7jofVWVUMDvffWjBxMQlATjVrRngHBFCZMCtdkoEVMcWWeORzuOByPmsyZXKpIZVkWnA/kIpooBK9zzRKVZBu7r0JOM3dp4SiO6XjHMk9MpxMpZZwP9COIU3nE0+GOnDWRuL3c0cUO7wJvbm7VP6QbqSWpsWL15JSZ55lSJlPC8jjUBbUkRQ8lRKgaQPhSGPcq/7fbXbDMyql1wSPFUwrMs70/1bi6GhDEaGomHtN7D5S6kJLgclnnUxZZK6M6N00fnQZqaOKIcwSKjbOKC50qUyGkFSJx61JQBYKcJbmWbDb+cJOk9D4wdqM1Vf420/hNh/oqwVoFbj+wPUpo81vBo5Z7NCPWdpyDUfpQ3L0KRQOh1/W2xe3nQT8NfWJ9rmeR4pY0nAf0nANEcm8bvJdkuC1Z2t5J2qmuycy9pJXz3KZ9rmzXLmef2/pPzoNgp/4519fXfPjhhzx8+GjltcOmuKNeDmVViBOpKqBhFKN8PDG9uaXmrIHdfoFhQLqOrjfqaacocx1U4CH2SqnKpyOzE8oskIq9vylU5YzPySqGulf6cUd0XhONkjXRkIITR05KZQwi9GzX6Zyw2w0MIahLslT1lLBEo+SqrshScNn6T6QiVn2tJYNH94O1N7Td27PPaU/zPGCQVlfa4pLP5apvgQ2aIK+pL2BeE173m2bGF2KnIaXDGqqdjevt95qXgjLSz6p4bSzUdl72x551LZXqCyUXe62gLDXR/aS2uE375JohnwLLaB/INHF3e8vxaCCm92ZvI6RFqbUhZeIwKPAb7Pxp1RllcqS0cHtXOB49dzevmW1vyibpLmNY79bpcIdIwTvY9YEudoTgubs7UivE2BsApkBTzgs5zZS8tIWD1shdENJSkOLxXaeCQFTGYaTvB3b7C3LR5CIXZzLvlbxktQ4wABLrGfUeMzZ0ZnyosXZOAqW1LDQalfUE+03tra0JIpUlF7wr5CKkmq3XMGgsAtZ922Ihm1MiKsqE38YqrKpiLe72PrDb7dak5K87vnSiEaIGYA7ZykJA4y/qDdbyWUpbkL9OCmmcTUXISy7aeGvs6OAdxSoVWuKzBdQ2B8vr1qSmJQitybz9aZ97ryfEXhtCu1ncO797vNaz31GuuBi6iH1e44adh/fbIzmnaIGhRc4QAmMsnvcB6B2xKg/6Woymob6GYs3oW6Lhg4YupSb9bAGnauc2WPQ+lpw5HY6c7o4E1PPA40z1xriDfguwI4q/j2au6IBpPnF784bPPnlGnAvl7sDNT/+S+d/+EPeDH/NRFlxOLKVy6iNy/YDLr37Iw0cPySL8Z//xf8R0XLSKkTPjwyuu3n3Md//h3+Pi4UOWq0v+7L/5l/z644/5yb/5U4a+Y+g73D4iUY2c/vE/+SeEVPjz/+qf8+IHf8np1Wu6oacfemQYuL7cE6JnnhxEnUDHeeIvf/Qj/vTPv4/rOupcWJaiZd+zylejL7RmZdsj0HShR8RTq8c1o2sbp6kq+lMrlKQKDk02ENTTohhVB7EKmX1GCFpNaL0NbVPyFoxqdQREnCYYZgSnZXBHHC9MGSwwDMo7LVkb0Sx7t6aywjyfmOcT03LCd0EVkHxYeZUCm+t2UK5pDJ5Y9Tou/IhQcE7oHEppKgUk46USEJaSKGkh52WtZua0gGgj+5sXL1a05e7uRC0QQkeTyitOM3jtBgramDidwJyEg6vkmixZiKzCDpIpeWY6wrKo30smUYvS1kqdcQ5C0NK1twZCTcAgOFRS2Fd6p43+znlc0nU/4+hijwvBnMYVlSrFsUqfBp2jbXGXUsl5tgVcS81t/esdeDy9irUrWjfPuvl6T9ePqImWVjVjCFxfXbEsMznl37Q0//ZYA/+WHLACKRbVWYTUwCHW17TKtFaazwK8s8rEfQjs/qba9phmBOgtONkQjPb59r0WeMrn3gpLPc4+S9r/P3e966XZ+yhuIhrYOc7e/3xvst9t3zVkWhOK+4GxMx3tlBSpH3Yj7zx9ym6/x4VApjTYUOmfJq+p2tFiPVBadlWvoww5kQ8nrbLf3BhzRPu4QufxUfsdYohEo9d0zsMwMEav4hd5UTQ9J/ztQcu6JcE8a49HztQ8U7qemtS3I50m8t1B/bfQRmetbAiuFCRn6ukEpRCKqGGb81A9WTJZKqc0s5RETIHL3Ujr9FuWhePhyKvPXjHdnciz9mht6enZ8zvPT2181faMZYsdzl97b8zJ9n4GRK/7uCoBqMSwGIIurafEQDIXWoCOKSqySZDb+bh1/tRt6DrrNcCZeIWqfYZgPQOhrhStftip23ffE6KKgJSi6zNkTQatuXiZTkynE9NpQo1gwyZJC2vMFkKg60caJcv5aFWwoCAwOu5K0tBZiqkNSiXlWVVCp8kU/Bw5zQYuV16+erGKDWiiUQmhoxhvfTd0Kr1cyjrOxWRpEaVXV0mkDF1ugIfez1oKp9ORac6UXDXRsKb4lBKNohRa8F+3qqJSmHRviT4QoidIJBcVzvFN6dFk6yubZH9bH7zoOlYo5GrCK7SEEjMhZQNGHRC3GDrnbPFAYBxb07xStUOMXF5eal/PFzCC3j6+fI9Ga/xY0ZjzhdymQ1usOE8yWrbUXmObcgvnbIHcuKJgLipr9cLjrJLiQDRROVe0ap/T+keaIhPCOmhb8mB3dkVxzjGBttDbS9bvN9VnJ5vwoEjju9pAXxcRU406o4LdM1Jyxow9u2/aaMO6YTWFBqgtN7OP2M6uVbWgLThaQm8RqTh939s3b3j54gWH2zvcpbk7N1TMEIv1fc82wzQv5EWR8OPdgTSfGOIO10egqmFMSowma1er6GeXomXu2xstQ778FH9c6KaMSwXSxOyqGTdVigh3b264ffkCubvTHpvg6S56JCql6+YXv8AV4Xh7q70LAlTHftxz8egRu16N61wtUKr5MVRevnzFs2fPNLlDnUKrZRKyPgNn69RZImxIQRsjleZWv5Wm25iu9vP2MGyNWd+7oQRbUFMNWLSxsz57nRv6W61sbRuE9zhvI61FyaJx+rIool4lYVEvgi6EtVZymkl5IddsY0+R8m0TcasTaGg4RlVjn1ZzayXeU57XYGI5nchGichJlT0kV7xa3K/Ng1A5TafV1SanxbTtK864w10XVinbJbPR26RRDcM6x5p0KKAbSxEWtKysvU8FqaZyYkJ9bT5sgIdb1ymcIzgYQkcUa/5DVISibmOjOm9JqKJTGK2uEQtq8wpxrGIXAqZSpefQZFZ9bMijI8Zezca6nm7YAULOiz47ija9m8zkb48vPto2cF7FX2EgW9POg+vmqPw29WkdWS3YlreTjM8H/Z/LF5zTfMadAVFnUefnkob2GeubnH2itMqFfm/b7/RCnQWbLbZZd62zpOM84G1rU3vRtgeeA23tbbbekf2FqiqNu9GCIutVcRqk2EQ6Wy+2xKbtk21vc2D7xUbJLAjeFACTBTFd7AhdvypUiT1c7zHfn4jvjIJdVDK+1gxp1vUqK102zQvpNCPzjB+gC4HoPcGB5KR9INNMvrmFosaf/X6vNM0Y6KKqbHad9vY10LDRKXPV6vo0z+pjZMDi25HFvbHmuDc21nBlfc3ZoD0fKmuMYc919WRxNLWks7TyDHDd3rXNjPZ5a5y2vv/nRugZYG1UeWtwdtYXstJ0TQbWuQpOlaGcb8nO5sUkVRONNM8kazjHOZNF3+RSfW0A4MagQaCkbHYDup5LrQpSSwXrpciLCoaUJdm+4ICy9qk00HieJxqMndJsnhl1bVgPYcC5SAPYlS5lqOM6J2WN+drdS+aVIYsnLXkV9WixXa2WlHibyLD2cYlN1uDVS6YPEfHqaO5NaKQllC0CraIw9pa4tqtqwLNsca8YI8fGjp6GAibB4gFBZdi72NH3HeMwIFVUfh+tHOaUTS3xf8BEw9VNvSCYpKwr2rAo4tYGbOe1WQq2ibMGdOv3LFteB4+qsTTZqHPEv1ajeojDu07Vf2pZ1QPaHNDyX17VDlZDMb6AdiDQLFl0TbUqhcPKUM4WSAuzvFcZWbZScS6Cc2ULLNeNyzayuiVeOL0hzhrVC7C+gG0TcKiPRhZDOqp+aEsI2qvWDdHpz6rTUDAED8YRdSj15tNnn/Lzn37M819/ivsg0FlTsTisP+P+Rqkl6czh9Q13r17x5uaFIlN4dg+fIH3gzdVAPwSG4OinjCuOmh0ngfkwqfpUUWflh3mmr0IMMGVhShOn2zf6qL2e7+lwy3z7hvf6gatSuajCRQncnWZenF7xb/7pf07FcTrMdEvCVaFm4cH1Qx58+BEXw8C0zMiSkcUcp3Pl019/wsc//Rhnfi9ZktGh9Jk1nj7WmC1SralNPSKyLRzVO9OLjtrwZ4tDS0KqCR0on9oMJi16b5O61roqTpRarVKV25ZBCJ5WFsWV1WE3xKDGSNGpW3StlOlE8JESoko3Yjz1Np4kk7PybvX9TbPbNCO8eOs5cUgQqAUR9bFR9S9hmU6mqBKpJHJJvDnd0nlPwHG8fUM27qoQ1jEfurAKKFRRz4uUlA7VOa+uwALFVbzvCSHQ73ZGQyjcHpz1imicr+uNSgvbUqF2OVVYJGu/Tk6Ib+IJZ4xioymW9syt7yVYr1IVnZPBRy6HkSpVqzNB9eBdcWrClbI1walXiFSLDp3KRGPPFq9zqiFFIpr8egmAKVM5R+gMFMAx7np2457Li0v6bmSaJ16+fE4u2QKmfC8g+O3x+aMlGCvtpy2OLfFwm9zo6ln0uTdpLzAAYq1ofFFqsX3laLuWncg5d6u9F9t40OqJbe8tSAGroLizGPMs6LTXN+pCSzLuZzj3z1HEfe46m/fChp5b8GHIqqLidhkW/Hnvefz4Ee88fYfdfo8P2uemwnbbvqT339t7OduX2qPQ9+m6jhpNYCEVJCVqyeS8IGlC8gylbGpuXa+qfrud/ul7+oudNjf3ATd0quCXqprQSmZZTtQ0U52jnI5Mc1IBjqrJwn43sB86huAppyOn16+Zbm85vXi1JhqXDx/S7fcMDx4w9j2xV9nwlLQqn60p1yHkWlhy4ngyfn8FCetTXZPWeyPnPJ9o31ifCfdAxPNHeP6tra1fn5uCUWf0mWrjrTUWo2tTG9sbY2NTEqxigb0JBbSeMo2H6gqUBaf9Fl3XE/ue0Jk5ojhtps4VvyRiTLp/ruBeSzR0ECpoqEG/C34ztTWajqo66S9q5QKrBqjoSQxNqamyLFbRKpk8nVRmtilDoXu41Gy0fWtor5XpZHEtrICZdxXnI7GDYegtPohaCSlKdQomW+vDWRJkJ1hFOJ20Z6hkM17FE0LXCn76fBpTx23X2VJUB8QQGfuBsYu673eFJWdyFZZcWbL1W4iqFIpr8vx6OsHWi8ZwUcVXYyDVFt86VqnhYGpuFpxX6diNI/vdji5G0pLIydTJSuV4PH5pEOzLJxqu2dk7Gg2qNjTEWcmmFGsy67YLO6s8nPdKtAHegudaDeVbsy0NtLzXTLFmYWKx4E5w4rfFV1oZ0JpiQLPqNiFLtomvXHvntoYtWVdtjOawGfC1Qywj1rNtevaVYjVyQfne+G2j06DHr3teu65SBXEOcRFvCYGqzugJ1dIyzjMKQK1rgcR5t1aSRGts+vZO3z/nbJ4bDoLnV89+RTd0vHr9GdcPr5DrS91QpA1mM9VxKn9azWW51MqcMuPlNY161l+MlAh1NzANkUPnWbpIL4UuVx6ii8B0c1Cufi24NBNsMNdu4CRaTjwcTvRz4TrseffJu5TXb3j+i0944AMXwTPc3dKVynXxlNcz2cFJYMKzBOE2CO8/ecTXv/Z1lrSwzJP6XqSFiiMdjqRUyXhq9ESBHZ68SscZGofDu54YkqYN9sC0/GylWEMOHA4pjprMdHFRV3LN6Ksm2SJ0Ud2+S63qD5EXxAsugPNiyYzbvBHavLAReXUxMoxqnjQMO3xUre15KSypMB8myOrCCpMNImdImRg9zFAnnRg4CZqoOFhcpjfqjlSdvM6SbylamVhmdVmfHMRONMHPCxkhSeW03OlYsf4lnYuBXGakbLGdc2KNibqJSHJIFULR5nBXCohRIoPDuULwok2Dds+1d9Wqm51yj51zOMlQC9FXwtDrou88y5JJuSqlzdYnLVRUPHUNorrQM3YjFxd7hr4HEYZaGK6uqDjuTgsvX73keFS6h1KhHDlCMy+NtRI8ag7VmgrLSRssqyBNhQWn1LTgib1Kclep5KUwL7MGAPlGjZlKMpO0oDS9L1me/ht72Jq6htZnQZvg1iC+8c5bTLAmJWui0t7QAKN7ScD96FDjNaPwOYfk9nlbUrjuBfZba/DfTnIrelsCohtHPQsOnTs7wfWNzn5pPW+3ftbWkH6W9NDSgZYcNVDDrWtHCEpedAg+Bi4u9rzz9Cn/+B/9e/zhd/+IR48e0PUR9c1pEum2F1l/hO5VYn/aB3t8jMRhpOyUM58s2BSEkkFygmnCFwtavCoVFe+ph54yDuS+p552BJNjl8lclueZ+XhU6mjSnjPnPNRMKJXeFfphYLfveXy5Y5CCmw4cb15zfP2a+fYOOZ5wVdd/rbgfkZoI11fEvudq6FgCpKwKcg31leiowZFR3whpUvpnI+mLjtZE693WM7TGSZy/h9uGy9n9rs0iwJ2vvxpX1ZzsT6bmpPGZB6mOFDzqKo3SXZe0JoOrqIoJ4bQB5WlVKdjvdgzjwMXFhXqR+EDFMy+JlAplMmqbUYs01zIAWWRNGBBM+cqSCjHxmlSgc5sjeKts12KZirpki1Syt5EsosZ5xRJBSzpyTiacoPezGN25jXdQ0NyB9kLEYImYxnMB0ZjWxHDEqLxd9HQhrpLLYvGZ2DPwBuR6AaKohYDXaGNJmZRapd2DNOja1hypGksHbVIf+oHdMK6fM1zsKSK8vj1we6uJdM1lnepNQRNLHr2DsVeXdgFO80wuVfsPDZjRPdIqRy5YhI01sBfmOXE6TeSUVDzG0Ih5mv//QJ2yY61OiKwayesSb8Fxs8Q4n2T3Jo+u3ta0rN9vFIdVC729ugV+2ORyrMo4rbTdFtlz5GpNPuRsyxC3ovhNOWQ9JwcbLeLsOlsUDy2tsq/1PJ3RMpzBRY2mI7QkZrvkdbOznwlydg1n/SXtnq3rlb33vdsn257jWKsUykXXFLDWyuF04M3dDafTnZqwnZVKsU1RExO/3ncfPGHo6fc7Vfmx8+rGAaRoKbvryV3PyWd1ctfuVr36UsGZJFsV7QNxsMTA5BwnEU6lclkF5yMPHj1heXrL3fXHeDOOCZLxQOecBqPO0TnH4vQ5u6Hj+vEjvvKV9zS4NlECRE10lmnSBkEr82ta4fHOZEO9jgclEwV7/u2ctztEC8ANzZFaqDlrk6NNsmLKJr7q089ZSf5VbNEvSU3vgid2keA7Kztvc6SNXO9gt7tg3I3sLy7ohtFK055SFqQ4FmmBbkYkW/IZ1s2v1Iyi73p1q85h6xlxQq6Y74Zf54tq2Gv/VKPvWDFWURfT2q7SFLNM+nWDHPTnKBDg1w3QQAZD3ZrJpCBQMyXNhu5AdJoVxNASam2g966uSIs4Ld/7dsO8yi/70CoMeu1SipWjnQVseu3OtbFgdA4XcLEn2CbRjXtyrfhFVVtCF5GGVlY1a9xEKTSpH2Knylo4kvPb53njTTcOrDtb77CG/aoAQUmzAgcOSzRQxZCiCiu/Pb74uBd/t2krKzTAtlJuwfh6aAbA+T7A2fv8pkjx3stEWr/slkicJwS0vcD2oLO15f6L7DVvf+x6zp8/mXb6zm2f/cXVr/sn1PaNdYtqQYcIXoQ+ei7HkfeePOajD97n/a+8q8EYxp2PcXvPtuG15EKRMt2DV+zGGw0qahBqHkFa+TBQrSoIIAha9ld5a3JCaqKmDiQRuqC0qaWoQtUyU9Js0vMaleg274kBBK2ADNHTuYosJ4oI6e6WcjxQ5xOxJA1oAVkmqhPyKUDnCVLwvRArug7aeid+W9PEqpmtKvRF48adf22BrnPn33Nnfzv7+Tng2N563b1tSbMgtWifnhrwWbJhPTgNcCoGRJaqJn3VZM61cTxqVcHM7KQFQqKV8eBUgWy323Fxeckw7FCzRt1PSnU4t5joiVXTnZ27VVO0yq7XHloFzfYziqyvxXtT+dyuTapd4zLrXmxrrGDCQ6WsUsrVeoZaRKZAms1Tsb5fj+3/zuj5jVVgz0OUetzutUcnWgiRaJ5VWnXhrJLutwDeq9dH33mC7W9rtTRbLLvGlK3v0PbKlTKmIi/BmDbDbk8qhXhadG/KBV+q0aqV7UOL6ahE7xhCVMqjE8qyxbCuqTvZXrjSwqVRvqEUUaDLYp3myu5QoZlzN/q/6vjyqlNK8baJoSe0asCfJQYOa6iVdvO2fG198KYc4II1pIhbT0UTCFnRklbSdT4g3jZ2EbLTgdbkcZ1zZlqnWvfVHmgV8MEmrkSk0TKqJhW6YKDIq994qYAiwhYMtAWhinLBs1uIMuAl2EKg2tKrIpdo426b1DSjN6cBUjAUt3HHz9VsFPW2xiD7H2s8KGAc/mgIqzgIPmJEHpX+E0Fy4jglbg+veXXzGcvydVWdMp6tlELKajrkekt3vKPbjTz8ylOu333CYqpHXdch08TplWPsL/EXj8jXj/jVYWLsYO8DXjxFhLk6Jhe1pOdB7DOPXc+tc9yFwI2DnXPkGPnod7/L0/c+YNePPP/h9/nlL37GVQiKFlfRRmyEIo6pQoqBq/ef8o0/+F2+9/f+hOd3N7Cc6Pq4VmZevnrFaT6x1MKcNfgvKVsuaq3ztvF7w2yULqXBey6FYAmzNnUnSg3U5UQqCec8aTqwlMwiBY9oOVUii2RSa2gruknG3uPCQBwigU71tPt+pVNJykTniM7zcHdBvxvo93viuKdWOB1OuFRxS8Y5VTspJSMkXPV414EL1Kr0NO86nIv0vgdUkq+UpFU1qeQYiTGw348aF1QoSZOzVDK5zEAhUMgnpe8UUd5mxdHRU32luLwG3OIL2iUBiFOJPh+oxh6tVHoXcAF8dEpTksLdm1kRH+e46HuC69TscZnNlfdEN/SEGFgW9c7w4omjuvmG6BjGDudgSTNj7JHseXlzR0GT4BCgiCMloe9Hoo8EUW3/05LYXz1k3O253F1wc7rjOM28vnmDOMe4Gym5aJVnSYZ8alASqPQucj3stGpXhcpExlG8EMZBDfycY84qzexTIKMBlnMRwZMFCLo5dz4Q0crPlDTo8vUMRPnt8dbh1si5BUdtHW/7TnvZFwV4G2u9oXsooi6Nae/W7/vzX6SFOWd/f+GeayhnSwhqg74ssIAV4V4/fz37rQpyX5Ybtuq9u0e92F7WgLzt2pxbW/7W829+QUodyvhauRr3vPfgkj/4xkd87Svv8s71FdPxgODonGfsdb9uc79VHZUbUpXO1BpQG9prfj+uVqSL5BQovlBDIPtAcQGpCV8rvhZCLYYjePxywntPOsWtooFtniUjRRX8+mgGtMax71uS3w/E3sHpluPhtSoe3d4i80xMmdG71fQ2lxmZEkuZKemE73rCuMf3wyoOQQhIp6Z3vgsQz/4YWLCNn+0JnI+JdSzS8Ae3/cz8vtyZEZ1QzdxWgGKYrGg/XE4s05GyaGA8H+8oJa8eSMr89CwTJOcoy7KuYV3f27PZEo2ui2uVqqQF79V74/r6AeM4sr/Y4120/oBC8JEQdH4US3RKsswIWav3OZUtXut6y0krOSWjvQuxZKIP9F1nMueilJ0lad9FVlqpa3PIbX0KjUHjg1FdaSCXM3UnobqiXlgmkKPS8F7vrT2jUjI1V968XFZFyxg8vu+JXhM2rdxUBWlxVHOEd+Lou0CMji5CHyF4hZbHHlIOHA4LuWqPjyrhCVSsydsTfEcpMM2F6+uRYbdjv99zmI+klElLUePKrkNqJaWkCcGSzPDY0QfP4D3XXUeINuu9IwVHwkPXIXgKHtc8YHxY6V3FxE1K1eqY99rj20U19j0djyqo8JvQmLPjSycazZW3PbgqsqpGtKx6TQZdXefMehK1cX+0+dI5VZnREI91sCAYXcq+aYtoxZrHVl3w9n5tYVXqRpOyE2ze2iTVz8gmEdoaibQ5RzlMAsEUidZzattMayD1UPW6o/PqECxKkYBqGWlZz7vWbIlTVYqKa003aDYurDw/f36uwWnQaKewnouY0laDTJy5S+JYclrPoVVJvDhqKqQpcXd7YFnyyuNzgGsqD2ALUgudzBhvVSTR5LGGnjqM5KtLTtdX3F4/wE0zMUMvgYcPHtOPI5cXF7z34JrYR6LPjPsL+nGkDHtSjOTY8c43vk0/7oghatLYwQff/X3eef8J+fa7uOMdeZpIB1UDWZbEzd0du5TZDSMf/Z0/5uk3PiRc7OD4hrXZ0Gkj1ovPPlNFH6yJyxCWlgCfIw940xFvGtMGqDUKQhBHVyshZ5bjHTGq54grC0EqHWYQ5VA6j7lftzK3c1FdZilQ8qp97mwOrckmGgTkLDBXqkt05UQVIR0nLf16WV25l7zgXOtdWOjjaBNJKV/ObfPAO7dK2kqp5LpQsjaRRxcI4pCsvGlZFqKNpeDUWkWcoxt3LMWMtzyGsHm7746u81A1EM9zy7cdsQsEHKGBD2CNbajcXylKhfSRYTcAjpwKSxE1Mwoj1RQ21N1PaZbdbs84BC73HfudlsErQl0gz5VUF07TwmlJODzRCT44Ou9s4xjBR1MD6YjdBRfXT3g9zQiRvt9xseuIwTMfj0xhYnITd6dJOeG+MiD0JOJ8Z+7nMAyeXB1JhNJ5MjDXSoxGQhBd9Nszb9TE6PsVWFAVMBjwhtD99Yv539TD+7juIZiyynlot4V77dhQyxW1bWt8Qx5pQf8Zwsn6tvaN9rONZnVerWgvdeu7syK07ffO33LFGp1b+722+vZZM/hbucj9Xsiz/WL719m7GL3CblgLrbwIoRYGB7su8HQ/8mTouUJY3rzh8Po1/aNAP15YYOVpwhaG3ejalRQlL81gTbR/LKfEMk9GcdLX+OBxrsd1gRADZbenzpPSqHKiLpPuQTkhueAohJKJXaTroyK6zmlsEu1Km/rkym6wp1ILaT6S00wuGkvUeUFShlJIhiR75yzoUuBMTkfKNJEOR+IwEvqRcHGBH0d83xEdRO9NZSmavLZsD2NNVc+Gzln20QRswARJpD1/C5Dt+VaRtWdBWQh1G5e1ICWRTkdKCDqOasaZKqCleXjRxIEWvzkN+EPQNVXjDY1HQoyqDuUcVG2G9s5RUiH7xOJnnFf52ZRU4ramQs2L+U7k1d8G54g2CzcrAW/S440F46CcmTs6R81KIQ3GaqhV2QFe6goayJnkfKOm11I3kYT1GhXswZIN1xK8s33YSnp4tFdWqttMJp1nN4w0etqUZnWcF5SlECJLbUmOY3+xYxwiF/vI2DuC12Sj5MqSMr/69QtOUybPhdbEj9exrN5QOxAz8/M9cbhgf/2Im09OLEmpiw+vHxCCI6WF0/HE8XTkcHdAqiqq9QidVHxKBEui9w5qFymdp8aeLI6pyBrvrCwQYZ1D4pw6zZvDuNg9cDbu+7fAly86vnSi0ZQAzudKU5xwDYlpQfrqWNMmlNCan/V/1ZAhq0Bwtoi7beFqE1I1uqvy/qUtkrL9UpPNcf7sHNoYN6THCY5i2W1Y94iV6uTQLNnUL1RCt11H2yZkXeTVHdq+6xqla0OTNC/Q329id+dIU2u0Am/ScfbelpE771dFriaDtgYmbfFspT9bzD/3HrCqKBwOR5aUzjZDt1JHsKpLsOakJrNWRVbznCogISL9gL+6pn/6LuMHX6V2Ay47ag34977CcHHJ9cNHPHn6hHHsiV3h+vpKGwnHS4gdxI44XpJz4fbNLSKJPsBD/wHh6UPcciLf3jAfDpze3FJSYp4n0uuXuCUThpGvfOvrXDx5iOveHsKKXNy8uVHNdNtkVsrYivyZwpBTdKgaYq9/rEeGaiIAQhA1jSvzpJKIIaqEnt1RVVQRfKNHiCZ0AV1UteLg8U0xTVgrgRgy5ao+75wKlUQBcw6vLKdJGx9FtOGtNDlZlM6TqgkfeJqjqKOYOodfnzO22RRT2SoCfejofCDUgpQFslUYrMpQ7Rq62FNkoZQWyNkcdlpqjzESCwhZ6xr2MgUUdJzq3BACQnSAd8zZEjIcXddrYpUrWRwZb/KymmhIE2vwgdDt6IeO3UXH5c4RI7jgybMm18OrwJJ0A/PRqFlBFWe8d3T9oL1haG+W9z3deEElUMURfGQcRsYu0NVCyBWfCsnNKwgworK/Mc+KeJmPUBbHIo4laEK2oEIDVdwqL6jJhtYhFROLWwXYafAcQt56eX57fOGx8bDbqGz7DdswfStP2xIC2RbW9R3a+i33vve5Q7YUQ85ec55sONxK3ztHuP+qc9LfOf/52Qsd69qup1/feoXei9VIS+x7X1BqOf8MxVsqQ/RcxcijoedBjIy1UKcT+XSkv36Is4Snnel6j9q6YklGmZaW8SBSKcvCcjpxOhyU4iRWAfaO4A1R7wbKMGpikRbKqdO/pxM1LUgpq3ywAJ0AwRpZWyO096tClbTnIwUpUJMoyl+K0UwqkouJOYgBkB4lhRndJ2cqkAuQMgzm9eAdrlffBKSq8WdoVNQv5qzfC8cs/mhUaQ2RbGcWwNVNFbJVNOqWaLTnqSFQUdnxZTKxEvXy8G1EuUbUdGx7gGhPqdGmKuBK80Rr46eZwXmw/kXte7DxYjYDSyrK+zfqVrH+kNJUgXzT5XBbokGltH6WFqwhBqqYyE7J9CFA0L1DqvbkrcRTk7s19z3r1TLg18YC1ucbYsRXC6Br2a5xfTayxrErJdfESzxWIeh7uwdFVZVLi9VUGn6NSW1vGXcdl5cD4+C02OWxRKPw/LMb5qQsmGa4R1VRmBgCfT+Qk6ofCgEXBvrxglwhFY1Hx2FgHDpy6ggiUDN5mqhZY5roIKIAQigKwo7eGcMkkkJgKahZrzQWkVWH1sGl96jZR7T4olp5NkYFq/+648v3aDR03zmbqBrKtOBh5WqJgC+0Em5b75yT9YaWumgg59zagIWgDwy9ylrrmjWJKfy4QEsLcF4sKQkrhUrly3RQrKY3rYmTSqkzuEqVYMZ0AVxU/metSFD1g5blC22Cl5V3GHxnZU5bKPGE6JXHb+VxXeXU2wBRVLi6tqDUNYkKFpyujpCwltilYJrJBXEtMdNLKk6557UUOhcIBIItXLRSNspxDKHDi+OTXz/j9u5AFlHOeTXuXbVA0TdlcKNsBU902ktQK+RSoR8Yrh/wnT/8Ht/42tdIpwO3n75kPi4spwXpe0UoKoYcFIpMxCFCDEQ/ajBdhGFBS43jJbFUMhF8x3LqyKFjHPfs3yk8qYXb2zcgla8NgeIUmZhCJCMcT0fzkFB+pgNySjx/9qkqJ6H3XyzOztlK+kVoNONSC840yJNxjJ20yWGJiEt6Z5KWhcUHuqCyukGsWc57Qhe0ItKaIk0NYpkLkisl2RgO6AbYmigFaiksJbGko4L20dE0u8s8qeQqDhfVgRWpLNEaAJdCRJsgl1zAVNzqMuGIeCIu6HmlrNJ7VXSjXYDOwYNx1MbqHopo41zxHuc78J4lZUpRpLUk9SQptTKMqh4Vo0rEijiInSXj3hI1NalDlDvqXbU+BEd1UQPr0DPsd8oLrR4WVUDLVRjHkdBF8rJJ1vo+QtTrrbUDcdYEqeZKNU8g2h8T+mA68mrGFQM8fPSYtAgpwbwIx6VyzHA4LRwOE8vhiCMx9Z5QM1XUtDR4R6iOUOCq6xm848J7fBTwsCyCEOl8MPWsSpDKaZ5JArVuTvOtwVDZo7pY5lqZppNW13Jlf7FnHMcvvVT/TTvWCvT50cAvxwo+aWJngJjIaoypiYmtr2vlyARL9AMsZjevDRpY8VaiYRSN++ewJQZtT/JnaHtDsc8VC0NDpRsaJm5VhjoXVAFr6m7B0QreuTWqvQdu2dH6tNo5RVHkc1cK7+xH3r++5GtXV1zHSH93xwXCVRfVETx2gCPJxgWXlKhLIh1PHG9vyfMCy0LXdcSoCXO6u+Pu5UtefvYptWS6ENjtd3RdzzgOuNgRxx27q4c6v7xX9aBlJh3umA8H0jyxHG455YXDMZHmG7yDPkbG3ahAR6+f6UOAWldHZQVoCmlZVrUs7/wqA17zluT5oNSrGCMxqnu5E68B5unE7e2dmg3u9zy7u+PVZy9RQ1ftE1MlPjm/+WfPwm1jbk30tvG0gg/SXtfG4P1EowXb3nmcFKiOvEwQo4pvOCMWrbG8Cfk02WIpZySTvFYSGvWoMQCw14r1P+R5srhC51EthWmaVyEevIGbUs0nTT9fTBVxdbQG8rwFrxoXVpWjbeqMCDl4oveMXYQqBI8KlrQbagpYEoLtR9rA3ADFrlNKWD8OFOe0Yp/RnhRjkjTqoCZQAg10dVAJ+BDVG2RQmnF2GdeN4GyPDD0ENal2XhrevVK52jMvtZKrgmgpV3LRaEupfgZEOHDecXFxQUqQM5yWwpgqU3GkAilXpmlmih5JgbxMzKeJOi+aJAetEI7B0zvH3sA15wQJHdV5qvMcaiWVqsaWooBiFmjiJZiMs4jDRZV3Vof0vMaxIfR0fff/Y+9Pei3ZsvxO7Lf23mZ2zu38uvvrIyIjMhjJJpnJqqRU0kAiVZQEVFHdQANqoG+gGunrCBoXIAgQNBIoAQUJVVBJoJhkqasis4v+td7d5pxjZrtZGqy17VwPBjNfEtQo40T4e/7cb3Ou2ba91/qvf8Nf9PrWjcbT9FXBDtSA0vOPrePt6JBtqPrEg69fwM4n3TZGdzewTzsfGNZId6tZewDty1lxX4MV9lFir623poftQLAv1Nz1IHa3n9AnNL2TdBKXo81UPDywD9iCN7gW+GJrvG2dnfZC1t6mv9fq4iF1KhLb4u+Luk8WmgdJCaAeLqY0T/I871fy9JqpXXKDQq2JCz6205Z9D1NSCLTa+OmPf8y7V69o60Ia7KCzB6zrUM4ISd/i+mEWAwSJNKofxJUQvOAaE5dp5OrGRnG1WVJmXWdz+2qjp12afqHTFNRsuZiSsMZELZm1WmEe4mBOCn5PxzSYNqYp426EFMmOipmfc4baSH6Ar6Xw+uGOwzIb1eeJvd75Snp364WHeAjcNJy7kt7aWSMm2/3ckLqtfOniLePVt9odNIr9PBIY4rB9n247KLVriUxobRxpE3TFaFMtLQVxq+Ak0Roid2Cq2sw52SlM51TXFZzDWmslSoVg4iRbe2pZDo6cDmI1buzGDMHsffHJgcSESqBVb3yKj1rFgv4MAUikYUfEKF81W9hSihF0pWkjO/fa0kcb1d4CS1XbK6ry9vEBJFEJ7K6umDB9VhoGYozsnogY52UBFYaQmFfblGtdWE4z87yy5EautuGX2rZcgdYKkGwc3NjWvk3x6obSrDlzOmbyAkErmqsFfaFuwRm2Pa1bJlJNCC9e4Pbk11YtlyQiqNRu/WANVwykEE0AL5hQthUahpa2kinrv1JK/+blL6OD9IJetwK/NxlPCUj4n9t5I+eP88bkPRZAd/jzD3q6N249DLa+NnDWkVvgTIlwqmTfgTYk1d9Db5TO4X/n79SpvNqLUe2otzc29oNzFhDjjRS+5+l77/nJX9iPiCK1ElpjB1yKcBMju1IZcybNK0NrJFXaahqlEAth2L6bTTFyJi8LLWdzgot9z8QsnlsltkLIKy2vZFVizbRhQIpRksIwYUGWAyKROExISEBE4siQV8ZpT11nyjrb+dgqWRVdLbFb1uIFZC+Em01QgqHptdbtXoUgW8mChO0Oi0JoHipMIAYYwhkUXbNRbUupPDw+Mp9mo9JKd5jTrXG05fh0UfmZszUZ20LdPn4rop+ss85y6LVSH4d3WlBwnWkHRnVbyJ1FonbONGMq1FIQqb7X4xa09jGoGaD0ParVjFY7l4Iak8KEytXPrEzq9KutYW6bpkidHWLmTW1r9O1BDES1kUdQJYlakmrw+FbBf4k/W8HPG7EpRoqoGD21aaNUNmt5ayhNq5PGidQcDEZ9jw+mF9JGqeZIKGq0tG4Ik6siTclNaYcjEhJNAtPVDZMIIQ0eMmh1qJZMqytrLoS5cUpqtrZVWNeZec7MS2bJ1nQ0dVCSDoA4zTe5ViOJ6yYrtelmDLOuK4+HyhIErWYxa5Mg30NEXHvi60brVnuK3x+tPtnq4OC2y/X6XO1rxMA0hG3jrGKNZKuNUlfI7zfUv+71rRsNbZYGfuZA+j134KVzBgX8ZvYHqK/3zqEXf9j98UvhyYia7eHrjgRWvDWosj20YRuTWvNgzZe1kP1rBX9Cze3D3luIg01WAkiy5gJwlxp7j3bD7CJ2e12z9jUOuSmTG7VFekqkglXjqdNToE8yVKHAxv0XNX76032m8qTRwCg3jYa63a82lzX5OLNvXFLVFndQAjZyG4ZEKUrPJQmS0Fr58Z/+GW+90ZCL6XxA0Z1Eqrk8iDxZkNAF7iEKxcfOJa+U5URejuQys58uuby4QtOOUpVlWVlPQqsF5//YhqTQMbiKNR9j6o4IkbVUo9iEZAE3VcGFYbUqp3Vm2u8Nsal+vRwF0dYYYkKBtWRePbzjcV2YS6HQG96uy3jCd+bs0CACk4sMG0Z/6k3hNiXzZltF3NFKtp8FQItleLRaKeuCYvzONPWDo9tXNqR0xEDRumxCykADCSYab+Y1rjSGlIhBKNnWTkEJRTFL5p723UCeuItVhVgJeKo2NsaNcbDjp1lS9SBuLoBt3DEmoyGEaIm6aki7tkItakYQEiyLRAKEgTjsGDDkqqwraYgMw2DWw1qc+uBmDeAcYFia0xsozPeQhh3jdM31zTPGcWIaJxAHA0Ijn06shyP3p6+oFXbDnqOYK0heThyOM6d5YclGeahqKFC/f7U1JFRbR0m3aWzTStHMkCIp2maupRKk+n3Rc55OCKRgKeUGNAQPgdLzvuL6rVKrUQ7i4HuSF8MqxKAm2hvPTYuEYOFRfvi1sjqR7jevX/fSrot70ijY8aF+NnBmZ/QzRZ8Iu6XvvGxgmn1dYDuA7Z/b3suGUVih5n+4NZ4iZrzhZ0FrT4r7J29GnxyRRlUMT2jKvUVyjr4XuuawJ0+yLHoxwUZ/OE9I+pvv/jtP4RZfz7USamUfvNEIgV0pjKs3GtWE2WVZYFgIYWDYnxuYWkyDkVezNpXWGIboWQNW+IZWSdqIrZqtal5Z80JNCckrwz4zTAVNg92JOCBxJARlCIk07mxKfrmQl5k8Hw1EWhdqXpmrTWdLXbb7uGkSWiMmD5WjG8yci3dxuuPWbHjGQG2Woh1x9kGz89AQ6cq8ZB4fHzkdT2fbfM5mMD2L63zNz2fO5jbkS0G3v2Erwvs5Jf3M16dNtP8cW0Hd/6L5+XJuQPt+JK7Pa34PkLMzoP29blM8VRwAtQk+vm/bAnTKu1ZEG6PYhFgirNULFjoIK4i2XoI5w8TUxvZ9nLaKTb6SdJtlNu2ECAwxbC6EJDM+IZnJTMNrk1ZMowH+HFkDEGIijSODNnA3rRStgG45m6bD08SlC+6dRZOr0oioFGYNxGFimPZcXt8yTBPjbt83DZIKy+nAfHxgOb5FWyOFypCgROHh/sDjceZ0yixZ7WxCzOHQz5VaFCFaI5QStUUeDmYdXKpCiKgIy5qp64lo7+68RnwPDMHohJ1Wqno2MOnghf3cypYj55/bKeCCeRsMKTC6+2irlRLctawVcjEzgL/o9a0bjTE8Xbj+INip6YvS+X7+8PYR35Yk2tq2gT4d/26cZD03CXgHvD2ejh6eH8BzGElQs3/EqSp9bLx1d44oq7j4Kbj1XfEHbrMnC6RhIoWJJkYr2rifVONWV1/1alOC0ATR7qrjuEEHwFRIMaHBHAw6TSa47agqrE+E5aULp6jO9YxnizZVF3D3jbFzuW18XauLmdW5+T5JUrUNMSV48fIjdhdXVpB6tlsEQnNHITyBHWjdWxtsytNAC7Ql25htPlAe3rEeHnl89Zq2v0SunzE9/5C0u2B8doW8uEZVKctCnRfqspLnhVp7wWrN5iTmejHWyptlJlJJNIZpQLMh/kmtO59Coi2ZVhppGAhVLaRPTSMxTiP3h0e+uXvLN+/ecMonqlRH9QNRIs0nF9B8smXWpslRIbyotwIy+ISioy+G9BQ1VH7V6ja1Ri/qwrWglaiV5JMlQZBsxXnW3vBgKdYealeWmUGE5A2M0SxXrncD0zhyub+CaunUtQROpdivpVJUKSKWYkulLm7F6shNCMZdjeLcVCJJ2vb8DlEYkjCEgVKVtSqX188IaUTSxDDtaCK8fXxHvXsgt4o0Q9LSkBinRIoR1cqL25cMKXI63vf6hnd3hTUvLHWhFtPNjGkwu+rWrJkJdlKVVmwaKMLt7Qfc3Nxy++w53QJsnQ+8++ZrXh8f0Zw5rStfzQ8+MYL1tJCLoz8xoikyDMKymDo9xcgQJ8Y4Ge/bw/zu3t5xmg8cT4/Mp0fm+UhpGbCpg7bGEKIns1qDWZrSQmRBOK2NGCc79Is9T1WUWStZIxqsgFLUxXq2pAIQo5KwyYwCpWViNEF/CwqxIw2/ef26V+yAVy/M4AmQ8BQ4Dv/KNOEslDqXgX06cBZZ9/Ouf5T2LuS9M9E/evs6djA63WWzJ+6qxO1o38Cj4O/P6Dzq5icGdHUnJcMS1HE22Qpby186F3HbexQ2tNKoX8oQlLk0VALDtGNsjV1TblE+lsj3QmKaC0NbSHFGH1bKw8JhemApKzo/8tn1xBgGBu02pYkWRuIgaCgmCm6LTZyXmbJmQkpcXF0xpMh8fIRW0bKwPK4W1rfODDRIIwwTEr2gjMmQ3HFgvLph73jY8+//Nb8HyvHwyOl04vWrr1nmmZJXslu9amvWxKVIHMyaNIgBc7tpxziO7C+uCDEZcBLO9DMtBmAGreaCVzLP9nsKwqLKH/0//1883N+zPj7Q5hPkhSBWD51XVF+Evb6x33fzm6ZnsKOvv243mlI3r3kSvLa1n7o1zwobtcrMv5zKGwOD9GbEz/takLKeOffZ7Xq3Ve6FqNu517y4nb7Xcwi1wS4Fxmng+sU13c17rTDnwpwzp2z6luZC86aN0prrNJontHtRq7bWQxSSv1fU6rwQAuM4Uksll8rF9bVNu4aJNO1Qgbf39zQeNkpxiolpGBjSZE1kgxfPXxBT5DSbYFq1cXx8YF0a81rBqdcpmAGHgukZnLtTqu3DSQaubz/g+tktz19+6I96o60Lb199ybo+sq4za7Np+OPDIwocjwvZqdshRiQlhiEyL1YnjCkxjiPjOLltfqMWOB2OG+3v8fiOZT5Y3pIWRJQhRaKEzaShqbIUBysFTqsandAtfWtTSlNOtXiehpLcCKeV4kiakqIwhMiIaVQRkKikodlAK0IIjY6r/Xmvbx/YF3tA3nnL3XCeDvs+7aKlG02dEYTex5+7L5yCpFtGBggS1C229MmzaRuKiXv7AMIoF+qx9tapyVboYzUdPS+h/w8MFbIQsPOBUms7P7Taf77gYTJOd9mkaN3HuV8K3ehUVkh6RPx2Hnkh65qSzRvF0XFCl271A8IRhI3WYf9UT0UX+s9m7zM4lc1uRQ+C61Mb4XSa+clPfsIf/uE/5fmLW6ZxZBoGnu0vEFXm+cRunBhTYkpDJyya60fFpiezNRosJ/RwoJ2O5MdHcoMSEmm6sI0uBNJuIsTAtB8pEcoYLEG7FqjRGjX1TTwE33QCmldyXRn3pg+pYsaoCkgIlFpAG8NuQlTdK9xHnRo4HWceDyfWpSPCeg7c2vIfvJjo7k8+Tj3fK99ulbPYTI0Va/eVLTwp9E0Zo+YEcNczR0d8vZdWbPqhPs4FcwvxZFTLZ4DWiyYcZS8FjcLgDmFBhRL6c2jgUW5GYeyOO1EiBFtNaRi2Asa2SxNPjj7RKK0Y8hEDkkzHEZtQxBAlqRa82EfxnTKnWFBdlGq0n2Bjb6F5M5S3yWAp6xbsY4+0WJid/14kIpIgJFv3GEKV88KaF+OxOgqzrgtrXs0O0XnDNWdW80AmrwXvzz2Tw4EPDGBIITHESAAeHx8QEqo2Zc3LyvHhSGmmRQkxYXMj523HZMVeOfOQwUwbgppLTWgm+G+YBmbVShXAedPB15k66idBjAkQgWiUrFEipImhKWurlg7/G0H4v/YVvDC0Cfu5SATOU4x+bj1pQDoi/B69iG3LtclALwA3JJkN/Nn2aznvz9vHKag3qB0E22bW23vcWo0n1CfTuG2Bd8G+mJ2PsqHf1tp0oM+sozcekPay8f1CFLUztvl7CCJEVUZVdsDtMPA8DdymgVSVoEKoSj3MLI9H9OaaIkYuyMtMTMrQndKC52R4voGqWZ/284AYicNAGkdUG0NZ0bIao6MVWl6dk5/QtKLDSkiT7QlpRAafwodIGMzFL/XGMggy7UnLTImJvHqQmDcazR0Vg7vmRJ8cxRCYholhGJh2FxsCjrsXiog3Gg1qRtaZVDLDbuK4LCyPj7y7v+Pu7t5CN53O2+/OuSXgvB5/5aVPm9Zf+wHWzP66v+3fZVu3yOYYVNX2THFtKYiH9tkZKLRtrXatRuvnon9fS8+uZ2oiPrlzipV9XrRJe2+WCzjHiaqdnSFOX+4MAQe7YtxMR3qjHUNgcF1Pc2t9CYGUBiQkNJgOo9WKSIFUz4g9xlZRwRF5++/o1HRtlhOV19Woqa2Q19VZLNofXxdE27UNodPqg2twjXaWs2kVmtsqo8o8zyzLQsllo8vWXFnXAgrzWuiDzSTQ7Vf7ihHXNKLK8XCgaXAySGPNK4+HI2spZxDNGzaj6PRDRI0SJZWsgaqCVkjBaLsCrp+BFZv2N0PuCUEJ2s0MGoTuQCbEweoYDQJJSE0J1SYvZiX857/+Eo1GerJI+sJWR/iVyHmK0Rd+COp8aC+om265F11QkXM2RL7YBTMXhETxw7xVAWloqIzGVDBbzWabQRdFd946+EjZHWo0BKPj+D/79281b9SYnsZYPKLegu9sQw4Ia1NoFUoh9lMkOO1FjEbRC4fajK4Uw+TFlAKVGAaCRKoKDctqCMGaDDVLBh8N+uJxH3Hb8ayc7RzTwReAhLNNW39gY+halI6AGf/ul19+yf/x//SP+Wd/+P/g+z/4HrfPnvHBi+f87m/9NoMKr7/4gk9evuT22Q2fffIJMkSIgeNhhgZJIcwZKTZm13ykrSfW+weG0sjuDsR8pJ2O7G+fMe53XN5eES8TsTXaPhHX6paCAXKhHU+kkNEQuBwGHg73LMcHrqfngKAxUnIBVUIQo7ME4cUwINrI62xpoEVpNfDm+MjbN/esJ3OHSmq2quL0nOand5SIFqEJSDIdhwJDcFciMevjbveXszUoKQ2eFNF8EwSJjaaFXjQUtSJbgh/owNqyrSkVxA0FRMqGuPUCozWYpmgHQWucjgtaGs+vLtnvE2NKrIsSHfkhKrnCWoTjOtOakpI1YSowTHvjWYqgdSGoMMjAfrxEEA7t0WwZU0SngSCJQRKH42zBfzoT84xRHgtCYxwCtaym9UAYsDDFXYS8HDjWyv27d+ScKTlTPUCpqXrQkZCLHf4SAimM9NyPONizN88n3rz5hnVdGKfRwvha45tvvuJ4/85MAHJxOl+mtbwViEYijraXYPtHwKgs+2FHioZ6ff3Vl6Q0keJI0EvqqpzyCaZA08QwXlDXE2hh3CWGNDCERF7MR33VlZM38kYNMC3LkEC1oJopapPUISVSsGYhSGFtK00rYRDCEJBBaFEZorCf9lwNAxrgpCvjOJDSbxqNf92rU3LP+oYnL7UpJMi5eFSeYMKdXuRI7larq1teW7Psn3zm9ePnjZ8HKr1YOAMVhm2cKQv2R72xONtC+w6+NRtN1YcR3njg5igb7iaukbRnsqnrELx3CVtD499TdWs0iprgcxgSCSHmlV2p3Kjy2f6Cz/Z7Pp120JQWElVhfvuW8OqG8YPnqNoZd7x/IFwo0z6a1DEKYYxu+wwaA5SAVn8Ok50nw7LYz1kLZHP1yacKeTVRa8nEOBCHkTjskDSgwx6ZCmHcMV5cINFSxpvrOEOMXFxesdPG5Ucfb7e+tifhbT0Mze91xwjjdh96jpXfZ0fXpRn1R/PMvq5GBw7Kw9ff8PWbt/z057/gl198wfF4dFMRv/F+7bsubFuM/f5tbeevLNattgKjXm69xvkzZfuwrT6w945z/u2rq+KOWZXQAN+XmrZNnoqYBqM3KGetoZ9p7l5lNZtPJrweir6fI8I4TqQYibk5JTVBiOTWWLvg2Nd9dxubhrRRDQNGTxtiYhgGBFiW1Rd0JE77zSL97uGReppRSYz7FQmBZZ3RZtlX6jEDrSqRwR0PC8vxkdYq7+7eUqoZotRSOqK41VKl4Y5fgRBHZ5F47dYa8+nI3ds31FIYouVRocpXX37B8fCO4/FgDly5UtZ1u89N/V659CAIVsdha3D0n7uWwpvXr5wUFYnjFUspLMejTRAQ4jBakgLNJ3429dNie1PVutUbufrkyPPZbLpkuhOrZSGmaBS1MVDLyZrmZPlqcW+TK4n2rI22lVC1MU3/lsXguZhGw7Q6VvjW3gpjm9lGhfKRTn/o7AfnSX7AGXGq1Td6fALQBEKfGuBhe/b76lzcEM3JBnW+9a+g/g0LWROwArfZ2NGEU/G9sTooITpCVeuZbIt44qXZtAUUyzw5Cw/7yzycbfw47a2hiHJ2LYkyUlpPbMZdrBopBkQqgWpCX0fO+8bRHbCQQCmFnhURk7kKmGDIOu5I89GYuV3Z6NPoWKqwrEe+fvUl9w9v+erVF+yGkavdjtd/43d5cbHnsi784p//E+rxxE0NPNtf8OzigsurK5swaSUko8rc3FwzXu5JQ+JZK+T7mTf37/hQfgsZd6zhnnZ4YNntaIfnjDc3DBd7hstntEujgeW10taC7kfKvaKpMaxXhPxAzcL9wz3TkNiPEy0YxYimBDGO4joXxqmZNiUkEycOkbe/+AVvXj9xAVF7wDq91PjajiKIORjl4nxUMX5kdUTQmmvj5sZkQr+GICGRgDGNqHW9JpQEtuAJ9wTvca6aV/BmV8vqrUovG0yrgrMerOcOxAiEkRKFV4cTp2z0nbxUclPW1lgRmkQ0jYhGglZKW+3g96KrrEYjGKJPZEKg1cWfh47lBq6vnpPGiRAHlvmXrMvMac4Q7XqVmplSZEgRqeI2tJXD6YSw8MCJTKZo3SYOWm0eZYyxQJNoRX+KhMSGMhq9MlOzUhuUqty/e8vxcOTx4dEQHOB0uENzhpzJa7Y13g/hXlht/+gImvG1A2I6iWBFokilSaBKIE4TRv+ITBeGurZjo9aVshYeDyeCLEQJ1GwObTVC2k0gQl4qta1WiAFBLM2ckJEoyADjZNduGEYk7pGoTJPR9pJr1Wpr5FwJg32PVIpras577W9e77/6JPpcxvczBUf8z5XaWR/hH9DBsSfFGt00wJOKW1O3Ej+Dz9Zo/Hq0+lebDPScHG4HYNg+ZWt6Ws9a8jPSkXrFpwJPbF3tfbp5iZsr2PkbzmBgp3OFs2mFqCGSLQqhNmJVxrXw4TTy2W7H73//t/je5SWf7ffcffOKxzVzf3/gT/6rP+LytPC3f/TbjoAr777+hvi8cZ12iE9UU3KnxmTuS54aYxa1y0I+HqnzAWqmBSGOA7TAKI22zKa1mw+0EAl5QMeMxkSNC1ILsRXqsrdpK0q3ZyWIm1JYqJo4YNk0bsyB4NbTQcKWmVSqGWQYSi/nNSMWphkJ9I6kiU2Qqirv3rzhZ7/8Bf/yT/6Yz7/4nNdv37DmdWv6erPKeZXRmwjZFojvu53e1teWTzg63a01Kw6fWhobAcJ+3jP9PLjrVWAQn1D72qllBXrGRPX6w6bpgXMTa024TexrbYTgFD0HQp085c5KgSamA344zqzZNJ6npXgQnbL2gj0mBEPMt3A8o2DY+yhGl20hENTSrLfnNSbiMHJxc0MaRkIaOK4/N4ez0yPH+eh2xs1oVykSSFtK+nx8tOdCzHSnOTjZHJju0x4DCTYOJj2kLw7DeV9oahrFVrh/+4rj4wMPd3dOr1ceHu7QmtG2bjT+Pq1R8OfbRdXbn3VjkcQ02bOktTKvM0QzWxn3FzQiuQWGKSFUaoD5ZMnla16QYFR/rbLV0UMaTM8RBNUFaiFSsUBoaEO1XKkhcnm5ZxhMLzuEWzMAima3G2KgtOL1TWByLWwpmRgjMb7fLv+617duNEov6BU06HYobo+R6hmh2biG6vumUaGkK98a2w1VzxzYnjaB7g1+Lhx8d++dvPjh4YeIOGLUfcF1+1JmPdqLju7h3MNdtvGyHSv2a9tswkZxsAyP/obO9K/+so7cun3bYM2lqqqzcUP0zdiOim3MJx566A4PnebUf3h54j4Swlk0H2Mf++7MCUsCWyUthsTZ4dZ9sQ3dmedGXheWdeH68sJSVMfIeDlxk3bk05GyzMwPB+JpQe8eOKVXaMvkPBN3kXGaWJ4/5/L6kmE3cVrhlCun0hiBMO0pcWB/e0vb70klQ17R5Yq0vzARtUDLapxIUdIQadPAbr+zwycIx+UETEyDj0zVkZQQQVznITb9khiIBEJMHE5HDifbfEKIOCPFDxzlHPGi9Ca4+Zp5ijApfV2ZiD16cqY5zAQQc4ZoOJ/aD/uGoG4VWGsFn5CJh02aqN7WWVV8QzsfHGcnMcAbvAIcc6E1CxKquZkuA8jm+WzjyzgazUmrB74JnS5Wa7XRabBWvNVivN/mQtrgzhM+xdHmgva8QguoWKMvYbCpTnFb6GrNhhnVF1a1DA2jjHiRBdv0wn8wd2nBKQ3i1BBHkJvd63VZPAU1n+/7eiRqIzbOnOU+ufBHtFXH4ByxE7XNPIVIGkYE0zNJLD6Od8G7RCpOubKL6mN/LGBMBCHQckelgps0YFoKp8vFFBiSNQ8SgnFdx8TFLjGkyDgOSFQk6nagSRB3T7PnNiUrGAeBmJT0LTbzv6qvLVh0e/Wz4fyf9OdbemPdn3877OkOie/Dxdu/5b0vff5cnn6kfw/xgrGfTU+qyPMHnd+m/143b/qzWaP4RNqBMP94O1ObWcR3VLIXS08vg8hGD+vTFg3WbEiuxNbYC7zY7/j4+ppPbm+5HUemYOYordmzvTwe4OEAVSl1ZUVZcuVy3KHPCtJka6jsmDT9VhTbylrNvr+ao0+nBJupgoF/JQiIc8SdP48E+32DMIxITRbkl4M1G+LXK5iGRUIwk5f+e7yxFKMTBxFzwSPQp5x2bJ5pbeq1Aj3vpjv8VbN4LTXz9u4dr9+84ZtX3/B4OLDMy9kufKNBPb25763M9+6R9FpFvTF8b431pSHnz+w1zpP11Gl4FjZoAJtpY20Pr15zqE/oOp0sAE3AphZejPd1qG2rc2Rz5LIz1q6rQquUBsdlNdcmEealGs6mShOrVoMpvOnUd4kOqmKMl6YNcdpZc32EYNM6DW5T7M1sCAY4VW2UUhyXFWIyY5LoDW5VpVIoDpDjNUDDXAC3J9gnWB3Q7eupn1edKu1VLF1vvC4nspsadGOjeZkRHGDy7C7TBXcqu1WP/bnsuhY7mxLjMEE1pzNk9amnO1pp2MjYpgawrKfSoBYPshZFq1WUaDB7fAItaP8xkVFIfjYFScQkjGPi6nJvdMQYSEHOLmZ+pfJarCYKaplUZsNqDcm/TY3GmvO2kcStwz0/DK0qobVNuGQPiAmT1dYkPbm5VYXg9l2eGWk3wAr+7rkcAjSKI73KMES6mLVptk2g+kGhVsRtz2I4PyAmTmejHvWFZhsi9ARLib2BcX6f8wqrNyCtyYYWxZi2hgGUECNJBlp1kRdPUhbJ2wEUHccOwOCLQ5wqZcmM1sWHaAmRtTZKLcSYvHuMhABDGri5fkYaJkJInE4za17I+WRtk1o4UUp+zfywU4VxSvy1v/5D/v1/8Pf5H/0P/wd8+OGHxJhMuH1ayL/8hi/++Md8/kd/xr/4z/5zHr/6iuOXX3K1iwwxMqadoR005nk2zh/w0+cv2V1csX/2nN/+3b/B9YtbjjcXPKSRNozsbp7TJFKIpP0FaRyYLnZcX14h08Tp+pp5N3EIwquHd6z5AgkDu90ebY1jfUQGK5ZzDMh+Yri+pB4eiHFg2l/y5vTIN493ZJQwjkxihX8uhZIrkbKtF8uKwIrBIVnRR+9lI9XpPq0q45M+YExGoxEXiJn1n6GOa66uT6gm2PIHfBdgHALTlFiLIz5VGKeBEAPaImgEIikM9MZ3XS3giqo86urbfaJg9sdFizmzpJFhHM2KlkaYEimJiROb0RZKWVGpxGRi5aLKYV7QOCBxYFXXIaTI8XAkrytaM+O0Izm/ej/tGIaBU1J0mVlP7SxErc3niMHCjNQPKM+BSSlCsz+LMdhhURtpxJsBBXHERaGWBQi00hFrCFR/ghzBDYE0CfGJWroWe1a7Xbaqst/t2e0uuH32grWs5JrJBDSYNkTTZNOZdeGYMyHAGGEt5nuuKpsGpzY1CqdE6rIiCWRs7Ee7x9f7PZcXe64u91xcXTKOkWmMQLYCsTVKyeSSefXmNcUP0vu3d4SYuLy+5WIaGVJgKoUQ5Vtt5n9VX0axYCtygSeAUW8TntKavMzwRrVty8vOoe78FL2oCZ2OwfsF4IY9ibsS9e/V3Aa8TzTodCY5fwK41rDTtXxN0ycSVgPV1jOrvKjGC091yMs7jz7tlv4unS5l55+dhdG+ODEE0jKzV+W71xf8rc8+5UcfvOR7H38IhxMP9/d883jg2JQljcTdBcNuT1Pl7u07Xj0+UhDGGvj09gNDUptx12ndurmZJXktnO7vyPOR5XBgfbynLDO6nowDLnZ9jQseWdbZLm4r2Lk6MAzKxJ5EJeUjrcyUgyCtOFjRw/Kc7eB2o0Tb9yREZJrQNNDGabsbfeaCnEM0m5quAYzrvuRMqYUyP1DLwroc+bM/+1P+7Mc/4Wc//zmn5WR/X4ufF0/ASp6CV+fucnNB8/vjMtJN//B0hXW9a0fl+1errg1wzMubDBePRzOxKblSWzYdozdvprmotJIN6BQYk1lrpyGSq2J9uxD9TLSGwxqYcdrRp4b5dGApmeN82lwZVZKJjdWsWOPg9vRBjNEaMCujIB6eaGs8qp+1DdbFqOyH44LGGYmJx1yIw0QaJx6PB9Z1pWlhGCyRfX+584TuwLosdo2K6feaa3greo4j2G5AcIqUMyA21zcDtjuAaM1mNnC9NatLq6Bl2SZl0V26tFZyXrdru9vtCCFabll9Aij4nhWHkd205+ryhrKaVW0uYmYIafRQvcacMbtdNcevtVi9WIoD5aqgyfe8AFUIETRVdvvANI08ux25uJi4vNxxcbEjpcjgbqmtNfK6siyraVBqofraPs5HAAs+TEqSRBrUxfy/bld+//XtA/uAnmsh0REP36hRZYP2NvqUFQLdki/09k19Q4zBqDg6+NeCbkT6dMIhLhgaCJY06Q9X9EZHRW0jJTjPzLrRtZo49D3tRkezvHvtiKc2F4QL2/fvGIehMLCRGoPbfhLPi4ZCjK5l7eI9+rhbaRpI/bq0fmj17ccWaQtWrIqj2yEECzPauxDURcQpDbRWtjFnU3uPYQhIE+pi7zwNAzfXl/zt3/9dPv3kEz796APbjJoyf/UNN9dXXB0b/9//7J9y8+IF3/vhb3N1dcU4jFx8+F0+TjdcfPwDnv3wb3B895bHV19DWy09timSFzQvHL75htdffcXXX37BNw93xMd7xjdfc3h8zXixQ6eREiItJoIXrHEYSNMFaZrYXd/w0UefcHFxyTQNhLs7rlpjjYFYC+VohxoipBC9WIbd5eBalMA0TagEo2TRaFEYri9NOOVWytFH4wVHL1XP/FAXonchVi8F+l5kjLm2rcuSV7RkgkRaLbS6WnXbm1Rhc1/rB6n5ykc/WJSIkARz9WiWDRGj0Wj2o6WMNi0II7VVE8H7G8oVqorZJhclhILIQptnQKltBY3UaPxiir/fDof2qRJ2PSzJtbK0YNkSQzI9RUqGfIwJiZEUB7d2nM1XXBJpvDTRZbVDrU/WumuKYF7jW7Lok/+Z8bNTzJqL2NQnT/gGpoq2lW7f2MOqFOz+R98PxMbz1Z8NAVorKCbMD3FycaLlrORSTOBHgBYopVGLIUKle+0noYUBUkObTzgRSIPlikRz2xpG4fo2cXsbuNwHLpNpKoZoovxaM4flhKod+GXJzqVWVAdrboOwu7Sis2Tl8HgiRSVJZrcbf5MO/ue8RM7i3V5sbxPvpx8H29rYCr+twe1rUhzMieYaSBf+17PFrH92eiqCVPvayfnXiGkZ+pkzpIFeFZbatrXU95mOWvf/Fv8m/fM33w9/z+/99skEZDNicWMI3ZBg23MsaGDlSpTnQ+Kjiz0TSllmfvH11+i8UE4zh2lCpz2Xz19w/cMfcvHpp6wIa21bcOd8OPD47o7dsDvTtZpNN5fTI+vpwDofuXv1NXVdqMsMObs+I1MtoIkUxG3inWLpoI0GM6GwCWYmloV2fHBqTiNoc4ppeO8+m3GDOdl1nWacJsIwEfZ7NA7Ga08jwbntdIFxF0U4qk/JSLVfrSysy4kvv/icL774nK++/pLHw4F5XVnWdaPCvv/S87+2+qOv2944PP3zXjvZWjTdZaTb7PepS3VLUXubVkSTfVIdzNa0Vss3oRXLi3BHJlHcecss+EcPr4vBdbQBkLgxVGpp/jXNIdNukYGrVhrJNuWvRSmtUpyeFTHzALOLtfcdqxfzahlB6mnfGzWwF65iYHVtlXI6IWtGlsUyiaKw3+9I40CMFtBY1bJPcm00CTYFk0CoZtHbHanOU4X+rDvtTM4nU59O1XqeUBlfoZ3B4d7Wq9Pza+tDEaZxR4xiNOPgYcjqTaH65MjtZYfB3NUaidwquQhVI6Z+TE7h7ykB9h4i0DSgEsEdF43fOdLNVSRNpDHw7Aae3UYuLgIXl5CSAewxFqB4/lTXORvYR9BNX1nVKFbqz0RZF7RmUgikaWBIf3Eb8e3F4F449JtivFLOD4X2gvwJqrT182dhGjhdJIk3GqbNkOa2bGpfdxP3RSsCI5G5mUd29C7UvsXZxja5DZ6EQG3L5lrVR19PGw0bZ/Vx2NnBoz3dGDom1OdORPCUZPzRaO7bTHCKRuqLz/5se3p8EasE5MwctcMkeNXXMz68KAsxMU0ju92OkhsikSFN5LL6iDMQ/DCViHPPTTS93+/59JOP+IM/+AN+53d+xO/89g9s0lQqr/7f/4IyL5Ra+OpPf8H9N3fcXN4Qi8CF0OKe4eY5z6+fc/W977PORx7v35KXI9TCVDJyOqHzkcfPf4n82Z9xCPDmiy8py0rJC+Wbr0CELMbVzGo6nXGI7KaBOO5J447d1TNO3/keN89uuX1xay5IrbBXpeVMzo8ksXC11GlHQDrL+xmHkVway7qy5kxuShxHGxGXuqFGQZXzXe0Npwv/BHrZ0LHFbcnK0wLD0PpGM61Sq2grm8e3drqciDcvRg9I3jx2BwFBSYKjYFCzj69DZHBudm1mkSyOrOAbVmt1K5q7VWBrK9qyoVY0iorTkrAku1YQ7GBQEUN3UHOQaW6PXE+ElAh1YBeiawfSRrdAxPy8S0GjrceeFNwoFrLIE764+HOZBnteHRAQv8gizZ8h10ZtznM+JQwNmlkpPnWqs/sgjOPo+gclaXK9p4cyiYEM1SmEFTvwihodJBdzAesFn7bqYfZ2T5ubVTQiGkdMQ4Yj3pbroS7sCylyebXj+YvIzXVkj1PPmmmRSisseUF1tXs3F1ozs4HWZAMbpt2F3YfsYY9VLW0cCyb9zevXv/paC47WA/4sdrrRE4x4W0fnAq//uRXqRmVLjrD3xra1HubF1gBYSJl9fvNpfneGUwGpfi5iZgAi5l7Tw0dVn5yV8uT83P7hu9D2NnU7y/rZqs75FH/v4lRMG6a0rRxSNa0STZFSuR4iz8eB2/2OAdNxvc6rTSVLI1xdMVzfcPHxJ9x8+inThx+QJdDcBYhSKGvm9PBI2CtDSgwpWSBnzeTjI8f7d5we73n75Re0vELNjEHMVl2V2vz5iV3jiJ+zZ2tVmpGSQ6tIzdTZw/Jq9QmNodE9J0Bbs2wFt8xuYmdu2+2QcTKKzuhJ5JPA0BsktUlULW4c4kV5yUg1DYGWTFln3rx5zZs3r3n79i3zmlmL0XjMZ9nvz3afzv/yG872Y253u4OO/vvtfvbpWs8gc2fKZvdfvbhpzbQmqpUWnOQUxNO8i78l+7wOonUEPgS2YLcoYk2B79OI74/VzhibNPt79bovOEVXQtz20SbmatTUEtfV9Y/n++pTNgxoQ5XmjUjbnla7Dh2wzesCwRrUwTMwBgfFQnBqb7XmvlbdAC6RQAvVqfLFuGLSa0AD1vr0slMeN0xcG92Px1Fr+3sHJuyYapv22NLU7TzY73cWWJuCBVp2kByxa1G622rzLLlAa6YXzRVKCwQVpAlZG8WZyDZ9daaQuTAYHbrb5ofJGg2vVeMQub6OvHgxcXUVGUczIVEtVi80pVQDOlVtYuEwOaVmejZUdFBF/GfWqhuwMg3/FhuNPaMt2CYMcaChLC3byNi78NKyuTKM5+mBFVdOjvIGIcbUQxwQLS6NaHaoqtBUSGkgDQPXNy+2p3LMxs/eBQFsU6jhQM6VVhuje9XXJkgzIXDswiL/Gv3CldK8KOu7e0CjIC6gprSNe2duARGJE2m6MhpTUEIr/vVsXBxF2I+DPVCtUCRTtRlhohSy8xglJEMSxtE3R3erCGa/SbRmaS0VlgIsLHMFAikaX908spU4CiQhLzNVV4iVZ89u+b3f+33+o//Ff8QPf/hDnt/eMoReFFfyb/8urCu6zBwP72ilICp88y/+iNdffsU/+7/9382V6uVLPvrsu1zc3nD54Utur68ZxolpOguHmsLvlIVSZuZlJa+Z5XDi9Rdfcrx/4PD2G77++S95+9U3fPGTn3M4Hnh8OCD6aALInPmTf/5PkCTsd3tubm64vrriu9/5HrXCvDbq9XOm/Y6r60uejXuIA/mrB2S4ZpgKl7Ljy9df8y//+E/4+Z/8hK+/+ZrHu3tP3rT7m4u5X/Tm8z1OJuK5BuaiUZ1iV1p22kJfN7bxpmiIgIpYYI7WjSXRGpsoPzqf1W5tQH3MaR7nwjSOrM28xbUstKqUNXPIlYYdpuM0IiIMJCvqQ0DrTCsZcmWQgSiNJCdCdFM+FXKrtoGANe4N9zBXmjSGwR3PvFjSAGvGDmJgdzEg0UK31lqouZDn5gdrYdhbGN84RIY4oCkQW6VVoy2BuH7Ig5V6A4JZ/QWJZrdIYC2LPwd9YmHPUgwBiYa2pGgTrBQHOnf1u9/7HuM0QFLefPWa0/GEFpfcB6dKqhsNDyMlRo4lG6VgrTzUBdoImm0qo5EmycACgblUBEv8lWFHMMcBhuHSwrxyo0lFAwy7gWmKTKMQ2on5uDKfFpaTUqSyhozExhgTH33wkncPjzwejjze3RMwt5VnL58zjgO7cWD0A7Q5cPBtxtN/VV/jMIKw7dd2Fpr2yDCwc6PRxeAdtLZ12icBbrEZrbijF6965lr3SUdMicurS7NLjYH5dEK1WfGmBj6sHLZmZ0jRPSLUHdjACgM/wGn+7fzvvOjpScvWLnmR96QQNXOKsNFaQvTJoRuOVK0ksanBzRDZB+E6Bn50dc3zYeCjYSBpZQbS9TVXz265fv6Cm48+Ybi4It3cMu8vyfs9cZr46Hvf4yPg+O6eQQN3r1/DZWa/mxivrpBaCDUTTjNyOsHpiMxHKNZodNG2lQyBJoFSw6arTMMI0fQQBhq6JXTJVoSGQOxIfxq3grO799Vq912b0TKt0YiEQWmlUucZqQ0ZqtG3nS6jtVp4W159KmN05lgLURspNE554XR45PXrV7x9947H45HcTI/Qgcpffemv/llvNrb7exaPbzka70EqujVQZqGvGy16cxOj1zZ1c3QaogGpCfU8LyVrb4BcNI9Ph5tRaVtTT58ODGlgyYVSCstxpsUEyWoY+1HVKZ1Ci3Yf+yrdWAJ0I44eQquomBuUVof3/XuCM0tapiX7+WtrFLdiLdIgNIiNi/0VKZlN+Zoz67oaxc33+xis6R192iG1msYYkKB+jezZiw44t2bUX8GmPf1mdpc1c4Y0wDzGDnRboOMQk0/UAzENDMPAp599yjDY2fr27Wu3vp2tudDGqZ7sXjZoBHKB+8PC4biSc2HNFdYFQrb1JeIcTmMHaWxYLz0Q0h4koTIQws6yynKjRdMrXV5NXF0OXF0KUFjXlTWvzKdMKW4+EgwQ3E0jx+MDh+ORh4dHs36eJm6unzGkgWkYus8iUTA3xfQX83q/PXXqyZSiupOMq6XsT9UnDcPAObDPBdb+wJzTStvGky/Yl7AxsyN7w2QahTAQQ/TRWAApUDxwBsthiCkREFqEkIKPdu3mnEGrjjbb++0pwOfOWTfUqKMEPVWxc2vFw3xSsH+H6InenLu81g8JseFWQ1E/dFpz0XsfozVlzcYxNeeHJ0h753mqoTfLWsjFHJdE2PIIJCzkloiLMOcDpRYbKwbY7UY++eQjrq8umcYBaWajqyTaFUgdCXVPuJioxQKWbmshXez4/bySxMak33z1S6a7N7w4PPImCKVWHg8nxtHCZT768GOm3ci4G4m7PVNIDFc36MeBq2cz84uXXL34hOPDA9/962+p80ybZxN+5ZX18YE3b77g8XDHm1dvWB9OPJwKrZoLU83K1f6BcRh4nCbiMCIpoWOivnnF8RcvCNdX1OOJ65LZrSvjusK6mPAcQ7FLq9v98nHGti7rkw1e3ZGkW0yeHfYNG1QvklOIxOC0LLF8hVYb65p5327Q13rqyKMNYA3d9ALcEfsg5nfdhb8JD5sXyK1ua0jV0NWoEMSzyZu5p/W+WpsgzVyy+pRAOhopYeOe1lIoDZuARJ/WBaNW2bzP7BFLrdZwVB8/F1v/WRuEgHSiex80ehNnVtF1a7hMD+WC+qYgzd5Tc72SHwLJmzQb5TamcceQRsY0UWol18rj8URcFwjKacmstZF7sdY8WBFQIqX4tKNlWhZaS857Nw2TSrMJ6xgYd8nFcJUpBWI0/jMyomFCuWBZKo8Haw6bQilio2wv/EwQHqlj20Svua6oCkWENI7s1FgkKUSGNLC/2Jm3fAysa6XWzDqbm81T443fvH796xyw96TA681EHxyI241uBZ/tur20U/pUvRt3qGsKwxOEufO57WxKKRFjNqqeB6ACjGPaqE3d3r32Zh/xOqvriNoGgj35ibYzsxc50MPXOnfeGqCYBnNyC8Z/t1JJCM32hIiF7l6kxLNx4HIY2KeBlBLTdME4jlx++AG7m2cMz54RX7wkXV6xe3ZLuriG/Y7d7a3Rk4GwFtqcqUumjis1CHWerQAumbouRjtqRvPAaWeNLlAQagg0EQNDvPa2XCQr+nfTjoGRQTCHLTkDRCLmAFW9iNzCbQHLFBBaiOZ4lAbi/gIZBuI4IcNASAPjbmfOjSGQl4WaF/I8ozW7zsbqDbRRQ+Pd2ze8+uYb3t3dcZxPmyXs08nUr/YV8mv+zO+so+Aut9Vf/XscNNIn69rXY1O2/z2pccSb7SjBGwmbPCRvxFqpm/uZUa91Y4j5cMjWpZ4Tpc2Otudc2Uzcjk91oxMlt2r6Y5VN7N8dx4JCVMVZckiIRqvy8qz6+WS04m2l27/9PTZlM0gR/H03n1KXsmU09eenql27IAam0SmMYkyCcxf35Pl6ep2f3r8+hQhha1CCeehuU8JxnBjjwDDsbD3WxuF0Iq1mYDIvxrQo9TzFqFUdnLSJPbXBagF6VaxWc2TfGwox4XaKpCCMwxOAJE0QJjSMwI5lyTw8nGilUpq5p1anXlldm4ihkaJskQrWOJjofEwTbQdazblqmiZ2o9nkBwI1W525LotRHL/F2fStGw3jtQEIuVa/KSYEDYqhKkMiJKcYOEdPaO99FbRRm918xcZstq8rCeM2T9MedbQnIowxMYwD3Ze+LguBQkTNDzwmO+yjUE+VOa80km027p9tqEDpS9jsb/1B2lyueOrsFDfeqbZICAMxDaTO6QxiDYQ0zyhotFbILZ03UswZoBULETP0LNLDAktZiUEYh0QPjpXQCNofDrV8u2pOOiEYyrmuxdAaKmG2g2dts200wbIdpmng9vaGMXkR2NzaMATaaIsthIFpf0VrhVpn9s+f8XEp/I2/9bd4eP2at199zR//4/8DsSr17o53795xd3/Hj3/8Z6Qo7Kcd/+7v/zvcvnzJ7csPeP7JpwwXl6TLa55d3dCubykfKB//wB6KIQhabDQvGijziePbb/jj//Kf88UvfsrXf/iHnO6PtMcjx8cvSA1Sg2Mwz/fUgKhIFMaLHXeXl+wvL3n5ve8Q9xe83O+5roV9yUie0RipAosjiFsj5+iAdHTIsULzIuioT1fp9GXvG5IoMQ6exlmN25rMjauUSnkoZmPnPMxSzPnDXLDsDGwSCERCSGZFrLaBphgYY2QaXK6YoiH6KFUza62Gzm8bqRJw2lZrPgaHmKzJsPF1NKqBqPE2xT3jtaDNXKVyswMm7faoGVbQxL6vNCXXwloKaz7z0zU3ahVqWZFx8lgcuz52zp8NIyxbBgYJlFbNYSV4Q93UMluc/5qGaIjUMG42lEplmvbspz3TsOMwz8zHI6/fvu27iqPEzlV2MKLUYmFEMpCziboXWRE1W2gNyQ5MbFyeJmF3HdlfTaQYGKRyvUtMyfRkGvY02THnHY8PK6U0jrOFPZUVSrHxt0SznmanaGhbEXF/amiFtSlxmrgcJ4Zkbh/jMBBidSBVuX88shwXDncHTvOJnPO33ar/Cr60/3+jFj115dmefMFoql7446CQ2OO6FTGtta2IU6c4dc1R9NBGC0WNfmgPhGDFXCl2rkXMuri/ryXbvpdLNWDDz4gNfOtuQPr0vLT3Lv3o9cYihnimJqo576XBpiw9nLLXU9LMMjQCE8JFjDwbRy5iYoqJlAYunj3n4uaam+98h3R5Sby4hNvnxMsrds+fk25fEPd7xmeXVoDWSr1/ZF4rS8601ey6cwiQF1rJlNmmrvIk20DVroFi+4t6cdlaR8mxFPFSKMu6Ifb7Dgy54K2DJdnzt0qvR0TczAKfQpp4OE470tUVYRgJ0+TBpIlpvzcwpJkFbF5nltOBts5oLbSaCdXoqCvK66+/4vPPf8mbt285HE/O9rRzIoQe3eqglcBT3c17fYT/R59O6JP/PjfFasUsfZrRG4P+Od0SA7fINaAqRmsyBm8IBTMvqaWSfZ33taXqaeNubhHdF9MmZXaNJahZ6YfIGIO54AV/joJFu5VtuiLYPm4Om6Keqd2UMbmtbRJKsel67TVlUFLyLIbNUATss/skQbZntWnzmsjSsg147e5svp58gtG6lbRrd6XJGWBWA5+2+nC7Ef3Z8yknBkQN4+DhttHOpWb7wzRO7MaJy4trHg9HTg8PvHv3zjXNsHjW19nxqzNqjP5UqlKlWQGvYs/FAJ13n5IwuJHM1X50+nlyx82IpguIewg7Gjvu74/M+Q2nw5HcGsvaWHOjlEAcre4YksA4UANEt3u3ZyEwDnuGNJHCxJAGxmEkBaORtlyZT5V1nnn39h2n05F1Xf68zRn4SzQarf3KQecPfqdG5VrQYpzKnmIbY6Jlf/TC045fXakf3/tyqlCKIbRWyEXKcTXLx1o5nY6UPJPnE0kzYxJuLq9RtW5tnhcbM4UEMoAYx6/qimKZBt1arxecIXaRlY1A42B2sWNISOu6C+eXC9S6QjOr3NqKI7QmtgraaMtpK+b2aYQYyWMiZw/7kUIIxnfUGhFVSnYvdBQtjSEaPz56W9RUjV3fMnk1qlkU+2W8SGEUG9ntdjv+e/+d/z7/9b/7d3l+fetTWhMetU5LkxFRodVASxa5NnAJNdshEk5c7m+4+PS3+B9//wd276WxrifqaWH9/C0//+M/4Ztf/IL/zz/9L/jg6oZPX7zg64sL5mXh1dt3PDw+kmulTSNMI2Ea+eCjj7l8+Yybj57z8SefMO32TM8v+O0/+Pf4zu/9XX73v/sfoNnWUagmUFxPB/L9O8rxyPz2Dfdv75mPJ5bHB07zifr1HT/+4hesBGYCb04LJYNmm5LVAFX6lisgdijVnDcLxCjidImweYpv26aP41NKNuGqKykWUnA3jdaoa6FoNFQlK1ULSGAY3FFKldWDe0IMNsVTmEtDsOJAhuqHBASdScF43QWFZm5LSQRRyLVaY6FKovqabtYkSCCQoBbURadBElMM7C+f0bRxnGf2IZJiY9eEETseENNsVMSsjrEpQ25m3SjnE5HWcM/thK7FmpqqplsQRbXQ8akUBqLY83y1HzbR3VKhaAUPNQ0Ik3NmRYKJ67Am5XQ8spxOXFxcs+TMWmbOHGVL2FaFtWSkqvOsTRQX4oS2HWncc3X9kmGyYqSGE2NspAhTHIgJ4qAMsiBaCC1TirIssNYdYQqk3Z7rZx/RhhPxpHAqlHXl/n7hxfNE3o8MSYwa4BxfJSCS2CVbX8e7aiK7Vjk+Hi1JNhdOx5MVTrnSiiHp3bnufaT7N6+nr1Ytnwh5SjmBXqir9mbv6WSjf4xPF/yZB2/yHWSycbM6L96EtP3s0gatNAqVsmZzbJlPJCnmPnZ5ZWBXg1OeaXjznsxpsWHFkrqLzLk7sMmJ+FRdfBLaz6yzDkV8VzM9Q802TbUC2NDTUAsJZRRl1wKXKLdD4jsffcQHz2757mff4dmnn7C/vaXe3NCGkTYOXD27ZX9xwc3NDWF/gcbA0gpvvv6ahzdvefvzX8JaiLlx1cEzEcgLtazMxwPz6cC6HI0y4qLfKOdirhUrpEou5JLJOXN4vKdksyUNKZCmkbgb0WQWuEs1mnRDOK4rpVTWUpguLpimHc9efsDu6pph2hHGvRlRDAPDOPkUyECDbqudl5myLsyPdyZePxyoywmtmZpXpmR0lcM68+UXn/OTn/yEr1+95rjYtVYxcbGXpZitPRtY1bsMeX/RPWlyXeDN+3/Vf7dpdJ40CAGcGaEbze4p7S/FSHRjE21KK82dlyqbnWunsDWbDPXmojq1oubznmPsEpvsmmTZQcMARRvZ3RtRsdBj9ck6eDp5s45ExVgZDQtCJDKIkKKw218AkHPxAYMSBk+gRs1+3J5A1nmhm/SYo5b6ea3bJE9Q+54hurbBNTd+ZnSwQTaNykAcu1kJ5GoOavgUTQSmcXRbXnvmqlo22uk0sy7ZXMrWjLbC6bB4m6AbfdMcT92lEteQpAFJE3HYsb+6ZtztXBtWCNIIobEbA0MSxiQM2NlUykzVQC2R3CppF0hpz35/RSExHVaWXKms3D1mbp9PVDWtYWuQ10YrZjIURcjF9Bg1r9vU7OH+RCmP1NI4HY6UUi27qqk3S1068G9xotFa20a3T23WcFHPUwF37xmfPj3n3zqS0z/qDBTTrcYUp1D0sdWGNDvKJGJFpAaKr5uqSs5G7diQBW/fdVuI27ffOmRQ4+n59zoH4Nin29c+B/lFtcOniWlE0IqIjQpDaJjfbgAxzq1Bt80qXyrNbftQPYuIHE63d2OCIlE8AIlt6rPVGhs95cl1dGR9GBLf/63v853vfNfoPGpiq80bWrq5Xy+m/X5I6NUeGg2hk9i4fvEBJa+sy0wcduhQuGx7jvOKDhNzU24vLnl2fW0oyuMjo1ZCWWBplDozqTAoPP7yZ+R3e5ZXF7QvvmDY7Yn7K8J0TRh37K4uIY6oWW5b0zdExilRl5lhP8L1JdPpxPx4STkeqacTVHvPNU28+uprHu4i+njv43Z1MNOpB80JQd3TW2ydxScWie3JeNoOgnZe296UNjVOKU1go+UoQW1tEpoLqOxaO9nQNj3Z7Mn6jbQpg6/JWm2UmYJ7meObNcU2ayycETxUio6GOR2qdoTKihKVCMGE3VXNpYpgh445mnUsqpm5gGJ6HrVr1Qv6bl0dxEWywfQLStzyUSQ0ojSi5u39RH/UBBON9sPGnewhsR1MqsV51o1c1ZmZ5wNsXWdz4FJPVfeffXOOa9kOMsUaru2UjkRJpHFg3EdisgZ0jEIKyiDVqGehMYSycdxbiBSN5DhaGuuwowwDdchUt9OmNVrOlLWyLoWQM62a7uN4atuIfF1tf8qrcedrayynmVqqAymzFQW530tHft+vnn/z+pVXpx8B7zUb57puGwnwK9iyI8L0StD+TM8f1/fc87Pv9Cl/FlDcke6MZle10M3SHORpSu4Un/5x0nUi54Kun6v9rXSEWnqx8+Rc7YCd9jfZGlXsLFJH7WyS0RgFdgJ7sYnG1TDy4vlznr94wcWzG4b9jjAOTNeXyH6P7HaM19eM44TsR+JkjRFHsz9fHg8c7+4JuTEqtMtL+54pWQJ0rS54r2YQ4VNio52xFYnd+l5plLKyLPOGjqbUJzSubamWkr1qoFs8DpcTCRgQ9pdXjLsdly9eMu4vSOMEafQ8oWRsCz/tupaHZhStssyUdaauCy0vtHW2tOx1QZsh7W1ZmB8eeHz7lrIYit4kOl+j31M4AwKdEvfr1+x7f9xR1vf+6Czq7u5P2tQnQ2L3Wc9UIPu5QJ6uYT9wmnZqmb2/nnMirgGT1rqvD1uylzr4RCAFddp194ayl32kWs3T/PtpO5+pEqzGcf1iX+9G0zHBufqUKsXB3m4Tp+PY2duTsJUu0j7nykjrRbs3Nj7tMvmH50+IG6AQjC1i34X+poIaIyeJEEOiZyVBMM2j57v0aqm1rufoeSOmx6VWlsWClWnFNWL2PtWf67Y5O8FmpK+Bzt5Jw8C0G4nJQLYYMJF+KMZoDkKUgtHxrf6tBFoYaHFE04iGAQ3ZqVdqwcGlkNdGXipzNUBknRdKthq1VliW5clkyPbU02G2565UZj+nSjm7nZlN77Z5/rmvb91o1KrODT1/UdXmEwEhadhsxkrJfujbBME2w+gJjoJi/GjRRiy2kIRe7EUkWQBLH9mFYBkDKUTzwtZGaStLUx7W5pt54/E4m8sMlvYrGogatiZFIi6W8zrP19wQu+4iOQWj0rRsvsvW3QroyjR0q6+C1hW0mXd18EC+6jaoTcjFmqYS6iYAtIR0p5uJdZSqOMqCNyCGW1xMlzRpFDK19oveUQdl6OgVUAYlDoEwRf7m3/5b/PB3fmTp0/6Ju3G3/TyhVP/RHQmmUczCyJq+kFjzSlkzYVXyoXB6c7StUxTixOUPf8TFX/8d/mv/83/EMJjoSvPC6d07Xv/s53zzs59wePeW+1df8Mn1FZci/PN//J9w+LN3vLl74JcPC4sqdwL/y//0/8r1hx8Z3aTzBHyd9UN2W8yOiK3HB/7wf/e/ItTGy+uXXN0849nLD/hf/2//98x/9Cfou7c0tYmT6EoUJQKFc5BOwP6d4mBanxhtbVWzRLWWrJGCozACEgZH702bFpoQStgoUIlEY0YVQ4B8bU37kXkpPJ4yDDsfyTYXA7YNxRcNrGV1MKUaj7KZ+4n6GkrBKA8xJNA+Xcs0tQC9WTNjiIwpEsO4PQ/RbamHcYS62P1PEdk2GBs5h2oOGRbK6Zkz2OG/Gyab5KBWgGukSkKxhiaFRpLKniNa1zPSKebUNaSBKAO0ZMeWQJgSEgzvvXv7pRXeTSjVHtRxHG1ttsJ8vMPc2ZRuNywSLZW3VVJdt2IiqN2rUpySFQPDoIy7RhoaVTOJQqCSZ9N6hAj7XURUOJVAnm4oaU8eL6m7Z8juGSVGDgJrbGiohFaQtrAeBg6hctJH8rqwriuHw0JeM+uSeXw8UXJFC5v4lWrXdUjJ0G4VkiYDMmIzbU8X3vzm9Wtf7WmmAGzhm2eR97mpbz7R7iYRvWjfaLTYuupFEdjplJwy1Q1NLBQteLFcjMYYLHuglMba4N5pda01jrPZa9amIKV/6zMauL1/bxLcESil7kAYrEhpSi7mFmNfxCACqs1IpIvZvcnYaeE6RG5S5DYmXgw7Pri84ru/9V2ePb+lxcDjeiA8ZL733Q+5enHJxcsXzGkgi3AALoIitVJPJ+rhRHs4cnr1jlgrDaHudkbv8YndRpluJuoODrjFYOGVG9TodKpcZtYyc5gfaLVwsb/g2bPnXF7dkKYdp1yZWyOroNOeYZwYLy958dHHTLsLdheXTPu96VTGkT4tKnZjre6IVnjFqITSkNKo60o5HlgeH8jHA2U5UpcTbTnR8kpdjui4t/PneOT05g13X31NW7PVBYHNpamFZs5Vfr5vDSDbMjt3F36cacdC9dxY9L83QwvZJuk4ANapU03DNsnuEtMOym6W/r0B3Sh5wadnZrcckiVPL2sml8Kai6HpWDJ6bQ5CSTDHPoHoxjfJfz5tlhtRtfokx4NRY2QcBiuIS/aa0CjcIbjdP2Y/3Ny2XwGVwLquoNXqTRWC+prX3mGL/VylGJtOzNVxnCaGcWSpXgMGP5ucgpaCmTUkWZHmDYEasBubaVmiG5iMgxkUhBGfPhcejweKXyfxGmKMwXR/rXE6mL28YoJyxWnPTpcyFoIb0IhT17IiySj1w2iGIjHCuqwMyYCv+XTPKsqahKsLOw/mGCky0WSPTC9o0zPqcMOsA0szq3+tK9QZLYXlMPOolUM7sMxHlvnEfFpYc2GeC/O8GPW71G0RBjlnCp1Pn9C3KzZ3729xNH3rRsOKpmgL0dHeBvQk1RCSuRbU7Jv1efog25MV6TZciFE9Uhrpgpvd/pKQ4tbh53VlLrPx6FtjrUcXXFuTIgLl/rC9x+rIfPAHqh8oIXQlUSOIbgeSSDBrNi/4a250TmAtxYSeTdFmrjdjGs12simjCPthJEUx553BrMxKzhtqmXOhurNV8HG3hvN4rm5NViAOCRGxws4XSkWIaWA3TEavqM0dCXzMJWErQjLFOHwXOy73O8YUWWdLr0QVrX7/gukWNpqAH7ASAqJxswg17vHEw3pPHifq81ubtEQhTYH9YCLIi6tLKErLjW9evWM5Vebxhs9+999jCEIoK+XhHevdWz75b56YYuL6Ys/Ffo+WzHp3x7OPPuTygw++7VIEIJ9O/Ol/8p8z7Xcsn32Hi+e33H34mm+++Zy7h9dknFoTlFgDsQqhCX3IIJjvNYAksfuas0+xrDHt6MuQohe/HkjpgUhRAiGYZqQ2t2pFidFChJ7tX1ijIRElE9uJvFjCZlP1TAor8psIlMraVi6G5CJqHLXqeqFi07MQGaaJadyxu7qm1sq6nLi/f0ur2Zwh1Gh/tWQzJpBIWwqEyBBGei5IkoKHr1JOszVRyEYbTFU33u/VNHB9c8vF5Q3H1igEikSOas9eaREpJ0JbmFpBskCJVBlMgaFCDGKJ5RK4GnYECdyd7ixYqayweMZIDJYo3IzmFnGqYC0GQsRAGo0rm0tmUfNiD8No7jJVXawYaJIoUSAoh7YQwkCNjfk0c3O1Z7+75tiOJmIMoHFPqfCQM6cVVlYWChIXJN4Ta2I9HMnv3tIeHtG28jifaOtbXo8NabMJWkujVaPOtGa/F0mEsdMlbO2EXgg3R9IwmgBNkOzI2F/q6fir9erp6iHapKFPuTpAYfWJbufBexkb/XzqBvi6zQ3odu4pmvGFUX2dopczy2piyKbVLMcdpFLPOFiL493qnvn+Nc96R9x1yoGPrv9E30OyAZvEdseq+gTVlehHgPi/ndeNkkS5HiMf7HZ8sNvzo5cf8NmHH/GjH/6Alx9+QGmNf/HHf8xXr19zygs/+NlP+OR73+XT3/oeH3znu0z7Cy4vrhgHa4BjiITbW56lxMvd3vbLUtgPpq1kiLTsuUBOtwS1zCyxZ38zY2kW5ldK5v7+nvuHRx6PR652e8JgDcMxZwKRYWgM17dcXFxx+cFHTJdXTBeX7C8uPUBsML56MPvgik+cDea2axyMZ189G0OXleXhnf+653T3muV4YDkcIFsukuaFJb9jXVd+/OWX/OynP+P1m7eW/iNhE+xuU7H+EhPZqnRK3vbH7/3G8Jew1UodZNuaBj+LKmx6wjMId9bLnSusLpTG6KhiSdpVK92IJoVoAXcXFwzjSEyR07wwLwutzRRH3BtYHkUzOq2qNVUNPE1cGPwaxDiQOkiZBqbRzqbL/Z7WGnlZjBJXyhMKrnVY2ppZ0xajGwumRe1ci81NTMuWI9HNBWyINriN7MD1s1sur67RmMhNmYvZvLfmtVZdkZaJKgRNoMVrAGNzhGisj+5kRhDm9UApC2tezKJZ2/u29AQiPZi6+X7hOg5Vc/vYbrls2g7xBrhKBEmIBg4ZdLWci6aWnRSHQJKEfVKjxoGmypwzp1XJbabJa+AR5GtokfU0c7q/px7vkLbyMM/U0xvGAaQtNm2vvb412UGr1vX27CB8PfXp7bkNPlNR9Ym26i96fetGw0Y3NsoxFF37WvfGXRzNaO5AYH/WRXbWtePUlP7mxHmoxnlN7pxBgOoWn62Zn28umdxWL9J6MJNS8lN+2DkQLOCooZgeZAtpEyGIXdTuctWvVnPnG0VtY1fb3DtCmmKgZkfE6W4xgXFIjGNiGCI5CGUtxh10fq/bXhuyFuK26Mx5qwv87KBrzS6UuQUZj28cB0QylEwu1Ruv6mNAbza8w970HT0EqW/stdDlYeo/Y7eDxjGg4NevOUos0dpWEQvZC2J2g2kXmcaR0VG+WjK1mCVbIZAurrl+8cIasVZ490ViyY39Z9/j9uaajz76kJvnt4S8Ul99szVhVStfzK/+3HX46e4DopjD0+HzV/Dsmrs4siwra62spxOtWBDcxtnsDi09CFJ8muR2J9vBp7ppicTqUkTsujYvVLZD4snm3tf7VtBI2H4Zucki+pJYSF/VamNoxcRfaht2VtvYJ0yf07CgHmvYExLV7pFPDkNKpHE0tLGWzU8+SDDOd39TPvQ2x6gAIQHueEW3I+w/0ZOiVrECw122hjiwm3bsLy6tMQFWtYwUUUEY0LUSSiOUaGOfFjbELQimaRLxBt/0F9SMlgVytg3J0d2AFQatNZIYmuw7nHPlnWPXXMuBF27y1I3dig1ztxFyU7I3cLlh2hoSpUXjK1flGAKlwnGGU8msbWVtishshV0W2rKgx0ckz9AKpc4cdGU+VYJbdlNBNG4gXEeyuiB5AzvOFQgdeNimeI6un8vf37x+9dWL8uiAktBpDfjWrvQwqqcUp3O1L9uevH0SuEW1nUtbFoy7vtHUkn6bpefmkun0mf51qmsQtiK03//t+27faetzLAzsfMD31zmh+P1f4tSFbmoA2DmHTXDHGLkYEje7kQ+uLvn4+TM++/gTbm5ueJxnSq08PD5w9/hI+ulPWRYzWiinxabEz15QL64NMFFhEmHY77n4MFLzSl2zGUKo03po23S0T5WC06BDkM3es7VGzpl1XTgcT5xmQ1flIjjlRajN9u9hnJiub9jd3HL98kPGi0vG/Z4hDTy1Ke804s0NSny73niZNkGqJaN5Mf3f6ZF8emR+vGc+WHp5UtMztHWhPh44HI58+cUXvHv3jtM828kSgjM0njybel5B26vfan3/D54yQ/on95Unv3LfbULi9CGkM2z9034NnOxrv+81nV7kB9+2t2zZaNsvOU9h/PHpuojq7y0iBBWSytkfRazRjwgS3TQnJdIwuilQM6ZKq+Bi7H7S2PGkpid0YMjyIdhoz7j2UN03sqnrNrx+lGBn4bjbs7+6Nup3LtRlteNBIQ1Cs0GJT6D1SZNn76mqhzxroBe3ra4GeNWMUP2MES/Mn+4nuk0nxSf49PgEp8UH1xF2F0j1+6EIVf1sqn3KFSgaiUSqprOb3WIuVadZOc2ZXLye0AOtBaQKNWfKfIR8QttKZuFQKnNohI3SbIY8in2v3uh2oKav1L5fnVdZP5f61O7JWvxzXt8+sC+oH+CVc91u3aIArXiqN34TpD8wznEnMyRDXZZS0GCdnDYLphvSzpApMbFWFJucXOwSSz6xrEeGZj7kpeKCb/sJN2uzVs3yVq0waRFqEqKG3mdYsRZMIGv0leCJxJyRRcXHlbaohtQfwmr+1KK0UClURJUx+mVsEJpavkc+EQVCUChqXFHnbBlt0d6HjecrTZOJzKsjdGmgxYFhd8nNzTXLemL2CYUkQz5LsU1IMJepIQVDsqnEoOx3I2Mb7GerglRHw+jWc2LCdBpVFzrrMrVhG1HeXu6oUWhDZAgDiFCpxrFUmI8H1vnEOp+4fL5jGK653F8Sm1Lmmc8//zlvv/maw90devuS4ZNPufrB97m8fIm0Sv7wLTJNAHwxv+J7/+f/8M9dhz//B/+Y7+4/JhD46OIjLi5v+PyXXxNeP7B/9cBVm/hwfMaVTsxUVpRVFI1KCcqyNXaR3iEUX7uIu431g1HUR7+F5KbgquKbraMtQSA6ai22/jNGGZjffWUifUkM0YrsQRStC5WAxpE4TCCBYQzoutJyZg6BGgzgzssMCjFNxCExREHChAJLqZR3D7RaqcvCXkw0uZTZPMyxiVgjUDWyVC8CgqBhpBHJa2AYbNIzXibIK3VdEU/bzR5wpXHgEC9IMlnTczmS55nHx0cWAhIS4zCB2L1cl0fqasVWdkeLIFDmEwKMaWSRV9bIJRilEYdGmCzhdWmN1a93dYTOmIXmXLNUOM6roUpNLZvH0RDtz5iIuY5IQFtAS6DMA8txohZBy3Me3hYObw8sj0fyWliWDPrOgIbcaHlBtdg4xY/doM2cVNxNS0MjazHHFIUko+lDJECzjV2C0oJlmGQtiNnu2OHsa0+iCfxRcwJpAk0Hng6uf/P6V199otELNNNu9ybbkeHeaDzlmHvF5uc+bEW7HabJXZnGcXRLW7dd9sZkKsMmYpZVvKiwyQpwdpz7FQMSfdJwbjbwPqEPYiBR14T1qSuwvc8gwYqwXhF0RFyrg1euCAvCboxcpsCzceD5OPDh1RXf+/Ajbj77lAJMux2fffopX33zDT/7xc/4o3/2X/CH/5f/lMv9Jc+fPef73/0BH3/3e1w/u+WDDz/i2e0zLi4vubq8oA6RMkbu71cTdGejpIhWgrp9ZopoMlsTwdweS6us68rjwwOn05FXb944XdWEx4pZgsarPburGz797R/x7NPvsrt5Tthf0hO/xYFN02Wei+m2oZobtObOfMXErsdH6uHA/O4Vh7evOdzd8eqXvyAvKy0Xrvd7Ws4cH+64++UXvHt3x0+/+Jy3j0fW0pA0eIHYFw7b/X3Sc7x33572A/LkIzZ02IEs9fX4lLq3fZ7IttZTMFpTo7rxhCfA/2oz4ohzxXSsrTabVLx9Z5Rvt8GttaGlGCikVihHD+PrxadhJ4EV0yjE2l08IQ4DQ0zUYM1fyYXj4eBObDaZDhK2fbz/kB2uy8W0RS0ELHVDaMHuIdqII+YmmLOtc9fKFn9fMY3E3SXD5Y1R7ZbCw7xueVb7/UQNlZob+VjRmmkle+1owanaZixeIbkkAGo9EaNwMQqa0jaZP6g5zNVqFK8mRlPv2iSCsQRybZv2M8b0PlDgls292bChkHt2NTidVk7HyuFwR8krZV3MXKRZAro7jWDfzDsqxKn5jdjs6lSb8dk9GPqEwoYkHT/Vvo+ce/Lt2QGcqunraltfsfeuf+Hr29vbNnGHAxNqW7hLPQuQRM5vuH9n7YmCdhGt0rfAlLNFm2wCORNzV2KLPrEQd3ayh7H6v0OwMS1ihbls1gveganxZ7vnuRYbZyuGRFVVD3axsarW3ma6cJszIqLhjHDRmwOMWmX8+MA0RLK7O+TVA8Ea7vRkN8/7NGor/n0M7Wa7LAkhkqIFFaZhII07W9TzzDyfWJaZU85mh6YYj1erUYKq0JbM8eGRP/6jP2IcBn7v936fZmMdmwL1hdNM4LOsKxSPtI/FpnMqJB2h97GD01RyRFLxDbNuTk6hVQYJhGEkBkVKob79hvu7d8yPj7z96kuWwwldM7uLKwYRdK0saaGVwum48uzfoJAaL/b87f/p/4RxP/Fb+UAVoYbIh7XxZ7/8nD96uOfV/TvyfLIUzg2pKdsEw9Bk06qwLdmM2Vb2e2PuPwauCIMXs9sUIFrBUNayjVMbXiTWBpKpUlnFJyyiLguH1MSauBDITQhhJAyJpa2UaoFTmv2968I+ml93SgO1VNskFw8VVOOS0orTi5KNcPuxJuaQYRomozpayE9zn21zSKoarIl360kk0YaJNo7EmxsuPvqQ2+fPeXP3jrkUHo5HtPXi54h4um47zdTiGRDYI2SDN3NVmwabuggwBBPzhSasJZ83OW3dcNH8+W0nsXZYLIRso6qD6fu6lXF3ctCCtgXEwzxPC3MzcV1tM6IZ0UJbFlorJuxr2Z4J9fA1+oHoAkLpYIU/u6KMEsxKe5v3VkOyQke47A0KNnrXiCN51e2K2SZc3eDCL4IZbnyb3fyv6OscpmkXrVOVrIlQpyv1w9SO0W2S6+tH3ivcbY9vtVqzWgJVqhVKg58bIluDcFbC0mFAtoalm4L4NLQLZS1kzxOxlY0O1VCobPzobdtSRboLiDdRDkJuyKKBp7pVEOaKVcjzwkkOvAmvkLWyvDvw4W99j/HyEsaBF9MFV59+xqfPbzk8PPBwf8/963dobtz/9Bfc/fIrQhq4uL7m+Qcvubl9xsff+ZT91QUXl5fECEJFtLCejtSa/bArUAt1Xeze+N5XWyW3yimvHOaZwzwj4m5JXZMZAtPFFRc3z7h+8ZJhf4mkkexubnZMN6eUnWlE3eSjU+fOjUY1lsFyojw+UB7vOb17w8PrV9y/fcvd69emXQim2lpPR15/8RUP37zi4f6R0/FELmVD+G3NiF9vtqnte83H09cGEyv69GP9BsuvNBby9NP0vKw6dIue9RH4+bTZ24bAmBKgW51mdLbzhGRdV0ox8GeIbu7RzuecoKQ4QDhT2VGlqmsLarWmEpv4T47bBW+Oiwvtje5nuQuq6vpYp2tLMCfMFmxyL92cKtgZ6vC/PplcxGg6pF4hh5QYhonr58+5vL1lf33D45t3LKVynGebpgRhPR2RZqGR6+loAZAtm0WtswrM6c3O/uBU3GR5s8QgLCX7REZMN+mMl+ZIUVMIXXOL6bfs0vmz2nooZ3+G7RpqzWgR8ilwbAtBlJqPiGdkrcuJ5hlpWvq+5Zos+vqxDSC4QYDdF3suYpS+OdjHb1vVuXnYXE/7pKJvWb0O1L4mz2fRNvH4t9poaJ8eKNFHTdoazUe+QZL/mWybOFhQi42Gzl17CAGqF+LBvJwV8xbuNya5zWWt1cU0fqD0bir6k9eePMPe9PRRuhWEA4UzaqC+CVs6s0KyC2+uNZjC196p+e3ImYShYJ+jzcW/Yh17Lmg1MXhes/v/B+ffK2KJQwjW6fdRvZg/rV3bZh6fMQRSmhjSSIoDTQ3dOc4r65rNsqyP+6QTnRrSIi0X5uOJn/z4xzy7ueF3f/d3Uc4Wwnpeb7RSWZeFOttIcEyGFNOUQceN0hEns2iNMdJSRIMaLuUbUNRIVAvcSVqoy8zp7jXvvvglh4cHHt+9RdR4lxfDYAnlfvitOfNwPHLzb9BopN3ED/79v0eMkKKylsphzXw3jex//GM+/qf/hMefZQ55sWaqPxzaOajNH0Arws+1oE/sQugjCkMKJLr4K9KcFhWTUR4IhhsUbYaMbPuypUJbtFAhepaIbWE2/lWxjy8NBjGHlFUzpZrXeCiGwlZtDONE8llFU9cArHZDNeLoaSFSCcEsCXv9VDH6XEUpiOXBYEK81oqhY83L+ND9+P0ATAkdBsJ+x3h9xXRzw/r2Lac1czyeiE2JfhDZUFAtAMuzdFov6sQcqDTA4GeFoAyd9gQs1Q5z89jvG6rtEVXt45IXa8Zl9cOp+vO9OQD1/cZcbySsoELVSJvxp3u1iUMrhGbW00gBnUHapufZmu6+WTuKIxpwp0JSF8J642HMatNgbJuTv6uO6Kk4nc2/g6pN2JoDMNB5998ONfqr+uo5A5tHm551GGw0Bp7Uf95s2Gfbv7U3H7J9rmKuNlWqmZc4MMHmTmcIZkfT7Xn5Fei6q/71SaG4ARVhe+7sLdgz1ICeYeBHJj236sky8n/0dYl/rFNtfIpoWQOZmRN3RVnePvD6p1/w6devuH7xgo9+67tc3Fxxc3nF7sMPyMvM6XDiZ3/yY+7f3PH6i1d88/Ytc84QI7cfvOTmxS0Pb3/I8w9f8vLjD7l9fmP7a1lpy5FasmXj1OLT/byd8UTTIZZWWfLKaV04rStjGhiiA4z+a9zt2V1csb+6QcYdGiK5GlprIBt0Glt/Pqw39zNb/BlEDYBZF+p8ohwfWQ8PzI93HO7e8vj2DYe7O8Y0knYXlLZwenjk3TevOLx5x+F4ZJlXitOgFXwqRa8avYA73/tz0/Gri5Wt2dj+QH/1799fQk//rjcagheH3egGT2p2jcCYogNfppWp/b3391+8SUAJY9p2OGm2FxFsiCudzuRujdu0sCla3GI9CrHZYxbVaFDmvtR5v24QINBpoSFY89Bqt9XFs5twCpVQnCILeBPQNjMffK8PMRKGxP7yknG/I44jay0sOTMvs9kkq1JCIIVG0EpeLOPFnKH6FTVaexQIYnbToo0hqTlSiTnHtaZANBfIbTrRdWH9+gp9UtoDQvv1s+Xi08/WkFDQltGsVj9krL7MB6vrpLm7qRm14FptK2/tTBVvikA3pol9b9t0WkzbeuuN99Y4SP/92V3y6dLsrfqvrsbu2hpENrr5n/f69sngBFT7GM02yBT0jPz6wItQt/FfCNgN9U1Y/RBdq6H6otEKdS2oLu7eZLy50+nkdluWS1C12JhQldIy1MUuYglejChDUIaYGGNyUVOwReF0J3LZOk3Ukq9TiKRhsDFXVkozUV/VunEEl1YZXBBbi3HfY3f3EOHhsJjIR5XdeIGxywNxmmBDzL1wG5Jb8zakFH8OhRUFAkEGdk3QGhii612CshDIkmgMtsCC/bz2nXQTTWlr/Mv/8r/i+uKS8A//oSPXgaLq4jiQZtqSMCbqtFLWmcP9G9qaIVuGxRAiQ0yUd8X1KYlTWWkCwzSR9ibaK0t1dEm5u3vN47tXvPripxwOdzZWHC+4vH7J5eUzPv70O4zT3tySSmZ5eMeXP/lTPvt3f+/bL0N/NYV3jyuK6VvG3cTl9XMeT0c+fPER/7N/9I/4j/83/zFvX3/DYGQmqk/T7NDvYkuQGG3krECtDMAgQhgMzmjDAM3W+tXuwilnwtXtxGE9cXd6pEixpjuO9DF6DJakmlCmGBzNUxvZqmllUmhEoiOwCRVrGFUrmUKMvnsBj8uJeV097dfe/5AGVJQmlaILEWW/39vkztdXViW3hqTRJoxjsvC/1iitj9qD8WsJjGRCrR4uVGDN0GZO36z8+O1rfhwS94eDGR/klVILSZQQhTQm32QLUUwkF1NyXrY/z7VyODyaII1GCoqpRqCEuAk6JSaCNsqaSWMipoGSswUKRoFhZ0WGp/i2aoF41g8IWhezbe6uGe2ItncEuitOsQyVIAwJVBotKOL+uFYHBvDE736QbMVAwIoGETQJUiPJC4nQJxgaHMgwQKFpoKiFmEWERLAmPUSKH/dJIp1iqVKfTER+8/p1L3nPbkq2QuZchwvnk7YXANCr+OZTKntq3TUQMSqrWlpvSBFQalbWxRzOWqvb2ZZb3ZpDik0ezOHSCpLkZiop2b3tH9opXfjbATsnbWhvYbSq6tkSvsb953raKJ2dhzqSb+s118ZpXbkvjVesXGrkVhNfLJlvxp/ziz/6YzINYuCj73zMJ598wmeffsZ/42//PtKEeiz86c9+yut3b/n8q694XE68+fwLfvLjP0WGSJwGvv/D7/Py5Qt+8L3vcnOxJ4pweLi3c1mVVO08LdrM9rcWlnVhyZmlFHJTJjE6q+kP1QreOEIabK/MFW2ZDVcV04qajrJu0wujt3oRmO2iaIC2LuST0aXWt6/IhwebbBwPlMWoplEhVuXh9WvuXr/mzS8+p66FpVbW2li1sapl/zTdbuBWtLVtmfVG9knR9qT16NQTu3vd6czvpRjldVukvWl2gCKJ6TAH/0pNhWmcSL62gk/K4pBY1hWd522t4fWO9d5t+2Uu3T1V26ca2iBj02nc8t2bBnWautazFqithVgV0dXXopJcR4tYG+7yUxBrJLQpucHaGqsaHVCDFfwNZa2G6ItWomZCqwStRAVoNi1vhVZXvv7yF7x68wqJA6/fWu3RagWfSDcFBjvvo7o9vAOGBmKr5YjRkCpmbVyNwVF8er2u9v7CYAyVANsELoRgk/3oZjEpWmMm1SZh/bppBzx9Clo8cDdEKD2gsCJ1JgU3YQodcJKzK740lzOc94+uITN8TX1fFAv9rR2AsbWwWTz79oiehaadutkVb0G6MbQ1ijw5j/6tTzQ6HG5CnL69pW1zFBzJfbIROEDkB6078ouJHUNIREk2yhM50xGCI0ndvaNfFInGLfRFZt1oOHfI2OeaKO7s9dvdL1TbBjgI1rXi2RLdbcACbQJVzsKe/hnB5tvbAgnJhCp96tFb7+a42iYMFCt6RHp3a9fpKfe2C4fs95VSF3RtpCEYVzAJraw27qvlnEuwjSBBWyNNE9fPbvjRX/8b/NZv/5Agzlv3ona7L8kudPKQujBGNDbqshrSMRtXdc4Ly2khIJsLg4iga7b7nAsB8RF94/7+HcfjkazCeHlr4/ZnzxnHS4ZhB0OyjQShVLO8K/XfMPFYlbxmRCI1NqQkpqYM08jl9RWfffopL29fcHN5ybu7bEYGIqzaXSaS+XyLHVaJ7osfGePAEEfARVPS2F9e2Gi/9sYW1nlhXRezRu3dvwgpRR+rA267Skq+11uTYKBQRXVFWkBqp9y4aG7LK3f0QA2dKthUAJ9mFRdd9oMEgDhStdLE/NELUEKgOj0whuB2vQ2RuvGqd0EQLYgWBmmWKzH4+CGAtpX1tLBWJftY3A7C4kiX2GAuQNOCSCAmP0A6yhqeYEjRpjMxekhliLQQDeHC9A0ayra/4Axke84sUdVG8+cNtF8KRJ021lBxrFvseYmiiDaaZHogmq3tLq61V3s6LQ3S9YEbmqxPUG5j0Nj+2PckO9D7dMWKggaoJDtoe1ZQN4nY7qU+AWe2b/ib15/3Up6UdeczyPG77Rzq9Zv9nd3QLWdJnJaL0CfQZ/qNa4pdnyj9976fB1ynpW4lquLroIMasulILHPHCVeum+rghP06f19rmARiRKs17ps17/kTbE968l7Fi9WisFZl1soRQ5yXpjCfGGpBIpzyQtFGLYbk3715y4ubF0xxZJIREbi+vuY7gwEUS818c/+Wx/nIw3zky8+/4P7dOx7evuPmYseYEjEI+3FkGszMJAZBQrS9sBnqHRBSjOymiXEYGVKiVc8BaqaxMu66ngvjM8vVEfpOgxVnVtikyUxcXKsiSl1O1OOB8vhAPjxSTifQxjAM7Pd7rq4qEbfDr43QGoNYuGppBtQU+pxStyb2XGN52/fkmcfvQ9dE/upTfC7QOjHzrN05l4FiVS3YpMKvZ/IMiaYwDQNDSsToBh9qIFPxX72WCeL5Gc4EMRONJ3WjOh0Ur6O05z7Iec/b0BY2zWLDhMwVm3B0aus2EMbupf27C5ANcCo9C4Jme6CDNzbpO4NV3eU7NqPaighhGJFgNUWtmXws1sjOJ1AHe1o936MarUZtPhn0Qjz0ek/9mmjzYjsyBDMBijEwjq7/i5FVF9dJ+B6i3lD5xMemSdY0n6ccbPfV8Kg+iXPjlhY2zSxiDWBQiH0vUi/04b3VpE/2uX6v3FKC/s06nTiILdLW742c38+GocmTfU/eX4tPjll/B0+nc//617cXg8PmCU60m6RhsEJs47j3Tff8Zu0m2NinYovFItCNGlSKoRQh2IMkG5Wq2ajMKhIkRMqpIljzYeKU5l2z6xWibyoUOme3tUzrISe9OECRWN2twBYRCpIsxyCg0Do7TSjYDddSTGwdIAyB4hoMUkCa+H7gJUJvPhyVMPcNDDbpfNw+MvcCxzh5hVwKucxIbKQxmbB9WYxjWlZicgceF86HYMqj/fUlH37yCf+tv//3+dGP/rohQr0Z8jWlCKQe85aI40Bix3h7aVzavKIPRx7fveM4HzicDgQC0zBwfXFpAXDFEsQJgbSfqFUppfLu/p1ZPk4X3Dz/gIura15++Km5s5RCCdUOAgmUfDJLSPkWq/TXvFSVdV5JaTDb1JKpuTBe77geIx+3T/jogw95+ew5jw/3lqEYxBwk6Oi93a9aGlEGBrH1MCS3Mi4zDVs7t8+uGdPA8e0BqqGZD+9OHMvMvM7Qwtbtj+NktL+y2rVpjebCxCDNhXwNbRb42BpIto29EQlStzUk0TmX1TbDKpaX0tGHtVZiCAwybBxTDRNryGStFHGSlgi1BCLBcjiCBUdqzNAWQitcRrP8qzWzT8qQAvvdhHoq62HJFqq1rJ6NYTQrsAyRWkFiQwKUVhgGs/mttYI0m17AZgE4hGhoTayM48Q4TvY+VSglUPKDhRf2TqrTG11zlNfzhAR68ajbTmjW+TZFlWDc3uTuRIIhk7aZ2gm7rUS16W0tvvEF3axHpZ0B8qad/2q8ZEvfbQjeaG5OQA4uqPnTEyIaTewYt4wM8VBGO7BVe+Cn/fo2qNFf1dc2EOgNgDs3iTv5bXwReL84x1BH+2V7fexibxdk2tc5uybZWWFI7cYYcHpEoVGLOy9iGqLo9IIUziLM7qvf3Ze2Mwn7fsEbF4fk8CUDsRr1UfuUS7amFJ40QF7UKFBUmbWRmnIIFji7qw1WgMaujtTZ9rC3b17x+S9+QUwjVxdm6vHy+jmf/fAHXD17xoeffcq4n5AY+eL11/zyqy/56S9/zk9/8XPWdeGPtLEfR/bjyKcfvODFzQ3Prq/59NNPSNNkWTGlGkBQKkkCUxq4urhg6hN08zC1ZsSIPcazbzZ1Ev87tBkF1QXh/XKoWOCbdXJGa2vaKKcj+fDAenfP8nBPXRdEld1+T4gDyEhbCm1ejQ4kgctx4rQWsipraxTBreG3unu71v6f6Hn7efKS/hnn5Se9GT7/beig6VMnOu0rUxiHxDSN7MbJcpWkUpqyG0dSMopzziu5FtaSWdaVdV239djzWEJvdvX8HkCQcNZ6BG/gNrrPk3KzF6N4GF5TyA2kVUf5g09JugGChaOKiJmMqCdLV582iC1eCUpM2FS5NlpbbRIYYAxCbLZfTmLZZfvdRBwmGsLbhxPLvDAvKxTPtAnBpl1+bW3C4I2GU7dEvMnpG7rYNbcMqsSUIuOQGIbBDHoQ1hY4lndkb5iNhm+FvNF42zYBMvqw3fvwdPLKGRjoGq/g+r3g3XTXYARvHs703SfTCXw6hGzNRKdyBXH6cSsbbc4AkL4qfceRTpwyepf9GdvfAT6468An9F77yT/+3NdfgjrVkZk+u1GQaqi4OzgVH4/iHDvExKhJhN0eay5S4mJ/RSkrJS+sWTdEKQ2QUmScLt0NoHCaj+Scycu6CWAszMXEO7vRLNRozbjpzca11cebWU2kJsCYom/iaoeFRtqq5JCJvtENwehcy9InJLCUzkus9ORIbVawgble/SoS0Slg6vkKJhoTBj/MUgzm9e8LoFTrqGMUujBdKORlZj6Vvr7Yj9ELGkU0cHVxxYsXz/kP/uF/yN/6m3+T3/87f4dPPv6MadrZEK47kAxhQ0wohc2nwwt9VSUNE2GYGIZLbq9uuf5o5XT3lvnxkcPrd9w/PhARrna7DXk4PL41NDgKn374MVUiNU0M+xvSOBLHiaIrrRXWfAAaY7ID00bfwVHEv9xLFUq2B3E/7hg1wVwgZGJQrocLPv3gY77zyXf42c9+brQD7ABpKmaf7EhiqyZOVA3cXF0ziq2DZTYe8Twf+OVSGYfEfhytUWyVpcwmehOjVZgjUmFdF4IItZkfO1rJeTa6jOCUQwhNXbskXEzTpisVHagCOUDa7wyZLJlOw1hrIaoSFYbxAglCjYG5LoCgQ0RHs/cYgzBOI9N+IpFIYWAc95xy4Tif+PwXP2ZMyjQKL64GxpBIMhDraghSsI2/VMinlVGrHSpgVDzYjAZCDKYdDDCMVoy1Zg1NUGEkWTCSJC6HvU/sQHVBmwUHlQKlCrkIy8nsN2mRVrxIJ5meCnwvsPU7DOZ2YkWHVR15Xd2hZaAWcytp0tyhShDMn1z9mAcfoTsWF4I5tdhJqu473qi5bRWCDH3jNYm/immt+ras2ix7Zogk9QOometUd+7r8ZCm3sGzFXDELW4H829ev/71FFFT32eNYx62ZqO5dkc8advwlm41DtM4MiSzb661UrKl4fZgvHEyy85hTEbZqIVlnSnFrG2z0xRFHDATA2c2rLFTT2q1TB4/qQ2FxyZjag1HCtGKErUMmeDi3mG3R7WxruuGXBetjjl4+eu/N9c1yCLMncdfV7IIGgM3MXCRIpdjILbEFCfibrSOJkROy4nj4cBXn3/Bv/jpn5KmHc+fP+f5y5dc31xz+/I5H90848Pnt/y173+f0zxz//DA8fGR5XTky198zjftc5IIH334IVc3V1w/f8bu2RUhRaYoEAfGAUIufp5H03iGgWl/xeXlNfv9JUECLRczWVmL0ZwQMyRRqx06DdYQhGwhcusCrUDJrIcH1sMDx3dvOT48UGtGkpmYDOOOmJXj6Y77d3esx5NpMopyqpVTa6xiPH9Lsj6DkOILUFV9KspTrOOMAIuc/+Pcm/jqONOj7F62jeCAdkaHF4bNQNbTaaGsK/NpJlebzAzDQKkWLrfm1QFLE2Er0Go29F6E5ucSqO1Z3u6e64Je3Copmh5TMK1tH+cFD9i1ZW3gW3W6UcP0Z/0MwZkjYUjEZKL/YUieg5IIaSLEkWHas5bKaZ75xc/vSEEZo/Di8oKkjdSqUXtFSENyilWFdSbWwqCNlMxEQb3htOb9nB6O16uy2c3az5OSZWZN047dkIgx0GphacoyZ0pbqQprU46zXfet3we6sk77piJsLmHgEQa+V9XSGSzOlnEwpNPO7K/Cdt8Vu13qoIY11A56iWyNRKfwdzSsPxO9qcSbEHyP2Namv7rFsbnQ6wbAtHZevL3O3SYa//9oNES6uwewdT/9CbcDMqbkFAUPNbN9n2GYGNLAMEznw7lvwKinKMfta/eU0R5+1cfbyTlW5v3cXXwUWk83duES/fE5d9Z90994Z4oLyu0uJxei1eIbF56I3rrYzwvKKkR3HDqDD08QzL5x4MX8hlCafWGMiWmM2+IoXfuRki2g5g9vLdSSzYe6e137ryjCs5sbvvPpZ/ydv/Pv8KPf+RE//OFfM8oUPhny9/FkW6SLJdvGBQHViqTBOYeBMAhRAnnakXIl7RayLmb32hxNAmoxkVdowtBF48NgyaMhbeJcmlJzQaNlcVTPrYheIP5lXyJnmoM4HQu1/JWKBUYNaWCadufDl+3DrHdX3QpNe859Q6ZRWrNxea3k2mBZKLWa7bLrF3JTimIc4u1CuqVlwLnDXoDbzNJcn9RJG9vGI5Y23zeFKtuBpD4lMaMN5x4j29MWQzILwhTYBSGkyOXNFcOUSENiGhPDNDBNoxX6YWBMOx7WlbvHB775MhA9ydeEcIYcmoAP0z5g/t6tNHdoc0TLPsyR1P4siE+tALe/1k5tchSkqZJrs0me4nx3Q4ZKMz5pKcEmQf611feETa8ghvZ2ymLfm7rQVkRofkCaMYQ/mn0TbrJl+IjvT7XTu85PxVbFmgW2fa4FgvoifG8vZLs32tEntT2D5mGhvh/ZfvXk08W+hsJZkNkxpu6q95vXr329d1j281Df//u+x8To06ZgtD7f4klptGJtHAm5IhQ3/LCvkZJZXvamr0/3a+vGIPaNex5S8GyBXkB0UMM+/5zzckYVn7xfefLjOA3L3rvRYGuwQFoVA//fe+mTub0aiTjjWgnnkA8CMVRCaJQE6pN8LcVoR7UZrzwXypppeSYc3alnXVkeH2jrwrCbGHYj1MKgwvVuzz4m1t0OTkfWw5GyrLx785ZlnjmdZq7mE8M0Ml7sTH+ryuS6LEIg+Z59eXnFxeUlu93Onn93nMQNYfp+sJU/fYqlDakNLdUaDv9V54WyLJRl9WmSFZdxnIjDyLA0wuOJFgKSBrOwDZEqQhZD5K3JsCayr6wePtcVPk+9APra2x7xrf6U9/726d54bjb6/ewguGy1kp1J9mstldOayQ1GX2etVXKpm3gdP/u7RtaKREOLQv+51PZlx7q2TmgTbjvNqAdP9h+o/3nw/w6uJwh+lkRnqsQUDGS+vLCzaBy42O2IKXhC+UiIA2ncM88rD4+PvP7KDAVCqyQxrWNEzWVU1DJcEErVJ+Drk+uK0xexoj2E6I6pWx3ugvqtDKQplKrk0KhqdZmqn03V/0ydErU9rOcb1aef+LSi05qEJyC9Yq6D22rwi92MJtabun6edt1F3zV6rdKerK1+pHTzFJ7UvX3Kdl6p/U2c9wzx2vo9gklTX89P6VEKLWzrXHm6WP/1r2/daJhNmPmI11ad/WgCuG4uYAs0Mu0uiSFuIkdaoywrKU7EaIV0kIFpjMRovvu2oI23fjodWNbZJhllQauJo0spxCGyu9ghybeaXGxE2hq1riYOVaWIWmBeDMSerIwVgTQlTRecJS5WDNWW2V1c+LTBkKvWjDaBGJpQs/1ZrRkZLfU5RHP3MKHeeeIT3JnJrKCLFbYSiWlkmEZub1+gCsu8uu2tHWjLklkXS0yt1WzpYjL6GERSsiZgHAZ++IMf8Ad/9w/4b/+9v8fV1RUSovMC7fqE1rl2/XkQsk9apFZbWNpQXRgEBlXPD2juTKUQdlx/8AnL6URZF44Pb6ilmq4hBlqtlCXTQrN8lFJIcSBqJWcbk1Mr5XhEh8QwJOZlobTKxeX1VgR8uvuAn/+Df/znrsNPdx/4eglM02TrLwT7JcHcrGrmcTlSi5KCiSk7JWFp3oBKpPPxNbjBAZFVm4VvaeHYMlkbqwilKWtp6NLcaq5Sg7if1PnwiDRzkVCzBBiGxBAjY0rkWk0AWc0z3ETSjj4mMceaZoiJqTSEuhan/JgjFQEiI1OIjDESy2xJpvvE5c0lu8s9Lz58yfPnN1xf7Xl2c4VtFI1JJ5s+hpGv5wNfvXnNlz/7KcvDHW2ZKUOmUZk1m16nW962QG3CUvy9NZDR6EWt+JRPxEVxgxVYOW8FWSle/Hhh0UrhzePjhrZUv17nRlBQXM8TDahQpxWZTtoO/BSS75e62YOGGLeNfgrWELQqTNOV3eviqFtrrg1xbnPNPgYv5xJfzQK5u4TYGgqmW4Gzna13W70Aat3e+ep9HwABAABJREFUDWOZUuxZSu5SFsAbVJtkBgcr1K0Rtbozn4BKn7z9xXv0X9XX1lyGwDkvww9U7RoZDJzxMLGYBj99rVEgRFSi7d9BCSGxv7jcTBdaq5RaOZ1OrHmhFguRba1SW3W//kAaBr934podb6Ld2KSHwPa1Lr0c6GLM3oCI0bRa6RlRT/z4w8YeIopx+58CJfZjW6Lz6o1N8e+9IsyxUUKgxMbtANLMUuTxYBaupVRSTGZWMEJ0CkZ5vOft4yN3Inz+/2PvT5okW7L8Tuyn0x1scPeY3pSZlVVZQDVA9ACQIqSw9xThgsJPwUV/xZZecEFywyZF0EQ30CgUgKqsyuENET7YcAcdDhdH9ZpHogr5QPau0kTiRTwPDzNzu3pVz/mf//DnZkP3u8OB/d0dX/7kJ/zk66/p+o6XLz7w/a9/w+N3P/Dxu+85PT6TSmY4joy7kTcf3nJ/f0c/9uyCJxrVZ+33d9y/eceHr77hw/sv6Q53YKxOjrMChJa2V97sVTdqldQ8iBRhWSGuSFxJ1yvpOrGusQJqHSV4wuGOMO6QsCMmuF4WqFbz9vGFNF+JOZKp2R019VkxKg1QBdnAEHUS/Hx9bjXG63u4wcmtyahNAFSQ4lbJbfqwVASifg5zLsQszAJpibiU8TlvdL6SG3im1GpBVMD9CtjY0HbndI3kotbaVOTf1nXo/dYQp6opyqUGw1rBWM0I897RdyOu2sEGR/2aZzcODOPAu7dveLg/st/vuD/stTYyhZy1aTG243y+8vHTEx9/81ecn1+I84Qs+h5JLdW6EHMmG9V4qMmVOvelhr5XPYizqpt0PmCsJaW4GfK0BkVytV7OgpTrRpVNNWAWjMYrQOP/03QTUqfZztXg0JpN0pqC9oE3Sqbe2/Wag9oIo66Qqj2WrTHSvYfqutgUQs39TBsuWwH0RnurWx3GaDZNukEPehXlBqxSf4ZW4jqjtUep+8Zt9Va6FgZjXgHUP/Jg+tGNRhcaB1xfcHtz0hB221pE1mnG1kZjrn5wUgoxJloYml54Vy+MJ/hQG4vC5ZqIq3aRzqrOQLzo4WANQqqOHrVTr3oIFRoXWrgIYhSpqRdGre31/aYUVUAVguZsoIKl63KtU86M9VSqTd3Zi+gkRQq2Hi6mHii2do0xq32trUoeY2TzT0YM2UCJhUTi4V5/7v64J5dEypHL5cw8zyzzQkwRg6HzmsTtnI4ZnXV473k4HPj5z3/Bn/3ZPyaEHqVZ3EatCFqcihZiueQqys8KhaXE8w9PlFVdhsr+oA4Ww6BOTD5wfKfNkBHhkIWcVtbzgbTM5GVheXrBVbFWQ26JK1yeSMaxZKnhjJbOKHXMZjAZJCn9qd2Mzjh+On75o9ajMQYXAusSkWxIpSAxYb3BecfO71lL5LRcKL0lR3VYWrLa1wZfj4Wiha/S/WApGgJXshBJJJOJFeG3BSRGNQQQ3ZyMU3qSOIUoDBW5NqpFav7fxWnhbHBYm6t9o6JpphYQaU7kNWJNa12sjvedox8DfuwJQ8/7N3fcjSPHfmAfVHcQvKG3hj543twfuJ6eSS+f6NYTh/2Bw+HIp29/w7REzrGQ+gPuOhOsZS2GFAuX04zqhEqdEjmKh9ANBOvwCfKka1OnkE4PIcnVuckjFflZ19o8FFPtgGGz7zRoOndFQ7KoU4etIVRtWmEqtaWl2zdopsqToHFfb9iN3t91NKQaKD3JfSj1tVYFJCgYo45zwXvma7xNaltTjtVGsPKUjbzizaPv37eJZvE65TMGMQFb0TeSZgoYW1TEaS3euI3aQJFtwy+54aLmJvj9w+P3PrzXCS5AqYdgK4y2A7IWUHGNpFRwVrnTugYLaVX76WkL7FR03dW9K2Yhxcw0r9X9Kd+KNdeQ7urOU6m0Fm7Nxdbu6Fn1espCnZJUEg25KOpcmjsKEEuirKn+xNrYGkfVBramqr5CnYAZUfFtlFtj2xWhZMO7Q8Dte7r7ARs9JXo6E5F5JS0r11nNHkwRnKjphxdDMBoy2TuHLYoX5+cXrteJX7+c+fjLv8EHj/qQWA6HPcPQKwV1WbjMF6ZpYvrrXzFPE4fjkS+++pIx7PDjnm9++scc3r7j/v0XDH1XC7JEKrGCDQbrlH7TSwuW1SJN7T8TrmhgoDGGiGq41hRJIhjfMYwDznvwNShYPNb1cLjHf5mJ45nTMHBdFyyJcvbIfNF9oaJ2gvaGuU085QZsY27c9lZxtlyP7YttjzEGkUwxzZXJ3PbB7fl0S0s5kyo1VMXpIE7DXQWU2m0rnl2F2jfwRddKHUDggsd63b+tsxrYFyMlKrji+2Gr64JXunbOGe+pxXihH4ea+eXpgqPrAu/fv2HsPEPneXe3U+ONHOlrDfPhzRtOL8+slyd6Gxn2A/1u4LtPz0zLymWKYAOyTHgp2JoldTlP6hBYF7kCjI4wjApeJyFOC2VeqR1SZa3oOmygXkmJGFOdoN9EcG1KJaDai9eFOGZryFTbUa+vMRtVqYGZypKR20SjPWm97trwtQmBfk/oFG6IOaujqgi+C+o45Sxr1PUhtlmhUJ9DwbeyPTO3562uqO19lNoMWedvzUZKWAFvoAtedS3esq6x7nE34KNgKcZsZ9y2jAVe8Tn+zsePbjScrwFe24XRI7f2Up+9VI6RYjLFuS2qXYts2TTzoQsE8ZqWiDrQxFRYY2aNmZy0OHfBafFjSvV01sKjSCsF9GP4DM2hXcTacdYPRicpbB98odScDP0XuY4lDWhGQkWzrOimYmqjIbk6YrUL234VNqGRYpl6UxS5jfSyoMJeo2KsJoy3FdWNMRNjIuaISKnBTrrgNK3SKKriHcO4482bt3zx4Uul0CgczM0xgNsiL9oESLWMk1wgZdbTlTQt+CQsCzCsyCFjuoANHtsF/XlEN0BxBid7FmeI1hAv00ZVMTXLgJIp66wfSSzgAjiHF8HmhKxRUz5T2gKllGLkuNHw/sPFexNAibq1YGpmye3Km+pkbK1hWVeuy1QzJtgEmHYLFDHb8zZuaqrTulzXVDFS15ze2OryJBsNTzmo6lW9uafR1lClBBiLDUFRN+phYA3GO/yggmmlAa4kY7E2aENrPS54fHAM+47+7kC/G/jq/RuOXc8xdDzsBnXGsCDTRADe7gd+eP6B83TGRkvvPcfDnqfliswLaS06qi5Fxar1pkmp+tPbeq2t8rxNCFjn1RFjtbd1Zdpau9EnG52khagBNPtR5aFXwbNppboispjaWJQbHbMh/RqT0IrG1oLV+6qd2NuBfyu61BBETRasETCFYrMiPbKlLmA2lyfZfrC2YWuTcdsjlEMur+qARml0G43COo9DcFKqPa2uk2CtWlOagM0ZpzcMWaghonUZm3ZA/aHZ+DEP84r7XKs3/WPdSkQaYqyHqzFCsUU1cvWal4oGR6PaDXXwgWKVvhdzqnqMvFGllJlna5ZOI8TJVlhiWjBtXTv111YttO+vb7K1mY1aqba7lX/dLNGpJgfGbPtQe4q/7dFQUz2H9HdfBNMF/NATxg7bOUiOPq0UZ4hWJ/e5Ot3pvmUIooVGwKpOou77kjXpe5lmeHrCeEe/6zkcj+z2O4ZxxHUB1wViUUOJ63TlfLogGHaHO0YJGDcgRfVz83VGHh+xIYAPLDGRcsE4h69TqcGO2zSr5KjUk6rXZLNvrZJyo2BG6HqGYYere5pa31vEFPq+Z384smCIJRPuj5jnHcSIpOXV/Viv56vBA7Sia+tGbnQ40y7Q33GRzG1tGPOqAdULuK2T1M45Y5TmqWiWcvQ3CvmrJrsWAaaeq9a7CiJpo+FCwHqvAu2cccaQiFqkdgGMTiq6LmxT/J6OIpCLsNsf8KGj6wP7sWccez58eMPgLUOwfP3uASuZNF9xpdB7z/u7HfH5E+t0VvC4twx2wOYViQtpmfHdvgI1bGdTjAVx9sY+MCBGCD6oDToFbHx1f73+DGpjUs0XNMFbtuavuRHeCHmVUlU/680Z0Nyuj6mjA9t0Hs2Zy/yHt2Pbyw03mlxpBbrR/BOgUpZ1b7H4SmVuV79VKM1dqj6xImDba9VIId1P7O1na82xcaEOCYSSSrXfN3RWae/Ou811rXADaFI7Aet+2jaez2rM/8jjx2s0vDpY5NwmBxqc0nhipST9dK1oYI8xWNGnF6mfQIX9DRDzSlqUkiI4da8xTjfpUrTAc1BstUoz5nZgmFID4xT9qdApMUYsSiuyOKU4paIfnjGUEsFW3qD3QGFZ562s1Q/QYbCEojabDh0hOmvxvdcwmrgwx6mOuiySHCarMxDVXcgUFV8VRA+vGvhGUfS/kzoSy0KisKyZeU68nGd1zTAG33tKKax5xhZXx6cZ43qGfscXBg77Pe/evNWbUupn1YogqVkKWXMKbDPjkEQqmt5psmCjIOvKZboyScHKqnpW36x/HdYFnO9xPtDtRroQGMY9b3564DrPXK8TeVkpcSHNJ2xS5N/GRLmulJzphh3EC9P5ifz8og3Hmvif/tv/jm6/54tf/BGH45FxGCiX69aIrKVQnMWMPdcpssZMSoXLPDNdrtwbzxACfego88qaFp6uz3z3m1/z3be/JRcVUrsiBDGQhbKsipwA2VvmrKYBgqKigm6MzhoITjU0gOvRwC4LVodXZAvG7XChZzcMpOWElETXdboBGcvx/p41r5xXtVZMOTEtZ3YDjH7g7f4Odz9irePw5o7dfs/D3QPv93vG4BkHx+GLd3S7gXx64fz9D1x/+MgXRZNdnTf88q//gmleOL79gHn8hJ/ORO+YreMaOsx4ZHf3jv3dHR/nzOXxhdBZ+sFhJTAabXqDD0TRCdiSogKFkjhfrixRPyOLCgpTUcF1qZkDDdZT1uANjLDO4YJHajI7oM2u6P2gvuoFysLNRO+GTKntTqgoVG0ihI1ukHOdSpZXFBVR55/g1CmtTRcdNd07R9Iq5LRUAaOido1L27RFBhUkNivdYBTwyEbIpgff0R1G5vOVkjIPxyOuJFy9/00GVwp3CUIBLwVXHNYEZpuZgEsxPKMOd/po7+EzJu4fHn/LQyg3MKBZL2FoLFa9p6vLU6qWzq+KuYZEFwPGCKkYbLIKUtQiwlqdFuuUWW5WoY0l1Q73en6JVINqKZsN9OfXseVA6Is3AKy5NipXXukaFLlRKlA6SuPB5+rB/FkJa1+dlaIIKkXNIxz6XnfHPYeHO3b3B7wUTCl0u4HrdeZ8nsA5llntzeOitOClCK4e49eS6Kylc06DRo2BkkhpoUyF+CkxDD1d33O4OzLud+yOB77+Wl0In08vvJzPPP3mO/7ln/87DuOB/Xjg8M//R/Ce4h1+GHFdR1dRa+c9w27URiME3j685bDfc//mgd04ELzTRt5VbajVgNTBO/Zv3pBKYk6R0PWbLWosWsAva2L1njT0iDNkCuvjHrsb8cuMmXVyizTqW+vcbtdzgzpfVV/bXreBZA0Nr2uzan2kTmDMtmKlgiW1uBQq9bo2d9WtznplLBhDbZraM5hKv7FbQ+GGDoqGv+WSwGpu09CNakvrE0s6k4uwRCF0ns733B3vakaZ4Wdff8E49IzDoHu68wzjwNdff8FxP5Iuj5yeHrm8PPHVoJOGyzVxfn5mBq458fztb3n89Mj8siMWwQ57jBvZHffs3/YUPO7phPFqTuO6QvAeX69vqhbSpeabSF5ZYlYrX1pjr5TGdn/nnG4AjpFKr9WpZdMVtqbOonWliGwaXGNUV6qGL62OvTmEWaNslfaCDXTI9cxoYHtbIlK0yXFW6V7aE7brLlVYb5SmFlc1IskFbZv1uVvyuH01GcVWSjNK+XUm0I0jErUR96HHG4Ov4IqTQmeE0SozwhjDGDxidYqailL0rtK0pbLlxUh9N39H+/zZ40c3Gimn217ZJgSgiK1eHe24zI2juKWzIhgUvdtYXzV4SFrGQym0FGupnZKl8sEqmozVDzmLpUYBfwYTWduSkKVqSHQs1Dh0ugiaC8nN47x1t6WU+tfqtFAqEbY51WYyJSpXV4wW4RhLStVCzTQOp/5dTBoAY03eNpZtMxFhXRc0BT1zXRbmdWZNa/XT15RHZ/TmMm1ElzMWTau8v79nv9/TDd1n04DX+Jmg0xNTmhODbALGtEQt/vrMusyYosW2SwtEDbspok2jMw4feozzTMFjK5IQuhHrHIN32O4AuScPAZmvlLgypZWcIyVGHf/7jug78rIgST9PyFgn9IPHmkKJC5fHR9I8E6eZmBO279i9e0MXBnzfMdnEsB+Vc1kKURI9TlEbcaSciGsirQlbVDxZEBVr6pVAtSlKCZCGNhiDM17pVaHTm8QJ3pft760YbDGM/UCbX9iwx/qAeA9mRErkGlcw2pDvOoczPcfB8vbhARc83X5k/3BkGHoehh1kReCOb+/pnKMXg7ycKOvKc5rZmUL39oGuCHldmS8XCJ4SDYVMyGBcx+HuyPl6Ii0OO4xwOGLfvGNvAtEHYjdgHp/BXShiSAViEqITSlqJOZKybpKxZJZV5ztLjBVlrXe/pf58r5KON8Mky206VZEgdEqpm6pFnN1uyXbfi+g9bMXcrD+do8GyZSuq6uFQN8w202z0JuoUztg673RtjK60RRGDC73y+q2pItHqDlepLUghOF37fV/1IAXimm+UCWM0xMl34BakZNY400nz4i903rJzPV2n9FOXLX2pVqMi6okvhUv1xS/tQ4Q6Ib3tuX94/IePG7f9NeKsB/hn6sbaSGxgZ6sLXzUAUj2FPxNeCq9EsLWoa8A1ram9IZetIXj9uvpPzas//84Pod37Zw2QoMVFkYI0OlYF3Fr7Ka/0QBuKJ202V38yY+qkV/DeMg6ew/HA/rADW22iUySWTLHgOk+/HzBVF2h8UtveNW02zqCOV2sWPLkCfLf3Hnx1ZEyJ8/nMsq5c5gnjHalkpmVhjZGUCz50iAgxrlAtT1OMOiExWiiH0BGCJ467zZr0/N33+KBmF61Rc61uqNfC1rRx751SVPvAbnek6wd2xzvCqM2M8V5tyb1nzZEBITwcFVS7XpUimoWWy/A5kPv6mr26xK+u8asV9tnX29pV5oKCkc7aTXOmz9O48bfU9Ea3Vac9rYW06Kx7sfMVINTAYusctutw4kAycak1hghjzeBwznK/02nP3f09u92Rvu85DB0SZ8grP/vqHV3weGs5nc6kZWKdXyiHgHGZgcw1LaTrhXjtyDGyTleW6bo5qe3GkXxfGHc7hv0RPx54GO+VYu06Pj6dWMuJOWWi6PQ7gWpBq9BdarPRPttUG7Ytqbr19lRtXdtDzSYP17O+2pMbLQfqVJpNI3e7vFINWW4w2Dbh2C6tNOfaG/DBrdmst2K93nXiZaqBkWn6DkcxqtG45Vmovng7m+pzOKshl31XzyYR1ijkyow3Vdfpu54lZ9X71smVMTBYq46wFgbntnrWVspy7juWlFlMZl21frJSqp6tTX1+F0D52x8/utHIKdVuWjdDgUo7qgOurYvPt7uw/vBblHpdFaV+YG2C0E7wRicSMSo0puE+1au4va6YSn14VVhILXSkdYRtzGzI3ERQZrOMbNtFsz5UtwErmt3RFofSnoxCqAXSGjU1vHWz1m4ImbEaQKQ3uAaKGdE4mvZqjUOJFNZ1riKszLTMLKvqMnQsfXMrssZWtyKpAS7QOc/79+/ZH/d0XdhsHG+HnX7YmzdB7apFqJOeTI4J13m9gVuOR8mQE5JWJK3EeMaIEBBy6MFapb3YoPaEu3sOxwOH45F+7EAC4h1ZMqtkZgqUpIK8pNMgYwO52oVKLlirmQ1d57CSyMvK9fGR9XJhOV9IORLGgS5YhjcB23eKPjLiQ+B8eiEbSCR632GKJVfBWs4tnVnXhq8by+aIJEpryzV4CFHhtfOO0ASjVORJijY9YnBYdv2BjCUWiw2D5rAEi++FXBzzy6oCMW9h8PTe0tmBN7sDu8Oeh6/ec3i4Yxh7DsaTlpkSVx4+vMWskfJy5uOvf8X1+Znnl0+82/cYI+x2e87Lgr1eYTdSjJDjihNDCB3D8Yh9GinLDLs9crjD3D8Q+j2CZRFLfr4oZadUl41ciEgFFBIpGXU+Ew2rqhKjmgej95/6dLttQ3TOVqvA3909boV7C4fQkLq68bsGSjSwQTClZlNIpam3Qo6G1t1epNQpJ7VBaTzadgdos63cUms9yKqNhu8UdABKWWoGRsWM6nnVOW30d8OwbXEvaVZxLqIuNVUEb5xDEsRVk4a9gKcweMtD6MhBA5+cMYQCXQHnO6QktSxOmnpbRD9n5fOWWmD8odH4ux6l0lihnk3toNl+M1vzKLXZ0GX6ujHR35t7VIXNtr+VCkrcqBPtL28antuR24qBG4JJextb8a/b9LaMRf+uod2tQMlStqyIJjIvDYGtr2fk8wIXmtqD25mN8ttD8Ixjz2G/Z9yNYCotLK5aiIiAU/2YsTWvySdizKxmocREMdp4GRFsLnVSolkh3jqcMfRV4JpzZr1GpnmGi6U4S0GnCLYWwOOwU5TVWoa+0/s0KfhWRCjLgu17bAj1HNR64FL3+Jgj6zKrS2OqQaKlKABodBrV9x1hGBjvjxyPD4y7Pe+++JLjmzeMxyOHNw8Y7yqlyOJij9vv8EOP77oKYGXl4H52ST/z8fnsIZ/9va6prQVty3MDt2yl0NY1UGq+xOurau3WONngt8I0p3QzDLBOc5X6YWs0BAPeYrtAZ5wmbJfK/rCWQx/o+56h7xU03O348uuvubu71zBFU1jOz8TpzE8/3OMQJCfi08TlemW+TizHnugyXe9gnUnThfXa69R7mYnLorURMO4VlAvDSL87YLsdh90Bsdqyxscz1zUxx7QZo6TqJkpRpy2pZ0nTsjVtW0tGb5NF6j2lDdqtM5B69exn+6psjbqCZmbbE27X8rZvbDS5OqnYaq/WbHwGQLTm5BWtve4YDbxrzSZbo1Fb5leda4viMEbjGry37MeepseBRDSCJFEKr/O40MG81HM9q67QGrW+t4ad08mfNVoDBWNxDkoIeKPygwtqKKG1rKvT2Nc75H/88eNdp3LcbM5MdTGIOdHGFwZbedBKWTC1S7SvnuN1Z2fREWwpCTEWYxzYOiY03LiVJdWvWVJMWhQYs6UqOus2YYwtYJzDOUOJysX1VlMrC2ptqI9MxuJth/MDkhJIwlm2hepD2C7uvMzVkabgjSYdF2PIScdXfbevjYh+vUghrXHTamwcUaOOIRQt8k9PT8p9954sRoPHqldysYZu3GvxJZlj12+0KOs9P/v5T/hv/pv/C/fv3pKcIVJw9TM3DYarq/v1ZA3AuA7XawJ2dBHxgc4IZbpQ5pm0LlAsJhvksiJpJqYJ29eGxgZs6LDe4/PEcvXE7z2h32mTF1fyeiXnlXWZKCmrcNo7lKBSmM8T2Vi6fsfPvv6C49u3hGXh8umR6fmZ+PETNib2lRtKnlj+5kr59ImwO/Lws58QR8c6dhB6ypqY1lkbDl9g1+P3O/xuR3z5CPUQGfc7dUTDcHm5VD2MNqQWg/M9oesJXUdMCeccwzBswUe9EYJT+97D7oByP+GSVYi+2we+ePeew+g5dEq9stYSxo4QDL03+EXD7I4PA8e3O7z3XH7zPY/ffsvl8Ymv5ReQM8v5xF2Z6FjJ85Xzn/8byq9+zfCnv0DOJ6UA7geKgbRYLv0CxvKrNcNPf8b9z/+IM5ZHN/DpNPP460eu08zz05mP333Ly+MTPzw+kmNErGWiOooglIoaeutUV9KOyM0W2mz+CK+tZTdua32oa4mt7mb1UCjl5jRl0Olm1UIUqxMjKRYfdjr5MDcAYSvqCmRZdJRrm/CbrQlSvMPQLLSnadFpgnEsJdQCRtpZgqHHkXFEejq8dXR9UPqBsxzGKo7EMPZviTkzxcjqRnAB73osF2yxkKKixyL0RuhKweSVy3VRQSqBnXH0xjAqZMFoA4NEjKh7ifFOi8Ca7r5VvX94/AePnNPWALQqQvUIeSu2oTWzt6pca4Jm7XijrTQwRqCi4b5upzcAi9IuidwoSvW1WnFgjd0aXUxzLbtxrBUgbYWHNkPQ4C99X7Zy0o1Biwbn6EK3vW6Ocvu5arXTgDOh2Yzq647B83C345svHtiPPdYarvOiTlrzzNKsXwuaTGcNYRwoNmFDDRG1BnGQVqmYgeDEbHlZDsEWIa1zDeO0GxNBxGCsagJ6H9jtdgyD5nN889UXfPnhPT/5oz/CV4OMVpSbWhBbUwvrpgNDQbo1rXz8+JHz+cR3v/0tL49PXM4XXh6fdH9fZ/11PnF5/IHvczWPsE7Tpb3H7UZsH7BDz91XHyB4Zls4X8+sKd6urbHaqNZl1ZrF1y3r60luezQ+fis2aWtENA7ABa8uikWp50uZEXJFmWsR3SYTzuGC6lT6viOuUcHClNSi2QfG/QFQV8SYEs5bhmPPN2+OHAfPaApelLZ6dzgQQqALHbEUfN/x8P4N+706cM7nJ06cmNITYdYGM60r5eU71tOZ549P/Cpdefn+jrdfvOc6zapZHHYEA/t+JPtegdBxRx8GbBaWXDglw8vjmfNvH7nMC5+eTvzm2295fHzm8XyhxIgUzUTTGqtsmj3nvGZQtM+0fk6GmmFmm5W1Iv+3KaW8ulY3QOK13X+bEulfbfNDWjNTYQGd0tT7rmktRGSz72/Aed0pbvVwXTwiwrqmOuGwxFRtqa1RO2qLuq4W1ZAMIeCdI3SaxeadZbcbqUIx+kGBwyWK6jGcxXRBJ3JxJa0rCQUVXVBznmAdaVrJRVgLjM7QOaUdm4KC/kWBs1A/S7GGtepJfn+b8Z+YDH77g37odvvAKpfQtg3SbJvlzTv4NopqsjlDqV15IPS6EEt1pzJFKUuN6iKifuDQxDm6gTpjlVNvUC2Fszivm5ERuVlvwrbJI21jrxuZMWAcrr4fa1VsLUU2NEkRreoy0XzE6sKW+lza2FbEReQ2wi21K7UqoFPhVlFKkRRsTYRW55HGr1X+bfNVzjnW6Y3lZz/7Kf/wj/+Idw/32OBJWZndnwnTtk1ab4TmslCapiULkiq/14DxRp1TnKXUkZsU1cKIoH7S6MFbjOByqY5DgrMecR5ZNJwNSZS8qBNIvl1HY93mzjIMHViPHQf9+ZeJeT6zVuSkpFmdvaQQ0OZJ4kqZzsRSmJ56cteRfaD3hiKOnBuuQeXxDnT9Dt/tdAJmwPkeI4aUMqkYclFtwOZVY72OBiu3NfhA1w/V0rCKekPAu0A3DoCOv1OGrvd88ebAh7uOXWcYSqJzls6JWqlaS2dRikBciWSyE0wI5NMT5fKCTCdkulCksMSF5C3sRnZv3yLGsBi45MzqAxwPLMOAYIjWE8dIKsJvrzPRFKIUnuZIzLAmOJ0XlnnlfLpyPj0zX6+kNakaWdoarqI3NOncbA4o2lTTaprbzVyRn99BhrbNtU0ptfpr425roLy6h9TLRi05b8iuUB0WNvs9KiVSnavq0WGqKYUoL74Fn1nlc2pTEgvFKm+/qAkxa67sL6jyVv2f4HtCtUPMRbNS5tR+WIMxjlRdOAxOm66YsAWcWJwYTNHRvgowa9p5VrtRqZu8cQ5bCqkeZXZrdj1u7PWQWN1nguI/PP62R8MbG2qI2ihvf13/3jQ0sJ4h6Fm0JQWD3gO12TAVcOp7RQxLEeKqts/ILRlctJ/dHm1q3TIKRG6UFmNsdarZ3hYb6toA0oZwmppubJRS6Jy7Ta4r91vNVur7qUd+c3W01iq33akJwXHoeHsceTge8NUG2neBQZQug5uJMZGqEHyrr9rnBlszJPW+17AwLaaKVIBQdE90xmlCtDUY7zHB0427atNriQAxcjqf+f57w7pMXOdJz5WG3tfPrHVOtyLe4Lv6fd6SlwUvwt0wEo6FQ+i473qdilanJuushrwlbabUzlW29PScM3meKeczOThWU4jLQkqRz5zv6gegu+IN424hjK+Jc7dlccPBqWtQKZ4WrMcYDzWpvhSls5bcmuEm6HUY6xWcdB7nAt53qh+q1KEuaB7MuNvXzI2CdZGu9zzcH3hzHDkEy1hWAkIwcAgG6wqWSIkLUhauT4ItB7x3XJ4/cTk9Mp1fmPdBIwuAYbfbJvqhHyjGkU2AYHDiya5XEEwsiwn6+b5cmdfEGhOnaSHhiHierxPXeeH5dOZ0vjBNyvYocjtzWtNg6/2i7NhX+2Krx6T9mQr2al1ZanPOq8bws2lE+2qtGdvTmNf/oNadrQxEbg5y1t7oRPl3LMlb3Vna9zbgrEDMOsE3xpBKdcIsCjarhuOWBxV8h3dOQxRRPdm85G1aU9q0oe4ZFINJGv+gpWQ7H4vW5KLTyRg1d2UV1TcpOKCUtWxQxy3q1LLrNgrfBqT8nsePF4Nvs2K2zcdZMGiaZ86rfvA3RgTWaFgL6E1jqyc+UHMlinblw8Dx7q4GpCTOp0stUAu+IpTNsg9jalJlbTSsUwTUlFpgenwILDnXzbcWNby6uTFNzq+bum1c8VCfs2Yc5JpgXUfzxjqdOkgTXSunLUvjXVYRkUKktG1IGw2lZXjjyAbENku+TCkOsW7jn6uHMawxKvXGGdbpqjQSOv5X/+AX/Bf/5T9h5x1zKcS0boictOYKbqN+Cimt1XFBhX+SMnld9UbZaCCoyKxNfowheU+OjpxhzZWuRsb7hPWWtK70XUcfOmJawKgQGJJ+/pnqs+0wPmyc9uF+p4fPMJKXiUtcSPOFtC7qWlbm6vcsBOury2Nmns8s68S1TJhxjx13HL/6oILtetMWqGF9O/rhjn73UBH0gvUDaU3MU2RdjPp3tzG1RekvVovIfujpQsewG6EMGKond0009b0mS2tjabnbD/zim/fc+UiXV9LjCwfvGMURbE8ojpAdT8/PTDHyJAm7XumHnuXxiXJ5wq5X8nRhBc5xQcYOO44cHt5yvl5YS+YTUHYjxR84j3ukTtfWBZ1YPL/wclLLyU+fXpimmfm6EGchJyHGjJBqBZ5pLFCkWsw6oYUg6mbqQJT+WFkJGIpOIrcRMypwe3X8bonWpo6fm+uXMQTnt6JJp6FaVKl+QtQWN6l7ga3ua84ajJVtw47bvSYInoKhlISVSuhsRZ5ooyHGoJ4KXg/AXHRCiKGrxQ/W0fU7gtd1MC/KI1+ueaOKOqcwS6HTnJqSSWXBpEIQS0BpFjlnbDcgVieOa7GsAskaDYALgVKLulQy4hXkoOvp7w7qSrZWIeAfGo2/89HW7ybqpPW5rz63VizXCWMrtJGbeYmpRXGbToQQ6IeBw+GAACklLmdDiuummWgTEHk1PXHWvipQ9GzxLSjQWFIqtXm81SK67SpVtjkfNjpFu6sab1tEU5dLTRlHGn9bgawQnAqxQ2C3G+iDpw+Bd3d77sbA+8NA8Ppaw7Bjtz8gIpxOZ6Zp5nqdyeepnntNg1K212luV+rmaDWwVNAsgmrw0BnwFkVFvcN3KkoN9/cYa8kxcblcKNcrT09P/M1fL0hOeK8hrIjQ9f0WIJti1YcU2VKw76qr1d3DPQ/39/RdxyEE7u4fsPdK53LOaWCc8/Rd4HDY6TQqC+sauU4z12Xhu8dPnNeF07qy5sScVl7izHq9btPsJvKvfd3WVLRS62Z+eANhXt+2N9qUqSCOwVlfRdmeXNSlM2bVzOWk/8JarQGcddXaN1RxvIYfu00jZ+i6nhA6+n6o056Ijyu7Xc9PvnjP204YTSJMs05bjTCwqNV8LsSXF9aSef7kmN69wXee88sT19Mzy3Tl7jAwDiN9N3L37gPjg7B7G1lSphiL9AdMEFxfWJwm2UdjORXHNK9Mjz9wumhT8enphWVNzGvi8eWsGVNrxHeaRfOZl6mhUr28uinplzb6Tgvge9383fqDau9fm8VGT9RmojUask2nGkVxiwmgIQll221ayLSI1Gmb9oyl0o1TVdoV47Z7Xeu31mpKBbI1xHcDlKuWllJZFgbN0DIeHwxdGPGVorzGlVwK1yViHbpGfEcWtehViULBSNK6Fa2nXTHbZKUUIUphWrXRSM5j8bVpNCRTiDZDULAkOE83qC7Xl7TVvb/v8Z+UDK7d4itPGGs2dKYJrlRXYAkhMAwDIkJKkfPpGW+83hQ0znRH1w262Y0HlnVFasWXa3iJbRsPpfLXagCf1UPBYbGdV8Hm0OkCdZbQhSrmhq6NH0tWZT1wmS7knMhpvaXFiiFnIYF6GmcN90pFizFXF1hbfLla6eVctuYgBPXQ/4zha1LdKAzO1a+LJVk9PKy1REm1UKuLUQQvGYcKdnpTuB9Hfv7+K/j4kZe/+PfI4xNhGPHDgCv1R5Qb+mSNCqhKVItCiRlSUjF7EbyoFXFaVuLTpW6inuz2OG+wPXgc/rBi3644Y8gp8vz8A5f5SplXusvC0M/sBkcXBtWTJHNbB4OvwFi1K0VTaJ2IisGvE8v1XB1hsmaa5My8TNqoiLCgaF7XdYh1uFJIL8+U6Urynu8/fscwHDjcvaU7PhCCZTLgdnu6uwe+6nacTycu5xNiDL433HVv6bqrrjMyPnhs8HSHfbV3hc4HvPPqsNUpncZbnZg57+iGQCITS6SbL+w7R2cK6XQmTSfOv/5rrgZ6a7C+24oPZ3v8OPL2wwfef/NzhsOB0/ET8vREvpw4H95B1zF0geQCMQtP54nJ9CyXiX/7V9/xPF15nq5cr4pCrmusI3QNFFQkX4irCjWtserDLxCqSBpjEX8r0jYb14rUbHSlXLbNu6GwbQhssnrtA9hSVA9lIHjVjghqFQ2q+Wh7hzeWWAsHa/X0LiXROPa6gStq5HImOBWyhoCiiWLw0lGwiPVc5oJmd440Ke+S5+1GEBwYr3kmeN3HXlsjW4fxBtcZVmNYcmaeV2IlVJkSaHentx2lJNY4422dnphMNhHxqsSz3mON51wSXhQcSf2RYjzFj6yHDjN4OpNJeSWmGZcOSDFIdlg/EoLH7w8ErxbIf3j87Y+bwcarL0q79OZWNNiWj+Hpuq6m0qubUitqnHV1/4au6+mDFm7Log2fFge6/mwD3+qL13nXTZBrld7hnWMcdxvFcJ7XG+Wwgly5uaJJQZaFkgspKW24TT22X6LdvpGCN0IXPGPf83B3YL/b8f7dAw93d4xjz9DreWSl0DtDZ4XeZDyZ4B3HuztFxBGKC9huwoYZxBKXlfU664RjXTUcN+eNbVCotszGgvO4oSe4gPWOvg+1GRHWlEnBk7oe0wcQIS6aGyVpxcfIvnPshpEueJ18tgl8TbjOuVmTCmVdWY1hfT7hvOf7vmMcBoJzDN7j6mRFok7YjYD1um+HzmFRCmXXsqmcw4TAXd9xf39HGnue14XlccLVglLtx2tB6extrZU6YRXVGuoaCnxGk6oNZgtga25N1nn6fqBNZDdbemC6nImV6uKDx/vAuN/pND2EbW31fa95YFWv0ayZfacThJgS0zIxDp7d0Kkr1HRi/v7XdGS6anyjkxWH3+3ox4H7+we++sWfMBwPvLy88Pz0xPl8ZnjzDmsD0Thy0nyZaCOPj4+crxdefvMXXKZ5+5VSJMaVaZpqaKUhFwVT15Tq3FybVG8ctrM3QLgKj401aFJOReONo5n33CiLrcl4LdY2mwB9+zNswZebZgO2gtlU8DpXEwZeNx9bI0ltOtUevrMQvMU7NSvJWLrSKfBlPEtUK+2UapMjbFofqQCfGI+1PUYTDGtTpACwXtt6hhRHLAr6puIoYinGQdZpp00tJLdok2EKoay1JqiMHcVHSM0YyTpiH5Qg3Y3YuzvCOCAlkuNKjJFS3SaxDrfbEbrAoe+q895tgvd3Pf5/Pr1e1SF6czm/8cy2/AlrNzvKhrarrVdbCqaOMDPzsrDGFqYir56/0SiaAK/9ULqBGIsKqZyj7wb9wZ3yuhvFQ7UBkNZFeXTVj1xacUMTXNoNPcw5b8Kz9m7l9cvrW6hEjhpJ35CORqVq77EWmKaOvJvfdmOcvG4MmmOCgerFr7aEdyHwfhj42fGOcV4xL2fcqywKIzf+X3NOkFpsSi7EeSGv8Sbqr98Xr1fWaWJ+ecZarwu9TXysxfZ7TDfiTNExeFoJpYDvKMsEy0yUwmVNiE26QWTBez1w/KvQGL2e2naoE5hSSmJZKaLZHpuQb123kVwSg6+x99b7SlwUkIxJjlyuysU1juICyWmqe/Ce3W5P2L+hHw4MuzuMJO3MrdfU0XUlxoXQKU827HqsU/S884qseOtujQbqR2691X8jGVMs67ria56CdR5cwIVOtQ2mUu6q60wYR9z+SHf3BnZ7Uj8Sux1rtzKvmeUaYSlIyMwys6bM9TyxPJ9ZLxPf/fCJl3niNE9cnk+kmIgxboL/15og5Vq76txU+eVitzXSih9QbVETzVpbC5rc0B7Z0FnZ1pleVOWZV7u9do80RHf7AnWTbWuzroHS3Lzq15uyFTBGm43eOYbBE4LFmtpEiQCejCMTmGPSe1Aaily23AC9d1sZ6FCTzwZ31ZyMpnbH0oxES0UaQZPR6ydbaTTKODNFMzoqFR1B3eJaQiw5UYylOEfOniSeiMPbgHGB4grJCLEkJDhtwovDhQHXBca9Frreh79jJ/7Do23QtwlB2zlu+gdjdWqmOsO25l8j02z/v9WQtdhfl5V10aC+nGpzWtgmeW1lyav/a7+0sNQpuwJatTgQFXy6SoFYVzSfqYJjzQjgRsOpKKxowaVovWHf9ezGgbvDng/v3nDc19+Pe4a+U/OLnKEknCRMSZhUMM39rRZbuj016qQivaUIMWmuU46qlVNk//VnZTA+YENPtzvgq3OTHzy5KJI6z5PSlqzmDJlSWEtSS/yS1HxEq5g6xal2oe1TFc0zqnCFFpkZJEfMurLOM/E64Z1lcV7vbkEbjUbVtAbjDMYbvNXQ23EYt8LdDwMu9zgpJAoprpRlVVthkaoP8XhTqnEImz1xXUJbneBqUKutzYXWRRqya52GhHrf4YOmz4PdAEJrdSJ2fnlmXWaul7O+R+8Zd7stIK8l1gcfCE0YbmvYpFWKmK21UCxRXaVM3ded7k0O3WM3epcx+HGk3+0YjgdcP2LCgPiV5AZWs/I4ZUrJpCjEqMXzNEc+PT5zvpz59PSkup9l4Xy9klIipUhKsRbtzYJXQVtvVNvTqEi2HRny+m6y23Wk3s91Jby6Xxt1vf653vutHNsaP1qNylZXtk2kaSnapELqNJ52b5e22ehXrFXr5KH3dN6i8ZAqqHZiKViy8WRJWveY36mFt4N0qwBpZ1NzryrVhEKq4VKp91zBbZTlIlXRVfT+kQKpaONrt/McEFu1qFaDD42t7A2vU/V65q0uYHyHZIhFf4lR0yfjHLYfcX1HvxuV3eFeK7H/9sf/XzBZSo2f5ui6XsfHVSASY9xQCW0u1GkoIzgjSg8zhWm9UC4X5NNjLQLaG9ObW4RaKFksSfmxNTBPKkJlBTyWsdsRho7QB+R8qei1domSC+fTIynOpLhuXNSUEglook9Bkd1UNH9DuaKV6y28WqTQdBvtpBKBuCacs3hvKTlV9FZtUqUIy5JrEIsu+Ibe+kpBEQfBOPUBLxErBZ/hH76554+OD/yz+/d8Op3YnSf2CE9xZd6wVr2ZSk0Al6LJmiUmPv32O1IVjR3u71W4J8LTb3/L+eWJ08dv6cc9XTey3x+rz7gn7O7A+8rRiwQRvrj/AlknSpyZn7/n5UlFxXtRe9wSZ7rQ473Dr54h9HQ+YIohlsRaElIDGRXhmLXR2BBJTaouQLGKZnlj2ceIG7SB6bzDFavhezGRlysfnx4pn57IXc889hyC5+v37wkPX9bxtKXIrG5C1vLtr37F5eWFx+8/YYOpzQO6mXcdoeo5pChyYcTgijQACopgiiWkHh8XvPVYt2f3diTwluPdUW0SEU6Xa7VBDRw+fI3bHTCHI49dYM7CSzQ8RcvTZPj1v/13TNeJeZr49PRMjFFR1DVTUmG+rtgu4DpPXlR43FWVgUFwtjVsoltKrvaYQfmbJat7ijEQjN+0RZohAd5aRRZFSBI1NRYBc8vFKQWsEawr9T7UjduWalEteoC1YMymPdqoh4BUel3MDmcDzgYyM5vLh8903vHuzZH7w0DfW87nj7qTFhjxrMUzpcDVFVJJlDLrWaC11Y1OU6kl1noKvp4Xq967RrnMSgVz6uMeAsf9HRGl5J0uF1rGzhobldJjEYIVDr1TSkwpdNbROU9wnlAnltYaTs8TU1q5RiENji5o07MulnWy7PuBEHr6biTsOvq+4+HNgxYr5vdv5n9fH58FeW7lBLQE3wZ63ZoL2ZJvS1a7zIZmtv24SGFZEpgJY162NdnsmRvF9qatqKJQWhO8+YNo0WM9PnRqmW1VXG6N0jBBMBdY5okUy9aA59cWp9zAqGANY99zGHt+/s1XvHvzwFcf3vPlh3fsx4HDbqgFeiEuEzlCTpmyFlKJrMsEUpDimKZZpxJFOF0uLJMG7yndcuLyciZerpSUsFXTpwUQCuY5T393T78/cnj7HjeM4ByrLyznE5frhU/zFVsyPkeWaDEpkZcJGxdcXHGlsKwJWxasDCp29R5fw3xTKdioNLEUqXRMIEm1PC3kZVHqpfNVlK7VRJtkKdVMr4l3BWcdK2CWGYwh5kI2msZexoHVwFkySy0cQ9ch6PMGYytabarm0FYTmhqMhzYVvlnmWv270Clg0A8jwzjSdT339w/1XNKr7KwheM/33/6G8+mFH77/Tp/LOUIXNqZAS72+UfVu1Om2ll1NsraL0YYiZ+6PB4a7Hf5+R6jQyRpXkhiyMRw/vMePI+Fw4GkprNOJj08nfvj4zKfHZ55f/obLeeL58cQ8rap1jJl1VS3LusxV6+k2+iLyyq7VVhcs0elEKaqTaRRHU7n3beJQWU56NhmlBjqrYZqvTRCaTvb1Q6lKUj+jmzsYrUEp8mqiIVW/Chlq6KxswIQ1CgRQZyadt/Sd5/3DgcMY6BxcLk+1hlPdSRLLki1rKnq+KDKte0lqjdPnkxVooJjdGqmWd5ZU7Ip1jn4YEBcoxjKtDQDRk7bRia1V6YLaEWs92DtLMEZ/uQosG0e8LsypcFkL1zkScFiTVQcmFt8NShcPHW4c8X3HcHek77u6h/3HHz8+R0O0WGiaB0XkdQxpjCAl1jCPghVBSla3gHLbuOunqDSOovnLUixs3ve5/r6Bs3S+oyUEO1uFqtbcciOMVTFlSnx6fiLMHWHoSFmdKdLLSROaRZimc024VLesZiFW35aGH1VERzmCDRFTWzYrtoYVCoWkiJTR9+q9rTZ6w7YJLPOioTKSKKK2tCXl7ZDqvfoVa0GnC9sJrCVpURu8JjSWxG7JHOzC7odPrGRGUQG4DR2uH5CcNUiFdtMq4v/y9MRyvhKXmd5r+FHnvPohl8TgIbnCpczkKbKuJ0w8E7oR3406MRpGQnfAiH4OzqnIsYSAS5l3+7d8+EY4n75lurxwefqOaV0xK1gruLpOOq9OJ8YKZY2AJmavaSJLdTCr0yyDbkoWV61XCzEJLiudLnRqvbaJOqsweHp5IoWelI8MtuNhPEI36vu1kGWPJjUL3TCQ08rhvteAOdsQyIBzASN1vVunWZMVLG+Jmep4XChOyDaSHWQnLM6S8YgPFMm4kplCx5KVT3n5y79iToWXJXJOkSUmlvNMnCNxiZwvp0qNgGWNqgGyVmlKInSdxZiCyQleTflK5TWJtRhy1bgUilFEJJeqsWj0x7ZJUzaDAlDikauNgbo3/U6RW2mLIkozbGneZUOa1KWuHQbGGX2NyvMWZBufC+q/n6QolQKlhOiGL4iHYQx4n3EkjjurHGXveZodslqmqaaVFw2obKFiHr3XlL/aU0SIZaGUrAd7CzzCECx4b+i84bjfMe733L3/wJwyc4wIC8sSiTHRG6eoXloRk8gOlmIrp92AD4hz4D3OdojAUjIldBgLHQPdsGeoBQcHXUz73YjzAe97+t7hvdOGj88P0D88fudhbhOzDf9ve0NbkyLbLw3DytqvtqwWbgVHy39qRVt5NZlTsMls04jWRGrtpNTDliFjrYIU67LwIif6vqfrhzq1V42Fc+qQM08XctKJc26Uvm3aoqWHq4XWrve8vRt5c3fgZ1++4c39kfdvdtx1EFiRedWg1pJJUc8gyYk0T8QYWZdVgTCDFodRKTaX04X5OjFdJi7PZ9ZpZrpc1DCiaOCpq5N/axzGd7iupzvc4cYd0QdOayTKwmQS1+nKPM2cooYcuriyLBM+Z9w0MaSogWHe0g2erveELqgroLPElFUflaImsmf9f6kUNlsLKrEgzqjOzgjFWbyx6pxH5dkbS3GG0lmKCxjriD7UPQqiyVpgorbaycJcaSXWOPqg7ytYR65mIUq39HVi1RG6TsX7qej0wzu60G91ivdqN9oPI6HTprMfdjpJQgFCaw1dcPRDT0wDu/1ONQB1euZdnYy0ukWkNtG67nVCrLpStQFWUBbjcMFigwFTSClUwXJhtoElZi4x8le//DVLzpzWhcslsayZy7KyLJF5WVnmlRQzaUnYWqynGFVLgGB6tQzHQtNPNFouIoikra56nXFjpU0E231KrdHq14qOO5qL480co36vNZ+91qYJpDYJ9gYElPoZCdxoP1IB2jrEUDYLehIaqfq/m5C68+CM0HeGzmd6D+GogCw+cE2GOQlpljrJUMesShrYzE2MQ+3dEXJJ9frdAvysFbweJXTBcDiMDLsdx7fvWTIsMfGb7z4iJZNL2gA8KWubw1Cy05q3TjFsUH0Pxlc9B6wukIxgO4ff7enHkf2uo7nf9f2A94Gu7+s61sR4593vWAT/7Y//BDG4addj49AZ424oupSNk12oHE5pHdyG9WzjrBsdo445pZYoVoBGewI2Kha4YmojIDquURKo0hhKJs4TPidCVruwnDLLNOEqarQscx2FaraCcBsbtwXbbthbAcs2djPCtik0RKqtUp1iVG4qBslCNFbdpUQUeTeQKyJeBIbK+SzUblSKIui50quqqxO5MGZhFzPhctXFXXIdrUMxhrguOFE7M31LurDXZWKernpQWLUVNLURJCecAe90pC1lIWWhQmAqwnUOZ8ENQ0XVVH8hJihy0e8Zh4H9MFBcoTiPW2ckJUQyKVehWM74pK/lraGs6ybwXbJuis0lCDEVxVEP6GKVi5nFINbpJmt8/VxVcGitxTeHrZyJc8Th6H1PsYHiBDEFa3zt+HNFnQL9EJRfa9Bmyro6rtWf2NZilLZuqfzkoo11JpMkshThsi6sYrBkZF6wOWJyZomFa0qc1sj3Ty+cpoWPzycu00RcI3nJmGygQM6rUrdcIKPOLuL0Z1WXr3qvlHwLx6wNQrtHrWEL+NFtzlRqEZsrhYKC5XYvWvnsPtUfVCoQUAuvVszpW1V3tWoFKhWFshgK6YYWbKz3gh7ldSpS/1qNrRpFsX7mtE1BUApxwdpM11l8cLjOc84GV2zbElTYXbRJ8rUyM041ItapaDW3sL2at+GMrsfeW7w3BG8Z+8Bu6LjbD4QY8aswdJac1LbaGTBkiinKifaoyLzUw8x6LUBCwIdR125MdKbHiqW3I+NhRz/2HMbdRnMbdooaWdvR9ZVGUnIdn98O5T88Pn9s1Fpua9M0pLA+2h6/8a4bJaEVHO37bs9a/51UmpNph8FGvTL2Nq1y1ZWuiGxIrDWWVOlGuUwbpzynQi6ZFNMGNC3LtLlZNYej1qi3d9WmGfvec7cfeHu3Uxepfc/d4OhtxpREibGmCWdyipWSlUnLpFP8NeFQY44cI2lVynJcFpY6yVimmTgvVfel96IVVIhrrVpndh30PbbrKN4zl8LLsrKkxERkXmaWZWFK6iLp0J8tlEK/rnRFabTOah6A7zyu89rMGENOiSSFJSdiqYFjFWmWIvjWABrqVNVsYx+xVjNutGJTYMQZSlB6rXGO5Pwm1F1RKmQW9W7JxhCtQZzHWk/oB20orKO4WlA6Da513hM6TUF3zlHWdLMi7rr6BqlnqaPrh0qlU8qTUtagTTR0AuIJXvWBbXKWayPinK3ag7r/2rbyW/aG7qelZFJOqjNNGrh6FVgp5AqCSinMOTOtkfO88uly5jLPfHx54fw8syyJWCmpAuRYJ9Ji6JxOvXOMai7g7AYG6/lQ123T8taGYbtPGzDWrmOb3r2qF6l1oYiwtQrtJn81yTS8Kt7afaP+y/W5zK0ZkwYoFAU3273eDiRplCxzm3q03DfYGC3WCt4WgjUEB67TNSHekxYVhCsBMGMot6k/zYXTYF+dTdLMFiQriF9dSvtgqz5RKcS7sePuuGdKGTevBAfZqWuaBcRkMAXvmsGEpZTa7FmDDUHXsw1kUWaSd/pZBB/Y7Y+Mw8DdQSejFqHv+63RsBWM1173tcfa3/340Y1G36u7gbN+awySKNcTqXxSqym77UMTKbUoUtvHVysI7zzWG9KqizDnrbPYxtwGtSVzzmGNJ/iKjJZSNzzd4EuMpBhJKeGKJSZHXDVy3RTBDB0CrNeJBhTZKq4srxau2xDyV+LYUmrwnhYxua1xU51EqrjcWUvwFikq5MuxRseLahta8mY76IoxdOMBENY4k69KUSlWxevBWoKsHA28CZZvfMd7HN2irjrMC+t05dO68Mk6ppx48/YtX37xhVrX5kKeZoIP2P0OQ4ekwuV60fAkyRijyK7pBw4fPjCdrsR55no+kZeZMr3QzxfcsKfMV0qntremH9V/3DrVaoSOPAx88Sf/OV8g/KJkhn0gl8hvv/+WTz/8wMvLM08fP5HSqgJ877XJKwYX7nDO0oeeoR/oQ8/hcGToR8ZxX3nMFcFxogLDvLJeJ+I0I1kIPnAcRr54eM9pTfyP//avWCuPvqRISSrgNJ1gKsJgkmavOBMqii6oJZwiL61OSej1M4AtVPchtbBb88KSZz4+P7KuC3/xl39JiQs5LpyevqeskRwTKdYm1arhgO6PZhsTd6IZKQZDwkCpQZMVuTIa9qEWrdWVRg+v1ljWDRJICA5FXygaLllEyDXUTsTgK1U2aSujm3DOGk5prGZBFFH+UZ1YWHPTCRRRrjU53zb+uikq0tsxV29+iaoLctaAq5utdSxV6KnTD33d4AKdd+z6Dikngiss6xO7XaDbO7pBNFk4Qc4WSQaTHS4lulw4dD1j8PTOgUQVUgbPWgxLEk4mcZFV7Yi7HUMfGLrA8TDibMGaDGVlXZ74/tsJbKCIYXCFHKBkozSQLjAMe7748ku890zThfPLo1IHuo7xeOD+cOBwvMf5DuMGXBiwPtCPPbaof2VeJtIyk5aZNZ4xyaqTDBZrCrKcVYeVPw8K+8Pj9nAVNbbW1vC6xq++FRRbO2HsbfJQU8IbqFAxpTott5U2IJhcPnu9VrCobSqA3abmtr2WKOVH0dNMicKcVpbpDMbUvIpyK3qKTooVvFJOupRqtCDqorYLhv3g+PmX93z94YEv3t7zYQeDWfBLpkwFKZkYV3KM5FIbjUqjTauekWVdyWmH8R3rmnU/ygUzrTCtlOtCmVZIhc4ExJZtf8F6pIqGpRuQfuRchOly4fHjR67LQiqZIlkNVUpSWpMUQlFvOEuztgfjDPgEToNvg+8rulxYU2ZZE5clElNRUXijnsC2d+pEsgbVOU/cJk1u0xqWWi/YSicCq6BedfWKLigMYi10HWItyWoQq+ogNG9DXQmdvl+reRabDsd7bRLG/fb6Ti3qbii9MVCS2m2nyKWkrbm1RqeYNnfVuEUPMK27LLaKjx3o+hCp2kzXpJ0VCCvklFjjyrIuPD99Yo0r//4vZ9ZZqePz5UJcV1Ks60NXNimrDWwRwXCrw9pM20nrtwXJ6wYGxVKoI6WtSbCVElShrG2t1w+k3pN2W+/6DhrWqK/bGBoiBYrF2EJX6fillE136GzrAqqLk5RtwmxQ/UI/dHiv7cq6LKxr3nJxDBoS3RqBJKrVK0WtY421hKHDOUPwhs5EnBPifML3PbsQ8DtLLLBUrVVJibzO+BIZDAydp3cdnfX0OeM7da5ci7Ckwst1YTKFLBCCNql9CNwd9qq1kEwiMU8nfvhtwngFW8dQKfZGKGIwpsce9nx4/x4fAmuOnJ8+EpcrXd9xuL/n7v6B4fAALpCt0vmc83TNUhpBFk1+T8uElAnigi0z1oW6joV1nshx/b179H9CMriOCnFWLexQSknzeFfaTpsOsF08UzvPkmsmBFroSAHJYG2odI4MphVHZusoM6miskJTyEilGWHB+6pFQNQyF0OqxZFFx82SE6UWU6aJ3VqScEMbTBOpN9TK1vcDJpeKwIoW1+bVz1f335wz61KdJ0QdqMRo0JkOM/QwkZqpYYzFVIcqVwrOL4CG6ASrjcYByxtr+cp73ljPDoE40fsOGyPf/+pXyNdfc3hz4Hq+Mg4jKUZ8pW4ZLN56pdb3HnEZkzOdqSIjCmuBKIbkI2ZwGmIoBlOi8unTQp6EOSb19vcB1hUTOvAeIx2SMmkthK4FLQnFByCzvyuYsOPwduLNl5MWlXnFZEUKpDpxGKNiNhW0OfWL9kGLNNP+3mMCYIVAYjyulBirYN7gxXJaEt8/v/Dvf/0bPl0uXNeogVSrHlxd7xjHnrvjXmkKqepFTJu2VQu7up7bzrcmFQVKzKxxZU2JeVmIeWbJk4r3UmSJK6VSINYpV8tH3ei2aUATZRu0sG9beV1+VpTW0LItEMhSsJVO1Q4Gfa62rb9GPlsxZRFTt/maNgoaiEcrxqhrEalhctpwq60mYG0t1Ep9K0o8L1oN4EQ2AZ+UTMFvgk691fS1G+qrY3/UN9xDsoU1omsBEJOUQWdk80s3GHX66jw2GEwSqNdMMJCF4Aq+F4ZgeXMYOAw9JWVC1zMMO07XhesSwcz044gYRRadVZFqHzTHJuZEkeZlPhN61dUMhz3d4ci9WCy+UvEM92/eELznbnfH/X5PijM2J/bjjsNuTx92WN/huj2m61VMZwyYBUjkeEHWibxMLNMVjCN1I/v9DufVnW2ZJuZ5/rFb9d+7R0zVTUVeo2t1b2a7RdqXt4KMhqxym2S0SZvlFf3i1fM2AKqFxdW7DM1okkq/uJ0jqllsU8P6inKbsFTAXZHGWlCqnqkgrkCuid5WeHs3cLcf+PLtHW8OA/vOYvNCKStrZJtc5BQrNUzpWSXrNGBddF+KMUGC7CLFJ1JSH/3lPBGvM/k6IzFhihobFOdqE2Y0qNV5JHREY1hT5JwLU86c54U1q12zTm9UONymGd4InTF0QMDirGwFcin6eS5RgzxTLkxxZUmZNWeiKEJeaIXoTY/vqo5STK1PvDYBtrkpuZp5YzUHQOrEBOdUZ2JUn1CMIRsNOBPrKNbi+kFpJj5sjUZzaDJOGwzTdBqv+f6NNVCbomaK0wrxbUI5a6ZTzoUQOrUkHgdiXMjVKUj/qU4oFOms9sJSNQ5R/5yzNhcpJZZ13hqNl5Pq/Na4kNaVnHV6lSvToHXYhleaInMTTbfpSeUzbULl2z31O5OEdp/VNV7HSvV91/VvzMbIoCL923O8/tX6EnSyX6iib3P7Hmg26vpct8wweRWip2uxZGWfbIYQokZA3jnVLEA1TwAjwpqK6iORmg6/tS76yzpc6Gq2RKpEEq1FTYnYstLbQhcc3W5g1+8Y/EAoha7v6HcDz9eZaVkpztNlKMYxDBos7BuAnVVPHIFiCnMWPb9C4P7hQWtoVCSuWSuB49093jtEEne7gbROBArjMDL0A13Xq+jb9/TDqHVYyUiOkCNpOhPnK+t0YVkWrcFCz+5wh/dBTYamC/P1wu97/CckgzvUzcUSo3Kfg3fkov7h0goTblaBdaaphUlJGFsbAvG6kWbRESw60t6WWnOiAcU/cvUlFo+p9IsouXonC5vTeM408xhPFdsZS8qJFvPelPaJFStadJn6Xm+9N1szobBvRYLRUdYW5tLuiiIkySTU5lIPDxVgYXXMuAVQSt2QrMV4pzoAV3RTLIUuF4LRRmMvjreh5+t+4I3v2JeMxJlu8BAj3/3VL7l/947jfs+vf/OJabyyzrMK4IXKI/aYYikBcAlbMs57EoVV1C4wiyWHjBWH9b1+ZtOZPF8oaUViJOYzfd7jfIf4CJ3XzXe4R2KgOOWBYh3FGJJ4jAmMB8twd0+z3zLV+aTErAIup64+1EZORXs1iKoW4CqdsTjfYXv1FDdO8xWsFDoyZc3Ea+SXv/wVv/7+I//u178iGUMS4XRdOF9XrvPKYXA83N9x6IMmmKdITpkm6tQdRqcWxt7E+muMNdBpZboqMnQ5n4l5JuaJaVmI1X+9VETDFIOIA1G3mfYaYhJshbvRIMatCVGUp+3lzUaycLORrbeZbvjbBiv13tMDtRSl7RW2RarFmJbtlJS2e6wdBLkm/Io1emgb6jVN2zCyIcRFcrVg3mZNFTDQV23Bf42QaqxylHtfC+2ccRaSZHKq3m3a1eshVOkqtiKW1qlA23iDKcqmpjYyphSGTt00dqPl/duB+8OBuBT6fs9ud4f/+ESYFtYCx37E+o7Q97U408nnEhNr1tfPUlhjZheEzjqG/Z5+2NH1O6ztyJJZ88phf6Rzga54Sj5S8sx6OjF0PX0/YlFHHt/voOsRIOUVStZQy+VMnq+k6cry8oLg8MOBwVsCHV4gTTPT6eXHbtV/7x6x5aEImz7udj+3cr421TdAtT5uBQ61mNWwP7OBaFI0g8XUgkjrJ6ln3+eNhuoStRy21mz3y1YSvXK22c4XzOYW5Cq9hpZbkcEbYQzw7n7P27sdX745chgCO28wcaaUzFoyJaXNErYh3qUUcsrklFimlZxVmEoSvA0UG4lLIsbMepmJy0qeV4iFTbxrK0jiPK7vsSEQnWfNwiWunIow5cJlWbd7txT17Uc0ccYBnUEtdjEESjVF0c9Cw+Uy87rWhr8wrVGnGiXfsjpaoSmQTc2McpZc84/EWXINKzTh1hQ0apXuS5V23f6NMeoM1+hWdaJRnCX0PdZXUM25LWdJA8vcBjy2gqHtkW0CWSro81qj2lwtlVJXWBY1pxn6gb7vKTnWoEDNGktZJ+9Krc7kYqv+RzVpKam711Kpauu6Ms1X1tpcXCd1f1KDnkq5zm2C3+Bg82qN1ztj0z3oFEBqA7z9IL9zb20P8/n/tlpJm/RKuannqp5M6hyKuX2t3aSb5fpW2jfK+6tGQ5o+sf65tEZPtrhukULOCYPbQqBb02MsleYW9PxLmm9G0fuvSDWuKUXrtu3Hr/TJ0OG6gWymCoLrpMUWtZG2QU2LDoeRw3hk7He4DP04MOz3lE+P2HkhWsdgPMZ5dvvjxi0utbbIKWtNg0oFcIE+dLx5eKMOl95TTIexHuM7QnVh7UyiHHeUdUaWqQIaqtOwocP2YzVNMqRZweAcJ9J0Yr1emC8nLtUMpRv2DJ1+r6TMer1yffn9Z9OPTwYPOhqOJWkSjzUaMIVupDEttyVlXy2Qot238w6rwyn93WRFW7OtIptbEb/x5mquhRHlnmJSDUyzpCXfOuzaILi6yE0d64A+lXVtiUIuKsym0qFcqS+FvLLirdy5uvhN8LpBJz10MOpQ1DQaa4wVONFURWvUQKzzKjorleeJsYTekHIklsjpPEMp5LRoGroUhqqXcBTCnPj6/Tv+2S/+mD8LAXs+8/LLX2JFuL6c+Nf/t/8H/9UXX/LmZz/n9PiJebpwPj/zn/3iT9kNO4LRwixLZrouOKM6kt3bI6lk5riwHwbWaeJE5PK8kBMc7+6R/Z4SV374zV8TpHDoPHZ5wSSP+MRyLRRrOb7rGHxgMAk7P9dDyerGbC0heEXrrdNNygTlMRoULQ+eavag1yyLxt2HUA9+tBCtHbu1etAkSYpqp8z3L4+UNZHnxP/r//Mv+Kvf/IZf/vqXhH7A+Q7ne3adUtKsLcTlxG9+NbNMV2LUiYexupbmeSLGlaWiQSkm0rKyrouKEdOiG3W1Dd7CJE1rBgqu/UClbeT6kSgKp4V+ayas1TV3E6gJpvkzVlTVGOi8oZrrflbsNMcoqUWPPmlFXYpF0tY6K42qmgC0gmxDYK3B+h68+nJfikOyMBcLosGEbUpoUZpXTrBEIXRVE2Is87IiayR4Xws0pSpowKEaO1iUntK51kRFlhiJOWqTjcFJqaFjpiKQR5CB+XzSiWqEkUjfGQ5vLO/ePjCOKq7OWcOuMpkpCS+fnvn+8UXRUWM5DAP9uONw96YK9ArrdYZ5ZjVhs+gM3UDX9xoQ1g+Ersd3PVJMnXBZWAvGRfZDE8EbTusEcSUvM+H4huA6Qu8wQdf9usQqfrSUZWW+XFlenum7HhdG/O4O6wZiFi6nE58en3l5fv6xW/Xfu0c/jjf489ZB/A7SCg1EaBbOCh7ppKFpDZt4fJvG13XdArVq2QK0e1aTnG9NjbDZp5v2nK8KsnpmfWat2aYbpp6OTgEoIzB0gV3n+HA/8M27Iw+HgTeDwbNilwzrXKcWlV7XppQVdaXqivIaSdOqP6txNU8pMs+JZY7qHpS1mHcFxDoVR4sQDYizuL6DvgPnuaTMOUZe5oWLqKbBVj6ms5ah7/FGmwyuFzrJDCIcLDqBzhEnGU8BS6Wh6uQ4lUJMhanSpaLcNGCtqBcAp0WZ6fQ9ibUU7zEhIF5FuZvvtLtZWm9nVJ1ObCnkzqm7YhduGgyjE/Vi2/eaag5Q7cBLBcTqxMSge/yms9kar0LKqbqJ5VtBbZTG6qy6OsY18RyrMUBOrOtMzgpyqbNTIuVEiu3vV20Oc1JXyYrm55KraUmd/EoD72p9Y93rVbKtwzYZl3b2wI16+PrWqtaq9jasqH9x+619aTNYoN1LrfhPdf8vGyZl6tXdXr/dQ/X6GO+JoCJ02Kx5Xbv/2wvX/399v6o9tRoKlFzIBYzzasfc9dVBzGjApdWzNaXCtKyafZMU3Haoy2rXWWwXSLZjEk+KgZT1nvHO4/cjx/09x8Ox5sXdYyQgYjk/X5lz4vnTJ779+MiSM9l6dsc9w7jj4c1b8prIcWU+nRVcNcJut6u6IG0svPccD3u6YST0PbFYpjVzui4ssRCcxfeW3llcF5ivJ8qqU7KxOxA6R+j6auQCQ9+RWMmVVbFKRlJi7Ad86BkPD3ShQwqcT2cupxOX04nf9/jRjcZuv6tdofpqg3KljWmj4eomYOqCKW1PfT3nsCC2OgE4WjKjqZuT3ZZo8w8Fg9Xxc85gtUwryd449VlRzcanbyK9UseWLecCg4qN6/tTPq3BGasi9noi6M0ldQJRYeMK5243g9GbwVXrgMatbUmfxqhThbFB/9xyDIytvHcLNckY6thvQ7j08/LG8JN37/jp+/d8/eEt7nTWIlF5WrCsxNOZl+9/4PHb73i4u+O6Lnz322/5k5/8jMH35GI0F0Y03GcTfltU6F0iJi3YNGHjBRuvOsEwGppkEPquw+RITlGvjwjOrmrzisXGGZs6bOrIU6q+zJbU9Cuh6jqs5mA0viOCbuQ1LV7qtcM0z/TKFX1t8SiGUpO8Y1ko60qJ6qO+XDRT4vHxe87nJ4wt6t9dBJ+EXFZS0YTXqYquYrXkm6YZqaPpZZ2JKRKT6n5KznpQV6eYVDS5GqniSCoKahuLVW77cS0mtg2XOgY3ZdsAbyJfowdCXVObpV7dLJt2iO2/+n2l3Wj1DBajSGs7/KQ17QaQXDff1vwYhtBTagNUrGbhCJYoDjFCsUF1TirGUtDAGBAHtiAuv7IAtDebwWoXbZzuCTd0V5uM3TjQ9x3WWcYDXK5XLtMVU5ZqyWcJXkWizgdy7lmXDsl7SsrkmImzNnnOWoauZ+wHbBfUy0DA9BYxmSyRbD3iLcF7wjAQhgHXdcRlrZQNDbI0Ap33hK5j3A16gXMiXy/YnFTcbyx5iUznKyUM6rQyWLwDgsVbyGlhXheGw922V5Rq/Y2kivS2z1NBiv3+SBgP9HdvicUQ48p1LSQCJow/dqv+e/fYjePm4pSSBp/KVgS2wr4VOvqlZmULdXvfCqR2dzQkt9xExu3f1327GRhsWqu2h+uz1udpxZ20F3jVxNTCt4FrDeUtGWuEYOEwBo5D4O3dyP0usO8sQRJOsjoHZjX1MDljGw2m/hwIOl1NWYukSgFGjFKVs5DXOl3O6nYj1ap1GEelCnUdq7dkY8nWsqTCmjOndWWKiSiNzqQ/q6s0lLHrCEa1YqwLoUBfMr2plqM3bBqoScuV7pJKIRbl2quTZSs/t50PQaecSmfy4Kt9j/fgfW002kRDgS9F5M02oaGeyWqZ5Cs1XBsMalGLNEVJXSil7vBtXzdtrZhKgy03mk65TZVKUTt9FbPnV/v+rfjOSWupJuIvJRPjovrTnFiXWZuMpALvnIuK+VNCcq7W4bVVqKCVIHVP51UTbl6tzgoO35Zn+8pnNKhbDdSab3OjO5nbqdcaaz57jlYDtvugNRqv/+Z2fzXQqjUzesYqlUswZLGVPuX1vquNfbtNjWvapma7zmbi0+4N63x1mlTtLNapIY019MNAN3icd5QC58vE2U/M61pNfwI+WJy3iA9EOlaCMmVyIZbCtGScEYbO03UjwzDivacUV3WpoR7JBZwa3NjQ0Q0D3aCUqJxV25VFayGpdXIInt1+vzWs8/mkOtTYU0xgnVcuz1dcv8P0Hf3uQI/DSmLNibImUiwQV0w3EIwlVqMKkVyNLG/GPGA5Hu/pxz27uzekLKzryhpTlRP8jivl3/L40Y3G2/dvapMReX5+Zo1RKQCbk0zGGy2IbKxvUG4LSnvXgBG3ba6vWwsV82RoYlRpTYitXM8a1JVBkiJMBtQdyVkVcqNojXOOJekHl6SovaVRRNi1tyUrFos3jmylFlXqN04l6rabR0fRfBYoYyg314iuekMbV4WJ6uKdRUWFrhbXYqCUWDfm1nyAmKVOQSqXXtSL/5/+2T/gH3/9JX/89QdOHz+yTtdqVShgC11IfPzl35DuH/hn/4f/I3/1N3/Nn//r/5l/+k/+c3I3ktcEqINS3/U15EdAZiTNyHKmnJ8olxNy+h4zXTExsS76vg2Gh7sDcbpy/XRGek8QoQsLvbGI8bjlgvEW4y3rNVGsAecpYrRf7MDYADXIzlVHjWKU79tbwQa7IUsmZ5I0XnFmXVe2EEEq77oUlvWyiWglLpweP/HrX/41zz/8muVyYb9znK+JdY7MeSLlKylfmddEXCOxTi5SSkyzNhzq0BFriyN4Uw0MctGRKpDFVb/tyl+2kKxmw5i6Z7am1dSb9VbQZHLR6Vc7M3UjrhoNp0ibFN1orXEbyqOp9GUbXbdN3mwULH0UhBgXvK/5MdV5Q+lZdSJRr62zjv3dgSXp5riqjwuCIZpq/RgcNhsN+pJVN7qKMtlKD3S+Ub+0qRSrPvjq964FmDqgRAyGrgu8efuWh/sj/TBQ6Pn09MgPnz5xefwea4RxCJrD4j1dtyeuI5IDgz+Q14U0z5yfVowt7PcOQwfGM+fMIh3JddjdARsS1s2YMeEpdH3PcDgSugHjO5bLzPl8ZTpftGCTyGANQ/Dc7TquJ7X5vFwu+l6HntB3zJczj9//wLB/Rzoeefu2ZwgOHzxzb3iZZy7nK3fv3mPIWKN5DbkIOa0YUe2ZcZqlMIwDH95/YLx7w+79V3z38ZnnlxOn1VK6I8Hvf+xW/ffucX9/JEVFd5d5VtQ3VjvlViaaWxFzK/Ar5eJVAWa2RsDe7isLUt3Sbk6D5jObzBtlS4uuVvRsU0puxdnr57gV0EqxybmQJanVcmd5dxx4OPR88/bA/WDoneDzXHVphZLVxtaWZonbSkhFfYkZiZkSlZ8ujZZaCmTIS4ZiMNLOMI8Jnrv3HxiOB3ZvHlidZRXh+Trxm+9/4Pn5mR/OZ6UFOVdBRG28nPF01rLvOk1MpiCzw6dCJ5leCqYi7kbKTd8l2likrLkKSdR4pdSL9ooZo5+ZsSrE9tpsUINcTRcQrxMJcTddqXW+uju5WnTW5zXt7KnTDHdrTox1VLySLLm1rLdL1xbVrQ/VWqcGPeacSPWMeU1dajaq2qzenIF07UYFP1L7Xl3XKUXWdVX6bnlFMxe5ha+K0HQVt8etsNcm6db8voKc9N+b1/+mPe/njYh+X8ulad99uzi3Z2vAV6M1vX6eW8vRXkfvAKoLoMN5qzQyLcW4rgnBomGXGpyKt5iSNgq1bfc3QimGZNhYLqWZqmDUvt4HTWj3vjaDibhmnDfsjgfevjmyG3sEx/PzmcenE08vJzDgg8P3FhscxQcWM4AEguuIKTLlhceXE94K9wePmA7rOlKW2mgaXNdrALAxDLudchW6gXG/pxsGcFZZJ+vKUqdbuWSCqNPhw/HI+XximiZ++PgDfdepYVO/43xd+PTphd3DO/z9Pfuv39IlFetPKbJOE3GO5MOE6UYChpgKUhIprXgjOLQhEnEY2/H+y59yuLvncP+W3377Hcv6zLxGxCi98Pc9fnSjsV5f6mKPdFZwARagJN1sLRqc5wS1aDTKOU0Rci6wJuVgc6MfYRRdbyiA8tYNPmiHd0vr9irsqZxPU6q9LbJdvFTXsq83iUKIzVMaSqlpnkpfxXSDctlcwJn6+qIWoCXr87UphR/GOnpUtAFDdUJSUbty8PXGymjiaS7QzH+NOEpsI1cwxutidSPWFsLoMGWBHCnLlT9698CfHA98OF8I/+6XnP/9r5DzM9N85S/zyvTuPd3XX/O/+z/9n+l/9nPkzVv+2//7/5XnT49cHp+5fPvMIfXsupGYJnJRipozGSORj7/9ay6nJ06PP+BLLXpkwRUIYulcz2vHCZMK0dVxeynMzmFDdSEbPIXIdH1iTbF+HlIFcmBc3dyMCr+TgWQNxSj6NPcD4bBXjqHrcKGn8x3GOLL1uN4xzZFKeybmFSRhk9Fgwy7wnC58+/wD//zP/yf++b/8FzyeTswUVjEkgZjQBiJFYkWTDVKnbsJaUN6/ZJBIS9PUh8XYQEFPHIfUQsEgTuWJ2kA4/axuNmaVp6z/r2eXreJ2aNttS5631Aa86MbcvOEVnRWi1PdHqeI8qeiVcl6NFRWBCdgIwap9YrJstrZSfck7q+5Qfed5cxy5LgvXNfK4JBKOUnNjDAUrSZ2YbKHEOmVyhtA7QnG44smiwT5rKpiScB6G8cjd3T3H45FxVAeql9MzZV3ovWPneuJlYT0vlAJxWfBSePvhS3zf0e11HOx8oPOqd/Cuw4o6XSzXK2RPkcwaLI+p5zo5zRwxmuhtyVXwHxl7dcpw/YgYz1oKeTlxOX3k8vSEzBOqtCw8Pmb265HD8UjKhTVFpssLOU6UtUN2e1wxvL17x7uvf8793T0//fCe5fyJ5fKCLCtlWViXiV9/+ysOy8L7MDCnwhpXnp9/YLAGL4XpZWG6Zq4TpOeVMD3hfrjy8dN3zMtESbHaPP9+1Ojv6yM4RQYtSTVgkjCvwmOlIpVbTk49W0rNq0g51SJMG3Wqf71SEmVzlzJWw9RaQFqpVERpkxPTijWFalUXWAGSWphqQWWrtben8iRVmFvUNaqzcD8G3t+P/PTDgbsx8GY09CR8LviSNitniQlygVzUtKS0804n5fMSmWNiWRNrqSnCxRKznl3ZOJIxZGewuz1379/z5ssv+Ef/63/Gw4d3vP3qS2JFPJ+nmX/15/+Gv/zlL/l//vf/b06XC9dp3gIlnTGq2cqFPE0kyZiSCfNMkMIghaHWAEluBaomVFe7T+twAl4EkzVIMOYW/sk2RWhmFfrRy+bYV9EbPfvrpaC5dxkLzcmvTZs3cxizuQLqZm20SSHUVlU/T5FS91MFMj+fWmhzm6LSm3KqFKeSyZXadstzKbWxzHWST9XNKZWzTT2URdKaZv2BDM0Zzdwof6JU3ta8NAoUaMMpv7MObwMV2V7fmAYz3VoFU+lLpZ5DCqBRNUnQqIfb821jCtl+WfQzFWqydX0v1rptDWxGDkXULtgGxv6g53cumByVWW0sGaXxm5Jwpb63vCpbw1n6vqOUgs+maqa0RnQodfz+cGR3ODLu90rFipHr9UKJM0MX+OLDe6SsTNcr85yZpkhOwv3DO8IwMBwO+LHDBU839oROrYxdNrhphW7hMnuMRCQYptxRFkNcI8YUjPH0occJdD6z7wd1x7QOV4SyrFymmafHR04vz+R1VXC5FDJqVTuOZ+brxDpPrNcLJi7YuBCAHfDFYeDLrz9w9/DAh4d71pfEsqrua11mTi9nFn7Lcc2Y8cCcMsu68PTxe9UHGji/TFynhet15bffPeKfJmz4xKfHTyyznk1d37Hb/S/YaHhn1CWKsvHCN4pR0UmCRV1xnL0FGZWsDkw6uS51SkG1mjP1a7qht+bEB4e1vtJRDOKEksGWuBWJ1lWaU2mOUHqjqIjPbHw7ct5cR6QiIeJs5Yvr2FVKBLG6YVcBcJPvGam2nE3Q3W74OnrXz2IbtqOKkeoSZM3WLBlj6w1nsMYrxcppcepM0A3aWWxOfNWN/LQb2U0zkoRzKtjeEnc7zJs9/pufEr76BvfVN9j7B0o3MC0zxlge7u5ZLhNTODPeByRXe9IsFFmRtDA/PzI9P3J9/IiXiLNCCAWD1/crdkO9wah1mnPaMLaNq26Y2s/pJEBiop0I1tV8g9RWUDsclBol1SZR4goCuYu4kGEw+vquqxso1HQ3wKrOoGRsbiPqQkwr1/nKp5cnHl+eeTq9sJREQq1iYzbKYS6Z0pDJKoxGqCJozdT8DNVprk9NvVYLiIZIlmo5pshPFfu8ov1tHNNafLx28rjRChuP226UrA0gkraVt4NGKV+N09reJkUnYbcJ4SuOOb8zIq/f0awXnfUELww4Ds4RcURjNaQrt5+r+oGb5vIC/RB0WSVBYkVtjdpZe2sY+4H9OHLY7el6hxFhmTpiSnhj8UCMKmLMWR1TjBj6/YEwjISD0oicDwTjNZnUeUhZp6IF3O6o7h4O1uLIq6Ek1XJhNLCPknAlsXfNbcYq3SNnsiS1lZ2v+KIOL4KozsTOvJyuTNeJZZ41gydHSDoJNb5n6Ha8uXvD/cM9h3FPujxpcGbS4iCnzOV6xXYTcU2sq2YLXE4vZKufwbpE5liYk+H5MmOvKzllzqeP5BwZ+k6XlLgfu1X/vXtYo/QzxTkbJe1GfxXqNKE6n9nGE6/7+aZ5gm2/xig9V2oBZq3SFppzmrMGEa/6iIpS1wOjPlG7f9vjdjfqtFhfowWvqchUJy+73nEcPQ/7jrshcOgsvRVCLlhRipSp+6ysuU65lXcutcEoottmipkUCzHDWqCIqa5aSpEKg7rPuK5nfPOWhy+/4O1XX/H2j37G/v6e7s2DIs0Cckh8uE7MGN781V+Tf/iBaY26lxirNrBGk7klKuBWcsKkXJ2zINTPXUE5tj+7evYLpgr7lQJqTG3+NlBcqU8qzG6i7Fvj0IroJuKvKA5tJYjVMxrTCt4qBq9PL/Xr+mcLRhuNTG0qqsaiNRm5ZkA1Z68ipabO55pfcdNNtDA9qWBrayLampHSjGTYHJluTYmeWdsQZTtL9PPSg+l2dtwmELWUl7b/36YX27fcBjPcJh5VvbE1KNKOv+3pt5+lUmJv31BnXFLPUyM3mhWNctUo1PV5NzMggzEeawPeD/r/HnaubIkU16jTIsm5vlNdHFsmUheqJkaBbigKgNdpydB17MeR/f6AOMs8z6zrQime4BzOGtY1E9eVOCdyFqyxDOOebrdnvLvH9h02eLpxwPmawD5ndaDqA914D2XFuEwslrKq65utYcEUWwXjhcG5rdGw9XNd14XYALVGWxMN8MXOvLycictMXGbSumJzxuZE5xQ833cdb++O3N8dGfueZMy2/nIpxJzJ84Sbr/rzl8IyL1xOJ3JwdNYQozrS5SycThewMxk4nU/kFOmDAi//i1KnvvzwnmmeOZ/PvLy8aAGbVsgOIw3lSVhT6LqwLayI6jms1eRDEPpuwA0W28M6a+deDJvwctgNVetgSUmLBSOZvGqh5cRRbA3vqRMGg6kOENpsON/rgreZNeqEQYwn9DtCP9Ifd1gcRizrdNHsg5TBGRUMr7FVudrYVMRGySfa2VgrGDHVZk+LmGaFBoau3xNChx80oMdaR0miCLBk5YoK2GK5Y+QgIz8bdvyzbuRPkmf4+JFZCh8duJ/9gsOf/BH/xX/9v2X/s18wm8B//z/8G3Y/zOwOO/7Lf/Rfcbfb8bDb8zf/8i+I5yu7oEmr1lrIkXW5sE5nMiv4gukcyzJjc8YbIZJrcS54dedWkbSBIXii143O21D5pAtdScwpMS+RYPXfeGsJlu0A34wB0ivNDAVx1d0nXREXcWNhWQTbF+67UalT80JZVgzQeeUtSk6keGZdV+Z1ZXp55no+cZ4vrJKIZOY4K/JUwODB5JpaXz2ScoLmPiGphmzZLXVU/bVVU2Sq7SQIKSVsaWnWFXmrGyXW1gb4hhhpfopTHq3oOmncylJ009EiCNqcWPsadd+SNsoR6oEqpJSrLavbqGQlZ0wPUK0eK1rWGhU9XJWytmJxZgA6ToveE4d9xzcfvmEVYYqJ3/zN37BOF2KaK20xERwMwTJ2gQ9fvGWJiZfzTLkINgt90Caj6wJfvb9n6HuCLUynE/M8k+Yrss6Id0hakaRUgDWpxXLG0e3f0e0PhMMBM+wx1lPwrBWpFNSdI3rP/t073aylkJaFZVqYTi9Up2wG4BAcd71jP4yItSwlsUhmFeEcV9LlzHK5EHZ7ChpedEnC03zhNz/8OYGEJePihJeCB9KdsDvec3x/zzdffMH9wwODKzwXiHNWYW0qrAmW84r1C/Nl4XK5Mk8Xrj88Em2zXnSsWRvi7779jnVZuZzO9KHQB0v39o6YF+KrGdsfHp8/nCkUKxoG6qoOMFdgo9J3lYbn6PpA091pUk2pGU5aAIXQb3bbOWvQXCnqsOid03TvoLQ+azRZO8WojWjT0FXypSl2K0ptbSo0aFbpRjkLxSiiHZzBeUuwhp+8P/DhbuCrhx1vBuhtoksJLwVb9F7LaybHxHKaVbOUcgX1dAogRt3/ZjHMyTBlwySGWCAWIXSB/fGen//ZP+KbP/5j3n7xJd/8gz+l2++xw8B3z098ez7z3b/+c2IqGOvY3d0xvn3PP3z7nvOa+Lf/5t+Q/tX/jORM5wP3uwNlTUhM5OmCVFc/mxPBGQbr2FWuVCyWmCtFVdQd0lUXpyJKPxJRMbhkRcULRsPyug4TOmwIChY2fYW1Wy6Ggo+ihjNFELLa11YKs0jVhdQzqtQpQJHbr1TUkVHDTptlatZJWHUXajbCuairUSna5G60us9oUrL9vjUd7WwEncxYg3cKKhhpgmyzGWrot1Uynmw4k7axcgOyqD9LfkXvk1onta1k06HWKce2xcgN5Np6ja3DUFA4Vw3N1mBw+7dKgWoNQH1auTVIVAtnYwqNIp+iaqG6EHB+h+8GfHek63ps6PjyeA/OUazhl3/zN0yXM0tOuKIAQ+9gN3h2Q8/hXifR87Jyvc6UUhjEqvOZ99wNA8dxYD/2TDGpY9u6IHEhlcj500fVyORMSUYt//uO491bwv5Ad/dA8jW0cRgqFb8Q85lCwAXP/duvKHlB8sRlvZLTwjJdN5MH1sS+c9z1HftuVBZQ6CnOqUZpWTDzhCwzPoRqWeu5rInzfOaHxzOkhCkZLyuLFK6oqcnx7p53X37NT794x/HhAazlqaiofRUhWUvxjiUnzDLzcjmRimaLTNOVdNVzzlU7X+c9P/zwA8sauUyTBhV6izmOUKzWhb/n8aMbjU+fHkkpE1PEewcSSLngcVh0A7ZeME4YxkE7ypToR08oQu4C1niM9XShB0dFYb06AOSCdx7jDCmp7aV6im1NMrmoENhkdb4qqO91LnVqUnRDtGKQHPXfGVQ8hKaZFhsoBFLutqlLNp5iMoJuXELBhXqzo+O4xq11vv5uG09Rb6c2xWmMXMGwH/eaADr2hDDgbFBObfVWT53gJNHHhbdz4o0Y/rPuyEO1R1vv9tj3bzh+8wV3/5t/ytz3/A8fn/jQP7I7PvCP/8t/wm63YxwGDruBNM0sLycOfY+kzK/+6q/4yU+/Yb/fMc1X0qIuSlIUQdYisgqKMps4rxDJVORPRJFeUdocGPxwwHmPcZZlXTBi2FVXCB1AyAbsp+rukEVFTQ1V2R32hH7ksD9SfNAbzDv8fo8fd4RxYD1duFzP2Kgj+KVkDfzLiRJnbOfYOcO/f3zku2+/5dd//SvOlwvrmtRQ0aiDk9pPosLErDxW6xWFEyksVdgORi20xVBEHaoakhNcqJoEQxDVTARrdFOo/uVSClk04GcL56siq1JH5Hq4NMe0tqGbbZEbhM5perk2pLfRtFC1RKXg64RMrWxBiq1Cc6lNXhujR0VjjZoqWN8xjEe+/uZnHA937I/HOuFxHN++JUphTpGyzMznnvViSKtFykqwupkPfaCvzjh5FM1qwdCHQFrUfS5PZzIFb5STbUUIBvCKlhAnjES8Fbphxxh6StfT+ZrpkQtlXsFmHBGTMuRMWhZiiax51cKuFGxKLKcTcb4yvTzR2UAwjpwWcmeR6MhxwvpA141avMTMy+MTy+mM1ORhYzXt2BpHiplpPrNIwhvhoRvYBcvo1dc8OHBk1unCxVoueeXTD594fnxU5Nh4rOvY9XussTw/PavY0MCb+ztKXJAUWWPUcM21ME0TaU2YvIDJJOD0sio1xf6h0fi7HtN1qoixVGqUA9SkAFQDE3ylq3pfReOxJvMWfCvQrKXvBtpYU5LRtVtUS5cxLCkRqx22TnOrCD1WO9d6DxeENaUNhe/6jr7rGYYB7wMlF5ZlIaVVNXnBcxx6joPnJ++PvBk9b0bHKAs+Z5xkTFJL+LhE0pLJa2I+z9pkpJqYjYJhrg9gNftBrNJ+l5hJzpKM4+s/+VO++uYn/NP//X/N/YcPDPsDM/DXHz/x2+9/4F/8q3/F6XzmdD7XgFGDC54//dM/4YsPHzjeHXn//j0vX33Jcr7gjGXXDax50pTxlLfcH0strkrBFJ2QQ2UgtKDSrM2AMXJzH4wZV4TOWKQKtKUfka5DQtC5brWvLcZuZ0+pKc46o77JlLNB7aupBXopGx0r16Jem4yyNWwZV1kSpVKfymeNxmvqVAOQrG2giNSGFm4jmTo5aEwIe5umSSnb5Mw6W2uecmsWGgUWUXvxOm3vQ1Cg13tulFplVZis51MDtowtVbTO7f1tk3dza4YqPczAxg6xrylrRbbXarMQLRVqUnl14KSefXofWGwtSpWKnjbGi8Uw9D1v37zj7bv3jLsdu+O92q+GwHA4qgNaSVxPL1wdzCyYNWMLDMayG3vGoacfem2OjcU5BRaCtZASFsGTKcvEYoQlJcqy0BltvoMFlyLkhBNhv9sjrkNcj/Oqw0opsSQNqE5JXRzJCbleSFHdSbXOU/3UdJ2Iy8R0ORGMArE+F1J2muZdLMZlWBNryswpcnl5Zj2fkXXFVUcsqtlKksw8LRpVYIRh6OidoXeGIXSEEDAC0+WqTZwUnp6eeDqdeLnOLKVACHT9gPGGy/VUr2fh7f2ePE/kqneLSYH6eboSY0KqGQrFME+JuJq6z/7HHz+60Tidztuf1QoOrEkq8DVOkzOD2sI6H9T7MgkuOEVhjK3iaacbrehm7Gwdc9vGEaybRbU0ddVmSww6LShgSuX9GQNWby61J62iLuvJJWqT7pqwz+G7cZto+H6vIiyvI8K8WNYUtwKtyohoKcatG3c1ddTVg6ndfC1sSZAtXXk/7HBdwI6BLuxwNpDzitofFmKf8OLYLcJDFt4Ww1e7PcM0UUj4rz5gf/oV7k9+xviP/owlZj7+xV/Sx0JnLH/685+yGwb60BGK8LREXk5nOmtJknh5fOSrL97C2JHirC5KUTmLJRdyUj9/AVLWAq+loajzk342UiI5z8yXGYxl9D2DV45ozAlvHN6qGC+L6gliqXkERchYtUs0t2th9kf8uGc8PlCCp1jDYiAcD4TdiBV1VFrWmT5lTEqkeSKmVRH2kgkSwBueHj/x6eNHHj9+YqkuQlKLM2PUjRlRZCmXG2rknAq7c1o3gWCpSFgRsyEyIhnnB/032eKLNi3ZGOVFQ9Wn1M253neKNhXlf5eycWBVa1GHvgYaB69RtzpndfLT8iXqYbkhY/WAsCIbbcBgtte46Z4AkhokeG1Eut5zuLvjzbsvuL9/YNzvN6vn3W5PLBmXF/ZDj0srXepJLEhRveVuDAx9wKMUhiEEgh+w1jJ2HfPFkmOEvCDZIclq6jBCcFZpgqZAXrEmYVBvfQYPY68TZSmk5vBFLQyWBdbIsixECpE2USzYpEVbnK7M14um+Tp1S7P1gNQfIOOM06TnJTK/nChxVcZB5TGLU31HsRCLNknFCMZ1hC4w9r6aQhQkR66XFw1nXBeen585ny9a2BmDqy4iGMv1clbTCgu7sdfJW06UHDX/IGXW5UpJGSsZKYmchGmaFO1yf6BO/V2PeV42PZlu+tWEuU6Zve9w3m97tzJqsuqaMJv7jLUO21BjFLjCaBpxQ54VYc+VNlo5kKLFIK3Mr1Y3znl8CAQfON7dMY4j47ijq44y0/XKMp0pOTEGw5td4GEMvL8buesMh05wS8aWhE0ZYqGkQpwieUmkNfH/Ze+/mmTLsjw/7LfVUe4e6soUlVmyq1pM9wiMMpAgFAmakQ/kO1/5xu9EfgK+0AgjjTDCCIwRBAaDad1dqrNSXxXKxRFb8mFt94jMrp4pmOFt6qTdvHE9PDwi/Jyz91rrr/zspclIsmYdXZQ0Vkw4TEMmE0vCa002BpqOq+98zPs/+AEf/8EfoNqOiOKrr1/x6ZtrfvqLX/Lf/+mfc9gfqgC5Tt5VwVRk58WTKy7Oz3j25IqdUhKaqQ0RmcRLlsCRTFq5/ll0cYoiVKzjeEcUw6fivJTaaGSZeGutxQnKOWhbkmvIzhFykmaiUp+Eslw1KhyprccSX5GAWCf9BSrVSb5f+laTIRSTuncdG41Kf8rlIZn6SGsqp0bk+FvJ8cg8lpMLmaoOnOroVnh0VoocE8WdsXIpx0QpEoJ40u9RKlWcOl2ulB+laoaT/F6qBh9Tt5vyiJb7gLAcP66UphO1qw4YqXIVJZQicWKSXLPHuU6lblAll+rAJtkYQvutyLyWqupItSqVEq0yOOvou47Li3Ourq7ohxXdaoOuQYmu74kpMvuFwVlUUwNcseic6Y2i7xxt6zBWivJUjnpfRWO07CGVvVGiJ8xFWCw50mhFbyxWgck1TgEYnBgeZGPIWnbfY/Mnmt9I8Qs5ephGYszEKDT441UZfDyhK501FGNwWktobUgoEyXAmCiDNO8JhwNlWdA5n/QwqTbP4vGQ0FnsdpUxOGdpnaExVlgTMbLf7SRLJUa22x2Hw8TkvTgyNg7XScDyvIyUlLFKsek7pjCTSHg/SaMRI2GZiDVbhCKGNX6h6kP/J2w0xnGsvG5LoztKUcwJGmUoxXJYamGkC3r0pxtTV6tZvyxSsKOBiVyS3DwIncQaVwVOgOLEN6UmiistzcpR22G7HmM0rhScdRjjcK49UVVSiaAFgYg4tHGcn19y9eQpZ+eXdP0KbQ3aapZxZHt7wyc//RnTblctL0U0XArSIdbq0TknU4gaea+Uwlp7mghoY2QxTYXWNFWrYEXwRibrCCQKiSF4uhg584HLGDnH0mjLYRiYVj3/6f/p/8irac/P377m1fWWqycv+N/97/8PXJ31dI2tE/pECp7Pfv4p7756xZvPv+Tl2RlD1/LB00vCdODOT5QYSN4T/UIYA2kOEBKqLLJQKHfSXlhtJUU0BDKe2U9sD/e8/votTdvxD/7+mrZb068GlG3wOXGIM7lYfCmMMXJ9syWVwvrikmfPX3J+ecXm4hJtW5SVPALh9mmSEd1M17eYaoc6b3eEOEKa0MtCnmb2NzdgCtpqNps1n335KZ99/SX/6k//hF998RX77S35aKWLpnEtjWu4PN/gl4VlmTkc9rVptKzWmwrhGpbqry3OTPVcVs8CbQpnm4FV19MaQ5wWwrxws72v1J2CU+JyEaprjFzE+bQAH1fsVGRKepx0icmJwihD6xpa61itBmJKjMvCfllIpYA21WI31fsIUpQCpSA0nGVeSLpgByf86CxUi8Yq2qZwdvaMi8unfPSd74vActkxjnd0tsEozatXnzKnhTlOvPv6DSV4GpVwRKwurKyhQ2OT4jAdwLas2hXr86c1GDKRuo6SFlT2QiGadsyLx7mWq/NzBqvROVL2t0QvKEWf90Ix8BF1YUlFE3JgzkHoJYeZsL0jjCNzmInGEJ2jXw8442iNg7ZjTp5tWUA7bKv5ztUHdBTaFClRigl/8LLupMi6odpAayKWg0/cH7aMypLR2G6D8gd0DizLhFeRQEPftQQ/sX1z4M3NHUpbafZKhJIIaaYb1pw/Pacfzhgnz5s3t8RlEQrJkxVx3OHnA7u7W0JR+KIoy0jleIoOp1JKCxmVf9to/F3H/faAMQZnRXeXiiTkUmS/8VFJSJ0/arCOE3URoyZVHyqZuPhT8SnruZYhGkfaiRL3oBhJHF9PkFEpIjXt0LFaDbz3/vv84Ic/5P333+eDDz/EVE1e0zgp3shsb98y7u95++Wn6GmL9SPP+kJLpMtehqUpExbPfFgIc8SPkRQyKSRiKFRPbKF9WYdue2g7ojEcQuQ+Zu5DYVc0/eqMJ+9/wD/4T/4TPv7BD1m//wH/7f/wx/z0l7/kX/3rP+Xm5pbb2zum/YwqhsatmPOE0nC2GaptLWw6h3t2xcbC9asVh92e++s74nxgPkyko5Vubfio9uE5Ho04injc1QFiSrUeyKW+04pWOZQ1mKajNA3ZWnzTUowmICF7sTw4VaVSkfMKEFdfEuD4b0E1jlqKXI56lnIafEqDkY79I4lH+o2jpX55oEFRWQAoRLeDTHgfqSHqtfbw9ykb4lHtAOAX2Yu1UjSN5HdEU902cyQ8QmOMFu2oNZrLsw2rvqd1VprXeWacplPeRKjCc61OfmS1ocsc7dOPP1uujlaCcstgROzGLU3j6LuelDM+RMZprtRAqT9rX15TosAZ0bvqIudJ3lDRPKRc2Ryto29bnlw+4ezsnBcvXqJtg9KQ/Ejw0lxNbyameWKaDty+eQvR0+pIryONK3RWYXVGZ3FVQjsa17K5eIo1Bl2CGH7EADnVTKwZh6JzBje0dFpJ8T4dCN5TUsAuhmKDhBSnDpxB6Q5TMiEmwjix3N8KzdgHaSAxdMMK1zja3hGbhhI9hyRhyb21fOfZU5pcaHzCJKnjKAUXZY9fW4vqe5qcCdowhcRuWfDVbrnrWkr0qJyYp4lWd+jWYq3BzzN3d1veXN9LXooSMufRTdO1DV3b0q/WeC8usvN+J43G0yv8vGdZJsZpS6zao5TmqnkqJI+smVqJvfT/lBoN1fQ1IKTFNT2mFM5dh8nC5re2wTQG0xhc8wCPHf3zo/dYK8F1RtuaXSGrgNYyETfVSaEoiD4QQ2Q+zLVoiigdpOlACW+t3qCSyWEqfUkmIFmlh+FWPrqMRPw8MWlDnGdBZqwmeI+fZqyxwglEobw6Ca60lcKOIlxfFCSdKnIh1ndGCdXomDpZSqEYgTMbU4ODFLX4TCgiq5hYp8JV0TzvVlwNKz760fcJTpHbhndvXmGGnh+9/yHq/ILV2RVX52u6xmK1FiF8zhSf2d9t2d3ecX99Dbt7Ls42nK0/IgdPyUo81nNCk/HLnhgm4fcZi6nTN5k8Q2ucNEYlsT1MTPPIOI5cPX1CP6zBOYLSqAK+IggxJWzfoNuOzeWa9tn7KGPoz884O7+kX62xTSf8ZGXQrqmiaBGOc6SiVV94f3dP3G5Rhz1hfyD7BZUWcr3Bv7y/RlnDy5fPGP+/W+ZpL3OhKoymbihJHcXGhRhL5WNTk1RjdXAyJ4qYJLoKSiDTcBGRrfqezWrFYCyLMnhl8CEQkqA3+IyqE7Yj79Q6VxtmcYU5qiUe8hNUTcetzUfKoKRxTCmRYxCUSR3xj7oFa3EbsSj6YcAYjTKa+92OkAKQa06V5qJvWa16VuserToak8UdaZHwKEdGWVvT4Ce8X5iXiU5nTGtpjUUl0CRczrgCDgjGoWyLaTr61RptDNl7SpnJBJlEGrHvG0xT3+fMtB9RwaOng/xdMjlEkvVEM4Ny6EHh3EbC8VAUbVnygleBeLeT9zOAiuLjvQSx3S4Fhn5D0w6YtscMK3KMTMtMNziskRyNddeRlaLf3rPbHTiMM5OXdOQ2g2oajOtYrc9Y9rfEaU883BB0xivRTuSiKKmwWtfkYFnCQWXO2jXrzTnr9TkhCJ3z4jxyfy25L7vbhRBGQligBLEENY7WiUZQaCTy32m48lvq1N95NP0G6xyNa7C2oRToKnVCaS1rnDHVA9/InqAKx8TjnB/eZ+fco0KSmo2kTihGyZLVIRkHXsT/OeH9XPn7kbPzM66urvh7f/+P+OCDD7m4uGQcJw6HA+N44Pmzp5xtBp5dnaNiT1MW5kah5oDOI27OmCLrYNrPxCXg9zNxCiSfyUuiZAXFYJQgycVYVNeTjWXWmikJLeTaB7beswuRCYVVlvXFE7p+Q0yKX/z0b/jlz/6Gzz75jHk/Y5TlfHOBU1ayq1Jmsx5YDT0/+MFHfP+jD3j59JLBgJkLUSdGFYlEbPZYlXGmNm/Hwl0dszbk/ValoMtDPlLWBVM01eBdTqpSAqEag3KGZKRJCCWxpMyiFL66UcUif46IRoJKnSqnwjw/bji+1WQcEQ1pJh7EzfK5B+GCKg/C6qOlrPysnChy324wvn0cX/sovj4algHEJNhG0ZBTkTDX05MfcjuUUsLUqI3G0DesVx3rrsOpwqikmfPBMyuEJn1MAj9+vdandPKTtqjkit+oU8ahaIuqRXRO5CTIPTlWO/4HpB0kR0WafkM/tFKPqcK8zIQYWXwQeqzSNOs1w9AzDD1d0+JswU/3PGgcZQ9BKfKykOeZNE2sTUFrQ2cUJifEGwyh8WtHwmFsh2pXrFdnaGNIYSaEVJG2VANjK927opTLuFBCQC0ThEUGZ2UkmUDSM2SHzYphOMN1new9Bho/MqeF7TxVm5YMaRatko6yj+dC1/SS/t61uH4tCL2fGAbRffVdyxlCMb9cZm52e+4PB+59IqlCozXWtVjXsFmvmPdbwjyRDluiVywajpcMSrEaeqlBshifFAXdaqAbBrp+IGZYFgkgPmqqtnfXTMuMjx7SIk2jhtbWyJ6j+xhHU4tHF/C/4fjNXaeGDc41tE2Pcz1aKQYyKoAqmqbt6FYdTd8wrBpqFSk2sKWIFVbTCcxXNRpUupRWulKqjr2wYpnE6eXm3W3VFiwU4+FhKeI4+Sji2nWirRydDooShx4d5Gbyy8z+vuAPIxqZVmmrRUMQIkZpmkamuzmXEzpS6iYvwWUKCZVLpwUmpVgLR42pdJioIVtDsYbGWrLWpJrQqYrYhq5j5iLDMzTvrc949vQJ3/2D3yH3Dq8KP/vFT/ngez/gJx9/j+G9l+h+oPR1YlfApmqbu2TG3YHDdsf+/p4pzMT5go8/fo8UhRerSpGE9ZLwy47oR1SJNLqvTiqGYiSwrHMNQQElMi8j43xgmhc+/Oi7rDcXFNfglSakwn5ZRLRcCsPQsFqdc/nehwwXF7iuw656rGvRxjKFIKnOGbR1yCYfJVFWV/eMECnLzHJzS7y/g92OcH9HSUJ1yMkz+5nPvviKj374Az547yXTeGCZxhokV28EU4TSUiDUIjKEJC5JReZb8ySOKeIlKw1CjgLxaqXQrlo2alh1HWe10ZiLZlGGmBI+BpYUxf42RmKJQvFTisY14qceZCqV6lThmMdirX4IrcoSeilJvDW0KgRxVnm0aSklvusWjVOG1XpF27U0XUMyhXka8csoKIY1PLvacHZ2xvnZGdutLPb7m9cyPcuZvhEntqjqVHEO+HFhszmjsZbOadIiULONgYaKYjYNtAN6WNGvN2ht8GYixj0pSRCWsQarLL3r5VxME+P9PWWeafxEW1JF+cAzsihHUR1taenODF23kSZ/8Ew6MLvEtL9GpUhMoJMI9nwsJC8L5mp1TmNbbNNQ2h7Pgl88zdDTdh3D2Yqzqydo61jf3vL661eot9ekw4FOFXxJDENHs9rw9NkL7t/BaODm/g1BJTyJ1DjxZS+wWQ+0XU+ulEE0XDzZcHZ2wWZ9zpvX72SVypr5/o5p8twd7ikESokoErZuzKlR5AhFFUIWNOOYWKx/g6nRv6vH6vwK6xxt09E0nQyrMpXaquue42ico+sagfr14zwLoZ+YKvY+Pib21OUU7ilajOVkPzpNB0LwhOCFwxwDwXsur65474MP+KN/+I/YbM7QSvM3//Jf8eb1a96+fcNPfvxDPnjvOR+8uCI7jXKSck8a0X6HzpLwnWPG30/EObDsF5KvWRgRiragLMb0kordNJTViqgU2xi49QuHELnxC3sfGX0gasO5cWyunmJcx3RY+LM/+Qt+/uc/58uvX1GMYdUNuE3L1jZE7wnzzHvPr3jx/An//J/9I15cnbHpHXevPqfoxJxn2rLgy4LNC40pRKvwRyt7hIqUFZKJoRSKjCkP1t2lZAwScltURSI0YCThO1uh1gZVxMwBWArMqVJJEDOFAsRytMI9IhTScIhgWlqdXGlExybjSJctj54vIHT5RlMh5dWRjvWAZBybjNNxZMjy0G48FOOc0DKBpSWEuCB6RgXYUsP79EMJd9T9UQ1LsHJ9G6Pp2ob10HK+GiCJXb0U9/KDxCRMkRxzbTQ01jUoVYP/jtkApdS9qYiOQEvzfdJp5kQMnqPV/8mlUT0Um0aLDso1jmG1omkMbWPY7bbM80yKS0VHGi4vLhhWK/rVijB7So6MuxuS9+ScUKXQNi3WWmFfLB41ey6GFdY6GpPJc4CUsQWcthjbkujQ7Qq7Ome9uUBrxThawjSTgkch5g7OGRonoa3TfuRwvyMvCyYuNDljKYSQCWiC0pAsg25onym61Uo0qo1hTDMTgWm/Ez2NyhBFG0y2pGWmpETX9rRtT9N12HYgpImpzPSrFW694uLJJV3jKjthovv6FfbtO5abLUlLxIAeevph4OWLp9y/g8M2c7MLpKUwHzVQ2mCM4/xiTdt2pOjx0VM0XD17Xq19N1zf3Il2DZhur5nmkbubO0KOojVFwnC1FSfSqAshQMxyLZtjcMlvMAP7jRuNf/8//A9qd2vQylbOWEKFeo2V4zdVOJNOYnCAnBNRbndiioQohdnRtjMneVzcczLBe/GfjpGw+Mq3hBIX6bofWcyqIs3GqbeqN3jW1TZOK6KPlAzaWaI24nBhVeXqK7RpEHNQRcmRXCLaFFASkoKuid4po5wIdWPw4pKh6jKRk8DcNX9Cmg6ZBEx4VM1JcCHRpEwbC2dL5kwZzpuWj37wYy5ePGdre/7mz/6c15/9ivKrz7jf/Au+eHrB7/7P/33OP/gO5z/8HfT5E1TT43NLWCJpifzgo+/z3Zcfkv/wHwp5rkL5sUyUEtHGMC8TyzTStiusMkIzQnQmVjlikgndfhyZJhFif/bVa7QzbC4umRP4cWbee7qgaAZFs3nC85cvefH++zJFblpcvyHWZTYXXUXkQfQRSuO0RdljAyebCzkRxgN5e0febkk3b/DbLYf7W2yduoQQ+fkXnzN5zz/88e/yx//6X/Nnf/Zn7F7fCGc5F5aSq21ixigDRTFNCyF5QvYMvam6GoMPEZ8yRTtCPorYbUXFFNpK4J2PkdvbO/y80GuLkmAOukb0JiknTNFYROgs0yZD13X4ZUHKSRHh6wjOiDitq6FBhcK0G8lKJoQxZ9mYCzKFAVCZrpWU0SdXVzi0iNJLwRlF4xQvr1bE3FDymhdPLzlfr1ClsL3f8earL7i/HaForG2rFidxtx9xCpzW9Jsznl6s+c4Hz1itL8lRGthsHSpnnGs4OztntT6ju3qOW53RbC44u3xKypmb67f89K//mO3BUxI8e/aUp0+eMgwDu9s7Xn/2GXMSbq4EhMkmPy+ZaBTZGByas37go5cf8N73vo9rW3a7e8b9c6Zpy/n5GdfX17y7fkeIixQGKRMOd+TgUQToVhA7Xn0x1o00UEzmsjG8OL+kcS0xRW5vXuPnLUbNmOjpKOhG4xpDiTP3v/o5Jc10yfPyfFW9yj3j/S1oRdaG29ef065WXDx9xmrd0vQtF+cXeJ/4+utX/PynP6VkxarfoFRA28w0zaAiYgcs9FKLprMK3TS0bUeJBdDgGo7J6789fv3xD//Jv4cxVuyPj8F38cFIpFSes9KCIIoRhj8NJXJKBJ+IShH8cip+j7a1OUXivFBSFD1NpSWmVIO0UuKw3dK0DS+ePuU/+g//Qz786COePn3GH//rP+XnP/8lf/lXf816veLZ0yd85zsf8ezJBUZprl+/5u7Vl7z99FPOwsgqeRkChET2kXm/kGImhkIpjmIMtC3KNmAbfLcmakNQhn3OzClxX2CvNKPSvAsJnzPRGN7/6GNefu97vPedj/nrX3zCbnfgT/7kL3j15i2HceLs6pK0eOYY2e8OrFc93/2dH/Gf/af/C7738Qd8/P4zbr78lLvXX3H9y58xbW9J2zv0/h47TzRpoiEQlFhM55KJJbNkSRsWdNMI+m80hbrnF8hakY4J3caAsyQrur5FK6ZS8AVGMkv9OOTqRKX0Cb1ItQn4BqJRm4qjeDnXov9YK5w+z3EufyQXPUI4qP2DOnUWD38fU+dRp+bkeDymbpXH/6iIT0rxpB1yTSvFPoKwpPSgCxJjNH1CI4o2JGDykbfvbpgOI/N6ICwLKQQMon1TjYOSWEKqNZewB5xtOOIv+URzU5Vzr6vZi/yO3ntUknaucfn0foUo7ZYylq7vcdZxtllLI+EMQ2exGozOqNKx7h0vn11xcXHB0A8oYLc/cH93y367r1b8pWoqIcfArIShst6ccb4aePHsCf1whlKQoifOa0rykBLnV8/YXDxh9fwjTL/BrM7ohxUhBq7fveVXPrGfI8Zazp5ccnV1QeMsh+2W8PVrOMyUDDFnFJ6cM7NfyFqTjeNsaDi/WPPixVMu3/uAtu9RWnN//Zb93S2r81+x3W3ZbbccDnuijywpsMwLOWW0MoSwMI6WdzUjKfoF1yq0A+wVOE0smevtLff7e3bjDusUjbZ0JtN2FqMid6+/xB92ME9snBEjJD/Xe8lQlOb155/TDT3nVxcMq4G271it10yL5/ruSz7//EvIma5xFDLaKJYkw9JchBVBvVSdVTTWQduchl9tJ/kf37Tx/vXHb9xolCRWgIVEJsoNUDI6SUVUNa+gIKpEyokYaqNRsnSSNZuhFHVqNGRydEzSFE/wuCzVJ7kKrFR18UnV6z7nkzXpsZ0S94gjAxEptJX8XEfYWwRzmaINOesKcglHX3YlU3mLGUgn1JJyzCcQ/jTU4Db56orTSnOVqJCKqNeJSUESKk0pYKcDxQd0CKIxaVoa23Hx8glPPnwP8+IJm8M9hxy5fvOGMC/sv3jF6o//gs0Xrzn74g3tsxe4zTn90/cwrkNbR2cVxTTQWdIifP6wzOiiKUWfXFlKBm1qkmoyVWCG8OmTbKohLGzHA/e7e2LONErsi0ud+mvT0A1nDOdXrJ9/yObZU7qLK7RxKGPRzopIupR6GupCnFOlLVThZJGJSEkZkkws8jgS9juWccsy75n9yO72Hkqh6Tq00jTK8PbTL7n/6i3j9b0srinXkEb5GVXtOguluoGIUNo5yWdR2hBShHTkl9b8lQptPwDgct7meZFAyqatPvYZqzWajNOF9apjCYky+1NAkdW6BgxRKXVWmk1r5N9KH+G30zWelSIdJ38aShRvdessXdvRta2kq6PQRYnbRYX0rCpYKw3OejXQdq0scuXo7CGcWWJ1VavXdipCq3PVQUv7hXIYKVnhY8Eoh7GKYh122NCdP+HsyUtMt8L0K5TtUDHSND396pJVkGnIxbPnXD17ijOymXWbNauLc+JoYRyJcSIm0dxEpYmqYFUihInd/Vu6tz1N35NKtQs1VsIElcJQHUPqmbJa6GMdWoI9Y5DNtUgK8bTM9MtCiBHmBe8X7u5uGacD3i9YJyI6pzTaKXyIhGlbZ6U1JFEZMk68+43o1WLOmJQQ8a9Da4dfMrvdxPZ+x/3dPaooSkzM8wEfZ2JJaCXaM30qWCosW8uVY3NhrfkGlee3x98+JI8gVhqIUHVTOlWRJ945VOvRmm9wajRyPr2W3O+5FqYPlqZplqkktfE4NSGVbqm1ou86nj59ytNnz9hszthud7x5845Xr94AiouLS777ve/z0ccfc77q6LQ45mQfiPMsoaI5E5ZI9kkez4qMBWckiBJDNo5kHdk4JueI2gqPOyUmrTnEwDYlxhA4xIhxjq7refbeS9bn58wxcv/unu12x/ZwIEQZZoQQxSnKaJrGcXFxwfe++12+993v8uH7L1h3hnfec7i75XBzTZr26GXG5YDNEVMiKgcoAVVdI8WiNhEQFMJXBoMT8RsVIxCxrTFQxbLFSJ5PAOYMcyl4CnMBTyGUQizH0L5cHaa+iUacGoV6jZRybBzkWjg2Gsdu4GEuf7zXyqOPH3/0cLV860o8PekRgMHxWzygJDx6Xv4G8ib9h6Q0H5vdUh5e+jhvOBq1KJRk8QCT1rVYTzUjydA4iKWhqITLsRoGKIzRpKQrPVjWTnWk8WpVUdT686oHu/Zy3KtKOdEPrXUyqW8bbNOcvi7FIKwVXXBao62l7wc2qzV91zFNEyVnYnzIgtFUKrwukp+L1GwpJRlSh0Aep2NhhsKgTYc10A5nDJsrNhdPUe1AaQZM01K0o1+d0a/PCTHROcXFsysuri6EFqks3W5iOYwEpYV5sEgEAVpMT4pWxBxZlont/S3FNTS90JBCKhTjyNqQiiKkoxuZXJW2ut8ZXRkMObJMh9M6NPuZJXjR0gRPDJ53tzfc73fMfsH2KzqktlFGy352EEeqkrPQPaO8fydqnRZL/RCFMqWtRVtHTIVxnLm7u+f25gZKYdW3LNNIDAsxp5OW48Tvq720UqLzMUaQNGc0OmfSb7A1/caNxteffnm6r3SRHySqjM2CKuRYjpo0VLX9OyIacu+kepMotBIuc1EFd4qAz8QY5AYLNQmxlIpUCBdQ1btV+ujqKsLRpq5CnLXONyeuZS02Sp1saYdVCpRw/4ri1BgIV6/y9EuUn7EUdBb7Tq2A7FFKyeT6OJUoAmnHkoXDWKhWliIkiyR8DVTqDxP9NLOeFnhxgb04p+03vPzhe7z3kx9iv/Nd1r/zPV6+fcf/Iy3sf/U506dfsf1//ze4mHFFc/7Be1y894Lf+4/+Ay4+/pjV8xd47UhKXDWmONffNWOxkBXLdKAkMFiytZANWYuIMeUsk/cizd60HHizveHd9Vu6zuEai1IJUxRON7SbK9774Ltcvfchlx//iGIVWR+dmnjE+SzVA70OfVIUSpMCk446iCKc4xDQ40TabpnvbtjvrjlMI7v5wP/wV3+KQvHxx9/jxfklzIH/6v/6n1Ny4coM/Hx+Q1QF3Th0qs2Np1IcIilolAFnDK7tT1SUOQjyk7yipEqdylkKclUq5UzEbPNhooRIeyGhijoltLJoMl1TuNhcMPtEeXtHrN7rGk0sYoWrrMWWQtaWprUykakBiBTR82QlDUqxIgTUSqHShNKa9WrF2XpD0wjUWyplgBTJymBTpERP4wzPL67QzuBz5vZwYIkFYztWa0cOmTglmrYHCylpcSRLgTkVDvd74vUWX26wtmW9OmfVDzTG4oGr4YzuyXNWzz6kaEPImbv9LPdMtlw9fZ/V+RNs3/P86RVPr86Z9jckBWfTgb51+MOe21dfs98mwpJEMJeELuZU4H77hvu/uuWTX/017WrD8+98B1f9ym/v98zjImn13pOURjUNq76jyY4esdaMMRDSqe9kPx6wzrG932LQTPPE519/LS5mwPtX74tBgXMsFeIP0x0YoXe64silpege3XWSCts0JDxZzI5RtJTU8u7txM3NDdfv3nJ3cw8kxv09MdRMEpVOsY6aqvcoMiEvWWxttTJYY+lsYZmD5Pr89vi1x+s3rzgOkkWvKO43x/1BchSOBgzHBiI9UKe+URAeJ9hHm1JkjZhnMX7Q6uSxLwJn2SP6ruPpkyf84Pvf58nVFcYY/vKvf8Znn33Ou+sb3v/gA/7gD/+If/7P/yl/9Ps/xpbI/t3XfNm2bJVGBykUQsqkUeiWKSSUadFNg2kHCoaEZi4KrzReabZKkYwmW0dsW+YYOYTA9eLZ7g/M3vP07JwnL1/yw5/8BGdbXr295vPPvuRwECqlsgaHY15mQXKN4cXzp3zvux/zT//JP+aHP/oB55sV881rttfXvPn8c+6++oqGyGChK1WjUYTXXeKx0ZD3M2SZVJcELYJcauskB0hboUtVBCMbS1KKqDVTLpLrkzNLEae5BYgcHXjKQ3NxYjQc1U3fnLTmo1V++Sb1upyajMePP74eah/yuKc4zga+dfGcXulR4wKqNgkPblcPeRry2roamHTDILS/koV7X6mh8uzjtfhAAdMojDaiZc2ZEXBVU2SsOGQWJa5NJiQiC7FaFWtjSDqSkH3RWCMT61rA55IfQpGDuAMqpdDW1YZJmgJlDF0/sN5saNuWXAIhBvzsWUqgMYq+sWI727Scb84YOqFrz+Mormmp7pZG4Yyhax1KQdD6dH+FlFgOI3f7iTmIwU7b92xWYlBgu45mfcVw8ZRufUlUljkroi+Aplud8eT5+6w255yfr7i8Ouf8fEPwM7rpmbyga0u/Y75RjDkSc8Q5Vy2UZc/w795wP3vKJ7/Ctj0XT5+zqhrF293Idj+yO0yonDFKwgM7KxpQqy3p6DA4HYgpElPgMHW4qWMMnnBYOBwO/OLTT1mWhZwLL6+e0jUtg2nY7Uf8uHB/v6VRMmDru1U1+oko06Ctw7gGakgtxqCMo2jL9jDz7vaeN6/f8vr1G1TJDJ0jx1m0KznW5hC5FmrxVo73jyroosWSOscapvwwqPm7jt+40UjR1+mBaBFQ4tNMTTOkggLHJ6lynNbVe9NYjrhASbVnUtKclFyLriLC3JTUkflTUYpj/17dfNAiSFKPJ1E8wKMgEGeBXHQVehUMosdYkMnUUextjEzCYizi1hADyU8c/SaOv4lW8rMf4dFS7eNyFopVzlmsfYEj37EAUQlvT5fMsES6lLlQ8LIYzg8L6vMv+K/+z/8X3MU5/Ucfs/7gu7RXz/j3/sl/TPs/s3SN4bM//hP2X73i7q9/ybvbN1z/9IZ3X31Fsxpoh4EX3/shm6dP2Dx/hn1yhek77HrAey9FZFggLpQc8P5AWGaWZZJzBViniD6xhJnX19fc3N9zfxhRdqAp4kNP7WjPV2s26zOG9QajNUHkCVgjlLqS8knkph6J/h9gWk9R1W0jR8o0keeZ+fodu7dvGG/fUpaFrz/5lD/+4z/n7//Tf0ZnW8a3N/zsz/47xusb3GHkZpm59Qv7JTA1mqAVKYl+xdRmOJfMYQ40XUPrWrQ7R2sLRdN1C1p75rSnlBoMeRK+FXIKVT+kUcqisJSiJa3aNZyve4rKpPo95lHcqCLI4lS6k/e5MjD0A2frDQXxR1+8NNYpRUzINbwuE5I/WTaCCD6naChjwC2ZEgXZI2dK9PRti8JCMQSf+MXffE43DFjnmH2oGhpDu1rRupahX2GcWPvuD1uWZSTEBWUa5nkhxIXV+pJhOOPy6QvmeWaOHu9H1stCuyyUw76GKjWoxlF8YVpm9uPCtCyURbQ0726vMTmyvb3h1Ztb7t98jR/3LPsdKmW0alBuwK0b2tYRDFgHXW+5vn5NunvD7faOdi2OZa++uiYuI2nxTCkIchTF/bKozBImGtNibc/KNoTkWcKCdh3K9eRm4M3bN9ze33BzOJCz0Pde3U8UNRKJTIdJgvMOs+i4tOisYoSUCk1jWbsVbXfB1bpjtR5476P3GVYbrGuZJs+wOqNpOm7v7pinPfNy4MgkN1XndbL1NlIYNE70ATkWTGNQxqKMBR2PoOpvj19zhPlAnRhxKuyqRuNBoFv3JF2nyKo+6USLUXVIdaTCPBLgF4V2Vow3ah6ONtIqHtONnz57xtWTJ/TDwJ/++V+wP4z87JefcHu3QyklzlPvvcfL589Zdx06BVTbcbnaMA9r3hTFPEemeSbsFxrX0K/PWF08AS1F0/1h5OADd0tgybCg8IiuLJtEKHVdAdZXT9g8ecqwWnF5ecnF5SVKKe7u7/jqyzfsdiOgOFufobTCe8U0Hmhdx3rT84e/9xN+9MMf8KPvf4zVmrAsGBSrpuWsG3gTEyXMhOIxutCpwvnQMsWMNpoYZ2IQDgS66iiUYlSKUASN1Mf33ehTER5yJiJT4TkXYikspRAQOpFYXVTH1mPTUCfutXyXUwaPkIrHiOAj1sM3EIhHSMfxtJd8ev7pa+sw8/g1xyYCZLB1PI6IxulzJ4DtSOM6/lsms8o2tKtNTZyvbIBFUYqXfbRUO/OKsKmSUNpU5MKK9bpt0VYMaUwrhabSmhgjioWYZ0J1QnTVnEZbLdaoTUPXdkC9hkKo7nyJjDmxTRZfTj+30rXgDBmzBGIqTMsISYLkVo1BF00yinHvGfHcXu9xrqmhsjKALViunj6nbVs2qwEQStlut61BiYWYCsFHpjnQnT2l7ddsLi8pVSe5u9ti1yNmmOieFIoRrUIuhRA8u7sb9odJ7O9LYb8EXt/ek6Nne3fLm6/fsHvzjjCOhP2+Uu077Go4aXW1a1HGUmJgtx/JaO7v96zOLrFNy5dvb5kOB+ZxxhKxGnqnIAYJmtaKxkiez9CtiTV/y3UdWCv39t2W7f09b+93MmhXmlfXt2RtiRgOs2dZFra7GafEUGY0XgYruXDenTH0K9bn53RDz2qz5oOPP6TpV2jrGCePsj1KOXbbO+bDnnHck4LsTa2TQa1cswlXDFSkTYKLzUnPdhwqy9Dl33z85tSpHE+UkuONmItMf/MjtIEi3s6CRjxMCQR60VWMlR9u0qNz0olqU2lYudRm4vj1D41F4SHjoOp/pahMx8agLmCIs0Qs6XTjH5NYoYbUcEyDFteHpboj5LDUhSqLbZtS1ac6PzyeVEVjBGbLOWNtPL45pyUqKVA6oUpG+SKWakrThUSbMnqM3N/dktuG/s014XZk8/5HrD/8iL67ZH1+zsWH38G4juzBfG3x93dc32zJb9+hKPhx5vzZUy5v32N474U4Ojy5JBst7VLwkAIle0oM5CQamCNcmrVQaHyKTH5mDh6f4glC05Xio7TQOVwjxfaRHpVPrLICqXbAUJGregHICiXn1UiHTPLkeSJOI8t+y3LYMx8OhDAx3u+4ff2OdTPQu4b9bmL/1Wt2b97QKrFx2y4Tc8n4pAm5nKgTpbpPFURk59C12x9kipYrH9VkJNdCPK/1sYlEyYKuZYojtDCHuGYV0ZcYizEKY+Cw5Dpnko1C1Iei4dC6oM3RV98SU5E3S0WK0hRlwDiOxlOVoQZaYa0EFinTCuXvCGeSUTqjraJg8V6uy5wlFb0LBecajmaFShmGpsd1Pd3ZmdBFYkSbjqbTmNxTlKHojmw8l09eslpf8OT5+9xtbzkcdtxPe3bzQns40J4tNEqRlcy2YgwswYvuJcRKZcyEGDA5c78fud0duNvu8fNE8lGcQrSm0FCMpP3OccLljCUToscvCR8UrdcYN7AfoxRWEZYka41SMvGMRKJfWHWubqASJqqSTHUiit3sebu95/b+nilEVBHHujEINdSXyLSIbeicFKaIvbEyRawuFSjToExbXbcGbLvCtgOm6YWmgmNYbVhtDjJ4UJqYhC6l6/0mQ03x9hfLTRF+i+NLkY+1qfzs8hvB0/+uHiXJAEporHVnyFDhqBPyDJwQ8rpj1Bc4OlA9HlYfB0WlFpDyNbnkev89iJmVgq7rcU1DLoVXr15xc3vH11+/oqDp+p7zszPONmvWfYfTWsTQ1rLueja9BFZOzPisyKZBtSua9Tl2fUaoOrNdhl3M3IUkU/4MuQnoRsw8tBN7y03b0Pc9bdswDANt09I0DTFEpnFiu98RgjgOCmVPhiwlBaxuWXUNH773nA9ePONis5Z9PAYc0FrL0DQyV4yRGBdsYzAK+rZh1QuNaRyTUKVKIucaXopiUYqINBQnu9U6lCoFAtJc+AJLOTYX8lguNQfjiF4cz9UjlOLULDxcHfXxX38D/a2G4NHrldM3qH9/myn1+DuVR39/S0/18LOWR9/v4aUlq8VgavBeKRkllk/1ZzgObuveVLJY6CvJ89K6TqyNlT3CaLIVLr2yBq0k0yyrB6veY9ihKqYGgsofQW8UQh2Xtb0oKdgf1iGh5ljjTpQcVXUBkmVmpSB1ondMqciekDIxRLSZ0drQtlaCFpWmaXq6rqPt16KLjQHtwul+VBmyjWSbOH/6kmFzzsXTZ4y7HdNhz831LdtxYdiPXC4zyhUJYi4Q/CLhcyEQYyLNBZ8zxntyDmx3B+52B3b7kThPlMVLHI0xOGWxSsJ9LQqdC6pE/DwTUoEgoY6m6RgXoev6BCknkq5ZIkFsz3UB1SHmO86CFoMYlCakxHZ/4OZ+y/Z+y+gDVhusUYyzJ6lERDP7jPdJ6FqAUQVddcqm1hE4h3YNrpP93rY9tulQxtEUS9+vGFZrGtfgK0JbagN9pMWVeq51lj8CLghlWEnwkJg85Ad907/p+I0bDfx8SqxUOddQvUBxlbOcOfHSXGuRduAhLTPlLAWT0tUVQfQa2S8SgFI1GkL9UyQvEFOpIXj5xIfhRE06QZTHN+ZRZ/X4sQfLuofF5AQNFXXy/FYoVIVSJLmzbi5RshX0URRe6aVHPYc4Z1Ghds8RE9UVMXHGoGLB5ILNig7FSkG526JyYRUjl85hXEIvXzN+8Y43WvHHuy36/ILm6Uv+/v/yP+WD9z/gd//RP6PtLONux7/4f/4XvPnlz7n98nPe/PQv0X9ZcEpz4QbOV2u+894HvPx7P2H18jn9kzOWsuDzgg2BHCImJlzrKAqmGBj9whgWklZkLZuDazuMa0hFySKmDZ4MVhbGxS8UJdaEaQlVfy+cdChgOPHoj6FNJmV0Xig5kcPItL1mPuzYvX3N4e6GaXfP9vYdaZx5vj5j/+UrppjZf/I59vqO4TDhrWHvZ66D517DEjJ+jOSiIYPKhWKO+h5k8bMDbnVFURqfEt4vkhQbDqjKK1Y1JC8DHmhax2q1oWlF7EbTMi5SKC+msNn0nK9XdKxIbqSJijxP5AyuGUB3mFhwzpLywut378TlLGV8DGjTgDIo05KSIeqIMhrjLLZxrDZnNE1L13e0uhEtQopYbWisYdV14sP/1ecs8yjUHA3bcUSpiaZf1QbHcPXiAtqGQyzcbe8JiwevJONks6YUi2077LDmOx99n83ZJZdPnvHu5g2v337N3/wX/znL23dcHw6cXT3Dh4nog2hRcmGeIktYxGJXi54hFcP9bs+72y1f3tyynxZySOgiRY4q0EaD3hf0wZPzROMMqynR2p5GwX4X8WWpKcdnRNUQcMSyx9ap9Lube0KYyWXm2YW4V3XGn3i2yVpu54mvfvZXvP7qK6bDQSwOrTg+TcWSbENwjtQo4uKZ4zt0mrE502nxam+M5eWzS7RrwGT2fiYcwLzbY9sJ2xj6diAbxXC2oe1bYmxQNOS0AHXiW2SCmpRlyYqYFc5oetdwtloDgpRtt3vZHI80u98ef+swpTyq7Y6UlPLgElgfl6NqX7Q0dzIuFuQVJaGXx70i5FwDPWPV+cm/j9O8aVmAUoNfLSEl3r675tPPPuP29o7t/Z7zi0vWw8DzJ5dcbVasncUGj8uJ3rW8d3GJffaC7Yv3eYXlDsvZi3NWmw2b80tuZ8/d/sDf3N5zM06MIbJPmdEH5hgxynD5ZOD58+d88OGHPH32lB/96Id8+OH7rIaBt2/e8uWXX/LlF1/y85/9nN1+xGiFbiwlF+7vrpn2e8Iyo3KiOxt4thn4w9/5Ph+8/z4bZ4ihfq5kzpqGwzDQWye6iXnBmBbnHBdDT2k6+jlSSsv9buQwTYwlCt1JaUI5Ik6lNoFCS5HZSZZ8jFLEspaje9Q3/5Zz/IA8HYGGbzYYj1ALeGgEfs3xuPg/CruPNLuiKpvi1HUcJ5+c7O1PVsinV1Tf+lnKkZEkj9ehmzpq8aq9O8ZKvZNTHXQVcoyQs6THa06hgkZZ4co3LbrtKdYxm1au76IZdE/TtDRdCzGicBQ3kghCM9eOggEl1Ok5FHyYT4VjzEdkR6NsD0SKEjG5tZam7aqrlATtNdVy/1xlWmtpjMWVyHw4cPf2DdNBXNu0MogRRiLlo3ZAkbJi8YW0m1lCIKbEEjVtL26B62FD03a03cDLj3/M+vyKy+cv+OqzT3n91Rf86tNPeXN7yxI8duhpul4QCCUhhskvkKUWXJaAoWCKZKZsx4U3t1t29zuyX3A5ExUUrbgr1eJVwapxtdFuCRXByWkmqT2qiWTdoGxBO1gOnlh1eGEO5OjJ0RPzmqwUXdcg403FfpqJk+fL63veXr9jmiaIhdWqxXQdPkHWGkyDbRVFO5xP6JwxFGwjjnqNc7i+J2vDfp7IzuAB/8VrhvWGthtYDSuUFrctcSKVtr3r6vVkTM2RqXV7UagM2jkwFmUdCUVK1eQpFX6Trek3bjRinOWmCEqEs7kIn3TxKPSp04ZM8OpU5B8L/VwnGCAuMcfuPlUkI58W+NqiRBGDG6OrKWiqdoMPq8MpfqY8iPpUhb8fmpBcoSD59zH1U9IrRQh1FAOW4ysqKjQuXyXhSlX8XYP6qqbqhK0cF7rjgiJFhGxgUSeRhOgqtCqKVDSDKlySeaJgKBkTI+z2uFWDdoaeCX0o2Bj4/L/4L/lqcw5PnqIu1pTGUhrD9/7BH9H/43/I/PYtYRxZ9iOvPvmEr8eZV5/9kif7W9brFRcX5zStwbWWfjPgupbzoSdlRaBQYpLGLmeapuVscyZx9qahZM0SoAkRmxIocXdB3kY5dymdplOlvl6hYLKqyIJMBktM0oQEoa/F5cB8e8d82OKnPZpE1zryqie9eArWiq94KWw2GybnmJUiGYM34h2djap6E1UHSgVlxHtamkpNUYlcAvOypyhNyhmVZxqTuTzfkONMyYESIyFnfAbbrk4p8rlpCc7huxVLcQQWZg/7Q+auLKQl4JfCTENygpBN2WBcg2010zySUyZnjdYOZzRtJxMCrQ3KWarlB9Y5tLFi4dd2NTDJYI04o+XF03cdfd/RGEuIM2McKXisM1ycXeCXSIyZElXN7Uh8+fWXgLjFDd2KpulYX53Trle4rkfZgXbY0J9dEMzAPirifmK3eEYviEXyE3k58Kuf/SnWWFRWtG1fER+B7rumo+17rBHh/WwnUJqloh0pJoHUq8h7TJ7WOTrneHL1nL51bLqW6X5HzoUnlxc0m+fY/pzSdOx3d9zfvuX++gDJU9KCVQnlDNYJZUkbRZwmUvSEEJhDIaAZqxVz0zi6xjG0A63r8XaFXq8x5+eMY2I+HIiHHa0yOJVZ2UhvNZ2FOL0jTIo5J9p+w7L05Ox58uwp1qxZpj3b7R13tzcsyySWqDFgjWSbWGMZnEVrI8GJqdR0Z81cMjntocS60EsOh7K/+Uzo37XDLzNHmP1otS2N2bdH0EKdEuBV6Bkni1X5tKxlx2eXUnVeWXjvxtB3PUaLY1rwQah1xrAsMjC7u7tnPIyklITarQpOw9Vm4LxvWVnFcnuD9wt6PqC9Z+0cH334IU+fvWCJCWsb5pjYz563b2643u25WwJTUfh6zZi2Zb1e87t/+A/4+Hvf5ye/+3s8f/6crmtpGsc8Tdy8veYv/vwvuH73jpubG6bDQQIJ/UIMkgcyjyNxmckh4CikaU+a9pjoMcFT5oMESeZIVoXeGq7Oz/jhj37I7vac3e1bduOeJSWmw8T9FNgvkf3sOfjAISSmJIWzcKcr6lt5748bDVUerGhzeaTBKA/nKD+cHB422281C99oNx5K/l8DSPya/uOB7VA7j/qwOrLyOPElVBHXS/WoBTmae9SfopSjfuSbeUioh8xwyWYJzPMs1rV1eNk2Le5sQ66aoJSEop2yQjmHaXvc+gzXr9HWkZU4KcaUmOZIkxRNlMbEhwJGKLZiauLqfl3ETjaKBbwgGxrnan6YEbF3kW5c3N2swzpH14n1bNeKJSsUwjKzGQbWwwqVAiUr5vCKOSS00lyen4sFbJGMK+pA4O5O8jNiLrTDCtd1rC+f0Q0rmq7HNR1t19Ov1gQsh5BQh5E5idFAyIntfssy7yTLrW0wrmU1DBhj0cqhlaJrG7rG4boW7Sz397fEnBmnGR/TibLv6zUYk2hYGmNp1hv6pmXdtShzIOeCHda0Z5fYfiAqw3TYs99ueedHchLnqqKE/dBYi+16tGukuQiRECLJCdrki0gGjLK43laBfU/vOhGerzeMh4lxHEnLhEoRXWDoHI21OGtQJRC9Z5ozPs40XU88Vq+5oFLicH/H/v6WsIzkGLDqITOMAm3ToCvlLmdpJGKsjW9OYopxRNf+rhvrW8dvvHt5P8kNVGqIYRYnm1jEQlSKfHF60suDU8DjRuNxQ/D442NhfjyyQn6ZUjDaSJOh4ils7cHQVp2aiuMfdUQWjjdxpXMdHzk2GiWpijgcQc3aPBwh+NMbKKJAcUOQqXxR4gt+dNE6TlmOq0g5UiPqYpKoXOyiGLV46qeiWJM5UFgUbCjYnMnzzFWnGRqFNQkdJ8zsefd2SzANS78mPTvHXJ7z4vd/h6vvfMiLly/xH2yZ9jt2t3e8HffMb9/y7quvuftsS680z/qes6FnPfScv/eE1eUFw/Nn8ntoUFXUowpY6xg66KyVi0kZQpJ03ZQyyrjq1FXdnZI0D8fF+WgZSSkUo4U+dUS3QqQECQ4sKRLnkbDbEQ5b4jyhS6Kxmty2lEvxjd69O5BypB96lDVkrYhaEbTCG0U2qp4sIUYoBUrL75NR8v1LEq2KP3CkPejssTrTrweihxQVKSpUyuRUcG1Xw98GUiNOL6EZ8FGxZE3wAbMUXInYVMhREVTVLBS5OU3TYp0lLZNkL2AxrsUaS9t0ghAajeokiMc5h2satLIY7TBWaAnW5BMFJAD9amCzXktw39YRckQjQUTrzYpJeRERL1Hgz1K4vxOP7BAC77/3EX3fMpxf0rQN2jVot8YOZzSrC3wx+JCZDhPTvDB6T4iBHGZySXz9xSc0xuF0Q786wzUd/eYctznDdg2r1XAaQBgj10pMSYYTUYSEocLxpEhGo42lH87YDB3nXUc8BBKZ8/Mn9JfPaFYXqGGguTHkMrO/E82Uyh5riryn3YqmaatI0kv4oV/kfCmNL8JhbpqGvrGsuo6+HRhVh1ut6Z88wZkZU+DQOHpjaFSiJzM4RWdhXHbMKbGPgVQSIc7E5FmtO9rGklNie3/Lzc07gp8pWaBzo5X40xtD18q53i814yVByoqUEz54yBLWqIzFOS2e5b89fu2xzEsddEmjIdazD/a2j/4nmrG64YhTlaxVJwQ8VydB9WiIlTNN42ibViaCdZ1LKaGN8JZ9iCzeM41TFXFWmlyRAdWqdQzW0JbMYXtHnkbUdADvaY3hxdNnFNdSjGPykTc3t9xMr7nZj9wcRg4xsQChutK1w8Bqs+H3f//3+Z0f/4S/94d/xHq9JsXIu+u3fP3ll3z95Vf89V/8Jfv9nmkccdYSQyR5yZYJPjDutiLeTgmtCmE64A874nggjHt8a8nzAZUTUSsshVXf8/zlSxqnKWTuloXZR+6nmfv9wsFHDnNiCoE5JuZ0ZAhwssAv1fiC2mgc36uTqJuH5uJxI/gNrUV5hDCczvC3W41T91H394fjcc3xa/EOdSRgn9qP09fLY49Qlb/1Qo9qiEeIh1w68js+UPMSKUSWY6OBFGbGGpwZSN6TYmDxBZXkPSyuQbUdth8wqzXaNPgCPs8syYPPuBxpUnVaixm0Q2OlYXANpiaYh6IJxZPDgjMN2lhM47BOnPWarsPYY4PR1I9Ft2nqEIwcBYmJia7rWW/OIHoOuz2h2vMqo2lXK2IIxBQI/sEUYxql0J+WyKXtML1jOLuSpqNpQRtcP9AOa3yGuATi/sDkJTQ3loRfJqbRo42E5VrnuLy4pOt6+v4M2/Wyv65WuK7FNI7t7p6cMov3xFwL0QIBMRxISWjSWhtst6LtO4a+P+lzh7ML+ssrmtWaYhy7+xan4P6d7MmlJJEMWHFyaypDZN5vT42GUoasjFCVTi5ekgnknCR4D2dnbC6vuLd3aAVb52QgTqZ1Bmc11kAuoYYRe2LyLMGD63GuQVHIfma/u+ewvSP5pYY2a0xF6JQCZ51Qu9DEmAghEpWwRFJKpKoRPQbJqt9gb/qNG423r9+cOFmnIhNFyZpcqH7QCmOUWAc+QhaODcUROVDqwRf+8XOOd6O2csfKcCBjcsFk0In6fTX5GLr0KMjqRGPS6gGleESvUkrRNOI4tIRUHYXkBijIBEWakkIpchNorWj65vQ9gp+FNpYLRcmmlHIS+pitCduIXuTotmRL1SUUcNYSSNyWyOelcKdh5wpPXEOjFMl77POn2KeXvHr7CjVNmHFmiJ4+JV4cCml/R/ikcPMnf8abYaCsVzz/vd+n3axpNmv+/f/N/5akC1+/fc39F59yePeW65/9ki9v3hA/Hbn8tGO1GticnXPx/guGy3OuvvchynY0ypCCZ8qREBdJfbaOYhyjVhhrWV9cyOJjNPM412IuYI05bQzyRhZK9bUXIUcixSB5HaFQ5oW43RLevSGOO/J+B7pQtLzv/arHnp/x808+I44zL7sV+yazc5md8hxMwjtQJeOUpqniNxAHo1RK7cg987zFxxmmfd1ACpu2YdU4NqsVIxlfCkpZsq10r6ZHDWvs5TNM25KV5hAjS9MRlGUiYLTCKc2m0agmYdoZpTJGaYZ2fUpet40jxYUcF1artSQZNy3GNcLFV0qgbteglTS3xiha18j9UhLL7Anes0QxFKAohrZhPaw431wx7u/E/CAmligC7pwzzvYMq46LJ1dCcVoCL9//PsP5Je35pTijFRh9Ru1GtBdKjzaapjUs+1sO97cQCyVkcgy8+/JrmrZlWK+l8cmZbthgNXRW0zdGbJRRfPVqJOQZZQshi7uZVU4GChrQiTmNpMPIuB8YrKY/P+fp1TOsbXj50XexqzWqabibRpTu6LqnHG4/oyyZtRlYcgRt6M8vabXFFsUhRJxLrIaMNw3YFrPasCwz0S8iSEeGB5tVS9MYuhIpjGg9krpCkwOmBFSaCV6RgiLqFtNYzoaGaVnEZSUnPvnkZyLKVIpxv2fc71BxoTXghh6nRLeVckYnKbDyIo1XzjDrVJtkhWuaUy3lyRD8b7pU/zt3vHn16sRlr+XcQ3H5uIJUQNUHlkpvfTzsOg6cxPxBPRqcZFwNnqVIY5NSou97NmcSiKlRLD4yTaOgVlqhUiLOB5adxd/dsFyvGQfH/WefkucRNU+4kjBkNn0P/ZqgLX/xr/+UX3z6OX/5N5/w+jCKALrr2B9GfIo0fc/v/PjH/O7v/y7/6//sf8V6c0brLH/5p3/KF198wb/87/4ln3zyCbc3NyzzQte19G3LmALLIq42IUShLIeAzrI2j8vE2+hJ+y3/7f/nv+TDD97now8+ZLAFpyUA1E8jfhq5nmZe7w58cXPPL79+x26cuB9n7g8Lc0jskyJmxP7A2OrcU/9W6hs6C4rYrVSs4+HEPYIpHsTax+M42Htc/j88fPrH3/qSb18Q/K3nHNuK07NOSMRxgnv8juqb3+Z4DX2jg/nmEBSk10rVbj5VRDOEyBT86TU3XcPQNlycrYnOEYPHp4R1jZiurNbYtkcNG3I7kI1YH2skrC3NI6kUYoy0RqjNGCe6NW1o2pbGiYg8NCPBe3w7S1Br29IOg9BOVcE4aTCsa2jaTmodpXhISk6kUMRFaZ4IbUPoFsnQsIZu6LEVkTdOc5hnsbYtkcF0uKajW/WkolllxdP3P2J1fsHqyTN8yhxSxs+BMc2MSRGVJxXwryJpOTDt7sT5s0RKjmwP9zW0zkCJ9MOKguZi6Oh6x7AZUFa0q2EeiXUYpJSsDSEFuT6VGDTE6InRE55coYxhtdnQtS3WGC6ePqXZnGG6jmUONMVj08DdumM2mZKFHm2d5fz8gq6VBu/tsgj9zRZs14vIXBviqqaXV7aNUjKYMoDKCU3CmcJ6cJDkMVUWopfQCeNcRcMQXYcfeff6S/y0o2sapv2OZTzgxz26ePpWo3V3iqKw2uJq1pzY9crQVUKpRc+sldRZ2hwpgr+2Tf/G8T+COhUfuK914qMqP7GU4415pD6V0/Th2FA8/lg84vU3PncUoxxhxWpsVRuJ8lCsIiN4ddxPHr3uN1iSjxqZXF/72EyUkh/QC8Vp2iKvXpuhmpFxRDIe0IkqqKob23F/U/UFcqlpslnEhMeBxvFkSBiMLLM7pMBLgE+RTmuGxuAbTWg0s1FkZ6B37HPBxczWz5iUxIEialzOaO/hV78iDD1p6Ph0e03QcDPtaRrN6nzD1T/8Iw7X94y39xyu37EPkcPNNXOO9Ld37HcH7FmP7hx9r1FGoY2iNVa4o7bl6bP3uHjyjKtnT7HOEkIghUhOBapNJ1AdX45CP8k8AGmiiAl8IodEXjzRz/jgCTEh4li5tux6kHAqZaDtIRSKtqi2QbWOaZ6IpSapKsQaz4ldYiqZKcSacyLno+RUocwHKahNgRIajLGkUEjZEnLB9AOr1QrVDuimR3WdXJNFEt1bnXAm07QJoxRGZ9baoYsiKyuQugJHxqaEAZqUCSGxeI/poTWW9bCSzBGjKVpjjcNpmYiLZ3UhTntSivh5IXgJCNMxgp9Is2UMM9lH1sMZ62HAGsWwGmTT8jPFRLISb+y+HyhoMJFDVMxjwDVewr+MwStksjmNJDRawzJnchiJydN0nUyigvBt/TwxhsCwRIZhxpgW3RiOFqJLCEyL5+uvv+T29i1hPGCRSa+qQvuMouRQtVGZsByYR8XuXqOLQRvFPO0hTmQFt7v7GpIW6HQiuxoulaqzTS4kL/Gl8xhkYdaZZDQlKkgjc5ScHl2U6FSi5GT4FFhC4DBu8bNshKmaPKRc+awKcdjDomhOa0nKXu7zLAGVJczYEmlbiyoalWVqTKGKOAtGFTprqpd8oNRcAI0CZSuULajw46yH3x7fPHJK39pvvlkAnlg21OLo+CDHodfxS2TN0rXJ0FWMezSYiDEKbaE6Tz179pT1ZsNqteL+/o5UtVNaK1IRl8HsF5bDnteff8amJFZhpmzvsTnSUTBKivxpOrC9P3C3BH76i1/yxes3vL255QAEbYgshFIwTcuH3/kOP/zRD/nJj3+M1YrDdsubw8jnn37Kq6+/5v7mhmWayEFIE9l75iS5SkeUL6dch19JrOeL3JcpeA77HT//6V+xu7lmf3vNk1WPM5qYIrvtlv1hz7t3r7m7v+f67obr/cwSEnM2TDQsKuGVICAZ0R4orUEblNKnPfNxeSLSfHVq/B83GXzj+Q8IwumcPn6dx5DDtxoGvv3QNz59NA345hMfnqpOiEipTArUA/+hFBk8Hinkxz0/lUeNyqOaQ/aho9GAUMIlfUiutZkMKXKwMjjKKZGUpu1XdJs1arVG2QblOpLSVawtr+AMMuGm4CgMTsKCk5JwQ0kXV1hVMCXJ16UAMWDINFaxHlqUlvtJW/tA8dVSBZVc8H4mhYBfJkr05JQwOZG9x48HslGUnFiteqxZ4axhWPXMfmTxk9Dmq7FKv15LXkwo+KLISyQcJjEoUUoE6TETxplcPJlCzFG0niXSNA4fzck59DhwKDkzzAtKO9qhR1tDLKnuTTNvvv6C7d07SB5dEqXmu7nKTJHg6wKpsIx7Jqs4dA4Zocnw8LC/J487dvc7CZteZhqrUJ2VtQNQWoubaaVrTrOHXMRUIQRhlChBEI6DD1WF/ovWkm8WPdvDHr8sCFdDmCK52qJDxuoCVZifT7eRp8SJRCQue8gL1mSMsad2X1V3TKPUSZNitDoZNpwG66q6jWm5yVJO9Xv/m4/f3HWqPEwUTuKnB4RZ6EpKlgtxcSrfaAKOEyJZwPXpz7eF2pxuYLkpjarONrUQOTUatTX4N23Ax+/3+DnpiHRoU3uj4yuJA4CpHYM+TVnqm1qnMBlVBTJHODfXl5HGQvjnUovo+m2zPn0rYooYXbCqsMuaqRQOBXYxsjKaD4aWpVF4W5hsIWBItmUkwRzRYWKtYIXiJY4hBpqU0J/8DdFIc/LzfzkyqsxkNT/6R3+f9773Xf7gD/+I3d09d9c3/Nm/+u/ZvnrD7qsbxt0epzTmF5/y5KP3OHt+yYsfvoc1tZPWBkxDaXo+/M7HPHn5Hs/ee8ESNMviST4DGqXcw/VBRmHkVBbxk1YUFp8pPlIWSdhN3osjRIj4mDHaiTOG0bQXV+SiyTFhhzNIBlUUtu8xfcd02ErSOApXHYaG1oJyhCRp3lqJ/7euCFWpCfS5SOwkeBbbMGeDMwatHXNWXAxXnL94CX1HQhMz5DBDitgcMCqhbcaaB9euQSl0ERtcryTXpcSALUJdanwgzQtpnNDrRINhs1qjnapNncVU4VXMIjwtKTJur5nGmd39nlztd8+GNSyKqDJzlAZm059zfrXCOkMqke20hVkcMrIOBCJd34NyRJV4N0bCMuJ0g1sZTNugDOgQ0RW1k5x7T2MyOXm6YcXBT/hZfj8/zczLTLvdsVpt0MZhG03JgcN+y/X9Pdd3d7x984Z53DHv73FGhggpRUoxFJQEf9bJblx2TCpwm2fO1lcoDbvtNT56fFy4vn2LdZbGNXQqUZxGOUcOImDMMeIPgTB50nbGqkRjM8pCJuDLzJzFTW3TOJa44NMBwgK2A7tlCQdyCVBqCFzO+Cj3uiLjSkRlh0qVa04mZy+wtzZMfo9OidYUhr4TDvYcSUHWUGWMUCNUZnCGlAIz8n5IsrWq9480tzFmCb/67fHrj/JoD6iI9DerxvJQENbJT1FCU4BjqSoF7FHjd9ynZEghe14MUmgrpWi7lufPnzMMA03TcP3uLTlGWucoJUOSc5cWEW1/+rOfYXb3mPsbnraOlbOshk7uhRi4u73l03d3fP7ujj/987/gZj9yOy+k1YqoM5OP2E4QxN/53Z/we3/w+/ze7/2Ew27i+t01X3z+Jb/65FNub26YDnt0zrTWkBUE75nHhemwk7X5UYGtcqki2YwzmhwjY/D8xZ/9GV+fn/Pu65e8//QJzhrudjtevX3Lzf09b2+vWVLC54TuepS2YFoW64gq49Us+TBKXIhOqdYntOlIIHr4WaRJqLXFN5qMh+HQ4y94oDh/C1mgPPQfv27Y+vjSONYnp0bj0Rc+/vHUQ7Oha9Dqabpb24+cUtX8iKlNrhPInGtNccreAq2yjDRLOTV6qVRtSimMMRCtTLJPA1xjadcbLp+/RK9WJBQ+FQ6LJ0WhC2ok0dk5Q0OhVYV1Y1BoonVSwxTZY3TNOlFhgbCQ/YTKa6zKrPsG10iCu9K6/lxZAvOy6Dn9fssyTey295DFrnjTrcl+Yt6LvrZEz2bVc3a+xjmLsZr94Z5p0eSlgC4koN+ckZUlzJF9SOQ0orOh7XtcI1qQJUbStAgCh1DYWyNC+b5vyMEQFjgcxpMt7jKNDMMA2tIPA4VMuEvc3t9xd3/Hzbu3zNNIibO4eqkMKmNrlm5UilKd2abxHkfkXhVWXUvJLcvccdjdMQXP29fvaKyhc47WgtMWlBG6cClM04z3nuAjflqwIA50mTrIVsQQ5Hop1LwvIwyhwx7uNPvgKSVXqpPkvcWwQB1wZ83JFv2YwGJUlnwbFSBOWJXRjcIZV1G1xDF0WyuhURlq01GbjXiyejaVLoVQ/pI0T/+243+EwvBoAVg7xTrZF7iqcII/teRK1HtIMIG6sqkKBQkSkqpLlDo99+GLHsTcGSp6ok5Tcq0RK7Xq5fyAHNTUjaIEmgRpUlSqiIhAiAoFMdcpi6rq+yKFXrUkVTrL54zm7PxSxK7KEMM7lryQ8PXkgjU8OHJZS0mZFBLa2co9lYno8ecrGYKCUmSxUQoO8osSXEe0jmItF88vGKeJ/TiSfCHbAo0ietgn2MVAX6At0AdFZx1D0/KiDGLr6xPhX/2CX/3Fp/zqX/wroi5ko/jgex/w/ntPsP/47/H1p5+zvb7jq09esf3sUzZvX8P+QL/q6IYOow2bi+e8/PHv8eLFd+iGDXGfZQOpjlqFDCpBPSe5WLHCyyIGX6Inp0iKQNSoqFFZU7AE26PPL2jPMivXY12Lso5sNTEXmpj4wfs/YdntyLs7zj7wpPUFXddzZR2ds6TGCFowB+Y5ozNcrM4p2zvyMklRW/e3lBMogzMWqx3WOHrX0LYt1jp6bVj3PY2q0+4sPtHZe7Gpmw9QhD/fb1b1kpU8i5QKKQSi8F/o2h6rDBpF8EYsHnUhqUzWkWI82kjuyv3ba9LsSbNn3G/rFDuJUDMlcso0jcFajY+RtL9nrxQZyePYjyM3d404VQ0drco8P98wT5ZUFDEsvHv3lpAUd2NgpwZKO7BetfRtR+MaKBDmGb+7Z3e/xWrF5bqnO++xWhHHW0wa6XRkzgFLprOaGD3jfserzz/n/uYVxhlmH1liYomJ4MVOuUTP0HbCd297ptkTYsZbx6rr2PQdTy/WUoSHxMXFU4b1Gd35Fe9u3jFu70i+wDKh1YG4iC98OBzYL6Eu6IYShMt8NjQ4VbA6Y7qWjMZmTRgTPkbux5lWCfVNLZkcJqKZyKYWmCmT8yL5KnCsAoS2mSO5TNW6WtOkhu0iAZAqZ3SpltCLBMMpt6Yof9KnifAwobRjAbLSxFwNFbQlRLlOUphFS1D+7oHKv+tHLCdbkJPg9oGyIgWqehhHnybJxbjTBl9Ba7Fml2eIK1XN58gqUlLB+8D3v/c93nv5kpfvvWB7f8/XX38JJdE0ltY5dtt7wjwxjwfwAZ8zf/Yn/wNf/WLgrzdr3j8/52IYeH55gcqZZVn49LPP+Wy35+vDyNc3W3xRRGWxqkM7R980/ON/9k/40e/8kP/4P/5fsEwHPvmbT/h//d/+78zzjFKKaZoZx5n7d285HA4sy0JYZgkJS7G6/sieaeuQL9XimFIoWijJBcPb/cTdHPjqbsfQfYZWMM0Ls/eEGAVNNgZlG5xqZc9UGozs2zrZekZqxVALlVPw3Omz9bwVGUadiNCPmoHyiLFQHn9KPZy3hzqifPOLv4V4HJkYv/bxI1Jx+qnKQ4NUheuq8vWl2NKnia8MBeT3MUU0ELY69cQU8YuvafJi+X2Y9izeU+xycnqyJVa0R+GsuAi1Q4e1Dm0MRRva1UCximX2pFzwKaFiwMREnidMKVhgaBxWgVHggxf6S8jidgfYxmFNi7WGZdKCylLpTykSk0eXhpwSh+t7/Dzjl4X9dncaIC/zLAPDGGicCMfnORKMYjZK0O8YmJaJ22uHsZama3HG8vzqiulwkH17HHn95RdEDHsPs+mhHdh0Z2QsUTWoXAhzZDnsub95S2M0zy42tL3BpoDLEZcDoQScimiVSRT8HEkhkObI4fYW52xN4g746Jn9IoOBkhm6jsY29O2awziyhEBrG1arDZvNhlXf01iLcQ3D1RNW6zVXz14Q371jvL2V9PK4EJZEPuzwIYqGRDtCVuwXQdGNgvO252h8apwEQmdgWRa895Qkid/WOaJPEj+gVRV2F2IK6BJQWZgbRQRq5JAoUWregNSzxzWJUijBS3CxtaRUBzDKoRt3GqZEHyQ0uyhh4FRdlQzbC6E2QuKGeGyk/83Hbx7Yd5oUcUrgzuU4bXiYThyhIlDSEVhbaUXVeaJ+Tr7uBJY+YJ4P+8FpkvHwVXUBKI9mGyeu7fE5jxeKh5/vKACkLgolH5EI9fAauVSeFBVeNFUA1WGMhLw9TDCOCA3VkUSfhIGJLOIrgCKoTDm+X9U27hjAdeTHWwXFGLrNgOsabGMYbIu2YJy4JC12YYm5hhrJBGTJ4Ap0qtCTmFOkzxpdFDZDPMzkaSbOE8lAsZp4tkKvOsrQohtLd77h+Xc0eTzIwnK3Iy2BOHtMcRjTMJ2/4tYHbNOSTENxDoxBa1vTZBXGNsLDVTV3QgsFi0oVMyWL+5MWiBJTUE7TmB6AthlEaK4tQYlDgsqFZhjkJiBj5j2mJPTuEtfKBpwbSwgRxgXVyGQnloT1Hlsk5yJXu1BlAhqDsw2NdjjrWPUdrRMKVUTTKIVOIt5VRRCRXM9hyul0c7uKZqWSiPNCjklu1FM3nGlMg9WmFos1b6UEcq6ZJklc2PZ3t6RpIc2e6bA/ueHkHKQzLZC1JaNROnGc8eUi4uEYJmIxGG8h96z7jr5tISZmn/A+smOPT7CdIksjjlc5J0LwFC0Et7AsLMuMXzwYhYqOMI0QZ/AztiSsVcTqCVOUWFGSE6oESoJEYNyPhCSLUs4FRcIocBo6o1l3DY02hFwIrmPVday7nr5phBZIxNoG13SsVhsO08Q0zTVYSNK1VdX95ChTLcEWjuYNSjYFxHjA6uoCVwqURE4i0C7agFEPPvG5nLzmjxk/FMm+kcVcjCRKfe9jLUZM1iQSuVSmtFYYpYm1aGi7HmtlZQspEmIkpMjiI7EIxURqJA1KzkWuk/esJL/jt8evP/JpQi7Haf+gFouFail6nD0LEqVrEnKK8fGzUccJcjm+pj5NGDebjidPnvD06VMUqmoe9qJPrLz1HAIpeKEUZBmobfd7oTCNI/N+ZN13vLvfQs54H3j16i2v5pmb4JmyTK9pOrAO1w2cPb3i+z/4AT/80Y+4OD/nV+/e8Nknn/DJL39JDIGmaQhRRKD73ZZlWUR065fTdayLWK4b9YDu1PnWaXB4HNz5LLqBOWb2y4ICQkp1gFdqUK/GYIQaWIfBkth9PAv1/+WIJHH837cO9bf+//jDb1/6p+fVWuGENnz7NX7dPaMeKoTHTYU0II+0ObUfOj6mq4Oe0mIBqlQdLKrq2HOimShUKriuw7UtxjaEGJnnmRgq9TUshCLW/dpZYk7EqtlQSAPT2AZnG3Eeck5McRRYVX2Z63Mt5cT6KCliSsYADouu65X3y0nUm3KR3IpcxcHZEoOv62Eml0yudLoYAyVntvd3LNNEmGemwyj3gtYEL4MTRSYrSy6GUBIpigC9kPAh4JeZEhaMNeSSceu1ZDw1DSkthLSQDgdC1hyiwjcKrSxtSlDdtkrO+GVhmWsgrNFE3+ABnRbyMqFyxKmCM3LyMpVZkJXsE34h5sA87vFJ1t9Uh+JaKZyG1hnWfYvWii4mMNJorFdrWmsxWlDrpmlp256uH+jajqZpSSGgsseoKFb5RbJpctFCIazXmFaSRaaqHECo+XVvqedAqmNpQHMu1XdVn9g9JSWpg3hwcy2lBiIrIePFgmRtoer+nGvtLrWu1lV4XkXyQL1WRKw/zxJuGEqp+V0yQD3ebUeGT34YD/ydx2/caCzVOlYXsEenqdPiQf1F5e+MET6mseLxXGSlORZNtjQCLxLJlSaglTu92JHu9E39xXFaIW4flSQmhcDxJlVKgmKMqWKlUhNHazNUHiDVI+9Z3LKqHW8+psdqUBZre/qux9lBviZXBOYIfxqD0WCNWB9aa2iMIypxViopg1IYZyhHaCuVU5MhkGTBp0JjFa53vPjwBecXPcPK0aeC1iuUsbw+u+Pu7p6vgscrTwwwRU4J3A6wKWJj5CrBCs2VbrBZ0RZF5zMxB0IKvPv//Sm+USwrw9Mf/oBnz5/xo3/+z/nkz/+a669fc3O9hdt7FJmm/4L+lz/n7Z//uRRKWhEwNEOLbRr6vqPrB/p+Rbs6w7gO0264uHpO0/WU3tKse1zXoDvLohOTS5IeajKN1XR2jdYGpxz+WJw6TVwiC4G0MtCucOc9lJmsCxwitmugb9DWEXOm8ZGcwPvA/fYeFwqt7bi4XJNyIMbANM8YpelMS28Fkm1biy3SnM1BUk3VPNF1rZxj21Sxlmae1Inb3McgU5OSuL25PQksgxbnNJRi3a3oXYefPT7MpLyQ40QOhjyPBCXai+svPiPPAUIkhiwLmnW1KRMupgqJXDTOlNoPF2KYyCmiVGSeBSwNU8P5Bx9wNmxQsRD8iJ8mbg83zLmwSwWrLU2xqBKZxx15GgVSXxbCPKNzlgW1JLavXhPnHXo+0DlwrSVoqSxyKZgCjVZsVo71egVaMe4P5CITj1KSiMSdplMwGMWToUedNWAswQ5iH6gtOgXRjQ690MmM4/LsilTvp0/mBWUSutVYVeqEJTM0VuwdtcUmg82GnizanBjRVU+Rc6o89UDbaqzTGKPxqfr0Z2pabTk1eBrF0fuvlEyMpk4xJYhKwNJMMVCqbbZzcj0X5Wi6NecvnnP17ArrLOM0cjiMjIeRzz/9jJANqThpkpRB6YZcqjC8aSB4cvy3T43+XT1CDUdVSjjPjyZV3yhrpSitG742tKs1APM0UVKQyaaiUheOLccD5XcYBr733e/xox/9iKurK7768gu29/fc397y/PkzlCos88QyT5JLUcSFEQ17n5j8xM1h4ot398KBPiEsECLMSlyl7LDGdQPNsCZby/rqCb//9/4e/+Sf/hO+/72PWfb3/PKv/5r/5l/813zyi1+QU8I6RwjS1CzeV7tKJU6C1AbDiBGKNmLPKzS+I32ZU2YEPHZnjKQgFp3GHIPd1MkGNWkjznGZU75WyVV18LiQLw9t3LExOJ2U2ogckYuHr/rbDYN6/Jxvwht/W2NxbCqO/6sDxRNd6pjfcWwyqnZU1/pBJrlVkOsaef9OWgV1ajq0lnRtWwM3lyXQ9j1N19F1HSFEmmmSYj0E9DKTjcUFj7JKtGEpkFPGGkfXdDhtcdrSm4bWWqzS+OCFJTgtWG1QxmCaFqwmaaAkVEoYCi2CRsQQ2d/fsXiZ3h81Gq5txT7XWZZpIkbJTjhqdlIKxGlhWRa++uJz/DyTvK85WdJkpSRIr7WijSglUqojEWSa1pFzIPiJmAvaWqy15DyglKbpekafWOLEtL/HJ8WcDWWQIU2zTASt0SnifcDPI8thjyky5Fnmkbzbgx8Z72+wKjNYBc4wlUz0SajVRrEZGoahQSmY5oxK8aQNlHtR0xjoneZ81XF5eYkyDQmLM04QgBAwSuGMpbcNQ9Ox7gaWzTkpRPw8kuKCUpHOaUoN89VaGsRV26IRDYTTSu6tKDVlLoImpWMkpdEUpUQxUqoOWilCypW6FrGV6u+MkZoESVAvdQgd6jA92ChsI4W4MWbQsdC0lna14fLlS87PzjDVpvtw2HOYRg5ffoWPI2MU22OtNZjqFAdk/TCs/7cdv3GjoW1f6U4RyVEo5BIrZMgRlwBkGuOahq5fcfXkKSkl3r1+hZ9F1FRUQGYo+iS7KEcDYyXe8aUW0LnUCYPmG4F8J/1DFQIeu5xcMiE/rHFKKXQ2HFelXDvGo3e3UBx0nc6KjaHRRpy0SmGOid1ygJxFZFpEY5E1GC2Ly3rVQhUAKzQ6i0VsLFGmnX1LWTylyMQh16lPSUWeW6C3mlVn2awdQ2/orGIJhehnYow0MXJhG+zTp0xzwvskfu1RNpewiCtNVHBrYEvhHZ6mgC2KfhHko0FxbjtKKoRtIX56zVdfb/nkrz5lmmeCD/hpqRs3eO/RU6KZsyRPosilaldQNBbarqPpelptaLRisIZGy2KdqwOTRlAk6X8zg2pAaZLR9OcXtMOKs6dPWF89YXV+zvpig3IW7SzvP39GLIUxRrZ3r3m7M+yLwpgG165EVDzP5HlhPOyJMUJOrFaOplOiidGazjasWpmYm1zQOaJLRIV6HWZwMWNKi9OFwfSgDUkppmVkmUa221uiH0nR4+5uiRlCKsyLP00ijohG03XM00haFlJIxBLRJTPNE0orul1DZx0l1om7E6SrbQQq19ZK9kYs5MUTTCZlmWr01Wbv4uJDQvTc7++YR/HH91GxnyM+71l8IZqO/rKjzJEye3bzSJhmctHcvnuNaTqMazHtgDUat1qhjULHmdvrr/Dba7If6VlQtsW5hp/8wY9JGeYQ+fzzLwlLYJkOgiBoLVa7iOWuZJcrDEb0QAXiPLLZNDjXMKWMSh5YiPEgXu1tTxxHpqJ4/fmvGP1I8gcuz9eip8iBtm8xMYPy0LZkYzDKkMZInAPbacTqQuMgpEDIhXFJZA04jU++IjKK9XCObltoW3bjnuAX/BSx2mGUYugtJQZSCIQlkYpQdkrWZApLSRCliLVWgTJo26B0Q1KG0Ufi9e1JKNw4x7DZMGw2pLJj9kstYPTRCg+lxQ/eNqmuj789ft2hrKvrv+SywOMatw6GVN2hlEJbh2lazq+uKLnItDeL1a0pD1/3mM7bDwOXl1f8+Mc/ZugH5mni6y+/Yr/fCZpNIXjP9u4WP0/kFLAUMFLAliwyU2FjlYciuQ6dkhant6JtTXiWa+nq6gnf+e53+af//J9xeXHBtD/w3/3X/4K/+pM/4dWnn+KUrPnJe6IPYqtbacxCi6gIX3WMoXLOj1oAGWEcByOcim6OW2au2SNKTBeOb+mRtVCUkrToilbIe3acfB6f/nehDQ+NwIM25tHjj16BR/v5o0cf/q+++bqnx75BlSoPMs/HzUVFEY5/jLUVpZBiXiktdrBGErxPVKpHWlNnLW3rhPHQRLS1UIM5Q5bJ/uJ9pbGJ46XRQmvp+pZiqcisrJMqFtmngqcsizRwKWLbBqta+vOhfg/LOI7MfiHsd6RlJseAv7ekJDStcZa9KamCqineeMgp4hctYZR1mj5PB5TK7DuLsaYaHIByhqwk5E0rsQgvWBm8pEjKQcTEGvquZeg7Li4vCDGw3W7ZHUahUmuN914GOiGS0Axn5xQ9g08sc8SHmThp9vc3GD+j21YQJaNYb9ZoB8rP7O+vUYc7CCN63jNsBtbrFR9dfod43Ju+/FqscIPHeznvMSVSTjUEmlOj6IzBKgUx0XUG6xyLF8e/5BfJrTAWp2C5v4PFU0LAx0jxCxfrARUNrgS6xgjFEDC2oxiHagaWaSF6z3a3F0MQrdBO1YGz2LknXa9XrVDGMqzWYhrjHOowiajcgCkSPNg0hhwi2SRUFAOCUqSRySWTE4i+UNF2TpLcrSNbx1I028njyx6jNTkntGloVpZ2tSUUMKlm0Qm3VEIWlabRDRUf5t92/MaNhtJOvINVIStZhcrJBYrTBAiOrgZiidYPa2KUG++o8cjVvUUWoOOUIZ8oTNUsmsfCsdM0oh6nWdXx80d6Uv3Fxd76gT8pg4wHK91jg6Trn4Kq4heZcOYq4FEpMi0TJWVKCIgvsiy+ssgYrLEchfA5VcqDvGmVPmRqOFFdUB9+CdGGKKqnv6PvDM6AQnQeRypLSQqdC72z6GJpdIIYCToSgyL5IPCphkWp+pZlGgUuw5ShR9GjWCuNzgUdEvNuZlQTr/0ijk7WoIe2No6KbA2q62FzRlHitVCyJldnu2QyoWmgbQVZoqBTYp4ncowsfiZPEmgXxhlTIi5HVjRobcjWsrq4pF2v2b94xuWLF/irK+KTS2zXYocO1fVkY075KkUpoeRZi9KGnI4F4EwYR2KOZF3drowWoXGltxm00PiCF+CvgEWjUkbFjMlgtcImTVO34ZILYZlY5gPzMhEWCYKbi6DYIUlTWmrHnbWuVDxBkXIJUjsqMBhSSPjFM48zmAjpEVxa3aaKKWBl0qLQhEUKqaKQMD/naNqWzfkFPiz4HNDZELRYEi6hsMRAxNTCyqHjjNJJ3NFSgLgQ5qnuzwVjW7Rz2MZhWChTIcwHkp9QcUFbmaBYa3j+/Blog4+Ju/t7Dts9cVzwy1IRSaF3Ha/3Y4aEVmKkEJaZ1AWsDmJ1XCeoKe7JxqJyZs6W6IXbHFUipIC1ShqvmmqPUrhkKc5RrAFj8RHRfsQIVs5vyTLlKQrxUC+F4Iu4mWhJ2LVtjx4G5iRi8RwsuuYhHF1zjMmCqBUoRYwixHmqTp2KQml7+iOCzcxhXpiDr5NQYKWwxmCtxTqLcRatZAF/mDwL4vLICPS3x685lH6wnj0i17L+HgvWh2KzINN46xq6fhDdQs15+YYt6aOjAH3Xs9lsePLkKfM0cTiM7HY7UvRi650TKXiWeTpRPXSpJbMSQ5CjC8xR+lGODZCqgydl5Hqs+57ORXjgT57w0UffwSjF7u6OX/70p7z96ium7VZouSD3W05Qg3GFxlNzpSq151iMP1Cea5lQN6RSaUJHVE7eW0E9JAvAfFNLyeOr8vFHxwbiuNM9bhwewxMPn/1Gg6G+9fxTk/HNrz++tw/f65vf99uNhvxVTs8VKtSx4XhoHIy1p71dV8csY91Jk1HUA8r1mDpljRTn+Wjzjpi/xCCmJzE8NBoUaQitUmirUY3khZVUIB11XuCKQsWKVMQoQu/G0FW5bMyJvCzEaSTOM2GeyMFL45qy0DSPOSZWoZJoSXK9ZpLSUlwj+pgUPH5RzNOIsbrqAyUTS9fzrjWyl+o6uE3+dPptbbj6oWe9Xkn2UpbG1ocolscxkbLHh4yyDts0aBtRse5xOVKS0IGzQZwDK4WsbRp0tuQkUQPKT6gwY8k0RtM3Dc+ePgVjCBm2uz377Z4wLcQgVqYnXVK9N450KAWy13tP8h6DJntB0ksSFEQZab6mlPHTRIgRjFDbbb2edJb9LluDrQ1CMQ2mayUYOXiWECgalJUhN0rOkW0kXTxl2W+K0di2xTiHcY4mJIl1UEl0xuRaZxoxczkC8eWo+nhUOitF5eKjbUNG4WPmMC34mKu5AbRdKwY1VuoM1zQnxpDWsmdJ8OyROsi/9fjN7W11A9qANcLJyqCypC0K9JlPgqlUIBVHSg25NEjz0YBpISlS9BidMbrUeUrljMo7dLLXksZAybuUoTNOuNRHca8S3nU5QjmVg6qViMGp0JGyRpCFLJNslWVCo0vVrqVI0QrbHB1kjhSJTEye3bSt1qaFxsqba2yd05RMiOkkmBmniRAifg50jVBvyAJ3JQraidCUyr3TCpyB95+d8eHzc55uOvAz+3Hm9m7LMi/4eSYuwpMS6NJgUGw6x5gVc1CYspwCj1KRdNWjvC5qWGxilws6F7bMWBRWQYsBZzk/W5H7Brf6/7P3J722bFueJ/QbszCzVezqnHOrV/hLr9JfOJFJICCbiYAkEyECBBItPgFCAlp0+AjwEVJKCUQqRDOVDYoGEggSkRABZEbh9Sv8vVude87eexVWzIrGmNPW2ufe534D0fNnV+futdc2s2XLbM4xR/Ef//+GP/h7f0CJkRwiP/jx7/L6k8/40e/9IdLvKNYRnMUah7GW7XZQA16UpSCHQDidOZ9OjKcTX//6c77+xc94/PILvvrFL1ieD0xPBw7jEVkythQeT08gMP9pqSV5y36zp1HmHh3Y/Y77n/wY++nHmN2WH3z6mlPJnMrMu68+ZzmdWY5n0jKTU2ZJFT8PbHqP7zydeJCoTFenE70InXe83u84TSfCODN0A8SIMFKWniiGc4i8f/c55/OJcZrJJZJNIcV06ReqCxXWqX6EGELQYNGmwu2wxTjtbZmnmbBEnuZn3hXNrozTDOj4T/FM5xybzcCrmz1SCoecKKZgnePTN59cnNEAJgg+dsSkHCW+d7w7nziHhdRpH0pvBo5pZMyJYiJWsopv2SsKv7zgOsf2vsOPniyG+X3k4WbAFwfhzOAdO+v47NUb/G5H6Qe+fv/EW/uWx+UbzuNCjIlzTohzGN9rn03nuNkOWgYPC+P5wNPzCRGLl45ODL1Ais/atySOxTqM77i9f0U/9BhrOD6+1SAxRNxwr5zww0DoHDjPfrcndJFls/B2PJFzYo4Za9Tg3+4Hbl69wjjPN8/vCXNQ+kjXEYyFBLYf6L2j7wdO798yTWeWMOKM4EVUyNE4xHfk55kQM8UUUokgwvbmFmtU8Og4jeRp5O3TE9thwDmFWz69f6eVHjG1P6V/kQV2Tp3fJUclmvitYN9v3IzrtA+h1CSCtJBCtxZsrDkpYxX2ud0qBMFZgtQE0QqbolYd1CH9+OOP+ezTz7i7veXLz3/Nr3/1a6bxzNB3bDYbzqcT03gmzJNSold6W1ZHXh3UTFlthSjulkZpGiOkJMQlYHOhK/DRR2/4nR/9kN/7nd/hn/+Tf8xf/um/4D/+P/2fieMJlyLGCMGgsBejDd3GGFoYoF9B3d5ce8q0eCur3dJA7AIVWp32et22JQlFE2OlVjpW3Ffrfaz/F6hsbB+O2avAAK6eUKMU/rCqcR1IvKxgQKtitH2uf16dowZzF6XvSwBiGwSqVnu+FWhYu/YacpW8SzGt39mIUJzBy4DD01nHsNkyTiPjNDGez0znURMxi5KLmFKQFJBScFZRDbJAnAJpiYRpYet7Bud52GzVj0mJJS9IyJgxwrljyYXH08jXb98xjiNh0j4FKdr3o31n4Hyv7GOUVb+jhFTFQx2b3Xbt25mXiSkFHktkCTMpRubTWeOzAilGhr7n9uaG7WZLKYkwnzSJ5gyvXt3RdR2dd8QQKKXQdx37/Z5pDjweTsSg1YTUetmKISal+I7LjOsFK4mtSZQ867V6w8Z59ruBnEZiVK96s+nxvaHHs9tsGLqOjz76iGG3x282PD0f+NJ+xefPv9I+SQrzPEP97r7zVfnbkpbEeQ5MjwcezTsdC8bpfAbSPKrPaAy4DuN7htt73DCAs5wOz5QwQZpJuw1UVfVuM2B8jxs22JxxJROfNYFUBGVddI7d3YY3N/eI9TwfJ8bTyDwHqJUrrGW329PXStR4isQlcq4K4YI+a4smLGIxhJSrH6RVON9tcZ2KLp7OZ8Yp8PR8qrpdhs6rWJ+xAjnSdR2D91d6dZdZKKb2e/3/Ezol2dE8Sp3MhSy5KmRrhiRX85UrxRsmk3JQfHwJpLyQS8A6DSQMXHiv4ZJRcpU7GSGn+n7J6sDVTuo1C2LcWgKWmrUpLY0qchECqjYx1890tZydyZg6izJUXK0GE6vmxhWzVkq1lGw1o5mLIca8Gkqb0eYjLCZqIBVDXhs7sYI3Fussm25g8Jab3vI7v/MZH93tVJTHWKTbsnnY4OYZN42MzydK1OYoL+pQziEhnZZh0yyUJEgRTMxrpSajzFa2frZYWIwlGcNihdA73GZgc3fHWALLkvnZf/KnbDJssvD2V+8Zd3uO9/8fcqVLnDV6Q8SCM5VtI4N34Bym8/jNRrHAJdN3hYeP7+m2vjYoBlwpeOPY9xu8VbayiLCEQFgiYZyZ5pnzODGUgukHzP6WZB0hZ5Zl5FhFoo5Pj8pFHQN5Gsm5Uvw5zQp3JtGJxZOYDidsjOxy4eFmz7YfuNtv2UZDsDO7zY4xLJyXGYmRlGEcJ8ISyRF665WjmsRcFoqlZhTUsSzS+OIt3ju23cDGd2x8RymQciGdsmpjxEDMMykHQlq0ekIh5agwI2u52e5WfvtQaeRySIQpEGNiPEwalAwdDMry9DQujCUyFhX4kbAgKZPGkTLPmFSQonA2ExadPyFo1sYUnDO4nDEY+s0AS1bWKz+Qi2NaCl9+9YjfTJjOw5IZjOd2s4OuJ+WEHUe9D8bS97rwbLwjjWdKaXhvNR6ZTCxxrTrofE6KJUUIcWE5BlIpHM6jsn/FyHx4Vjw1ljx7jPdaPUxqkzb7LSkEcgzEoufqh55+t9Xs0HkkzVnFspaFIgtJjspnQIa4XNSjKbrgS80U5UTOi9JZWF/hFhExBe/7Wr2FYVBYjxEYvNWKqZGa3S66QJjViLJ6Q5UlySDaW/K3U5X/Hd7MJXluqPaourEt877+rAmtnBXiFCM5hAoJuXaCm9OrBB9GtGn83TdvOTw/M41nus4jovSxp+OBGBaFlFSl8evlt7rEmhW+XpgL2v8govZZgFQTbSXjjUAMvP/qS37+F3/Gz/70Tzg/PSJxUTZDNDMtWSkvASXgaNWL+ukFDSJq4YfVYahrZJHLMReYme7XnP91eH7w3b61yfq/+uvLO/EC5dTeu+Lsv0YicP3z5UHrecv1OZvjIy+Plw9OcHXkGpSaFQ2R10BqzQS3DygFUacEoVZqxeKzxYQZUIXqufVkTBNpninTGZbWEyB4FGa0o8FKhaWyTyVjuN8MbLqO281ADoYSLEsnRCCqx6/+S1JYpYhmww0OKZmwCC0QNF23Ngwr2YrF+47eezrnudkMmvhMkcNRlLAkJeISlCikKKSrUOUBRAVoh80AJbPM41rl8M4R5oXxeObZHNTR7ge8H7Rh/KAK4DEX7YFICVMhZSUl7Y9MERMXZD6To1PhOBSSHJ3S9lor4CwdDp+LOu8xcTpPfPHFV/S7E91mSwwRbx33t7fq49UKdYWksN1utApjnT6nGMk5rJX4sg6WjFTUSkxxTUDEFFmmkUThcDpT4gxpUQ0OV2GQ+YxxgS7q+On7npubW+2DSYEQk/aNuo7dzS2uGwjlwLwk8hxUF0QmHavVp9IqWSAui8oyIJWuu/YNiPYQ+/qPOv+914Z2A3RWey6MEa2qWxVVTFn7dZqPLmt19DrIr/fkexbbvz+9bVlBm5VC8FLuAe1vgBr1t0CDREoLMSrLTq4wEqlMVJqdr6e/mtTimkHU0lzJl2Y1BC3tNiiKMVX0plwW7Hon1FiZykWtx0dpwYZUuENZV4Gy5nlKZd9o1Y1ajs/qAIFOqhZcpZhqORUkgy0VJlVAUqZkqVlJ/dd1nqHz3N/csO0d91vPp59+zN2mI87PlenKsRt2LPOsAmrZkSrtmC2VNStNujh5VBwHMEk0yMjam7HUQMP4SuUrQhJPquW2OHj6YeD29p7pdGA5n3j85S95KJYH0Wbhk8B7I0SJpJKZY6bgyRiWnGj8A7nvMNsN/at77j/7hO3NnruHB9xmYL/xbPdvCCIEEbwfGLqB+90tvReMNRRrmc4T03ni3du3mNOJeHjGJYUL9ds9Z2sIMTJPJ8bnZ07PJ+blhMmFrhTKopzSrtPGfOcEJ5lOEr4Iy3lEsnLG3/ueXb9h63psF4nFcrPdI6cj86SZlJQzy7yQomYFOqf46YyK62B0vGJa5U5FBo21bDcb7m5u2e92WIQUInGeOYaTvl5UfT3lQCpRx6MW0MFA5xzboceIMA49sihJQk6ZZVoYR+39uNnvuNluyb2QBKbjmTkHFiIuxyoeGSEoztRWcgaTUfxpTESjc85YQ3CWbAVbwDpPCVqENbYjZ5jnwldfP+J7h/OWEhKdKPGDs5pdzZRVfHG3V7EmZ4xC6bRmXP+ZCjHIpBLUcaoZ3lwdwhQjU1C63PO0UGKkxMR0zkr+IB5jgwYavcfhapDUsxiYSyJExd8P1uI6p6VoYylZVKwxLcoilRe6Taec6nHWsrkaqFp7rQ2vkom5gHQY43C+pxiLMQXnfPXHCkPnNNNkhK46U1aEUBTbLrmsfkyuFa1qEAF1AhV68D2s+d/ZTd1E9SPLasNfBBnNwW7Z+JxYxklpX2NA6rr2Em8sK7RCaqDx/v17TscjyzLjnaWkpDoV45lS4ROxBCQ33nnWtaoi7mgQ7MLFmRExrYwPdVE3RfvZ4jzy9vPP+dXP/opf/exnzCcVvnSGSlda1Emu9l1aw6bU6nb9Lit57MV7ulQqLnftckv5IFtZMRh6hWvEQiNe+c3P5sUpL8e82EsuzvB1gHO9r3zrbC9frVWRq4Dj8qdLVnMNXDSBWcN5vQao7Dz1O1U/ZL1uNNCQ+tphcFnFXyUIJRmWRZ3PMKmgXV4WCBMSYoVKq8q6F8uGQofBFWFOCjEqItx1nk3fsessCUuWQmc7phhVfDFHZdfPFxE1Zw0GxTTHkmrwLNjOQ6Ufdr7HOsd2s2XT9/Rdx9Z7UoqEZWFeZkJYiDmSov5r43WtFllTVcJ7pGSGYcAalHnSWKYwcTyeSDGrb/Hg2fRbnDiyGGXbCwnXFRXVzRo0SSmYkpEcMElgqYJ9xpBFiNYSvGew6rM5UTiuxWCyJcZMSDNfff0N3fFMv9kQQ8BZy+3NHkGDckrSBLkx7LZbvNOG7ynrmhWTsma1athKnGBYfcBSVPcolsgyB5aUOY8TJS2UFMBarMuIV1phTGDIolTyzrPdbpnnWRNdy0ypycmuH/D9FtfNygpZYJoXSiUu6jrtB04pEGNUGFhJFDH6DFa9C/WpjDG4rl9bB5yt1MxS8C3IcK72hSp0al4yMWWcXKxGgUqmdJXUKfmFHfibtu8faNiqeC36sYJg82UyF6MUerkUnPWYFEmHA6faeCPzpCXDCmFqhVXt5a5Rh55Jm1hyUaVp0UjL+BrFV8Oaa2Aj2vmCJSutmjVYZ1QYDO3NsPWGGusJIdaG2aCKzZVNpnXkY6WWSh25iOKxQ2X9qVSXpUAkY4z2a5yngBF9gLZkrBH6wdBZS+89d3c7Pv3kY+4fHvj04x8qh7V3EAOmLNg8sWVBUmDJws3uFbf7B/b3n3I4PvPu6Rv621vm85nju/ecnh9Z5onpPJKXSA4JF1I1PGogMzA7IfsNWEcadtjeIb6qs0ohSsFvb8j9wLzbEuMMcWa73WJnNTIbA4NkesmUABSDM46MQuii9MqMIGCXrMb06S3l51+Dc4TbWyb0ekLOTMvEaZyYRFnLijFMW0fpHcP+hm7Y4Pue/c0N/dDzZthw++YB33U43/FPf/5XHB6/4fnwDMCtwHaLsnktiYUZcqLLPbe2Y+MtPQUfE27ObBOEJTLPM/OUmQ38Kp3bEsMvxZDEEGuDX3KObuvZy0AIljQFnVdZuaxzFiiWfujpuoHt7pb7h1f0w4DvvTrFKZKnhRgW5mVUXG3RCo6Om0IHK1PJOWT2my33D/ecY6LkiHSeh/2AcypimBFCNhgnJAvvxhG7HQjOspS0UgEmk+h2O7b7PRuz0+yrnzhMZ9Jy4Hl8xvQbxA8KWTTaIzIL5OnM9PYLbr0wWEgWpmVhDpEvf/aMd45N13HTb+jEcDP03L+6xXnHzTfvmVMlZtjpdXdO+CYcyXPCFod0KqQ0hZkcAkSLdalmSeo8E1QkMBaWmDkuygQlGGwwqH8WMSEi88xxmdhv9wz9AHXMnebAeZ5hGnmeJqYp4LuOw/OJcVxY5sjGG6xD72+aFWKQMs5bDZJsWQW6rO3QkKNoSVssxThAcb6erMafdHFusgYmSlmsfTQta7Z6wEZho17MmlyhlOqg/jbQ+E1bTnl1Yhv5+ApMrtVwHTPVtY+BeD4pHDGrereUrGq/60PRqpM1hs45hk7pQL/49a+YxjOmFFIMzNPINI7kqLj7mNJa0WjwoeYwa9aRlVFGow+F9eaKlc+V5ah5/e+++DV/Nh55+vUv+Gf/5B/zzZdfYGsGPmdV5vVdx247aA+FNLYajaemENf+p1LXQ1WlvoRU5QpW0N5b6eqhUsHLigqg9jnWW74GTC8KF1ze+PDtbwcZFeFwde/lat+1InF9Vnnx29V5a8Dy4TFrlKk/RPQG6flLzd5qwKbxvs44W5u/Te2xNCI4035qMlJSIJ8WzodMyonDea616ULvPb0zbLc90YoyUYbIviYbB+cxMUEMzIeJUimEDxmOBn4dAzlFSsm4rmPJCguWDNl1YC3ddgOdJ4RAjAsxZs5Ry7rGGG42W7p+YLPd0/UbOt+x221xos90Oh1V82GcmJdQqbcXEMH7js5ZrHUYY0kps9vt2N3fY7yHnOg3W2wN8OdxQYplO+xIWRNVKVuWrMx+oVhOc1T2xzmw3W7Y73Zsb3bE3tFJ5jyOpDGwkJCuV9iRdWAMc1ESlzyPLO8fCZLopLDxlpBULfzxl7/Geo/venbbDYNzvHn9ik3fIVJ4/35gDoGQIt2w1aZ/MSxiKVLoBtWVwArTEpjmkRgCvWt9dDBHrT6d55mQNVG2FNWgKQJpyUiMSBWSRYR+Ctzs9myGgRIzc4iMU+A8zZQpcF4KhzEgznM8TbXKkxl6TWKWoj5HKbpGb4Yeeq8q5GtFQ+tylNq0bTTpmWvQrLkMJaTtfE2ql5k4jrV/WXs1nBFV7CiN9apRL4smV1Hipd/U1/bh9i+hDJ5qBqBQ29nW6B9UwrxNfGsET8GXpCXenHClNtZKxokqXkpR/YjGW69Uw0ofFtFeCuMa3MCwLHPlEW4Go1QeZzW8zmrvhHdWI1FNXNXeEeHKjmmzi36kQpUMyqe/Zjky7eVaPnJGI27Ri5WmAgdob4cgJbHpe17d7Pn44YGb3ZY3rx54uH9gt9tzc3OHWEFMIbdu4ggmRkiBptKaSBznE4fpxHE8scyLUryFxGmamceR5TwhMWtTULxEltGI6gN0Pf3dPXazJQ17jLcYZxSKEmbG+YxPiT5GTFoY00KIC5RANIngMt3WMVjL4CwxaMOrF8sSdFENIdeeHI2mLeBKgZixKbI5qGUXtOk9hQU3z+zqoiAi3ERDcQZznnH9BtcNuOezGrKuY/n6Pcl7ZOgph3eY6cRyOoD32K7DGq8ZQsm4169JIRLmGcnodYhQQiQupTaiAVimoMvBKSwKAxNhsUIUIRrBnE8k61iMIaZETIU5xKvmJ6v9MtZzf/tA32/oNzuMCDlFTDZKr5oiyzJqM2BaoKiGg5CxzmDw9KarQdZAlqiUwTc3sExKCHA6IFkNQFwWchG8dwSj1NOn5wN9KirOl3V2GqON8MSFsoy1Kb4ojZ/RZ2aN9gOYzpHJ2BhJ06QGZp7IIWO8V1yqNFXZTChKV4j3bPd7BufZiLCpasd95ykhV9YaR86ZcZwZl0iIagNutnu67Z6NKUzHE+PpyHR8qtTWsCQVgdx4ZePBeySog5djWCGLahh1jscl41ylzo4qlBVzqnO2UFJiPJ+17ByVEMBbVZfHFUqFB5ZsEKNMHVo5zazNpdXoVzABDfFeUy6U2DJiWjlqzlkuaXV8ayJZ8/ClOYKNM6n1cbVc63f4cL/d1q3R0jbIVLM3l9c1y00dK1Y5803VDDDCCo1tWUzREhPOWYah59WrB4a+48svviCGhRgXQtWqyCnVhVf7thoEq8FMpFJT6rlr8LGOmIszLlChNWZdVp4f36tTdXhiPJ+BQj/0lBokeePp+o5+u9UekFIqBaYGtjGXleWwacToequj6hJOvBxhpTnjNeBvAcVvrly07UXo8a1Q4wUcqp1rvTfXIcblqDYD2vyiBj0vMVjX8CguPd9XX0jaZ724vrImNqjIhRb4N9IYI8oqpsxdgjNygUAGTUikqOMgZw00VdhPiR2sMdhhIHc9KWjPgzEGipCquC9LIiVIWUgYxqhV4WmZV2KNDsOSEnOKyGkku0CynmkJhJSILRFbYTtUYontdqfMkL3ChKwVSEnVnnNmnidCWOrntIJXY99CdTycUy0xo+cbdnu1wVmrEwbVaYgh6X0SSySzhMg5HHBR9ZZiqs+vwnxKiuQwo7os2tCdnCGVrBB1A2KKBjIpkuaJOc6UZVYiB2/0+xhRHauUVVDOOHpj2W63bLxnYy2bziEUxk5pbk1UPYtclIlqnGdCSDjruLm/Z9hu2YhwOj5zPDyxzEd1KHNmjnqffS4rVDovi3JqSiFEtfEW0SoA2ocyL4vamphYloVY1zgRXVOWeYaQSLH28BiFva/9SM2miazJE2dr5Q/taW7D2YiuTyvJUqkTpCbrKavnrfak/V4Mq3BTSyrUcSUq7MRK4gQfTLTv3r5/RUNlUkGUL1kXX3TRLNrQZKWxLyjjjy9ZsXZkumr8M4WuRr/VX2+Cu2AUutF5hS5kUbE6azxGHFOMaji5KIjmrNGZGOi8Uf5658iIMgKVXMvDUu91AbIKLKEsft5roKGiN6rCjFFO/ZL0s6ytGYzUHrClxVaNsjJXnv5N7/jhR6/41/7wD/jo1Ss+/eQzrHQIhiVOpBVGpk5oCAs5TMrekAIxzYxx4vT+Kw6HZ56f3pOWSJoD83nicDwznc6Ew4Qv4GrjhDH6RKMzZOcx+xs2P/gR3d0952FXHxhMx/ccD4+8n464aaJPidxbpuVMWM7kNDGYwuAh3HuGwbIdDGMs5CzYbDifJuZpYR4zMUGKulg4YIOhiwWXM8P5QC/QGbjtLF4yGw87a/BF6IuhLwVZEuP5CC5Q7MhY3umiSWYqaEPUbiC93uE6YTk947d7Ze0x2qxke8v21Y6wBH79+a8U879ExDjiFAnzwhS0moDtWaI6zacoVIYAgkAgM8dEPgpJLEsxOK/KmcdxoXOKZURUWbz3A5+8+ZR+2CDW8nR4IiwjHRvF86bINB40Q5EzJTWsblkz5jf9gHMD1nZkE9jsdmzu7siTJwOn48gipUIpJja7PZvdDdEUxnHmy/fP7CYw1rNkAeOwLuPigoSRdFqQzmEodLZgrAajvnMKFeoHzhliCsQpk0OEsEAWnPUqMFRheDFnijUY39Ht9ty+ecOu69laB3khxRlvXRX3UnjTuESeD2eezwuxqp4+3Dxw99HHbG42vP/6LfHLL/nm+YkYEqUI4xyUurgftBnceSTpnF/STFkUGuAsCpsyRsvecyYkZQCiiqa51tApKH5aJjBgxdJ1lq5ziC0UK2RjVka6iwcYq8UpCqOrYoGl4nlNMRqsAikGdS6crNniUqCkBVC6UanicVYqE17OpMYSglkdQRH72yDjb9tW6l+17Zqlq45jXXdMZQxyFYfcWYOVQhLltA+psSiaVT0bCp137HcbfvDpJ1hn+dUvfkGYZ5Z5Yj6fNdtcoTQlF5Y5MvRaaYu5YpiRylhk12D1w3/qOFTonJgV+/zum7ccjOHRGSQudN7TDX3NXkd819ENPcNuQ0hJRcjSotnjlKsmjIZbqVYm1kbwyyjjw2BD44Dm1JfWMqRHXQcbsoYgV5ugEDbWc7b/r7Co9djLMfLhW+247wga9PDL+bj+UdBAn5YILOs5LkHLdcCiQarkS2BaUKdEjNLMOqO+jTU6hmzN+i7Lotol07xWshqVsHVKf991HdvtBikQ5oX3IYJYUhHKkimzYvFjFhKWBIRYCDlynAOlJVJFhT7nGCnlQLGO7BxzSsp6SME7JWmxXb8Kst3c3tH3Pda6KkCaWeZzVfWOjKdRyWoqE5PUyq13HmcNvVf2Ies8ftiw3e7Y3tzy9P4dU0icxhnJmiTNMTP0A32vyaXztPB4PGE2M1hLRLQR2ztdG3MkTCPeO6QUeosycBWDeKOwZGsQ0Wz+EhNxOmNS0MZq3+mxFDKRJWlw3RlLP2y4u71n4x19Tpr5L5neO7TnQjDeM4fEHCJPp5ElRPphw6vdLXcff8yw251IGR0AAQAASURBVPHNN1+Tv/Z886USf6QQCVEXiG2BznmccZRxItVE+BIjIkr20fdKLlBKYZxmZmZImZRUmsBYpVE2YkghUkSFipvoq5Wy2qTWk60tgGqj7PXcrNW4lGuQkVsSpc4Paex6l2RMuRxY16a0TrPG0rrO2Xz1YTSE09++fe9Awzp1uI2oYJ+RomrWqebgvFOMl7XsfI8DOgrGajaYFCBGUixoEKeTWJk4VHRJmQ8uzWfquHpShlAWrNVqQs6mZoug6+xaXvVeGy+XWTFrORdy1OiyJpVISXFtYsDX5iUVqFG+6xpOqYx7qZoRrgYpUUskAnTVuVC+0UJl1uTHH3/Mjz76iL/3k3+FN/c3DF6YH78Bq6xdRqI2keYFbwIzZ47ju4oThn7bM8aR01PgPKkkfZgn5tPIMk4cHp+YjiNpjspW0RwWD8UIyRqy22B3N9z88IfM+y0nA0/HE00d+3R85Hw8cDiMWnkSmJ7f4cKCjZEB5bv23jJYRy8GXwy+72g9CBZLZxw2LIScCCWp+c4wpchStGK02EIv0Buh95YUqRk3HckhRUwtVbrdDd3NHXa7ZcyJ8zhxOJ4YlwgWum3HZApTKWy3OyZjOM/KMrXb7nm4u0W6QceQUwGrkApLVgFJhoGz1cbgmCGLI+bMYYGSVbmbCmtKRXtdYsksKWrFRgzDdst+t2fTD8gyEUJgWQLn6UzM1cEkYCWTJm3gLylis8Lssina1A9sthteP9yz6TpYIkvILCFj/JY5wBdff8PbL79kOp05P83sHHQWvO0Ix4Wn5284pcKcEssSiOUIYllyoHcwOOFus60sJ4lxPqHxvGe/3ytG06kORIln9pt7xlg4hZllHJEU8TlwngshCTklxhAVEhULxcwYd+Rpf2aeA88pkcNESVotMF3Pttvz+gc/ZlpmNu/f8e40EuJMsXtm6VjEc9PfMuwz+ynTvXuiTCNpXjC2YJ2l2+xVNFEMQ7dh228xr6wGEtWJ3O+3WFc52pNme4d+cyWMpoGkqU356pIWtV+5QJ61glAdzgKKC06BXHKlmdW5ZhaFz5XKmlcK5BJ0AUCq4FeGYjC5OsEiWKuZoFSSzttS6bhrxtjljBGLw5GKMqQkiTQ3+rfbd2/eyQpr0dxhhcDUDLWy+6hz2HXd2i+DMaSUKVF7dWJzRuta2nnPfrfl44/fcHd3QwyB0/GZ8XQihBkh01Tmc4xQCl1Xe2ouLYsgZSU+afSxSisrl4qBqeuoiIq6icGKYRonFoEghZvNgOs6ZRTsHbYrLCkyz4FDiIQYiDmzhFSFvrRqCepOSO3DajCqtrVEZ3PIdbtk/FtFo+38IhYo5eXvzYE3sp7rRTM3DVkgL/Y3Ldhq+6x/02uVWl1Yi1ZU0dKrYz64LK7P1rDkUr+ABiM14MqKSW8VCGedznXD2iuWr+5LztpLELMwx0IImWlOlw81qCxzTpSY2GJwe8emHzB2ZjZPTEF7E1yxWPGYzjFLJJbCQiFYIZA5GUuMi8LPUyFlXZu6IpCV5rsYsNbSd57NZqMq8YuShaSoFZYcFtUqqoGGlKw0uinhJJJEk0I5R1rV7OHuXuE55AqnSpznhVBgzvDN1++YziemwzPeKFVvbx3H08ThpE3fc1QmJ/KZYrTfwlpR9sK+136XnIjnA4p6EG42PdZZxKsGUTaW4g1TzMQQmacRyYmOpBTmaI/dOM9My6LzePF006QaIikxBoWmlxyZ5wk/DOxvN+wf3jCGiHk+YZ5H8jiz+I4Zx1IsN7s7hhAZloA8PWr1IyaKBWOsBl9OKz6b/Q4Rg1idwwVNQm+GHmuNqpwHpTcuKdM1Y1OHrx6ryaqS8/pPmqQC0AhjyKVWoGo1t86rki4yEQ1ymGsiRoqssKe2//X8b/uauiZdUgWtj7DOpHo+JTh6maD4Tdv3DjR8ZYqyCL3RCLLkiPL1VtVR5zDO4q3DFjBVmKYtvtZa9B5JrYmp8TMFxT1WiJSxDpMTSPUB6n+KEyzqM9Soy1XFQmM065yiqiY2/yGVKgCIZvxzVWttLFHthuWSqxaCGp9YFwAutZdqNz9QE0Wwkhl6y3bj+OGrOz653XHbWzam4IiQErlEDX7KTE4LKc0YiaR5JC9nxRmLQDGUqKVzCQUTIzYX0jQTxollnir7VGl2WPc1AtYizuO3O2S7IXWO47IwzQvvT43VKDOdDszjWbMwprKFlcyQM30daNZos5UXWVkxTMP/NorgrE3npi4UDVNeSqMdhsWJsohZw7PTxnyTCyeEIobUW+xuQDoPQ4+rQcc5wSkYnkRY6uToUyaEREwwIUylMEvBeEsSRxZPEQvisE5VMIoDTKdUxTFxSrqoBK0tkoxhrrTJORfI8bL4pwy2UmF2tWms0mJ2viOPUM6FpWJjxWiPUMmqjqoBduW2r6wVIobtZqdl195jdTVTFqolMi2ReYmUWZBJeP90XJvRvbPrYqhN4alC+wxD1xMKpByJKbB1js5atsNADoGYC6HOC4Ow22ywncd7W3VfDGboSXPgHBYo2mSWcmSq9zzlzBJViTsUQULEjCOH05noPT5n4qxZXiTT2Y7OGEIRYtFMqjEeYzMiliVmztOMORyYxpGl9p4oi5D2ApmKkW7QBr0HThu5k0IKdOjXLKKVamOq1o1oFlInyXXqR+1Za8CXki7Z0+rNFJH6GblmcgoUQXKuGV+pFeayagOpI6XwmIvB1+uosTWlZZGaia4LwupEVRvU2PS+j/Lq3+XNOVMr7AprEco67yiaVXR1/fHOKWxXmn0vVTvJ1lsva9XBOsswDNze3uKdJcVFg4oKW2oQqVY9UedXKmFRWZNbjTq2UdqWNj64kJGU9eGrk5Gbw5oUslwEuphorZ4tJ7mkXMdJrrDQTMyN//GSt4RLM3rhO7YP32wBSs32f9cxL0OF7zi+OUBXR8h3vPdt6EW5+tEgT9TA8eVnf+dWKx7lg/OsB64XXNb+lZwzpYqd2FqRMBWKlrKOJw12lAxC6mfEZVFV6HShvKUxEYr24GXrKcZTxFFMxvpee0wziKiwXoyJU1BK9lAUkJnQ9SmgUCKtmOgdaYkv6x390OO80qH3nSqYjzICSvSRYiSJNmtrNV2DjxaIW2lEOpbtZtAx5rTnVO9LJC4LSwiMS8K4jmlOPB/PLPNCCJniLViDF2VFyknHoBiL74RIvZch4I1Sym77jhQDcdZAhlJw1jBYo1pOnSeL1UbpvqdMgWkOlZhHmQqnZSYmoWQNOmLKxALzEjiPE8fzmegdLiVSmFVzK0W2vmAV8EWscGOxHnEZrGOOkdM44g7PnM5a6UhFW6OLOK10GVeHZVubvDryV/TS0tYmkdUeGNGkcGviv8yuC9KnacLpe43dqVYb2rpQ2c9KbTnQ3VsVtVzGY74wUa2t0HUtgxZA1MPLZXW6kDBU/7euZZTr/b5f9+D3DjQ2G4MVdT7vNjtyzjwez1X1GYbNplY1LD5TMYf1nxRwDi8Wk5XjWb8AuE4pKU2luzQVE1lMJMZIWALFFsQKnd8plEAMKauolq0MCM5poDPPM3GaSHMkFVVjTnkBMk4Mxmik1zmHKep85aLc68UKGEspohRmLaLLlYrTgBGvgmquYKqS5K5EPnt1ww9e3/LTn/yQjbX46RnfZTwO8YYlquM5nZ4IYSItI3PRRcsEbSouYok5MfQ3OOfxJbIgeCyPx5HldCKeZ6j0tRRUcbaAcQbjevx2T/fxJyyd511Y+OKbr3k+jrx7PGrVxRRKXKq4U6TYFhSUmunTDLAX6EVF/jyCL0qzmVJmOS7Mx5l5ilrqw4D3pGXRIK414FjDtPGk7cDce96OC3ig71hSxvU9u/t7+ts92Vi+ORyJORLOR56miWmcOZ1HfBZsKfTnQvE6HoobENdhOs/r3Suk37AUR186ijEMm1uFwFhHd/PA+8cDT4/PvD+flRUkRFynYyFKp5RuKZGXRKNyS1Ngs+t4/foNH71+w3azYbvdaEUkJh7fBkyaKXNiCRMiic50xOVMjoESZpwYrAjeSBXk6njz409ADOflzPHpkcM0UuLCeVw4T4G354lce2xi0jSrFctm2JOHjkhGbEZ8Zl+Ukct2Pd88PXNeZmKJDNZz0znu9zecx5HnkDjPqvkSc2R390Dfb/FDpwI8ztHtX1GenjiMZ7wXYslMcWKOoUIRLAmjfSAIc06clxknjm3Xs/Oe+XwgxoD0lg2ewQ4cv/iSsCycT0ec92zFEjE8Hw4clonpFxMmZ2xKjOOkFM7GKFTKCmUJJEkYY9n0W00+xIhrfJ4UlnmqRm+5ZC6rW7bClzLEqONVBCW9qsw+LiutdRFZWexy0b9bcoVWKK7fVYctZ7VLmUKkKG212EpFm2sSRgNBRLPnDSbaoCjGaubaiDAvTdW5EGndH4rZ/z5c5X9Xt6GzKm5oDdthoJTMPE6kEJECm2HAW4WxpNqsHVJcm2yNdfS94LJWfNsC3fUdN7c3fPrZJxhbSHHRrCu6/JtS0EXBXHzZmsAqImQpKlJplFbSVBrkVJM1yutPFQ9TVfMVlZQVc98qBhFUz0Au7EzNR1c/pzIWlZfBxVpVQQkzWuCjf7pOoF0dcPWeILUPEq51Xpoz1Pa5fr1WDNrrq8BC2r/r66hOUsnfro5oPJDXyGJlolpdo8u+a1xRHb9cct23Vg2rZkZ9QBpgRIVKpxj1PovQmb2KlTnLmLTXJS95Df7HaSLGSAwqoNeSGTGqEnNxHr+xeO+52d9htlvwe0JSm7Lbv1oFAnGO59OZp8OJr48nZegsma4opXLOSvGfgvYXNvhfxuC95/b+jo8//Yjtbst2O1SfaeHtV0kVpLM2M5dSG5zDpD17YaoBlaX3PRhHsZ6Pbz4hlcLxdOZ0OvA8z5Q4rz2iz+eFLA5sz5ybFovH+gHXORSFnMFlhqqqfmMsx/OZaV44jiO+82yc43a7ZRxnDnPiFHJVpRYG5/H9gO09fdfjfM+wu8W8P3A6nvHWaLJxGpnGAyIF771yXxYIobCkifMUKEXY9D3brmOaz9r7YIS9cexMxyE9Ms0LTwfVdOq7gSKGp+OB43TmF7/6Bbn1Wc6BnMCYToUWRRQCtSg1fNf3tfp1CfMN2lMpFHKM+n4BaiW89UIo3Klq0bVqQ6kooroOSUnQoJC1v6ZAZZkr61hvW2viLut5deKVmlQ1yOpz6wwqq9i0oEyJoHO52YBcjy81ga99NH/72vS9A42h9Dhn6TodBLkUtljiqHgzMRbrOox3jKfzmvkxptL2OVHp+FwI2WgAkpUfXimRtSqiZWVDYiFUYTSl0c2qmpqFFLMy1ZSsXfUmqBiJV1xgioUSQbLBYqsDoSUfqfCs3JhIBOVUFipLiBoi6zuc6/C+52Z7S+c6vPdVFToQ0xnJEW8KP3p1x6d3Wz653THYhDcJTyItR/ICIUZO08gSAx1o1jwtxHkmRh3AU72HsivEQ6AUwzRNTNPC+TxzencgLBET8pqJEAE/dFjvkc0GfE/pB758fOScM4dSCClhS2TrEt7q4Dk3XQ9Aqi7I4BVO4AFPwQEO5elOFdsRi2IkH4/n6rQqFWvK2ujqRPGCtpKm2N7x6oef8qvHJ94/HhDfY1yHsTW7A3wzLsjySKZwmmaKcRSxjDmRYiYbi/E93lm2nSOZQHHQ3b5i2N3S72549fpjSJkwTXz59TviPJHDwu52jx8GChExGWshhplUy6iyLBhjGJww5YmYAs45dvs9+5tb9g+3ZGBcZp6enjifz9ylW1zXgQgxqVNfTMZ5wZiiQWSsSuXnSat1Yri7v2d/+8Dd64+5uXtNzIW3j+8YjwdOYWE6nSjUxWnn6G9uufnoE8YEiKHrO6yGdGxMURXY88jyfFQ8Z4lIhVvkFAiLYZTMo7xnCZF5WTDG0w0Du2FLt9lSnOcUoz73bMjLREwJEYu1PXgDQ2aaVCNAkyCFbAxZLFLLt09PB0Y3MjpPIdUsPEynERcEI2OlT5xq/5NRPZJSIEZ6tbQo9ES/Z2eNlvuBzroLYQRZK4QxasdIrRZoBbegBIXNgWnjUTNrClutOWGBkgMNx1+MmlpNJemnqf2uMJOc1yymKklrJSXUaqkglFRIRA0sqNCoinvWTJdgqJS+zf4Yu1ZUMRoUvXA46xLw2+1v2EytVnSdzvdciLWfTBMxCnHNqageTtZmy9IcUVP7Fiq0SMkI1K7FKjBpjYp7Dp2DYJVkoSoeS5aqml0X4KyLdutZtMbQ94Ny4BvLvIRaedAFSIPbtshflR1KY3u5FNREXo4FU6t1l5zoJZG5OtRwVX64BBkfuOmsu61+Q4tSrhwJua5G8KIa8SIYrpyo1zApud6nRRtrReOSHV2LDqXFbrJe+uV1C1nadTas+VXzarl8pjFSYdpmrbynrIkzTQBohtmKJVlNVs0x8XxSAd4MWOsQoyQiqcKYBucxVQHaogiN/uaW24dX7G7v6IZBYS4h8P75kTTPpHlR6KrvyNauWe2ctb8mpYDBqd3Sp48YYdhs2G427HZbuv2OTGGJM0+HZ6ZlIqa9Oo25aXyYVU3bWSGFmTTP5LgQp6nee8N237G/2/Hw5hM+/uwHxJz54osv+cUvf85yGpnOi/pqWLr9HW7YMezvMcMOMap51lmF0nclsoxn5vOJeVnUT0FFARrTWkiJeQ48HU4sy8IUFkznsOLpOo/tO3BWUQc5U3LCRKXWxxqwDukKTnaEeSSmWukQW4NhS0nqd71/PnLyM0PnNaFcMsYIi5w5hoSYIzFlpjnoXK4iexrAV5hZpb7uvEOqblgTyDONaIhCKUnJX7LCpVefso7vRqa01horuYAxhlwKki7zScd+NQTVTrTgWhpcUa7SAnXiNOY2QRQGvk7f8qLnQqUZaK2pa/WtBSLQKunl2mysVfs1CfA981/fX7CvGAwOIx6MBzLGdWAiFe5Xs+zKB52SlhidlZqRM9XuFQ0Y6m1MuSjlm80IGsUXFJKQ6+BcG7su3xQx2thqras4SpRasNJqNLYWNeRmdUpqFwiNvm5l/mgl8/q7sXaVXx82W4Z+YNNvGM+OGCaWOWIRBiu8ud/zaj9wu+1wJlXiVxW8yamwjDPTfCKkgPNDFQSKxGkmhKjq37kg1jF4FWGJS2Y8j0zTwjTOpOOiLChclfid4HqPGwbydkd2nmwdz48HTkvgXIpWOgR6W+icxRshOk/KiZygE61iDBalgS0aZNiizzPHi5GYY14xl1MshHxhMCmFqhKpjfNYg+09ZjOwPB84pkzXa1bP+IF+s6dQNNN9PhHCwrwslee7NuZTNBttLGIdtu8RY8Eb+v0tw809w/4OW/VGxjTxeDwRpxFnMl3OWAo5VOG1klRVPgekBCSrUE5nPMkUsEI3bNjf3HL/6hU3D7dM88RpPHKeRpyz9INnMGCdreeKgIplGZRMQJI2FuZY50ERLS9jcH7A+k7pMI0l5sIS9J46pyq8rjP0my03d/d0RRVB+74jLAslRbxBtSiWRCqmlpG1gbplLnLWcvTxPJJyYklZlW5dxzAMYIRYkhIQKK0aOcykpJk9VzPAw9AhVliWiWUKa9Z0zUIWmEPUACIWbeCz1WGOGVMWDArzSikqCUOFJuSSKalgK01eKUWVs0XZfrJULnjT5qsSUZSKjW8KAaVmWqvl4GqWVwN6oZLN1cA38aZq3KpDp83AF+WB5ti8yBGvTpJIXQRQGIMC4osGFc3jK4XctB1W6FazM6Ve9RWTnvDS4fxW0PHb7VtbE8k02pBfJGtlutr9WNAgUKpeS3UwpWUBm3dLax2/PJMYa6NvVvIG7yzBVMjclZ9rrMJucq2INP+8wbK8c9rzAxd40/pcyyoKuTZat2Cj/jA1yL+OMwpUcVguDv9V0PEdN2r9eR1YfBhwyIt96+t6f+TF7+3tbwciL4OKq+Dk2kN6EWhcXcCHl/utr/HBzb867HLbpM71CnaufkCp7D4FqsZIfd9o0I9zmH5ARMhhYYmJaVlIGbpeVDeoJi4TuUJ7HLhOA0tnGXY3DPtbtjd3YAxhmhiXwOF4Is0zkjL9ZoOjjoUqAVAqXLXkWBmZLw3lxhj6YcP+5obb2xvcfsu8TJzencjnyLJMdE4DCyO6JigJggZZAqu4X65sZDHVNaOLDFmJRHw3IClhrCMlXZvGJeizNxbre7phy+bmjv7mDqmaQapInuhyUJ9uXoh5ppRS2d3qUzGNplWr1yFFQopIhTbazis9bG56RZo8IzT2QMF0HlMcw3ZgHj3LMnM6nRR2m6U2XmugsISo1cMKpRVT51JMBBZApRRizFURvvbSNY21Wp0Q0eq1lAtjqjr9V8xtNZBp/6p/v/bRlgoMXkeolBVWaQo0xihaQqGtIVJ/YmjEFy2Ab91WL1FO1xDF8iIBcA10UtjmxU/WIy/rn8Im6714MTWvfq8Q0b9t+96BxnOKmFnhDZt6cSEmwpIpS8KlSDlM6rA4T0ywLAXrMjYr5CpHpYKLC6pY6A3TMpJDIo2Z3d2+KhR68A7vLDkqZ7Q+WHVWN6+23N9/RN9vGIaBcRyZ54nHx3cs08gyj5BVYGmZF6QYCh3FVGhCoepwsC40K3FJ7Xj31gGFtMycpyMiRct4VvsVNiJ89uojXu16fnDr2DthY8Cmo2LbS+b0eCItC3mZ1Xl0hsEoBWecE9MUmeaF5/OIGxzeCaUkjt88c3o8E57TmqXe5loZ6p02+hlBtg7ZbinDwNLtmVPmHALHtDCmSASFWYmw8R3bYUs/bLh93TPPM+fjkU9vNmzI9KcDElQNe5OSNruLkMaoipzGMIXIkjLLrEFGaA4nVH0obWaynWP7+p7gDH/61efkbsOrzz5jYEPMQsiWn/7xv06/25Gc5f/+H/1HPH/+a8IYudvsub+7wfSWx6cjXx3fs0Qo1iNLYn/b450nLomnw8i7MfP1n/xCqeKWiXJ4wpbE7eCZ0oLzFmMdhylwGBeWsoAsCDPGOrqu59XNLft9phjD7ccfMWy3dJsNz49veXp+z9uv/1rZmrqO/Y3D+4TFkeczJcyQMy5pkCaxYEQrc+IzpzBynGe++MufYf76K9xf/DWvHt6AGM7jxPn0zDwnjjO4qPOleEucI/npyO3DJ1jvtUqXtZQ+xsQ8R8YlETDaADrPWK8L3u7ujkLiXDKn5bRiyu/2d4rTzROPjweQTO+E4Dqc8wzDlhQTjki/v+f2/hX/yu/9IdMyczwe+ef/7J9xenxmOp3pcBVuWPB9D8YwW+07cc7iXbdCFZx1qh0RFN4iQAxgUkBSJqcLlNJYdbJDyVivdmZK8+pX5DRp4mIQre6hRtk0o5cjUpyaTGNpzWuSg87xqn6O6MLZAoIcU8XRi0L/0PGMEXJLQmQtQ8/N2BtdaFwxSK6VCIoykFTct0oiFHVsjRrttPZzQCrpkgmvGOxQtMGRApISunB8z9TR38XNGFIuTEvQakIphCUQgmLF52VaMfe6ZhcS2rvxwmelKDTXqj5CypnT6cQXn3/OZx/dK6kDBakZSwtUWhelfzZAMSyExj3AZtjgh54FYZoDp3lmaiKQ1SHS01wCTU2FXr6e0DL43/bDL/07F8+/0bK+2PE7tutKw1WsRXNU2oEXIT25HCcfnEdevr7Wvvjw9YsLk+v3L32T7dteHs1VZvVysksQI+2eVReoOknSvDBRqJJ1boWUeF9tgFgwDuc8rut48+YNYoRlnnkaF+IcOM8Tfruj3+3ZdT3jeeL5cGBR8jlcTZJascyp8NW793zx/onT6UyYJ8L5TDqPmJLZVEa+fuiZU+I8njmNZ2JSZXFntSfWO8tmu8W6Dus6djd3FSK15ZxnTtOJd998TY4LvfdsrUE2G5z1zKezEsksC2kYkCrG1g0bSteTxTCfJ8Zp5v1Xb/nq8cDPfv01t3/2V+RSODwfOJ8PzMvMNI5Y57Fe8J5Km5xxWfstU2GlDk2pkoWUwhSDkiSkuCaad5thTYQ9PR3JWoBQ6L21ZOBwPNH0hrqux/kO243Eqrn28Po1t7d3/OhHn7FMI6fTkT/9kz/l+fnA+TTiXaf9K5WCuEkXuM5jncW6S18voAncpikBlKTzVwN7rWhwFTw0uQNa2a3qx6WgVQyrw02DgJIgt10blO8ypku6dDqU/DKIULSNrJV0FcHWue2svUpcoZWfcmnUVrhwrtdziUJsXdxK0cCT+iwqs0INGhrwuH1uS8oVWnhDYdXR+D55sO8daHz85mO9mUUXzFwKxYIdAJcxKStWzBqMs6ScCUGhKNrfUGiCC2ZjyFGboueLj8EyT+Ts2fR27UHQIEC777VHQvF4S1BRrWWZSZVDeo2aMYpPTMogdCk6GZxUaI+zGnSketeNIM5gfYcYQy6GGJWCLI4jSy7MqWBY6Fzh1b7j9cZw2wtDWfC54CiUdF7LZ86C7SxiO+U0FvScpZCkcK6MTcZ19H7AGsPp+cQyLZSQKoWvwsbspsf0He52h91uwFvORjiEwDkmTuPIHBNTCEylkGpDWiudJ12BVaTQO/qS6fuObh5xJbE12qsByuKDGDIodR6FuchKHRdy3de0wagDORihWKE4S8hJG6yGHd1mh+02mMUQl0icI0+HR/q0IH1PIoEziOtIpmOhw0hPcIXkA9F0iHOUzUC0BsRCgJAWFknM06gc4jmq05oSCxFvElIcUQLzeWEeF7p+izUDXiIb5+rCYBHf136hjlIMKWSceHrbset6LIW+8+x9R14WzueJ80Gb4WKMnPwZJwZSxjmtOk0lMwssYggiGMmQA8+HRygwz8sKtVInOZGTYrvn8wmMI85RnZiclEmHQokzeZlJi6pka6d2oEisNP2pogGFKamGhK3QjlQzukX0/VQsnVM9kpgL4jxDt6HzW4x1HE9nQlgIy6Ll522PkULnPA0VaZwGVhkqTZ9o83sBQZ0y5QTPeE3NUuyl0pBrFkVZT2pGOJeGaKwBQ90yl/RNzY61DLKAMmw1562Umhm6bqhuxniVdtPTitR3rrLKZK3k1mJEqYupZoKuKm7VxjRTHMta9mk+jxrurKFIKtWMrwuInjPGSFOxbvDI9vr7CiP9Xdzubu9qFrHez1wQDM4mbfbNFw0EI5BzIqalKn7rsppXuE1ZKUBJynX//PTM4flZyTGcQ0qmxABX+gqNnamUrEJoTokY/GaDOMfxeGaaZ8ZpIZnq+K7VqsLatFPaMn/l1P/G7YMgo/32nUGprFWGDwOF68+RD9+RS5D7YZBwFYtcnH0u6y1y9foqiLjadb0mfV3X7zXmunq/TSK43Kvmtq2RUg3O5SrLXPdpeURl+tTKr3Ne2QjRJFoMEVtgjlHpvK3Feq/Q5CUg1mEqfKqIVsfUtbEYp8Qa1unfUy6EHFRpe55Z5hlTe24SME1nYgwsOTPOE/M80/e99klWcgNpyRDjEOsxXpkrU4F5nMghsPEe36mg5L7rMLmQ48x0PDLNC3NY6DulqSVnJeShMIVEyAo0zRSWEIn5RIya2AiLrmtkhaeDOqbj6UiIiSVm+vOE1MCN3HoIZkpYVBsjpUoBnqi4oAv0rajYJAiNs7UJPqfak2ONCgU677Uaby3OK/VuKcpAlbM+467r2QwRKUrLq8KqpvrPSpZgnfZyiTTnOa3j05jLuFuNduOYXoPcsv5JIVD6fUoNBlZovkhlLGOFyKpnXysY67C9rEkVz3eZhVfj/eLKC02/qSFxLn1W5YUNbKOfWjHJFYqg/SNy+Xv97JzqGlWr6bldU732y9pULtdVmjL43742fe9A4/Wr18rhvOjgTbV50opT/umUMU4F4awzasyjxzkHopk7ieoEDHjGCcYprtkOEQhBpdYH21+yKFkdsBIjxYg6y0aYp4lcRkDWyDSny8CLUWnEmuFpsC0nqsBanCBZI9ZSSmWtcnR9j7GWEApTUlq5NE+KKwyBwRe6reXNfs/9YNj5jC8zLmVMyaQw1gxywtpBJ0cx67XNNdCIFMYYyRms7fB2QHLh8PxEmoOyXxijEDIDdjfgb/ZsP37D7s1rpO/5JiZO798zPx14PByYloVpDixkSsX+Nb7eNgANMBgD1jJ4i30+40kMvSeQSUJVRld4QCyKJR5jIWJIRRsTS638rJAWBCxkK2RvOeekAobDDr/Z4/qBLLrwp2XhcHxmTgs2DOQSFeLlO6JxTMVhSs8imeiDlmw7j9nuKC5TrGArDjPXcjMlQdEGT2IkpEx0qO5ELoRJM1Pbm1f0nWXjFTZWEhyOqbJ19ORstUoXA6YYeuPZdwPeFPquY+86ns8j4+nMeJxIVbDr7FSEqeSC7zowhiUnFiBYQ3ZKKFBInM9HrewFhXPlkqsIoEKvMplQFN+/HI86P3LUhlKBFMaVwlOiKAtSUb0OZTLJWK9sTSXn2ihr1UY0KkdLbWQ26yIWloS1jm6zxZmBgvD8/ExKgRgWOmfIQ4c1Sv3pKstPY8hIlKqUDpTWVA+lNqFaI7iahSxFVjXZZC8ZFFMzOzlnJJvqINrVISyZuhiVKmzWHEMdhaY56VdG86UGwGqyW26GBpfJUBeMi+GUXFbcs+KFS9UVKFAau4/CQxNXjirV7lwtFopzrj/XEvsFMxuqMdc1pwVqVLrU35Lc/qbt5uaGlJQ8JEW1Mc7YtnaTK3VpCzRSitionPRS512utJA5pco2BqkoGcnxcODwfGDoPL2vTDNJ1d2N1HPkFqwo6Yjzjtv9Hpwniui6OQemJWA6X6thl0VaL+NlAPA3hRjNGbkCFf9Ne758sTr534o2Lj/kg0N+UzXjKnpYA5MP3r9EGN8VbFwHONcBSgsa9N01ILv+tOqwlRfBxtW1VJqfNT4p2nfTKq22Ou6lQJwChQgps4QAohAa6x3We4xzCvuRy3lS7TdDDN53DEOHdQ58p75HjpSiSb4QAq4yiCVgGkfEzNrkHxZCDOx3e/q+Yzt0xKAQpJCqQ4v2EcVUIETmUQlHtl3HvleV8V3XKc35sjCfR+ZlZg6BqdKrlqwENggsQddIhY41qO3EsoTVgc6VmcqaRpJRmOdR2RHnhX6ckKo6rc8rk9Os/Z1SsFWUVtfn+niqGGW5srMr6q9VdbP2UXjnsdZVNieFT4vx2hcaE+M4klMkVpG9oeuxGBUlXPsfdB2IJVZmLR0ohXwlxqz76p9akqiN52pEKCvD4BqHQIX6o/0/uUlAyNpj0Rz21UkXQWhQ3zqMVxtwnWDQ4dvu22Xol/X+yfobl7Xkik79elaVlkCrDFTt2LbeaJ/gZY1a929JsJDqurzOJj3H90yCfe9A43R41q9khM5bSrG6WOZMbZDQG5Yic20qDVFLSa3UE8aZFALEXB3vqM2aYiliNZIFxvl8MWxLWpvzvDjOx5F5/lx1uIB0JQxks0Z1OWvTiEUwrqPYiueOFQsJlKxOj68AM28s+82O7f4W5zvmAOPxmUmOkCOGGRPPvN7f8Grb84PbjlsT6YnYcFKGCCN4a3RAZ0OcY83AOjTxXIglMc0L4zTTm46cC+mceP/lW0rIuKRZs94PcG8pzlG84/VPfp/Pfvd3+Qf/pX+TH/zhTxnuHjhJ4bgsvD8c+Uf/6H/Dn/zJn/Av/tk/5XweoRSGzpJTxInl9cNn9N7hrXB6/zU2zHTLzOuqc+HCCVMrFjEmotPmyM2uw1EwOVJMR8pwmgMxVZVoIFEIoFWJTY+9fyAaZaA45cxpXpBQcEHohw2fvHrgo48+ZUmBr775Em9hu+k4hYXn88z7UyT7I6HAlIWH/T27u1t+8pMfcLNxDL3j5u4Gv9liXc9f/uwX/PVf/4I//Rf/lLSM5BiYKQgLkzOqo2J6NsOG1w93bDc9223PV198xWk883iaicczGaHvPd6AN4XBRjor3Awb7u7v6fueTixdWfDF0HeGGQ2iY6WaC7kQjs8q4JgrVbN4hkH7YqZpWg2RWC2dihFudvsaCOjCoyWbwHa7x1mHMZ4QJkqK7P3FkIZ5JKVSFUjVqE/zCNJjnGXjulo2t1VBXVRz5coELEHZjUIsmBww8UxKo8KCjCGlQCmq/Oos+I3lisBPw0wB78yV4anwDQEp2hDbWUcrQRdJa+k1Lyp6ZxHVMilgxWjvVsm0jrUiQmxmsGhA1bKdCj2pIp+SaaoXIkq7uHJ+G7tylcdqC6BUuIw+j0t2WUi1wdxUo0oz5qLnTkmvJxIJWZnubK4aBoBU25VzJuS0BkltGWh8/oJUzPTF5jb8rn6z7yeM9HdxC9O05vicsOpU5Fp9UnriXJepSKwiqY0ekhbclqzw3qIBJSmyiLCMI+/evuPh9oaPXr8hHE8wL0zHozpZpZBqMO2csLvZsdlueXh4xbvjiePpzPE8seRcNVYa/TFIY0C7rN/Axfn6riDiuwKBb+17HQBcooXVifz2ueXlOa+rE1dVjcs5v+P833G9366UXJ//Mg+A6lSV1Ulbr6A5RtURbNn+VC6/t820ig1Q7PV16/2OKZFCfQ7e46o98H2nxxtTe+0CISRNqnSO3jvG05HT8UhKtXE/w/39a+5ub/nhDz/j9nbPsBlw2xvEOTCGL7/8gi8//5yf/8Wfc3j7NUsIJKPZdu1JUJjP0A/c3N4zDD3bTc/j0xPTeeLd44GQj6QM8qsvcc7gnOV+Yxic4ZPbO+53G2XRRJjnqCQkCJ3rsDW7nzMsSyTkWX2OcrHPpsL+XLloBQkwJoWAW++0f8Fa3BJrYFfoRfWijFOhuVwS2II3BmfUfudU6WNrEiXlUisUhmE7VFp+s0J6DKJsgBXmU3ImLEFJNqzD2EQphufzifdffVH7JBt80bIb3AUSVZJWcETw4i+Jp6tx2CBWztrVcV4V3kuuwVbtd6mWeE0GtdBALmNaQJ351iPDJf699N3lCiVrgXBjcrrMwQuDHJTS5qCptkOfX4NJrYF4vaYWZJQWPEQV92wV9XYD1K+uxZZWTaqyEvq5lz6TFmDouqs2y0jzAv62VMe/TI/G83vNLlqj8vb1oTRYU45pjQZz1sadGOO6qEZjiHPD7F0aZhBWjnHT2J/KpZRtywWnmavDkyuDSEbA2XVipFQ59UXhJ9Yahr7DdkIhM57OVBBvLXddaPkyhSUlbIykyl5gnTJZSYx0AhsRPr3pebjx7G1mkIgvSXn60cjUpKITLETiqI5LypE56qQ1XadqcbEQpkAKhTAWUgDJDtcNbF49MNzu6V5v2dzesH+456Pf+X12r97A7pYvDyfKHJkMFKsNxT/94z/GOUeKkb/6kz9lmWZ65+mGLZ1xdN5TSmJZIiVEbEi4oP02gwFnDLMtLGRS0kSNs1UJ1RickoASU2EhVNiN1AxgpQ63hoJwDoFZoFhHt93Sb29w/YYyq3Kp98qPnXOgxKy6IDHV6lUmZVhKIYvBisVLwZEhBlLMBEk8H6CPCecXiDOSAqbCdErScZes9kt0viMUIeXE4fmJZfEsS8c0jSxhYUkzIYnStsbA4C3SWagNYAaBXIghMoWR8zSrKFYWSrGI8ZRiSKUwhbg6lKAUmNZknFWms5xjbTozGMyKg1S4lRodO3h1yFNcVcjVcFMXCFUU73yHGG1sjQGEpNdjwfeaXbOpLQz6GS3DV6phXHVhKlNJyaWKj+m8KFmq0ayGUzQrbEQhKY1ZrvU3XCVpV4eoNI2KyvxWSJQS10xKM9TXDdfNIJb2Gl5mLAu1LF1WKs1CJYyqtkmDEz1Or6tl7/RUuTQDD6VCvcyafdIPbIq7WsCo15+a3dLegFI0nxCKLrY2S9X/0e9Ova+a5GiYXFmNuN7Py33TR1MXjDUz9bdnjf6ubofnp3qrzIX6tWiDdckKf61vVnHWRAhB+4bq+CstIKzrQ4v6Ba3qPj8fFHZ6s1dK0K4nd4tWNur8MMbQ9Zeq+GmcOJzOqjOTVZVbqShldUouTgpXQcYHzvmHjrx8231/ue+HQcBl7/XzLn/8jnPIi/N9Z3Hi25f2rU3+th24BBZXb7T/XYLxdh3IhTShfDvgalfdmHcarXU7Y8vSapCg89Y67dPragO4IKotlCokNwRK0oAjVCrckqtis2/MUIUcAzEEgjFEzgr1FWGZJ9XaiIFU+xWK2DVdba0KC6cYOZ1OhBAIYeFUiWCWGFVcNkMmUop+pqVqUhXtLwuVVGeeF5YQK8OTOtyxaq0sMRFSTdzWAEP1fdJ6k0ydQ9ZYnLfa/Oy1smCt9ju2p+OcVgysFe21Q4UxvbNKwZuElBLWGVxySnhQLurlpT1EuaBSSm7VhUa7eqFTbdcp4lZCHVO0siiGSt8PUmGpK72xqJB0ynm1v+3+GylQqcj1Asq6rlCTCNfj+YMVqjr7ssbpetgl2XY57mosXq9jvFyPS/t7C2hqBV9aYq1+SKPhLus11z6KGmyIVKIlWvWt+SR1XS2F62pEzpcqRrlgj+v9lvU62zy7hKPfb2363oHG26+/UPYM6xj6jiY9nuvAVX76GiWiXzqmRExppZJtAkomt2vUgSdGJ633HYhmHXKtlDgx66NIaYJskGKJsYBodG+aM5EixmkTecgLvbfc327Y7LeUUnibkpYkU1IRmAr5whgCysW/GIeLiW3fI1bohw47jewtvO4cv/9mx+3W0dkZmyNWlM2ppEJOBXImzInltLCcCylk0hxYcqQI3Ly6xUSFvIyPZ8JSWBbwfovzA9zec/v7f8CrH3/G3Y8/4ge/82N+5/d/l48/+wmP55H/5M//kj/7f/+nPB6PBAt3d3fc3d/zb/wX/w1++OlnvLq7Y3k68PTuPbbA6/sHet8xHhfOp5F5PNOHhAmZfsnsjGHrNJN/NAmThDlHnBc6L3ihqoQ7QhCWnJhLxhZLLFrCbIuRuC0L8HQ4E8Tjhi2ffvTA608+ZXd7z+kcCBULO0dYQlbneQrEaYEEUvnClmXBWsfgDVsCPo7Mh/ekScDAeY50fY/vO+J8JozPOBJjCqvKeooFb4T93Y7jGJnOgc9//SuME4be4m1HKoU5jsRsSVnVR812w7Z3GhQZDTKWcSID749HQtRzzwFKcRhxJCxLShynmStMBpIThgydJeVISoGuc1irhAMZLUcaJ1oato7NfqsqovOMy5rp74wjBcOS1aL53rPZbZEopJCJszKd6UTbKa7YGpYYtRyaM96aS7ZijQKaQVcq2FIyKSoVsqlZC6yhFEMuASsafFoRUomkFJWy2LhaRm5QpWaACqGEmligZoqUWSUVhVAZkRdOVsustPyaGt9qJIWV8UO576Vi7fVcqSjsJecC9uKMpKtgI5dWEVE9A13otWfFmIuhz7kJeVVRtJxXVVcd84WSNasTS1nVvN1qBYVEujhL1XAb03Jjl4VKs0QXw26kNajUhfZDD++327q9/fILzbZapYduKtMNDpXSpXIBOrZSTCs3/AqZgPpexW2jwWLMmbffvCPOM0PNKg7DBpNVfyFHpcy1zjEMA/2wIRX46t17vnk+cpgmgqDMeZWqGa70MKjL9RWr1IdPew0VrgKFK3TEtwKPNvBfOOMfVDS+tX0YYFyd7OUhV5929fnlxV+/40tcZwquMqtlndMv328nldqoSrnAiK6vYnV7qt1pFZhW+Vz1BGgJBlYRwr7v2O33bLe7dY4u05nzeWE8HVjGMzGEau9KtaOqBt11PVYgx8DpeFT0gHNEsQp5LnA4PvNcSWpy1P7B1phtKzokTgvLvPDVVxPWKU2z0v8rPX0pLYFTsMYzdI6Nd3gppCVwTjqOQ0hMS2AKkYxZmRuXoH7YvCwa8BZlSStktSvqzVJKxhkL1mK8pfPaNG5cCzIsQ+uXq5l/kYIzIEmTtZuho/Ne/YXolUq62s/mDHuvQqwxN6jo5ZkL6m+APjd97DVMzOpge6sN19aLBh3rs9f9cquEV3E7oaq91zWi5uY1uNCub9WYgbWi0eyFXA3scnWRzcFPFVrbHO8PHfhWfRNB2craLCiNLeoSaCh892UwvAoJr6mpy31sybhckyn5g4p4zplMq45UaLFcYIgrzKrwsu2p6L28Tt6UtaDeNJ0u8/g6oP9N2/cONPKyKB7PZqYUteTkbIU3FGxR7GtKiWyUlzpnqrKu3khbF1DfBD5EIQeFGpVTFXdJeKPZH5uVFUK/eFwfgrFqmFOYSZWKouRc+YvbAM1KFTv7NYpNMbEE/S4igljh9ZtXGOcIQEiZJUfGwwlHwpP5bLvl09uB33u9Z98XrAQiS404CzkkiIUSC/MYWM6B8+MEI5SYyVGzt2KFYBTe4lLidn/LbDxnO3BEkM2Gze/+Lr/7b/87/PQf/AMePvqEJcw8jgf+w//gP+Qv/uqv+I//8T9hPB6IMWKc4iO7rucf/rf+IQ+3d/zw9Rt+9PCGbSzM05l973HWMZWZnCEk6KpWiEFISyQn8AjWFowt2N6shiXFoA3OSSihQCz42CExq4he53F9hxt64s3Ac0ycjhMhwJJOfPHrX3M4zwz7Rza3D4QMS1SVzuV05Onto0IQYmC7vaHLhozlJx//kKH3bL1hfP8WR2QQj7UDSyr86tdfMoWRJU7YkEhpIcSJzoKIx2PxTqFL3jo6X+i7TIw1C0Omq6xCbAfmWtHwpuej1w988tEryvmZcD7x/P494kYyMMZATIaYhSXXPH9BmdNUzWc1ZEImS3VSw6X8KlnF5ra94bNPf4Dreo7HiZiUtnboN2qE+i0lqjHIIgx9R58rDZ+zRGuR3uAR+mzwlUUphEXnXM4seULdpUxs7cpS6IzRkK6I3gMxOHG6+JSEr0xOQgJL5aDv1TCjBr+IsnUYWzBGM7oxCilXw9oWl+IrhWC8KJxiL+rH9Vq1SV0dbFNL76UoVbC9cpDavGv0pAqcVqYgU41yEYFMDeQUcqUWXlYFZSXSqAtYTZQURGFvpZXZ64JhDDloD0Bj8bgECnp/2rXnqo5bcoGWASxgjVKk2nbJXBrdpfZVtSxRg/1kY9bXv92+eys1mRVrNVNqhtRW8StNfCkcoqbz1lCwwAWnQBuOH3Y+CE/PR6bzxHg8sXGe3lm2u/3KdrZCQ0rh7dORKQQeTyemlIkC1nc6RmjOcMV3v8gaqjOzBj/1sz906K9hTevP7woE2oEvjuXqby/35+XutADjGjuu7179Xi7nusyK65N/8HsNmluyYE3hXkGeXlzDd3zv5u+Zq781O3B5fcGcp5Sh9qjlomKrhcTxeKo0rppAUMXpxHg+MY0j59OJ8XwmxIT3HV3Xsdk47u5faf+A8xqEWItzjmUJnE5nPv/iC6ag1Qgdd1rJ2G56TFGNIGsqYsJZus4Rc+E0jZSo2fmu7+mMoU8KZc6l0HvPw8Mdrx/ukelAmCZO45mcNKCKRcESoRTGSvqhWmOmwgYLjcEjN8cd1XvB6EwRpz0p3XbD9vYO13crnDqlRN8PuAr9WqYJipKfhMmTohKX+M7TdR0m+TXx5Fxz9PMq5BzHpKxLJa+JFUEr41IDS1N1RlrCJeeCysWq4vZaDV/paEFMJmsJoOb8ilaWW7O0rFmnlXlJx1FbjEoNQMqqUfmiCiEgmdXRbxdxsdBXMFcjdb+yOvyXmaGSrG3dKVArD6oU32QbWgBxjfTRj9ULagmwliRpF7mSY6yBgfbdrlZDbN21rHPJWFmvpgXthtZMvt421uoHDUb2N2/fX0cD1s76GFLNyjVn5NJIU7KyxxR08V9XWV1WX5aKq8FZI/akNFvOqgp5y0yogqHCNXRBKeuD1Qzp5SmvOdCsOgbzOF8GqwhiNOv18OY1m+2O3X7PRx9/ivOeSGFaZpZl5vndN6TphISJh83Aw03P3b6jyxMG1QSQpKWtFCJ5UfXQ6TgTzpF4SlgF8Fc8fqXRE0/GEMWw+I5JPEfrmLue4eGeT//eH/Hx7/8eDz/6EYfjxNtv3vP553/NP/ln/4Kf/ezn/MXPf4nEAGiZMuWM9x2ff/4lDuH+kw1v7ve4NHM6Cr1XobIYQo30Wd0nfSJGKeqWDH0TmJIqRGMoQTMgiUiOel9dksrkKLihw3Qd4ntwPd7AZtsTpqwUuHNiPJ6JSbCuJxZYUiLOM8ukInkhahO3rxkWY4Sbmz37oWfXO8454Jzl7v6B5BxmiYigmRRnCNMZUxKDt0CHKYKtCu7W6oCzVvDe4HBrCTJXrL0V1aYzRfC2YEWbq3OOpByJORCXRALmlInFkrJUsTadwMYo25KjletYg91SLqI/1ogKP1kLRtXsrXdgzeqEl4I+B+dqs7sGqaAOuViFWcVmcEDpha3idK3o805ciYBdJyHq3DI0PYDr7E3FtFPnbc34qGGq1BxF57ig/SWtdPuiFFsdiNIciTonQS7BRg1GaEFJzi99EpoYntKONrxrW3BKhWrlrLxVFK2s6gm17TInbfKOlW/UiBAqt3peU0ma6ChARiF2GS4lZKGKE+baUHmdhaq7XGFSLhjeizN4saFXTp5c3mvZWprhrqXs3PDgvw00fuPWOOfbQi01Syu4tVqnytk10C7Xw+z6KTafoa4ibaEuaGY5ZyQn8jCQu06TMfX8sQbKMWZO06LsfyGSWpmsUajRpqK8mJK8qOq1/a6DhA8Chvr7b3p/PeqDgOJlEHM5ihfvy8u/yId7/v++FdSPuP6+pT2P9n0o33HQd1/DxYX69tU1xjGtBNhq60Xduzqfw7IwWatZ9FIoSfvolE1Q+0xjTIixOLEYY9nt9/Rdj/f9yqx5d3tLjIFpGnFWNDFn1ek3RsBb1RRDdaqaiKAIWGvpusKS3AthNJGCMfpPclFoEEqZmlOoybVArOKBIUNEe1dCqyKgQsgiBuOSrjty5SRTqv5MvSbnFBpvK82zMUilSdXESNUYq4kuiqjmkXfVTupTWaGj1S4aZ1e2qFwypOZ0X9nYdXxePVFhvTZtOm+QodXYfjAoNJAQVsbWuluF6ldv+fLZ6t/I1Rj7cHxVS7w61pfz6T65tIRXc8Sv7HW+fJ724F057Ch8tw1xRKFmuQbHbR1JjeykNObCy/1C1G9uPUOXZahe50srs9rJaz+8zbk1aLua/+t9aRdcLmPnukr4t23fO9DovF9fh8bKkLOqTja8QTWo1Z3Q8lwtQyX0QedavsJaCpYYavRnRLnJxbIdujWihMpWYw1YzTbGqI2VKatQmT4U8MbQi2FjhWkuxBB4fDcx3o+43uH6gX63ZRg2/Dv/zr/NH/zhT/npT/8+t3f3eK+6HvN44nR45s/+0/8Xv/6rP+Htr37O3ozsJHArMz4skAJpmXSypMJyCsznyDxGxscFFjAT+GQUauI7yn4D2x7/6p4xZh5D4osl8hgjX53OfPqTT/j4d/+I/+Z/77/Pm08+QgT+1/+rf48///O/5C/+8ud88/6ZEBOYge7mvmImYTMMbDcbjnPi6XjibvueP/i9Twif7jg9vefLt0feP544Pj8Sc6nOpWYyIjC4DT4nng9PID1WLK4o04TFks5CWhJxiTUIgL0rmN5hek//0StOEY4BZrbY7Q0ff/oR+d2RaZ7J00g+L8ynR2KIlZlIoQuURN/BU6kl39MZ6wd83+E3W/r9DfvtDT/47PfY7Ta8/vgj3p9PvD888+5w4tVNz93G85d/8c8IIVBK4XzMpGQwpiOFkVICWRLWC4P1xHmrznsOHOcFSlGYEFYhTnHk+ZsT8/MXdEYNUeozx3FiSYU5e+3/QIgpYMXSGcfNTlVZY5gx4gBDrFn/toIbqxkDUw3hXApfPR4QcyRjQTQYTeNIbx0b7ylZCRWc61hiVuHBHLlk22v5OUPe7PDW47xjCWemaSQlDUoRXWz1csxVBqkSJRTNruQclf2oZYMLUAMP4xetIggazIuBYisiMmNKIpe4GvG2mMYYMVk55tUgqw3IddEwIlq5iQFfFCOapFYj0IDAGO1riQFU8VmDyZQi83yqGjSF83mqVqr2cZXqVBRtwFMIoDbGGetWA9rcmxVaJfr9tPdO6R+tSG3iNGvOp21N3bUUrY6YWr2VtaysGOpMWbV6oEF12j1ROxZjY3yUtTnvA+/wt9vV5qxdFzvNIEOutOWlwTCyampclt4Gw2mLvN5mZy1tYVZWuDo+rCECh2kmpMxxmvjm+Xl11lJq1JxFe9eKhuLiXFUEvyzftmX0c1GhP2n0qxc4BVc/6y/16Jfbi2HRoE9Xkax8cNDfCJ36jv1X1+Pbf/j29axRd3lxYX/TyG2JiGvV7w+DhrJ6FO1aqvfZ0qtiVkahdoZC7YkrWkfuhw2+6xmGntN5ZAmBaZqIIXJOJ5ZxUohkbQTOSXsVlyUxh4U5FoZBENexv73j5vaOm5s7rLXsdjt+8NlnLGFhPB252Xq1XaXw9Tdva3XkqBO7Ml2meLGTXWfxvafbdIQUmZeZlGZK1ORLg9nkJXJ4PzE+f4MXXe9CLoQihFw4TFHpauv9MVUsstvtkAK+094hGsFESw7Vey/VvokIQeD5cNB7bYxWm4tqe7TrDjEiFJxXSl+xkEtkjpEpRmK+9OAWUT+OnFXfIyyEECo8t3m91autUCMya6VbrKxshC37rsUIHXSmCtW+GHGmBTN5PVdegYvNa85VxF64eK5rbg3QtaNVGtrnpaaFU3Q91cTEy0Cj0JqxY2X1ClrlLqyQKO2NqKO+0dBygfZq2nydWFd9Fpf3GwOVQvKu7oNc5soFupbWWy2rTSo10aXRYbuetXICa9Ws3fFSmlfA94L1fu9AI4TwwkCVeuNSTto8hKyqq8ZoxtuKNsEW5b9EUGxd7z3SOe3eOV26/Dun8ALipelUjIGSKEEdUxFlFsFUHhZRvv2SWTOl4HBdRmxGnIApFBLGGv73/7v/C2/efEzn/dXDrlhdI3inkKr/wn/+3yTFQI6J4+NX/Pv/s/8ukgMSo5bqI8RzIE+R+LxQpoKZC36sTabOYt/cY4ae2G94lsSpJL7+5h1jLpwTPALnWDjMkZ8+vOKTjz/ldnvDL/7853z++Rf86hefs8yJV6/esL35hJQrTRvqpzgDP/2jP+T3fvJjfv/HP8TmkTK+54svnsjTAZMXwvnAcj7hrbbIhJyIkgkCi7cca8546/dMcyQtEWczzgvW1ZKzg5ITm11P13l2Q6+N41L48jzxbgy8myIkB4vHMPJ8fGZeZkycSXEip8A0vqOg6qyCI5XEOY7M40KMhVQC99t77u4euNnfsru5Ydiryuqw3TDc3PKwGXC95/ZmQ4oTj++PpCykpBjVOYlmCcQhbgN0LGS2N7fc3ezZhMA0j5zOzxzfHUghEovFi8WJwXcWCExhRrxWjOawEOainyHqhCMW329xxuIrb7pG+qZmVDLW1Ib5gtIo8pLSFDJEq5ktq7N3FYZcM2wq3lacjnPnlfJYecUNpigXOEXouqEGEKIN9zkxTQtiwDqjwklZKzfFot/DunXhUHF0HVjShH0yOBRmlSv7BtXNLlkbzi6pI4FcHQAu/SBCgxSVigUWyLYGEaUKJCVyKixUJtlSoVSlqi2r/CQUWeleG/Qk5UQM+jrGvGZ6UiwrbZ9WY4w28HNpyG1VVVpWCrU7Rdo+al2d03tguGqc44IHTxUiSlGMcakNeO7SrrNuTeCq3bXKQURTITe1dNOyXPLbQONv3GIIa3puZR8rVHjd1cJfygpZMsIKe6oYOm3mrrTQemAipUKK2kclAratJ6Yu8g3iViEQLQjXc6NOYs46n9ZnWKoQF7S+HCvXz/vDgOGDoINvv98CgQ+F+r4r098O+HbQ8l2BhHzw+4tTvNzj+qOvMsTXJA8rQKrNN7l6t5R17xfEEKvD0yCTsjYs670quPrIMlV1PSulbEiZkDLGOWLMxAzTOBNiIMwzsdqynC4imRhDSplpWSpMWx3pzf6G+4cH7l69Zr+/Ybfb0/mOzTDgu14dxRSw3hGmM/M8ksJcqe4tIaHjJkNpidvOMux29NstuQjjNPH0/Mzz0xMpJbxxl+SOUYbHnAJJcoXYFJZYiKstrgyDvtNxbowyolEdy1YtECqUr6zPXqjjtVaXSwtYiuCNitx5cSs5ShvjKYTV7kmlATbG1h4L/cyh7zFGkynN5zKipDLGNLZCPWGRdDUPSos91j6BF1XiNo6v0uolNzhSi0fNOnbWPoWrcVxoMEYdl239UbITDRJaI3mu17/2fa0VinL57KvPz1yc/FKbtctVoKEgHql2oPUW8SLh0N5odZxSkUFXi8Q6/ZRsRT/DiKywqetemCJtLulBhot9zO1zpTXCN1ukPYRrIUjqh8gakf2N2/fv0aiNI2siATWyIakD4GrUpIOrUZVp2bCobVZWF+qi7Sx4S3CGREZywVvBWpBKS2aNwRSzYnCp7DWtEd0YHXzN/SELRtOFFS6FUqXZhPOO12/e8ObNR9zd3n3fr63fuSRsWjApUObKJxwz4RxI50g6RAiCiYIrjuwsqevg/pa8GZiGDU/LxOM88VffvGPJhViEk1UIThLD3f0993f3zNPML3/+1/zZn/05b79+Twa6fkO3uVE63xKAjHeG13e3/P0//mN++q/+Hp/uB07vv+Dd+BUSzhDOSEqUMJGXqRoQXVBzyUQpLBZOKeMQbn1HXLTRtbiMKVIZHaBYA77gO4fvPX4zsBAJJfHNYeHtOPP2HLBuxuQJb46cxhMhzLi8kNNCjoHzcgYsGI83A6lkprhQskKPCgbvlYZWMy+GbPT+hCIKRcgRSmMBCczjqBbYqJK77TtEPNiNjpeSwSx0N7fcvn5NV1SJtTw5nsdEkkWnQQ3PxWqvUcwJl0VFIUMiZ6MOsiiESKzFd4Oyj8iFSm6VgZNq0KQ61pWV6eK7VsenoOytpmWVVFDRimAavRyKHTZilLWmKFuJcxaTWrnZqpiYaGbdWUdyOgeasF7Dd5JFF7yis5Q1y6MT3Iqs/QKlgKYRoJWZr2FPumA0IGu1DbWEW3IrrZYKCWiECZp4UMWQRK7VqFIysWWDU16b+pQRKFcIhDLItexWDZG0J6xlk0S9tpzL2gxnr77PZaFtTj6rzRZ0AW7OfSsTqyZGfRrVmOdSsNaui8jF0VSIgDbb1UijOab1eqS+rvqFq21dr63Znho0/Xb7zVuDS0mdh+1ZNrap1kcDCv1oa+Xlwec1QFCRL53n0aoDlMwlEHTOYG2FvVDHdi6rZy01GFVh3gs8amVCur7whqaqFYALhOHbAcNLh/5l0NHm7YdBx7e268V7fevKaWv/lw9+/+AUH4Yf19e1hlLl5d++66dcDlvvzRpQwHp/WwRfyrXzY3Arlr+pHzfCBrXfsVLUzjHhpomYC0sRlmkmp0gKQfWHSiYsl0qodV73XQIYo1BX5+iGgWGzwzqPiK4Hzd5O00gMC9OkmltLWFgWpVA2RpToxrTbX4VGBayDYX/L7u4WsQ5/HgkYTlMgL4sKzBWFhhZRfa6Sa+9fLoSca5BRbVTVm+hcR0tStGexVrHl+lnJ+p7ey1r1u3p+UsCJqqo7a2oGX++5wjvzyhSFmFV1u1UKVN6g0c4WgluI0a0Z9ab31DLoGhhcxsWLsdYM5/q02uC5VBjWqgIowUJNcLUGakX0l9VGi7SelbwCaTSZVYi1CpFLa6zWxFauMCgNyvRDRaCVU1vto6pJ1Wu8zD0NtnR3dZevQYMXyGOzVhd79R2pg3pgaROv1O9XB1wpcjkHF/u4Xoxc5td6a8t1wH8JUD+wYN9+QL9h+/49GlJeGDI1hpYY8lrOMaLwkM61hT4xR70wKxcaR1Cp+lISfdVrKM6y3Q5Ya8BEBt8ps4NsCHFhXkbCnDCifP0x6QRz3tUbqtoeijE02KKLinOW4gc+++GP+B/9j/+ndF0PqPbB59Pbv/E7fza8wWqqmS7M+Azn55k0RdIpcHoOLHPSTHDnsbue/v4Bc3OHvHrD23HhmBJfxYVvkuEpO35ZLKEkFTDMwn6/50effMrf/8/9fT56/Zr/5T/69/nZz3/F51++5fMv34LV7MRul/De0XWGj17f87s/+R3+J//D/wFDByWO/D//D/8B3/z1X/LNL/6MLo5IXJhPJ7o80xMJ05GEA+PIJTOXSCHyZQpEDJ/2O94g2GgZp8gYMpMNuMFqE9z9Ld8cjjxOE6fDibMIZ+BnY+EY4Rgt8+MzHI6Y919gUQFDmxMbb/HGUFxHipm4BLJ1GOfZ7l7hdx3GK6XwsN1TTOFnv/w5vvP0fYctKKtXCIzjIzFOIIHbmx373YZNd8PGeMQO3H/8Y6wbWBKM5xNhmYlx4vb+ltv7W/b39xX6cOav/vmfMx7POGd5fPs1p8MTp/OocBnXc04RimC6LbLxOHHspCMbRxGL63olO4hB54e6vGj5riAuaZbHiDr8WFxx2KZWXbQ5Veqk7jqnLCi7fqX7mztDjJFlWTBOJ/oyLtp8LobzeEJA+44eHnC1Umesikh525OTQtWaFkMUZeMyBky+QBTFaEN8KIJLpVYlhUTQfpBUlVxRUgUqYUOpGWEtr1aGKTTLH2NiSWk1cyk2jQIhlrg2a7eAQFpwIpCjmmkvpjr70HVC73v6znKeT4SQmZa8LvrWdZdEk2lG0mBsLULngK2puNYbTAFbAClko7WT9bZcYL0vbJ8uOOBSVgYUY0imxlAp6L4qOqym2rBS72qlVm1pDI2eF5wrigV3fa32VLhpTmvG7Lfbd22XBfxCbcoanFLKms1tWPymf9EW5raw58rtrc6RJhE6Z+m8Nu4OvddgBIUExtgYrFpG9iWEoin6mQrvUgfn6tLXNVWuAs6Wzb2GTei51yBi9egvv38nJOoDhxKay/ESDnU59Bo+dQmm1ii6feyHFZFvVUhaqHD58eKXD5ym8uLv+gBzC/I/+IzWOLvphuqkwhIjISZO06Sw6lKICNOSmaaFcXrUSWhN5YMDWxmTjGjSShPOghOFsZpuoN/ucF1Hv9ngfc8UAv/iT/5EhU2do+86KIWwzJxPB0KYySWw2w5sNj39zS3WelzXs799hfc91necq6Desozsbm/Z391yc3tHCIHn5wO/+uVf6/o1z4ynI/M0cj48gYZYEEMdTxbXeyUCMb5qTTis82o7UkvDZtWNqXdb++vM6iNp9UPWObFSvCK10ufwXcd2M6zil7OrcyCEmhwpVTiTWl3WfjntZTJ0XUfXK1sXBcKyrCQNTblakJr9uYSiLwOIVuXQvzeHOV0ROrTBpFO7EaC0qkQNLEquvRCxVi4yKaS1rydmPWdZFwnVSWuED01jwhmzVoG2nVOxQCPMVRAxxFT7g5VpTIMSrcZjdI0S22hX6mJUlLZYql+9VrtFtFoHVxWgOo/apG3vl2s4Ynkxd9eArh6rla2rud3+XVXdrUXZYcVcPr/C6b5HnPEvEWi0p311NUXSOiZaaU8Ma4noGh4gtJJ1hRlkVWDVXt2KQYwRQcvXoBmpUxwrnm+ufNYNqqAPv7cdYMgYQpaq3ilAVbOUwsPDKz766FMe7l9XnC58Pr3lx//H//rf+J1/+V/+3/KjzSdQCvEcOM+J4+NMWpRlSrqBrnewHYjOMTnL174jOyhp4YQwi+VsemYMsQhiNwgzZNhtdjzcPvDpR59yOJ5Zli/5+S9/xbunA0vMiOuwViemF4stBWLgj//oX+Xv/dEfse87JI8sy8j8/MT09Mj89B4rEZMifVrY2czSwdYXzjFo2VVrIwQyoxROZB7DwgOwMYaN69dnGowliuM5W+Zux1wyRxEOpXDOEDeeEDJhUSJPkaKTxOoEiSkQcgFjiWJIxpBswW0GxHqyNSRRqM52t8d1HWIt4zgxTiNQyGHRsZQzKZ2gRIZNT0yFkGBKWq2xUjieThgfEeO1iTsHzucjIc8czs9sD8+agQqB8XRimWdisKSstIP4itE2GTEdUnTBF69ZLKk83xiFBhaTKaaVP+Uqc6neqxZmtGRsi1YLNNNzydQDOOvoLfTW4Bq1aWHlNVdGNd3XUqBUBdVqQBrFXdO0sFagmPqTlTXiMn+bYb5qXLuaq80YJQqxGuUSE40isDVGl1i4St+QWs8HRnHOuVwJ42nwoAasZoZK0b6u6mXFXI1iVeGVGkBodUoDEXKmJMGIQ0yq4n+VulCMQjHTFQNHacjcsjZZU+1WjQn1GdfqT+WaqIJgUGp5u903tS56vI4Whey0TPa1I9kIB0y1n+vfcrnYzbaoWgFpeipUY5q+24H87bZul6rPZYzrutsyunJ1n+tWs34CL/6WU7qCXOmupjm4FautTkYlFYiJmDQTqh9Zn6XI6mC08XzJaLZB0EIAWf+vX+X6ef9Nz75974ujIbyc5i/3u/rM31D9uA44LlGAXP0qH1zS1e8vS3G/+frXL3pxFK9OcpVVbfPppQMpFeJRrMN5XSNNiJSwkEMmVzFQMVb7KE0i5oIYrdS3sVKKKmPrtZhKuGEQ67UyYCy263F9T7/ZYq3DiFFF6qiEMF2taKa4EJaJUjKb3VAbobVykVMizgtunokFfBHGZWaeZ06nM2OIPJ1O7J6eSSnV948s81yzE1rxF9P0NzLivEI5jeCcR6r2l9Qg2UgN1ExlFCpmJUO6tjsiWu29TgLXcHgN0g26jnhnFY1SP8Oa5nynC8ql0XVfPU0NeCIpGXLSaoUxKuIcSya2RFeryjVTS/U72wWTL1O8QX3qz5QuvQdwYahqDnmGNWFTpFa+ygUCVQqrFpwUbQNQJ7qW5yl1fVm92XUcNzuScwHD2huj3DmpQpQqu1ddU3JZQ6CVsCWXrMgfrpz8UskEqj3JV99bv+5L6JjawutEQgsn2j0tV6+uvtcLoyEvfgA1+aJ+mtSorwlrfp8k2PcONK7LPnL10KXy6oqsyRtSzC2IvIyRUhkL0GxokRpx2Yq3pGJtsRjxlV0qMZ4nZdAJEWeEXHs+1D8xbGxHEatsMako5MMIpVjFJRh49epjPv74M5zrr8Sb/iW2Ass5Eg8zx0Mgp+oY7ne4YUt8uGWywlEKv55nFhJhHjEMFCxBPKFCQqwdSEWdkoebO97cv+aTjz7l/ftn5iXwqy++IlQ1TesHOt+xrYrUSo2Z+c/89Kf8Z/+1v4+lkMJCms6E05FwOLAcDmxcxJTMkDI7mwkd7DqIObDEREEbwqNkJgOnXHgXFnrrcWLZeacwFIRkHbNxnPGEzZZghHNOHGLilCHbLXkKRCZKShjJGJM0g1xUWyAWgSIEMWSrAaDZ7bTBMiVVSjWOzf6miv7BcjyyTBPTOLKMZ6RkOmuxdsFa8INnSRkbC2NI6lyXwPT0iHGeYbMl1QD1eHwiHRJZCv2w1e+VYT6e1bhg1VAZZd0oVE0FFI8qWZQZSoQcGxSpYEylWzZoGV9YoYJIJpusYntiSFHFgWypgUbJ5NIoNxVO6A1KfSh67zOV1U3TC6paTVkzI6XUfgCoxjbqHKssIvpaVirVOpRpcAOqYbyw6+hPxeDWRmyKVuBqoNFCES0vp0ppXcvHsVQ4VFn30ebqC3QlxwiVgStXVW1jG369NsOZGlxUQ9eEm7TjHW2qNmDEroGdtrIrnjhlXdx9hXA2xpB2AxoswJgLpFNqsGis4p3JV0FDadCr9vtVkIC8ZI2q19LudQs0rrecqVUVfUYXR0exoDlLVbdu3uuHzudvt+vNSF1AW/CwVgQA5ING46uMXT2+VTtEtMmT6n42h6qxWJUMMdZ+H7QnTGk/62CpiQapRArOmrU60sbAt9bk1fHlOm74zc/7ivD+4vhf4FOX7/ibF3+5+ryXQcbVZ764hnL95vXBL4KM5hOu18klhFh/ystgaH1GyMvPbMmV0r5LParmRwTAeUw/0G92mJDI8wzjQqmN1tY7TCwUEyArxPu69SqXcoEumuqoi8H4TjWNjMN1Pb6rgYbR8uTz8zPT+cz5dNIrL0oJLmSctfTbrrnqVSwvkXIA2+GWiOsip/OZaZo5HJ4rtx50vafZufF0JqeMt0qVLSKVvEJtsBW3OuvO+bXHoKwPuCpZS8FKCzKaGN71OGMlRJOL64uQqygcWik2omxa9pJMM0YDmkvfIesAvwju6dNNKWFiIBp9rnrLDZLkYk+RNaiHuh5djel1ZDdnu7Iz5aLaT5e95PK31ueXL4KpCvFv2khqCaTU6yqqW5VqZd0ZrrbL2Gz2ApHad6hrTqkN2caq35BRhkOgikRr1NOa8IuUSljQrqX1jrVnUkUIjagtqdfYoE3X87FdjlRhmstsvn59sQ3XIcc6H+XKnqznrN/XVNvWFsWGzOBv375/oNEadrI6TAahEyEbRxZ9sFp7VK749ZkUqQt5WSd5jgqtKCLECtEoteM+xEAoCWcsUoRlDsrjnGGujpevjoQzwn7Y4LpO9RIkki1kq4503/Xcbx/4r/xb/w3uH+75d//df4//xf/8X//eX7ltORUev1pgKWxu37C5veXVj3+HL+Yzj/PMV++PPKfIIUXezhPROEo3sRlusLbDmI7H8xOH45mYZ262Pff7e/6t/9p/lc12R0jwf/u//j949/6Z3f41GI+zltvOIyQkjJynkd//3Z/w3/lv/0P+wU//iI8e7nFDj3e3WArDsEWsYQozPs6YnCkBtqaD3nPfF1JIpBLojdVsi3gwkZHML0ziy5zpinCD1WyJWLYPH7P5+BM++8nvMXvP07Lw17/6FefpzDkGrOtI794zzUfI4f/L3p892bIlZ37Yz9cQsYfMPMMdqwAUIKDYUrNBUqKpRYqSySQ+USLN2P+a9KB3melRxjcNNEqtFkXJ1E0T2S02hkajARRQw53OkMPeOyLW4HrwtSJ2nnsLdWHGN1SY5Tk57CF2DL7cP/++z4leGIdArQmtQhZwTlEqc8m4uMPfHLj59CN8HEiq7G/27I8HfuPzH6w0mTdff8NXX37Jz/7qL1sSYaiIBQ3h8WnmNCvycCHVJioTR1pMmBa8FQwdhey3lacFAudXFDJIYDT+C3m/a8uezTuwhU2bRaDgXGkB2bo3OSSyX/ByBPEWLINr1/qwtmWdt+Q9N92IoKYHaek8gNOI1GD/E0A9NhDOFohajNdpdosdFXLmxKaVx9NDQzeuUYaO3oDQhK7OLB6LKppmC5TVKFlZC4tmpNRm+GBanKrWTrZmmLk+2Q0ONJ5r8IEi9mlKbTJLATDKYxABMfF69BZ6pFZ8rbjgkeDIgy1wuUyrNWKWQhVr5UsWcBFHIO731KxoMS50rdXcoaqhcKWWNUDWlhyqU1wx5MipLSRBhF0w1xSioMUstOe50kXktuZaMaE9wIoSpRUoamiPipDaIKqKIt4shHMT0gn2fs63c1qtqOrnRqW7xtjjbYzKhxSaX2/Pt4Z09rrMsRXcyIoYdjqT9sW+5f9e3Kq56MO6pL1QPyea7eSJb0UwzcKz2jm0260BAc7yVqqs7mN2DlfAlZ6VX6X59Fdo5JBvFRtbgSBrUWtxqP9/9RrfebnI+t5bUXFdPFzvyiZKfb5v28/fflxPaZ6/+WbcTK8V1s/y/JGbc4JAs69uHHOlZWDbfpe4wx1u2b/6mJ044pI4+5FpNrG3AIsKPiVLkJxpcLSWlpxm8ppA2SyMYdxzvHtpnZI4cLw1I5KPPvqIsVkav3x5x9tv3vDVF7/g9PiAUhriP+Cc8PT0yDxdCLF1O6qaJT+/sGvK+bWAyiU3lLrafCfnCCGsnYy1QwEcd8OzBHJNLNej3IbHtevaLMAxloGzQsWKg1606bq2rt31Xlz0G0qtAOlaFi3JdAdaKXkxEX3b/1q7XsMKNjMCsvXncn7icnVFgOV60IqSprexTqKJsLsdbC+gSnMDM5pbH1K3CbSvX74LzvsF1u8Xhd66WYfWSrvP126AsjJtxmYOJCIstRolr1/APZ6UahRqVVCHc5W4P0CExY1clmRDqEs1+9/Wrahia8jaaWqXeFuGiMb0I4SIilCwTonVEYXe+7PEv7mT6XYQ1gJBtmKh6xg3gsMWl/r96XsR6cJ6XLobYylGh1s7WN9xv3/X9r0LjRjM2af0CqYFXdcGfxXVdafKs2jSkIqWCJqosnwrvpW+4wp5sZvO4fBuwHkhApc28Kuqs5PlhGSTA0Bc43pbpbrUhTGOvHz1mnlOvH1zz89++kVzJfkbbiIgIy4KhxevGO5esByOPCwzb0rlfco85sRTzsxJqQ0m1Z0nxJHbl6/5+PMfmsZidByGyGEcCCGyzAvzYmiZa5/DBpVVNC1ota9Xdzd8+vFLfvu3fsDtzZ7ghZQTg1a8OPbDnjHu8C6S5jOuFlwBGQKDd7y+OyJ+YBgybx9OlI0XQHGeyTvmasnXuTqCDwQfeHSOWCpv22Tsp5x5V2EerIDZ7fcc8szl8kSZO4pSW7UuGBXEm32rc/ghstvvDM1wwuDa1E6Fy/nMpZgW4HR6Is0TaLGb3skVem9ds6I2TLBIv10SmgwxL1nWy89dLaxe2zyLJugWrtGJdrobltDXtdUIgWu+ZEdC+s/d7Uiwvh1X1qZunURrKJqu9wSCdega6pNSRtxin6UaB9YmilvnoFbz43ba3LVaQqsCxcixduv396tlFbM5tsmkdV0c7DmogWWFavqhbtdZi1Gn2vPMBVdMUN6TlhYra6lom1vSVztpn6+jvXUdsteOtDiiMzRffEve2knuCZ0dU1twun1oRghusOnf0ePUZrF0B6EucO/Bczu/yhgDUaT50ls31Qumz1BATLjpfCs0qrQWexNK9rS/Yk4o/Tyu5cCWdvXbzD5LXSO6NhZEp5s6gQ0VZM0UO1L5YS74623bvHNr4qboapnZky66wBMrMtaOFo0y4ow/vZJ2WgHgXUsmam3zZrB/mgtQL0Scd607h71RO6muDT3tHZAtP+nFwbZdU0a2IuLbxYb96brI+PaVIbTY+ywBuCppPuhcPPvrd11oa2F0/YRvv8Z1EbDqOvpPz5BpvtXZ0fZvf1R/yzWZWV9aVhBlzhW3ZPy0UMWRUiZVUOdxwYxl4jIyjGMDc9pA4Kv4tOpinE3ADkMkDgM+RqNKtdbjdLmQlhkBzk9P5ihVUkv8zRbWKC5WrGaUqp1qqmhRA18s0222xk0vogbEORU8SqCuXbbr6fH4zW1ow5E2wxCkdSfaU7oBiLQEuFd52ooMEV27sWvB0Skx69saFz+XjEvzGpe0gcLWNbAp5r2o2AbrdaS+OzE9p9nY4MTm+NbPuLKaCnXL6L7mdwMQs5rVZhKk61rXr6sNUGClxfZ72lydnl9Pq5GE1LZm27FxCKEBFoi03FfbGrPNHrHktiP9zWVSPHjwEVy1XLbWxHN1hJ2L7tDmBAbviU4YxdYlJ4Dzlh9XEBcsf+niP23aG93S/n599JCyMQLo9eVWKGgzbFoXqv6PrIWPieVZC7jeYdxO5a9enb53obEfHCkXZoVS21EZjRYiKiYqbTdu3pgSrbigcd5dT8GgdTpo4pLSglFVmBezCxQnfHx7S4wOCcLp/SM5K1qFERNFXdRRVPBVmOeKklHNPJ0f2Mc9n/7gE/78z3/C6TTx9dfvn1e+33MTEYbDHUEiLz79TerxwBcS+KvzwtcPxrE8LYlLSigR1CPJEd2O480rfvS7P+bf+3f/Pj/+vd/h009egwrzvPC//d/8r3n35j2ewM3ujiAH5iosaSYvM3k6kdOFnC/8W3/3v8OPf+eH/OYPP2J/GEAq02XCeQgUbo63HHe3jOHI/P4tlIXBCy5GYvT85uef8HpWni6Z//oP/4ylVPBKDZ7qhXkI1uYtUIsQxz1x2HHWSrq/Z77MDC/uKCK8PZ843B3YH3e8fPUC7wq+zJwfhZwSeZ4bcu4N1ddAVY8Ljt1+x+3dAa0ZCgxhxOVCzhM/e/dgrh3zTFom8jIjJRG9ITXBB0pptJ2sUDJIRsadFWY5MbhW7NREiBHnmiK3Ufw8nUMZiHEEEZZqCapqNSS/VwFXQX7lg1JWW0W7OR2uRloaY+WJYol4E32JdKqRdQ4aZbMJgs02DtrE6jKzLEapyiW1JKVNh6W1fQtINdSIbPcJwZMXQ6R8q5BUlfPpvAYRwYqmXAqpo3q1awDcyiUVp02ggM2uaYVMxAZKVQFpIyiqdkEclui7AM3esE90LblpU6Q9WZVStAnihHEc6ZahU6rNQaoNNuyICkLVYt7s1YqXICPqA26seJ8gJ+pUkNKSG5W1sxBawqBFud2PHMaBccRoWFVtQFeFSwLxh1YUN22FVso02fWmZudtCyHr8eiuWqu9KlcWq86sOKuKuZ+UYsfYGVXLeev6lUm3blELk0EcHY3/9fbd2xDDmuTUZn/qm2C1V5rN/+uqFNwGk5q4m5Z81TXB887bfZiLgVvtPu6dkBi7c44jkzZk2nt88IQ4rElKLeYcVK8Q6WdgW0/Er5P5D7deXFx//x2FRv+zfvA68ku/k1/6ltc7Ks9/82y/P9y+db22JOz6Ra6TznabrYk7cpUUsuISDSSx5z5NM5cqPCYj+5RaucyzaQliZBh8s6hfSBgQUVr3FZE2+NQyMisyBobdjjjEZmnrqCUzXwqPD+9J80JKC+enR9Iyk+YJwYw3QvQt5mzoPlgn3EGjEne77kIgrtSnXmS5BqaF4K2DTo+xnZdf1+ujJ/a9k9aT3r7eCD0utZhUrdip0vtlelXIWObZrZp7MdtAe+sszEZhd9ME9P3ZknorCjpIBCbF3873WoBc0Whzzk08njc3rdVKlivUvZ/8BhS0FsBG4QERtxUbWLG/gg0YpbYXb23awnruO9jYY3hblfHCOgVdpA1yLS3v8DYry3VLR2lWK85TW06Kc7gY8EXMXbFs64PtbQP/1J5rDJ2BXQzsg29rhdkX91lQzscGYnRqYaEs83psnoML/chddSAq7Tx123caENgeK/1et/vQlqFWNGrPX9YSqT/pW+/54fa9C42gdvEPB5hytqFvriI14yqgiZ6f+T70SC1YG1XFFk2nQNwGXx32e2uHzTO5FJZaqGVhbgdDAKkBSZHD6CnREsLD4BnHHS9ff8rnn33O3d0dj+/f8f7N17z5+gte3b1kNwy8e/eWx4cT05SIg/vrP+Qv2Xa7Hf/BP/iPKbLjJw8nvni6589+/ue8uZw41cycFi4lc0HxIfDpZz/g7/ydv8f/5H/+7/ODH/4GP/jsE447h2jin/3jf8xPfvIz/uInP+UXP/uSZclU9Tw+PTFdZt4/3lOWGS0LA5klzSwp8fj+a04Pb8nTIzhbzIaSIS3UZeJHLw7c/s6P+CTCH/wzWJaJm9sDXz+ceX+68C9//jMmdcwqvA1CxqFZmVOhOkepDicRwVM14FLAVU94eYfu9rA/MjlH1UoMe8pSueQnfvb1V9TLiXp6gmnC5YzPhXG3Q4FTTQ0xqYTRgybS0xMlnRtSK+by1C7e0maq5JzQZlzc270isp1Drc39Apsl4QSCWeYiNPqE2b2aXV5DFl1uDkdCTta6NBeFli1Wt1JjRD64acUhOrIVLtpoUIVakwVw8c+8qxFpyKmswkNtHZK+HwqrtkA1k6WgWlrRbPtQqyO3IZWpuSypSuOdYtTDNr1YS37mYNMRpbXQqHXVsjln1CxEKA3VUVeJ7V6N4pobhgkSS63gCrUlcVLFLH4RYisyVJUlZ9OgtIWgQNcxAoqr2mhsgg7tPPhKkIGaCzWZhSCYMC+IJW43za8ehIe39xQc2UVUc+ve0JCXDcHqqJwDBoFRhKhQF1159kgwS8sCWiPiIjEOONr8Ht8Quabxchhopc1pynTbtclINqpO9NGWlLJ1MwSHVMUls1B21Sgd42jXatWBy8VsMqvb3Hd+vX33NoSw+dJ36pOqeX4CThti2hOPRtMwC3RL7tYFVSz5i96z241NnLsw59Kuj9o6nMIwOoKPhOBh6slUZdeS1cNht6K7uQ2JrHpdNF6d1KvFWvpfrpDanvw9exD9+t7y+OvtKkV/9tvv6pJ819YLmvXxVy+lPN8fvXrOd9YY13+U7/67oepbN+SaLthxVDutTbuRFnOIihlaojlEb/bD0twNywJq4KM2Aw0wkCdIWJPN4K1QKHnh8eHdCgz5YClSSskcipqRjaAMYdM82NxFW5t88E2v+pwEF0NYC7tOLzJEuVH0esJfLM73a2IVPHfbumcH8fpoa6+r6XC2rTt69dCOXG9pZD853YRi7QS0jp09y9anornRkjYBuHXZmx1s2QqtnvjasSxXxVK/ZnVNkGsrNPqgOysse/HQr79tjwWe6TmgKUvE9rUDVK4d/dDm2FiHpbR70Tr1qw6r9m61WGHopJUDVkuEGFFXSJhpSe1mJtUKk3G3W9H/82WmIMyYPMDW38184trWsIOOwXmCRIILCEIuhZwKc6qk5oSlYsBVCIPdTrWwlLo6YT0r5Ns/VqS0e6dsjKQhhFXHmUs/r5arqaNZ7xpouIsDVSGXypzK6uD1zBL3r9n+BmJwWV1Zum1+bQ4w0tx0+hVwjUKs7WtgnbLaPqg4GyymriK5dKt5gnNkBRUPzqPak0VLahDM+jZGdrsdx5sbbm9vqWnh/HiPE2F3ODAOI8u8cD6fmecNHf6bbt57PvrBZzwuwts3b/nq6cT704nzMrOkTKrmXiHOZnX81o9+m3/993+fv/uv/z0++eQT9sHz7puf8+7Nl/zJH/8Jf/bnf8lf/MVPjTuuSsrK+XxmmiYup0dKnqAkc8tImZoz5/u3PL39mvuvfs7u7gUuRqiFuixoWhhU2ceB4/GGuL9hUThl4f0l8c3jzC/uzyw4FnGc1CzaajXcoapQilEABGfoXQaplVE7hS1Qam4c5kpNmVoT+fE9Li34nNpAuGrUIOz8indIbTe9CNRKWRbKIs8RlHY9GNKiCG26srfZKNK/l42O47uAtxjFRdpglc1kwC5Wqe3/7kSmPcgVo3g56G3jZ5GWdqGu94Bd2+aQJOtCInR0pT2o2rAjmyNhwU/EbGBLmw0h2M3fBwHZIDptaLYFIKWsAR28CedrJaWK1nbetKW18u1CQ0TwITR/cCuKum1qH6LXb9q1ndyKJKNDSbOJ3o6biR/tGD0nOMhq2Sp2s7OKBFu8KLBauW7nvbWk1ToQIQ6oFHLunY2+Sy1R9L6/ADkbX7h6LIm4Qsv6eVnPSlubBWkJqbl4paWScrXOTePPVgpOvXnebutwO7vXKBqr0F7aNaWwIkVOhDGGtbOzLMsqUJT+MqrNs6Ka2NR2Ae+bJDn4tdv26+2XbO28XgMD3X5yTUh6x6CdSNcQzI7NtSetxakt5sEStVrJCFpKK2D6/d9nBvgVHVYxRLqj0toAi+52aLFh2/E1ynxXhv4dn5Oru+7Znz5MMJ4/6cOXeF4ZXB+ZNX+9Sk6v74FfsY/Xuez1775dy7QXWw/9NamEFWDp//bfdzTWkqaCqw0Nl4aC1+5qZx3uPE+UnK4c/nQ7Vmuy3Y+f6QBrNsvTUspqVNFpqdqpt60b1udHrFx4WOfwSPsA6zV1hZ6bfXmLqS0OdppQveq69E9va1a9Om3PO2Mt8WpJ5HUvS64OfivgbAFtx9sy0NK6Cd/F+Hh2ba2dw1ZotPNRmsNgKa3zv8Z/e99ehFts7Md8K5a6ucm6f8/2Xba80T5eoz9v1LKCXq3B7VjI1bW33v/tWuufg4bcN1e4dYim2AT1ur6i4KNHvWcQQVMrMrSbrYglxm0nSylmk67X+YauMWn9sFefyQTpSs1KopKbZXMuldIKBi0FR3Ow63Ht+Us9O+fKdeepPa0Bt+MQzcLbO6ZZSbk0QKzl6bKt1+uxVqzBgAGQ9vq/Oqf+/pPBG7pqfD3W6mfwVmQchmF1aZnz0j67tR4LSqqlOQyYLWhURyRwI0dwJowNfkBrJaog4lEXkHikFqXkQpqeEK3GmwuVUB0HXyCdmc+O6WJIuZfEJ598RtztWFJlmhfmecGJ3wLo32QT4XE58//7y5/xf/wv/h988/TE7uULHp+emJeEuoj3kRe7Pf/Rf/C/5Pf/jX+Lf+d//D9l2B05PZ345//sn/J//4f/V/74D/+QX/zsK5Y8k8rCqxevKKXw9PTE0/liHNM8U9NEzQuXmojACHz9Z/+SP09P/FfHyr/54x/z8d0dYwXBWnjnOfPN+/f8/Ou3zGHHm/mRP/hnf8RXpzMPS+Zt9izNSq5obx3C/nCD+ICq8dO7aLu7Lgyn9+zIHKOjzJMJ6OqM5sW8vE+PBLULSTCRh3OOqdggvhBsrrQTQQrUXFiozfe7TVpuQ1asyyXNiWfAid0ERdscBjEkWFUpLQn2qoaWN0FbTzqcepwzKoQtQjYTg2rJQk+CRcGLb8JOoyhZoDFr2p5QaO0uD0YvEwwFQwuOzKonUEtIegDv1n0Za0HPTQDX5yNYgG8LTW+tug3lyckWOJssawuBa8OiVKUN1msBtOR2nNjoICXjRZAg1GQt2xAEcFuAbBa+QZqgrAohFzzC4I1rriJMl6kVBa1wath9cQUVBxpbPLduZ2l+9u202KLehHDOAzGi3jNpxhWHI3B3c4c4x+3R/O9zMWereZnJOXHJk30eB3HncQpLnZsoUHFSEDH3M0GbnGTDFas4HqaEI+OKLbBFlURGRPHOHFdEAq6OWMjSJr4zU4GirEVw7a3ohljRCmbvhOgcH7285XDYcXN35Gc//wVPpzOPT5na3cfEwBtzc7H7r9aF3S6yE48bR+aUmiPfr7fv2moujQrQdEINLXTO4Z1jjGEFKFLOa9G5aKUUtVkmtKKkJyDFsxsHuy+CJwLiHdW5Zn2pa3LZEwhacem733xHaFU3d7FGlejbh/nB9bfNPOaqGLlO1/WDJ3/Xy/ySyuCDzP9bHY6rV+lx7FuPUVrn90pvstYmz1HO55/xecHXd9FonE1XtRYTG//+OlnsHeOaZ6p31DK3RLcwT0a5zTlRs9nDOip9ikmPQz0/24qrSs3JrLi7+484pFFLhyE0LU8Dl2QrSFcyUkPjO23KXrpTlIBWKHS7ZddMCEpVSk3terEjtrnuGQXX7Fm77uwK4OqxrV+PqpsG5cNzWbczo6rkdg2VRikzNoHte632+84qWc/lOn+ibGi2XouMP6xKdX3eqt0QW+NjiO140AoJowTR1qUPrcKhg1zVOgjRE4M5C16WhaXa3JBu/LHuR2cTtHu1i96lXduKtg5DvyaESqCKI6NtxpJwPBxREcZamZZkBUCupDmbZnQdXLgVw9qOO7WzfzYzmPXYSANFVTifZy7MlGXZ7ptGrysoulyoLjVr+wZM9W45HVDR9csK11Z1QTvuniEGPnr1wmZ3xcCbd+84XybeP070y2eIzb2Srr1twLGLdg2GDn7+aifX79/RwNwaSlU0bRWPwxGcYxBvXDbniAHLJFzknDJLykxL7gNQCYOnYonXkk3OLcFb68g54otblgJJDaHo6HRNJriJogQtaJp5ePeGy+WM85Gn0xPRK68/esmPfvRbnKbEn/zZX7IssyFcPq8n9we7j/mr/8X/5a/9xD/YfQyYaOn/+9/8Af+v/+aPuH+6kNSR5sIlQ64WRF6/fM0PfvhD/p2///f57LMfMJ+f+Bf//A/46uuv+Rf/4o/5+suvqEU5HEbcojAXTk/3pHnm/PRkvG2t+JyRnPC14tW3tn9luiR+8cU3/D//3/+EN199w6evXvHZzR2nKfE4Lfzpz37B/dMj7x/vOS0X5iXxUBzlcMewh91c0GmhLMYldt6Eby4MiHOMeFKx6jlowcbSC0PKyPnCUpS0XKg1UynmFNScxqRRbzxhpSINjePqvaPjAsH7hvwK0fnNn76Xpc4CklRLrJHWVuwtY9dmN9BRHruZfUeDOlJP48FLaEOJXBNEa0OHLcB0mz7QhogrNN9s4263AK1Xiwmsi0FKCbRAaydrC5ZLSXT5tBgvC6lWbC9abBFRs9K0IXdKt5ldeZN0PmordNhcIFS1G2dYYGwLmTQEtb+GiA3y6zxzzZuTiTbHC3sf35CZNhdHFVFLsA77HX6wBaHkQkmZ3FHZttD29yyiW5HVW9eiqzWsgLmgtH2o3pObHSAqaK48PNyv8wcqIM6MDkptQX3J5PZa1ZllcRWFYqI7ERpKI0RnnOTq4DKZC40LNqfC5nt0ZyyBUky/54W9BycVJJHUOi4pL6DVxOPOrs3upgW6UtHAEjDnBB+EnBeWS2UqiaEm9l5ZBhgHzzAEjvsduU0RnpeMYslq3B0IQ2Q4HtilRC75+4fqv2Vbbcip1r6oNkcx7xmC5zCOK8IcLMMzK+HFhkmWJbdEB6JzRtgUS57MQcozOCGK4xgHE2aqUnNLbEqmD60UkRVBz3nZaBnIFdLbUogtywV6HPzwd1dbh7/bH3qCuT38w4JBv/1jv15XbuUH76sfPFc/fMzV6+gWvbeCyL6pV4/Vlhqj2ug42+vZeasrLXTtbFwVLf2t10KrHc+yTNSS25C8K6S9Fkvo0Ga0YDmKJdD1WReiF6DXVsb2ZcViUcsZzAK2rkmyXU+6diF61wFWU6M1kaVfn+shtC63zbhwrCYj2IFc1yFo6053FLLOtYO1wFnP57oPdvC78cG1QJt6JdZuHVILfVvx0PZ6pUdtPP5+MvVb56S7YvUu/vrZ29+tyLbBx7VsQvchBnKupoHqdGLdKEv9OuiXW/+oXiB6x34cGNvalEohlSYsl+vnt+5XEyfYMTLqsOvXey9g23rrWkKNM31cVqM+6vncihbAuRZfBrRMRvdPS0vSG8BFK3DaufNSCUHwOIIEO9fQ4n67j723+8f5tTij1gbEC9F3J7yynktRM8CxLlv/3BWa2L8bWXQqmZMGtqYLKgEk4jURpbKPwm4XGcbAfhzIKbHMC8tkLpDiHHHcEWJkPB5IxRy1ftX2vQuNqmJuZ9WSp1ZAGYIjjuCM12qip4A6j4SBuWqzyqQhOy0haoElN6/ortnwMXJ7d2ui6KI8PJxXVX5xJuoZxNyDyInL0yOPTycKMKeFzz5+xccff8LNzS1LfuR0Oje+pLbxv7Z58TaM73tsuWT++M/+nD/4kz9lOb6gxMiyJFJRUMdhf+TTzz7j9373x/zWb/4WMUa++fIL/uUf/yFffPEL/vwnP+Hh/SMlZ0OaW5V4OdusiOX01CYXgy89gbd9FGxQ2ZIKb98/Ml0eWFLik1ev+O2PP+HN04W3jyf+6b/6M87zhWlZkGAT0uNwJAwjznkCCz71ydWK85Eh7ugzC7wL1iruSX87v6EUWGZKTpQ8WULeLuDOf+wWjl6asE1tNoJ4QxxsAnYlhpZQahMQt+d21wRxm0OF824NlCskrhuHdA16636oFSSuB6faYrVHvNAnnWrt3Qb7gKtHfkNqGkNzO/ltf/t7Ve0Xv640MrTYzdYKjanMK8fWta4JuZDVWqLOBSs0mkBPFeu6tMT/Gof0bR+VNjAHadQnXREaR2ttNupNWZ2XDL1IyRCczr5RFSvapLc9qyUN8gHi5hwhRmKIlvR7b04PXQjRFplOOauoUbnUNAftCNuQzV5Oao963oY9NTFtLwKX6WyUlDbd1vttsiyIUZ7aqq1eGme1QjFTCnEWj6I4hgB4Gyq1LNuU2l7oLSWxrkg0vFmEMRjnulJRdea0pW2xFwiu46PNm7+v91d5WstnqTmTqwEqQZWddyyDY79vU+APe85nZZ5mcmqapGC0wOBdQ1IhVv+9YtXfxm21wOxxAYAmrPWeYeXGK9Ri06GjZ6oteWuFAwihFxmw0iq8d82SODAej9Cu1/PpQpoWlpTs+hBLXnpXpRSj3doQzTUDuMo4r+70DrH3+7r9/cPSoX8MYF0XtwLiu7a1/P2bHNH1vx7P+948r0N0pW5cFw50pLs/9Opn1yuSTt9R1iLBEHS2m+mD3aEXVdriTjXXvJxTi2O6FgACa5EhQptHYQlgLyquqU+uAyD0v7eha7k2XUFXMMiKJPdu1vb5tn22KKf0ZGldy9pf1yFpqyZlTY23r/U41asCtUlz1a/V3aaFuPq6AtRKm7ytV12LPpsDYbVgr42nuhUadb20nu1jAwi/RYHS6wKjn+8rYwagrja2pklQZ0NeaQDidlE/LzT6+/ScwXtHDIEYAtrep7srda1M31+j95T1eKz1mev+kLZVbXdcQ+l6HNBedM1LO7FCHAacd6bHaZ/NJqG3Y+RksyrXLjA3yl0Qx9g6MSqQSkbV1qYQjBtS+v3QrPnNxEYYYxemW/FUtBWp7Z5x7up+69XZ9foGzSynUPPSBg4rHiU6M3067CPjbmAcRiYgL4klJxQxkwtn3Y79GPFF/tstNKZklIWAg2BizlxAolU5Enyz9bDhKZlig/aaEAbtbhE0VFlQsS7GPg7c7CIpJ+Iu8Nlnr9nf3YGL/Om/+CtODw+cnx5BCx7YuYiSqDlzWSqXUkkK+7s9v/N7P+Z/9j/59/hP/g//CefLxG9+/hlP08UQyWXi66++pNbS75dmz8t68fouzFKja5VS+OrLL/iH/+U/5z4VcAtlyVyenojxwIuXr/mP/8E/4O//D/8+/8bf+33+6I/+OX/0R3/Af/Gf/yMOh1vj6VK4f/8179+953Q6k5aJZZmQUqAUQlrwtVksqlBxqDhz73IO9cJjzTxVeFfhF//iL/Hup9zEgXPNTKVyKoUQPbv9HlybKB53uGw3nKaKV2V0IEPEu0DAU5NNVtZYCFJs5kXo00UFdEarUMRxHJr9rmYrDluxYAHANYtO0wh0dMZ581YwC1dDZ1RNkNzRkKzJgkDuwQTmy3ldDFZUsEBp3FbXriO0bjzIxmEEwNssBLQiRe32UmszSiuQSzGUX1GjJamC+Ma/3JLQ2virNqshbQhRDys9zqpSNbcuxXOUrKMsIJa4AtSGnAir44qjtsGHDt/81mt/E7WCzIk0GYe1qgvmPrHfR+sgRb+ha2ATbuPAOS9GFamZ1qxpetnaFmhBW6dBvLXgL3nhUgoV4VKb8Dp41BkFRZM2dygoJVGslqTWstrGhmrc9QLrsalOcTkhateGxygOxVnBIVNBfaE4WJZH5qVQilKEJvgDNNtQ0Czm6NIWhtBapw4buhUHz27MOHEc9wde3LzEB8/9+R2P9yfOT5NNpMfOsfcQoyfujoTsWDLk7BpynfFWJ1Ixr/Mez7PaoM2UFC3WSs9Z8cFRd4H9buDoPHfOsT/uCEPg/nw2ilkp7HYmAnRVkKxkXXhf3uMb3//X23dvqXR6xybs9kBsFt0rZUS72YTdv0sqxktuN4vrHT5qc7yxztQQja8dhsjN7Z4YBhThTSmcc6JM3TLbCvvN8tIMFDrPXxXrwNVrK9wtqaJ9hmftMeCZHWd/yFrVtsRMPnyND7ftNeSve5gdCXvfbmV6DStfJcvSMYMNql958Wsc7hlne4Eee113U2tWRaK9O94Sftc7Qf3pPamu2/OdWaQ71zj27X3MJai7jmnP+1p89utx9+7qOK/W1TRQSihkM9vo6H/7nDW3j3WNMHSkW3v+r+vrrR+/J+7i1rkUuZTNCai26dYt/zAa1qadqP0wWIgEekHRaUnbgDptoAhiwFTv9m1gmjQGyreLWVtaKjizf9c2JLBrP9Y6UJsLYgfxtIGj7bDUK9vV4KMd78YuUAVfDcAO4iktB1DpBZodvd4xcs6Z1s9v3y95YUmzae6yMRhiHJhXmjM4Z46SOW1mRd3NTBogSit2e5wQZ8M4ydpAanDi7XetoCupz2jyLI1GpdJznHaS2jVl+ga7frRgXalg9vp4T2xaoOPxyO3tLd55Tk8nHh4eOZ9Ods0DVCV4JQaHjyO5OkqBx9NEbXHNN7G40IYNttwiqzSdRzW2RVXmeQINBIHjfuTmuAdnAydd8DydFqNES2CIFhWiF3xJMBVOJaE+ou5XlxHfu9BwlX4I6Wqc6IynrAJzziwNGb6UbLxo51iyXp0EO/up0G5CGwBSq6NWh7UNC/PlhA8OcQGdTshywecJKAQfGMaIb8HeZ0/0Dr/b8ff/vf8RQ/T8N3/4RzydzjYhuCqxUTGeLhf+wX/47zOfT+RpYRc9x13g4IVdDLw47nl9d8cQB+Yp8ebtO969f+DtnEjiyDHihxHxHo/y2z/6MT/60W/z3/+3/m0+//xzqhb+6T/9r/iTf/HH/NVPfsLN4RbnHEuaTM8xTSxLouaEJJsB4VStQmw+3FqVpSpJldwuGu8chGiq/4aoS1ZSSRQxB6kqjoJjKZa4OVUyubVcK1ozxUGN3W7YgqEEa91WsaFpTkGzCVMNlbYFU5sLAyilGuLrnBiKjNAJlTagsYnue9vvOoRpv9FbMKyCx68LZUsJGk2IFS2QK2SgYz4glI76id3AfQqn4KkF6xi0edVVMWu6tm8rD7j2gAnmTqJNC7ElAZs/eF3F1ds+d1SnFyvu+ZoMq0DQjllbWLp4taFS0j9fSyBqK8ivHmRHaP22UavoQn4LiiFst3WrqTdBGC0x7vvWT1X7DGom3TabpC32427PMIzcjQdUDM19Ot+becH5TE6pic3ZTCFq43ZKPzZWHHZKRZ8PUUulVpuv4Rsa0ykKFrBlq+QEKLomhCujTtQcNHqh0Rf7Ks2b3nMYRjtOWinLhZodWjJBlDFi70kr4nCIeMRFXr5+gY87PvkUpunEdDkxTfeUrOZyaLcHzaoC0VbAVnMmyRS8s2FT3bax1MLjqcJFOC2JnCuhDftyGK0QWlJVK+SNn/3r7dtbKR200LUD6L3N7SkK53lZxalVqw2rzJUp2yDYKk3P1NaoUjDjhFJR3xjxqmgulGnGDQ35LKWZX9QVVfXObZPuXUdXN2hR6Ne+frfodf3vg+Ji3eTZt1uM+SBh/OU/fMem3/Hzt59zrS3pqfSWVNPiSItPtduEP39tARvEJz0h7jF/E2mvxcNVx7RTr1DfOhEtSe5f1l4wWnDXUvSCT7eEX7Qn2usOf+szWYNXEe1zK/oa05D8lghfo980B6mVQtU+l1wdXu1UM7U8B2HNUcqKwm7FXac4dQcnbdeh/by9Vv8c2lzN+trWd6+xCenNeMFytqrGTlkBV2efw17fWAgg63okaFvmnx83czZs1wNmDrQet7Yodf1NjAZyighLsjhZsNlIsNHO0J4JdNqy7RviyAioY1FhvzuwjwOv9gfURSqeb94/Mk0T58vZ6GDtM/rmMreK6vt62/7ZmAyd5liozXBGe9FqB9p0mg3wW50h+7ljO15OlBCcFRtXazztenfBMY6xFZeZZb6YvisveOpKlWrhhJ5FhxB4efuKMOxYcuV8vjBdzk2nvNikdDEABO+29V8Eqq2tuSo+21BeaYB7rYWn00QVmOZCScXy7DZryIkaSCm2JhUq15bFv2z7G9jbslXF0RLNOARcMLLNZUmUnCmlMKlaMu6FObcEL1j2okBqLWtPpZRELkIuVmiUknl6vKeWjBNPeXpApwsu2WyG6ALjGBnGPYjHZyEcD9x+9Jr/1X/0H/Jf/pN/wn/6f/4/kafEEAfykggte7ucTuS8WGVcjY5UtfIogM7UN0+E+NZuzmr8+VpgqSCDIw4jYb/H+cgonn/tv/f7/Ju///v8D/7tf5taEvcP7/jH/+T/w1/+xZ/z9Re/YB92aFXun+6JoVmmidlZOqsa8AKjF3bNKq+UShZLZpMoznnUt4mQ1ZwBpM04WLLZ74n3OGdhYWlzJqgVVxI2ibna6HqniPP0FUJFCcGjYi5UzvvGW1wIwdA5JNj97a3FWVWRomuCZRHMkkFt++XUAc3RqdhdLg2h6E+x+9wC5SDRNDjSxbnVppgKayuwb3JFn7ISpp1MAGezKEDwalSwUpWCDVDKWvHNRq80qpPVQm2/1K4/s5Yt6zTwFXXUtYnSOhBXQeXKpWr1zu/iPrXdNN/0Nmiva0b63zua11Ajbe5HK0FNrrmxuraBg5jWJXi3JsrDEBvC51imZPcfLbFpft/S2VJBto6MxXFojkelOauE45HjzR0//Pw38W1K6S+++Bnv799R+Jr5fkG1ELG5OqvWpn2enjM5beSL1qnKWlf6WG2FbxdxG6W6tGtmWIsoWrB2bQFFLBbtBk/w3jomuTZKmhW9Ds9h2IEqJWeWy8mOB5kgFTe4KwGomGmEBHCB1x99wu3LV4zDnoeHd9zfv+FnP7uQpoyUrdDwGD1GVEiNAli0BfNazE65ZESNEjqdEksu1DawMsYRasWLDbG0pMEQsVrLem/9evv2Vqot6M6BNvc5H8JaaEyXhW6v6ZwjAwsYQIPYuV4TnFaMVKXkSvXtnms89uV8hlzsGknJ3BJbkrUKwUNoOqituIcrQKJ3MnoC3WLjFk9YY863tpbg/tLS4CrOfvi8Xpl813P7Q/TD337rsmuJtFgsNnCw/35LkjuIs713j+PauvayJclXBZYTKzKc36xV109joaTRrP1WYMi257Vu682zYXd9XzaUZgMwuCqW6GCHtDxbNrALtibGekhdK1Blneuw2lvXqzOlfb2zH2rrQuScTVRc9YqKdVUwrLoCaWuKbq5U7fN0FkAvAPrxvzpsdOKXa5QeVFsHRhs4ZNRAe6Uu9G4FIFfHrq1BRt9tz6MDWQqU1sF3ps1rr12KLZi7OLDb7/E+kh+eQLM5KIrHzGS29d6MUXqGbUmIeLMhbz0ZXhzvuL2747PPf4gPO1Q88pOf8vbdOy5LtiGLqgzOEWK4snJt+oZ+XSnb9SZuHRYoihXGa7ljifAKgl1Vkv2Y2TVidDvXaEahJfKay6ozlWaAs/MDqpWcE9O5sUGK4iiMQdZu9mqQL1ZofPLpp9y9fAU+8v7dO969e8ebr5TpolzytO6X95VS/TOhflXIxUC9kIzJ4px12E45mWVuNZqXzRLxeDFThUYqMYaCmtPYr9q+P3WKJoxzdkJijLx4cWtTN1V59807G6aG5+XtDThPJbCX2KZuShuOlZkvJ5SMuGwuA1RyTUyTtc9OjxPneCaKx10yslQ0w6UWLjlxrhN+p0gI+HHHv/tv/hv87u/9Lv/5f/YP+auf/AUyZz568QJFeLqcycuJZbrwcP++oazKsG+THKsh9FVtRtmULEGmB7vgqB7wkRIid3cfcTzecXv7ir/z3/17/Phf+7vc3N7xj/7Rf8Y//L/9p/zFn/0p56dHBi+U+UytlegsCa9FiVFWfcO4l9Uq75wzWsD5QMJTcKSSCWJ0rtzajeoNxQfBj4GKZYdSS7MedjTLaBMzS0RECOjaYhWspe99P/3KoB1FVTR4KspSMjFYRqelQLCKujtMifaiAtQp0vypS0lIoxDYwDLXgr8tCKKN/9yO81IXqNpQYSUI+JUOtaEvpWZS84zOaUvCc543xKfJB3orWrWuJgR2k27Vd0qGpKhzlsip4p22bg2s/RJtFpaIZejBgmcu2YRiVcm5JQvOUHND4mStTEQUL/Y6WqslLk38C+0l7QS0He1xYktT6lqc9AULNJoIDNeGLB6OfPzDH/Ebv/lbvHz1Ea56Hh6fePv+nj/+kz/g6fGB0+Pjtuj7HmQgxpH9bsfhsEdnoxqFsOOzT3+T2xcveHH3iipCVuXm5UdoGCAMlCVTl4m9qwyjcVfnsw0eXJKStNj5XxcMa+dT27kJvgUu3TohLSHRKtaEwuZ65DYkD6eEoEQnHILnbj/YxO/RM8+JJWVUPZXKXGdCHNbr2zegZOcGW2QqaKoghmB7iTY1fhCGAYKvnB7fMT09UqbE6+MLFuc5F7N4toTRNEKigvedgy3kajOIikTmZMc8F5iLkKrDScC5yDAMlCUhpVDTzPGww4dACoE4jvi2/7/evr2FcNUtRHDBM+x3HA83dt/GJy6XC/O8sN/vDGwRz2HcNQS3QM5Qi4EzpSBaUBy1Qs7NMrpWptOFIQ4450lLpuYeI+zWTbmSydbNaLqMXmBsLj16dVe3TZ7/3Knq35Hn2++akHTFYNacuaflPfm5fiNdv+0Fzrde9zrl7s9pwXNN++V5YSNsCbT9XQghbq8tW+d47VpcJWh27jxBLQ5cU2afHZWWzPaEfD2OVzWRtgRY1RAIgWY22DvRzwXn/T3c1Rq1HjLt3SwrH5rQtIVn61YppSVtlqTZQNQrStMKNl0XYsav7510aXB1bLrEWgsll+3x62T51uVpSSuwWpXKet5bodHWi3LVEanSrw692h/F4cHpBrB2V6nW7ljnVayFUDvYzUltm96tzcJc2/oeWkfbMex2HI4HfvTbv82nn/+A27s7coaHxxPv7h/583/1pzw9PvD48J7gtYE3ls+Ic4RhJA4DwziSasU7z2F/4PWnn3F3e8ft64+MAaPCJ59+wm6/43jY8bOf/BklXRiDWwE4yZBSJudKSmYIYkWDHdVa2too2/VKA7ecNEfHdhPoavvSi1w7PjEY+LcbPHc3B8YYCC1mlGT06oqyLDNxjAboOXuME+vC16an2QrQgniHD5FxGAHThaQ5kfKCiLI/jjjJaJ1wtTkpemmsIUizXVeisnbic3XkKkhVpiWx5EpSJUYbITHGQNRszos1E2JAgieGHcQDGkZ+1fa9Cw3vMHGdM5eYIUSij7x48ZoQIz7sOD2emM4TSaRVnwNhvLF5EbVQdKJWoQ9Eoyo1F7JCogk9K2jK+CTgKoHAPkAQz5IWowipXShBHIfDnsPNkXG344tf/ILHh0eCbzQKVbRmlnlimSdzdXJG7/AO2p23Vf9rFAQXQkPNzUpVWzIyT4nDHj7+6CM+/+RTPn71kjdffcVf/cWf86d/8kdMp0fIicE5SqMuRe8s0GlLptcy2t5TnaH55mND46FbsHbetQDDOqisz7vwPtKzUpszsuZxFryx1xdMVNzpa71F2Pmutje9pavrItKpQr2Kr0VWDq5TvoWrbV4P7fWA7pjU/9QD3ZooV21WedVesyHWpQX42pAXKzQKWc0OtpaCqr12qekKqGqfp2ICMGxOgW8UtCHakKZcKyn1gGtoi6zHuVG2rsR25iojUCrSBA5OHB4TU7U5Yfa1Bob+uXuR9/yIrShUO09bS7//Sta/Xz+zDxVz3rE/HIjeMQRhvz+yPxy5u3vB8XjLYX/EyYAf9ozHO968f4NznulyQXM2ZEabmNyZk0doOqXijD7kvLehZdPCyZ/BexO44RjHHXd3LzntvyGhSLFJudKRtbbgd6Gma1lB/6RON9OBldeKcWSj92YuoMKcdF0sr6/P7gwWgiO4rbvQhZumBzIdShhoaPPIEKwFnFOCbB0VXwF/hQSrFdfz+QwKT08XLqeLHbs024JRlcEHG/A27LikwlzMlteSB0dFySIk1ByPMJNcwwc8ftgxjCO7/Y4aFiQnXJpX+k3XtDzPCn+9XW82IK2ZDogjxoFxv+f25StiHAjjHnl/T318pDqHuoALA8P+iIiQlsUGjqnNT3DteFt3uZDcBhjUXE282ub7eFHUBVKTjpe2rtFjWdvHPsKp383ftV3d4Q0slb/mtPe16iqiPOuCrETnX/Iev/yXK8axZpfX/3/w4Gc/bpSZLpjuxYdSqV3PdFUUweYS1J+yzaRoRc7Ve6zaBW3UVt2OUV/DtkOxrTPPdrWtic9drPrrX71Ho9tZd2LTG3QcCKRRn2jGNqUl9+3d2vpJK7K2/RSutRTO+xWEoqWtZe0q9C7wc73f5uyxfTrtNaEIHksAtLY5Re3v63qzLZio2wq2lZpVsd+3YOv69aiyvemzYtje3NYSM/fZjTtiCAxDZNyNHA4Hbm5uORwO7A8HfBjZ3dxy8+I1j4+POOc4n1qXQ3WN4yJmjBF861qLAaWIkEphWmaenp7a7xxCYTcG3Mtb7r/ZsVwKTtN6TV3VDqs+y45dozZe6e7W67AdWy+OIfhV45hypdBdvLbHORGCs/U0OGnUKYy61zU1amWKyGCfLQzmV6SYZXez67Wie6Nyo2ZEczmbPOA8L1wuF6bpzDJP5GzmFDHaeRh3g+kYs3JKF8xhs63ETTtZmhGAOeVaoT+OO3bjwH4ccWWBktE8g5PWoa/46HDuClT4Jdv3LjT2wboYwzCapa0PBB344Q9/hxevX3OaJ37287/iiy++4OdfvkEwLcXdi9cowtPje1I+UZaJQMLXhO+TwJ2nhrrSekoqJBHEw93hphU3kJ7umVEW70jLgguBjz/9mDgG5mXi5z//OSVndoc9tRqNy9dMnmfyPDOGnkjZcDNLyh21qXO1e1c7YdjtmVNiTpmSzUkk14U3+oZ93PPbP/gBP/7Rb/EbH33MP/4n/4g/+K//S/7lH/wzYq1EH9jHkVkc1ZlgNLfAZc5MHXHo3AuPBmtnpVpJmC3n/rC3C7IU4907Qb0jusEmrruwJtddZE0TBtOSY2me0xbCemvPOJM5JYZhABFy3qZQd9GbILaotou7qNFvakP8Hbb7vYjopl7iXJ9pRXTBZkVcLbpoR0HsmKQ+Bbo25LCUxhdUci3komvHqa993rUgX4DGBuvQgjSHJu1T0TDELA6B2xcHai1c5oVUFjTXZvfrWrvXBKDiW6pabHBOd/8iGwXIeZsRYva7SmlBoM/NsAKoUdbaZ6naOK590WilZQ94duldL3pXi2YLul6sbbrb7djtdrx+/TG7GDgMnv3hwLjbc/fqNdEJabrggnJ7+4LPf/AbTNMTuyFy/+ZrUl3sHiiF4K1FOnhwmF1nZrtu3r17y/3DI+PwnrjbE8YRRNiPO17eveDy7i0nJ0z3iZIsEesdOMThpK5JgDTPbXFW/Pp2nrS5oogrZhCxD+yGHarwcJrJU5vMWxXxdt9G5xm8W12FVAs52UTgtHY0WmGMMsbIzc2BIFBL4uunb0gXM3cY4w4XzI0oUsEVKAtvvvgSdZ7H88QyL6RlQfNk7mVaePHRHTfHA69ef8ybxxMP5wv30xs7x960J8nBWSuHYYcgZK02edwHxsMtx+OBl8cDkmfICzqdWOaZJVVOKZHwxOL49fbd2zDEpimzLu047rh9+Yof/OZvcjjeMk0LP/3pT6lffMHp9ATO44c9++MtCpT6RCon0pxwebGOqsDSYnQpmdhR5CZg9WrroThFfKXMS6PKQSe+dzqGE9MKAVzXDs9z9A74bHqAq/++/fi/Zvsg9+fDH1W3x3y7jpHt3y2v+fYrt1i2liFrzm6B37s+1bmh9upM8M1WSKwuQMC1Hm59076z/f20TX5vWyRsGeH6NF2F4Ss4dPUyzwbnue2Y0/ZHdRtel0u1ieC1UEuzx24Jn1ZjKCypT7xmmzHkty5D72j0/ZKGBq60WmkAbggM40A30ylt3osl3H61ae+0sLKYmPwKFrQ1uGktXAhs3Ye6AmCr1kt1q1Gt/b/mGgbimb4Pad0JL9tJ1p6Yb+eln8PgPeMwMI4jr168ZNcKjHE3Mo4DN7c3lh+UyuF2z4uPbhl3R6Z5ZhgG3nzzDWk6UWsjNgZvTk1eCK51FMQ+U1oS796+5fHhgbfxjeWk3hNjZL8b+fjuFZd3L3l6gPPDe6htHkmbV1WVBhDaz+vaLx7fZmmtVEdVnNp+7IfIEMzF7HJZqDkZ9Xy9J7YiI3rTvVIKOae2hiQzsBHDur3zjMPI8bCnpkxOicenC8uykHMmxmifP9g8L9P0XEhff4XieP94ImWbHePILefL7A5H9ocddy9f8rgoT3Ph/mIOV6WWBoQ5ShVSMxfIzf0qhsDt3QsO+z3Hwx5dJnJaSJcTU5pJuXJKC3tfGeOvXpu+d6ERdwec8xQXGfc37PcHXrx6RZKB+1Pm8XThdJpJaSaIVWqpFi4pUYCntFBSQrINynJOkGji5VSMFnW4Ga0C3pmNZq7CKRe7AMSRxLHUzGWZKFoZpDCMga+//pL7929XHUOuhen0REkz5TIxn5/QWri7OVDT3HzOAW2e1OuCYDw+vDkUhRARH0m5IoPH+4jWStDEzhUu777mp9MT/8n//n/Hz3/6Zxy18OJ4QIuS5pkRGxCW87L6TOdSGi1LGMc9OEd2rapEcNETWoCIzlvV22wae6EhnVakVyiF9qR6E0S64C3MquKytdEqNnfA2tthtUSNMa5tZYHVxUCqX1vZ9ISxmBhKpYvlWrDp8ybEmZsG5pxT2vyVVdhW1YbwaesYabYiqVR2Q2AcBvbDwLwsLJcLWRXBMQ47al1MpJUV7zwhOFLNDUU3cfrWN9m+Sq3MOXM620yVpSSjORRrKZdacFTifgCx2Lu0YXk2+dcCebdp1mLUNAFwhsyrCl6bqUEP5k3g61zn1bo1yHV6VUUbZci6TqVZZW4AhlGbnKi1oYdgQ+BubhjHQBBBc2J5eiKdzjy9fyQMO8Kw5/WnPySlhdPlhKZMUIiCISmYnfEABJRBFcnW1pXmCrPkC0Fmogv4m4yXhCuR0/mCu73hzr/ko11gX/ac0oGiNvRqyuAGxyiOfdDmwJSRknE0elqzUcm12Rs2W2dQylRYWGxh9Yr3SihqQc3ZMddSKCjZwQykDFKLoUzFFkdLCCo1nkm6cJHE+WlmWTLTPJuGqFqr2yHmODJPduDdTF4mKo55TqRi7lBSc9PbNIOGpXB5OiPqGIc9x+MtWa2TokmpNbNMMzVdsDkCAYIBKcf9DeFwg7+5wdWClkTdHzm/vedUZt7mzOsXHxHvXnzfUP23bhN8674F9scbduOecXekqGPOhSllllLJVduAVXA64eMZgOlyIS0LpTQ3ttYOTqW0HMwh40hwnmHw1iXxwYCGok0U3pO12vzmBXFXGi/p1FGeNyOuMvXrH+G6q/B8e9apuEKYN8T+239bK5wOXbfEVD98vevjqlsC/teXOd8uivpskw/foesJVl3BmiPr9v/6qrJ2H1bo6/pNrr5fJ093N0MEJNPl2/3Db9onWqeizQBq611toFhfUkvTSHin7MfIEAMOY1TMudMmxQC7BuTlnNt+m4jYEll7x/5p7LpocbZa0jyENmui5nVtB1ubRJseU6zDYc57shULaiLn2hyzXFcwSuvOd8RFry659ehtxZzQuuWjM9pV78Y05oG0y6jPRgKjOIGBR/sxcnM8cnO84bDf22tpJU0X0mwC7TCMhDjw6uNPORzv2B1uSdOE1Gq2r84aiF5gCEKMwkCGbLRs1Nk6SbZZViGwuzkSqHg8aT4Ty47qlbvDQKgHJC2kakyGJVW8H9gFYRh2VlymTF5sVpK7Olh2tBv1rJjbVPZtCO5VUW6g69URLWZAU1Cb1YPY72rFVXDekxtF7Xw6k5aFmjNpXsgp8/RwboWyidjVhI+klIwZIQU3JetILMkm2pdC1bxao3sfcARKbk5pRTgMe4jtbkgzJWUul4mSi4Gt7b1UHNVHZDwSbl7Y9ZcTcjlzebgnXSaezicCI0M48Ku270+dChEV2wE/7gm7A2E8MC2FS7pwOl1YlmQ0BMuKqKqknChKmx64XcjGYVPKTBuAJNTgYYhEP6LJbElL7aikudavbaoWv7VWnp4eVz9kbYjAssyUZabMMyUlughWGwItWDvLizMxn/QhbVZoZDVk3ot1C1wTbealILWwnE+8/foLnkT4iz/5Y+bpgagmOiqlkHPGSVypIV3gEnywzyDgoglrVc3rXxEkBKR79iOWjDW6GtJlz1sK3QPis4FJ9Pado1tNrO4gLWpfC8hWd4/2O9TCvaHsRvfqFJhKvSpIKtmuf2q1ZLXvV6plpXzUFtxTQ6Q7P7Ej+VXatdGS+hgHfPBIblM9+rkIoZkSFBZNmEe6a2/ZEMS2Wl8vsatDiYjdSHiCE4ZR8U2InJe8unZ0CV8Hf6ShFEKL11etaKSDbxt39xoBFJq1HR1Nc0hzgxjiQGyTUKWa7iSXslIunGMVKUtDxGzScWQ3WEtT2PjAOdsxX8oFFy+EeCbu9kxpJownTo8PzNMFoZoWRUx4PIyeIXpC8NRqrkn9sNZmS1xdQZdmSVkS6fxE9pW8j3gtDKKkEGyyRPXooiv1ar8PlFpYlgWdJ+PCtynkAL4t0P1cazWnOsmm7bDOnHVzqpPNdrMqKjavIIvgRXGNv+udw4XIkrKZVOSESCU5mKaZZbZpuFS9KkqtkuzCYWnXbVGhJHON6sJjQ0TNoSXlwvkykyVQRRjHHbHFynxJpGVmXqzlbIP8PKXTIEOAEE3vIkC24mVxExPKpEIKB+p4+31D9d+6TZxvSX1gGHaEYYf4YHzjolwuE0tKlsh3q1mMOqdgVAO0FY/BmsyY937VNhvGoGd8HHAhGrXN+Y48dNcKumhXW5L5jMsKzwsHuSoDWgtBYUseG4jTt+9M9eWDP8iH32+/WFlIHyT0v2zrxJ1nhcIvfZ/r/fhllKXv2v1Opf6wyLh+9gefoT2s1jXLXu/ZWsuW5F+9sa0THexq9uSy0aNSsinYtVnx98Kmd9ENVfc2IK5YjtEXAHGO2ITGPYasAOC3PpA9x/VCQbpw2jEOA1DJsn0+RYxVUbZOxPqCvYPSL4L2nhv4uJVYra5Z96HrFvs56I/zDXgUL3avYPqWtCRSNkBQxB63aUgMCPZ+W5t247BaTVsC3MTv0wXxF3yIiPNMl4VxP3F+eiTNE6JGMVXvGIJj14s7bxSwUjJOm4pPrly4UrIivxbSdGGhsgTT4RogGZv9fQUptm8+sD8czf42JGaUmrOBXs3ExMymbMCiNoewnCve1ZZ/bsfZyxVdsTTGhrRhgWIaiOA8LjokDsw5kZbaBv8qs3PkJZFTJqW8UrDgijZcG3VctTlKCiUXu/5rz5Rtx7WaI988LaQklAJjHFca2nyCpWoDcu294hBtDXeuMY0iGnbWJXSZmoXsZhapJGaqG5D/NjUaEgLm8u8Zjre4uOM8FR7efMGSEiXPaL7g1LEfdxQJZPEs50eqKqMm86aPO16OB3wA54X7xwu5VqOc7AbC/sDNy4+t1VyV/DgxzxPTNDFppgoMuwFtNoLvvnnDbjAqUUqz6TEuF6NL5cRSMrV58z88PBIbd+447Izb7YV6ulhgCtEWfjHhTG12aruDaSxqyozRU9KFf/WHf8Dp65/hKEyPbxGMMpVOi1F/cgWfcE6I+8Bw3BF3O44vPubxfOb+6YmEtazmgnGHEaT0wNHEsWIJKs1LO6vifWwB18JDvxHWqqMvjGqFF2pdjqpWqyNqxZY2riibFqC3p1fBXE2WHONJZTaamRiCZ1a8hh5bAuY6DERHn0y8ZDSStMzrjYnz9JVW22yLw37gxc2Rm+Oeh4f35GWhLpWgFujjELi9eYl3jnfvvyEtmZQKOdu+OxrqzyYMFfEMw0AcHMPg+PwHv4H3oS0qjU5dHV+++YqHx3umy6VpkTyhaWvyXMyBi643sNt5KUvvOts9IiZi7u3p0BIW0aYTEUcMA45M8J67m1s++uxjdoc9Zc78/Bdf8OVXX1GrDQGKwZHnaV38YgxmwnA8cns4cBh3vHl/jxM4DgNFDTFJJVGWExV48/SOEEd8GHjz1RuW6UJOM4eDdY5eHG+43R3YDQOXeeZ8mXg8XcjdOKBqsysWUsnUYAMQL9MTZX4gnd6xzIshNSi7/ZEg3qaOEhAf+fizT3BSycvM+2++Ik0X8jzZLA5Roh9WN5VcCkWUqVSW82KXU7Mv9QhVavMDt+uoB343eiTYFPGXd3cc9gf8OPD2/h2/+Por60ikilZPkIAbHGXJjQtdkVBRKmUu6/lUVeZlIhdlKXZZl2qdGgRcrlzmhXlOlMczSQISIh998inHm1v2xwPvv/mGp4cH3l0uvLq7Y9hFhqPn/nHmspgLUsUz18AwBHLNnHPhqe44i5BCZHIHznL8vqH6b93mw2iD8UJk3N0S4kAuwk9/9gXTNHM+n9Zk66PXr6mYxXoqudHxMrtdJLiB2/3Q7MAL59OTLd6qEANuGAj7vTlKIaRSjepaCqnpx2zijN9mO3SLlt6x6EVy+6cnJtu/lnhvTYQrCLpv+vw1uHruilY/Q/6v89wGFn1QZ8iz97hK81WfP7//dcttV3Dq2e5cFQidftKVUys6c/UeG5XpqiC7WpO6i9VKQa2VUjvd14oF0A1gw7oOfQaFtDWuJ73IlQ24WIzp7+fcNrNGG3d98I79buBmv+dyPpHUOqpePD5E9vs9h8OAOOHx/oFpmpnnpQmL+/Ht5Uu1gbbOgDJ77p7PP/8UUJZ5Xg1UcJ6f//wL3r2/Z1mSaQ2927ou3T2wQ139+JDWgsuh9qB1nV8f3YqGDv4Gox86zxAHPvnkY/b7PSll3rx5y7t37+xeEgjBk3JaC5phDAwx8uL2yH4cGLxjvpy3UynWdZqWGZxDnOd8PuNcRFzg8f090/lMOp84jEa/enk7cjzsGIfIvCxM08JlWsjJaOalqrk4SWXBBjojytPjE48x8HjYr3Q2F/aMLhCAqZ7MYTMEbu/uQCt5WYjeU5aZNJ+NcdEAZhVwqiTN5KKcLgvzkleb6trcycZ2Xqqa9riWZkgTHOIdh3Hk5vbW9CnjyPunJ75+945pmkg1ma6mJf3GlJeNbtdsZLsDmqbSwC8DKI0Ro6vNfa7C49OMyExOD6gbcGHg1euPuL05cDzsef/1l5xPgQct7I9H4hAZDnsel8RcleQiswxc3A4kklh4yon3KTCXSI03+N0tw+EFv2r7/oXGuCO6gAsBHz14JWtmWSbmeUFLMjFNiNzd3lrC7iPv759ISyIvjX+MwrCnpEpO3SfU0IV5SZR6ZslfWdu2ArOhkblkZjXkSQp89skP+fjjT/j9v/f7/NVPfsLXX31tU7bniSXNLGmm5GxcP7GipgvEkyrLvOCT2XGqBNOBDI7qDCUNvg0Ya8mjiE2Hj65S84Uvv/opNT8yRs9HH79mvpxZ5nn9PBLgkx98wrAbKaKc08xSCm8fn6yVr7bYFe1VsdmtlmLHQhq9SWniMl2B+609LN15ya2C27UbQW3e3M0is8UaW5zMBUtzQVrSXUqyC1ghp20gXWlJrlQBzNlqd7QBLgI8nJcVVV+Dl2q3vCaEzqkHfABvxzOMOwu5CtM8gVb20bMf7OviIDlL1msFSiXNM7qP+BB5+eLI/f0T87QwxG7p22x3nWMYIxIGxHlqrQzRs9tFxnE0C7enk4mn93tevvqYS1mYloX5MtE6xaxFnJrzDCLtODYRs3NEZ12xJdlAuVTqilRu4uTO9qnQZje4Ru97+1UlxghFWU4nAlAdhGDCda9xFSLu9ua8gVbOpyem84mn82RWntigKltiKit7tyZKAaSgOoEuOE34Ar54pCQ0z0alKokgym4IXJIV/0speN26WmaN65mqY0nKXBfy6qxiDkkMI4fXr80isChv7i/UMpPnC8t5QotR0vocgZ5IlGqDxwHIbTAXpokRseJxPw4r1aHkbLS04Bj8YNPmVW2SqczEtgDvd3suutj5rNIWUzWbUgz5CaXbP4NbJ9gr4+CJCrEG5lTMklaVXJTU7i/feL2pzb0ITkww/pjRy5mxZF7vAgcpBMMfjFbphGVZcDHji1KKMCXh/Um5ZE+pnhiN4lbK/H1D9d+6LTQXqBCi6d0QSm4obEML4xAYYmA3jo12AafzxLxU0rJZ2ubVkrRxN8SojkvJlGWjPIpeO/RUcmkOctKBFW9DuTrevCbEz5H7Z6g3POto9NT9GcVKt99/qykhFuRX/cPaoW6vK/beH76n7cf16zzfoQ+7H3r1BNUPipq+Tn34nKui4fottK1Z23vLukPXMyF6F71PuK79e6wPJC3WhuBXZ8zcXJ9qszynPcc0w8a37++3auNEGKIVDKhwmWdqrQQvjNGzGwPp0mmsbV+K5UH7vSf4yOG4bzGiUGpuDS1zA3DOTF5i0xWVUhmCX+3JS85cLmcOx6OZbbx8xdPpwjQv3N8/QHd51AYK1moU5qtTZ0Cb32yA52QU06zrebFhhdt6vfq2V7uul1J49803PEUznDk/PpKmadUIDrsBv7RhgFo57EZbx2phmi5Ml4l5nvHe9IRxiKtlsbZ7J80zPlScK0ZRzQu+zWnw0nKXWqA6nNp07GaC25gRZn+OCPOc7ByKDaerGcqlGDimxsvY3x7wMbK7HVaN6GUp5LQwX07k6YLW3BIOu7KMjdE0lq0WVbTZ+/ZjbQVjDHFdm3I146EY/aYLbucrF7sma+u2eOfX9U2wAtMmnndd66Y1cs1lzKtbKf7ee1KpBvqqMUaSVqRfe22eg1P7IifqLNRlxmle8y4fPSLNOQtjneSqzNl0v/OceTovpKwonv3ugFY1w5RfsX3vQgNvaF2MgyF/NTex1EyaZxs+F5sv8GFPCAEfAtP5ESkZqQu5WUGq7iilNregukadlDIpFy7T1GoPwWUL+kpdKTauCnd3d3z26Wf8nR//Hm+//pqfTRPLNJHSTE4LOaemMygE1zmRTeCrypwsSQniGXeDOT+ExsfDkMaG6Tdk3DjfXiq1LLy/f4Nj4bAbOd4cMRFX0wrYPczxxS27455Flcv796R05mk6U1SMw91EznWNzr21pzYW3rn1pqxX02J7KaF9WJ403+1GMuvuT7oOfGht2HYjqjSr4ZRXSlXKy+qWklJH1MzpCes24pwSoyNIZIxGK7tMiU4VoP3rHVZcOOO+9wInturcO7VCQNogmbKgxWyAh9Yyjd4GQkaBLFhATwu1LAjCYT9wejJ+a4yuuUyZliF4MfR/3CHeM10mQrBugHOOuiycTyfG0a7TV69fc/Pma94/3PfTQK19YW5FRy/knBUbiC1WMQTGEEAXEoXe4Ub65232dNU6G1ILwThR5PnCY7b5MAFPyhnfijQvEMSQEG2IxjAEYgzUXFjmmZwK05IJw4AfAoNEQEmdK64taRHFROcJmx5QbPp0MVF0za5dg7XxYgNzSdAKp6KmHylqST9OmKsdc8nlap5JYCcjIRzY7V+Sl0xOC+eHN+R5MdpWo4YZzttCtVpHrFQld5ROm/ASGMS1QU6OMY6oFooT5mqOHMMQGeJork46k1NmZrbrriohDIjklaoXmrZI2n3qnOBrXVfpjojWgoEqCFUiIguqFtBzNeG/p4s5jdOsxQwA6jKTaoVpIpTM0ETmUhXJQlAIIpyXhAwJlzJI4DJXHiZbXL2LjIMQnUL+daHxyzZpCCmux5NKysWEvDkhWCyNwe4fxGLSvAjGzrOFtGLUDAuTuiEEsHYsrmffXAt9lZYEOBDvLKkyfsxaGFwXG7TfPSsctl892/Tqz3zw2PV7sfVSW7FhP6/fYqBJf/xfT5ySb/1Rr97qam/7brSux+r4d1XM9KJk65Dr1YfZaD5rl6R3P1RXitPq/nTVzair2YSdK+fMdSy2eVROXAMqdAXh+m76Zl3v23pkK3y1zr0TxnGwawrIJVOyDdWNbW2yRNio10U69Wqh1h2CZxgiIfhm522fqQvPXaNZ7cYB7z3zvOC94AW0ZFJamC5n9oc9IXhevLjjeHNk9/jI+/cPVIzj389Jj2myvRVgMSl66zJormY93zpZIsbh305gAwntxQAll8zjspjAOw5M00RJCRfc+toayhqrY7BCXqtRgXIqTNNiRg0h4KOZ4is9n6G5jCo+1KabzVeuge3+qtZdFEyE78XWodK7Bm0g5jpbRIRS21C/pTDl0oTXQpRIGA4M0fKaUgopzyy52FDPlEGL2eo2LQxrkVFXALLrKtdVT8zKNoSw2RVrIXrHOA4MThptv1KqDchDZBs06rZOpLOKw9xG+8G9ult7MeV8c95CcEFtLEPKRqNSm22htZru2AlOutYmU5NQpKJ5QWphjJ4YHOIh19KMTuz8pJxbA0BZpj6CwiimN/sRL5CX6a+JJrZ970Lj3TePZtHlHMG9BWxKtbYhFE5aRjgLeT7bQS3ZEnatZBJhZ7azT+lCLx5oJ3VwDjSDSgsAzRKPrgdQhhAxb+aBcTjgfWC6XLicHrk8vef8+ICgBIzmocUQxkWx4XReeklqibAqkJE4oF6ZcqU4Z9zaduP5qhTP2h5ulwxZKm8fH7k/PTGGwBgHbj75lBi9+RXnyr/6xRurqL3NwagV1EcKNpQO1/qe2hZIFG3sI22TJ7tHdbmKIrXa1E4nbk0o+0AvgVXYVkqhmt8VdR2cZ1a49nEUptSCdbcD3pw9BCX6Ji8J1mESlJoyGvfgA8eDGB+xKLUmq8J9JQZb0I0jnVmW2lCW9sq5IN4QqMF5Sq1M05m8DLjsebkbiLVAdqg6coVLLtTlwkzifA6klPDRkXM7P96TaqECMTjCaM4Py2VBklLPys//8qdM08z940Ozy4M8v+PuJvLZJy95983XbdhbLzLttfria/Zv9v/gI8fdwO1hIAbHNCXKfMF78EE43gx0ysTTY0Kw1s4YBpvcXqzzVrVSwkjJtbVBK2VJFCZisAIzaUZOF7LPNihTAkMc0GaseXk8c3KG9swFu79U0ZwJwROjR1NFqzRuuVATPD3O+FsrtKPfYQ3YTKyZJRXmxzM402ctVCy1DgzjDdUpyVVSCeaiNB4Zb35AvLlh2HlzlqsLLz5/wel84ps373h7OpHyQs1PxJLwWnBqU0yLGp0PZ5S72jQnqcIuDoQYEW/c3yjC8ZA57Ec+evXKbLKXhfdvv+GcshU2D/cr8jkvNok3eBMQOqDoQmyLl5ZilBVaAdQ6GnfDgTEOqINTFE4DfHNfLPQLLApSKyEtOAJSlbdf/YzDzjQ0tVqiq05IakjWaX5groFUA+dZOE+V90+J2UzjkCz86NWej25v+d0ffsTPvvqab969+b6h+m/ddrqcGxLoeDpdrGu9tO43EByc8sz5SS0ZwHQ4paGjzrPajqcOfvWEwdkspT5kKzX0HFpe7WhAlFWu4rcEs9tu9zVHf0kVsf5evv239Q+y/VnaS149qP1+lRrbGgdbV+NaoOEEUf3WW/bXrLohqLS1sz/guwoU1Y5nbdO+V8H1VcGwFQ26rVttzZEOD18VGrbbrXjpZiKlXn2MBlU4afOxDKAx0bbF5pxML9n1HCLakn5tjlIt7rR91SLUmvHiTS/ozXlParJOsBaGIOjOQKs5G7AzLzPT9EQpgaKO8zyxlLzqdGrrguEcw2iuTM4J59OJ6qyL/e7N15wvM2/fPRhzpBXGx+OBu9tb3r55Z3EK++zON9e+blCyCvDNHvyw23Fz2BNFmKcF8gW8dXRvbm7seGrlcjkTgChiGhRVlmKMkNJQN6mF4M3kZZ4nckl0xSgo8zyZO1uw7uKwi6iYmc3D6czD2ZLRnuCXlmfY2hRWQMwFM8xRLThX8N7maAxxZBAFGVnSmZwy53mmNNl7bcfWaBSDdS1FyDogPhB2R7h5jb+5Zb8bGgCoUBbm84mn+3ecHt6Sl5myTDg19yaak2etNiOk662q1m2fvSfEgB+GNrBWiPEl+3Hg1d0NXq2QevvmDU/TTHo6Met1RzSDwjLP5lIlHRqg4XD9nmkicLXcdT8Y8O/iyNO08HRZyE/ndQBkUgNRcgVXbXDs4wPkIZCiQzQRg3W/5uVMnirnnEjqyDjS4jg/XsDfIzJaYVUrP3h9x93Nns8+ecXbb97w8HD/HVHh+fb9qVMNQae5MCDSRKuGBLp+oyqUrC36bNWYMax9C8oOk3br2k7bbOfWp9hj/SY66pWfDSEx5HoYAkYtWBiiR0ubClzafVAd0syJteg2fAajmgxtHoG61cR7/bIJxM0bvZ301oRdL25pN0xSZS6VUKIdg6qci3HlRBpFSizAlRZwuQ7g7XDVFjRox7E2RKb2QXPtArVg49bnlFzX3V+dNOpmgbclztuKdR3MXUPfaLzA/maGg9iFPbRBLTIM+MHsVV+9HAliPuCn0yM5L+QyW3GjSiU3FLHbDtr104+p957DzR50pFLAeS5zwlWIIXJ7PEA1cf5YCi7Y8ZqXuYmfTXBlp0dt4Xc21dy3Sr53eASQmvFi7hZeFNE2nKjZ0JrrjCHpMXhD3sWTZ6vqVQxNQYWcK8uSuUhzLPOOIRjtyQcTxuViwuZ+ojQXqqS2R7Vd094SlGpe2yUb0lOA2JunGZLYELF9PDIOe4ZhR6mVyzxx//hox6TRPzpySbsG0IpX10SATUTvzPlo3B+4ubtjN4yczmeWhwek2wQedit6T9E1uNqi5kAjPu4QH5Fxz1xB58Q8PxHrzKALwVeWXHAR4jCaSDoviLPBaLE5r5iNYruIvaeorFNdx93AOIyM445x3LHf7dkNZm27H0eWy7m5mQlzNiRGvZgOp3UOVRu80eyT1Quhea+bxbU9SJtA3Gvr/Lnc7hEbfoQ2i8FGA+jJYhBFKKSspGT2u6rmMBJjaE5rhVoywZuoODfgQktC0oKosMOzr55ddoTlzL4mbtx3pXi/3oBWJFagozR2X6+hHIuJqkrud153h6LRGvvgswa62Iyhtjat3W1Yg6ds6HH/rekvms14Wyd7LG8XyXck6t9xXq9/db0gXsXuK4bRVsz0236rEa4KiiaQbq91Pbl7Tebbfl4PlqMfO7j6LNe7uXVotqLiOjnSdb3i6ne9w9HXvvUz9UKDDVXuRiVcdfVpxbudHywpD45h3LHb79nv9jaQ0T4s59OJXDIpW1eytgG3KRdcrYZ69zlHDUUIwZJ8tBKwafApJbxz7EfHOI7MuZBLZcoexGLLkouh9R2NaB+wd11863y5Zg7RjUpqiztDNLMSp5WldYGDWMHTT2+MvlH4hNwGwJWyXaUpFRafmH3Ai3VcvRej6gQz/yi5TYfWTThc8gYyinOt4+vaHK5KXuqKdne9QK3KsmRqhWE8sNvtGIYdORemeebx8YmpUdAUNmevTtfSSnR+7Tz2OWcikd3+hpvbG3a7PefThTk9meVtVeJYkaabq+14r3W9CNr0MxIiYdjZeZouLMvZkFw1tkvNCSc2sFaweOIqOC2N8pbZKP6CD6GJ85Xg7DoYo73Hbrdjv99zc9wTg2cMjjSd7dgWJedCSsVmp1UMgDYMDKeWa1a5ikfOrTR0kWbnD00f0ovjgjSNJKrNyfOqC1krQ7R7KZVMKJgjlVjnxMWBUApaMi4VRj8wuMgijqqZks4IS2MAOWLdEWrA54WRxMFtltO/bPvehUZP2KR9yAb2rIEBrWblJlCzdTI2ZwLBSUS0tTO9iZKr2vTBvnlvdqzXUzF7AdIiRkvOG/8tuLU6rTVxGAfSkplTpo0oAHV4Xw19KrravVVVc5HYjeg6hKyhHb3QaHF9cwERE2irWdH2v6dSzFuzKt7FflWQmw2bCA0tNeZb7ReXWyM0tTYrznYzdgcNbcepLwD1SgR3XWgseTvZ28LREkOFbTJtxfttIej2ttecXu/9etNmbRZ+CuMw4seI2w0MhxsOhyM/+vRzduPIECNff/UFl8uJ0+meZZ5JJZMUdgKxCuqVnMzhwxA3QXzgeHsgBHMXWi4zp2lhHwIhjOzHPdRNW3NOE1NamOfZJntXpXarPW22qUFsqE5rWV6DZYFqE873kSiC1NoE5TaNtee5UZR9tGs4eM8pZ6PMwHq85mROVXkp3N4ciN4b1aU5OI1xQKsJyGiBVXM2VBQsIQneOJ4+mNWCOLNHbAFjnQpbYKFQRIjjjuPdC25vXuCd4/39PfdPZ6Y2Eds6Fna/emk6m1rxITSr3WCFjRd8dOxvbrl79Zrb4wH95hve3d/jgiPKwG0InOcFyZk092tMsOA74nQkDAeIA+z2XHLhkp/g9I6dTuyYmeSCiyOyv202kJ56mUAmRJTBO8h2fYYgVvS7SKYgwG507Pc7GwAVd7y4e8nLV6+5vTkiWsnThObCsiSSwpwyS0rs9nsEc+nolMlaGk9bLI5V51EXKCo4qbhqQ7dMvO/NcrCJ8BQQbxqASru/271ZqyLOHKlKpdFKKw5zvxqOR5ba3K9yZRx2OB+hWOwpmsnljFe4cZFdcsQpU+4LQ1q467X/r7dvbdqdhsSuc0GIvQsNazaudGpqc/vprkUieNy6roGjTSRtv7Of1zTug5rjg72h1tLub7l6MM+///C58q1H0DvNbRc/+N+iWherV9XVQl16wXz1NmvXpf3UC43uOrh1ErbJ2awFAy25/HZCsRYL6/3Vk8irYqM+Pwa6PZP29O3F+jmQrUPT6SJ9//u8X3X2efEwjCPDENnt9xyOt9wej3z+6acMwfSXX3/1la1N50eWvFBKwS2CX8wOu6q0YqPXbEIcBsYhWnFApSwT07wwetdmig3MOTf0WLl/fOI8m3V2yXXFeuw8aFtLLOHvduXBNwaHc9C6Bod9ZAwep8rl8ZG6LDitBFipcPs+O0ZgopCx7mpbapiXbO+qcDNG6947Z4Y8je47V23uWYIWyEtFNK95TR8a6nwwilOtkJLlI1Xb3DPTq5VayFW4C5H98Ya7uxeoKg8PjzydzkzzQsqZbpsO4KSCOrRUwmB5WXBtwF2bgH28fcmrjz5it9+h8ob3D4+2ZoqwE9cs6itlymYSQr/vBMQTxh0+DIRxJKeZnC42pyMvUBP7cTBWRYyMccCLUJfSHdQxt12zQUIzLghxjLZGIwwhctjtGOMAYc/tixe8fvWajz96BVqZzyfuU6boRMpXecYQML6J1TAOAeepuRU0QQzUda5pvSqQbWgyZq1f1QoXyXbfibYuDVAaQF4raFZcFIITci0kdXhVvAvEEHH7I0NVXEqkKRPjER9H5gopZ1I+GwgqgneBkAbcrJSzI5YLNz59Ky58uH3vQmOMWzvHuxXLWMeYQ7MAE0CHFc3ptqwqJvARoZ006G5HPYBslJ3niXD/HinWzhLBhMmV3eC4OYzc3exJ0wXvlf0egh/J2QQstQWztSVVlRg8+3Hk5njDuSS07dMqMqu1uQDQuHkteIuFP199sz3sHR3jOZY6WxqpwpzS6o4jbhOsFTWeIY03XrIJQU1zsW3W9bDg61x3OGj2myhuFYPLOizPiooe2gRxXQOjV4vGc2QJrtGo7Xwo4HDsxpG7m1s++/QzDsc9h+PYiouB3e0tToRMZRJlEcAHXn58h4jjeMq8e3riNM0QlTDCDuPGhiFyuLnh5nDEu+Zk1ChYw3FgiMa9X8t4Eeq9zWepTQzhhDZTwzi0h8aPpfniVxGG6PAeqlgrOBVlSsrTN+9x7x75xZv3zGkmLYkyFwJGYXM+EGJkCBFVR0yZOk+Q7TVSVrJWJoX5tBgS44/WCo6R4o5UX6ghU4M2K1S4lC5mLHhngV3d0iE95obuV4WpzWDxzpJXnRI//fJLwjfv8H7gOO5YUuJ0mQxJq2o2wy0BtiAFaEGqCRFvdnvUG7J1OOyRMHJJidM3X/H+3XseTidOl8kGVzlHCObadXADy1LNbSQr6gsqiXS5wBKQZUDIUAv+8gSuIEE5vtihksnzI0MdCSj7nRI0WMCj4EaP92LaKqCIo1DwwXH74oab4y0xjjy8P/H+4YklCafphJeK5BmXJ0QvRBZGMa3JTVBSrszYwh+9Z3/YcRgGHMLT5RGvGXJmiJHqHMlBmUxrFb3RIhxA8kgcceOe3/m7P6bgmErl7f1bck4EJ7y8u+WwGwlU0nlmOS9U8Rxef8Tv/J3f5XYfqMvET//0TxiHAeccbx9PJjJPCYYRTYl6fqQ8PfLuBG/eAHFno81/vX3nFkNT/EibmtxBoDWX3aJqN9hQ7cRdrh7fM1hLnF1L1MxIoYM9152M/o1eJfHQXf+0636ut96UuBrg9+yP7fXWl+qdkB6n+z8tEe/6hdrpR+sTnxcLtk/9uZ2eshUa2/73DkOjQHVdxNU+XO/rsz3V3m3XZ4L2Pg9Ars7NdWfICatWUfr79zVzfX5Dz6+Sd60Qx8jN8cAPPv+Mm8OB4/Fomq0wsL95gfdWQBIfIBf8kDmMexTY18rD0wkuMykr0Qd8GFBM8Lw/7Li5uyF44fL0yJLMLnnc7ZAQwAebreIDr44HCib2fTot63XUZ3R5EcYQicGbYcW8AODEU1VYsiWNOWfmOfPFV29w/j0/++Ib5qWQUmZJmxrOBpcKQxwRCeRcqBebC5SruVPmpM3kpFjBHAZk3CExwrBH1VPVoaGSqxl3nHNq11x5bgmvdi3OK6BpFHUrZsTctUriF19+w9v3j4zj18Q4sKSFp742NaOUraBvOQ2FWhzRR3bjyLgzC1bnjMnwdJl4PF94+/Y9b97fc56XZsricWKuUD7SittKkQWtGSWRpkRyHqaAa2uTpjPRC4MX9rsjgYCrGd9maKivzZLeEby5RTocublILWmxa8QHDjcHXtzcMsaRb94+8PjwQM2Fy/mEQ9GyIGVBKK2wsq/DLhCK4hYhSyU6x93xYPPSBC7zRBVjzqgYdbyWNgQYKyrnCs5VvIvE3Z7j7Z7b37oli2dW4au3D6Ql4VFetbXJldnsf6cLg4+8ePUxv/t7v8dhvyMvM3/5r/50zZMv05laPDV7pFRyylwuT5zfnpjee87v96gm0A6//vLt+3c0XA/cTTTUoPKOGFtKanWXuOYsACtcYcwcixBWddctYrAFxe/aeoLc45Ngor2SzFXEidFclnYSRdtAGe+o0ZuTk9rF0/dnHMyfWZwjL5WktQWKVRNt3QQwK7v+RQvw2qzLsG6JHQdFtdB7PymVlcbkXEdRG+0KMAqKtTxrLzQ6usRzrqyuzKmrFq9IO4Taq7N1/2zxW48gXXi70ai2Y/vdx9t+730g+EAcBmLjlh4OR0LwJmYr2ZCVhvLWVkTl0qprH8AFS0hLXqdOeu/bACJvi0c1Z6fO3+zDsnIuqxf2sB+baN9xtS6uJ0pErU2MtXxzyg1payLO6sjZqEyp1GaLaxa53RpWGz3KCsCCx1kL1jk0eIYSrMDsfNiGhC3ZRN59TkdV1xCWpox3A6rZ9BjakwOjpZlXdwEx4XehmwSwOmmBCdBMb5BYKIgspuVoArzOQ+6CSxG9Sp4A10R/IrgYmkgvUlCmJZHmC1NqDiXNOaPkQsWCftcR2b/VHDqkXfPappKSEc24ciE4IYpjF4NdG6kg5WIBIC8gxm9ckWKh0esEMzgw8XTnzPfWcE6JM2cKE14qoSZuBrOqHqKgCYIKt4c9S8qITqSScEE47AZu9wccwpIuzdHLtGC5QqrGhXUizSXNW6fWCbvdgf3NHS9ef466QMKxv721mT1p4e72ht0wUNNErSdIEIY9w/GOw91rjjtHuZwY44hooaZEKAkvyn4QvA9kVzlPhZQzuVamqvhScfFXB/O/rds2BK6Hzu7W0v7e/pGW5CoW4zc5rK6xs68PWy2hHT1bi/e1SLi6bvv6pFevuemerwoRvXrP/kbXSfnVPlw9av2dbi8AcKV5+KDYuXpcL0TWz8h1AbEVGiLX79PBJ13Dx4dLxfbI7X37Y7fPpc+eIN86MbRfbha06591e+3eT7qmb7k2CX4YRnbjjt1uz35/aNOxzYmnNDpSrtpExKyfVXyAluiXWpFGpfTO2Rwn51FY1yNDd8s6ryjlQlEljsq+db7DOiR3TZFWMNZJcyvLZkeqatbcUkGKDfrLpTS6bUIkc5myUaLWc2mXX6kVXyoaFBHX2CWNWibV1hK1fV9KB+J6t7g5arYkVptTW21i5fV6MnTWJlu3a7z2c4ABtv1+ssKvOYeWyrwkhmFogus2kPeDU9+/3Hq92k1k3YzQbHwr87I0UfJi56IBaioV503Ef7WKtFu0CcmzgjNnUe1rU12IwbOLkf1gbl+1pmYeUW0KvGZbg1pnTsThvKXL6/wO+oyddrK1UlJiupwpzUHLUTmO3lzLhkBtQ0GPhx0xGbi9pGQg2BAZmp1nqclMXTDWhjazlKpGZQtDpM8SQQLj7sDx7o7jx5+iYSC5SLwxylqeLry8ObKLkTKdAHM7i+OO3eGGmxcv2e9G0nQhjiNlmak54cnEoITocUVYfEWXynnOzTAo2Tysb7tHfGv7m1OnFKiWwEnvYbaXUjyKw40tqLcbyZIEt4qUu8uEiKEW11FM24m0v8sz5N1cJIQgkKaZ89OJh/sHaikmPq6FsmTqUghhwHmb9J0mhWJiJxvoo9ze7MBFSoHT2RxiNNg49o7M9Ks2122Rrx1dCcW4wc2KwLQPjlK7O4yARgtU0qahcxULhMb/a+3avkquQd9ufETWANvRhd5dca5pUmq1G4se5FsgaMfPCi9HQdfhSMBKm+oLVO8e5ZzXBWM3RlyIEDxJCkms7adqPvT3Dw8cxoNZnamnqGNKyunyACL43YGZQvLK/dPMbhg4ykAcdjgR0pzJ+WQB5fxEmidqWtBikzqX88QQIvvDno8+/RTnHXEMVvh26mS7fGo2RzLvHR7PNJ2Z02KdtkaJm2ajo4mzQY1USJfcFO9bEacF5qeJGhJuLPhhIPrAfgCRwuwqU8omRBRHWhLVe6IL1OKMv5+ySSRUCd6mmiemtUAVZ0VNlYYKtcW/9gVXbTHoPEXV0hLtghl02jGyS9DskQX7vhuekMsWwwXUZVLN7Abz8tbBM+WFaakslzNzKhAi+EitmWnO0FwlJAiIt8Cu2YTltR87Z64hruClMPqFQxy42QdeHI5m/zufOV/OpLVF23J559riig2vUwxIKIla4Pz4xCgeX5SIsOSFyzzxeJ/wVAZXuf3hJ+x2IzeHkVALNRV+47NPOc8z7x8eUd7hg+fV3ZEXdy8QhPNyMuvtnJlSJpXKVJQxBnyIhJ11p5x3JEm8/Pg1n3z2Az75/LeJ4w1uuOVymTlfznz99RcEHxCUh3ffEBKEDDcvP+b29ScMx1domcllJlfh4f0bpvMDoxiS9eLmSNwPXC7Klxfh9LRwyZkZB1OG6UNo/Ndb3/wVoGKI4Zbebims/XRdWGx/34pzesIusha9GxXper27LlKuX7vXJdd8f66aFVcJEVvStoqoOxB0VXx8WGRc/78a06BN79U+aauuLB60Yr2ue7y+bx9QKm1R+qApsnbV+9FaKVvrfvPMNYeWTDc5Hle1wlrw9R9WKpQ0vSG0TvUVsHh1nFQ3kbmIMESbBbQfR+tGOE/oSXNV3t8/NkCocl4WlpS5zAaOiAghRlI2h7JpTgx4fFB8DCuw8nQ6U7VweXxkOtv8Hy821DQtiVwrh+OBcbfHe89utG6p06048Bi3XRS0VJacG6BWzVzEeUOtu+13v960FxxG3/PO24molbQsSLXhpM4FtOcRLQ/p9OcOZglNsgo2jDhXm5St2JDg0kXP9aqYaPeDOdOs17Z166x7sw77tSuwORUVdJoJYV6vW1tzZRPwY9Qk7zA9Srt3a8kIVmwMzYo+nc9M88y0JHyM1MvFaNlZkabxdSulFevS9LWzJsykIeKk4ClEV7gdI3c3Iy9vRlJKPD5euDw+kZIVdkZvs6PWXe3izoapFrB1t1QeTydz4KqKF6XmhSnNPC4z3sF+8Nx9+pphjNS7I/vBkXPh009ec74sRHfiXDPRe24PA/v9DkTIdeG8JErOpJzWrmLBHL4OL16tSgKP8OLVaz7+9BM+/+3fwe+PyO6GxyScThNf/OxnjN7hqZzfvzHtGY7buxtuX37E8e4VTgtpXlBVnh7eM50fOYyO28PIi+OegGeewOdAXmYuOXFJMyGYKcGv2r53oWF595VYWwDvzKNXMaGoWOupudiiWtdk9pqW08XHq3f19WZZBteYVFW7KX0YqChzSXzz1TdQKl/89OdoytyOO97NiVCVEAM52wWzqOJKMR9mhd0QiGPkeHvDw9PEN2/f8JQzqdoN2MXpwFUw3W4oY+xhmSjNVs5tKEmMcV24tLbPvk6vNrBBnf2gnRNaP3D6eHY42k16VXRdt7rXRateoQQtqZSGgksruG1vHPkDdOG6g3G99WLPCUitzE9ndFmo82TPqZW5WxG3x9vQNbs5VIRR6zZQqJQ2c6VSy9x4o76J9St5OlMXKzJqsU7TtMCcKpnM4TzhPEQiuzBAyUipDLtxLUJLKUyl4oMhEDsfuORsAaJiqH47Z0MMiCpTyjiv+OC4Ob4wenatlHlB1By/vBcLNmIOZb4o6h5xqHF4d3tUK2k5UzXhsiFiuQ16cy7gg3CIAykrteZVi9EXFW1IaSv/UOkUhPYY6faASucyR++hVqoZtiFi1ovRCUGEvXMcd3uO+z3O2T2YilKXmVwLrgRym56dW3u76xhKuye6W5a0hAqBdVKHgqhDqrN5M9Xsc0MLFEUrD9OFeU48Pp2YLnNrobvWyXJoOHDz8gU3dy/Y3+zagqXkZSYtE0/vvrFhT9MZT7D5GL5NiZWKa7otEcdhP3KIEakmuqw5Mc1POK1IKeTzE+/nGVU15KYJxQsO9Q4fhN/8rR/z4vYFr1+94uHpHefLE+/fv+Hp/TvS5czTm/eE4UjcvYDhhjllvvryDXEw/rWURPCe4/FADELJE+/efYXMJ+bTPW8fv2Gan6h14eXNDced52b0NleogI47M4JIGaeZ4MyH/dfbL9muEbWrOOZ6wdB+bYn5Csc8W39qS257XS8rIl+bkUCbLdTuQ3urb8fM693olt9tJ7ci44OuAdBmQzwvLLh69rMu9JqIbgUAKE4tu5f+mOsXwJB1RJqwt8f97g5F63fLttftudfdEOlU6KtE2uoq6Q9GMc3h8xbIc1aCfQRt4cStCHGfl4FCbdQd3DYn4roAsQS1UvLM+7ffcHoIPO72TQcgXC7TehycM/DC3JEKIrDb763j4QOKIdqqZ0rJeG96ikozcMiW2DsR5nmhNE1YqQoycX//SPAwhIExBkSLzTJo3WDfQUHXnDvH2ICvZN31Uq17L000Hm1ooJSME9Px7cfdqstY5ot1EKYLu/2RIUY+/uiVvU6tnM4XSnNg3O+GBvrOTOcTiOnGukEGzdY3ikfVXDNL71TTitF+b/Sr2bXSej3F27leC962BqwztkQIrpkvAKP3HPY7jod9i2/VRhIUm5iNKEtbl+YlbSY43uOqot1NTGxfepFudPamrWr7Zl46JgCvNZGDkIKwRM+yWBciLzO1YnbozoCGOEZubm65ub1jPB7prAMTlc883r+HqlwuZyK6zbkoJs4OVLwmIrAbPKIDJZpex0YiGM2rUliWC6rmIjnP5h7Vp5Ej5hb2W7/7O9ze3fHq9cc8vnvP+enEuy+/5P7t1yyXR+4f3iHDHnY3uP0r5qx8/eU3DM0y3+UZVWG3a2YyufD1l1+xTCeby/X4SF5mpGaiHxiCZwyBkjr47K071ICEMESG4VeXEd+70Fhbd2sYakFcjTJlMmlDI2rpQdB4fFYFXwerBpGIbnSPnuyqmmCvX6jKSmvJtKF2WXl8PDGEwMP9PVKV/bDDtc6Cd0LSsvJXHXaQPcp+HNgf9zjvKVWZpoUEJDWKVGyJ9bYUtOB2neCLIS+rPlO2x4Y2REVFV8H7sxShAwVXx3W94VsU7ce6L4Q9WD5vjT/fnmFRHa2T52vw6jtyFfCfLZbf8fI2REZBi3UbsqOk2c5TrRa4c6GWwrgb6e4ZS7L5GjXOLMkGLtbm7rTUgpfcrIS9OUmJFZjS6EtgQqbSijCXCsucGAaPKAzeU5xpKYbQHDiQ5ophk9CHcYd4RzrP5rndh2NYvYiPrk1/yITBXJZubnbWeVJlPgk1VzRDiNECUNgxVmdozslckxyV/f5Ayon7NFOKtcARv9oah2jFil+7Zs3RpgmItgRjQ3wQWc+VXKGc9epsm8WmtI6NPdE74wQHcUTn2A2B434HUloBPqPZbI9VKmXJhuS0Y230sV5BG73AOmt1vYRrZ7hL3yNAC06zidqDLajiPFmsWKvS8QlzuhCPJRFxT9jdsLt5ye44rK5nQZQ0X9DlwnKZyCnhXfOw944au9vX5uAyjoPtchVqKXYumquIF0Wq8Z3tEtu6gKrmcBdj4PbuFbcvXnG8fcF5uSDzxYrI+UJNEy5VnH/CxRPu9iNSEU6PZ+LoCFHYD5YY+BhWlOv89EC+PDCfHzgvE7lkK1J9c6IBlmTOJEUCxUWqt2JxFwND2KYV/3r7YLtOwq86Fc8R+g0Rv/7dllQ/D8z2u82xr9Z6lX1va9Oz/sQH335Yh6yYwfo+2zqp9ep7ZQvQ7bH6wRt86AwFrVst2+fp/6+0KOmCd7cWKv1ln5c2WyH1oZaPho9/KPBGV9B7KyLYAKhexqxv1rvt/UFXx+T5OXm2S8j6QxukS0VLYbqcWcSR5tkoT2rdiL4Tw9hsW1Mi5wQ0Q4cOrrTZHKUYldJ7RwnWuUWrzeLCWAm1mKC3NGpWXgqX88zxMOBEiD5QPa3b7taZHrYrfWCfxblcoZDRmrZzIGaYY8Y1nuCNanw87gx0EOEsxax7k7E5xnHkcLwh12prTxsvUEvl5niglszTybo6pap1usWh4vA+bF08YaUirsXx1Xnpj+k725fTvq1w6fUf+pIrLdkFPDZnagie3RBN3FwKSzVXPqi2dqfU9Cl5BXqdc21t6aQro6qr6jbj6urSFGoDYs3Q2tPpbC3xUm30bCu4hiGaOZA4Ytwx7A7sDzfsjjd2Xrzj5ubIMk9QEpenE3leGMSod8E7XHQ4UQYvRC9t4KN163Np82GKnSMrwkC1GxOYuL7HA7COXwiB27sX3L18yfHmlvk8MV8mtJS2LwupLBB31HhgeFFI1XF6eiQ5R3CwD83/NQRErLvy8PjI5emB5XJibvNStJlqmPOVN1vi2g2OAjiz8Q3jjmG3GTr9su37dzSKtZC889gMPcWpTaUsIubG0pPPVBAxN4WUDfnX0ODRuk1PxrEWA91Cj6o2Q8I5Om2Ilnw+6oLDEfBcnsxL+f3799wMkY9evebnuwMpmSNT6pMXcYQI0cHeCz/8/BNevv6YP/zTv2K+ZNwwoKlNvL5qPXe3LBGhVFlF2DFawMq5NLaN4Fs1LUAIRglShLNkSi0sc1kvfKeWcFUx54ktiLeQvN7UNpDFjk1t0yetyi5XQj4nggueQcK6IObSByPWraBpRYdXnk2aLb2oafxUodFwRFtQBOcrqhPnU2nnqZoOArgsl6ZXUfQRtumXbeH0b2nrHzUXswcNjksSvCjJldWl6WY8koojF0d0A9klRMx3e5kL9+8njjeOEGA3DEj1eK4md2ph2I2EGDkcDrx6/Yo4DHzx5RvuH57ITyeQCM4WKD8GvIPbWHnx8gX7/QHXAs0wDJyeLqQpMz0ufPrRZ9zc3PHy8x8izgbzfP2zv2S5PJEvT3z6+Sdcppm/+Iuf8tX9PedltvtEzJoxp4yrnqCeNC8tuLnnNpN24TUT6F5y1FZ8bx0NwZtQ0tsgMZzD7QekFDzK4D2h2gwYmsf7w1nYRU8tmZonKyLwCHt8VRRnE74bFSOGHTihevOAN7Q1UUtG1QwWXONC1zbwyWlu4jTYxZHD7sj+5obx9UtKKexvZ6b7JwD2NzecSyWrEOIeCLx7f+GnP/8FwxB4eXfD7/7ubzHGl+wHxy/+4ifcf/2GnCcOhwM3xxt2h1t88ITo2A2DnbtRmB5nllPi6fzEeZqgCuNos0R2+4AmoRQQjeQpkUuiVmHYjRxe3uLintNc+OLPfsLTw1fM0yM133N3GLgbR/aucD4/8PX9N+jNI1kCT6mwy4FxjNzub3HOHKwkz6SnmTfnBy6X96T5wrxkm98RvOkwlsyTJp7OlccM9ylwXgKK4+WrGz59dcvL2/33DdV/67Z61aXYEuKGz8v2GG2zhfpjG8APHQl9lnA/1z9cgz9r4s63i4ln+6XPk7BrcOn/z95/NcmSZHme2E+pmTkLclmyyqpqtj3ADr7/2wICCHYFgAgwkJ3p6SHVxZJdEsSJEaV4OGoeN3u6pwsi89ZlIlGZeetGhLubmuo558+uL2Ctpdff/49QgM8HT+v3aK1ZiVr5M6SlqHJFsmWy+zKgWpOL1yIyrs52OX/2elak/KWJ+VybuL5kWN1t2t+v9TrU0jQ66Nrg8GJksn7vz652Hummg9HGXs+81S1OrIrXbK2Xgl3XCiVTUmxW7pVplNedS2Walutg07rP9BZRKCL6Wbciten52ucYvMMa3SzSC0Yr+qFrkVeaECLU5kpHJafK8fmEZntNn9faYk3mysBuA1DnLIfbA8NmIxqTp2dOlwt5rO3MlX3dtfBj5xy77Zah77k57EWzVgrLvCMskekyc3t7z3a744svvqBWSRf/6f1PjYZUuTkcuIwj//D73/H0fCanSEyLtGpKo80LBbiUzBr0q9o9+7xo//z+mVUsrlUzcZE1sSLra0ihiKnlXHOaZtWr6CzokojzSNFNI5IiVdXWSCAFr6qtVpLfa51DaYsykly90ploNPK1WdJKGmJVK6Qg9sfWcLPdsN9u2G0HhmEgpoT1A7skVZy14iaWSsVYCSE8Ho98/PgJ5x37w46vv36Hu92xc4o//v4PPF3OlFowfc+2c2xubluIn2K3lcy30A3oKTCHyOkSOI8z0zKz8RJ2aDt31f0o42Q9FDG5cc4zDAO5wPNp5MOnJ86Pj4RxhBJxzrFxilIWCdYbL4xTJBbD6RLY9h1D5/H9pskglIRtx4XL5cR0OZGWmXAeG6Ihro0+W7rieV4y41x5Dh3B9iinGYaOw6Fnu+n4l64/udGIaUGhSSpc7TqVKihlWUPsBIAWAalCSUhN201rKqj04kaRlQSqyDS/LeeV86NXPUhbuK3xXPUNNJ1BSIF/+O3v+Obtaw7DwLDZoS4Xlmmia5uXM5qUCtZb3n39NVOGxx8+8tPjmUuMjE18VZU8AP/NFKoiXPTaBDkN3nzJ/GgbuuK6wQrPv7bi9+UZ/Tm6sP5wqGUV1Qv0tk6nRXchD5pp3GNKaZ/LOuOShzmUdoCqSmmuYA2du76PtVG5GbqWUCl5FRUEgam5vcYXalXOWWg5pmLbq0z5BW6P4eVBXx1H1ikgCjRZJtgoimlTjVpb0jg47bC5YmqlanGTykBSwpXdbTXzJIV5CjPTLGJwMBjvGJxmjgKrUirOW5wTlGSaL0zLxBxGqkr4TkRwV54ZcmgP24H9bsdmu2HVqIzjJMU9gBGHo1Ay4/pntZDOT6Qwk+LM5fxMiBGlpdg3VfrqF2Qro3ILCmu5GuJXINOuNSVUK9VoiG1Kb2RyYKwhZtlYY3wpBFgP4qoaaifT8c5avNJYMUhnHi8Ub1dIgUpFl0LVV8NecowiYK8NNdEa75tNXhUxmlYKqqWW9ZARO15Vxe3KUfAocaYriRQm6lGmOGGO5LiggHAWC0GvNL0R5Cpn2OpIZxU7V1DxQsoQ5xMpzqQShS4QJ8xU0LVDa01Eo/Z7tDOElHi+BMZLYM6FZYEpaPa9RlVLxpAoJApLKSyNaqeURuXENF74+OF7lLYipIuCZnhr6Iyla4VQUZlqE1VlMpoQUzN8qOTYKF1UKKIBGcPCebywhIXxNEv4l6rk0rFsPaXb84mJxVrUsOWwl/u59xlKZTz9dyraf+VXjC/2ii/WrLXRfNbBEW2KmP/RsPXlc31BGl50cT+f6MvQQH/+A66/959+bavecK3R6uej/7r+Wftd5fOh0/UF/uy6nhuf/d71e/VaFaqX93Ldiz/7ZS+v5bPv52d9z8v3Fq6vVyvapF1JYX99Le2HKcXaCghp4eXFX+uAz5q86zCvyl7nlKHrvOzBORFCuNK2VHvP+vN/Nsi75Nzsp6Whye2rtuq0VJjncP3dV7pYafx7JQ3AOpxbTVuMqtg2hb/qMavYvJeiBAGehYaZYmaaFmILudNG45Voz+rKrDDCZ6+1EOJCjTAvE6VkrBHbcaiSOWc11hqG3rHZ9AxDjzWamAMxLGKH3+7bPM8tg2N1pswcn56ERqvF1nQOgbUxXGnY4myYr02hNIQv2lSlPrtzbT2seh6lJKtKGxHBx5hkUp9fUOLVCU1ozVzPC2+NoBlNyBPC0pqWz59H+cyua6msdN7c7P6FSoSS+2tQZNVSwFvB+KLrFTG810Ip1kBOiXlehGqWM8sSG6VXQUrX79043xZrIqZZBmnZoeIMxVDjTI0LNQVyhRAWJiUoim30O5RBmcwSC6fzzDgvTEsiLIFc1YvpCIKy5aolfDgGpiWSC3SdAu359HgErQnLQp4nSInBWJx3+N4TUoJcyCmBXsNHMzEsqJrIW99SxWEJwjSJMXE5nQjzTLhM1BKF9rUo6qwo3nBcJGA2d1u871tIoUJ1ivw/UqOxwo1Ac0GQ5aSQUBPRDlRQRRAJViemdVMuqNymF9pQlASJ57axXyPfm5hA1YpqhU1txY/S6yRJFmPIke++/4GNczgE5komEOvMoK0UXFpzSRWrHYf71/z+hw/88P6BT6eRUCtRQyptwFtelvnPdBpVX/NaRHitrumi60PVnslGlaqy4K8Ixfro/HwocJ1ildZkNFgRLYS6VOSXiqfz1XZqPQuvAnKZ1Eg8ttIvFJVr/7f+0gbJ7ncDKUUul9RcsMQOb6W8rZQwRW0Bc5Wiha6Ekg0W5J7kpEgIQlOu08KKNq1npOIa3SVX1f4MCU/EYLXH1IjOlRxzK2qFn6uNYfCGmmrTEETKUtBF46zQXKxxpCp8fVRtYXkKpSrTPMkmEiYqFeuVhBPVVQUh97nr/DWtVXQWkWmcMNo1GlHlsoywzHAWqJJaGAiUkiglcTqp5tiRZQLT+uaVd10Qd5FCuQbCAchHqsRQQK+HQGn3qmKsNFbee4gZtbqe8LJupDcXSNi0zdpZQ2ccpkTJlwiBQsZYg+sctWShSSEWwFVXchUv8lxUc8sCa2prbqXpFRmZFokSjffdKJNGgWtfumXbpFCbb31t9oxSgKcUsFoarWFwLXciY72iN5peJ8p8JlOI85mcxXaxaEglsSwZV7NYkGaFcR6dHZeYeBojpykSlCVlQ6qWrbKSmaE0SSNrFk1pgnw0xFIo88xj+SCe5lXuj9XQOU/nPZ3zpKzQrmIHQ+0dpViYUmveEyUlqpaCoaRIXGbO5wunaWGOiXGS7l4rsF6j+g6ndjzUTDYdfnvPrh/otGKbR/J8Zl7mf2mL/ld7xc8yhD5vDOTseZnJvmjc2h/Xz0vhz68XdOFzRGNlE4qb4j/6jroOfuRa95af/51/9GvUy9Z8bYQ+Q2dk9vbS1Ah4oK6vZf2hL6jDP2pSrt3Ey+/4eTfx2RnEWkjKL/5cpH49n7Vq4mPZo9Ya4Kq1qHJWCYqrWyPz8zNw7bOud6XK8NEiBeum7ym1EKOmpESqgt5fGw1evned7gvbwoJSFEprNGgGFfK5hCgUKKVVK/643v+VFSD6EClE17wtqyX0VWi/8m1yTmhygTk0emYuzEvAJC2p3saKQFkl0SQW1XR+ilIzIRRyFbS5lNLC/Ew724W6ZYw0QN7ba+htzpFlmaE6cSOqlWmeWZbIMi+sbobzNMr3W/GDjGml4rzUDKWuVKPcmpSfr911mFrXmqu+NCrayPBrdZGU782kxkxZh2DX50+tjYYEIXprsApSjKQYqM3O1tqVH7I2hGujU8lNy1JaoaMbW2BtarVqQ96aKVlSyFfamtMvukVqQ7BKQYXQ9u3cmnWFMgnRRGgGK1rCkjMmBzH1SZ6yTGStKGGGFNv5KBrREAJGQTIiyi/KoUxhDJXn8yzmQ23YqIwR8wFjmrUrgmjpDoK4iy0xicOWy4TnMxVpaFyrrWzn8F2P7zqKXrAxY3JCWwPVYE0h50ioSRArY1BakXJgWQLjKOdTWAJxjkLlNYYxG1Q01KA5RkfFYPst/X6PdRalIkYn6v/IwL41q0ehoDboVr/wXmutGCV0H8w6SXhJ4q6YKxKRtEBpHWso3bqxy5osSC6ErgoVZXPAavJa0GgtOoCcOY4T/+Hv/wu/0YbDZsfd4cBXf/EVugqkGqaJjdGElPi//j/+HdNcWGIlWlYzToxrAGqlCUvbJMBYjNbMixR3qbxYsa2QK0izpBscKJ9TJbPazimUeoGnW7i6FJuqvedCq86garE+894zXU7C2abiaBZ5KDrfnJW6jnGJzCER0voLuE5krDaNfyqv1mtDZz33hy3LslBTZJwWSqmC5rSDxiia6EyTQ6QkuMSF2BdQhlTbBl8VenuLMc0y73JG54Svmc6A1pWsEp13OGOoRYq52Do74xz9dgM6Ukri+TzKHVaaze6AMR6N5XwpxBRIbdqgckTrgvcF5zLWOow11JpY5gthgc575AOtskHUJl82ghjVKs1zipH5MvH0NOGsFSg1RMISsNZRSmmHVFuc6kRoNoc1RNFCGM2nywjSdhONgU5BSNfDV2XVLA4Rr+y2oeeaJXVbrc/RujdXcluLpQUShSgWrKjmKFKluFetW61V0KCMmB4Uq7HKCI1HW3zfYayRyf9loYRMbNP8qjQxigd7LpVYGv3R2CstwSlNZxxOW6q2LDFwWWaMlcbKVehsh7OGpVbiOJNSwih7PbiHzuGtYW+tNC5W82rfUQqknPnp00fGyzPjpw889APWO7rdhsPNK7a71zjlqHGiLhdylCT5zg8s2ZOL5nlJHJfKmCpvvrhj2zt2vcHFEV3EPIB+g+u3vP3q1zyfAs+nmd/+/jdM84VxuZCKNMbdZovvPL03vN5Z7vcbbrYbXL8H4ym6Z/vma5YEv/mHP/Db3/5XTs+PDcGTpNVPj4+cxpmPx5FgBow7cP/t33DYbek6x3y+kPyGR7vj/VzQfuDWfcndmzdse0uXHnE1YPizve0/d6WYXyY9vDQIcrUBS0Nztf680l4djNZy5qXgv9ZHdR0n0cDAz0xx23MrHUP7O/Vl8LSikupnc9q1AVHX/65tkibDtPKPe4H2GtX1tcq0+YWWRBFL7CvCee1CrhLZ66R7fY/rGxJ3pfJyPl1f2TrQemkyrNH0vQScTWOmtHBLb60U60poMkZrrPcsIRNiYpyW6y+1tlGCrBWnvlxQRazBO6XYdZ5cMnPNxNYQ1vUetddrm914KYUaMiGDynJupFrJKGo1aCsBbFqpJk7PaDLeGRmwrSGmxlwpyTEWMdNwls2mbwGemcs4NXRHs73ZNKcnzSVkSgyUkhmXSCWiXWAzbOg700TIUhIpXak1Ms8RpSW0OOfQPhqFUhKAV3JmSYFFVeZpYhwnvHOIBrGdTdpTqyKnukYzyFnfUJlcEqznucRsU5Qm5CK0bWOuTd56t1+AuhfU42Xdtmbhs4BfcWgS9824pqGvOsh1FdVW8xQZRIuSt1CVaYMueT6tc1f9Q4oito9lblay6oo4pFSv+gmlSktgr2249jKAjDExz1nQTgXOKpwxGA3LPDM21y9tm+bDaDprcMZy2HhJyVaVm645aZHJKlFDZHyc+OPpk3yftdzsd9zsb6BqGYhGqStSUSgMSnWA5bjMHGeYo+arr76m7zSdL6g4oqpkP/l+S9dvefXltzyfZ57PE9/9+IHT+czxeKSeF6w17Hd7bnYbBm8ZjOLmsONw2NINA8o6tOs53L1lDpm/+y+/4/vv/sjldKS0sOdaFKfjM5fLxPNpROkO63e8fv0t290G7zuWVMhonrJmVIW+23D75i2vXt/TdYaSzlgVsPpfPpv+dDF4qaCEy826+ZaXjWjd0CvquhgpbRLQfoZmncq0MT71Z6IyzfpjpGlRWgmqYRTOaqprU5JSrtZeFUlozmSMnlHGyEaTEyUnUgxiT5kTxzkQs6R6F/Uy1aA9XOsBI123bIZaG1z7KzmXzzbhl8lT2yeoSl2dD0qtAsvywhOu7YEVS9OWyr1Cz20nFdjUyMOiZXpstWLjnRSVpWKNBAptd3u8DYxm4SmMrMnH3hm8M2z7nmlcxFWo2ftawBSwVXobrzS52f3VFpDUO4ezFmuEQ15UJWuhAuWWeJyr5GUqo1DKY6xHuYy1iY2KeCVuHVOSDrIi42FpyLRsFFrLplNlupNrvdKNUGLbZ3SHdh26KmwxpDpRAOMc2ju0c1eEQCtNr724LfU9ruuoSvPh4aN4ZMeINk42TS3TB1pDJoI7R4tVgKIkob4gtuQt0TQncWgSf3BxIdGlYvN6/0yzEW5c6tZAF4RWYzToVuDkz4oY2ccFxje6/a6aKKmJEHVrTuUBeJlUtrHoKiaV4gFKyaQkCy+XQtWQaqZkAWhTEz8S1ywLeb+rxe7K635x5qnYWui0ZvCe7WbHHBZO04XLdJaAy2YHWqr8rlTknpq2voyWDX/oHPf7G1IJQMVpRciJHBfqIkGLFckxsV2H8R6FQxsr2SdVUXGEIsnbSlnAkopiCpWCx3cd3/7i1+wGy9bD+Ok7agroWnGbGzb7O/7qr/+GWD1LUvziV3/Bp4cP/Pj+e356/yOlVLbDlvv7W/bbgTf7jv1mYDf0KNOB8SjT0232+FL54t1bjsdHqFlE7g3qjzG0jJNCN2xww4F+d4fynqw0oRZiNHLw6Q3oniVpHp5PXC4w1CN3W8du+JcFd/9ar9Wl6FrbfP6frSBXq4C0DVTksH1BoPVnxdHP9BprA6HWqexLMyL6gVVorT5/QUCblF+pKu1ZXx93JXvK+tfVSlctXAunF7rK+j74bDL8Iohdg27F2XFtgH7erlRWLQufFYPtLVdBgFfHqfV/1LWRkn9oLRNy7y0pGsRtWzF03TWjyrYB3WazZVqS0DNatkKtVc6WpmOY1UyKiRIzXiu8Vle3Ol1F6yWIjn6xttcGbx3eWkFfgVQroUIqhVDqNR9C3PcM2lpcJ8YdTiWc0UAhhAWt2r5s9M9Qrs+zwEpdQ3blEyrKoK3DGIvpeozSlBSuDZsxBtW+yC0sD40zWtysnAx9qhLWQmhmHFKUqquYnTbw01gUQlGXtZlbNhitdNAymKr1xTZ3LeIBVRo1dEXjlJJzu5RGRVsb6VVz8/Nm/cVFqg2S24A4lyJZumXNW2lrtQ1sVxfF9XlY66KcC0mntl4FJpIUa6GFxzUGoci5VKpQuFcdSNXyOa0URqE5FTbeMfSew37LEiLns+b5OIrGdW2YVzQH+bzWZ1drsUseOs/NfkNpKIU3EHImlUiJgZQb1cwKEjFsd2Jrri0xSF2UqyZV0z5RSyyG2mz/i7K43vGLb3/FMCi8zZw//UCOAVULh5tbdjf3/Oqv/4ZYDXOCbz8+8uHjR/743Xf8+P13UDKbYcPd7R373YZd79nvtmx3G4x3oC0Yx2Z/wOfK118FwjRiapWaFqnLUwiklCgFfN/j+x3D/hXKOZLWLDWSq6ZULVTjqjnPCfV0xDmFZuSwtdj+aov0z17/fzYaICmpL57Na7es25S2oj7LZ5AAl9oKF5qgq3wmZl5rbNOmRwqEdtNgRqpMQZwzmK0l5sI0L9cwQqXFQCHnynmZuSyBnz49E0O4bhrFCZ0oZPlntVVsQWtFqczaZJT64mjjnMSzG+NEM0Ekxkw7pq6IhMDEXGlMqalpaxHdgVLiNpTzui9o4e03+7Rr+KFa/aAljMV3luCMHGTA3WErXNEY22fieHt3x2acObuZ8biwFOFz971j23W8OdzyXJ+Z1EKYM1YpAU6i2LN6oGgtVCulBJ5TisMwSPK39yRVSVQC8On5SEqRMBdSaz6MrnjncGaL7yu9ityYiC4zOUXmMIsIs2jwzUZPi8edUpLFURFIr0ArTqFUhVIWaztMt8FpRy2JFDOlRuwwYDsRfi/zKCJordjZDb2zbIeB3f0tGMN5GcnnM2UJWIwsGqPblEUx9B1DP+CMJ4YkTQGFEuUANzR7QpoLUs7ULB7osa0F2ywChTImd3otvGtVEhinwOqKbmstv+zx6IYKKW3kc8+JZW60ABAOb3tOci0inqyfOciUF3qHNQIbL7EhEy0jZElCryMKSlJKpaTYQomkaFh1RbrzaG2EKtGEgT5XNtZwGDq+/uodS4wcT0d+88dF4GJkc5X0dUGQ0BpjpVn2VtE7zW7wvHv3jhDOpBRQwBwX5vFMnmS9FAVpEceRfrMFZ6kKxmVGl4quljEF2X9waDypwmWpKD2w3Wz5P/zt/4ldr/B64bf5TFomOqvZ7d5wc/+W//nf/h/Z3n5BN9xxOi787g+/5X//u/8P/9v//f/GeLlw2G349Te/4NX9HTe7gc57vPVidqEN2niKdhgUX37xjuPxSQ7YeKQmqFkajZwiqip2uwPd7p5hd0eImSlmxtS8/ONEN+yp1jMtmafjD6iycDAz5pvXDMPhT92q/9VdV/Ti2rivTUFr/tXqVCOc8lKE159LaW5S9bNCRP9MBA7rmfSPjULakEy3wn/9/xRXLv/aEFw58RWEd66uhbtqFCOV1XVuUFZTBsoLLakdlCv9xLSwOqWU2GRf7Vk/e93X3kc+h/X/K6VchbovPdIKHXz2wSrVjEPaOaYV3hv6zpGjFfv2WtltxamvJrFi9s5xd3NgXAQxny4XAiKa3nSd5N1sN1yUcM3nMtMZQ28MtqHlqhScgmqFUiVosKazjqHrGDrJwVpy5rwEwjiRUmHOmaqEPWER6qmynm7QGDK9io3WmUhxQaicTfhd9RUpUQjCqlrYYUKov6BIymCsw/gevwlUa8mzQlBljek8xnu0c6gU27CwhQR7y263Zbs/oI1hjpHT85nYrNSVXrUaQgUz1uDdgHPCaSjJCLJfYivoVRPQQ2gWuTEXBM9Yv6QQt3V1AhQdn2pr7YVCxrUpjulzC/yXRl0b00JOIScZeNWmL6SdT2tzJohgvT6XlYaW54RC6LgrCpaa4U+pos+ptX7G/hCNX7nSBmUtGNPOJiWGPIfBcXvY8u7dG+Z54bFzhHkhhrLGZL3QPRp9WhvbEDZZ17tNz+vbQ0OpEkpJjlqJC2mZCDGxpILxFtf3DLtm96osc5iaPbxqjYZG41iqJRfFGAoYEXX/zd/+LZtBY/TCH/5zYJkukCJv3rzm9dsv+bf/9n9muHmFHfY8nRd+/8c/8u//w3/kf/s//y9MlxO77cDbt++4v7vl/u6Gfhjoho5YhPWQSsV2A05pfv3LDfPlgqagcqCkhRSFTi2aY0PX7xl2tww375iDZJacgyBPSlkyhRQV8enE49MntMoMPqG+uqPrdv/iHv0nNxqsWmQEppXRP63rfuHraaWhio1pSWuyb72GxX0GqrFaodImE6tbAW0DVRVolmcxF7yTB2VwG+E+trZfdwpVlAixUiHlgPItAKiI7aoxGpulW865MMUsh8La2SN2a84ZsbZDundtPTe7LTlXdvvC46cPYrPJS7CNaodLJrO6cFAqlXydaMuBs86yBZlQbRKlkU2qKLXGpmOs5Yt37xjHkdP5zONJCrCaE4N3dEnz/PEkgtckIWtWawyVzjmc0rAs3A0bbvsN8xjF8kpVQgjkKnx9FSOmSrNgtTj3WDJWZbypbDdb5pQIl4kUMyFlokmAlfcdJ5ZSCPPCoBPWVqIT4XapmX67wbge4zqGzaEdkJqwJGJcJLSs38rm12VCazSq0WQFiUy/8eRsqCWh5kRKATKkRcIZp2nGW4sbOsY5sYTMEuAcFRjDkjSldigNSy7oKqXpzg5CkamGnd3QdT0zgTGNxBpIMWGNYdhsriLFkgolVdlkFdcJTjZijlCqhFMCpNzchZSitzStheZmu6fUynG8sCzC70W/qPZjEJczjbiPWCPN0G7o8U6S1k+nidNpJCbxck+l6T2AGhGhs26TulxRqYjYgHVaJcWOQTizSolJdWmFSGwHSG76DKsNNzdbdl3H4KxkWyhJvL+52TGHSJgTSXh3bPbbFqKlCZcLKkdKjqQ5c8kzvy0/UEqk1MxYMvO8MM8LNWu0MjhjuD/sGTYb7l6/4dNp4TRHUu2kQNMKvdthfI873DIvkiAbzJllXjjNC3/3H/4dt1vLoYfp9EgOM0uI9Hiy7/nw+3/g/HTEDzdcxoBKC3/57RdcPv4F4/mEVYXX246NkQNvzhCuU8KELlHWQq3EUnDlxEaNLPGMrhWlK2/v7ph3hX1QJG1J08JPf/weiR9SEjpVFbYawvRMnSRpXucTlkDtAj/85nsefvf5wf/n6/PrcwH4lf8hkKI4JTautASSvrjSrBSP8llDYVabaH6OlJRmGKLIVy3VS2CRDIiMNjhrREvWxLmt/bi6GlUE7WtVHs454UtThPZTWgPzGZKilaDrtImz9YIKWGvpBy8FWsx8+vhAWKKglmb9zZ8Vee1P1qDz9eebNpCs1KumbNUjrOJfrWhaLbDG8sWXX7AsM+M4Ms2TiIBTYtsN6KoZjzNzsyZVdUWxK1ZZvDL4quk2O2o/MPv5+jmWFjDaO9+mH0Jl8kr49Z2Bzsg/62BRSRFqpl6y6LiyuDaB7NVzjsT5Qm8NVnS5SPBpAevx/UDXdfSbzRVhio36Mk8TfhikwO6jTNorFFXIqlAMGO9wSibkxipx5UMxh0KMCyVmESIb05DmQljOXKaCNpawaHKxFOWJUTKZtNVX6vOmG9hutzjnmOaF3AZOc8xobRg6z3azaVRgyWbKSIG/IndrNlitMpCFdi9VveZAWWvx3tH3PbVWpmlmWtp75kXuybUxB22lMRv6js3Q45zY8J7PI6fzyBJajVZ062NlKBtCIZtmfFPlfmj9QlesjZqvG+tBG4VxNASlkoum5krKAafFlemw2YkhkHNcno+khrDvd1vmJTAtQXQy2rC/vZPVXgs5jtD28jxXplT4KetrsX4JsYUDJqaxYpShd55XtzcMmw27mzuezjPny0zOmqIc1Rm0t2jn6TZbQcNiJNQzOYjd/9/9+3/H7dZzGAznDw/kuGBrJrgHZhSX73/P/PQEfuC4ZFxK/JtffUH4t3/D5XREU3h1f8NmM+CtoeTMPM4yvFRiHzw/fhRUPUGdL/giuUwpR0iRt7cHlgRT0iTTkVLhhx9+JFTR7IZEM0swYjhTMqFEDELlVT7z3fiej38C2P6nNxrrtW7i0IpoKUxyKbIwzMv2tm7o1652hdZEMUYDiK8/N7MWbnWtiaG27rhWVBR3Bmc0yrn2bS8tdGpUmDbslT/WirweHIKYXuE26bjX6ZJYyRkrEGoqVQo0U6lK4E5nDafjM6nlQaz9FtfXzfUP1s183eilmV4PtHo93Lj+eYOvSyVl4R767Q60Q9teNpCUCPNEQRELLCFRtMEYj+s6dE7UIlCtrkAuuN7J1Cy1jUdXkgGNwdiuHaIZinT91mg2vmcYBoahxw9bdIxMGZw9E3MmsU7qpLHMNVPS1OIWFDiNdR1KV0zfg+5QxokVcqnkIjzGktJnAzSZhK9Tt3mRYJmVXrXavG76HoUn5hYwF5MEndWMNc3xqQA1UUxGWY3vdtTiqNUS40XO8PIyiayxpeqVFswIMp0qYt8sVs5rzaGu61K3ict1xcuuuQ5LrlMZmRrWK5XCWln7nTOklK/TnxcA+2X6InQrhXeaTe8Y+g5rPeRMWhZKiTSvWUzLsxDEUbG6uanSJkulPW/l51SR1Y1MnoXy0uSvj+aKumiB7nOOzFkEfMVquqFHWUcpC9VrtLPsdjt5zEshXMbrsDTXSkiZ5/MIVIqqXGohRAhJoyt0xuL6jtu7e3a7HTe39yzlSCwTESVmMxWqc1Q/UG0vtr25sroQlJJ5evyEzR09vml7MiolagjkZWJ6fiSGhPYnxjminaPvO75695p5P1CWkaFzOF0FqSyFTG420NKAURI1J8Iyk5YLOU1okjQapbaiRnr8HCOxKkJpXaFR5GIwSoOu8h6KOLfoMqEIVD2yhIVYwz+9H//5+kfX5wU27fyQe7EijTQUWZ7LzzQU9R9/v7ru7y8mH3IvQV21b/ASTKu0+N2vZ4EMh3LLZlqNOxqXHkQfgLq66TT/j+uzZ7RM9L3zzWyCly9Wmo4GU7HWkVPz5r+eRfWzvWU9cz6HLep1f5J/EyG1auf82rep2rRiWezGu65HG4u2juA62YfnBZQmZbjMizh0tUFNjJEQBL2sRfYgawRhIueGYleqUi3I1Yvlac6okkQLp5XkYPU9/TBQhgGd5Dxy5zM2J0wTVquGFoG48omph1B27aopMRrf9TjrGppb2v724hi5Wuzmz+qcOUytjzXkxnk3RtO5AUVlTlksZNsZZZSiFrV6vAAFTME4cN0WnxWpKOK8NEa5un7mNQl6jqnNJlbukYTofbZQ/tHtVdebXn/2HFyfkvpSo9GWilZC26ZWkrMsKbdzgyvtSLWfvbqpWaPxzrLpO/rO45yn5kJcWnZVfVn3jZUlr6PQ9Bcva/mqF6m0wZe+MmHWYqt+7s3f3t36tlYzjnlJranRDJsebR1ZGZS2WOsZdrvm/hjJaeLadORCqInTZSFWRapwTqkluCtiNfRG47qO/eGW/X7H4faOWI6EPBGzcCEyBmU7lPMo14vtbgZtPSkIlfbx4QGdBlzpZLCMlMUlzITxwuXpE3WcKKbjGDLWd/TbgS/fvmLa9cRlYug9zqhmTrMOvfWVGVRzIsfEPC4tDHnG6oIqSQZlV6qb6G1ShaVCUlrcr9DNkCmja5azLi1QZiCRSmJeAvFP0A/+6WJw5H4rrdBFVoxudmNRiYof59DOoqw4rhilsUWTE4JuNFMi42n8ygZ0aylcc24IQM6ovBZ8XO1T05jwHszW03U91hgMirQEckgyjTIyARpjFpqU0Sw5osp6gMikUTc9wvoQeefY3tzKVGDlr5VESBMYzX7jub255eHTAzFl4pxoUR+fNRsKdMsTUVU2jFqhJBH5KaHA1HUTy9Lpay00m1ohxMQ0LihluH/1Ba/vb9jvbljywjReePzwgaePjyxLYMqFzbBn6AdC5wnzTGpcPIocDMpqEbyFBbQcSn2nm9WejMDnZeann36USapxfPn118L52wwU7bgsCbsZmZcZe9aUUdP3Pd47nPPM48g0XvBF46rDqoGbV+8k02IYmGNhjomPTw9M5wvT+YIrCe8Mu/1AipFcC8+n05V3W09Htrsdd3f3LCFCKuhY+eU3b9lue07zmQ8fHnk4T4RUWFJhXBL7TY8zhpwKxWu8H3j9+hXjeOFyPrF8/EMLBpSkWPEdj+ISERa078VJKufGPU0slwlHBg0lCxpUqlgf5gapq7RuepWsxUJTNo+mT2ljQo0ipQmlNYN3LV0WKjLJV8pgnaM2jQNJDqfeKBE2bzu22w26RmqYyElctKx1zCGQS6W0YlspLdbMpVKrQfSBQoNyduW46muqb2liwlRBXxd2lQ69KmIQMdxSC9pJxkZ1lpu7NwxVU82E2/b43vPq7o7z8zOn52diisKP1kqe45RZxhElIS1MnSfhSbpACTjfc/vmnl//5a+5vT2w3R+wm490DyfSpxOXOTEtGbfZoHzHogzFSaHnnJcGICeOjw/s7QF760GJ8a9WDsJMOD9x+fADc/2BuVTGKXG4u+fdV9/wt3/1F9QcOX38iWm8EGNkKUEKQV3wbs+aSB41pBB4/vgjT0/vOZ2euOsctcom//jwiTlUQtbMRIoeUN1eBhFKjDNKS5vNKaNqwtaIrQuaibI8QElXIe+fr//2Ui8bcGv4paHOuVXtqWJMuaY9r82GoAWAfnHcKVV9Rv0wLw1yfhHXrr8rxIrSgnDkIhRda62cTW0SG5ZAipHVbKRWoeRQKqlkqpJg05RSGwzo9U1QS6X3omfY73aM00wIkTALapFzZdhscG0a7buBnIX2slJZrgOF1hyt2sK1vaq50UpWASWrCLhRoitI4JnYak+XWWhMbx03t0LZ0NoQ5oWnhyceP3xkHCeW8cTN3S273Z7NqzvmceJ0PJJjYEkVHzXeSr6Acw6VRVdg+h7jHabr0PNIDAvL5SxTWmu4fXXPfr9nt9u8aJCuAADWSklEQVSTuoEpRvrzyHlZRBg/TlhvMNbKPtpcqeKyoJGMpMPhQNcLhaUUcS378cefmKeFeVmkAdKyNnIZKRSmeSakJAPA8cIwbFi2CynJgNV7z5vX93Rdx+PxyPPzidP5xDiLkYhCcagOZ4QpoYqn1wOvX79mvJzpT0fe//A9UDBKKEElJk7TBKWShwHXdazuUNIQZZYQ0C0JPaYkRfzaYLXOY6Xs1VbAa8Q6W5ZFM/RpQX8l52Zr7rCpkKqko6/UqTXRWpqXgtWa3jt2DdXYbDYy8FwWdG4uki2jSejC5fqcraj6msItf95qwiq6lrXpyrk2Daqs0xVVLCURS+E8jqQUGEdDTBFrHX7ouXn1horGjxNKW4x13NzcMk0j43gmlEjNWez1Szs35pGI5MNFY6mYNrSWunNzd8u7X/yKV3e3vHnzBvfdT7iPT/z2x0dSLCwJvPEo25G1FQWkUwzbnaz/uPDp0wOm7Ni6A8PQY6pFpZmSZsbzIz9993uWapiL4nlO3Nzd8eU3X/OXv/qakhPPDw9M80wMkplhux7nO6xZu7mMNwYVFi4PP3J5/InpeMTvB8gLNc9czifGUDkuiqkOZNWhu1sZ4JkXlgNIYyqDtUhZRmoJJL1QCWRe7MX/uetPbjQ6p5vQmSvkVfLqUywbY8mZUKs4w9QqHVUqV7haBi8apx2xueQU1ZCBNmVGK5zzGC0J0NNlhEY/UShKhmVaqDljrWHbD80SFrZDJ/H0RvPh6Sh8uiyFE6wT2XXy/AKZ7/c7trsdb999wfuPHwjj2KYezSnHWnIMfPzwE/MyycRobUGve3iV/27BFKY5OakqBSetbvPWNPeE0sYbUoh2TiDO2ltxSCBz+ulH4unIuH3ADn07jDIyVy0E5fji9WvefvEFfzV4zs9PfHr/E9PjJ2oIlJQ4n88opXC6IxbRQIidnKVY+f0pFKas6WvGqoXl8owqSQ610jGGxPM0EZO8Ea8SusyQEl1n2N/ucK/vyEuQ++wUt+/u6bdblB3YRqG1XC4nitMkD12VUCRxoorEkmWjK21jVBCXhcv5WWgLBVQsfHz4xDh6lDa8fv0lX/7ibyhdz2WaeHp84nYzyOceM5vdLcN2z5dffyu0nTDx8acvmacL0/nEpw8/EeaJWApLipSo8M5TjEF1HalRpM5TZMqyhscQQWkJ+zOSrBlSorYierXiVihs5Qp5WICiWBLES5KwJuMpbofWhRhkKqHE2AulNE53lDLJYZ9gPo0ilh5n4nnGxsJN3wma4RzlKAmqJRdSEc2NMrrxm1voVCnEAKG0kD1d0VH+PaYi9pBUrDVX9EZVmejNKXJ/2LPbDjw/fqI0j9vtrmezPfCrv7xplomVHBaK1WSr8PcHnFYMzrIsiRAyeUzYYYcdtnzzy7+m6zd436OWERUnTDjxdDwyXk5su0/Mi6TDUxRVS2ORlaHkSpxmSW3Xmn5wXOLEHGc+TBdKvJDmM3/19Rt2N7fsTCUukZIDDz/9niXDUuB5Cizhgu0VOc9QCpfjI6rZHoY4tylVxrlOGj+ncf6GmLYcrEHNZz7kxNYppmniUheMVdiqqNoS2z3JJQu/HdMGE+I4JvsNOBQlB0GILBhjsfbPYvB/7rLW/KxRqLWy9hjXJl+YO9dCqdCKnvqCbKzT7jW5NzeuvtT/Qmfpend1noppaq+gGSAksTgVVNfSO481GlUNXpvroV2KoHolJRmZN3pUww4QCpOCWiWIa+h5dX+HO56Yponn41km/MqQY6KmTKiLeOunJNPpNhSsn51PCvUzu09VK4UgdB2lUNZSqgxOSnPso1T6Ttx6xJhFo2rh8dMnunGkGzZ0/UCOmSVEQspkYLPb8cVXX/L23Tucs5xPJx4+feLy/EyJkRoTSwhEBXEJoi8o4oajU0UXxdg0WjEkBiN2+FMBFTNpWricF5YYuYwTYVmoJUsKsxaWaN+CV511LPOE1pqu97x+/Yphs6EfBpYlMk0znz4+EkyCuprCGPrOM6dZHCdzupqO1JJJMRDmCXFWVoQQsFrR9R6lLW/fveWbb3+J0pZlCVxOF5z1WG0khO9wYLPd8faLLykpEMPMh+//yHQ5M52eefr0nmUeWULAzGKA0iFN6iqQFsOPRAgywQ8hXvOPXNMi6SbarkBamQGrdgnWw0oarli4jMtVx4EyGKdfWBo0Cngzc0lRBlsxRC7nMznMhGlkHid0CRw2nQwOK5yXQEzisCi2/7K2jF7ZES9GP9dnOZdGNa/XIVitVQrJNg3QZJzR9JsN297TecvlcpEBGtB3nn6746tffkvFNPpYodbIPBVu9lu81Wz6jjAnwpI5HgPDZovdbHnzi2/pNzu6fhAKcIrYHDjNkeX9J87jzGWOQkHse5TKVFWISkt21LLIeyoV23W4riOnwOPzCV0itgZ+/c1bhq5nMBviPFErPD09MCaYUuW0CPrSeUMJB6iV6XIU2UHJxHmEWjC1MvQ3WK2xyrPrO2Lc4XREp5EHJ0YwtUh7UKqsJescOhuqEnppbs2sNvpq6KQRMwVFkSGbLnRODIXMzxDSf2aP/lM389UBYlXqS1+grpkLoCSjALH0opb2RhpE3KYrWmuBRWsSV53VCaOtrpWPao1DAdM4tZ8uO37NlVwzkYKqFrqe2g4M8Z2WibAE9bXNtMhG+wI7y0JfJ1/GOrquZ7ff83x8JoYFMq0QkyYnxcg4TaQYKDWjtDQh18/4swmBVpICapVGtwdLN9Ggb65YuoJWth0qic4ZjBHHIavFnSmNF6YcSWlmqIcWGBioJVHJVC3C8WEzsDtsUCUynQfy6MX1J0ViDII+DR0xV+Hul0K2ULAtKVoRq8bWTCqZJcxUZSS+PiTmmDkv89Vr2mlQNUMBXTO9H9htd8xWws2qrvihww891XSo5rOsW4I01Jb83uDO9ntXJFitjWBKLPMsG5NUBlymCzlFOj+wu99y++YL1G6PP52IVbPpexwKQmKzu2HY7NnubsTpKUcMicvpmUcUj58+kGsh1opKiayhpiBND2J9HCuEVBr3UQoE51yD/Y3Aj43zp5DhvxCy5F7qnMX1ownDBYKtqCIPaFWOaqCq0ESQMkMVxycaXxV01c37WyhAaUmoIi4uyhi0s1ijSBlqU5mvG/pKJdRKUbS6HlRQr+iXahOyjAQ+qiK/X63+70bjvKPbDmz2O06nJ4T1Lc9d11nubg9yKMfEJcd24Fc2m57OGgbnOKkZiOilopxDdwPbm1fsDnfs9ntsmkiXZ+aHH5gefmQKC4u5oN2A1Z6h68lO7Lar9g0ZFCqCArxzzEZE6eMcsBS8qvz1L7+hGwZ6V4nhiRQXpmUkpMqS4RIzdvCM05nO95Ar0zTSaye0p2WhpoxKkawN1Wkoba/Sipu+56brmV2HM5mFep2Ca61lSpnXPfJlui1OMkLT0y1jRKuC0mJ32HcdXol488/XP329cL0bnbGoRjCR/2lbsxQDSsw4arMhb6QNVgtX3YTHpVE1KzTt4GrL6sSAoFa0mq97FlWKpBjFaMQoqNVddR66NRMKhdWaoiT3ZqVeXhHEKufqij2s4urdZiCFQC2Zi5a9xWihTaQiA5EUBflaB2TaNFc/Xowi5GwS8auucpauFrDa2Ctloqx7Ry703mKNFqFvlc8rtJC4lBtvPheWZbk6YFlv6Yee7XbAGENOgaHvSLMnVtEJxhQlPC1nUi4sGZJOQsk1hSlXUq7EsjpBVZZaJUtoCTxPkSVE5lmQnpJLCy0V1yqrkH1n6EWfoRTWWbq+p+vkK2fQpmWE1Rdkt+rSnKfqZ7XJuqak+IohkItaFwiXy0hKiX6z4dAP3N6/oh+2jJcZY59QiGW8cx2b3YHNdst2dyOrLUdUKZyfH/mUE08PWs7GLAM/lKZoCQbNzc0vN1qeZDIocqnidtXusVopIQiaYD6jQK2xA2socoE2UEkvom8lyE7RujUAjZqzfhir2X9FtDglU2IkhYAqRXSNShFKZYqRZoLYGB+q6UhempifhWNWWh7Yi4GBhAyu9YGgNGtNOQwbhqGj85YQ44vuqrlJ3ez3kptUKuM4YrXCKKlThs5x2G44qQlqBJXQ1uG6nsP9Kw43d2z3N6RpIk0T8fTE8eMPjJeRZZ6xvscYx7DZUmymhELRlooSiq9w/4WB4zzWeZbxmfMEx7NMBYz3eAcpLuQQOZ6eGWNlTjBlaWCXeWSZLdRCWCasEQepnMT4iJxJnUcZK3Vr59BGsR869puOMHlCnFlUcy4rBZA6xshTw/VgantWUes9kcR4TRH5gjJseoWka/zL15/uOpVfkAfV0hjFeq6hFdbgXI9zHdvNQMqRZZmYF6FX1Vow1mG1oxt2jdscWZo1pqLinaZzhpttL2IwYBkvxCA3j0Z9TRVMg95KzIR5EdoLBaMlLKdMEZMrfVZkVygaKYxk1ENcBXdt01C1sPGGL1/fMe96nj49iLtCKaTlwjIvzMczJYpKznhN5z3GGGotVyFWqRlrxSbt4Ad0hXk6sek9zlhCc2hQyqBdL4VuDDiDcFCbq4c1huNpFMrU+UKJM7kIhFtDxCnNwSuODz8wXT7xfDoSQySGyK7voGaWskCbjl/qzGlOXObC0t2gzA3GvWEKT5R4gToBC7pWTnPEloiKC99/+ih2trGSwojWlc1hT4nCwTw9X6gIhSbVLMmf3nM5z0xLJvBETYW4RJ4fPjGPEi6UrQgWtdVX8f/G97wEQQn6Mp1GghI9iDee0xKZU8aEQjldCMOFGqpM86rheJmxCgZjUTmR5pH/9F//iwj+S2G/98yp8jyOPF0uXMaRkAumRPSiqMexCcEQTmgVPmpVuk32NbqI7bIqzR1LK7TO6CrNgzTTlpvNlnkcCcsshanWKKup1ZCrYl4SSlmZdFbdNsdK54ZWPFWSy1StUP2GXAO5JtK0UFPTrHQetNBvnBdv8pBFm1K1knuiNFppzs9H+Ww18loUzS+8ibbVZ3B7RvjSKIZ+4LDf8m/+9i+ab39mCWPTJUyMjw8slwuPHx+xvsM4SbPNNRFz4P5mi9fgVOKsAhXxmz/PIykVnv7j33O4vefm9o53b7b0qrLZ33L68J7xMvPT+cQvvv01r+5f8e4vv2FWlkvRfPjwiXmemaaJ6XKm5MzQ3WJueobuhk8xUVVliYaoNpyz4en5kcvjIynIRj2GzBwLbn8HylOqETpaLIznxPZmh3OG8PjI8fTI5XziddcL9SUl9rsbnPPYvkfNgRs/MC1HlmnieHxiigVlOvwwMM0eioVqUdqIc1VVwvMuM9RErYmSF+73Gw7bPX/x1S3L+UwYp39qW/7zRUPD61pMSxJwae4l0vCLuYAzlt57WZeUFtooxYw8w4au67BVqBrTPDdXnnINGdv0Pc5IczhdzqI5q+IkRxVBbqBSk0XVQgqBHDOmoSlWG2qQotLBdbose0w737LoSaQxqDij2G46VNnSOy0TTCXPb4kLKUSmeSEtQmFwTtN1ojfMtZCKFPKrpkTOGYfTGt3Zaxge2koxpmSqCdKgdTZjDXTW4ZxDGyNC4ZRYTkfm04mUxJRDVaEBm2R5/PEH5ucHnp6PxCYM995TUma+jHRG44xhNwwyTS6ZMQEadFEk05GrJupALZGUCo9zRIcCTDw+jRJGuszUKuGznTPUKBrAMWV0KXitpakrhXmeeX4+Mo5ihT+OE9M4cz6dCSFQc2KaZrRR5BSa4LkFCTZqUQiJmAJhCigt1qbaOk7nC5fLiDqeqFqyDFK1TEtkjgLVKwpqKUyx4o4TH5/G63O/7xzTkjjPgdM0M82BUuE0z6hlIR9PV+JbzE13UgQGb22DrDNkMKyLGJSYRosTjYK7UmJSTFcWgUzINCEDuaKyJJmjVRtwNoMf111F88qKyc6w3WFqhJKYxhFVMprKrndUpZhz4TwrYkb2O4HYqDTr9VIEgaiVWkQXIoxG1YYDzf5WMPYrbUory7bv2G0GvvnmazpvMUbOzSUsLCEwnk/EEDifLuhGB9JKUZeRQcNhu6Hzht4ZTnEhh1los8cjx3khu57D3ZHD7T33N7c46xn2N/z4x99xeX4iLyPffvtLXr254e7XX7NkzZwKD89nlihhufM0SW0YEn3fo2phPj0RcuU4BbJxZG04h4mn05HpcuF8mVmyImHY37/BWsVm0wOJnAPzdOTu9g5rLI9p5uHje86nC3+wTp7nnHndKIJuZ8lhpLNI7kqVfJFlCWTd44eBwkDIhvO8gAXtFN60/YNCSQFqxKrE3e2O/WD48r6HeIb0L59Nf7oY3OoWDFPbJFf456vgilIoKZFRpIhM/UmsFn21IoF7VTz8MQ7jOjpjyUk8ikGcl5YYZLFWZOKqK8VBtVypHKswyWhBD4pWkEVQSS54U3CNs6SsWGOmCjGLQ4yxDUUp4FVE5Ynl9AlbMr1KdCqKd3LOFGWxqrDtPahArlXEd0asRGXYrdBFbozOhRIiqWgpPJVMo0tKhFypxlGNhpKwxtL3BzZOYVXFksQmtOklTAFHwVRpemxuwjhjGZyBHIjjwnx+JqVCToWpyKawhEA3OJxTdH1HqIZQC4sbKNrLRKpqqngPEWpm0WAPt3TDDuMHzJTIc6SQ8bbHGOi8oWooRqzeakEakZTRWuDZcTxhvcd027aRKbbDls527FJimi/kKgjJqufpnSXnRM7iK26UwlmPavkOlESoELUClYkf3vM0BWy/F7s7WqFhhPOeUqYQwSDromRsNkRAuQ43bOhqQbW1VxGx4yqiLuXqRC7TIqUoRpEb3c8bjTGOrhqcFw64txZjPdpYOjfwbARBSFVRqjixlSJWfbJpJtl0i7y+WgupBLSyKGPY379iO/R88/Y1MVxIYeL46YFMoCLpn6XSxJaFkOQZEkc0aTLr2ky3uqa2Z0grRWcNvbVYbeXvaShGsen34rpWxV5aK8X5NIqgtoq9q/Ndy/xYE14vlHmWZFx7i/WW/c0e48VxxehKv4ViE1sVqRGoGctEDUeWc+HiF7rtlvvXr2D+kuVmTwgTv/jlX/Dm7Zfcv/s1Yygcp8DBGnFHmWeenjzjNHM8nyWZuzSvFK0o2qFcj3EO1S9gHTkskpZahFrpjaCah92WzsMcZ07njwydNFrDvifVDZVM53vSvDBPE9P5mew9Owev73dYf4/rv+Xj85GfHh/5//6n33KZM3NqjiTaSngYFVUTui6oElB5odZILdJobNyGQ+8YfMV4JKflz9c/ef3MdWqdxoHwypVMZ4V620LrGk9czpCXqer6D928MF1xEiibBUWkZGqKQilBconUVVS+fq8g4GLg4KTAVYm8SHNRSpEsI930Ika3/CWhxaRaJDzVKDBizpBzZJ4u5LRATXirmj216J6UUVRrwLcUbaOQoGHZezQKXdXVzUpCxZqjTwvjFARUzC+KNihjm97EM3jJmqAU+SzFPomahballcHUQqcbI8Fo9s5g40JKgXA6EpuboFZa0ICccMaJVm3omKvG18RSxJmxZNmPS87kJJbjyhi22z2+6zHWMS4fqUwtcNZhjKJ3hpwitSHkJSbCLK5WBZnQLouE1DrfCY3MWTE+cYacvDSqJZNDEETZSGK11pJKbTong180ITWqaEyUlXJUCp8eHphCYtg+Cx0tFfpuwBqHNRbvZbJdSyHESEqBbd+hjMW4DtcN0iBGRS6l2b43JxvVJuXt3+HF30w3rYFGQuh8s281WmOdwXeiqSkVpnFmmhfmJTZ2h6yR9VmqVbSGV+Ob1syIXbRhv79huxn44u296AXDzOnhA3mZKTGQi4j8Y8rXjCaQPI/PHt6W27RSh6sYumhFb4XKaLQmpIbcVegGMSIwSgbTzhqxdi5J2hcF1sn7VlRSWFjmKBRUY9nvtwzO0qmejReqnSmZjTfoOuDtnnMsLFWRxhMXKmVZ6CkcthtuDzv+4le/IEz31DDyi29+wes3b9l+/ZfMqXCZIv/w+z9yGSfGaeKkK/O8cJwXcW+qYtxgncL1jm4YsF4TTsemG810naNGgXVWkx7vLVpXQk6cTkd67+h9x6Z3lG2PpdK5jpIycZ45HZ9ZZsN9f8/ru1vM29egNU+nEw9PR9Lf/5bTXBhb1pmqMoRQqqBqgjBCThADNY4yBFMBayyd9wy9A+No/MH/7vWnIxpGN/y5XjlyWn/m0lNK24grOTaZ92ojtzYaVTazVDOYDu16nPPouBDVSM1RtAcxoZOo4nUtKA3VKErDaHRpVKwGQ2ejxQ61yOsopUigiOzjLYlZ3F7GKkI845orT6k4ldBpYjk/SIo1FUeAGoTSkwtOG7qhEwSiJIouGF0xprkerJabWTVeWyJGqFqjfRP7lUyoUKom4yg5s+09t8OerRNb2RwuQhsqULHif42WTI6asbWgtCRt91aLvWkKlHmk5kotmilVShUHBjdYtNX0Q0fMhlgyF+XJSl3F0HJUGiKaoBTucEO3PeD7De7hTKoTlAVnO5wGL5beVKOJZYH60mgo1UJ1yLic2Pntlb6w3WxRRQ75D58iIQZiMwBQNP1KLaQiiJOzht53lDI3iD4TK2RVyQRO8SPq+cSwuWXoBvbDDucs1VqqXV+PBm1IVXiOm9ykS9bh+oHc1lfKQcSjrVCBz1w6lLpSBqoRbrcqQqvzxuC0Zhgq3hu2Q4dxPUpbWUUhsSyFFAq1SNBfyYWVrtG61AYhyPOScpSJlLbs7+64O9zwxTdfM4/PzJcT43mSx60d/DlnQoqEmIkJlJHD+mqw2XIDTBOKlSJDAqtgcE5CtIwVlxADxWpuD3ussVCQAkfB+XRGiB2FzjXdgLXEGCg5kVNmKQVlDdtdjzWa3W6LKWKcoK1YCVdX2OtIvgR0rFgdMelCmTLLKUHvuLk5YNMXYpNcIl9/+y1v3nzBV199y/ky8/h4Qs0zU++ZZoeviSdVeXr4SGlNvQjdDdV6jOswncPWAW0taAnLylSy0mAM1lk2Q4dVmZmZcX5iXDqUg37Xk6tYRA9uYEajjieW6ULJC9t9z83NPTf3d7x6/Zqny8zbpzN//DQSP504Pi0UZahYitjJCEEmiwBelYWShRZJXhjsjl1n8CajrDQbf77+O1fjSX2eIeHaNFq3gC8F1Jwpn2sz1sn9S80mVttKqIIlK7KqUsTURlPQXpKyNYhY9cW9pzY9odWKzlmqUmStmUNkFaC5lpmD1tQ2iMhVzsua5XxV1wJSXN6m8dJYABmnxaa9liz0CQPaGShGNFKsNGWodQ0N5Fo05kZRQivMGitdq6iztAHdaB5GMww9QycNzzJO19e1ummVGLFOUCTdqL/OaLZWk7OgGHmaZBKvLdkI9Ue0BmLt23eeLoHLYFMlsWoRCuSmZdHynrbbLdvdAdcPfHiYyFmQRW8VzigGb0lRk2MUqmkWxoPSgvAWrQlLaBx0Kwi8c2yGjpJdCwOOLMvMPE9U1fI1rGn3VmO8kXNFGcoYJAcnZbSpqKIoCh4fn3h8PtNvTjjf0fsBZ1xjXIjDpfOOGMVuP0TRWayCZdv1uJwoiKayNKeydaGtmRJ8topVK9p1Fdta1xoN5xzWGrrO0w9bjLGkLDbstVRCaO5QDVKrrBbL5bpmrvhWFWq8No7D7R23Nwe++PoL4uXIMl0I88hSpf5JzR49XJGTKnXS9WFpDW6jFynktVst3P/BGRGlW8u0BEIqhFwkjNc6scqnYo3ksURezm9rLMZrUoqklJimiNEG7xw320Gog7bD6SQ1ZslsvKOzmsN+RzfOXELivEzEnCjLzDR4Dl6z377m9tuvUTlQw8jXX37Fq9evufv2W8YlcTxPTM8PHHXhREIFg0mKc47QdFnGWKwzOO/p+h5nK1NOQk/SsPGeqjMliumIHFHCIMolM44n5qHDUhi8RW+FnrzpNsQQuGh4//xAWBS3rw/cHt5wc3fDZrfj6Xzh0+MzP3y8UB4unB9nSvN8ddoAMtSuIUFOqBQgTtSaqDph9Y7OiWsmSIbIv3T9yY2GR1+53nGJbUOrvLp/w2bY0Gsrjjw5cDyLBWzOFZWaB7MC6yQAr2hFCgL5YsXCc+gdy3FClYK3ns5rjIZYRaClqm4HdOtYjUDE3mm2wwEFnJ6eyDGSU2LT9eiqqbGyLDOZgu07dnvP1hisdZSUmud5JtfE6fTMKHZNzPMi5beWpGzh1xrYbkSzMI7UCikUcdVpoqpc1+4QYpXN0idRIq7Wh12/ZRj2LEWx3Wx5++4NaToRppGnyyRUGBSfThM1JXRO9M7grWbot6gsdqvL4xPDxrHrDJtXN8xL5jJnTkslZ0XKhnipuJzZ7CvGKzoUx+P3xJQJqbC1HlUyaTxhLGjd4+zAze6e/eGO7/sH5tPM8+MD28HSOY0tBqNe7D1TEG1GCCIGt9ZSI9ROMbuJGLP4iaPoup6hc8yXM5cCcT4L8qBgnCa63rHtPa9f3+C7nr4b+Pj4xHmc+XQ8SnASrdjPEV0U+77ibcSUM3m2JOtIFjbbLd2wETeWEEhhkYyJS+L58UKYCznUlo5ZWlAX18mfbgYwkkbakLtYJHxOa2wKeOXpnUWnRAoLD0+j2AZrw4yW4G3niKeTkDWMJHErhCqXizS8RomvOaqi8iwbS+253b9ivzuwLIrTJTNNGe16iJInEnMmZskfsa5HWcBpQkqkFuColcEag6qp0RwrnTd4a7nZbfDayXTIGI7TxON5ZNInvPV45+msHI4ltcOHQixBpndmRUwKYYnS/BehtYn2RqzvjHfYoUMdR3bW86tvfsl5XJhC4BIuDL1h6B1ZRfr4xPHDb3i13+P2A+FcSM8/8X584Pn977icLpwenvnf//1/4Pl05ngZJZEVRcAwLokpJtAVNxi2e8tur9j6RAhHOn3CDoG3X73l09PEw/PM+fSJDz9FjJm5v/coVfjq2z2KSCzP6LgR//7tgV989SuWaeHTzRv+7t/9vwinE0kXkiocTyceHx7IxhLQ6JrROQm3V4mAXZsqloQ5EeOEoWBVweiMVZrOWnor08nLwxMqpWuD/ufrv72MbeYjyLReni1pcn0zFklrI7zMMmktuYVcNoOTptHIzeGrVDDWCt2qt6RzhizIe1bSzHfWCLoAV7VHrY3DrCXl2g+9oIFtMl+z0CdQEHNmabkL/aZnbzcoYxq60cLXYiDGhY+fPojFZC3iOJGFCuqUQVkDzuOdI+TMZV4kjT5WcV5ktRdVbSAun5VQx8UJTxtN3/Vo49DO4YcNwzBwe3sghoUQFi5hRMcEFU6n+erMN3jh8jslyKwpCTWPdNYydI7h3TsuMXGcA8c5EFMi5IJPGWeFhmTJbHVhyeICtFwyzjtcLXgKNhe6qLExsu88+9tbfuO+I+XI8fhM7zS9M3RmK0wLIxoqSiGFRYp0o1HOM5aCWcQuumuorFbI5N8ZuvtbpnHkY1xkeKgUqmSMEjvim5uDOPy4jo9PZy7jwtPxLGdI09ZgpPz31rQvTZhG8jKT5lGe97plt9mw6XaUuiGFwPl05vHxmWlaCCGJaUxVGC3TbFkXq2hdsRrbqKbj0o065bWsz94LTbOWwni8MI1RaJvGMU3iWpRDaFohdeXm6+a8BcIAWa2OU4gor3G+43A4sDscQBlO08L5dGYumqgs2Xiq7VrjplF2FaKbNnhsNLKWWE4VBovVsPWWzlkO216oelpyHKgSmqxLRleDU7ZlrRUu1yFYFUvbNsjLKZKTGG3kGFly4vT8hNWiN/A6442W39cPKO1Bb9g4S8wZvEc7+VKm0uUL4fiew8ZhTCGUhaePPzAdH/jDH77nfBk5Pp34+//4nzhdLoJqxErIklcRspiuhHnGKkvoaQ2yQW06+jxQoqbrBj48XShp5PL8wCer8d5wd39HSZFtPzRq+ERvHFtv2Tfb3RgT583Ahw/vGeeJH3/4iZwzx+OR2/tboYXnglMalTLz6UQkUrXD9htoyPo8XWQgqaHXBWsVfae5GQyDVYynZ3ReUOV/oOtUXrUFui2MRofJWfhexhSZrOfY+HxSrBlrxOKzSgaGsSIuLVk2bqOF+zq4DrtYSAlDbh70snurBn+vkxeQTltTZKqjRdMwOxHHaA1d11ELhBJJuVKUout7TO9RzlIKLAsCedZKzZU5BHTzy0+pysaiBaZGy3TcaIszMtlIzRVBOLXyd1OD7Y1WWG8FBs9S4Mn0psN7I7Qrb+l7gzFwWgLTvDCmIhQP6+j2nWxwJbPzBqsqqkZqFBheq9q+oLNekkx1JFdxd4hVN6epCqXSWeEr30ZNFytLrLzaduhamXVkjgFNIUwzNSYcitvDnjCPPD6IwFEjATleCyw5q0WEQk3Y56xju9uKPk5rSsl4a1HGMk0TiUiohfu7W4bNgHGa0Jo9U6UAzzmLo0aMTBVCiJ/ZPwJUjAxHMKpAiuScmeqMzhqtLfMyMy0L/TBwc3vXDhMlNreXI5fLWVKbW8o31M+mgGIgcM2PUDLlUQitwhlNZ7VMXJzBWSt806qJDbFSVSaWWosIvjZvZ1m3goZ0VgRjpUKKWfAHJd28VgpnzJXn/Rwij0+PjJcj0+lIiSIMVVpyGLyHMSyCymTE5rZULKqhf0JP06pilExv+s6x6awI0IsUSNbKV4zi4iKOGfoquL1agva2eboLZbLkck2ILSiWacK0dN6VGhIp8npqZX4+yqGVMzceOlPpdGFBY1thXoeeomAeT6jFoLTi8vzAPE5cjmd0mXAEPJGsLFU7hqGn6kRRkTCN1BTF+ztOaKPoWNj5QtGVTke8iniV2Q09u94zeIfX4vy2dT0xFEos5MtMTQqK4fjpgRAj4zwyxcASAqfzSDdc2tg4U40jKY0tGa9hsFrcwOp6/8VuoKYZZzXeCl/dakNnO+4OB/abnjRGaKqDP1//9FXqalWrKe05q+1sKCudomktckM06no2VeGJayNUE2NNK45EJ2GsobMG5S01VVSbMudSrxPmlTO+2sKuE9taWiia1pLPhFBOnXfNRrqIJY9CqDTeoa1hSYVSI5WWq1IqC0Umr7W0fBqZ3OaUr7bzSksOjVKKkqukLesXWlgptZ1NjQqkhG4ski2NcxZt5cs7K6GAznK+XBjHhcsU8L4T6sRmLz8LxWaQcyqGGbISUwO9oijiamMqVJWuJhtVSepPrvK6vBNtZVIaFxMmRPpNJ9kCDvI8Y6iEaSKHgKZye7MjxZnx/ISpgpoaca2hKkkihwZ2KUFp+s1AUUqK7c8m63Kv5D5uNxusMYQwN91lS45vULcksetGiRKmgkAB5Urj01rukwikA0vOon0AtDaQAst2S7m9FdcfYxhPJ8bziWWaWnChnNuqXt9FsxmtV5PLqjRrFoxRYp/vrNxLZ+UzFdq6IpYidBwtaHZFN42JRjextV7vmZGzC6C0cNorcqJodvwyXHx4euTT0yPn4zPj+QwpoEtm29A2UzVKJ5RKjd3YBnmNlSIZUxI2bFVl6FyjBYl2s1KwRmOtBCrHEITSHiWJXkTLDcNXYGOiFNE8CqqSWzaK0KJjDNT2GRQjs/ysizgrqUipc6PNZTpvsbpiDKQaUdmQlpHabWToHgM1JabLSMzPzNPCeBnRccLlBZsWfNUYY+k3W85zZFwi49TcWGsV1KBovJZ1WzV4VemtIHRW9wydl/dapcb64tUrbK1Cx2y29oJeGmJKXC4T0yLUOG01/UksorWW8zmkCjljtWLTeZaiJdCziBaj1oSrAe9MM4NQWKvpe8vtdsN205HDiCr2Sjn9711/cqMRktjJOrvyPaFExTSPxLgwKSg5U3OmpgRKyZSjc9Llxywpx1Y3wY5YTDrXs+0Nd9uBMY7kGWqWyXOtUJIIr7Wz6CLc66LEWULVIptO3+OtxVtHVlCKpt8OpJSZU7hSmLr9ln63wXYdp9OFOWWW/AITLiFfIUhdpLu2FagRpSvKKqztqEYoW3OILKVQaA49VYo7ZxTOafpdj1GV6RREIGwNh91GLC11Zr/rcV6mQE+ns6RpxsrQdXT9llc3t7KZ18yrwVDCzOnTB1Kj2jhTrwmw1np0ylQt6cVLrYSsWCo45JzdeIOzmmjEaz2nwjev7jG1cnw2/PDwyBgS4+MTYXuLuol88fYVEHh8/BEdI51WbL2jd9JALueRWCupRJzu2G62vHv7jvN0IpZMJQmyYDou7z8xTxMLhb/5N/8Tmcrm08DpfCKEhRRmUgiCjIyKUkdyhcsUialKwEabz1kUzlasrpR5bu4cCzkp4cBXg7fQdY5f/PIb9jd3DLsbnp4+cHo+cnx6QhGgJggZ7dph3cRk5CJWs41OQStmnHX0TpqM/dDLIeE8IVuSqoTihXagJcgopkitAWVyo2vIAey0YtN3GCUb4jGJs4iI4hRGWQZnyXFmzInT6cLHTz9yOT8znS/0zjD0ogexxqBd5fHyidj0CanKbE17Iwd/LXhtMUqcpg6bgc3g2fSaZRJkxGiH94YByzJNxKhJJhKDfAQpJoxxUjh0ezmcSiSFNfBQGvpSK+fzmd61aasWGsW0ZA67W0qpvP/tH8R5x2p++fVrjJYmGiwqJcplIfYzqWYePr7HGXnGlmUmhEAICzcby+A2bJwmVg/G093e4Z4D+rTwfLqQ5kAyhXJ5RmPo1IIfFCUpWE6YGOhq5vb+HTe3t7y+fUXvhca33QzM55HlPPPx+x8hiaPRH94/sNTMXCKnMBFioD6LfWGhQorNOx5ciWwN3PUONVdCyRQNVhcMmVIjfe/ZDL4dKg6re755945NP/D9H5Zr0fnn65++Ui5Ya6RxKJraEIvQmmXdHN8ke6ClFWtF10lg6RICxhm0NfjOQRLqndJVDtehQ+eFEuUcLkXCvVLJV7qQaoOXVSdSKaQUyU445tq2CXE1uM4LJTcFWS9K4/sO5z3GWtI0UxGxdcyCYuQCumTZ+xRXp6glBNFS6Yp2nSDvSlPasKGuRapCMjOMxnnJ3dBKkYNMe03LTtDOYazDeaF2aK05nUeen088nUYOB8/Wd9zevMY7S2ctlkIOM5fjIzVrdC0YlVkzepSVJi0rQ1KarC3VKrLSJKTX2g4dXeexfWAOkcsc2B/2or9cBo4PD4RlYXx+Yr69JcfIV1+8wVsI4zPLdBa6Wmcoki1GDK3ob7qCvu94dX9HvGY6rFu7OO61aSGH/YGyTVijOB6PLGFpiLdo6KZxArWAEvQ0xDXAt1ybA20MrrkYhmUWClmIrXEsnB8H+qEnvnvHdren32x4+vCRcRyZL2fIMuGnCIIs5w+NTs6Kmwiq3EY+RgmdpXOWvutxVpDskIpQqQWQhyJmAFgRZxszSY0mYkpxEXTSeFdaXSfbu4T6aYWzUrDnc+J8PvHw8IHL+cw0zXRG9BWvXCcNrE7oMUB6EZVTC84baXJpekcljcZu07PpPL0zhCjPgTWKzjuqMpzOozTNyjD0nbi86aaXak23aYODnMVdaaWua5S4ijYnxdJoi6lmSl0oJRDiTEoLUOmcxljwVUvzFypp0qTeUjUs88J5ieSYGC8TNWXImYODrlpMMgzag+sZXn/Bh6czn45nHo9P8lkrKGEBY/BVUJ9aM7YkNkZR+w57eMWwP7DbbvFKs/Edb9++ZT4+s1wuvH98Zl4CISaen0+ElDnPgcfjiRACBTlnhWYfKVXJkDwGOqO5P+wYI4RcGReRDKiasDqyHyy3hx6F7LF93/H21S1D3/P8UClKC7XxX7j+5EbDdh7nZINSUWNLpXPqmqNhVGW/39L5jtPlLAtXa+5fv6UCT8cH0U5Yyy9/+UuqhlQzHz+8F6u6Tx/IYQYK2kpnVtEUBVnLZL7GhFHgrYiuCnCcJy6LhAiVmAVJsIp0OhJT4XQJjFHyOuafHuDDowiFG7UrpybKVPKArZMC25x50C1sJhXKvND3nYhvK1StrjqRVZzurMM7w7Zz1BIJJVONudqczTGiygIl82k6iiB+2HP/+pbD/Q1//OEDiUqcFy7hCYWEeD3rjM4Blgv3+x2Dd/ReEVJmKZXqtywqsRRLThasiFa1iRRVJPhH9Qza46qR0MBYePr4KMmlRmG8xyjNcTrx8fk9qtNsbnbsDx2/+vVXjI9C4xicpagsovqhl88mF0pdmMbMD9/PpLaRz6XwaJ+Fm1qycDRR/OHHHyglcTqfmJeRlAWSFyRYc54iOVdCbCKwAiHLxKbTir7pIfrOkYrwG5clNDgZYkYaNmeo8xPZZFKaKKeP9AW+urshxpkQFo7zjG4itM5pOlVJSlGa2xRGUkWl8c2AFh1JlUPN1EB1G0zv2ew2xKrJVYEulHAWKkcLaqSlv9eSmccXv+9U2qmnFP2wxXcbfLehlkSIM6fjB1IaQUuhGpRQ/BYlhU6q6ioCj6WgG5qxsz2boWOz6dh1DkoiLyM3+w3eGZQulKjQNXN49Ra/2+B3G37zX//IPC2kJdP3Hu8tm8GTciImCYoqRXjXFXGWW+YJo4Tb3R+2GANQOJ4uTeieOF4WFJoSxX3bFRinggoLVQXGavCbPTdDxxTFC34ujjEIWjqdn0kpkFOg9x0piWub2e7ptre8++bXLPqRS3ymswObXnPYd6iQ0bay146qNxRtyaGI0YOHORTGp5H38wdyTPTW8OXNgXQ8shyP/PCf/yu262RIoQuTKhxr4scPjyxzoPeGqAxjKJg3VvJVYmTrOvrbDa9uLdEMpKqYUuTx4Scu50dQhde7gXdfvMXbDmd7hu6W3eZGJoddx3RemKb5T92q/9VdSiu0lQLeWi16odYdlyrFhfDUXePWC/Xp9u6WUitPx+dm39zx9S9/KU7aufDx40diWLiMJ+IyQq30XfsZVVFCkGcXdeWzayMWpgBTiCwxIvlP+WotG6eZlDOXObDETKEQPj62NyMIeSrC+0cJlUUYw6qlkgPNiS9n0UpUwFU5Z1Jaczg0mtXmFHzncc7Qd2LJXHImpSDWtdqgVCbHTAgz5/GC8x3zPHH36hX721fY9w9UFEtRfDwKrULXiq1yRpECN7uO3lu81cSWjVFcR66GmhVaOXROYoNaM6HAeVqaWUsmJtGxURM5zjKxLxnTNFRTCDw+H6n9e27uD+y3jndvbzgfZQC13YkYNqfcdHdijRpSJF9O5B8Tqdn0LyGJy5h1zThEEKJPDw/UUpjGC9M0Ea+FlHz4oU2QU66EJALlWgWldkYzdCLwdd1AzpU5R5blAimjqxSXNoMOiXxxZBUodcaVmY0umI0nhEKMmRqa8Y0R5KwYLU5nrUHVxsk+XAVBM0aaw1SgZmnmdLfBDp7N7SCkXSUD33k8UsYzRWuoGqMEPaMkUpxRqQnEc6YqCezre8ew6Tnst2gle+/z6YkQA0VVMVppzVBSUh/lVtiKzrKhckqx8R3bTc9uOzB4CyWTw8z9YSv8/5phUihrePPmLX7Y4votv/+HPzCNE2GJbDcbvHN0nSNnoQuHKA38Su/PpTAtc2uQjGh+EebEaVykmcsFqxxKGRRONEFWU3MlzE2H0xr3YbMjJGnMHk8LcY4tOO8ke0IM9M5SmunQbrfBbQ7cfPWOYC0j0J029FbTO0ddAhjD1ogFfEF0xkuRfUDlQhpnjuWR05LYWIt7dcfp4RPj8Zkfv/uOVIU4pjc7ppw5TjMPj8+EFDlNE7lWYsl0vW+NdWU7iGbn9duBpRqpo2Lk4dMHLqdnMIFXNxu+eveKzovOxzjP67vXaG14+HhkmgJh+ZfR9j+50VhpU8Y5jLPUXEhz+lknr2nTHSubmzIW23VUwLqOkjPWOTb7Pdo7qlbMS2Q8PnMaJ3HM0MiU1ougdohGrM1qIZV0hbOVhAzIokqJmgsGjbOaohQQSakSMy3dsjItsS1A8RhSzfmHqsRCVClUS72UsDIlFLEi4uySJGiv0LQY1DYNEkhRXHxkyuOtYx4DOQnMblqyprUessCx07ygYiYWTb87SDr50DMuiSXMwm+vEpZSVcbUhMmJVEXEumSIVZOUQrmOWi2mGLpssSmLU0qWo3CJGbtEKoo5ROEJRkGfjDH4bY/dbBlKRchrlWmZcMmhKAxDh1o6VDJ4bUU0rBQ7u2dZAvMSmOcTqSTSeAbtyCjGGDFaKHJbN2CUAi2BZjkn4hKEvtbcnnK7PznLBiETIK60HdOmAGvD2XvHHJPQCa4jqnYo1CwC7GUiafElN2FGV4MxrhkUyCDLaoFmO6eFb6+LBFcpTVGGsgZqKQmzKhiWKkJBjcL3B2y/w+/umYsm5wphpNRCDgu1tCZWgbNeEDBKm64ptHWgxCrRD1v8MNBtNlRdm7BxFGRNFaG5Kj5bx22ZtuektPAeowTNGpxlPwxsByd6HKfZ7bc4Z1vo3kyOmd3hhu3tDbu7G+axMo0zYV6wVtCZ1/cHCpWYEz/88IEpLMzp5dBNuWA7cVS5udlfRXZLSMRQWWJhihMKja4dThsKhikWapT3csmRDo/bRwgyfY7VEXMmhcwUNLVoajF0yrRhQEG5HtVt0N0e5RaUnTDWNv5vYTpemBZF1EI9JDc/+gA5K+a0UBc4j5k4L2y0YRgD9Xgknk5MD8/o3qOHjpOuLAZmoySPoWpykcM05kIo4rQyh0gpQntSqtAZhTNWJtrLDlUCIU0ynLCOzbCh63bsd68Z+v1VMBuTZgl/Aj79r/VSGm1sQ9ocJWWCAq7Be1UOusY9XxsT6z2lVqGqGoPtOrb7PaZRGudl4XKGZZ7a1qLAWrzvMMbS5SpOUSkxz7MM3VbkoojbTc4ywZVzQtyqUmqC6FqbGx1MzZp2zQoQtqvQroqSIkI1pESoM3L+XV3aqULTWYteOZAkCHBtNJw0Yka3ZqzlVxgjKIh3Ts61VMT6sshZ54c91jn6vmdaAilEMdqokvtiam60l0ysHlMrc5YCPCupGbQydNUw6EBKmWwCOsxtkJLQi7jyzSlLUZczSwwYbaRA3AyY0pNRZKWYl8A2iVtg11nqpoNa8Z1Ddb0gOcYTgth4hvOZnAuXcaIoSXJfYiSXgrMZ27QxtYpDkGSiRHIrjtdSqtYq7o6lkLPQVdpHLdklWgaPzog2I7bPZqWnrto/cfOBPI8ko4kigGi6m9rsXNvQ02jRj1hpMlKR4ZuIxxWZVp8oRVWWoiyhWky16OrYDDe4bku3uWNNsqJE5phJZaLURrvSGmNbTaTld9VSwZhrbMCw2bDZDPRDB6pSiuhca6OzrwyANT9t1fXW9tkpGn1PrQiMY7sR3aaqhZos+8MOby05R4o26JQ43Nyy2d8w7A7kJTNdJsZxpu883jtuDjuhNObM+0+fmJaFcRJHspwLKSc639N1Hbv9DtOepzEX0hIISxOFS2uEdRZbrVCMiljTihGNwS8RMyUqsEQjjlhJMUUpKHSR2lfpCkVhfI/pN5huENTROYw1oMQ46fJ8olsMvY2oSahYKVfSkkmxkNVEsYk8Buo4MxlDFwPT0yPz6cT48ERCapUaMkuFOa3vxZCyDF5TFufVkgqxZe6gNcZUXK0Yq/HDlhxHjEqEU8Rbcerabff4xrTZbA6SY1U9KS9/0tn0JzcaKVWsN2jX8eb+FTFGPvz0Xjyss/C9llG4/VEFcA7jDbMY8lOVBKB0XY/qdnT7G+yw4Z3b8+n9DzyNMwmxNRsOBw53r9ls9kDPMotP+PP7f0DVLJuJEienMGeWmMmp4o1s5JaKLpFaNWiP0dIU5FKo7WlQ6qXzRhnQkLVCq4CqlZSbqw+ANkKjqUqs2qjEKHQqpySUTFUwFQ6uUVmyJo+5pWtX9nvH4Ade37wllcwcFz599x0pB/T4TOc2bDdbfnF/zx++/5HL8yNj44ZaFMZpcotPf5hGjmEiLhG/OeCHPVu/xXnDYQPbbaTmiAoTx+dCnCfmMbIsEaVOHMNEwaBMB0bjvOLgOu7ffsXQD8QQmu658PT0jEKw6Lv9FiMgGsPNLX6zQ5s9x+cjD48P/PjH/0oYT8zTEe3F93qaZ4zxWFMwrqdrFrBhWYSekMEli8qaSwjMubBUyT1xWpoJmxGqlGriWppTDxus9gKXKksj1IlZgJbE0ilFxhzRc8D4iU3K5KoJRQRZIUeMhWEzMPSerTOEFFniwpwqMSuWpFmWQqka3fUo3YGxPBdFNQ5lOr764t+wef0FN9/+ilCUOD989zsef/efmJ4nwmyFd+kLX9zeYaxmLpGny8iSM66/xbge63u2hz3bw4ab+z2nh59Iy0wtI0pnjC2YDnSRiWaR0RW5KkJMhBTl8FeNXlYWNnrgdrAyjdUd6mbPqzdv8L0nl8TlMhJi4u7VW3a7A7v9Da/vvqHkzLJMXE6PGFX561//kv3tAeM9/8v/5X/lux9+5A/ffc8yS0hfLrDb77m/v+Fv/+YvidNCGCcu24mn52eO799zvFxE4Ehk7zcMnUWPMnVMKfEcZro5cdaG2yyUwKQ2jNGyLJGYDNYkXFewO4fKGctM3bwidrd8Sj1n3RO7ATN4chw5Phz5w/GZE2L9rIsIhpV3PJbKsVaOw4WgFIuCvIxsiyLoHn+8wBIIaWYcFZOCUwXd99j9gVfbW+pWEr+3uw1+Y1msYQxwSRKslJbIcl6www1+2HH75Te8ffc1r1694bt/kOLgfEnsD1s2u1e8evMLnNsyTQvL/CPTOHM5/5k69c9dylqM83TDhtvDgZIix8dHpvOFGCIhJMBQq2l6DIexHUuRIr/aTlx+hg2+37Pb7+n7nlI1Hz+85/l0BtuJDqQbuHn1iv1+z3a353KZOB7PfPfH7wShG3p00y1dlsQSIylGobFoCU3TWoqwooy4jVRIpWkGlCKVfNX8vRRuSmhWVVFqJrXmZQ0aVFoRSmqFbKHTutE09UqyYdcPoBW5Fi7jLMnOCZy1aNPx6v6NNPYp8vvvf2QcJz4dR4pyDP1A5yzjaWY+n5mnWajUzkHTZFijKOOInhQlZbp+oBsG7oYtG2Xo9rCbJb28hMD54YE4T0xTYAoRNEwNJUIrXAz4znO4veXuiy/oh41kOmVxH3o8niEHDJm7m60kTBvP7vCKrt+D7jk+H3n89ED8/W8YpwvjZZJBKUqKuXlB68ThsL/q+KZloeYsVKcszdwSkrhmlirc+nZ/rDVt+NTC5GjJ003jJyiWwWkrmpxSUblSc6LoTFQwx0xeAiXLulBC/kelhK0y+e86jx+c5HeEhTm1QWqK1GIl/0d1oHuy8Sx4FA6lPPs3f8X27g37L38JjQI0Pn7i6VQ5zk8QKs5qdp3msOvRxpBQPJ8mlljADPh+oO8HXr+6o+8dfe95Oj2TckDpjDMFXStRI1bIFIkzUDIVbO1za0jFOMDEhKcyeEvvxB1r099ze3uD9zJc6tvZdP/2S7bbHfv9gW9ef02KifP5TAwz3hv+6q9+ie87qlL8r//P/zffff8jv/vdH0nLKIL3WDi82fPq/o6/+vWvJLizFL77/R95fnzmMj0wXiQFPkfYbwaGoUNvIiEn5hhIVPohcImW3SS05Vz2xDKTiuOSI970DL7Q32xJuTBdZnJ3B/bAKfUstaeoDgPEeeHhGPnddOboFLNV2CzudklpTilzKYWLvRC0YlGadLnQKXjaDNhlQYXAfLoQCiwVzvoZ1Q+Y/YG7/T0ZxRwzzu+oZkNSPXOU5+ByPosJgLYEDLYbeP3VL/jyyzfk17e8/z1oZXh+nnn15lcc7l/z+t1XlAzjZQT1npgic/gfSJ3y3YDvN1fHJGsD3XAixEXcZWqSSe3geXN4RbWGbLSI0poFK9mgSuX999/T7474zYbT0yPHp0fCOFFzIlN5Dg+kJTEMJzbbe0CEQt4YOue5u73h9v4V1jrmceb9Tx94enji+elZiq5ciVGExYp8tYST7fYlNXaFovNq79cmwnot8I3BG8MweHRVqAQhyURBWSUUL61wvpMJfK5Mi7hVUSthFZIZCRLa9o77w0C/lYn1/rDn09Mz3//0no9PTzw8H6lJeHIhZ5QXn+2YE7ZYnNE423EJbV5QNEuoWBWl21Xij305PkOOeFVYwkxOs/i/txC2XD1VGSgO6zzG9fhuj++2WO9ZliS80hDYbzuMypgs78taz+HuwO3bd2wO9/SbV8xLYJpGPn3zBR8//Mhv/svfM6WFECNOi/NDCBFSYVSyEYmwUdwncs4C7ZFRBrwSKzdvDL2z3O5uqBVOl5HTMhFyIaEwVVOx+PtXdLvEdnvhcnwWF404o62c41DIIbKk5i2vJDlzu93SU1lqz3470HmHIhNLJeeFmKqI6avCdD3WeLr9DShBH1JJZG3IynJKsFwmjt+9pypLrYWaFUFZsnOo3uKtYr9V7G+cUPxipuv3Et6XLdv9lu12RzdsKGTS4yfCw0dqmHmz3zOFmSVFamqIWpbkdGMNBY0zhcEJqrjrPIO1bJ1wSU+XM5cLDNstb754y7DbYr3leHoWN5ZqeDo9cxwvmE/vheaANHvj+VmoEfFCv9lirOfydKQsEacMOhW80mxv7viLb37Jl1+843/6679qnvmF//yff4P9+IlFGYJ6+P+x9x+9lmVpmib2LLnVUVeYdBEiM1JWVXY3QYFugCAaBAn+XBIkBxxwQICDbrKa3V1ZWRkRGeHa3dS996gtluZgbbPIQVVnEOAs8wCG0Ah3s3P3Xuv73vd5cC7UF6PumZVhPo2E5AnR4wAVMx+SwDwsCGEQKBo9oKQluoxSEZsjjb2nbRpunzUkfSCJlnnWiNLRNwf+zV/9z+iEp2NGvvsOc70Qnp4wvq6j/RTJVqOsxghNJFKSQ8eATBBjRjuP8hG7bo8QAolEZUlTFGcBcw6c/JXxzYh+MGy2Z3ysJXGtNEY3dIcdp+vM2c08TiN911TnijBIDCVo5jGTw8R8+QmpOpyPnE8TfsmU/Mcrj/65fYQ0KG0xtr6jUvAUeSGWKiDzPqGtpFGWw35fqX6CtWexIqeXhRQTP3z7Hf0w0LYtp+OJ8/GMGxdSDPUQ6QLJRc7didvbOxASLQTbvsdaw+3hwHbTI6VgWWY+fPjA+XjifDqv5dR1jVo+BnGqiXyVO1PEuq3gD/EOAdWSXOo8WkDtk2hJ39q1jC7xrnqfYqn59Y8I1o+F63GqWfy4Oq9KAaUUxliapmO729M2TXUQtD2PpzPfv/3A6XzhdBnJBZbZVQu0FGt5tHZgipAobZhjhFI31F5KFiEolwtC1SHQNM11g+197dCkuFLACglqE0lWWzHKInUDtkP3W0zX4y4T0zwyTxPbaDAiUTWDuoIU2o6bwy3b/T3D7p4QIm5xfP75a969f8PvfvfbNQ5V30cxVPfIueRa2hcV3Ss+Fm1L9X98vEQIUXH5xmgaa2iHvsbJYuQ8jngfmUVZSV6Wfr9Fh4gaZs4PT0RX6YdSQhLgc6E4R4yxuiG0wTbtulHINF1LP3TY1lKoF8yQHUuSxFwIqSBNi9Qtpt+DburBMZU6IFWaMRbitDC+fVf7ixlMSaDq9ry4HqsTTQdt21Sj/LolTFmAGeiHga7rGNoaUQrXI3m6IEJgaxVJaqIsBKtWF1VmWeYqNM41KaLXaGHFyGo2VqNKZjydcUYzDAObzQbTdujGEoOnhEDMmYfLmafrFfn2HSaL1Q5eWMYzgsR8fstmt8O2LePxCTeOpOBJMaKk4tndPT/74ktevXjOX/zqT1CywoU60/Du/QNCGh7tlWUJjKPHK0VKkvE44XPEp0iRoFzhYc6oDyNSWpTuauleCK6ToNMabwWD2mP7hvvbBjnckGXDyQOio+tu+M/+5n9BkxxNGNHvfkDNI/N0QbilEgaVrr0NpchaQ864EGlipAHU7FHeI2KkZd2oCUFUVfwpSvrk7LpOjjmM6KPk4aklp0COsXZJdU0oLd6TXWTy36zvJfCLp21alNCcTiPOC06XhBAK5zxPTyPTFAih8E99/ui3l9IWpQxS2WrClBmhdBX8rLGqrBUYTdMPlVdNxruJ4OshopRaHDk/VKOv7VqulzPT9VK19euBf4nVzRC9RwmLsS1aW1pr6FrLfrPj2d0zmqatrOwIJRQup0tFE9Y+DoiCkonCR476Sk0XH9UzK8+l/CF2Ij7uSCVIJdCytu4VEqEEOS+fWlFyXcE3tiHmup6a57kSEVZcKqxUhRWdrhX0bcNmt+M8zbiYKG/fc52mmuueA0IbxEr/KDHUL0yp7GxQuFinK1LUDYsSETG7OuFGcB2viBwpRhBWNr8gUoqsv0QVx5ei6qFZWoSwNRJUBDFmnAu4ZWFoNVqsU+AiUDrTN5rt0DFsN3TDjiFlfNwyNNXH8P7tG9J4pJCxXuFTrA9I5yglk0vCarXKFiVR1t//IkuV9MlVxKOqsfOw7WsZLQbG6Mi5Zk8dEoWh394jc0F2CyUXwjQSs8fKutmo9Lxa5lNWI5VCG4sxlixAR11pYEaTUv19hBXbWipJTGuLajpMvyVjKEhS8EQkSSqWnPGLI8UjQugaoxOFuHocdNPQ2Ew3SJqmFt+KkHSqrdulObJrDbtNgzaKefG48UyeRmRJDJseSo0rzKoibVNJBO/IuZJDtCig6mRx0zds2pZOVxGfD7UIpkz9+5eqSskiFa5QBExuWT0fgeAranXTNPjlUkVyfsLaFqUb/Fxf1FYqFBW/uBs23B1ueHZzy81ujzUWISRv3z3gQmR0njkIptmz+EwpBl9gnEd8XAjRkbWFBCIKcvYgDFq37DeWrrHkpDGC+j22O9Rmw2a7I4ktPghO7y6QJa2x/PzzZ/Qm0UnPMU31onA+V6hAyKRUhYdWKhqlyCXhU0JTMLmQQ0VtlpxRrPhOZN1YotCpTo9LjrjomHztnyzeEVMg5EDfDvS9Ymgt7nRhXhz+cuGw3TF0HdY0NNpiZEPwheAXjuEBIVpizEyjI4RMyf8SnfpPfYRQn0zrQiqKUKSyRko+ulRkJd+1XU+iDoHCShWKIQLVJv344QPTONE0LW6ema8j0XnKx2HU6mhx84yRmq7raZqWTdfRtS03+x2Hww6jNTF/JJoUrtexemo+RkHrX3ll4/Oxv8WazhTrf/qHCNWalkesW3+5EhCbRq/odUGJdatY+LgNkQhtEaUWw513xJTwKVZ7tBB1CyBWsaFUWNvQ9h3b7cISElI+MS9Lfd58BKdQ459I8Qec69pnqwby9YAeE1F65DwhZAVdTNNcKXUhUFLkY1E9Foglk2XFsSJ1HeJIXX8JRULhU6lx69nRqjrEM2rdHiBWHHFXD63bHVDFq1rVy9nbd28q2ljULWpOqf6eLMsnO3z9Ka8RqI8yx48eFvmxcG0NXdvQ9z1FCOTiGadqKA8ULJKkFM12j80F3Xm8zzg1VlysKAi5EvlyIZeIlLXf1rQNKtX4VMqp9j2sISRfQTLI2uMsmQBYbZG2RfdbirIkoUk+rOV2hUuZuCyk8ERO9buz7xqKqL2k0jQYnbBNJWWqjxdHZWrUSre1oN13WFlwybG4iRIWZM50RhKRhFKpUJSaMPHOVay6UNUYL6rbZmgbhtaysaYSMr0nhojRpv4sSEmRkrz+SkJwXRZSiEQfkD6udnuLG0+U6HHXB3aHPV2/wU0LOYbaT0KsEJ4Nt/sDdze33BwOny6UN4cDISSu40wWlnFyBKYqUiyFaXKEHAklIZRE+AxzJOOQ0mKbbe2JWMsS63dco8i6R3UbdocbaHb4LPjw7lgHo6bnZ1++YBCePl55CiORTJwutSwfI1IXhBQYaUApEqBKpBGSJhdErFkoERMasbp3JF5pkhKffv5qD2upYmVRGGe1mtcLwzBgEFhtK3I6Zvy4MLQtjdGrd8TSth1udiwuU04OqSwpZq7Xmegj+Z/29f3xF40QQfqCnAM//PSOGEJladNg2pZN3yFkYaYwPx4JKbIER1iqC6KkhIwVhzebBqEUQsnKN1/Le0bXh6bRmhw8SwqMwnJ7d8/Ndo/qX9Jay26zI/nEFCZKApHBKIPRGudqWVWt5d0YIkVRUaOq9iSErKKaegGo3YyYaxFMComkkEImEYmiMDtZS65Z4QP4JJijxojqBSnqhm6/YdN2XL//lnmeWdyEVnadggSOi8flRP7qa5T8FiUl15CYfbWeuhDrylVLhNYIbVDG1i+QEuRY8DETo1uLYPVgHkOBHJjGCa01xmr8dERSc4M5OYTMdJuGUiy5aC6+CosQhSgqHu3t+yOn64zWguyXT36RF2VHIzINlbcuQmA6PiB1yzgF5vABnyIhBfbdjpQEm80edCHEll0/4Ba/iuuq8TvEwG6/+2TvLLI+UKenE40UNEpxu9/UOE0KNcsLbKzi6mv3wwsNegCz5ebwM4Zhw2Zoefrtf2B+eMv5u9+ScUBEU3npjWkZdgO239Bt73G54ELg8emhlr5K9aEoY2mGDV5Ggk+4OaBMQ7EdM5oiLVkY5mKqCVjJekiOkcmdCcEhheD25h4hLN3wjL5kdk3ibpMJp7fEnLC2oWhbOzHZ49zCdBEgE8HPhPFKp8v64k0IWc3rTavrYSlnnJvRseYoLQmrKhbv9X7D/eGW57f3HC8XPjw+cRrP+Bh4PB6ZU6g4TSuZ3IL3AWtbUna4eOV6vtaYXNsyNAYhM29/+hajW6xu6do7BmNobu5gcUgpeLY7IHPgenrPf/j/vMdIhRaKskRurGL3iy/467/611wnz9/95vd8//YtT+cTx/lcD2BAUyzJC/y4IFRC6UizkYTlBNGx6Vq2g2G/63lxM9BtOtqtwTQD85L45pvfouPEoDJ/+vIVu+2WTWd5I04s7xpmseC+f0O6OFrgZuhpbvZMVnJJgscQMaZBuISIM9EIklRkAca2tLZBtx0Xv/Dm8p6TEEQl2XcWj6iysZxwMeMDQCCJhXw5sWRPFAnFGqEomi8+/5zDdst+s+H33/zI0/HC23cXpOyhSGLw/wh99i+f/9inUIcj8+yAM84tPBzPNLalbzY0tlkLz4Lj5bqu+5fq1Eh1+i7W4uoiL2ht0aqWOYN31QrctZ+iNTlGig8slyudNvTDwOH+DmstQ9eRncMHj26qWNVojSi1z5NjAdY2KmJ1WZRKq5GAFNimZriVVoTga0Q4+NX4DHyCj4hVSlrXISmVTwMv1t7XZrhh0/Vo2/Du/TvSdCVcT58GDYXaFUwx8utf/wOmqVS5cXGMi2OaFxbvKyq3CNq2wRpL17a1kxRCvVzEeuFIoca3hNFrF6LwtJarP/p2Pub0zdqL60yzViEFvtR3cSgFnyXJJdLTlXGuhfDpOkKqAxe77+m0oFWSEnzVi9iImxZO4szvv3736eJz2A/kUtgfdlirPpXzL5cL02pwLlBx4arSmqw2VTSXEsG5elCWgsPQYXSlSAoJfnXiKCq9y5UqaSzacnj2gq7taI3l7XbP9fjE448/IKNHlkRnJK1WNEbRbXe0/cBmd+AyLyzOcbpcSEAO63DRNPRbxfUy8rEtKG2DaFqyaQlifZ8Y87FSyHWaSNeRcfYUNMZY9LP7OghsG0w5sDGZTSfQBKDeVrWtGoCn64UUI8E5tq2uElXvUGsBXlnNHGsZfOgtTmbckpjHy2rjNigSRgs2jeWLV3c8uzlwu91wPJ348PTE6VoH0ufLhSAKylbfmk+BQL2gp1zPGccPb7FS8vz2htbUIff16T3z+YjSlmb3nG3b03y24cOH90hRuN0MiBiYjo989R+W6oZxC4sPCKn5xZef8Ys/HZhd4uvv3/Hjm/c8Hs88PD6SSiKJTNPUxAPlo1gvUaRFLIKYErZpaXpLv2kZDjfs9jvunj3DJ8V1crjxAt7RCvj87oa7QXLTRN6Xmflhz3WwHN/8hBtHSk7YRmN6S2xbTMoIaxiGDdJH4vmKd5kSKoLXdD1d32GbhilGTstMcFMle3aaLNXa68zEUEET53HC+EST/6BBmBdHow1D2/Hnv/wTDrsDu+2ev/sPv+fDwxNv3h2xzVDt8qm6ZcRHD8D/xOePvmh8nM4bpevDNCeElNzf3zEMPZvthsU75mXmh2+/IXtHWepqh1JvU8h1QpMjShSEUHRa1sJYXjnVZd0y1KYr2TvCNLHYM6bCn5GM+HisJXNtuM5nJj8SS41eJSrKUJaad1RCImQt6QlZJzdd32GtwRpbS61u4XQ58nHcJD5mC4UgpEKWUKRC9z2SSntAVEOm3d6yub1ls9tx8oX89Mh1eVsvN2Rk9sR1hT+PSyVDKMm4eOYQmd36sF5/j6WoUwddWB0iupatqIxsH6qXYxh62r5DG8t8XWqxt8Qa60LRNw3ZGpSCw25LyYqcJU2qRdVpcvXmm0JdkYpaDMzBr9Exs14IBbJ0hHkmlUSDpBkG+sOeOGb8lPEuscSFRKLtW9AbKD1DN/Du3XuOxzPW1Eyp94EYUhXpaIkyAkTBWo3MtcAt11JjiZlLmMgFfKglphIrAi5cJ+b4xNtvv6YfBrZDTzwfyd7RNlXUpURey/q1u7E4TxALQU0sqZKBFrcg1FrSE7Xg+fF7WnKCXL0epCoeLKpe8sqKMxYl4S5PKK3Z2J7tzY6hG3j+/DOmxwfm4wNLeCSRGF1ECIVtLN3+lv5wh9SW9nitnRHvKnEl1h/Pj4Xmimg0KCN5dtjjfMQvET+N1RujNa3qEKLQas1uGNhtOjZDh4+epjE0qVqxQ8yUeUGlRKcrV75IQQw1eiGQ1RkgBEZoOltz51dpEalO4LqtxTaVrLKx9VBmmyoF9MuIkAL30dAtFbbr2fQW20pUURx6gz9ssQoWdyXElbwl65+9FlVkZI3kpl1lg3lEupmEYI6Sb+NDJQ11HcbeEAKc3v7AodP0vWV6/x3ppLlowXh8T3JXsk6UXlGSxl1cJbn5hSAVITqCC8hikFKjuw2lWQvFKYO1CGuZFSwUUqPYb3uUNbR9hyt1yrh4z+wC8xIYZ08ca9xvcqFOV6XEBo91C3FxOKkZS2G8HpnHCb9MKJ0QQq+ulHrA/ZfPf/zzcTOqVC00Sym5ubnl/tnzmuve7PFuZpln3v74LTElgl89NKXS2/5g4gZRf/iQpWCkQNhaVOVjhn51LqTg8fPMYsxqsA7kGIgpVISuUhyfTkzXmRRzzfsnVu9Cfcab1d2hmhZp6j9v2qaiepVkniec9zCVlXiXP+F6Uy4sPtVJuFSoZoO0AtnIegDSlvbmBf1mS9N1XBIEqSjTWKOXH/sGtarLOM9I79d3k2MJsRaiP2KNEJ88CDnXWb/6uBFZ+wqpaISAdujpmhZj9Tqx9gTnVqFitTkbWbeDQ9vVzgqVaDX7wGV2FaRSBMHH6kgSkuADjVZ0Tb30G1XJVy7kNUkAxjT0/cDkBfPiWBbHMtdoXNO0aCUR5PqdEazOiApzSKWsRdmKIv+DF6Oa4I0UGEWNrfqFkCsy1sf6PZLrt8gvnsvpzI/ff8/QdgxdR5hHZAoMRlajO4JGrp6mnKtnqhSSkEw+4EPAeY9Iq6eFQlqjXPVmViNwMQSk8EQXSEoSpVj/OwlBJriE0Yq7bcOwOdD1G149f8b1UTMdFcv7EZUdIXiEKBij2Ww37G5ukdrSfDhVX0iMjONCCg7nAug6uK2dJ4MVgq4bCCHgncctrp5ZlAGjUUBvFJveMvSWzdASgmOcbAW6aEVMiWmekdFXsMPaTvr4Lpbr91+qeiFsrUEmiZNqjUIGBqkYug2m39FaS86B3tSua1wcF7/glgXvFmzbYjtN39fLmtKJvm8ZthtcBjvPhBTquUpU47qgYLRBa8GmUxXQUjx4R0QxZcUP31546FrevtmShcGFzOn9A0YKlDFc3n5DbuCqAuPTB8J0IYpMkBBVjZRnmckkUgrEmGvXrChEFgjT0hw6tKi44SwFixQsGXypMcR+MyCNRPQtRdW46DgtzHP1ayw+k0ogMLPEitCOqTA7j1YL1+uIFtU1NI9nwjwisodYt8Y51Qilkv/0u+mPvmiUXNeG1mh2m6E+4LXiV3/yJ9w/e8bmsON4ufB4PPHmux8hZMQSUNRLRlE11kGpyEFVBKooOqtIqSCLIMXaPaiCpXpLKs4TxiuTADt0hBAIi2eczxQKbT9wnk5MbqzEIyrL/2M1yxaJUaZy0lVBoJBSc7Pd0Q893TBwul64jhdmfyHGsk4b6zqqyPWiIQAhsX2PMA223RJTjTK1u3s2d8853N2xmwIuSfLDkSypX9ACKWZihmX26FWMNI0Lc4zMIf1harn+mUkhkCvOVSlNJlW+dfNxSyI5bHYcDnu6ruVJPeHdhHNhJYsourZHqMqCvzncknOdqm2E4HSpecRqRc9E6jpXKUXyoWZ1m6YSQzTIrOqUuUAvFc1my/bmlkUuLKkeXF0KJJGwnUWqHq01r168wrnAPNcLVkwR7wNPD2dSzggjaVBoJWkbS3ZLxQCyXkpT4TrPhBVFHCj1LhgLMY6kOfDGZdquYzts6MOCLZ6usXSm4gaVEPjoWaKvk6tUEBh8rCJA5xa0WUuapayPNlYBZa5Z3ZgoKhFVpLKuC0VUuWPOCe+utK3lsGn5+atbbu/uef3i57z/qeGDEfx4+q5OQUPGaIvtOvq7Fzx/9ZqmGxiOI29/+pGH92/JAUqSIBqkFrXsTkbIiFaGZ89ekmMhuMDbn76DkmmNRlG7H43RbIeWoW9oW0Mza6zVtLkjC0lKEJaVcNK3dT0uJWEJFfVXJCLVWEUjLb2pPphGtURfEX+t0my7nt3hhvv9hpA843IlpVq+00imcWSZRtqhRyvo5I5GJjCZfachb2i14t3TW2AVQ0lfKV5FVGGRydx2iuhCveQ5Rw6ZZUo8vT+vnP4OrfeUopmmicOLO9p2x+Xtt5xXKooqAREcSkZyr8jF4K4LpEDyC0EpXPC4JYDWGGkwfYewteyZfKAoSdSCMY7MBXKrubvf0vcdm27HkiI+R67LyDh5rsZzvS44H5kWh0sZhKTpGmxwWKFx1wkZE2GppftlmknB18ul1CvNT1V60L98/qMfLWU9uCpF0zS0okrivvz5L7i9veP+/hlPj488PXzg7Zvv64EkhvozVWpfTK7mY1UqcELkOvDRUmCtwYX6rCy5VPGlhOQDfp6ZpKSkGn2ZVXVbxFzRrtO0sCyOFEst++b6TBNUBolRmsZauq7DNFWQ1/YdUtXD5VlJ9DLXgzpArheUsvYuFldpMcYq+maLVBYjLEmsF43DS4b9jm4Y6Gdf3zXyPSn5Wmxe35MFmBbHR3v4dV4IORPWy9W6gKkeq5TX7sg6EFsPnEZXcpOUgk2/YbcZ6NuW6GbcPDEJSKG+4uzqeNBasRnqeSIXWJJAMjNPrrpGcvVvuFUGSsroxtL3HV3bYUgQ6rshy0zOEms7+mHLNmlgrJFkX+WsxlraRlf6n5LV+bUG2XxIuBCZZ1fHlWsfQ6yXESOqI0tLQYgRN41c51hR7kpX/9Ha+wzLgnORFDJD13HYbOjIqBzYWIlFo6iDsBhrZHMer0jvmWOucaeUWbz7lLooa0kkQyVY5VzjcsGT0WTjSFqRVZ1eV6FIIJVMp1teHG548eoFu/2BZ/fPOPaKYyv4sDyQ5kJaHFkJlG44HG55/eUvaPoBMzxwenricjxyvVyIwRNDwmqzGsQ1WhuUUtzc3da4Tog8fKibLCUUVq4/S6IwtJquqR6ouTE01tK2iSIVOddnoYiSRnVr5I4as1svxWqVOyqtsNagssJoQ3ZVFq1RDN3A4f4ZXduSgoMwInMgOcfVzSzzRPCO2/s7tISuMWA1qQja1jJsBxyC5nKB4CA6BK46Ysj0ptBY2PeKGGryIvu5blZdYXyq0TWhNFK3FCTeJXZ9T9N3HH/KXGSE7MnXMzIETI54WYhqHbaLetEIyeNjxoXAki0KTdMMbHd7+sZCjkzLxOIWpuTxuZAEHLYb2r7i1VGSVODD06lS50ph9tU/lpeFcanDZqUtanGIIjgej/X75R3T9UR0DiMystSLFzEi9EcTyj/xjP5jH+bPnm8Y+p7DrsdI8CHWScPoWDrPdtegRcKqiJEGLU219VL5A+TER2drCaUKhlLG4VBa1gdSqJPDEAPyIw6OyJjPXKcLwqg6WfmE5Kur57Ai8RbnVyxc3WLYpuF+d+D+7o6+azFWYXSDlJrrNDJOEz99/wNzcLjgyQGsVEhTbd1lXSlNwde+hs3sug4lW0qsojZtG4abG3yCt++P9cYfE73R4K6IHJCqToBCKozZYWLCmLq+ShWAjJRrHCpDDp6QMskFtK5yHCsEvWp5sd1zFlXEMr7/iSaMmM3AIUPRkJVFbJs6BVWGXBI5F9yx4j6V0ey2PdHPaCqmMBfwBYwWaNXQtj2H3Z7D/sCzFy9plMKkAuYduSREv2UpW+bY8/zV5zx7WUVY33/9D3x48wPv3n5gvDxRcuLhp584X874xbHb72hth9hsWaZALoWmb9ltuvriyRlNxgi4PRy4jCNvH5+Yrg8sPlU/hag386IKgoAoic5s2DaZ+x4G0WBFQ292DI1BSRinK/5yZvET769nAlfiZUQ1tfimZCWY1QJVXF+sgug8AsnQNSQiJS1Y0ZJFoEiJSAFVIroE9jbz/NDyr/70Nfcv7ug3W/o2c/vqhl/e9rifvyDHhRwnpvEBqRSb3R33r17RDRs+L4I/u07Mlwu//vt/x/H4yOPDB4RMlFx599g6ubT9ntY0WKkRZJbpwnI5Qw4ICUY2+MuJc5iZTo8ssVqSu25AmgbddHw4PeAnR9Msn7COJeb6XcyCm+0tvWl4drghLSOLc5hskaUeNL773Vc0bUO/3XBzu8c2mq5VlG5DyIm33/9Qc8IZDts9RWo+vP9AePNASFAmiHPd4OhmV4EGIVWLd8nIkjBEGqHYGk8IC1kGDvuOzdCwGSyP144lZpYkmZ3GhYIIiTg5Fn3luATcMjFOV0RTMbgFXyVM2wYhJKrbIduBa/SMsmFSHefU0/V7Nr/4FX/9r/6aF8+fYYvm7//u3/GbX/97fvzm7wlBVoKXMFjVsBs64vGInxdsyti259Dt2W/vWWJmioEf3r5jcg6XE2IeCdPMb64ndkPPYTNAWtgOkrvbLabbQ5FcTieUYnWS/MvnP/a53W1pu5bNZqgktZQJvh5Ock6f0Kxt3/PRW1MHZ6wZbs1HTmyOoTpfZEIZU23E2qBUjSm5pYq8SoEQAufzmev1CnwkQFWcqxDVbbMsVaTl3Eo6E4LNZlP7HIc9m6HH6FpMlar6ofw6EfbBM41XXAjrgU1Up4/gE7bTJ4HOkiQMsrQo0SHtQFYtKMs1W8ICtnhOLuOyRNqW4uqUWKxFbEi4ENaDYxWZVSdRqTJCURGqIWRSrNh2KeoWaTN0nzClH7cW0+MT2ntk19EbhQFaoyugQ1UfQ1m3JFaVWlxHsO9bLAU/jqRpIXwsYmuNUAprFF3XsN0M3D17hVUCkSPt9lwx8m1PNj1JtTx7fc8zCiUl3v74LT/99B3ff/8D0c2UnFCifCqDbw83NL2kyxUNWkqhaVrubg40xkDw6/M+c7/f4tzC+Xzh9P0bZl89ClKb2tdIlawklWQjBYOAgcTe1sHNsDVsGoPVsvq0zlfeny+8f/eh+sJOZ0zbffqzYO28fITLpAJ5WVAls9ECpQUYQVKCKKmT8RgoyUFcaEXh1mj+4mXPy9dbNrstu12H718QX+3hT18RpivueqSEBWM0u/2em5evaYYNX/xCcT4eOR+f+OGrf2C8nLicn2qsKSWWsBBzxTff7fZYu6YJYmG8XhkvZ4oSFAVCS6brE2SHcxOLyyQhsMO2xsStwfuFkjImZRR1BpuDr++mAtvNrkr6lMXNHpE8RlmKloSc+eb336B//EC3fcOLl8/qsM22RFfPKfPiCSGTsyAXyfU6c7x+jyuShKLIhvUH+lP/SMiaupElo5JD+oKRiZ3a1j8XmXn2oqVrNG2jOV/PuJhYYmLxU0U2O0c/wN4o/OknlugZvUPlhBbQKcUiC1lLOtug2wbVtAhpKTIRomCiZ7O94Zd//lf867/8K+5vb5jOR37/+3/g669+z9vvvsLFRCzwYqjR4qEznMexYptj5OZw4PnLz7j6xLhEnsaZ6w9v8S5ghK40Phf45scf2XUN+74leEfXau7udiA0uQic82itUX/Ey+mPL4OLRMkB5yaidIRQc+Tn4xNKSPphy+wW3DSS4kdGd131IgtaKYpYH1wi1XK0qg9MmdfpnawTjJjWo56o248cq1ehpNqtIGWsrojbVKpCPhdR5XemwazlvL5puNts6LsWJQU+ziQXyAUu15FxnhmnsUZlcsZIhRQVw5ZirbnlNTMqZWVfhbz+NddsDylnFreACOQiSbFmVJUUKz+6rOvmus70uZBiJpRQ6Ubwhy8z6/+mUFG81JW+UmuvpGQW5+pWJ0Z8KIyzRyDYt6audpWqESSlENrWCUipUjQlBUpBYySLqbE1HyOi5LUcFUix/r0KCtYYrO1QUlFERnX7WvRShtFFyvnKHMFYW7c0ok5ec6yF4hg8D37B+/qA9DljhagT/b5uPG6f3fHi2Qu6poFlwY1nwjwRiyAWWaccSLLIIFTNSutatrbW0hjDZrNlsJZto+lIKxO8oNrqVRnMgBeRuXi4XiuVLAWMsBgtqyU1CUoSXJ1bKSMSpTRGVS+EtIaiFc6AE7kanoNDElEE+gZMWpge3/BmGVGmxdgBKRRaKp7f34FUBATddoPUGjt0kCNuGUmpdmNKDjRG0jeGMLRk6kTeJUcWVXQkZcFaRW8bDrsNI5G8XNFZYiR0rV4PDhUXHLLAZ4FPHpmhUbqWO3MV733couUUVyN6YbAtevVsLH4hRU8zNJRQfzbGVB0g0+K4bzr63ZbdzZZsIOaIRtdpYS4cbg6EEBivV65LzQlv9necswBfEcIhgU+ZkgqKjC51q6VJyFQvgVIUurahaw1dozATZCVqcbRoihCYtkUaC9LggmMOmTkm2m2PUJAwjNOMzJntpoOmhTUj7nNgzpksLU27YXj+ivbuBWp/y+V45Rjh0SXmoohZUGJi9onGJ3xi/fsQpCTp+oF+e4NyhTkmlPP0UyTrickvn54FVx9QxmODIeWAyLXnYUql9MxhpJUWIcwf+6j+Z/cRuWbkU/C4UjHJ0zhzOh4RQjIMW6ZxxM0fYQc1pirE6uSRikJaU7NlndSvsI9/9I8f02u5lE9OnE/umpQ/FbxNrgfnsLpVQNCtzztrDNthoO8a9rstVtfysVtmcq7gj8t1xMc1OhM8acXd1ozNOhT49EtWOEYWhFhIolRi7prP9yFSpCfmRIip/rXL+t2q/g2xvueqYV0Wakk5l0/egwL/aKXBp64Fa5SkpFQvdbEOaj6Wdv28sORC0zdoAb1tsKbB6HpZSKtPSgj16dIhtKI1ks4qRgekQiqh/vWIvHYoZI2UGlujvTmiuzqYLMpydZF8vmJ9ojG6gkeUqh1GpQm5xqNc9LV8i6ANEaktUmm2uwNKa3a7HZ+/ekXftRS3cD0+4cYLGUHMkoQmUal+Smna9c+4z1TYiLXsNhtaoxkaQ0fEiEKrCm2jaXQlGxlrMGvkj1IhFVbUd3nb2kplTJHg3ac/F6sEWhpaa6s3RFsWBY5UI+fJ1SGniPRKYvOCO77jfU4cbYex3er7kDzfVTR+O/SIYlG6RstTDMzTREITY40aGqNoGkNoG7KHLAqsvXOx4jytqkX5m90OQ6H4GSPyujnQCFFW0d8VnwQuCpJaRZqrpLeQMT6QdbWee+er+0Jqurat3SelSW6GkKqQU1mShctSz6BunrHGsBk2HHY9OTpy8EzXbTVk58h2v2fxYe1uZYRWbDYbzi6jZ8cf4oL1Z1mtMlzKKh4kr7HeTKc7eqvoGoObZT3IiTo8UCERXKjSOyUJwbF4z+Q8fVcHnkkpvKobqbYx9d1kG2JRBJHxBZK1lGGgvX+Gub1DHva4ZWZCck6Zs68LgBwTS8w0uTAIVVHIIaOkpe+3DPsbyuQRTSTZjv2SMNNCCKtYMSbmkmmMIuREyPVnheUKYu0/p0wRhiz+6WvEH9/RiI4ledx8Qa4yF+cTP/5QOD8dscqwBMe4jCwf1zhuQcuCNvWGJhGQCyHMGFMJBWGpB/QiDElCEPVgoKSoh3sRyRlShhDSOnEFua5Ss8okqUFp2m7L4XDH3e1zXr94Rt8YBiu4nB8YxzMPH94xjhfmZcL5OhFKOaMxKKUZmoYQ6zZhduETnzwVhaiVYpxLqBxpVSLG2q14eHhASl2nWOvUAV1tnhRBjKWuVIVkLtS2nguVqgCrLHDlqBdIyLoiX6dcmYp7DTny7umJGD05F2JpCNfAdQk0LwZ21rBrDZuuQRuDaDqs7SlCcrle6/ovR4xV5EZz6gxjcCQyrVSUOBEjJBpy2lUEq6mT3yUHxHCLLBlXHA/nMw+XulkZdns2uwM2C5RQGCHQuk783n44onSDNhYZEp0BqTT9Yc9ud+DP/uzP+fO/+DdsNzuWh/d8+/vf8ua7b3j74Q2zSwRRyWZCKqwx3N3d0Q0DxhgONwf2+x2tSMgYEH5BRl+N7MmBVcim4XB/gF6SLfw0jgQXED4xWEXfGfb7jhItMQSu51M9MBbY9j1Do7ntGrbbDrThnYfHOXMJgbBckSJiZWIrLOX6xO/+x+95vEwsPpGFZrfdc3O45f/wv/2vKytkPPPsfodpLLSKh+Nbrs4xzQGCh+BRcWRrC92hZ8qBqxM8umq61UhE8TS6YxgU6m7HWUXS/FQJEkqwHdq6Zk2exSVS0UQ0x/mINIZh7egUCuOyrNzzAjGS6vKR/W5Xs9rhwtWdIWdevnqGiIXsKxrRxcycCsPda569eslnP/+CwEIuEfOrUtFvKbLMjsfHJ67z94zhhLEdP//izzmVr3n0ktG/YVzWSw8RKxKdDGhR0EWCd5WwgaAbepoGlEqU6JFF0DUtxbSorMja0GwGZGOZzhNLkThh2N+8QBlNiJ73p9+TFs/u1R3SDEjZ1AmNL5xnh9lYxGbH3ec/QwwHzknzt1/9wG9/eM83D2eyMIQicdPMw9iTpKGZMlNQLMkQQuFme8/Ln/8Ccw2MLqBGz020yMsZd3pPXhKeRAkeVQSmJLyr21DvE0ocQUAQnv1+wyD7P/ZR/c/uE5elSlCDX83AkfN1JMXE+Xgip7xGJB1+RYmmdQgmlEQZXZ/DVDOyUrXo+1HAJsXHSOvKfVoP+VqpdSsCKdfNccq1a4CQFT2qLdpaDjc3bIaezTBws99WNKo1+GXCu5lpXFayi+fNu/dVUFky2tp6sDb60yEzxrz+cwBJLtUEPS+xloyzRxWF0LX36INDKojBrfLAurH4iLnK5WPfLMJKq0r5o7h2rWewUhvX3mdJud47Sq641pxwFJxzlXbjE1PMxNnRlC3boWO7Gdhv20ps6m0dmKWIczXCmlNCGUlvFdtWM3uJDJE5+dq/KAopGpQSaKPIUhPX9wOtQZSKI397vFKOV3JKHLYbbvYbTEk01nDY78ihejKurvYFUy4oO9H0gra3PH/5mt1ux+vXr/nzP/sV++2WMF356je/4ftvvuHdT2+Y58TVQxAN2IZ+s+Hu7pau79BC0FhL0zQcNgNaFFSuSFhSwBAxWq5Y8oKxukZcupbia0S0tXq9jO4IbsF5hxuvaym6sGkNQ9tye9iTZEMommMAETwlQvYzWiYanblpLDpc+ek3b3i6emYXmZbI3e0tz27v+C//5/85m66ls4q26esmxRo+PD4weY9PgrAsdVsVHFIU2sYQSySXVc68UrnC4lH9hk3b8/r5My7WoKOjJIdShc2wQgRS4HSeqL8blqKpMaMEyxL+UXStfofnccIqjbSC7U2P1QZTCpfLkRICu756PpSyXOc3hFyvyIfthhcvnvPFz7+sEI6ScPNY6aS5TpDfPzxw/eob5OIxbcfLV6+4uMRpnPkodM4ZoouotatR1pOzoKy42IQV0CpFpzUKUfsNjaXVLSEVvAdjO6RuWKaRySeuLrK5vUM3tbzvr1dSLojNBmFbMAY3B2YkYwbRdYjdDvv8Oa7vOQnJt+cL357OfH888/Yy1j+jHHiaHNJYdnuDDwLnoRkGtvs7bp+9wD2eUKlgDxLaHZfryNs377meLwTnaRtJFJKiFUv0FfxweqyZz9VKb22zunT+pz9/9EVjfHiqX0BjKKq27KcV6Xa8ngk5MS8T8zJzvpxI0SM02MZirKbrWsJSD7XWNmsR27BttpUvnv9gFtdWV+M40HbNygiGOVRqRw6RoTdYq7F9V63AukHIAa0sBMdXv/01lIiVkd1g6FvLv/nTX/F0euJ4PvK7739YpzQSpAatEcYgRf6UJUwrolaTkDlAcsSllvIq2rZBqFogE7KuAnycCHkhi0LJFY1Zj3GrxRVq5l6tuLwCuggodbIilKgHtAJDY7BW0LSK2111SVxnV2NrMeNyLeKEDD+cFnypRcLiCyYnrC44H+sXQ1vSeqP3XDBW8rOffY49nZkWxzhOhBQpCLrNgfvnBw53G67zBecDl+uE1DX7mUqqK00KYZpI8xXcyOubHc1NQ/9nP+Pte8X5csGohtGFGh+ZPblMZATbzYGm3eAW+Pbb79h0Pfebiss93L/kaZqQbU8PtNs7hNRsdge6vgUKb9/+yOP7t7z/6VsGDa2S9EqhskMrQbdpCeGK8xe++f5MCAkfM0ZkGpHJOSD9Fa0SW1pCziwpV1JYyaRUs8ZWKTatIk1HfEzMoySzQ4oWS6Y3kl2veHG/R6bAOXvmCYrM6wZhQcSR88OPiLSwnB+5vIkIrSntBtn2FKlxPjI+PTGfjuRlrFnoXLgGj8sZSOtUKJPPD5QSUcnTi4JsDRx2+HlCCdi0LVBx/ZfFo9sW2x94dvcSqatB+ZAXlCj0bctHw+uHDx9QraLtOv6L/+xv2PU9LYLvvvo919MJTcA2CrWRuMUzmJ5me8P9q3va3cA4TRTh68aSSN80tM3AsNuQpOThOvFq2KFtQ7vVvPr8Jf3tnv2XP2NJgSk4/u1/898wX55Y3JG5FFQpXHLC59pLuhazIrULTnZ1ZV8MX/zyTxn2d9huUwk0fuGnbw16mjBu5tnLnzNsBzbbnl8rzfXhA9ZaUvSMbmFZIilWss1nn73m2avXtG2Lcwv+euHb77/m7cNbjuOZkmaMFPQ3d7z4+Z9wdzjw/PYZ5nhkWuY6RW0HTmPgd9/9xPZwx1/8q7/hv/qv//dkUfjmh2/4H//tf8/3X3+NjJ5nN1ue3+/47qvf4MaJJWRSrIVioQLxfOE0TX/so/qf3ef89IjSqm5VlSLmTPKOy/GRZZ7w6xbYec/5dFpNxqC1pjGavu+I3tXDrFY0TUtj7drJyIT1YvKRjAb12dA0phaKpSD6mnvOuWBsu8ZUG4Q2SG1o2hYpYXETb99eEBSkyGz7lq61/PLnn/HwcOTp6cTjsW5YRS40XVNx3FrXYvbHTsG6Xik5V29FDohUt5MyqcqLxVOyJAcqzMSNlDBXH8c/2ooA/2gkXQ9WlYxVNzei1GvYR8mZYPVC9T277UDbNuScmVcXSYi1lF0bIIWLS6ATqsmk0dHEzEbV32fdSBwzucyEnFEKur7huTrQ73smH3i4XBmXQAa2m5bdfsNuv2dZHCFMLPNMzLWbKbShyHoZ9NNImE+Eqeez+wPb1vDzVy8wJXIxCpkjsS2r1kTgnSekgu36T7b33/3uK/qu5dXdDdo27G9uOZ5GMD16C/39ZwilafqOxirIiad3PzGPZ0qKnLTEKLHSFFcBbdcwek9eZj48PuFS7WSg6mCzOphqrK23mlAMqsRqE0/r778yNLpgRWTxK+LfS0QElcDEwNBqdp3l5W2PyhF/nLgkV7tqqaDSgogz0/mB+ZQIy0RMCaEUpusxwwBScTyPXM4npssZsW42corMwRNzLahXYJpkvo5MxtBKSasEpdH43pLX4fF223OZHNEFPBJpWrpmi7AVqtG0HTnXy0y3YuApiYuxKyJX8ld//iu2w4DKhfffb1guJ0R0SCSlCO7u9kjd0AxbPnv9rIKK5muVGJeMNYqm6zHWglT4AvvTBTUtGNuw3fT84svPub9/xu3Lz1hCZPae//C3/z3j+Ynl/IjLEpUEZxeJWSCEJqmegGVJiutSiEWgdcPPf/lXDLsDMQt0zT3yw1e/hXlE+oVf/uVf0HZ29cgJxuMR1bdVEVHg6jxzTBQlefbqOc9fv+Jwf8sUPU+XM3/7m1/z3bff8tOHD8i2Y7Pbsulads9u6DcD3f6Oe7NnF2IdXJiG65J4/3BiuLnhz/7iL/mvXr2mIPj2m+/5H/+7/4Hvvv4WHSc2257NzYYoBHm6cj4eiSGRqbQ7nQo6/P9R2BdcQJtSpTaqvuwV9dBcRGZ0I9M0Ms/jSt2ouD6x3tytMZAzMgikKGita76LmkEkVIxc/ggCr488lBTVqqokmUISiUyhsWrNhTfkFT9ZSKQwE5fC+fwEJWBkwjDQiIFN8xzfNLimQQlBkisxW2ukqpz1kgJFpE/4wAqfWmkDJa0UokhOYS0q1TpdLVcIYnCkVPnphXV7Rn03FD7+i/VZvv5LuY6NBFT5USlIAYNR9H3DsOk57DaEkJidX7Gv1XIutUFbg+ktuh9Q3RYICGNoNnukaUEokl+YgyOWCS0Kbduw7TfIoWeaFx4fHjlfL/gYaU2VQWkl8GHBh0CMHiXrrTvECKJ6uKObCRK8ArkxKJHYDQ3noyFYs5afVs52rhGwj3xmJUT1jjxE5qahEy9gJZZsD3sKAqU1naudCGM7cvJ4N+OWmXm84JYRWkUxBttYCmEtzzZ1+pdSlUSV+mdtTUNOgiDrZUlRqoOjZGSpl8xGa9CS7dAzNBU9OLvKfidKpFzQonaPrJQ0WtHoOtUxRq2Uq4+c9khKgXk8Q1xYxiPRjRQpodvSH+7RTUcKGT+PzNcLMi7r/7YwLQuhFLJVKF23Ytk70jITlUI3GrG+lGoMpPLfxbryTesLAG0w3QZtLU1j6WVlog9ti1T15VZ3Z6CNprE1cmCKoDWWZC0yZcw6xdUalJXYToEqlBIIcyLmCUogigCxo6QedF8dKVajS/XThDRjTWE3NMjdjiAlS0589Q+/46lErmGssTlVWfqi0ShloekpVpBNIQpNpFCKYLPbc/fsBbu75/hlYpknFudYxpFlmtju7+mGjrYzaNMhlEFIScqViON9JcMJIStW0EpSDizLyLwsXK8nlvmK9w6jRY1nbhqEbcjGItseu8mUpqUzhphhWlfyutvQtC33z56jbQVTPL59xM+O88M70Kb+fAhFFIokFZ6ay5ZZEHxG/BFSpH+unxg9UAu+SgmUBKNV3dSVhHdTpaw4t2K786dnrdKSxprV5i1IKdf3jVbEuMra1kt/Xg/cUM/k9d1Ui+gKXf87OWOMQhuDbZvV4yHI0ZMoa5m6dstESRixq0jq5lCn3FIg1SqFXCM5ciVQEdf/948xI7GCIsTHOnekXhBqnp2kIQvKStMTa5xG8PHvo3y6OJWyTqXLx//k40d8Iu1o+fHfKXRGsesb7g9bbNOweMeyTKS8RqaFQWiLshbTbzBDj91sQBWwGtUO9LttRfjKMz4loncg6zOl6Ru2AmbnKznneMGt/gT98XIXayk5hFAvCx+zbbL+DaUw4+fAQiDvGiSZ3mpaLQlG0bcNylikqhvKkOtGRKvaBV3mGTfPXK2l15KcK3RkfziQiiBLUz1Ja1HbuwnvF5ZlIriZFBxZSxotwWh0a8nKkEV1ZMScmeJaJge0tegiUDHVP89SiVqSigOuHora09tsOnpbex7OOUgZGQU6iSrlKx5DoRGKVq2pOyUQa19WUCgpVMfCMpKjZ75emJa5UgKHDXuRMbYhhhm/jCzztQ5cVwDKx05skfV8Vn8WI9453DyjrYKP76b1+2NU3YCkUiiiCgWVsSjbYJqGYRjQqkcrwdAqlCyIkumNIXpPCnEFvNRzmTWK0hiE+uhPK1hbN4BtYypJskTCEvFuIudI21ia1JFyi7INhYKxBu3DCnnw2NVF9Vo9IwqBT5m3P35baWPTlaJM3aihkI2ukrtuhzCSrCBiiEApim574ObZK5p+Q47VG3KdJsx0pXET+7tnWKtxy4S0LWhDErUmUFJm8bULUwRYYzCmUkgXNzOOV55ORy7TyBI8u2GgWalZmJasLOieZmhqpFOqOlT1keu0YIaI1pab2zts06Ck5unDE9FHTm9/pChTN1ooArr+oyjr8xB0rH3Kf+rzx1OnCkgkrdI8u3sOwPl6obk5oNq2Fr9VIuAJwdXVbKnFXaElw2Zg0/WUlJmvE1oLtBYsl2uNGhWYp7mWzVIV2ykpEDFWUkTbgailOFKli2itMVrycHriMk44t0pKYsZahbWKZmiYx4CKM5euZ5on/LSghEBrgxQaabqKaDOasIzVYr1iJbWqT/K6Qq8kAIiUspBjRGQNxq6EpEx2M8V7ZEiUVEt+pbKw1nxrfQeUTKVbCdDy4y9B21RbpgbutgMvX77g88/rbfPxeObpw6kyoGOi3e443N1zc3PLn/3pr9i0msEKkp/o+47XP/sZu/0BKQQ/fvN7vv/9rzmOI6/3O7aHAzfPn/NXux2z93z13bf8+7/997x/957iJ9J8IYwDIVcZ2+12QFhNzImni6ezFiME+ZJguuCWK95GrAaSI08Twnn2XcPPfvVX3L/6HJckHx4eePv2DRlBio4Pb74mpJpdnE4vubu9Yb/b8lfP/rL2HEzP6bpwulz4+ttv+N1v/gNPD2/Jfl5xgpldM9SHsNA0WqKtQirqA1BqNrtnhOq3wfSWaZqJ+ZGubzBas0yVJCVLzc9uNz3tdsfPPn+JKol4PePmK0JlNhuNTB6dAk3y9Gi61BDG+n2tB29BLIVpiWgTsUvg8ekJkWbC/MR0earm1d6RdEOTIQu15pVhs+nxITLOHucjS0qkrOisRRuB95mLmCgp0FnJeLnw9s0bdpsNumnIMeO9xzmP7XqEtaxQSUwzcPf8Ga+2sLGCrdVstgNNaxn9zMOHB9799Iav/v7vSC4iloAtBasVd4cB7z1zcCiTicycp3c8fNiwtD0H1fDw8D3LfK50J2koquHw4mfEIih4zudHUkpcz+9obH3JbHafIYcbaHb863/9N/zw3Y7f/N2MbiW6sdjdgWF7R9/v2N/fYlRGC0948x4XAyJmbD+wu73js89/WQ3DOfH81S8YT0fOj08Muw2Ln/nhzbe8+3BkPI/szK7y4f3M5XJhQZKVZVqeuFwbnp5+pCSYpwV/fiCMJ7Ibub1/yeGw5/nzW3788Sc+nGdsf0u32bEzBpkz8+nMcTpxOh2RWvPm7Y8IJdkMW7abDf/5X/8bvnjxGf/X/9P/kTdvHvnmm28QqgCGbCwxRWKFG66G13+5aPynPlpJrNG0rWWz236Km+qmRWqN0Janp4z3y4qKrgMerSr9qO8aiq24xmVx66Ag12f3irausr1UqWyiHr+VLFgtaI0CLcg5EUNCG4k2gqHXnMaJcXacLtcaRyqFxur6vBeFViVUWbieNMt0xfu5gkfWKK3UNeNdKJUQuPYaqhOqduKErK4lZERQSUSlqPXfl59IUjJGdPZkciXarLeKGp36NAOrQ6+1MyiFWDepgq4xCGpBd7/tePXqli+++Byk4uF45MOHDzjvcSHTDBuG++fc3tzy5Zdfst9t2O+2eD9hjebubs/z5/dorfn2m2+Yf/8bxuuFTWPZ7zc8u7/hcNjjguerb7/j73/7NR8ejuTg8PPEPI4oDFJINjWPS6KweFcP6SKjdUQnR7xecKeKzC5+QSxXTPY8P2x59cWX3NzdI0zL6TrxeLrgYiKEyId3b5nnESUF7vzA8/v7WqR98a9RtkM1HU/XmdP5zDfffssPP3zH08M74nhElogi0e56pKgSVmUBA0GWKqRTmuZmj4y1l7rbSBrnUfaKzJlSMm6pFLoUAo21bPqedrPlF5/focmkZWKZR0Jy2FIJla2SuOJpSkKGSFp07T+ssIF1TYULC9crnC+PFdHuRo6XExmBDjOyVQzDhrZVxN5AshAhhrAKfef1AKxp2xZhJCUllmniHANeZvx85fL0gdYKRGPJsW4WFx8QdoNQtgIZlKZvWm73N9weBvrOcrNr6RuDMQI3jRwfn3j/7j1f/+7XpBAg1pitVYK7XU8IiVQiOTtSSKQx8f79j/RdLWk/fHjLPI11gKM00hgO98+rCDkncphxc+Lb6xkpDco03Dz/nOFwS7PZ8f7dT7RNQ4yxDheMRW4OPLu/Z7/bsd/fIHIge4fczCTnmQIkO2D3d7z+8hfElEgxsnv1mul84np6pB0swS9M5wtLyCwhMZZco6Dec7qcCUIilCUuV+bzIx9++o5SBPNcL4opR6RSbG9uGPqefrPl6XxiSZ7bu0ppa7TG+4AfL5zHiafTSEDx9TffoKxhfziw3+35m3/zr/ns5Wf83/4v/2eO1wvvPjzhU+2KedmTlawAIR9XzPIf8Yz+Yx/mH3Ooi3NcLpfqdhCykmpCoussTiu8kiQtSbEKhIiJuDiOD48MTYsWGlkE0QWiizTG0g89+5tbfnj7jst15Hi8rDdWsLZh6Fq22x5rHDEEwpwrF1lVz4YKEZ1yLSy3Bq1r4UgKKLFi03wovP3wyJIScwogTDWjClkP7mVhjJmUfd28CLBK1q2LMeSiiLGymnNMhNGhjUUpVakHpsryus2W6D3zVXDNtZgTUjWAftxqfCSXK6nXyXfCNqa+9KyleI9Iiew9y/XC8eEDxhjCPGNUxlqJ0Iq72wOvv/iM5y9f8/LlS4wqGBFwU6EoxdPTldnVw+vpPHE6TZyOI1pGRueYgqc97xBases7Pn/5jN5IHh6vzPOFd+8LMQmUNFjdga0P8yl4cIZGKrQSyBTJMXB++lAfWPNIiBGpDRTFh/cfOF1n5lC4XC6cjif6foMxio3VjIurk4L5zIf3M6enSscqRVGKYXKJ2S2cjk8Uv2ARYFSN2anC0DUYKQkpEmIkL450nWg2e0w30Nzck5ZIXEJFFbeG9rYhl4gvCXyleylpef7iFe3Q0282PL+/I3rHk19AGwiJ4iNb07PvGpQeMEZirSSnwDx7Hk9npiWQyfSbiqkMwXE8fUAXD2Fhdh7TtNzu93z2+ef02wPH00i4jowF5hAJKeFKQvUNLVCsRotajLuOM8UHymK4iMA8z1ynwNBXeI5znmVxeOdptluk1kgtWeYRLzJzK7jGDKY6ApbzI0pr+v0GIwWb7cDThyPTPDM9Xei0om8su/2OJA1ZZs6zx+WIB/Y3LyFJMp6UMgpJmgJLDPiyoPuFZtiyv73FBcl8vTI+vWcRuRIhJkl/J+luOlohud3s+JMvf8mXz2+5O+z51Z/+CcoOIDXX64XHh5/48PYNT49HlnkmhMR/99/+t3z/3Y/8q/8icrh7zrDZsdndIJCVuuYd8+JZXGT2qXL3pSZLTRIaF2EKgbEEwjIh08K+Fdwf7miM5c9e3/Kb3/6G33/1FQlFLIn3H95zGReMybx/OqKvIwLJPJ64jhPn68jlckFpzduffkArjdvOJB9Qqv78/tW/+mu+//5rvv3uq9oVKBADBFUNw0kpSqm7t3/5/Mc/qRR8ShQfkPNSD3VaYUgoJCUHtCq0RuK1Wn0WpYrYvON6Oa8mXIHVipgy3ie0tgzDlu1my8PjI+M0cTpd6uZECrrGMnTVcpycr5dWoOsMUukKi/ALyjtaUVCNxTRNPezlRAqO6CJTWXgvnxhnj3ehRpQUq5Avfoo4BV9N9UqUOtnXEtN2ZKHqRH6lNua0YFcZqtYC0xisNTS7DcEHpovilAPBQ04Jcu1pZLG2MoT4dBmjFLQxGL1CRtbNpyQT3MLlVHtfflk+TZqNUtzsD7x+9YqXL17x6tWrOkVuNNdzRJTCfHUc9QWtFMsYmEbP5bqgeCQEhyiRFD0AjZS8uDnQKMO7xwt+uvLgI4pqEVfagK6bhVTyOvUHYqzJCjLj8UhJETdPpFQQUhNS4cOHR06XhVAE12nmfL3Sdh1KKYwS5DXNkPzM8eEd8+VY5a2iEopO48y8OM7nC2G8IGOg1R/fTYK+H7CmbqUu00LOE6mc6Ld7mq5n2D/jMjvmxdW+g2zodUecJnJOnCeHURV08+LlC/rNwGa35cXzW2LwPD1KsrqSZEGpQmPq+UftGhqraVpDToHROd4fz1ycIwpo+2obl1pxPB0hR5JfiMuCsS33w46X9y/pdzumeSbMnpmJabySYiSnQt9UBxPGUFYH5dM44mLER4tJnuQm3OJrV7QorlePmxLJQ9NqtKy/wjyzlMxkJYMOqKQ5OVhM3RpWL1ZkGAwfHhLTsrBcrzTrBXi3P5BUIiY4LzMxA3KhP9zgYmFeBCmDlAo/TTXaJyRtd8D2W7a7LT5ZmK6cH98TU924TFmyhMAQIl3T8OzuDg28fHbPfrvjs88+Y9juMNYynk88vP2Rh6d3nB7fMc0Lswv8+n/473h8+5bz6czt/XO2uwPbzS0KA1ni3Mh8DRzfHytivgiEthVaIzIuCVysssK4jOi88LyX3N3dYq3lT59v+Orrb/ju2x+4zh7nIg/v3rNMjrnxvN0daa4jUgiulxOX65nr9VJ1CLPm+PDI28073ByRxaBkw/5wx69+9We8/fEH3vz0AyFlCnU1Fouorjpb3evyDyOK/+Tnj79ofMw9xsg4LTUPawwxVJuytAZdKllArWjdEisJIvnMlAItCmMlWip8rLnZzaZl6Hqe3d8xLjOlZK6XK7IUlBAYXTnLXWOrpI2MCJKhqYp0FxJGgBU1ktE0mrbrVlJDXVOlWPA58RAupLqBJrNuKoQkp9qor7iu2nuQQmCkxGpF0/fkoglJgavEpxiWlRClECVgTEtvFDfblugVFyJxHqFIErJir+ETXaMgENLUbCNpNVcrjFakEMm5ys6WeeZ8Pq3434g1lUhghOb2sOf5/R0vnt8z9D2SuomRSpJS5ny5svhaqnIu4H3E+8jp7HAx4FOiWxy2bdnsBrZ9Rwk7TqdppSJU4peShqAXiq351ygFPhdQio2qWWJRIvNYGdvjeEH3A0VpYsw8Pj4Sy5HZJ5Z5YZ5myDB0LYOVaFIVB8aZ0dd+Qn3JFpwDFzIhJXxwEDxGgFQKYwrGCBqrVg9LJoRETJkxRnZ2S98a+s0NUjpKXurLWja0dgPLWCdkMSCKRArFZrulG3qGoafvWhbKSr5SdV0eM7aVdK2h7eqGQWvJ9XrCe8/pfCYUjdSW7fawkpNg8TO6BGQMxJwxUjIMG+7u79kc7oj5A+d2QOmGVBxZVjvqZugQUiGsocREDpF4vBAo+JLwuboffKxF1JQL3td4iJSCzdAjTF3HjucZXzyzTSxRoKzA2IZc8jo9FeSSUXp1R5TCEqoFFSVr8XLNT8Qi8Il6URMapCYmQOiaV/UF5yJzhNYl1GAw/YGmc3hXiSApODKFEizoDcrukAWGtse+eMUvvviMl8/v+eu/+kuyMPgE33/3NZend8zjRPKe6Bxudvz4zddM14mb+5fkUukku822Tq60ZjweuVxHrtPM7GM1d+dSU5tF4GL9ni0hkINH5chGw4t9x2G7w372jE5FGpl493Tl8Xzm6cNT3b6u9Dbn60b18fE981IPDzEG3Dzz9PCBoRvIIaGlZn/Y0/ctn3/xOdNy5c27n+qUs3q/SEIRJSTdIoT9/+VR/c/uk6nvGVJi8R6TFTZr8lryzqLGlLQSGCUqMYxaaI4UlnnBiEpZM/oPwyRpJF3b8ezuHu8rgONynpCiUgWtqcKwrrWEkogUREoMbR1AzT6iSq7wECmwjaXt+xqbiYElBKKPLCnzlCr+PCTWg34tJsYYa3Sr5BX3Tn0vrrGtrmvIQuOLQsjqL3Bhqd4BavTXCEVnJLttR3BVirpMVQYZqTHekj9GqepFQwiJoKAKmKZZyU0CWVaZas54t3C9VBRrioF2pQBqLTnsd9zf3nJ/f892u/lHWyJIKTFPC0rI6lYKtdfhY+J8vtSLoUiInNBaUVKhbxrKAMfjFecc87QgSu3kKFOpgELKKoBl9TusXRRKZplGoveM1yuiqZE2FyLL05nMhcXXw+s0z9ze3dC2DUPXoNfYEimwTJ5lrFHpkDLOJ87jQoy59oLcjFovOlqtF0Fb/RJFCFyo7+DFJ0SzQbWKXb9jLhM51cKxRNA21S6evcO5GSENWiq2u4HNZmC729B1PYtQZDkSqREeSFitaK1m6C1NY7Ct4Xg+4r3n6XIlZYk0ht1hv7pMJEvwlOjJfiGnhBaSbTdwONwyHA7wdGRqJ4y5QpaIUh0o7dAgjEY2hiV6XPBclxGVMjplvAsUH4mx+k1SFsQ5kpNAC0PXDQjdUpRluV5Ysmc0mW2bUdlQZMDLUoeZN3tKqh2eIlhllYEkZY2GS0smUTREwRqpzSRRz18+FaQ0SJ0/fd/qUC6hO43pDpg5s7jEsiwsi6/xV2EIQhKocsnNZkOjNX/y5Zfc397ys5/9DNW0FATfffc1Tw+CZbkS/UhyM2FaePf917h5QtsWhaTRDXZ7QAoDwjJPRy7niePTmWV2VTmw/nWHIvG5Ol689xS/oLJnZzOvDx373Y6fPzuwbzUbo/jquzc8PJ55mkZiFERVmH0dXJaceHp6YLyeGa8XsijE4BgvF54+PFGiYDvs6botXdvz6tVr/Dzz+OED0xLq80Ho9aJRNyxCrBvTf+LzR7+9hn1tzrsIo/PgPIiCeqwlbqMFeZ0AlBiq60KIlQ5VV7NGKoamYzhsuFweuYxPiBxx44X3P36PSIFWS1oNGomWms60KOoPXZivSCG43bV89volfddRhOLb73+spaqYaW1L1w64GGr34LowjRdSKnioGSUlCBQaZei1ZdAaaQ1qW9nVlMK4jGhdV+C393fc3L3g2YsveTpdOZ+PfPfN7whhpuSAkoldr9lvYdMnclORqjJMjLNkdLbGYEKq0jylKEqhbc+mbbnbb9l2BnLk9Pgej6svLSqJZnwq3N9Imrbh8599zuYyI4Thy1/8nG7bg5/58Xc/UOICaSampZrQmw39/pamG7h9dkv2LzDS8bvf/y1mGvEhos8XUspcL5eKcVWawVYrpstijauFatKlRzcDd3evqp1TFNR8xWqJ7RVpPONSZMoZYl37fv/dm5VSoMhCEEIkeE/KkckqxrPk9lDLS4MtGFMLluN04TxfuD4emaYqlxJCoEJFvDbtRyY7lYYhJAiNbrYYodggePbyZwz7G4JoaPqGrDecn460jeV+f0C4K3kZmT4ISpgJyXM8vWeaDddLwzweSalwnRzvzzPTtNSX1zKSRWDYHDhs99wfDrx7NBQk+f0T/eaGw91z/tf/m/8dm2HACMm//W/+74znB+brE8ZK7GaH2O5oDs/o715woEc2A4dnLzm+e4NtFLv9wGdffk4/bGi7gTc/veHp8ZFvfvsVCoGRikzgej6TebN+vzy9EXz2+jWHZ/f8yV/+DZfJ8eHxwk//z/8HT8vI9F5y+PJnbLbbim+OFVX70+M/EGUm6sLN7o797jmfvZa8ff+m4hW7LV3TMBjFz7c36Kaj2x74i7/+G/puIPvEb//2v+XDj99wSRPXYpmkpog9Y9pymjuueYsXHqd6xvOZZR5ZTpGfnkb0dz+iurrBfP7ZZ9zePceYlq9+/x0JVVfcybGxhs/ubvhy86tqcY6JySVcEnz9t/+Whx++Z9je0G32pFQzw1999x2n84l3D+9ZxidE8Ujh0TkhYmZMukqycqIvsC2Jmzwhnr5jGQ1LgTsV+JtfvOan/cwPb97jzyN/+Sd/wu5wx+vPv2A6H7leTvw2X9mnjpIz540l+MDDD98Qp4nd/gZEohDo+4Gua7i7veGzz17xD//wNUvIFN2RpakXOLGhoPmXjcZ/+mPabt0Wr9u8OVOSR3xYI6/GVhyqVMicqzdW6RpFylSKEwqpLI21gIPiCbNjkSNjc6TEhCz1kF97dWI1klcceCqp9pAazc3ze7quo6TEu7fveTqeWEJGtx2261mc+yT/m9ctxVO8rFl/iWoahJZIFEPT1Om61iuetxY1tFZobdjuNmz2NxzunyOEZh5nvvv6G6brmeh9BWNoyWAV+9YSlITkcZNFy8K8+CqYLaz0x3pwM21Lbw2Hvq3RpBQ5fnhH8JGSqlhsCZHzuPDi1WuavueXv3rB7u5MLoJXn/2M3W6LJvDjN/+AcwvOzZ86l13f4RaLMYb9dsP97Y7k7/jx298xX46c3r/lcb9DKkXwAZQBUY3gqYQqUCyxSv1SpFUdVtmKv24ajNLIZJC54rGX6criAk+zI7s67DldrsRUViMyxLXIXgS01jBaw2aw9F3DYVM7HpTE+XQizAv+OuGvCzEVMpKmZKwu9btG1b7O87xa6+v73nSajW7Z3dzTDdWX06ue3DjmaUZSsBLuNh3EwHQ6Mo8j07IQc+Y8zpjHE/37R2LKXKeF07TgFk/yHqUEdr2Adn1L17UIrQhCkt9+4NmL59zdv+B/+b/6LzFaU0rmt3//7zgdHzg9fsAMEjvssIc9+1cv2d/dQ9uhmoZ+u+fVy1doKekay7NXL2k3A81uy9sP73h8euIf/v53GKlptSFezyyXI+cYmWZPCIlhs+Xz16/Z3tzx81/9K47XK+8eH/l//b+/YVkmTh/ApteU/cBh07DEShw7PT4QU7Ww7w8v2B0k/kXgcjxByUQ9YK2iVZI/393Q9gO7/S2ff/EnaNOwuMD333zF44d3PL6/EHMmF0HxLZNv8bHnIiIXEXkMluPpyDyNxKeR/uHE5vABa+t36/72lr5tESXz/s0bsqhRzRAuDC188WLPF/tfEBbHeL0Si6bImesPv+W75cLDD99QVM+4eI7jxOPDO8brkacPPzKe3iOy56W/BapKYQqRmDKxCGQJqDARLw8cfwi4hxajLF1e+PLZnt42vDucaKzl7v4Vw3bP/bMXzNOVeRqxujANlnHTcB2vZFG4Hh/JqXA5nZBFcP/seUUCbwfOhz2HmxuOsyf6xFI0QdZdMdLUc+wfIZP9oy8ah7u7OtVFcn26ErzHLWPliSOQQtF1Lbq1dY1IxOe8xpjqGjaEyLw4uqZHNw2d3IGvTfsQUxVoKYXSGkp96MYU6m2/CLRUNVIFRO/xq3lRUEtzJUZcyKS41NVOVvT9tpqvc6YsM2ElXMUMpmSKiBz2B9q2od/0jHNlmDeDXgtyEiHXLoVWvHz5OYfDLaJE3r35juv1CMGTF4WXgjnnylyOUEpCUPPVRWiQiiwr5UoohZAGITVSSIa2qwKh5YpRmRjqyjOXgg+e2XuyVAib0UqjjaXvG0RJxGVini6I7FDFE/yMULoSn05PLOOVPPUsy4jUpaIBS+I6XetUgSpRStGTY6i54CwggfOhlvRjphW1NF+WmaIkRdbpVCgJSmQaHfO8cJ4qnSvkQhYfUZGKECNKFtCKnAM+ZvAScbkw+wVBojFr8T/MqBIZrKARHyVcsXpMSsGuXEkhanm56zfsdrd0/QFE9UQo01BSRqrEpmvYbg0uzsQQOR/fM6iMItL1DeN5wkVPXDzKafS8cJlmUoLFJS5TIISCVbIeeAuQ1vjA9cyyLMSUPk3QkZLZu7U0X627c0iVtCEtQRhcElzmhXQ68fvvvuXy4QPT6cjWahrbctjuGGxLozQyFzrbkIYtr1+9RkuFkYqYHPNuz67fYEWskQM3cTjcsN9sETmgSbQWOisJc2Y8jTwej4icKaUKq1IpuMUxp8CcI81dy2bYc/v8Ht1Vz8T98xeV3y4Ktm+QyqBtX70as2NZAmOUONERzVA3Q/2Omy9/ie53yHa7Wpk9YxYcl/qdWRBYLK1u2LQaKNVbQCInz+QTQhkKgvnyiJuuyJRoVSXjxOywJQGCpgji9MQ5eN68f7vGyBbePT2yeIeLywp40CyxoJNAJoXQGiM1Kts6G1xmju9+YnyfqisgF3yS+KIoeoPICYmg73uGzUDbGLyWKCPZDpuVlFeLq8F7/OLIObK4GR9CRQWGACkxdB0vn7/kux/eEoqveOuV/lPWTZuQ/3LR+E99bu+frVM1gZsmgl9YxlWQh8QojTEWpQ051u87JVVsrKgo2irAKzUu1Wta23E+nSAn/DyhRRXOdaZKUKXI9R2kQItMdSdJpNFVqpYz1hjU+isFV7eRzMRc3Rpt1yNyhaDMUz1IplJIwa/Idcm272iahq7tmKeJECoGFrH2L2Sdmm83A9vNHrcsxHnkQWSm8UoIrkZ5J7goSS6ZEj1WC7JR+CAReQWwKAOoGomWBqFspfBsNxUNGh1+MSTvkSVRqAmH8+VKmzJIg9EapS37TYsSkbhccdO50tv8UrftWlGILLOoiOASat+sMWgp18tfIqW8RsY8mUpPlE1fPUlaMi+OlOuGQdu6cRG0lfQoqksgpQghMo4z8zLX562s21qfM1AnslKAkPlTXM2x0raKJ4aFB11JW0ZCSQFVEo2Cvqlb+5AglkIu1c0CNfrWWEvf9+z3B7a7G1AGF6AoA1ITQsYYy75pSd6vcTqPag1SQWs1y7h6P3z89Geux6kqBkJidqH+XqWKCLdaEEMgBkXQspblU0ap+v/nXMCHVCPcOXMaZ86TY1zjQR6YUuR0vRKE5Nvvv+fy9MR8vrBvLHYY2Gw3DEOPaRsEYLVm6Do+e/0KLRRGathvicsBd7NDxKX+fora1+2aBikKRgu6VmM0OCJuXhjPJ4yIdHKz0hdT7Sr62l+4Nbe0/Ybbu1s2wwEhBM/uDhVQIgouzChtaBoLQEyJcQlc5sDF1W3SZt/Tdhv2z7+kGQ50+3scEuUDQRimkLg6R0yCpC1ZafZ7SWdt3QRJUXHKK6wl5sx1+oAfL5AjfaMpsmBLy+xypbJOJ44pc3o6MgbJeQ48TQvTdCElDylRhAKhGSf3aVOgjUVrixCC1hhETlyfHgmnJyR1A+6TwGeJkw3BLRU5LSucxljNPK0Rfaswastu23IdOxYfa9Q7OMIy491MdDPZaBqj2G567u5ueft0xhdPWhJZ1bP5R2pE+acXGn/8ReP2/iVKVxv29/kHLqcz4/WEERIpJEYIdl3HsB/IfmEumRJr9Emsf1HOR3KZ2W53qKalH1qmp1PNVmaQuuYttW2qAKlQdfdJUKhralkKKhfcNJNCQGtNThkh9acfvBQCUrcYrdhs9wgjiTmSnzIXVw3EOa4UEZm43fbsdjtu7u754cOPTMtE0zX4kFd5YCKXSMqJV89fU0pGycg8PtWpdwiEsbCEQFrcOr1X5FxL4BWLqClSUaRCSP2JelN/bzJ909JoQXAdqVOk5Dkdz6RV3DS59QCiLUpVwU9jFc4FwuxZlhFVAlZGwjIjlEE3gevlQsqJq7EY6av3oTEsznGerpWOYjRtb3HXkRQiulhElrUIuzhSrFGCzmikEuTxDFpTVCWGpRzwMXA+z0zzwnlaWIojS4ExVXinlaRkj0RipKoxuFTI0bCczlgtsAKCllhFRaflxK7VyF4TQ+ZynnClcsSNFpU0JkS1MN/e8/kXv2R/+wIhNdO88PDuPeM4oRrYtj3DfmAajzw9jbx7/xZ7GNBGMwwt4wgueqZxrE4TqYg5rSIsSUw1BKWUrLQMIapcaF44xYXJpbWXUi8ZsSSeTo9cpIKUOF8rZCAUiUWhimaKmeP5ynVJ/N1vf835/Xvc6cx/9hd/jjWG3WZLIyUyJYKf0EUwND3tZ59hVX2YL26s378XLzAiE/3C4/s3HA5bhr4jTBdKKlgZ2bQNy1XxdF14OJ7IOaFUWWMNEJeZeV44TTNbu6XvNtze37F/9hypNLvDfnV9OLZ9Q1mjR9P1ii+S0xy4BIGTHbnZsb9/zv7ZS1788s/AtriiCbEets9J8LgkrqNjSZGNbsn9hi6nevnJkRwdkVgjjU0LCI5P78nTBbxHm1J/LpcrMheMUAxGM7sL4zjy9fsj12nmOs24HBBK0PQNrVZoFCElcpLIJJFW0wpRRY8CwjLz8OZ7wngmuaVKjERL0R13X/wppIiUkrbv6IYOrSVCFYQs7DZbjFYYo9FKEbwnBsf7hxMxr9OpWEuBxMim7VEvXtNvfodLI3nh04SeJBBaoP6IqdE/18/zly9rMVoqHt+9Y7peKvBDglKK1jY0bYs2huAWck4ESjV+ixqTTatp2xhbLwhS4ecZWTJ+nmi6FmUNc2MJHz1GzuHJqJKqDVlrjG2JqVq2jTUIrZBaE/NMTK72c7Su5dfNptLrYnVwFF99EsGHujFpTCXf9QO77ZaxaeozJEQSFV+dqMLBrmt58eyuHjDHK8XNiBw4+bm6Q4Ine1+JVlpilaRYxeIES1wNyNJQUBSh1sGYRiqzxkUEKgfm0eKXmZICzjkWt3A6n6uXR2jabqBrDJvOsMyOZVnw07m+x6MHIYhKVmJUrH+fIlUkdmMVRstVnvqRnCJWxHCgIGi0recNpbjGgE+1A2nbGtliRcOmLCg+kkIghUp/m5eF87yQV5kuiFrqFWqlR1aaToypEp/Itfi8gIiObWfpGoORAkWhNQqJJKRcu1+pkMgVMCMqAnnoe+7u7vj8iy94/vILitQ8HEeezhUSsPjI0Ha0w8Dl8QM5BcJ0QZgNRtXn0olKcxpn/6l7W4mZNStfoWICkesw1ztBirH2WZVYMcAJpQzOBa7XifN5rJ2wnHn/dK5CyyUgTYMpMPrAh+MTapr49T/8lul4wk8Tf/rZazZ9yzB0ldYmBYtbEDnTaM0Xn71GIhFFYlJE5oCKn5HmC9EvXK5XhG5QRtWBKIm2kbS2WrGdXxivZ7SonispBJTC9TIxTp7r7Gm2M7bdcnP7HK3r5Xa/6RB4KKFGl1KqMuVlJhbF02XhOC5cl4Tqdtw8f8nd/Qu291+gmh7swJzgOi8EUd/N18UTVSEpTZaKoe8oua3PjFIQORGix8WEi57Hp/cId0UGR9NV0JBNFplddZfMC+fLlSkI3p08xznwMDkKmcYabg9DVSZkwTj7OriQAmu7Kvu0q6AxZ84PD4TxSlgWxuuMtD2yHehuX+GmCTfPfBzYVe9dIsWAMYpu29K3lmkeuVxH3n94YvaJkhw5OJKfyUHX7st24NmzO4af3jPFQp4j5R/dLD56PP+pzx990bi5eY3ULdK0HJ8CIcDDwwdCrgY9WwSjm4jXhNCSpq9UBiEMQiikqv9XWmvs/obb+xt2hy3f/PrXSDJDY9gddjgfSCkxjjMxRmxr6TYD2/3AZy/qbTmHxIf371iWhWmJPE2RpzlzdIIUJCUJeqlBNgzNwKav1utwPRPmQHARpST7tuHltsdmT5xPfHgIuMVTskJg6TuFkILreGU8HfkhfI2UW5TSLBfHphkoh1vOccL7ugb7/7b3Hr+WZXl63dru2OufiYgXaSIrq6uLqm42rSBLTTTS3yuA0kAjAQJoWySbza7urrRhn7v2uG052LeSHIioplCzvh8QQAIZyEjEu/ecbX7fWvJ8elZWFZv5IqPr4gHbJaLP5lKhTearx4AKnsJG0vAIhWRZBoJPhKColkv2pyPPh4GHT09Ipahmz2zWN8Tg+e6v//KMVIRgBKXRSNNgDx32dOLx4ZnD8RkfHIvlnPmypW5KEPz0JYzzJVII5qWh9AVJK5qmzezzwfGxD4w+bwrqckKJyKwIGBpELNidpnxCMjm63uF8YowGf26HefKCUZNwQ59Py4RClCVlXbO4uaWuNIUSNFKh3IgIE5wtuc4l+qHLM7whIkWiKBVX6w3aVBRlxZs/+Jrb21d89vkbTDVnnDwfPnxEjoEiwsPjR/b375j8yPPjJ7QUvKoqvlgsadsZyrS40WIt9KFEFhlFWOgKbVqa+orr5RKVAg/vv6USA40J/OFXd9RVRVEUfHg+8PF5x8NpZHfacxo6FotFtg7HyLbf5QVCjBSiYLQDgU9IXSK15vtf/zuScxgh8O6AknPWc8O6LYkRnrcHpsOJwVpMVfG87xhOJ2zX51Gj6zWzqiZWBuEOpDDR7QZcyB0EGwWvbl+zWNywvu2ZL2eUWuHDiMQhk0P7gTJaGuk57R7QSvO83bK+vqOuWqL1PL79lu3HH0j9FutGhmlCzm+pFjdcf/Erbl7dEV+8xh5PrDYblus1PjqETbSq4MWsIjUV05TY94F9F1C1wp/2HKeecHxirAvCvMY+zKlMSV3P8kijAHvakdxESg5PzAMKQmKDRwhYzefEMdI7z2gdU4wEJanLGXVVcb1e4U4dzloGe+7mKMVivqAuDU2tKWTeMOqqZb3Ip7n7/ZFkGkQxZ35zR5x7Xpcb2usbysWCarVAdAfoOkppmDU181lN29YZmasMNkiENJSLa0olUUTsofvJojwrZ0wm5gK5KiEJQtcjTYU0F+rUfykv7l6jlEYpTXfsOB17Docx334rSQwJpbJR+MX1FT56bMi26eAjdpwg5kVmaQo2qzWL+YxKgEyBUuebq8l6RIh0XYcLjvm8YrWcs14vWM4zjntynqftM/v9kfvnLf1gGSfHEAU2JFwMtDobstvFAk0iOMcwjdiUIAa0ltRVwWLWIkK+UdlOmSIXYh4VK4oCoTTb7shudyR+8z3TqUcLkW9glKAqCrYxW5h9jEzjlEvdpaKuaqQxTNrl70GMCCRSaJLUpCQJIeEnS7/fE408D/AlFAmhFSSDEIlxmuhPmUK0Wm3w44nv7IFptHgfWCwXNKVhPpvxuN1y6idO3cA4DMQY+FiVzGYVTWXy7XnMc/TWBapSs9ls8N7jY8TlyyAg422tdYwuUFQVQirsaPEpiwmnU0/wgeADx9PI6By9TyQFCIESEKJHREew/6l0b1RB29ZcX2+oKpP7FumM8YyBYcq34t7lW/l4Hr2SQqMKyfr6itmsZtY2vH79iqura17dvaaeLZlcRKhHXHjG+cR2+0jfHYHIw/vvIVhK6SmXhrZsKGYLvA9IbQj7AWUKTFkxkdBF/gwtZw2KxLh9QPuRgsDXX95R1RVFVfDu4Qlpjjz1nsNhYL898Rd//ldIlYWBT48HEg6lDNYn+jFbu/XjA0JK3v34PePxSJwsP7u9otSSm+WculT44Dnun2AcUSFSFDXHY8/p0JGspS0118uWui5IpQAcNoKPIx/ff48wGozm889fc3t7zTRNVEaj5Rk5EM/9q9+ijULgw/fvsL3nZnPH3es8pjh0W7aP7zls7+m7Z/q+53jqaOc3tIsrbr74BS9evOD29hYps/19Nl8hqzlRFgSZD1ETiW4YOPU9x74nKk2IkeAtyk/0ZUl//57jek1VlPlwoa6zFytEok8EG9lPPXGa6PZ7fIigNOvVhrkssUlxsp/wQhK1YfIeYzRleb4hSgE/dD/dijdtgznj+8fRooFQ12xWNxRKcToOeGGIquDq8zesXWR++xkvXn9BM5szXywR5O7Q/tlRGIk2mqvmiuvra968+QqpCpQumLUL4llkPQ5HYpgojaQqNZVRVFJgk8OH7J0q2ppalb/zGf03x9uqClU2lPWM5WpDcJbnqqKWEiOzwVGXeQb15tWamBLOevp+xNt8Kpni+csaPCIEVAhUSiCToFL5RDsJqLUmGEOQkkXb0NYFRkv6yeYymfXsu55xHAkpcRonBusZXCIGAUGiYkTFgIuByUaI7icWeKklZdNyNW+5XS/QKiGMQZQtrZkRkshldjIubZgc2J7RCcr7txit8d0BRaCpDGNRnk88Q3ZikAtoUiS0EFRGomX8yYdEyjx1LTPZqjIKmbJJOfhc6Isx33IouaCsSg7HnkRCGYkWERE8cerxIRKAolpQFAVlXaHLEusdwykvBJ23Z99Jyidmoye6hAgKNwWc8AQtUUkgUOACRmSbe1WUeDw2eVwA62OW9IwTIVp2uw7rIy6kXH4N+d//1vkkzi/PcL6el+J8ilQYmqpkMWuZLxpKY6hTwh33uD6ei7QJ7xMnGwlRgDRIkYVCssgm1bqqUedTx+3DI7Ic8mlWgqqq8E3Dh2lk6E90Y4/wjrou2LQlq6airWtMM+N0fQVSM4ltJlqVBlPPaeoFm9UdrzbrPIKkRuKwRcWBWVNTlSXGFFTlRNs0rNdrkunwKTH2A1ophMjM/rIskFKjQnaJ4D2n/Y5IxPYnVEqgNMJ7knO4caCLuWDc7fa5JxMjIgqC67Hjiegd2SXZM8UJkkcmn2EL3nHqHYOLjB68LEFqFstrmlmDkgl38MjMuETKIn8mRSK5SJgcbpzylW4IDP3AYXtg+7SliAemaaAbOtIUqV1kdnXHYvOSomwJZUXTzjBFRd8PICxCWvrjju64zydodsIFj4yKFCDJSPIaN1m61FOnQCoq/DhR1U3mzCtNJJJkJEpBxBMwBJEt9vP1FaWuWUXJp0nQxkiUiqosc6nTu7Mg7IzvVNnzU1cFWgsCgd46pEycLBRVSaklqYyocoluVixffE6NoXmVWN7eUtUV88agk+DYzOm2T6RoidExDnnRMwqVMdoaYndkTAFCyFK5aWIYB+zUZ9KOiIjkc58gRualpm1+98P8b22EyPK9smY+X+AnR78+Is6+AK3zoruta1bLOZH8/ei7gWm0HH0WpCohzrd0+Qb3t24jJeVP0lgpJcoYUJKibFCmAmGYbMD7QD+MnI49g50YgmeyecE8ufiTp8G4iFZ5HMSTXTtJSITKN/pVWTKbzVguFlRFgVKawhRUVUNEIJTBIXApF8j9MOHCFhkjhVbI4DMtSqtcto55tCvEM7jDJ5qU5bil0RQqYGWmd8XzVZr+beFcCmQKmYLoHSLkwb6qLKkKQ4gV/TDkE9OY0DIhUzjbt7NzIXtNJKYsctdE5sNE67IXQfg88hm9IZw7E84n+sERk6QoM+VJShAxZeS8lBhd4AIIDzEk/HksKPkMUhmOp3wQFyL9aLHBMwUPaISEeD5wkzEiUjh3KbJ/oaoK6rpivphTFAZFYuo77NDR247gI+eprHzxkgRJKJTSmKI8G5MLSIlpGtlttwxTICSJFIK6LJlqh3d5GmGaBqIbqYxkPW/ZrBbMZy1lNcNFDaai81tQeapkVlXUs5armxuulgs0gUOpCN0O5UZmTUNZZSt92zT0LrGYDwgKQhDZ5+Byx6XQeZNeVhJB7kA6azkd9sQU6Y8Hwjid/54ieJ9vtc7vmHG/y9CCMyY5Dj22O4H3OAq8ywCCFB0+WkLM7/X9vsMlcICP2TS9XM3QSkNM2KHP756YEMKgVaIswHpPmCx2GEjhvPk7nThsn3l+uCe4E8M4MJw6ghOEAPPrE4vVJhPFtEHpPPLV9x1RTARZ5L7g0DMMXf5sBp8JcWdZYrADLjr6MHGS4IsSIRVtWmLqGil1HolTJSJFkhREMZJUxJQVV7cvUfUMLwzv9xNlkKylwcVcXCdFpu6Id4EQElVhKExBUdR5kiJJJpe/Y6NN+MpgZIEqNVIViLLh+sVr1tKw9oHl1S1lnY3pUina2YzCKGKYSN7S9d1PEtKiqDEmIIXKPVrncq9jnOiHkWnsiW5Cnd9LOoFMkZlpWbTF73xE/403GqPQFGVDu9rwOiXq0tBtP7FoarRUDOPEbLVkcbXhv/sf/kdS8nTHHT9881dsn594/+M7krMIJ4inPVYE+uFE7Se0hCok0vEIPtAohaxKEvD57RqhMhT219//wDhNuGFkHMbzyBR0PjD6SOcgxYJEQfIj0XmKIdF3EySHSBZTCuZFyYurW+6uNnz54oqn/YGgC8zVK0zREhHcPz1w6p7puh2Ph4GUeoQ8sj8dMFJQEbhZzVk2hrGd4RE4MolEn50bwU8IIZkXhr3JCF4vYpYC+kA9q2grw7ytMRJi9HS9xU0DxMj1yzWzly+YLZe8/fg+L8zcRHYheqpk6b0jxERTXTObtywWCyY/4VRi2m+xSmN9YNx19H0mg6iYL1xL0dAfLH7KyMQ2SVSUjPsB1S5YzWbcOI0eJtyxZ/IeISVVKOhOR/q+59PjDqE0UhuGcSSe3SCyMEgUQoJzFhU8rS4xRlOXmnYxY7ac82o9Y/PylqquKUPi0wfFk4887Lb54RXgZCVCKpqqwacRoyWxrDGzhqYpeL5/z/27t0xTgnJOPV9y99UfUM9mKC0z6eo0Mg6Wq82Cq2XDZ7cbbhZL2mbGbLVmNl/wqrPYv/iOKUWikizXV2xW13z5+g2v1iuMCLy+VTy9+45+90RTVXkjARitWcwXfP1Vy9Uw0I0jj49bCm0otGbetFRVxaydE7psIQ7Bs//0gWEcwI7IJFAqYbzHdx1P9w88ujxv2R8OlLMGXVWIEBD+CO5IbUpUmjhtP3HwA5Dxx9Y5Rmf59LRje5rYnybM/JrZ8ppXrz+jqVtS8NzvMolEJ0VhNCaMlLbHWxBjJHQ90Q44AY+fnnn4uOXp/sD1wjLZkX7o6I8T1TDl4tl6ydV8Q9mscEFgXeK432XBpJS8//E7Prx/x/PDJ4bhRAgTySW0MlTSUBhPCiO7546ZlMRpZOwnbl7csVhtaGYLYnAEPxF8h3Mw4QgKTDPj+quf8/rNH1AvrtjL/wthSmarDU1dsn165E//xT9j8AnrAkbFjKQuFPO5ZnQjz6c9YQw0ZYUsW1w5p1UVzhja2TXN+iWv/5t/xHx9y3z1gqauUCKCO3L68sRwOnH/8S3ffvtXfPObX/P2u7f0Q88wjczXG0xZok2Bt5k4ZLsT1lustzw9PeTSsDJ4ly3Alej5bFNzd7v6/7EC/9uRaRx/ohPevbpjPV+wmbW4cfyJgrdZrthcrfnlH36NIGJtx/t3H9nvD2BdRp4KlTe5hxNxspwOB4wS6JQt4ZMLhASqqFBSYto5QUgOnefjx4xaPuz3uVdIxJqMVXc+MfhsCo5IUrJYFwkuoEVCnLGyQheU0rBZLTJR8GqDRFAUBYvFEqVLohAc+omH3Z5uf2CwETsNODuxvX+gLrLzqCrL88FTTVKa5Hy+wSGRHMSYS9ltVTHaRIw+j/OJPJLTmJJZYZhXBbUElQL92JO8Q6XEZrnIkjOjGcZ8o98PA4Upc9m7UGgJIUJhNGVRUFQVTdsSEBy7ASEUMTmstZySw04CrSusS/Q2Mu17qtEjlcFoce5g5GdtoQrmszkoi2MkJMVoI4fTgB9Hgp3oD8ez4DCPArkYsSkjj6VSGdPrHTIGmvNmdNbWtIuWummo65L19Q1tO6MuSz5+eM/gEtv+iXjud4Rw7uudR8iFMuiiIqFwPnD/6ZGPH+7x4S+pZyua2YKXr9+wmLdorfkLO7J9vGe7feTuZs7Vas7P39zx1eefMZvNKZsl9WrP7OnI3n/H6Dw2Jm5fvebq5pov3nzJy6sVMjo+NYbj/XvcacesqTAmj+4tZguCLOiS5uYKfEhMg6cf8s3M9WJJ3Rhm84rDfpvHjsaB7XhichPd7plSaqqiRANu6Hn68D7Lib3LojkhcuG9dYRTT+wzTjWqwDRA57ss2/UjSeZxs0+f3vGwO/K463h594bN9S03L75A6xLvPPvDW6LN0rqmqKmrktI0nPYHlHf0ux32eEAGx/b+E/fv3/L06UfaWhBCQHrHsN8Rg2D/eM/ru9fcvHyJMRW7w5H9/sTHp30uNpuSp+0j26dP7HdPTGNPCJ6y0BiZKFREhZEUBc5CLwJWZURykpFWQlE3Z/BNQaU0zkxMvkCRaOYtP//Vn7C4ukEUJR+OlqKasbq6JUnF4Xjkm998w3fbLYfdEZ0iddnStgvqusZ5zzANebQvJbZ9whQCj0HohrJdUC/XfPmHf0K7WlMtcj1BCIlIibvDgb478eHt99x/+sD9h/d895ffcDqv42ZtS1lWzGdzIgkfIvvtE9Y57GR5fnhinDzKC0w4y/q04uXCcHsz/53P6L/xRqPbfkTYDuUHGiV4uZ7x4r/9B6xmc6RUPDztQGtEodl9+kRwI+NpRzrtKWzHSk2oWqKkZlZkjvgwWMbBYZQ+71grRFlw+/kdNuW52dF3PO8eeHq+537XEWJEicTVrKKpSxaLOYdh5DhMdB8eCTIgZcBZj0qaUQmsHzFa8dUXX7NcLKnrmu7wiDZwsh3JFCxW17z5O3/EzcvXFGXN49MT3/74PT+8+4GHg2Pse8JosacdRkFsNbuTQBtNFwTN+iWrV/O8E7YTYeipqpKyMLy4rZnfRI5T4P2+ZxgmxnGiLhNNLZnPS2aFIkXPZAfs0GGnEefzabIB1m1LL2DXdygJZaF5dTVje+w4dAMP79/yZDS6KPIJk4/UTYOzAZkU2lRURUFlDFILusmxPZ0pIA5sF3nRNrRVgZQRXTeYqmGzqRCdZaIDN5JkpHcJe3aDvHpxgzQaoRUfPz0wTpbRelSU+QXqBTKeiSYk6qrger1guZ4TU+L9D9+w3T3TzGZ88fpzgpLIpmZ585LFasOLF5+RRIH3meDxsLvH2hFTVzhvORw6Yn9iGj1Db4lFT9F3BKWYL5aQYFQ1sZIo3TJbLzG1YoqC+/0Rc5poTp4uCvoA7WqDDgkbAVkTkmAKI/fb9wg3sv/4HjF56qJGBMkwWQY74ZKmauZ89dkNsqqJKfH0+Mxxu2PsO9bLmjxmH3n+8Ii1E9YLXAwE7SlNtri2Js8A+2nk6eGB8bRHxEitNfZ4wg09p+0zPiREjJm8QkIIz9BvSQTKpqCZzynnFZ/2e4TIHaOmrFjPFtzdvOB2c30uhvp8a1hVLLQkTRO+7/j3//7PSU5idx3FXaRpBGORWM0K0qpFiohAIaNg6kamacu3/Ib5+hXSNCxlxbGbOHYD3dCjjKYuakY30o99RnDiUSYxW9Ss5i3LeUtFAC9JMdCW5myQV8xXK5ZXV5j5/LeAf0R0uGGkm+9xLmDKmqK6ph8Vp+nIn/27X7O6uuZnxYKv33zN3e0dL9fX/Om//pd8fP+W3fN7Xrx6zd1d5vz7mHgZI7dXr2jrhsWsxboJHxzSOmS9IMzWHGOBn2DoBsxkszk5TLjJERAUty/4om3YvPmS5s//Pe/eveUvf/0X/NV377B2yhS9MEB0VKrIM/0+dzdSSDg75o2Xkcxnhpcbw4uN+a9cfv/tyWH3THIOnaDUmnoxZ9NUlGeqzv6wQ5vsgcgOAIsdevw4EqfsLFLk3lUMucjtY8o4Si1IWuNNiawML9evs38FQT8MPG+f2T09cnh4hOApJFyvZ1RNSTlv2R97jt2IfT6dEbKAFESfGEZHaRRlWbC5uaKuakpTIqKj1JqYcs9nNlvy5s3XrK+uMWXFfrT89fc/oH54x+Ohz7x2leiGnmmcCNNI2zZoYyibmtnmClNWOOuxk6U/dVRNSWUUdWmYLxyD9TwcJ7rRMUyeRQHrWnG7bNjUiuQt435LmKZs/o6JsjBZ9llKxnGEaIFMm6yrEiZHmByf7h+QxmDKEo/AnpH4SuaifmU0xVngG1OGpiR5xntGzWmCKkJhBG1T55n1ouKFaKgHizp0GcMdI9ZGMm9EsVrOkVKCkHA4MDpPdDZjysP5tiqCjhlhW5ea9bJltmhBSo7HPQ5BVbfcXN8y+gSm5uWbr5nPF1xdX4OQeJ9Hvfe7HcE66nmNTJ6QPN5ODH3P4XBA6h3NbIFPiqJuMvEqONp5S9UUfH53xawy2JD4y2++QwiFqRYE3eApuH79GdN5hHi2XCKUYrvdEacenTx9d0KKlP/uU6Lre4ZpYhSaqm7447/7BpEkwUV2T1umYcS5ibIQaJ1VUQ8mMY4Tw+jpx4EUE40y1EVJW9WIJBj7iYf7Z+zQQQqUJt+MoQLH8YnJ5huwsq4hRQ7HPV3/TEqestY08xmlLri+WZC0JClNVZdUVZ39R7M1JEmp2jy2oxWLusBOA0N34ru/+nXGME8n0tShSrhaNsRxRSkGgusYhoFxCGyfn0n7gaPX1PMVkwtc3b5gHEect9kcTiLh6bsDx9OWU3ckpogxmrapWcwaFrOGkoiOER0Ci7aiKEoCivV6xWy9oVps8vdjGGlN1hGo5op+GtBVgdUNpyBw/cQ3b9+zXK4p2xm//NUfkxJcXV3R1iWP9/cMhwPL5ZLFfM71zQ1JgI+R1dUVTVWxburs9QoR5xO6bpHtnGM0BCewFkTMiGsZE9ZLgqzZvHhDNbtiffs5TpR8+viRH374joenJ6Zph3c/EFI8C6bzhI6EfKPhIzrlfopSiuWs4MVC82L5e7zRiNMJLxOTlrkIpAXNPL+MldQEn3AZVER/OuDGjum0JQwnsJkgVKhs85YqX5MJVZKkIYisN9dFi2lmVKvbrDqPkdP2nnF34qmPHPoJkSKlERgzy6M3bZ3LUTFi4MzqDhASUYDzWdKmCk093zBfrZnVFXbYgxS4BNIU6LKiruvMAi8LrtcbHrc7TDEniZIkA0mCDwMiZS60C5EkElEW1Itr1tcv6fqBqTvRi2dMKSmLXNRbm0RZRWyCvYiIMFHqSKkShcl22RihUOoniV8200ZiCJTGEIxGkQ2nRmYKRqEERsJwOGTbtDFnFnq+BRDnsmNVVFQmn64nLUguMsWEDOBFgiky1oJSqmyuNfps3FUURcKYAhfzgjXTlbJEZ9nOEEaBlHTdESnPp3YyFwzD+Tr1t2gCoxVtXbJsSkbn2B9Gds9PDMPAZnOFiwlRFMzMhs3NS1599gVR5BLkbrejjwHRnQgpMNiBwY0onwuSo7WkpPAI5PMTo/UkqZnQiMpQK027WlHIgKNnGhyCwGkSxLImmZLV6iqjfUOmW4WUOzpj6El2YDgcaCSZJuQi42Q59T2xnKFLgdYF2hQkYNHOUCFgtWQ9r/F+oh86tIgkCdJIbJB4nX0tlTRUZx68j4l+mBj7CUWibgzeepKNjM4jdKZbRcia+egZp5GIQxSwKCRVW7PerEAWSD1QNzVNVVAqSV1oBIL1cs1quWTRtsyVIHQdozDoJHHeY08nfH8iFQqNp6k0Yd4wDcP5JS5w3hP8RDoceXp+RjcLkmo4diPHbsRFT6Gyktk5x+QmfPAkkRBSoLWiLEvapka5gZQCUZ7RpFKgtKKoSoq6JkhFIn+m2qZBmxZBxTRZlC5AlvklOQ08PT2ThOKw36OEoG1nNJ9/zuP9J0SKjMMObQqQeS69bhs27YIvv/iapm4pTcHuuGOcxmyDLVtMNSfICpskyeZRDEEuBgYfSREKU1GtDMV8zqt+JOqSXTdw7C3Tbsd+v8PbPP86K+pMxUsx/zxjHgMRErRQtJWm1NmEfsn/d7ydsNowjT1F1SDPJKZZU58/QxAJIPIiytuBsTvlhZa1pJAQSqBkHn2R6tyhK0qEzMVbXTWYqqVevSBIjY/gnp/wh56jjexOI4aIrjOytS5LZnVFsJ5oA+b8HEwpIfODkZAiQefSdbNYMqtnlEWB7U6ZdEY+mNPaUBQlRVlRVDUzU1HVLaYsiSKXt4UyRCQheqzzGO8RSlE0DfPVktlihZ08fdcDClNwFqHpPDroI4Es3CN4SpkoVaI2UGlBJHulslj6t++nbGUvjSEFh1aCGCNCSLTKI0IpJfq+B6XQ1mGqKv8e0ll8KClMgdHZ1G6Dyl4PYh5hDoLJRpRQZw9KLv9qld9TpQejc1cinDE4Wquf3CFSZeDKGBxymogChiQJ/9nPIpHH4gqtaKqCWVPiYmI49hz2e4bR0jQzfExIU9AsGjZXV7x4dUdMAmsd5nDERcHQdwQSzscz5t8x2fwzSR6i6Hh6fqKoBiLgY6CqKopyznK1RsuEDxOnfZdH0cpAtdCYpmK53uBipmUpJYkpcTgdCWMu6seuowyBUkh8iIzTxOnUEauGokyZwhQFUQSaqqA2CpFqxBlhH+NEJQVohShENpJLRV0UVKagNAUkcD4yTg5nfzuOLggiL3r7aTqPLsvz/6NnOPtJEAHTNJgiu86urtdgCmRRIXVNVZqfPg9KGlitmddl7vdUmv54YBezN817jxs67HDEl4LSCNq6xM9butOEtZnSZ63DAWF/4PHxCV3mGz5rHZN1JFJGV4qEnQbGccjggfSfv5sMdV1Rpjzmx+h/knaqcx+3PHeEMpJco8sGVUBUVb7dMQonNMFl18/z4UhEsdrvM9inqniZXrLfPlMYzYOQaGMICXSZ//tFVfHi8y9o6oaZMQynHjtZrM3obFM3eFkwpeyeESn3WmTIo2oxClTZUCuDLhvuvjiiypYpkCW2Yct+uzu/n3OXw6gMXgjBnasPAgMYkWgLqFWkkO53PqP/xhuNMp6Qk8NjsaEkpMBh6NmZGqVLdLMgak2QgqftI+Npx7C/B3vAW8epn2jahkLWRDnjevOC9eaax08fmKzj6CNXr79mdf2Kmze/YEqKMUSePr7jUbS47UjcHSnxLERiVRgWxmCspbSW2jk2UjBNAWsDaEMKiePYUc83FPMVanbLoZ847p8ZukRTVVT1grqekVD8+N1v+A9/+q8QEX728z/k8e092087equhWNKsK+z+R3ScqIzEFDWqqClnLa9+/kd8/Ytfceh6Dk/33P/wG2q7RYWJaRxQAhZKsPzihscHyUMaaZWjFYo6WmqpiUJQmry490GhjMJGy6470M5rSgrquswbKQTHU4cPEakUdjghz2M6y6trbAgZ6TmdSN6z3NyihUCQ6MaI82ClIViBdBHvHTvdI1Lki82GspBoFXB9h3MBUmCKHpLHeMuL5Zx1W/JiPctCnJiYFYrTYNn1lqf9gW607O2ISDLfLotEqVUu4S8bbAwIkfirb9/x/PSMqBqaxZJmNufzl3csZkuqpmW76xnGidFaYpTEqLjfnvI843jkdpPnpH0hQZW5ZPf+A8+n7xhDot685PXdaz67u+PVqsD2e7YffuDY9Ux24uj3vPnZL3hx84ovvvo7BKmxAf7622/Zbh/5sz/7c5TPVK9KBVZVxdxo/JCLocfjgWqtiGPk/W7k4fke60YWdcnPPn/Nm9dX7B/esbu/5+2798yalqIsKWc12mSbqz1OVKqkLmqibJiSYvICbZbnB1pF1+2ZJks3jOhZg5mVlKYm+Qk/dOy6AYRDzCRFW3Dz6opf/t2/xzBETqeJX//1jzgHh+e3yHFPW7f84s0d88WMqixh33P/8MiH776nf37G+wmmPe8Lz2y9pF7N2KwKrjev+OH7LDpM5sQYE56IFJI/+/Vf8Osf3nH32UeSMCSpWd9usgHVW47DidN4YgwDEYmUJcGnLIGSJULbLGoMlj6MWVqXJLosMFXNN+8+cuw6hnHkH/69f8RstuZqfkfX9cQQmTzstvc8PG/p+yPj+56u2/HmbsOrVy+42qz4n/7JP+Zw+AX/5z8NfPv9D/zb//CXfPHmK375qz/ij3/1x3zx+R9QFg0xwcpZfPQEEkpX+Zeck4j4MGGTzwjjZBimgHeO0hikkChV8Ys/+sf84o/+Ef/z//q/8ed/9m/49pvf8H/80/+d548fGPdbbN+hjEQVEh0zCpsUwFuE0DRqxrh/5GE4/lctvv82RYtIChNjdyCNPSImonUsF4vci9KaSCKEwMf7T3THPaftU76BCpEQoCrzDe5ss6GZzajqht1+i/eWU3B8fveGxfULrj7/OneerIdPH+kwFL2F5x0yBeq2zM9wESlsx0IEdCHYy0gfEqMPWeAmMyY7IRGmZH79EuEj1nmO3URlFLrKFKsQEj/+8JZvv/8xb0rWGz7cP7I/nOhGS0qComopjcrYVRkwpUGXBaurK16+/pybl69wNnDYH/j04RP0W/Aj3va5v1Jq2tmKp2fBg7CUaqKIiTQJXMxko6v1HKUV/TTR9wO60JS14ez3BNJP/ogU/1PfcBhGhNYUQFmVaJFQ4iz31YKmKlAyIWXKMsX0n3otSkpSSihRURpDaSokgmQd48ky9BNj1+OcQwioas31cs6iKbla1PmWKkXqVnMaJg6nkY/7nn7Ki/8MQJZIEqVRLJuK6/UyF8f7gbf394QoKIuSup3TzmZsbm5p5wtU1dCdekYfGSIMEToXePj0iB1OhGlgNSspjGax3mScrQ988933jNbhY6KoKu5e3/Hy9SvmdYEdOw7Pj3SZdoqKET3X1GXLZ1/+DGEMUcB333zDYb/n+fmRNPXI4KjDyFVbsqwLBJHj6cTzfk+1VgS344fnHf3hRPKRq9mcV7c3bJZzHj4+sts98fj4CW1M7ro1WZ5aKo1fh/NGz2B9RqZiGkqT3SIpeo79CW8nTn2HLiuKqiGdHSj7rmecLNrkRfN8tWC9XvOzn3/NMAVOg+PHt894r5i6A1bX1GXDZj5jM2+Z1SXJ9hzGjocPb9k9fMA5T3Ha09YSN67ZXC2pK41YzbGuQ04ukz1VgUATheSbH37k7cMzVfMbTFFQliWvPvscXZSA4NAdOZ6OuBh/2gz7lFBFwWw+p8IznY4cdgO7w56qcszXFdKUCF3yw4/vCZMD56m+nFM3LevlNWYcCESGIDg+79nu9nx62vLwuOP+/pG7L97w6u4lV5s1f/L3/pj99jP+5T/753zzzXfc3z8QteHN11/zi1/8kruf/Zy6aiiEojtkkmXit9LKAlkWeAHj6DOumXxrN41TvmERgqqqqBcz/sF/f4d1E8fjnn/7//5rvv/+W/7Z//N/8+79D3S7nilECqWotCJFm3H4IWBM9qQ0hccNT+wfT7/7Gf03fZhPo8OrjHurmKFllo+PPkJwpNhnFb1SeO+xdqLre4wQoCqK5ZLm6nOq2ZpicUMyil2IvH16ZLIWnxLVcc9Ytbj9gS5KXARdzmlv7nj51RG3fUfhYG4SjYi0KnI1r3l9tQYUN+09n+6f+XD/TE/CCYEVElXWNPMVL15/SasVpYBoT9R1zXw+p9CKGCxDt8VtR6Zp5O33v+H+sWO7P3G0HmmyclLrFo2mMB4lPCpNtGbOcNrz9sfvc2ktBu5ubxCHgB8OdIf9+RZHIdVEXURmlabwI3E8sb3vOWpNVVd8/vkX3L66wcVss0UqhFL4FBmsZXc8oFLCKEkhFYcu2479MFLONGVZUNUlOkRmfYGcNwjvaQuNVnkXvljMqAcHh45Pz0es9cQpMGqFlTLPXtqRGCPTFJh6T390GTMqQS8M89Kwagp0HPO8+eSQdkCHQBEDOnhMjFTofDZ3Nrcn8ql2dzgwOcdxe8yWTiTeeYL1uMnx8PDE8/MOJd5xPI5no6rl2PWMw8Rxu8eNB6LrKVvDom3ZXM1ZzOaEEHh4euLQ97huxO+feS40SgSe3g346cR4fKIuWoRSaNXyuDtwHL/n/dMeITVJKEaXR9mEEihlyG2MCWEUwhSU2hCFwiOZXV0RpCHYmHnvaDaLFY1WCDvw4fvv2O/3TN2Ru5srZvMF9XyJOO5BD1y/UlS6pSlmXN28oqxKqqqijIHkJobdE0IX4B02JrQsqMo517cvcXZgt02YcCClCakrng8nbPqISxqtSpQsWLYFboqIkCjiRJoSx8f39KcSqTTiYHl4+44P794xdUcQeZRHCIcUDj8dCRPEFPHBoYuC5foW8WyxU8L1DnvaE8WRdx+faGcL2vmSotL4aeJ0PPK03XHoxmyE9WO+mXIhW7qlpJAVk5042Inx0yOFqVkvX3CaEmr0PG9PuehfzKjbOXU9o4j5djScDcqehIuOosgnvNN4YL9/pG0NbVuyWi1Yr6/4u3/yD5m84DR4Xr3+ilefveH21RcUzQypDESB1gaRAiLG3DkSEnDE6AmuJ5yRmJ094s5G9mBDFlrKvJCUMlMu1uuX8JXmn/wvPf/mX/0Lvv/mrzluP0KKiBAIKZeRJYGb1YLb1YK//8uvc7Gz/N3X039bM00DMXiic6imzaVuAuPU47wFnQ3SyEx+mnyidwkhzRkEUDNbrqialtlqQxKSLkbePu+Y7ESIHnV7ojct0+zAFHP3QM8WzK+uub47cvr0FuUGlEpoGal05KquKFZLktAU0vC4P/Gw6+iDJyZJVJqyqmnmS9Y3L2iLklJq7HHPrC5ZnxdZwTl2z8+8//TAME2U48TT8579bs84Zd6+1IpCKsS50Cy1AqkYJsvheEKVOyCXqG9f3BJPkjAcOD0dz1Z1xaydY2uJbWR2OljLYZsnGeqq5sVnb9jcSnwUnMYBU2hMURDCmGfIhyHPxktFoQxdN9L1U95864ynb+uClCLJG4TXxCDPh2tZ+rtYzNmfJmI88Ph8wDnHOARcIXBGYMc+E8J8YOoDdrDYvsdHj1YS09TUOtEWCRXz6bR1FnyHjp5aBirJ+QAjO46UEBRKooDkHVPfMVmHHQbwDpBnkpdCCnh+emS73yM+fGJ/6rA+4H3ksDsw9h3d845o+0yQKiRlXbPaXDFbrrDOE959pHt4ohsHbEo8bvcEoRDREZ3FDR2lNkhp8F7w/LRldxx5Pg4IrUhSMA4jztmMLzUGpQQ6JFRRIk2BMApdJ2oks6vrTDgaR7rDiRDDeYw3EIPj+fGB/W7LaX/gs8+/oJ0vmC2ved7v6fqBiKYsasqq5mpzQ9s0LOZzYnC5P3jc4c/fCSdGiqqlWa5ZXt8yjj1jtDjhSHi6YeLxccs4Wm6vI6ooaCrDal4zTRkgFKcj1lmiUIhhz2AU0fbcv3vL/fu3jN0p+7NkTXQDU6/ZKU9MjhA9pqyoGqidRD07Rptv1XZTnnBASpqmYTafUc5mmLICqdjv9/TDgDYFU/TEmPswNoJLCQVMPnIaJ6xLlKXH6xnt6BFTYLs9YKSkMQVN29LO5pR1i6pKXAxZhhsSk3VUdYufLONoeXp6pCg0hZasF3PauuTrr79iGLJzabnZcHVzy4vPsrzXaJNvFuoadJHBJiqPr6Nkxnc7d+4nJZIP+d0UsvvJhXyrUpRFvswxJXdfvqGatySZ+Dd/+s/57ls47h6JKeBCRBORMqEFXF8vWK8W/MHPv2Q2q/Ph9+/I33ijYZ1H+uyomExB0nm0JoREImDDhAgJoTUxeLz3jNMERYEyJUW9oly/oFreUi9umOyJ07Dn4bhnmkaikCz7jth3pO7E0Ut8UrxYrKmWV6xfvuZTVVIkS60zGacUkVVVcHV9TVW1qKCQ1nN82mJTxIuMvsx//ozN1QvWbUNbGmQcqeuaWTtHCcfU7bl/f+AoHdZ3PD44dntP13l6H1BCogMYVeV/1j2SgEz5ATf1HQ/3H6mblnlZcLVaYt2BKQz0cUJpjZIJIS2FTtSFQvhItJbjNBJFZLFa8aubv4+qSpKA+4cPmSqV8tXX5B2nocMkQaE0benpTwOn05FgbSZyaJOZ7jFk70hdIoLK5CuViU/tYoYqHEOAh+dTtj7bjKh1hSF4S3AWO1lckNjRM/YT3jqEVihRUBtNW2hEOJLsgO9HpPMon1ApoWJAxYhBEUXeWcs8EEnwnqHLG4f+eMqfISmJPv50Crbb7zMTfJwYO5elSAnGyTFNjv12j7cnUpi4dpG5KVlsrnixWeWCmu1RkixA6o4cCoOSkWH/SPQDuI6XL+8oTYvSFYfTgN2d8B8+IKVGK8N8vQGZEAqk1plXHlymXmlNUeUORxmgmS9xQtIdRxAaKQOLdkapFMJNPN1/ou97nPc/0bbaxZKTd7gEydTUZk5dLFisb2malsVsRi0yieLd4ZD9K1LhEwihMaZhuV4zTiXd1KGGKoMCdMGxHxhcRuEu2iWzeklT5rEybEJGDy7QH0ZCpwlIxNHz+PDA9ukRNw5oIyCq3McQnuAs3p8dEMGhtKEtWzCP+MkyjZkVPjnPqduzub7h5vYFrz/7LBNOUuBwyiQLoQoIlpg8Uwi4lDs/UhUkoeidY3ecKI2jmb1k8AkzeU7HIZfqm5qybCjKBh0U0hTEFOjtQBQJnwLGSNJk8dbT9wf6foZzVxl1Wpe8+ern/Ob7d1Tv7tncvGRz/ZLV5gapC1LK0kqJhpTJQCIKRBJAyFQpNxGjwIdA3/fZhZAgqoQQeYMhpD5TiySzdkWhS5SIfPrwgfuHe477h+zaCfk0mJSQKbJqK15erfjlz97QtA1leaFO/ZfinD1LRT1tWeSRUeJ5gelJTmHKjJF2KZOfppBHZXRRUs/nzJYr6nZGNZ/TW8c4jjwcT4xT3gwvTwOxHgiHDo8kKcVmOadeZABK2VSI0aOkQ8tIIROLQrNaLyiqlnFwiAR9PzL1WcTKmVBUNS3tcsX1fMm8qojDmmXbcLNeUGvJ6XikP50Yh57d4UgREodDR9d1WOeQSlEkQCmETCgtECpbvq1zdMOAOh4xOh9eLNdLop6YlKN/zmOXCEll5tSFoCkkg/NE7+gGSxABmQKr5RzTzEnKcP/0TEwBRMT7LG6drMW77JeZioFxGBlHe17gQGEUVZEPntykCYUm+HAev8ouhWo+B6k59hM8R4J3OALeG4JT+Gkieo93HjtE3OiyYCwFklFoUVDqRKlBxIloR9zQg5+QKWGEwIiEETCRF4+/FWtKEikE3DjmkZtpghiyY8jaswRNMZ0PRkYX2J363JeTmrEfsNNIdzyd/zyHdQ1Cadr5gpvbWybredyfiI/P+VYDwf54yl3A7gQxIGPg9uqKQuVRytO+w8UTT/sTKAk6L5R/OxatlUZJgZYRpTM+H61QFZRS0SyW+ATDeUYspZhH4EjE4Dnu95yOB8aupy4rFvMFy9WGyYUzTctQNzOads7m+pa2bVksljg7Mg09NngYRqK1eBSqqKhmc9rFClFoim6PmvJ7fpwc+/0Jax11WTNbzGmrkrYuUAQ6F0h2xOHwPsGgmBQEO7B9yu8mOw4ZRCDJ3hE7EI8WoUUeOTUFphSUFUhTEq2lHyd6N2BDZPKexXzOclzx6rMThc/Ut67PNy9K5Z5QSBmn7FPCJTCAi+mMTQ+MLmFmE+PkKVzk1PW0ZUlb1pRVRVXXVE0DhcEGx+lc5nY+UhQl0eUNweFwpG0blvOWV7fXVGXBq1cveff+I4/PO2bzOfPVivXVFaqoEEhSSChTZPpiBKQknUeZU0qE4LPMMkai8wTvSSEizhuNyTmMd3lsqy7Z3N5Sz1uSiHy6f8fz8z3HQ4YehBgy6VRkGt1i0XBzs+arN5/RzmrK6nf3B0VK6QJov+SSSy655JJLLrnkkkt+r7noZi+55JJLLrnkkksuueSS33suG41LLrnkkksuueSSSy655Peey0bjkksuueSSSy655JJLLvm957LRuOSSSy655JJLLrnkkkt+77lsNC655JJLLrnkkksuueSS33suG41LLrnkkksuueSSSy655Peey0bjkksuueSSSy655JJLLvm957LRuOSSSy655JJLLrnkkkt+77lsNC655JJLLrnkkksuueSS33v+I+bP8qNCDOguAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, axs = plt.subplots(1, 2, figsize=(10, 5))\n", + "\n", + "# Visualize the input image and selected patches\n", + "axs[0].imshow(img.cpu()[0].permute(1,2,0).clamp(0, 1))\n", + "axs[0].set_axis_off()\n", + "axs[0].set_title('Input image')\n", + "\n", + "for (px, py) in move_patches:\n", + " circle = patches.Rectangle((py * patch_size, px * patch_size), 7, 7, facecolor='#00b530', edgecolor='white', linewidth=2, label='moving')\n", + " axs[0].add_patch(circle)\n", + "\n", + "# Visualize the counterfactual prediction\n", + "axs[1].imshow(recon[0].clamp(0, 1).float().permute(1,2,0).cpu().detach())\n", + "axs[1].set_axis_off()\n", + "axs[1].set_title('Counterfactual prediction')\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/scripts/cwm/2frame_clumping_tpu.sh b/scripts/cwm/2frame_clumping_tpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..61bb73dfc5b86daeb944a53346563c07d2a1a268 --- /dev/null +++ b/scripts/cwm/2frame_clumping_tpu.sh @@ -0,0 +1,30 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_2frame_clumping/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_2frames_1tube_cf2 \ + --context_frames 1 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 100 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla diff --git a/scripts/cwm/2frame_no_clumping_tpu.sh b/scripts/cwm/2frame_no_clumping_tpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..30e3e38fb5ef9dbfa507a9961adc41807944f3b2 --- /dev/null +++ b/scripts/cwm/2frame_no_clumping_tpu.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_2frame_no_clumping/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_2frames_1tube \ + --context_frames 1 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 100 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 diff --git a/scripts/cwm/2frame_no_clumping_tpu_mr0.90.sh b/scripts/cwm/2frame_no_clumping_tpu_mr0.90.sh new file mode 100755 index 0000000000000000000000000000000000000000..75fbd91c8270d635a00702f2f8b3edfb69d3bd48 --- /dev/null +++ b/scripts/cwm/2frame_no_clumping_tpu_mr0.90.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_2frame_no_clumping_mr0.90/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_2frames_1tube \ + --context_frames 1 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 100 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 diff --git a/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.85.sh b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.85.sh new file mode 100755 index 0000000000000000000000000000000000000000..1adfca7f3cadb44aeb389633e16d2db84f004a57 --- /dev/null +++ b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.85.sh @@ -0,0 +1,30 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_16x16_no_clumping_mr0.85/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.85 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_16x16patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 32 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ diff --git a/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.90.sh b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.90.sh new file mode 100755 index 0000000000000000000000000000000000000000..bb17a97788393e77b5145031d9c44210360e1d9f --- /dev/null +++ b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.90.sh @@ -0,0 +1,30 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_16x16_no_clumping_mr0.90/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_16x16patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 32 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ diff --git a/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.90_extra_data.sh b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.90_extra_data.sh new file mode 100755 index 0000000000000000000000000000000000000000..b63f9b13a467a560a24c65a05f3754afc3fe9397 --- /dev/null +++ b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.90_extra_data.sh @@ -0,0 +1,34 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_16x16_no_clumping_mr0.90_extra_data/" +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset2/how_to_100m/how_to_100m_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_16x16patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 48 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --resume ./checkpoint-799.pth \ No newline at end of file diff --git a/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.95.sh b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.95.sh new file mode 100755 index 0000000000000000000000000000000000000000..654fa2489e2946591988e72c23ff66aee27ad927 --- /dev/null +++ b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.95.sh @@ -0,0 +1,30 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_16x16_no_clumping_mr0.95/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.95 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_16x16patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 32 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ diff --git a/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.98.sh b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.98.sh new file mode 100755 index 0000000000000000000000000000000000000000..2e878e948cef2dc6e5af0b11c7c78b3fcb435780 --- /dev/null +++ b/scripts/cwm/3frame_16x16_no_clumping_tpu_mr0.98.sh @@ -0,0 +1,30 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_16x16_no_clumping_mr0.98/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.98 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_16x16patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 32 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ diff --git a/scripts/cwm/3frame_clumping3_tpu.sh b/scripts/cwm/3frame_clumping3_tpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..b1560d4d8cc2aab3c8579deb8b5602173b8910e7 --- /dev/null +++ b/scripts/cwm/3frame_clumping3_tpu.sh @@ -0,0 +1,30 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_clumping3/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube_cf3 \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 100 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla diff --git a/scripts/cwm/3frame_clumping_gpu.sh b/scripts/cwm/3frame_clumping_gpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..4d41333645b66c798cfd5017d9f0a1a0dd1bd7cf --- /dev/null +++ b/scripts/cwm/3frame_clumping_gpu.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR='/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_clumping_v2/' +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +CUDA_VISIBLE_DEVICES=0 OMP_NUM_THREADS=1 python -m torch.distributed.launch --nproc_per_node=1 \ + --master_addr=10.102.2.157 --master_port=32240 \ + --nnodes=1 --node_rank=0 \ + run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube_cf2 \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 3 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 10 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 0 diff --git a/scripts/cwm/3frame_clumping_tpu.sh b/scripts/cwm/3frame_clumping_tpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..53970008ab660c06fd0bf38cfaddb47858cece6e --- /dev/null +++ b/scripts/cwm/3frame_clumping_tpu.sh @@ -0,0 +1,30 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_clumping_v3/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube_cf2 \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 100 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ No newline at end of file diff --git a/scripts/cwm/3frame_no_clumping_gpu.sh b/scripts/cwm/3frame_no_clumping_gpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..38fa8d71f629f625ded73561a39bd6ae61711d37 --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_gpu.sh @@ -0,0 +1,32 @@ +OUTPUT_DIR='/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_clumping_debug/' +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +CUDA_VISIBLE_DEVICES=0 OMP_NUM_THREADS=1 python -m torch.distributed.launch --nproc_per_node=1 \ + --master_addr=10.102.2.137 --master_port=32240 \ + --nnodes=1 --node_rank=0 \ + run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 diff --git a/scripts/cwm/3frame_no_clumping_gpu_extra_data.sh b/scripts/cwm/3frame_no_clumping_gpu_extra_data.sh new file mode 100755 index 0000000000000000000000000000000000000000..ba062436cbe01e208c84f3b0c130bb90c329dcdb --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_gpu_extra_data.sh @@ -0,0 +1,34 @@ +OUTPUT_DIR='/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_clumping_debug/' +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset/how_to_100m/how_to_100m_train_list.txt" + +CUDA_VISIBLE_DEVICES=0 OMP_NUM_THREADS=1 python -m torch.distributed.launch --nproc_per_node=1 \ + --master_addr=10.102.2.137 --master_port=32240 \ + --nnodes=1 --node_rank=0 \ + run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_H} ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 3 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 1 \ + --save_ckpt_freq 1 \ + --epochs 19 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 0 diff --git a/scripts/cwm/3frame_no_clumping_maskvit_gpu.sh b/scripts/cwm/3frame_no_clumping_maskvit_gpu.sh new file mode 100644 index 0000000000000000000000000000000000000000..842df2f83287df411d30f30693131acc6d98d65d --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_maskvit_gpu.sh @@ -0,0 +1,33 @@ +OUTPUT_DIR='/ccn2/u/honglinc/cwm_checkpoints/ablation_3frame_no_clumping_maskvit/' +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +OMP_NUM_THREADS=1 python -m torch.distributed.launch --nproc_per_node=8 \ + --master_addr=10.102.2.153 --master_port=32240 \ + --nnodes=2 --node_rank=1 \ + run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table_maskvit \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 16 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 10 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 20 \ + --num_workers 32 \ + --min_lr 1e-5 diff --git a/scripts/cwm/3frame_no_clumping_tpu.sh b/scripts/cwm/3frame_no_clumping_tpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..61fd7281abaa2125168b14299a7a1f0fe53b7898 --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_ep3200/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.99 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 100 \ + --epochs 3200 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --resume ./checkpoint-899.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.60.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.60.sh new file mode 100755 index 0000000000000000000000000000000000000000..83af544a2260ab536cede1dcf4b90dad0ece9bfe --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.60.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.60/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.60 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.70.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.70.sh new file mode 100755 index 0000000000000000000000000000000000000000..c14b98571766b10920d6314956843e68b6f36bdd --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.70.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.70/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.70 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.80.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.80.sh new file mode 100755 index 0000000000000000000000000000000000000000..3897d0c36b352c5d183fca3378dc1f07ec312f43 --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.80.sh @@ -0,0 +1,32 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.80_rerun/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.80 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 \ + #--resume checkpoint-249.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.85.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.85.sh new file mode 100755 index 0000000000000000000000000000000000000000..bf990bf7de1f3bff1fe51a7c70da85f980286252 --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.85.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.85/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.85 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.85_extra_data_ep400_huge.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.85_extra_data_ep400_huge.sh new file mode 100755 index 0000000000000000000000000000000000000000..0f38124e47c0ea550fdde24a8ae305ad6ffe8b4a --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.85_extra_data_ep400_huge.sh @@ -0,0 +1,34 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.85_extra_data_ep400_huge/" +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset2/how_to_100m/how_to_100m_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.85 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vithuge_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 2 \ + --accum_iter 8 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 20 \ + --save_ckpt_freq 10 \ + --epochs 400 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 8 \ + --use_xla \ + --resume checkpoint-219.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.85_extra_data_ep400_large.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.85_extra_data_ep400_large.sh new file mode 100755 index 0000000000000000000000000000000000000000..a40b857a49309a632c92caebc4b07472601da51b --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.85_extra_data_ep400_large.sh @@ -0,0 +1,33 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.85_extra_data_ep400_large/" +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset2/how_to_100m/how_to_100m_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.85 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitlarge_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 8 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 20 \ + --save_ckpt_freq 10 \ + --epochs 400 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.90.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.90.sh new file mode 100755 index 0000000000000000000000000000000000000000..32e19d695ab15e5eb30b7bcf0f2161786ddbbccb --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.90.sh @@ -0,0 +1,32 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.90/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 \ + --resume ./checkpoint-699.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data.sh new file mode 100755 index 0000000000000000000000000000000000000000..614e4978a0f0d7caaaf2eca3f4b05c8993b06b0a --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data.sh @@ -0,0 +1,36 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_wo_howto/" + +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset2/how_to_100m/how_to_100m_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 5 \ + --save_ckpt_freq 5 \ + --epochs 105 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 \ + --resume checkpoint-29.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400.sh new file mode 100755 index 0000000000000000000000000000000000000000..4483c67362e378a2d6978e2fa9e3b18a7d0c8cec --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400.sh @@ -0,0 +1,34 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400/" +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset2/how_to_100m/how_to_100m_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 20 \ + --save_ckpt_freq 10 \ + --epochs 400 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --resume checkpoint-239.pth \ No newline at end of file diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400_huge.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400_huge.sh new file mode 100755 index 0000000000000000000000000000000000000000..12b9adaf4624e428c2eaa341d0b4cb136371cf0d --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400_huge.sh @@ -0,0 +1,34 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400_huge/" +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset2/how_to_100m/how_to_100m_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vithuge_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 2 \ + --accum_iter 8 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 20 \ + --save_ckpt_freq 10 \ + --epochs 400 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 8 \ + --use_xla \ + --resume checkpoint-339.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400_large.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400_large.sh new file mode 100755 index 0000000000000000000000000000000000000000..da9eac8e6a59dfe51c33f931422cd5ec9027e30d --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_extra_data_ep400_large.sh @@ -0,0 +1,34 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.90_extra_data_ep400_large/" +DATA_PATH_Ktr="/ccn2/dataset/Kinetics700/kinetics_700_train_list.txt" +DATA_PATH_M="/ccn2/dataset/Moments/multi_moment_train_list.txt" +DATA_PATH_E="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/ego4d_train_list_320p_chunked_imu.txt" +DATA_PATH_H="/ccn2/dataset2/how_to_100m/how_to_100m_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path_list ${DATA_PATH_Ktr} ${DATA_PATH_M} ${DATA_PATH_E} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitlarge_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 8 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 20 \ + --save_ckpt_freq 10 \ + --epochs 400 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --resume checkpoint-229.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.90_rotated_table.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_rotated_table.sh new file mode 100755 index 0000000000000000000000000000000000000000..c350428465a6f7266f035050b4d84442134b1cbb --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.90_rotated_table.sh @@ -0,0 +1,31 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.90_rotated_tbl/" +DATA_PATH="${HOME}/cwm/cwm/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/cwm/cwm/run_cwm_pretraining_legacy.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 6}' \ + --model vitbase_8x8patch_8frames_1tube \ + --context_frames 2 \ + --target_frames 6 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 1 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 256 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 1 \ + --use_xla \ + --min_lr 1e-5 \ diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr0.95.sh b/scripts/cwm/3frame_no_clumping_tpu_mr0.95.sh new file mode 100755 index 0000000000000000000000000000000000000000..646c7f647223f4a868bd0ab1aeeea226665728f3 --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr0.95.sh @@ -0,0 +1,32 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr0.95/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 0.95 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 \ + --resume ./checkpoint-649.pth diff --git a/scripts/cwm/3frame_no_clumping_tpu_mr1.0.sh b/scripts/cwm/3frame_no_clumping_tpu_mr1.0.sh new file mode 100755 index 0000000000000000000000000000000000000000..efca48088d3c32d5a83b5258fcde7a0c422bdf78 --- /dev/null +++ b/scripts/cwm/3frame_no_clumping_tpu_mr1.0.sh @@ -0,0 +1,32 @@ +OUTPUT_DIR="${HOME}/checkpoints/cwm_cvpr_checkpoints/ablation_3frame_no_clumping_mr1.0/" +DATA_PATH="${HOME}/BBNet/bbnet/models/VideoMAE-main/video_file_lists/kinetics_400_train_list.txt" + +python3 ~/BBNet/bbnet/models/VideoMAE-main/run_cwm_pretraining.py \ + --data_path ${DATA_PATH} \ + --mask_type rotated_table \ + --mask_ratio 1.0 \ + --mask_kwargs '{"tube_length": 1}' \ + --model vitbase_8x8patch_3frames_1tube \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 16 \ + --accum_iter 2 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --no_normlize_target \ + --rescale_size 224 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 \ + --use_xla \ + --min_lr 1e-5 \ + #--resume checkpoint-249.pth diff --git a/scripts/pretrain/3frame_patch8x8_mr0.90_gpu.sh b/scripts/pretrain/3frame_patch8x8_mr0.90_gpu.sh new file mode 100755 index 0000000000000000000000000000000000000000..f48072225171857f78c15dcda1afcbb6e875daff --- /dev/null +++ b/scripts/pretrain/3frame_patch8x8_mr0.90_gpu.sh @@ -0,0 +1,39 @@ +OUTPUT_DIR='checkpoints/3frame_patch8x8_mr0.90_gpu/' +DATA_PATH="cwm/data/video_file_lists/kinetics_400_train_list.txt" +MASTER_ADDRESS=10.102.2.146 +NNODES=1 +NODE_RANK=0 +NPROC_PER_NODE=1 + +echo "master addr: $MASTER_ADDRESS" +echo "num of nodes: $NNODES" +echo "node rank: $NODE_RANK" +echo "procs per node: $NPROC_PER_NODE" + +OMP_NUM_THREADS=1 torchrun \ + --nproc_per_node=$NPROC_PER_NODE --nnodes=$NNODES --node_rank=$NODE_RANK \ + --master_addr=$MASTER_ADDRESS --master_port=19234 \ + cwm/run_pretraining.py \ + --data_path ${DATA_PATH} \ + --model vitb_8x8patch_3frames \ + --mask_type rotated_table \ + --mask_ratio 0.90 \ + --mask_kwargs '{"tube_length": 1}' \ + --context_frames 2 \ + --target_frames 1 \ + --temporal_units 'ms' \ + --sampling_rate 150 \ + --context_target_gap 150 150 \ + --batch_size 1 \ + --accum_iter 1 \ + --opt adamw \ + --opt_betas 0.9 0.95 \ + --warmup_epochs 40 \ + --save_ckpt_freq 50 \ + --epochs 800 \ + --augmentation_type 'multiscale' \ + --augmentation_scales 1.0 0.875 0.75 0.66 \ + --log_dir ${OUTPUT_DIR} \ + --output_dir ${OUTPUT_DIR} \ + --print_freq 1 \ + --num_workers 16 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..df22e58d1eeec4d90c8906e6bbdc1673da29383d --- /dev/null +++ b/setup.py @@ -0,0 +1,33 @@ +from setuptools import setup, find_packages + +setup( + name="cwm", + version="1.0", + packages=find_packages(), + description="Video modeling transformers package for MAE", + author="Dan Bear, Kevin Figelis, Honglin Chen, Rahul Venakatesh, Wanhee Lee, Dan Yamins, Klemen Kotar", + install_requires=[ + # 'scipy', + # 'scikit-learn', + # 'matplotlib', + # 'h5py', + # 'kornia', + # 'future', + # 'einops', + # 'timm', + # 'opencv-python', + # 'decord', + # 'iopath', + # 'pandas', + # 'IPython', + # 'tensorboardx', + # 'tensorboard', + # 'positional_encodings', + # 'scikit-image', + # 'packaging', + # 'wandb', + # 'numpy==1.23.5', + # 'torch==2.0.0', + # 'torchvision==0.15.1' + ], +)