From 62b1d118f85564d70b00616a8c2a9a936d3235ee Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 15 Aug 2022 20:18:57 -0400 Subject: [PATCH 01/61] using requests to download soft files --- geofetch/geofetch.py | 57 +++++++++++++++++++++++--------------------- geofetch/utils.py | 32 +++++++++++++++++-------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 82244d3..c5ca7d5 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -16,7 +16,7 @@ # import tarfile import time -from .utils import ( +from utils import ( Accession, parse_accessions, parse_SOFT_line, @@ -24,7 +24,7 @@ clean_soft_files, run_subprocess, ) -from ._version import __version__ +from _version import __version__ import logmuse from ubiquerg import expandpath, is_command_callable @@ -277,24 +277,26 @@ def fetch_all(self, input, name=None): # The GSM file has metadata describing each sample, which we will use to # produce a sample annotation sheet. if not os.path.isfile(file_gse) or self.refresh_metadata: - Accession(acc_GSE).fetch_metadata(file_gse) + file_gse_content = Accession(acc_GSE).fetch_metadata(file_gse, clean=self.discard_soft) else: self._LOGGER.info(f"Found previous GSE file: {file_gse}") + gse_file_obj = open(file_gse, "r") + file_gse_content = gse_file_obj.read().split('\n') if not os.path.isfile(file_gsm) or self.refresh_metadata: - Accession(acc_GSE).fetch_metadata(file_gsm, typename="GSM") + file_gsm_content = Accession(acc_GSE).fetch_metadata(file_gsm, typename="GSM", clean=self.discard_soft) else: self._LOGGER.info(f"Found previous GSM file: {file_gsm}") - - # if not os.path.isfile(file_gsm) or not os.path.isfile(file_gse): + gsm_file_obj = open(file_gsm, "r") + file_gsm_content = gsm_file_obj.read().split('\n') # download processed data if self.processed: - try: + #try: ( meta_processed_samples, meta_processed_series, - ) = self.get_list_of_processed_files(file_gse, file_gsm) + ) = self.get_list_of_processed_files(file_gse_content, file_gsm_content) # taking into account list of GSM that is specified in the input file gsm_list = acc_GSE_list[acc_GSE] @@ -307,6 +309,7 @@ def fetch_all(self, input, name=None): ) meta_processed_series = self.unify_list_keys(meta_processed_series) + # samples list_of_keys = self.get_list_of_keys(meta_processed_samples) self._LOGGER.info("Expanding metadata list...") for key_in_list in list_of_keys: @@ -314,6 +317,7 @@ def fetch_all(self, input, name=None): meta_processed_samples, key_in_list ) + # series list_of_keys_series = self.get_list_of_keys(meta_processed_series) self._LOGGER.info("Expanding metadata list...") for key_in_list in list_of_keys_series: @@ -409,17 +413,17 @@ def fetch_all(self, input, name=None): ] for file_url in processed_series_files: self.download_processed_file(file_url, data_geo_folder) - except Exception as processed_exception: - failed_runs.append(acc_GSE) - self._LOGGER.warning(f"Error occurred: {processed_exception}") + # except Exception as processed_exception: + # failed_runs.append(acc_GSE) + # self._LOGGER.warning(f"Error occurred: {processed_exception}") else: # download gsm metadata - gsm_metadata = self.get_gsm_metadata(acc_GSE, acc_GSE_list, file_gsm) + gsm_metadata = self.get_gsm_metadata(acc_GSE, acc_GSE_list, file_gsm_content) metadata_dict[acc_GSE] = gsm_metadata # download gsm metadata - SRP_list_result = self.get_SRA_meta(file_gse, gsm_metadata, file_sra) + SRP_list_result = self.get_SRA_meta(file_gse_content, gsm_metadata, file_sra) if not SRP_list_result: # delete current acc if no raw data was found # del metadata_dict[acc_GSE] @@ -1345,18 +1349,18 @@ def download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): else: self._LOGGER.info(f"\033[38;5;242mFile {full_filepath} exists.\033[0m") - def get_list_of_processed_files(self, file_gse, file_gsm): + def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: list): """ Given a paths to GSE and GSM metafile create a list of dicts of metadata of processed files - :param str file_gse: the path to gse metafile - :param str file_gsm: the path to gse metafile + :param list file_gse_content: list of lines of gse metafile + :param list file_gsm_content: list of lines of gse metafile :return list: list of metadata of processed files """ tar_re = re.compile(r".*\.tar$") gse_numb = None meta_processed_samples = [] meta_processed_series = {"GSE": "", "files": []} - for line in open(file_gse, "r"): + for line in file_gse_content: if re.compile(r"!Series_geo_accession").search(line): gse_numb = self.get_value(line) @@ -1373,7 +1377,7 @@ def get_list_of_processed_files(self, file_gse, file_gsm): if tar_re.search(filename): # find and download filelist - file with information about files in tar index = file_url.rfind("/") - tar_files_list_url = file_url[: index + 1] + "filelist.txt" + tar_files_list_url = "https" + file_url[3 : index + 1] + "filelist.txt" # file_list_name filelist_path = os.path.join( self.metadata_expanded, gse_numb + "_file_list.txt" @@ -1385,7 +1389,7 @@ def get_list_of_processed_files(self, file_gse, file_gsm): ) nb = len(meta_processed_samples) - 1 - for line_gsm in open(file_gsm, "r"): + for line_gsm in file_gsm_content: if line_gsm[0] == "^": nb = len(self.check_file_existance(meta_processed_samples)) meta_processed_samples.append( @@ -1589,7 +1593,7 @@ def run_size_filter(self, meta_list, col_name="file_size"): return filtered_list @staticmethod - def read_tar_filelist(file_path): + def read_tar_filelist(file_path: str): """ Creating list for supplementary files that are listed in "filelist.txt" :param str file_path: path to the file with information about files that are zipped ("filelist.txt") @@ -1621,7 +1625,6 @@ def get_value(all_line): return line_value.split(": ")[-1].rstrip("\n") def download_processed_file(self, file_url, data_folder): - """ Given a url for a file, download it, and extract anything passing the filter. :param str file_url: the URL of the file to download @@ -1664,16 +1667,16 @@ def download_processed_file(self, file_url, data_folder): if ntry > 4: raise e - def get_SRA_meta(self, file_gse, gsm_metadata, file_sra=None): + def get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): """ Parse out the SRA project identifier from the GSE file - :param str file_gse: full path to GSE.soft metafile + :param list file_gse_content: list of content of file_sde_content :param dict gsm_metadata: dict of GSM metadata :param str file_sra: full path to SRA.csv metafile that has to be downloaded """ # acc_SRP = None - for line in open(file_gse, "r"): + for line in file_gse_content: found = re.findall(PROJECT_PATTERN, line) if found: acc_SRP = found[0] @@ -1780,13 +1783,13 @@ def get_SRP_list(self, srp_number: str) -> list: return SRP_list - def get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm): + def get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): """ A simple state machine to parse SOFT formatted files (Here, the GSM file) :param str acc_GSE: GSE number (Series accession) :param dict acc_GSE_list: list of GSE - :param str file_gsm: full path to GSM.soft metafile + :param list file_gsm_content: list of contents of gsm file :return dict: dictionary of experiment information (gsm_metadata) """ gsm_metadata = {} @@ -1798,7 +1801,7 @@ def get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm): current_sample_id = None current_sample_srx = False samples_list = [] - for line in open(file_gsm, "r"): + for line in file_gsm_content: line = line.rstrip() if len(line) == 0: # Apparently SOFT files can contain blank lines continue diff --git a/geofetch/utils.py b/geofetch/utils.py index 7835196..8c95da4 100644 --- a/geofetch/utils.py +++ b/geofetch/utils.py @@ -5,6 +5,7 @@ import subprocess import sys import re +import requests __author__ = [ @@ -181,18 +182,17 @@ def __init__(self, accn, strict=True): self.accn = accn self.typename = typename.upper() - def fetch_metadata(self, outpath=None, typename=None): + def fetch_metadata(self, outpath: str = None, typename: str = None, clean: bool = False) -> list: """ Fetch the metadata associated with this accession. - :param str outpath: path to file to which to write output, optional :param str typename: type indicating URL format, use type parsed at construction if unspecified + :param str outpath: path to file to which to write output, optional + :param bool clean: if true, files won't be saved + :return: list of lines in soft file """ - # TODO: note this sort of type-dependent strategy suggests subclassing. - # For now, class is small, but that should maybe be done if it grows. - typename = (typename or self.typename).upper() if not is_known_type(typename=typename): raise self.accn_type_exception(self.accn, typename) @@ -210,7 +210,16 @@ def fetch_metadata(self, outpath=None, typename=None): raise _LOGGER.debug("Fetching: '%s'", full_url) - if outpath: + result = requests.get(full_url) + if result.ok: + result_text = result.text + result_list = result_text.replace("\r", "").split("\n") + result_list = [elem for elem in result_list if len(elem) > 0] + + else: + raise Exception(f"Error in requesting fileL: {full_url}") + + if outpath and not clean: # Ensure we have filepath and that needed directories exist. if not os.path.splitext(outpath)[1]: _LOGGER.debug("Looks like folder, not file: %s", outpath) @@ -222,11 +231,12 @@ def fetch_metadata(self, outpath=None, typename=None): if not os.path.exists(dirpath): _LOGGER.debug("Forging path to '%s'", dirpath) os.makedirs(dirpath) - cmd = "wget -O {} {}".format(outpath, full_url) - else: - cmd = "wget {}".format(full_url) - run_subprocess(cmd.split(" ")) + # save file: + with open(outpath, 'w') as f: + f.write(result_text) + + return result_list @staticmethod def _validate(accn): @@ -335,3 +345,5 @@ def run_subprocess(*args, **kwargs): except OSError as ose: _LOGGER.warn(f"Exception raised during subprocess termination: {ose}") sys.exit(1) + +#file_gse_content \ No newline at end of file From 51ee83a7c8f2b4fd02ea32d4127a5d9d64a0e905 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 16 Aug 2022 00:21:27 -0400 Subject: [PATCH 02/61] added requests for additional files --- geofetch/geofetch.py | 58 ++++++++++++++++++++++++++------------------ geofetch/utils.py | 4 +-- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index c5ca7d5..31afe51 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -28,6 +28,7 @@ import logmuse from ubiquerg import expandpath, is_command_callable +from io import StringIO _STRING_TYPES = str _LOGGER = None @@ -282,6 +283,7 @@ def fetch_all(self, input, name=None): self._LOGGER.info(f"Found previous GSE file: {file_gse}") gse_file_obj = open(file_gse, "r") file_gse_content = gse_file_obj.read().split('\n') + file_gse_content = [elem for elem in file_gse_content if len(elem) > 0] if not os.path.isfile(file_gsm) or self.refresh_metadata: file_gsm_content = Accession(acc_GSE).fetch_metadata(file_gsm, typename="GSM", clean=self.discard_soft) @@ -289,6 +291,7 @@ def fetch_all(self, input, name=None): self._LOGGER.info(f"Found previous GSM file: {file_gsm}") gsm_file_obj = open(file_gsm, "r") file_gsm_content = gsm_file_obj.read().split('\n') + file_gsm_content = [elem for elem in file_gsm_content if len(elem) > 0] # download processed data if self.processed: @@ -1377,16 +1380,24 @@ def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: if tar_re.search(filename): # find and download filelist - file with information about files in tar index = file_url.rfind("/") - tar_files_list_url = "https" + file_url[3 : index + 1] + "filelist.txt" + tar_files_list_url = "https" + file_url[3: index + 1] + "filelist.txt" # file_list_name filelist_path = os.path.join( self.metadata_expanded, gse_numb + "_file_list.txt" ) - self.download_file( - tar_files_list_url, - self.metadata_expanded, - gse_numb + "_file_list.txt", - ) + + if not os.path.isfile(filelist_path) or self.refresh_metadata: + result = requests.get(tar_files_list_url) + if result.ok: + filelist_raw_text = result.text + if not self.discard_soft: + with open(filelist_path, 'w') as f: + f.write(filelist_raw_text) + else: + self._LOGGER.info(f"Found previous GSM file: {filelist_path}") + filelist_obj = open(filelist_path, "r") + filelist_raw_text = filelist_obj.read() + nb = len(meta_processed_samples) - 1 for line_gsm in file_gsm_content: @@ -1449,7 +1460,7 @@ def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: ) # expand meta_processed_samples with information about type and size - file_info_add = self.read_tar_filelist(filelist_path) + file_info_add = self.read_tar_filelist(filelist_raw_text) for index_nr in range(len(meta_processed_samples)): file_name = meta_processed_samples[index_nr]["file"] meta_processed_samples[index_nr].update( @@ -1593,29 +1604,28 @@ def run_size_filter(self, meta_list, col_name="file_size"): return filtered_list @staticmethod - def read_tar_filelist(file_path: str): + def read_tar_filelist(raw_text: str): """ Creating list for supplementary files that are listed in "filelist.txt" :param str file_path: path to the file with information about files that are zipped ("filelist.txt") :return dict: dict of supplementary file names and additional information """ - + f = StringIO(raw_text) files_info = {} - with open(file_path, newline="") as csvfile: - csv_reader = csv.reader(csvfile, delimiter="\t") - line_count = 0 - for row in csv_reader: - if line_count == 0: - name_index = row.index("Name") - size_index = row.index("Size") - type_index = row.index("Type") - - line_count += 1 - else: - files_info[row[name_index]] = { - "file_size": row[size_index], - "type": row[type_index], - } + csv_reader = csv.reader(f, delimiter="\t") + line_count = 0 + for row in csv_reader: + if line_count == 0: + name_index = row.index("Name") + size_index = row.index("Size") + type_index = row.index("Type") + + line_count += 1 + else: + files_info[row[name_index]] = { + "file_size": row[size_index], + "type": row[type_index], + } return files_info diff --git a/geofetch/utils.py b/geofetch/utils.py index 8c95da4..270123f 100644 --- a/geofetch/utils.py +++ b/geofetch/utils.py @@ -233,8 +233,8 @@ def fetch_metadata(self, outpath: str = None, typename: str = None, clean: bool os.makedirs(dirpath) # save file: - with open(outpath, 'w') as f: - f.write(result_text) + with open(outpath, 'w') as f: + f.write(result_text) return result_list From 533d3a2746bc8496a33ed6aa27e6c04c6474da6e Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 16 Aug 2022 10:38:19 -0400 Subject: [PATCH 03/61] Refactored const --- geofetch/const.py | 40 ++++++++++++++++++++++++++++++ geofetch/geofetch.py | 58 ++++++++------------------------------------ geofetch/utils.py | 14 +---------- 3 files changed, 51 insertions(+), 61 deletions(-) create mode 100644 geofetch/const.py diff --git a/geofetch/const.py b/geofetch/const.py new file mode 100644 index 0000000..6c0f1cf --- /dev/null +++ b/geofetch/const.py @@ -0,0 +1,40 @@ +import re +_LOGGER = None + +# A set of hard-coded keys if you want to limit to just a few instead of taking +# all information provided in GEO. Use with `--use-key-subset` +ANNOTATION_SHEET_KEYS = [ + "sample_name", + "protocol", + "read_type", + "organism", + "data_source", + "Sample_title", + "Sample_source_name_ch1", + "Sample_organism_ch1", + "Sample_library_selection", + "Sample_library_strategy", + "Sample_type", + "SRR", + "SRX", + "Sample_geo_accession", + "Sample_series_id", + "Sample_instrument_model", +] + +# Regex to parse out SRA accession identifiers +PROJECT_PATTERN = re.compile(r"(SRP\d{4,8})") +EXPERIMENT_PATTERN = re.compile(r"(SRX\d{4,8})") +GSE_PATTERN = re.compile(r"(GSE\d{4,8})") +SUPP_FILE_PATTERN = re.compile("Sample_supplementary_file") +SER_SUPP_FILE_PATTERN = re.compile("Series_supplementary_file") + +SAMPLE_SUPP_METADATA_FILE = "_samples.csv" +EXP_SUPP_METADATA_FILE = "_series.csv" + +# How many times should we retry failing prefetch call? +NUM_RETRIES = 3 +REQUEST_SLEEP = 0.4 + +NCBI_ESEARCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=sra&term={SRP_NUMBER}&retmax=999&rettype=uilist&retmode=json" +NCBI_EFETCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=sra&id={ID}&rettype=runinfo&retmode=xml" \ No newline at end of file diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 31afe51..ef52647 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -2,7 +2,6 @@ __author__ = ["Oleksandr Khoroshevskyi", "Vince Reuter", "Nathan Sheffield"] - import argparse import copy import csv @@ -16,6 +15,8 @@ # import tarfile import time +from _version import __version__ +from const import * from utils import ( Accession, parse_accessions, @@ -24,54 +25,11 @@ clean_soft_files, run_subprocess, ) -from _version import __version__ -import logmuse +import logmuse from ubiquerg import expandpath, is_command_callable from io import StringIO -_STRING_TYPES = str -_LOGGER = None - -# A set of hard-coded keys if you want to limit to just a few instead of taking -# all information provided in GEO. Use with `--use-key-subset` -ANNOTATION_SHEET_KEYS = [ - "sample_name", - "protocol", - "read_type", - "organism", - "data_source", - "Sample_title", - "Sample_source_name_ch1", - "Sample_organism_ch1", - "Sample_library_selection", - "Sample_library_strategy", - "Sample_type", - "SRR", - "SRX", - "Sample_geo_accession", - "Sample_series_id", - "Sample_instrument_model", -] - -# Regex to parse out SRA accession identifiers -PROJECT_PATTERN = re.compile(r"(SRP\d{4,8})") -EXPERIMENT_PATTERN = re.compile(r"(SRX\d{4,8})") -GSE_PATTERN = re.compile(r"(GSE\d{4,8})") -SUPP_FILE_PATTERN = re.compile("Sample_supplementary_file") -SER_SUPP_FILE_PATTERN = re.compile("Series_supplementary_file") - -SAMPLE_SUPP_METADATA_FILE = "_samples.csv" -EXP_SUPP_METADATA_FILE = "_series.csv" - -# How many times should we retry failing prefetch call? -NUM_RETRIES = 3 -REQUEST_SLEEP = 0.4 - -NCBI_ESEARCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=sra&term={SRP_NUMBER}&retmax=999&rettype=uilist&retmode=json" -NCBI_EFETCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=sra&id={ID}&rettype=runinfo&retmode=xml" - - class Geofetcher: def __init__( self, @@ -485,7 +443,7 @@ def fetch_all(self, input, name=None): ) if ( - isinstance(gsm_metadata[experiment]["SRR"], _STRING_TYPES) + isinstance(gsm_metadata[experiment]["SRR"], str) and experiment not in gsm_multi_table ): # Only one has been stuck in so far, make a list @@ -806,14 +764,16 @@ def write_gsm_annotation(self, gsm_metadata, file_annotation, use_key_subset=Fal # keys = gsm_metadata[gsm_metadata.keys().next()].keys() keys = list(list(gsm_metadata.values())[0].keys()) - self._LOGGER.info(f"Sample annotation sheet: {file_annotation}") + self._LOGGER.info(f"Sample annotation sheet: {file_annotation} . Saving....") fp = expandpath(file_annotation) - self._LOGGER.info(f"Writing: {fp}") with open(fp, "w") as of: w = csv.DictWriter(of, keys, extrasaction="ignore") w.writeheader() for item in gsm_metadata: w.writerow(gsm_metadata[item]) + self._LOGGER.info( + "\033[92mFile has been saved successfully\033[0m" + ) return fp def write_processed_annotation(self, processed_metadata, file_annotation_path): @@ -1393,6 +1353,8 @@ def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: if not self.discard_soft: with open(filelist_path, 'w') as f: f.write(filelist_raw_text) + else: + raise Exception(f"error in requesting tar_files_list") else: self._LOGGER.info(f"Found previous GSM file: {filelist_path}") filelist_obj = open(filelist_path, "r") diff --git a/geofetch/utils.py b/geofetch/utils.py index 270123f..efbc7ff 100644 --- a/geofetch/utils.py +++ b/geofetch/utils.py @@ -7,20 +7,8 @@ import re import requests - -__author__ = [ - "Oleksandr Khoroshevskyi", - "Vince Reuter", - "Nathan Sheffield", -] -__email__ = "bnt4me@virginia.edu" - -__all__ = ["parse_accessions"] - - _LOGGER = logging.getLogger(__name__) - # This dict provides NCBI lookup URLs for different accession types. SRX # identifiers can be used to grab metadata from SRA for a single sample, just as # an SRP identifier is used to grab the same table for multiple samples, so @@ -343,7 +331,7 @@ def run_subprocess(*args, **kwargs): p.terminate() print("Pipeline aborted.") except OSError as ose: - _LOGGER.warn(f"Exception raised during subprocess termination: {ose}") + _LOGGER.warning(f"Exception raised during subprocess termination: {ose}") sys.exit(1) #file_gse_content \ No newline at end of file From 69fc8ea909f13e9851d2e3c11ba10934491e5755 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 16 Aug 2022 12:39:15 -0400 Subject: [PATCH 04/61] #81 first stage - done --- geofetch/geofetch.py | 135 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 20 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index ef52647..535e2c3 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +from __future__ import annotations + __author__ = ["Oleksandr Khoroshevskyi", "Vince Reuter", "Nathan Sheffield"] import argparse @@ -29,6 +31,8 @@ import logmuse from ubiquerg import expandpath, is_command_callable from io import StringIO +from typing import List, Union, Dict +import peppy class Geofetcher: def __init__( @@ -173,7 +177,82 @@ def __init__( if bam_conversion and not just_metadata and not self.which("samtools"): raise SystemExit("For SAM/BAM processing, samtools should be on PATH.") - def fetch_all(self, input, name=None): + def get_project_obj(self, input: str) -> Dict[peppy.Project]: + """ + Function for fetching projects from GEO|SRA and obtaining peppy project + :param input: GSE number, or path to file of GSE numbers + :return: peppy project or list of project, if acc_anno is set. + """ + acc_GSE_list = parse_accessions( + input, self.metadata_expanded, self.just_metadata + ) + + raw_project_dict = {} + + if self.processed: + if self.supp_by == "all": + data_source_all = True + else: + data_source_all = False + + import pandas as pd + + if self.acc_anno: + self.acc_anno = False + for acc_GSE in acc_GSE_list.keys(): + if data_source_all: + # samples + self.supp_by = "samples" + samples_list = self.fetch_all(input=acc_GSE, just_object=True) + if len(samples_list) > 0: + raw_project_dict[acc_GSE + "_samples"] = pd.DataFrame(samples_list) + + # series + self.supp_by = "series" + series_list = self.fetch_all(input=acc_GSE, just_object=True) + if len(series_list) > 0: + raw_project_dict[acc_GSE + "_series"] = pd.DataFrame(series_list) + else: + ser_list = self.fetch_all(input=acc_GSE, just_object=True) + if len(ser_list) > 0: + raw_project_dict[acc_GSE+"_"+self.supp_by] = pd.DataFrame(ser_list) + else: + if data_source_all: + # samples + self.supp_by = "samples" + samples_list = self.fetch_all(input=input, just_object=True) + if len(samples_list) > 0: + raw_project_dict["project_samples"] = pd.DataFrame(samples_list) + + # series + self.supp_by = "series" + series_list = self.fetch_all(input=input, just_object=True) + if len(series_list) > 0: + raw_project_dict["project_series"] = pd.DataFrame(series_list) + + else: + ser_list = self.fetch_all(input=input, just_object=True) + if len(ser_list) > 0: + raw_project_dict["project_" + self.supp_by] = pd.DataFrame(ser_list) + print(raw_project_dict) + + else: + if self.acc_anno: + self.acc_anno = False + for acc_GSE in acc_GSE_list.keys(): + project_dict = self.fetch_all(input=input, just_object=True) + if len(project_dict) > 0: + raw_project_dict[acc_GSE+"_raw_samples"] = project_dict + + else: + ser_dict = self.fetch_all(input=input, just_object=True) + if len(ser_dict) > 0: + raw_project_dict["raw_samples"] = ser_dict + + + return peppy.Project() + + def fetch_all(self, input: str, name: str = None, just_object: bool = False): """Main script driver/workflow""" if name: @@ -578,28 +657,44 @@ def fetch_all(self, input, name=None): ) elif self.supp_by == "samples": - supp_sample_path_meta = os.path.join( - self.metadata_raw, - "PEP_samples", - self.project_name + SAMPLE_SUPP_METADATA_FILE, - ) - self.write_processed_annotation( - processed_metadata_samples, supp_sample_path_meta - ) + if just_object: + return processed_metadata_samples + else: + supp_sample_path_meta = os.path.join( + self.metadata_raw, + "PEP_samples", + self.project_name + SAMPLE_SUPP_METADATA_FILE, + ) + self.write_processed_annotation( + processed_metadata_samples, supp_sample_path_meta + ) elif self.supp_by == "series": - supp_series_path_meta = os.path.join( - self.metadata_raw, - "PEP_series", - self.project_name + EXP_SUPP_METADATA_FILE, - ) - self.write_processed_annotation( - processed_metadata_exp, supp_series_path_meta - ) + if just_object: + return processed_metadata_exp + else: + supp_series_path_meta = os.path.join( + self.metadata_raw, + "PEP_series", + self.project_name + EXP_SUPP_METADATA_FILE, + ) + self.write_processed_annotation( + processed_metadata_exp, supp_series_path_meta + ) # saving PEPs for raw data else: - self.write_raw_annotation(metadata_dict, subannotation_dict) + if not just_object: + self.write_raw_annotation(metadata_dict, subannotation_dict) + else: + raw_meta_list = [] + for meta_key in metadata_dict.keys(): + for srx_key in metadata_dict[meta_key].keys(): + metadata_dict[meta_key][srx_key]["gse_number"] = meta_key + metadata_dict[meta_key][srx_key]["srx_number"] = srx_key + raw_meta_list.append(metadata_dict[meta_key][srx_key]) + # TODO: add subannotation_dict!!!! + return raw_meta_list def expand_metadata_list(self, metadata_list, dict_key): """ @@ -869,7 +964,7 @@ def write_raw_annotation(self, metadata_dict, subannotation_dict): Combining individual accessions into project-level annotations, and writeing individual accession files (if requested) :param dict metadata_dict: dictionary of metadata - :param dict subannotation_dict: dictionary of sub-annotation metadata + :param dict sub-annotation_dict: dictionary of sub-annotation metadata """ if self.discard_soft: @@ -2109,7 +2204,7 @@ def main(): args = _parse_cmdl(sys.argv[1:]) args_dict = vars(args) args_dict["args"] = args - Geofetcher(**args_dict).fetch_all(args_dict["input"]) + Geofetcher(**args_dict).get_project_obj(args_dict["input"]) if __name__ == "__main__": From 7439526782880bdd6c9345672e847a513460ddc4 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 16 Aug 2022 15:43:02 -0400 Subject: [PATCH 05/61] to peppy(done) + requirements + black --- geofetch/_version.py | 2 +- geofetch/const.py | 3 +- geofetch/geofetch.py | 295 +++++++++++++++--------------- geofetch/utils.py | 9 +- requirements/requirements-all.txt | 2 + 5 files changed, 163 insertions(+), 148 deletions(-) diff --git a/geofetch/_version.py b/geofetch/_version.py index 1f4c4d4..ae6db5f 100644 --- a/geofetch/_version.py +++ b/geofetch/_version.py @@ -1 +1 @@ -__version__ = "0.10.1" +__version__ = "0.11.0" diff --git a/geofetch/const.py b/geofetch/const.py index 6c0f1cf..6bc0ff4 100644 --- a/geofetch/const.py +++ b/geofetch/const.py @@ -1,4 +1,5 @@ import re + _LOGGER = None # A set of hard-coded keys if you want to limit to just a few instead of taking @@ -37,4 +38,4 @@ REQUEST_SLEEP = 0.4 NCBI_ESEARCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=sra&term={SRP_NUMBER}&retmax=999&rettype=uilist&retmode=json" -NCBI_EFETCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=sra&id={ID}&rettype=runinfo&retmode=xml" \ No newline at end of file +NCBI_EFETCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=sra&id={ID}&rettype=runinfo&retmode=xml" diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 535e2c3..7b689f8 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -17,9 +17,9 @@ # import tarfile import time -from _version import __version__ -from const import * -from utils import ( +from ._version import __version__ +from .const import * +from .utils import ( Accession, parse_accessions, parse_SOFT_line, @@ -33,6 +33,8 @@ from io import StringIO from typing import List, Union, Dict import peppy +import pandas as pd + class Geofetcher: def __init__( @@ -183,6 +185,7 @@ def get_project_obj(self, input: str) -> Dict[peppy.Project]: :param input: GSE number, or path to file of GSE numbers :return: peppy project or list of project, if acc_anno is set. """ + self.just_metadata = True acc_GSE_list = parse_accessions( input, self.metadata_expanded, self.just_metadata ) @@ -195,8 +198,6 @@ def get_project_obj(self, input: str) -> Dict[peppy.Project]: else: data_source_all = False - import pandas as pd - if self.acc_anno: self.acc_anno = False for acc_GSE in acc_GSE_list.keys(): @@ -205,52 +206,57 @@ def get_project_obj(self, input: str) -> Dict[peppy.Project]: self.supp_by = "samples" samples_list = self.fetch_all(input=acc_GSE, just_object=True) if len(samples_list) > 0: - raw_project_dict[acc_GSE + "_samples"] = pd.DataFrame(samples_list) + raw_project_dict[acc_GSE + "_samples"] = samples_list # series self.supp_by = "series" series_list = self.fetch_all(input=acc_GSE, just_object=True) if len(series_list) > 0: - raw_project_dict[acc_GSE + "_series"] = pd.DataFrame(series_list) + raw_project_dict[acc_GSE + "_series"] = series_list else: ser_list = self.fetch_all(input=acc_GSE, just_object=True) if len(ser_list) > 0: - raw_project_dict[acc_GSE+"_"+self.supp_by] = pd.DataFrame(ser_list) + raw_project_dict[acc_GSE + "_" + self.supp_by] = ser_list else: if data_source_all: # samples self.supp_by = "samples" samples_list = self.fetch_all(input=input, just_object=True) if len(samples_list) > 0: - raw_project_dict["project_samples"] = pd.DataFrame(samples_list) + raw_project_dict["project_samples"] = samples_list # series self.supp_by = "series" series_list = self.fetch_all(input=input, just_object=True) if len(series_list) > 0: - raw_project_dict["project_series"] = pd.DataFrame(series_list) + raw_project_dict["project_series"] = series_list else: ser_list = self.fetch_all(input=input, just_object=True) if len(ser_list) > 0: - raw_project_dict["project_" + self.supp_by] = pd.DataFrame(ser_list) - print(raw_project_dict) + raw_project_dict["project_" + self.supp_by] = ser_list else: + # Not sure about below code... if self.acc_anno: self.acc_anno = False for acc_GSE in acc_GSE_list.keys(): project_dict = self.fetch_all(input=input, just_object=True) if len(project_dict) > 0: - raw_project_dict[acc_GSE+"_raw_samples"] = project_dict + raw_project_dict[acc_GSE + "_raw_samples"] = project_dict else: ser_dict = self.fetch_all(input=input, just_object=True) if len(ser_dict) > 0: raw_project_dict["raw_samples"] = ser_dict + new_dict = {} + for proj_key in raw_project_dict.keys(): + new_dict[proj_key] = peppy.Project( + pd_object=pd.DataFrame(raw_project_dict[proj_key]) + ) - return peppy.Project() + return new_dict def fetch_all(self, input: str, name: str = None, just_object: bool = False): """Main script driver/workflow""" @@ -315,155 +321,157 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): # The GSM file has metadata describing each sample, which we will use to # produce a sample annotation sheet. if not os.path.isfile(file_gse) or self.refresh_metadata: - file_gse_content = Accession(acc_GSE).fetch_metadata(file_gse, clean=self.discard_soft) + file_gse_content = Accession(acc_GSE).fetch_metadata( + file_gse, clean=self.discard_soft + ) else: self._LOGGER.info(f"Found previous GSE file: {file_gse}") gse_file_obj = open(file_gse, "r") - file_gse_content = gse_file_obj.read().split('\n') + file_gse_content = gse_file_obj.read().split("\n") file_gse_content = [elem for elem in file_gse_content if len(elem) > 0] if not os.path.isfile(file_gsm) or self.refresh_metadata: - file_gsm_content = Accession(acc_GSE).fetch_metadata(file_gsm, typename="GSM", clean=self.discard_soft) + file_gsm_content = Accession(acc_GSE).fetch_metadata( + file_gsm, typename="GSM", clean=self.discard_soft + ) else: self._LOGGER.info(f"Found previous GSM file: {file_gsm}") gsm_file_obj = open(file_gsm, "r") - file_gsm_content = gsm_file_obj.read().split('\n') - file_gsm_content = [elem for elem in file_gsm_content if len(elem) > 0] + file_gsm_content = gsm_file_obj.read().split("\n") + file_gsm_content = [elem for elem in file_gsm_content if len(elem) > 0] # download processed data if self.processed: - #try: - ( - meta_processed_samples, - meta_processed_series, - ) = self.get_list_of_processed_files(file_gse_content, file_gsm_content) - - # taking into account list of GSM that is specified in the input file - gsm_list = acc_GSE_list[acc_GSE] - meta_processed_samples = self.filter_gsm( - meta_processed_samples, gsm_list + # try: + ( + meta_processed_samples, + meta_processed_series, + ) = self.get_list_of_processed_files(file_gse_content, file_gsm_content) + + # taking into account list of GSM that is specified in the input file + gsm_list = acc_GSE_list[acc_GSE] + meta_processed_samples = self.filter_gsm( + meta_processed_samples, gsm_list + ) + # Unify keys: + meta_processed_samples = self.unify_list_keys(meta_processed_samples) + meta_processed_series = self.unify_list_keys(meta_processed_series) + + # samples + list_of_keys = self.get_list_of_keys(meta_processed_samples) + self._LOGGER.info("Expanding metadata list...") + for key_in_list in list_of_keys: + meta_processed_samples = self.expand_metadata_list( + meta_processed_samples, key_in_list ) - # Unify keys: - meta_processed_samples = self.unify_list_keys( - meta_processed_samples + + # series + list_of_keys_series = self.get_list_of_keys(meta_processed_series) + self._LOGGER.info("Expanding metadata list...") + for key_in_list in list_of_keys_series: + meta_processed_series = self.expand_metadata_list( + meta_processed_series, key_in_list ) - meta_processed_series = self.unify_list_keys(meta_processed_series) - # samples - list_of_keys = self.get_list_of_keys(meta_processed_samples) - self._LOGGER.info("Expanding metadata list...") - for key_in_list in list_of_keys: - meta_processed_samples = self.expand_metadata_list( - meta_processed_samples, key_in_list + # convert column names to lowercase and underscore + meta_processed_samples = self.standardize_colnames( + meta_processed_samples + ) + meta_processed_series = self.standardize_colnames(meta_processed_series) + + if not self.acc_anno: + # adding metadata from current experiment to the project + processed_metadata_samples.extend(meta_processed_samples) + processed_metadata_exp.extend(meta_processed_series) + + # save PEP for each accession if acc-anno flag is true + if self.acc_anno and len(acc_GSE_list.keys()) > 1: + if self.supp_by == "all": + # samples + pep_acc_path_sample = os.path.join( + self.metadata_raw, + f"{acc_GSE}_samples", + acc_GSE + SAMPLE_SUPP_METADATA_FILE, + ) + self.write_processed_annotation( + meta_processed_samples, pep_acc_path_sample ) - # series - list_of_keys_series = self.get_list_of_keys(meta_processed_series) - self._LOGGER.info("Expanding metadata list...") - for key_in_list in list_of_keys_series: - meta_processed_series = self.expand_metadata_list( - meta_processed_series, key_in_list + # series + pep_acc_path_exp = os.path.join( + self.metadata_raw, + f"{acc_GSE}_series", + acc_GSE + EXP_SUPP_METADATA_FILE, + ) + self.write_processed_annotation( + meta_processed_series, pep_acc_path_exp + ) + elif self.supp_by == "samples": + pep_acc_path_sample = os.path.join( + self.metadata_raw, + f"{acc_GSE}_samples", + acc_GSE + SAMPLE_SUPP_METADATA_FILE, + ) + self.write_processed_annotation( + meta_processed_samples, pep_acc_path_sample + ) + elif self.supp_by == "series": + pep_acc_path_exp = os.path.join( + self.metadata_raw, + f"{acc_GSE}_series", + acc_GSE + EXP_SUPP_METADATA_FILE, + ) + self.write_processed_annotation( + meta_processed_series, pep_acc_path_exp ) - # convert column names to lowercase and underscore - meta_processed_samples = self.standardize_colnames( - meta_processed_samples - ) - meta_processed_series = self.standardize_colnames( - meta_processed_series - ) + if not self.just_metadata: + data_geo_folder = os.path.join(self.geo_folder, acc_GSE) + self._LOGGER.debug("Data folder: " + data_geo_folder) - if not self.acc_anno: - # adding metadata from current experiment to the project - processed_metadata_samples.extend(meta_processed_samples) - processed_metadata_exp.extend(meta_processed_series) - - # save PEP for each accession if acc-anno flag is true - if self.acc_anno and len(acc_GSE_list.keys()) > 1: - if self.supp_by == "all": - # samples - pep_acc_path_sample = os.path.join( - self.metadata_raw, - f"{acc_GSE}_samples", - acc_GSE + SAMPLE_SUPP_METADATA_FILE, - ) - self.write_processed_annotation( - meta_processed_samples, pep_acc_path_sample - ) + if self.supp_by == "all": + processed_samples_files = [ + each_file["file_url"] + for each_file in meta_processed_samples + ] + for file_url in processed_samples_files: + self.download_processed_file(file_url, data_geo_folder) - # series - pep_acc_path_exp = os.path.join( - self.metadata_raw, - f"{acc_GSE}_series", - acc_GSE + EXP_SUPP_METADATA_FILE, - ) - self.write_processed_annotation( - meta_processed_series, pep_acc_path_exp - ) - elif self.supp_by == "samples": - pep_acc_path_sample = os.path.join( - self.metadata_raw, - f"{acc_GSE}_samples", - acc_GSE + SAMPLE_SUPP_METADATA_FILE, - ) - self.write_processed_annotation( - meta_processed_samples, pep_acc_path_sample - ) - elif self.supp_by == "series": - pep_acc_path_exp = os.path.join( - self.metadata_raw, - f"{acc_GSE}_series", - acc_GSE + EXP_SUPP_METADATA_FILE, - ) - self.write_processed_annotation( - meta_processed_series, pep_acc_path_exp - ) + processed_series_files = [ + each_file["file_url"] for each_file in meta_processed_series + ] + for file_url in processed_series_files: + self.download_processed_file(file_url, data_geo_folder) - if not self.just_metadata: - data_geo_folder = os.path.join(self.geo_folder, acc_GSE) - self._LOGGER.debug("Data folder: " + data_geo_folder) - - if self.supp_by == "all": - processed_samples_files = [ - each_file["file_url"] - for each_file in meta_processed_samples - ] - for file_url in processed_samples_files: - self.download_processed_file(file_url, data_geo_folder) - - processed_series_files = [ - each_file["file_url"] - for each_file in meta_processed_series - ] - for file_url in processed_series_files: - self.download_processed_file(file_url, data_geo_folder) - - elif self.supp_by == "samples": - processed_samples_files = [ - each_file["file_url"] - for each_file in meta_processed_samples - ] - for file_url in processed_samples_files: - self.download_processed_file(file_url, data_geo_folder) - - elif self.supp_by == "series": - processed_series_files = [ - each_file["file_url"] - for each_file in meta_processed_series - ] - for file_url in processed_series_files: - self.download_processed_file(file_url, data_geo_folder) - # except Exception as processed_exception: - # failed_runs.append(acc_GSE) - # self._LOGGER.warning(f"Error occurred: {processed_exception}") + elif self.supp_by == "samples": + processed_samples_files = [ + each_file["file_url"] + for each_file in meta_processed_samples + ] + for file_url in processed_samples_files: + self.download_processed_file(file_url, data_geo_folder) + + elif self.supp_by == "series": + processed_series_files = [ + each_file["file_url"] for each_file in meta_processed_series + ] + for file_url in processed_series_files: + self.download_processed_file(file_url, data_geo_folder) + # except Exception as processed_exception: + # failed_runs.append(acc_GSE) + # self._LOGGER.warning(f"Error occurred: {processed_exception}") else: # download gsm metadata - gsm_metadata = self.get_gsm_metadata(acc_GSE, acc_GSE_list, file_gsm_content) + gsm_metadata = self.get_gsm_metadata( + acc_GSE, acc_GSE_list, file_gsm_content + ) metadata_dict[acc_GSE] = gsm_metadata # download gsm metadata - SRP_list_result = self.get_SRA_meta(file_gse_content, gsm_metadata, file_sra) + SRP_list_result = self.get_SRA_meta( + file_gse_content, gsm_metadata, file_sra + ) if not SRP_list_result: # delete current acc if no raw data was found # del metadata_dict[acc_GSE] @@ -866,9 +874,7 @@ def write_gsm_annotation(self, gsm_metadata, file_annotation, use_key_subset=Fal w.writeheader() for item in gsm_metadata: w.writerow(gsm_metadata[item]) - self._LOGGER.info( - "\033[92mFile has been saved successfully\033[0m" - ) + self._LOGGER.info("\033[92mFile has been saved successfully\033[0m") return fp def write_processed_annotation(self, processed_metadata, file_annotation_path): @@ -1407,7 +1413,9 @@ def download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): else: self._LOGGER.info(f"\033[38;5;242mFile {full_filepath} exists.\033[0m") - def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: list): + def get_list_of_processed_files( + self, file_gse_content: list, file_gsm_content: list + ): """ Given a paths to GSE and GSM metafile create a list of dicts of metadata of processed files :param list file_gse_content: list of lines of gse metafile @@ -1435,7 +1443,9 @@ def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: if tar_re.search(filename): # find and download filelist - file with information about files in tar index = file_url.rfind("/") - tar_files_list_url = "https" + file_url[3: index + 1] + "filelist.txt" + tar_files_list_url = ( + "https" + file_url[3 : index + 1] + "filelist.txt" + ) # file_list_name filelist_path = os.path.join( self.metadata_expanded, gse_numb + "_file_list.txt" @@ -1446,7 +1456,7 @@ def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: if result.ok: filelist_raw_text = result.text if not self.discard_soft: - with open(filelist_path, 'w') as f: + with open(filelist_path, "w") as f: f.write(filelist_raw_text) else: raise Exception(f"error in requesting tar_files_list") @@ -1455,7 +1465,6 @@ def get_list_of_processed_files(self, file_gse_content: list, file_gsm_content: filelist_obj = open(filelist_path, "r") filelist_raw_text = filelist_obj.read() - nb = len(meta_processed_samples) - 1 for line_gsm in file_gsm_content: if line_gsm[0] == "^": @@ -2204,7 +2213,7 @@ def main(): args = _parse_cmdl(sys.argv[1:]) args_dict = vars(args) args_dict["args"] = args - Geofetcher(**args_dict).get_project_obj(args_dict["input"]) + Geofetcher(**args_dict).fetch_all(args_dict["input"]) if __name__ == "__main__": diff --git a/geofetch/utils.py b/geofetch/utils.py index efbc7ff..f3f97ff 100644 --- a/geofetch/utils.py +++ b/geofetch/utils.py @@ -170,7 +170,9 @@ def __init__(self, accn, strict=True): self.accn = accn self.typename = typename.upper() - def fetch_metadata(self, outpath: str = None, typename: str = None, clean: bool = False) -> list: + def fetch_metadata( + self, outpath: str = None, typename: str = None, clean: bool = False + ) -> list: """ Fetch the metadata associated with this accession. @@ -221,7 +223,7 @@ def fetch_metadata(self, outpath: str = None, typename: str = None, clean: bool os.makedirs(dirpath) # save file: - with open(outpath, 'w') as f: + with open(outpath, "w") as f: f.write(result_text) return result_list @@ -334,4 +336,5 @@ def run_subprocess(*args, **kwargs): _LOGGER.warning(f"Exception raised during subprocess termination: {ose}") sys.exit(1) -#file_gse_content \ No newline at end of file + +# file_gse_content diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index a38f1f0..3853373 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -7,3 +7,5 @@ logmuse>=0.2.7 ubiquerg>=0.6.0 requests>=2.28.1 xmltodict>=0.13.0 +pandas>=1.4.3 +peppy @ git+https://github.com/pepkit/peppy.git@dev_pd_init#egg=peppy From 3c896a6fdffc15d43f512cae471d58db90e85a63 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 17 Aug 2022 15:43:42 -0400 Subject: [PATCH 06/61] Refactoring names of the methods in Geofetcher --- geofetch/geofetch.py | 310 +++++++++++++++++------------------------ tests/test_geofetch.py | 10 +- 2 files changed, 133 insertions(+), 187 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 7b689f8..291282a 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -37,40 +37,43 @@ class Geofetcher: + """ + Class to download or get projects, metadata, data from GEO and SRA + """ + def __init__( self, - name="", - metadata_root="", - metadata_folder="", - just_metadata=False, - refresh_metadata=False, - config_template=None, - pipeline_samples=None, - pipeline_project=None, + name: str = "", + metadata_root: str = "", + metadata_folder: str = "", + just_metadata: bool = False, + refresh_metadata: bool = False, + config_template: str = None, + pipeline_samples: str = None, + pipeline_project: str = None, skip=0, - acc_anno=False, - use_key_subset=False, - processed=True, - data_source="samples", - filter=None, - filter_size=None, - geo_folder=".", - split_experiments=False, - bam_folder="", - fq_folder="", - sra_folder="", + acc_anno: bool = False, + use_key_subset: bool = False, + processed: bool = True, + data_source: str = "samples", + filter: str = None, + filter_size: str = None, + geo_folder: str = ".", + split_experiments: bool = False, + bam_folder: str = "", + fq_folder: str = "", + sra_folder: str = "", bam_conversion=False, - picard_path="", - input=None, - const_limit_project=50, - const_limit_discard=250, - attr_limit_truncate=500, - discard_soft=False, - add_dotfile=False, + picard_path: str = "", + input: str = None, + const_limit_project: int = 50, + const_limit_discard: int = 250, + attr_limit_truncate: int = 500, + discard_soft: bool = False, + add_dotfile: bool = False, opts=None, **kwargs, ): - global _LOGGER if opts is not None: _LOGGER = logmuse.logger_via_cli(opts) @@ -176,7 +179,7 @@ def __init__( ) # Some sanity checks before proceeding - if bam_conversion and not just_metadata and not self.which("samtools"): + if bam_conversion and not just_metadata and not self._which("samtools"): raise SystemExit("For SAM/BAM processing, samtools should be on PATH.") def get_project_obj(self, input: str) -> Dict[peppy.Project]: @@ -346,38 +349,30 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): ( meta_processed_samples, meta_processed_series, - ) = self.get_list_of_processed_files(file_gse_content, file_gsm_content) + ) = self._get_list_of_processed_files(file_gse_content, file_gsm_content) # taking into account list of GSM that is specified in the input file gsm_list = acc_GSE_list[acc_GSE] - meta_processed_samples = self.filter_gsm( - meta_processed_samples, gsm_list - ) + meta_processed_samples = self._filter_gsm(meta_processed_samples, gsm_list) # Unify keys: - meta_processed_samples = self.unify_list_keys(meta_processed_samples) - meta_processed_series = self.unify_list_keys(meta_processed_series) + meta_processed_samples = self._unify_list_keys(meta_processed_samples) + meta_processed_series = self._unify_list_keys(meta_processed_series) # samples - list_of_keys = self.get_list_of_keys(meta_processed_samples) + list_of_keys = self._get_list_of_keys(meta_processed_samples) self._LOGGER.info("Expanding metadata list...") for key_in_list in list_of_keys: - meta_processed_samples = self.expand_metadata_list( - meta_processed_samples, key_in_list - ) + meta_processed_samples = self._expand_metadata_list(meta_processed_samples, key_in_list) # series - list_of_keys_series = self.get_list_of_keys(meta_processed_series) + list_of_keys_series = self._get_list_of_keys(meta_processed_series) self._LOGGER.info("Expanding metadata list...") for key_in_list in list_of_keys_series: - meta_processed_series = self.expand_metadata_list( - meta_processed_series, key_in_list - ) + meta_processed_series = self._expand_metadata_list(meta_processed_series, key_in_list) # convert column names to lowercase and underscore - meta_processed_samples = self.standardize_colnames( - meta_processed_samples - ) - meta_processed_series = self.standardize_colnames(meta_processed_series) + meta_processed_samples = self._standardize_colnames(meta_processed_samples) + meta_processed_series = self._standardize_colnames(meta_processed_series) if not self.acc_anno: # adding metadata from current experiment to the project @@ -393,9 +388,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): f"{acc_GSE}_samples", acc_GSE + SAMPLE_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - meta_processed_samples, pep_acc_path_sample - ) + self._write_processed_annotation(meta_processed_samples, pep_acc_path_sample) # series pep_acc_path_exp = os.path.join( @@ -403,27 +396,21 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): f"{acc_GSE}_series", acc_GSE + EXP_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - meta_processed_series, pep_acc_path_exp - ) + self._write_processed_annotation(meta_processed_series, pep_acc_path_exp) elif self.supp_by == "samples": pep_acc_path_sample = os.path.join( self.metadata_raw, f"{acc_GSE}_samples", acc_GSE + SAMPLE_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - meta_processed_samples, pep_acc_path_sample - ) + self._write_processed_annotation(meta_processed_samples, pep_acc_path_sample) elif self.supp_by == "series": pep_acc_path_exp = os.path.join( self.metadata_raw, f"{acc_GSE}_series", acc_GSE + EXP_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - meta_processed_series, pep_acc_path_exp - ) + self._write_processed_annotation(meta_processed_series, pep_acc_path_exp) if not self.just_metadata: data_geo_folder = os.path.join(self.geo_folder, acc_GSE) @@ -435,13 +422,13 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): for each_file in meta_processed_samples ] for file_url in processed_samples_files: - self.download_processed_file(file_url, data_geo_folder) + self._download_processed_file(file_url, data_geo_folder) processed_series_files = [ each_file["file_url"] for each_file in meta_processed_series ] for file_url in processed_series_files: - self.download_processed_file(file_url, data_geo_folder) + self._download_processed_file(file_url, data_geo_folder) elif self.supp_by == "samples": processed_samples_files = [ @@ -449,29 +436,25 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): for each_file in meta_processed_samples ] for file_url in processed_samples_files: - self.download_processed_file(file_url, data_geo_folder) + self._download_processed_file(file_url, data_geo_folder) elif self.supp_by == "series": processed_series_files = [ each_file["file_url"] for each_file in meta_processed_series ] for file_url in processed_series_files: - self.download_processed_file(file_url, data_geo_folder) + self._download_processed_file(file_url, data_geo_folder) # except Exception as processed_exception: # failed_runs.append(acc_GSE) # self._LOGGER.warning(f"Error occurred: {processed_exception}") else: # download gsm metadata - gsm_metadata = self.get_gsm_metadata( - acc_GSE, acc_GSE_list, file_gsm_content - ) + gsm_metadata = self._get_gsm_metadata(acc_GSE, acc_GSE_list, file_gsm_content) metadata_dict[acc_GSE] = gsm_metadata # download gsm metadata - SRP_list_result = self.get_SRA_meta( - file_gse_content, gsm_metadata, file_sra - ) + SRP_list_result = self._get_SRA_meta(file_gse_content, gsm_metadata, file_sra) if not SRP_list_result: # delete current acc if no raw data was found # del metadata_dict[acc_GSE] @@ -510,17 +493,13 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): ) if not sample_name or sample_name == "": temp = gsm_metadata[experiment]["Sample_title"] - sample_name = self.sanitize_name(temp) + sample_name = self._sanitize_name(temp) # Otherwise, record that there's SRA data for this run. # And set a few columns that are used as input to the Looper # print("Updating columns for looper") - self.update_columns( - gsm_metadata, - experiment, - sample_name=sample_name, - read_type=line["LibraryLayout"], - ) + self._update_columns(gsm_metadata, experiment, sample_name=sample_name, + read_type=line["LibraryLayout"]) # Some experiments are flagged in SRA as having multiple runs. if gsm_metadata[experiment].get("SRR") is not None: @@ -595,7 +574,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): else: if not self.just_metadata: try: - self.download_SRA_file(run_name) + self._download_SRA_file(run_name) except Exception as err: failed_runs.append(run_name) self._LOGGER.warning( @@ -607,7 +586,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): if self.bam_conversion and self.bam_folder != "": try: # converting sra to bam using - self.sra_bam_conversion(bam_file, run_name) + self._sra_bam_conversion(bam_file, run_name) # checking if bam_file converted correctly, if not --> use fastq-dump st = os.stat(bam_file) @@ -615,9 +594,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): self._LOGGER.warning( "Bam conversion failed with sam-dump. Trying fastq-dump..." ) - self.sra_bam_conversion2( - bam_file, run_name, self.picard_path - ) + self._sra_bam_conversion2(bam_file, run_name, self.picard_path) except FileNotFoundError as err: self._LOGGER.info( @@ -651,18 +628,14 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): "PEP_samples", self.project_name + SAMPLE_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - processed_metadata_samples, supp_sample_path_meta - ) + self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) supp_series_path_meta = os.path.join( self.metadata_raw, "PEP_series", self.project_name + EXP_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - processed_metadata_exp, supp_series_path_meta - ) + self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) elif self.supp_by == "samples": if just_object: @@ -673,9 +646,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): "PEP_samples", self.project_name + SAMPLE_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - processed_metadata_samples, supp_sample_path_meta - ) + self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) elif self.supp_by == "series": if just_object: @@ -686,14 +657,12 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): "PEP_series", self.project_name + EXP_SUPP_METADATA_FILE, ) - self.write_processed_annotation( - processed_metadata_exp, supp_series_path_meta - ) + self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) # saving PEPs for raw data else: if not just_object: - self.write_raw_annotation(metadata_dict, subannotation_dict) + self._write_raw_annotation(metadata_dict, subannotation_dict) else: raw_meta_list = [] for meta_key in metadata_dict.keys(): @@ -704,7 +673,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): # TODO: add subannotation_dict!!!! return raw_meta_list - def expand_metadata_list(self, metadata_list, dict_key): + def _expand_metadata_list(self, metadata_list, dict_key): """ Expanding list items in the list by creating new items or joining them @@ -776,7 +745,7 @@ def expand_metadata_list(self, metadata_list, dict_key): self._LOGGER.warning("Value Error: %s" % err1) return metadata_list - def filter_gsm(self, meta_processed_samples: list, gsm_list: dict) -> list: + def _filter_gsm(self, meta_processed_samples: list, gsm_list: dict) -> list: """ Getting metadata list of all samples of one experiment and filtering it by the list of GSM that was specified in the input files. @@ -801,7 +770,7 @@ def filter_gsm(self, meta_processed_samples: list, gsm_list: dict) -> list: return meta_processed_samples @staticmethod - def get_list_of_keys(list_of_dict): + def _get_list_of_keys(list_of_dict): """ Getting list of all keys that are in the dictionaries in the list @@ -815,7 +784,7 @@ def get_list_of_keys(list_of_dict): list_of_keys.extend(list(element.keys())) return list(set(list_of_keys)) - def unify_list_keys(self, processed_meta_list): + def _unify_list_keys(self, processed_meta_list): """ Unifying list of dicts with metadata, so every dict will have same keys @@ -824,18 +793,18 @@ def unify_list_keys(self, processed_meta_list): :return str: list of unified dicts with metadata """ - list_of_keys = self.get_list_of_keys(processed_meta_list) + list_of_keys = self._get_list_of_keys(processed_meta_list) for k in list_of_keys: for list_elem in range(len(processed_meta_list)): if k not in processed_meta_list[list_elem]: processed_meta_list[list_elem][k] = "" return processed_meta_list - def find_genome(self, metadata_list): + def _find_genome(self, metadata_list): """ Create new genome table by joining few columns """ - list_keys = self.get_list_of_keys(metadata_list) + list_keys = self._get_list_of_keys(metadata_list) genome_keys = [ "assembly", "genome_build", @@ -849,7 +818,7 @@ def find_genome(self, metadata_list): metadata_list[sample[0]]["sample_genome"] = sample_genome return metadata_list - def write_gsm_annotation(self, gsm_metadata, file_annotation, use_key_subset=False): + def _write_gsm_annotation(self, gsm_metadata, file_annotation, use_key_subset=False): """ Write metadata sheet out as an annotation file. @@ -877,7 +846,7 @@ def write_gsm_annotation(self, gsm_metadata, file_annotation, use_key_subset=Fal self._LOGGER.info("\033[92mFile has been saved successfully\033[0m") return fp - def write_processed_annotation(self, processed_metadata, file_annotation_path): + def _write_processed_annotation(self, processed_metadata, file_annotation_path): """ Saving annotation file by providing list of dictionaries with files metadata :param list processed_metadata: list of dictionaries with files metadata @@ -896,18 +865,14 @@ def write_processed_annotation(self, processed_metadata, file_annotation_path): os.makedirs(pep_file_folder) self._LOGGER.info("Unifying and saving of metadata... ") - processed_metadata = self.unify_list_keys(processed_metadata) + processed_metadata = self._unify_list_keys(processed_metadata) # delete rare keys - processed_metadata = self.find_genome(processed_metadata) + processed_metadata = self._find_genome(processed_metadata) # filtering huge annotation strings that are repeating for each sample - processed_metadata, proj_meta = self.separate_common_meta( - processed_metadata, - self.const_limit_project, - self.const_limit_discard, - self.attr_limit_truncate, - ) + processed_metadata, proj_meta = self._separate_common_meta(processed_metadata, self.const_limit_project, + self.const_limit_discard, self.attr_limit_truncate) meta_list_str = [ f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta ] @@ -948,12 +913,12 @@ def write_processed_annotation(self, processed_metadata, file_annotation_path): # save .pep.yaml file if self.add_dotfile: dot_yaml_path = os.path.join(pep_file_folder, ".pep.yaml") - self.create_dot_yaml(dot_yaml_path, yaml_name) + self._create_dot_yaml(dot_yaml_path, yaml_name) return True @staticmethod - def sanitize_name(name_str: str): + def _sanitize_name(name_str: str): """ Function that sanitizing strings. (Replace all odd characters) :param str name_str: Any string value that has to be sanitized. @@ -965,7 +930,7 @@ def sanitize_name(name_str: str): new_str = new_str.replace(" ", "_").replace("__", "_") return new_str - def write_raw_annotation(self, metadata_dict, subannotation_dict): + def _write_raw_annotation(self, metadata_dict, subannotation_dict): """ Combining individual accessions into project-level annotations, and writeing individual accession files (if requested) @@ -997,9 +962,7 @@ def write_raw_annotation(self, metadata_dict, subannotation_dict): fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] # sanitize sample names - fixed_dict[key_sample]["sample_name"] = self.sanitize_name( - fixed_dict[key_sample]["sample_name"] - ) + fixed_dict[key_sample]["sample_name"] = self._sanitize_name(fixed_dict[key_sample]["sample_name"]) metadata_dict[key] = fixed_dict @@ -1009,20 +972,13 @@ def write_raw_annotation(self, metadata_dict, subannotation_dict): self.metadata_expanded, acc_GSE + "_annotation.csv" ) if self.acc_anno: - self.write_gsm_annotation( - gsm_metadata, - file_annotation, - use_key_subset=self.use_key_subset, - ) + self._write_gsm_annotation(gsm_metadata, file_annotation, use_key_subset=self.use_key_subset) metadata_dict_combined.update(gsm_metadata) # filtering huge annotation strings that are repeating for each sample - metadata_dict_combined, proj_meta = self.separate_common_meta( - metadata_dict_combined, - self.const_limit_project, - self.const_limit_discard, - self.attr_limit_truncate, - ) + metadata_dict_combined, proj_meta = self._separate_common_meta(metadata_dict_combined, self.const_limit_project, + self.const_limit_discard, + self.attr_limit_truncate) meta_list_str = [ f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta ] @@ -1034,7 +990,7 @@ def write_raw_annotation(self, metadata_dict, subannotation_dict): self.metadata_expanded, acc_GSE + "_subannotation.csv" ) if self.acc_anno: - self.write_subannotation(gsm_multi_table, file_subannotation) + self._write_subannotation(gsm_multi_table, file_subannotation) subannotation_dict_combined.update(gsm_multi_table) self._LOGGER.info( "Creating complete project annotation sheets and config file..." @@ -1045,17 +1001,13 @@ def write_raw_annotation(self, metadata_dict, subannotation_dict): file_annotation = os.path.join( self.metadata_raw, self.project_name + "_annotation.csv" ) - self.write_gsm_annotation( - metadata_dict_combined, - file_annotation, - use_key_subset=self.use_key_subset, - ) + self._write_gsm_annotation(metadata_dict_combined, file_annotation, use_key_subset=self.use_key_subset) # Write combined subannotation table if len(subannotation_dict_combined) > 0: file_subannotation = os.path.join( self.metadata_raw, self.project_name + "_subannotation.csv" ) - self.write_subannotation(subannotation_dict_combined, file_subannotation) + self._write_subannotation(subannotation_dict_combined, file_subannotation) else: file_subannotation = "null" # Write project config file @@ -1084,10 +1036,10 @@ def write_raw_annotation(self, metadata_dict, subannotation_dict): # save .pep.yaml file if self.add_dotfile: dot_yaml_path = os.path.join(self.metadata_raw, ".pep.yaml") - self.create_dot_yaml(dot_yaml_path, yaml_name) + self._create_dot_yaml(dot_yaml_path, yaml_name) @staticmethod - def create_dot_yaml(file_path: str, yaml_path: str): + def _create_dot_yaml(file_path: str, yaml_path: str): """ Function that creates .pep.yaml file that points to actual yaml file :param str file_path: Path to the .pep.yaml file that we want to create @@ -1096,7 +1048,7 @@ def create_dot_yaml(file_path: str, yaml_path: str): with open(file_path, "w+") as file: file.writelines(f"config_file: {yaml_path}") - def separate_common_meta( + def _separate_common_meta( self, meta_list, max_len=50, del_limit=250, attr_limit_truncate=500 ): """ @@ -1120,7 +1072,7 @@ def separate_common_meta( meta_list = new_meta_list - list_of_keys = self.get_list_of_keys(meta_list) + list_of_keys = self._get_list_of_keys(meta_list) list_keys_diff = [] # finding columns with common values for this_key in list_of_keys: @@ -1179,20 +1131,20 @@ def separate_common_meta( return meta_list, new_meta_project - def standardize_colnames(self, meta_list): + def _standardize_colnames(self, meta_list): """ Standardize column names by lower-casing and underscore :param list meta_list: list of dictionaries of samples :return : list of dictionaries of samples with standard colnames """ new_metalist = [] - list_keys = self.get_list_of_keys(meta_list) + list_keys = self._get_list_of_keys(meta_list) for item_nb, values in enumerate(meta_list): new_metalist.append({}) for key in list_keys: try: new_key_name = key.lower().strip() - new_key_name = self.sanitize_name(new_key_name) + new_key_name = self._sanitize_name(new_key_name) new_metalist[item_nb][new_key_name] = values[key] @@ -1201,7 +1153,7 @@ def standardize_colnames(self, meta_list): return new_metalist - def download_SRA_file(self, run_name): + def _download_SRA_file(self, run_name): """ Downloading SRA file by ising 'prefetch' utility from the SRA Toolkit more info: (http://www.ncbi.nlm.nih.gov/books/NBK242621/) @@ -1230,7 +1182,7 @@ def download_SRA_file(self, run_name): time.sleep(t * 2) @staticmethod - def which(program): + def _which(program): """ return str: the path to a program to make sure it exists """ @@ -1250,7 +1202,7 @@ def is_exe(fp): if is_exe(exe_file): return exe_file - def sra_bam_conversion(self, bam_file, run_name): + def _sra_bam_conversion(self, bam_file, run_name): """ Converting of SRA file to BAM file by using samtools function "sam-dump" :param str bam_file: path to BAM file that has to be created @@ -1275,7 +1227,7 @@ def sra_bam_conversion(self, bam_file, run_name): run_subprocess(cmd, shell=True) @staticmethod - def update_columns(metadata, experiment_name, sample_name, read_type): + def _update_columns(metadata, experiment_name, sample_name, read_type): """ Update the metadata associated with a particular experiment. @@ -1319,7 +1271,7 @@ def update_columns(metadata, experiment_name, sample_name, read_type): return exp - def sra_bam_conversion2(self, bam_file, run_name, picard_path=None): + def _sra_bam_conversion2(self, bam_file, run_name, picard_path=None): """ Converting of SRA file to BAM file by using fastq-dump (is used when sam-dump fails, yielding an empty bam file. Here fastq -> bam conversion is used) @@ -1358,7 +1310,7 @@ def sra_bam_conversion2(self, bam_file, run_name, picard_path=None): self._LOGGER.info(f"Conversion command: {cmd}") run_subprocess(cmd, shell=True) - def write_subannotation(self, tabular_data, filepath, column_names=None): + def _write_subannotation(self, tabular_data, filepath, column_names=None): """ Writes one or more tables to a given CSV filepath. @@ -1385,7 +1337,7 @@ def write_subannotation(self, tabular_data, filepath, column_names=None): writer.writerows(values) return fp - def download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): + def _download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): """ Given an url for a file, downloading to specified folder :param str file_url: the URL of the file to download @@ -1413,7 +1365,7 @@ def download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): else: self._LOGGER.info(f"\033[38;5;242mFile {full_filepath} exists.\033[0m") - def get_list_of_processed_files( + def _get_list_of_processed_files( self, file_gse_content: list, file_gsm_content: list ): """ @@ -1429,7 +1381,7 @@ def get_list_of_processed_files( for line in file_gse_content: if re.compile(r"!Series_geo_accession").search(line): - gse_numb = self.get_value(line) + gse_numb = self._get_value(line) meta_processed_series["GSE"] = gse_numb found = re.findall(SER_SUPP_FILE_PATTERN, line) @@ -1468,7 +1420,7 @@ def get_list_of_processed_files( nb = len(meta_processed_samples) - 1 for line_gsm in file_gsm_content: if line_gsm[0] == "^": - nb = len(self.check_file_existance(meta_processed_samples)) + nb = len(self._check_file_existance(meta_processed_samples)) meta_processed_samples.append( {"files": [], "GSE": gse_numb} ) @@ -1512,13 +1464,9 @@ def get_list_of_processed_files( if file_url_gsm != "NONE": meta_processed_samples[nb]["files"].append(file_url_gsm) - self.check_file_existance(meta_processed_samples) - meta_processed_samples = self.separate_list_of_files( - meta_processed_samples - ) - meta_processed_samples = self.separate_file_url( - meta_processed_samples - ) + self._check_file_existance(meta_processed_samples) + meta_processed_samples = self._separate_list_of_files(meta_processed_samples) + meta_processed_samples = self._separate_file_url(meta_processed_samples) self._LOGGER.info( f"Total number of processed SAMPLES files found is: " @@ -1526,7 +1474,7 @@ def get_list_of_processed_files( ) # expand meta_processed_samples with information about type and size - file_info_add = self.read_tar_filelist(filelist_raw_text) + file_info_add = self._read_tar_filelist(filelist_raw_text) for index_nr in range(len(meta_processed_samples)): file_name = meta_processed_samples[index_nr]["file"] meta_processed_samples[index_nr].update( @@ -1534,11 +1482,9 @@ def get_list_of_processed_files( ) if self.filter_re: - meta_processed_samples = self.run_filter(meta_processed_samples) + meta_processed_samples = self._run_filter(meta_processed_samples) if self.filter_size: - meta_processed_samples = self.run_size_filter( - meta_processed_samples - ) + meta_processed_samples = self._run_size_filter(meta_processed_samples) # other files than .tar: saving them into meta_processed_series list else: @@ -1563,19 +1509,19 @@ def get_list_of_processed_files( f"IndexError in adding value to meta_processed_series: %s" % ind_err ) - meta_processed_series = self.separate_list_of_files(meta_processed_series) - meta_processed_series = self.separate_file_url(meta_processed_series) + meta_processed_series = self._separate_list_of_files(meta_processed_series) + meta_processed_series = self._separate_file_url(meta_processed_series) self._LOGGER.info( f"Total number of processed SERIES files found is: " f"%s" % str(len(meta_processed_series)) ) if self.filter_re: - meta_processed_series = self.run_filter(meta_processed_series) + meta_processed_series = self._run_filter(meta_processed_series) return meta_processed_samples, meta_processed_series @staticmethod - def check_file_existance(meta_processed_sample): + def _check_file_existance(meta_processed_sample): """ Checking if last element of the list has files. If list of files is empty deleting it """ @@ -1587,7 +1533,7 @@ def check_file_existance(meta_processed_sample): return meta_processed_sample @staticmethod - def separate_list_of_files(meta_list, col_name="files"): + def _separate_list_of_files(meta_list, col_name="files"): """ This method is separating list of files (dict value) or just simple dict into two different dicts @@ -1611,7 +1557,7 @@ def separate_list_of_files(meta_list, col_name="files"): return separated_list - def separate_file_url(self, meta_list): + def _separate_file_url(self, meta_list): """ This method is adding dict key without file_name without path """ @@ -1629,12 +1575,12 @@ def separate_file_url(self, meta_list): new_dict["sample_name"] = os.path.basename(meta_elem["file"]) # sanitize sample names - new_dict["sample_name"] = self.sanitize_name(new_dict["sample_name"]) + new_dict["sample_name"] = self._sanitize_name(new_dict["sample_name"]) separated_list.append(new_dict) return separated_list - def run_filter(self, meta_list, col_name="file"): + def _run_filter(self, meta_list, col_name="file"): """ If user specified filter it will filter all this files here by col_name """ @@ -1649,7 +1595,7 @@ def run_filter(self, meta_list, col_name="file"): return filtered_list - def run_size_filter(self, meta_list, col_name="file_size"): + def _run_size_filter(self, meta_list, col_name="file_size"): """ function for filtering file size """ @@ -1670,10 +1616,10 @@ def run_size_filter(self, meta_list, col_name="file_size"): return filtered_list @staticmethod - def read_tar_filelist(raw_text: str): + def _read_tar_filelist(raw_text: str): """ Creating list for supplementary files that are listed in "filelist.txt" - :param str file_path: path to the file with information about files that are zipped ("filelist.txt") + :param str raw_text: path to the file with information about files that are zipped ("filelist.txt") :return dict: dict of supplementary file names and additional information """ f = StringIO(raw_text) @@ -1696,11 +1642,11 @@ def read_tar_filelist(raw_text: str): return files_info @staticmethod - def get_value(all_line): + def _get_value(all_line): line_value = all_line.split("= ")[-1] return line_value.split(": ")[-1].rstrip("\n") - def download_processed_file(self, file_url, data_folder): + def _download_processed_file(self, file_url, data_folder): """ Given a url for a file, download it, and extract anything passing the filter. :param str file_url: the URL of the file to download @@ -1725,7 +1671,7 @@ def download_processed_file(self, file_url, data_folder): while ntry < 10: try: - self.download_file(file_url, data_folder) + self._download_file(file_url, data_folder) self._LOGGER.info( "\033[92mFile %s has been downloaded successfully\033[0m" % f"{data_folder}/{filename}" @@ -1743,7 +1689,7 @@ def download_processed_file(self, file_url, data_folder): if ntry > 4: raise e - def get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): + def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): """ Parse out the SRA project identifier from the GSE file :param list file_gse_content: list of content of file_sde_content @@ -1789,7 +1735,7 @@ def get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): if not os.path.isfile(file_sra) or self.refresh_metadata: try: # downloading metadata - srp_list = self.get_SRP_list(acc_SRP) + srp_list = self._get_SRP_list(acc_SRP) if file_sra is not None: with open(file_sra, "w") as m_file: dict_writer = csv.DictWriter(m_file, srp_list[0].keys()) @@ -1819,7 +1765,7 @@ def get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): return srp_list else: try: - srp_list = self.get_SRP_list(acc_SRP) + srp_list = self._get_SRP_list(acc_SRP) return srp_list except Exception as err: @@ -1829,7 +1775,7 @@ def get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): ) return False - def get_SRP_list(self, srp_number: str) -> list: + def _get_SRP_list(self, srp_number: str) -> list: """ By using requests and xml searching and getting list of dicts of SRRs :param str srp_number: SRP number @@ -1859,7 +1805,7 @@ def get_SRP_list(self, srp_number: str) -> list: return SRP_list - def get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): + def _get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): """ A simple state machine to parse SOFT formatted files (Here, the GSM file) diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index f16b56f..6c227d9 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -83,7 +83,7 @@ def test_file_list( ( meta_processed_samples, meta_processed_series, - ) = initiate_geofetcher.get_list_of_processed_files(soft_gse, soft_gsm) + ) = initiate_geofetcher._get_list_of_processed_files(soft_gse, soft_gsm) assert len(meta_processed_samples) == sample_len assert len(meta_processed_series) == series_len @@ -137,7 +137,7 @@ def initiate_geofetcher(self, tmpdir): ], ) def test_downloading_files(self, file_url, file_name, tmpdir, initiate_geofetcher): - initiate_geofetcher.download_processed_file(file_url, tmpdir) + initiate_geofetcher._download_processed_file(file_url, tmpdir) assert len(tmpdir.listdir()) == 1 assert os.path.basename(tmpdir.listdir()[0]) == file_name @@ -178,7 +178,7 @@ def initiate_geofetcher(self, tmpdir): ], ) def test_filter(self, meta_list, output, initiate_geofetcher): - result = initiate_geofetcher.run_filter(meta_list) + result = initiate_geofetcher._run_filter(meta_list) assert result == output @pytest.mark.parametrize( @@ -199,7 +199,7 @@ def test_filter(self, meta_list, output, initiate_geofetcher): ], ) def test_size_filter(self, meta_list, output, initiate_geofetcher): - result = initiate_geofetcher.run_size_filter(meta_list) + result = initiate_geofetcher._run_size_filter(meta_list) assert result == output @pytest.mark.parametrize( @@ -248,7 +248,7 @@ def test_size_filter(self, meta_list, output, initiate_geofetcher): def test_large_meta_separation( self, init_meta_data, result_sample, result_proj, initiate_geofetcher ): - samp, proj = initiate_geofetcher.separate_common_meta(init_meta_data, max_len=0) + samp, proj = initiate_geofetcher._separate_common_meta(init_meta_data, max_len=0) assert samp == result_sample assert proj == result_proj From 6357dc5adc2ed47b54b66018b8cbe27da8348d83 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 19 Aug 2022 11:31:57 -0400 Subject: [PATCH 07/61] fixed #80 --- geofetch/config_template.yaml | 2 +- geofetch/geofetch.py | 15 +++++++-------- requirements/requirements-all.txt | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/geofetch/config_template.yaml b/geofetch/config_template.yaml index b492ae6..a47348a 100644 --- a/geofetch/config_template.yaml +++ b/geofetch/config_template.yaml @@ -3,7 +3,7 @@ name: {project_name} pep_version: 2.1.0 sample_table: {annotation} -subsample_table: {subannotation} +{subannotation} looper: output_dir: {project_name} diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 291282a..60544cc 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -51,7 +51,7 @@ def __init__( config_template: str = None, pipeline_samples: str = None, pipeline_project: str = None, - skip=0, + skip: int = 0, acc_anno: bool = False, use_key_subset: bool = False, processed: bool = True, @@ -74,7 +74,7 @@ def __init__( opts=None, **kwargs, ): - global _LOGGER + if opts is not None: _LOGGER = logmuse.logger_via_cli(opts) else: @@ -182,9 +182,9 @@ def __init__( if bam_conversion and not just_metadata and not self._which("samtools"): raise SystemExit("For SAM/BAM processing, samtools should be on PATH.") - def get_project_obj(self, input: str) -> Dict[peppy.Project]: + def get_project(self, input: str) -> Dict[peppy.Project]: """ - Function for fetching projects from GEO|SRA and obtaining peppy project + Function for fetching projects from GEO|SRA and receiving peppy project :param input: GSE number, or path to file of GSE numbers :return: peppy project or list of project, if acc_anno is set. """ @@ -255,8 +255,8 @@ def get_project_obj(self, input: str) -> Dict[peppy.Project]: new_dict = {} for proj_key in raw_project_dict.keys(): - new_dict[proj_key] = peppy.Project( - pd_object=pd.DataFrame(raw_project_dict[proj_key]) + new_dict[proj_key] = peppy.Project().from_pandas( + pd.DataFrame(raw_project_dict[proj_key]) ) return new_dict @@ -1020,7 +1020,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): template_values = { "project_name": self.project_name, "annotation": os.path.basename(file_annotation), - "subannotation": os.path.basename(file_subannotation), + "subannotation": f"subsample_table: {os.path.basename(file_subannotation)}", "pipeline_samples": self.file_pipeline_samples, "pipeline_project": self.file_pipeline_project, "additional_columns": modifiers_str, @@ -1790,7 +1790,6 @@ def _get_SRP_list(self, srp_number: str) -> list: if x.status_code != 200: self._LOGGER.error(f"Error in ncbi esearch response: {x.status_code}") raise x.raise_for_status() - id_results = x.json()["esearchresult"]["idlist"] id_r_string = ",".join(id_results) diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index 3853373..11f99b6 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -8,4 +8,4 @@ ubiquerg>=0.6.0 requests>=2.28.1 xmltodict>=0.13.0 pandas>=1.4.3 -peppy @ git+https://github.com/pepkit/peppy.git@dev_pd_init#egg=peppy +peppy>=0.34.0 From 5d982cd4f78c5336cd6986eb70a147fc6e1c9af4 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 19 Aug 2022 12:09:16 -0400 Subject: [PATCH 08/61] fixed #82 --- geofetch/geofetch.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 60544cc..45803d5 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1736,7 +1736,8 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): try: # downloading metadata srp_list = self._get_SRP_list(acc_SRP) - if file_sra is not None: + srp_list = self._unify_list_keys(srp_list) + if file_sra is not None and not self.discard_soft: with open(file_sra, "w") as m_file: dict_writer = csv.DictWriter(m_file, srp_list[0].keys()) dict_writer.writeheader() @@ -1791,16 +1792,22 @@ def _get_SRP_list(self, srp_number: str) -> list: self._LOGGER.error(f"Error in ncbi esearch response: {x.status_code}") raise x.raise_for_status() id_results = x.json()["esearchresult"]["idlist"] - - id_r_string = ",".join(id_results) - id_api = NCBI_EFETCH.format(ID=id_r_string) - y = requests.get(id_api) - if y.status_code != 200: - self._LOGGER.error(f"Error in ncbi efetch response: {x.status_code}") - raise y.raise_for_status() - - xml_result = y.text - SRP_list = xmltodict.parse(xml_result)["SraRunInfo"]["Row"] + if len(id_results) > 500: + id_results = [id_results[x:x + 100] for x in range(0, len(id_results), 100)] + else: + id_results = [id_results] + + SRP_list = [] + for result in id_results: + id_r_string = ",".join(result) + id_api = NCBI_EFETCH.format(ID=id_r_string) + + y = requests.get(id_api) + if y.status_code != 200: + self._LOGGER.error(f"Error in ncbi efetch response in SRA fetching: {x.status_code}") + raise y.raise_for_status() + xml_result = y.text + SRP_list.extend(xmltodict.parse(xml_result)["SraRunInfo"]["Row"]) return SRP_list From 212f6eb1cfbbad5e989c1a235b89c90fcd71e09d Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 19 Aug 2022 12:16:52 -0400 Subject: [PATCH 09/61] Fixed #80 (2) --- geofetch/geofetch.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 45803d5..892c927 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1008,8 +1008,10 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): self.metadata_raw, self.project_name + "_subannotation.csv" ) self._write_subannotation(subannotation_dict_combined, file_subannotation) + subanot_path_yaml = f"subsample_table: {os.path.basename(file_subannotation)}" else: file_subannotation = "null" + subanot_path_yaml = f"" # Write project config file if not self.config_template: geofetchdir = os.path.dirname(__file__) @@ -1020,7 +1022,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): template_values = { "project_name": self.project_name, "annotation": os.path.basename(file_annotation), - "subannotation": f"subsample_table: {os.path.basename(file_subannotation)}", + "subannotation": subanot_path_yaml, "pipeline_samples": self.file_pipeline_samples, "pipeline_project": self.file_pipeline_project, "additional_columns": modifiers_str, From c880492e344b0904e978f0eeef1dda84b60d2ed0 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 19 Aug 2022 14:36:58 -0400 Subject: [PATCH 10/61] fixed #73 --- geofetch/geofetch.py | 51 +++++++++++++++++++++---------- requirements/requirements-all.txt | 1 + 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 892c927..02da536 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -13,6 +13,8 @@ from string import punctuation import requests import xmltodict +from rich.progress import track +#from tqdm import tqdm # import tarfile import time @@ -71,6 +73,7 @@ def __init__( attr_limit_truncate: int = 500, discard_soft: bool = False, add_dotfile: bool = False, + disable_progressbar: bool = False, opts=None, **kwargs, ): @@ -167,6 +170,7 @@ def __init__( self.discard_soft = discard_soft self.add_dotfile = add_dotfile + self.disable_progressbar = disable_progressbar self._LOGGER.info(f"Metadata folder: {self.metadata_expanded}") @@ -182,6 +186,8 @@ def __init__( if bam_conversion and not just_metadata and not self._which("samtools"): raise SystemExit("For SAM/BAM processing, samtools should be on PATH.") + self.just_object = False + def get_project(self, input: str) -> Dict[peppy.Project]: """ Function for fetching projects from GEO|SRA and receiving peppy project @@ -189,6 +195,8 @@ def get_project(self, input: str) -> Dict[peppy.Project]: :return: peppy project or list of project, if acc_anno is set. """ self.just_metadata = True + self.just_object = True + self.disable_progressbar = True acc_GSE_list = parse_accessions( input, self.metadata_expanded, self.just_metadata ) @@ -207,35 +215,35 @@ def get_project(self, input: str) -> Dict[peppy.Project]: if data_source_all: # samples self.supp_by = "samples" - samples_list = self.fetch_all(input=acc_GSE, just_object=True) + samples_list = self.fetch_all(input=acc_GSE) if len(samples_list) > 0: raw_project_dict[acc_GSE + "_samples"] = samples_list # series self.supp_by = "series" - series_list = self.fetch_all(input=acc_GSE, just_object=True) + series_list = self.fetch_all(input=acc_GSE) if len(series_list) > 0: raw_project_dict[acc_GSE + "_series"] = series_list else: - ser_list = self.fetch_all(input=acc_GSE, just_object=True) + ser_list = self.fetch_all(input=acc_GSE) if len(ser_list) > 0: raw_project_dict[acc_GSE + "_" + self.supp_by] = ser_list else: if data_source_all: # samples self.supp_by = "samples" - samples_list = self.fetch_all(input=input, just_object=True) + samples_list = self.fetch_all(input=input) if len(samples_list) > 0: raw_project_dict["project_samples"] = samples_list # series self.supp_by = "series" - series_list = self.fetch_all(input=input, just_object=True) + series_list = self.fetch_all(input=input) if len(series_list) > 0: raw_project_dict["project_series"] = series_list else: - ser_list = self.fetch_all(input=input, just_object=True) + ser_list = self.fetch_all(input=input) if len(ser_list) > 0: raw_project_dict["project_" + self.supp_by] = ser_list @@ -244,12 +252,12 @@ def get_project(self, input: str) -> Dict[peppy.Project]: if self.acc_anno: self.acc_anno = False for acc_GSE in acc_GSE_list.keys(): - project_dict = self.fetch_all(input=input, just_object=True) + project_dict = self.fetch_all(input=input) if len(project_dict) > 0: raw_project_dict[acc_GSE + "_raw_samples"] = project_dict else: - ser_dict = self.fetch_all(input=input, just_object=True) + ser_dict = self.fetch_all(input=input) if len(ser_dict) > 0: raw_project_dict["raw_samples"] = ser_dict @@ -261,7 +269,7 @@ def get_project(self, input: str) -> Dict[peppy.Project]: return new_dict - def fetch_all(self, input: str, name: str = None, just_object: bool = False): + def fetch_all(self, input: str, name: str = None): """Main script driver/workflow""" if name: @@ -288,7 +296,10 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): acc_GSE_keys = acc_GSE_list.keys() nkeys = len(acc_GSE_keys) ncount = 0 - for acc_GSE in acc_GSE_list.keys(): + for acc_GSE in track(acc_GSE_list.keys(), + description="Processing... ", + disable=self.disable_progressbar): + ncount += 1 if ncount <= self.skip: continue @@ -638,7 +649,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) elif self.supp_by == "samples": - if just_object: + if self.just_object: return processed_metadata_samples else: supp_sample_path_meta = os.path.join( @@ -649,7 +660,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) elif self.supp_by == "series": - if just_object: + if self.just_object: return processed_metadata_exp else: supp_series_path_meta = os.path.join( @@ -661,7 +672,7 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): # saving PEPs for raw data else: - if not just_object: + if not self.just_object: self._write_raw_annotation(metadata_dict, subannotation_dict) else: raw_meta_list = [] @@ -670,7 +681,6 @@ def fetch_all(self, input: str, name: str = None, just_object: bool = False): metadata_dict[meta_key][srx_key]["gse_number"] = meta_key metadata_dict[meta_key][srx_key]["srx_number"] = srx_key raw_meta_list.append(metadata_dict[meta_key][srx_key]) - # TODO: add subannotation_dict!!!! return raw_meta_list def _expand_metadata_list(self, metadata_list, dict_key): @@ -1471,7 +1481,7 @@ def _get_list_of_processed_files( meta_processed_samples = self._separate_file_url(meta_processed_samples) self._LOGGER.info( - f"Total number of processed SAMPLES files found is: " + f"\nTotal number of processed SAMPLES files found is: " f"%s" % str(len(meta_processed_samples)) ) @@ -1712,7 +1722,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): # as part of this GEO submission. Can't proceed. self._LOGGER.warning( "\033[91mUnable to get SRA accession (SRP#) from GEO GSE SOFT file. " - "No raw data?\033[0m" + "No raw data detected! Continuing anyway...\033[0m" ) # but wait; another possibility: there's no SRP linked to the GSE, but there # could still be an SRX linked to the (each) GSM. @@ -1784,6 +1794,9 @@ def _get_SRP_list(self, srp_number: str) -> list: :param str srp_number: SRP number :return: list of dicts of SRRs """ + if not srp_number: + self._LOGGER.info(f"No srp number in this accession found") + return [] self._LOGGER.info(f"Downloading {srp_number} sra metadata") ncbi_esearch = NCBI_ESEARCH.format(SRP_NUMBER=srp_number) @@ -1972,6 +1985,12 @@ def _parse_cmdl(cmdl): "These will be added to the project config file to make it immediately " "compatible with looper. [Default: null]", ) + # Optional + parser.add_argument( + "--disable-progressbar", + action="store_true", + help="Optional: Disable progressbar", + ) # Optional parser.add_argument( diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index 11f99b6..06cc825 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -9,3 +9,4 @@ requests>=2.28.1 xmltodict>=0.13.0 pandas>=1.4.3 peppy>=0.34.0 +rich>=12.5.1 From 66717331f5c8948b2ead512a3740b95da98d7dd5 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 22 Aug 2022 19:44:52 -0400 Subject: [PATCH 11/61] New, optimized version to peppy project --- geofetch/geofetch.py | 182 +++++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 83 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 02da536..965fadf 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -14,7 +14,7 @@ import requests import xmltodict from rich.progress import track -#from tqdm import tqdm +import yaml # import tarfile import time @@ -201,7 +201,7 @@ def get_project(self, input: str) -> Dict[peppy.Project]: input, self.metadata_expanded, self.just_metadata ) - raw_project_dict = {} + project_dict = {} if self.processed: if self.supp_by == "all": @@ -216,36 +216,30 @@ def get_project(self, input: str) -> Dict[peppy.Project]: # samples self.supp_by = "samples" samples_list = self.fetch_all(input=acc_GSE) - if len(samples_list) > 0: - raw_project_dict[acc_GSE + "_samples"] = samples_list + project_dict[acc_GSE + "_samples"] = samples_list # series self.supp_by = "series" series_list = self.fetch_all(input=acc_GSE) - if len(series_list) > 0: - raw_project_dict[acc_GSE + "_series"] = series_list + project_dict[acc_GSE + "_series"] = series_list else: ser_list = self.fetch_all(input=acc_GSE) - if len(ser_list) > 0: - raw_project_dict[acc_GSE + "_" + self.supp_by] = ser_list + project_dict[acc_GSE + "_" + self.supp_by] = ser_list else: if data_source_all: # samples self.supp_by = "samples" samples_list = self.fetch_all(input=input) - if len(samples_list) > 0: - raw_project_dict["project_samples"] = samples_list + project_dict["project_samples"] = samples_list # series self.supp_by = "series" series_list = self.fetch_all(input=input) - if len(series_list) > 0: - raw_project_dict["project_series"] = series_list + project_dict["project_series"] = series_list else: ser_list = self.fetch_all(input=input) - if len(ser_list) > 0: - raw_project_dict["project_" + self.supp_by] = ser_list + project_dict["project_" + self.supp_by] = ser_list else: # Not sure about below code... @@ -253,21 +247,13 @@ def get_project(self, input: str) -> Dict[peppy.Project]: self.acc_anno = False for acc_GSE in acc_GSE_list.keys(): project_dict = self.fetch_all(input=input) - if len(project_dict) > 0: - raw_project_dict[acc_GSE + "_raw_samples"] = project_dict + project_dict[acc_GSE + "_raw_samples"] = project_dict else: ser_dict = self.fetch_all(input=input) - if len(ser_dict) > 0: - raw_project_dict["raw_samples"] = ser_dict + project_dict["raw_samples"] = ser_dict - new_dict = {} - for proj_key in raw_project_dict.keys(): - new_dict[proj_key] = peppy.Project().from_pandas( - pd.DataFrame(raw_project_dict[proj_key]) - ) - - return new_dict + return project_dict def fetch_all(self, input: str, name: str = None): """Main script driver/workflow""" @@ -639,49 +625,43 @@ def fetch_all(self, input: str, name: str = None): "PEP_samples", self.project_name + SAMPLE_SUPP_METADATA_FILE, ) - self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) + peppy_obj = self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) supp_series_path_meta = os.path.join( self.metadata_raw, "PEP_series", self.project_name + EXP_SUPP_METADATA_FILE, ) - self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) + peppy_obj = self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) elif self.supp_by == "samples": - if self.just_object: - return processed_metadata_samples - else: - supp_sample_path_meta = os.path.join( - self.metadata_raw, - "PEP_samples", - self.project_name + SAMPLE_SUPP_METADATA_FILE, - ) - self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) + supp_sample_path_meta = os.path.join( + self.metadata_raw, + "PEP_samples", + self.project_name + SAMPLE_SUPP_METADATA_FILE, + ) + peppy_obj = self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) elif self.supp_by == "series": - if self.just_object: - return processed_metadata_exp - else: - supp_series_path_meta = os.path.join( - self.metadata_raw, - "PEP_series", - self.project_name + EXP_SUPP_METADATA_FILE, - ) - self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) + supp_series_path_meta = os.path.join( + self.metadata_raw, + "PEP_series", + self.project_name + EXP_SUPP_METADATA_FILE, + ) + peppy_obj = self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) + + else: + return None + + if self.just_object: + return peppy_obj # saving PEPs for raw data else: - if not self.just_object: - self._write_raw_annotation(metadata_dict, subannotation_dict) - else: - raw_meta_list = [] - for meta_key in metadata_dict.keys(): - for srx_key in metadata_dict[meta_key].keys(): - metadata_dict[meta_key][srx_key]["gse_number"] = meta_key - metadata_dict[meta_key][srx_key]["srx_number"] = srx_key - raw_meta_list.append(metadata_dict[meta_key][srx_key]) - return raw_meta_list + return_value = self._write_raw_annotation(metadata_dict, subannotation_dict) + if self.just_object: + return return_value + def _expand_metadata_list(self, metadata_list, dict_key): """ @@ -888,14 +868,6 @@ def _write_processed_annotation(self, processed_metadata, file_annotation_path): ] modifiers_str = "\n ".join(d for d in meta_list_str) - with open(file_annotation_path, "w") as m_file: - dict_writer = csv.DictWriter(m_file, processed_metadata[0].keys()) - dict_writer.writeheader() - dict_writer.writerows(processed_metadata) - self._LOGGER.info( - "\033[92mFile %s has been saved successfully\033[0m" % file_annotation_path - ) - geofetchdir = os.path.dirname(__file__) config_template = os.path.join(geofetchdir, "config_processed_template.yaml") @@ -915,17 +887,34 @@ def _write_processed_annotation(self, processed_metadata, file_annotation_path): placeholder = "{" + str(k) + "}" template = template.replace(placeholder, str(v)) - # save .yaml file - yaml_name = os.path.split(file_annotation_path)[1][:-4] + ".yaml" - config = os.path.join(pep_file_folder, yaml_name) - self._write(config, template, msg_pre=" Config file: ") + if not self.just_object: + with open(file_annotation_path, "w") as m_file: + dict_writer = csv.DictWriter(m_file, processed_metadata[0].keys()) + dict_writer.writeheader() + dict_writer.writerows(processed_metadata) + self._LOGGER.info( + "\033[92mFile %s has been saved successfully\033[0m" % file_annotation_path + ) + + # save .yaml file + yaml_name = os.path.split(file_annotation_path)[1][:-4] + ".yaml" + config = os.path.join(pep_file_folder, yaml_name) + self._write(config, template, msg_pre=" Config file: ") + + # save .pep.yaml file + if self.add_dotfile: + dot_yaml_path = os.path.join(pep_file_folder, ".pep.yaml") + self._create_dot_yaml(dot_yaml_path, yaml_name) + + return None + + else: + pd_value = pd.DataFrame(processed_metadata) - # save .pep.yaml file - if self.add_dotfile: - dot_yaml_path = os.path.join(pep_file_folder, ".pep.yaml") - self._create_dot_yaml(dot_yaml_path, yaml_name) + conf = yaml.load(template, Loader=yaml.Loader) + proj = peppy.Project().from_pandas(pd_value, config=conf) + return proj - return True @staticmethod def _sanitize_name(name_str: str): @@ -1011,7 +1000,8 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): file_annotation = os.path.join( self.metadata_raw, self.project_name + "_annotation.csv" ) - self._write_gsm_annotation(metadata_dict_combined, file_annotation, use_key_subset=self.use_key_subset) + + # Write combined subannotation table if len(subannotation_dict_combined) > 0: file_subannotation = os.path.join( @@ -1022,6 +1012,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): else: file_subannotation = "null" subanot_path_yaml = f"" + # Write project config file if not self.config_template: geofetchdir = os.path.dirname(__file__) @@ -1039,16 +1030,40 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): } for k, v in template_values.items(): placeholder = "{" + str(k) + "}" + # v1 = v.replace(':', '=') template = template.replace(placeholder, str(v)) - # save .yaml file - yaml_name = self.project_name + "_config.yaml" - config = os.path.join(self.metadata_raw, yaml_name) - self._write(config, template, msg_pre=" Config file: ") - # save .pep.yaml file - if self.add_dotfile: - dot_yaml_path = os.path.join(self.metadata_raw, ".pep.yaml") - self._create_dot_yaml(dot_yaml_path, yaml_name) + if not self.just_object: + # write annotation + self._write_gsm_annotation(metadata_dict_combined, file_annotation, use_key_subset=self.use_key_subset) + # write subannotation + if len(subannotation_dict_combined) > 0: + self._write_subannotation(subannotation_dict_combined, file_subannotation) + + # save .yaml file + yaml_name = self.project_name + "_config.yaml" + config = os.path.join(self.metadata_raw, yaml_name) + self._write(config, template, msg_pre=" Config file: ") + + # save .pep.yaml file + if self.add_dotfile: + dot_yaml_path = os.path.join(self.metadata_raw, ".pep.yaml") + self._create_dot_yaml(dot_yaml_path, yaml_name) + + else: + sddd = [metadata_dict_combined.values()] + sdddd = subannotation_dict_combined.values() + meta_df = pd.DataFrame.from_dict(metadata_dict_combined, orient='index') + + print(meta_df) + + sub_meta_df = pd.DataFrame.from_dict(subannotation_dict_combined, orient='index') + if sub_meta_df.empty: + sub_meta_df = None + conf = yaml.load(template, Loader=yaml.Loader) + + proj = peppy.Project().from_pandas(meta_df, sub_meta_df, conf) + return proj @staticmethod def _create_dot_yaml(file_path: str, yaml_path: str): @@ -1115,7 +1130,7 @@ def _separate_common_meta( if first_key: if len(str(nb_sample[1][this_key])) <= del_limit: new_meta_project.append( - {this_key: nb_sample[1][this_key]} + {this_key: f'\"{nb_sample[1][this_key]}\"'} ) first_key = False del meta_list[nb_sample[0]][this_key] @@ -2186,7 +2201,8 @@ def main(): args = _parse_cmdl(sys.argv[1:]) args_dict = vars(args) args_dict["args"] = args - Geofetcher(**args_dict).fetch_all(args_dict["input"]) + #Geofetcher(**args_dict).fetch_all(args_dict["input"]) + Geofetcher(**args_dict).get_project(args_dict["input"]) if __name__ == "__main__": From 23afea22d5c74c9bcd4462d5fd90e4ac967ae90b Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 22 Aug 2022 20:26:55 -0400 Subject: [PATCH 12/61] small corrections --- geofetch/geofetch.py | 223 +++++++++++++++++++++++++---------------- tests/test_geofetch.py | 4 +- 2 files changed, 138 insertions(+), 89 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 965fadf..a65f40e 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -204,42 +204,13 @@ def get_project(self, input: str) -> Dict[peppy.Project]: project_dict = {} if self.processed: - if self.supp_by == "all": - data_source_all = True - else: - data_source_all = False - if self.acc_anno: self.acc_anno = False for acc_GSE in acc_GSE_list.keys(): - if data_source_all: - # samples - self.supp_by = "samples" - samples_list = self.fetch_all(input=acc_GSE) - project_dict[acc_GSE + "_samples"] = samples_list + project_dict.update(self.fetch_all(input=acc_GSE, name=acc_GSE)) - # series - self.supp_by = "series" - series_list = self.fetch_all(input=acc_GSE) - project_dict[acc_GSE + "_series"] = series_list - else: - ser_list = self.fetch_all(input=acc_GSE) - project_dict[acc_GSE + "_" + self.supp_by] = ser_list else: - if data_source_all: - # samples - self.supp_by = "samples" - samples_list = self.fetch_all(input=input) - project_dict["project_samples"] = samples_list - - # series - self.supp_by = "series" - series_list = self.fetch_all(input=input) - project_dict["project_series"] = series_list - - else: - ser_list = self.fetch_all(input=input) - project_dict["project_" + self.supp_by] = ser_list + project_dict.update(self.fetch_all(input=input, name="project")) else: # Not sure about below code... @@ -282,9 +253,11 @@ def fetch_all(self, input: str, name: str = None): acc_GSE_keys = acc_GSE_list.keys() nkeys = len(acc_GSE_keys) ncount = 0 - for acc_GSE in track(acc_GSE_list.keys(), - description="Processing... ", - disable=self.disable_progressbar): + for acc_GSE in track( + acc_GSE_list.keys(), + description="Processing... ", + disable=self.disable_progressbar, + ): ncount += 1 if ncount <= self.skip: @@ -346,11 +319,15 @@ def fetch_all(self, input: str, name: str = None): ( meta_processed_samples, meta_processed_series, - ) = self._get_list_of_processed_files(file_gse_content, file_gsm_content) + ) = self._get_list_of_processed_files( + file_gse_content, file_gsm_content + ) # taking into account list of GSM that is specified in the input file gsm_list = acc_GSE_list[acc_GSE] - meta_processed_samples = self._filter_gsm(meta_processed_samples, gsm_list) + meta_processed_samples = self._filter_gsm( + meta_processed_samples, gsm_list + ) # Unify keys: meta_processed_samples = self._unify_list_keys(meta_processed_samples) meta_processed_series = self._unify_list_keys(meta_processed_series) @@ -359,17 +336,25 @@ def fetch_all(self, input: str, name: str = None): list_of_keys = self._get_list_of_keys(meta_processed_samples) self._LOGGER.info("Expanding metadata list...") for key_in_list in list_of_keys: - meta_processed_samples = self._expand_metadata_list(meta_processed_samples, key_in_list) + meta_processed_samples = self._expand_metadata_list( + meta_processed_samples, key_in_list + ) # series list_of_keys_series = self._get_list_of_keys(meta_processed_series) self._LOGGER.info("Expanding metadata list...") for key_in_list in list_of_keys_series: - meta_processed_series = self._expand_metadata_list(meta_processed_series, key_in_list) + meta_processed_series = self._expand_metadata_list( + meta_processed_series, key_in_list + ) # convert column names to lowercase and underscore - meta_processed_samples = self._standardize_colnames(meta_processed_samples) - meta_processed_series = self._standardize_colnames(meta_processed_series) + meta_processed_samples = self._standardize_colnames( + meta_processed_samples + ) + meta_processed_series = self._standardize_colnames( + meta_processed_series + ) if not self.acc_anno: # adding metadata from current experiment to the project @@ -385,7 +370,9 @@ def fetch_all(self, input: str, name: str = None): f"{acc_GSE}_samples", acc_GSE + SAMPLE_SUPP_METADATA_FILE, ) - self._write_processed_annotation(meta_processed_samples, pep_acc_path_sample) + self._write_processed_annotation( + meta_processed_samples, pep_acc_path_sample + ) # series pep_acc_path_exp = os.path.join( @@ -393,21 +380,27 @@ def fetch_all(self, input: str, name: str = None): f"{acc_GSE}_series", acc_GSE + EXP_SUPP_METADATA_FILE, ) - self._write_processed_annotation(meta_processed_series, pep_acc_path_exp) + self._write_processed_annotation( + meta_processed_series, pep_acc_path_exp + ) elif self.supp_by == "samples": pep_acc_path_sample = os.path.join( self.metadata_raw, f"{acc_GSE}_samples", acc_GSE + SAMPLE_SUPP_METADATA_FILE, ) - self._write_processed_annotation(meta_processed_samples, pep_acc_path_sample) + self._write_processed_annotation( + meta_processed_samples, pep_acc_path_sample + ) elif self.supp_by == "series": pep_acc_path_exp = os.path.join( self.metadata_raw, f"{acc_GSE}_series", acc_GSE + EXP_SUPP_METADATA_FILE, ) - self._write_processed_annotation(meta_processed_series, pep_acc_path_exp) + self._write_processed_annotation( + meta_processed_series, pep_acc_path_exp + ) if not self.just_metadata: data_geo_folder = os.path.join(self.geo_folder, acc_GSE) @@ -447,11 +440,15 @@ def fetch_all(self, input: str, name: str = None): else: # download gsm metadata - gsm_metadata = self._get_gsm_metadata(acc_GSE, acc_GSE_list, file_gsm_content) + gsm_metadata = self._get_gsm_metadata( + acc_GSE, acc_GSE_list, file_gsm_content + ) metadata_dict[acc_GSE] = gsm_metadata # download gsm metadata - SRP_list_result = self._get_SRA_meta(file_gse_content, gsm_metadata, file_sra) + SRP_list_result = self._get_SRA_meta( + file_gse_content, gsm_metadata, file_sra + ) if not SRP_list_result: # delete current acc if no raw data was found # del metadata_dict[acc_GSE] @@ -495,8 +492,12 @@ def fetch_all(self, input: str, name: str = None): # Otherwise, record that there's SRA data for this run. # And set a few columns that are used as input to the Looper # print("Updating columns for looper") - self._update_columns(gsm_metadata, experiment, sample_name=sample_name, - read_type=line["LibraryLayout"]) + self._update_columns( + gsm_metadata, + experiment, + sample_name=sample_name, + read_type=line["LibraryLayout"], + ) # Some experiments are flagged in SRA as having multiple runs. if gsm_metadata[experiment].get("SRR") is not None: @@ -591,7 +592,9 @@ def fetch_all(self, input: str, name: str = None): self._LOGGER.warning( "Bam conversion failed with sam-dump. Trying fastq-dump..." ) - self._sra_bam_conversion2(bam_file, run_name, self.picard_path) + self._sra_bam_conversion2( + bam_file, run_name, self.picard_path + ) except FileNotFoundError as err: self._LOGGER.info( @@ -622,17 +625,27 @@ def fetch_all(self, input: str, name: str = None): if self.supp_by == "all": supp_sample_path_meta = os.path.join( self.metadata_raw, - "PEP_samples", + "s", self.project_name + SAMPLE_SUPP_METADATA_FILE, ) - peppy_obj = self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) + peppy_obj_samples = self._write_processed_annotation( + processed_metadata_samples, supp_sample_path_meta + ) supp_series_path_meta = os.path.join( self.metadata_raw, "PEP_series", self.project_name + EXP_SUPP_METADATA_FILE, ) - peppy_obj = self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) + peppy_obj_series = self._write_processed_annotation( + processed_metadata_exp, supp_series_path_meta + ) + + if self.just_object: + return { + f"{name}_samples": peppy_obj_samples, + f"{name}_series": peppy_obj_series, + } elif self.supp_by == "samples": supp_sample_path_meta = os.path.join( @@ -640,7 +653,11 @@ def fetch_all(self, input: str, name: str = None): "PEP_samples", self.project_name + SAMPLE_SUPP_METADATA_FILE, ) - peppy_obj = self._write_processed_annotation(processed_metadata_samples, supp_sample_path_meta) + peppy_obj = self._write_processed_annotation( + processed_metadata_samples, supp_sample_path_meta + ) + if self.just_object: + return {f"{name}_samples": peppy_obj} elif self.supp_by == "series": supp_series_path_meta = os.path.join( @@ -648,21 +665,21 @@ def fetch_all(self, input: str, name: str = None): "PEP_series", self.project_name + EXP_SUPP_METADATA_FILE, ) - peppy_obj = self._write_processed_annotation(processed_metadata_exp, supp_series_path_meta) + peppy_obj = self._write_processed_annotation( + processed_metadata_exp, supp_series_path_meta + ) + if self.just_object: + return {f"{name}_PEP_series": peppy_obj} else: return None - if self.just_object: - return peppy_obj - # saving PEPs for raw data else: return_value = self._write_raw_annotation(metadata_dict, subannotation_dict) if self.just_object: return return_value - def _expand_metadata_list(self, metadata_list, dict_key): """ Expanding list items in the list by creating new items or joining them @@ -808,7 +825,9 @@ def _find_genome(self, metadata_list): metadata_list[sample[0]]["sample_genome"] = sample_genome return metadata_list - def _write_gsm_annotation(self, gsm_metadata, file_annotation, use_key_subset=False): + def _write_gsm_annotation( + self, gsm_metadata, file_annotation, use_key_subset=False + ): """ Write metadata sheet out as an annotation file. @@ -861,8 +880,12 @@ def _write_processed_annotation(self, processed_metadata, file_annotation_path): processed_metadata = self._find_genome(processed_metadata) # filtering huge annotation strings that are repeating for each sample - processed_metadata, proj_meta = self._separate_common_meta(processed_metadata, self.const_limit_project, - self.const_limit_discard, self.attr_limit_truncate) + processed_metadata, proj_meta = self._separate_common_meta( + processed_metadata, + self.const_limit_project, + self.const_limit_discard, + self.attr_limit_truncate, + ) meta_list_str = [ f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta ] @@ -893,7 +916,8 @@ def _write_processed_annotation(self, processed_metadata, file_annotation_path): dict_writer.writeheader() dict_writer.writerows(processed_metadata) self._LOGGER.info( - "\033[92mFile %s has been saved successfully\033[0m" % file_annotation_path + "\033[92mFile %s has been saved successfully\033[0m" + % file_annotation_path ) # save .yaml file @@ -915,7 +939,6 @@ def _write_processed_annotation(self, processed_metadata, file_annotation_path): proj = peppy.Project().from_pandas(pd_value, config=conf) return proj - @staticmethod def _sanitize_name(name_str: str): """ @@ -961,7 +984,9 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] # sanitize sample names - fixed_dict[key_sample]["sample_name"] = self._sanitize_name(fixed_dict[key_sample]["sample_name"]) + fixed_dict[key_sample]["sample_name"] = self._sanitize_name( + fixed_dict[key_sample]["sample_name"] + ) metadata_dict[key] = fixed_dict @@ -971,13 +996,18 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): self.metadata_expanded, acc_GSE + "_annotation.csv" ) if self.acc_anno: - self._write_gsm_annotation(gsm_metadata, file_annotation, use_key_subset=self.use_key_subset) + self._write_gsm_annotation( + gsm_metadata, file_annotation, use_key_subset=self.use_key_subset + ) metadata_dict_combined.update(gsm_metadata) # filtering huge annotation strings that are repeating for each sample - metadata_dict_combined, proj_meta = self._separate_common_meta(metadata_dict_combined, self.const_limit_project, - self.const_limit_discard, - self.attr_limit_truncate) + metadata_dict_combined, proj_meta = self._separate_common_meta( + metadata_dict_combined, + self.const_limit_project, + self.const_limit_discard, + self.attr_limit_truncate, + ) meta_list_str = [ f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta ] @@ -1001,14 +1031,15 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): self.metadata_raw, self.project_name + "_annotation.csv" ) - # Write combined subannotation table if len(subannotation_dict_combined) > 0: file_subannotation = os.path.join( self.metadata_raw, self.project_name + "_subannotation.csv" ) self._write_subannotation(subannotation_dict_combined, file_subannotation) - subanot_path_yaml = f"subsample_table: {os.path.basename(file_subannotation)}" + subanot_path_yaml = ( + f"subsample_table: {os.path.basename(file_subannotation)}" + ) else: file_subannotation = "null" subanot_path_yaml = f"" @@ -1030,15 +1061,20 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): } for k, v in template_values.items(): placeholder = "{" + str(k) + "}" - # v1 = v.replace(':', '=') template = template.replace(placeholder, str(v)) if not self.just_object: # write annotation - self._write_gsm_annotation(metadata_dict_combined, file_annotation, use_key_subset=self.use_key_subset) + self._write_gsm_annotation( + metadata_dict_combined, + file_annotation, + use_key_subset=self.use_key_subset, + ) # write subannotation if len(subannotation_dict_combined) > 0: - self._write_subannotation(subannotation_dict_combined, file_subannotation) + self._write_subannotation( + subannotation_dict_combined, file_subannotation + ) # save .yaml file yaml_name = self.project_name + "_config.yaml" @@ -1051,13 +1087,11 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): self._create_dot_yaml(dot_yaml_path, yaml_name) else: - sddd = [metadata_dict_combined.values()] - sdddd = subannotation_dict_combined.values() - meta_df = pd.DataFrame.from_dict(metadata_dict_combined, orient='index') - - print(meta_df) + meta_df = pd.DataFrame.from_dict(metadata_dict_combined, orient="index") - sub_meta_df = pd.DataFrame.from_dict(subannotation_dict_combined, orient='index') + sub_meta_df = pd.DataFrame.from_dict( + subannotation_dict_combined, orient="index" + ) if sub_meta_df.empty: sub_meta_df = None conf = yaml.load(template, Loader=yaml.Loader) @@ -1130,7 +1164,7 @@ def _separate_common_meta( if first_key: if len(str(nb_sample[1][this_key])) <= del_limit: new_meta_project.append( - {this_key: f'\"{nb_sample[1][this_key]}\"'} + {this_key: f'"{nb_sample[1][this_key]}"'} ) first_key = False del meta_list[nb_sample[0]][this_key] @@ -1492,8 +1526,12 @@ def _get_list_of_processed_files( meta_processed_samples[nb]["files"].append(file_url_gsm) self._check_file_existance(meta_processed_samples) - meta_processed_samples = self._separate_list_of_files(meta_processed_samples) - meta_processed_samples = self._separate_file_url(meta_processed_samples) + meta_processed_samples = self._separate_list_of_files( + meta_processed_samples + ) + meta_processed_samples = self._separate_file_url( + meta_processed_samples + ) self._LOGGER.info( f"\nTotal number of processed SAMPLES files found is: " @@ -1509,9 +1547,13 @@ def _get_list_of_processed_files( ) if self.filter_re: - meta_processed_samples = self._run_filter(meta_processed_samples) + meta_processed_samples = self._run_filter( + meta_processed_samples + ) if self.filter_size: - meta_processed_samples = self._run_size_filter(meta_processed_samples) + meta_processed_samples = self._run_size_filter( + meta_processed_samples + ) # other files than .tar: saving them into meta_processed_series list else: @@ -1823,7 +1865,9 @@ def _get_SRP_list(self, srp_number: str) -> list: raise x.raise_for_status() id_results = x.json()["esearchresult"]["idlist"] if len(id_results) > 500: - id_results = [id_results[x:x + 100] for x in range(0, len(id_results), 100)] + id_results = [ + id_results[x : x + 100] for x in range(0, len(id_results), 100) + ] else: id_results = [id_results] @@ -1834,7 +1878,9 @@ def _get_SRP_list(self, srp_number: str) -> list: y = requests.get(id_api) if y.status_code != 200: - self._LOGGER.error(f"Error in ncbi efetch response in SRA fetching: {x.status_code}") + self._LOGGER.error( + f"Error in ncbi efetch response in SRA fetching: {x.status_code}" + ) raise y.raise_for_status() xml_result = y.text SRP_list.extend(xmltodict.parse(xml_result)["SraRunInfo"]["Row"]) @@ -2201,8 +2247,9 @@ def main(): args = _parse_cmdl(sys.argv[1:]) args_dict = vars(args) args_dict["args"] = args - #Geofetcher(**args_dict).fetch_all(args_dict["input"]) - Geofetcher(**args_dict).get_project(args_dict["input"]) + # Geofetcher(**args_dict).fetch_all(args_dict["input"]) + abc = Geofetcher(**args_dict).get_project(args_dict["input"]) + abc if __name__ == "__main__": diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index 6c227d9..4c8eeb8 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -248,7 +248,9 @@ def test_size_filter(self, meta_list, output, initiate_geofetcher): def test_large_meta_separation( self, init_meta_data, result_sample, result_proj, initiate_geofetcher ): - samp, proj = initiate_geofetcher._separate_common_meta(init_meta_data, max_len=0) + samp, proj = initiate_geofetcher._separate_common_meta( + init_meta_data, max_len=0 + ) assert samp == result_sample assert proj == result_proj From 27fdfc1ac22a3d6544fec192ebc5a56b7adb9980 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 22 Aug 2022 20:39:07 -0400 Subject: [PATCH 13/61] run corrections --- geofetch/geofetch.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index a65f40e..0fad630 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -2247,9 +2247,8 @@ def main(): args = _parse_cmdl(sys.argv[1:]) args_dict = vars(args) args_dict["args"] = args - # Geofetcher(**args_dict).fetch_all(args_dict["input"]) - abc = Geofetcher(**args_dict).get_project(args_dict["input"]) - abc + Geofetcher(**args_dict).fetch_all(args_dict["input"]) + if __name__ == "__main__": From ffa1fddcee92ebf538ba55501b7639a26781e0c1 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 23 Aug 2022 10:34:16 -0400 Subject: [PATCH 14/61] yaml regex fix --- geofetch/geofetch.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 0fad630..82b9906 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1163,8 +1163,10 @@ def _separate_common_meta( if this_key not in list_keys_diff: if first_key: if len(str(nb_sample[1][this_key])) <= del_limit: + new_str = nb_sample[1][this_key].replace('"', '') + new_str = re.sub('[^A-Za-z0-9]+', ' ', new_str) new_meta_project.append( - {this_key: f'"{nb_sample[1][this_key]}"'} + {this_key: f'"{new_str}"'} ) first_key = False del meta_list[nb_sample[0]][this_key] From 4b3ec7145ac4a6804c865e7b500cf022490231ed Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 24 Aug 2022 12:02:13 -0400 Subject: [PATCH 15/61] some changes to get_project() --- geofetch/geofetch.py | 81 ++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 82b9906..932e20f 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -56,7 +56,7 @@ def __init__( skip: int = 0, acc_anno: bool = False, use_key_subset: bool = False, - processed: bool = True, + processed: bool = False, data_source: str = "samples", filter: str = None, filter_size: str = None, @@ -174,51 +174,59 @@ def __init__( self._LOGGER.info(f"Metadata folder: {self.metadata_expanded}") - # check to make sure prefetch is callable - if not just_metadata and not processed: - if not is_command_callable("prefetch"): - raise SystemExit( - "To download raw data You must first install the sratoolkit, with prefetch in your PATH." - " Installation instruction: http://geofetch.databio.org/en/latest/install/" - ) - # Some sanity checks before proceeding if bam_conversion and not just_metadata and not self._which("samtools"): raise SystemExit("For SAM/BAM processing, samtools should be on PATH.") self.just_object = False - def get_project(self, input: str) -> Dict[peppy.Project]: + def get_project(self, input: str, just_metadata: bool = True, discard_soft: bool = True) -> Dict[peppy.Project]: """ Function for fetching projects from GEO|SRA and receiving peppy project :param input: GSE number, or path to file of GSE numbers + :param just_metadata: process only metadata + :param discard_soft: clean run, without downloading soft files :return: peppy project or list of project, if acc_anno is set. """ - self.just_metadata = True + self.just_metadata = just_metadata self.just_object = True self.disable_progressbar = True + self.discard_soft = discard_soft acc_GSE_list = parse_accessions( input, self.metadata_expanded, self.just_metadata ) project_dict = {} + # processed data: if self.processed: if self.acc_anno: + nkeys = len(acc_GSE_list.keys()) + ncount = 0 self.acc_anno = False for acc_GSE in acc_GSE_list.keys(): + ncount += 1 + self._LOGGER.info( + f"\033[38;5;200mProcessing accession {ncount} of {nkeys}: '{acc_GSE}'\033[0m" + ) project_dict.update(self.fetch_all(input=acc_GSE, name=acc_GSE)) - else: project_dict.update(self.fetch_all(input=input, name="project")) + # raw data: else: # Not sure about below code... if self.acc_anno: self.acc_anno = False + nkeys = len(acc_GSE_list.keys()) + ncount = 0 for acc_GSE in acc_GSE_list.keys(): + ncount += 1 + self._LOGGER.info( + f"\033[38;5;200mProcessing accession {ncount} of {nkeys}: '{acc_GSE}'\033[0m" + ) project_dict = self.fetch_all(input=input) - project_dict[acc_GSE + "_raw_samples"] = project_dict + project_dict[acc_GSE + "_raw"] = project_dict else: ser_dict = self.fetch_all(input=input) @@ -234,6 +242,14 @@ def fetch_all(self, input: str, name: str = None): else: self.project_name = os.path.splitext(os.path.basename(input))[0] + # check to make sure prefetch is callable + if not self.just_metadata and not self.processed: + if not is_command_callable("prefetch"): + raise SystemExit( + "To download raw data You must first install the sratoolkit, with prefetch in your PATH." + " Installation instruction: http://geofetch.databio.org/en/latest/install/" + ) + acc_GSE_list = parse_accessions( input, self.metadata_expanded, self.just_metadata ) @@ -264,9 +280,11 @@ def fetch_all(self, input: str, name: str = None): continue elif ncount == self.skip + 1: self._LOGGER.info(f"Skipped {self.skip} accessions. Starting now.") - self._LOGGER.info( - f"\033[38;5;200mProcessing accession {ncount} of {nkeys}: '{acc_GSE}'\033[0m" - ) + + if not self.just_object: + self._LOGGER.info( + f"\033[38;5;200mProcessing accession {ncount} of {nkeys}: '{acc_GSE}'\033[0m" + ) if len(re.findall(GSE_PATTERN, acc_GSE)) != 1: self._LOGGER.debug(len(re.findall(GSE_PATTERN, acc_GSE))) @@ -983,13 +1001,15 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): ): fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] - # sanitize sample names + # sanitize names fixed_dict[key_sample]["sample_name"] = self._sanitize_name( fixed_dict[key_sample]["sample_name"] ) metadata_dict[key] = fixed_dict + # TODO: should be checked: + # annotation table metadata_dict_combined = {} for acc_GSE, gsm_metadata in metadata_dict.items(): file_annotation = os.path.join( @@ -1001,6 +1021,19 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): ) metadata_dict_combined.update(gsm_metadata) + # subatnotation table + subannotation_dict_combined = {} + for acc_GSE, gsm_multi_table in subannotation_dict.items(): + file_subannotation = os.path.join( + self.metadata_expanded, acc_GSE + "_subannotation.csv" + ) + if self.acc_anno: + self._write_subannotation(gsm_multi_table, file_subannotation) + subannotation_dict_combined.update(gsm_multi_table) + + self._LOGGER.info( + "Creating complete project annotation sheets and config file..." + ) # filtering huge annotation strings that are repeating for each sample metadata_dict_combined, proj_meta = self._separate_common_meta( metadata_dict_combined, @@ -1013,17 +1046,6 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): ] modifiers_str = "\n ".join(d for d in meta_list_str) - subannotation_dict_combined = {} - for acc_GSE, gsm_multi_table in subannotation_dict.items(): - file_subannotation = os.path.join( - self.metadata_expanded, acc_GSE + "_subannotation.csv" - ) - if self.acc_anno: - self._write_subannotation(gsm_multi_table, file_subannotation) - subannotation_dict_combined.update(gsm_multi_table) - self._LOGGER.info( - "Creating complete project annotation sheets and config file..." - ) # If the project included more than one GSE, we can now output combined # annotation tables for the entire project. # Write combined annotation sheet @@ -1063,7 +1085,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): placeholder = "{" + str(k) + "}" template = template.replace(placeholder, str(v)) - if not self.just_object: + if not self.just_object and not self.acc_anno: # write annotation self._write_gsm_annotation( metadata_dict_combined, @@ -1089,6 +1111,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): else: meta_df = pd.DataFrame.from_dict(metadata_dict_combined, orient="index") + # TODO: correct error here: sub_meta_df = pd.DataFrame.from_dict( subannotation_dict_combined, orient="index" ) From 457f9aa789bb15f15b44afdd6c8fd4cb7198d201 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 25 Aug 2022 11:53:29 -0400 Subject: [PATCH 16/61] peppy init fix --- geofetch/geofetch.py | 95 +++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 932e20f..52264ae 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -from __future__ import annotations - __author__ = ["Oleksandr Khoroshevskyi", "Vince Reuter", "Nathan Sheffield"] import argparse @@ -180,7 +178,7 @@ def __init__( self.just_object = False - def get_project(self, input: str, just_metadata: bool = True, discard_soft: bool = True) -> Dict[peppy.Project]: + def get_project(self, input: str, just_metadata: bool = True, discard_soft: bool = True) -> Dict[peppy.Project, peppy.Project]: """ Function for fetching projects from GEO|SRA and receiving peppy project :param input: GSE number, or path to file of GSE numbers @@ -225,11 +223,11 @@ def get_project(self, input: str, just_metadata: bool = True, discard_soft: bool self._LOGGER.info( f"\033[38;5;200mProcessing accession {ncount} of {nkeys}: '{acc_GSE}'\033[0m" ) - project_dict = self.fetch_all(input=input) + project_dict = self.fetch_all(input=acc_GSE) project_dict[acc_GSE + "_raw"] = project_dict else: - ser_dict = self.fetch_all(input=input) + ser_dict = self.fetch_all(input=acc_GSE_list) project_dict["raw_samples"] = ser_dict return project_dict @@ -965,7 +963,8 @@ def _sanitize_name(name_str: str): :return: sanitized strings """ new_str = name_str - for odd_char in list(punctuation): + punctuation1 = r"""!"#$%&'()*,./:;<=>?@[\]^_`{|}~""" + for odd_char in list(punctuation1): new_str = new_str.replace(odd_char, "_") new_str = new_str.replace(" ", "_").replace("__", "_") return new_str @@ -1001,10 +1000,10 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): ): fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] - # sanitize names - fixed_dict[key_sample]["sample_name"] = self._sanitize_name( - fixed_dict[key_sample]["sample_name"] - ) + # # sanitize names + # fixed_dict[key_sample]["sample_name"] = self._sanitize_name( + # fixed_dict[key_sample]["sample_name"] + # ) metadata_dict[key] = fixed_dict @@ -1012,14 +1011,15 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): # annotation table metadata_dict_combined = {} for acc_GSE, gsm_metadata in metadata_dict.items(): + gsm_metadata1 = self._standardize_colnames(gsm_metadata) file_annotation = os.path.join( self.metadata_expanded, acc_GSE + "_annotation.csv" ) if self.acc_anno: self._write_gsm_annotation( - gsm_metadata, file_annotation, use_key_subset=self.use_key_subset + gsm_metadata1, file_annotation, use_key_subset=self.use_key_subset ) - metadata_dict_combined.update(gsm_metadata) + metadata_dict_combined.update(gsm_metadata1) # subatnotation table subannotation_dict_combined = {} @@ -1111,12 +1111,17 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): else: meta_df = pd.DataFrame.from_dict(metadata_dict_combined, orient="index") - # TODO: correct error here: - sub_meta_df = pd.DataFrame.from_dict( - subannotation_dict_combined, orient="index" - ) + # open list: + new_sub_list = [] + for sub_key in subannotation_dict_combined.keys(): + new_sub_list.extend([col_item for col_item in subannotation_dict_combined[sub_key]]) + + sub_meta_df = pd.DataFrame(new_sub_list, columns=["sample_name", "SRX", "SRR"]) + if sub_meta_df.empty: sub_meta_df = None + else: + sub_meta_df = [sub_meta_df] conf = yaml.load(template, Loader=yaml.Loader) proj = peppy.Project().from_pandas(meta_df, sub_meta_df, conf) @@ -1133,7 +1138,7 @@ def _create_dot_yaml(file_path: str, yaml_path: str): file.writelines(f"config_file: {yaml_path}") def _separate_common_meta( - self, meta_list, max_len=50, del_limit=250, attr_limit_truncate=500 + self, meta_list: Union[List, Dict], max_len: int = 50, del_limit: int = 250, attr_limit_truncate: int = 500 ): """ This function is separating information for the experiment from a sample @@ -1145,16 +1150,11 @@ def _separate_common_meta( list of samples metadata dictionaries and 2: list of common samples metadata dictionaries that are linked to the project. """ + # check if meta_list is dict and converting it to list input_is_dict = False if isinstance(meta_list, dict): input_is_dict = True - new_meta_list = [] - for key in meta_list: - new_dict = meta_list[key] - new_dict["big_key"] = key - new_meta_list.append(new_dict) - - meta_list = new_meta_list + meta_list = self._dict_to_list_convector(proj_dict=meta_list) list_of_keys = self._get_list_of_keys(meta_list) list_keys_diff = [] @@ -1210,11 +1210,7 @@ def _separate_common_meta( meta_list = new_list if input_is_dict: - new_sample_dict = {} - for sample in meta_list: - new_sample_dict[sample["big_key"]] = sample - meta_list = new_sample_dict - + meta_list = self._dict_to_list_convector(proj_list=meta_list) return meta_list, new_meta_project def _standardize_colnames(self, meta_list): @@ -1223,6 +1219,12 @@ def _standardize_colnames(self, meta_list): :param list meta_list: list of dictionaries of samples :return : list of dictionaries of samples with standard colnames """ + # check if meta_list is dict and converting it to list + input_is_dict = False + if isinstance(meta_list, dict): + input_is_dict = True + meta_list = self._dict_to_list_convector(proj_dict=meta_list) + new_metalist = [] list_keys = self._get_list_of_keys(meta_list) for item_nb, values in enumerate(meta_list): @@ -1237,8 +1239,39 @@ def _standardize_colnames(self, meta_list): except KeyError: pass + if input_is_dict: + new_metalist = self._dict_to_list_convector(proj_list=new_metalist) + return new_metalist + @staticmethod + def _dict_to_list_convector(proj_dict: Dict = None, proj_list: List = None) -> Union[Dict, List]: + """ + Convector project dict to list and vice versa + :param proj_dict: project dictionary + :param proj_list: project list + :return: converted values + """ + if proj_dict is not None: + new_meta_list = [] + for key in proj_dict: + new_dict = proj_dict[key] + new_dict["big_key"] = key + new_meta_list.append(new_dict) + + meta_list = new_meta_list + + elif proj_list is not None: + new_sample_dict = {} + for sample in proj_list: + new_sample_dict[sample["big_key"]] = sample + meta_list = new_sample_dict + + else: + raise ValueError + + return meta_list + def _download_SRA_file(self, run_name): """ Downloading SRA file by ising 'prefetch' utility from the SRA Toolkit @@ -1633,14 +1666,14 @@ def _separate_list_of_files(meta_list, col_name="files"): into two different dicts """ separated_list = [] - if type(meta_list) == list: + if isinstance(meta_list, list): for meta_elem in meta_list: for file_elem in meta_elem[col_name]: new_dict = meta_elem.copy() new_dict.pop(col_name, None) new_dict["file"] = file_elem separated_list.append(new_dict) - elif type(meta_list) == dict: + elif isinstance(meta_list, dict): for file_elem in meta_list[col_name]: new_dict = meta_list.copy() new_dict.pop(col_name, None) From c8a3b8df34f084a85a8982201911ea9e5ad11fdc Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 26 Aug 2022 14:17:27 -0400 Subject: [PATCH 17/61] test fixed --- geofetch/geofetch.py | 54 +++++++++++++++++++++++++++++------------- tests/test_geofetch.py | 14 ++++++++--- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 52264ae..db6d415 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -178,7 +178,9 @@ def __init__( self.just_object = False - def get_project(self, input: str, just_metadata: bool = True, discard_soft: bool = True) -> Dict[peppy.Project, peppy.Project]: + def get_project( + self, input: str, just_metadata: bool = True, discard_soft: bool = True + ) -> Dict[peppy.Project, peppy.Project]: """ Function for fetching projects from GEO|SRA and receiving peppy project :param input: GSE number, or path to file of GSE numbers @@ -223,8 +225,8 @@ def get_project(self, input: str, just_metadata: bool = True, discard_soft: bool self._LOGGER.info( f"\033[38;5;200mProcessing accession {ncount} of {nkeys}: '{acc_GSE}'\033[0m" ) - project_dict = self.fetch_all(input=acc_GSE) - project_dict[acc_GSE + "_raw"] = project_dict + project = self.fetch_all(input=acc_GSE) + project_dict[acc_GSE + "_raw"] = project else: ser_dict = self.fetch_all(input=acc_GSE_list) @@ -999,7 +1001,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): or value_sample["sample_name"] is None ): fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] - + # TODO: should be corrected: # # sanitize names # fixed_dict[key_sample]["sample_name"] = self._sanitize_name( # fixed_dict[key_sample]["sample_name"] @@ -1007,7 +1009,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): metadata_dict[key] = fixed_dict - # TODO: should be checked: + # annotation table metadata_dict_combined = {} for acc_GSE, gsm_metadata in metadata_dict.items(): @@ -1015,6 +1017,7 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): file_annotation = os.path.join( self.metadata_expanded, acc_GSE + "_annotation.csv" ) + # for each sample if self.acc_anno: self._write_gsm_annotation( gsm_metadata1, file_annotation, use_key_subset=self.use_key_subset @@ -1027,10 +1030,13 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): file_subannotation = os.path.join( self.metadata_expanded, acc_GSE + "_subannotation.csv" ) + # for each sample: if self.acc_anno: self._write_subannotation(gsm_multi_table, file_subannotation) subannotation_dict_combined.update(gsm_multi_table) + # TODO: were is .yaml file for each acc_anno? + self._LOGGER.info( "Creating complete project annotation sheets and config file..." ) @@ -1114,9 +1120,13 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): # open list: new_sub_list = [] for sub_key in subannotation_dict_combined.keys(): - new_sub_list.extend([col_item for col_item in subannotation_dict_combined[sub_key]]) + new_sub_list.extend( + [col_item for col_item in subannotation_dict_combined[sub_key]] + ) - sub_meta_df = pd.DataFrame(new_sub_list, columns=["sample_name", "SRX", "SRR"]) + sub_meta_df = pd.DataFrame( + new_sub_list, columns=["sample_name", "SRX", "SRR"] + ) if sub_meta_df.empty: sub_meta_df = None @@ -1138,7 +1148,11 @@ def _create_dot_yaml(file_path: str, yaml_path: str): file.writelines(f"config_file: {yaml_path}") def _separate_common_meta( - self, meta_list: Union[List, Dict], max_len: int = 50, del_limit: int = 250, attr_limit_truncate: int = 500 + self, + meta_list: Union[List, Dict], + max_len: int = 50, + del_limit: int = 250, + attr_limit_truncate: int = 500, ): """ This function is separating information for the experiment from a sample @@ -1186,11 +1200,11 @@ def _separate_common_meta( if this_key not in list_keys_diff: if first_key: if len(str(nb_sample[1][this_key])) <= del_limit: - new_str = nb_sample[1][this_key].replace('"', '') - new_str = re.sub('[^A-Za-z0-9]+', ' ', new_str) - new_meta_project.append( - {this_key: f'"{new_str}"'} - ) + new_str = nb_sample[1][this_key] + if isinstance(nb_sample[1][this_key], str): + new_str = nb_sample[1][this_key].replace('"', "") + new_str = re.sub("[^A-Za-z0-9]+", " ", new_str) + new_meta_project.append({this_key: new_str}) first_key = False del meta_list[nb_sample[0]][this_key] except KeyError: @@ -1245,7 +1259,9 @@ def _standardize_colnames(self, meta_list): return new_metalist @staticmethod - def _dict_to_list_convector(proj_dict: Dict = None, proj_list: List = None) -> Union[Dict, List]: + def _dict_to_list_convector( + proj_dict: Dict = None, proj_list: List = None + ) -> Union[Dict, List]: """ Convector project dict to list and vice versa :param proj_dict: project dictionary @@ -1522,13 +1538,18 @@ def _get_list_of_processed_files( self.metadata_expanded, gse_numb + "_file_list.txt" ) + # TODO: make new function of code below: if not os.path.isfile(filelist_path) or self.refresh_metadata: result = requests.get(tar_files_list_url) if result.ok: filelist_raw_text = result.text if not self.discard_soft: - with open(filelist_path, "w") as f: - f.write(filelist_raw_text) + try: + with open(filelist_path, "w") as f: + f.write(filelist_raw_text) + except OSError: + self._LOGGER.warning(f"{filelist_path} not found. File won't be saved..") + else: raise Exception(f"error in requesting tar_files_list") else: @@ -2308,7 +2329,6 @@ def main(): Geofetcher(**args_dict).fetch_all(args_dict["input"]) - if __name__ == "__main__": try: sys.exit(main()) diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index 4c8eeb8..d26cbb1 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -1,3 +1,4 @@ +import geofetch from geofetch import parse_accessions, Geofetcher, utils import os import pytest @@ -15,6 +16,7 @@ def get_soft_path(gse_numb, sample_len, series_len): run test test_file_list """ return ( + gse_numb, os.path.join(GSE_FILES, gse_numb, GSE_SOFT_NAME), os.path.join(GSE_FILES, gse_numb, GSM_SOFT_NAME), sample_len, @@ -75,15 +77,21 @@ def initiate_geofetcher(self, tmpdir): yield instance @pytest.mark.parametrize( - "soft_gse, soft_gsm, sample_len, series_len", processed_meta_file_test + "gse_numb,soft_gse, soft_gsm, sample_len, series_len", processed_meta_file_test ) def test_file_list( - self, soft_gse, soft_gsm, sample_len, series_len, initiate_geofetcher + self, gse_numb, soft_gse, soft_gsm, sample_len, series_len, initiate_geofetcher ): + file_gse_content = geofetch.Accession(gse_numb).fetch_metadata( + soft_gse, typename="GSE", clean=False + ) + file_gsm_content = geofetch.Accession(gse_numb).fetch_metadata( + soft_gsm, typename="GSM", clean=False + ) ( meta_processed_samples, meta_processed_series, - ) = initiate_geofetcher._get_list_of_processed_files(soft_gse, soft_gsm) + ) = initiate_geofetcher._get_list_of_processed_files(file_gse_content, file_gsm_content) assert len(meta_processed_samples) == sample_len assert len(meta_processed_series) == series_len From a63558926b36666ff1025fdad573a09f5e8a0eec Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 26 Aug 2022 14:26:33 -0400 Subject: [PATCH 18/61] lint --- geofetch/geofetch.py | 5 +++-- requirements/requirements-all.txt | 2 +- tests/test_geofetch.py | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index db6d415..860876c 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1009,7 +1009,6 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): metadata_dict[key] = fixed_dict - # annotation table metadata_dict_combined = {} for acc_GSE, gsm_metadata in metadata_dict.items(): @@ -1548,7 +1547,9 @@ def _get_list_of_processed_files( with open(filelist_path, "w") as f: f.write(filelist_raw_text) except OSError: - self._LOGGER.warning(f"{filelist_path} not found. File won't be saved..") + self._LOGGER.warning( + f"{filelist_path} not found. File won't be saved.." + ) else: raise Exception(f"error in requesting tar_files_list") diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index 06cc825..f8a0182 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -7,6 +7,6 @@ logmuse>=0.2.7 ubiquerg>=0.6.0 requests>=2.28.1 xmltodict>=0.13.0 -pandas>=1.4.3 +pandas>=1.3.5 peppy>=0.34.0 rich>=12.5.1 diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index d26cbb1..f9e268b 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -91,7 +91,9 @@ def test_file_list( ( meta_processed_samples, meta_processed_series, - ) = initiate_geofetcher._get_list_of_processed_files(file_gse_content, file_gsm_content) + ) = initiate_geofetcher._get_list_of_processed_files( + file_gse_content, file_gsm_content + ) assert len(meta_processed_samples) == sample_len assert len(meta_processed_series) == series_len From 0bedaf96f2ccce1ffd23c9a57f6349a62c7fb470 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 26 Aug 2022 14:42:19 -0400 Subject: [PATCH 19/61] fixed test --- geofetch/geofetch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 860876c..ab1d817 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -643,7 +643,7 @@ def fetch_all(self, input: str, name: str = None): if self.supp_by == "all": supp_sample_path_meta = os.path.join( self.metadata_raw, - "s", + "PEP_samples", self.project_name + SAMPLE_SUPP_METADATA_FILE, ) peppy_obj_samples = self._write_processed_annotation( From f4d5adabc5e395afd2ea2e1eac34ade9e6dc2f0c Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 26 Aug 2022 15:08:22 -0400 Subject: [PATCH 20/61] added changelog --- docs/changelog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 2adcd81..89bcb72 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,12 @@ # Changelog +## [0.11.0] -- 2022-XX-XX +- Added initialization of peppy Project without saving any files functionality +- Added progress bar +- Fixed None issue in config file +- Changed way of saving soft files to request library +- + ## [0.10.1] -- 2022-08-04 - Updated metadata fetching requests from SRA database From 3e690fd84def3b0c381c31b0855eda99cd168a61 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 26 Aug 2022 16:45:15 -0400 Subject: [PATCH 21/61] added corrections to PR --- geofetch/geofetch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index ab1d817..0655838 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -63,7 +63,7 @@ def __init__( bam_folder: str = "", fq_folder: str = "", sra_folder: str = "", - bam_conversion=False, + bam_conversion: bool = False, picard_path: str = "", input: str = None, const_limit_project: int = 50, @@ -180,7 +180,7 @@ def __init__( def get_project( self, input: str, just_metadata: bool = True, discard_soft: bool = True - ) -> Dict[peppy.Project, peppy.Project]: + ) -> Dict[str, peppy.Project]: """ Function for fetching projects from GEO|SRA and receiving peppy project :param input: GSE number, or path to file of GSE numbers From 655ade122f6fe13711ebc7669ed347784cb6b7ec Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 26 Aug 2022 16:56:29 -0400 Subject: [PATCH 22/61] added encoding-UTF-8 to requests --- geofetch/geofetch.py | 2 ++ geofetch/utils.py | 1 + 2 files changed, 3 insertions(+) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 0655838..b54eb08 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1541,6 +1541,7 @@ def _get_list_of_processed_files( if not os.path.isfile(filelist_path) or self.refresh_metadata: result = requests.get(tar_files_list_url) if result.ok: + result.encoding = "UTF-8" filelist_raw_text = result.text if not self.discard_soft: try: @@ -1941,6 +1942,7 @@ def _get_SRP_list(self, srp_number: str) -> list: x = requests.post(ncbi_esearch) if x.status_code != 200: + x.encoding = "UTF-8" self._LOGGER.error(f"Error in ncbi esearch response: {x.status_code}") raise x.raise_for_status() id_results = x.json()["esearchresult"]["idlist"] diff --git a/geofetch/utils.py b/geofetch/utils.py index f3f97ff..99735b7 100644 --- a/geofetch/utils.py +++ b/geofetch/utils.py @@ -202,6 +202,7 @@ def fetch_metadata( result = requests.get(full_url) if result.ok: + result.encoding = "UTF-8" result_text = result.text result_list = result_text.replace("\r", "").split("\n") result_list = [elem for elem in result_list if len(elem) > 0] From 93f84b048e6f5a76e29227a5acf34c130257611c Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 29 Aug 2022 13:35:42 -0400 Subject: [PATCH 23/61] Refactored processed functions --- geofetch/const.py | 2 + geofetch/geofetch.py | 557 +++++++++++++++++++++---------------------- 2 files changed, 279 insertions(+), 280 deletions(-) diff --git a/geofetch/const.py b/geofetch/const.py index 6bc0ff4..aa727d0 100644 --- a/geofetch/const.py +++ b/geofetch/const.py @@ -39,3 +39,5 @@ NCBI_ESEARCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=sra&term={SRP_NUMBER}&retmax=999&rettype=uilist&retmode=json" NCBI_EFETCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=sra&id={ID}&rettype=runinfo&retmode=xml" + +NEW_GENOME_COL_NAME = "ref_genome" \ No newline at end of file diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index b54eb08..49b16ff 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -17,9 +17,9 @@ # import tarfile import time -from ._version import __version__ -from .const import * -from .utils import ( +from _version import __version__ +from const import * +from utils import ( Accession, parse_accessions, parse_SOFT_line, @@ -31,7 +31,7 @@ import logmuse from ubiquerg import expandpath, is_command_callable from io import StringIO -from typing import List, Union, Dict +from typing import List, Union, Dict, Tuple, NoReturn import peppy import pandas as pd @@ -42,38 +42,38 @@ class Geofetcher: """ def __init__( - self, - name: str = "", - metadata_root: str = "", - metadata_folder: str = "", - just_metadata: bool = False, - refresh_metadata: bool = False, - config_template: str = None, - pipeline_samples: str = None, - pipeline_project: str = None, - skip: int = 0, - acc_anno: bool = False, - use_key_subset: bool = False, - processed: bool = False, - data_source: str = "samples", - filter: str = None, - filter_size: str = None, - geo_folder: str = ".", - split_experiments: bool = False, - bam_folder: str = "", - fq_folder: str = "", - sra_folder: str = "", - bam_conversion: bool = False, - picard_path: str = "", - input: str = None, - const_limit_project: int = 50, - const_limit_discard: int = 250, - attr_limit_truncate: int = 500, - discard_soft: bool = False, - add_dotfile: bool = False, - disable_progressbar: bool = False, - opts=None, - **kwargs, + self, + name: str = "", + metadata_root: str = "", + metadata_folder: str = "", + just_metadata: bool = False, + refresh_metadata: bool = False, + config_template: str = None, + pipeline_samples: str = None, + pipeline_project: str = None, + skip: int = 0, + acc_anno: bool = False, + use_key_subset: bool = False, + processed: bool = False, + data_source: str = "samples", + filter: str = None, + filter_size: str = None, + geo_folder: str = ".", + split_experiments: bool = False, + bam_folder: str = "", + fq_folder: str = "", + sra_folder: str = "", + bam_conversion: bool = False, + picard_path: str = "", + input: str = None, + const_limit_project: int = 50, + const_limit_discard: int = 250, + attr_limit_truncate: int = 500, + discard_soft: bool = False, + add_dotfile: bool = False, + disable_progressbar: bool = False, + opts=None, + **kwargs, ): if opts is not None: @@ -179,7 +179,7 @@ def __init__( self.just_object = False def get_project( - self, input: str, just_metadata: bool = True, discard_soft: bool = True + self, input: str, just_metadata: bool = True, discard_soft: bool = True ) -> Dict[str, peppy.Project]: """ Function for fetching projects from GEO|SRA and receiving peppy project @@ -264,15 +264,15 @@ def fetch_all(self, input: str, name: str = None): subannotation_dict = {} failed_runs = [] processed_metadata_samples = [] - processed_metadata_exp = [] + processed_metadata_series = [] acc_GSE_keys = acc_GSE_list.keys() nkeys = len(acc_GSE_keys) ncount = 0 for acc_GSE in track( - acc_GSE_list.keys(), - description="Processing... ", - disable=self.disable_progressbar, + acc_GSE_list.keys(), + description="Processing... ", + disable=self.disable_progressbar, ): ncount += 1 @@ -298,9 +298,6 @@ def fetch_all(self, input: str, name: str = None): f"Limit to: {list(acc_GSE_list[acc_GSE])}" ) # a list of GSM#s - if self.refresh_metadata: - self._LOGGER.info("Refreshing metadata...") - # For each GSE acc, produce a series of metadata files file_gse = os.path.join(self.metadata_expanded, acc_GSE + "_GSE.soft") file_gsm = os.path.join(self.metadata_expanded, acc_GSE + "_GSM.soft") @@ -333,128 +330,26 @@ def fetch_all(self, input: str, name: str = None): # download processed data if self.processed: - # try: - ( - meta_processed_samples, - meta_processed_series, - ) = self._get_list_of_processed_files( - file_gse_content, file_gsm_content - ) - - # taking into account list of GSM that is specified in the input file gsm_list = acc_GSE_list[acc_GSE] - meta_processed_samples = self._filter_gsm( - meta_processed_samples, gsm_list - ) - # Unify keys: - meta_processed_samples = self._unify_list_keys(meta_processed_samples) - meta_processed_series = self._unify_list_keys(meta_processed_series) - - # samples - list_of_keys = self._get_list_of_keys(meta_processed_samples) - self._LOGGER.info("Expanding metadata list...") - for key_in_list in list_of_keys: - meta_processed_samples = self._expand_metadata_list( - meta_processed_samples, key_in_list - ) + meta_processed_samples, meta_processed_series = self.fetch_processed_one(acc_gse=acc_GSE, + gse_file_content=file_gse_content, + gsm_file_content=file_gsm_content, + gsm_filter_list=gsm_list) - # series - list_of_keys_series = self._get_list_of_keys(meta_processed_series) - self._LOGGER.info("Expanding metadata list...") - for key_in_list in list_of_keys_series: - meta_processed_series = self._expand_metadata_list( - meta_processed_series, key_in_list - ) + # download processed files: + if not self.just_metadata: + self._download_processed_data(acc_gse=acc_GSE, meta_processed_samples=meta_processed_samples, + meta_processed_series=meta_processed_series) - # convert column names to lowercase and underscore - meta_processed_samples = self._standardize_colnames( - meta_processed_samples - ) - meta_processed_series = self._standardize_colnames( - meta_processed_series - ) + # generating PEPs for processed files: + if self.acc_anno: + self._generate_processed_meta(acc_GSE, meta_processed_samples, meta_processed_series) - if not self.acc_anno: + else: # adding metadata from current experiment to the project processed_metadata_samples.extend(meta_processed_samples) - processed_metadata_exp.extend(meta_processed_series) - - # save PEP for each accession if acc-anno flag is true - if self.acc_anno and len(acc_GSE_list.keys()) > 1: - if self.supp_by == "all": - # samples - pep_acc_path_sample = os.path.join( - self.metadata_raw, - f"{acc_GSE}_samples", - acc_GSE + SAMPLE_SUPP_METADATA_FILE, - ) - self._write_processed_annotation( - meta_processed_samples, pep_acc_path_sample - ) - - # series - pep_acc_path_exp = os.path.join( - self.metadata_raw, - f"{acc_GSE}_series", - acc_GSE + EXP_SUPP_METADATA_FILE, - ) - self._write_processed_annotation( - meta_processed_series, pep_acc_path_exp - ) - elif self.supp_by == "samples": - pep_acc_path_sample = os.path.join( - self.metadata_raw, - f"{acc_GSE}_samples", - acc_GSE + SAMPLE_SUPP_METADATA_FILE, - ) - self._write_processed_annotation( - meta_processed_samples, pep_acc_path_sample - ) - elif self.supp_by == "series": - pep_acc_path_exp = os.path.join( - self.metadata_raw, - f"{acc_GSE}_series", - acc_GSE + EXP_SUPP_METADATA_FILE, - ) - self._write_processed_annotation( - meta_processed_series, pep_acc_path_exp - ) - - if not self.just_metadata: - data_geo_folder = os.path.join(self.geo_folder, acc_GSE) - self._LOGGER.debug("Data folder: " + data_geo_folder) - - if self.supp_by == "all": - processed_samples_files = [ - each_file["file_url"] - for each_file in meta_processed_samples - ] - for file_url in processed_samples_files: - self._download_processed_file(file_url, data_geo_folder) - - processed_series_files = [ - each_file["file_url"] for each_file in meta_processed_series - ] - for file_url in processed_series_files: - self._download_processed_file(file_url, data_geo_folder) + processed_metadata_series.extend(meta_processed_series) - elif self.supp_by == "samples": - processed_samples_files = [ - each_file["file_url"] - for each_file in meta_processed_samples - ] - for file_url in processed_samples_files: - self._download_processed_file(file_url, data_geo_folder) - - elif self.supp_by == "series": - processed_series_files = [ - each_file["file_url"] for each_file in meta_processed_series - ] - for file_url in processed_series_files: - self._download_processed_file(file_url, data_geo_folder) - # except Exception as processed_exception: - # failed_runs.append(acc_GSE) - # self._LOGGER.warning(f"Error occurred: {processed_exception}") else: # download gsm metadata @@ -622,7 +517,11 @@ def fetch_all(self, input: str, name: str = None): # accumulate subannotations subannotation_dict[acc_GSE] = gsm_multi_table - # Logging additional information about processing + if len(failed_runs) > 0: + self._LOGGER.warn( + f"The following samples could not be downloaded: {failed_runs}" + ) + self._LOGGER.info(f"Finished processing {len(acc_GSE_list)} accession(s)") # Logging cleaning process: @@ -630,67 +529,16 @@ def fetch_all(self, input: str, name: str = None): self._LOGGER.info(f"Cleaning soft files ...") clean_soft_files(self.metadata_raw) - if len(failed_runs) > 0: - self._LOGGER.warn( - f"The following samples could not be downloaded: {failed_runs}" - ) - ####################################################################################### # saving PEPs for processed data if self.processed: if not self.acc_anno: - if self.supp_by == "all": - supp_sample_path_meta = os.path.join( - self.metadata_raw, - "PEP_samples", - self.project_name + SAMPLE_SUPP_METADATA_FILE, - ) - peppy_obj_samples = self._write_processed_annotation( - processed_metadata_samples, supp_sample_path_meta - ) - - supp_series_path_meta = os.path.join( - self.metadata_raw, - "PEP_series", - self.project_name + EXP_SUPP_METADATA_FILE, - ) - peppy_obj_series = self._write_processed_annotation( - processed_metadata_exp, supp_series_path_meta - ) - - if self.just_object: - return { - f"{name}_samples": peppy_obj_samples, - f"{name}_series": peppy_obj_series, - } - - elif self.supp_by == "samples": - supp_sample_path_meta = os.path.join( - self.metadata_raw, - "PEP_samples", - self.project_name + SAMPLE_SUPP_METADATA_FILE, - ) - peppy_obj = self._write_processed_annotation( - processed_metadata_samples, supp_sample_path_meta - ) - if self.just_object: - return {f"{name}_samples": peppy_obj} - - elif self.supp_by == "series": - supp_series_path_meta = os.path.join( - self.metadata_raw, - "PEP_series", - self.project_name + EXP_SUPP_METADATA_FILE, - ) - peppy_obj = self._write_processed_annotation( - processed_metadata_exp, supp_series_path_meta - ) - if self.just_object: - return {f"{name}_PEP_series": peppy_obj} - - else: - return None + return_value = self._generate_processed_meta(name="PEP_processed", + meta_processed_samples=processed_metadata_samples, + meta_processed_series=processed_metadata_series) + if self.just_object: + return return_value # saving PEPs for raw data else: @@ -698,14 +546,159 @@ def fetch_all(self, input: str, name: str = None): if self.just_object: return return_value - def _expand_metadata_list(self, metadata_list, dict_key): + def fetch_processed_one(self, acc_gse: str, gse_file_content: list, gsm_file_content: list, + gsm_filter_list: dict) -> Tuple: + """ + Fetching just one processed GSE project + :param acc_gse: GSE number + :param gsm_file_content: gse soft file content + :param gse_file_content: gsm soft file content + :param gsm_filter_list: list of gsm that have to be downloaded + :return: Tuple of project list of gsm samples and gse samples + """ + ( + meta_processed_samples, + meta_processed_series, + ) = self._get_list_of_processed_files( + gse_file_content, gsm_file_content + ) + + # taking into account list of GSM that is specified in the input file + meta_processed_samples = self._filter_gsm( + meta_processed_samples, gsm_filter_list + ) + # # Unify keys: -- probably we don't need this + # meta_processed_samples = self._unify_list_keys(meta_processed_samples) + # meta_processed_series = self._unify_list_keys(meta_processed_series) + + # samples + meta_processed_samples = self._expand_metadata_list(meta_processed_samples) + + # series + meta_processed_series = self._expand_metadata_list(meta_processed_series) + + # convert column names to lowercase and underscore + meta_processed_samples = self._standardize_colnames( + meta_processed_samples + ) + meta_processed_series = self._standardize_colnames( + meta_processed_series + ) + + return meta_processed_samples, meta_processed_series + + + def _generate_processed_meta(self, name: str, meta_processed_samples: list, meta_processed_series: list) -> dict: + """ + Generate and save PEPs for processed accessions. GEO has data in GSE and GSM, + conditions are used to decide which PEPs have to be saved. + :param name: name of the folder/file where PEP will be saved + :param meta_processed_samples: + :param meta_processed_series: + :return: dict of objects if just_object is set, otherwise dicts of None """ - Expanding list items in the list by creating new items or joining them + return_objects = {f"{name}_samples": None, + f"{name}_series": None} + + if self.supp_by == "all": + # samples + pep_acc_path_sample = os.path.join( + self.metadata_raw, + f"{name}_samples", + name + SAMPLE_SUPP_METADATA_FILE, + ) + return_objects[f"{name}_samples"] = self._write_processed_annotation( + meta_processed_samples, pep_acc_path_sample, just_object=self.just_object, + ) + + # series + pep_acc_path_exp = os.path.join( + self.metadata_raw, + f"{name}_series", + name + EXP_SUPP_METADATA_FILE, + ) + return_objects[f"{name}_series"] = self._write_processed_annotation( + meta_processed_series, pep_acc_path_exp, just_object=self.just_object, + ) + + elif self.supp_by == "samples": + pep_acc_path_sample = os.path.join( + self.metadata_raw, + f"{name}_samples", + name + SAMPLE_SUPP_METADATA_FILE, + ) + return_objects[f"{name}_samples"] = self._write_processed_annotation( + meta_processed_samples, pep_acc_path_sample, just_object=self.just_object, + ) + elif self.supp_by == "series": + return_objects[f"{name}_series"] = pep_acc_path_exp = os.path.join( + self.metadata_raw, + f"{name}_series", + name + EXP_SUPP_METADATA_FILE, + ) + self._write_processed_annotation( + meta_processed_series, pep_acc_path_exp, just_object=self.just_object, + ) + + return return_objects + + def _download_processed_data(self, acc_gse: str, meta_processed_samples: list, + meta_processed_series: list) -> NoReturn: + data_geo_folder = os.path.join(self.geo_folder, acc_gse) + self._LOGGER.debug("Data folder: " + data_geo_folder) + + if self.supp_by == "all": + processed_samples_files = [ + each_file["file_url"] + for each_file in meta_processed_samples + ] + for file_url in processed_samples_files: + self._download_processed_file(file_url, data_geo_folder) + + processed_series_files = [ + each_file["file_url"] for each_file in meta_processed_series + ] + for file_url in processed_series_files: + self._download_processed_file(file_url, data_geo_folder) + + elif self.supp_by == "samples": + processed_samples_files = [ + each_file["file_url"] + for each_file in meta_processed_samples + ] + for file_url in processed_samples_files: + self._download_processed_file(file_url, data_geo_folder) + + elif self.supp_by == "series": + processed_series_files = [ + each_file["file_url"] for each_file in meta_processed_series + ] + for file_url in processed_series_files: + self._download_processed_file(file_url, data_geo_folder) + + def _expand_metadata_list(self, metadata_list: list) -> list: + """ + Expanding all lists of all items in the list by creating new items or joining them :param list metadata_list: list of dicts that store metadata - :param str dict_key: key in the dictionaries that have to be expanded + :return list: expanded metadata list + """ + self._LOGGER.info("Expanding metadata list...") + list_of_keys = self._get_list_of_keys(metadata_list) + for key_in_list in list_of_keys: + metadata_list = self._expand_metadata_list_item( + metadata_list, key_in_list + ) + return metadata_list - :return str: path to file written + def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): + """ + Expanding list of one element (item) in the list by creating new items or joining them + ["first1: fff", ...] -> separate columns + + :param list metadata_list: list of dicts that store metadata + :param str dict_key: key in the dictionaries that have to be expanded + :return list: expanded metadata list """ try: element_is_list = any( @@ -760,14 +753,14 @@ def _expand_metadata_list(self, metadata_list, dict_key): return metadata_list else: self._LOGGER.debug( - "metadata with %s was not expanded, as item is not list" % dict_key + f"Metadata with {dict_key} was not expanded, as item is not list" ) return metadata_list except KeyError as err: - self._LOGGER.warning("Key Error: %s" % err) + self._LOGGER.warning(f"expand_metadata_list: Key Error: {err}") return metadata_list - except ValueError as err1: - self._LOGGER.warning("Value Error: %s" % err1) + except ValueError as err: + self._LOGGER.warning("expand_metadata_list: Value Error: {err}") return metadata_list def _filter_gsm(self, meta_processed_samples: list, gsm_list: dict) -> list: @@ -800,7 +793,6 @@ def _get_list_of_keys(list_of_dict): Getting list of all keys that are in the dictionaries in the list :param list list_of_dict: list of dicts with metadata - :return list: list of dictionary keys """ @@ -815,7 +807,6 @@ def _unify_list_keys(self, processed_meta_list): same keys :param list processed_meta_list: list of dicts with metadata - :return str: list of unified dicts with metadata """ list_of_keys = self._get_list_of_keys(processed_meta_list) @@ -840,11 +831,11 @@ def _find_genome(self, metadata_list): sample_genome = "" for key in proj_gen_keys: sample_genome = " ".join([sample_genome, sample[1][key]]) - metadata_list[sample[0]]["sample_genome"] = sample_genome + metadata_list[sample[0]][NEW_GENOME_COL_NAME] = sample_genome return metadata_list def _write_gsm_annotation( - self, gsm_metadata, file_annotation, use_key_subset=False + self, gsm_metadata, file_annotation, use_key_subset=False ): """ Write metadata sheet out as an annotation file. @@ -873,11 +864,13 @@ def _write_gsm_annotation( self._LOGGER.info("\033[92mFile has been saved successfully\033[0m") return fp - def _write_processed_annotation(self, processed_metadata, file_annotation_path): + def _write_processed_annotation(self, processed_metadata: list, file_annotation_path: str, just_object: bool = False) -> Union[NoReturn, peppy.Project]: """ Saving annotation file by providing list of dictionaries with files metadata :param list processed_metadata: list of dictionaries with files metadata :param str file_annotation_path: the path to the metadata file that has to be saved + :type just_object: True, if you want to get peppy object without saving file + :return: """ if len(processed_metadata) == 0: self._LOGGER.info( @@ -928,7 +921,7 @@ def _write_processed_annotation(self, processed_metadata, file_annotation_path): placeholder = "{" + str(k) + "}" template = template.replace(placeholder, str(v)) - if not self.just_object: + if not just_object: with open(file_annotation_path, "w") as m_file: dict_writer = csv.DictWriter(m_file, processed_metadata[0].keys()) dict_writer.writeheader() @@ -997,8 +990,8 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): for key_sample, value_sample in value.items(): fixed_dict[key_sample] = value_sample if ( - value_sample["sample_name"] == "" - or value_sample["sample_name"] is None + value_sample["sample_name"] == "" + or value_sample["sample_name"] is None ): fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] # TODO: should be corrected: @@ -1147,11 +1140,11 @@ def _create_dot_yaml(file_path: str, yaml_path: str): file.writelines(f"config_file: {yaml_path}") def _separate_common_meta( - self, - meta_list: Union[List, Dict], - max_len: int = 50, - del_limit: int = 250, - attr_limit_truncate: int = 500, + self, + meta_list: Union[List, Dict], + max_len: int = 50, + del_limit: int = 250, + attr_limit_truncate: int = 500, ): """ This function is separating information for the experiment from a sample @@ -1259,7 +1252,7 @@ def _standardize_colnames(self, meta_list): @staticmethod def _dict_to_list_convector( - proj_dict: Dict = None, proj_list: List = None + proj_dict: Dict = None, proj_list: List = None ) -> Union[Dict, List]: """ Convector project dict to list and vice versa @@ -1350,10 +1343,10 @@ def _sra_bam_conversion(self, bam_file, run_name): # The -u here allows unaligned reads, and seems to be # required for some sra files regardless of aligned state cmd = ( - "sam-dump -u " - + os.path.join(self.sra_folder, run_name + ".sra") - + " | samtools view -bS - > " - + bam_file + "sam-dump -u " + + os.path.join(self.sra_folder, run_name + ".sra") + + " | samtools view -bS - > " + + bam_file ) # sam-dump -u SRR020515.sra | samtools view -bS - > test.bam @@ -1416,10 +1409,10 @@ def _sra_bam_conversion2(self, bam_file, run_name, picard_path=None): # check to make sure it worked cmd = ( - "fastq-dump --split-3 -O " - + os.path.realpath(self.sra_folder) - + " " - + os.path.join(self.sra_folder, run_name + ".sra") + "fastq-dump --split-3 -O " + + os.path.realpath(self.sra_folder) + + " " + + os.path.join(self.sra_folder, run_name + ".sra") ) self._LOGGER.info(f"Command: {cmd}") run_subprocess(cmd, shell=True) @@ -1500,7 +1493,7 @@ def _download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): self._LOGGER.info(f"\033[38;5;242mFile {full_filepath} exists.\033[0m") def _get_list_of_processed_files( - self, file_gse_content: list, file_gsm_content: list + self, file_gse_content: list, file_gsm_content: list ): """ Given a paths to GSE and GSM metafile create a list of dicts of metadata of processed files @@ -1530,7 +1523,7 @@ def _get_list_of_processed_files( # find and download filelist - file with information about files in tar index = file_url.rfind("/") tar_files_list_url = ( - "https" + file_url[3 : index + 1] + "filelist.txt" + "https" + file_url[3: index + 1] + "filelist.txt" ) # file_list_name filelist_path = os.path.join( @@ -1575,14 +1568,14 @@ def _get_list_of_processed_files( element_values = list(pl.values())[0] if not re.findall(SUPP_FILE_PATTERN, line_gsm): if ( - element_keys - not in meta_processed_samples[nb].keys() + element_keys + not in meta_processed_samples[nb].keys() ): meta_processed_samples[nb].update(pl) else: if ( - type(meta_processed_samples[nb][element_keys]) - is not list + type(meta_processed_samples[nb][element_keys]) + is not list ): meta_processed_samples[nb][element_keys] = [ meta_processed_samples[nb][element_keys] @@ -1792,7 +1785,11 @@ def _read_tar_filelist(raw_text: str): return files_info @staticmethod - def _get_value(all_line): + def _get_value(all_line: str): + """ + :param all_line: string with key value. (e.g. '!Series_geo_accession = GSE188720') + :return: value (e.g. GSE188720) + """ line_value = all_line.split("= ")[-1] return line_value.split(": ")[-1].rstrip("\n") @@ -1948,7 +1945,7 @@ def _get_SRP_list(self, srp_number: str) -> list: id_results = x.json()["esearchresult"]["idlist"] if len(id_results) > 500: id_results = [ - id_results[x : x + 100] for x in range(0, len(id_results), 100) + id_results[x: x + 100] for x in range(0, len(id_results), 100) ] else: id_results = [id_results] @@ -1994,8 +1991,8 @@ def _get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): if line[0] == "^": pl = parse_SOFT_line(line) if ( - len(acc_GSE_list[acc_GSE]) > 0 - and pl["SAMPLE"] not in GSM_limit_list + len(acc_GSE_list[acc_GSE]) > 0 + and pl["SAMPLE"] not in GSM_limit_list ): # sys.stdout.write(" Skipping " + a['SAMPLE'] + ".") current_sample_id = None @@ -2082,16 +2079,16 @@ def _parse_cmdl(cmdl): dest="metadata_root", default=safe_echo("SRAMETA"), help="Specify a parent folder location to store metadata. " - "The project name will be added as a subfolder " - "[Default: $SRAMETA:" + safe_echo("SRAMETA") + "]", + "The project name will be added as a subfolder " + "[Default: $SRAMETA:" + safe_echo("SRAMETA") + "]", ) parser.add_argument( "-u", "--metadata-folder", help="Specify an absolute folder location to store metadata. " - "No subfolder will be added. Overrides value of --metadata-root " - "[Default: Not used (--metadata-root is used by default)]", + "No subfolder will be added. Overrides value of --metadata-root " + "[Default: Not used (--metadata-root is used by default)]", ) parser.add_argument( @@ -2116,8 +2113,8 @@ def _parse_cmdl(cmdl): "--pipeline-samples", default=None, help="Optional: Specify one or more filepaths to SAMPLES pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", ) # Optional @@ -2125,8 +2122,8 @@ def _parse_cmdl(cmdl): "--pipeline-project", default=None, help="Optional: Specify one or more filepaths to PROJECT pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", ) # Optional parser.add_argument( @@ -2148,7 +2145,7 @@ def _parse_cmdl(cmdl): "--acc-anno", action="store_true", help="Optional: Produce annotation sheets for each accession." - " Project combined PEP for the whole project won't be produced.", + " Project combined PEP for the whole project won't be produced.", ) parser.add_argument( @@ -2162,7 +2159,7 @@ def _parse_cmdl(cmdl): type=int, default=50, help="Optional: Limit of the number of the constant sample characters " - "that should not be in project yaml. [Default: 50]", + "that should not be in project yaml. [Default: 50]", ) parser.add_argument( @@ -2170,7 +2167,7 @@ def _parse_cmdl(cmdl): type=int, default=250, help="Optional: Limit of the number of the constant sample characters " - "that should not be discarded [Default: 250]", + "that should not be discarded [Default: 250]", ) parser.add_argument( @@ -2178,8 +2175,8 @@ def _parse_cmdl(cmdl): type=int, default=500, help="Optional: Limit of the number of sample characters." - "Any attribute with more than X characters will truncate to the first X," - " where X is a number of characters [Default: 500]", + "Any attribute with more than X characters will truncate to the first X," + " where X is a number of characters [Default: 500]", ) parser.add_argument( @@ -2202,17 +2199,17 @@ def _parse_cmdl(cmdl): choices=["all", "samples", "series"], default="samples", help="Optional: Specifies the source of data on the GEO record" - " to retrieve processed data, which may be attached to the" - " collective series entity, or to individual samples. " - "Allowable values are: samples, series or both (all). " - "Ignored unless 'processed' flag is set. [Default: samples]", + " to retrieve processed data, which may be attached to the" + " collective series entity, or to individual samples. " + "Allowable values are: samples, series or both (all). " + "Ignored unless 'processed' flag is set. [Default: samples]", ) processed_group.add_argument( "--filter", default=None, help="Optional: Filter regex for processed filenames [Default: None]." - "Ignored unless 'processed' flag is set.", + "Ignored unless 'processed' flag is set.", ) processed_group.add_argument( @@ -2231,8 +2228,8 @@ def _parse_cmdl(cmdl): "--geo-folder", default=safe_echo("GEODATA"), help="Optional: Specify a location to store processed GEO files." - " Ignored unless 'processed' flag is set." - "[Default: $GEODATA:" + safe_echo("GEODATA") + "]", + " Ignored unless 'processed' flag is set." + "[Default: $GEODATA:" + safe_echo("GEODATA") + "]", ) raw_group.add_argument( @@ -2254,8 +2251,8 @@ def _parse_cmdl(cmdl): help="""Optional: Specify folder of bam files. Geofetch will not download sra files when corresponding bam files already exist. [Default: $SRABAM:""" - + safe_echo("SRABAM") - + "]", + + safe_echo("SRABAM") + + "]", ) raw_group.add_argument( @@ -2266,8 +2263,8 @@ def _parse_cmdl(cmdl): help="""Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding fastq files already exist. [Default: $SRAFQ:""" - + safe_echo("SRAFQ") - + "]", + + safe_echo("SRAFQ") + + "]", ) # Deprecated; these are for bam conversion which now happens in sra_convert From d940a99d3dbb2278006f737b923a6d24f5a13b41 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 29 Aug 2022 21:57:11 -0400 Subject: [PATCH 24/61] Refactored raw functions 1 --- geofetch/const.py | 2 +- geofetch/geofetch.py | 687 +++++++++++++++++++++-------------------- tests/test_geofetch.py | 12 +- 3 files changed, 354 insertions(+), 347 deletions(-) diff --git a/geofetch/const.py b/geofetch/const.py index aa727d0..01d1e05 100644 --- a/geofetch/const.py +++ b/geofetch/const.py @@ -40,4 +40,4 @@ NCBI_ESEARCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=sra&term={SRP_NUMBER}&retmax=999&rettype=uilist&retmode=json" NCBI_EFETCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=sra&id={ID}&rettype=runinfo&retmode=xml" -NEW_GENOME_COL_NAME = "ref_genome" \ No newline at end of file +NEW_GENOME_COL_NAME = "ref_genome" diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 49b16ff..5fee104 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -17,9 +17,9 @@ # import tarfile import time -from _version import __version__ -from const import * -from utils import ( +from ._version import __version__ +from .const import * +from .utils import ( Accession, parse_accessions, parse_SOFT_line, @@ -42,38 +42,38 @@ class Geofetcher: """ def __init__( - self, - name: str = "", - metadata_root: str = "", - metadata_folder: str = "", - just_metadata: bool = False, - refresh_metadata: bool = False, - config_template: str = None, - pipeline_samples: str = None, - pipeline_project: str = None, - skip: int = 0, - acc_anno: bool = False, - use_key_subset: bool = False, - processed: bool = False, - data_source: str = "samples", - filter: str = None, - filter_size: str = None, - geo_folder: str = ".", - split_experiments: bool = False, - bam_folder: str = "", - fq_folder: str = "", - sra_folder: str = "", - bam_conversion: bool = False, - picard_path: str = "", - input: str = None, - const_limit_project: int = 50, - const_limit_discard: int = 250, - attr_limit_truncate: int = 500, - discard_soft: bool = False, - add_dotfile: bool = False, - disable_progressbar: bool = False, - opts=None, - **kwargs, + self, + name: str = "", + metadata_root: str = "", + metadata_folder: str = "", + just_metadata: bool = False, + refresh_metadata: bool = False, + config_template: str = None, + pipeline_samples: str = None, + pipeline_project: str = None, + skip: int = 0, + acc_anno: bool = False, + use_key_subset: bool = False, + processed: bool = False, + data_source: str = "samples", + filter: str = None, + filter_size: str = None, + geo_folder: str = ".", + split_experiments: bool = False, + bam_folder: str = "", + fq_folder: str = "", + sra_folder: str = "", + bam_conversion: bool = False, + picard_path: str = "", + input: str = None, + const_limit_project: int = 50, + const_limit_discard: int = 250, + attr_limit_truncate: int = 500, + discard_soft: bool = False, + add_dotfile: bool = False, + disable_progressbar: bool = False, + opts=None, + **kwargs, ): if opts is not None: @@ -179,8 +179,8 @@ def __init__( self.just_object = False def get_project( - self, input: str, just_metadata: bool = True, discard_soft: bool = True - ) -> Dict[str, peppy.Project]: + self, input: str, just_metadata: bool = True, discard_soft: bool = True + ) -> dict: """ Function for fetching projects from GEO|SRA and receiving peppy project :param input: GSE number, or path to file of GSE numbers @@ -254,15 +254,9 @@ def fetch_all(self, input: str, name: str = None): input, self.metadata_expanded, self.just_metadata ) - # Loop through each accession. - # This will process that accession, produce metadata and download files for - # the GSM #s included in the list for each GSE#. - # acc_GSE = "GSE61150" # example - - # This loop populates a list of metadata. metadata_dict = {} subannotation_dict = {} - failed_runs = [] + processed_metadata_samples = [] processed_metadata_series = [] @@ -270,9 +264,9 @@ def fetch_all(self, input: str, name: str = None): nkeys = len(acc_GSE_keys) ncount = 0 for acc_GSE in track( - acc_GSE_list.keys(), - description="Processing... ", - disable=self.disable_progressbar, + acc_GSE_list.keys(), + description="Processing... ", + disable=self.disable_progressbar, ): ncount += 1 @@ -303,11 +297,6 @@ def fetch_all(self, input: str, name: str = None): file_gsm = os.path.join(self.metadata_expanded, acc_GSE + "_GSM.soft") file_sra = os.path.join(self.metadata_expanded, acc_GSE + "_SRA.csv") - # Grab the GSE and GSM SOFT files from GEO. - # The GSE file has metadata describing the experiment, which includes - # The SRA number we need to download the raw data from SRA - # The GSM file has metadata describing each sample, which we will use to - # produce a sample annotation sheet. if not os.path.isfile(file_gse) or self.refresh_metadata: file_gse_content = Accession(acc_GSE).fetch_metadata( file_gse, clean=self.discard_soft @@ -328,200 +317,75 @@ def fetch_all(self, input: str, name: str = None): file_gsm_content = gsm_file_obj.read().split("\n") file_gsm_content = [elem for elem in file_gsm_content if len(elem) > 0] + gsm_enter_dict = acc_GSE_list[acc_GSE] + # download processed data if self.processed: - gsm_list = acc_GSE_list[acc_GSE] - meta_processed_samples, meta_processed_series = self.fetch_processed_one(acc_gse=acc_GSE, - gse_file_content=file_gse_content, - gsm_file_content=file_gsm_content, - gsm_filter_list=gsm_list) + ( + meta_processed_samples, + meta_processed_series, + ) = self.fetch_processed_one( + gse_file_content=file_gse_content, + gsm_file_content=file_gsm_content, + gsm_filter_list=gsm_enter_dict, + ) # download processed files: if not self.just_metadata: - self._download_processed_data(acc_gse=acc_GSE, meta_processed_samples=meta_processed_samples, - meta_processed_series=meta_processed_series) + self._download_processed_data( + acc_gse=acc_GSE, + meta_processed_samples=meta_processed_samples, + meta_processed_series=meta_processed_series, + ) # generating PEPs for processed files: if self.acc_anno: - self._generate_processed_meta(acc_GSE, meta_processed_samples, meta_processed_series) + self._generate_processed_meta( + acc_GSE, meta_processed_samples, meta_processed_series + ) else: # adding metadata from current experiment to the project processed_metadata_samples.extend(meta_processed_samples) processed_metadata_series.extend(meta_processed_series) - else: - # download gsm metadata - gsm_metadata = self._get_gsm_metadata( + # read gsm metadata + gsm_metadata = self._read_gsm_metadata( acc_GSE, acc_GSE_list, file_gsm_content ) - metadata_dict[acc_GSE] = gsm_metadata - # download gsm metadata - SRP_list_result = self._get_SRA_meta( + # download sra metadata + srp_list_result = self._get_SRA_meta( file_gse_content, gsm_metadata, file_sra ) - if not SRP_list_result: + if not srp_list_result: + self._LOGGER.info(f"No SRP data, continuing ....") # delete current acc if no raw data was found # del metadata_dict[acc_GSE] continue - # Parse metadata from SRA - # Produce an annotated output from the GSM and SRARunInfo files. - # This will merge the GSM and SRA sample metadata into a dict of dicts, - # with one entry per sample. - # NB: There may be multiple SRA Runs (and thus lines in the RunInfo file) - # Corresponding to each sample. - # For multi samples (samples with multiple runs), we keep track of these - # relations in a separate table, which is called the subannotation table. - - gsm_multi_table = {} - self._LOGGER.info("Parsing SRA file to download SRR records") - - for line in SRP_list_result: - - # Only download if it's in the include list: - experiment = line["Experiment"] - run_name = line["Run"] - if experiment not in gsm_metadata: - # print(f"Skipping: {experiment}") - continue - - # local convenience variable - # possibly set in the input tsv file - sample_name = None # initialize to empty - try: - sample_name = acc_GSE_list[acc_GSE][ - gsm_metadata[experiment]["gsm_id"] - ] - except KeyError: - self._LOGGER.info( - f"sample_name does not exist, creating new..." - ) - if not sample_name or sample_name == "": - temp = gsm_metadata[experiment]["Sample_title"] - sample_name = self._sanitize_name(temp) - - # Otherwise, record that there's SRA data for this run. - # And set a few columns that are used as input to the Looper - # print("Updating columns for looper") - self._update_columns( - gsm_metadata, - experiment, - sample_name=sample_name, - read_type=line["LibraryLayout"], - ) - - # Some experiments are flagged in SRA as having multiple runs. - if gsm_metadata[experiment].get("SRR") is not None: - # This SRX number already has an entry in the table. - self._LOGGER.info( - f"Found additional run: {run_name} ({experiment})" - ) - - if ( - isinstance(gsm_metadata[experiment]["SRR"], str) - and experiment not in gsm_multi_table - ): - # Only one has been stuck in so far, make a list - gsm_multi_table[experiment] = [] - # Add first the original one, which was stored as a string - # previously - gsm_multi_table[experiment].append( - [ - sample_name, - experiment, - gsm_metadata[experiment]["SRR"], - ] - ) - # Now append the current SRR number in a list as [SRX, SRR] - gsm_multi_table[experiment].append( - [sample_name, experiment, run_name] - ) - else: - # this is the 3rd or later sample; the first two are done, - # so just add it. - gsm_multi_table[experiment].append( - [sample_name, experiment, run_name] - ) - - if self.split_experiments: - # Duplicate the gsm metadata for this experiment (copy to make sure - # it's not just an alias). - rep_number = len(gsm_multi_table[experiment]) - new_SRX = experiment + "_" + str(rep_number) - gsm_metadata[new_SRX] = copy.copy(gsm_metadata[experiment]) - # gsm_metadata[new_SRX]["SRX"] = new_SRX - gsm_metadata[new_SRX]["sample_name"] += "_" + str( - rep_number - ) - gsm_metadata[new_SRX]["SRR"] = run_name - else: - # Either way, set the srr code to multi in the main table. - gsm_metadata[experiment]["SRR"] = "multi" - else: - # The first SRR for this SRX is added to GSM metadata - gsm_metadata[experiment]["SRR"] = run_name - - self._LOGGER.info(f"Getting SRR: {run_name} ({experiment})") - bam_file = ( - "" - if self.bam_folder == "" - else os.path.join(self.bam_folder, run_name + ".bam") - ) - fq_file = ( - "" - if self.fq_folder == "" - else os.path.join(self.fq_folder, run_name + "_1.fq") + else: + self._LOGGER.info("Parsing SRA file to download SRR records") + gsm_multi_table = self._process_sra_meta( + srp_list_result, gsm_enter_dict, gsm_metadata ) - # TODO: sam-dump has a built-in prefetch. I don't have to do - # any of this stuff... This also solves the bad sam-dump issues. - - if os.path.exists(bam_file): - self._LOGGER.info(f"BAM found: {bam_file} . Skipping...") - elif os.path.exists(fq_file): - self._LOGGER.info(f"FQ found: {fq_file} .Skipping...") - else: - if not self.just_metadata: - try: - self._download_SRA_file(run_name) - except Exception as err: - failed_runs.append(run_name) - self._LOGGER.warning( - f"Error occurred while downloading SRA file: {err}" - ) - else: - self._LOGGER.info("Dry run (no raw data will be download)") - - if self.bam_conversion and self.bam_folder != "": - try: - # converting sra to bam using - self._sra_bam_conversion(bam_file, run_name) - - # checking if bam_file converted correctly, if not --> use fastq-dump - st = os.stat(bam_file) - if st.st_size < 100: - self._LOGGER.warning( - "Bam conversion failed with sam-dump. Trying fastq-dump..." - ) - self._sra_bam_conversion2( - bam_file, run_name, self.picard_path - ) - - except FileNotFoundError as err: + # download raw data: + if not self.just_metadata: + for file_key in gsm_multi_table.keys(): + for run in gsm_multi_table[file_key]: + # download raw data self._LOGGER.info( - f"SRA file doesn't exist, please download it first: {err}" + f"Getting SRR: {run[2]} in ({acc_GSE})" ) + self._download_raw_data(run[2]) + else: + self._LOGGER.info(f"Dry run, no data will be downloaded") # accumulate subannotations + metadata_dict[acc_GSE] = gsm_metadata subannotation_dict[acc_GSE] = gsm_multi_table - if len(failed_runs) > 0: - self._LOGGER.warn( - f"The following samples could not be downloaded: {failed_runs}" - ) - self._LOGGER.info(f"Finished processing {len(acc_GSE_list)} accession(s)") # Logging cleaning process: @@ -534,9 +398,11 @@ def fetch_all(self, input: str, name: str = None): # saving PEPs for processed data if self.processed: if not self.acc_anno: - return_value = self._generate_processed_meta(name="PEP_processed", - meta_processed_samples=processed_metadata_samples, - meta_processed_series=processed_metadata_series) + return_value = self._generate_processed_meta( + name="PEP_processed", + meta_processed_samples=processed_metadata_samples, + meta_processed_series=processed_metadata_series, + ) if self.just_object: return return_value @@ -546,11 +412,130 @@ def fetch_all(self, input: str, name: str = None): if self.just_object: return return_value - def fetch_processed_one(self, acc_gse: str, gse_file_content: list, gsm_file_content: list, - gsm_filter_list: dict) -> Tuple: + def _process_sra_meta(self, srp_list_result, gsm_enter_dict, gsm_metadata): + gsm_multi_table = {} + for line in srp_list_result: + + # Only download if it's in the include list: + experiment = line["Experiment"] + run_name = line["Run"] + if experiment not in gsm_metadata: + # print(f"Skipping: {experiment}") + continue + + sample_name = None + try: + sample_name = gsm_enter_dict[gsm_metadata[experiment]["gsm_id"]] + except KeyError: + # No name in input file + pass + + if not sample_name or sample_name == "": + temp = gsm_metadata[experiment]["Sample_title"] + sample_name = self._sanitize_name(temp) + + # Otherwise, record that there's SRA data for this run. + # And set a few columns that are used as input to the Looper + # print("Updating columns for looper") + self._update_columns( + gsm_metadata, + experiment, + sample_name=sample_name, + read_type=line["LibraryLayout"], + ) + + # Some experiments are flagged in SRA as having multiple runs. + if gsm_metadata[experiment].get("SRR") is not None: + # This SRX number already has an entry in the table. + self._LOGGER.debug(f"Found additional run: {run_name} ({experiment})") + if ( + isinstance(gsm_metadata[experiment]["SRR"], str) + and experiment not in gsm_multi_table + ): + gsm_multi_table[experiment] = [] + + gsm_multi_table[experiment].append( + [ + sample_name, + experiment, + gsm_metadata[experiment]["SRR"], + ] + ) + gsm_multi_table[experiment].append( + [sample_name, experiment, run_name] + ) + else: + gsm_multi_table[experiment].append( + [sample_name, experiment, run_name] + ) + + if self.split_experiments: + rep_number = len(gsm_multi_table[experiment]) + new_SRX = experiment + "_" + str(rep_number) + gsm_metadata[new_SRX] = copy.copy(gsm_metadata[experiment]) + # gsm_metadata[new_SRX]["SRX"] = new_SRX + gsm_metadata[new_SRX]["sample_name"] += "_" + str(rep_number) + gsm_metadata[new_SRX]["SRR"] = run_name + else: + # Either way, set the srr code to multi in the main table. + gsm_metadata[experiment]["SRR"] = "multi" + else: + # The first SRR for this SRX is added to GSM metadata + gsm_metadata[experiment]["SRR"] = run_name + return gsm_multi_table + + def _download_raw_data(self, run_name): + bam_file = ( + "" + if self.bam_folder == "" + else os.path.join(self.bam_folder, run_name + ".bam") + ) + fq_file = ( + "" + if self.fq_folder == "" + else os.path.join(self.fq_folder, run_name + "_1.fq") + ) + + if os.path.exists(bam_file): + self._LOGGER.info(f"BAM found: {bam_file} . Skipping...") + elif os.path.exists(fq_file): + self._LOGGER.info(f"FQ found: {fq_file} .Skipping...") + else: + try: + self._download_SRA_file(run_name) + except Exception as err: + self._LOGGER.warning( + f"Error occurred while downloading SRA file: {err}" + ) + + if self.bam_conversion and self.bam_folder != "": + try: + # converting sra to bam using + # TODO: sam-dump has a built-in prefetch. I don't have to do + # any of this stuff... This also solves the bad sam-dump issues. + self._sra_bam_conversion(bam_file, run_name) + + # checking if bam_file converted correctly, if not --> use fastq-dump + st = os.stat(bam_file) + if st.st_size < 100: + self._LOGGER.warning( + "Bam conversion failed with sam-dump. Trying fastq-dump..." + ) + self._sra_bam_conversion2(bam_file, run_name, self.picard_path) + + except FileNotFoundError as err: + self._LOGGER.info( + f"SRA file doesn't exist, please download it first: {err}" + ) + + def fetch_processed_one( + self, + gse_file_content: list, + gsm_file_content: list, + gsm_filter_list: dict, + ) -> Tuple: """ Fetching just one processed GSE project - :param acc_gse: GSE number :param gsm_file_content: gse soft file content :param gse_file_content: gsm soft file content :param gsm_filter_list: list of gsm that have to be downloaded @@ -559,17 +544,12 @@ def fetch_processed_one(self, acc_gse: str, gse_file_content: list, gsm_file_con ( meta_processed_samples, meta_processed_series, - ) = self._get_list_of_processed_files( - gse_file_content, gsm_file_content - ) + ) = self._get_list_of_processed_files(gse_file_content, gsm_file_content) # taking into account list of GSM that is specified in the input file meta_processed_samples = self._filter_gsm( meta_processed_samples, gsm_filter_list ) - # # Unify keys: -- probably we don't need this - # meta_processed_samples = self._unify_list_keys(meta_processed_samples) - # meta_processed_series = self._unify_list_keys(meta_processed_series) # samples meta_processed_samples = self._expand_metadata_list(meta_processed_samples) @@ -578,17 +558,14 @@ def fetch_processed_one(self, acc_gse: str, gse_file_content: list, gsm_file_con meta_processed_series = self._expand_metadata_list(meta_processed_series) # convert column names to lowercase and underscore - meta_processed_samples = self._standardize_colnames( - meta_processed_samples - ) - meta_processed_series = self._standardize_colnames( - meta_processed_series - ) + meta_processed_samples = self._standardize_colnames(meta_processed_samples) + meta_processed_series = self._standardize_colnames(meta_processed_series) return meta_processed_samples, meta_processed_series - - def _generate_processed_meta(self, name: str, meta_processed_samples: list, meta_processed_series: list) -> dict: + def _generate_processed_meta( + self, name: str, meta_processed_samples: list, meta_processed_series: list + ) -> dict: """ Generate and save PEPs for processed accessions. GEO has data in GSE and GSM, conditions are used to decide which PEPs have to be saved. @@ -597,8 +574,7 @@ def _generate_processed_meta(self, name: str, meta_processed_samples: list, meta :param meta_processed_series: :return: dict of objects if just_object is set, otherwise dicts of None """ - return_objects = {f"{name}_samples": None, - f"{name}_series": None} + return_objects = {f"{name}_samples": None, f"{name}_series": None} if self.supp_by == "all": # samples @@ -608,7 +584,9 @@ def _generate_processed_meta(self, name: str, meta_processed_samples: list, meta name + SAMPLE_SUPP_METADATA_FILE, ) return_objects[f"{name}_samples"] = self._write_processed_annotation( - meta_processed_samples, pep_acc_path_sample, just_object=self.just_object, + meta_processed_samples, + pep_acc_path_sample, + just_object=self.just_object, ) # series @@ -618,7 +596,9 @@ def _generate_processed_meta(self, name: str, meta_processed_samples: list, meta name + EXP_SUPP_METADATA_FILE, ) return_objects[f"{name}_series"] = self._write_processed_annotation( - meta_processed_series, pep_acc_path_exp, just_object=self.just_object, + meta_processed_series, + pep_acc_path_exp, + just_object=self.just_object, ) elif self.supp_by == "samples": @@ -628,7 +608,9 @@ def _generate_processed_meta(self, name: str, meta_processed_samples: list, meta name + SAMPLE_SUPP_METADATA_FILE, ) return_objects[f"{name}_samples"] = self._write_processed_annotation( - meta_processed_samples, pep_acc_path_sample, just_object=self.just_object, + meta_processed_samples, + pep_acc_path_sample, + just_object=self.just_object, ) elif self.supp_by == "series": return_objects[f"{name}_series"] = pep_acc_path_exp = os.path.join( @@ -637,20 +619,22 @@ def _generate_processed_meta(self, name: str, meta_processed_samples: list, meta name + EXP_SUPP_METADATA_FILE, ) self._write_processed_annotation( - meta_processed_series, pep_acc_path_exp, just_object=self.just_object, + meta_processed_series, + pep_acc_path_exp, + just_object=self.just_object, ) return return_objects - def _download_processed_data(self, acc_gse: str, meta_processed_samples: list, - meta_processed_series: list) -> NoReturn: + def _download_processed_data( + self, acc_gse: str, meta_processed_samples: list, meta_processed_series: list + ) -> NoReturn: data_geo_folder = os.path.join(self.geo_folder, acc_gse) self._LOGGER.debug("Data folder: " + data_geo_folder) if self.supp_by == "all": processed_samples_files = [ - each_file["file_url"] - for each_file in meta_processed_samples + each_file["file_url"] for each_file in meta_processed_samples ] for file_url in processed_samples_files: self._download_processed_file(file_url, data_geo_folder) @@ -663,8 +647,7 @@ def _download_processed_data(self, acc_gse: str, meta_processed_samples: list, elif self.supp_by == "samples": processed_samples_files = [ - each_file["file_url"] - for each_file in meta_processed_samples + each_file["file_url"] for each_file in meta_processed_samples ] for file_url in processed_samples_files: self._download_processed_file(file_url, data_geo_folder) @@ -676,6 +659,11 @@ def _download_processed_data(self, acc_gse: str, meta_processed_samples: list, for file_url in processed_series_files: self._download_processed_file(file_url, data_geo_folder) + def _expand_metadata_list_in_dict(self, metadata_dict: dict) -> dict: + prj_list = self._dict_to_list_convector(proj_dict=metadata_dict) + prj_list = self._expand_metadata_list(prj_list) + return self._dict_to_list_convector(proj_list=prj_list) + def _expand_metadata_list(self, metadata_list: list) -> list: """ Expanding all lists of all items in the list by creating new items or joining them @@ -686,9 +674,7 @@ def _expand_metadata_list(self, metadata_list: list) -> list: self._LOGGER.info("Expanding metadata list...") list_of_keys = self._get_list_of_keys(metadata_list) for key_in_list in list_of_keys: - metadata_list = self._expand_metadata_list_item( - metadata_list, key_in_list - ) + metadata_list = self._expand_metadata_list_item(metadata_list, key_in_list) return metadata_list def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): @@ -706,49 +692,52 @@ def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): ) if element_is_list: for n_elem in range(len(metadata_list)): - if type(metadata_list[n_elem][dict_key]) is not list: - metadata_list[n_elem][dict_key] = [ - metadata_list[n_elem][dict_key] - ] - - just_string = False - this_string = "" - for elem in metadata_list[n_elem][dict_key]: - separated_elements = elem.split(": ") - if len(separated_elements) >= 2: - - # if first element is larger than 40 then treat it like simple string - if len(separated_elements[0]) > 40: - just_string = True - if this_string != "": - this_string = ", ".join([this_string, elem]) + try: + if type(metadata_list[n_elem][dict_key]) is not list: + metadata_list[n_elem][dict_key] = [ + metadata_list[n_elem][dict_key] + ] + + just_string = False + this_string = "" + for elem in metadata_list[n_elem][dict_key]: + separated_elements = elem.split(": ") + if len(separated_elements) >= 2: + + # if first element is larger than 40 then treat it like simple string + if len(separated_elements[0]) > 40: + just_string = True + if this_string != "": + this_string = ", ".join([this_string, elem]) + else: + this_string = elem + # additional elem for all bed files + elif len(separated_elements[0].split("(")) > 1: + just_string = True + if this_string != "": + this_string = "(".join([this_string, elem]) + else: + this_string = elem else: - this_string = elem - # additional elem for all bed files - elif len(separated_elements[0].split("(")) > 1: + list_of_elem = [ + separated_elements[0], + ": ".join(separated_elements[1:]), + ] + sample_char = dict([list_of_elem]) + metadata_list[n_elem].update(sample_char) + else: just_string = True if this_string != "": - this_string = "(".join([this_string, elem]) + this_string = ", ".join([this_string, elem]) else: this_string = elem - else: - list_of_elem = [ - separated_elements[0], - ": ".join(separated_elements[1:]), - ] - sample_char = dict([list_of_elem]) - metadata_list[n_elem].update(sample_char) - else: - just_string = True - if this_string != "": - this_string = ", ".join([this_string, elem]) - else: - this_string = elem - if just_string: - metadata_list[n_elem][dict_key] = this_string - else: - del metadata_list[n_elem][dict_key] + if just_string: + metadata_list[n_elem][dict_key] = this_string + else: + del metadata_list[n_elem][dict_key] + except KeyError as err: + self._LOGGER.warning(f"expand_metadata_list: Key Error: {err}") return metadata_list else: @@ -835,7 +824,7 @@ def _find_genome(self, metadata_list): return metadata_list def _write_gsm_annotation( - self, gsm_metadata, file_annotation, use_key_subset=False + self, gsm_metadata, file_annotation, use_key_subset=False ): """ Write metadata sheet out as an annotation file. @@ -864,7 +853,12 @@ def _write_gsm_annotation( self._LOGGER.info("\033[92mFile has been saved successfully\033[0m") return fp - def _write_processed_annotation(self, processed_metadata: list, file_annotation_path: str, just_object: bool = False) -> Union[NoReturn, peppy.Project]: + def _write_processed_annotation( + self, + processed_metadata: list, + file_annotation_path: str, + just_object: bool = False, + ) -> Union[NoReturn, peppy.Project]: """ Saving annotation file by providing list of dictionaries with files metadata :param list processed_metadata: list of dictionaries with files metadata @@ -990,8 +984,8 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): for key_sample, value_sample in value.items(): fixed_dict[key_sample] = value_sample if ( - value_sample["sample_name"] == "" - or value_sample["sample_name"] is None + value_sample["sample_name"] == "" + or value_sample["sample_name"] is None ): fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] # TODO: should be corrected: @@ -1140,11 +1134,11 @@ def _create_dot_yaml(file_path: str, yaml_path: str): file.writelines(f"config_file: {yaml_path}") def _separate_common_meta( - self, - meta_list: Union[List, Dict], - max_len: int = 50, - del_limit: int = 250, - attr_limit_truncate: int = 500, + self, + meta_list: Union[List, Dict], + max_len: int = 50, + del_limit: int = 250, + attr_limit_truncate: int = 500, ): """ This function is separating information for the experiment from a sample @@ -1252,7 +1246,7 @@ def _standardize_colnames(self, meta_list): @staticmethod def _dict_to_list_convector( - proj_dict: Dict = None, proj_list: List = None + proj_dict: Dict = None, proj_list: List = None ) -> Union[Dict, List]: """ Convector project dict to list and vice versa @@ -1343,10 +1337,10 @@ def _sra_bam_conversion(self, bam_file, run_name): # The -u here allows unaligned reads, and seems to be # required for some sra files regardless of aligned state cmd = ( - "sam-dump -u " - + os.path.join(self.sra_folder, run_name + ".sra") - + " | samtools view -bS - > " - + bam_file + "sam-dump -u " + + os.path.join(self.sra_folder, run_name + ".sra") + + " | samtools view -bS - > " + + bam_file ) # sam-dump -u SRR020515.sra | samtools view -bS - > test.bam @@ -1409,10 +1403,10 @@ def _sra_bam_conversion2(self, bam_file, run_name, picard_path=None): # check to make sure it worked cmd = ( - "fastq-dump --split-3 -O " - + os.path.realpath(self.sra_folder) - + " " - + os.path.join(self.sra_folder, run_name + ".sra") + "fastq-dump --split-3 -O " + + os.path.realpath(self.sra_folder) + + " " + + os.path.join(self.sra_folder, run_name + ".sra") ) self._LOGGER.info(f"Command: {cmd}") run_subprocess(cmd, shell=True) @@ -1493,7 +1487,7 @@ def _download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): self._LOGGER.info(f"\033[38;5;242mFile {full_filepath} exists.\033[0m") def _get_list_of_processed_files( - self, file_gse_content: list, file_gsm_content: list + self, file_gse_content: list, file_gsm_content: list ): """ Given a paths to GSE and GSM metafile create a list of dicts of metadata of processed files @@ -1523,7 +1517,7 @@ def _get_list_of_processed_files( # find and download filelist - file with information about files in tar index = file_url.rfind("/") tar_files_list_url = ( - "https" + file_url[3: index + 1] + "filelist.txt" + "https" + file_url[3 : index + 1] + "filelist.txt" ) # file_list_name filelist_path = os.path.join( @@ -1568,14 +1562,14 @@ def _get_list_of_processed_files( element_values = list(pl.values())[0] if not re.findall(SUPP_FILE_PATTERN, line_gsm): if ( - element_keys - not in meta_processed_samples[nb].keys() + element_keys + not in meta_processed_samples[nb].keys() ): meta_processed_samples[nb].update(pl) else: if ( - type(meta_processed_samples[nb][element_keys]) - is not list + type(meta_processed_samples[nb][element_keys]) + is not list ): meta_processed_samples[nb][element_keys] = [ meta_processed_samples[nb][element_keys] @@ -1945,7 +1939,7 @@ def _get_SRP_list(self, srp_number: str) -> list: id_results = x.json()["esearchresult"]["idlist"] if len(id_results) > 500: id_results = [ - id_results[x: x + 100] for x in range(0, len(id_results), 100) + id_results[x : x + 100] for x in range(0, len(id_results), 100) ] else: id_results = [id_results] @@ -1966,7 +1960,9 @@ def _get_SRP_list(self, srp_number: str) -> list: return SRP_list - def _get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): + def _read_gsm_metadata( + self, acc_GSE: str, acc_GSE_list: dict, file_gsm_content: list + ) -> dict: """ A simple state machine to parse SOFT formatted files (Here, the GSM file) @@ -1991,8 +1987,8 @@ def _get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): if line[0] == "^": pl = parse_SOFT_line(line) if ( - len(acc_GSE_list[acc_GSE]) > 0 - and pl["SAMPLE"] not in GSM_limit_list + len(acc_GSE_list[acc_GSE]) > 0 + and pl["SAMPLE"] not in GSM_limit_list ): # sys.stdout.write(" Skipping " + a['SAMPLE'] + ".") current_sample_id = None @@ -2020,7 +2016,17 @@ def _get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): f"line: {line}" ) continue - gsm_metadata[current_sample_id].update(pl) + new_key = list(pl.keys())[0] + if new_key in gsm_metadata[current_sample_id]: + if isinstance(gsm_metadata[current_sample_id][new_key], list): + gsm_metadata[current_sample_id][new_key].append(pl[new_key]) + else: + gsm_metadata[current_sample_id][new_key] = [ + gsm_metadata[current_sample_id][new_key] + ] + gsm_metadata[current_sample_id][new_key].append(pl[new_key]) + else: + gsm_metadata[current_sample_id].update(pl) # Now convert the ids GEO accessions into SRX accessions if not current_sample_srx: @@ -2036,6 +2042,7 @@ def _get_gsm_metadata(self, acc_GSE, acc_GSE_list, file_gsm_content: list): current_sample_srx = True # GSM SOFT file parsed, save it in a list self._LOGGER.info(f"Processed {len(samples_list)} samples.") + gsm_metadata = self._expand_metadata_list_in_dict(gsm_metadata) return gsm_metadata def _write(self, f_var_value, content, msg_pre=None, omit_newline=False): @@ -2079,16 +2086,16 @@ def _parse_cmdl(cmdl): dest="metadata_root", default=safe_echo("SRAMETA"), help="Specify a parent folder location to store metadata. " - "The project name will be added as a subfolder " - "[Default: $SRAMETA:" + safe_echo("SRAMETA") + "]", + "The project name will be added as a subfolder " + "[Default: $SRAMETA:" + safe_echo("SRAMETA") + "]", ) parser.add_argument( "-u", "--metadata-folder", help="Specify an absolute folder location to store metadata. " - "No subfolder will be added. Overrides value of --metadata-root " - "[Default: Not used (--metadata-root is used by default)]", + "No subfolder will be added. Overrides value of --metadata-root " + "[Default: Not used (--metadata-root is used by default)]", ) parser.add_argument( @@ -2113,8 +2120,8 @@ def _parse_cmdl(cmdl): "--pipeline-samples", default=None, help="Optional: Specify one or more filepaths to SAMPLES pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", ) # Optional @@ -2122,8 +2129,8 @@ def _parse_cmdl(cmdl): "--pipeline-project", default=None, help="Optional: Specify one or more filepaths to PROJECT pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", ) # Optional parser.add_argument( @@ -2145,7 +2152,7 @@ def _parse_cmdl(cmdl): "--acc-anno", action="store_true", help="Optional: Produce annotation sheets for each accession." - " Project combined PEP for the whole project won't be produced.", + " Project combined PEP for the whole project won't be produced.", ) parser.add_argument( @@ -2159,7 +2166,7 @@ def _parse_cmdl(cmdl): type=int, default=50, help="Optional: Limit of the number of the constant sample characters " - "that should not be in project yaml. [Default: 50]", + "that should not be in project yaml. [Default: 50]", ) parser.add_argument( @@ -2167,7 +2174,7 @@ def _parse_cmdl(cmdl): type=int, default=250, help="Optional: Limit of the number of the constant sample characters " - "that should not be discarded [Default: 250]", + "that should not be discarded [Default: 250]", ) parser.add_argument( @@ -2175,8 +2182,8 @@ def _parse_cmdl(cmdl): type=int, default=500, help="Optional: Limit of the number of sample characters." - "Any attribute with more than X characters will truncate to the first X," - " where X is a number of characters [Default: 500]", + "Any attribute with more than X characters will truncate to the first X," + " where X is a number of characters [Default: 500]", ) parser.add_argument( @@ -2199,17 +2206,17 @@ def _parse_cmdl(cmdl): choices=["all", "samples", "series"], default="samples", help="Optional: Specifies the source of data on the GEO record" - " to retrieve processed data, which may be attached to the" - " collective series entity, or to individual samples. " - "Allowable values are: samples, series or both (all). " - "Ignored unless 'processed' flag is set. [Default: samples]", + " to retrieve processed data, which may be attached to the" + " collective series entity, or to individual samples. " + "Allowable values are: samples, series or both (all). " + "Ignored unless 'processed' flag is set. [Default: samples]", ) processed_group.add_argument( "--filter", default=None, help="Optional: Filter regex for processed filenames [Default: None]." - "Ignored unless 'processed' flag is set.", + "Ignored unless 'processed' flag is set.", ) processed_group.add_argument( @@ -2228,8 +2235,8 @@ def _parse_cmdl(cmdl): "--geo-folder", default=safe_echo("GEODATA"), help="Optional: Specify a location to store processed GEO files." - " Ignored unless 'processed' flag is set." - "[Default: $GEODATA:" + safe_echo("GEODATA") + "]", + " Ignored unless 'processed' flag is set." + "[Default: $GEODATA:" + safe_echo("GEODATA") + "]", ) raw_group.add_argument( @@ -2251,8 +2258,8 @@ def _parse_cmdl(cmdl): help="""Optional: Specify folder of bam files. Geofetch will not download sra files when corresponding bam files already exist. [Default: $SRABAM:""" - + safe_echo("SRABAM") - + "]", + + safe_echo("SRABAM") + + "]", ) raw_group.add_argument( @@ -2263,8 +2270,8 @@ def _parse_cmdl(cmdl): help="""Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding fastq files already exist. [Default: $SRAFQ:""" - + safe_echo("SRAFQ") - + "]", + + safe_echo("SRAFQ") + + "]", ) # Deprecated; these are for bam conversion which now happens in sra_convert diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index f9e268b..d3fa7de 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -109,20 +109,20 @@ def test_downloading_soft_files(self, initiate_geofetcher): def test_creating_sample_pep_files(self, initiate_geofetcher): initiate_geofetcher.fetch_all("GSE138657") downloaded_meta_files = list( - os.walk(initiate_geofetcher.metadata_expanded + "/PEP_samples") + os.walk(initiate_geofetcher.metadata_expanded + "/PEP_processed_samples") )[0][2] - assert "GSE138657_samples.csv" in downloaded_meta_files - assert "GSE138657_samples.yaml" in downloaded_meta_files + assert "PEP_processed_samples.csv" in downloaded_meta_files + assert "PEP_processed_samples.yaml" in downloaded_meta_files def test_creating_series_pep_files(self, initiate_geofetcher): initiate_geofetcher.fetch_all("GSE199313") downloaded_meta_files = list( - os.walk(initiate_geofetcher.metadata_expanded + "/PEP_series") + os.walk(initiate_geofetcher.metadata_expanded + "/PEP_processed_series") )[0][2] - assert "GSE199313_series.csv" in downloaded_meta_files - assert "GSE199313_series.yaml" in downloaded_meta_files + assert "PEP_processed_series.csv" in downloaded_meta_files + assert "PEP_processed_series.yaml" in downloaded_meta_files class TestDownloadingProcFiles: From 259bcff3c4c96bd5900c156787672fab0fd3e946 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 31 Aug 2022 17:11:41 -0400 Subject: [PATCH 25/61] Refactored raw functions 2 + stability --- geofetch/const.py | 5 + geofetch/geofetch.py | 357 ++++++++++++++++++++----------------------- geofetch/utils.py | 23 +-- 3 files changed, 180 insertions(+), 205 deletions(-) diff --git a/geofetch/const.py b/geofetch/const.py index 01d1e05..cc3e898 100644 --- a/geofetch/const.py +++ b/geofetch/const.py @@ -32,6 +32,8 @@ SAMPLE_SUPP_METADATA_FILE = "_samples.csv" EXP_SUPP_METADATA_FILE = "_series.csv" +FILE_RAW_NAME_SAMPLE_PATTERN = "_raw.csv" +FILE_RAW_NAME_SUBSAMPLE_PATTERN = "_raw_subtable.csv" # How many times should we retry failing prefetch call? NUM_RETRIES = 3 @@ -41,3 +43,6 @@ NCBI_EFETCH = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=sra&id={ID}&rettype=runinfo&retmode=xml" NEW_GENOME_COL_NAME = "ref_genome" + +CONFIG_PROCESSED_TEMPLATE_NAME = "config_processed_template.yaml" +CONFIG_RAW_TEMPLATE_NAME = "config_template.yaml" \ No newline at end of file diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 5fee104..ba4ef26 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -94,18 +94,18 @@ def __init__( if metadata_folder: self.metadata_expanded = expandpath(metadata_folder) if os.path.isabs(self.metadata_expanded): - self.metadata_raw = metadata_folder + self.metadata_root_full = metadata_folder else: self.metadata_expanded = os.path.abspath(self.metadata_expanded) - self.metadata_raw = os.path.abspath(metadata_root) - self.metadata_raw = metadata_folder + self.metadata_root_full = os.path.abspath(metadata_root) + self.metadata_root_full = metadata_folder else: self.metadata_expanded = expandpath(metadata_root) if os.path.isabs(self.metadata_expanded): - self.metadata_raw = metadata_root + self.metadata_root_full = metadata_root else: self.metadata_expanded = os.path.abspath(self.metadata_expanded) - self.metadata_raw = os.path.abspath(metadata_root) + self.metadata_root_full = os.path.abspath(metadata_root) self.just_metadata = just_metadata self.refresh_metadata = refresh_metadata @@ -143,7 +143,7 @@ def __init__( self.metadata_expanded = os.path.join( self.metadata_expanded, self.project_name ) - self.metadata_raw = os.path.join(self.metadata_raw, self.project_name) + self.metadata_root_full = os.path.join(self.metadata_root_full, self.project_name) if filter_size is not None: try: @@ -229,7 +229,7 @@ def get_project( project_dict[acc_GSE + "_raw"] = project else: - ser_dict = self.fetch_all(input=acc_GSE_list) + ser_dict = self.fetch_all(input=input) project_dict["raw_samples"] = ser_dict return project_dict @@ -240,7 +240,10 @@ def fetch_all(self, input: str, name: str = None): if name: self.project_name = name else: - self.project_name = os.path.splitext(os.path.basename(input))[0] + try: + self.project_name = os.path.splitext(os.path.basename(input))[0] + except TypeError: + self.project_name = input # check to make sure prefetch is callable if not self.just_metadata and not self.processed: @@ -254,8 +257,8 @@ def fetch_all(self, input: str, name: str = None): input, self.metadata_expanded, self.just_metadata ) - metadata_dict = {} - subannotation_dict = {} + metadata_dict_combined = {} + subannotation_dict_combined = {} processed_metadata_samples = [] processed_metadata_series = [] @@ -361,37 +364,42 @@ def fetch_all(self, input: str, name: str = None): ) if not srp_list_result: self._LOGGER.info(f"No SRP data, continuing ....") + self._LOGGER.warning(f"No raw pep will be created! ....") # delete current acc if no raw data was found # del metadata_dict[acc_GSE] - continue + pass else: self._LOGGER.info("Parsing SRA file to download SRR records") - gsm_multi_table = self._process_sra_meta( - srp_list_result, gsm_enter_dict, gsm_metadata - ) + gsm_multi_table = self._process_sra_meta( + srp_list_result, gsm_enter_dict, gsm_metadata + ) - # download raw data: - if not self.just_metadata: - for file_key in gsm_multi_table.keys(): - for run in gsm_multi_table[file_key]: - # download raw data - self._LOGGER.info( - f"Getting SRR: {run[2]} in ({acc_GSE})" - ) - self._download_raw_data(run[2]) - else: - self._LOGGER.info(f"Dry run, no data will be downloaded") + # download raw data: + if not self.just_metadata: + for file_key in gsm_multi_table.keys(): + for run in gsm_multi_table[file_key]: + # download raw data + self._LOGGER.info( + f"Getting SRR: {run[2]} in ({acc_GSE})" + ) + self._download_raw_data(run[2]) + else: + self._LOGGER.info(f"Dry run, no data will be downloaded") - # accumulate subannotations - metadata_dict[acc_GSE] = gsm_metadata - subannotation_dict[acc_GSE] = gsm_multi_table + # save one project + if self.acc_anno and nkeys > 1: + self._write_raw_annotation_new(name=acc_GSE, metadata_dict=gsm_metadata, subannot_dict=gsm_multi_table) + + else: + metadata_dict_combined.update(gsm_metadata) + subannotation_dict_combined.update(gsm_multi_table) self._LOGGER.info(f"Finished processing {len(acc_GSE_list)} accession(s)") # Logging cleaning process: if self.discard_soft: self._LOGGER.info(f"Cleaning soft files ...") - clean_soft_files(self.metadata_raw) + clean_soft_files(self.metadata_root_full) ####################################################################################### @@ -408,11 +416,11 @@ def fetch_all(self, input: str, name: str = None): # saving PEPs for raw data else: - return_value = self._write_raw_annotation(metadata_dict, subannotation_dict) + return_value = self._write_raw_annotation_new("PEP", metadata_dict_combined, subannotation_dict_combined) if self.just_object: return return_value - def _process_sra_meta(self, srp_list_result, gsm_enter_dict, gsm_metadata): + def _process_sra_meta(self, srp_list_result=None, gsm_enter_dict=None, gsm_metadata=None): gsm_multi_table = {} for line in srp_list_result: @@ -482,6 +490,7 @@ def _process_sra_meta(self, srp_list_result, gsm_enter_dict, gsm_metadata): else: # The first SRR for this SRX is added to GSM metadata gsm_metadata[experiment]["SRR"] = run_name + return gsm_multi_table def _download_raw_data(self, run_name): @@ -579,7 +588,7 @@ def _generate_processed_meta( if self.supp_by == "all": # samples pep_acc_path_sample = os.path.join( - self.metadata_raw, + self.metadata_root_full, f"{name}_samples", name + SAMPLE_SUPP_METADATA_FILE, ) @@ -591,7 +600,7 @@ def _generate_processed_meta( # series pep_acc_path_exp = os.path.join( - self.metadata_raw, + self.metadata_root_full, f"{name}_series", name + EXP_SUPP_METADATA_FILE, ) @@ -603,7 +612,7 @@ def _generate_processed_meta( elif self.supp_by == "samples": pep_acc_path_sample = os.path.join( - self.metadata_raw, + self.metadata_root_full, f"{name}_samples", name + SAMPLE_SUPP_METADATA_FILE, ) @@ -614,7 +623,7 @@ def _generate_processed_meta( ) elif self.supp_by == "series": return_objects[f"{name}_series"] = pep_acc_path_exp = os.path.join( - self.metadata_raw, + self.metadata_root_full, f"{name}_series", name + EXP_SUPP_METADATA_FILE, ) @@ -688,7 +697,7 @@ def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): """ try: element_is_list = any( - type(list_item[dict_key]) is list for list_item in metadata_list + type(list_item.get(dict_key)) is list for list_item in metadata_list ) if element_is_list: for n_elem in range(len(metadata_list)): @@ -737,7 +746,7 @@ def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): else: del metadata_list[n_elem][dict_key] except KeyError as err: - self._LOGGER.warning(f"expand_metadata_list: Key Error: {err}") + self._LOGGER.warning(f"expand_metadata_list: Key Error: {err}, continuing ...") return metadata_list else: @@ -824,7 +833,7 @@ def _find_genome(self, metadata_list): return metadata_list def _write_gsm_annotation( - self, gsm_metadata, file_annotation, use_key_subset=False + self, gsm_metadata, file_annotation ): """ Write metadata sheet out as an annotation file. @@ -832,16 +841,9 @@ def _write_gsm_annotation( :param Mapping gsm_metadata: the data to write, parsed from a file with metadata/annotation information :param str file_annotation: the path to the file to write - :param bool use_key_subset: whether to use the keys present in the - metadata object given (False), or instead use a fixed set of keys - defined within this module (True) :return str: path to file written """ - if use_key_subset: - keys = ANNOTATION_SHEET_KEYS - else: - # keys = gsm_metadata[gsm_metadata.keys().next()].keys() - keys = list(list(gsm_metadata.values())[0].keys()) + keys = list(list(gsm_metadata.values())[0].keys()) self._LOGGER.info(f"Sample annotation sheet: {file_annotation} . Saving....") fp = expandpath(file_annotation) @@ -891,29 +893,8 @@ def _write_processed_annotation( self.const_limit_discard, self.attr_limit_truncate, ) - meta_list_str = [ - f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta - ] - modifiers_str = "\n ".join(d for d in meta_list_str) - geofetchdir = os.path.dirname(__file__) - config_template = os.path.join(geofetchdir, "config_processed_template.yaml") - - with open(config_template, "r") as template_file: - template = template_file.read() - - template_values = { - "project_name": self.project_name, - "sample_table": os.path.basename(file_annotation_path), - "geo_folder": self.geo_folder, - "pipeline_samples": self.file_pipeline_samples, - "pipeline_project": self.file_pipeline_project, - "additional_columns": modifiers_str, - } - - for k, v in template_values.items(): - placeholder = "{" + str(k) + "}" - template = template.replace(placeholder, str(v)) + template = self._create_config_processed(file_annotation_path, proj_meta) if not just_object: with open(file_annotation_path, "w") as m_file: @@ -944,170 +925,78 @@ def _write_processed_annotation( proj = peppy.Project().from_pandas(pd_value, config=conf) return proj - @staticmethod - def _sanitize_name(name_str: str): + def _write_raw_annotation_new(self, name, metadata_dict: dict, subannot_dict: dict = None) -> Union[None, peppy.Project]: """ - Function that sanitizing strings. (Replace all odd characters) - :param str name_str: Any string value that has to be sanitized. - :return: sanitized strings - """ - new_str = name_str - punctuation1 = r"""!"#$%&'()*,./:;<=>?@[\]^_`{|}~""" - for odd_char in list(punctuation1): - new_str = new_str.replace(odd_char, "_") - new_str = new_str.replace(" ", "_").replace("__", "_") - return new_str - - def _write_raw_annotation(self, metadata_dict, subannotation_dict): - """ - Combining individual accessions into project-level annotations, and writeing + Combining individual accessions into project-level annotations, and writing individual accession files (if requested) - :param dict metadata_dict: dictionary of metadata - :param dict sub-annotation_dict: dictionary of sub-annotation metadata + :param name: + :param metadata_dict: + :param subannot_dict: + :return: none or peppy object """ - - if self.discard_soft: - clean_soft_files(os.path.join(self.metadata_raw)) - try: assert len(metadata_dict) > 0 except AssertionError: self._LOGGER.warning( "\033[33mNo PEP created, as no raw data was found!!!\033[0m" ) - return False + return None - # checking sample_name value if it's not empty, - # otherwise pulling from title - for key, value in metadata_dict.items(): - fixed_dict = {} - for key_sample, value_sample in value.items(): - fixed_dict[key_sample] = value_sample - if ( - value_sample["sample_name"] == "" - or value_sample["sample_name"] is None - ): - fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] - # TODO: should be corrected: - # # sanitize names - # fixed_dict[key_sample]["sample_name"] = self._sanitize_name( - # fixed_dict[key_sample]["sample_name"] - # ) + if self.discard_soft: + clean_soft_files(os.path.join(self.metadata_root_full)) - metadata_dict[key] = fixed_dict + self._LOGGER.info( + "Creating complete project annotation sheets and config file..." + ) - # annotation table - metadata_dict_combined = {} - for acc_GSE, gsm_metadata in metadata_dict.items(): - gsm_metadata1 = self._standardize_colnames(gsm_metadata) - file_annotation = os.path.join( - self.metadata_expanded, acc_GSE + "_annotation.csv" - ) - # for each sample - if self.acc_anno: - self._write_gsm_annotation( - gsm_metadata1, file_annotation, use_key_subset=self.use_key_subset - ) - metadata_dict_combined.update(gsm_metadata1) + proj_root = os.path.join(self.metadata_root_full, name) + if not os.path.exists(proj_root): + os.makedirs(proj_root) - # subatnotation table - subannotation_dict_combined = {} - for acc_GSE, gsm_multi_table in subannotation_dict.items(): - file_subannotation = os.path.join( - self.metadata_expanded, acc_GSE + "_subannotation.csv" - ) - # for each sample: - if self.acc_anno: - self._write_subannotation(gsm_multi_table, file_subannotation) - subannotation_dict_combined.update(gsm_multi_table) + proj_root_sample = os.path.join(proj_root, f"{name}{FILE_RAW_NAME_SAMPLE_PATTERN}") + proj_root_subsample = os.path.join(proj_root, f"{name}{FILE_RAW_NAME_SUBSAMPLE_PATTERN}") + yaml_name = f"{name}.yaml" + proj_root_yaml = os.path.join(proj_root, yaml_name) + dot_yaml_path = os.path.join(proj_root, ".pep.yaml") - # TODO: were is .yaml file for each acc_anno? + metadata_dict = self._check_sample_name_standard(metadata_dict) - self._LOGGER.info( - "Creating complete project annotation sheets and config file..." - ) - # filtering huge annotation strings that are repeating for each sample - metadata_dict_combined, proj_meta = self._separate_common_meta( - metadata_dict_combined, + metadata_dict, proj_meta = self._separate_common_meta( + metadata_dict, self.const_limit_project, self.const_limit_discard, self.attr_limit_truncate, ) - meta_list_str = [ - f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta - ] - modifiers_str = "\n ".join(d for d in meta_list_str) - - # If the project included more than one GSE, we can now output combined - # annotation tables for the entire project. - # Write combined annotation sheet - file_annotation = os.path.join( - self.metadata_raw, self.project_name + "_annotation.csv" - ) # Write combined subannotation table - if len(subannotation_dict_combined) > 0: - file_subannotation = os.path.join( - self.metadata_raw, self.project_name + "_subannotation.csv" - ) - self._write_subannotation(subannotation_dict_combined, file_subannotation) + if len(subannot_dict) > 0: subanot_path_yaml = ( - f"subsample_table: {os.path.basename(file_subannotation)}" + f"subsample_table: {os.path.basename(proj_root_subsample)}" ) else: - file_subannotation = "null" subanot_path_yaml = f"" - # Write project config file - if not self.config_template: - geofetchdir = os.path.dirname(__file__) - self.config_template = os.path.join(geofetchdir, "config_template.yaml") - with open(self.config_template, "r") as template_file: - template = template_file.read() + template = self._create_config_raw(proj_meta, proj_root_sample, subanot_path_yaml) - template_values = { - "project_name": self.project_name, - "annotation": os.path.basename(file_annotation), - "subannotation": subanot_path_yaml, - "pipeline_samples": self.file_pipeline_samples, - "pipeline_project": self.file_pipeline_project, - "additional_columns": modifiers_str, - } - for k, v in template_values.items(): - placeholder = "{" + str(k) + "}" - template = template.replace(placeholder, str(v)) + if not self.just_object: + self._write_gsm_annotation(metadata_dict, proj_root_sample) - if not self.just_object and not self.acc_anno: - # write annotation - self._write_gsm_annotation( - metadata_dict_combined, - file_annotation, - use_key_subset=self.use_key_subset, - ) - # write subannotation - if len(subannotation_dict_combined) > 0: - self._write_subannotation( - subannotation_dict_combined, file_subannotation - ) + if len(subannot_dict) > 0: + self._write_subannotation(subannot_dict, proj_root_subsample) - # save .yaml file - yaml_name = self.project_name + "_config.yaml" - config = os.path.join(self.metadata_raw, yaml_name) - self._write(config, template, msg_pre=" Config file: ") + self._write(proj_root_yaml, template, msg_pre=" Config file: ") - # save .pep.yaml file if self.add_dotfile: - dot_yaml_path = os.path.join(self.metadata_raw, ".pep.yaml") self._create_dot_yaml(dot_yaml_path, yaml_name) else: - meta_df = pd.DataFrame.from_dict(metadata_dict_combined, orient="index") + meta_df = pd.DataFrame.from_dict(metadata_dict, orient="index") # open list: new_sub_list = [] - for sub_key in subannotation_dict_combined.keys(): + for sub_key in subannot_dict.keys(): new_sub_list.extend( - [col_item for col_item in subannotation_dict_combined[sub_key]] + [col_item for col_item in subannot_dict[sub_key]] ) sub_meta_df = pd.DataFrame( @@ -1123,6 +1012,83 @@ def _write_raw_annotation(self, metadata_dict, subannotation_dict): proj = peppy.Project().from_pandas(meta_df, sub_meta_df, conf) return proj + def _create_config_processed(self, file_annotation_path, proj_meta): + geofetchdir = os.path.dirname(__file__) + config_template = os.path.join(geofetchdir, CONFIG_PROCESSED_TEMPLATE_NAME) + with open(config_template, "r") as template_file: + template = template_file.read() + meta_list_str = [ + f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta + ] + modifiers_str = "\n ".join(d for d in meta_list_str) + template_values = { + "project_name": self.project_name, + "sample_table": os.path.basename(file_annotation_path), + "geo_folder": self.geo_folder, + "pipeline_samples": self.file_pipeline_samples, + "pipeline_project": self.file_pipeline_project, + "additional_columns": modifiers_str, + } + for k, v in template_values.items(): + placeholder = "{" + str(k) + "}" + template = template.replace(placeholder, str(v)) + return template + + def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): + meta_list_str = [ + f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta + ] + modifiers_str = "\n ".join(d for d in meta_list_str) + # Write project config file + if not self.config_template: + geofetchdir = os.path.dirname(__file__) + self.config_template = os.path.join(geofetchdir, CONFIG_RAW_TEMPLATE_NAME) + with open(self.config_template, "r") as template_file: + template = template_file.read() + template_values = { + "project_name": self.project_name, + "annotation": os.path.basename(proj_root_sample), + "subannotation": subanot_path_yaml, + "pipeline_samples": self.file_pipeline_samples, + "pipeline_project": self.file_pipeline_project, + "additional_columns": modifiers_str, + } + for k, v in template_values.items(): + placeholder = "{" + str(k) + "}" + template = template.replace(placeholder, str(v)) + return template + + def _check_sample_name_standard(self, metadata_dict): + fixed_dict = {} + for key_sample, value_sample in metadata_dict.items(): + fixed_dict[key_sample] = value_sample + if ( + value_sample["sample_name"] == "" + or value_sample["sample_name"] is None + ): + fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] + # sanitize names + fixed_dict[key_sample]["sample_name"] = self._sanitize_name( + fixed_dict[key_sample]["sample_name"] + ) + metadata_dict = fixed_dict + metadata_dict = self._standardize_colnames(metadata_dict) + return metadata_dict + + @staticmethod + def _sanitize_name(name_str: str): + """ + Function that sanitizing strings. (Replace all odd characters) + :param str name_str: Any string value that has to be sanitized. + :return: sanitized strings + """ + new_str = name_str + punctuation1 = r"""!"#$%&'()*,./:;<=>?@[\]^_`{|}~""" + for odd_char in list(punctuation1): + new_str = new_str.replace(odd_char, "_") + new_str = new_str.replace(" ", "_").replace("__", "_") + return new_str + @staticmethod def _create_dot_yaml(file_path: str, yaml_path: str): """ @@ -1213,7 +1179,7 @@ def _separate_common_meta( meta_list = self._dict_to_list_convector(proj_list=meta_list) return meta_list, new_meta_project - def _standardize_colnames(self, meta_list): + def _standardize_colnames(self, meta_list: Union[list, dict]): """ Standardize column names by lower-casing and underscore :param list meta_list: list of dictionaries of samples @@ -2336,6 +2302,7 @@ def main(): Geofetcher(**args_dict).fetch_all(args_dict["input"]) + if __name__ == "__main__": try: sys.exit(main()) diff --git a/geofetch/utils.py b/geofetch/utils.py index 99735b7..7917c67 100644 --- a/geofetch/utils.py +++ b/geofetch/utils.py @@ -311,16 +311,19 @@ def clean_soft_files(meta_dir: str): and creating PEPs :param str meta_dir: Path to the metadata files """ - dir_files = os.listdir(meta_dir) - - for item in dir_files: - if ( - item.endswith(".soft") - or item.endswith("_file_list.txt") - or item.endswith("SRA.csv") - or item.endswith("SRA_filt.csv") - ): - os.remove(os.path.join(meta_dir, item)) + try: + dir_files = os.listdir(meta_dir) + + for item in dir_files: + if ( + item.endswith(".soft") + or item.endswith("_file_list.txt") + or item.endswith("SRA.csv") + or item.endswith("SRA_filt.csv") + ): + os.remove(os.path.join(meta_dir, item)) + except FileNotFoundError: + _LOGGER.debug("Can't clean soft files...folder doesn't exist") def run_subprocess(*args, **kwargs): From bf37d2e8fc437d41e6e1d3a783d1b4e57e52ab07 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 1 Sep 2022 11:04:45 -0400 Subject: [PATCH 26/61] Bug fix --- geofetch/geofetch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index ba4ef26..2011627 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1881,7 +1881,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): f"\033[91mError occurred, while downloading SRA Info Metadata of {acc_SRP}. " f"Error: {err} \033[0m" ) - return False + return [] def _get_SRP_list(self, srp_number: str) -> list: """ From f034235173a1827178026c60f20629f959abfc57 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 1 Sep 2022 11:27:47 -0400 Subject: [PATCH 27/61] Bug fix 2 --- geofetch/geofetch.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 2011627..f2d200e 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -845,13 +845,14 @@ def _write_gsm_annotation( """ keys = list(list(gsm_metadata.values())[0].keys()) - self._LOGGER.info(f"Sample annotation sheet: {file_annotation} . Saving....") + self._LOGGER.info(f"\033[92mSample annotation sheet: {file_annotation} . Saved!\033[0m") fp = expandpath(file_annotation) with open(fp, "w") as of: w = csv.DictWriter(of, keys, extrasaction="ignore") w.writeheader() for item in gsm_metadata: w.writerow(gsm_metadata[item]) + self._LOGGER.info(f"\033[92mSample annotation sheet: {file_annotation} . Saved!\033[0m") self._LOGGER.info("\033[92mFile has been saved successfully\033[0m") return fp @@ -1830,7 +1831,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): ) except TypeError: self._LOGGER.warning("Error in gsm_metadata") - return False + return [] # else: # # More than one sample? not sure what to do here. Does this even happen? @@ -1857,7 +1858,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): f"\033[91mError occurred, while downloading SRA Info Metadata of {acc_SRP}. " f"Error: {err} \033[0m" ) - return False + return [] else: # open existing annotation self._LOGGER.info(f"Found SRA metadata, opening..") From 156213ddcf7dd0e590620134b739739fd08aad08 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 1 Sep 2022 12:36:19 -0400 Subject: [PATCH 28/61] requirements + lint --- geofetch/const.py | 2 +- geofetch/geofetch.py | 70 ++++++++++++++++++------------- requirements/requirements-all.txt | 2 +- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/geofetch/const.py b/geofetch/const.py index cc3e898..566aeac 100644 --- a/geofetch/const.py +++ b/geofetch/const.py @@ -45,4 +45,4 @@ NEW_GENOME_COL_NAME = "ref_genome" CONFIG_PROCESSED_TEMPLATE_NAME = "config_processed_template.yaml" -CONFIG_RAW_TEMPLATE_NAME = "config_template.yaml" \ No newline at end of file +CONFIG_RAW_TEMPLATE_NAME = "config_template.yaml" diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index f2d200e..3dbb9c0 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -6,9 +6,9 @@ import copy import csv import os -import re +# import re import sys -from string import punctuation +# from string import punctuation import requests import xmltodict from rich.progress import track @@ -143,7 +143,9 @@ def __init__( self.metadata_expanded = os.path.join( self.metadata_expanded, self.project_name ) - self.metadata_root_full = os.path.join(self.metadata_root_full, self.project_name) + self.metadata_root_full = os.path.join( + self.metadata_root_full, self.project_name + ) if filter_size is not None: try: @@ -379,16 +381,18 @@ def fetch_all(self, input: str, name: str = None): for file_key in gsm_multi_table.keys(): for run in gsm_multi_table[file_key]: # download raw data - self._LOGGER.info( - f"Getting SRR: {run[2]} in ({acc_GSE})" - ) + self._LOGGER.info(f"Getting SRR: {run[2]} in ({acc_GSE})") self._download_raw_data(run[2]) else: self._LOGGER.info(f"Dry run, no data will be downloaded") # save one project if self.acc_anno and nkeys > 1: - self._write_raw_annotation_new(name=acc_GSE, metadata_dict=gsm_metadata, subannot_dict=gsm_multi_table) + self._write_raw_annotation_new( + name=acc_GSE, + metadata_dict=gsm_metadata, + subannot_dict=gsm_multi_table, + ) else: metadata_dict_combined.update(gsm_metadata) @@ -416,11 +420,15 @@ def fetch_all(self, input: str, name: str = None): # saving PEPs for raw data else: - return_value = self._write_raw_annotation_new("PEP", metadata_dict_combined, subannotation_dict_combined) + return_value = self._write_raw_annotation_new( + "PEP", metadata_dict_combined, subannotation_dict_combined + ) if self.just_object: return return_value - def _process_sra_meta(self, srp_list_result=None, gsm_enter_dict=None, gsm_metadata=None): + def _process_sra_meta( + self, srp_list_result=None, gsm_enter_dict=None, gsm_metadata=None + ): gsm_multi_table = {} for line in srp_list_result: @@ -746,7 +754,9 @@ def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): else: del metadata_list[n_elem][dict_key] except KeyError as err: - self._LOGGER.warning(f"expand_metadata_list: Key Error: {err}, continuing ...") + self._LOGGER.warning( + f"expand_metadata_list: Key Error: {err}, continuing ..." + ) return metadata_list else: @@ -832,9 +842,7 @@ def _find_genome(self, metadata_list): metadata_list[sample[0]][NEW_GENOME_COL_NAME] = sample_genome return metadata_list - def _write_gsm_annotation( - self, gsm_metadata, file_annotation - ): + def _write_gsm_annotation(self, gsm_metadata, file_annotation): """ Write metadata sheet out as an annotation file. @@ -845,14 +853,18 @@ def _write_gsm_annotation( """ keys = list(list(gsm_metadata.values())[0].keys()) - self._LOGGER.info(f"\033[92mSample annotation sheet: {file_annotation} . Saved!\033[0m") + self._LOGGER.info( + f"\033[92mSample annotation sheet: {file_annotation} . Saved!\033[0m" + ) fp = expandpath(file_annotation) with open(fp, "w") as of: w = csv.DictWriter(of, keys, extrasaction="ignore") w.writeheader() for item in gsm_metadata: w.writerow(gsm_metadata[item]) - self._LOGGER.info(f"\033[92mSample annotation sheet: {file_annotation} . Saved!\033[0m") + self._LOGGER.info( + f"\033[92mSample annotation sheet: {file_annotation} . Saved!\033[0m" + ) self._LOGGER.info("\033[92mFile has been saved successfully\033[0m") return fp @@ -926,7 +938,9 @@ def _write_processed_annotation( proj = peppy.Project().from_pandas(pd_value, config=conf) return proj - def _write_raw_annotation_new(self, name, metadata_dict: dict, subannot_dict: dict = None) -> Union[None, peppy.Project]: + def _write_raw_annotation_new( + self, name, metadata_dict: dict, subannot_dict: dict = None + ) -> Union[None, peppy.Project]: """ Combining individual accessions into project-level annotations, and writing individual accession files (if requested) @@ -954,8 +968,12 @@ def _write_raw_annotation_new(self, name, metadata_dict: dict, subannot_dict: di if not os.path.exists(proj_root): os.makedirs(proj_root) - proj_root_sample = os.path.join(proj_root, f"{name}{FILE_RAW_NAME_SAMPLE_PATTERN}") - proj_root_subsample = os.path.join(proj_root, f"{name}{FILE_RAW_NAME_SUBSAMPLE_PATTERN}") + proj_root_sample = os.path.join( + proj_root, f"{name}{FILE_RAW_NAME_SAMPLE_PATTERN}" + ) + proj_root_subsample = os.path.join( + proj_root, f"{name}{FILE_RAW_NAME_SUBSAMPLE_PATTERN}" + ) yaml_name = f"{name}.yaml" proj_root_yaml = os.path.join(proj_root, yaml_name) dot_yaml_path = os.path.join(proj_root, ".pep.yaml") @@ -977,7 +995,9 @@ def _write_raw_annotation_new(self, name, metadata_dict: dict, subannot_dict: di else: subanot_path_yaml = f"" - template = self._create_config_raw(proj_meta, proj_root_sample, subanot_path_yaml) + template = self._create_config_raw( + proj_meta, proj_root_sample, subanot_path_yaml + ) if not self.just_object: self._write_gsm_annotation(metadata_dict, proj_root_sample) @@ -996,9 +1016,7 @@ def _write_raw_annotation_new(self, name, metadata_dict: dict, subannot_dict: di # open list: new_sub_list = [] for sub_key in subannot_dict.keys(): - new_sub_list.extend( - [col_item for col_item in subannot_dict[sub_key]] - ) + new_sub_list.extend([col_item for col_item in subannot_dict[sub_key]]) sub_meta_df = pd.DataFrame( new_sub_list, columns=["sample_name", "SRX", "SRR"] @@ -1063,10 +1081,7 @@ def _check_sample_name_standard(self, metadata_dict): fixed_dict = {} for key_sample, value_sample in metadata_dict.items(): fixed_dict[key_sample] = value_sample - if ( - value_sample["sample_name"] == "" - or value_sample["sample_name"] is None - ): + if value_sample["sample_name"] == "" or value_sample["sample_name"] is None: fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] # sanitize names fixed_dict[key_sample]["sample_name"] = self._sanitize_name( @@ -1824,7 +1839,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): # could still be an SRX linked to the (each) GSM. if len(gsm_metadata) == 1: try: - acc_SRP = gsm_metadata.keys()[0] + acc_SRP = list(gsm_metadata.keys())[0] self._LOGGER.warning( "But the GSM has an SRX number; instead of an " "SRP, using SRX identifier for this sample: " + acc_SRP @@ -2303,7 +2318,6 @@ def main(): Geofetcher(**args_dict).fetch_all(args_dict["input"]) - if __name__ == "__main__": try: sys.exit(main()) diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index f8a0182..a916a7b 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -8,5 +8,5 @@ ubiquerg>=0.6.0 requests>=2.28.1 xmltodict>=0.13.0 pandas>=1.3.5 -peppy>=0.34.0 +peppy>=0.35.0 rich>=12.5.1 From d71dd780e9702cda5fb5bc985883d66745b6d973 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 1 Sep 2022 13:34:30 -0400 Subject: [PATCH 29/61] added docString to the functions --- geofetch/geofetch.py | 135 ++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 35 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 3dbb9c0..bb0bff2 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -6,8 +6,10 @@ import copy import csv import os + # import re import sys + # from string import punctuation import requests import xmltodict @@ -427,8 +429,18 @@ def fetch_all(self, input: str, name: str = None): return return_value def _process_sra_meta( - self, srp_list_result=None, gsm_enter_dict=None, gsm_metadata=None + self, + srp_list_result: list = None, + gsm_enter_dict: dict = None, + gsm_metadata: dict = None, ): + """ + Creating srp multitable and updating gsm_metadata based on srp + :param srp_list_result: list of srp got from sra file + :param gsm_enter_dict: gsm enter content + :param gsm_metadata: dict of samples of gsm + :return: srp multitable + """ gsm_multi_table = {} for line in srp_list_result: @@ -646,6 +658,13 @@ def _generate_processed_meta( def _download_processed_data( self, acc_gse: str, meta_processed_samples: list, meta_processed_series: list ) -> NoReturn: + """ + Function that downloads processed data + :param acc_gse: accession number of the project + :param meta_processed_samples: list of annotation of samples + :param meta_processed_series: list of annotation of series + :return: Noreturn + """ data_geo_folder = os.path.join(self.geo_folder, acc_gse) self._LOGGER.debug("Data folder: " + data_geo_folder) @@ -677,6 +696,12 @@ def _download_processed_data( self._download_processed_file(file_url, data_geo_folder) def _expand_metadata_list_in_dict(self, metadata_dict: dict) -> dict: + """ + Expanding all lists of all items in the dict by creating new items or joining them + + :param metadata_dict: metadata dict + :return: expanded metadata dict + """ prj_list = self._dict_to_list_convector(proj_dict=metadata_dict) prj_list = self._expand_metadata_list(prj_list) return self._dict_to_list_convector(proj_list=prj_list) @@ -796,7 +821,7 @@ def _filter_gsm(self, meta_processed_samples: list, gsm_list: dict) -> list: return meta_processed_samples @staticmethod - def _get_list_of_keys(list_of_dict): + def _get_list_of_keys(list_of_dict: list): """ Getting list of all keys that are in the dictionaries in the list @@ -809,13 +834,13 @@ def _get_list_of_keys(list_of_dict): list_of_keys.extend(list(element.keys())) return list(set(list_of_keys)) - def _unify_list_keys(self, processed_meta_list): + def _unify_list_keys(self, processed_meta_list: list) -> list: """ Unifying list of dicts with metadata, so every dict will have same keys :param list processed_meta_list: list of dicts with metadata - :return str: list of unified dicts with metadata + :return list: list of unified dicts with metadata """ list_of_keys = self._get_list_of_keys(processed_meta_list) for k in list_of_keys: @@ -826,7 +851,7 @@ def _unify_list_keys(self, processed_meta_list): def _find_genome(self, metadata_list): """ - Create new genome table by joining few columns + Create new genome column by searching joining few columns """ list_keys = self._get_list_of_keys(metadata_list) genome_keys = [ @@ -842,14 +867,14 @@ def _find_genome(self, metadata_list): metadata_list[sample[0]][NEW_GENOME_COL_NAME] = sample_genome return metadata_list - def _write_gsm_annotation(self, gsm_metadata, file_annotation): + def _write_gsm_annotation(self, gsm_metadata: dict, file_annotation: str) -> str: """ Write metadata sheet out as an annotation file. :param Mapping gsm_metadata: the data to write, parsed from a file with metadata/annotation information :param str file_annotation: the path to the file to write - :return str: path to file written + :return str: path to the file """ keys = list(list(gsm_metadata.values())[0].keys()) @@ -879,7 +904,7 @@ def _write_processed_annotation( :param list processed_metadata: list of dictionaries with files metadata :param str file_annotation_path: the path to the metadata file that has to be saved :type just_object: True, if you want to get peppy object without saving file - :return: + :return: none, or peppy project """ if len(processed_metadata) == 0: self._LOGGER.info( @@ -944,9 +969,9 @@ def _write_raw_annotation_new( """ Combining individual accessions into project-level annotations, and writing individual accession files (if requested) - :param name: - :param metadata_dict: - :param subannot_dict: + :param name: Name of the run, project, or acc --> will influence name of the folder where project will be created + :param metadata_dict: dictionary of sample annotations + :param subannot_dict: dictionary of subsample annotations :return: none or peppy object """ try: @@ -1031,7 +1056,15 @@ def _write_raw_annotation_new( proj = peppy.Project().from_pandas(meta_df, sub_meta_df, conf) return proj - def _create_config_processed(self, file_annotation_path, proj_meta): + def _create_config_processed( + self, file_annotation_path: str, proj_meta: list + ) -> str: + """ + completing and generating config file content + :param file_annotation_path: root to the annotation file + :param proj_meta: common metadata that has to added to config file + :return: generated, complete config file content + """ geofetchdir = os.path.dirname(__file__) config_template = os.path.join(geofetchdir, CONFIG_PROCESSED_TEMPLATE_NAME) with open(config_template, "r") as template_file: @@ -1054,6 +1087,13 @@ def _create_config_processed(self, file_annotation_path, proj_meta): return template def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): + """ + completing and generating config file content for raw data + :param proj_meta: root to the annotation file + :param proj_root_sample: path to sampletable file + :param subanot_path_yaml: path to subannotation file + :return: generated, complete config file content + """ meta_list_str = [ f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta ] @@ -1077,7 +1117,13 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): template = template.replace(placeholder, str(v)) return template - def _check_sample_name_standard(self, metadata_dict): + def _check_sample_name_standard(self, metadata_dict: dict) -> dict: + """ + Standardizing sample name and checking if it exists + (This function is used for raw data) + :param metadata_dict: metadata dict + :return: metadata dict with standardize sample names + """ fixed_dict = {} for key_sample, value_sample in metadata_dict.items(): fixed_dict[key_sample] = value_sample @@ -1092,7 +1138,7 @@ def _check_sample_name_standard(self, metadata_dict): return metadata_dict @staticmethod - def _sanitize_name(name_str: str): + def _sanitize_name(name_str: str) -> str: """ Function that sanitizing strings. (Replace all odd characters) :param str name_str: Any string value that has to be sanitized. @@ -1106,7 +1152,7 @@ def _sanitize_name(name_str: str): return new_str @staticmethod - def _create_dot_yaml(file_path: str, yaml_path: str): + def _create_dot_yaml(file_path: str, yaml_path: str) -> NoReturn: """ Function that creates .pep.yaml file that points to actual yaml file :param str file_path: Path to the .pep.yaml file that we want to create @@ -1121,7 +1167,7 @@ def _separate_common_meta( max_len: int = 50, del_limit: int = 250, attr_limit_truncate: int = 500, - ): + ) -> tuple: """ This function is separating information for the experiment from a sample :param list or dict meta_list: list of dictionaries of samples @@ -1195,7 +1241,7 @@ def _separate_common_meta( meta_list = self._dict_to_list_convector(proj_list=meta_list) return meta_list, new_meta_project - def _standardize_colnames(self, meta_list: Union[list, dict]): + def _standardize_colnames(self, meta_list: Union[list, dict]) -> Union[list, dict]: """ Standardize column names by lower-casing and underscore :param list meta_list: list of dictionaries of samples @@ -1256,7 +1302,7 @@ def _dict_to_list_convector( return meta_list - def _download_SRA_file(self, run_name): + def _download_SRA_file(self, run_name: str): """ Downloading SRA file by ising 'prefetch' utility from the SRA Toolkit more info: (http://www.ncbi.nlm.nih.gov/books/NBK242621/) @@ -1285,7 +1331,7 @@ def _download_SRA_file(self, run_name): time.sleep(t * 2) @staticmethod - def _which(program): + def _which(program: str): """ return str: the path to a program to make sure it exists """ @@ -1305,7 +1351,7 @@ def is_exe(fp): if is_exe(exe_file): return exe_file - def _sra_bam_conversion(self, bam_file, run_name): + def _sra_bam_conversion(self, bam_file: str, run_name: str) -> NoReturn: """ Converting of SRA file to BAM file by using samtools function "sam-dump" :param str bam_file: path to BAM file that has to be created @@ -1330,7 +1376,9 @@ def _sra_bam_conversion(self, bam_file, run_name): run_subprocess(cmd, shell=True) @staticmethod - def _update_columns(metadata, experiment_name, sample_name, read_type): + def _update_columns( + metadata: dict, experiment_name: str, sample_name: str, read_type: str + ) -> dict: """ Update the metadata associated with a particular experiment. @@ -1346,7 +1394,7 @@ def _update_columns(metadata, experiment_name, sample_name, read_type): associated :param str read_type: usually "single" or "paired," an indication of the type of sequencing reads for this experiment - :return Mapping: + :return: updated metadata """ exp = metadata[experiment_name] @@ -1374,7 +1422,9 @@ def _update_columns(metadata, experiment_name, sample_name, read_type): return exp - def _sra_bam_conversion2(self, bam_file, run_name, picard_path=None): + def _sra_bam_conversion2( + self, bam_file: str, run_name: str, picard_path: str = None + ) -> NoReturn: """ Converting of SRA file to BAM file by using fastq-dump (is used when sam-dump fails, yielding an empty bam file. Here fastq -> bam conversion is used) @@ -1413,7 +1463,9 @@ def _sra_bam_conversion2(self, bam_file, run_name, picard_path=None): self._LOGGER.info(f"Conversion command: {cmd}") run_subprocess(cmd, shell=True) - def _write_subannotation(self, tabular_data, filepath, column_names=None): + def _write_subannotation( + self, tabular_data: dict, filepath: str, column_names: list = None + ): """ Writes one or more tables to a given CSV filepath. @@ -1440,7 +1492,9 @@ def _write_subannotation(self, tabular_data, filepath, column_names=None): writer.writerows(values) return fp - def _download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): + def _download_file( + self, file_url: str, data_folder: str, new_name: str = None, sleep_after=0.5 + ) -> NoReturn: """ Given an url for a file, downloading to specified folder :param str file_url: the URL of the file to download @@ -1470,12 +1524,12 @@ def _download_file(self, file_url, data_folder, new_name=None, sleep_after=0.5): def _get_list_of_processed_files( self, file_gse_content: list, file_gsm_content: list - ): + ) -> tuple: """ Given a paths to GSE and GSM metafile create a list of dicts of metadata of processed files :param list file_gse_content: list of lines of gse metafile :param list file_gsm_content: list of lines of gse metafile - :return list: list of metadata of processed files + :return: tuple[list of metadata of processed sample files and series files] """ tar_re = re.compile(r".*\.tar$") gse_numb = None @@ -1640,7 +1694,7 @@ def _get_list_of_processed_files( return meta_processed_samples, meta_processed_series @staticmethod - def _check_file_existance(meta_processed_sample): + def _check_file_existance(meta_processed_sample: list): """ Checking if last element of the list has files. If list of files is empty deleting it """ @@ -1769,18 +1823,13 @@ def _get_value(all_line: str): line_value = all_line.split("= ")[-1] return line_value.split(": ")[-1].rstrip("\n") - def _download_processed_file(self, file_url, data_folder): + def _download_processed_file(self, file_url: str, data_folder: str) -> bool: """ Given a url for a file, download it, and extract anything passing the filter. :param str file_url: the URL of the file to download :param str data_folder: the local folder where the file should be saved :return bool: True if the file is downloaded successfully; false if it does not pass filters and is not downloaded. - - # :param re.Pattern tar_re: a regulator expression (produced from re.compile) - # that pulls out filenames with .tar in them --- deleted - # :param re.Pattern filter_re: a regular expression (produced from - # re.compile) to filter filenames of interest. """ if not self.geo_folder: @@ -2027,7 +2076,20 @@ def _read_gsm_metadata( gsm_metadata = self._expand_metadata_list_in_dict(gsm_metadata) return gsm_metadata - def _write(self, f_var_value, content, msg_pre=None, omit_newline=False): + def _write( + self, + f_var_value: str, + content: str, + msg_pre: str = None, + omit_newline: bool = False, + ): + """ + Save new file (used for config file) + :param f_var_value: path to the file + :param content: content of the file + :param msg_pre: msg that have to be printed + :param omit_newline: omit new line + """ fp = expandpath(f_var_value) self._LOGGER.info((msg_pre or "") + fp) with open(fp, "w") as f: @@ -2037,6 +2099,9 @@ def _write(self, f_var_value, content, msg_pre=None, omit_newline=False): def _parse_cmdl(cmdl): + """ + parser + """ parser = argparse.ArgumentParser( description="Automatic GEO and SRA data downloader" ) From d7b2b702a55c05c4a7a00d14c068dc08d473753a Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 1 Sep 2022 15:46:45 -0400 Subject: [PATCH 30/61] naming correction --- geofetch/geofetch.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index bb0bff2..c422acc 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -215,7 +215,7 @@ def get_project( ) project_dict.update(self.fetch_all(input=acc_GSE, name=acc_GSE)) else: - project_dict.update(self.fetch_all(input=input, name="project")) + project_dict.update(self.fetch_all(input=input, name="")) # raw data: else: @@ -234,15 +234,17 @@ def get_project( else: ser_dict = self.fetch_all(input=input) - project_dict["raw_samples"] = ser_dict + project_dict["raw"] = ser_dict return project_dict def fetch_all(self, input: str, name: str = None): """Main script driver/workflow""" - if name: + if name is not None: self.project_name = name + print("------------------------") + print(self.project_name) else: try: self.project_name = os.path.splitext(os.path.basename(input))[0] @@ -413,7 +415,7 @@ def fetch_all(self, input: str, name: str = None): if self.processed: if not self.acc_anno: return_value = self._generate_processed_meta( - name="PEP_processed", + name=self.project_name, meta_processed_samples=processed_metadata_samples, meta_processed_series=processed_metadata_series, ) From a88a02b29961e3e71a3df82e2e022f31bf9bd501 Mon Sep 17 00:00:00 2001 From: Nathan Sheffield Date: Fri, 2 Sep 2022 14:16:38 -0400 Subject: [PATCH 31/61] use https --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ed5c01e..98e381c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # geofetch logo -[![PEP compatible](http://pepkit.github.io/img/PEP-compatible-green.svg)](http://pepkit.github.io) +[![PEP compatible](https://pepkit.github.io/img/PEP-compatible-green.svg)](https://pepkit.github.io) ![Run pytests](https://github.com/pepkit/geofetch/workflows/Run%20pytests/badge.svg) -[![docs-badge](https://readthedocs.org/projects/geofetch/badge/?version=latest)](http://geofetch.databio.org/en/latest/) +[![docs-badge](https://readthedocs.org/projects/geofetch/badge/?version=latest)](https://geofetch.databio.org/en/latest/) [![pypi-badge](https://img.shields.io/pypi/v/geofetch)](https://pypi.org/project/geofetch) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -`geofetch` is a command-line tool that downloads sequencing data and metadata from GEO and SRA and creates [standard PEPs](http://pep.databio.org/). `geofetch` is hosted at [pypi](https://pypi.org/project/geofetch/) and documentation is hosted at [geofetch.databio.org](http://geofetch.databio.org) (source in the [/docs](/docs) folder). +`geofetch` is a command-line tool that downloads sequencing data and metadata from GEO and SRA and creates [standard PEPs](https://pep.databio.org/). `geofetch` is hosted at [pypi](https://pypi.org/project/geofetch/) and documentation is hosted at [geofetch.databio.org](https://geofetch.databio.org) (source in the [/docs](/docs) folder). You can convert the result of geofetch into unmapped `bam` or `fastq` files with the included `sraconvert` command. From cb464afa55a8cc4637480ba0ba651cef9cb84654 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 2 Sep 2022 17:42:19 -0400 Subject: [PATCH 32/61] Added tests --- tests/test_geofetch.py | 101 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 10 deletions(-) diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index d3fa7de..ae0029c 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -1,3 +1,5 @@ +import peppy + import geofetch from geofetch import parse_accessions, Geofetcher, utils import os @@ -62,7 +64,7 @@ def test_accessions_file(self): class TestListProcessedMetaFiles: """ - Testing + Testing downloading and saving process soft files """ @pytest.fixture(scope="function") @@ -107,22 +109,50 @@ def test_downloading_soft_files(self, initiate_geofetcher): assert "GSE138657_GSE.soft" in downloaded_meta_files def test_creating_sample_pep_files(self, initiate_geofetcher): - initiate_geofetcher.fetch_all("GSE138657") + gse_numb = "GSE138657" + initiate_geofetcher.fetch_all(gse_numb) + downloaded_meta_files = list( + os.walk(initiate_geofetcher.metadata_expanded + f"/{gse_numb}_samples") + )[0][2] + + assert f"{gse_numb}_samples.csv" in downloaded_meta_files + assert f"{gse_numb}_samples.yaml" in downloaded_meta_files + + def test_creating_series_pep_files(self, initiate_geofetcher): + gse_numb = "GSE199313" + initiate_geofetcher.fetch_all(gse_numb) downloaded_meta_files = list( - os.walk(initiate_geofetcher.metadata_expanded + "/PEP_processed_samples") + os.walk(initiate_geofetcher.metadata_expanded + f"/{gse_numb}_series") )[0][2] - assert "PEP_processed_samples.csv" in downloaded_meta_files - assert "PEP_processed_samples.yaml" in downloaded_meta_files + assert f"{gse_numb}_series.csv" in downloaded_meta_files + assert f"{gse_numb}_series.yaml" in downloaded_meta_files + + +class TestListRawMetaFiles: + """ + Testing downloading and saving raw files and metadata + """ + @pytest.fixture(scope="function") + def initiate_geofetcher(self, tmpdir): + instance = Geofetcher( + just_metadata=True, + processed=False, + name="test", + metadata_folder=tmpdir, + discard_soft=True, + ) + yield instance def test_creating_series_pep_files(self, initiate_geofetcher): - initiate_geofetcher.fetch_all("GSE199313") + initiate_geofetcher.fetch_all("GSE138656") downloaded_meta_files = list( - os.walk(initiate_geofetcher.metadata_expanded + "/PEP_processed_series") + os.walk(initiate_geofetcher.metadata_expanded + f"/PEP") )[0][2] - assert "PEP_processed_series.csv" in downloaded_meta_files - assert "PEP_processed_series.yaml" in downloaded_meta_files + assert "PEP_raw.csv" in downloaded_meta_files + assert "PEP.yaml" in downloaded_meta_files + assert "PEP_raw_subtable.csv" in downloaded_meta_files class TestDownloadingProcFiles: @@ -165,7 +195,7 @@ def initiate_geofetcher(self, tmpdir): processed=True, name="test", metadata_folder=tmpdir, - filter="\.Bed.gz$", + filter=r"\.Bed.gz$", filter_size="2MB", ) yield instance @@ -264,6 +294,57 @@ def test_large_meta_separation( assert samp == result_sample assert proj == result_proj +class TestPeppyInitProcessed: + """ + Testing downloading and saving raw files and metadata + """ + @pytest.fixture(scope="function") + def initiate_geofetcher(self, tmpdir): + instance = Geofetcher( + just_metadata=True, + processed=True, + name="test", + metadata_folder=tmpdir, + discard_soft=True, + data_source="all" + ) + yield instance + + def test_creating_processed_peppy(self, initiate_geofetcher): + p_prop = initiate_geofetcher.get_project("GSE190287") + assert isinstance(p_prop['_samples'], peppy.Project) + assert isinstance(p_prop['_series'], peppy.Project) + + def test_number_of_samples(self, initiate_geofetcher): + p_prop = initiate_geofetcher.get_project("GSE190287") + assert len(p_prop['_samples'].samples) == 8 #it has 11 files but 8 samples + assert len(p_prop['_series'].samples) == 2 + +class TestPeppyInitRaw: + """ + Testing downloading and saving raw files and metadata + """ + + @pytest.fixture(scope="function") + def initiate_geofetcher(self, tmpdir): + instance = Geofetcher( + just_metadata=True, + processed=False, + name="test", + metadata_folder=tmpdir, + discard_soft=True, + ) + yield instance + + def test_creating_processed_peppy(self, initiate_geofetcher): + p_prop = initiate_geofetcher.get_project("GSE189141") + assert isinstance(p_prop['raw'], peppy.Project) + + def test_number_of_samples(self, initiate_geofetcher): + p_prop = initiate_geofetcher.get_project("GSE189141") + a = ([d['sample_name'] for d in p_prop['raw'].samples]) + assert len(p_prop['raw'].samples) == 16 #it has 16 samples + def test_clean_func(tmpdir): """ From 07f6cadbf3c1e60d7fabed733430236d6773082d Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 6 Sep 2022 11:37:06 -0400 Subject: [PATCH 33/61] added docstring --- geofetch/geofetch.py | 76 +++++++++++++++++++++++++++++++++++++++--- tests/test_geofetch.py | 20 ++++++----- 2 files changed, 84 insertions(+), 12 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index c422acc..d7a3679 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -41,6 +41,64 @@ class Geofetcher: """ Class to download or get projects, metadata, data from GEO and SRA + + :param input: + :param name: Specify a project name. Defaults to GSE number or name of accessions file name + :param metadata_root: Specify a parent folder location to store metadata. + The project name will be added as a subfolder [Default: $SRAMETA:] + :param metadata_folder: Specify an absolute folder location to store metadata. No subfolder will be added. + Overrides value of --metadata-root [Default: Not used (--metadata-root is used by default)] + :param just_metadata: If set, don't actually run downloads, just create metadata + :param refresh_metadata: If set, re-download metadata even if it exists. + :param config_template: Project config yaml file template. + :param pipeline_samples: Specify one or more filepaths to SAMPLES pipeline interface yaml files. + These will be added to the project config file to make it immediately compatible with looper. + [Default: null] + :param pipeline_project: Specify one or more filepaths to PROJECT pipeline interface yaml files. + These will be added to the project config file to make it immediately compatible with looper. + [Default: null] + :param acc_anno: Produce annotation sheets for each accession. + Project combined PEP for the whole project won't be produced. + :param discard_soft: Create project without downloading soft files on the disc + :param add_dotfile: Add .pep.yaml file that points .yaml PEP file + :param disable_progressbar: Set true to disable progressbar + + :param const_limit_project: Optional: Limit of the number of the constant sample characters + that should not be in project yaml. [Default: 50] + :param const_limit_discard: Optional: Limit of the number of the constant sample characters + that should not be discarded [Default: 250] + :param attr_limit_truncate: Optional: Limit of the number of sample characters. + Any attribute with more than X characters will truncate to the first X, where X is a number of characters + [Default: 500] + + :param processed: Download processed data [Default: download raw data]. + :param data_source: Specifies the source of data on the GEO record to retrieve processed data, + which may be attached to the collective series entity, or to individual samples. Allowable values are: + samples, series or both (all). Ignored unless 'processed' flag is set. [Default: samples] + :param filter: Filter regex for processed filenames [Default: None].Ignored unless 'processed' flag is set. + :param filter_size: Filter size for processed files that are stored as sample repository [Default: None]. + Works only for sample data. Supported input formats : 12B, 12KB, 12MB, 12GB. + Ignored unless 'processed' flag is set. + :param geo_folder: Specify a location to store processed GEO files. + Ignored unless 'processed' flag is set.[Default: $GEODATA:] + + :param split_experiments: Split SRR runs into individual samples. By default, SRX experiments with multiple SRR + Runs will have a single entry in the annotation table, with each run as a separate row in the + subannotation table. This setting instead treats each run as a separate sample [Works with raw data] + :param bam_folder: Optional: Specify folder of bam files. Geofetch will not download sra files when + corresponding bam files already exist. [Default: $SRABAM:] [Works with raw data] + :param fq_folder: Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding + fastq files already exist. [Default: $SRAFQ:] [Works with raw data] + :param use_key_subset: Use just the keys defined in this module when writing out metadata. [Works with raw data] + :param sra_folder: [Doesn't work ]Optional: Specify a location to store sra files + [Default: $SRARAW:" + safe_echo("SRARAW") + ] + :param bam_conversion: Optional: set True to convert bam files [Works with raw data] + :param picard_path: Specify a path to the picard jar, if you want to convert fastq to bam + [Default: $PICARD:" + safe_echo("PICARD") + "] [Works with raw data] + + :param skip: Skip some accessions. [Default: no skip]. + :param opts: opts object [Optional] + :param kwargs: other values """ def __init__( @@ -194,7 +252,6 @@ def get_project( """ self.just_metadata = just_metadata self.just_object = True - self.disable_progressbar = True self.discard_soft = discard_soft acc_GSE_list = parse_accessions( input, self.metadata_expanded, self.just_metadata @@ -205,6 +262,7 @@ def get_project( # processed data: if self.processed: if self.acc_anno: + self.disable_progressbar = True nkeys = len(acc_GSE_list.keys()) ncount = 0 self.acc_anno = False @@ -221,6 +279,7 @@ def get_project( else: # Not sure about below code... if self.acc_anno: + self.disable_progressbar = True self.acc_anno = False nkeys = len(acc_GSE_list.keys()) ncount = 0 @@ -236,14 +295,18 @@ def get_project( ser_dict = self.fetch_all(input=input) project_dict["raw"] = ser_dict - return project_dict + new_pr_dict = {} + for pr_key in project_dict.keys(): + if project_dict[pr_key]: + new_pr_dict[pr_key] = project_dict[pr_key] + + return new_pr_dict def fetch_all(self, input: str, name: str = None): """Main script driver/workflow""" if name is not None: self.project_name = name - print("------------------------") print(self.project_name) else: try: @@ -284,7 +347,7 @@ def fetch_all(self, input: str, name: str = None): elif ncount == self.skip + 1: self._LOGGER.info(f"Skipped {self.skip} accessions. Starting now.") - if not self.just_object: + if not self.just_object or not self.acc_anno: self._LOGGER.info( f"\033[38;5;200mProcessing accession {ncount} of {nkeys}: '{acc_GSE}'\033[0m" ) @@ -2355,6 +2418,11 @@ def _parse_cmdl(cmdl): action="store_true", help="Use just the keys defined in this module when writing out metadata.", ) + raw_group.add_argument( + "--bam-conversion", + action="store_true", + help="specify this argument to convert bam files", + ) logmuse.add_logging_options(parser) return parser.parse_args(cmdl) diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index ae0029c..da9f788 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -133,6 +133,7 @@ class TestListRawMetaFiles: """ Testing downloading and saving raw files and metadata """ + @pytest.fixture(scope="function") def initiate_geofetcher(self, tmpdir): instance = Geofetcher( @@ -294,10 +295,12 @@ def test_large_meta_separation( assert samp == result_sample assert proj == result_proj + class TestPeppyInitProcessed: """ Testing downloading and saving raw files and metadata """ + @pytest.fixture(scope="function") def initiate_geofetcher(self, tmpdir): instance = Geofetcher( @@ -306,19 +309,20 @@ def initiate_geofetcher(self, tmpdir): name="test", metadata_folder=tmpdir, discard_soft=True, - data_source="all" + data_source="all", ) yield instance def test_creating_processed_peppy(self, initiate_geofetcher): p_prop = initiate_geofetcher.get_project("GSE190287") - assert isinstance(p_prop['_samples'], peppy.Project) - assert isinstance(p_prop['_series'], peppy.Project) + assert isinstance(p_prop["_samples"], peppy.Project) + assert isinstance(p_prop["_series"], peppy.Project) def test_number_of_samples(self, initiate_geofetcher): p_prop = initiate_geofetcher.get_project("GSE190287") - assert len(p_prop['_samples'].samples) == 8 #it has 11 files but 8 samples - assert len(p_prop['_series'].samples) == 2 + assert len(p_prop["_samples"].samples) == 8 # it has 11 files but 8 samples + assert len(p_prop["_series"].samples) == 2 + class TestPeppyInitRaw: """ @@ -338,12 +342,12 @@ def initiate_geofetcher(self, tmpdir): def test_creating_processed_peppy(self, initiate_geofetcher): p_prop = initiate_geofetcher.get_project("GSE189141") - assert isinstance(p_prop['raw'], peppy.Project) + assert isinstance(p_prop["raw"], peppy.Project) def test_number_of_samples(self, initiate_geofetcher): p_prop = initiate_geofetcher.get_project("GSE189141") - a = ([d['sample_name'] for d in p_prop['raw'].samples]) - assert len(p_prop['raw'].samples) == 16 #it has 16 samples + a = [d["sample_name"] for d in p_prop["raw"].samples] + assert len(p_prop["raw"].samples) == 16 # it has 16 samples def test_clean_func(tmpdir): From 528a7fc6afc3a900abe5bb29cff0c4e969a414d7 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 6 Sep 2022 14:47:20 -0400 Subject: [PATCH 34/61] Added documentation --- .github/workflows/run-codecov.yml | 2 +- docs/README.md | 18 + docs/changelog.md | 7 +- docs/img/arguments_outputs.svg | 8186 +++++++++++++++++ docs/img/pipeline.svg | 8072 ++++++++++++++++ docs/install.md | 32 +- docs/metadata_output.md | 9 +- docs/usage.md | 112 +- .../build/processed-data-downloading.md | 125 +- docs_jupyter/processed-data-downloading.ipynb | 152 +- docs_jupyter/python-usage.ipynb | 725 ++ geofetch/geofetch.py | 5 - mkdocs.yml | 2 + 13 files changed, 17128 insertions(+), 319 deletions(-) create mode 100644 docs/img/arguments_outputs.svg create mode 100644 docs/img/pipeline.svg create mode 100644 docs_jupyter/python-usage.ipynb diff --git a/.github/workflows/run-codecov.yml b/.github/workflows/run-codecov.yml index a41a1fd..1db19ff 100644 --- a/.github/workflows/run-codecov.yml +++ b/.github/workflows/run-codecov.yml @@ -2,7 +2,7 @@ name: Run codecov on: pull_request: - branches: [master] + branches: [master, dev] jobs: pytest: diff --git a/docs/README.md b/docs/README.md index 1cc4626..2f21910 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,6 +12,8 @@ - Produce a standardized [PEP](http://pepkit.github.io) sample table. This makes it really easy to run [looper](https://pepkit.github.io/docs/looper/)-compatible pipelines on public datasets by handling data acquisition and metadata formatting and standardization for you. - Prepare a project to run with [sraconvert](sra_convert.md) to convert SRA files into FASTQ files. +![](./img/pipeline.svg) + ## Quick example `geofetch` runs on the command line. This command will download the raw data and metadata for the given GSE number. @@ -38,5 +40,21 @@ geofetch -i GSE95654 --just-metadata geofetch -i GSE95654 --processed --just-metadata ``` +### Check out what exactly argument you want to use to download data: + +![](./img/arguments_outputs.svg) + +### New geofetch 0.11.0 feature: +- Now geofetch is available as Python package to straight initiate [peppy](http://peppy.databio.org/) projects without downloading any soft files. +```python +from geofetch import Geofetcher + +# initiate Geofetcher with all necessary arguments: +geof = Geofetcher(processed=True, acc_anno=True, discard_soft=True) + +# get projects by providing as input GSE or file with GSEs +geof.get_project("GSE160204") +``` + For more details, check out the [usage](usage.md) reference, [installation instructions](install.md), or head on over to the [tutorial for raw data](raw-data-downloading.md) and [tutorial for processed data](processed-data-downloading.md) for a detailed walkthrough. diff --git a/docs/changelog.md b/docs/changelog.md index 89bcb72..23c3729 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,11 +1,12 @@ # Changelog -## [0.11.0] -- 2022-XX-XX +## [0.11.0] -- 2022-09-06 - Added initialization of peppy Project without saving any files functionality - Added progress bar - Fixed None issue in config file -- Changed way of saving soft files to request library -- +- Switched way of saving soft files to request library +- Fixed saving raw peps bug +- Refactored code ## [0.10.1] -- 2022-08-04 - Updated metadata fetching requests from SRA database diff --git a/docs/img/arguments_outputs.svg b/docs/img/arguments_outputs.svg new file mode 100644 index 0000000..89cb3c5 --- /dev/null +++ b/docs/img/arguments_outputs.svg @@ -0,0 +1,8186 @@ + + + +--processed --just-metadata --data-source samples--processed--data-source samples--processed --just-metadata--data-source series--processed--data-source series--processed--data-source all--processed --just-metadata --data-source allArguments#12345678--just-metadataOutputData SourceSamplesSamplesSeriesSeriesallallSamplesSamplesMetadataProcessedProcessedProcessedProcessedProcessedProcessedRawRawDataProcessedProcessedProcessedNoneNoneNoneRawNone diff --git a/docs/img/pipeline.svg b/docs/img/pipeline.svg new file mode 100644 index 0000000..ef4d501 --- /dev/null +++ b/docs/img/pipeline.svg @@ -0,0 +1,8072 @@ + + + +geofetchgeofetchPortableEncapsulatedProjectpeppypeprGEO/SRAData diff --git a/docs/install.md b/docs/install.md index 355cd70..01c9c12 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,21 +1,5 @@ # Installing geofetch -## Prerequisites - -You must have the [sratoolkit from NCBI](https://www.ncbi.nlm.nih.gov/books/NBK158900/) installed, with the tools in your PATH. Once it's installed, you should check to make sure you can run `prefetch`. Also, make sure it's configured to store SRA files where you want them. For more information, see how to change sratools download location. - -## Setting data download location for `sratools` - -`geofetch` is using the [sratoolkit](https://trace.ncbi.nlm.nih.gov/Traces/sra/?view=toolkit_doc&f=std) to download raw data from SRA -- which means it's stuck with the [default path for downloading SRA data](http://databio.org/posts/downloading_sra_data.html), which is in your home directory. So before you run `geofetch`, make sure you have set up your download location to the correct place. In our group, we use a shared group environment variable called `${SRARAW}`, which points to a shared folder (`${DATA}/sra`) where the whole group has access to downloaded SRA data. You can point the `sratoolkit` (and therefore `geofetch`) to use that location with this one-time configuration code: - -``` -echo "/repository/user/main/public/root = \"$DATA\"" > ${HOME}/.ncbi/user-settings.mkfg -``` - -Now `sratoolkit` will download data into an `/sra` folder in `${DATA}`, which is what `${SRARAW}` points to. - -If you are getting an error that the `.ncbi` folder does not exist in your home directory, you can just make a folder `.ncbi` with an empty file `user-settings.mkfg` and follow the same command above. - ## Installing geofetch Releases are posted as [GitHub releases](https://github.com/pepkit/geofetch/releases), or you can install from PyPI using `pip`: @@ -35,3 +19,19 @@ If the executable in not in your $PATH, append this to your `.bashrc` or `.profi ``` export PATH=~/.local/bin:$PATH ``` + +## Prerequisites for SRA data downloading + +To download **raw data** You must have the [sratoolkit from NCBI](https://www.ncbi.nlm.nih.gov/books/NBK158900/) installed, with the tools in your PATH. Once it's installed, you should check to make sure you can run `prefetch`. Also, make sure it's configured to store SRA files where you want them. For more information, see how to change sratools download location. + +## Setting data download location for `sratools` + +`geofetch` is using the [sratoolkit](https://trace.ncbi.nlm.nih.gov/Traces/sra/?view=toolkit_doc&f=std) to download raw data from SRA -- which means it's stuck with the [default path for downloading SRA data](http://databio.org/posts/downloading_sra_data.html), which is in your home directory. So before you run `geofetch`, make sure you have set up your download location to the correct place. In our group, we use a shared group environment variable called `${SRARAW}`, which points to a shared folder (`${DATA}/sra`) where the whole group has access to downloaded SRA data. You can point the `sratoolkit` (and therefore `geofetch`) to use that location with this one-time configuration code: + +``` +echo "/repository/user/main/public/root = \"$DATA\"" > ${HOME}/.ncbi/user-settings.mkfg +``` + +Now `sratoolkit` will download data into an `/sra` folder in `${DATA}`, which is what `${SRARAW}` points to. + +If you are getting an error that the `.ncbi` folder does not exist in your home directory, you can just make a folder `.ncbi` with an empty file `user-settings.mkfg` and follow the same command above. \ No newline at end of file diff --git a/docs/metadata_output.md b/docs/metadata_output.md index 3c2eace..e9f5fde 100644 --- a/docs/metadata_output.md +++ b/docs/metadata_output.md @@ -1,12 +1,17 @@ # Metadata output -For each GSE input accession (ACC), `geofetch` produces: +Geofetch produces [PEPs](http://pep.databio.org/) for either processed or raw data (including metadata from SRA). + +# Outdated: + +For each GSE input accession (ACC), `geofetch` produces (if discard-soft is not set): - GSE_ACC####.soft a SOFT file (annotating the experiment itself) - GSM_ACC####.soft a SOFT file (annotating the samples within the experiment) - SRA_ACC####.soft a CSV file (annotating each SRA Run, retrieved from GSE->GSM->SRA) -In addition, a single combined metadata file (.csv) for the whole input, +For raw data: +a single combined metadata file (.csv) will be created for the whole input, including SRA and GSM annotations for each sample. Here, "combined" means that it will have rows for every sample in every GSE included in your input. So if you just gave a single GSE, then the combined file is the same as the GSE file. If any "merged" samples exist diff --git a/docs/usage.md b/docs/usage.md index 89b3fad..29ba6b1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,19 +1,24 @@ -# - -Usage reference - -`geofetch` command-line usage instructions: +# Usage reference +geofetch command-line usage instructions: +`geofetch -V` +```console +geofetch 0.11.0 +``` `geofetch --help` -```{console} -usage: geofetch [-h] [-V] -i INPUT [-n NAME] [-m METADATA_ROOT] [-u METADATA_FOLDER] [--just-metadata] [-r] [--config-template CONFIG_TEMPLATE] - [--pipeline_samples PIPELINE_SAMPLES] [--pipeline_project PIPELINE_PROJECT] [-k SKIP] [--acc-anno] [--discard-soft] - [--const-limit-project CONST_LIMIT_PROJECT] [--const-limit-discard CONST_LIMIT_DISCARD] - [--attr-limit-truncate ATTR_LIMIT_TRUNCATE] [-p] [--data-source {all,samples,series}] [--filter FILTER] - [--filter-size FILTER_SIZE] [-g GEO_FOLDER] [-x] [-b BAM_FOLDER] [-f FQ_FOLDER] [--use-key-subset] [--silent] [--verbosity V] - [--logdev] +```console +usage: geofetch [-h] [-V] -i INPUT [-n NAME] [-m METADATA_ROOT] [-u METADATA_FOLDER] + [--just-metadata] [-r] [--config-template CONFIG_TEMPLATE] + [--pipeline-samples PIPELINE_SAMPLES] [--pipeline-project PIPELINE_PROJECT] + [--disable-progressbar] [-k SKIP] [--acc-anno] [--discard-soft] + [--const-limit-project CONST_LIMIT_PROJECT] + [--const-limit-discard CONST_LIMIT_DISCARD] + [--attr-limit-truncate ATTR_LIMIT_TRUNCATE] [--add-dotfile] [-p] + [--data-source {all,samples,series}] [--filter FILTER] + [--filter-size FILTER_SIZE] [-g GEO_FOLDER] [-x] [-b BAM_FOLDER] + [-f FQ_FOLDER] [--use-key-subset] [--silent] [--verbosity V] [--logdev] Automatic GEO and SRA data downloader @@ -21,34 +26,47 @@ optional arguments: -h, --help show this help message and exit -V, --version show program's version number and exit -i INPUT, --input INPUT - required: a GEO (GSE) accession, or a file with a list of GSE numbers + required: a GEO (GSE) accession, or a file with a list of GSE + numbers -n NAME, --name NAME Specify a project name. Defaults to GSE number -m METADATA_ROOT, --metadata-root METADATA_ROOT - Specify a parent folder location to store metadata. The project name will be added as a subfolder [Default: $SRAMETA:] + Specify a parent folder location to store metadata. The project name + will be added as a subfolder [Default: $SRAMETA:] -u METADATA_FOLDER, --metadata-folder METADATA_FOLDER - Specify an absolute folder location to store metadata. No subfolder will be added. Overrides value of --metadata-root - [Default: Not used (--metadata-root is used by default)] + Specify an absolute folder location to store metadata. No subfolder + will be added. Overrides value of --metadata-root [Default: Not used + (--metadata-root is used by default)] --just-metadata If set, don't actually run downloads, just create metadata -r, --refresh-metadata If set, re-download metadata even if it exists. --config-template CONFIG_TEMPLATE Project config yaml file template. - --pipeline_samples PIPELINE_SAMPLES - Optional: Specify one or more filepaths to SAMPLES pipeline interface yaml files. These will be added to the project - config file to make it immediately compatible with looper. [Default: null] - --pipeline_project PIPELINE_PROJECT - Optional: Specify one or more filepaths to PROJECT pipeline interface yaml files. These will be added to the project - config file to make it immediately compatible with looper. [Default: null] + --pipeline-samples PIPELINE_SAMPLES + Optional: Specify one or more filepaths to SAMPLES pipeline + interface yaml files. These will be added to the project config file + to make it immediately compatible with looper. [Default: null] + --pipeline-project PIPELINE_PROJECT + Optional: Specify one or more filepaths to PROJECT pipeline + interface yaml files. These will be added to the project config file + to make it immediately compatible with looper. [Default: null] + --disable-progressbar + Optional: Disable progressbar -k SKIP, --skip SKIP Skip some accessions. [Default: no skip]. - --acc-anno Optional: Produce annotation sheets for each accession. Project combined PEP for the whole project won't be produced. - --discard-soft Optional: After creation of PEP files, all soft and additional files will be deleted + --acc-anno Optional: Produce annotation sheets for each accession. Project + combined PEP for the whole project won't be produced. + --discard-soft Optional: After creation of PEP files, all soft and additional files + will be deleted --const-limit-project CONST_LIMIT_PROJECT - Optional: Limit of the number of the constant sample characters that should not be in project yaml. [Default: 50] + Optional: Limit of the number of the constant sample characters that + should not be in project yaml. [Default: 50] --const-limit-discard CONST_LIMIT_DISCARD - Optional: Limit of the number of the constant sample characters that should not be discarded [Default: 250] + Optional: Limit of the number of the constant sample characters that + should not be discarded [Default: 250] --attr-limit-truncate ATTR_LIMIT_TRUNCATE - Optional: Limit of the number of sample characters.Any attribute with more than X characters will truncate to the first - X, where X is a number of characters [Default: 500] + Optional: Limit of the number of sample characters.Any attribute + with more than X characters will truncate to the first X, where X is + a number of characters [Default: 500] + --add-dotfile Optional: Add .pep.yaml file that points .yaml PEP file --silent Silence logging. Overrides verbosity. --verbosity V Set logging level (1-5 or logging module level name) --logdev Expand content of logging message format. @@ -56,27 +74,35 @@ optional arguments: processed: -p, --processed Download processed data [Default: download raw data]. --data-source {all,samples,series} - Optional: Specifies the source of data on the GEO record to retrieve processed data, which may be attached to the - collective series entity, or to individual samples. Allowable values are: samples, series or both (all). Ignored unless - 'processed' flag is set. [Default: samples] - --filter FILTER Optional: Filter regex for processed filenames [Default: None].Ignored unless 'processed' flag is set. + Optional: Specifies the source of data on the GEO record to retrieve + processed data, which may be attached to the collective series + entity, or to individual samples. Allowable values are: samples, + series or both (all). Ignored unless 'processed' flag is set. + [Default: samples] + --filter FILTER Optional: Filter regex for processed filenames [Default: + None].Ignored unless 'processed' flag is set. --filter-size FILTER_SIZE - Optional: Filter size for processed files that are stored as sample repository [Default: None]. Works only for sample - data. Supported input formats : 12B, 12KB, 12MB, 12GB. Ignored unless 'processed' flag is set. + Optional: Filter size for processed files that are stored as sample + repository [Default: None]. Works only for sample data. Supported + input formats : 12B, 12KB, 12MB, 12GB. Ignored unless 'processed' + flag is set. -g GEO_FOLDER, --geo-folder GEO_FOLDER - Optional: Specify a location to store processed GEO files. Ignored unless 'processed' flag is set.[Default: $GEODATA:] + Optional: Specify a location to store processed GEO files. Ignored + unless 'processed' flag is set.[Default: $GEODATA:] raw: -x, --split-experiments - Split SRR runs into individual samples. By default, SRX experiments with multiple SRR Runs will have a single entry in - the annotation table, with each run as a separate row in the subannotation table. This setting instead treats each run as - a separate sample + Split SRR runs into individual samples. By default, SRX experiments + with multiple SRR Runs will have a single entry in the annotation + table, with each run as a separate row in the subannotation table. + This setting instead treats each run as a separate sample -b BAM_FOLDER, --bam-folder BAM_FOLDER - Optional: Specify folder of bam files. Geofetch will not download sra files when corresponding bam files already exist. - [Default: $SRABAM:] + Optional: Specify folder of bam files. Geofetch will not download + sra files when corresponding bam files already exist. [Default: + $SRABAM:] -f FQ_FOLDER, --fq-folder FQ_FOLDER - Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding fastq files already - exist. [Default: $SRAFQ:] + Optional: Specify folder of fastq files. Geofetch will not download + sra files when corresponding fastq files already exist. [Default: + $SRAFQ:] --use-key-subset Use just the keys defined in this module when writing out metadata. - ``` diff --git a/docs_jupyter/build/processed-data-downloading.md b/docs_jupyter/build/processed-data-downloading.md index 052d413..b851a61 100644 --- a/docs_jupyter/build/processed-data-downloading.md +++ b/docs_jupyter/build/processed-data-downloading.md @@ -15,126 +15,6 @@ geofetch 0.10.1 To see your CLI options, invoke `geofetch -h`: - -```bash -geofetch -h -``` - -```.output -usage: geofetch [-h] [-V] -i INPUT [-n NAME] [-m METADATA_ROOT] - [-u METADATA_FOLDER] [--just-metadata] [-r] - [--config-template CONFIG_TEMPLATE] - [--pipeline-samples PIPELINE_SAMPLES] - [--pipeline-project PIPELINE_PROJECT] [-k SKIP] [--acc-anno] - [--discard-soft] [--const-limit-project CONST_LIMIT_PROJECT] - [--const-limit-discard CONST_LIMIT_DISCARD] - [--attr-limit-truncate ATTR_LIMIT_TRUNCATE] [--add-dotfile] - [-p] [--data-source {all,samples,series}] [--filter FILTER] - [--filter-size FILTER_SIZE] [-g GEO_FOLDER] [-x] - [-b BAM_FOLDER] [-f FQ_FOLDER] [--use-key-subset] [--silent] - [--verbosity V] [--logdev] - -Automatic GEO and SRA data downloader - -optional arguments: - -h, --help show this help message and exit - -V, --version show program's version number and exit - -i INPUT, --input INPUT - required: a GEO (GSE) accession, or a file with a list - of GSE numbers - -n NAME, --name NAME Specify a project name. Defaults to GSE number - -m METADATA_ROOT, --metadata-root METADATA_ROOT - Specify a parent folder location to store metadata. - The project name will be added as a subfolder - [Default: $SRAMETA:] - -u METADATA_FOLDER, --metadata-folder METADATA_FOLDER - Specify an absolute folder location to store metadata. - No subfolder will be added. Overrides value of - --metadata-root [Default: Not used (--metadata-root is - used by default)] - --just-metadata If set, don't actually run downloads, just create - metadata - -r, --refresh-metadata - If set, re-download metadata even if it exists. - --config-template CONFIG_TEMPLATE - Project config yaml file template. - --pipeline-samples PIPELINE_SAMPLES - Optional: Specify one or more filepaths to SAMPLES - pipeline interface yaml files. These will be added to - the project config file to make it immediately - compatible with looper. [Default: null] - --pipeline-project PIPELINE_PROJECT - Optional: Specify one or more filepaths to PROJECT - pipeline interface yaml files. These will be added to - the project config file to make it immediately - compatible with looper. [Default: null] - -k SKIP, --skip SKIP Skip some accessions. [Default: no skip]. - --acc-anno Optional: Produce annotation sheets for each - accession. Project combined PEP for the whole project - won't be produced. - --discard-soft Optional: After creation of PEP files, all soft and - additional files will be deleted - --const-limit-project CONST_LIMIT_PROJECT - Optional: Limit of the number of the constant sample - characters that should not be in project yaml. - [Default: 50] - --const-limit-discard CONST_LIMIT_DISCARD - Optional: Limit of the number of the constant sample - characters that should not be discarded [Default: 250] - --attr-limit-truncate ATTR_LIMIT_TRUNCATE - Optional: Limit of the number of sample characters.Any - attribute with more than X characters will truncate to - the first X, where X is a number of characters - [Default: 500] - --add-dotfile Optional: Add .pep.yaml file that points .yaml PEP - file - --silent Silence logging. Overrides verbosity. - --verbosity V Set logging level (1-5 or logging module level name) - --logdev Expand content of logging message format. - -processed: - -p, --processed Download processed data [Default: download raw data]. - --data-source {all,samples,series} - Optional: Specifies the source of data on the GEO - record to retrieve processed data, which may be - attached to the collective series entity, or to - individual samples. Allowable values are: samples, - series or both (all). Ignored unless 'processed' flag - is set. [Default: samples] - --filter FILTER Optional: Filter regex for processed filenames - [Default: None].Ignored unless 'processed' flag is - set. - --filter-size FILTER_SIZE - Optional: Filter size for processed files that are - stored as sample repository [Default: None]. Works - only for sample data. Supported input formats : 12B, - 12KB, 12MB, 12GB. Ignored unless 'processed' flag is - set. - -g GEO_FOLDER, --geo-folder GEO_FOLDER - Optional: Specify a location to store processed GEO - files. Ignored unless 'processed' flag is - set.[Default: $GEODATA:] - -raw: - -x, --split-experiments - Split SRR runs into individual samples. By default, - SRX experiments with multiple SRR Runs will have a - single entry in the annotation table, with each run as - a separate row in the subannotation table. This - setting instead treats each run as a separate sample - -b BAM_FOLDER, --bam-folder BAM_FOLDER - Optional: Specify folder of bam files. Geofetch will - not download sra files when corresponding bam files - already exist. [Default: $SRABAM:] - -f FQ_FOLDER, --fq-folder FQ_FOLDER - Optional: Specify folder of fastq files. Geofetch will - not download sra files when corresponding fastq files - already exist. [Default: $SRAFQ:] - --use-key-subset Use just the keys defined in this module when writing - out metadata. - -``` - Calling geofetch will do 4 tasks: 1. download all or filtered processed files from `GSE#####` into your geo folder. @@ -144,6 +24,11 @@ Calling geofetch will do 4 tasks: Complete details about geofetch outputs is cataloged in the [metadata outputs reference](metadata_output.md). +from IPython.core.display import SVG +SVG(filename='logo.svg') + +![arguments_outputs.svg](attachment:arguments_outputs.svg) + ## Download the data First, create the metadata for processed data (by adding --processed and --just-metadata): diff --git a/docs_jupyter/processed-data-downloading.ipynb b/docs_jupyter/processed-data-downloading.ipynb index c691aea..b386a74 100644 --- a/docs_jupyter/processed-data-downloading.ipynb +++ b/docs_jupyter/processed-data-downloading.ipynb @@ -33,135 +33,6 @@ "To see your CLI options, invoke `geofetch -h`:" ] }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "usage: geofetch [-h] [-V] -i INPUT [-n NAME] [-m METADATA_ROOT]\n", - " [-u METADATA_FOLDER] [--just-metadata] [-r]\n", - " [--config-template CONFIG_TEMPLATE]\n", - " [--pipeline-samples PIPELINE_SAMPLES]\n", - " [--pipeline-project PIPELINE_PROJECT] [-k SKIP] [--acc-anno]\n", - " [--discard-soft] [--const-limit-project CONST_LIMIT_PROJECT]\n", - " [--const-limit-discard CONST_LIMIT_DISCARD]\n", - " [--attr-limit-truncate ATTR_LIMIT_TRUNCATE] [--add-dotfile]\n", - " [-p] [--data-source {all,samples,series}] [--filter FILTER]\n", - " [--filter-size FILTER_SIZE] [-g GEO_FOLDER] [-x]\n", - " [-b BAM_FOLDER] [-f FQ_FOLDER] [--use-key-subset] [--silent]\n", - " [--verbosity V] [--logdev]\n", - "\n", - "Automatic GEO and SRA data downloader\n", - "\n", - "optional arguments:\n", - " -h, --help show this help message and exit\n", - " -V, --version show program's version number and exit\n", - " -i INPUT, --input INPUT\n", - " required: a GEO (GSE) accession, or a file with a list\n", - " of GSE numbers\n", - " -n NAME, --name NAME Specify a project name. Defaults to GSE number\n", - " -m METADATA_ROOT, --metadata-root METADATA_ROOT\n", - " Specify a parent folder location to store metadata.\n", - " The project name will be added as a subfolder\n", - " [Default: $SRAMETA:]\n", - " -u METADATA_FOLDER, --metadata-folder METADATA_FOLDER\n", - " Specify an absolute folder location to store metadata.\n", - " No subfolder will be added. Overrides value of\n", - " --metadata-root [Default: Not used (--metadata-root is\n", - " used by default)]\n", - " --just-metadata If set, don't actually run downloads, just create\n", - " metadata\n", - " -r, --refresh-metadata\n", - " If set, re-download metadata even if it exists.\n", - " --config-template CONFIG_TEMPLATE\n", - " Project config yaml file template.\n", - " --pipeline-samples PIPELINE_SAMPLES\n", - " Optional: Specify one or more filepaths to SAMPLES\n", - " pipeline interface yaml files. These will be added to\n", - " the project config file to make it immediately\n", - " compatible with looper. [Default: null]\n", - " --pipeline-project PIPELINE_PROJECT\n", - " Optional: Specify one or more filepaths to PROJECT\n", - " pipeline interface yaml files. These will be added to\n", - " the project config file to make it immediately\n", - " compatible with looper. [Default: null]\n", - " -k SKIP, --skip SKIP Skip some accessions. [Default: no skip].\n", - " --acc-anno Optional: Produce annotation sheets for each\n", - " accession. Project combined PEP for the whole project\n", - " won't be produced.\n", - " --discard-soft Optional: After creation of PEP files, all soft and\n", - " additional files will be deleted\n", - " --const-limit-project CONST_LIMIT_PROJECT\n", - " Optional: Limit of the number of the constant sample\n", - " characters that should not be in project yaml.\n", - " [Default: 50]\n", - " --const-limit-discard CONST_LIMIT_DISCARD\n", - " Optional: Limit of the number of the constant sample\n", - " characters that should not be discarded [Default: 250]\n", - " --attr-limit-truncate ATTR_LIMIT_TRUNCATE\n", - " Optional: Limit of the number of sample characters.Any\n", - " attribute with more than X characters will truncate to\n", - " the first X, where X is a number of characters\n", - " [Default: 500]\n", - " --add-dotfile Optional: Add .pep.yaml file that points .yaml PEP\n", - " file\n", - " --silent Silence logging. Overrides verbosity.\n", - " --verbosity V Set logging level (1-5 or logging module level name)\n", - " --logdev Expand content of logging message format.\n", - "\n", - "processed:\n", - " -p, --processed Download processed data [Default: download raw data].\n", - " --data-source {all,samples,series}\n", - " Optional: Specifies the source of data on the GEO\n", - " record to retrieve processed data, which may be\n", - " attached to the collective series entity, or to\n", - " individual samples. Allowable values are: samples,\n", - " series or both (all). Ignored unless 'processed' flag\n", - " is set. [Default: samples]\n", - " --filter FILTER Optional: Filter regex for processed filenames\n", - " [Default: None].Ignored unless 'processed' flag is\n", - " set.\n", - " --filter-size FILTER_SIZE\n", - " Optional: Filter size for processed files that are\n", - " stored as sample repository [Default: None]. Works\n", - " only for sample data. Supported input formats : 12B,\n", - " 12KB, 12MB, 12GB. Ignored unless 'processed' flag is\n", - " set.\n", - " -g GEO_FOLDER, --geo-folder GEO_FOLDER\n", - " Optional: Specify a location to store processed GEO\n", - " files. Ignored unless 'processed' flag is\n", - " set.[Default: $GEODATA:]\n", - "\n", - "raw:\n", - " -x, --split-experiments\n", - " Split SRR runs into individual samples. By default,\n", - " SRX experiments with multiple SRR Runs will have a\n", - " single entry in the annotation table, with each run as\n", - " a separate row in the subannotation table. This\n", - " setting instead treats each run as a separate sample\n", - " -b BAM_FOLDER, --bam-folder BAM_FOLDER\n", - " Optional: Specify folder of bam files. Geofetch will\n", - " not download sra files when corresponding bam files\n", - " already exist. [Default: $SRABAM:]\n", - " -f FQ_FOLDER, --fq-folder FQ_FOLDER\n", - " Optional: Specify folder of fastq files. Geofetch will\n", - " not download sra files when corresponding fastq files\n", - " already exist. [Default: $SRAFQ:]\n", - " --use-key-subset Use just the keys defined in this module when writing\n", - " out metadata.\n" - ] - } - ], - "source": [ - "geofetch -h" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -176,6 +47,29 @@ "Complete details about geofetch outputs is cataloged in the [metadata outputs reference](metadata_output.md)." ] }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "from IPython.core.display import SVG\n", + "SVG(filename='logo.svg')" + ] + }, + { + "attachments": { + "arguments_outputs.svg": { + "image/svg+xml": [ + "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB3aWR0aD0iODIuODUwMjczbW0iCiAgIGhlaWdodD0iNTIuNzQ4MjgzbW0iCiAgIHZpZXdCb3g9IjAgMCA4Mi44NTAyNzMgNTIuNzQ4MjgzIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmc1IgogICB4bWw6c3BhY2U9InByZXNlcnZlIgogICBzb2RpcG9kaTpkb2NuYW1lPSI3YTUzODBmNS1iZGE3LTQ2OGItOWE1Yi05Yzc3YWY0Y2FjMzQuc3ZnIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIxLjIgKDE6MS4yKzIwMjIwNjAxMTMyNytmYzRlNDA5NmM1KSIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJuYW1lZHZpZXc3IgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzAwMDAwMCIKICAgICBib3JkZXJvcGFjaXR5PSIwLjI1IgogICAgIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIKICAgICBpbmtzY2FwZTpkZXNrY29sb3I9IiNkMWQxZDEiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9Im1tIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpbmtzY2FwZTp6b29tPSIxLjIzNzEyNSIKICAgICBpbmtzY2FwZTpjeD0iMjQ4Ljk2NDMzIgogICAgIGlua3NjYXBlOmN5PSItMjkuNTAzODkiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxODQ4IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEwMTYiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjcyIgogICAgIGlua3NjYXBlOndpbmRvdy15PSIyNyIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3VpZGVzPSJ0cnVlIiAvPjxkZWZzCiAgICAgaWQ9ImRlZnMyIj48cmVjdAogICAgICAgeD0iNzMuNDg4NjYzIgogICAgICAgeT0iMTc0LjQ2NTg4IgogICAgICAgd2lkdGg9IjEyOS42MTIyNyIKICAgICAgIGhlaWdodD0iMjUuNjQwMTEyIgogICAgICAgaWQ9InJlY3QxMDQ4NSIgLz48cmVjdAogICAgICAgeD0iODkuNDkwNjYyIgogICAgICAgeT0iMjI1LjEyMzM4IgogICAgICAgd2lkdGg9IjYyMi45ODM4OSIKICAgICAgIGhlaWdodD0iNDEyLjc1NDE4IgogICAgICAgaWQ9InJlY3Q3NDciIC8+PHJlY3QKICAgICAgIHg9IjUwOS45MzM0MSIKICAgICAgIHk9IjQ4MS40ODg1NiIKICAgICAgIHdpZHRoPSIyMDguMjUzODgiCiAgICAgICBoZWlnaHQ9IjY4LjcyMzA4MyIKICAgICAgIGlkPSJyZWN0NzQxIiAvPjxmaWx0ZXIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQiIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJEcm9wIFNoYWRvdyIKICAgICAgIGlkPSJmaWx0ZXI0NzIwIgogICAgICAgeD0iLTAuMDg5NTkxMDQ5IgogICAgICAgeT0iLTAuMjI4ODI0MzMiCiAgICAgICB3aWR0aD0iMS4xNTI4MzE4IgogICAgICAgaGVpZ2h0PSIxLjM5MDM0NzQiPjxmZUZsb29kCiAgICAgICAgIGZsb29kLW9wYWNpdHk9IjAuNDk4MDM5IgogICAgICAgICBmbG9vZC1jb2xvcj0icmdiKDAsMCwwKSIKICAgICAgICAgcmVzdWx0PSJmbG9vZCIKICAgICAgICAgaWQ9ImZlRmxvb2Q0NzIyIiAvPjxmZUNvbXBvc2l0ZQogICAgICAgICBpbj0iZmxvb2QiCiAgICAgICAgIGluMj0iU291cmNlR3JhcGhpYyIKICAgICAgICAgb3BlcmF0b3I9Im91dCIKICAgICAgICAgcmVzdWx0PSJjb21wb3NpdGUxIgogICAgICAgICBpZD0iZmVDb21wb3NpdGU0NzI0IiAvPjxmZUdhdXNzaWFuQmx1cgogICAgICAgICBpbj0iY29tcG9zaXRlMSIKICAgICAgICAgc3RkRGV2aWF0aW9uPSIyIgogICAgICAgICByZXN1bHQ9ImJsdXIiCiAgICAgICAgIGlkPSJmZUdhdXNzaWFuQmx1cjQ3MjYiIC8+PGZlT2Zmc2V0CiAgICAgICAgIGR4PSItMiIKICAgICAgICAgZHk9Ii0yIgogICAgICAgICByZXN1bHQ9Im9mZnNldCIKICAgICAgICAgaWQ9ImZlT2Zmc2V0NDcyOCIgLz48ZmVDb21wb3NpdGUKICAgICAgICAgaW49Im9mZnNldCIKICAgICAgICAgaW4yPSJTb3VyY2VHcmFwaGljIgogICAgICAgICBvcGVyYXRvcj0iYXRvcCIKICAgICAgICAgcmVzdWx0PSJjb21wb3NpdGUyIgogICAgICAgICBpZD0iZmVDb21wb3NpdGU0NzMwIiAvPjwvZmlsdGVyPjxsaW5lYXJHcmFkaWVudAogICAgICAgeDE9IjI2LjY0ODkzNyIKICAgICAgIHkxPSIyMC42MDM3ODEiCiAgICAgICB4Mj0iMTM1LjY2NTI1IgogICAgICAgeTI9IjExNC4zOTc2NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE0NzgiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0Njg5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNTYyNTQxLDAsMCwwLjU2Nzk3MiwtOS4zOTk3NDksLTUuMzA1MzE3KSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ2ODkiPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM1YTlmZDQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0NjkxIiAvPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzMDY5OTg7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0NjkzIiAvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50CiAgICAgICB4MT0iMTUwLjk2MTExIgogICAgICAgeTE9IjE5Mi4zNTE3NiIKICAgICAgIHgyPSIxMTIuMDMxNDQiCiAgICAgICB5Mj0iMTM3LjI3Mjk5IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTQ3NSIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQ2NzEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41NjI1NDEsMCwwLDAuNTY3OTcyLC05LjM5OTc0OSwtNS4zMDUzMTcpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDY3MSI+PHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZDQzYjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQ2NzMiIC8+PHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZTg3MztzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQ2NzUiIC8+PC9saW5lYXJHcmFkaWVudD48cmFkaWFsR3JhZGllbnQKICAgICAgIGN4PSI2MS41MTg4ODMiCiAgICAgICBjeT0iMTMyLjI4NTc1IgogICAgICAgcj0iMjkuMDM2OTEzIgogICAgICAgZng9IjYxLjUxODg4MyIKICAgICAgIGZ5PSIxMzIuMjg1NzUiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQxNDgwIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjc5NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjc0OTA1NjVlLTgsLTAuMjM5OTQ2OTYsMS4wNTQ2NjgsMy43OTE1NDU3ZS03LC0xNi40OTA2NzIsMTg4LjY1ODk0KSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI3OTUiPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiOGI4Yjg7c3RvcC1vcGFjaXR5OjAuNDk4MDM5MjIiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AyNzk3IiAvPjxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3ZjdmN2Y7c3RvcC1vcGFjaXR5OjAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyNzk5IiAvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iZ3JhZGllbnRGaWxsLTEiCiAgICAgICB4MT0iMC43NDE0NDI1IgogICAgICAgeDI9IjU5MC44NjI2MSIKICAgICAgIHkxPSIzLjY2NTgyNjgiCiAgICAgICB5Mj0iNTkzLjc4Njk5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBzcHJlYWRNZXRob2Q9InBhZCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC4xMTQ5NDE5NiwwLDAsMC4wNzY5Nzk4NywyOTMuMDU1NTUsNzUyLjE4NDA2KSI+PHN0b3AKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdG9wLWNvbG9yPSJyZ2IoMjAzLDIwNiwyMDgpIgogICAgICAgICBzdG9wLW9wYWNpdHk9IjEiCiAgICAgICAgIGlkPSJzdG9wNyIgLz48c3RvcAogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0b3AtY29sb3I9InJnYigxMzIsMTMxLDEzOSkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMSIKICAgICAgICAgaWQ9InN0b3A5IiAvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iZ3JhZGllbnRGaWxsLTIiCiAgICAgICB4MT0iMzAxLjAyNjAzIgogICAgICAgeDI9IjcwMy4wNjc1IgogICAgICAgeTE9IjE1MS40MDA2IgogICAgICAgeTI9IjU1My40NDIwOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgc3ByZWFkTWV0aG9kPSJwYWQiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuMDkzMTE5MzksMCwwLDAuMDk1MDIwMTUsMjkzLjA1NTU1LDc1Mi4xODQwNikiPjxzdG9wCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3RvcC1jb2xvcj0icmdiKDM5LDEwOSwxOTUpIgogICAgICAgICBzdG9wLW9wYWNpdHk9IjEiCiAgICAgICAgIGlkPSJzdG9wMTIiIC8+PHN0b3AKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdG9wLWNvbG9yPSJyZ2IoMjIsOTIsMTcwKSIKICAgICAgICAgc3RvcC1vcGFjaXR5PSIxIgogICAgICAgICBpZD0ic3RvcDE0IiAvPjwvbGluZWFyR3JhZGllbnQ+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48c3R5bGUKICAgICAgIHR5cGU9InRleHQvY3NzIgogICAgICAgaWQ9InN0eWxlNi0yIj4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PHJlY3QKICAgICAgIHg9IjQ2NC4zNjkwOCIKICAgICAgIHk9IjMzNS45ODUyMyIKICAgICAgIHdpZHRoPSIyMDUuNTUzNSIKICAgICAgIGhlaWdodD0iMTMwLjUyMzQ1IgogICAgICAgaWQ9InJlY3Q0NDMxIiAvPjxyZWN0CiAgICAgICB4PSIyODUuMDUzOTkiCiAgICAgICB5PSIzMjMuODAyMzEiCiAgICAgICB3aWR0aD0iNDIuMTY2MTE1IgogICAgICAgaGVpZ2h0PSIyMi44NDgyNjkiCiAgICAgICBpZD0icmVjdDM5MTIiIC8+PHJlY3QKICAgICAgIHg9IjczLjQ4ODY2MyIKICAgICAgIHk9IjE3NC40NjU4OCIKICAgICAgIHdpZHRoPSIxMjkuNjEyMjciCiAgICAgICBoZWlnaHQ9IjI1LjY0MDExMiIKICAgICAgIGlkPSJyZWN0MTA0ODUtMyIgLz48cmVjdAogICAgICAgeD0iODkuNDkwNjYyIgogICAgICAgeT0iMjI1LjEyMzM4IgogICAgICAgd2lkdGg9IjYyMi45ODM4OSIKICAgICAgIGhlaWdodD0iNDEyLjc1NDE4IgogICAgICAgaWQ9InJlY3Q3NDctNiIgLz48cmVjdAogICAgICAgeD0iNTA5LjkzMzQxIgogICAgICAgeT0iNDgxLjQ4ODU2IgogICAgICAgd2lkdGg9IjIwOC4yNTM4OCIKICAgICAgIGhlaWdodD0iNjguNzIzMDgzIgogICAgICAgaWQ9InJlY3Q3NDEtNyIgLz48ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0IiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iRHJvcCBTaGFkb3ciCiAgICAgICBpZD0iZmlsdGVyNDcyMC01IgogICAgICAgeD0iLTAuMDg5NTkxMDQ5IgogICAgICAgeT0iLTAuMjI4ODI0MzMiCiAgICAgICB3aWR0aD0iMS4xNTI4MzE4IgogICAgICAgaGVpZ2h0PSIxLjM5MDM0NzQiPjxmZUZsb29kCiAgICAgICAgIGZsb29kLW9wYWNpdHk9IjAuNDk4MDM5IgogICAgICAgICBmbG9vZC1jb2xvcj0icmdiKDAsMCwwKSIKICAgICAgICAgcmVzdWx0PSJmbG9vZCIKICAgICAgICAgaWQ9ImZlRmxvb2Q0NzIyLTMiIC8+PGZlQ29tcG9zaXRlCiAgICAgICAgIGluPSJmbG9vZCIKICAgICAgICAgaW4yPSJTb3VyY2VHcmFwaGljIgogICAgICAgICBvcGVyYXRvcj0ib3V0IgogICAgICAgICByZXN1bHQ9ImNvbXBvc2l0ZTEiCiAgICAgICAgIGlkPSJmZUNvbXBvc2l0ZTQ3MjQtNSIgLz48ZmVHYXVzc2lhbkJsdXIKICAgICAgICAgaW49ImNvbXBvc2l0ZTEiCiAgICAgICAgIHN0ZERldmlhdGlvbj0iMiIKICAgICAgICAgcmVzdWx0PSJibHVyIgogICAgICAgICBpZD0iZmVHYXVzc2lhbkJsdXI0NzI2LTYiIC8+PGZlT2Zmc2V0CiAgICAgICAgIGR4PSItMiIKICAgICAgICAgZHk9Ii0yIgogICAgICAgICByZXN1bHQ9Im9mZnNldCIKICAgICAgICAgaWQ9ImZlT2Zmc2V0NDcyOC0yIiAvPjxmZUNvbXBvc2l0ZQogICAgICAgICBpbj0ib2Zmc2V0IgogICAgICAgICBpbjI9IlNvdXJjZUdyYXBoaWMiCiAgICAgICAgIG9wZXJhdG9yPSJhdG9wIgogICAgICAgICByZXN1bHQ9ImNvbXBvc2l0ZTIiCiAgICAgICAgIGlkPSJmZUNvbXBvc2l0ZTQ3MzAtOSIgLz48L2ZpbHRlcj48cmFkaWFsR3JhZGllbnQKICAgICAgIGN4PSI2MS41MTg4ODMiCiAgICAgICBjeT0iMTMyLjI4NTc1IgogICAgICAgcj0iMjkuMDM2OTEzIgogICAgICAgZng9IjYxLjUxODg4MyIKICAgICAgIGZ5PSIxMzIuMjg1NzUiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQxNDgwLTkiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyNzk1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuNzQ5MDU2NWUtOCwtMC4yMzk5NDY5NiwxLjA1NDY2OCwzLjc5MTU0NTdlLTcsLTE2LjQ5MDY3MiwxODguNjU4OTQpIiAvPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTE4Ij4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMi03Ij4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMSI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTAiPgogICAKICAgIC5maWwwIHtmaWxsOiMwMDAwMDA7ZmlsbC1ydWxlOm5vbnplcm99CiAgIAogIDwvc3R5bGU+PHJlY3QKICAgICAgIHg9IjczLjQ4ODY2MyIKICAgICAgIHk9IjE3NC40NjU4OCIKICAgICAgIHdpZHRoPSIxMjkuNjEyMjciCiAgICAgICBoZWlnaHQ9IjI1LjY0MDExMiIKICAgICAgIGlkPSJyZWN0MTA0ODUtOSIgLz48cmVjdAogICAgICAgeD0iODkuNDkwNjYyIgogICAgICAgeT0iMjI1LjEyMzM4IgogICAgICAgd2lkdGg9IjYyMi45ODM4OSIKICAgICAgIGhlaWdodD0iNDEyLjc1NDE4IgogICAgICAgaWQ9InJlY3Q3NDctNCIgLz48cmVjdAogICAgICAgeD0iNTA5LjkzMzQxIgogICAgICAgeT0iNDgxLjQ4ODU2IgogICAgICAgd2lkdGg9IjIwOC4yNTM4OCIKICAgICAgIGhlaWdodD0iNjguNzIzMDgzIgogICAgICAgaWQ9InJlY3Q3NDEtOSIgLz48ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0IiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iRHJvcCBTaGFkb3ciCiAgICAgICBpZD0iZmlsdGVyNDcyMC0wIgogICAgICAgeD0iLTAuMDg5NTkxMDQ5IgogICAgICAgeT0iLTAuMjI4ODI0MzMiCiAgICAgICB3aWR0aD0iMS4xNTI4MzE4IgogICAgICAgaGVpZ2h0PSIxLjM5MDM0NzQiPjxmZUZsb29kCiAgICAgICAgIGZsb29kLW9wYWNpdHk9IjAuNDk4MDM5IgogICAgICAgICBmbG9vZC1jb2xvcj0icmdiKDAsMCwwKSIKICAgICAgICAgcmVzdWx0PSJmbG9vZCIKICAgICAgICAgaWQ9ImZlRmxvb2Q0NzIyLTkiIC8+PGZlQ29tcG9zaXRlCiAgICAgICAgIGluPSJmbG9vZCIKICAgICAgICAgaW4yPSJTb3VyY2VHcmFwaGljIgogICAgICAgICBvcGVyYXRvcj0ib3V0IgogICAgICAgICByZXN1bHQ9ImNvbXBvc2l0ZTEiCiAgICAgICAgIGlkPSJmZUNvbXBvc2l0ZTQ3MjQtMSIgLz48ZmVHYXVzc2lhbkJsdXIKICAgICAgICAgaW49ImNvbXBvc2l0ZTEiCiAgICAgICAgIHN0ZERldmlhdGlvbj0iMiIKICAgICAgICAgcmVzdWx0PSJibHVyIgogICAgICAgICBpZD0iZmVHYXVzc2lhbkJsdXI0NzI2LTciIC8+PGZlT2Zmc2V0CiAgICAgICAgIGR4PSItMiIKICAgICAgICAgZHk9Ii0yIgogICAgICAgICByZXN1bHQ9Im9mZnNldCIKICAgICAgICAgaWQ9ImZlT2Zmc2V0NDcyOC03IiAvPjxmZUNvbXBvc2l0ZQogICAgICAgICBpbj0ib2Zmc2V0IgogICAgICAgICBpbjI9IlNvdXJjZUdyYXBoaWMiCiAgICAgICAgIG9wZXJhdG9yPSJhdG9wIgogICAgICAgICByZXN1bHQ9ImNvbXBvc2l0ZTIiCiAgICAgICAgIGlkPSJmZUNvbXBvc2l0ZTQ3MzAtMSIgLz48L2ZpbHRlcj48cmFkaWFsR3JhZGllbnQKICAgICAgIGN4PSI2MS41MTg4ODMiCiAgICAgICBjeT0iMTMyLjI4NTc1IgogICAgICAgcj0iMjkuMDM2OTEzIgogICAgICAgZng9IjYxLjUxODg4MyIKICAgICAgIGZ5PSIxMzIuMjg1NzUiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQxNDgwLTciCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyNzk1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuNzQ5MDU2NWUtOCwtMC4yMzk5NDY5NiwxLjA1NDY2OCwzLjc5MTU0NTdlLTcsLTE2LjQ5MDY3MiwxODguNjU4OTQpIiAvPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTMiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48c3R5bGUKICAgICAgIHR5cGU9InRleHQvY3NzIgogICAgICAgaWQ9InN0eWxlNi0yLTkiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI4NjkiCiAgICAgICBpbmtzY2FwZTpzd2F0Y2g9InNvbGlkIj48c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDI4NjciIC8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI4MTEiCiAgICAgICBpbmtzY2FwZTpzd2F0Y2g9InNvbGlkIj48c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZlNDQzO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDI4MDkiIC8+PC9saW5lYXJHcmFkaWVudD48c3R5bGUKICAgICAgIHR5cGU9InRleHQvY3NzIgogICAgICAgaWQ9InN0eWxlNi0zNSI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgxMjQxIj48cGF0aAogICAgICAgICBkPSJNIC0xLjk5OTk5NSwtMi4wMDAwMDQ1IEggNTAzIFYgMjk1IEggLTEuOTk5OTk1IFoiCiAgICAgICAgIGlkPSJwYXRoMTI0MyIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgxMjQ1Ij48cGF0aAogICAgICAgICBkPSJNIC0xLjk5OTk5NSwtMi4wMDAwMDQ1IEggNTAzIFYgMjk1IEggLTEuOTk5OTk1IFoiCiAgICAgICAgIGlkPSJwYXRoMTI0NyIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgxMjQ5Ij48cGF0aAogICAgICAgICBkPSJNIC0xLjk5OTk5NSwtMi4wMDAwMDQ1IEggNTAzIFYgMjk1IEggLTEuOTk5OTk1IFoiCiAgICAgICAgIGlkPSJwYXRoMTI1MSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNDA1Ij48cGF0aAogICAgICAgICBkPSJNIC0yLC0yIEggNTI1IFYgMjk1IEggLTIgWiIKICAgICAgICAgaWQ9InBhdGgyNDAzIiAvPjwvY2xpcFBhdGg+PHJlY3QKICAgICAgIHg9IjczLjQ4ODY2MyIKICAgICAgIHk9IjE3NC40NjU4OCIKICAgICAgIHdpZHRoPSIxMjkuNjEyMjciCiAgICAgICBoZWlnaHQ9IjI1LjY0MDExMiIKICAgICAgIGlkPSJyZWN0MTA0ODUtMiIgLz48cmVjdAogICAgICAgeD0iODkuNDkwNjYyIgogICAgICAgeT0iMjI1LjEyMzM4IgogICAgICAgd2lkdGg9IjYyMi45ODM4OSIKICAgICAgIGhlaWdodD0iNDEyLjc1NDE4IgogICAgICAgaWQ9InJlY3Q3NDctMiIgLz48cmVjdAogICAgICAgeD0iNTA5LjkzMzQxIgogICAgICAgeT0iNDgxLjQ4ODU2IgogICAgICAgd2lkdGg9IjIwOC4yNTM4OCIKICAgICAgIGhlaWdodD0iNjguNzIzMDgzIgogICAgICAgaWQ9InJlY3Q3NDEtOCIgLz48ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0IiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iRHJvcCBTaGFkb3ciCiAgICAgICBpZD0iZmlsdGVyNDcyMC05IgogICAgICAgeD0iLTAuMDg5NTkxMDQ5IgogICAgICAgeT0iLTAuMjI4ODI0MzMiCiAgICAgICB3aWR0aD0iMS4xNTI4MzE4IgogICAgICAgaGVpZ2h0PSIxLjM5MDM0NzQiPjxmZUZsb29kCiAgICAgICAgIGZsb29kLW9wYWNpdHk9IjAuNDk4MDM5IgogICAgICAgICBmbG9vZC1jb2xvcj0icmdiKDAsMCwwKSIKICAgICAgICAgcmVzdWx0PSJmbG9vZCIKICAgICAgICAgaWQ9ImZlRmxvb2Q0NzIyLTciIC8+PGZlQ29tcG9zaXRlCiAgICAgICAgIGluPSJmbG9vZCIKICAgICAgICAgaW4yPSJTb3VyY2VHcmFwaGljIgogICAgICAgICBvcGVyYXRvcj0ib3V0IgogICAgICAgICByZXN1bHQ9ImNvbXBvc2l0ZTEiCiAgICAgICAgIGlkPSJmZUNvbXBvc2l0ZTQ3MjQtMyIgLz48ZmVHYXVzc2lhbkJsdXIKICAgICAgICAgaW49ImNvbXBvc2l0ZTEiCiAgICAgICAgIHN0ZERldmlhdGlvbj0iMiIKICAgICAgICAgcmVzdWx0PSJibHVyIgogICAgICAgICBpZD0iZmVHYXVzc2lhbkJsdXI0NzI2LTYxIiAvPjxmZU9mZnNldAogICAgICAgICBkeD0iLTIiCiAgICAgICAgIGR5PSItMiIKICAgICAgICAgcmVzdWx0PSJvZmZzZXQiCiAgICAgICAgIGlkPSJmZU9mZnNldDQ3MjgtMjkiIC8+PGZlQ29tcG9zaXRlCiAgICAgICAgIGluPSJvZmZzZXQiCiAgICAgICAgIGluMj0iU291cmNlR3JhcGhpYyIKICAgICAgICAgb3BlcmF0b3I9ImF0b3AiCiAgICAgICAgIHJlc3VsdD0iY29tcG9zaXRlMiIKICAgICAgICAgaWQ9ImZlQ29tcG9zaXRlNDczMC0zIiAvPjwvZmlsdGVyPjxsaW5lYXJHcmFkaWVudAogICAgICAgeDE9IjI2LjY0ODkzNyIKICAgICAgIHkxPSIyMC42MDM3ODEiCiAgICAgICB4Mj0iMTM1LjY2NTI1IgogICAgICAgeTI9IjExNC4zOTc2NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE0NzgtMSIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQ2ODkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41NjI1NDEsMCwwLDAuNTY3OTcyLC05LjM5OTc0OSwtNS4zMDUzMTcpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgeDE9IjE1MC45NjExMSIKICAgICAgIHkxPSIxOTIuMzUxNzYiCiAgICAgICB4Mj0iMTEyLjAzMTQ0IgogICAgICAgeTI9IjEzNy4yNzI5OSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE0NzUtNyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQ2NzEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41NjI1NDEsMCwwLDAuNTY3OTcyLC05LjM5OTc0OSwtNS4zMDUzMTcpIiAvPjxyYWRpYWxHcmFkaWVudAogICAgICAgY3g9IjYxLjUxODg4MyIKICAgICAgIGN5PSIxMzIuMjg1NzUiCiAgICAgICByPSIyOS4wMzY5MTMiCiAgICAgICBmeD0iNjEuNTE4ODgzIgogICAgICAgZnk9IjEzMi4yODU3NSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDE0ODAtNSIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI3OTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS43NDkwNTY1ZS04LC0wLjIzOTk0Njk2LDEuMDU0NjY4LDMuNzkxNTQ1N2UtNywtMTYuNDkwNjcyLDE4OC42NTg5NCkiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iZ3JhZGllbnRGaWxsLTEtNiIKICAgICAgIHgxPSIwLjc0MTQ0MjUiCiAgICAgICB4Mj0iNTkwLjg2MjYxIgogICAgICAgeTE9IjMuNjY1ODI2OCIKICAgICAgIHkyPSI1OTMuNzg2OTkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHNwcmVhZE1ldGhvZD0icGFkIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjExNDk0MTk2LDAsMCwwLjA3Njk3OTg3LDI5My4wNTU1NSw3NTIuMTg0MDYpIj48c3RvcAogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0b3AtY29sb3I9InJnYigyMDMsMjA2LDIwOCkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMSIKICAgICAgICAgaWQ9InN0b3A3LTEiIC8+PHN0b3AKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdG9wLWNvbG9yPSJyZ2IoMTMyLDEzMSwxMzkpIgogICAgICAgICBzdG9wLW9wYWNpdHk9IjEiCiAgICAgICAgIGlkPSJzdG9wOS0wIiAvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iZ3JhZGllbnRGaWxsLTItNiIKICAgICAgIHgxPSIzMDEuMDI2MDMiCiAgICAgICB4Mj0iNzAzLjA2NzUiCiAgICAgICB5MT0iMTUxLjQwMDYiCiAgICAgICB5Mj0iNTUzLjQ0MjA4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBzcHJlYWRNZXRob2Q9InBhZCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC4wOTMxMTkzOSwwLDAsMC4wOTUwMjAxNSwyOTMuMDU1NTUsNzUyLjE4NDA2KSI+PHN0b3AKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdG9wLWNvbG9yPSJyZ2IoMzksMTA5LDE5NSkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMSIKICAgICAgICAgaWQ9InN0b3AxMi0zIiAvPjxzdG9wCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3RvcC1jb2xvcj0icmdiKDIyLDkyLDE3MCkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMSIKICAgICAgICAgaWQ9InN0b3AxNC0yIiAvPjwvbGluZWFyR3JhZGllbnQ+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMDYiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48c3R5bGUKICAgICAgIHR5cGU9InRleHQvY3NzIgogICAgICAgaWQ9InN0eWxlNi0yLTEiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48cmVjdAogICAgICAgeD0iNzMuNDg4NjYzIgogICAgICAgeT0iMTc0LjQ2NTg4IgogICAgICAgd2lkdGg9IjEyOS42MTIyNyIKICAgICAgIGhlaWdodD0iMjUuNjQwMTEyIgogICAgICAgaWQ9InJlY3QxMDQ4NS0zOCIgLz48cmVjdAogICAgICAgeD0iODkuNDkwNjYyIgogICAgICAgeT0iMjI1LjEyMzM4IgogICAgICAgd2lkdGg9IjYyMi45ODM4OSIKICAgICAgIGhlaWdodD0iNDEyLjc1NDE4IgogICAgICAgaWQ9InJlY3Q3NDctNjAiIC8+PHJlY3QKICAgICAgIHg9IjUwOS45MzM0MSIKICAgICAgIHk9IjQ4MS40ODg1NiIKICAgICAgIHdpZHRoPSIyMDguMjUzODgiCiAgICAgICBoZWlnaHQ9IjY4LjcyMzA4MyIKICAgICAgIGlkPSJyZWN0NzQxLTQiIC8+PGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkRyb3AgU2hhZG93IgogICAgICAgaWQ9ImZpbHRlcjQ3MjAtOCIKICAgICAgIHg9Ii0wLjA4OTU5MTA0OSIKICAgICAgIHk9Ii0wLjIyODgyNDMzIgogICAgICAgd2lkdGg9IjEuMTUyODMxOCIKICAgICAgIGhlaWdodD0iMS4zOTAzNDc0Ij48ZmVGbG9vZAogICAgICAgICBmbG9vZC1vcGFjaXR5PSIwLjQ5ODAzOSIKICAgICAgICAgZmxvb2QtY29sb3I9InJnYigwLDAsMCkiCiAgICAgICAgIHJlc3VsdD0iZmxvb2QiCiAgICAgICAgIGlkPSJmZUZsb29kNDcyMi04IiAvPjxmZUNvbXBvc2l0ZQogICAgICAgICBpbj0iZmxvb2QiCiAgICAgICAgIGluMj0iU291cmNlR3JhcGhpYyIKICAgICAgICAgb3BlcmF0b3I9Im91dCIKICAgICAgICAgcmVzdWx0PSJjb21wb3NpdGUxIgogICAgICAgICBpZD0iZmVDb21wb3NpdGU0NzI0LTgiIC8+PGZlR2F1c3NpYW5CbHVyCiAgICAgICAgIGluPSJjb21wb3NpdGUxIgogICAgICAgICBzdGREZXZpYXRpb249IjIiCiAgICAgICAgIHJlc3VsdD0iYmx1ciIKICAgICAgICAgaWQ9ImZlR2F1c3NpYW5CbHVyNDcyNi05IiAvPjxmZU9mZnNldAogICAgICAgICBkeD0iLTIiCiAgICAgICAgIGR5PSItMiIKICAgICAgICAgcmVzdWx0PSJvZmZzZXQiCiAgICAgICAgIGlkPSJmZU9mZnNldDQ3MjgtNzciIC8+PGZlQ29tcG9zaXRlCiAgICAgICAgIGluPSJvZmZzZXQiCiAgICAgICAgIGluMj0iU291cmNlR3JhcGhpYyIKICAgICAgICAgb3BlcmF0b3I9ImF0b3AiCiAgICAgICAgIHJlc3VsdD0iY29tcG9zaXRlMiIKICAgICAgICAgaWQ9ImZlQ29tcG9zaXRlNDczMC02IiAvPjwvZmlsdGVyPjxyYWRpYWxHcmFkaWVudAogICAgICAgY3g9IjYxLjUxODg4MyIKICAgICAgIGN5PSIxMzIuMjg1NzUiCiAgICAgICByPSIyOS4wMzY5MTMiCiAgICAgICBmeD0iNjEuNTE4ODgzIgogICAgICAgZnk9IjEzMi4yODU3NSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDE0ODAtMiIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI3OTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS43NDkwNTY1ZS04LC0wLjIzOTk0Njk2LDEuMDU0NjY4LDMuNzkxNTQ1N2UtNywtMTYuNDkwNjcyLDE4OC42NTg5NCkiIC8+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMjIiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48c3R5bGUKICAgICAgIHR5cGU9InRleHQvY3NzIgogICAgICAgaWQ9InN0eWxlNi0yLTQiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48cmVjdAogICAgICAgeD0iNDY0LjM2OTA4IgogICAgICAgeT0iMzM1Ljk4NTIzIgogICAgICAgd2lkdGg9IjIwNS41NTM1IgogICAgICAgaGVpZ2h0PSIxMzAuNTIzNDUiCiAgICAgICBpZD0icmVjdDQ0MzEtNyIgLz48cmVjdAogICAgICAgeD0iMjg1LjA1Mzk5IgogICAgICAgeT0iMzIzLjgwMjMxIgogICAgICAgd2lkdGg9IjQyLjE2NjExNSIKICAgICAgIGhlaWdodD0iMjIuODQ4MjY5IgogICAgICAgaWQ9InJlY3QzOTEyLTciIC8+PHJlY3QKICAgICAgIHg9IjczLjQ4ODY2MyIKICAgICAgIHk9IjE3NC40NjU4OCIKICAgICAgIHdpZHRoPSIxMjkuNjEyMjciCiAgICAgICBoZWlnaHQ9IjI1LjY0MDExMiIKICAgICAgIGlkPSJyZWN0MTA0ODUtMy01IiAvPjxyZWN0CiAgICAgICB4PSI4OS40OTA2NjIiCiAgICAgICB5PSIyMjUuMTIzMzgiCiAgICAgICB3aWR0aD0iNjIyLjk4Mzg5IgogICAgICAgaGVpZ2h0PSI0MTIuNzU0MTgiCiAgICAgICBpZD0icmVjdDc0Ny02LTQiIC8+PHJlY3QKICAgICAgIHg9IjUwOS45MzM0MSIKICAgICAgIHk9IjQ4MS40ODg1NiIKICAgICAgIHdpZHRoPSIyMDguMjUzODgiCiAgICAgICBoZWlnaHQ9IjY4LjcyMzA4MyIKICAgICAgIGlkPSJyZWN0NzQxLTctOCIgLz48ZmlsdGVyCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0IiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iRHJvcCBTaGFkb3ciCiAgICAgICBpZD0iZmlsdGVyNDcyMC01LTEiCiAgICAgICB4PSItMC4wODk1OTEwNDkiCiAgICAgICB5PSItMC4yMjg4MjQzMyIKICAgICAgIHdpZHRoPSIxLjE1MjgzMTgiCiAgICAgICBoZWlnaHQ9IjEuMzkwMzQ3NCI+PGZlRmxvb2QKICAgICAgICAgZmxvb2Qtb3BhY2l0eT0iMC40OTgwMzkiCiAgICAgICAgIGZsb29kLWNvbG9yPSJyZ2IoMCwwLDApIgogICAgICAgICByZXN1bHQ9ImZsb29kIgogICAgICAgICBpZD0iZmVGbG9vZDQ3MjItMy0yIiAvPjxmZUNvbXBvc2l0ZQogICAgICAgICBpbj0iZmxvb2QiCiAgICAgICAgIGluMj0iU291cmNlR3JhcGhpYyIKICAgICAgICAgb3BlcmF0b3I9Im91dCIKICAgICAgICAgcmVzdWx0PSJjb21wb3NpdGUxIgogICAgICAgICBpZD0iZmVDb21wb3NpdGU0NzI0LTUtOCIgLz48ZmVHYXVzc2lhbkJsdXIKICAgICAgICAgaW49ImNvbXBvc2l0ZTEiCiAgICAgICAgIHN0ZERldmlhdGlvbj0iMiIKICAgICAgICAgcmVzdWx0PSJibHVyIgogICAgICAgICBpZD0iZmVHYXVzc2lhbkJsdXI0NzI2LTYtOSIgLz48ZmVPZmZzZXQKICAgICAgICAgZHg9Ii0yIgogICAgICAgICBkeT0iLTIiCiAgICAgICAgIHJlc3VsdD0ib2Zmc2V0IgogICAgICAgICBpZD0iZmVPZmZzZXQ0NzI4LTItMyIgLz48ZmVDb21wb3NpdGUKICAgICAgICAgaW49Im9mZnNldCIKICAgICAgICAgaW4yPSJTb3VyY2VHcmFwaGljIgogICAgICAgICBvcGVyYXRvcj0iYXRvcCIKICAgICAgICAgcmVzdWx0PSJjb21wb3NpdGUyIgogICAgICAgICBpZD0iZmVDb21wb3NpdGU0NzMwLTktNiIgLz48L2ZpbHRlcj48cmFkaWFsR3JhZGllbnQKICAgICAgIGN4PSI2MS41MTg4ODMiCiAgICAgICBjeT0iMTMyLjI4NTc1IgogICAgICAgcj0iMjkuMDM2OTEzIgogICAgICAgZng9IjYxLjUxODg4MyIKICAgICAgIGZ5PSIxMzIuMjg1NzUiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQxNDgwLTktOCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI3OTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS43NDkwNTY1ZS04LC0wLjIzOTk0Njk2LDEuMDU0NjY4LDMuNzkxNTQ1N2UtNywtMTYuNDkwNjcyLDE4OC42NTg5NCkiIC8+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMTgtMCI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTItNy0yIj4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMS0xIj4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMC0wIj4KICAgCiAgICAuZmlsMCB7ZmlsbDojMDAwMDAwO2ZpbGwtcnVsZTpub256ZXJvfQogICAKICA8L3N0eWxlPjxyZWN0CiAgICAgICB4PSI3My40ODg2NjMiCiAgICAgICB5PSIxNzQuNDY1ODgiCiAgICAgICB3aWR0aD0iMTI5LjYxMjI3IgogICAgICAgaGVpZ2h0PSIyNS42NDAxMTIiCiAgICAgICBpZD0icmVjdDEwNDg1LTktNSIgLz48cmVjdAogICAgICAgeD0iODkuNDkwNjYyIgogICAgICAgeT0iMjI1LjEyMzM4IgogICAgICAgd2lkdGg9IjYyMi45ODM4OSIKICAgICAgIGhlaWdodD0iNDEyLjc1NDE4IgogICAgICAgaWQ9InJlY3Q3NDctNC0xIiAvPjxyZWN0CiAgICAgICB4PSI1MDkuOTMzNDEiCiAgICAgICB5PSI0ODEuNDg4NTYiCiAgICAgICB3aWR0aD0iMjA4LjI1Mzg4IgogICAgICAgaGVpZ2h0PSI2OC43MjMwODMiCiAgICAgICBpZD0icmVjdDc0MS05LTEiIC8+PGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkRyb3AgU2hhZG93IgogICAgICAgaWQ9ImZpbHRlcjQ3MjAtMC0wIgogICAgICAgeD0iLTAuMDg5NTkxMDQ5IgogICAgICAgeT0iLTAuMjI4ODI0MzMiCiAgICAgICB3aWR0aD0iMS4xNTI4MzE4IgogICAgICAgaGVpZ2h0PSIxLjM5MDM0NzQiPjxmZUZsb29kCiAgICAgICAgIGZsb29kLW9wYWNpdHk9IjAuNDk4MDM5IgogICAgICAgICBmbG9vZC1jb2xvcj0icmdiKDAsMCwwKSIKICAgICAgICAgcmVzdWx0PSJmbG9vZCIKICAgICAgICAgaWQ9ImZlRmxvb2Q0NzIyLTktOCIgLz48ZmVDb21wb3NpdGUKICAgICAgICAgaW49ImZsb29kIgogICAgICAgICBpbjI9IlNvdXJjZUdyYXBoaWMiCiAgICAgICAgIG9wZXJhdG9yPSJvdXQiCiAgICAgICAgIHJlc3VsdD0iY29tcG9zaXRlMSIKICAgICAgICAgaWQ9ImZlQ29tcG9zaXRlNDcyNC0xLTUiIC8+PGZlR2F1c3NpYW5CbHVyCiAgICAgICAgIGluPSJjb21wb3NpdGUxIgogICAgICAgICBzdGREZXZpYXRpb249IjIiCiAgICAgICAgIHJlc3VsdD0iYmx1ciIKICAgICAgICAgaWQ9ImZlR2F1c3NpYW5CbHVyNDcyNi03LTAiIC8+PGZlT2Zmc2V0CiAgICAgICAgIGR4PSItMiIKICAgICAgICAgZHk9Ii0yIgogICAgICAgICByZXN1bHQ9Im9mZnNldCIKICAgICAgICAgaWQ9ImZlT2Zmc2V0NDcyOC03LTYiIC8+PGZlQ29tcG9zaXRlCiAgICAgICAgIGluPSJvZmZzZXQiCiAgICAgICAgIGluMj0iU291cmNlR3JhcGhpYyIKICAgICAgICAgb3BlcmF0b3I9ImF0b3AiCiAgICAgICAgIHJlc3VsdD0iY29tcG9zaXRlMiIKICAgICAgICAgaWQ9ImZlQ29tcG9zaXRlNDczMC0xLTQiIC8+PC9maWx0ZXI+PHJhZGlhbEdyYWRpZW50CiAgICAgICBjeD0iNjEuNTE4ODgzIgogICAgICAgY3k9IjEzMi4yODU3NSIKICAgICAgIHI9IjI5LjAzNjkxMyIKICAgICAgIGZ4PSI2MS41MTg4ODMiCiAgICAgICBmeT0iMTMyLjI4NTc1IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MTQ4MC03LTYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyNzk1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuNzQ5MDU2NWUtOCwtMC4yMzk5NDY5NiwxLjA1NDY2OCwzLjc5MTU0NTdlLTcsLTE2LjQ5MDY3MiwxODguNjU4OTQpIiAvPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTMtMiI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTItOS01Ij4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PGZpbHRlcgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkJsdXIiCiAgICAgICBpZD0iZmlsdGVyMjc3NTUiCiAgICAgICB4PSItMC4wMzY0NzI1NTUiCiAgICAgICB5PSItMC4wMzU5NDgwMzgiCiAgICAgICB3aWR0aD0iMS4wNzI5NDUxIgogICAgICAgaGVpZ2h0PSIxLjA3MTg5NjEiPjxmZUdhdXNzaWFuQmx1cgogICAgICAgICBzdGREZXZpYXRpb249IjAuMTUgMC4xNSIKICAgICAgICAgcmVzdWx0PSJmYlNvdXJjZUdyYXBoaWMiCiAgICAgICAgIGlkPSJmZUdhdXNzaWFuQmx1cjI3NzUzIiAvPjxmZUNvbG9yTWF0cml4CiAgICAgICAgIHJlc3VsdD0iZmJTb3VyY2VHcmFwaGljQWxwaGEiCiAgICAgICAgIGluPSJmYlNvdXJjZUdyYXBoaWMiCiAgICAgICAgIHZhbHVlcz0iMCAwIDAgLTEgMCAwIDAgMCAtMSAwIDAgMCAwIC0xIDAgMCAwIDAgMSAwIgogICAgICAgICBpZD0iZmVDb2xvck1hdHJpeDI3NzgxIiAvPjxmZUdhdXNzaWFuQmx1cgogICAgICAgICBpZD0iZmVHYXVzc2lhbkJsdXIyNzc4MyIKICAgICAgICAgc3RkRGV2aWF0aW9uPSIwLjE1IDAuMTUiCiAgICAgICAgIHJlc3VsdD0iYmx1ciIKICAgICAgICAgaW49ImZiU291cmNlR3JhcGhpYyIgLz48L2ZpbHRlcj48bWFya2VyCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpZD0ibWFya2VyMjMxNTgiCiAgICAgICByZWZYPSIwIgogICAgICAgcmVmWT0iMCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IlRyaWFuZ2xlT3V0TCI+PHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgwLjgpIgogICAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoxcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSA1Ljc3LDAgLTIuODgsNSBWIC01IFoiCiAgICAgICAgIGlkPSJwYXRoMjMxNTYiIC8+PC9tYXJrZXI+PG1hcmtlcgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaWQ9Im1hcmtlcjIzMDEwIgogICAgICAgcmVmWD0iMCIKICAgICAgIHJlZlk9IjAiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJUcmlhbmdsZUluTCI+PHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgtMC44KSIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MXB0O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Ik0gNS43NywwIC0yLjg4LDUgViAtNSBaIgogICAgICAgICBpZD0icGF0aDIzMDA4IiAvPjwvbWFya2VyPjxtYXJrZXIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IlRyaWFuZ2xlT3V0TCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjE3NTA4IgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj48cGF0aAogICAgICAgICBpZD0icGF0aDE3NTA2IgogICAgICAgICBkPSJNIDUuNzcsMCAtMi44OCw1IFYgLTUgWiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2FlZDZkYztmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6I2FlZDZkYztzdHJva2Utd2lkdGg6MXB0O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMC44KSIgLz48L21hcmtlcj48bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJUcmlhbmdsZUluTCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjE3MzcyIgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj48cGF0aAogICAgICAgICBpZD0icGF0aDE3MzcwIgogICAgICAgICBkPSJNIDUuNzcsMCAtMi44OCw1IFYgLTUgWiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2FlZDZkYztmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6I2FlZDZkYztzdHJva2Utd2lkdGg6MXB0O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoLTAuOCkiIC8+PC9tYXJrZXI+PG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iVHJpYW5nbGVPdXRMIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgcmVmWT0iMCIKICAgICAgIHJlZlg9IjAiCiAgICAgICBpZD0ibWFya2VyMTY4NTEiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiPjxwYXRoCiAgICAgICAgIGlkPSJwYXRoMTY4NDkiCiAgICAgICAgIGQ9Ik0gNS43NywwIC0yLjg4LDUgViAtNSBaIgogICAgICAgICBzdHlsZT0iZmlsbDojZmZmYmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojZmZmYmZmO3N0cm9rZS13aWR0aDoxcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgwLjgpIiAvPjwvbWFya2VyPjxtYXJrZXIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IlRyaWFuZ2xlT3V0TCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjgzODMzIgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj48cGF0aAogICAgICAgICBpZD0icGF0aDgzODMxIgogICAgICAgICBkPSJNIDUuNzcsMCAtMi44OCw1IFYgLTUgWiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2FlZDZkYztmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6I2FlZDZkYztzdHJva2Utd2lkdGg6MXB0O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMC44KSIgLz48L21hcmtlcj48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBpZD0icGF0aC1lZmZlY3QzNjY4MiIKICAgICAgIGlzX3Zpc2libGU9InRydWUiCiAgICAgICBscGV2ZXJzaW9uPSIwIiAvPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDM2Njc4IgogICAgICAgZWZmZWN0PSJzcGlybyIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGlua3NjYXBlOnBhdGgtZWZmZWN0CiAgICAgICBlZmZlY3Q9InNwaXJvIgogICAgICAgaWQ9InBhdGgtZWZmZWN0MzY2NjIiCiAgICAgICBpc192aXNpYmxlPSJ0cnVlIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGlzX3Zpc2libGU9InRydWUiCiAgICAgICBpZD0icGF0aC1lZmZlY3QzNjY1OCIKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBscGV2ZXJzaW9uPSIwIiAvPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgZWZmZWN0PSJzcGlybyIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDM2NjMzIgogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGlua3NjYXBlOnBhdGgtZWZmZWN0CiAgICAgICBlZmZlY3Q9ImJzcGxpbmUiCiAgICAgICBpZD0icGF0aC1lZmZlY3QzNjYyOSIKICAgICAgIGlzX3Zpc2libGU9InRydWUiCiAgICAgICB3ZWlnaHQ9IjMzLjMzMzMzMyIKICAgICAgIHN0ZXBzPSIyIgogICAgICAgaGVscGVyX3NpemU9IjAiCiAgICAgICBhcHBseV9ub193ZWlnaHQ9InRydWUiCiAgICAgICBhcHBseV93aXRoX3dlaWdodD0idHJ1ZSIKICAgICAgIG9ubHlfc2VsZWN0ZWQ9ImZhbHNlIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJEaWFtb25kTGVuZCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjM2MjY5IgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIj48cGF0aAogICAgICAgICBpZD0icGF0aDgxMTUiCiAgICAgICAgIGQ9Ik0gMCwtNy4wNzEwNzY4IC03LjA3MTA4OTQsMCAwLDcuMDcxMDU4OSA3LjA3MTA0NjIsMCBaIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44LDAsMCwwLjgsLTUuNiwwKSIgLz48L21hcmtlcj48bWFya2VyCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpZD0ibWFya2VyMTM1MDkiCiAgICAgICByZWZYPSIwIgogICAgICAgcmVmWT0iMCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IlRyaWFuZ2xlSW5MIj48cGF0aAogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKC0wLjgpIgogICAgICAgICBzdHlsZT0iZmlsbDojYjliOWI5O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojYjliOWI5O3N0cm9rZS13aWR0aDoxcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSA1Ljc3LDAgLTIuODgsNSBWIC01IFoiCiAgICAgICAgIGlkPSJwYXRoMTM1MDciIC8+PC9tYXJrZXI+PG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iRGlhbW9uZExlbmQiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICByZWZZPSIwIgogICAgICAgcmVmWD0iMCIKICAgICAgIGlkPSJEaWFtb25kTGVuZCIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSI+PHBhdGgKICAgICAgICAgaWQ9InBhdGgxMDE3MyIKICAgICAgICAgZD0iTSAwLC03LjA3MTA3NjggLTcuMDcxMDg5NCwwIDAsNy4wNzEwNTg5IDcuMDcxMDQ2MiwwIFoiCiAgICAgICAgIHN0eWxlPSJmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MXB0IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjgsMCwwLDAuOCwtNS42LDApIiAvPjwvbWFya2VyPjxtYXJrZXIKICAgICAgIGlua3NjYXBlOnN0b2NraWQ9IkFycm93MUxzdGFydCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9IkFycm93MUxzdGFydCIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaW5rc2NhcGU6aXNzdG9jaz0idHJ1ZSI+PHBhdGgKICAgICAgICAgaWQ9InBhdGgxMDA3NiIKICAgICAgICAgZD0iTSAwLDAgNSwtNSAtMTIuNSwwIDUsNSBaIgogICAgICAgICBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFwdCIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44LDAsMCwwLjgsMTAsMCkiIC8+PC9tYXJrZXI+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDQyNzMiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjE7ZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eTowLjk0MTE3NiIKICAgICAgICAgaWQ9InJlY3Q0Mjc1IgogICAgICAgICB3aWR0aD0iNy40ODc3NTEiCiAgICAgICAgIGhlaWdodD0iNy40OTM2MDA0IgogICAgICAgICB4PSI2OS4wMTY1NDEiCiAgICAgICAgIHk9IjEwMS4zNDQ0NCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGg0MzcxIj48cmVjdAogICAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MC45NDExNzYiCiAgICAgICAgIGlkPSJyZWN0NDM3MyIKICAgICAgICAgd2lkdGg9IjExLjA1MDE0NCIKICAgICAgICAgaGVpZ2h0PSI4LjY5OTA1MjgiCiAgICAgICAgIHg9Ijg5LjEwNjQ5OSIKICAgICAgICAgeT0iMTM4LjUyNjcyIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxMDI2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTAyNCIKICAgICAgICAgZD0iTSAwLDAgSCAzNjAgViAzNjAgSCAwIFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDEwMzgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxMDM2IgogICAgICAgICBkPSJtIDMzLjQ4LDMyNS4yOSBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTI5NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDEyOTQiCiAgICAgICAgIGQ9Im0gMzMuNDgsMzEzLjc0IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjIyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYyMCIKICAgICAgICAgZD0ibSAzMy40OCwzMDIuMTkgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE3OTAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNzg4IgogICAgICAgICBkPSJtIDMzLjQ4LDI5MC42MyBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTk0NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE5NDQiCiAgICAgICAgIGQ9Im0gMzMuNDgsMjc5LjA4IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgyMTY4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMjE2Ni0wIgogICAgICAgICBkPSJtIDMzLjQ4LDI2Ny41MiBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMjMzNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDIzMzQiCiAgICAgICAgIGQ9Im0gMzMuNDgsMjU1Ljk3IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgyNTI2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMjUyNCIKICAgICAgICAgZD0ibSAzMy40OCwyNDQuNDIgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDI3MDIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyNzAwIgogICAgICAgICBkPSJtIDMzLjQ4LDIzMi44NiBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMjkwMCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDI4OTgiCiAgICAgICAgIGQ9Im0gMzMuNDgsMjIxLjMxIGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMDc0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzA3MiIKICAgICAgICAgZD0iTSAzMy40OCwyMDkuNzUgSCAzMTUuNzQgViAyMjEuMyBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMxODQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMTgyIgogICAgICAgICBkPSJtIDMzLjQ4LDE5OC4yIGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMjkyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzI5MCIKICAgICAgICAgZD0iTSAzMy40OCwxODYuNjUgSCAzMTUuNzQgViAxOTguMiBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDM0MDIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzNDAwIgogICAgICAgICBkPSJtIDMzLjQ4LDE3NS4wOSBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzUzMiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDM1MzAiCiAgICAgICAgIGQ9Im0gMzMuNDgsMTYzLjU0IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzNjMwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzYyOCIKICAgICAgICAgZD0ibSAzMy40OCwxNTEuOTkgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDM4NTQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzODUyIgogICAgICAgICBkPSJtIDMzLjQ4LDE0MC40MyBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzk1NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDM5NTIiCiAgICAgICAgIGQ9Im0gMzMuNDgsMTI4Ljg4IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0MTEwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDEwOCIKICAgICAgICAgZD0ibSAzMy40OCwxMTcuMzIgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQxNTIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0MTUwIgogICAgICAgICBkPSJtIDMzLjQ4LDEwNS43NyBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDIzNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQyMzQiCiAgICAgICAgIGQ9Im0gMzMuNDgsOTQuMjIgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQyODIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0MjgwIgogICAgICAgICBkPSJNIDMzLjQ4LDgyLjY2IEggMzE1Ljc0IFYgOTQuMjEgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0MzE4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDMxNiIKICAgICAgICAgZD0iTSAzMy40OCw3MS4xMSBIIDMxNS43NCBWIDgyLjY2IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDM5OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQzOTYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDMyNS4yOSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDQwNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ0MDQtNyIKICAgICAgICAgZD0ibSAzMTUuNzQsMzI1LjI5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0NDE4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDQxNi05IgogICAgICAgICBkPSJtIDMxNS43NCwzMjUuMjkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ0MjYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NDI0IgogICAgICAgICBkPSJtIDMxNS43NCwzMjUuMjkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ0MzYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NDM0IgogICAgICAgICBkPSJtIDMxNS43NCwzMTMuNzQgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ0NDQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NDQyLTMiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDMxMy43NCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDQ1NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ0NTQtOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMzEzLjc0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0NDY0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDQ2MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMzEzLjc0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0NDc0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDQ3MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMzAyLjE5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0NDgyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDQ4MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMzAyLjE5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0NDk0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDQ5Mi0wIgogICAgICAgICBkPSJtIDMxNS43NCwzMDIuMTkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ1MDIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NTAwIgogICAgICAgICBkPSJtIDMxNS43NCwzMDIuMTkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ1MTIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NTEwIgogICAgICAgICBkPSJtIDMxNS43NCwyOTAuNjMgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ1MjAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NTE4IgogICAgICAgICBkPSJtIDMxNS43NCwyOTAuNjMgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ1MzIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NTMwIgogICAgICAgICBkPSJtIDMxNS43NCwyOTAuNjMgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ1NDAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NTM4LTIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI5MC42MyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDU1MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ1NDgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI3OS4wOCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDU1OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ1NTYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI3OS4wOCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDU3MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ1NjgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI3OS4wOCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDU3OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ1NzYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI3OS4wOCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDU4OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ1ODYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI2Ny41MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDU5NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ1OTQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI2Ny41MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDYwOCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2MDYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI2Ny41MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDYxNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2MTQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI2Ny41MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDYyNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2MjQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI1NS45NyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDYzNCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2MzIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI1NS45NyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDY0NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NDQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI1NS45NyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDY1NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NTIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI1NS45NyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDY2NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NjIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI0NC40MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDY3MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NzAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI0NC40MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDY4NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2ODIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI0NC40MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDY5MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2OTAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI0NC40MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDcwMiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MDAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIzMi44NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDcxMCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MDgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIzMi44NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDcyMiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MjAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIzMi44NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDczMCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MjgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIzMi44NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDc0MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MzgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIyMS4zMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDc0OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3NDYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIyMS4zMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDc2MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3NTgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIyMS4zMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDc2OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3NjYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIyMS4zMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDc3OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3NzYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIwOS43NSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDc4NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3ODQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIwOS43NSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDc5OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3OTYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIwOS43NSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDgwNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ4MDQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIwOS43NSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDgxNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ4MTQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE5OC4yIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODI0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDgyMiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTk4LjIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4MzYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0ODM0IgogICAgICAgICBkPSJtIDMxNS43NCwxOTguMiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDg0NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ4NDIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE5OC4yIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODU0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg1MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTg2LjY1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODYyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg2MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTg2LjY1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODc0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg3MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTg2LjY1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODgyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg4MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTg2LjY1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODkyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg5MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTc1LjA5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTAwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg5OCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTc1LjA5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTEyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDkxMCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTc1LjA5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTIwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDkxOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTc1LjA5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTMwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDkyOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTYzLjU0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTM4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDkzNiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTYzLjU0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTUwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDk0OCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTYzLjU0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTU4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDk1NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTYzLjU0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTY4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDk2NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTUxLjk5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTc2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDk3NCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTUxLjk5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTg4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDk4NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTUxLjk5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0OTk2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDk5NCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTUxLjk5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDA2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTAwNCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTQwLjQzIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDE0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTAxMiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTQwLjQzIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDI2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTAyNCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTQwLjQzIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDM0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTAzMiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTQwLjQzIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDQ0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTA0MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTI4Ljg4IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDUyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTA1MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTI4Ljg4IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDY0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTA2MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTI4Ljg4IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDcyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTA3MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTI4Ljg4IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDgyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTA4MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTE3LjMyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MDkwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTA4OCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTE3LjMyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTAyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTEwMCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTE3LjMyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTEwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTEwOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTE3LjMyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTIwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTExOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTA1Ljc3IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTI4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTEyNiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTA1Ljc3IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTQwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTEzOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTA1Ljc3IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTQ4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTE0NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTA1Ljc3IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTU4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTE1NiIKICAgICAgICAgZD0ibSAzMTUuNzQsOTQuMjIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDUxNjYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg1MTY0IgogICAgICAgICBkPSJtIDMxNS43NCw5NC4yMiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNTE3OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDUxNzYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDk0LjIyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MTg2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTE4NCIKICAgICAgICAgZD0ibSAzMTUuNzQsOTQuMjIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDUxOTYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg1MTk0IgogICAgICAgICBkPSJtIDMxNS43NCw4Mi42NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNTIwNCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDUyMDIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDgyLjY2IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MjE2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTIxNCIKICAgICAgICAgZD0ibSAzMTUuNzQsODIuNjYgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDUyMjQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg1MjIyIgogICAgICAgICBkPSJtIDMxNS43NCw4Mi42NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNTIzNCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDUyMzIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDcxLjExIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg1MjQyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNTI0MCIKICAgICAgICAgZD0ibSAzMTUuNzQsNzEuMTEgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDUyNTQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg1MjUyIgogICAgICAgICBkPSJtIDMxNS43NCw3MS4xMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNTI2MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDUyNjAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDcxLjExIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxMjYxMiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDEyNjEwIgogICAgICAgICBkPSJNIDAsMCBIIDM2MCBWIDM2MCBIIDAgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTI2MjQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxMjYyMiIKICAgICAgICAgZD0ibSAzMy40OCwzMjUuMjkgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDEyODgyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTI4ODAiCiAgICAgICAgIGQ9Im0gMzMuNDgsMzEzLjc0IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxMzIwOCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDEzMjA2IgogICAgICAgICBkPSJtIDMzLjQ4LDMwMi4xOSBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTMzNzYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxMzM3NCIKICAgICAgICAgZD0ibSAzMy40OCwyOTAuNjMgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDEzNTMyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTM1MzAiCiAgICAgICAgIGQ9Im0gMzMuNDgsMjc5LjA4IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxMzc1NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDEzNzUyIgogICAgICAgICBkPSJtIDMzLjQ4LDI2Ny41MiBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTM5MjIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxMzkyMCIKICAgICAgICAgZD0ibSAzMy40OCwyNTUuOTcgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE0MTEyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTQxMTAiCiAgICAgICAgIGQ9Im0gMzMuNDgsMjQ0LjQyIGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNDI4OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE0Mjg2IgogICAgICAgICBkPSJtIDMzLjQ4LDIzMi44NiBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTQ0ODYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNDQ4NCIKICAgICAgICAgZD0ibSAzMy40OCwyMjEuMzEgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE0NjYwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTQ2NTgiCiAgICAgICAgIGQ9Ik0gMzMuNDgsMjA5Ljc1IEggMzE1Ljc0IFYgMjIxLjMgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNDc3MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE0NzY4IgogICAgICAgICBkPSJtIDMzLjQ4LDE5OC4yIGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNDg3OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE0ODc2IgogICAgICAgICBkPSJNIDMzLjQ4LDE4Ni42NSBIIDMxNS43NCBWIDE5OC4yIEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTQ5ODgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNDk4NiIKICAgICAgICAgZD0ibSAzMy40OCwxNzUuMDkgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE1MTE4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTUxMTYiCiAgICAgICAgIGQ9Im0gMzMuNDgsMTYzLjU0IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNTIxNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE1MjE0IgogICAgICAgICBkPSJtIDMzLjQ4LDE1MS45OSBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTU0NDAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNTQzOCIKICAgICAgICAgZD0ibSAzMy40OCwxNDAuNDMgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE1NTQwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTU1MzgiCiAgICAgICAgIGQ9Im0gMzMuNDgsMTI4Ljg4IGggMjgyLjI2IHYgMTEuNTUgSCAzMy40OCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNTY5NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE1Njk0IgogICAgICAgICBkPSJtIDMzLjQ4LDExNy4zMiBoIDI4Mi4yNiB2IDExLjU1IEggMzMuNDggWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTU3MzgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNTczNiIKICAgICAgICAgZD0ibSAzMy40OCwxMDUuNzcgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE1ODIyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTU4MjAiCiAgICAgICAgIGQ9Im0gMzMuNDgsOTQuMjIgaCAyODIuMjYgdiAxMS41NSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE1ODY4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTU4NjYiCiAgICAgICAgIGQ9Ik0gMzMuNDgsODIuNjYgSCAzMTUuNzQgViA5NC4yMSBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE1OTA0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTU5MDIiCiAgICAgICAgIGQ9Ik0gMzMuNDgsNzEuMTEgSCAzMTUuNzQgViA4Mi42NiBIIDMzLjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE1OTg0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTU5ODIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDMyNS4yOSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTU5OTIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNTk5MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMzI1LjI5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjAwNCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MDAyIgogICAgICAgICBkPSJtIDMxNS43NCwzMjUuMjkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MDEyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYwMTAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDMyNS4yOSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYwMjIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjAyMCIKICAgICAgICAgZD0ibSAzMTUuNzQsMzEzLjc0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjAzMCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MDI4IgogICAgICAgICBkPSJtIDMxNS43NCwzMTMuNzQgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MDQyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYwNDAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDMxMy43NCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYwNTAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjA0OCIKICAgICAgICAgZD0ibSAzMTUuNzQsMzEzLjc0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjA2MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MDU4IgogICAgICAgICBkPSJtIDMxNS43NCwzMDIuMTkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MDY4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYwNjYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDMwMi4xOSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYwODAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjA3OCIKICAgICAgICAgZD0ibSAzMTUuNzQsMzAyLjE5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjA4OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MDg2IgogICAgICAgICBkPSJtIDMxNS43NCwzMDIuMTkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MDk4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYwOTYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI5MC42MyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYxMDYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjEwNCIKICAgICAgICAgZD0ibSAzMTUuNzQsMjkwLjYzIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjExOCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MTE2IgogICAgICAgICBkPSJtIDMxNS43NCwyOTAuNjMgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MTI2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYxMjQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI5MC42MyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYxMzYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjEzNCIKICAgICAgICAgZD0ibSAzMTUuNzQsMjc5LjA4IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjE0NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MTQyIgogICAgICAgICBkPSJtIDMxNS43NCwyNzkuMDggaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MTU2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYxNTQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI3OS4wOCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYxNjQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjE2MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMjc5LjA4IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjE3NCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MTcyIgogICAgICAgICBkPSJtIDMxNS43NCwyNjcuNTIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MTgyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYxODAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI2Ny41MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYxOTQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjE5MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMjY3LjUyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjIwMiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MjAwIgogICAgICAgICBkPSJtIDMxNS43NCwyNjcuNTIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MjEyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYyMTAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI1NS45NyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYyMjAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjIxOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMjU1Ljk3IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjIzMiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MjMwIgogICAgICAgICBkPSJtIDMxNS43NCwyNTUuOTcgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MjQwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYyMzgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI1NS45NyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYyNTAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjI0OCIKICAgICAgICAgZD0ibSAzMTUuNzQsMjQ0LjQyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjI1OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MjU2IgogICAgICAgICBkPSJtIDMxNS43NCwyNDQuNDIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MjcwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYyNjgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDI0NC40MiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYyNzgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjI3NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMjQ0LjQyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjI4OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2Mjg2IgogICAgICAgICBkPSJtIDMxNS43NCwyMzIuODYgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2Mjk2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYyOTQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIzMi44NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYzMDgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjMwNiIKICAgICAgICAgZD0ibSAzMTUuNzQsMjMyLjg2IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjMxNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MzE0IgogICAgICAgICBkPSJtIDMxNS43NCwyMzIuODYgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MzI2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYzMjQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIyMS4zMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYzMzQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjMzMiIKICAgICAgICAgZD0ibSAzMTUuNzQsMjIxLjMxIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjM0NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MzQ0IgogICAgICAgICBkPSJtIDMxNS43NCwyMjEuMzEgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2MzU0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYzNTIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIyMS4zMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYzNjQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjM2MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMjA5Ljc1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjM3MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2MzcwIgogICAgICAgICBkPSJtIDMxNS43NCwyMDkuNzUgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2Mzg0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTYzODIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDIwOS43NSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTYzOTIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjM5MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMjA5Ljc1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjQwMiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NDAwIgogICAgICAgICBkPSJtIDMxNS43NCwxOTguMiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY0MTAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjQwOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTk4LjIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NDIyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY0MjAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE5OC4yIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjQzMCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NDI4IgogICAgICAgICBkPSJtIDMxNS43NCwxOTguMiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY0NDAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjQzOCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTg2LjY1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjQ0OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NDQ2IgogICAgICAgICBkPSJtIDMxNS43NCwxODYuNjUgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NDYwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY0NTgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE4Ni42NSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY0NjgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjQ2NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTg2LjY1IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjQ3OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NDc2IgogICAgICAgICBkPSJtIDMxNS43NCwxNzUuMDkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NDg2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY0ODQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE3NS4wOSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY0OTgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjQ5NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTc1LjA5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjUwNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NTA0IgogICAgICAgICBkPSJtIDMxNS43NCwxNzUuMDkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NTE2IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY1MTQiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE2My41NCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY1MjQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjUyMiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTYzLjU0IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjUzNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NTM0IgogICAgICAgICBkPSJtIDMxNS43NCwxNjMuNTQgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NTQ0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY1NDIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE2My41NCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY1NTQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjU1MiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTUxLjk5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjU2MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NTYwIgogICAgICAgICBkPSJtIDMxNS43NCwxNTEuOTkgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NTc0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY1NzIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE1MS45OSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY1ODIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjU4MCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTUxLjk5IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjU5MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NTkwIgogICAgICAgICBkPSJtIDMxNS43NCwxNDAuNDMgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NjAwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY1OTgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDE0MC40MyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY2MTIiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjYxMCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTQwLjQzIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjYyMCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NjE4IgogICAgICAgICBkPSJtIDMxNS43NCwxNDAuNDMgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NjMwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY2MjgiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDEyOC44OCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY2MzgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjYzNiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTI4Ljg4IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjY1MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NjQ4IgogICAgICAgICBkPSJtIDMxNS43NCwxMjguODggaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NjU4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY2NTYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDEyOC44OCBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY2NjgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjY2NiIKICAgICAgICAgZD0ibSAzMTUuNzQsMTE3LjMyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjY3NiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2Njc0IgogICAgICAgICBkPSJtIDMxNS43NCwxMTcuMzIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2Njg4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY2ODYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDExNy4zMiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY2OTYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjY5NCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTE3LjMyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjcwNiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NzA0IgogICAgICAgICBkPSJtIDMxNS43NCwxMDUuNzcgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NzE0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY3MTIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDEwNS43NyBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY3MjYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjcyNCIKICAgICAgICAgZD0ibSAzMTUuNzQsMTA1Ljc3IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjczNCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NzMyIgogICAgICAgICBkPSJtIDMxNS43NCwxMDUuNzcgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NzQ0IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY3NDIiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDk0LjIyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjc1MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NzUwIgogICAgICAgICBkPSJtIDMxNS43NCw5NC4yMiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY3NjQiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjc2MiIKICAgICAgICAgZD0ibSAzMTUuNzQsOTQuMjIgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2NzcyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY3NzAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDk0LjIyIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjc4MiIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2NzgwIgogICAgICAgICBkPSJtIDMxNS43NCw4Mi42NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY3OTAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjc4OCIKICAgICAgICAgZD0ibSAzMTUuNzQsODIuNjYgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2ODAyIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY4MDAiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDgyLjY2IGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjgxMCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2ODA4IgogICAgICAgICBkPSJtIDMxNS43NCw4Mi42NiBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY4MjAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjgxOCIKICAgICAgICAgZD0ibSAzMTUuNzQsNzEuMTEgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDE2ODI4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMTY4MjYiCiAgICAgICAgIGQ9Im0gMzE1Ljc0LDcxLjExIGggMzguNzggdiAxMS41NSBoIC0zOC43OCB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgxNjg0MCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDE2ODM4IgogICAgICAgICBkPSJtIDMxNS43NCw3MS4xMSBoIDM4Ljc4IHYgMTEuNTUgaCAtMzguNzggeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTY4NDgiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgxNjg0NiIKICAgICAgICAgZD0ibSAzMTUuNzQsNzEuMTEgaCAzOC43OCB2IDExLjU1IGggLTM4Ljc4IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyMjQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzIyNiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyMjgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzIzMCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyMzIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzIzNCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyMzYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzIzOCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNDAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI0MiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNDQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI0NiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNDgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI1MCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNTIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI1NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNTYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI1OCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNjAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI2MiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNjQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI2NiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNjgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI3MCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNzIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI3NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyNzYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI3OCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyODAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI4MiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyODQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI4NiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyODgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI5MCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyOTIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI5NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjcyOTYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzI5OCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMDAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMwMiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMDQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMwNiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMDgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMxMCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMTIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMxNCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMTYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMxOCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMjAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMyMiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMjQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMyNiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMjgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMzMCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMzIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMzNCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczMzYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzMzOCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNDAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM0MiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNDQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM0NiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNDgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM1MCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNTIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM1NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNTYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM1OCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNjAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM2MiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNjQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM2NiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNjgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM3MCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNzIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM3NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczNzYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM3OCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczODAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM4MiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczODQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM4NiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczODgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM5MCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczOTIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM5NCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjczOTYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzM5OCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0MDAiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzQwMiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0MDQiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzQwNiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0MDgiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzQxMCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0MTIiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzQxNCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0MTYiPjxyZWN0CiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHg9IjEyLjkyNDI2NCIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHdpZHRoPSIyMDEuOTMzMyIKICAgICAgICAgaWQ9InJlY3QyNzQxOCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0MjIiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NDI0IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NDI2Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzQyOCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzQzMCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc0MzIiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0MzQiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NDM2IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NDM4Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzQ0MCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzQ0MiI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc0NDQiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0NDYiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NDQ4IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NDUwIj48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzQ1MiIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzQ1NCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc0NTYiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0NTgiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NDYwIgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NDYyIj48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzQ2NCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzQ2NiI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc0NjgiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0NzAiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NDcyIgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NDc0Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzQ3NiIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzQ3OCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc0ODAiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0ODIiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NDg0IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NDg2Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzQ4OCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzQ5MCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc0OTIiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc0OTQiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NDk2IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NDk4Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzUwMCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzUwMiI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1MDQiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1MDYiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTA4IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTEwIj48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzUxMiIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzUxNCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1MTYiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1MTgiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTIwIgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTIyIj48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzUyNCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzUyNiI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1MjgiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1MzAiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTMyIgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTM0Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzUzNiIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzUzOCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1NDAiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1NDIiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTQ0IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTQ2Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzU0OCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzU1MCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1NTIiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1NTQiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTU2IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTU4Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzU2MCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzU2MiI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1NjQiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1NjYiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTY4IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTcwIj48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzU3MiIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzU3NCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1NzYiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1NzgiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTgwIgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTgyIj48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzU4NCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzU4NiI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc1ODgiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc1OTAiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NTkyIgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NTk0Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzU5NiIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzU5OCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc2MDAiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc2MDIiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NjA0IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDI3NjA2Ij48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojNGE1MzZiO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZDdiOGI1O3N0cm9rZS13aWR0aDoyLjQ4OTkyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaWQ9InJlY3QyNzYwOCIKICAgICAgICAgd2lkdGg9IjE0MC4yMzE0NiIKICAgICAgICAgaGVpZ2h0PSIxNjMuMjI1NjYiCiAgICAgICAgIHg9IjEyLjEyMjkyNyIKICAgICAgICAgeT0iLTIxOC44ODM1OCIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgxLC0xKSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyNzYxMCI+PHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzRhNTM2YjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2Q3YjhiNTtzdHJva2Utd2lkdGg6Mi40ODk5MjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGlkPSJyZWN0Mjc2MTIiCiAgICAgICAgIHdpZHRoPSIxNDAuMjMxNDYiCiAgICAgICAgIGhlaWdodD0iMTYzLjIyNTY2IgogICAgICAgICB4PSIxMi4xMjI5MjciCiAgICAgICAgIHk9Ii0yMTguODgzNTgiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMSwtMSkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjc2MTQiPjxyZWN0CiAgICAgICAgIHN0eWxlPSJmaWxsOiM0YTUzNmI7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNkN2I4YjU7c3Ryb2tlLXdpZHRoOjIuNDg5OTI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDI3NjE2IgogICAgICAgICB3aWR0aD0iMTQwLjIzMTQ2IgogICAgICAgICBoZWlnaHQ9IjE2My4yMjU2NiIKICAgICAgICAgeD0iMTIuMTIyOTI3IgogICAgICAgICB5PSItMjE4Ljg4MzU4IgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDEsLTEpIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgyODU1NyIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDI4NTU1IgogICAgICAgICBkPSJNIDUxLjI1LDg1LjAzIEggMzU0LjUyIFYgMjEwLjUyIEggNTEuMjUgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMjk1NzciCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyOTU3NSIKICAgICAgICAgZD0iTSAxMi4xLDAgSCAzNDcuOTEgViAyMTYgSCAxMi4xIFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDI5NTg5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMjk1ODciCiAgICAgICAgIGQ9Ik0gNDAuNTcsMzEuOTEgSCAxODQuMyBWIDE3NS42NCBIIDQwLjU3IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMwMDAxIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMjk5OTkiCiAgICAgICAgIGQ9Ik0gMTk4LjcsMzEuOTEgSCAzNDIuNDMgViAxNzUuNjQgSCAxOTguNyBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMDQxMyIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwNDExIgogICAgICAgICBkPSJNIDQwLjU3LDE3NS42NCBIIDE4NC4zIHYgMTcuMjEgSCA0MC41NyBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMDQyMSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwNDE5IgogICAgICAgICBkPSJNIDQwLjU3LDE3NS42NCBIIDE4NC4zIHYgMTcuMjEgSCA0MC41NyBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMDQzMyIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwNDMxIgogICAgICAgICBkPSJNIDQwLjU3LDE3NS42NCBIIDE4NC4zIHYgMTcuMjEgSCA0MC41NyBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMDQ0MSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwNDM5IgogICAgICAgICBkPSJNIDQwLjU3LDE3NS42NCBIIDE4NC4zIHYgMTcuMjEgSCA0MC41NyBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMDQ1MSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwNDQ5IgogICAgICAgICBkPSJtIDE5OC43LDE3NS42NCBoIDE0My43MyB2IDE3LjIxIEggMTk4LjcgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzA0NTkiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMDQ1NyIKICAgICAgICAgZD0ibSAxOTguNywxNzUuNjQgaCAxNDMuNzMgdiAxNy4yMSBIIDE5OC43IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMwNDcxIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzA0NjkiCiAgICAgICAgIGQ9Im0gMTk4LjcsMTc1LjY0IGggMTQzLjczIHYgMTcuMjEgSCAxOTguNyBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMDQ3OSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwNDc3IgogICAgICAgICBkPSJtIDE5OC43LDE3NS42NCBoIDE0My43MyB2IDE3LjIxIEggMTk4LjcgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzE4OTUiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMTg5MyIKICAgICAgICAgZD0iTSAwLDAgSCAyODggViAzNjAgSCAwIFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMxOTA3IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzE5MDUiCiAgICAgICAgIGQ9Ik0gNDIuNTUsMTE2LjY5IEggMTg2Ljg2IFYgMzU0LjUyIEggNDIuNTUgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzI3ODciCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMjc4NSIKICAgICAgICAgZD0iTSAwLDAgSCA0MzIgViAzNjAgSCAwIFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMyNzk5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzI3OTciCiAgICAgICAgIGQ9Ik0gNDIuNTUsMjM4LjM1IEggMjk3LjQgViAzNTQuNTIgSCA0Mi41NSBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMjgzNSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMyODMzIgogICAgICAgICBkPSJNIDQyLjU1LDExNi42OSBIIDI5Ny40IFYgMjMyLjg2IEggNDIuNTUgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzI4NzEiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMjg2OSIKICAgICAgICAgZD0ibSAyOTcuNCwyMzguMzUgaCAzMy40NiBWIDM1NC41MiBIIDI5Ny40IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMyODc5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzI4NzciCiAgICAgICAgIGQ9Im0gMjk3LjQsMjM4LjM1IGggMzMuNDYgViAzNTQuNTIgSCAyOTcuNCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMjg5MSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMyODg5IgogICAgICAgICBkPSJtIDI5Ny40LDIzOC4zNSBoIDMzLjQ2IFYgMzU0LjUyIEggMjk3LjQgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzI4OTkiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMjg5NyIKICAgICAgICAgZD0ibSAyOTcuNCwyMzguMzUgaCAzMy40NiBWIDM1NC41MiBIIDI5Ny40IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMyOTA5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzI5MDciCiAgICAgICAgIGQ9Im0gMjk3LjQsMTE2LjY5IGggMzMuNDYgViAyMzIuODYgSCAyOTcuNCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMjkxNyIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMyOTE1IgogICAgICAgICBkPSJtIDI5Ny40LDExNi42OSBoIDMzLjQ2IFYgMjMyLjg2IEggMjk3LjQgWiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzI5MjkiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMjkyNyIKICAgICAgICAgZD0ibSAyOTcuNCwxMTYuNjkgaCAzMy40NiBWIDIzMi44NiBIIDI5Ny40IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDMyOTM3IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzI5MzUiCiAgICAgICAgIGQ9Im0gMjk3LjQsMTE2LjY5IGggMzMuNDYgViAyMzIuODYgSCAyOTcuNCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzMzg3OCIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMzODc2IgogICAgICAgICBkPSJtIDI4LjUsMCBoIDIzMSB2IDI4OCBoIC0yMzEgeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzM4OTAiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMzg4OCIKICAgICAgICAgZD0iTSA2NC40OCw3NS4zMSBIIDI1NC4wMiBWIDI2NC44NSBIIDY0LjQ4IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDM0NDE4IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzQ0MTYiCiAgICAgICAgIGQ9Ik0gODcuMTksMCBIIDIwMC44MSBWIDIxNiBIIDg3LjE5IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDM0NDMwIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzQ0MjgiCiAgICAgICAgIGQ9Im0gMTIwLjY2LDExOC4xOCBoIDc0LjY3IHYgNzQuNjcgaCAtNzQuNjcgeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMzQ5NzYiCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzNDk3NCIKICAgICAgICAgZD0iTSAyOC40Nyw3MS4xMSBIIDI4Mi41MiBWIDI2NC44NSBIIDI4LjQ3IFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDM1NDc5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzU0NzciCiAgICAgICAgIGQ9Ik0gNDIuNiwwIEggMjQ1LjM5IFYgMjE2IEggNDIuNiBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGgzNTQ4OSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDM1NDg3IgogICAgICAgICBkPSJNIDEyMS41OCw5Mi4xOSBIIDIzOS45MSBWIDIxMC41MiBIIDEyMS41OCBaIiAvPjwvY2xpcFBhdGg+PG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iVHJpYW5nbGVJbkwiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICByZWZZPSIwIgogICAgICAgcmVmWD0iMCIKICAgICAgIGlkPSJUcmlhbmdsZUluTC03IgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIgogICAgICAgdmlld0JveD0iMCAwIDguNTE5MDUzIDkuODQ4NjE2MSIKICAgICAgIG1hcmtlcldpZHRoPSI4LjUxOTA1MjUiCiAgICAgICBtYXJrZXJIZWlnaHQ9IjkuODQ4NjE1NiIKICAgICAgIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDgxNTEtOSIKICAgICAgICAgZD0iTSA1Ljc3LDAgLTIuODgsNSBWIC01IFoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFwdDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKC0wLjgpIiAvPjwvbWFya2VyPjxzdHlsZQogICAgICAgaWQ9InN0eWxlMTY2MDYiCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyI+CiAgIAogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIzNjgyIj48cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjgwMTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpZD0icmVjdDIzNjg0IgogICAgICAgICB3aWR0aD0iMjcuNTE2NjY2IgogICAgICAgICBoZWlnaHQ9IjE2LjEzOTU4NCIKICAgICAgICAgeD0iMTYyLjcxODc1IgogICAgICAgICB5PSIxMjkuMDM3NDkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4NjUxIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg2NDkiCiAgICAgICAgIGQ9Ik0gMCwwIEggNDMyIFYgMzYwIEggMCBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODY2MyIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ4NjYxIgogICAgICAgICBkPSJNIDM4LjEsMjIxLjY1IEggMjg0LjI2IFYgMzU0LjUyIEggMzguMSBaIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODY5NyIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ4Njk1IgogICAgICAgICBkPSJNIDM4LjEsODMuMzEgSCAyODQuMjYgViAyMTYuMTggSCAzOC4xIFoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4NzMxIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg3MjkiCiAgICAgICAgIGQ9Im0gMjg0LjI2LDIyMS42NSBoIDMzLjQ2IHYgMTMyLjg3IGggLTMzLjQ2IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4NzM5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg3MzciCiAgICAgICAgIGQ9Im0gMjg0LjI2LDIyMS42NSBoIDMzLjQ2IHYgMTMyLjg3IGggLTMzLjQ2IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4NzUxIgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg3NDkiCiAgICAgICAgIGQ9Im0gMjg0LjI2LDIyMS42NSBoIDMzLjQ2IHYgMTMyLjg3IGggLTMzLjQ2IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4NzU5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg3NTciCiAgICAgICAgIGQ9Im0gMjg0LjI2LDIyMS42NSBoIDMzLjQ2IHYgMTMyLjg3IGggLTMzLjQ2IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4NzY5IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg3NjciCiAgICAgICAgIGQ9Im0gMjg0LjI2LDgzLjMxIGggMzMuNDYgdiAxMzIuODcgaCAtMzMuNDYgeiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoNDg3NzciCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0ODc3NSIKICAgICAgICAgZD0ibSAyODQuMjYsODMuMzEgaCAzMy40NiB2IDEzMi44NyBoIC0zMy40NiB6IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBpZD0iY2xpcFBhdGg0ODc4OSIKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ4Nzg3IgogICAgICAgICBkPSJtIDI4NC4yNiw4My4zMSBoIDMzLjQ2IHYgMTMyLjg3IGggLTMzLjQ2IHoiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGlkPSJjbGlwUGF0aDQ4Nzk3IgogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDg3OTUiCiAgICAgICAgIGQ9Im0gMjg0LjI2LDgzLjMxIGggMzMuNDYgdiAxMzIuODcgaCAtMzMuNDYgeiIgLz48L2NsaXBQYXRoPjxzdHlsZQogICAgICAgaWQ9InN0eWxlMTg5ODIiCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyI+CiAgIAogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iVHJpYW5nbGVJbkwiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICByZWZZPSIwIgogICAgICAgcmVmWD0iMCIKICAgICAgIGlkPSJUcmlhbmdsZUluTC03LTciCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiCiAgICAgICB2aWV3Qm94PSIwIDAgOC41MTkwNTMgOS44NDg2MTYxIgogICAgICAgbWFya2VyV2lkdGg9IjguNTE5MDUyNSIKICAgICAgIG1hcmtlckhlaWdodD0iOS44NDg2MTU2IgogICAgICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoODE1MS05LTMiCiAgICAgICAgIGQ9Ik0gNS43NywwIC0yLjg4LDUgViAtNSBaIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgtMC44KSIgLz48L21hcmtlcj48bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJUcmlhbmdsZUluTCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjYwMDU5IgogICAgICAgc3R5bGU9Im92ZXJmbG93OnZpc2libGUiCiAgICAgICBpbmtzY2FwZTppc3N0b2NrPSJ0cnVlIgogICAgICAgdmlld0JveD0iMCAwIDguNTE5MDUzIDkuODQ4NjE2MSIKICAgICAgIG1hcmtlcldpZHRoPSI4LjUxOTA1MjUiCiAgICAgICBtYXJrZXJIZWlnaHQ9IjkuODQ4NjE1NiIKICAgICAgIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYwMDU3IgogICAgICAgICBkPSJNIDUuNzcsMCAtMi44OCw1IFYgLTUgWiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MXB0O3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoLTAuOCkiIC8+PC9tYXJrZXI+PG1hcmtlcgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iVHJpYW5nbGVJbkwiCiAgICAgICBvcmllbnQ9ImF1dG8iCiAgICAgICByZWZZPSIwIgogICAgICAgcmVmWD0iMCIKICAgICAgIGlkPSJUcmlhbmdsZUluTC03LTQiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiCiAgICAgICB2aWV3Qm94PSIwIDAgOC41MTkwNTMgOS44NDg2MTYxIgogICAgICAgbWFya2VyV2lkdGg9IjguNTE5MDUyNSIKICAgICAgIG1hcmtlckhlaWdodD0iOS44NDg2MTU2IgogICAgICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoODE1MS05LTciCiAgICAgICAgIGQ9Ik0gNS43NywwIC0yLjg4LDUgViAtNSBaIgogICAgICAgICBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxcHQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJzY2FsZSgtMC44KSIgLz48L21hcmtlcj48bWFya2VyCiAgICAgICBpbmtzY2FwZTpzdG9ja2lkPSJUcmlhbmdsZUluTCIKICAgICAgIG9yaWVudD0iYXV0byIKICAgICAgIHJlZlk9IjAiCiAgICAgICByZWZYPSIwIgogICAgICAgaWQ9Im1hcmtlcjYwMDU5LTkiCiAgICAgICBzdHlsZT0ib3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgIGlua3NjYXBlOmlzc3RvY2s9InRydWUiCiAgICAgICB2aWV3Qm94PSIwIDAgOC41MTkwNTMgOS44NDg2MTYxIgogICAgICAgbWFya2VyV2lkdGg9IjguNTE5MDUyNSIKICAgICAgIG1hcmtlckhlaWdodD0iOS44NDg2MTU2IgogICAgICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNjAwNTctNyIKICAgICAgICAgZD0iTSA1Ljc3LDAgLTIuODgsNSBWIC01IFoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjFwdDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKC0wLjgpIiAvPjwvbWFya2VyPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDI2MDEiCiAgICAgICBlZmZlY3Q9InNwaXJvIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGVmZmVjdD0iYnNwbGluZSIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDI2MTAiCiAgICAgICBpc192aXNpYmxlPSJ0cnVlIgogICAgICAgd2VpZ2h0PSIzMy4zMzMzMzMiCiAgICAgICBzdGVwcz0iMiIKICAgICAgIGhlbHBlcl9zaXplPSIwIgogICAgICAgYXBwbHlfbm9fd2VpZ2h0PSJ0cnVlIgogICAgICAgYXBwbHlfd2l0aF93ZWlnaHQ9InRydWUiCiAgICAgICBvbmx5X3NlbGVjdGVkPSJmYWxzZSIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGlua3NjYXBlOnBhdGgtZWZmZWN0CiAgICAgICBlZmZlY3Q9ImJzcGxpbmUiCiAgICAgICBpZD0icGF0aC1lZmZlY3QyNjAwIgogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIHdlaWdodD0iMzMuMzMzMzMzIgogICAgICAgc3RlcHM9IjIiCiAgICAgICBoZWxwZXJfc2l6ZT0iMCIKICAgICAgIGFwcGx5X25vX3dlaWdodD0idHJ1ZSIKICAgICAgIGFwcGx5X3dpdGhfd2VpZ2h0PSJ0cnVlIgogICAgICAgb25seV9zZWxlY3RlZD0iZmFsc2UiCiAgICAgICBscGV2ZXJzaW9uPSIwIiAvPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDM1MDMiCiAgICAgICBlZmZlY3Q9InNwaXJvIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBpZD0icGF0aC1lZmZlY3Q2ODkxIgogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGlua3NjYXBlOnBhdGgtZWZmZWN0CiAgICAgICBpc192aXNpYmxlPSJ0cnVlIgogICAgICAgaWQ9InBhdGgtZWZmZWN0NDU2MCIKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBscGV2ZXJzaW9uPSIwIiAvPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgZWZmZWN0PSJzcGlybyIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDI4NzEiCiAgICAgICBpc192aXNpYmxlPSJ0cnVlIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBpZD0icGF0aC1lZmZlY3QyODE5IgogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGlua3NjYXBlOnBhdGgtZWZmZWN0CiAgICAgICBpc192aXNpYmxlPSJ0cnVlIgogICAgICAgaWQ9InBhdGgtZWZmZWN0Mjc0NCIKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBscGV2ZXJzaW9uPSIwIiAvPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDk4OTkiCiAgICAgICBlZmZlY3Q9InNwaXJvIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBpZD0icGF0aC1lZmZlY3Q4OTI5IgogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MzU5Ij48c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWVlZWVjIgogICAgICAgICBpZD0ic3RvcDUzNTUiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjEiIC8+PHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2QzZDdjZiIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDUzNTciCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNkM2Q3Y2Y7c3RvcC1vcGFjaXR5OjAuMDMyNDMyNDMiIC8+PC9saW5lYXJHcmFkaWVudD48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGlzX3Zpc2libGU9InRydWUiCiAgICAgICBpZD0icGF0aC1lZmZlY3Q2MzMyIgogICAgICAgZWZmZWN0PSJzcGlybyIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGlua3NjYXBlOnBhdGgtZWZmZWN0CiAgICAgICBlZmZlY3Q9InNwaXJvIgogICAgICAgaWQ9InBhdGgtZWZmZWN0NjMyMCIKICAgICAgIGlzX3Zpc2libGU9InRydWUiCiAgICAgICBscGV2ZXJzaW9uPSIwIiAvPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgZWZmZWN0PSJzcGlybyIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDYxNTAiCiAgICAgICBpc192aXNpYmxlPSJ0cnVlIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGlzX3Zpc2libGU9InRydWUiCiAgICAgICBpZD0icGF0aC1lZmZlY3Q1NzI3IgogICAgICAgZWZmZWN0PSJzcGlybyIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGlua3NjYXBlOnBhdGgtZWZmZWN0CiAgICAgICBlZmZlY3Q9InNwaXJvIgogICAgICAgaWQ9InBhdGgtZWZmZWN0NTEwMCIKICAgICAgIGlzX3Zpc2libGU9InRydWUiCiAgICAgICBscGV2ZXJzaW9uPSIwIiAvPjxpbmtzY2FwZTpwYXRoLWVmZmVjdAogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGlkPSJwYXRoLWVmZmVjdDQ4NzQiCiAgICAgICBlZmZlY3Q9InNwaXJvIgogICAgICAgbHBldmVyc2lvbj0iMCIgLz48aW5rc2NhcGU6cGF0aC1lZmZlY3QKICAgICAgIGVmZmVjdD0ic3Bpcm8iCiAgICAgICBpZD0icGF0aC1lZmZlY3Q0ODcwIgogICAgICAgaXNfdmlzaWJsZT0idHJ1ZSIKICAgICAgIGxwZXZlcnNpb249IjAiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNTYyNTQxLDAsMCwwLjU2Nzk3MiwtOS4zOTk3NDksLTUuMzA1MzE3KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDY4OSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE0NzgtMyIKICAgICAgIHkyPSIxMTQuMzk3NjciCiAgICAgICB4Mj0iMTM1LjY2NTI1IgogICAgICAgeTE9IjIwLjYwMzc4MSIKICAgICAgIHgxPSIyNi42NDg5MzciIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNTYyNTQxLDAsMCwwLjU2Nzk3MiwtOS4zOTk3NDksLTUuMzA1MzE3KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDY3MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE0NzUtMiIKICAgICAgIHkyPSIxMzcuMjcyOTkiCiAgICAgICB4Mj0iMTEyLjAzMTQ0IgogICAgICAgeTE9IjE5Mi4zNTE3NiIKICAgICAgIHgxPSIxNTAuOTYxMTEiIC8+PHJhZGlhbEdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuMzgyNzE2ZS04LC0wLjI5NjQwNSwxLjQzNjc2LDQuNjgzNjczZS03LC0xMjguNTQ0LDE1MC41MjAyKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjc5NSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDE0ODAtNTgiCiAgICAgICBmeT0iMTMyLjI4NTc1IgogICAgICAgZng9IjYxLjUxODg4MyIKICAgICAgIHI9IjI5LjAzNjkxMyIKICAgICAgIGN5PSIxMzIuMjg1NzUiCiAgICAgICBjeD0iNjEuNTE4ODgzIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjExNDk0MTk2LDAsMCwwLjA3Njk3OTg3LDI5My4wNTU1NSw3NTIuMTg0MDYpIgogICAgICAgc3ByZWFkTWV0aG9kPSJwYWQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHkyPSI1OTMuNzg2OTkiCiAgICAgICB5MT0iMy42NjU4MjY4IgogICAgICAgeDI9IjU5MC44NjI2MSIKICAgICAgIHgxPSIwLjc0MTQ0MjUiCiAgICAgICBpZD0iZ3JhZGllbnRGaWxsLTEtMCI+PHN0b3AKICAgICAgICAgaWQ9InN0b3A3LTciCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMSIKICAgICAgICAgc3RvcC1jb2xvcj0icmdiKDIwMywyMDYsMjA4KSIKICAgICAgICAgb2Zmc2V0PSIwIiAvPjxzdG9wCiAgICAgICAgIGlkPSJzdG9wOS0zIgogICAgICAgICBzdG9wLW9wYWNpdHk9IjEiCiAgICAgICAgIHN0b3AtY29sb3I9InJnYigxMzIsMTMxLDEzOSkiCiAgICAgICAgIG9mZnNldD0iMSIgLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjA5MzExOTM5LDAsMCwwLjA5NTAyMDE1LDI5My4wNTU1NSw3NTIuMTg0MDYpIgogICAgICAgc3ByZWFkTWV0aG9kPSJwYWQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHkyPSI1NTMuNDQyMDgiCiAgICAgICB5MT0iMTUxLjQwMDYiCiAgICAgICB4Mj0iNzAzLjA2NzUiCiAgICAgICB4MT0iMzAxLjAyNjAzIgogICAgICAgaWQ9ImdyYWRpZW50RmlsbC0yLTgiPjxzdG9wCiAgICAgICAgIGlkPSJzdG9wMTItMiIKICAgICAgICAgc3RvcC1vcGFjaXR5PSIxIgogICAgICAgICBzdG9wLWNvbG9yPSJyZ2IoMzksMTA5LDE5NSkiCiAgICAgICAgIG9mZnNldD0iMCIgLz48c3RvcAogICAgICAgICBpZD0ic3RvcDE0LTMiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMSIKICAgICAgICAgc3RvcC1jb2xvcj0icmdiKDIyLDkyLDE3MCkiCiAgICAgICAgIG9mZnNldD0iMSIgLz48L2xpbmVhckdyYWRpZW50PjxtYXJrZXIKICAgICAgIHN0eWxlPSJvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgaWQ9IlRyaWFuZ2xlT3V0TSIKICAgICAgIHJlZlg9IjAiCiAgICAgICByZWZZPSIwIgogICAgICAgb3JpZW50PSJhdXRvIgogICAgICAgaW5rc2NhcGU6c3RvY2tpZD0iVHJpYW5nbGVPdXRNIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuNCkiCiAgICAgICAgIHN0eWxlPSJmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MXB0IgogICAgICAgICBkPSJNIDUuNzcsMCAtMi44OCw1IFYgLTUgWiIKICAgICAgICAgaWQ9InBhdGg0MTU2IiAvPjwvbWFya2VyPjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50ODkyLTMtMCI+PHN0b3AKICAgICAgICAgaWQ9InN0b3A4OTMtMi0zIgogICAgICAgICBvZmZzZXQ9IjAuMDAwMDAwMDAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjAuMDAwMDAwMDA7IiAvPjxzdG9wCiAgICAgICAgIGlkPSJzdG9wODk0LTItMSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmO3N0b3Atb3BhY2l0eToxOyIgLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDQ5MiIKICAgICAgIHkyPSI4OSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeTE9IjIwIgogICAgICAgeDI9IjEwMCIKICAgICAgIHgxPSIzNSI+PHN0b3AKICAgICAgICAgaWQ9InN0b3A0NDg4IgogICAgICAgICBzdG9wLWNvbG9yPSIjMDBjMGMwIgogICAgICAgICBzdG9wLW9wYWNpdHk9Ii43NTI5NCIKICAgICAgICAgb2Zmc2V0PSIwIiAvPjxzdG9wCiAgICAgICAgIGlkPSJzdG9wNDQ5MCIKICAgICAgICAgc3RvcC1jb2xvcj0iIzgwZjVmNSIKICAgICAgICAgc3RvcC1vcGFjaXR5PSIuMzAxOTYiCiAgICAgICAgIG9mZnNldD0iMSIgLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB5Mj0iMTA4Ljg3MjE4IgogICAgICAgeTE9IjEwOC44NzIxOCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDE1MjUxIgogICAgICAgeDI9IjI5Mi42NTg0MiIKICAgICAgIHgxPSIyODUuNDcwMzciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxNTM3OCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44OTgzOTU0NCwwLDAsMS40MjYyOTg3LC0yNTgzLjAzODEsMjk2Ni41NTAyKSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1MjUxIj48c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjMTFmZmZmIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMTUyNTIiIC8+PHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2UxZWJmZiIKICAgICAgICAgc3RvcC1vcGFjaXR5PSIwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTUyNTMiIC8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeTI9IjE4Ni44MTQ3NyIKICAgICAgIHkxPSIxODYuODE0NzciCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQxNTI1MSIKICAgICAgIHgyPSIyNDQuMjUxMDgiCiAgICAgICB4MT0iMjM5LjIyNDA4IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTUzNzkiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMjc1MDE1MywwLDAsMS4wMDQ5OTIxLC0yNTgzLjAzODEsMjk2Ni41NTAyKSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeTI9IjExMS40Nzk0MiIKICAgICAgIHkxPSIxMTEuNDc5NDIiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQxNTI1MSIKICAgICAgIHgyPSIzMTEuOTczOTciCiAgICAgICB4MT0iMzA1LjM2NzQ2IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTUzODAiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMTQ4NjA3LDAsMCwxLjExNTU5NSwtMjU4My4wMzgxLDI5NjYuNTUwMikiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHkyPSIyNzAuNTgwNzUiCiAgICAgICB5MT0iMjcwLjU4MDc1IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MTUyNTEiCiAgICAgICB4Mj0iMjcxLjM5NTMyIgogICAgICAgeDE9IjI2Ni43NDEwMyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1MzgzIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjUwMzEwOTksMCwwLDAuODUyNDg2MDMsLTI1ODMuMDM4MSwyOTY2LjU1MDIpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB5Mj0iMjEyLjU2ODcxIgogICAgICAgeTE9IjIxMi41Njg3MSIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDE1MjUxIgogICAgICAgeDI9IjE3NS44NzcxMSIKICAgICAgIHgxPSIxNjkuNjI4MDIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxNTM4NCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4xNDkzMDcsMCwwLDEuMTE0OTE1NSwtMjU4My4wMzgxLDI5NjYuNTUwMikiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHkyPSIyMjAuMDA5NTgiCiAgICAgICB5MT0iMjIwLjAwOTU4IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MTUyNTEiCiAgICAgICB4Mj0iMjE1LjE4MTc5IgogICAgICAgeDE9IjIwOC4yMDM4NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1Mzg1IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk0ODA4OTksMCwwLDEuMzUxNTM4NywtMjU4My4wMzgxLDI5NjYuNTUwMikiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHkyPSIyNjQuNTE3ODUiCiAgICAgICB5MT0iMjY0LjUxNzg1IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MTUyNTEiCiAgICAgICB4Mj0iMjE5LjAyODU5IgogICAgICAgeDE9IjIxNi40ODcyNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1Mzg2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjYwODA2MjMsMCwwLDAuNzk2ODQ3MzYsLTI1ODMuMDM4MSwyOTY2LjU1MDIpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB5Mj0iNTI5LjEwNDM3IgogICAgICAgeTE9IjUyOS4xMDQzNyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDE1MjUxIgogICAgICAgeDI9IjE4Ni4zMzE2IgogICAgICAgeDE9IjE4NC40MDY4OCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1Mzg3IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjg0NzExNywwLDAsMC42OTM3MTkwNSwtMjU4My4wMzgxLDI5NjYuNTUwMikiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHkyPSIyNDUuODQ4MzEiCiAgICAgICB5MT0iMjQ1Ljg0ODMxIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MTUyNTEiCiAgICAgICB4Mj0iMzE1LjI2MzM3IgogICAgICAgeDE9IjMwNy4wNTU3NiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1Mzg4IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjkyNDA4OTE2LDAsMCwxLjM4NjY0MTMsLTI1ODMuMDM4MSwyOTY2LjU1MDIpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB5Mj0iMTY4LjM2OTI4IgogICAgICAgeTE9IjE2OC4zNjkyOCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDE1MjUxIgogICAgICAgeDI9IjYzMC44MDM3MSIKICAgICAgIHgxPSI2MjIuNjk2NzgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxNTM4OSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC43MjUwNzg4NSwwLDAsMS43NjcyMjg4LC0yNTgzLjAzODEsMjk2Ni41NTAyKSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeTI9IjIzNC44MTkyMSIKICAgICAgIHkxPSIyMzQuODE5MjEiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQxNTI1MSIKICAgICAgIHgyPSI0OTUuOTY3MjkiCiAgICAgICB4MT0iNDkxLjE3OTM4IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTUzOTAiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTMzMjAyMTYsMCwwLDEuMzczMTAwNCwtMjU4My4wMzgxLDI5NjYuNTUwMikiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHkyPSIyMjUuMTg4NzgiCiAgICAgICB5MT0iMjI1LjE4ODc4IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MTUyNTEiCiAgICAgICB4Mj0iNTM1Ljc4NDM2IgogICAgICAgeDE9IjUyNy45MTE2OCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1MzkxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk3MjAwODU3LDAsMCwxLjMxODI4MDgsLTI1ODMuMDM4MSwyOTY2LjU1MDIpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB5Mj0iMjM4LjQ0ODI3IgogICAgICAgeTE9IjIzOC40NDgyNyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDE1MjUxIgogICAgICAgeDI9IjIwNi43MDAxIgogICAgICAgeDE9IjIwNC42MjI2MyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1MzkyIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjIzMDA2MTYsMCwwLDEuMDQxNzIwNCwtMjU4My4wMzgxLDI5NjYuNTUwMikiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iRSI+PHN0b3AKICAgICAgICAgaWQ9IlIiCiAgICAgICAgIHN0b3AtY29sb3I9IiMyZTM0MzYiIC8+PHN0b3AKICAgICAgICAgaWQ9IlMiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3RvcC1jb2xvcj0iIzJlMzQzNiIKICAgICAgICAgc3RvcC1vcGFjaXR5PSIwIiAvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iRCI+PHN0b3AKICAgICAgICAgaWQ9IlAiCiAgICAgICAgIHN0b3AtY29sb3I9IiNlZWVlZWMiIC8+PHN0b3AKICAgICAgICAgaWQ9IlEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3RvcC1jb2xvcj0iI2QzZDdjZiIgLz48L2xpbmVhckdyYWRpZW50PjxmaWx0ZXIKICAgICAgIHg9Ii0wLjE2IgogICAgICAgeT0iLTAuMTUwOTk5OTkiCiAgICAgICB3aWR0aD0iMS4zMjEiCiAgICAgICBoZWlnaHQ9IjEuMzAyIgogICAgICAgaWQ9IksiCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0IiPjxmZUdhdXNzaWFuQmx1cgogICAgICAgICBzdGREZXZpYXRpb249IjAuNTMyNyIKICAgICAgICAgaWQ9IlQiIC8+PC9maWx0ZXI+PHJhZGlhbEdyYWRpZW50CiAgICAgICBjeD0iMjUuNzEyIgogICAgICAgY3k9IjQ4LjczNTAwMSIKICAgICAgIHI9IjIxLjg1NjAwMSIKICAgICAgIGlkPSJGIgogICAgICAgeGxpbms6aHJlZj0iI0UiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi42NjA3MDc1LDAsMCwwLjIxNzExNzQ4LC0yNTkuOTAxNjEsNTY0LjY2MjQyKSIgLz48cmFkaWFsR3JhZGllbnQKICAgICAgIGN4PSIxMy41NTkiCiAgICAgICBjeT0iMTIuMDYiCiAgICAgICByPSIxNi4yMTkiCiAgICAgICBpZD0iRyIKICAgICAgIHhsaW5rOmhyZWY9IiNEIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuNTAxMDkzNiw2LjIyNDk5NjQsLTkuMjEwODc4OCwyLjIyMTExMSwtMTI5LjgxNjAzLDM3NC45MTM1NSkiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNDMxMTY1NCwwLDAsMi40MzExNjU0LC0yNDkuODM2MjMsNDY2Ljk3ODUpIgogICAgICAgeTE9IjIuNDM4IgogICAgICAgeDI9IjAiCiAgICAgICB5Mj0iNDMuMzQiCiAgICAgICBpZD0iSCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDg5Mi0zLTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz48cmFkaWFsR3JhZGllbnQKICAgICAgIGN4PSIzNC4xMzAwMDEiCiAgICAgICBjeT0iOC42MDkwMDAyIgogICAgICAgcj0iMy4wMyIKICAgICAgIGlkPSJJIgogICAgICAgeGxpbms6aHJlZj0iI0QiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoNC44NjIzMzA2LDUuMDM2NzU4MmUtNywtNS4yNzA0MjI2ZS03LDUuMDg3OTAzMSwtMzMyLjc5OTczLDQ0NC4wODYxOCkiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNDMxMTY1NCwwLDAsMi40MzExNjU0LC0yNDkuODM2MjMsNDY2LjYxNzE3KSIKICAgICAgIHgxPSIzNC4xMzAwMDEiCiAgICAgICB5MT0iOC43NSIKICAgICAgIHgyPSIzNi41MzMwMDEiCiAgICAgICB5Mj0iNi4zNjI5OTk5IgogICAgICAgaWQ9IkoiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ4OTItMy0wIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+PGZpbHRlcgogICAgICAgeD0iLTAuMTYiCiAgICAgICB5PSItMC4xNTA5OTk5OSIKICAgICAgIHdpZHRoPSIxLjMyMSIKICAgICAgIGhlaWdodD0iMS4zMDIiCiAgICAgICBpZD0iSy0wIgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCIj48ZmVHYXVzc2lhbkJsdXIKICAgICAgICAgc3RkRGV2aWF0aW9uPSIwLjUzMjciCiAgICAgICAgIGlkPSJULTAiIC8+PC9maWx0ZXI+PHJhZGlhbEdyYWRpZW50CiAgICAgICBjeD0iMjUuNzEyIgogICAgICAgY3k9IjQ4LjczNTAwMSIKICAgICAgIHI9IjIxLjg1NjAwMSIKICAgICAgIGlkPSJGLTUiCiAgICAgICB4bGluazpocmVmPSIjRSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjY2MDcwNzUsMCwwLDAuMjE3MTE3NDgsLTI4MS44NDE1Niw1NDMuNDg5MTUpIiAvPjxyYWRpYWxHcmFkaWVudAogICAgICAgY3g9IjEzLjU1OSIKICAgICAgIGN5PSIxMi4wNiIKICAgICAgIHI9IjE2LjIxOSIKICAgICAgIGlkPSJHLTMiCiAgICAgICB4bGluazpocmVmPSIjRCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjUwMTA5MzYsNi4yMjQ5OTY0LC05LjIxMDg3ODgsMi4yMjExMTEsLTE1MS43NTU5OCwzNTMuNzQwMjgpIiAvPjxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjQzMTE2NTQsMCwwLDIuNDMxMTY1NCwtMjcxLjc3NjE4LDQ0NS44MDUyMykiCiAgICAgICB5MT0iMi40MzgiCiAgICAgICB4Mj0iMCIKICAgICAgIHkyPSI0My4zNCIKICAgICAgIGlkPSJILTciCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ4OTItMy0wIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+PHJhZGlhbEdyYWRpZW50CiAgICAgICBjeD0iMzQuMTMwMDAxIgogICAgICAgY3k9IjguNjA5MDAwMiIKICAgICAgIHI9IjMuMDMiCiAgICAgICBpZD0iSS05IgogICAgICAgeGxpbms6aHJlZj0iI0QiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoNC44NjIzMzA2LDUuMDM2NzU4MmUtNywtNS4yNzA0MjI2ZS03LDUuMDg3OTAzMSwtMzU0LjczOTY5LDQyMi45MTI5MSkiIC8+PGZpbHRlcgogICAgICAgeD0iLTAuMTYiCiAgICAgICB5PSItMC4xNTA5OTk5OSIKICAgICAgIHdpZHRoPSIxLjMyMSIKICAgICAgIGhlaWdodD0iMS4zMDIiCiAgICAgICBpZD0iSy0wLTMiCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0IiPjxmZUdhdXNzaWFuQmx1cgogICAgICAgICBzdGREZXZpYXRpb249IjAuNTMyNyIKICAgICAgICAgaWQ9IlQtMC01IiAvPjwvZmlsdGVyPjxyYWRpYWxHcmFkaWVudAogICAgICAgY3g9IjI1LjcxMiIKICAgICAgIGN5PSI0OC43MzUwMDEiCiAgICAgICByPSIyMS44NTYwMDEiCiAgICAgICBpZD0iRi01LTYiCiAgICAgICB4bGluazpocmVmPSIjRSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCg2LjIzMjc0MDksMCwwLDAuNTA4NjAwNDMsNDI3Ny43MDY1LC0xMTAwLjU3MjgpIiAvPjxyYWRpYWxHcmFkaWVudAogICAgICAgY3g9IjEzLjU1OSIKICAgICAgIGN5PSIxMi4wNiIKICAgICAgIHI9IjE2LjIxOSIKICAgICAgIGlkPSJHLTMtMiIKICAgICAgIHhsaW5rOmhyZWY9IiNEIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDMuNTE2MzMxLDE0LjU4MjEzMiwtMjEuNTc2Niw1LjIwMjk4MDMsNDU4Mi40MzM2LC0xNTQ1LjA2MikiIC8+PGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDUuNjk1MDM1MywwLDAsNS42OTUwMzUzLDQzMDEuMjg0NywtMTMyOS4zOTg2KSIKICAgICAgIHkxPSIyLjQzOCIKICAgICAgIHgyPSIwIgogICAgICAgeTI9IjQzLjM0IgogICAgICAgaWQ9IkgtNy05IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50ODkyLTMtMCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPjxmaWx0ZXIKICAgICAgIHg9Ii0wLjE2IgogICAgICAgeT0iLTAuMTUwOTk5OTkiCiAgICAgICB3aWR0aD0iMS4zMjEiCiAgICAgICBoZWlnaHQ9IjEuMzAyIgogICAgICAgaWQ9ImZpbHRlcjQ2MTkiCiAgICAgICBzdHlsZT0iY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzOnNSR0IiPjxmZUdhdXNzaWFuQmx1cgogICAgICAgICBzdGREZXZpYXRpb249IjAuNTMyNyIKICAgICAgICAgaWQ9ImZlR2F1c3NpYW5CbHVyNDYyMSIgLz48L2ZpbHRlcj48cmFkaWFsR3JhZGllbnQKICAgICAgIGN4PSIzNC4xMzAwMDEiCiAgICAgICBjeT0iOC42MDkwMDAyIgogICAgICAgcj0iMy4wMyIKICAgICAgIGlkPSJJLTktMSIKICAgICAgIHhsaW5rOmhyZWY9IiNEIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDExLjM5MDA3MSwxLjE3OTg2NjllLTYsLTEuMjM0NjAzMWUtNiwxMS45MTg0NzcsNDEwNi45NDE4LC0xMzgzLjAyNDIpIiAvPjxmaWx0ZXIKICAgICAgIHg9Ii0wLjE2IgogICAgICAgeT0iLTAuMTUwOTk5OTkiCiAgICAgICB3aWR0aD0iMS4zMjEiCiAgICAgICBoZWlnaHQ9IjEuMzAyIgogICAgICAgaWQ9IkstMiIKICAgICAgIHN0eWxlPSJjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM6c1JHQiI+PGZlR2F1c3NpYW5CbHVyCiAgICAgICAgIHN0ZERldmlhdGlvbj0iMC41MzI3IgogICAgICAgICBpZD0iVC03IiAvPjwvZmlsdGVyPjxyYWRpYWxHcmFkaWVudAogICAgICAgY3g9IjEzLjU1OSIKICAgICAgIGN5PSIxMi4wNiIKICAgICAgIHI9IjE2LjIxOSIKICAgICAgIGlkPSJHLTAiCiAgICAgICB4bGluazpocmVmPSIjRCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjg1NTg5NDUsNy42OTYzNDU4LC0xMS4zODc5NzYsMi43NDYwOTYsNDk2Ljc5OTEsMTk3LjE0NTU3KSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMy4wMDU3OTkxLDAsMCwzLjAwNTc5OTEsMzQ4LjQxMDc1LDMxMC45NzExKSIKICAgICAgIHkxPSIyLjQzOCIKICAgICAgIHgyPSIwIgogICAgICAgeTI9IjQzLjM0IgogICAgICAgaWQ9IkgtOSIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDg5Mi0zLTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz48ZmlsdGVyCiAgICAgICB4PSItMC4xNiIKICAgICAgIHk9Ii0wLjE1MDk5OTk5IgogICAgICAgd2lkdGg9IjEuMzIxIgogICAgICAgaGVpZ2h0PSIxLjMwMiIKICAgICAgIGlkPSJmaWx0ZXI0Njg4IgogICAgICAgc3R5bGU9ImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpzUkdCIj48ZmVHYXVzc2lhbkJsdXIKICAgICAgICAgc3RkRGV2aWF0aW9uPSIwLjUzMjciCiAgICAgICAgIGlkPSJmZUdhdXNzaWFuQmx1cjQ2OTAiIC8+PC9maWx0ZXI+PHJhZGlhbEdyYWRpZW50CiAgICAgICBjeD0iMzQuMTMwMDAxIgogICAgICAgY3k9IjguNjA5MDAwMiIKICAgICAgIHI9IjMuMDMiCiAgICAgICBpZD0iSS0zIgogICAgICAgeGxpbms6aHJlZj0iI0QiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoNi4wMTE1OTgyLDYuMjI3MjUzN2UtNywtNi41MTYxNDc1ZS03LDYuMjkwNDg3NCwyNDUuODM3ODgsMjgyLjY2NzkyKSIgLz48bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMy4wMDU3OTkxLDAsMCwzLjAwNTc5OTEsMzQ4LjQxMDc1LDMxMC41MjQzNykiCiAgICAgICB4MT0iMzQuMTMwMDAxIgogICAgICAgeTE9IjguNzUiCiAgICAgICB4Mj0iMzYuNTMzMDAxIgogICAgICAgeTI9IjYuMzYyOTk5OSIKICAgICAgIGlkPSJKLTYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ4OTItMy0wIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtMDciPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48c3R5bGUKICAgICAgIHR5cGU9InRleHQvY3NzIgogICAgICAgaWQ9InN0eWxlNi0yLTc3Ij4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PHN0eWxlCiAgICAgICBpZD0ic3R5bGU2LTciCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTYiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48c3R5bGUKICAgICAgIGlkPSJzdHlsZTYtMy02IgogICAgICAgdHlwZT0idGV4dC9jc3MiPgogICAKICAgIC5maWwxIHtmaWxsOm5vbmV9CiAgICAuZmlsMCB7ZmlsbDpibGFja30KICAgCiAgPC9zdHlsZT48c3R5bGUKICAgICAgIGlkPSJzdHlsZTUyMzYiPi5jbHMtMXtmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjRweDt9PC9zdHlsZT48c3R5bGUKICAgICAgIGlkPSJzdHlsZTYtMzUtOSIKICAgICAgIHR5cGU9InRleHQvY3NzIj4KICAgCiAgICAuZmlsMSB7ZmlsbDpub25lfQogICAgLmZpbDAge2ZpbGw6YmxhY2t9CiAgIAogIDwvc3R5bGU+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDEtMCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCA1NDIuNjMzNTYgViAxOTEuNzU3NzIgSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoNjU3OSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGg1MDkwLTEiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggNTQyLjYzMzU2IFYgMTkxLjc1NzcyIEggMCBaIgogICAgICAgICBpZD0icGF0aDUwOTItNSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGg1MDk0Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDU0Mi42MzM1NiBWIDE5MS43NTc3MiBIIDAgWiIKICAgICAgICAgaWQ9InBhdGg1MDk2IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDUwOTgiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggNTQyLjYzMzU2IFYgMTkxLjc1NzcyIEggMCBaIgogICAgICAgICBpZD0icGF0aDUxMDAtMSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGg1MTAyLTkiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggNTQyLjYzMzU2IFYgMTkxLjc1NzcyIEggMCBaIgogICAgICAgICBpZD0icGF0aDUxMDQiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoNTEwNiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCA1NDIuNjMzNTYgViAxOTEuNzU3NzIgSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoNTEwOC0wIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDEtMC0xIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDU0Mi42MzM1NiBWIDE5MS43NTc3MiBIIDAgWiIKICAgICAgICAgaWQ9InBhdGg2NTc5LTkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoNTA5MC03Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDU0Mi42MzM1NiBWIDE5MS43NTc3MiBIIDAgWiIKICAgICAgICAgaWQ9InBhdGg1MDkyLTEiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoNTA5NC0zIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDU0Mi42MzM1NiBWIDE5MS43NTc3MiBIIDAgWiIKICAgICAgICAgaWQ9InBhdGg1MDk2LTEiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoNTA5OC0yIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDU0Mi42MzM1NiBWIDE5MS43NTc3MiBIIDAgWiIKICAgICAgICAgaWQ9InBhdGg1MTAwLTAiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoNTEwMi02Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDU0Mi42MzM1NiBWIDE5MS43NTc3MiBIIDAgWiIKICAgICAgICAgaWQ9InBhdGg1MTA0LTgiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoNTEwNi03Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDU0Mi42MzM1NiBWIDE5MS43NTc3MiBIIDAgWiIKICAgICAgICAgaWQ9InBhdGg1MTA4LTQiIC8+PC9jbGlwUGF0aD48c3R5bGUKICAgICAgIHR5cGU9InRleHQvY3NzIgogICAgICAgaWQ9InN0eWxlNi0yMyI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgaWQ9InN0eWxlNi0zLTgiCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgaWQ9InN0eWxlNTIzNi01Ij4uY2xzLTF7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS13aWR0aDo0cHg7fTwvc3R5bGU+PHN0eWxlCiAgICAgICBpZD0ic3R5bGU2LTM1LTAiCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyI+CiAgIAogICAgLmZpbDEge2ZpbGw6bm9uZX0KICAgIC5maWwwIHtmaWxsOmJsYWNrfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU0MzIwIj4KICAgCiAgICAuZmlsMCB7ZmlsbDojMDAwMDAwO2ZpbGwtcnVsZTpub256ZXJvfQogICAKICA8L3N0eWxlPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU2LTEtOCI+CiAgIAogICAgLmZpbDAge2ZpbGw6IzAwMDAwMDtmaWxsLXJ1bGU6bm9uemVyb30KICAgCiAgPC9zdHlsZT48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMi01Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwxLjAxOTk4NzkgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgxNzI2MyIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgzLTQiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMS4wMTk5ODc5LDEuMDE5OTg3OSBIIDE4MTIuNTE4NSBWIDQyLjgzOTQ5MSBIIDEuMDE5OTg3OSBaIgogICAgICAgICBpZD0icGF0aDE3MjY2IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyMzQ4Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwxLjAxOTk4NzkgSCAxODEyLjUxODUgViA0Mi44Mzk0OTEgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjM0NiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGg0LTA5Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJtIDU0MC41OTM1OCwxLjAxOTk4NzkgaCAxMDkuMTM4NyBWIDQyLjgzOTQ5MSBoIC0xMDkuMTM4NyB6IgogICAgICAgICBpZD0icGF0aDE3MjY5IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDUtMCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSA2NTAuNzUyMjcsMS4wMTk5ODc5IEggNzYwLjkxMDk2IFYgNDIuODM5NDkxIEggNjUwLjc1MjI3IFoiCiAgICAgICAgIGlkPSJwYXRoMTcyNzIiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoNi02Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDc2MS45MzA5NSwxLjAxOTk4NzkgSCA4NjguMDA5NjkgViA0Mi44Mzk0OTEgSCA3NjEuOTMwOTUgWiIKICAgICAgICAgaWQ9InBhdGgxNzI3NSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjM1OCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxLjAxOTk4NzksMS4wMTk5ODc5IEggMTgxMi41MTg1IFYgNDIuODM5NDkxIEggMS4wMTk5ODc5IFoiCiAgICAgICAgIGlkPSJwYXRoMjIzNTYiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoNy04OSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSA5NjEuODQ4NTgsMS4wMTk5ODc5IEggMTA3Mi4wMDczIFYgNDIuODM5NDkxIEggOTYxLjg0ODU4IFoiCiAgICAgICAgIGlkPSJwYXRoMTcyNzgiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjIzNjQiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMS4wMTk5ODc5LDEuMDE5OTg3OSBIIDE4MTIuNTE4NSBWIDQyLjgzOTQ5MSBIIDEuMDE5OTg3OSBaIgogICAgICAgICBpZD0icGF0aDIyMzYyIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyMzY4Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwxLjAxOTk4NzkgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjM2NiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGg4LTgiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gNjguMzM5MTg4LDQzLjg1OTQ3OSBIIDE2NS4yMzgwNCBWIDE1NS4wMzgxNiBIIDY4LjMzOTE4OCBaIgogICAgICAgICBpZD0icGF0aDE3MjgxIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDktNSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxNjYuMjU4MDMsNDMuODU5NDc5IEggMjkyLjczNjUyIFYgMTU1LjAzODE2IEggMTY2LjI1ODAzIFoiCiAgICAgICAgIGlkPSJwYXRoMTcyODQiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMTAtMSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxLjAxOTk4NzksNDMuODU5NDc5IEggMTgxMi41MTg1IFYgMTU1LjAzODE2IEggMS4wMTk5ODc5IFoiCiAgICAgICAgIGlkPSJwYXRoMTcyODciIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMTEtMzEiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Im0gNTQwLjU5MzU4LDQzLjg1OTQ3OSBoIDEwOS4xMzg3IFYgMTU1LjAzODE2IGggLTEwOS4xMzg3IHoiCiAgICAgICAgIGlkPSJwYXRoMTcyOTAiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMTItMzIiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gNjUwLjc1MjI3LDQzLjg1OTQ3OSBIIDc2MC45MTA5NiBWIDE1NS4wMzgxNiBIIDY1MC43NTIyNyBaIgogICAgICAgICBpZD0icGF0aDE3MjkzIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyMzgyIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSw0My44NTk0NzkgSCAxODEyLjUxODUgViAxNTUuMDM4MTYgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjM4MCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxMy0wNyI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0ibSA4NjkuMDI5NjgsNDMuODU5NDc5IGggOTEuNzk4OTEgViAxNTUuMDM4MTYgaCAtOTEuNzk4OTEgeiIKICAgICAgICAgaWQ9InBhdGgxNzI5NiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxNC00Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDk2MS44NDg1OCw0My44NTk0NzkgSCAxMDcyLjAwNzMgViAxNTUuMDM4MTYgSCA5NjEuODQ4NTggWiIKICAgICAgICAgaWQ9InBhdGgxNzI5OSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxNS04Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJtIDEwNzMuMDI3Myw0My44NTk0NzkgaCA4OS43NTg5IFYgMTU1LjAzODE2IGggLTg5Ljc1ODkgeiIKICAgICAgICAgaWQ9InBhdGgxNzMwMiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxNi0yIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJtIDExNjMuODA2Miw0My44NTk0NzkgaCAxMjIuMzk4NSBWIDE1NS4wMzgxNiBoIC0xMjIuMzk4NSB6IgogICAgICAgICBpZD0icGF0aDE3MzA1IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyMzk0Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSw0My44NTk0NzkgSCAxODEyLjUxODUgViAxNTUuMDM4MTYgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjM5MiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxNy0wNiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0ibSAxMzk1LjM0MzQsNDMuODU5NDc5IGggMTA2LjA3ODggViAxNTUuMDM4MTYgaCAtMTA2LjA3ODggeiIKICAgICAgICAgaWQ9InBhdGgxNzMwOCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxOC0xMiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0ibSAxNTAyLjQ0MjIsNDMuODU5NDc5IGggMTI3LjQ5ODQgViAxNTUuMDM4MTYgaCAtMTI3LjQ5ODQgeiIKICAgICAgICAgaWQ9InBhdGgxNzMxMSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjQwMiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxLjAxOTk4NzksNDMuODU5NDc5IEggMTgxMi41MTg1IFYgMTU1LjAzODE2IEggMS4wMTk5ODc5IFoiCiAgICAgICAgIGlkPSJwYXRoMjI0MDAiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI0MDYiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMS4wMTk5ODc5LDEuMDE5OTg3OSBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDEuMDE5OTg3OSBaIgogICAgICAgICBpZD0icGF0aDIyNDA0IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDE5LTMiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMS4wMTk5ODc5LDE1Ni4wNTgxNSBIIDE4MTIuNTE4NSBWIDI2Ny4yMzY4MyBIIDEuMDE5OTg3OSBaIgogICAgICAgICBpZD0icGF0aDE3MzE0IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDIwLTAiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMTY2LjI1ODAzLDE1Ni4wNTgxNSBIIDI5Mi43MzY1MiBWIDI2Ny4yMzY4MyBIIDE2Ni4yNTgwMyBaIgogICAgICAgICBpZD0icGF0aDE3MzE3IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNDE0Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwxNTYuMDU4MTUgSCAxODEyLjUxODUgViAyNjcuMjM2ODMgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjQxMiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgyMS0xIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJtIDU0MC41OTM1OCwxNTYuMDU4MTUgaCAxMDkuMTM4NyB2IDExMS4xNzg2OCBoIC0xMDkuMTM4NyB6IgogICAgICAgICBpZD0icGF0aDE3MzIwIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNDIwIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwxNTYuMDU4MTUgSCAxODEyLjUxODUgViAyNjcuMjM2ODMgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjQxOCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgyMi03Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDc2MS45MzA5NSwxNTYuMDU4MTUgSCA4NjguMDA5NjkgViAyNjcuMjM2ODMgSCA3NjEuOTMwOTUgWiIKICAgICAgICAgaWQ9InBhdGgxNzMyMyIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjQyNiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxLjAxOTk4NzksMTU2LjA1ODE1IEggMTgxMi41MTg1IFYgMjY3LjIzNjgzIEggMS4wMTk5ODc5IFoiCiAgICAgICAgIGlkPSJwYXRoMjI0MjQiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMjMtMCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSA5NjEuODQ4NTgsMTU2LjA1ODE1IEggMTA3Mi4wMDczIFYgMjY3LjIzNjgzIEggOTYxLjg0ODU4IFoiCiAgICAgICAgIGlkPSJwYXRoMTczMjYiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI0MzIiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMS4wMTk5ODc5LDE1Ni4wNTgxNSBIIDE4MTIuNTE4NSBWIDI2Ny4yMzY4MyBIIDEuMDE5OTg3OSBaIgogICAgICAgICBpZD0icGF0aDIyNDMwIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDI0LTYiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Im0gMTE2My44MDYyLDE1Ni4wNTgxNSBoIDEyMi4zOTg1IHYgMTExLjE3ODY4IGggLTEyMi4zOTg1IHoiCiAgICAgICAgIGlkPSJwYXRoMTczMjkiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMjUtOSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0ibSAxMjg3LjIyNDcsMTU2LjA1ODE1IGggMTA3LjA5ODcgdiAxMTEuMTc4NjggaCAtMTA3LjA5ODcgeiIKICAgICAgICAgaWQ9InBhdGgxNzMzMiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjQ0MCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxLjAxOTk4NzksMTU2LjA1ODE1IEggMTgxMi41MTg1IFYgMjY3LjIzNjgzIEggMS4wMTk5ODc5IFoiCiAgICAgICAgIGlkPSJwYXRoMjI0MzgiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMjYtMSI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0ibSAxNTAyLjQ0MjIsMTU2LjA1ODE1IGggMTI3LjQ5ODQgdiAxMTEuMTc4NjggaCAtMTI3LjQ5ODQgeiIKICAgICAgICAgaWQ9InBhdGgxNzMzNSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgyNy0yIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJtIDE2MzAuOTYwNiwxNTYuMDU4MTUgaCAxODAuNTM3OSB2IDExMS4xNzg2OCBoIC0xODAuNTM3OSB6IgogICAgICAgICBpZD0icGF0aDE3MzM4IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNDQ4Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwxLjAxOTk4NzkgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjQ0NiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgyOC00Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDY4LjMzOTE4OCwyNjguMjU2ODEgSCAxNjUuMjM4MDQgViAzNzkuNDM1NDkgSCA2OC4zMzkxODggWiIKICAgICAgICAgaWQ9InBhdGgxNzM0MSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgyOS0yIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDE2Ni4yNTgwMywyNjguMjU2ODEgSCAyOTIuNzM2NTIgViAzNzkuNDM1NDkgSCAxNjYuMjU4MDMgWiIKICAgICAgICAgaWQ9InBhdGgxNzM0NCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgzMC02Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwyNjguMjU2ODEgSCAxODEyLjUxODUgViAzNzkuNDM1NDkgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgxNzM0NyIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgzMS03Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJtIDQ2MS4wMzQ1MiwyNjguMjU2ODEgaCA3OC41MzkwNyB2IDExMS4xNzg2OCBoIC03OC41MzkwNyB6IgogICAgICAgICBpZD0icGF0aDE3MzUwIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDMyLTMiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Im0gNTQwLjU5MzU4LDI2OC4yNTY4MSBoIDEwOS4xMzg3IHYgMTExLjE3ODY4IGggLTEwOS4xMzg3IHoiCiAgICAgICAgIGlkPSJwYXRoMTczNTMiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMzMtNzUiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gNjUwLjc1MjI3LDI2OC4yNTY4MSBIIDc2MC45MTA5NiBWIDM3OS40MzU0OSBIIDY1MC43NTIyNyBaIgogICAgICAgICBpZD0icGF0aDE3MzU2IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNDY0Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwyNjguMjU2ODEgSCAxODEyLjUxODUgViAzNzkuNDM1NDkgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgyMjQ2MiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgzNC04Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDk2MS44NDg1OCwyNjguMjU2ODEgSCAxMDcyLjAwNzMgViAzNzkuNDM1NDkgSCA5NjEuODQ4NTggWiIKICAgICAgICAgaWQ9InBhdGgxNzM1OSIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjQ3MCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxLjAxOTk4NzksMjY4LjI1NjgxIEggMTgxMi41MTg1IFYgMzc5LjQzNTQ5IEggMS4wMTk5ODc5IFoiCiAgICAgICAgIGlkPSJwYXRoMjI0NjgiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMzUtOCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0ibSAxNjMwLjk2MDYsMjY4LjI1NjgxIGggMTgwLjUzNzkgdiAxMTEuMTc4NjggaCAtMTgwLjUzNzkgeiIKICAgICAgICAgaWQ9InBhdGgxNzM2MiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxLTA2Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgxNzI2MCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjQ3OCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI0NzYiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI0ODIiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDIyNDgwIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNDg2Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgyMjQ4NCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjQ5MCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI0ODgiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI0OTQiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDIyNDkyIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNDk4Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgyMjQ5NiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjUwMiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI1MDAiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI1MDYiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDIyNTA0IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNTEwIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgyMjUwOCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjUxNCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI1MTIiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI1MTgiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDIyNTE2IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNTIyIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgyMjUyMCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjUyNiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI1MjQiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI1MzAiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDIyNTI4IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNTM0Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgyMjUzMiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjUzOCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI1MzYiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI1NDIiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDIyNTQwIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNTQ2Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgyMjU0NCIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjU1MCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI1NDgiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBQYXRoMjI1NTQiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDIyNTUyIiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwUGF0aDIyNTU4Ij48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDAsMCBIIDE4MTIuNTE4NSBWIDM4MC40NTU0OCBIIDAgWiIKICAgICAgICAgaWQ9InBhdGgyMjU1NiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcFBhdGgyMjU2MiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMjI1NjAiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMy00LTgiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMS4wMTk5ODc5LDEuMDE5OTg3OSBIIDE4MTIuNTE4NSBWIDQyLjgzOTQ5MSBIIDEuMDE5OTg3OSBaIgogICAgICAgICBpZD0icGF0aDE3MjY2LTAiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMy00LTgyIj48cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJNIDEuMDE5OTg3OSwxLjAxOTk4NzkgSCAxODEyLjUxODUgViA0Mi44Mzk0OTEgSCAxLjAxOTk4NzkgWiIKICAgICAgICAgaWQ9InBhdGgxNzI2Ni04IiAvPjwvY2xpcFBhdGg+PGNsaXBQYXRoCiAgICAgICBjbGlwUGF0aFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJjbGlwRW1mUGF0aDMtNC04NCI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAxLjAxOTk4NzksMS4wMTk5ODc5IEggMTgxMi41MTg1IFYgNDIuODM5NDkxIEggMS4wMTk5ODc5IFoiCiAgICAgICAgIGlkPSJwYXRoMTcyNjYtMiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGg0LTA5LTYiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Im0gNTQwLjU5MzU4LDEuMDE5OTg3OSBoIDEwOS4xMzg3IFYgNDIuODM5NDkxIGggLTEwOS4xMzg3IHoiCiAgICAgICAgIGlkPSJwYXRoMTcyNjktMiIgLz48L2NsaXBQYXRoPjxjbGlwUGF0aAogICAgICAgY2xpcFBhdGhVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iY2xpcEVtZlBhdGgxLTA2LTMiPjxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gMCwwIEggMTgxMi41MTg1IFYgMzgwLjQ1NTQ4IEggMCBaIgogICAgICAgICBpZD0icGF0aDE3MjYwLTMiIC8+PC9jbGlwUGF0aD48Y2xpcFBhdGgKICAgICAgIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImNsaXBFbWZQYXRoMS0wNi0zNiI+PHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0iTSAwLDAgSCAxODEyLjUxODUgViAzODAuNDU1NDggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMTcyNjAtNyIgLz48L2NsaXBQYXRoPjxzdHlsZQogICAgICAgdHlwZT0idGV4dC9jc3MiCiAgICAgICBpZD0ic3R5bGU0MzIwLTciPgogICAKICAgIC5maWwwIHtmaWxsOiMwMDAwMDA7ZmlsbC1ydWxlOm5vbnplcm99CiAgIAogIDwvc3R5bGU+PHN0eWxlCiAgICAgICB0eXBlPSJ0ZXh0L2NzcyIKICAgICAgIGlkPSJzdHlsZTYtNSI+CiAgIAogICAgLmZpbDAge2ZpbGw6IzAwMDAwMDtmaWxsLXJ1bGU6bm9uemVyb30KICAgCiAgPC9zdHlsZT48L2RlZnM+PGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEwLjI2MTg3NywtNTUuMDIzMzIzKSI+PHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI2NDU4MzMzLDAsMCwwLjI2NDU4MzMzLC0xMy4wMjY1NDcsLTE1LjU3NzY2NikiCiAgICAgICBpZD0idGV4dDEwNDgzIgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToxNS42ODlweDtmb250LWZhbWlseTonTGF0aW4gTW9kZXJuIFNhbnMgUXVvdGF0aW9uJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidMYXRpbiBNb2Rlcm4gU2FucyBRdW90YXRpb24sIEJvbGQnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3doaXRlLXNwYWNlOnByZTtzaGFwZS1pbnNpZGU6dXJsKCNyZWN0MTA0ODUpO2Rpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2YxZjMyZjtzdHJva2Utd2lkdGg6NC4yMDg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3BhaW50LW9yZGVyOm5vcm1hbCIgLz48ZwogICAgICAgc3R5bGU9ImNsaXAtcnVsZTpldmVub2RkO2ZpbGwtcnVsZTpldmVub2RkO2ltYWdlLXJlbmRlcmluZzpvcHRpbWl6ZVF1YWxpdHk7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbjt0ZXh0LXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24iCiAgICAgICBpZD0iZzk5NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0wLjA3MjAwNTA3LDAuMjU0NTk2OTUsLTAuMjU0NTk2OTUsLTAuMDcyMDA1MDcsNjUuNjYxNzg0LDg2LjE5NzUxNCkiIC8+PGcKICAgICAgIGlkPSJnNDA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zOTQyNTc1NywwLDAsMC4zOTQyNTc1NywzNC4yOTQ1NiwtNi43OTYxOTMxKSIgLz48dGV4dAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMTA0MzEzOTgsMCwwLDAuMTA0MzEzOTgsMjQuNjE2NjgyLDE3LjU5NDYwNSkiCiAgICAgICBpZD0idGV4dDEwNDgzLTIiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjE1LjY4OXB4O2ZvbnQtZmFtaWx5OidMYXRpbiBNb2Rlcm4gU2FucyBRdW90YXRpb24nOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J0xhdGluIE1vZGVybiBTYW5zIFF1b3RhdGlvbiwgQm9sZCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7d2hpdGUtc3BhY2U6cHJlO3NoYXBlLWluc2lkZTp1cmwoI3JlY3QxMDQ4NS0zKTtkaXNwbGF5OmlubGluZTtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNmMWYzMmY7c3Ryb2tlLXdpZHRoOjQuMjA4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpiZXZlbDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtwYWludC1vcmRlcjpub3JtYWwiIC8+PGcKICAgICAgIHN0eWxlPSJjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsLXJ1bGU6ZXZlbm9kZDtpbWFnZS1yZW5kZXJpbmc6b3B0aW1pemVRdWFsaXR5O3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb247dGV4dC1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uIgogICAgICAgaWQ9Imc5OTQtMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0wLjAyODM4ODU0LDAuMTAwMzc2NzcsLTAuMTAwMzc2NzcsLTAuMDI4Mzg4NTQsNTUuNjQwMTUyLDU3LjcyMDI0MikiIC8+PHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjEwNDMxMzk4LDAsMCwwLjEwNDMxMzk4LDM0LjI5NDU2LC02Ljc5NjE5MzEpIgogICAgICAgaWQ9InRleHQ0NDI5IgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjEycHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonQXJpYWwsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7d2hpdGUtc3BhY2U6cHJlO3NoYXBlLWluc2lkZTp1cmwoI3JlY3Q0NDMxKTtkaXNwbGF5OmlubGluZTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjA7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjIuMjY3NzI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOmJldmVsIiAvPjx0ZXh0CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4xMDQzMTM5OCwwLDAsMC4xMDQzMTM5OCwzNC4yOTQ1NiwtNi43OTYxOTMxKSIKICAgICAgIGlkPSJ0ZXh0MzkxMCIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J0FyaWFsLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3doaXRlLXNwYWNlOnByZTtzaGFwZS1pbnNpZGU6dXJsKCNyZWN0MzkxMik7ZGlzcGxheTppbmxpbmU7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eTowO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyLjI2NzcyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpiZXZlbCIgLz48dGV4dAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMTA0MzEzOTgsMCwwLDAuMTA0MzEzOTgsMjMuMDIwNjkyLC0wLjc4ODc1NDQ5KSIKICAgICAgIGlkPSJ0ZXh0MTA0ODMtOCIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6MTUuNjg5cHg7Zm9udC1mYW1pbHk6J0xhdGluIE1vZGVybiBTYW5zIFF1b3RhdGlvbic7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonTGF0aW4gTW9kZXJuIFNhbnMgUXVvdGF0aW9uLCBCb2xkJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOm5vcm1hbDt3aGl0ZS1zcGFjZTpwcmU7c2hhcGUtaW5zaWRlOnVybCgjcmVjdDEwNDg1LTkpO2Rpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2YxZjMyZjtzdHJva2Utd2lkdGg6NC4yMDg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3BhaW50LW9yZGVyOm5vcm1hbCIgLz48ZwogICAgICAgc3R5bGU9ImNsaXAtcnVsZTpldmVub2RkO2ZpbGwtcnVsZTpldmVub2RkO2ltYWdlLXJlbmRlcmluZzpvcHRpbWl6ZVF1YWxpdHk7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbjt0ZXh0LXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24iCiAgICAgICBpZD0iZzk5NC0xIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTAuMDI4Mzg4NTQsMC4xMDAzNzY3NywtMC4xMDAzNzY3NywtMC4wMjgzODg1NCw1NC4wNDQxNjIsMzkuMzM2ODgzKSIgLz48ZwogICAgICAgc3R5bGU9ImNsaXAtcnVsZTpldmVub2RkO2ZpbGw6IzAwODAwMDtmaWxsLXJ1bGU6ZXZlbm9kZDtpbWFnZS1yZW5kZXJpbmc6b3B0aW1pemVRdWFsaXR5O3NoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb247dGV4dC1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uIgogICAgICAgaWQ9Imc0MTEtMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0wLjA3OTI5ODgxLDAuMDY3NzcyNDUsLTAuMDY3NzcyNDUsLTAuMDc5Mjk4ODEsMTQxLjIxMzEzLDEzLjczMjYzOCkiIC8+PHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zaXplOjUuMjkxNjdweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidBcmlhbCwgTm9ybWFsJzt0ZXh0LWFsaWduOnN0YXJ0O3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzA5OTgwMDtzdHJva2U6IzA1ODhmZjtzdHJva2Utd2lkdGg6MCIKICAgICAgIHg9IjEwNi44NzMwOCIKICAgICAgIHk9IjE3Ljg0OTUxIgogICAgICAgaWQ9InRleHQyMDc5NiI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIGlkPSJ0c3BhbjIwNzk0IgogICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAiCiAgICAgICAgIHg9IjEwNi44NzMwOCIKICAgICAgICAgeT0iMTcuODQ5NTEiIC8+PC90ZXh0Pjx0ZXh0CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgc3R5bGU9ImZvbnQtc2l6ZToyLjAxNzA1cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonQXJpYWwsIE5vcm1hbCc7ZmlsbDojMDAwMDAwO3N0cm9rZTojMDA4MDAwO3N0cm9rZS13aWR0aDowLjEzMTc1NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46YmV2ZWwiCiAgICAgICB4PSI3LjUwMTIzNzkiCiAgICAgICB5PSI1Mi44MTg2NTciCiAgICAgICBpZD0idGV4dDExNDciPjx0c3BhbgogICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICBpZD0idHNwYW4xMTQ1IgogICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTMxNzU0IgogICAgICAgICB4PSI3LjUwMTIzNzkiCiAgICAgICAgIHk9IjUyLjgxODY1NyIgLz48L3RleHQ+PGcKICAgICAgIGlkPSJnMjkxOC02LTctNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuNDE3NTkxOTgsMCwwLDAuMjcxMTEzMzcsLTM5LjIxMTYxNyw5My44NjQ1NjgpIiAvPjx0ZXh0CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNDEzMTUzMSwwLDAsMC4yNDEzMTUzMSwtMTEuMzI3MTYzLC0xMS42NDQ0MTQpIgogICAgICAgaWQ9InRleHQxMDQ4My01IgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToxNS42ODlweDtmb250LWZhbWlseTonTGF0aW4gTW9kZXJuIFNhbnMgUXVvdGF0aW9uJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidMYXRpbiBNb2Rlcm4gU2FucyBRdW90YXRpb24sIEJvbGQnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3doaXRlLXNwYWNlOnByZTtzaGFwZS1pbnNpZGU6dXJsKCNyZWN0MTA0ODUtMik7ZGlzcGxheTppbmxpbmU7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojZjFmMzJmO3N0cm9rZS13aWR0aDo0LjIwODtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46YmV2ZWw7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7cGFpbnQtb3JkZXI6bm9ybWFsIiAvPjxnCiAgICAgICBzdHlsZT0iY2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbC1ydWxlOmV2ZW5vZGQ7aW1hZ2UtcmVuZGVyaW5nOm9wdGltaXplUXVhbGl0eTtzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uO3RleHQtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbiIKICAgICAgIGlkPSJnOTk0LTMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMC4wNjU2NzI3OSwwLjIzMjIwNzE1LC0wLjIzMjIwNzE1LC0wLjA2NTY3Mjc5LDYwLjQ0MTE0OSw4MS4xODA0NDEpIiAvPjx0ZXh0CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNjQ1ODMzMywwLDAsMC4yNjQ1ODMzMywtMTQuMjk1NjAyLC0xNy44MDU2NzQpIgogICAgICAgaWQ9InRleHQxMDQ4My02IgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToxNS42ODlweDtmb250LWZhbWlseTonTGF0aW4gTW9kZXJuIFNhbnMgUXVvdGF0aW9uJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidMYXRpbiBNb2Rlcm4gU2FucyBRdW90YXRpb24sIEJvbGQnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3doaXRlLXNwYWNlOnByZTtzaGFwZS1pbnNpZGU6dXJsKCNyZWN0MTA0ODUtMzgpO2Rpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2YxZjMyZjtzdHJva2Utd2lkdGg6NC4yMDg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3BhaW50LW9yZGVyOm5vcm1hbCIgLz48ZwogICAgICAgc3R5bGU9ImNsaXAtcnVsZTpldmVub2RkO2ZpbGwtcnVsZTpldmVub2RkO2ltYWdlLXJlbmRlcmluZzpvcHRpbWl6ZVF1YWxpdHk7c2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbjt0ZXh0LXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb24iCiAgICAgICBpZD0iZzk5NC0yIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTAuMDcyMDA1MDcsMC4yNTQ1OTY5NSwtMC4yNTQ1OTY5NSwtMC4wNzIwMDUwNyw2NC4zOTI3MjksODMuOTY5NTA2KSIgLz48ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsODYuMjc0MjcsLTE1OS43MzA3OCkiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iY2hyb21EaXN0cmlidXRpb25fMiIKICAgICAgIGlkPSJnODk0Ij48ZwogICAgICAgICBpZD0iZzg5NiIgLz48ZwogICAgICAgICBpZD0iZzg5OCIgLz48ZwogICAgICAgICBpZD0iZzkwMCIgLz48ZwogICAgICAgICBpZD0iZzkwMiIgLz48ZwogICAgICAgICBpZD0iZzkwNCIgLz48ZwogICAgICAgICBpZD0iZzkwNiIgLz48ZwogICAgICAgICBpZD0iZzkwOCIgLz48ZwogICAgICAgICBpZD0iZzkxMCIgLz48ZwogICAgICAgICBpZD0iZzkxMiIgLz48ZwogICAgICAgICBpZD0iZzkxNCIgLz48ZwogICAgICAgICBpZD0iZzkxNiIgLz48ZwogICAgICAgICBpZD0iZzkxOCIgLz48ZwogICAgICAgICBpZD0iZzkyMCIgLz48ZwogICAgICAgICBpZD0iZzkyMiIgLz48ZwogICAgICAgICBpZD0iZzkyNCIgLz48ZwogICAgICAgICBpZD0iZzkyNiIgLz48ZwogICAgICAgICBpZD0iZzkyOCIgLz48ZwogICAgICAgICBpZD0iZzkzMCIgLz48ZwogICAgICAgICBpZD0iZzkzMiIgLz48ZwogICAgICAgICBpZD0iZzkzNCIgLz48ZwogICAgICAgICBpZD0iZzkzNiIgLz48ZwogICAgICAgICBpZD0iZzkzOCIgLz48ZwogICAgICAgICBpZD0iZzk0MCIgLz48ZwogICAgICAgICBpZD0iZzk0MiIgLz48ZwogICAgICAgICBpZD0iZzk0NCIgLz48ZwogICAgICAgICBpZD0iZzk0NiIgLz48ZwogICAgICAgICBpZD0iZzk0OCIgLz48ZwogICAgICAgICBpZD0iZzk1MCIgLz48ZwogICAgICAgICBpZD0iZzk1MiIgLz48ZwogICAgICAgICBpZD0iZzk1NCIgLz48ZwogICAgICAgICBpZD0iZzk1NiIgLz48ZwogICAgICAgICBpZD0iZzk1OCIgLz48ZwogICAgICAgICBpZD0iZzk2MCIgLz48ZwogICAgICAgICBpZD0iZzk2MiIgLz48ZwogICAgICAgICBpZD0iZzk2NCIgLz48ZwogICAgICAgICBpZD0iZzk2NiIgLz48ZwogICAgICAgICBpZD0iZzk2OCIgLz48ZwogICAgICAgICBpZD0iZzk3MCIgLz48ZwogICAgICAgICBpZD0iZzk3MiIgLz48ZwogICAgICAgICBpZD0iZzk3NCIgLz48ZwogICAgICAgICBpZD0iZzk3NiIgLz48ZwogICAgICAgICBpZD0iZzk3OCIgLz48ZwogICAgICAgICBpZD0iZzk4MCIgLz48ZwogICAgICAgICBpZD0iZzk4MiIgLz48ZwogICAgICAgICBpZD0iZzk4NCIgLz48ZwogICAgICAgICBpZD0iZzk4NiIgLz48ZwogICAgICAgICBpZD0iZzk4OCIgLz48ZwogICAgICAgICBpZD0iZzk5MCIgLz48ZwogICAgICAgICBpZD0iZzk5MiIgLz48ZwogICAgICAgICBpZD0iZzk5NC0yMSIgLz48ZwogICAgICAgICBpZD0iZzk5NiIgLz48ZwogICAgICAgICBpZD0iZzk5OCIgLz48ZwogICAgICAgICBpZD0iZzEwMDAiIC8+PGcKICAgICAgICAgaWQ9ImcxMDAyIiAvPjxnCiAgICAgICAgIGlkPSJnMTAwNCIgLz48ZwogICAgICAgICBpZD0iZzEwMDYiIC8+PGcKICAgICAgICAgaWQ9ImcxMDA4IiAvPjxnCiAgICAgICAgIGlkPSJnMTAxMCIgLz48ZwogICAgICAgICBpZD0iZzEwMTIiIC8+PGcKICAgICAgICAgaWQ9ImcxMDE0IiAvPjxnCiAgICAgICAgIGlkPSJnMTAxNiIgLz48ZwogICAgICAgICBpZD0iZzEwMTgiIC8+PGcKICAgICAgICAgaWQ9ImcxMDMwIiAvPjxnCiAgICAgICAgIGlkPSJnMTI4OCIgLz48ZwogICAgICAgICBpZD0iZzE2MTQiIC8+PGcKICAgICAgICAgaWQ9ImcxNzgyIiAvPjxnCiAgICAgICAgIGlkPSJnMTkzOCIgLz48ZwogICAgICAgICBpZD0iZzIxNjAtNyIgLz48ZwogICAgICAgICBpZD0iZzIzMjgiIC8+PGcKICAgICAgICAgaWQ9ImcyNTE4IiAvPjxnCiAgICAgICAgIGlkPSJnMjY5NCIgLz48ZwogICAgICAgICBpZD0iZzI4OTIiIC8+PGcKICAgICAgICAgaWQ9ImczMDY2IiAvPjxnCiAgICAgICAgIGlkPSJnMzE3NiIgLz48ZwogICAgICAgICBpZD0iZzMyODQiIC8+PGcKICAgICAgICAgaWQ9ImczMzk0IiAvPjxnCiAgICAgICAgIGlkPSJnMzUyNCIgLz48ZwogICAgICAgICBpZD0iZzM2MjIiIC8+PGcKICAgICAgICAgaWQ9ImczODQ2IiAvPjxnCiAgICAgICAgIGlkPSJnMzk0NiIgLz48ZwogICAgICAgICBpZD0iZzQxMDIiIC8+PGcKICAgICAgICAgaWQ9Imc0MTQ0IiAvPjxnCiAgICAgICAgIGlkPSJnNDIyOCIgLz48ZwogICAgICAgICBpZD0iZzQyNzQiIC8+PGcKICAgICAgICAgaWQ9Imc0MzEwIiAvPjxnCiAgICAgICAgIGlkPSJnNDM5MCIgLz48ZwogICAgICAgICBpZD0iZzQzOTIiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDM5OCkiCiAgICAgICAgICAgaWQ9Imc0Mzk0IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ0MTIiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDQxOCkiCiAgICAgICAgICAgaWQ9Imc0NDE0IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ0MjAiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDQyNikiCiAgICAgICAgICAgaWQ9Imc0NDIyIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ0MjgiIC8+PGcKICAgICAgICAgaWQ9Imc0NDMwIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ0MzYpIgogICAgICAgICAgIGlkPSJnNDQzMiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0NDUwIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ0NTYpIgogICAgICAgICAgIGlkPSJnNDQ1MiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0NDU4Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ0NjQpIgogICAgICAgICAgIGlkPSJnNDQ2MCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0NDY2IiAvPjxnCiAgICAgICAgIGlkPSJnNDQ2OCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NDc0KSIKICAgICAgICAgICBpZD0iZzQ0NzAiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDQ4OCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NDk0KSIKICAgICAgICAgICBpZD0iZzQ0OTAiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDQ5NiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NTAyKSIKICAgICAgICAgICBpZD0iZzQ0OTgiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDUwNCIgLz48ZwogICAgICAgICBpZD0iZzQ1MDYiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDUxMikiCiAgICAgICAgICAgaWQ9Imc0NTA4IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ1MjYiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDUzMikiCiAgICAgICAgICAgaWQ9Imc0NTI4IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ1MzQiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDU0MCkiCiAgICAgICAgICAgaWQ9Imc0NTM2IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ1NDIiIC8+PGcKICAgICAgICAgaWQ9Imc0NTQ0Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ1NTApIgogICAgICAgICAgIGlkPSJnNDU0NiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0NTY0Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ1NzApIgogICAgICAgICAgIGlkPSJnNDU2NiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0NTcyIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ1NzgpIgogICAgICAgICAgIGlkPSJnNDU3NCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0NTgwIiAvPjxnCiAgICAgICAgIGlkPSJnNDU4MiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NTg4KSIKICAgICAgICAgICBpZD0iZzQ1ODQiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDYwMiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NjA4KSIKICAgICAgICAgICBpZD0iZzQ2MDQiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDYxMCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NjE2KSIKICAgICAgICAgICBpZD0iZzQ2MTIiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDYxOCIgLz48ZwogICAgICAgICBpZD0iZzQ2MjAiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDYyNikiCiAgICAgICAgICAgaWQ9Imc0NjIyIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ2NDAiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDY0NikiCiAgICAgICAgICAgaWQ9Imc0NjQyIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ2NDgiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDY1NCkiCiAgICAgICAgICAgaWQ9Imc0NjUwIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ2NTYiIC8+PGcKICAgICAgICAgaWQ9Imc0NjU4Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ2NjQpIgogICAgICAgICAgIGlkPSJnNDY2MCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0Njc4Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ2ODQpIgogICAgICAgICAgIGlkPSJnNDY4MCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0Njg2Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ2OTIpIgogICAgICAgICAgIGlkPSJnNDY4OCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0Njk0IiAvPjxnCiAgICAgICAgIGlkPSJnNDY5NiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NzAyKSIKICAgICAgICAgICBpZD0iZzQ2OTgiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDcxNiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NzIyKSIKICAgICAgICAgICBpZD0iZzQ3MTgiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDcyNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NzMwKSIKICAgICAgICAgICBpZD0iZzQ3MjYiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDczMiIgLz48ZwogICAgICAgICBpZD0iZzQ3MzQiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDc0MCkiCiAgICAgICAgICAgaWQ9Imc0NzM2IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ3NTQiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDc2MCkiCiAgICAgICAgICAgaWQ9Imc0NzU2LTUiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDc2MiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0NzY4KSIKICAgICAgICAgICBpZD0iZzQ3NjQiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDc3MCIgLz48ZwogICAgICAgICBpZD0iZzQ3NzIiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDc3OCkiCiAgICAgICAgICAgaWQ9Imc0Nzc0IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ3OTIiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDc5OCkiCiAgICAgICAgICAgaWQ9Imc0Nzk0IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ4MDAiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDgwNikiCiAgICAgICAgICAgaWQ9Imc0ODAyIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ4MDgiIC8+PGcKICAgICAgICAgaWQ9Imc0ODEwIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ4MTYpIgogICAgICAgICAgIGlkPSJnNDgxMiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0ODMwIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ4MzYpIgogICAgICAgICAgIGlkPSJnNDgzMiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0ODM4Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ4NDQpIgogICAgICAgICAgIGlkPSJnNDg0MCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0ODQ2IiAvPjxnCiAgICAgICAgIGlkPSJnNDg0OCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODU0KSIKICAgICAgICAgICBpZD0iZzQ4NTAiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDg2OCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODc0KSIKICAgICAgICAgICBpZD0iZzQ4NzAiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDg3NiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODgyKSIKICAgICAgICAgICBpZD0iZzQ4NzgiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDg4NCIgLz48ZwogICAgICAgICBpZD0iZzQ4ODYiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDg5MikiCiAgICAgICAgICAgaWQ9Imc0ODg4IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ5MDYiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDkxMikiCiAgICAgICAgICAgaWQ9Imc0OTA4IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ5MTQiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNDkyMCkiCiAgICAgICAgICAgaWQ9Imc0OTE2IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzQ5MjIiIC8+PGcKICAgICAgICAgaWQ9Imc0OTI0Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ5MzApIgogICAgICAgICAgIGlkPSJnNDkyNiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0OTQ0Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ5NTApIgogICAgICAgICAgIGlkPSJnNDk0NiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0OTUyIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDQ5NTgpIgogICAgICAgICAgIGlkPSJnNDk1NCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc0OTYwIiAvPjxnCiAgICAgICAgIGlkPSJnNDk2MiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0OTY4KSIKICAgICAgICAgICBpZD0iZzQ5NjQiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDk4MiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0OTg4KSIKICAgICAgICAgICBpZD0iZzQ5ODQiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDk5MCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0OTk2KSIKICAgICAgICAgICBpZD0iZzQ5OTIiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNDk5OCIgLz48ZwogICAgICAgICBpZD0iZzUwMDAiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTAwNikiCiAgICAgICAgICAgaWQ9Imc1MDAyIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUwMjAiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTAyNikiCiAgICAgICAgICAgaWQ9Imc1MDIyIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUwMjgiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTAzNCkiCiAgICAgICAgICAgaWQ9Imc1MDMwIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUwMzYiIC8+PGcKICAgICAgICAgaWQ9Imc1MDM4Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDUwNDQpIgogICAgICAgICAgIGlkPSJnNTA0MCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc1MDU4Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDUwNjQpIgogICAgICAgICAgIGlkPSJnNTA2MCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc1MDY2Ij48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDUwNzIpIgogICAgICAgICAgIGlkPSJnNTA2OCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc1MDc0IiAvPjxnCiAgICAgICAgIGlkPSJnNTA3NiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg1MDgyKSIKICAgICAgICAgICBpZD0iZzUwNzgiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNTA5NiI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg1MTAyKSIKICAgICAgICAgICBpZD0iZzUwOTgiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNTEwNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg1MTEwKSIKICAgICAgICAgICBpZD0iZzUxMDYiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNTExMiIgLz48ZwogICAgICAgICBpZD0iZzUxMTQiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTEyMCkiCiAgICAgICAgICAgaWQ9Imc1MTE2IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUxMzQiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTE0MCkiCiAgICAgICAgICAgaWQ9Imc1MTM2IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUxNDIiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTE0OCkiCiAgICAgICAgICAgaWQ9Imc1MTQ0IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUxNTAiIC8+PGcKICAgICAgICAgaWQ9Imc1MTUyIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDUxNTgpIgogICAgICAgICAgIGlkPSJnNTE1NCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc1MTcyIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDUxNzgpIgogICAgICAgICAgIGlkPSJnNTE3NCIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc1MTgwIj48ZwogICAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDUxODYpIgogICAgICAgICAgIGlkPSJnNTE4MiIgLz48L2c+PGcKICAgICAgICAgaWQ9Imc1MTg4IiAvPjxnCiAgICAgICAgIGlkPSJnNTE5MCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg1MTk2KSIKICAgICAgICAgICBpZD0iZzUxOTIiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNTIxMCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg1MjE2KSIKICAgICAgICAgICBpZD0iZzUyMTIiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNTIxOCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg1MjI0KSIKICAgICAgICAgICBpZD0iZzUyMjAiIC8+PC9nPjxnCiAgICAgICAgIGlkPSJnNTIyNiIgLz48ZwogICAgICAgICBpZD0iZzUyMjgiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTIzNCkiCiAgICAgICAgICAgaWQ9Imc1MjMwIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUyNDgiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTI1NCkiCiAgICAgICAgICAgaWQ9Imc1MjUwIiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUyNTYiPjxnCiAgICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoNTI2MikiCiAgICAgICAgICAgaWQ9Imc1MjU4IiAvPjwvZz48ZwogICAgICAgICBpZD0iZzUyNjQiIC8+PGcKICAgICAgICAgaWQ9Imc1MjY2IiAvPjxnCiAgICAgICAgIGlkPSJnNTI2OCIgLz48ZwogICAgICAgICBpZD0iZzUyNzAiIC8+PGcKICAgICAgICAgaWQ9Imc1Mjc2IiAvPjxnCiAgICAgICAgIGlkPSJnNTI3OCIgLz48ZwogICAgICAgICBpZD0iZzUyODQiIC8+PGcKICAgICAgICAgaWQ9Imc1MjkyIiAvPjxnCiAgICAgICAgIGlkPSJnNTI5NCIgLz48ZwogICAgICAgICBpZD0iZzUyOTYiIC8+PGcKICAgICAgICAgaWQ9Imc1Mjk4IiAvPjxnCiAgICAgICAgIGlkPSJnNTMwNCIgLz48ZwogICAgICAgICBpZD0iZzUzMDYiIC8+PGcKICAgICAgICAgaWQ9Imc1MzE0IiAvPjxnCiAgICAgICAgIGlkPSJnNTMyMCIgLz48ZwogICAgICAgICBpZD0iZzUzMjIiIC8+PGcKICAgICAgICAgaWQ9Imc1MzI0IiAvPjxnCiAgICAgICAgIGlkPSJnNTMyNiIgLz48ZwogICAgICAgICBpZD0iZzUzMzIiIC8+PGcKICAgICAgICAgaWQ9Imc1MzM0IiAvPjxnCiAgICAgICAgIGlkPSJnNTM0MiIgLz48ZwogICAgICAgICBpZD0iZzUzNDgiIC8+PGcKICAgICAgICAgaWQ9Imc1MzUwIiAvPjxnCiAgICAgICAgIGlkPSJnNTM1MiIgLz48ZwogICAgICAgICBpZD0iZzUzNTQiIC8+PGcKICAgICAgICAgaWQ9Imc1MzYwIiAvPjxnCiAgICAgICAgIGlkPSJnNTM2MiIgLz48ZwogICAgICAgICBpZD0iZzUzNzAiIC8+PGcKICAgICAgICAgaWQ9Imc1Mzc2IiAvPjxnCiAgICAgICAgIGlkPSJnNTM3OCIgLz48ZwogICAgICAgICBpZD0iZzUzODAiIC8+PGcKICAgICAgICAgaWQ9Imc1MzgyIiAvPjxnCiAgICAgICAgIGlkPSJnNTM4OCIgLz48ZwogICAgICAgICBpZD0iZzUzOTAiIC8+PGcKICAgICAgICAgaWQ9Imc1Mzk4IiAvPjxnCiAgICAgICAgIGlkPSJnNTQwNCIgLz48ZwogICAgICAgICBpZD0iZzU0MDYiIC8+PGcKICAgICAgICAgaWQ9Imc1NDA4IiAvPjxnCiAgICAgICAgIGlkPSJnNTQxMCIgLz48ZwogICAgICAgICBpZD0iZzU0MTYiIC8+PGcKICAgICAgICAgaWQ9Imc1NDE4IiAvPjxnCiAgICAgICAgIGlkPSJnNTQyNiIgLz48ZwogICAgICAgICBpZD0iZzU0MzIiIC8+PGcKICAgICAgICAgaWQ9Imc1NDM0IiAvPjxnCiAgICAgICAgIGlkPSJnNTQzNiIgLz48ZwogICAgICAgICBpZD0iZzU0MzgiIC8+PGcKICAgICAgICAgaWQ9Imc1NDQ0IiAvPjxnCiAgICAgICAgIGlkPSJnNTQ0NiIgLz48ZwogICAgICAgICBpZD0iZzU0NTQiIC8+PGcKICAgICAgICAgaWQ9Imc1NDYwIiAvPjxnCiAgICAgICAgIGlkPSJnNTQ2MiIgLz48ZwogICAgICAgICBpZD0iZzU0NjQiIC8+PGcKICAgICAgICAgaWQ9Imc1NDY2IiAvPjxnCiAgICAgICAgIGlkPSJnNTQ3MiIgLz48ZwogICAgICAgICBpZD0iZzU0NzQiIC8+PGcKICAgICAgICAgaWQ9Imc1NDgyIiAvPjxnCiAgICAgICAgIGlkPSJnNTQ4OCIgLz48ZwogICAgICAgICBpZD0iZzU0OTAiIC8+PGcKICAgICAgICAgaWQ9Imc1NDkyIiAvPjxnCiAgICAgICAgIGlkPSJnNTQ5NCIgLz48ZwogICAgICAgICBpZD0iZzU1MDAiIC8+PGcKICAgICAgICAgaWQ9Imc1NTAyIiAvPjxnCiAgICAgICAgIGlkPSJnNTUxMCIgLz48ZwogICAgICAgICBpZD0iZzU1MTYiIC8+PGcKICAgICAgICAgaWQ9Imc1NTE4IiAvPjxnCiAgICAgICAgIGlkPSJnNTUyMCIgLz48ZwogICAgICAgICBpZD0iZzU1MjIiIC8+PGcKICAgICAgICAgaWQ9Imc1NTI4IiAvPjxnCiAgICAgICAgIGlkPSJnNTUzMCIgLz48ZwogICAgICAgICBpZD0iZzU1MzgiIC8+PGcKICAgICAgICAgaWQ9Imc1NTQ0IiAvPjxnCiAgICAgICAgIGlkPSJnNTU0NiIgLz48ZwogICAgICAgICBpZD0iZzU1NDgiIC8+PGcKICAgICAgICAgaWQ9Imc1NTUwIiAvPjxnCiAgICAgICAgIGlkPSJnNTU1NiIgLz48ZwogICAgICAgICBpZD0iZzU1NTgiIC8+PGcKICAgICAgICAgaWQ9Imc1NTY2IiAvPjxnCiAgICAgICAgIGlkPSJnNTU3MiIgLz48ZwogICAgICAgICBpZD0iZzU1NzQiIC8+PGcKICAgICAgICAgaWQ9Imc1NTc2IiAvPjxnCiAgICAgICAgIGlkPSJnNTU3OCIgLz48ZwogICAgICAgICBpZD0iZzU1ODQiIC8+PGcKICAgICAgICAgaWQ9Imc1NTg2IiAvPjxnCiAgICAgICAgIGlkPSJnNTU5NCIgLz48ZwogICAgICAgICBpZD0iZzU2MDAiIC8+PGcKICAgICAgICAgaWQ9Imc1NjAyIiAvPjxnCiAgICAgICAgIGlkPSJnNTYwNCIgLz48ZwogICAgICAgICBpZD0iZzU2MDYiIC8+PGcKICAgICAgICAgaWQ9Imc1NjEyIiAvPjxnCiAgICAgICAgIGlkPSJnNTYxNCIgLz48ZwogICAgICAgICBpZD0iZzU2MjIiIC8+PGcKICAgICAgICAgaWQ9Imc1NjI4IiAvPjxnCiAgICAgICAgIGlkPSJnNTYzMCIgLz48ZwogICAgICAgICBpZD0iZzU2MzIiIC8+PGcKICAgICAgICAgaWQ9Imc1NjM0IiAvPjxnCiAgICAgICAgIGlkPSJnNTY0MCIgLz48ZwogICAgICAgICBpZD0iZzU2NDIiIC8+PGcKICAgICAgICAgaWQ9Imc1NjUwIiAvPjxnCiAgICAgICAgIGlkPSJnNTY1NiIgLz48ZwogICAgICAgICBpZD0iZzU2NTgiIC8+PGcKICAgICAgICAgaWQ9Imc1NjYwIiAvPjxnCiAgICAgICAgIGlkPSJnNTY2MiIgLz48ZwogICAgICAgICBpZD0iZzU2NjgiIC8+PGcKICAgICAgICAgaWQ9Imc1NjcwIiAvPjxnCiAgICAgICAgIGlkPSJnNTY3OCIgLz48ZwogICAgICAgICBpZD0iZzU2ODQiIC8+PGcKICAgICAgICAgaWQ9Imc1Njg2IiAvPjxnCiAgICAgICAgIGlkPSJnNTY4OCIgLz48ZwogICAgICAgICBpZD0iZzU2OTAiIC8+PGcKICAgICAgICAgaWQ9Imc1Njk2IiAvPjxnCiAgICAgICAgIGlkPSJnNTY5OCIgLz48ZwogICAgICAgICBpZD0iZzU3MDYiIC8+PGcKICAgICAgICAgaWQ9Imc1NzEyIiAvPjxnCiAgICAgICAgIGlkPSJnNTcxNCIgLz48ZwogICAgICAgICBpZD0iZzU3MTYiIC8+PGcKICAgICAgICAgaWQ9Imc1NzE4IiAvPjxnCiAgICAgICAgIGlkPSJnNTcyNCIgLz48ZwogICAgICAgICBpZD0iZzU3MjYiIC8+PGcKICAgICAgICAgaWQ9Imc1NzM0IiAvPjxnCiAgICAgICAgIGlkPSJnNTc0MCIgLz48ZwogICAgICAgICBpZD0iZzU3NDIiIC8+PGcKICAgICAgICAgaWQ9Imc1NzQ0IiAvPjxnCiAgICAgICAgIGlkPSJnNTc0NiIgLz48ZwogICAgICAgICBpZD0iZzU3NTIiIC8+PGcKICAgICAgICAgaWQ9Imc1NzU0IiAvPjxnCiAgICAgICAgIGlkPSJnNTc2MiIgLz48ZwogICAgICAgICBpZD0iZzU3NjgiIC8+PGcKICAgICAgICAgaWQ9Imc1NzcwIiAvPjxnCiAgICAgICAgIGlkPSJnNTc3MiIgLz48ZwogICAgICAgICBpZD0iZzU3NzQiIC8+PGcKICAgICAgICAgaWQ9Imc1NzgwIiAvPjxnCiAgICAgICAgIGlkPSJnNTc4MiIgLz48ZwogICAgICAgICBpZD0iZzU3OTAiIC8+PGcKICAgICAgICAgaWQ9Imc1Nzk2IiAvPjxnCiAgICAgICAgIGlkPSJnNTc5OCIgLz48ZwogICAgICAgICBpZD0iZzU4MDAiIC8+PGcKICAgICAgICAgaWQ9Imc1ODAyIiAvPjxnCiAgICAgICAgIGlkPSJnNTgwOCIgLz48ZwogICAgICAgICBpZD0iZzU4MTAiIC8+PGcKICAgICAgICAgaWQ9Imc1ODE4IiAvPjxnCiAgICAgICAgIGlkPSJnNTgyNCIgLz48ZwogICAgICAgICBpZD0iZzU4MjYiIC8+PGcKICAgICAgICAgaWQ9Imc1ODI4IiAvPjxnCiAgICAgICAgIGlkPSJnNTgzMCIgLz48ZwogICAgICAgICBpZD0iZzU4MzYiIC8+PGcKICAgICAgICAgaWQ9Imc1ODM4IiAvPjxnCiAgICAgICAgIGlkPSJnNTg0NiIgLz48ZwogICAgICAgICBpZD0iZzU4NTIiIC8+PGcKICAgICAgICAgaWQ9Imc1ODU0IiAvPjxnCiAgICAgICAgIGlkPSJnNTg1NiIgLz48ZwogICAgICAgICBpZD0iZzU4NTgiIC8+PGcKICAgICAgICAgaWQ9Imc1ODY0IiAvPjxnCiAgICAgICAgIGlkPSJnNTg2NiIgLz48ZwogICAgICAgICBpZD0iZzU4NzQiIC8+PGcKICAgICAgICAgaWQ9Imc1ODgwIiAvPjxnCiAgICAgICAgIGlkPSJnNTg4MiIgLz48ZwogICAgICAgICBpZD0iZzU4ODQiIC8+PGcKICAgICAgICAgaWQ9Imc1ODg2IiAvPjxnCiAgICAgICAgIGlkPSJnNTg5MiIgLz48ZwogICAgICAgICBpZD0iZzU4OTQiIC8+PGcKICAgICAgICAgaWQ9Imc1OTAyIiAvPjxnCiAgICAgICAgIGlkPSJnNTkwOCIgLz48ZwogICAgICAgICBpZD0iZzU5MTAiIC8+PGcKICAgICAgICAgaWQ9Imc1OTEyIiAvPjxnCiAgICAgICAgIGlkPSJnNTkxNCIgLz48ZwogICAgICAgICBpZD0iZzU5MjAiIC8+PGcKICAgICAgICAgaWQ9Imc1OTIyIiAvPjxnCiAgICAgICAgIGlkPSJnNTkzMCIgLz48ZwogICAgICAgICBpZD0iZzU5MzYiIC8+PGcKICAgICAgICAgaWQ9Imc1OTM4IiAvPjxnCiAgICAgICAgIGlkPSJnNTk0MCIgLz48ZwogICAgICAgICBpZD0iZzU5NDIiIC8+PGcKICAgICAgICAgaWQ9Imc1OTQ0IiAvPjxnCiAgICAgICAgIGlkPSJnNTk0NiIgLz48ZwogICAgICAgICBpZD0iZzU5NDgiIC8+PGcKICAgICAgICAgaWQ9Imc1OTUwIiAvPjxnCiAgICAgICAgIGlkPSJnNTk1MiIgLz48ZwogICAgICAgICBpZD0iZzU5NTQiIC8+PGcKICAgICAgICAgaWQ9Imc1OTU2IiAvPjxnCiAgICAgICAgIGlkPSJnNTk1OCIgLz48ZwogICAgICAgICBpZD0iZzU5NjAiIC8+PGcKICAgICAgICAgaWQ9Imc1OTYyIiAvPjxnCiAgICAgICAgIGlkPSJnNTk2NCIgLz48ZwogICAgICAgICBpZD0iZzU5NjYiIC8+PGcKICAgICAgICAgaWQ9Imc1OTY4IiAvPjxnCiAgICAgICAgIGlkPSJnNTk3MCIgLz48ZwogICAgICAgICBpZD0iZzU5NzIiIC8+PGcKICAgICAgICAgaWQ9Imc1OTc0IiAvPjxnCiAgICAgICAgIGlkPSJnNTk3NiIgLz48ZwogICAgICAgICBpZD0iZzU5NzgiIC8+PGcKICAgICAgICAgaWQ9Imc1OTgwIiAvPjxnCiAgICAgICAgIGlkPSJnNTk4MiIgLz48ZwogICAgICAgICBpZD0iZzU5ODQiIC8+PGcKICAgICAgICAgaWQ9Imc1OTg2IiAvPjxnCiAgICAgICAgIGlkPSJnNTk4OCIgLz48ZwogICAgICAgICBpZD0iZzU5OTAiIC8+PGcKICAgICAgICAgaWQ9Imc1OTkyIiAvPjxnCiAgICAgICAgIGlkPSJnNTk5NCIgLz48ZwogICAgICAgICBpZD0iZzU5OTYiIC8+PGcKICAgICAgICAgaWQ9Imc1OTk4IiAvPjxnCiAgICAgICAgIGlkPSJnNjAwMCIgLz48ZwogICAgICAgICBpZD0iZzYwMDIiIC8+PGcKICAgICAgICAgaWQ9Imc2MDA0IiAvPjxnCiAgICAgICAgIGlkPSJnNjAwNiIgLz48ZwogICAgICAgICBpZD0iZzYwMDgiIC8+PGcKICAgICAgICAgaWQ9Imc2MDEwIiAvPjxnCiAgICAgICAgIGlkPSJnNjAxMiIgLz48ZwogICAgICAgICBpZD0iZzYwMTQiIC8+PGcKICAgICAgICAgaWQ9Imc2MDE2IiAvPjxnCiAgICAgICAgIGlkPSJnNjAxOCIgLz48ZwogICAgICAgICBpZD0iZzYwMjAiIC8+PGcKICAgICAgICAgaWQ9Imc2MDIyIiAvPjxnCiAgICAgICAgIGlkPSJnNjAyNCIgLz48ZwogICAgICAgICBpZD0iZzYwMjYiIC8+PGcKICAgICAgICAgaWQ9Imc2MDI4IiAvPjxnCiAgICAgICAgIGlkPSJnNjAzMCIgLz48ZwogICAgICAgICBpZD0iZzYwMzIiIC8+PGcKICAgICAgICAgaWQ9Imc2MDM0IiAvPjxnCiAgICAgICAgIGlkPSJnNjAzNiIgLz48ZwogICAgICAgICBpZD0iZzYwNDQiIC8+PGcKICAgICAgICAgaWQ9Imc2MDUyIiAvPjxnCiAgICAgICAgIGlkPSJnNjA1NCIgLz48ZwogICAgICAgICBpZD0iZzYwNTYiIC8+PGcKICAgICAgICAgaWQ9Imc2MDU4IiAvPjxnCiAgICAgICAgIGlkPSJnNjA2MCIgLz48ZwogICAgICAgICBpZD0iZzYwNjIiIC8+PGcKICAgICAgICAgaWQ9Imc2MDY0IiAvPjxnCiAgICAgICAgIGlkPSJnNjA3MCIgLz48ZwogICAgICAgICBpZD0iZzYwNzIiIC8+PGcKICAgICAgICAgaWQ9Imc2MDc0IiAvPjxnCiAgICAgICAgIGlkPSJnNjA4MiIgLz48ZwogICAgICAgICBpZD0iZzYwODQiIC8+PGcKICAgICAgICAgaWQ9Imc2MDg2IiAvPjxnCiAgICAgICAgIGlkPSJnNjA4OCIgLz48ZwogICAgICAgICBpZD0iZzYwOTQiIC8+PGcKICAgICAgICAgaWQ9Imc2MDk2IiAvPjxnCiAgICAgICAgIGlkPSJnNjA5OCIgLz48ZwogICAgICAgICBpZD0iZzYxMDQiIC8+PGcKICAgICAgICAgaWQ9Imc2MTA2IiAvPjxnCiAgICAgICAgIGlkPSJnNjEwOCIgLz48ZwogICAgICAgICBpZD0iZzYxMTYiIC8+PGcKICAgICAgICAgaWQ9Imc2MTE4IiAvPjxnCiAgICAgICAgIGlkPSJnNjEyMCIgLz48ZwogICAgICAgICBpZD0iZzYxMjIiIC8+PGcKICAgICAgICAgaWQ9Imc2MTMwIiAvPjxnCiAgICAgICAgIGlkPSJnNjEzMiIgLz48ZwogICAgICAgICBpZD0iZzYxMzQiIC8+PGcKICAgICAgICAgaWQ9Imc2MTM2IiAvPjxnCiAgICAgICAgIGlkPSJnNjEzOCIgLz48ZwogICAgICAgICBpZD0iZzYxNDAiIC8+PGcKICAgICAgICAgaWQ9Imc2MTQ4IiAvPjxnCiAgICAgICAgIGlkPSJnNjE1MCIgLz48ZwogICAgICAgICBpZD0iZzYxNTIiIC8+PGcKICAgICAgICAgaWQ9Imc2MTU0IiAvPjxnCiAgICAgICAgIGlkPSJnNjE1NiIgLz48ZwogICAgICAgICBpZD0iZzYxNTgiIC8+PC9nPjxnCiAgICAgICBpZD0iZzEyMTgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC41MjY4MjI2NywwLDAsMC41MzA0NTA1LC02LjEwOTYzNSwtMTQ0LjMyNjI3KSI+PGcKICAgICAgICAgaWQ9ImcxMjE0OCI+PGcKICAgICAgICAgICBpZD0iZzEyMTQ2IiAvPjwvZz48L2c+PGcKICAgICAgIGlkPSJnMTI0ODItNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNDg0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI0ODYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjQ4OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNDkwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI0OTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjQ5NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNDk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI0OTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjUwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTAyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1MDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjUwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1MTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjUxMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTE0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1MTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjUxOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTIwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1MjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjUyNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTI2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1MjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjUzMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTMyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1MzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjUzNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTM4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1NDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTQ0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1NDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTUwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1NTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU1NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTU2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1NTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTYyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1NjQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU2NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTY4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1NzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU3MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTc0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1NzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU3OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1ODIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU4NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTg2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1ODgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU5MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTkyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI1OTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjU5NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyNTk4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI2MDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjYwMi01IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTI2MDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMjYxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEyODc0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTMyMDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMzM2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzEzNTI0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTM3NDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxMzkxNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE0MTA0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTQyODAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNDQ3OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE0NjUyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTQ3NjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNDg3MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE0OTgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTUxMTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNTIwOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE1NDMyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTU1MzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNTY4OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE1NzMwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTU4MTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNTg2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE1ODk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTU5NzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNTk3OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE1OTgwIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNTk4NCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE1OTk4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYwMDAiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MDA0KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYwMDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjAwOCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYwMTIpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjAxNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2MDE2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYwMTgiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MDIyKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYwMzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjAzOCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYwNDIpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjA0NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MDQ2IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjA1MCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MDUyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTYwNTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjA1NiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYwNjApIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjA3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MDc2IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjA4MCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MDgyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYwODQiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MDg4KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYwOTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjA5MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MDk0IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjA5OCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MTEyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYxMTQiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MTE4KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYxMjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjEyMiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYxMjYpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjEyOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2MTMwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYxMzIiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MTM2KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYxNTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjE1MiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYxNTYpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjE1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MTYwIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjE2NCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MTY2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTYxNjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjE3MCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYxNzQpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjE4OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MTkwIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjE5NCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MTk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYxOTgiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MjAyKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYyMDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjIwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MjA4IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjIxMikiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MjI2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYyMjgiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MjMyKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYyMzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjIzNiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYyNDApIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjI0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2MjQ0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYyNDYiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MjUwKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYyNjQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjI2NiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYyNzApIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjI3MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2Mjc0IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjI3OCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MjgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTYyODIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjI4NCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYyODgpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjMwMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MzA0IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjMwOCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MzEwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYzMTIiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MzE2KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYzMTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjMyMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2MzIyIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjMyNikiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2MzQwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYzNDIiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MzQ2KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYzNDgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjM1MCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYzNTQpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjM1NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2MzU4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTYzNjAiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2MzY0KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTYzNzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjM4MCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTYzODQpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjM4NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2Mzg4IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjM5MikiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2Mzk0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTYzOTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjM5OCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY0MDIpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjQxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NDE4IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjQyMikiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NDI0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY0MjYiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NDMwKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY0MzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjQzNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NDM2IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjQ0MCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NDU0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY0NTYiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NDYwKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY0NjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjQ2NCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY0NjgpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjQ3MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2NDcyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY0NzQiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NDc4KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY0OTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjQ5NCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY0OTgpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjUwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NTAyIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjUwNikiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NTA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY1MTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjUxMiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY1MTYpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjUzMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NTMyIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjUzNikiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NTM4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY1NDAiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NTQ0KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY1NDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjU0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NTUwIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjU1NCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NTY4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY1NzAiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NTc0KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY1NzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjU3OCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY1ODIpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjU4NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2NTg2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY1ODgiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NTkyKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY2MDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjYwOCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY2MTIpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjYxNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NjE2IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjYyMCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NjIyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY2MjQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjYyNiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY2MzApIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjY0NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NjQ2IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjY1MCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NjUyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY2NTQiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NjU4KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY2NjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjY2MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NjY0IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjY2OCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NjgyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY2ODQiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2Njg4KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY2OTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjY5MiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY2OTYpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjY5OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2NzAwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY3MDIiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NzA2KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY3MjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjcyMiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY3MjYpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjcyOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NzMwIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjczNCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NzM2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY3MzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjc0MCIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY3NDQpIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjc1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2NzYwIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjc2NCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2NzY2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY3NjgiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2NzcyKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY3NzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjc3NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2Nzc4IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjc4MikiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2Nzk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY3OTgiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2ODAyKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY4MDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjgwNiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY4MTApIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjgxMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2ODE0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiPjxnCiAgICAgICAgIGlkPSJnMTY4MTYiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDE2ODIwKSIgLz48L2c+PGcKICAgICAgIGlkPSJnMTY4MzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSI+PGcKICAgICAgICAgaWQ9ImcxNjgzNiIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMTY4NDApIiAvPjwvZz48ZwogICAgICAgaWQ9ImcxNjg0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIj48ZwogICAgICAgICBpZD0iZzE2ODQ0IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxNjg0OCkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzE2ODUwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY4NTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjg1NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2ODU2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY4NjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjg2NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2ODcwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY4NzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjg4MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2ODgyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY4ODQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjg5MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2ODkyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5MDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjkwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5MTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjkxMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTE4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5MjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjkyOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTM0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5MzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjkzOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTQwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5NDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjk0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTU2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5NjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjk2NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTY2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5NjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjk3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTc2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5ODQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjk5MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE2OTkyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTY5OTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNjk5NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDAyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwMDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzAxMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDE4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwMjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzAyMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDI0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwMzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzAzMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDQwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwNDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzA0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDUwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwNTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzA1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDYwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwNjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzA3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDc2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwNzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzA4MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MDg2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcwODgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzA5NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTAyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxMDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzEwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxMTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzExNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTI0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxMzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzEzMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTM0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxMzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzE0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTQ0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxNTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzE1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTYwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxNjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzE2NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTcwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxNzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzE4MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTg2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxODgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzE5MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MTkyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcxOTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzIwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MjA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyMTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzIxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MjE4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyMjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzIyNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MjI4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyMzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzI0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MjQ0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyNDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzI0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MjU0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyNTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzI2NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MjcwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyNzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzI3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3Mjc2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyODIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzI4NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MjkyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTcyOTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzMwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MzAyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczMDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzMxMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MzEyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczMjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzMyNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MzI4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczMzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzMzMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MzM4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczNDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzM0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MzU0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczNTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzM1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3MzYwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczNjYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzM2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3Mzc2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczODIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzM4NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3Mzg2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTczODgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzM5NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3Mzk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0MDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQxMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDEyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0MTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDIyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0MjQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQzMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDM4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0NDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQ0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDQ0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0NTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQ1MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDYwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0NjYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQ2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDcwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0NzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQ3OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0ODgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzQ5NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NDk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc0OTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzUwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTA2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1MDgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzUxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTIyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1MjQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzUyNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTI4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1MzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzUzMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTM0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1MzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzUzOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTQwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1NDIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU0NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTQ2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1NDgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU1MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTUyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1NTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU1NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTU4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1NjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU2MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTY0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1NjYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTcwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1NzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTc2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1NzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU4MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTgyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1ODQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU4NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTg4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1OTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU5MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NTk0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc1OTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzU5OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjAwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2MDIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzYwNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjA2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2MDgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzYxMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjEyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2MTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzYxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjE4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2MjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzYyMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjMwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2MzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzY0MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjQyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2NDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzY0NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjQ4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2NTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzY1NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjU4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2NjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzY2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjcwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2NzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzY3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2ODIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzY4NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NjkwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc2OTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzY5NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NzAyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc3MDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzcwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NzA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc3MTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzcxOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NzIwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc3MjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzcyNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NzI2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc3MzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzczNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NzM4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMTc3NDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjMzMTM4NjQ0LDAsMCwtMC4zMTA3MzI3Niw4NS40MzgxOCwtMTI3LjQ4NDM4KSIgLz48ZwogICAgICAgaWQ9ImcxNzc0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzMxMzg2NDQsMCwwLC0wLjMxMDczMjc2LDg1LjQzODE4LC0xMjcuNDg0MzgpIiAvPjxnCiAgICAgICBpZD0iZzE3NzQ0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMzEzODY0NCwwLDAsLTAuMzEwNzMyNzYsODUuNDM4MTgsLTEyNy40ODQzOCkiIC8+PGcKICAgICAgIGlkPSJnMjg1MTciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODUxOSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4NTIxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg1MjMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODUyNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4NTI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg1MjkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODUzMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4NTMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg1MzUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODUzNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4NTM5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg1NDEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODU0MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4NTQ5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg5NjUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODk2NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4OTY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg5NzEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODk3MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4OTc1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg5NzciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODk3OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4OTgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg5ODMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODk4NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI4OTg3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjg5OTMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyODk5NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDA3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwMTUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTAxNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDE5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwMjEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTAyMyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwMzEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTAzMyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwNTMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTA1NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDU3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwNTkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTA2MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwNzciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTA3OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwODMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTA4NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MDg3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkwODkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTA5NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MTAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkxMjMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTEyNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MTI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkxMzUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTEzNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MTU3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkxNTkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTE2MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MTYzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkxNjUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTE2NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MTY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkxNzEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTE3MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5MTc1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsOTYuMzY1MTQsLTEwOS4zODg0OSkiIC8+PGcKICAgICAgIGlkPSJnMjkxNzciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw5Ni4zNjUxNCwtMTA5LjM4ODQ5KSIgLz48ZwogICAgICAgaWQ9ImcyOTE3OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDk2LjM2NTE0LC0xMDkuMzg4NDkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTQzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTQ3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTQ5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTUzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTU1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTU3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTYxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTYzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTY1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTY3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5NTgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzI5OTkzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDA3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIj48ZwogICAgICAgICBpZD0iZzMwNDA5IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMDQxMykiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMwNDI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIj48ZwogICAgICAgICBpZD0iZzMwNDI5IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMDQzMykiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMwNDM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIj48ZwogICAgICAgICBpZD0iZzMwNDM3IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMDQ0MSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMwNDQzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIj48ZwogICAgICAgICBpZD0iZzMwNDQ3IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMDQ1MSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMwNDY1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIj48ZwogICAgICAgICBpZD0iZzMwNDY3IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMDQ3MSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMwNDczIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIj48ZwogICAgICAgICBpZD0iZzMwNDc1IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMDQ3OSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMwNDgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDgzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDg1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDg3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDg5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDkxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNDk5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNzAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNzE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNzE3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNzE5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNzIxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNzI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwNzI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTQ3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTQ5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTU3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTc5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTkxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTkzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTk1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMwOTk5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDAxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDExIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDE5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDIxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDM3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDM5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDQzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMxMDQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zMTAxOTYyNSwwLDAsLTAuMjk4ODQ4MDQsMTAyLjA1NDI0LC0xNjYuNTY3NjkpIiAvPjxnCiAgICAgICBpZD0iZzMyNzE3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjcxOSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3MjEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjcyNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3MjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjczMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3MzMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjczNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3MzkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjc0MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3NDUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzQ3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjc0OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3NTEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzUzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjc1NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3NTciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjc2MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3NjMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzY1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjc2NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3NjkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzcxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjc3MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3NzUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyNzc3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjc3OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI3OTEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyODI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjg2MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI4NjUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIj48ZwogICAgICAgICBpZD0iZzMyODY3IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMjg3MSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMyODg1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSI+PGcKICAgICAgICAgaWQ9ImczMjg4NyIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzI4OTEpIiAvPjwvZz48ZwogICAgICAgaWQ9ImczMjg5MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiPjxnCiAgICAgICAgIGlkPSJnMzI4OTUiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMyODk5KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMzI5MDEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyOTAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSI+PGcKICAgICAgICAgaWQ9ImczMjkwNSIKICAgICAgICAgY2xpcC1wYXRoPSJ1cmwoI2NsaXBQYXRoMzI5MDkpIiAvPjwvZz48ZwogICAgICAgaWQ9ImczMjkyMyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiPjxnCiAgICAgICAgIGlkPSJnMzI5MjUiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDMyOTI5KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMzI5MzEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIj48ZwogICAgICAgICBpZD0iZzMyOTMzIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzMjkzNykiIC8+PC9nPjxnCiAgICAgICBpZD0iZzMyOTM5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjk0MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI5NDMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyOTQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjk0NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzI5NDkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMyOTUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMjk3NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMwMjUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMDI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzAyOSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMwMzEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMDMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzAzNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMwMzciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMDYxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzA3NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMwNzciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMDc5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzA4MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMwODMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMDg1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzA4NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxMTEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzEyNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxMjkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTMxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzEzMyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxMzUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTM3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzEzOSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxNDEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTQzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzE0NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxNTMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTU1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzE1NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxNTkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTYxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzE2MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxNjUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTcxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzE3MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxNzUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTgzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzE4NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMxOTEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMTk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzIwMyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMyMDkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMjE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzIyMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMyMjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMjMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzIzOSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMyNDUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMjUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzI1NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMyNjMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMjY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzI3NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMyODEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMjg3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzI5MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMyOTUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMjk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzMwNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzMDciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzA5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzMxMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzMTkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzIxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzMyMyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzMjUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzMzNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzMzciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzM5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzM0NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzNDkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzM1MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzNjEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzYzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzM2NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzNjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzc1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzM3NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzNzkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzM4OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzMzOTEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzMzkzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzM5NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzM0MDMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzNDA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzQwNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzM0MDkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzNDE3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzQxOSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzM0MjEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzNDIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzQyNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzM0MjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzNDI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzQzMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzM0MzMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzNDM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzQzNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDYxLjYyNDg3LC0yMC40Mzg2MykiIC8+PGcKICAgICAgIGlkPSJnMzM0MzkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3Nyw2MS42MjQ4NywtMjAuNDM4NjMpIiAvPjxnCiAgICAgICBpZD0iZzMzNDQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNjEuNjI0ODcsLTIwLjQzODYzKSIgLz48ZwogICAgICAgaWQ9ImczMzgzNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzgzOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg0MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg0MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg0NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg0NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg1MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg1MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg1NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg1NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg2MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg2NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg2NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg3MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzg4MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkwMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkwNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkwOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkxMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkxMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkxNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkxOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkyMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkyMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkyNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkzMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzkzMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk1MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk2NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk2NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk3MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk3MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk4MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk4MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczMzk5NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDAyMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDAyMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDAyNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDAyNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDAyOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA2MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMTk0NjQzNzcsMCwwLC0wLjE1NTI0MTAyLDQwLjgyNDk4LDI2LjMzMTg1KSIgLz48ZwogICAgICAgaWQ9ImczNDA2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA3MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA3MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA3NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA3OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA4MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA4NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA4OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA5MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDA5OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEwMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEwNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDExMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDExMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDExNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEyMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEyMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEyNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEzMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEzNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEzNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDEzOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE0NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE1MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE1MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE1NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE1NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE2NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE2NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE3MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE3MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDE3NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LDM1LjQ1NDI3LDM1LjYxOTA2KSIgLz48ZwogICAgICAgaWQ9ImczNDM3NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQzNzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0MzgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDM4MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQzODQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0Mzg2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDM4OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQzOTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0MzkyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDM5NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQzOTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0Mzk4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDQwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ0MDIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NDA0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDQwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ0MDgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NDEwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDQyMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ0NjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NDY0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDQ2NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ0NjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NDcwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDQ3MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ0NzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NDc2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDQ3OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ0ODAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NDgyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDQ4NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ0OTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NDkyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDUxMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ1MjQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NTI2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDUyOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ1MzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NTMyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDUzNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ1NDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NTQyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDU2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ1OTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NTk0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDU5NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ1OTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjAwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDYwOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2MTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjE4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDYyMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2MjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjI0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDYyNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2MjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjM0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDYzNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2MzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjQ2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDY0OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2NTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjUyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDY1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2NjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjYyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDY2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2NzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NjcyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDY4MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2ODIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0Njg0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDY4NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ2OTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0Njk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDY5OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ3MDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NzAyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDcwNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ3MTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NzE0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDcxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ3MTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtNzEuNDcyNzIsLTEuNjg3MTkpIiAvPjxnCiAgICAgICBpZD0iZzM0NzIwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTcxLjQ3MjcyLC0xLjY4NzE5KSIgLz48ZwogICAgICAgaWQ9ImczNDcyMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC03MS40NzI3MiwtMS42ODcxOSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5MjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5MzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5MzIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5MzQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5MzYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5MzgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NDAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NDIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NDQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NDYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NDgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NTAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NTIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NTQiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NTYiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NjAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NjIiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NjgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjI3MTI5MTYzLDAsMCwtMC4yODUwNzIwMSwtMTc3LjA2NzIsLTE0NC4yNTc2NSkiIC8+PGcKICAgICAgIGlkPSJnMzQ5NzAiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjE2NzE5OTAzLDAsMCwtMC4xNjM3MDUyMiw3LjY1MTQ1OSwxMy4zMDQ2KSIKICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC42MDQ0Mzg7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lIj48ZwogICAgICAgICBpZD0iZzM0OTcyIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgzNDk3NikiCiAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC42MDQ0Mzg7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPjwvZz48ZwogICAgICAgaWQ9ImczNDk4OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNDk5MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNDk5MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNDk5NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNDk5NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNDk5OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAwMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAwMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAwNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAwOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAxMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAxNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAxOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTAzOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA1MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA1MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA1NCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA1NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA1OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA2NiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA2OCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTA4MiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTEwNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTEwOCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTExMCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTExMiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTExNCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMjcxMjkxNjMsMCwwLC0wLjI4NTA3MjAxLC0xNzcuMDY3MiwtMTQ0LjI1NzY1KSIgLz48ZwogICAgICAgaWQ9ImczNTExNiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMTY3MTk5MDMsMCwwLC0wLjE2MzcwNTIyLDcuNjUxNDU5LDEzLjMwNDYpIiAvPjxnCiAgICAgICBpZD0iZzM1MTIyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTMwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTMyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTM0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTM2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTM4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTQwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTQyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTQ4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTUwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTUyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTYwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTYyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTY0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTY2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTcyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTc4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTgwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTgyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTg4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTk0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTk2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MTk4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjA2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjEwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjEyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjIwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjIyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjI0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjI2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjI4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjMwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjM4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjQwIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjQyIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjQ0IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjQ2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1MjQ4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yNzEyOTE2MywwLDAsLTAuMjg1MDcyMDEsLTE3Ny4wNjcyLC0xNDQuMjU3NjUpIiAvPjxnCiAgICAgICBpZD0iZzM1NDQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTQ0MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU0NDUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NDQ3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTQ0OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU0NTEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NDUzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTQ1NSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU0NTciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NDU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTQ2MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU0NjMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NDY1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTQ2NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU0NjkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NDcxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTQ3MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiPjxnCiAgICAgICAgIGlkPSJnMzU0NzUiCiAgICAgICAgIGNsaXAtcGF0aD0idXJsKCNjbGlwUGF0aDM1NDc5KSIgLz48L2c+PGcKICAgICAgIGlkPSJnMzU0ODEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NTIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTUyNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU1MjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NTI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTUzMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU1MzMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NTM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTUzNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU1MzkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NTQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTU0MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU1NDUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NTUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTU1MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU1ODUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NjAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTYwNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU2MDciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NjA5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTYxMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU2MTMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NjE5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTYyMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU2MzUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NjU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTY2MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU2NjMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NjY1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTY2NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3MjEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NzIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTcyNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3MjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NzI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTczMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3MzMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NzM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTczNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3NDMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NzQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTc0NyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3NTUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1NzU3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTc2MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3NjkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1Nzc1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTc4MSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3ODMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1Nzg1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTc5MyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU3OTUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1Nzk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTc5OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU4MDciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1ODA5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTgxMSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU4MTMiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1ODE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTgxNyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU4MTkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1ODIxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTgyMyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU4MjUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzM1ODI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsLTE5Ny40Njg3MSwtMTA2LjcyNjc4KSIgLz48ZwogICAgICAgaWQ9ImczNTgyOSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMzUyNzc3NzcsMCwwLC0wLjM1Mjc3Nzc3LC0xOTcuNDY4NzEsLTEwNi43MjY3OCkiIC8+PGcKICAgICAgIGlkPSJnMzU4MzEiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM1Mjc3Nzc3LDAsMCwtMC4zNTI3Nzc3NywtMTk3LjQ2ODcxLC0xMDYuNzI2NzgpIiAvPjxnCiAgICAgICBpZD0iZzQ4NTg5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NTkxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NTkzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NTk1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NTk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NTk5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjAxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjA3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjA5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjExIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjEzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjE3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjE5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjIxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjMxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjM3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjM5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjQzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NjU1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4Njg5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NzIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NzI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIj48ZwogICAgICAgICBpZD0iZzQ4NzI3IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODczMSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzQ4NzQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIj48ZwogICAgICAgICBpZD0iZzQ4NzQ3IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODc1MSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzQ4NzUzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIj48ZwogICAgICAgICBpZD0iZzQ4NzU1IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODc1OSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzQ4NzYxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4NzYzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIj48ZwogICAgICAgICBpZD0iZzQ4NzY1IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODc2OSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzQ4NzgzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIj48ZwogICAgICAgICBpZD0iZzQ4Nzg1IgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODc4OSkiIC8+PC9nPjxnCiAgICAgICBpZD0iZzQ4NzkxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIj48ZwogICAgICAgICBpZD0iZzQ4NzkzIgogICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGg0ODc5NykiIC8+PC9nPjxnCiAgICAgICBpZD0iZzQ4Nzk5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODAxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODA3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODA5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODExIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODc5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODgzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODg1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODg3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODg5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4ODkxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTExIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTMxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTM1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTU1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTY3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTcxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTczIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTc1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTc3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTc5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTgzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTg1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTg3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTk1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTk5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDAxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDAzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDA3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDEzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDE3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDMzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDM5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDQ1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDU3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDYzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDc1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDg3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDkzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MDk5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTExIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTEzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTM3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTM5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTQxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTQzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTUxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTUzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTU1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTU3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTY1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTY3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTY5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTcxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTc5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTgxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTgzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTg1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTkzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTk1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTk3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MTk5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjA3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjA5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjExIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjEzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjE3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjE5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjIxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjIzIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjI1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjI3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjI5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ5MjMxIgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4zNTI3Nzc3NywwLDAsLTAuMzUyNzc3NzcsNzUuMzg1MjUsNzcuNjg3ODEpIiAvPjxnCiAgICAgICBpZD0iZzQ4OTg5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4yMjIxNzUzNCwwLDAsLTAuMjQ4NDM5NCwxNDQuMDg0NSwtNjEuNjI1NjcpIiAvPjxmbG93Um9vdAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIGlkPSJmbG93Um9vdDczNDM3IgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6MTJweDtsaW5lLWhlaWdodDowLjI7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjt0ZXh0LWFsaWduOmNlbnRlcjtsZXR0ZXItc3BhY2luZzowcHg7d29yZC1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTY5LjM0MTgzLC0yOTUuMDMwOTQpIj48Zmxvd1JlZ2lvbgogICAgICAgICBpZD0iZmxvd1JlZ2lvbjczNDM5Ij48cmVjdAogICAgICAgICAgIGlkPSJyZWN0NzM0NDEiCiAgICAgICAgICAgd2lkdGg9IjAiCiAgICAgICAgICAgaGVpZ2h0PSI1MCIKICAgICAgICAgICB4PSI4MTgiCiAgICAgICAgICAgeT0iMjUxLjcwMDc5IiAvPjwvZmxvd1JlZ2lvbj48Zmxvd1BhcmEKICAgICAgICAgaWQ9ImZsb3dQYXJhNzM0NDMiIC8+PC9mbG93Um9vdD48Zmxvd1Jvb3QKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBpZD0iZmxvd1Jvb3Q3MzQ0NSIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjEycHg7bGluZS1oZWlnaHQ6MC4yO2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7dGV4dC1hbGlnbjpjZW50ZXI7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7dGV4dC1hbmNob3I6bWlkZGxlO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIKICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKC02OS4zNDE4MywtMjk1LjAzMDk0KSI+PGZsb3dSZWdpb24KICAgICAgICAgaWQ9ImZsb3dSZWdpb243MzQ0NyI+PHJlY3QKICAgICAgICAgICBpZD0icmVjdDczNDQ5IgogICAgICAgICAgIHdpZHRoPSIxIgogICAgICAgICAgIGhlaWdodD0iNTAiCiAgICAgICAgICAgeD0iODE2IgogICAgICAgICAgIHk9IjI0Ny43MDA3OSIgLz48L2Zsb3dSZWdpb24+PGZsb3dQYXJhCiAgICAgICAgIGlkPSJmbG93UGFyYTczNDUxIiAvPjwvZmxvd1Jvb3Q+PGZsb3dSb290CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgaWQ9ImZsb3dSb290NzM0NTMiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToxMnB4O2xpbmUtaGVpZ2h0OjAuMjtmb250LWZhbWlseTpzYW5zLXNlcmlmO3RleHQtYWxpZ246Y2VudGVyO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3RleHQtYW5jaG9yOm1pZGRsZTtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNjkuMzQxODMsLTI5NS4wMzA5NCkiPjxmbG93UmVnaW9uCiAgICAgICAgIGlkPSJmbG93UmVnaW9uNzM0NTUiPjxyZWN0CiAgICAgICAgICAgaWQ9InJlY3Q3MzQ1NyIKICAgICAgICAgICB3aWR0aD0iNCIKICAgICAgICAgICBoZWlnaHQ9IjcwIgogICAgICAgICAgIHg9IjgxNCIKICAgICAgICAgICB5PSIyMjguNzAwNzkiIC8+PC9mbG93UmVnaW9uPjxmbG93UGFyYQogICAgICAgICBpZD0iZmxvd1BhcmE3MzQ1OSIgLz48L2Zsb3dSb290PjxmbG93Um9vdAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIGlkPSJmbG93Um9vdDczNDYxIgogICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6MTJweDtsaW5lLWhlaWdodDowLjI7Zm9udC1mYW1pbHk6c2Fucy1zZXJpZjt0ZXh0LWFsaWduOmNlbnRlcjtsZXR0ZXItc3BhY2luZzowcHg7d29yZC1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTY5LjM0MTgzLC0yOTUuMDMwOTQpIj48Zmxvd1JlZ2lvbgogICAgICAgICBpZD0iZmxvd1JlZ2lvbjczNDYzIj48cmVjdAogICAgICAgICAgIGlkPSJyZWN0NzM0NjUiCiAgICAgICAgICAgd2lkdGg9IjIuMTIxMzIwMiIKICAgICAgICAgICBoZWlnaHQ9IjUwLjIwNDU4MiIKICAgICAgICAgICB4PSI4MTQuNTg3MDQiCiAgICAgICAgICAgeT0iMjQ4LjUyMTQ1IiAvPjwvZmxvd1JlZ2lvbj48Zmxvd1BhcmEKICAgICAgICAgaWQ9ImZsb3dQYXJhNzM0NjciIC8+PC9mbG93Um9vdD48ZwogICAgICAgaWQ9ImcxMDIwMzAiIC8+PGcKICAgICAgIGlkPSJnNjEwOSIKICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTguOTk1ODMzOCkiPjxnCiAgICAgICAgIGlkPSJnMTI0NDYiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMDYwNTE2NywwLDAsMS4wNjA1MTY3LC05OS42NjA1NjYsMTUuODk5OTA4KSI+PHRleHQKICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToyLjAyNzU2cHg7Zm9udC1mYW1pbHk6bW9ub3NwYWNlOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J21vbm9zcGFjZSwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOm5vcm1hbDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE1NTk2NiIKICAgICAgICAgICBpZD0idGV4dDI0MjEiCiAgICAgICAgICAgeD0iMTEwLjY2NjY2IgogICAgICAgICAgIHk9IjYzLjI1ODI1OSI+PHRzcGFuCiAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgaWQ9InRzcGFuMjQxOSIKICAgICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToyLjAyNzU2cHg7Zm9udC1mYW1pbHk6bW9ub3NwYWNlOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J21vbm9zcGFjZSwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOm5vcm1hbDtzdHJva2Utd2lkdGg6MC4xNTU5NjYiCiAgICAgICAgICAgICB4PSIxMTAuNjY2NjYiCiAgICAgICAgICAgICB5PSI2My4yNTgyNTkiPi0tcHJvY2Vzc2VkIC0tanVzdC1tZXRhZGF0YSA8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgIGlkPSJ0ZXh0MjQyMS0zIgogICAgICAgICAgIHg9IjExMC42NjY2NiIKICAgICAgICAgICB5PSI2NS4zNTk4NzEiPjx0c3BhbgogICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMyIKICAgICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToyLjAyNzU2cHg7Zm9udC1mYW1pbHk6bW9ub3NwYWNlOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J21vbm9zcGFjZSwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOm5vcm1hbDtzdHJva2Utd2lkdGg6MC4xNTU5NjYiCiAgICAgICAgICAgICB4PSIxMTAuNjY2NjYiCiAgICAgICAgICAgICB5PSI2NS4zNTk4NzEiPi0tZGF0YS1zb3VyY2Ugc2FtcGxlczwvdHNwYW4+PC90ZXh0PjwvZz48ZwogICAgICAgICBpZD0iZzEyMTgyIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjA2MDUxNjcsMCwwLDEuMDYwNTE2NywtMTAwLjI3MzE2LDE3LjE0MzI4NikiPjx0ZXh0CiAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNTU5NjYiCiAgICAgICAgICAgaWQ9InRleHQyNDIxLTgiCiAgICAgICAgICAgeD0iMTExLjE5ODAyIgogICAgICAgICAgIHk9IjY4LjEzNjEzOSI+PHRzcGFuCiAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS0wIgogICAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3N0cm9rZS13aWR0aDowLjE1NTk2NiIKICAgICAgICAgICAgIHg9IjExMS4xOTgwMiIKICAgICAgICAgICAgIHk9IjY4LjEzNjEzOSI+LS1wcm9jZXNzZWQ8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgIGlkPSJ0ZXh0MjQyMS01IgogICAgICAgICAgIHg9IjExMS4xOTgwMiIKICAgICAgICAgICB5PSI3MC4yMDIxMSI+PHRzcGFuCiAgICAgICAgICAgICB4PSIxMTEuMTk4MDIiCiAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS02IgogICAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3N0cm9rZS13aWR0aDowLjE1NTk2NiIKICAgICAgICAgICAgIHk9IjcwLjIwMjExIj4tLWRhdGEtc291cmNlIHNhbXBsZXM8L3RzcGFuPjwvdGV4dD48L2c+PGcKICAgICAgICAgaWQ9ImcxMjE3NiIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wNjA1MTY3LDAsMCwxLjA2MDUxNjcsLTEwMC4yNzMxNiw1Ljc2NjcwNzUpIj48dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgIGlkPSJ0ZXh0MjQyMS0wIgogICAgICAgICAgIHg9IjExMS4yMzE0OSIKICAgICAgICAgICB5PSI4NC44NzgxOTciPjx0c3BhbgogICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMDQiCiAgICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgICAgeT0iODQuODc4MTk3Ij4tLXByb2Nlc3NlZCAtLWp1c3QtbWV0YWRhdGE8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgIGlkPSJ0ZXh0MjQyMS02MiIKICAgICAgICAgICB4PSIxMTEuMjMxNDkiCiAgICAgICAgICAgeT0iODcuMTY5NDAzIj48dHNwYW4KICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTY3IgogICAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3N0cm9rZS13aWR0aDowLjE1NTk2NiIKICAgICAgICAgICAgIHg9IjExMS4yMzE0OSIKICAgICAgICAgICAgIHk9Ijg3LjE2OTQwMyI+LS1kYXRhLXNvdXJjZSBzZXJpZXM8L3RzcGFuPjwvdGV4dD48L2c+PGcKICAgICAgICAgaWQ9ImcxMjE3MCIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wNjA1MTY3LDAsMCwxLjA2MDUxNjcsLTEwMC4yNzMxNiw2LjMyOTY4NjgpIj48dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgIGlkPSJ0ZXh0MjQyMS04LTkiCiAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgIHk9IjkwLjE5NDIwNiI+PHRzcGFuCiAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS0wLTEiCiAgICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgICAgeT0iOTAuMTk0MjA2Ij4tLXByb2Nlc3NlZDwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNTU5NjYiCiAgICAgICAgICAgaWQ9InRleHQyNDIxLTYyLTkiCiAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgIHk9IjkyLjQ0OTc2OCI+PHRzcGFuCiAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS02Ny02IgogICAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3N0cm9rZS13aWR0aDowLjE1NTk2NiIKICAgICAgICAgICAgIHg9IjExMS4yMzE0OSIKICAgICAgICAgICAgIHk9IjkyLjQ0OTc2OCI+LS1kYXRhLXNvdXJjZSBzZXJpZXM8L3RzcGFuPjwvdGV4dD48L2c+PGcKICAgICAgICAgaWQ9ImcxMjE1OCIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wNjA1MTY3LDAsMCwxLjA2MDUxNjcsLTEwMC4yNzMxNiw3LjQ3MTI3MDMpIj48dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgIGlkPSJ0ZXh0MjQyMS04LTktOSIKICAgICAgICAgICB4PSIxMTEuMjMxNDkiCiAgICAgICAgICAgeT0iMTAwLjc3NTA5Ij48dHNwYW4KICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTAtMS05IgogICAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3N0cm9rZS13aWR0aDowLjE1NTk2NiIKICAgICAgICAgICAgIHg9IjExMS4yMzE0OSIKICAgICAgICAgICAgIHk9IjEwMC43NzUwOSI+LS1wcm9jZXNzZWQ8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjIuMDI3NTZweDtmb250LWZhbWlseTptb25vc3BhY2U7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonbW9ub3NwYWNlLCBOb3JtYWwnO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7Zm9udC12YXJpYW50LWVhc3QtYXNpYW46bm9ybWFsO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgIGlkPSJ0ZXh0MjQyMS01NiIKICAgICAgICAgICB4PSIxMTEuMjMxNDkiCiAgICAgICAgICAgeT0iMTAzLjAzMDY1Ij48dHNwYW4KICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTkiCiAgICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgICAgeT0iMTAzLjAzMDY1Ij4tLWRhdGEtc291cmNlIGFsbDwvdHNwYW4+PC90ZXh0PjwvZz48ZwogICAgICAgICBpZD0iZzEyMTY0IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjA2MDUxNjcsMCwwLDEuMDYwNTE2NywtMTAwLjI3MzE2LDcuMjIwMzc2NCkiPjx0ZXh0CiAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNTU5NjYiCiAgICAgICAgICAgaWQ9InRleHQyNDIxLTI1IgogICAgICAgICAgIHg9IjExMS4yMzE0OSIKICAgICAgICAgICB5PSI5NS4xNjUxODQiPjx0c3BhbgogICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktNDQiCiAgICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgICAgeT0iOTUuMTY1MTg0Ij4tLXByb2Nlc3NlZCAtLWp1c3QtbWV0YWRhdGEgPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToyLjAyNzU2cHg7Zm9udC1mYW1pbHk6bW9ub3NwYWNlOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J21vbm9zcGFjZSwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOm5vcm1hbDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE1NTk2NiIKICAgICAgICAgICBpZD0idGV4dDI0MjEtODciCiAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgIHk9Ijk3LjQ1NjM5Ij48dHNwYW4KICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTIiCiAgICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4wMjc1NnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7c3Ryb2tlLXdpZHRoOjAuMTU1OTY2IgogICAgICAgICAgICAgeD0iMTExLjIzMTQ5IgogICAgICAgICAgICAgeT0iOTcuNDU2MzkiPi0tZGF0YS1zb3VyY2UgYWxsPC90c3Bhbj48L3RleHQ+PC9nPjx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgaWQ9InRleHQyNDIxLTYxLTIiCiAgICAgICAgIHg9IjI5LjY5OTgyMSIKICAgICAgICAgeT0iNjkuNjU0MTYiPjx0c3BhbgogICAgICAgICAgIHg9IjI5LjY5OTgyMSIKICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMzItNiIKICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgIHk9IjY5LjY1NDE2Ij5Bcmd1bWVudHM8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgIGlkPSJ0ZXh0MjQyMS05IgogICAgICAgICB4PSIxMi43MDI0NTIiCiAgICAgICAgIHk9IjcwLjA4MDQyOSI+PHRzcGFuCiAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICBpZD0idHNwYW4yNDE5LTkxIgogICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgeD0iMTIuNzAyNDUyIgogICAgICAgICAgIHk9IjcwLjA4MDQyOSI+IzwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgaWQ9InRleHQyNDIxLTQiCiAgICAgICAgIHg9IjEyLjUyNDY1MiIKICAgICAgICAgeT0iNzQuODQyNTM3Ij48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktOTEwIgogICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgeD0iMTIuNTI0NjUyIgogICAgICAgICAgIHk9Ijc0Ljg0MjUzNyI+MTwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgaWQ9InRleHQyNDIxLTciCiAgICAgICAgIHg9IjEyLjQ2ODU2NSIKICAgICAgICAgeT0iNzkuMTU2NzQ2Ij48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktNTgiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICB4PSIxMi40Njg1NjUiCiAgICAgICAgICAgeT0iNzkuMTU2NzQ2Ij4yPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICBpZD0idGV4dDI0MjEtNzAiCiAgICAgICAgIHg9IjEyLjQ0ODAwOCIKICAgICAgICAgeT0iODQuMzA0NjY1Ij48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktNDgiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICB4PSIxMi40NDgwMDgiCiAgICAgICAgICAgeT0iODQuMzA0NjY1Ij4zPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICBpZD0idGV4dDI0MjEtMDQiCiAgICAgICAgIHg9IjEyLjQ4MjY1NiIKICAgICAgICAgeT0iOTAuNjc0NjgzIj48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjkiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICB4PSIxMi40ODI2NTYiCiAgICAgICAgICAgeT0iOTAuNjc0NjgzIj40PC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICBpZD0idGV4dDI0MjEtNjEwIgogICAgICAgICB4PSIxMi40NDI3NTkiCiAgICAgICAgIHk9Ijk2Ljk0MDczNSI+PHRzcGFuCiAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICBpZD0idHNwYW4yNDE5LTQyIgogICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgeD0iMTIuNDQyNzU5IgogICAgICAgICAgIHk9Ijk2Ljk0MDczNSI+NTwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgaWQ9InRleHQyNDIxLTIiCiAgICAgICAgIHg9IjEyLjQ1MzI1OCIKICAgICAgICAgeT0iMTAyLjkxMjExIj48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjAiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICB4PSIxMi40NTMyNTgiCiAgICAgICAgICAgeT0iMTAyLjkxMjExIj42PC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICBpZD0idGV4dDI0MjEtNTUiCiAgICAgICAgIHg9IjEyLjQ0MjIzMiIKICAgICAgICAgeT0iMTA5LjIyNzg1Ij48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjkwIgogICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgeD0iMTIuNDQyMjMyIgogICAgICAgICAgIHk9IjEwOS4yMjc4NSI+NzwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgaWQ9InRleHQyNDIxLTU1LTIiCiAgICAgICAgIHg9IjEyLjQ0ODAwOCIKICAgICAgICAgeT0iMTE1LjU0MzU5Ij48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjkwLTgiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICB4PSIxMi40NDgwMDgiCiAgICAgICAgICAgeT0iMTE1LjU0MzU5Ij44PC90c3Bhbj48L3RleHQ+PHBhdGgKICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC4wNjg5MzM2O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eTowLjMxMzU5NSIKICAgICAgICAgZD0ibSAxMC44NjQwODMsODYuNzEyNTU5IDgxLjkyMDAxNywwLjAwNjQiCiAgICAgICAgIGlkPSJwYXRoMTE0NjctNCIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLXR5cGU9InBvbHlsaW5lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPjxwYXRoCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuMDY4OTMzNjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MC4zMTM1OTUiCiAgICAgICAgIGQ9Im0gMTAuODY0MDgzLDkzLjA5MTIxMyA4MS45MjAwMTcsMC4wMDY0IgogICAgICAgICBpZD0icGF0aDExNDY3LTQtMCIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLXR5cGU9InBvbHlsaW5lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPjxwYXRoCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuMDY4OTMzNjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MC4zMTM1OTUiCiAgICAgICAgIGQ9Im0gMTAuODY0MDgzLDk5LjI5MTkwOSA4MS45MjAwMTcsMC4wMDY0IgogICAgICAgICBpZD0icGF0aDExNDY3LTQtODYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci10eXBlPSJwb2x5bGluZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz48cGF0aAogICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjA2ODkzMzY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjAuMzEiCiAgICAgICAgIGQ9Im0gMTAuODY0MDgzLDEwNS40NTQ4IDgxLjkyMDAxNywwLjAwNiIKICAgICAgICAgaWQ9InBhdGgxMTQ2Ny00LTIiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci10eXBlPSJwb2x5bGluZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz48cGF0aAogICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjA2ODkzMzY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjAuMzEzNTk1IgogICAgICAgICBkPSJtIDEwLjg2NDA4MywxMTEuNjU1MSA4MS45MjAwMTcsMC4wMDYiCiAgICAgICAgIGlkPSJwYXRoMTE0NjctNC00IgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItdHlwZT0icG9seWxpbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+PHBhdGgKICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC4wNztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MC4zMSIKICAgICAgICAgZD0ibSA1NC4yMTQ3MjMsMTE2LjY1MDE5IDAuMDA2LC00Ny4wMTMzNjciCiAgICAgICAgIGlkPSJwYXRoMTE0NjctMCIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLXR5cGU9InBvbHlsaW5lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPjxwYXRoCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuMjgwNTk1cHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0ibSAxMC4yNjE4ODgsNzEuNzQzMzE1IDgyLjg1MDI1NSwwLjAwNjQiCiAgICAgICAgIGlkPSJwYXRoMTE0NjciCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci10eXBlPSJwb2x5bGluZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz48cGF0aAogICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjI4MDU5NXB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Im0gMTUuNDg5ODkzLDExNi42NDYwMyAwLjAwNjQsLTQ3LjAxMzM3MiIKICAgICAgICAgaWQ9InBhdGgxMTQ2Ny0wLTQiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci10eXBlPSJwb2x5bGluZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz48cGF0aAogICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjA3O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eTowLjMxIgogICAgICAgICBkPSJtIDY4LjkwMDYxOSwxMTYuNjUwMTkgMC4wMDYsLTQ3LjAxMzM2NyIKICAgICAgICAgaWQ9InBhdGg3MDg2NiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLXR5cGU9InBvbHlsaW5lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPjxwYXRoCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvcGFjaXR5OjAuMzE7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjA3O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJtIDgxLjcyNzA5MiwxMTYuNjUwMTkgMC4wMDYsLTQ3LjAxMzM2NyIKICAgICAgICAgaWQ9InBhdGg3MDg2OCIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLXR5cGU9InBvbHlsaW5lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPjx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6bW9ub3NwYWNlOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J21vbm9zcGFjZSwgTm9ybWFsJztmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO2ZvbnQtdmFyaWFudC1lYXN0LWFzaWFuOm5vcm1hbDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgaWQ9InRleHQyNDIxLTYiCiAgICAgICAgIHg9IjE3LjcwMzI3MiIKICAgICAgICAgeT0iNzguNzk4NjkxIj48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjI0MTktNCIKICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidtb25vc3BhY2UsIE5vcm1hbCc7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtmb250LXZhcmlhbnQtZWFzdC1hc2lhbjpub3JtYWw7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgIHg9IjE3LjcwMzI3MiIKICAgICAgICAgICB5PSI3OC43OTg2OTEiPi0tanVzdC1tZXRhZGF0YTwvdHNwYW4+PC90ZXh0PjxnCiAgICAgICAgIGlkPSJnNTk3NyI+PHRleHQKICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICBpZD0idGV4dDI0MjEtMSIKICAgICAgICAgICB4PSI3MS4xMTU1NTUiCiAgICAgICAgICAgeT0iNjUuNTg1NjU1Ij48dHNwYW4KICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTUiCiAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgeD0iNzEuMTE1NTU1IgogICAgICAgICAgICAgeT0iNjUuNTg1NjU1Ij5PdXRwdXQ8L3RzcGFuPjwvdGV4dD48cGF0aAogICAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOm5vbmU7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuMjgwNTk1cHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBkPSJtIDYwLjE0MDA5Niw2Ni45OTYyMTQgMjguNDk0MDksMC4wMDY0IgogICAgICAgICAgIGlkPSJwYXRoMTE0NjctNiIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItdHlwZT0icG9seWxpbmUiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPjxnCiAgICAgICAgICAgaWQ9Imc1OTExIj48ZwogICAgICAgICAgICAgaWQ9Imc1ODA1Ij48dGV4dAogICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgIGlkPSJ0ZXh0MjQyMS0xLTkiCiAgICAgICAgICAgICAgIHg9IjU1LjU0NjEzNSIKICAgICAgICAgICAgICAgeT0iNzAuMDgwNDI5Ij48dHNwYW4KICAgICAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktNS00IgogICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgeD0iNTUuNTQ2MTM1IgogICAgICAgICAgICAgICAgIHk9IjcwLjA4MDQyOSI+RGF0YSBTb3VyY2U8L3RzcGFuPjwvdGV4dD48ZwogICAgICAgICAgICAgICBpZD0iZzU3ODQiPjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYxIgogICAgICAgICAgICAgICAgIHg9IjU3LjM4NDQ5MSIKICAgICAgICAgICAgICAgICB5PSI4NC4wNzY1OTkiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgeD0iNTcuMzg0NDkxIgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMzIiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeT0iODQuMDc2NTk5Ij5TYW1wbGVzPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtNjEtMCIKICAgICAgICAgICAgICAgICB4PSI1Ny4zNzA5MTEiCiAgICAgICAgICAgICAgICAgeT0iOTAuNDc0MTUyIj48dHNwYW4KICAgICAgICAgICAgICAgICAgIHg9IjU3LjM3MDkxMSIKICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTMyLTUiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeT0iOTAuNDc0MTUyIj5TYW1wbGVzPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtNjEtNSIKICAgICAgICAgICAgICAgICB4PSI1OC41MDY0MTYiCiAgICAgICAgICAgICAgICAgeT0iOTYuOTY0MzYzIj48dHNwYW4KICAgICAgICAgICAgICAgICAgIHg9IjU4LjUwNjQxNiIKICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTMyLTEiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeT0iOTYuOTY0MzYzIj5TZXJpZXM8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgIGlkPSJ0ZXh0MjQyMS02MS01LTQiCiAgICAgICAgICAgICAgICAgeD0iNTguNTA2NDE2IgogICAgICAgICAgICAgICAgIHk9IjEwMy4xNDYxNiI+PHRzcGFuCiAgICAgICAgICAgICAgICAgICB4PSI1OC41MDY0MTYiCiAgICAgICAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS0zMi0xLTYiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeT0iMTAzLjE0NjE2Ij5TZXJpZXM8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgIGlkPSJ0ZXh0MjQyMS02MS03IgogICAgICAgICAgICAgICAgIHg9IjYwLjUyMTc2NyIKICAgICAgICAgICAgICAgICB5PSIxMDkuMjI1MjMiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgeD0iNjAuNTIxNzY3IgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMzItNCIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB5PSIxMDkuMjI1MjMiPmFsbDwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYxLTctMyIKICAgICAgICAgICAgICAgICB4PSI2MC41MjE3NjciCiAgICAgICAgICAgICAgICAgeT0iMTE1LjU0MDk2Ij48dHNwYW4KICAgICAgICAgICAgICAgICAgIHg9IjYwLjUyMTc2NyIKICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTMyLTQtMSIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB5PSIxMTUuNTQwOTYiPmFsbDwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYxLTAyIgogICAgICAgICAgICAgICAgIHg9IjU3LjM4NDQ5MSIKICAgICAgICAgICAgICAgICB5PSI3NC42Mzg4NTUiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgeD0iNTcuMzg0NDkxIgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMzItOSIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB5PSI3NC42Mzg4NTUiPlNhbXBsZXM8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgIGlkPSJ0ZXh0MjQyMS02MS00IgogICAgICAgICAgICAgICAgIHg9IjU3LjM4NDQ5MSIKICAgICAgICAgICAgICAgICB5PSI3OC45NTMwNjQiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgeD0iNTcuMzg0NDkxIgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMzItMyIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB5PSI3OC45NTMwNjQiPlNhbXBsZXM8L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnCiAgICAgICAgICAgICBpZD0iZzU4MjciCiAgICAgICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC4yNDg1MzA5NykiPjx0ZXh0CiAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTEtMiIKICAgICAgICAgICAgICAgeD0iNzAuODAwMDQ5IgogICAgICAgICAgICAgICB5PSI3MC4wODE0ODIiPjx0c3BhbgogICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS01LTIiCiAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICB4PSI3MC44MDAwNDkiCiAgICAgICAgICAgICAgICAgeT0iNzAuMDgxNDgyIj5NZXRhZGF0YTwvdHNwYW4+PC90ZXh0PjxnCiAgICAgICAgICAgICAgIGlkPSJnNTc2NiI+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtNjAiCiAgICAgICAgICAgICAgICAgeD0iNzAuNDgwNTY4IgogICAgICAgICAgICAgICAgIHk9Ijg0LjI2NDUzNCI+PHRzcGFuCiAgICAgICAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS0yNyIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB4PSI3MC40ODA1NjgiCiAgICAgICAgICAgICAgICAgICB5PSI4NC4yNjQ1MzQiPlByb2Nlc3NlZDwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYwLTIiCiAgICAgICAgICAgICAgICAgeD0iNzAuNDgwNTY4IgogICAgICAgICAgICAgICAgIHk9IjkwLjY2MjA4NiI+PHRzcGFuCiAgICAgICAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS0yNy04IgogICAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICAgIHg9IjcwLjQ4MDU2OCIKICAgICAgICAgICAgICAgICAgIHk9IjkwLjY2MjA4NiI+UHJvY2Vzc2VkPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtNjAtOCIKICAgICAgICAgICAgICAgICB4PSI3MC40ODA1NjgiCiAgICAgICAgICAgICAgICAgeT0iOTYuOTUxNzU5Ij48dHNwYW4KICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTI3LTkiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeD0iNzAuNDgwNTY4IgogICAgICAgICAgICAgICAgICAgeT0iOTYuOTUxNzU5Ij5Qcm9jZXNzZWQ8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgIGlkPSJ0ZXh0MjQyMS02MC0yOCIKICAgICAgICAgICAgICAgICB4PSI3MC40ODA1NjgiCiAgICAgICAgICAgICAgICAgeT0iMTAzLjEzMzU2Ij48dHNwYW4KICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTI3LTg4IgogICAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICAgIHg9IjcwLjQ4MDU2OCIKICAgICAgICAgICAgICAgICAgIHk9IjEwMy4xMzM1NiI+UHJvY2Vzc2VkPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtNjAtNiIKICAgICAgICAgICAgICAgICB4PSI3MC40ODA1NjgiCiAgICAgICAgICAgICAgICAgeT0iMTA5LjIyNTIzIj48dHNwYW4KICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTI3LTgzIgogICAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICAgIHg9IjcwLjQ4MDU2OCIKICAgICAgICAgICAgICAgICAgIHk9IjEwOS4yMjUyMyI+UHJvY2Vzc2VkPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtNjAtODMiCiAgICAgICAgICAgICAgICAgeD0iNzAuNDgwNTY4IgogICAgICAgICAgICAgICAgIHk9IjExNS41NDA5NiI+PHRzcGFuCiAgICAgICAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS0yNy0zIgogICAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICAgIHg9IjcwLjQ4MDU2OCIKICAgICAgICAgICAgICAgICAgIHk9IjExNS41NDA5NiI+UHJvY2Vzc2VkPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtODItMyIKICAgICAgICAgICAgICAgICB4PSI3My4zMzg0NzgiCiAgICAgICAgICAgICAgICAgeT0iNzQuODI2NzkiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktOTktOCIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB4PSI3My4zMzg0NzgiCiAgICAgICAgICAgICAgICAgICB5PSI3NC44MjY3OSI+UmF3PC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtODItMCIKICAgICAgICAgICAgICAgICB4PSI3My4zMzg0NzgiCiAgICAgICAgICAgICAgICAgeT0iNzkuMTQwOTk5Ij48dHNwYW4KICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTk5LTQiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeD0iNzMuMzM4NDc4IgogICAgICAgICAgICAgICAgICAgeT0iNzkuMTQwOTk5Ij5SYXc8L3RzcGFuPjwvdGV4dD48L2c+PC9nPjxnCiAgICAgICAgICAgICBpZD0iZzU4NDgiPjx0ZXh0CiAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTEtNiIKICAgICAgICAgICAgICAgeD0iODUuODM1MDYiCiAgICAgICAgICAgICAgIHk9IjcwLjA4MTQ4MiI+PHRzcGFuCiAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTUtNDEiCiAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICB4PSI4NS44MzUwNiIKICAgICAgICAgICAgICAgICB5PSI3MC4wODE0ODIiPkRhdGE8L3RzcGFuPjwvdGV4dD48ZwogICAgICAgICAgICAgICBpZD0iZzU3NDgiPjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYwLTItNyIKICAgICAgICAgICAgICAgICB4PSI4My4wNTg1MSIKICAgICAgICAgICAgICAgICB5PSI5MC42NjIwODYiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjctOC02IgogICAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICAgIHg9IjgzLjA1ODUxIgogICAgICAgICAgICAgICAgICAgeT0iOTAuNjYyMDg2Ij5Qcm9jZXNzZWQ8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgIGlkPSJ0ZXh0MjQyMS02MC02LTgiCiAgICAgICAgICAgICAgICAgeD0iODMuMDU4NTEiCiAgICAgICAgICAgICAgICAgeT0iMTE1LjU0MDk2Ij48dHNwYW4KICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTI3LTgzLTkiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeD0iODMuMDU4NTEiCiAgICAgICAgICAgICAgICAgICB5PSIxMTUuNTQwOTYiPlByb2Nlc3NlZDwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYwLTYtMCIKICAgICAgICAgICAgICAgICB4PSI4My4wNTg1MSIKICAgICAgICAgICAgICAgICB5PSIxMDMuMTMzNTYiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjctODMtNiIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB4PSI4My4wNTg1MSIKICAgICAgICAgICAgICAgICAgIHk9IjEwMy4xMzM1NiI+UHJvY2Vzc2VkPC90c3Bhbj48L3RleHQ+PHRleHQKICAgICAgICAgICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXNpemU6Mi4xNTAyNnB4O2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWxNVDt3cml0aW5nLW1vZGU6bHItdGI7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICBpZD0idGV4dDI0MjEtNjAtNi04NyIKICAgICAgICAgICAgICAgICB4PSI4NS41MzU4MiIKICAgICAgICAgICAgICAgICB5PSI4NC4yNjQ1MzQiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjctODMtOTAiCiAgICAgICAgICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgICAgeD0iODUuNTM1ODIiCiAgICAgICAgICAgICAgICAgICB5PSI4NC4yNjQ1MzQiPk5vbmU8L3RzcGFuPjwvdGV4dD48dGV4dAogICAgICAgICAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc2l6ZToyLjE1MDI2cHg7Zm9udC1mYW1pbHk6QXJpYWw7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpBcmlhbE1UO3dyaXRpbmctbW9kZTpsci10YjtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjAuMTY1NDA1IgogICAgICAgICAgICAgICAgIGlkPSJ0ZXh0MjQyMS02MC02LTg3LTM3IgogICAgICAgICAgICAgICAgIHg9Ijg1LjUzNTgyIgogICAgICAgICAgICAgICAgIHk9Ijk2Ljk1MTc1OSI+PHRzcGFuCiAgICAgICAgICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgICAgICAgICAgaWQ9InRzcGFuMjQxOS0yNy04My05MC0zMiIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB4PSI4NS41MzU4MiIKICAgICAgICAgICAgICAgICAgIHk9Ijk2Ljk1MTc1OSI+Tm9uZTwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYwLTYtODctNiIKICAgICAgICAgICAgICAgICB4PSI4NS41MzU4MiIKICAgICAgICAgICAgICAgICB5PSIxMDkuMjI1MjMiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjctODMtOTAtNSIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB4PSI4NS41MzU4MiIKICAgICAgICAgICAgICAgICAgIHk9IjEwOS4yMjUyMyI+Tm9uZTwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTgyIgogICAgICAgICAgICAgICAgIHg9Ijg1LjkxNjQyIgogICAgICAgICAgICAgICAgIHk9Ijc0LjgyNjc5Ij48dHNwYW4KICAgICAgICAgICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgICAgICAgICBpZD0idHNwYW4yNDE5LTk5IgogICAgICAgICAgICAgICAgICAgc3R5bGU9InN0cm9rZS13aWR0aDowLjE2NTQwNSIKICAgICAgICAgICAgICAgICAgIHg9Ijg1LjkxNjQyIgogICAgICAgICAgICAgICAgICAgeT0iNzQuODI2NzkiPlJhdzwvdHNwYW4+PC90ZXh0Pjx0ZXh0CiAgICAgICAgICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgICAgICAgICBzdHlsZT0iZm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zaXplOjIuMTUwMjZweDtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsTVQ7d3JpdGluZy1tb2RlOmxyLXRiO2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgaWQ9InRleHQyNDIxLTYwLTYtODctMyIKICAgICAgICAgICAgICAgICB4PSI4NS41MzU4MiIKICAgICAgICAgICAgICAgICB5PSI3OS4xNDA5OTkiPjx0c3BhbgogICAgICAgICAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICAgICAgICAgIGlkPSJ0c3BhbjI0MTktMjctODMtOTAtMyIKICAgICAgICAgICAgICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC4xNjU0MDUiCiAgICAgICAgICAgICAgICAgICB4PSI4NS41MzU4MiIKICAgICAgICAgICAgICAgICAgIHk9Ijc5LjE0MDk5OSI+Tm9uZTwvdHNwYW4+PC90ZXh0PjwvZz48L2c+PC9nPjwvZz48cGF0aAogICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjA2ODkzMzY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjAuMzEzNTk1IgogICAgICAgICBkPSJtIDEwLjg3NzY2NCw4MC4yOTYxMDcgODEuOTIwMDE3LDAuMDA2NCIKICAgICAgICAgaWQ9InBhdGgxMTQ2Ny00LTgiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci10eXBlPSJwb2x5bGluZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz48cGF0aAogICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjA2ODkzMzY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjAuMzEzNTk1IgogICAgICAgICBkPSJtIDEwLjg3NzY2NCw3Ni4xMDg0NTIgODEuOTIwMDE3LDAuMDA2NCIKICAgICAgICAgaWQ9InBhdGgxMTQ2Ny00LTciCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci10eXBlPSJwb2x5bGluZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz48L2c+PC9nPjxzdHlsZQogICAgIGlkPSJzdHlsZTExNzE4IgogICAgIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1taXRlcmxpbWl0OjEwO30KCS5zdDF7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9Cgkuc3Qye2ZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5OjIsMjt9Cgkuc3Qze2ZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MTA7fQoJLnN0NHtmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6MTA7fQoJLnN0NXtmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVqb2luOmJldmVsO3N0cm9rZS1taXRlcmxpbWl0OjEwO30KCS5zdDZ7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5OjIsMjt9Cgkuc3Q3e2ZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5OjIsMzt9Cjwvc3R5bGU+PHN0eWxlCiAgICAgaWQ9InN0eWxlNCIKICAgICB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2NsaXAtcGF0aDp1cmwoI3gpO30KCS5zdDF7b3BhY2l0eTowLjU0O2NsaXAtcGF0aDp1cmwoI3cpO30KCS5zdDJ7Y2xpcC1wYXRoOnVybCgjdik7fQoJLnN0M3tvcGFjaXR5OjAuNTQ7Y2xpcC1wYXRoOnVybCgjdSk7fQoJLnN0NHtjbGlwLXBhdGg6dXJsKCN0KTt9Cgkuc3Q1e29wYWNpdHk6MC41NDtjbGlwLXBhdGg6dXJsKCNzKTt9Cgkuc3Q2e2NsaXAtcGF0aDp1cmwoI3IpO30KCS5zdDd7b3BhY2l0eTowLjU0O2NsaXAtcGF0aDp1cmwoI3EpO30KCS5zdDh7Y2xpcC1wYXRoOnVybCgjcCk7fQoJLnN0OXtvcGFjaXR5OjAuNTQ7Y2xpcC1wYXRoOnVybCgjbyk7fQoJLnN0MTB7Y2xpcC1wYXRoOnVybCgjbik7fQoJLnN0MTF7b3BhY2l0eTowLjU0O2NsaXAtcGF0aDp1cmwoI20pO30KPC9zdHlsZT48c3R5bGUKICAgICBpZD0ic3R5bGU5MTI4IgogICAgIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojMDAwMDAwO30KCS5zdDF7ZmlsbDojMDAwMDAwO30KPC9zdHlsZT48L3N2Zz4K" + ] + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![arguments_outputs.svg](attachment:arguments_outputs.svg)" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/docs_jupyter/python-usage.ipynb b/docs_jupyter/python-usage.ipynb new file mode 100644 index 0000000..d295392 --- /dev/null +++ b/docs_jupyter/python-usage.ipynb @@ -0,0 +1,725 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "67fc2596", + "metadata": {}, + "source": [ + "# Tutorial of usage geofetch as python package" + ] + }, + { + "cell_type": "markdown", + "id": "3ced4b1e", + "metadata": {}, + "source": [ + "♪♫*•♪♪♫*•♪♪♫*•♪♪♫*•♪♪♫*" + ] + }, + { + "cell_type": "markdown", + "id": "0093b8ef", + "metadata": {}, + "source": [ + "Geofetch provides python fuctions to fetch metadata and metadata from GEO and SRA by using python language. `get_project` function returns dictionary of peppy projects that were found using filters and input you specified.\n", + " peppy is a Python package that provides an API for handling standardized project and sample metadata. \n", + " \n", + "More information you can get here:\n", + " \n", + "http://peppy.databio.org/en/latest/\n", + "\n", + "http://pep.databio.org/en/2.0.0/" + ] + }, + { + "cell_type": "markdown", + "id": "64746e18", + "metadata": {}, + "source": [ + "### First let's import geofetch" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "60b65668", + "metadata": {}, + "outputs": [], + "source": [ + "from geofetch import Geofetcher" + ] + }, + { + "cell_type": "markdown", + "id": "b6edbdd7", + "metadata": {}, + "source": [ + "### Initiate Geofetch object by specifing parameters that you want to use for downloading metadata/data" + ] + }, + { + "cell_type": "markdown", + "id": "dc107c16", + "metadata": {}, + "source": [ + "1) If you won't specify any parameters, defaul parameters will be used" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "af268078", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Metadata folder: /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name\n" + ] + } + ], + "source": [ + "geof = Geofetcher()" + ] + }, + { + "cell_type": "markdown", + "id": "1916922e", + "metadata": {}, + "source": [ + "2) To download processed data with samples and series specify this two arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d451856a", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Metadata folder: /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name\n" + ] + } + ], + "source": [ + "geof = Geofetcher(processed=True, data_source=\"all\")" + ] + }, + { + "cell_type": "markdown", + "id": "8debdd11", + "metadata": {}, + "source": [ + "3) To tune project parameter, where metadata should be stored use next parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "f8edb462", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Metadata folder: /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name\n" + ] + } + ], + "source": [ + "geof = Geofetcher(processed=True, data_source=\"all\", const_limit_project = 20, const_limit_discard = 500, attr_limit_truncate = 10000 )" + ] + }, + { + "cell_type": "markdown", + "id": "d2739b13", + "metadata": {}, + "source": [ + "4) To add more filter of other options see documentation" + ] + }, + { + "cell_type": "markdown", + "id": "00b66d4a", + "metadata": {}, + "source": [ + "## Run Geofetch" + ] + }, + { + "cell_type": "markdown", + "id": "5e6c5df8", + "metadata": {}, + "source": [ + "### By default: \n", + "1) No actual data will be downloaded (just_metadata=True)\n", + "\n", + "2) No soft files will be saved on the disc (discard_soft=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "12d70387", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Trying GSE95654 (not a file) as accession...\n", + "Trying GSE95654 (not a file) as accession...\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ca09a8e58d97432fa8313cf788e78430", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Skipped 0 accessions. Starting now.\n", + "\u001b[38;5;200mProcessing accession 1 of 1: 'GSE95654'\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "Total number of processed SAMPLES files found is: 40\n", + "Total number of processed SERIES files found is: 0\n", + "Expanding metadata list...\n", + "Expanding metadata list...\n" + ] + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Finished processing 1 accession(s)\n", + "Cleaning soft files ...\n", + "Unifying and saving of metadata... \n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d6a43f81689c446b8b38a57f2ee5f38f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d54492fe1ca547ff9b0c839a5d2f30f1", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n",
+       "
\n" + ], + "text/plain": [ + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "No files found. No data to save. File /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name/_series/_series.csv won't be created\n" + ] + } + ], + "source": [ + "projects = geof.get_project(\"GSE95654\")" + ] + }, + { + "cell_type": "markdown", + "id": "bc198009", + "metadata": {}, + "source": [ + "Check if projects were created by checking dict keys:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "95896f25", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['_samples'])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "projects.keys()" + ] + }, + { + "cell_type": "markdown", + "id": "4e27f971", + "metadata": {}, + "source": [ + "project for smaples was created! Now let's look into it." + ] + }, + { + "cell_type": "markdown", + "id": "fa2d0bda", + "metadata": {}, + "source": [ + "\\* the values of the dictionary are peppy projects. More information about peppy Project you can find in the documentation: http://peppy.databio.org/en/latest/" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "e8642711", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "40" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(projects['_samples'].samples)" + ] + }, + { + "cell_type": "markdown", + "id": "a4d50082", + "metadata": {}, + "source": [ + "We got 40 samples from GSE95654 project. If you want to check if it's correct information go into: https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE95654" + ] + }, + { + "cell_type": "markdown", + "id": "d0cd958a", + "metadata": {}, + "source": [ + "Now let's see actuall data. first 15 project and 5 clolumns:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "ba7be762", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sample_organism_ch1sample_channel_countsample_contact_namesample_library_sourcegenome_build
sample_name
RRBS_on_CRC_patient_8Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_adjacent_normal_colon_patient_8Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_CRC_patient_32Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_adjacent_normal_colon_patient_32Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_CRC_patient_41Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_adjacent_normal_colon_patient_41Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_CRC_patient_42Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_adjacent_normal_colon_patient_42Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_ACF_patient_173Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_ACF_patient_515Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_normal_crypts_patient_139Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_ACF_patient_143Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_normal_crypts_patient_143Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_normal_crypts_patient_165Homo sapiens1Xiwei,,Wugenomichg19
RRBS_on_ACF_patient_165Homo sapiens1Xiwei,,Wugenomichg19
\n", + "
" + ], + "text/plain": [ + " sample_organism_ch1 \\\n", + "sample_name \n", + "RRBS_on_CRC_patient_8 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_8 Homo sapiens \n", + "RRBS_on_CRC_patient_32 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_32 Homo sapiens \n", + "RRBS_on_CRC_patient_41 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_41 Homo sapiens \n", + "RRBS_on_CRC_patient_42 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_42 Homo sapiens \n", + "RRBS_on_ACF_patient_173 Homo sapiens \n", + "RRBS_on_ACF_patient_515 Homo sapiens \n", + "RRBS_on_normal_crypts_patient_139 Homo sapiens \n", + "RRBS_on_ACF_patient_143 Homo sapiens \n", + "RRBS_on_normal_crypts_patient_143 Homo sapiens \n", + "RRBS_on_normal_crypts_patient_165 Homo sapiens \n", + "RRBS_on_ACF_patient_165 Homo sapiens \n", + "\n", + " sample_channel_count \\\n", + "sample_name \n", + "RRBS_on_CRC_patient_8 1 \n", + "RRBS_on_adjacent_normal_colon_patient_8 1 \n", + "RRBS_on_CRC_patient_32 1 \n", + "RRBS_on_adjacent_normal_colon_patient_32 1 \n", + "RRBS_on_CRC_patient_41 1 \n", + "RRBS_on_adjacent_normal_colon_patient_41 1 \n", + "RRBS_on_CRC_patient_42 1 \n", + "RRBS_on_adjacent_normal_colon_patient_42 1 \n", + "RRBS_on_ACF_patient_173 1 \n", + "RRBS_on_ACF_patient_515 1 \n", + "RRBS_on_normal_crypts_patient_139 1 \n", + "RRBS_on_ACF_patient_143 1 \n", + "RRBS_on_normal_crypts_patient_143 1 \n", + "RRBS_on_normal_crypts_patient_165 1 \n", + "RRBS_on_ACF_patient_165 1 \n", + "\n", + " sample_contact_name \\\n", + "sample_name \n", + "RRBS_on_CRC_patient_8 Xiwei,,Wu \n", + "RRBS_on_adjacent_normal_colon_patient_8 Xiwei,,Wu \n", + "RRBS_on_CRC_patient_32 Xiwei,,Wu \n", + "RRBS_on_adjacent_normal_colon_patient_32 Xiwei,,Wu \n", + "RRBS_on_CRC_patient_41 Xiwei,,Wu \n", + "RRBS_on_adjacent_normal_colon_patient_41 Xiwei,,Wu \n", + "RRBS_on_CRC_patient_42 Xiwei,,Wu \n", + "RRBS_on_adjacent_normal_colon_patient_42 Xiwei,,Wu \n", + "RRBS_on_ACF_patient_173 Xiwei,,Wu \n", + "RRBS_on_ACF_patient_515 Xiwei,,Wu \n", + "RRBS_on_normal_crypts_patient_139 Xiwei,,Wu \n", + "RRBS_on_ACF_patient_143 Xiwei,,Wu \n", + "RRBS_on_normal_crypts_patient_143 Xiwei,,Wu \n", + "RRBS_on_normal_crypts_patient_165 Xiwei,,Wu \n", + "RRBS_on_ACF_patient_165 Xiwei,,Wu \n", + "\n", + " sample_library_source genome_build \n", + "sample_name \n", + "RRBS_on_CRC_patient_8 genomic hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_8 genomic hg19 \n", + "RRBS_on_CRC_patient_32 genomic hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_32 genomic hg19 \n", + "RRBS_on_CRC_patient_41 genomic hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_41 genomic hg19 \n", + "RRBS_on_CRC_patient_42 genomic hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_42 genomic hg19 \n", + "RRBS_on_ACF_patient_173 genomic hg19 \n", + "RRBS_on_ACF_patient_515 genomic hg19 \n", + "RRBS_on_normal_crypts_patient_139 genomic hg19 \n", + "RRBS_on_ACF_patient_143 genomic hg19 \n", + "RRBS_on_normal_crypts_patient_143 genomic hg19 \n", + "RRBS_on_normal_crypts_patient_165 genomic hg19 \n", + "RRBS_on_ACF_patient_165 genomic hg19 " + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "projects['_samples'].sample_table.iloc[:15 , :5]" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index d7a3679..a1aabdc 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -2418,11 +2418,6 @@ def _parse_cmdl(cmdl): action="store_true", help="Use just the keys defined in this module when writing out metadata.", ) - raw_group.add_argument( - "--bam-conversion", - action="store_true", - help="specify this argument to convert bam files", - ) logmuse.add_logging_options(parser) return parser.parse_args(cmdl) diff --git a/mkdocs.yml b/mkdocs.yml index c6c6549..0d84ac9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,8 +9,10 @@ nav: - Introduction: README.md - Install and configure: install.md - SRA convert: sra_convert.md + - Tutorials: - Tutorial for processed data: processed-data-downloading.md - Tutorial for raw data: raw-data-downloading.md + - Python geofetch tutorial: python-usage.md - How-to Guides: - Specifying samples to download: file-specification.md - Set SRA data download location: howto-location.md From deaa72a6444f001c28f9687c1b527e01bfccb96b Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 6 Sep 2022 17:37:49 -0400 Subject: [PATCH 35/61] Added additional documentation --- docs/changelog.md | 2 +- docs/how_to_get_gse.md | 6 ++++ docs/metadata_output.md | 55 ++++++++++++++++++++----------- requirements/requirements-all.txt | 1 + 4 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 docs/how_to_get_gse.md diff --git a/docs/changelog.md b/docs/changelog.md index 23c3729..56bc55a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,7 +1,7 @@ # Changelog ## [0.11.0] -- 2022-09-06 -- Added initialization of peppy Project without saving any files functionality +- Added initialization of peppy Project without saving any files - Added progress bar - Fixed None issue in config file - Switched way of saving soft files to request library diff --git a/docs/how_to_get_gse.md b/docs/how_to_get_gse.md new file mode 100644 index 0000000..b497f89 --- /dev/null +++ b/docs/how_to_get_gse.md @@ -0,0 +1,6 @@ +# How to find and get list of files of GSEs + +There is two options: +1) You can create your own file with GSE numbers that you want to download using geofetch +2) Use [gse_finder](https://github.com/pepkit/gse_finder) - Python package that enables get list +of GSEs in certain period of time and at the same time use NCBI filters \ No newline at end of file diff --git a/docs/metadata_output.md b/docs/metadata_output.md index e9f5fde..5763b2f 100644 --- a/docs/metadata_output.md +++ b/docs/metadata_output.md @@ -1,29 +1,46 @@ # Metadata output Geofetch produces [PEPs](http://pep.databio.org/) for either processed or raw data (including metadata from SRA). +A project can be created either for a single combined (whole) input or for each project separately. +(if `--acc-anno` is set). "combined" means that it will have rows for every sample in every GSE included +in your input. So if you just gave a single GSE, then the combined file is the same as the GSE file. -# Outdated: +**For raw data**: a metadata file will be created including SRA and GSM annotation. -For each GSE input accession (ACC), `geofetch` produces (if discard-soft is not set): +**For processed data**: a metadata file will be created just for GSE and GSM annotation. User +can choose which data should he download. There are 3 downloading options for processed: samples, series and both. + +### Single PEP will contain: +- project_name.csv - all metadata for sample processed data +- project_name_subannotation.csv (*just for raw data*) - for *merged* samples +(samples for which there are multiple SRR Runs for a single SRX `Experiment`) +- project_name.yaml - project config file that stores all project information + common samples metadata + +Storing common metadata in project file is an efficient way to reduce project size and complexity of csv files. +To specify and manage common metadata (where and how it should be stored) you can use next arguments: +`--const-limit-project`, `--const-limit-discard`, `--attr-limit-truncate` + +### Saving actual data: +Actual data will be saved if `--just-metadata` argument is not set. User should specify path to the folder where this +data should be downloaded. + +---- +Additionally, for each GSE input accession (ACC), `geofetch` produces (if discard-soft is not set): - GSE_ACC####.soft a SOFT file (annotating the experiment itself) - GSM_ACC####.soft a SOFT file (annotating the samples within the experiment) - SRA_ACC####.soft a CSV file (annotating each SRA Run, retrieved from GSE->GSM->SRA) -For raw data: -a single combined metadata file (.csv) will be created for the whole input, -including SRA and GSM annotations for each sample. Here, "combined" means that it will have -rows for every sample in every GSE included in your input. So if you just gave a single GSE, -then the combined file is the same as the GSE file. If any "merged" samples exist -(samples for which there are multiple SRR Runs for a single SRX `Experiment`), the -script will also produce a merge table CSV file with the relationships between -SRX and SRR. - -The way this works: Starting from a GSE, select a subset of samples (GSM Accessions) provided, -and then obtain the SRX identifier for each of these from GEO. Now, query SRA for these SRX -accessions and get any associated SRR accessions. Finally, download all of these SRR data files. - -### The most important metadata in pep format will be stored in -- NAME_annotation_sample_processed.csv - all metadata for sample processed data -- NAME_annotation.csv - all metadata for series processed data -- NAME_annotation_series_processed.csv file - all metadata for raw data +____ +# geofetch - Geofetcher using Python + +user can use geofetch in Python without saving any files. All the geofetch projects will be automatically downloaded +as peppy Project. It helps save time and processing work. + +THe output in this case will be dictionary of projects: +```python +{'key1': (some_project), + 'key2': (second_project)} +``` + +More information you can find in tutorial files. \ No newline at end of file diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index a916a7b..1eebcb5 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -10,3 +10,4 @@ xmltodict>=0.13.0 pandas>=1.3.5 peppy>=0.35.0 rich>=12.5.1 +coloredlogs>=15.0.1 From 2f447bd66658d280c153992a7ebd39e0fd76f9a1 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 6 Sep 2022 17:45:33 -0400 Subject: [PATCH 36/61] Added additional documentation2 --- docs/how_to_get_gse.md | 4 +++- mkdocs.yml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/how_to_get_gse.md b/docs/how_to_get_gse.md index b497f89..2e7f30a 100644 --- a/docs/how_to_get_gse.md +++ b/docs/how_to_get_gse.md @@ -1,6 +1,8 @@ # How to find and get list of files of GSEs -There is two options: +### There is two options: + 1) You can create your own file with GSE numbers that you want to download using geofetch + 2) Use [gse_finder](https://github.com/pepkit/gse_finder) - Python package that enables get list of GSEs in certain period of time and at the same time use NCBI filters \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 0d84ac9..c72d2f0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,6 +16,7 @@ nav: - How-to Guides: - Specifying samples to download: file-specification.md - Set SRA data download location: howto-location.md + - Download list of GSEs: how_to_get_gse.md - Reference: - Metadata output: metadata_output.md - Usage: usage.md From a9536851a5d31f2273c58c9929354611c2e4f186 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 7 Sep 2022 16:19:06 -0400 Subject: [PATCH 37/61] Change naming of PEPs and function --- docs/README.md | 3 ++- geofetch/geofetch.py | 15 +++++++++++---- tests/test_geofetch.py | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2f21910..19e4f98 100644 --- a/docs/README.md +++ b/docs/README.md @@ -46,6 +46,7 @@ geofetch -i GSE95654 --processed --just-metadata ### New geofetch 0.11.0 feature: - Now geofetch is available as Python package to straight initiate [peppy](http://peppy.databio.org/) projects without downloading any soft files. + ```python from geofetch import Geofetcher @@ -53,7 +54,7 @@ from geofetch import Geofetcher geof = Geofetcher(processed=True, acc_anno=True, discard_soft=True) # get projects by providing as input GSE or file with GSEs -geof.get_project("GSE160204") +geof.get_projects("GSE160204") ``` For more details, check out the [usage](usage.md) reference, [installation instructions](install.md), or head on over to the [tutorial for raw data](raw-data-downloading.md) and [tutorial for processed data](processed-data-downloading.md) for a detailed walkthrough. diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index a1aabdc..7fc44e0 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -240,7 +240,7 @@ def __init__( self.just_object = False - def get_project( + def get_projects( self, input: str, just_metadata: bool = True, discard_soft: bool = True ) -> dict: """ @@ -273,7 +273,11 @@ def get_project( ) project_dict.update(self.fetch_all(input=acc_GSE, name=acc_GSE)) else: - project_dict.update(self.fetch_all(input=input, name="")) + try: + project_n = os.path.splitext(os.path.basename(input))[0] + except TypeError: + project_n = input + project_dict.update(self.fetch_all(input=input, name=project_n)) # raw data: else: @@ -292,8 +296,12 @@ def get_project( project_dict[acc_GSE + "_raw"] = project else: + try: + project_n = os.path.splitext(os.path.basename(input))[0] + except TypeError: + project_n = input ser_dict = self.fetch_all(input=input) - project_dict["raw"] = ser_dict + project_dict[project_n + "_raw"] = ser_dict new_pr_dict = {} for pr_key in project_dict.keys(): @@ -307,7 +315,6 @@ def fetch_all(self, input: str, name: str = None): if name is not None: self.project_name = name - print(self.project_name) else: try: self.project_name = os.path.splitext(os.path.basename(input))[0] diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index da9f788..efc052b 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -314,12 +314,12 @@ def initiate_geofetcher(self, tmpdir): yield instance def test_creating_processed_peppy(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_project("GSE190287") + p_prop = initiate_geofetcher.get_projects("GSE190287") assert isinstance(p_prop["_samples"], peppy.Project) assert isinstance(p_prop["_series"], peppy.Project) def test_number_of_samples(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_project("GSE190287") + p_prop = initiate_geofetcher.get_projects("GSE190287") assert len(p_prop["_samples"].samples) == 8 # it has 11 files but 8 samples assert len(p_prop["_series"].samples) == 2 @@ -341,11 +341,11 @@ def initiate_geofetcher(self, tmpdir): yield instance def test_creating_processed_peppy(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_project("GSE189141") + p_prop = initiate_geofetcher.get_projects("GSE189141") assert isinstance(p_prop["raw"], peppy.Project) def test_number_of_samples(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_project("GSE189141") + p_prop = initiate_geofetcher.get_projects("GSE189141") a = [d["sample_name"] for d in p_prop["raw"].samples] assert len(p_prop["raw"].samples) == 16 # it has 16 samples From 34a3a3c4fef9e6a230e03b195fe545935e47bd4e Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 7 Sep 2022 16:23:49 -0400 Subject: [PATCH 38/61] black + tests --- tests/test_geofetch.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/test_geofetch.py b/tests/test_geofetch.py index efc052b..ad8c923 100644 --- a/tests/test_geofetch.py +++ b/tests/test_geofetch.py @@ -314,14 +314,18 @@ def initiate_geofetcher(self, tmpdir): yield instance def test_creating_processed_peppy(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_projects("GSE190287") - assert isinstance(p_prop["_samples"], peppy.Project) - assert isinstance(p_prop["_series"], peppy.Project) + gse_numb = "GSE190287" + p_prop = initiate_geofetcher.get_projects(gse_numb) + assert isinstance(p_prop[f"{gse_numb}_samples"], peppy.Project) + assert isinstance(p_prop[f"{gse_numb}_series"], peppy.Project) def test_number_of_samples(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_projects("GSE190287") - assert len(p_prop["_samples"].samples) == 8 # it has 11 files but 8 samples - assert len(p_prop["_series"].samples) == 2 + gse_numb = "GSE190287" + p_prop = initiate_geofetcher.get_projects(gse_numb) + assert ( + len(p_prop[f"{gse_numb}_samples"].samples) == 8 + ) # it has 11 files but 8 samples + assert len(p_prop[f"{gse_numb}_series"].samples) == 2 class TestPeppyInitRaw: @@ -341,13 +345,15 @@ def initiate_geofetcher(self, tmpdir): yield instance def test_creating_processed_peppy(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_projects("GSE189141") - assert isinstance(p_prop["raw"], peppy.Project) + gse_numb = "GSE189141" + p_prop = initiate_geofetcher.get_projects(gse_numb) + assert isinstance(p_prop[f"{gse_numb}_raw"], peppy.Project) def test_number_of_samples(self, initiate_geofetcher): - p_prop = initiate_geofetcher.get_projects("GSE189141") - a = [d["sample_name"] for d in p_prop["raw"].samples] - assert len(p_prop["raw"].samples) == 16 # it has 16 samples + gse_numb = "GSE189141" + p_prop = initiate_geofetcher.get_projects(gse_numb) + a = [d["sample_name"] for d in p_prop[f"{gse_numb}_raw"].samples] + assert len(p_prop[f"{gse_numb}_raw"].samples) == 16 # it has 16 samples def test_clean_func(tmpdir): From ebe586e67a9fa1140c6692ed0bd2c9f90600f008 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 7 Sep 2022 16:43:53 -0400 Subject: [PATCH 39/61] Added Finder to geofetch + documentation + peppy version --- docs/gse_finder.md | 82 +++++++++++++ docs/how_to_get_gse.md | 8 -- geofetch/__init__.py | 1 + geofetch/const.py | 16 +++ geofetch/finder.py | 186 ++++++++++++++++++++++++++++++ mkdocs.yml | 2 +- requirements/requirements-all.txt | 2 +- 7 files changed, 287 insertions(+), 10 deletions(-) create mode 100644 docs/gse_finder.md delete mode 100644 docs/how_to_get_gse.md create mode 100644 geofetch/finder.py diff --git a/docs/gse_finder.md b/docs/gse_finder.md new file mode 100644 index 0000000..dc949ab --- /dev/null +++ b/docs/gse_finder.md @@ -0,0 +1,82 @@ +s a python package that provides functions to find and retrieve a list of GSE ([GEO](https://www.ncbi.nlm.nih.gov/geo/) accession number) by using NCBI searching tool. + + +### The main features of the geofetch Finder are: +- Find GEO accession numbers (GSE) of the project that were uploaded or updated in certain period of time. +- Use the same filter query as [GEO DataSets Advanced Search Builder](https://www.ncbi.nlm.nih.gov/gds/advanced) is using +- Save list of the GSEs to file (This file with geo can be used later in **[geofetch](http://geofetch.databio.org/en/latest/)**) +- Fast execution time +- Easy to use + + +___ +## Tutorial + +0) Initiale Finder object. +```python +from geofetch import Finder +gse_obj = Finder() + +# Optionally: provide filter string and max number of retrieve elements +gse_obj = Finder(filter="((bed) OR narrow peak) AND Homo sapiens[Organism]", retmax=10) +``` + +1) Get list of all GSE in GEO +```python + +gse_list = gse_obj.get_gse_all() + +``` + +2) Get list of GSE that were uploaded and updated last week +```python + +gse_list = gse_obj.get_gse_last_week() + +``` + +3) Get list of GSE that were uploaded and updated last 3 month +```python + +gse_list = gse_obj.get_gse_last_3_month() + +``` + +4) Get list of GSE that were uploaded and updated in las *number of days* +```python + +# project that were uploaded in last 5 days: +gse_list = gse_obj.get_gse_by_day_count(5) + +``` + +5) Get list of GSE that were uploaded in certain period of time +```python + +gse_list = gse_obj.get_gse_by_date(start_date="2015/05/05", end_date="2020/05/05") + +``` + +6) Save last searched list of items to the file +```python + +gse_obj.generate_file("path/to/the/file") + +# if you want to save different list of files you can provide it to the funciton +gse_obj.generate_file("path/to/the/file", gse_list=["123", "124"]) + +``` + +7) Compare two lists: +```python + +new_gse_list = gse_obj.find_differences(list1, list2) + +``` + +---- + +More information about gse and queries and id: +- https://www.ncbi.nlm.nih.gov/geo/info/geo_paccess.html +- https://newarkcaptain.com/how-to-retrieve-ncbi-geo-information-using-apis-part1/ +- https://www.ncbi.nlm.nih.gov/books/NBK3837/#EntrezHelp.Using_the_Advanced_Search_Pag \ No newline at end of file diff --git a/docs/how_to_get_gse.md b/docs/how_to_get_gse.md deleted file mode 100644 index 2e7f30a..0000000 --- a/docs/how_to_get_gse.md +++ /dev/null @@ -1,8 +0,0 @@ -# How to find and get list of files of GSEs - -### There is two options: - -1) You can create your own file with GSE numbers that you want to download using geofetch - -2) Use [gse_finder](https://github.com/pepkit/gse_finder) - Python package that enables get list -of GSEs in certain period of time and at the same time use NCBI filters \ No newline at end of file diff --git a/geofetch/__init__.py b/geofetch/__init__.py index 003168a..ef3887f 100644 --- a/geofetch/__init__.py +++ b/geofetch/__init__.py @@ -1,5 +1,6 @@ """ Package-level data """ from .geofetch import * +from .finder import * from ._version import __version__ import logmuse diff --git a/geofetch/const.py b/geofetch/const.py index 566aeac..91669c3 100644 --- a/geofetch/const.py +++ b/geofetch/const.py @@ -46,3 +46,19 @@ CONFIG_PROCESSED_TEMPLATE_NAME = "config_processed_template.yaml" CONFIG_RAW_TEMPLATE_NAME = "config_template.yaml" + +# const for Finder: +RETMAX = 10000000 # once it should be increased + +# gds = geo DataSets +ETOOLS_GEO_BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=gds" +ETOOLS_GEO_GSE_BASE = f"{ETOOLS_GEO_BASE}&term=GSE[ETYP]" + +ETOOLS_ENDING = "&retmax={retmax}&usehistory=y" + +TODAY_DATE = "3000" + +DATE_FILTER = ( + '+AND+("{start_date}"[Publication%20Date]%20:%20"{end_date}"[Publication%20Date])' +) +THREE_MONTH_FILTER = '+AND+"published+last+3+months"[Filter]' diff --git a/geofetch/finder.py b/geofetch/finder.py new file mode 100644 index 0000000..eeb105b --- /dev/null +++ b/geofetch/finder.py @@ -0,0 +1,186 @@ +from .const import ( + RETMAX, + ETOOLS_GEO_GSE_BASE, + ETOOLS_ENDING, + TODAY_DATE, + DATE_FILTER, + THREE_MONTH_FILTER, +) +import requests +import xmltodict +import re +import os +import logmuse +import coloredlogs +from datetime import datetime +from datetime import timedelta + +__author__ = "Oleksandr Khoroshevskyi" + +_LOGGER = logmuse.init_logger("pepannot") +coloredlogs.install( + logger=_LOGGER, + datefmt="%H:%M:%S", + fmt="[%(levelname)s] [%(asctime)s] %(message)s", +) + + +class Finder: + """ + Class for finding GSE accessions in special period of time + Additionally user can add specific filters for the search. + """ + + def __init__(self, filters: str = None, retmax: int = RETMAX): + """ + :param filters: filters that have to be added to query. + Filter Patterns can be found here: + https://www.ncbi.nlm.nih.gov/books/NBK3837/#EntrezHelp.Using_the_Advanced_Search_Pag + :param retmax: maximum items should be retrieved + """ + self.query_customized_ending = ETOOLS_ENDING.format(retmax=retmax) + self.query_filter_str = self._create_filter_str(filters) + self.last_result = [] + + def get_gse_all(self) -> list: + """ + Get list of all gse accession available in GEO + :return: list of gse accession + """ + return self.get_gse_id_by_query(url=self._compose_url()) + + def get_gse_last_3_month(self) -> list: + """ + Get list of gse accession that were uploaded or updated in last 3 month + :return: list of gse accession + """ + return self.get_gse_id_by_query(url=self._compose_url(THREE_MONTH_FILTER)) + + def get_gse_last_week(self) -> list: + """ + Get list of gse accession that were uploaded or updated in last week + :return: list of gse accession + """ + return self.get_gse_by_day_count(7) + + def get_gse_by_day_count(self, n_days: int = 1) -> list: + """ + Get list of gse accession that were uploaded or updated in last specified number of days + :param n_days: number of days from now + :return: list of gse accession + """ + today = datetime.today() + start_date = today - timedelta(days=n_days) + start_date_str = start_date.strftime("%Y/%m/%d") + return self.get_gse_by_date(start_date_str) + + def get_gse_by_date(self, start_date: str, end_date: str = None) -> list: + """ + Search gse accessions by providing start date and end date. By default, the last date is today. + :param start_date: the oldest date of update (from YYYY/MM/DD to now) [input format: 'YYYY/MM/DD'] + :param end_date: the nearest date of update (from __ to YYYY/MM/DD) [input format: 'YYYY/MM/DD'] + :return: list of gse accessions + """ + if end_date is None: + end_date = TODAY_DATE + new_date_filter = DATE_FILTER.format(start_date=start_date, end_date=end_date) + return self.get_gse_id_by_query(url=self._compose_url(new_date_filter)) + + def get_gse_id_by_query(self, url: str) -> list: + """ + Use esearch query to find uids and then convert them to gse ids + :param url: url of the query + :return: list of gse ids + """ + uids_list = self._run_search_query(url) + gse_id_list = [self.uid_to_gse(d) for d in uids_list] + self.last_result = gse_id_list + return gse_id_list + + @staticmethod + def uid_to_gse(uid: str) -> str: + """ + UID to GES accession converter + :param uid: uid string + :return: GSE id string + """ + uid_regex = re.compile(r"[1-9]+0+([1-9]+[0-9]*)") + return "GSE" + uid_regex.match(uid).group(1) + + def read_file(self, file_path: str) -> list: + """ + Getting list of gse's from file by specifying a file path + :param file_path: path to the file + :return: list of gse's + """ + pass + + @staticmethod + def find_differences(old_list: list, new_list: list) -> list: + """ + Comparing 2 lists and searching for elements that are not in old list + :param old_list: old list of elements + :param new_list: new list of elements + :return: list of elements that are not in old list but are in new_list + """ + return list(set(new_list) - set(old_list)) + + @staticmethod + def _run_search_query(url: str) -> list: + """ + Run get request and return list of uids found + :param url: url of the query + :return: list of UIDs + """ + x = requests.get(url) + if x.status_code != 200: + _LOGGER.error(f"Request status != 200. Error. Check your request") + return [] + try: + x_result = xmltodict.parse(x.text)["eSearchResult"] + _LOGGER.info(f"Found elements: {x_result['Count']}") + _LOGGER.info(f"Additional information: {x_result['TranslationSet']}") + + return x_result["IdList"]["Id"] + except Exception: + return [] + + @staticmethod + def _create_filter_str(filters: str = None) -> str: + """ + Tuning filter for url request + :param filters: filter should look like here: https://www.ncbi.nlm.nih.gov/books/NBK3837/#EntrezHelp.Using_the_Advanced_Search_Pag + :return: tuned filter string + """ + if filters == "" or filters is None: + return "" + return f"+(AND+{filters})" + + def _compose_url(self, date_filter: str = None) -> str: + """ + Composing final url by adding date filter + :param date_filter: date filter that has to be used in the query + :return: string of final url + """ + if date_filter is None: + date_filter = "" + + return f"{ETOOLS_GEO_GSE_BASE}{self.query_filter_str}{date_filter}{self.query_customized_ending}" + + def generate_file(self, file_path: str, gse_list: list = None): + """ + Saving list of gse numbers to the file + :param file_path: root to the file where gse accessions have to be saved + :param gse_list: list of gse accessions + :return: NoReturn + """ + if gse_list is None: + gse_list = self.last_result + file_dir = os.path.split(file_path)[0] + if not os.path.exists(file_dir) and file_dir != "": + _LOGGER.error(f"Path: '{file_dir}' does not exist! No file will be saved") + + with open(file_path, "w") as fp: + for item in gse_list: + fp.write("%s\n" % item) + _LOGGER.info("File has been saved!") diff --git a/mkdocs.yml b/mkdocs.yml index c72d2f0..69b5a07 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -13,10 +13,10 @@ nav: - Tutorial for processed data: processed-data-downloading.md - Tutorial for raw data: raw-data-downloading.md - Python geofetch tutorial: python-usage.md + - Use GSE Finder: gse_finder.md - How-to Guides: - Specifying samples to download: file-specification.md - Set SRA data download location: howto-location.md - - Download list of GSEs: how_to_get_gse.md - Reference: - Metadata output: metadata_output.md - Usage: usage.md diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt index 1eebcb5..f3ec919 100644 --- a/requirements/requirements-all.txt +++ b/requirements/requirements-all.txt @@ -8,6 +8,6 @@ ubiquerg>=0.6.0 requests>=2.28.1 xmltodict>=0.13.0 pandas>=1.3.5 -peppy>=0.35.0 +peppy>=0.35.1 rich>=12.5.1 coloredlogs>=15.0.1 From de2a0f1cede1fd66e519089245cb64d5fd435c06 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 8 Sep 2022 11:25:23 -0400 Subject: [PATCH 40/61] added Finder documentation --- docs/README.md | 28 ++- docs/changelog.md | 1 + docs/gse_finder.md | 5 +- docs_jupyter/python-usage.ipynb | 317 +++++++++++++++----------------- 4 files changed, 181 insertions(+), 170 deletions(-) diff --git a/docs/README.md b/docs/README.md index 19e4f98..e0b9c74 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,6 +14,15 @@ ![](./img/pipeline.svg) +Key geofetch advantages: + +- Works with GEO and SRA metadata +- Combines samples from different projects +- Standardizes output metadata +- Filters type and size of processed files (from GEO) before downloading them +- Easy to use +- Fast execution + ## Quick example `geofetch` runs on the command line. This command will download the raw data and metadata for the given GSE number. @@ -44,8 +53,9 @@ geofetch -i GSE95654 --processed --just-metadata ![](./img/arguments_outputs.svg) -### New geofetch 0.11.0 feature: -- Now geofetch is available as Python package to straight initiate [peppy](http://peppy.databio.org/) projects without downloading any soft files. +--- +### New features available in geofetch 0.11.0 : +1) Now geofetch is available as Python package. Geofetch can initialize [peppy](http://peppy.databio.org/) projects without downloading any soft files. Example: ```python from geofetch import Geofetcher @@ -57,5 +67,19 @@ geof = Geofetcher(processed=True, acc_anno=True, discard_soft=True) geof.get_projects("GSE160204") ``` +2) Now to find GSEs and save them to file you can use `Finder` - GSE finder tool: + +```python +from geofetch import Finder + +# initiate Finder (use filters if necessary) +find_gse = Finder(filters='bed') + +# get all projects that were found: +gse_list = find_gse.get_gse_all() +``` +Find more information here: [GSE Finder](./gse_finder.md) + + For more details, check out the [usage](usage.md) reference, [installation instructions](install.md), or head on over to the [tutorial for raw data](raw-data-downloading.md) and [tutorial for processed data](processed-data-downloading.md) for a detailed walkthrough. diff --git a/docs/changelog.md b/docs/changelog.md index 56bc55a..f9c3c57 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,7 @@ ## [0.11.0] -- 2022-09-06 - Added initialization of peppy Project without saving any files +- Added Finder (searching GSE tool) - Added progress bar - Fixed None issue in config file - Switched way of saving soft files to request library diff --git a/docs/gse_finder.md b/docs/gse_finder.md index dc949ab..14a353f 100644 --- a/docs/gse_finder.md +++ b/docs/gse_finder.md @@ -1,12 +1,11 @@ -s a python package that provides functions to find and retrieve a list of GSE ([GEO](https://www.ncbi.nlm.nih.gov/geo/) accession number) by using NCBI searching tool. +is a geofetch class that provides functions to find and retrieve a list of GSE ([GEO](https://www.ncbi.nlm.nih.gov/geo/) accession number) by using NCBI searching tool. ### The main features of the geofetch Finder are: - Find GEO accession numbers (GSE) of the project that were uploaded or updated in certain period of time. - Use the same filter query as [GEO DataSets Advanced Search Builder](https://www.ncbi.nlm.nih.gov/gds/advanced) is using - Save list of the GSEs to file (This file with geo can be used later in **[geofetch](http://geofetch.databio.org/en/latest/)**) -- Fast execution time -- Easy to use +- Easier and faster to get GSEs using NCBI filter and certain period of time. ___ diff --git a/docs_jupyter/python-usage.ipynb b/docs_jupyter/python-usage.ipynb index d295392..9b34736 100644 --- a/docs_jupyter/python-usage.ipynb +++ b/docs_jupyter/python-usage.ipynb @@ -41,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "60b65668", "metadata": {}, "outputs": [], @@ -67,7 +67,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "af268078", "metadata": { "scrolled": false @@ -95,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "id": "d451856a", "metadata": { "scrolled": false @@ -123,7 +123,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "id": "f8edb462", "metadata": { "scrolled": true @@ -170,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 6, "id": "12d70387", "metadata": {}, "outputs": [ @@ -185,7 +185,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ca09a8e58d97432fa8313cf788e78430", + "model_id": "0f96c1a1ee8c48f4af31e0dc939fe116", "version_major": 2, "version_minor": 0 }, @@ -201,20 +201,7 @@ "output_type": "stream", "text": [ "Skipped 0 accessions. Starting now.\n", - "\u001b[38;5;200mProcessing accession 1 of 1: 'GSE95654'\u001b[0m\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ + "\u001b[38;5;200mProcessing accession 1 of 1: 'GSE95654'\u001b[0m\n", "\n", "Total number of processed SAMPLES files found is: 40\n", "Total number of processed SERIES files found is: 0\n", @@ -257,7 +244,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "d6a43f81689c446b8b38a57f2ee5f38f", + "model_id": "b2c4c738728b4b43938fa6e7f29615ef", "version_major": 2, "version_minor": 0 }, @@ -307,7 +294,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "d54492fe1ca547ff9b0c839a5d2f30f1", + "model_id": "02401b3d938a4a588052ba99af677f84", "version_major": 2, "version_minor": 0 }, @@ -358,12 +345,12 @@ "name": "stderr", "output_type": "stream", "text": [ - "No files found. No data to save. File /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name/_series/_series.csv won't be created\n" + "No files found. No data to save. File /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name/GSE95654_series/GSE95654_series.csv won't be created\n" ] } ], "source": [ - "projects = geof.get_project(\"GSE95654\")" + "projects = geof.get_projects(\"GSE95654\")" ] }, { @@ -376,7 +363,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 7, "id": "95896f25", "metadata": { "scrolled": false @@ -385,10 +372,10 @@ { "data": { "text/plain": [ - "dict_keys(['_samples'])" + "dict_keys(['GSE95654_samples'])" ] }, - "execution_count": 10, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -415,7 +402,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 9, "id": "e8642711", "metadata": {}, "outputs": [ @@ -425,13 +412,13 @@ "40" ] }, - "execution_count": 12, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "len(projects['_samples'].samples)" + "len(projects['GSE95654_samples'].samples)" ] }, { @@ -452,7 +439,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 10, "id": "ba7be762", "metadata": {}, "outputs": [ @@ -477,11 +464,11 @@ " \n", " \n", " \n", - " sample_organism_ch1\n", - " sample_channel_count\n", - " sample_contact_name\n", - " sample_library_source\n", + " sample_name\n", + " sample_library_strategy\n", " genome_build\n", + " tissue\n", + " sample_organism_ch1\n", " \n", " \n", " sample_name\n", @@ -495,209 +482,209 @@ " \n", " \n", " RRBS_on_CRC_patient_8\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_CRC_patient_8\n", + " Bisulfite-Seq\n", " hg19\n", + " primary tumor\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_adjacent_normal_colon_patient_8\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_adjacent_normal_colon_patient_8\n", + " Bisulfite-Seq\n", " hg19\n", + " adjacent normal colon\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_CRC_patient_32\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_CRC_patient_32\n", + " Bisulfite-Seq\n", " hg19\n", + " primary tumor\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_adjacent_normal_colon_patient_32\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_adjacent_normal_colon_patient_32\n", + " Bisulfite-Seq\n", " hg19\n", + " adjacent normal colon\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_CRC_patient_41\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_CRC_patient_41\n", + " Bisulfite-Seq\n", " hg19\n", + " primary tumor\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_adjacent_normal_colon_patient_41\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_adjacent_normal_colon_patient_41\n", + " Bisulfite-Seq\n", " hg19\n", + " adjacent normal colon\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_CRC_patient_42\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_CRC_patient_42\n", + " Bisulfite-Seq\n", " hg19\n", + " primary tumor\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_adjacent_normal_colon_patient_42\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_adjacent_normal_colon_patient_42\n", + " Bisulfite-Seq\n", " hg19\n", + " adjacent normal colon\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_ACF_patient_173\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_ACF_patient_173\n", + " Bisulfite-Seq\n", " hg19\n", + " aberrant crypt foci\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_ACF_patient_515\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_ACF_patient_515\n", + " Bisulfite-Seq\n", " hg19\n", + " aberrant crypt foci\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_normal_crypts_patient_139\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_normal_crypts_patient_139\n", + " Bisulfite-Seq\n", " hg19\n", + " normal colonic crypt\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_ACF_patient_143\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_ACF_patient_143\n", + " Bisulfite-Seq\n", " hg19\n", + " aberrant crypt foci\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_normal_crypts_patient_143\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_normal_crypts_patient_143\n", + " Bisulfite-Seq\n", " hg19\n", + " normal colonic crypt\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_normal_crypts_patient_165\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_normal_crypts_patient_165\n", + " Bisulfite-Seq\n", " hg19\n", + " normal colonic crypt\n", + " Homo sapiens\n", " \n", " \n", " RRBS_on_ACF_patient_165\n", - " Homo sapiens\n", - " 1\n", - " Xiwei,,Wu\n", - " genomic\n", + " RRBS_on_ACF_patient_165\n", + " Bisulfite-Seq\n", " hg19\n", + " aberrant crypt foci\n", + " Homo sapiens\n", " \n", " \n", "\n", "" ], "text/plain": [ - " sample_organism_ch1 \\\n", - "sample_name \n", - "RRBS_on_CRC_patient_8 Homo sapiens \n", - "RRBS_on_adjacent_normal_colon_patient_8 Homo sapiens \n", - "RRBS_on_CRC_patient_32 Homo sapiens \n", - "RRBS_on_adjacent_normal_colon_patient_32 Homo sapiens \n", - "RRBS_on_CRC_patient_41 Homo sapiens \n", - "RRBS_on_adjacent_normal_colon_patient_41 Homo sapiens \n", - "RRBS_on_CRC_patient_42 Homo sapiens \n", - "RRBS_on_adjacent_normal_colon_patient_42 Homo sapiens \n", - "RRBS_on_ACF_patient_173 Homo sapiens \n", - "RRBS_on_ACF_patient_515 Homo sapiens \n", - "RRBS_on_normal_crypts_patient_139 Homo sapiens \n", - "RRBS_on_ACF_patient_143 Homo sapiens \n", - "RRBS_on_normal_crypts_patient_143 Homo sapiens \n", - "RRBS_on_normal_crypts_patient_165 Homo sapiens \n", - "RRBS_on_ACF_patient_165 Homo sapiens \n", + " sample_name \\\n", + "sample_name \n", + "RRBS_on_CRC_patient_8 RRBS_on_CRC_patient_8 \n", + "RRBS_on_adjacent_normal_colon_patient_8 RRBS_on_adjacent_normal_colon_patient_8 \n", + "RRBS_on_CRC_patient_32 RRBS_on_CRC_patient_32 \n", + "RRBS_on_adjacent_normal_colon_patient_32 RRBS_on_adjacent_normal_colon_patient_32 \n", + "RRBS_on_CRC_patient_41 RRBS_on_CRC_patient_41 \n", + "RRBS_on_adjacent_normal_colon_patient_41 RRBS_on_adjacent_normal_colon_patient_41 \n", + "RRBS_on_CRC_patient_42 RRBS_on_CRC_patient_42 \n", + "RRBS_on_adjacent_normal_colon_patient_42 RRBS_on_adjacent_normal_colon_patient_42 \n", + "RRBS_on_ACF_patient_173 RRBS_on_ACF_patient_173 \n", + "RRBS_on_ACF_patient_515 RRBS_on_ACF_patient_515 \n", + "RRBS_on_normal_crypts_patient_139 RRBS_on_normal_crypts_patient_139 \n", + "RRBS_on_ACF_patient_143 RRBS_on_ACF_patient_143 \n", + "RRBS_on_normal_crypts_patient_143 RRBS_on_normal_crypts_patient_143 \n", + "RRBS_on_normal_crypts_patient_165 RRBS_on_normal_crypts_patient_165 \n", + "RRBS_on_ACF_patient_165 RRBS_on_ACF_patient_165 \n", "\n", - " sample_channel_count \\\n", - "sample_name \n", - "RRBS_on_CRC_patient_8 1 \n", - "RRBS_on_adjacent_normal_colon_patient_8 1 \n", - "RRBS_on_CRC_patient_32 1 \n", - "RRBS_on_adjacent_normal_colon_patient_32 1 \n", - "RRBS_on_CRC_patient_41 1 \n", - "RRBS_on_adjacent_normal_colon_patient_41 1 \n", - "RRBS_on_CRC_patient_42 1 \n", - "RRBS_on_adjacent_normal_colon_patient_42 1 \n", - "RRBS_on_ACF_patient_173 1 \n", - "RRBS_on_ACF_patient_515 1 \n", - "RRBS_on_normal_crypts_patient_139 1 \n", - "RRBS_on_ACF_patient_143 1 \n", - "RRBS_on_normal_crypts_patient_143 1 \n", - "RRBS_on_normal_crypts_patient_165 1 \n", - "RRBS_on_ACF_patient_165 1 \n", + " sample_library_strategy genome_build \\\n", + "sample_name \n", + "RRBS_on_CRC_patient_8 Bisulfite-Seq hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_8 Bisulfite-Seq hg19 \n", + "RRBS_on_CRC_patient_32 Bisulfite-Seq hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_32 Bisulfite-Seq hg19 \n", + "RRBS_on_CRC_patient_41 Bisulfite-Seq hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_41 Bisulfite-Seq hg19 \n", + "RRBS_on_CRC_patient_42 Bisulfite-Seq hg19 \n", + "RRBS_on_adjacent_normal_colon_patient_42 Bisulfite-Seq hg19 \n", + "RRBS_on_ACF_patient_173 Bisulfite-Seq hg19 \n", + "RRBS_on_ACF_patient_515 Bisulfite-Seq hg19 \n", + "RRBS_on_normal_crypts_patient_139 Bisulfite-Seq hg19 \n", + "RRBS_on_ACF_patient_143 Bisulfite-Seq hg19 \n", + "RRBS_on_normal_crypts_patient_143 Bisulfite-Seq hg19 \n", + "RRBS_on_normal_crypts_patient_165 Bisulfite-Seq hg19 \n", + "RRBS_on_ACF_patient_165 Bisulfite-Seq hg19 \n", "\n", - " sample_contact_name \\\n", - "sample_name \n", - "RRBS_on_CRC_patient_8 Xiwei,,Wu \n", - "RRBS_on_adjacent_normal_colon_patient_8 Xiwei,,Wu \n", - "RRBS_on_CRC_patient_32 Xiwei,,Wu \n", - "RRBS_on_adjacent_normal_colon_patient_32 Xiwei,,Wu \n", - "RRBS_on_CRC_patient_41 Xiwei,,Wu \n", - "RRBS_on_adjacent_normal_colon_patient_41 Xiwei,,Wu \n", - "RRBS_on_CRC_patient_42 Xiwei,,Wu \n", - "RRBS_on_adjacent_normal_colon_patient_42 Xiwei,,Wu \n", - "RRBS_on_ACF_patient_173 Xiwei,,Wu \n", - "RRBS_on_ACF_patient_515 Xiwei,,Wu \n", - "RRBS_on_normal_crypts_patient_139 Xiwei,,Wu \n", - "RRBS_on_ACF_patient_143 Xiwei,,Wu \n", - "RRBS_on_normal_crypts_patient_143 Xiwei,,Wu \n", - "RRBS_on_normal_crypts_patient_165 Xiwei,,Wu \n", - "RRBS_on_ACF_patient_165 Xiwei,,Wu \n", + " tissue \\\n", + "sample_name \n", + "RRBS_on_CRC_patient_8 primary tumor \n", + "RRBS_on_adjacent_normal_colon_patient_8 adjacent normal colon \n", + "RRBS_on_CRC_patient_32 primary tumor \n", + "RRBS_on_adjacent_normal_colon_patient_32 adjacent normal colon \n", + "RRBS_on_CRC_patient_41 primary tumor \n", + "RRBS_on_adjacent_normal_colon_patient_41 adjacent normal colon \n", + "RRBS_on_CRC_patient_42 primary tumor \n", + "RRBS_on_adjacent_normal_colon_patient_42 adjacent normal colon \n", + "RRBS_on_ACF_patient_173 aberrant crypt foci \n", + "RRBS_on_ACF_patient_515 aberrant crypt foci \n", + "RRBS_on_normal_crypts_patient_139 normal colonic crypt \n", + "RRBS_on_ACF_patient_143 aberrant crypt foci \n", + "RRBS_on_normal_crypts_patient_143 normal colonic crypt \n", + "RRBS_on_normal_crypts_patient_165 normal colonic crypt \n", + "RRBS_on_ACF_patient_165 aberrant crypt foci \n", "\n", - " sample_library_source genome_build \n", - "sample_name \n", - "RRBS_on_CRC_patient_8 genomic hg19 \n", - "RRBS_on_adjacent_normal_colon_patient_8 genomic hg19 \n", - "RRBS_on_CRC_patient_32 genomic hg19 \n", - "RRBS_on_adjacent_normal_colon_patient_32 genomic hg19 \n", - "RRBS_on_CRC_patient_41 genomic hg19 \n", - "RRBS_on_adjacent_normal_colon_patient_41 genomic hg19 \n", - "RRBS_on_CRC_patient_42 genomic hg19 \n", - "RRBS_on_adjacent_normal_colon_patient_42 genomic hg19 \n", - "RRBS_on_ACF_patient_173 genomic hg19 \n", - "RRBS_on_ACF_patient_515 genomic hg19 \n", - "RRBS_on_normal_crypts_patient_139 genomic hg19 \n", - "RRBS_on_ACF_patient_143 genomic hg19 \n", - "RRBS_on_normal_crypts_patient_143 genomic hg19 \n", - "RRBS_on_normal_crypts_patient_165 genomic hg19 \n", - "RRBS_on_ACF_patient_165 genomic hg19 " + " sample_organism_ch1 \n", + "sample_name \n", + "RRBS_on_CRC_patient_8 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_8 Homo sapiens \n", + "RRBS_on_CRC_patient_32 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_32 Homo sapiens \n", + "RRBS_on_CRC_patient_41 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_41 Homo sapiens \n", + "RRBS_on_CRC_patient_42 Homo sapiens \n", + "RRBS_on_adjacent_normal_colon_patient_42 Homo sapiens \n", + "RRBS_on_ACF_patient_173 Homo sapiens \n", + "RRBS_on_ACF_patient_515 Homo sapiens \n", + "RRBS_on_normal_crypts_patient_139 Homo sapiens \n", + "RRBS_on_ACF_patient_143 Homo sapiens \n", + "RRBS_on_normal_crypts_patient_143 Homo sapiens \n", + "RRBS_on_normal_crypts_patient_165 Homo sapiens \n", + "RRBS_on_ACF_patient_165 Homo sapiens " ] }, - "execution_count": 29, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "projects['_samples'].sample_table.iloc[:15 , :5]" + "projects['GSE95654_samples'].sample_table.iloc[:15 , :5]" ] } ], From f8fc5e438885f4cd08e14b0c0d4a8d9d8fe3d551 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 8 Sep 2022 12:32:24 -0400 Subject: [PATCH 41/61] added package Readme --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index ed5c01e..5bf1d6d 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,14 @@ `geofetch` is a command-line tool that downloads sequencing data and metadata from GEO and SRA and creates [standard PEPs](http://pep.databio.org/). `geofetch` is hosted at [pypi](https://pypi.org/project/geofetch/) and documentation is hosted at [geofetch.databio.org](http://geofetch.databio.org) (source in the [/docs](/docs) folder). You can convert the result of geofetch into unmapped `bam` or `fastq` files with the included `sraconvert` command. + +Key geofetch features: + +- Works with GEO and SRA metadata +- Combines samples from different projects +- Standardizes output metadata +- Filters type and size of processed files (from GEO) before downloading them +- Easy to use +- Fast execution time +- Available GSE search tool +- Available both as command-line tool and Python execution Package From 567ca863237b6c77f244bd5a02cbe0bdb39851e5 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 8 Sep 2022 12:38:27 -0400 Subject: [PATCH 42/61] added missing .md file --- README.md | 2 +- docs_jupyter/build/python-usage.md | 360 +++++++++++++++++++++++++++++ 2 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 docs_jupyter/build/python-usage.md diff --git a/README.md b/README.md index 5bf1d6d..2388aca 100644 --- a/README.md +++ b/README.md @@ -18,5 +18,5 @@ Key geofetch features: - Filters type and size of processed files (from GEO) before downloading them - Easy to use - Fast execution time -- Available GSE search tool +- Provides GSE search tool - Available both as command-line tool and Python execution Package diff --git a/docs_jupyter/build/python-usage.md b/docs_jupyter/build/python-usage.md new file mode 100644 index 0000000..13e98c6 --- /dev/null +++ b/docs_jupyter/build/python-usage.md @@ -0,0 +1,360 @@ +jupyter:True +# Tutorial of usage geofetch as python package + +♪♫*•♪♪♫*•♪♪♫*•♪♪♫*•♪♪♫* + +Geofetch provides python fuctions to fetch metadata and metadata from GEO and SRA by using python language. `get_project` function returns dictionary of peppy projects that were found using filters and input you specified. + peppy is a Python package that provides an API for handling standardized project and sample metadata. + +More information you can get here: + +http://peppy.databio.org/en/latest/ + +http://pep.databio.org/en/2.0.0/ + +### First let's import geofetch + + +```python +from geofetch import Geofetcher +``` + +### Initiate Geofetch object by specifing parameters that you want to use for downloading metadata/data + +1) If you won't specify any parameters, defaul parameters will be used + + +```python +geof = Geofetcher() +``` + +```.output +Metadata folder: /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name + +``` + +2) To download processed data with samples and series specify this two arguments: + + +```python +geof = Geofetcher(processed=True, data_source="all") +``` + +```.output +Metadata folder: /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name + +``` + +3) To tune project parameter, where metadata should be stored use next parameters: + + +```python +geof = Geofetcher(processed=True, data_source="all", const_limit_project = 20, const_limit_discard = 500, attr_limit_truncate = 10000 ) +``` + +```.output +Metadata folder: /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name + +``` + +4) To add more filter of other options see documentation + +## Run Geofetch + +### By default: +1) No actual data will be downloaded (just_metadata=True) + +2) No soft files will be saved on the disc (discard_soft=True) + + +```python +projects = geof.get_projects("GSE95654") +``` + +```.output +Trying GSE95654 (not a file) as accession... +Trying GSE95654 (not a file) as accession... + +``` + + + Output() + + +```.output +Skipped 0 accessions. Starting now. +Processing accession 1 of 1: 'GSE95654' + +Total number of processed SAMPLES files found is: 40 +Total number of processed SERIES files found is: 0 +Expanding metadata list... +Expanding metadata list... + +``` + + +

+
+
+
+
+
+
+ + + +```.output +Finished processing 1 accession(s) +Cleaning soft files ... +Unifying and saving of metadata... + +``` + + + Output() + + + +

+
+
+
+
+
+
+ + + + +
+
+ + + + + Output() + + + +

+
+
+
+
+
+
+ + + + +
+
+ + + +```.output +No files found. No data to save. File /home/bnt4me/Virginia/repos/geof2/geofetch/docs_jupyter/project_name/GSE95654_series/GSE95654_series.csv won't be created + +``` + +Check if projects were created by checking dict keys: + + +```python +projects.keys() +``` + + + + + dict_keys(['GSE95654_samples']) + + + +project for smaples was created! Now let's look into it. + +\* the values of the dictionary are peppy projects. More information about peppy Project you can find in the documentation: http://peppy.databio.org/en/latest/ + + +```python +len(projects['GSE95654_samples'].samples) +``` + + + + + 40 + + + +We got 40 samples from GSE95654 project. If you want to check if it's correct information go into: https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE95654 + +Now let's see actuall data. first 15 project and 5 clolumns: + + +```python +projects['GSE95654_samples'].sample_table.iloc[:15 , :5] +``` + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
sample_namesample_library_strategygenome_buildtissuesample_organism_ch1
sample_name
RRBS_on_CRC_patient_8RRBS_on_CRC_patient_8Bisulfite-Seqhg19primary tumorHomo sapiens
RRBS_on_adjacent_normal_colon_patient_8RRBS_on_adjacent_normal_colon_patient_8Bisulfite-Seqhg19adjacent normal colonHomo sapiens
RRBS_on_CRC_patient_32RRBS_on_CRC_patient_32Bisulfite-Seqhg19primary tumorHomo sapiens
RRBS_on_adjacent_normal_colon_patient_32RRBS_on_adjacent_normal_colon_patient_32Bisulfite-Seqhg19adjacent normal colonHomo sapiens
RRBS_on_CRC_patient_41RRBS_on_CRC_patient_41Bisulfite-Seqhg19primary tumorHomo sapiens
RRBS_on_adjacent_normal_colon_patient_41RRBS_on_adjacent_normal_colon_patient_41Bisulfite-Seqhg19adjacent normal colonHomo sapiens
RRBS_on_CRC_patient_42RRBS_on_CRC_patient_42Bisulfite-Seqhg19primary tumorHomo sapiens
RRBS_on_adjacent_normal_colon_patient_42RRBS_on_adjacent_normal_colon_patient_42Bisulfite-Seqhg19adjacent normal colonHomo sapiens
RRBS_on_ACF_patient_173RRBS_on_ACF_patient_173Bisulfite-Seqhg19aberrant crypt fociHomo sapiens
RRBS_on_ACF_patient_515RRBS_on_ACF_patient_515Bisulfite-Seqhg19aberrant crypt fociHomo sapiens
RRBS_on_normal_crypts_patient_139RRBS_on_normal_crypts_patient_139Bisulfite-Seqhg19normal colonic cryptHomo sapiens
RRBS_on_ACF_patient_143RRBS_on_ACF_patient_143Bisulfite-Seqhg19aberrant crypt fociHomo sapiens
RRBS_on_normal_crypts_patient_143RRBS_on_normal_crypts_patient_143Bisulfite-Seqhg19normal colonic cryptHomo sapiens
RRBS_on_normal_crypts_patient_165RRBS_on_normal_crypts_patient_165Bisulfite-Seqhg19normal colonic cryptHomo sapiens
RRBS_on_ACF_patient_165RRBS_on_ACF_patient_165Bisulfite-Seqhg19aberrant crypt fociHomo sapiens
+
+ + From 79dbe2d0aea709070b43cd67e6b7b9c3c369b676 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 29 Sep 2022 13:29:49 -0400 Subject: [PATCH 43/61] fixed #88 --- geofetch/geofetch.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 7fc44e0..fb4b067 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -446,17 +446,16 @@ def fetch_all(self, input: str, name: str = None): pass else: self._LOGGER.info("Parsing SRA file to download SRR records") - gsm_multi_table = self._process_sra_meta( + gsm_multi_table, gsm_metadata, runs = self._process_sra_meta( srp_list_result, gsm_enter_dict, gsm_metadata ) # download raw data: if not self.just_metadata: - for file_key in gsm_multi_table.keys(): - for run in gsm_multi_table[file_key]: - # download raw data - self._LOGGER.info(f"Getting SRR: {run[2]} in ({acc_GSE})") - self._download_raw_data(run[2]) + for run in runs: + # download raw data + self._LOGGER.info(f"Getting SRR: {run} in ({acc_GSE})") + self._download_raw_data(run) else: self._LOGGER.info(f"Dry run, no data will be downloaded") @@ -514,6 +513,7 @@ def _process_sra_meta( :return: srp multitable """ gsm_multi_table = {} + runs = [] for line in srp_list_result: # Only download if it's in the include list: @@ -582,8 +582,9 @@ def _process_sra_meta( else: # The first SRR for this SRX is added to GSM metadata gsm_metadata[experiment]["SRR"] = run_name + runs.append(run_name) - return gsm_multi_table + return gsm_multi_table, gsm_metadata, runs def _download_raw_data(self, run_name): bam_file = ( From 10f3386babec27e8a30f6e396df3d1832654564f Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 3 Oct 2022 16:53:45 -0400 Subject: [PATCH 44/61] Added usage to the cli. Fixed #89 --- geofetch/geofetch.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index fb4b067..2e4cd8e 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -2176,7 +2176,18 @@ def _parse_cmdl(cmdl): parser """ parser = argparse.ArgumentParser( - description="Automatic GEO and SRA data downloader" + description="Automatic GEO and SRA data downloader", + usage="""geofetch [] + +The example how to use geofetch (to download GSE573030 just metadata): + geofetch -i GSE67303 -m `pwd` --just-metadata + +To download all processed data of GSE57303: + geofetch -i GSE67303 --processed --geo-folder `pwd` -m `pwd` + +* where `pwd` is a current directory + +""" ) processed_group = parser.add_argument_group("processed") From 375ae3d5c79f101d329d693dbb8366411d73b852 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 4 Oct 2022 12:11:50 -0400 Subject: [PATCH 45/61] Fixed #90 --- geofetch/config_processed_template.yaml | 2 ++ geofetch/config_template.yaml | 6 ++---- geofetch/geofetch.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/geofetch/config_processed_template.yaml b/geofetch/config_processed_template.yaml index 66690c9..9f8eb38 100644 --- a/geofetch/config_processed_template.yaml +++ b/geofetch/config_processed_template.yaml @@ -7,7 +7,9 @@ sample_table: {sample_table} sample_modifiers: append: output_file_path: FILES + # Project metadata: {additional_columns} + # End of project metadata {pipeline_samples} derive: attributes: [output_file_path] diff --git a/geofetch/config_template.yaml b/geofetch/config_template.yaml index a47348a..59fcaa2 100644 --- a/geofetch/config_template.yaml +++ b/geofetch/config_template.yaml @@ -5,13 +5,11 @@ pep_version: 2.1.0 sample_table: {annotation} {subannotation} -looper: - output_dir: {project_name} - pipeline_interfaces: {pipeline_interfaces} - sample_modifiers: append: + # Project metadata: {additional_columns} + # End of project metadata SRR_files: SRA {pipeline_samples} derive: diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 2e4cd8e..b9445a9 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -2187,7 +2187,7 @@ def _parse_cmdl(cmdl): * where `pwd` is a current directory -""" +""", ) processed_group = parser.add_argument_group("processed") From b826b0df6f7c3ef0f6f0182ac5ce4b1325124cca Mon Sep 17 00:00:00 2001 From: Nathan Sheffield Date: Fri, 21 Oct 2022 14:38:33 -0400 Subject: [PATCH 46/61] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2388aca..978a127 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,7 @@ [![pypi-badge](https://img.shields.io/pypi/v/geofetch)](https://pypi.org/project/geofetch) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -`geofetch` is a command-line tool that downloads sequencing data and metadata from GEO and SRA and creates [standard PEPs](http://pep.databio.org/). `geofetch` is hosted at [pypi](https://pypi.org/project/geofetch/) and documentation is hosted at [geofetch.databio.org](http://geofetch.databio.org) (source in the [/docs](/docs) folder). - -You can convert the result of geofetch into unmapped `bam` or `fastq` files with the included `sraconvert` command. +`geofetch` is a command-line tool that downloads sequencing data and metadata from GEO and SRA and creates [standard PEPs](http://pep.databio.org/). `geofetch` is hosted at [pypi](https://pypi.org/project/geofetch/). You can convert the result of geofetch into unmapped `bam` or `fastq` files with the included `sraconvert` command. Key geofetch features: @@ -18,5 +16,7 @@ Key geofetch features: - Filters type and size of processed files (from GEO) before downloading them - Easy to use - Fast execution time -- Provides GSE search tool -- Available both as command-line tool and Python execution Package +- Can search GEO to find relevant data +- Can be used either as a command-line tool or from within Python using an API + +For more information, see [complete documentation at geofetch.databio.org](http://geofetch.databio.org) (source in the [/docs](/docs) folder). From a852062dcca8fa000fc8bb4b23365fc035de8bba Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 21 Oct 2022 15:34:09 -0400 Subject: [PATCH 47/61] fixed issues in PR comments --- docs/README.md | 2 +- docs/changelog.md | 2 ++ geofetch/geofetch.py | 13 +++++-------- setup.py | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/README.md b/docs/README.md index e0b9c74..b2e711b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -55,7 +55,7 @@ geofetch -i GSE95654 --processed --just-metadata --- ### New features available in geofetch 0.11.0 : -1) Now geofetch is available as Python package. Geofetch can initialize [peppy](http://peppy.databio.org/) projects without downloading any soft files. Example: +1) Now geofetch is available as Python API package. Geofetch can initialize [peppy](http://peppy.databio.org/) projects without downloading any soft files. Example: ```python from geofetch import Geofetcher diff --git a/docs/changelog.md b/docs/changelog.md index f9c3c57..e5d3406 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,6 +7,8 @@ - Fixed None issue in config file - Switched way of saving soft files to request library - Fixed saving raw peps bug +- Fixed config errors +- Improved documentation - Refactored code ## [0.10.1] -- 2022-08-04 diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index b9445a9..03e63ab 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -90,7 +90,7 @@ class Geofetcher: :param fq_folder: Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding fastq files already exist. [Default: $SRAFQ:] [Works with raw data] :param use_key_subset: Use just the keys defined in this module when writing out metadata. [Works with raw data] - :param sra_folder: [Doesn't work ]Optional: Specify a location to store sra files + :param sra_folder: Optional: Specify a location to store sra files [Default: $SRARAW:" + safe_echo("SRARAW") + ] :param bam_conversion: Optional: set True to convert bam files [Works with raw data] :param picard_path: Specify a path to the picard jar, if you want to convert fastq to bam @@ -403,11 +403,8 @@ def fetch_all(self, input: str, name: str = None): ( meta_processed_samples, meta_processed_series, - ) = self.fetch_processed_one( - gse_file_content=file_gse_content, - gsm_file_content=file_gsm_content, - gsm_filter_list=gsm_enter_dict, - ) + ) = self.fetchone_processed(gse_file_content=file_gse_content, gsm_file_content=file_gsm_content, + gsm_filter_list=gsm_enter_dict) # download processed files: if not self.just_metadata: @@ -630,7 +627,7 @@ def _download_raw_data(self, run_name): f"SRA file doesn't exist, please download it first: {err}" ) - def fetch_processed_one( + def fetchone_processed( self, gse_file_content: list, gsm_file_content: list, @@ -670,7 +667,7 @@ def _generate_processed_meta( ) -> dict: """ Generate and save PEPs for processed accessions. GEO has data in GSE and GSM, - conditions are used to decide which PEPs have to be saved. + conditions are used to decide which PEPs will be saved. :param name: name of the folder/file where PEP will be saved :param meta_processed_samples: :param meta_processed_series: diff --git a/setup.py b/setup.py index e92f5b0..79cca69 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ def read_reqs(reqs_name): ], keywords="project, bioinformatics, sequencing, ngs, workflow, GUI", url="https://github.com/pepkit/{}/".format(PACKAGE), - author="Nathan Sheffield, Vince Reuter, Oleksandr Khoroshevskyi", + author="Oleksandr Khoroshevskyi, Nathan Sheffield, Vince Reuter, Nathan LeRoy", license="BSD2", entry_points={ "console_scripts": [ From 0e658335ae20f454edd482f33a740939d41e8e05 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Fri, 21 Oct 2022 15:35:08 -0400 Subject: [PATCH 48/61] lint --- geofetch/geofetch.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 03e63ab..992efd1 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -403,8 +403,11 @@ def fetch_all(self, input: str, name: str = None): ( meta_processed_samples, meta_processed_series, - ) = self.fetchone_processed(gse_file_content=file_gse_content, gsm_file_content=file_gsm_content, - gsm_filter_list=gsm_enter_dict) + ) = self.fetchone_processed( + gse_file_content=file_gse_content, + gsm_file_content=file_gsm_content, + gsm_filter_list=gsm_enter_dict, + ) # download processed files: if not self.just_metadata: From 5ff204fa870147271ed4291f6a577ef07b28250d Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 24 Oct 2022 12:04:45 -0400 Subject: [PATCH 49/61] Fixed #92 --- geofetch/geofetch.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 992efd1..4a51ca1 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1143,7 +1143,8 @@ def _create_config_processed( with open(config_template, "r") as template_file: template = template_file.read() meta_list_str = [ - f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta + f'{list(i.keys())[0]}: "{self._sanitize_config_string(list(i.values())[0])}"' + for i in proj_meta ] modifiers_str = "\n ".join(d for d in meta_list_str) template_values = { @@ -1168,7 +1169,8 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): :return: generated, complete config file content """ meta_list_str = [ - f"{list(i.keys())[0]}: {list(i.values())[0]}" for i in proj_meta + f"{list(i.keys())[0]}: {self._sanitize_name((i.values())[0])}" + for i in proj_meta ] modifiers_str = "\n ".join(d for d in meta_list_str) # Write project config file @@ -1210,10 +1212,23 @@ def _check_sample_name_standard(self, metadata_dict: dict) -> dict: metadata_dict = self._standardize_colnames(metadata_dict) return metadata_dict + @staticmethod + def _sanitize_config_string(text: str) -> str: + """ + Function that sanitizes text in config file. + :param text: Any string that have to be sanitized + :return: sanitized strings + """ + new_str = text + punctuation1 = r""""'`""" + for odd_char in list(punctuation1): + new_str = new_str.replace(odd_char, "_") + return new_str + @staticmethod def _sanitize_name(name_str: str) -> str: """ - Function that sanitizing strings. (Replace all odd characters) + Function that sanitizes strings. (Replace all odd characters) :param str name_str: Any string value that has to be sanitized. :return: sanitized strings """ From bb9892e954669c1a19171be148f5f99206eae18b Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 24 Oct 2022 12:21:04 -0400 Subject: [PATCH 50/61] Fix of #92 (2) --- geofetch/geofetch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 4a51ca1..0dd6446 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1305,7 +1305,7 @@ def _separate_common_meta( new_str = nb_sample[1][this_key] if isinstance(nb_sample[1][this_key], str): new_str = nb_sample[1][this_key].replace('"', "") - new_str = re.sub("[^A-Za-z0-9]+", " ", new_str) + # new_str = re.sub("[^A-Za-z0-9]+", " ", new_str) new_meta_project.append({this_key: new_str}) first_key = False del meta_list[nb_sample[0]][this_key] From ac03f3f01fcaad7a9d7f5a47404e380cb22e6a8a Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 24 Oct 2022 12:51:18 -0400 Subject: [PATCH 51/61] Fixed errors --- geofetch/geofetch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 0dd6446..55279c5 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1169,7 +1169,7 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): :return: generated, complete config file content """ meta_list_str = [ - f"{list(i.keys())[0]}: {self._sanitize_name((i.values())[0])}" + f'{list(i.keys())[0]}: "{self._sanitize_config_string(list(i.values())[0])}"' for i in proj_meta ] modifiers_str = "\n ".join(d for d in meta_list_str) From cb5c2d5ff456674a4793f9821b0be5d2b1f2ea0b Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 24 Oct 2022 16:18:48 -0400 Subject: [PATCH 52/61] Fixed #95 (3) --- geofetch/geofetch.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 55279c5..cdf9fd5 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1220,9 +1220,8 @@ def _sanitize_config_string(text: str) -> str: :return: sanitized strings """ new_str = text - punctuation1 = r""""'`""" - for odd_char in list(punctuation1): - new_str = new_str.replace(odd_char, "_") + new_str = new_str.replace('"', f'\\"') + new_str = new_str.replace("'", f"''") return new_str @staticmethod From 90e8bfec322ce7b61178c66db8b96dbdce8affc7 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Mon, 24 Oct 2022 21:20:27 -0400 Subject: [PATCH 53/61] refactoring cli --- geofetch/cli.py | 280 ++++++++++++++++++++++++++++++++++++++++ geofetch/geofetch.py | 298 +------------------------------------------ 2 files changed, 284 insertions(+), 294 deletions(-) create mode 100644 geofetch/cli.py diff --git a/geofetch/cli.py b/geofetch/cli.py new file mode 100644 index 0000000..53ed9f4 --- /dev/null +++ b/geofetch/cli.py @@ -0,0 +1,280 @@ +import argparse +import os +import logmuse +from ._version import __version__ + + +def _safe_echo(var): + """Returns an environment variable if it exists, or an empty string if not""" + return os.getenv(var, "") + + +def _parse_cmdl(cmdl): + """ + parser + """ + parser = argparse.ArgumentParser( + description="Automatic GEO and SRA data downloader", + usage="""geofetch [] + +The example how to use geofetch (to download GSE573030 just metadata): + geofetch -i GSE67303 -m `pwd` --just-metadata + +To download all processed data of GSE57303: + geofetch -i GSE67303 --processed --geo-folder `pwd` -m `pwd` + +* where `pwd` is a current directory + +""", + ) + + processed_group = parser.add_argument_group("processed") + raw_group = parser.add_argument_group("raw") + + parser.add_argument( + "-V", "--version", action="version", version=f"%(prog)s {__version__}" + ) + + # Required + parser.add_argument( + "-i", + "--input", + dest="input", + required=True, + help="required: a GEO (GSE) accession, or a file with a list of GSE numbers", + ) + + # Optional + parser.add_argument( + "-n", "--name", help="Specify a project name. Defaults to GSE number" + ) + + parser.add_argument( + "-m", + "--metadata-root", + dest="metadata_root", + default=_safe_echo("SRAMETA"), + help="Specify a parent folder location to store metadata. " + "The project name will be added as a subfolder " + "[Default: $SRAMETA:" + _safe_echo("SRAMETA") + "]", + ) + + parser.add_argument( + "-u", + "--metadata-folder", + help="Specify an absolute folder location to store metadata. " + "No subfolder will be added. Overrides value of --metadata-root " + "[Default: Not used (--metadata-root is used by default)]", + ) + + parser.add_argument( + "--just-metadata", + action="store_true", + help="If set, don't actually run downloads, just create metadata", + ) + + parser.add_argument( + "-r", + "--refresh-metadata", + action="store_true", + help="If set, re-download metadata even if it exists.", + ) + + parser.add_argument( + "--config-template", default=None, help="Project config yaml file template." + ) + + # Optional + parser.add_argument( + "--pipeline-samples", + default=None, + help="Optional: Specify one or more filepaths to SAMPLES pipeline interface yaml files. " + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", + ) + + # Optional + parser.add_argument( + "--pipeline-project", + default=None, + help="Optional: Specify one or more filepaths to PROJECT pipeline interface yaml files. " + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", + ) + # Optional + parser.add_argument( + "--disable-progressbar", + action="store_true", + help="Optional: Disable progressbar", + ) + + # Optional + parser.add_argument( + "-k", + "--skip", + default=0, + type=int, + help="Skip some accessions. [Default: no skip].", + ) + + parser.add_argument( + "--acc-anno", + action="store_true", + help="Optional: Produce annotation sheets for each accession." + " Project combined PEP for the whole project won't be produced.", + ) + + parser.add_argument( + "--discard-soft", + action="store_true", + help="Optional: After creation of PEP files, all soft and additional files will be deleted", + ) + + parser.add_argument( + "--const-limit-project", + type=int, + default=50, + help="Optional: Limit of the number of the constant sample characters " + "that should not be in project yaml. [Default: 50]", + ) + + parser.add_argument( + "--const-limit-discard", + type=int, + default=250, + help="Optional: Limit of the number of the constant sample characters " + "that should not be discarded [Default: 250]", + ) + + parser.add_argument( + "--attr-limit-truncate", + type=int, + default=500, + help="Optional: Limit of the number of sample characters." + "Any attribute with more than X characters will truncate to the first X," + " where X is a number of characters [Default: 500]", + ) + + parser.add_argument( + "--add-dotfile", + action="store_true", + help="Optional: Add .pep.yaml file that points .yaml PEP file", + ) + + processed_group.add_argument( + "-p", + "--processed", + default=False, + action="store_true", + help="Download processed data [Default: download raw data].", + ) + + processed_group.add_argument( + "--data-source", + dest="data_source", + choices=["all", "samples", "series"], + default="samples", + help="Optional: Specifies the source of data on the GEO record" + " to retrieve processed data, which may be attached to the" + " collective series entity, or to individual samples. " + "Allowable values are: samples, series or both (all). " + "Ignored unless 'processed' flag is set. [Default: samples]", + ) + + processed_group.add_argument( + "--filter", + default=None, + help="Optional: Filter regex for processed filenames [Default: None]." + "Ignored unless 'processed' flag is set.", + ) + + processed_group.add_argument( + "--filter-size", + dest="filter_size", + default=None, + help="""Optional: Filter size for processed files + that are stored as sample repository [Default: None]. + Works only for sample data. + Supported input formats : 12B, 12KB, 12MB, 12GB. + Ignored unless 'processed' flag is set.""", + ) + + processed_group.add_argument( + "-g", + "--geo-folder", + default=_safe_echo("GEODATA"), + help="Optional: Specify a location to store processed GEO files." + " Ignored unless 'processed' flag is set." + "[Default: $GEODATA:" + _safe_echo("GEODATA") + "]", + ) + + raw_group.add_argument( + "-x", + "--split-experiments", + action="store_true", + help="""Split SRR runs into individual samples. By default, SRX + experiments with multiple SRR Runs will have a single entry in the + annotation table, with each run as a separate row in the + subannotation table. This setting instead treats each run as a + separate sample""", + ) + + raw_group.add_argument( + "-b", + "--bam-folder", + dest="bam_folder", + default=_safe_echo("SRABAM"), + help="""Optional: Specify folder of bam files. Geofetch will not + download sra files when corresponding bam files already exist. + [Default: $SRABAM:""" + + _safe_echo("SRABAM") + + "]", + ) + + raw_group.add_argument( + "-f", + "--fq-folder", + dest="fq_folder", + default=_safe_echo("SRAFQ"), + help="""Optional: Specify folder of fastq files. Geofetch will not + download sra files when corresponding fastq files already exist. + [Default: $SRAFQ:""" + + _safe_echo("SRAFQ") + + "]", + ) + + # Deprecated; these are for bam conversion which now happens in sra_convert + # it still works here but I hide it so people don't use it, because it's confusing. + raw_group.add_argument( + "-s", + "--sra-folder", + dest="sra_folder", + default=_safe_echo("SRARAW"), + help=argparse.SUPPRESS, + # help="Optional: Specify a location to store sra files " + # "[Default: $SRARAW:" + safe_echo("SRARAW") + "]" + ) + raw_group.add_argument( + "--bam-conversion", + action="store_true", + # help="Turn on sequential bam conversion. Default: No conversion.", + help=argparse.SUPPRESS, + ) + + raw_group.add_argument( + "--picard-path", + dest="picard_path", + default=_safe_echo("PICARD"), + # help="Specify a path to the picard jar, if you want to convert " + # "fastq to bam [Default: $PICARD:" + safe_echo("PICARD") + "]", + help=argparse.SUPPRESS, + ) + + raw_group.add_argument( + "--use-key-subset", + action="store_true", + help="Use just the keys defined in this module when writing out metadata.", + ) + + logmuse.add_logging_options(parser) + return parser.parse_args(cmdl) \ No newline at end of file diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index cdf9fd5..3dd374f 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -6,20 +6,16 @@ import copy import csv import os - -# import re import sys # from string import punctuation +# import tarfile import requests import xmltodict -from rich.progress import track import yaml - -# import tarfile import time -from ._version import __version__ +from .cli import _parse_cmdl from .const import * from .utils import ( Accession, @@ -30,6 +26,8 @@ run_subprocess, ) +from rich.progress import track +import re import logmuse from ubiquerg import expandpath, is_command_callable from io import StringIO @@ -2185,294 +2183,6 @@ def _write( f.write("\n") -def _parse_cmdl(cmdl): - """ - parser - """ - parser = argparse.ArgumentParser( - description="Automatic GEO and SRA data downloader", - usage="""geofetch [] - -The example how to use geofetch (to download GSE573030 just metadata): - geofetch -i GSE67303 -m `pwd` --just-metadata - -To download all processed data of GSE57303: - geofetch -i GSE67303 --processed --geo-folder `pwd` -m `pwd` - -* where `pwd` is a current directory - -""", - ) - - processed_group = parser.add_argument_group("processed") - raw_group = parser.add_argument_group("raw") - - parser.add_argument( - "-V", "--version", action="version", version=f"%(prog)s {__version__}" - ) - - # Required - parser.add_argument( - "-i", - "--input", - dest="input", - required=True, - help="required: a GEO (GSE) accession, or a file with a list of GSE numbers", - ) - - # Optional - parser.add_argument( - "-n", "--name", help="Specify a project name. Defaults to GSE number" - ) - - parser.add_argument( - "-m", - "--metadata-root", - dest="metadata_root", - default=safe_echo("SRAMETA"), - help="Specify a parent folder location to store metadata. " - "The project name will be added as a subfolder " - "[Default: $SRAMETA:" + safe_echo("SRAMETA") + "]", - ) - - parser.add_argument( - "-u", - "--metadata-folder", - help="Specify an absolute folder location to store metadata. " - "No subfolder will be added. Overrides value of --metadata-root " - "[Default: Not used (--metadata-root is used by default)]", - ) - - parser.add_argument( - "--just-metadata", - action="store_true", - help="If set, don't actually run downloads, just create metadata", - ) - - parser.add_argument( - "-r", - "--refresh-metadata", - action="store_true", - help="If set, re-download metadata even if it exists.", - ) - - parser.add_argument( - "--config-template", default=None, help="Project config yaml file template." - ) - - # Optional - parser.add_argument( - "--pipeline-samples", - default=None, - help="Optional: Specify one or more filepaths to SAMPLES pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", - ) - - # Optional - parser.add_argument( - "--pipeline-project", - default=None, - help="Optional: Specify one or more filepaths to PROJECT pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", - ) - # Optional - parser.add_argument( - "--disable-progressbar", - action="store_true", - help="Optional: Disable progressbar", - ) - - # Optional - parser.add_argument( - "-k", - "--skip", - default=0, - type=int, - help="Skip some accessions. [Default: no skip].", - ) - - parser.add_argument( - "--acc-anno", - action="store_true", - help="Optional: Produce annotation sheets for each accession." - " Project combined PEP for the whole project won't be produced.", - ) - - parser.add_argument( - "--discard-soft", - action="store_true", - help="Optional: After creation of PEP files, all soft and additional files will be deleted", - ) - - parser.add_argument( - "--const-limit-project", - type=int, - default=50, - help="Optional: Limit of the number of the constant sample characters " - "that should not be in project yaml. [Default: 50]", - ) - - parser.add_argument( - "--const-limit-discard", - type=int, - default=250, - help="Optional: Limit of the number of the constant sample characters " - "that should not be discarded [Default: 250]", - ) - - parser.add_argument( - "--attr-limit-truncate", - type=int, - default=500, - help="Optional: Limit of the number of sample characters." - "Any attribute with more than X characters will truncate to the first X," - " where X is a number of characters [Default: 500]", - ) - - parser.add_argument( - "--add-dotfile", - action="store_true", - help="Optional: Add .pep.yaml file that points .yaml PEP file", - ) - - processed_group.add_argument( - "-p", - "--processed", - default=False, - action="store_true", - help="Download processed data [Default: download raw data].", - ) - - processed_group.add_argument( - "--data-source", - dest="data_source", - choices=["all", "samples", "series"], - default="samples", - help="Optional: Specifies the source of data on the GEO record" - " to retrieve processed data, which may be attached to the" - " collective series entity, or to individual samples. " - "Allowable values are: samples, series or both (all). " - "Ignored unless 'processed' flag is set. [Default: samples]", - ) - - processed_group.add_argument( - "--filter", - default=None, - help="Optional: Filter regex for processed filenames [Default: None]." - "Ignored unless 'processed' flag is set.", - ) - - processed_group.add_argument( - "--filter-size", - dest="filter_size", - default=None, - help="""Optional: Filter size for processed files - that are stored as sample repository [Default: None]. - Works only for sample data. - Supported input formats : 12B, 12KB, 12MB, 12GB. - Ignored unless 'processed' flag is set.""", - ) - - processed_group.add_argument( - "-g", - "--geo-folder", - default=safe_echo("GEODATA"), - help="Optional: Specify a location to store processed GEO files." - " Ignored unless 'processed' flag is set." - "[Default: $GEODATA:" + safe_echo("GEODATA") + "]", - ) - - raw_group.add_argument( - "-x", - "--split-experiments", - action="store_true", - help="""Split SRR runs into individual samples. By default, SRX - experiments with multiple SRR Runs will have a single entry in the - annotation table, with each run as a separate row in the - subannotation table. This setting instead treats each run as a - separate sample""", - ) - - raw_group.add_argument( - "-b", - "--bam-folder", - dest="bam_folder", - default=safe_echo("SRABAM"), - help="""Optional: Specify folder of bam files. Geofetch will not - download sra files when corresponding bam files already exist. - [Default: $SRABAM:""" - + safe_echo("SRABAM") - + "]", - ) - - raw_group.add_argument( - "-f", - "--fq-folder", - dest="fq_folder", - default=safe_echo("SRAFQ"), - help="""Optional: Specify folder of fastq files. Geofetch will not - download sra files when corresponding fastq files already exist. - [Default: $SRAFQ:""" - + safe_echo("SRAFQ") - + "]", - ) - - # Deprecated; these are for bam conversion which now happens in sra_convert - # it still works here but I hide it so people don't use it, because it's confusing. - raw_group.add_argument( - "-s", - "--sra-folder", - dest="sra_folder", - default=safe_echo("SRARAW"), - help=argparse.SUPPRESS, - # help="Optional: Specify a location to store sra files " - # "[Default: $SRARAW:" + safe_echo("SRARAW") + "]" - ) - raw_group.add_argument( - "--bam-conversion", - action="store_true", - # help="Turn on sequential bam conversion. Default: No conversion.", - help=argparse.SUPPRESS, - ) - - raw_group.add_argument( - "--picard-path", - dest="picard_path", - default=safe_echo("PICARD"), - # help="Specify a path to the picard jar, if you want to convert " - # "fastq to bam [Default: $PICARD:" + safe_echo("PICARD") + "]", - help=argparse.SUPPRESS, - ) - - raw_group.add_argument( - "--use-key-subset", - action="store_true", - help="Use just the keys defined in this module when writing out metadata.", - ) - - logmuse.add_logging_options(parser) - return parser.parse_args(cmdl) - - -def safe_echo(var): - """Returns an environment variable if it exists, or an empty string if not""" - return os.getenv(var, "") - - -class InvalidSoftLineException(Exception): - """Exception related to parsing SOFT line.""" - - def __init__(self, l): - """ - Create the exception by providing the problematic line. - - :param str l: the problematic SOFT line - """ - super(self, f"{l}") - - def main(): """Run the script.""" args = _parse_cmdl(sys.argv[1:]) From 2ce6b4831b3c20ce07282ccda888c3cec55d12bd Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 25 Oct 2022 12:58:46 -0400 Subject: [PATCH 54/61] refactored static function + docstring --- geofetch/cli.py | 50 ++-- geofetch/geofetch.py | 569 +++++++++++-------------------------------- geofetch/utils.py | 346 +++++++++++++++++++++++++- 3 files changed, 501 insertions(+), 464 deletions(-) diff --git a/geofetch/cli.py b/geofetch/cli.py index 53ed9f4..54ce083 100644 --- a/geofetch/cli.py +++ b/geofetch/cli.py @@ -55,16 +55,16 @@ def _parse_cmdl(cmdl): dest="metadata_root", default=_safe_echo("SRAMETA"), help="Specify a parent folder location to store metadata. " - "The project name will be added as a subfolder " - "[Default: $SRAMETA:" + _safe_echo("SRAMETA") + "]", + "The project name will be added as a subfolder " + "[Default: $SRAMETA:" + _safe_echo("SRAMETA") + "]", ) parser.add_argument( "-u", "--metadata-folder", help="Specify an absolute folder location to store metadata. " - "No subfolder will be added. Overrides value of --metadata-root " - "[Default: Not used (--metadata-root is used by default)]", + "No subfolder will be added. Overrides value of --metadata-root " + "[Default: Not used (--metadata-root is used by default)]", ) parser.add_argument( @@ -89,8 +89,8 @@ def _parse_cmdl(cmdl): "--pipeline-samples", default=None, help="Optional: Specify one or more filepaths to SAMPLES pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", ) # Optional @@ -98,8 +98,8 @@ def _parse_cmdl(cmdl): "--pipeline-project", default=None, help="Optional: Specify one or more filepaths to PROJECT pipeline interface yaml files. " - "These will be added to the project config file to make it immediately " - "compatible with looper. [Default: null]", + "These will be added to the project config file to make it immediately " + "compatible with looper. [Default: null]", ) # Optional parser.add_argument( @@ -121,7 +121,7 @@ def _parse_cmdl(cmdl): "--acc-anno", action="store_true", help="Optional: Produce annotation sheets for each accession." - " Project combined PEP for the whole project won't be produced.", + " Project combined PEP for the whole project won't be produced.", ) parser.add_argument( @@ -135,7 +135,7 @@ def _parse_cmdl(cmdl): type=int, default=50, help="Optional: Limit of the number of the constant sample characters " - "that should not be in project yaml. [Default: 50]", + "that should not be in project yaml. [Default: 50]", ) parser.add_argument( @@ -143,7 +143,7 @@ def _parse_cmdl(cmdl): type=int, default=250, help="Optional: Limit of the number of the constant sample characters " - "that should not be discarded [Default: 250]", + "that should not be discarded [Default: 250]", ) parser.add_argument( @@ -151,8 +151,8 @@ def _parse_cmdl(cmdl): type=int, default=500, help="Optional: Limit of the number of sample characters." - "Any attribute with more than X characters will truncate to the first X," - " where X is a number of characters [Default: 500]", + "Any attribute with more than X characters will truncate to the first X," + " where X is a number of characters [Default: 500]", ) parser.add_argument( @@ -175,17 +175,17 @@ def _parse_cmdl(cmdl): choices=["all", "samples", "series"], default="samples", help="Optional: Specifies the source of data on the GEO record" - " to retrieve processed data, which may be attached to the" - " collective series entity, or to individual samples. " - "Allowable values are: samples, series or both (all). " - "Ignored unless 'processed' flag is set. [Default: samples]", + " to retrieve processed data, which may be attached to the" + " collective series entity, or to individual samples. " + "Allowable values are: samples, series or both (all). " + "Ignored unless 'processed' flag is set. [Default: samples]", ) processed_group.add_argument( "--filter", default=None, help="Optional: Filter regex for processed filenames [Default: None]." - "Ignored unless 'processed' flag is set.", + "Ignored unless 'processed' flag is set.", ) processed_group.add_argument( @@ -204,8 +204,8 @@ def _parse_cmdl(cmdl): "--geo-folder", default=_safe_echo("GEODATA"), help="Optional: Specify a location to store processed GEO files." - " Ignored unless 'processed' flag is set." - "[Default: $GEODATA:" + _safe_echo("GEODATA") + "]", + " Ignored unless 'processed' flag is set." + "[Default: $GEODATA:" + _safe_echo("GEODATA") + "]", ) raw_group.add_argument( @@ -227,8 +227,8 @@ def _parse_cmdl(cmdl): help="""Optional: Specify folder of bam files. Geofetch will not download sra files when corresponding bam files already exist. [Default: $SRABAM:""" - + _safe_echo("SRABAM") - + "]", + + _safe_echo("SRABAM") + + "]", ) raw_group.add_argument( @@ -239,8 +239,8 @@ def _parse_cmdl(cmdl): help="""Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding fastq files already exist. [Default: $SRAFQ:""" - + _safe_echo("SRAFQ") - + "]", + + _safe_echo("SRAFQ") + + "]", ) # Deprecated; these are for bam conversion which now happens in sra_convert @@ -277,4 +277,4 @@ def _parse_cmdl(cmdl): ) logmuse.add_logging_options(parser) - return parser.parse_args(cmdl) \ No newline at end of file + return parser.parse_args(cmdl) diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 3dd374f..50d0a58 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -2,7 +2,6 @@ __author__ = ["Oleksandr Khoroshevskyi", "Vince Reuter", "Nathan Sheffield"] -import argparse import copy import csv import os @@ -24,13 +23,27 @@ convert_size, clean_soft_files, run_subprocess, + _get_list_of_keys, + _get_value, + _read_tar_filelist, + _check_file_existance, + _separate_list_of_files, + _update_columns, + _sanitize_name, + _sanitize_config_string, + _create_dot_yaml, + _which, + _dict_to_list_converter, + _standardize_colnames, + _separate_file_url, + _filter_gsm, + _unify_list_keys, ) from rich.progress import track import re import logmuse from ubiquerg import expandpath, is_command_callable -from io import StringIO from typing import List, Union, Dict, Tuple, NoReturn import peppy import pandas as pd @@ -39,64 +52,6 @@ class Geofetcher: """ Class to download or get projects, metadata, data from GEO and SRA - - :param input: - :param name: Specify a project name. Defaults to GSE number or name of accessions file name - :param metadata_root: Specify a parent folder location to store metadata. - The project name will be added as a subfolder [Default: $SRAMETA:] - :param metadata_folder: Specify an absolute folder location to store metadata. No subfolder will be added. - Overrides value of --metadata-root [Default: Not used (--metadata-root is used by default)] - :param just_metadata: If set, don't actually run downloads, just create metadata - :param refresh_metadata: If set, re-download metadata even if it exists. - :param config_template: Project config yaml file template. - :param pipeline_samples: Specify one or more filepaths to SAMPLES pipeline interface yaml files. - These will be added to the project config file to make it immediately compatible with looper. - [Default: null] - :param pipeline_project: Specify one or more filepaths to PROJECT pipeline interface yaml files. - These will be added to the project config file to make it immediately compatible with looper. - [Default: null] - :param acc_anno: Produce annotation sheets for each accession. - Project combined PEP for the whole project won't be produced. - :param discard_soft: Create project without downloading soft files on the disc - :param add_dotfile: Add .pep.yaml file that points .yaml PEP file - :param disable_progressbar: Set true to disable progressbar - - :param const_limit_project: Optional: Limit of the number of the constant sample characters - that should not be in project yaml. [Default: 50] - :param const_limit_discard: Optional: Limit of the number of the constant sample characters - that should not be discarded [Default: 250] - :param attr_limit_truncate: Optional: Limit of the number of sample characters. - Any attribute with more than X characters will truncate to the first X, where X is a number of characters - [Default: 500] - - :param processed: Download processed data [Default: download raw data]. - :param data_source: Specifies the source of data on the GEO record to retrieve processed data, - which may be attached to the collective series entity, or to individual samples. Allowable values are: - samples, series or both (all). Ignored unless 'processed' flag is set. [Default: samples] - :param filter: Filter regex for processed filenames [Default: None].Ignored unless 'processed' flag is set. - :param filter_size: Filter size for processed files that are stored as sample repository [Default: None]. - Works only for sample data. Supported input formats : 12B, 12KB, 12MB, 12GB. - Ignored unless 'processed' flag is set. - :param geo_folder: Specify a location to store processed GEO files. - Ignored unless 'processed' flag is set.[Default: $GEODATA:] - - :param split_experiments: Split SRR runs into individual samples. By default, SRX experiments with multiple SRR - Runs will have a single entry in the annotation table, with each run as a separate row in the - subannotation table. This setting instead treats each run as a separate sample [Works with raw data] - :param bam_folder: Optional: Specify folder of bam files. Geofetch will not download sra files when - corresponding bam files already exist. [Default: $SRABAM:] [Works with raw data] - :param fq_folder: Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding - fastq files already exist. [Default: $SRAFQ:] [Works with raw data] - :param use_key_subset: Use just the keys defined in this module when writing out metadata. [Works with raw data] - :param sra_folder: Optional: Specify a location to store sra files - [Default: $SRARAW:" + safe_echo("SRARAW") + ] - :param bam_conversion: Optional: set True to convert bam files [Works with raw data] - :param picard_path: Specify a path to the picard jar, if you want to convert fastq to bam - [Default: $PICARD:" + safe_echo("PICARD") + "] [Works with raw data] - - :param skip: Skip some accessions. [Default: no skip]. - :param opts: opts object [Optional] - :param kwargs: other values """ def __init__( @@ -133,6 +88,66 @@ def __init__( opts=None, **kwargs, ): + """ + init function + :param input: GSEnumber or path to the input file + :param name: Specify a project name. Defaults to GSE number or name of accessions file name + :param metadata_root: Specify a parent folder location to store metadata. + The project name will be added as a subfolder [Default: $SRAMETA:] + :param metadata_folder: Specify an absolute folder location to store metadata. No subfolder will be added. + Overrides value of --metadata-root [Default: Not used (--metadata-root is used by default)] + :param just_metadata: If set, don't actually run downloads, just create metadata + :param refresh_metadata: If set, re-download metadata even if it exists. + :param config_template: Project config yaml file template. + :param pipeline_samples: Specify one or more filepaths to SAMPLES pipeline interface yaml files. + These will be added to the project config file to make it immediately compatible with looper. + [Default: null] + :param pipeline_project: Specify one or more filepaths to PROJECT pipeline interface yaml files. + These will be added to the project config file to make it immediately compatible with looper. + [Default: null] + :param acc_anno: Produce annotation sheets for each accession. + Project combined PEP for the whole project won't be produced. + :param discard_soft: Create project without downloading soft files on the disc + :param add_dotfile: Add .pep.yaml file that points .yaml PEP file + :param disable_progressbar: Set true to disable progressbar + + :param const_limit_project: Optional: Limit of the number of the constant sample characters + that should not be in project yaml. [Default: 50] + :param const_limit_discard: Optional: Limit of the number of the constant sample characters + that should not be discarded [Default: 250] + :param attr_limit_truncate: Optional: Limit of the number of sample characters. + Any attribute with more than X characters will truncate to the first X, where X is a number of characters + [Default: 500] + + :param processed: Download processed data [Default: download raw data]. + :param data_source: Specifies the source of data on the GEO record to retrieve processed data, + which may be attached to the collective series entity, or to individual samples. Allowable values are: + samples, series or both (all). Ignored unless 'processed' flag is set. [Default: samples] + :param filter: Filter regex for processed filenames [Default: None].Ignored unless 'processed' flag is set. + :param filter_size: Filter size for processed files that are stored as sample repository [Default: None]. + Works only for sample data. Supported input formats : 12B, 12KB, 12MB, 12GB. + Ignored unless 'processed' flag is set. + :param geo_folder: Specify a location to store processed GEO files. + Ignored unless 'processed' flag is set.[Default: $GEODATA:] + + :param split_experiments: Split SRR runs into individual samples. By default, SRX experiments with multiple SRR + Runs will have a single entry in the annotation table, with each run as a separate row in the + subannotation table. This setting instead treats each run as a separate sample [Works with raw data] + :param bam_folder: Optional: Specify folder of bam files. Geofetch will not download sra files when + corresponding bam files already exist. [Default: $SRABAM:] [Works with raw data] + :param fq_folder: Optional: Specify folder of fastq files. Geofetch will not download sra files when corresponding + fastq files already exist. [Default: $SRAFQ:] [Works with raw data] + :param use_key_subset: Use just the keys defined in this module when writing out metadata. [Works with raw data] + :param sra_folder: Optional: Specify a location to store sra files + [Default: $SRARAW:" + safe_echo("SRARAW") + ] + :param bam_conversion: Optional: set True to convert bam files [Works with raw data] + :param picard_path: Specify a path to the picard jar, if you want to convert fastq to bam + [Default: $PICARD:" + safe_echo("PICARD") + "] [Works with raw data] + + :param skip: Skip some accessions. [Default: no skip]. + :param opts: opts object [Optional] + :param kwargs: other values + """ if opts is not None: _LOGGER = logmuse.logger_via_cli(opts) @@ -233,7 +248,7 @@ def __init__( self._LOGGER.info(f"Metadata folder: {self.metadata_expanded}") # Some sanity checks before proceeding - if bam_conversion and not just_metadata and not self._which("samtools"): + if bam_conversion and not just_metadata and not _which("samtools"): raise SystemExit("For SAM/BAM processing, samtools should be on PATH.") self.just_object = False @@ -308,8 +323,13 @@ def get_projects( return new_pr_dict - def fetch_all(self, input: str, name: str = None): - """Main script driver/workflow""" + def fetch_all(self, input: str, name: str = None) -> Union[NoReturn, peppy.Project]: + """ + Main script driver/workflow + :param input: GSE or input file with gse's + :param name: Name of the project + :return: NoReturn or peppy Project + """ if name is not None: self.project_name = name @@ -530,12 +550,12 @@ def _process_sra_meta( if not sample_name or sample_name == "": temp = gsm_metadata[experiment]["Sample_title"] - sample_name = self._sanitize_name(temp) + sample_name = _sanitize_name(temp) # Otherwise, record that there's SRA data for this run. # And set a few columns that are used as input to the Looper # print("Updating columns for looper") - self._update_columns( + _update_columns( gsm_metadata, experiment, sample_name=sample_name, @@ -584,7 +604,12 @@ def _process_sra_meta( return gsm_multi_table, gsm_metadata, runs - def _download_raw_data(self, run_name): + def _download_raw_data(self, run_name: str) -> NoReturn: + """ + Downloading raw data from SRA by providing run name + :param run_name: Run name from SRA + :return: NoReturn + """ bam_file = ( "" if self.bam_folder == "" @@ -613,7 +638,7 @@ def _download_raw_data(self, run_name): # converting sra to bam using # TODO: sam-dump has a built-in prefetch. I don't have to do # any of this stuff... This also solves the bad sam-dump issues. - self._sra_bam_conversion(bam_file, run_name) + self._sra_bam_conversion1(bam_file, run_name) # checking if bam_file converted correctly, if not --> use fastq-dump st = os.stat(bam_file) @@ -635,7 +660,7 @@ def fetchone_processed( gsm_filter_list: dict, ) -> Tuple: """ - Fetching just one processed GSE project + Fetching one processed GSE project :param gsm_file_content: gse soft file content :param gse_file_content: gsm soft file content :param gsm_filter_list: list of gsm that have to be downloaded @@ -647,9 +672,7 @@ def fetchone_processed( ) = self._get_list_of_processed_files(gse_file_content, gsm_file_content) # taking into account list of GSM that is specified in the input file - meta_processed_samples = self._filter_gsm( - meta_processed_samples, gsm_filter_list - ) + meta_processed_samples = _filter_gsm(meta_processed_samples, gsm_filter_list) # samples meta_processed_samples = self._expand_metadata_list(meta_processed_samples) @@ -658,8 +681,8 @@ def fetchone_processed( meta_processed_series = self._expand_metadata_list(meta_processed_series) # convert column names to lowercase and underscore - meta_processed_samples = self._standardize_colnames(meta_processed_samples) - meta_processed_series = self._standardize_colnames(meta_processed_series) + meta_processed_samples = _standardize_colnames(meta_processed_samples) + meta_processed_series = _standardize_colnames(meta_processed_series) return meta_processed_samples, meta_processed_series @@ -773,9 +796,9 @@ def _expand_metadata_list_in_dict(self, metadata_dict: dict) -> dict: :param metadata_dict: metadata dict :return: expanded metadata dict """ - prj_list = self._dict_to_list_convector(proj_dict=metadata_dict) + prj_list = _dict_to_list_converter(proj_dict=metadata_dict) prj_list = self._expand_metadata_list(prj_list) - return self._dict_to_list_convector(proj_list=prj_list) + return _dict_to_list_converter(proj_list=prj_list) def _expand_metadata_list(self, metadata_list: list) -> list: """ @@ -785,7 +808,7 @@ def _expand_metadata_list(self, metadata_list: list) -> list: :return list: expanded metadata list """ self._LOGGER.info("Expanding metadata list...") - list_of_keys = self._get_list_of_keys(metadata_list) + list_of_keys = _get_list_of_keys(metadata_list) for key_in_list in list_of_keys: metadata_list = self._expand_metadata_list_item(metadata_list, key_in_list) return metadata_list @@ -867,77 +890,6 @@ def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): self._LOGGER.warning("expand_metadata_list: Value Error: {err}") return metadata_list - def _filter_gsm(self, meta_processed_samples: list, gsm_list: dict) -> list: - """ - Getting metadata list of all samples of one experiment and filtering it - by the list of GSM that was specified in the input files. - And then changing names of the sample names. - - :param meta_processed_samples: list of metadata dicts of samples - :param gsm_list: list of dicts where GSM (samples) are keys and - sample names are values. Where values can be empty string - """ - - if gsm_list.keys(): - new_gsm_list = [] - for gsm_sample in meta_processed_samples: - if gsm_sample["Sample_geo_accession"] in gsm_list.keys(): - gsm_sample_new = gsm_sample - if gsm_list[gsm_sample["Sample_geo_accession"]] != "": - gsm_sample_new["sample_name"] = gsm_list[ - gsm_sample["Sample_geo_accession"] - ] - new_gsm_list.append(gsm_sample_new) - return new_gsm_list - return meta_processed_samples - - @staticmethod - def _get_list_of_keys(list_of_dict: list): - """ - Getting list of all keys that are in the dictionaries in the list - - :param list list_of_dict: list of dicts with metadata - :return list: list of dictionary keys - """ - - list_of_keys = [] - for element in list_of_dict: - list_of_keys.extend(list(element.keys())) - return list(set(list_of_keys)) - - def _unify_list_keys(self, processed_meta_list: list) -> list: - """ - Unifying list of dicts with metadata, so every dict will have - same keys - - :param list processed_meta_list: list of dicts with metadata - :return list: list of unified dicts with metadata - """ - list_of_keys = self._get_list_of_keys(processed_meta_list) - for k in list_of_keys: - for list_elem in range(len(processed_meta_list)): - if k not in processed_meta_list[list_elem]: - processed_meta_list[list_elem][k] = "" - return processed_meta_list - - def _find_genome(self, metadata_list): - """ - Create new genome column by searching joining few columns - """ - list_keys = self._get_list_of_keys(metadata_list) - genome_keys = [ - "assembly", - "genome_build", - ] - proj_gen_keys = list(set(list_keys).intersection(genome_keys)) - - for sample in enumerate(metadata_list): - sample_genome = "" - for key in proj_gen_keys: - sample_genome = " ".join([sample_genome, sample[1][key]]) - metadata_list[sample[0]][NEW_GENOME_COL_NAME] = sample_genome - return metadata_list - def _write_gsm_annotation(self, gsm_metadata: dict, file_annotation: str) -> str: """ Write metadata sheet out as an annotation file. @@ -990,7 +942,7 @@ def _write_processed_annotation( os.makedirs(pep_file_folder) self._LOGGER.info("Unifying and saving of metadata... ") - processed_metadata = self._unify_list_keys(processed_metadata) + processed_metadata = _unify_list_keys(processed_metadata) # delete rare keys processed_metadata = self._find_genome(processed_metadata) @@ -1023,7 +975,7 @@ def _write_processed_annotation( # save .pep.yaml file if self.add_dotfile: dot_yaml_path = os.path.join(pep_file_folder, ".pep.yaml") - self._create_dot_yaml(dot_yaml_path, yaml_name) + _create_dot_yaml(dot_yaml_path, yaml_name) return None @@ -1034,6 +986,27 @@ def _write_processed_annotation( proj = peppy.Project().from_pandas(pd_value, config=conf) return proj + @staticmethod + def _find_genome(metadata_list: list) -> list: + """ + Create new genome column by searching joining few columns + :param metadata_list: list with metadata dict + :return: list with metadata dict where genome column was added + """ + list_keys = _get_list_of_keys(metadata_list) + genome_keys = [ + "assembly", + "genome_build", + ] + proj_gen_keys = list(set(list_keys).intersection(genome_keys)) + + for sample in enumerate(metadata_list): + sample_genome = "" + for key in proj_gen_keys: + sample_genome = " ".join([sample_genome, sample[1][key]]) + metadata_list[sample[0]][NEW_GENOME_COL_NAME] = sample_genome + return metadata_list + def _write_raw_annotation_new( self, name, metadata_dict: dict, subannot_dict: dict = None ) -> Union[None, peppy.Project]: @@ -1104,7 +1077,7 @@ def _write_raw_annotation_new( self._write(proj_root_yaml, template, msg_pre=" Config file: ") if self.add_dotfile: - self._create_dot_yaml(dot_yaml_path, yaml_name) + _create_dot_yaml(dot_yaml_path, yaml_name) else: meta_df = pd.DataFrame.from_dict(metadata_dict, orient="index") @@ -1141,7 +1114,7 @@ def _create_config_processed( with open(config_template, "r") as template_file: template = template_file.read() meta_list_str = [ - f'{list(i.keys())[0]}: "{self._sanitize_config_string(list(i.values())[0])}"' + f'{list(i.keys())[0]}: "{_sanitize_config_string(list(i.values())[0])}"' for i in proj_meta ] modifiers_str = "\n ".join(d for d in meta_list_str) @@ -1167,7 +1140,7 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): :return: generated, complete config file content """ meta_list_str = [ - f'{list(i.keys())[0]}: "{self._sanitize_config_string(list(i.values())[0])}"' + f'{list(i.keys())[0]}: "{_sanitize_config_string(list(i.values())[0])}"' for i in proj_meta ] modifiers_str = "\n ".join(d for d in meta_list_str) @@ -1203,51 +1176,15 @@ def _check_sample_name_standard(self, metadata_dict: dict) -> dict: if value_sample["sample_name"] == "" or value_sample["sample_name"] is None: fixed_dict[key_sample]["sample_name"] = value_sample["Sample_title"] # sanitize names - fixed_dict[key_sample]["sample_name"] = self._sanitize_name( + fixed_dict[key_sample]["sample_name"] = _sanitize_name( fixed_dict[key_sample]["sample_name"] ) metadata_dict = fixed_dict - metadata_dict = self._standardize_colnames(metadata_dict) + metadata_dict = _standardize_colnames(metadata_dict) return metadata_dict @staticmethod - def _sanitize_config_string(text: str) -> str: - """ - Function that sanitizes text in config file. - :param text: Any string that have to be sanitized - :return: sanitized strings - """ - new_str = text - new_str = new_str.replace('"', f'\\"') - new_str = new_str.replace("'", f"''") - return new_str - - @staticmethod - def _sanitize_name(name_str: str) -> str: - """ - Function that sanitizes strings. (Replace all odd characters) - :param str name_str: Any string value that has to be sanitized. - :return: sanitized strings - """ - new_str = name_str - punctuation1 = r"""!"#$%&'()*,./:;<=>?@[\]^_`{|}~""" - for odd_char in list(punctuation1): - new_str = new_str.replace(odd_char, "_") - new_str = new_str.replace(" ", "_").replace("__", "_") - return new_str - - @staticmethod - def _create_dot_yaml(file_path: str, yaml_path: str) -> NoReturn: - """ - Function that creates .pep.yaml file that points to actual yaml file - :param str file_path: Path to the .pep.yaml file that we want to create - :param str yaml_path: path or name of the actual yaml file - """ - with open(file_path, "w+") as file: - file.writelines(f"config_file: {yaml_path}") - def _separate_common_meta( - self, meta_list: Union[List, Dict], max_len: int = 50, del_limit: int = 250, @@ -1267,9 +1204,9 @@ def _separate_common_meta( input_is_dict = False if isinstance(meta_list, dict): input_is_dict = True - meta_list = self._dict_to_list_convector(proj_dict=meta_list) + meta_list = _dict_to_list_converter(proj_dict=meta_list) - list_of_keys = self._get_list_of_keys(meta_list) + list_of_keys = _get_list_of_keys(meta_list) list_keys_diff = [] # finding columns with common values for this_key in list_of_keys: @@ -1323,70 +1260,9 @@ def _separate_common_meta( meta_list = new_list if input_is_dict: - meta_list = self._dict_to_list_convector(proj_list=meta_list) + meta_list = _dict_to_list_converter(proj_list=meta_list) return meta_list, new_meta_project - def _standardize_colnames(self, meta_list: Union[list, dict]) -> Union[list, dict]: - """ - Standardize column names by lower-casing and underscore - :param list meta_list: list of dictionaries of samples - :return : list of dictionaries of samples with standard colnames - """ - # check if meta_list is dict and converting it to list - input_is_dict = False - if isinstance(meta_list, dict): - input_is_dict = True - meta_list = self._dict_to_list_convector(proj_dict=meta_list) - - new_metalist = [] - list_keys = self._get_list_of_keys(meta_list) - for item_nb, values in enumerate(meta_list): - new_metalist.append({}) - for key in list_keys: - try: - new_key_name = key.lower().strip() - new_key_name = self._sanitize_name(new_key_name) - - new_metalist[item_nb][new_key_name] = values[key] - - except KeyError: - pass - - if input_is_dict: - new_metalist = self._dict_to_list_convector(proj_list=new_metalist) - - return new_metalist - - @staticmethod - def _dict_to_list_convector( - proj_dict: Dict = None, proj_list: List = None - ) -> Union[Dict, List]: - """ - Convector project dict to list and vice versa - :param proj_dict: project dictionary - :param proj_list: project list - :return: converted values - """ - if proj_dict is not None: - new_meta_list = [] - for key in proj_dict: - new_dict = proj_dict[key] - new_dict["big_key"] = key - new_meta_list.append(new_dict) - - meta_list = new_meta_list - - elif proj_list is not None: - new_sample_dict = {} - for sample in proj_list: - new_sample_dict[sample["big_key"]] = sample - meta_list = new_sample_dict - - else: - raise ValueError - - return meta_list - def _download_SRA_file(self, run_name: str): """ Downloading SRA file by ising 'prefetch' utility from the SRA Toolkit @@ -1415,28 +1291,7 @@ def _download_SRA_file(self, run_name: str): ) time.sleep(t * 2) - @staticmethod - def _which(program: str): - """ - return str: the path to a program to make sure it exists - """ - import os - - def is_exe(fp): - return os.path.isfile(fp) and os.access(fp, os.X_OK) - - fpath, fname = os.path.split(program) - if fpath: - if is_exe(program): - return program - else: - for path in os.environ["PATH"].split(os.pathsep): - path = path.strip('"') - exe_file = os.path.join(path, program) - if is_exe(exe_file): - return exe_file - - def _sra_bam_conversion(self, bam_file: str, run_name: str) -> NoReturn: + def _sra_bam_conversion1(self, bam_file: str, run_name: str) -> NoReturn: """ Converting of SRA file to BAM file by using samtools function "sam-dump" :param str bam_file: path to BAM file that has to be created @@ -1460,53 +1315,6 @@ def _sra_bam_conversion(self, bam_file: str, run_name: str) -> NoReturn: self._LOGGER.info(f"Conversion command: {cmd}") run_subprocess(cmd, shell=True) - @staticmethod - def _update_columns( - metadata: dict, experiment_name: str, sample_name: str, read_type: str - ) -> dict: - """ - Update the metadata associated with a particular experiment. - - For the experiment indicated, this function updates the value (mapping), - including new data and populating columns used by looper based on - existing values in the mapping. - - :param Mapping metadata: the key-value mapping to update - :param str experiment_name: name of the experiment from which these - data came and are associated; the key in the metadata mapping - for which the value is to be updated - :param str sample_name: name of the sample with which these data are - associated - :param str read_type: usually "single" or "paired," an indication of the - type of sequencing reads for this experiment - :return: updated metadata - """ - - exp = metadata[experiment_name] - - # Protocol-agnostic - exp["sample_name"] = sample_name - exp["protocol"] = exp["Sample_library_selection"] - exp["read_type"] = read_type - exp["organism"] = exp["Sample_organism_ch1"] - exp["data_source"] = "SRA" - exp["SRX"] = experiment_name - - # Protocol specified is lowercased prior to checking here to alleviate - # dependence on case for the value in the annotations file. - bisulfite_protocols = {"reduced representation": "RRBS", "random": "WGBS"} - - # Conditional on bisulfite sequencing - # print(":" + exp["Sample_library_strategy"] + ":") - # Try to be smart about some library methods, refining protocol if possible. - if exp["Sample_library_strategy"] == "Bisulfite-Seq": - # print("Parsing protocol") - proto = exp["Sample_library_selection"].lower() - if proto in bisulfite_protocols: - exp["protocol"] = bisulfite_protocols[proto] - - return exp - def _sra_bam_conversion2( self, bam_file: str, run_name: str, picard_path: str = None ) -> NoReturn: @@ -1623,7 +1431,7 @@ def _get_list_of_processed_files( for line in file_gse_content: if re.compile(r"!Series_geo_accession").search(line): - gse_numb = self._get_value(line) + gse_numb = _get_value(line) meta_processed_series["GSE"] = gse_numb found = re.findall(SER_SUPP_FILE_PATTERN, line) @@ -1670,7 +1478,7 @@ def _get_list_of_processed_files( nb = len(meta_processed_samples) - 1 for line_gsm in file_gsm_content: if line_gsm[0] == "^": - nb = len(self._check_file_existance(meta_processed_samples)) + nb = len(_check_file_existance(meta_processed_samples)) meta_processed_samples.append( {"files": [], "GSE": gse_numb} ) @@ -1714,13 +1522,11 @@ def _get_list_of_processed_files( if file_url_gsm != "NONE": meta_processed_samples[nb]["files"].append(file_url_gsm) - self._check_file_existance(meta_processed_samples) - meta_processed_samples = self._separate_list_of_files( - meta_processed_samples - ) - meta_processed_samples = self._separate_file_url( + _check_file_existance(meta_processed_samples) + meta_processed_samples = _separate_list_of_files( meta_processed_samples ) + meta_processed_samples = _separate_file_url(meta_processed_samples) self._LOGGER.info( f"\nTotal number of processed SAMPLES files found is: " @@ -1728,7 +1534,7 @@ def _get_list_of_processed_files( ) # expand meta_processed_samples with information about type and size - file_info_add = self._read_tar_filelist(filelist_raw_text) + file_info_add = _read_tar_filelist(filelist_raw_text) for index_nr in range(len(meta_processed_samples)): file_name = meta_processed_samples[index_nr]["file"] meta_processed_samples[index_nr].update( @@ -1767,8 +1573,8 @@ def _get_list_of_processed_files( f"IndexError in adding value to meta_processed_series: %s" % ind_err ) - meta_processed_series = self._separate_list_of_files(meta_processed_series) - meta_processed_series = self._separate_file_url(meta_processed_series) + meta_processed_series = _separate_list_of_files(meta_processed_series) + meta_processed_series = _separate_file_url(meta_processed_series) self._LOGGER.info( f"Total number of processed SERIES files found is: " f"%s" % str(len(meta_processed_series)) @@ -1778,66 +1584,6 @@ def _get_list_of_processed_files( return meta_processed_samples, meta_processed_series - @staticmethod - def _check_file_existance(meta_processed_sample: list): - """ - Checking if last element of the list has files. If list of files is empty deleting it - """ - nb = len(meta_processed_sample) - 1 - if nb > -1: - if len(meta_processed_sample[nb]["files"]) == 0: - del meta_processed_sample[nb] - nb -= 1 - return meta_processed_sample - - @staticmethod - def _separate_list_of_files(meta_list, col_name="files"): - """ - This method is separating list of files (dict value) or just simple dict - into two different dicts - """ - separated_list = [] - if isinstance(meta_list, list): - for meta_elem in meta_list: - for file_elem in meta_elem[col_name]: - new_dict = meta_elem.copy() - new_dict.pop(col_name, None) - new_dict["file"] = file_elem - separated_list.append(new_dict) - elif isinstance(meta_list, dict): - for file_elem in meta_list[col_name]: - new_dict = meta_list.copy() - new_dict.pop(col_name, None) - new_dict["file"] = file_elem - separated_list.append(new_dict) - else: - return TypeError("Incorrect type") - - return separated_list - - def _separate_file_url(self, meta_list): - """ - This method is adding dict key without file_name without path - """ - separated_list = [] - for meta_elem in meta_list: - new_dict = meta_elem.copy() - new_dict["file_url"] = meta_elem["file"] - new_dict["file"] = os.path.basename(meta_elem["file"]) - # new_dict["sample_name"] = os.path.basename(meta_elem["file"]) - try: - new_dict["sample_name"] = str(meta_elem["Sample_title"]) - if new_dict["sample_name"] == "" or new_dict["sample_name"] is None: - raise KeyError("sample_name Does not exist. Creating .. ") - except KeyError: - new_dict["sample_name"] = os.path.basename(meta_elem["file"]) - - # sanitize sample names - new_dict["sample_name"] = self._sanitize_name(new_dict["sample_name"]) - - separated_list.append(new_dict) - return separated_list - def _run_filter(self, meta_list, col_name="file"): """ If user specified filter it will filter all this files here by col_name @@ -1873,41 +1619,6 @@ def _run_size_filter(self, meta_list, col_name="file_size"): ) return filtered_list - @staticmethod - def _read_tar_filelist(raw_text: str): - """ - Creating list for supplementary files that are listed in "filelist.txt" - :param str raw_text: path to the file with information about files that are zipped ("filelist.txt") - :return dict: dict of supplementary file names and additional information - """ - f = StringIO(raw_text) - files_info = {} - csv_reader = csv.reader(f, delimiter="\t") - line_count = 0 - for row in csv_reader: - if line_count == 0: - name_index = row.index("Name") - size_index = row.index("Size") - type_index = row.index("Type") - - line_count += 1 - else: - files_info[row[name_index]] = { - "file_size": row[size_index], - "type": row[type_index], - } - - return files_info - - @staticmethod - def _get_value(all_line: str): - """ - :param all_line: string with key value. (e.g. '!Series_geo_accession = GSE188720') - :return: value (e.g. GSE188720) - """ - line_value = all_line.split("= ")[-1] - return line_value.split(": ")[-1].rstrip("\n") - def _download_processed_file(self, file_url: str, data_folder: str) -> bool: """ Given a url for a file, download it, and extract anything passing the filter. @@ -1993,7 +1704,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): try: # downloading metadata srp_list = self._get_SRP_list(acc_SRP) - srp_list = self._unify_list_keys(srp_list) + srp_list = _unify_list_keys(srp_list) if file_sra is not None and not self.discard_soft: with open(file_sra, "w") as m_file: dict_writer = csv.DictWriter(m_file, srp_list[0].keys()) diff --git a/geofetch/utils.py b/geofetch/utils.py index 7917c67..b8e4e08 100644 --- a/geofetch/utils.py +++ b/geofetch/utils.py @@ -6,6 +6,9 @@ import sys import re import requests +from io import StringIO +import csv +from typing import NoReturn, Dict, List, Union _LOGGER = logging.getLogger(__name__) @@ -19,7 +22,7 @@ } -def is_known_type(accn=None, typename=None): +def is_known_type(accn: str = None, typename: str = None): """ Determine if the given accession is of a known type. @@ -49,7 +52,7 @@ def parse_accessions(input_arg, metadata_folder, just_metadata=False): interested in from that GSE#. An empty sample list means we should get all samples from that GSE#. This loop will create this dict. - :param input_arg: + :param input_arg: Input argument (GSE, or file) :param str metadata_folder: path to folder for accession metadata :param bool just_metadata: whether to only process metadata, not the actual data associated with the accession @@ -119,13 +122,12 @@ def parse_accessions(input_arg, metadata_folder, just_metadata=False): return acc_GSE_list -def parse_SOFT_line(l): +def parse_SOFT_line(l: str) -> dict: """ Parse SOFT formatted line, returning a dictionary with the key-value pair. :param str l: A SOFT-formatted line to parse ( !key = value ) :return dict[str, str]: A python Dict object representing the key-value. - :raise InvalidSoftLineException: if given line can't be parsed as SOFT line """ elems = l[1:].split("=") return {elems[0].rstrip(): elems[1].lstrip()} @@ -134,7 +136,7 @@ def parse_SOFT_line(l): class AccessionException(Exception): """Exceptional condition(s) dealing with accession number(s).""" - def __init__(self, reason=""): + def __init__(self, reason: str = ""): """ Optionally provide explanation for exceptional condition. @@ -230,8 +232,12 @@ def fetch_metadata( return result_list @staticmethod - def _validate(accn): - """Determine if given value looks like an accession.""" + def _validate(accn: str): + """ + Determine if given value looks like an accession. + :param str accn: ordinary accession identifier. + :return: typename, number + """ typename, number = split_accn(accn) if len(typename) != 3: raise AccessionException( @@ -248,7 +254,7 @@ def _validate(accn): return typename, number @staticmethod - def accn_type_exception(accn, typename, include_known=True): + def accn_type_exception(accn: str, typename: str, include_known: bool = True): """ Create an exception instance based on an accession and a parsed unknown typename. @@ -266,7 +272,7 @@ def accn_type_exception(accn, typename, include_known=True): return AccessionException(message) -def split_accn(accn): +def split_accn(accn: str): """ Split accession into prefix and number, leaving suffix as text and converting the type prefix to uppercase. @@ -341,4 +347,324 @@ def run_subprocess(*args, **kwargs): sys.exit(1) -# file_gse_content +def _get_list_of_keys(list_of_dict: list): + """ + Getting list of all keys that are in the dictionaries in the list + + :param list list_of_dict: list of dicts with metadata + :return list: list of dictionary keys + """ + + list_of_keys = [] + for element in list_of_dict: + list_of_keys.extend(list(element.keys())) + return list(set(list_of_keys)) + + +def _get_value(all_line: str): + """ + :param all_line: string with key value. (e.g. '!Series_geo_accession = GSE188720') + :return: value (e.g. GSE188720) + """ + line_value = all_line.split("= ")[-1] + return line_value.split(": ")[-1].rstrip("\n") + + +def _read_tar_filelist(raw_text: str) -> dict: + """ + Creating list for supplementary files that are listed in "filelist.txt" + :param str raw_text: path to the file with information about files that are zipped ("filelist.txt") + :return dict: dict of supplementary file names and additional information + """ + f = StringIO(raw_text) + files_info = {} + csv_reader = csv.reader(f, delimiter="\t") + line_count = 0 + for row in csv_reader: + if line_count == 0: + name_index = row.index("Name") + size_index = row.index("Size") + type_index = row.index("Type") + + line_count += 1 + else: + files_info[row[name_index]] = { + "file_size": row[size_index], + "type": row[type_index], + } + + return files_info + + +def _check_file_existance(meta_processed_sample: list) -> list: + """ + Checking if last element of the list has files. If list of files is empty deleting it + :param: meta_processed_sample: list with metadata dictionary + :return: list with metadata dictionary after processing + """ + nb = len(meta_processed_sample) - 1 + if nb > -1: + if len(meta_processed_sample[nb]["files"]) == 0: + del meta_processed_sample[nb] + nb -= 1 + return meta_processed_sample + + +def _separate_list_of_files(meta_list: Union[list, dict], col_name: str = "files"): + """ + This method is separating list of files (dict value) or just simple dict + into two different dicts + :param col_name: column name that should be added with filenames + :param meta_list: list, or dict with metadata + """ + separated_list = [] + if isinstance(meta_list, list): + for meta_elem in meta_list: + for file_elem in meta_elem[col_name]: + new_dict = meta_elem.copy() + new_dict.pop(col_name, None) + new_dict["file"] = file_elem + separated_list.append(new_dict) + elif isinstance(meta_list, dict): + for file_elem in meta_list[col_name]: + new_dict = meta_list.copy() + new_dict.pop(col_name, None) + new_dict["file"] = file_elem + separated_list.append(new_dict) + else: + return TypeError("Incorrect type") + + return separated_list + + +def _update_columns( + metadata: dict, experiment_name: str, sample_name: str, read_type: str +) -> dict: + """ + Update the metadata associated with a particular experiment. + + For the experiment indicated, this function updates the value (mapping), + including new data and populating columns used by looper based on + existing values in the mapping. + + :param Mapping metadata: the key-value mapping to update + :param str experiment_name: name of the experiment from which these + data came and are associated; the key in the metadata mapping + for which the value is to be updated + :param str sample_name: name of the sample with which these data are + associated + :param str read_type: usually "single" or "paired," an indication of the + type of sequencing reads for this experiment + :return: updated metadata + """ + + exp = metadata[experiment_name] + + # Protocol-agnostic + exp["sample_name"] = sample_name + exp["protocol"] = exp["Sample_library_selection"] + exp["read_type"] = read_type + exp["organism"] = exp["Sample_organism_ch1"] + exp["data_source"] = "SRA" + exp["SRX"] = experiment_name + + # Protocol specified is lowercased prior to checking here to alleviate + # dependence on case for the value in the annotations file. + bisulfite_protocols = {"reduced representation": "RRBS", "random": "WGBS"} + + # Conditional on bisulfite sequencing + # print(":" + exp["Sample_library_strategy"] + ":") + # Try to be smart about some library methods, refining protocol if possible. + if exp["Sample_library_strategy"] == "Bisulfite-Seq": + # print("Parsing protocol") + proto = exp["Sample_library_selection"].lower() + if proto in bisulfite_protocols: + exp["protocol"] = bisulfite_protocols[proto] + + return exp + + +def _sanitize_config_string(text: str) -> str: + """ + Function that sanitizes text in config file. + :param text: Any string that have to be sanitized + :return: sanitized strings + """ + new_str = text + new_str = new_str.replace('"', f'\\"') + new_str = new_str.replace("'", f"''") + return new_str + + +def _sanitize_name(name_str: str) -> str: + """ + Function that sanitizes strings. (Replace all odd characters) + :param str name_str: Any string value that has to be sanitized. + :return: sanitized strings + """ + new_str = name_str + punctuation1 = r"""!"#$%&'()*,./:;<=>?@[\]^_`{|}~""" + for odd_char in list(punctuation1): + new_str = new_str.replace(odd_char, "_") + new_str = new_str.replace(" ", "_").replace("__", "_") + return new_str + + +def _create_dot_yaml(file_path: str, yaml_path: str) -> NoReturn: + """ + Function that creates .pep.yaml file that points to actual yaml file + :param str file_path: Path to the .pep.yaml file that we want to create + :param str yaml_path: path or name of the actual yaml file + """ + with open(file_path, "w+") as file: + file.writelines(f"config_file: {yaml_path}") + + +def _which(program: str): + """ + return str: the path to a program to make sure it exists + """ + import os + + def is_exe(fp): + return os.path.isfile(fp) and os.access(fp, os.X_OK) + + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + path = path.strip('"') + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + + +def _dict_to_list_converter( + proj_dict: Dict = None, proj_list: List = None +) -> Union[Dict, List]: + """ + Converter project dict to list and vice versa + dict -> list + list -> dict + :param proj_dict: project dictionary + :param proj_list: project list + :return: converted values + """ + if proj_dict is not None: + new_meta_list = [] + for key in proj_dict: + new_dict = proj_dict[key] + new_dict["big_key"] = key + new_meta_list.append(new_dict) + + meta_list = new_meta_list + + elif proj_list is not None: + new_sample_dict = {} + for sample in proj_list: + new_sample_dict[sample["big_key"]] = sample + meta_list = new_sample_dict + + else: + raise ValueError + + return meta_list + + +def _standardize_colnames(meta_list: Union[list, dict]) -> Union[list, dict]: + """ + Standardize column names by lower-casing and underscore + :param list meta_list: list of dictionaries of samples + :return : list of dictionaries of samples with standard colnames + """ + # check if meta_list is dict and converting it to list + input_is_dict = False + if isinstance(meta_list, dict): + input_is_dict = True + meta_list = _dict_to_list_converter(proj_dict=meta_list) + + new_metalist = [] + list_keys = _get_list_of_keys(meta_list) + for item_nb, values in enumerate(meta_list): + new_metalist.append({}) + for key in list_keys: + try: + new_key_name = key.lower().strip() + new_key_name = _sanitize_name(new_key_name) + + new_metalist[item_nb][new_key_name] = values[key] + + except KeyError: + pass + + if input_is_dict: + new_metalist = _dict_to_list_converter(proj_list=new_metalist) + + return new_metalist + + +def _separate_file_url(meta_list): + """ + This method is adding dict key without file_name without path + """ + separated_list = [] + for meta_elem in meta_list: + new_dict = meta_elem.copy() + new_dict["file_url"] = meta_elem["file"] + new_dict["file"] = os.path.basename(meta_elem["file"]) + # new_dict["sample_name"] = os.path.basename(meta_elem["file"]) + try: + new_dict["sample_name"] = str(meta_elem["Sample_title"]) + if new_dict["sample_name"] == "" or new_dict["sample_name"] is None: + raise KeyError("sample_name Does not exist. Creating .. ") + except KeyError: + new_dict["sample_name"] = os.path.basename(meta_elem["file"]) + + # sanitize sample names + new_dict["sample_name"] = _sanitize_name(new_dict["sample_name"]) + + separated_list.append(new_dict) + return separated_list + + +def _filter_gsm(meta_processed_samples: list, gsm_list: dict) -> list: + """ + Getting metadata list of all samples of one experiment and filtering it + by the list of GSM that was specified in the input files. + And then changing names of the sample names. + + :param meta_processed_samples: list of metadata dicts of samples + :param gsm_list: list of dicts where GSM (samples) are keys and + sample names are values. Where values can be empty string + """ + + if gsm_list.keys(): + new_gsm_list = [] + for gsm_sample in meta_processed_samples: + if gsm_sample["Sample_geo_accession"] in gsm_list.keys(): + gsm_sample_new = gsm_sample + if gsm_list[gsm_sample["Sample_geo_accession"]] != "": + gsm_sample_new["sample_name"] = gsm_list[ + gsm_sample["Sample_geo_accession"] + ] + new_gsm_list.append(gsm_sample_new) + return new_gsm_list + return meta_processed_samples + + +def _unify_list_keys(processed_meta_list: list) -> list: + """ + Unifying list of dicts with metadata, so every dict will have + same keys + + :param list processed_meta_list: list of dicts with metadata + :return list: list of unified dicts with metadata + """ + list_of_keys = _get_list_of_keys(processed_meta_list) + for k in list_of_keys: + for list_elem in range(len(processed_meta_list)): + if k not in processed_meta_list[list_elem]: + processed_meta_list[list_elem][k] = "" + return processed_meta_list From 924b5581586591e3ccac23e84fb0544298aa044b Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 25 Oct 2022 13:06:13 -0400 Subject: [PATCH 55/61] Adding comments to the config file --- geofetch/config_processed_template.yaml | 2 ++ geofetch/config_template.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/geofetch/config_processed_template.yaml b/geofetch/config_processed_template.yaml index 9f8eb38..1198863 100644 --- a/geofetch/config_processed_template.yaml +++ b/geofetch/config_processed_template.yaml @@ -11,6 +11,8 @@ sample_modifiers: {additional_columns} # End of project metadata {pipeline_samples} + + # adding file paths to the project derive: attributes: [output_file_path] sources: diff --git a/geofetch/config_template.yaml b/geofetch/config_template.yaml index 59fcaa2..de5ccf5 100644 --- a/geofetch/config_template.yaml +++ b/geofetch/config_template.yaml @@ -12,6 +12,8 @@ sample_modifiers: # End of project metadata SRR_files: SRA {pipeline_samples} + + # Adding additional infromation to the project derive: attributes: [read1, read2, SRR_files] sources: From 88b251c4410797b67b0c5a8826d3f4e562ac62cc Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 25 Oct 2022 16:53:32 -0400 Subject: [PATCH 56/61] making SRA looper optional --- MANIFEST.in | 1 + geofetch/cli.py | 6 +++++ geofetch/config_template.yaml | 45 +------------------------------- geofetch/const.py | 1 + geofetch/geofetch.py | 24 ++++++++++++----- geofetch/looper_sra_convert.yaml | 45 ++++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 51 deletions(-) create mode 100644 geofetch/looper_sra_convert.yaml diff --git a/MANIFEST.in b/MANIFEST.in index e704c91..4f3018a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,3 +3,4 @@ include README.md include docs/img/geofetch_logo.svg include geofetch/config_template.yaml include geofetch/config_processed_template.yaml +include geofetch/looper_sra_convert.yaml diff --git a/geofetch/cli.py b/geofetch/cli.py index 54ce083..1d5bcce 100644 --- a/geofetch/cli.py +++ b/geofetch/cli.py @@ -276,5 +276,11 @@ def _parse_cmdl(cmdl): help="Use just the keys defined in this module when writing out metadata.", ) + raw_group.add_argument( + "--add-convert-modifier", + action="store_true", + help="Add looper SRA convert modifier to config file.", + ) + logmuse.add_logging_options(parser) return parser.parse_args(cmdl) diff --git a/geofetch/config_template.yaml b/geofetch/config_template.yaml index de5ccf5..9de5e97 100644 --- a/geofetch/config_template.yaml +++ b/geofetch/config_template.yaml @@ -10,51 +10,8 @@ sample_modifiers: # Project metadata: {additional_columns} # End of project metadata - SRR_files: SRA {pipeline_samples} - # Adding additional infromation to the project - derive: - attributes: [read1, read2, SRR_files] - sources: - SRA: "${SRABAM}/{SRR}.bam" - FQ: "${SRAFQ}/{SRR}.fastq.gz" - FQ1: "${SRAFQ}/{SRR}_1.fastq.gz" - FQ2: "${SRAFQ}/{SRR}_2.fastq.gz" - imply: - - if: - organism: "Mus musculus" - then: - genome: mm10 - - if: - organism: "Homo sapiens" - then: - genome: hg38 - - if: - read_type: "PAIRED" - then: - read1: FQ1 - read2: FQ2 - - if: - read_type: "SINGLE" - then: - read1: FQ1 - -project_modifiers: - amend: - sra_convert: - looper: - results_subdir: sra_convert_results - sample_modifiers: - append: - SRR_files: SRA - pipeline_interfaces: ${CODE}/geofetch/pipeline_interface_convert.yaml - derive: - attributes: [read1, read2, SRR_files] - sources: - SRA: "${SRARAW}/{SRR}.sra" - FQ: "${SRAFQ}/{SRR}.fastq.gz" - FQ1: "${SRAFQ}/{SRR}_1.fastq.gz" - FQ2: "${SRAFQ}/{SRR}_2.fastq.gz" +{sra_convert} {pipeline_project} diff --git a/geofetch/const.py b/geofetch/const.py index 91669c3..2267223 100644 --- a/geofetch/const.py +++ b/geofetch/const.py @@ -46,6 +46,7 @@ CONFIG_PROCESSED_TEMPLATE_NAME = "config_processed_template.yaml" CONFIG_RAW_TEMPLATE_NAME = "config_template.yaml" +CONFIG_SRA_TEMPLATE = "looper_sra_convert.yaml" # const for Finder: RETMAX = 10000000 # once it should be increased diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 50d0a58..6122944 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -85,6 +85,7 @@ def __init__( discard_soft: bool = False, add_dotfile: bool = False, disable_progressbar: bool = False, + add_convert_modifier: bool = False, opts=None, **kwargs, ): @@ -143,6 +144,7 @@ def __init__( :param bam_conversion: Optional: set True to convert bam files [Works with raw data] :param picard_path: Specify a path to the picard jar, if you want to convert fastq to bam [Default: $PICARD:" + safe_echo("PICARD") + "] [Works with raw data] + :param add_convert_modifier: Add looper SRA convert modifier to config file. :param skip: Skip some accessions. [Default: no skip]. :param opts: opts object [Optional] @@ -244,7 +246,7 @@ def __init__( self.discard_soft = discard_soft self.add_dotfile = add_dotfile self.disable_progressbar = disable_progressbar - + self.add_convert_modifier = add_convert_modifier self._LOGGER.info(f"Metadata folder: {self.metadata_expanded}") # Some sanity checks before proceeding @@ -638,7 +640,7 @@ def _download_raw_data(self, run_name: str) -> NoReturn: # converting sra to bam using # TODO: sam-dump has a built-in prefetch. I don't have to do # any of this stuff... This also solves the bad sam-dump issues. - self._sra_bam_conversion1(bam_file, run_name) + self._sra_to_bam_conversion_sam_dump(bam_file, run_name) # checking if bam_file converted correctly, if not --> use fastq-dump st = os.stat(bam_file) @@ -646,7 +648,7 @@ def _download_raw_data(self, run_name: str) -> NoReturn: self._LOGGER.warning( "Bam conversion failed with sam-dump. Trying fastq-dump..." ) - self._sra_bam_conversion2(bam_file, run_name, self.picard_path) + self._sra_to_bam_conversion_fastq_damp(bam_file, run_name, self.picard_path) except FileNotFoundError as err: self._LOGGER.info( @@ -1145,9 +1147,15 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): ] modifiers_str = "\n ".join(d for d in meta_list_str) # Write project config file + geofetchdir = os.path.dirname(__file__) if not self.config_template: - geofetchdir = os.path.dirname(__file__) self.config_template = os.path.join(geofetchdir, CONFIG_RAW_TEMPLATE_NAME) + if self.add_convert_modifier: + sra_convert_path = os.path.join(geofetchdir, CONFIG_SRA_TEMPLATE) + with open(sra_convert_path, "r") as template_file: + sra_convert_template = template_file.read() + else: + sra_convert_template = "" with open(self.config_template, "r") as template_file: template = template_file.read() template_values = { @@ -1157,13 +1165,15 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): "pipeline_samples": self.file_pipeline_samples, "pipeline_project": self.file_pipeline_project, "additional_columns": modifiers_str, + "sra_convert": sra_convert_template, } for k, v in template_values.items(): placeholder = "{" + str(k) + "}" template = template.replace(placeholder, str(v)) return template - def _check_sample_name_standard(self, metadata_dict: dict) -> dict: + @staticmethod + def _check_sample_name_standard(metadata_dict: dict) -> dict: """ Standardizing sample name and checking if it exists (This function is used for raw data) @@ -1291,7 +1301,7 @@ def _download_SRA_file(self, run_name: str): ) time.sleep(t * 2) - def _sra_bam_conversion1(self, bam_file: str, run_name: str) -> NoReturn: + def _sra_to_bam_conversion_sam_dump(self, bam_file: str, run_name: str) -> NoReturn: """ Converting of SRA file to BAM file by using samtools function "sam-dump" :param str bam_file: path to BAM file that has to be created @@ -1315,7 +1325,7 @@ def _sra_bam_conversion1(self, bam_file: str, run_name: str) -> NoReturn: self._LOGGER.info(f"Conversion command: {cmd}") run_subprocess(cmd, shell=True) - def _sra_bam_conversion2( + def _sra_to_bam_conversion_fastq_damp( self, bam_file: str, run_name: str, picard_path: str = None ) -> NoReturn: """ diff --git a/geofetch/looper_sra_convert.yaml b/geofetch/looper_sra_convert.yaml new file mode 100644 index 0000000..bf5905d --- /dev/null +++ b/geofetch/looper_sra_convert.yaml @@ -0,0 +1,45 @@ + # Adding sra convert looper pipeline + SRR_files: SRA + + derive: + attributes: [read1, read2, SRR_files] + sources: + SRA: "${SRABAM}/{SRR}.bam" + FQ: "${SRAFQ}/{SRR}.fastq.gz" + FQ1: "${SRAFQ}/{SRR}_1.fastq.gz" + FQ2: "${SRAFQ}/{SRR}_2.fastq.gz" + imply: + - if: + organism: "Mus musculus" + then: + genome: mm10 + - if: + organism: "Homo sapiens" + then: + genome: hg38 + - if: + read_type: "PAIRED" + then: + read1: FQ1 + read2: FQ2 + - if: + read_type: "SINGLE" + then: + read1: FQ1 + +project_modifiers: + amend: + sra_convert: + looper: + results_subdir: sra_convert_results + sample_modifiers: + append: + SRR_files: SRA + pipeline_interfaces: ${CODE}/geofetch/pipeline_interface_convert.yaml + derive: + attributes: [read1, read2, SRR_files] + sources: + SRA: "${SRARAW}/{SRR}.sra" + FQ: "${SRAFQ}/{SRR}.fastq.gz" + FQ1: "${SRAFQ}/{SRR}_1.fastq.gz" + FQ2: "${SRAFQ}/{SRR}_2.fastq.gz" From 360356a2c47fad08914815e150aad6e93c50b545 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 25 Oct 2022 21:52:01 -0400 Subject: [PATCH 57/61] docstring corrections --- geofetch/finder.py | 25 +++++++++---------------- geofetch/geofetch.py | 41 +++++++++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/geofetch/finder.py b/geofetch/finder.py index eeb105b..0cbd460 100644 --- a/geofetch/finder.py +++ b/geofetch/finder.py @@ -27,16 +27,17 @@ class Finder: """ - Class for finding GSE accessions in special period of time - Additionally user can add specific filters for the search. + Class for finding GSE accessions in special period of time. + Additionally, user can add specific filters for the search, + while initialization of the class """ def __init__(self, filters: str = None, retmax: int = RETMAX): """ - :param filters: filters that have to be added to query. + :param filters: filters that have to be added to the query. Filter Patterns can be found here: https://www.ncbi.nlm.nih.gov/books/NBK3837/#EntrezHelp.Using_the_Advanced_Search_Pag - :param retmax: maximum items should be retrieved + :param retmax: maximum number of retrieved accessions. """ self.query_customized_ending = ETOOLS_ENDING.format(retmax=retmax) self.query_filter_str = self._create_filter_str(filters) @@ -65,8 +66,8 @@ def get_gse_last_week(self) -> list: def get_gse_by_day_count(self, n_days: int = 1) -> list: """ - Get list of gse accession that were uploaded or updated in last specified number of days - :param n_days: number of days from now + Get list of gse accessions that were uploaded or updated in last X days + :param n_days: number of days from now [e.g. 5] :return: list of gse accession """ today = datetime.today() @@ -88,7 +89,7 @@ def get_gse_by_date(self, start_date: str, end_date: str = None) -> list: def get_gse_id_by_query(self, url: str) -> list: """ - Use esearch query to find uids and then convert them to gse ids + Run esearch (ncbi search tool) by specifying URL and retrieve gse list result :param url: url of the query :return: list of gse ids """ @@ -101,20 +102,12 @@ def get_gse_id_by_query(self, url: str) -> list: def uid_to_gse(uid: str) -> str: """ UID to GES accession converter - :param uid: uid string + :param uid: uid string (Unique Identifier Number in GEO) :return: GSE id string """ uid_regex = re.compile(r"[1-9]+0+([1-9]+[0-9]*)") return "GSE" + uid_regex.match(uid).group(1) - def read_file(self, file_path: str) -> list: - """ - Getting list of gse's from file by specifying a file path - :param file_path: path to the file - :return: list of gse's - """ - pass - @staticmethod def find_differences(old_list: list, new_list: list) -> list: """ diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 6122944..1c2e6cc 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -327,7 +327,8 @@ def get_projects( def fetch_all(self, input: str, name: str = None) -> Union[NoReturn, peppy.Project]: """ - Main script driver/workflow + Main function driver/workflow + Function that search, filters, downloads and save data and metadata from GEO and SRA :param input: GSE or input file with gse's :param name: Name of the project :return: NoReturn or peppy Project @@ -423,7 +424,7 @@ def fetch_all(self, input: str, name: str = None) -> Union[NoReturn, peppy.Proje ( meta_processed_samples, meta_processed_series, - ) = self.fetchone_processed( + ) = self.fetch_processed_one( gse_file_content=file_gse_content, gsm_file_content=file_gsm_content, gsm_filter_list=gsm_enter_dict, @@ -648,21 +649,23 @@ def _download_raw_data(self, run_name: str) -> NoReturn: self._LOGGER.warning( "Bam conversion failed with sam-dump. Trying fastq-dump..." ) - self._sra_to_bam_conversion_fastq_damp(bam_file, run_name, self.picard_path) + self._sra_to_bam_conversion_fastq_damp( + bam_file, run_name, self.picard_path + ) except FileNotFoundError as err: self._LOGGER.info( f"SRA file doesn't exist, please download it first: {err}" ) - def fetchone_processed( + def fetch_processed_one( self, gse_file_content: list, gsm_file_content: list, gsm_filter_list: dict, ) -> Tuple: """ - Fetching one processed GSE project + Fetching one processed GSE project and return its metadata :param gsm_file_content: gse soft file content :param gse_file_content: gsm soft file content :param gsm_filter_list: list of gsm that have to be downloaded @@ -755,7 +758,7 @@ def _download_processed_data( self, acc_gse: str, meta_processed_samples: list, meta_processed_series: list ) -> NoReturn: """ - Function that downloads processed data + Download processed data from GEO by providing project annotation list :param acc_gse: accession number of the project :param meta_processed_samples: list of annotation of samples :param meta_processed_series: list of annotation of series @@ -791,7 +794,7 @@ def _download_processed_data( for file_url in processed_series_files: self._download_processed_file(file_url, data_geo_folder) - def _expand_metadata_list_in_dict(self, metadata_dict: dict) -> dict: + def _expand_metadata_dict(self, metadata_dict: dict) -> dict: """ Expanding all lists of all items in the dict by creating new items or joining them @@ -1106,7 +1109,7 @@ def _create_config_processed( self, file_annotation_path: str, proj_meta: list ) -> str: """ - completing and generating config file content + Composing and generating config file content :param file_annotation_path: root to the annotation file :param proj_meta: common metadata that has to added to config file :return: generated, complete config file content @@ -1135,7 +1138,7 @@ def _create_config_processed( def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): """ - completing and generating config file content for raw data + Composing and generating config file content for raw data :param proj_meta: root to the annotation file :param proj_root_sample: path to sampletable file :param subanot_path_yaml: path to subannotation file @@ -1201,7 +1204,7 @@ def _separate_common_meta( attr_limit_truncate: int = 500, ) -> tuple: """ - This function is separating information for the experiment from a sample + This function is separating experiment(project) metadata from sample metadata :param list or dict meta_list: list of dictionaries of samples :param int max_len: threshold of the length of the common value that can be stored in the sample table :param int del_limit: threshold of the length of the common value that have to be deleted @@ -1399,7 +1402,7 @@ def _download_file( self, file_url: str, data_folder: str, new_name: str = None, sleep_after=0.5 ) -> NoReturn: """ - Given an url for a file, downloading to specified folder + Given an url for a file, downloading file to specified folder :param str file_url: the URL of the file to download :param str data_folder: path to the folder where data should be downloaded :param float sleep_after: time to sleep after downloading @@ -1594,9 +1597,12 @@ def _get_list_of_processed_files( return meta_processed_samples, meta_processed_series - def _run_filter(self, meta_list, col_name="file"): + def _run_filter(self, meta_list: list, col_name: str = "file") -> list: """ - If user specified filter it will filter all this files here by col_name + Filters files and metadata using Regular expression filter + :param meta_list: list of composed metadata + :param col_name: name of the column where file names are stored + :return: metadata list after file_name filter """ filtered_list = [] for meta_elem in meta_list: @@ -1611,7 +1617,10 @@ def _run_filter(self, meta_list, col_name="file"): def _run_size_filter(self, meta_list, col_name="file_size"): """ - function for filtering file size + Filters files and metadata by file size column specified in meta_list + :param meta_list: list of composed metadata + :param col_name: name of the column where is size information stored + :return: metadata list after size filter """ if self.filter_size is not None: filtered_list = [] @@ -1756,7 +1765,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): def _get_SRP_list(self, srp_number: str) -> list: """ - By using requests and xml searching and getting list of dicts of SRRs + Getting list of srp by using requests and xml searching and getting list of dicts of SRRs :param str srp_number: SRP number :return: list of dicts of SRRs """ @@ -1879,7 +1888,7 @@ def _read_gsm_metadata( current_sample_srx = True # GSM SOFT file parsed, save it in a list self._LOGGER.info(f"Processed {len(samples_list)} samples.") - gsm_metadata = self._expand_metadata_list_in_dict(gsm_metadata) + gsm_metadata = self._expand_metadata_dict(gsm_metadata) return gsm_metadata def _write( From 54107e327575e00e3c45d82b5195012cda0dd4c3 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Tue, 25 Oct 2022 22:21:24 -0400 Subject: [PATCH 58/61] docstring corrections 2 --- geofetch/finder.py | 8 ++++---- geofetch/geofetch.py | 32 ++++++++++++++++---------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/geofetch/finder.py b/geofetch/finder.py index 0cbd460..1882e11 100644 --- a/geofetch/finder.py +++ b/geofetch/finder.py @@ -111,7 +111,7 @@ def uid_to_gse(uid: str) -> str: @staticmethod def find_differences(old_list: list, new_list: list) -> list: """ - Comparing 2 lists and searching for elements that are not in old list + Compare 2 lists and search for elements that are not in old list :param old_list: old list of elements :param new_list: new list of elements :return: list of elements that are not in old list but are in new_list @@ -141,7 +141,7 @@ def _run_search_query(url: str) -> list: @staticmethod def _create_filter_str(filters: str = None) -> str: """ - Tuning filter for url request + Tune filter for url request :param filters: filter should look like here: https://www.ncbi.nlm.nih.gov/books/NBK3837/#EntrezHelp.Using_the_Advanced_Search_Pag :return: tuned filter string """ @@ -151,7 +151,7 @@ def _create_filter_str(filters: str = None) -> str: def _compose_url(self, date_filter: str = None) -> str: """ - Composing final url by adding date filter + Compose final url by adding date filter :param date_filter: date filter that has to be used in the query :return: string of final url """ @@ -162,7 +162,7 @@ def _compose_url(self, date_filter: str = None) -> str: def generate_file(self, file_path: str, gse_list: list = None): """ - Saving list of gse numbers to the file + Save the list of GSE accessions stored in this Finder object to a given file :param file_path: root to the file where gse accessions have to be saved :param gse_list: list of gse accessions :return: NoReturn diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index 1c2e6cc..eb6c144 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -527,7 +527,7 @@ def _process_sra_meta( gsm_metadata: dict = None, ): """ - Creating srp multitable and updating gsm_metadata based on srp + Create srp multitable and update gsm_metadata based on srp :param srp_list_result: list of srp got from sra file :param gsm_enter_dict: gsm enter content :param gsm_metadata: dict of samples of gsm @@ -609,7 +609,7 @@ def _process_sra_meta( def _download_raw_data(self, run_name: str) -> NoReturn: """ - Downloading raw data from SRA by providing run name + Downloade raw data from SRA by providing run name :param run_name: Run name from SRA :return: NoReturn """ @@ -665,7 +665,7 @@ def fetch_processed_one( gsm_filter_list: dict, ) -> Tuple: """ - Fetching one processed GSE project and return its metadata + Fetche one processed GSE project and return its metadata :param gsm_file_content: gse soft file content :param gse_file_content: gsm soft file content :param gsm_filter_list: list of gsm that have to be downloaded @@ -796,7 +796,7 @@ def _download_processed_data( def _expand_metadata_dict(self, metadata_dict: dict) -> dict: """ - Expanding all lists of all items in the dict by creating new items or joining them + Expand all lists of all items in the dict by creating new items or joining them :param metadata_dict: metadata dict :return: expanded metadata dict @@ -820,7 +820,7 @@ def _expand_metadata_list(self, metadata_list: list) -> list: def _expand_metadata_list_item(self, metadata_list: list, dict_key: str): """ - Expanding list of one element (item) in the list by creating new items or joining them + Expand list of one element (item) in the list by creating new items or joining them ["first1: fff", ...] -> separate columns :param list metadata_list: list of dicts that store metadata @@ -928,7 +928,7 @@ def _write_processed_annotation( just_object: bool = False, ) -> Union[NoReturn, peppy.Project]: """ - Saving annotation file by providing list of dictionaries with files metadata + Save annotation file by providing list of dictionaries with files metadata :param list processed_metadata: list of dictionaries with files metadata :param str file_annotation_path: the path to the metadata file that has to be saved :type just_object: True, if you want to get peppy object without saving file @@ -1016,7 +1016,7 @@ def _write_raw_annotation_new( self, name, metadata_dict: dict, subannot_dict: dict = None ) -> Union[None, peppy.Project]: """ - Combining individual accessions into project-level annotations, and writing + Combine individual accessions into project-level annotations, and writing individual accession files (if requested) :param name: Name of the run, project, or acc --> will influence name of the folder where project will be created :param metadata_dict: dictionary of sample annotations @@ -1109,7 +1109,7 @@ def _create_config_processed( self, file_annotation_path: str, proj_meta: list ) -> str: """ - Composing and generating config file content + Compose and generate config file content :param file_annotation_path: root to the annotation file :param proj_meta: common metadata that has to added to config file :return: generated, complete config file content @@ -1138,7 +1138,7 @@ def _create_config_processed( def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): """ - Composing and generating config file content for raw data + Compose and generate config file content for raw data :param proj_meta: root to the annotation file :param proj_root_sample: path to sampletable file :param subanot_path_yaml: path to subannotation file @@ -1178,7 +1178,7 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): @staticmethod def _check_sample_name_standard(metadata_dict: dict) -> dict: """ - Standardizing sample name and checking if it exists + Standardize sample name and checking if it exists (This function is used for raw data) :param metadata_dict: metadata dict :return: metadata dict with standardize sample names @@ -1204,7 +1204,7 @@ def _separate_common_meta( attr_limit_truncate: int = 500, ) -> tuple: """ - This function is separating experiment(project) metadata from sample metadata + Separate experiment(project) metadata from sample metadata :param list or dict meta_list: list of dictionaries of samples :param int max_len: threshold of the length of the common value that can be stored in the sample table :param int del_limit: threshold of the length of the common value that have to be deleted @@ -1278,7 +1278,7 @@ def _separate_common_meta( def _download_SRA_file(self, run_name: str): """ - Downloading SRA file by ising 'prefetch' utility from the SRA Toolkit + Download SRA file by ising 'prefetch' utility from the SRA Toolkit more info: (http://www.ncbi.nlm.nih.gov/books/NBK242621/) :param str run_name: SRR number of the SRA file """ @@ -1306,7 +1306,7 @@ def _download_SRA_file(self, run_name: str): def _sra_to_bam_conversion_sam_dump(self, bam_file: str, run_name: str) -> NoReturn: """ - Converting of SRA file to BAM file by using samtools function "sam-dump" + Convert SRA file to BAM file by using samtools function "sam-dump" :param str bam_file: path to BAM file that has to be created :param str run_name: SRR number of the SRA file that has to be converted """ @@ -1332,7 +1332,7 @@ def _sra_to_bam_conversion_fastq_damp( self, bam_file: str, run_name: str, picard_path: str = None ) -> NoReturn: """ - Converting of SRA file to BAM file by using fastq-dump + Convert SRA file to BAM file by using fastq-dump (is used when sam-dump fails, yielding an empty bam file. Here fastq -> bam conversion is used) :param str bam_file: path to BAM file that has to be created :param str run_name: SRR number of the SRA file that has to be converted @@ -1373,7 +1373,7 @@ def _write_subannotation( self, tabular_data: dict, filepath: str, column_names: list = None ): """ - Writes one or more tables to a given CSV filepath. + Write one or more tables to a given CSV filepath. :param tabular_data: Mapping | Iterable[Mapping]: single KV pair collection, or collection of such collections, to write to disk as tabular data @@ -1765,7 +1765,7 @@ def _get_SRA_meta(self, file_gse_content: list, gsm_metadata, file_sra=None): def _get_SRP_list(self, srp_number: str) -> list: """ - Getting list of srp by using requests and xml searching and getting list of dicts of SRRs + Get a list of srp by using requests and xml searching and getting list of dicts of SRRs :param str srp_number: SRP number :return: list of dicts of SRRs """ From 6ef994660bec583cd90027eff0dfe38b74fb0bdc Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 26 Oct 2022 16:00:13 -0400 Subject: [PATCH 59/61] raw config correction --- geofetch/config_template.yaml | 3 +-- geofetch/geofetch.py | 6 ++++++ mkdocs.yml | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/geofetch/config_template.yaml b/geofetch/config_template.yaml index 9de5e97..588d81a 100644 --- a/geofetch/config_template.yaml +++ b/geofetch/config_template.yaml @@ -5,8 +5,7 @@ pep_version: 2.1.0 sample_table: {annotation} {subannotation} -sample_modifiers: - append: +{sample_modifier_str} # Project metadata: {additional_columns} # End of project metadata diff --git a/geofetch/geofetch.py b/geofetch/geofetch.py index eb6c144..ecb0480 100755 --- a/geofetch/geofetch.py +++ b/geofetch/geofetch.py @@ -1151,6 +1151,11 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): modifiers_str = "\n ".join(d for d in meta_list_str) # Write project config file geofetchdir = os.path.dirname(__file__) + + if self.file_pipeline_samples or modifiers_str != "": + sample_modifier_str = "sample_modifiers:\n append:" + else: + sample_modifier_str = "" if not self.config_template: self.config_template = os.path.join(geofetchdir, CONFIG_RAW_TEMPLATE_NAME) if self.add_convert_modifier: @@ -1165,6 +1170,7 @@ def _create_config_raw(self, proj_meta, proj_root_sample, subanot_path_yaml): "project_name": self.project_name, "annotation": os.path.basename(proj_root_sample), "subannotation": subanot_path_yaml, + "sample_modifier_str": sample_modifier_str, "pipeline_samples": self.file_pipeline_samples, "pipeline_project": self.file_pipeline_project, "additional_columns": modifiers_str, diff --git a/mkdocs.yml b/mkdocs.yml index 69b5a07..e6bb189 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,8 +12,8 @@ nav: - Tutorials: - Tutorial for processed data: processed-data-downloading.md - Tutorial for raw data: raw-data-downloading.md - - Python geofetch tutorial: python-usage.md - - Use GSE Finder: gse_finder.md + - geofetch API tutorial: python-usage.md + - GSE Finder: gse_finder.md - How-to Guides: - Specifying samples to download: file-specification.md - Set SRA data download location: howto-location.md From 25fca873cb1a1e94ea7d544d94a807ab1bdc3fbb Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 26 Oct 2022 17:23:07 -0400 Subject: [PATCH 60/61] Corrected readme files --- docs/README.md | 6 ++++-- docs/changelog.md | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index b2e711b..7b87b32 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,9 @@ Key geofetch advantages: - Standardizes output metadata - Filters type and size of processed files (from GEO) before downloading them - Easy to use -- Fast execution +- Fast execution time +- Can search GEO to find relevant data +- Can be used either as a command-line tool or from within Python using an API ## Quick example @@ -54,7 +56,7 @@ geofetch -i GSE95654 --processed --just-metadata ![](./img/arguments_outputs.svg) --- -### New features available in geofetch 0.11.0 : +### New features available in geofetch 0.11.0: 1) Now geofetch is available as Python API package. Geofetch can initialize [peppy](http://peppy.databio.org/) projects without downloading any soft files. Example: ```python diff --git a/docs/changelog.md b/docs/changelog.md index e5d3406..7f2ef68 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,15 +1,17 @@ # Changelog -## [0.11.0] -- 2022-09-06 -- Added initialization of peppy Project without saving any files +## [0.11.0] -- 2022-10-26 +- Added initialization of peppy Project without saving any files (from within Python using an API) - Added Finder (searching GSE tool) - Added progress bar -- Fixed None issue in config file - Switched way of saving soft files to request library -- Fixed saving raw peps bug -- Fixed config errors - Improved documentation - Refactored code +- Added `--add-convert-modifier` flag +- fixed looper amendments in the config file +- Fixed special character bug in the config file +- Fixed None issue in config file +- Fixed saving raw peps bug ## [0.10.1] -- 2022-08-04 - Updated metadata fetching requests from SRA database From b91329be7f3a76aa5fd9d4699e145634d0b40bce Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Wed, 26 Oct 2022 17:30:36 -0400 Subject: [PATCH 61/61] Corrected readme files 2 --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index e6bb189..dfc6c83 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,7 +12,7 @@ nav: - Tutorials: - Tutorial for processed data: processed-data-downloading.md - Tutorial for raw data: raw-data-downloading.md - - geofetch API tutorial: python-usage.md + - geofetch from within Python: python-usage.md - GSE Finder: gse_finder.md - How-to Guides: - Specifying samples to download: file-specification.md