From f23731119ced565734a879ba270793eb745f8c8d Mon Sep 17 00:00:00 2001 From: khushal Date: Thu, 28 Nov 2024 18:01:40 +0530 Subject: [PATCH] Resetting utils subtree. --- utils_v2/.gitignore | 8 - utils_v2/__init__.py | 0 utils_v2/ai/__init__.py | 0 utils_v2/ai/image_classification/__init__.py | 0 .../ai/image_classification/async_blur.py | 202 -- .../ai/image_classification/async_nsfw.py | 188 -- utils_v2/ai/image_segmentation/__init__.py | 0 .../async_dichotomous_segmentation.py | 223 --- utils_v2/ai/object_detection/__init__.py | 0 utils_v2/ai/object_detection/yolo.py | 176 -- utils_v2/ai/tts/__init__.py | 0 utils_v2/ai/tts/easy_tts.py | 175 -- utils_v2/ai/tts/test.wav | Bin 162150 -> 0 bytes utils_v2/api/__init__.py | 0 .../api/__pycache__/__init__.cpython-310.pyc | Bin 166 -> 0 bytes .../__pycache__/async_quart.cpython-310.pyc | Bin 32014 -> 0 bytes .../api/__pycache__/codes.cpython-310.pyc | Bin 3712 -> 0 bytes utils_v2/api/__pycache__/log.cpython-310.pyc | Bin 1782 -> 0 bytes .../metrics_prometheus.cpython-310.pyc | Bin 5163 -> 0 bytes .../api/__pycache__/response.cpython-310.pyc | Bin 1877 -> 0 bytes utils_v2/api/async_quart.py | 1265 ------------ utils_v2/api/codes.py | 164 -- utils_v2/api/log.py | 139 -- utils_v2/api/response.py | 133 -- utils_v2/cache/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 168 -> 0 bytes .../async_redis_cache.cpython-310.pyc | Bin 13364 -> 0 bytes utils_v2/cache/async_redis_cache.py | 497 ----- utils_v2/cache/async_redis_cache_v2.py | 568 ------ utils_v2/database/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 171 -> 0 bytes .../async_mongo_v2.cpython-310.pyc | Bin 40273 -> 0 bytes .../async_mysql_v2.cpython-310.pyc | Bin 9102 -> 0 bytes utils_v2/database/async_firebase.py | 504 ----- utils_v2/database/async_mongo.py | 843 -------- utils_v2/database/async_mongo_storage.py | 358 ---- utils_v2/database/async_mongo_v2.py | 1736 ----------------- utils_v2/database/async_mysql_v2.py | 424 ---- utils_v2/dataframe/__init__.py | 0 utils_v2/dataframe/splitter.py | 118 -- utils_v2/date_time/__init__.py | 0 utils_v2/date_time/date_time.py | 335 ---- utils_v2/goog/__init__.py | 0 utils_v2/goog/base.py | 450 ----- utils_v2/goog/gmail/__init__.py | 0 utils_v2/goog/gmail/gmail_client.py | 980 ---------- utils_v2/goog/gmail/gmail_message.py | 336 ---- .../chatgpt_suggested_message_format.json | 69 - .../formatted_message_list_20241126.json | 36 - ...3669615aa33694_no_attachment_20241126.json | 148 -- ...7930033154ca_with_attachment_20241126.json | 258 --- ..._message_03_19365d0239aa1aaf_20241126.json | 175 -- ..._message_04_193640e74d93dc9b_20241126.json | 179 -- ..._message_05_19363d6a7f50225a_20241126.json | 183 -- ..._message_06_19363ba8e2582133_20241126.json | 183 -- ..._message_07_19362f9983e58ea6_20241126.json | 210 -- ..._message_08_19360aabcb976cfc_20241126.json | 175 -- ..._message_09_193604ad97c9fe62_20241126.json | 183 -- ..._message_10_1935e92672e67f22_20241126.json | 183 -- utils_v2/goog/models/__init__.py | 0 utils_v2/goog/models/data/__init__.py | 0 utils_v2/goog/models/data/api_call.py | 132 -- utils_v2/goog/models/data/auth_tokens.py | 237 --- utils_v2/image/__init__.py | 0 utils_v2/image/scanner/__init__.py | 0 utils_v2/image/scanner/scanner.py | 410 ---- utils_v2/image/scanner/scanner_v2.py | 379 ---- utils_v2/logging/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 170 -> 0 bytes .../logging/__pycache__/model.cpython-310.pyc | Bin 1713 -> 0 bytes utils_v2/logging/context.py | 468 ----- utils_v2/logging/model.py | 131 -- utils_v2/mail/__init__.py | 0 utils_v2/mail/async_smpt.py | 443 ----- utils_v2/mail/mail_parser.py | 177 -- utils_v2/network/__init__.py | 0 utils_v2/network/ip.py | 173 -- utils_v2/network/ping.py | 218 --- utils_v2/pdf/__init__.py | 0 utils_v2/pdf/pdf_maker.py | 1642 ---------------- utils_v2/queue/__init__.py | 0 utils_v2/queue/async_kafka.py | 554 ------ utils_v2/rate_limit/__init__.py | 0 utils_v2/rate_limit/async_token_bucket.py | 212 -- utils_v2/security/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 171 -> 0 bytes .../__pycache__/sanitizers.cpython-310.pyc | Bin 1933 -> 0 bytes utils_v2/security/hash.py | 245 --- utils_v2/security/otp.py | 156 -- utils_v2/security/sanitizers.py | 135 -- utils_v2/serialization/__init__.py | 0 utils_v2/serialization/json_serializer.py | 129 -- utils_v2/serialization/pickle_serializer.py | 122 -- .../serialization/universal_serializer.py | 265 --- utils_v2/sms/__init__.py | 0 utils_v2/sms/async_nimbus.py | 252 --- utils_v2/string/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 169 -> 0 bytes .../string/__pycache__/json.cpython-310.pyc | Bin 3546 -> 0 bytes .../string/__pycache__/regex.cpython-310.pyc | Bin 7489 -> 0 bytes utils_v2/string/fuzzy.py | 168 -- utils_v2/string/help.py | 177 -- utils_v2/string/json.py | 202 -- utils_v2/string/regex.py | 288 --- utils_v2/system/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 169 -> 0 bytes .../system/__pycache__/files.cpython-310.pyc | Bin 5497 -> 0 bytes utils_v2/system/files.py | 508 ----- 108 files changed, 19627 deletions(-) delete mode 100644 utils_v2/.gitignore delete mode 100644 utils_v2/__init__.py delete mode 100644 utils_v2/ai/__init__.py delete mode 100644 utils_v2/ai/image_classification/__init__.py delete mode 100644 utils_v2/ai/image_classification/async_blur.py delete mode 100644 utils_v2/ai/image_classification/async_nsfw.py delete mode 100644 utils_v2/ai/image_segmentation/__init__.py delete mode 100644 utils_v2/ai/image_segmentation/async_dichotomous_segmentation.py delete mode 100644 utils_v2/ai/object_detection/__init__.py delete mode 100644 utils_v2/ai/object_detection/yolo.py delete mode 100644 utils_v2/ai/tts/__init__.py delete mode 100644 utils_v2/ai/tts/easy_tts.py delete mode 100644 utils_v2/ai/tts/test.wav delete mode 100644 utils_v2/api/__init__.py delete mode 100644 utils_v2/api/__pycache__/__init__.cpython-310.pyc delete mode 100644 utils_v2/api/__pycache__/async_quart.cpython-310.pyc delete mode 100644 utils_v2/api/__pycache__/codes.cpython-310.pyc delete mode 100644 utils_v2/api/__pycache__/log.cpython-310.pyc delete mode 100644 utils_v2/api/__pycache__/metrics_prometheus.cpython-310.pyc delete mode 100644 utils_v2/api/__pycache__/response.cpython-310.pyc delete mode 100644 utils_v2/api/async_quart.py delete mode 100644 utils_v2/api/codes.py delete mode 100644 utils_v2/api/log.py delete mode 100644 utils_v2/api/response.py delete mode 100644 utils_v2/cache/__init__.py delete mode 100644 utils_v2/cache/__pycache__/__init__.cpython-310.pyc delete mode 100644 utils_v2/cache/__pycache__/async_redis_cache.cpython-310.pyc delete mode 100644 utils_v2/cache/async_redis_cache.py delete mode 100644 utils_v2/cache/async_redis_cache_v2.py delete mode 100644 utils_v2/database/__init__.py delete mode 100644 utils_v2/database/__pycache__/__init__.cpython-310.pyc delete mode 100644 utils_v2/database/__pycache__/async_mongo_v2.cpython-310.pyc delete mode 100644 utils_v2/database/__pycache__/async_mysql_v2.cpython-310.pyc delete mode 100644 utils_v2/database/async_firebase.py delete mode 100644 utils_v2/database/async_mongo.py delete mode 100644 utils_v2/database/async_mongo_storage.py delete mode 100644 utils_v2/database/async_mongo_v2.py delete mode 100644 utils_v2/database/async_mysql_v2.py delete mode 100644 utils_v2/dataframe/__init__.py delete mode 100644 utils_v2/dataframe/splitter.py delete mode 100644 utils_v2/date_time/__init__.py delete mode 100644 utils_v2/date_time/date_time.py delete mode 100644 utils_v2/goog/__init__.py delete mode 100644 utils_v2/goog/base.py delete mode 100644 utils_v2/goog/gmail/__init__.py delete mode 100644 utils_v2/goog/gmail/gmail_client.py delete mode 100644 utils_v2/goog/gmail/gmail_message.py delete mode 100644 utils_v2/goog/gmail/json/messages/chatgpt_suggested_message_format.json delete mode 100644 utils_v2/goog/gmail/json/messages/formatted_message_list_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_01_193669615aa33694_no_attachment_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_02_19367930033154ca_with_attachment_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_03_19365d0239aa1aaf_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_04_193640e74d93dc9b_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_05_19363d6a7f50225a_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_06_19363ba8e2582133_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_07_19362f9983e58ea6_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_08_19360aabcb976cfc_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_09_193604ad97c9fe62_20241126.json delete mode 100644 utils_v2/goog/gmail/json/messages/raw_message_10_1935e92672e67f22_20241126.json delete mode 100644 utils_v2/goog/models/__init__.py delete mode 100644 utils_v2/goog/models/data/__init__.py delete mode 100644 utils_v2/goog/models/data/api_call.py delete mode 100644 utils_v2/goog/models/data/auth_tokens.py delete mode 100644 utils_v2/image/__init__.py delete mode 100644 utils_v2/image/scanner/__init__.py delete mode 100644 utils_v2/image/scanner/scanner.py delete mode 100644 utils_v2/image/scanner/scanner_v2.py delete mode 100644 utils_v2/logging/__init__.py delete mode 100644 utils_v2/logging/__pycache__/__init__.cpython-310.pyc delete mode 100644 utils_v2/logging/__pycache__/model.cpython-310.pyc delete mode 100644 utils_v2/logging/context.py delete mode 100644 utils_v2/logging/model.py delete mode 100644 utils_v2/mail/__init__.py delete mode 100644 utils_v2/mail/async_smpt.py delete mode 100644 utils_v2/mail/mail_parser.py delete mode 100644 utils_v2/network/__init__.py delete mode 100644 utils_v2/network/ip.py delete mode 100644 utils_v2/network/ping.py delete mode 100644 utils_v2/pdf/__init__.py delete mode 100644 utils_v2/pdf/pdf_maker.py delete mode 100644 utils_v2/queue/__init__.py delete mode 100644 utils_v2/queue/async_kafka.py delete mode 100644 utils_v2/rate_limit/__init__.py delete mode 100644 utils_v2/rate_limit/async_token_bucket.py delete mode 100644 utils_v2/security/__init__.py delete mode 100644 utils_v2/security/__pycache__/__init__.cpython-310.pyc delete mode 100644 utils_v2/security/__pycache__/sanitizers.cpython-310.pyc delete mode 100644 utils_v2/security/hash.py delete mode 100644 utils_v2/security/otp.py delete mode 100644 utils_v2/security/sanitizers.py delete mode 100644 utils_v2/serialization/__init__.py delete mode 100644 utils_v2/serialization/json_serializer.py delete mode 100644 utils_v2/serialization/pickle_serializer.py delete mode 100644 utils_v2/serialization/universal_serializer.py delete mode 100644 utils_v2/sms/__init__.py delete mode 100644 utils_v2/sms/async_nimbus.py delete mode 100644 utils_v2/string/__init__.py delete mode 100644 utils_v2/string/__pycache__/__init__.cpython-310.pyc delete mode 100644 utils_v2/string/__pycache__/json.cpython-310.pyc delete mode 100644 utils_v2/string/__pycache__/regex.cpython-310.pyc delete mode 100644 utils_v2/string/fuzzy.py delete mode 100644 utils_v2/string/help.py delete mode 100644 utils_v2/string/json.py delete mode 100644 utils_v2/string/regex.py delete mode 100644 utils_v2/system/__init__.py delete mode 100644 utils_v2/system/__pycache__/__init__.cpython-310.pyc delete mode 100644 utils_v2/system/__pycache__/files.cpython-310.pyc delete mode 100644 utils_v2/system/files.py diff --git a/utils_v2/.gitignore b/utils_v2/.gitignore deleted file mode 100644 index ebb370b..0000000 --- a/utils_v2/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/.venv/ -/.idea/ -**/__pycache__/ -__pycache__/ - -*.pem -*.pyc -*.pyd \ No newline at end of file diff --git a/utils_v2/__init__.py b/utils_v2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/ai/__init__.py b/utils_v2/ai/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/ai/image_classification/__init__.py b/utils_v2/ai/image_classification/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/ai/image_classification/async_blur.py b/utils_v2/ai/image_classification/async_blur.py deleted file mode 100644 index f69af42..0000000 --- a/utils_v2/ai/image_classification/async_blur.py +++ /dev/null @@ -1,202 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Monday, 2nd Sept., 2024 - - OBJECTIVE: - - To provide an easy way to assess images for blurriness. - Tried and implemented using HuggingFace behaviour_models. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# For using the AI model: -import torch -from transformers import pipeline - -# To download images from URLs: -import requests - -# To read images: -from PIL import Image - -# Common: -from shared import variables - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AssessImageBlur: - - def __init__( - self, - model, - blur_label = "Blur", - clarity_label = "Normal", - blur_threshold = 0.25, - clarity_threshold = 0.65 - ): - - """ - This class assesses the input image and tells if it is blurry or clear. - :param model: The model to use. Either the name of the HuggingFace repo, or the directory where the model is - stored. - :param blur_threshold: The max allowed blurriness (0 to 1 range). - :param clarity_threshold: The minimum needed clarity (0 to 1 range). - """ - - # Note down the config: - self.__model = model - self.__device = "gpu" if torch.cuda.is_available() else "cpu" - self.__blur_label = blur_label - self.__clarity_label = clarity_label - self.__blur_threshold = blur_threshold - self.__clarity_threshold = clarity_threshold - - # Initialize the classifier: - self.__classifier = pipeline( - task = "image-classification", - model = self.__model, - device = self.__device - ) - - @staticmethod - async def read_image(source): - - """ - Reads an image in whichever format it is provided and returns it as a PIL object. - :param source: The image as either a path or a URL or a io.BytesIO object. - :return: The image opened as a PIL object. - """ - - # If the input image is already a PIL image: - if isinstance(source, Image.Image): return source - - # If a buffer is provided: - elif isinstance(source, io.BytesIO): - source.seek(0) - return Image.open(source) - - # If a string is provided (local path or URL): - elif isinstance(source, str): - if source.startswith("http://") or source.startswith("https://"): - response = await variables.http_client.get(source) - return Image.open(io.BytesIO(response.content)) - else: return Image.open(source) - - async def classify(self, image): - - """ - To get the prediction of the model from the given input image. - :param image: The image (as a PIL object or file path or a URL). - :return: The dictionary of classes with their respective predictions. - """ - - image = await self.read_image(image) - predictions = self.__classifier(image) - classes = {p["label"]: p["score"] for p in predictions} - return classes - - async def is_ok( - self, - image, - blur_threshold = None, - clarity_threshold = None - ): - - """ - Checks if the image given to it can be used, or should be rejected. - :param image: The image (as a PIL object or file path or a URL). - :param blur_threshold: A custom threshold to test against. If not provided, the default will be taken that was - provided when the instance was created. - :param clarity_threshold: A custom threshold to test against. If not provided, the default will be taken that - was provided when the instance was created. - :return: True if the image is okay, else False. - """ - - image = await self.read_image(image) - blur_threshold = blur_threshold or self.__blur_threshold - clarity_threshold = clarity_threshold or self.__clarity_threshold - classes = await self.classify(image) - if ( - classes[self.__blur_label] <= blur_threshold and - classes[self.__clarity_label] >= clarity_threshold - ): return True - return False - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - - - async def main(): - image = r"/home/developer/Downloads/low-res-check.png" - assessor = AssessImageBlur(model = r"/home/developer/PycharmProjects/utils/data/ai/behaviour_models/hugging_face/image_classification/BlurOrBokeh") - usable = await assessor.is_ok(image) - classes = await assessor.classify(image) - print("IS OKAY:", usable) - print("CLASSES:", classes) - - asyncio.run(main()) diff --git a/utils_v2/ai/image_classification/async_nsfw.py b/utils_v2/ai/image_classification/async_nsfw.py deleted file mode 100644 index 446c34a..0000000 --- a/utils_v2/ai/image_classification/async_nsfw.py +++ /dev/null @@ -1,188 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Monday, 2nd Sept., 2024 - - OBJECTIVE: - - To provide an easy way to assess images for adult content. - Tried and implemented using HuggingFace behaviour_models. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# For using the AI model: -import torch -from transformers import pipeline - -# To download images from URLs: -import requests - -# To read images: -from PIL import Image - -# Common: -from shared import variables - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AssessImageNSFW: - - def __init__( - self, - model, - nsfw_label = "nsfw", - nsfw_threshold = 0.25, - ): - - """ - This class assesses the input image and tells if it is blurry or clear. - :param model: The model to use. Either the name of the HuggingFace repo, or the directory where the model is - stored. - :param nsfw_threshold: The max allowed blurriness (0 to 1 range). - """ - - # Note down the config: - self.__model = model - self.__device = "gpu" if torch.cuda.is_available() else "cpu" - self.__nsfw_label = nsfw_label - self.__nsfw_threshold = nsfw_threshold - - # Initialize the classifier: - self.__classifier = pipeline( - task = "image-classification", - model = self.__model, - device = self.__device - ) - - @staticmethod - async def read_image(source): - - """ - Reads an image in whichever format it is provided and returns it as a PIL object. - :param source: The image as either a path or a URL or a io.BytesIO object. - :return: The image opened as a PIL object. - """ - - # If the input image is already a PIL image: - if isinstance(source, Image.Image): return source - - # If a buffer is provided: - elif isinstance(source, io.BytesIO): - source.seek(0) - return Image.open(source) - - # If a string is provided (local path or URL): - elif isinstance(source, str): - if source.startswith("http://") or source.startswith("https://"): - response = await variables.http_client.get(source) - return Image.open(io.BytesIO(response.content)) - else: return Image.open(source) - - async def classify(self, image): - - """ - To get the prediction of the model from the given input image. - :param image: The image (as a PIL object or file path or a URL). - :return: The dictionary of classes with their respective predictions. - """ - - image = await self.read_image(image) - predictions = self.__classifier(image) - classes = {p["label"]: p["score"] for p in predictions} - return classes - - async def is_ok( - self, - image, - nsfw_threshold = None - ): - - """ - Checks if the image given to it can be used, or should be rejected. - :param image: The image (as a PIL object or file path or a URL). - :param nsfw_threshold: A custom threshold to test against. If not provided, the default will be taken that was - provided when the instance was created. - :return: True if the image is okay, else False. - """ - - image = await self.read_image(image) - nsfw_threshold = nsfw_threshold or self.__nsfw_threshold - classes = await self.classify(image) - return True if classes[self.__nsfw_label] <= nsfw_threshold else False - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - - - async def main(): - - assessor = AssessImageNSFW(model = r"/path/to/model") - usable = await assessor.is_ok(r"/path/to/image/img.jpg") - classes = await assessor.classify(r"https://...") - - - asyncio.run(main()) diff --git a/utils_v2/ai/image_segmentation/__init__.py b/utils_v2/ai/image_segmentation/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/ai/image_segmentation/async_dichotomous_segmentation.py b/utils_v2/ai/image_segmentation/async_dichotomous_segmentation.py deleted file mode 100644 index fb6d6c7..0000000 --- a/utils_v2/ai/image_segmentation/async_dichotomous_segmentation.py +++ /dev/null @@ -1,223 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Saturday, 14th Sept., 2024 - - OBJECTIVE: - - To provide an easy way to get masks from dichotomous image segmentation. - - This code uses a very specific model from HuggingFace: "ZhengPeng7/BiRefNet-portrait". - You may experiment with other behaviour_models too, but make sure that model is made for "dichotomous" behaviour. This - means that the model should have only two classes like "foreground", and "background". The specified model was - trained for implementing portrait mode style blurring of backgrounds. - - The originally tested model has an MIT license as per their GitHub page. The code in this file may or may not - support drop-in replacement for other behaviour_models, please be aware about this. - - REFERENCES: - - 01. https://huggingface.co/ZhengPeng7/BiRefNet-portrait - 02. https://github.com/ZhengPeng7/BiRefNet - - DOWNLOADS: - - 01. https://huggingface.co/ZhengPeng7/BiRefNet-portrait/tree/main - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For system-level activities: -import io - -# To work with PIL images: -from PIL import Image - -# To make asynchronous HTTP calls: -from shared.variables import http_client - -# For using the AI model: -import torch -from torchvision import transforms -from transformers import AutoModelForImageSegmentation - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class DichotomousSegmenter: - - def __init__( - self, - model = r"zhengpeng7/BiRefNet-portrait" - ): - - """ - This class uses Dichotomous Image Segmentation to produce a mask of what is in the foreground (or what is of - interest in a given image). - :param model: The path of the model. - """ - - # Check if GPU is available for faster predictions: - self.__cuda_is_available = True if torch.cuda.is_available() else False - - # Initialize the model: - self.__model = AutoModelForImageSegmentation.from_pretrained( - pretrained_model_name_or_path = model, - trust_remote_code = True - ) - torch.set_float32_matmul_precision(["high", "highest"][0]) - self.__model.to("cuda" if self.__cuda_is_available else "cpu") - - @staticmethod - async def read_image(source): - - """ - Reads an image in whichever format it is provided and returns it as a PIL object. - :param source: The image as either a path or a URL or a io.BytesIO object. - :return: The image opened as a PIL object. - """ - - # If the input image is already a PIL image: - if isinstance(source, Image.Image): return source - - # If a buffer is provided: - elif isinstance(source, io.BytesIO): - source.seek(0) - return Image.open(source) - - # If a string is provided (local path or URL): - elif isinstance(source, str): - if source.startswith("http://") or source.startswith("https://"): - response = await http_client.get(source) - return Image.open(io.BytesIO(response.content)) - else: return Image.open(source) - - async def get_mask(self, image): - - """ - Process the image to figure out the mask. In some cases (like the image of a sunset) you will have no white - pixels in the mask. White pixels represent the areas that the AI considered to be the foreground (area of - interest) and the black parts are the background. - :param image: The image data as either a PIL object, or a path to a file on the local disk, or a URL. - :return: The mask as a PIL object. - """ - - # Prepare the image transformer: - image_size = (1024, 1024) - transform_image = transforms.Compose([ - transforms.Resize(image_size), - transforms.ToTensor(), - transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) - ]) - - # Read and transform the image: - image = await self.read_image(image) - input_image = transform_image(image).unsqueeze(0).to("cuda" if self.__cuda_is_available else "cpu") - - # Make the prediction: - with torch.no_grad(): - if self.__cuda_is_available: mask = self.__model(input_image)[-1].sigmoid().cuda() - else: mask = self.__model(input_image)[-1].sigmoid().cpu() - - # Create a PIL object of the mask data: - mask = mask[0].squeeze() - mask = transforms.ToPILImage()(mask) - mask = mask.resize(image.size) - - # Done here: - return mask - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - import numpy as np - - async def main(): - - model = DichotomousSegmenter() - - images = [ - # r"/home/developer/Downloads/kate.jpg", - # r"/home/developer/Downloads/IMG-20240730-WA0001.jpg", - # r"/home/developer/Downloads/pexels-pixabay-57416.jpg", - # r"/home/developer/Downloads/summer_clothes.jpg", - # r"/home/developer/Downloads/low_res_cat - upscaled.png", - # r"/home/developer/Downloads/blurry_traffic.jpg", - r"/home/developer/Downloads/card_0.jpg", - r"/home/developer/Downloads/card_1.jpg", - r"/home/developer/Downloads/card_2.jpg", - r"/home/developer/Downloads/card_3.jpg", - r"/home/developer/Downloads/sushmita_card.jpg", - r"/home/developer/Downloads/niranjan_card.jpg", - r"/home/developer/Downloads/niranjan_card_2.jpg", - ] - - for image in images: - print(image.split("/")[-1]) - image = await DichotomousSegmenter.read_image(image) - mask = await model.get_mask(image) - image.show() - mask.show() - print("MASK!") - array = np.array(mask) - print("Dimensions of the array:", array.shape) - masked_count = np.sum(array > 125) - print(masked_count, type(masked_count), np.size, type(np.size)) - percentage = masked_count / np.prod(array.shape) - print("Area:", round(percentage * 100, 4)) - # image.putalpha(mask) - # image.show() - # mask.show() - - - asyncio.run(main()) diff --git a/utils_v2/ai/object_detection/__init__.py b/utils_v2/ai/object_detection/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/ai/object_detection/yolo.py b/utils_v2/ai/object_detection/yolo.py deleted file mode 100644 index a435ca6..0000000 --- a/utils_v2/ai/object_detection/yolo.py +++ /dev/null @@ -1,176 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Thursday, 4th Jul, 2024 - - OBJECTIVE: - - To provide a class to detect objects in images using YOLO behaviour_models. - - REFERENCES: - - 1) Code Examples: https://docs.ultralytics.com/usage/python/ - 2) Models: https://docs.ultralytics.com/models/yolov8/#supported-tasks-and-modes - - DOWNLOADS: - - N/A - -""" - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import os - -# To use YOLO architecture: -from ultralytics import YOLO - -# To work with images: -from PIL import Image - -# utils: -from utils_v2.string import json - -# Common: -from shared import constants - -# For debugging: -from icecream import IceCreamDebugger - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -class YoloDetect: - - def __init__( - self, - model_file, - debug = True, - debug_prefix = "YOLO | " - ): - - # Load the model: - self._model = YOLO(model = model_file) - - # Initialize the dbugging tool: - self._printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self._printer.disable() - - def disable_debug(self): - self._printer.disable() - - def enable_debug(self): - self._printer.enable() - - @staticmethod - def _process_result(raw_result): - - # Extract the various types of results available from the inference: - speed = {k: (v / 100.0) for k, v in raw_result.speed.items()} - class_mapping = raw_result.names - probabilities = raw_result.probs - boxes = raw_result.boxes - masks = raw_result.masks - - # Construct a default response: - response_json = { - "speed": speed, - "classes": class_mapping, - "boxes": None - } - - # Object-Detection results: - formatted_boxes = [] - for box in boxes: - detected_class = int(box.cls.numpy()[0]) - x1, y1, x2, y2 = box.xyxy[0] - formatted_boxes.append( - { - "class": detected_class, - "className": class_mapping[detected_class], - "confidence": float(box.conf.numpy()[0]), - "x1": int(x1.numpy()), - "y1": int(y1.numpy()), - "x2": int(x2.numpy()), - "y2": int(y2.numpy()) - } - ) - response_json["boxes"] = formatted_boxes - - # Done here: - return response_json - - def predict(self, image, show = False, verbose = False): - - # Process the input image with the given task: - results = self._model( - source = image, - show = show, - verbose = verbose - ) - - # Based on the task, interpret the results: - results_json = self._process_result(results[0]) - - # Done here: - return results_json - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - # model_file_path = os.path.join(constants.PROJECT_DIRECTORY, "ai", "yolo", "behaviour_models", "yolov8x.pt") - model_file_path = r"/home/developer/PycharmProjects/utils/data/ai/models/hugging_face/object_detection/YOLOv10-Document-Layout-Analysis/yolov10x_best.pt" - # sample_image_path = r"/home/developer/Downloads/2_cats.jpg" - sample_image_path = r"/home/developer/Downloads/flattened_image.jpg" - my_yolo = YoloDetect(model_file = model_file_path) - results = my_yolo.predict(image = Image.open(sample_image_path)) - print("FINAL RESULTS:", json.to_string(results)) - diff --git a/utils_v2/ai/tts/__init__.py b/utils_v2/ai/tts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/ai/tts/easy_tts.py b/utils_v2/ai/tts/easy_tts.py deleted file mode 100644 index fc4bb9b..0000000 --- a/utils_v2/ai/tts/easy_tts.py +++ /dev/null @@ -1,175 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Thursday, 26th Sept., 2024 - - OBJECTIVE: - - To provide a fast way to make audio from TTS engines. - - REFERENCES: - - 01. Usage: https://github.com/myshell-ai/MeloTTS/blob/main/docs/install.md#python-api - 02. Installation: https://github.com/myshell-ai/MeloTTS/blob/main/docs/install.md#linux-and-macos-install - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# To use the AI: -from melo.api import TTS -import numpy as np -import soundfile - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class EasyTTS: - - __sampling_rate = 44_100 - - def __init__( - self, - language = "EN", - speed = 1.0 - ): - - self.__audio = np.zeros(1) - self.__language = language - self.__speed = speed - self.__model = TTS(language = language, device = "auto") - self.__speakers = self.__model.hps.data.spk2id - - def list_speakers(self): - return list(self.__speakers.keys()) - - def speak( - self, - text, - speaker - ): - - this_audio = self.__model.tts_to_file( - text, - self.__speakers[speaker], - speed = self.__speed, - quiet = True - ) - - self.__audio = np.concatenate((self.__audio, this_audio)) - - def pause(self, seconds): - - self.__audio = np.concatenate(( - self.__audio, - np.zeros(int(self.__sampling_rate * seconds)) - )) - - def to_wav(self, path = None): - - if path is None: - audio_buffer = io.BytesIO() - soundfile.write(audio_buffer, self.__audio, self.__sampling_rate) - return audio_buffer - - else: soundfile.write(path, self.__audio, self.__sampling_rate) - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - speaker = "EN-BR" - tts_maker = EasyTTS(language = "EN", speed = 0.9) - - tts_maker.speak( - text = """ - Imagine delighting your doctors with a personalized calendar, - crafted from their own cherished memories. - """, - speaker = speaker - ) - tts_maker.pause(seconds = 0.3) - tts_maker.speak( - text = """ - Every day, as they turn the page, - they’ll not only relive those special moments but also remember you, - the one who made it happen. - """, - speaker = speaker - ) - tts_maker.pause(seconds = 0.75) - tts_maker.speak( - text = "STEP 1:", - speaker = speaker - ) - tts_maker.pause(seconds = 0.3) - tts_maker.speak( - text = "Start by identifying the doctors you’d like to engage with, and add them to our app.", - speaker = speaker - ) - tts_maker.pause(seconds = 0.3) - tts_maker.speak( - text = "No rush, you can add their photographs later as well.", - speaker = speaker - ) - tts_maker.pause(seconds = 0.3) - tts_maker.speak( - text = "With this, your engagement funnel is created.", - speaker = speaker - ) - - tts_maker.to_wav(r"/home/developer/Downloads/voiceover.wav") diff --git a/utils_v2/ai/tts/test.wav b/utils_v2/ai/tts/test.wav deleted file mode 100644 index d38cfc00b1dfaeac3bbc500cb2dea7b17deeca71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162150 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
  • =4x^Y`%c_@1yXzb&2;4e_k_ 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 diff --git a/utils_v2/api/__init__.py b/utils_v2/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/api/__pycache__/__init__.cpython-310.pyc b/utils_v2/api/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index f44186d9d0089262b43182fa8bd7b156153c914e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 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 HdHsI_Jb`PU diff --git a/utils_v2/api/__pycache__/codes.cpython-310.pyc b/utils_v2/api/__pycache__/codes.cpython-310.pyc deleted file mode 100644 index 47eef7c9e003e8a39553f6860780ee9120afd165..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3712 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 diff --git a/utils_v2/api/__pycache__/metrics_prometheus.cpython-310.pyc b/utils_v2/api/__pycache__/metrics_prometheus.cpython-310.pyc deleted file mode 100644 index 724908a216d73a378997428f0066c51893a99d87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5163 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 g0Dc?0SYC$1F*;WuH+%Md|E6U@4gdD+S str_limit: value = value[:str_limit] + "..." - - # Done here: - return value - - -# --------------------------------------------------------------------------------------------------------------------- - - -def set_api_version(api_version): - - """ - Use this decorator to automatically note down the API version no. and propagate it throughout the downstream - decorators. Use this as the entry point if possible. - :param api_version: The version code to assign to the API. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # set the version information in the variable. - # This makes it available to the downstream decorators too! - kwargs["api_version"] = api_version - - # we are ready to call the function that we are wrapping: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Add the API version to the response: - if isinstance(response, ResponseModel): response.api_version = api_version - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def read_input( - read_headers = True, - read_data = True, - read_files = True, - sanitize_headers = True, - sanitize_data = True -): - - """ - Use this decorator to read the inputs from the incoming request and sanitize them. Sanitization makes the inputs - safe against certain threats like injections attacks. If you expect to take in inputs that you want to use to run - database commands, you could disable them manually. - PLEASE USE "ResponseModel" AS THE RETURNED VALUE OF THE API ENDPOINT IF YOU ARE USING THIS DECORATOR. - :param read_headers: Whether, or not, to read the headers of the request. - :param read_data: Whether, or not, to read the data of the request. - :param read_files: Whether, or not, to read the files of the request. - :param sanitize_headers: Whether, or not, you would like to sanitize the params coming in through the headers. - :param sanitize_data: Whether, or not, you would like to sanitize the params coming in through the body or query. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Get the headers: - if read_headers: - kwargs["inbound_headers"] = await headers_from_request(request) - if sanitize_headers: kwargs["inbound_headers"] = sanitizers.for_mongo(kwargs["inbound_headers"]) - # else: kwargs["inbound_headers"] = None - - # Get the data: - if read_data: - kwargs["inbound_data"] = await data_from_request(request) - if sanitize_data: kwargs["inbound_data"] = sanitizers.for_mongo(kwargs["inbound_data"]) - # else: kwargs["inbound_data"] = None - - # Get small files from the request: - if read_files: kwargs["inbound_files"] = await files_from_request(request) - # else: kwargs["inbound_files"] = None - - # # We also make a provision for capturing an identifier - # # for the logs that we make through a sister decorator: - # kwargs["log_id"] = "".join(random.choice(ALPHANUMERIC_CHARS) for _ in range(8)) - # kwargs["log_chain"] = kwargs.get("inbound_headers", {}).get("X-Log-Chain") or kwargs["log_id"] - - # Now that we have unpacked the incoming data, - # we are ready to run the function that we are wrapping: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def get_session_info( - key: str, - model: str = None, - session_func: str = None, - session_coro: str = None, - get: str = None, - mandatory: bool = False, - sensitive_keys: List[str] = None -): - - """ - To get the information about the user from the session token or some similar identifier. Use this after - 'read_input', and note that the callable func/coro should only take on parameter - the thing to identify the session - by, and it should return a dictionary with all the needed details. - PLEASE USE "ResponseModel" AS THE RETURNED VALUE OF THE API ENDPOINT IF YOU ARE USING THIS DECORATOR. - :param key: The key in either the 'inbound_data' or the 'inbound_headers' from which the session info will be - available. Examples: 'sessionToken' or 'X-Session-Token'. - :param model: The object from which the func/coro should be called. This could be the name of the variable holding - an instance of a class. Should be available in the scope of 'current_app'. - :param session_func: The synchronous func of the model to call. This can either be an independent function or a - class's method. Should be available in the scope of 'current_app'. - :param session_coro: The asynchronous func of the model to call. This can either be an independent function or a - class's method. Ignored if 'func' was provided. Should be available in the scope of 'current_app'. - :param get: The field inside the dict to get. Specify this in dot notation. The whole response will be returned as - is if this is null. - :param mandatory: If set to True, the API call will enforce session checking; and if a session is not found, the - client will receive an unauthorized failure message. - :param sensitive_keys: Any keys to obscure when retrieving details about the session. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Start by assuming failure: - session_info = None - - # Get the identifier of the session from the values extracted in the 'read_input' decorator: - session_id = kwargs["inbound_data"].get(key, kwargs["inbound_headers"].get(key)) - - # If the key is present, - # we call the function that will get the session's info for us: - if session_id is not None: - - try: - - # For synchronous functions: - if session_func: - if model: session_info = getattr(getattr(current_app, model), session_func)(session_id) - else: session_info = getattr(current_app, session_func)(session_id) - - # For asynchronous coroutines: - elif session_coro: - if model: session_info = await getattr(getattr(current_app, model), session_coro)(session_id) - else: session_info = await getattr(current_app, session_coro)(session_id) - - # If something goes wrong: - except Exception as exception: - if hasattr(current_app, "printer"): getattr(current_app, "printer")(exception) - - # We note down whatever we got: - if session_info and isinstance(get, str): - for subkey in get.split("."): - session_info = session_info.get(subkey, {}) if isinstance(session_info, dict) else {} - session_info = summarize_variable(session_info, expand = True, sensitive_keys = sensitive_keys) - kwargs["session_info"] = session_info - - # If no session info was found, but it was mandatory: - if mandatory and not session_info: - response = ResponseModel( - status_code = StatusCodes.FAILED, - http_code = HttpCodes.UNAUTHORIZED, - message = f"invalid session" - ) - - # Now we are ready to run the function that we are wrapping: - else: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def validate_input( - mandatory_header_keys = None, - mandatory_data_keys = None, - mandatory_file_keys = None, - header_validator = None, - data_validator = None -): - - """ - USE THIS ONLY AFTER YOU HAVE USED 'read_input'. This decorator will help you run validation on the inputs that were - extracted from the request. The mandatory keys will be checked first and the validations will be run after that. If - your validator already checks for keys, you may skip mentioning mandatory keys. DO NOTE THAT YOUR VALIDATOR - FUNCTIONS MUST RAISE AN EXCEPTION FOR THIS DECORATOR TO WORK. - :param mandatory_header_keys: The keys in 'inbound_headers' that are absolutely necessary. - :param mandatory_data_keys: The keys in 'inbound_data' that are absolutely necessary. - :param mandatory_file_keys: The keys in 'inbound_files' that are absolutely necessary. - :param header_validator: The function to use to validate the 'inbound_headers'. - :param data_validator: The function to use to validate 'inbound_data'. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # We first validate the mandatory header keys. - # Having a null value in this case is NOT allowed: - if mandatory_header_keys is not None: - for mandatory_key in mandatory_header_keys: - if kwargs["inbound_headers"].get(mandatory_key) is None: - return ResponseModel( - status_code = StatusCodes.HEADERS_INCOMPLETE, - message = f"missing: '{mandatory_key}'" - ) - - # Return with failure if any of the mandatory JSON details are missing. - # Having a null value is allowed, but is should be sent by the user on intention. - if mandatory_data_keys is not None: - for mandatory_key in mandatory_data_keys: - try: kwargs["inbound_data"][mandatory_key] - except: return ResponseModel( - status_code = StatusCodes.DATA_INCOMPLETE, - message = f"missing: '{mandatory_key}'" - ) - - # Return with failure if any of the mandatory file-keys details are missing: - if mandatory_file_keys is not None: - provided_file_keys = kwargs["inbound_files"].keys() - for mandatory_key in mandatory_file_keys: - if mandatory_key not in provided_file_keys: - return ResponseModel( - status_code = StatusCodes.FILE_MISSING, - message = f"missing: '{mandatory_key}'" - ) - - # Next we validate the headers: - if header_validator is not None: - - # Try validate the data: - try: kwargs["inbound_headers"] = header_validator(kwargs["inbound_headers"]) - - # In case some needed field is missing: - except KeyError as exception: - return ResponseModel( - status_code = StatusCodes.DATA_VALIDATION_FAILURE, - message = "missing: " + str(exception), - http_code = HttpCodes.BAD_REQUEST, - ) - - # In case some pydantic data model fails validation: - except pydantic.ValidationError as exception: - return ResponseModel( - status_code = StatusCodes.DATA_VALIDATION_FAILURE, - message = messages_from_pydantic_exception(exception), - http_code = HttpCodes.BAD_REQUEST - ) - - # In case some other exception was raised: - except Exception as exception: - return ResponseModel( - status_code = StatusCodes.DATA_VALIDATION_FAILURE, - message = str(exception), - http_code = HttpCodes.BAD_REQUEST - ) - - # Finally, we validate the incoming data: - if data_validator is not None: - - # Try validate the data: - try: kwargs["inbound_data"] = data_validator(kwargs["inbound_data"]) - - # In case some needed field is missing: - except KeyError as exception: - return ResponseModel( - status_code = StatusCodes.DATA_VALIDATION_FAILURE, - message = "missing: " + str(exception), - http_code = HttpCodes.BAD_REQUEST - ) - - # In case some pydantic data model fails validation: - except pydantic.ValidationError as exception: - return ResponseModel( - status_code = StatusCodes.DATA_VALIDATION_FAILURE, - message = messages_from_pydantic_exception(exception), - http_code = HttpCodes.BAD_REQUEST - ) - - # In case some other exception was raised: - except Exception as exception: - return ResponseModel( - status_code = StatusCodes.DATA_VALIDATION_FAILURE, - message = str(exception), - http_code = HttpCodes.BAD_REQUEST - ) - - # Now that we have unpacked the incoming data, - # we are ready to run the function that we are wrapping: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def log_request_to_mongo( - attr_name, - collection: str = "logs", - api_version: str = None, - project: str = None, - log_type: str = None, - operation: str = None, - log_input: bool | int = True, - log_output: bool | int = True, - sensitive_keys: list = None -): - - """ - USE THIS ONLY AFTER YOU HAVE USED 'read_input'. This decorator will log the whole process of the API call to - MongoDB. The variable that holds the instance of 'AsyncMongo' needs to be accessible in the scope of 'current_app'. - PLEASE USE "ResponseModel" AS THE RETURNED VALUE OF THE API ENDPOINT IF YOU ARE USING THIS DECORATOR. - :param attr_name: The name of the variable that holds the instance of 'AsyncMongo'. It should be accessible in the - scope of 'current_app'. - :param collection: The name of the collection to write the log into. - :param api_version: The version code of the API endpoint that is being logged. - :param project: The name of the project that the endpoint was built for. - :param log_type: A hint to identify what the log was for. - :param operation: A hint to identify what was action was being performed. - :param log_input: Set to True to capture everything that went into the function, False to capture the least - info, and set it to an integer to capture a certain depth of the input (applicable on iterables and dicts. - :param log_output: The same as 'log_input', but applicable to the response from the function. - :param sensitive_keys: The list of keys to not log. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Create ids for getting logs: - kwargs["log_id"] = "".join(random.choice(ALPHANUMERIC_CHARS) for _ in range(8)) - kwargs["log_chain"] = kwargs.get("inbound_headers", {}).get("X-Log-Chain") or kwargs["log_id"] - - # Set the api version as needed: - kwargs["api_version"] = kwargs.get("api_version", api_version) - - # Make variables and extract available info.: - exception = None - response = None - request_ts = date_time.get_current_utc_date_time() - start_ts = time.perf_counter() - cpu_start_ts = time.process_time() - - # Execute the function that is being wrapped: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - try: response = await func(*args, **kwargs) - except Exception as exc: exception = exc - kwargs["decorator_count"] -= 1 - - # Ensure that the response is not null: - response = response if response is not None else ResponseModel( - status_code = StatusCodes.UNKNOWN_ERROR, - message = "null response for request" - ) - - # Add params to the response. - # THIS IS ONLY APPLICABLE WHEN THE TYPE OF THE RESPONSE IS 'ResponseModel': - if isinstance(response, ResponseModel): - response.api_version = kwargs.get("api_version") - response.log_id = kwargs.get("log_id") - - # Extract the response to log: - response_to_log = "not logged" - http_code_to_log = 200 - if log_output: - if isinstance(response, ResponseModel): response_to_log, http_code_to_log = response.for_quart() - elif isinstance(response, tuple): response_to_log, http_code_to_log = response - else: response_to_log, http_code_to_log = str(response), 200 - response_to_log = summarize_variable( - response_to_log, - expand = log_output, - sensitive_keys = sensitive_keys - ) - - # Try to get the information about the request. - # There will be no data in any of these if the decorator was used to catch start-up and shut-down events. - request_method = None - request_url = None - request_route = None - try: - request_method = f"{request.method}" - request_url = f"{request.url}" - request_route = str(request.url_rule.rule) - except: pass - - # Redact the sensitive keys: - if sensitive_keys: - for k in sensitive_keys: - for var in ["inbound_headers", "inbound_data"]: - try: kwargs[var][k] = len(str(kwargs[var][k])) * "*" - except: pass - - # Construct the log: - api_log = APILogModel( - pid = PROCESS_ID, - ppid = PARENT_PROCESS_ID, - project = project, - log = log_type, - operation = operation, - apiVer = kwargs.get("api_version"), - logId = kwargs.get("log_id"), - logChain = kwargs.get("log_chain", kwargs.get("inbound_headers", {}).get("X-Log-Chain")), - ts = request_ts, - tat = time.perf_counter() - start_ts, - cpuTime = time.process_time() - cpu_start_ts, - sessionInfo = kwargs.get("session_info"), - method = request_method, - url = request_url, - route = request_route, - headers = kwargs.get("inbound_headers"), - data = summarize_variable( - kwargs.get("inbound_data"), - expand = log_input, - sensitive_keys = sensitive_keys - ), - files = { - k: { - "name": v["name"], - "size": v["size"] - } for k, v in kwargs.get("inbound_files", {}).items() - }, - exception = None if exception is None else describe_exception(exception), - response = response_to_log, - httpCode = http_code_to_log - ) - - # Write the log: - app_attr = getattr(current_app, attr_name) - inserted_id = await app_attr.insert_one( - collection = collection, - document = api_log.model_dump() - ) - - # Return the response from the wrapped function. - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def log_chain_to_mongo(attr_name): - - """ - Use this to run everything in the context of the logging decorator. Everything that is decorated with the - custom decorator will be logged if this is used. - :param attr_name: The name of the db connection (an instance of 'AsyncMongo' or 'AsyncMongoStorage') - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Let the next in-line decorator know that it has been wrapped: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - - # Fetch the attribute and get it to log the whole chain: - async with AsyncLoggerContext.logging_context( - logger = AsyncMongoLogger(getattr(current_app, attr_name)), - log_chain = kwargs.get("log_chain") - ): - response = await func(*args, **kwargs) - - # Done here: - kwargs["decorator_count"] -= 1 - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def should_not_be_under_maintenance(attr_name): - - """ - Use this decorator to reject a request when the app is being marked as "under-maintenance". You will need to create - a boolean variable within the scope of the 'current_app' for this to work. An alternate to this is to set the value - in an environment variable named 'IS_UNDER_MAINTENANCE' to a string value of either 'True' or 'False' for - multi-worker deployments. - :param attr_name: The name of the boolean variable that will hold the information about the app being under - maintenance. If its value is True at the time of checking, the incoming request will be rejected. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Get the attribute and check if it indicates that the app is under maintenance, - # call the wrapped function if not under maintenance: - app_attr = getattr(current_app, attr_name) - env_attr = True if os.environ.get("IS_UNDER_MAINTENANCE", "False").lower() == "true" else False - if app_attr or env_attr: - response = ResponseModel(status_code = StatusCodes.DOWN_FOR_MAINTENANCE).for_quart() - else: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def only_whitelisted_ips(attr_name): - - """ - Use this decorator to reject any requests coming from unauthorized IPs. The list of IP addresses to allow must be - in a list that is accessible in the context of 'current_app'. - :param attr_name: The name of the boolean variable that will hold the information about the app being under - maintenance. If its value is True at the time of checking, the incoming request will be rejected. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Get the attribute and check if the request's IP is in the permitted list: - app_attr = getattr(current_app, attr_name) - if request.remote_addr not in app_attr: - return ResponseModel( - status_code = StatusCodes.AUTHORIZATION_FAILED, - message = "bad ip", - http_code = HttpCodes.UNAUTHORIZED - ).for_quart() - - # Now that we have checked that the IP is permitted, - # we are ready to run the function that we are wrapping: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def limit_rate( - attr_name, - rate_limit: int = 5, - seconds: float = 1.0, - message = None, - header_keys: list = None, - data_keys: list = None, - allow_if_exception = False, - count_for_http_codes = None -): - - """ - Use this decorator to apply rate-limiting to incoming requests. - SUGGESTION: WHEN STACKING UP MANY RATE LIMITS, PUT THE SMALLEST TIME PERIOD ON TOP AND LARGEST TIME PERIOD AT THE - BOTTOM. THIS ENSURES PROPER FUNCTIONALITY. - WARNING: TIMING STARTS WHEN THE FIRST PERMITTED REQUEST GOES THROUGH. THIS MEANS THAT, IF YOU HAVE A PER-DAY LIMIT, - AND YOU START MAKING REQUESTS AT 11:00 PM AND EXHAUST YOUR LIMIT AT 11:59 PM, YOUR LIMIT WILL BE REPLENISHED AT - 11:00 PM OF THE NEXT DAY, NOT AT 12:00 AM. - :param attr_name: The name of the variable that holds the instance of 'AsyncRedisCache'. Should be available in the - context of 'current_app'. - :param rate_limit: The number of requests per unit time. - :param seconds: The time period in which the rate limit is to be applied. - :param message: The custom message to respond with. - :param header_keys: The keys in the header to consider when apply rate limits (like 'sessionToken'). - :param data_keys: The keys in the header to consider when apply rate limits (like 'sessionToken'). - :param allow_if_exception: In case Redis is unresponsive, would you prefer allowing the request to pass through or - would you prefer the request getting blocked. - :param count_for_http_codes: If this is provided, the counter will be incremented only if the response code was one - of these values. If not provided, all requests will be counted. This can be used in cases when you want to count - only when the request was successfully served. - :return: The decorator factory. - """ - - # Param-cleaning: - rate_limit = max(1, rate_limit) - if header_keys is None: header_keys = [] - if data_keys is None: data_keys = [] - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Note down the combination of values requested and the limits prescribed: - params = {"route": str(request.url_rule), "header": {}, "data": {}, "limit": rate_limit, "seconds": seconds} - for key in header_keys: params["header"][key] = kwargs["inbound_headers"].get(key) - for key in data_keys: params["data"][key] = kwargs["inbound_data"].get(key) - - # Now make a unique key from this combination: - params_json = json.to_string(params, no_space = True) - sha256_hash = hashlib.sha256() - sha256_hash.update(params_json.encode("utf-8")) - hashed_key = sha256_hash.digest() - base64_key = base64.b64encode(hashed_key).decode("utf-8") - - # We first get the value of the counter: - app_attr = getattr(current_app, attr_name) - counter_value = await app_attr.count(base64_key, value = 1, expiry = seconds) - - # If any exception occurred in getting the count, - # and exceptions haven't been allowed: - if counter_value is None and not allow_if_exception: - response = ResponseModel( - status_code = StatusCodes.RATE_LIMIT_EXCEEDED, - message = "Please contact admin (E)" - ) - - # If the rate-limit has already been crossed, - # or when the counter was not fetched but exceptions are allowed: - elif (counter_value or 0) > rate_limit: - response = ResponseModel( - status_code = StatusCodes.RATE_LIMIT_EXCEEDED, - message = message or ", ".join([ - f"rate limit: {rate_limit} in {humanize.naturaldelta(datetime.timedelta(seconds = seconds))}", - f"this is your {humanize.ordinal(counter_value)} request in the given period" - ]) - ) - - # If the rate-limit hasn't been crossed: - else: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # If we have been told to count only for specific status codes, - # and if the HTTP code of this response is not in the list of codes, we reduce the counter by one: - if count_for_http_codes: - http_code = 200 # ... Default assumption. - if isinstance(response, (list, tuple, set)): http_code = response[1] - elif isinstance(response, ResponseModel): http_code = response.http_code.value - if http_code not in count_for_http_codes: - await app_attr.count(base64_key, value = -1, expiry = seconds) - - # Return the response from the function call: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def handle_cancelled_request(cleanup_func = None, cleanup_coro = None): - - """ - Use this decorator to handle prematurely terminated requests. If your clean-up function needs access to variables, - consider using 'g' to hold data in the scope of the request. - :param cleanup_func: The function to call when the cancelled request needs graceful handling. - :param cleanup_coro: The coroutine to call when the cancelled request needs graceful handling. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - try: - - # we are ready to run the function that we are wrapping: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - # In case the client closes the connection pre-maturely: - except asyncio.CancelledError as exception: - kwargs["decorator_count"] -= 1 - if hasattr(current_app, "printer"): getattr(current_app, "printer")(exception) - if cleanup_func is not None: cleanup_func() - if cleanup_coro is not None: await cleanup_coro() - return ResponseModel( - api_version = kwargs.get("api_version"), - status_code = StatusCodes.CLIENT_CLOSED_REQUEST - ).for_quart() - - # We propagate any other kind of exception: - except Exception as exception: - kwargs["decorator_count"] -= 1 - raise - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def handle_failed_request(cleanup_func = None, cleanup_coro = None): - - """ - Use this decorator to handle requests that fail due to exceptions. If your clean-up function needs access to - variables, consider using 'g' to hold data in the scope of the request. THIS DECORATOR IS NOT MEANT TO SUPRESS - EXCEPTIONS. IT IS, INSTEAD, MEANT TO PERFORM CLEAN-UP AND PROPAGATE THE EXCEPTION. - :param cleanup_func: The function to call when the cancelled request needs graceful handling. - :param cleanup_coro: The coroutine to call when the cancelled request needs graceful handling. - :return: The decorator factory. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - try: - - # we are ready to run the function that we are wrapping: - kwargs["decorator_count"] = kwargs.get("decorator_count", 0) + 1 - response = await func(*args, **kwargs) - kwargs["decorator_count"] -= 1 - - # Done here: - if ( - kwargs["decorator_count"] == 0 and - isinstance(response, ResponseModel) - ): response = response.for_quart() - return response - - # In case the client closes the connection pre-maturely: - except Exception as exception: - kwargs["decorator_count"] -= 1 - if hasattr(current_app, "printer"): getattr(current_app, "printer")(exception) - if cleanup_func is not None: cleanup_func() - if cleanup_coro is not None: await cleanup_coro() - raise exception - - return wrapper - - return decorator - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/api/codes.py b/utils_v2/api/codes.py deleted file mode 100644 index 5773cc9..0000000 --- a/utils_v2/api/codes.py +++ /dev/null @@ -1,164 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Thursday, 12th Sept., 2024 - - OBJECTIVE: - - To maintain all status codes in one place. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -from enum import Enum, unique - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -@unique -class HttpCodes(Enum): - - """ - Commonly used standard HTTP status codes. - Can be sent after an API Call is processed. - Refer to: https://http.dev/status - NOTE: THIS LIST IS NOT EXHAUSTIVE! - """ - - # 1XX - Informational: - CONTINUE = 100 # .............. https://http.dev/102 - SWITCHING_PROTOCOLS = 101 # ... https://http.dev/101 - PROCESSING = 102 # ............ https://http.dev/102 - EARLY_HINTS = 103 # ........... https://http.dev/103 - - # 2XX - Success: - SUCCESS = 200 # .................. https://http.dev/200 - CREATED = 201 # .................. https://http.dev/201 - ACCEPTED = 202 # ................. https://http.dev/202 - NON_AUTHORITATIVE_INFO = 203 # ... https://http.dev/203 - NO_CONTENT = 204 # ............... https://http.dev/204 - RESET_CONTENT = 205 # ............ https://http.dev/205 - PARTIAL_CONTENT = 206 # .......... https://http.dev/206 - MULTI_STATUS = 207 # ............. https://http.dev/207 - ALREADY_REPORTED = 208 # ......... https://http.dev/208 - THIS_IS_FINE = 218 # ............. https://http.dev/218 - IM_USED = 226 # .................. https://http.dev/226 - - # 3XX - Redirection: - MULTIPLE_CHOICES = 300 # ..... https://http.dev/300 - MOVED_PERMANENTLY = 301 # .... https://http.dev/301 - MOVED_TEMPORARILY = 302 # .... https://http.dev/302 - SEE_OTHER = 303 # ............ https://http.dev/303 - NOT_MODIFIED = 304 # ......... https://http.dev/304 - USE_PROXY = 305 # ............ https://http.dev/305 - SWITCH_PROXY = 306 # ......... https://http.dev/306 - TEMPORARY_REDIRECT = 307 # ... https://http.dev/307 - PERMANENT_REDIRECT = 308 # ... https://http.dev/308 - - # 4XX - Client Errors: - BAD_REQUEST = 400 # ..................... https://http.dev/401 - UNAUTHORIZED = 401 # .................... https://http.dev/401 - PAYMENT_REQUIRED = 402 # ................ https://http.dev/402 - FORBIDDEN = 403 # ....................... https://http.dev/403 - NOT_FOUND = 404 # ....................... https://http.dev/404 - METHOD_NOT_ALLOWED = 405 # .............. https://http.dev/405 - NOT_ACCEPTABLE = 406 # .................. https://http.dev/406 - PROXY_AUTH_REQUIRED = 407 # ............. https://http.dev/407 - REQUEST_TIMEOUT = 408 # ................. https://http.dev/408 - CONFLICT = 409 # ........................ https://http.dev/409 - GONE = 410 # ............................ https://http.dev/410 - LENGTH_REQUIRED = 411 # ................. https://http.dev/411 - PRECONDITION_FAILED = 412 # ............. https://http.dev/412 - PAYLOAD_TOO_LARGE = 413 # ............... https://http.dev/413 - URI_TOO_LONG = 414 # .................... https://http.dev/414 - UNSUPPORTED_MEDIA_TYPE = 415 # .......... https://http.dev/415 - PAGE_EXPIRED = 419 # .................... https://http.dev/419 - TOO_MANY_REQUESTS = 429 # ............... https://http.dev/429 - UNAVAILABLE_FOR_LEGAL_REASONS = 451 # ... https://http.dev/451 - INVALID_TOKEN = 498 # ................... https://http.dev/498 - CLIENT_CLOSED_REQUEST = 499 # ........... https://http.dev/499 - - # 5XX - Server Errors: - INTERNAL_SERVER_ERROR = 500 # ........... https://http.dev/500 - NOT_IMPLEMENTED = 501 # ................. https://http.dev/501 - BAD_GATEWAY = 502 # ..................... https://http.dev/502 - SERVICE_UNAVAILABLE = 503 # ............. https://http.dev/503 - GATEWAY_TIMEOUT = 504 # ................. https://http.dev/504 - HTTP_VERSION_NOT_SUPPORTED = 505 # ...... https://http.dev/505 - VARIANT_ALSO_NEGOTIATES = 506 # ......... https://http.dev/506 - INSUFFICIENT_STORAGE = 507 # ............ https://http.dev/507 - LOOP_DETECTED = 508 # ................... https://http.dev/508 - BANDWIDTH_LIMIT_EXCEEDED = 509 # ........ https://http.dev/509 - WEB_SERVER_DOWN = 521 # ................. https://http.dev/521 - ORIGIN_IS_UNREACHABLE = 523 # ........... https://http.dev/523 - SERVICE_IS_OVERLOADED = 529 # ........... https://http.dev/529 - NETWORK_READ_TIMEOUT_ERROR = 598 # ...... https://http.dev/598 - NETWORK_CONNECT_TIMEOUT_ERROR = 599 # ... https://http.dev/599 - - -# --------------------------------------------------------------------------------------------------------------------- - - -@unique -class StatusCodes(Enum): - - """ - To be used internally within the context of your service. Customize these to match your service. - The format is: (SUCCESS_INDICATOR, INTERNAL_NUMERIC_CODE, HTTP_CODE) - Example: (True, 1, 200) - """ - - # Legacy Codes: - OK = (True, 1, HttpCodes.SUCCESS.value) - FAILED = (False, 0, HttpCodes.INTERNAL_SERVER_ERROR.value) - PARTIAL_SUCCESS = (True, 2, HttpCodes.PARTIAL_CONTENT.value) - PARTIAL_FAILURE = (False, 3, HttpCodes.PARTIAL_CONTENT.value) - - # Authentication Codes: - LOGGED_IN_SUCCESSFULLY = (True, 200, HttpCodes.SUCCESS.value) - LOGIN_FAILED = (False, 201, HttpCodes.UNAUTHORIZED.value) - INVALID_SESSION_TOKEN = (False, 202, HttpCodes.UNAUTHORIZED.value) - AUTHENTICATION_DETAILS_INCOMPLETE = (False, 203, HttpCodes.BAD_REQUEST.value) - - # Authorization Codes: - AUTHORIZED_SUCCESSFULLY = (True, 300, HttpCodes.SUCCESS.value) - NOT_ALLOWED = (False, 301, HttpCodes.FORBIDDEN.value) - AUTHORIZATION_DETAILS_INCOMPLETE = (False, 302, HttpCodes.BAD_REQUEST.value) - AUTHORIZATION_FAILED = (False, 303, HttpCodes.UNAUTHORIZED.value) - - # General failures: - DOWN_FOR_MAINTENANCE = (False, 800, HttpCodes.SERVICE_UNAVAILABLE.value) - UNKNOWN_ERROR = (False, 801, HttpCodes.INTERNAL_SERVER_ERROR.value) - DATA_INCOMPLETE = (False, 802, HttpCodes.BAD_REQUEST.value) - HEADERS_INCOMPLETE = (False, 803, HttpCodes.BAD_REQUEST.value) - FILES_MISSING = (False, 804, HttpCodes.BAD_REQUEST.value) - CLIENT_CLOSED_REQUEST = (False, 805, HttpCodes.CLIENT_CLOSED_REQUEST.value) - - # Validation failure: - DATA_VALIDATION_FAILURE = (False, 900, HttpCodes.BAD_REQUEST.value) - RATE_LIMIT_EXCEEDED = (False, 901, HttpCodes.TOO_MANY_REQUESTS.value) diff --git a/utils_v2/api/log.py b/utils_v2/api/log.py deleted file mode 100644 index 49ccd77..0000000 --- a/utils_v2/api/log.py +++ /dev/null @@ -1,139 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Thursday, 12th Sept., 2024 - - OBJECTIVE: - - To have a structure to the response sent from the API calls. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# System-level activities: -import distro -import socket -import platform - -# For data-modelling: -from pydantic import BaseModel, Field -from typing import Any, Optional, List, Literal - -# To work with date and time: -import datetime - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# Info for logging that will stay constant during runtime: -SERVER_HOSTNAME = str(socket.gethostname()) -PLATFORM_INFO = platform.uname() -HOST_OS = str(distro.name(True)) -HOST_CPU = f"{PLATFORM_INFO.processor} ({PLATFORM_INFO.machine})" - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class APILogModel(BaseModel): - - # To identify the machine the code is running on. - # DO NOT MODIFY THESE: - hostname: str = SERVER_HOSTNAME - os: str = HOST_OS - cpu: str = HOST_CPU - # Can modify these: - pid: Optional[Any] = None - ppid: Optional[Any] = None - - # To identify the project and actions: - project: Optional[str] = None - log: str - operation: str - apiVer: Optional[str] = None - logId: Optional[str] = None - logChain: Optional[str] = None - - # Timing metrics: - ts: datetime.datetime - tat: float - cpuTime: float - - # To understand the request that came in: - sessionInfo: Optional[Any] = None - method: Optional[str] = None - url: Optional[str] = None - route: Optional[str] = None - headers: Optional[Any] = None - data: Optional[Any] = None - files: Optional[Any] = None - - # To understand the output that went out: - exception: Optional[Any] = None - response: Optional[Any] = None - httpCode: Optional[int] = None - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - my_log = APILogModel( - log = "internal" - ) - - print(my_log) diff --git a/utils_v2/api/response.py b/utils_v2/api/response.py deleted file mode 100644 index 02e3d72..0000000 --- a/utils_v2/api/response.py +++ /dev/null @@ -1,133 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Thursday, 12th Sept., 2024 - - OBJECTIVE: - - To have a structure to the response sent from the API calls. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# For data-modelling: -from pydantic import BaseModel -from typing import Any, Optional, List - -# My utils: -from utils_v2.api.codes import StatusCodes, HttpCodes - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class ResponseModel(BaseModel): - - """ - A model for how the response should be when developing API endpoints. - """ - - # The fields that you want in your response: - status_code: StatusCodes - message: Optional[str | List] = None - data: Optional[Any] = None - seconds: Optional[float | int] = None - log_id: Optional[str] = None - http_code: Optional[HttpCodes] = None - api_version: Optional[str] = None - - def for_quart(self): - - """ - Call this when you are using either Flask or Quart as your framework. - :return: The output as expected by Flask and Quart. - """ - - # Construct the basic structure: - response_dict = { - "status": 1 if self.status_code.value[0] else 0, - "code": self.status_code.value[1], - "message": self.message or self.status_code.name.replace("_", " ").lower(), - "data": self.data, - "apiVer": self.api_version - } - - # Now add the additional fields: - if self.seconds is not None: response_dict["seconds"] = self.seconds - if self.log_id is not None: response_dict["logId"] = self.log_id - - # Figure out the HTTP code: - response_http_code = self.http_code.value if self.http_code is not None else self.status_code.value[2] - - # Done here: - return response_dict, response_http_code - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - my_response = ResponseModel( - status_code = StatusCodes.RATE_LIMIT_EXCEEDED - ) - my_response.log_id = "abc123" - - print(my_response.for_quart()) diff --git a/utils_v2/cache/__init__.py b/utils_v2/cache/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/cache/__pycache__/__init__.cpython-310.pyc b/utils_v2/cache/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index b168cc850596affdce0ed0cd7af9dc4af6a49b13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168 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 self.__ping_counter: - try: - await self.__client.ping() - self.__requests_since_last_ping = 0 - return True - except Exception as exception: - self.__printer(exception) - return await self.connect() - else: - self.__requests_since_last_ping += 1 - return True - - async def set(self, key, value, expiry: float = 120, raise_exception = False): - - """ - Saves some value to the cache. - :param key: The key with which the data will be stored and retrieved. - :param value: The value to store. - :param expiry: The time in seconds after which the data will expire. Must be a positive number. - :param raise_exception: If you want to raise an exception if the process fails. - :return: True if cached, else False. - """ - - await self.ensure_connection() - - try: - - # We handle conversion for unsupported Pythonic datatypes: - original_type = type(value).__name__ - converter = self.__set_converters.get(original_type) - if converter is not None: value = converter(value) - - # Here we actually try to store the data: - response = await self.__client.setex( - key, - int(expiry), - json.to_string({ - "value": value, - "type": original_type - }, indent = 0, no_space = False) - ) - return response - - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return False - - async def get(self, key, raise_exception = False, on_fail = None): - - """ - Retrieve the cached value. - :param key: The key with which the data was saved. - :param raise_exception: If you want to raise an exception if the process fails. - :param on_fail: What to return if the process fails due to an exception. - :return: The retrieved data or null if not found. - """ - - await self.ensure_connection() - - try: - data = await self.__client.get(key) - data = data.decode("utf-8") - data = json.from_string(data) - converter = self.__get_converters.get(data["type"]) - if converter is not None: return converter(data["value"]) - return data["value"] - - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return on_fail - - async def delete(self, key, raise_exception = False): - - """ - Prematurely delete the value from the cache before it expires. - :param key: The key with which the data was saved. - :param raise_exception: If you want to raise an exception if the process fails. - :return: True if deleted, else False. - """ - - await self.ensure_connection() - - try: - response = await self.__client.delete(key) - return True if response else False - - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return False - - async def count(self, key, value: int = 1, expiry: float = None, raise_exception = False): - - """ - To use simple counters. If the counter (identified by the 'key') exists, it will be incremented, else the - counter will be created and the value will be incremented from 0. - :param key: The name of the counter. - :param value: The amount to increment the value by. Send negative values to count backwards. - :param expiry: The time (in seconds) in which the counter expires. Starts from the time the counter is created. - This value has to be an integer. If a float is passed, the value will be rounded off. - :param raise_exception: If you want to raise an exception if the process fails. - :return: The latest value of the counter. Will be null if something went wrong and the exception was suppressed. - """ - - await self.ensure_connection() - - try: - - already_existed = await self.__client.exists(key) - new_value = await self.__client.incrby(key, value) - if expiry and not already_existed: await self.__client.expire(key, int(expiry)) - return new_value - - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return None - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - - def set_complex(x): - return {"r": x.real, "i": x.imag} - - def get_complex(x): - return complex(x["r"], x["i"]) - - async def main(): - - my_cache = AsyncRedisCache( - connection_string = r"redis://:dc4da94197c843ab6a730113c2b801d9@redis.ditscentre.in/0", - ping_counter = 100, - debug = False - ) - - my_cache.add_converter( - type_name = type(2j).__name__, - set_converter_func = set_complex, - get_converter_func = get_complex - ) - - value = await my_cache.get(key = "6b61afd0-b066-4611-9791-411a30d34624") - print("GET:", value) - print("TYP:", type(value), end = "\n\n") - - # success = await my_cache.set( - # key = "name", - # value = {"first": "John", "last": "Doe"}, - # expiry = 10 - # ) - # print("SET:", success, end = "\n\n") - # - # value = await my_cache.get(key = "name") - # print("GET:", value) - # print("TYP:", type(value), end = "\n\n") - # - # success = await my_cache.delete(key = "name") - # print("DEL:", success, end = "\n\n") - # - # value = await my_cache.get(key = "cnt") - # print("GET:", value) - # print("TYP:", type(value), end = "\n\n") - # - # await my_cache.delete(key = "cnt") - # for _ in range(50): - # await asyncio.sleep(1.0) - # counter = await my_cache.count(key = "cnt", value = 1, expiry = 10) - # print("COUNTER:", counter) - - asyncio.run(main()) diff --git a/utils_v2/cache/async_redis_cache_v2.py b/utils_v2/cache/async_redis_cache_v2.py deleted file mode 100644 index 0192dae..0000000 --- a/utils_v2/cache/async_redis_cache_v2.py +++ /dev/null @@ -1,568 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Saturday, 26th Oct., 2024 - - OBJECTIVE: - - To provide an easy way to cache data for fast access. This version has the change that it can handle custom - serializers by way of dependency injection. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To use redis: -import redis.asyncio as redis - -# Other utils: -from utils_v2.string import json -from utils_v2.serialization.pickle_serializer import PickleSerializer - -# For debugging: -from icecream import IceCreamDebugger - -# To make a decorator: -from functools import wraps - -# For hashing and shortening the hash: -import hashlib -import base64 - -# To work with datatypes: -from typing import List, Any - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** WRAPPERS *** -# ***** **** -# ***************************************************************************************************************** - - -def cache_it(cache = None, expiry = 120): - - """ - This decorator factory takes an instance of the async caching class 'AsyncRedisCache' and holds your data there. - If a subsequent call is made to the same decorated function with the same inputs, the result is fetched from the - cache instead of going through the whole function again. - :param cache: The instance of 'AsyncRedisCache'. - :param expiry: The time in seconds after which the cached data must be cleared. - :return: The decorator that automatically caches your data. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # We first use the name of the function and the inputs given to it to generate a key for Redis with the - # simple hashing and shortening by way of base64 strings: - inputs_given = func.__name__ + str([_ for _ in args]) + str(kwargs) - sha256_hash = hashlib.sha256() - sha256_hash.update(inputs_given.encode("utf-8")) - hashed_key = sha256_hash.digest() - base64_key = base64.b64encode(hashed_key).decode("utf-8") - - # Now we check if we have the value in cache: - try: response = await cache.get(base64_key, raise_exception = True) - - # If the key doesn't exist, we pass through the function and store the results. - except: - response = await func(*args, **kwargs) - await cache.set(key = base64_key, value = response, expiry = expiry) - - # Return the response from the wrapped function. - return response - - return wrapper - - return decorator - - -# --------------------------------------------------------------------------------------------------------------------- - - -def cache_class_methods(attr_name, expiry = 120): - - """ - This decorator factory takes an instance of the async caching class 'AsyncRedisCache' and holds your data there. - If a subsequent call is made to the same decorated function with the same inputs, the result is fetched from the - cache instead of going through the whole function again. - :param attr_name: The name of the variable that has an instance of "AsyncRedisCache". - :param expiry: The time in seconds after which the cached data must be cleared. - :return: The decorator that automatically caches your data. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(self, *args, **kwargs): - - # Get the cache object first: - cache_obj = getattr(self, attr_name) - - # We first use the name of the function and the inputs given to it to generate a key for Redis with the - # simple hashing and shortening by way of base64 strings: - inputs_given = func.__name__ + str([_ for _ in args]) + str(kwargs) - sha256_hash = hashlib.sha256() - sha256_hash.update(inputs_given.encode("utf-8")) - hashed_key = sha256_hash.digest() - base64_key = base64.b64encode(hashed_key).decode("utf-8") - - # Now we check if we have the value in cache: - try: response = await cache_obj.get(base64_key, raise_exception = True) - - # If the key doesn't exist, we pass through the function and store the results. - except: - response = await func(self, *args, **kwargs) - await cache_obj.set(key = base64_key, value = response, expiry = expiry) - - # Return the response from the wrapped function. - return response - - return wrapper - - return decorator - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncRedisCache: - - def __init__( - self, - connection_string, - serializer = None, - ping_counter = 1_000, - debug = False, - debug_prefix = "R-Cache | " - ): - - """ - Implements a simple cache in Redis which holds and returns all native datatypes like ints, floats, bools, - strings, dicts, lists, sets, and tuples :) - :param connection_string: The connection URL for connecting to Redis. - :param serializer: The serializer to use. - :param ping_counter: The number of requests to Redis after which you want to ping to ensure connection. - :param debug: Whether, or not, you want to show debugging messages from the start. - :param debug_prefix: The prefix text to show with the debugging messages. - """ - - # Note down the configuration: - self.__client = None - self.__serializer = serializer or PickleSerializer() - self.__ping_counter = ping_counter - self.__requests_since_last_ping = 0 - self.__connection_string = connection_string - - # For debugging: - self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self.__printer.disable() - - def enable_debug(self): - self.__printer.enable() - - def disable_debug(self): - self.__printer.disable() - - @staticmethod - def make_key(*args, **kwargs) -> str: - - """ - Generates a key by hashing the args and kwargs sent to it. Can be useful to generate a predictable key. If the - inputs stay the same, the output stays the same. - :param args: Any number of args that you would like to use to generate the key. - :param kwargs: Any number of kwargs that you would like to use to generate the key. - :return: A string that can be used as a key to store values on Redis. - """ - - # Take everything into one plain text string: - plain_text = "".join(str(a) for a in args) - plain_text += json.to_string(kwargs, no_space = True) - - # Hash the plain text value, and create a key from it: - sha256_hash = hashlib.sha256() - sha256_hash.update(plain_text.encode("utf-8")) - hashed_key = sha256_hash.digest() - base64_key = base64.b64encode(hashed_key).decode("utf-8") - - # Done here: - return base64_key - - async def connect(self) -> bool: - - """ - To make an asynchronous connection request to the Redis server to establish a connection. - :return: True if connected, else False. - """ - - try: - self.__client = redis.from_url( - self.__connection_string - ) - return True - - except Exception as exception: - self.__printer(exception) - return False - - async def disconnect(self) -> bool: - - """ - Close the connection to the Redis server. - :return: True if successful, else False. - """ - - if self.__client is not None: - try: await self.__client.close() - except Exception as exception: - self.__printer(exception) - return False - return True - return True - - async def ensure_connection(self) -> bool: - - """ - To ensure that we are connected. We keep pinging the Redis server every once in a while even when connected. - :return: True if connected, else False. - """ - - # If we are not connected, we try to establish a connection: - if self.__client is None: return await self.connect() - - # Else we check if we are connected. If not, we try to connect. - # But we check only once in a while. In the meantime, we assume that we are connected. - elif self.__requests_since_last_ping > self.__ping_counter: - try: - await self.__client.ping() - self.__requests_since_last_ping = 0 - return True - except Exception as exception: - self.__printer(exception) - return await self.connect() - else: - self.__requests_since_last_ping += 1 - return True - - async def list_keys( - self, - match: str = "*", - raise_exception: bool = False - ) -> List[str] | None: - - """ - To get a list of all the keys that match the pattern. - :param match: To match a glob-style pattern. THIS IS NOT FULL-FLEDGED REGEX. - :param raise_exception: If you want to raise an exception if the process fails. - :return: The list of keys if successful, else None. - """ - - # Standard connectivity check: - await self.ensure_connection() - - # Start with an empty list: - keys_list = [] - - try: - - # Start at the beginning, - # and break out of the loop if the pointer returns to zero: - pointer = 0 - while True: - pointer, keys = await self.__client.scan(pointer, match = match) - keys_list = keys_list + [k.decode("utf-8") for k in keys] - if pointer == 0: break - - # Done here: - return list(set(keys_list)) if keys_list else None - - # If an exception occurs in th eprocess: - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return None - - async def ttl( - self, - key: str | bytes, - raise_exception: bool = False - ) -> int | float | None: - - """ - To get the no. of seconds till the expiry of some key. - :param key: The key to check the expiry of. - :param raise_exception: - :return: -1 if the key is persistent (i.e., no expiry time set), -2 if the key does not exist, or the time left - in seconds if the key exists and is not persistent. If something goes wrong, you will get a null value. - """ - - # Standard connectivity check: - await self.ensure_connection() - - # Start by assuming failure: - ttl = None - - try: - - # Get the TTL of the key in ms, - # convert it to seconds and return the value: - ttl_ms = await self.__client.pttl(key) - if ttl_ms >= 0: ttl = ttl_ms / 1_000 - return ttl - - # If an exception occurs in th eprocess: - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return None - - async def set( - self, - key: str | bytes, - value: Any, - expiry: float = None, - raise_exception: bool = False - ) -> bool: - - """ - Saves some value to the cache. If an expiry is specified, the data will be deleted after that many seconds. - :param key: The key with which the data will be stored and retrieved. - :param value: The value to store. - :param expiry: The time in seconds after which the data will expire. Must be a positive number. - :param raise_exception: If you want to raise an exception if the process fails. - :return: True if cached, else False. - """ - - # Standard connectivity check: - await self.ensure_connection() - - try: - - # Here we actually try to set the data: - data = self.__serializer.serialize(value) - if expiry: response = await self.__client.setex(key, int(expiry), data) - else: response = await self.__client.set(key, data) - return response - - # If an exception occurs in th eprocess: - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return False - - async def get( - self, - key: str | bytes, - raise_exception: bool = False, - on_fail: Any = None - ) -> Any: - - """ - Retrieve the cached value. - :param key: The key with which the data was saved. - :param raise_exception: If you want to raise an exception if the process fails. - :param on_fail: What to return if the process fails due to an exception. - :return: The retrieved data or null if not found. - """ - - # Standard connectivity check: - await self.ensure_connection() - - try: - - # Here we try to fetch the data: - data = await self.__client.get(key) - data = self.__serializer.deserialize(data) - return data - - # If an exception occurs in th eprocess: - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return on_fail - - async def delete( - self, - key: str | bytes, - raise_exception: bool = False - ) -> bool: - - """ - Prematurely delete the value from the cache before it expires. - :param key: The key with which the data was saved. - :param raise_exception: If you want to raise an exception if the process fails. - :return: True if deleted, else False. - """ - - # Standard connectivity check: - await self.ensure_connection() - - try: - - # Try to manually delete the key before expiry: - response = await self.__client.delete(key) - return True if response else False - - # If an exception occurs in th eprocess: - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return False - - async def count( - self, - key: str | bytes, - value: int = 1, - expiry: float = None, - raise_exception: bool = False - ) -> int | None: - - """ - To use simple counters. If the counter (identified by the 'key') exists, it will be incremented, else the - counter will be created and the value will be incremented from 0. - :param key: The name of the counter. - :param value: The amount to increment the value by. Send negative values to count backwards. - :param expiry: The time (in seconds) in which the counter expires. Starts from the time the counter is created. - This value has to be an integer. If a float is passed, the value will be rounded off. - :param raise_exception: If you want to raise an exception if the process fails. - :return: The latest value of the counter. Will be null if something went wrong and the exception was suppressed. - """ - - # Standard connectivity check: - await self.ensure_connection() - - try: - - # check if the key already exists, - # regardless of that, increment the counter: - already_existed = await self.__client.exists(key) - new_value = await self.__client.incrby(key, value) - - # If the key didn't already exist, specify the expiry: - if expiry and not already_existed: await self.__client.expire(key, int(expiry)) - - # Done here: - return new_value - - # If an exception occurs in th eprocess: - except Exception as exception: - self.__printer(exception) - if raise_exception: raise - else: return None - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - from utils_v2.string import json - - async def main(): - - my_cache = AsyncRedisCache( - connection_string = str(input("Paste your conn. str.: ")), - ping_counter = 100, - debug = True - ) - print("Connecting.") - connected = await my_cache.connect() - print("Success:", connected) - - # Proceed only if we connected to the database successfully: - if connected: - - existing_keys = await my_cache.list_keys() - print(f"KEYS ({len(existing_keys)}):", json.to_string(existing_keys, default = str)) - - key = str(input("Paste a key to check its TTL: ")) - key_ttl = await my_cache.ttl(key = key) - print(f"KEY '{key}' has {key_ttl} seconds of TTL.") - - value = await my_cache.get(key = str(input("Paste a key to get: "))) - print("GET:", json.to_string(value, default = str) if isinstance(value, (dict, list)) else value) - print("TYP:", type(value), end = "\n\n") - - success = await my_cache.set( - key = "name", - value = {"first": "John", "last": "Doe"}, - expiry = 10 - ) - print("SET:", success, end = "\n\n") - - value = await my_cache.get(key = "name") - print("GET:", value) - print("TYP:", type(value), end = "\n\n") - - success = await my_cache.delete(key = "name") - print("DEL:", success, end = "\n\n") - - print("Starting count test.") - await my_cache.delete(key = "cnt") - for _ in range(5): - print("Step:", _) - await asyncio.sleep(1.0) - counter = await my_cache.count(key = "cnt", value = 1, expiry = 10) - print("COUNTER:", counter) - - asyncio.run(main()) diff --git a/utils_v2/database/__init__.py b/utils_v2/database/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/database/__pycache__/__init__.cpython-310.pyc b/utils_v2/database/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index e6bb512d4970b23d76ed4be4d6ae51fd87d208b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 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 X`Zsz{bX53g^{vBZ)f~Oq`mO&5Y|^k> diff --git a/utils_v2/database/__pycache__/async_mysql_v2.cpython-310.pyc b/utils_v2/database/__pycache__/async_mysql_v2.cpython-310.pyc deleted file mode 100644 index 91e17146e137288a26302ba549e4c4ff7f8bb79c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9102 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 {message}" - return message - - -# --------------------------------------------------------------------------------------------------------------------- - - -class MongoInsertException(Exception): - - def __init__(self, hint = None, origin = None): - self.__hint = hint - self.__origin = origin - - def __str__(self): - message = "mongo insert operation failed" - if self.__hint is not None: message = f"{message} ({self.__hint})" - if self.__origin is not None: message = f"{self.__origin} --> {message}" - return message - - -# --------------------------------------------------------------------------------------------------------------------- - - -class MongoUpdateException(Exception): - - def __init__(self, hint = None, origin = None): - self.__hint = hint - self.__origin = origin - - def __str__(self): - message = "mongo update operation failed" - if self.__hint is not None: message = f"{message} ({self.__hint})" - if self.__origin is not None: message = f"{self.__origin} --> {message}" - return message - - -# --------------------------------------------------------------------------------------------------------------------- - - -class MongoReplaceException(Exception): - - def __init__(self, hint = None, origin = None): - self.__hint = hint - self.__origin = origin - - def __str__(self): - message = "mongo replace operation failed" - if self.__hint is not None: message = f"{message} ({self.__hint})" - if self.__origin is not None: message = f"{self.__origin} --> {message}" - return message - - -# --------------------------------------------------------------------------------------------------------------------- - - -class MongoDeleteException(Exception): - - def __init__(self, hint = None, origin = None): - self.__hint = hint - self.__origin = origin - - def __str__(self): - message = "mongo delete operation failed" - if self.__hint is not None: message = f"{message} ({self.__hint})" - if self.__origin is not None: message = f"{self.__origin} --> {message}" - return message - - -# --------------------------------------------------------------------------------------------------------------------- - - -class MongoException(Exception): - - def __init__(self, hint = None, origin = None): - self.__hint = hint - self.__origin = origin - - def __str__(self): - message = "mongo operation failed" - if self.__hint is not None: message = f"{message} ({self.__hint})" - if self.__origin is not None: message = f"{self.__origin} --> {message}" - return message - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncMongo: - - __db = None - __db_name = None - __client = None - - def __init__( - self, - database_name = "myDb", - max_connections = 5, - debug = True, - debug_only_errors = True, - host = "localhost", - port = 27017, - connection_string = None - ): - - # Basic config: - self.__max_connections = max_connections - self.__db_name = database_name - self.__host = host, - self.__port = port - self.__connection_string = connection_string - - # For debugging: - self.__debug_only_errors = debug_only_errors - self.__printer = IceCreamDebugger(prefix = f"Mongo ({self.__db_name}) | ", includeContext = True) - if not debug: self.__printer.disable() - - # Rate/access control: - self.__exclusive_semaphore = asyncio.Semaphore(1) - - def enable_debug(self): - self.__printer.enable() - - def disable_debug(self): - self.__printer.disable() - - @staticmethod - def generate_id(): - - """ - Just generates an '_id' in MongoDB style. - :return: The '_id' in MongoDB style. - """ - - return str(ObjectId()) - - async def connect(self): - try: - if self.__connection_string is None: - self.__client = AsyncIOMotorClient( - self.__host, - self.__port, - maxPoolSize = self.__max_connections, - minPoolSize = self.__max_connections - ) - else: - self.__client = AsyncIOMotorClient( - self.__connection_string, - maxPoolSize = self.__max_connections, - minPoolSize = self.__max_connections - ) - self.__db = self.__client.get_database(self.__db_name) - if not self.__debug_only_errors: - server_info = await self.__client.server_info() - self.__printer(server_info) - except Exception as exception: self.__printer(exception) - - async def ensure_connection(self): - if self.__db is None: - async with self.__exclusive_semaphore: - await self.connect() - - @property - async def client(self): - await self.ensure_connection() - return self.__client - - @staticmethod - def dict_to_dot_notation(input_dict, parent_key = "", separator = "."): - items = [] - for k, v in input_dict.items(): - new_key = f"{parent_key}{separator}{k}" if parent_key else k - if isinstance(v, dict) and v: - items.extend(AsyncMongo.dict_to_dot_notation(v, new_key, separator = separator).items()) - else: - items.append((new_key, v)) - return dict(items) - - @staticmethod - def normalize_date_time(document): - - """ - MongoDB doesn't support timezones. A good strategy would be to convert everything to UTC format and store it. - This method does exactly that. Any datetime object is converted to UTC timezone. If the datetime object was - timezone naive, UTC timezone will be applied to it without changing the time value. - :param document: The document that you want to normalize the date-time in. - :return: The document with normalized datetime. - """ - - if isinstance(document, datetime.datetime): - utc_tz = pytz.timezone("UTC") - if document.tzinfo is None: document = utc_tz.localize(document) - else: document = document.astimezone(utc_tz) - - if type(document) is list: - document = [AsyncMongo.normalize_date_time(item) for item in document] - - if type(document) is dict: - document = { - AsyncMongo.normalize_date_time(k): AsyncMongo.normalize_date_time(v) - for k, v in document.items() - } - - return document - - @staticmethod - def __from_json_string(json_data): - return loads(json_data) - - @staticmethod - def __to_json_string(python_data, indent = 4, default = None): - return dumps(python_data, indent = indent, default = default) - - async def list_indexes( - self, - collection, - session = None, - raise_exception = False - ): - - """ - Lists out the indexes of a collection. - :param collection: The collection whose indexes you want to list out, - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The list of indexes or None if the action fails. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - indexes = None - - # Try to list the indexes: - try: - responses = await self.__db[collection].list_indexes(session = session).to_list(None) - indexes = [{key: value for key, value in response.items()} for response in responses] - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not indexes: raise MongoException(hint = "list indexes") - return indexes - - async def create_index( - self, - collection, - keys, - options = None, - session = None, - raise_exception = False - ): - - """ - Creates an index on a collection. - :param collection: The collection to create the index on. - :param keys: The keys (and sorting) to implement the index on. - :param options: Additional config. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the execution. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to make the insertion: - try: - options = options or {} - keys = [(k, v) for k, v in keys.items()] - response = await self.__db[collection].create_index(keys, session = session, **options) - if response: success = True - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not success: raise MongoException(hint = "create index") - return success - - async def insert_one( - self, - collection, - document, - session = None, - raise_exception = False - ): - - """ - Insert data into a collection. - :param collection: The collection you want to feed the data into. - :param document: The data to be stored. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The id of the inserted data, or null if the action fails. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - inserted_id = None - - # Try to make the insertion: - try: - response = await self.__db[collection].insert_one(document.copy(), session = session) - inserted_id = response.inserted_id - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not inserted_id: raise MongoInsertException(hint = f"{collection}") - return inserted_id - - async def insert_many( - self, - collection, - documents, - session = None, - raise_exception = False - ): - - """ - Insert a lot of data into a collection. - :param collection: The collection you want to feed the data into. - :param documents: The data to be stored. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The id of the inserted data, or null if the action fails. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - inserted_ids = [] - - # Try to make the insertion: - try: - response = await self.__db[collection].insert_many(documents, session = session) - inserted_ids = response.inserted_ids - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not inserted_ids: raise MongoInsertException(hint = f"{collection}") - return inserted_ids - - async def update_one( - self, - collection, - filter_json = None, - update_json = None, - upsert = False, - session = None, - raise_exception = False - ): - - """ - Update one document. - :param collection: The collection you want to update. - :param filter_json: The selection criteria to locate the document to update. - :param update_json: The values you want to update. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to make the insertion: - try: - response = await self.__db[collection].update_one( - filter_json, - update_json, - upsert = upsert, - session = session - ) - success = False if response.modified_count == 0 else True - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not success: raise MongoUpdateException(hint = f"{collection}") - return success - - async def update_many( - self, - collection, - filter_json = None, - update_json = None, - upsert = False, - session = None, - raise_exception = False - ): - - """ - Update many documents. - :param collection: The collection you want to update. - :param filter_json: The selection criteria to locate the document to update. - :param update_json: The values you want to update. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - update_count = 0 - - # Try to make the insertion: - try: - response = await self.__db[collection].update_many( - filter_json, - update_json, - upsert = upsert, - session = session - ) - update_count = response.modified_count - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not update_count: raise MongoUpdateException(hint = f"{collection}") - return update_count - - async def count( - self, - collection, - filter_json = None - ): - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = 0 - - # try to query the data: - try: - if filter_json is None: filter_json = {} - count = await self.__db[collection].count_documents(filter_json) - except Exception as exception: self.__printer(exception) - - # Done here: - return count - - async def bulk_write( - self, - collection, - requests, - session = None, - raise_exception = False - ): - - """ - To perform various individual operations in one go. You will have to import individual actions like "UpdateOne" - and "InsertMany" from PyMongo and pass them as an array of requests (operations) to this method. - :param collection: The collection you want to run the requests on. - :param requests: The array of requests (operations) to be performed. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = 0 - - # try to query the data: - try: - response = await self.__db[collection].bulk_write(requests, session = session) - count = response.modified_count + response.inserted_count + response.upserted_count + response.deleted_count - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not count: raise MongoException(hint = "bulk write") - return count - - async def find_many( - self, - collection, - filter_json, - projections = None, - skip = 0, - limit = None, - sort = None, - session = None, - as_json_string = False, - indent = 4, - raise_exception = False - ): - - """ - Finds one or more records that match the given conditions. - :param collection: The name of the collection to perform the search in. - :param filter_json: The filter criteria. - :param projections: What parts of the matching data you want to fetch. - :param skip: The no. of records to skip before picking next ones. Needed for pagination. - :param limit: The max. no. of records you want to fetch. - :param sort: The sorting rules to apply. - :param session: The session if you need to do this in a transaction. - :param as_json_string: Whether you want it as a JSON string or a Python dict/list. - :param indent: The indentation to use if you want it as a JSON string. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The array of matching records or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # Assume defaults: - if sort is None: sort = {"_id": -1} - if limit is None: limit = 10 - - # try to query the data: - try: - results = await self.__db[collection].find( - filter_json, - projections, - session = session - ).sort(sort).skip(skip).limit(limit).to_list(None) - if as_json_string: results = self.__to_json_string(results, indent = indent, default = str) - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not results: raise MongoFindException(hint = f"{collection}") - return results - - async def find_one( - self, - collection, - filter_json, - projections = None, - session = None, - as_json_string = False, - indent = 4, - raise_exception = False - ): - - """ - Finds one record that matches the given conditions. - :param collection: The name of the collection to perform the search in. - :param filter_json: The filter criteria. - :param projections: What parts of the matching data you want to fetch. - :param session: The session if you need to do this in a transaction. - :param as_json_string: Whether you want it as a JSON string or a Python dict/list. - :param indent: The indentation to use if you want it as a JSON string. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The array of matching records or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # try to query the data: - try: - results = await self.__db[collection].find_one(filter_json, projections, session = session) - if as_json_string: results = self.__to_json_string(results, indent = indent, default = str) - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not results: raise MongoFindException(hint = f"{collection}") - return results - - async def replace_one( - self, - collection, - filter_json, - replacement_json, - upsert = False, - session = None, - raise_exception = False - ): - - """ - To delete one document from a collection. - :param collection: The collection from which you want to delete many records. - :param filter_json: The filter criteria. - :param replacement_json: The data to put in place of the existing document. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # try to query the data: - try: - result = await self.__db[collection].replace_one( - filter_json, - replacement_json, - upsert = upsert, - session = session - ) - if result.modified_count or result.upserted_id: success = True - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not success: raise MongoReplaceException(hint = f"{collection}") - return success - - async def delete_one( - self, - collection, - filter_json, - session = None, - raise_exception = False - ): - - """ - To delete one document from a collection. - :param collection: The collection from which you want to delete many records. - :param filter_json: The filter criteria. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = 0 - - # try to query the data: - try: - result = await self.__db[collection].delete_one(filter_json, session = session) - count = result.deleted_count - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not count: raise MongoDeleteException(hint = f"{collection}") - return count - - async def delete_many( - self, - collection, - filter_json, - session = None, - raise_exception = False - ): - - """ - To delete many documents from a collection. - WARNING: sending {} in the filter would mean deleting ALL the documents. - :param collection: The collection from which you want to delete many records. - :param filter_json: The filter criteria. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = 0 - - # try to query the data: - try: - result = await self.__db[collection].delete_many(filter_json, session = session) - count = result.deleted_count - except Exception as exception: - self.__printer(exception) - - # Check results and return: - if raise_exception and not count: raise MongoDeleteException(hint = f"{collection}") - return count - - async def aggregate( - self, - collection, - pipeline, - limit = None, - raise_exception = False - ): - - """ - Perform an advance query on the data. - :param collection: The collection to perform the query on. - :param pipeline: The pipeline of actions to take. Must be a list. - :param limit: The max. no. of records to retrieve. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The array of matching records or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # try to perform the aggregation action: - try: results = await self.__db[collection].aggregate(pipeline).to_list(limit) - except Exception as exception: self.__printer(exception) - - # Check results and return: - if raise_exception and not results: raise MongoException(hint = "aggregation") - return results - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/database/async_mongo_storage.py b/utils_v2/database/async_mongo_storage.py deleted file mode 100644 index 94df2d8..0000000 --- a/utils_v2/database/async_mongo_storage.py +++ /dev/null @@ -1,358 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 28th May, 2024 - - OBJECTIVE: - - To have one central place from where all async database connectivity happens. - - REFERENCES: - - 01. https://motor.readthedocs.io/en/stable/ - - DOWNLOADS: - - N/A - -""" - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -# --- -import sys -sys.path.append(".") -sys.path.append("..") - -# For system-level activity: -import io - -# For async behaviour: -import asyncio - -# MongoDB for File Storage: -from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorGridFSBucket -from bson.objectid import ObjectId - -# For debugging: -from icecream import IceCreamDebugger - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncMongoStorage: - - __db = None - __db_name = None - __client = None - __store = None - - def __init__( - self, - connection_string = None, - max_connections = 5, - host_name = "localhost", - port = 27017, - database_name = "fileStore", - debug = True, - debug_prefix = "GridFS (M) | ", - debug_only_errors = True - ): - - # Database Initialization: - self.__host_name = host_name - self.__port = port - self.__db_name = database_name - self.__connection_string = connection_string - self.__max_connections = max_connections - - # Debugging: - self.__debug_only_errors = debug_only_errors - self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self.__printer.disable() - - @staticmethod - def generate_id(): - - """ - Just generates an '_id' in MongoDB style. - :return: The '_id' in MongoDB style. - """ - - return str(ObjectId()) - - async def connect(self): - - """ - Initialize the database connection. - :return: Nothing. - """ - - if self.__connection_string is None: - self.__client = AsyncIOMotorClient( - self.__host_name, - self.__port, - maxPoolSize = self.__max_connections, - minPoolSize = self.__max_connections - ) - else: - self.__client = AsyncIOMotorClient( - self.__connection_string, - maxPoolSize = self.__max_connections, - minPoolSize = self.__max_connections - ) - self.__db = self.__client.get_database(self.__db_name) - self.__store = AsyncIOMotorGridFSBucket(self.__db) - - @property - def fs(self): - - """ - To access the features that have not been wrapped in this reportlab directly. - This could include things like streaming files chunk-by-chunk. - :return: The file-store instance. - """ - - return self.__store - - async def write_from_memory(self, file_name, file_data, metadata_json = None): - - """ - Save a file (from RAM) to Mongo. Suitable for smaller files (a few MBs max.). - :param file_name: The name of the file. - :param file_data: The data of the file (held in RAM). - :param metadata_json: A JSON of metadata information that can later be used to search files (RECOMMENDED). - :return: The file's id as a string (if it gets saved) or None. - """ - - if self.__store is None: await self.connect() - - file_data.seek(0) - file_size = file_data.__sizeof__() - - file_id = None - try: file_id = await self.__store.upload_from_stream(file_name, file_data, metadata = metadata_json) - except Exception as exception: self.__printer(exception, file_name, file_size, file_id) - if not self.__debug_only_errors: self.__printer(file_name, file_size, file_id) - return str(file_id) - - async def read_to_memory(self, file_identifier, by_id = True): - - """ - To retrieve a file (in RAM) based on the provided identifier. - Suitable for smaller files (a few MBs max.). - :param file_identifier: Either the name or the "_id" of the file. - :param by_id: Set to True if you are fetching by the "_id" of the file. - :return: Either the file (in RAM) or None. - """ - - if self.__store is None: await self.connect() - - file_data = None - - try: - if by_id: grid_out = await self.__store.open_download_stream(ObjectId(file_identifier)) - else: grid_out = await self.__store.open_download_stream_by_name(file_identifier) - file_data = io.BytesIO(await grid_out.read()) - file_data.seek(0) - - except Exception as exception: - file_data = None - self.__printer(exception, file_identifier, by_id) - - if not self.__debug_only_errors: self.__printer(file_identifier, by_id) - return file_data - - async def delete_file_by_id(self, file_id): - - """ - Tries to delete one file by the id. - :param file_id: The id of the file in the database. - :return: True or False based on the success of the operation. - """ - - if self.__store is None: await self.connect() - - deleted = False - - try: - response = await self.__store.delete(file_id = ObjectId(file_id)) - deleted = True - except Exception as exception: - self.__printer(exception, file_id, deleted) - - return deleted - - def __format_metadata_json(self, metadata_json): - - """ - NOTE: ONLY USE WHEN SEARCHING FILES BY METADATA. - MongoDB expects dot-notation while searching for files by the metadata. We are making a function to search - files assuming that the conditions are to be applied to the metadata itself. So this function add the - dot-notation to the right places to conduct a successful search. - :param metadata_json: The JSON to format. - :return: The formatted JSON that has the right dot-notation. - """ - - formatted_metadata_json = {} - - for key, value in metadata_json.items(): - if not key.startswith("$"): key = f"metadata.{key}" - else: - if type(value) is dict: value = self.__format_metadata_json(value) - if type(value) is list: value = [self.__format_metadata_json(item) for item in value] - formatted_metadata_json[key] = value - - return formatted_metadata_json - - async def find_file_by_metadata(self, metadata_json, limit = None, skip = None, sort = None): - - """ - This method only lists the files that match the criteria mentioned in the metadata JSON. - :param metadata_json: The JSON that describes what you want to find. - :param limit: Max. no. of records to retrieve. - :param skip: No. of starting results to skip. Useful for pagination. - :param sort: The sorting conditions to follow. - :return: A list of (JSONs of) files that match the conditions. The list can be empty. - """ - - if self.__store is None: await self.connect() - - files_list = [] - - try: - limit = limit or 10 - skip = skip or 0 - sort = {"_id": -1} if not isinstance(sort, dict) else sort - formatted_metadata_json = self.__format_metadata_json(metadata_json) - return await self.__store.find( - formatted_metadata_json - ).sort(sort).skip(skip).limit(limit).to_list(None) - - except Exception as exception: self.__printer(exception, metadata_json, len(files_list)) - - if not self.__debug_only_errors: self.__printer(metadata_json, len(files_list)) - return files_list - - async def find_file_by_id(self, file_id): - - """ - This method allows you to get the file's info from the id of the file. - :param file_id: The id that was assigned by Mongo during upload. - :return: The file's info or None if the file doesn't exist. - """ - - if self.__store is None: await self.connect() - - file_info = None - - try: - formatted_metadata_json = {"_id": ObjectId(file_id)} - file_info = (await self.__store.find(formatted_metadata_json).to_list(1))[0] - - except Exception as exception: self.__printer(exception, file_id, file_info) - - return file_info - - async def get_file_name(self, file_id): - - """ - Returns the file name if the id of the file is known. - :param file_id: The id of the file as assigned by MongoDB when the file was stored. - :return: The file's name (if it exists), or None. - """ - - # Ensure that we are connected: - if self.__store is None: await self.connect() - - # Ensure that the input given is of 'ObjectId' type: - if type(file_id) is not ObjectId: file_id = ObjectId(str(file_id)) - - # Fetch and return the file name: - files_list = await self.__store.find( - {"_id": file_id}, - {"filename": True} - ).sort({"_id": -1}).limit(1).to_list(None) - try: file_name = files_list[0]["filename"] - except: file_name = None - return file_name - - async def aggregate( - self, - collection, - pipeline, - limit = None - ): - - """ - Perform an advance query on the data. - :param collection: The collection to perform the query on. - :param pipeline: The pipeline of actions to take. Must be a list. - :param limit: The max. no. of records to retrieve. - :return: The array of matching records or null if there was an exception. - """ - - if self.__store is None: await self.connect() - - results = None - try: results = await self.__db[collection].aggregate(pipeline).to_list(limit) - except Exception as exception: self.__printer(exception) - return results - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/database/async_mongo_v2.py b/utils_v2/database/async_mongo_v2.py deleted file mode 100644 index f15b817..0000000 --- a/utils_v2/database/async_mongo_v2.py +++ /dev/null @@ -1,1736 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Original: Tuesday, 28th May, 2024 - Modified: Tuesday, 17th Sept., 2024 - - OBJECTIVE: - - To have one central place from where all async MongoDB activity happens. - - REFERENCES: - - 01. https://motor.readthedocs.io/en/stable/ - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For system-level activity: -import io - -# For async behaviour: -import asyncio - -# MongoDB for File Storage: -from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorGridFSBucket -from bson.objectid import ObjectId -from bson.json_util import dumps, loads - -# My utils: -from utils_v2.string import json - -# For datetime handling: -import pytz -import datetime - -# For debugging: -from icecream import IceCreamDebugger - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** EXCEPTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncMongoBase: - - def __init__( - self, - connection_string = None, - max_connections = 5, - host_name = "localhost", - port = 27017, - database_name = "myDb", - debug = True, - debug_prefix = "Mongo | ", - debug_only_errors = True - ): - - # Basic variables that will be needed later: - self._client = None - self._db = None - self._fs = None - - # Database Initialization: - self._host_name = host_name - self._port = port - self._db_name = database_name - self._connection_string = connection_string - self._max_connections = max_connections - - # Debugging: - self._debug_only_errors = debug_only_errors - self._printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self._printer.disable() - - def enable_debug(self): - self._printer.enable() - - def disable_debug(self): - self._printer.disable() - - async def connect(self): - - """ - Initialize the database connection. - :return: None. - """ - - self._printer("Connecting...") - - # If a connection string is given, - # give preference to it: - if self._connection_string is None: - self._client = AsyncIOMotorClient( - self._host_name, - self._port, - maxPoolSize = self._max_connections, - minPoolSize = self._max_connections - ) - - # In the absense of a connection string, - # try to connect through the other credentials: - else: - self._client = AsyncIOMotorClient( - self._connection_string, - maxPoolSize = self._max_connections, - minPoolSize = self._max_connections - ) - - # Debugging print: - if not self._debug_only_errors: - server_info = await self._client.server_info() - self._printer(server_info) - - # Now we connect to the database and the file-store: - self._db = self._client.get_database(self._db_name) - self._fs = AsyncIOMotorGridFSBucket(self._db) - - async def ensure_connection(self): - - """ - Call this at the start of every function to automatically connect to the database when the user of the library - forgets to explicitly connect to the database. - :return: None. - """ - - if self._client is None: await self.connect() - - @staticmethod - def generate_id(as_str = False): - - """ - Just generates an '_id' in MongoDB style. - :param as_str: Set to True to convert the generated id to a string; and False to receive it as an instance of - 'ObjectId'. This is useful when you need to pre-assign ids to files. - :return: The '_id' in MongoDB style. - """ - - generated_id = ObjectId() - return str(generated_id) if as_str else generated_id - - @property - async def client(self): - - """ - returns the client to perform activities that have not been explicitly wrapped in the class. - :return: The client's instance. - """ - - await self.ensure_connection() - return self._client - - @property - async def db(self): - - """ - returns the database connector to perform activities that have not been explicitly wrapped in the class. - :return: The database's connection instance. - """ - - await self.ensure_connection() - return self._fs - - @property - async def fs(self): - - """ - returns the file-store to perform activities that have not been explicitly wrapped in the class. - :return: The file-store instance. - """ - - await self.ensure_connection() - return self._fs - - @staticmethod - def from_json_string(json_data): - - """ - Converts from a JSON string to BSON. - :param json_data: The JSON string to convert to BSON. - :return: The BSON interpretation of the input JSON string. - """ - - return loads(json_data) - - @staticmethod - def to_json_string(data, indent = 4, default = None): - - """ - Converts from a BSON to JSON string. - :param data: The input BSON data. - :param indent: The no. of spaces to put into the string for pretty print. - :param default: The default function to apply to data that cannot be converted directly. - :return: The JSON string from the input data. - """ - - return dumps(data, indent = indent, default = default) - - @staticmethod - def dict_to_dot_notation(input_dict, pk = "", s = "."): - - """ - Converts an input dict to dot notation format. Can be used as a utility to perform searches. - :param input_dict: The dict that you want to convert to dot notation. - :param pk: Parent Key. DO NOT TOUCH (meant to be used during recursion). - :param s: Separator. DO NOT TOUCH (meant to be used during recursion). - :return: The dot notation representation of the input dict. - """ - - items = [] - for k, v in input_dict.items(): - new_key = f"{pk}{s}{k}" if pk else k - if isinstance(v, dict) and v: items.extend(AsyncMongoBase.dict_to_dot_notation(v, new_key, s = s).items()) - else: items.append((new_key, v)) - return dict(items) - - @staticmethod - def normalize_date_time(document): - - """ - MongoDB doesn't support timezones. A good strategy would be to convert everything to UTC format and store it. - This method does exactly that. Any datetime object is converted to UTC timezone. If the datetime object was - timezone naive, UTC timezone will be applied to it without changing the time value. - :param document: The document that you want to normalize the date-time in. - :return: The document with normalized datetime. - """ - - if isinstance(document, datetime.datetime): - utc_tz = pytz.timezone("UTC") - if document.tzinfo is None: document = utc_tz.localize(document) - else: document = document.astimezone(utc_tz) - - if type(document) is list: - document = [AsyncMongoBase.normalize_date_time(item) for item in document] - - if type(document) is dict: - document = { - AsyncMongoBase.normalize_date_time(k): AsyncMongoBase.normalize_date_time(v) - for k, v in document.items() - } - - return document - - @staticmethod - def read_to_ram(file_path): - - """ - Reads a file into a BytesIO object in RAM. - :param file_path: The path to the file on disk. - :return: The file in a BytesIO object. - """ - - with open(file_path, "rb") as file: file_data = file.read() - file_in_ram = io.BytesIO(file_data) - file_in_ram.seek(0) - return file_in_ram - - -# --------------------------------------------------------------------------------------------------------------------- - - -class AsyncMongo(AsyncMongoBase): - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - async def list_indexes( - self, - collection, - session = None, - raise_exception = False - ): - - """ - Lists out the indexes of a collection. - :param collection: The collection whose indexes you want to list out, - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The list of indexes or None if the action fails. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - indexes = None - - # Try to list the indexes: - try: - responses = await self._db[collection].list_indexes(session = session).to_list(None) - indexes = [{key: value for key, value in response.items()} for response in responses] - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return indexes - - async def create_index( - self, - collection, - keys, - options = None, - session = None, - raise_exception = False - ): - - """ - Creates an index on a collection. - :param collection: The collection to create the index on. - :param keys: The keys (and sorting) to implement the index on. - :param options: Additional config. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the execution. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to make the insertion: - try: - options = options or {} - keys = [(k, v) for k, v in keys.items()] - response = await self._db[collection].create_index(keys, session = session, **options) - if response: success = True - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def count( - self, - collection, - filter, - session = None, - raise_exception = False - ): - - """ - Counts the no. of documents that match the given filter condition. - :param collection: The name of the collection to count in. - :param filter: The filter criteria that the documents must satisfy to be counted. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The count if the operation was performed successfully or None is something went wrong and the exception - was suppressed. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = None - - # try to query the data: - try: count = await self._db[collection].count_documents(filter, session = session) - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return count - - async def insert_one( - self, - collection, - document, - session = None, - raise_exception = False - ): - - """ - Insert data into a collection. - :param collection: The collection you want to feed the data into. - :param document: The data to be stored. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The id of the inserted data, or null if the action fails. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - inserted_id = None - - # Try to make the insertion: - try: - response = await self._db[collection].insert_one(document.copy(), session = session) - inserted_id = response.inserted_id - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return inserted_id - - async def insert_many( - self, - collection, - documents, - session = None, - raise_exception = False - ): - - """ - Insert a lot of data into a collection. - :param collection: The collection you want to feed the data into. - :param documents: The list of documents to be stored. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The id of the inserted data, or null if the action fails. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - inserted_ids = [] - - # Try to make the insertion: - try: - response = await self._db[collection].insert_many(documents, session = session) - inserted_ids = response.inserted_ids - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return inserted_ids - - async def find_one( - self, - collection, - filter, - projection = None, - session = None, - raise_exception = False - ): - - """ - Finds one record that matches the given conditions. - :param collection: The name of the collection to perform the search in. - :param filter: The filter criteria. - :param projection: What parts of the matching data you want to fetch. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The matching record or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # try to query the data: - try: results = await self._db[collection].find_one(filter, projection, session = session) - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Check results and return: - return results - - async def find_many( - self, - collection, - filter, - projection = None, - skip = 0, - limit = None, - sort = None, - session = None, - raise_exception = False - ): - - """ - Finds one or more records that match the given conditions. - :param collection: The name of the collection to perform the search in. - :param filter: The filter criteria. - :param projection: What parts of the matching data you want to fetch. - :param skip: The no. of records to skip before picking next ones. Needed for pagination. - :param limit: The max. no. of records you want to fetch. - :param sort: The sorting rules to apply. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The array of matching records or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # Assume defaults: - if sort is None: sort = {"_id": -1} - if limit is None: limit = 10 - - # try to query the data: - try: - results = await self._db[collection].find( - filter, - projection, - sort = sort, - skip = skip, - limit = limit, - session = session - ).to_list(None) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return results - - async def update_one( - self, - collection, - filter = None, - update = None, - upsert = False, - session = None, - raise_exception = False - ): - - """ - Update one document. - :param collection: The collection you want to update. - :param filter: The selection criteria to locate the document to update. - :param update: The values you want to update. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to make the update: - try: - response = await self._db[collection].update_one( - filter, - update, - upsert = upsert, - session = session - ) - success = True if response.modified_count > 0 or response.upserted_id else False - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def update_many( - self, - collection, - filter = None, - update = None, - upsert = False, - session = None, - raise_exception = False - ): - - """ - Update many documents. - :param collection: The collection you want to update. - :param filter: The selection criteria to locate the document to update. - :param update: The values you want to update. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - update_count = 0 - - # Try to make the insertion: - try: - response = await self._db[collection].update_many( - filter, - update, - upsert = upsert, - session = session - ) - update_count = response.modified_count + response.upserted_count - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return update_count - - async def find_one_and_update( - self, - collection, - filter = None, - update = None, - projection = None, - return_updated = False, - upsert = False, - session = None, - raise_exception = False - ): - - """ - Update one document. - :param collection: The collection you want to update. - :param filter: The selection criteria to locate the document to update. - :param update: The values you want to update. - :param projection: What parts of the matching data you want to fetch. - :param return_updated: To choose whether you want to retrieve the original document or the updated document. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The fetched document. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - document = None - - # Try to make the update: - try: - document = await self._db[collection].find_one_and_update( - filter, - update, - projection = projection, - return_document = return_updated, - upsert = upsert, - session = session - ) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return document - - async def replace_one( - self, - collection, - filter, - replacement, - upsert = False, - session = None, - raise_exception = False - ): - - """ - To delete one document from a collection. - :param collection: The collection from which you want to delete many records. - :param filter: The filter criteria. - :param replacement: The data to put in place of the existing document. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # try to query the data: - try: - result = await self._db[collection].replace_one( - filter, - replacement, - upsert = upsert, - session = session - ) - if result.modified_count or result.upserted_id: success = True - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def find_one_and_replace( - self, - collection, - filter, - replacement, - projection = None, - return_replaced = False, - upsert = False, - session = None, - raise_exception = False - ): - - """ - To delete one document from a collection. - :param collection: The collection from which you want to delete many records. - :param filter: The filter criteria. - :param replacement: The data to put in place of the existing document. - :param projection: What parts of the matching data you want to fetch. - :param return_replaced: To choose whether you want to retrieve the original document or the updated document. - :param upsert: If you want to insert if the document doesn't already exist. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - document = None - - # try to query the data: - try: - document = await self._db[collection].find_one_and_replace( - filter, - replacement, - projection = projection, - return_document = return_replaced, - upsert = upsert, - session = session - ) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return document - - async def delete_one( - self, - collection, - filter, - session = None, - raise_exception = False - ): - - """ - To delete one document from a collection. - :param collection: The collection from which you want to delete many records. - :param filter: The filter criteria. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # try to query the data: - try: - result = await self._db[collection].delete_one(filter, session = session) - success = True if result.deleted_count else False - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def delete_many( - self, - collection, - filter, - session = None, - raise_exception = False - ): - - """ - To delete many documents from a collection. - WARNING: sending {} in the filter would mean deleting ALL the documents. - :param collection: The collection from which you want to delete many records. - :param filter: The filter criteria. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = 0 - - # try to query the data: - try: - result = await self._db[collection].delete_many(filter, session = session) - count = result.deleted_count - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return count - - async def find_one_and_delete( - self, - collection, - filter, - projection = None, - session = None, - raise_exception = False - ): - - """ - To delete one document from a collection. - :param collection: The collection from which you want to delete a record. - :param filter: The filter criteria. - :param projection: What parts of the matching data you want to fetch. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The document that matched your criteria or None. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - document = None - - # try to query the data: - try: - document = await self._db[collection].find_one_and_delete( - filter, - projection = projection, - session = session - ) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return document - - async def bulk_write( - self, - collection, - requests, - session = None, - raise_exception = False - ): - - """ - To perform various individual operations in one go. You will have to import individual actions like "UpdateOne" - and "InsertMany" from PyMongo and pass them as an array of requests (operations) to this method. - :param collection: The collection you want to run the requests on. - :param requests: The array of requests (operations) to be performed. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = 0 - - # try to query the data: - try: - response = await self._db[collection].bulk_write(requests, session = session) - count = response.modified_count + response.inserted_count + response.upserted_count + response.deleted_count - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return count - - async def aggregate( - self, - collection, - pipeline, - limit = None, - session = None, - raise_exception = False - ): - - """ - Perform an advance query on the data. - :param collection: The collection to perform the query on. - :param pipeline: The pipeline of actions to take. Must be a list. - :param limit: The max. no. of records to retrieve. preferably apply the limit from within the pipeline. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The array of matching records or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # try to perform the aggregation action: - try: results = await self._db[collection].aggregate(pipeline, session = session).to_list(limit) - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return results - - -# --------------------------------------------------------------------------------------------------------------------- - - -class AsyncMongoStorage(AsyncMongo): - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - async def easy_upload( - self, - source, - file_name: str, - file_metadata: dict = None, - file_id = None, - chunk_size: int = None, - session = None, - raise_exception = False - ): - - """ - Easily write one file to MongoDB's GridFS. Ideal for directly uploading small files without having to worry - about any internal mechanisms. - :param source: The actual file, supplied as either a path string or a file-like object, to be written to the - database. - :param file_name: The name of the file as it will be stored on (and retrieved from) GridFS. - :param file_metadata: Any metadata to later search the file by. - :param file_id: Any custom id to be given to the file. TRY STICKING TO THE ID GENERATED BY 'generate_id'. - :param chunk_size: The chunk size (in bytes) to use for storing this file. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The id of the inserted file or None if the upload failed. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - inserted_id = None - - # Try to write the file: - try: - - # Input pre-processing: - if isinstance(source, io.BytesIO): source.seek(0) - elif isinstance(source, str): source = open(source, mode = "rb") - - # If no file id was supplied: - if file_id is None: - inserted_id = await self._fs.upload_from_stream( - filename = file_name, - source = source, - metadata = file_metadata, - chunk_size_bytes = chunk_size, - session = session - ) - - # If a file id was supplied: - else: - await self._fs.upload_from_stream_with_id( - file_id = file_id, - filename = file_name, - source = source, - metadata = file_metadata, - chunk_size_bytes = chunk_size, - session = session - ) - inserted_id = file_id - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return inserted_id - - async def easy_download( - self, - destination, - file_id = None, - file_name = None, - session = None, - raise_exception = False - ): - - """ - Easily read one file from MongoDB's GridFS. Ideal for directly downloading small files without having to worry - about any internal mechanisms. - :param destination: The path on the local disk or a buffer in RAM to save the downloaded data to. - :param file_id: (RECOMMENDED) the id of the save file. - :param file_name: The name of the saved file. NOT RECOMMENDED because you could have many files with the same - name. The best way to tell files apart if from the id. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. The contents of the stored file are written - directly to the destination. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to read the file: - try: - - # Input pre-processing: - if isinstance(destination, str): destination = open(destination, mode = "wb") - - # If a file id is supplied (preferred way): - if file_id is not None: - await self._fs.download_to_stream( - destination = destination, - file_id = file_id, - session = session - ) - if isinstance(destination, io.BytesIO): destination.seek(0) - success = True - - # If a file name is supplied: - elif file_name is not None: - await self._fs.download_to_stream_by_name( - destination = destination, - filename = file_name, - session = session - ) - if isinstance(destination, io.BytesIO): destination.seek(0) - success = True - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def count_files( - self, - filter, - session = None, - raise_exception = False - ): - - """ - Counts the no. of documents that match the given filter condition. - :param filter: The filter criteria that the documents must satisfy to be counted. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The count if the operation was performed successfully or None is something went wrong and the exception - was suppressed. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = None - - # try to query the data: - try: count = await self._db["fs.files"].count_documents(filter, session = session) - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return count - - async def find_one_file( - self, - filter, - projection = None, - session = None, - raise_exception = False - ): - - """ - Finds one record that matches the given conditions. This does NOT return the file itself, it returns the record - that describes the file. - :param filter: The filter criteria. - :param projection: What parts of the matching data you want to fetch. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The matching record or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # try to query the data: - try: results = await self._db["fs.files"].find_one(filter, projection, session = session) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Check results and return: - return results - - async def find_many_files( - self, - filter, - projection = None, - skip = 0, - limit = None, - sort = None, - session = None, - raise_exception = False - ): - - """ - Finds one or more records that match the given conditions. This doesn't return any actual files directly, it - returns the records that describe the files. - :param filter: The filter criteria. - :param projection: What parts of the matching data you want to fetch. - :param skip: The no. of records to skip before picking next ones. Needed for pagination. - :param limit: The max. no. of records you want to fetch. - :param sort: The sorting rules to apply. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The array of matching records or null if there was an exception. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - results = None - - # Assume defaults: - if sort is None: sort = {"_id": -1} - if limit is None: limit = 10 - - # try to query the data: - try: - results = await self._db["fs.files"].find( - filter, - projection, - session = session - ).sort(sort).skip(skip).limit(limit).to_list(None) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return results - - async def update_metadata_for_one_file( - self, - filter: dict, - unset_data: dict = None, - set_data: dict = None, - session = None, - raise_exception = False - ): - - """ - Updates the metadata for one file. - :param filter: The conditions to filter the files by. - :param unset_data: The fields that you want to discard. - :param set_data: The fields that you want to add or update. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to make the update: - try: - - # Input pre-processing: - update = {} - if unset_data is not None: update["$unset"] = self.dict_to_dot_notation({"metadata": unset_data}) - if set_data is not None: update["$set"] = self.dict_to_dot_notation({"metadata": set_data}) - - # Actual update happens here: - if update: - response = await self._db["fs.files"].update_one( - filter, - update, - session = session - ) - success = False if response.modified_count == 0 else True - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def update_metadata_for_many_files( - self, - filter: dict, - unset_data: dict = None, - set_data: dict = None, - session = None, - raise_exception = False - ): - - """ - Updates the metadata for many files. Practically the same as 'update_metadata_for_one' except that the scope of - the modifications is far wider. - :param filter: The conditions to filter the files by. - :param unset_data: The fields that you want to discard. - :param set_data: The fields that you want to add or update. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = None - - # Try to make the update: - try: - - # Input pre-processing: - update = {} - if unset_data is not None: update["$unset"] = self.dict_to_dot_notation({"metadata": unset_data}) - if set_data is not None: update["$set"] = self.dict_to_dot_notation({"metadata": set_data}) - - # Actual update happens here: - if update: - response = await self._db["fs.files"].update_many( - filter, - update, - session = session - ) - count = response.modified_count - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return count - - async def replace_metadata_for_one_file( - self, - filter: dict, - replacement, - session = None, - raise_exception = False - ): - - """ - Updates the metadata for one file. - :param filter: The conditions to filter the files by. - :param replacement: The new metadata to put inplace of the old one. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to make the update: - try: - - # Actual update happens here: - result = await self._db["fs.files"].update_one( - filter, - {"$set": {"metadata": replacement}}, - upsert = False, - session = session - ) - if result.modified_count or result.upserted_id: success = True - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def replace_metadata_for_many_files( - self, - filter: dict, - replacement, - session = None, - raise_exception = False - ): - - """ - Updates the metadata for one file. - :param filter: The conditions to filter the files by. - :param replacement: The new metadata to put inplace of the old one. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = None - - # Try to make the update: - try: - - # Actual update happens here: - response = await self._db["fs.files"].update_many( - filter, - {"$set": {"metadata": replacement}}, - session = session - ) - count = response.modified_count - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return count - - async def delete_file_by_id( - self, - file_id, - session = None, - raise_exception = False - ): - - """ - Deletes one file by the file's id. Deleting files is different from deleting simple documents because, in files, - you also need to clear out the chunks (which are stored in a separate collection). The built-in mechanism of - Motor only provides support to delete by the file's id. - :param file_id: The id of the file that you want to delete. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Try to read the file: - try: - - # Delete the file: - await self._fs.delete(file_id = file_id, session = session) - success = True - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return success - - async def delete_one_file( - self, - filter, - session = None, - raise_exception = False - ): - - """ - To delete one document from a collection. - :param filter: The filter criteria. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: True or False based on the success of the operation. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - success = False - - # Find one file that matches the given filter: - file = await self.find_one( - collection = "fs.files", - filter = filter, - session = session, - raise_exception = raise_exception - ) - - # If we have a list of files to work with: - if file: success = await self.delete_file_by_id(file["_id"]) - - # Done here: - return success - - async def delete_many_files( - self, - filter, - session = None, - raise_exception = False - ): - - """ - To delete many documents from a collection. - WARNING: sending {} in the filter would mean deleting ALL the documents. - :param filter: The filter criteria. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The number of files deleted (can be zero) or None if something failed while searching the files. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - count = 0 - - # Find all the files that match the given filter: - files = await self.find_many( - filter = filter, - session = session, - raise_exception = raise_exception - ) - - # If we have a list of files to work with: - if files is not None: - tasks = [self.delete_file_by_id(file["_id"]) for file in files] - results = await asyncio.gather(*tasks) - count = sum(results) - - # Done here: - return count - - async def get_upload_stream( - self, - file_name: str, - file_metadata: dict = None, - file_id = None, - chunk_size: int = None, - session = None, - raise_exception = False - ): - - """ - Returns a GridIn object so that you can perform your own upload using the built-in writing methods. You must use - the 'write' method to write data to the file by passing it either a string of bytes or a file-like object. When - the file has been fully written, you must call the 'close' method to finish the operation. In case you need to - cancel the operation, you can call the 'abort' method to delete all the already written data and stop uploading - new data. - :param file_name: The name of the file as it will be stored on (and retrieved from) GridFS. - :param file_metadata: Any metadata to later search the file by. - :param file_id: Any custom id to be given to the file. TRY STICKING TO THE ID GENERATED BY 'generate_id'. - :param chunk_size: The chunk size (in bytes) to use for storing this file. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The upload stream that implements the 'write', 'close', and 'abort' methods, or None if something - failed. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - stream = None - - # Try to open the upload stream: - try: - - # If no file id was supplied: - if file_id is None: - stream = self._fs.open_upload_stream( - filename = file_name, - metadata = file_metadata, - chunk_size_bytes = chunk_size, - session = session - ) - - # If a file id was supplied: - else: - stream = self._fs.open_upload_stream_with_id( - file_id = file_id, - filename = file_name, - metadata = file_metadata, - chunk_size_bytes = chunk_size, - session = session - ) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return stream - - async def get_download_stream( - self, - file_id = None, - file_name = None, - session = None, - raise_exception = False - ): - - """ - Returns a GridOut object so that you can implement your own download logic using the built-in 'read' method. - Once the reading is done, use the 'close' method to release the resources used by the stream. - :param file_id: (RECOMMENDED) the id of the save file. - :param file_name: The name of the saved file. NOT RECOMMENDED because you could have many files with the same - name. The best way to tell files apart if from the id. - :param session: The session if you need to do this in a transaction. - :param raise_exception: Whether, or not, you want to raise an exception when something fails. - :return: The download stream that implements the 'read' and 'close' methods, or None if something failed. - """ - - # Ensure you are connected: - await self.ensure_connection() - - # Assume failure: - stream = None - - # Try to open a download stream: - try: - - # If a file id is supplied (preferred way): - if file_id is not None: - stream = await self._fs.open_download_stream( - file_id = file_id, - session = session - ) - - # If a file name is supplied: - elif file_name is not None: - stream = await self._fs.open_download_stream_by_name( - filename = file_name, - session = session - ) - - # When something goes wrong: - except Exception as exception: - self._printer(exception) - if raise_exception: raise - - # Done here: - return stream - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - from shared import constants - - async def main(): - - # Create an instance of the database connector: - my_db = AsyncMongo( - connection_string = constants.MONGO_DATA_CONNECTION_STRING, - database_name = constants.MONGO_DATA_DATABASE_NAME, - max_connections = 10, - debug = True - ) - - # Connect to the database: - await my_db.connect() - - # # Get the documents to migrate: - # documents = await my_db.find_many( - # collection = "scriptData", - # filter = {}, - # limit = 50, - # projection = {"_id": False} - # ) - # # print(json.to_string(documents, default = str)) - # - # # Adjust them: - # adjusted_documents = [] - # for document in documents: - # script_id = document.pop("scriptId") - # adjusted_document = { - # "scriptId": script_id, - # "desc": "no desc", - # "content": document - # } - # adjusted_documents.append(adjusted_document) - # print(json.to_string(adjusted_documents, default = str)) - # - # # Insert the adjusted ones to the new collection: - # response = await my_db.insert_many( - # collection = "_scriptData", - # documents = adjusted_documents - # ) - # print("RESPONSE:", response) - - - asyncio.run(main()) diff --git a/utils_v2/database/async_mysql_v2.py b/utils_v2/database/async_mysql_v2.py deleted file mode 100644 index f4cac6e..0000000 --- a/utils_v2/database/async_mysql_v2.py +++ /dev/null @@ -1,424 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Friday, 30th Aug., 2024 - - OBJECTIVE: - - To be able to access SQL-based databases from python in a simple way. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# MySQL Database: -import aiomysql -import decimal - -# For data-crunching: -import pandas as pd - -# For time-keeping: -import time - -# OS-level operations: -import os - -# My utils: -from utils_v2.string import json - -# For async activities: -import asyncio - -# For debugging: -from icecream import IceCreamDebugger -import traceback - -# To work with datatypes: -from typing import List - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncMySQL: - - def __init__( - self, - pool_size, - *args, - **kwargs - ): - - """ - A class to work with SQL-based databases. Originally meant to only invoke stored procedures and retrieve them as - JSON-like structures (list or dict). The format for the results was very specific to our use case for serving - Bicree's requirement. This may not serve your requirement at all. - :param pool_size: The number of connections to maintain n a pool. - :param args: Any arguments to pass. Not used. - :param kwargs: Pass the connection configuration from here. - """ - - # Set up the variables: - self.__args = args - self.__kwargs = kwargs - self.__min_pool_size = 10 - self.__max_pool_size = max(pool_size, self.__min_pool_size) - self.__pool = None - - # Set up the debugging tools: - self.__printer = IceCreamDebugger(prefix = "MySQL | ", includeContext = True) - - def __del__(self): - pass - - async def connect(self): - - """ - Establish a connection and create a pool of connections to call from. - :return: None. - """ - - try: - - self.__kwargs["db"] = self.__kwargs.pop("database") - self.__pool = await aiomysql.create_pool( - minsize = self.__min_pool_size, - maxsize = self.__max_pool_size, - loop = asyncio.get_event_loop(), - **self.__kwargs - ) - - except Exception as exception: - self.__printer(exception) - self.__pool = None - - async def ensure_connection(self): - - """ - Tries to ensure that a connection is present. - Can be called before every function to make sure that our pool is established. - :return: None. - """ - - if self.__pool is None: await self.connect() - - @staticmethod - def __parse_row(row): - - """ - Converts from the custom objects of 'aiomysql' to types that are supported by Python. - :param row: The row from the result. - :return: The parsed row which will have types that are closer to being native to Python.. - """ - - parsed_row = [] - for item in row: - if isinstance(item, decimal.Decimal): parsed_row.append(float(item)) - else: parsed_row.append(item) - return parsed_row - - async def fetch_all(self, cursor): - - # Make a variable to hold all the result sets. - # Needed for when the procedure responds with many "tables": - all_result_sets = [] - - # Iterate over all result sets, - # and process them one-by-one: - while True: - - # Process the current result set: - this_result_set = [] - result = await cursor.fetchall() - if not cursor.description: break - columns = [desc[0] for desc in cursor.description] - for row in result: this_result_set.append(dict(zip(columns, self.__parse_row(row)))) - all_result_sets.append(this_result_set) - - # Move to the next set, - # or break out of the loop if all done: - if not await cursor.nextset(): break - - # Done here: - return all_result_sets - - async def call_procedure(self, procedure_name, procedure_args): - - """ - To call stored procedures and retrieve all the responses. - :param procedure_name: The name of the stored procedure that must be called. - :param procedure_args: The args to be sent to the stored procedure. - :return: The raw result set as received from the database. - """ - - # Make sure we have a connection: - await self.ensure_connection() - - # Make a variable to hold all the result sets. - # Needed for when the procedure responds with many "tables": - all_result_sets = [] - - # Call the procedure and get the results: - async with self.__pool.acquire() as connection: - async with connection.cursor() as cursor: - await cursor.callproc(procedure_name, procedure_args) - all_result_sets = await self.fetch_all(cursor) - - # # Iterate over all result sets, - # # and process them one-by-one: - # while True: - # this_result_set = [] - # result = await cursor.fetchall() - # if not cursor.description: break - # columns = [desc[0] for desc in cursor.description] - # for row in result: this_result_set.append(dict(zip(columns, self.__parse_row(row)))) - # all_result_sets.append(this_result_set) - # await cursor.nextset() - - # Done here: - return all_result_sets - - async def call_procedure_and_get_json( - self, - procedure_name, - procedure_args, - retry_count = 1, - backoff_seconds = 0.5, - backoff_multiplier = 1.1, - return_exception = False - ): - - """ - The method to call when you need to call a stored procedure and retrieve the response as a JSON-like object. - This is custom formatting based on the structure created by Mr. bhushan Thakkar in late April (2024). - :param procedure_name: The name of the stored procedure that must be called. - :param procedure_args: The args to be sent to the stored procedure. - :param retry_count: The max. number of times to try in case one or more attempts fail. - :param backoff_seconds: The time to wait before making the next attempt if the retry count is more than 1. - :param backoff_multiplier: The factor that dictates how much to modify the time delay by when waiting to retry. - :param return_exception: Whether, or not, you would like to return the exception object if something goes wrong. - :return: The formatted response and the exception (if asked for). - """ - - # Note down the start time: - start_ts = time.time() - - # Try to get the data from the database: - results = [] - exception = None - for _ in range(retry_count): - try: results = await self.call_procedure( - procedure_name = procedure_name, - procedure_args = procedure_args, - ) - except Exception as exc: exception = exc - if exception is None: break - await asyncio.sleep(backoff_seconds) - backoff_seconds = backoff_seconds * backoff_multiplier - - # If the results are blank: - if len(results) == 0: - formatted_results = { - "status": 0, - "message": "Please contact admin (NE)" if exception is None else "Please contact admin (E)", - "seconds": time.time() - start_ts, - "data": {} - } - if return_exception: return formatted_results, exception - else: return formatted_results - - # Extract the very basic success or failure indicators: - formatted_results = { - "status": results[0][0]["status"], - "message": results[0][0].get("message", "ok"), - "seconds": 0.0, - "data": {} - } - - # Handle the remaining keys of the zeroth result set: - for key, value in results[0][0].items(): - if key not in formatted_results.keys(): - formatted_results["data"][key] = value - - # Format - for index in range(len(results)): - if index > 0: formatted_results["data"][f"rs{index-1}"] = results[index] - - # Note down the time taken: - formatted_results["seconds"] = time.time() - start_ts - - # Done here: - if return_exception: return formatted_results, exception - else: return formatted_results - - async def execute_one( - self, - query: str, - commit: bool = True, - return_exception: bool = False - ): - - """ - Runs one command / query in SQL. - :param query: The query / command to run. - :param commit: Whether, or not, you would like to commit the execution. - :param return_exception: Whether, or not, you would like to return the exception from this function. - :return: Either just the result or the result and the exception. - """ - - # Make sure we have a connection: - await self.ensure_connection() - - # Start by assuming failure: - rows_affected = None - results = None - excp = None - - try: - - # Get a connection and execute the command: - async with self.__pool.acquire() as connection: - async with connection.cursor() as cursor: - rows_affected = await cursor.execute(query) - results = await self.fetch_all(cursor) - if commit: await connection.commit() - - # SQL-specific errors: - except aiomysql.MySQLError as exception: - self.__printer("SQL Exception", exception) - excp = exception - - # Other errors: - except Exception as exception: - self.__printer("Other Exception", exception) - excp = exception - - # Done here: - if return_exception: return rows_affected, results, excp - else: return rows_affected, results - - async def execute_many( - self, - query: str, - data: List[tuple], - commit: bool = True, - return_exception: bool = False - ): - - """ - Runs many commands / queries in SQL. - Consider the following example: - QUERY: "INSERT INTO pincodeMaster (pincode, city, state) VALUES (%s, %s, %s);" - DATA: [ - ('110001', 'New Delhi', 'Delhi'), - ('500001', 'Hyderabad', 'Telangana'), - ('600001', 'Chennai', 'Tamil Nadu') - ] - :param query: The query / command to run. - :param data: The data to substitute into the query string. - :param commit: Whether, or not, you would like to commit the execution. - :param return_exception: Whether, or not, you would like to return the exception from this function. - :return: Either just the result or the result and the exception. - """ - - # Make sure we have a connection: - await self.ensure_connection() - - # Start by assuming failure: - rows_affected = None - results = None - excp = None - - try: - - # Get a connection and execute the command: - async with self.__pool.acquire() as connection: - async with connection.cursor() as cursor: - rows_affected = await cursor.executemany(query, data) - results = await self.fetch_all(cursor) - if commit: await connection.commit() - - # SQL-specific errors: - except aiomysql.MySQLError as exception: - self.__printer("SQL Exception", exception) - excp = exception - - # Other errors: - except Exception as exception: - self.__printer("Other Exception", exception) - excp = exception - - # Done here: - if return_exception: return rows_affected, results, excp - else: return rows_affected, results - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/dataframe/__init__.py b/utils_v2/dataframe/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/dataframe/splitter.py b/utils_v2/dataframe/splitter.py deleted file mode 100644 index 7725905..0000000 --- a/utils_v2/dataframe/splitter.py +++ /dev/null @@ -1,118 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 22nd Oct., 2024 - - OBJECTIVE: - - To provide an easy way to split dataframes into chunks and divide the workload nto more manageable batches. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - - USAGE EXAMPLE: - - for sub_df in DataFrameSplitter(df, chunk_size = 50): - - # Do your task here: - pass - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class DataFrameSplitter: - - def __init__(self, df, chunk_size): - - """ - Use this to process your dataframe in batches. Useful for when you need to send out alerts at intervals or need - to maintain checkpoints. - :param df: The dataframe to iterate over. - :param chunk_size: The max. no. of rows to pick at once. - """ - - self.df = df - self.row_count = df.shape[0] - self.chunk_size = chunk_size - self.offset = 0 - - def __iter__(self): - self.offset = 0 - return self - - def __next__(self): - if self.offset >= self.row_count: - raise StopIteration - end = self.offset + self.chunk_size - chunk = self.df.iloc[self.offset:end] - self.offset = end - return chunk - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/date_time/__init__.py b/utils_v2/date_time/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/date_time/date_time.py b/utils_v2/date_time/date_time.py deleted file mode 100644 index c882b15..0000000 --- a/utils_v2/date_time/date_time.py +++ /dev/null @@ -1,335 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Friday, 21st jun, 2024 - - OBJECTIVE: - - To provide an easy way to work with time. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For date and time handling: -import pytz -from datetime import datetime, time, timedelta, tzinfo -import dateparser - -# To handle date-time objects from a Numpy array and Pandas Dataframe: -import numpy as np -import pandas as pd - -# To work with datatypes: -from typing import List - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# Date-Time Formats: -DATE_TIME_FORMATS = ( - "%d/%m/%y", - "%d-%b-%y", - "%d-%m-%y", - "%d.%m.%y", - "%d/%m/%Y", - "%d-%b-%Y", - "%d-%m-%Y", - "%d.%m.%Y", - "%d/%b", - "%d%m%Y", - "%Y%m%d", - "%Y-%m-%d %H:%M:%S" -) - -# Useful Timezones: -TIMEZONE_UTC = pytz.timezone("UTC") -TIMEZONE_IST = pytz.timezone("Asia/Kolkata") -TIMEZONE_ET = pytz.timezone("America/New_York") -TIMEZONE_CT = pytz.timezone("America/Chicago") -TIMEZONE_MT = pytz.timezone("America/Denver") -TIMEZONE_PT = pytz.timezone("America/Los_Angeles") -TIMEZONE_JST = pytz.timezone("Asia/Tokyo") -TIMEZONE_CET = pytz.timezone("Europe/Paris") -TIMEZONE_GMT = pytz.timezone("GMT") -TIMEZONE_AEST = pytz.timezone("Australia/Sydney") -TIMEZONE_NZST = pytz.timezone("Pacific/Auckland") -TIMEZONE_CST = pytz.timezone("Asia/Shanghai") -TIMEZONE_KST = pytz.timezone("Asia/Seoul") -TIMEZONE_MSK = pytz.timezone("Europe/Moscow") -TIMEZONE_BRT = pytz.timezone("America/Sao_Paulo") -TIMEZONE_GST = pytz.timezone("Asia/Dubai") -TIMEZONE_SAST = pytz.timezone("Africa/Johannesburg") -TIMEZONE_AST = pytz.timezone("Asia/Riyadh") - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def translate_date_time_string( - datetime_string: str, - source_format: str = None, - destination_format: str = "%Y-%m-%dT%H:%M:%S" -) -> str | None: - - """ - To convert an input datetime string to a different format. - :param datetime_string: The datetime string to translate. - :param source_format: The current format of the string. If not provided, dateparser will be used. - :param destination_format: The format to convert to. - :return: The converted datetime string. - """ - - try: - - if source_format is None: datetime_obj = dateparser.parse(datetime_string) - else: datetime_obj = datetime.strptime(datetime_string, source_format) - return datetime_obj.strftime(destination_format) - - except Exception as exception: - return None - - -# --------------------------------------------------------------------------------------------------------------------- - - -def parse_date_time( - input_value: datetime | str | int | float, - timezone: str | tzinfo = None, - date_formats: List[str] = None -) -> datetime: - - """ - To take any kind of input and interpret the datetime from it. - :param input_value: Either a string or an integer or some form of datetime representation. - :param timezone: The timezone to apply to the interpreted datetime. IF THE INPUT IS NAIVE, THIS TIMEZONE WILL BE - APPLIED AS IS, ELSE THE TIMEZONE WILL BE TRANSLATED. - :param date_formats: The string formats to consider when parsing a string input. - :return: The parsed datetime or null. - """ - - datetime_object = None - date_formats = date_formats or DATE_TIME_FORMATS - - # It could either be in seconds or milliseconds from epoch time's base date (January 1, 1970), - # or it could be days since Microsoft Excel's base date (December 31, 1899). - if isinstance(input_value, (int, float, np.number)) and not np.isnan(input_value): - if input_value > 9999999999.0: datetime_object = datetime.fromtimestamp(input_value / 1000.0) - if input_value > 999999.0: datetime_object = datetime.fromtimestamp(input_value) - else: datetime_object = datetime.fromtimestamp(input_value * 24 * 60 * 60.0) - timedelta(days = 25569) - - # The input can even be a pre-formatted date: - if isinstance(input_value, str): - datetime_object = dateparser.parse( - input_value, - date_formats = date_formats, - settings = { - "DATE_ORDER": "DMY", - "PREFER_DAY_OF_MONTH": "first", - } - ) - - # If the type is a datetime object, then return it as it is: - if isinstance(input_value, datetime): - datetime_object = input_value - - # If the type is the native datetime format of pandas: - if isinstance(input_value, pd._libs.tslibs.timestamps.Timestamp): - datetime_object = input_value.to_pydatetime() - - # Process the timezone: - if datetime_object is not None and timezone is not None: - datetime_object = to_timezone(datetime_object, timezone) - - # Done here: - return datetime_object - - -# --------------------------------------------------------------------------------------------------------------------- - - -def get_current_date_time( - timezone: str | tzinfo = None, - as_string: bool = False -) -> datetime: - - """ - Returns the current time as a datetime object. - :param timezone: The timezone to apply to the returned datetime. - :param as_string: Whether, or not, you want the output as a string. - :return: The datetime object/string representing the current time. - """ - - if timezone is not None and isinstance(timezone, str): timezone = pytz.timezone(timezone) - now = datetime.now(timezone) - return now.isoformat() if as_string else now - - -# --------------------------------------------------------------------------------------------------------------------- - - -def get_current_ist_date_time( - as_string = False -) -> datetime: - - """ - Gives out the current time in IST timezone. - :param as_string: Whether, or not, you want the output as a string. - :return: The datetime object or string representing the current time. - """ - - return get_current_date_time( - timezone = TIMEZONE_IST, - as_string = as_string - ) - - -# --------------------------------------------------------------------------------------------------------------------- - - -def get_current_utc_date_time( - as_string: bool = False -) -> datetime: - - """ - Gives out the current time in UTC timezone. - :param as_string: Whether, or not, you want the output as a string. - :return: The datetime object or string representing the current time. - """ - - return get_current_date_time( - timezone = TIMEZONE_UTC, - as_string = as_string - ) - - -# --------------------------------------------------------------------------------------------------------------------- - - -def as_if_timezone( - datetime_object: datetime, - timezone: str | tzinfo -) -> datetime: - - """ - Ignores existing timezone info and applies the intended timezone. - The time stays the same, only the timezone marker changes. - e.g. for IST to UTC: 2024-08-09 00:00:00+05:30 --> 2024-08-09 00:00:00+00:00 - HINT: IT PRETENDS "AS IF" THE TIMEZONE WAS THE INPUT TIMEZONE. - :param datetime_object: The datetime object on which the timezone needs to be applied. - :param timezone: The timezone that needs to be applied. - :return: A timezone-aware datetime object. - """ - - tz_object = pytz.timezone(timezone) if isinstance(timezone, str) else timezone - return tz_object.localize(datetime_object.replace(tzinfo = None)) - - -# --------------------------------------------------------------------------------------------------------------------- - - -def to_timezone( - datetime_object: datetime, - timezone: str | tzinfo -) -> datetime: - - """ - Converts from one timezone to another. The time is adjusted by computing the difference between the two timezones. - NOTE: THIS FUNCTION APPLIES TH EINPUT TIMEZONE IF THE INPUT DATETIME WAS TIMEZONE-NAIVE. - e.g. for IST to UTC: 2024-08-09 00:00:00+05:30 --> 2024-08-08 18:30:00+00:00 - :param datetime_object: The datetime object on which the timezone needs to be applied. - :param timezone: The timezone that needs to be applied. - :return: A timezone-aware datetime object. - """ - - if isinstance(timezone, str): timezone = pytz.timezone(timezone) - if datetime_object.tzinfo is None: return datetime_object.replace(tzinfo = timezone) - return datetime_object.astimezone(timezone) - - -# --------------------------------------------------------------------------------------------------------------------- - - -def round_datetime( - datetime_object: datetime, - seconds: int -) -> datetime: - - """ - 'Snaps' the time to the closest 'n-second' window. For example, if you want to round the time off to the nearest - 5-minute period (maybe for use cases like trading), you set the value of seconds to 300. This way any input value - of, say, 12:01:50 AM gets converted to 12:00:00 AM; and a value of 12:02:31 AM gets converted to 12:05:00 AM. - :param datetime_object: The input datetime that you want to round off. - :param seconds: The period of rounding in seconds. 60 for 1 minute, 300 for 5 minutes and so on. - :return: The rounded date-time (with the original timezone). - """ - - # For timezone-naive cases: - if datetime_object.tzinfo is None: - total_seconds = datetime_object.timestamp() - rounded_seconds = round(total_seconds / seconds) * seconds - rounded_datetime = datetime.fromtimestamp(rounded_seconds) - return rounded_datetime - - # For timezone-aware cases: - else: - original_tz = datetime_object.tzinfo - _dt = to_timezone(datetime_object, timezone = original_tz) - total_seconds = _dt.timestamp() - rounded_seconds = round(total_seconds / seconds) * seconds - rounded_datetime = datetime.fromtimestamp(rounded_seconds, tz = original_tz) - return rounded_datetime - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/goog/__init__.py b/utils_v2/goog/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/goog/base.py b/utils_v2/goog/base.py deleted file mode 100644 index f371bdf..0000000 --- a/utils_v2/goog/base.py +++ /dev/null @@ -1,450 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 26th Nov., 2024 - - OBJECTIVE: - - To provide a base class for common behaviour of Google's APIs. - - REFERENCES: - - 1. Quickstart: https://developers.google.com/gmail/api/quickstart/python - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# My utils: -from utils_v2.date_time import date_time -from utils_v2.goog.models.data.api_call import GoogleApiResponse -from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens - -# Related to Google: -from google_auth_oauthlib.flow import InstalledAppFlow - -# To make API calls: -import httpx - -# To work with date and time: -import datetime - -# For working with datatypes: -from typing import Literal, List - -# For debugging: -from icecream import IceCreamDebugger -import inspect - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncGoogleBase: - - def __init__( - self, - service_name: str, - oauth_json: dict, - http_client: httpx.AsyncClient, - scopes: List[str] = None, - redirect_url: str = None, - debug = True, - debug_prefix = "GMail | ", - debug_only_errors = True - ): - - """ - To initialize any Google API from one base class. The client's id and secret are available in the file - downloaded form https://console.cloud.google.com/apis/credentials (do not forget to select your app). - :param service_name: A string to identify this service. - :param oauth_json: The OAuth credentials downloaded from https://console.cloud.google.com/apis/credentials - :param http_client: An asynchronous HTTP client to make API calls. - :param redirect_url: Where you would like to receive the confirmation of the user authorization. - :param scopes: The list of permissions needed for this particular authorization. - :param debug: Whether, or not, you would like to show debugging messages on the terminal. - :param debug_prefix: The prefix string to identify the debugging messages. - :param debug_only_errors: Whether you would like to show all debugging messages or just error messages. - """ - - # Prepare the debugging utility: - self._debug_prefix = debug_prefix - self._printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self._printer.disable() - self._debug_only_errors = debug_only_errors - - # Accept the input configuration: - self._service_name = service_name - self._http_client = http_client - self._oauth_json = oauth_json - self._client_id = self._oauth_json["web"]["client_id"] - self._client_secret = self._oauth_json["web"]["client_secret"] - self._redirect_url = redirect_url - self._flow = InstalledAppFlow.from_client_config( - self._oauth_json, - scopes = scopes, - redirect_uri = self._redirect_url - ) - - def enable_debug(self): - self._printer.enable() - - def disable_debug(self): - self._printer.disable() - - def debug_only_errors(self): - self._debug_only_errors = True - - def debug_everything(self): - self._debug_only_errors = False - - # ┏┓┏┓ ┓ ┏┓ ┏┓ - # ┃┃┣┫┓┏╋┣┓ ┏┛ ┃┫ - # ┗┛┛┗┗┻┗┛┗ ┗━•┗┛ - - async def get_authorization_url( - self, - state: str = None, - access_type: Literal["online", "offline"] = "offline", - approval_prompt: Literal["auto", "force", "consent"] = "force", - include_granted_scopes: Literal["true", "false"] = "true", - user_email: str = None - ) -> str: - - """ - TO get the OAuth2.0 authorization URL for one user. - DOCUMENTATION: - 1. https://developers.google.com/identity/protocols/oauth2/web-server - :param state: A unique identifier for your user. If not supplied, a random string will be generated. - :param access_type: Set the value to offline if your application needs to refresh access tokens when the user is - not present at the browser. - :param approval_prompt: "force" ensures that the consent screen is always shown to the user, regardless of - whether the user has previously granted consent for the requested scopes. It forces the user to re-approve - the app's access, which can be useful if the app is requesting new permissions or if the consent needs to be - explicitly confirmed. "consent" ensures the user's consent is required if they haven't approved the app's - requested permissions yet. "auto" allows Google to automatically determine whether the consent screen should - be shown. - :param include_granted_scopes: Enables applications to use incremental authorization to request access to - additional scopes in context. If you set this parameter's value to true and the authorization request is - granted, then the new access token will also cover any scopes to which the user previously granted the - application access. - :param user_email: - :return: - """ - - # Get an authorization URL: - auth_url, state = self._flow.authorization_url( - access_type = access_type, - approval_prompt = approval_prompt, - include_granted_scopes = include_granted_scopes, - login_hint = user_email, - state = state - ) - - # Done here: - return auth_url - - async def get_authorization_tokens( - self, - redirect_url: str - ) -> GoogleAuthTokens: - - """ - When the user accepts or declines an authorization request, Google sends you an alert on your redirect URL. Pass - the URL as it is to this method to generate the authorization tokens that you can store in the database and - reuse for this user's activities. - :param redirect_url: The exact URL that was hit (with the query params) that Google hit when the user did - something on your authorization URL. Fortunately, this URL is readily available in Quart and Flask by - calling 'request.url'. - :return: The authorization tokens. - """ - - credentials = self._flow.fetch_token(authorization_response = redirect_url) - ttl = credentials["expires_in"] - 60 - return GoogleAuthTokens( - accessToken = credentials.get("access_token"), - refreshToken = credentials.get("refresh_token"), - expiresAt = date_time.get_current_utc_date_time() + datetime.timedelta(seconds = ttl), - scopes = credentials.get("scope") - ) - - # ┏┓ ┳┓ ┓• - # ┣ ┏┓┏┓┏┓┏┓ ┃┃┏┓┏┏┓┏┫┓┏┓┏┓ - # ┗┛┛ ┛ ┗┛┛ ┻┛┗ ┗┗┛┗┻┗┛┗┗┫ - # ┛ - - @staticmethod - async def __get_error_message(api_response: GoogleApiResponse) -> str: - - """ - To extract various kinds of error messages from Google's responses. - :param api_response: The formatted response from the API call. - :return: The message string. - """ - - try: return (await api_response.get_json())["error"]["message"] - except: return api_response.response.reason_phrase - - # ┏┓┏┓┳ ┏┓ ┓┓• - # ┣┫┃┃┃ ┃ ┏┓┃┃┓┏┓┏┓ - # ┛┗┣┛┻ ┗┛┗┻┗┗┗┛┗┗┫ - # ┛ - - async def get( - self, - url: str, - headers: dict = None, - params: dict = None - ) -> GoogleApiResponse: - - """ - To call an API using the GET method. - :param url: The URL to call. - :param headers: The headers to pass. - :param params: The params to send in the query string itself. - :return: A structured response that includes the raw response, the exception (if any), and so on. - """ - - # Prepare the structure of the response: - api_response = GoogleApiResponse( - serviceName = self._service_name, - action = inspect.stack()[1].function, - url = url, - method = "GET" - ) - - try: - - # Make the API call: - response = await self._http_client.get( - url = url, - headers = headers, - params = params - ) - - # Note down the results: - api_response.response = response - api_response.httpCode = response.status_code - api_response.message = await self.__get_error_message(api_response) - - # If something goes wrong: - except Exception as exception: - api_response.exception = exception - api_response.message = str(exception) - self._printer(exception, api_response.url, api_response.method, headers, params) - - # Done here: - return api_response - - async def post( - self, - url: str, - headers: dict = None, - json: dict = None, - data: dict = None, - content: str | bytes = None - ) -> GoogleApiResponse: - - """ - To call an API using the POST method. - :param url: The URL to call. - :param headers: The headers to pass. - :param json: The params to send in the JSON body. - :param data: The params to send in the form-data in the body. - :param content: The raw content to be sent in the body (typically as an octet-stream). - :return: A structured response that includes the raw response, the exception (if any), and so on. - """ - - # Prepare the structure of the response: - api_response = GoogleApiResponse( - serviceName = self._service_name, - action = inspect.stack()[1].function, - url = url, - method = "POST" - ) - - try: - - # Make the API call: - response = await self._http_client.post( - url = url, - headers = headers, - json = json, - data = data, - content = content - ) - - # Note down the results: - api_response.response = response - api_response.httpCode = response.status_code - api_response.message = await self.__get_error_message(api_response) - - # If something goes wrong: - except Exception as exception: - api_response.exception = exception - api_response.message = str(exception) - self._printer(exception, api_response.url, api_response.method, headers, json, data) - - # Done here: - return api_response - - async def put( - self, - url: str, - headers: dict = None, - json: dict = None, - data: dict = None - ) -> GoogleApiResponse: - - """ - To call an API using the PUT method. - :param url: The URL to call. - :param headers: The headers to pass. - :param json: The params to send in the JSON body. - :param data: The params to send in the form-data in the body. - :return: A structured response that includes the raw response, the exception (if any), and so on. - """ - - # Prepare the structure of the response: - api_response = GoogleApiResponse( - serviceName = self._service_name, - action = inspect.stack()[1].function, - url = url, - method = "PUT" - ) - - try: - - # Make the API call: - response = await self._http_client.put( - url = url, - headers = headers, - json = json, - data = data - ) - - # Note down the results: - api_response.response = response - api_response.httpCode = response.status_code - api_response.message = await self.__get_error_message(api_response) - - # If something goes wrong: - except Exception as exception: - api_response.exception = exception - api_response.message = str(exception) - self._printer(exception, api_response.url, api_response.method, headers, json, data) - - # Done here: - return api_response - - async def delete( - self, - url: str, - headers: dict = None - ) -> GoogleApiResponse: - - """ - To call an API using the DELETE method. - :param url: The URL to call. - :param headers: The headers to pass. - :return: A structured response that includes the raw response, the exception (if any), and so on. - """ - - # Prepare the structure of the response: - api_response = GoogleApiResponse( - serviceName = self._service_name, - action = inspect.stack()[1].function, - url = url, - method = "DELETE" - ) - - try: - - # Make the API call: - response = await self._http_client.delete( - url = url, - headers = headers - ) - - # Note down the results: - api_response.response = response - api_response.httpCode = response.status_code - api_response.message = await self.__get_error_message(api_response) - - # If something goes wrong: - except Exception as exception: - api_response.exception = exception - api_response.message = str(exception) - self._printer(exception, api_response.url, api_response.method, headers) - - # Done here: - return api_response - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/goog/gmail/__init__.py b/utils_v2/goog/gmail/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/goog/gmail/gmail_client.py b/utils_v2/goog/gmail/gmail_client.py deleted file mode 100644 index d968ca5..0000000 --- a/utils_v2/goog/gmail/gmail_client.py +++ /dev/null @@ -1,980 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Monday, 25th Nov., 2024 - - OBJECTIVE: - - To manage e-mails in a GMail account. - - REFERENCES: - - 1. Quickstart: https://developers.google.com/gmail/api/quickstart/python - 2. Labels: https://developers.google.com/gmail/api/guides/labels - 3. Messages: https://developers.google.com/gmail/api/reference/rest/v1/users.messages - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -from http.client import responses - -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# My utils: -from utils_v2.string import json -from utils_v2.string import regex -from utils_v2.date_time import date_time -from utils_v2.mail import mail_parser - -# My Google utils: -from utils_v2.goog.base import AsyncGoogleBase -from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens -from utils_v2.goog.models.data.api_call import GoogleApiResponse -from utils_v2.goog.gmail.gmail_message import GMailMessage - -# Related to Google: -from google.auth.transport.requests import Request -from google.oauth2.credentials import Credentials -from googleapiclient.discovery import build - -# To make API calls: -import httpx - -# For asynchronous activities: -import asyncio - -# To work with date and time: -import datetime - -# For working with datatypes: -from typing import Dict, Literal, List, Any - -# For debugging: -from icecream import IceCreamDebugger -import inspect - -# For computational help: -import math - -# For base64 encoding: -import base64 - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# Google Scopes: -SCOPES_GMAIL_MAIL_MANAGEMENT = [ - r"https://www.googleapis.com/auth/gmail.modify", - r"https://www.googleapis.com/auth/gmail.labels" -] -SCOPES_GMAIL_FULL = [r"https://mail.google.com/"] - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncGMailClient(AsyncGoogleBase): - - async def get_user_profile( - self, - tokens: GoogleAuthTokens, - user_id: str = "me", - ) -> GoogleApiResponse: - - """ - To get the list of labels of this user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users/getProfile - :param tokens: The object that holds the access token to the service. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting User Profile.") - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/profile", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - # ┓ ┓ ┓ - # ┃ ┏┓┣┓┏┓┃┏ - # ┗┛┗┻┗┛┗ ┗┛ - - async def list_labels( - self, - tokens: GoogleAuthTokens, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To get the list of labels of this user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/list - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param tokens: The object that holds the access token to the service. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Listing All Labels.", user_id) - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_json = await api_response.get_json() - api_response.data = {label.pop("name"): label for label in api_json.get("labels", [])} - - # Done here: - return api_response - - async def get_label( - self, - tokens: GoogleAuthTokens, - label_id: str, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To get one label of this user. the label will be identified by its id. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/get - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param tokens: The object that holds the access token to the service. - :param label_id: The id that Google assigned to the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting One Label.", user_id) - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def create_label( - self, - tokens: GoogleAuthTokens, - label_name: str, - label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = "labelShow", - message_visibility: Literal["show", "hide"] = "show", - label_text_color: str = "#434343", - label_background_color: str = "#000000", - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - Create one label for the user. Doesn't apply it to any mail, just creates it. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/create - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param tokens: The object that holds the access token to the service. - :param label_name: The display name of the label. - :param label_visibility: Whether, or not, you would like to show the label in the web UI. - :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. - :param label_text_color: The colour of the text of the label. - :param label_background_color: The colour of the background/tag of the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Creating One Label.", user_id) - api_response = await self.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - json = { - "name": label_name, - "messageListVisibility": "show" if message_visibility else "hide", - "labelListVisibility": "labelShow" if label_visibility else "labelHide", - "color": { - "textColor": label_text_color.lower(), - "backgroundColor": label_background_color.lower() - } - } - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def update_label( - self, - tokens: GoogleAuthTokens, - label_id: str, - label_name: str = None, - label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = None, - message_visibility: Literal["show", "hide"] = None, - label_text_color: str = None, - label_background_color: str = None, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - Updates one label for the user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/update - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - NOTE: Both or none of the colours must be updated. For this reason, a simple default will be chosen for the - other if only one is provided. - :param tokens: The object that holds the access token to the service. - :param label_id: The id that Google assigned to the label. - :param label_name: The display name of the label. - :param label_visibility: Whether, or not, you would like to show the label in the web UI. - :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. - :param label_text_color: The colour of the text of the label. - :param label_background_color: The colour of the background/tag of the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Format the JSON body: - json_body = {} - if label_name: json_body["name"] = label_name - if label_visibility: json_body["labelListVisibility"] = label_visibility - if message_visibility: json_body["messageListVisibility"] = message_visibility - if label_text_color or label_background_color: - json_body["color"] = { - "textColor": (label_text_color or "#434343").lower(), - "backgroundColor": (label_background_color or "#000000").lower() - } - - # Make the API call: - if not self._debug_only_errors: self._printer("Updating One Label.", user_id) - api_response = await self.put( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - json = json_body - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def delete_label( - self, - tokens: GoogleAuthTokens, - label_id: str, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To delete one label of this user. the label will be identified by its id. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/delete - :param tokens: The object that holds the access token to the service. - :param label_id: The id that Google assigned to the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Deleting One Label.", user_id) - api_response = await self.delete( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200, 204]: - api_response.success = True - - # Done here: - return api_response - - # ┳┳┓ - # ┃┃┃┏┓┏┏┏┓┏┓┏┓┏ - # ┛ ┗┗ ┛┛┗┻┗┫┗ ┛ - # ┛ - - async def __list_messages_on_page( - self, - tokens: GoogleAuthTokens, - count: int = 100, - query: str = None, - label_ids: List[str] | str = None, - include_spam_and_trash: bool = False, - next_page_token: str = None, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To enlist messages on one page. Google allows at most 500 results on one page. This method respects that - pagination limit and returns only what Google gives. This method should be used internally by the class and the - class should expose another method that calls this one in loop to get any arbitrary no. of messages as the user - desires. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - :param tokens: The object that holds the access token to the service. - :param count: The no. of messages to fetch. - :param query: Any query filter that is supported by GMail. - :param label_ids: The list of labels' ids that the mails must have on them. - :param include_spam_and_trash: Whether, or not, you would like to include mails categorized as spam and trash. - :param next_page_token: The token to fetch the next set of results. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Build the needed params: - params_json = { - "maxResults": count, - "includeSpamTrash": include_spam_and_trash - } - if query: params_json["q"] = query - if next_page_token: params_json["pageToken"] = next_page_token - if label_ids: params_json["labelIds"] = label_ids if isinstance(label_ids, list) else [label_ids] - - # Make the API call: - if not self._debug_only_errors: self._printer("Listing Messages for Page.", user_id, count, next_page_token) - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - params = params_json - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_json = await api_response.get_json() - api_response.data = { - "messages": {m.pop("id"): m for m in api_json.get("messages", [])}, - "nextPageToken": api_json.get("nextPageToken"), - "resultSizeEstimate": api_json["resultSizeEstimate"], - } - - # Done here: - return api_response - - async def list_messages( - self, - tokens: GoogleAuthTokens, - count: int = 100, - query: str = None, - label_ids: List[str] | str = None, - include_spam_and_trash: bool = False, - next_page_token: str = None, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To enlist mail messages from a user's account. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - :param tokens: The object that holds the access token to the service. - :param count: The no. of messages to fetch. - :param query: Any query filter that is supported by GMail. - :param label_ids: The list of labels' ids that the mails must have on them. - :param include_spam_and_trash: Whether, or not, you would like to include mails categorized as spam and trash. - :param next_page_token: The token to fetch the next set of results. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # We create a variable that will hold the results. - # We must supply the URL, Method and a few other params here due to the custom looping functionality: - all_messages = GoogleApiResponse( - serviceName = self._service_name, - action = inspect.stack()[0].function, - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages", - method = "GET", - data = { - "messages": {}, - "nextPageToken": None, - "resultSizeEstimate": 0 - } - ) - - # Let's figure out how many times we'll have to loop through the process to retrieve the target no. of - # messages. Google allows you to fetch info about at most 500 messages in one go. - max_per_call = 500 # ... because Google allows at most 500 entries in one call. - iterations_needed = int(math.ceil(count / max_per_call)) - last_iteration_count = count - int((max_per_call * (iterations_needed - 1))) - - # Run the loop those many times: - results_size_estimate = 0 - for iteration_no in range(iterations_needed): - - # Figure out the count for this page: - if iterations_needed > 1: - if iteration_no < (iterations_needed - 1): iteration_count = max_per_call - else: iteration_count = last_iteration_count - else: iteration_count = count - - # Retrieve the messages for this page: - iteration_response = await self.__list_messages_on_page( - tokens = tokens, - count = iteration_count, - query = query, - label_ids = label_ids, - include_spam_and_trash = include_spam_and_trash, - next_page_token = next_page_token - ) - - # Check if no data was received: - if ( - iteration_response.data is None or - not iteration_response.data.get("messages") - ): break - - # Now that we know that messages were received: - for k, v in iteration_response.data["messages"].items(): all_messages.data["messages"][k] = v - results_size_estimate += iteration_response.data["resultSizeEstimate"] - - # Also copy the API call params: - all_messages.httpCode = iteration_response.httpCode - all_messages.message = iteration_response.message - all_messages.success = iteration_response.success - - # If there is no next page after this, we break out of the loop: - next_page_token = iteration_response.data["nextPageToken"] - if next_page_token is None: break - - # Format the final response: - all_messages.data["nextPageToken"] = next_page_token - all_messages.data["resultSizeEstimate"] = results_size_estimate - - # Done here: - return all_messages - - async def get_message( - self, - tokens: GoogleAuthTokens, - message_id: str, - return_raw: bool = False, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To get one message of this user. The message will be identified by its id. Note that, if you choose to return - the raw message, the message body will be compliant with RFC 5322 and RFC 2045 (among others). - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/get - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - 2. https://developers.google.com/gmail/api/reference/rest/v1/Format - :param tokens: The object that holds the access token to the service. - :param message_id: The id that Google assigned to the message. - :param return_raw: Whether you want the raw message or the formatted message. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting One Message.", user_id) - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/{message_id}", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - params = {"format": "raw"} - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_json = await api_response.get_json() - raw_message = base64.urlsafe_b64decode(api_json["raw"]).decode() - if return_raw: api_response.data = raw_message - else: - parsed_message = mail_parser.parse(raw_message) - parsed_message["labels"] = api_json["labelIds"] - parsed_message["messageId"] = api_json["id"] - parsed_message["threadId"] = api_json["threadId"] - parsed_message["historyId"] = api_json["historyId"] - parsed_message["snippet"] = api_json["snippet"] - parsed_message["sizeEstimate"] = api_json["sizeEstimate"] - api_response.data = parsed_message - - # Done here: - return api_response - - async def modify_messages( - self, - tokens: GoogleAuthTokens, - message_ids: List[str] | str, - add_label_ids: List[str] | str = None, - remove_label_ids: List[str] | str = None, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To add or remove labels from one or more messages. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/batchModify - :param tokens: The object that holds the access token to the service. - :param message_ids: One or more message ids (assigned by Google). - :param add_label_ids: One or more label ids (not the display name of the label). - :param remove_label_ids: One or more label ids (not the display name of the label). - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Build the needed JSON: - body_json = {"ids": message_ids if isinstance(message_ids, list) else [message_ids]} - if add_label_ids: body_json["addLabelIds"] = add_label_ids if isinstance(add_label_ids, list) else [add_label_ids] - if remove_label_ids: body_json["removeLabelIds"] = remove_label_ids if isinstance(remove_label_ids, list) else [remove_label_ids] - - # Make the API call: - if not self._debug_only_errors: self._printer("Modifying Message(s).", user_id) - api_response = await self.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/batchModify", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - json = body_json - ) - - # If the call was successful: - if api_response.httpCode in [200, 204]: - api_response.success = True - - # Done here: - return api_response - - async def delete_messages( - self, - tokens: GoogleAuthTokens, - message_ids: List[str] | str, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To PERMANENTLY delete one or more messages. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/batchDelete - :param tokens: The object that holds the access token to the service. - :param message_ids: One or more message ids (assigned by Google). - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Deleting Message(s).", user_id) - api_response = await self.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/batchDelete", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - json = {"ids": message_ids if isinstance(message_ids, list) else [message_ids]} - ) - - # If the call was successful: - if api_response.httpCode in [200, 204]: - api_response.success = True - - # Done here: - return api_response - - async def trash_message( - self, - tokens: GoogleAuthTokens, - message_id: str, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To move one message to trash. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/trash - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - :param tokens: The object that holds the access token to the service. - :param message_id: The id of the message (assigned by Google). - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Trashing One Message.", user_id) - api_response = await self.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/{message_id}/trash", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - ) - - # If the call was successful: - if api_response.httpCode in [200, 204]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def untrash_message( - self, - tokens: GoogleAuthTokens, - message_id: str, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To move one message to trash. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/trash - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - :param tokens: The object that holds the access token to the service. - :param message_id: The id of the message (assigned by Google). - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Un-Trashing One Message.", user_id) - api_response = await self.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/{message_id}/untrash", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def send_message( - self, - tokens: GoogleAuthTokens, - message: GMailMessage, - thread_id: str = None, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To send one message. - NOTE: If you want to apply a custom label to your outgoing mails, this API endpoint doesn't allow you to do that - in one go. Instead, you should note down the 'id' field from a successful response and use the 'modify_messages' - method of this class to immediately apply that label to the mail in a separate call. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/send - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - :param tokens: The object that holds the access token to the service. - :param message: The object that has the content of the message to be sent. - :param thread_id: Replies to an existing mail if the correct thread-id is specified. If not specified, a new - mail with a new thread-id is created. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Construct the JSON body: - json_body = {"raw": message.get_raw_message(as_base64 = True)} - if thread_id: json_body["threadId"] = thread_id - - # Make the API call: - if not self._debug_only_errors: self._printer("Sending One Message.", user_id) - api_response = await self.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/send", - headers = { - "Authorization": f"Bearer {tokens.accessToken}", - "Content-Type": "message/rfc822" - }, - json = json_body - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - # Create an HTTP client: - test_client = httpx.AsyncClient( - limits = httpx.Limits( - max_connections = 100, # ............ Maximum number of connections allowed in the pool. - max_keepalive_connections = 50, # ... Maximum number of connections that can be kept alive. - ), - timeout = httpx.Timeout( - connect = 2.5, # ... Shorter connection timeout. - read = 2.5, # ...... Like what EasyEcom gives. - write = 10.0, # .... Time to wait for sending data. - pool = 120.0 # ..... Time to wait for a free connection from the pool. - ) - ) - - # Read the secrets that give you access to the app: - secrets_file = r"../../../creds/goog/app/google_tcaoff_test_oauth_20241125.json" - secrets_dict = json.from_file(secrets_file) - - # Read the user's tokens that will give you app access to that user's account: - tokens_file = r"../../../creds/goog/user/test_user_tokens_20241125.json" - tokens_dict = json.from_file(tokens_file) - test_tokens = GoogleAuthTokens(**tokens_dict) - - async def main(): - - # Create an instance of the client: - my_gmail = AsyncGMailClient( - service_name = "gmail", - oauth_json = secrets_dict, - http_client = test_client, - redirect_url = r"https://api.thecaoffice.com/converse/mail/callback/gmail", - scopes = [ - r"https://www.googleapis.com/auth/gmail.modify", - r"https://www.googleapis.com/auth/gmail.labels" - ], - debug = True, - debug_prefix = "GMail (M) | ", - debug_only_errors = False - ) - - # Request Auth: - # print("AUTH URL:", await my_gmail.get_authorization_url( - # state = "User123-Bhopli" - # )) - - # Get tokens from callback: - # print("TOKENS:", await my_gmail.get_authorization_tokens( - # redirect_url = r"https://api.thecaoffice.com/converse/mail/callback/gmail?state=User123-Bhopli..." - # )) - - # Create a sample mail: - my_mail = GMailMessage( - from_email = "pskhushal@gmail.com", - to_email = "orangebhopli@gmail.com", - subject = "Bhopli is the best! (Parts Sequence Test)", - cc_emails = None, - bcc_emails = None - ) - my_mail.add_html( - """ - - - - - Sample HTML String - - - -

    Hello, Bhopli!

    -

    Bhopli is the best, most well-behaved cat in the known universe.

    - - - """ - ) - my_mail.add_text("(3rd part - text) This is how you should pet her 👇") - my_mail.add_inline_image(r"../../../data/images/cat_petting.png") - my_mail.add_attachment(r"../../../data/pdf/sample_label.pdf") - # print(my_mail.get_raw_message(as_base64 = False)) - - # Test some feature: - response = await my_gmail.send_message( - tokens = test_tokens, - message = my_mail, - thread_id = None - ) - print("SUCCESS:", response.success) - print("SUMMARY:", response.to_markdown()) - print("\n\n---\n\n") - print("DATA:", json.to_string(response.data, default = str)) - if not response.success: - print("\n\n---\n\n") - print("FULL RESPONSE JSON:", json.to_string(await response.get_json())) - - - asyncio.run(main()) diff --git a/utils_v2/goog/gmail/gmail_message.py b/utils_v2/goog/gmail/gmail_message.py deleted file mode 100644 index 62556bd..0000000 --- a/utils_v2/goog/gmail/gmail_message.py +++ /dev/null @@ -1,336 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 16th Jul, 2024 - - OBJECTIVE: - - To be able to send out mails from code. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For working with mails: -from email.mime.multipart import MIMEMultipart -from email.mime.image import MIMEImage -from email.mime.text import MIMEText -from email.mime.base import MIMEBase -from email import encoders - -# For random strings: -import string -import random - -# For system-level activities: -import os - -# For working with files in RAM: -import io - -# To work with Base64 encoding: -import base64 - -# To work with datatypes: -from typing import List - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class GMailMessage: - - def __init__( - self, - from_email: str, - to_email: str, - subject: str, - cc_emails: List[str] = None, - bcc_emails: List[str] = None - ): - - """ - Create an instance of the message that you would like to send. - :param from_email: The EMail ID of the sender. - :param to_email: The EMail ID of the recipient. - :param subject: The subject of the mail. - :param cc_emails: A list of recipients to add to the CC section. - :param bcc_emails: A list of recipients to add to the BCC section. - """ - - # Create the instance of the message: - self.message = MIMEMultipart() - self.message["From"] = from_email - self.message["To"] = to_email - self.message["Subject"] = subject - if cc_emails: self.message["CC"] = ",".join(cc_emails) - if bcc_emails: self.message["BCC"] = ",".join(bcc_emails) - - # Note down the values for accessing later: - self.__from = from_email - self.__to = to_email - self.__cc = cc_emails, - self.__bcc = bcc_emails - self.__subject = subject - - # ┏┓ • - # ┃┃┏┓┏┓┏┓┏┓┏┓╋┓┏┓┏ - # ┣┛┛ ┗┛┣┛┗ ┛ ┗┗┗ ┛ - # ┛ - - @property - def from_mail(self): - return self.__from - - @property - def to_mail(self): - return self.__to - - @property - def cc_mails(self): - return self.__cc - - @property - def bcc_mails(self): - return self.__bcc - - @property - def subject(self): - return self.__subject - - # ┏┓ ┓ ┓ ┏┓ - # ┣┫┏┫┏┫ ┃ ┏┓┏┓╋┏┓┏┓╋ - # ┛┗┗┻┗┻ ┗┛┗┛┛┗┗┗ ┛┗┗ - - def add_text(self, text): - - """ - Add plain-text to the mail body. - :param text: The text to add to the mail body. - :return: None. - """ - - self.message.attach(MIMEText(text, "plain")) - - def add_html(self, html_text): - - """ - Add HTML text to the mail body. - :param html_text: The HTML text to add to the mail body. - :return: None. - """ - - self.message.attach(MIMEText(html_text, "html")) - - def add_inline_image( - self, - image_file: str | io.BytesIO, - file_name: str = None, - content_id: str = None - ): - - """ - Add an inline image to the body of the mail. - NOTE: This is NOT the same as sending an image as an attachment. - :param image_file: The image data to attach to the mail body. - :param file_name: The name of the file. This is the same name by which it will be downloaded. You need not - specify this if the input file is specified as a path. Needed when you give the input file as a buffer. - :param content_id: Inline images are inserted via HTML bocks. This field identifies the image resource. If not - specified, I will generate a random string. You may write a custom value here if you know what you are - doing. For most use cases, please ignore this field. - :return: None. - """ - - # Read the image as bytes: - image_bytes = None - if type(image_file) is str: - file_name = file_name or os.path.split(image_file)[-1] - with open(image_file, "rb") as opened_image_file: - image_bytes = opened_image_file.read() - if type(image_file) is io.BytesIO: - image_file.seek(0) - image_bytes = image_file.getvalue() - - # Declare the part to be attached to the multipart message: - if image_bytes is not None: - - # Create the HTML block if the image pointer is blank: - if content_id is None: - content_id = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8)) - self.add_html(f""" - - -

    - - - """) - - # Then add the image: - image_part = MIMEImage(image_bytes) - image_part.add_header( - "Content-ID", f"<{content_id}>" - ) - image_part.add_header( - "Content-Disposition", - f"inline; filename=\"{file_name}\"", - ) - self.message.attach(image_part) - - def add_attachment( - self, - attachment_file: str | io.BytesIO, - file_name: str = None - ): - - """ - Add a file as an attachment to the mail. This file, even if possible, will not be rendered on the screen in-line - with the body. It will be made available as a download. - :param attachment_file: The file that you would like to attach. - :param file_name: The name of the file. This is the same name by which it will be downloaded. You need not - specify this if the input file is specified as a path. Needed when you give the input file as a buffer. - :return: - """ - - # Declare the part to be attached to the multipart message: - part = MIMEBase("application", "octet-stream") - - # If the attachment is a file stored in the local disk: - if isinstance(attachment_file, str): - file_name = file_name or os.path.split(attachment_file)[-1] - with open(attachment_file, "rb") as attachment: - part.set_payload(attachment.read()) - - # If the file is held in RAM: - elif isinstance(attachment_file, io.BytesIO): - attachment_file.seek(0) - part.set_payload(attachment_file.read()) - - # Encode and attach the file: - encoders.encode_base64(part) - part.add_header( - "Content-Disposition", - f"attachment; filename=\"{file_name}\"", - ) - self.message.attach(part) - - # ┏┓ - # ┣ ┏┓┏┓┏┳┓┏┓╋ - # ┻ ┗┛┛ ┛┗┗┗┻┗ - - def get_raw_message( - self, - as_base64: bool = True - ): - - """ - Get the raw string dump from the current contents of the message. This text will be compliant with RFC 5322 and - RFC 2045 (among others). - :param as_base64: If set to True, the response will be a URL-safe B64 output, else it'll be a raw string. - :return: The standardized raw text dump. either as a raw string or as a Base64 (url-safe) string. - """ - - if not as_base64: return self.message - else: return base64.urlsafe_b64encode(self.message.as_bytes()).decode() - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - my_mail = GMailMessage( - from_email = "sender@gmail.com", - to_email = "recipient@gmail.com", - subject = "Bhopli is the best!", - cc_emails = None, - bcc_emails = None - ) - my_mail.add_html( - """ - - - - - Sample HTML String - - - -

    Hello, Bhopli!

    -

    Bhopli is the best, most well-behaved cat in the known universe.

    - - - """ - ) - my_mail.add_text("This is how you should pet her 👇") - my_mail.add_inline_image(r"../../../data/images/cat_petting.png") - my_mail.add_attachment(r"../../../data/pdf/sample_label.pdf") - print(my_mail.get_raw_message(as_base64 = True)) diff --git a/utils_v2/goog/gmail/json/messages/chatgpt_suggested_message_format.json b/utils_v2/goog/gmail/json/messages/chatgpt_suggested_message_format.json deleted file mode 100644 index 21bef48..0000000 --- a/utils_v2/goog/gmail/json/messages/chatgpt_suggested_message_format.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "_id": ObjectId("..."), // MongoDB auto-generated ID - "message_id": "unique-message-id", // Unique identifier for the email - "thread_id": "thread-id", // Optional: Group of related messages - "subject": "Subject of the email", - "from": { - "name": "Sender Name", // Name of the sender - "email": "sender@example.com" // Sender's email address - }, - "to": [ // List of recipients - { - "name": "Recipient Name", - "email": "recipient@example.com" - } - ], - "cc": [ // List of CC recipients (optional) - { - "name": "CC Name", - "email": "cc@example.com" - } - ], - "bcc": [ // List of BCC recipients (optional) - { - "name": "BCC Name", - "email": "bcc@example.com" - } - ], - "date": ISODate("2024-11-26T12:00:00Z"), // Date the email was sent - "headers": { // Raw headers from the email - "X-Priority": "3", - "Content-Type": "multipart/alternative; boundary=\"boundary\"", - "X-Mailer": "Mailer XYZ" - }, - "body": { // The body of the email, with parts if multipart - "text": "Plain text body content", // Plain text part (if any) - "html": "

    HTML body content

    ", // HTML part (if any) - "parts": [ // List of parts for multipart emails - { - "content_type": "text/plain", - "content_transfer_encoding": "base64", - "content": "base64-encoded-content-here" - }, - { - "content_type": "text/html", - "content_transfer_encoding": "base64", - "content": "base64-encoded-html-content-here" - } - ] - }, - "attachments": [ // Attachments in the email - { - "filename": "file1.pdf", - "content_type": "application/pdf", - "content_transfer_encoding": "base64", - "content": "base64-encoded-file-content" - }, - { - "filename": "image1.jpg", - "content_type": "image/jpeg", - "content_transfer_encoding": "base64", - "content": "base64-encoded-image-content" - } - ], - "flags": { // Optional flags for internal tracking - "read": false, - "spam": false - }, - "received_timestamp": ISODate("2024-11-26T12:01:00Z") // Time the email was received (optional) -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/formatted_message_list_20241126.json b/utils_v2/goog/gmail/json/messages/formatted_message_list_20241126.json deleted file mode 100644 index 5e50380..0000000 --- a/utils_v2/goog/gmail/json/messages/formatted_message_list_20241126.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "messages": { - "193669615aa33694": { - "threadId": "193669615aa33694" - }, - "19365d0239aa1aaf": { - "threadId": "19365d0239aa1aaf" - }, - "193641e1379da64d": { - "threadId": "193641e1379da64d" - }, - "193640e74d93dc9b": { - "threadId": "193640e74d93dc9b" - }, - "19363d6a7f50225a": { - "threadId": "19363d6a7f50225a" - }, - "19363ba8e2582133": { - "threadId": "19363ba8e2582133" - }, - "19362f9983e58ea6": { - "threadId": "19362f9983e58ea6" - }, - "19360aabcb976cfc": { - "threadId": "19360aabcb976cfc" - }, - "193604ad97c9fe62": { - "threadId": "193604ad97c9fe62" - }, - "1935e92672e67f22": { - "threadId": "1935e92672e67f22" - } - }, - "nextPageToken": "11954226706764006151", - "resultSizeEstimate": 402 -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_01_193669615aa33694_no_attachment_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_01_193669615aa33694_no_attachment_20241126.json deleted file mode 100644 index 3d9008e..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_01_193669615aa33694_no_attachment_20241126.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "id": "193669615aa33694", - "threadId": "193669615aa33694", - "labelIds": [ - "IMPORTANT", - "CATEGORY_UPDATES", - "INBOX" - ], - "snippet": "Khushal PS, Someone is attempting to reset the password of your account. When: Nov 26, 2024 04:48 AM Central European Standard Time Device: Google Chrome Windows (Desktop) Near: Luxembourg, Luxembourg", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp1258653wrq; Mon, 25 Nov 2024 19:48:52 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IHex3BNvuKbH0rDOVdVZr5VN+wGXuempHJ5NU47Pc6su+PhLTTyWxQVeZqbgHHqPxn1k368" - }, - { - "name": "X-Received", - "value": "by 2002:a05:6000:4904:b0:382:4eef:28a with SMTP id ffacd0b85a97d-38260bce857mr13224341f8f.43.1732592932057; Mon, 25 Nov 2024 19:48:52 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732592932; cv=none; d=google.com; s=arc-20240605; b=MGUuj+jr2ksXZS0o19wNISVfgnf59VtgpBi6dc45I4/NyDwg2NVtSewPcv4jOAcnGX H+mxaJV5fgziT52/Kd6U/n+MSCut6o9DvIPg5qNz4ahcTeuRo5n4K+yLmz5Rp2PvLuQs 1tALdDnwpNjbCjd+gYvOZHSfYovK3BZ3+B+utyiE0U57nYkdOhIBEJ/oGoy6OVAN+Lb5 lukod7ijj+dKdMcsw8SNO7JQWsjDMpG0LtUXtY0B44bKdF+LeBgYkzzNhiT5eedH7V3N 7cMvVw0ZCjLZKA1YH/CMKgTdwqgJqVWi3RvL4X/uCJxbBAOQtq/6JzPJCOneXVqEU3Wh my8A==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=feedback-id:bounces-to:mime-version:subject:message-id:to:from:date :dkim-signature:dkim-signature; bh=jxPSaVfaHN0N+lJ6K9ay8G6f4hb8T+t7HKX1DJ6mpfY=; fh=u/EceduMLbMJaVmVACWimtVNyu5iebWbNB9Q7JrDYgs=; b=Iq4DXicQhzSSrkkA+f9fABfl6pE1B6vhbNEJ/p5/5vAFtyJVzZCmhcBKT11U4gUHPk PopE3XbKRLAspJKz08ZlECgkXOpfT0ukUgCwyCMj+YBpf7iNRjMRqkw9bgW+INj0wdhm e+jPcPitmLhqI5zJqaKhbdK1Af66uL//OfwaZi0Wo/OGY/wP5C4SpCCFpW9n3acD7Fjz HyUwpB/ek0xzHYKscBTnjCovwmff0LCkgUcBAgNxf/Nze+++yd5FAh2v/asvfI4MRZT3 aQZZRsdLrzDVX1iiwpooCqKf8XJpmlC5JG/rOVhz01cgqLEpVEQXwxLUxpf+4JMJFbsx LRgQ==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@amazon.in header.s=micqgm67cqsvdipseryzt5t5odsvewta header.b=LswfTW3G; dkim=pass header.i=@amazonses.com header.s=uku4taia5b5tsbglxyj6zym32efj7xqv header.b=YyxLmGgS; spf=pass (google.com: domain of 202411260348515ca421ac8b144afa9c8567766550p0eu-c3tl5yxbh49vj7@bounces.amazon.in designates 54.240.1.2 as permitted sender) smtp.mailfrom=202411260348515ca421ac8b144afa9c8567766550p0eu-C3TL5YXBH49VJ7@bounces.amazon.in; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.in" - }, - { - "name": "Return-Path", - "value": "<202411260348515ca421ac8b144afa9c8567766550p0eu-C3TL5YXBH49VJ7@bounces.amazon.in>" - }, - { - "name": "Received", - "value": "from a1-2.smtp-out.eu-west-1.amazonses.com (a1-2.smtp-out.eu-west-1.amazonses.com. [54.240.1.2]) by mx.google.com with ESMTPS id ffacd0b85a97d-385be9920f4si1030431f8f.693.2024.11.25.19.48.51 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 25 Nov 2024 19:48:52 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of 202411260348515ca421ac8b144afa9c8567766550p0eu-c3tl5yxbh49vj7@bounces.amazon.in designates 54.240.1.2 as permitted sender) client-ip=54.240.1.2;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@amazon.in header.s=micqgm67cqsvdipseryzt5t5odsvewta header.b=LswfTW3G; dkim=pass header.i=@amazonses.com header.s=uku4taia5b5tsbglxyj6zym32efj7xqv header.b=YyxLmGgS; spf=pass (google.com: domain of 202411260348515ca421ac8b144afa9c8567766550p0eu-c3tl5yxbh49vj7@bounces.amazon.in designates 54.240.1.2 as permitted sender) smtp.mailfrom=202411260348515ca421ac8b144afa9c8567766550p0eu-C3TL5YXBH49VJ7@bounces.amazon.in; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.in" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=micqgm67cqsvdipseryzt5t5odsvewta; d=amazon.in; t=1732592931; h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type; bh=LH5AoXgTmD6qrgNMmPg2N4Kjd+MdburdNGizfre6x3E=; b=LswfTW3GeZuY88a0WncujiGM27tYdnz6Av7797ZGsnTKvkeVWnWqYBMHcRH50Cgs QWcPBr4jmdQU9h3TpG9J+78+mXdrtdwhdz3K5fujCT02uy0oOK2uqvTrnPfHsBlkAip LpDrgn2P6RF7y72ddT/unLtQlsnmWZBLgXjBKZOo=" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1732592931; h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:Feedback-ID; bh=LH5AoXgTmD6qrgNMmPg2N4Kjd+MdburdNGizfre6x3E=; b=YyxLmGgSMzhlrPeg3A8LjAG8yfh270KXdGxCTA6Yq3TJSGytfPO8zz7Tnpq4n/0A skRS4H3ESkjUsX2RDrZ90YR5zp8sSZmRBzRi6oBoQokldSoICr/MzFp4dBS9gYu8zC/ OhWBqAiYL4hgBR//EkoyVt2QHKG3x7Gq+jVg9WIo=" - }, - { - "name": "Date", - "value": "Tue, 26 Nov 2024 03:48:51 +0000" - }, - { - "name": "From", - "value": "\"amazon.in\" " - }, - { - "name": "To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Message-ID", - "value": "<0102019366961300-e4b92b6b-20ce-4b13-bc9f-440655f4fc7d-000000@eu-west-1.amazonses.com>" - }, - { - "name": "Subject", - "value": "amazon.in: Password recovery" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"----=_Part_1336386_1018227011.1732592931577\"" - }, - { - "name": "X-AMAZON-MAIL-RELAY-TYPE", - "value": "notification" - }, - { - "name": "Bounces-to", - "value": "202411260348515ca421ac8b144afa9c8567766550p0eu-C3TL5YXBH49VJ7@bounces.amazon.in" - }, - { - "name": "X-AMAZON-METADATA", - "value": "CA=C3TL5YXBH49VJ7-CU=AO8IZF00FXJKW" - }, - { - "name": "X-Original-MessageID", - "value": "" - }, - { - "name": "Feedback-ID", - "value": "610684451::1.eu-west-1.UIAUrMfbpGrxavqnRE0yoZrAUBI9C7GRNUx/kUDo6B4=:AmazonSES" - }, - { - "name": "X-SES-Outgoing", - "value": "2024.11.26-54.240.1.2" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=utf-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 9148, - "data": "PGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPg0KPGhlYWQ-DQogICAgPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9VVRGLTgiLz4NCiAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KICAgICAgICBib2R5IHsNCiAgICAgICAgICAgIG1hcmdpbjowOw0KICAgICAgICAgICAgY29sb3I6IzMzMzsNCiAgICAgICAgfQ0KDQogICAgICAgIGEgew0KICAgICAgICAgICAgdGV4dC1kZWNvcmF0aW9uOm5vbmU7DQogICAgICAgICAgICBjb2xvcjojMDA2Njk5Ow0KICAgICAgICB9DQoNCiAgICAgICAgcCB7DQogICAgICAgICAgICBtYXJnaW46MHB4Ow0KICAgICAgICB9DQoNCiAgICAgICAgaW1nIHsNCiAgICAgICAgICAgIGJvcmRlcjowOw0KICAgICAgICAgICAgbWFyZ2luOjA7DQogICAgICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogICAgICAgIH0NCg0KICAgICAgICAjdGl0bGUgcHsNCiAgICAgICAgICAgIGZvbnQtc2l6ZToxNXB4Ow0KICAgICAgICAgICAgZm9udC1mYW1pbHk6ICJBbWF6b24gRW1iZXIiLCBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICAgICAgfQ0KDQogICAgPC9zdHlsZT4NCiAgICA8dGl0bGU-PC90aXRsZT4NCjwvaGVhZD4NCjxib2R5PjxpbWcgd2lkdGg9IjEiIGhlaWdodD0iMSIgc3JjPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9RFI5QUVRM0NVVkdEJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDM0ODUxNWNhNDIxYWM4YjE0NGFmYTljODU2Nzc2NjU1MHAwZXUmUj1EUVQxMVZSWks5UlcmVD1PJlU9aHR0cHMlM0ElMkYlMkZpbWFnZXMtZXUuc3NsLWltYWdlcy1hbWF6b24uY29tJTJGaW1hZ2VzJTJGRyUyRjAxJTJGbmF2JTJGdHJhbnNwLmdpZiZIPTZUQVQzQU5OOUFIS1BJTFVIUkVIN0FOQUxNMEEmcmVmXz1wZV8zMzI3MDMyMV82MTA2ODQ0NTFfb3BlbnMiIC8-DQo8dGFibGUgYWxpZ249ImNlbnRlciIgY2VsbHNwYWNpbmc9IjAiIHdpZHRoPSI1MjAiIGNlbGxwYWRkaW5nPSIwIiBzdHlsZT0icGFkZGluZy1ib3R0b206IDIwcHg7Ij4NCiAgICA8dGJvZHk-DQogICAgICAgIDx0cj4NCiAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICA8dGFibGUgY2VsbHNwYWNpbmc9IjAiIHdpZHRoPSI1MjAiIGNlbGxwYWRkaW5nPSIwIiBzdHlsZT0ibWFyZ2luLXRvcDowcHg7IG1hcmdpbi1ib3R0b206IDBweDsgbWFyZ2luLWxlZnQ6IDIwcHg7IG1hcmdpbi1yaWdodDogMjBweDsiPg0KICAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgIDx0ciB3aWR0aD0iNTIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNTIwIiBoZWlnaHQ9IjUyIiBzdHlsZT0iYm9yZGVyLWJvdHRvbToxcHggc29saWQgI2VhZWFlYTsgcGFkZGluZy10b3A6MTBweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIHdpZHRoPSI1MjAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDciIGlkPSJsb2dvIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aW1nIGlkPSJhbWF6b25Mb2dvSW1nIiBhbHQ9IkxvZ28gSW1hZ2UiIHdpZHRoPSIxMDciIGhlaWdodD0iYXV0byIgc3JjPSJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvRy8wMS9hdXRocG9ydGFsL3Rpdi9hbWF6b25fbG9nb19SR0IuX0NCNDI0ODg3ODIwXy5wbmciLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNvbHNwYW49IjIiIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsgZm9udC1zaXplOjE3cHg7IGZvbnQtZmFtaWx5OiAnQW1hem9uIEVtYmVyJywgQXJpYWwsIHNhbnMtc2VyaWY7IHBhZGRpbmctdG9wOiAxNXB4OyBwYWRkaW5nLWJvdHRvbTogMHB4OyBwYWRkaW5nLWxlZnQ6IDBweDsgcGFkZGluZy1yaWdodDogMXB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwPktodXNoYWwgUCBTLDwvcD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNvbHNwYW49IjIiIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsgZm9udC1zaXplOjE3cHg7IGZvbnQtZmFtaWx5OiAnQW1hem9uIEVtYmVyJywgQXJpYWwsIHNhbnMtc2VyaWY7IHBhZGRpbmctdG9wOiAxNXB4OyBwYWRkaW5nLWJvdHRvbTogMTBweDsgcGFkZGluZy1sZWZ0OiAwcHg7IHBhZGRpbmctcmlnaHQ6IDFweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwPlNvbWVvbmUgaXMgYXR0ZW1wdGluZyB0byByZXNldCB0aGUgcGFzc3dvcmQgb2YgeW91ciBhY2NvdW50LjwvcD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQoNCiAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGFibGUgYWxpZ249ImxlZnQiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgc3R5bGU9ImZvbnQtc2l6ZToxN3B4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBzdHlsZT0idmVydGljYWwtYWxpZ246IHRvcDsgZm9udC1mYW1pbHk6ICdBbWF6b24gRW1iZXInLCBBcmlhbCwgc2Fucy1zZXJpZjsgdGV4dC1hbGlnbjogbGVmdDsgcGFkZGluZy10b3A6IDEwcHg7IHBhZGRpbmctbGVmdDogMHB4OyBwYWRkaW5nLXJpZ2h0OiA1cHg7IiA-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV2hlbjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgc3R5bGU9InZlcnRpY2FsLWFsaWduOiB0b3A7IGZvbnQtZmFtaWx5OiAnQW1hem9uIEVtYmVyJywgQXJpYWwsIHNhbnMtc2VyaWY7IHRleHQtYWxpZ246IGxlZnQ7IHBhZGRpbmctdG9wOiAxMHB4OyBwYWRkaW5nLWxlZnQ6IDBweDsgcGFkZGluZy1yaWdodDogMXB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTm92IDI2LCAyMDI0IDA0OjQ4IEFNIENlbnRyYWwgRXVyb3BlYW4gU3RhbmRhcmQgVGltZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHN0eWxlPSJ2ZXJ0aWNhbC1hbGlnbjogdG9wOyBmb250LWZhbWlseTogJ0FtYXpvbiBFbWJlcicsIEFyaWFsLCBzYW5zLXNlcmlmOyB0ZXh0LWFsaWduOiBsZWZ0OyBwYWRkaW5nLWxlZnQ6IDBweDsgcGFkZGluZy1yaWdodDogNXB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGV2aWNlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBzdHlsZT0idmVydGljYWwtYWxpZ246IHRvcDsgZm9udC1mYW1pbHk6ICdBbWF6b24gRW1iZXInLCBBcmlhbCwgc2Fucy1zZXJpZjsgdGV4dC1hbGlnbjogbGVmdDsgcGFkZGluZy1sZWZ0OiAwcHg7IHBhZGRpbmctcmlnaHQ6IDFweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdvb2dsZSBDaHJvbWUgV2luZG93cyAoRGVza3RvcCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBzdHlsZT0idmVydGljYWwtYWxpZ246IHRvcDsgZm9udC1mYW1pbHk6ICdBbWF6b24gRW1iZXInLCBBcmlhbCwgc2Fucy1zZXJpZjsgdGV4dC1hbGlnbjogbGVmdDsgcGFkZGluZy1sZWZ0OiAwcHg7IHBhZGRpbmctcmlnaHQ6IDVweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5lYXI6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkID4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBzdHlsZT0idmVydGljYWwtYWxpZ246IHRvcDsgZm9udC1mYW1pbHk6ICdBbWF6b24gRW1iZXInLCBBcmlhbCwgc2Fucy1zZXJpZjsgdGV4dC1hbGlnbjogbGVmdDsgcGFkZGluZy1sZWZ0OiAwcHg7IHBhZGRpbmctYm90dG9tOiAxMHB4OyBwYWRkaW5nLXJpZ2h0OiAxcHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMdXhlbWJvdXJnLCBMdXhlbWJvdXJnDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNvbHNwYW49IjIiIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsgZm9udC1zaXplOjE3cHg7IGZvbnQtZmFtaWx5OiAnQW1hem9uIEVtYmVyJywgQXJpYWwsIHNhbnMtc2VyaWY7IHBhZGRpbmctdG9wOiAxNXB4OyBwYWRkaW5nLWJvdHRvbTogMTBweDsgcGFkZGluZy1sZWZ0OiAwcHg7IHBhZGRpbmctcmlnaHQ6IDFweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHA-SWYgdGhpcyB3YXMgeW91LCB5b3VyIHZlcmlmaWNhdGlvbiBjb2RlIGlzOjwvcD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNvbHNwYW49IjIiIGFsaWduPSJsZWZ0IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogI0QzRDNEMzsgdGV4dC1hbGlnbjogbGVmdDsgZm9udC1zaXplOjIwcHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBmb250LWZhbWlseTogJ0FtYXpvbiBFbWJlcicsIEFyaWFsLCBzYW5zLXNlcmlmOyBwYWRkaW5nLXRvcDogMTVweDsgcGFkZGluZy1ib3R0b206IDEwcHg7IHBhZGRpbmctbGVmdDogMTBweDsgcGFkZGluZy1yaWdodDogMXB4OyBib3JkZXItdG9wLWxlZnQtcmFkaXVzOiAxMHB4OyBib3JkZXItdG9wLXJpZ2h0LXJhZGl1czogMTBweDsgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogMTBweDsgYm9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXM6IDEwcHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwPiAgMzM2NjA1PC9wPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgY29sc3Bhbj0iMiIgYWxpZ249ImxlZnQiIHN0eWxlPSJ0ZXh0LWFsaWduOiBsZWZ0OyBmb250LXNpemU6MTdweDsgZm9udC1mYW1pbHk6ICdBbWF6b24gRW1iZXInLCBBcmlhbCwgc2Fucy1zZXJpZjsgcGFkZGluZy10b3A6IDE1cHg7IHBhZGRpbmctYm90dG9tOiAxMHB4OyBwYWRkaW5nLWxlZnQ6IDBweDsgcGFkZGluZy1yaWdodDogMXB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8cD5JZiB5b3UgZGlkbiYjMzk7dCByZXF1ZXN0IGl0OiA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9RFI5QUVRM0NVVkdEJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDM0ODUxNWNhNDIxYWM4YjE0NGFmYTljODU2Nzc2NjU1MHAwZXUmUj0zRkxBS1VTRVNUR1YzJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmElMkZjJTJGciUyRkFDbHFWOUtwZGp1ZmFoRVRjdnFVaHhkTm8lM0ZyZWZfJTNEcGVfMzMyNzAzMjFfNjEwNjg0NDUxJkg9VVNDNFc2QU5CSVNHOFlKMFRMU1RJVUNNTEkwQSZyZWZfPXBlXzMzMjcwMzIxXzYxMDY4NDQ1MSI-IGNsaWNrIGhlcmUgdG8gZGVueS4gPC9hPjwvcD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI1MjAiIGhlaWdodD0iNDUiIGNvbHNwYW49IjIiIGFsaWduPSJsZWZ0IiBzdHlsZT0iZm9udC1zaXplOjE3cHg7IGZvbnQtZmFtaWx5OiAnQW1hem9uIEVtYmVyJywgQXJpYWwsIHNhbnMtc2VyaWY7IHRleHQtYWxpZ246IGxlZnQ7IHBhZGRpbmctbGVmdDogMHB4OyBwYWRkaW5nLWJvdHRvbTogMTBweDsgcGFkZGluZy10b3A6IDEwcHg7IHBhZGRpbmctcmlnaHQ6IDFweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRG9u4oCZdCBzaGFyZSBpdCB3aXRoIG90aGVycy4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjUyMCIgc3R5bGU9ImZvbnQtZmFtaWx5OiAnQW1hem9uIEVtYmVyJywgQXJpYWwsIHNhbnMtc2VyaWY7IHRleHQtYWxpZ246IGxlZnQ7IHBhZGRpbmctbGVmdDogMHB4OyBwYWRkaW5nLWJvdHRvbTogMTBweDsgcGFkZGluZy10b3A6IDEwcHg7IHBhZGRpbmctcmlnaHQ6IDFweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgc3R5bGU9IndpZHRoOiA1MjBweDsgYm9yZGVyOiAxcHggc29saWQgIzgwODA4MDsgcGFkZGluZy10b3A6IDVweDsgcGFkZGluZy1sZWZ0OiAxMHB4OyBwYWRkaW5nLXJpZ2h0OiAxMHB4OyBwYWRkaW5nLWJvdHRvbTogMjBweDsgbWFyZ2luLXRvcDogMjVweDsgbWFyZ2luLXJpZ2h0OiAwcHg7IG1hcmdpbi1sZWZ0OiAwcHg7IG1hcmdpbi1ib3R0b206IDhweDsgY29sb3I6ICM0NDQ7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGgyIHN0eWxlPSJmb250LXdlaWdodDogNzAwOyBmb250LXNpemU6IDE1cHg7IHBhZGRpbmctYm90dG9tOiAxMHB4OyI-SXMgaXQgc2FmZSB0byBmb2xsb3cgdGhpcyBsaW5rPzwvaDI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXY-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YSBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBjb2xvcjogYmxhY2s7IHBvaW50ZXItZXZlbnRzOiBub25lOyBjdXJzb3I6IGRlZmF1bHQ7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRoZSBsaW5rIHByb3ZpZGVkIGluIHRoaXMgZW1haWwgc3RhcnRzIHdpdGgg4oCcaHR0cHM6Ly93d3cuYW1hem9uLmlu4oCdLiBJZiB5b3UgcHJlZmVyLCBjb3B5IHRoZSBmb2xsb3dpbmcgbGluayBhbmQgcGFzdGUgaXQgaW50byBhIGJyb3dzZXIgdG8gdmlldy4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxicj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGEgc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgY29sb3I6IGJsYWNrOyBwb2ludGVyLWV2ZW50czogbm9uZTsgY3Vyc29yOiBkZWZhdWx0OyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtd2VpZ2h0OiA2MDAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHR0cHM6Ly93d3cuYW1hem9uLmluL2EvYy9yL0FDbHFWOUtwZGp1ZmFoRVRjdnFVaHhkTm8NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2Pg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgPC90cj4NCiAgICA8L3Rib2R5Pg0KPC90YWJsZT4NCjxpbWcgd2lkdGg9IjEiIGhlaWdodD0iMSIgc3JjPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9RFI5QUVRM0NVVkdEJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDM0ODUxNWNhNDIxYWM4YjE0NGFmYTljODU2Nzc2NjU1MHAwZXUmUj0zMlQ0N0s3UFBPMFhOJlQ9RSZVPWh0dHBzJTNBJTJGJTJGaW1hZ2VzLWV1LnNzbC1pbWFnZXMtYW1hem9uLmNvbSUyRmltYWdlcyUyRkclMkYwMSUyRm5hdiUyRnRyYW5zcC5naWYmSD1GQkZFTjVTSVVGWTJBNFZTSkVFSzA1V1pRVFVBJnJlZl89cGVfMzMyNzAzMjFfNjEwNjg0NDUxX29wZW4iIC8-PC9ib2R5Pg0KPC9odG1sPg==" - } - } - ] - }, - "sizeEstimate": 14907, - "historyId": "527966", - "internalDate": "1732592931000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_02_19367930033154ca_with_attachment_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_02_19367930033154ca_with_attachment_20241126.json deleted file mode 100644 index a9a6834..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_02_19367930033154ca_with_attachment_20241126.json +++ /dev/null @@ -1,258 +0,0 @@ -{ - "id": "19367930033154ca", - "threadId": "19367930033154ca", - "labelIds": [ - "UNREAD", - "IMPORTANT", - "CATEGORY_PERSONAL", - "INBOX" - ], - "snippet": "Sample content. Inline graphics done. Sample monospaced How about some Headers? Hello, World! These are quotes. How about some emojis? \ud83d\ude1a\ud83d\ude05\ud83d\ude05\ud83e\udd70\ud83d\ude18\ud83d\ude01\ud83d\ude01 There's also an attachment!", - "payload": { - "partId": "", - "mimeType": "multipart/mixed", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp1327351wrq; Tue, 26 Nov 2024 00:25:08 -0800 (PST)" - }, - { - "name": "X-Received", - "value": "by 2002:a05:690c:6111:b0:6e3:fd6:6ccb with SMTP id 00721157ae682-6eee08c3459mr156525787b3.13.1732609507838; Tue, 26 Nov 2024 00:25:07 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732609507; cv=none; d=google.com; s=arc-20240605; b=VDostCh8Kr1QGeQoXgLjYyrkymtwKEVHTyPaNeSjy30Q0B4GTTIBIPbKgkL6UazG4T s92UnE+Br4HJUSsqbtOdKTV1Pwt9lI3EzASDMX3OVGccdViTyUgGjgNuagV2fUVQugYi BJWxLrWZXVVtKkLNqRDOEQgiPi6t869FTB4877V8dKxQs99Q8IBncekOq3f6+SmsFlIl U3l6EUgaV/7MFzNRofsmXFGEG0TLto+Xgx5bMQ8B0OpjSFXR2Va/1xF5BmrzJTLgL6N5 zct3VIRLMxkf+8v3oniTG7yaaCQMPLxOq1pKXhP/MfKzgvdo5r14/kAzsj05rQ/L2/rT 2OrQ==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:mime-version:dkim-signature; bh=9NSLykdU3XzuxItzVTTQJjRRBR6yhJqdgYRarHa+VdY=; fh=KtxgdfxhT3MZUXDfdB/Mxp08o9TbOvoJMvz1V2wYTKk=; b=Xqtl2jfteUY2I+wdSwdllaqPKg1QP8hUyJpP/644zwGrOBdLbjCO8Po5C9KJfxUh7i H7UMWfEWkulB52WFTDU/54UY8lnX7iGZEMtT/4twKUGToWPPWeG/wmh/I4W9ZEmA/qXG OiRrBlJI3NJowsrnfoqXrpV/W5mz1SNuJBkj5k71+3vrPVlEmGwGmz8/MCG+RF2yV4nz QEVg613QkuThPEEsgYdHbfWDlF8jnGbAS+Lyt8ZdixVvO4/Gq5swuGUHihfeV+Fxt5Kv L2Wbqiq7UFJF9YJEtezJOdkdrTxs8dz6bTUZTrpWtRYxoBuH76HB+f9yrhOIRFTxor+9 18dA==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=\"Adx/Ch2H\"; spf=pass (google.com: domain of orangebhopli@gmail.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=orangebhopli@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@gmail.com" - }, - { - "name": "Return-Path", - "value": "" - }, - { - "name": "Received", - "value": "from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) by mx.google.com with SMTPS id 00721157ae682-6eee01062easor78223267b3.12.2024.11.26.00.25.07 (Google Transport Security); Tue, 26 Nov 2024 00:25:07 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of orangebhopli@gmail.com designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=\"Adx/Ch2H\"; spf=pass (google.com: domain of orangebhopli@gmail.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=orangebhopli@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@gmail.com" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732609507; x=1733214307; dara=google.com; h=cc:to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=9NSLykdU3XzuxItzVTTQJjRRBR6yhJqdgYRarHa+VdY=; b=Adx/Ch2H1Vw5fzCEcIPf/EuHGviFMr1/Gw93WwruoabampXxraQ5hkcJNx0yi+zM2/ 9wlmVqcDwiWM1dFrkc1hPNMyyH4h7hCXjGsDbK8hkUE/Fk1AR51fhjliB9AZFkps+PUR 21CYTDMzWWlHjKlBpnM1axU9suvv04NqDZ8Hr7LAXysd9eF1ypoTWjwWMJ5QGKpoQo6W qf3m5yuqSXLAtbTKZN6K3qUO+S9ZRjUahw0eke7ieQ2uKR8dFwaoS899KhVBY5bZpLzr gEjYkNbzZGN4bp/LIJcHmgueZ5J0L6V+zaYMIqNRp3wOwAe41nZSAf6PvLxixLZoTvyH TmmA==" - }, - { - "name": "X-Google-DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732609507; x=1733214307; h=cc:to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=9NSLykdU3XzuxItzVTTQJjRRBR6yhJqdgYRarHa+VdY=; b=F5yE7IslZpO2UHCSg9jCYE645+q7dW9WO9S0DIb4oRcTlz/qgI1fwnnB0vlWvgXQxJ Af8/WUW6AJm/8mJ//SNXSDwE28OZiZqR+i/SYc0yontGepFawQAZg9xFRLspp7O/2UAL EHrkssz9noe2wPPdcPGYanXfoiSLtX/3XnrGCg1P5Y4jdy7p6624f87Xx+Mno1t8q2xh Odh2QrURKad50BqY+UB20+um9ommh4J0BOsD9WiVCfu5isvTCfwZYAtjYUJ48UVWLh3b kAPAaSic4g1zQzlOychUnqFB95VrrODUNUACfKBuIR0YbUdsgjMzn9p4RQ1LAgr9NfvY 62kw==" - }, - { - "name": "X-Forwarded-Encrypted", - "value": "i=1; AJvYcCVe+1Kjt1hhMEjYG2UyrzV/DvH4xn376Ya7lsLKkTIVIAJGmG8xKSkvvJAmXIAXRyYuWSNpPVXGyjSKXTgsLlU=@gmail.com" - }, - { - "name": "X-Gm-Message-State", - "value": "AOJu0Ywb3oN+4RLkTx99fCaTMOlGwSTJR7AWBy7IvxJyBYNwLV6Of7c2 vtYqtaRl1CcUgUXmGnXqjfQsSX6DT4LLNPGCsrrzk4VXfV26FJA1iaDFm/ey7pRaAucm5dGPHRO 9oG7H+96wM0pzmY3Tlb9LUEY3NIdSR9H2" - }, - { - "name": "X-Gm-Gg", - "value": "ASbGncuwgQwpQZrb7exEtts26PEAwkklAu9DD/4RvvBSiHYGDUD7+909oeyrMtfk66q IuA94Z8WcFFe3TabyhyXIjGTCEF5+Qg==" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IFy7wXSaJCDrrXclKRzxMFtyv1HrgyWSfgyomoDnvBS4NPu9KBdzHjvcekKjw9uKzJAj5R2iOl+mZuCt5sjIws=" - }, - { - "name": "X-Received", - "value": "by 2002:a05:690c:6701:b0:6ee:b5a6:a67a with SMTP id 00721157ae682-6eee0a402acmr176495297b3.28.1732609506221; Tue, 26 Nov 2024 00:25:06 -0800 (PST)" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "From", - "value": "TheBhopli " - }, - { - "name": "Date", - "value": "Tue, 26 Nov 2024 13:54:54 +0530" - }, - { - "name": "Message-ID", - "value": "" - }, - { - "name": "Subject", - "value": "Test Mail for GMail API." - }, - { - "name": "To", - "value": "\"pskhushal@gmail.com\" " - }, - { - "name": "Cc", - "value": "\"khushal@easyfi.net.in\" , \"bhushan.thakkar@gmail.com\" " - }, - { - "name": "Content-Type", - "value": "multipart/mixed; boundary=\"00000000000027d46c0627cc96ea\"" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "multipart/related", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "multipart/related; boundary=\"00000000000027d46c0627cc96e9\"" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0.0", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"00000000000027d46c0627cc96e8\"" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0.0.0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain; charset=\"UTF-8\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 236, - "data": "U2FtcGxlIGNvbnRlbnQuDQoNCltpbWFnZTogY2hhdC5wbmddDQoNCklubGluZSBncmFwaGljcyBkb25lLg0KDQpTYW1wbGUgbW9ub3NwYWNlZA0KDQoqSG93IGFib3V0IHNvbWUgSGVhZGVycz8qDQoNCkhlbGxvLCBXb3JsZCEgVGhlc2UgYXJlIHF1b3Rlcy4NCg0KDQpIb3cgYWJvdXQgc29tZSBlbW9qaXM_IPCfmJrwn5iF8J-YhfCfpbDwn5iY8J-YgfCfmIENClRoZXJlJ3MgYWxzbyBhbiAqYXR0YWNobWVudCohDQo=" - } - }, - { - "partId": "0.0.1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=\"UTF-8\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 675, - "data": "PGRpdiBkaXI9Imx0ciI-U2FtcGxlIGNvbnRlbnQuPGRpdj48YnI-PGRpdj48aW1nIHNyYz0iY2lkOmlpX20zeTZ0dTg1MCIgYWx0PSJjaGF0LnBuZyIgd2lkdGg9IjIyMiIgaGVpZ2h0PSIyMjIiIHN0eWxlPSJtYXJnaW4tcmlnaHQ6IDBweDsiPjwvZGl2PjxkaXY-PGJyPjwvZGl2PjxkaXY-SW5saW5lIGdyYXBoaWNzIGRvbmUuPC9kaXY-PGRpdj48YnI-PC9kaXY-PGRpdj48Zm9udCBmYWNlPSJtb25vc3BhY2UiPlNhbXBsZSBtb25vc3BhY2VkPC9mb250PjwvZGl2PjxkaXY-PGJyPjwvZGl2PjxkaXY-PGI-PGZvbnQgc2l6ZT0iNiI-SG93IGFib3V0IHNvbWUgSGVhZGVycz88L2ZvbnQ-PC9iPjwvZGl2PjxkaXY-PGJyPjwvZGl2PjxibG9ja3F1b3RlIGNsYXNzPSJnbWFpbF9xdW90ZSIgc3R5bGU9Im1hcmdpbjowcHggMHB4IDBweCAwLjhleDtib3JkZXItbGVmdDoxcHggc29saWQgcmdiKDIwNCwyMDQsMjA0KTtwYWRkaW5nLWxlZnQ6MWV4Ij5IZWxsbywgV29ybGQhIFRoZXNlIGFyZSBxdW90ZXMuPC9ibG9ja3F1b3RlPjxkaXY-PGJyPjwvZGl2PjxkaXY-SG93IGFib3V0IHNvbWUgZW1vamlzP8Kg8J-YmvCfmIXwn5iF8J-lsPCfmJjwn5iB8J-YgTxicj48L2Rpdj48L2Rpdj48ZGl2PlRoZXJlJiMzOTtzIGFsc28gYW4gPGk-PHU-YXR0YWNobWVudDwvdT48L2k-ITwvZGl2PjwvZGl2Pg0K" - } - } - ] - }, - { - "partId": "0.1", - "mimeType": "image/png", - "filename": "chat.png", - "headers": [ - { - "name": "Content-Type", - "value": "image/png; name=\"chat.png\"" - }, - { - "name": "Content-Disposition", - "value": "inline; filename=\"chat.png\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "base64" - }, - { - "name": "Content-ID", - "value": "" - }, - { - "name": "X-Attachment-Id", - "value": "ii_m3y6tu850" - } - ], - "body": { - "attachmentId": "ANGjdJ88SNHhnjq5-Alk71WYYaL72CUhJn6_geE_GP7JZKZdcSIR56LPGVklvFO_IuMFqeDkDT2U4r8SXTSMb-uBnNrio-NeXiW2p8vPWnV2yq-YaZxG0xBD6WILt5Qwg_43lv9_TGnjSvWn5QrGzusOttPluVRIWtv0-dksvYXrHDbS5MC0IYX4qpv8dbvGto5rgH_iIsIMav2aXbm5_o_mmxlxO9GavC8G9ZWD9BbuLlKKMJQAXgGXlfOlWA1Ukr5Cr0UO5LZbeTtVX3dZMYs3QfMwlGkVLT7Gam6aZfW8JduWhObFP9ghg2haF4tooXcUFNOPX7e2Axto-OmYAXLaPZRh-xpSzEObOeQv8gAHihoXlkA5Y_A2m45-emjdSiwff2Ui0VRZs96_DMGO", - "size": 17466 - } - } - ] - }, - { - "partId": "1", - "mimeType": "image/png", - "filename": "chat.png", - "headers": [ - { - "name": "Content-Type", - "value": "image/png; name=\"chat.png\"" - }, - { - "name": "Content-Disposition", - "value": "attachment; filename=\"chat.png\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "base64" - }, - { - "name": "Content-ID", - "value": "" - }, - { - "name": "X-Attachment-Id", - "value": "f_m3y6xx8e1" - } - ], - "body": { - "attachmentId": "ANGjdJ-XMpv18VYpIKT1zc45Su99KXSI3r3YaVquSLfKE3DqgQ7XjO7p4iHRHvc47lIr70rLBk2H8lLlMifTCFxFLMy0q_uFgsCHASCDeq-opjPkeDxC3BaxACeyeNWaZYANXgUCFYqCygTLkIoeggJDBxmzPn99baxvoJqcRLXROO1mSWGB4K0PLJcP35r8Y2D9lVRjSAJupzf7HLYLzimY1Q-X6Ge2qNCNnree-rS47FNXQgvFfVdV_x7jcvLE7JJl5cBBIyus-TtTulMk0RrFbcn5zKH7AniW6IF7v-mLOUzpDVye9tIiVqc6W4EdLeP3wmIaMVy4shsAdHkKtbjwLxicycke8Vi5hAV50s0pCllN26rSHakAA9zswG9q5z3cbS5LNMdEUpgWt6ON", - "size": 17466 - } - } - ] - }, - "sizeEstimate": 55270, - "historyId": "528587", - "internalDate": "1732609494000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_03_19365d0239aa1aaf_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_03_19365d0239aa1aaf_20241126.json deleted file mode 100644 index 1697bdc..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_03_19365d0239aa1aaf_20241126.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "id": "19365d0239aa1aaf", - "threadId": "19365d0239aa1aaf", - "labelIds": [ - "CATEGORY_PROMOTIONS", - "UNREAD", - "INBOX" - ], - "snippet": "Amazon.in Your Amazon.in Today's Deals Get Amazon App Hello Khushal PS, Are you looking for something in our ACCESSORY OR PART OR SUPPLY store? If so, you might be interested in these items.", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp1199268wrq; Mon, 25 Nov 2024 16:12:39 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IGrkPfvb+dSkwa9iS6Kivda2qwRAG9D9snZa0xCBnTtWrRkREL9rtlGKQGz3LviU5rqswOE" - }, - { - "name": "X-Received", - "value": "by 2002:a05:6512:5c1:b0:53d:d3cb:debb with SMTP id 2adb3069b0e04-53dd3cbdf8dmr6301124e87.0.1732579959442; Mon, 25 Nov 2024 16:12:39 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732579959; cv=none; d=google.com; s=arc-20240605; b=T0Yokutt7qdL5F2L8pFD9jy1sTZkKCQjCtzNVwWxLQnQLWddpXD69lwysx8hp6p9nP Ld/Kdy4Jg98AsGT9wsizztjLhBYB30vfpDRnlxjbmNQ42f/uZZgmdAsJ79uRfpJ9Nn6M ZXDRLgrUc3jFMoKlHBTEwVieL8tPaZ5magEYD4egIHS7CA+nIArfHz6aSb33oylx//5p PKYD+3f19u86uzbCEEdWbbNh/zfCkt31Rz3/3PY24DE9Cc9ZusKjbjQ66juEQiSV9W71 1xDNuIurQUXB+kk7ctRfy7OyuEIFMSN6UrKRwG20ge7uf8mz3jAnIzE6ouaej2BqI8Yk wQwQ==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=feedback-id:list-unsubscribe:list-unsubscribe-post:bounces-to :mime-version:subject:message-id:to:from:date:dkim-signature :dkim-signature; bh=ae6BFYuWr0k+7ooGQp/2cSWiFLurA8Xuta8hwCJJBCo=; fh=u/EceduMLbMJaVmVACWimtVNyu5iebWbNB9Q7JrDYgs=; b=CHLYewk0wxYzvOHRZrCpm/dKZmGowdrShKvKQ4v8wZnK754ewrNclJiBlUupwLrl51 Vbek14E9T2sW0yYGLghgWMmOskjKnx8hK7l2LwdD1hpegXReORvlSnIDAsIoftn3/5KF cHRYLlUVecVfDgj0fhKvvpA/9NNNc0R113RoyfJlGcv+Km8NhKpvZdIRpbvPzyFd5S4B aiOO7AztFhQaKYphmno1otSs/oXEPywWTwNT6ZyJ/qAwoHqwKrHzRu8GvphwsoimngTQ Fbo0+vFrZFWFrKBv6n7uxA9hWQv/jqssH8uJ0/RD9E3rmUSAQQlS6NCh6mU/7i0wiVLI 6aoA==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@amazon.in header.s=55spn7jg3iwyluzn4ej7wq3ev2vqedgu header.b=CjSOuKcT; dkim=pass header.i=@amazonses.com header.s=uku4taia5b5tsbglxyj6zym32efj7xqv header.b=Frviu8Z2; spf=pass (google.com: domain of 202411260012388bce9401ff544ee1b647d13d7450p0eu-c17nwh9w055t8b@bounces.amazon.in designates 54.240.0.92 as permitted sender) smtp.mailfrom=202411260012388bce9401ff544ee1b647d13d7450p0eu-C17NWH9W055T8B@bounces.amazon.in; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.in" - }, - { - "name": "Return-Path", - "value": "<202411260012388bce9401ff544ee1b647d13d7450p0eu-C17NWH9W055T8B@bounces.amazon.in>" - }, - { - "name": "Received", - "value": "from a0-92.smtp-out.eu-west-1.amazonses.com (a0-92.smtp-out.eu-west-1.amazonses.com. [54.240.0.92]) by mx.google.com with ESMTPS id a640c23a62f3a-aa5421552e6si288994166b.31.2024.11.25.16.12.39 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 25 Nov 2024 16:12:39 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of 202411260012388bce9401ff544ee1b647d13d7450p0eu-c17nwh9w055t8b@bounces.amazon.in designates 54.240.0.92 as permitted sender) client-ip=54.240.0.92;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@amazon.in header.s=55spn7jg3iwyluzn4ej7wq3ev2vqedgu header.b=CjSOuKcT; dkim=pass header.i=@amazonses.com header.s=uku4taia5b5tsbglxyj6zym32efj7xqv header.b=Frviu8Z2; spf=pass (google.com: domain of 202411260012388bce9401ff544ee1b647d13d7450p0eu-c17nwh9w055t8b@bounces.amazon.in designates 54.240.0.92 as permitted sender) smtp.mailfrom=202411260012388bce9401ff544ee1b647d13d7450p0eu-C17NWH9W055T8B@bounces.amazon.in; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.in" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=55spn7jg3iwyluzn4ej7wq3ev2vqedgu; d=amazon.in; t=1732579959; h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:List-Unsubscribe-Post:List-Unsubscribe; bh=07AqkIKTtFOwN0qQZIsK14iOi5M9FBw5xK/nDSihny0=; b=CjSOuKcT6144qJClJDfhA83J75Biy6AiZzwkz1rze/q29TcfgzOIwpacPSDoi7Un DUw0V0T5HsxjSaGw/G72tgb0saDuF4O+bqVqetsmjAnX61PsFFIxQXWjjLgApsPL1tv BHQIbkKctKw0UQeFGJHflfYzIIUnq4ECRRRCAKcY=" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1732579959; h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:List-Unsubscribe-Post:List-Unsubscribe:Feedback-ID; bh=07AqkIKTtFOwN0qQZIsK14iOi5M9FBw5xK/nDSihny0=; b=Frviu8Z24nZPNoNtEHMtr1G9zZuEOzjdBz2fwkAzpXiNjVuGh4ZAJxWpzEzbQ9SQ TxUOUfozpEGG5Cg3kPUMleQyFcfiqE63KLMcbasJlTIWzQXBpBNZHwKUvLCQYZyELaU BBo3cBXTMnKiQECLni+V2efPFroHEXCQ/onlojaU=" - }, - { - "name": "Date", - "value": "Tue, 26 Nov 2024 00:12:38 +0000" - }, - { - "name": "From", - "value": "\"Amazon.in\" " - }, - { - "name": "To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Message-ID", - "value": "<0102019365d02057-191fac4d-c476-4ca2-89d4-15b01d7efbd4-000000@eu-west-1.amazonses.com>" - }, - { - "name": "Subject", - "value": "Amkette USB Hub" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"----=_Part_4594082_890675294.1732579958850\"" - }, - { - "name": "X-AMAZON-MAIL-RELAY-TYPE", - "value": "notification" - }, - { - "name": "Bounces-to", - "value": "202411260012388bce9401ff544ee1b647d13d7450p0eu-C17NWH9W055T8B@bounces.amazon.in" - }, - { - "name": "X-AMAZON-METADATA", - "value": "CA=C17NWH9W055T8B-CU=AO8IZF00FXJKW" - }, - { - "name": "List-Unsubscribe-Post", - "value": "List-Unsubscribe=One-Click" - }, - { - "name": "List-Unsubscribe", - "value": "" - }, - { - "name": "X-Original-MessageID", - "value": "" - }, - { - "name": "Feedback-ID", - "value": "1217703571::1.eu-west-1.kjoQSiqb8G+7lWWiDVsxjM2m0ynYd4I6yEFlfoox6aY=:AmazonSES" - }, - { - "name": "X-SES-Outgoing", - "value": "2024.11.26-54.240.0.92" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain; charset=utf-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 4887, - "data": "DQoNCg0KDQoNCg0KPT09PT09PT09PQ0KQU1BWk9OLklODQo9PT09PT09PT09DQoNCkFyZSB5b3UgbG9va2luZyBmb3Igc29tZXRoaW5nIGluIG91ciBBQ0NFU1NPUlkgT1IgUEFSVCBPUiBTVVBQTFkgc3RvcmU_IElmIHNvLCB5b3UgbWlnaHQgYmUgaW50ZXJlc3RlZCBpbiB0aGVzZSBpdGVtcy4NCiANCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgDQoNCkFta2V0dGUgNCBQb3J0IFN1cGVyc3BlZWQgVVNCIEh1YiAzLjAgZm9yIFBDL0xhcHRvcHMsIFBvcnRhYmxlIERhdGEgSHViIHdpdGggSGktU3BlZWQgRGF0YSBUcmFuc2ZlciBVcCB0byA1IEdCUFMsIENoYXJnaW5nIEZ1bmN0aW9ufCBTdHJvbmcgYW5kIER1cmFibGUsIFBvd2VyIFN1cHBseSBQb3J0IGFuZCA4MCBjbSBMb25nIENhYmxlIChCbGFjaykNCmJ5IEFta2V0dGUNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwOEpIWVdKTVAvcmVmPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMV90aQ0KLi4uDQoNCg0KWkVCUk9OSUNTIDE1MEhiIDQgUG9ydCBVU0IgSHViIHdpdGggRGVkaWNhdGVkIE9uL09mZiBTd2l0Y2gsIExlZCBJbmRpY2F0b3JzLCA0NUNtIENhYmxlIExlbmd0aCwgT3B0aW9uYWwgUG93ZXIgSW5wdXQgUG9ydCwgTXVsdGkgRGV2aWNlIGFuZCBQbHVnIFBsYXkgVXNhZ2UNCmJ5IFpFQlJPTklDUw0KaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3Byb2R1Y3QvQjBCNUg4NDZIVC9yZWY9cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8yX3RpDQouLi4NCg0KDQpBUk9QQU5BIFVTQiAzLjEgR2VuIDEgL1VTQiAzLjAgSGlnaCBTcGVlZCA1R2JwcyBIdWIgZm9yIExhcHRvcCA0IFBvcnQgUG9ydGFibGUgQWRhcHRlciB3aXRoIEluZGl2aWR1YWwgUG93ZXIgT04vT2ZmIFN3aXRjaCBhbmQgSW5kaXZpZHVhbCBCbHVlIExFRCBJbmRpY2F0b3JzIE11bHRpLVBvcnQNCmJ5IEFST1BBTkENCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwOUc5TUcxQlAvcmVmPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfM190aQ0KLi4uDQoNCg0KVFAtTGluayBVSDQwMCBVU0IgMy4wIDQtUG9ydCBQb3J0YWJsZSBEYXRhIEh1YiBmb3IgTWFjLCBpTWFjLCBNYWNCb29rIFBybyBBaXIsIFVsdHJhYm9va3MsIFRhYmxldCwgTGFwdG9wIGFuZCBBbnkgUEMsIFdpbmRvd3MsIE1hYyBPUyBYIGFuZCBMaW51eCBTeXN0ZW1zLSBCbGFjaw0KYnkgVFAtTGluaw0KaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3Byb2R1Y3QvQjAwVjRCR0QwMC9yZWY9cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF80X3RpDQouLi4NCg0KDQpbMSBNZXRlciBMb25nIENhYmxlLCA1R2JwcywgVVNCIDMuMSBHZW4gMV0gUVogVVNCIEh1YiBmb3IgTmV4dCBHZW4gT2ZmaWNlIFdvcmsgU3RhdGlvbiwgNCBQb3J0cywgVVNCIDMuMSBHZW4gMSBmb3IgUEMgYW5kIExhcHRvcHMNCmJ5IFFaDQpodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvcHJvZHVjdC9CMDExT0xQNkxHL3JlZj1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzVfdGkNCi4uLg0KDQoNClsxLjMgRmVldCBMb25nIENhYmxlLCA1R2JwcywgVVNCIDMuMSBHZW4gMV0gUVogVVNCIEh1YiBmb3IgTmV4dCBHZW4gT2ZmaWNlIFdvcmsgU3RhdGlvbiwgNCBQb3J0cywgVVNCIDMuMSBHZW4gMSBmb3IgUEMgYW5kIExhcHRvcHMNCmJ5IFFaDQpodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvcHJvZHVjdC9CMDExT05KVjdZL3JlZj1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzZfdGkNCi4uLg0KDQoNClBvcnRyb25pY3MgTXBvcnQgMzEgVVNCIEh1YiAoNC1pbi0xKSwgTXVsdGlwb3J0IEFkYXB0ZXIgd2l0aCAxIHggVVNCIDMuMCAmIDMgeCBVU0IgMi4wIFBvcnRzLCB1cCB0byA1IEdicHMgSGlnaCBTcGVlZCBEYXRhIFRyYW5zZmVyIGZvciBMYXB0b3AvUEMgKEdyZXkpDQpieSBQb3J0cm9uaWNzDQpodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvcHJvZHVjdC9CMDlNODg4OERNL3JlZj1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzdfdGkNCi4uLg0KDQoNCk9SSUNPIFVTQiAzLjAgSHViIDcgUG9ydHMgVVNCMy4wIFRyYW5zcGFyZW50IERlc2t0b3AgSFVCIHdpdGggQmx1ZSBJbmRpY2F0b3IgTGlnaHQgJiBEdWFsIFBvcnQgUG93ZXIgU3VwcGx5IHdpdGggMU0gQ2FibGUNCmJ5IE9SSUNPDQpodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvcHJvZHVjdC9CMDdLQlZSVjVIL3JlZj1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzhfdGkNCi4uLg0KDQoNClFaIEFjdGl2ZSBQb3dlcmVkIFVTQiBIdWIsIDEwIFBvcnQgVVNCIEh1YiB3aXRoIDEyViA1QSA2MFcgUG93ZXIgQWRhcHRlciwgVVNCIDMuMSBHZW4gMQ0KYnkgUVoNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwMU0wVDY0RU0vcmVmPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfOV90aQ0KLi4uDQoNCg0KWkVCUk9OSUNTIFplYi0xMDBIQiA0IFBvcnRzIFVTQiBIdWIgZm9yIExhcHRvcCwgUEMgQ29tcHV0ZXJzLCBQbHVnICYgUGxheSwgQmFja3dhcmQgQ29tcGF0aWJsZSAtIEJsYWNrDQpieSBaRUJST05JQ1MNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwN0dMTkpDMjUvcmVmPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMTBfdGkNCi4uLg0KDQoNClR1a3plciA0LVBvcnRzIFVTQiBBIHRvIFVTQiAzLjAgSFVCIHdpdGggSGlnaC1TcGVlZCBEYXRhIFRyYW5zZmVyICYgRmFzdCBDaGFyaW5nIFBvcnRzLCBDb21wYXRpYmxlIGZvciBNYWNCb29rIEFpciwgTWFjIE1pbmksIGlNYWMgUHJvLCBNaWNyb3NvZnQgU3VyZmFjZSwgVWx0cmFCb29rcywgTGFwdG9wLCBOb3RlYm9vaywgRGVza3RvcCAoV2hpdGUpDQpieSBUdWt6ZXINCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwOFFKTktYOTQvcmVmPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMTFfdGkNCi4uLg0KDQoNClZlcmlsdXjCriBVU0IgSHViIDMuMCBmb3IgUEMsIDQtUG9ydCBIaWdoIFNwZWVkIFVTQiBIdWIgd2l0aCBBbHVtaW5pdW0gU2hlbGwsIFVTQiBQb3J0IEh1YiAzLjAgQ29tcGF0aWJsZSBmb3IgUEMsIE1hY0Jvb2ssIE1hYyBQcm8sIE1hYyBNaW5pLCBpTWFjLCBTdXJmYWNlIFBybywgWFBTLCBQQyAoR3JleSkNCmJ5IFZlcmlsdXgNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwOTE2NTI1VDMvcmVmPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMTJfdGkNCi4uLg0KDQpTZWUgc2ltaWxhciBwcm9kdWN0cw0KaHR0cDovL3d3dy5hbWF6b24uaW4vZ3AvYj9pZT1VVEYtOCZub2RlPTEzNzUyNDgwMzEgDQoNCj09PT09PT09PT0NCkFtYXpvbi5pbg0KaHR0cDovL3d3dy5hbWF6b24uaW4vcmVmPXBlX2Zvb3Rlci8NCg0KQ29ubmVjdCB3aXRoIFVzDQpPbiBGYWNlYm9vaw0KaHR0cDovL3d3dy5hbWF6b24uaW4vZ3AvcmVkaXJlY3QuaHRtbC9yZWY9cGVfNDIzMzcxXzM4NDc4OTMxX3BlXzBfMzQzNl9wZV9mYl9mdHIvP2xvY2F0aW9uPWh0dHA6Ly93d3cuZmFjZWJvb2suY29tL0FtYXpvbklOJnRva2VuPTIwNzVENUVBQzdCQjIxNDA4OTcyOEUyMTgzRkQzOTE3MDZENDFFOTQNCg0KT24gVHdpdHRlcg0KaHR0cDovL3d3dy5hbWF6b24uaW4vZ3AvcmVkaXJlY3QuaHRtbC9yZWY9cGVfNDIzMzcxXzM4NDc4OTMxX3BlXzBfMzQzNl9wZV90d19mdHIvP2xvY2F0aW9uPWh0dHA6Ly90d2l0dGVyLmNvbS9BbWF6b25JTiZ0b2tlbj1BMzA5REZCRkNCMUUzN0E4MDhGRjUzMTkzNDg1NURDODE3RjEzMEI2DQoNCj09PT09PT09PT0NCg0KV2UgaG9wZSB5b3UgZm91bmQgdGhpcyBtZXNzYWdlIHRvIGJlIHVzZWZ1bC4gSG93ZXZlciwgaWYgeW91J2QgcmF0aGVyIG5vdCByZWNlaXZlIGZ1dHVyZSBlLW1haWxzIG9mIHRoaXMgc29ydCBmcm9tIEFtYXpvbi5pbiwgcGxlYXNlIHZpc2l0IHRoZSBvcHQtb3V0IGxpbmsgaGVyZToNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi8vZ3AvZ3NzL28vMTFYTHowVmxkclFGOWpweU1PbksybUlTY2wxLjdqT291VXZ6QnE4anlmM3RWYmlUS1FlZVJNaWdaSWVlTUlQVzMuDQoNClBsZWFzZSBub3RlIHRoYXQgcHJvZHVjdCBwcmljZXMgYW5kIGF2YWlsYWJpbGl0eSBhcmUgc3ViamVjdCB0byBjaGFuZ2UuIFByaWNlcyBhbmQgYXZhaWxhYmlsaXR5IHdlcmUgYWNjdXJhdGUgYXQgdGhlIHRpbWUgdGhpcyBuZXdzbGV0dGVyIHdhcyBzZW50OyBob3dldmVyLCB0aGV5IG1heSBkaWZmZXIgZnJvbSB0aG9zZSB5b3Ugc2VlIHdoZW4geW91IHZpc2l0IEFtYXpvbi5pbi4gDQoNCg0KDQpBbWF6b24uaW4gTWFya2V0cGxhY2UgcGxhdGZvcm06IFByb2R1Y3RzIHNvbGQgYnkgYSBNYXJrZXRwbGFjZSBzZWxsZXIgYXJlIHN1YmplY3QgdG8gdGhhdCBzZWxsZXIncyB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiBzYWxlLiBTZWUgd3d3LkFtYXpvbi5pbiBmb3IgZGV0YWlscy4NCg0KUmVmZXJlbmNlOiAxMjE3NzAzNTcxDQoNClRoaXMgbWVzc2FnZSB3YXMgc2VudCB0byB0aGUgZm9sbG93aW5nIGUtbWFpbCBhZGRyZXNzOiBwc2todXNoYWxAZ21haWwuY29tDQoNCg0K" - } - }, - { - "partId": "1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=utf-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 174865, - "data": "DQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KICAgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KPCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgU3RyaWN0Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXN0cmljdC5kdGQiPg0KPGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPg0KICAgIDxoZWFkPg0KICAgICAgICA8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsgY2hhcnNldD11dGYtOCI-DQogICAgICAgIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ0YXJnZXQtZGVuc2l0eWRwaT1kZXZpY2UtZHBpIj4NCiAgICAgICAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZSA9IDEuMCwgbWF4aW11bS1zY2FsZSA9IDEuMCIgLz4NCiAgICAgICAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4ud2lkZ2V0SGVhZGVyDQp7DQp0ZXh0LWRlY29yYXRpb246bm9uZTsNCmNvbG9yOiNFNDc5MTE7DQpmb250LXNpemU6MTVweDsNCmZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOw0KZm9udC13ZWlnaHQ6Ym9sZDsNCn0NCi5idG4tbGVhcm5tb3JlLXNtYWxsDQp7IA0KYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KHRvIGJvdHRvbSwjZjdkZmE1LCNmMGMxNGIpOw0KYm9yZGVyLXJhZGl1czogNXB4OyANCmZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgDQpmb250LXNpemU6IDEycHg7DQpmb250LXdlaWdodDogbm9ybWFsOw0KYm9yZGVyLWNvbG9yOiAjYTg4NzM0ICM5YzdlMzEgIzg0NmEyOSAhaW1wb3J0YW50Ow0KYm9yZGVyLXN0eWxlOnNvbGlkICFpbXBvcnRhbnQ7DQpib3JkZXItd2lkdGg6MXB4ICFpbXBvcnRhbnQ7DQpib3JkZXItY29sbGFwc2U6aW5pdGlhbCAhaW1wb3J0YW50Ow0KfQ0KLmJ0bi1hZGR0b2xpc3Qtc21hbGwNCnsNCmJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudCh0byBib3R0b20sI2Y3ZjhmYSwjZTdlOWVjKTsNCmJvcmRlci1yYWRpdXM6IDVweDsNCmZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgDQpmb250LXNpemU6IDEycHg7DQpmb250LXdlaWdodDogbm9ybWFsOw0KYm9yZGVyLWNvbG9yOiAjYWRiMWI4ICNhMmE2YWMgIzhkOTA5NiAhaW1wb3J0YW50Ow0KYm9yZGVyLXN0eWxlOnNvbGlkICFpbXBvcnRhbnQ7DQpib3JkZXItd2lkdGg6MXB4ICFpbXBvcnRhbnQ7DQptaW4td2lkdGg6IDEwMHB4Ow0KYm9yZGVyLWNvbGxhcHNlOmluaXRpYWwgIWltcG9ydGFudDsNCn0gDQpzcGFuLm1haW5tZXNzYWdlIHsNCiAgICBmb250LXNpemU6IDM0cHg7DQogICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOw0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICBsaW5lLWhlaWdodDogMTsNCiAgICBjb2xvcjogI0ZGOTkwMDsNCiAgICBmb250LXdlaWdodDogNTAwOw0KICAgIG1hcmdpbi1ib3R0b206IDVweDsNCn0NCi5vbWFfcHJfaW1hZ2Ugew0KICAgIGRpc3BsYXk6YmxvY2s7DQogIA0KfQ0KLmVtYWlsX3N1cGVyX3N1YmplY3QgYSB7DQogICAgY29sb3I6ICMzMzY2OTkgIWltcG9ydGFudDsNCn0NCi5jdGEtYnRuIHsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjRkZDNDM1Ow0KICAgIGJvcmRlci1yYWRpdXM6IDVweDsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgZm9udC1zaXplOiAxNHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KLmJ0bi1sZWFybm1vcmUtYmlnIHsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjRkZDNDM1Ow0KICAgIGJvcmRlci1yYWRpdXM6IDVweDsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgZm9udC1zaXplOiAxNHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KLmJ0bi1hZGR0b2xpc3QtYmlnIHsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjRTdFN0MyOw0KICAgIGJvcmRlci1yYWRpdXM6IDVweDsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgZm9udC1zaXplOiAxMnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KLmVtYWlsLXN1cGVyLXN1YmplY3Qgew0KICAgIGZvbnQtZmFtaWx5OiB2ZXJkYW5hLCBhcmlhbCwgc2Fucy1zZXJpZjsNCiAgICBmb250LXNpemU6IDlweDsNCiAgICBsaW5lLWhlaWdodDogMTFweDsNCiAgICBjb2xvcjogIzU1NTsNCn0NCi5oZWFkZXItbWVudSB7DQogICAgZm9udC1mYW1pbHk6IGFyaWFsLCB2ZXJkYW5hLCBzYW5zLXNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCiAgICBjb2xvcjogcmdiKDUxLCAxMDIsIDE1Myk7DQogICAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KLmludHJvLXRleHQgew0KICAgIGZvbnQtc2l6ZTogMTJweDsNCiAgICBjb2xvcjogIzMzMzMzMzsNCiAgICBmb250LXdlaWdodDogbm9ybWFsOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOw0KICAgIGxpbmUtaGVpZ2h0OiAxNnB4Ow0KICAgIHZlcnRpY2FsLWFsaWduOiB0b3A7DQogICAgcGFkZGluZzogNnB4IDE1cHggMTJweCAxNXB4Ow0KfQ0KLmZhcm1oZWFkIHsNCiAgICBmb250LWZhbWlseTogYXJpYWw7DQogICAgZm9udC1zaXplOiAxNHB4Ow0KICAgIGNvbG9yOiAjZTQ3OTExOw0KICAgIGxpbmUtaGVpZ2h0OiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KLmZhcm1oZWFkLWZvbnQgew0KICAgIGZvbnQtZmFtaWx5OiBhcmlhbDsNCiAgICBmb250LXNpemU6IDE0cHg7DQogICAgY29sb3I6ICNlNDc5MTE7DQogICAgbGluZS1oZWlnaHQ6IDE2cHg7DQp9DQoubGlua2Zhcm0tY29sLXMxIHsNCiAgICBmb250LWZhbWlseTogYXJpYWwsIGhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgICBmb250LXNpemU6IDE0cHg7DQp9DQoubGlua2Zhcm0tY29sLXMyIHsNCiAgICBmb250LWZhbWlseTogYXJpYWwsIGhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgICBmb250LXNpemU6IDEycHg7DQp9DQoubGlua2Zhcm0tbGluay1zMSB7DQogICAgY29sb3I6ICM2NjY7DQogICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOw0KfQ0KLmxlZ2FsLXRleHQgew0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBTYW5zLVNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTBweDsNCiAgICBjb2xvcjogIzY2Ng0KfQ0KLmxlZ2FsLXRleHQtYzEgew0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBTYW5zLVNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTBweDsNCiAgICBjb2xvcjogIzk5OTsNCn0NCi5sZWdhbC10ZXh0LWMyIHsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgU2Fucy1TZXJpZjsNCiAgICBmb250LXNpemU6IDEwcHg7DQogICAgY29sb3I6ICNiZmJmYmY7DQp9DQoubGVnYWwtdGV4dC1jMyB7DQogICAgZm9udC1mYW1pbHk6IFZlcmRhbmEsIEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogICAgZm9udC1zaXplOiA3cHQ7DQogICAgY29sb3I6ICMzRTdDQkI7DQp9DQouc2FsdXRhdGlvbi10ZXh0IHsNCiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7DQogICAgY29sb3I6ICMzMDM5NDI7DQogICAgZm9udC1zaXplOiAxNHB4Ow0KICAgIGNvbG9yOiAjMzAzOTQyOw0KICAgIGZvbnQtd2VpZ2h0OiBub3JtYWw7DQp9DQpib2R5IHsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZTNlM2UzOw0KfQ0KYm9keVt5YWhvb10gew0KICAgIC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogbm9uZTsNCiAgICB3aWR0aDogMTAwJTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZTNlM2UzOw0KICAgIG1hcmdpbjogMDsNCiAgICBwYWRkaW5nOiAwOw0KICAgIC13ZWJraXQtZm9udC1zbW9vdGhpbmc6IGFudGlhbGlhc2VkOw0KfQ0KLlJlYWRNc2dCb2R5IHsNCiAgICB3aWR0aDogMTAwJTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZTNlM2UzOw0KfQ0KLkV4dGVybmFsQ2xhc3Mgew0KICAgIHdpZHRoOiAxMDAlOw0KICAgIGJhY2tncm91bmQtY29sb3I6ICNlM2UzZTM7DQp9DQpodG1sIHsNCiAgICB3aWR0aDogMTAwJTsNCn0NCmJvZHlbeWFob29dIHRhYmxlIHsNCiAgICBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlOw0KfQ0KYm9keVt5YWhvb10gLmJ0biB7DQogICAgd2lkdGg6IDEwMCU7DQogICAgdGV4dC1hbGlnbjogY2VudGVyIWltcG9ydGFudDsNCn0NCmJvZHlbeWFob29dIC5mYXJtLXJvdyB7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCiAgICBwYWRkaW5nOiAzcHg7DQogICAgY29sb3I6ICMzMzMzMzMNCn0NCmJvZHlbeWFob29dIC50b3AxMC1pbWctV2lkdGggew0KICAgIHdpZHRoOiAyOTBweCFpbXBvcnRhbnQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyDQp9DQpzcGFuLm1haW5tZXNzYWdlIHsNCiAgICBmb250LXNpemU6IDM0cHg7DQogICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOw0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICBsaW5lLWhlaWdodDogMTsNCiAgICBjb2xvcjogI0ZGOTkwMDsNCiAgICBmb250LXdlaWdodDogNTAwDQp9DQpib2R5W3lhaG9vXSAuaW1hZ2UtY3NzbG90LW5vcm1hbCBpbWcgew0KICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgaGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7DQp9DQpib2R5W3lhaG9vXSB0ZFtjbGFzcz0ibGNvbCJdIGltZyB7DQogICAgd2lkdGg6IDE3NXB4ICFpbXBvcnRhbnQ7DQogICAgaGVpZ2h0OiAxNzVweCAhaW1wb3J0YW50Ow0KfQ0KLnNlZl9sZWdhbF9mb290ZXIgew0KICAgIGJhY2tncm91bmQtY29sb3I6ICNFM0UzRTM7DQp9DQouc2VmX2Zvb3Rlcl9jb25uZWN0IHsNCiAgICBib3JkZXItYm90dG9tOiAzcHggc29saWQgIzg4ODg4ODsNCiAgICBoZWlnaHQ6IDBweCAhaW1wb3J0YW50Ow0KICAgIG1heC1oZWlnaHQ6IDBweCAhaW1wb3J0YW50Ow0KICAgIGZvbnQtc2l6ZTogMHB4Ow0KICAgIG1hcmdpbjogMDsNCiAgICB3aWR0aDogMTAwJTsNCn0NCmJvZHlbeWFob29dIC5zZWZfc3BhY2VyIGRpdiB7DQogICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCJodHRwczovL2ltYWdlcy1uYS5zc2wtaW1hZ2VzLWFtYXpvbi5jb20vaW1hZ2VzL0cvMDEvdGVtcGxhdGUvc2VjdGlvbi1kaXZfNjQweDguanBnIikgIWltcG9ydGFudDsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjRkZGRkZGOw0KICAgIGhlaWdodDogMTBweCAhaW1wb3J0YW50Ow0KICAgIGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7DQp9DQpAbWVkaWEgb25seSBzY3JlZW4gYW5kIChtYXgtd2lkdGg6IDY4MHB4KSB7DQogICAgLm1vYmlsZS1oaWRlLWdtYWlsIHsNCiAgICAgICAgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50Ow0KICAgICAgICBvdmVyZmxvdzpoaWRkZW4gIWltcG9ydGFudDsNCiAgICAgICAgbXNvLWhpZGU6YWxsICFpbXBvcnRhbnQ7DQogICAgICAgIGxpbmUtaGVpZ2h0OiAwcHggIWltcG9ydGFudDsNCiAgICB9DQogICAgLm1vYmlsZS1oaWRlLWdtYWlsIHRhYmxlew0KICAgICAgICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7DQogICAgICAgIG92ZXJmbG93OmhpZGRlbiAhaW1wb3J0YW50Ow0KICAgICAgICBtc28taGlkZTphbGwgIWltcG9ydGFudDsNCiAgICAgICAgbGluZS1oZWlnaHQ6IDBweCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICANCiAgICBib2R5W3lhaG9vXSAuZGV2aWNlV2lkdGggew0KICAgICAgICB3aWR0aDogMTAwJSFpbXBvcnRhbnQNCiAgICB9DQogICAgYm9keVt5YWhvb10gdGRbY2xhc3M9ImNvbCJdIGEgaW1nIHsNCiAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICAgICAgbWF4LXdpZHRoOiA2MHB4ICFpbXBvcnRhbnQ7DQogICAgICAgIGhlaWdodDogYXV0byAhaW1wb3J0YW50Ow0KICAgICAgICBtaW4td2lkdGg6IDQxcHggIWltcG9ydGFudDsNCiAgICB9DQogICAgdGRbY2xhc3M9ImNvbCJdIHsNCiAgICAgICAgd2lkdGg6IDMwJSAhaW1wb3J0YW50Ow0KICAgICAgICBtYXgtd2lkdGg6IDYwcHggIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmZhcm1MaW5rcyB7DQogICAgICAgIHdpZHRoOiBhdXRvICFpbXBvcnRhbnQ7DQogICAgICAgIHRleHQtYWxpZ246IGxlZnQgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmZhcm1MaW5rcyB0ZCB7DQogICAgICAgIHRleHQtYWxpZ246IGxlZnQgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gdGRbY2xhc3M9ImZhcm1Db250YWluZXIiXSB7DQogICAgICAgIHdpZHRoOiA1MCUgIWltcG9ydGFudDsNCiAgICAgICAgdGV4dC1hbGlnbjogbGVmdCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2Zvb3Rlcl9saW5rZmFybSB0ZCB7DQogICAgICAgIHdpZHRoOiBhdXRvICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5zZWZfZm9vdGVyX2xpbmtmYXJtIHRhYmxlIHsNCiAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9sZWdhbF9mb290ZXIsDQogICAgYm9keVt5YWhvb10gLnNlZl9zcGFjZXIsDQogICAgYm9keVt5YWhvb10gLnNlZl9mb290ZXJfY29ubmVjdCwNCiAgICBib2R5W3lhaG9vXSAuc2VmX2xlZ2FsX2Zvb3RlciwNCiAgICBib2R5W3lhaG9vXSAuc2VmX2Zvb3Rlcl9saW5rZmFybSB7DQogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5zZWZfZm9vdGVyX2xpbmtmYXJtIHRyOmxhc3QtY2hpbGQgdGQsDQogICAgYm9keVt5YWhvb10gLnNlZl9mb290ZXJfbGlua2Zhcm0gdHI6Zmlyc3QtY2hpbGQgdGQgew0KICAgICAgICB3aWR0aDogMTAwJTsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9mb290ZXJfbGlua2Zhcm0gdHIgdGQgdGFibGUgew0KICAgICAgICB3aWR0aDogMTAwJTsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmJ0biB7DQogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgICAgIHRleHQtYWxpZ246IGNlbnRlciFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIHRkW2NsYXNzPSJ4LXNpdGUtdGFibGV0Il0gew0KICAgICAgICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5zZXBlcmF0b3Igew0KICAgICAgICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VwZXJhdG9yIGltZyB7DQogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgICAgIGhlaWdodDogYXV0bzsNCiAgICB9DQp9DQpAbWVkaWEgb25seSBzY3JlZW4gYW5kIChtYXgtd2lkdGg6IDU5OXB4KSB7DQogICAgYm9keVt5YWhvb10gLnRvcDEwLWltZy1XaWR0aCB7DQogICAgICAgIHdpZHRoOiA0NDBweCFpbXBvcnRhbnQ7DQogICAgICAgIHRleHQtYWxpZ246IGNlbnRlcg0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuY2VudGVyIHsNCiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmZvb3RlckxpbmtzIHsNCiAgICAgICAgd2lkdGg6IDMyJTsNCiAgICAgICAgbWFyZ2luLWJvdHRvbTogNDBweA0KICAgIH0NCiAgICBib2R5W3lhaG9vXSB0ZFtjbGFzcz0ibGNvbCJdLA0KICAgIGJvZHlbeWFob29dIHRkW2NsYXNzPSJyY29sIl0gew0KICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2sgIWltcG9ydGFudDsNCiAgICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrOw0KICAgICAgICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KICAgICAgICBmbG9hdDogbm9uZSAhaW1wb3J0YW50Ow0KICAgICAgICBvdmVyZmxvdzogdmlzaWJsZSAhaW1wb3J0YW50Ow0KICAgICAgICBtYXgtaGVpZ2h0OiBub25lICFpbXBvcnRhbnQ7DQogICAgICAgIHBhZGRpbmc6IDBweCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuZmFybUxpbmtzIHsNCiAgICAgICAgbWluLXdpZHRoOiAxNDhweCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuZmFybUJvdHRvbSB7DQogICAgICAgIHdpZHRoOiAxMDAlIWltcG9ydGFudA0KICAgIH0NCiAgICBib2R5W3lhaG9vXSB0ZFtjbGFzcz0icGVfYXNpbiJdIHsNCiAgICAgICAgcGFkZGluZzogNHB4IDE1cHggNHB4IDE1cHggIWltcG9ydGFudDsNCiAgICB9DQp9DQpAbWVkaWEgb25seSBzY3JlZW4gYW5kIChtYXgtd2lkdGg6IDUxNXB4KSB7DQogICAgYm9keVt5YWhvb10gLmxvZ29Ub3Agew0KICAgICAgICB3aWR0aDogMTAwJSFpbXBvcnRhbnQNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnRvcDEwLWltZy1XaWR0aCB7DQogICAgICAgIHdpZHRoOiAyOTBweCFpbXBvcnRhbnQ7DQogICAgICAgIHRleHQtYWxpZ246IGNlbnRlcg0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuY2VudGVyIHsNCiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmZvb3RlckxpbmtzIHsNCiAgICAgICAgd2lkdGg6IDMyJTsNCiAgICAgICAgbWFyZ2luLWJvdHRvbTogNDBweA0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuYnRuIHsNCiAgICAgICAgd2lkdGg6IDEwMCU7DQogICAgICAgIHRleHQtYWxpZ246IGNlbnRlciFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIHRkW2NsYXNzPSJ4LXNpdGUiXSwNCiAgICBib2R5W3lhaG9vXSAueC1zaXRlIHsNCiAgICAgICAgZGlzcGxheTogbm9uZTsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9mb290ZXJfbGlua2Zhcm0gew0KICAgICAgICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5zZWZfc3BhY2VyIHsNCiAgICAgICAgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2Zvb3Rlcl9jb25uZWN0IHsNCiAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9sZWdhbF9mb290ZXIgew0KICAgICAgICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAubG9nb1RvcCAuY2VudGVyIGEgew0KICAgICAgICB0ZXh0LWRlY29yYXRpb246IG5vbmUgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmxvZ29Ub3AgdGQgew0KICAgICAgICBwYWRkaW5nOiByaWdodDogMHB4ICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5hbWF6b25Mb2dvIHsNCiAgICAgICAgcGFkZGluZzogMCAxMHB4ICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC50b3BNZW51IHsNCiAgICAgICAgcGFkZGluZzogMCAwIDVweCAwICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5jcy1pbWFnZS1zbG90IHsNCiAgICAgICAgbWFyZ2luOiBhdXRvOw0KICAgIH0NCn0NCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogNTk5cHgpIHsNCiAgICBib2R5W3lhaG9vXSB0ZFtjbGFzcz0icGFja0NvbCJdIHsNCiAgICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrICFpbXBvcnRhbnQ7DQogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgICAgIGZsb2F0OiBub25lICFpbXBvcnRhbnQ7DQogICAgICAgIG92ZXJmbG93OiB2aXNpYmxlICFpbXBvcnRhbnQ7DQogICAgICAgIG1heC1oZWlnaHQ6IG5vbmUgIWltcG9ydGFudDsNCiAgICAgICAgcGFkZGluZzogMHB4ICFpbXBvcnRhbnQ7DQogICAgfQ0KfQ0KICAgICAgICA8L3N0eWxlPg0KICAgIDwvaGVhZD4NCiAgICA8Ym9keT48aW1nIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHNyYz0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MkhJNlRJSTEwTUhRWiZUPU8mVT1odHRwcyUzQSUyRiUyRmltYWdlcy1ldS5zc2wtaW1hZ2VzLWFtYXpvbi5jb20lMkZpbWFnZXMlMkZHJTJGMDElMkZuYXYlMkZ0cmFuc3AuZ2lmJkg9NlJFS0lGUFBDWlROOVhXUE9FQVBFSU5FRERJQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfb3BlbnMiIC8-DQogICAgDQogICAgDQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICA8dGFibGUgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBib3JkZXI9IjAiIGNsYXNzPSJtb2JpbGUtaGlkZS1nbWFpbCI-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxIiBjbGFzcz0iaGlkZSIgc3R5bGU9Im1pbi13aWR0aDo3MDBweCAhaW1wb3J0YW50OyBmb250LXNpemU6MHB4O2xpbmUtaGVpZ2h0OjBweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgPGltZyBoZWlnaHQ9IjEiIHN0eWxlPSJtaW4td2lkdGg6IDcwMHB4ICFpbXBvcnRhbnQ7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgYm9yZGVyOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyIgLz4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgIA0KICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjEwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6ICNlM2UzZTMiDQogICAgICAgICAgICB5YWhvbz0iZml4Ij4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICA8dGQgdmFsaWduPSJtaWRkbGUiPg0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCg0KPHRhYmxlIHdpZHRoPSI2NDAiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBjbGFzcz0iZGV2aWNlV2lkdGgiPg0KICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICA8dGQgc3R5bGU9InBhZGRpbmc6MCAwIDEwcHggMDsgZm9udC1zaXplOjA7IGhlaWdodDowOyIgY2xhc3M9Ingtc2l0ZSIgdmFsaWduPSJib3R0b20iPg0KICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgPC90YWJsZT4NCg0KICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICA8dGQgYWxpZ249InJpZ2h0IiBjbGFzcz0iaGVhZGVyLWNzc2xvdCI-DQoNCg0KDQogICAgDQoNCiAgICANCg0KICAgIA0KICAgICAgIA0KICAgICAgICAgDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KPC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQo8L3RhYmxlPg0KDQo8dGFibGUgd2lkdGg9IjY0MCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGNsYXNzPSJkZXZpY2VXaWR0aCI-DQogICAgPHRyPg0KICAgICAgPHRkIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJoZWFkZXItY3NzbG90Ij4NCiAgICAgICAgDQoNCg0KDQogICAgDQogICAgICAgDQogICAgICAgICANCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KPC90ZD4NCiAgICA8L3RyPg0KDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjQwIiBoZWlnaHQ9IjYiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIg0KICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9ImRldmljZVdpZHRoIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwMCUiIGJnY29sb3I9IiNlM2UzZTMiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJib3JkZXItYm90dG9tOiA2cHggc29saWQgI0ZGOTkwMDsgaGVpZ2h0OiAwcHggIWltcG9ydGFudDsgbWF4LWhlaWdodDogMHB4ICFpbXBvcnRhbnQ7IGZvbnQtc2l6ZTowcHg7IG1hcmdpbjogMDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8cD4mbmJzcDs8L3A-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgPHRhYmxlIHdpZHRoPSI2NDAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgIGJnY29sb3I9IiNmZmZmZmYiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2ZmZmZmZiIgY2xhc3M9ImRldmljZVdpZHRoIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGhlaWdodD0iNXB4IiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgYWxpZ249ImNlbnRlciIgY2xhc3M9ImRldmljZVdpZHRoIj4NCiAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGQ-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTAwJSIgdmFsaWduPSJtaWRkbGUiID4NCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tIEJlZ2luIFNpbXBsZSBUZW1wbGF0ZSAtLT4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI-DQogICAgQG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWF4LXdpZHRoOiA0ODBweCkgew0KICAgIGJvZHlbeWFob29dIC5sb2dvVG9wLCAubG9nb1RvcCB0YWJsZSAgeyB3aWR0aDogMzAwcHggIWltcG9ydGFudDsgfQ0KICAgIGJvZHlbeWFob29dIC5sb2dvVG9wIC5zZWZfbG9nb19jb250ZW50IHsgDQogICAgcGFkZGluZzogMTBweCAyMHB4IDAgMjBweCAhaW1wb3J0YW50OyANCiAgICBib3JkZXItdG9wOiBzb2xpZCA0cHggI2Y2OTQwNCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAubG9nb1RvcCAuc3BhY2VyIHsgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50OyB9DQogICAgYm9keVt5YWhvb10gLmxvZ29Ub3AgLnRvcE1lbnUgeyBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7IH0NCiAgICBib2R5W3lhaG9vXSAubG9nb1RvcCwgLmxvZ29Ub3AgdGQgeyBkaXNwbGF5OiBpbmxpbmUgIWltcG9ydGFudDsgfQ0KICAgIGJvZHlbeWFob29dIC5zZWZfbG9nb19oZWFkZXIsIGJvZHlbeWFob29dIC5zZWZfbG9nb19oZWFkZXIgdGFibGUgIHsgd2lkdGg6IDMwMHB4ICFpbXBvcnRhbnQ7IH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2xvZ29faGVhZGVyIC5zZWZfbG9nb19jb250ZW50IHsNCiAgICBwYWRkaW5nOiAxMHB4IDIwcHggMCAyMHB4ICFpbXBvcnRhbnQ7DQogICAgYm9yZGVyLXRvcDogc29saWQgNHB4ICNmNjk0MDQgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9sb2dvX2hlYWRlciwgYm9keVt5YWhvb10gLnNlZl9sb2dvX2hlYWRlciB0YWJsZSAgeyB3aWR0aDogMzAwcHggIWltcG9ydGFudDsgfQ0KICAgICAgICBib2R5W3lhaG9vXSAuc2VmX2xvZ29faGVhZGVyIC5zZWZfbG9nb19jb250ZW50IHsNCiAgICAgICAgICAgIHBhZGRpbmc6IDEwcHggMjBweCAwIDIwcHggIWltcG9ydGFudDsNCiAgICAgICAgICAgIGJvcmRlci10b3A6IHNvbGlkIDRweCAjZjY5NDA0ICFpbXBvcnRhbnQ7DQogICAgICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2xvZ29faGVhZGVyIC5zcGFjZXIgeyBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7IH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2xvZ29faGVhZGVyIC5zZWZfaGVhZGVyX21lbnUgeyBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7IH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2xvZ29faGVhZGVyIHRyLCBib2R5W3lhaG9vXSAuc2VmX2xvZ29faGVhZGVyIHRkIHsgZGlzcGxheTogaW5saW5lICFpbXBvcnRhbnQ7IH0NCiAgICB9DQo8L3N0eWxlPg0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KICAgIGJvZHlbeWFob29dIC5zZXBlcmF0b3Ige3dpZHRoOiAxMDAlICFpbXBvcnRhbnQ7fQ0KICAgIGJvZHlbeWFob29dIC5zZXBlcmF0b3IgaW1nIHt3aWR0aDogMTAwJSAhaW1wb3J0YW50OyBoZWlnaHQ6IGF1dG87fQ0KPC9zdHlsZT4NCjx0YWJsZSBiZ2NvbG9yPSIjRkZGRkZGIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9ImxvZ29Ub3AiIGFsaWduPSJsZWZ0Ij4NCiAgICA8dGJvZHk-DQogICAgICAgIDx0cj4NCiAgICAgICAgICAgIDx0ZCBjbGFzcz0iY2VudGVyIj4NCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xQUg4SFZHUThKTEc5JlQ9QyZVPWh0dHAlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9zZWZfbG9nbyZIPThLSDZPVUVIRUQ2UFlaRkFEVE4yNVZNWkNMQ0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3NlZl9sb2dvIj4NCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8aW1nIHNyYz0iaHR0cHM6Ly9pbWFnZXMtZXUuc3NsLWltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzMxL2VtYWlsL2luL2xvZ28vYW1hem9uX3ByaW1lX2xvZ29faW5fMTUweDQ4LmpwZyIgYWx0PSJBbWF6b24uaW4iIGJvcmRlcj0iMCIgaHNwYWNlPSI2IiB2c3BhY2U9IjYiPg0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgIDwvdHI-DQogICAgPC90Ym9keT4NCjwvdGFibGU-DQo8dGFibGUgY2xhc3M9ImxvZ29Ub3AgIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIxMCIgY2VsbHNwYWNpbmc9IjAiIGFsaWduPSJyaWdodCI-DQogICAgPHRib2R5Pg0KICAgICAgICA8dHI-DQogICAgICAgICAgICA8dGQgYWxpZ249InJpZ2h0IiBjbGFzcz0idG9wTWVudSI-DQogICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9Im1hcmdpbjowIGF1dG87Ij4NCiAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0iY2VudGVyIj48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj00MEFWT01XNUxORU8mVD1DJlU9aHR0cCUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnlvdXJzdG9yZSUyRmhvbWUlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX3lvdXJzdG9yZSUyRiZIPVpWVjA5ME5WWjJDNjJRQVhLMUNMS0tRU0FKUUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX3lvdXJzdG9yZSIgc3R5bGU9ImZvbnQtZmFtaWx5OiBhcmlhbCx2ZXJkYW5hLHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6IHJnYig1MSwgMTAyLCAxNTMpOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtd2VpZ2h0OiBib2xkO3RleHQtYWxpZ246Y2VudGVyOyB3b3JkLXdyYXA6IG5vcm1hbCAhIGltcG9ydGFudDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZb3VyIEFtYXpvbi5pbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgcm93c3Bhbj0iMiIgd2lkdGg9IjgiPiZuYnNwOzwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNjY2MiIHdpZHRoPSIyIiBoZWlnaHQ9IjE1Ij48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCByb3dzcGFuPSIyIiB3aWR0aD0iMTIiPiZuYnNwOzwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJjZW50ZXIiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9mLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPUQyN1c3RFNPVUMwSiZUPUMmVT1odHRwJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcmVkaXJlY3QuaHRtbCUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfZGVhbHMlM0Zsb2NhdGlvbiUzRGh0dHAlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZnb2xkYm94Jkg9VVpMQllPMDIwTlE1MkNZOU1NWlJKRFpHWURZQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfZGVhbHMiIHN0eWxlPSJmb250LWZhbWlseTogYXJpYWwsdmVyZGFuYSxzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiByZ2IoNTEsIDEwMiwgMTUzKTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXdlaWdodDogYm9sZDt0ZXh0LWFsaWduOmNlbnRlcjsgd29yZC13cmFwOiBub3JtYWwgISBpbXBvcnRhbnQ7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVG9kYXkncyBEZWFscw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgcm93c3Bhbj0iMiIgd2lkdGg9IjgiPiZuYnNwOzwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNjY2MiIHdpZHRoPSIyIiBoZWlnaHQ9IjE1Ij48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCByb3dzcGFuPSIyIiB3aWR0aD0iOCI-Jm5ic3A7PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImNlbnRlciI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL2YuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9Mkk5WFBLMURNNDFZRyZUPUMmVT1odHRwJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcmVkaXJlY3QuaHRtbCUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfYXBwJTJGJTNGbG9jYXRpb24lM0RodHRwJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRm1zaG9wJkg9R0RZRUZSTFNJUEpQVVlRTFNYSENTVFFOSjdNQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfYXBwIiBzdHlsZT0iZm9udC1mYW1pbHk6IGFyaWFsLHZlcmRhbmEsc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyBjb2xvcjogcmdiKDUxLCAxMDIsIDE1Myk7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgZm9udC13ZWlnaHQ6IGJvbGQ7dGV4dC1hbGlnbjpjZW50ZXI7IHdvcmQtd3JhcDogbm9ybWFsICEgaW1wb3J0YW50OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdldCBBbWF6b24gQXBwDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCByb3dzcGFuPSIyIiB3aWR0aD0iOCIgY2xhc3M9Ingtc2l0ZSI-Jm5ic3A7PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgIDwvdHI-DQogICAgPC90Ym9keT4NCjwvdGFibGU-DQoNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tIEVuZCBTaW1wbGUgVGVtcGxhdGUgLS0-DQogICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KPCEtLSAgRW5kIEhFQURFUiAtLT48dGFibGUgd2lkdGg9IjY0MCIgY2xhc3M9ImRldmljZVdpZHRoIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYWxpZ249ImNlbnRlciIgYmdjb2xvcj0iI0ZGRkZGRiI-DQogICAgPHRyPg0KICAgICAgICA8dGQgYWxpZ249ImNlbnRlciI-DQogICAgICAgICAgICA8aW1nIHNyYz0iaHR0cHM6Ly9pbWFnZXMtbmEuc3NsLWltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzE1L2VtYWlsL3RlbXBsYXRlL3N0dWRlbnQvY3VzdG9tLXJ1bGVfNjQwLl9DQjM4Njg1NjEyOV8uZ2lmIg0KICAgICAgICAgICAgICAgIGFsdD0iPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ICIgYm9yZGVyPSIwIiBhbGlnbj0ibWlkZGxlIiBjbGFzcz0iZGV2aWNlV2lkdGgiDQogICAgICAgICAgICAgICAgc3R5bGU9ImJpY3ViaWM7IG1heC13aWR0aDo2NDBweDsgbWF4LWhlaWdodDo4cHg7IGNvbG9yOiNDQ0NDQ0M7IGxpbmUtaGVpZ2h0OjFweCINCiAgICAgICAgICAgICAgICAvPg0KICAgICAgICA8L3RkPg0KICAgIDwvdHI-DQo8L3RhYmxlPg0KDQoNCiAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIDx0YWJsZSBhbGlnbj0iY2VudGVyIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7IHdpZHRoOjEwMCU7IiA-DQogICAgICAgIDx0cj4NCiAgICAgICAgICAgIDx0ZCBjbGFzcz0iQWxleGEtYmFubmVyIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249Im1pZGRsZSI-DQoNCg0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCg0KICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgPC90cj4NCiAgICA8L3RhYmxlPg0KICAgICAgICANCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICANCg0KICAgIDx0YWJsZSAgd2lkdGg9IjYxMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIxNSIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0iZGV2aWNlV2lkdGgiIHN0eWxlPSJ3aWR0aDoxMDAlOyI-DQogICAgPHRib2R5Pg0KICAgICAgPHRyPg0KICAgICAgICA8dGQgY2xhc3M9ImludHJvLXRleHQiIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0Ij4NCiAgICAgICAgICA8c3BhbiBjbGFzcz0ic2FsdXRhdGlvbi10ZXh0Ij4NCiAgICAgICAgICAgICAgICBIZWxsbyBLaHVzaGFsIFAgUywNCiAgICAgICAgICAgICAgDQogICAgICAgICAgDQogICAgICAgICAgPGJyPkFyZSB5b3UgbG9va2luZyBmb3Igc29tZXRoaW5nIGluIG91ciA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xV0JRSEs3QUdHV0UzJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkYlM0Zub2RlJTNEMTM3NTI0ODAzMSUyNnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxJkg9Mk5NR1dKQUlMUVpDQUNOUzFBR1FQSjFEWjBVQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzEiPkFDQ0VTU09SWSBPUiBQQVJUIE9SIFNVUFBMWTwvYT4gc3RvcmU_IElmIHNvLCB5b3UgbWlnaHQgYmUgaW50ZXJlc3RlZCBpbiB0aGVzZSBpdGVtcy4NCiANCiAgICAgICAgPC9zcGFuPg0KDQogICAgICAgIDwvdGQ-DQogICAgICA8L3RyPg0KICAgIDwvdGJvZHk-DQo8L3RhYmxlPg0KPHRhYmxlIHdpZHRoPSI2NDAiIGNsYXNzPSJkZXZpY2VXaWR0aCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGFsaWduPSJjZW50ZXIiIGJnY29sb3I9IiNGRkZGRkYiPg0KICAgIDx0cj4NCiAgICAgICAgPHRkIGFsaWduPSJjZW50ZXIiPg0KICAgICAgICAgICAgPGltZyBzcmM9Imh0dHBzOi8vaW1hZ2VzLW5hLnNzbC1pbWFnZXMtYW1hem9uLmNvbS9pbWFnZXMvRy8xNS9lbWFpbC90ZW1wbGF0ZS9zdHVkZW50L2N1c3RvbS1ydWxlXzY0MC5fQ0IzODY4NTYxMjlfLmdpZiINCiAgICAgICAgICAgICAgICBhbHQ9Ij0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSAiIGJvcmRlcj0iMCIgYWxpZ249Im1pZGRsZSIgY2xhc3M9ImRldmljZVdpZHRoIg0KICAgICAgICAgICAgICAgIHN0eWxlPSJiaWN1YmljOyBtYXgtd2lkdGg6NjQwcHg7IG1heC1oZWlnaHQ6OHB4OyBjb2xvcjojQ0NDQ0NDOyBsaW5lLWhlaWdodDoxcHgiDQogICAgICAgICAgICAgICAgLz4NCiAgICAgICAgPC90ZD4NCiAgICA8L3RyPg0KPC90YWJsZT4NCiAgICANCiAgICANCiAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGJvcmRlcj0iMCIgYmdjb2xvcj0iI0ZGRkZGRiIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBjbGFzcz0id2lkZ2V0X2hlYWRlciIgYWxpZ249ImNlbnRlciIgc3R5bGU9Im1pbi13aWR0aDoxMDAlOyI-DQogICAgPHRyPg0KICAgICAgICA8dGQgY29sc3Bhbj0iMyIgd2lkdGg9IjEwMCUiPg0KICAgICAgICAgICAgPGRpdiB3aWR0aD0iMTAwJSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZTo4cHg7bGluZS1oZWlnaHQ6OHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgIDwvdGQ-DQogICAgPC90cj4NCiAgICA8dHI-DQogICAgICAgIDx0ZCB3aWR0aD0iMyUiPg0KICAgICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MXB4O2xpbmUtaGVpZ2h0OjFweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICA8L3RkPg0KICAgICAgICA8dGQgaGVpZ2h0PSIxNiIgd2lkdGg9Ijk3JSI-DQogICAgICAgICAgICA8dGFibGUgYm9yZGVyPSIwIiBiZ2NvbG9yPSIjRkZGRkZGIiBjZWxsc3BhY2luZz0iMiIgYWxpZ249ImxlZnQiIGNlbGxwYWRkaW5nPSIwIiBjbGFzcz0id2lkZ2V0X2NvbnRlbnQiPg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDAlIiB2YWxpZ249ImJvdHRvbSIgY2xhc3M9ImNhdGVnb3J5Ij4gPHNwYW4gY2xhc3M9IndpZGdldEhlYWRlciIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiNFNDc5MTE7Zm9udC1zaXplOjE1cHg7Zm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7Zm9udC13ZWlnaHQ6Ym9sZDsiPkFDQ0VTU09SWSBPUiBQQVJUIE9SIFNVUFBMWTwvc3Bhbj4gPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMCI-DQogICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxMCIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxcHg7bGluZS1oZWlnaHQ6MXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgIDwvdGQ-DQogICAgPC90cj4NCiAgICAgPHRyPg0KICAgICAgICAgPHRkIGNvbHNwYW49IjMiPg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQogPHRhYmxlIHdpZHRoPSI5NyUiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0ic2VwZXJhdG9yIiBzdHlsZT0ibWluLXdpZHRoOjk3JTsiPg0KICAgIDx0Ym9keT4NCiAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxMDAlIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgPC90cj4NCiAgICAgICAgPHRyIGhlaWdodD0iMSI-DQogICAgICAgICAgICA8dGQgYmdjb2xvcj0iI2VhZWJlYyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMSI-DQogICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMTAwJSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxcHg7bGluZS1oZWlnaHQ6MXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICA8dGQgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEwMCUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgIDwvdGJvZHk-DQo8L3RhYmxlPg0KICAgICAgICAgPC90ZD4NCiAgICAgPC90cj4NCiAgICANCjwvdGFibGU-DQogICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICANCiAgICAgICAgDQoNCiAgICANCiAgICANCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIAkgICAgICAgIA0KICAgIA0KDQogICAgDQogICAgDQogICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICAgICAgICANCiAgICAgICAgDQogICAgDQogICAgDQoNCg0KDQoNCg0KPHRhYmxlIHdpZHRoPSI2NDAiPg0KICAgPHRyPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjYyMCIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0IiBjbGFzcz0icHJfY29udGFpbmVyIj4NCiAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgY2xhc3M9Imxpc3RfcHJvZHVjdCI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE1MCIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiIGNsYXNzPSJwcl9pbWFnZSI-DQogICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9S0VSTVRBWFdXVkcyJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwOEpIWVdKTVAlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzFfaW0mSD1VQTFDVkFOVFFYVzQ3TkIyQ0ZBQkJEUlo1UVdBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8xX2ltIj4NCiAgICAgICAgICAgICAgPGltZyBzcmM9Imh0dHBzOi8vbS5tZWRpYS1hbWF6b24uY29tL2ltYWdlcy9JLzMxUUlPOXdjR1pMLl9TUjUwMCw1MDBfLl9TTDE0MF8uanBnIiBjbGFzcz0icHJfaW1hZ2VfMTc1IHByX2ltYWdlX2Rlc2t0b3AiIGFsdD0iQW1rZXR0ZSA0IFBvcnQgU3VwZXJzcGVlZCBVU0IgSHViIDMuMCBmb3IgUEMvTGFwdG9wcywgUG9ydGFibGUgRGF0YSBIdWIgd2l0aCBIaS1TcGVlZCBEYXRhIFRyYW5zZmVyIFVwIHRvIDUgR0JQUywgQ2hhcmdpbmcgRnVuY3Rpb258IFN0cm9uZyBhbmQgRHVyYWJsZSwgUG93ZXIgU3VwcGx5IFBvcnQgYW5kIDgwIGNtIExvbmcgQ2FibGUgKEJsYWNrKSIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjM2NSIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0Ij4NCiAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl90aXRsZSI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICANCg0KDQogICAgDQoNCg0KICAgIA0KDQoNCg0KDQoNCjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxNXB4O2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtYWxpZ246bGVmdDtjb2xvcjojMzM2Njk5OyI-DQogICAgIDxhIGNsYXNzPSJvbWFfcHJfdGl0bGUiIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPVU3NjJXRFJVMkIxVCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDhKSFlXSk1QJTNGcmVmJTNEZW1fMXBfMV90aSUyNnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxJkg9VlNSWUQ3UUNCQlBISERKRlJLTFpaUFZISlpXQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzEiIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyBjb2xvcjojMzM2Njk5OyI-DQogICAgICAgICAgQW1rZXR0ZSA0IFBvcnQgU3VwZXJzcGVlZCBVU0IgSHViIDMuMCBmb3IgUEMvTGFwdG9wcywgUG9ydGFibGUuLi48L2E-DQo8L3NwYW4-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9ieWxpbmUiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KDQoNCg0KDQoNCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICAgICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgIA0KICAgIA0KICAgIA0KDQogICAgDQogICAgICAgIDxzcGFuIGNsYXNzPSJvbWEtcHItYmwiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxIZWx2ZXRpY2EsU2Fucy1TZXJpZjtmb250LXNpemU6MTJweDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzMzMzt0ZXh0LWFsaWduOmxlZnQ7Ij4NCiAgICAgICAgICAgICA8YnI-IGJ5DQogICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9Mkw1N04zUkRTM0NLJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRnN0b3JlcyUyRkFta2V0dGUlMkZwYWdlJTJGNjUxRTBENTAtNTE3Ni00RTlFLTg3NTYtRUEwRDkyQTk3Qzg4JTNGcmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfYXN0X2JsbiUyNnN0b3JlX3JlZiUzRGJsX2FzdF9kcF9icmFuZExvZ29fc3RvJkg9R1hVVUtLR09PNVFENThRN01JSTFTVkcwUUc0QSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfYXN0X2JsbiIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjogbm9uZTsgZm9udC1zaXplOiAxMnB4OyBjb2xvcjojMzM2Njk5OyI-QW1rZXR0ZTwvYT4NCiAgICAgICAgPC9zcGFuPg0KICAgIA0KDQogDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0ic3BhY2VyIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX2xpc3QiPg0KICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTS5SLlAuOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9saXN0Ij4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzdHJpa2U-4oK5MSwzOTkuMDA8L3N0cmlrZT4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX291ciI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcmljZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEzcHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJwcl9wcmljZV9oaWdobGlnaHQiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrk5MjguMDAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWW91IFNhdmU6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogbm9ybWFsOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJvbWFfcHJfcHJpY2VfdmFsX3NhdmluZ3MiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4oK5NDcxLjAwIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgzNCUpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KDQoNCg0KDQoNCg0KICAgIA0KDQoNCg0KCQ0KDQoNCg0KDQoNCg0KDQoJDQoNCg0KDQoJDQoNCgkNCg0KICAgIA0KCSAgICAgDQogICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgPHRyIGNsYXNzPSJwcl9tZXJjaGFudCI-DQogICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCxIZWx2ZXRpY2Esc2Fucy1zZXJpZjsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgY29sb3I6IzU1NTU1NTsgZm9udC1zaXplOjEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICBTb2xkIGJ5IA0KICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJSQVY0MUNJWEYzTUEmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZhYWclMkZtYWluJTNGaWUlM0RVVEY4JTI2YXNpbiUzREIwOEpIWVdKTVAlMjZpc0FtYXpvbkZ1bGZpbGxlZCUzRDElMjZtYXJrZXRwbGFjZUlEJTNEQTIxVEpSVVVONEtHViUyNnByb3RvY29sJTNEY3VycmVudCUyNnNlbGxlciUzREFKNlNJWkM4WVFEWlglMjZzc2htUGF0aCUzRCUyNnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxJkg9QkFQVkszTUFTVlBTUkxUV1M0TldBT1hDNVdRQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzEiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTsgZm9udC13ZWlnaHQ6bm9ybWFsOyBmb250LXNpemU6MTJweDtjb2xvcjogIzMzNjY5OTsiPkNsaWNrdGVjaCBSZXRhaWwgUHJpdmF0ZSBMdGQ8L2E-IGFuZCANCiAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6MTJweDsiPkZ1bGZpbGxlZCBieSBBbWF6b248L3NwYW4-Lg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8L3NwYW4-IA0KICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgPC90cj4NCiAgICANCg0KDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDUiIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0idG9wIj4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCg0KDQo8ZGl2IGNsYXNzPSJwcl9sZWFybl9tb3JlIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0iZGlzcGxheTogaW5saW5lLWJsb2NrOyI-DQogICAgICAgIDx0YWJsZSBjbGFzcz0iYnRuLWxlYXJubW9yZS1zbWFsbCIgIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMyIgc3R5bGU9ImNvbG9yOiAjMTExOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgIHdoaXRlLXNwYWNlOiBub3dyYXA7YmFja2dyb3VuZC1jb2xvcjogI0ZFQzY1MDsgZm9udC1zaXplOjEwcHg7IHRleHQtYWxpZ246Y2VudGVyOyBib3JkZXItcmFkaXVzOiA1cHg7Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgIDx0ZCBub3dyYXA-DQogICAgICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPUFETFVZOUpBNkEyRSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDhKSFlXSk1QJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8xX2xtJkg9V0taMEoyNzVBS1Y1NkZBMlJFTTVUV1BRVkhTQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMV9sbSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMTExOyI-DQogICAgICAgICAgICAgICAgICAgICAgICBMZWFybiBtb3JlDQogICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgPC90YWJsZT4NCjwvZGl2Pg0KDQoNCg0KIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPiA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJzZXBlcmF0b3IiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCBiZ2NvbG9yPSIjZWFlYmVjIiB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjFweDtsaW5lLWhlaWdodDoxcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgIDwvdHI-DQo8L3RhYmxlPg0KICAgIA0KICAgIA0KICAgIA0KDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQoNCg0KDQoNCg0KPHRhYmxlIHdpZHRoPSI2NDAiPg0KICAgPHRyPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjYyMCIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0IiBjbGFzcz0icHJfY29udGFpbmVyIj4NCiAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgY2xhc3M9Imxpc3RfcHJvZHVjdCI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE1MCIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiIGNsYXNzPSJwcl9pbWFnZSI-DQogICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MUgxNkRQUU1VRUIyTSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMEI1SDg0NkhUJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8yX2ltJkg9UElaSU9TTkZHU0FCRVlQSlRET1Y1SFlCWktDQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMl9pbSI-DQogICAgICAgICAgICAgIDxpbWcgc3JjPSJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvSS8zMVU1UURIaUI3TC5fU1I1MDAsNTAwXy5fU0wxNDBfLmpwZyIgY2xhc3M9InByX2ltYWdlXzE3NSBwcl9pbWFnZV9kZXNrdG9wIiBhbHQ9IlpFQlJPTklDUyAxNTBIYiA0IFBvcnQgVVNCIEh1YiB3aXRoIERlZGljYXRlZCBPbi9PZmYgU3dpdGNoLCBMZWQgSW5kaWNhdG9ycywgNDVDbSBDYWJsZSBMZW5ndGgsIE9wdGlvbmFsIFBvd2VyIElucHV0IFBvcnQsIE11bHRpIERldmljZSBhbmQgUGx1ZyBQbGF5IFVzYWdlIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMzY1IiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiPg0KICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3RpdGxlIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLFNhbnMtU2VyaWY7Zm9udC1zaXplOjE1cHg7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1hbGlnbjpsZWZ0O2NvbG9yOiMzMzY2OTk7Ij4NCiAgICAgPGEgY2xhc3M9Im9tYV9wcl90aXRsZSIgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MjVIMkJSU0tOVEU3RCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMEI1SDg0NkhUJTNGcmVmJTNEZW1fMXBfMl90aSUyNnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxJkg9RlBGTzNLNDM3TjhBNTZSQlBBUjA1WVMxVDRNQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzEiIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyBjb2xvcjojMzM2Njk5OyI-DQogICAgICAgICAgWkVCUk9OSUNTIDE1MEhiIDQgUG9ydCBVU0IgSHViIHdpdGggRGVkaWNhdGVkIE9uL09mZiBTd2l0Y2gsLi4uPC9hPg0KPC9zcGFuPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfYnlsaW5lIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgICAgIA0KDQogICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICA8c3BhbiBjbGFzcz0ib21hLXByLWJsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMzMzM7dGV4dC1hbGlnbjpsZWZ0OyI-DQogICAgICAgICAgICAgPGJyPiBieQ0KICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJBMU5VT1NPUzlHRlomVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGc3RvcmVzJTJGWmVicm9uaWNzJTJGcGFnZSUyRkVBNjhGQzI3LTIxMzUtNDYyNi1BRjE5LTgyOTZGQTQ0NjQyOSUzRnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4mSD1DMThOWVJKWUFVQTFaWjhZRlZUUEgxWlk5NklBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9hc3RfYmxuIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiMzMzY2OTk7Ij5aRUJST05JQ1M8L2E-DQogICAgICAgIDwvc3Bhbj4NCiAgICANCg0KIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9saXN0Ij4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE0uUi5QLjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-ICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3RyaWtlPuKCuTY5OS4wMDwvc3RyaWtlPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlYWwgUHJpY2U6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0icHJfcHJpY2VfaGlnaGxpZ2h0Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4oK5MTk5LjAwICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX3NhdmluZ3MiPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFlvdSBTYXZlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTUwMC4wMCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoNzIlKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCg0KDQoNCg0KDQoNCiAgICANCg0KDQoNCgkNCg0KDQoNCg0KDQoNCg0KCQ0KDQoNCg0KCQ0KDQoJDQoNCiAgICANCgkgICAgIA0KICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgIDx0ciBjbGFzcz0icHJfbWVyY2hhbnQiPg0KICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7IHRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGNvbG9yOiM1NTU1NTU7IGZvbnQtc2l6ZToxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgU29sZCBieSANCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zNDJLVFdBSTNZNExRJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGYWFnJTJGbWFpbiUzRmllJTNEVVRGOCUyNmFzaW4lM0RCMEI1SDg0NkhUJTI2aXNBbWF6b25GdWxmaWxsZWQlM0QxJTI2bWFya2V0cGxhY2VJRCUzREEyMVRKUlVVTjRLR1YlMjZwcm90b2NvbCUzRGN1cnJlbnQlMjZzZWxsZXIlM0RBSjZTSVpDOFlRRFpYJTI2c3NobVBhdGglM0QlMjZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPUJBWkFBREVLRzI4TzFTV01ITEJIQ1VVQTdZSUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgZm9udC1zaXplOjEycHg7Y29sb3I6ICMzMzY2OTk7Ij5DbGlja3RlY2ggUmV0YWlsIFByaXZhdGUgTHRkPC9hPiBhbmQgDQogICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOjEycHg7Ij5GdWxmaWxsZWQgYnkgQW1hem9uPC9zcGFuPi4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPC9zcGFuPiANCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgIDwvdHI-DQogICAgDQoNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTA1IiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQoNCg0KPGRpdiBjbGFzcz0icHJfbGVhcm5fbW9yZSIgYWxpZ249ImNlbnRlciIgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsiPg0KICAgICAgICA8dGFibGUgY2xhc3M9ImJ0bi1sZWFybm1vcmUtc21hbGwiICBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjMiIHN0eWxlPSJjb2xvcjogIzExMTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7ICB3aGl0ZS1zcGFjZTogbm93cmFwO2JhY2tncm91bmQtY29sb3I6ICNGRUM2NTA7IGZvbnQtc2l6ZToxMHB4OyB0ZXh0LWFsaWduOmNlbnRlcjsgYm9yZGVyLXJhZGl1czogNXB4OyI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICA8dGQgbm93cmFwPg0KICAgICAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zN1dIOUVRR0dSTDBGJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwQjVIODQ2SFQlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzJfbG0mSD1FT1pSSTdSUVZUUjNaU1BDRU1HS0paTzdKODBBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8yX2xtIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249Im1pZGRsZSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMxMTE7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgIExlYXJuIG1vcmUNCiAgICAgICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KPC9kaXY-DQoNCg0KDQogDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgIDwvdGFibGU-IDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2xhc3M9InNlcGVyYXRvciI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNlYWViZWMiIHdpZHRoPSI2MjAiIGhlaWdodD0iMSI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MXB4O2xpbmUtaGVpZ2h0OjFweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iMTUiPg0KICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTVweDtsaW5lLWhlaWdodDoxNXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICA8L3RkPg0KICAgPC90cj4NCjwvdGFibGU-DQogICAgDQogICAgDQogICAgDQoNCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCg0KDQoNCg0KDQo8dGFibGUgd2lkdGg9IjY0MCI-DQogICA8dHI-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iNjIwIiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiIGNsYXNzPSJwcl9jb250YWluZXIiPg0KICAgICAgICAgPHRhYmxlIHdpZHRoPSI2MjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBjbGFzcz0ibGlzdF9wcm9kdWN0Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTUwIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCIgY2xhc3M9InByX2ltYWdlIj4NCiAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj1FMFJBVUk2NktOU00mVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA5RzlNRzFCUCUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfM19pbSZIPVlaT09IQ1VPWDZSWEpVQTFOUVYzWUI2QTlSQUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzNfaW0iPg0KICAgICAgICAgICAgICA8aW1nIHNyYz0iaHR0cHM6Ly9tLm1lZGlhLWFtYXpvbi5jb20vaW1hZ2VzL0kvNDErMGtZUXVxbkwuX1NSNTAwLDUwMF8uX1NMMTQwXy5qcGciIGNsYXNzPSJwcl9pbWFnZV8xNzUgcHJfaW1hZ2VfZGVza3RvcCIgYWx0PSJBUk9QQU5BIFVTQiAzLjEgR2VuIDEgL1VTQiAzLjAgSGlnaCBTcGVlZCA1R2JwcyBIdWIgZm9yIExhcHRvcCA0IFBvcnQgUG9ydGFibGUgQWRhcHRlciB3aXRoIEluZGl2aWR1YWwgUG93ZXIgT04vT2ZmIFN3aXRjaCBhbmQgSW5kaXZpZHVhbCBCbHVlIExFRCBJbmRpY2F0b3JzIE11bHRpLVBvcnQiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIzNjUiIHZhbGlnbj0idG9wIiBhbGlnbj0ibGVmdCI-DQogICAgICAgICAgICAgICAgICAgICA8dGFibGUgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfdGl0bGUiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KDQoNCg0KDQo8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsU2Fucy1TZXJpZjtmb250LXNpemU6MTVweDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWFsaWduOmxlZnQ7Y29sb3I6IzMzNjY5OTsiPg0KICAgICA8YSBjbGFzcz0ib21hX3ByX3RpdGxlIiBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zNFZZWlBHNTBLNkdHJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwOUc5TUcxQlAlM0ZyZWYlM0RlbV8xcF8zX3RpJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1TMFBKUE1ZRVVJN1A4VUZKR0hIWlAxRU9HRVNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IGNvbG9yOiMzMzY2OTk7Ij4NCiAgICAgICAgICBBUk9QQU5BIFVTQiAzLjEgR2VuIDEgL1VTQiAzLjAgSGlnaCBTcGVlZCA1R2JwcyBIdWIgZm9yIExhcHRvcC4uLjwvYT4NCjwvc3Bhbj4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX2J5bGluZSI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KDQoNCg0KDQoNCg0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCg0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgDQogICAgDQoNCiAgICANCiAgICAgICAgPHNwYW4gY2xhc3M9Im9tYS1wci1ibCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMzMzO3RleHQtYWxpZ246bGVmdDsiPg0KICAgICAgICAgICAgIDxicj4gYnkNCiAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zMDE5NEYyMDE3RFcwJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRnN0b3JlcyUyRmFyb3BhbmElMkZwYWdlJTJGNDFDODNDRTAtNkUwMS00OTBBLUFEN0YtOUY0NjdFQTBBREVGJTNGcmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfYXN0X2JsbiUyNnN0b3JlX3JlZiUzRGJsX2FzdF9kcF9icmFuZExvZ29fc3RvJkg9Q0hVQ0tTSDFDTUFFMkc0TDFQNUZYSURUMlhJQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfYXN0X2JsbiIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjogbm9uZTsgZm9udC1zaXplOiAxMnB4OyBjb2xvcjojMzM2Njk5OyI-QVJPUEFOQTwvYT4NCiAgICAgICAgPC9zcGFuPg0KICAgIA0KDQogDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0ic3BhY2VyIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX2xpc3QiPg0KICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTS5SLlAuOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9saXN0Ij4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzdHJpa2U-4oK5MSw1OTkuMDA8L3N0cmlrZT4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX291ciI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcmljZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEzcHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJwcl9wcmljZV9oaWdobGlnaHQiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrk4OTkuMDAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWW91IFNhdmU6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogbm9ybWFsOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJvbWFfcHJfcHJpY2VfdmFsX3NhdmluZ3MiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4oK5NzAwLjAwIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICg0NCUpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KDQoNCg0KDQoNCg0KICAgIA0KDQoNCg0KCQ0KDQoNCg0KDQoNCg0KDQoJDQoNCg0KDQoJDQoNCgkNCg0KICAgIA0KCSAgICAgDQogICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgPHRyIGNsYXNzPSJwcl9tZXJjaGFudCI-DQogICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCxIZWx2ZXRpY2Esc2Fucy1zZXJpZjsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgY29sb3I6IzU1NTU1NTsgZm9udC1zaXplOjEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICBTb2xkIGJ5IA0KICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTM1UzZUMDRMTVJFS00mVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZhYWclMkZtYWluJTNGaWUlM0RVVEY4JTI2YXNpbiUzREIwOUc5TUcxQlAlMjZpc0FtYXpvbkZ1bGZpbGxlZCUzRDElMjZtYXJrZXRwbGFjZUlEJTNEQTIxVEpSVVVONEtHViUyNnByb3RvY29sJTNEY3VycmVudCUyNnNlbGxlciUzREEzSUdPR05WR005R0JUJTI2c3NobVBhdGglM0QlMjZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPVpWNExYUk1IN1JOVTVGRUdCNFlQSFIzT01ZWUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgZm9udC1zaXplOjEycHg7Y29sb3I6ICMzMzY2OTk7Ij5BUk9QQU5BPC9hPiBhbmQgDQogICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOjEycHg7Ij5GdWxmaWxsZWQgYnkgQW1hem9uPC9zcGFuPi4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPC9zcGFuPiANCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgIDwvdHI-DQogICAgDQoNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTA1IiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQoNCg0KPGRpdiBjbGFzcz0icHJfbGVhcm5fbW9yZSIgYWxpZ249ImNlbnRlciIgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsiPg0KICAgICAgICA8dGFibGUgY2xhc3M9ImJ0bi1sZWFybm1vcmUtc21hbGwiICBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjMiIHN0eWxlPSJjb2xvcjogIzExMTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7ICB3aGl0ZS1zcGFjZTogbm93cmFwO2JhY2tncm91bmQtY29sb3I6ICNGRUM2NTA7IGZvbnQtc2l6ZToxMHB4OyB0ZXh0LWFsaWduOmNlbnRlcjsgYm9yZGVyLXJhZGl1czogNXB4OyI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICA8dGQgbm93cmFwPg0KICAgICAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zOERKNVdJUDFHRThDJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwOUc5TUcxQlAlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzNfbG0mSD1KV1NIWjZMUEcyVEtVTEpNTEVNVjdCSDJaMFlBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8zX2xtIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249Im1pZGRsZSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMxMTE7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgIExlYXJuIG1vcmUNCiAgICAgICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KPC9kaXY-DQoNCg0KDQogDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgIDwvdGFibGU-IDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2xhc3M9InNlcGVyYXRvciI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNlYWViZWMiIHdpZHRoPSI2MjAiIGhlaWdodD0iMSI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MXB4O2xpbmUtaGVpZ2h0OjFweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iMTUiPg0KICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTVweDtsaW5lLWhlaWdodDoxNXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICA8L3RkPg0KICAgPC90cj4NCjwvdGFibGU-DQogICAgDQogICAgDQogICAgDQoNCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCg0KDQoNCg0KDQo8dGFibGUgd2lkdGg9IjY0MCI-DQogICA8dHI-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iNjIwIiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiIGNsYXNzPSJwcl9jb250YWluZXIiPg0KICAgICAgICAgPHRhYmxlIHdpZHRoPSI2MjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBjbGFzcz0ibGlzdF9wcm9kdWN0Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTUwIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCIgY2xhc3M9InByX2ltYWdlIj4NCiAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zODQwWFMyRDZCNkpTJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwMFY0QkdEMDAlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzRfaW0mSD1QVUZBOTdEQlhGSlpVWjVWS0NJWEcxWTJUN09BJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF80X2ltIj4NCiAgICAgICAgICAgICAgPGltZyBzcmM9Imh0dHBzOi8vbS5tZWRpYS1hbWF6b24uY29tL2ltYWdlcy9JLzQxK0F1OVRlRGhMLl9TUjUwMCwzMjBfLl9TTDE0MF8uanBnIiBjbGFzcz0icHJfaW1hZ2VfMTc1IHByX2ltYWdlX2Rlc2t0b3AiIGFsdD0iVFAtTGluayBVSDQwMCBVU0IgMy4wIDQtUG9ydCBQb3J0YWJsZSBEYXRhIEh1YiBmb3IgTWFjLCBpTWFjLCBNYWNCb29rIFBybyBBaXIsIFVsdHJhYm9va3MsIFRhYmxldCwgTGFwdG9wIGFuZCBBbnkgUEMsIFdpbmRvd3MsIE1hYyBPUyBYIGFuZCBMaW51eCBTeXN0ZW1zLSBCbGFjayIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjM2NSIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0Ij4NCiAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl90aXRsZSI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KDQoNCg0KDQoNCjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxNXB4O2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtYWxpZ246bGVmdDtjb2xvcjojMzM2Njk5OyI-DQogICAgIDxhIGNsYXNzPSJvbWFfcHJfdGl0bGUiIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJIWkFNTTlBOFBPMjcmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjAwVjRCR0QwMCUzRnJlZiUzRGVtXzFwXzRfdGklMjZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPUZYWVMxTFVFR0hGV01XNlVDVktNUkxFSkxPV0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0iZm9udC1zaXplOiAxNHB4OyB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsgY29sb3I6IzMzNjY5OTsiPg0KICAgICAgICAgIFRQLUxpbmsgVUg0MDAgVVNCIDMuMCA0LVBvcnQgUG9ydGFibGUgRGF0YSBIdWIgZm9yIE1hYywgaU1hYywuLi48L2E-DQo8L3NwYW4-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9ieWxpbmUiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KDQoNCg0KDQoNCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICAgICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgIA0KICAgIA0KICAgIA0KDQogICAgDQogICAgICAgIDxzcGFuIGNsYXNzPSJvbWEtcHItYmwiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxIZWx2ZXRpY2EsU2Fucy1TZXJpZjtmb250LXNpemU6MTJweDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzMzMzt0ZXh0LWFsaWduOmxlZnQ7Ij4NCiAgICAgICAgICAgICA8YnI-IGJ5DQogICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9Tk1MUVlCVkhZSlQxJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRnN0b3JlcyUyRlRQLUxJTktJTkRJQVBWVExURCUyRnBhZ2UlMkZEMjBCMTgxOS1FRTVFLTRCNDgtOUQ5MS1CNTBEM0ZFNDMxRTIlM0ZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9hc3RfYmxuJTI2c3RvcmVfcmVmJTNEYmxfYXN0X2RwX2JyYW5kTG9nb19zdG8mSD1YNzI5MUFKUEpSWFpGWUdIUUdSMVlEVlNBMU1BJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9hc3RfYmxuIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiMzMzY2OTk7Ij5UUC1MaW5rPC9hPg0KICAgICAgICA8L3NwYW4-DQogICAgDQoNCiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2VfbGlzdCI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNLlIuUC46DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogbm9ybWFsOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJvbWFfcHJfcHJpY2VfdmFsX2xpc3QiPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHN0cmlrZT7igrkxLDQ5OS4wMDwvc3RyaWtlPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByaWNlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9InByX3ByaWNlX2hpZ2hsaWdodCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTg5OS4wMCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZb3UgU2F2ZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrk2MDAuMDAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDQwJSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQoNCg0KDQoNCg0KDQogICAgDQoNCg0KDQoJDQoNCg0KDQoNCg0KDQoNCgkNCg0KDQoNCgkNCg0KCQ0KDQogICAgDQoJICAgICANCiAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICA8dHIgY2xhc3M9InByX21lcmNoYW50Ij4NCiAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgZm9udC13ZWlnaHQ6bm9ybWFsOyBjb2xvcjojNTU1NTU1OyBmb250LXNpemU6MTJweDsiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIFNvbGQgYnkgDQogICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MUZVQTBTRVlGRTNRMyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmFhZyUyRm1haW4lM0ZpZSUzRFVURjglMjZhc2luJTNEQjAwVjRCR0QwMCUyNmlzQW1hem9uRnVsZmlsbGVkJTNEMSUyNm1hcmtldHBsYWNlSUQlM0RBMjFUSlJVVU40S0dWJTI2cHJvdG9jb2wlM0RjdXJyZW50JTI2c2VsbGVyJTNEQUo2U0laQzhZUURaWCUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1OSVpMMUswQVlPWEVBVjA4R0kwRktIWktBQUlBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGZvbnQtc2l6ZToxMnB4O2NvbG9yOiAjMzM2Njk5OyI-Q2xpY2t0ZWNoIFJldGFpbCBQcml2YXRlIEx0ZDwvYT4gYW5kIA0KICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4OyI-RnVsZmlsbGVkIGJ5IEFtYXpvbjwvc3Bhbj4uDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvc3Bhbj4gDQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgIA0KDQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwNSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KDQoNCjxkaXYgY2xhc3M9InByX2xlYXJuX21vcmUiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij4NCiAgICAgICAgPHRhYmxlIGNsYXNzPSJidG4tbGVhcm5tb3JlLXNtYWxsIiAgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIzIiBzdHlsZT0iY29sb3I6ICMxMTE7IHRleHQtZGVjb3JhdGlvbjpub25lOyAgd2hpdGUtc3BhY2U6IG5vd3JhcDtiYWNrZ3JvdW5kLWNvbG9yOiAjRkVDNjUwOyBmb250LXNpemU6MTBweDsgdGV4dC1hbGlnbjpjZW50ZXI7IGJvcmRlci1yYWRpdXM6IDVweDsiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkIG5vd3JhcD4NCiAgICAgICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9NDZHWDFNTzNCRUpIJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwMFY0QkdEMDAlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzRfbG0mSD1YVU5BT0VYTkZYUEw4OE1MVEVCNlA1QVA2VUlBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF80X2xtIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249Im1pZGRsZSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMxMTE7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgIExlYXJuIG1vcmUNCiAgICAgICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KPC9kaXY-DQoNCg0KDQogDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgIDwvdGFibGU-IDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2xhc3M9InNlcGVyYXRvciI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNlYWViZWMiIHdpZHRoPSI2MjAiIGhlaWdodD0iMSI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MXB4O2xpbmUtaGVpZ2h0OjFweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iMTUiPg0KICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTVweDtsaW5lLWhlaWdodDoxNXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICA8L3RkPg0KICAgPC90cj4NCjwvdGFibGU-DQogICAgDQogICAgDQogICAgDQoNCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCg0KDQoNCg0KDQo8dGFibGUgd2lkdGg9IjY0MCI-DQogICA8dHI-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iNjIwIiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiIGNsYXNzPSJwcl9jb250YWluZXIiPg0KICAgICAgICAgPHRhYmxlIHdpZHRoPSI2MjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBjbGFzcz0ibGlzdF9wcm9kdWN0Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTUwIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCIgY2xhc3M9InByX2ltYWdlIj4NCiAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xTElBWERKRk5CTlVHJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwMTFPTFA2TEclMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzVfaW0mSD1DTVhBSjJXRFRPTlVIMVpCSENXRkNPRkZPRlNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF81X2ltIj4NCiAgICAgICAgICAgICAgPGltZyBzcmM9Imh0dHBzOi8vbS5tZWRpYS1hbWF6b24uY29tL2ltYWdlcy9JLzMxaTNHNUE0cWRMLl9TUjUwMCw1MDBfLl9TTDE0MF8uanBnIiBjbGFzcz0icHJfaW1hZ2VfMTc1IHByX2ltYWdlX2Rlc2t0b3AiIGFsdD0iWzEgTWV0ZXIgTG9uZyBDYWJsZSwgNUdicHMsIFVTQiAzLjEgR2VuIDFdIFFaIFVTQiBIdWIgZm9yIE5leHQgR2VuIE9mZmljZSBXb3JrIFN0YXRpb24sIDQgUG9ydHMsIFVTQiAzLjEgR2VuIDEgZm9yIFBDIGFuZCBMYXB0b3BzIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMzY1IiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiPg0KICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3RpdGxlIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLFNhbnMtU2VyaWY7Zm9udC1zaXplOjE1cHg7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1hbGlnbjpsZWZ0O2NvbG9yOiMzMzY2OTk7Ij4NCiAgICAgPGEgY2xhc3M9Im9tYV9wcl90aXRsZSIgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9V0hTRjFCM0hEM1JGJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwMTFPTFA2TEclM0ZyZWYlM0RlbV8xcF81X3RpJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1GNEhEUE9LTFpIMkNBQk9KTkpBSzJYSExYRVlBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IGNvbG9yOiMzMzY2OTk7Ij4NCiAgICAgICAgICBbMSBNZXRlciBMb25nIENhYmxlLCA1R2JwcywgVVNCIDMuMSBHZW4gMV0gUVogVVNCIEh1YiBmb3IgTmV4dC4uLjwvYT4NCjwvc3Bhbj4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX2J5bGluZSI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KDQoNCg0KDQoNCg0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCg0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgDQogICAgDQoNCiAgICANCiAgICAgICAgPHNwYW4gY2xhc3M9Im9tYS1wci1ibCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMzMzO3RleHQtYWxpZ246bGVmdDsiPg0KICAgICAgICAgICAgIDxicj4gYnkNCiAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xRlJYR0szVElVVkpPJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRnN0b3JlcyUyRlFaJTJGcGFnZSUyRkI3MDI1NTVDLUIyQjMtNDhENi05NjQ3LUFFRTYzOUU3MDZGMiUzRnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4lMjZzdG9yZV9yZWYlM0RibF9hc3RfZHBfYnJhbmRMb2dvX3N0byZIPVNKT1IwWVdVWUZDSkVUN1NaQUo0Q0hSUDdTNEEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4iIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6IzMzNjY5OTsiPlFaPC9hPg0KICAgICAgICA8L3NwYW4-DQogICAgDQoNCiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2VfbGlzdCI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNLlIuUC46DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogbm9ybWFsOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJvbWFfcHJfcHJpY2VfdmFsX2xpc3QiPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHN0cmlrZT7igrkxLDI2MC4wMDwvc3RyaWtlPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByaWNlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9InByX3ByaWNlX2hpZ2hsaWdodCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTg4Mi4wMCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZb3UgU2F2ZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrkzNzguMDAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDMwJSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQoNCg0KDQoNCg0KDQogICAgDQoNCg0KDQoJDQoNCg0KDQoNCg0KDQoNCgkNCg0KDQoNCgkNCg0KCQ0KDQogICAgDQoJICAgICANCiAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICA8dHIgY2xhc3M9InByX21lcmNoYW50Ij4NCiAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgZm9udC13ZWlnaHQ6bm9ybWFsOyBjb2xvcjojNTU1NTU1OyBmb250LXNpemU6MTJweDsiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIFNvbGQgYnkgDQogICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MlZDMVpET01CUk1GNSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmFhZyUyRm1haW4lM0ZpZSUzRFVURjglMjZhc2luJTNEQjAxMU9MUDZMRyUyNmlzQW1hem9uRnVsZmlsbGVkJTNEMSUyNm1hcmtldHBsYWNlSUQlM0RBMjFUSlJVVU40S0dWJTI2cHJvdG9jb2wlM0RjdXJyZW50JTI2c2VsbGVyJTNEQUo2U0laQzhZUURaWCUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1MT0FJSVFOU0FST1JPVjZEQlVSU1BRS0NXQVVBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGZvbnQtc2l6ZToxMnB4O2NvbG9yOiAjMzM2Njk5OyI-Q2xpY2t0ZWNoIFJldGFpbCBQcml2YXRlIEx0ZDwvYT4gYW5kIA0KICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4OyI-RnVsZmlsbGVkIGJ5IEFtYXpvbjwvc3Bhbj4uDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvc3Bhbj4gDQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgIA0KDQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwNSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KDQoNCjxkaXYgY2xhc3M9InByX2xlYXJuX21vcmUiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij4NCiAgICAgICAgPHRhYmxlIGNsYXNzPSJidG4tbGVhcm5tb3JlLXNtYWxsIiAgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIzIiBzdHlsZT0iY29sb3I6ICMxMTE7IHRleHQtZGVjb3JhdGlvbjpub25lOyAgd2hpdGUtc3BhY2U6IG5vd3JhcDtiYWNrZ3JvdW5kLWNvbG9yOiAjRkVDNjUwOyBmb250LXNpemU6MTBweDsgdGV4dC1hbGlnbjpjZW50ZXI7IGJvcmRlci1yYWRpdXM6IDVweDsiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkIG5vd3JhcD4NCiAgICAgICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9NU1MVVpGUFFBTldIJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwMTFPTFA2TEclMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzVfbG0mSD05Q0w5SkxITEdJMEFGU0tYS1NYS0ZQU0FJVUNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF81X2xtIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249Im1pZGRsZSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMxMTE7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgIExlYXJuIG1vcmUNCiAgICAgICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KPC9kaXY-DQoNCg0KDQogDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgIDwvdGFibGU-IDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2xhc3M9InNlcGVyYXRvciI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNlYWViZWMiIHdpZHRoPSI2MjAiIGhlaWdodD0iMSI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MXB4O2xpbmUtaGVpZ2h0OjFweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSI2MjAiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iMTUiPg0KICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTVweDtsaW5lLWhlaWdodDoxNXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICA8L3RkPg0KICAgPC90cj4NCjwvdGFibGU-DQogICAgDQogICAgDQogICAgDQoNCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCg0KDQoNCg0KDQo8dGFibGUgd2lkdGg9IjY0MCI-DQogICA8dHI-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgICAgIDx0ZCB3aWR0aD0iNjIwIiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiIGNsYXNzPSJwcl9jb250YWluZXIiPg0KICAgICAgICAgPHRhYmxlIHdpZHRoPSI2MjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBjbGFzcz0ibGlzdF9wcm9kdWN0Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTUwIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCIgY2xhc3M9InByX2ltYWdlIj4NCiAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj1WOUlOTzlORVBSUUUmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjAxMU9OSlY3WSUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfNl9pbSZIPVFUTkZSUUpNUlpBTDNYT1JFUEVROTlDVFNNVUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzZfaW0iPg0KICAgICAgICAgICAgICA8aW1nIHNyYz0iaHR0cHM6Ly9tLm1lZGlhLWFtYXpvbi5jb20vaW1hZ2VzL0kvMzFZbW11WEpiUEwuX1NSNTAwLDUwMF8uX1NMMTQwXy5qcGciIGNsYXNzPSJwcl9pbWFnZV8xNzUgcHJfaW1hZ2VfZGVza3RvcCIgYWx0PSJbMS4zIEZlZXQgTG9uZyBDYWJsZSwgNUdicHMsIFVTQiAzLjEgR2VuIDFdIFFaIFVTQiBIdWIgZm9yIE5leHQgR2VuIE9mZmljZSBXb3JrIFN0YXRpb24sIDQgUG9ydHMsIFVTQiAzLjEgR2VuIDEgZm9yIFBDIGFuZCBMYXB0b3BzIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMzY1IiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiPg0KICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3RpdGxlIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLFNhbnMtU2VyaWY7Zm9udC1zaXplOjE1cHg7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1hbGlnbjpsZWZ0O2NvbG9yOiMzMzY2OTk7Ij4NCiAgICAgPGEgY2xhc3M9Im9tYV9wcl90aXRsZSIgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MUJDRkNYVVVPOTJVMCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDExT05KVjdZJTNGcmVmJTNEZW1fMXBfNl90aSUyNnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxJkg9TkxUSU9ZVkNMTUM3T0xJRFJNU0FUNEJLUFNTQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzEiIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyBjb2xvcjojMzM2Njk5OyI-DQogICAgICAgICAgWzEuMyBGZWV0IExvbmcgQ2FibGUsIDVHYnBzLCBVU0IgMy4xIEdlbiAxXSBRWiBVU0IgSHViIGZvci4uLjwvYT4NCjwvc3Bhbj4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX2J5bGluZSI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KDQoNCg0KDQoNCg0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgICAgICANCg0KICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgDQogICAgDQogICAgDQoNCiAgICANCiAgICAgICAgPHNwYW4gY2xhc3M9Im9tYS1wci1ibCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMzMzO3RleHQtYWxpZ246bGVmdDsiPg0KICAgICAgICAgICAgIDxicj4gYnkNCiAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zU09MWDY0MTM1NVVBJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRnN0b3JlcyUyRlFaJTJGcGFnZSUyRkI3MDI1NTVDLUIyQjMtNDhENi05NjQ3LUFFRTYzOUU3MDZGMiUzRnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4lMjZzdG9yZV9yZWYlM0RibF9hc3RfZHBfYnJhbmRMb2dvX3N0byZIPU9EOUlBSlUzRFdFM0NPVkdBVlAwUjhBQk5ST0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4iIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6IzMzNjY5OTsiPlFaPC9hPg0KICAgICAgICA8L3NwYW4-DQogICAgDQoNCiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2VfbGlzdCI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNLlIuUC46DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogbm9ybWFsOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJvbWFfcHJfcHJpY2VfdmFsX2xpc3QiPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHN0cmlrZT7igrkxLDI0Mi4wMDwvc3RyaWtlPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByaWNlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9InByX3ByaWNlX2hpZ2hsaWdodCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTkzNi4wMCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZb3UgU2F2ZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrkzMDYuMDAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDI1JSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQoNCg0KDQoNCg0KDQogICAgDQoNCg0KDQoJDQoNCg0KDQoNCg0KDQoNCgkNCg0KDQoNCgkNCg0KCQ0KDQogICAgDQoJICAgICANCiAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICA8dHIgY2xhc3M9InByX21lcmNoYW50Ij4NCiAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgZm9udC13ZWlnaHQ6bm9ybWFsOyBjb2xvcjojNTU1NTU1OyBmb250LXNpemU6MTJweDsiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIFNvbGQgYnkgDQogICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9M0tJSEdSMlAyVllDTyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmFhZyUyRm1haW4lM0ZpZSUzRFVURjglMjZhc2luJTNEQjAxMU9OSlY3WSUyNmlzQW1hem9uRnVsZmlsbGVkJTNEMSUyNm1hcmtldHBsYWNlSUQlM0RBMjFUSlJVVU40S0dWJTI2cHJvdG9jb2wlM0RjdXJyZW50JTI2c2VsbGVyJTNEQUo2U0laQzhZUURaWCUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1DOEFTQkM0QURZQ043T1JTSVhJM1ZJQ0hORVNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGZvbnQtc2l6ZToxMnB4O2NvbG9yOiAjMzM2Njk5OyI-Q2xpY2t0ZWNoIFJldGFpbCBQcml2YXRlIEx0ZDwvYT4gYW5kIA0KICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4OyI-RnVsZmlsbGVkIGJ5IEFtYXpvbjwvc3Bhbj4uDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvc3Bhbj4gDQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgIA0KDQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwNSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KDQoNCjxkaXYgY2xhc3M9InByX2xlYXJuX21vcmUiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij4NCiAgICAgICAgPHRhYmxlIGNsYXNzPSJidG4tbGVhcm5tb3JlLXNtYWxsIiAgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIzIiBzdHlsZT0iY29sb3I6ICMxMTE7IHRleHQtZGVjb3JhdGlvbjpub25lOyAgd2hpdGUtc3BhY2U6IG5vd3JhcDtiYWNrZ3JvdW5kLWNvbG9yOiAjRkVDNjUwOyBmb250LXNpemU6MTBweDsgdGV4dC1hbGlnbjpjZW50ZXI7IGJvcmRlci1yYWRpdXM6IDVweDsiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkIG5vd3JhcD4NCiAgICAgICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MlpaT1JaQVBKVlBCQyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDExT05KVjdZJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF82X2xtJkg9MVQ2R01GMDhUWkRZTEpRSTVUVElKT0dYVjJPQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfNl9sbSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMTExOyI-DQogICAgICAgICAgICAgICAgICAgICAgICBMZWFybiBtb3JlDQogICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgPC90YWJsZT4NCjwvZGl2Pg0KDQoNCg0KIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPiA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJzZXBlcmF0b3IiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCBiZ2NvbG9yPSIjZWFlYmVjIiB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjFweDtsaW5lLWhlaWdodDoxcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgIDwvdHI-DQo8L3RhYmxlPg0KICAgIA0KICAgIA0KICAgIA0KDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQoNCg0KDQoNCg0KPHRhYmxlIHdpZHRoPSI2NDAiPg0KICAgPHRyPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjYyMCIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0IiBjbGFzcz0icHJfY29udGFpbmVyIj4NCiAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgY2xhc3M9Imxpc3RfcHJvZHVjdCI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE1MCIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiIGNsYXNzPSJwcl9pbWFnZSI-DQogICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9M0dXWE5XR1RKN1U5OSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDlNODg4OERNJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF83X2ltJkg9U09BT0VWVUdOU05BSkNHT1dIS05BWEpKS1o0QSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfN19pbSI-DQogICAgICAgICAgICAgIDxpbWcgc3JjPSJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvSS8yMVVLSXdmMElWTC5fU1I1MDAsNTAwXy5fU0wxNDBfLmpwZyIgY2xhc3M9InByX2ltYWdlXzE3NSBwcl9pbWFnZV9kZXNrdG9wIiBhbHQ9IlBvcnRyb25pY3MgTXBvcnQgMzEgVVNCIEh1YiAoNC1pbi0xKSwgTXVsdGlwb3J0IEFkYXB0ZXIgd2l0aCAxIHggVVNCIDMuMCAmYW1wOyAzIHggVVNCIDIuMCBQb3J0cywgdXAgdG8gNSBHYnBzIEhpZ2ggU3BlZWQgRGF0YSBUcmFuc2ZlciBmb3IgTGFwdG9wL1BDIChHcmV5KSIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjM2NSIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0Ij4NCiAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl90aXRsZSI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KDQoNCg0KDQoNCjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxNXB4O2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtYWxpZ246bGVmdDtjb2xvcjojMzM2Njk5OyI-DQogICAgIDxhIGNsYXNzPSJvbWFfcHJfdGl0bGUiIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPUlNTDdYN1lVTVdFWiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDlNODg4OERNJTNGcmVmJTNEZW1fMXBfN190aSUyNnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxJkg9MkFVUVVVWk9PUVY4NzBKT0ZMVEs5QTZBTVpHQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzEiIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyBjb2xvcjojMzM2Njk5OyI-DQogICAgICAgICAgUG9ydHJvbmljcyBNcG9ydCAzMSBVU0IgSHViICg0LWluLTEpLCBNdWx0aXBvcnQgQWRhcHRlciB3aXRoIDEuLi48L2E-DQo8L3NwYW4-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9ieWxpbmUiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KDQoNCg0KDQoNCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICAgICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgIA0KICAgIA0KICAgIA0KDQogICAgDQogICAgICAgIDxzcGFuIGNsYXNzPSJvbWEtcHItYmwiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxIZWx2ZXRpY2EsU2Fucy1TZXJpZjtmb250LXNpemU6MTJweDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzMzMzt0ZXh0LWFsaWduOmxlZnQ7Ij4NCiAgICAgICAgICAgICA8YnI-IGJ5DQogICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MzQ0NU5XUldBVDAzSiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZzdG9yZXMlMkZQb3J0cm9uaWNzJTJGcGFnZSUyRjgyQ0M4MjRCLTE5QUMtNEE0NS04NzJELTU5ODg4QTEwRUZERiUzRnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4lMjZzdG9yZV9yZWYlM0RibF9hc3RfZHBfYnJhbmRMb2dvX3N0byZIPTFQUDhEVlBBUTBUMkhHWVRCM0cwVklHSFVCUUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4iIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6IzMzNjY5OTsiPlBvcnRyb25pY3M8L2E-DQogICAgICAgIDwvc3Bhbj4NCiAgICANCg0KIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9saXN0Ij4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE0uUi5QLjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-ICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3RyaWtlPuKCuTc5OS4wMDwvc3RyaWtlPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByaWNlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9InByX3ByaWNlX2hpZ2hsaWdodCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTM0OS4wMCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZb3UgU2F2ZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrk0NTAuMDAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDU2JSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQoNCg0KDQoNCg0KDQogICAgDQoNCg0KDQoJDQoNCg0KDQoNCg0KDQoNCgkNCg0KDQoNCgkNCg0KCQ0KDQogICAgDQoJICAgICANCiAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICA8dHIgY2xhc3M9InByX21lcmNoYW50Ij4NCiAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgZm9udC13ZWlnaHQ6bm9ybWFsOyBjb2xvcjojNTU1NTU1OyBmb250LXNpemU6MTJweDsiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIFNvbGQgYnkgDQogICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9M1MzM1hVSDNPRU01NiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmFhZyUyRm1haW4lM0ZpZSUzRFVURjglMjZhc2luJTNEQjA5TTg4ODhETSUyNmlzQW1hem9uRnVsZmlsbGVkJTNEMSUyNm1hcmtldHBsYWNlSUQlM0RBMjFUSlJVVU40S0dWJTI2cHJvdG9jb2wlM0RjdXJyZW50JTI2c2VsbGVyJTNEQUo2U0laQzhZUURaWCUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1QTlVPVkFVU0hZS1hBMTZQQUFIOFFJN0dQQkVBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGZvbnQtc2l6ZToxMnB4O2NvbG9yOiAjMzM2Njk5OyI-Q2xpY2t0ZWNoIFJldGFpbCBQcml2YXRlIEx0ZDwvYT4gYW5kIA0KICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4OyI-RnVsZmlsbGVkIGJ5IEFtYXpvbjwvc3Bhbj4uDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvc3Bhbj4gDQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgIA0KDQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwNSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KDQoNCjxkaXYgY2xhc3M9InByX2xlYXJuX21vcmUiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij4NCiAgICAgICAgPHRhYmxlIGNsYXNzPSJidG4tbGVhcm5tb3JlLXNtYWxsIiAgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIzIiBzdHlsZT0iY29sb3I6ICMxMTE7IHRleHQtZGVjb3JhdGlvbjpub25lOyAgd2hpdGUtc3BhY2U6IG5vd3JhcDtiYWNrZ3JvdW5kLWNvbG9yOiAjRkVDNjUwOyBmb250LXNpemU6MTBweDsgdGV4dC1hbGlnbjpjZW50ZXI7IGJvcmRlci1yYWRpdXM6IDVweDsiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkIG5vd3JhcD4NCiAgICAgICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MTJYS0gwMFI3TDFaMyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDlNODg4OERNJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF83X2xtJkg9VFdLU0pDTFE1TDJCWUFXSVdBRFc0TEtUWTBNQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfN19sbSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMTExOyI-DQogICAgICAgICAgICAgICAgICAgICAgICBMZWFybiBtb3JlDQogICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgPC90YWJsZT4NCjwvZGl2Pg0KDQoNCg0KIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPiA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJzZXBlcmF0b3IiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCBiZ2NvbG9yPSIjZWFlYmVjIiB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjFweDtsaW5lLWhlaWdodDoxcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgIDwvdHI-DQo8L3RhYmxlPg0KICAgIA0KICAgIA0KICAgIA0KDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQoNCg0KDQoNCg0KPHRhYmxlIHdpZHRoPSI2NDAiPg0KICAgPHRyPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjYyMCIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0IiBjbGFzcz0icHJfY29udGFpbmVyIj4NCiAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgY2xhc3M9Imxpc3RfcHJvZHVjdCI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE1MCIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiIGNsYXNzPSJwcl9pbWFnZSI-DQogICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MTZISzFaWU9JR043SyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDdLQlZSVjVIJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF84X2ltJkg9SkNKV1RMQkJWSE9MS0FXWDFOUVJTVVo5UEtXQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfOF9pbSI-DQogICAgICAgICAgICAgIDxpbWcgc3JjPSJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvSS81MVVoYTJsK1Y5TC5fU1I1MDAsNTAwXy5fU0wxNDBfLmpwZyIgY2xhc3M9InByX2ltYWdlXzE3NSBwcl9pbWFnZV9kZXNrdG9wIiBhbHQ9Ik9SSUNPIFVTQiAzLjAgSHViIDcgUG9ydHMgVVNCMy4wIFRyYW5zcGFyZW50IERlc2t0b3AgSFVCIHdpdGggQmx1ZSBJbmRpY2F0b3IgTGlnaHQgJmFtcDsgRHVhbCBQb3J0IFBvd2VyIFN1cHBseSB3aXRoIDFNIENhYmxlIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMzY1IiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiPg0KICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3RpdGxlIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLFNhbnMtU2VyaWY7Zm9udC1zaXplOjE1cHg7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1hbGlnbjpsZWZ0O2NvbG9yOiMzMzY2OTk7Ij4NCiAgICAgPGEgY2xhc3M9Im9tYV9wcl90aXRsZSIgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9TUkwNTZMUUcyTFo1JlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwN0tCVlJWNUglM0ZyZWYlM0RlbV8xcF84X3RpJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1PRkpNTlhVSlRGT08wSU5XRldGSExWSFJIS0VBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IGNvbG9yOiMzMzY2OTk7Ij4NCiAgICAgICAgICBPUklDTyBVU0IgMy4wIEh1YiA3IFBvcnRzIFVTQjMuMCBUcmFuc3BhcmVudCBEZXNrdG9wIEhVQiB3aXRoLi4uPC9hPg0KPC9zcGFuPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfYnlsaW5lIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgICAgIA0KDQogICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICA8c3BhbiBjbGFzcz0ib21hLXByLWJsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMzMzM7dGV4dC1hbGlnbjpsZWZ0OyI-DQogICAgICAgICAgICAgPGJyPiBieQ0KICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPU9VOU43U0dLS0JHOSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZzdG9yZXMlMkZPUklDTyUyRnBhZ2UlMkY5RDUzQTQ4OC04QUMxLTQwRDktOUM4QS1FRjI2MzlCRUIwNjElM0ZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9hc3RfYmxuJTI2c3RvcmVfcmVmJTNEYmxfYXN0X2RwX2JyYW5kTG9nb19zdG8mSD1IQTZBQ0ZXTElMQkFVRldaQUtTVU9DREg2TE9BJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9hc3RfYmxuIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiMzMzY2OTk7Ij5PUklDTzwvYT4NCiAgICAgICAgPC9zcGFuPg0KICAgIA0KDQogDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0ic3BhY2VyIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX2xpc3QiPg0KICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTS5SLlAuOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9saXN0Ij4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzdHJpa2U-4oK5MSw4OTkuMDA8L3N0cmlrZT4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX291ciI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcmljZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEzcHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJwcl9wcmljZV9oaWdobGlnaHQiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrkxLDc5OS4wMCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZb3UgU2F2ZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrkxMDAuMDAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDUlKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCg0KDQoNCg0KDQoNCiAgICANCg0KDQoNCgkNCg0KDQoNCg0KDQoNCg0KCQ0KDQoNCg0KCQ0KDQoJDQoNCiAgICANCgkgICAgIA0KICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgIDx0ciBjbGFzcz0icHJfbWVyY2hhbnQiPg0KICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7IHRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGNvbG9yOiM1NTU1NTU7IGZvbnQtc2l6ZToxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgU29sZCBieSANCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zWTFOWEU1RzNHR1UmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZhYWclMkZtYWluJTNGaWUlM0RVVEY4JTI2YXNpbiUzREIwN0tCVlJWNUglMjZpc0FtYXpvbkZ1bGZpbGxlZCUzRDElMjZtYXJrZXRwbGFjZUlEJTNEQTIxVEpSVVVONEtHViUyNnByb3RvY29sJTNEY3VycmVudCUyNnNlbGxlciUzREEzVFVZTFpDUDQzQzZFJTI2c3NobVBhdGglM0QlMjZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPU5IN09MRU5GVDJJVElRSUpDRVkzQzdESjBQWUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgZm9udC1zaXplOjEycHg7Y29sb3I6ICMzMzY2OTk7Ij5PUklDTyBEaXJlY3QgU3RvcmU8L2E-IGFuZCANCiAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6MTJweDsiPkZ1bGZpbGxlZCBieSBBbWF6b248L3NwYW4-Lg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8L3NwYW4-IA0KICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgPC90cj4NCiAgICANCg0KDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDUiIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0idG9wIj4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCg0KDQo8ZGl2IGNsYXNzPSJwcl9sZWFybl9tb3JlIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0iZGlzcGxheTogaW5saW5lLWJsb2NrOyI-DQogICAgICAgIDx0YWJsZSBjbGFzcz0iYnRuLWxlYXJubW9yZS1zbWFsbCIgIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMyIgc3R5bGU9ImNvbG9yOiAjMTExOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgIHdoaXRlLXNwYWNlOiBub3dyYXA7YmFja2dyb3VuZC1jb2xvcjogI0ZFQzY1MDsgZm9udC1zaXplOjEwcHg7IHRleHQtYWxpZ246Y2VudGVyOyBib3JkZXItcmFkaXVzOiA1cHg7Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgIDx0ZCBub3dyYXA-DQogICAgICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTIxS01QNkJHNjlHSUwmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA3S0JWUlY1SCUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfOF9sbSZIPUdXQUY5Q1NISU8ySlRFU05NTU1aVzJMS0NJV0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzhfbG0iIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0ibWlkZGxlIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzExMTsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgTGVhcm4gbW9yZQ0KICAgICAgICAgICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgIDwvdGFibGU-DQo8L2Rpdj4NCg0KDQoNCiANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4gPHRhYmxlIHdpZHRoPSI2MjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0ic2VwZXJhdG9yIj4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjYyMCIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMSI-DQogICAgICAgICAgICAgICAgICA8dGQgYmdjb2xvcj0iI2VhZWJlYyIgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjYyMCIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxcHg7bGluZS1oZWlnaHQ6MXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjYyMCIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgIDwvdGFibGU-DQogICAgICA8L3RkPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICA8L3RyPg0KPC90YWJsZT4NCiAgICANCiAgICANCiAgICANCg0KDQogICAgDQoNCiAgICANCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KDQoNCg0KDQoNCjx0YWJsZSB3aWR0aD0iNjQwIj4NCiAgIDx0cj4NCiAgICAgIDx0ZCB3aWR0aD0iMTUiPg0KICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTVweDtsaW5lLWhlaWdodDoxNXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICA8L3RkPg0KICAgICAgPHRkIHdpZHRoPSI2MjAiIHZhbGlnbj0idG9wIiBhbGlnbj0ibGVmdCIgY2xhc3M9InByX2NvbnRhaW5lciI-DQogICAgICAgICA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGNsYXNzPSJsaXN0X3Byb2R1Y3QiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxNTAiIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0idG9wIiBjbGFzcz0icHJfaW1hZ2UiPg0KICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJORUlXVlNJNFEzVlgmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjAxTTBUNjRFTSUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfOV9pbSZIPTFHS1A0U0hWTTBQQUZJWUJVSlBYSDZJVFhPT0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzlfaW0iPg0KICAgICAgICAgICAgICA8aW1nIHNyYz0iaHR0cHM6Ly9tLm1lZGlhLWFtYXpvbi5jb20vaW1hZ2VzL0kvMzFvOTRVU25SQUwuX1NSNTAwLDUwMF8uX1NMMTQwXy5qcGciIGNsYXNzPSJwcl9pbWFnZV8xNzUgcHJfaW1hZ2VfZGVza3RvcCIgYWx0PSJRWiBBY3RpdmUgUG93ZXJlZCBVU0IgSHViLCAxMCBQb3J0IFVTQiBIdWIgd2l0aCAxMlYgNUEgNjBXIFBvd2VyIEFkYXB0ZXIsIFVTQiAzLjEgR2VuIDEiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIzNjUiIHZhbGlnbj0idG9wIiBhbGlnbj0ibGVmdCI-DQogICAgICAgICAgICAgICAgICAgICA8dGFibGUgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfdGl0bGUiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KDQoNCg0KDQo8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsU2Fucy1TZXJpZjtmb250LXNpemU6MTVweDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWFsaWduOmxlZnQ7Y29sb3I6IzMzNjY5OTsiPg0KICAgICA8YSBjbGFzcz0ib21hX3ByX3RpdGxlIiBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zNlBDSUNISjFCMTNZJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwMU0wVDY0RU0lM0ZyZWYlM0RlbV8xcF85X3RpJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1TWFFVS0I3Rk1BTkhHNkZHMkZDNDNLTExUNUdBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IGNvbG9yOiMzMzY2OTk7Ij4NCiAgICAgICAgICBRWiBBY3RpdmUgUG93ZXJlZCBVU0IgSHViLCAxMCBQb3J0IFVTQiBIdWIgd2l0aCAxMlYgNUEgNjBXLi4uPC9hPg0KPC9zcGFuPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfYnlsaW5lIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgICAgIA0KDQogICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICA8c3BhbiBjbGFzcz0ib21hLXByLWJsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMzMzM7dGV4dC1hbGlnbjpsZWZ0OyI-DQogICAgICAgICAgICAgPGJyPiBieQ0KICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTNDNTJRMVowT0tHWlYmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGc3RvcmVzJTJGUVolMkZwYWdlJTJGQjcwMjU1NUMtQjJCMy00OEQ2LTk2NDctQUVFNjM5RTcwNkYyJTNGcmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfYXN0X2JsbiUyNnN0b3JlX3JlZiUzRGJsX2FzdF9kcF9icmFuZExvZ29fc3RvJkg9TVJGVUtDRlYxMERRQUsxWFJVS1NBSFlGSUQ4QSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfYXN0X2JsbiIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjogbm9uZTsgZm9udC1zaXplOiAxMnB4OyBjb2xvcjojMzM2Njk5OyI-UVo8L2E-DQogICAgICAgIDwvc3Bhbj4NCiAgICANCg0KIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9saXN0Ij4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE0uUi5QLjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-ICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3RyaWtlPuKCuTQsOTE0LjAwPC9zdHJpa2U-ICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9vdXIiPg0KICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJpY2U6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0icHJfcHJpY2VfaGlnaGxpZ2h0Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4oK5NCwzNDQuMDAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWW91IFNhdmU6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogbm9ybWFsOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJvbWFfcHJfcHJpY2VfdmFsX3NhdmluZ3MiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4oK5NTcwLjAwIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgxMiUpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KDQoNCg0KDQoNCg0KICAgIA0KDQoNCg0KCQ0KDQoNCg0KDQoNCg0KDQoJDQoNCg0KDQoJDQoNCgkNCg0KICAgIA0KCSAgICAgDQogICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgPHRyIGNsYXNzPSJwcl9tZXJjaGFudCI-DQogICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCxIZWx2ZXRpY2Esc2Fucy1zZXJpZjsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgY29sb3I6IzU1NTU1NTsgZm9udC1zaXplOjEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICBTb2xkIGJ5IA0KICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPUpSS1o3QzdQSFE0VyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmFhZyUyRm1haW4lM0ZpZSUzRFVURjglMjZhc2luJTNEQjAxTTBUNjRFTSUyNmlzQW1hem9uRnVsZmlsbGVkJTNEMSUyNm1hcmtldHBsYWNlSUQlM0RBMjFUSlJVVU40S0dWJTI2cHJvdG9jb2wlM0RjdXJyZW50JTI2c2VsbGVyJTNEQUo2U0laQzhZUURaWCUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1NRU9aNkcxQzMxQ0hVN0VIWUQ3RFVEVVpRR0lBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGZvbnQtc2l6ZToxMnB4O2NvbG9yOiAjMzM2Njk5OyI-Q2xpY2t0ZWNoIFJldGFpbCBQcml2YXRlIEx0ZDwvYT4gYW5kIA0KICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4OyI-RnVsZmlsbGVkIGJ5IEFtYXpvbjwvc3Bhbj4uDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDwvc3Bhbj4gDQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgIA0KDQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwNSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiPg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KDQoNCjxkaXYgY2xhc3M9InByX2xlYXJuX21vcmUiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7Ij4NCiAgICAgICAgPHRhYmxlIGNsYXNzPSJidG4tbGVhcm5tb3JlLXNtYWxsIiAgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIzIiBzdHlsZT0iY29sb3I6ICMxMTE7IHRleHQtZGVjb3JhdGlvbjpub25lOyAgd2hpdGUtc3BhY2U6IG5vd3JhcDtiYWNrZ3JvdW5kLWNvbG9yOiAjRkVDNjUwOyBmb250LXNpemU6MTBweDsgdGV4dC1hbGlnbjpjZW50ZXI7IGJvcmRlci1yYWRpdXM6IDVweDsiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkIG5vd3JhcD4NCiAgICAgICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MkFYRlE2VUFEWE5HWCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDFNMFQ2NEVNJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF85X2xtJkg9QlNLWU40UUQ4Qk1UVVlJN05JTjMyR0hJM0lTQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfOV9sbSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMTExOyI-DQogICAgICAgICAgICAgICAgICAgICAgICBMZWFybiBtb3JlDQogICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgPC90YWJsZT4NCjwvZGl2Pg0KDQoNCg0KIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPiA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJzZXBlcmF0b3IiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCBiZ2NvbG9yPSIjZWFlYmVjIiB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjFweDtsaW5lLWhlaWdodDoxcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgIDwvdHI-DQo8L3RhYmxlPg0KICAgIA0KICAgIA0KICAgIA0KDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQoNCg0KDQoNCg0KPHRhYmxlIHdpZHRoPSI2NDAiPg0KICAgPHRyPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjYyMCIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0IiBjbGFzcz0icHJfY29udGFpbmVyIj4NCiAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgY2xhc3M9Imxpc3RfcHJvZHVjdCI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE1MCIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiIGNsYXNzPSJwcl9pbWFnZSI-DQogICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MjBHMFNVMVpVNjVLTyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDdHTE5KQzI1JTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8xMF9pbSZIPVpKOUE4T1JYWTQ2SUFXWUlPUFZXWkZaRVlPR0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzEwX2ltIj4NCiAgICAgICAgICAgICAgPGltZyBzcmM9Imh0dHBzOi8vbS5tZWRpYS1hbWF6b24uY29tL2ltYWdlcy9JLzQxM1ptYkhsQUtMLl9TUjUwMCw1MDBfLl9TTDE0MF8uanBnIiBjbGFzcz0icHJfaW1hZ2VfMTc1IHByX2ltYWdlX2Rlc2t0b3AiIGFsdD0iWkVCUk9OSUNTIFplYi0xMDBIQiA0IFBvcnRzIFVTQiBIdWIgZm9yIExhcHRvcCwgUEMgQ29tcHV0ZXJzLCBQbHVnICZhbXA7IFBsYXksIEJhY2t3YXJkIENvbXBhdGlibGUgLSBCbGFjayIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjM2NSIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0Ij4NCiAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl90aXRsZSI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KDQoNCg0KDQoNCjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxNXB4O2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtYWxpZ246bGVmdDtjb2xvcjojMzM2Njk5OyI-DQogICAgIDxhIGNsYXNzPSJvbWFfcHJfdGl0bGUiIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTE4RjEwNjhXQTJNVlYmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA3R0xOSkMyNSUzRnJlZiUzRGVtXzFwXzEwX3RpJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1UTk9USldXRjk1RkFPNUNBMVFSRk9aSkJYQ0tBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IGNvbG9yOiMzMzY2OTk7Ij4NCiAgICAgICAgICBaRUJST05JQ1MgWmViLTEwMEhCIDQgUG9ydHMgVVNCIEh1YiBmb3IgTGFwdG9wLCBQQyBDb21wdXRlcnMsLi4uPC9hPg0KPC9zcGFuPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfYnlsaW5lIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgICAgIA0KDQogICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICA8c3BhbiBjbGFzcz0ib21hLXByLWJsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMzMzM7dGV4dC1hbGlnbjpsZWZ0OyI-DQogICAgICAgICAgICAgPGJyPiBieQ0KICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTFBSE43T1JOVkNaRVEmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGc3RvcmVzJTJGWmVicm9uaWNzJTJGcGFnZSUyRkVBNjhGQzI3LTIxMzUtNDYyNi1BRjE5LTgyOTZGQTQ0NjQyOSUzRnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4mSD1UV0VEU0pSVDBDUEpGR05ITFJMTVRVNkUxQkNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9hc3RfYmxuIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiMzMzY2OTk7Ij5aRUJST05JQ1M8L2E-DQogICAgICAgIDwvc3Bhbj4NCiAgICANCg0KIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9saXN0Ij4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE0uUi5QLjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-ICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3RyaWtlPuKCuTM5OS4wMDwvc3RyaWtlPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlYWwgUHJpY2U6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0icHJfcHJpY2VfaGlnaGxpZ2h0Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4oK5MjQ5LjAwICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX3NhdmluZ3MiPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFlvdSBTYXZlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTE1MC4wMCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMzglKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCg0KDQoNCg0KDQoNCiAgICANCg0KDQoNCgkNCg0KDQoNCg0KDQoNCg0KCQ0KDQoNCg0KCQ0KDQoJDQoNCiAgICANCgkgICAgIA0KICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgIDx0ciBjbGFzcz0icHJfbWVyY2hhbnQiPg0KICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7IHRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGNvbG9yOiM1NTU1NTU7IGZvbnQtc2l6ZToxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgU29sZCBieSANCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xTU9GN0dVV0w0U1BWJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGYWFnJTJGbWFpbiUzRmllJTNEVVRGOCUyNmFzaW4lM0RCMDdHTE5KQzI1JTI2aXNBbWF6b25GdWxmaWxsZWQlM0QxJTI2bWFya2V0cGxhY2VJRCUzREEyMVRKUlVVTjRLR1YlMjZwcm90b2NvbCUzRGN1cnJlbnQlMjZzZWxsZXIlM0RBSjZTSVpDOFlRRFpYJTI2c3NobVBhdGglM0QlMjZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPVlXS0tSV1hZSVZNTVFBNDlPR0hYTFpHS0ZQUUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgZm9udC1zaXplOjEycHg7Y29sb3I6ICMzMzY2OTk7Ij5DbGlja3RlY2ggUmV0YWlsIFByaXZhdGUgTHRkPC9hPiBhbmQgDQogICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOjEycHg7Ij5GdWxmaWxsZWQgYnkgQW1hem9uPC9zcGFuPi4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPC9zcGFuPiANCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgIDwvdHI-DQogICAgDQoNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTA1IiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQoNCg0KPGRpdiBjbGFzcz0icHJfbGVhcm5fbW9yZSIgYWxpZ249ImNlbnRlciIgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsiPg0KICAgICAgICA8dGFibGUgY2xhc3M9ImJ0bi1sZWFybm1vcmUtc21hbGwiICBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjMiIHN0eWxlPSJjb2xvcjogIzExMTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7ICB3aGl0ZS1zcGFjZTogbm93cmFwO2JhY2tncm91bmQtY29sb3I6ICNGRUM2NTA7IGZvbnQtc2l6ZToxMHB4OyB0ZXh0LWFsaWduOmNlbnRlcjsgYm9yZGVyLXJhZGl1czogNXB4OyI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICA8dGQgbm93cmFwPg0KICAgICAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj1ZVTVTVFlBTFRXV0MmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA3R0xOSkMyNSUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMTBfbG0mSD1FNFdYQTU4VzE5QURXRUVSVDBBR0JXOUpRRkFBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8xMF9sbSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMTExOyI-DQogICAgICAgICAgICAgICAgICAgICAgICBMZWFybiBtb3JlDQogICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgPC90YWJsZT4NCjwvZGl2Pg0KDQoNCg0KIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPiA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJzZXBlcmF0b3IiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCBiZ2NvbG9yPSIjZWFlYmVjIiB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjFweDtsaW5lLWhlaWdodDoxcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgIDwvdHI-DQo8L3RhYmxlPg0KICAgIA0KICAgIA0KICAgIA0KDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQoNCg0KDQoNCg0KPHRhYmxlIHdpZHRoPSI2NDAiPg0KICAgPHRyPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjYyMCIgdmFsaWduPSJ0b3AiIGFsaWduPSJsZWZ0IiBjbGFzcz0icHJfY29udGFpbmVyIj4NCiAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgY2xhc3M9Imxpc3RfcHJvZHVjdCI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE1MCIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiIGNsYXNzPSJwcl9pbWFnZSI-DQogICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9M0MxSzdGUFJQUE0xMSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDhRSk5LWDk0JTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8xMV9pbSZIPVVHSVpCMzVBNUFZMkhLT1ZVMlBXR01OREtPUUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzExX2ltIj4NCiAgICAgICAgICAgICAgPGltZyBzcmM9Imh0dHBzOi8vbS5tZWRpYS1hbWF6b24uY29tL2ltYWdlcy9JLzQxdUcwLVd6QWxMLl9TUjUwMCw1MDBfLl9TTDE0MF8uanBnIiBjbGFzcz0icHJfaW1hZ2VfMTc1IHByX2ltYWdlX2Rlc2t0b3AiIGFsdD0iVHVremVyIDQtUG9ydHMgVVNCIEEgdG8gVVNCIDMuMCBIVUIgd2l0aCBIaWdoLVNwZWVkIERhdGEgVHJhbnNmZXIgJmFtcDsgRmFzdCBDaGFyaW5nIFBvcnRzLCBDb21wYXRpYmxlIGZvciBNYWNCb29rIEFpciwgTWFjIE1pbmksIGlNYWMgUHJvLCBNaWNyb3NvZnQgU3VyZmFjZSwgVWx0cmFCb29rcywgTGFwdG9wLCBOb3RlYm9vaywgRGVza3RvcCAoV2hpdGUpIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMzY1IiB2YWxpZ249InRvcCIgYWxpZ249ImxlZnQiPg0KICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3RpdGxlIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLFNhbnMtU2VyaWY7Zm9udC1zaXplOjE1cHg7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1hbGlnbjpsZWZ0O2NvbG9yOiMzMzY2OTk7Ij4NCiAgICAgPGEgY2xhc3M9Im9tYV9wcl90aXRsZSIgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9M0c5OFJLSlpYQ0lKQSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDhRSk5LWDk0JTNGcmVmJTNEZW1fMXBfMTFfdGklMjZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPVFORkVMQlYyVldGUDFRRkdNVVBENkdXNFVaR0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0iZm9udC1zaXplOiAxNHB4OyB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsgY29sb3I6IzMzNjY5OTsiPg0KICAgICAgICAgIFR1a3plciA0LVBvcnRzIFVTQiBBIHRvIFVTQiAzLjAgSFVCIHdpdGggSGlnaC1TcGVlZCBEYXRhLi4uPC9hPg0KPC9zcGFuPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfYnlsaW5lIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCg0KDQoNCg0KDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgDQogICAgICAgIA0KDQogICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICANCiAgICANCiAgICANCg0KICAgIA0KICAgICAgICA8c3BhbiBjbGFzcz0ib21hLXByLWJsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMzMzM7dGV4dC1hbGlnbjpsZWZ0OyI-DQogICAgICAgICAgICAgPGJyPiBieQ0KICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJaSjY1WU9EWDVGTjkmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGc3RvcmVzJTJGVHVremVyJTJGcGFnZSUyRjIzRjIxRkUzLTU1QkUtNDE1Ri05QzA1LUE4M0NGNEIyMTIxMSUzRnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4lMjZzdG9yZV9yZWYlM0RibF9hc3RfZHBfYnJhbmRMb2dvX3N0byZIPVlJQ0dPVTRaQjlONTZBUUxBNVIyWVRNSFQ3V0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4iIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6IzMzNjY5OTsiPlR1a3plcjwvYT4NCiAgICAgICAgPC9zcGFuPg0KICAgIA0KDQogDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0ic3BhY2VyIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX2xpc3QiPg0KICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTS5SLlAuOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9saXN0Ij4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzdHJpa2U-4oK5MSw1OTkuMDA8L3N0cmlrZT4gICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX291ciI-DQogICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJwcl9wcmljZV9sYWJlbCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWFsIFByaWNlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9InByX3ByaWNlX2hpZ2hsaWdodCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTU5OS4wMCAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZb3UgU2F2ZToNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICDigrkxLDAwMC4wMCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoNjMlKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCg0KDQoNCg0KDQoNCiAgICANCg0KDQoNCgkNCg0KDQoNCg0KDQoNCg0KCQ0KDQoNCg0KCQ0KDQoJDQoNCiAgICANCgkgICAgIA0KICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgIDx0ciBjbGFzcz0icHJfbWVyY2hhbnQiPg0KICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7IHRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGNvbG9yOiM1NTU1NTU7IGZvbnQtc2l6ZToxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgU29sZCBieSANCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xSlhYSVhERk9TQ05KJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGYWFnJTJGbWFpbiUzRmllJTNEVVRGOCUyNmFzaW4lM0RCMDhRSk5LWDk0JTI2aXNBbWF6b25GdWxmaWxsZWQlM0QxJTI2bWFya2V0cGxhY2VJRCUzREEyMVRKUlVVTjRLR1YlMjZwcm90b2NvbCUzRGN1cnJlbnQlMjZzZWxsZXIlM0RBSjZTSVpDOFlRRFpYJTI2c3NobVBhdGglM0QlMjZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPVVJN1A4SlRRWFVJTkJVQ0FITzE0Tk1BWldHV0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgZm9udC1zaXplOjEycHg7Y29sb3I6ICMzMzY2OTk7Ij5DbGlja3RlY2ggUmV0YWlsIFByaXZhdGUgTHRkPC9hPiBhbmQgDQogICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOjEycHg7Ij5GdWxmaWxsZWQgYnkgQW1hem9uPC9zcGFuPi4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPC9zcGFuPiANCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgIDwvdHI-DQogICAgDQoNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTA1IiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQoNCg0KPGRpdiBjbGFzcz0icHJfbGVhcm5fbW9yZSIgYWxpZ249ImNlbnRlciIgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsiPg0KICAgICAgICA8dGFibGUgY2xhc3M9ImJ0bi1sZWFybm1vcmUtc21hbGwiICBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjMiIHN0eWxlPSJjb2xvcjogIzExMTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7ICB3aGl0ZS1zcGFjZTogbm93cmFwO2JhY2tncm91bmQtY29sb3I6ICNGRUM2NTA7IGZvbnQtc2l6ZToxMHB4OyB0ZXh0LWFsaWduOmNlbnRlcjsgYm9yZGVyLXJhZGl1czogNXB4OyI-DQogICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICA8dGQgbm93cmFwPg0KICAgICAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0yUjBXWURBVkRLMlpCJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwOFFKTktYOTQlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2VtXzFwXzExX2xtJkg9WENaSlNJTlJWQkxJV0xUTUNHUUFYV1RBVDdFQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMTFfbG0iIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0ibWlkZGxlIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzExMTsiPg0KICAgICAgICAgICAgICAgICAgICAgICAgTGVhcm4gbW9yZQ0KICAgICAgICAgICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgIDwvdGFibGU-DQo8L2Rpdj4NCg0KDQoNCiANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4gPHRhYmxlIHdpZHRoPSI2MjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0ic2VwZXJhdG9yIj4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjYyMCIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMSI-DQogICAgICAgICAgICAgICAgICA8dGQgYmdjb2xvcj0iI2VhZWJlYyIgd2lkdGg9IjYyMCIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjYyMCIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxcHg7bGluZS1oZWlnaHQ6MXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjYyMCIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgIDwvdGFibGU-DQogICAgICA8L3RkPg0KICAgICAgPHRkIHdpZHRoPSIxNSI-DQogICAgICAgICA8ZGl2IHdpZHRoPSIxNSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgIDwvdGQ-DQogICA8L3RyPg0KPC90YWJsZT4NCiAgICANCiAgICANCiAgICANCg0KDQogICAgDQoNCiAgICANCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KDQoNCg0KDQoNCjx0YWJsZSB3aWR0aD0iNjQwIj4NCiAgIDx0cj4NCiAgICAgIDx0ZCB3aWR0aD0iMTUiPg0KICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTVweDtsaW5lLWhlaWdodDoxNXB4OyI-Jm5ic3A7PC9kaXY-DQogICAgICA8L3RkPg0KICAgICAgPHRkIHdpZHRoPSI2MjAiIHZhbGlnbj0idG9wIiBhbGlnbj0ibGVmdCIgY2xhc3M9InByX2NvbnRhaW5lciI-DQogICAgICAgICA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGNsYXNzPSJsaXN0X3Byb2R1Y3QiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxNTAiIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0idG9wIiBjbGFzcz0icHJfaW1hZ2UiPg0KICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJaNE1BUjk2UTlNMlImVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA5MTY1MjVUMyUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMTJfaW0mSD1ITjNOQUYwNTNaMDdSVktWSFlEUFhBUDRBU0lBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8xMl9pbSI-DQogICAgICAgICAgICAgIDxpbWcgc3JjPSJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvSS80MTNoTndoc29WUy5fU1I1MDAsNTAwXy5fU0wxNDBfLmpwZyIgY2xhc3M9InByX2ltYWdlXzE3NSBwcl9pbWFnZV9kZXNrdG9wIiBhbHQ9IlZlcmlsdXjCriBVU0IgSHViIDMuMCBmb3IgUEMsIDQtUG9ydCBIaWdoIFNwZWVkIFVTQiBIdWIgd2l0aCBBbHVtaW5pdW0gU2hlbGwsIFVTQiBQb3J0IEh1YiAzLjAgQ29tcGF0aWJsZSBmb3IgUEMsIE1hY0Jvb2ssIE1hYyBQcm8sIE1hYyBNaW5pLCBpTWFjLCBTdXJmYWNlIFBybywgWFBTLCBQQyAoR3JleSkiIGJvcmRlcj0iMCI-DQogICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIzNjUiIHZhbGlnbj0idG9wIiBhbGlnbj0ibGVmdCI-DQogICAgICAgICAgICAgICAgICAgICA8dGFibGUgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfdGl0bGUiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KDQoNCg0KDQo8c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsU2Fucy1TZXJpZjtmb250LXNpemU6MTVweDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWFsaWduOmxlZnQ7Y29sb3I6IzMzNjY5OTsiPg0KICAgICA8YSBjbGFzcz0ib21hX3ByX3RpdGxlIiBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zQlROUU9IWkpWOE0mVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA5MTY1MjVUMyUzRnJlZiUzRGVtXzFwXzEyX3RpJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1JUURLRFFNT0c2RFdPQTFHUjdaQ1ZBUFFGREdBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IGNvbG9yOiMzMzY2OTk7Ij4NCiAgICAgICAgICBWZXJpbHV4wq4gVVNCIEh1YiAzLjAgZm9yIFBDLCA0LVBvcnQgSGlnaCBTcGVlZCBVU0IgSHViIHdpdGguLi48L2E-DQo8L3NwYW4-IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9ieWxpbmUiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkPiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCg0KDQoNCg0KDQoNCg0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICANCiAgICAgICAgDQoNCiAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQoNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgICAgICANCg0KDQogICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgIA0KICAgICAgICAgICAgDQogICAgICAgIA0KICAgIA0KICAgIA0KDQogICAgDQogICAgICAgIDxzcGFuIGNsYXNzPSJvbWEtcHItYmwiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxIZWx2ZXRpY2EsU2Fucy1TZXJpZjtmb250LXNpemU6MTJweDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzMzMzt0ZXh0LWFsaWduOmxlZnQ7Ij4NCiAgICAgICAgICAgICA8YnI-IGJ5DQogICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MVpXTjIxRTkyNTJQWSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZzdG9yZXMlMkZWZXJpbHV4JTJGcGFnZSUyRkYzRDE2QUM1LTIwOTItNEY2RS1CN0M0LTZBMTRCRUQyNDExNSUzRnJlZl8lM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4lMjZzdG9yZV9yZWYlM0RibF9hc3RfZHBfYnJhbmRMb2dvX3N0byZIPUtMQllaVklLWFdMOUpIWEFPR09DNFBVQUtUMEEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX2FzdF9ibG4iIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6IzMzNjY5OTsiPlZlcmlsdXg8L2E-DQogICAgICAgIDwvc3Bhbj4NCiAgICANCg0KIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9saXN0Ij4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE0uUi5QLjoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-ICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3RyaWtlPuKCuTgzOS4wMDwvc3RyaWtlPiAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlYWwgUHJpY2U6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0icHJfcHJpY2VfaGlnaGxpZ2h0Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg4oK5Mjk5LjAwICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3ByaWNlX3NhdmluZ3MiPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFlvdSBTYXZlOg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKCuTU0MC4wMCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoNjQlKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCg0KDQoNCg0KDQoNCiAgICANCg0KDQoNCgkNCg0KDQoNCg0KDQoNCg0KCQ0KDQoNCg0KCQ0KDQoJDQoNCiAgICANCgkgICAgIA0KICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgIDx0ciBjbGFzcz0icHJfbWVyY2hhbnQiPg0KICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7IHRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGNvbG9yOiM1NTU1NTU7IGZvbnQtc2l6ZToxMnB4OyI-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgU29sZCBieSANCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xOVNDVE04UkFGMkdGJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGYWFnJTJGbWFpbiUzRmllJTNEVVRGOCUyNmFzaW4lM0RCMDkxNjUyNVQzJTI2aXNBbWF6b25GdWxmaWxsZWQlM0QxJTI2bWFya2V0cGxhY2VJRCUzREEyMVRKUlVVTjRLR1YlMjZwcm90b2NvbCUzRGN1cnJlbnQlMjZzZWxsZXIlM0RBMkpKMUFRV1pHRU44NyUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1USVJVVUNYNUpURkNROElRNkpSWDNST1lJQ0VBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGZvbnQtc2l6ZToxMnB4O2NvbG9yOiAjMzM2Njk5OyI-RXhwcmVzcyBNYXg8L2E-IGFuZCANCiAgICAgICAgICAgIDxzcGFuIHN0eWxlPSJmb250LXNpemU6MTJweDsiPkZ1bGZpbGxlZCBieSBBbWF6b248L3NwYW4-Lg0KICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8L3NwYW4-IA0KICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgPC90cj4NCiAgICANCg0KDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDUiIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0idG9wIj4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCg0KDQo8ZGl2IGNsYXNzPSJwcl9sZWFybl9tb3JlIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0iZGlzcGxheTogaW5saW5lLWJsb2NrOyI-DQogICAgICAgIDx0YWJsZSBjbGFzcz0iYnRuLWxlYXJubW9yZS1zbWFsbCIgIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMyIgc3R5bGU9ImNvbG9yOiAjMTExOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgIHdoaXRlLXNwYWNlOiBub3dyYXA7YmFja2dyb3VuZC1jb2xvcjogI0ZFQzY1MDsgZm9udC1zaXplOjEwcHg7IHRleHQtYWxpZ246Y2VudGVyOyBib3JkZXItcmFkaXVzOiA1cHg7Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgIDx0ZCBub3dyYXA-DQogICAgICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTMyTFdIWEtHOVQ3MTgmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA5MTY1MjVUMyUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfZW1fMXBfMTJfbG0mSD1MM0xFRUYyTkJLSklVT0ROU1VFOEtWWkpUVFFBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9lbV8xcF8xMl9sbSIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMTExOyI-DQogICAgICAgICAgICAgICAgICAgICAgICBMZWFybiBtb3JlDQogICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgPC90YWJsZT4NCjwvZGl2Pg0KDQoNCg0KIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICA8L3RhYmxlPiA8dGFibGUgd2lkdGg9IjYyMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJzZXBlcmF0b3IiPg0KICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIxIj4NCiAgICAgICAgICAgICAgICAgIDx0ZCBiZ2NvbG9yPSIjZWFlYmVjIiB3aWR0aD0iNjIwIiBoZWlnaHQ9IjEiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjFweDtsaW5lLWhlaWdodDoxcHg7Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPHRyIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2MjAiIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iNjIwIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgPC90YWJsZT4NCiAgICAgIDwvdGQ-DQogICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjE1cHg7bGluZS1oZWlnaHQ6MTVweDsiPiZuYnNwOzwvZGl2Pg0KICAgICAgPC90ZD4NCiAgIDwvdHI-DQo8L3RhYmxlPg0KICAgIA0KICAgIA0KICAgIA0KDQoNCg0KDQogICAgICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KICAgIA0KDQogICAgDQogICAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCiAgICAgICAgLnNlZl9zcGFjZXIgew0KICAgICAgICAgICAgdmlzaWJpbGl0eTpoaWRkZW47DQogICAgICAgIH0NCiAgICANCiAgICAgICAgDQogICAgICAgIA0KICAgIDwvc3R5bGU-DQogICAgDQogICAgDQogICAgDQogICAgDQoNCg0KPHRhYmxlIGNsYXNzPSJjcy1zbG90IGRldmljZVdpZHRoIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgIHdpZHRoPSI2NDAiPg0KICAgIDx0cj4NCiAgICAgICAgPHRkPg0KICAgICAgICAgICAgDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8dGFibGUgYWxpZ249ImNlbnRlciIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlOyB3aWR0aDoxMDAlOyIgPg0KICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3M9ImZvb3Rlci1iYW5uZXIiIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0ibWlkZGxlIj4NCg0KDQoNCiAgICANCg0KICAgIA0KICAgICAgIA0KICAgICAgICAgDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQoNCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz0iZm9vdGVyLWJhbm5lciIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiPg0KDQoNCg0KICAgIA0KDQogICAgDQoNCiAgICANCg0KICAgIA0KICAgICAgIA0KICAgICAgICAgDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzPSJmb290ZXItYmFubmVyIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249Im1pZGRsZSI-DQoNCg0KDQogICAgDQoNCiAgICANCg0KICAgIA0KDQogICAgDQoNCiAgICANCiAgICAgICANCiAgICAgICAgIA0KICAgIA0KDQogICAgDQoNCiAgICANCg0KDQogICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICANCiAgICAgICAgPC90ZD4NCiAgICAgICAgPHRyPg0KICAgICAgICAgICAgPHRkPg0KDQo8dGFibGUgd2lkdGg9IjY0MCIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJkZXZpY2VXaWR0aCBzZWZfZm9vdGVyX2xpbmtmYXJtIg0KICAgIHZhbGlnbj0ibWlkZGxlIj4NCiAgICA8dHI-DQogICAgICAgIDx0ZCB3aWR0aD0iMTAwJSIgIGNsYXNzPSJsaW5rZmFybSIgc3R5bGU9ImZvbnQtZmFtaWx5OkhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWY7ZGlzcGxheTppbmxpbmUtYmxvY2s7Ij4NCiAgICAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjQwIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgYWxpZ249ImNlbnRlciIgY2xhc3M9ImRldmljZVdpZHRoIHNlZl9mb290ZXJfbGlua2Zhcm0iIGJnY29sb3I9IiNGRkZGRkYiIHZhbGlnbj0ibWlkZGxlIj4NCiAgICA8dHI-DQogICAgICAgIDx0ZCB3aWR0aD0iMTAwJSIgYmdjb2xvcj0iI0ZGRkZGRiIgY2xhc3M9ImxpbmtmYXJtIiBzdHlsZT0iZm9udC1mYW1pbHk6SGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZjsiPg0KICAgICAgICAgICAgPHRhYmxlIHdpZHRoPSIxMDAlIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNlbGxwYWRkaW5nPSIxMCIgY2VsbHNwYWNpbmc9IjAiIGJnY29sb3I9IiNGRkZGRkYiIGNsYXNzPSJmYXJtIj4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTAwJSIgYWxpZ249ImxlZnQiIGNsYXNzPSJmYXJtaGVhZCIgc3R5bGU9ImZvbnQtZmFtaWx5OmFyaWFsO2ZvbnQtc2l6ZToxNHB4O2NvbG9yOiNlNDc5MTE7bGluZS1oZWlnaHQ6MTZweDsgZm9udC13ZWlnaHQ6Ym9sZDsiPjxmb250IGZhY2U9ImFyaWFsLCB2ZXJkYW5hLGEgc2Fucy1zZXJpZiIgc2l6ZT0iMyIgY29sb3I9IiNlNDc5MTEiIHN0eWxlPSJmb250LWZhbWlseTphcmlhbDtmb250LXNpemU6MTRweDtjb2xvcjojZTQ3OTExO2xpbmUtaGVpZ2h0OjE2cHgiPkZpbmQgR3JlYXQgRGVhbHMgb24gTWlsbGlvbnMgb2YgUHJvZHVjdHM8L2ZvbnQ-PC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBzdHlsZT0iZm9udC1mYW1pbHk6YXJpYWwsaGVsdmV0aWNhLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHgiIGNsYXNzPSJzZWZfZm9vdGVyX2xpbmtmYXJtIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTU1IiB2YWxpZ249InRvcCIgY2xhc3M9ImZhcm0xIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBzdHlsZT0iZm9udC1mYW1pbHk6YXJpYWwsaGVsdmV0aWNhLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHgiIHdpZHRoPSI5NSUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjIiIGNlbGxwYWRkaW5nPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MU1DSkFBNDhKNFJETSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9Cb29rcyUyRiUzRm5vZGUlM0Q5NzYzODkwMzEmSD1BR0U4RUNETVBOUTZTRDNFUVhNTFYySk1FWjRBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9Cb29rcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkJvb2tzPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9M0lRSjJYUk9WR1g0NSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9lQm9va3MlMkYlM0Zub2RlJTNEMTYzNDc1MzAzMSZIPUtYWFBVWU1LOUlRSkFPRldEUFIxQ1ZOV1EzUUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX2xmX2VCb29rcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPktpbmRsZSBlQm9va3M8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zUlBIVDNIWUM2UU5QJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlM0Zub2RlJTNEOTg0MDA5NzAzMSUyNnJlZiUzRHBlX2xmX0tlUmVhZGVyJTI2cmVmXyUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzEmSD1PODZJQVpPQ1BBNTZJMFcwUFBZREVFU0pGVThBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPktpbmRsZSBlLXJlYWRlcg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJDTFIwT1Q0MElVVU8mVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZHAlMkZCMDBRSkRPRUFPJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9LUFcmSD02Mks5QzFCRVZDT1VYRE9XU1pUOVFIRFFHRVlBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9LUFciIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5LaW5kbGUgUGFwZXJ3aGl0ZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTNCR0I5N1JJSzdHNEYmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfbGZfTXVzaWMlMkYlM0Zub2RlJTNEOTc2NDQ1MDMxJkg9SjFHSTc3ME9ITFdSVTRPSjRHMFBBRVhKQlBTQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfbGZfTXVzaWMiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5NdXNpYyw8L2E-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPUZPSUVENUQyWU9ETyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9Nb3ZpZXMlMkYlM0Zub2RlJTNEOTc2NDE2MDMxJkg9V1ZOVTdKSUpBRkFCUkRVVktSTEtQV1NNV0hDQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfbGZfTW92aWVzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-TW92aWVzPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9M001MjkyUUxPTDRXTCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9WRyUyRiUzRm5vZGUlM0Q5NzY0NjAwMzEmSD1EUEpXRTNJOFM1RVVMTEtEVTBDR1JKU0FRWTBBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9WRyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPlZpZGVvIEdhbWVzPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTgwIiB2YWxpZ249InRvcCIgY2xhc3M9ImZhcm0yIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBzdHlsZT0iZm9udC1mYW1pbHk6YXJpYWwsaGVsdmV0aWNhLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHgiIHdpZHRoPSI5NSUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjIiIGNlbGxwYWRkaW5nPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MU4wRkdTS0NBVkM4SyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9Nb2JpbGVzJTJGJTNGbm9kZSUzRDEzODk0MDEwMzEmSD1YTk9BUkFZV0hXTkJFSkFITEVGU1hBTzJNQ0NBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9Nb2JpbGVzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-TW9iaWxlcyAmYW1wOyA8L2E-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MTNDTFpXRDA5VUVLTCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9UYWJsZXRzJTJGJTNGbm9kZSUzRDEzNzU0NTgwMzEmSD1aTFZENTFWUVAwTU5HQ1hVWTJYTUYwWExFR1NBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9UYWJsZXRzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-VGFibGV0czwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPUIxQThZWURDQjZEVSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9Db21wcyUyRiUzRm5vZGUlM0Q5NzYzOTIwMzEmSD1DSklTVDdJMExNWkpRV1lJSk5FRFpPSlVIQVVBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9Db21wcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkNvbXB1dGVycyAmYW1wOyBBY2Nlc3NvcmllczwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPUZHVUU0UVRVNlhCVyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9sZl9DYW1lcmElMkYlM0Zub2RlJTNEMTM4ODk3NzAzMSZIPURaQUVMRldLSERYUlJUSTk1QlY3QUhLR01GV0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX2xmX0NhbWVyYSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkNhbWVyYXMsPC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTFPR1E1QkdNQUgyQkUmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfQVZUViUyRiUzRm5vZGUlM0QxNTc1NDA3MDMxJkg9SkpVVkFOR0xRWDNZSTdVUUk0Q1U3S0JGVE40QSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfQVZUViIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPiBBdWRpbyAmIFZpZGVvPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MjBHTUlXOEJUTUU2SiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9NdXNpY2FsSW5zdHIlMkYlM0Zub2RlJTNEMzY3NzY5NzAzMSZIPThPWVBSRUFaMkpLMVZGWjRQVVNMWkdTQUpORUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX011c2ljYWxJbnN0ciIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPk11c2ljYWwgSW5zdHJ1bWVudHM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zSUIzRUE2OUNOMzBGJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX1Nwb3J0cyUyRiUzRm5vZGUlM0QxOTg0NDQzMDMxJkg9TVo1UE5JSExIWVVSSzFJWUVQV08wMFpHNzE4QSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfU3BvcnRzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-U3BvcnRzICYgRml0bmVzczwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTExVkVXOFNKVDEzR1MmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfSEslMkYlM0Zub2RlJTNEOTc2NDQyMDMxJkg9MDFRTUlHWktBTEVDSUpGU1VFMk1BQUxDWVhXQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfSEsiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5Ib21lICYgS2l0Y2hlbjwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEzNSIgdmFsaWduPSJ0b3AiIGNsYXNzPSJmYXJtMyI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGFibGUgc3R5bGU9ImZvbnQtZmFtaWx5OmFyaWFsLGhlbHZldGljYSxzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxMnB4IiB3aWR0aD0iOTUlIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIyIiBjZWxscGFkZGluZz0iMCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTRTQTVJNUlRV1M4WSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9DbG90aGluZyUyRiUzRm5vZGUlM0QxNTcxMjcxMDMxJkg9V09LS0UxTFBIQlU3TUhCWkdENjhXUkJITlZPQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfQ2xvdGhpbmciIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5DbG90aGluZywgQWNjZXNzb3JpZXM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj1HOVE2NDgxS1NSTzEmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfV2F0Y2hlcyUyRiUzRm5vZGUlM0QxMzUwMzg3MDMxJkg9RzJZTFQyVkNaVUlQVUpBTVBBMDJORFg5TkM0QSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfV2F0Y2hlcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPldhdGNoZXMsPC9hPiA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj00WE40TkxGOTNGQlAmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfSmV3ZWxsZXJ5JTJGJTNGbm9kZSUzRDE5NTEwNDgwMzEmSD1HMUVHRjlGM0I1TDBSNEVUV0JWS1ZISUkxVjhBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9KZXdlbGxlcnkiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5KZXdlbGxlcnk8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xUUxHNTE0QjFKOFFXJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX0hhbmRiYWdzJTJGJTNGbm9kZSUzRDE5ODMzMzgwMzEmSD1STElCS0JPMERTWUdWUzJCV09MUlhNRk0yRThBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9IYW5kYmFncyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkhhbmRiYWdzICYgPC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTFRWTI4Vk1DNDIySlMmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfTHVnZ2FnZSUyRiUzRm5vZGUlM0QyNDU0MTY5MDMxJkg9OUFMWlQ5VEY0S0RJTVhPN0xZVDhDQ1ZHUlRFQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfTHVnZ2FnZSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkx1Z2dhZ2U8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj1NV1IwQ0FRNFFCMzEmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfU2hvZXMlMkYlM0Zub2RlJTNEMTk4MzM5NjAzMSZIPTE4SEdQT0dYQ0dYRExISkJTUklUOFhLUzdaQUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX1Nob2VzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-U2hvZXM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0xSFEwVUE5V1VMNklaJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX0JlYXV0eSUyRiUzRm5vZGUlM0QxMzU1MDE2MDMxJkg9Vzg3MDJGUlpRSlBKQUdSMVJNNFlFVjM4RFcwQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfQmVhdXR5IiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-QmVhdXR5ICYgPC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJPUVhVVjVJMVBLMEImVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfSGVhbHRoJTJGJTNGbm9kZSUzRDEzNTAzODQwMzEmSD1aOTBITlpBRUFUUkYwOFZBM1FDWDZMRkFPNk1BJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9IZWFsdGgiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5IZWFsdGg8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zUDlRWVRZTDVBTTdKJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX1RveXMlMkYlM0Zub2RlJTNEMTM1MDM4MDAzMSZIPVhQRVdEQTZWRVQ2Uk9QWkM2SERaQ0VCVU9BS0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX1RveXMiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5Ub3lzICYgPC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTNPUjFTN1hBWDJFOEomVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfQmFieSUyRiUzRm5vZGUlM0QxNTcxMjc0MDMxJkg9QVNJWENFTDBBQVNZWUlNTVU4U0hVRUszWVFDQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfQmFieSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkJhYnkgUHJvZHVjdHM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxNzAiIHZhbGlnbj0idG9wIiBjbGFzcz0iZmFybTQiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIHN0eWxlPSJmb250LWZhbWlseTphcmlhbCxoZWx2ZXRpY2Esc2Fucy1zZXJpZjtmb250LXNpemU6MTJweCIgd2lkdGg9Ijk1JSIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMiIgY2VsbHBhZGRpbmc9IjAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0yUFNGS09VOElGMUtFJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX0dDJTJGJTNGbm9kZSUzRDM3MDQ5ODIwMzEmSD1UR1dBSjhJTE9VQVlMUzZOQ0dUMlVYTUVBUkNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9HQyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkdpZnQgQ2FyZHM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0yV1lCQzlaSzhDM0JMJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX1BldHMlMkYlM0Zub2RlJTNEMjQ1NDE4MTAzMSZIPVVDTTlBWFVYS1MyOEZRRU1WQVJSMU1NVENaU0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX1BldHMiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5QZXQgU3VwcGxpZXM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zSzVUVFNTQVFQVzgwJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX0dvdXJtZXQlMkYlM0Zub2RlJTNEMjQ1NDE3ODAzMSZIPVFIVEtPV05QT1c2TzBBN1ZJSVhRUjdGTjczSUEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX0dvdXJtZXQiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5Hb3VybWV0IDwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9mLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJSSTdVWTM1T1ZVRlcmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGbXNob3AlM0ZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MSZIPVNJWEZLTEJaU0FGRThSSDBUSEhNWDZCRTZROEEmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-QW1hem9uIFNob3BwaW5nIEFwcDwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9mLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTZKSjZXQTFHUVY4UiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmRpZ2l0YWwlMkZmaW9uYSUyRmtjcC1sYW5kaW5nLXBhZ2UlM0ZyZWZfJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9LQ1AmSD1ZREpJTjVBU1VJMTNBS0ZFTEFMV0pGRkVVSjBBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9LQ1AiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5LaW5kbGUgUmVhZGluZyBBcHBzPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL2YuaHRtbD9DPUJEU0YxUUREN1RUSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNjAwMTIzODhiY2U5NDAxZmY1NDRlZTFiNjQ3ZDEzZDc0NTBwMGV1JlI9MUQ1OENZWDFXOEVXMiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmZlYXR1cmUuaHRtbCUyRnJlZiUzRHBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfQXBwc3RvcmUlM0ZpZSUzRFVURjglMjZkb2NJZCUzRDEwMDA3MjE3NzMmSD1VU0kxWFlTWUtSTTRIWkVBTU5YQUFKVEZRQVFBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9BcHBzdG9yZSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkFwcHN0b3JlIGZvciBBbmRyb2lkPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgIDwvdGQ-DQogICAgPC90cj4NCjwvdGFibGU-DQo8dGFibGUgY2xhc3M9InNlZl9zcGFjZXIiIHdpZHRoPSI2NDAiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBzdHlsZT0iYm9yZGVyLXNwYWNpbmc6MHB4O2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZTsiPg0KICAgIDx0ciBoZWlnaHQ9IjIiPg0KICAgICAgICA8dGQgYmdjb2xvcj0iI2NjY2NjOSIgd2lkdGg9IjY0MCIgaGVpZ2h0PSIyIj4NCiAgICAgICAgICAgIDxkaXYgd2lkdGg9IjY0MCIgc3R5bGU9ImZvbnQtc2l6ZToycHg7bGluZS1oZWlnaHQ6MnB4Ij4mbmJzcDs8L2Rpdj4NCiAgICAgICAgPC90ZD4NCiAgICA8L3RyPg0KPC90YWJsZT4NCiAgICAgICAgPC90ZD4NCiAgICA8L3RyPg0KPC90YWJsZT4gIA0KIA0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KICAgIC5zZWZfZm9vdGVyX2Nvbm5lY3QgLnlzaG9ydGN1dHMgeyBjb2xvcjojRkZGRkZGIH0NCjwvc3R5bGU-DQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI-DQogICAgQG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWF4LWRldmljZS13aWR0aDogNDgwcHgpIHsNCiAgICAuc2VmX2Zvb3Rlcl9jb25uZWN0IHsgd2lkdGg6IDMwMHB4ICFpbXBvcnRhbnQ7IH0NCiAgICB9DQo8L3N0eWxlPg0KDQo8dGFibGUgY2xhc3M9InNlZl9mb290ZXJfY29ubmVjdCIgYmdjb2xvcj0iI0ZGRkZGRiIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMTAiIGNlbGxzcGFjaW5nPSIwIiB3aWR0aD0iNjQwIiBhbGlnbj0iY2VudGVyIj4NCiAgICA8dGJvZHk-DQogICAgICAgIDx0cj4NCiAgICAgICAgICAgIDx0ZCB3aWR0aD0iNTAlIj4NCiAgICAgICAgICAgICAgICA8dGFibGUgYm9yZGVyPSIwIiBhbGlnbj0ibGVmdCIgY2VsbHBhZGRpbmc9IjYiIGNlbGxzcGFjaW5nPSIwIiBjbGFzcz0ic2V0dGluZ3MiIGNib3JkZXI9IjAiPg0KICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJIS1k1TFRQUjY4QzkmVD1DJlU9aHR0cCUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX2Zvb3Rlcl9hbWF6b25sb2dvJTJGJkg9OVdFMEFBWlRVUVJPMVNSQzBNWVFJT0xEUFpLQSZyZWZfPXBlXzQwNTAwMDQxXzEyMTc3MDM1NzFfcGVfZm9vdGVyX2FtYXpvbmxvZ28iIHRhcmdldD0iX2JsYW5rIj48aW1nIHNyYz0iaHR0cDovL2ctZWMyLmltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzMxL2FhL2FtYXpvbi9sb2dvMi5naWYiIGFsdD0iQW1hem9uLmluImJvcmRlcj0iMCJhbGlnbj0ibGVmdCIvPjwvYT4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICA8dGQgYWxpZ249InJpZ2h0Ij48dGFibGUgY2xhc3M9ImNvbm5lY3QiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjYiIGNlbGxzcGFjaW5nPSIwIiBhbGlnbj0icmlnaHQiPg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJyaWdodCI-PGZvbnQgc3R5bGU9ImZvbnQtZmFtaWx5OiB2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTBweDsgY29sb3I6ICM2NjY7IGxpbmUtaGVpZ2h0OjEwcHgiIGNvbG9yPSIjOTk5IiBmYWNlPSJ2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWYiIHNpemU9IjEiPkNvbm5lY3Qgd2l0aCBBbWF6b24gSW5kaWE8L2ZvbnQ-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzPSJmYWNlYm9vayI-PGZvbnQgc3R5bGU9ImZvbnQtZmFtaWx5OiB2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTBweDsgY29sb3I6ICM5OTk7IiBjb2xvcj0iIzk5OSIgZmFjZT0idmVyZGFuYSxhcmlhbCxzYW5zLXNlcmlmIiBzaXplPSIxIj48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9QkRTRjFRREQ3VFRLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI2MDAxMjM4OGJjZTk0MDFmZjU0NGVlMWI2NDdkMTNkNzQ1MHAwZXUmUj0zMjVVOElNMlJNUzhFJlQ9QyZVPWh0dHAlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZyZWRpcmVjdC5odG1sJTJGcmVmJTNEcGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9mYl9mdHIlMkYlM0Zsb2NhdGlvbiUzRGh0dHAlM0ElMkYlMkZ3d3cuZmFjZWJvb2suY29tJTJGQW1hem9uSU4lMjZ0b2tlbiUzRDIwNzVENUVBQzdCQjIxNDA4OTcyOEUyMTgzRkQzOTE3MDZENDFFOTQmSD1KMlBBMkFBTkNCVFFBOUxJQ01ZVlU2RFFUUkNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV9mYl9mdHIiIHRhcmdldD0iX2JsYW5rIj48aW1nIHNyYz0iaHR0cDovL2ctZWN4LmltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzAxL3VzLW1haWwvRkJsb2dvLmdpZiIgYWx0PSJpbWFnZSIgYm9yZGVyPSIwIiBoZWlnaHQ9IjMwIiBoc3BhY2U9IjAiIHZzcGFjZT0iMCIgd2lkdGg9IjMwIiBzdHlsZT0id2lkdGg6MzBweDsgaGVpZ2h0OjMwcHg7IiAvPjwvYT48L2ZvbnQ-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzPSJ0d2l0dGVyIj48Zm9udCBzdHlsZT0iZm9udC1mYW1pbHk6IHZlcmRhbmEsYXJpYWwsc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMHB4OyBjb2xvcjogIzk5OTsiIGNvbG9yPSIjOTk5IiBmYWNlPSJ2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWYiIHNpemU9IjEiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9mLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJBTldJU1UxMFJINlUmVD1DJlU9aHR0cCUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnJlZGlyZWN0Lmh0bWwlMkZyZWYlM0RwZV80MDUwMDA0MV8xMjE3NzAzNTcxX3BlX3R3X2Z0ciUyRiUzRmxvY2F0aW9uJTNEaHR0cCUzQSUyRiUyRnR3aXR0ZXIuY29tJTJGQW1hem9uSU4lMjZ0b2tlbiUzREEzMDlERkJGQ0IxRTM3QTgwOEZGNTMxOTM0ODU1REM4MTdGMTMwQjYmSD0zVEJTTEFDSjZUOVBIUU4zTFBET0hFNlRBTVNBJnJlZl89cGVfNDA1MDAwNDFfMTIxNzcwMzU3MV9wZV90d19mdHIiIHRhcmdldD0iX2JsYW5rIj48aW1nIHNyYz0iaHR0cDovL2ctZWN4LmltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzAxL3VzLW1haWwvVHdpdHRlckxvZ28uZ2lmIiBhbHQ9ImltYWdlIiBib3JkZXI9IjAiIGhlaWdodD0iMzAiIGhzcGFjZT0iMCIgdnNwYWNlPSIwIiB3aWR0aD0iMzAiIHN0eWxlPSJ3aWR0aDozMHB4OyBoZWlnaHQ6MzBweDsiIC8-PC9hPjwvZm9udD48L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-ICAgICAgICAgICAgDQogICAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgIDwvdGJvZHk-DQo8L3RhYmxlPg0KICAgICAgICAgICANCiAgICAgICAgICAgIDwvdGQ-DQogICAgICAgIDwvdHI-DQoNCiAgICA8L3RyPg0KDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICANCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI-DQogIEBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogNDgwcHgpIHsNCiAgICBib2R5W3lhaG9vXSAuc2VmX2xlZ2FsX2Zvb3RlciB7IHdpZHRoOiAzMDBweCAhaW1wb3J0YW50OyB9DQogIH0gICAgDQo8L3N0eWxlPg0KDQoNCg0KDQo8dGFibGUgYWxpZ249ImNlbnRlciIgIHdpZHRoPSI2NDAiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjIiIGNlbGxzcGFjaW5nPSIwIiBjbGFzcz0ic2VmX2xlZ2FsX2Zvb3RlciIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2UzZTNlMyIgYmdjb2xvcj0iI2UzZTNlMyIgPg0KICAgIDx0ciBoZWlnaHQ9IjEwIj4NCiAgICAgIDx0ZCB3aWR0aD0iMTAwJSI-PGRpdiB3aWR0aD0iMTAwJSIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4OyBsaW5lLWhlaWdodDoxMHB4Ij4mbmJzcDs8L2Rpdj48L3RkPg0KICAgIDwvdHI-DQogICAgPHRyPg0KICAgICAgPHRkIGFsaWduPSJsZWZ0IiBjbGFzcz0ibGVnYWwtdGV4dCI-DQogICAgICBXZSBob3BlIHlvdSBmb3VuZCB0aGlzIG1lc3NhZ2UgdG8gYmUgdXNlZnVsLiBIb3dldmVyLCBpZiB5b3UnZCByYXRoZXIgbm90IHJlY2VpdmUgZnV0dXJlIGUtbWFpbHMgb2YgdGhpcyBzb3J0IGZyb20gQW1hem9uLmluLCBwbGVhc2UgPGENCiAgICAgICAgICAgIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9mLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTFVSTNIQVdWM0k0QUUmVD1YJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGJTJGZ3AlMkZnc3MlMkZvJTJGMTFYTHowVmxkclFGOWpweU1PbksybUlTY2wxLjdqT291VXZ6QnE4anlmM3RWYmlUS1FlZVJNaWdaSWVlTUlQVzMmSD1HTUlNSExTQVJHQVRHS0NYMUtKMEJGQUlTSEFBIiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLEhlbHZldGljYSxTYW5zLVNlcmlmOyBmb250LXNpemU6IDEwcHg7Ij5vcHQtb3V0IGhlcmU8L2E-IDxici8-IDxici8-DQogICAgICAgIFBsZWFzZSBub3RlIHRoYXQgcHJvZHVjdCBwcmljZXMgYW5kIGF2YWlsYWJpbGl0eSBhcmUgc3ViamVjdCB0byBjaGFuZ2UuIFByaWNlcyBhbmQgYXZhaWxhYmlsaXR5IHdlcmUgYWNjdXJhdGUgYXQgdGhlIHRpbWUgdGhpcyBuZXdzbGV0dGVyIHdhcyBzZW50OyBob3dldmVyLCB0aGV5IG1heSBkaWZmZXIgZnJvbSB0aG9zZSB5b3Ugc2VlIHdoZW4geW91IHZpc2l0IEFtYXpvbi5pbi4gDQogICAgICAgIA0KICAgICAgICA8YnIvPjxici8-QW1hem9uLmluIE1hcmtldHBsYWNlIHBsYXRmb3JtOiBQcm9kdWN0cyBzb2xkIGJ5IGEgTWFya2V0cGxhY2Ugc2VsbGVyIGFyZSBzdWJqZWN0IHRvIHRoYXQgc2VsbGVyJ3MgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2Ygc2FsZS4gU2VlIHd3dy5BbWF6b24uaW4gZm9yIGRldGFpbHMuIDxiciAvPjxiciAvPg0KICAgICAgICBSZWZlcmVuY2U6IDEyMTc3MDM1NzE8YnIgLz48YnIgLz4NCiAgICAgICAgVGhpcyBtZXNzYWdlIHdhcyBzZW50IHRvIHRoZSBmb2xsb3dpbmcgZS1tYWlsIGFkZHJlc3M6IDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7IGZvbnQtc2l6ZTogMTBweDsiPnBza2h1c2hhbEBnbWFpbC5jb208L3NwYW4-DQogICAgICA8L3RkPg0KICAgIDwvdHI-DQogIDwvdGJvZHk-DQo8L3RhYmxlPg0KICANCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICANCiAgICAgICAgPC90YWJsZT4NCiAgICAgICAgDQogICAgPGltZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBzcmM9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz1CRFNGMVFERDdUVEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjYwMDEyMzg4YmNlOTQwMWZmNTQ0ZWUxYjY0N2QxM2Q3NDUwcDBldSZSPTJOR00yS0VGMU5DN1ImVD1FJlU9aHR0cHMlM0ElMkYlMkZpbWFnZXMtZXUuc3NsLWltYWdlcy1hbWF6b24uY29tJTJGaW1hZ2VzJTJGRyUyRjAxJTJGbmF2JTJGdHJhbnNwLmdpZiZIPVhCMzBWWTk1T0xOQUtITUpaOUVGQlZKWk44V0EmcmVmXz1wZV80MDUwMDA0MV8xMjE3NzAzNTcxX29wZW4iIC8-PC9ib2R5Pg0KPC9odG1sPg0KDQoNCg0KDQoNCg==" - } - } - ] - }, - "sizeEstimate": 198800, - "historyId": "527715", - "internalDate": "1732579958000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_04_193640e74d93dc9b_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_04_193640e74d93dc9b_20241126.json deleted file mode 100644 index aaefb58..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_04_193640e74d93dc9b_20241126.json +++ /dev/null @@ -1,179 +0,0 @@ -{ - "id": "193640e74d93dc9b", - "threadId": "193640e74d93dc9b", - "labelIds": [ - "UNREAD", - "CATEGORY_UPDATES", - "INBOX" - ], - "snippet": "Feast your eyes on our completely redesigned web console, plus expanded migration options and more... Hello, As we gather to celebrate Thanksgiving in the US, we're especially grateful for our", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp984823wrq; Mon, 25 Nov 2024 08:01:29 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IH+vf8/Fteko3M8o3piPWLQDPikJ1wq+G3dKPy69Vuxm+CTLGfM304hsif0pHcSATwRtMiP" - }, - { - "name": "X-Received", - "value": "by 2002:a05:620a:17a5:b0:7b1:50a8:3394 with SMTP id af79cd13be357-7b51455cc96mr1998061085a.36.1732550489464; Mon, 25 Nov 2024 08:01:29 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732550489; cv=none; d=google.com; s=arc-20240605; b=U0GfsIWubWP6yFaeQTUTLUXf86KkhphJhC+lyqVLrCZlta3hBcfGm7bHPJvBZsp9gU yA5m9aNMZWG0qszyQzMZotMWTaYSHuHV9vrHbJAymzpHlaCASGoZPw28d8zeqibeuork hdexr4PjezkCb+SCMZ/o/lhbsGv9KSpDLrkJbn4wsyVIZTMZDd/4KP9XfXEVjCk6WyG7 +G2C2kEanh/mP2bQk059GCKpbvfiqmHZbL5PtIdijZ5eO9pZFKFc86tDKJO+0vgpm+D8 HY3WEsGb/PzVFYSQGaFcE+oxNEzENXqcC6n5Sfz3BWCbBel1gHqu+H2vcNfGu/bUwelG MfyQ==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=feedback-id:list-unsubscribe-post:precedence:mime-version:subject :message-id:to:reply-to:from:date:list-unsubscribe:dkim-signature :dkim-signature; bh=hvQzqDR16zPZGhiM7v8hurpvFgqpnV1lolZcpeqI8r0=; fh=u/EceduMLbMJaVmVACWimtVNyu5iebWbNB9Q7JrDYgs=; b=DbOqZM5uvFufkZaBlxN5XdanVQCZiMNAevcLjyV8RyOACO1vFtLSLnxtnz8q276iOk l4YAUBVUepCxvJPjdi+tldA9ZJpbyZD/3l7cOlx1qpAmvP2jNySSqolco8HqJ2Q+c6AT 5v8cmjMoVm1Ni82iUWLGHURa4PJgAGC9dPH6DHmkorMJxWFeHRAn35vhF6d5MQzY2MlI qWJxD1Mlr+hamALJRukMDRiMJShkc1/3kdmzeIkd/cvjyrizSFCr15pc7m3PSE7HSe84 FvbJ9twKEDkKsJfqXcGHHJCdcMWmTVpEE1V2eB2ch0cETMJLvnuxFb+H9d4WeqrrluU8 pzkA==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@bf01x.hubspotemail.net header.s=hs2 header.b=m+NNTsoY; dkim=pass header.i=@zilliz.com header.s=hs2-24054828 header.b=dCZcJzff; spf=pass (google.com: domain of 1axbzsh1c0inx9vvhdkhx9vxwsytxpfuxt98ee-pskhushal=gmail.com@bf01x.hubspotemail.net designates 158.247.24.91 as permitted sender) smtp.mailfrom=\"1axbzsh1c0inx9vvhdkhx9vxwsytxpfuxt98ee-pskhushal=gmail.com@bf01x.hubspotemail.net\"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=zilliz.com" - }, - { - "name": "Return-Path", - "value": "<1axbzsh1c0inx9vvhdkhx9vxwsytxpfuxt98ee-pskhushal=gmail.com@bf01x.hubspotemail.net>" - }, - { - "name": "Received", - "value": "from bid47t5.bf01x.hubspotemail.net (bid47t5.bf01x.hubspotemail.net. [158.247.24.91]) by mx.google.com with ESMTPS id af79cd13be357-7b657597496si812333685a.609.2024.11.25.08.01.29 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 25 Nov 2024 08:01:29 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of 1axbzsh1c0inx9vvhdkhx9vxwsytxpfuxt98ee-pskhushal=gmail.com@bf01x.hubspotemail.net designates 158.247.24.91 as permitted sender) client-ip=158.247.24.91;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@bf01x.hubspotemail.net header.s=hs2 header.b=m+NNTsoY; dkim=pass header.i=@zilliz.com header.s=hs2-24054828 header.b=dCZcJzff; spf=pass (google.com: domain of 1axbzsh1c0inx9vvhdkhx9vxwsytxpfuxt98ee-pskhushal=gmail.com@bf01x.hubspotemail.net designates 158.247.24.91 as permitted sender) smtp.mailfrom=\"1axbzsh1c0inx9vvhdkhx9vxwsytxpfuxt98ee-pskhushal=gmail.com@bf01x.hubspotemail.net\"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=zilliz.com" - }, - { - "name": "Received", - "value": "by 172.16.224.35 with SMTP id a0b2377bl4ybydq92cr5x2s5w50rr0v0djrec38pwv4; Mon, 25 Nov 2024 16:01:29 GMT" - }, - { - "name": "DKIM-Signature", - "value": "v=1; s=hs2; d=bf01x.hubspotemail.net; i=@bf01x.hubspotemail.net; h=sender:from:from:reply-to:to:to:cc:cc:subject:subject:list-unsubscribe:form-sub:feedback-id:list-unsubscribe-post; a=rsa-sha256; c=relaxed/relaxed; bh=hvQzqDR16zPZGhiM7v8hurpvFgqpnV1lolZcpeqI8r0=; b=m+NNTsoYyn2tZ/wV/I6UXPnfIpGJuLdZAU4vRxS4NKPIDG+i5HNt9eY5o5cAIs 4mUUepea+TfNyi1PilJDnFg6Zhh6LD7j9Oj/VROX4FGC0adfVydQqIPRPVqH4zM +/F5GZ/f/dAJbmFmMM+gTkM0ifvVULVahaMhI3c5gvseCadkXRFOjZHyJTyUBYm uGgBP0x4ohO9zFOTHs9GytG3rcfEu/7Gs3mxCQAxarLMl89Cm2poJriAHxRLAQ2 BoxWeEhly3BAdFYdysDY0Ry1nawXbaisH4vCjZWJvQk6lOOnYMk02ngYgrrJh82 dSeSmMjmJiY/OvItyWj2X8mXBivQ==; q=dns/txt; t=1732550489; x=1732813289;" - }, - { - "name": "DKIM-Signature", - "value": "v=1; s=hs2-24054828; d=zilliz.com; i=@zilliz.com; h=sender:from:from:reply-to:to:to:cc:cc:subject:subject:list-unsubscribe:form-sub:feedback-id:list-unsubscribe-post; a=rsa-sha256; c=relaxed/relaxed; bh=hvQzqDR16zPZGhiM7v8hurpvFgqpnV1lolZcpeqI8r0=; b=dCZcJzffwhM4dmI/qrCp3/TW07yVpibY8OLH0z05VJsoBTyRH9wcaDsP75uYMr BeNlVnAWQyLy866E2CYJOzgeb9OMJFZNelPwFDng3eYzdJksy/kXP5suqVdb7Tl 7s/dfdnogPgL6by5j1ZedccQag7j6RUCMQVnKeV1j5L3sXQidbd1MlTLBZzzstl hKQiujdK8VX9qPp4BMRlOnOPnFLKDnYxPp+Zmx4/xR9iB6zPeEi+d+QHJhDgoqu yun7oQEDtdIe8QG1mw3W0U6SIYAoe5eaduaeA4QfYTdUvIaCTaTBMYZlD35UiQw m3NzBexw0u61kEnBll4lbBVFuEqQ==; q=dns/txt; t=1732550489; x=1732813289;" - }, - { - "name": "Return-Path", - "value": "<1axbzsh1c0inx9vvhdkhx9vxwsytxpfuxt98ee-pskhushal=gmail.com@bf01x.hubspotemail.net>" - }, - { - "name": "X-HS-Cid", - "value": "1axe6rm4ft7e61m9x0ng8rdlct79zcgp3ad5ty" - }, - { - "name": "List-Unsubscribe", - "value": ", " - }, - { - "name": "Date", - "value": "Mon, 25 Nov 2024 08:01:29 -0800" - }, - { - "name": "From", - "value": "Steffi Li " - }, - { - "name": "Reply-To", - "value": "chloe.williams@zilliz.com" - }, - { - "name": "To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Message-ID", - "value": "<1732550488892.f6001060-de41-4256-ae9f-3bd110de9463@bf01x.hubspotemail.net>" - }, - { - "name": "Subject", - "value": "\ud83e\udd83 Zilliz Cloud November Update: Much to be Thankful For!" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"----=_Part_52217_1401384494.1732550489030\"" - }, - { - "name": "Precedence", - "value": "bulk" - }, - { - "name": "X-Report-Abuse-To", - "value": "abuse@hubspot.com (see https://policy.hubspot.com/abuse-complaints)" - }, - { - "name": "List-Unsubscribe-Post", - "value": "List-Unsubscribe=One-Click" - }, - { - "name": "Feedback-ID", - "value": "aeolu3y:aiftvzxh:aidf:HubSpot" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain; charset=utf-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 8758, - "data": "RmVhc3QgeW91ciBleWVzIG9uIG91ciBjb21wbGV0ZWx5IHJlZGVzaWduZWQgd2ViIGNvbnNvbGUsIHBsdXMgZXhwYW5kZWQgbWlncmF0aW9uIG9wdGlvbnMgYW5kIG1vcmUuLi4NCg0KSGVsbG8sDQoNCkFzIHdlIGdhdGhlciB0byBjZWxlYnJhdGUgVGhhbmtzZ2l2aW5nIGluIHRoZSBVUywgd2UncmUgZXNwZWNpYWxseSBncmF0ZWZ1bCBmb3Igb3VyIHZpYnJhbnQgY29tbXVuaXR5IGFuZCBleGNpdGVkIHRvIHNoYXJlIG91ciBsYXRlc3QgdXBkYXRlcyEgVGhpcyBOb3ZlbWJlciwgd2UncmUgc2VydmluZyB1cCBhIGNvbXBsZXRlbHkgcmVkZXNpZ25lZCBleHBlcmllbmNlIHRoYXQgd2lsbCB0cmFuc2Zvcm0gaG93IHlvdSBpbnRlcmFjdCB3aXRoIFppbGxpeiBDbG91ZC4gTGV0J3MgZGl2ZSBpbnRvIHdoYXQncyBjb29raW5nOg0KDQrwn46oIEZyZXNoICYgTW9kZXJuIFdlYiBDb25zb2xlOiBXZSd2ZSBjb21wbGV0ZWx5IHJlaW1hZ2luZWQgb3VyIHdlYiBjb25zb2xlIGludGVyZmFjZSwgYnJpbmdpbmcgeW91IGEgbW9yZSBpbnR1aXRpdmUgYW5kIHZpc3VhbGx5IGFwcGVhbGluZyBleHBlcmllbmNlOg0KDQotIFJlZGVzaWduZWQgTmF2aWdhdGlvbjogU3RyZWFtbGluZWQgbWVudSBzdHJ1Y3R1cmUgc2VwYXJhdGluZyBvcmdhbml6YXRpb24gYW5kIHByb2plY3QgbGV2ZWxzIGZvciBjbGVhcmVyIG5hdmlnYXRpb24gcGF0aHMgYW5kIGltcHJvdmVkIGZlYXR1cmUgZGlzY292ZXJhYmlsaXR5Lg0KLSBDYXJkLUJhc2VkIERlc2lnbjogUmVwbGFjZWQgdGFibGUgbGF5b3V0cyB3aXRoIG9yZ2FuaXplZCBjYXJkIHZpZXdzIGZvciBiZXR0ZXIgaW5mb3JtYXRpb24gaGllcmFyY2h5IGFuZCByZWR1Y2VkIHZpc3VhbCBjb21wbGV4aXR5Lg0KLSBDb25zaXN0ZW50IExheW91dCBTeXN0ZW06IFN0YW5kYXJkaXplZCBncmlkIHN5c3RlbSBhY3Jvc3MgYWxsIHBhZ2VzIGZvciBtb3JlIGludHVpdGl2ZSBmZWF0dXJlIGFjY2VzcyBhbmQgcmVkdWNlZCBjb2duaXRpdmUgbG9hZC4NCg0KQ2hlY2sgb3V0IHRoZSBuZXcgbG9vayEg8J-Rhw0KDQpMYXJrMjAyNDExMTQtMTYwNTIwIChodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzFuM3B5ZDBXOHdMS1NSNmxaM21wVzV0SEtfUzd4ekh6Ulc1Z3NOVEY1eExUbTdXOFhOMzRDMTQ5clZIVzJQOU03QzhCWHlxQ1c1dEJDdG40VHJfTFRXNEhoTXIyMnhWcHZNVzN6Y3NfTjUzY3czcFc2TnJHdHo0ZDltajdXN0tUaHhuNFpTdlI4VzZ4anZLQzV2Sk04NFc3cDcyYi0xWlhWbjFXNzN4RE1iNTRuZ1h5VzZZTmtUbjVOTjY0M1c0ckJucm0yRFFyTVBXOGtMLXpNM2dWeFY1VzdyeW53VzU3UzlRRFcxc0RfRjU4Tk4wZFNXMnhnWGhuMkNicnNZVzRxei0ybTNOOWM2Ylcxc2MyQzExZFl2MC1XN0pRdmYyNVBWNFRxVzg4bDNjeTdXbjlGbVc2OUZwc3o0UHMtamJOMTJuUmxGcHdUalFXM1NzZmY4NFE3bWg5VzRaRFRaRjF2SkJfdFc1OGpiOXY5Z1JYOFRWNnQwREMxWThwWFpmOWxXemh6MDQgKQ0KDQrwn6aDIE90aGVyIEhpZ2hsaWdodHMgJiBJbXByb3ZlbWVudHMNCg0KLSBFbmhhbmNlZCBEYXRhIE1pZ3JhdGlvbjogTm93IHN1cHBvcnRpbmcgUWRyYW50IChodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzFuM2dWRFlXOHdMS1NSNmxaM3BaVlh5a1Y1Mm02dGZDTjg5WHJmWmxTTDJ3VnhkWHJIODBXZ3gxVzdQQnhKejZWUEdkQ1ZQWWxENDJDeENmU1czc2ZRUXIxLUJjRkdXM1F6WGxGOG1qM3A2TjM0bXhDNjUybVlKVzRTSE1XSjQ5SFo1bVc1Y05fRDk3TnczZE5XOWx6eWNiNERWS3NoVzhCWkIyTTVsd19Zblc1eU5zSzc4M1ctdmtXNjVfa3d5M3N6MXpHVzRnbE40ZjNWeEtDYlc4eFpja3k0ZHdQRF9XMWJZeGg0N0hKZmtLVzRWam1jZDItX1h0Ulc0R2hIeTY3WXptLTdXN19jaEJsMlRZd3NGVzdLS2dONDczRzlLdlc2alNzNDQybERkM3lOOEJxU3ltdDR2M1ZWWVZkWHY1bXc0bXhWSzc2LTkyX2xMSG1XM1hrdzhCN3JLc04xVnZxTUoyNS1ydmJ5VzFTeDNWUDkwU0o5TGY3WF82NE0wNCApIGFuZCBQaW5lY29uZSBTZXJ2ZXJsZXNzIChodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzFuM2dWRFlXOHdMS1NSNmxaM2tfVzJMWVNEODZ3WGxiTVZmNjRoNDN6N2JmMVczeTZmYmQ1REpfakJXMzNQMlJyNXpwQndOVzh2bEtaaDNQV1Rzc1c1WDc2ZDExTlpycEJXOE5YNjNNNWg5MzQtTjRLeFktdkxDcDdfVzVkd1JScThqZEM3MlczVmRLVFQyZGJzZjBXMVE4S25zM3NydERuVjh3MzBONjNXN0RKVzNtcDBHdjd2ODRZOFc3V2MxWGo1SHd4NUNXOERCTmxsMm5CRl9GVzZaWWJOMjlrcmNyaFc2NTIzYzMxYzh2N1pXM3JyTWtfNGdubDFwTjdiR3JxVzcxWVlmTjQwcjNXM1JUd0JwVzE1bXFOWTk1dFNSN1c2SGJxY3cxcFJIbjdXMkM3Zmw3OHAwNFZaVzNTSy1zajFwalNWX1c4XzZIbVozMENqTVROMktoWUdWbHctRjJOODUyMkg2YllMenNXNXNONEJxNHQyYzNOZjRoNkpkNDA0ICkgZm9yIHNlYW1sZXNzIHRyYW5zaXRpb25zIHRvIFppbGxpeiBDbG91ZC4NCi0gRmxleGlibGUgUmVwbGljYSBNYW5hZ2VtZW50OiBBZGQgb3IgcmVtb3ZlIHlvdXIgcmVwbGljYXMgaW5zdGFudGx5IHdpdGhvdXQgYW55IHNlcnZpY2UgaW50ZXJydXB0aW9uLiBDaGVjayB0aGUgZG9jIChodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzFuM2dWRFlXOHdMS1NSNmxaM21sVzRGSzR2SDNucWhRd1Z0bWQxYjhMbXZSYlc2S1hyX200NFdycy1ON2pqWjc0SncyMVNXMXNNcVJ3N3RLV1JqVzhHOXR3SjhzN0s4V1cxaHJyd04yTU5CdjFXMTJyV1dSOF9oeWtZVzF6TVp4eDRWZjVnRlc0TkhMVzY2ZkJfdHBXNGNDRF9GMUs5R0hIVko0UzlNM0ZxS2JfVzV4d3F6aDh5c0hSVFc4R2ZMNlM4WDY0ZnFXOTk2azlDNkwwOUpxVzVxc2daVDE2Q3Izd1czSG4tekg1TUJXXzlOOEpZX1EwbURkcXhXMmdfUEhuM0taU1R5VzdyazRjVzJEUjFaY1ZtQmJ5dDNKRGdsOVcxZGpTOHI5MzBRMlpXNDdsRDFNMjAtUlZiVzhTdzZtdDZGLXFWNlc4MWozTXM3WjF4d3pWQmNDaGg0cHlrTkxXMnE3Y0NmN18tN3NDVzZRMGMyOTUxbU1meWY2OE1KLW4wNCApIGZvciBtb3JlIGRldGFpbHMuDQotIFJlZGVzaWduZWQgSW52b2ljZSBQYWdlOiBBIGNsZWFyZXIgdmlldyBvZiB5b3VyIHVzYWdlIGFuZCBjb3N0cyB3aXRoIGRvd25sb2FkIG9wdGlvbnMuDQoNCldlJ3JlIHRoYW5rZnVsIGZvciB5b3VyIGNvbnRpbnVlZCB0cnVzdCBpbiBaaWxsaXogQ2xvdWQgYW5kIGNhbid0IHdhaXQgdG8gc2VlIHdoYXQgeW91IGJ1aWxkIHdpdGggdGhlc2UgbmV3IGZlYXR1cmVzISBBcyBhbHdheXMsIHdlJ2QgbG92ZSB0byBoZWFyIHlvdXIgZmVlZGJhY2sgaW4gb3VyIERpc2NvcmQgY29tbXVuaXR5IChodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzBQM3B5ZDBXN2xDZExXNmxaM21EVzRaa3hQMzhicGhfa1c1dHlubGs4ZFpUQ2xWUFdEbWIzd3BxbHNOMm50TDRHczY0aDJXMlQ1TDdGOTh3ZmNQTjRIVHdmS3dta01ZVzdGX1pGODNQeHE0aFcyVE5DNnY2S0toOFFXMUhQM1dmNHZDREszTjFURlMzTFpiM3A2Vzd3OFNMazgxczRmMVcyTXR0d2ozSloyc1lXNzc4LTdXNExZUk5SVzFXWkJUNjJtVlRTTFc3Z0tDX1czTkhZR25XM0d0TFJXMlhaR0ZCVzk2UnF3TjdQUC1yMlc4MWtjd24ySkszWkZONWdfejdQeUNyNWNXMkNQQndTOFNoLVRDVzJNY1lOcDNDZ2dZU1c5Nk4ydkw0QzljM3NXOF9MbTlLOGY5OWRNVzhXN016YzN5eDBReGY4R1RfTkswNCApIC4NCg0KSGFwcHkgVGhhbmtzZ2l2aW5nIGFuZCBIYXBweSBCdWlsZGluZyEg8J-NgQ0KDQpCZXN0IFJlZ2FyZHMsDQoNClN0ZWZmaSBMaQ0KDQpEaXJlY3RvciBvZiBQcm9kdWN0IE1hcmtldGluZywgWmlsbGl6DQoNCkdpdGh1Yl9pY29uIChodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzBQM3B5ZDBXN2xDZExXNmxaM204VzVGR3RaTTNzalBKTVc5NWw4Q2Y4VjhXMWdXN182NFdLM0t2MVc4TjJ4N2x6MUZNTmtfVzk5S0ZrODhzNmZGVFcybDlqMDM2UktjOUZXNW14XzYwMzJ4MnFqVzVsMDFOazc0TVBzV1c1SjBYeHQ2YzZNUDlWMjI2Q0c5MS1IanpXNk54M3Q2NXpzNnFZTjRqVm5abEtLX1hjVzc1UEZLXzZ3US1nYlcxNHNmaEsybTBkWENXN3BjSlFjNy1MOUd3TjZkWjZCdE5kcl9OVzMxWkJkZDExRERyZ1czX3g2Z3M4eTQ1ZDhWTUp2ZzA3R1JCTnlXOFFXcU1MMnpwSjQ5TjJRX0hLYkNWWmdQVzRkdHl0aDZTMzc4NVc0ZDNacmc0aFhyODVXODgxM1ljNU1RejJLZjU1UkctZDA0ICkNCg0KVHdpdHRlci0yMDIzMTAxOC0xMTExMTAgKGh0dHBzOi8vZDJSTmZQMDQubmExLmh1YnNwb3RsaW5rcy5jb20vQ3RjL0RQKzExMy9kMlJOZlAwNC9WWGZ2U0YzeTZacVlXMzkxR1RtN0Z3Y2wtVzNEbDRTbTVuUVpMSk4yYnBjMTQzcHlkMFc3WTgtUFQ2bFozbUxOOTd4cHRtWG1zVjFON21xc2Z6NE5oRHJOMVdncTJ0X0I0S3hXN0Q1Tnk0MnJIaFZDVzZqaF8wbTE2Um1kalc3QmgxNWcyRFJIQl9XNndmdDgxNEp0dnJRVzFDazIwYzNkQ2pWbFc2blI4c1Y5MHhiMjlXMXlWMzFaOFR5MFBmTjZqQ0tmenFSaDV5VzZ0NHRreTVYanNfWVc0UlMyU3YyODVwSjhWS003aFk1M1ZDWmNXNExiS0tnMTVkYlFKVzNDWTlWUjdHVHNNZ1c2elRzR1g1bm5HMjBXOG40ZDB5MWJQNFRqVzM4UnBrWjZIY0xta1czUmpuVFQ0a3lkeHdXNnh0Vmc5NUgzVDU2VzhLY2pYdjZKTlo1NlZIbTVfNDhyZ1Y4M1cyMkxDU3gxbjBYVG5XM0psUlMzM00zSzRuVzNicnFscjlqclpHcmY0SF8yakMwNCApDQoNCkxpbmtlZGluX2ljb24gKGh0dHBzOi8vZDJSTmZQMDQubmExLmh1YnNwb3RsaW5rcy5jb20vQ3RjL0RQKzExMy9kMlJOZlAwNC9WWGZ2U0YzeTZacVlXMzkxR1RtN0Z3Y2wtVzNEbDRTbTVuUVpMSk4yYnBjMTQzcHlkMFc3WTgtUFQ2bFozcDhXMjIxWndCMlFYS1dZVnQwTHByN3oxUFlSVzVZQkN0OThsNzkwTFcycms3Sy03VzRUU3RXMllKTjNsNTdXamc4VzFWQl9DQjhIdEpIelczQko1WlQ3ZmxxTlNWa0wwVjMxYkduR21XMmtuUzdoNnJwS0g2VzgtandsMjYyYnIzVFZYR3AtczNGQkZMelc1UXlZU3g1Vi1EMFhXMjktVmh4M19OU3ZQVzd0c1Y5eTRWY2NReFc3TDBqV1c0NVc5NjFXMzN6eXpnNjJYZ1BoVzZtUkwxcTFQTDZoNlcxdkhsWVE4azdoOXFXOGwwajN4MWdrcTFwVzZLcm5UQjJLa0Y4M1c1MV9RQ2QyVjlKZm1XMnBrbk1LNU55SnRmVzNOZGhxSDRHNWMwQlZmVFlWMDNwUUYzUlczOFZ6eXk3d3l3a0hXMXE5c0NZNWxmZkJYZjhtTHkzWTA0ICkNCg0KaW5zLTIwMjMxMDE4LTExMTExOCAoaHR0cHM6Ly9kMlJOZlAwNC5uYTEuaHVic3BvdGxpbmtzLmNvbS9DdGMvRFArMTEzL2QyUk5mUDA0L1ZYZnZTRjN5NlpxWVczOTFHVG03RndjbC1XM0RsNFNtNW5RWkxKTjJicGMxNDNweWQwVzdZOC1QVDZsWjNwOVc3cjdTX2s3cjIxc21XNG02V3hxMXJUTUoxVzhkdlIzZDM4YzlKcFcxLXBoQjk4ajZEV3lXNVNzcHBqM2hrLTlHVzN4UGxneDdYMmNiQ1czSzBZN1ozREJYMHJXMl8wQ2J2MXZmc2oxVzJGZlFmVDZMdmpiRlc3bnItTE44M3dWRkxWd3l0cS0yTVh3VjVXNlJZTXRyNUp3Ujh0VzRRZm01XzFSLVZDdFZndGg2aDYwX1RYM1czNmRSMVQyOGhmWmRXNC1ZVkoxMlZnR19WVmw3dFNsOFR6QjFsVzNrVi1jYjcxbS04dlc2bWhDNzI2QjRRc25XNXZ3cHljMjRER1BCVzVsWFJLcDN4VzJiNVc1WWsyc1Y0ajgwTE5XM3ZGeEIxMUtIbld3VzM3Rk5xeDJocUJkblc1bHlNcDgyc2hTMHlXNkw1OVljNW55MnRsZHEwVlFZMDQgKQ0KDQpEaXNjb3JkIChodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzBQM3B5ZDBXN2xDZExXNmxaM2t2VzRNSFhKUDhIWnc1elcyZ1F5X3g4TmZGbVNXMmtnUEd3MlhUTmZaTjR2MmZyWXZHVmRLVzV6c0w3czZKZmRudFc0Vy1zNE0xVzh2Nk1XMThKRjJnNFB0eWtYVzdKMXJzdzJtclJyUlc4MWNUMG0xNlFKQ0hXMVZoU2RXM3RoWFdNVzZOY2s2MTFUcjFNd1c2M3hkU3M5MHpKUUhXOGtjbGdjOEJHa0NHVzJERm5jUjF5MGZMdFc4SjhSbjU1WjRmTm1XMk54NThZMzYweGZ2TTRSczcxRGNrWWhXNk03Y0NNNnFjcmxkVzQwWWNkajI3bUpRNVZNODJTSDR6UlotNFc1eF95TU42UEt0NVRWNWsyMEg2am5NLWhXNmZyMER2OHY0dEJMVzE0ekJGZzN6ODJrRmY0dkdaZEgwNCApDQoNCkxpbmtlZGluLTIwMjMxMDE4LTExMTEwMyAoaHR0cHM6Ly9kMlJOZlAwNC5uYTEuaHVic3BvdGxpbmtzLmNvbS9DdGMvRFArMTEzL2QyUk5mUDA0L1ZYZnZTRjN5NlpxWVczOTFHVG03RndjbC1XM0RsNFNtNW5RWkxKTjJicGMxNDNweWQwVzdZOC1QVDZsWjNwWE44WWdTY1dEZ3kzWFc4YzNTUUI5MF9SeVRXOWZSTlJTM3A0LWJWVzk3dmQ5ZzFmeUg3Qlc2dGR4MlY0WEh5SnNXMnE0SHdoNmQ0S0JOVnZCTno4MXQ1VExCVzkzeHQ2ZzRrd3h6bVc3c3ZxX1A3NlhsTk5XMlpkN3FXNEZuREhkVzJOZG1mTjV2LUhSTlc4d3Z0cUcyMFl5MEZXNE5ETTJCOFdHZ21SVzQ0NFQ1SzNmMTIzWE40NHdRSFlHY3N6ZFczeENNM1I3Z1IwNWxXNU5YZnpzMThqY1YtVjNrMGJXMkxTTG43VzFqUEo3YzJQbnNTSlc4NnQtczA0dGROOFBXMVkwOGMyMlNwWjJ6VzFyWmhCYjczbjNITlc3Q1I3V0c3bThKRHpXNFRnNnJkOFhZSDN2VzJuaFdyLTQ3dzkzVlc0MGd6bHo5MlNQcE1mN2hHeG4wMDQgKQ0KDQpaaWxsaXogSW5jLCAyMDEgUmVkd29vZCBTaG9yZXMgUGt3eSwgU3VpdGUgMzMwLCBSZWR3b29kIENpdHksIENBIDk0MDY1LCBVbml0ZWQgU3RhdGVzDQoNClVuc3Vic2NyaWJlIChodHRwczovL2hzLTI0MDU0ODI4LnMuaHVic3BvdGVtYWlsLm5ldC9ocy9wcmVmZXJlbmNlcy1jZW50ZXIvZW4vZGlyZWN0P2RhdGE9VzJuWFMtTjMwaC1CY1cySEZWcXA0Y0tkOXdXM2JyTU5MMzJsSlZuVzN6MUpOVzNDOU5SYlcyQ0Z0Qm0zMnNYQktXNDFWOHlIMUJOeVlHVzJLQktHNDJQTms3a1czajYyUGczemR5SjFXMjE3eWRKMjJUTjBwVzItQmRCcTMycXNjWVcxUXJsOXozNkI3UVZXM2gtQjVfM1hOLVYxVzJ0MDQySDJXSF9oLVczMDZTeTc0M1FmMkZXM0NqMjhCMVZ4bGNjVzNIZEd5ZzMyZy1NNlc0M0YxNW0zTEdZcmJXMnFNeTRTNGNzMnkzVzNOWFdjdDFaZzdKaFc0M1h4eUg0aEtqZzVXM1A1dktiNHREeGhaVzRjbEpWXzJNQ1I4TFczOGNSWTIycjE1Sk1XMnNGdDB2MjUyclc1VzFMRnlXMDJSdjhjM1czRE1LN0Q0M0doanJXMUJ2X2czMnZ5RmxTVzQzcVNRYjNTSFkyX1cyMWxmZjg0ZkxnRGRXMlRoWFc4NDFZN19MVzFfanNaSzM4M3RxSFczZ25tUFgxVnk4LWpXNGtNOU1MMzBLM19KVzFWYlJDLTJUUzdmbVczX3MzUkc0bXEyOTZXM2Q5a0pDM3prdnZ4VzIyV3F6cDQ1TXlXWFcyQ01IcFozMExsU0tXNGt0NlF2M1FWRjNNVzJSal9kVjFMOE43R1czanItZkQycDB0MjFXMnAza3RrMzBEU2pxVzFRM01MdjJIRng1LVc0cnBmTFEyMzFXWWpXM19weC1HNHJmS2NsVzRmdFpTdDFCcVRaRzAmX2hzZW5jPXAyQU5xdHotOHBwOWlUWVBxSkxkV1lYQWxUSmdpTnlqMk4wTkY2cmdXaEtvbWwtU1lMcGxNSFdDb2I0czJUMUp4bXJfLVd2cGZ0d1UyRl9wLVRTclZ6ZjhYUEwyTlJwRXdDb2cmX2hzbWk9MzM1MjU2NTk1ICkNCk1hbmFnZSBwcmVmZXJlbmNlcyAoaHR0cHM6Ly9ocy0yNDA1NDgyOC5zLmh1YnNwb3RlbWFpbC5uZXQvaHMvcHJlZmVyZW5jZXMtY2VudGVyL2VuL3BhZ2U_ZGF0YT1XMm5YUy1OMzBoLUJjVzJIRlZxcDRjS2Q5d1czYnJNTkwzMmxKVm5XM3oxSk5XM0M5TlJiVzJDRnRCbTMyc1hCS1c0MVY4eUgxQk55WUdXMktCS0c0MlBOazdrVzNqNjJQZzN6ZHlKMVcyMTd5ZEoyMlROMHBXMi1CZEJxMzJxc2NZVzFRcmw5ejM2QjdRVlczaC1CNV8zWE4tVjFXMnQwNDJIMldIX2gtVzMwNlN5NzQzUWYyRlczQ2oyOEIxVnhsY2NXM0hkR3lnMzJnLU02VzQzRjE1bTNMR1lyYlcycU15NFM0Y3MyeTNXM05YV2N0MVpnN0poVzQzWHh5SDRoS2pnNVczUDV2S2I0dER4aFpXNGNsSlZfMk1DUjhMVzM4Y1JZMjJyMTVKTVcyc0Z0MHYyNTJyVzVXMUxGeVcwMlJ2OGMzVzNETUs3RDQzR2hqclcxQnZfZzMydnlGbFNXNDNxU1FiM1NIWTJfVzIxbGZmODRmTGdEZFcyVGhYVzg0MVk3X0xXMV9qc1pLMzgzdHFIVzNnbm1QWDFWeTgtalc0a005TUwzMEszX0pXMVZiUkMtMlRTN2ZtVzNfczNSRzRtcTI5NlczZDlrSkMzemt2dnhXMjJXcXpwNDVNeVdYVzJDTUhwWjMwTGxTS1c0a3Q2UXYzUVZGM01XMlJqX2RWMUw4TjdHVzNqci1mRDJwMHQyMVcycDNrdGszMERTanFXMVEzTUx2MkhGeDUtVzRycGZMUTIzMVdZalczX3B4LUc0cmZLY2xXNGZ0WlN0MUJxVFpHMCZfaHNlbmM9cDJBTnF0ei04cHA5aVRZUHFKTGRXWVhBbFRKZ2lOeWoyTjBORjZyZ1doS29tbC1TWUxwbE1IV0NvYjRzMlQxSnhtcl8tV3ZwZnR3VTJGX3AtVFNyVnpmOFhQTDJOUnBFd0NvZyZfaHNtaT0zMzUyNTY1OTUgKQ==" - } - }, - { - "partId": "1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=\"utf-8\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 39340, - "data": "PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgVHJhbnNpdGlvbmFsIC8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9UUi94aHRtbDEvRFREL3hodG1sMS10cmFuc2l0aW9uYWwuZHRkIj48aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgeG1sbnM6bz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6b2ZmaWNlIiB4bWxuczp2PSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnZtbCIgbGFuZz0iZW4iPjxoZWFkPg0KICAgIDx0aXRsZT7wn6aDIFppbGxpeiBDbG91ZCBOb3ZlbWJlciBVcGRhdGU6IE11Y2ggdG8gYmUgVGhhbmtmdWwgRm9yITwvdGl0bGU-DQogICAgPG1ldGEgcHJvcGVydHk9Im9nOnRpdGxlIiBjb250ZW50PSLwn6aDIFppbGxpeiBDbG91ZCBOb3ZlbWJlciBVcGRhdGU6IE11Y2ggdG8gYmUgVGhhbmtmdWwgRm9yISI-DQogICAgPG1ldGEgbmFtZT0idHdpdHRlcjp0aXRsZSIgY29udGVudD0i8J-mgyBaaWxsaXogQ2xvdWQgTm92ZW1iZXIgVXBkYXRlOiBNdWNoIHRvIGJlIFRoYW5rZnVsIEZvciEiPg0KICAgIA0KICAgIA0KICAgIA0KPG1ldGEgbmFtZT0ieC1hcHBsZS1kaXNhYmxlLW1lc3NhZ2UtcmVmb3JtYXR0aW5nIj4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04Ij4NCjxtZXRhIGh0dHAtZXF1aXY9IlgtVUEtQ29tcGF0aWJsZSIgY29udGVudD0iSUU9ZWRnZSI-DQo8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI-DQogICAgPCEtLVtpZiBndGUgbXNvIDldPg0KICA8eG1sPg0KICAgICAgPG86T2ZmaWNlRG9jdW1lbnRTZXR0aW5ncz4NCiAgICAgIDxvOkFsbG93UE5HLz4NCiAgICAgIDxvOlBpeGVsc1BlckluY2g-OTY8L286UGl4ZWxzUGVySW5jaD4NCiAgICAgIDwvbzpPZmZpY2VEb2N1bWVudFNldHRpbmdzPg0KICA8L3htbD4NCiAgDQogIDxzdHlsZT4NCiAgICB1bCA-IGxpIHsNCiAgICAgIHRleHQtaW5kZW50OiAtMWVtOw0KICAgIH0NCiAgPC9zdHlsZT4NCjwhW2VuZGlmXS0tPg0KPCEtLVtpZiBtc29dPg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCiBib2R5LCB0ZCB7Zm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7fQ0KIC5oc2UtYm9keS13cmFwcGVyLXRhYmxlIHtiYWNrZ3JvdW5kLWNvbG9yOiAjRUFGMEY2O30NCjwvc3R5bGU-DQo8IVtlbmRpZl0tLT4NCiAgICANCiAgICAgIA0KICANCiAgICANCiAgPG1ldGEgbmFtZT0iZ2VuZXJhdG9yIiBjb250ZW50PSJIdWJTcG90Ij48bWV0YSBwcm9wZXJ0eT0ib2c6dXJsIiBjb250ZW50PSJodHRwOi8vMjQwNTQ4MjguaHMtc2l0ZXMuY29tLy10ZW1wb3Jhcnktc2x1Zy01NmE2NDdiYi03MmRlLTQ1YjktYTlkNy1lZTE2NTNkMmVkNWIiPjxtZXRhIG5hbWU9InJvYm90cyIgY29udGVudD0ibm9pbmRleCxmb2xsb3ciPjwhLS1baWYgISgobXNvKXwoSUUpKV0-PCEtLSAtLT48c3R5bGUgdHlwZT0idGV4dC9jc3MiPkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDo2MzlweCl7aW1nLnN0cmV0Y2gtb24tbW9iaWxlLC5oc19yc3NfZW1haWxfZW50cmllc190YWJsZSBpbWcsLmhzLXN0cmV0Y2gtY3RhIC5ocy1jdGEtaW1ne2hlaWdodDphdXRvICFpbXBvcnRhbnQ7d2lkdGg6MTAwJSAhaW1wb3J0YW50fQ0KLmRpc3BsYXlfYmxvY2tfb25fc21hbGxfc2NyZWVuc3tkaXNwbGF5OmJsb2NrfS5oc19wYWRkZWR7cGFkZGluZy1sZWZ0OjIwcHggIWltcG9ydGFudDtwYWRkaW5nLXJpZ2h0OjIwcHggIWltcG9ydGFudH0NCi5ocy1obSx0YWJsZS5ocy1obXtkaXNwbGF5Om5vbmV9LmhzLWhke2Rpc3BsYXk6YmxvY2sgIWltcG9ydGFudH10YWJsZS5ocy1oZHtkaXNwbGF5OnRhYmxlICFpbXBvcnRhbnR9DQp9Lm1vei10ZXh0LWh0bWwgLmhzZS1jb2x1bW4tY29udGFpbmVye21heC13aWR0aDo2MDBweCAhaW1wb3J0YW50O3dpZHRoOjYwMHB4ICFpbXBvcnRhbnR9DQoubW96LXRleHQtaHRtbCAuaHNlLWNvbHVtbntkaXNwbGF5OnRhYmxlLWNlbGw7dmVydGljYWwtYWxpZ246dG9wfS5tb3otdGV4dC1odG1sIC5oc2Utc2VjdGlvbiAuaHNlLXNpemUtMTJ7bWF4LXdpZHRoOjYwMHB4ICFpbXBvcnRhbnQ7d2lkdGg6NjAwcHggIWltcG9ydGFudH0NCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1pbi13aWR0aDo2NDBweCl7LmhzZS1jb2x1bW4tY29udGFpbmVye21heC13aWR0aDo2MDBweCAhaW1wb3J0YW50O3dpZHRoOjYwMHB4ICFpbXBvcnRhbnR9DQouaHNlLWNvbHVtbntkaXNwbGF5OnRhYmxlLWNlbGw7dmVydGljYWwtYWxpZ246dG9wfS5oc2Utc2VjdGlvbiAuaHNlLXNpemUtMTJ7bWF4LXdpZHRoOjYwMHB4ICFpbXBvcnRhbnQ7d2lkdGg6NjAwcHggIWltcG9ydGFudH0NCn1AbWVkaWEgb25seSBzY3JlZW4gYW5kIChtYXgtd2lkdGg6NjM5cHgpe3VsLGJsb2NrcXVvdGV7bWFyZ2luOjA7cGFkZGluZzoxZW0gNDBweH0NCn1AbWVkaWEgc2NyZWVuIGFuZCAobWF4LXdpZHRoOjYzOXB4KXsuc29jaWFsLW5ldHdvcmstY2VsbHtkaXNwbGF5OmlubGluZS1ibG9ja30gfTwvc3R5bGU-PCEtLTwhW2VuZGlmXS0tPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI-I2hzX2JvZHkgI2hzX2Nvc193cmFwcGVyX21haW4gYVt4LWFwcGxlLWRhdGEtZGV0ZWN0b3JzXXtjb2xvcjppbmhlcml0ICFpbXBvcnRhbnQ7dGV4dC1kZWNvcmF0aW9uOm5vbmUgIWltcG9ydGFudDtmb250LXNpemU6aW5oZXJpdCAhaW1wb3J0YW50O2ZvbnQtZmFtaWx5OmluaGVyaXQgIWltcG9ydGFudDtmb250LXdlaWdodDppbmhlcml0ICFpbXBvcnRhbnQ7bGluZS1oZWlnaHQ6aW5oZXJpdCAhaW1wb3J0YW50fQ0KYXt0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lfXB7bWFyZ2luOjB9Ym9keXstbXMtdGV4dC1zaXplLWFkanVzdDoxMDAlOy13ZWJraXQtdGV4dC1zaXplLWFkanVzdDoxMDAlOy13ZWJraXQtZm9udC1zbW9vdGhpbmc6YW50aWFsaWFzZWQ7bW96LW9zeC1mb250LXNtb290aGluZzpncmF5c2NhbGV9DQp0YWJsZXtib3JkZXItc3BhY2luZzowO21zby10YWJsZS1sc3BhY2U6MDttc28tdGFibGUtcnNwYWNlOjB9dGFibGUsdGR7Ym9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlfQ0KaW1ney1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6YmljdWJpY31wLGEsbGksdGQsYmxvY2txdW90ZXttc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5fTwvc3R5bGU-PC9oZWFkPg0KICA8Ym9keSBpZD0iaHNfYm9keSIgYmdjb2xvcj0iI0VBRjBGNiIgc3R5bGU9Im1hcmdpbjowICFpbXBvcnRhbnQ7IHBhZGRpbmc6MCAhaW1wb3J0YW50OyBmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZCI-DQogICAgPGRpdiBpZD0icHJldmlld190ZXh0IiBzdHlsZT0iZGlzcGxheTpub25lO2ZvbnQtc2l6ZToxcHg7Y29sb3I6I0VBRjBGNjtsaW5lLWhlaWdodDoxcHg7bWF4LWhlaWdodDowcHg7bWF4LXdpZHRoOjBweDtvcGFjaXR5OjA7b3ZlcmZsb3c6aGlkZGVuOyIgbGFuZz0iZW4iPkZlYXN0IHlvdXIgZXllcyBvbiBvdXIgY29tcGxldGVseSByZWRlc2lnbmVkIHdlYiBjb25zb2xlLCBwbHVzIGV4cGFuZGVkIG1pZ3JhdGlvbiBvcHRpb25zIGFuZCBtb3JlLi4uPC9kaXY-DQogICAgDQo8IS0tW2lmIGd0ZSBtc28gOV0-DQo8djpiYWNrZ3JvdW5kIHhtbG5zOnY9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206dm1sIiBmaWxsPSJ0Ij4NCiAgICA8djpmaWxsIHR5cGU9InRpbGUiIHNpemU9IjEwMCUsMTAwJSIgY29sb3I9IiNmZmZmZmYiLz4NCjwvdjpiYWNrZ3JvdW5kPg0KPCFbZW5kaWZdLS0-DQogICAgPGRpdiBjbGFzcz0iaHNlLWJvZHktYmFja2dyb3VuZCIgbGFuZz0iZW4iIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlYWYwZjYiIGJnY29sb3I9IiNlYWYwZjYiPg0KICAgICAgPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgY2xhc3M9ImhzZS1ib2R5LXdyYXBwZXItdGFibGUiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9Im1hcmdpbjowOyBwYWRkaW5nOjA7IHdpZHRoOjEwMCUgIWltcG9ydGFudDsgbWluLXdpZHRoOjMyMHB4ICFpbXBvcnRhbnQ7IGhlaWdodDoxMDAlICFpbXBvcnRhbnQiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiPg0KICAgICAgICA8dGJvZHk-PHRyPg0KICAgICAgICAgIDx0ZCBjbGFzcz0iaHNlLWJvZHktd3JhcHBlci10ZCIgdmFsaWduPSJ0b3AiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZDsgcGFkZGluZy10b3A6MjBweDsgcGFkZGluZy1ib3R0b206MjBweCI-DQogICAgICAgICAgICA8ZGl2IGlkPSJoc19jb3Nfd3JhcHBlcl9tYWluIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfZG5kX2FyZWEiIHN0eWxlPSJjb2xvcjogaW5oZXJpdDsgZm9udC1zaXplOiBpbmhlcml0OyBsaW5lLWhlaWdodDogaW5oZXJpdDsiIGRhdGEtaHMtY29zLWdlbmVyYWwtdHlwZT0id2lkZ2V0IiBkYXRhLWhzLWNvcy10eXBlPSJkbmRfYXJlYSI-ICA8ZGl2IGlkPSJzZWN0aW9uLTAiIGNsYXNzPSJoc2Utc2VjdGlvbiBoc2Utc2VjdGlvbi1maXJzdCIgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyBwYWRkaW5nLXJpZ2h0OjEwcHgiPg0KICAgIA0KICAgIA0KICAgIDwhLS1baWYgISgobXNvKXwoSUUpKV0-PCEtLSAtLT4NCiAgICAgIDxkaXYgY2xhc3M9ImhzZS1jb2x1bW4tY29udGFpbmVyIiBzdHlsZT0ibWluLXdpZHRoOjI4MHB4OyBtYXgtd2lkdGg6NjAwcHg7IE1hcmdpbi1sZWZ0OmF1dG87IE1hcmdpbi1yaWdodDphdXRvOyBiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmY7IHBhZGRpbmctYm90dG9tOjEwcHgiIGJnY29sb3I9IiNmZmZmZmYiPg0KICAgIDwhLS08IVtlbmRpZl0tLT4NCiAgICANCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7bWF4LXdpZHRoOjYwMHB4O3dpZHRoOjEwMCU7TWFyZ2luLWxlZnQ6YXV0bztNYXJnaW4tcmlnaHQ6YXV0bzsiPg0KICAgICAgPHRhYmxlIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDo2MDBweDsiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNjAwIiBiZ2NvbG9yPSIjZmZmZmZmIj4NCiAgICAgIDx0ciBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmOyI-DQogICAgPCFbZW5kaWZdLS0-DQogICAgPCEtLVtpZiAobXNvKXwoSUUpXT4NCiAgPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0id2lkdGg6NjAwcHg7cGFkZGluZy1ib3R0b206MTBweDsiPg0KPCFbZW5kaWZdLS0-DQo8IS0tW2lmIGd0ZSBtc28gOV0-DQogIDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSI2MDAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9IndpZHRoOjYwMHB4Ij4NCjwhW2VuZGlmXS0tPg0KPGRpdiBpZD0iY29sdW1uLTAtMCIgY2xhc3M9ImhzZS1jb2x1bW4gaHNlLXNpemUtMTIiPg0KICA8ZGl2IGlkPSJoc19jb3Nfd3JhcHBlcl9tb2R1bGUtMC0wLTAiIGNsYXNzPSJoc19jb3Nfd3JhcHBlciBoc19jb3Nfd3JhcHBlcl93aWRnZXQgaHNfY29zX3dyYXBwZXJfdHlwZV9tb2R1bGUiIHN0eWxlPSJjb2xvcjogaW5oZXJpdDsgZm9udC1zaXplOiBpbmhlcml0OyBsaW5lLWhlaWdodDogaW5oZXJpdDsiIGRhdGEtaHMtY29zLWdlbmVyYWwtdHlwZT0id2lkZ2V0IiBkYXRhLWhzLWNvcy10eXBlPSJtb2R1bGUiPjx0YWJsZSBjbGFzcz0iaHNlLWltYWdlLXdyYXBwZXIiIHJvbGU9InByZXNlbnRhdGlvbiIgd2lkdGg9IjEwMCUiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI-DQogIDx0Ym9keT4NCiAgICA8dHI-DQogICAgICA8dGQgYWxpZ249ImNlbnRlciIgdmFsaWduPSJ0b3AiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgY29sb3I6IzIzNDk2ZDsgd29yZC1icmVhazpicmVhay13b3JkOyB0ZXh0LWFsaWduOmNlbnRlcjsgcGFkZGluZzowcHg7IGZvbnQtc2l6ZTowcHgiPg0KICAgICAgICA8aW1nIGFsdD0iaGVhZGVyIiBzcmM9Imh0dHBzOi8vaHMtMjQwNTQ4MjguZi5odWJzcG90ZW1haWwubmV0L2h1Yi8yNDA1NDgyOC9odWJmcy9oZWFkZXIucG5nP3dpZHRoPTEyMDAmYW1wO3Vwc2NhbGU9dHJ1ZSZhbXA7bmFtZT1oZWFkZXIucG5nIiBzdHlsZT0ib3V0bGluZTpub25lOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgbWF4LXdpZHRoOjEwMCU7IGZvbnQtc2l6ZToxNnB4IiB3aWR0aD0iNjAwIiBhbGlnbj0ibWlkZGxlIj4NCiAgICAgIDwvdGQ-DQogICAgPC90cj4NCiAgPC90Ym9keT4NCjwvdGFibGU-PC9kaXY-DQo8L2Rpdj4NCjwhLS1baWYgZ3RlIG1zbyA5XT48L3RhYmxlPjwhW2VuZGlmXS0tPg0KPCEtLVtpZiAobXNvKXwoSUUpXT48L3RkPjwhW2VuZGlmXS0tPg0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPg0KICAgIDwvZGl2Pg0KICAgDQogIDwvZGl2Pg0KICA8ZGl2IGlkPSJtb2R1bGVfMTY4OTg4OTc2NDI5NSIgY2xhc3M9ImhzZS1zZWN0aW9uIiBzdHlsZT0icGFkZGluZy1sZWZ0OjEwcHg7IHBhZGRpbmctcmlnaHQ6MTBweCI-DQogICAgDQogICAgDQogICAgPCEtLVtpZiAhKChtc28pfChJRSkpXT48IS0tIC0tPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7IG1heC13aWR0aDo2MDBweDsgTWFyZ2luLWxlZnQ6YXV0bzsgTWFyZ2luLXJpZ2h0OmF1dG87IGJhY2tncm91bmQtY29sb3I6I2ZmZmZmZiIgYmdjb2xvcj0iI2ZmZmZmZiI-DQogICAgPCEtLTwhW2VuZGlmXS0tPg0KICAgIA0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-DQogICAgICA8ZGl2IGNsYXNzPSJoc2UtY29sdW1uLWNvbnRhaW5lciIgc3R5bGU9Im1pbi13aWR0aDoyODBweDttYXgtd2lkdGg6NjAwcHg7d2lkdGg6MTAwJTtNYXJnaW4tbGVmdDphdXRvO01hcmdpbi1yaWdodDphdXRvOyI-DQogICAgICA8dGFibGUgYWxpZ249ImNlbnRlciIgc3R5bGU9IndpZHRoOjYwMHB4OyIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSI2MDAiIGJnY29sb3I9IiNmZmZmZmYiPg0KICAgICAgPHRyIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmY7Ij4NCiAgICA8IVtlbmRpZl0tLT4NCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICA8dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJ3aWR0aDo2MDBweDsiPg0KPCFbZW5kaWZdLS0-DQo8IS0tW2lmIGd0ZSBtc28gOV0-DQogIDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSI2MDAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9IndpZHRoOjYwMHB4Ij4NCjwhW2VuZGlmXS0tPg0KPGRpdiBpZD0ibW9kdWxlXzE2ODk4ODk3NjQyOTVfMCIgY2xhc3M9ImhzZS1jb2x1bW4gaHNlLXNpemUtMTIiPg0KICA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHdpZHRoPSIxMDAlIj48dGJvZHk-PHRyPjx0ZCBjbGFzcz0iaHNfcGFkZGVkIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxNXB4OyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IHBhZGRpbmc6MTBweCAzMHB4Ij48ZGl2IGlkPSJoc19jb3Nfd3JhcHBlcl9tb2R1bGVfMTY4OTg4OTc2NDI1ODMiIGNsYXNzPSJoc19jb3Nfd3JhcHBlciBoc19jb3Nfd3JhcHBlcl93aWRnZXQgaHNfY29zX3dyYXBwZXJfdHlwZV9tb2R1bGUiIHN0eWxlPSJjb2xvcjogaW5oZXJpdDsgZm9udC1zaXplOiBpbmhlcml0OyBsaW5lLWhlaWdodDogaW5oZXJpdDsiIGRhdGEtaHMtY29zLWdlbmVyYWwtdHlwZT0id2lkZ2V0IiBkYXRhLWhzLWNvcy10eXBlPSJtb2R1bGUiPjxkaXYgaWQ9ImhzX2Nvc193cmFwcGVyX21vZHVsZV8xNjg5ODg5NzY0MjU4M18iIGNsYXNzPSJoc19jb3Nfd3JhcHBlciBoc19jb3Nfd3JhcHBlcl93aWRnZXQgaHNfY29zX3dyYXBwZXJfdHlwZV9yaWNoX3RleHQiIHN0eWxlPSJjb2xvcjogaW5oZXJpdDsgZm9udC1zaXplOiBpbmhlcml0OyBsaW5lLWhlaWdodDogaW5oZXJpdDsiIGRhdGEtaHMtY29zLWdlbmVyYWwtdHlwZT0id2lkZ2V0IiBkYXRhLWhzLWNvcy10eXBlPSJyaWNoX3RleHQiPjxwIHN0eWxlPSJtc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyBsaW5lLWhlaWdodDoxNzUlIj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij48c3BhbiBzdHlsZT0iY29sb3I6ICMyMzQ5NmQ7Ij5IZWxsbyw8L3NwYW4-PC9zcGFuPjwvcD4NCjxwIHN0eWxlPSJtc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyBsaW5lLWhlaWdodDoxNzUlIj4mbmJzcDs8L3A-DQo8cCBzdHlsZT0ibXNvLWxpbmUtaGVpZ2h0LXJ1bGU6ZXhhY3RseTsgbGluZS1oZWlnaHQ6MTc1JSI-QXMgd2UgZ2F0aGVyIHRvIGNlbGVicmF0ZSBUaGFua3NnaXZpbmcgaW4gdGhlIFVTLCB3ZSdyZSBlc3BlY2lhbGx5IGdyYXRlZnVsIGZvciBvdXIgdmlicmFudCBjb21tdW5pdHkgYW5kIGV4Y2l0ZWQgdG8gc2hhcmUgb3VyIGxhdGVzdCB1cGRhdGVzISBUaGlzIE5vdmVtYmVyLCB3ZSdyZSBzZXJ2aW5nIHVwIGEgY29tcGxldGVseSByZWRlc2lnbmVkIGV4cGVyaWVuY2UgdGhhdCB3aWxsIHRyYW5zZm9ybSBob3cgeW91IGludGVyYWN0IHdpdGggWmlsbGl6IENsb3VkLiBMZXQncyBkaXZlIGludG8gd2hhdCdzIGNvb2tpbmc6PC9wPjwvZGl2PjwvZGl2PjwvdGQ-PC90cj48L3Rib2R5PjwvdGFibGU-DQo8L2Rpdj4NCjwhLS1baWYgZ3RlIG1zbyA5XT48L3RhYmxlPjwhW2VuZGlmXS0tPg0KPCEtLVtpZiAobXNvKXwoSUUpXT48L3RkPjwhW2VuZGlmXS0tPg0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPg0KICAgIDwvZGl2Pg0KICAgDQogIDwvZGl2Pg0KICA8ZGl2IGlkPSJtb2R1bGVfMTY4MjU1NzEyOTIzOCIgY2xhc3M9ImhzZS1zZWN0aW9uIiBzdHlsZT0icGFkZGluZy1sZWZ0OjEwcHg7IHBhZGRpbmctcmlnaHQ6MTBweCI-DQogICAgDQogICAgDQogICAgPCEtLVtpZiAhKChtc28pfChJRSkpXT48IS0tIC0tPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7IG1heC13aWR0aDo2MDBweDsgTWFyZ2luLWxlZnQ6YXV0bzsgTWFyZ2luLXJpZ2h0OmF1dG87IGJhY2tncm91bmQtY29sb3I6I2ZmZmZmZiIgYmdjb2xvcj0iI2ZmZmZmZiI-DQogICAgPCEtLTwhW2VuZGlmXS0tPg0KICAgIA0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-DQogICAgICA8ZGl2IGNsYXNzPSJoc2UtY29sdW1uLWNvbnRhaW5lciIgc3R5bGU9Im1pbi13aWR0aDoyODBweDttYXgtd2lkdGg6NjAwcHg7d2lkdGg6MTAwJTtNYXJnaW4tbGVmdDphdXRvO01hcmdpbi1yaWdodDphdXRvOyI-DQogICAgICA8dGFibGUgYWxpZ249ImNlbnRlciIgc3R5bGU9IndpZHRoOjYwMHB4OyIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSI2MDAiIGJnY29sb3I9IiNmZmZmZmYiPg0KICAgICAgPHRyIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmY7Ij4NCiAgICA8IVtlbmRpZl0tLT4NCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICA8dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJ3aWR0aDo2MDBweDsiPg0KPCFbZW5kaWZdLS0-DQo8IS0tW2lmIGd0ZSBtc28gOV0-DQogIDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSI2MDAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9IndpZHRoOjYwMHB4Ij4NCjwhW2VuZGlmXS0tPg0KPGRpdiBpZD0ibW9kdWxlXzE2ODI1NTcxMjkyMzhfMCIgY2xhc3M9ImhzZS1jb2x1bW4gaHNlLXNpemUtMTIiPg0KICA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHdpZHRoPSIxMDAlIj48dGJvZHk-PHRyPjx0ZCBjbGFzcz0iaHNfcGFkZGVkIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxNXB4OyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IHBhZGRpbmc6MTBweCAzMHB4Ij48ZGl2IGlkPSJoc19jb3Nfd3JhcHBlcl9tb2R1bGVfMTY4MjU1NzEyOTIxMTEiIGNsYXNzPSJoc19jb3Nfd3JhcHBlciBoc19jb3Nfd3JhcHBlcl93aWRnZXQgaHNfY29zX3dyYXBwZXJfdHlwZV9tb2R1bGUiIHN0eWxlPSJjb2xvcjogaW5oZXJpdDsgZm9udC1zaXplOiBpbmhlcml0OyBsaW5lLWhlaWdodDogaW5oZXJpdDsiIGRhdGEtaHMtY29zLWdlbmVyYWwtdHlwZT0id2lkZ2V0IiBkYXRhLWhzLWNvcy10eXBlPSJtb2R1bGUiPjxkaXYgaWQ9ImhzX2Nvc193cmFwcGVyX21vZHVsZV8xNjgyNTU3MTI5MjExMV8iIGNsYXNzPSJoc19jb3Nfd3JhcHBlciBoc19jb3Nfd3JhcHBlcl93aWRnZXQgaHNfY29zX3dyYXBwZXJfdHlwZV9yaWNoX3RleHQiIHN0eWxlPSJjb2xvcjogaW5oZXJpdDsgZm9udC1zaXplOiBpbmhlcml0OyBsaW5lLWhlaWdodDogaW5oZXJpdDsiIGRhdGEtaHMtY29zLWdlbmVyYWwtdHlwZT0id2lkZ2V0IiBkYXRhLWhzLWNvcy10eXBlPSJyaWNoX3RleHQiPjxwIHN0eWxlPSJtc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyBsaW5lLWhlaWdodDoxNzUlIj7wn46oIDxzcGFuIHN0eWxlPSJmb250LXdlaWdodDogYm9sZDsiPkZyZXNoICZhbXA7IE1vZGVybiBXZWIgQ29uc29sZTogPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LXdlaWdodDogbm9ybWFsOyI-V2UndmUgY29tcGxldGVseSByZWltYWdpbmVkIG91ciB3ZWIgY29uc29sZSBpbnRlcmZhY2UsIGJyaW5naW5nIHlvdSBhIG1vcmUgaW50dWl0aXZlIGFuZCB2aXN1YWxseSBhcHBlYWxpbmcgZXhwZXJpZW5jZTo8L3NwYW4-PHNwYW4gc3R5bGU9ImZvbnQtd2VpZ2h0OiBib2xkOyI-PGJyPjwvc3Bhbj48L3A-DQo8dWwgc3R5bGU9Im1zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7IGxpbmUtaGVpZ2h0OjE3NSUiPg0KPGxpIGFyaWEtbGV2ZWw9IjEiPjxzdHJvbmc-UmVkZXNpZ25lZCBOYXZpZ2F0aW9uOjwvc3Ryb25nPiBTdHJlYW1saW5lZCBtZW51IHN0cnVjdHVyZSBzZXBhcmF0aW5nIG9yZ2FuaXphdGlvbiBhbmQgcHJvamVjdCBsZXZlbHMgZm9yIGNsZWFyZXIgbmF2aWdhdGlvbiBwYXRocyBhbmQgaW1wcm92ZWQgZmVhdHVyZSBkaXNjb3ZlcmFiaWxpdHkuPC9saT4NCjxsaSBhcmlhLWxldmVsPSIxIj48c3Ryb25nPkNhcmQtQmFzZWQgRGVzaWduOjwvc3Ryb25nPiBSZXBsYWNlZCB0YWJsZSBsYXlvdXRzIHdpdGggb3JnYW5pemVkIGNhcmQgdmlld3MgZm9yIGJldHRlciBpbmZvcm1hdGlvbiBoaWVyYXJjaHkgYW5kIHJlZHVjZWQgdmlzdWFsIGNvbXBsZXhpdHkuPC9saT4NCjxsaSBhcmlhLWxldmVsPSIxIj48c3Ryb25nPkNvbnNpc3RlbnQgTGF5b3V0IFN5c3RlbTo8L3N0cm9uZz4gU3RhbmRhcmRpemVkIGdyaWQgc3lzdGVtIGFjcm9zcyBhbGwgcGFnZXMgZm9yIG1vcmUgaW50dWl0aXZlIGZlYXR1cmUgYWNjZXNzIGFuZCByZWR1Y2VkIGNvZ25pdGl2ZSBsb2FkLjwvbGk-DQo8L3VsPg0KPHAgc3R5bGU9Im1zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7IGxpbmUtaGVpZ2h0OjE3NSUiPkNoZWNrIG91dCB0aGUgbmV3IGxvb2shIPCfkYc8L3A-PC9kaXY-PC9kaXY-PC90ZD48L3RyPjwvdGJvZHk-PC90YWJsZT4NCjwvZGl2Pg0KPCEtLVtpZiBndGUgbXNvIDldPjwvdGFibGU-PCFbZW5kaWZdLS0-DQo8IS0tW2lmIChtc28pfChJRSldPjwvdGQ-PCFbZW5kaWZdLS0-DQogICAgPCEtLVtpZiAobXNvKXwoSUUpXT48L3RyPjwvdGFibGU-PCFbZW5kaWZdLS0-DQogICAgPC9kaXY-DQogICANCiAgPC9kaXY-DQogIDxkaXYgaWQ9Im1vZHVsZV8xNjg5ODg5Mjc4ODg3IiBjbGFzcz0iaHNlLXNlY3Rpb24iIHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBweDsgcGFkZGluZy1yaWdodDoxMHB4Ij4NCiAgICANCiAgICANCiAgICA8IS0tW2lmICEoKG1zbyl8KElFKSldPjwhLS0gLS0-DQogICAgICA8ZGl2IGNsYXNzPSJoc2UtY29sdW1uLWNvbnRhaW5lciIgc3R5bGU9Im1pbi13aWR0aDoyODBweDsgbWF4LXdpZHRoOjYwMHB4OyBNYXJnaW4tbGVmdDphdXRvOyBNYXJnaW4tcmlnaHQ6YXV0bzsgYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmIiBiZ2NvbG9yPSIjZmZmZmZmIj4NCiAgICA8IS0tPCFbZW5kaWZdLS0-DQogICAgDQogICAgPCEtLVtpZiAobXNvKXwoSUUpXT4NCiAgICAgIDxkaXYgY2xhc3M9ImhzZS1jb2x1bW4tY29udGFpbmVyIiBzdHlsZT0ibWluLXdpZHRoOjI4MHB4O21heC13aWR0aDo2MDBweDt3aWR0aDoxMDAlO01hcmdpbi1sZWZ0OmF1dG87TWFyZ2luLXJpZ2h0OmF1dG87Ij4NCiAgICAgIDx0YWJsZSBhbGlnbj0iY2VudGVyIiBzdHlsZT0id2lkdGg6NjAwcHg7IiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgd2lkdGg9IjYwMCIgYmdjb2xvcj0iI2ZmZmZmZiI-DQogICAgICA8dHIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2ZmZmZmZjsiPg0KICAgIDwhW2VuZGlmXS0tPg0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-DQogIDx0ZCB2YWxpZ249InRvcCIgc3R5bGU9IndpZHRoOjYwMHB4OyI-DQo8IVtlbmRpZl0tLT4NCjwhLS1baWYgZ3RlIG1zbyA5XT4NCiAgPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgd2lkdGg9IjYwMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBzdHlsZT0id2lkdGg6NjAwcHgiPg0KPCFbZW5kaWZdLS0-DQo8ZGl2IGlkPSJtb2R1bGVfMTY4OTg4OTI3ODg4N18wIiBjbGFzcz0iaHNlLWNvbHVtbiBoc2Utc2l6ZS0xMiI-DQogIDxkaXYgaWQ9ImhzX2Nvc193cmFwcGVyX21vZHVsZV8xNzMyMzAwMzY4MTc0MSIgY2xhc3M9ImhzX2Nvc193cmFwcGVyIGhzX2Nvc193cmFwcGVyX3dpZGdldCBoc19jb3Nfd3JhcHBlcl90eXBlX21vZHVsZSIgc3R5bGU9ImNvbG9yOiBpbmhlcml0OyBmb250LXNpemU6IGluaGVyaXQ7IGxpbmUtaGVpZ2h0OiBpbmhlcml0OyIgZGF0YS1ocy1jb3MtZ2VuZXJhbC10eXBlPSJ3aWRnZXQiIGRhdGEtaHMtY29zLXR5cGU9Im1vZHVsZSI-PHRhYmxlIGNsYXNzPSJoc2UtaW1hZ2Utd3JhcHBlciIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iMTAwJSIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIj4NCiAgICA8dGJvZHk-DQogICAgICA8dHI-DQogICAgICAgIDx0ZCBjbGFzcz0iaHNfcGFkZGVkIiBhbGlnbj0iY2VudGVyIiB2YWxpZ249InRvcCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IHRleHQtYWxpZ246Y2VudGVyOyBwYWRkaW5nOjEwcHggMjBweDsgZm9udC1zaXplOjBweCI-DQogICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly9kMlJOZlAwNC5uYTEuaHVic3BvdGxpbmtzLmNvbS9DdGMvRFArMTEzL2QyUk5mUDA0L1ZYZnZTRjN5NlpxWVczOTFHVG03RndjbC1XM0RsNFNtNW5RWkxKTjJicGMxbjNxbjlnVzh3TEtTUjZsWjNtWVZxalBLczYzOEpzNFcxUkRuajU0V3A5V0xXNFpGNVRLNG1Yai15VzdENjhkeDZmdGJuWE42MnhxTDJ6TVNkMFc0M2hYeUsyUEdSVjZON2M2WnIzaC1tSE1XNnpZRDY5OTVXRFZSVzdGUnc4azgwTHRDSFZ5NENWSDJRNDNxd1c2NFQ4UEIybFc1cldXOF9OVHRSOWd4eFJkVzdweXpycTF4NmdfVFcxY21aQ183Njl4d3ZXM252UEpyNTYzdnB0VzYwd2dQajdwTDJSR1cxaGdUelY0eWNCNm1XNHpua2tXOEIyakJKVzZTZE5nMDNXTVBqeVcxYmxZMkc4WUJZWHhXNWZaNHRENmQtTm01VzhNOFI5bjNnMnlKYlc1c0I5LU0xek5aODJXMWNTTmdLNDgtTGxIVzR5eUROczJ2RzBrQ042UlhkODVGaDlnalc3OUctNWozWmxiVkdXNnlUcGxZOWxfenZyZjVQSkxmZzA0IiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiMwMGE0YmQiIGRhdGEtaHMtbGluay1pZD0iMCI-DQogICAgICAgICAgICA8aW1nIGFsdD0iTGFyazIwMjQxMTE0LTE2MDUyMCIgc3JjPSJodHRwczovLzI0MDU0ODI4LmZzMS5odWJzcG90dXNlcmNvbnRlbnQtbmExLm5ldC9odWIvMjQwNTQ4MjgvaHViZnMvY3VzdG9tLXZpZGVvLXRodW1ibmFpbHMvTGFyazIwMjQxMTE0LTE2MDUyMC10aHVtYi0xLmpwZWc_dD0xNzMyMzAwNzkxODEyJmFtcDt3aWR0aD01MDAmYW1wO2NvbXBvc2VUeXBlPXBsYXlfYnV0dG9uJmFtcDtvdmVybGF5Q29sb3I9JTIzMmY0MjU0JmFtcDtvdmVybGF5U2NhbGU9MC4zJmFtcDtuYW1lPUxhcmsyMDI0MTExNC0xNjA1MjAtdGh1bWItMS5qcGVnIiBzdHlsZT0ib3V0bGluZTpub25lOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgYm9yZGVyOm5vbmU7IG1heC13aWR0aDoxMDAlOyBmb250LXNpemU6MTZweCIgd2lkdGg9IjUwMCIgYWxpZ249Im1pZGRsZSI-DQogICAgICAgICAgPC9hPg0KICAgICAgICA8L3RkPg0KICAgICAgPC90cj4NCiAgICA8L3Rib2R5Pg0KICA8L3RhYmxlPjwvZGl2Pg0KPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiB3aWR0aD0iMTAwJSI-PHRib2R5Pjx0cj48dGQgY2xhc3M9ImhzX3BhZGRlZCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTVweDsgY29sb3I6IzIzNDk2ZDsgd29yZC1icmVhazpicmVhay13b3JkOyBwYWRkaW5nOjEwcHggMzBweCI-PGRpdiBpZD0iaHNfY29zX3dyYXBwZXJfbW9kdWxlXzE2ODk4ODkyNzg4NjAxIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfbW9kdWxlIiBzdHlsZT0iY29sb3I6IGluaGVyaXQ7IGZvbnQtc2l6ZTogaW5oZXJpdDsgbGluZS1oZWlnaHQ6IGluaGVyaXQ7IiBkYXRhLWhzLWNvcy1nZW5lcmFsLXR5cGU9IndpZGdldCIgZGF0YS1ocy1jb3MtdHlwZT0ibW9kdWxlIj48ZGl2IGlkPSJoc19jb3Nfd3JhcHBlcl9tb2R1bGVfMTY4OTg4OTI3ODg2MDFfIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfcmljaF90ZXh0IiBzdHlsZT0iY29sb3I6IGluaGVyaXQ7IGZvbnQtc2l6ZTogaW5oZXJpdDsgbGluZS1oZWlnaHQ6IGluaGVyaXQ7IiBkYXRhLWhzLWNvcy1nZW5lcmFsLXR5cGU9IndpZGdldCIgZGF0YS1ocy1jb3MtdHlwZT0icmljaF90ZXh0Ij48cCBzdHlsZT0ibXNvLWxpbmUtaGVpZ2h0LXJ1bGU6ZXhhY3RseTsgbGluZS1oZWlnaHQ6MTc1JSI-PHN0cm9uZz7wn6aDIE90aGVyIEhpZ2hsaWdodHMgJmFtcDsgSW1wcm92ZW1lbnRzPC9zdHJvbmc-PC9wPg0KPHVsIHN0eWxlPSJtc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyBsaW5lLWhlaWdodDoxNzUlIj4NCjxsaSBhcmlhLWxldmVsPSIxIj48c3Ryb25nPkVuaGFuY2VkIERhdGEgTWlncmF0aW9uOjwvc3Ryb25nPiBOb3cgc3VwcG9ydGluZyA8YSBocmVmPSJodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzFuM2hLQmJXOHdMS1NSNmxaM3BkVzIydEdISDF0ZnlZWVc2Z203RG41eFZGbHBOMTNULVJYUlFUU0RXNjU1ZEZxNWRmVGQ5TjQ3eWZCZ1RZcHg4VzFxVG1WWThtMXBtNVcyRnN0ZncxSGxQV2tXNHgtVEwxNWw2QmZSVzVLSnNRODFyTEtDR1ZyR0ZKdDdaYnpCV1c1MDdWbUwyckN0VmpXMzdQbXdNNjY0eC1aTUJUNEs2eTQxSzZXMkNWYnNkNGpIVGtwVzctTlo3TjliVHgzNVc1d0tER003UzJXWjdWRERud3M3UmhHNlBXNm1MZjQxNGhLS19MVzJKQzZYcTgtZlRTcFcxbnRGUWY4SnlramJONUhkOFZxWm5yQ0xXNUh5Zm53OTBSelZwTjFmYzVteGdtUXduTVd0SzVWX1kxakxXNEJtbnpMN1J5UHRKVzNSazBneThaelk5Y1c1Y1hYOUwyWHlRanFONFh2UFlmc2RTNG5mNGRKbnBiMDQiIHJlbD0ibm9vcGVuZXIiIHN0eWxlPSJjb2xvcjojMzY3MGYyIiBkYXRhLWhzLWxpbmstaWQ9IjAiIHRhcmdldD0iX2JsYW5rIj5RZHJhbnQ8L2E-IGFuZCA8YSBocmVmPSJodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzFuM2hLQmJXOHdMS1NSNmxaM20xTjZyX21ZMFREVGgyVzhsZnNjejkzX1psUlc2VmtzSDM4S1FSQ0NXMjc4X1BYN3NtMjlZVzI1UHZ4ZzJCQmIyRlc5OWxIeXA0X3oxdGdWZzdTZ1I4UU10ZGRXOGxyZnZyMWJLa3hWVzNtamhtbTJYRmY5OVc3M1NGbDE2NmtDbGNXNDBtOFQzNnZDQkNwVzZLUlp4QjMtcmI3N1c3NGRNeHk0M3FTVDdXNVBTakRoN18zOGxSVzNyYmduNDVSQ1p3Tlc1bTBxaHQ1ZFNqbDdXNTBSTnpxM1RNbDdKVzYtc2dTWjhHXzZ6OVc2OXhWckY4NnI3ZlpXMzZ4dHhHNlc1WFR2Vzg1WnNCUTdTWmx2WFc4WTduLXcyOE02dnBXOG1OeXZEMThLY3FZVzFtZDBaMjhkak1yV1ZMSlAtUzdRcGtfNVcyNzZRcUI4S0dMdk1XMXpzV0hQM1J2SExIVzFOdmpMNDhaLTR2VGY3bDMyXzIwNCIgcmVsPSJub29wZW5lciIgc3R5bGU9ImNvbG9yOiMzNjcwZjIiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPlBpbmVjb25lIFNlcnZlcmxlc3M8L2E-IGZvciBzZWFtbGVzcyB0cmFuc2l0aW9ucyB0byBaaWxsaXogQ2xvdWQuPC9saT4NCjxsaSBhcmlhLWxldmVsPSIxIj48c3Ryb25nPkZsZXhpYmxlIFJlcGxpY2EgTWFuYWdlbWVudDo8L3N0cm9uZz4gQWRkIG9yIHJlbW92ZSB5b3VyIHJlcGxpY2FzIGluc3RhbnRseSB3aXRob3V0IGFueSBzZXJ2aWNlIGludGVycnVwdGlvbi4gQ2hlY2sgdGhlIDxhIGhyZWY9Imh0dHBzOi8vZDJSTmZQMDQubmExLmh1YnNwb3RsaW5rcy5jb20vQ3RjL0RQKzExMy9kMlJOZlAwNC9WWGZ2U0YzeTZacVlXMzkxR1RtN0Z3Y2wtVzNEbDRTbTVuUVpMSk4yYnBjMW4zaEtCYlc4d0xLU1I2bFoza1JXNDIwd3hUMXdmeHNOVzZyZk1XeTctM0NIcVc2TDVTaFI0V190cl9WeW1HTHE5NFREUlFXNk52NHBGOFk0akpsVzJNTFZaTDJZTmwzUVZjcHEwejcxS0NjN1c0Rjc5d3I1Ml9HQllXOWxqODRyN216bks0VzMzRkJjeDc2c2RwdFc4bEotWXM0bXFSUmpXN3d3a1dxN3EzUHpnVzEySFQwQjRUYzAwUU43bHZNS0YxeWZwM1c4RFh6WGozRkpSQ2hXNHdSX2JHMWcxcVYzVzdjREd5TjdCOFktVFc1MGJYNG00eXk0Q0tONlRnY0pXa2JkNUhXNkhOZ2tsNXNIVGxLVzJSYzM5eThXTDczcVc3N2ZoNnE1dGpMd1lXOThzUl9fMVl0SERkVzFtSkcxeTdXV3JOOU41dEZUY1ZSM2RXc1c0d2tEVmM1ajk4Tl9XNXN5VDVuMm5QOEN4VzRieGo0ODNzdllQVmY5bHFkQzAwNCIgcmVsPSJub29wZW5lciIgc3R5bGU9ImNvbG9yOiMzNjcwZjIiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPmRvYzwvYT4gZm9yIG1vcmUgZGV0YWlscy48L2xpPg0KPGxpIGFyaWEtbGV2ZWw9IjEiPjxzdHJvbmc-UmVkZXNpZ25lZCBJbnZvaWNlIFBhZ2U6PC9zdHJvbmc-IEEgY2xlYXJlciB2aWV3IG9mIHlvdXIgdXNhZ2UgYW5kIGNvc3RzIHdpdGggZG93bmxvYWQgb3B0aW9ucy48L2xpPg0KPC91bD48L2Rpdj48L2Rpdj48L3RkPjwvdHI-PC90Ym9keT48L3RhYmxlPg0KPC9kaXY-DQo8IS0tW2lmIGd0ZSBtc28gOV0-PC90YWJsZT48IVtlbmRpZl0tLT4NCjwhLS1baWYgKG1zbyl8KElFKV0-PC90ZD48IVtlbmRpZl0tLT4NCiAgICA8IS0tW2lmIChtc28pfChJRSldPjwvdHI-PC90YWJsZT48IVtlbmRpZl0tLT4NCiAgICA8L2Rpdj4NCiAgIA0KICA8L2Rpdj4NCiAgPGRpdiBpZD0ibW9kdWxlXzE2ODI1NTc2MTYyODciIGNsYXNzPSJoc2Utc2VjdGlvbiIgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyBwYWRkaW5nLXJpZ2h0OjEwcHgiPg0KICAgIA0KICAgIA0KICAgIDwhLS1baWYgISgobXNvKXwoSUUpKV0-PCEtLSAtLT4NCiAgICAgIDxkaXYgY2xhc3M9ImhzZS1jb2x1bW4tY29udGFpbmVyIiBzdHlsZT0ibWluLXdpZHRoOjI4MHB4OyBtYXgtd2lkdGg6NjAwcHg7IE1hcmdpbi1sZWZ0OmF1dG87IE1hcmdpbi1yaWdodDphdXRvOyBiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYiIGJnY29sb3I9IiNmZmZmZmYiPg0KICAgIDwhLS08IVtlbmRpZl0tLT4NCiAgICANCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7bWF4LXdpZHRoOjYwMHB4O3dpZHRoOjEwMCU7TWFyZ2luLWxlZnQ6YXV0bztNYXJnaW4tcmlnaHQ6YXV0bzsiPg0KICAgICAgPHRhYmxlIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDo2MDBweDsiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNjAwIiBiZ2NvbG9yPSIjZmZmZmZmIj4NCiAgICAgIDx0ciBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmOyI-DQogICAgPCFbZW5kaWZdLS0-DQogICAgPCEtLVtpZiAobXNvKXwoSUUpXT4NCiAgPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0id2lkdGg6NjAwcHg7Ij4NCjwhW2VuZGlmXS0tPg0KPCEtLVtpZiBndGUgbXNvIDldPg0KICA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNjAwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJ3aWR0aDo2MDBweCI-DQo8IVtlbmRpZl0tLT4NCjxkaXYgaWQ9Im1vZHVsZV8xNjgyNTU3NjE2Mjg3XzAiIGNsYXNzPSJoc2UtY29sdW1uIGhzZS1zaXplLTEyIj4NCiAgPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiB3aWR0aD0iMTAwJSI-PHRib2R5Pjx0cj48dGQgY2xhc3M9ImhzX3BhZGRlZCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTVweDsgY29sb3I6IzIzNDk2ZDsgd29yZC1icmVhazpicmVhay13b3JkOyBwYWRkaW5nOjEwcHggMzBweCI-PGRpdiBpZD0iaHNfY29zX3dyYXBwZXJfbW9kdWxlXzE2ODI1NTc2MTYyNzQzIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfbW9kdWxlIiBzdHlsZT0iY29sb3I6IGluaGVyaXQ7IGZvbnQtc2l6ZTogaW5oZXJpdDsgbGluZS1oZWlnaHQ6IGluaGVyaXQ7IiBkYXRhLWhzLWNvcy1nZW5lcmFsLXR5cGU9IndpZGdldCIgZGF0YS1ocy1jb3MtdHlwZT0ibW9kdWxlIj48ZGl2IGlkPSJoc19jb3Nfd3JhcHBlcl9tb2R1bGVfMTY4MjU1NzYxNjI3NDNfIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfcmljaF90ZXh0IiBzdHlsZT0iY29sb3I6IGluaGVyaXQ7IGZvbnQtc2l6ZTogaW5oZXJpdDsgbGluZS1oZWlnaHQ6IGluaGVyaXQ7IiBkYXRhLWhzLWNvcy1nZW5lcmFsLXR5cGU9IndpZGdldCIgZGF0YS1ocy1jb3MtdHlwZT0icmljaF90ZXh0Ij48ZGl2IHN0eWxlPSJtc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyBsaW5lLWhlaWdodDoxNzUlIj4NCjxkaXYgc3R5bGU9Im1zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7IGxpbmUtaGVpZ2h0OjE3NSUiPg0KPHAgc3R5bGU9Im1zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7IGxpbmUtaGVpZ2h0OjE3NSUiPldlJ3JlIHRoYW5rZnVsIGZvciB5b3VyIGNvbnRpbnVlZCB0cnVzdCBpbiBaaWxsaXogQ2xvdWQgYW5kIGNhbid0IHdhaXQgdG8gc2VlIHdoYXQgeW91IGJ1aWxkIHdpdGggdGhlc2UgbmV3IGZlYXR1cmVzISBBcyBhbHdheXMsIHdlJ2QgbG92ZSB0byBoZWFyIHlvdXIgZmVlZGJhY2sgaW4gb3VyIDxhIGhyZWY9Imh0dHBzOi8vZDJSTmZQMDQubmExLmh1YnNwb3RsaW5rcy5jb20vQ3RjL0RQKzExMy9kMlJOZlAwNC9WWGZ2U0YzeTZacVlXMzkxR1RtN0Z3Y2wtVzNEbDRTbTVuUVpMSk4yYnBjMFAzcW45Z1c3bENkTFc2bFozbHhXNGd6dks3NF95NWR0VzR2WWg0UTNMTE5KM1c5N1BGR1c2cUJqNTVXM3NNakpaNzNSazJ3VzRNUHdybjVzQzIybFc1dnZjZ2gzODVNNTRXMzhoNFozOF9iY0h2VzNTWU5qSjhyUlRWa043Qll2NEZNeWxoVlc2QjlNcjA3U2t0RjNXN2JIcTg2NjRoSE1oVzd6OTZXWTJ0VlJ4UE44WFI2d2p4dnMtcVc3cGJQbUw0dEtwcDFWOWM2a18xWDgwRnhWU1Y2TUs4V1JLSjBWbXNNa0o3eXZ6VnhXN0tUdlluNzlmMVBRVzJqLWpxazJqRlBsbU43R1FtN05DV3p6NlczTldXTmY3ckQxQlRWZ0xNS0w0Yk4wMzFXN1NtSjd5N2c4RnhmVzkwVm10SzVNMnQyaGYzakZTYjAwNCIgc3R5bGU9ImNvbG9yOiMzNjcwZjIiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPkRpc2NvcmQgY29tbXVuaXR5PC9hPi48L3A-DQo8cCBzdHlsZT0ibXNvLWxpbmUtaGVpZ2h0LXJ1bGU6ZXhhY3RseTsgbGluZS1oZWlnaHQ6MTc1JSI-Jm5ic3A7PC9wPg0KPHAgc3R5bGU9Im1zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7IGxpbmUtaGVpZ2h0OjE3NSUiPkhhcHB5IFRoYW5rc2dpdmluZyBhbmQgSGFwcHkgQnVpbGRpbmchIPCfjYE8L3A-DQo8L2Rpdj4NCjx1bCBzdHlsZT0ibXNvLWxpbmUtaGVpZ2h0LXJ1bGU6ZXhhY3RseTsgbGluZS1oZWlnaHQ6MTc1JSI-PC91bD4NCjwvZGl2Pg0KPHVsIHN0eWxlPSJtc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyBsaW5lLWhlaWdodDoxNzUlIj48L3VsPjwvZGl2PjwvZGl2PjwvdGQ-PC90cj48L3Rib2R5PjwvdGFibGU-DQo8L2Rpdj4NCjwhLS1baWYgZ3RlIG1zbyA5XT48L3RhYmxlPjwhW2VuZGlmXS0tPg0KPCEtLVtpZiAobXNvKXwoSUUpXT48L3RkPjwhW2VuZGlmXS0tPg0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPg0KICAgIDwvZGl2Pg0KICAgDQogIDwvZGl2Pg0KICA8ZGl2IGlkPSJzZWN0aW9uLTIiIGNsYXNzPSJoc2Utc2VjdGlvbiIgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyBwYWRkaW5nLXJpZ2h0OjEwcHgiPg0KICAgIA0KICAgIA0KICAgIDwhLS1baWYgISgobXNvKXwoSUUpKV0-PCEtLSAtLT4NCiAgICAgIDxkaXYgY2xhc3M9ImhzZS1jb2x1bW4tY29udGFpbmVyIiBzdHlsZT0ibWluLXdpZHRoOjI4MHB4OyBtYXgtd2lkdGg6NjAwcHg7IE1hcmdpbi1sZWZ0OmF1dG87IE1hcmdpbi1yaWdodDphdXRvOyBiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYiIGJnY29sb3I9IiNmZmZmZmYiPg0KICAgIDwhLS08IVtlbmRpZl0tLT4NCiAgICANCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7bWF4LXdpZHRoOjYwMHB4O3dpZHRoOjEwMCU7TWFyZ2luLWxlZnQ6YXV0bztNYXJnaW4tcmlnaHQ6YXV0bzsiPg0KICAgICAgPHRhYmxlIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDo2MDBweDsiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNjAwIiBiZ2NvbG9yPSIjZmZmZmZmIj4NCiAgICAgIDx0ciBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmOyI-DQogICAgPCFbZW5kaWZdLS0-DQogICAgPCEtLVtpZiAobXNvKXwoSUUpXT4NCiAgPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0id2lkdGg6NjAwcHg7Ij4NCjwhW2VuZGlmXS0tPg0KPCEtLVtpZiBndGUgbXNvIDldPg0KICA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNjAwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJ3aWR0aDo2MDBweCI-DQo8IVtlbmRpZl0tLT4NCjxkaXYgaWQ9ImNvbHVtbi0yLTAiIGNsYXNzPSJoc2UtY29sdW1uIGhzZS1zaXplLTEyIj4NCiAgPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiB3aWR0aD0iMTAwJSI-PHRib2R5Pjx0cj48dGQgY2xhc3M9ImhzX3BhZGRlZCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTVweDsgY29sb3I6IzIzNDk2ZDsgd29yZC1icmVhazpicmVhay13b3JkOyBwYWRkaW5nOjEwcHggMzBweCI-PGRpdiBpZD0iaHNfY29zX3dyYXBwZXJfbW9kdWxlLTItMC0yIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfbW9kdWxlIiBzdHlsZT0iY29sb3I6IGluaGVyaXQ7IGZvbnQtc2l6ZTogaW5oZXJpdDsgbGluZS1oZWlnaHQ6IGluaGVyaXQ7IiBkYXRhLWhzLWNvcy1nZW5lcmFsLXR5cGU9IndpZGdldCIgZGF0YS1ocy1jb3MtdHlwZT0ibW9kdWxlIj48ZGl2IGlkPSJoc19jb3Nfd3JhcHBlcl9tb2R1bGUtMi0wLTJfIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfcmljaF90ZXh0IiBzdHlsZT0iY29sb3I6IGluaGVyaXQ7IGZvbnQtc2l6ZTogaW5oZXJpdDsgbGluZS1oZWlnaHQ6IGluaGVyaXQ7IiBkYXRhLWhzLWNvcy1nZW5lcmFsLXR5cGU9IndpZGdldCIgZGF0YS1ocy1jb3MtdHlwZT0icmljaF90ZXh0Ij48cCBzdHlsZT0ibXNvLWxpbmUtaGVpZ2h0LXJ1bGU6ZXhhY3RseTsgbGluZS1oZWlnaHQ6MTc1JSI-QmVzdCBSZWdhcmRzLDxicj5TdGVmZmkgTGk8YnI-RGlyZWN0b3Igb2YgUHJvZHVjdCBNYXJrZXRpbmcsIFppbGxpejxicj48YnI-PC9wPjwvZGl2PjwvZGl2PjwvdGQ-PC90cj48L3Rib2R5PjwvdGFibGU-DQo8L2Rpdj4NCjwhLS1baWYgZ3RlIG1zbyA5XT48L3RhYmxlPjwhW2VuZGlmXS0tPg0KPCEtLVtpZiAobXNvKXwoSUUpXT48L3RkPjwhW2VuZGlmXS0tPg0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPg0KICAgIDwvZGl2Pg0KICAgDQogIDwvZGl2Pg0KICA8ZGl2IGlkPSJzZWN0aW9uLTMiIGNsYXNzPSJoc2Utc2VjdGlvbiIgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyBwYWRkaW5nLXJpZ2h0OjEwcHgiPg0KICAgIA0KICAgIA0KICAgIDwhLS1baWYgISgobXNvKXwoSUUpKV0-PCEtLSAtLT4NCiAgICAgIDxkaXYgY2xhc3M9ImhzZS1jb2x1bW4tY29udGFpbmVyIiBzdHlsZT0ibWluLXdpZHRoOjI4MHB4OyBtYXgtd2lkdGg6NjAwcHg7IE1hcmdpbi1sZWZ0OmF1dG87IE1hcmdpbi1yaWdodDphdXRvOyBiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYiIGJnY29sb3I9IiNmZmZmZmYiPg0KICAgIDwhLS08IVtlbmRpZl0tLT4NCiAgICANCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7bWF4LXdpZHRoOjYwMHB4O3dpZHRoOjEwMCU7TWFyZ2luLWxlZnQ6YXV0bztNYXJnaW4tcmlnaHQ6YXV0bzsiPg0KICAgICAgPHRhYmxlIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDo2MDBweDsiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNjAwIiBiZ2NvbG9yPSIjZmZmZmZmIj4NCiAgICAgIDx0ciBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmOyI-DQogICAgPCFbZW5kaWZdLS0-DQogICAgPCEtLVtpZiAobXNvKXwoSUUpXT4NCiAgPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0id2lkdGg6NjAwcHg7Ij4NCjwhW2VuZGlmXS0tPg0KPCEtLVtpZiBndGUgbXNvIDldPg0KICA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNjAwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJ3aWR0aDo2MDBweCI-DQo8IVtlbmRpZl0tLT4NCjxkaXYgaWQ9ImNvbHVtbi0zLTAiIGNsYXNzPSJoc2UtY29sdW1uIGhzZS1zaXplLTEyIj4NCiAgPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiB3aWR0aD0iMTAwJSI-PHRib2R5Pjx0cj48dGQgY2xhc3M9ImhzX3BhZGRlZCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTVweDsgY29sb3I6IzIzNDk2ZDsgd29yZC1icmVhazpicmVhay13b3JkOyBwYWRkaW5nOjEwcHggMjBweCI-PGRpdiBpZD0iaHNfY29zX3dyYXBwZXJfbW9kdWxlLTMtMC0wIiBjbGFzcz0iaHNfY29zX3dyYXBwZXIgaHNfY29zX3dyYXBwZXJfd2lkZ2V0IGhzX2Nvc193cmFwcGVyX3R5cGVfbW9kdWxlIiBzdHlsZT0iY29sb3I6IGluaGVyaXQ7IGZvbnQtc2l6ZTogaW5oZXJpdDsgbGluZS1oZWlnaHQ6IGluaGVyaXQ7IiBkYXRhLWhzLWNvcy1nZW5lcmFsLXR5cGU9IndpZGdldCIgZGF0YS1ocy1jb3MtdHlwZT0ibW9kdWxlIj48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0id2lkdGg6IGF1dG87IHRleHQtYWxpZ246IGNlbnRlcjsiIGNsYXNzPSJoc19jb3Nfd3JhcHBlcl90eXBlX3NvY2lhbF9tb2R1bGUiPg0KICA8dGJvZHk-DQogICAgPHRyIGFsaWduPSJjZW50ZXIiPg0KICAgICAgPHRkIGNsYXNzPSJzb2NpYWwtbmV0d29yay1jZWxsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxNXB4OyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQiPg0KICAgICAgICA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0id2lkdGg6IGF1dG87IHRleHQtYWxpZ246IGNlbnRlcjsiIGNsYXNzPSJoc19jb3Nfd3JhcHBlcl90eXBlX3NvY2lhbF9tb2R1bGVfc2luZ2xlIj4NCiAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICA8dHIgYWxpZ249ImNlbnRlciI-DQogICAgICAgICAgICAgIDx0ZCBjbGFzcz0iZGlzcGxheV9ibG9ja19vbl9zbWFsbF9zY3JlZW5zIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxNXB4OyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IHBhZGRpbmc6OHB4IDVweDsgbGluZS1oZWlnaHQ6MTsgdmVydGljYWwtYWxpZ246bWlkZGxlIiB2YWxpZ249Im1pZGRsZSI-DQogICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly9kMlJOZlAwNC5uYTEuaHVic3BvdGxpbmtzLmNvbS9DdGMvRFArMTEzL2QyUk5mUDA0L1ZYZnZTRjN5NlpxWVczOTFHVG03RndjbC1XM0RsNFNtNW5RWkxKTjJicGMwUDNxbjlnVzdsQ2RMVzZsWjNuLU43UHBDSDh6LWRQMFc4ODZ4OHA4VGRDMlpXMzdsOXlQNW56YjFRVzE2NDdodjk1bkMwcVc0OEdocDI3cGQ3TmZXM0JHUDdqOF9uVGN6VzFObEN6ejVzU21UV1cyX0Z4em4xTFZ2azhXNU4wSzh6NzR5bWZrVzc0R0NnMzc1djdrOU4yRnlZcngtak41OFc3U18xNVE0TDAwcmZXNlMwdHBRMUdyNlo3VzZUOHZnSjd6MDZ2OVc4V3Fqd3czMVI2eFlXOWQ0bUZnMmg2a1ltVzNYNENybTNHREZTM1czOEJfeC00UVdIdHFXNVl2bVlLNWQxMDRjVzY1Y1p6RzJmLWNGYlc1S1l3ank4WVpHckxNaFlwek05NjlHa1cybk5oN04xNkpMUFZWd0pqc0o1dzdQcnJmNGstN2w4MDQiIHN0eWxlPSJjb2xvcjojMDBhNGJkOyB0ZXh0LWRlY29yYXRpb246bm9uZSAhaW1wb3J0YW50IiBkYXRhLWhzLWxpbmstaWQ9IjAiIHRhcmdldD0iX2JsYW5rIj48aW1nIHNyYz0iaHR0cHM6Ly9ocy0yNDA1NDgyOC5mLmh1YnNwb3RlbWFpbC5uZXQvaHViLzI0MDU0ODI4L2h1YmZzL0ltcG9ydGVkJTIwc2l0ZXBhZ2UlMjBpbWFnZXMvR2l0aHViXzE5ZTdiYzI4MjQucG5nP2hlaWdodD01MCZhbXA7dXBzY2FsZT10cnVlJmFtcDtuYW1lPUdpdGh1Yl8xOWU3YmMyODI0LnBuZyIgYWx0PSJHaXRodWJfaWNvbiIgaGVpZ2h0PSIyNSIgc3R5bGU9Im91dGxpbmU6bm9uZTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGJvcmRlcjpub25lOyB3aWR0aDphdXRvIWltcG9ydGFudDsgaGVpZ2h0OjI1cHghaW1wb3J0YW50OyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGUiIHZhbGlnbj0ibWlkZGxlIiB3aWR0aD0iYXV0byI-DQogICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD48dGQgY2xhc3M9InNvY2lhbC1uZXR3b3JrLWNlbGwiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZCI-DQogICAgICAgIDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDogYXV0bzsgdGV4dC1hbGlnbjogY2VudGVyOyIgY2xhc3M9ImhzX2Nvc193cmFwcGVyX3R5cGVfc29jaWFsX21vZHVsZV9zaW5nbGUiPg0KICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0ciBhbGlnbj0iY2VudGVyIj4NCiAgICAgICAgICAgICAgPHRkIGNsYXNzPSJkaXNwbGF5X2Jsb2NrX29uX3NtYWxsX3NjcmVlbnMiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZDsgcGFkZGluZzo4cHggNXB4OyBsaW5lLWhlaWdodDoxOyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGUiIHZhbGlnbj0ibWlkZGxlIj4NCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzE0M3FuOWdXN1k4LVBUNmxaM25IVzQ3cERHdzM0UFlxX1c0MllsMjU2blg0OXZXNlRyLURkMmZIZ1RSVzdXa3ZsWjNIRDJsak1mNUtxZDQ5Zm1CVzYwXzJQNjRNNGN0Tk44UjNYQnMyTlhSclcxQmNWc0I4VjU4QkxXOHlLdnR2MXZ4eldaVzQ4UFpMLTJnSHl6WVczdjE2WUY3SFQ4cTJXOWRnV0RkNExxNmR4VzRINVlzRzZqWnowMFcyaGNiZE4xV1gxUk1XNnBxNk5LMVc4OUgwVzRkcVNEZzJDZ1JLZlc4SnJ5eXIzNjhTbHdXOHF5NHFzNks4YkItVzczMWh5WTlqajNwYlc4ZkMzbGMyNmRMUWNXNndWVng3MllmMDVwVzhZQkY5SjZoY3dnalcxcFRyMms0Q0w1UzhXNWJMUThzNE4wRHc4VzRybGpHbDljZnAwNlcxakNzbHYxWnEyWmRmNnp3SmxzMDQiIHN0eWxlPSJjb2xvcjojMDBhNGJkOyB0ZXh0LWRlY29yYXRpb246bm9uZSAhaW1wb3J0YW50IiBkYXRhLWhzLWxpbmstaWQ9IjAiIHRhcmdldD0iX2JsYW5rIj48aW1nIHNyYz0iaHR0cHM6Ly9ocy0yNDA1NDgyOC5mLmh1YnNwb3RlbWFpbC5uZXQvaHViLzI0MDU0ODI4L2h1YmZzL1R3aXR0ZXItMjAyMzEwMTgtMTExMTEwLnBuZz9oZWlnaHQ9NTAmYW1wO3Vwc2NhbGU9dHJ1ZSZhbXA7bmFtZT1Ud2l0dGVyLTIwMjMxMDE4LTExMTExMC5wbmciIGFsdD0iVHdpdHRlci0yMDIzMTAxOC0xMTExMTAiIGhlaWdodD0iMjUiIHN0eWxlPSJvdXRsaW5lOm5vbmU7IHRleHQtZGVjb3JhdGlvbjpub25lOyBib3JkZXI6bm9uZTsgd2lkdGg6YXV0byFpbXBvcnRhbnQ7IGhlaWdodDoyNXB4IWltcG9ydGFudDsgdmVydGljYWwtYWxpZ246bWlkZGxlIiB2YWxpZ249Im1pZGRsZSIgd2lkdGg9ImF1dG8iPg0KICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgPC90YWJsZT4NCiAgICAgIDwvdGQ-PHRkIGNsYXNzPSJzb2NpYWwtbmV0d29yay1jZWxsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxNXB4OyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQiPg0KICAgICAgICA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0id2lkdGg6IGF1dG87IHRleHQtYWxpZ246IGNlbnRlcjsiIGNsYXNzPSJoc19jb3Nfd3JhcHBlcl90eXBlX3NvY2lhbF9tb2R1bGVfc2luZ2xlIj4NCiAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICA8dHIgYWxpZ249ImNlbnRlciI-DQogICAgICAgICAgICAgIDx0ZCBjbGFzcz0iZGlzcGxheV9ibG9ja19vbl9zbWFsbF9zY3JlZW5zIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxNXB4OyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IHBhZGRpbmc6OHB4IDVweDsgbGluZS1oZWlnaHQ6MTsgdmVydGljYWwtYWxpZ246bWlkZGxlIiB2YWxpZ249Im1pZGRsZSI-DQogICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0cHM6Ly9kMlJOZlAwNC5uYTEuaHVic3BvdGxpbmtzLmNvbS9DdGMvRFArMTEzL2QyUk5mUDA0L1ZYZnZTRjN5NlpxWVczOTFHVG03RndjbC1XM0RsNFNtNW5RWkxKTjJicGMxNDNxbjlnVzdZOC1QVDZsWjNsVlc1UFZDbV8yZFI4WDRXOEZTdjg5MXFsV0gwVzFGNWNrMjFaTEM0Q1cyZm5aMWg4anZfNEpXMzVmVDY4NlpkanRoVzgzcDJ4XzFkUTZnWFcxQ2JNLWM0S1drOGpXNlNuYjkzMjd4Z3BsVzRKdHpnQzdybDdNRFcybGxSbUYzc1p0U1hOMWo4Qjl4bU5qdnZXNHBiWnZiNk03eWt5VzZnQ2RQWDJZUFg4Q1c0bnZxek0yeFZ4RmJXOWI0ejJCNzY1TE4xTjROd3RGekpxM0NMVzJIOVlZVjZod256alc5aGh3Rmw1dGw3c1JXOF9OYnFmNmhta2NuRjg0ZFdGd2tzM3dXMUc1UzlzOHlfWFhZVzdqdno5dDNrMFk5cFc1V015QlgzLXNSTHJXODEzSy1wMXZnbmtrVzJnZ0dzejdCR2xoc1c2UENWNnM2MXh4ODRkSkYwTWowNCIgc3R5bGU9ImNvbG9yOiMwMGE0YmQ7IHRleHQtZGVjb3JhdGlvbjpub25lICFpbXBvcnRhbnQiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgc3JjPSJodHRwczovL2hzLTI0MDU0ODI4LmYuaHVic3BvdGVtYWlsLm5ldC9odWIvMjQwNTQ4MjgvaHViZnMvSW1wb3J0ZWQlMjBzaXRlcGFnZSUyMGltYWdlcy9MaW5rZWRpbl8zNjk4MGI2ZmI0LnBuZz9oZWlnaHQ9NTAmYW1wO3Vwc2NhbGU9dHJ1ZSZhbXA7bmFtZT1MaW5rZWRpbl8zNjk4MGI2ZmI0LnBuZyIgYWx0PSJMaW5rZWRpbl9pY29uIiBoZWlnaHQ9IjI1IiBzdHlsZT0ib3V0bGluZTpub25lOyB0ZXh0LWRlY29yYXRpb246bm9uZTsgYm9yZGVyOm5vbmU7IHdpZHRoOmF1dG8haW1wb3J0YW50OyBoZWlnaHQ6MjVweCFpbXBvcnRhbnQ7IHZlcnRpY2FsLWFsaWduOm1pZGRsZSIgdmFsaWduPSJtaWRkbGUiIHdpZHRoPSJhdXRvIj4NCiAgICAgICAgICAgICAgICA8L2E-DQogICAgICAgICAgICAgIDwvdGQ-DQogICAgICAgICAgICA8L3RyPg0KICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgIDwvdGFibGU-DQogICAgICA8L3RkPjx0ZCBjbGFzcz0ic29jaWFsLW5ldHdvcmstY2VsbCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTVweDsgY29sb3I6IzIzNDk2ZDsgd29yZC1icmVhazpicmVhay13b3JkIj4NCiAgICAgICAgPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgYWxpZ249ImNlbnRlciIgc3R5bGU9IndpZHRoOiBhdXRvOyB0ZXh0LWFsaWduOiBjZW50ZXI7IiBjbGFzcz0iaHNfY29zX3dyYXBwZXJfdHlwZV9zb2NpYWxfbW9kdWxlX3NpbmdsZSI-DQogICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgPHRyIGFsaWduPSJjZW50ZXIiPg0KICAgICAgICAgICAgICA8dGQgY2xhc3M9ImRpc3BsYXlfYmxvY2tfb25fc21hbGxfc2NyZWVucyIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTVweDsgY29sb3I6IzIzNDk2ZDsgd29yZC1icmVhazpicmVhay13b3JkOyBwYWRkaW5nOjhweCA1cHg7IGxpbmUtaGVpZ2h0OjE7IHZlcnRpY2FsLWFsaWduOm1pZGRsZSIgdmFsaWduPSJtaWRkbGUiPg0KICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0dHBzOi8vZDJSTmZQMDQubmExLmh1YnNwb3RsaW5rcy5jb20vQ3RjL0RQKzExMy9kMlJOZlAwNC9WWGZ2U0YzeTZacVlXMzkxR1RtN0Z3Y2wtVzNEbDRTbTVuUVpMSk4yYnBjMTQzcW45Z1c3WTgtUFQ2bFozcDNXMktjYmxtNUpEX0xsVzE0alY2RzdUbG5LcVY4SHFkaDR6OU04cVc3Y0NHSkI4TlJTUG5XMlNTMzB5N3dadldkVzkyNFdfRDdMS3Y3d1cxa1hUcnk0OWZwM0dXNHB0Y1dZOGs5dnR0VnFzaEd2NDRGWHFTVzZaWFE4WjJYbmM4eFc3UTRiMEsxRDFCQzJWd3N0RzQ0bjUtRDJXNm43cERQNUQwazdDVzRNQzhGcTQ4d180LU40Q3BkTmg3Tm5qbFcxck1YeHo5MjdNbWZXOWR3V0wtNmQta25XVzdIdlNXYjRNUDRXWlcyelczZ3c1R2NKRnRXOEsxRHlCN2xnQjNZVzg3c0dDMTJSNW1ROVc4SEgtNU44WW1UemNONXFMUkd0Z19iQ1ZXNEJzalpRNWZCM1RXTjc3bVcwTnN3M2twVzVoWVRrcjZmS25qNWYyUUw1OWcwNCIgc3R5bGU9ImNvbG9yOiMwMGE0YmQ7IHRleHQtZGVjb3JhdGlvbjpub25lICFpbXBvcnRhbnQiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgc3JjPSJodHRwczovL2hzLTI0MDU0ODI4LmYuaHVic3BvdGVtYWlsLm5ldC9odWIvMjQwNTQ4MjgvaHViZnMvaW5zLTIwMjMxMDE4LTExMTExOC5wbmc_aGVpZ2h0PTUwJmFtcDt1cHNjYWxlPXRydWUmYW1wO25hbWU9aW5zLTIwMjMxMDE4LTExMTExOC5wbmciIGFsdD0iaW5zLTIwMjMxMDE4LTExMTExOCIgaGVpZ2h0PSIyNSIgc3R5bGU9Im91dGxpbmU6bm9uZTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGJvcmRlcjpub25lOyB3aWR0aDphdXRvIWltcG9ydGFudDsgaGVpZ2h0OjI1cHghaW1wb3J0YW50OyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGUiIHZhbGlnbj0ibWlkZGxlIiB3aWR0aD0iYXV0byI-DQogICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD48dGQgY2xhc3M9InNvY2lhbC1uZXR3b3JrLWNlbGwiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZCI-DQogICAgICAgIDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDogYXV0bzsgdGV4dC1hbGlnbjogY2VudGVyOyIgY2xhc3M9ImhzX2Nvc193cmFwcGVyX3R5cGVfc29jaWFsX21vZHVsZV9zaW5nbGUiPg0KICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0ciBhbGlnbj0iY2VudGVyIj4NCiAgICAgICAgICAgICAgPHRkIGNsYXNzPSJkaXNwbGF5X2Jsb2NrX29uX3NtYWxsX3NjcmVlbnMiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZDsgcGFkZGluZzo4cHggNXB4OyBsaW5lLWhlaWdodDoxOyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGUiIHZhbGlnbj0ibWlkZGxlIj4NCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzBQM3FuOWdXN2xDZExXNmxaM3BEVzI4MjN3LTFOMFk4TVc0Z2RXM1o3YjliR05XOGtZUmp0OEpHZnZaTjRoZHNSYzQ3OWY2VzR3UDNTSDVCN3E1Nk42UndiakY5OG1qUVcxd1ZUNlk3SlRRMzRXM0hselJ6M2xNWGtCVzhiUGdKeTdUMDA2MVczZGRqYlA0S3dYRkhONUwwMDRNbi1ELTFXMW5oRHpuNkdaSER6VzRWbFJORzZOSFpRcFc2S0tqdDAzQ2RCS2dXMXJQOVltM2hoTG1nVzMxMF9ybTJwV190R042THo1VnpINzNyN1czNFpqRDU2Y0RMNlRUTktSNjFsSHlOUlRfOV9xM1FfY3pUVzQtS2hrVDRaU25rLVc3V0tnWEYzMTRnZkRXNzhkakJZOWZiTndXVzVTalZqOTdzTjEyN2YxME1fS00wNCIgc3R5bGU9ImNvbG9yOiMwMGE0YmQ7IHRleHQtZGVjb3JhdGlvbjpub25lICFpbXBvcnRhbnQiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgc3JjPSJodHRwczovL2hzLTI0MDU0ODI4LmYuaHVic3BvdGVtYWlsLm5ldC9odWIvMjQwNTQ4MjgvaHViZnMvRGlzY29yZC5wbmc_aGVpZ2h0PTUwJmFtcDt1cHNjYWxlPXRydWUmYW1wO25hbWU9RGlzY29yZC5wbmciIGFsdD0iRGlzY29yZCIgaGVpZ2h0PSIyNSIgc3R5bGU9Im91dGxpbmU6bm9uZTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGJvcmRlcjpub25lOyB3aWR0aDphdXRvIWltcG9ydGFudDsgaGVpZ2h0OjI1cHghaW1wb3J0YW50OyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGUiIHZhbGlnbj0ibWlkZGxlIiB3aWR0aD0iYXV0byI-DQogICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD48dGQgY2xhc3M9InNvY2lhbC1uZXR3b3JrLWNlbGwiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZCI-DQogICAgICAgIDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDogYXV0bzsgdGV4dC1hbGlnbjogY2VudGVyOyIgY2xhc3M9ImhzX2Nvc193cmFwcGVyX3R5cGVfc29jaWFsX21vZHVsZV9zaW5nbGUiPg0KICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0ciBhbGlnbj0iY2VudGVyIj4NCiAgICAgICAgICAgICAgPHRkIGNsYXNzPSJkaXNwbGF5X2Jsb2NrX29uX3NtYWxsX3NjcmVlbnMiIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE1cHg7IGNvbG9yOiMyMzQ5NmQ7IHdvcmQtYnJlYWs6YnJlYWstd29yZDsgcGFkZGluZzo4cHggNXB4OyBsaW5lLWhlaWdodDoxOyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGUiIHZhbGlnbj0ibWlkZGxlIj4NCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0Yy9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpOMmJwYzE0M3FuOWdXN1k4LVBUNmxaM3BiVzhLVmN2XzRkZEw0a1cyQlNuOEc3S21qVFRON0RtR3RkbGZzOXZXM0ZWYzlENDRYTDJrVzVwY3JNdzN0TnM2UVc0WHRDbEI4YjhMckdXMTNoZmNaNVNHWTdITjZLMFMwSmdaTjkxVzFYd1FybjZfc2tNSlcxcExEcHQ0WjZUVnBXNlIxNDVzN1ZSakdRVzNEWlFMMjdmWjNESlcxVnRjOHM2eDV2S1JOMngyU3BjWHpUMUxXNlRUWG5UMVFEOGY2VmwxOFpXN0Z2R1hoVzRUTjhXNDJ0Z3ByR1c0UTNScDk4V2dXbGdXMkt3WjZMNVkxa2RZVzNfbnZDYzduVGNrZ1c4WkhIM180QkR2ODJWWUxxYmsxOXgtcmZWLUM0WEc5MFpnR3JXODJwTVJXOTh0djg4TjJSYmpHMkY1NE10VzdqSFdjNjljS1FfOWYzakdxMDAwNCIgc3R5bGU9ImNvbG9yOiMwMGE0YmQ7IHRleHQtZGVjb3JhdGlvbjpub25lICFpbXBvcnRhbnQiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgc3JjPSJodHRwczovL2hzLTI0MDU0ODI4LmYuaHVic3BvdGVtYWlsLm5ldC9odWIvMjQwNTQ4MjgvaHViZnMvTGlua2VkaW4tMjAyMzEwMTgtMTExMTAzLnBuZz9oZWlnaHQ9NTAmYW1wO3Vwc2NhbGU9dHJ1ZSZhbXA7bmFtZT1MaW5rZWRpbi0yMDIzMTAxOC0xMTExMDMucG5nIiBhbHQ9IkxpbmtlZGluLTIwMjMxMDE4LTExMTEwMyIgaGVpZ2h0PSIyNSIgc3R5bGU9Im91dGxpbmU6bm9uZTsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGJvcmRlcjpub25lOyB3aWR0aDphdXRvIWltcG9ydGFudDsgaGVpZ2h0OjI1cHghaW1wb3J0YW50OyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGUiIHZhbGlnbj0ibWlkZGxlIiB3aWR0aD0iYXV0byI-DQogICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICA8L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICA8L3RhYmxlPg0KICAgICAgPC90ZD4NCiAgICA8L3RyPg0KICA8L3Rib2R5Pg0KPC90YWJsZT4NCjwvZGl2PjwvdGQ-PC90cj48L3Rib2R5PjwvdGFibGU-DQo8L2Rpdj4NCjwhLS1baWYgZ3RlIG1zbyA5XT48L3RhYmxlPjwhW2VuZGlmXS0tPg0KPCEtLVtpZiAobXNvKXwoSUUpXT48L3RkPjwhW2VuZGlmXS0tPg0KICAgIDwhLS1baWYgKG1zbyl8KElFKV0-PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPg0KICAgIDwvZGl2Pg0KICAgDQogIDwvZGl2Pg0KICA8ZGl2IGlkPSJzZWN0aW9uLTQiIGNsYXNzPSJoc2Utc2VjdGlvbiBoc2Utc2VjdGlvbi1sYXN0IiBzdHlsZT0icGFkZGluZy1sZWZ0OjEwcHg7IHBhZGRpbmctcmlnaHQ6MTBweCI-DQogICAgDQogICAgDQogICAgPCEtLVtpZiAhKChtc28pfChJRSkpXT48IS0tIC0tPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7IG1heC13aWR0aDo2MDBweDsgTWFyZ2luLWxlZnQ6YXV0bzsgTWFyZ2luLXJpZ2h0OmF1dG87IHBhZGRpbmctYm90dG9tOjIwcHg7IHBhZGRpbmctdG9wOjIwcHgiPg0KICAgIDwhLS08IVtlbmRpZl0tLT4NCiAgICANCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICAgICAgPGRpdiBjbGFzcz0iaHNlLWNvbHVtbi1jb250YWluZXIiIHN0eWxlPSJtaW4td2lkdGg6MjgwcHg7bWF4LXdpZHRoOjYwMHB4O3dpZHRoOjEwMCU7TWFyZ2luLWxlZnQ6YXV0bztNYXJnaW4tcmlnaHQ6YXV0bzsiPg0KICAgICAgPHRhYmxlIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ3aWR0aDo2MDBweDsiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIj4NCiAgICAgIDx0cj4NCiAgICA8IVtlbmRpZl0tLT4NCiAgICA8IS0tW2lmIChtc28pfChJRSldPg0KICA8dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJ3aWR0aDo2MDBweDtwYWRkaW5nLWJvdHRvbToyMHB4OyBwYWRkaW5nLXRvcDoyMHB4OyI-DQo8IVtlbmRpZl0tLT4NCjwhLS1baWYgZ3RlIG1zbyA5XT4NCiAgPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgd2lkdGg9IjYwMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBzdHlsZT0id2lkdGg6NjAwcHgiPg0KPCFbZW5kaWZdLS0-DQo8ZGl2IGlkPSJjb2x1bW4tNC0wIiBjbGFzcz0iaHNlLWNvbHVtbiBoc2Utc2l6ZS0xMiI-DQogIDxkaXYgaWQ9ImhzX2Nvc193cmFwcGVyX21vZHVsZS00LTAtMCIgY2xhc3M9ImhzX2Nvc193cmFwcGVyIGhzX2Nvc193cmFwcGVyX3dpZGdldCBoc19jb3Nfd3JhcHBlcl90eXBlX21vZHVsZSIgc3R5bGU9ImNvbG9yOiBpbmhlcml0OyBmb250LXNpemU6IGluaGVyaXQ7IGxpbmUtaGVpZ2h0OiBpbmhlcml0OyIgZGF0YS1ocy1jb3MtZ2VuZXJhbC10eXBlPSJ3aWRnZXQiIGRhdGEtaHMtY29zLXR5cGU9Im1vZHVsZSI-PHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgY2xhc3M9ImhzZS1mb290ZXIgaHNlLXNlY29uZGFyeSIgd2lkdGg9IjEwMCUiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MTJweDsgbGluZS1oZWlnaHQ6MTM1JTsgY29sb3I6IzIzNDk2ZDsgbWFyZ2luLWJvdHRvbTowOyBwYWRkaW5nOjAiPg0KICA8dGJvZHk-DQogICAgPHRyPg0KICAgICAgPHRkIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0idG9wIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxNXB4OyBjb2xvcjojMjM0OTZkOyB3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IHRleHQtYWxpZ246Y2VudGVyOyBtYXJnaW4tYm90dG9tOjA7IGxpbmUtaGVpZ2h0OjEzNSU7IHBhZGRpbmc6MTBweCAyMHB4Ij4NCiAgICAgICAgPHAgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtd2VpZ2h0Om5vcm1hbDt0ZXh0LWRlY29yYXRpb246bm9uZTtmb250LXN0eWxlOm5vcm1hbDtjb2xvcjojMjM0OTZkIj4NCiAgICAgICAgICBaaWxsaXogSW5jLCAyMDEgUmVkd29vZCBTaG9yZXMgUGt3eSwgU3VpdGUgMzMwLCBSZWR3b29kIENpdHksIENBIDk0MDY1LCBVbml0ZWQgU3RhdGVzDQogICAgICAgIDwvcD4NCiAgICAgICAgPHA-DQogICAgICAgICAgPGEgZGF0YS11bnN1YnNjcmliZT0idHJ1ZSIgaHJlZj0iaHR0cHM6Ly9ocy0yNDA1NDgyOC5zLmh1YnNwb3RlbWFpbC5uZXQvaHMvcHJlZmVyZW5jZXMtY2VudGVyL2VuL2RpcmVjdD9kYXRhPVcyblhTLU4zMGgtQmNXMkhGVnFwNGNLZDl3VzNick1OTDMybEpWblczejFKTlczQzlOUmJXMkNGdEJtMzJzWEJLVzQxVjh5SDFCTnlZR1cyS0JLRzQyUE5rN2tXM2o2MlBnM3pkeUoxVzIxN3lkSjIyVE4wcFcyLUJkQnEzMnFzY1lXMVFybDl6MzZCN1FWVzNoLUI1XzNYTi1WMVcydDA0MkgyV0hfaC1XMzA2U3k3NDNRZjJGVzNDajI4QjFWeGxjY1czSGRHeWczMmctTTZXNDNGMTVtM0xHWXJiVzJxTXk0UzRjczJ5M1czTlhXY3QxWmc3SmhXNDNYeHlINGhLamc1VzNQNXZLYjR0RHhoWlc0Y2xKVl8yTUNSOExXMzhjUlkyMnIxNUpNVzJzRnQwdjI1MnJXNVcxTEZ5VzAyUnY4YzNXM0RNSzdENDNHaGpyVzFCdl9nMzJ2eUZsU1c0M3FTUWIzU0hZMl9XMjFsZmY4NGZMZ0RkVzJUaFhXODQxWTdfTFcxX2pzWkszODN0cUhXM2dubVBYMVZ5OC1qVzRrTTlNTDMwSzNfSlcxVmJSQy0yVFM3Zm1XM19zM1JHNG1xMjk2VzNkOWtKQzN6a3Z2eFcyMldxenA0NU15V1hXMkNNSHBaMzBMbFNLVzRrdDZRdjNRVkYzTVcyUmpfZFYxTDhON0dXM2pyLWZEMnAwdDIxVzJwM2t0azMwRFNqcVcxUTNNTHYySEZ4NS1XNHJwZkxRMjMxV1lqVzNfcHgtRzRyZktjbFc0ZnRaU3QxQnFUWkcwJmFtcDt1dG1fY2FtcGFpZ249WmlsbGl6LU1vbnRobHktUHJvZHVjdC1VcGRhdGVzJmFtcDt1dG1fc291cmNlPWhzX2VtYWlsJmFtcDt1dG1fbWVkaXVtPWVtYWlsJmFtcDt1dG1fY29udGVudD0zMzUyNTY1OTUmYW1wO19oc2VuYz1wMkFOcXR6LTkzNjBicFV1T1ZXbkZFOS1VYVl1NUg2Y2NGa0tZdS1zNXBYbEZQMVlMNV95YUQ2LXNjeWlxME9zMnhSVExaeTFaX095cnJ4NEd5LWgyOHZRUmlNWWNXRW1QV1VBJmFtcDtfaHNtaT0zMzUyNTY1OTUiIHN0eWxlPSJmb250LWZhbWlseTpIZWx2ZXRpY2EsQXJpYWwsc2Fucy1zZXJpZjsgZm9udC1zaXplOjEycHg7IGNvbG9yOiMzNjcwZjI7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgdGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZTsgZm9udC1zdHlsZTpub3JtYWwiIGRhdGEtaHMtbGluay1pZD0iMCIgdGFyZ2V0PSJfYmxhbmsiPlVuc3Vic2NyaWJlPC9hPg0KICAgICAgICAgIDxhIGRhdGEtdW5zdWJzY3JpYmU9InRydWUiIGhyZWY9Imh0dHBzOi8vaHMtMjQwNTQ4Mjgucy5odWJzcG90ZW1haWwubmV0L2hzL3ByZWZlcmVuY2VzLWNlbnRlci9lbi9wYWdlP2RhdGE9VzJuWFMtTjMwaC1CY1cySEZWcXA0Y0tkOXdXM2JyTU5MMzJsSlZuVzN6MUpOVzNDOU5SYlcyQ0Z0Qm0zMnNYQktXNDFWOHlIMUJOeVlHVzJLQktHNDJQTms3a1czajYyUGczemR5SjFXMjE3eWRKMjJUTjBwVzItQmRCcTMycXNjWVcxUXJsOXozNkI3UVZXM2gtQjVfM1hOLVYxVzJ0MDQySDJXSF9oLVczMDZTeTc0M1FmMkZXM0NqMjhCMVZ4bGNjVzNIZEd5ZzMyZy1NNlc0M0YxNW0zTEdZcmJXMnFNeTRTNGNzMnkzVzNOWFdjdDFaZzdKaFc0M1h4eUg0aEtqZzVXM1A1dktiNHREeGhaVzRjbEpWXzJNQ1I4TFczOGNSWTIycjE1Sk1XMnNGdDB2MjUyclc1VzFMRnlXMDJSdjhjM1czRE1LN0Q0M0doanJXMUJ2X2czMnZ5RmxTVzQzcVNRYjNTSFkyX1cyMWxmZjg0ZkxnRGRXMlRoWFc4NDFZN19MVzFfanNaSzM4M3RxSFczZ25tUFgxVnk4LWpXNGtNOU1MMzBLM19KVzFWYlJDLTJUUzdmbVczX3MzUkc0bXEyOTZXM2Q5a0pDM3prdnZ4VzIyV3F6cDQ1TXlXWFcyQ01IcFozMExsU0tXNGt0NlF2M1FWRjNNVzJSal9kVjFMOE43R1czanItZkQycDB0MjFXMnAza3RrMzBEU2pxVzFRM01MdjJIRng1LVc0cnBmTFEyMzFXWWpXM19weC1HNHJmS2NsVzRmdFpTdDFCcVRaRzAmYW1wO3V0bV9jYW1wYWlnbj1aaWxsaXotTW9udGhseS1Qcm9kdWN0LVVwZGF0ZXMmYW1wO3V0bV9zb3VyY2U9aHNfZW1haWwmYW1wO3V0bV9tZWRpdW09ZW1haWwmYW1wO3V0bV9jb250ZW50PTMzNTI1NjU5NSZhbXA7X2hzZW5jPXAyQU5xdHotOTM2MGJwVXVPVlduRkU5LVVhWXU1SDZjY0ZrS1l1LXM1cFhsRlAxWUw1X3lhRDYtc2N5aXEwT3MyeFJUTFp5MVpfT3lycng0R3ktaDI4dlFSaU1ZY1dFbVBXVUEmYW1wO19oc21pPTMzNTI1NjU5NSIgc3R5bGU9ImZvbnQtZmFtaWx5OkhlbHZldGljYSxBcmlhbCxzYW5zLXNlcmlmOyBmb250LXNpemU6MTJweDsgY29sb3I6IzM2NzBmMjsgZm9udC13ZWlnaHQ6bm9ybWFsOyB0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lOyBmb250LXN0eWxlOm5vcm1hbCIgZGF0YS1ocy1saW5rLWlkPSIwIiB0YXJnZXQ9Il9ibGFuayI-TWFuYWdlIHByZWZlcmVuY2VzPC9hPg0KICAgICAgICA8L3A-DQogICAgICA8L3RkPg0KICAgIDwvdHI-DQogIDwvdGJvZHk-DQo8L3RhYmxlPjwvZGl2Pg0KPC9kaXY-DQo8IS0tW2lmIGd0ZSBtc28gOV0-PC90YWJsZT48IVtlbmRpZl0tLT4NCjwhLS1baWYgKG1zbyl8KElFKV0-PC90ZD48IVtlbmRpZl0tLT4NCiAgICA8IS0tW2lmIChtc28pfChJRSldPjwvdHI-PC90YWJsZT48IVtlbmRpZl0tLT4NCiAgICA8L2Rpdj4NCiAgIA0KICA8L2Rpdj48L2Rpdj4NCiAgICAgICAgICA8L3RkPg0KICAgICAgICA8L3RyPg0KICAgICAgPC90Ym9keT48L3RhYmxlPg0KICAgIDwvZGl2Pg0KICANCjxpbWcgc3JjPSJodHRwczovL2QyUk5mUDA0Lm5hMS5odWJzcG90bGlua3MuY29tL0N0by9EUCsxMTMvZDJSTmZQMDQvVlhmdlNGM3k2WnFZVzM5MUdUbTdGd2NsLVczRGw0U201blFaTEpXMmJwYk5DOGZZQlZsMzExRjEiIGFsdD0iIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBib3JkZXI9IjAiIHN0eWxlPSJkaXNwbGF5Om5vbmUhaW1wb3J0YW50O21pbi1oZWlnaHQ6MXB4IWltcG9ydGFudDt3aWR0aDoxcHghaW1wb3J0YW50O2JvcmRlci13aWR0aDowIWltcG9ydGFudDttYXJnaW4tdG9wOjAhaW1wb3J0YW50O21hcmdpbi1ib3R0b206MCFpbXBvcnRhbnQ7bWFyZ2luLXJpZ2h0OjAhaW1wb3J0YW50O21hcmdpbi1sZWZ0OjAhaW1wb3J0YW50O3BhZGRpbmctdG9wOjAhaW1wb3J0YW50O3BhZGRpbmctYm90dG9tOjAhaW1wb3J0YW50O3BhZGRpbmctcmlnaHQ6MCFpbXBvcnRhbnQ7cGFkZGluZy1sZWZ0OjAhaW1wb3J0YW50Ij48L2JvZHk-PC9odG1sPg==" - } - } - ] - }, - "sizeEstimate": 58097, - "historyId": "528446", - "internalDate": "1732550489000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_05_19363d6a7f50225a_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_05_19363d6a7f50225a_20241126.json deleted file mode 100644 index a73143e..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_05_19363d6a7f50225a_20241126.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "id": "19363d6a7f50225a", - "threadId": "19363d6a7f50225a", - "labelIds": [ - "UNREAD", - "CATEGORY_SOCIAL", - "INBOX" - ], - "snippet": "I was shocked the first time I saw an email thread between CEOs. \u27a1\ufe0f Super\u2026 \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp947819wrq; Mon, 25 Nov 2024 07:00:33 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IEFN1+qQXQRzIufLuGn81fBtiEMpNVd70cc7F1JDgilDRmsroGRc1KakuQdeito894ZaWCJ" - }, - { - "name": "X-Received", - "value": "by 2002:a17:903:1cc:b0:213:1f66:7a0 with SMTP id d9443c01a7336-2131f660bb1mr162505755ad.5.1732546832257; Mon, 25 Nov 2024 07:00:32 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732546832; cv=none; d=google.com; s=arc-20240605; b=OefoSg4Osa/7UqDyfBdsqSwauKWbKt3mgv0CO65iqxq/6tJAToTEgQqKLwRQPjD2rI k1iTVlniP0xAeT7tF9IO5FszCwdxJMtApbZ1w5sgs6dCuhCW8CqaZPiyvRSM48d/EmS0 XU9zPhk1v3CamElaGDy44tgV/B1l+v7KHEyeH1cTrgMJWc2CQo2pq8YvgSLh0Dwi65hE 7+qHqYRTQCIxnFdTnSUCZ/re+ZBIdlsfRI6zbPD19CQ+m3gd0VZXydf1eku+xwx/syge 1XYXvWQlTvuwy48Alwj0W187eulpAdoBX9GLndpNIbSyXgsXWcDBzRpJHV/eDgRFppHq Oyog==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=require-recipient-valid-since:feedback-id:list-unsubscribe-post :list-unsubscribe:date:to:mime-version:subject:message-id:from :dkim-signature:dkim-signature; bh=QJIMampnsNTw4Zkt1PMWLbsgyfglSgJ+8/XrmCsl3fE=; fh=kl8GOc3xH49wmCQ5W74DCe5pDhPNnAeFoI4mGP4/wX4=; b=QtG1E2EuFXHDoOzoBPbZlyUiK3QsGFK+E9AUVyvVedcojVDu7DNTYeIetMQrPoQhyE aBU1SWlhJUhfIPBWOgx3PXCxEYOf79tzmq6+IJmhEngsM/mK3QIRFVxFIPNK6ntATr5l QN0xCBODlttA3zlPodu5X1oYKky6HSadTmNmeFsJCGz2XSL2PNgLSjrIT00vEu0DlqUg 6DGn0y4QGNRHTTu+G++Q/5RTl83KJbPUDw25q1zNPyoXm2S+tJmPRBwZIrOqWlcEfkGl JgXww2mZNo0PJ8YUYxi/V/GFefbJZCPNprtKngB894TrBjwreir+RAVnPG0xMLyMYH2G tKMA==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@maile.linkedin.com header.s=d2048-202308-0e header.b=JRwv1bF1; dkim=pass header.i=@linkedin.com header.s=d2048-202308-00 header.b=A29Lk2pK; spf=pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emfuz3e1jqnvn@bounce.linkedin.com designates 2620:109:c003:104::193 as permitted sender) smtp.mailfrom=m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emfuz3e1jqnvn@bounce.linkedin.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=linkedin.com" - }, - { - "name": "Return-Path", - "value": "" - }, - { - "name": "Received", - "value": "from maile-ca.linkedin.com (maile-ca.linkedin.com. [2620:109:c003:104::193]) by mx.google.com with ESMTPS id d9443c01a7336-2129dcc2421si100253625ad.265.2024.11.25.07.00.31 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 25 Nov 2024 07:00:32 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emfuz3e1jqnvn@bounce.linkedin.com designates 2620:109:c003:104::193 as permitted sender) client-ip=2620:109:c003:104::193;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@maile.linkedin.com header.s=d2048-202308-0e header.b=JRwv1bF1; dkim=pass header.i=@linkedin.com header.s=d2048-202308-00 header.b=A29Lk2pK; spf=pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emfuz3e1jqnvn@bounce.linkedin.com designates 2620:109:c003:104::193 as permitted sender) smtp.mailfrom=m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emfuz3e1jqnvn@bounce.linkedin.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=linkedin.com" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=maile.linkedin.com; s=d2048-202308-0e; t=1732546821; bh=QJIMampnsNTw4Zkt1PMWLbsgyfglSgJ+8/XrmCsl3fE=; h=From:Subject:MIME-Version:Content-Type:To:Date:X-LinkedIn-Class:\t X-LinkedIn-Template:X-LinkedIn-fbl; b=JRwv1bF1ZgWasLaV5ISDB6oRtNvnGdArHv7IH8WuhaNOJS9K9FKUTqls8jNUT9nKW\t qIuO1K8MiNn896sL30tt5C9aHXp9PlcByFX4R1nhF9KmBryfPf7fqyJ9PSU3kUIUji\t CwPW9QR2ebErCuAwYUbTIwzLrEK+tkC1088+vQt8llQdM1UcCq6lTIAHid8sCMgVfk\t U1tEhyImFWHlsoU6/bbL9xWu0zODgSdPu3k/7FMa4BXaTUGLdpatHoeMYQ7NB05hTu\t +/L1oBJNru7tikOJi+Lg5uqDXE9dbIxBHYxDxBpzxexJ4KIqAIBp5f+fM2uLlAALsh\t 8wv8egbBZVVXQ==" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linkedin.com; s=d2048-202308-00; t=1732546821; bh=QJIMampnsNTw4Zkt1PMWLbsgyfglSgJ+8/XrmCsl3fE=; h=From:Subject:MIME-Version:Content-Type:To:Date:X-LinkedIn-Class:\t X-LinkedIn-Template:X-LinkedIn-fbl; b=A29Lk2pKp3MdOrd0ot1HCr426rNkgJG1uG5FwFw3Msav7EiuR3Hu9D8W8sp3Aguk3\t DJ4F8+Q1GyrSAQqp2EG+ej5Mkq0wIFCknKqS+dfIbV0WkXyt5gChl9U9+a0f3q45Sw\t kuc+Hu2npHCSqCS/ZnCEAGFac48iuxjWEZg5Gx+f3TgvaRk+4GbzLj9N3GpWK8gQJ1\t 0NfWqIwPtgD8x22otnhgaIMSe8p/SpmaHTA9is3oWFKy6cK6JiDYF9QCm9L7FUik6l\t doYcPxSEfyY1GOeDv77sE39JNZAInSnaoRLkMyhjpxa+wuZkjrk3e2OD2LcGANTjB6\t 5SXY4dCgRTuNw==" - }, - { - "name": "From", - "value": "LinkedIn Conversations " - }, - { - "name": "Message-ID", - "value": "<2103564692.15888884.1732546821012@lva1-app83618.prod.linkedin.com>" - }, - { - "name": "Subject", - "value": "Khushal, Kyle Coleman has a new post out now" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"----=_Part_15888882_780257305.1732546821006\"" - }, - { - "name": "To", - "value": "Khushal PS " - }, - { - "name": "Date", - "value": "Mon, 25 Nov 2024 15:00:21 +0000 (UTC)" - }, - { - "name": "X-LinkedIn-Class", - "value": "EMAIL-DEFAULT" - }, - { - "name": "X-LinkedIn-Template", - "value": "email_network_conversations_01" - }, - { - "name": "X-LinkedIn-fbl", - "value": "m2-aszvgmongouahf4m5l6zqvhltq38farw322nvqfwdw9s3eg192u3az2ognwtxtplrdia86qo0p50dvbiigckd8r282ipmolfihgoqa" - }, - { - "name": "X-LinkedIn-Id", - "value": "j7zu7i-m3x43csv-2c" - }, - { - "name": "List-Unsubscribe", - "value": "" - }, - { - "name": "List-Unsubscribe-Post", - "value": "List-Unsubscribe=One-Click" - }, - { - "name": "Feedback-ID", - "value": "email_network_conversations_01:linkedin" - }, - { - "name": "Require-Recipient-Valid-Since", - "value": "pskhushal@gmail.com; Mon, 24 Jul 2023 06:55:23 +0000" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain;charset=UTF-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - }, - { - "name": "Content-ID", - "value": "text-body" - } - ], - "body": { - "size": 8151, - "data": "LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoNCg0KICAgICAgICAgIA0KICAgICAgICANCg0KICAgICAgICAgIEt5bGUgQ29sZW1hbiBzaGFyZWQgYSBwb3N0OiBJIHdhcyBzaG9ja2VkIHRoZSBmaXJzdCB0aW1lIEkgc2F3IGFuIGVtYWlsIHRocmVhZCBiZXR3ZWVuIENFT3MuDQoNCuKeoe-4jyBTdXBlciBzaG9ydCBzZW50ZW5jZXMNCuKeoe-4jyBJbXByb3BlciBwdW5jdHVhdGlvbg0K8J-ZgCBTcGVsbGluZyBlcnJvcnMhISANCg0KSXQgd2FzIG1vcmXigKYNCkxJS0UgUFJBSVNFIEVNUEFUSFkgMSwyODksIDIzOCBDb21tZW50cw0KUmVhZCBtb3JlOiBodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2NDcxNjg0MTk3NjA1Mzc2MD9oaWdobGlnaHRlZFVwZGF0ZVVybj11cm4lM0FsaSUzQWFjdGl2aXR5JTNBNzI2NDcxNjg0MTk3NjA1Mzc2MCZzaG93Q29tbWVudEJveD10cnVlJm9yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmbGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJm1pZFRva2VuPUFRRlBhMjNOem8xOEZRJm1pZFNpZz0wRkVyWjdMWHc0RGJ3MSZ0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhfnRleHQtMC1yZWFkfm1vcmUmdHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhfnRleHQtMC1yZWFkfm1vcmUtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmVpZD1qN3p1N2ktbTN4NDNjc3YtMmMmb3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRA0KICAgICAgICANCg0KDQoNCiAgICAgICAgICANCiAgICAgICAgDQoNCiAgICAgICAgICBLaHVzaGkgQWdyYXdhbCBzaGFyZWQgYSBwb3N0OiDwn5qoRGVsZXRlIHRoZXNlIGZyb20geW91ciBDViBub3ch8J-aqA0KSW1hZ2luZSB0aGUgcmVjcnVpdGVyIHNpdHRpbmcgdGhlcmUsIGdvaW5nIHRocm91Z2ggZG96ZW5zIG9mIENWcyBldmVyeSBkYXkuIFdoYXQgbWFrZXMgdGhlbSBzdG9wIGF0IHlvdXJzPyBOb3TigKYNCkxJS0UgUFJBSVNFIEVNUEFUSFkgMjIyLCAxMTEgQ29tbWVudHMNCg0KDQpSZWFkIG1vcmU6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjYzMDk4NjMwMDQ2MTcxMTM3P2hpZ2hsaWdodGVkVXBkYXRlVXJuPXVybiUzQWxpJTNBYWN0aXZpdHklM0E3MjYzMDk4NjMwMDQ2MTcxMTM3JnNob3dDb21tZW50Qm94PXRydWUmb3JpZ2luPU5FVFdPUktfQ09OVkVSU0FUSU9OUyZsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmbWlkVG9rZW49QVFGUGEyM056bzE4RlEmbWlkU2lnPTBGRXJaN0xYdzREYncxJnRyaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGF-dGV4dC0wLXJlYWR-bW9yZSZ0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGF-dGV4dC0wLXJlYWR-bW9yZS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEDQogICAgICAgIA0KDQoNCg0KICAgICAgICAgIA0KICAgICAgICANCg0KICAgICAgICAgIFB1cnZpIEJvdGhyYSBzaGFyZWQgYSBwb3N0OiBPdmVyY29taW5nIEJ1cm5vdXQgaW4gUmVtb3RlIFdvcms6IE15IEV4cGVyaWVuY2UgYW5kIFN0cmF0ZWdpZXMNCg0KQnVybm91dCBpbiByZW1vdGUgd29yayBpcyByZWFsLCBhbmQgSeKAmXZlIHNlZW4gaG93IGl0IGNhbiBzaWxlbnRseSBjcmVlcCBpbnRvIG91cuKApg0KTElLRSBQUkFJU0UgQVBQUkVDSUFUSU9OIDc4LCA1NyBDb21tZW50cw0KUmVhZCBtb3JlOiBodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2MzUzNTAyMjU5MzIyMDYwOD9oaWdobGlnaHRlZFVwZGF0ZVVybj11cm4lM0FsaSUzQWFjdGl2aXR5JTNBNzI2MzUzNTAyMjU5MzIyMDYwOCZzaG93Q29tbWVudEJveD10cnVlJm9yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmbGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJm1pZFRva2VuPUFRRlBhMjNOem8xOEZRJm1pZFNpZz0wRkVyWjdMWHc0RGJ3MSZ0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhfnRleHQtMC1yZWFkfm1vcmUmdHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhfnRleHQtMC1yZWFkfm1vcmUtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmVpZD1qN3p1N2ktbTN4NDNjc3YtMmMmb3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRA0KICAgICAgICANCg0KDQoNCiAgICAgICAgICANCiAgICAgICAgDQoNCiAgICAgICAgICBBbGlzaGEgU2FudGlhZ28gc2hhcmVkIGEgcG9zdDogRGVzcGl0ZSB0aGUgbnVtZXJvdXMgam9iIGludGVydmlld3MgSSd2ZSBwYXJ0aWNpcGF0ZWQgaW4sIEkgc3RpbGwgZmluZCBteXNlbGYgdW5jZXJ0YWluIGFib3V0IHdoZW4gaXQncyBhcHByb3ByaWF0ZSB0byBkaXNjdXNzIHNhbGFyeS4gSW4gbXkgbW9zdOKApg0KTElLRSBQUkFJU0UgRU1QQVRIWSAxNDUsIDg3IENvbW1lbnRzDQpSZWFkIG1vcmU6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjY0MzM4MDczMzkwMzUwMzM2P2hpZ2hsaWdodGVkVXBkYXRlVXJuPXVybiUzQWxpJTNBYWN0aXZpdHklM0E3MjY0MzM4MDczMzkwMzUwMzM2JnNob3dDb21tZW50Qm94PXRydWUmb3JpZ2luPU5FVFdPUktfQ09OVkVSU0FUSU9OUyZsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmbWlkVG9rZW49QVFGUGEyM056bzE4RlEmbWlkU2lnPTBGRXJaN0xYdzREYncxJnRyaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGF-dGV4dC0wLXJlYWR-bW9yZSZ0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGF-dGV4dC0wLXJlYWR-bW9yZS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEDQogICAgICAgIA0KDQoNCg0KICAgICAgICAgIA0KICAgICAgICANCg0KICAgICAgICAgIEF1c3RpbiBCZWxjYWsgc2hhcmVkIGEgcG9zdDogSSBzaGFyZWQgYSBwb3N0IGFib3V0IHdoeSB5b3UgcHVyc3VlIGpvYnMgZXZlbiBpZiB5b3UgZG9u4oCZdCBtZWV0IDEwMCUgb2YgdGhlIHF1YWxpZmljYXRpb25zLg0KDQpNYW55IHBlb3BsZSByZXBsaWVkIHRlbGxpbmcgbWUgaXQgd2FzIOKAnHRlcnJpYmxl4oCmDQpMSUtFIFBSQUlTRSBFTVBBVEhZIDUyNiwgMTE4IENvbW1lbnRzDQpSZWFkIG1vcmU6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjY0MzM4MDcxMTUwNjI4ODY1P2hpZ2hsaWdodGVkVXBkYXRlVXJuPXVybiUzQWxpJTNBYWN0aXZpdHklM0E3MjY0MzM4MDcxMTUwNjI4ODY1JnNob3dDb21tZW50Qm94PXRydWUmb3JpZ2luPU5FVFdPUktfQ09OVkVSU0FUSU9OUyZsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmbWlkVG9rZW49QVFGUGEyM056bzE4RlEmbWlkU2lnPTBGRXJaN0xYdzREYncxJnRyaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGF-dGV4dC0wLXJlYWR-bW9yZSZ0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGF-dGV4dC0wLXJlYWR-bW9yZS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEDQogICAgICAgIA0KDQoNClNlZSBtb3JlIG9uIExpbmtlZEluOiBodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkLz9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmbWlkVG9rZW49QVFGUGEyM056bzE4RlEmbWlkU2lnPTBGRXJaN0xYdzREYncxJnRyaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWZvb3Rlcl9wcm9tby0wLWZvb3Rlcl9zZWVfYWxsJnRya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtZm9vdGVyX3Byb21vLTAtZm9vdGVyX3NlZV9hbGwtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmVpZD1qN3p1N2ktbTN4NDNjc3YtMmMmb3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRA0KICAgICAgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KVGhpcyBlbWFpbCB3YXMgaW50ZW5kZWQgZm9yIEtodXNoYWwgUFMgKC0tKQ0KTGVhcm4gd2h5IHdlIGluY2x1ZGVkIHRoaXM6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9oZWxwL2xpbmtlZGluL2Fuc3dlci80Nzg4P2xhbmc9ZW4mbGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJm1pZFRva2VuPUFRRlBhMjNOem8xOEZRJm1pZFNpZz0wRkVyWjdMWHc0RGJ3MSZ0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1TZWN1cml0eUhlbHAtMC10ZXh0Zm9vdGVyZ2xpbW1lciZ0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLVNlY3VyaXR5SGVscC0wLXRleHRmb290ZXJnbGltbWVyLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJm90cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QNCllvdSBhcmUgcmVjZWl2aW5nIE5ldHdvcmsgQ29udmVyc2F0aW9ucyBlbWFpbHMuIFNvbWUgY29udGVudCBtYXkgYmUgYXV0b21hdGljYWxseSB0cmFuc2xhdGVkIGJhc2VkIG9uDQogICAgICA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vbXlwcmVmZXJlbmNlcy9kL2xhbmd1YWdlLWZvci10cmFuc2xhdGlvbiIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJsaW5rLW5vLXZpc2l0ZWQtc3RhdGUiIGRhdGEtdHJhY2tpbmctd2lsbC1uYXZpZ2F0ZSBkYXRhLXRyYWNraW5nLWNvbnRyb2wtbmFtZT0iZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zX2NvbnRlbnRfc2V0dGluZ3NfbGluayIgc3R5bGU9ImN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IGZvbnQtd2VpZ2h0OiA2MDA7IGNvbG9yOiAjMGE2NmMyOyI-eW91ciBzZXR0aW5nczwvYT4uDQoNClVuc3Vic2NyaWJlOiBodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9wc2V0dGluZ3MvZW1haWwtdW5zdWJzY3JpYmU_bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJm1pZFRva2VuPUFRRlBhMjNOem8xOEZRJm1pZFNpZz0wRkVyWjdMWHc0RGJ3MSZ0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS11bnN1YnNjcmliZS0wLXRleHRmb290ZXJnbGltbWVyJnRya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtdW5zdWJzY3JpYmUtMC10ZXh0Zm9vdGVyZ2xpbW1lci1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZsb2lkPUFRR1NlMFF6V1F4MjZBQUFBWk5qMW5mY3RCalBkV2V6a2lud05HMFVkN3ZZd3NuYWxoMFVzTWFZWWFRM2wzNmZUcnJqOXNjVko5emJjRzgtdENqalhhWEFDQkZEbWpjZ0pCVEZheHNRMFR4MDdpLU5FLVh5LU55V2JnDQpIZWxwOiBodHRwczovL3d3dy5saW5rZWRpbi5jb20vaGVscC9saW5rZWRpbi9hbnN3ZXIvNjc_bGFuZz1lbiZsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmbWlkVG9rZW49QVFGUGEyM056bzE4RlEmbWlkU2lnPTBGRXJaN0xYdzREYncxJnRyaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWhlbHAtMC10ZXh0Zm9vdGVyZ2xpbW1lciZ0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWhlbHAtMC10ZXh0Zm9vdGVyZ2xpbW1lci1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEDQoNCsKpIDIwMjQgTGlua2VkSW4gQ29ycG9yYXRpb24sIDF6d25qMDAwIFdlc3QgTWF1ZGUgQXZlbnVlLCBTdW5ueXZhbGUsIENBIDk0MDg1Lg0KTGlua2VkSW4gYW5kIHRoZSBMaW5rZWRJbiBsb2dvIGFyZSByZWdpc3RlcmVkIHRyYWRlbWFya3Mgb2YgTGlua2VkSW4u" - } - }, - { - "partId": "1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html;charset=UTF-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - }, - { - "name": "Content-ID", - "value": "html-body" - } - ], - "body": { - "size": 102165, - "data": "PGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIGxhbmc9ImVuIiB4bWw6bGFuZz0iZW4iPiA8aGVhZD4gPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7Y2hhcnNldD11dGYtOCI-IDxtZXRhIG5hbWU9IkhhbmRoZWxkRnJpZW5kbHkiIGNvbnRlbnQ9InRydWUiPiA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoOyBpbml0aWFsLXNjYWxlPTAuNjY2NjY3OyB1c2VyLXNjYWxhYmxlPTAiPiA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoIj4gPHRpdGxlPjwvdGl0bGU-IDxzdHlsZT4NCiAgICAgICAgICAgIEBtZWRpYSAobWF4LXdpZHRoOiA1MTJweCkgeyAubWVyY2Fkby1jb250YWluZXIgeyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyB9IH0NCiAgICAgICAgICA8L3N0eWxlPiA8c3R5bGU-DQogICAgICAgICAgICBAbWVkaWEgKG1heC13aWR0aDogNDgwcHgpIHsgLmlubGluZS1idXR0b24sIC5pbmxpbmUtYnV0dG9uIHRhYmxlIHsgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50OyB9DQogICAgICAgICAgICAuZnVsbC13aWR0aC1idXR0b24sIC5mdWxsLXdpZHRoLWJ1dHRvbiB0YWJsZSB7IGRpc3BsYXk6IHRhYmxlICFpbXBvcnRhbnQ7IH0gfQ0KICAgICAgICAgIDwvc3R5bGU-IDxzdHlsZT5ib2R5IHtmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgc3lzdGVtLXVpLCBCbGlua01hY1N5c3RlbUZvbnQsICdTZWdvZSBVSScsIFJvYm90bywgJ0hlbHZldGljYSBOZXVlJywNCiAgICAgICAgICAgICdGaXJhIFNhbnMnLCBVYnVudHUsIE94eWdlbiwgJ094eWdlbiBTYW5zJywgQ2FudGFyZWxsLCAnRHJvaWQgU2FucycsICdBcHBsZSBDb2xvciBFbW9qaScsICdTZWdvZSBVSSBFbW9qaScsDQogICAgICAgICAgICAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgU3ltYm9sJywgJ0x1Y2lkYSBHcmFuZGUnLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmO308L3N0eWxlPiA8IS0tW2lmIG1zb10-PHN0eWxlIHR5cGU9InRleHQvY3NzIj4gPC9zdHlsZT48IVtlbmRpZl0tLT4gPCEtLVtpZiBJRV0-PHN0eWxlIHR5cGU9InRleHQvY3NzIj4gPC9zdHlsZT48IVtlbmRpZl0tLT4gPC9oZWFkPiA8Ym9keSBkaXI9Imx0ciIgY2xhc3M9ImZvbnQtc2FucyBiZy1jb2xvci1iYWNrZ3JvdW5kLWNhbnZhcyB3LWZ1bGwgbS0wIHAtMCBwdC0xIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbWFyZ2luOiAwcHg7IHdpZHRoOiAxMDAlOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjNmMmYwOyBwYWRkaW5nOiAwcHg7IHBhZGRpbmctdG9wOiA4cHg7IGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBzeXN0ZW0tdWksIEJsaW5rTWFjU3lzdGVtRm9udCwgJ1NlZ29lIFVJJywgUm9ib3RvLCAnSGVsdmV0aWNhIE5ldWUnLCAnRmlyYSBTYW5zJywgVWJ1bnR1LCBPeHlnZW4sICdPeHlnZW4gU2FucycsIENhbnRhcmVsbCwgJ0Ryb2lkIFNhbnMnLCAnQXBwbGUgQ29sb3IgRW1vamknLCAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgU3ltYm9sJywgJ0x1Y2lkYSBHcmFuZGUnLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmOyI-IDxkaXYgY2xhc3M9ImgtMCBvcGFjaXR5LTAgdGV4dC10cmFuc3BhcmVudCBpbnZpc2libGUgb3ZlcmZsb3ctaGlkZGVuIHctMCBtYXgtaC1bMF0iIHN0eWxlPSJ2aXNpYmlsaXR5OiBoaWRkZW47IGhlaWdodDogMHB4OyBtYXgtaGVpZ2h0OiAwOyB3aWR0aDogMHB4OyBvdmVyZmxvdzogaGlkZGVuOyBvcGFjaXR5OiAwOyBtc28taGlkZTogYWxsOyIgZGF0YS1lbWFpbC1wcmVoZWFkZXI9InRydWUiPkkgd2FzIHNob2NrZWQgdGhlIGZpcnN0IHRpbWUgSSBzYXcgYW4gZW1haWwgdGhyZWFkIGJldHdlZW4gQ0VPcy4g4p6h77iPIFN1cGVy4oCmPC9kaXY-IDxkaXYgY2xhc3M9ImgtMCBvcGFjaXR5LTAgdGV4dC10cmFuc3BhcmVudCBpbnZpc2libGUgb3ZlcmZsb3ctaGlkZGVuIHctMCBtYXgtaC1bMF0iIHN0eWxlPSJ2aXNpYmlsaXR5OiBoaWRkZW47IGhlaWdodDogMHB4OyBtYXgtaGVpZ2h0OiAwOyB3aWR0aDogMHB4OyBvdmVyZmxvdzogaGlkZGVuOyBvcGFjaXR5OiAwOyBtc28taGlkZTogYWxsOyI-IM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgPC9kaXY-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjUxMiIgYWxpZ249ImNlbnRlciIgY2xhc3M9Im1lcmNhZG8tY29udGFpbmVyIHctWzUxMnB4XSBtYXgtdy1bNTEycHhdIG14LWF1dG8gbXktMCBwLTAgYmctY29sb3ItYmFja2dyb3VuZC1jb250YWluZXIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgbWFyZ2luLXRvcDogMHB4OyBtYXJnaW4tYm90dG9tOiAwcHg7IG1hcmdpbi1sZWZ0OiBhdXRvOyBtYXJnaW4tcmlnaHQ6IGF1dG87IHdpZHRoOiA1MTJweDsgbWF4LXdpZHRoOiA1MTJweDsgYmFja2dyb3VuZC1jb2xvcjogI2ZmZmZmZjsgcGFkZGluZzogMHB4OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9InRleHQtY2VudGVyIHAtMyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nOiAyNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgY2xhc3M9Im1pbi13LWZ1bGwiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgbWluLXdpZHRoOiAxMDAlOyI-IDx0Ym9keT4gPHRyPiA8dGQgYWxpZ249ImxlZnQiIHZhbGlnbj0ibWlkZGxlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC8_bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1oZWFkZXItMC1ob21lX2dsaW1tZXJfZHluYW1pY19iYWRnaW5nX2hpZ2hfZHBpJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWhlYWRlci0wLWhvbWVfZ2xpbW1lcl9keW5hbWljX2JhZGdpbmdfaGlnaF9kcGktbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgY2xhc3M9InctWzg0cHhdIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHdpZHRoOiA4NHB4OyI-IDxpbWcgY2xhc3M9ImgtWzM3cHhdIHctWzEwMXB4XSIgYWx0PSJMaW5rZWRJbiIgc3JjPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9kbXMvbG9nby92Mj9iYWRnZVRoZW1lPW1lcmNhZG8mYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1udWxsLTAtY29tbXMlN0ViYWRnaW5nJTdFZHluYW1pYyU3RWdsaW1tZXIlN0V2Mi1udWxsLWo3enU3aSU3RW0zeDQzY3N2JTdFMmMtbnVsbC1udWxsJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1udWxsLTAtY29tbXMlN0ViYWRnaW5nJTdFZHluYW1pYyU3RWdsaW1tZXIlN0V2MiZhbXA7X3NpZz0wcDFBZ2xuREE0RGJ3MSIgZGF0YS10ZXN0LWhlYWRlci1keW5hbWljLWJhZGdpbmctaW1nLWhpZ2gtZHBpIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGhlaWdodDogMzdweDsgd2lkdGg6IDEwMXB4OyIgd2lkdGg9IjEwMSIgaGVpZ2h0PSIzNyI-IDwvYT4gPC90ZD4gPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0icmlnaHQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBkYXRhLXRlc3QtaGVhZGVyLXByb2ZpbGUgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgYWxpZ249InJpZ2h0IiB2YWxpZ249Im1pZGRsZSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDxhIGhyZWY9Imh0dHBzOi8vaW4ubGlua2VkaW4uY29tL2NvbW0vaW4va2h1c2hhbC1wcy03YTYyYjcyODU_bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1oZWFkZXItMC1wcm9maWxlX2dsaW1tZXImYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtaGVhZGVyLTAtcHJvZmlsZV9nbGltbWVyLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsiPiA8c3BhbiBjbGFzcz0ibm8tdW5kZXJsaW5lIHRleHQtc3lzdGVtLWdyYXktOTAiIHN0eWxlPSJjb2xvcjogIzI4MjgyODsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij5LaHVzaGFsIFBTPC9zcGFuPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwLTAgIXBiLTAgcGItMyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nOiAwcHg7IHBhZGRpbmctYm90dG9tOiAwcHggIWltcG9ydGFudDsiPiA8ZGl2PiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0icC0zIGJvcmRlci0wIGJvcmRlci1iLTEgYm9yZGVyLXNvbGlkIGJvcmRlci1zeXN0ZW0tZ3JheS0zMCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItd2lkdGg6IDA7IGJvcmRlci1ib3R0b20td2lkdGg6IDFweDsgYm9yZGVyLXN0eWxlOiBzb2xpZDsgYm9yZGVyLWNvbG9yOiAjZTZlNmU2OyBwYWRkaW5nOiAyNHB4OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjY0NzE2ODQxOTc2MDUzNzYwP29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0LTAtd3JhcHBlcn5saW5rJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdC0wLXdyYXBwZXJ-bGluay1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0idy1mdWxsIiBkYXRhLXRlc3QtaWQ9Im5ldHdvcmstcG9zdC1saW5rIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHdpZHRoOiAxMDAlOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC91cGRhdGUvdXJuOmxpOmFjdGl2aXR5OjcyNjQ3MTY4NDE5NzYwNTM3NjA_aGlnaGxpZ2h0ZWRVcGRhdGVVcm49dXJuJTNBbGklM0FhY3Rpdml0eSUzQTcyNjQ3MTY4NDE5NzYwNTM3NjAmYW1wO3Nob3dDb21tZW50Qm94PXRydWUmYW1wO29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtYWN0b3JfY2FyZCZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1hY3Rvcl9jYXJkLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJibG9jayIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtbGluayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgZGlzcGxheTogYmxvY2s7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyIGRhdGEtdGVzdC1pZD0idjJzdHlsZS1kaXNhYmxlIj4gPHRkIGNsYXNzPSJ3LVs3MnB4XSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB3aWR0aDogNzJweDsiIHdpZHRoPSI3MiI-IDxpbWcgY2xhc3M9ImlubGluZS1ibG9jayByZWxhdGl2ZSBiZy1jb2xvci1lbnRpdHktZ2hvc3QtYmFja2dyb3VuZCBjbGlwLXBhdGgtY2lyY2xlLTUwIHJvdW5kZWQtZnVsbCB3LTYgaC02ICF3LVs3MnB4XSAhaC1bNzJweF0gIWJsb2NrIiBzcmM9Imh0dHBzOi8vbWVkaWEubGljZG4uY29tL2Rtcy9pbWFnZS92Mi9DNEQwM0FRSExib2l4VFU0QkdRL3Byb2ZpbGUtZGlzcGxheXBob3RvLXNocmlua180MDBfNDAwL3Byb2ZpbGUtZGlzcGxheXBob3RvLXNocmlua180MDBfNDAwLzAvMTY0Mzg1MDY2MzU5OT9lPTIxNDc0ODM2NDcmYW1wO3Y9YmV0YSZhbXA7dD02RWJXZnhOOEpZMC1FWjZXN0xaRTd3cGsxNVZXdHJQeERXbnBIWm9XdVlzIiBhbHQ9Ikt5bGUgQ29sZW1hbiIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgcG9zaXRpb246IHJlbGF0aXZlOyBib3JkZXItcmFkaXVzOiA5OTk5cHg7IGJhY2tncm91bmQtY29sb3I6ICNlYWU2ZGY7IGNsaXAtcGF0aDogY2lyY2xlKDUwJSk7IGRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7IGhlaWdodDogNzJweCAhaW1wb3J0YW50OyB3aWR0aDogNzJweCAhaW1wb3J0YW50OyIgd2lkdGg9IjcyIiBoZWlnaHQ9IjcyIj4gPC90ZD4gPHRkIGNsYXNzPSJwbC0xIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctbGVmdDogOHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJmb250LWJvbGQgdGV4dC1tZCBsZWFkaW5nLXJlZ3VsYXIgdGV4dC1zeXN0ZW0tZ3JheS05MCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE2cHg7IGZvbnQtd2VpZ2h0OiA2MDA7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzI4MjgyODsiPiBLeWxlIENvbGVtYW4gPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0iYWN0b3ItY2FyZC1oZWFkbGluZSI-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLVsxNnB4XSB0ZXh0LWNvbG9yLXRleHQtc29saWQtc2Vjb25kYXJ5IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGZvbnQtc2l6ZTogMTRweDsgbGluZS1oZWlnaHQ6IDE2cHg7IGNvbG9yOiAjNjY2NjY2OyI-IENNTyBAIENvcHkuYWkgfHwgSGVscGluZyBjb21wYW5pZXMgZWxpbWluYXRlIEdUTSBCbG9hdOKApiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDx0ZCBjbGFzcz0icGwtMSBtdC1bMjJweF0gbXItMSBpbmxpbmUtYmxvY2siIGRhdGEtdGVzdC1pZD0ibmV0d29yay1wb3N0LWZvbGxvdy1jdGEiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgbWFyZ2luLXJpZ2h0OiA4cHg7IG1hcmdpbi10b3A6IDIycHg7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgcGFkZGluZy1sZWZ0OiA4cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgY2xhc3M9ImVtYWlsLWJ1dHRvbiAiIGRhdGEtdGVzdC1pZD0iZW1haWwtYnV0dG9uIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249Im1pZGRsZSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2J1aWxkLXJlbGF0aW9uL3Blb3BsZS1mb2xsb3cvP2VudGl0eU5hbWU9a3lsZXRjb2xlbWFuJmFtcDtlbnRpdHlVcm49QURvQUFBWVItZWtCS3VNM2oxZko5UlY5V2cwRnczZ2dTOEpQcXhzJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtZm9sbG93X2N0YS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBhcmlhLWxhYmVsPSJGb2xsb3ciIGNsYXNzPSJhbGlnbi10b3Agbm8tdW5kZXJsaW5lICIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB2ZXJ0aWNhbC1hbGlnbjogdG9wOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSJhdXRvIiBjbGFzcz0iYm9yZGVyLXNlcGFyYXRlICIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IHNlcGFyYXRlOyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImJ0bi1zbSBidG4tdGVydGlhcnktZW1waGFzaXMgYm9yZGVyLW5vbmUgYnV0dG9uLWxpbmsgbGVhZGluZy1yZWd1bGFyICFtaW4taC1bYXV0b10gIXNoYWRvdy1ub25lIGJvcmRlci0xIGJvcmRlci1zb2xpZCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBoZWlnaHQ6IG1pbi1jb250ZW50OyBib3JkZXItcmFkaXVzOiAyNHB4OyBwYWRkaW5nLXRvcDogN3B4OyBwYWRkaW5nLWJvdHRvbTogN3B4OyBwYWRkaW5nLWxlZnQ6IDE2cHg7IHBhZGRpbmctcmlnaHQ6IDE2cHg7IHRleHQtYWxpZ246IGNlbnRlcjsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogNjAwOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDAsIDAsIDAsIDApOyBjb2xvcjogIzBhNjZjMjsgYm9yZGVyLXdpZHRoOiAxcHg7IGJvcmRlci1zdHlsZTogbm9uZTsgbGluZS1oZWlnaHQ6IDEuMjU7IG1pbi1oZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsgYm94LXNoYWRvdzogMCAwICMwMDAwLCAwIDAgIzAwMDAsIDAgMCAjMDAwMCAhaW1wb3J0YW50OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2J1aWxkLXJlbGF0aW9uL3Blb3BsZS1mb2xsb3cvP2VudGl0eU5hbWU9a3lsZXRjb2xlbWFuJmFtcDtlbnRpdHlVcm49QURvQUFBWVItZWtCS3VNM2oxZko5UlY5V2cwRnczZ2dTOEpQcXhzJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtZm9sbG93X2N0YS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiB0YWJpbmRleD0iLTEiIGFyaWEtaGlkZGVuPSJ0cnVlIiBjbGFzcz0ibm8tdW5kZXJsaW5lIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IDxzcGFuIGNsYXNzPSJuby11bmRlcmxpbmUgIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gRm9sbG93IDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwdC0yIHRleHQtbWQgbGVhZGluZy1yZWd1bGFyIHRleHQtc3lzdGVtLWdyYXktOTAiIGNvbHNwYW49IjIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7IGZvbnQtc2l6ZTogMTZweDsgbGluZS1oZWlnaHQ6IDEuMjU7IGNvbG9yOiAjMjgyODI4OyI-IDxzcGFuIGRhdGEtdGVzdC1pZD0idHJ1bmNhdGVkLW1lc3NhZ2UtdGV4dCI-IEkgd2FzIHNob2NrZWQgdGhlIGZpcnN0IHRpbWUgSSBzYXcgYW4gZW1haWwgdGhyZWFkIGJldHdlZW4gQ0VPcy4g4p6h77iPIFN1cGVyIHNob3J0IHNlbnRlbmNlcyDinqHvuI8gSW1wcm9wZXLigKYgPC9zcGFuPiA8c3BhbiBkYXRhLXRlc3QtaWQ9InRydW5jYXRlZC1tZXNzYWdlLXNlZS1tb3JlIiBjbGFzcz0idGV4dC1jb2xvci1saW5rIGZvbnQtYm9sZCIgc3R5bGU9ImZvbnQtd2VpZ2h0OiA2MDA7IGNvbG9yOiAjMGE2NmMyOyI-IHNlZSBtb3JlIDwvc3Bhbj4gPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0ibmV0d29yay1wb3N0LXNvY2lhbC1tZXRhZGF0YSI-IDx0ZCBjbGFzcz0icHQtMiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXRvcDogMTZweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSJhdXRvIiBjbGFzcz0idy1hdXRvIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHdpZHRoOiBhdXRvOyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9InByLTAuNSIgZGF0YS10ZXN0LXJlYWN0aW9uPSJMSUtFIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctcmlnaHQ6IDRweDsiPiA8aW1nIGNsYXNzPSJibG9jayB3LTIgaC0yIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9zYy9oLzkxdGRzY24waDFhYW9lZnVpOWNyZjExajYiIGFsdD0iTElLRSIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgZGlzcGxheTogYmxvY2s7IGhlaWdodDogMTZweDsgd2lkdGg6IDE2cHg7IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiPiA8L3RkPiA8dGQgY2xhc3M9InByLTAuNSIgZGF0YS10ZXN0LXJlYWN0aW9uPSJQUkFJU0UiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1yaWdodDogNHB4OyI-IDxpbWcgY2xhc3M9ImJsb2NrIHctMiBoLTIiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL3NjL2gvYWRpZzV1cnF4aTAzcXp1eTZpeWpmbTFiNSIgYWx0PSJQUkFJU0UiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGRpc3BsYXk6IGJsb2NrOyBoZWlnaHQ6IDE2cHg7IHdpZHRoOiAxNnB4OyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij4gPC90ZD4gPHRkIGNsYXNzPSJwci0wLjUiIGRhdGEtdGVzdC1yZWFjdGlvbj0iRU1QQVRIWSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXJpZ2h0OiA0cHg7Ij4gPGltZyBjbGFzcz0iYmxvY2sgdy0yIGgtMiIgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vc2MvaC9ldnMyeDV6Zm56NWcweHJjNnUyMnRyZXEyIiBhbHQ9IkVNUEFUSFkiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGRpc3BsYXk6IGJsb2NrOyBoZWlnaHQ6IDE2cHg7IHdpZHRoOiAxNnB4OyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij4gPC90ZD4gPHRkIGNsYXNzPSJ0ZXh0LXNtIGxlYWRpbmctcmVndWxhciBmb250LW5vcm1hbCB0ZXh0LXN5c3RlbS1ncmF5LTcwIiBkYXRhLXRlc3QtaWQ9InJlYWN0aW9ucy1jb3VudCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiA0MDA7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzY2NjY2NjsiPiAxLDI4OSA8L3RkPiA8dGQgY2xhc3M9InB4LTAuNSIgZGF0YS10ZXN0LWlkPSJzZXBhcmF0b3IiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1sZWZ0OiA0cHg7IHBhZGRpbmctcmlnaHQ6IDRweDsiPsK3PC90ZD4gPHRkIGNsYXNzPSJ0ZXh0LXNtIGxlYWRpbmctcmVndWxhciBmb250LW5vcm1hbCB0ZXh0LXN5c3RlbS1ncmF5LTcwIiBkYXRhLXRlc3QtaWQ9ImNvbW1lbnRzLWNvdW50IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IDQwMDsgbGluZS1oZWlnaHQ6IDEuMjU7IGNvbG9yOiAjNjY2NjY2OyI-IDIzOCBDb21tZW50cyA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8dHIgZGF0YS10ZXN0LWlkPSJyZWFkLW1vcmUtY3RhLWJsb2NrIj4gPHRkIGNsYXNzPSJwdC0zIiBjb2xzcGFuPSIyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctdG9wOiAyNHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGNsYXNzPSJlbWFpbC1idXR0b24gdy1mdWxsIGtvc2hpbl9fYnV0dG9uLXdpdGgtZnVsbC13aWR0aCIgZGF0YS10ZXN0LWlkPSJlbWFpbC1idXR0b24iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgd2lkdGg6IDEwMCU7Ij4gPHRib2R5PiA8dHI-IDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249Im1pZGRsZSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjY0NzE2ODQxOTc2MDUzNzYwP29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhLTAtcmVhZH5tb3JlLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGFyaWEtbGFiZWw9IlJlYWQgbW9yZSIgY2xhc3M9ImFsaWduLXRvcCBuby11bmRlcmxpbmUgIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB2ZXJ0aWNhbC1hbGlnbjogdG9wOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iYm9yZGVyLXNlcGFyYXRlICIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IHNlcGFyYXRlOyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImJ0bi1tZCBidG4tc2Vjb25kYXJ5LWVtcGhhc2lzIGJvcmRlci1jb2xvci1icmFuZCBidXR0b24tbGluayBsZWFkaW5nLXJlZ3VsYXIgIW1pbi1oLVthdXRvXSAhc2hhZG93LW5vbmUgYm9yZGVyLTEgYm9yZGVyLXNvbGlkIiBkYXRhLXRlc3QtaWQ9InJlYWQtbW9yZS1jdGEtYmVsb3ciIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgaGVpZ2h0OiBtaW4tY29udGVudDsgYm9yZGVyLXJhZGl1czogMjRweDsgcGFkZGluZy10b3A6IDEycHg7IHBhZGRpbmctYm90dG9tOiAxMnB4OyBwYWRkaW5nLWxlZnQ6IDI0cHg7IHBhZGRpbmctcmlnaHQ6IDI0cHg7IHRleHQtYWxpZ246IGNlbnRlcjsgZm9udC1zaXplOiAxNnB4OyBmb250LXdlaWdodDogNjAwOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDAsIDAsIDAsIDApOyBjb2xvcjogIzBhNjZjMjsgYm9yZGVyLXdpZHRoOiAxcHg7IGJvcmRlci1zdHlsZTogc29saWQ7IGJvcmRlci1jb2xvcjogIzBhNjZjMjsgbGluZS1oZWlnaHQ6IDEuMjU7IG1pbi1oZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsgYm94LXNoYWRvdzogMCAwICMwMDAwLCAwIDAgIzAwMDAsIDAgMCAjMDAwMCAhaW1wb3J0YW50OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjY0NzE2ODQxOTc2MDUzNzYwP29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhLTAtcmVhZH5tb3JlLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIHRhYmluZGV4PSItMSIgYXJpYS1oaWRkZW49InRydWUiIGNsYXNzPSJuby11bmRlcmxpbmUiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyBkaXNwbGF5OiBibG9jayAhaW1wb3J0YW50OyI-IDxzcGFuIGNsYXNzPSJuby11bmRlcmxpbmUgdGV4dC1jb2xvci1icmFuZCIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiBSZWFkIG1vcmUgPC9zcGFuPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvYT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icC0zIGJvcmRlci0wIGJvcmRlci1iLTEgYm9yZGVyLXNvbGlkIGJvcmRlci1zeXN0ZW0tZ3JheS0zMCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItd2lkdGg6IDA7IGJvcmRlci1ib3R0b20td2lkdGg6IDFweDsgYm9yZGVyLXN0eWxlOiBzb2xpZDsgYm9yZGVyLWNvbG9yOiAjZTZlNmU2OyBwYWRkaW5nOiAyNHB4OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjYzMDk4NjMwMDQ2MTcxMTM3P29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0LTAtd3JhcHBlcn5saW5rJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdC0wLXdyYXBwZXJ-bGluay1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0idy1mdWxsIiBkYXRhLXRlc3QtaWQ9Im5ldHdvcmstcG9zdC1saW5rIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHdpZHRoOiAxMDAlOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC91cGRhdGUvdXJuOmxpOmFjdGl2aXR5OjcyNjMwOTg2MzAwNDYxNzExMzc_aGlnaGxpZ2h0ZWRVcGRhdGVVcm49dXJuJTNBbGklM0FhY3Rpdml0eSUzQTcyNjMwOTg2MzAwNDYxNzExMzcmYW1wO3Nob3dDb21tZW50Qm94PXRydWUmYW1wO29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtYWN0b3JfY2FyZCZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1hY3Rvcl9jYXJkLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJibG9jayIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtbGluayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgZGlzcGxheTogYmxvY2s7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyIGRhdGEtdGVzdC1pZD0idjJzdHlsZS1kaXNhYmxlIj4gPHRkIGNsYXNzPSJ3LVs3MnB4XSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB3aWR0aDogNzJweDsiIHdpZHRoPSI3MiI-IDxpbWcgY2xhc3M9ImlubGluZS1ibG9jayByZWxhdGl2ZSBiZy1jb2xvci1lbnRpdHktZ2hvc3QtYmFja2dyb3VuZCBjbGlwLXBhdGgtY2lyY2xlLTUwIHJvdW5kZWQtZnVsbCB3LTYgaC02ICF3LVs3MnB4XSAhaC1bNzJweF0gIWJsb2NrIiBzcmM9Imh0dHBzOi8vbWVkaWEubGljZG4uY29tL2Rtcy9pbWFnZS92Mi9ENEQwM0FRRm8tWkhqLU4wZlFnL3Byb2ZpbGUtZGlzcGxheXBob3RvLXNocmlua180MDBfNDAwL3Byb2ZpbGUtZGlzcGxheXBob3RvLXNocmlua180MDBfNDAwLzAvMTcyMjQxMzMzODM5OD9lPTIxNDc0ODM2NDcmYW1wO3Y9YmV0YSZhbXA7dD1sVC0wRk5xNmFmUmlXbkoyWHNrTnZPQTkwWXBXOURUTVJGY2JTbFNnanU4IiBhbHQ9IktodXNoaSBBZ3Jhd2FsIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBwb3NpdGlvbjogcmVsYXRpdmU7IGJvcmRlci1yYWRpdXM6IDk5OTlweDsgYmFja2dyb3VuZC1jb2xvcjogI2VhZTZkZjsgY2xpcC1wYXRoOiBjaXJjbGUoNTAlKTsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsgaGVpZ2h0OiA3MnB4ICFpbXBvcnRhbnQ7IHdpZHRoOiA3MnB4ICFpbXBvcnRhbnQ7IiB3aWR0aD0iNzIiIGhlaWdodD0iNzIiPiA8L3RkPiA8dGQgY2xhc3M9InBsLTEiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1sZWZ0OiA4cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImZvbnQtYm9sZCB0ZXh0LW1kIGxlYWRpbmctcmVndWxhciB0ZXh0LXN5c3RlbS1ncmF5LTkwIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGZvbnQtc2l6ZTogMTZweDsgZm9udC13ZWlnaHQ6IDYwMDsgbGluZS1oZWlnaHQ6IDEuMjU7IGNvbG9yOiAjMjgyODI4OyI-IEtodXNoaSBBZ3Jhd2FsIDwvdGQ-IDwvdHI-IDx0ciBkYXRhLXRlc3QtaWQ9ImFjdG9yLWNhcmQtaGVhZGxpbmUiPiA8dGQgY2xhc3M9InRleHQtc20gbGVhZGluZy1bMTZweF0gdGV4dC1jb2xvci10ZXh0LXNvbGlkLXNlY29uZGFyeSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE0cHg7IGxpbmUtaGVpZ2h0OiAxNnB4OyBjb2xvcjogIzY2NjY2NjsiPiBTb2Z0d2FyZSBFbmdpbmVlciB8fCBFeCBTREUgSW50ZXJuIEAgSVRKT0JYUyxHRkcgfHzigKYgPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC9hPiA8L3RkPiA8dGQgY2xhc3M9InBsLTEgbXQtWzIycHhdIG1yLTEgaW5saW5lLWJsb2NrIiBkYXRhLXRlc3QtaWQ9Im5ldHdvcmstcG9zdC1mb2xsb3ctY3RhIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IG1hcmdpbi1yaWdodDogOHB4OyBtYXJnaW4tdG9wOiAyMnB4OyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHBhZGRpbmctbGVmdDogOHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGNsYXNzPSJlbWFpbC1idXR0b24gIiBkYXRhLXRlc3QtaWQ9ImVtYWlsLWJ1dHRvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJtaWRkbGUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9idWlsZC1yZWxhdGlvbi9wZW9wbGUtZm9sbG93Lz9lbnRpdHlOYW1lPWtodXNoaS1hZ3Jhd2FsLXplcm90d28mYW1wO2VudGl0eVVybj1BRG9BQURPLWxvY0JySnRLQXVhaldQczJHbmhENWR0dVUxUmNpVWsmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtZm9sbG93X2N0YSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1mb2xsb3dfY3RhLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGFyaWEtbGFiZWw9IkZvbGxvdyIgY2xhc3M9ImFsaWduLXRvcCBuby11bmRlcmxpbmUgIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHZlcnRpY2FsLWFsaWduOiB0b3A7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9ImF1dG8iIGNsYXNzPSJib3JkZXItc2VwYXJhdGUgIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogc2VwYXJhdGU7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0iYnRuLXNtIGJ0bi10ZXJ0aWFyeS1lbXBoYXNpcyBib3JkZXItbm9uZSBidXR0b24tbGluayBsZWFkaW5nLXJlZ3VsYXIgIW1pbi1oLVthdXRvXSAhc2hhZG93LW5vbmUgYm9yZGVyLTEgYm9yZGVyLXNvbGlkIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGhlaWdodDogbWluLWNvbnRlbnQ7IGJvcmRlci1yYWRpdXM6IDI0cHg7IHBhZGRpbmctdG9wOiA3cHg7IHBhZGRpbmctYm90dG9tOiA3cHg7IHBhZGRpbmctbGVmdDogMTZweDsgcGFkZGluZy1yaWdodDogMTZweDsgdGV4dC1hbGlnbjogY2VudGVyOyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiA2MDA7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7IGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMCk7IGNvbG9yOiAjMGE2NmMyOyBib3JkZXItd2lkdGg6IDFweDsgYm9yZGVyLXN0eWxlOiBub25lOyBsaW5lLWhlaWdodDogMS4yNTsgbWluLWhlaWdodDogYXV0byAhaW1wb3J0YW50OyBib3gtc2hhZG93OiAwIDAgIzAwMDAsIDAgMCAjMDAwMCwgMCAwICMwMDAwICFpbXBvcnRhbnQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vYnVpbGQtcmVsYXRpb24vcGVvcGxlLWZvbGxvdy8_ZW50aXR5TmFtZT1raHVzaGktYWdyYXdhbC16ZXJvdHdvJmFtcDtlbnRpdHlVcm49QURvQUFETy1sb2NCckp0S0F1YWpXUHMyR25oRDVkdHVVMVJjaVVrJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtZm9sbG93X2N0YS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiB0YWJpbmRleD0iLTEiIGFyaWEtaGlkZGVuPSJ0cnVlIiBjbGFzcz0ibm8tdW5kZXJsaW5lIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IDxzcGFuIGNsYXNzPSJuby11bmRlcmxpbmUgIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gRm9sbG93IDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwdC0yIHRleHQtbWQgbGVhZGluZy1yZWd1bGFyIHRleHQtc3lzdGVtLWdyYXktOTAiIGNvbHNwYW49IjIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7IGZvbnQtc2l6ZTogMTZweDsgbGluZS1oZWlnaHQ6IDEuMjU7IGNvbG9yOiAjMjgyODI4OyI-IDxzcGFuIGRhdGEtdGVzdC1pZD0idHJ1bmNhdGVkLW1lc3NhZ2UtdGV4dCI-IPCfmqhEZWxldGUgdGhlc2UgZnJvbSB5b3VyIENWIG5vdyHwn5qoIEltYWdpbmUgdGhlIHJlY3J1aXRlciBzaXR0aW5nIHRoZXJlLCBnb2luZyB0aHJvdWdoIGRvemVucyBvZiBDVnMgZXZlcnnigKYgPC9zcGFuPiA8c3BhbiBkYXRhLXRlc3QtaWQ9InRydW5jYXRlZC1tZXNzYWdlLXNlZS1tb3JlIiBjbGFzcz0idGV4dC1jb2xvci1saW5rIGZvbnQtYm9sZCIgc3R5bGU9ImZvbnQtd2VpZ2h0OiA2MDA7IGNvbG9yOiAjMGE2NmMyOyI-IHNlZSBtb3JlIDwvc3Bhbj4gPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0ibmV0d29yay1wb3N0LXNvY2lhbC1tZXRhZGF0YSI-IDx0ZCBjbGFzcz0icHQtMiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXRvcDogMTZweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSJhdXRvIiBjbGFzcz0idy1hdXRvIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHdpZHRoOiBhdXRvOyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9InByLTAuNSIgZGF0YS10ZXN0LXJlYWN0aW9uPSJMSUtFIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctcmlnaHQ6IDRweDsiPiA8aW1nIGNsYXNzPSJibG9jayB3LTIgaC0yIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9zYy9oLzkxdGRzY24waDFhYW9lZnVpOWNyZjExajYiIGFsdD0iTElLRSIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgZGlzcGxheTogYmxvY2s7IGhlaWdodDogMTZweDsgd2lkdGg6IDE2cHg7IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiPiA8L3RkPiA8dGQgY2xhc3M9InByLTAuNSIgZGF0YS10ZXN0LXJlYWN0aW9uPSJQUkFJU0UiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1yaWdodDogNHB4OyI-IDxpbWcgY2xhc3M9ImJsb2NrIHctMiBoLTIiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL3NjL2gvYWRpZzV1cnF4aTAzcXp1eTZpeWpmbTFiNSIgYWx0PSJQUkFJU0UiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGRpc3BsYXk6IGJsb2NrOyBoZWlnaHQ6IDE2cHg7IHdpZHRoOiAxNnB4OyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij4gPC90ZD4gPHRkIGNsYXNzPSJwci0wLjUiIGRhdGEtdGVzdC1yZWFjdGlvbj0iRU1QQVRIWSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXJpZ2h0OiA0cHg7Ij4gPGltZyBjbGFzcz0iYmxvY2sgdy0yIGgtMiIgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vc2MvaC9ldnMyeDV6Zm56NWcweHJjNnUyMnRyZXEyIiBhbHQ9IkVNUEFUSFkiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGRpc3BsYXk6IGJsb2NrOyBoZWlnaHQ6IDE2cHg7IHdpZHRoOiAxNnB4OyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij4gPC90ZD4gPHRkIGNsYXNzPSJ0ZXh0LXNtIGxlYWRpbmctcmVndWxhciBmb250LW5vcm1hbCB0ZXh0LXN5c3RlbS1ncmF5LTcwIiBkYXRhLXRlc3QtaWQ9InJlYWN0aW9ucy1jb3VudCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiA0MDA7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzY2NjY2NjsiPiAyMjIgPC90ZD4gPHRkIGNsYXNzPSJweC0wLjUiIGRhdGEtdGVzdC1pZD0ic2VwYXJhdG9yIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctbGVmdDogNHB4OyBwYWRkaW5nLXJpZ2h0OiA0cHg7Ij7CtzwvdGQ-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLXJlZ3VsYXIgZm9udC1ub3JtYWwgdGV4dC1zeXN0ZW0tZ3JheS03MCIgZGF0YS10ZXN0LWlkPSJjb21tZW50cy1jb3VudCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiA0MDA7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzY2NjY2NjsiPiAxMTEgQ29tbWVudHMgPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0icmVhZC1tb3JlLWN0YS1ibG9jayI-IDx0ZCBjbGFzcz0icHQtMyIgY29sc3Bhbj0iMiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXRvcDogMjRweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iZW1haWwtYnV0dG9uIHctZnVsbCBrb3NoaW5fX2J1dHRvbi13aXRoLWZ1bGwtd2lkdGgiIGRhdGEtdGVzdC1pZD0iZW1haWwtYnV0dG9uIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHdpZHRoOiAxMDAlOyI-IDx0Ym9keT4gPHRyPiA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJtaWRkbGUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2MzA5ODYzMDA0NjE3MTEzNz9vcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGEtMC1yZWFkfm1vcmUmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBhcmlhLWxhYmVsPSJSZWFkIG1vcmUiIGNsYXNzPSJhbGlnbi10b3Agbm8tdW5kZXJsaW5lICIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgdmVydGljYWwtYWxpZ246IHRvcDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IGRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgY2xhc3M9ImJvcmRlci1zZXBhcmF0ZSAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBzZXBhcmF0ZTsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJidG4tbWQgYnRuLXNlY29uZGFyeS1lbXBoYXNpcyBib3JkZXItY29sb3ItYnJhbmQgYnV0dG9uLWxpbmsgbGVhZGluZy1yZWd1bGFyICFtaW4taC1bYXV0b10gIXNoYWRvdy1ub25lIGJvcmRlci0xIGJvcmRlci1zb2xpZCIgZGF0YS10ZXN0LWlkPSJyZWFkLW1vcmUtY3RhLWJlbG93IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGhlaWdodDogbWluLWNvbnRlbnQ7IGJvcmRlci1yYWRpdXM6IDI0cHg7IHBhZGRpbmctdG9wOiAxMnB4OyBwYWRkaW5nLWJvdHRvbTogMTJweDsgcGFkZGluZy1sZWZ0OiAyNHB4OyBwYWRkaW5nLXJpZ2h0OiAyNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtc2l6ZTogMTZweDsgZm9udC13ZWlnaHQ6IDYwMDsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgwLCAwLCAwLCAwKTsgY29sb3I6ICMwYTY2YzI7IGJvcmRlci13aWR0aDogMXB4OyBib3JkZXItc3R5bGU6IHNvbGlkOyBib3JkZXItY29sb3I6ICMwYTY2YzI7IGxpbmUtaGVpZ2h0OiAxLjI1OyBtaW4taGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7IGJveC1zaGFkb3c6IDAgMCAjMDAwMCwgMCAwICMwMDAwLCAwIDAgIzAwMDAgIWltcG9ydGFudDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2MzA5ODYzMDA0NjE3MTEzNz9vcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGEtMC1yZWFkfm1vcmUmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiB0YWJpbmRleD0iLTEiIGFyaWEtaGlkZGVuPSJ0cnVlIiBjbGFzcz0ibm8tdW5kZXJsaW5lIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsiPiA8c3BhbiBjbGFzcz0ibm8tdW5kZXJsaW5lIHRleHQtY29sb3ItYnJhbmQiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gUmVhZCBtb3JlIDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDx0cj48dGQgY2xhc3M9ImgtMiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBoZWlnaHQ6IDE2cHg7IiBoZWlnaHQ9IjE2Ij48L3RkPjwvdHI-IDx0cj4gPHRkIGNsYXNzPSJyb3VuZGVkLW1kIG92ZXJmbG93LWhpZGRlbiIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtdXBkYXRlLWNhcmQiIGNvbHNwYW49IjIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgb3ZlcmZsb3c6IGhpZGRlbjsgYm9yZGVyLXJhZGl1czogOHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJiZy1jb29sLWdyYXktMjAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYmFja2dyb3VuZC1jb2xvcjogI2VkZjNmODsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0iYmctY2VudGVyIGJnLW5vLXJlcGVhdCBoLVsyNTJweF0gYmctc3lzdGVtLWdyYXktNDAiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgaGVpZ2h0OiAyNTJweDsgYmFja2dyb3VuZC1jb2xvcjogI2NmY2ZjZjsgYmFja2dyb3VuZC1wb3NpdGlvbjogY2VudGVyOyBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0OyBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyOyBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoJnF1b3Q7aHR0cHM6Ly9tZWRpYS5saWNkbi5jb20vZG1zL2ltYWdlL3YyL0Q0RDIyQVFGd2dpMEZnRHhvUkEvZmVlZHNoYXJlLXNocmlua18yMDQ4XzE1MzYvZmVlZHNoYXJlLXNocmlua18yMDQ4XzE1MzYvMC8xNzMxNjU3NjUzNzExP2U9MTczNTE3MTIwMCZhbXA7dj1iZXRhJmFtcDt0PXdWejE3Xy0ycy1tbkRSVDU3c1Nxbm9rckZVTkFqZmM0RWh4LTZic1MwdVEmcXVvdDspOyIgaGVpZ2h0PSIyNTIiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2MzA5ODYzMDA0NjE3MTEzNz9oaWdobGlnaHRlZFVwZGF0ZVVybj11cm4lM0FsaSUzQWFjdGl2aXR5JTNBNzI2MzA5ODYzMDA0NjE3MTEzNyZhbXA7c2hvd0NvbW1lbnRCb3g9dHJ1ZSZhbXA7b3JpZ2luPU5FVFdPUktfQ09OVkVSU0FUSU9OUyZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS11cGRhdGV-Y2FyZC0wLXRodW1ibmFpbH5vdmVybGF5fmltYWdlJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLXVwZGF0ZX5jYXJkLTAtdGh1bWJuYWlsfm92ZXJsYXl-aW1hZ2UtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgYXJpYS1sYWJlbD0iUmVhZCBtb3JlIiBjbGFzcz0idy1mdWxsICIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB3aWR0aDogMTAwJTsiPiA8aW1nIGNsYXNzPSJ3LVs0NDhweF0gaC1bMjUycHhdIGhpZGRlbiAiIHNyYz0iaHR0cHM6Ly9tZWRpYS5saWNkbi5jb20vZG1zL2ltYWdlL3YyL0Q0RDIyQVFGd2dpMEZnRHhvUkEvZmVlZHNoYXJlLXNocmlua18yMDQ4XzE1MzYvZmVlZHNoYXJlLXNocmlua18yMDQ4XzE1MzYvMC8xNzMxNjU3NjUzNzExP2U9MTczNTE3MTIwMCZhbXA7dj1iZXRhJmFtcDt0PXdWejE3Xy0ycy1tbkRSVDU3c1Nxbm9rckZVTkFqZmM0RWh4LTZic1MwdVEiIGFsdD0iVmlldyBpbWFnZSIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgZGlzcGxheTogbm9uZTsgaGVpZ2h0OiAyNTJweDsgd2lkdGg6IDQ0OHB4OyIgd2lkdGg9IjQ0OCIgaGVpZ2h0PSIyNTIiPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvYT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InAtMyBib3JkZXItMCBib3JkZXItYi0xIGJvcmRlci1zb2xpZCBib3JkZXItc3lzdGVtLWdyYXktMzAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLXdpZHRoOiAwOyBib3JkZXItYm90dG9tLXdpZHRoOiAxcHg7IGJvcmRlci1zdHlsZTogc29saWQ7IGJvcmRlci1jb2xvcjogI2U2ZTZlNjsgcGFkZGluZzogMjRweDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2MzUzNTAyMjU5MzIyMDYwOD9vcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdC0wLXdyYXBwZXJ-bGluayZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3QtMC13cmFwcGVyfmxpbmstbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgY2xhc3M9InctZnVsbCIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtbGluayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB3aWR0aDogMTAwJTsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjYzNTM1MDIyNTkzMjIwNjA4P2hpZ2hsaWdodGVkVXBkYXRlVXJuPXVybiUzQWxpJTNBYWN0aXZpdHklM0E3MjYzNTM1MDIyNTkzMjIwNjA4JmFtcDtzaG93Q29tbWVudEJveD10cnVlJmFtcDtvcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWFjdG9yX2NhcmQmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtYWN0b3JfY2FyZC1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0iYmxvY2siIGRhdGEtdGVzdC1pZD0ibmV0d29yay1wb3N0LWxpbmsiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IGRpc3BsYXk6IGJsb2NrOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0ciBkYXRhLXRlc3QtaWQ9InYyc3R5bGUtZGlzYWJsZSI-IDx0ZCBjbGFzcz0idy1bNzJweF0iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgd2lkdGg6IDcycHg7IiB3aWR0aD0iNzIiPiA8aW1nIGNsYXNzPSJpbmxpbmUtYmxvY2sgcmVsYXRpdmUgYmctY29sb3ItZW50aXR5LWdob3N0LWJhY2tncm91bmQgY2xpcC1wYXRoLWNpcmNsZS01MCByb3VuZGVkLWZ1bGwgdy02IGgtNiAhdy1bNzJweF0gIWgtWzcycHhdICFibG9jayIgc3JjPSJodHRwczovL21lZGlhLmxpY2RuLmNvbS9kbXMvaW1hZ2UvdjIvRDREMDNBUUgzT3ExSzJDTWFsQS9wcm9maWxlLWRpc3BsYXlwaG90by1zaHJpbmtfNDAwXzQwMC9wcm9maWxlLWRpc3BsYXlwaG90by1zaHJpbmtfNDAwXzQwMC8wLzE3MjMzNTQ3NTY0MTE_ZT0yMTQ3NDgzNjQ3JmFtcDt2PWJldGEmYW1wO3Q9UXF5SnZMYlZVZzFXVW10N0RteDlFUnFYZVhZTm5wZEwyN3U5OWZOYUI3YyIgYWx0PSJQdXJ2aSBCb3RocmEiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IHBvc2l0aW9uOiByZWxhdGl2ZTsgYm9yZGVyLXJhZGl1czogOTk5OXB4OyBiYWNrZ3JvdW5kLWNvbG9yOiAjZWFlNmRmOyBjbGlwLXBhdGg6IGNpcmNsZSg1MCUpOyBkaXNwbGF5OiBibG9jayAhaW1wb3J0YW50OyBoZWlnaHQ6IDcycHggIWltcG9ydGFudDsgd2lkdGg6IDcycHggIWltcG9ydGFudDsiIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiI-IDwvdGQ-IDx0ZCBjbGFzcz0icGwtMSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWxlZnQ6IDhweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0iZm9udC1ib2xkIHRleHQtbWQgbGVhZGluZy1yZWd1bGFyIHRleHQtc3lzdGVtLWdyYXktOTAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgZm9udC1zaXplOiAxNnB4OyBmb250LXdlaWdodDogNjAwOyBsaW5lLWhlaWdodDogMS4yNTsgY29sb3I6ICMyODI4Mjg7Ij4gUHVydmkgQm90aHJhIDwvdGQ-IDwvdHI-IDx0ciBkYXRhLXRlc3QtaWQ9ImFjdG9yLWNhcmQtaGVhZGxpbmUiPiA8dGQgY2xhc3M9InRleHQtc20gbGVhZGluZy1bMTZweF0gdGV4dC1jb2xvci10ZXh0LXNvbGlkLXNlY29uZGFyeSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE0cHg7IGxpbmUtaGVpZ2h0OiAxNnB4OyBjb2xvcjogIzY2NjY2NjsiPiBWZXJzYXRpbGUgUHJvamVjdCBNYW5hZ2VyIGZyb20gUHJvamVjdCBJbml0aWF0aW9uIHRv4oCmIDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvYT4gPC90ZD4gPHRkIGNsYXNzPSJwbC0xIG10LVsyMnB4XSBtci0xIGlubGluZS1ibG9jayIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtZm9sbG93LWN0YSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW4tcmlnaHQ6IDhweDsgbWFyZ2luLXRvcDogMjJweDsgZGlzcGxheTogaW5saW5lLWJsb2NrOyBwYWRkaW5nLWxlZnQ6IDhweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iZW1haWwtYnV0dG9uICIgZGF0YS10ZXN0LWlkPSJlbWFpbC1idXR0b24iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0ibWlkZGxlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vYnVpbGQtcmVsYXRpb24vcGVvcGxlLWZvbGxvdy8_ZW50aXR5TmFtZT1wdXJ2aS1ib3RocmEyNCZhbXA7ZW50aXR5VXJuPUFEb0FBQVBHUV9nQnNjRFdXWkFMN29oLWdnMnBiNWxCUHV0VzlhQSZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1mb2xsb3dfY3RhJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgYXJpYS1sYWJlbD0iRm9sbG93IiBjbGFzcz0iYWxpZ24tdG9wIG5vLXVuZGVybGluZSAiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgdmVydGljYWwtYWxpZ246IHRvcDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iYXV0byIgY2xhc3M9ImJvcmRlci1zZXBhcmF0ZSAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBzZXBhcmF0ZTsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJidG4tc20gYnRuLXRlcnRpYXJ5LWVtcGhhc2lzIGJvcmRlci1ub25lIGJ1dHRvbi1saW5rIGxlYWRpbmctcmVndWxhciAhbWluLWgtW2F1dG9dICFzaGFkb3ctbm9uZSBib3JkZXItMSBib3JkZXItc29saWQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgaGVpZ2h0OiBtaW4tY29udGVudDsgYm9yZGVyLXJhZGl1czogMjRweDsgcGFkZGluZy10b3A6IDdweDsgcGFkZGluZy1ib3R0b206IDdweDsgcGFkZGluZy1sZWZ0OiAxNnB4OyBwYWRkaW5nLXJpZ2h0OiAxNnB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IDYwMDsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgwLCAwLCAwLCAwKTsgY29sb3I6ICMwYTY2YzI7IGJvcmRlci13aWR0aDogMXB4OyBib3JkZXItc3R5bGU6IG5vbmU7IGxpbmUtaGVpZ2h0OiAxLjI1OyBtaW4taGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7IGJveC1zaGFkb3c6IDAgMCAjMDAwMCwgMCAwICMwMDAwLCAwIDAgIzAwMDAgIWltcG9ydGFudDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9idWlsZC1yZWxhdGlvbi9wZW9wbGUtZm9sbG93Lz9lbnRpdHlOYW1lPXB1cnZpLWJvdGhyYTI0JmFtcDtlbnRpdHlVcm49QURvQUFBUEdRX2dCc2NEV1daQUw3b2gtZ2cycGI1bEJQdXRXOWFBJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtZm9sbG93X2N0YS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiB0YWJpbmRleD0iLTEiIGFyaWEtaGlkZGVuPSJ0cnVlIiBjbGFzcz0ibm8tdW5kZXJsaW5lIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IDxzcGFuIGNsYXNzPSJuby11bmRlcmxpbmUgIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gRm9sbG93IDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwdC0yIHRleHQtbWQgbGVhZGluZy1yZWd1bGFyIHRleHQtc3lzdGVtLWdyYXktOTAiIGNvbHNwYW49IjIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7IGZvbnQtc2l6ZTogMTZweDsgbGluZS1oZWlnaHQ6IDEuMjU7IGNvbG9yOiAjMjgyODI4OyI-IDxzcGFuIGRhdGEtdGVzdC1pZD0idHJ1bmNhdGVkLW1lc3NhZ2UtdGV4dCI-IE92ZXJjb21pbmcgQnVybm91dCBpbiBSZW1vdGUgV29yazogTXkgRXhwZXJpZW5jZSBhbmQgU3RyYXRlZ2llcyBCdXJub3V0IGluIHJlbW90ZSB3b3JrIGlzIHJlYWwsIGFuZCBJ4oCZdmXigKYgPC9zcGFuPiA8c3BhbiBkYXRhLXRlc3QtaWQ9InRydW5jYXRlZC1tZXNzYWdlLXNlZS1tb3JlIiBjbGFzcz0idGV4dC1jb2xvci1saW5rIGZvbnQtYm9sZCIgc3R5bGU9ImZvbnQtd2VpZ2h0OiA2MDA7IGNvbG9yOiAjMGE2NmMyOyI-IHNlZSBtb3JlIDwvc3Bhbj4gPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0ibmV0d29yay1wb3N0LXNvY2lhbC1tZXRhZGF0YSI-IDx0ZCBjbGFzcz0icHQtMiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXRvcDogMTZweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSJhdXRvIiBjbGFzcz0idy1hdXRvIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHdpZHRoOiBhdXRvOyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9InByLTAuNSIgZGF0YS10ZXN0LXJlYWN0aW9uPSJMSUtFIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctcmlnaHQ6IDRweDsiPiA8aW1nIGNsYXNzPSJibG9jayB3LTIgaC0yIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9zYy9oLzkxdGRzY24waDFhYW9lZnVpOWNyZjExajYiIGFsdD0iTElLRSIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgZGlzcGxheTogYmxvY2s7IGhlaWdodDogMTZweDsgd2lkdGg6IDE2cHg7IiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiPiA8L3RkPiA8dGQgY2xhc3M9InByLTAuNSIgZGF0YS10ZXN0LXJlYWN0aW9uPSJQUkFJU0UiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1yaWdodDogNHB4OyI-IDxpbWcgY2xhc3M9ImJsb2NrIHctMiBoLTIiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL3NjL2gvYWRpZzV1cnF4aTAzcXp1eTZpeWpmbTFiNSIgYWx0PSJQUkFJU0UiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGRpc3BsYXk6IGJsb2NrOyBoZWlnaHQ6IDE2cHg7IHdpZHRoOiAxNnB4OyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij4gPC90ZD4gPHRkIGNsYXNzPSJwci0wLjUiIGRhdGEtdGVzdC1yZWFjdGlvbj0iQVBQUkVDSUFUSU9OIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctcmlnaHQ6IDRweDsiPiA8aW1nIGNsYXNzPSJibG9jayB3LTIgaC0yIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9zYy9oL2J1ZDhsM2JobTBhanB5Y2R3anZhaGEybDEiIGFsdD0iQVBQUkVDSUFUSU9OIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBkaXNwbGF5OiBibG9jazsgaGVpZ2h0OiAxNnB4OyB3aWR0aDogMTZweDsiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI-IDwvdGQ-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLXJlZ3VsYXIgZm9udC1ub3JtYWwgdGV4dC1zeXN0ZW0tZ3JheS03MCIgZGF0YS10ZXN0LWlkPSJyZWFjdGlvbnMtY291bnQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogNDAwOyBsaW5lLWhlaWdodDogMS4yNTsgY29sb3I6ICM2NjY2NjY7Ij4gNzggPC90ZD4gPHRkIGNsYXNzPSJweC0wLjUiIGRhdGEtdGVzdC1pZD0ic2VwYXJhdG9yIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctbGVmdDogNHB4OyBwYWRkaW5nLXJpZ2h0OiA0cHg7Ij7CtzwvdGQ-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLXJlZ3VsYXIgZm9udC1ub3JtYWwgdGV4dC1zeXN0ZW0tZ3JheS03MCIgZGF0YS10ZXN0LWlkPSJjb21tZW50cy1jb3VudCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiA0MDA7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzY2NjY2NjsiPiA1NyBDb21tZW50cyA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8dHIgZGF0YS10ZXN0LWlkPSJyZWFkLW1vcmUtY3RhLWJsb2NrIj4gPHRkIGNsYXNzPSJwdC0zIiBjb2xzcGFuPSIyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctdG9wOiAyNHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGNsYXNzPSJlbWFpbC1idXR0b24gdy1mdWxsIGtvc2hpbl9fYnV0dG9uLXdpdGgtZnVsbC13aWR0aCIgZGF0YS10ZXN0LWlkPSJlbWFpbC1idXR0b24iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgd2lkdGg6IDEwMCU7Ij4gPHRib2R5PiA8dHI-IDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249Im1pZGRsZSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjYzNTM1MDIyNTkzMjIwNjA4P29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhLTAtcmVhZH5tb3JlLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGFyaWEtbGFiZWw9IlJlYWQgbW9yZSIgY2xhc3M9ImFsaWduLXRvcCBuby11bmRlcmxpbmUgIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB2ZXJ0aWNhbC1hbGlnbjogdG9wOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iYm9yZGVyLXNlcGFyYXRlICIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IHNlcGFyYXRlOyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImJ0bi1tZCBidG4tc2Vjb25kYXJ5LWVtcGhhc2lzIGJvcmRlci1jb2xvci1icmFuZCBidXR0b24tbGluayBsZWFkaW5nLXJlZ3VsYXIgIW1pbi1oLVthdXRvXSAhc2hhZG93LW5vbmUgYm9yZGVyLTEgYm9yZGVyLXNvbGlkIiBkYXRhLXRlc3QtaWQ9InJlYWQtbW9yZS1jdGEtYmVsb3ciIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgaGVpZ2h0OiBtaW4tY29udGVudDsgYm9yZGVyLXJhZGl1czogMjRweDsgcGFkZGluZy10b3A6IDEycHg7IHBhZGRpbmctYm90dG9tOiAxMnB4OyBwYWRkaW5nLWxlZnQ6IDI0cHg7IHBhZGRpbmctcmlnaHQ6IDI0cHg7IHRleHQtYWxpZ246IGNlbnRlcjsgZm9udC1zaXplOiAxNnB4OyBmb250LXdlaWdodDogNjAwOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDAsIDAsIDAsIDApOyBjb2xvcjogIzBhNjZjMjsgYm9yZGVyLXdpZHRoOiAxcHg7IGJvcmRlci1zdHlsZTogc29saWQ7IGJvcmRlci1jb2xvcjogIzBhNjZjMjsgbGluZS1oZWlnaHQ6IDEuMjU7IG1pbi1oZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsgYm94LXNoYWRvdzogMCAwICMwMDAwLCAwIDAgIzAwMDAsIDAgMCAjMDAwMCAhaW1wb3J0YW50OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjYzNTM1MDIyNTkzMjIwNjA4P29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhLTAtcmVhZH5tb3JlLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIHRhYmluZGV4PSItMSIgYXJpYS1oaWRkZW49InRydWUiIGNsYXNzPSJuby11bmRlcmxpbmUiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyBkaXNwbGF5OiBibG9jayAhaW1wb3J0YW50OyI-IDxzcGFuIGNsYXNzPSJuby11bmRlcmxpbmUgdGV4dC1jb2xvci1icmFuZCIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiBSZWFkIG1vcmUgPC9zcGFuPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvYT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icC0zIGJvcmRlci0wIGJvcmRlci1iLTEgYm9yZGVyLXNvbGlkIGJvcmRlci1zeXN0ZW0tZ3JheS0zMCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItd2lkdGg6IDA7IGJvcmRlci1ib3R0b20td2lkdGg6IDFweDsgYm9yZGVyLXN0eWxlOiBzb2xpZDsgYm9yZGVyLWNvbG9yOiAjZTZlNmU2OyBwYWRkaW5nOiAyNHB4OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjY0MzM4MDczMzkwMzUwMzM2P29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0LTAtd3JhcHBlcn5saW5rJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdC0wLXdyYXBwZXJ-bGluay1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0idy1mdWxsIiBkYXRhLXRlc3QtaWQ9Im5ldHdvcmstcG9zdC1saW5rIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHdpZHRoOiAxMDAlOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC91cGRhdGUvdXJuOmxpOmFjdGl2aXR5OjcyNjQzMzgwNzMzOTAzNTAzMzY_aGlnaGxpZ2h0ZWRVcGRhdGVVcm49dXJuJTNBbGklM0FhY3Rpdml0eSUzQTcyNjQzMzgwNzMzOTAzNTAzMzYmYW1wO3Nob3dDb21tZW50Qm94PXRydWUmYW1wO29yaWdpbj1ORVRXT1JLX0NPTlZFUlNBVElPTlMmYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtYWN0b3JfY2FyZCZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1hY3Rvcl9jYXJkLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJibG9jayIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtbGluayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgZGlzcGxheTogYmxvY2s7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyIGRhdGEtdGVzdC1pZD0idjJzdHlsZS1kaXNhYmxlIj4gPHRkIGNsYXNzPSJ3LVs3MnB4XSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB3aWR0aDogNzJweDsiIHdpZHRoPSI3MiI-IDxpbWcgY2xhc3M9ImlubGluZS1ibG9jayByZWxhdGl2ZSBiZy1jb2xvci1lbnRpdHktZ2hvc3QtYmFja2dyb3VuZCBjbGlwLXBhdGgtY2lyY2xlLTUwIHJvdW5kZWQtZnVsbCB3LTYgaC02ICF3LVs3MnB4XSAhaC1bNzJweF0gIWJsb2NrIiBzcmM9Imh0dHBzOi8vbWVkaWEubGljZG4uY29tL2Rtcy9pbWFnZS92Mi9ENTYwM0FRR3Vlc0tGMi0wVmhBL3Byb2ZpbGUtZGlzcGxheXBob3RvLXNocmlua180MDBfNDAwL3Byb2ZpbGUtZGlzcGxheXBob3RvLXNocmlua180MDBfNDAwLzAvMTY3OTQ5NjkzMDIyMj9lPTIxNDc0ODM2NDcmYW1wO3Y9YmV0YSZhbXA7dD1kQkI4ZEpma2NpNGJNWFNxRkM5OFVCQTA5WjFuYkM3M0NjRWt4RnpnWUhZIiBhbHQ9IkFsaXNoYSBTYW50aWFnbyIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgcG9zaXRpb246IHJlbGF0aXZlOyBib3JkZXItcmFkaXVzOiA5OTk5cHg7IGJhY2tncm91bmQtY29sb3I6ICNlYWU2ZGY7IGNsaXAtcGF0aDogY2lyY2xlKDUwJSk7IGRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7IGhlaWdodDogNzJweCAhaW1wb3J0YW50OyB3aWR0aDogNzJweCAhaW1wb3J0YW50OyIgd2lkdGg9IjcyIiBoZWlnaHQ9IjcyIj4gPC90ZD4gPHRkIGNsYXNzPSJwbC0xIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctbGVmdDogOHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJmb250LWJvbGQgdGV4dC1tZCBsZWFkaW5nLXJlZ3VsYXIgdGV4dC1zeXN0ZW0tZ3JheS05MCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDE2cHg7IGZvbnQtd2VpZ2h0OiA2MDA7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzI4MjgyODsiPiBBbGlzaGEgU2FudGlhZ28gPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0iYWN0b3ItY2FyZC1oZWFkbGluZSI-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLVsxNnB4XSB0ZXh0LWNvbG9yLXRleHQtc29saWQtc2Vjb25kYXJ5IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGZvbnQtc2l6ZTogMTRweDsgbGluZS1oZWlnaHQ6IDE2cHg7IGNvbG9yOiAjNjY2NjY2OyI-IFNvY2lhbCBKdXN0aWNlIHwgQ3VsdHVyYWwgQXdhcmVuZXNzIHwgTGFuZ3VhZ2XigKYgPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC9hPiA8L3RkPiA8dGQgY2xhc3M9InBsLTEgbXQtWzIycHhdIG1yLTEgaW5saW5lLWJsb2NrIiBkYXRhLXRlc3QtaWQ9Im5ldHdvcmstcG9zdC1mb2xsb3ctY3RhIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IG1hcmdpbi1yaWdodDogOHB4OyBtYXJnaW4tdG9wOiAyMnB4OyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHBhZGRpbmctbGVmdDogOHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGNsYXNzPSJlbWFpbC1idXR0b24gIiBkYXRhLXRlc3QtaWQ9ImVtYWlsLWJ1dHRvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJtaWRkbGUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9idWlsZC1yZWxhdGlvbi9wZW9wbGUtZm9sbG93Lz9lbnRpdHlOYW1lPWFsaXNoYWJzYW50aWFnbyZhbXA7ZW50aXR5VXJuPUFEb0FBRDQ5RlA4QmxwdVhhX2dENm5oYk4xVUR3Ymg1eGFzRHBXdyZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1mb2xsb3dfY3RhJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgYXJpYS1sYWJlbD0iRm9sbG93IiBjbGFzcz0iYWxpZ24tdG9wIG5vLXVuZGVybGluZSAiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgdmVydGljYWwtYWxpZ246IHRvcDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iYXV0byIgY2xhc3M9ImJvcmRlci1zZXBhcmF0ZSAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBzZXBhcmF0ZTsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJidG4tc20gYnRuLXRlcnRpYXJ5LWVtcGhhc2lzIGJvcmRlci1ub25lIGJ1dHRvbi1saW5rIGxlYWRpbmctcmVndWxhciAhbWluLWgtW2F1dG9dICFzaGFkb3ctbm9uZSBib3JkZXItMSBib3JkZXItc29saWQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgaGVpZ2h0OiBtaW4tY29udGVudDsgYm9yZGVyLXJhZGl1czogMjRweDsgcGFkZGluZy10b3A6IDdweDsgcGFkZGluZy1ib3R0b206IDdweDsgcGFkZGluZy1sZWZ0OiAxNnB4OyBwYWRkaW5nLXJpZ2h0OiAxNnB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IDYwMDsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgwLCAwLCAwLCAwKTsgY29sb3I6ICMwYTY2YzI7IGJvcmRlci13aWR0aDogMXB4OyBib3JkZXItc3R5bGU6IG5vbmU7IGxpbmUtaGVpZ2h0OiAxLjI1OyBtaW4taGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7IGJveC1zaGFkb3c6IDAgMCAjMDAwMCwgMCAwICMwMDAwLCAwIDAgIzAwMDAgIWltcG9ydGFudDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9idWlsZC1yZWxhdGlvbi9wZW9wbGUtZm9sbG93Lz9lbnRpdHlOYW1lPWFsaXNoYWJzYW50aWFnbyZhbXA7ZW50aXR5VXJuPUFEb0FBRDQ5RlA4QmxwdVhhX2dENm5oYk4xVUR3Ymg1eGFzRHBXdyZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1mb2xsb3dfY3RhJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgdGFiaW5kZXg9Ii0xIiBhcmlhLWhpZGRlbj0idHJ1ZSIgY2xhc3M9Im5vLXVuZGVybGluZSIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiA8c3BhbiBjbGFzcz0ibm8tdW5kZXJsaW5lICIgc3R5bGU9InRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IEZvbGxvdyA8L3NwYW4-IDwvYT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icHQtMiB0ZXh0LW1kIGxlYWRpbmctcmVndWxhciB0ZXh0LXN5c3RlbS1ncmF5LTkwIiBjb2xzcGFuPSIyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctdG9wOiAxNnB4OyBmb250LXNpemU6IDE2cHg7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzI4MjgyODsiPiA8c3BhbiBkYXRhLXRlc3QtaWQ9InRydW5jYXRlZC1tZXNzYWdlLXRleHQiPiBEZXNwaXRlIHRoZSBudW1lcm91cyBqb2IgaW50ZXJ2aWV3cyBJJ3ZlIHBhcnRpY2lwYXRlZCBpbiwgSSBzdGlsbCBmaW5kIG15c2VsZiB1bmNlcnRhaW4gYWJvdXQgd2hlbiBpdCdz4oCmIDwvc3Bhbj4gPHNwYW4gZGF0YS10ZXN0LWlkPSJ0cnVuY2F0ZWQtbWVzc2FnZS1zZWUtbW9yZSIgY2xhc3M9InRleHQtY29sb3ItbGluayBmb250LWJvbGQiIHN0eWxlPSJmb250LXdlaWdodDogNjAwOyBjb2xvcjogIzBhNjZjMjsiPiBzZWUgbW9yZSA8L3NwYW4-IDwvdGQ-IDwvdHI-IDx0ciBkYXRhLXRlc3QtaWQ9Im5ldHdvcmstcG9zdC1zb2NpYWwtbWV0YWRhdGEiPiA8dGQgY2xhc3M9InB0LTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iYXV0byIgY2xhc3M9InctYXV0byIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB3aWR0aDogYXV0bzsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJwci0wLjUiIGRhdGEtdGVzdC1yZWFjdGlvbj0iTElLRSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXJpZ2h0OiA0cHg7Ij4gPGltZyBjbGFzcz0iYmxvY2sgdy0yIGgtMiIgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vc2MvaC85MXRkc2NuMGgxYWFvZWZ1aTljcmYxMWo2IiBhbHQ9IkxJS0UiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGRpc3BsYXk6IGJsb2NrOyBoZWlnaHQ6IDE2cHg7IHdpZHRoOiAxNnB4OyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij4gPC90ZD4gPHRkIGNsYXNzPSJwci0wLjUiIGRhdGEtdGVzdC1yZWFjdGlvbj0iUFJBSVNFIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctcmlnaHQ6IDRweDsiPiA8aW1nIGNsYXNzPSJibG9jayB3LTIgaC0yIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9zYy9oL2FkaWc1dXJxeGkwM3F6dXk2aXlqZm0xYjUiIGFsdD0iUFJBSVNFIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBkaXNwbGF5OiBibG9jazsgaGVpZ2h0OiAxNnB4OyB3aWR0aDogMTZweDsiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI-IDwvdGQ-IDx0ZCBjbGFzcz0icHItMC41IiBkYXRhLXRlc3QtcmVhY3Rpb249IkVNUEFUSFkiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1yaWdodDogNHB4OyI-IDxpbWcgY2xhc3M9ImJsb2NrIHctMiBoLTIiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL3NjL2gvZXZzMng1emZuejVnMHhyYzZ1MjJ0cmVxMiIgYWx0PSJFTVBBVEhZIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBkaXNwbGF5OiBibG9jazsgaGVpZ2h0OiAxNnB4OyB3aWR0aDogMTZweDsiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI-IDwvdGQ-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLXJlZ3VsYXIgZm9udC1ub3JtYWwgdGV4dC1zeXN0ZW0tZ3JheS03MCIgZGF0YS10ZXN0LWlkPSJyZWFjdGlvbnMtY291bnQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogNDAwOyBsaW5lLWhlaWdodDogMS4yNTsgY29sb3I6ICM2NjY2NjY7Ij4gMTQ1IDwvdGQ-IDx0ZCBjbGFzcz0icHgtMC41IiBkYXRhLXRlc3QtaWQ9InNlcGFyYXRvciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWxlZnQ6IDRweDsgcGFkZGluZy1yaWdodDogNHB4OyI-wrc8L3RkPiA8dGQgY2xhc3M9InRleHQtc20gbGVhZGluZy1yZWd1bGFyIGZvbnQtbm9ybWFsIHRleHQtc3lzdGVtLWdyYXktNzAiIGRhdGEtdGVzdC1pZD0iY29tbWVudHMtY291bnQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogNDAwOyBsaW5lLWhlaWdodDogMS4yNTsgY29sb3I6ICM2NjY2NjY7Ij4gODcgQ29tbWVudHMgPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0icmVhZC1tb3JlLWN0YS1ibG9jayI-IDx0ZCBjbGFzcz0icHQtMyIgY29sc3Bhbj0iMiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXRvcDogMjRweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iZW1haWwtYnV0dG9uIHctZnVsbCBrb3NoaW5fX2J1dHRvbi13aXRoLWZ1bGwtd2lkdGgiIGRhdGEtdGVzdC1pZD0iZW1haWwtYnV0dG9uIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHdpZHRoOiAxMDAlOyI-IDx0Ym9keT4gPHRyPiA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJtaWRkbGUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2NDMzODA3MzM5MDM1MDMzNj9vcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGEtMC1yZWFkfm1vcmUmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBhcmlhLWxhYmVsPSJSZWFkIG1vcmUiIGNsYXNzPSJhbGlnbi10b3Agbm8tdW5kZXJsaW5lICIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgdmVydGljYWwtYWxpZ246IHRvcDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IGRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgY2xhc3M9ImJvcmRlci1zZXBhcmF0ZSAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBzZXBhcmF0ZTsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJidG4tbWQgYnRuLXNlY29uZGFyeS1lbXBoYXNpcyBib3JkZXItY29sb3ItYnJhbmQgYnV0dG9uLWxpbmsgbGVhZGluZy1yZWd1bGFyICFtaW4taC1bYXV0b10gIXNoYWRvdy1ub25lIGJvcmRlci0xIGJvcmRlci1zb2xpZCIgZGF0YS10ZXN0LWlkPSJyZWFkLW1vcmUtY3RhLWJlbG93IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGhlaWdodDogbWluLWNvbnRlbnQ7IGJvcmRlci1yYWRpdXM6IDI0cHg7IHBhZGRpbmctdG9wOiAxMnB4OyBwYWRkaW5nLWJvdHRvbTogMTJweDsgcGFkZGluZy1sZWZ0OiAyNHB4OyBwYWRkaW5nLXJpZ2h0OiAyNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtc2l6ZTogMTZweDsgZm9udC13ZWlnaHQ6IDYwMDsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgwLCAwLCAwLCAwKTsgY29sb3I6ICMwYTY2YzI7IGJvcmRlci13aWR0aDogMXB4OyBib3JkZXItc3R5bGU6IHNvbGlkOyBib3JkZXItY29sb3I6ICMwYTY2YzI7IGxpbmUtaGVpZ2h0OiAxLjI1OyBtaW4taGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7IGJveC1zaGFkb3c6IDAgMCAjMDAwMCwgMCAwICMwMDAwLCAwIDAgIzAwMDAgIWltcG9ydGFudDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2NDMzODA3MzM5MDM1MDMzNj9vcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGEtMC1yZWFkfm1vcmUmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya35wb3N0fmN0YS0wLXJlYWR-bW9yZS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiB0YWJpbmRleD0iLTEiIGFyaWEtaGlkZGVuPSJ0cnVlIiBjbGFzcz0ibm8tdW5kZXJsaW5lIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsiPiA8c3BhbiBjbGFzcz0ibm8tdW5kZXJsaW5lIHRleHQtY29sb3ItYnJhbmQiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gUmVhZCBtb3JlIDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvYT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InAtMyBib3JkZXItMCBib3JkZXItYi0xIGJvcmRlci1zb2xpZCBib3JkZXItc3lzdGVtLWdyYXktMzAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLXdpZHRoOiAwOyBib3JkZXItYm90dG9tLXdpZHRoOiAxcHg7IGJvcmRlci1zdHlsZTogc29saWQ7IGJvcmRlci1jb2xvcjogI2U2ZTZlNjsgcGFkZGluZzogMjRweDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL3VwZGF0ZS91cm46bGk6YWN0aXZpdHk6NzI2NDMzODA3MTE1MDYyODg2NT9vcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdC0wLXdyYXBwZXJ-bGluayZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3QtMC13cmFwcGVyfmxpbmstbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgY2xhc3M9InctZnVsbCIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtbGluayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB3aWR0aDogMTAwJTsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybjpsaTphY3Rpdml0eTo3MjY0MzM4MDcxMTUwNjI4ODY1P2hpZ2hsaWdodGVkVXBkYXRlVXJuPXVybiUzQWxpJTNBYWN0aXZpdHklM0E3MjY0MzM4MDcxMTUwNjI4ODY1JmFtcDtzaG93Q29tbWVudEJveD10cnVlJmFtcDtvcmlnaW49TkVUV09SS19DT05WRVJTQVRJT05TJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWFjdG9yX2NhcmQmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtYWN0b3JfY2FyZC1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0iYmxvY2siIGRhdGEtdGVzdC1pZD0ibmV0d29yay1wb3N0LWxpbmsiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IGRpc3BsYXk6IGJsb2NrOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0ciBkYXRhLXRlc3QtaWQ9InYyc3R5bGUtZGlzYWJsZSI-IDx0ZCBjbGFzcz0idy1bNzJweF0iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgd2lkdGg6IDcycHg7IiB3aWR0aD0iNzIiPiA8aW1nIGNsYXNzPSJpbmxpbmUtYmxvY2sgcmVsYXRpdmUgYmctY29sb3ItZW50aXR5LWdob3N0LWJhY2tncm91bmQgY2xpcC1wYXRoLWNpcmNsZS01MCByb3VuZGVkLWZ1bGwgdy02IGgtNiAhdy1bNzJweF0gIWgtWzcycHhdICFibG9jayIgc3JjPSJodHRwczovL21lZGlhLmxpY2RuLmNvbS9kbXMvaW1hZ2UvdjIvQzREMDNBUUVPYkFZYkJkWnZvQS9wcm9maWxlLWRpc3BsYXlwaG90by1zaHJpbmtfNDAwXzQwMC9wcm9maWxlLWRpc3BsYXlwaG90by1zaHJpbmtfNDAwXzQwMC8wLzE1OTA3ODUyMTIwODI_ZT0yMTQ3NDgzNjQ3JmFtcDt2PWJldGEmYW1wO3Q9VXF4ekdQUlZSSS1xVEpSSnFFQ25Hb29rXy1JU2RidEFvYnh1ZVRuMzYzSSIgYWx0PSJBdXN0aW4gQmVsY2FrIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBwb3NpdGlvbjogcmVsYXRpdmU7IGJvcmRlci1yYWRpdXM6IDk5OTlweDsgYmFja2dyb3VuZC1jb2xvcjogI2VhZTZkZjsgY2xpcC1wYXRoOiBjaXJjbGUoNTAlKTsgZGlzcGxheTogYmxvY2sgIWltcG9ydGFudDsgaGVpZ2h0OiA3MnB4ICFpbXBvcnRhbnQ7IHdpZHRoOiA3MnB4ICFpbXBvcnRhbnQ7IiB3aWR0aD0iNzIiIGhlaWdodD0iNzIiPiA8L3RkPiA8dGQgY2xhc3M9InBsLTEiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1sZWZ0OiA4cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImZvbnQtYm9sZCB0ZXh0LW1kIGxlYWRpbmctcmVndWxhciB0ZXh0LXN5c3RlbS1ncmF5LTkwIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGZvbnQtc2l6ZTogMTZweDsgZm9udC13ZWlnaHQ6IDYwMDsgbGluZS1oZWlnaHQ6IDEuMjU7IGNvbG9yOiAjMjgyODI4OyI-IEF1c3RpbiBCZWxjYWsgPC90ZD4gPC90cj4gPHRyIGRhdGEtdGVzdC1pZD0iYWN0b3ItY2FyZC1oZWFkbGluZSI-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLVsxNnB4XSB0ZXh0LWNvbG9yLXRleHQtc29saWQtc2Vjb25kYXJ5IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGZvbnQtc2l6ZTogMTRweDsgbGluZS1oZWlnaHQ6IDE2cHg7IGNvbG9yOiAjNjY2NjY2OyI-IEkgVGVhY2ggUGVvcGxlIEhvdyBUbyBMYW5kIEFtYXppbmcgSm9icyBXaXRob3V04oCmIDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvYT4gPC90ZD4gPHRkIGNsYXNzPSJwbC0xIG10LVsyMnB4XSBtci0xIGlubGluZS1ibG9jayIgZGF0YS10ZXN0LWlkPSJuZXR3b3JrLXBvc3QtZm9sbG93LWN0YSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW4tcmlnaHQ6IDhweDsgbWFyZ2luLXRvcDogMjJweDsgZGlzcGxheTogaW5saW5lLWJsb2NrOyBwYWRkaW5nLWxlZnQ6IDhweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iZW1haWwtYnV0dG9uICIgZGF0YS10ZXN0LWlkPSJlbWFpbC1idXR0b24iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0ibWlkZGxlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vYnVpbGQtcmVsYXRpb24vcGVvcGxlLWZvbGxvdy8_ZW50aXR5TmFtZT1hYmVsY2FrJmFtcDtlbnRpdHlVcm49QURvQUFBY241OElCc05SWDU4WEtOLUVDdngyVTZqZDluUWdZRmpZJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtbmV0d29ya19wb3N0LTAtZm9sbG93X2N0YS1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBhcmlhLWxhYmVsPSJGb2xsb3ciIGNsYXNzPSJhbGlnbi10b3Agbm8tdW5kZXJsaW5lICIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB2ZXJ0aWNhbC1hbGlnbjogdG9wOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSJhdXRvIiBjbGFzcz0iYm9yZGVyLXNlcGFyYXRlICIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IHNlcGFyYXRlOyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImJ0bi1zbSBidG4tdGVydGlhcnktZW1waGFzaXMgYm9yZGVyLW5vbmUgYnV0dG9uLWxpbmsgbGVhZGluZy1yZWd1bGFyICFtaW4taC1bYXV0b10gIXNoYWRvdy1ub25lIGJvcmRlci0xIGJvcmRlci1zb2xpZCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBoZWlnaHQ6IG1pbi1jb250ZW50OyBib3JkZXItcmFkaXVzOiAyNHB4OyBwYWRkaW5nLXRvcDogN3B4OyBwYWRkaW5nLWJvdHRvbTogN3B4OyBwYWRkaW5nLWxlZnQ6IDE2cHg7IHBhZGRpbmctcmlnaHQ6IDE2cHg7IHRleHQtYWxpZ246IGNlbnRlcjsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogNjAwOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDAsIDAsIDAsIDApOyBjb2xvcjogIzBhNjZjMjsgYm9yZGVyLXdpZHRoOiAxcHg7IGJvcmRlci1zdHlsZTogbm9uZTsgbGluZS1oZWlnaHQ6IDEuMjU7IG1pbi1oZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsgYm94LXNoYWRvdzogMCAwICMwMDAwLCAwIDAgIzAwMDAsIDAgMCAjMDAwMCAhaW1wb3J0YW50OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2J1aWxkLXJlbGF0aW9uL3Blb3BsZS1mb2xsb3cvP2VudGl0eU5hbWU9YWJlbGNhayZhbXA7ZW50aXR5VXJuPUFEb0FBQWNuNThJQnNOUlg1OFhLTi1FQ3Z4MlU2amQ5blFnWUZqWSZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrX3Bvc3QtMC1mb2xsb3dfY3RhJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmtfcG9zdC0wLWZvbGxvd19jdGEtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgdGFiaW5kZXg9Ii0xIiBhcmlhLWhpZGRlbj0idHJ1ZSIgY2xhc3M9Im5vLXVuZGVybGluZSIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiA8c3BhbiBjbGFzcz0ibm8tdW5kZXJsaW5lICIgc3R5bGU9InRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IEZvbGxvdyA8L3NwYW4-IDwvYT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icHQtMiB0ZXh0LW1kIGxlYWRpbmctcmVndWxhciB0ZXh0LXN5c3RlbS1ncmF5LTkwIiBjb2xzcGFuPSIyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctdG9wOiAxNnB4OyBmb250LXNpemU6IDE2cHg7IGxpbmUtaGVpZ2h0OiAxLjI1OyBjb2xvcjogIzI4MjgyODsiPiA8c3BhbiBkYXRhLXRlc3QtaWQ9InRydW5jYXRlZC1tZXNzYWdlLXRleHQiPiBJIHNoYXJlZCBhIHBvc3QgYWJvdXQgd2h5IHlvdSBwdXJzdWUgam9icyBldmVuIGlmIHlvdSBkb27igJl0IG1lZXQgMTAwJSBvZiB0aGUgcXVhbGlmaWNhdGlvbnMuIE1hbnkgcGVvcGxl4oCmIDwvc3Bhbj4gPHNwYW4gZGF0YS10ZXN0LWlkPSJ0cnVuY2F0ZWQtbWVzc2FnZS1zZWUtbW9yZSIgY2xhc3M9InRleHQtY29sb3ItbGluayBmb250LWJvbGQiIHN0eWxlPSJmb250LXdlaWdodDogNjAwOyBjb2xvcjogIzBhNjZjMjsiPiBzZWUgbW9yZSA8L3NwYW4-IDwvdGQ-IDwvdHI-IDx0ciBkYXRhLXRlc3QtaWQ9Im5ldHdvcmstcG9zdC1zb2NpYWwtbWV0YWRhdGEiPiA8dGQgY2xhc3M9InB0LTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iYXV0byIgY2xhc3M9InctYXV0byIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB3aWR0aDogYXV0bzsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJwci0wLjUiIGRhdGEtdGVzdC1yZWFjdGlvbj0iTElLRSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLXJpZ2h0OiA0cHg7Ij4gPGltZyBjbGFzcz0iYmxvY2sgdy0yIGgtMiIgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vc2MvaC85MXRkc2NuMGgxYWFvZWZ1aTljcmYxMWo2IiBhbHQ9IkxJS0UiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGRpc3BsYXk6IGJsb2NrOyBoZWlnaHQ6IDE2cHg7IHdpZHRoOiAxNnB4OyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij4gPC90ZD4gPHRkIGNsYXNzPSJwci0wLjUiIGRhdGEtdGVzdC1yZWFjdGlvbj0iUFJBSVNFIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctcmlnaHQ6IDRweDsiPiA8aW1nIGNsYXNzPSJibG9jayB3LTIgaC0yIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9zYy9oL2FkaWc1dXJxeGkwM3F6dXk2aXlqZm0xYjUiIGFsdD0iUFJBSVNFIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBkaXNwbGF5OiBibG9jazsgaGVpZ2h0OiAxNnB4OyB3aWR0aDogMTZweDsiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI-IDwvdGQ-IDx0ZCBjbGFzcz0icHItMC41IiBkYXRhLXRlc3QtcmVhY3Rpb249IkVNUEFUSFkiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1yaWdodDogNHB4OyI-IDxpbWcgY2xhc3M9ImJsb2NrIHctMiBoLTIiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL3NjL2gvZXZzMng1emZuejVnMHhyYzZ1MjJ0cmVxMiIgYWx0PSJFTVBBVEhZIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBkaXNwbGF5OiBibG9jazsgaGVpZ2h0OiAxNnB4OyB3aWR0aDogMTZweDsiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI-IDwvdGQ-IDx0ZCBjbGFzcz0idGV4dC1zbSBsZWFkaW5nLXJlZ3VsYXIgZm9udC1ub3JtYWwgdGV4dC1zeXN0ZW0tZ3JheS03MCIgZGF0YS10ZXN0LWlkPSJyZWFjdGlvbnMtY291bnQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogNDAwOyBsaW5lLWhlaWdodDogMS4yNTsgY29sb3I6ICM2NjY2NjY7Ij4gNTI2IDwvdGQ-IDx0ZCBjbGFzcz0icHgtMC41IiBkYXRhLXRlc3QtaWQ9InNlcGFyYXRvciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWxlZnQ6IDRweDsgcGFkZGluZy1yaWdodDogNHB4OyI-wrc8L3RkPiA8dGQgY2xhc3M9InRleHQtc20gbGVhZGluZy1yZWd1bGFyIGZvbnQtbm9ybWFsIHRleHQtc3lzdGVtLWdyYXktNzAiIGRhdGEtdGVzdC1pZD0iY29tbWVudHMtY291bnQiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogNDAwOyBsaW5lLWhlaWdodDogMS4yNTsgY29sb3I6ICM2NjY2NjY7Ij4gMTE4IENvbW1lbnRzIDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDx0ciBkYXRhLXRlc3QtaWQ9InJlYWQtbW9yZS1jdGEtYmxvY2siPiA8dGQgY2xhc3M9InB0LTMiIGNvbHNwYW49IjIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDI0cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgY2xhc3M9ImVtYWlsLWJ1dHRvbiB3LWZ1bGwga29zaGluX19idXR0b24td2l0aC1mdWxsLXdpZHRoIiBkYXRhLXRlc3QtaWQ9ImVtYWlsLWJ1dHRvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB3aWR0aDogMTAwJTsiPiA8dGJvZHk-IDx0cj4gPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0ibWlkZGxlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC91cGRhdGUvdXJuOmxpOmFjdGl2aXR5OjcyNjQzMzgwNzExNTA2Mjg4NjU_b3JpZ2luPU5FVFdPUktfQ09OVkVSU0FUSU9OUyZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhLTAtcmVhZH5tb3JlJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGEtMC1yZWFkfm1vcmUtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgYXJpYS1sYWJlbD0iUmVhZCBtb3JlIiBjbGFzcz0iYWxpZ24tdG9wIG5vLXVuZGVybGluZSAiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHZlcnRpY2FsLWFsaWduOiB0b3A7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyBkaXNwbGF5OiBibG9jayAhaW1wb3J0YW50OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGNsYXNzPSJib3JkZXItc2VwYXJhdGUgIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogc2VwYXJhdGU7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0iYnRuLW1kIGJ0bi1zZWNvbmRhcnktZW1waGFzaXMgYm9yZGVyLWNvbG9yLWJyYW5kIGJ1dHRvbi1saW5rIGxlYWRpbmctcmVndWxhciAhbWluLWgtW2F1dG9dICFzaGFkb3ctbm9uZSBib3JkZXItMSBib3JkZXItc29saWQiIGRhdGEtdGVzdC1pZD0icmVhZC1tb3JlLWN0YS1iZWxvdyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBoZWlnaHQ6IG1pbi1jb250ZW50OyBib3JkZXItcmFkaXVzOiAyNHB4OyBwYWRkaW5nLXRvcDogMTJweDsgcGFkZGluZy1ib3R0b206IDEycHg7IHBhZGRpbmctbGVmdDogMjRweDsgcGFkZGluZy1yaWdodDogMjRweDsgdGV4dC1hbGlnbjogY2VudGVyOyBmb250LXNpemU6IDE2cHg7IGZvbnQtd2VpZ2h0OiA2MDA7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7IGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMCk7IGNvbG9yOiAjMGE2NmMyOyBib3JkZXItd2lkdGg6IDFweDsgYm9yZGVyLXN0eWxlOiBzb2xpZDsgYm9yZGVyLWNvbG9yOiAjMGE2NmMyOyBsaW5lLWhlaWdodDogMS4yNTsgbWluLWhlaWdodDogYXV0byAhaW1wb3J0YW50OyBib3gtc2hhZG93OiAwIDAgIzAwMDAsIDAgMCAjMDAwMCwgMCAwICMwMDAwICFpbXBvcnRhbnQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC91cGRhdGUvdXJuOmxpOmFjdGl2aXR5OjcyNjQzMzgwNzExNTA2Mjg4NjU_b3JpZ2luPU5FVFdPUktfQ09OVkVSU0FUSU9OUyZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1uZXR3b3JrfnBvc3R-Y3RhLTAtcmVhZH5tb3JlJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLW5ldHdvcmt-cG9zdH5jdGEtMC1yZWFkfm1vcmUtbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgdGFiaW5kZXg9Ii0xIiBhcmlhLWhpZGRlbj0idHJ1ZSIgY2xhc3M9Im5vLXVuZGVybGluZSIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IGRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7Ij4gPHNwYW4gY2xhc3M9Im5vLXVuZGVybGluZSB0ZXh0LWNvbG9yLWJyYW5kIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IFJlYWQgbW9yZSA8L3NwYW4-IDwvYT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwdC00IHBiLTIgcHgtMyBiZy1jb2xvci1iYWNrZ3JvdW5kLWNhbnZhcyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjNmMmYwOyBwYWRkaW5nLWxlZnQ6IDI0cHg7IHBhZGRpbmctcmlnaHQ6IDI0cHg7IHBhZGRpbmctYm90dG9tOiAxNnB4OyBwYWRkaW5nLXRvcDogMzJweDsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iZW1haWwtYnV0dG9uICIgZGF0YS10ZXN0LWlkPSJlbWFpbC1idXR0b24iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0ibWlkZGxlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC8_bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDElM0JsaURBSWtKSFN0cUtua2kwOGNJaG5RJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTBGRXJaN0xYdzREYncxJmFtcDt0cms9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1mb290ZXJfcHJvbW8tMC1mb290ZXJfc2VlX2FsbCZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS1mb290ZXJfcHJvbW8tMC1mb290ZXJfc2VlX2FsbC1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBhcmlhLWxhYmVsPSJTZWUgbW9yZSBvbiBMaW5rZWRJbiIgY2xhc3M9ImFsaWduLXRvcCBuby11bmRlcmxpbmUgIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHZlcnRpY2FsLWFsaWduOiB0b3A7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9ImF1dG8iIGNsYXNzPSJib3JkZXItc2VwYXJhdGUgIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogc2VwYXJhdGU7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0iYnRuLW1kIGJ0bi1wcmltYXJ5IGJvcmRlci1jb2xvci1icmFuZCBidXR0b24tbGluayBsZWFkaW5nLXJlZ3VsYXIgIW1pbi1oLVthdXRvXSAhc2hhZG93LW5vbmUgYm9yZGVyLTEgYm9yZGVyLXNvbGlkIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGhlaWdodDogbWluLWNvbnRlbnQ7IGJvcmRlci1yYWRpdXM6IDI0cHg7IHBhZGRpbmctdG9wOiAxMnB4OyBwYWRkaW5nLWJvdHRvbTogMTJweDsgcGFkZGluZy1sZWZ0OiAyNHB4OyBwYWRkaW5nLXJpZ2h0OiAyNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtc2l6ZTogMTZweDsgZm9udC13ZWlnaHQ6IDYwMDsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgYmFja2dyb3VuZC1jb2xvcjogIzBhNjZjMjsgY29sb3I6ICNmZmZmZmY7IGJvcmRlci13aWR0aDogMXB4OyBib3JkZXItc3R5bGU6IHNvbGlkOyBib3JkZXItY29sb3I6ICMwYTY2YzI7IGxpbmUtaGVpZ2h0OiAxLjI1OyBtaW4taGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7IGJveC1zaGFkb3c6IDAgMCAjMDAwMCwgMCAwICMwMDAwLCAwIDAgIzAwMDAgIWltcG9ydGFudDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkLz9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWZvb3Rlcl9wcm9tby0wLWZvb3Rlcl9zZWVfYWxsJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWZvb3Rlcl9wcm9tby0wLWZvb3Rlcl9zZWVfYWxsLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIHRhYmluZGV4PSItMSIgYXJpYS1oaWRkZW49InRydWUiIGNsYXNzPSJuby11bmRlcmxpbmUiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gPHNwYW4gY2xhc3M9Im5vLXVuZGVybGluZSB0ZXh0LXdoaXRlIiBzdHlsZT0iY29sb3I6ICNmZmZmZmY7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IFNlZSBtb3JlIG9uIExpbmtlZEluIDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvZGl2PiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0iYmctY29sb3ItYmFja2dyb3VuZC1jYW52YXMgcC0zIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJhY2tncm91bmQtY29sb3I6ICNmM2YyZjA7IHBhZGRpbmc6IDI0cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9InRleHQtY2VudGVyIHBiLTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1ib3R0b206IDE2cHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPiA8aDIgY2xhc3M9InRleHQtbGcgdGV4dC10ZWFsLTgwIiBzdHlsZT0ibWFyZ2luOiAwOyBmb250LXdlaWdodDogNTAwOyBmb250LXNpemU6IDIwcHg7IGNvbG9yOiAjMTE0OTUxOyI-IEdldCB0aGUgbmV3IExpbmtlZEluIGRlc2t0b3AgYXBwIDwvaDI-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJ0ZXh0LWNlbnRlciBwYi0yIiBkYXRhLXRlc3QtaWQ9ImZvb3Rlci1hcHAtc3RvcmUtaWNvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogMTZweDsgdGV4dC1hbGlnbjogY2VudGVyOyI-IDxhIGhyZWY9Imh0dHBzOi8vYXBwcy5taWNyb3NvZnQuY29tL3N0b3JlL2RldGFpbC85V1pETkNSRko0UTc_bGF1bmNoPXRydWUmYW1wO2NpZD1saW5rZWRpbl9lbWFpbF91cHNlbGwmYW1wO21vZGU9ZnVsbCIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxpbWcgYWx0PSJHZXQgaXQgZnJvbSBNaWNyb3NvZnQiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL3NjL2gvZWpwa2twd3Zxa3MzMWEzY2pxb2tiN2ZibSIgY2xhc3M9ImgtWzQwcHhdIHctWzExMnB4XSIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgaGVpZ2h0OiA0MHB4OyB3aWR0aDogMTEycHg7IiB3aWR0aD0iMTEyIiBoZWlnaHQ9IjQwIj4gPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0idGV4dC1jZW50ZXIgcGItMiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogMTZweDsgdGV4dC1hbGlnbjogY2VudGVyOyI-IDxoMiBjbGFzcz0idGV4dC1tZCB0ZXh0LXRlYWwtODAiIHN0eWxlPSJtYXJnaW46IDA7IGZvbnQtd2VpZ2h0OiA1MDA7IGZvbnQtc2l6ZTogMTZweDsgY29sb3I6ICMxMTQ5NTE7Ij4gQWxzbyBhdmFpbGFibGUgb24gbW9iaWxlIDwvaDI-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJ0ZXh0LWNlbnRlciIgZGF0YS10ZXN0LWlkPSJmb290ZXItYXBwLXN0b3JlLWljb24iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgdGV4dC1hbGlnbjogY2VudGVyOyI-IDxhIGhyZWY9Imh0dHBzOi8vaXR1bmVzLmFwcGxlLmNvbS91cy9hcHAvbGlua2VkaW4vaWQyODg0MjkwNDA_cHQ9MTA3NDYmYW1wO2N0PXN0X2FwcHNpdGVfZmxhZ3NoaXAmYW1wO210PTgiIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vb3BlbmVyIG5vcmVmZXJyZXIiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsiPiA8aW1nIGFsdD0iRG93bmxvYWQgb24gdGhlIEFwcCBTdG9yZSIgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vc2MvaC83Nnl6a2QwaDVraXYyN2xyZDR5YWVueWxrIiBjbGFzcz0iaC1bNDBweF0gdy1bMTIwcHhdIHByLTEiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGhlaWdodDogNDBweDsgd2lkdGg6IDEyMHB4OyBwYWRkaW5nLXJpZ2h0OiA4cHg7IiB3aWR0aD0iMTIwIiBoZWlnaHQ9IjQwIj4gPC9hPiA8YSBocmVmPSJodHRwczovL3BsYXkuZ29vZ2xlLmNvbS9zdG9yZS9hcHBzL2RldGFpbHM_aWQ9Y29tLmxpbmtlZGluLmFuZHJvaWQmYW1wO3JlZmVycmVyPXN0X2FwcHNpdGVfZmxhZ3NoaXAiIHRhcmdldD0iX2JsYW5rIiByZWw9Im5vb3BlbmVyIG5vcmVmZXJyZXIiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsiPiA8aW1nIGFsdD0iR2V0IGl0IG9uIEdvb2dsZSBQbGF5IiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9zYy9oLzE0MnF1ZHdibHA1OHp3bWM5dmtxZnBsdWciIGNsYXNzPSJoLVs0MHB4XSB3LVsxMzRweF0iIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGhlaWdodDogNDBweDsgd2lkdGg6IDEzNHB4OyIgd2lkdGg9IjEzNCIgaGVpZ2h0PSI0MCI-IDwvYT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InB5LTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7IHBhZGRpbmctYm90dG9tOiAxNnB4OyI-PGhyIGNsYXNzPSJib3JkZXItbm9uZSBiZy1bI2UwZGZkZF0gaC1bMXB4XSIgc3R5bGU9ImhlaWdodDogMXB4OyBib3JkZXItc3R5bGU6IG5vbmU7IGJhY2tncm91bmQtY29sb3I6ICNlMGRmZGQ7Ij48L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0idGV4dC14cyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDEycHg7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0icGItMSBtLTAiIGRhdGEtdGVzdC1pZD0iZW1haWwtZm9vdGVyX19pbnRlbmRlZCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW46IDBweDsgcGFkZGluZy1ib3R0b206IDhweDsiPiBUaGlzIGVtYWlsIHdhcyBpbnRlbmRlZCBmb3IgS2h1c2hhbCBQUyAoLS0pIDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwYi0xIG0tMCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW46IDBweDsgcGFkZGluZy1ib3R0b206IDhweDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vaGVscC9saW5rZWRpbi9hbnN3ZXIvNDc4OD9sYW5nPWVuJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLVNlY3VyaXR5SGVscC0wLWZvb3RlcmdsaW1tZXImYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtU2VjdXJpdHlIZWxwLTAtZm9vdGVyZ2xpbW1lci1udWxsLWo3enU3aX5tM3g0M2Nzdn4yYy1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NDNjc3YtMmMmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1NNFpEZzBNems1WVdVNE56WmtOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5ETmtZV1l3WkRjME5qaGlaams0TUdaall6QTJNakEyWVRsak5ESXdPREU1WldKak5UVmhaV0l5T1dSaVpEa3dMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0idGV4dC1pbmhlcml0IHVuZGVybGluZSIgc3R5bGU9ImN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IGNvbG9yOiBpbmhlcml0OyB0ZXh0LWRlY29yYXRpb24tbGluZTogdW5kZXJsaW5lOyI-TGVhcm4gd2h5IHdlIGluY2x1ZGVkIHRoaXMuPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icGItMSBtLTAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgbWFyZ2luOiAwcHg7IHBhZGRpbmctYm90dG9tOiA4cHg7Ij5Zb3UgYXJlIHJlY2VpdmluZyBOZXR3b3JrIENvbnZlcnNhdGlvbnMgZW1haWxzLiBTb21lIGNvbnRlbnQgbWF5IGJlIGF1dG9tYXRpY2FsbHkgdHJhbnNsYXRlZCBiYXNlZCBvbiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vbXlwcmVmZXJlbmNlcy9kL2xhbmd1YWdlLWZvci10cmFuc2xhdGlvbiIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJsaW5rLW5vLXZpc2l0ZWQtc3RhdGUiIGRhdGEtdHJhY2tpbmctd2lsbC1uYXZpZ2F0ZSBkYXRhLXRyYWNraW5nLWNvbnRyb2wtbmFtZT0iZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zX2NvbnRlbnRfc2V0dGluZ3NfbGluayIgc3R5bGU9ImN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IGZvbnQtd2VpZ2h0OiA2MDA7IGNvbG9yOiAjMGE2NmMyOyI-eW91ciBzZXR0aW5nczwvYT4uPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InBiLTEgbS0wIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IG1hcmdpbjogMHB4OyBwYWRkaW5nLWJvdHRvbTogOHB4OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL3BzZXR0aW5ncy9lbWFpbC11bnN1YnNjcmliZT9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLXVuc3Vic2NyaWJlLTAtZm9vdGVyR2xpbW1lciZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMS11bnN1YnNjcmliZS0wLWZvb3RlckdsaW1tZXItbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtsb2lkPUFRR1NlMFF6V1F4MjZBQUFBWk5qMW5mY3RCalBkV2V6a2lud05HMFVkN3ZZd3NuYWxoMFVzTWFZWWFRM2wzNmZUcnJqOXNjVko5emJjRzgtdENqalhhWEFDQkZEbWpjZ0pCVEZheHNRMFR4MDdpLU5FLVh5LU55V2JnIiB0YXJnZXQ9Il9ibGFuayIgY2xhc3M9InRleHQtaW5oZXJpdCB1bmRlcmxpbmUiIHN0eWxlPSJjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBjb2xvcjogaW5oZXJpdDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IHVuZGVybGluZTsiPlVuc3Vic2NyaWJlPC9hPiDCoMKgwrfCoMKgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9oZWxwL2xpbmtlZGluL2Fuc3dlci82Nz9sYW5nPWVuJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25ldHdvcmtfY29udmVyc2F0aW9uc18wMSUzQmxpREFJa0pIU3RxS25raTA4Y0loblElM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MEZFclo3TFh3NERidzEmYW1wO3Ryaz1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWhlbHAtMC1mb290ZXJnbGltbWVyJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxLWhlbHAtMC1mb290ZXJnbGltbWVyLW51bGwtajd6dTdpfm0zeDQzY3N2fjJjLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0M2Nzdi0yYyZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU00WkRnME16azVZV1U0Tnpaa04ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkROa1lXWXdaRGMwTmpoaVpqazRNR1pqWXpBMk1qQTJZVGxqTkRJd09ERTVaV0pqTlRWaFpXSXlPV1JpWkRrd0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJ0ZXh0LWluaGVyaXQgdW5kZXJsaW5lIiBzdHlsZT0iY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgY29sb3I6IGluaGVyaXQ7IHRleHQtZGVjb3JhdGlvbi1saW5lOiB1bmRlcmxpbmU7Ij5IZWxwPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icGItMSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogOHB4OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvP2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbmV0d29ya19jb252ZXJzYXRpb25zXzAxJTNCbGlEQUlrSkhTdHFLbmtpMDhjSWhuUSUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0wRkVyWjdMWHc0RGJ3MSZhbXA7dHJrPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtZm9vdGVyLTAtbG9nb0dsaW1tZXImYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9uZXR3b3JrX2NvbnZlcnNhdGlvbnNfMDEtZm9vdGVyLTAtbG9nb0dsaW1tZXItbnVsbC1qN3p1N2l-bTN4NDNjc3Z-MmMtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDQzY3N2LTJjJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTTRaRGcwTXprNVlXVTROelprTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVORE5rWVdZd1pEYzBOamhpWmprNE1HWmpZekEyTWpBMllUbGpOREl3T0RFNVpXSmpOVFZoWldJeU9XUmlaRGt3TERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxpbWcgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vc2MvaC85ZWhlNm4zOWZhMDdkYzVlZHp2MHJsYTRlIiBhbHQ9IkxpbmtlZEluIiBjbGFzcz0iYmxvY2sgaC1bMTRweF0gdy1bNTZweF0gaW1hZ2UtcmVuZGVyaW5nLWNyaXNwIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBpbWFnZS1yZW5kZXJpbmc6IC1tb3otY3Jpc3AtZWRnZXM7IGltYWdlLXJlbmRlcmluZzogLW8tY3Jpc3AtZWRnZXM7IGltYWdlLXJlbmRlcmluZzogLXdlYmtpdC1vcHRpbWl6ZS1jb250cmFzdDsgaW1hZ2UtcmVuZGVyaW5nOiBjcmlzcC1lZGdlczsgLW1zLWludGVycG9sYXRpb24tbW9kZTogbmVhcmVzdC1uZWlnaGJvcjsgZGlzcGxheTogYmxvY2s7IGhlaWdodDogMTRweDsgd2lkdGg6IDU2cHg7IiB3aWR0aD0iNTYiIGhlaWdodD0iMTQiPiA8L2E-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGRhdGEtdGVzdC1jb3B5cmlnaHQtdGV4dCBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gwqkgMjAyNCBMaW5rZWRJbiBDb3Jwb3JhdGlvbiwgMSZ6d25qOzAwMCBXZXN0IE1hdWRlIEF2ZW51ZSwgU3Vubnl2YWxlLCBDQSA5NDA4NS4gPHNwYW4gZGF0YS10ZXN0LXRyYWRlbWFya3MtdGV4dD4gTGlua2VkSW4gYW5kIHRoZSBMaW5rZWRJbiBsb2dvIGFyZSByZWdpc3RlcmVkIHRyYWRlbWFya3Mgb2YgTGlua2VkSW4uIDwvc3Bhbj4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPGltZyBhbHQgcm9sZT0icHJlc2VudGF0aW9uIiBzcmM9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9lbWltcC9pcF9ZV3BrTm1SVVpIQk1WekI2WlVSUmVsa3pUakpNVkVwcU9scFhNV2hoVjNobVltMVdNR1F5T1hsaE1UbHFZakkxTWxwWVNucFpXRkp3WWpJMWVsaDZRWGc2LmdpZiIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgd2lkdGg6IDFweDsgaGVpZ2h0OiAxcHg7IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIj4gPC9ib2R5PiA8L2h0bWw-" - } - } - ] - }, - "sizeEstimate": 126327, - "historyId": "527489", - "internalDate": "1732546821000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_06_19363ba8e2582133_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_06_19363ba8e2582133_20241126.json deleted file mode 100644 index 540a154..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_06_19363ba8e2582133_20241126.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "id": "19363ba8e2582133", - "threadId": "19363ba8e2582133", - "labelIds": [ - "UNREAD", - "CATEGORY_SOCIAL", - "INBOX" - ], - "snippet": "Here's what's happened since you were last on LinkedIn \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp931742wrq; Mon, 25 Nov 2024 06:29:51 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IEbPIe+TQ88Z+DHd/A8yyLcAOjv+R1/RIRwiGYiSt7ujLYGK/lw0vafU0SHGdQj6lXZicwS" - }, - { - "name": "X-Received", - "value": "by 2002:a05:6a00:3ccc:b0:71e:818a:97d9 with SMTP id d2e1a72fcca58-724df3c8151mr20294806b3a.5.1732544991113; Mon, 25 Nov 2024 06:29:51 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732544991; cv=none; d=google.com; s=arc-20240605; b=Wxqp5Njjc5z1wRZ9vyWy4ihWjaE4SrMZsFoHfAbUhXYc7PnTsQaLebvf+Zg9oqipO2 7e72Ig1P9gfmke8h4jj0AfYHkiXQjkcOk0L0qQRrk7Fhm8y+bbqU/R6GjhZJO5Hp5njx bN/jQzJtO8Rnz5NpVU1ETfKChDRkM4/STfudNz0CvRDyskVVkeuoYmbvLFcSN6CUn4tt ye1hOKaQtTkq52DX9jVw1T0VXynCViWWpaybNg1TJOnezXXcNm2b+sTA61Cu8PQnhrNJ n9gi1Q/PW60s8yENi5loDvB3iAvi+7E1iNrUui3OhKTVHgWAV7KWiAKkvlsCCLORUc1T z42Q==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=require-recipient-valid-since:feedback-id:list-unsubscribe-post :list-unsubscribe:date:to:mime-version:subject:message-id:from :dkim-signature:dkim-signature; bh=udF/XJRPK1mCktHLuGIIfGeisUjxh0OfM+Tlg7u5R9g=; fh=kl8GOc3xH49wmCQ5W74DCe5pDhPNnAeFoI4mGP4/wX4=; b=RgsKftzTPZcKwxh/G/887LKpeDh6lU89MW+LoktXl0h6OZM2Mv8afCVBFjWsojIANF OY81a561ZEk9EbYADd1vGn7zL1cByE1/7p6xsigppTnhotEK8DpHCwGJeqdnpjVitPvA I106x5rD2+qzC/Lsmb0zAfify/FXY+NfInQQczg16gG6ONKcVGgxbUgzbtHePWmhxdRI XSbZNVRZIzLz1vTX/GfZjRmKBe1J2vY22BpD1mx0GAmAPE1rjVS0cFKavyz8rF/br8WN OLjkjTwY/CyKq4cfnH5uvDI7N+CsxMIgIu6NDt8/l01KLYjSmKPFOBkpzT6Ks/Grtt3+ 5O4w==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@mailc.linkedin.com header.s=d2048-202308-0c header.b=XUxElvqG; dkim=pass header.i=@linkedin.com header.s=d2048-202308-00 header.b=eEOICj8q; spf=pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emjprzmiodkrl@bounce.linkedin.com designates 2620:109:c003:104::161 as permitted sender) smtp.mailfrom=m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emjprzmiodkrl@bounce.linkedin.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=linkedin.com" - }, - { - "name": "Return-Path", - "value": "" - }, - { - "name": "Received", - "value": "from mailc-ca.linkedin.com (mailc-ca.linkedin.com. [2620:109:c003:104::161]) by mx.google.com with ESMTPS id d2e1a72fcca58-72519ec5c96si400699b3a.371.2024.11.25.06.29.50 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 25 Nov 2024 06:29:51 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emjprzmiodkrl@bounce.linkedin.com designates 2620:109:c003:104::161 as permitted sender) client-ip=2620:109:c003:104::161;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@mailc.linkedin.com header.s=d2048-202308-0c header.b=XUxElvqG; dkim=pass header.i=@linkedin.com header.s=d2048-202308-00 header.b=eEOICj8q; spf=pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emjprzmiodkrl@bounce.linkedin.com designates 2620:109:c003:104::161 as permitted sender) smtp.mailfrom=m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo1emjprzmiodkrl@bounce.linkedin.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=linkedin.com" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailc.linkedin.com; s=d2048-202308-0c; t=1732544987; bh=udF/XJRPK1mCktHLuGIIfGeisUjxh0OfM+Tlg7u5R9g=; h=From:Subject:MIME-Version:Content-Type:To:Date:X-LinkedIn-Class:\t X-LinkedIn-Template:X-LinkedIn-fbl; b=XUxElvqGO3ViqDffleqSmJOF/ZDaKDpiTnSv7vejgQqlK5ac8rl7QpZ74KquDvVSY\t OhGD5AQMrZw+yR913qRvj3tzS+n+9x2M4vdiCzVaZEZB4vPoeg7osKsdsFgor5yi+R\t b9zg16ovDDFoB2QPkrwSWQyFss+iOxGvM0w0fyHoqoNYf/q3JOwigzjj4SvtmGSxJ3\t UNIR9Lc2K9DGvTyYJ8e3Y/906t20DvpelCbxvTBEyGgi0diSxmA0Rw5a0UUSxVaUqd\t VqjhBTDqxSwRQwttoRQ0XBVjqm64XQ5fGsazJSRjuHD1VloxHu3dtX/Ss5dAoajvus\t cMMSwhfbsnUBA==" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linkedin.com; s=d2048-202308-00; t=1732544987; bh=udF/XJRPK1mCktHLuGIIfGeisUjxh0OfM+Tlg7u5R9g=; h=From:Subject:MIME-Version:Content-Type:To:Date:X-LinkedIn-Class:\t X-LinkedIn-Template:X-LinkedIn-fbl; b=eEOICj8q4rI5QFph2OzYmK3p6xwZY3pJfAfq7/+JS+IHd0fAjuEA34d3dZgADxUNo\t QefEvudi3vlE6D/ygvX+8l1pm/8/feQaCnSTzssropJtrmc+PZGO12ba6m9sxfG7EQ\t +pq8I4pZ8+3YyDKCjcneoPzPbBqqX+LCnhJ8yuAX7v9IcW7KtT9qQtje9LwY7RRjTL\t QtYSqp7FCzay59pBDSFSYNeYXhYRGNtylfWofu+xgQ5D1YiR2ARqI4kolxvgPEmtkO\t PzxlGATlIzInLPKEppcmQ0cz1xK0sDIapONVyOhNgJaA+xK8AwbunLrSeqei2TgyO0\t p0uM+TQMHBGXg==" - }, - { - "name": "From", - "value": "LinkedIn " - }, - { - "name": "Message-ID", - "value": "<1307744455.19685006.1732544987164@lor1-app113732.prod.linkedin.com>" - }, - { - "name": "Subject", - "value": "Don\u2019t be too quick to accept a job\u2026" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"----=_Part_19685004_847781199.1732544987162\"" - }, - { - "name": "To", - "value": "Khushal PS " - }, - { - "name": "Date", - "value": "Mon, 25 Nov 2024 14:29:47 +0000 (UTC)" - }, - { - "name": "X-LinkedIn-Class", - "value": "NETWORKDIGEST" - }, - { - "name": "X-LinkedIn-Template", - "value": "email_notification_digest_01" - }, - { - "name": "X-LinkedIn-fbl", - "value": "m2-aszqd8zkspuf287a8bx31vrz8sk5ja17z01xcysyvru7cm8ox3fyjnnbn805spqs14tmds35nuyhnbcesiw70a1qp24c3d0m71rtbm" - }, - { - "name": "X-LinkedIn-Id", - "value": "j7zu7i-m3x4exhn-ja" - }, - { - "name": "List-Unsubscribe", - "value": "" - }, - { - "name": "List-Unsubscribe-Post", - "value": "List-Unsubscribe=One-Click" - }, - { - "name": "Feedback-ID", - "value": "email_notification_digest_01:linkedin" - }, - { - "name": "Require-Recipient-Valid-Since", - "value": "pskhushal@gmail.com; Mon, 24 Jul 2023 06:55:23 +0000" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain;charset=UTF-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - }, - { - "name": "Content-ID", - "value": "text-body" - } - ], - "body": { - "size": 2736, - "data": "RG9u4oCZdCBiZSB0b28gcXVpY2sgdG8gYWNjZXB0IGEgam9iIG9mZmVyLiBNYWtlIHN1cmUgdG8gYXNrIHlvdXJzZWxmIHRoZXNlIHF1ZXN0aW9ucyBmaXJzdC4NClNlZSBuZXdzbGV0dGVyOmh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybiUzQWxpJTNBYWN0aXZpdHklM0E3MjY1MzMzNDQ5NDA4ODY0MjU3P2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJm1pZFRva2VuPUFRRlBhMjNOem8xOEZRJm1pZFNpZz0ybWF1Y19tZnZCQ1h3MSZ0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtbm90aWZpY2F0aW9uX2RpZ2VzdC0wLUVESVRPUklBTF9CTEFaRV9JTkFQUCZ0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1ub3RpZmljYXRpb25fZGlnZXN0LTAtRURJVE9SSUFMX0JMQVpFX0lOQVBQLW51bGwtajd6dTdpfm0zeDRleGhufmphLW51bGwtbnVsbCZlaWQ9ajd6dTdpLW0zeDRleGhuLWphJm90cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1OaFpEazBPVGxtWVdFNFpUWmhOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5HUmtObU5oWmpNME5XWmpZekpoWWpFelpXSTJPVEZtTWpNd1lXUm1PVFppTXpJek1EWm1aR1V4T1RFME5UZzBMREVzTVElM0QlM0QNCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNClRoaXMgZW1haWwgd2FzIGludGVuZGVkIGZvciBLaHVzaGFsIFBTICgtLSkNCkxlYXJuIHdoeSB3ZSBpbmNsdWRlZCB0aGlzOiBodHRwczovL3d3dy5saW5rZWRpbi5jb20vaGVscC9saW5rZWRpbi9hbnN3ZXIvNDc4OD9sYW5nPWVuJmxpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJm1pZFRva2VuPUFRRlBhMjNOem8xOEZRJm1pZFNpZz0ybWF1Y19tZnZCQ1h3MSZ0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtU2VjdXJpdHlIZWxwLTAtdGV4dGZvb3RlcmdsaW1tZXImdHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtU2VjdXJpdHlIZWxwLTAtdGV4dGZvb3RlcmdsaW1tZXItbnVsbC1qN3p1N2l-bTN4NGV4aG5-amEtbnVsbC1udWxsJmVpZD1qN3p1N2ktbTN4NGV4aG4tamEmb3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU5oWkRrME9UbG1ZV0U0WlRaaE4ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkdSa05tTmhaak0wTldaall6SmhZakV6WldJMk9URm1Nak13WVdSbU9UWmlNekl6TURabVpHVXhPVEUwTlRnMExERXNNUSUzRCUzRA0KWW91IGFyZSByZWNlaXZpbmcgTGlua2VkSW4gbm90aWZpY2F0aW9uIGVtYWlscy4NCg0KVW5zdWJzY3JpYmU6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL3BzZXR0aW5ncy9lbWFpbC11bnN1YnNjcmliZT9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkJsOWY1ejVZUk9TbXJWc00lMkZFZ2hoZyUzRCUzRCZtaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZtaWRTaWc9Mm1hdWNfbWZ2QkNYdzEmdHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLXVuc3Vic2NyaWJlLTAtdGV4dGZvb3RlcmdsaW1tZXImdHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtdW5zdWJzY3JpYmUtMC10ZXh0Zm9vdGVyZ2xpbW1lci1udWxsLWo3enU3aX5tM3g0ZXhobn5qYS1udWxsLW51bGwmZWlkPWo3enU3aS1tM3g0ZXhobi1qYSZsb2lkPUFRSDVQQ3dDVjR3WF9BQUFBWk5qdW4wTEhVVHROM3R5dHdEYlN2Q0U0UWR2RTNNMFhaVzV4cmpfdFFRdFRLdEZ4WHljMHNOZnVmRHVXR2dkLXl5blNudkVrcFlDbWVIUEs3RFFNancNCkhlbHA6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9oZWxwL2xpbmtlZGluL2Fuc3dlci82Nz9sYW5nPWVuJmxpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJm1pZFRva2VuPUFRRlBhMjNOem8xOEZRJm1pZFNpZz0ybWF1Y19tZnZCQ1h3MSZ0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVscC0wLXRleHRmb290ZXJnbGltbWVyJnRya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLWhlbHAtMC10ZXh0Zm9vdGVyZ2xpbW1lci1udWxsLWo3enU3aX5tM3g0ZXhobn5qYS1udWxsLW51bGwmZWlkPWo3enU3aS1tM3g0ZXhobi1qYSZvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTmhaRGswT1RsbVlXRTRaVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVOR1JrTm1OaFpqTTBOV1pqWXpKaFlqRXpaV0kyT1RGbU1qTXdZV1JtT1RaaU16SXpNRFptWkdVeE9URTBOVGcwTERFc01RJTNEJTNEDQoNCsKpIDIwMjQgTGlua2VkSW4gQ29ycG9yYXRpb24sIDF6d25qMDAwIFdlc3QgTWF1ZGUgQXZlbnVlLCBTdW5ueXZhbGUsIENBIDk0MDg1Lg0KTGlua2VkSW4gYW5kIHRoZSBMaW5rZWRJbiBsb2dvIGFyZSByZWdpc3RlcmVkIHRyYWRlbWFya3Mgb2YgTGlua2VkSW4u" - } - }, - { - "partId": "1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html;charset=UTF-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - }, - { - "name": "Content-ID", - "value": "html-body" - } - ], - "body": { - "size": 22899, - "data": "PGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIGxhbmc9ImVuIiB4bWw6bGFuZz0iZW4iPiA8aGVhZD4gPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7Y2hhcnNldD11dGYtOCI-IDxtZXRhIG5hbWU9IkhhbmRoZWxkRnJpZW5kbHkiIGNvbnRlbnQ9InRydWUiPiA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoOyBpbml0aWFsLXNjYWxlPTAuNjY2NjY3OyB1c2VyLXNjYWxhYmxlPTAiPiA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoIj4gPHRpdGxlPjwvdGl0bGU-IDxzdHlsZT4NCiAgICAgICAgICAgIEBtZWRpYSAobWF4LXdpZHRoOiA1MTJweCkgeyAubWVyY2Fkby1jb250YWluZXIgeyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyB9IH0NCiAgICAgICAgICA8L3N0eWxlPiA8c3R5bGU-DQogICAgICAgICAgICBAbWVkaWEgKG1heC13aWR0aDogNDgwcHgpIHsgLmlubGluZS1idXR0b24sIC5pbmxpbmUtYnV0dG9uIHRhYmxlIHsgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50OyB9DQogICAgICAgICAgICAuZnVsbC13aWR0aC1idXR0b24sIC5mdWxsLXdpZHRoLWJ1dHRvbiB0YWJsZSB7IGRpc3BsYXk6IHRhYmxlICFpbXBvcnRhbnQ7IH0gfQ0KICAgICAgICAgIDwvc3R5bGU-IDxzdHlsZT5ib2R5IHtmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgc3lzdGVtLXVpLCBCbGlua01hY1N5c3RlbUZvbnQsICdTZWdvZSBVSScsIFJvYm90bywgJ0hlbHZldGljYSBOZXVlJywNCiAgICAgICAgICAgICdGaXJhIFNhbnMnLCBVYnVudHUsIE94eWdlbiwgJ094eWdlbiBTYW5zJywgQ2FudGFyZWxsLCAnRHJvaWQgU2FucycsICdBcHBsZSBDb2xvciBFbW9qaScsICdTZWdvZSBVSSBFbW9qaScsDQogICAgICAgICAgICAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgU3ltYm9sJywgJ0x1Y2lkYSBHcmFuZGUnLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmO308L3N0eWxlPiA8IS0tW2lmIG1zb10-PHN0eWxlIHR5cGU9InRleHQvY3NzIj4gPC9zdHlsZT48IVtlbmRpZl0tLT4gPCEtLVtpZiBJRV0-PHN0eWxlIHR5cGU9InRleHQvY3NzIj4gPC9zdHlsZT48IVtlbmRpZl0tLT4gPC9oZWFkPiA8Ym9keSBkaXI9Imx0ciIgY2xhc3M9ImZvbnQtc2FucyBiZy1jb2xvci1iYWNrZ3JvdW5kLWNhbnZhcyB3LWZ1bGwgbS0wIHAtMCBwdC0xIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbWFyZ2luOiAwcHg7IHdpZHRoOiAxMDAlOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjNmMmYwOyBwYWRkaW5nOiAwcHg7IHBhZGRpbmctdG9wOiA4cHg7IGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBzeXN0ZW0tdWksIEJsaW5rTWFjU3lzdGVtRm9udCwgJ1NlZ29lIFVJJywgUm9ib3RvLCAnSGVsdmV0aWNhIE5ldWUnLCAnRmlyYSBTYW5zJywgVWJ1bnR1LCBPeHlnZW4sICdPeHlnZW4gU2FucycsIENhbnRhcmVsbCwgJ0Ryb2lkIFNhbnMnLCAnQXBwbGUgQ29sb3IgRW1vamknLCAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgU3ltYm9sJywgJ0x1Y2lkYSBHcmFuZGUnLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmOyI-IDxkaXYgY2xhc3M9ImgtMCBvcGFjaXR5LTAgdGV4dC10cmFuc3BhcmVudCBpbnZpc2libGUgb3ZlcmZsb3ctaGlkZGVuIHctMCBtYXgtaC1bMF0iIHN0eWxlPSJ2aXNpYmlsaXR5OiBoaWRkZW47IGhlaWdodDogMHB4OyBtYXgtaGVpZ2h0OiAwOyB3aWR0aDogMHB4OyBvdmVyZmxvdzogaGlkZGVuOyBvcGFjaXR5OiAwOyBtc28taGlkZTogYWxsOyIgZGF0YS1lbWFpbC1wcmVoZWFkZXI9InRydWUiPkhlcmXigJlzIHdoYXTigJlzIGhhcHBlbmVkIHNpbmNlIHlvdSB3ZXJlIGxhc3Qgb24gTGlua2VkSW48L2Rpdj4gPGRpdiBjbGFzcz0iaC0wIG9wYWNpdHktMCB0ZXh0LXRyYW5zcGFyZW50IGludmlzaWJsZSBvdmVyZmxvdy1oaWRkZW4gdy0wIG1heC1oLVswXSIgc3R5bGU9InZpc2liaWxpdHk6IGhpZGRlbjsgaGVpZ2h0OiAwcHg7IG1heC1oZWlnaHQ6IDA7IHdpZHRoOiAwcHg7IG92ZXJmbG93OiBoaWRkZW47IG9wYWNpdHk6IDA7IG1zby1oaWRlOiBhbGw7Ij4gzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCA8L2Rpdj4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iNTEyIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0ibWVyY2Fkby1jb250YWluZXIgdy1bNTEycHhdIG1heC13LVs1MTJweF0gbXgtYXV0byBteS0wIHAtMCBiZy1jb2xvci1iYWNrZ3JvdW5kLWNvbnRhaW5lciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW4tbGVmdDogYXV0bzsgbWFyZ2luLXJpZ2h0OiBhdXRvOyBtYXJnaW4tdG9wOiAwcHg7IG1hcmdpbi1ib3R0b206IDBweDsgd2lkdGg6IDUxMnB4OyBtYXgtd2lkdGg6IDUxMnB4OyBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmZmZmOyBwYWRkaW5nOiAwcHg7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0idGV4dC1jZW50ZXIgcC0zIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmc6IDI0cHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0ibWluLXctZnVsbCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtaW4td2lkdGg6IDEwMCU7Ij4gPHRib2R5PiA8dHI-IDx0ZCBhbGlnbj0ibGVmdCIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkLz9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkJsOWY1ejVZUk9TbXJWc00lMkZFZ2hoZyUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0ybWF1Y19tZnZCQ1h3MSZhbXA7dHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLWhlYWRlci0wLWhvbWVfZ2xpbW1lcl9keW5hbWljX2JhZGdpbmdfaGlnaF9kcGkmYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLWhlYWRlci0wLWhvbWVfZ2xpbW1lcl9keW5hbWljX2JhZGdpbmdfaGlnaF9kcGktbnVsbC1qN3p1N2l-bTN4NGV4aG5-amEtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDRleGhuLWphJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTmhaRGswT1RsbVlXRTRaVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVOR1JrTm1OaFpqTTBOV1pqWXpKaFlqRXpaV0kyT1RGbU1qTXdZV1JtT1RaaU16SXpNRFptWkdVeE9URTBOVGcwTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgY2xhc3M9InctWzg0cHhdIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHdpZHRoOiA4NHB4OyI-IDxpbWcgY2xhc3M9ImgtWzM3cHhdIHctWzEwMXB4XSIgYWx0PSJMaW5rZWRJbiIgc3JjPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9kbXMvbG9nby92Mj9iYWRnZVRoZW1lPW1lcmNhZG8mYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRTaWc9Mm1hdWNfbWZ2QkNYdzEmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1udWxsLTAtY29tbXMlN0ViYWRnaW5nJTdFZHluYW1pYyU3RWdsaW1tZXIlN0V2Mi1udWxsLWo3enU3aSU3RW0zeDRleGhuJTdFamEtbnVsbC1udWxsJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtbnVsbC0wLWNvbW1zJTdFYmFkZ2luZyU3RWR5bmFtaWMlN0VnbGltbWVyJTdFdjImYW1wO19zaWc9MTVhdXNGVUtUQkNYdzEiIGRhdGEtdGVzdC1oZWFkZXItZHluYW1pYy1iYWRnaW5nLWltZy1oaWdoLWRwaSBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBoZWlnaHQ6IDM3cHg7IHdpZHRoOiAxMDFweDsiIHdpZHRoPSIxMDEiIGhlaWdodD0iMzciPiA8L2E-IDwvdGQ-IDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249InJpZ2h0IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgZGF0YS10ZXN0LWhlYWRlci1wcm9maWxlIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGFsaWduPSJyaWdodCIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8YSBocmVmPSJodHRwczovL2luLmxpbmtlZGluLmNvbS9jb21tL2luL2todXNoYWwtcHMtN2E2MmI3Mjg1P2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTJtYXVjX21mdkJDWHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVhZGVyLTAtcHJvZmlsZV9nbGltbWVyJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1oZWFkZXItMC1wcm9maWxlX2dsaW1tZXItbnVsbC1qN3p1N2l-bTN4NGV4aG5-amEtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDRleGhuLWphJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTmhaRGswT1RsbVlXRTRaVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVOR1JrTm1OaFpqTTBOV1pqWXpKaFlqRXpaV0kyT1RGbU1qTXdZV1JtT1RaaU16SXpNRFptWkdVeE9URTBOVGcwTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxzcGFuIGNsYXNzPSJuby11bmRlcmxpbmUgdGV4dC1zeXN0ZW0tZ3JheS05MCIgc3R5bGU9ImNvbG9yOiAjMjgyODI4OyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPktodXNoYWwgUFM8L3NwYW4-IDwvYT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InB4LTMgcGItMyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWxlZnQ6IDI0cHg7IHBhZGRpbmctcmlnaHQ6IDI0cHg7IHBhZGRpbmctYm90dG9tOiAyNHB4OyI-IDxkaXY-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJweC0xICIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWxlZnQ6IDhweDsgcGFkZGluZy1yaWdodDogOHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGNsYXNzIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJwYi0yIHRleHQtY2VudGVyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctYm90dG9tOiAxNnB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iYXV0byIgYWxpZ249ImNlbnRlciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImlubGluZS1ibG9jayB3LTggaC04IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgaGVpZ2h0OiA2NHB4OyB3aWR0aDogNjRweDsiIHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybiUzQWxpJTNBYWN0aXZpdHklM0E3MjY1MzMzNDQ5NDA4ODY0MjU3P2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTJtYXVjX21mdkJDWHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtZW50aXR5X3BpbGUtMC1FRElUT1JJQUxfQkxBWkVfSU5BUFBfMCZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtZW50aXR5X3BpbGUtMC1FRElUT1JJQUxfQkxBWkVfSU5BUFBfMC1udWxsLWo3enU3aX5tM3g0ZXhobn5qYS1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN4NGV4aG4tamEmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakU0WW1OaFpEazBPVGxtWVdFNFpUWmhOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU5HUmtObU5oWmpNME5XWmpZekpoWWpFelpXSTJPVEZtTWpNd1lXUm1PVFppTXpJek1EWm1aR1V4T1RFME5UZzBMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7Ij4gPGltZyBjbGFzcz0iaW5saW5lLWJsb2NrIHJlbGF0aXZlIGJnLWNvbG9yLWVudGl0eS1naG9zdC1iYWNrZ3JvdW5kIHctOCBoLTggIWJsb2NrIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9hZXJvLXYxL3NjL2gvODd1dTd4NW13bWF0c243djZmMjhzMjZvNSIgYWx0PSJHZXQgSGlyZWQgTG9nbyIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgcG9zaXRpb246IHJlbGF0aXZlOyBoZWlnaHQ6IDY0cHg7IHdpZHRoOiA2NHB4OyBiYWNrZ3JvdW5kLWNvbG9yOiAjZWFlNmRmOyBkaXNwbGF5OiBibG9jayAhaW1wb3J0YW50OyIgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0Ij4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icGItMiB0ZXh0LWNlbnRlciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogMTZweDsgdGV4dC1hbGlnbjogY2VudGVyOyI-IERvbuKAmXQgYmUgdG9vIHF1aWNrIHRvIGFjY2VwdCBhIGpvYiBvZmZlci4gTWFrZSBzdXJlIHRvIGFzayB5b3Vyc2VsZiB0aGVzZSBxdWVzdGlvbnMgZmlyc3QuIDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJ0ZXh0LWNlbnRlciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgY2xhc3M9ImVtYWlsLWJ1dHRvbiAiIGRhdGEtdGVzdC1pZD0iZW1haWwtYnV0dG9uIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249Im1pZGRsZSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybiUzQWxpJTNBYWN0aXZpdHklM0E3MjY1MzMzNDQ5NDA4ODY0MjU3P2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTJtYXVjX21mdkJDWHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVyb19ub3RpZmljYXRpb25fY3RhLTAtRURJVE9SSUFMX0JMQVpFX0lOQVBQJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1oZXJvX25vdGlmaWNhdGlvbl9jdGEtMC1FRElUT1JJQUxfQkxBWkVfSU5BUFAtbnVsbC1qN3p1N2l-bTN4NGV4aG5-amEtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDRleGhuLWphJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTmhaRGswT1RsbVlXRTRaVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVOR1JrTm1OaFpqTTBOV1pqWXpKaFlqRXpaV0kyT1RGbU1qTXdZV1JtT1RaaU16SXpNRFptWkdVeE9URTBOVGcwTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgYXJpYS1sYWJlbD0iUmVhZCBtb3JlIiBjbGFzcz0iYWxpZ24tdG9wIG5vLXVuZGVybGluZSAiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgdmVydGljYWwtYWxpZ246IHRvcDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iYXV0byIgY2xhc3M9ImJvcmRlci1zZXBhcmF0ZSAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBzZXBhcmF0ZTsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJidG4tbWQgYnRuLXByaW1hcnkgYm9yZGVyLWNvbG9yLWJyYW5kIGJ1dHRvbi1saW5rIGxlYWRpbmctcmVndWxhciAhbWluLWgtW2F1dG9dICFzaGFkb3ctbm9uZSBib3JkZXItMSBib3JkZXItc29saWQgdy1bMzkwcHhdIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGhlaWdodDogbWluLWNvbnRlbnQ7IGJvcmRlci1yYWRpdXM6IDI0cHg7IHBhZGRpbmctdG9wOiAxMnB4OyBwYWRkaW5nLWJvdHRvbTogMTJweDsgcGFkZGluZy1sZWZ0OiAyNHB4OyBwYWRkaW5nLXJpZ2h0OiAyNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGZvbnQtc2l6ZTogMTZweDsgZm9udC13ZWlnaHQ6IDYwMDsgY3Vyc29yOiBwb2ludGVyOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsgYmFja2dyb3VuZC1jb2xvcjogIzBhNjZjMjsgY29sb3I6ICNmZmZmZmY7IHdpZHRoOiAzOTBweDsgYm9yZGVyLXdpZHRoOiAxcHg7IGJvcmRlci1zdHlsZTogc29saWQ7IGJvcmRlci1jb2xvcjogIzBhNjZjMjsgbGluZS1oZWlnaHQ6IDEuMjU7IG1pbi1oZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsgYm94LXNoYWRvdzogMCAwICMwMDAwLCAwIDAgIzAwMDAsIDAgMCAjMDAwMCAhaW1wb3J0YW50OyIgd2lkdGg9IjM5MCI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvdXBkYXRlL3VybiUzQWxpJTNBYWN0aXZpdHklM0E3MjY1MzMzNDQ5NDA4ODY0MjU3P2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTJtYXVjX21mdkJDWHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVyb19ub3RpZmljYXRpb25fY3RhLTAtRURJVE9SSUFMX0JMQVpFX0lOQVBQJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1oZXJvX25vdGlmaWNhdGlvbl9jdGEtMC1FRElUT1JJQUxfQkxBWkVfSU5BUFAtbnVsbC1qN3p1N2l-bTN4NGV4aG5-amEtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDRleGhuLWphJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTmhaRGswT1RsbVlXRTRaVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVOR1JrTm1OaFpqTTBOV1pqWXpKaFlqRXpaV0kyT1RGbU1qTXdZV1JtT1RaaU16SXpNRFptWkdVeE9URTBOVGcwTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgdGFiaW5kZXg9Ii0xIiBhcmlhLWhpZGRlbj0idHJ1ZSIgY2xhc3M9Im5vLXVuZGVybGluZSIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiA8c3BhbiBjbGFzcz0ibm8tdW5kZXJsaW5lIHRleHQtd2hpdGUiIHN0eWxlPSJjb2xvcjogI2ZmZmZmZjsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gUmVhZCBtb3JlIDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvZGl2PiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0iYmctY29sb3ItYmFja2dyb3VuZC1jYW52YXMgcC0zIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJhY2tncm91bmQtY29sb3I6ICNmM2YyZjA7IHBhZGRpbmc6IDI0cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9InRleHQtY2VudGVyIHBiLTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1ib3R0b206IDE2cHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPiA8aDIgY2xhc3M9InRleHQtbGcgdGV4dC10ZWFsLTgwIiBzdHlsZT0ibWFyZ2luOiAwOyBmb250LXdlaWdodDogNTAwOyBmb250LXNpemU6IDIwcHg7IGNvbG9yOiAjMTE0OTUxOyI-IEdldCB0aGUgbmV3IExpbmtlZEluIGRlc2t0b3AgYXBwIDwvaDI-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJ0ZXh0LWNlbnRlciBwYi0yIiBkYXRhLXRlc3QtaWQ9ImZvb3Rlci1hcHAtc3RvcmUtaWNvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogMTZweDsgdGV4dC1hbGlnbjogY2VudGVyOyI-IDxhIGhyZWY9Imh0dHBzOi8vYXBwcy5taWNyb3NvZnQuY29tL3N0b3JlL2RldGFpbC85V1pETkNSRko0UTc_bGF1bmNoPXRydWUmYW1wO2NpZD1saW5rZWRpbl9lbWFpbF91cHNlbGwmYW1wO21vZGU9ZnVsbCIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxpbWcgYWx0PSJHZXQgaXQgZnJvbSBNaWNyb3NvZnQiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL2Flcm8tdjEvc2MvaC9lanBra3B3dnFrczMxYTNjanFva2I3ZmJtIiBjbGFzcz0iaC1bNDBweF0gdy1bMTEycHhdIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBoZWlnaHQ6IDQwcHg7IHdpZHRoOiAxMTJweDsiIHdpZHRoPSIxMTIiIGhlaWdodD0iNDAiPiA8L2E-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJ0ZXh0LWNlbnRlciBwYi0yIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctYm90dG9tOiAxNnB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPGgyIGNsYXNzPSJ0ZXh0LW1kIHRleHQtdGVhbC04MCIgc3R5bGU9Im1hcmdpbjogMDsgZm9udC13ZWlnaHQ6IDUwMDsgZm9udC1zaXplOiAxNnB4OyBjb2xvcjogIzExNDk1MTsiPiBBbHNvIGF2YWlsYWJsZSBvbiBtb2JpbGUgPC9oMj4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InRleHQtY2VudGVyIiBkYXRhLXRlc3QtaWQ9ImZvb3Rlci1hcHAtc3RvcmUtaWNvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPGEgaHJlZj0iaHR0cHM6Ly9pdHVuZXMuYXBwbGUuY29tL3VzL2FwcC9saW5rZWRpbi9pZDI4ODQyOTA0MD9wdD0xMDc0NiZhbXA7Y3Q9c3RfYXBwc2l0ZV9mbGFnc2hpcCZhbXA7bXQ9OCIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxpbWcgYWx0PSJEb3dubG9hZCBvbiB0aGUgQXBwIFN0b3JlIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9hZXJvLXYxL3NjL2gvNzZ5emtkMGg1a2l2MjdscmQ0eWFlbnlsayIgY2xhc3M9ImgtWzQwcHhdIHctWzEyMHB4XSBwci0xIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBoZWlnaHQ6IDQwcHg7IHdpZHRoOiAxMjBweDsgcGFkZGluZy1yaWdodDogOHB4OyIgd2lkdGg9IjEyMCIgaGVpZ2h0PSI0MCI-IDwvYT4gPGEgaHJlZj0iaHR0cHM6Ly9wbGF5Lmdvb2dsZS5jb20vc3RvcmUvYXBwcy9kZXRhaWxzP2lkPWNvbS5saW5rZWRpbi5hbmRyb2lkJmFtcDtyZWZlcnJlcj1zdF9hcHBzaXRlX2ZsYWdzaGlwIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciBub3JlZmVycmVyIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7Ij4gPGltZyBhbHQ9IkdldCBpdCBvbiBHb29nbGUgUGxheSIgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vYWVyby12MS9zYy9oLzE0MnF1ZHdibHA1OHp3bWM5dmtxZnBsdWciIGNsYXNzPSJoLVs0MHB4XSB3LVsxMzRweF0iIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGhlaWdodDogNDBweDsgd2lkdGg6IDEzNHB4OyIgd2lkdGg9IjEzNCIgaGVpZ2h0PSI0MCI-IDwvYT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InB5LTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7IHBhZGRpbmctYm90dG9tOiAxNnB4OyI-PGhyIGNsYXNzPSJib3JkZXItbm9uZSBiZy1bI2UwZGZkZF0gaC1bMXB4XSIgc3R5bGU9ImhlaWdodDogMXB4OyBib3JkZXItc3R5bGU6IG5vbmU7IGJhY2tncm91bmQtY29sb3I6ICNlMGRmZGQ7Ij48L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0idGV4dC14cyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDEycHg7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0icGItMSBtLTAiIGRhdGEtdGVzdC1pZD0iZW1haWwtZm9vdGVyX19pbnRlbmRlZCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW46IDBweDsgcGFkZGluZy1ib3R0b206IDhweDsiPiBUaGlzIGVtYWlsIHdhcyBpbnRlbmRlZCBmb3IgS2h1c2hhbCBQUyAoLS0pIDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwYi0xIG0tMCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW46IDBweDsgcGFkZGluZy1ib3R0b206IDhweDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vaGVscC9saW5rZWRpbi9hbnN3ZXIvNDc4OD9sYW5nPWVuJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkJsOWY1ejVZUk9TbXJWc00lMkZFZ2hoZyUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0ybWF1Y19tZnZCQ1h3MSZhbXA7dHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLVNlY3VyaXR5SGVscC0wLWZvb3RlcmdsaW1tZXImYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLVNlY3VyaXR5SGVscC0wLWZvb3RlcmdsaW1tZXItbnVsbC1qN3p1N2l-bTN4NGV4aG5-amEtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDRleGhuLWphJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpFNFltTmhaRGswT1RsbVlXRTRaVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVOR1JrTm1OaFpqTTBOV1pqWXpKaFlqRXpaV0kyT1RGbU1qTXdZV1JtT1RaaU16SXpNRFptWkdVeE9URTBOVGcwTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgY2xhc3M9InRleHQtaW5oZXJpdCB1bmRlcmxpbmUiIHN0eWxlPSJjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBjb2xvcjogaW5oZXJpdDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IHVuZGVybGluZTsiPkxlYXJuIHdoeSB3ZSBpbmNsdWRlZCB0aGlzLjwvYT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InBiLTEgbS0wIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IG1hcmdpbjogMHB4OyBwYWRkaW5nLWJvdHRvbTogOHB4OyI-WW91IGFyZSByZWNlaXZpbmcgTGlua2VkSW4gbm90aWZpY2F0aW9uIGVtYWlscy48L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icGItMSBtLTAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgbWFyZ2luOiAwcHg7IHBhZGRpbmctYm90dG9tOiA4cHg7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vcHNldHRpbmdzL2VtYWlsLXVuc3Vic2NyaWJlP2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTJtYXVjX21mdkJDWHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtdW5zdWJzY3JpYmUtMC1mb290ZXJHbGltbWVyJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS11bnN1YnNjcmliZS0wLWZvb3RlckdsaW1tZXItbnVsbC1qN3p1N2l-bTN4NGV4aG5-amEtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zeDRleGhuLWphJmFtcDtsb2lkPUFRSDVQQ3dDVjR3WF9BQUFBWk5qdW4wTEhVVHROM3R5dHdEYlN2Q0U0UWR2RTNNMFhaVzV4cmpfdFFRdFRLdEZ4WHljMHNOZnVmRHVXR2dkLXl5blNudkVrcFlDbWVIUEs3RFFNanciIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0idGV4dC1pbmhlcml0IHVuZGVybGluZSIgc3R5bGU9ImN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IGNvbG9yOiBpbmhlcml0OyB0ZXh0LWRlY29yYXRpb24tbGluZTogdW5kZXJsaW5lOyI-VW5zdWJzY3JpYmU8L2E-IMKgwqDCt8KgwqAgPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2hlbHAvbGlua2VkaW4vYW5zd2VyLzY3P2xhbmc9ZW4mYW1wO2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTJtYXVjX21mdkJDWHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVscC0wLWZvb3RlcmdsaW1tZXImYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLWhlbHAtMC1mb290ZXJnbGltbWVyLW51bGwtajd6dTdpfm0zeDRleGhufmphLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0ZXhobi1qYSZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU5oWkRrME9UbG1ZV0U0WlRaaE4ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkdSa05tTmhaak0wTldaall6SmhZakV6WldJMk9URm1Nak13WVdSbU9UWmlNekl6TURabVpHVXhPVEUwTlRnMExERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJ0ZXh0LWluaGVyaXQgdW5kZXJsaW5lIiBzdHlsZT0iY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgY29sb3I6IGluaGVyaXQ7IHRleHQtZGVjb3JhdGlvbi1saW5lOiB1bmRlcmxpbmU7Ij5IZWxwPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icGItMSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogOHB4OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvP2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyQmw5ZjV6NVlST1NtclZzTSUyRkVnaGhnJTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTJtYXVjX21mdkJDWHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtZm9vdGVyLTAtbG9nb0dsaW1tZXImYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLWZvb3Rlci0wLWxvZ29HbGltbWVyLW51bGwtajd6dTdpfm0zeDRleGhufmphLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3g0ZXhobi1qYSZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqRTRZbU5oWkRrME9UbG1ZV0U0WlRaaE4ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TkdSa05tTmhaak0wTldaall6SmhZakV6WldJMk9URm1Nak13WVdSbU9UWmlNekl6TURabVpHVXhPVEUwTlRnMExERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsiPiA8aW1nIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL2Flcm8tdjEvc2MvaC85ZWhlNm4zOWZhMDdkYzVlZHp2MHJsYTRlIiBhbHQ9IkxpbmtlZEluIiBjbGFzcz0iYmxvY2sgaC1bMTRweF0gdy1bNTZweF0gaW1hZ2UtcmVuZGVyaW5nLWNyaXNwIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBpbWFnZS1yZW5kZXJpbmc6IC1tb3otY3Jpc3AtZWRnZXM7IGltYWdlLXJlbmRlcmluZzogLW8tY3Jpc3AtZWRnZXM7IGltYWdlLXJlbmRlcmluZzogLXdlYmtpdC1vcHRpbWl6ZS1jb250cmFzdDsgaW1hZ2UtcmVuZGVyaW5nOiBjcmlzcC1lZGdlczsgLW1zLWludGVycG9sYXRpb24tbW9kZTogbmVhcmVzdC1uZWlnaGJvcjsgZGlzcGxheTogYmxvY2s7IGhlaWdodDogMTRweDsgd2lkdGg6IDU2cHg7IiB3aWR0aD0iNTYiIGhlaWdodD0iMTQiPiA8L2E-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGRhdGEtdGVzdC1jb3B5cmlnaHQtdGV4dCBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gwqkgMjAyNCBMaW5rZWRJbiBDb3Jwb3JhdGlvbiwgMSZ6d25qOzAwMCBXZXN0IE1hdWRlIEF2ZW51ZSwgU3Vubnl2YWxlLCBDQSA5NDA4NS4gPHNwYW4gZGF0YS10ZXN0LXRyYWRlbWFya3MtdGV4dD4gTGlua2VkSW4gYW5kIHRoZSBMaW5rZWRJbiBsb2dvIGFyZSByZWdpc3RlcmVkIHRyYWRlbWFya3Mgb2YgTGlua2VkSW4uIDwvc3Bhbj4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPGltZyBhbHQgcm9sZT0icHJlc2VudGF0aW9uIiBzcmM9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9lbWltcC9pcF9ZV3BrTm1SVVpIQk1WekI2WlVSU2JHVkhhSFZNVjNCb09scFhNV2hoVjNobVltMDVNR0ZYV25CWk1rWXdZVmM1ZFZneVVuQmFNbFo2WkVZNGQwMVJQVDA2LmdpZiIgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgd2lkdGg6IDFweDsgaGVpZ2h0OiAxcHg7IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIj4gPC9ib2R5PiA8L2h0bWw-" - } - } - ] - }, - "sizeEstimate": 35324, - "historyId": "527418", - "internalDate": "1732544987000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_07_19362f9983e58ea6_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_07_19362f9983e58ea6_20241126.json deleted file mode 100644 index 5786592..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_07_19362f9983e58ea6_20241126.json +++ /dev/null @@ -1,210 +0,0 @@ -{ - "id": "19362f9983e58ea6", - "threadId": "19362f9983e58ea6", - "labelIds": [ - "CATEGORY_PROMOTIONS", - "UNREAD", - "INBOX" - ], - "snippet": "INDIAN FILM & TELEVISION DIRECTORS' ASSOCIATION G- 8/9/10, Crescent Towers, Near Morya House, Andheri (W), Mumbai - 400 053 Tel: 022 46088096 Mob: 9892885346/ 7021494476 www.directorsiftda.com", - "payload": { - "partId": "", - "mimeType": "multipart/related", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp832066wrq; Mon, 25 Nov 2024 02:59:05 -0800 (PST)" - }, - { - "name": "X-Forwarded-Encrypted", - "value": "i=2; AJvYcCWTJ16JRatSfV54WvhqvY7z3mW9LUmKJsBYYVJp5gas68X0OXWAugWTJyyEQE0ESerQAquXl7ZIugA=@gmail.com" - }, - { - "name": "X-Received", - "value": "by 2002:a17:906:3188:b0:a99:7bc0:bca9 with SMTP id a640c23a62f3a-aa50990b300mr1091084466b.3.1732532345051; Mon, 25 Nov 2024 02:59:05 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732532345; cv=none; d=google.com; s=arc-20240605; b=cGPTlt9iJZomIZrEX1YxFZt7CeiQG3g/9XJ/DHe6g6ghGuBopYyGtWRIq/b0u5ezsK 3JyasTQwmCnqAmvhDEgUZQM/f2Bk8PshykVmLfSUzhP0vUS2wfg90N1jmaMTefDGFvlF lSjmHBlgpl4Vhn4BKGBnLuN3ttrMXvyZ6Vi4xGil9yDgW+KjwrL3fN2jdlFsOvhxODZR EE7q5SC0waIenSAllTd+0CcG4TrH7Q0ZrQYR0yVH98JZ4UJN6v5xqhwBmTMtlPx3mWw2 d8H5HXwevTXeYzYf/F7iKAlaaWu2IPM7k/e3HAatqQk/pKHfh6cmYqN1G/MzENERvOsk HmUQ==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=52sadrERSC8TqD31OwCOGWYBr43KUD3rPyq2rw8jz2Y=; fh=3tsGDR7RWsLBUvHMNbctop2/zoZmFmKl/B1BkNJ2jsE=; b=N9JHVDUsSOQO9HPax1y++VDKEbumii3FfXCPi2ec+NDD0lV4w+48dqXsrPO9k8XO03 FgGp+qnSgZps8TogBykk8a/bFPO4VJ0AZgt5b7v4i08Y+auiO+ywcP37yeZjB52iGVSU U0TcBLTtqQSBtlirHN4lG5t4CvNTgDhKDwr9UjvOqtLgValnrsySlSpoQQ+CRhaxC3Pq bEVn4CKh8dGlJWVvOA037UDZFBQtR6ygY7IbiXBEIFZsC49aH4lZbpyzA+Xh3H3X0Xtg LrM/0hxRNj33PLOvbm5gdS7F32djBbaoIXRl057QZV0JQbPa1fvEeDOwJCv8H6rECfHK m0UQ==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@directorsiftda-com.20230601.gappssmtp.com header.s=20230601 header.b=h3FDhhUH; spf=fail (google.com: domain of contact@directorsiftda.com does not designate 209.85.220.41 as permitted sender) smtp.mailfrom=contact@directorsiftda.com; dara=pass header.i=@gmail.com" - }, - { - "name": "Return-Path", - "value": "" - }, - { - "name": "Received", - "value": "from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) by mx.google.com with SMTPS id a640c23a62f3a-aa560bdd42csor237566b.0.2024.11.25.02.59.04 for (Google Transport Security); Mon, 25 Nov 2024 02:59:04 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "fail (google.com: domain of contact@directorsiftda.com does not designate 209.85.220.41 as permitted sender) client-ip=209.85.220.41;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@directorsiftda-com.20230601.gappssmtp.com header.s=20230601 header.b=h3FDhhUH; spf=fail (google.com: domain of contact@directorsiftda.com does not designate 209.85.220.41 as permitted sender) smtp.mailfrom=contact@directorsiftda.com; dara=pass header.i=@gmail.com" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=directorsiftda-com.20230601.gappssmtp.com; s=20230601; t=1732532344; x=1733137144; dara=google.com; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=52sadrERSC8TqD31OwCOGWYBr43KUD3rPyq2rw8jz2Y=; b=h3FDhhUHelnzSe5+as+rP+HnwiQlFmbqO/XDImaXOHroIQfkSRt1MAwH2o8MiNS07l fzAKjxqRmO+p+fy9FyRuQ7d0/TDALivdP4HW1CpU7nHUqqp8BamVDC06zS1RI2PCVo7s qp4cxTIJsFTVaMauaTWQCIj9xstz9lGMa7DuhyJ8deSJU6zIAn0rFOhLISFZfZkVtZEy Q4J4MBtf2DZVvaxqUNr/DqkaownkPsTWaxfXTE8Ztq41a9kb+2IfX+6kk6M80DF4pm8I 5Wju6mVd6xpms0UXJPtRPfRBFKEjEApYq6dypd37ETr+tkUynPrv10xfuSUvrZdzU73L 1uEQ==" - }, - { - "name": "X-Google-DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732532344; x=1733137144; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=52sadrERSC8TqD31OwCOGWYBr43KUD3rPyq2rw8jz2Y=; b=tQU+3IcgiGI90Bknb75WOMN2IpL9BIunrIP5KwfkJMvrRTWq9GzjUl0t6gUocRNiPn 1fJ2VgBd/nAvzUpg/2lcypTBbfp7019CxuW5aqungvCD5iWFzMUcOoudN0O4kMx0KrMX DFThj9pD951evE/jteODFBQt0886+8Ofo8KIWaCsSiJ7uerf968pWkkJm6lkHsMCFf97 wgiA4kN8X8i9d+ZFs2yo5MxZykY1Ll2YYmMozgIS6jsXLb0pveLtA1L0SFxbqRU+/Njf n6ibGo42xOWOM92qDEbJnDXNtlnOEVOAKA3sgazkG8pDpC9yf2RqMPWex9xCNAbbVNQE KTog==" - }, - { - "name": "X-Forwarded-Encrypted", - "value": "i=1; AJvYcCWtfq6Mi9XsVN+r9oOb64yoh/F6ROqg/9C0UMWDuXU/fz1A74BwcwwZQy0hyIykg2dwtgxUFBLIz0w=@gmail.com" - }, - { - "name": "X-Gm-Message-State", - "value": "AOJu0YxUy7pf/My+et+YkWa4bqQ26C2PeklIXRKdME1VkRVdK9A8dtmN p34rPukc6VEwoEvOLsIh42JHO+nLEOYgcdIMTfklpdIp+2SaamAG+j/zSQFpfdFhWov4PO2vbqx aOztICe4xCfaWEiv4jKQ3arZkHmUWwrT6xb1sOQ==" - }, - { - "name": "X-Gm-Gg", - "value": "ASbGncsXwRmXGJJAyTvAKY+pMS2y7/Mf8mmUI9AmHaycDBvZnbQkc20j125cXkjxmOG o3M/KYTcTZDKyHLOi5xRqMfOv1Qs8lwFelQ==" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IFopa4irNtf4tkqOS0N6Tc13BHGQQ6fNDsmqoW9klWPS/JD7cYNG9eMDQkP9k7DPZCzWaTq4bPYSLxo6IJY2OU=" - }, - { - "name": "X-Received", - "value": "by 2002:a17:906:1daa:b0:aa5:3853:5532 with SMTP id a640c23a62f3a-aa53853589dmr630025266b.43.1732532343546; Mon, 25 Nov 2024 02:59:03 -0800 (PST)" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "From", - "value": "Iftda India " - }, - { - "name": "Date", - "value": "Mon, 25 Nov 2024 16:28:50 +0530" - }, - { - "name": "Message-ID", - "value": "" - }, - { - "name": "Subject", - "value": "Sad Demise of Mr. Jalaj Dhir" - }, - { - "name": "To", - "value": "undisclosed-recipients:;" - }, - { - "name": "Content-Type", - "value": "multipart/related; boundary=\"000000000000e67bea0627ba9e63\"" - }, - { - "name": "Bcc", - "value": "pskhushal@gmail.com" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"000000000000e67be90627ba9e62\"" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0.0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain; charset=\"UTF-8\"" - } - ], - "body": { - "size": 672, - "data": "W2ltYWdlOiBjb25kb2xlbmNlcyBNci4gSkFMQUogREhJUi5qcGddDQoNCg0KKklORElBTioqIEZJTE0gJiBURUxFVklTSU9OIERJUkVDVE9SUycgQVNTT0NJQVRJT04qDQpHLSA4LzkvMTAsIENyZXNjZW50IFRvd2VycywNCk5lYXIgTW9yeWEgSG91c2UsDQpBbmRoZXJpIChXKSwgTXVtYmFpIC0gNDAwIDA1Mw0KVGVsOiAwMjIgNDYwODgwOTYNCk1vYjogOTg5Mjg4NTM0Ni8gNzAyMTQ5NDQ3Ng0Kd3d3LmRpcmVjdG9yc2lmdGRhLmNvbSB8IEZhY2Vib29rL2RpcmVjdG9yc2lmdGRhDQoNCipESVNDTEFJTUVSOiogVGhpcyBlLW1haWwgbWF5IGJlIHByaXZpbGVnZWQgYW5kL29yIGNvbmZpZGVudGlhbCwgYW5kIHRoZQ0Kc2VuZGVyIGRvZXMgbm90IHdhaXZlIGFueSByZWxhdGVkIHJpZ2h0cyBhbmQgb2JsaWdhdGlvbnMuIEFueSBkaXN0cmlidXRpb24sDQp1c2Ugb3IgY29weWluZyBvZiB0aGlzIGUtbWFpbCBvciB0aGUgaW5mb3JtYXRpb24gaXQgY29udGFpbnMgYnkgb3RoZXIgdGhhbg0KYW4gaW50ZW5kZWQgcmVjaXBpZW50KHMpIGlzIHVuYXV0aG9yaXplZC4gSWYgeW91IHJlY2VpdmVkIHRoaXMgZS1tYWlsIGluDQplcnJvciwgcGxlYXNlIGFkdmlzZSB1cyAoYnkgcmV0dXJuIGUtbWFpbCBvciBvdGhlcndpc2UpIGltbWVkaWF0ZWx5IGFuZA0KZGVsZXRlIHRoaXMgZS1tYWlsLg0K" - } - }, - { - "partId": "0.1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=\"UTF-8\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 2187, - "data": "PGRpdiBkaXI9Imx0ciI-PGRpdj48ZGl2IGNsYXNzPSJnbWFpbF9kZWZhdWx0IiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7dHJlYnVjaGV0IG1zJnF1b3Q7LHNhbnMtc2VyaWY7Y29sb3I6cmdiKDY4LDY4LDY4KSI-PC9kaXY-PGltZyBzcmM9ImNpZDppaV9tM3d4MGo5YzAiIGFsdD0iY29uZG9sZW5jZXMgTXIuIEpBTEFKIERISVIuanBnIiB3aWR0aD0iNDcyIiBoZWlnaHQ9IjMzNCI-PGJyPjxiciBjbGVhcj0iYWxsIj48L2Rpdj48ZGl2PjxkaXYgZGlyPSJsdHIiIGNsYXNzPSJnbWFpbF9zaWduYXR1cmUiIGRhdGEtc21hcnRtYWlsPSJnbWFpbF9zaWduYXR1cmUiPjxkaXYgZGlyPSJsdHIiPjxkaXY-PGRpdiBkaXI9Imx0ciI-PGRpdj48ZGl2IGRpcj0ibHRyIj48ZGl2IGRpcj0ibHRyIj48ZGl2IGRpcj0ibHRyIj48ZGl2IGRpcj0ibHRyIj48ZGl2IGRpcj0ibHRyIj48ZGl2IGRpcj0ibHRyIj48ZGl2IGRpcj0ibHRyIj48ZGl2IGRpcj0ibHRyIj48ZGl2PjxzcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpyZ2IoNjgsNjgsNjgpIj48c3Bhbj48Yj48Zm9udCBzaXplPSI0Ij48YnI-PC9mb250PjwvYj48L3NwYW4-PC9zcGFuPjwvc3Bhbj48ZGl2Pjxmb250IGZhY2U9InRhaG9tYSwgc2Fucy1zZXJpZiI-PGZvbnQ-PGI-SU5ESUFOPC9iPjwvZm9udD48Yj7CoEZJTE0gJmFtcDsgVEVMRVZJU0lPTiBESVJFQ1RPUlMmIzM5OyBBU1NPQ0lBVElPTjwvYj48L2ZvbnQ-PC9kaXY-PGRpdj48Zm9udCBmYWNlPSJ0YWhvbWEsIHNhbnMtc2VyaWYiPkctIDgvOS8xMCwgQ3Jlc2NlbnQgVG93ZXJzLMKgPGJyPjwvZm9udD48L2Rpdj48ZGl2IGRpcj0ibHRyIj48ZGl2Pjxmb250IGZhY2U9InRhaG9tYSwgc2Fucy1zZXJpZiI-TmVhciBNb3J5YSBIb3VzZSw8L2ZvbnQ-PC9kaXY-PGRpdj48Zm9udCBmYWNlPSJ0YWhvbWEsIHNhbnMtc2VyaWYiPkFuZGhlcmkgKFcpLCBNdW1iYWkgLSA0MDAgMDUzPC9mb250PjwvZGl2PjxkaXY-PHNwYW4gc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj5UZWw6wqA8L3NwYW4-PHNwYW4gc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj4wMjIgNDYwODgwOTY8L3NwYW4-PGZvbnQgZmFjZT0idGFob21hLCBzYW5zLXNlcmlmIj48YnI-PC9mb250PjwvZGl2PjxkaXY-PGZvbnQgZmFjZT0idGFob21hLCBzYW5zLXNlcmlmIj5Nb2I6IDxzcGFuIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI-OTg5Mjg4NTM0Ni8gNzAyMTQ5NDQ3Njwvc3Bhbj48L2ZvbnQ-PC9kaXY-PC9kaXY-PC9kaXY-PGRpdj48ZGl2IGRpcj0ibHRyIj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjpyZ2IoNjgsNjgsNjgpIj48Zm9udCBmYWNlPSJ0YWhvbWEsIHNhbnMtc2VyaWYiPjxmb250IHNpemU9IjIiPnd3dy5kaXJlY3RvcnNpZnRkYTwvZm9udD4uY29tIHwgRmFjZWJvb2svZGlyZWN0b3JzaWZ0ZGE8L2ZvbnQ-PGJyPjxicj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEyLjhweCI-PGI-PGk-PHU-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo4cHQiIGxhbmc9IkVOLVVTIj5ESVNDTEFJTUVSOjwvc3Bhbj48L3U-PC9pPjwvYj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjhwdCI-PC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LXNpemU6OHB0O2JhY2tncm91bmQ6d2hpdGUgbm9uZSByZXBlYXQgc2Nyb2xsIDAlIDAlIj4gVGhpcw0KIGUtbWFpbCBtYXkgYmUgcHJpdmlsZWdlZCBhbmQvb3IgY29uZmlkZW50aWFsLCBhbmQgdGhlIHNlbmRlciBkb2VzIG5vdCANCndhaXZlIGFueSByZWxhdGVkIHJpZ2h0cyBhbmQgb2JsaWdhdGlvbnMuIEFueSBkaXN0cmlidXRpb24sIHVzZSBvciANCmNvcHlpbmcgb2YgdGhpcyBlLW1haWwgb3IgdGhlIGluZm9ybWF0aW9uIGl0IGNvbnRhaW5zIGJ5IG90aGVyIHRoYW4gYW4gDQppbnRlbmRlZCByZWNpcGllbnQocykgaXMgdW5hdXRob3JpemVkLiBJZiB5b3UgcmVjZWl2ZWQgdGhpcyBlLW1haWwgaW4gDQplcnJvciwgcGxlYXNlIGFkdmlzZSB1cyAoYnkgcmV0dXJuIGUtbWFpbCBvciBvdGhlcndpc2UpIGltbWVkaWF0ZWx5IGFuZCANCmRlbGV0ZSB0aGlzIGUtbWFpbC48L3NwYW4-PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo4cHQiPjwvc3Bhbj48L3NwYW4-PC9zcGFuPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2Pg0K" - } - } - ] - }, - { - "partId": "1", - "mimeType": "image/jpeg", - "filename": "condolences Mr. JALAJ DHIR.jpg", - "headers": [ - { - "name": "Content-Type", - "value": "image/jpeg; name=\"condolences Mr. JALAJ DHIR.jpg\"" - }, - { - "name": "Content-Disposition", - "value": "inline; filename=\"condolences Mr. JALAJ DHIR.jpg\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "base64" - }, - { - "name": "Content-ID", - "value": "" - }, - { - "name": "X-Attachment-Id", - "value": "ii_m3wx0j9c0" - } - ], - "body": { - "attachmentId": "ANGjdJ8zCv8y-pC8ecFP7IVoYsW4sTkayvcSepjUwiCDIrSUTJPBua7Ack8YvSuFPYcM-np_PeWRTl_wq5dYpyz3k6Hc5e-tp4RZjT6t2ITBDpkqJhPn17eR36sVN41ojkJ63Wzd9HD60LDk3o4GiL8C6iyMlsHMhadvOXKYK5zITlU9mvtdMoye6fofiiLwRsoNuT9dEpBbk9r2gh-vmuYpbu0waybh_EKefEejDvuOl7cIFU1Y3Dv8kxWYQwtZ1kx1LhHF24TzisZjvBaF6cno1T6f9aTdNd3x5T0_YsgJNilfU3xdWbCYilbVACU8axpIN5mC9CwhD45ogliA9kLadSpig8KmW9MNJJxr1vMnOAI4G-zr1SAhkzm6ZXcHllk9WpncS8RRRaLilLxo", - "size": 1736748 - } - } - ] - }, - "sizeEstimate": 2385712, - "historyId": "527104", - "internalDate": "1732532330000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_08_19360aabcb976cfc_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_08_19360aabcb976cfc_20241126.json deleted file mode 100644 index 3d27db3..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_08_19360aabcb976cfc_20241126.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "id": "19360aabcb976cfc", - "threadId": "19360aabcb976cfc", - "labelIds": [ - "CATEGORY_PROMOTIONS", - "UNREAD", - "INBOX" - ], - "snippet": "We have recommendations for you. Amazon.in Your Amazon.in Today's Deals Get Amazon App Hello Khushal PS, Amazon has new recommendations for you based on your browsing history. ApTechDeals Jumper", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp661788wrq; Sun, 24 Nov 2024 16:13:42 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IHanryCaGmStSWs4yq7Sf1frpeEiyg5Nggft2Z8FInics0aCrk0ZHEoyH5QEoE10zCg/rlE" - }, - { - "name": "X-Received", - "value": "by 2002:a05:6402:1ed1:b0:5cf:d154:8360 with SMTP id 4fb4d7f45d1cf-5d020629086mr8314902a12.14.1732493622319; Sun, 24 Nov 2024 16:13:42 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732493622; cv=none; d=google.com; s=arc-20240605; b=UIRhCb665snEBYH7WT/9jeDblWtB56t1BU6l9H+yfSaNFtRD5rWCBgwJA3px3AmImK DdiaEz0+DyVA5MZzVNNE7ElVVLv16fRL+2rkS7BsocFTdooUdo746+MlE/8Nc7LAjLVU 02xrjPGQnPg0R+gia6OTfn6EB2CaNxgzvTTNrc4MLX8B2fQGbVcgorjBZXb7SLXtcPEe YgmyvfLt5rH/zIxUUxcWVDffT4naGSgLZu4gGJEWc1Lb4bimx0JyXMZZz0JQKpoCngZ2 vz3KECtMn3zyBx7074Dfgkp+AJ1c6pdUeOaOmLyb/kRJbYlZzKmjARDOw0opKjsmmTIJ X6hw==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=feedback-id:list-unsubscribe:list-unsubscribe-post:bounces-to :mime-version:subject:message-id:to:from:date:dkim-signature :dkim-signature; bh=ldmDubq3LFGMnmC2Cu4/f11BWUDZh+9c76Uthp8D9q4=; fh=u/EceduMLbMJaVmVACWimtVNyu5iebWbNB9Q7JrDYgs=; b=BMSGvb44O+D1FMvIpIUyDdENgV2TzRErw6LmoIlmuab/SR6d+bWpDaEpskmxWYGl35 58rcSu0aeIDRmj/t859PlX7YBf5ncJt47K9VaNj8HkAYajFcp3jGUxXNuvo0pI4RmX+e DQTTKqw036f2nsuSoZT/6ZUFKODp7Ul6okiO/Ox1qVlB2IEAGcPun1lGOjIhKCRgbYao G51Tx9eZz73WUWN2px/FN3es920oHjbAkFiu869kZNb+wHROuqY6s3EepMPkX2V6cEFm EszKcCahoFYW3z3LUVEpQTIbCwtJ1nqhXQHxkdVFzs/LeAzptWwXd4eRJt3B/I+1/tcq XWow==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@amazon.in header.s=55spn7jg3iwyluzn4ej7wq3ev2vqedgu header.b=s9BTBq8d; dkim=pass header.i=@amazonses.com header.s=uku4taia5b5tsbglxyj6zym32efj7xqv header.b=\"g/7NynP4\"; spf=pass (google.com: domain of 202411250013413641827aa48d45a0a7523e458630p0eu-c1omwb0dighlu8@bounces.amazon.in designates 23.249.218.111 as permitted sender) smtp.mailfrom=202411250013413641827aa48d45a0a7523e458630p0eu-C1OMWB0DIGHLU8@bounces.amazon.in; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.in" - }, - { - "name": "Return-Path", - "value": "<202411250013413641827aa48d45a0a7523e458630p0eu-C1OMWB0DIGHLU8@bounces.amazon.in>" - }, - { - "name": "Received", - "value": "from d218-111.smtp-out.eu-west-2.amazonses.com (d218-111.smtp-out.eu-west-2.amazonses.com. [23.249.218.111]) by mx.google.com with ESMTPS id a640c23a62f3a-aa50b5aac4bsi380328066b.813.2024.11.24.16.13.42 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 24 Nov 2024 16:13:42 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of 202411250013413641827aa48d45a0a7523e458630p0eu-c1omwb0dighlu8@bounces.amazon.in designates 23.249.218.111 as permitted sender) client-ip=23.249.218.111;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@amazon.in header.s=55spn7jg3iwyluzn4ej7wq3ev2vqedgu header.b=s9BTBq8d; dkim=pass header.i=@amazonses.com header.s=uku4taia5b5tsbglxyj6zym32efj7xqv header.b=\"g/7NynP4\"; spf=pass (google.com: domain of 202411250013413641827aa48d45a0a7523e458630p0eu-c1omwb0dighlu8@bounces.amazon.in designates 23.249.218.111 as permitted sender) smtp.mailfrom=202411250013413641827aa48d45a0a7523e458630p0eu-C1OMWB0DIGHLU8@bounces.amazon.in; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=amazon.in" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=55spn7jg3iwyluzn4ej7wq3ev2vqedgu; d=amazon.in; t=1732493621; h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:List-Unsubscribe-Post:List-Unsubscribe; bh=BWlUoMNUXOKxZJNOjaXvq7Yu52kYUSPrnq16gYbWThY=; b=s9BTBq8d8PNsS3tkQOQHNpDubQYycaDvfh9Yo7nr675VilgUodcx+FoDklgEz1fy sAccjqxkAgSGtulLLF9LeALdylPONbtfh5tPNnWtq5ffx4jQ23Wx2ctCYcYu92jl31k 3u0SS6pqy97wJC6cxQj1YDDBifahkV0JUiOpxsy0=" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1732493621; h=Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:List-Unsubscribe-Post:List-Unsubscribe:Feedback-ID; bh=BWlUoMNUXOKxZJNOjaXvq7Yu52kYUSPrnq16gYbWThY=; b=g/7NynP4SzLDufmCYtRzshP8Vhzusb0okP9AzqCIOl88VBEHn51s+ixZmMD8TBbj XapRYYsU6j7DxsYv7e7hkMLFk7BooJxrcqxNsI7RSsShBr82OUptA6VmpinPN1W8Trq 0288+IonhmVzaQwXJ+0OfhxJmtJHULN66zT5zXDE=" - }, - { - "name": "Date", - "value": "Mon, 25 Nov 2024 00:13:41 +0000" - }, - { - "name": "From", - "value": "\"Amazon.in\" " - }, - { - "name": "To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Message-ID", - "value": "<0102019360aaba40-7b9b78a6-a8c2-466a-b85d-ae4a38330684-000000@eu-west-1.amazonses.com>" - }, - { - "name": "Subject", - "value": "\"ApTechDeals Jumper Wires Male to...\" and more" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"----=_Part_3547416_1504951793.1732493621814\"" - }, - { - "name": "X-AMAZON-MAIL-RELAY-TYPE", - "value": "notification" - }, - { - "name": "Bounces-to", - "value": "202411250013413641827aa48d45a0a7523e458630p0eu-C1OMWB0DIGHLU8@bounces.amazon.in" - }, - { - "name": "X-AMAZON-METADATA", - "value": "CA=C1OMWB0DIGHLU8-CU=AO8IZF00FXJKW" - }, - { - "name": "List-Unsubscribe-Post", - "value": "List-Unsubscribe=One-Click" - }, - { - "name": "List-Unsubscribe", - "value": "" - }, - { - "name": "X-Original-MessageID", - "value": "" - }, - { - "name": "Feedback-ID", - "value": "1217521881::1.eu-west-1.kjoQSiqb8G+7lWWiDVsxjM2m0ynYd4I6yEFlfoox6aY=:AmazonSES" - }, - { - "name": "X-SES-Outgoing", - "value": "2024.11.25-23.249.218.111" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain; charset=utf-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 2315, - "data": "DQoNCg0KDQo9PT09PT09PT09DQpBTUFaT04uSU4NCj09PT09PT09PT0NCg0KDQoNCkFtYXpvbiBoYXMgbmV3IHJlY29tbWVuZGF0aW9ucyBmb3IgeW91IGJhc2VkIG9uIHlvdXIgYnJvd3NpbmcgaGlzdG9yeS4NCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQpBcFRlY2hEZWFscyBKdW1wZXIgV2lyZXMgTWFsZSB0byBNYWxlLCBNYWxlIHRvIEZlbWFsZSwgRmVtYWxlIHRvIEZlbWFsZS9icmVhZGJvYXJkIGp1bXBlciB3aXJlcyAoNDArNDArNDApDQpBcFRlY2hEZWFscw0KaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3Byb2R1Y3QvQjA3NEpCNlNYOC9yZWY9cGVfNDEwNzUwMV8xMjE3NTIxODgxX2VtXzFwXzFfdGkNCk0uUi5QLjog4oK5NDk5LjAwICAgDQpQcmljZTog4oK5MTg5LjAwDQpZb3UgU2F2ZTog4oK5MzEwLjAwICg2MiUpDQouLi4NCg0KICAgIA0KDQoNClNxdWFkUGl4ZWwgRXNwLTMyIFdpZmksIEJsdWV0b290aCwgRHVhbCBDb3JlIENoaXAgRGV2ZWxvcG1lbnQgQm9hcmQgKEVTUC1XUk9PTS0zMikNCmRpeW1vcmUNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwNzFYUDU2TE0vcmVmPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9lbV8xcF8yX3RpDQpNLlIuUC46IOKCuTk5OS4wMCAgIA0KUHJpY2U6IOKCuTU1Ny4wMA0KWW91IFNhdmU6IOKCuTQ0Mi4wMCAoNDQlKQ0KLi4uDQoNCiAgICANCg0KDQp4Y2x1bWEgREFDIE1vZHVsZSAxMzM0IFVEQTEzMzRBIEkyUyBEQUMgU3RlcmVvIERlY29kZXIgTW9kdWxlIEZvciB1bm8gMy4zViAtIDVWDQp4Y2x1bWENCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9wcm9kdWN0L0IwQkI3UEc1NFQvcmVmPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9lbV8xcF8zX3RpDQpNLlIuUC46IOKCuTcwOS4wMCAgIA0KRGVhbCBQcmljZTog4oK5NTE2LjAwDQpZb3UgU2F2ZTog4oK5MTkzLjAwICgyNyUpDQouLi4NCg0KICAgIA0KDQoNCg0KDQoNCg0KU2VlIHNpbWlsYXIgcHJvZHVjdHMNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC95b3Vyc3RvcmUvcmVmPWVtX2ZsDQoNCj09PT09PT09PT0NCkFtYXpvbi5pbg0KaHR0cDovL3d3dy5hbWF6b24uaW4vcmVmPXBlX2Zvb3Rlci8NCg0KQ29ubmVjdCB3aXRoIFVzDQpPbiBGYWNlYm9vaw0KaHR0cDovL3d3dy5hbWF6b24uaW4vZ3AvcmVkaXJlY3QuaHRtbC9yZWY9cGVfNDIzMzcxXzM4NDc4OTMxX3BlXzBfMzQzNl9wZV9mYl9mdHIvP2xvY2F0aW9uPWh0dHA6Ly93d3cuZmFjZWJvb2suY29tL0FtYXpvbklOJnRva2VuPTIwNzVENUVBQzdCQjIxNDA4OTcyOEUyMTgzRkQzOTE3MDZENDFFOTQNCg0KT24gVHdpdHRlcg0KaHR0cDovL3d3dy5hbWF6b24uaW4vZ3AvcmVkaXJlY3QuaHRtbC9yZWY9cGVfNDIzMzcxXzM4NDc4OTMxX3BlXzBfMzQzNl9wZV90d19mdHIvP2xvY2F0aW9uPWh0dHA6Ly90d2l0dGVyLmNvbS9BbWF6b25JTiZ0b2tlbj1BMzA5REZCRkNCMUUzN0E4MDhGRjUzMTkzNDg1NURDODE3RjEzMEI2DQoNCj09PT09PT09PT0NCg0KV2UgaG9wZSB5b3UgZm91bmQgdGhpcyBtZXNzYWdlIHRvIGJlIHVzZWZ1bC4gSG93ZXZlciwgaWYgeW91J2QgcmF0aGVyIG5vdCByZWNlaXZlIGZ1dHVyZSBlLW1haWxzIG9mIHRoaXMgc29ydCBmcm9tIEFtYXpvbi5pbiwgcGxlYXNlIHZpc2l0IHRoZSBvcHQtb3V0IGxpbmsgaGVyZToNCmh0dHBzOi8vd3d3LmFtYXpvbi5pbi8vZ3AvZ3NzL28vMS1QaXZqVnF4STU2aFBTNGJFUElhaWZyekswcXFVaHk0UlZlSklQRmFGU21kTmpaemplNVc0dlRob3AwY21RM0EuDQoNClBsZWFzZSBub3RlIHRoYXQgcHJvZHVjdCBwcmljZXMgYW5kIGF2YWlsYWJpbGl0eSBhcmUgc3ViamVjdCB0byBjaGFuZ2UuIFByaWNlcyBhbmQgYXZhaWxhYmlsaXR5IHdlcmUgYWNjdXJhdGUgYXQgdGhlIHRpbWUgdGhpcyBuZXdzbGV0dGVyIHdhcyBzZW50OyBob3dldmVyLCB0aGV5IG1heSBkaWZmZXIgZnJvbSB0aG9zZSB5b3Ugc2VlIHdoZW4geW91IHZpc2l0IEFtYXpvbi5pbi4gDQoNCg0KDQpBbWF6b24uaW4gTWFya2V0cGxhY2UgcGxhdGZvcm06IFByb2R1Y3RzIHNvbGQgYnkgYSBNYXJrZXRwbGFjZSBzZWxsZXIgYXJlIHN1YmplY3QgdG8gdGhhdCBzZWxsZXIncyB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiBzYWxlLiBTZWUgd3d3LkFtYXpvbi5pbiBmb3IgZGV0YWlscy4NCg0KUmVmZXJlbmNlOiAxMjE3NTIxODgxDQoNClRoaXMgbWVzc2FnZSB3YXMgc2VudCB0byB0aGUgZm9sbG93aW5nIGUtbWFpbCBhZGRyZXNzOiBwc2todXNoYWxAZ21haWwuY29tDQo=" - } - }, - { - "partId": "1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=utf-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 81426, - "data": "DQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoJDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo8IURPQ1RZUEUgaHRtbCBQVUJMSUMgIi0vL1czQy8vRFREIFhIVE1MIDEuMCBTdHJpY3QvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIveGh0bWwxL0RURC94aHRtbDEtc3RyaWN0LmR0ZCI-DQo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9IndpZHRoOiAxMDAlIj4NCiA8aGVhZD4NCiAgPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgiPg0KICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0idGFyZ2V0LWRlbnNpdHlkcGk9ZGV2aWNlLWRwaSI-DQogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGUgPSAxLjAsIG1heGltdW0tc2NhbGUgPSAxLjAiPg0KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KICAgICAgICAgICAgYm9keSB7DQogICAgcGFkZGluZzowOw0KICAgIG1hcmdpbjowOw0KICAgIC1tcy10ZXh0LXNpemUtYWRqdXN0OjEwMCU7DQogICAgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OjEwMCU7DQp9DQppbWcgew0KICAgIGhlaWdodDogYXV0bzsNCiAgICBvdXRsaW5lOm5vbmU7DQogICAgYm9yZGVyOjAgbm9uZTsNCiAgICAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOmJpY3ViaWM7DQp9DQoNCnRhYmxlIHsNCiAgICBtc28tdGFibGUtbHNwYWNlOjBwdDsNCiAgICBtc28tdGFibGUtcnNwYWNlOjBwdDsNCiAgICBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlOw0KfQ0KDQouRXh0ZXJuYWxDbGFzc3sNCiAgICB3aWR0aDoxMDAlOw0KfQ0KDQouRXh0ZXJuYWxDbGFzcywNCi5FeHRlcm5hbENsYXNzIHAsDQouRXh0ZXJuYWxDbGFzcyBzcGFuLA0KLkV4dGVybmFsQ2xhc3MgdGQsDQouRXh0ZXJuYWxDbGFzcyBkaXYgew0KICAgIGxpbmUtaGVpZ2h0OiAxMDAlOw0KfQ0KDQojb3V0bG9vayBhIHsNCiAgcGFkZGluZzogMDsgDQp9DQoNCi53aWRnZXRIZWFkZXINCnsNCnRleHQtZGVjb3JhdGlvbjpub25lOw0KY29sb3I6I0U0NzkxMTsNCmZvbnQtc2l6ZToxNXB4Ow0KZm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7DQpmb250LXdlaWdodDpib2xkOw0KfQ0KLmJ0bi1sZWFybm1vcmUtc21hbGwNCnsgDQpiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQodG8gYm90dG9tLCNmN2RmYTUsI2YwYzE0Yik7DQpib3JkZXItcmFkaXVzOiA1cHg7IA0KZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyANCmZvbnQtc2l6ZTogMTJweDsNCmZvbnQtd2VpZ2h0OiBub3JtYWw7DQpib3JkZXItY29sb3I6ICNhODg3MzQgIzljN2UzMSAjODQ2YTI5ICFpbXBvcnRhbnQ7DQpib3JkZXItc3R5bGU6c29saWQgIWltcG9ydGFudDsNCmJvcmRlci13aWR0aDoxcHggIWltcG9ydGFudDsNCmJvcmRlci1jb2xsYXBzZTppbml0aWFsICFpbXBvcnRhbnQ7DQp9DQouYnRuLWFkZHRvbGlzdC1zbWFsbA0Kew0KYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KHRvIGJvdHRvbSwjZjdmOGZhLCNlN2U5ZWMpOw0KYm9yZGVyLXJhZGl1czogNXB4Ow0KZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyANCmZvbnQtc2l6ZTogMTJweDsNCmZvbnQtd2VpZ2h0OiBub3JtYWw7DQpib3JkZXItY29sb3I6ICNhZGIxYjggI2EyYTZhYyAjOGQ5MDk2ICFpbXBvcnRhbnQ7DQpib3JkZXItc3R5bGU6c29saWQgIWltcG9ydGFudDsNCmJvcmRlci13aWR0aDoxcHggIWltcG9ydGFudDsNCm1pbi13aWR0aDogMTAwcHg7DQpib3JkZXItY29sbGFwc2U6aW5pdGlhbCAhaW1wb3J0YW50Ow0KfSANCnNwYW4ubWFpbm1lc3NhZ2Ugew0KICAgIGZvbnQtc2l6ZTogMzRweDsNCiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOw0KICAgIGxpbmUtaGVpZ2h0OiAxOw0KICAgIGNvbG9yOiAjRkY5OTAwOw0KICAgIGZvbnQtd2VpZ2h0OiA1MDA7DQogICAgbWFyZ2luLWJvdHRvbTogNXB4Ow0KfQ0KLm9tYV9wcl9pbWFnZSB7DQogICAgZGlzcGxheTpibG9jazsNCiAgDQp9DQouZW1haWxfc3VwZXJfc3ViamVjdCBhIHsNCiAgICBjb2xvcjogIzMzNjY5OSAhaW1wb3J0YW50Ow0KfQ0KLmN0YS1idG4gew0KICAgIGJhY2tncm91bmQtY29sb3I6ICNGRkM0MzU7DQogICAgYm9yZGVyLXJhZGl1czogNXB4Ow0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICBmb250LXNpemU6IDE0cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQouYnRuLWxlYXJubW9yZS1iaWcgew0KICAgIGJhY2tncm91bmQtY29sb3I6ICNGRkM0MzU7DQogICAgYm9yZGVyLXJhZGl1czogNXB4Ow0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICBmb250LXNpemU6IDE0cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQouYnRuLWFkZHRvbGlzdC1iaWcgew0KICAgIGJhY2tncm91bmQtY29sb3I6ICNFN0U3QzI7DQogICAgYm9yZGVyLXJhZGl1czogNXB4Ow0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICBmb250LXNpemU6IDEycHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQouZW1haWwtc3VwZXItc3ViamVjdCB7DQogICAgZm9udC1mYW1pbHk6IHZlcmRhbmEsIGFyaWFsLCBzYW5zLXNlcmlmOw0KICAgIGZvbnQtc2l6ZTogOXB4Ow0KICAgIGxpbmUtaGVpZ2h0OiAxMXB4Ow0KICAgIGNvbG9yOiAjNTU1Ow0KfQ0KLmhlYWRlci1tZW51IHsNCiAgICBmb250LWZhbWlseTogYXJpYWwsIHZlcmRhbmEsIHNhbnMtc2VyaWY7DQogICAgZm9udC1zaXplOiAxMnB4Ow0KICAgIGNvbG9yOiByZ2IoNTEsIDEwMiwgMTUzKTsNCiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQouaW50cm8tdGV4dCB7DQogICAgZm9udC1zaXplOiAxMnB4Ow0KICAgIGNvbG9yOiAjMzMzMzMzOw0KICAgIGZvbnQtd2VpZ2h0OiBub3JtYWw7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgbGluZS1oZWlnaHQ6IDE2cHg7DQogICAgdmVydGljYWwtYWxpZ246IHRvcDsNCiAgICBwYWRkaW5nOiA2cHggMTVweCAxMnB4IDE1cHg7DQp9DQouZmFybWhlYWQgew0KICAgIGZvbnQtZmFtaWx5OiBhcmlhbDsNCiAgICBmb250LXNpemU6IDE0cHg7DQogICAgY29sb3I6ICNlNDc5MTE7DQogICAgbGluZS1oZWlnaHQ6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQouZmFybWhlYWQtZm9udCB7DQogICAgZm9udC1mYW1pbHk6IGFyaWFsOw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgICBjb2xvcjogI2U0NzkxMTsNCiAgICBsaW5lLWhlaWdodDogMTZweDsNCn0NCi5saW5rZmFybS1jb2wtczEgew0KICAgIGZvbnQtZmFtaWx5OiBhcmlhbCwgaGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCn0NCi5saW5rZmFybS1jb2wtczIgew0KICAgIGZvbnQtZmFtaWx5OiBhcmlhbCwgaGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCn0NCi5saW5rZmFybS1saW5rLXMxIHsNCiAgICBjb2xvcjogIzY2NjsNCiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7DQp9DQoubGVnYWwtdGV4dCB7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIFNhbnMtU2VyaWY7DQogICAgZm9udC1zaXplOiAxMHB4Ow0KICAgIGNvbG9yOiAjNjY2DQp9DQoubGVnYWwtdGV4dC1jMSB7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIFNhbnMtU2VyaWY7DQogICAgZm9udC1zaXplOiAxMHB4Ow0KICAgIGNvbG9yOiAjOTk5Ow0KfQ0KLmxlZ2FsLXRleHQtYzIgew0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBTYW5zLVNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTBweDsNCiAgICBjb2xvcjogI2JmYmZiZjsNCn0NCi5sZWdhbC10ZXh0LWMzIHsNCiAgICBmb250LWZhbWlseTogVmVyZGFuYSwgQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgICBmb250LXNpemU6IDdwdDsNCiAgICBjb2xvcjogIzNFN0NCQjsNCn0NCi5zYWx1dGF0aW9uLXRleHQgew0KICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZTsNCiAgICBjb2xvcjogIzMwMzk0MjsNCiAgICBmb250LXNpemU6IDE0cHg7DQogICAgY29sb3I6ICMzMDM5NDI7DQogICAgZm9udC13ZWlnaHQ6IG5vcm1hbDsNCn0NCmJvZHkgew0KICAgIGJhY2tncm91bmQtY29sb3I6ICNlM2UzZTM7DQp9DQpib2R5W3lhaG9vXSB7DQogICAgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiBub25lOw0KICAgIHdpZHRoOiAxMDAlOw0KICAgIGJhY2tncm91bmQtY29sb3I6ICNlM2UzZTM7DQogICAgbWFyZ2luOiAwOw0KICAgIHBhZGRpbmc6IDA7DQogICAgLXdlYmtpdC1mb250LXNtb290aGluZzogYW50aWFsaWFzZWQ7DQp9DQouUmVhZE1zZ0JvZHkgew0KICAgIHdpZHRoOiAxMDAlOw0KICAgIGJhY2tncm91bmQtY29sb3I6ICNlM2UzZTM7DQp9DQouRXh0ZXJuYWxDbGFzcyB7DQogICAgd2lkdGg6IDEwMCU7DQogICAgYmFja2dyb3VuZC1jb2xvcjogI2UzZTNlMzsNCn0NCmh0bWwgew0KICAgIHdpZHRoOiAxMDAlOw0KfQ0KYm9keVt5YWhvb10gdGFibGUgew0KICAgIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7DQp9DQpib2R5W3lhaG9vXSAuYnRuIHsNCiAgICB3aWR0aDogMTAwJTsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXIhaW1wb3J0YW50Ow0KfQ0KYm9keVt5YWhvb10gLmZhcm0tcm93IHsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgZm9udC1zaXplOiAxMnB4Ow0KICAgIHBhZGRpbmc6IDNweDsNCiAgICBjb2xvcjogIzMzMzMzMw0KfQ0KYm9keVt5YWhvb10gLnRvcDEwLWltZy1XaWR0aCB7DQogICAgd2lkdGg6IDI5MHB4IWltcG9ydGFudDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXINCn0NCnNwYW4ubWFpbm1lc3NhZ2Ugew0KICAgIGZvbnQtc2l6ZTogMzRweDsNCiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOw0KICAgIGxpbmUtaGVpZ2h0OiAxOw0KICAgIGNvbG9yOiAjRkY5OTAwOw0KICAgIGZvbnQtd2VpZ2h0OiA1MDANCn0NCmJvZHlbeWFob29dIC5pbWFnZS1jc3Nsb3Qtbm9ybWFsIGltZyB7DQogICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICBoZWlnaHQ6IGF1dG8gIWltcG9ydGFudDsNCn0NCmJvZHlbeWFob29dIHRkW2NsYXNzPSJsY29sIl0gaW1nIHsNCiAgICB3aWR0aDogMTc1cHggIWltcG9ydGFudDsNCiAgICBoZWlnaHQ6IDE3NXB4ICFpbXBvcnRhbnQ7DQp9DQouc2VmX2xlZ2FsX2Zvb3RlciB7DQogICAgYmFja2dyb3VuZC1jb2xvcjogI0UzRTNFMzsNCn0NCi5zZWZfZm9vdGVyX2Nvbm5lY3Qgew0KICAgIGJvcmRlci1ib3R0b206IDNweCBzb2xpZCAjODg4ODg4Ow0KICAgIGhlaWdodDogMHB4ICFpbXBvcnRhbnQ7DQogICAgbWF4LWhlaWdodDogMHB4ICFpbXBvcnRhbnQ7DQogICAgZm9udC1zaXplOiAwcHg7DQogICAgbWFyZ2luOiAwOw0KICAgIHdpZHRoOiAxMDAlOw0KfQ0KYm9keVt5YWhvb10gLnNlZl9zcGFjZXIgZGl2IHsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoImh0dHBzOi8vaW1hZ2VzLW5hLnNzbC1pbWFnZXMtYW1hem9uLmNvbS9pbWFnZXMvRy8wMS90ZW1wbGF0ZS9zZWN0aW9uLWRpdl82NDB4OC5qcGciKSAhaW1wb3J0YW50Ow0KICAgIGJhY2tncm91bmQtY29sb3I6ICNGRkZGRkY7DQogICAgaGVpZ2h0OiAxMHB4ICFpbXBvcnRhbnQ7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsNCn0NCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogNjgwcHgpIHsNCiAgICAubW9iaWxlLWhpZGUtZ21haWwgew0KICAgICAgICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7DQogICAgICAgIG92ZXJmbG93OmhpZGRlbiAhaW1wb3J0YW50Ow0KICAgICAgICBtc28taGlkZTphbGwgIWltcG9ydGFudDsNCiAgICAgICAgbGluZS1oZWlnaHQ6IDBweCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICAubW9iaWxlLWhpZGUtZ21haWwgdGFibGV7DQogICAgICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDsNCiAgICAgICAgb3ZlcmZsb3c6aGlkZGVuICFpbXBvcnRhbnQ7DQogICAgICAgIG1zby1oaWRlOmFsbCAhaW1wb3J0YW50Ow0KICAgICAgICBsaW5lLWhlaWdodDogMHB4ICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIA0KICAgIGJvZHlbeWFob29dIC5kZXZpY2VXaWR0aCB7DQogICAgICAgIHdpZHRoOiAxMDAlIWltcG9ydGFudA0KICAgIH0NCiAgICBib2R5W3lhaG9vXSB0ZFtjbGFzcz0iY29sIl0gYSBpbWcgew0KICAgICAgICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KICAgICAgICBtYXgtd2lkdGg6IDYwcHggIWltcG9ydGFudDsNCiAgICAgICAgaGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7DQogICAgICAgIG1pbi13aWR0aDogNDFweCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICB0ZFtjbGFzcz0iY29sIl0gew0KICAgICAgICB3aWR0aDogMzAlICFpbXBvcnRhbnQ7DQogICAgICAgIG1heC13aWR0aDogNjBweCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuZmFybUxpbmtzIHsNCiAgICAgICAgd2lkdGg6IGF1dG8gIWltcG9ydGFudDsNCiAgICAgICAgdGV4dC1hbGlnbjogbGVmdCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuZmFybUxpbmtzIHRkIHsNCiAgICAgICAgdGV4dC1hbGlnbjogbGVmdCAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSB0ZFtjbGFzcz0iZmFybUNvbnRhaW5lciJdIHsNCiAgICAgICAgd2lkdGg6IDUwJSAhaW1wb3J0YW50Ow0KICAgICAgICB0ZXh0LWFsaWduOiBsZWZ0ICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5zZWZfZm9vdGVyX2xpbmtmYXJtIHRkIHsNCiAgICAgICAgd2lkdGg6IGF1dG8gIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9mb290ZXJfbGlua2Zhcm0gdGFibGUgew0KICAgICAgICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2xlZ2FsX2Zvb3RlciwNCiAgICBib2R5W3lhaG9vXSAuc2VmX3NwYWNlciwNCiAgICBib2R5W3lhaG9vXSAuc2VmX2Zvb3Rlcl9jb25uZWN0LA0KICAgIGJvZHlbeWFob29dIC5zZWZfbGVnYWxfZm9vdGVyLA0KICAgIGJvZHlbeWFob29dIC5zZWZfZm9vdGVyX2xpbmtmYXJtIHsNCiAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9mb290ZXJfbGlua2Zhcm0gdHI6bGFzdC1jaGlsZCB0ZCwNCiAgICBib2R5W3lhaG9vXSAuc2VmX2Zvb3Rlcl9saW5rZmFybSB0cjpmaXJzdC1jaGlsZCB0ZCB7DQogICAgICAgIHdpZHRoOiAxMDAlOw0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2Zvb3Rlcl9saW5rZmFybSB0ciB0ZCB0YWJsZSB7DQogICAgICAgIHdpZHRoOiAxMDAlOw0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuYnRuIHsNCiAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gdGRbY2xhc3M9Ingtc2l0ZS10YWJsZXQiXSB7DQogICAgICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlcGVyYXRvciB7DQogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5zZXBlcmF0b3IgaW1nIHsNCiAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICAgICAgaGVpZ2h0OiBhdXRvOw0KICAgIH0NCn0NCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogNTk5cHgpIHsNCiAgICBib2R5W3lhaG9vXSAudG9wMTAtaW1nLVdpZHRoIHsNCiAgICAgICAgd2lkdGg6IDQ0MHB4IWltcG9ydGFudDsNCiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyDQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5jZW50ZXIgew0KICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXIhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuZm9vdGVyTGlua3Mgew0KICAgICAgICB3aWR0aDogMzIlOw0KICAgICAgICBtYXJnaW4tYm90dG9tOiA0MHB4DQogICAgfQ0KICAgIGJvZHlbeWFob29dIHRkW2NsYXNzPSJsY29sIl0sDQogICAgYm9keVt5YWhvb10gdGRbY2xhc3M9InJjb2wiXSB7DQogICAgICAgIGRpc3BsYXk6IGlubGluZS1ibG9jayAhaW1wb3J0YW50Ow0KICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7DQogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgICAgIGZsb2F0OiBub25lICFpbXBvcnRhbnQ7DQogICAgICAgIG92ZXJmbG93OiB2aXNpYmxlICFpbXBvcnRhbnQ7DQogICAgICAgIG1heC1oZWlnaHQ6IG5vbmUgIWltcG9ydGFudDsNCiAgICAgICAgcGFkZGluZzogMHB4ICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5mYXJtTGlua3Mgew0KICAgICAgICBtaW4td2lkdGg6IDE0OHB4ICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5mYXJtQm90dG9tIHsNCiAgICAgICAgd2lkdGg6IDEwMCUhaW1wb3J0YW50DQogICAgfQ0KICAgIGJvZHlbeWFob29dIHRkW2NsYXNzPSJwZV9hc2luIl0gew0KICAgICAgICBwYWRkaW5nOiA0cHggMTVweCA0cHggMTVweCAhaW1wb3J0YW50Ow0KICAgIH0NCn0NCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogNTE1cHgpIHsNCiAgICBib2R5W3lhaG9vXSAubG9nb1RvcCB7DQogICAgICAgIHdpZHRoOiAxMDAlIWltcG9ydGFudA0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAudG9wMTAtaW1nLVdpZHRoIHsNCiAgICAgICAgd2lkdGg6IDI5MHB4IWltcG9ydGFudDsNCiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyDQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5jZW50ZXIgew0KICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXIhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuZm9vdGVyTGlua3Mgew0KICAgICAgICB3aWR0aDogMzIlOw0KICAgICAgICBtYXJnaW4tYm90dG9tOiA0MHB4DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5idG4gew0KICAgICAgICB3aWR0aDogMTAwJTsNCiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gdGRbY2xhc3M9Ingtc2l0ZSJdLA0KICAgIGJvZHlbeWFob29dIC54LXNpdGUgew0KICAgICAgICBkaXNwbGF5OiBub25lOw0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2Zvb3Rlcl9saW5rZmFybSB7DQogICAgICAgIGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnNlZl9zcGFjZXIgew0KICAgICAgICBkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5zZWZfZm9vdGVyX2Nvbm5lY3Qgew0KICAgICAgICB3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAuc2VmX2xlZ2FsX2Zvb3RlciB7DQogICAgICAgIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7DQogICAgfQ0KICAgIGJvZHlbeWFob29dIC5sb2dvVG9wIC5jZW50ZXIgYSB7DQogICAgICAgIHRleHQtZGVjb3JhdGlvbjogbm9uZSAhaW1wb3J0YW50Ow0KICAgIH0NCiAgICBib2R5W3lhaG9vXSAubG9nb1RvcCB0ZCB7DQogICAgICAgIHBhZGRpbmc6IHJpZ2h0OiAwcHggIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmFtYXpvbkxvZ28gew0KICAgICAgICBwYWRkaW5nOiAwIDEwcHggIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLnRvcE1lbnUgew0KICAgICAgICBwYWRkaW5nOiAwIDAgNXB4IDAgIWltcG9ydGFudDsNCiAgICB9DQogICAgYm9keVt5YWhvb10gLmNzLWltYWdlLXNsb3Qgew0KICAgICAgICBtYXJnaW46IGF1dG87DQogICAgfQ0KfQ0KQG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWF4LXdpZHRoOiA1OTlweCkgew0KICAgIGJvZHlbeWFob29dIHRkW2NsYXNzPSJwYWNrQ29sIl0gew0KICAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2sgIWltcG9ydGFudDsNCiAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCiAgICAgICAgZmxvYXQ6IG5vbmUgIWltcG9ydGFudDsNCiAgICAgICAgb3ZlcmZsb3c6IHZpc2libGUgIWltcG9ydGFudDsNCiAgICAgICAgbWF4LWhlaWdodDogbm9uZSAhaW1wb3J0YW50Ow0KICAgICAgICBwYWRkaW5nOiAwcHggIWltcG9ydGFudDsNCiAgICB9DQp9DQogICAgICAgIDwvc3R5bGU-DQogPC9oZWFkPg0KIDxib2R5IHlhaG9vPSJmaXgiIGNsYXNzPSJvbWFfbWFpbl9ib2R5IiBzdHlsZT0icGFkZGluZzogMDsgbWFyZ2luOiAwOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlO2JhY2tncm91bmQtY29sb3I6IHJnYigyMjcsIDIyNywgMjI3KTstd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IG5vbmU7IHdpZHRoOiAxMDAlOyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjI3LCAyMjcsIDIyNyk7IG1hcmdpbjogMDsgcGFkZGluZzogMDsgLXdlYmtpdC1mb250LXNtb290aGluZzogYW50aWFsaWFzZWQiPjxpbWcgd2lkdGg9IjEiIGhlaWdodD0iMSIgc3JjPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MUtVQlQ0V1ZXME9CUCZUPU8mVT1odHRwcyUzQSUyRiUyRmltYWdlcy1ldS5zc2wtaW1hZ2VzLWFtYXpvbi5jb20lMkZpbWFnZXMlMkZHJTJGMDElMkZuYXYlMkZ0cmFuc3AuZ2lmJkg9SUxSMUNPWVJWS05JNExZRFA3TkFUWFJTVEJZQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9vcGVucyIgLz4NCiAgPHRhYmxlIHdpZHRoPSIxMDAlIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIxMCIgY2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiAjZTNlM2UzO21zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiIHlhaG9vPSJmaXgiPg0KICAgPHRib2R5Pg0KICAgIDx0cj4NCiAgICAgPHRkIHZhbGlnbj0ibWlkZGxlIj4NCiAgICAgIDx0YWJsZSB3aWR0aD0iNjQwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9ImRldmljZVdpZHRoIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgPHRib2R5Pg0KICAgICAgICA8dHI-DQogICAgICAgICA8dGQgc3R5bGU9InBhZGRpbmc6MCAwIDEwcHggMDsgZm9udC1zaXplOjA7IGhlaWdodDowOyIgY2xhc3M9Ingtc2l0ZSIgdmFsaWduPSJib3R0b20iPg0KICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgPHRkPjxzcGFuIGNsYXNzPSJlbWFpbF9zdXBlcl9zdWJqZWN0IiBzdHlsZT0iZm9udC1mYW1pbHk6dmVyZGFuYSxhcmlhbCxzYW5zLXNlcmlmO2ZvbnQtc2l6ZTo5cHg7bGluZS1oZWlnaHQ6MTFweDtjb2xvcjojNTU1OyI-IFdlIGhhdmUgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL2YuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFPSVRLSkxTUzI1QlQmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZ5b3Vyc3RvcmUlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcmVjX3NzJkg9UlU2SVNBQ0tPV1FHV1BBQVBBTE5IVFBEM09VQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9yZWNfc3MiIHN0eWxlPSJjb2xvcjogcmdiKDUxLCAxMDIsIDE1MykgIWltcG9ydGFudCI-cmVjb21tZW5kYXRpb25zPC9hPiBmb3IgeW91LiA8L3NwYW4-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgPHRkIGFsaWduPSJyaWdodCIgY2xhc3M9ImhlYWRlci1jc3Nsb3QiPjwvdGQ-DQogICAgICAgIDwvdHI-DQogICAgICAgPC90Ym9keT4NCiAgICAgIDwvdGFibGU-DQogICAgICA8dGFibGUgd2lkdGg9IjY0MCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGNsYXNzPSJkZXZpY2VXaWR0aCIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgIDx0Ym9keT4NCiAgICAgICAgPHRyPg0KICAgICAgICAgPHRkIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJoZWFkZXItY3NzbG90Ij48L3RkPg0KICAgICAgICA8L3RyPg0KICAgICAgIDwvdGJvZHk-DQogICAgICA8L3RhYmxlPg0KICAgICAgPHRhYmxlIHdpZHRoPSI2NDAiIGhlaWdodD0iNiIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGNsYXNzPSJkZXZpY2VXaWR0aCIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgIDx0Ym9keT4NCiAgICAgICAgPHRyPg0KICAgICAgICAgPHRkIHdpZHRoPSIxMDAlIiBiZ2NvbG9yPSIjZTNlM2UzIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0iYm9yZGVyLWJvdHRvbTogNnB4IHNvbGlkICNGRjk5MDA7IGhlaWdodDogMHB4ICFpbXBvcnRhbnQ7IG1heC1oZWlnaHQ6IDBweCAhaW1wb3J0YW50OyBmb250LXNpemU6MHB4OyBtYXJnaW46IDA7Ij48cD4mbmJzcDs8L3A-PC90ZD4NCiAgICAgICAgPC90cj4NCiAgICAgICA8L3Rib2R5Pg0KICAgICAgPC90YWJsZT4NCiAgICAgIDx0YWJsZSB3aWR0aD0iNjQwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGJnY29sb3I9IiNmZmZmZmYiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I2ZmZmZmZjttc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIiBjbGFzcz0iZGV2aWNlV2lkdGgiPg0KICAgICAgIDx0Ym9keT4NCiAgICAgICAgPHRyPg0KICAgICAgICAgPHRkPg0KICAgICAgICAgIDx0YWJsZSB3aWR0aD0iMTAwJSIgaGVpZ2h0PSI1cHgiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0iZGV2aWNlV2lkdGgiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgIDx0ZD48L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwMCUiIHZhbGlnbj0ibWlkZGxlIj48IS0tIEJlZ2luIFNpbXBsZSBUZW1wbGF0ZSAtLT4gPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCiAgICBib2R5W3lhaG9vXSAuc2VwZXJhdG9yIHt3aWR0aDogMTAwJSAhaW1wb3J0YW50O30NCiAgICBib2R5W3lhaG9vXSAuc2VwZXJhdG9yIGltZyB7d2lkdGg6IDEwMCUgIWltcG9ydGFudDsgaGVpZ2h0OiBhdXRvO30NCjwvc3R5bGU-DQogICAgICAgICAgICAgIDx0YWJsZSBiZ2NvbG9yPSIjRkZGRkZGIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9ImxvZ29Ub3AiIGFsaWduPSJsZWZ0IiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICA8dGQgY2xhc3M9ImNlbnRlciI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPVo4MEE5Nzc4VVhDNSZUPUMmVT1odHRwJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9zZWZfbG9nbyZIPUtXVzJTTDVQQlhBRFBWUFhNNEVBT1JSU1VUT0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfc2VmX2xvZ28iPiA8aW1nIHNyYz0iaHR0cHM6Ly9pbWFnZXMtZXUuc3NsLWltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzMxL2VtYWlsL2luL2xvZ28vYW1hem9uX3ByaW1lX2xvZ29faW5fMTUweDQ4LmpwZyIgYWx0PSJBbWF6b24uaW4iIGJvcmRlcj0iMCIgaHNwYWNlPSI2IiB2c3BhY2U9IjYiIHN0eWxlPSJoZWlnaHQ6IGF1dG87IG91dGxpbmU6IG5vbmU7IGJvcmRlcjogMCBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljIj4gPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgIDx0YWJsZSBjbGFzcz0ibG9nb1RvcCAiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjEwIiBjZWxsc3BhY2luZz0iMCIgYWxpZ249InJpZ2h0IiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICA8dGQgYWxpZ249InJpZ2h0IiBjbGFzcz0idG9wTWVudSI-DQogICAgICAgICAgICAgICAgICA8dGFibGUgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBzdHlsZT0ibWFyZ2luOjAgYXV0bzttc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0iY2VudGVyIj48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9VjA1VUYwS1M4U0dJJlQ9QyZVPWh0dHAlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZ5b3Vyc3RvcmUlMkZob21lJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX3lvdXJzdG9yZSUyRiZIPVRYMVVMTVZST1JISENCWFEzSFkyV1BPRkQwVUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfeW91cnN0b3JlIiBzdHlsZT0iZm9udC1mYW1pbHk6IGFyaWFsLHZlcmRhbmEsc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyBjb2xvcjogcmdiKDUxLCAxMDIsIDE1Myk7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgZm9udC13ZWlnaHQ6IGJvbGQ7dGV4dC1hbGlnbjpjZW50ZXI7IHdvcmQtd3JhcDogbm9ybWFsICEgaW1wb3J0YW50OyI-IFlvdXIgQW1hem9uLmluIDwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIHJvd3NwYW49IjIiIHdpZHRoPSI4Ij4mbmJzcDs8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNjY2MiIHdpZHRoPSIyIiBoZWlnaHQ9IjE1Ij48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIHJvd3NwYW49IjIiIHdpZHRoPSIxMiI-Jm5ic3A7PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0iY2VudGVyIj48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MTVXNlU0NjJaN0MwTSZUPUMmVT1odHRwJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcmVkaXJlY3QuaHRtbCUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9kZWFscyUzRmxvY2F0aW9uJTNEaHR0cCUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmdvbGRib3gmSD1EME1RMEE1VDFJRU9BWU9YTERMOFIxVkFUUE1BJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2RlYWxzIiBzdHlsZT0iZm9udC1mYW1pbHk6IGFyaWFsLHZlcmRhbmEsc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyBjb2xvcjogcmdiKDUxLCAxMDIsIDE1Myk7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgZm9udC13ZWlnaHQ6IGJvbGQ7dGV4dC1hbGlnbjpjZW50ZXI7IHdvcmQtd3JhcDogbm9ybWFsICEgaW1wb3J0YW50OyI-IFRvZGF5J3MgRGVhbHMgPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICA8dGQgcm93c3Bhbj0iMiIgd2lkdGg9IjgiPiZuYnNwOzwvdGQ-DQogICAgICAgICAgICAgICAgICAgICA8dGQgYmdjb2xvcj0iI2NjYyIgd2lkdGg9IjIiIGhlaWdodD0iMTUiPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICA8dGQgcm93c3Bhbj0iMiIgd2lkdGg9IjgiPiZuYnNwOzwvdGQ-DQogICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImNlbnRlciI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL2YuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTJITlg0RTJPWDYzVEImVD1DJlU9aHR0cCUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnJlZGlyZWN0Lmh0bWwlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfYXBwJTJGJTNGbG9jYXRpb24lM0RodHRwJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRm1zaG9wJkg9WFlVRzI0WEdEV0tMUlZCV1VGV1cxV1pHWVY4QSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9hcHAiIHN0eWxlPSJmb250LWZhbWlseTogYXJpYWwsdmVyZGFuYSxzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiByZ2IoNTEsIDEwMiwgMTUzKTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXdlaWdodDogYm9sZDt0ZXh0LWFsaWduOmNlbnRlcjsgd29yZC13cmFwOiBub3JtYWwgISBpbXBvcnRhbnQ7Ij4gR2V0IEFtYXpvbiBBcHAgPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICA8dGQgcm93c3Bhbj0iMiIgd2lkdGg9IjgiIGNsYXNzPSJ4LXNpdGUiPiZuYnNwOzwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgIDwvdGFibGU-PC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgPC90YWJsZT48IS0tIEVuZCBTaW1wbGUgVGVtcGxhdGUgLS0-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgPC90YWJsZT48IS0tICBFbmQgSEVBREVSIC0tPg0KICAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjQwIiBjbGFzcz0iZGV2aWNlV2lkdGgiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBhbGlnbj0iY2VudGVyIiBiZ2NvbG9yPSIjRkZGRkZGIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgYWxpZ249ImNlbnRlciI-PGltZyBzcmM9Imh0dHBzOi8vaW1hZ2VzLW5hLnNzbC1pbWFnZXMtYW1hem9uLmNvbS9pbWFnZXMvRy8wMS90ZW1wbGF0ZS9zZWN0aW9uLWRpdl82NDB4OC5qcGciIGFsdD0iPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ICIgYm9yZGVyPSIwIiBhbGlnbj0ibWlkZGxlIiBjbGFzcz0iZGV2aWNlV2lkdGgiIHN0eWxlPSJiaWN1YmljOyBtYXgtd2lkdGg6NjQwcHg7IG1heC1oZWlnaHQ6OHB4OyBjb2xvcjojQ0NDQ0NDOyBsaW5lLWhlaWdodDoxcHg7aGVpZ2h0OiBhdXRvOyBvdXRsaW5lOiBub25lOyBib3JkZXI6IDAgbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYyI-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICA8dGFibGUgYWxpZ249ImNlbnRlciIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlOyB3aWR0aDoxMDAlO21zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgPHRkIGNsYXNzPSJBbGV4YS1iYW5uZXIiIGFsaWduPSJjZW50ZXIiIHZhbGlnbj0ibWlkZGxlIj48L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjEwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjE1IiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJkZXZpY2VXaWR0aCIgc3R5bGU9IndpZHRoOjEwMCU7bXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgY2xhc3M9ImludHJvLXRleHQiIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjpsZWZ0O2ZvbnQtc2l6ZTogMTJweDsgY29sb3I6IHJnYig1MSwgNTEsIDUxKTsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgdGV4dC1hbGlnbjogbGVmdDsgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBsaW5lLWhlaWdodDogMTZweDsgdmVydGljYWwtYWxpZ246IHRvcDsgcGFkZGluZzogNnB4IDE1cHggMTJweCAxNXB4Ij48c3BhbiBjbGFzcz0ic2FsdXRhdGlvbi10ZXh0IiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOiBub25lOyBjb2xvcjogcmdiKDQ4LCA1NywgNjYpOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiByZ2IoNDgsIDU3LCA2Nik7IGZvbnQtd2VpZ2h0OiBub3JtYWwiPiBIZWxsbyBLaHVzaGFsIFAgUywgPGJyPg0KICAgICAgICAgICAgICAgQW1hem9uIGhhcyBuZXcgcmVjb21tZW5kYXRpb25zIGZvciB5b3UgYmFzZWQgb24geW91ciBicm93c2luZyBoaXN0b3J5LiA8L3NwYW4-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICA8dGFibGUgd2lkdGg9IjY0MCIgY2xhc3M9ImRldmljZVdpZHRoIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYWxpZ249ImNlbnRlciIgYmdjb2xvcj0iI0ZGRkZGRiIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgPHRkIGFsaWduPSJjZW50ZXIiPjxpbWcgc3JjPSJodHRwczovL2ltYWdlcy1uYS5zc2wtaW1hZ2VzLWFtYXpvbi5jb20vaW1hZ2VzL0cvMDEvdGVtcGxhdGUvc2VjdGlvbi1kaXZfNjQweDguanBnIiBhbHQ9Ij0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSAiIGJvcmRlcj0iMCIgYWxpZ249Im1pZGRsZSIgY2xhc3M9ImRldmljZVdpZHRoIiBzdHlsZT0iYmljdWJpYzsgbWF4LXdpZHRoOjY0MHB4OyBtYXgtaGVpZ2h0OjhweDsgY29sb3I6I0NDQ0NDQzsgbGluZS1oZWlnaHQ6MXB4O2hlaWdodDogYXV0bzsgb3V0bGluZTogbm9uZTsgYm9yZGVyOiAwIG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWMiPjwvdGQ-DQogICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgPHRhYmxlIHdpZHRoPSI2NDAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0idmVydGljYWwtYWxpZ246Y2VudHJhbDttc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIiBjbGFzcz0iZGV2aWNlV2lkdGgiPg0KICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgPHRkIHdpZHRoPSIzMiUiIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0ibGVmdCIgc3R5bGU9InBhZGRpbmc6NnB4IDAiIGNsYXNzPSJsY29sIj4NCiAgICAgICAgICAgICAgPHRhYmxlIHdpZHRoPSIxMDAlIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMHB4IiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICA8dGQgdmFsaWduPSJib3R0b20iIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlOyBwYWRkaW5nOjRweCA4cHggNHB4IDhweDttYXgtd2lkdGg6MjQycHggIWltcG9ydGFudDsiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj1ZODhJSUs1STkzUSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMDc0SkI2U1g4JTNGcmVmJTNEZW1fMXBfMV9pbSUyNnJlZl8lM0RwZV80MTA3NTAxXzEyMTc1MjE4ODEmSD1RN0pTQk9FQjFENUZOT0owNElHSFNCUzRZUElBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxIj4gPGltZyBzcmM9Imh0dHBzOi8vbS5tZWRpYS1hbWF6b24uY29tL2ltYWdlcy9JLzUxMkVudWJmTXpMLl9TUjUwMCw1MDBfLl9BQ19TTDUwMF9TUzE3NV8uanBnIiBjbGFzcz0ib21hX3ByX2ltYWdlIiBhbHQ9IkFwVGVjaERlYWxzIEp1bXBlciBXaXJlcyBNYWxlIHRvIE1hbGUsIE1hbGUgdG8gRmVtYWxlLCBGZW1hbGUgdG8gRmVtYWxlL2JyZWFkYm9hcmQganVtcGVyIHdpcmVzICg0MCs0MCs0MCkiIGJvcmRlcj0iMCIgc3R5bGU9ImhlaWdodDogYXV0bzsgb3V0bGluZTogbm9uZTsgYm9yZGVyOiAwIG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7ZGlzcGxheTogYmxvY2s7d2lkdGg6IDE3NXB4ICFpbXBvcnRhbnQ7IGhlaWdodDogMTc1cHggIWltcG9ydGFudCI-IDwvYT48L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICAgPHRkIHdpZHRoPSI2NyUiIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0icmlnaHQiIHN0eWxlPSJwYWRkaW5nOjZweCAwIiBjbGFzcz0icmNvbCI-DQogICAgICAgICAgICAgIDx0YWJsZSB3aWR0aD0iMTAwJSIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgIDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249ImxlZnQiIGNsYXNzPSJwZV9hc2luIiBzdHlsZT0iZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzMzMzMzMzsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgdGV4dC1hbGlnbjogbGVmdDsgZm9udC1mYW1pbHk6QXJpYWwsIHNhbnMtc2VyaWY7IGxpbmUtaGVpZ2h0OiAxNHB4OyB2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlOyBwYWRkaW5nOjRweCAxNXB4IDRweCAwIj4NCiAgICAgICAgICAgICAgICAgIDx0YWJsZSB3aWR0aD0iMTAwJSIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfdGl0bGUiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0ibGVmdCI-PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLFNhbnMtU2VyaWY7Zm9udC1zaXplOjE1cHg7Zm9udC1zdHlsZTpub3JtYWw7dGV4dC1hbGlnbjpsZWZ0O2NvbG9yOiMzMzY2OTk7Ij4gPGEgY2xhc3M9Im9tYV9wcl90aXRsZSIgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTI0SlBSVEEzRU5VRTAmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA3NEpCNlNYOCUzRnJlZiUzRGVtXzFwXzFfdGklMjZyZWZfJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxJkg9T1NZR1EwTVFZOEZXTlhFR1BBVFdUSVRBVjFDQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MSIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7IGNvbG9yOiMzMzY2OTk7Ij4gQXBUZWNoRGVhbHMgSnVtcGVyIFdpcmVzIE1hbGUgdG8gTWFsZSwgTWFsZSB0byBGZW1hbGUsIEZlbWFsZS4uLjwvYT4gPC9zcGFuPiA8c3BhbiBjbGFzcz0ib21hLXByLWJsIiBzdHlsZT0iZm9udC1mYW1pbHk6QXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7Zm9udC1zaXplOjEycHg7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMzMzM7dGV4dC1hbGlnbjpsZWZ0OyI-IDxicj48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MlBPUldFQVFVNk8yMSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZzdG9yZXMlMkZBcHRlY2hkZWFscyUyRnBhZ2UlMkYzN0JEN0I1NS00MDQ4LTQ5REEtQkQxQy0zRkI5NEE2MkE2RTglM0ZyZWZfJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX2FzdF9ibG4mSD1JNU5QWERKQVZBR040SU1aNlRJUkhSOTVDVldBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX2FzdF9ibG4iIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246IG5vbmU7IGZvbnQtc2l6ZTogMTJweDsgY29sb3I6IzMzNjY5OTsiPkFwVGVjaERlYWxzPC9hPiA8L3NwYW4-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICZuYnNwOw0KICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2VfbGlzdCI-DQogICAgICAgICAgICAgICAgICAgICA8dGQ-PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4gPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4gTS5SLlAuOiA8L3NwYW4-IDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-IDxzdHJpa2U-4oK5NDk5LjAwPC9zdHJpa2U-IDwvc3Bhbj4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZD48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPiA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPiBQcmljZTogPC9zcGFuPiA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0icHJfcHJpY2VfaGlnaGxpZ2h0Ij4g4oK5MTg5LjAwIDwvc3Bhbj4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICA8dGQ-PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4gPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4gWW91IFNhdmU6IDwvc3Bhbj4gPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9zYXZpbmdzIj4g4oK5MzEwLjAwICg2MiUpIDwvc3Bhbj4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfbWVyY2hhbnQiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7IHRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGNvbG9yOiM1NTU1NTU7IGZvbnQtc2l6ZToxMnB4OyI-IFNvbGQgYnkgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTNJWDJUSDFHRERJUlYmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZhYWclMkZtYWluJTNGaWUlM0RVVEY4JTI2YXNpbiUzREIwNzRKQjZTWDglMjZpc0FtYXpvbkZ1bGZpbGxlZCUzRDElMjZtYXJrZXRwbGFjZUlEJTNEQTIxVEpSVVVONEtHViUyNnByb3RvY29sJTNEY3VycmVudCUyNnNlbGxlciUzREFKNlNJWkM4WVFEWlglMjZzc2htUGF0aCUzRCUyNnJlZl8lM0RwZV80MTA3NTAxXzEyMTc1MjE4ODEmSD1PRTVRVlBPSkZKOExaQVhKU1YzVEJaMzRIS0VBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgZm9udC1zaXplOjEycHg7Y29sb3I6ICMzMzY2OTk7Ij5DbGlja3RlY2ggUmV0YWlsIFByaXZhdGUgTHRkPC9hPiBhbmQgPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMnB4OyI-RnVsZmlsbGVkIGJ5IEFtYXpvbjwvc3Bhbj4uIDwvc3Bhbj48L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMCI-DQogICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxMHB4O2xpbmUtaGVpZ2h0OjEwcHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgJm5ic3A7DQogICAgICAgICAgICAgICAgICAgICAgPC9kaXY-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIGhlaWdodD0iMTBweCI-DQogICAgICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZTo4cHg7bGluZS1oZWlnaHQ6OHB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICZuYnNwOw0KICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfYnlsaW5lIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICA8dGFibGUgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGhlaWdodD0iNTAiIGNsYXNzPSJidG4iIHdpZHRoPSI4MCUiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO3dpZHRoOiAxMDAlOyB0ZXh0LWFsaWduOiBjZW50ZXIgIWltcG9ydGFudCI-DQogICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgaGVpZ2h0PSIzNCIgd2lkdGg9IjEwMCUiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249ImNlbnRlciIgaGVpZ2h0PSIzNCIgY2xhc3M9ImJ0bi1sZWFybm1vcmUtYmlnIiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogcmdiKDI1NSwgMTk2LCA1Myk7IGJvcmRlci1yYWRpdXM6IDVweDsgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiBib2xkIj48YSBjbGFzcz0ib21hX2JpZ19sbWJ1dHRvbiIgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTJOQ0YzQUhZTFUzVlMmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA3NEpCNlNYOCUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9lbV8xcF8xX2xtJkg9VEE0MTU0VFdSSkxRVFhNVE9NU1RTV0pWR0RLQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9lbV8xcF8xX2xtIiBzdHlsZT0iZGlzcGxheTpibG9jazt0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMzAzOTQyO3doaXRlLXNwYWNlOm5vd3JhcDtwYWRkaW5nOjEwcHg7Ij5MZWFybiBtb3JlPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNnB4Ij4mbmJzcDs8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJidG4tYWRkdG9saXN0LWJpZyIgd2lkdGg9IjMwJSIgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6IHJnYigyMzEsIDIzMSwgMTk0KTsgYm9yZGVyLXJhZGl1czogNXB4OyBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IGJvbGQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9mLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0xNkI3V01QTzY2TTZRJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGaXRlbS1kaXNwYXRjaCUyRjE4Ni01NzUzNTMzLTUyNjIyNDklM0YlMjZhY3Rpb24lM0RhZGQtdG8tcmVnaXN0cnkud2lzaGxpc3QlMjZhc2luLjElM0RCMDc0SkI2U1g4JTI2c3VibWl0LmFkZC10by1yZWdpc3RyeS53aXNobGlzdC54JTNEMSUyNnN1Ym1pdC5hZGQtdG8tcmVnaXN0cnkud2lzaGxpc3QueSUzRDElMjZyZWZfJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxJkg9VFRMTEQyQkc4TTRaVUxDNlFVR0E4OVFVTUZLQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MSIgc3R5bGU9ImRpc3BsYXk6IGJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IHdoaXRlLXNwYWNlOiBub3dyYXA7IGNvbG9yOiByZ2IoNDcsIDQ3LCAxMjEpOyBwYWRkaW5nOjdweDsiPkFkZCB0byBXaXNoIExpc3Q8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgIDwvdGFibGU-PC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjQwIiBjbGFzcz0iZGV2aWNlV2lkdGgiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBhbGlnbj0iY2VudGVyIiBiZ2NvbG9yPSIjRkZGRkZGIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgYWxpZ249ImNlbnRlciI-PGltZyBzcmM9Imh0dHBzOi8vaW1hZ2VzLW5hLnNzbC1pbWFnZXMtYW1hem9uLmNvbS9pbWFnZXMvRy8wMS90ZW1wbGF0ZS9zZWN0aW9uLWRpdl82NDB4OC5qcGciIGFsdD0iPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ICIgYm9yZGVyPSIwIiBhbGlnbj0ibWlkZGxlIiBjbGFzcz0iZGV2aWNlV2lkdGgiIHN0eWxlPSJiaWN1YmljOyBtYXgtd2lkdGg6NjQwcHg7IG1heC1oZWlnaHQ6OHB4OyBjb2xvcjojQ0NDQ0NDOyBsaW5lLWhlaWdodDoxcHg7aGVpZ2h0OiBhdXRvOyBvdXRsaW5lOiBub25lOyBib3JkZXI6IDAgbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYyI-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICA8dGFibGUgd2lkdGg9IjY0MCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ2ZXJ0aWNhbC1hbGlnbjpjZW50cmFsO21zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiIGNsYXNzPSJkZXZpY2VXaWR0aCI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgd2lkdGg9IjMyJSIgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJsZWZ0IiBzdHlsZT0icGFkZGluZzo2cHggMCIgY2xhc3M9Imxjb2wiPg0KICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwcHgiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgIDx0ZCB2YWxpZ249ImJvdHRvbSIgYWxpZ249ImNlbnRlciIgc3R5bGU9InZlcnRpY2FsLWFsaWduOiBtaWRkbGU7IHBhZGRpbmc6NHB4IDhweCA0cHggOHB4O21heC13aWR0aDoyNDJweCAhaW1wb3J0YW50OyI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFPMTAwSFM5TEhES1EmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjA3MVhQNTZMTSUzRnJlZiUzRGVtXzFwXzJfaW0lMjZyZWZfJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxJkg9U1ZITE9HQ1RTWlZDTUozQUFLU0kyVUJDQ0tZQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MSI-IDxpbWcgc3JjPSJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvSS81MW1YdWU2ek5BTC5fU1I1MDAsNTAwXy5fQUNfU0w1MDBfU1MxNzVfLmpwZyIgY2xhc3M9Im9tYV9wcl9pbWFnZSIgYWx0PSJTcXVhZFBpeGVsIEVzcC0zMiBXaWZpLCBCbHVldG9vdGgsIER1YWwgQ29yZSBDaGlwIERldmVsb3BtZW50IEJvYXJkIChFU1AtV1JPT00tMzIpIiBib3JkZXI9IjAiIHN0eWxlPSJoZWlnaHQ6IGF1dG87IG91dGxpbmU6IG5vbmU7IGJvcmRlcjogMCBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljO2Rpc3BsYXk6IGJsb2NrO3dpZHRoOiAxNzVweCAhaW1wb3J0YW50OyBoZWlnaHQ6IDE3NXB4ICFpbXBvcnRhbnQiPiA8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNjclIiB2YWxpZ249Im1pZGRsZSIgYWxpZ249InJpZ2h0IiBzdHlsZT0icGFkZGluZzo2cHggMCIgY2xhc3M9InJjb2wiPg0KICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJsZWZ0IiBjbGFzcz0icGVfYXNpbiIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IHRleHQtYWxpZ246IGxlZnQ7IGZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBsaW5lLWhlaWdodDogMTRweDsgdmVydGljYWwtYWxpZ246IG1pZGRsZTsgcGFkZGluZzo0cHggMTVweCA0cHggMCI-DQogICAgICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3RpdGxlIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249ImxlZnQiPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxNXB4O2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtYWxpZ246bGVmdDtjb2xvcjojMzM2Njk5OyI-IDxhIGNsYXNzPSJvbWFfcHJfdGl0bGUiIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0yVUFGSFdLUVFDQ01BJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwNzFYUDU2TE0lM0ZyZWYlM0RlbV8xcF8yX3RpJTI2cmVmXyUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MSZIPURIRlBYWURDRFBUQ0U3Rk1GU0pFUFhVQVhQQUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODEiIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyBjb2xvcjojMzM2Njk5OyI-IFNxdWFkUGl4ZWwgRXNwLTMyIFdpZmksIEJsdWV0b290aCwgRHVhbCBDb3JlIENoaXAgRGV2ZWxvcG1lbnQuLi48L2E-IDwvc3Bhbj4gPHNwYW4gY2xhc3M9Im9tYS1wci1ibCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMzMzO3RleHQtYWxpZ246bGVmdDsiPiA8YnI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTMzT0NBUTJZWElCSk4mVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGc3RvcmVzJTJGc3Vucm9ib3RpY3MlMkZwYWdlJTJGMTA0MEYyRTktQTNCRS00NkUyLUExMjItRkE1RDZFREVEMzY2JTNGcmVmXyUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9hc3RfYmxuJkg9TkhHWlNBR1hXM0tKVVQyUUhETk1VUEE4QVhPQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9hc3RfYmxuIiBzdHlsZT0idGV4dC1kZWNvcmF0aW9uOiBub25lOyBmb250LXNpemU6IDEycHg7IGNvbG9yOiMzMzY2OTk7Ij5kaXltb3JlPC9hPiA8L3NwYW4-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICZuYnNwOw0KICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2VfbGlzdCI-DQogICAgICAgICAgICAgICAgICAgICA8dGQ-PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4gPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4gTS5SLlAuOiA8L3NwYW4-IDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-IDxzdHJpa2U-4oK5OTk5LjAwPC9zdHJpa2U-IDwvc3Bhbj4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZD48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPiA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPiBQcmljZTogPC9zcGFuPiA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0icHJfcHJpY2VfaGlnaGxpZ2h0Ij4g4oK5NTU3LjAwIDwvc3Bhbj4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfc2F2aW5ncyI-DQogICAgICAgICAgICAgICAgICAgICA8dGQ-PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4gPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4gWW91IFNhdmU6IDwvc3Bhbj4gPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgY29sb3I6ICNDQzAwMDA7IiBjbGFzcz0ib21hX3ByX3ByaWNlX3ZhbF9zYXZpbmdzIj4g4oK5NDQyLjAwICg0NCUpIDwvc3Bhbj4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfbWVyY2hhbnQiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWY7IHRleHQtZGVjb3JhdGlvbjpub25lOyBmb250LXdlaWdodDpub3JtYWw7IGNvbG9yOiM1NTU1NTU7IGZvbnQtc2l6ZToxMnB4OyI-IFNvbGQgYnkgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPThUUzhUOFU1VkZVUiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmFhZyUyRm1haW4lM0ZpZSUzRFVURjglMjZhc2luJTNEQjA3MVhQNTZMTSUyNmlzQW1hem9uRnVsZmlsbGVkJTNEMSUyNm1hcmtldHBsYWNlSUQlM0RBMjFUSlJVVU40S0dWJTI2cHJvdG9jb2wlM0RjdXJyZW50JTI2c2VsbGVyJTNEQUo2U0laQzhZUURaWCUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MSZIPU1OU0RaU0ZOQUtCQ0FZV1BQUU8xTDdEWUZTMEEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODEiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTsgZm9udC13ZWlnaHQ6bm9ybWFsOyBmb250LXNpemU6MTJweDtjb2xvcjogIzMzNjY5OTsiPkNsaWNrdGVjaCBSZXRhaWwgUHJpdmF0ZSBMdGQ8L2E-IGFuZCA8c3BhbiBzdHlsZT0iZm9udC1zaXplOjEycHg7Ij5GdWxmaWxsZWQgYnkgQW1hem9uPC9zcGFuPi4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0ic3BhY2VyIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAmbmJzcDsNCiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj48L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMHB4Ij4NCiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjhweDtsaW5lLWhlaWdodDo4cHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgJm5ic3A7DQogICAgICAgICAgICAgICAgICAgICAgPC9kaXY-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9ieWxpbmUiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgaGVpZ2h0PSI1MCIgY2xhc3M9ImJ0biIgd2lkdGg9IjgwJSIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7d2lkdGg6IDEwMCU7IHRleHQtYWxpZ246IGNlbnRlciAhaW1wb3J0YW50Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBoZWlnaHQ9IjM0IiB3aWR0aD0iMTAwJSIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0iY2VudGVyIiBoZWlnaHQ9IjM0IiBjbGFzcz0iYnRuLWxlYXJubW9yZS1iaWciIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAxOTYsIDUzKTsgYm9yZGVyLXJhZGl1czogNXB4OyBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IGJvbGQiPjxhIGNsYXNzPSJvbWFfYmlnX2xtYnV0dG9uIiBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9V0JUUllSVTJGUFAwJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwNzFYUDU2TE0lMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfZW1fMXBfMl9sbSZIPVZSUksyNUtQNlZDRFNDUjdNWktTMEdFTzFPUUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfZW1fMXBfMl9sbSIgc3R5bGU9ImRpc3BsYXk6YmxvY2s7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzMwMzk0Mjt3aGl0ZS1zcGFjZTpub3dyYXA7cGFkZGluZzoxMHB4OyI-TGVhcm4gbW9yZTwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjZweCI-Jm5ic3A7PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0iYnRuLWFkZHRvbGlzdC1iaWciIHdpZHRoPSIzMCUiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjMxLCAyMzEsIDE5NCk7IGJvcmRlci1yYWRpdXM6IDVweDsgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBib2xkIj48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9VElQS082MDJFTlQwJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGaXRlbS1kaXNwYXRjaCUyRjE4Ni01NzUzNTMzLTUyNjIyNDklM0YlMjZhY3Rpb24lM0RhZGQtdG8tcmVnaXN0cnkud2lzaGxpc3QlMjZhc2luLjElM0RCMDcxWFA1NkxNJTI2c3VibWl0LmFkZC10by1yZWdpc3RyeS53aXNobGlzdC54JTNEMSUyNnN1Ym1pdC5hZGQtdG8tcmVnaXN0cnkud2lzaGxpc3QueSUzRDElMjZyZWZfJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxJkg9VkpYQTJITzhWQ0dOVVRYU1hGQU1GMklSTEFJQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MSIgc3R5bGU9ImRpc3BsYXk6IGJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IHdoaXRlLXNwYWNlOiBub3dyYXA7IGNvbG9yOiByZ2IoNDcsIDQ3LCAxMjEpOyBwYWRkaW5nOjdweDsiPkFkZCB0byBXaXNoIExpc3Q8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgICAgIDwvdGFibGU-PC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgIDx0YWJsZSB3aWR0aD0iNjQwIiBjbGFzcz0iZGV2aWNlV2lkdGgiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBhbGlnbj0iY2VudGVyIiBiZ2NvbG9yPSIjRkZGRkZGIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgYWxpZ249ImNlbnRlciI-PGltZyBzcmM9Imh0dHBzOi8vaW1hZ2VzLW5hLnNzbC1pbWFnZXMtYW1hem9uLmNvbS9pbWFnZXMvRy8wMS90ZW1wbGF0ZS9zZWN0aW9uLWRpdl82NDB4OC5qcGciIGFsdD0iPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ICIgYm9yZGVyPSIwIiBhbGlnbj0ibWlkZGxlIiBjbGFzcz0iZGV2aWNlV2lkdGgiIHN0eWxlPSJiaWN1YmljOyBtYXgtd2lkdGg6NjQwcHg7IG1heC1oZWlnaHQ6OHB4OyBjb2xvcjojQ0NDQ0NDOyBsaW5lLWhlaWdodDoxcHg7aGVpZ2h0OiBhdXRvOyBvdXRsaW5lOiBub25lOyBib3JkZXI6IDAgbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYyI-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgPC90YWJsZT4NCiAgICAgICAgICA8dGFibGUgd2lkdGg9IjY0MCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ2ZXJ0aWNhbC1hbGlnbjpjZW50cmFsO21zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiIGNsYXNzPSJkZXZpY2VXaWR0aCI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgd2lkdGg9IjMyJSIgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJsZWZ0IiBzdHlsZT0icGFkZGluZzo2cHggMCIgY2xhc3M9Imxjb2wiPg0KICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwcHgiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgIDx0ZCB2YWxpZ249ImJvdHRvbSIgYWxpZ249ImNlbnRlciIgc3R5bGU9InZlcnRpY2FsLWFsaWduOiBtaWRkbGU7IHBhZGRpbmc6NHB4IDhweCA0cHggOHB4O21heC13aWR0aDoyNDJweCAhaW1wb3J0YW50OyI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTNNRURLUlJNRTFPRVAmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZwcm9kdWN0JTJGQjBCQjdQRzU0VCUzRnJlZiUzRGVtXzFwXzNfaW0lMjZyZWZfJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxJkg9VE5BUkRQWkFWRkRXSEU2Q1U2N0FJSzJXN0xFQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MSI-IDxpbWcgc3JjPSJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvSS80MThVdWdjZk9sTC5fU1I1MDAsNTAwXy5fQUNfU0w1MDBfU1MxNzVfLmpwZyIgY2xhc3M9Im9tYV9wcl9pbWFnZSIgYWx0PSJ4Y2x1bWEgREFDIE1vZHVsZSAxMzM0IFVEQTEzMzRBIEkyUyBEQUMgU3RlcmVvIERlY29kZXIgTW9kdWxlIEZvciB1bm8gMy4zViAtIDVWIiBib3JkZXI9IjAiIHN0eWxlPSJoZWlnaHQ6IGF1dG87IG91dGxpbmU6IG5vbmU7IGJvcmRlcjogMCBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljO2Rpc3BsYXk6IGJsb2NrO3dpZHRoOiAxNzVweCAhaW1wb3J0YW50OyBoZWlnaHQ6IDE3NXB4ICFpbXBvcnRhbnQiPiA8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNjclIiB2YWxpZ249Im1pZGRsZSIgYWxpZ249InJpZ2h0IiBzdHlsZT0icGFkZGluZzo2cHggMCIgY2xhc3M9InJjb2wiPg0KICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJsZWZ0IiBjbGFzcz0icGVfYXNpbiIgc3R5bGU9ImZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICMzMzMzMzM7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IHRleHQtYWxpZ246IGxlZnQ7IGZvbnQtZmFtaWx5OkFyaWFsLCBzYW5zLXNlcmlmOyBsaW5lLWhlaWdodDogMTRweDsgdmVydGljYWwtYWxpZ246IG1pZGRsZTsgcGFkZGluZzo0cHggMTVweCA0cHggMCI-DQogICAgICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InByX3RpdGxlIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249ImxlZnQiPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTpBcmlhbCxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxNXB4O2ZvbnQtc3R5bGU6bm9ybWFsO3RleHQtYWxpZ246bGVmdDtjb2xvcjojMzM2Njk5OyI-IDxhIGNsYXNzPSJvbWFfcHJfdGl0bGUiIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0yMDdaS1o4WkFCMlhMJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcHJvZHVjdCUyRkIwQkI3UEc1NFQlM0ZyZWYlM0RlbV8xcF8zX3RpJTI2cmVmXyUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MSZIPVlaQVFHVUU3T0FHSjBDVUFHQUJFRU1BWFNFQ0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODEiIHN0eWxlPSJmb250LXNpemU6IDE0cHg7IHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyBjb2xvcjojMzM2Njk5OyI-IHhjbHVtYSBEQUMgTW9kdWxlIDEzMzQgVURBMTMzNEEgSTJTIERBQyBTdGVyZW8gRGVjb2RlciBNb2R1bGUuLi48L2E-IDwvc3Bhbj4gPHNwYW4gY2xhc3M9Im9tYS1wci1ibCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0eWxlOm5vcm1hbDt0ZXh0LWRlY29yYXRpb246bm9uZTtjb2xvcjojMzMzO3RleHQtYWxpZ246bGVmdDsiPiA8YnI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFYNTVTSTBFUEtNRDEmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGc3RvcmVzJTJGeGNsdW1hJTJGcGFnZSUyRjE1NzFEMzBELTAyOTYtNDA0Qy04OTZFLUJBMzQzNjFGRkI1NyUzRnJlZl8lM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfYXN0X2JsbiZIPU5OMElPTlVBOUFWNlJBWEhUVUJDT05GTktGVUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfYXN0X2JsbiIgc3R5bGU9InRleHQtZGVjb3JhdGlvbjogbm9uZTsgZm9udC1zaXplOiAxMnB4OyBjb2xvcjojMzM2Njk5OyI-eGNsdW1hPC9hPiA8L3NwYW4-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIGhlaWdodD0iMTAiPg0KICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-DQogICAgICAgICAgICAgICAgICAgICAgICZuYnNwOw0KICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2VfbGlzdCI-DQogICAgICAgICAgICAgICAgICAgICA8dGQ-PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDEycHg7Ij4gPHNwYW4gY2xhc3M9InByX3ByaWNlX2xhYmVsIj4gTS5SLlAuOiA8L3NwYW4-IDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiAjQ0MwMDAwOyIgY2xhc3M9Im9tYV9wcl9wcmljZV92YWxfbGlzdCI-IDxzdHJpa2U-4oK5NzA5LjAwPC9zdHJpa2U-IDwvc3Bhbj4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0icHJfcHJpY2Vfb3VyIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZD48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPiA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPiBEZWFsIFByaWNlOiA8L3NwYW4-IDxzcGFuIHN0eWxlPSJmb250LXNpemU6IDEzcHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJwcl9wcmljZV9oaWdobGlnaHQiPiDigrk1MTYuMDAgPC9zcGFuPiA8L3NwYW4-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9wcmljZV9zYXZpbmdzIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZD48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTJweDsiPiA8c3BhbiBjbGFzcz0icHJfcHJpY2VfbGFiZWwiPiBZb3UgU2F2ZTogPC9zcGFuPiA8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogbm9ybWFsOyBjb2xvcjogI0NDMDAwMDsiIGNsYXNzPSJvbWFfcHJfcHJpY2VfdmFsX3NhdmluZ3MiPiDigrkxOTMuMDAgKDI3JSkgPC9zcGFuPiA8L3NwYW4-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9tZXJjaGFudCI-DQogICAgICAgICAgICAgICAgICAgICA8dGQ-PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCxIZWx2ZXRpY2Esc2Fucy1zZXJpZjsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7IGZvbnQtd2VpZ2h0Om5vcm1hbDsgY29sb3I6IzU1NTU1NTsgZm9udC1zaXplOjEycHg7Ij4gRGlzcGF0Y2hlZCBmcm9tIGFuZCBzb2xkIGJ5IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0yQjhSUVJKSjVIU1BLJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGYWFnJTJGbWFpbiUzRmllJTNEVVRGOCUyNmFzaW4lM0RCMEJCN1BHNTRUJTI2aXNBbWF6b25GdWxmaWxsZWQlM0QwJTI2bWFya2V0cGxhY2VJRCUzREEyMVRKUlVVTjRLR1YlMjZwcm90b2NvbCUzRGN1cnJlbnQlMjZzZWxsZXIlM0RBMzFQVUlPUEhKNTZZMyUyNnNzaG1QYXRoJTNEJTI2cmVmXyUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MSZIPUFTUFNCQUwwMjJWTUFOWERMSVJBMkJZRE5MMEEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODEiIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb246bm9uZTsgZm9udC13ZWlnaHQ6bm9ybWFsOyBmb250LXNpemU6MTJweDtjb2xvcjogIzMzNjY5OTsiPnhjbHVtYcKuPC9hPi4gPC9zcGFuPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgIDx0ciBjbGFzcz0ic3BhY2VyIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPg0KICAgICAgICAgICAgICAgICAgICAgICAmbmJzcDsNCiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj48L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICA8dHIgY2xhc3M9InNwYWNlciI-DQogICAgICAgICAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxMHB4Ij4NCiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IHdpZHRoPSIxIiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjhweDtsaW5lLWhlaWdodDo4cHg7Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgJm5ic3A7DQogICAgICAgICAgICAgICAgICAgICAgPC9kaXY-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgPHRyIGNsYXNzPSJwcl9ieWxpbmUiPg0KICAgICAgICAgICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGJvcmRlcj0iMCIgaGVpZ2h0PSI1MCIgY2xhc3M9ImJ0biIgd2lkdGg9IjgwJSIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7d2lkdGg6IDEwMCU7IHRleHQtYWxpZ246IGNlbnRlciAhaW1wb3J0YW50Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgYm9yZGVyPSIwIiBoZWlnaHQ9IjM0IiB3aWR0aD0iMTAwJSIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0iY2VudGVyIiBoZWlnaHQ9IjM0IiBjbGFzcz0iYnRuLWxlYXJubW9yZS1iaWciIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAxOTYsIDUzKTsgYm9yZGVyLXJhZGl1czogNXB4OyBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IGJvbGQiPjxhIGNsYXNzPSJvbWFfYmlnX2xtYnV0dG9uIiBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MjdDSVIyTlJSQkU2WSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnByb2R1Y3QlMkZCMEJCN1BHNTRUJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX2VtXzFwXzNfbG0mSD0zVTRZQTAyTjEwREFOQVJZUlgyNElESEdBV1VBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX2VtXzFwXzNfbG0iIHN0eWxlPSJkaXNwbGF5OmJsb2NrO3RleHQtZGVjb3JhdGlvbjpub25lO2NvbG9yOiMzMDM5NDI7d2hpdGUtc3BhY2U6bm93cmFwO3BhZGRpbmc6MTBweDsiPkxlYXJuIG1vcmU8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSI2cHgiPiZuYnNwOzwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB2YWxpZ249Im1pZGRsZSIgYWxpZ249ImNlbnRlciIgY2xhc3M9ImJ0bi1hZGR0b2xpc3QtYmlnIiB3aWR0aD0iMzAlIiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogcmdiKDIzMSwgMjMxLCAxOTQpOyBib3JkZXItcmFkaXVzOiA1cHg7IGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOiAxMnB4OyBmb250LXdlaWdodDogYm9sZCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL2YuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTJKODMyNk5RTjlLRVkmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGZ3AlMkZpdGVtLWRpc3BhdGNoJTJGMTg2LTU3NTM1MzMtNTI2MjI0OSUzRiUyNmFjdGlvbiUzRGFkZC10by1yZWdpc3RyeS53aXNobGlzdCUyNmFzaW4uMSUzREIwQkI3UEc1NFQlMjZzdWJtaXQuYWRkLXRvLXJlZ2lzdHJ5Lndpc2hsaXN0LnglM0QxJTI2c3VibWl0LmFkZC10by1yZWdpc3RyeS53aXNobGlzdC55JTNEMSUyNnJlZl8lM0RwZV80MTA3NTAxXzEyMTc1MjE4ODEmSD1KUVRYMUFETVhYQjBWV1BEOE9QQ0tQM0hQVVlBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxIiBzdHlsZT0iZGlzcGxheTogYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgd2hpdGUtc3BhY2U6IG5vd3JhcDsgY29sb3I6IHJnYig0NywgNDcsIDEyMSk7IHBhZGRpbmc6N3B4OyI-QWRkIHRvIFdpc2ggTGlzdDwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgPHRhYmxlIHdpZHRoPSI2NDAiIGNsYXNzPSJkZXZpY2VXaWR0aCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIGFsaWduPSJjZW50ZXIiIGJnY29sb3I9IiNGRkZGRkYiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgIDx0ZCBhbGlnbj0iY2VudGVyIj48aW1nIHNyYz0iaHR0cHM6Ly9pbWFnZXMtbmEuc3NsLWltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzAxL3RlbXBsYXRlL3NlY3Rpb24tZGl2XzY0MHg4LmpwZyIgYWx0PSI9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gPSA9ID0gIiBib3JkZXI9IjAiIGFsaWduPSJtaWRkbGUiIGNsYXNzPSJkZXZpY2VXaWR0aCIgc3R5bGU9ImJpY3ViaWM7IG1heC13aWR0aDo2NDBweDsgbWF4LWhlaWdodDo4cHg7IGNvbG9yOiNDQ0NDQ0M7IGxpbmUtaGVpZ2h0OjFweDtoZWlnaHQ6IGF1dG87IG91dGxpbmU6IG5vbmU7IGJvcmRlcjogMCBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljIj48L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgIDx0YWJsZSBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjUiIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMTAwJSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZTo1cHg7bGluZS1oZWlnaHQ6NXB4OyI-DQogICAgICAgICAgICAgICAmbmJzcDsNCiAgICAgICAgICAgICAgPC9kaXY-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICA8dGFibGUgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJsZWZ0IiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE1Ij4NCiAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjE1IiBjbGFzcz0ic3BhY2VyIiBzdHlsZT0iZm9udC1zaXplOjEwcHg7bGluZS1oZWlnaHQ6MTBweDsiPg0KICAgICAgICAgICAgICAgICAgICZuYnNwOw0KICAgICAgICAgICAgICAgICAgPC9kaXY-PC90ZD4NCiAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMCIgdmFsaWduPSJ0b3AiPjxpbWcgY2xhc3M9Im9tYV9vdXRyb190ZXh0X2hhbGZfYXJyb3ciIHNyYz0iaHR0cHM6Ly9pbWFnZXMtbmEuc3NsLWltYWdlcy1hbWF6b24uY29tL2ltYWdlcy9HLzAxL3RlYS9hNC5fQ0IzMzI5MzUzNzlfLmdpZiIgd2lkdGg9IjEwIiBhbHQ9Ij4iIGhlaWdodD0iMTRweCIgYm9yZGVyPSIwIiBzdHlsZT0iaGVpZ2h0OiBhdXRvOyBvdXRsaW5lOiBub25lOyBib3JkZXI6IDAgbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYyI-PC90ZD4NCiAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MUpNUjFDSjFPQUNDQyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnlvdXJzdG9yZSUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9lbV9mbCZIPTI1S01LWFpERlBCQkNHQVhHTlZKTldaU0haSUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfZW1fZmwiIGNsYXNzPSJvbWEtb3V0cm8tdGV4dCIgc3R5bGU9ImZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxTYW5zLVNlcmlmO2ZvbnQtc2l6ZToxNHB4O2ZvbnQtd2VpZ2h0Om5vcm1hbDsgZm9udC1zdHlsZTpub3JtYWw7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzAwNEI5MTt0ZXh0LWFsaWduOmxlZnQ7Ij4gU2VlIHNpbWlsYXIgcHJvZHVjdHMgPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTUiPg0KICAgICAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMTUiIGNsYXNzPSJzcGFjZXIiIHN0eWxlPSJmb250LXNpemU6MTBweDtsaW5lLWhlaWdodDoxMHB4OyI-DQogICAgICAgICAgICAgICAgICAgJm5ic3A7DQogICAgICAgICAgICAgICAgICA8L2Rpdj48L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPHRyIGhlaWdodD0iMTUiIGNsYXNzPSJzcGFjZXIiPg0KICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgPGRpdiB3aWR0aD0iMTAwJSIgY2xhc3M9InNwYWNlciIgc3R5bGU9ImZvbnQtc2l6ZToxNXB4O2xpbmUtaGVpZ2h0OjE1cHg7Ij4NCiAgICAgICAgICAgICAgICZuYnNwOw0KICAgICAgICAgICAgICA8L2Rpdj48L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgIDx0YWJsZSBjbGFzcz0ic2VmX3NwYWNlciIgd2lkdGg9IjEwMCUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBzdHlsZT0iYm9yZGVyLXNwYWNpbmc6MHB4O2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZTttaW4td2lkdGg6MTAwJTttc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgPHRyIGhlaWdodD0iMiI-DQogICAgICAgICAgICAgPHRkIGJnY29sb3I9IiNjY2NjYzkiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjIiPg0KICAgICAgICAgICAgICA8ZGl2IGNsYXNzPSJvbWFfZGl2aWRlcl9mb290ZXIiIHdpZHRoPSIxMDAlIiBzdHlsZT0iZm9udC1zaXplOjJweDtsaW5lLWhlaWdodDoycHg7YmFja2dyb3VuZC1pbWFnZTogdXJsKGh0dHBzOi8vaW1hZ2VzLW5hLnNzbC1pbWFnZXMtYW1hem9uLmNvbS9pbWFnZXMvRy8wMS90ZW1wbGF0ZS9zZWN0aW9uLWRpdl82NDB4OC5qcGcpICFpbXBvcnRhbnQ7IGJhY2tncm91bmQtY29sb3I6IHJnYigyNTUsIDI1NSwgMjU1KTsgaGVpZ2h0OiAxMHB4ICFpbXBvcnRhbnQ7IGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQiPg0KICAgICAgICAgICAgICAgJm5ic3A7DQogICAgICAgICAgICAgIDwvZGl2PjwvdGQ-DQogICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgIDwvdGFibGU-PCEtLSBjaGVjayBpZiB3ZSBhcmUgZ2V0dGluZyB0aGUgZW1haWxBZHMgcHJvcGVybHkgb3RoZXJ3aXNlIGRvIG5vdCBkaXNwbGF5IEFkcy0tPg0KICAgICAgICAgIDx0YWJsZSBjbGFzcz0iY3Mtc2xvdCBkZXZpY2VXaWR0aCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIHdpZHRoPSI2NDAiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgPHRhYmxlIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgd2lkdGg6MTAwJTttc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIj4NCiAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz0iZm9vdGVyLWJhbm5lciIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiPjwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz0iZm9vdGVyLWJhbm5lciIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiPjwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz0iZm9vdGVyLWJhbm5lciIgYWxpZ249ImNlbnRlciIgdmFsaWduPSJtaWRkbGUiPjwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgIDwvdGFibGU-PC90ZD4NCiAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgPHRkPg0KICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjY0MCIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJkZXZpY2VXaWR0aCBzZWZfZm9vdGVyX2xpbmtmYXJtIiB2YWxpZ249Im1pZGRsZSIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDAlIiBjbGFzcz0ibGlua2Zhcm0iIHN0eWxlPSJmb250LWZhbWlseTpIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmO2Rpc3BsYXk6aW5saW5lLWJsb2NrOyI-DQogICAgICAgICAgICAgICAgICA8dGFibGUgd2lkdGg9IjY0MCIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGFsaWduPSJjZW50ZXIiIGNsYXNzPSJkZXZpY2VXaWR0aCBzZWZfZm9vdGVyX2xpbmtmYXJtIiBiZ2NvbG9yPSIjRkZGRkZGIiB2YWxpZ249Im1pZGRsZSIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDAlIiBiZ2NvbG9yPSIjRkZGRkZGIiBjbGFzcz0ibGlua2Zhcm0iIHN0eWxlPSJmb250LWZhbWlseTpIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmOyI-DQogICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIHdpZHRoPSIxMDAlIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNlbGxwYWRkaW5nPSIxMCIgY2VsbHNwYWNpbmc9IjAiIGJnY29sb3I9IiNGRkZGRkYiIGNsYXNzPSJmYXJtIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjEwMCUiIGFsaWduPSJsZWZ0IiBjbGFzcz0iZmFybWhlYWQiIHN0eWxlPSJmb250LWZhbWlseTphcmlhbDtmb250LXNpemU6MTRweDtjb2xvcjojZTQ3OTExO2xpbmUtaGVpZ2h0OjE2cHg7IGZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1mYW1pbHk6IGFyaWFsOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiByZ2IoMjI4LCAxMjEsIDE3KTsgbGluZS1oZWlnaHQ6IDE2cHg7IGZvbnQtd2VpZ2h0OiBib2xkIj48Zm9udCBmYWNlPSJhcmlhbCwgdmVyZGFuYSxhIHNhbnMtc2VyaWYiIHNpemU9IjMiIGNvbG9yPSIjZTQ3OTExIiBzdHlsZT0iZm9udC1mYW1pbHk6YXJpYWw7Zm9udC1zaXplOjE0cHg7Y29sb3I6I2U0NzkxMTtsaW5lLWhlaWdodDoxNnB4Ij5GaW5kIEdyZWF0IERlYWxzIG9uIE1pbGxpb25zIG9mIFByb2R1Y3RzPC9mb250PjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBzdHlsZT0iZm9udC1mYW1pbHk6YXJpYWwsaGVsdmV0aWNhLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHg7bXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSIgY2xhc3M9InNlZl9mb290ZXJfbGlua2Zhcm0iPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxNTUiIHZhbGlnbj0idG9wIiBjbGFzcz0iZmFybTEiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlIHN0eWxlPSJmb250LWZhbWlseTphcmlhbCxoZWx2ZXRpY2Esc2Fucy1zZXJpZjtmb250LXNpemU6MTJweDttc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlIiB3aWR0aD0iOTUlIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIyIiBjZWxscGFkZGluZz0iMCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj1KOVBVSjVXUExINlAmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9sZl9Cb29rcyUyRiUzRm5vZGUlM0Q5NzYzODkwMzEmSD1PU0dKOE9IM1FRWUM2NzlVVkFFRExRVUFQS1FBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX0Jvb2tzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-Qm9va3M8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0xUjc1SlA1STRSRkdLJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfbGZfZUJvb2tzJTJGJTNGbm9kZSUzRDE2MzQ3NTMwMzEmSD1ETjFWSlRTME1YME5aSVc1SkdQSk1KUlRDWDRBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX2VCb29rcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPktpbmRsZSBlQm9va3M8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj1MOENIMVpPTlJWSlYmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUzRm5vZGUlM0Q5ODQwMDk3MDMxJTI2cmVmJTNEcGVfbGZfS2VSZWFkZXIlMjZyZWZfJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxJkg9T0VNRk5CVTdESVBTR0xFN0hZS0dFSEtYQUgwQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPktpbmRsZSBlLXJlYWRlciA8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0yWDg3SU05OFNNR1Q1JlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmRwJTJGQjAwUUpET0VBTyUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9sZl9LUFcmSD1YS1pERThFNFJUNEVGWlZSVkdHUlA2WFVTSktBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX0tQVyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPktpbmRsZSBQYXBlcndoaXRlIDwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFLRFk4RjdTTlk1SzgmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9sZl9NdXNpYyUyRiUzRm5vZGUlM0Q5NzY0NDUwMzEmSD1RN0RVMUZQRElXMFBGV1ZES0NTQTBEMU01MU9BJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX011c2ljIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-TXVzaWMsPC9hPiA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MlFESzZWSVVJTkJRRyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX01vdmllcyUyRiUzRm5vZGUlM0Q5NzY0MTYwMzEmSD1VSkJQSTVETUU2UkVLVDZRSUE5VkNGTVJXS0FBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX01vdmllcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPk1vdmllczwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFKN0tVN0ZSOVBISUsmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9sZl9WRyUyRiUzRm5vZGUlM0Q5NzY0NjAwMzEmSD1CR0tPR0NCRlhBSTczNDlRUVJUUEJHSENBSENBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX1ZHIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-VmlkZW8gR2FtZXM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE4MCIgdmFsaWduPSJ0b3AiIGNsYXNzPSJmYXJtMiI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGFibGUgc3R5bGU9ImZvbnQtZmFtaWx5OmFyaWFsLGhlbHZldGljYSxzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxMnB4O21zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiIHdpZHRoPSI5NSUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjIiIGNlbGxwYWRkaW5nPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTNRUThRUk9VWFpRUTEmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9sZl9Nb2JpbGVzJTJGJTNGbm9kZSUzRDEzODk0MDEwMzEmSD1TQUFLQ0pBTzE4RktQS1NBTEVMQ0pUU05VSUtBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2xmX01vYmlsZXMiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5Nb2JpbGVzICZhbXA7IDwvYT48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MjhUTjdVQUFLSUJBVSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX1RhYmxldHMlMkYlM0Zub2RlJTNEMTM3NTQ1ODAzMSZIPU1aNk9YTDVaU1Y5WEhERkZLRkRJWlU2QkFBQ0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfVGFibGV0cyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPlRhYmxldHM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0zT1VPTjU1Rk5NNjU4JlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfbGZfQ29tcHMlMkYlM0Zub2RlJTNEOTc2MzkyMDMxJkg9TlcyN1VCOU9ZRUZSQVZEQUdXQklZQktBV09XQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9sZl9Db21wcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkNvbXB1dGVycyAmYW1wOyBBY2Nlc3NvcmllczwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFGS0FSUlpZVVdIUUYmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9sZl9DYW1lcmElMkYlM0Zub2RlJTNEMTM4ODk3NzAzMSZIPUVaMEZFUlNKVEFaSFRYR1A1QlpBSExYNlVBWUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfbGZfQ2FtZXJhIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-Q2FtZXJhcyw8L2E-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPU9PQ0hRSUJTS1FaRyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0FWVFYlMkYlM0Zub2RlJTNEMTU3NTQwNzAzMSZIPVEyTldRU0xGSzFKMkFXRUlBM1hYOUFGUkFYRUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfQVZUViIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPiBBdWRpbyAmYW1wOyBWaWRlbzwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFLWlJMT1NPRUpPSkcmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9NdXNpY2FsSW5zdHIlMkYlM0Zub2RlJTNEMzY3NzY5NzAzMSZIPTRJRUEyMDdEREFZQVZFVUxYWDlZN1dBU0hTU0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfTXVzaWNhbEluc3RyIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-TXVzaWNhbCBJbnN0cnVtZW50czwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTNMUEozWEg4M0FNSEQmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9TcG9ydHMlMkYlM0Zub2RlJTNEMTk4NDQ0MzAzMSZIPU1BRlY4UFNVTFVWSktOWlBRNVBKTFJWQ1NPT0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfU3BvcnRzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-U3BvcnRzICZhbXA7IEZpdG5lc3M8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0yTzFZT0JUWkxaOEdJJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfSEslMkYlM0Zub2RlJTNEOTc2NDQyMDMxJkg9VTI2RzdCUVMzQVRSWERaNVZRU09QR1ZZRzNTQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9ISyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkhvbWUgJmFtcDsgS2l0Y2hlbjwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iMTM1IiB2YWxpZ249InRvcCIgY2xhc3M9ImZhcm0zIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZSBzdHlsZT0iZm9udC1mYW1pbHk6YXJpYWwsaGVsdmV0aWNhLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHg7bXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSIgd2lkdGg9Ijk1JSIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMiIgY2VsbHBhZGRpbmc9IjAiPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MzhMV0xGQjFURzlRRCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0Nsb3RoaW5nJTJGJTNGbm9kZSUzRDE1NzEyNzEwMzEmSD1RUU9POU9OSlVKSlhTN1E4R0FIWFZBTEJGQUFBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0Nsb3RoaW5nIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-Q2xvdGhpbmcsIEFjY2Vzc29yaWVzPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MUxGMUkxQldVUlVSMSZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX1dhdGNoZXMlMkYlM0Zub2RlJTNEMTM1MDM4NzAzMSZIPUFaU0tRVEw0WURLREZRVkNMWVNKTEFUM040OEEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfV2F0Y2hlcyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPldhdGNoZXMsPC9hPiA8YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9Mk01SUhISTFGSDk3SCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0pld2VsbGVyeSUyRiUzRm5vZGUlM0QxOTUxMDQ4MDMxJkg9V1hBT0ZUTERNNFZIRk9LTllXQ1FBWkJWRlBXQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9KZXdlbGxlcnkiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5KZXdlbGxlcnk8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj1WWEcxOVhZUlVKWFomVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9IYW5kYmFncyUyRiUzRm5vZGUlM0QxOTgzMzM4MDMxJkg9S1BMM1NZNUpOSjdLNUxWRUJUVkJPM09YVlpJQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9IYW5kYmFncyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkhhbmRiYWdzICZhbXA7IDwvYT48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9Mlo0QTBWQ1FDOERWUiZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0x1Z2dhZ2UlMkYlM0Zub2RlJTNEMjQ1NDE2OTAzMSZIPUFLQ0VBWVRRMkVFR1NVTllSWDNCOFBEODNISUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfTHVnZ2FnZSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkx1Z2dhZ2U8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0yQTM5QUpXTk02MDdZJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfU2hvZXMlMkYlM0Zub2RlJTNEMTk4MzM5NjAzMSZIPUNBUUMzTklJVVRFTVVSTFhWQUJRQUNNT0JaT0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfU2hvZXMiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5TaG9lczwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTNPMTZMUlVZOVRVUEQmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9CZWF1dHklMkYlM0Zub2RlJTNEMTM1NTAxNjAzMSZIPUM1RjhQUFlZWFlWTFhYWk1YSzFIQUxWOUxTS0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfQmVhdXR5IiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-QmVhdXR5ICZhbXA7IDwvYT48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9M0dYRk4yWTFOQ0tTTyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0hlYWx0aCUyRiUzRm5vZGUlM0QxMzUwMzg0MDMxJkg9RFhLRUpaTFcxVlcwUFNPVU5EM0ZFWFlUTlg0QSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9IZWFsdGgiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5IZWFsdGg8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0xWVM1UlVKVlNDUFEmVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9Ub3lzJTJGJTNGbm9kZSUzRDEzNTAzODAwMzEmSD1ISERRN1EzRkVESjBSQTVZQVZMNFhBMEJQQU1BJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX1RveXMiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5Ub3lzICZhbXA7IDwvYT48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MTdEMTBHRTUzQzZCRCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0JhYnklMkYlM0Zub2RlJTNEMTU3MTI3NDAzMSZIPUNEQUVMR1ZZT1NEOFJPNEQ3QVNSR1hQSDNHUUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfQmFieSIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkJhYnkgUHJvZHVjdHM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgd2lkdGg9IjE3MCIgdmFsaWduPSJ0b3AiIGNsYXNzPSJmYXJtNCI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGFibGUgc3R5bGU9ImZvbnQtZmFtaWx5OmFyaWFsLGhlbHZldGljYSxzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxMnB4O21zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiIHdpZHRoPSI5NSUiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjIiIGNlbGxwYWRkaW5nPSIwIj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBhbGlnbj0ibGVmdCI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL3IuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTM1RklTQjRMTEczTE0mVD1DJlU9aHR0cHMlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGYiUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9HQyUyRiUzRm5vZGUlM0QzNzA0OTgyMDMxJkg9VjFITUkxTjNJS1NGWkRLTUVRRjlFTVhBU0JJQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9HQyIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkdpZnQgQ2FyZHM8L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9yLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0xWUZFU1dQUklBUkJUJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmIlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfUGV0cyUyRiUzRm5vZGUlM0QyNDU0MTgxMDMxJkg9SDFWRkI5TkFVTkUxRkZYQ0tBSlE2QkhZR1QwQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9QZXRzIiBzdHlsZT0iY29sb3I6IzY2Njt0ZXh0LWRlY29yYXRpb246bm9uZSI-UGV0IFN1cHBsaWVzPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MkdKT0VBWkRVMFczTCZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZiJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX0dvdXJtZXQlMkYlM0Zub2RlJTNEMjQ1NDE3ODAzMSZIPTNMOEE1VlY2VlZSTlFEWFhQMEFPVENZMEU4T0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfR291cm1ldCIgc3R5bGU9ImNvbG9yOiM2NjY7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPkdvdXJtZXQgPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9UVMwRFpESU9TQ0FPJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRm1zaG9wJTNGcmVmXyUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MSZIPTVPU0xSNExRSEwwQlVaSDhJVExFV1hQVUJNVUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODEiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5BbWF6b24gU2hvcHBpbmcgQXBwPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9OUk3M1c2WE9OUU5ZJlQ9QyZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGZGlnaXRhbCUyRmZpb25hJTJGa2NwLWxhbmRpbmctcGFnZSUzRnJlZl8lM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfS0NQJkg9SlpLQVZUVE9JS1UzQVROUkdQSzU1TERTVlRPQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9LQ1AiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5LaW5kbGUgUmVhZGluZyBBcHBzPC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3AvZi5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MjFOREZDSlFUOVVONyZUPUMmVT1odHRwcyUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRmZlYXR1cmUuaHRtbCUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9BcHBzdG9yZSUzRmllJTNEVVRGOCUyNmRvY0lkJTNEMTAwMDcyMTc3MyZIPTBHOE9EQUhRSVlOVVNJRllVSUYySlBaVTNaR0EmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfQXBwc3RvcmUiIHN0eWxlPSJjb2xvcjojNjY2O3RleHQtZGVjb3JhdGlvbjpub25lIj5BcHBzdG9yZSBmb3IgQW5kcm9pZDwvYT48L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgICAgICAgICAgPHRhYmxlIGNsYXNzPSJzZWZfc3BhY2VyIiB3aWR0aD0iNjQwIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgc3R5bGU9ImJvcmRlci1zcGFjaW5nOjBweDtib3JkZXItY29sbGFwc2U6Y29sbGFwc2U7bXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgICAgICA8dHIgaGVpZ2h0PSIyIj4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCBiZ2NvbG9yPSIjY2NjY2M5IiB3aWR0aD0iNjQwIiBoZWlnaHQ9IjIiPg0KICAgICAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjY0MCIgc3R5bGU9ImZvbnQtc2l6ZToycHg7bGluZS1oZWlnaHQ6MnB4O2JhY2tncm91bmQtaW1hZ2U6IHVybChodHRwczovL2ltYWdlcy1uYS5zc2wtaW1hZ2VzLWFtYXpvbi5jb20vaW1hZ2VzL0cvMDEvdGVtcGxhdGUvc2VjdGlvbi1kaXZfNjQweDguanBnKSAhaW1wb3J0YW50OyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7IGhlaWdodDogMTBweCAhaW1wb3J0YW50OyBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ij4NCiAgICAgICAgICAgICAgICAgICAgICAgJm5ic3A7DQogICAgICAgICAgICAgICAgICAgICAgPC9kaXY-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICA8L3RhYmxlPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI-DQogICAgLnNlZl9mb290ZXJfY29ubmVjdCAueXNob3J0Y3V0cyB7IGNvbG9yOiNGRkZGRkYgfQ0KPC9zdHlsZT4NCiAgICAgICAgICAgICAgPHRhYmxlIGNsYXNzPSJzZWZfZm9vdGVyX2Nvbm5lY3QiIGJnY29sb3I9IiNGRkZGRkYiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjEwIiBjZWxsc3BhY2luZz0iMCIgd2lkdGg9IjY0MCIgYWxpZ249ImNlbnRlciIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWJvdHRvbTogM3B4IHNvbGlkIHJnYigxMzYsIDEzNiwgMTM2KTsgaGVpZ2h0OiAwcHggIWltcG9ydGFudDsgbWF4LWhlaWdodDogMHB4ICFpbXBvcnRhbnQ7IGZvbnQtc2l6ZTogMHB4OyBtYXJnaW46IDA7IHdpZHRoOiAxMDAlIj4NCiAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICA8dHI-DQogICAgICAgICAgICAgICAgIDx0ZCB3aWR0aD0iNTAlIj4NCiAgICAgICAgICAgICAgICAgIDx0YWJsZSBib3JkZXI9IjAiIGFsaWduPSJsZWZ0IiBjZWxscGFkZGluZz0iNiIgY2VsbHNwYWNpbmc9IjAiIGNsYXNzPSJzZXR0aW5ncyIgY2JvcmRlcj0iMCIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJsZWZ0Ij48YSBocmVmPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9VkNFSERKREozR1pQJlQ9QyZVPWh0dHAlM0ElMkYlMkZ3d3cuYW1hem9uLmluJTJGcmVmJTNEcGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2Zvb3Rlcl9hbWF6b25sb2dvJTJGJkg9WUNYR0lDVk8wVlNVQkYyNVJETjRQRjZLNExHQSZyZWZfPXBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9mb290ZXJfYW1hem9ubG9nbyIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgc3JjPSJodHRwOi8vZy1lYzIuaW1hZ2VzLWFtYXpvbi5jb20vaW1hZ2VzL0cvMzEvYWEvYW1hem9uL2xvZ28yLmdpZiIgYWx0PSJBbWF6b24uaW4iIGJvcmRlcj0iMCIgYWxpZ249ImxlZnQiIHN0eWxlPSJoZWlnaHQ6IGF1dG87IG91dGxpbmU6IG5vbmU7IGJvcmRlcjogMCBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljIj48L2E-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgICAgICA8dGQgYWxpZ249InJpZ2h0Ij4NCiAgICAgICAgICAgICAgICAgIDx0YWJsZSBjbGFzcz0iY29ubmVjdCIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iNiIgY2VsbHNwYWNpbmc9IjAiIGFsaWduPSJyaWdodCIgc3R5bGU9Im1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlO2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2UiPg0KICAgICAgICAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICAgICAgPHRkIGFsaWduPSJyaWdodCI-PGZvbnQgc3R5bGU9ImZvbnQtZmFtaWx5OiB2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWY7IGZvbnQtc2l6ZTogMTBweDsgY29sb3I6ICM2NjY7IGxpbmUtaGVpZ2h0OjEwcHgiIGNvbG9yPSIjOTk5IiBmYWNlPSJ2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWYiIHNpemU9IjEiPkNvbm5lY3Qgd2l0aCBBbWF6b24gSW5kaWE8L2ZvbnQ-PC90ZD4NCiAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz0iZmFjZWJvb2siPjxmb250IHN0eWxlPSJmb250LWZhbWlseTogdmVyZGFuYSxhcmlhbCxzYW5zLXNlcmlmOyBmb250LXNpemU6IDEwcHg7IGNvbG9yOiAjOTk5OyIgY29sb3I9IiM5OTkiIGZhY2U9InZlcmRhbmEsYXJpYWwsc2Fucy1zZXJpZiIgc2l6ZT0iMSI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL2YuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPVpBQjUyTURHNDZIOCZUPUMmVT1odHRwJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRmdwJTJGcmVkaXJlY3QuaHRtbCUyRnJlZiUzRHBlXzQxMDc1MDFfMTIxNzUyMTg4MV9wZV9mYl9mdHIlMkYlM0Zsb2NhdGlvbiUzRGh0dHAlM0ElMkYlMkZ3d3cuZmFjZWJvb2suY29tJTJGQW1hem9uSU4lMjZ0b2tlbiUzRDIwNzVENUVBQzdCQjIxNDA4OTcyOEUyMTgzRkQzOTE3MDZENDFFOTQmSD05SVRBM0VFUlVKWjhFOUJaQjJNWUpWQVRZQ1lBJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX3BlX2ZiX2Z0ciIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgc3JjPSJodHRwOi8vZy1lY3guaW1hZ2VzLWFtYXpvbi5jb20vaW1hZ2VzL0cvMDEvdXMtbWFpbC9GQmxvZ28uZ2lmIiBhbHQ9ImltYWdlIiBib3JkZXI9IjAiIGhlaWdodD0iMzAiIGhzcGFjZT0iMCIgdnNwYWNlPSIwIiB3aWR0aD0iMzAiIHN0eWxlPSJ3aWR0aDozMHB4OyBoZWlnaHQ6MzBweDtoZWlnaHQ6IGF1dG87IG91dGxpbmU6IG5vbmU7IGJvcmRlcjogMCBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljIj48L2E-PC9mb250PjwvdGQ-DQogICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3M9InR3aXR0ZXIiPjxmb250IHN0eWxlPSJmb250LWZhbWlseTogdmVyZGFuYSxhcmlhbCxzYW5zLXNlcmlmOyBmb250LXNpemU6IDEwcHg7IGNvbG9yOiAjOTk5OyIgY29sb3I9IiM5OTkiIGZhY2U9InZlcmRhbmEsYXJpYWwsc2Fucy1zZXJpZiIgc2l6ZT0iMSI-PGEgaHJlZj0iaHR0cHM6Ly93d3cuYW1hem9uLmluL2dwL2YuaHRtbD9DPTFEWVdGQ1lEQllGMEsmSz0ySDVEUEtYVlNaQTJTJk09dXJuOnJ0bjptc2c6MjAyNDExMjUwMDEzNDEzNjQxODI3YWE0OGQ0NWEwYTc1MjNlNDU4NjMwcDBldSZSPTFRRTNJRFRWVEhMN1QmVD1DJlU9aHR0cCUzQSUyRiUyRnd3dy5hbWF6b24uaW4lMkZncCUyRnJlZGlyZWN0Lmh0bWwlMkZyZWYlM0RwZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfdHdfZnRyJTJGJTNGbG9jYXRpb24lM0RodHRwJTNBJTJGJTJGdHdpdHRlci5jb20lMkZBbWF6b25JTiUyNnRva2VuJTNEQTMwOURGQkZDQjFFMzdBODA4RkY1MzE5MzQ4NTVEQzgxN0YxMzBCNiZIPUEwQTI3WElSUzlNRkFDSTJZMEVTUTQ2WkFTSUEmcmVmXz1wZV80MTA3NTAxXzEyMTc1MjE4ODFfcGVfdHdfZnRyIiB0YXJnZXQ9Il9ibGFuayI-PGltZyBzcmM9Imh0dHA6Ly9nLWVjeC5pbWFnZXMtYW1hem9uLmNvbS9pbWFnZXMvRy8wMS91cy1tYWlsL1R3aXR0ZXJMb2dvLmdpZiIgYWx0PSJpbWFnZSIgYm9yZGVyPSIwIiBoZWlnaHQ9IjMwIiBoc3BhY2U9IjAiIHZzcGFjZT0iMCIgd2lkdGg9IjMwIiBzdHlsZT0id2lkdGg6MzBweDsgaGVpZ2h0OjMwcHg7aGVpZ2h0OiBhdXRvOyBvdXRsaW5lOiBub25lOyBib3JkZXI6IDAgbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYyI-PC9hPjwvZm9udD48L3RkPg0KICAgICAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgIDwvdGJvZHk-DQogICAgICAgICAgICAgIDwvdGFibGU-DQogICAgICAgICAgICAgIDx0YWJsZSBhbGlnbj0iY2VudGVyIiB3aWR0aD0iNjQwIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIyIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9InNlZl9sZWdhbF9mb290ZXIiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNlM2UzZTM7bXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTtiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjI3LCAyMjcsIDIyNykiIGJnY29sb3I9IiNlM2UzZTMiPg0KICAgICAgICAgICAgICAgPHRib2R5Pg0KICAgICAgICAgICAgICAgIDx0ciBoZWlnaHQ9IjEwIj4NCiAgICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIxMDAlIj4NCiAgICAgICAgICAgICAgICAgIDxkaXYgd2lkdGg9IjEwMCUiIHN0eWxlPSJmb250LXNpemU6MTBweDsgbGluZS1oZWlnaHQ6MTBweCI-DQogICAgICAgICAgICAgICAgICAgJm5ic3A7DQogICAgICAgICAgICAgICAgICA8L2Rpdj48L3RkPg0KICAgICAgICAgICAgICAgIDwvdHI-DQogICAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgICA8dGQgYWxpZ249ImxlZnQiIGNsYXNzPSJsZWdhbC10ZXh0IiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIFNhbnMtU2VyaWY7IGZvbnQtc2l6ZTogMTBweDsgY29sb3I6IHJnYigxMDIsIDEwMiwgMTAyKSI-V2UgaG9wZSB5b3UgZm91bmQgdGhpcyBtZXNzYWdlIHRvIGJlIHVzZWZ1bC4gSG93ZXZlciwgaWYgeW91J2QgcmF0aGVyIG5vdCByZWNlaXZlIGZ1dHVyZSBlLW1haWxzIG9mIHRoaXMgc29ydCBmcm9tIEFtYXpvbi5pbiwgcGxlYXNlIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmFtYXpvbi5pbi9ncC9mLmh0bWw_Qz0xRFlXRkNZREJZRjBLJks9Mkg1RFBLWFZTWkEyUyZNPXVybjpydG46bXNnOjIwMjQxMTI1MDAxMzQxMzY0MTgyN2FhNDhkNDVhMGE3NTIzZTQ1ODYzMHAwZXUmUj0zQ1JFUFhBQTdaVk9CJlQ9WCZVPWh0dHBzJTNBJTJGJTJGd3d3LmFtYXpvbi5pbiUyRiUyRmdwJTJGZ3NzJTJGbyUyRjEtUGl2alZxeEk1NmhQUzRiRVBJYWlmcnpLMHFxVWh5NFJWZUpJUEZhRlNtZE5qWnpqZTVXNHZUaG9wMGNtUTNBJkg9TUlESVpONllSUE9BVTJLTklUVTFDTExGSFQ4QSIgc3R5bGU9ImZvbnQtZmFtaWx5OiBBcmlhbCxIZWx2ZXRpY2EsU2Fucy1TZXJpZjsgZm9udC1zaXplOiAxMHB4OyI-b3B0LW91dCBoZXJlPC9hPiA8YnI-PGJyPg0KICAgICAgICAgICAgICAgICAgIFBsZWFzZSBub3RlIHRoYXQgcHJvZHVjdCBwcmljZXMgYW5kIGF2YWlsYWJpbGl0eSBhcmUgc3ViamVjdCB0byBjaGFuZ2UuIFByaWNlcyBhbmQgYXZhaWxhYmlsaXR5IHdlcmUgYWNjdXJhdGUgYXQgdGhlIHRpbWUgdGhpcyBuZXdzbGV0dGVyIHdhcyBzZW50OyBob3dldmVyLCB0aGV5IG1heSBkaWZmZXIgZnJvbSB0aG9zZSB5b3Ugc2VlIHdoZW4geW91IHZpc2l0IEFtYXpvbi5pbi4gPGJyPjxicj4NCiAgICAgICAgICAgICAgICAgIEFtYXpvbi5pbiBNYXJrZXRwbGFjZSBwbGF0Zm9ybTogUHJvZHVjdHMgc29sZCBieSBhIE1hcmtldHBsYWNlIHNlbGxlciBhcmUgc3ViamVjdCB0byB0aGF0IHNlbGxlcidzIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHNhbGUuIFNlZSB3d3cuQW1hem9uLmluIGZvciBkZXRhaWxzLiA8YnI-PGJyPg0KICAgICAgICAgICAgICAgICAgIFJlZmVyZW5jZTogMTIxNzUyMTg4MTxicj48YnI-DQogICAgICAgICAgICAgICAgICAgVGhpcyBtZXNzYWdlIHdhcyBzZW50IHRvIHRoZSBmb2xsb3dpbmcgZS1tYWlsIGFkZHJlc3M6IDxzcGFuIHN0eWxlPSJmb250LWZhbWlseTogQXJpYWwsSGVsdmV0aWNhLFNhbnMtU2VyaWY7IGZvbnQtc2l6ZTogMTBweDsiPnBza2h1c2hhbEBnbWFpbC5jb208L3NwYW4-PC90ZD4NCiAgICAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICAgICAgPC90YWJsZT48L3RkPg0KICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICA8L3RhYmxlPg0KICAgICAgICAgIDx0YWJsZSBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGJvcmRlcj0iMCIgY2xhc3M9Im1vYmlsZS1oaWRlLWdtYWlsIiBzdHlsZT0ibXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7Ym9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZSI-DQogICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgICA8dGQgaGVpZ2h0PSIxIiBjbGFzcz0iaGlkZSIgc3R5bGU9Im1pbi13aWR0aDo2MjBweDsgZm9udC1zaXplOjBweDtsaW5lLWhlaWdodDowcHg7Ij48aW1nIGhlaWdodD0iMSIgc3R5bGU9Im1pbi13aWR0aDogNjIwcHg7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgYm9yZGVyOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljO2hlaWdodDogYXV0bzsgb3V0bGluZTogbm9uZTsgYm9yZGVyOiAwIG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWMiPjwvdGQ-DQogICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICA8L3Rib2R5Pg0KICAgICAgICAgIDwvdGFibGU-PC90ZD4NCiAgICAgICAgPC90cj4NCiAgICAgICA8L3Rib2R5Pg0KICAgICAgPC90YWJsZT48L3RkPg0KICAgIDwvdHI-DQogICA8L3Rib2R5Pg0KICA8L3RhYmxlPg0KIDxpbWcgd2lkdGg9IjEiIGhlaWdodD0iMSIgc3JjPSJodHRwczovL3d3dy5hbWF6b24uaW4vZ3Avci5odG1sP0M9MURZV0ZDWURCWUYwSyZLPTJINURQS1hWU1pBMlMmTT11cm46cnRuOm1zZzoyMDI0MTEyNTAwMTM0MTM2NDE4MjdhYTQ4ZDQ1YTBhNzUyM2U0NTg2MzBwMGV1JlI9MUNSVkoyQU5JWEtEJlQ9RSZVPWh0dHBzJTNBJTJGJTJGaW1hZ2VzLWV1LnNzbC1pbWFnZXMtYW1hem9uLmNvbSUyRmltYWdlcyUyRkclMkYwMSUyRm5hdiUyRnRyYW5zcC5naWYmSD0wNkRRQUcxQ1I0VDlVUDEyM05KWk41S1NPUU9BJnJlZl89cGVfNDEwNzUwMV8xMjE3NTIxODgxX29wZW4iIC8-PC9ib2R5Pg0KPC9odG1sPg0KDQoNCg0K" - } - } - ] - }, - "sizeEstimate": 95303, - "historyId": "527027", - "internalDate": "1732493621000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_09_193604ad97c9fe62_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_09_193604ad97c9fe62_20241126.json deleted file mode 100644 index 6c7dde9..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_09_193604ad97c9fe62_20241126.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "id": "193604ad97c9fe62", - "threadId": "193604ad97c9fe62", - "labelIds": [ - "CATEGORY_PROMOTIONS", - "UNREAD", - "INBOX" - ], - "snippet": "Recycle your PDF gold and reduce your workload with Acrobat Pro. Don't retype \u2014 convert. Don't start from scratch. Easily export PDFs to Microsoft Word, Excel, or PowerPoint with Adobe Acrobat", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp636404wrq; Sun, 24 Nov 2024 14:28:58 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IG02Zz30iAXQJFRHwhVqBjRs62bpBBF9EmsARKy8d0TbGNC/QbESPGoHcwafLZ+/DTw8fAP" - }, - { - "name": "X-Received", - "value": "by 2002:a05:6a00:2ea5:b0:724:f1c9:236c with SMTP id d2e1a72fcca58-724f1c924a3mr11174135b3a.23.1732487338215; Sun, 24 Nov 2024 14:28:58 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732487338; cv=none; d=google.com; s=arc-20240605; b=BkRQX1CoSbdgeVpMHZuyACpWp9taQwJGxtvDTif3IxAICjpTdjeWq+5JdDV4Uwnu02 NdzQIxmVL/NR2u6kGifSp2aNI5G5kNlAcKbW3FFAuYPYGyEwKGF4cgayfyT5ttOxXSb8 OL/vIfHGMB+EhWM9CdxN/bDiqrwSKhKr7HeyE5qa5+KvcnWayhPk+drRLcxfaVdx8c09 G9a+LuNwnaRkINQuT9uCNYn1nYbt6VXC6aycx0tXwKbkT1jEMmbEbfATfxz0JV7N0LZL S20NrLq6gyBqaOeMtYj7yoGK66S1WO93I2IvkQ/cL1RHjVTWi11uJQwCX6r+a0DIJSr+ SqVw==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe-post:list-unsubscribe:precedence:list-id :message-id:mime-version:reply-to:to:date:subject:from :dkim-signature; bh=1lptYPv/3h7ptWQkDQ2BQd+y6H+sw4rkTtaN67WzQ0g=; fh=wSHF2rrasHXl3o4LupFQZ06Qw8S5yTQ44eGiiuBsHt4=; b=O2SbZHiPbOR3NTCBFGyrvX4FO8Jt4Xk1bZYoKlaJJ4iIJa4s7H972SL3ulx8p387KG KPDMaDD3rK5AFHj912NyuvG1E0hnbbPM7avJ9b/etApzS7vAqPWsbsRNlzlVA1fkVwBE I09G12ixs68RrKRG4ektvSgvwtadrSQbIjGshTRdUEh37rn3qg4onOYrm51/8vw5hx4k bErFBhmk/NSiM0Bhd36CbJjIYhpF2es4focowTXAUku8/Z5FTGjn42PmCclg1MXNDAb/ pAaYYlblh3eqDhsMxxWS4Cg5e4AMC3BXZK90q++mstuxthl4CxL7gxcPVaUD7s/NYN5w QoNg==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@mail.adobe.com header.s=neolane header.b=PGed0onR; spf=pass (google.com: domain of adobe1apacmid@mail.adobe.com designates 192.243.228.145 as permitted sender) smtp.mailfrom=adobe1apacmid@mail.adobe.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=mail.adobe.com" - }, - { - "name": "Return-Path", - "value": "" - }, - { - "name": "Received", - "value": "from r145.mail.adobe.com (r145.mail.adobe.com. [192.243.228.145]) by mx.google.com with ESMTPS id d2e1a72fcca58-724de6d55b0si7337017b3a.335.2024.11.24.14.28.57 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 24 Nov 2024 14:28:58 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of adobe1apacmid@mail.adobe.com designates 192.243.228.145 as permitted sender) client-ip=192.243.228.145;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@mail.adobe.com header.s=neolane header.b=PGed0onR; spf=pass (google.com: domain of adobe1apacmid@mail.adobe.com designates 192.243.228.145 as permitted sender) smtp.mailfrom=adobe1apacmid@mail.adobe.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=mail.adobe.com" - }, - { - "name": "Return-Path", - "value": "" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=mail.adobe.com; s=neolane; t=1732487085; bh=1lptYPv/3h7ptWQkDQ2BQd+y6H+sw4rkTtaN67WzQ0g=; h=From:Subject:Date:To:MIME-Version:Message-ID:List-Unsubscribe:\t List-Unsubscribe-Post:Content-Type; b=PGed0onRzbU40A0rSs93G37hCp/BC21G75ixcyQIY7N0j4E/T2iszXK69V8W6VR6b\t FhQiwITgY75GLCbWQFfXS/f53b1d0KcnR1flrGqCUOwVnhnC4BMxb2jSNuRY7xJQzU\t oj2qPmkO2EDyiqWgMRdKgO7iYcfGa3HHQVjOtbeY=" - }, - { - "name": "X-MSFBL", - "value": "FNvCf8tUPE+TVHz+Db2yzES18D7yLKbBjFGiRb5d/P0=|eyJnIjoicHJvZC5kZWZ hdWx0XzQ3YjUzMWVjLWY5MzEtNDYwMS1hMGU4LTIzZTE4MWRlYTBkMCIsInJjcHR fbWV0YSI6eyAibSI6ICItNzI4MDY3MTk2IiwgImQiOiAiMTQ3OTQwNDkxIiwgIml uIjogImFkb2JlaW5fbWlkX3Byb2Q4IiwgInIiOiAicHNraHVzaGFsQGdtYWlsLmN vbSIgfSwiciI6InBza2h1c2hhbEBnbWFpbC5jb20iLCJiIjoiYXdzX2Fkb2JlaW5 0X3Byb2Q4X3Byb2QuZGVmYXVsdF9tb21lbnR1bTAzX210YTAwMV8xOTIuMjQzLjI yOC4xNDUifQ==" - }, - { - "name": "Received", - "value": "from [10.139.37.132] ([10.139.37.132:39084] helo=r143.mail.adobe.com) by momentum03.or1.cpt.adobe.net (envelope-from ) (ecelerity 4.2.38.999 r(:)) with ESMTP id F7/55-50100-DA7A3476; Sun, 24 Nov 2024 14:24:45 -0800" - }, - { - "name": "From", - "value": "Adobe Acrobat " - }, - { - "name": "Subject", - "value": "Save time and reuse your best content" - }, - { - "name": "Date", - "value": "Sun, 24 Nov 2024 14:24:43 -0800" - }, - { - "name": "To", - "value": "" - }, - { - "name": "Reply-To", - "value": "Adobe Acrobat " - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "X-mailer", - "value": "nlserver, Build 6.7.0" - }, - { - "name": "Message-ID", - "value": "" - }, - { - "name": "X-250ok-CID", - "value": "adobeA681974_APAC-17120766_241124" - }, - { - "name": "X-CSA-Complaints", - "value": "whitelist-complaints@eco.de" - }, - { - "name": "List-Id", - "value": "<-509008722.neolane.client.com>" - }, - { - "name": "Precedence", - "value": "bulk" - }, - { - "name": "List-Unsubscribe", - "value": "" - }, - { - "name": "List-Unsubscribe-Post", - "value": "List-Unsubscribe=One-Click" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; charset=\"windows-1252\"; boundary=\"----=_NextPart_823_A9D79D3B.A9D79D3B\"" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain; charset=\"utf-8\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "8bit" - } - ], - "body": { - "size": 1357, - "data": "VmlldyB3ZWIgdmVyc2lvbjoNCmh0dHBzOi8vdC1pbmZvLm1haWwuYWRvYmUuY29tL3IvP2lkPXRlOWVmZTIxOCxmZTNlOGJlZSxjMDA1ODE0ZiZlPWNERTlKVFF3YmxkelEyUndSRkk0VVRsTGRsTnVZVzVESlRKR2JuUnJVVU5hY0ZsellqTlpSa3RSZGtGUmRXNWpNelZqSlRORSZzPXozblFVcjV0TDZrMERWOFd5eDhYb2U0QXJKWWk0dTdheGI3N0dZaU51dlENCg0KVW5mb3J0dW5hdGVseSwgeW91ciBlbWFpbCBjbGllbnQgY2Fubm90IGRpc3BsYXkgSFRNTCBvciB5b3VyIHNldHRpbmdzIGFyZSB0dXJuZWQgb2ZmLiBUbyB2aWV3IHRoaXMgZW1haWwsIHBsZWFzZSBjbGljayBvciBjb3B5IGFuZCBwYXN0ZSB0aGUgbGluayBhYm92ZSBpbnRvIHlvdXIgYnJvd3Nlci4NCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KVGhpcyBpcyBhIG1hcmtldGluZyBlbWFpbCBmcm9tIEFkb2JlIFN5c3RlbXMgU29mdHdhcmUgSXJlbGFuZCBMaW1pdGVkLCA0LTYgUml2ZXJ3YWxrLCBDaXR5d2VzdCBCdXNpbmVzcyBQYXJrLCBEdWJsaW4gMjQsIElyZWxhbmQuDQoNCkNsaWNrIG9uIHRoZSBmb2xsb3dpbmcgbGluayB0byB1bnN1YnNjcmliZSwgb3Igc2VuZCB1cyBhbiB1bnN1YnNjcmliZSByZXF1ZXN0IHRvIHRoZSBwb3N0YWwgYWRkcmVzcyBhYm92ZS4NCkNsaWNrJm5ic3A7aGVyZTogIGh0dHBzOi8vdC1pbmZvLm1haWwuYWRvYmUuY29tL3IvP2lkPXRlOWVmZTIxOCxmZTNlOGJlZSxjMDA1ODE1MCZlPWNERTlKVFF3VDFjMGNuSTRVMGRqTmpKT1RVVlZiWGRoU1RKU2RITmtVV2xsY0V4NU1VZG1Ua1FsTWtadVNsWm5WMWhKSlRORUpuQXlQU1pzYjJNOWFXNG1jRE05TVRrJnM9TnJxVGxzVmhUcTBLWnY1dnB2UXRPd0hWZi03bDB0UWhRU3RfbDRRX3NOcyAgDQoNClBsZWFzZSByZXZpZXcgdGhlIEFkb2JlIFByaXZhY3kgUG9saWN5Lg0KaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9dGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MTUxDQoNClRvIGVuc3VyZSBmdXR1cmUgZGVsaXZlcnkgb2YgZW1haWwsIHBsZWFzZSBhZGQgbWFpbEBtYWlsLmFkb2JlLmNvbSB0byB5b3VyIGFkZHJlc3MgYm9vaywgY29udGFjdHMsIG9yIHNhZmUgc2VuZGVycyBsaXN0Lg0KaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9dGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MTUyDQoNClBsZWFzZSBkbyBub3QgcmVwbHkgdG8gdGhpcyBtZXNzYWdlLiBUbyBjb250YWN0IEFkb2JlLGZpbmQgb3B0aW9ucyBvbmxpbmUuDQpodHRwczovL3QtaW5mby5tYWlsLmFkb2JlLmNvbS9yLz9pZD10ZTllZmUyMTgsZmUzZThiZWUsYzAwNTgxNTMNCg==" - } - }, - { - "partId": "1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html; charset=\"utf-8\"" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - } - ], - "body": { - "size": 15684, - "data": "DQoNCg0KPCFET0NUWVBFIGh0bWw-DQo8aHRtbCB4bWxucz0iaHR0cHM6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIHhtbG5zOnY9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206dm1sIiB4bWxuczpvPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTpvZmZpY2UiPg0KPGhlYWQ-DQo8bGluayByZWw9Imljb24iIGhyZWY9Imh0dHBzOi8vd3d3LmFkb2JlLmNvbS9mYXZpY29uLmljbyIgdHlwZT0iaW1hZ2UveC1pY29uIj4NCjxsaW5rIHJlbD0ic2hvcnRjdXQgaWNvbiIgaHJlZj0iaHR0cHM6Ly93d3cuYWRvYmUuY29tL2Zhdmljb24uaWNvIiB0eXBlPSJpbWFnZS94LWljb24iPg0KPG1ldGEgbmFtZT0ieC1hcHBsZS1kaXNhYmxlLW1lc3NhZ2UtcmVmb3JtYXR0aW5nIj4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04Ij4NCjxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsaW5pdGlhbC1zY2FsZT0xLjAiPg0KPG1ldGEgbmFtZT0iZm9ybWF0LWRldGVjdGlvbiIgY29udGVudD0idGVsZXBob25lPW5vIj4NCjxtZXRhIG5hbWU9ImZvcm1hdC1kZXRlY3Rpb24iIGNvbnRlbnQ9ImRhdGU9bm8iPg0KPG1ldGEgbmFtZT0iZm9ybWF0LWRldGVjdGlvbiIgY29udGVudD0iYWRkcmVzcz1ubyI-DQo8bWV0YSBuYW1lPSJmb3JtYXQtZGV0ZWN0aW9uIiBjb250ZW50PSJlbWFpbD1ubyI-DQo8dGl0bGU-U2F2ZSB0aW1lIGFuZCByZXVzZSB5b3VyIGJlc3QgY29udGVudDwvdGl0bGU-DQoNCjwhLS1baWYgbXNvXT4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI-DQpib2R5LCB0YWJsZSwgdGQgew0KZm9udC1mYW1pbHk6YWRvYmUtY2xlYW4sIEhlbHZldGljYSBOZXVlLCBIZWx2ZXRpY2EsIFZlcmRhbmEsIEFyaWFsLCBzYW5zLXNlcmlmICFpbXBvcnRhbnQ7DQp9DQp0ZC5oaWRle2Rpc3BsYXk6bm9uZSAhaW1wb3J0YW50O30NCi53ZWI1MHt3aWR0aDogMjBweCAhaW1wb3J0YW50O30NCi53ZWIyMHt3aWR0aDogNTBweCAhaW1wb3J0YW50O30NCjwvc3R5bGU-DQo8eG1sPg0KPG86T2ZmaWNlRG9jdW1lbnRTZXR0aW5ncz4NCjxvOkFsbG93UE5HLz4NCjxvOlBpeGVsc1BlckluY2g-OTY8L286UGl4ZWxzUGVySW5jaD4NCjwvbzpPZmZpY2VEb2N1bWVudFNldHRpbmdzPg0KPC94bWw-DQo8IVtlbmRpZl0tLT4gDQo8IS0tW2lmIGd0IG1zbyAxNV0-DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiIG1lZGlhPSJhbGwiPg0KLyogT3V0bG9vayAyMDE2IEhlaWdodCBGaXggKi8NCnRhYmxlLCB0ciwgdGQge2JvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7fQ0KdHIgeyBmb250LXNpemU6MHB4OyBsaW5lLWhlaWdodDowcHg7IGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7IH0NCjwvc3R5bGU-DQo8IVtlbmRpZl0tLT4NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCkBpbXBvcnQgdXJsKCJodHRwczovL3VzZS50eXBla2l0Lm5ldC9vbnI4dGJyLmNzcyIpOw0KDQpAbWVkaWEgKHByZWZlcnMtY29sb3Itc2NoZW1lOiBkYXJrKSB7DQp9DQouUmVhZE1zZ0JvZHkgew0Kd2lkdGg6IDEwMCU7DQp9DQouRXh0ZXJuYWxDbGFzcyB7DQp3aWR0aDogMTAwJTsNCn0NCnRhYmxlIHsNCmJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7DQp9DQphLCBhOnZpc2l0ZWQgew0KY29sb3I6ICMzMjFGRUQ7DQp0ZXh0LWRlY29yYXRpb246IG5vbmU7DQp9DQoubGVnYWwgYSB7DQp0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsNCn0NCi8qIGlPUyBCTFVFIExJTktTICovDQphW3gtYXBwbGUtZGF0YS1kZXRlY3RvcnNdIHsNCmNvbG9yOiBpbmhlcml0ICFpbXBvcnRhbnQ7DQp0ZXh0LWRlY29yYXRpb246IG5vbmUgIWltcG9ydGFudDsNCmZvbnQtc2l6ZTogaW5oZXJpdCAhaW1wb3J0YW50Ow0KZm9udC1mYW1pbHk6IGluaGVyaXQgIWltcG9ydGFudDsNCmZvbnQtd2VpZ2h0OiBpbmhlcml0ICFpbXBvcnRhbnQ7DQpsaW5lLWhlaWdodDogaW5oZXJpdCAhaW1wb3J0YW50Ow0KfQ0KLm1vYmlsZSB7DQpib3JkZXItc3BhY2luZzogMDsNCmRpc3BsYXk6IG5vbmUhaW1wb3J0YW50Ow0KaGVpZ2h0OiAwOw0KbWF4LWhlaWdodDogMDsNCm1zby1oaWRlOiBhbGw7DQpvdmVyZmxvdzogaGlkZGVuOw0KdmlzaWJpbGl0eTogaGlkZGVuOw0Kd2lkdGg6IDA7DQp9DQoNCkBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDo0ODBweCkgew0KdSB-IGRpdiB7DQptaW4td2lkdGg6IDEwMHZ3Ow0KfQ0KZGl2ID4gdSB-IGRpdiB7DQptaW4td2lkdGg6IDEwMCU7DQp9DQoud2ViLCAud2ViMjAsIC53ZWI1MCB7DQpkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7DQp9DQoubW9iaWxlIHsNCmRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7DQp3aWR0aDogYXV0byAhaW1wb3J0YW50Ow0Kb3ZlcmZsb3c6IHZpc2libGUgIWltcG9ydGFudDsNCmhlaWdodDogYXV0byAhaW1wb3J0YW50Ow0KbWF4LWhlaWdodDogaW5oZXJpdCAhaW1wb3J0YW50Ow0KZm9udC1zaXplOiAxNXB4ICFpbXBvcnRhbnQ7DQpsaW5lLWhlaWdodDogMjFweCAhaW1wb3J0YW50Ow0KdmlzaWJpbGl0eTogdmlzaWJsZSAhaW1wb3J0YW50Ow0KfQ0KLmJsb2NrIHsNCmRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7DQp3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0Kb3ZlcmZsb3c6IHZpc2libGUgIWltcG9ydGFudDsNCmhlaWdodDogYXV0byAhaW1wb3J0YW50Ow0KbWF4LWhlaWdodDogaW5oZXJpdCAhaW1wb3J0YW50Ow0KdmlzaWJpbGl0eTogdmlzaWJsZSAhaW1wb3J0YW50Ow0KcGFkZGluZy1sZWZ0OiAwICFpbXBvcnRhbnQ7DQp9DQoucGFkYi01MCB7DQpwYWRkaW5nLWJvdHRvbTogNTBweCAhaW1wb3J0YW50Ow0KfQ0KLm1rdG9UZXh0IHsNCndpZHRoOiAyMDBweCFpbXBvcnRhbnQ7DQp9DQouZW1haWwtd2lkdGggew0Kd2lkdGg6IDg0JSAhaW1wb3J0YW50Ow0KfQ0KLmZ1bGwtd2lkdGggew0Kd2lkdGg6IDEwMCUgIWltcG9ydGFudDsNCn0NCi5tb2JpbGUtaW1hZ2Ugew0KaGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7DQp3aWR0aDogMTAwJSAhaW1wb3J0YW50Ow0KfQ0KLnNvY2lhbCB7DQpmbG9hdDogbGVmdCAhaW1wb3J0YW50Ow0KcGFkZGluZy10b3A6IDY2cHggIWltcG9ydGFudDsNCnRleHQtYWxpZ246IGxlZnQgIWltcG9ydGFudDsNCn0NCi5oZWFkZXIgew0KZm9udC1zaXplOiA0MHB4ICFpbXBvcnRhbnQ7DQpsaW5lLWhlaWdodDogNDZweCAhaW1wb3J0YW50Ow0KfQ0KLnBhZGRpbmctcjAgew0KcGFkZGluZy1yaWdodDogMHB4ICFpbXBvcnRhbnQ7DQp9DQoucmFpbmJvdzEgew0KYmFja2dyb3VuZC1zaXplOiAxMDAlIDEwMCUgIWltcG9ydGFudDsNCn0NCi5wYWRiLTAgew0KcGFkZGluZy1ib3R0b206IDBweCAhaW1wb3J0YW50Ow0KfQ0KLnBhZGItNDAgew0KcGFkZGluZy1ib3R0b206IDQwcHggIWltcG9ydGFudDsNCn0NCi5idG1fcGFkYm90dG9tIHsNCnBhZGRpbmctYm90dG9tOiAxMDBweCFpbXBvcnRhbnQ7DQp9DQp9DQo8L3N0eWxlPg0KPC9tZXRhPjwvbWV0YT48L21ldGE-PC9tZXRhPjwvbWV0YT48L21ldGE-PC9tZXRhPjwvbGluaz48L2xpbms-PC9oZWFkPg0KDQo8Ym9keSBiZ2NvbG9yPSIjRTRFNEU0IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojRTRFNEU0OyBtYXJnaW46MDsgcGFkZGluZzowOy13ZWJraXQtZm9udC1zbW9vdGhpbmc6YW50aWFsaWFzZWQ7d2lkdGg6MTAwJSAhaW1wb3J0YW50Ow0KLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0Om5vbmU7IiB0b3BtYXJnaW49IjAiPg0KPGRpdiBzdHlsZT0iZm9udC1zaXplOjFweDsgY29sb3I6I0U0RTRFNDsgZGlzcGxheTpub25lOyBvdmVyZmxvdzpoaWRkZW47IHZpc2liaWxpdHk6aGlkZGVuOyI-UmVjeWNsZSB5b3VyIFBERiBnb2xkIGFuZCByZWR1Y2UgeW91ciB3b3JrbG9hZCB3aXRoIEFjcm9iYXQgUHJvLjwvZGl2Pg0KPHRhYmxlIHdpZHRoPSIxMDAlIiBiZ2NvbG9yPSIjRTRFNEU0IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojRTRFNEU0OyIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiI-DQo8dGJvZHk-DQo8dHI-DQo8dGQ-PHRhYmxlIGNsYXNzPSJmdWxsLXdpZHRoIiBhbGlnbj0iY2VudGVyIiB3aWR0aD0iNjAwIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0id2lkdGg6NjAwcHg7Ij4NCjx0Ym9keT4NCjx0cj4NCjx0ZCBiZ2NvbG9yPSIjZmZmZmZmIiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogI2ZmZmZmZjsiPjwhLS0gUE9EIDEgLS0-DQoNCjx0YWJsZSBjbGFzcz0iZW1haWwtd2lkdGgiIGFsaWduPSJjZW50ZXIiIHdpZHRoPSI1MDAiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHN0eWxlPSJ3aWR0aDo1MDBweDsiPg0KPHRib2R5Pg0KICA8dHI-DQogICAgPHRkIHN0eWxlPSJjb2xvcjojMkMyQzJDO2ZvbnQtZmFtaWx5OmFkb2JlLWNsZWFuLCBIZWx2ZXRpY2EgTmV1ZSwgSGVsdmV0aWNhLCBWZXJkYW5hLCBBcmlhbCwgc2Fucy1zZXJpZjtmb250LXNpemU6MThweDtsaW5lLWhlaWdodDoyNnB4O3BhZGRpbmctdG9wOiA0N3B4O3BhZGRpbmctYm90dG9tOiA0N3B4OyI-PHRhYmxlIGFsaWduPSJsZWZ0IiB3aWR0aD0iYXV0byIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiI-DQogICAgICAgIDx0Ym9keT4NCiAgICAgICAgICA8dHI-DQogICAgICAgICAgICA8dGQgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsgZm9udC1mYW1pbHk6YWRvYmUtY2xlYW4sIEhlbHZldGljYSBOZXVlLCBIZWx2ZXRpY2EsIFZlcmRhbmEsIEFyaWFsLCBzYW5zLXNlcmlmOyANCmZvbnQtc2l6ZToxNHB4OyBsaW5lLWhlaWdodDoyMHB4OyI-PGltZyBhbHQ9IkFkb2JlIEFjcm9iYXQgUHJvIiBzcmM9Imh0dHBzOi8vbGFuZGluZy5hZG9iZS5jb20vZGFtL2dsb2JhbC9pbWFnZXMvbG9ja3Vwcy9hY3JvYmF0LXByby5sb2dvLjc0Nzc3YS40NDR4NDAucG5nIiB3aWR0aD0iMjIyIiBoZWlnaHQ9ImF1dG8iIGJvcmRlcj0iMCIgaHNwYWNlPSIwIiB2c3BhY2U9IjAiIHN0eWxlPSJkaXNwbGF5OmJsb2NrO3ZlcnRpY2FsLWFsaWduOnRvcCIgLz48L3RkPg0KICAgICAgICAgIDwvdHI-DQogICAgICAgIDwvdGJvZHk-DQogICAgICA8L3RhYmxlPjwvdGQ-DQogIDwvdHI-DQogIDx0cj4NCiAgICA8dGQ-PHRhYmxlIGNsYXNzPSJmdWxsLXdpZHRoIiBhbGlnbj0ibGVmdCIgd2lkdGg9IjUwMCIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjUwMHB4OyI-DQogICAgICAgIDx0Ym9keT4NCiAgICAgICAgICA8dHIgc3R5bGU9ImZvbnQtc2l6ZTogMCAhaW1wb3J0YW50OyBsaW5lLWhlaWdodDogMCAhaW1wb3J0YW50OyBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlICFpbXBvcnRhbnQ7Ij4NCiAgICAgICAgICAgIDx0ZCBzdHlsZT0iDQpjb2xvcjogIzAwMDAwMDsNCmZvbnQtZmFtaWx5Og0KYWRvYmUtY2xlYW4sIEhlbHZldGljYSBOZXVlLCBIZWx2ZXRpY2EsIFZlcmRhbmEsIEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6NjBweDsgbGluZS1oZWlnaHQ6NjRweDsNCnBhZGRpbmctdG9wOiAyMHB4Ow0KcGFkZGluZy1yaWdodDogMHB4Ow0KZm9udC13ZWlnaHQ6OTAwOyIgY2xhc3M9ImhlYWRlciI-RG9u4oCZdCByZXR5cGUg4oCUIGNvbnZlcnQuIDwvdGQ-DQogICAgICAgICAgPC90cj4NCiAgICAgICAgPC90Ym9keT4NCiAgICAgIDwvdGFibGU-PC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBzdHlsZT0iDQpjb2xvcjogIzAwMDAwMDsNCmZvbnQtZmFtaWx5Og0KYWRvYmUtY2xlYW4sIEhlbHZldGljYSBOZXVlLCBIZWx2ZXRpY2EsIFZlcmRhbmEsIEFyaWFsLCBzYW5zLXNlcmlmOw0KZm9udC1zaXplOjE4cHg7DQpsaW5lLWhlaWdodDoyNnB4Ow0KcGFkZGluZy10b3A6MjBweDsNCmZvbnQtd2VpZ2h0OiA0MDA7DQoiIGNsYXNzPSJwYWRkaW5nLXIwIj5Eb27igJl0IHN0YXJ0IGZyb20gc2NyYXRjaC4gRWFzaWx5IGV4cG9ydCBQREZzIHRvIE1pY3Jvc29mdCBXb3JkLCBFeGNlbCwgb3IgUG93ZXJQb2ludCB3aXRoIEFkb2JlIEFjcm9iYXQgUHJvLiAgPC90ZD4NCiAgPC90cj4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0iZGFyay1zcGFjZSIgc3R5bGU9Ig0KY29sb3I6IzE0NzNFNjsNCmZvbnQtZmFtaWx5Og0KYWRvYmUtY2xlYW4sIEhlbHZldGljYSBOZXVlLCBIZWx2ZXRpY2EsIFZlcmRhbmEsIEFyaWFsLCBzYW5zLXNlcmlmOw0KZm9udC1zaXplOjE1cHg7DQpsaW5lLWhlaWdodDo0MHB4Ow0KcGFkZGluZy10b3A6IDQwcHg7DQpwYWRkaW5nLWJvdHRvbTogNDBweDsNCiI-PCEtLVtpZiBndGUgbXNvIDldPjx2OnJvdW5kcmVjdA0KeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiDQp4bWxuczp3PSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTp3b3JkIiBzdHlsZT0iaGVpZ2h0OjQwcHg7IHYtdGV4dC1hbmNob3I6bWlkZGxlOyANCndpZHRoOjIwMHB4OyIgYXJjc2l6ZT0iNTAlIiBzdHJva2U9ImYiIGZpbGxjb2xvcj0iIzE0NzNFNiIgc3R5bGU9ImNvbG9yOiNmZmZmZmY7Zm9udC1zaXplOjE2cHg7Zm9udC13ZWlnaHQ6NjAwIj4NCjx2OnRleHRib3ggc3R5bGU9Im1zby1maXQtc2hhcGUtdG8tdGV4dDp0Ij4NCjxjZW50ZXIgc3R5bGU9ImNvbG9yOiNmZmZmZmY7IGZvbnQtZmFtaWx5OmFkb2JlLWNsZWFuLCBIZWx2ZXRpY2EgTmV1ZSwgSGVsdmV0aWNhLCBWZXJkYW5hLCBBcmlhbCwgc2Fucy1zZXJpZjsgZm9udC1zaXplOjE2cHg7Ij48IVtlbmRpZl0tLT4gDQogICAgICA8YSBocmVmPSJodHRwczovL3QtaW5mby5tYWlsLmFkb2JlLmNvbS9yLz9pZD1oZTllZmUyMTgsZmUzZThiZWUsYzAwNTgwZGUmZT1jREU5U0VoS05GZzNNbG8mcz1TSTdGV2M1dkU5QTFkd25PZDRENk9DMFlJY2szY2lsbWlUOHlVY2NNdUI4IiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiNmZmY7bGluZS1oZWlnaHQ6NDBweDt0ZXh0LWFsaWduOmxlZnQiPjxkaXYgY2xhc3M9Im1rdG9UZXh0IiBhbGlnbj0ibGVmdCIgaWQ9IkFETzEwODcxLWUiIHN0eWxlPSJmb250LWZhbWlseTphZG9iZS1jbGVhbixIZWx2ZXRpY2EsQXJpYWwsc2Fucy1zZXJpZjtmb250LXNpemU6MTZweDtmb250LXdlaWdodDo3MDA7YmFja2dyb3VuZC1jb2xvcjojMTQ3M2U2O2JvcmRlci1yYWRpdXM6NTBweDt3aWR0aDoyMDBweDt0ZXh0LWFsaWduOmNlbnRlcjtjb2xvcjojZmZmO2xpbmUtaGVpZ2h0OjQwcHgiPjxzdHJvbmc-R2V0IHN0YXJ0ZWQ8L3N0cm9uZz48L2Rpdj4NCiAgICAgIDwvYT4gDQogICAgICA8IS0tW2lmIGd0ZSBtc28gOV0-PC9jZW50ZXI-DQo8cCBzdHlsZT0ibWFyZ2luOjA7IGZvbnQtc2l6ZTowOyBsaW5lLWhlaWdodDowOyI-DQo8bzpwDQp4bWxuczpvPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOm9mZmljZTpvZmZpY2UiPiANCjwvbzpwPg0KPC9wPg0KPC92OnRleHRib3g-DQo8L3Y6cm91bmRyZWN0PjwhW2VuZGlmXS0tPjwvdGQ-DQogIDwvdHI-DQo8L3Rib2R5Pg0KPC90YWJsZT48L3RkPg0KPC90cj4NCjx0cj4NCjx0ZCBiZ2NvbG9yPSIjRkFEQTNBIiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogI0ZBREEzQTsiPjwhLS0gUE9EIDEgLS0-IA0KDQo8IS0tIHBvZDEgbWFycXVlZSAtLT4NCg0KPHRhYmxlIGNsYXNzPSJmdWxsLXdpZHRoIiBhbGlnbj0iY2VudGVyIiB3aWR0aD0iNjAwIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0id2lkdGg6NjAwcHg7Ij4NCjx0Ym9keT4NCiAgPHRyPg0KICAgIDx0ZCBiZ2NvbG9yPSIjZmZmZmZmIiBzdHlsZT0iY29sb3I6IzAwMDAwMDtmb250LWZhbWlseTphZG9iZS1jbGVhbiwgSGVsdmV0aWNhIE5ldWUsIEhlbHZldGljYSwgVmVyZGFuYSwgQXJpYWwsIHNhbnMtc2VyaWY7Zm9udC1zaXplOjIycHg7bGluZS1oZWlnaHQ6MjhweDtiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmZmZmOyI-PGEgaHJlZj0iaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9aGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MGRmJmU9Y0RFOVNFaEtORmczTWxvJnM9a1FRWXAzaE1qNkNKLUtmazM1bzVGNndQZ2kxZ2dueFAwMHd2WGdrb1NYYyIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgY2xhc3M9Im1vYmlsZS1pbWFnZSIgYWx0PSJEb27igJl0IHJldHlwZSDigJQgY29udmVydC4iIHNyYz0iaHR0cHM6Ly9sYW5kaW5nLmFkb2JlLmNvbS9jb250ZW50L2RhbS9sYW5kaW5nL3VwbG9hZHMvMjAyNC9lbWVhL2Fzc2V0cy9pbWFnZXMvbWFycXVlZS82NzMyNGE2NjAwMTBiNDcxYjBjMjZmYTM2ZjM4MzhjMF9hcGFjX2VuX2Fjcm9iYXRfY29udmVyc2lvbl9kZXNrdG9wXzJ4LmpwZyIgc3Jjc2V0PSJodHRwczovL2xhbmRpbmcuYWRvYmUuY29tL2NvbnRlbnQvZGFtL2xhbmRpbmcvdXBsb2Fkcy8yMDI0L2VtZWEvYXNzZXRzL2ltYWdlcy9tYXJxdWVlLzY3MzI0YTY2MDAxMGI0NzFiMGMyNmZhMzZmMzgzOGMwX2FwYWNfZW5fYWNyb2JhdF9jb252ZXJzaW9uX21vYmlsZV8yeC5qcGcgNjIxdywNCmh0dHBzOi8vbGFuZGluZy5hZG9iZS5jb20vY29udGVudC9kYW0vbGFuZGluZy91cGxvYWRzLzIwMjQvZW1lYS9hc3NldHMvaW1hZ2VzL21hcnF1ZWUvNjczMjRhNjYwMDEwYjQ3MWIwYzI2ZmEzNmYzODM4YzBfYXBhY19lbl9hY3JvYmF0X2NvbnZlcnNpb25fZGVza3RvcF8yeC5qcGcgMTIwMHciIHNpemVzPSIobWF4LXdpZHRoOiA0ODBweCkgNTB2dyIgd2lkdGg9IjYwMCIgaGVpZ2h0PSJhdXRvIiBib3JkZXI9IjAiIGhzcGFjZT0iMCIgdnNwYWNlPSIwIiBzdHlsZT0iY29sb3I6IzAwMDAwMDsgZm9udC1mYW1pbHk6YWRvYmUtY2xlYW4sIEhlbHZldGljYSBOZXVlLCBIZWx2ZXRpY2EsIFZlcmRhbmEsIEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6MjJweDsgbGluZS1oZWlnaHQ6MjhweDsgZGlzcGxheTpibG9jazsgdmVydGljYWwtYWxpZ246dG9wOyIgLz48L2E-PC90ZD4NCiAgPC90cj4NCjwvdGJvZHk-DQo8L3RhYmxlPg0KDQo8IS0tIEVORCBwb2QxIG1hcnF1ZWUgLS0-IA0KPCEtLSBFTkQgcG9kMSAtLT48L3RkPg0KPC90cj4NCjwhLS0gUE9EIDIgLS0-IA0KDQo8IS0tIFBPRCAyIEVORFMgLS0-DQoNCjx0cj4NCjx0ZCBiZ2NvbG9yPSIjRjVGNUY1IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojRjVGNUY1Ij48dGFibGUgY2xhc3M9ImVtYWlsLXdpZHRoIiBhbGlnbj0iY2VudGVyIiB3aWR0aD0iNTAwIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0id2lkdGg6NTAwcHgiPg0KPHRib2R5Pg0KICA8dHI-DQogICAgPHRkIHZhbGlnbj0idG9wIiBzdHlsZT0icGFkZGluZy10b3A6NTBweCI-PHRhYmxlIGNsYXNzPSJmdWxsLXdpZHRoIiBhbGlnbj0ibGVmdCIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgd2lkdGg9IjUwMCIgc3R5bGU9IndpZHRoOjUwMHB4Ij4NCiAgICAgICAgPHRib2R5Pg0KICAgICAgICAgIDx0cj4NCiAgICAgICAgICAgIDx0ZCB2YWxpZ249InRvcCIgc3R5bGU9ImNvbG9yOiNFQjEwMDA7Zm9udC1mYW1pbHk6YWRvYmUtY2xlYW4sSGVsdmV0aWNhIE5ldWUsSGVsdmV0aWNhLFZlcmRhbmEsQXJpYWwsc2Fucy1zZXJpZjtmb250LXNpemU6MTJweDtsaW5lLWhlaWdodDoxOHB4O3BhZGRpbmctYm90dG9tOjAiIGNsYXNzPSJibG9jayBwYWRiLTUwIj48aW1nIGFsdD0iQWRvYmUiIHNyYz0iaHR0cHM6Ly9sYW5kaW5nLmFkb2JlLmNvbS9jb250ZW50L2RhbS9sYW5kaW5nL3VwbG9hZHMvMjAyMy9lbWVhL2Fzc2V0cy9pbWFnZXMvbWFycXVlZS82NTI4ZTA2OTAwMGM0MGUyYzQ0MzQ2ZDJkNzI2NTg2Ml9hZG9iZV9sb2dvXzJ4LnBuZyIgd2lkdGg9IjgwIiBoZWlnaHQ9ImF1dG8iIGJvcmRlcj0iMCIgaHNwYWNlPSIwIiB2c3BhY2U9IjAiIHN0eWxlPSJjb2xvcjojRUIxMDAwO2ZvbnQtZmFtaWx5OmFkb2JlLWNsZWFuLEhlbHZldGljYSBOZXVlLEhlbHZldGljYSxWZXJkYW5hLEFyaWFsLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHg7bGluZS1oZWlnaHQ6MThweDtkaXNwbGF5OmJsb2NrO3ZlcnRpY2FsLWFsaWduOnRvcCIgLz48L3RkPg0KICAgICAgICAgICAgPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0icmlnaHQiIHN0eWxlPSJjb2xvcjojRUIxMDAwO2ZvbnQtZmFtaWx5OmFkb2JlLWNsZWFuLEhlbHZldGljYSBOZXVlLEhlbHZldGljYSxWZXJkYW5hLEFyaWFsLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHg7bGluZS1oZWlnaHQ6MThweDtwYWRkaW5nLWJvdHRvbTowO3RleHQtYWxpZ246cmlnaHQ7cGFkZGluZy1sZWZ0OjE4MHB4IiBjbGFzcz0iYmxvY2siPg0KICAgICAgICAgICAgICA8dGFibGUgY2xhc3M9InNvY2lhbCIgYWxpZ249InJpZ2h0IiB3aWR0aD0iYXV0byIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9ImZsb2F0OnJpZ2h0Ij4NCiAgICAgICAgICAgIDx0Ym9keT4NCiAgICAgICAgICAgICAgPHRyPg0KICAgICAgICAgICAgICAgIDx0ZCBzdHlsZT0iY29sb3I6Izk1OTU5NTtmb250LWZhbWlseTphZG9iZS1jbGVhbixIZWx2ZXRpY2EgTmV1ZSxIZWx2ZXRpY2EsVmVyZGFuYSxBcmlhbCxzYW5zLXNlcmlmO2ZvbnQtc2l6ZToxMnB4O2xpbmUtaGVpZ2h0OjIxcHg7cGFkZGluZy1ib3R0b206NDBweCI-PGEgaHJlZj0iaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9aGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MGUwIiBhbGlhcz0iRmFjZWJvb2siIHRhcmdldD0iX2JsYW5rIj48aW1nIGFsdD0iRmFjZWJvb2siIHNyYz0iaHR0cHM6Ly9sYW5kaW5nLmFkb2JlLmNvbS9kYW0vZ2xvYmFsL2ltYWdlcy9zb2NpYWwvZmFjZWJvb2suOTU5NTk1LnBuZyIgd2lkdGg9IjkiIGhlaWdodD0iYXV0byIgYm9yZGVyPSIwIiBoc3BhY2U9IjAiIHZzcGFjZT0iMCIgc3R5bGU9ImRpc3BsYXk6YmxvY2s7dmVydGljYWwtYWxpZ246dG9wIj4gPC9pbWc-PC9hPjwvdGQ-DQogICAgICAgICAgICAgICAgPHRkIHdpZHRoPSIzNiIgc3R5bGU9IndpZHRoOjM2cHgiPjwvdGQ-DQogICAgICAgICAgICAgICAgPHRkIHN0eWxlPSJjb2xvcjojOTU5NTk1O2ZvbnQtZmFtaWx5OmFkb2JlLWNsZWFuLEhlbHZldGljYSBOZXVlLEhlbHZldGljYSxWZXJkYW5hLEFyaWFsLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHg7bGluZS1oZWlnaHQ6MjFweDtwYWRkaW5nLWJvdHRvbTo0MHB4Ij48YSBocmVmPSJodHRwczovL3QtaW5mby5tYWlsLmFkb2JlLmNvbS9yLz9pZD1oZTllZmUyMTgsZmUzZThiZWUsYzAwNTgwZTEiIGFsaWFzPSJMaW5rZWRJbiIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgYWx0PSJMaW5rZWRJbiIgc3JjPSJodHRwczovL2xhbmRpbmcuYWRvYmUuY29tL2RhbS9nbG9iYWwvaW1hZ2VzL3NvY2lhbC9saW5rZWRpbi45NTk1OTUucG5nIiB3aWR0aD0iMTgiIGhlaWdodD0iYXV0byIgYm9yZGVyPSIwIiBoc3BhY2U9IjAiIHZzcGFjZT0iMCIgc3R5bGU9ImRpc3BsYXk6YmxvY2s7dmVydGljYWwtYWxpZ246dG9wIj4gPC9pbWc-PC9hPjwvdGQ-DQogICAgPHRkIHdpZHRoPSIzNiIgc3R5bGU9IndpZHRoOjM2cHgiPjwvdGQ-DQogICAgICAgICAgICAgICAgPHRkIHN0eWxlPSJjb2xvcjojOTU5NTk1O2ZvbnQtZmFtaWx5OmFkb2JlLWNsZWFuLEhlbHZldGljYSBOZXVlLEhlbHZldGljYSxWZXJkYW5hLEFyaWFsLHNhbnMtc2VyaWY7Zm9udC1zaXplOjEycHg7bGluZS1oZWlnaHQ6MjFweDtwYWRkaW5nLWJvdHRvbTo0MHB4O3BhZGRpbmctcmlnaHQ6MTBweCI-PGEgaHJlZj0iaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9aGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MGUyIiBhbGlhcz0iVHdpdHRlciIgdGFyZ2V0PSJfYmxhbmsiPjxpbWcgYWx0PSJUd2l0dGVyIiBzcmM9Imh0dHBzOi8vbGFuZGluZy5hZG9iZS5jb20vZGFtL2dsb2JhbC9pbWFnZXMvc29jaWFsL3R3aXR0ZXIuOTU5NTk1LnBuZyIgd2lkdGg9IjE3IiBoZWlnaHQ9ImF1dG8iIGJvcmRlcj0iMCIgaHNwYWNlPSIwIiB2c3BhY2U9IjAiIHN0eWxlPSJkaXNwbGF5OmJsb2NrO3ZlcnRpY2FsLWFsaWduOnRvcCI-IDwvaW1nPjwvYT48L3RkPiAgICAgICAgICAgIA0KIDx0ZCB3aWR0aD0iMTAiIHN0eWxlPSJ3aWR0aDoxMHB4Ij48L3RkPiAgICAgICAgICAgICA8L3RyPg0KICAgICAgICAgICAgPC90Ym9keT4NCiAgICAgICAgICA8L3RhYmxlPjwvdGQ-DQogICAgICAgICAgPC90cj4NCiAgICAgICAgPC90Ym9keT4NCiAgICAgIDwvdGFibGU-PC90ZD4NCiAgPC90cj4NCjwvdGJvZHk-DQo8L3RhYmxlPg0KPHRhYmxlIGNsYXNzPSJlbWFpbC13aWR0aCIgYWxpZ249ImNlbnRlciIgd2lkdGg9IjUwMCIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjUwMHB4Ij4NCjx0Ym9keT4NCiAgPHRyPg0KICAgIDx0ZCBjbGFzcz0ibGVnYWwiIHN0eWxlPSJjb2xvcjojOTU5NTk1O2ZvbnQtZmFtaWx5OmFkb2JlLWNsZWFuLEhlbHZldGljYSBOZXVlLEhlbHZldGljYSxWZXJkYW5hLEFyaWFsLHNhbnMtc2VyaWY7Zm9udC1zaXplOjExcHg7bGluZS1oZWlnaHQ6MThweDtwYWRkaW5nLXRvcDowO3BhZGRpbmctYm90dG9tOjEwMHB4Ij5BZG9iZSBzZXJ2aWNlcywgbGlrZSBBZG9iZSBEb2N1bWVudCBDbG91ZCwgYXJlIGF2YWlsYWJsZSBvbmx5IHRvIHVzZXJzIDEzIGFuZCBvbGRlci4gVXNlIG9mIEFkb2JlIHNlcnZpY2VzIGFuZCBhcHBsaWNhdGlvbnMgcmVxdWlyZXMgYWdyZWVtZW50IHdpdGggdGhlIGFwcGxpY2FibGUgPGEgaHJlZj0iaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9aGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MGUzIiBhbGlhcz0iRk9PVEVSIC0gVGVybXMiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6Izk1OTU5NTsgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmUiPlRlcm1zIG9mIFVzZTwvYT4gYW5kIHRoZSA8YSBocmVmPSJodHRwczovL3QtaW5mby5tYWlsLmFkb2JlLmNvbS9yLz9pZD1oZTllZmUyMTgsZmUzZThiZWUsYzAwNTgwZTYiIGFsaWFzPSJGT09URVIgLSBQcml2YWN5IFBvbGljeSIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxlPSJjb2xvcjojOTU5NTk1O3RleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lIj5BZG9iZSBQcml2YWN5IFBvbGljeTwvYT4uDQogICAgICA8cCBpZD0icmVnX2Zvb3QiPkFkb2JlLCB0aGUgQWRvYmUgbG9nbywgQ3JlYXRpdmUgQ2xvdWQsIHRoZSBDcmVhdGl2ZSBDbG91ZCBsb2dvLCBhbmQgRG9jdW1lbnQgQ2xvdWQgYXJlIGVpdGhlciByZWdpc3RlcmVkIHRyYWRlbWFya3Mgb3IgdHJhZGVtYXJrcyBvZiBBZG9iZSBpbiB0aGUgVW5pdGVkIFN0YXRlcyBhbmQvb3Igb3RoZXIgY291bnRyaWVzLjxiciAvPjxiciAvPg0KICBUaGlzIGlzIG5vdCBhIGNvbXByZWhlbnNpdmUgbGlzdCBvZiBhbGwgQWRvYmUgdHJhZGVtYXJrcy4gRm9yIGEgZnVsbCBsaXN0LCByZWZlciB0byB0aGUgPGEgaHJlZj0iaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9aGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MGU0IiBhbGlhcz0iRk9PVEVSIC0gVHJhZGVtYXJrIEd1aWRlbGluZXMiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6Izk1OTU5NTsiPkFkb2JlIFRyYWRlbWFyayBHdWlkZWxpbmVzPC9hPi4gQWxsIG90aGVyIHRyYWRlbWFya3MgYXJlIHRoZSBwcm9wZXJ0eSBvZiB0aGVpciByZXNwZWN0aXZlIG93bmVycy48YnIgLz48YnIgLz4NCiAgVGhpcyBpcyBhIG1hcmtldGluZyBlbWFpbCBmcm9tIEFkb2JlIFN5c3RlbXMgU29mdHdhcmUgSXJlbGFuZCBMaW1pdGVkLCA04oCRNiZuYnNwO1JpdmVyd2FsaywgQ2l0eXdlc3QgQnVzaW5lc3MgUGFyaywgRHVibGluJm5ic3A7MjQsIElyZWxhbmQuDQogICA8YSBzdHlsZT0iVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmU7IENPTE9SOiAjYTFhMWExIiBocmVmPSJodHRwczovL3QtaW5mby5tYWlsLmFkb2JlLmNvbS9yLz9pZD1oZTllZmUyMTgsZmUzZThiZWUsYzAwNTgwZTUmZT1jREU5SlRRd1QxYzBjbkk0VTBkak5qSk9UVVZWYlhkaFNUSlNkSE5rVVdsbGNFeDVNVWRtVGtRbE1rWnVTbFpuVjFoSkpUTkVKbkF5UFNac2IyTTlhVzRtY0RNOU1UayZzPVYzMThHRXRzWDg1blR3N0l6eVlPNEtQS2FwaGVUVGQ5eDlpMzJPUTN3SmMiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0ib3B0X291dCIgYWxpYXM9IlVuc3Vic2NyaWJlIiBfdHlwZT0ib3B0b3V0IiBfbGFiZWw9Ik9wdC1vdXQgbGluayI-Q2xpY2smbmJzcDtoZXJlPC9BPiAgdG8gdW5zdWJzY3JpYmUuIFBsZWFzZSByZXZpZXcgdGhlIDxhIGhyZWY9Imh0dHBzOi8vdC1pbmZvLm1haWwuYWRvYmUuY29tL3IvP2lkPWhlOWVmZTIxOCxmZTNlOGJlZSxjMDA1ODBlNyIgYWxpYXM9IkZPT1RFUiAtIFByaXZhY3kiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6Izk1OTU5NTsiPkFkb2JlIFByaXZhY3kgUG9saWN5PC9hPi48YnIgLz48YnIgLz4NCiAgVG8gZW5zdXJlIGVtYWlsIGRlbGl2ZXJ5LCBhZGQgPGEgaHJlZj0iaHR0cHM6Ly90LWluZm8ubWFpbC5hZG9iZS5jb20vci8_aWQ9aGU5ZWZlMjE4LGZlM2U4YmVlLGMwMDU4MGU4IiBhbGlhcz0iQWRkIHRvIGFkZHJlc3MgYm9vayAtIG1haWxAbWFpbC5hZG9iZS5jb20iIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6Izk1OTU5NTsiPm1haWxAbWFpbC5hZG9iZS5jb208L2E-IHRvIHlvdXIgYWRkcmVzcyBib29rLCBjb250YWN0cywgb3Igc2FmZSBzZW5kZXImbmJzcDtsaXN0LjxiciAvPjxiciAvPjwvcD4gPHNwYW4-DQogICAgICANCiAgICAgIDxhIGhyZWY9Imh0dHBzOi8vdC1pbmZvLm1haWwuYWRvYmUuY29tL3IvP2lkPWhlOWVmZTIxOCxmZTNlOGJlZSxjMDA1ODBlOSZlPWNERTlKVFF3YmxkelEyUndSRkk0VVRsTGRsTnVZVzVESlRKR2JuUnJVVU5hY0ZsellqTlpSa3RSZGtGUmRXNWpNelZqSlRORSZzPWlQdmMzX0pvbGdyY2RmUTJiZFRpOEcwQTVSaXp1N3YydEo1MkdVTl8xd00iIF9sYWJlbD0iTWlycm9yIFBhZ2UiIF90eXBlPSJtaXJyb3JQYWdlIiBhbGlhcz0iUmVhZCBvbmxpbmUiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6Izk1OTU5NTt0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lIj5SZWFkIG9ubGluZTwvYT4NCiAgICAgIA0KICAgICAgPC9zcGFuPjwvdGQ-DQogIDwvdHI-DQo8L3Rib2R5Pg0KPC90YWJsZT48L3RkPg0KPC90cj4NCjwvdGJvZHk-DQo8L3RhYmxlPjwvdGQ-DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU-DQo8L2JvZHk-DQo8L2h0bWw-DQo8aW1nIGhlaWdodD0nMCcgd2lkdGg9JzAnIGFsdD0nJyBzcmM9J2h0dHBzOi8vdC1pbmZvLm1haWwuYWRvYmUuY29tL3IvP2lkPWhlOWVmZTIxOCxmZTNlOGJlZSwxJy8-PGltZyBoZWlnaHQ9JzAnIHdpZHRoPScwJyBhbHQ9Jycgc3JjPSdodHRwczovL2Fkb2JlLmRlbWRleC5uZXQvZXZlbnQ_Y19zeW5jcGxhY2VtZW50PWVtYWlsJmRfY2lkPTgxMyUwMTFGQ0Y2OUVCNjE1NUExRjAwQTQ5NUNCNCcvPg0K" - } - } - ] - }, - "sizeEstimate": 23490, - "historyId": "526904", - "internalDate": "1732487083000" -} \ No newline at end of file diff --git a/utils_v2/goog/gmail/json/messages/raw_message_10_1935e92672e67f22_20241126.json b/utils_v2/goog/gmail/json/messages/raw_message_10_1935e92672e67f22_20241126.json deleted file mode 100644 index 4adaa68..0000000 --- a/utils_v2/goog/gmail/json/messages/raw_message_10_1935e92672e67f22_20241126.json +++ /dev/null @@ -1,183 +0,0 @@ -{ - "id": "1935e92672e67f22", - "threadId": "1935e92672e67f22", - "labelIds": [ - "UNREAD", - "CATEGORY_SOCIAL", - "INBOX" - ], - "snippet": "Here's what's happened since you were last on LinkedIn \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f \u034f", - "payload": { - "partId": "", - "mimeType": "multipart/alternative", - "filename": "", - "headers": [ - { - "name": "Delivered-To", - "value": "pskhushal@gmail.com" - }, - { - "name": "Received", - "value": "by 2002:a5d:4205:0:b0:382:44a8:2102 with SMTP id n5csp489491wrq; Sun, 24 Nov 2024 06:27:53 -0800 (PST)" - }, - { - "name": "X-Google-Smtp-Source", - "value": "AGHT+IEcS3t6I5EYTeXutTWCaj0fEAX/BFkSa6Xaw/nMo6+pyLJJtvz7S/MBZv44qMdTc6JVxq+f" - }, - { - "name": "X-Received", - "value": "by 2002:a05:6602:13c8:b0:83e:6232:11a with SMTP id ca18e2360f4ac-83ecdcaa81emr914357339f.7.1732458473211; Sun, 24 Nov 2024 06:27:53 -0800 (PST)" - }, - { - "name": "ARC-Seal", - "value": "i=1; a=rsa-sha256; t=1732458473; cv=none; d=google.com; s=arc-20240605; b=hrGVGOdrsnWXBSb3+YUlgbJwXMCirSm5AHNJ8GbUwyw7Bz6C2fOxPZw1GlXVDn0okR OXBflsE0WgRxGsJTDGO56d9MDdZRW1VTE+O3bquEXcbN1D19PrxCGxNa4rFZIlVhpGqz WqCvyOK3NlpyyILFmKYAQWjBRY/OOlDC9AlDshnhzDB5Vg1AoDlywRK/peISQ/OPbnwt klOd3kzKIRKsQNDB6CqVG0Ag7EhAZHGYTvc2HmiuPg9FPOePJTWXJ1h2zJKGTAR+Ouzi SA8IWMA7MknUNK/8RMRYowg967Y3kub0ABo89lyuUZMeZRCsWchxvKDcBmR8Z4o1W29V irKQ==" - }, - { - "name": "ARC-Message-Signature", - "value": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=require-recipient-valid-since:feedback-id:list-unsubscribe-post :list-unsubscribe:date:to:mime-version:subject:message-id:from :dkim-signature:dkim-signature; bh=nySe/MiYyd+StYNNKhFQvs+nBTs6HguWRtf5H+LonXg=; fh=kl8GOc3xH49wmCQ5W74DCe5pDhPNnAeFoI4mGP4/wX4=; b=MOuaP5zl+0G9/BbA/whMa6POlvCfiPyZFMqwLKvGoiOB8nBXoMnqdomtKf/QzkWDBg sTFkP+4nEfEbokkWOWwgee+e+5lDg/BDJPkS/Pwfm5jkzCxxOVSAJbsd5Ad7zS9hcowa BnZE/5W5Z7FfdQh+zZbRMRNA8Mmv/U7tBT1a0fNtm1LmKAb2QMIJtRXfwbLu+XNjCXHY p2lPn6YM+mnGmcFvW4QpTZERJ2GHEVZdPXZpf7SW5qkUFEQGOKlrSaoZHS+xAuC5hoV3 kn9lAQ8YaRKk3tgtCjDGr0d5lR9k5YQA6stK2iJS0xqVfn7xlIe2OYdiL3KtpxExoIni yDaQ==; dara=google.com" - }, - { - "name": "ARC-Authentication-Results", - "value": "i=1; mx.google.com; dkim=pass header.i=@mailc.linkedin.com header.s=d2048-202308-0c header.b=Adk2r7bx; dkim=pass header.i=@linkedin.com header.s=d2048-202308-00 header.b=M94Hf2OM; spf=pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo17qlc4r172gpk4@bounce.linkedin.com designates 108.174.3.172 as permitted sender) smtp.mailfrom=m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo17qlc4r172gpk4@bounce.linkedin.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=linkedin.com" - }, - { - "name": "Return-Path", - "value": "" - }, - { - "name": "Received", - "value": "from mailc-bd.linkedin.com (mailc-bd.linkedin.com. [108.174.3.172]) by mx.google.com with ESMTPS id ca18e2360f4ac-83ecd39e071si357074239f.47.2024.11.24.06.27.52 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 24 Nov 2024 06:27:53 -0800 (PST)" - }, - { - "name": "Received-SPF", - "value": "pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo17qlc4r172gpk4@bounce.linkedin.com designates 108.174.3.172 as permitted sender) client-ip=108.174.3.172;" - }, - { - "name": "Authentication-Results", - "value": "mx.google.com; dkim=pass header.i=@mailc.linkedin.com header.s=d2048-202308-0c header.b=Adk2r7bx; dkim=pass header.i=@linkedin.com header.s=d2048-202308-00 header.b=M94Hf2OM; spf=pass (google.com: domain of m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo17qlc4r172gpk4@bounce.linkedin.com designates 108.174.3.172 as permitted sender) smtp.mailfrom=m-7rn15dcklyh67ma8mwwua3ozups21yzaxmcrqxdlmxexo17qlc4r172gpk4@bounce.linkedin.com; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=linkedin.com" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=mailc.linkedin.com; s=d2048-202308-0c; t=1732458470; bh=nySe/MiYyd+StYNNKhFQvs+nBTs6HguWRtf5H+LonXg=; h=From:Subject:MIME-Version:Content-Type:To:Date:X-LinkedIn-Class:\t X-LinkedIn-Template:X-LinkedIn-fbl; b=Adk2r7bx1vZ9JpUoh2QYgUmH2WTHWP8wXudTdb0M060/7XwbzuiqBRKyhy6zEyWkq\t AlFD7cTp2ya5xg8Ouev9TmtYownVpWgqyGvYkRBqkHczCA49ozHxHUo5qrfgU8DKI0\t V2fZkhgIM/AEiZERzuSvhUnBRo7nBWBjQg1vTl7kk5NMphCn1sxCq1qIyLUDLDp60D\t DPVmFR75bri3sECOzbu1K/EZnspoLLV/spGKLgb9S/FVzJMRmi2oRi0l8uz0jH8fBo\t 17VWd6k3rTpFeGVNPrSK3lWdOSDf2i2QQA5oK37vxvczzz/SDWZnx1LTHVInRjLlJm\t nEf8cH5ewVn+A==" - }, - { - "name": "DKIM-Signature", - "value": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linkedin.com; s=d2048-202308-00; t=1732458470; bh=nySe/MiYyd+StYNNKhFQvs+nBTs6HguWRtf5H+LonXg=; h=From:Subject:MIME-Version:Content-Type:To:Date:X-LinkedIn-Class:\t X-LinkedIn-Template:X-LinkedIn-fbl; b=M94Hf2OMaPkAxHXA/zOhOXLZzzHQVibZfX4W1pWVaf+eoUen1hl1rvFQWA0YEjIzz\t 9Xv+x9YT0Z5+yRma/Sq9Ys/Mh8AZi/a4UI4439oLy8RP1IXiMqr8idcWVJzhMJboi1\t VsaVxftwyt79bfN6E9DGKYGObpulcq/LYFzY64usl1/VXJg6bySmaHaFtoFDVLXqe0\t o8rQXswkdDJHZtoMur05q1Fal4PXbnGe6G7f/Roq7WALaPXldYeiyvPyGmkABQItTA\t w3MEAf7iDcTptv3SOY2vmAjX4Tq7lbG66eO/stqeTaR3fSgx5gqYC1sk9rjd4Ua5bQ\t FRtdrqLGbTcJw==" - }, - { - "name": "From", - "value": "LinkedIn " - }, - { - "name": "Message-ID", - "value": "<936622671.17289057.1732458470082@lor1-app81838.prod.linkedin.com>" - }, - { - "name": "Subject", - "value": "Using AI at work? Take note of these\u2026" - }, - { - "name": "MIME-Version", - "value": "1.0" - }, - { - "name": "Content-Type", - "value": "multipart/alternative; boundary=\"----=_Part_17289055_909100289.1732458470080\"" - }, - { - "name": "To", - "value": "Khushal PS " - }, - { - "name": "Date", - "value": "Sun, 24 Nov 2024 14:27:50 +0000 (UTC)" - }, - { - "name": "X-LinkedIn-Class", - "value": "NETWORKDIGEST" - }, - { - "name": "X-LinkedIn-Template", - "value": "email_notification_digest_01" - }, - { - "name": "X-LinkedIn-fbl", - "value": "m2-aszz463uxzxisdhpefpvpzxet5cq38t8k08yi4636s5ds5vlxlpz3fpxz5rw4m9h9czfj84szwhzrzycmbllc5jq2ky0sgxcabi7n6" - }, - { - "name": "X-LinkedIn-Id", - "value": "j7zu7i-m3voz2l3-sd" - }, - { - "name": "List-Unsubscribe", - "value": "" - }, - { - "name": "List-Unsubscribe-Post", - "value": "List-Unsubscribe=One-Click" - }, - { - "name": "Feedback-ID", - "value": "email_notification_digest_01:linkedin" - }, - { - "name": "Require-Recipient-Valid-Since", - "value": "pskhushal@gmail.com; Mon, 24 Jul 2023 06:55:23 +0000" - } - ], - "body": { - "size": 0 - }, - "parts": [ - { - "partId": "0", - "mimeType": "text/plain", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/plain;charset=UTF-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - }, - { - "name": "Content-ID", - "value": "text-body" - } - ], - "body": { - "size": 2660, - "data": "VXNpbmcgQUkgYXQgd29yaz8gVGFrZSBub3RlIG9mIHRoZXNlIGlzc3Vlcy4NClNlZSBuZXdzbGV0dGVyOmh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvbmV3cy82MjE3MjIwP2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyRk1MJTJCTXJrQVJkeVBzJTJGZlZOSG1NNnclM0QlM0QmbWlkVG9rZW49QVFGUGEyM056bzE4RlEmbWlkU2lnPTFPUXN1S3hSQjNCSHcxJnRyaz1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1ub3RpZmljYXRpb25fZGlnZXN0LTAtRURJVE9SSUFMX0JMQVpFX0lOQVBQJnRya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLW5vdGlmaWNhdGlvbl9kaWdlc3QtMC1FRElUT1JJQUxfQkxBWkVfSU5BUFAtbnVsbC1qN3p1N2l-bTN2b3oybDN-c2QtbnVsbC1udWxsJmVpZD1qN3p1N2ktbTN2b3oybDMtc2Qmb3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqQTRZV00yWkRRME56a3dZV1E0T1RaaE4ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TVRabU1XUmhaREkzT0dZeVpqZGlNVGRqTXpVNFptTmpZVE0yTmpKaE1HUXlOekF5TkRJeFkySXdOakUyWW1Ka0xERXNNUSUzRCUzRA0KDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KVGhpcyBlbWFpbCB3YXMgaW50ZW5kZWQgZm9yIEtodXNoYWwgUFMgKC0tKQ0KTGVhcm4gd2h5IHdlIGluY2x1ZGVkIHRoaXM6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9oZWxwL2xpbmtlZGluL2Fuc3dlci80Nzg4P2xhbmc9ZW4mbGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxJTNCJTJGTUwlMkJNcmtBUmR5UHMlMkZmVk5IbU02dyUzRCUzRCZtaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZtaWRTaWc9MU9Rc3VLeFJCM0JIdzEmdHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLVNlY3VyaXR5SGVscC0wLXRleHRmb290ZXJnbGltbWVyJnRya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLVNlY3VyaXR5SGVscC0wLXRleHRmb290ZXJnbGltbWVyLW51bGwtajd6dTdpfm0zdm96MmwzfnNkLW51bGwtbnVsbCZlaWQ9ajd6dTdpLW0zdm96MmwzLXNkJm90cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakE0WVdNMlpEUTBOemt3WVdRNE9UWmhOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU1UWm1NV1JoWkRJM09HWXlaamRpTVRkak16VTRabU5qWVRNMk5qSmhNR1F5TnpBeU5ESXhZMkl3TmpFMlltSmtMREVzTVElM0QlM0QNCllvdSBhcmUgcmVjZWl2aW5nIExpbmtlZEluIG5vdGlmaWNhdGlvbiBlbWFpbHMuDQoNClVuc3Vic2NyaWJlOiBodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9wc2V0dGluZ3MvZW1haWwtdW5zdWJzY3JpYmU_bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxJTNCJTJGTUwlMkJNcmtBUmR5UHMlMkZmVk5IbU02dyUzRCUzRCZtaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZtaWRTaWc9MU9Rc3VLeFJCM0JIdzEmdHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLXVuc3Vic2NyaWJlLTAtdGV4dGZvb3RlcmdsaW1tZXImdHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtdW5zdWJzY3JpYmUtMC10ZXh0Zm9vdGVyZ2xpbW1lci1udWxsLWo3enU3aX5tM3ZvejJsM35zZC1udWxsLW51bGwmZWlkPWo3enU3aS1tM3ZvejJsMy1zZCZsb2lkPUFRRzdEcE1jQm1KQmVnQUFBWk5la2xmZHk1UmlsbVhRUzBMWkx5UUZjZGhNU1E4emR3V1I3b0NaUUU4YzZkNjRMbmRxZFFUZXZMb3RERFByallETUVLeTZMMkZwSjNxcTB1U2ctblkNCkhlbHA6IGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9oZWxwL2xpbmtlZGluL2Fuc3dlci82Nz9sYW5nPWVuJmxpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyRk1MJTJCTXJrQVJkeVBzJTJGZlZOSG1NNnclM0QlM0QmbWlkVG9rZW49QVFGUGEyM056bzE4RlEmbWlkU2lnPTFPUXN1S3hSQjNCSHcxJnRyaz1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1oZWxwLTAtdGV4dGZvb3RlcmdsaW1tZXImdHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVscC0wLXRleHRmb290ZXJnbGltbWVyLW51bGwtajd6dTdpfm0zdm96MmwzfnNkLW51bGwtbnVsbCZlaWQ9ajd6dTdpLW0zdm96MmwzLXNkJm90cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakE0WVdNMlpEUTBOemt3WVdRNE9UWmhOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU1UWm1NV1JoWkRJM09HWXlaamRpTVRkak16VTRabU5qWVRNMk5qSmhNR1F5TnpBeU5ESXhZMkl3TmpFMlltSmtMREVzTVElM0QlM0QNCg0KwqkgMjAyNCBMaW5rZWRJbiBDb3Jwb3JhdGlvbiwgMXp3bmowMDAgV2VzdCBNYXVkZSBBdmVudWUsIFN1bm55dmFsZSwgQ0EgOTQwODUuDQpMaW5rZWRJbiBhbmQgdGhlIExpbmtlZEluIGxvZ28gYXJlIHJlZ2lzdGVyZWQgdHJhZGVtYXJrcyBvZiBMaW5rZWRJbi4=" - } - }, - { - "partId": "1", - "mimeType": "text/html", - "filename": "", - "headers": [ - { - "name": "Content-Type", - "value": "text/html;charset=UTF-8" - }, - { - "name": "Content-Transfer-Encoding", - "value": "quoted-printable" - }, - { - "name": "Content-ID", - "value": "html-body" - } - ], - "body": { - "size": 22763, - "data": "PGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIGxhbmc9ImVuIiB4bWw6bGFuZz0iZW4iPiA8aGVhZD4gPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7Y2hhcnNldD11dGYtOCI-IDxtZXRhIG5hbWU9IkhhbmRoZWxkRnJpZW5kbHkiIGNvbnRlbnQ9InRydWUiPiA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoOyBpbml0aWFsLXNjYWxlPTAuNjY2NjY3OyB1c2VyLXNjYWxhYmxlPTAiPiA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoIj4gPHRpdGxlPjwvdGl0bGU-IDxzdHlsZT4NCiAgICAgICAgICAgIEBtZWRpYSAobWF4LXdpZHRoOiA1MTJweCkgeyAubWVyY2Fkby1jb250YWluZXIgeyB3aWR0aDogMTAwJSAhaW1wb3J0YW50OyB9IH0NCiAgICAgICAgICA8L3N0eWxlPiA8c3R5bGU-DQogICAgICAgICAgICBAbWVkaWEgKG1heC13aWR0aDogNDgwcHgpIHsgLmlubGluZS1idXR0b24sIC5pbmxpbmUtYnV0dG9uIHRhYmxlIHsgZGlzcGxheTogbm9uZSAhaW1wb3J0YW50OyB9DQogICAgICAgICAgICAuZnVsbC13aWR0aC1idXR0b24sIC5mdWxsLXdpZHRoLWJ1dHRvbiB0YWJsZSB7IGRpc3BsYXk6IHRhYmxlICFpbXBvcnRhbnQ7IH0gfQ0KICAgICAgICAgIDwvc3R5bGU-IDxzdHlsZT5ib2R5IHtmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgc3lzdGVtLXVpLCBCbGlua01hY1N5c3RlbUZvbnQsICdTZWdvZSBVSScsIFJvYm90bywgJ0hlbHZldGljYSBOZXVlJywNCiAgICAgICAgICAgICdGaXJhIFNhbnMnLCBVYnVudHUsIE94eWdlbiwgJ094eWdlbiBTYW5zJywgQ2FudGFyZWxsLCAnRHJvaWQgU2FucycsICdBcHBsZSBDb2xvciBFbW9qaScsICdTZWdvZSBVSSBFbW9qaScsDQogICAgICAgICAgICAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgU3ltYm9sJywgJ0x1Y2lkYSBHcmFuZGUnLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmO308L3N0eWxlPiA8IS0tW2lmIG1zb10-PHN0eWxlIHR5cGU9InRleHQvY3NzIj4gPC9zdHlsZT48IVtlbmRpZl0tLT4gPCEtLVtpZiBJRV0-PHN0eWxlIHR5cGU9InRleHQvY3NzIj4gPC9zdHlsZT48IVtlbmRpZl0tLT4gPC9oZWFkPiA8Ym9keSBkaXI9Imx0ciIgY2xhc3M9ImZvbnQtc2FucyBiZy1jb2xvci1iYWNrZ3JvdW5kLWNhbnZhcyB3LWZ1bGwgbS0wIHAtMCBwdC0xIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbWFyZ2luOiAwcHg7IHdpZHRoOiAxMDAlOyBiYWNrZ3JvdW5kLWNvbG9yOiAjZjNmMmYwOyBwYWRkaW5nOiAwcHg7IHBhZGRpbmctdG9wOiA4cHg7IGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBzeXN0ZW0tdWksIEJsaW5rTWFjU3lzdGVtRm9udCwgJ1NlZ29lIFVJJywgUm9ib3RvLCAnSGVsdmV0aWNhIE5ldWUnLCAnRmlyYSBTYW5zJywgVWJ1bnR1LCBPeHlnZW4sICdPeHlnZW4gU2FucycsIENhbnRhcmVsbCwgJ0Ryb2lkIFNhbnMnLCAnQXBwbGUgQ29sb3IgRW1vamknLCAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgRW1vamknLCAnU2Vnb2UgVUkgU3ltYm9sJywgJ0x1Y2lkYSBHcmFuZGUnLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmOyI-IDxkaXYgY2xhc3M9ImgtMCBvcGFjaXR5LTAgdGV4dC10cmFuc3BhcmVudCBpbnZpc2libGUgb3ZlcmZsb3ctaGlkZGVuIHctMCBtYXgtaC1bMF0iIHN0eWxlPSJ2aXNpYmlsaXR5OiBoaWRkZW47IGhlaWdodDogMHB4OyBtYXgtaGVpZ2h0OiAwOyB3aWR0aDogMHB4OyBvdmVyZmxvdzogaGlkZGVuOyBvcGFjaXR5OiAwOyBtc28taGlkZTogYWxsOyIgZGF0YS1lbWFpbC1wcmVoZWFkZXI9InRydWUiPkhlcmXigJlzIHdoYXTigJlzIGhhcHBlbmVkIHNpbmNlIHlvdSB3ZXJlIGxhc3Qgb24gTGlua2VkSW48L2Rpdj4gPGRpdiBjbGFzcz0iaC0wIG9wYWNpdHktMCB0ZXh0LXRyYW5zcGFyZW50IGludmlzaWJsZSBvdmVyZmxvdy1oaWRkZW4gdy0wIG1heC1oLVswXSIgc3R5bGU9InZpc2liaWxpdHk6IGhpZGRlbjsgaGVpZ2h0OiAwcHg7IG1heC1oZWlnaHQ6IDA7IHdpZHRoOiAwcHg7IG92ZXJmbG93OiBoaWRkZW47IG9wYWNpdHk6IDA7IG1zby1oaWRlOiBhbGw7Ij4gzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgIM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqAgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoM2PwqDNj8KgzY_CoCA8L2Rpdj4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iNTEyIiBhbGlnbj0iY2VudGVyIiBjbGFzcz0ibWVyY2Fkby1jb250YWluZXIgdy1bNTEycHhdIG1heC13LVs1MTJweF0gbXgtYXV0byBteS0wIHAtMCBiZy1jb2xvci1iYWNrZ3JvdW5kLWNvbnRhaW5lciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW4tbGVmdDogYXV0bzsgbWFyZ2luLXJpZ2h0OiBhdXRvOyBtYXJnaW4tdG9wOiAwcHg7IG1hcmdpbi1ib3R0b206IDBweDsgd2lkdGg6IDUxMnB4OyBtYXgtd2lkdGg6IDUxMnB4OyBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmZmZmOyBwYWRkaW5nOiAwcHg7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0idGV4dC1jZW50ZXIgcC0zIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmc6IDI0cHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0ibWluLXctZnVsbCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtaW4td2lkdGg6IDEwMCU7Ij4gPHRib2R5PiA8dHI-IDx0ZCBhbGlnbj0ibGVmdCIgdmFsaWduPSJtaWRkbGUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkLz9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkZNTCUyQk1ya0FSZHlQcyUyRmZWTkhtTTZ3JTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTFPUXN1S3hSQjNCSHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVhZGVyLTAtaG9tZV9nbGltbWVyX2R5bmFtaWNfYmFkZ2luZ19oaWdoX2RwaSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVhZGVyLTAtaG9tZV9nbGltbWVyX2R5bmFtaWNfYmFkZ2luZ19oaWdoX2RwaS1udWxsLWo3enU3aX5tM3ZvejJsM35zZC1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN2b3oybDMtc2QmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakE0WVdNMlpEUTBOemt3WVdRNE9UWmhOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU1UWm1NV1JoWkRJM09HWXlaamRpTVRkak16VTRabU5qWVRNMk5qSmhNR1F5TnpBeU5ESXhZMkl3TmpFMlltSmtMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0idy1bODRweF0iIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgd2lkdGg6IDg0cHg7Ij4gPGltZyBjbGFzcz0iaC1bMzdweF0gdy1bMTAxcHhdIiBhbHQ9IkxpbmtlZEluIiBzcmM9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2Rtcy9sb2dvL3YyP2JhZGdlVGhlbWU9bWVyY2FkbyZhbXA7bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxJTNCJTJGTUwlMkJNcmtBUmR5UHMlMkZmVk5IbU02dyUzRCUzRCZhbXA7bWlkU2lnPTFPUXN1S3hSQjNCSHcxJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtbnVsbC0wLWNvbW1zJTdFYmFkZ2luZyU3RWR5bmFtaWMlN0VnbGltbWVyJTdFdjItbnVsbC1qN3p1N2klN0VtM3ZvejJsMyU3RXNkLW51bGwtbnVsbCZhbXA7dHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLW51bGwtMC1jb21tcyU3RWJhZGdpbmclN0VkeW5hbWljJTdFZ2xpbW1lciU3RXYyJmFtcDtfc2lnPTBxWDVWZ3BaNTNCSHcxIiBkYXRhLXRlc3QtaGVhZGVyLWR5bmFtaWMtYmFkZ2luZy1pbWctaGlnaC1kcGkgc3R5bGU9Im91dGxpbmU6IG5vbmU7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLW1zLWludGVycG9sYXRpb24tbW9kZTogYmljdWJpYzsgaGVpZ2h0OiAzN3B4OyB3aWR0aDogMTAxcHg7IiB3aWR0aD0iMTAxIiBoZWlnaHQ9IjM3Ij4gPC9hPiA8L3RkPiA8dGQgdmFsaWduPSJtaWRkbGUiIGFsaWduPSJyaWdodCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGRhdGEtdGVzdC1oZWFkZXItcHJvZmlsZSBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPHRib2R5PiA8dHI-IDx0ZCBhbGlnbj0icmlnaHQiIHZhbGlnbj0ibWlkZGxlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly9pbi5saW5rZWRpbi5jb20vY29tbS9pbi9raHVzaGFsLXBzLTdhNjJiNzI4NT9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkZNTCUyQk1ya0FSZHlQcyUyRmZWTkhtTTZ3JTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTFPUXN1S3hSQjNCSHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVhZGVyLTAtcHJvZmlsZV9nbGltbWVyJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1oZWFkZXItMC1wcm9maWxlX2dsaW1tZXItbnVsbC1qN3p1N2l-bTN2b3oybDN-c2QtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zdm96MmwzLXNkJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpBNFlXTTJaRFEwTnprd1lXUTRPVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVNVFptTVdSaFpESTNPR1l5WmpkaU1UZGpNelU0Wm1OallUTTJOakpoTUdReU56QXlOREl4WTJJd05qRTJZbUprTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxzcGFuIGNsYXNzPSJuby11bmRlcmxpbmUgdGV4dC1zeXN0ZW0tZ3JheS05MCIgc3R5bGU9ImNvbG9yOiAjMjgyODI4OyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPktodXNoYWwgUFM8L3NwYW4-IDwvYT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPC90Ym9keT4gPC90YWJsZT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InB4LTMgcGItMyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWxlZnQ6IDI0cHg7IHBhZGRpbmctcmlnaHQ6IDI0cHg7IHBhZGRpbmctYm90dG9tOiAyNHB4OyI-IDxkaXY-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJweC0xICIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWxlZnQ6IDhweDsgcGFkZGluZy1yaWdodDogOHB4OyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9IjEwMCUiIGNsYXNzIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIGNsYXNzPSJwYi0yIHRleHQtY2VudGVyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctYm90dG9tOiAxNnB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iYXV0byIgYWxpZ249ImNlbnRlciIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9ImlubGluZS1ibG9jayB3LTggaC04IiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgaGVpZ2h0OiA2NHB4OyB3aWR0aDogNjRweDsiIHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvbmV3cy82MjE3MjIwP2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyRk1MJTJCTXJrQVJkeVBzJTJGZlZOSG1NNnclM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MU9Rc3VLeFJCM0JIdzEmYW1wO3Ryaz1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1lbnRpdHlfcGlsZS0wLUVESVRPUklBTF9CTEFaRV9JTkFQUF8wJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1lbnRpdHlfcGlsZS0wLUVESVRPUklBTF9CTEFaRV9JTkFQUF8wLW51bGwtajd6dTdpfm0zdm96MmwzfnNkLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3ZvejJsMy1zZCZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqQTRZV00yWkRRME56a3dZV1E0T1RaaE4ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TVRabU1XUmhaREkzT0dZeVpqZGlNVGRqTXpVNFptTmpZVE0yTmpKaE1HUXlOekF5TkRJeFkySXdOakUyWW1Ka0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxlPSJjb2xvcjogIzBhNjZjMjsgY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsiPiA8aW1nIGNsYXNzPSJpbmxpbmUtYmxvY2sgcmVsYXRpdmUgYmctY29sb3ItZW50aXR5LWdob3N0LWJhY2tncm91bmQgdy04IGgtOCAhYmxvY2siIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL2Flcm8tdjEvc2MvaC84N3V1N3g1bXdtYXRzbjd2NmYyOHMyNm81IiBhbHQ9IkdldCBIaXJlZCBMb2dvIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBwb3NpdGlvbjogcmVsYXRpdmU7IGhlaWdodDogNjRweDsgd2lkdGg6IDY0cHg7IGJhY2tncm91bmQtY29sb3I6ICNlYWU2ZGY7IGRpc3BsYXk6IGJsb2NrICFpbXBvcnRhbnQ7IiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwYi0yIHRleHQtY2VudGVyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctYm90dG9tOiAxNnB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gVXNpbmcgQUkgYXQgd29yaz8gVGFrZSBub3RlIG9mIHRoZXNlIGlzc3Vlcy4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InRleHQtY2VudGVyIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHRleHQtYWxpZ246IGNlbnRlcjsiPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0iZW1haWwtYnV0dG9uICIgZGF0YS10ZXN0LWlkPSJlbWFpbC1idXR0b24iIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiA8dGJvZHk-IDx0cj4gPHRkIHZhbGlnbj0ibWlkZGxlIiBhbGlnbj0ibWlkZGxlIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7Ij4gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbW0vZmVlZC9uZXdzLzYyMTcyMjA_bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxJTNCJTJGTUwlMkJNcmtBUmR5UHMlMkZmVk5IbU02dyUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0xT1FzdUt4UkIzQkh3MSZhbXA7dHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLWhlcm9fbm90aWZpY2F0aW9uX2N0YS0wLUVESVRPUklBTF9CTEFaRV9JTkFQUCZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVyb19ub3RpZmljYXRpb25fY3RhLTAtRURJVE9SSUFMX0JMQVpFX0lOQVBQLW51bGwtajd6dTdpfm0zdm96MmwzfnNkLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3ZvejJsMy1zZCZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqQTRZV00yWkRRME56a3dZV1E0T1RaaE4ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TVRabU1XUmhaREkzT0dZeVpqZGlNVGRqTXpVNFptTmpZVE0yTmpKaE1HUXlOekF5TkRJeFkySXdOakUyWW1Ka0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGFyaWEtbGFiZWw9IlJlYWQgbW9yZSIgY2xhc3M9ImFsaWduLXRvcCBuby11bmRlcmxpbmUgIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IHZlcnRpY2FsLWFsaWduOiB0b3A7IHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOyI-IDx0YWJsZSByb2xlPSJwcmVzZW50YXRpb24iIHZhbGlnbj0idG9wIiBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgd2lkdGg9ImF1dG8iIGNsYXNzPSJib3JkZXItc2VwYXJhdGUgIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJvcmRlci1jb2xsYXBzZTogc2VwYXJhdGU7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0iYnRuLW1kIGJ0bi1wcmltYXJ5IGJvcmRlci1jb2xvci1icmFuZCBidXR0b24tbGluayBsZWFkaW5nLXJlZ3VsYXIgIW1pbi1oLVthdXRvXSAhc2hhZG93LW5vbmUgYm9yZGVyLTEgYm9yZGVyLXNvbGlkIHctWzM5MHB4XSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBoZWlnaHQ6IG1pbi1jb250ZW50OyBib3JkZXItcmFkaXVzOiAyNHB4OyBwYWRkaW5nLXRvcDogMTJweDsgcGFkZGluZy1ib3R0b206IDEycHg7IHBhZGRpbmctbGVmdDogMjRweDsgcGFkZGluZy1yaWdodDogMjRweDsgdGV4dC1hbGlnbjogY2VudGVyOyBmb250LXNpemU6IDE2cHg7IGZvbnQtd2VpZ2h0OiA2MDA7IGN1cnNvcjogcG9pbnRlcjsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7IGJhY2tncm91bmQtY29sb3I6ICMwYTY2YzI7IGNvbG9yOiAjZmZmZmZmOyB3aWR0aDogMzkwcHg7IGJvcmRlci13aWR0aDogMXB4OyBib3JkZXItc3R5bGU6IHNvbGlkOyBib3JkZXItY29sb3I6ICMwYTY2YzI7IGxpbmUtaGVpZ2h0OiAxLjI1OyBtaW4taGVpZ2h0OiBhdXRvICFpbXBvcnRhbnQ7IGJveC1zaGFkb3c6IDAgMCAjMDAwMCwgMCAwICMwMDAwLCAwIDAgIzAwMDAgIWltcG9ydGFudDsiIHdpZHRoPSIzOTAiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9mZWVkL25ld3MvNjIxNzIyMD9saXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkZNTCUyQk1ya0FSZHlQcyUyRmZWTkhtTTZ3JTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTFPUXN1S3hSQjNCSHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVyb19ub3RpZmljYXRpb25fY3RhLTAtRURJVE9SSUFMX0JMQVpFX0lOQVBQJmFtcDt0cmtFbWFpbD1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1oZXJvX25vdGlmaWNhdGlvbl9jdGEtMC1FRElUT1JJQUxfQkxBWkVfSU5BUFAtbnVsbC1qN3p1N2l-bTN2b3oybDN-c2QtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zdm96MmwzLXNkJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpBNFlXTTJaRFEwTnprd1lXUTRPVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVNVFptTVdSaFpESTNPR1l5WmpkaU1UZGpNelU0Wm1OallUTTJOakpoTUdReU56QXlOREl4WTJJd05qRTJZbUprTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgdGFiaW5kZXg9Ii0xIiBhcmlhLWhpZGRlbj0idHJ1ZSIgY2xhc3M9Im5vLXVuZGVybGluZSIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyB0ZXh0LWRlY29yYXRpb24tbGluZTogbm9uZTsiPiA8c3BhbiBjbGFzcz0ibm8tdW5kZXJsaW5lIHRleHQtd2hpdGUiIHN0eWxlPSJjb2xvcjogI2ZmZmZmZjsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IG5vbmU7Ij4gUmVhZCBtb3JlIDwvc3Bhbj4gPC9hPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L2E-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvdGQ-IDwvdHI-IDwvdGJvZHk-IDwvdGFibGU-IDwvZGl2PiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0iYmctY29sb3ItYmFja2dyb3VuZC1jYW52YXMgcC0zIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IGJhY2tncm91bmQtY29sb3I6ICNmM2YyZjA7IHBhZGRpbmc6IDI0cHg7Ij4gPHRhYmxlIHJvbGU9InByZXNlbnRhdGlvbiIgdmFsaWduPSJ0b3AiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIwIiB3aWR0aD0iMTAwJSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyI-IDx0Ym9keT4gPHRyPiA8dGQgY2xhc3M9InRleHQtY2VudGVyIHBiLTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy1ib3R0b206IDE2cHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPiA8aDIgY2xhc3M9InRleHQtbGcgdGV4dC10ZWFsLTgwIiBzdHlsZT0ibWFyZ2luOiAwOyBmb250LXdlaWdodDogNTAwOyBmb250LXNpemU6IDIwcHg7IGNvbG9yOiAjMTE0OTUxOyI-IEdldCB0aGUgbmV3IExpbmtlZEluIGRlc2t0b3AgYXBwIDwvaDI-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJ0ZXh0LWNlbnRlciBwYi0yIiBkYXRhLXRlc3QtaWQ9ImZvb3Rlci1hcHAtc3RvcmUtaWNvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogMTZweDsgdGV4dC1hbGlnbjogY2VudGVyOyI-IDxhIGhyZWY9Imh0dHBzOi8vYXBwcy5taWNyb3NvZnQuY29tL3N0b3JlL2RldGFpbC85V1pETkNSRko0UTc_bGF1bmNoPXRydWUmYW1wO2NpZD1saW5rZWRpbl9lbWFpbF91cHNlbGwmYW1wO21vZGU9ZnVsbCIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxpbWcgYWx0PSJHZXQgaXQgZnJvbSBNaWNyb3NvZnQiIHNyYz0iaHR0cHM6Ly9zdGF0aWMubGljZG4uY29tL2Flcm8tdjEvc2MvaC9lanBra3B3dnFrczMxYTNjanFva2I3ZmJtIiBjbGFzcz0iaC1bNDBweF0gdy1bMTEycHhdIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBoZWlnaHQ6IDQwcHg7IHdpZHRoOiAxMTJweDsiIHdpZHRoPSIxMTIiIGhlaWdodD0iNDAiPiA8L2E-IDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJ0ZXh0LWNlbnRlciBwYi0yIiBzdHlsZT0iLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgbXNvLXRhYmxlLWxzcGFjZTogMHB0OyBtc28tdGFibGUtcnNwYWNlOiAwcHQ7IHBhZGRpbmctYm90dG9tOiAxNnB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPGgyIGNsYXNzPSJ0ZXh0LW1kIHRleHQtdGVhbC04MCIgc3R5bGU9Im1hcmdpbjogMDsgZm9udC13ZWlnaHQ6IDUwMDsgZm9udC1zaXplOiAxNnB4OyBjb2xvcjogIzExNDk1MTsiPiBBbHNvIGF2YWlsYWJsZSBvbiBtb2JpbGUgPC9oMj4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InRleHQtY2VudGVyIiBkYXRhLXRlc3QtaWQ9ImZvb3Rlci1hcHAtc3RvcmUtaWNvbiIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij4gPGEgaHJlZj0iaHR0cHM6Ly9pdHVuZXMuYXBwbGUuY29tL3VzL2FwcC9saW5rZWRpbi9pZDI4ODQyOTA0MD9wdD0xMDc0NiZhbXA7Y3Q9c3RfYXBwc2l0ZV9mbGFnc2hpcCZhbXA7bXQ9OCIgdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxpbWcgYWx0PSJEb3dubG9hZCBvbiB0aGUgQXBwIFN0b3JlIiBzcmM9Imh0dHBzOi8vc3RhdGljLmxpY2RuLmNvbS9hZXJvLXYxL3NjL2gvNzZ5emtkMGg1a2l2MjdscmQ0eWFlbnlsayIgY2xhc3M9ImgtWzQwcHhdIHctWzEyMHB4XSBwci0xIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyBoZWlnaHQ6IDQwcHg7IHdpZHRoOiAxMjBweDsgcGFkZGluZy1yaWdodDogOHB4OyIgd2lkdGg9IjEyMCIgaGVpZ2h0PSI0MCI-IDwvYT4gPGEgaHJlZj0iaHR0cHM6Ly9wbGF5Lmdvb2dsZS5jb20vc3RvcmUvYXBwcy9kZXRhaWxzP2lkPWNvbS5saW5rZWRpbi5hbmRyb2lkJmFtcDtyZWZlcnJlcj1zdF9hcHBzaXRlX2ZsYWdzaGlwIiB0YXJnZXQ9Il9ibGFuayIgcmVsPSJub29wZW5lciBub3JlZmVycmVyIiBzdHlsZT0iY29sb3I6ICMwYTY2YzI7IGN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7Ij4gPGltZyBhbHQ9IkdldCBpdCBvbiBHb29nbGUgUGxheSIgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vYWVyby12MS9zYy9oLzE0MnF1ZHdibHA1OHp3bWM5dmtxZnBsdWciIGNsYXNzPSJoLVs0MHB4XSB3LVsxMzRweF0iIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC1tcy1pbnRlcnBvbGF0aW9uLW1vZGU6IGJpY3ViaWM7IGhlaWdodDogNDBweDsgd2lkdGg6IDEzNHB4OyIgd2lkdGg9IjEzNCIgaGVpZ2h0PSI0MCI-IDwvYT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgY2xhc3M9InB5LTIiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgcGFkZGluZy10b3A6IDE2cHg7IHBhZGRpbmctYm90dG9tOiAxNnB4OyI-PGhyIGNsYXNzPSJib3JkZXItbm9uZSBiZy1bI2UwZGZkZF0gaC1bMXB4XSIgc3R5bGU9ImhlaWdodDogMXB4OyBib3JkZXItc3R5bGU6IG5vbmU7IGJhY2tncm91bmQtY29sb3I6ICNlMGRmZGQ7Ij48L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiB2YWxpZ249InRvcCIgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiBjbGFzcz0idGV4dC14cyIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBmb250LXNpemU6IDEycHg7Ij4gPHRib2R5PiA8dHI-IDx0ZCBjbGFzcz0icGItMSBtLTAiIGRhdGEtdGVzdC1pZD0iZW1haWwtZm9vdGVyX19pbnRlbmRlZCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW46IDBweDsgcGFkZGluZy1ib3R0b206IDhweDsiPiBUaGlzIGVtYWlsIHdhcyBpbnRlbmRlZCBmb3IgS2h1c2hhbCBQUyAoLS0pIDwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwYi0xIG0tMCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW46IDBweDsgcGFkZGluZy1ib3R0b206IDhweDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vaGVscC9saW5rZWRpbi9hbnN3ZXIvNDc4OD9sYW5nPWVuJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkZNTCUyQk1ya0FSZHlQcyUyRmZWTkhtTTZ3JTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTFPUXN1S3hSQjNCSHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtU2VjdXJpdHlIZWxwLTAtZm9vdGVyZ2xpbW1lciZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtU2VjdXJpdHlIZWxwLTAtZm9vdGVyZ2xpbW1lci1udWxsLWo3enU3aX5tM3ZvejJsM35zZC1udWxsLW51bGwmYW1wO2VpZD1qN3p1N2ktbTN2b3oybDMtc2QmYW1wO290cFRva2VuPU1UTXdOREU0WlRJeE1ESTJZMlpqTTJJeU1qZ3dabVZpTkRFeFpHVTFZakE0WVdNMlpEUTBOemt3WVdRNE9UWmhOMkpqWmpBMk5qWTBZelZpTldSbU5HWm1aREZrTTJVNU1UWm1NV1JoWkRJM09HWXlaamRpTVRkak16VTRabU5qWVRNMk5qSmhNR1F5TnpBeU5ESXhZMkl3TmpFMlltSmtMREVzTVElM0QlM0QiIHRhcmdldD0iX2JsYW5rIiBjbGFzcz0idGV4dC1pbmhlcml0IHVuZGVybGluZSIgc3R5bGU9ImN1cnNvcjogcG9pbnRlcjsgZGlzcGxheTogaW5saW5lLWJsb2NrOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IC13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IGNvbG9yOiBpbmhlcml0OyB0ZXh0LWRlY29yYXRpb24tbGluZTogdW5kZXJsaW5lOyI-TGVhcm4gd2h5IHdlIGluY2x1ZGVkIHRoaXMuPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icGItMSBtLTAiIHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsgbWFyZ2luOiAwcHg7IHBhZGRpbmctYm90dG9tOiA4cHg7Ij5Zb3UgYXJlIHJlY2VpdmluZyBMaW5rZWRJbiBub3RpZmljYXRpb24gZW1haWxzLjwvdGQ-IDwvdHI-IDx0cj4gPHRkIGNsYXNzPSJwYi0xIG0tMCIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBtYXJnaW46IDBweDsgcGFkZGluZy1ib3R0b206IDhweDsiPiA8YSBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tbS9wc2V0dGluZ3MvZW1haWwtdW5zdWJzY3JpYmU_bGlwaT11cm4lM0FsaSUzQXBhZ2UlM0FlbWFpbF9lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxJTNCJTJGTUwlMkJNcmtBUmR5UHMlMkZmVk5IbU02dyUzRCUzRCZhbXA7bWlkVG9rZW49QVFGUGEyM056bzE4RlEmYW1wO21pZFNpZz0xT1FzdUt4UkIzQkh3MSZhbXA7dHJrPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLXVuc3Vic2NyaWJlLTAtZm9vdGVyR2xpbW1lciZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtdW5zdWJzY3JpYmUtMC1mb290ZXJHbGltbWVyLW51bGwtajd6dTdpfm0zdm96MmwzfnNkLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3ZvejJsMy1zZCZhbXA7bG9pZD1BUUc3RHBNY0JtSkJlZ0FBQVpOZWtsZmR5NVJpbG1YUVMwTFpMeVFGY2RoTVNROHpkd1dSN29DWlFFOGM2ZDY0TG5kcWRRVGV2TG90RERQcmpZRE1FS3k2TDJGcEozcXEwdVNnLW5ZIiB0YXJnZXQ9Il9ibGFuayIgY2xhc3M9InRleHQtaW5oZXJpdCB1bmRlcmxpbmUiIHN0eWxlPSJjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBjb2xvcjogaW5oZXJpdDsgdGV4dC1kZWNvcmF0aW9uLWxpbmU6IHVuZGVybGluZTsiPlVuc3Vic2NyaWJlPC9hPiDCoMKgwrfCoMKgIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9oZWxwL2xpbmtlZGluL2Fuc3dlci82Nz9sYW5nPWVuJmFtcDtsaXBpPXVybiUzQWxpJTNBcGFnZSUzQWVtYWlsX2VtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDElM0IlMkZNTCUyQk1ya0FSZHlQcyUyRmZWTkhtTTZ3JTNEJTNEJmFtcDttaWRUb2tlbj1BUUZQYTIzTnpvMThGUSZhbXA7bWlkU2lnPTFPUXN1S3hSQjNCSHcxJmFtcDt0cms9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtaGVscC0wLWZvb3RlcmdsaW1tZXImYW1wO3Rya0VtYWlsPWVtbC1lbWFpbF9ub3RpZmljYXRpb25fZGlnZXN0XzAxLWhlbHAtMC1mb290ZXJnbGltbWVyLW51bGwtajd6dTdpfm0zdm96MmwzfnNkLW51bGwtbnVsbCZhbXA7ZWlkPWo3enU3aS1tM3ZvejJsMy1zZCZhbXA7b3RwVG9rZW49TVRNd05ERTRaVEl4TURJMlkyWmpNMkl5TWpnd1ptVmlOREV4WkdVMVlqQTRZV00yWkRRME56a3dZV1E0T1RaaE4ySmpaakEyTmpZMFl6VmlOV1JtTkdabVpERmtNMlU1TVRabU1XUmhaREkzT0dZeVpqZGlNVGRqTXpVNFptTmpZVE0yTmpKaE1HUXlOekF5TkRJeFkySXdOakUyWW1Ka0xERXNNUSUzRCUzRCIgdGFyZ2V0PSJfYmxhbmsiIGNsYXNzPSJ0ZXh0LWluaGVyaXQgdW5kZXJsaW5lIiBzdHlsZT0iY3Vyc29yOiBwb2ludGVyOyBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHRleHQtZGVjb3JhdGlvbjogbm9uZTsgLXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyAtbXMtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgY29sb3I6IGluaGVyaXQ7IHRleHQtZGVjb3JhdGlvbi1saW5lOiB1bmRlcmxpbmU7Ij5IZWxwPC9hPiA8L3RkPiA8L3RyPiA8dHI-IDx0ZCBjbGFzcz0icGItMSIgc3R5bGU9Ii13ZWJraXQtdGV4dC1zaXplLWFkanVzdDogMTAwJTsgLW1zLXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IG1zby10YWJsZS1sc3BhY2U6IDBwdDsgbXNvLXRhYmxlLXJzcGFjZTogMHB0OyBwYWRkaW5nLWJvdHRvbTogOHB4OyI-IDxhIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21tL2ZlZWQvP2xpcGk9dXJuJTNBbGklM0FwYWdlJTNBZW1haWxfZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMSUzQiUyRk1MJTJCTXJrQVJkeVBzJTJGZlZOSG1NNnclM0QlM0QmYW1wO21pZFRva2VuPUFRRlBhMjNOem8xOEZRJmFtcDttaWRTaWc9MU9Rc3VLeFJCM0JIdzEmYW1wO3Ryaz1lbWwtZW1haWxfbm90aWZpY2F0aW9uX2RpZ2VzdF8wMS1mb290ZXItMC1sb2dvR2xpbW1lciZhbXA7dHJrRW1haWw9ZW1sLWVtYWlsX25vdGlmaWNhdGlvbl9kaWdlc3RfMDEtZm9vdGVyLTAtbG9nb0dsaW1tZXItbnVsbC1qN3p1N2l-bTN2b3oybDN-c2QtbnVsbC1udWxsJmFtcDtlaWQ9ajd6dTdpLW0zdm96MmwzLXNkJmFtcDtvdHBUb2tlbj1NVE13TkRFNFpUSXhNREkyWTJaak0ySXlNamd3Wm1WaU5ERXhaR1UxWWpBNFlXTTJaRFEwTnprd1lXUTRPVFpoTjJKalpqQTJOalkwWXpWaU5XUm1OR1ptWkRGa00yVTVNVFptTVdSaFpESTNPR1l5WmpkaU1UZGpNelU0Wm1OallUTTJOakpoTUdReU56QXlOREl4WTJJd05qRTJZbUprTERFc01RJTNEJTNEIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiAjMGE2NmMyOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGlubGluZS1ibG9jazsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyI-IDxpbWcgc3JjPSJodHRwczovL3N0YXRpYy5saWNkbi5jb20vYWVyby12MS9zYy9oLzllaGU2bjM5ZmEwN2RjNWVkenYwcmxhNGUiIGFsdD0iTGlua2VkSW4iIGNsYXNzPSJibG9jayBoLVsxNHB4XSB3LVs1NnB4XSBpbWFnZS1yZW5kZXJpbmctY3Jpc3AiIHN0eWxlPSJvdXRsaW5lOiBub25lOyB0ZXh0LWRlY29yYXRpb246IG5vbmU7IGltYWdlLXJlbmRlcmluZzogLW1vei1jcmlzcC1lZGdlczsgaW1hZ2UtcmVuZGVyaW5nOiAtby1jcmlzcC1lZGdlczsgaW1hZ2UtcmVuZGVyaW5nOiAtd2Via2l0LW9wdGltaXplLWNvbnRyYXN0OyBpbWFnZS1yZW5kZXJpbmc6IGNyaXNwLWVkZ2VzOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBuZWFyZXN0LW5laWdoYm9yOyBkaXNwbGF5OiBibG9jazsgaGVpZ2h0OiAxNHB4OyB3aWR0aDogNTZweDsiIHdpZHRoPSI1NiIgaGVpZ2h0PSIxNCI-IDwvYT4gPC90ZD4gPC90cj4gPHRyPiA8dGQgZGF0YS10ZXN0LWNvcHlyaWdodC10ZXh0IHN0eWxlPSItd2Via2l0LXRleHQtc2l6ZS1hZGp1c3Q6IDEwMCU7IC1tcy10ZXh0LXNpemUtYWRqdXN0OiAxMDAlOyBtc28tdGFibGUtbHNwYWNlOiAwcHQ7IG1zby10YWJsZS1yc3BhY2U6IDBwdDsiPiDCqSAyMDI0IExpbmtlZEluIENvcnBvcmF0aW9uLCAxJnp3bmo7MDAwIFdlc3QgTWF1ZGUgQXZlbnVlLCBTdW5ueXZhbGUsIENBIDk0MDg1LiA8c3BhbiBkYXRhLXRlc3QtdHJhZGVtYXJrcy10ZXh0PiBMaW5rZWRJbiBhbmQgdGhlIExpbmtlZEluIGxvZ28gYXJlIHJlZ2lzdGVyZWQgdHJhZGVtYXJrcyBvZiBMaW5rZWRJbi4gPC9zcGFuPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8L3RkPiA8L3RyPiA8L3Rib2R5PiA8L3RhYmxlPiA8aW1nIGFsdCByb2xlPSJwcmVzZW50YXRpb24iIHNyYz0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2VtaW1wL2lwX1lXcGtObVJVWkhCTVZ6QjZaRzA1TmsxdGQzcE1XRTVyT2xwWE1XaGhWM2htWW0wNU1HRlhXbkJaTWtZd1lWYzVkVmd5VW5CYU1sWjZaRVk0ZDAxUlBUMDYuZ2lmIiBzdHlsZT0ib3V0bGluZTogbm9uZTsgdGV4dC1kZWNvcmF0aW9uOiBub25lOyAtbXMtaW50ZXJwb2xhdGlvbi1tb2RlOiBiaWN1YmljOyB3aWR0aDogMXB4OyBoZWlnaHQ6IDFweDsiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiPiA8L2JvZHk-IDwvaHRtbD4=" - } - } - ] - }, - "sizeEstimate": 35040, - "historyId": "526827", - "internalDate": "1732458470000" -} \ No newline at end of file diff --git a/utils_v2/goog/models/__init__.py b/utils_v2/goog/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/goog/models/data/__init__.py b/utils_v2/goog/models/data/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/goog/models/data/api_call.py b/utils_v2/goog/models/data/api_call.py deleted file mode 100644 index 6301dff..0000000 --- a/utils_v2/goog/models/data/api_call.py +++ /dev/null @@ -1,132 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Wednesday, 30th Oct., 2024. - - OBJECTIVE: - - To provide a data model for describing the API response from Google's APIs. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For making data behaviour_models: -from pydantic import BaseModel, Field, field_validator, model_validator -from typing import Optional, Literal, Union, Dict, List, Any - -# My utils: -from utils_v2.string import json -from utils_v2.string import regex - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -class GoogleApiResponse(BaseModel): - - serviceName: str = Field(frozen = True, default = None) - action: str = Field(frozen = True, default = None) - - url: str = Field(frozen = True) - method: str = Field(frozen = True) - response: Any = None - httpCode: int = None - - success: bool = False - message: str = None - data: Any = None - - exception: Any = None - - # ┏┓ ┏• - # ┃ ┏┓┏┓╋┓┏┓ - # ┗┛┗┛┛┗┛┗┗┫ - # ┛ - - class Config: - extra = "forbid" - - # ┏┓ ┏┓ - # ┃ ┓┏┏╋┏┓┏┳┓ ┣ ┓┏┏┓┏┏ - # ┗┛┗┻┛┗┗┛┛┗┗ ┻ ┗┻┛┗┗┛ - - def to_markdown(self): - if self.exception: message = "❌ *GOOGLE API EXCEPTION:* ❌\n\n" - else: message = "*PROVIDER API RESPONSE:*\n\n" - message += f"*SERVICE:*\n`{self.serviceName}`\n\n" - message += f"*ACTION:*\n`{self.action}`\n\n" - message += f"*URL:*\n`{self.url}`\n\n" - message += f"*METHOD:*\n`{self.method}`\n\n" - message += f"*RESPONSE:*\n`{self.response}`\n\n" - message += f"*MESSAGE:*\n`{self.message}`\n\n" - message += f"*EXCEPTION:*\n`{self.exception.__class__.__name__}: {str(self.exception)}`\n\n" - return message - - async def get_json(self): - try: return self.response.json() - except: return {} - - async def get_content(self): - try: return self.response.content - except: return b"" - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/goog/models/data/auth_tokens.py b/utils_v2/goog/models/data/auth_tokens.py deleted file mode 100644 index df57f53..0000000 --- a/utils_v2/goog/models/data/auth_tokens.py +++ /dev/null @@ -1,237 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Wednesday, 30th Oct., 2024. - - OBJECTIVE: - - To provide a data model for describing the tokens to be used for Google's APIs. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys - -import httpx - -sys.path.append(".") -sys.path.append("..") - -# For making data behaviour_models: -from pydantic import BaseModel, Field, field_validator, model_validator, AwareDatetime -from typing import Optional, Literal, Union, Dict, List, Any - -# Related to Google: -from google.auth.transport.requests import Request -from google.oauth2.credentials import Credentials - -# My utils: -from utils_v2.string import json -from utils_v2.string import regex -from utils_v2.date_time import date_time - -# To work with date and time: -import datetime -import dateparser - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -class GoogleAuthTokens(BaseModel): - - accessToken: str = Field(description = "the main 'bearer' token") - refreshToken: str = Field(description = "token to be used to refresh the access token") - expiresAt: AwareDatetime = Field(description = "the time (utc) at which the token will expire") - scopes: List[str] = Field(description = "the list of permissions", default = []) - email: str | None = Field(description = "the email id of the user", default = None) - - # ┏┓ ┏• - # ┃ ┏┓┏┓╋┓┏┓ - # ┗┛┗┛┛┗┛┗┗┫ - # ┛ - - class Config: - extra = "ignore" - - # ┓┏ ┓• ┓ • - # ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓ - # ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗ - - @field_validator("expiresAt", mode = "before") - def parse_dates(cls, value): - if not isinstance(value, datetime.datetime): - parsed = date_time.parse_date_time(value, date_formats = ["%Y%m%d", "%Y-%m-%d"]) - value = parsed if isinstance(parsed, datetime.datetime) else dateparser.parse(value) - if isinstance(value, datetime.datetime): value = date_time.to_timezone(value, date_time.TIMEZONE_UTC) - return value - - # ┏┓ • - # ┃┃┏┓┏┓┏┓┏┓┏┓╋┓┏┓┏ - # ┣┛┛ ┗┛┣┛┗ ┛ ┗┗┗ ┛ - # ┛ - - @property - def expired(self): - return True if date_time.get_current_utc_date_time() >= self.expiresAt else False - - @property - def ttl(self): - return (self.expiresAt - date_time.get_current_utc_date_time()).total_seconds() - - # ┏┓ ┏┓ - # ┃ ┓┏┏╋┏┓┏┳┓ ┣ ┓┏┏┓┏┏ - # ┗┛┗┻┛┗┗┛┛┗┗ ┻ ┗┻┛┗┗┛ - - def refresh( - self, - client_id: str, - client_secret: str, - force_refresh: bool = False - ) -> bool: - - """ - Synchronously (blocking) refreshes the existing access tokens in place. - :param client_id: The id of the client (OAuth JSON) for which these tokens were granted. - :param client_secret: The secret of the client (OAuth JSON) for which these tokens were granted. - :param force_refresh: Whether you want to refresh the token even if it hasn't expired. - :return: True if refreshed, else False. - """ - - # Start by assuming failure: - success = False - - try: - - # Go ahead only if either the token has expired, - # or the user has asked to forcefully refresh the tokens: - if self.expired or force_refresh: - - # Create the credentials: - credentials = Credentials.from_authorized_user_info( - info = { - "client_id": client_id, - "client_secret": client_secret, - "refresh_token": self.refreshToken, - "expires_at": self.expiresAt - } - ) - - # Request a refresh: - credentials.refresh(Request()) - - # Note down the new credentials: - if credentials.token != self.accessToken: - success = True - self.accessToken = credentials.token - self.refreshToken = credentials.refresh_token - self.expiresAt = date_time.as_if_timezone(credentials.expiry, timezone = date_time.TIMEZONE_UTC) - - # In case something goes wrong: - except Exception as exception: - success = False - - # Done here: - return success - - async def arefresh( - self, - http_client: httpx.AsyncClient, - client_id: str, - client_secret: str, - force_refresh: bool = False - ) -> bool: - - """ - Asynchronously refreshes the existing access tokens in place. - :param http_client: The HTTP client to use to make the refresh request. - :param client_id: The id of the client (OAuth JSON) for which these tokens were granted. - :param client_secret: The secret of the client (OAuth JSON) for which these tokens were granted. - :param force_refresh: Whether you want to refresh the token even if it hasn't expired. - :return: True if refreshed, else False. - """ - - # Currently we don't really know how to refresh tokens through low-level API calls, - # so we will pass on the intent to the regular, synchronous function. - return self.refresh( - client_id = client_id, - client_secret = client_secret, - force_refresh = force_refresh - ) - - def has_scopes(self, scopes: List[str]) -> bool: - - """ - Checks if all the specified scopes were granted. - :param scopes: The list of scopes to check. These are the permissions you need. - :return: True if all specified scoped are present, else False. - """ - - # Start by assuming success: - has_scopes = True - - # Now loop through the needed scopes and check: - for scope in scopes: - if scope not in self.scopes: - has_scopes = False - break - - # Done here: - return has_scopes - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/image/__init__.py b/utils_v2/image/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/image/scanner/__init__.py b/utils_v2/image/scanner/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/image/scanner/scanner.py b/utils_v2/image/scanner/scanner.py deleted file mode 100644 index 28fe69b..0000000 --- a/utils_v2/image/scanner/scanner.py +++ /dev/null @@ -1,410 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Thursday, 19th Sept., 2024 - - OBJECTIVE: - - To provide a way to easily scan documents like printouts and visiting cards. - - REFERENCES: - - 01. https://medium.com/@victorolufemi/build-a-document-scanner-with-opencv-ff9f645a4085 - 02. https://github.com/JaidedAI/EasyOCR - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys - -from diffusers.utils.import_utils import candidates - -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# To work with image processing: -import cv2 -import imutils -import numpy as np - -# To run OCR: -import easyocr - -# To download images from the web: -import requests - -# My utils: -from utils_v2.string import json -from utils_v2.ai.object_detection.yolo import YoloDetect - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class DocumentScanner: - - def __init__( - self, - layout_detection_yolo = None, - whitelisted_yolo_classes = None, - ocr_languages = None - ): - - self.__yolo = YoloDetect( - model_file = layout_detection_yolo, - debug = False - ) - self.__whitelisted_yolo_classes = whitelisted_yolo_classes or [] - self.__ocr_engine = easyocr.Reader(ocr_languages or ["en"]) - pass - - @staticmethod - def open_image(image): - - """ - Opens an image from various sources. - :param image: The image either as a path to a file on the local disk, or a URL, or an io.BytesIO buffer. - :return: The image as a CV2 object. - """ - - # When the image is provided as a string, - # it could be either as a URL or a path to a local file: - if isinstance(image, str): - if image.startswith("https://") or image.startswith("http://"): - image = io.BytesIO(requests.get(image).content) - else: image = cv2.imread(image) - - # If the image is provided as a io.BytesIO buffer: - if isinstance(image, io.BytesIO): - image.seek(0) - image = np.asarray(bytearray(image.read()), dtype = np.uint8) - image = cv2.imdecode(image, cv2.IMREAD_COLOR) - - # Done here: - return image - - @staticmethod - def polygon_area(points): - - """ - Computes the area occupied by a shape described by the array of points. - Example input: [[x1, y1], [x2, y2], [x3, y3], [x4, y4]] - :return: The area of the shape. - """ - - n = len(points) - area = 0.0 - for i in range(n): - j = (i + 1) % n # next vertex - area += points[i][0] * points[j][1] - area -= points[j][0] * points[i][1] - return abs(area) / 2.0 - - @staticmethod - def show(image, title = "Preview", wait = True): - - """ - Just a quick wrapper to show the image in a window. - :param image: The image that you want to show. - :param title: The title of the window. - :param wait: Set this to True when you want to show the window(s). This is useful when you want to show many - windows at once. Suppose you want to show a lot of windows, you set this to False for all calls except the - very last one. - :return: None. - """ - - cv2.imshow(title, image) - if wait: - cv2.waitKey() - cv2.destroyAllWindows() - - @staticmethod - def enhance(image): - - """ - Applies a form of contrast boost to make the edges more easily visible. - :param image: The OpenCV image that needs to be enhanced. - :return: The enhanced CV2 image. - """ - - return cv2.detailEnhance( - src = image, - sigma_s = 20, - sigma_r = 0.15 - ) - - @staticmethod - def get_edges(image): - - """ - Gets the edges in an image. - :param image: A CV2 image. - :return: The image with the edges detected. - """ - - # Denoise the image: - processed_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) - processed_image = cv2.GaussianBlur( - processed_image, - ksize = (5, 5), - sigmaX = 0 - ) - - # Detect edges in the image: - processed_image = cv2.Canny( - processed_image, - threshold1 = 50, - threshold2 = 200 - ) - - # Close small gaps in the edges: - kernel = np.ones((5, 5), np.uint8) - processed_image = cv2.dilate(processed_image, kernel, iterations = 1) - # processed_image = cv2.morphologyEx(processed_image, cv2.MORPH_CLOSE, kernel) - # processed_image = cv2.erode(processed_image, kernel, iterations = 1) - - # Done here: - return processed_image - - def scan(self, image, min_area = 0.125): - - """ - Looks for a rectangle in an image and flattens it out. No colour filters are applied here. - :param image: The image either as a path to a file on the local disk, or a URL, or an io.BytesIO buffer. - :param min_area: The minimum area occupied by the document in the image. - :return: The flattened image if any, else None. - """ - - # Open the image and read the data: - image = self.open_image(image) - if image is None: return None - height, width = image.shape[:2] - image_area = height * width - - # Enhance the image to have better visibility of edges: - # processed_image = self.enhance(image.copy()) - - # Detect edges in the image: - processed_image = self.get_edges(image.copy()) - - # Find the contours in the edges, - # and sort them in ascending order: - contours = cv2.findContours(processed_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) - contours = imutils.grab_contours(contours) - contours = sorted(contours, key = cv2.contourArea, reverse = True) - - # We try to get clean and passable contours. - # For our purposes, 'clean' is when it can be approximated to exactly 4 sides, - # and 'passable' is when the approximation comes close to it: - clean_rects = [] - passable_rects = [] - for contour in contours: - perimeter = cv2.arcLength(contour, closed = True) - approximation = cv2.approxPolyDP(contour, 0.025 * perimeter, closed = True) - if len(approximation) == 4: clean_rects.append(approximation) - elif len(approximation) <= 32: - candidate_contour = cv2.minAreaRect(approximation) - candidate_contour = cv2.boxPoints(candidate_contour) - candidate_contour = np.intp(candidate_contour) - passable_rects.append(candidate_contour) - clean_rects = sorted(clean_rects, key = cv2.contourArea, reverse = True) - passable_rects = sorted(passable_rects, key = cv2.contourArea, reverse = True) - - # Now we decide between the best candidate: - document_outline = None - if len(clean_rects) > 0: - candidate_rect = np.array([p[0] for p in clean_rects[0]]) - rectangle_area = cv2.contourArea(candidate_rect) - if rectangle_area / image_area >= min_area: document_outline = candidate_rect - if document_outline is None and len(passable_rects) > 0: - candidate_rect = cv2.minAreaRect(passable_rects[0]) - candidate_rect = cv2.boxPoints(candidate_rect) - candidate_rect = np.intp(candidate_rect) - rectangle_area = cv2.contourArea(candidate_rect) - if rectangle_area / image_area >= min_area: document_outline = candidate_rect - - # If there is no rectangular contour, - # we exit with failure: - if document_outline is None: return None - - # Since we did get the best candidate for the document, - # we figure out which point n the contour is which corner of the document: - document_rectangle = np.zeros((4, 2), dtype = "float32") - sum_points = document_outline.sum(axis = 1) - document_rectangle[0] = document_outline[np.argmin(sum_points)] - document_rectangle[2] = document_outline[np.argmax(sum_points)] - diff_points = np.diff(document_outline, axis = 1) - document_rectangle[1] = document_outline[np.argmin(diff_points)] - document_rectangle[3] = document_outline[np.argmax(diff_points)] - (top_left, top_right, bottom_right, bottom_left) = document_rectangle - - # let's compute the dimensions of the document in the image: - left_height = np.sqrt(((top_left[0] - bottom_left[0]) ** 2) + ((top_left[1] - bottom_left[1]) ** 2)) - right_height = np.sqrt(((top_right[0] - bottom_right[0]) ** 2) + ((top_right[1] - bottom_right[1]) ** 2)) - top_width = np.sqrt(((top_right[0] - top_left[0]) ** 2) + ((top_right[1] - top_left[1]) ** 2)) - bottom_width = np.sqrt(((bottom_right[0] - bottom_left[0]) ** 2) + ((bottom_right[1] - bottom_left[1]) ** 2)) - max_height = max(int(left_height), int(right_height)) - max_width = max(int(top_width), int(bottom_width)) - - # We compute the destination of the transform: - destination = np.array( - object = [ - [0, 0], - [max_width - 1, 0], - [max_width - 1, max_height - 1], - [0, max_height - 1] - ], - dtype = "float32" - ) - - # We apply the transform that flattens out the document: - matrix = cv2.getPerspectiveTransform(document_rectangle, destination) - flattened_image = cv2.warpPerspective(image, matrix, dsize = (max_width, max_height)) - - # Done here: - return flattened_image - - def extract_text( - self, - image, - min_confidence = 0.5, - margin = 0.05 - ): - - """ - To run OCR on the input image. - :param image: The image either as a path to a file on the local disk, or a URL, or an io.BytesIO buffer. - :param min_confidence: The minimum amount of confidence for detected text to be considered. - :param margin: The extra pixels to include when cropping into a section for OCR. - :return: The extracted text. - """ - - # Make a variable that will hold the final result: - extracted_text = {} - - # Open the image and read the data: - image = self.open_image(image) - height, width = image.shape[:2] - - # Run OCR on the entire canvas: - ocr_result = [r[1] for r in self.__ocr_engine.readtext(image) if r[-1] >= min_confidence] - extracted_text["fullDoc"] = " ".join(ocr_result) - - # Get the doc layout in the image: - document_sections = self.__yolo.predict(image) - document_sections = document_sections["boxes"] - - # For each section, we run the OCR process individually: - section_results = [] - for section in document_sections: - if section["class"] in self.__whitelisted_yolo_classes: - section_width = section["x2"] - section["x1"] - section_height = section["y2"] - section["y1"] - x1 = max(int(section["x1"] - (margin * section_width)), 0) - y1 = max(int(section["y1"] - (margin * section_height)), 0) - x2 = min(int(section["x2"] + (margin * section_width)), width) - y2 = min(int(section["y2"] + (margin * section_height)), height) - sub_image = image[y1:y2, x1:x2] - ocr_result = [r[1] for r in self.__ocr_engine.readtext(sub_image) if r[-1] >= min_confidence] - section_results.append({ - "text": " ".join(ocr_result), - "class": section["class"], - "className": section["className"], - "x1": x1, - "y1": y1, - "x2": x2, - "y2": y2 - }) - extracted_text["bySection"] = section_results - - # Done here: - return extracted_text - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import time - - my_scanner = DocumentScanner( - layout_detection_yolo = r"/home/developer/PycharmProjects/utils/data/ai/behaviour_models/hugging_face/object_detection/YOLOv10-Document-Layout-Analysis/yolov10x_best.pt", - whitelisted_yolo_classes = [0, 1, 3, 4, 5, 7, 9, 10], - # whitelisted_yolo_classes = [0, 1, 3, 4, 5, 6, 7, 8, 9, 10], - ocr_languages = ["en"] - ) - - image = my_scanner.open_image(r"/home/developer/Downloads/talkaholics_card.jpg") - document_image = my_scanner.scan(image) - if document_image is not None: - cv2.imwrite(r"/home/developer/Downloads/flattened_image.jpg", document_image) - start_time = time.time() - document_text = my_scanner.extract_text( - document_image, - min_confidence = 0.5 - ) - print("OCR RESULT:") - print(document_text) - - print(f"FINISHED IN {time.time() - start_time} SECONDS!") - - else: print("No image") diff --git a/utils_v2/image/scanner/scanner_v2.py b/utils_v2/image/scanner/scanner_v2.py deleted file mode 100644 index fc63627..0000000 --- a/utils_v2/image/scanner/scanner_v2.py +++ /dev/null @@ -1,379 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 24th Sept., 2024 - - OBJECTIVE: - - To provide a way to easily scan documents like printouts and visiting cards. - - REFERENCES: - - 01. https://medium.com/@victorolufemi/build-a-document-scanner-with-opencv-ff9f645a4085 - 02. https://github.com/JaidedAI/ - 03. https://github.com/criistian14/flutter_document_scanner/blob/master/flutter_document_scanner_android/android/src/main/kotlin/com/christian/flutterDocumentScanner/OpenCVPlugin.kt - 04. https://www.geeksforgeeks.org/python-bilateral-filtering/ - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# To work with image processing: -import cv2 -import imutils -import numpy as np - -# To run OCR: -import easyocr - -# To download images from the web: -import requests - -# My utils: -from utils_v2.string import json -from utils_v2.ai.object_detection.yolo import YoloDetect - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class DocumentScanner: - - def __init__( - self, - layout_detection_yolo = None, - whitelisted_yolo_classes = None, - ocr_languages = None - ): - - self.__yolo = YoloDetect( - model_file = layout_detection_yolo, - debug = False - ) - self.__whitelisted_yolo_classes = whitelisted_yolo_classes or [] - self.__ocr_engine = easyocr.Reader(ocr_languages or ["en"]) - pass - - @staticmethod - def open_image(image): - - """ - Opens an image from various sources. - :param image: The image either as a path to a file on the local disk, or a URL, or an io.BytesIO buffer. - :return: The image as a CV2 object. - """ - - # When the image is provided as a string, - # it could be either as a URL or a path to a local file: - if isinstance(image, str): - if image.startswith("https://") or image.startswith("http://"): - image = io.BytesIO(requests.get(image).content) - else: image = cv2.imread(image) - - # If the image is provided as a io.BytesIO buffer: - if isinstance(image, io.BytesIO): - image.seek(0) - image = np.asarray(bytearray(image.read()), dtype = np.uint8) - image = cv2.imdecode(image, cv2.IMREAD_COLOR) - - # Done here: - return image - - @staticmethod - def show(image, title = "Preview", wait = True): - - """ - Just a quick wrapper to show the image in a window. - :param image: The image that you want to show. - :param title: The title of the window. - :param wait: Set this to True when you want to show the window(s). This is useful when you want to show many - windows at once. Suppose you want to show a lot of windows, you set this to False for all calls except the - very last one. - :return: None. - """ - - cv2.imshow(title, image) - if wait: - cv2.waitKey() - cv2.destroyAllWindows() - - @staticmethod - def get_edges(image): - - """ - Apply all the preprocessing filters on the image before sending it off for contour-finding. - :param image: The image to pre-process. - :return: The pre-processed image. - """ - - # Denoise the image: - processed_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) - processed_image = cv2.bilateralFilter( - processed_image, - d = 9, - sigmaColor = 75, - sigmaSpace = 75 - ) - - # Detect edges in the image: - processed_image = cv2.Canny( - processed_image, - threshold1 = 75, - threshold2 = 200 - ) - - # Close small gaps in the edges: - kernel = np.ones((5, 5), np.uint8) - processed_image = cv2.dilate(processed_image, kernel, iterations = 1) - # processed_image = cv2.morphologyEx(processed_image, cv2.MORPH_CLOSE, kernel) - # processed_image = cv2.erode(processed_image, kernel, iterations = 1) - - # Done here: - return processed_image - - def scan(self, image, min_area = 0.125): - - """ - Looks for a rectangle in an image and flattens it out. No colour filters are applied here. - :param image: The image either as a path to a file on the local disk, or a URL, or an io.BytesIO buffer. - :param min_area: The minimum area occupied by the document in the image. - :return: The flattened image if any, else None. - """ - - # Open the image and read the data: - image = self.open_image(image) - if image is None: return None - height, width = image.shape[:2] - image_area = height * width - - # image = self.enhance(image) - processed_image = self.get_edges(image) - # self.show(processed_image) - - # Find the contours in the edges, - # and sort them in ascending order: - contours = cv2.findContours(processed_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) - contours = imutils.grab_contours(contours) - contours = sorted(contours, key = cv2.contourArea, reverse = True) - - # We try to get clean and passable contours. - # For our purposes, 'clean' is when it can be approximated to exactly 4 sides, - # and 'passable' is when the approximation comes close to it: - clean_rects = [] - passable_rects = [] - for contour in contours: - perimeter = cv2.arcLength(contour, closed = True) - approximation = cv2.approxPolyDP(contour, 0.025 * perimeter, closed = True) - if len(approximation) == 4: clean_rects.append(approximation) - elif len(approximation) <= 32: - candidate_contour = cv2.minAreaRect(approximation) - candidate_contour = cv2.boxPoints(candidate_contour) - candidate_contour = np.intp(candidate_contour) - passable_rects.append(candidate_contour) - clean_rects = sorted(clean_rects, key = cv2.contourArea, reverse = True) - passable_rects = sorted(passable_rects, key = cv2.contourArea, reverse = True) - - # Now we decide between the best candidate: - document_outline = None - if len(clean_rects) > 0: - candidate_rect = np.array([p[0] for p in clean_rects[0]]) - rectangle_area = cv2.contourArea(candidate_rect) - if rectangle_area / image_area >= min_area: document_outline = candidate_rect - if document_outline is None and len(passable_rects) > 0: - candidate_rect = cv2.minAreaRect(passable_rects[0]) - candidate_rect = cv2.boxPoints(candidate_rect) - candidate_rect = np.intp(candidate_rect) - rectangle_area = cv2.contourArea(candidate_rect) - if rectangle_area / image_area >= min_area: document_outline = candidate_rect - - # If there is no rectangular contour, - # we exit with failure: - if document_outline is None: return None - - # Since we did get the best candidate for the document, - # we figure out which point n the contour is which corner of the document: - document_rectangle = np.zeros((4, 2), dtype = "float32") - sum_points = document_outline.sum(axis = 1) - document_rectangle[0] = document_outline[np.argmin(sum_points)] - document_rectangle[2] = document_outline[np.argmax(sum_points)] - diff_points = np.diff(document_outline, axis = 1) - document_rectangle[1] = document_outline[np.argmin(diff_points)] - document_rectangle[3] = document_outline[np.argmax(diff_points)] - (top_left, top_right, bottom_right, bottom_left) = document_rectangle - - # let's compute the dimensions of the document in the image: - left_height = np.sqrt(((top_left[0] - bottom_left[0]) ** 2) + ((top_left[1] - bottom_left[1]) ** 2)) - right_height = np.sqrt(((top_right[0] - bottom_right[0]) ** 2) + ((top_right[1] - bottom_right[1]) ** 2)) - top_width = np.sqrt(((top_right[0] - top_left[0]) ** 2) + ((top_right[1] - top_left[1]) ** 2)) - bottom_width = np.sqrt(((bottom_right[0] - bottom_left[0]) ** 2) + ((bottom_right[1] - bottom_left[1]) ** 2)) - max_height = max(int(left_height), int(right_height)) - max_width = max(int(top_width), int(bottom_width)) - - # We compute the destination of the transform: - destination = np.array( - object = [ - [0, 0], - [max_width - 1, 0], - [max_width - 1, max_height - 1], - [0, max_height - 1] - ], - dtype = "float32" - ) - - # We apply the transform that flattens out the document: - matrix = cv2.getPerspectiveTransform(document_rectangle, destination) - flattened_image = cv2.warpPerspective(image, matrix, dsize = (max_width, max_height)) - - # Done here: - return flattened_image - - def extract_text( - self, - image, - min_confidence = 0.5, - margin = 0.05 - ): - - """ - To run OCR on the input image. - :param image: The image either as a path to a file on the local disk, or a URL, or an io.BytesIO buffer. - :param min_confidence: The minimum amount of confidence for detected text to be considered. - :param margin: The extra pixels to include when cropping into a section for OCR. - :return: The extracted text. - """ - - # Make a variable that will hold the final result: - extracted_text = {} - - # Open the image and read the data: - image = self.open_image(image) - height, width = image.shape[:2] - - # Run OCR on the entire canvas: - ocr_result = [r[1] for r in self.__ocr_engine.readtext(image) if r[-1] >= min_confidence] - extracted_text["fullDoc"] = " ".join(ocr_result) - - # Get the doc layout in the image: - document_sections = self.__yolo.predict(image) - document_sections = document_sections["boxes"] - - # For each section, we run the OCR process individually: - section_results = [] - for section in document_sections: - if section["class"] in self.__whitelisted_yolo_classes: - section_width = section["x2"] - section["x1"] - section_height = section["y2"] - section["y1"] - x1 = max(int(section["x1"] - (margin * section_width)), 0) - y1 = max(int(section["y1"] - (margin * section_height)), 0) - x2 = min(int(section["x2"] + (margin * section_width)), width) - y2 = min(int(section["y2"] + (margin * section_height)), height) - sub_image = image[y1:y2, x1:x2] - ocr_result = [r[1] for r in self.__ocr_engine.readtext(sub_image) if r[-1] >= min_confidence] - section_results.append({ - "text": " ".join(ocr_result), - "class": section["class"], - "className": section["className"], - "x1": x1, - "y1": y1, - "x2": x2, - "y2": y2 - }) - extracted_text["bySection"] = section_results - - # Done here: - return extracted_text - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import time - - my_scanner = DocumentScanner( - layout_detection_yolo = r"/home/developer/PycharmProjects/utils/data/ai/behaviour_models/hugging_face/object_detection/YOLOv10-Document-Layout-Analysis/yolov10x_best.pt", - whitelisted_yolo_classes = [0, 1, 3, 4, 5, 7, 9, 10], - # whitelisted_yolo_classes = [0, 1, 3, 4, 5, 6, 7, 8, 9, 10], - ocr_languages = ["en"] - ) - - image = my_scanner.open_image(r"/home/developer/Downloads/sushmita_card.jpg") - # image = my_scanner.open_image(r"/home/developer/Downloads/niranjan_card.jpg") - # image = my_scanner.open_image(r"/home/developer/Downloads/niranjan_card_2.jpg") - # image = my_scanner.open_image(r"/home/developer/Downloads/card_square.jpg") - document_image = my_scanner.scan(image) - if document_image is not None: - cv2.imwrite(r"/home/developer/Downloads/flattened_image.jpg", document_image) - start_time = time.time() - document_text = my_scanner.extract_text( - document_image, - min_confidence = 0.5 - ) - print("OCR RESULT:") - print(document_text) - - print(f"FINISHED IN {time.time() - start_time} SECONDS!") - - else: print("No image") diff --git a/utils_v2/logging/__init__.py b/utils_v2/logging/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/logging/__pycache__/__init__.cpython-310.pyc b/utils_v2/logging/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index f14ac0acad66a3ca250ff5e9cb77c08349fcd42a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170 zcmd1j<>g`kf)G>dbP)X*L?8o3AjbiSi&=m~3PUi1CZpd+BMHEL)oZ6Bg$u6*$1+%22wf9vn z<<`BX|Dq^h1HJTL^mp*uQ~yE^MTe9l_>z_Q&3wb*kQ@$~EG*avzTwVyGEl+;~aNy9Zj8lf5G++37*^P2QC!$M@aR#bG0k?q=1$t@|n z9+urQU7-5a;x&4wxfN<$Rj-k|1UBtzndGiDu&&Uhv)b>7YQN z6lw0A;ohZd#6H(quZV~~P_16VQw<^8cHnEB3}1KqPiI6Lewa+N2@ai}Gf0w{P<9r~ zI$ySi?OT2aEFk#ufwQ&6Cr;Prn-84r=JunRZ}-KU_Wtnj^!9*Z;!N-bb+D6hHud?G zQD>Aehfk;zCgaSBa1e87lqfr+<7tSQGn&Re50cpNaTsQsYSnU~!%2`i@F&4&L>Y~_ zGh#{f(QvKa;fDw+M8AE|?zcPp?ZK^0HMcgM3Fm3{w9)VMeZP=A*q|fXvLSp>ZWqHI27hlka1Bs3OHpr9R8|1_up%EUq-n789<&x z%gS)56hYk~S3g12a7~({d7?c-wBTAw*Fi73w$hDfh?s7PLY=K6@XIN_IOloAE5LKA zzW`%pJWJWDb9+(or8&11U!L=l;wy7rhB&pe8bn$EZ58C=jjY_vP*o%Dz=+w(mK47` z=gW$(&H0Mr>vLX{e1Ph!qVkHyGI>YIc$RBxl4Lx_5fyrp3BymP9bu#a5oRi}kh0{A z`dk=Lk)oKSFj$_3$m29PrA*|&en^A`Vt)d)Ds&EEIEHhASi=AUo3dbqiP<<4`SYKZ zEYe?ms?JqdjAm&PXS9A#Se_@>;(5aMyeJ{lQ0isR`)P{9o1V&`-9K&jz1Q8ru+utj zGx-_`1MZNhcpi@91ZIaNW-ziKoxJXVm86fQ*naPXm4UJa2{{S!#bS#RDiW3?EK69C z0B;}%*yD`%fcZJy7WCigF_XS2%q9 str_limit: value = value[:str_limit] + "..." - - # Done here: - return value - - @classmethod - def log_it( - cls, - api_version: str = None, - project: str = None, - log_type: str = None, - operation: str = None, - log_input: bool | int = True, - log_output: bool | int = True, - sensitive_keys: list = None - ): - - """ - A decorator factor that can be used to log the results of functions automatically. - :param api_version: A string that indicates the version code of the function being decorated. - :param project: A hint about which project is being worked on. - :param log_type: A hint about which module is being worked on. - :param operation: A hint about which action in a particular module is being worked on. - :param log_input: Set to True to capture everything that went into the function, False to capture the least - info, and set it to an integer to capture a certain depth of the input (applicable on iterables and dicts. - :param log_output: The same as 'log_input', but applicable to the response from the function. - :param sensitive_keys: Keys of a dict whose values must be obscured even if that depth is being captured. - :return: A decorator with the configuration. - """ - - def decorator(func): - - @wraps(func) - async def wrapper(*args, **kwargs): - - # Make variables and extract available info.: - exception = None - response = None - request_ts = date_time.get_current_utc_date_time() - start_ts = time.perf_counter() - cpu_start_ts = time.process_time() - - # Execute the function that is being wrapped: - try: response = await func(*args, **kwargs) - except Exception as exc: exception = exc - - # Do the next steps only if within the logging context: - if cls.get_logger() is not None: - - # Create the log: - if not args: args = None - if not kwargs: kwargs = None - func_log = GeneralLogModel( - pid = PROCESS_ID, - ppid = PARENT_PROCESS_ID, - project = project, - log = log_type or func.__name__, - operation = operation or func.__name__, - apiVer = api_version, - logId = cls.generate_log_id(), - logChain = cls.get_log_chain(), - ts = request_ts, - tat = time.perf_counter() - start_ts, - cpuTime = time.process_time() - cpu_start_ts, - func = func.__name__, - args = cls.summarize(args, expand = log_input, sensitive_keys = sensitive_keys), - kwargs = cls.summarize(kwargs, expand = log_input, sensitive_keys = sensitive_keys), - exception = None if exception is None else describe_exception(exception), - response = cls.summarize(response, expand = log_output, sensitive_keys = sensitive_keys), - ).model_dump() - - # Write the log: - await cls.get_logger().log(func_log) - - # Done here: - if exception is not None: raise exception - return response - - return wrapper - - return decorator - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - from utils_v2.database.async_mongo_v2 import AsyncMongo - - @AsyncLoggerContext.log_it( - api_version = "0.0.1", - project = "testProj", - log_type = "work", - operation = "someWork", - log_input = True, - log_output = True, - sensitive_keys = None - ) - async def some_work(*args, **kwargs): - print("SOME WORK:", AsyncLoggerContext.get_log_chain()) - await asyncio.sleep(max(2.0 * random.random(), 1.0)) - total = sum(args) - return total - - @AsyncLoggerContext.log_it( - api_version = "0.0.1", - project = "testProj", - log_type = "work", - operation = "moreWork", - log_input = True, - log_output = True, - sensitive_keys = ["password", "sessionToken"] - ) - async def more_work(*args, **kwargs): - print("MORE WORK:", AsyncLoggerContext.get_log_chain()) - await asyncio.sleep(max(2.0 * random.random(), 1.0)) - return {"success": True, "sessionToken": "1234567890"} - - @AsyncLoggerContext.log_it( - api_version = "0.0.1", - project = "testProj", - log_type = "work", - operation = "moreWork", - log_input = True, - log_output = True, - sensitive_keys = None - ) - async def last_work(*args, **kwargs): - print("LAST WORK:", AsyncLoggerContext.get_log_chain()) - await asyncio.sleep(max(2.0 * random.random(), 1.0)) - - async def main(chain = None): - - # Connect to MongoDB: - mongo = AsyncMongo( - connection_string = r"mongodb://del.ditscentre.in:27017,wtt.ditscentre.in:27017,mum.arh.001.ditscentre.in:27017/admin?tls=true&tlsCAFile=%2Fetc%2Fssl%2Fcerts%2Fmongo_data_ca.pem&tlsCertificateKeyFile=%2Fetc%2Fssl%2Fcerts%2Fmongo_data_cert.pem&replicaSet=dits_mongod_rep&readPreference=primary&authMechanism=MONGODB-X509&authSource=%24external", - database_name = "converse", - max_connections = 10, - debug = True - ) - - # Convert the connection to a logger instance that can be injected - # into the context as a dependency: - mongo_logger = AsyncMongoLogger( - db_conn = mongo, - collection = "logs" - ) - - # Initialize the context: - async with AsyncLoggerContext.logging_context( - logger = mongo_logger, - log_chain = chain - ): - - # Run some functions within the context: - await some_work(1, 2, 3, 4, 5) - await more_work(username = "john.doe@domain.com", password = "mySecretPass") - - # Run something outside the context: - await last_work() - - # async def multi_main(): - # tasks = [ - # main(chain = "kPRwXdItb1"), - # main(chain = "456") - # ] - # await asyncio.gather(*tasks) - - asyncio.run(main(chain = "00wGHRFYPY123")) diff --git a/utils_v2/logging/model.py b/utils_v2/logging/model.py deleted file mode 100644 index 355d07e..0000000 --- a/utils_v2/logging/model.py +++ /dev/null @@ -1,131 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Friday, 11th Oct., 2024 - - OBJECTIVE: - - To have a structure for the logs maintained for regular function calls. - This is different from the logs maintained for API calls. - - REFERENCES: - - 01. https://chatgpt.com/share/6708b6c9-6ba4-800f-9ea9-00ec35067512 - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# System-level activities: -import distro -import socket -import platform - -# For data-modelling: -from pydantic import BaseModel, Field -from typing import Any, Optional, List, Literal - -# To work with date and time: -import datetime - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# Info for logging that will stay constant during runtime: -SERVER_HOSTNAME = str(socket.gethostname()) -PLATFORM_INFO = platform.uname() -HOST_OS = str(distro.name(True)) -HOST_CPU = f"{PLATFORM_INFO.processor} ({PLATFORM_INFO.machine})" - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class GeneralLogModel(BaseModel): - - # To identify the machine the code is running on. - # DO NOT MODIFY THESE: - hostname: str = SERVER_HOSTNAME - os: str = HOST_OS - cpu: str = HOST_CPU - # Can modify these: - pid: Optional[Any] = None - ppid: Optional[Any] = None - - # To identify the project and actions: - project: Optional[str] = None - log: str - operation: Optional[str] = None - apiVer: Optional[str] = None - logId: Optional[str] = None - logChain: Optional[str] = None - - # Timing metrics: - ts: datetime.datetime - tat: float - cpuTime: float - - # To understand the inputs: - func: str - args: Optional[Any] = None - kwargs: Optional[Any] = None - - # To understand the outputs: - exception: Optional[Any] = None - response: Optional[Any] = None - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/mail/__init__.py b/utils_v2/mail/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/mail/async_smpt.py b/utils_v2/mail/async_smpt.py deleted file mode 100644 index 0e8ed06..0000000 --- a/utils_v2/mail/async_smpt.py +++ /dev/null @@ -1,443 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 16th Jul, 2024 - - OBJECTIVE: - - To be able to send out mails from code. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For working with mails: -import aiosmtplib -from email.mime.multipart import MIMEMultipart -from email.mime.image import MIMEImage -from email.mime.text import MIMEText -from email.mime.base import MIMEBase -from email import encoders - -# For random strings: -import string -import random - -# For system-level activities: -import os - -# For working with files in RAM: -import io - -# For debugging: -from icecream import IceCreamDebugger - -# To work with datatypes: -from typing import List - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class SMTPMessage: - - def __init__( - self, - to_email: str, - subject: str, - cc_emails: List[str] = None, - bcc_emails: List[str] = None - ): - - """ - Create an instance of the message that you would like to send. - :param to_email: The EMail ID of th recipient. - :param subject: The subject of the mail. - :param cc_emails: A list of recipients to add to the CC section. - :param bcc_emails: A list of recipients to add to the BCC section. - """ - - self.message = MIMEMultipart() - self.message["To"] = to_email - self.message["Subject"] = subject - if cc_emails: self.message["CC"] = ",".join(cc_emails) - if bcc_emails: self.message["BCC"] = ",".join(bcc_emails) - - def add_text(self, text): - - """ - Add plain-text to the mail body. - :param text: The text to add to the mail body. - :return: None. - """ - - self.message.attach(MIMEText(text, "plain")) - - def add_html(self, html_text): - - """ - Add HTML text to the mail body. - :param html_text: The HTML text to add to the mail body. - :return: None. - """ - - self.message.attach(MIMEText(html_text, "html")) - - def add_inline_image(self, image_file, content_id = None): - - """ - Add an inline image to the body of the mail. - NOTE: This is NOT the same as sending an image as an attachment. - :param image_file: The image data to attach to the mail body. - :param content_id: Inline images are inserted via HTML bocks. This field identifies the image resource. If not - specified, I will generate a random string. You may write a custom value here if you know what you are - doing. For most use cases, please ignore this field. - :return: None. - """ - - # Read the image as bytes: - image_bytes = None - if type(image_file) is str: - with open(image_file, "rb") as opened_image_file: - image_bytes = opened_image_file.read() - if type(image_file) is io.BytesIO: - image_file.seek(0) - image_bytes = image_file.getvalue() - - # Declare the part to be attached to the multipart message: - if image_bytes is not None: - - # Create the HTML block if the image pointer is blank: - if content_id is None: - content_id = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8)) - self.add_html(f""" - - -

    - - - """) - - # Then add the image: - image_part = MIMEImage(image_bytes) - image_part.add_header("Content-ID", f"<{content_id}>") - self.message.attach(image_part) - - def add_attachment(self, attachment_file, file_name = None): - - # Declare the part to be attached to the multipart message: - part = MIMEBase("application", "octet-stream") - - # If the attachment is a file stored in the local disk: - if isinstance(attachment_file, str): - file_name = file_name or os.path.split(attachment_file)[-1] - with open(attachment_file, "rb") as attachment: - part.set_payload(attachment.read()) - - # If the file is held in RAM: - elif isinstance(attachment_file, io.BytesIO): - attachment_file.seek(0) - part.set_payload(attachment_file.read()) - - # Encode and attach the file: - encoders.encode_base64(part) - part.add_header( - "Content-Disposition", - f"attachment; filename= {file_name}", - ) - self.message.attach(part) - - def get_message(self): - return self.message - - -# --------------------------------------------------------------------------------------------------------------------- - - -class AsyncSMTPClient: - - # Constants: - SMTP_TLS_PORT = 587 - SMTP_SSL_PORT = 465 - - # variables: - __smtp = None - - def __init__( - self, - email, - password, - server, - port = 587, - rate_limiters = None, - wait_for_turn = True, - debug = True, - debug_prefix = "Mail (C) | " - ): - - """ - Set up the mail client. - :param email: The Email ID to use when sending out mails. - :param password: The password of the EMail ID that is being used. - :param server: The EMail server. - :param port: The port number to connect to the host. - :param rate_limiters: The rate limiters to use. Must have "get_turn" and "has_turn" methods. "get_turn" method - must wait for the turn, and "has_turn" method must only check if a turn is available. - :param wait_for_turn: To wait for turn if the rate limit has been exceeded, or to return with failure. - :param debug: Whether, or not, you want to print debugging messages. - :param debug_prefix: The prefix to identify the debugging messages. - """ - - # Initialize the debugger: - self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self.__printer.disable() - - # Note down the credentials and other details: - self.__email = email - self.__password = password - self.__server = server - self.__port = port - self.__rate_limiters = rate_limiters if type(rate_limiters) is list else ([rate_limiters] if rate_limiters is not None else []) - self.__wait_for_turn = wait_for_turn - - def enable_debug(self): - self.__printer.enable() - - def disable_debug(self): - self.__printer.disable() - - async def login(self): - - """ - To connect to the mail server and authenticate the user. - :return: True if authenticated, else False. - """ - - # Initialize the SMTP connection, - # and return with success if all goes well: - try: - self.__smtp = aiosmtplib.SMTP( - hostname = self.__server, - port = self.__port, - use_tls = False, - start_tls = False - ) - await self.__smtp.connect() - await self.__smtp.starttls() - await self.__smtp.login(self.__email, self.__password) - return True - - # Return with failure if something goes wrong: - except Exception as exception: - self.__printer(exception) - try: await self.__smtp.quit() - except Exception as exception: self.__printer(exception) - self.__smtp = None - return False - - async def ensure_connection(self): - - """ - Can be run before the sending operation to confirm that we are yet connected to the server. - If not connected, this code will reattempt to connect and log-in. - :return: True if connected, else False. - """ - - # If the login had failed initially, the object will be set to null. - # In such a case, we make an attempt to login: - if self.__smtp is None: - return await self.login() - - # If the login was successful, we check if the connection is active. - # If not, we try to re-login: - if self.__smtp.is_connected: - return True - else: - try: - await self.__smtp.connect() - await self.__smtp.starttls() - await self.__smtp.login(self.__email, self.__password) - return True - except Exception as exception: - self.__printer(exception) - try: await self.__smtp.quit() - except Exception as exception: self.__printer(exception) - self.__smtp = None - return False - - async def logout(self): - - """ - Closes the connection to the SMTP client. - :return: True by default. - """ - - if self.__smtp is not None: - try: await self.__smtp.quit() - except Exception as exception: self.__printer(exception) - self.__smtp = None - return True - - async def send(self, mail: SMTPMessage): - - """ - Send out the mail. - :param mail: The instance of 'MailMessage' with all the content populated. - :return: A dict with 'success' and 'message'. - """ - - # Return with failure if we aren't connected, - # and our attempt to (re)connect fails: - if not await self.ensure_connection(): - return { - "success": False, - "message": "login failed" - } - - # Comply with the rate-limit: - for rate_limiter in self.__rate_limiters: - if not self.__wait_for_turn: - if not await rate_limiter.has_turn(): return False - got_turn = await rate_limiter.get_turn() - if not got_turn: - return { - "success": False, - "message": "rate-limit wait timeout" - } - - # Try to send the message: - try: - mail.message["From"] = self.__email - response = await self.__smtp.send_message(mail.message) - return { - "success": True, - "message": f"mail accepted - {response[-1]}" - } - - # If something goes wrong: - except Exception as exception: - self.__printer(exception) - return { - "success": False, - "message": str(exception) - } - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - from utils_v2.string import json - - async def test(): - - mail_client = AsyncSMTPClient( - email = "sender@gmail.com", - password = "zcaf nmqy ncfz fave", - server = "smtp.gmail.com", - rate_limiters = None - ) - - my_mail = SMTPMessage( - to_email = "orangebhopli@gmail.coms", - subject = "Bhopli is the best!", - cc_emails = None, - bcc_emails = None - ) - my_mail.add_html( - """ - - - - - Sample HTML String - - - -

    Hello, Bhopli!

    -

    Bhopli is the best, most well-behaved cat in the known universe.

    - - - """ - ) - my_mail.add_text("This is how you should pet her 👇") - my_mail.add_inline_image(r"/path/to/image/cat_petting.png") - my_mail.add_attachment(r"/path/to/file/sample_label.pdf") - - await mail_client.login() - result = await mail_client.send(my_mail) - print("MAIL RESULT:", json.to_string(result)) - await mail_client.logout() - - asyncio.run(test()) diff --git a/utils_v2/mail/mail_parser.py b/utils_v2/mail/mail_parser.py deleted file mode 100644 index 7229112..0000000 --- a/utils_v2/mail/mail_parser.py +++ /dev/null @@ -1,177 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 26th Nov., 2024 - - OBJECTIVE: - - To parse raw mail bodies and give a structure that is suitable for storing in No-SQL databases like MongoDB. The - raw mail's text is expected to be compliant with standard defined in RFC 5322, RFC 2045, and maybe a few more. - - REFERENCES: - - 1. GitHub: https://github.com/SpamScope/mail-parser - 2. RFC 5322: https://datatracker.ietf.org/doc/html/rfc5322 - 3. RFC 2045: https://datatracker.ietf.org/doc/html/rfc2045 - - DOWNLOADS: - - N/A - -""" -import base64 -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# My utils: -from utils_v2.string import json -from utils_v2.string import regex -from utils_v2.date_time import date_time - -# To work with mails: -import mailparser - -# To parse the HTML content in the mail: -from bs4 import BeautifulSoup - -# To work with datatypes: -from typing import Any, Dict - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def parse(raw_mail: str | bytes) -> Dict[str, Any]: - - """ - To parse the raw mail text to a usable JSON that can even be stored on a No-SQL database like MongoDB. - DOCUMENTATION: - 1. GitHub: https://github.com/SpamScope/mail-parser - 2. RFC 5322: https://datatracker.ietf.org/doc/html/rfc5322 - 3. RFC 2045: https://datatracker.ietf.org/doc/html/rfc2045 - :param raw_mail: The raw mail body that adheres to RFC 5322 and RFC 2045 (among others). - :return: The parsed JSON format (dict) of the mail. - """ - - # Parse the raw format: - if isinstance(raw_mail, str): parsed_mail = mailparser.parse_from_string(raw_mail) - else: parsed_mail = mailparser.parse_from_bytes(raw_mail) - - # Format the attachments: - message_attachments = [ - { - "filename": attachment["filename"], - "type": attachment["mail_content_type"], - "cid": regex.find_first(text = attachment["content-id"], pattern = r"(?<=<).*(?=>)"), - "rawCid": attachment["content-id"], - "contentDisposition": (cd := attachment["content-disposition"]), - "isInline": True if cd.lower().find("inline") >= 0 else False, - "charset": attachment["charset"], - "contentTransferEncoding": attachment["content_transfer_encoding"], - "payload": attachment["payload"] - } for attachment in parsed_mail.attachments - ] - - # Figure out which entity (text and HTML) came in which sequence. - # The library doesn't give us any sequence info so we do some custom string processing here to figure out the order - # in which to render the contents of the page. - parts = [ - { - "no": None, - "offset": max( - parsed_mail.message_as_string.find(t), - parsed_mail.message_as_string.find(base64.b64encode(t.encode()).decode()) - ), - "type": "text/plain", - "data": t - } for t in parsed_mail.text_plain - ] - parts = parts + [ - { - "partNo": None, - "offset": max( - parsed_mail.message_as_string.find(h), - parsed_mail.message_as_string.find(base64.b64encode(h.encode()).decode()) - ), - "type": "text/html", - "data": h - } for h in parsed_mail.text_html - ] - parts = sorted(parts, key = lambda x: x["offset"]) - for i, p in enumerate(parts): p["no"] = i - - # Get the unformatted text from everything in the mail: - unformatted_text = [] - for p in parts: - if p["type"] == "text/html": - html_parser = BeautifulSoup(p["data"], "html.parser") - unformatted_text.append(html_parser.get_text()) - else: unformatted_text.append(p["data"]) - - # Put everything together: - return { - "ts": date_time.to_timezone(parsed_mail.date, timezone = date_time.TIMEZONE_UTC), - "headers": parsed_mail.headers, - "from": [{"name": _[0] or _[1], "email": _[1]} for _ in parsed_mail.headers["From"]], - "to": [{"name": _[0] or _[1], "email": _[1]} for _ in parsed_mail.headers["To"]], - "cc": [{"name": _[0] or _[1], "email": _[1]} for _ in parsed_mail.headers.get("Cc", [])], - "bcc": [{"name": _[0] or _[1], "email": _[1]} for _ in parsed_mail.headers.get("Bcc", [])], - "text": parsed_mail.text_plain, - "html": parsed_mail.text_html, - "parts": parts, - "unformattedText": "\n".join(unformatted_text), - "attachments": message_attachments, - } - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/network/__init__.py b/utils_v2/network/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/network/ip.py b/utils_v2/network/ip.py deleted file mode 100644 index 134078f..0000000 --- a/utils_v2/network/ip.py +++ /dev/null @@ -1,173 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Friday, 12th Jul., 2024 - - OBJECTIVE: - - To provide an easy way to get geolocation information of an IP address. - - REFERENCES: - - 1) https://medium.com/@tubelwj/how-to-retrieve-ip-geolocation-information-in-python-929e15041e3e - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For working with IP Addresses: -import ipaddress - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def ipv4_to_int(ip_string): - - """ - Converts an IP (v4) string to an integer value. - :param ip_string: The IP address (v4) that you want to convert to integer format. - :return: An integer representation of the IP (v4) address. - """ - - ip_numerical = int(ipaddress.IPv4Address(ip_string)) - return ip_numerical - - -# --------------------------------------------------------------------------------------------------------------------- - - -def int_to_ipv4(ip_numerical): - - """ - Interprets the IP (v4) value from the given integer value. - :param ip_numerical: The integer value that represents an IP (v4) address. - :return: - """ - - ip_string = str(ipaddress.IPv4Address(ip_numerical)) - return ip_string - - -# --------------------------------------------------------------------------------------------------------------------- - - -def ipv4_to_bin(ip_string): - - """ - Converts an input IP (v4) address to the binary string that represents the 32 bits. - :param ip_string: The IP (v4) string in a format like "192.168.0.1" - :return: The binary representation (as a string) of the input IP address. - """ - - ip_binary = bin(int(ipaddress.IPv4Address(ip_string)))[2:].zfill(32) - return ip_binary - - -# --------------------------------------------------------------------------------------------------------------------- - - -def bin_to_ipv4(ip_binary): - - """ - Interprets the IP (v4) value from the given binary string. - :param ip_binary: The string of 1s and 0s that represents the IP (v4) address. - :return: The IP (v4) address as a string. - """ - - ip_string = str(ipaddress.IPv4Address(int(ip_binary, 2))) - return ip_string - - -# --------------------------------------------------------------------------------------------------------------------- - - -def get_ipv4_range(ip_string, as_string = True): - - """ - Given a network description in the format "88.95.100.128/25", this function tells you the first and last IP - addresses of that network. Useful for determining if an IP address lies in a network. - :param ip_string: The input network description in the format "88.95.100.128/25" - :param as_string: To select between integer and string formats for the IP range output. - :return: The first and last IP addresses of the input network, and the count. - """ - - # Extract the components of the string: - ip_components = ip_string.split("/") - ip_addr = ipv4_to_int(ip_components[0]) - ip_bits = int(ip_components[1]) - - # Convert the mask number to binary representation: - ip_mask = (1 << ip_bits) - 1 - ip_mask = ip_mask << (32 - ip_bits) - inv_ip_mask = (~ip_mask) & 0xFFFF - - # Figure out the start and end IP addresses: - start_ip = ip_addr & ip_mask - end_ip = ip_addr | inv_ip_mask - count = end_ip - start_ip + 1 - - # If the IPs are needed as strings, we perform the conversion: - if as_string: - start_ip = int_to_ipv4(start_ip) - end_ip = int_to_ipv4(end_ip) - - # Done here: - return start_ip, end_ip, count - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - print(ipv4_to_int("255.255.255.255")) - print(ipv4_to_int("x.x.x.x")) diff --git a/utils_v2/network/ping.py b/utils_v2/network/ping.py deleted file mode 100644 index 39e42c7..0000000 --- a/utils_v2/network/ping.py +++ /dev/null @@ -1,218 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Friday, 28th Jun, 2024 - - OBJECTIVE: - - To provide a way to ping a server and get the traceroute dump. - - REFERENCES: - - 1) https://www.geeksforgeeks.org/traceroute-implementation-on-python/ - - DOWNLOADS: - - N/A - -""" - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -# --- -import sys -sys.path.append(".") -sys.path.append("..") - -# Utils: -# --- -from utils import json_utils -from utils import time_utils -from utils import regex_utils - -# For networking: -# --- -import socket -from scapy.all import * - -# For running the script from the terminal: -# --- -import argparse - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def get_name_and_addr(destination): - - # If the user provided the IP address: - # --- - if ( - regex_utils.match(destination, regex_utils.REGEX_IPV4) or - regex_utils.match(destination, regex_utils.REGEX_IPV6) - ): - try: destination_name = socket.gethostbyaddr(destination)[0] - except Exception as exception: destination_name = "*" - destination_ip = destination - - # If the provided destination was the domain name: - # --- - else: - destination_name = destination - try: destination_ip = socket.gethostbyname(destination) - except Exception as exception: destination_ip = "*" - - # Done here: - # --- - return destination_name, destination_ip - - -# --------------------------------------------------------------------------------------------------------------------- - - -def tracert( - destination, - max_hops = 30, - timeout = 2.0, - port = 33434 -): - - # Initialize the variables: - # --- - destination_name, destination_ip = get_name_and_addr(destination) - full_trace = [] - ttl = 1 - - # Keep noting hops till the limit is reached: - # --- - while ttl <= max_hops: - - # Create a JSON for this stage: - # --- - this_hop = { - "destAddr": destination_ip, - "destName": destination_name, - "hopNo": ttl - 1, - "isDest": False, - "hopAddr": None, - "hopName": None, - "ts": None - } - - # Create the IP and UDP headers and combine them: - # --- - ip_packet = IP(dst = destination, ttl = ttl) - udp_packet = UDP(dport = port) - trace_packet = ip_packet / udp_packet - - # Send the packet and receive a reply and note down the timestamp: - # --- - reply = sr1(trace_packet, timeout = timeout, verbose = 0) - this_hop["ts"] = time_utils.get_current_utc_datetime(as_string = True) - - # No response: - # --- - if reply is None: this_hop["hopAddr"] = this_hop["hopName"] = "*" - - # If some response was received, we note the values and break out if this was the destination hop: - # --- - else: - this_hop["hopName"], this_hop["hopAddr"] = get_name_and_addr(f"{reply.src}") - if reply.type == 3: - this_hop["isDest"] = True - full_trace.append(this_hop) - break - - # Carry on to the next hop: - # --- - full_trace.append(this_hop) - ttl += 1 - - # Done here: - # --- - return full_trace - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser(description = "Traceroute Implementation in Python!") - - parser.add_argument( - "dest", - help = "Destination (Name or IP address)." - ) - parser.add_argument( - "-m", - "--max-hops", - type = int, - default = 30, - help = - "Maximum number of hops (default: 30)." - ) - parser.add_argument( - "-t", - "--timeout", - type = float, - default = 2.0, - help = "Timeout for each packet in seconds (default: 2.0)." - ) - parser.add_argument( - "-p", - "--port", - type = int, - default = 33434, - help = "Timeout for each packet in seconds (default: 33434)." - ) - - args = parser.parse_args() - - trace = tracert( - destination = args.dest, - max_hops = args.max_hops, - timeout = args.timeout, - port = args.port - ) - print("TRACE:") - print(json_utils.to_json_string(trace)) diff --git a/utils_v2/pdf/__init__.py b/utils_v2/pdf/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/pdf/pdf_maker.py b/utils_v2/pdf/pdf_maker.py deleted file mode 100644 index fb97cdd..0000000 --- a/utils_v2/pdf/pdf_maker.py +++ /dev/null @@ -1,1642 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Tuesday, 13th Aug., 2024 - - OBJECTIVE: - - To generate custom PDFs. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For conversion to PDF: -from PyPDF2 import PdfMerger, PdfReader, PdfWriter, Transformation - -# For barcode and QR code generation: -import xml.etree.ElementTree as ET -from barcode import Code128 -from barcode.writer import ImageWriter, SVGWriter -import segno -from PIL import Image, ExifTags, ImageFilter - -# System-level activities: -import os -import io -import inspect -import contextlib - -# For calculations: -import math - -# For PDF generation: -import fitz -from reportlab.pdfgen import canvas -from reportlab.lib.units import mm, cm, inch -from reportlab.lib.styles import ParagraphStyle -from reportlab.platypus import Paragraph -from reportlab.pdfbase import pdfmetrics -from reportlab.pdfbase.ttfonts import TTFont -from reportlab.lib.utils import ImageReader -from reportlab.graphics import renderSVG - -# My utils: -from utils_v2.string import json -from utils_v2.system import files -from utils_v2.string import regex - -# For debugging: -from icecream import IceCreamDebugger -import traceback - -# For random string generation: -import random -import string - -# To validate the font file: -from fontTools import ttLib - -# To make http calls: -import requests -import httpx - -# To work with base64 coding: -import base64 - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make async API calls: -max_connections = 5 -limits = httpx.Limits( - max_keepalive_connections = max_connections, - max_connections = max_connections, - keepalive_expiry = 3600 -) -http_client = httpx.AsyncClient( - limits = limits, - follow_redirects = False, - timeout = httpx.Timeout(None) -) - -# Headers for downloading files: -HEADERS_DOWNLOAD = { - "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:129.0) Gecko/20100101 Firefox/129.0", - "Accept": "*/*", - "Accept-Encoding": "gzip, deflate" -} - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class PDFMaker: - - def __init__( - self, - width, - height, - unit = "mm", - dpi = 72, - debug = True, - debug_prefix = "PDF (M) | ", - raise_exception = True, - **kwargs - ): - - """ - IMPORTANT: To keep things intuitively oriented (left-to-right, and top-to-bottom), the internal bottom-up - coordinates have been flipped mathematically. All measurements start from the top-left corner. Moreover, I have - ensured that all numbers follow the same units. So, if you set your unit to "inch", everything will be measured - in the same unit. I hope this creates maximum consistency for you. - A NOTE ON IMAGES: All images will be measured in pixels when operating on them directly (like cropping and - resizing), but will be measured in the 'unit' of the canvas when placing it in the PDF. - A NOTE OF FONT SIZES: Font sizes (and their line spacings) are measured in 'points'. As per the standard, there - are 72 'points' in one inch. While everything else in this utility uses the unit of measurement defined in the - 'unit' param, fonts need to be specified in 'points' to maintain compatibility with HTML rendering engines to - work with well-formatted paragraphs. - WARNING: I STRONGLY RECOMMEND NOT USING DPI AS A SETTING. THE PDF FORMAT ITSELF DOESN'T HAVE ANY PROVISION FOR - PIXEL DENSITY. THIS SETTING HAS BEEN MADE AVAILABLE FOR PLACEBO EFFECT WHEN CLIENTS ASK FOR VERY HIGH RESOLUTION - FILES WITHOUT WANTING TO UNDERSTAND ANY TECHNICALITY. USE WITH CAUTION. - :param width: [int|float] The width of the page (in the specified unit). - :param height: [int|float] The height of the page (in the specified unit). - :param unit: [str] The unit ("mm", "cm", "inch") to use. - :param dpi: [int|float] The pixel density. AVOID USING THIS. - :param debug: [bool] Whether, or not, you want to print debugging messages. Can be changed on the fly. - :param debug_prefix: [str] The prefix to show in debugging messages. - :param raise_exception: If set to True, any failure will immediately stop the PDF building process. If set to - False, the PDF building will continue by ignoring failed steps. Set to True by default for an all-or-nothing - output behaviour. - :param kwargs: Just a placeholder, does nothing for now (20240904). - """ - - # For debugging: - self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self.__printer.disable() - - # Note down the exception-handling choice: - self.__raise_exception = raise_exception - - # We pick the unit from the user's choice: - self.__unit = { - "mm": mm, - "cm": cm, - "inch": inch - }[unit] - - # To know the canvas size multipliers, we need a few parameters: - # 01. The DPI Factor is the multiplier to apply to achieve the target DPI considering a default DPI of 72, - # 02. The Unit Factor is the multiplier to apply to the unit to achieve a high-res result. - self.__dpi_factor = (dpi / 72.0) - self.__unit_factor = self.__unit * self.__dpi_factor - - # Now we create the canvas: - self.__pdf_in_ram = io.BytesIO() - self.__canvas_width = width * self.__unit_factor - self.__canvas_height = height * self.__unit_factor - self.__canvas = canvas.Canvas( - self.__pdf_in_ram, - pagesize = (self.__canvas_width, self.__canvas_height) - ) - - def enable_debug(self): - - """ - To enable the debugging text in the terminal. - :return: None. - """ - - self.__printer.enable() - - def disable_debug(self): - - """ - To disable the debugging text in the terminal. - :return: None. - """ - - self.__printer.disable() - - # ┏┓┓ ┓ ┳┳ •┓• • - # ┗┓┣┓┏┓┏┓┏┓┏┫ ┃┃╋┓┃┓╋┓┏┓┏ - # ┗┛┛┗┗┻┛ ┗ ┗┻ ┗┛┗┗┗┗┗┗┗ ┛ - - @staticmethod - async def download_from_url(url, follow_redirects = False): - - """ - Download a file from a URL. - :param url: The URL to download the file from. - :param follow_redirects: Whether, or not, to follow along with any redirects when downloading the file. - :return: The downloaded file or None. - """ - - file = io.BytesIO((await http_client.get( - url, - headers = HEADERS_DOWNLOAD, - follow_redirects = follow_redirects - )).content) - file.seek(0) - return file - - @staticmethod - def read_to_ram(file_path): - - """ - Reads a file into a BytesIO object in RAM. - NOTE: The method doesn't itself verify if the file is a PDF. - :param file_path: The path to the file on disk. - :return: The file in a BytesIO object. - """ - - with open(file_path, "rb") as file: - file_data = file.read() - file_in_ram = io.BytesIO(file_data) - file_in_ram.seek(0) - return file_in_ram - - def __parse_color(self, input_color): - - """ - The reportlab 'reportlab' needs the colour to be specified in an array of RGS values where each value is a - number in the range 0-1. - :param input_color: Either a hex string or an array of numbers. - :return: An array that can be used by 'reportlab'. - """ - - # Start by assuming failure: - processed_color = None - - # If the input color is a string, we convert from hex to an array of hex codes: - if isinstance(input_color, str): - input_color = input_color.lstrip("#") - color_tuple = ( - input_color[0:2].upper(), - input_color[2:4].upper(), - input_color[4:6].upper() - ) - input_color = color_tuple - - # If the input color is a list/tuple of hex-strings: - if isinstance(input_color, (list, tuple)): - try: - if all(isinstance(item, str) for item in input_color): - processed_color = [int(item, 16) / 255.0 for item in input_color] - elif all(isinstance(item, (float, int)) for item in input_color): - processed_color = [max(min(item, 255.0), 0.0) / 255.0 for item in input_color] - except: - if self.__raise_exception: raise - - # Done here: - return processed_color - - def __parse_x(self, *args): - - """ - To adjust the horizontal coordinates for the canvas. - :param args: As many horizontal coordinates as you would like to adjust. - :return: The adjusted coordinates. - """ - - if len(args) == 0: return None - parsed_x = [x * self.__unit_factor for x in args] - parsed_x = [x if x >= 0 else x + self.__canvas_width for x in parsed_x] - return tuple(parsed_x) if len(parsed_x) > 1 else parsed_x[0] - - def __parse_y(self, *args, flip = False): - - """ - To adjust the vertical coordinates for the canvas. - :param args: As many vertical coordinates as you would like to adjust. - :param flip: To convert from bottom-up system to top-down system. - :return: The adjusted coordinates. - """ - - if len(args) == 0: return None - parsed_y = [y * self.__unit_factor for y in args] - parsed_y = [y if y >= 0 else y + self.__canvas_height for y in parsed_y] - if flip: parsed_y = [self.__canvas_height - y for y in parsed_y] - return tuple(parsed_y) if len(parsed_y) > 1 else parsed_y[0] - - def __parse_font_size(self, *args): - - """ - Adjust the font size. - :param args: The font sizes to adjust - :return: The adjusted font-size. - """ - - if len(args) == 0: return None - parsed_font_sizes = args - return parsed_font_sizes if len(parsed_font_sizes) > 1 else parsed_font_sizes[0] - - @staticmethod - def _parse_coordinates_for_rotation( - original_x, - original_y, - angle - ): - - """ - Adjusts the x and y coordinates to compensate for the effect of a rotation operation. - :param original_x: The x coordinate before applying rotation. - :param original_y: The y coordinate before applying rotation. - :param angle: The angle (in degrees) by which the rotation will be applied. - :return: The adjusted x and y coordinates that compensate for the effect of the canvas's rotation. - """ - - # Get the angle in radians: - angle_radians = math.radians(angle) - angle_cos = math.cos(angle_radians) - angle_sin = math.sin(angle_radians) - - # Compute the inverse rotation: - adjusted_x = original_x * angle_cos + original_y * angle_sin - adjusted_y = -original_x * angle_sin + original_y * angle_cos - - # Done here: - return adjusted_x, adjusted_y - - # ┳ ┏┓ • - # ┃┏┓┏╋┏┓┏┓┏┏┓ ┃┃┏┓┏┓┏┓┏┓┏┓╋┓┏┓┏ - # ┻┛┗┛┗┗┻┛┗┗┗ ┣┛┛ ┗┛┣┛┗ ┛ ┗┗┗ ┛ - # ┛ - - @property - def canvas(self): - - """ - Use this to fetch just the canvas with all the inputs applied to it. - :return: The canvas (page) that is being used currently in the instance. - """ - - return self.__canvas - - @property - def unit_factor(self): - - """ - The scaling factor after taking into consideration the physical unit of measurement being use (e.g.: "mm"). - :return: The unit-factor. - """ - - return self.__unit_factor - - @property - def dpi_factor(self): - - """ - The scaling factor derived from comparing the default DPI of 72 and a custom DPI specified when creating the - instance. Since the PDF format doesn't have a native DPI configuration, this scaling factor will help in - adjusting the sizes of whatever you wish to add to the canvas. - :return: The DPI scaling factor. - """ - - return self.__dpi_factor - - @property - def shape(self): - - """ - an array of the dimensions (width, height) of the canvas. - :return: The width and height of the canvas. - """ - - return self.__canvas_width, self.__canvas_height - - # ┏┓ ┏┓ ┏┓•┓ - # ┃ ┏┓┏┓┓┏┏┓┏ ┣╋ ┣ ┓┃┏┓ - # ┗┛┗┻┛┗┗┛┗┻┛ ┗┻ ┻ ┗┗┗ - - def save(self, path: str = None): - - """ - Save the Canvas as a PDF either to RAM or a file on disk. - :param path: The path you want to save the PDF to on disk. If not specified, the PDF will be saved to RAM and - returned as a BytesIO object. - :return: A BytesIO object, or True/False if a path is supplied and the file gets saved. - """ - - # Save the changes to the file in RAM. - self.__canvas.save() - self.__pdf_in_ram.seek(0) - - # If the user has not specified a path, return the buffer: - if path is None: return self.__pdf_in_ram - - # In case a path was specified, - # We try to save the file in the specified path: - try: - with open(path, "wb") as file: file.write(self.__pdf_in_ram.getvalue()) - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - return False - - def next_page(self): - - """ - To start working on the next page. - The library that is being used doesn't support moving back and forth between pages in any random order, it, - instead, needs to go in a sequential fashion from one page to the next. - :return: None. - """ - - self.__canvas.showPage() - - # ┏┓ - # ┣ ┏┓┏┓╋┏ - # ┻ ┗┛┛┗┗┛ - - @staticmethod - async def register_font_from_url(name, url, follow_redirects = False): - - """ - Download a font from a URL and then register it for use. - :param name: The name you would later refer to the font by. - :param url: The URL to download the font from. - :param follow_redirects: Whether, or not, to follow along with any redirects when downloading the file. - :return: True if registered, else False. - """ - - try: return PDFMaker.register_font( - name, - await PDFMaker.download_from_url(url, follow_redirects = follow_redirects) - ) - except Exception as exception: - return False - - @staticmethod - def register_fonts_from_directory(directory): - - """ - Register all the fonts from a directory to be used later in the PDF. - :param directory: The directory that has the TTF files to register. - :return: A dict describing the fonts that were registered. - """ - - # List out all the files in the folder: - all_files = files.list_files(directory, full_path = True) - - # Keep only TTF files and make a name-to-path map: - font_map = { - os.path.split(file)[-1].split(".")[0].lower(): file - for file in all_files if file.lower().rstrip().endswith(".ttf") - } - - # Register the custom fonts: - registered_fonts = [] - for font_name, font_path in font_map.items(): - if PDFMaker.register_font(font_name, font_path): - registered_fonts.append({"name": font_name, "file": font_path}) - - # Done here: - return registered_fonts - - @staticmethod - def register_font(name, file): - - """ - Register one TTF font from either a BytesIO object or a path on the disk. - :param name: The name of the font as you would like to use when invoking it. - :param file: The font file (TTF format). - :return: True if registered, else False. - """ - - try: - - if isinstance(file, io.BytesIO): file.seek(0) - pdfmetrics.registerFont(TTFont(name, file)) - return True - - except Exception as exception: - return False - - @staticmethod - def get_font_height(font, size, count_ascent = True, count_descent = True): - - """ - Compute the height of the font for the given size. - :param font: [str] The name of the font (as registered). - :param size: [int|float] The size of the font (in points). - :param count_ascent: [bool] Whether, or not, you would like to consider the ascent of the font. - :param count_descent: [bool] Whether, or not, you would like to consider the descent of the font. - :return: The height of the font in points. - """ - - # Get font's information and compute the height: - ascent, descent = pdfmetrics.getAscentDescent(font, size) - if not count_ascent: ascent = 0.0 - if not count_descent: descent = 0.0 - height = ascent - descent - return height - - @staticmethod - def font_is_registered(font): - - """ - Checks if a particular font is available for use. - :param font: [str] The name of the font to check. - :return: True if registered, else False - """ - - return font in pdfmetrics.getRegisteredFontNames() - - @staticmethod - def get_first_registered_font(): - - """ - Returns the name of the first registered font. Useful for cases like those when your font fails to load and you - need a default to fall back on. - :return: The name of the first font that has been registered. - """ - - return pdfmetrics.getRegisteredFontNames()[0] - - @staticmethod - def list_registered_fonts(): - - """ - Returns the list of names of all the registered fonts. - :return: The list of names of the fonts that have been registered. - """ - - return pdfmetrics.getRegisteredFontNames() - - @staticmethod - def is_valid_ttf(file): - - """ - Checks if a font file is valid and usable or not. - :param file: [str|io.BytesIO] The file to check. - :return: True if valid, else False. - """ - - if isinstance(file, io.BytesIO): file.seek(0) - try: font = ttLib.TTFont(file)["head"].fontRevision - except Exception as exception: return False - return True - - # ┳ - # ┃┏┳┓┏┓┏┓┏┓┏ - # ┻┛┗┗┗┻┗┫┗ ┛ - # ┛ - - @staticmethod - def make_barcode_image( - data, - bar_width = 2, - bar_height = 125, - border = 10, - bar_color = "#000000", - background_color = "#FFFFFF", - dpi = 300, - format = "png", - as_pil = True - ): - - """ - Makes a barcode in Code128 format. - :param data: [str] The data to encode in the barcode. - :param bar_width: [int] The base bar-module width in pixels. - :param bar_height: [int] The bar-module height in pixels. - :param border: [int] The size of the border around all sides of the barcode in pixels. - :param bar_color: [str] The colour of the bars as a hex string. - :param background_color: [str] The colour of the background as a hex string. - :param dpi: [int] The pixel density to note in the image. Leave it to default for most use cases. - :param format: [str] The file format to save the image in. - :param as_pil: [bool] If True, a PIL object will be returned, else a PNG file will be returned in RAM (BytesIO). - :return: Either a PIL object or a PNG file in RAM. - """ - - # Create the barcode in RAM: - barcode_in_ram = io.BytesIO() - barcode_options = { - "module_width": (bar_width / dpi) * 25.4, - "module_height": (bar_height / dpi) * 25.4, - "quiet_zone": 0, - "foreground": bar_color, - "background": background_color, - "format": format, - "dpi": dpi - } - Code128(str(data), writer = ImageWriter()).write(barcode_in_ram, options = barcode_options) - barcode_in_ram.seek(0) - - # Remove the rasterized text at the bottom, and create a border of the desired size: - barcode_image = Image.open(barcode_in_ram, formats = [format]) - width, height = barcode_image.size - barcode_image = barcode_image.crop(( - 0, - int(dpi * 0.0393701), - width, - int(dpi * 0.0393701) + bar_height - )) - width, height = barcode_image.size - background_image = Image.new( - mode = "RGB", - size = (width + border + border, height + border + border), - color = background_color - ) - background_image.paste(barcode_image, (border, border)) - barcode_image = background_image - - # If the user has asked for a PIL object: - if as_pil: return barcode_image - - # Else, ave the PNG in ram: - barcode_in_ram = io.BytesIO() - barcode_image.save(barcode_in_ram, format = "png") - barcode_in_ram.seek(0) - - # Done: - return barcode_in_ram - - @staticmethod - def make_qr_image( - data, - scale = 5, - border = 2, - foreground_color = "#000000", - background_color = "#FFFFFF", - border_color = "#FFFFFF", - background_art = None, - format = "png", - as_pil = True - ): - - """ - Create a QR code. - :param data: [str] The data that you want to encode in the QR code. - :param scale: [int] The size (in pixels) for each tiny block in the QR code. - :param border: [int] The size (in multiples of scale) of the quiet zone. - :param foreground_color: [str] The color of the foreground, a.k.a. the dark color. - :param background_color: [str] The color of the background, a.k.a. the light color. - :param border_color: [str] The color of the quiet zone. - :param background_art: [io.BytesIO|PIL.Image] Any image that you would like to feed into the background instead - of a plain QR code. This can be an animated GIF image as well. - :param format: [str] The type of output file that you want. - :param as_pil: [bool] If True, a PIL object will be returned, else a PNG file will be returned in RAM (BytesIO). - :return: Either a PIL object or a PNG file in RAM. - """ - - qr_code = segno.make_qr(str(data)) - params = { - "scale": scale, - "border": border, - "dark": foreground_color, - "light": background_color, - "quiet_zone": border_color, - "kind": format - } - - qr_image = io.BytesIO() - - if background_art is not None: - if isinstance(background_art, Image.Image): - buffer = io.BytesIO() - background_art.save(buffer, format = format) - buffer.seek(0) - background_art = buffer - params["background"] = background_art - params["target"] = qr_image - qr_code.to_artistic(**params) - - else: - params["out"] = qr_image - qr_code.save(**params) - - qr_image.seek(0) - if as_pil: qr_image = Image.open(qr_image, formats = [format]) - return qr_image - - async def image_from_url(self, url, follow_redirects = False, as_pil = True, format = "png"): - - """ - Asynchronously downloads an image and returns it as a PIL object. - Use this instead of just passing the URL to 'draw_image' for better efficiency. - :param url: [str] The URL to download the image from. - :param follow_redirects: [bool] Whether, or not, to follow redirect URLs when downloading the file. - :param as_pil: [bool] If True, a PIL object will be returned, else a PNG file will be returned in RAM (BytesIO). - :param format: [str] The type of output file that you want. Not applicable for PIL objects. - :return: The image as a PIL object or as a file in RAM. - """ - - try: - - pil_image = Image.open(await PDFMaker.download_from_url(url, follow_redirects = follow_redirects)) - if as_pil: return pil_image - image_in_memory = io.BytesIO() - pil_image.save(image_in_memory, format = format) - image_in_memory.seek(0) - return image_in_memory - - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - - def image_from_base64(self, data, as_pil = True): - - """ - Converts a base64 string to an image. - :param data: [str] The base-64 representation of the image data. - :param as_pil: [bool] If True, a PIL object will be returned, else a PNG file will be returned in RAM (BytesIO). - :return: The image as a PIL object or as a file in RAM. - """ - - try: - - image = io.BytesIO(base64.b64decode(data)) - image.seek(0) - if not as_pil: return image - image = Image.open(image) - return image - - except Exception as exception: - if self.__raise_exception: raise - - @staticmethod - def crop_image_to_aspect_ratio(image, target_aspect_ratio, anchor = "c"): - - """ - Shaves off pixels from an image to achieve the target aspect ratio. - :param image: [PIL.Image] The image to work on, held in a PIL object. - :param target_aspect_ratio: [int|float] The aspect ratio you want to achieve. - :param anchor: [str] Which part of the image you want to retain. Imagine it like a compass - "nw", "n", "ne", - "e", "se", "s", "sw", "w", and "c". - :return: The adjusted image. - """ - - # Get the existing figures: - width, height = image.size - original_aspect_ratio = width / height - - # Compute the new dimensions: - if original_aspect_ratio > target_aspect_ratio: - scaling_factor = target_aspect_ratio / original_aspect_ratio - new_width, new_height = int(width * scaling_factor), height - else: - scaling_factor = original_aspect_ratio / target_aspect_ratio - new_width, new_height = width, int(height * scaling_factor) - - # Now we figure out the start and end points of cropping: - match anchor.strip().lower(): - case "nw": - start_x = 0 - start_y = 0 - case "n": - start_x = int(abs(new_width - width) / 2.0) - start_y = 0 - case "ne": - start_x = int(abs(new_width - width)) - start_y = 0 - case "e": - start_x = int(abs(new_width - width)) - start_y = int(abs(new_height - height) / 2.0) - case "se": - start_x = int(abs(new_width - width)) - start_y = int(abs(new_height - height)) - case "s": - start_x = int(abs(new_width - width) / 2.0) - start_y = int(abs(new_height - height)) - case "sw": - start_x = 0 - start_y = int(abs(new_height - height)) - case "w": - start_x = 0 - start_y = int(abs(new_height - height) / 2.0) - case _: - start_x = int(abs(new_width - width) / 2.0) - start_y = int(abs(new_height - height) / 2.0) - - end_x = start_x + new_width - end_y = start_y + new_height - - # And we finally crop and return the image: - return image.crop((start_x, start_y, end_x, end_y)) - - @staticmethod - def crop_image(image, start_x, start_y, end_x, end_y): - - """ - Crops an image. - :param image: [PIL.Image] The image to work on, held in a PIL object. - :param start_x: [int|float] The left coordinate (in the same unit as the dimension of the canvas). - :param start_y: [int|float] The top coordinate (in the same unit as the dimension of the canvas). - :param end_x: [int|float] The right coordinate (in the same unit as the dimension of the canvas). - :param end_y: [int|float] The bottom coordinate (in the same unit as the dimension of the canvas). - :return: The cropped image. - """ - - return image.crop((start_x, start_y, end_x, end_y)) - - @staticmethod - def resize_image_to_aspect_ratio(image, target_aspect_ratio): - - """ - Resizes the image (by stretching and squishing) till it fits the target aspect ratio. - :param image: [PIL.Image] The image to adjust. - :param target_aspect_ratio: [int|float] The aspect ratio that you want to achieve. - :return: The adjusted image. - """ - - # Get the existing figures: - width, height = image.size - original_aspect_ratio = width / height - - # Compute the new dimensions: - if original_aspect_ratio > target_aspect_ratio: - new_width, new_height = width, int(width / target_aspect_ratio) - else: - new_width, new_height = int(height * target_aspect_ratio), height - - # Resize and return the image: - return image.resize((new_width, new_height)) - - @staticmethod - def resize_image(image, width, height): - - """ - Resizes an image to the specified width and height. - :param image: [PIL.Image] The image as a PIL object. - :param width: [int|float] The new width. - :param height: [int|float] The new height. - :return: The resized image. - """ - - return image.resize((width, height)) - - @staticmethod - def fit_image_to_aspect_ratio( - image: Image, - target_aspect_ratio: float, - blur_strength = 0.01, - alpha: float = 0.8 - ): - - """ - Fits an image to any aspect ratio by adding a blurred background to it. - :param image: [PIL.Image] The image to adjust. - :param target_aspect_ratio: [int|float] The aspect ratio that you want to achieve. - :param blur_strength: How intense the blur must be. - :param alpha: The opacity of the blurred background. - :return: The adjusted image. - """ - - # Get the existing figures: - width, height = image.size - original_aspect_ratio = width / height - - # Compute the new dimensions: - if original_aspect_ratio > target_aspect_ratio: - new_width, new_height = width, int(width / target_aspect_ratio) - scaling_factor = new_height / height - paste_x = 0 - paste_y = int((new_height - height) / 2) - else: - new_width, new_height = int(height * target_aspect_ratio), height - scaling_factor = new_width / width - paste_x = int((new_width - width) / 2) - paste_y = 0 - - # Prepare the background image: - # bg_image = image.copy().resize((new_width, new_height)) - bg_image = image.copy().resize((int(width * scaling_factor), int(height * scaling_factor))) - bg_image = bg_image.filter(ImageFilter.GaussianBlur(radius = int((new_width + new_height) / 2) * blur_strength)) - bg_image = PDFMaker.crop_image_to_aspect_ratio(bg_image, target_aspect_ratio) - - # darken the background a little: - bg_image = Image.blend( - bg_image, - Image.new("RGB", bg_image.size, (0, 0, 0)), - alpha = 1.0 - alpha - ) - - # Paste the original image on top of the background: - bg_image.paste(image, (paste_x, paste_y)) - - # Resize and return the image: - return bg_image - - @staticmethod - def adjust_image_orientation_from_exif(image): - - """ - Rotates the image as per the instructions in the EXIF tags. - :param image: The PIL object that holds the image data. - :return: The adjusted image. - """ - - # Guard clause to return if the attribute is not even found: - if not hasattr(image, "getexif"): return image - - # Else we start extracting EXIF data: - exif = image.getexif() - if exif is None: return image - - # We look for the tag that indicates orientation: - # ORIENTATION CODES: - # 1: Normal (Landscape) - # 2: Flipped horizontally - # 3: Upside down (Reverse Landscape) - # 4: Flipped vertically - # 5: Rotated 90° clockwise and flipped horizontally - # 6: Rotated 90° clockwise (Portrait) - # 7: Rotated 90° counter-clockwise and flipped horizontally - # 8: Rotated 90° counter-clockwise (Reverse Portrait) - orientation = exif.get(274, 0) - if orientation == 1: pass - elif orientation == 2: image = image.transpose(Image.FLIP_LEFT_RIGHT) - elif orientation == 3: image = image.rotate(180, expand = True) - elif orientation == 4: image = image.rotate(180, expand = True).transpose(Image.FLIP_LEFT_RIGHT) - elif orientation == 5: image = image.rotate(270, expand = True).transpose(Image.FLIP_LEFT_RIGHT) - elif orientation == 6: image = image.rotate(270, expand = True) - elif orientation == 7: image = image.rotate(90, expand = True).transpose(Image.FLIP_LEFT_RIGHT) - elif orientation == 8: image = image.rotate(90, expand = True) - - # Done here: - return image - - # ┏┓┳┓┏ - # ┃┃┃┃╋ - # ┣┛┻┛┛ - - def draw_line( - self, - start_x, - start_y, - end_x, - end_y, - thickness = 1.0, - color = (0, 0, 0), - alpha = 1.0 - ): - - """ - Draw a line in the PDF page. - :param start_x: [int|float] The left coordinate. - :param start_y: [int|float] The top coordinate. - :param end_x: [int|float] The right coordinate. - :param end_y: [int|float] The bottom coordinate. - :param thickness: [int|float] The thickness of the line (in the same unit as the canvas's dimensions). - :param color: [str] The RGB color in an array. - :param alpha: [int|float] The opacity of the line. 1 is 100% and 0 is 0% - :return: True or False based on the success of the operation. - """ - - # Handle color: - color = self.__parse_color(color) - - # Adjust the dimensions: - thickness *= self.__unit_factor - start_x, end_x = self.__parse_x(start_x, end_x) - start_y, end_y = self.__parse_y(start_y, end_y, flip = True) - - try: - - self.__canvas.setLineWidth(thickness) - self.__canvas.setStrokeColorRGB(color[0], color[1], color[2], alpha) - self.__canvas.line( - start_x, - start_y, - end_x, - end_y - ) - return True - - # In case something goes wrong: - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - return False - - def draw_circle( - self, - x, - y, - radius, - fill_color = (255, 255, 255), - fill_alpha = 0.0, - stroke_color = (0, 0, 0), - stroke_alpha = 1.0, - thickness = 1.0 - ): - - """ - Draw a circle in the PDF page. - :param x: [int|float] The horizontal coordinate of the center of the circle. - :param y: [int|float] The vertical coordinate of the center of the circle. - :param radius: [int|float] The radius of the circle. - :param fill_color: [str] The color-array (0-255) or hex string to define the inner fill color of the rectangle. - :param fill_alpha: [int|float] The opacity of the inner fill color. - :param stroke_color: [str] The color-array (0-255) or hex string to define the outline color of the rectangle. - :param stroke_alpha: [int|float] The opacity of the outline color. - :param thickness: [int|float] The thickness of the line (in the same unit as the canvas's dimensions). - :return: True or False based on the success of the operation. - """ - - try: - - # Handle color: - fill_color = self.__parse_color(fill_color) - stroke_color = self.__parse_color(stroke_color) - - # Adjust the dimensions: - x = self.__parse_x(x) - y = self.__parse_y(y, flip = True) - thickness *= self.__unit_factor - radius *= self.__unit_factor - - # Draw the circle here: - self.__canvas.setLineWidth(thickness) - self.__canvas.setFillColorRGB(fill_color[0], fill_color[1], fill_color[2]) - self.__canvas.setFillAlpha(fill_alpha) - self.__canvas.setStrokeColorRGB(stroke_color[0], stroke_color[1], stroke_color[2]) - self.__canvas.setStrokeAlpha(stroke_alpha) - self.__canvas.circle(x, y, radius, stroke = 1, fill = 1) - - # In case something goes wrong: - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - return False - - def draw_rect( - self, - start_x, - start_y, - end_x, - end_y, - radius = 0.0, - fill_color = (255, 255, 255), - fill_alpha = 0.0, - stroke_color = (0, 0, 0), - stroke_alpha = 1.0, - thickness = 1.0, - ): - - """ - Draws a rectangle on the page. - :param start_x: [int|float] The left coordinate. - :param start_y: [int|float] The top coordinate. - :param end_x: [int|float] The right coordinate. - :param end_y: [int|float] The bottom coordinate. - :param radius: [int|float] The corner radius. - :param fill_color: [str] The color-array (0-255) or hex string to define the inner fill color of the rectangle. - :param fill_alpha: [int|float] The opacity of the inner fill color. - :param stroke_color: [str] The color-array (0-255) or hex string to define the outline color of the rectangle. - :param stroke_alpha: [int|float] The opacity of the outline color. - :param thickness: [int|float] The line thickness of the outline (in the same unit as the canvas's dimensions). - :return: True or False based on the success of the operation. - """ - - try: - - # Handle color: - fill_color = self.__parse_color(fill_color) - stroke_color = self.__parse_color(stroke_color) - - # Adjust the dimensions: - thickness *= self.__unit_factor - start_x, end_x = self.__parse_x(start_x, end_x) - start_y, end_y = self.__parse_y(start_y, end_y, flip = False) - - # Compute the width and height desired by the user: - width = end_x - start_x - height = end_y - start_y - - # Draw the rectangle here: - self.__canvas.setLineWidth(thickness) - self.__canvas.setFillColorRGB(fill_color[0], fill_color[1], fill_color[2]) - self.__canvas.setFillAlpha(fill_alpha) - self.__canvas.setStrokeColorRGB(stroke_color[0], stroke_color[1], stroke_color[2]) - self.__canvas.setStrokeAlpha(stroke_alpha) - self.__canvas.roundRect( - start_x, - self.__canvas_height - start_y - height, - width, - height, - radius * self.__unit_factor, - stroke = 1, - fill = 1 - ) - - return True - - # In case something goes wrong: - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - return False - - def make_paragraph_style( - self, - font_name = "Helvetica", - font_size = 12, - font_color = (0, 0, 0), - line_spacing = 12, - border_size = 0.0, - border_color = (255, 255, 255), - align = "left", - style_name = "CustomStyle" - ): - - """ - Creates a text style for using in a paragraph. - :param font_name: [str] The name of the font. Has to be registered. - :param font_size: [int|float] The size that you want the font to be printed in. - :param font_color: [str] The color-array (0-255) or hex string that you want the font to be printed in. - :param line_spacing: [int|float] The line spacing to apply. - :param border_size: [int|float] The thickness of the border. - :param border_color: [str] The color-array (0-255) or hex string of the color you wan the border to be in. - :param align: [str] Text alignment ("left", "center", or "right"). - :param style_name: [str] A name that you would like to give this style. - :return: The paragraph style. - """ - - # Make adjustments: - font_color = self.__parse_color(font_color) - font_size = self.__parse_font_size(font_size) - border_color = self.__parse_color(border_color) - border_size *= self.__unit_factor - - return ParagraphStyle( - name = style_name, - fontName = font_name, - fontSize = font_size, - textColor = (font_color[0], font_color[1], font_color[2]), - alignment = { - "left": 0, - "center": 1, - "right": 2 - }[align], - leading = line_spacing * font_size, - spaceBefore = 0, - spaceAfter = 0, - borderWidth = border_size, - borderColor = border_color - ) - - def write_paragraph( - self, - text, - start_x, - start_y, - end_x, - end_y, - alpha = 1.0, - style = None - ): - - """ - To write text into a bounding box in the PDF. - This can be either plaintext or an HTML string. - :param text: [str] The text to type in the bounding box. - :param start_x: [int|float] The left coordinate (in the same unit as used while setting up the canvas). - :param start_y: [int|float] The top coordinate (in the same unit as used while setting up the canvas). - :param end_x: [int|float] The right coordinate (in the same unit as used while setting up the canvas). - :param end_y: [int|float] The bottom coordinate (in the same unit as used while setting up the canvas). - :param alpha: [int|float] The opacity of the text. 1 is 100% and 0 is 0% - :param style: The paragraph-style generated by using "make_paragraph_style" method. Avoid using this if you are - passing in an HTML string. - :return: True or False based on the success of the operation. You will get a False even if the text flows out of - the bounding box (which will cause it to not render). - """ - - try: - - # Adjust the dimensions: - start_x, end_x = self.__parse_x(start_x, end_x) - start_y, end_y = self.__parse_y(start_y, end_y, flip = False) - - # Compute the width and height desired by the user: - width = end_x - start_x - height = end_y - start_y - - # Make the paragraph: - paragraph = Paragraph(text, style = style) - - # Wrap the paragraph to compute the needed dimensions: - needed_width, needed_height = paragraph.wrap(width, height) - - # Adjust the y coordinates (for top-down system): - start_y = self.__canvas_height - start_y - needed_height - - # Write the text to the canvas if the text fits. - # Return true in case of success, else false: - if width >= needed_width and height >= needed_height: - self.__canvas.setFillAlpha(alpha) - paragraph.drawOn(self.__canvas, start_x, start_y, _sW = 0) - return True - else: return False - - # In case something goes wrong: - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - return False - - def write_string( - self, - text, - x, - y, - font = "Helvetica", - size = 12, - color = (0, 0, 0), - alpha = 1.0, - align = "left", - angle = 0 - ): - - """ - Writes a string onto the canvas. - :param text: [str] The text to be written. - :param x: [int|float] The horizontal coordinate (of the baseline). - :param y: [int|float] The vertical coordinate (of the baseline). - :param font: [str] The name of the font to be used. - :param size: [int|float] The size of the font to be used (in points). - :param color: [str] The color-array (0-255) or hex string that you want the font to be printed in. - :param alpha: [int|float] The opacity of the text. 1 is 100% and 0 is 0% - :param align: [str] The alignment to use ("left", "center", "right"). - :param angle: The angle at which you want the text to be printed in. - :return: True or False based on the success of the operation. - """ - - try: - - # Handle the color - color = self.__parse_color(color) - - # Adjust the dimensions: - x = self.__parse_x(x) - y = self.__parse_y(y, flip = True) - size = self.__parse_font_size(size) - - # Adjust the canvas's values: - self.__canvas.setFont(font, size) - self.__canvas.setFillColorRGB(color[0], color[1], color[2]) - self.__canvas.setFillAlpha(alpha) - - # Handle angular adjustments: - self.__canvas.rotate(angle) - x, y = self._parse_coordinates_for_rotation( - original_x = x, - original_y = y, - angle = angle - ) - - # Adjust the font coordinates as per the angle: - text_width = self.__canvas.stringWidth(text, fontName = font, fontSize = size) - if align == "center": x -= text_width / 2 - elif align == "right": x -= text_width - - # Draw the string: - self.__canvas.drawString(x, y, text) - - # Reset angular adjustments: - self.__canvas.rotate(-angle) - - # Return with success if nothing broke till here: - return True - - # In case something goes wrong: - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - return False - - def draw_image( - self, - image, - start_x, - start_y, - end_x, - end_y, - crop = False, - crop_anchor = "c", - alpha = 1.0, - stroke_color = (0, 0, 0), - stroke_alpha = 0.0, - thickness = 1.0, - identifier: str = None, - format = "jpeg" - ): - - """ - Draw an image onto the PDF page in the specified bounding box. The image can be drawn in either "fit" mode where - the image is scaled down to fit in the bounding box, or in "fill" mode where the image is cropped to fill up the - space in the bounding box by matching their aspec ratios. - :param image: The image data as a PIL object or a valid URL or a file path. NOTE: If given as a URL, the image - will be downloaded synchronously. - :param start_x: [int|float] The left coordinate. - :param start_y: [int|float] The top coordinate. - :param end_x: [int|float] The right coordinate. - :param end_y: [int|float] The bottom coordinate. - :param crop: [bool] Set to True for "fill" mode, False for "fit" mode. - :param crop_anchor: [str] If cropping is to be performed, what should the anchor be for cropping. Refer to the - description in 'crop_image_to_aspect_ratio'. - :param alpha: [int|float] The opacity of the image. 1 is 100% and 0 is 0% - :param stroke_color: [str] The color-array (0-255) or hex string to define the outline color of the rectangle. - :param stroke_alpha: [int|float] The opacity of the outline color. - :param thickness: [int|float] The line thickness of the outline (in the same unit as the canvas's dimensions). - :param identifier: [str] A unique name for the image. - :param format: The file format of the image (when it will be embedded in the PDF). - :return: True or False based on the success of the operation. - """ - - try: - - # Cleaning: - format = format.strip().lower().split(".")[-1] - - # Handle color: - stroke_color = self.__parse_color(stroke_color) - - # The identifier can allow us to use the same image multiple times in a PDF file. - # If the identifier is not provided, we give the file a random identifier. - if identifier is None: identifier = "".join([random.choice(string.ascii_lowercase) for _ in range(8)]) - - # Adjust the dimensions: - start_x, end_x = self.__parse_x(start_x, end_x) - start_y, end_y = self.__parse_y(start_y, end_y, flip = True) - - # Compute the width and height desired by the user: - width = end_x - start_x - height = end_y - start_y - - # In case the image is passed as a URL, we try to download it and open it as a PIL object: - if isinstance(image, str): - if image.startswith("https://") or image.startswith("http://"): - image = Image.open(io.BytesIO(requests.get(image).content)) - else: image = Image.open(image) - - # The image can have orientation data in its EXIF tags. - # If so, we adjust for it so that reportlab can work with it properly: - image = self.adjust_image_orientation_from_exif(image) - - # If the image needs to be cropped, we compute the aspect ratio and get the image adjusted: - if crop: image = self.crop_image_to_aspect_ratio( - image, - abs(end_x - start_x) / abs(end_y - start_y), - anchor = crop_anchor - ) - - # Else we add a blurred background to the image: - else: image = self.fit_image_to_aspect_ratio( - image, - abs(end_x - start_x) / abs(end_y - start_y), - blur_strength = 0.1 - ) - - # We set the image opacity and outline settings here: - self.__canvas.setFillAlpha(alpha) - self.__canvas.setLineWidth(thickness * self.__unit_factor) - self.__canvas.setStrokeColorRGB(stroke_color[0], stroke_color[1], stroke_color[2]) - self.__canvas.setStrokeAlpha(stroke_alpha) - - # Draw the image onto the canvas: - if ( - image.mode == "P" or - format in ["jpeg", "jpg"] - ): - image = image.convert("RGB") - image_buffer = io.BytesIO() - image.save(image_buffer, format = format) - image_buffer.seek(0) - self.__canvas.drawImage( - ImageReader(image_buffer, ident = identifier), - start_x, - start_y, - width = width, - height = height, - preserveAspectRatio = True, - mask = "auto", - anchor = "c", - showBoundary = True - ) - - return True - - # In case something goes wrong: - except Exception as exception: - self.__printer(exception) - if self.__raise_exception: raise - return False - - # def draw_svg( - # self, - # svg, - # start_x, - # start_y, - # end_x, - # end_y - # ): - # - # renderSVG.draw(svg, sta) - - # ┏┓┳┓┏ ┏┳┓ ┓ - # ┃┃┃┃╋ ┃ ┏┓┏┓┃┏ - # ┣┛┻┛┛ ┻ ┗┛┗┛┗┛ - - @staticmethod - def make_thumbnails( - pdf_file, - pages = None, - scale = 1.0, - as_pil = True, - format = "png" - ): - - """ - Makes thumbnails of pages of the PDF and returns them - :param pdf_file: The PDF file whose pages must be converted to thumbnails. - :param pages: The list of page nos. to make thumbnails of. If not specified, all pages will be converted. - :param scale: The scaling multiplier, applied to both axes, to change the output size. - :param as_pil: If True, the output will be an array of PIL objects, else the output will be an array of - file-like BytesIO objects. - :param format: The file format of the output image. - :return: The array of thumbnails, either as PIL objects, or as BytesIO objects. - """ - - # Open the PDF, and ensure that we have the pages numbers: - if isinstance(pdf_file, io.BytesIO): - pdf_file.seek(0) - pdf_document = fitz.open(stream = pdf_file) - pdf_file.seek(0) - else: pdf_document = fitz.open(pdf_file) - if pages is None: pages = list(range(len(pdf_document))) - - # Iterate over the pages and make the thumbnails: - thumbnails = [] - for page_no in pages: - img = pdf_document.load_page(page_no).get_pixmap(matrix = fitz.Matrix(scale, scale)) - img = io.BytesIO(img.tobytes(format)) - if as_pil: img = Image.open(img, formats = [format]) - thumbnails.append(img) - - # Done here: - return thumbnails - - @staticmethod - def join_from_ram(pdf_files, raise_exception = True): - - """ - Joins a set of PDF files held in RAM (as BytesIO objects). - :param pdf_files: The list of PDF files (as BytesIO objects). - :param raise_exception: Set to True for an all-or-nothing process. - :return: The joined PDF file (as a BytesIo object). - """ - - try: - - # Create a file in RAM that will hold the merged PDF: - joined_pdf_in_ram = io.BytesIO() - - # Merge the files into one: - merger = PdfMerger() - for pdf_file in pdf_files: merger.append(pdf_file) - merger.write(joined_pdf_in_ram) - merger.close() - - # Done here: - joined_pdf_in_ram.seek(0) - return joined_pdf_in_ram - - # In case something goes wrong: - except Exception as exception: - if raise_exception: raise - return None - - @staticmethod - def grid_from_ram( - pdf_files, - input_width, - input_height, - output_width, - output_height, - cutting_width, - cutting_height, - unit = "mm", - dpi = 72 - ): - - """ - Lays out a set of input PDFs into a larger pdf in a grid. - NOTE: The 'unit' and 'dpi' choice will be used for both (input and output). - WARNING: I STRONGLY RECOMMEND NOT USING DPI AS A SETTING. THE PDF FORMAT ITSELF DOESN'T HAVE ANY PROVISION FOR - PIXEL DENSITY. THIS SETTING HAS BEEN MADE AVAILABLE FOR PLACEBO EFFECT WHEN CLIENTS ASK FOR VERY HIGH RESOLUTION - FILES WITHOUT WANTING TO UNDERSTAND ANY TECHNICALITY. USE WITH CAUTION. - :param pdf_files: The list of PDF files (as BytesIO objects) to lay onto the larger canvas. - :param input_width: The width of the input PDFs. - :param input_height: The height of the input PDFs - :param output_width: The width of the large PDF on which the smaller PDFs will be laid out. - :param output_height: The height of the large PDF on which the smaller PDFs will be laid out. - :param cutting_width: The horizontal buffer to leave between the grid. - :param cutting_height: The vertical buffer to leave between the grid. - :param unit: The unit to use (common to the input and output PDFs). - :param dpi: The pixel density to consider (common to the input and output PDFs). - :return: The PDF grid. - """ - - # Create the base PDF: - base_canvas = PDFMaker( - width = output_width, - height = output_height, - unit = unit, - dpi = dpi - ) - base_canvas.draw_line(0, 1, 1, 0, alpha = 0.0) - base_pdf = base_canvas.save() - - # Adjust all units to match the pixel density adjustments: - input_width *= base_canvas.unit_factor - input_height *= base_canvas.unit_factor - output_width *= base_canvas.unit_factor - output_height *= base_canvas.unit_factor - cutting_width *= base_canvas.unit_factor - cutting_height *= base_canvas.unit_factor - - # Calculate how many input pdfs will fit and the page count needed: - per_row = math.floor((output_width - cutting_width) / (input_width + cutting_width)) - per_column = math.floor((output_height - cutting_height) / (input_height + cutting_height)) - per_page = per_row * per_column - output_page_count = math.ceil(len(pdf_files) / per_page) - - # Calculate the starting point on the page from where the pasting will start: - page_start_x = (output_width - (per_row * (input_width + cutting_width)) + cutting_width) / 2.0 - page_start_y = (output_height - (per_column * (input_height + cutting_height)) + cutting_height) / 2.0 - - # We make a writer object to write pages to the output file, - # and we make a list that will hold the individual output pages: - grid_pdf = PdfWriter() - - # We create each needed page: - for page_number in range(output_page_count): - - # Open the base PDF and create a page here: - grid_page = PdfReader(base_pdf).pages[0] - - # Shortlist the input pdfs to be pasted on this page: - starting_offset = page_number * per_page - ending_offset = starting_offset + per_page - ending_offset = min(ending_offset, len(pdf_files)) - pdf_files_for_page = pdf_files[starting_offset:ending_offset] - - # We paste all the input PDFs one-by-one: - for index, input_pdf in enumerate(pdf_files_for_page): - - # Compute the coordinates to paste on: - row_number = math.floor(index / per_row) - column_number = index if index < per_row else index % per_row - paste_x = page_start_x + (column_number * input_width) + (column_number * cutting_width) - paste_y = page_start_y + (row_number * input_height) + (row_number * cutting_height) - - # The default system for the reportlab is bottom-up, - # we convert to top-down for intuitive operations: - paste_y = base_canvas.shape[1] - paste_y - input_height - - # Open th smaller PDF and paste it on those coordinates: - input_page = PdfReader(input_pdf).pages[0] - input_page.add_transformation(Transformation().translate( - tx = paste_x, - ty = paste_y - ), expand = True) - grid_page.merge_page(input_page) - - # Add the grid page to the grid PDF: - grid_pdf.add_page(grid_page) - - # Join and return the result: - grid_pdf_in_ram = io.BytesIO() - grid_pdf.write(grid_pdf_in_ram) - return grid_pdf_in_ram - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - - async def main(): - - my_pdf = PDFMaker(width = 210, height = 297) - # my_image = await my_pdf.image_from_url(r"https://images.pexels.com/photos/28973930/pexels-photo-28973930/free-photo-of-historic-saigon-central-post-office-architecture.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1") - # my_image = await my_pdf.image_from_url(r"") - # my_image = await my_pdf.image_from_url(r"") - my_image = await my_pdf.image_from_url(r"https://images.pexels.com/photos/18317748/pexels-photo-18317748/free-photo-of-peoples-committee-of-ho-chi-minh.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1") - # my_image.show() - blurred_image = PDFMaker.fit_image_to_aspect_ratio(my_image, 1.49) - blurred_image.show() - - asyncio.run(main()) diff --git a/utils_v2/queue/__init__.py b/utils_v2/queue/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/queue/async_kafka.py b/utils_v2/queue/async_kafka.py deleted file mode 100644 index d6c0a82..0000000 --- a/utils_v2/queue/async_kafka.py +++ /dev/null @@ -1,554 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Saturday, 13th Jul, 2024 - - OBJECTIVE: - - To be able to work with keys - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# To use Kafka: -from aiokafka import AIOKafkaProducer -from aiokafka import AIOKafkaConsumer - -# For working with JSON strings: -from utils_v2.string import json -from utils_v2.serialization.json_serializer import JSONSerializer - -# For debugging: -from icecream import IceCreamDebugger - -# For SSL security: -import ssl - -# For asynchronous activities: -import asyncio - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def get_ssl_context( - ca_file, - cert_file, - key_file -): - - """ - Generate the SSL context to use with the Kafka instances. - :param ca_file: The Certificate Authority file as a path to a local file. - :param cert_file: The Certificate file as a path to a local file. - :param key_file: The Key file as a path to a local file. - :return: The SSL context instance as a path to a local file. - """ - - ssl_context = ssl.create_default_context() - ssl_context.load_verify_locations(ca_file) - ssl_context.load_cert_chain(certfile = cert_file, keyfile = key_file) - return ssl_context - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class ProducerKafka: - - def __init__( - self, - topic, - serializer = None, - debug = True, - debug_prefix = "Kafka (P) | ", - **kwargs - ): - - """ - Create a Kafka Producer. - :param topic: The topic to produce on. - :param serializer: The serializer to use. - :param debug: Whether, or not, you want to print the debug strings. - :param debug_prefix: The prefix to use while debugging. - :param kwargs: Any configuration parameters for the Kafka instances. - """ - - # Initialize the debugger: - self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self.__printer.disable() - - # initialize the Kafka producer: - self.__topic = topic - self.__kwargs = kwargs - self.__producer = None - self.__connected = False - self.__serializer = serializer or JSONSerializer() - - # For establishing connection: - self.__exclusive_semaphore = asyncio.Semaphore(1) - - def enable_debug(self): - self.__printer.enable() - - def disable_debug(self): - self.__printer.disable() - - async def connect(self): - - """ - Connects to the Kafka server if not connected. - :return: True or False based on the success of the operation. - """ - - async with self.__exclusive_semaphore: - if not self.__connected: - try: - self.__producer = AIOKafkaProducer(**self.__kwargs) - await self.__producer.start() - self.__connected = True - except Exception as exception: self.__printer(exception) - return self.__connected - - async def ensure_connection(self): - - """ - Connects to the Kafka server if not connected. - :return: True or False based on the success of the operation. - """ - - if not self.__connected: await self.connect() - return self.__connected - - async def close(self): - - """ - Terminates the connection. - :return: None. - """ - - if self.__connected: - try: - await self.__producer.stop() - self.__printer("Producer closed!") - self.__connected = False - except Exception as exception: self.__printer(exception) - - async def produce(self, value, key = None, topic = None, encoding = "utf-8"): - - """ - Sends one message to the Kafka server on the topic that has been set for this instance. - :param value: The message to send. - :param key: The key to use when you want the messages to follow an order. - :param topic: A custom topic for this message, else the topic defined during the creation of this instance will - be used by default. - :param encoding: The encoding format. - :return: True or False based on the success of the operation. - """ - - # Ensure connectivity to the server. - # If not connected, return with failure immediately. - if not await self.ensure_connection(): return False - - try: - - # Send the message: - await self.__producer.send_and_wait( - topic = topic or self.__topic, - value = self.__serializer.serialize(data = value, encoding = encoding), - key = key - ) - - # Return with success if no exception occurred: - return True - - # Return with failure if something went wrong: - except Exception as exception: - self.__printer(exception, self.__topic, type(value), value) - return False - - -# --------------------------------------------------------------------------------------------------------------------- - - -class ConsumerKafka: - - def __init__( - self, - topic, - serializer = None, - debug = True, - debug_prefix = "Kafka (C) | ", - **kwargs - ): - - """ - Create a Kafka Consumer. - :param topic: The topic to consumer on. - :param serializer: The serializer to use. - :param debug: Whether, or not, you want to print the debug strings. - :param debug_prefix: The prefix to use while debugging. - :param kwargs: Any configuration parameters for the Kafka instances. - """ - - # Initialize the debugger: - self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self.__printer.disable() - - # initialize the Kafka producer: - self.__topic = topic - self.__kwargs = kwargs - self.__consumer = None - self.__connected = False - self.__serializer = serializer or JSONSerializer() - - # For establishing connection: - self.__exclusive_semaphore = asyncio.Semaphore(1) - - def enable_debug(self): - self.__printer.enable() - - def disable_debug(self): - self.__printer.disable() - - async def connect(self): - - """ - Connects to the Kafka server if not connected. - :return: True or False based on the success of the operation. - """ - - async with self.__exclusive_semaphore: - if not self.__connected: - try: - self.__consumer = AIOKafkaConsumer(self.__topic, **self.__kwargs) - await self.__consumer.start() - self.__connected = True - except Exception as exception: self.__printer(exception) - return self.__connected - - async def ensure_connection(self): - - """ - Connects to the Kafka server if not connected. - :return: True or False based on the success of the operation. - """ - - if not self.__connected: await self.connect() - return self.__connected - - async def close(self): - - """ - Terminates the connection. - :return: None. - """ - - if self.__connected: - try: - await self.__consumer.stop() - self.__printer("Consumer closed!") - self.__connected = False - except Exception as exception: self.__printer(exception) - - async def consume(self, count = 1, timeout = 0.05, encoding = "utf-8"): - - """ - Get messages from the Kafka server. - :param count: The number of messages to get from the Kafka server. - :param timeout: The time in seconds to wait for retrieval. - :param encoding: The encoding to use. - :return: The messages that were received. If no messages are available, an empty list will be returned. - """ - - # Ensure connectivity to the server. - # If not connected, return with failure immediately. - if not await self.ensure_connection(): return [] - - # Make a variable that will hold the final results: - messages = [] - - try: - - # Read some messages: - results = await self.__consumer.getmany( - max_records = max(1, count), - timeout_ms = int(timeout * 1_000) - ) - - # Format the received messages: - if results: - for topic_partition, records in results.items(): - for record in records: - record_dict = record.__dict__ - record_dict["value"] = self.__serializer.deserialize( - data = record_dict["value"], - encoding = encoding - ) - messages.append(record_dict) - - # Debugging print if something went wrong: - except Exception as exception: self.__printer(exception) - - # Done here: - return messages - - -# --------------------------------------------------------------------------------------------------------------------- - - -class BidirectionalKafka: - - # The 'roles' that the instance can take. - # The master talks on the channel (topic) that the slave listens on and vice versa. - # Master-Slave is only for deciding who talks on which channel and who listens on which. - # In a two-party system, one must be the master, the other must be the slave. - # There are no extra privileges that the master enjoys. The naming convention was borrowed from common protocols - # used in electronics (like I2C). - ROLE_MASTER = 1 - ROLE_SLAVE = 0 - - def __init__( - self, - role, - topic, - ack_topic: str = None, - group: str = None, - serializer = None, - debug = True, - debug_prefix = "Kafka (B) | ", - **kwargs - ): - - """ - Creates a walkie-talkie type setup to use Kafka in a bidirectional manner. Fo more information on all the - individual methods, please read through the doc-strings of the component classes 'ProducerKafka', and - 'ConsumerKafka'. - :param role: Select from "ROLE_MASTER" and "ROLE_SLAVE". Between the two parties that are talking, one will be - the master and the other will be the slave. The channel that the master uses to speak will the one the slave - uses to listen, and vice versa. - :param topic: The topic to communicate on. Will be the same between the master and the slave. - :param ack_topic: Explicitly provide this for the second channel, or it will be created from the name of the - topic itself. Will be the same between the master and the slave. - :param group: The group to assign the instance to. - :param debug: Whether, or not, you want to print the debug strings. - :param debug_prefix: The prefix to use while debugging. - :param kwargs: Any configuration parameters for the Kafka instances. - """ - - # Not down the basic variables: - self.__role = role - self.__topic = topic - self.__ack_topic = ack_topic or topic + "Ack" - self.__group = group - - # In case the current instance is the master, - # it will talk on "topic", and listen on "ack_topic": - if self.__role == self.ROLE_MASTER: - self.__producer_kwargs = kwargs.copy() - self.__producer = ProducerKafka( - topic = self.__topic, - serializer = serializer, - debug = debug, - debug_prefix = debug_prefix.strip() + " (P) | ", - **self.__producer_kwargs - ) - self.__consumer_kwargs = kwargs.copy() - self.__consumer_kwargs["group_id"] = self.__group - self.__consumer = ConsumerKafka( - topic = self.__ack_topic, - group = group, - serializer = serializer, - debug = debug, - debug_prefix = debug_prefix.strip() + " (C) | ", - **self.__consumer_kwargs - ) - - # On the other hand, if the current instance is a slave, - # It will listen on "topic", and talk on "ack_topic": - else: - self.__producer_kwargs = kwargs.copy() - self.__producer = ProducerKafka( - topic = self.__ack_topic, - serializer = serializer, - debug = debug, - debug_prefix = debug_prefix.strip() + " (P) | ", - **self.__producer_kwargs - ) - self.__consumer_kwargs = kwargs.copy() - self.__consumer_kwargs["group_id"] = self.__group - self.__consumer = ConsumerKafka( - topic = self.__topic, - group = group, - serializer = serializer, - debug = debug, - debug_prefix = debug_prefix.strip() + " (C) | ", - **self.__consumer_kwargs - ) - - def enable_debug(self): - self.__producer.enable_debug() - self.__consumer.enable_debug() - - def disable_debug(self): - self.__producer.disable_debug() - self.__consumer.disable_debug() - - async def ensure_connection(self): - await self.__producer.ensure_connection() - await self.__consumer.ensure_connection() - - async def close(self): - await self.__producer.close() - await self.__consumer.close() - - async def produce(self, message, encoding = "utf-8"): - return await self.__producer.produce(message, encoding = encoding) - - async def consume(self, count = 1, timeout = 0.05, encoding = "utf-8"): - return await self.__consumer.consume(count = count, timeout = timeout, encoding = encoding) - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import asyncio - import time - from data_models.kafka_message import KafkaMessage - - ssl_ctx = get_ssl_context( - ca_file = r"/home/developer/PycharmProjects/utils/cred/kafka/cert_authority.pem", - cert_file = r"/home/developer/PycharmProjects/utils/cred/kafka/fullchain.pem", - key_file = r"/home/developer/PycharmProjects/utils/cred/kafka/privkey.pem" - ) - - async def consumer_test(): - - consumer = ConsumerKafka( - topic = "kft_file_upload", - # group_id = "assessImg", - group_id = "updateMedia", - bootstrap_servers = "wtt.ditscentre.in:9092", - security_protocol = "SSL", - ssl_context = ssl_ctx - ) - await consumer.connect() - await asyncio.sleep(1.5) - print("READY!") - - while True: - messages = await consumer.consume(count = 1) - if len(messages) > 0: print("MESSAGE:", json.to_string(messages[0], default=str)) - await asyncio.sleep(1.0) - - async def producer_test(): - - producer = ProducerKafka( - topic = "kft_file_upload", - bootstrap_servers = "del.ditscentre.in:9092", - security_protocol = "SSL", - ssl_context = ssl_ctx - ) - await producer.connect() - print("READY!") - - while True: - my_msg = KafkaMessage( - data = { - "accepted": False, - "reason": "low resolution" - }, - media = { - "name": "pikachu_poster.jpg", - "ext": "jpg", - "url": "https://nexcom.ditscentre.in/utils/files/small/download/66ded1c1c1c05139a618b5ff", - "attr": { - "user": "SarangKabir", - "project": "ACE-PGP", - "id": 173, - "campaignActivityId": "25", - "idCampaign": 49, - "phoneNo": "7977821877" - } - }, - appId = "aceWockhardt", - proc = { - "name": "_assessImg", - "attr": { - "blurThreshold": 0.25, - "clarityThreshold": 0.65, - "nsfwThreshold": 0.25, - "minWidth": 512, - "minHeight": 512 - } - }, - ack = None - ) - success = await producer.produce(my_msg.model_dump()) - print("produced...") - time.sleep(1.0) - break - - await producer.close() - - - asyncio.run(consumer_test()) diff --git a/utils_v2/rate_limit/__init__.py b/utils_v2/rate_limit/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/rate_limit/async_token_bucket.py b/utils_v2/rate_limit/async_token_bucket.py deleted file mode 100644 index 4fb85e7..0000000 --- a/utils_v2/rate_limit/async_token_bucket.py +++ /dev/null @@ -1,212 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Wednesday, 15th May, 2024 - - OBJECTIVE: - - To provide a rate-limiting mechanism using the simple token bucket algorithm. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# For date and time keeping: -import datetime -import time - -# For asynchronous activities: -import asyncio - -# For mathematical operations: -import math - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class TokenBucket: - - """ - MODES: "add" - Add 'rate_limit' no. of tokens to the bucket every interval. - "reset" - Reset the token count to 'rate_limit' every interval - """ - - MODE_RESET = 0 - MODE_ADD = 1 - - ONE_YEAR = 3_15_36_000.0 - ONE_MONTH = 26_78_400.0 - ONE_WEEK = 6_04_800.0 - ONE_DAY = 86_400.0 - ONE_HOUR = 3_600.0 - ONE_MINUTE = 60.0 - ONE_SECOND = 1.0 - - def __init__(self, rate_limit, seconds = 1.0, mode = "reset", sleep = 0.1, in_sequence = False): - - """ - Initialize the rate controller. - :param rate_limit: The no. of operations allowed per unit of time. - :param seconds: The time period in seconds in which the tokens get reset or added. - :param mode: To select what happens when the period is over. 'reset' mode means that the remaining tokens from - the previous period are discarded and the counter is set back to the rate limit, and 'add' mode means that - new tokens are added on top of the exiting ones that were unused in the previous period. - :param sleep: The delay to add before checking back to see if tokens are available. Keep it longer for longer - periods (which is adjusted by the 'seconds' parameter). - :param in_sequence: Whether, or not, you want to maintain the sequence in which the requests were made - (experimental). - """ - - if rate_limit is not None: - rate_limit = int(rate_limit) - self.__semaphore = asyncio.Semaphore(1 if in_sequence else rate_limit) - mode = mode.lower() - if mode not in [self.MODE_RESET, self.MODE_ADD]: mode = self.MODE_RESET - self.__mode = mode - self.__rate_limit = rate_limit - self.__token_count = rate_limit - self.__last_token_generation_time = time.time() - self.__sleep = sleep - self.__seconds = seconds - - async def has_turn(self): - - """ - Just to check if a token is available. - Should be used only if you don't want to wait for turn in case it is unavailable. - :return: True if the token is available, False if not. - """ - - # If the user doesn't want any rate-limits, we return immediately. - # Otherwise, we check if the user has any tokens available: - if self.__rate_limit is None: return True - if self.__token_count > 0: return True - else: return False - - async def get_turn(self, timeout = None): - - """ - To wait till either you get your turn or the wait gets timed-out. - :param timeout: The time (in seconds) to wait to get a turn before exiting with failure. - :return: True if a turn was received, else False if timed-out. - """ - - # If the user doesn't want any rate-limits, we return immediately: - if self.__rate_limit is None: return - - # Start by making variables: - got_turn = False - wait_start = time.time() - - # Otherwise, we wait for the semaphore: - async with self.__semaphore: - - # Wait till you get your turn or the attempt gets timed-out: - while True: - - # If the timeout has been exceeded: - if ( - timeout is not None and - time.time() - wait_start >= timeout - ): break - - # If it is time to generate new tokens: - time_delta = time.time() - self.__last_token_generation_time - if time_delta >= self.__seconds: - if self.__mode == self.MODE_RESET: self.__token_count = self.__rate_limit - else: self.__token_count += int(self.__rate_limit * math.floor(time_delta / self.__seconds)) - self.__last_token_generation_time = time.time() - - # If a token is available (or not): - if self.__token_count > 0: - self.__token_count -= 1 - got_turn = True - break - else: await asyncio.sleep(self.__sleep) - - # Done here: - return got_turn - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import random - - async def single_test(rate_controller, count): - has_turn = await rate_controller.has_turn() - got_turn = await rate_controller.get_turn() - print(f"TURN: {count:.<5} {'Y' if has_turn else '-'} / {'Y' if got_turn else '-'} ({datetime.datetime.now()})") - if got_turn: await asyncio.sleep(random.random()) - - async def multi_test(max_count): - rate_controller = TokenBucket( - rate_limit = 10, - seconds = 1, - in_sequence = False, - sleep = 0.025, - mode = "reset", - timeout = 3 - ) - tasks = [single_test(rate_controller, count + 1) for count in range(max_count)] - await asyncio.gather(*tasks) - - - start_time = time.time() - asyncio.run(multi_test(100)) - print(f"FINISHED IN {time.time() - start_time} SECONDS!") diff --git a/utils_v2/security/__init__.py b/utils_v2/security/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils_v2/security/__pycache__/__init__.cpython-310.pyc b/utils_v2/security/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 7cd905e67a53b0e1d2dea85a60f9b3bc0627e9b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmd1j<>g`kf)G>dbP)X*L?8o3AjbiSi&=m~3PUi1CZpd z%ZBl{9$bAa7<>y&44|V%$DoLs5$Yg@4$LTxQ|zgB zs?=d_&!koAp4go^I!9|KMyJMZ(OZWmU!60k*)Cdro;b)bYBdbc#?N~{Z11j>1O4L1 zK`sU)!aKN~rU_;IAS@>zZR~AbS+_UHxu9gYf>-a$0e+H49)$N+zbaR6fA?f-bMNsl z*S4fM1aRu5YH1Q#H(l|h4;|
    oSM|4Hm$t2+D6?O{Z&xBslQI( zJi~IpaG4Uz6q6`QU*b^eSdbozhWI%P(pa<83nP}0n0ZBpwTy5QmwZeyt>L{Z$p%E? zVVdKYBq`Fx1Sr!v3m$W!xh3LeUe09Blbg8$l3YT^cmh6>O)r?5Vc%l|X{#?jV=92k(=FH?4(5I@LWf2M38R9mK&kVi@ zf9E^R0Z`GT?1)8a#&~mQ7z_xHcX)ch0x6m#3w_e>`!o&mm?g5AODGBdXtgO=kn>Ou zn*ypzh9jsLFB_^kO{%Y1eGCT(?M&OPArpSizx+KIUK3i2JQF&Dffo40n1I+5QyODK zqGOXUYr#)o^vF0y6LSn6E9Oj?`#OY`P#V@L%@ zEBf8o9HX&yjMj}8pXfaG%IMER{`T}UK){4z8VaC6$3y(2z1?aQ{wV4d3JeM%Nb`t7 zDV4fuBel}@Pfr_RqKN}{VNiqwhvFT@bwOrX5>Y6?q#TY6in4;77nIWJ=4%x+#Yw@k zmmAB4*QmYlP#ahka4$|hqzR_hYij~@!spwq(cLShwc>XhU9a2iHrF0}-uYO;97FKGWrPE@#8ey>k6Eyr$j< zZHBiG2=|={0;$n4`rUj1ausL74Kg>&SvQsG-Ba!bsc%E8t!tjZ@!3PJ;pt3&GGrk|bct)+v;&6;hQ@vRHuchTxa?Az8hm7Rrlk24M+atEHKWGxsQT zsL;_{2#X}oG&C)eTeIhC)&he5+(viMXUMjS70UH}xQ`Rxug|NhuXFmovcwRufcpo^ zAz8)}sunLS>Xo-(c>y@(Ksg-BJB?wZ3$ X+)w8b{4CdU(ZXGK$^FtX?f?Dg`kf)G>dbP)X*L?8o3AjbiSi&=m~3PUi1CZpdVA0MBYmst`YuUAlci^C>2KczG$)edA!F%ytrVE_OIhbf-` diff --git a/utils_v2/string/__pycache__/json.cpython-310.pyc b/utils_v2/string/__pycache__/json.cpython-310.pyc deleted file mode 100644 index cc302a5c730bb28ea4bb248fa6991af305935e97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3546 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 Rq0kZkuHo;|i1HUj`6n4TLu>#5 diff --git a/utils_v2/string/fuzzy.py b/utils_v2/string/fuzzy.py deleted file mode 100644 index 34c08d4..0000000 --- a/utils_v2/string/fuzzy.py +++ /dev/null @@ -1,168 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Saturday, 18th May, 2024 - - OBJECTIVE: - - To provide a quick set of functions to work with fuzzy logic. - - REFERENCES: - - 1) https://www.w3schools.com/python/python_json.asp - - DOWNLOADS: - - N/A - -""" - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# To apply fuzzy logic: -from thefuzz import fuzz, process - -# To work with tabulated data: -import pandas as pd - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def get_best_match( - target, - choices, - threshold = 0.70, - partial = False -): - - if partial: scorer = fuzz.partial_token_sort_ratio - else: scorer = fuzz.ratio - - result = process.extractOne( - target, - choices, - score_cutoff = threshold * 100, - scorer = scorer - ) - - try: return result[0] - except: return None - - -# --------------------------------------------------------------------------------------------------------------------- - - -def rank(target, choices, partial = True): - - if partial: scorer = fuzz.partial_token_sort_ratio - else: scorer = fuzz.ratio - - result = process.extract( - target, - choices, - limit = len(choices), - scorer = scorer - ) - - result = pd.DataFrame(result, columns = ["choice", "closeness"]) - result["closeness"] = result["closeness"] / 100.0 - - return result - - -# --------------------------------------------------------------------------------------------------------------------- - - -def match(targets, choices, threshold = 0.7, partial = False, allow_null = False): - - all_matches_df = None - all_matches = {target: None for target in targets} - something_is_null = False - - for target in targets: - match_df = rank(target, choices, partial = partial) - match_df["target"] = target - if all_matches_df is None: all_matches_df = match_df - else: all_matches_df = pd.concat([all_matches_df, match_df]) - - all_matches_df = all_matches_df.sort_values(by = ["closeness"], ascending = False).reset_index(drop = True) - - for target in targets: - target_df = all_matches_df[all_matches_df["target"] == target].reset_index(drop = True) - if target_df.empty: continue - if target_df.at[0, "closeness"] >= threshold: - choice = target_df.at[0, "choice"] - all_matches[target] = choice - all_matches_df = all_matches_df[all_matches_df["choice"] != choice] - else: - all_matches[target] = None - something_is_null = True - - # print(all_matches) - if something_is_null and not allow_null: return None - else: return all_matches - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import async_json_utils - - awb_numbers = [ - "SF1111BIC", - "SF2222BIC", - "SF3333BIC", - "SF4444BIC", - ] - - chat_text = "SF1112BIC" - - # print(chat_text == names[0]) - best_match = get_best_match(chat_text, awb_numbers, threshold = 0.60, partial = False) - print(f"Best match for '{chat_text}' is '{best_match}'") diff --git a/utils_v2/string/help.py b/utils_v2/string/help.py deleted file mode 100644 index 85dcc97..0000000 --- a/utils_v2/string/help.py +++ /dev/null @@ -1,177 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Saturday, 24th Aug., 2024 - - OBJECTIVE: - - To provide an overview of any function or class in a string. - The generated overview can then either be shown on the terminal, or transmitted over some other medium for - collaborative work. - - REFERENCES: - - N/A - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# System-level activities: -import io -import inspect - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def get_help_for_class(cls, skip_methods = None): - - """ - Returns the help documentation to use this class. - :param cls: The class whose help string is desired. - :param skip_methods: A list of methods to NOT include in the help text. - :return: This help documentation. - """ - - separator = "\n\n" + ("=" * 120) + "\n\n" - if skip_methods is None: skip_methods = [] - elif not isinstance(skip_methods, list): skip_methods = [skip_methods] - - # Get class name and docstring: - class_name = cls.__name__ - docstring = inspect.getdoc(cls) or "" - help_string = "HELP FOR:\n\n" - help_string += class_name + "\n\n" - help_string += "This document has upto 120 chars per line.\n" - help_string += "Best viewed with monospaced font :)" - help_string += docstring + separator - - # Get all methods and their docstrings. - # Then note the documentation of the methods while ignoring the blacklisted ones: - members = inspect.getmembers(cls, predicate = inspect.isfunction) - func_help = [] - for name, method in members: - - # Ignore if asked, or extract the details: - if name in skip_methods or name.startswith(f"_{class_name}__"): continue - else: func_help.append(get_help_for_function(method)) - - # Put all the things together: - func_help = separator.join(func_help) - help_string += func_help - - # Done here: - return help_string - - -# --------------------------------------------------------------------------------------------------------------------- - - -def get_help_for_function(func): - - """ - Get the help string for one function. - It could be a standalone function, or a method of a class. - :param func: The function (or method) whose help string is needed. - :return: The help string of the function. - """ - - # Get the name and documentation: - func_name = func.__name__ - async_indicator = " (async)" if inspect.iscoroutinefunction(func) else "" - func_doc = inspect.getdoc(func) or "" - - # Create the decorated header: - func_decorator = "-" * (len(func_name) + 2) - func_head = "." + func_decorator + f".\n| {func_name} |{async_indicator}\n`" + func_decorator + "`\n\n" - - # Add the 'args' and 'kwargs': - func_args = [] - for name, param in inspect.signature(func).parameters.items(): - default = param.default - if isinstance(default, str): default = f"\"{default}\"" - if default == inspect.Parameter.empty: func_args.append(f"{name}") - else: func_args.append(f"{name}: {type(default).__name__} = {default}") - if len(func_args) > 0: func_args = f"{func_name} (\n\t" + "\n\t".join(func_args) + "\n):\n\n" - else: func_args = f"{func_name} ():\n\n" - - # Get the params and return value part from the doc: - params_start = func_doc.find(":param") - return_start = func_doc.find(":return") - func_params = "\n" + func_doc[params_start:return_start] if params_start >= 0 else "" - func_return = "\n" + func_doc[return_start:] if return_start >= 0 else "" - - # Isolate the documentation part: - if params_start >= 0: func_doc = func_doc[:params_start] - elif return_start >= 0: func_doc = func_doc[:return_start] - - # Done here: - return func_head + func_args + func_doc + func_params + func_return - - -# --------------------------------------------------------------------------------------------------------------------- - - -def get_help(entity, skip_methods = None): - - """ - Get the help documentation for anything from its docstring. - :param entity: The entity you want to get help for. - :param skip_methods: A list of methods to ignore if inspecting a class. Not valid for standalone functions. - :return: The help string. - """ - - if inspect.isclass(entity): return get_help_for_class(entity, skip_methods = skip_methods) - else: return get_help_for_function(entity) - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/string/json.py b/utils_v2/string/json.py deleted file mode 100644 index 67d39f7..0000000 --- a/utils_v2/string/json.py +++ /dev/null @@ -1,202 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Create: Saturday, 18th May, 2022 - Update: Thursday, 22nd Aug. 2024 - - OBJECTIVE: - - To provide an easy way to work with '.json' data and files. - - REFERENCES: - - 1) https://www.w3schools.com/python/python_json.asp - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# To work with the JSON standard: -import json - -# To work with files: -from utils_v2.system import files - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def from_string(json_data): - - """ - Decodes a JSON string to a pythonic variable like a dict. - :param json_data: The JSON string to decode. - :return: The decoded pythonic variable. - """ - - python_data = json.loads(json_data) - return python_data - - -# --------------------------------------------------------------------------------------------------------------------- - - -def to_string( - python_data, - indent = 4, - default = None, - separators = None, - no_space = False -): - - """ - Converts the given pythonic data to a JSON string. - :param python_data: The input data like a dict. - :param indent: The tab-width for pretty presentation. - :param default: The function to use on something that cannot be directly parsed into a JSON string. - :param separators: Custom separators to use. - :param no_space: If you want a dense JSON string that saves memory by not using spaces or tabs or line-breaks. Not - good for human readability, very good for saving memory. WARNING: THIS OVERRIDES EVERY OTHER PARAMETER EXCEPT - 'default'. - :return: The JSON string representation of the input pythonic data. - """ - - if no_space: - json_data = json.dumps( - python_data, - default = default, - separators = (',', ':') - ) - - else: - json_data = json.dumps( - python_data, - indent = indent, - default = default, - separators = separators - ) - - return json_data - - -# --------------------------------------------------------------------------------------------------------------------- - - -def from_file(file): - - """ - Reads a JSON file and returns it as a pythonic variable like a dict. - :param file: The path to the file on the disk or a file held in RAM as a BytesIO object. - :return: The decoded pythonic variable. - """ - - if isinstance(file, io.BytesIO): - file.seek(0) - json_data = file.getvalue() - else: json_data = files.read_file(file) - python_data = from_string(json_data) - return python_data - - -# --------------------------------------------------------------------------------------------------------------------- - - -def to_file( - file, - python_data, - indent = 4, - default = None, - separators = None, - no_space = False -): - - """ - - :param file: Either a path to a file on disk, or a buffer in RAM in the form of a BytesIO object. - :param python_data: The pythonic data to be converted to the JSON string. - :param indent: The tab-width for pretty presentation. - :param default: The function to use on something that cannot be directly parsed into a JSON string. - :param separators: Custom separators to use. - :param no_space: If you want a dense JSON string that saves memory by not using spaces or tabs or line-breaks. Not - good for human readability, very good for saving memory. WARNING: THIS OVERRIDES EVERY OTHER PARAMETER EXCEPT - 'default'. - :return: True/False if a path was given, else the same BytesIO object with the written JSON data. - """ - - json_data = to_string( - python_data, - indent = indent, - default = default, - separators = separators, - no_space = no_space - ) - - if isinstance(file, io.BytesIO): - file.write(json_data.encode("utf-8")) - file.seek(0) - return file - - else: - try: - files.write_file(file, json_data, mode = "w") - return True - except: return False - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - pass diff --git a/utils_v2/string/regex.py b/utils_v2/string/regex.py deleted file mode 100644 index 3a8234f..0000000 --- a/utils_v2/string/regex.py +++ /dev/null @@ -1,288 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Sunday, 28th Apr., 2024 - - OBJECTIVE: - - To provide a convenient way to perform RegEx operations like finding patterns and substituting them. - - REFERENCES: - - 1) https://www.w3schools.com/python/python_regex.asp - - DOWNLOADS: - - N/A - -""" - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# To work with RegEx: -import re - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# Common RegEx patterns: -REGEX_EMAIL_ID = r"[\d\w\-_.+]*@[\d\w\-_]*.[\d\w]{2,}" -REGEX_PASSWORD = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*[\d])(?=.*[!@#$%^&*()_+{}\[\]:;<>,.?~\\\/-]).{8,}$" -REGEX_NAME = r"^[\d\w .\-]{1,30}$" -REGEX_USERNAME = r"^[\d\w_]{8,25}$" -REGEX_CONTACT_NUMBER = r"\+?\d{0,3}\s*\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}" -REGEX_DATE = r"\b(?:\d{4}-\d{2}-\d{2}|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{1,2},?\s+\d{4}|\d{1,2}\/\d{1,2}\/\d{4}|\d{1,2}-\d{1,2}-\d{2}|\d{1,2}(?:st|nd|rd|th)\s+(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?),?\s+\d{4})\b" -REGEX_GSTIN = r"[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}" -REGEX_PAN = r"[A-Z]{5}[0-9]{4}[A-Z]{1}" -REGEX_IPV4 = (r"[0-9]{1,3}\." * 3) + r"[0-9]{1,3}" -REGEX_IPV6 = (r"[0-9a-fA-F]{1,4}:" * 7) + r"[0-9a-fA-F]{1,4}" -REGEX_IFSC = r"[A-Z]{4}0[A-Z0-9]{6}" -REGEX_UPI = r"[a-zA-Z0-9\.\-]{2,256}@[a-zA-Z][a-zA-Z]{2,64}" -REGEX_MAC_ADDRESS = r"([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})|([0-9a-fA-F]{4}\\.[0-9a-fA-F]{4}\\.[0-9a-fA-F]{4})" -REGEX_METRIC_WEIGHT = r"[\d\.]+[ ]?[k]?g" - - -# RegEx chars (append them to the patterns if needed): -REGEX_START = "^" -REGEX_END = "$" - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -def find(text, pattern, case_sensitive = True, dot_all = False): - - """ - Returns a list of substrings that match the given RegEx pattern in the input text. - :param text: The text in which the pattern needs to be found. - :param pattern: The RegEx pattern to look for. - :param case_sensitive: Whether, or not, you want the operation to be case-sensitive. - :param dot_all: Allow all characters to be matched in ".". - :return: An array (list) of substring that match the pattern. Can be an empty list as well. - """ - - # Prepare the flags: - flags = 0 - if not case_sensitive: flags |= re.IGNORECASE - if dot_all: flags |= re.DOTALL - - # Perform the RegEx operation, and clean the results: - matches = [match if type(match) is str else match[1] for match in re.findall(pattern, text, flags = flags)] - matches = [match for match in matches if len(match) > 0] - - # Return the results: - return matches - - -# --------------------------------------------------------------------------------------------------------------------- - - -def find_first(text, pattern, case_sensitive = True, dot_all = False): - - """ - Returns the first substring that matches the given RegEx pattern in the input text. - :param text: The text in which the pattern needs to be found. - :param pattern: The RegEx pattern to look for. - :param case_sensitive: Whether, or not, you want the operation to be case-sensitive. - :param dot_all: Allow all characters to be matched in ".". - :return: The first match as a string, or None if no match was found.. - """ - - matches = find( - text = text, - pattern = pattern, - case_sensitive = case_sensitive, - dot_all = dot_all - ) - - if not matches: return None - else: return matches[0] - - -# --------------------------------------------------------------------------------------------------------------------- - - -def replace(text, pattern, substitute_text, case_sensitive = True, dot_all = False): - - """ - Replaces any substring in the text that matches the RegEx pattern. - :param text: The text in which the substitutions need to be made. - :param pattern: The RegEx pattern that needs to be substituted. - :param substitute_text: The text that will replace the matches that were found. - :param case_sensitive: Whether, or not, you want the operation to be case-sensitive. - :param dot_all: Allow all characters to be matched in ".". - :return: The text with the substitutions. If no matches are found, the original string is returned. - """ - - # Prepare the flags: - flags = 0 - if not case_sensitive: flags |= re.IGNORECASE - if dot_all: flags |= re.DOTALL - - # Perform the RegEx operation, and return the results: - return re.sub(pattern, substitute_text, text, flags = flags) - - -# --------------------------------------------------------------------------------------------------------------------- - - -def search(text, pattern, case_sensitive = True, dot_all = False): - - """ - Checks if the given RegEx pattern occurs ANYWHERE in the text that was provided. - :param text: The text that needs to be matched against the pattern. - :param pattern: The RegEx pattern to look for. - :param case_sensitive: Whether, or not, you want the operation to be case-sensitive. - :param dot_all: Allow all characters to be matched in ".". - :return: True if the pattern matches, else False. - """ - - # Prepare the flags: - flags = 0 - if not case_sensitive: flags |= re.IGNORECASE - if dot_all: flags |= re.DOTALL - - # Perform the RegEx operation, and return the results: - if re.search(pattern, text, flags = flags): return True - else: return False - - -# --------------------------------------------------------------------------------------------------------------------- - - -def match(text, pattern, case_sensitive = True, dot_all = False): - - """ - Checks if the given text matches the RegEx pattern that was provided. The check is made only at the start of the - input string. - :param text: The text that needs to be matched against the pattern. - :param pattern: The RegEx pattern to look for. - :param case_sensitive: Whether, or not, you want the operation to be case-sensitive. - :param dot_all: Allow all characters to be matched in ".". - :return: True if the pattern matches, else False. - """ - - # Prepare the flags: - flags = 0 - if not case_sensitive: flags |= re.IGNORECASE - if dot_all: flags |= re.DOTALL - - # Perform the RegEx operation, and return the results: - if re.match(pattern, text, flags = flags): return True - else: return False - - -# --------------------------------------------------------------------------------------------------------------------- - - -def split(text, pattern, case_sensitive = True, dot_all = False): - - """ - Splits an input string based on the pattern that is being matched. - :param text: The text that needs to be matched against the pattern. - :param pattern: The RegEx pattern to look for. - :param case_sensitive: Whether, or not, you want the operation to be case-sensitive. - :param dot_all: Allow all characters to be matched in ".". - :return: True if the pattern matches, else False. - """ - - # Prepare the flags: - flags = 0 - if not case_sensitive: flags |= re.IGNORECASE - if dot_all: flags |= re.DOTALL - - # Perform the RegEx operation, and return the results: - substrings = re.split(pattern, text, flags = flags) - if len(substrings) > 0 and substrings[0] == "": substrings.pop(0) - return substrings - - -# --------------------------------------------------------------------------------------------------------------------- - - -def to_json(text, pattern, case_sensitive = True, dot_all = False): - - """ - Gives out a dict from the extracted features in a string. It is based on the concept of Named Groups. - Consider the following example (assuming the search is case-insensitive): - TEXT: "UPI/309258561479/14:17:35/UPI/omsainurses@okhdfc" - PATTERN: "upi/.*/(?P