diff --git a/utils_v2/.gitignore b/utils_v2/.gitignore
new file mode 100644
index 0000000..ebb370b
--- /dev/null
+++ b/utils_v2/.gitignore
@@ -0,0 +1,8 @@
+/.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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/ai/__init__.py b/utils_v2/ai/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/ai/image_classification/__init__.py b/utils_v2/ai/image_classification/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/ai/image_classification/async_blur.py b/utils_v2/ai/image_classification/async_blur.py
new file mode 100644
index 0000000..f69af42
--- /dev/null
+++ b/utils_v2/ai/image_classification/async_blur.py
@@ -0,0 +1,202 @@
+"""
+
+ 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
new file mode 100644
index 0000000..446c34a
--- /dev/null
+++ b/utils_v2/ai/image_classification/async_nsfw.py
@@ -0,0 +1,188 @@
+"""
+
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/ai/image_segmentation/async_dichotomous_segmentation.py b/utils_v2/ai/image_segmentation/async_dichotomous_segmentation.py
new file mode 100644
index 0000000..fb6d6c7
--- /dev/null
+++ b/utils_v2/ai/image_segmentation/async_dichotomous_segmentation.py
@@ -0,0 +1,223 @@
+"""
+
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/ai/object_detection/yolo.py b/utils_v2/ai/object_detection/yolo.py
new file mode 100644
index 0000000..a435ca6
--- /dev/null
+++ b/utils_v2/ai/object_detection/yolo.py
@@ -0,0 +1,176 @@
+"""
+
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/ai/tts/easy_tts.py b/utils_v2/ai/tts/easy_tts.py
new file mode 100644
index 0000000..fc4bb9b
--- /dev/null
+++ b/utils_v2/ai/tts/easy_tts.py
@@ -0,0 +1,175 @@
+"""
+
+ 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
new file mode 100644
index 0000000..d38cfc0
Binary files /dev/null and b/utils_v2/ai/tts/test.wav differ
diff --git a/utils_v2/api/__init__.py b/utils_v2/api/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/api/__pycache__/__init__.cpython-310.pyc b/utils_v2/api/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000..f44186d
Binary files /dev/null and b/utils_v2/api/__pycache__/__init__.cpython-310.pyc differ
diff --git a/utils_v2/api/__pycache__/async_quart.cpython-310.pyc b/utils_v2/api/__pycache__/async_quart.cpython-310.pyc
new file mode 100644
index 0000000..81ae0d2
Binary files /dev/null and b/utils_v2/api/__pycache__/async_quart.cpython-310.pyc differ
diff --git a/utils_v2/api/__pycache__/codes.cpython-310.pyc b/utils_v2/api/__pycache__/codes.cpython-310.pyc
new file mode 100644
index 0000000..47eef7c
Binary files /dev/null and b/utils_v2/api/__pycache__/codes.cpython-310.pyc differ
diff --git a/utils_v2/api/__pycache__/log.cpython-310.pyc b/utils_v2/api/__pycache__/log.cpython-310.pyc
new file mode 100644
index 0000000..955fe4b
Binary files /dev/null and b/utils_v2/api/__pycache__/log.cpython-310.pyc differ
diff --git a/utils_v2/api/__pycache__/metrics_prometheus.cpython-310.pyc b/utils_v2/api/__pycache__/metrics_prometheus.cpython-310.pyc
new file mode 100644
index 0000000..724908a
Binary files /dev/null and b/utils_v2/api/__pycache__/metrics_prometheus.cpython-310.pyc differ
diff --git a/utils_v2/api/__pycache__/response.cpython-310.pyc b/utils_v2/api/__pycache__/response.cpython-310.pyc
new file mode 100644
index 0000000..30d35cd
Binary files /dev/null and b/utils_v2/api/__pycache__/response.cpython-310.pyc differ
diff --git a/utils_v2/api/async_quart.py b/utils_v2/api/async_quart.py
new file mode 100644
index 0000000..a0113ef
--- /dev/null
+++ b/utils_v2/api/async_quart.py
@@ -0,0 +1,1276 @@
+"""
+
+ AUTHOR:
+
+ Khushal P Soonderji
+
+ DATE:
+
+ Friday, 2nd Aug., 2024
+
+ OBJECTIVE:
+
+ To provide an easy way to perform repetitive tasks in quart.
+
+ REFERENCES:
+
+ N/A
+
+ DOWNLOADS:
+
+ N/A
+
+ NOTES:
+
+ 01. PLEASE USE "ResponseModel" AS THE RETURNED VALUE OF THE API ENDPOINT IF YOU ARE USING ANY OF THESE
+ DECORATORS.
+
+"""
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** IMPORT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# To work with Quart:
+from quart import request, current_app, g, make_response
+
+# To make decorators:
+from functools import wraps
+
+# My utils:
+from utils_v2.string import json
+from utils_v2.date_time import date_time
+from utils_v2.security import sanitizers
+from utils_v2.api.codes import StatusCodes, HttpCodes
+from utils_v2.api.log import APILogModel
+from utils_v2.api.response import ResponseModel
+from utils_v2.logging.context import AsyncLoggerContext, AsyncMongoLogger
+
+# System-level activities:
+import io
+import os
+
+# To work with datatypes:
+from types import NoneType
+import pandas as pd
+
+# For Pydantic data-behaviour_models:
+import pydantic
+from typing import List
+
+# For hashing and shortening the hash:
+import hashlib
+import base64
+
+# To make things human-readable:
+import humanize
+
+# For debugging:
+import traceback
+import random
+import string
+
+# For asynchronous activities:
+import asyncio
+
+# For timekeeping:
+import time
+import datetime
+
+# To make copies:
+import copy
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** MACROS / ONE-TIME INIT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# Chars to choose from for random strings:
+ALPHANUMERIC_CHARS = string.ascii_letters + string.digits
+
+# To capture system information:
+PROCESS_ID = os.getppid()
+PARENT_PROCESS_ID = os.getppid()
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** VARIABLES ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** FUNCTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** EXCEPTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+class AuthDetailsIncompleteException(Exception):
+ def __str__(self):
+ return "incomplete auth details"
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** FUNCTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+async def make_ordered_json(
+ json_data,
+ no_space = True,
+ http_code = 200
+):
+
+ """
+ Quart sorts the fields of a dict when converting to a JSON response. Here we are manually making the response when
+ the sequence of the fields is sensitive.
+ :param json_data: The data (dict, list, etc.) to be converted to a JSON string.
+ :param no_space: Set this to True to remove all excess white spaces from the JSON string. Saves bandwidth.
+ :param http_code: The HTTP status code you want to send with the response.
+ :return: The JSON-ified response such that the sequence of the fields is maintained.
+ """
+
+ response = await make_response(json.to_string(json_data, no_space = no_space), http_code)
+ response.headers["Content-Type"] = "application/json"
+ return response
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+async def data_from_request(inbound_request):
+
+ """
+ Adaptively extract the params from incoming request in whichever way it was provided.
+ :param inbound_request: The request that came in.
+ :return: A dict (could be empty) of the data/params that came in with the request.
+ """
+
+ inbound_data = {}
+
+ # Extract data from the params in the URL:
+ from_args = inbound_request.args.to_dict()
+ if isinstance(from_args, dict):
+ for k, v in from_args.items():
+ inbound_data[k] = v
+
+ # Extract data from the raw JSON data:
+ from_json = await request.get_json()
+ if isinstance(from_json, dict):
+ for k, v in from_json.items():
+ inbound_data[k] = v
+
+ # Extract inputs from the form body:
+ from_form = await inbound_request.form
+ from_form = from_form.to_dict()
+ if isinstance(from_form, dict):
+ for k, v in from_form.items():
+ inbound_data[k] = v
+
+ return inbound_data
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+async def file_from_request(inbound_request, file_key):
+
+ """
+ Extracts ONE file from the incoming request's form-data.
+ WARNING: NOT RECOMMENDED FOR LARGE FILES. STRICTLY USE FOR SMALL FILES THAT WON'T CRASH THE SCRIPT.
+ :param inbound_request: The incoming request.
+ :param file_key: The key of the file that you want to extract.
+ :return: A tuple of the file's name and data.
+ """
+
+ file_name = None
+ file_data = None
+ files = await inbound_request.files
+
+ if file_key in files:
+ file_name = files[file_key].filename
+ file_data = io.BytesIO(files[file_key].read())
+
+ return file_name, file_data
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+async def files_from_request(inbound_request: request):
+
+ """
+ Extracts ALL files from the incoming request's form-data.
+ WARNING: NOT RECOMMENDED FOR LARGE FILES. STRICTLY USE FOR SMALL FILES THAT WON'T CRASH THE SCRIPT.
+ :param inbound_request: The incoming request.
+ :return: A dict describing the file's name, data, and size.
+ """
+
+ files = await inbound_request.files
+
+ inbound_files = {}
+ for file_key in files:
+ file_data = io.BytesIO(files[file_key].read())
+ file_size = file_data.seek(0, 2)
+ file_data.seek(0)
+ inbound_files[file_key] = {
+ "name": files[file_key].filename,
+ "data": file_data,
+ "size": file_size,
+ "type": files[file_key].content_type
+ }
+
+ return inbound_files
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+async def headers_from_request(
+ inbound_request,
+ mandatory_keys: list = None
+):
+
+ """
+ Extract custom headers and some extra info. from the incoming request.
+ Raises an exception if any mandatory key is missing.
+ IMPORTANT: CUSTOMIZE THIS FOR THE NEEDS OF YOUR PROJECT.
+ :param inbound_request: The request that came in.
+ :param mandatory_keys: The keys that you need to have in the auth.
+ :return: The extracted auth details.
+ """
+
+ # Start by extracting whatever complies with the format of "X-{Header-Name}":
+ head_json = {k: v for k, v in request.headers.items() if k.startswith("X-")}
+
+ # Now note down things that you want to keep from incoming requests:
+ head_json["Remote-IP"] = inbound_request.remote_addr
+ head_json["Host"] = inbound_request.headers.get("Host")
+ head_json["Origin"] = inbound_request.headers.get("Origin")
+ head_json["User-Agent"] = inbound_request.headers.get("User-Agent")
+ head_json["Content-Type"] = inbound_request.headers.get("Content-Type")
+ head_json["Content-Length"] = inbound_request.headers.get("Content-Length")
+
+ # Raise an exception if any of the mandatory auth details were missing:
+ if mandatory_keys is not None:
+ available_keys = head_json.keys()
+ for mandatory_key in mandatory_keys:
+ if mandatory_key not in available_keys: raise AuthDetailsIncompleteException
+
+ # Done here:
+ return head_json
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+def cause_exception():
+
+ """
+ Call this from any function when you want to raise an exception.
+ Example use case would be when receiving data from an API call and that field is not supposed to be null.
+ :return: None.
+ """
+
+ return 100/0
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+def describe_exception(exc):
+
+ """
+ Describes the exception in detail. It extracts the type of exception, a brief message, and even the entire
+ traceback. Useful for debugging in details without the terminal. You could either log the resultant dict or send it
+ to the dev team over some service like WhatsApp/Telegram.
+ :param exc: The exception that occurred.
+ :return: The dict that explains the exception.
+ """
+
+ exc_desc = {
+ "type": type(exc).__name__,
+ "msg": str(exc),
+ "tb": [str(exc_tb) for exc_tb in traceback.format_exception(exc, value = exc, tb = exc.__traceback__)]
+ }
+
+ return exc_desc
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+def messages_from_pydantic_exception(exception, as_str = True, sep = ", "):
+
+ """
+ Creates a list of readable error messages from Pydantic's validation failure.
+ :param exception: Pydantic's ValidationError
+ :param as_str: Set to True to receive all messages as one string, False to receive an array of strings.
+ :param sep: The separator to use when joining multiple messages as one string.
+ :return: A list of messages of all the things that went wrong.
+ """
+
+ # Make a variable to hold all individual messages:
+ messages = []
+
+ # Interpret all the problems:
+ for error in exception.errors():
+ loc = " --> ".join([str(item) for item in error["loc"]])
+ msg = error.get("msg")
+ if error["type"] == "missing": messages.append(f"missing input: '{loc}'")
+ elif error["type"] == "model_type": messages.append(f"invalid input: '{loc}'")
+ elif error["type"] == "bool_parsing": messages.append(f"invalid bool: '{loc}'")
+ elif error["type"] == "string_type": messages.append(f"invalid string: '{loc}'")
+ elif error["type"] == "float_parsing": messages.append(f"invalid float: '{loc}'")
+ elif error["type"] == "int_parsing": messages.append(f"invalid integer: '{loc}'")
+ elif error["type"] == "extra_forbidden": messages.append(f"extra input: '{loc}'")
+ elif error["type"] == "value_error": messages.append(f"validation failed: '{loc}' ({msg})")
+ else: messages.append(f"invalid value: '{loc}'")
+
+ # Return a response as per the preference of the user:
+ if as_str: return sep.join(messages)
+ else: return messages
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+def summarize_variable(
+ value,
+ str_limit = 1024,
+ expand: bool | int = False,
+ sensitive_keys: list[str] = None
+):
+
+ """
+ To summarize an input value to capture the essence without hoarding to much data.
+ :param value: Anything that you want to summarize.
+ :param str_limit: The max. no. of chars of a string to retain.
+ :param expand: Set to True for full expansion, False for no expansion, and an integer for a specific level of
+ expansion. Applicable on iterables and dicts. The smaller this number, the more concise the summary will be,
+ and vice versa.
+ :param sensitive_keys: The list of keys (of a dict) to obscure when summarizing.
+ :return: The summarized version of the input.
+ """
+
+ # Basic prep:
+ if value is None: return None
+ if sensitive_keys is None: sensitive_keys = []
+ value_copy = copy.deepcopy(value)
+
+ # If the value is a Pydantic model, we convert to dict:
+ if isinstance(value_copy, pydantic.BaseModel):
+ value_copy = value_copy.model_dump()
+
+ # Handle datatypes that you don't want to modify:
+ if isinstance(value_copy, (int, float, bool, NoneType)): pass
+
+ # When the value is a list or similar iterable:
+ elif isinstance(value_copy, (list, tuple, set)):
+ if expand:
+ if not isinstance(expand, bool): expand -= 1
+ value_copy = [AsyncLoggerContext.summarize(
+ v,
+ expand = expand,
+ sensitive_keys = sensitive_keys
+ ) for v in value_copy]
+ else: value_copy = f"array of {len(value_copy)} item(s)"
+
+ # If the value is a dict:
+ elif isinstance(value_copy, dict):
+ if expand:
+ if not isinstance(expand, bool): expand -= 1
+ value_copy = {
+ k: AsyncLoggerContext.summarize(
+ v,
+ expand = expand,
+ sensitive_keys = sensitive_keys
+ ) if k not in sensitive_keys else f"{len(str(v))} sensitive char(s)"
+ for k, v in value_copy.items()
+ }
+ else: value_copy = f"object of {len(value_copy.keys())} field(s) [{', '.join(value_copy.keys())}]"
+
+ # When a dataframe is passed:
+ elif isinstance(value_copy, pd.DataFrame):
+ cols = value_copy.columns.to_list()
+ value_copy = f"table with {len(cols)} col(s) [{', '.join(cols)}] and {len(value_copy)} row(s)"
+ str_limit = 1024
+
+ # If the input is some form of non-standard object:
+ else: value_copy = str(value_copy)
+
+ # Handle strings:
+ if isinstance(value_copy, str):
+ if len(value_copy) > str_limit: value_copy = value_copy[:str_limit] + "...(trunc'd)"
+
+ # Done here:
+ return value_copy
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+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:
+ session_info = summarize_variable(session_info, expand = True, sensitive_keys = sensitive_keys)
+ if session_info and isinstance(get, str):
+ for subkey in get.split("."):
+ session_info = session_info.get(subkey, {}) if isinstance(session_info, dict) else {}
+ 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] = f"{len(str(kwargs[var][k]))} sensitive char(s)"
+ 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 = summarize_variable(kwargs.get("session_info"), expand = True),
+ 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
new file mode 100644
index 0000000..5773cc9
--- /dev/null
+++ b/utils_v2/api/codes.py
@@ -0,0 +1,164 @@
+"""
+
+ 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
new file mode 100644
index 0000000..49ccd77
--- /dev/null
+++ b/utils_v2/api/log.py
@@ -0,0 +1,139 @@
+"""
+
+ 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
new file mode 100644
index 0000000..7783cfe
--- /dev/null
+++ b/utils_v2/api/response.py
@@ -0,0 +1,133 @@
+"""
+
+ 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.
+ """
+
+ # 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]
+
+ # Construct the basic structure:
+ response_dict = {
+ "status": 1 if self.status_code.value[0] else 0,
+ "code": response_http_code,
+ "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
+
+ # 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/cache/__pycache__/__init__.cpython-310.pyc b/utils_v2/cache/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000..b168cc8
Binary files /dev/null and b/utils_v2/cache/__pycache__/__init__.cpython-310.pyc differ
diff --git a/utils_v2/cache/__pycache__/async_redis_cache.cpython-310.pyc b/utils_v2/cache/__pycache__/async_redis_cache.cpython-310.pyc
new file mode 100644
index 0000000..6a0d7d1
Binary files /dev/null and b/utils_v2/cache/__pycache__/async_redis_cache.cpython-310.pyc differ
diff --git a/utils_v2/cache/async_redis_cache.py b/utils_v2/cache/async_redis_cache.py
new file mode 100644
index 0000000..a0ab8c0
--- /dev/null
+++ b/utils_v2/cache/async_redis_cache.py
@@ -0,0 +1,497 @@
+"""
+
+ AUTHOR:
+
+ Khushal P Soonderji
+
+ DATE:
+
+ Thursday, 11th April, 2024
+
+ OBJECTIVE:
+
+ To provide an easy way to work with '.json' files in an async manner.
+
+ REFERENCES:
+
+ 1) https://www.w3schools.com/python/python_json.asp
+
+ DOWNLOADS:
+
+ N/A
+
+"""
+
+# *****************************************************************************************************************
+# ***** ****
+# *** IMPORT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# To use redis:
+import redis.asyncio as redis
+
+# Other utils:
+from utils_v2.string import json
+
+# For debugging:
+from icecream import IceCreamDebugger
+
+# To make a decorator:
+from functools import wraps
+
+# For hashing and shortening the hash:
+import hashlib
+import base64
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** 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:
+
+ # Handle datatypes when setting values to cache:
+ __set_converters = {
+ "set": lambda x: list(x),
+ "tuple": lambda x: list(x),
+ "complex": lambda x: {"r": x.real, "i": x.imag}
+ }
+
+ # Handle datatypes when getting from cache:
+ __get_converters = {
+ "set": lambda x: set(x),
+ "tuple": lambda x: tuple(x),
+ "complex": lambda x: complex(x["r"], x["i"])
+ }
+
+ def __init__(
+ self,
+ connection_string,
+ 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 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.__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):
+
+ """
+ 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
+
+ def add_converter(
+ self,
+ type_name,
+ set_converter_func,
+ get_converter_func,
+ ):
+
+ """
+ To add custom data converters to handle new values.
+ RULE: Each of the converter functions must take in exactly on argument.
+ :param type_name: The name of the type of the object to handle. HINT: type(obj).__name__.
+ :param set_converter_func: A converter function that converts from the custom datatype to a datatype that Redis
+ can work with. Try converting to an bool, int, float, str, list or dict.
+ :param get_converter_func: The inverse of the set converter. This function will be used to convert from a
+ datatype that Redis can work with to the custom datatype.
+ :return: None.
+ """
+
+ self.__set_converters[type_name] = lambda x: set_converter_func(x)
+ self.__get_converters[type_name] = lambda x: get_converter_func(x)
+
+ async def connect(self):
+
+ """
+ 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):
+
+ """
+ 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):
+
+ """
+ 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 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
new file mode 100644
index 0000000..0192dae
--- /dev/null
+++ b/utils_v2/cache/async_redis_cache_v2.py
@@ -0,0 +1,568 @@
+"""
+
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/database/__pycache__/__init__.cpython-310.pyc b/utils_v2/database/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000..e6bb512
Binary files /dev/null and b/utils_v2/database/__pycache__/__init__.cpython-310.pyc differ
diff --git a/utils_v2/database/__pycache__/async_mongo_v2.cpython-310.pyc b/utils_v2/database/__pycache__/async_mongo_v2.cpython-310.pyc
new file mode 100644
index 0000000..7128ae7
Binary files /dev/null and b/utils_v2/database/__pycache__/async_mongo_v2.cpython-310.pyc differ
diff --git a/utils_v2/database/__pycache__/async_mysql_v2.cpython-310.pyc b/utils_v2/database/__pycache__/async_mysql_v2.cpython-310.pyc
new file mode 100644
index 0000000..91e1714
Binary files /dev/null and b/utils_v2/database/__pycache__/async_mysql_v2.cpython-310.pyc differ
diff --git a/utils_v2/database/async_firebase.py b/utils_v2/database/async_firebase.py
new file mode 100644
index 0000000..a8065a1
--- /dev/null
+++ b/utils_v2/database/async_firebase.py
@@ -0,0 +1,504 @@
+"""
+
+ AUTHOR:
+
+ Khushal P Soonderji
+ Bhushan Thakkar
+
+ DATE:
+
+ Friday, 19th April, 2024
+
+ OBJECTIVE:
+
+ To provide an easy interface to work with Firebase.
+
+ REFERENCES:
+
+ N/A
+
+ DOWNLOADS:
+
+ N/A
+
+"""
+
+# *****************************************************************************************************************
+# ***** ****
+# *** IMPORT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# To make sibling directories accessible for imports:
+# ---
+import sys
+sys.path.append(".")
+sys.path.append("..")
+
+# For async operations:
+# ---
+import asyncio
+
+# For system-level activities:
+# ---
+import os
+
+# My async utils:
+# ---
+import async_json_utils
+
+# Firebase:
+# ---
+import firebase_admin
+import firebase_admin.firestore_async
+import firebase_admin.auth
+import firebase_admin.db
+
+# For debugging and logging:
+# ---
+from icecream import IceCreamDebugger
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** MACROS / ONE-TIME INIT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** VARIABLES ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** FUNCTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+class AsyncFirebase:
+
+ def __init__(
+ self,
+ credentials_json_path,
+ app_name,
+ max_connections = 5,
+ debug = True
+ ):
+
+ # Debugging print:
+ # ---
+ self.__printer = IceCreamDebugger(prefix = f"FBase ({app_name[:8]}) | ", includeContext = True)
+ if not debug: self.__printer.disable()
+ alert = f"Firebase session starting with max. {max_connections} connections."
+ self.__printer(alert)
+
+ # Initialize the instance:
+ # ---
+ self.__semaphore = asyncio.Semaphore(max_connections)
+ credentials = firebase_admin.credentials.Certificate(credentials_json_path)
+ self.__firebase_app = firebase_admin.initialize_app(credentials, name = app_name)
+ self.__firestore = firebase_admin.firestore_async.client(self.__firebase_app)
+
+ def __del__(self):
+ firebase_admin.delete_app(self.__firebase_app)
+ self.__firestore.close()
+ alert = "Firebase session ended."
+ self.__printer(alert)
+
+ def __user_to_json(self, firebase_user):
+
+ user_json = {
+ "uid": firebase_user.uid,
+ "email": firebase_user.email,
+ "emailVerified": firebase_user.email_verified,
+ "displayName": firebase_user.display_name,
+ "phoneNo": firebase_user.phone_number,
+ "photoUrl": firebase_user.photo_url,
+ "customClaims": firebase_user.custom_claims,
+ "disabled": firebase_user.disabled,
+ "providerId": firebase_user.provider_id,
+ "providerData": firebase_user.provider_data,
+ "tenantId": firebase_user.tenant_id
+ }
+
+ return user_json
+
+ async def create_custom_token(self, uid):
+
+ async with self.__semaphore:
+
+ try:
+ custom_token = firebase_admin.auth.create_custom_token(
+ uid = uid,
+ app = self.__firebase_app
+ ).decode("utf-8")
+ return custom_token
+
+ except Exception as exception:
+ self.__printer(exception)
+ return None
+
+ async def authenticate_token(self, token):
+
+ """
+ To authenticate the given session token.
+ :param token: The session token generated by Firebase on a successful sign-in.
+ :return: Either the retrieved user information or a blank dictionary.
+ """
+
+ try:
+ user_info = firebase_admin.auth.verify_id_token(token, app = self.__firebase_app)
+ return user_info
+ except Exception as exception:
+ self.__printer(exception)
+ return {}
+
+ async def create_user(
+ self,
+ uid,
+ display_name = None,
+ password = None,
+ email = None,
+ phone_number = None
+ ):
+
+ """
+ Create a new user.
+ :param uid: The id to identify the user by.
+ :return: True or False based on the success of the operation.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ firebase_admin.auth.create_user(
+ uid = uid,
+ app = self.__firebase_app
+ )
+ return True
+
+ except firebase_admin.auth.UidAlreadyExistsError as excp:
+ return True
+
+ except Exception as exception:
+ self.__printer(exception)
+ return False
+
+ async def delete_user(self, uid):
+
+ async with self.__semaphore:
+
+ try:
+ firebase_admin.auth.delete_user(
+ uid = uid,
+ app = self.__firebase_app
+ )
+ return True
+
+ except firebase_admin.auth.UserNotFoundError as excp:
+ return True
+
+ except Exception as exception:
+ self.__printer(exception)
+ return False
+
+ async def get_user(self, uid):
+
+ async with self.__semaphore:
+
+ try:
+ user = firebase_admin.auth.get_user(
+ uid = uid,
+ app = self.__firebase_app
+ )
+ return self.__user_to_json(user)
+
+ except Exception as exception:
+ self.__printer(exception)
+ return None
+
+ async def list_users(self, users_per_page, page_token = None):
+
+ """
+ To get a list of users. Firebase has a limit of 1000 per call of this API. So we use page-tokens to fetch next
+ pages of users.
+ :param users_per_page: How many users you want to list in this API call (Max. 1,000).
+ :param page_token: To be used in case of pagination.
+ :return: The list of users and the page token to be used for the next call. Will be None in case of failure.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ users = firebase_admin.auth.list_users(
+ page_token = page_token,
+ max_results = min(users_per_page, 1000),
+ app = self.__firebase_app
+ )
+ next_page_token = users.next_page_token if users.has_next_page else None
+ users = users.users
+ users_json = [self.__user_to_json(user) for user in users]
+ return users_json, next_page_token
+
+ except Exception as exception:
+ self.__printer(exception)
+ return None, None
+
+ async def create_document(self, collection_path, document_name, document_data = None):
+
+ """
+ To create a new document with the specified data in an existing collection.
+ :param collection_path: The path of the collection (can be a sub-collection).
+ :param document_name: The name of the document you want to create.
+ :param document_data: The data that you want to populate in the document.
+ :return: True or False based on the success of the operation.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshot = await self.__firestore.collection(
+ collection_path
+ ).add(
+ document_id = document_name,
+ document_data = document_data or {}
+ )
+ return True
+
+ except Exception as exception:
+ self.__printer(exception)
+ return False
+
+ async def delete_document(self, path):
+
+ """
+ To delete a document.
+ :param path: The path of the document.
+ :return: True or False based on the success of the operation.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshot = await self.__firestore.document(path).delete()
+ return True
+
+ except Exception as excp:
+ print("FIRESTORE DOCUMENT DELETION EXCEPTION:", excp)
+ return False
+
+ async def set_document(self, path, data):
+
+ """
+ To overwrite the data in a document.
+ :param path: The path of the document.
+ :param data: The data you want to update as a dictionary.
+ :return: True or False based on the success of the operation.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshot = await self.__firestore.document(path).set(data)
+ return True
+
+ except Exception as exception:
+ self.__printer(exception)
+ return False
+
+ async def update_document(self, path, data):
+
+ """
+ To update the data in a document. Provide only the fields that you want to update.
+ :param path: The path of the document.
+ :param data: The data you want to update as a dictionary.
+ :return: True or False based on the success of the operation.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshot = await self.__firestore.document(path).update(data)
+ return True
+
+ except Exception as exception:
+ self.__printer(exception)
+ return False
+
+ async def get_document(self, path):
+
+ """
+ To get the data in a document.
+ :param path: The path of the document.
+ :return: The dictionary of data as found in the path specified or None if the operation failed.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshot = await self.__firestore.document(path).get()
+ return snapshot.to_dict()
+
+ except Exception as exception:
+ self.__printer(exception)
+ return None
+
+ async def get_document_fields(self, path, fields):
+
+ """
+ To get only specific fields (keys) in a document. Like how projections are used in Mongo.
+ :param path: The path of the document.
+ :param fields: The list of fields (keys) of the document that you want.
+ :return: The dictionary of data as found in the path specified.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ if type(fields) is not list: fields = [fields]
+ snapshot = await self.__firestore.document(path).get(fields)
+ return snapshot.to_dict()
+
+ except Exception as exception:
+ self.__printer(exception)
+ return None
+
+ async def create_collection(self, collection_name, document_name, document_data):
+
+ """
+ Creates a new collection in the root of the database. Note that Firebase doesn't allow creating new empty
+ collections, so we must add one first document in it.
+ :param collection_name: The name of the collection you want to create.
+ :param document_name: The name of the first document you want to put in the collection.
+ :param document_data: The data that you want to put in the first document of the new collection.
+ :return: True or False based on the success of the operation.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshot = await self.__firestore.collection(
+ collection_name
+ ).add(
+ document_id = document_name,
+ document_data = document_data
+ )
+ return True
+
+ except Exception as exception:
+ self.__printer(exception)
+ return False
+
+ async def create_sub_collection(
+ self,
+ document_path,
+ sub_collection_name,
+ sub_document_name = None,
+ sub_document_data = None
+ ):
+
+ """
+ Firebase allows you to create collections inside documents. This method is built for that. Note that Firebase
+ doesn't allow creating new empty collections, so we must add one first document in it.
+ :param document_path: The path of the document in which you want to create a new collection.
+ :param sub_collection_name: The name of the collection you want to create.
+ :param sub_document_name: The name of the first document you want to put in the collection.
+ :param sub_document_data: The data that you want to put in the first document of the new collection.
+ :return: True or False based on the success of the operation.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshot = await self.__firestore.document(
+ document_path
+ ).collection(
+ sub_collection_name
+ ).add(
+ document_id = sub_document_name,
+ document_data = sub_document_data or {}
+ )
+ return True
+
+ except Exception as exception:
+ self.__printer(exception)
+ return False
+
+ async def get_collection(self, path):
+
+ """
+ Get a whole collection's data.
+ :param path: The path of the collection.
+ :return: The collection.
+ """
+
+ async with self.__semaphore:
+
+ try:
+ snapshots = await self.__firestore.collection(path).get()
+ return {snapshot.id: snapshot.to_dict() for snapshot in snapshots}
+
+ except Exception as exception:
+ self.__printer(exception)
+ return None
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** MAIN PROGRAM ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+if __name__ == "__main__":
+
+ import time
+ from shared import constants
+
+ user_data = {
+ "firebaseUid": None,
+ "roles": "ClientAdmin",
+ "sessionToken": "siddhesh_20240419"
+ }
+
+ async def test():
+ my_firebase = AsyncFirebase(
+ f"{constants.PROJECT_DIRECTORY}/utils/cred/firebase_certs.json",
+ "myFire",
+ max_connections = 5
+ )
+ print("\n\n---\n\n")
+ results = await my_firebase.get_document("testCollection/testDoc")
+ print(async_json_utils.to_json_string(results))
+ print("\n\n---\n\n")
+ results = await my_firebase.get_document_fields("testCollection/testDoc", ["sampleMap"])
+ print(async_json_utils.to_json_string(results))
+ # await my_firebase.create_sub_collection(
+ # "myDeepCollection/deepDocId",
+ # "subCollection3",
+ # "subDoc",
+ # {"sub_key": "sub_val"}
+ # )
+ # await my_firebase.create_collection(
+ # "rootCollection",
+ # "subDoc",
+ # {"sub_key": "sub_val"}
+ # )
+ # await my_firebase.delete_document("activeSessions/9d402f1502dfd55a4326fa7fc8e6cb7d")
+ # print(async_json_utils.to_json_string(await my_firebase.get_collection("myDeepCollection")))
+
+ start_time = time.time()
+ asyncio.run(test())
+ print(f"FINISHED IN {time.time() - start_time} SECONDS.")
diff --git a/utils_v2/database/async_mongo.py b/utils_v2/database/async_mongo.py
new file mode 100644
index 0000000..c052fac
--- /dev/null
+++ b/utils_v2/database/async_mongo.py
@@ -0,0 +1,843 @@
+"""
+
+ 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 async behaviour:
+import asyncio
+
+# For datetime handling:
+import pytz
+import datetime
+
+# MongoDB:
+from motor.motor_asyncio import AsyncIOMotorClient
+from bson.objectid import ObjectId
+from bson.json_util import dumps, loads
+
+# For debugging:
+from icecream import IceCreamDebugger
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** MACROS / ONE-TIME INIT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** VARIABLES ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** EXCEPTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+class MongoFindException(Exception):
+
+ def __init__(self, hint = None, origin = None):
+ self.__hint = hint
+ self.__origin = origin
+
+ def __str__(self):
+ message = "mongo find 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 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
new file mode 100644
index 0000000..94df2d8
--- /dev/null
+++ b/utils_v2/database/async_mongo_storage.py
@@ -0,0 +1,358 @@
+"""
+
+ 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
new file mode 100644
index 0000000..6af5329
--- /dev/null
+++ b/utils_v2/database/async_mongo_v2.py
@@ -0,0 +1,1736 @@
+"""
+
+ 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: The no of operations done.
+ """
+
+ # 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
new file mode 100644
index 0000000..6a1996f
--- /dev/null
+++ b/utils_v2/database/async_mysql_v2.py
@@ -0,0 +1,434 @@
+"""
+
+ 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: str,
+ procedure_args: tuple,
+ commit: bool = True
+ ):
+
+ """
+ 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.
+ :param commit: Whether, or not, you would like to commit the execution.
+ :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)
+ if commit: await connection.commit()
+
+ # # 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,
+ commit: bool = True,
+ 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 commit: Whether, or not, you would like to commit the execution.
+ :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,
+ commit = commit
+ )
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/dataframe/splitter.py b/utils_v2/dataframe/splitter.py
new file mode 100644
index 0000000..7725905
--- /dev/null
+++ b/utils_v2/dataframe/splitter.py
@@ -0,0 +1,118 @@
+"""
+
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/date_time/date_time.py b/utils_v2/date_time/date_time.py
new file mode 100644
index 0000000..98cf01e
--- /dev/null
+++ b/utils_v2/date_time/date_time.py
@@ -0,0 +1,349 @@
+"""
+
+ 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
+
+# For mathematical operations:
+import math
+
+# 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, Literal
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** 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",
+ "%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: dto = datetime_object.astimezone(timezone)
+ else: dto = datetime_object.astimezone(timezone)
+ return dto
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+def round_date_time(
+ datetime_object: datetime,
+ rounding_seconds: int,
+ mode: Literal["floor", "ceil", "nearest"] = "nearest"
+) -> 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 rounding_seconds: The period of rounding in seconds. 60 for 1 minute, 300 for 5 minutes and so on.
+ :param mode: "floor" means the previous time bucket, "ceil" means the next time bucket, and "nearest" means
+ whichever is closer will be picked.
+ :return: The rounded date-time (with the original timezone).
+ """
+
+ def round_by_mode() -> float | int:
+ if mode == "nearest": return round(int(total_seconds) / rounding_seconds) * rounding_seconds
+ if mode == "ceil": return math.ceil(int(total_seconds) / rounding_seconds) * rounding_seconds
+ if mode == "floor": return math.floor(int(total_seconds) / rounding_seconds) * rounding_seconds
+
+ # For timezone-naive cases:
+ if datetime_object.tzinfo is None:
+ total_seconds = datetime_object.timestamp()
+ rounded_seconds = round_by_mode()
+ 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_by_mode()
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/goog/controllers/__init__.py b/utils_v2/goog/controllers/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/goog/controllers/base.py b/utils_v2/goog/controllers/base.py
new file mode 100644
index 0000000..d5f51b4
--- /dev/null
+++ b/utils_v2/goog/controllers/base.py
@@ -0,0 +1,475 @@
+"""
+
+ 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.api_call import GoogleApiResponse
+from utils_v2.goog.models.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,
+ 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 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
+
+ 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
+
+ # ┏┓ •
+ # ┃┃┏┓┏┓┏┓┏┓┏┓╋┓┏┓┏
+ # ┣┛┛ ┗┛┣┛┗ ┛ ┗┗┗ ┛
+ # ┛
+
+ @property
+ def client_id(self):
+ return self._client_id
+
+ @property
+ def client_secret(self):
+ return self._client_secret
+
+ # ┏┓┏┓ ┓ ┏┓ ┏┓
+ # ┃┃┣┫┓┏╋┣┓ ┏┛ ┃┫
+ # ┗┛┛┗┗┻┗┛┗ ┗━•┗┛
+
+ async def get_authorization_url(
+ self,
+ scopes: List[str],
+ state: str = None,
+ access_type: Literal["online", "offline"] = "offline",
+ approval_prompt: Literal["auto", "force", "consent"] = "auto",
+ 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 scopes: The set of permission you want the user to give.
+ :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:
+ """
+
+ # Create a flow:
+ flow = InstalledAppFlow.from_client_config(
+ self._oauth_json,
+ scopes = scopes,
+ redirect_uri = self._redirect_url
+ )
+
+ # Get an authorization URL:
+ auth_url, state = 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,
+ scopes: List[str],
+ 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 scopes: The set of permissions the user granted.
+ :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.
+ """
+
+ # Create a flow:
+ flow = InstalledAppFlow.from_client_config(
+ self._oauth_json,
+ scopes = scopes,
+ redirect_uri = self._redirect_url
+ )
+
+ # Get the credentials:
+ credentials = flow.fetch_token(authorization_response = redirect_url)
+ ttl = credentials["expires_in"] - 60
+ return GoogleAuthTokens(
+ accessToken = credentials["access_token"],
+ refreshToken = credentials["refresh_token"],
+ expiresAt = date_time.get_current_utc_date_time() + datetime.timedelta(seconds = ttl),
+ scopes = credentials["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/controllers/gmail/__init__.py b/utils_v2/goog/controllers/gmail/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/goog/controllers/gmail/gmail_client.py b/utils_v2/goog/controllers/gmail/gmail_client.py
new file mode 100644
index 0000000..be458ed
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/gmail_client.py
@@ -0,0 +1,962 @@
+"""
+
+ AUTHOR:
+
+ Khushal P Soonderji
+
+ DATE:
+
+ Monday, 25th Nov., 2024
+
+ OBJECTIVE:
+
+ To manage e-mails in a GMail account.
+
+ REFERENCES:
+
+ 1. GMail Quickstart: https://developers.google.com/gmail/api/quickstart/python
+ 2. GMail Labels: https://developers.google.com/gmail/api/guides/labels
+ 3. GMail Messages: https://developers.google.com/gmail/api/reference/rest/v1/users.messages
+ 4. People Profile: https://developers.google.com/people/api/rest/v1/people/get
+
+ 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.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.controllers.base import AsyncGoogleBase
+from utils_v2.goog.models.auth_tokens import GoogleAuthTokens
+from utils_v2.goog.models.api_call import GoogleApiResponse
+from utils_v2.goog.controllers.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",
+ # r"profile",
+ r"https://www.googleapis.com/auth/userinfo.profile"
+]
+SCOPES_GMAIL_FULL = [
+ r"https://mail.google.com/",
+ # r"profile",
+ r"https://www.googleapis.com/auth/userinfo.profile"
+]
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** 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
+ 2. https://developers.google.com/people/api/rest/v1/people/get
+ 3. https://developers.google.com/people/api/rest/v1/people#Person
+ :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 GMail API call:
+ if not self._debug_only_errors: self._printer("Getting User Profile.")
+ gmail_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 gmail_api_response.httpCode in [200]:
+ gmail_api_response.success = True
+ gmail_api_response.data = await gmail_api_response.get_json()
+ gmail_api_response.data["displayName"] = None
+ gmail_api_response.data["displayPictureUrl"] = None
+
+ # Make the People API call:
+ if not self._debug_only_errors: self._printer("Getting User Profile.")
+ people_api_response = await self.get(
+ url = f"https://people.googleapis.com/v1/people/me?personFields=names,photos,birthdays,phoneNumbers,genders,emailAddresses,addresses",
+ headers = {"Authorization": f"Bearer {tokens.accessToken}"}
+ )
+
+ # If the call was successful:
+ if people_api_response.httpCode in [200]:
+ people_api_response.success = True
+ people_api_response.data = await people_api_response.get_json()
+ for item in people_api_response.data.get("names", []):
+ if item["metadata"]["primary"]:
+ gmail_api_response.data["displayName"] = item.get("displayName")
+ for item in people_api_response.data.get("photos", []):
+ if item["metadata"]["primary"]:
+ gmail_api_response.data["displayPictureUrl"] = item.get("url")
+
+ # Done here:
+ return gmail_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["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,
+ max_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 max_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": max_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, max_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["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,
+ max_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 max_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(max_count / max_per_call))
+ last_iteration_count = max_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 = max_count
+
+ # Retrieve the messages for this page:
+ iteration_response = await self.__list_messages_on_page(
+ tokens = tokens,
+ max_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)
+
+ 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",
+ debug = True,
+ debug_prefix = "GMail (M) | ",
+ debug_only_errors = False
+ )
+
+ # Request Auth:
+ print("AUTH URL:", await my_gmail.get_authorization_url(
+ scopes = SCOPES_GMAIL_MAIL_MANAGEMENT,
+ state = "Bhopli",
+ approval_prompt = "force"
+ ))
+
+ # Get tokens from callback:
+ test_tokens = await my_gmail.get_authorization_tokens(
+ scopes = SCOPES_GMAIL_MAIL_MANAGEMENT,
+ redirect_url = input("Paste the redirect URL here: ")
+ )
+ print("TOKENS:", test_tokens)
+
+ # Test some feature:
+ response = await my_gmail.get_user_profile(tokens = test_tokens)
+ 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/controllers/gmail/gmail_message.py b/utils_v2/goog/controllers/gmail/gmail_message.py
new file mode 100644
index 0000000..d6ea111
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/gmail_message.py
@@ -0,0 +1,336 @@
+"""
+
+ 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 | List[str],
+ subject: str,
+ cc_emails: str | List[str] = None,
+ bcc_emails: str | 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"] = ",".join(to_email if isinstance(to_email, list) else [to_email])
+ self.message["Subject"] = subject
+ if cc_emails: self.message["CC"] = ",".join(cc_emails if isinstance(cc_emails, list) else [cc_emails])
+ if bcc_emails: self.message["BCC"] = ",".join(bcc_emails if isinstance(bcc_emails, list) else [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 = False))
diff --git a/utils_v2/goog/controllers/gmail/json/messages/chatgpt_suggested_message_format.json b/utils_v2/goog/controllers/gmail/json/messages/chatgpt_suggested_message_format.json
new file mode 100644
index 0000000..21bef48
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/chatgpt_suggested_message_format.json
@@ -0,0 +1,69 @@
+{
+ "_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/controllers/gmail/json/messages/formatted_message_list_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/formatted_message_list_20241126.json
new file mode 100644
index 0000000..5e50380
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/formatted_message_list_20241126.json
@@ -0,0 +1,36 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_01_193669615aa33694_no_attachment_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_01_193669615aa33694_no_attachment_20241126.json
new file mode 100644
index 0000000..3d9008e
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_01_193669615aa33694_no_attachment_20241126.json
@@ -0,0 +1,148 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_02_19367930033154ca_with_attachment_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_02_19367930033154ca_with_attachment_20241126.json
new file mode 100644
index 0000000..a9a6834
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_02_19367930033154ca_with_attachment_20241126.json
@@ -0,0 +1,258 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_03_19365d0239aa1aaf_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_03_19365d0239aa1aaf_20241126.json
new file mode 100644
index 0000000..1697bdc
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_03_19365d0239aa1aaf_20241126.json
@@ -0,0 +1,175 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_04_193640e74d93dc9b_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_04_193640e74d93dc9b_20241126.json
new file mode 100644
index 0000000..aaefb58
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_04_193640e74d93dc9b_20241126.json
@@ -0,0 +1,179 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_05_19363d6a7f50225a_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_05_19363d6a7f50225a_20241126.json
new file mode 100644
index 0000000..a73143e
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_05_19363d6a7f50225a_20241126.json
@@ -0,0 +1,183 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_06_19363ba8e2582133_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_06_19363ba8e2582133_20241126.json
new file mode 100644
index 0000000..540a154
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_06_19363ba8e2582133_20241126.json
@@ -0,0 +1,183 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_07_19362f9983e58ea6_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_07_19362f9983e58ea6_20241126.json
new file mode 100644
index 0000000..5786592
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_07_19362f9983e58ea6_20241126.json
@@ -0,0 +1,210 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_08_19360aabcb976cfc_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_08_19360aabcb976cfc_20241126.json
new file mode 100644
index 0000000..3d27db3
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_08_19360aabcb976cfc_20241126.json
@@ -0,0 +1,175 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_09_193604ad97c9fe62_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_09_193604ad97c9fe62_20241126.json
new file mode 100644
index 0000000..6c7dde9
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_09_193604ad97c9fe62_20241126.json
@@ -0,0 +1,183 @@
+{
+ "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/controllers/gmail/json/messages/raw_message_10_1935e92672e67f22_20241126.json b/utils_v2/goog/controllers/gmail/json/messages/raw_message_10_1935e92672e67f22_20241126.json
new file mode 100644
index 0000000..4adaa68
--- /dev/null
+++ b/utils_v2/goog/controllers/gmail/json/messages/raw_message_10_1935e92672e67f22_20241126.json
@@ -0,0 +1,183 @@
+{
+ "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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/goog/models/api_call.py b/utils_v2/goog/models/api_call.py
new file mode 100644
index 0000000..4064079
--- /dev/null
+++ b/utils_v2/goog/models/api_call.py
@@ -0,0 +1,132 @@
+"""
+
+ 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 = "*GOOGLE 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/auth_tokens.py b/utils_v2/goog/models/auth_tokens.py
new file mode 100644
index 0000000..6dc568b
--- /dev/null
+++ b/utils_v2/goog/models/auth_tokens.py
@@ -0,0 +1,243 @@
+"""
+
+ 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
+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
+
+# To make API calls:
+import httpx
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** 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)
+ displayName: str | None = Field(description = "the display name of the user", default = None)
+ displayPictureUrl: str | None = Field(description = "the url to the display picture of the user", default = None)
+
+ # ┏┓ ┏•
+ # ┃ ┏┓┏┓╋┓┏┓
+ # ┗┛┗┛┛┗┛┗┗┫
+ # ┛
+
+ class Config:
+ extra = "allow"
+
+ # ┓┏ ┓• ┓ •
+ # ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓
+ # ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗
+
+ @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 client_user_id(self):
+ return {"email": self.email}
+
+ @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 app (OAuth JSON) for which these tokens were granted.
+ :param client_secret: The secret of the client app (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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/image/scanner/__init__.py b/utils_v2/image/scanner/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/image/scanner/scanner.py b/utils_v2/image/scanner/scanner.py
new file mode 100644
index 0000000..28fe69b
--- /dev/null
+++ b/utils_v2/image/scanner/scanner.py
@@ -0,0 +1,410 @@
+"""
+
+ 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
new file mode 100644
index 0000000..fc63627
--- /dev/null
+++ b/utils_v2/image/scanner/scanner_v2.py
@@ -0,0 +1,379 @@
+"""
+
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/logging/__pycache__/__init__.cpython-310.pyc b/utils_v2/logging/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000..f14ac0a
Binary files /dev/null and b/utils_v2/logging/__pycache__/__init__.cpython-310.pyc differ
diff --git a/utils_v2/logging/__pycache__/model.cpython-310.pyc b/utils_v2/logging/__pycache__/model.cpython-310.pyc
new file mode 100644
index 0000000..1ebab57
Binary files /dev/null and b/utils_v2/logging/__pycache__/model.cpython-310.pyc differ
diff --git a/utils_v2/logging/context.py b/utils_v2/logging/context.py
new file mode 100644
index 0000000..d7ead43
--- /dev/null
+++ b/utils_v2/logging/context.py
@@ -0,0 +1,468 @@
+"""
+
+ AUTHOR:
+
+ Khushal P Soonderji
+
+ DATE:
+
+ Friday, 2nd Aug., 2024
+
+ OBJECTIVE:
+
+ To provide an easy way to log all system activities by way of managing the context of what is going on.
+
+ REFERENCES:
+
+ N/A
+
+ DOWNLOADS:
+
+ N/A
+
+ NOTES:
+
+ N/A
+
+"""
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** IMPORT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# To manage context:
+import contextvars
+from contextlib import contextmanager, asynccontextmanager
+
+# To make decorators:
+from functools import wraps
+
+# For system-level activities:
+import os
+
+# My utils:
+from utils_v2.string import json
+from utils_v2.date_time import date_time
+from utils_v2.security import sanitizers
+from utils_v2.api.codes import StatusCodes, HttpCodes
+from utils_v2.api.log import APILogModel
+from utils_v2.api.response import ResponseModel
+
+# The needed data models:
+from utils_v2.logging.model import GeneralLogModel
+
+# To work with date and time:
+import time
+
+# For random strings:
+import random
+
+# For debugging:
+import traceback
+import string
+
+# To work with datatypes:
+from types import NoneType
+import pandas as pd
+
+# To work with Pydantic objects:
+from pydantic import BaseModel
+
+# For asynchronous activities:
+import asyncio
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** MACROS / ONE-TIME INIT ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# Chars to choose from for random strings:
+ALPHANUMERIC_CHARS = string.ascii_letters + string.digits
+
+# To capture system information:
+PROCESS_ID = os.getppid()
+PARENT_PROCESS_ID = os.getppid()
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** VARIABLES ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** FUNCTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** EXCEPTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+# --- Nothing Yet
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** FUNCTIONS ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+def describe_exception(exc):
+
+ """
+ Describes the exception in detail. It extracts the type of exception, a brief message, and even the entire
+ traceback. Useful for debugging in details without the terminal. You could either log the resultant dict or send it
+ to the dev team over some service like WhatsApp/Telegram.
+ :param exc: The exception that occurred.
+ :return: The dict that explains the exception.
+ """
+
+ exc_desc = {
+ "type": type(exc).__name__,
+ "msg": str(exc),
+ "tb": [str(exc_tb) for exc_tb in traceback.format_exception(exc, value = exc, tb = exc.__traceback__)]
+ }
+
+ return exc_desc
+
+
+# *****************************************************************************************************************
+# ***** ****
+# *** Classes ***
+# ***** ****
+# *****************************************************************************************************************
+
+
+class AsyncMongoLogger:
+
+ def __init__(self, db_conn, collection = "logs"):
+
+ """
+ This class uses an instance of 'AsyncMongo' and makes it usable as a logger.
+ :param db_conn: The instance of 'AsyncMongo' to use.
+ :param collection: The collection to write the log into.
+ """
+
+ self.__db_conn = db_conn
+ self.__collection = collection
+
+ async def log(self, log_json):
+
+ """
+ Log something to the database using the connection provided when the object was made.
+ :param log_json: The dict to log.
+ :return: True if logged successfully, else False.
+ """
+
+ asyncio.create_task(self.__db_conn.insert_one(
+ collection = self.__collection,
+ document = log_json,
+ raise_exception = False
+ ))
+
+
+# ---------------------------------------------------------------------------------------------------------------------
+
+
+class AsyncLoggerContext:
+
+ # Create the context-aware variable(s):
+ logger = contextvars.ContextVar("logger", default = None)
+ log_chain = contextvars.ContextVar("log_chain", default = None)
+
+ @classmethod
+ @asynccontextmanager
+ async def logging_context(cls, logger, log_chain = None):
+
+ """
+ This function makes the context manager that makes the value of the log chain available to everything that is
+ called within the scope of the context.
+ :param logger: The object which is to be used to write the log. It should have a 'log' method which should take
+ in a dict as its input.
+ :param log_chain: The value of the log chain to be made available within the scope.
+ :return: None.
+ """
+
+ # Set the context:
+ token_logger = cls.logger.set(logger)
+ token_log_chain = cls.log_chain.set(log_chain)
+
+ # Make the objects available within the context:
+ try: yield
+
+ # Release the objects when the context is over:
+ finally:
+ cls.logger.reset(token_logger)
+ cls.log_chain.reset(token_log_chain)
+
+ @staticmethod
+ def generate_log_id(count = 8):
+ return "".join(random.choice(ALPHANUMERIC_CHARS) for _ in range(min(8, count)))
+
+ @classmethod
+ def get_logger(cls):
+ return cls.logger.get()
+
+ @classmethod
+ def get_log_chain(cls):
+ return cls.log_chain.get()
+
+ @staticmethod
+ def summarize(
+ value,
+ str_limit = 100,
+ expand: bool | int = False,
+ sensitive_keys: list[str] = None
+ ):
+
+ """
+ To summarize an input value to capture the essence without hoarding to much data.
+ :param value: Anything that you want to summarize.
+ :param str_limit: The max. no. of chars of a string to retain.
+ :param expand: Set to True for full expansion, False for no expansion, and an integer for a specific level of
+ expansion. Applicable on iterables and dicts. The smaller this number, the more concise the summary will be,
+ and vice versa.
+ :param sensitive_keys: The list of keys (of a dict) to obscure when summarizing.
+ :return: The summarized version of the input.
+ """
+
+ # If the input is a Pydantic class:
+ if isinstance(value, BaseModel): value = value.model_dump()
+
+ # Check the sensitive keys:
+ if sensitive_keys is None: sensitive_keys = []
+
+ # Handle datatypes that you don't want to modify:
+ if isinstance(value, (int, float, bool, NoneType)): pass
+
+ # When the value is a list or similar iterable:
+ elif isinstance(value, (list, tuple, set)):
+ if expand:
+ if not isinstance(expand, bool): expand -= 1
+ value = [AsyncLoggerContext.summarize(
+ v,
+ expand = expand,
+ sensitive_keys = sensitive_keys
+ ) for v in value]
+ else: value = f"array of {len(value)} item(s)"
+
+ # If the value is a dict:
+ elif isinstance(value, dict):
+ if expand:
+ if not isinstance(expand, bool): expand -= 1
+ value = {
+ k: AsyncLoggerContext.summarize(
+ v,
+ expand = expand,
+ sensitive_keys = sensitive_keys
+ ) if k not in sensitive_keys else "********"
+ for k, v in value.items()
+ }
+ else: value = f"object of {len(value.keys())} field(s) [{', '.join(value.keys())}]"
+
+ # When a dataframe is passed:
+ elif isinstance(value, pd.DataFrame):
+ cols = value.columns.to_list()
+ value = f"table with {len(cols)} col(s) [{', '.join(cols)}] and {len(value)} row(s)"
+ str_limit = 999
+
+ # If the input is some form of non-standard object:
+ else: value = str(value)
+
+ # Handle strings:
+ if isinstance(value, str):
+ if len(value) > 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
new file mode 100644
index 0000000..355d07e
--- /dev/null
+++ b/utils_v2/logging/model.py
@@ -0,0 +1,131 @@
+"""
+
+ 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
new file mode 100644
index 0000000..e69de29
diff --git a/utils_v2/mail/async_smpt.py b/utils_v2/mail/async_smpt.py
new file mode 100644
index 0000000..0e8ed06
--- /dev/null
+++ b/utils_v2/mail/async_smpt.py
@@ -0,0 +1,443 @@
+"""
+
+ 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.