diff --git a/packages/compare-images/typescript/package.json b/packages/compare-images/typescript/package.json index a1d6f4ddb..1ff390261 100644 --- a/packages/compare-images/typescript/package.json +++ b/packages/compare-images/typescript/package.json @@ -62,4 +62,4 @@ "type": "git", "url": "https://github.com/InsightSoftwareConsortium/itk-wasm" } -} +} \ No newline at end of file diff --git a/packages/dicom/CMakeLists.txt b/packages/dicom/CMakeLists.txt index 98f92c8d6..cb25a8a74 100644 --- a/packages/dicom/CMakeLists.txt +++ b/packages/dicom/CMakeLists.txt @@ -4,4 +4,15 @@ project(itkwasm-dicom) set(CMAKE_CXX_STANDARD 17) add_subdirectory(gdcm) -add_subdirectory(dcmtk) \ No newline at end of file +add_subdirectory(dcmtk) + +enable_testing() + +add_test(NAME image-sets-normalization-help COMMAND image-sets-normalization --help) + +add_test(NAME image-sets-normalization-smoke + COMMAND image-sets-normalization image-sets.json --files + ${CMAKE_CURRENT_SOURCE_DIR}/test/data/input/DicomImageOrientationTest/ImageOrientation.1.dcm + ${CMAKE_CURRENT_SOURCE_DIR}/test/data/input/DicomImageOrientationTest/ImageOrientation.2.dcm + ${CMAKE_CURRENT_SOURCE_DIR}/test/data/input/DicomImageOrientationTest/ImageOrientation.3.dcm +) \ No newline at end of file diff --git a/packages/dicom/gdcm/CMakeLists.txt b/packages/dicom/gdcm/CMakeLists.txt index a82ccf4df..5ee74cfe4 100644 --- a/packages/dicom/gdcm/CMakeLists.txt +++ b/packages/dicom/gdcm/CMakeLists.txt @@ -10,6 +10,9 @@ include(${ITK_USE_FILE}) add_executable(read-image-dicom-file-series read-image-dicom-file-series.cxx) target_link_libraries(read-image-dicom-file-series PUBLIC ${ITK_LIBRARIES}) +add_executable(image-sets-normalization image-sets-normalization.cxx) +target_link_libraries(image-sets-normalization PUBLIC ${ITK_LIBRARIES}) + if (WASI) return() endif() diff --git a/packages/dicom/gdcm/CharStringToUTF8Converter.h b/packages/dicom/gdcm/CharStringToUTF8Converter.h new file mode 100644 index 000000000..64ddf5f4e --- /dev/null +++ b/packages/dicom/gdcm/CharStringToUTF8Converter.h @@ -0,0 +1,467 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef CHAR_STRING_TO_UTF8_CONVERTER_H +#define CHAR_STRING_TO_UTF8_CONVERTER_H + +#include +#include +#include + +#include + +const std::string DEFAULT_ENCODING("ISO_IR 6"); +const std::string DEFAULT_ISO_2022_ENCODING("ISO 2022 IR 6"); +constexpr const char *ASCII = "ASCII"; + +// delimiters: CR, LF, FF, ESC, TAB (see +// https://dicom.nema.org/medical/dicom/current/output/html/part05.html#sect_6.1.3, +// table 6.1-1) +// Also includes 05/12 (BACKSLASH in IR 13 or YEN SIGN in IR 14), since that +// separates Data Element Values and it resets to initial charset. +// See: dicom part 5, sect 6.1.2.5.3 +constexpr const char *DEFAULT_DELIMS = "\x1b\x09\x0a\x0c\x0d\x5c"; +// DEFAULT_DELIMS + "^" and "=" +constexpr const char *PATIENT_NAME_DELIMS = "\x1b\x09\x0a\x0c\x0d\x5c^="; + +// If not found, then pos == len +size_t +findDelim(const char *str, size_t len, size_t pos = 0, const char *delims = DEFAULT_DELIMS) +{ + while (pos < len && strchr(delims, str[pos]) == nullptr) + { + ++pos; + } + return pos; +} + +std::string +trimWhitespace(const std::string &term) +{ + auto start = term.begin(); + auto end = term.end(); + + while (start != end && std::isspace(*start)) + { + ++start; + } + + // need to --end once before checking isspace + do + { + --end; + } while (end != start && std::isspace(*end)); + + return std::string(start, end + 1); +} + +std::string +normalizeTerm(const std::string &term) +{ + return trimWhitespace(term); +} + +const char * +definedTermToIconvCharset(const std::string &defTerm) +{ + // be strict about comparing defined terms, so no fancy parsing + // that could possibly make these operations faster. + // See: + // https://dicom.nema.org/medical/dicom/current/output/chtml/part02/sect_D.6.2.html + if (defTerm == "ISO_IR 6" || defTerm == "ISO 2022 IR 6") + { + return ASCII; + } + if (defTerm == "ISO_IR 100" || defTerm == "ISO 2022 IR 100") + { + return "ISO-8859-1"; // Latin 1 + } + if (defTerm == "ISO_IR 101" || defTerm == "ISO 2022 IR 101") + { + return "ISO-8859-2"; // Latin 2 + } + if (defTerm == "ISO_IR 109" || defTerm == "ISO 2022 IR 109") + { + return "ISO-8859-3"; // Latin 3 + } + if (defTerm == "ISO_IR 110" || defTerm == "ISO 2022 IR 110") + { + return "ISO-8859-4"; // Latin 4 + } + if (defTerm == "ISO_IR 144" || defTerm == "ISO 2022 IR 144") + { + return "ISO-8859-5"; // Cyrillic + } + if (defTerm == "ISO_IR 127" || defTerm == "ISO 2022 IR 127") + { + return "ISO-8859-6"; // Arabic + } + if (defTerm == "ISO_IR 126" || defTerm == "ISO 2022 IR 126") + { + return "ISO-8859-7"; // Greek + } + if (defTerm == "ISO_IR 138" || defTerm == "ISO 2022 IR 138") + { + return "ISO-8859-8"; // Hebrew + } + if (defTerm == "ISO_IR 148" || defTerm == "ISO 2022 IR 148") + { + return "ISO-8859-9"; // Latin 5, Turkish + } + if (defTerm == "ISO_IR 13" || defTerm == "ISO 2022 IR 13") + { + // while technically not strict, SHIFT_JIS succeeds JIS X 0201 + // See: https://en.wikipedia.org/wiki/JIS_X_0201 + return "SHIFT_JIS"; // Japanese + } + if (defTerm == "ISO_IR 166" || defTerm == "ISO 2022 IR 166") + { + return "TIS-620"; // Thai + } + if (defTerm == "ISO 2022 IR 87") + { + // see: https://en.wikipedia.org/wiki/JIS_X_0208 + return "ISO-2022-JP"; // Japanese + } + if (defTerm == "ISO 2022 IR 159") + { + // see: https://en.wikipedia.org/wiki/JIS_X_0212 + return "ISO-2022-JP-1"; // Japanese + } + if (defTerm == "ISO 2022 IR 149") + { + return "EUC-KR"; // Korean + } + if (defTerm == "ISO 2022 IR 58") + { + return "EUC-CN"; // Chinese + } + if (defTerm == "ISO_IR 192") + { + return "UTF-8"; + } + if (defTerm == "GB18030") + { + return "GB18030"; + } + if (defTerm == "GBK") + { + return "GBK"; + } + return nullptr; +} + +// seq should be the sequence after the ESC char +// return value should match in definedTermToIconvCharset +const char * +iso2022EscSelectCharset(const char *seq) +{ + if (seq[0] == '(' && seq[1] == 'B') + { + return "ISO 2022 IR 6"; + } + if (seq[0] == '-' && seq[1] == 'A') + { + return "ISO 2022 IR 100"; + } + if (seq[0] == '-' && seq[1] == 'B') + { + return "ISO 2022 IR 101"; + } + if (seq[0] == '-' && seq[1] == 'C') + { + return "ISO 2022 IR 109"; + } + if (seq[0] == '-' && seq[1] == 'D') + { + return "ISO 2022 IR 110"; + } + if (seq[0] == '-' && seq[1] == 'L') + { + return "ISO 2022 IR 144"; + } + if (seq[0] == '-' && seq[1] == 'G') + { + return "ISO 2022 IR 127"; + } + if (seq[0] == '-' && seq[1] == 'F') + { + return "ISO 2022 IR 126"; + } + if (seq[0] == '-' && seq[1] == 'H') + { + return "ISO 2022 IR 138"; + } + if (seq[0] == '-' && seq[1] == 'M') + { + return "ISO 2022 IR 148"; + } + // technically 'J' corresponds to IR 14, byt SHIFT_JIS should still work + if (seq[0] == '-' && (seq[1] == 'I' || seq[1] == 'J')) + { + return "ISO 2022 IR 13"; + } + if (seq[0] == '-' && seq[1] == 'T') + { + return "ISO 2022 IR 166"; + } + if (seq[0] == '$' && seq[1] == 'B') + { + return "ISO 2022 IR 87"; + } + if (seq[0] == '$' && seq[1] == '(' && seq[2] == 'D') + { + return "ISO 2022 IR 159"; + } + if (seq[0] == '$' && seq[1] == ')' && seq[2] == 'C') + { + return "ISO 2022 IR 149"; + } + if (seq[0] == '$' && seq[1] == ')' && seq[2] == 'A') + { + return "ISO 2022 IR 58"; + } + if ((seq[0] == ')' && seq[1] == 'I') || (seq[0] == '(' && seq[1] == 'J')) + { + return "ISO 2022 IR 13"; + } + return ""; +} + +// seq should point after the ESC char. Returned length will +// not include ESC char. +size_t +iso2022EscSeqLength(const char *seq) +{ + if (seq[0] == '$' && seq[1] >= '(' && seq[1] <= '/') + { + return 3; + } + return 2; +} + +class CharStringToUTF8Converter +{ +public: + // See: setSpecificCharacterSet(const char *) + CharStringToUTF8Converter(const std::string &spcharsets) + : CharStringToUTF8Converter(spcharsets.c_str()) + { + } + CharStringToUTF8Converter(const char *spcharsets) + : handlePatientName(false) + { + this->setSpecificCharacterSet(spcharsets); + }; + + /** + * Input must be the DICOM SpecificCharacterSet element value. + * See: + * https://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2 + */ + void + setSpecificCharacterSet(const char *spcharsets) + { + std::string specificCharacterSet(spcharsets); + std::string token; + std::istringstream tokStream(specificCharacterSet); + + m_charsets.clear(); + + int count = 0; + while (std::getline(tokStream, token, '\\')) + { + token = normalizeTerm(token); + + // case: first element is empty. Use default ISO-IR 6 encoding. + if (token.size() == 0 && count == 0) + { + m_charsets.push_back(DEFAULT_ENCODING); + // "Hack" to handle case where ISO-646 (dicom default encoding) is + // implicitly first in the list. Since we check for charset existence when + // switching charsets as per ISO 2022, we put both regular and ISO 2022 + // names for the default encoding. + m_charsets.push_back(DEFAULT_ISO_2022_ENCODING); + } + else if (m_charsets.end() == std::find(m_charsets.begin(), m_charsets.end(), token)) + { + // case: no duplicates + const char *chname = definedTermToIconvCharset(token); + // handle charsets that do not allow code extensions + if (count > 0 && (token == "GB18030" || token == "GBK" || token == "ISO_IR 192")) + { + std::cerr << "WARN: charset " << token << " does not support code extensions; ignoring" << std::endl; + } + else if (chname != nullptr && chname != ASCII) + { + // ISO_IR 6 isn't a formally recognized defined term, so use ASCII + // above. + m_charsets.push_back(token); + } + } + else + { + std::cerr << "WARN: Found duplicate charset '" + token + "'; ignoring" << std::endl; + } + ++count; + } + + if (count == 0) + { + // use default encoding + m_charsets.push_back(DEFAULT_ENCODING); + } + + if (m_charsets.size() == 0) + { + std::cerr << "WARN: Found no suitable charsets!" << std::endl; + } + } + + std::string + convertCharStringToUTF8(const std::string &str) const + { + size_t len = str.size(); + return this->convertCharStringToUTF8(str.c_str(), len); + } + + std::string + convertCharStringToUTF8(const char *str, size_t len) const + { + // m_charsets must always have at least 1 element prior to calling + const char *initialCharset = definedTermToIconvCharset(m_charsets[0]); + if (initialCharset == nullptr) + { + return {}; + } + + iconv_t cd = iconv_open("UTF-8", initialCharset); + if (cd == (iconv_t)-1) + { + return {}; + } + + int utf8len = len * 4; + std::unique_ptr result(new char[utf8len + 1]()); // UTF8 will have max length of utf8len + + // make a copy because iconv requires a char * + char *copiedStr = (char *)malloc(len + 1); + strncpy(copiedStr, str, len); + + char *inbuf = copiedStr; + char *outbuf = result.get(); + size_t inbytesleft = len; + size_t outbytesleft = utf8len; + + // special case: only one charset, so assume string is just that charset. + if (m_charsets.size() == 1) + { + iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + } + else + { + size_t fragmentStart = 0; + size_t fragmentEnd = 0; + + while (fragmentStart < len) + { + const char *delims = this->handlePatientName ? PATIENT_NAME_DELIMS : DEFAULT_DELIMS; + // fragmentEnd will always be end of current fragment (exclusive end) + fragmentEnd = findDelim(str, len, fragmentStart + 1, delims); + inbuf = copiedStr + fragmentStart; + inbytesleft = fragmentEnd - fragmentStart; + + iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + + fragmentStart = fragmentEnd; + bool isEsc = str[fragmentEnd] == 0x1b; + + if (fragmentStart < len) + { + const char *nextCharset; + int seek = 0; + + if (isEsc) + { // case: ISO 2022 escape encountered + const char *escSeq = copiedStr + fragmentStart + 1; + + const char *nextTerm = iso2022EscSelectCharset(escSeq); + nextCharset = definedTermToIconvCharset(std::string(nextTerm)); + if (nextCharset == nullptr || m_charsets.end() == std::find(m_charsets.begin(), m_charsets.end(), nextTerm)) + { + std::cerr << "WARN: bailing because invalid charset: " << nextTerm << std::endl; + break; // bail out + } + + // ISO-2022-JP is a variant on ISO 2022 for japanese, and so + // it defines its own escape sequences. As such, do not skip the + // escape sequences for ISO-2022-JP, so iconv can properly interpret + // them. + if (0 != strcmp("ISO-2022-JP", nextCharset) && 0 != strcmp("ISO-2022-JP-1", nextCharset)) + { + seek = iso2022EscSeqLength(escSeq) + 1; + } + } + else + { // case: hit a CR, LF, or FF + // reset to initial charset + nextCharset = initialCharset; + } + + if (0 != iconv_close(cd)) + { + std::cerr << "WARN: bailing because iconv_close" << std::endl; + break; // bail out + } + cd = iconv_open("UTF-8", nextCharset); + if (cd == (iconv_t)-1) + { + std::cerr << "WARN: bailing because iconv_open" << std::endl; + break; // bail out + } + + fragmentStart += seek; + } + } + } + + free(copiedStr); + iconv_close(cd); + + // since result is filled with NULL bytes, string constructor will figure out + // the correct string ending. + return std::string(result.get()); + } + + bool + getHandlePatientName() + { + return this->handlePatientName; + } + + void + setHandlePatientName(bool yn) + { + this->handlePatientName = yn; + } + +private: + std::vector m_charsets; + bool handlePatientName; +}; + +#endif // CHAR_STRING_TO_UTF8_CONVERTER_H \ No newline at end of file diff --git a/packages/dicom/gdcm/DICOMTagReader.h b/packages/dicom/gdcm/DICOMTagReader.h new file mode 100644 index 000000000..59aed7622 --- /dev/null +++ b/packages/dicom/gdcm/DICOMTagReader.h @@ -0,0 +1,144 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef DICOM_TAG_READER_H +#define DICOM_TAG_READER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rapidjson/document.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" + +#include "itkCommonEnums.h" +#include "itkGDCMImageIO.h" +#include "itkGDCMSeriesFileNames.h" +#include "itkImageIOBase.h" +#include "itkMetaDataObject.h" + +#include "CharStringToUTF8Converter.h" + +std::string +unpackMetaAsString(const itk::MetaDataObjectBase::Pointer &metaValue) +{ + using MetaDataStringType = itk::MetaDataObject; + MetaDataStringType::Pointer value = dynamic_cast(metaValue.GetPointer()); + if (value != nullptr) + { + return value->GetMetaDataObjectValue(); + } + return {}; +} + +namespace itk +{ + + /** \class DICOMTagReader + * + * \brief Reads DICOM tags from a DICOM object. + */ + class DICOMTagReader + { + public: + using MetaDictType = itk::MetaDataDictionary; + using TagMapType = std::unordered_map; + + DICOMTagReader() + : m_dirtyCache(true) + { + m_GDCMImageIO = GDCMImageIO::New(); + } + + /** Sets file name. */ + void + SetFileName(const std::string &file) + { + m_fileName = file; + m_GDCMImageIO->SetFileName(file); + m_dirtyCache = true; + } + + /** Verify file can be read. */ + bool + CanReadFile(const std::string &file) + { + return m_GDCMImageIO->CanReadFile(file.c_str()); + } + + std::string + ReadTag(const std::string &tag) + { + + if (m_dirtyCache) + { + m_GDCMImageIO->SetUseStreamedReading(true); + m_GDCMImageIO->ReadImageInformation(); + m_tagDict = m_GDCMImageIO->GetMetaDataDictionary(); + auto specificCharacterSet = unpackMetaAsString(m_tagDict["0008|0005"]); + m_decoder = CharStringToUTF8Converter(specificCharacterSet); + m_dirtyCache = false; + } + + auto value = unpackMetaAsString(m_tagDict[tag]); + return m_decoder.convertCharStringToUTF8(value); + } + + TagMapType + ReadAllTags() + { + + if (m_dirtyCache) + { + m_GDCMImageIO->SetUseStreamedReading(true); + m_GDCMImageIO->ReadImageInformation(); + m_tagDict = m_GDCMImageIO->GetMetaDataDictionary(); + auto specificCharacterSet = unpackMetaAsString(m_tagDict["0008|0005"]); + m_decoder = CharStringToUTF8Converter(specificCharacterSet); + m_dirtyCache = false; + } + + TagMapType allTagsDict; + for (auto it = m_tagDict.Begin(); it != m_tagDict.End(); ++it) + { + auto value = unpackMetaAsString(it->second); + allTagsDict[it->first] = m_decoder.convertCharStringToUTF8(value); + } + + return allTagsDict; + } + + private: + std::string m_fileName; + itk::GDCMImageIO::Pointer m_GDCMImageIO; + MetaDictType m_tagDict; + CharStringToUTF8Converter m_decoder = CharStringToUTF8Converter(""); + bool m_dirtyCache; + }; + +} // end namespace itk + +#endif // DICOM_TAG_READER_H \ No newline at end of file diff --git a/packages/dicom/gdcm/SortSpatially.h b/packages/dicom/gdcm/SortSpatially.h new file mode 100644 index 000000000..832b47bd4 --- /dev/null +++ b/packages/dicom/gdcm/SortSpatially.h @@ -0,0 +1,94 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef SORT_SPATIALLY_H +#define SORT_SPATIALLY_H + +#include +#include + +#include "gdcmSerieHelper.h" + +class CustomSerieHelper : public gdcm::SerieHelper +{ +public: + void AddFileName(std::string const &fileName) + { + SerieHelper::AddFileName(fileName); + } +}; + +using FileNamesContainer = std::vector; + +FileNamesContainer sortSpatially(std::vector unsortedSerieFileNames) +{ + std::unique_ptr serieHelper(new CustomSerieHelper()); + for (const std::string &fileName : unsortedSerieFileNames) + { + serieHelper->AddFileName(fileName); + } + serieHelper->SetUseSeriesDetails(true); + // Add the default restrictions to refine the file set into multiple series. + serieHelper->CreateDefaultUniqueSeriesIdentifier(); + using SeriesIdContainer = std::vector; + SeriesIdContainer seriesUIDs; + // Accessing the first serie found (assume there is at least one) + gdcm::FileList *flist = serieHelper->GetFirstSingleSerieUIDFileSet(); + while (flist) + { + if (!flist->empty()) // make sure we have at least one serie + { + gdcm::File *file = (*flist)[0]; // for example take the first one + + // Create its unique series ID + const std::string id(serieHelper->CreateUniqueSeriesIdentifier(file)); + + seriesUIDs.push_back(id); + } + flist = serieHelper->GetNextSingleSerieUIDFileSet(); + } + + FileNamesContainer fileNames; + flist = serieHelper->GetFirstSingleSerieUIDFileSet(); + const std::string serie = seriesUIDs[0]; + bool found = false; + while (flist && !found) + { + if (!flist->empty()) // make sure we have at least one serie + { + gdcm::File *file = (*flist)[0]; // for example take the first one + const std::string id(serieHelper->CreateUniqueSeriesIdentifier(file)); + if (id == serie) + { + found = true; // we found a match + break; + } + } + flist = serieHelper->GetNextSingleSerieUIDFileSet(); + } + serieHelper->OrderFileList(flist); + + gdcm::FileList::iterator it; + for (it = flist->begin(); it != flist->end(); ++it) + { + gdcm::FileWithName *header = *it; + fileNames.push_back(header->filename); + } + return fileNames; +} + +#endif // SORT_SPATIALLY_H \ No newline at end of file diff --git a/packages/dicom/gdcm/Tags.h b/packages/dicom/gdcm/Tags.h new file mode 100644 index 000000000..9a9014b46 --- /dev/null +++ b/packages/dicom/gdcm/Tags.h @@ -0,0 +1,369 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef TAGS_H +#define TAGS_H + +#include +#include + +using Tag = gdcm::Tag; +using Tags = std::set; + +const Tag STUDY_UID(0x0020, 0x000d); // "Study Instance UID" +const Tag SERIES_UID(0x0020, 0x000e); // "Series Instance UID" +const Tag INSTANCE_UID(0x0008, 0x0018); // "Instance UID" + +const Tag FRAME_OF_REFERENCE_UID(0x0020, 0x0052); +const Tag IMAGE_ORIENTATION_PATIENT(0x0020, 0x0037); + +const Tag SPECIFIC_CHARACTER_SET(0x0008, 0x0005); +const Tag PIXEL_DATA_TAG(0x7fe0, 0x0010); + +const Tags EMPTY_TAGS = {}; + +// Tag names from https://docs.aws.amazon.com/healthimaging/latest/devguide/reference-dicom-support.html +const Tags PATIENT_TAGS = { + // Patient Module Elements + Tag(0x0010, 0x0010), // "Patient's Name" + Tag(0x0010, 0x0020), // "Patient ID" + // Issuer of Patient ID Macro Elements + Tag(0x0010, 0x0021), // "Issuer of Patient ID" + Tag(0x0010, 0x0024), // "Issuer of Patient ID Qualifiers Sequence" + Tag(0x0010, 0x0022), // "Type of Patient ID" + Tag(0x0010, 0x0030), // "Patient's Birth Date" + Tag(0x0010, 0x0033), // "Patient's Birth Date in Alternative Calendar" + Tag(0x0010, 0x0034), // "Patient's Death Date in Alternative Calendar" + Tag(0x0010, 0x0035), // "Patient's Alternative Calendar Attribute" + Tag(0x0010, 0x0040), // "Patient's Sex" + Tag(0x0010, 0x1100), // "Referenced Patient Photo Sequence" + Tag(0x0010, 0x0200), // "Quality Control Subject" + Tag(0x0008, 0x1120), // "Referenced Patient Sequence" + Tag(0x0010, 0x0032), // "Patient's Birth Time" + Tag(0x0010, 0x1002), // "Other Patient IDs Sequence" + Tag(0x0010, 0x1001), // "Other Patient Names" + Tag(0x0010, 0x2160), // "Ethnic Group" + Tag(0x0010, 0x4000), // "Patient Comments" + Tag(0x0010, 0x2201), // "Patient Species Description" + Tag(0x0010, 0x2202), // "Patient Species Code Sequence Attribute" + Tag(0x0010, 0x2292), // "Patient Breed Description" + Tag(0x0010, 0x2293), // "Patient Breed Code Sequence" + Tag(0x0010, 0x2294), // "Breed Registration Sequence Attribute" + Tag(0x0010, 0x0212), // "Strain Description" + Tag(0x0010, 0x0213), // "Strain Nomenclature Attribute" + Tag(0x0010, 0x0219), // "Strain Code Sequence" + Tag(0x0010, 0x0218), // "Strain Additional Information Attribute" + Tag(0x0010, 0x0216), // "Strain Stock Sequence" + Tag(0x0010, 0x0221), // "Genetic Modifications Sequence Attribute" + Tag(0x0010, 0x2297), // "Responsible Person" + Tag(0x0010, 0x2298), // "Responsible Person Role Attribute" + Tag(0x0010, 0x2299), // "Responsible Organization" + Tag(0x0012, 0x0062), // "Patient Identity Removed" + Tag(0x0012, 0x0063), // "De-identification Method" + Tag(0x0012, 0x0064), // "De-identification Method Code Sequence" + // Patient Group Macro Elements + Tag(0x0010, 0x0026), // "Source Patient Group Identification Sequence" + Tag(0x0010, 0x0027), // "Group of Patients Identification Sequence" + // Clinical Trial Subject Module + Tag(0x0012, 0x0010), // "Clinical Trial Sponsor Name" + Tag(0x0012, 0x0020), // "Clinical Trial Protocol ID" + Tag(0x0012, 0x0021), // "Clinical Trial Protocol Name Attribute" + Tag(0x0012, 0x0030), // "Clinical Trial Site ID" + Tag(0x0012, 0x0031), // "Clinical Trial Site Name" + Tag(0x0012, 0x0040), // "Clinical Trial Subject ID" + Tag(0x0012, 0x0042), // "Clinical Trial Subject Reading ID" + Tag(0x0012, 0x0081), // "Clinical Trial Protocol Ethics Committee Name" + Tag(0x0012, 0x0082) // "Clinical Trial Protocol Ethics Committee Approval Number" +}; + +const Tags STUDY_TAGS = { + // General Study Module + Tag(0x0020, 0x000d), // "Study Instance UID" + Tag(0x0008, 0x0020), // "Study Date" + Tag(0x0008, 0x0030), // "Study Time" + Tag(0x0008, 0x0090), // "Referring Physician's Name" + Tag(0x0008, 0x0096), // "Referring Physician Identification Sequence" + Tag(0x0008, 0x009c), // "Consulting Physician's Name" + Tag(0x0008, 0x009d), // "Consulting Physician Identification Sequence" + Tag(0x0020, 0x0010), // "Study ID" + Tag(0x0008, 0x0050), // "Accession Number" + Tag(0x0008, 0x0051), // "Issuer of Accession Number Sequence" + Tag(0x0008, 0x1030), // "Study Description" + Tag(0x0008, 0x1048), // "Physician(s) of Record" + Tag(0x0008, 0x1049), // "Physician(s) of Record Identification Sequence" + Tag(0x0008, 0x1060), // "Name of Physician(s) Reading Study" + Tag(0x0008, 0x1062), // "Physician(s) Reading Study Identification Sequence" + Tag(0x0032, 0x1033), // "Requesting Service" + Tag(0x0032, 0x1034), // "Requesting Service Code Sequence" + Tag(0x0008, 0x1110), // "Referenced Study Sequence" + Tag(0x0008, 0x1032), // "Procedure Code Sequence" + Tag(0x0040, 0x1012), // "Reason For Performed Procedure Code Sequence" + // Patient Study Module + Tag(0x0008, 0x1080), // "Admitting Diagnoses Description" + Tag(0x0008, 0x1084), // "Admitting Diagnoses Code Sequence" + Tag(0x0010, 0x1010), // "Patient's Age" + Tag(0x0010, 0x1020), // "Patient's Size" + Tag(0x0010, 0x1030), // "Patient's Weight" + Tag(0x0010, 0x1022), // "Patient's Body Mass Index" + Tag(0x0010, 0x1023), // "Measured AP Dimension" + Tag(0x0010, 0x1024), // "Measured Lateral Dimension" + Tag(0x0010, 0x1021), // "Patient's Size Code Sequence" + Tag(0x0010, 0x2000), // "Medical Alerts" + Tag(0x0010, 0x2110), // "Allergies" + Tag(0x0010, 0x21a0), // "Smoking Status" + Tag(0x0010, 0x21c0), // "Pregnancy Status" + Tag(0x0010, 0x21d0), // "Last Menstrual Date" + Tag(0x0038, 0x0500), // "Patient State" + Tag(0x0010, 0x2180), // "Occupation" + Tag(0x0010, 0x21b0), // "Additional Patient History" + Tag(0x0038, 0x0010), // "Admission ID" + Tag(0x0038, 0x0014), // "Issuer of Admission ID Sequence" + Tag(0x0032, 0x1066), // "Reason for Visit" + Tag(0x0032, 0x1067), // "Reason for Visit Code Sequence" + Tag(0x0038, 0x0060), // "Service Episode ID" + Tag(0x0038, 0x0064), // "Issuer of Service Episode ID Sequence" + Tag(0x0038, 0x0062), // "Service Episode Description" + Tag(0x0010, 0x2203), // "Patient's Sex Neutered" + // Clinical Trial Study Module + Tag(0x0012, 0x0050), // "Clinical Trial Time Point ID" + Tag(0x0012, 0x0051), // "Clinical Trial Time Point Description" + Tag(0x0012, 0x0052), // "Longitudinal Temporal Offset from Event" + Tag(0x0012, 0x0053), // "Longitudinal Temporal Event Type" + Tag(0x0012, 0x0083) // "Consent for Clinical Trial Use Sequence" +}; + +const Tags SERIES_TAGS = { + // General Series Module + Tag(0x0008, 0x0060), // "Modality" + Tag(0x0020, 0x000e), // "Series Instance UID" + Tag(0x0020, 0x0011), // "Series Number" + Tag(0x0020, 0x0060), // "Laterality" + Tag(0x0008, 0x0021), // "Series Date" + Tag(0x0008, 0x0031), // "Series Time" + Tag(0x0008, 0x1050), // "Performing Physician's Name" + Tag(0x0008, 0x1052), // "Performing Physician Identification Sequence" + Tag(0x0018, 0x1030), // "Protocol Name" + Tag(0x0008, 0x103e), // "Series Description" + Tag(0x0008, 0x103f), // "Series Description Code Sequence" + Tag(0x0008, 0x1070), // "Operators' Name" + Tag(0x0008, 0x1072), // "Operator Identification Sequence" + Tag(0x0008, 0x1111), // "Referenced Performed Procedure Step Sequence" + Tag(0x0008, 0x1250), // "Related Series Sequence" + Tag(0x0018, 0x0015), // "Body Part Examined" + Tag(0x0018, 0x5100), // "Patient Position" + Tag(0x0028, 0x0108), // "Smallest Pixel Value in Series" + Tag(0x0028, 0x0109), // "Largest Pixel Value in Series" + Tag(0x0040, 0x0275), // "Request Attributes Sequence" + Tag(0x0010, 0x2210), // "Anatomical Orientation Type" + Tag(0x300a, 0x0700), // "Treatment Session UID" + // Clinical Trial Series Module + Tag(0x0012, 0x0060), // "Clinical Trial Coordinating Center Name" + Tag(0x0012, 0x0071), // "Clinical Trial Series ID" + Tag(0x0012, 0x0072), // "Clinical Trial Series Description" + // General Equipment Module + Tag(0x0008, 0x0070), // "Manufacturer" + Tag(0x0008, 0x0080), // "Institution Name" + Tag(0x0008, 0x0081), // "Institution Address" + Tag(0x0008, 0x1010), // "Station Name" + Tag(0x0008, 0x1040), // "Institutional Department Name" + Tag(0x0008, 0x1041), // "Institutional Department Type Code Sequence" + Tag(0x0008, 0x1090), // "Manufacturer's Model Name" + Tag(0x0018, 0x100b), // "Manufacturer's Device Class UID" + Tag(0x0018, 0x1000), // "Device Serial Number" + Tag(0x0018, 0x1020), // "Software Versions" + Tag(0x0018, 0x1008), // "Gantry ID" + Tag(0x0018, 0x100a), // "UDI Sequence" + Tag(0x0018, 0x1002), // "Device UID" + Tag(0x0018, 0x1050), // "Spatial Resolution" + Tag(0x0018, 0x1200), // "Date of Last Calibration" + Tag(0x0018, 0x1201), // "Time of Last Calibration" + Tag(0x0028, 0x0120), // "Pixel Padding Value" + // Frame of Reference Module + Tag(0x0020, 0x0052), // "Frame of Reference UID" + Tag(0x0020, 0x1040), // "Position Reference Indicator" +}; + +const Tags NON_INSTANCE = { + // Patient Module Elements + Tag(0x0010, 0x0010), // "Patient's Name" + Tag(0x0010, 0x0020), // "Patient ID" + // Issuer of Patient ID Macro Elements + Tag(0x0010, 0x0021), // "Issuer of Patient ID" + Tag(0x0010, 0x0024), // "Issuer of Patient ID Qualifiers Sequence" + Tag(0x0010, 0x0022), // "Type of Patient ID" + Tag(0x0010, 0x0030), // "Patient's Birth Date" + Tag(0x0010, 0x0033), // "Patient's Birth Date in Alternative Calendar" + Tag(0x0010, 0x0034), // "Patient's Death Date in Alternative Calendar" + Tag(0x0010, 0x0035), // "Patient's Alternative Calendar Attribute" + Tag(0x0010, 0x0040), // "Patient's Sex" + Tag(0x0010, 0x1100), // "Referenced Patient Photo Sequence" + Tag(0x0010, 0x0200), // "Quality Control Subject" + Tag(0x0008, 0x1120), // "Referenced Patient Sequence" + Tag(0x0010, 0x0032), // "Patient's Birth Time" + Tag(0x0010, 0x1002), // "Other Patient IDs Sequence" + Tag(0x0010, 0x1001), // "Other Patient Names" + Tag(0x0010, 0x2160), // "Ethnic Group" + Tag(0x0010, 0x4000), // "Patient Comments" + Tag(0x0010, 0x2201), // "Patient Species Description" + Tag(0x0010, 0x2202), // "Patient Species Code Sequence Attribute" + Tag(0x0010, 0x2292), // "Patient Breed Description" + Tag(0x0010, 0x2293), // "Patient Breed Code Sequence" + Tag(0x0010, 0x2294), // "Breed Registration Sequence Attribute" + Tag(0x0010, 0x0212), // "Strain Description" + Tag(0x0010, 0x0213), // "Strain Nomenclature Attribute" + Tag(0x0010, 0x0219), // "Strain Code Sequence" + Tag(0x0010, 0x0218), // "Strain Additional Information Attribute" + Tag(0x0010, 0x0216), // "Strain Stock Sequence" + Tag(0x0010, 0x0221), // "Genetic Modifications Sequence Attribute" + Tag(0x0010, 0x2297), // "Responsible Person" + Tag(0x0010, 0x2298), // "Responsible Person Role Attribute" + Tag(0x0010, 0x2299), // "Responsible Organization" + Tag(0x0012, 0x0062), // "Patient Identity Removed" + Tag(0x0012, 0x0063), // "De-identification Method" + Tag(0x0012, 0x0064), // "De-identification Method Code Sequence" + // Patient Group Macro Elements + Tag(0x0010, 0x0026), // "Source Patient Group Identification Sequence" + Tag(0x0010, 0x0027), // "Group of Patients Identification Sequence" + // Clinical Trial Subject Module + Tag(0x0012, 0x0010), // "Clinical Trial Sponsor Name" + Tag(0x0012, 0x0020), // "Clinical Trial Protocol ID" + Tag(0x0012, 0x0021), // "Clinical Trial Protocol Name Attribute" + Tag(0x0012, 0x0030), // "Clinical Trial Site ID" + Tag(0x0012, 0x0031), // "Clinical Trial Site Name" + Tag(0x0012, 0x0040), // "Clinical Trial Subject ID" + Tag(0x0012, 0x0042), // "Clinical Trial Subject Reading ID" + Tag(0x0012, 0x0081), // "Clinical Trial Protocol Ethics Committee Name" + Tag(0x0012, 0x0082), // "Clinical Trial Protocol Ethics Committee Approval Number" + // General Study Module + Tag(0x0020, 0x000d), // "Study Instance UID" + Tag(0x0008, 0x0020), // "Study Date" + Tag(0x0008, 0x0030), // "Study Time" + Tag(0x0008, 0x0090), // "Referring Physician's Name" + Tag(0x0008, 0x0096), // "Referring Physician Identification Sequence" + Tag(0x0008, 0x009c), // "Consulting Physician's Name" + Tag(0x0008, 0x009d), // "Consulting Physician Identification Sequence" + Tag(0x0020, 0x0010), // "Study ID" + Tag(0x0008, 0x0050), // "Accession Number" + Tag(0x0008, 0x0051), // "Issuer of Accession Number Sequence" + Tag(0x0008, 0x1030), // "Study Description" + Tag(0x0008, 0x1048), // "Physician(s) of Record" + Tag(0x0008, 0x1049), // "Physician(s) of Record Identification Sequence" + Tag(0x0008, 0x1060), // "Name of Physician(s) Reading Study" + Tag(0x0008, 0x1062), // "Physician(s) Reading Study Identification Sequence" + Tag(0x0032, 0x1033), // "Requesting Service" + Tag(0x0032, 0x1034), // "Requesting Service Code Sequence" + Tag(0x0008, 0x1110), // "Referenced Study Sequence" + Tag(0x0008, 0x1032), // "Procedure Code Sequence" + Tag(0x0040, 0x1012), // "Reason For Performed Procedure Code Sequence" + // Patient Study Module + Tag(0x0008, 0x1080), // "Admitting Diagnoses Description" + Tag(0x0008, 0x1084), // "Admitting Diagnoses Code Sequence" + Tag(0x0010, 0x1010), // "Patient's Age" + Tag(0x0010, 0x1020), // "Patient's Size" + Tag(0x0010, 0x1030), // "Patient's Weight" + Tag(0x0010, 0x1022), // "Patient's Body Mass Index" + Tag(0x0010, 0x1023), // "Measured AP Dimension" + Tag(0x0010, 0x1024), // "Measured Lateral Dimension" + Tag(0x0010, 0x1021), // "Patient's Size Code Sequence" + Tag(0x0010, 0x2000), // "Medical Alerts" + Tag(0x0010, 0x2110), // "Allergies" + Tag(0x0010, 0x21a0), // "Smoking Status" + Tag(0x0010, 0x21c0), // "Pregnancy Status" + Tag(0x0010, 0x21d0), // "Last Menstrual Date" + Tag(0x0038, 0x0500), // "Patient State" + Tag(0x0010, 0x2180), // "Occupation" + Tag(0x0010, 0x21b0), // "Additional Patient History" + Tag(0x0038, 0x0010), // "Admission ID" + Tag(0x0038, 0x0014), // "Issuer of Admission ID Sequence" + Tag(0x0032, 0x1066), // "Reason for Visit" + Tag(0x0032, 0x1067), // "Reason for Visit Code Sequence" + Tag(0x0038, 0x0060), // "Service Episode ID" + Tag(0x0038, 0x0064), // "Issuer of Service Episode ID Sequence" + Tag(0x0038, 0x0062), // "Service Episode Description" + Tag(0x0010, 0x2203), // "Patient's Sex Neutered" + // Clinical Trial Study Module + Tag(0x0012, 0x0050), // "Clinical Trial Time Point ID" + Tag(0x0012, 0x0051), // "Clinical Trial Time Point Description" + Tag(0x0012, 0x0052), // "Longitudinal Temporal Offset from Event" + Tag(0x0012, 0x0053), // "Longitudinal Temporal Event Type" + Tag(0x0012, 0x0083), // "Consent for Clinical Trial Use Sequence" + + // General Series Module + Tag(0x0008, 0x0060), // "Modality" + Tag(0x0020, 0x000e), // "Series Instance UID" + Tag(0x0020, 0x0011), // "Series Number" + Tag(0x0020, 0x0060), // "Laterality" + Tag(0x0008, 0x0021), // "Series Date" + Tag(0x0008, 0x0031), // "Series Time" + Tag(0x0008, 0x1050), // "Performing Physician's Name" + Tag(0x0008, 0x1052), // "Performing Physician Identification Sequence" + Tag(0x0018, 0x1030), // "Protocol Name" + Tag(0x0008, 0x103e), // "Series Description" + Tag(0x0008, 0x103f), // "Series Description Code Sequence" + Tag(0x0008, 0x1070), // "Operators' Name" + Tag(0x0008, 0x1072), // "Operator Identification Sequence" + Tag(0x0008, 0x1111), // "Referenced Performed Procedure Step Sequence" + Tag(0x0008, 0x1250), // "Related Series Sequence" + Tag(0x0018, 0x0015), // "Body Part Examined" + Tag(0x0018, 0x5100), // "Patient Position" + Tag(0x0028, 0x0108), // "Smallest Pixel Value in Series" + Tag(0x0028, 0x0109), // "Largest Pixel Value in Series" + Tag(0x0040, 0x0275), // "Request Attributes Sequence" + Tag(0x0010, 0x2210), // "Anatomical Orientation Type" + Tag(0x300a, 0x0700), // "Treatment Session UID" + // Clinical Trial Series Module + Tag(0x0012, 0x0060), // "Clinical Trial Coordinating Center Name" + Tag(0x0012, 0x0071), // "Clinical Trial Series ID" + Tag(0x0012, 0x0072), // "Clinical Trial Series Description" + // General Equipment Module + Tag(0x0008, 0x0070), // "Manufacturer" + Tag(0x0008, 0x0080), // "Institution Name" + Tag(0x0008, 0x0081), // "Institution Address" + Tag(0x0008, 0x1010), // "Station Name" + Tag(0x0008, 0x1040), // "Institutional Department Name" + Tag(0x0008, 0x1041), // "Institutional Department Type Code Sequence" + Tag(0x0008, 0x1090), // "Manufacturer's Model Name" + Tag(0x0018, 0x100b), // "Manufacturer's Device Class UID" + Tag(0x0018, 0x1000), // "Device Serial Number" + Tag(0x0018, 0x1020), // "Software Versions" + Tag(0x0018, 0x1008), // "Gantry ID" + Tag(0x0018, 0x100a), // "UDI Sequence" + Tag(0x0018, 0x1002), // "Device UID" + Tag(0x0018, 0x1050), // "Spatial Resolution" + Tag(0x0018, 0x1200), // "Date of Last Calibration" + Tag(0x0018, 0x1201), // "Time of Last Calibration" + Tag(0x0028, 0x0120), // "Pixel Padding Value" + // Frame of Reference Module + Tag(0x0020, 0x0052), // "Frame of Reference UID" + Tag(0x0020, 0x1040), // "Position Reference Indicator" +}; + +std::pair +getTagBuffer(const gdcm::DataSet &ds, const gdcm::Tag &tag) +{ + if (!ds.FindDataElement(tag) || ds.GetDataElement(tag).IsEmpty()) + { + return std::make_pair(nullptr, 0); + } + const gdcm::DataElement de = ds.GetDataElement(tag); + const gdcm::ByteValue *bv = de.GetByteValue(); + const char *tagValue = bv->GetPointer(); + size_t len = bv->GetLength(); + return std::make_pair(tagValue, len); +} + +#endif // TAGS_H \ No newline at end of file diff --git a/packages/dicom/gdcm/TagsOptionParser.h b/packages/dicom/gdcm/TagsOptionParser.h new file mode 100644 index 000000000..89dc852db --- /dev/null +++ b/packages/dicom/gdcm/TagsOptionParser.h @@ -0,0 +1,62 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef TAGS_OPTION_PARSER_H +#define TAGS_OPTION_PARSER_H + +#include +#include "rapidjson/document.h" + +#include "Tags.h" + +std::optional parseTags(itk::wasm::InputTextStream &tagsToRead, itk::wasm::Pipeline &pipeline) +{ + if (tagsToRead.GetPointer() == nullptr) + { + return std::nullopt; + } + + rapidjson::Document inputTagsDocument; + const std::string inputTagsString((std::istreambuf_iterator(tagsToRead.Get())), + std::istreambuf_iterator()); + if (inputTagsDocument.Parse(inputTagsString.c_str()).HasParseError()) + { + CLI::Error err("Runtime error", "Could not parse input tags JSON.", 1); + pipeline.exit(err); + return std::nullopt; + } + if (!inputTagsDocument.HasMember("tags")) + { + CLI::Error err("Runtime error", "Input tags does not have expected \"tags\" member", 1); + pipeline.exit(err); + return std::nullopt; + } + + const rapidjson::Value &inputTagsArray = inputTagsDocument["tags"]; + + Tags tags; + for (rapidjson::Value::ConstValueIterator itr = inputTagsArray.Begin(); itr != inputTagsArray.End(); ++itr) + { + const std::string tagString(itr->GetString()); + Tag tag; + tag.ReadFromPipeSeparatedString(tagString.c_str()); + tags.insert(tag); + } + return tags; +} + +#endif // TAGS_OPTION_PARSER_H \ No newline at end of file diff --git a/packages/dicom/gdcm/gdcmDiscriminateVolume.h b/packages/dicom/gdcm/gdcmDiscriminateVolume.h new file mode 100644 index 000000000..7b315db2a --- /dev/null +++ b/packages/dicom/gdcm/gdcmDiscriminateVolume.h @@ -0,0 +1,251 @@ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ + +/*========================================================================= + + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef DISCRIMINATE_VOLUME_H +#define DISCRIMINATE_VOLUME_H + +#include "gdcmScanner.h" +#include "gdcmTesting.h" +#include "gdcmIPPSorter.h" +#include "gdcmDirectionCosines.h" +#include + +/* + * The following example is a basic sorted which should work in generic cases. + * It sort files based on: + * Study Instance UID + * Series Instance UID + * Frame of Reference UID + * Image Orientation (Patient) + * Image Position (Patient) (Sorting based on IPP + IOP) + */ + +namespace gdcm +{ + const Tag t1(0x0020, 0x000d); // Study Instance UID + const Tag t2(0x0020, 0x000e); // Series Instance UID + const Tag t3(0x0020, 0x0052); // Frame of Reference UID + const Tag t4(0x0020, 0x0037); // Image Orientation (Patient) + + class DiscriminateVolume + { + private: + std::vector SortedFiles; + std::vector UnsortedFiles; + + Directory::FilenamesType GetAllFilenamesFromTagToValue( + Scanner const &s, Directory::FilenamesType const &filesubset, Tag const &t, const char *valueref) + { + Directory::FilenamesType theReturn; + if (valueref) + { + size_t len = strlen(valueref); + Directory::FilenamesType::const_iterator file = filesubset.begin(); + for (; file != filesubset.end(); ++file) + { + const char *filename = file->c_str(); + const char *value = s.GetValue(filename, t); + if (value && strncmp(value, valueref, len) == 0) + { + theReturn.push_back(filename); + } + } + } + return theReturn; + } + + void ProcessAIOP(Scanner const &, Directory::FilenamesType const &subset, const char *iopval) + { + IPPSorter ipp; + ipp.SetComputeZSpacing(true); + ipp.SetZSpacingTolerance(1e-3); // ?? + bool b = ipp.Sort(subset); + if (!b) + { + // If you reach here this means you need one more parameter to discriminiat this + // series. Eg. T1 / T2 intertwinted. Multiple Echo (0018,0081) + std::cerr << "Failed to sort: " << subset.begin()->c_str() << std::endl; + for ( + Directory::FilenamesType::const_iterator file = subset.begin(); + file != subset.end(); ++file) + { + std::cerr << *file << std::endl; + } + UnsortedFiles.push_back(subset); + return; + } + SortedFiles.push_back(ipp.GetFilenames()); + } + + void ProcessAFrameOfRef(Scanner const &s, Directory::FilenamesType const &subset, const char *frameuid) + { + // In this subset of files (belonging to same series), let's find those + // belonging to the same Frame ref UID: + Directory::FilenamesType files = GetAllFilenamesFromTagToValue( + s, subset, t3, frameuid); + + std::set iopset; + + for ( + Directory::FilenamesType::const_iterator file = files.begin(); + file != files.end(); ++file) + { + const char *value = s.GetValue(file->c_str(), gdcm::t4); + assert(value); + iopset.insert(value); + } + size_t n = iopset.size(); + if (n == 0) + { + assert(files.empty()); + return; + } + + if (n == 1) + { + ProcessAIOP(s, files, iopset.begin()->c_str()); + } + else + { + const char *f = files.begin()->c_str(); + std::cerr << "More than one IOP: " << f << std::endl; + // Make sure that there is actually 'n' different IOP + gdcm::DirectionCosines ref; + gdcm::DirectionCosines dc; + for ( + std::set::const_iterator it = iopset.begin(); + it != iopset.end(); ++it) + { + ref.SetFromString(it->c_str()); + for ( + Directory::FilenamesType::const_iterator file = files.begin(); + file != files.end(); ++file) + { + std::string value = s.GetValue(file->c_str(), gdcm::t4); + if (value != it->c_str()) + { + dc.SetFromString(value.c_str()); + const double crossdot = ref.CrossDot(dc); + const double eps = std::fabs(1. - crossdot); + if (eps < 1e-6) + { + std::cerr << "Problem with IOP discrimination: " << file->c_str() + << " " << it->c_str() << std::endl; + return; + } + } + } + } + // If we reach here this means there is actually 'n' different IOP + for ( + std::set::const_iterator it = iopset.begin(); + it != iopset.end(); ++it) + { + const char *iopvalue = it->c_str(); + Directory::FilenamesType iopfiles = GetAllFilenamesFromTagToValue( + s, files, t4, iopvalue); + ProcessAIOP(s, iopfiles, iopvalue); + } + } + } + + void ProcessASeries(Scanner const &s, const char *seriesuid) + { + // let's find all files belonging to this series: + Directory::FilenamesType seriesfiles = GetAllFilenamesFromTagToValue( + s, s.GetFilenames(), t2, seriesuid); + + gdcm::Scanner::ValuesType vt3 = s.GetValues(t3); + for ( + gdcm::Scanner::ValuesType::const_iterator it = vt3.begin(); it != vt3.end(); ++it) + { + ProcessAFrameOfRef(s, seriesfiles, it->c_str()); + } + } + + void ProcessAStudy(Scanner const &s, const char *studyuid) + { + gdcm::Scanner::ValuesType vt2 = s.GetValues(t2); + for ( + gdcm::Scanner::ValuesType::const_iterator it = vt2.begin(); it != vt2.end(); ++it) + { + ProcessASeries(s, it->c_str()); + } + } + + public: + void Print(std::ostream &os) + { + os << "Sorted Files: " << std::endl; + for ( + std::vector::const_iterator it = SortedFiles.begin(); + it != SortedFiles.end(); ++it) + { + os << "Group: " << std::endl; + for ( + Directory::FilenamesType::const_iterator file = it->begin(); + file != it->end(); ++file) + { + os << *file << std::endl; + } + } + os << "Unsorted Files: " << std::endl; + for ( + std::vector::const_iterator it = UnsortedFiles.begin(); + it != UnsortedFiles.end(); ++it) + { + os << "Group: " << std::endl; + for ( + Directory::FilenamesType::const_iterator file = it->begin(); + file != it->end(); ++file) + { + os << *file << std::endl; + } + } + } + + std::vector const &GetSortedFiles() const { return SortedFiles; } + std::vector const &GetUnsortedFiles() const { return UnsortedFiles; } + + void ProcessIntoVolume(Scanner const &s) + { + gdcm::Scanner::ValuesType vt1 = s.GetValues(gdcm::t1); + for ( + gdcm::Scanner::ValuesType::const_iterator it = vt1.begin(); it != vt1.end(); ++it) + { + ProcessAStudy(s, it->c_str()); + } + } + }; + +} // namespace gdcm + +#endif // DISCRIMINATE_VOLUME_H \ No newline at end of file diff --git a/packages/dicom/gdcm/image-sets-normalization.cxx b/packages/dicom/gdcm/image-sets-normalization.cxx new file mode 100644 index 000000000..d32b2f5e0 --- /dev/null +++ b/packages/dicom/gdcm/image-sets-normalization.cxx @@ -0,0 +1,765 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +/*========================================================================= + + Program: GDCM (Grassroots DICOM). A DICOM library + + Copyright (c) 2006-2011 Mathieu Malaterre + All rights reserved. + See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include + +#include "rapidjson/document.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" + +#include "gdcmGlobal.h" +#include "gdcmDicts.h" +#include "gdcmImageReader.h" + +#include "itksys/SystemTools.hxx" +#include "itksys/Base64.h" +#include "itkMakeUniqueForOverwrite.h" + +#include "itkPipeline.h" +#include "itkInputTextStream.h" +#include "itkOutputTextStream.h" + +#include "CharStringToUTF8Converter.h" +#include "Tags.h" +#include "TagsOptionParser.h" +#include "SortSpatially.h" + +const Tags SERIES_GROUP_BY_DEFAULT = Tags{SERIES_UID, FRAME_OF_REFERENCE_UID}; +const Tags IMAGE_SET_GROUP_BY_DEFAULT = Tags{STUDY_UID}; + + +std::string getLabelFromTag(const gdcm::Tag &tag, const gdcm::DataSet &dataSet) +{ + if (tag.IsPrivateCreator()) + { + return tag.PrintAsContinuousUpperCaseString(); + } + std::string strowner; + const char *owner = 0; + if (tag.IsPrivate() && !tag.IsPrivateCreator()) + { + strowner = dataSet.GetPrivateCreator(tag); + owner = strowner.c_str(); + } + const gdcm::Global &g = gdcm::Global::GetInstance(); + const gdcm::Dicts &dicts = g.GetDicts(); + const gdcm::DictEntry &entry = dicts.GetDictEntry(tag, owner); + const std::string keyword = entry.GetKeyword(); + if (keyword.empty()) + { + // There are empty keywords in test/data/input/dicom-images/MR files + return tag.PrintAsContinuousUpperCaseString(); + } + return keyword; +} + +namespace gdcm +{ + + inline bool canContainBackslash(const VR::VRType vrType) + { + assert(VR::IsASCII(vrType)); + // PS 3.5-2011 / Table 6.2-1 DICOM VALUE REPRESENTATIONS + switch (vrType) + { + case VR::AE: // ScheduledStationAETitle + // case VR::AS: // no + // case VR::AT: // binary + case VR::CS: // SpecificCharacterSet + case VR::DA: // CalibrationDate + case VR::DS: // FrameTimeVector + case VR::DT: // ReferencedDateTime + // case VR::FD: // binary + // case VR::FL: + case VR::IS: // ReferencedFrameNumber + case VR::LO: // OtherPatientIDs + // case VR::LT: // VM1 + // case VR::OB: // binary + // case VR::OD: // binary + // case VR::OF: // binary + // case VR::OW: // binary + case VR::PN: // PerformingPhysicianName + case VR::SH: // PatientTelephoneNumbers + // case VR::SL: // binary + // case VR::SQ: // binary + // case VR::SS: // binary + // case VR::ST: // VM1 + case VR::TM: // CalibrationTime + case VR::UI: // SOPClassesInStudy + // case VR::UL: // binary + // case VR::UN: // binary + // case VR::US: // binary + // case VR::UT: // VM1 + assert(!(vrType & VR::VR_VM1)); + return true; + default:; + } + return false; + } + + void dataElementToJSONArray(const VR::VRType vr, const DataElement &de, rapidjson::Value &jsonArray, const CharStringToUTF8Converter toUtf8, rapidjson::Document::AllocatorType &allocator) + { + jsonArray.SetArray(); + if (de.IsEmpty()) + { + // F.2.5 DICOM JSON Model Null Values + if (vr == VR::PN) + { + jsonArray.PushBack(rapidjson::Value(rapidjson::kObjectType), allocator); + } + return; + } + const bool checkbackslash = canContainBackslash(vr); + const ByteValue *bv = de.GetByteValue(); + const char *value = bv->GetPointer(); + size_t len = bv->GetLength(); + + if (vr == VR::UI) + { + const std::string strui(value, len); + const size_t lenuid = strlen(strui.c_str()); // trick to remove trailing \0 + rapidjson::Value stringValue; + stringValue.SetString(strui.c_str(), lenuid, allocator); + jsonArray.PushBack(stringValue, allocator); + } + else if (vr == VR::PN) + { + const char *str1 = value; + // remove whitespace: + while (str1[len - 1] == ' ') + { + len--; + } + assert(str1); + std::stringstream ss; + // static const char *Keys[] = { + // "Alphabetic", + // "Ideographic", + // "Phonetic", + // }; + while (1) + { + assert(str1 && (size_t)(str1 - value) <= len); + const char *sep = strchr(str1, '\\'); + const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1); + const std::string component(str1, llen); + + const char *str2 = component.c_str(); + assert(str2); + const size_t len2 = component.size(); + assert(len2 == llen); + + int idx = 0; + // Just get Alphabetic name, hence the comments and extra breaks + // rapidjson::Value namesObject(rapidjson::kObjectType); + rapidjson::Value name; + while (1) + { + assert(str2 && (size_t)(str2 - component.c_str()) <= len2); + const char *sep2 = strchr(str2, '='); + const size_t llen2 = (sep2 != NULL) ? (sep2 - str2) : (component.c_str() + len2 - str2); + const std::string group = toUtf8.convertCharStringToUTF8(str2, llen2); + // const char *thekey = Keys[idx++]; + + // rapidjson::Value nameType(thekey, allocator); + name.SetString(group.c_str(), group.size(), allocator); + + // namesObject.AddMember(nameType, name, allocator); + break; // just Alphabetic, short circuit + // if (sep2 == NULL) + // break; + // str2 = sep2 + 1; + } + // jsonArray.PushBack(namesObject, allocator); + jsonArray.PushBack(name, allocator); + break; // just Alphabetic, short circuit + if (sep == NULL) + break; + str1 = sep + 1; + assert(checkbackslash); + } + } + else if (vr == VR::DS || vr == VR::IS) + { + const char *str1 = value; + assert(str1); + VRToType::Type vris; + VRToType::Type vrds; + while (1) + { + std::stringstream ss; + assert(str1 && (size_t)(str1 - value) <= len); + const char *sep = strchr(str1, '\\'); + const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1); + // This is complex, IS/DS should not be stored as string anymore + switch (vr) + { + case VR::IS: + ss.str(std::string(str1, llen)); + ss >> vris; + jsonArray.PushBack(rapidjson::Value(vris), allocator); + break; + case VR::DS: + ss.str(std::string(str1, llen)); + ss >> vrds; + jsonArray.PushBack(rapidjson::Value(vrds), allocator); + break; + default: + assert(0); // programmer error + } + if (sep == NULL) + break; + str1 = sep + 1; + assert(checkbackslash); + } + } + else if (checkbackslash) + { + const char *str1 = value; + assert(str1); + while (1) + { + assert(str1 && (size_t)(str1 - value) <= len); + const char *sep = strchr(str1, '\\'); + const size_t llen = (sep != NULL) ? (sep - str1) : (value + len - str1); + std::string valueUtf8 = toUtf8.convertCharStringToUTF8(str1, llen); + // Trim trailing space if exists + if (!valueUtf8.empty() && valueUtf8.back() == ' ') + { + valueUtf8.pop_back(); + } + rapidjson::Value valueString; + valueString.SetString(valueUtf8.c_str(), valueUtf8.size(), allocator); + jsonArray.PushBack(valueString, allocator); + if (sep == NULL) + break; + str1 = sep + 1; + } + } + else // default + { + std::string valueUtf8 = toUtf8.convertCharStringToUTF8(value, len); + // Trim trailing space if exists + if (!valueUtf8.empty() && valueUtf8.back() == ' ') + { + valueUtf8.pop_back(); + } + rapidjson::Value valueString; + valueString.SetString(valueUtf8.c_str(), valueUtf8.size(), allocator); + jsonArray.PushBack(valueString, allocator); + } + } + + rapidjson::Value *toJson(const gdcm::DataSet &dataSet, const Tags &pickTags, const Tags &skipTags, const CharStringToUTF8Converter &toUtf8, rapidjson::Value &dicomTagsObject, rapidjson::Document::AllocatorType &allocator) + { + for (gdcm::DataSet::ConstIterator it = dataSet.Begin(); it != dataSet.End(); ++it) + { + const gdcm::DataElement &de = *it; + VR::VRType vr = de.GetVR(); + const gdcm::Tag &t = de.GetTag(); + if (t.IsGroupLength() || t == PIXEL_DATA_TAG || skipTags.find(t) != skipTags.end()) + continue; // skip useless group length and pixel data tag + if (!pickTags.empty() && pickTags.find(t) == pickTags.end()) + continue; // skip tags that are not in the pick list if it has any + + const bool isSequence = vr == VR::SQ || de.IsUndefinedLength(); + const bool isPrivateCreator = t.IsPrivateCreator(); + if (isSequence) + vr = VR::SQ; + else if (isPrivateCreator) + vr = VR::LO; // always prefer VR::LO (over invalid/UN) + else if (vr == VR::INVALID) + vr = VR::UN; + const char *vr_str = VR::GetVRString(vr); + assert(VR::GetVRTypeFromFile(vr_str) != VR::INVALID); + + rapidjson::Value tagValue; + + if (vr == VR::SQ) + { + // Sequence Value Representations are nested datasets + SmartPointer sqi; + sqi = de.GetValueAsSQ(); + if (sqi) + { + tagValue.SetArray(); + int nitems = sqi->GetNumberOfItems(); + for (int i = 1; i <= nitems; ++i) + { + const Item &item = sqi->GetItem(i); + const DataSet &nested = item.GetNestedDataSet(); + rapidjson::Value sequenceObject(rapidjson::kObjectType); + // grab all nested tags, empty pick and skip tag sets + toJson(nested, EMPTY_TAGS, EMPTY_TAGS, toUtf8, sequenceObject, allocator); + tagValue.PushBack(sequenceObject, allocator); + } + } + + // Strange code from gdcmJSON.cxx + // else if (const SequenceOfFragments *sqf = de.GetSequenceOfFragments()) + // { + // tagValue.SetNull(); // FIXME + // assert(0); + // } + // else + // { + // assert(de.IsEmpty()); + // // json_object_array_add(my_array, NULL ); // F.2.5 req ? + // } + } + else if (VR::IsASCII(vr)) + { + dataElementToJSONArray(vr, de, tagValue, toUtf8, allocator); + } + else + { + tagValue.SetArray(); + + switch (vr) + { + case VR::FD: + { + Element el; + el.Set(de.GetValue()); + int ellen = el.GetLength(); + for (int i = 0; i < ellen; ++i) + { + rapidjson::Value elValue; + elValue.SetDouble(el.GetValue(i)); + tagValue.PushBack(elValue, allocator); + } + } + break; + case VR::FL: + { + Element el; + el.Set(de.GetValue()); + int ellen = el.GetLength(); + for (int i = 0; i < ellen; ++i) + { + rapidjson::Value elValue; + elValue.SetFloat(el.GetValue(i)); + tagValue.PushBack(elValue, allocator); + } + } + break; + case VR::SS: + { + Element el; + el.Set(de.GetValue()); + int ellen = el.GetLength(); + for (int i = 0; i < ellen; ++i) + { + rapidjson::Value elValue; + elValue.SetInt(el.GetValue(i)); + tagValue.PushBack(elValue, allocator); + } + } + break; + case VR::US: + { + Element el; + el.Set(de.GetValue()); + int ellen = el.GetLength(); + for (int i = 0; i < ellen; ++i) + { + rapidjson::Value elValue; + elValue.SetUint(el.GetValue(i)); + tagValue.PushBack(elValue, allocator); + } + } + break; + case VR::SL: + { + Element el; + el.Set(de.GetValue()); + int ellen = el.GetLength(); + for (int i = 0; i < ellen; ++i) + { + rapidjson::Value elValue; + elValue.SetInt(el.GetValue(i)); + tagValue.PushBack(elValue, allocator); + } + } + break; + case VR::UL: + { + Element el; + el.Set(de.GetValue()); + int ellen = el.GetLength(); + for (int i = 0; i < ellen; ++i) + { + rapidjson::Value elValue; + elValue.SetUint(el.GetValue(i)); + tagValue.PushBack(elValue, allocator); + } + } + break; + case VR::AT: + { + Element el; + el.Set(de.GetValue()); + int ellen = el.GetLength(); + for (int i = 0; i < ellen; ++i) + { + const std::string atstr = el.GetValue(i).PrintAsContinuousUpperCaseString(); + rapidjson::Value jsonElement; + jsonElement.SetString(atstr.c_str(), atstr.size(), allocator); + tagValue.PushBack(jsonElement, allocator); + } + } + break; + case VR::UN: + case VR::INVALID: + case VR::OD: + case VR::OF: + case VR::OB: + case VR::OW: + { + assert(!de.IsUndefinedLength()); // handled before + const gdcm::ByteValue *bv = de.GetByteValue(); + if (bv) + { + // base64 streams have to be a multiple of 4 bytes in length + int encodedLengthEstimate = 2 * bv->GetLength(); + encodedLengthEstimate = ((encodedLengthEstimate / 4) + 1) * 4; + + const auto bin = itk::make_unique_for_overwrite(encodedLengthEstimate); + auto encodedLengthActual = + static_cast(itksysBase64_Encode((const unsigned char *)bv->GetPointer(), + static_cast(bv->GetLength()), + (unsigned char *)bin.get(), + 0)); + std::string encodedValue(bin.get(), encodedLengthActual); + tagValue.SetString(encodedValue.c_str(), encodedValue.size(), allocator); + } + } + break; + default: + assert(0); // programmer error + } // end switch + } // end array else + + if (tagValue.IsArray()) + { + int arraySize = tagValue.Size(); + if (arraySize == 0) + { + continue; // skip empty arrays + } + else if (arraySize == 1) + { + // Unwrap array of size 1 + tagValue = tagValue[0]; // different from gdcmJSON.cxx + } + } + + const std::string &label = getLabelFromTag(t, dataSet); + rapidjson::Value tagName; + tagName.SetString(label.c_str(), label.size(), allocator); + dicomTagsObject.AddMember(tagName, tagValue, allocator); + } + return &dicomTagsObject; + } +} + +rapidjson::Value *toJson(const gdcm::DataSet &dataSet, const Tags &pickTags, const Tags &skipTags, rapidjson::Value &dicomTagsObject, rapidjson::Document::AllocatorType &allocator) +{ + const auto specificCharacterSet = getTagBuffer(dataSet, SPECIFIC_CHARACTER_SET); + const std::string charSet = specificCharacterSet.first == nullptr ? "" : std::string(specificCharacterSet.first, specificCharacterSet.second); + const CharStringToUTF8Converter decoder = CharStringToUTF8Converter(charSet); + return toJson(dataSet, pickTags, skipTags, decoder, dicomTagsObject, allocator); +} + +using FileName = std::string; + +struct DicomFile +{ + FileName fileName; + gdcm::DataSet dataSet; + + DicomFile(const FileName &fileName) + : fileName(fileName) + { + gdcm::ImageReader reader; + reader.SetFileName(fileName.c_str()); + if (!reader.Read()) + { + throw std::runtime_error("Failed to read the input DICOM file: " + fileName); + } + const gdcm::File &f = reader.GetFile(); + dataSet = f.GetDataSet(); + } + + bool operator==(const DicomFile &other) const + { + return fileName == other.fileName; + } +}; + +struct dicomFileHash +{ + std::size_t operator()(const DicomFile &dicomFile) const + { + return std::hash{}(dicomFile.fileName); + } +}; +using DicomFiles = std::unordered_set; + +DicomFiles loadFiles(const std::vector &fileNames) +{ + DicomFiles dicomFiles; + for (const FileName &fileName : fileNames) + { + dicomFiles.insert(DicomFile(fileName)); + } + return dicomFiles; +} + +using Volume = std::vector; +using Volumes = std::vector; // Aka ImageSet. A set of volumes/series that share Study and Patient. +using ImageSets = std::vector; + +bool compareTags(const gdcm::DataSet &tagsA, const gdcm::DataSet &tagsB, const Tags &tagKeys) +{ + for (const auto &tagKey : tagKeys) + { + const auto tagA = getTagBuffer(tagsA, tagKey); + const auto tagB = getTagBuffer(tagsB, tagKey); + if (tagA.first == nullptr || tagB.first == nullptr) + { + return false; + } + if (std::memcmp(tagA.first, tagB.first, tagB.second) != 0) + { + return false; + } + } + return true; +} + +bool isSameVolume(const gdcm::DataSet &tagsA, const gdcm::DataSet &tagsB, const Tags &criteria) +{ + return compareTags(tagsA, tagsB, criteria); +} + +Volumes groupByVolume(const DicomFiles &dicomFiles, const Tags &criteria = {SERIES_UID, FRAME_OF_REFERENCE_UID}) +{ + Volumes volumes; + for (const DicomFile &dicomFile : dicomFiles) + { + const auto candidate = dicomFile.dataSet; + auto matchingVolume = std::find_if(volumes.begin(), volumes.end(), [&candidate, &criteria](const Volume &volume) + { return isSameVolume(volume.begin()->dataSet, candidate, criteria); }); + + if (matchingVolume != volumes.end()) + { + matchingVolume->push_back(dicomFile); + } + else + { + Volume newVolume({dicomFile}); + volumes.push_back(newVolume); + } + } + return volumes; +} + +ImageSets groupByImageSet(const Volumes &volumes, const Tags &imageSetCriteria = {STUDY_UID}) +{ + ImageSets imageSets; + for (const Volume &volume : volumes) + { + const gdcm::DataSet volumeDataSet = volume.begin()->dataSet; + auto matchingImageSet = std::find_if(imageSets.begin(), imageSets.end(), [&volumeDataSet, &imageSetCriteria](const Volumes &volumes) + { + const gdcm::DataSet imageSetDataSet = volumes.begin()->begin()->dataSet; + return compareTags(volumeDataSet, imageSetDataSet, imageSetCriteria); }); + if (matchingImageSet != imageSets.end()) + { + matchingImageSet->push_back(volume); + } + else + { + Volumes newImageSet({volume}); + imageSets.push_back(newImageSet); + } + } + return imageSets; +} + +Volumes sortSpatially(Volumes &volumes) +{ + Volumes sortedVolumes; + for (Volume &volume : volumes) + { + std::vector unsortedSeriesFileNames; + for (const DicomFile &dicomFile : volume) + { + unsortedSeriesFileNames.push_back(dicomFile.fileName); + } + std::vector sortedFileNames = sortSpatially(unsortedSeriesFileNames); + + Volume sorted; + for (const auto &fileName : sortedFileNames) + { + const auto matchingDicomFile = std::find_if(volume.begin(), volume.end(), [&fileName](const DicomFile &dicomFile) + { return dicomFile.fileName == fileName; }); + if (matchingDicomFile != volume.end()) + { + sorted.push_back(*matchingDicomFile); + } + } + sortedVolumes.push_back(sorted); + } + return sortedVolumes; +} + +std::string getUID(const gdcm::DataSet &ds, const Tag &tag) +{ + if (!ds.FindDataElement(tag) || ds.GetDataElement(tag).IsEmpty()) + { + throw std::runtime_error("Tag not found"); + } + const gdcm::DataElement de = ds.GetDataElement(tag); + const gdcm::ByteValue *bv = de.GetByteValue(); + const char *tagValue = bv->GetPointer(); + size_t len = bv->GetLength(); + return std::string(tagValue, len); +} + +rapidjson::Document toJson(const ImageSets &imageSets) +{ + rapidjson::Document imageSetsJson(rapidjson::kArrayType); + rapidjson::Document::AllocatorType &allocator = imageSetsJson.GetAllocator(); + for (const Volumes &volumes : imageSets) + { + gdcm::DataSet dataSet; + rapidjson::Value seriesById(rapidjson::kObjectType); + for (const Volume &volume : volumes) + { + rapidjson::Value instances(rapidjson::kObjectType); + for (const auto &dicomFile : volume) + { + FileName file = dicomFile.fileName; + dataSet = dicomFile.dataSet; + rapidjson::Value instanceTagsJson(rapidjson::kObjectType); + + toJson(dataSet, EMPTY_TAGS, NON_INSTANCE, instanceTagsJson, allocator); + rapidjson::Value instance(rapidjson::kObjectType); + instance.AddMember("DICOM", instanceTagsJson, allocator); + + rapidjson::Value fileNameValue; + fileNameValue.SetString(file.c_str(), file.size(), allocator); + rapidjson::Value imageFrame(rapidjson::kObjectType); + imageFrame.AddMember("ID", fileNameValue, allocator); + rapidjson::Value imageFrames(rapidjson::kArrayType); + imageFrames.PushBack(imageFrame, allocator); + instance.AddMember("ImageFrames", imageFrames, allocator); + + // instance by UID under instances + const std::string instanceUID = getUID(dataSet, INSTANCE_UID); + rapidjson::Value instanceId; + instanceId.SetString(instanceUID.c_str(), instanceUID.size(), allocator); + instances.AddMember(instanceId, instance, allocator); + } + + // Series + rapidjson::Value seriesTags(rapidjson::kObjectType); + toJson(dataSet, SERIES_TAGS, EMPTY_TAGS, seriesTags, allocator); + rapidjson::Value series(rapidjson::kObjectType); + series.AddMember("DICOM", seriesTags, allocator); + series.AddMember("Instances", instances, allocator); + + int volumeIndex = std::distance(volumes.begin(), std::find(volumes.begin(), volumes.end(), volume)); + const std::string seriesId = getUID(dataSet, SERIES_UID) + '.' + std::to_string(volumeIndex); + + rapidjson::Value seriesIdJson; + seriesIdJson.SetString(seriesId.c_str(), seriesId.size(), allocator); + seriesById.AddMember(seriesIdJson, series, allocator); + } + + rapidjson::Value imageSet(rapidjson::kObjectType); + + // Patient + rapidjson::Value patientTags(rapidjson::kObjectType); + toJson(dataSet, PATIENT_TAGS, EMPTY_TAGS, patientTags, allocator); + rapidjson::Value patient(rapidjson::kObjectType); + patient.AddMember("DICOM", patientTags, allocator); + imageSet.AddMember("Patient", patient, allocator); + + // Study + rapidjson::Value studyTags(rapidjson::kObjectType); + toJson(dataSet, STUDY_TAGS, EMPTY_TAGS, studyTags, allocator); + rapidjson::Value study(rapidjson::kObjectType); + study.AddMember("DICOM", studyTags, allocator); + study.AddMember("Series", seriesById, allocator); + imageSet.AddMember("Study", study, allocator); + + imageSetsJson.PushBack(imageSet, allocator); + } + return imageSetsJson; +} + +int main(int argc, char *argv[]) +{ + itk::wasm::Pipeline pipeline("image-sets-normalization", "Group DICOM files into image sets", argc, argv); + + std::vector files; + pipeline.add_option("--files", files, "DICOM files")->required()->check(CLI::ExistingFile)->type_size(1, -1)->type_name("INPUT_BINARY_FILE"); + + itk::wasm::InputTextStream seriesGroupByOption; + pipeline.add_option("--series-group-by", seriesGroupByOption, "Create series so that all instances in a series share these tags. Option is a JSON object with a \"tags\" array. Example tag: \"0008|103e\". If not provided, defaults to Series UID and Frame Of Reference UID tags.")->type_name("INPUT_JSON"); + itk::wasm::InputTextStream imageSetGroupByOption; + pipeline.add_option("--image-set-group-by", imageSetGroupByOption, "Create image sets so that all series in a set share these tags. Option is a JSON object with a \"tags\" array. Example tag: \"0008|103e\". If not provided, defaults to Study UID tag.")->type_name("INPUT_JSON"); + + itk::wasm::OutputTextStream imageSetsOutput; + pipeline.add_option("image-sets", imageSetsOutput, "Image sets JSON")->required()->type_name("OUTPUT_JSON"); + + ITK_WASM_PARSE(pipeline); + + const std::optional seriesGroupByParse = parseTags(seriesGroupByOption, pipeline); + const Tags seriesGroupBy = seriesGroupByParse.value_or(SERIES_GROUP_BY_DEFAULT); + const std::optional imageSetGroupByParse = parseTags(imageSetGroupByOption, pipeline); + const Tags imageSetGroupBy = imageSetGroupByParse.value_or(IMAGE_SET_GROUP_BY_DEFAULT); + + const DicomFiles dicomFiles = loadFiles(files); + Volumes volumes = groupByVolume(dicomFiles, seriesGroupBy); + volumes = sortSpatially(volumes); + const ImageSets imageSets = groupByImageSet(volumes, imageSetGroupBy); + + rapidjson::Document imageSetsJson = toJson(imageSets); + rapidjson::StringBuffer stringBuffer; + rapidjson::Writer writer(stringBuffer); + imageSetsJson.Accept(writer); + imageSetsOutput.Get() << stringBuffer.GetString(); + + return EXIT_SUCCESS; +} diff --git a/packages/dicom/gdcm/read-dicom-tags.cxx b/packages/dicom/gdcm/read-dicom-tags.cxx index cf6d7fc55..de9cda83d 100644 --- a/packages/dicom/gdcm/read-dicom-tags.cxx +++ b/packages/dicom/gdcm/read-dicom-tags.cxx @@ -41,543 +41,7 @@ #include "itkInputTextStream.h" #include "itkOutputTextStream.h" -const std::string DEFAULT_ENCODING("ISO_IR 6"); -const std::string DEFAULT_ISO_2022_ENCODING("ISO 2022 IR 6"); -constexpr const char * ASCII = "ASCII"; - -// delimiters: CR, LF, FF, ESC, TAB (see -// https://dicom.nema.org/medical/dicom/current/output/html/part05.html#sect_6.1.3, -// table 6.1-1) -// Also includes 05/12 (BACKSLASH in IR 13 or YEN SIGN in IR 14), since that -// separates Data Element Values and it resets to initial charset. -// See: dicom part 5, sect 6.1.2.5.3 -constexpr const char * DEFAULT_DELIMS = "\x1b\x09\x0a\x0c\x0d\x5c"; -// DEFAULT_DELIMS + "^" and "=" -constexpr const char * PATIENT_NAME_DELIMS = "\x1b\x09\x0a\x0c\x0d\x5c^="; - -std::string -unpackMetaAsString(const itk::MetaDataObjectBase::Pointer & metaValue) -{ - using MetaDataStringType = itk::MetaDataObject; - MetaDataStringType::Pointer value = dynamic_cast(metaValue.GetPointer()); - if (value != nullptr) - { - return value->GetMetaDataObjectValue(); - } - return {}; -} - -// If not found, then pos == len -size_t -findDelim(const char * str, size_t len, size_t pos = 0, const char * delims = DEFAULT_DELIMS) -{ - while (pos < len && strchr(delims, str[pos]) == nullptr) - { - ++pos; - } - return pos; -} - -std::string -trimWhitespace(const std::string & term) -{ - auto start = term.begin(); - auto end = term.end(); - - while (start != end && std::isspace(*start)) - { - ++start; - } - - // need to --end once before checking isspace - do - { - --end; - } while (end != start && std::isspace(*end)); - - return std::string(start, end + 1); -} - -std::string -normalizeTerm(const std::string & term) -{ - return trimWhitespace(term); -} - -const char * -definedTermToIconvCharset(const std::string & defTerm) -{ - // be strict about comparing defined terms, so no fancy parsing - // that could possibly make these operations faster. - // See: - // https://dicom.nema.org/medical/dicom/current/output/chtml/part02/sect_D.6.2.html - if (defTerm == "ISO_IR 6" || defTerm == "ISO 2022 IR 6") - { - return ASCII; - } - if (defTerm == "ISO_IR 100" || defTerm == "ISO 2022 IR 100") - { - return "ISO-8859-1"; // Latin 1 - } - if (defTerm == "ISO_IR 101" || defTerm == "ISO 2022 IR 101") - { - return "ISO-8859-2"; // Latin 2 - } - if (defTerm == "ISO_IR 109" || defTerm == "ISO 2022 IR 109") - { - return "ISO-8859-3"; // Latin 3 - } - if (defTerm == "ISO_IR 110" || defTerm == "ISO 2022 IR 110") - { - return "ISO-8859-4"; // Latin 4 - } - if (defTerm == "ISO_IR 144" || defTerm == "ISO 2022 IR 144") - { - return "ISO-8859-5"; // Cyrillic - } - if (defTerm == "ISO_IR 127" || defTerm == "ISO 2022 IR 127") - { - return "ISO-8859-6"; // Arabic - } - if (defTerm == "ISO_IR 126" || defTerm == "ISO 2022 IR 126") - { - return "ISO-8859-7"; // Greek - } - if (defTerm == "ISO_IR 138" || defTerm == "ISO 2022 IR 138") - { - return "ISO-8859-8"; // Hebrew - } - if (defTerm == "ISO_IR 148" || defTerm == "ISO 2022 IR 148") - { - return "ISO-8859-9"; // Latin 5, Turkish - } - if (defTerm == "ISO_IR 13" || defTerm == "ISO 2022 IR 13") - { - // while technically not strict, SHIFT_JIS succeeds JIS X 0201 - // See: https://en.wikipedia.org/wiki/JIS_X_0201 - return "SHIFT_JIS"; // Japanese - } - if (defTerm == "ISO_IR 166" || defTerm == "ISO 2022 IR 166") - { - return "TIS-620"; // Thai - } - if (defTerm == "ISO 2022 IR 87") - { - // see: https://en.wikipedia.org/wiki/JIS_X_0208 - return "ISO-2022-JP"; // Japanese - } - if (defTerm == "ISO 2022 IR 159") - { - // see: https://en.wikipedia.org/wiki/JIS_X_0212 - return "ISO-2022-JP-1"; // Japanese - } - if (defTerm == "ISO 2022 IR 149") - { - return "EUC-KR"; // Korean - } - if (defTerm == "ISO 2022 IR 58") - { - return "EUC-CN"; // Chinese - } - if (defTerm == "ISO_IR 192") - { - return "UTF-8"; - } - if (defTerm == "GB18030") - { - return "GB18030"; - } - if (defTerm == "GBK") - { - return "GBK"; - } - return nullptr; -} - -// seq should be the sequence after the ESC char -// return value should match in definedTermToIconvCharset -const char * -iso2022EscSelectCharset(const char * seq) -{ - if (seq[0] == '(' && seq[1] == 'B') - { - return "ISO 2022 IR 6"; - } - if (seq[0] == '-' && seq[1] == 'A') - { - return "ISO 2022 IR 100"; - } - if (seq[0] == '-' && seq[1] == 'B') - { - return "ISO 2022 IR 101"; - } - if (seq[0] == '-' && seq[1] == 'C') - { - return "ISO 2022 IR 109"; - } - if (seq[0] == '-' && seq[1] == 'D') - { - return "ISO 2022 IR 110"; - } - if (seq[0] == '-' && seq[1] == 'L') - { - return "ISO 2022 IR 144"; - } - if (seq[0] == '-' && seq[1] == 'G') - { - return "ISO 2022 IR 127"; - } - if (seq[0] == '-' && seq[1] == 'F') - { - return "ISO 2022 IR 126"; - } - if (seq[0] == '-' && seq[1] == 'H') - { - return "ISO 2022 IR 138"; - } - if (seq[0] == '-' && seq[1] == 'M') - { - return "ISO 2022 IR 148"; - } - // technically 'J' corresponds to IR 14, byt SHIFT_JIS should still work - if (seq[0] == '-' && (seq[1] == 'I' || seq[1] == 'J')) - { - return "ISO 2022 IR 13"; - } - if (seq[0] == '-' && seq[1] == 'T') - { - return "ISO 2022 IR 166"; - } - if (seq[0] == '$' && seq[1] == 'B') - { - return "ISO 2022 IR 87"; - } - if (seq[0] == '$' && seq[1] == '(' && seq[2] == 'D') - { - return "ISO 2022 IR 159"; - } - if (seq[0] == '$' && seq[1] == ')' && seq[2] == 'C') - { - return "ISO 2022 IR 149"; - } - if (seq[0] == '$' && seq[1] == ')' && seq[2] == 'A') - { - return "ISO 2022 IR 58"; - } - if ((seq[0] == ')' && seq[1] == 'I') || (seq[0] == '(' && seq[1] == 'J')) - { - return "ISO 2022 IR 13"; - } - return ""; -} - -// seq should point after the ESC char. Returned length will -// not include ESC char. -size_t -iso2022EscSeqLength(const char * seq) -{ - if (seq[0] == '$' && seq[1] >= '(' && seq[1] <= '/') - { - return 3; - } - return 2; -} - -class CharStringToUTF8Converter -{ -public: - // See: setSpecificCharacterSet(const char *) - CharStringToUTF8Converter(const std::string & spcharsets) - : CharStringToUTF8Converter(spcharsets.c_str()) - {} - CharStringToUTF8Converter(const char * spcharsets) - : handlePatientName(false) - { - this->setSpecificCharacterSet(spcharsets); - }; - - /** - * Input must be the DICOM SpecificCharacterSet element value. - * See: - * https://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2 - */ - void - setSpecificCharacterSet(const char * spcharsets) - { - std::string specificCharacterSet(spcharsets); - std::string token; - std::istringstream tokStream(specificCharacterSet); - - m_charsets.clear(); - - int count = 0; - while (std::getline(tokStream, token, '\\')) - { - token = normalizeTerm(token); - - // case: first element is empty. Use default ISO-IR 6 encoding. - if (token.size() == 0 && count == 0) - { - m_charsets.push_back(DEFAULT_ENCODING); - // "Hack" to handle case where ISO-646 (dicom default encoding) is - // implicitly first in the list. Since we check for charset existence when - // switching charsets as per ISO 2022, we put both regular and ISO 2022 - // names for the default encoding. - m_charsets.push_back(DEFAULT_ISO_2022_ENCODING); - } - else if (m_charsets.end() == std::find(m_charsets.begin(), m_charsets.end(), token)) - { - // case: no duplicates - const char * chname = definedTermToIconvCharset(token); - // handle charsets that do not allow code extensions - if (count > 0 && (token == "GB18030" || token == "GBK" || token == "ISO_IR 192")) - { - std::cerr << "WARN: charset " << token << " does not support code extensions; ignoring" << std::endl; - } - else if (chname != nullptr && chname != ASCII) - { - // ISO_IR 6 isn't a formally recognized defined term, so use ASCII - // above. - m_charsets.push_back(token); - } - } - else - { - std::cerr << "WARN: Found duplicate charset '" + token + "'; ignoring" << std::endl; - } - ++count; - } - - if (count == 0) - { - // use default encoding - m_charsets.push_back(DEFAULT_ENCODING); - } - - if (m_charsets.size() == 0) - { - std::cerr << "WARN: Found no suitable charsets!" << std::endl; - } - } - - std::string - convertCharStringToUTF8(const std::string & str) - { - size_t len = str.size(); - return this->convertCharStringToUTF8(str.c_str(), len); - } - - std::string - convertCharStringToUTF8(const char * str, size_t len) - { - // m_charsets must always have at least 1 element prior to calling - const char * initialCharset = definedTermToIconvCharset(m_charsets[0]); - if (initialCharset == nullptr) - { - return {}; - } - - iconv_t cd = iconv_open("UTF-8", initialCharset); - if (cd == (iconv_t)-1) - { - return {}; - } - - int utf8len = len * 4; - std::unique_ptr result(new char[utf8len + 1]()); // UTF8 will have max length of utf8len - - // make a copy because iconv requires a char * - char * copiedStr = (char *)malloc(len + 1); - strncpy(copiedStr, str, len); - - char * inbuf = copiedStr; - char * outbuf = result.get(); - size_t inbytesleft = len; - size_t outbytesleft = utf8len; - - // special case: only one charset, so assume string is just that charset. - if (m_charsets.size() == 1) - { - iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); - } - else - { - size_t fragmentStart = 0; - size_t fragmentEnd = 0; - - while (fragmentStart < len) - { - const char * delims = this->handlePatientName ? PATIENT_NAME_DELIMS : DEFAULT_DELIMS; - // fragmentEnd will always be end of current fragment (exclusive end) - fragmentEnd = findDelim(str, len, fragmentStart + 1, delims); - inbuf = copiedStr + fragmentStart; - inbytesleft = fragmentEnd - fragmentStart; - - iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); - - fragmentStart = fragmentEnd; - bool isEsc = str[fragmentEnd] == 0x1b; - - if (fragmentStart < len) - { - const char * nextCharset; - int seek = 0; - - if (isEsc) - { // case: ISO 2022 escape encountered - const char * escSeq = copiedStr + fragmentStart + 1; - - const char * nextTerm = iso2022EscSelectCharset(escSeq); - nextCharset = definedTermToIconvCharset(std::string(nextTerm)); - if (nextCharset == nullptr || m_charsets.end() == std::find(m_charsets.begin(), m_charsets.end(), nextTerm)) - { - std::cerr << "WARN: bailing because invalid charset: " << nextTerm << std::endl; - break; // bail out - } - - // ISO-2022-JP is a variant on ISO 2022 for japanese, and so - // it defines its own escape sequences. As such, do not skip the - // escape sequences for ISO-2022-JP, so iconv can properly interpret - // them. - if (0 != strcmp("ISO-2022-JP", nextCharset) && 0 != strcmp("ISO-2022-JP-1", nextCharset)) - { - seek = iso2022EscSeqLength(escSeq) + 1; - } - } - else - { // case: hit a CR, LF, or FF - // reset to initial charset - nextCharset = initialCharset; - } - - if (0 != iconv_close(cd)) - { - std::cerr << "WARN: bailing because iconv_close" << std::endl; - break; // bail out - } - cd = iconv_open("UTF-8", nextCharset); - if (cd == (iconv_t)-1) - { - std::cerr << "WARN: bailing because iconv_open" << std::endl; - break; // bail out - } - - fragmentStart += seek; - } - } - } - - free(copiedStr); - iconv_close(cd); - - // since result is filled with NULL bytes, string constructor will figure out - // the correct string ending. - return std::string(result.get()); - } - - bool - getHandlePatientName() - { - return this->handlePatientName; - } - - void - setHandlePatientName(bool yn) - { - this->handlePatientName = yn; - } - -private: - std::vector m_charsets; - bool handlePatientName; -}; - -namespace itk -{ - -/** \class DICOMTagReader - * - * \brief Reads DICOM tags from a DICOM object. - */ -class DICOMTagReader -{ -public: - using MetaDictType = itk::MetaDataDictionary; - using TagMapType = std::map; - - DICOMTagReader() - : m_dirtyCache(true) - { - m_GDCMImageIO = GDCMImageIO::New(); - } - - /** Sets file name. */ - void - SetFileName(const std::string & file) - { - m_fileName = file; - m_GDCMImageIO->SetFileName(file); - m_dirtyCache = true; - } - - /** Verify file can be read. */ - bool - CanReadFile(const std::string & file) - { - return m_GDCMImageIO->CanReadFile(file.c_str()); - } - - std::string - ReadTag(const std::string & tag) - { - - if (m_dirtyCache) - { - m_GDCMImageIO->SetUseStreamedReading(true); - m_GDCMImageIO->ReadImageInformation(); - m_tagDict = m_GDCMImageIO->GetMetaDataDictionary(); - auto specificCharacterSet = unpackMetaAsString(m_tagDict["0008|0005"]); - m_decoder = CharStringToUTF8Converter(specificCharacterSet); - m_dirtyCache = false; - } - - auto value = unpackMetaAsString(m_tagDict[tag]); - return m_decoder.convertCharStringToUTF8(value); - } - - TagMapType - ReadAllTags() - { - - if (m_dirtyCache) - { - m_GDCMImageIO->SetUseStreamedReading(true); - m_GDCMImageIO->ReadImageInformation(); - m_tagDict = m_GDCMImageIO->GetMetaDataDictionary(); - auto specificCharacterSet = unpackMetaAsString(m_tagDict["0008|0005"]); - m_decoder = CharStringToUTF8Converter(specificCharacterSet); - m_dirtyCache = false; - } - - TagMapType allTagsDict; - for (auto it = m_tagDict.Begin(); it != m_tagDict.End(); ++it) - { - auto value = unpackMetaAsString(it->second); - allTagsDict[it->first] = m_decoder.convertCharStringToUTF8(value); - } - - return allTagsDict; - } - -private: - std::string m_fileName; - itk::GDCMImageIO::Pointer m_GDCMImageIO; - MetaDictType m_tagDict; - CharStringToUTF8Converter m_decoder = CharStringToUTF8Converter(""); - bool m_dirtyCache; -}; - -} // end namespace itk +#include "DICOMTagReader.h" int main( int argc, char * argv[] ) { diff --git a/packages/dicom/gdcm/read-image-dicom-file-series.cxx b/packages/dicom/gdcm/read-image-dicom-file-series.cxx index c93e51ea7..0795059f2 100644 --- a/packages/dicom/gdcm/read-image-dicom-file-series.cxx +++ b/packages/dicom/gdcm/read-image-dicom-file-series.cxx @@ -20,6 +20,10 @@ #include #include +#include "rapidjson/document.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/ostreamwrapper.h" + #include "itkCommonEnums.h" #include "gdcmSerieHelper.h" #include "itkImageIOBase.h" @@ -32,18 +36,7 @@ #include "itkOutputImage.h" #include "itkOutputTextStream.h" -#include "rapidjson/document.h" -#include "rapidjson/prettywriter.h" -#include "rapidjson/ostreamwrapper.h" - -class CustomSerieHelper: public gdcm::SerieHelper -{ -public: - void AddFileName(std::string const &fileName) - { - SerieHelper::AddFileName(fileName); - } -}; +#include "SortSpatially.h" namespace itk { @@ -210,60 +203,7 @@ int runPipeline(itk::wasm::Pipeline & pipeline, std::vector & input if (!singleSortedSeries) { - std::unique_ptr serieHelper(new CustomSerieHelper()); - for (const std::string & fileName: inputFileNames) - { - serieHelper->AddFileName(fileName); - } - serieHelper->SetUseSeriesDetails(true); - // Add the default restrictions to refine the file set into multiple series. - serieHelper->CreateDefaultUniqueSeriesIdentifier(); - using SeriesIdContainer = std::vector; - SeriesIdContainer seriesUIDs; - // Accessing the first serie found (assume there is at least one) - gdcm::FileList * flist = serieHelper->GetFirstSingleSerieUIDFileSet(); - while (flist) - { - if (!flist->empty()) // make sure we have at leat one serie - { - gdcm::File * file = (*flist)[0]; // for example take the first one - - // Create its unique series ID - const std::string id( serieHelper->CreateUniqueSeriesIdentifier(file)); - - seriesUIDs.push_back(id); - } - flist = serieHelper->GetNextSingleSerieUIDFileSet(); - } - - using FileNamesContainer = std::vector; - FileNamesContainer fileNames; - flist = serieHelper->GetFirstSingleSerieUIDFileSet(); - const std::string serie = seriesUIDs[0]; - bool found = false; - while (flist && !found) - { - if (!flist->empty()) // make sure we have at leat one serie - { - gdcm::File * file = (*flist)[0]; // for example take the first one - const std::string id( serieHelper->CreateUniqueSeriesIdentifier(file)); - if (id == serie) - { - found = true; // we found a match - break; - } - } - flist = serieHelper->GetNextSingleSerieUIDFileSet(); - } - serieHelper->OrderFileList(flist); - - gdcm::FileList::iterator it; - for (it = flist->begin(); it != flist->end(); ++it) - { - gdcm::FileWithName * header = *it; - fileNames.push_back(header->filename); - } - + std::vector fileNames = sortSpatially(inputFileNames); reader->SetFileNames(fileNames); } else diff --git a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/image_sets_normalization_async.py b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/image_sets_normalization_async.py new file mode 100644 index 000000000..feb74cef6 --- /dev/null +++ b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/image_sets_normalization_async.py @@ -0,0 +1,64 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, +) + +async def image_sets_normalization_async( + files: List[os.PathLike] = [], + series_group_by: Optional[Any] = None, + image_set_group_by: Optional[Any] = None, +) -> Any: + """Group DICOM files into image sets + + :param files: DICOM files + :type files: os.PathLike + + :param series_group_by: Create series so that all instances in a series share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Series UID and Frame Of Reference UID tags. + :type series_group_by: Any + + :param image_set_group_by: Create image sets so that all series in a set share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Study UID tag. + :type image_set_group_by: Any + + :return: Image sets JSON + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if files is not None: + kwargs["files"] = to_js(BinaryFile(files)) + if series_group_by is not None: + kwargs["seriesGroupBy"] = to_js(series_group_by) + if image_set_group_by is not None: + kwargs["imageSetGroupBy"] = to_js(image_set_group_by) + + outputs = await js_module.imageSetsNormalization(webWorker=web_worker, noCopy=True, **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py index c30a1d062..27b02cfe2 100644 --- a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py +++ b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py @@ -3,6 +3,6 @@ from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ -default_js_module = """data:text/javascript;base64,dmFyIFN0PU9iamVjdC5kZWZpbmVQcm9wZXJ0eTt2YXIgRnQ9KEEsZSk9Pntmb3IodmFyIHQgaW4gZSlTdChBLHQse2dldDplW3RdLGVudW1lcmFibGU6ITB9KX07dmFyIGt0PSI2LjAuMSIsa0E9a3Q7dmFyIFJ0PXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0saD1SdDt2YXIgYnQ9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LE09YnQ7ZnVuY3Rpb24gVXQoQSxlKXtsZXQgdD1udWxsO3N3aXRjaChBKXtjYXNlIGguVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBoLkludDg6e3Q9bmV3IEludDhBcnJheShlKTticmVha31jYXNlIGguVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShlKTticmVha31jYXNlIGguSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBoLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBoLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgaC5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBoLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoZSk6dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIE0uRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KGUpO2JyZWFrfWNhc2UgTS5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoZSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIEw9VXQ7dmFyIE50PXtVbmtub3duOiJVbmtub3duIixTY2FsYXI6IlNjYWxhciIsUkdCOiJSR0IiLFJHQkE6IlJHQkEiLE9mZnNldDoiT2Zmc2V0IixWZWN0b3I6IlZlY3RvciIsUG9pbnQ6IlBvaW50IixDb3ZhcmlhbnRWZWN0b3I6IkNvdmFyaWFudFZlY3RvciIsU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvcjoiU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvciIsRGlmZnVzaW9uVGVuc29yM0Q6IkRpZmZ1c2lvblRlbnNvcjNEIixDb21wbGV4OiJDb21wbGV4IixGaXhlZEFycmF5OiJGaXhlZEFycmF5IixBcnJheToiQXJyYXkiLE1hdHJpeDoiTWF0cml4IixWYXJpYWJsZUxlbmd0aFZlY3RvcjoiVmFyaWFibGVMZW5ndGhWZWN0b3IiLFZhcmlhYmxlU2l6ZU1hdHJpeDoiVmFyaWFibGVTaXplTWF0cml4In0sbGU9TnQ7dmFyIFJBPWNsYXNze2RpbWVuc2lvbjtjb21wb25lbnRUeXBlO3BpeGVsVHlwZTtjb21wb25lbnRzO2NvbnN0cnVjdG9yKGU9Mix0PWguVUludDgscj1sZS5TY2FsYXIsbj0xKXt0aGlzLmRpbWVuc2lvbj1lLHRoaXMuY29tcG9uZW50VHlwZT10LHRoaXMucGl4ZWxUeXBlPXIsdGhpcy5jb21wb25lbnRzPW59fSxCZT1SQTtmdW5jdGlvbiBHdChBLGUsdCxyLG4pe0Fbcit0KmVdPW59dmFyIENlPUd0O3ZhciBiQT1jbGFzc3tpbWFnZVR5cGU7bmFtZT0iaW1hZ2UiO29yaWdpbjtzcGFjaW5nO2RpcmVjdGlvbjtzaXplO21ldGFkYXRhO2RhdGE7Y29uc3RydWN0b3IoZT1uZXcgQmUpe3RoaXMuaW1hZ2VUeXBlPWU7bGV0IHQ9ZS5kaW1lbnNpb247dGhpcy5vcmlnaW49bmV3IEFycmF5KHQpLHRoaXMub3JpZ2luLmZpbGwoMCksdGhpcy5zcGFjaW5nPW5ldyBBcnJheSh0KSx0aGlzLnNwYWNpbmcuZmlsbCgxKSx0aGlzLmRpcmVjdGlvbj1uZXcgRmxvYXQ2NEFycmF5KHQqdCksdGhpcy5kaXJlY3Rpb24uZmlsbCgwKTtmb3IobGV0IHI9MDtyPHQ7cisrKUNlKHRoaXMuZGlyZWN0aW9uLHQscixyLDEpO3RoaXMuc2l6ZT1uZXcgQXJyYXkodCksdGhpcy5zaXplLmZpbGwoMCksdGhpcy5tZXRhZGF0YT1uZXcgTWFwLHRoaXMuZGF0YT1udWxsfX0sY2U9YkE7ZnVuY3Rpb24gVHQoQSl7aWYoQS5sZW5ndGg8MSl0aHJvdyBFcnJvcigiQXQgbGVhc3Qgb25lIGltYWdlcyBpcyByZXF1aXJlZC4iKTtsZXQgZT1BWzBdO2lmKGUuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIkltYWdlIGRhdGEgaXMgbnVsbC4iKTtsZXQgdD1uZXcgY2UoZS5pbWFnZVR5cGUpO3Qub3JpZ2luPUFycmF5LmZyb20oZS5vcmlnaW4pLHQuc3BhY2luZz1BcnJheS5mcm9tKGUuc3BhY2luZyk7bGV0IHI9dC5pbWFnZVR5cGUuZGltZW5zaW9uO3QuZGlyZWN0aW9uPWUuZGlyZWN0aW9uLnNsaWNlKCk7bGV0IG49ci0xO3Quc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSk7bGV0IGk9QS5yZWR1Y2UoKHMsYSk9PnMrYS5zaXplW25dLDApO3Quc2l6ZVtuXT1pO2xldCBvPXQuc2l6ZS5yZWR1Y2UoKHMsYSk9PnMqYSwxKSp0LmltYWdlVHlwZS5jb21wb25lbnRzLGc9ZS5kYXRhLmNvbnN0cnVjdG9yO3QuZGF0YT1uZXcgZyhvKTtsZXQgQz10LmltYWdlVHlwZS5jb21wb25lbnRzO2ZvcihsZXQgcz0wO3M8dC5zaXplLmxlbmd0aC0xO3MrKylDKj10LnNpemVbc107bGV0IGw9MDtpZih0LmRhdGEhPW51bGwpZm9yKGxldCBzPTA7czxBLmxlbmd0aDtzKyspdC5kYXRhLnNldChBW3NdLmRhdGEsQypsKSxsKz1BW3NdLnNpemVbbl07ZWxzZSB0aHJvdyBFcnJvcigiQ291bGQgbm90IGNyZWF0ZSByZXN1bHQgaW1hZ2UgZGF0YS4iKTtyZXR1cm4gdH12YXIgVUE9VHQ7dmFyIE5BPWNsYXNze2Zjbjt3b3JrZXJRdWV1ZTtydW5JbmZvO2NvbnN0cnVjdG9yKGUsdCl7dGhpcy5mY249dCx0aGlzLndvcmtlclF1ZXVlPW5ldyBBcnJheShlKSx0aGlzLndvcmtlclF1ZXVlLmZpbGwobnVsbCksdGhpcy5ydW5JbmZvPVtdfXJ1blRhc2tzKGUsdD1udWxsKXtsZXQgcj17dGFza1F1ZXVlOltdLHJlc3VsdHM6W10sYWRkaW5nVGFza3M6ITEscG9zdHBvbmVkOiExLHJ1bm5pbmdXb3JrZXJzOjAsaW5kZXg6MCxjb21wbGV0ZWRUYXNrczowLHByb2dyZXNzQ2FsbGJhY2s6dCxjYW5jZWxlZDohMX07cmV0dXJuIHRoaXMucnVuSW5mby5wdXNoKHIpLHIuaW5kZXg9dGhpcy5ydW5JbmZvLmxlbmd0aC0xLHtwcm9taXNlOm5ldyBQcm9taXNlKChuLGkpPT57ci5yZXNvbHZlPW4sci5yZWplY3Q9aSxyLnJlc3VsdHM9bmV3IEFycmF5KGUubGVuZ3RoKSxyLmNvbXBsZXRlZFRhc2tzPTAsci5hZGRpbmdUYXNrcz0hMCxlLmZvckVhY2goKG8sZyk9Pnt0aGlzLmFkZFRhc2soci5pbmRleCxnLG8pfSksci5hZGRpbmdUYXNrcz0hMX0pLHJ1bklkOnIuaW5kZXh9fXRlcm1pbmF0ZVdvcmtlcnMoKXtmb3IobGV0IGU9MDtlPHRoaXMud29ya2VyUXVldWUubGVuZ3RoO2UrKyl7bGV0IHQ9dGhpcy53b3JrZXJRdWV1ZVtlXTt0Py50ZXJtaW5hdGUoKSx0aGlzLndvcmtlclF1ZXVlW2VdPW51bGx9fWNhbmNlbChlKXtsZXQgdD10aGlzLnJ1bkluZm9bZV07dCE9bnVsbCYmKHQuY2FuY2VsZWQ9ITApfWFkZFRhc2soZSx0LHIpe2xldCBuPXRoaXMucnVuSW5mb1tlXTtpZihuPy5jYW5jZWxlZD09PSEwKXtuLnJlamVjdCgiUmVtYWluaW5nIHRhc2tzIGNhbmNlbGVkIiksdGhpcy5jbGVhclRhc2sobi5pbmRleCk7cmV0dXJufWlmKHRoaXMud29ya2VyUXVldWUubGVuZ3RoPjApe2xldCBpPXRoaXMud29ya2VyUXVldWUucG9wKCk7bi5ydW5uaW5nV29ya2VycysrLHJbci5sZW5ndGgtMV0ud2ViV29ya2VyPWksdGhpcy5mY24oLi4ucikudGhlbigoe3dlYldvcmtlcjpvLC4uLmd9KT0+e2lmKHRoaXMud29ya2VyUXVldWUucHVzaChvKSx0aGlzLnJ1bkluZm9bZV0hPT1udWxsKXtpZihuLnJ1bm5pbmdXb3JrZXJzLS0sbi5yZXN1bHRzW3RdPWcsbi5jb21wbGV0ZWRUYXNrcysrLG4ucHJvZ3Jlc3NDYWxsYmFjayE9bnVsbCYmbi5wcm9ncmVzc0NhbGxiYWNrKG4uY29tcGxldGVkVGFza3Msbi5yZXN1bHRzLmxlbmd0aCksbi50YXNrUXVldWUubGVuZ3RoPjApe2xldCBDPW4udGFza1F1ZXVlLnNoaWZ0KCk7dGhpcy5hZGRUYXNrKGUsQ1swXSxDWzFdKX1lbHNlIGlmKCFuLmFkZGluZ1Rhc2tzJiZuLnJ1bm5pbmdXb3JrZXJzPT09MCl7bGV0IEM9bi5yZXN1bHRzO24ucmVzb2x2ZShDKSx0aGlzLmNsZWFyVGFzayhuLmluZGV4KX19fSkuY2F0Y2gobz0+e24ucmVqZWN0KG8pLHRoaXMuY2xlYXJUYXNrKG4uaW5kZXgpfSl9ZWxzZSBuLnJ1bm5pbmdXb3JrZXJzIT09MHx8bi5wb3N0cG9uZWQ/bi50YXNrUXVldWUucHVzaChbdCxyXSk6KG4ucG9zdHBvbmVkPSEwLHNldFRpbWVvdXQoKCk9PntuLnBvc3Rwb25lZD0hMSx0aGlzLmFkZFRhc2sobi5pbmRleCx0LHIpfSw1MCkpfWNsZWFyVGFzayhlKXt0aGlzLnJ1bkluZm9bZV0ucmVzdWx0cz1bXSx0aGlzLnJ1bkluZm9bZV0udGFza1F1ZXVlPVtdLHRoaXMucnVuSW5mb1tlXS5wcm9ncmVzc0NhbGxiYWNrPW51bGwsdGhpcy5ydW5JbmZvW2VdLmNhbmNlbGVkPW51bGwsdGhpcy5ydW5JbmZvW2VdLnJlamVjdD0oKT0+e30sdGhpcy5ydW5JbmZvW2VdLnJlc29sdmU9KCk9Pnt9fX0sR0E9TkE7dmFyIEx0PXtUZXh0RmlsZToiVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkJpbmFyeUZpbGUiLFRleHRTdHJlYW06IlRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiQmluYXJ5U3RyZWFtIixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2giLFBvbHlEYXRhOiJQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6Ikpzb25Db21wYXRpYmxlIn0sUT1MdDt2YXIgRWU9U3ltYm9sKCJDb21saW5rLnByb3h5IikseHQ9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IikseEE9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLFRBPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxzQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksUWU9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsT3Q9e2NhbkhhbmRsZTpBPT5RZShBKSYmQVtFZV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTplLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gcGUoQSxlKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLE9BKEEpfX0sUHQ9e2NhbkhhbmRsZTpBPT5RZShBKSYmc0EgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgZTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP2U9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTplPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtlLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LGZlPW5ldyBNYXAoW1sicHJveHkiLE90XSxbInRocm93IixQdF1dKTtmdW5jdGlvbiBKdChBLGUpe2ZvcihsZXQgdCBvZiBBKWlmKGU9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gcGUoQSxlPWdsb2JhbFRoaXMsdD1bIioiXSl7ZS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiByKG4pe2lmKCFufHwhbi5kYXRhKXJldHVybjtpZighSnQodCxuLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gJyR7bi5vcmlnaW59JyBmb3IgY29tbGluayBwcm94eWApO3JldHVybn1sZXR7aWQ6aSx0eXBlOm8scGF0aDpnfT1PYmplY3QuYXNzaWduKHtwYXRoOltdfSxuLmRhdGEpLEM9KG4uZGF0YS5hcmd1bWVudExpc3R8fFtdKS5tYXAoSCksbDt0cnl7bGV0IHM9Zy5zbGljZSgwLC0xKS5yZWR1Y2UoKEUsQik9PkVbQl0sQSksYT1nLnJlZHVjZSgoRSxCKT0+RVtCXSxBKTtzd2l0Y2gobyl7Y2FzZSJHRVQiOmw9YTticmVhaztjYXNlIlNFVCI6c1tnLnNsaWNlKC0xKVswXV09SChuLmRhdGEudmFsdWUpLGw9ITA7YnJlYWs7Y2FzZSJBUFBMWSI6bD1hLmFwcGx5KHMsQyk7YnJlYWs7Y2FzZSJDT05TVFJVQ1QiOntsZXQgRT1uZXcgYSguLi5DKTtsPUt0KEUpfWJyZWFrO2Nhc2UiRU5EUE9JTlQiOntsZXR7cG9ydDE6RSxwb3J0MjpCfT1uZXcgTWVzc2FnZUNoYW5uZWw7cGUoQSxCKSxsPVBBKEUsW0VdKX1icmVhaztjYXNlIlJFTEVBU0UiOmw9dm9pZCAwO2JyZWFrO2RlZmF1bHQ6cmV0dXJufX1jYXRjaChzKXtsPXt2YWx1ZTpzLFtzQV06MH19UHJvbWlzZS5yZXNvbHZlKGwpLmNhdGNoKHM9Pih7dmFsdWU6cyxbc0FdOjB9KSkudGhlbihzPT57bGV0W2EsRV09bEEocyk7ZS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sYSkse2lkOml9KSxFKSxvPT09IlJFTEVBU0UiJiYoZS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixyKSxkZShlKSxUQSBpbiBBJiZ0eXBlb2YgQVtUQV09PSJmdW5jdGlvbiImJkFbVEFdKCkpfSkuY2F0Y2gocz0+e2xldFthLEVdPWxBKHt2YWx1ZTpuZXcgVHlwZUVycm9yKCJVbnNlcmlhbGl6YWJsZSByZXR1cm4gdmFsdWUiKSxbc0FdOjB9KTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxhKSx7aWQ6aX0pLEUpfSl9KSxlLnN0YXJ0JiZlLnN0YXJ0KCl9ZnVuY3Rpb24gSHQoQSl7cmV0dXJuIEEuY29uc3RydWN0b3IubmFtZT09PSJNZXNzYWdlUG9ydCJ9ZnVuY3Rpb24gZGUoQSl7SHQoQSkmJkEuY2xvc2UoKX1mdW5jdGlvbiBPQShBLGUpe3JldHVybiBMQShBLFtdLGUpfWZ1bmN0aW9uIGFBKEEpe2lmKEEpdGhyb3cgbmV3IEVycm9yKCJQcm94eSBoYXMgYmVlbiByZWxlYXNlZCBhbmQgaXMgbm90IHVzZWFibGUiKX1mdW5jdGlvbiBtZShBKXtyZXR1cm4gWShBLHt0eXBlOiJSRUxFQVNFIn0pLnRoZW4oKCk9PntkZShBKX0pfXZhciBJQT1uZXcgV2Vha01hcCxnQT0iRmluYWxpemF0aW9uUmVnaXN0cnkiaW4gZ2xvYmFsVGhpcyYmbmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KEE9PntsZXQgZT0oSUEuZ2V0KEEpfHwwKS0xO0lBLnNldChBLGUpLGU9PT0wJiZtZShBKX0pO2Z1bmN0aW9uIE10KEEsZSl7bGV0IHQ9KElBLmdldChlKXx8MCkrMTtJQS5zZXQoZSx0KSxnQSYmZ0EucmVnaXN0ZXIoQSxlLEEpfWZ1bmN0aW9uIFl0KEEpe2dBJiZnQS51bnJlZ2lzdGVyKEEpfWZ1bmN0aW9uIExBKEEsZT1bXSx0PWZ1bmN0aW9uKCl7fSl7bGV0IHI9ITEsbj1uZXcgUHJveHkodCx7Z2V0KGksbyl7aWYoYUEociksbz09PXhBKXJldHVybigpPT57WXQobiksbWUoQSkscj0hMH07aWYobz09PSJ0aGVuIil7aWYoZS5sZW5ndGg9PT0wKXJldHVybnt0aGVuOigpPT5ufTtsZXQgZz1ZKEEse3R5cGU6IkdFVCIscGF0aDplLm1hcChDPT5DLnRvU3RyaW5nKCkpfSkudGhlbihIKTtyZXR1cm4gZy50aGVuLmJpbmQoZyl9cmV0dXJuIExBKEEsWy4uLmUsb10pfSxzZXQoaSxvLGcpe2FBKHIpO2xldFtDLGxdPWxBKGcpO3JldHVybiBZKEEse3R5cGU6IlNFVCIscGF0aDpbLi4uZSxvXS5tYXAocz0+cy50b1N0cmluZygpKSx2YWx1ZTpDfSxsKS50aGVuKEgpfSxhcHBseShpLG8sZyl7YUEocik7bGV0IEM9ZVtlLmxlbmd0aC0xXTtpZihDPT09eHQpcmV0dXJuIFkoQSx7dHlwZToiRU5EUE9JTlQifSkudGhlbihIKTtpZihDPT09ImJpbmQiKXJldHVybiBMQShBLGUuc2xpY2UoMCwtMSkpO2xldFtsLHNdPXVlKGcpO3JldHVybiBZKEEse3R5cGU6IkFQUExZIixwYXRoOmUubWFwKGE9PmEudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Omx9LHMpLnRoZW4oSCl9LGNvbnN0cnVjdChpLG8pe2FBKHIpO2xldFtnLENdPXVlKG8pO3JldHVybiBZKEEse3R5cGU6IkNPTlNUUlVDVCIscGF0aDplLm1hcChsPT5sLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpnfSxDKS50aGVuKEgpfX0pO3JldHVybiBNdChuLEEpLG59ZnVuY3Rpb24gcXQoQSl7cmV0dXJuIEFycmF5LnByb3RvdHlwZS5jb25jYXQuYXBwbHkoW10sQSl9ZnVuY3Rpb24gdWUoQSl7bGV0IGU9QS5tYXAobEEpO3JldHVybltlLm1hcCh0PT50WzBdKSxxdChlLm1hcCh0PT50WzFdKSldfXZhciBoZT1uZXcgV2Vha01hcDtmdW5jdGlvbiBQQShBLGUpe3JldHVybiBoZS5zZXQoQSxlKSxBfWZ1bmN0aW9uIEt0KEEpe3JldHVybiBPYmplY3QuYXNzaWduKEEse1tFZV06ITB9KX1mdW5jdGlvbiBsQShBKXtmb3IobGV0W2UsdF1vZiBmZSlpZih0LmNhbkhhbmRsZShBKSl7bGV0W3Isbl09dC5zZXJpYWxpemUoQSk7cmV0dXJuW3t0eXBlOiJIQU5ETEVSIixuYW1lOmUsdmFsdWU6cn0sbl19cmV0dXJuW3t0eXBlOiJSQVciLHZhbHVlOkF9LGhlLmdldChBKXx8W11dfWZ1bmN0aW9uIEgoQSl7c3dpdGNoKEEudHlwZSl7Y2FzZSJIQU5ETEVSIjpyZXR1cm4gZmUuZ2V0KEEubmFtZSkuZGVzZXJpYWxpemUoQS52YWx1ZSk7Y2FzZSJSQVciOnJldHVybiBBLnZhbHVlfX1mdW5jdGlvbiBZKEEsZSx0KXtyZXR1cm4gbmV3IFByb21pc2Uocj0+e2xldCBuPVd0KCk7QS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBpKG8peyFvLmRhdGF8fCFvLmRhdGEuaWR8fG8uZGF0YS5pZCE9PW58fChBLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGkpLHIoby5kYXRhKSl9KSxBLnN0YXJ0JiZBLnN0YXJ0KCksQS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKHtpZDpufSxlKSx0KX0pfWZ1bmN0aW9uIFd0KCl7cmV0dXJuIG5ldyBBcnJheSg0KS5maWxsKDApLm1hcCgoKT0+TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKk51bWJlci5NQVhfU0FGRV9JTlRFR0VSKS50b1N0cmluZygxNikpLmpvaW4oIi0iKX1mdW5jdGlvbiBaKEEsZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIEEuYXBwbHkoZSxhcmd1bWVudHMpfX12YXJ7dG9TdHJpbmc6dnR9PU9iamVjdC5wcm90b3R5cGUse2dldFByb3RvdHlwZU9mOk1BfT1PYmplY3QsQ0E9KEE9PmU9PntsZXQgdD12dC5jYWxsKGUpO3JldHVybiBBW3RdfHwoQVt0XT10LnNsaWNlKDgsLTEpLnRvTG93ZXJDYXNlKCkpfSkoT2JqZWN0LmNyZWF0ZShudWxsKSksRz1BPT4oQT1BLnRvTG93ZXJDYXNlKCksZT0+Q0EoZSk9PT1BKSxjQT1BPT5lPT50eXBlb2YgZT09PUEse2lzQXJyYXk6cX09QXJyYXksWD1jQSgidW5kZWZpbmVkIik7ZnVuY3Rpb24ganQoQSl7cmV0dXJuIEEhPT1udWxsJiYhWChBKSYmQS5jb25zdHJ1Y3RvciE9PW51bGwmJiFYKEEuY29uc3RydWN0b3IpJiZVKEEuY29uc3RydWN0b3IuaXNCdWZmZXIpJiZBLmNvbnN0cnVjdG9yLmlzQnVmZmVyKEEpfXZhciBTZT1HKCJBcnJheUJ1ZmZlciIpO2Z1bmN0aW9uIF90KEEpe2xldCBlO3JldHVybiB0eXBlb2YgQXJyYXlCdWZmZXI8InUiJiZBcnJheUJ1ZmZlci5pc1ZpZXc/ZT1BcnJheUJ1ZmZlci5pc1ZpZXcoQSk6ZT1BJiZBLmJ1ZmZlciYmU2UoQS5idWZmZXIpLGV9dmFyIHp0PWNBKCJzdHJpbmciKSxVPWNBKCJmdW5jdGlvbiIpLEZlPWNBKCJudW1iZXIiKSx1QT1BPT5BIT09bnVsbCYmdHlwZW9mIEE9PSJvYmplY3QiLFZ0PUE9PkE9PT0hMHx8QT09PSExLEJBPUE9PntpZihDQShBKSE9PSJvYmplY3QiKXJldHVybiExO2xldCBlPU1BKEEpO3JldHVybihlPT09bnVsbHx8ZT09PU9iamVjdC5wcm90b3R5cGV8fE9iamVjdC5nZXRQcm90b3R5cGVPZihlKT09PW51bGwpJiYhKFN5bWJvbC50b1N0cmluZ1RhZyBpbiBBKSYmIShTeW1ib2wuaXRlcmF0b3IgaW4gQSl9LFp0PUcoIkRhdGUiKSxYdD1HKCJGaWxlIiksJHQ9RygiQmxvYiIpLEFyPUcoIkZpbGVMaXN0IiksZXI9QT0+dUEoQSkmJlUoQS5waXBlKSx0cj1BPT57bGV0IGU7cmV0dXJuIEEmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJkEgaW5zdGFuY2VvZiBGb3JtRGF0YXx8VShBLmFwcGVuZCkmJigoZT1DQShBKSk9PT0iZm9ybWRhdGEifHxlPT09Im9iamVjdCImJlUoQS50b1N0cmluZykmJkEudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0scnI9RygiVVJMU2VhcmNoUGFyYW1zIiksaXI9QT0+QS50cmltP0EudHJpbSgpOkEucmVwbGFjZSgvXltcc1x1RkVGRlx4QTBdK3xbXHNcdUZFRkZceEEwXSskL2csIiIpO2Z1bmN0aW9uICQoQSxlLHthbGxPd25LZXlzOnQ9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgcixuO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSxxKEEpKWZvcihyPTAsbj1BLmxlbmd0aDtyPG47cisrKWUuY2FsbChudWxsLEFbcl0scixBKTtlbHNle2xldCBpPXQ/T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSk6T2JqZWN0LmtleXMoQSksbz1pLmxlbmd0aCxnO2ZvcihyPTA7cjxvO3IrKylnPWlbcl0sZS5jYWxsKG51bGwsQVtnXSxnLEEpfX1mdW5jdGlvbiBrZShBLGUpe2U9ZS50b0xvd2VyQ2FzZSgpO2xldCB0PU9iamVjdC5rZXlzKEEpLHI9dC5sZW5ndGgsbjtmb3IoO3ItLSA+MDspaWYobj10W3JdLGU9PT1uLnRvTG93ZXJDYXNlKCkpcmV0dXJuIG47cmV0dXJuIG51bGx9dmFyIFJlPXR5cGVvZiBnbG9iYWxUaGlzPCJ1Ij9nbG9iYWxUaGlzOnR5cGVvZiBzZWxmPCJ1Ij9zZWxmOnR5cGVvZiB3aW5kb3c8InUiP3dpbmRvdzpnbG9iYWwsYmU9QT0+IVgoQSkmJkEhPT1SZTtmdW5jdGlvbiBIQSgpe2xldHtjYXNlbGVzczpBfT1iZSh0aGlzKSYmdGhpc3x8e30sZT17fSx0PShyLG4pPT57bGV0IGk9QSYma2UoZSxuKXx8bjtCQShlW2ldKSYmQkEocik/ZVtpXT1IQShlW2ldLHIpOkJBKHIpP2VbaV09SEEoe30scik6cShyKT9lW2ldPXIuc2xpY2UoKTplW2ldPXJ9O2ZvcihsZXQgcj0wLG49YXJndW1lbnRzLmxlbmd0aDtyPG47cisrKWFyZ3VtZW50c1tyXSYmJChhcmd1bWVudHNbcl0sdCk7cmV0dXJuIGV9dmFyIG5yPShBLGUsdCx7YWxsT3duS2V5czpyfT17fSk9PigkKGUsKG4saSk9Pnt0JiZVKG4pP0FbaV09WihuLHQpOkFbaV09bn0se2FsbE93bktleXM6cn0pLEEpLG9yPUE9PihBLmNoYXJDb2RlQXQoMCk9PT02NTI3OSYmKEE9QS5zbGljZSgxKSksQSksYXI9KEEsZSx0LHIpPT57QS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlLnByb3RvdHlwZSxyKSxBLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1BLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJzdXBlciIse3ZhbHVlOmUucHJvdG90eXBlfSksdCYmT2JqZWN0LmFzc2lnbihBLnByb3RvdHlwZSx0KX0sc3I9KEEsZSx0LHIpPT57bGV0IG4saSxvLGc9e307aWYoZT1lfHx7fSxBPT1udWxsKXJldHVybiBlO2Rve2ZvcihuPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKEEpLGk9bi5sZW5ndGg7aS0tID4wOylvPW5baV0sKCFyfHxyKG8sQSxlKSkmJiFnW29dJiYoZVtvXT1BW29dLGdbb109ITApO0E9dCE9PSExJiZNQShBKX13aGlsZShBJiYoIXR8fHQoQSxlKSkmJkEhPT1PYmplY3QucHJvdG90eXBlKTtyZXR1cm4gZX0sSXI9KEEsZSx0KT0+e0E9U3RyaW5nKEEpLCh0PT09dm9pZCAwfHx0PkEubGVuZ3RoKSYmKHQ9QS5sZW5ndGgpLHQtPWUubGVuZ3RoO2xldCByPUEuaW5kZXhPZihlLHQpO3JldHVybiByIT09LTEmJnI9PT10fSxncj1BPT57aWYoIUEpcmV0dXJuIG51bGw7aWYocShBKSlyZXR1cm4gQTtsZXQgZT1BLmxlbmd0aDtpZighRmUoZSkpcmV0dXJuIG51bGw7bGV0IHQ9bmV3IEFycmF5KGUpO2Zvcig7ZS0tID4wOyl0W2VdPUFbZV07cmV0dXJuIHR9LGxyPShBPT5lPT5BJiZlIGluc3RhbmNlb2YgQSkodHlwZW9mIFVpbnQ4QXJyYXk8InUiJiZNQShVaW50OEFycmF5KSksQnI9KEEsZSk9PntsZXQgcj0oQSYmQVtTeW1ib2wuaXRlcmF0b3JdKS5jYWxsKEEpLG47Zm9yKDsobj1yLm5leHQoKSkmJiFuLmRvbmU7KXtsZXQgaT1uLnZhbHVlO2UuY2FsbChBLGlbMF0saVsxXSl9fSxDcj0oQSxlKT0+e2xldCB0LHI9W107Zm9yKDsodD1BLmV4ZWMoZSkpIT09bnVsbDspci5wdXNoKHQpO3JldHVybiByfSxjcj1HKCJIVE1MRm9ybUVsZW1lbnQiKSx1cj1BPT5BLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXHNdKFthLXpcZF0pKFx3KikvZyxmdW5jdGlvbih0LHIsbil7cmV0dXJuIHIudG9VcHBlckNhc2UoKStufSksd2U9KCh7aGFzT3duUHJvcGVydHk6QX0pPT4oZSx0KT0+QS5jYWxsKGUsdCkpKE9iamVjdC5wcm90b3R5cGUpLEVyPUcoIlJlZ0V4cCIpLFVlPShBLGUpPT57bGV0IHQ9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoQSkscj17fTskKHQsKG4saSk9PntsZXQgbzsobz1lKG4saSxBKSkhPT0hMSYmKHJbaV09b3x8bil9KSxPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBLHIpfSxRcj1BPT57VWUoQSwoZSx0KT0+e2lmKFUoQSkmJlsiYXJndW1lbnRzIiwiY2FsbGVyIiwiY2FsbGVlIl0uaW5kZXhPZih0KSE9PS0xKXJldHVybiExO2xldCByPUFbdF07aWYoVShyKSl7aWYoZS5lbnVtZXJhYmxlPSExLCJ3cml0YWJsZSJpbiBlKXtlLndyaXRhYmxlPSExO3JldHVybn1lLnNldHx8KGUuc2V0PSgpPT57dGhyb3cgRXJyb3IoIkNhbiBub3QgcmV3cml0ZSByZWFkLW9ubHkgbWV0aG9kICciK3QrIiciKX0pfX0pfSxmcj0oQSxlKT0+e2xldCB0PXt9LHI9bj0+e24uZm9yRWFjaChpPT57dFtpXT0hMH0pfTtyZXR1cm4gcShBKT9yKEEpOnIoU3RyaW5nKEEpLnNwbGl0KGUpKSx0fSxwcj0oKT0+e30sZHI9KEEsZSk9PihBPStBLE51bWJlci5pc0Zpbml0ZShBKT9BOmUpLEpBPSJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiIsRGU9IjAxMjM0NTY3ODkiLE5lPXtESUdJVDpEZSxBTFBIQTpKQSxBTFBIQV9ESUdJVDpKQStKQS50b1VwcGVyQ2FzZSgpK0RlfSxtcj0oQT0xNixlPU5lLkFMUEhBX0RJR0lUKT0+e2xldCB0PSIiLHtsZW5ndGg6cn09ZTtmb3IoO0EtLTspdCs9ZVtNYXRoLnJhbmRvbSgpKnJ8MF07cmV0dXJuIHR9O2Z1bmN0aW9uIGhyKEEpe3JldHVybiEhKEEmJlUoQS5hcHBlbmQpJiZBW1N5bWJvbC50b1N0cmluZ1RhZ109PT0iRm9ybURhdGEiJiZBW1N5bWJvbC5pdGVyYXRvcl0pfXZhciB5cj1BPT57bGV0IGU9bmV3IEFycmF5KDEwKSx0PShyLG4pPT57aWYodUEocikpe2lmKGUuaW5kZXhPZihyKT49MClyZXR1cm47aWYoISgidG9KU09OImluIHIpKXtlW25dPXI7bGV0IGk9cShyKT9bXTp7fTtyZXR1cm4gJChyLChvLGcpPT57bGV0IEM9dChvLG4rMSk7IVgoQykmJihpW2ddPUMpfSksZVtuXT12b2lkIDAsaX19cmV0dXJuIHJ9O3JldHVybiB0KEEsMCl9LHdyPUcoIkFzeW5jRnVuY3Rpb24iKSxEcj1BPT5BJiYodUEoQSl8fFUoQSkpJiZVKEEudGhlbikmJlUoQS5jYXRjaCksST17aXNBcnJheTpxLGlzQXJyYXlCdWZmZXI6U2UsaXNCdWZmZXI6anQsaXNGb3JtRGF0YTp0cixpc0FycmF5QnVmZmVyVmlldzpfdCxpc1N0cmluZzp6dCxpc051bWJlcjpGZSxpc0Jvb2xlYW46VnQsaXNPYmplY3Q6dUEsaXNQbGFpbk9iamVjdDpCQSxpc1VuZGVmaW5lZDpYLGlzRGF0ZTpadCxpc0ZpbGU6WHQsaXNCbG9iOiR0LGlzUmVnRXhwOkVyLGlzRnVuY3Rpb246VSxpc1N0cmVhbTplcixpc1VSTFNlYXJjaFBhcmFtczpycixpc1R5cGVkQXJyYXk6bHIsaXNGaWxlTGlzdDpBcixmb3JFYWNoOiQsbWVyZ2U6SEEsZXh0ZW5kOm5yLHRyaW06aXIsc3RyaXBCT006b3IsaW5oZXJpdHM6YXIsdG9GbGF0T2JqZWN0OnNyLGtpbmRPZjpDQSxraW5kT2ZUZXN0OkcsZW5kc1dpdGg6SXIsdG9BcnJheTpncixmb3JFYWNoRW50cnk6QnIsbWF0Y2hBbGw6Q3IsaXNIVE1MRm9ybTpjcixoYXNPd25Qcm9wZXJ0eTp3ZSxoYXNPd25Qcm9wOndlLHJlZHVjZURlc2NyaXB0b3JzOlVlLGZyZWV6ZU1ldGhvZHM6UXIsdG9PYmplY3RTZXQ6ZnIsdG9DYW1lbENhc2U6dXIsbm9vcDpwcix0b0Zpbml0ZU51bWJlcjpkcixmaW5kS2V5OmtlLGdsb2JhbDpSZSxpc0NvbnRleHREZWZpbmVkOmJlLEFMUEhBQkVUOk5lLGdlbmVyYXRlU3RyaW5nOm1yLGlzU3BlY0NvbXBsaWFudEZvcm06aHIsdG9KU09OT2JqZWN0OnlyLGlzQXN5bmNGbjp3cixpc1RoZW5hYmxlOkRyfTtmdW5jdGlvbiBLKEEsZSx0LHIsbil7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPUEsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIixlJiYodGhpcy5jb2RlPWUpLHQmJih0aGlzLmNvbmZpZz10KSxyJiYodGhpcy5yZXF1ZXN0PXIpLG4mJih0aGlzLnJlc3BvbnNlPW4pfUkuaW5oZXJpdHMoSyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOkkudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIEdlPUsucHJvdG90eXBlLFRlPXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goQT0+e1RlW0FdPXt2YWx1ZTpBfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEssVGUpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShHZSwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtLLmZyb209KEEsZSx0LHIsbixpKT0+e2xldCBvPU9iamVjdC5jcmVhdGUoR2UpO3JldHVybiBJLnRvRmxhdE9iamVjdChBLG8sZnVuY3Rpb24oQyl7cmV0dXJuIEMhPT1FcnJvci5wcm90b3R5cGV9LGc9PmchPT0iaXNBeGlvc0Vycm9yIiksSy5jYWxsKG8sQS5tZXNzYWdlLGUsdCxyLG4pLG8uY2F1c2U9QSxvLm5hbWU9QS5uYW1lLGkmJk9iamVjdC5hc3NpZ24obyxpKSxvfTt2YXIgcD1LO3ZhciBFQT1udWxsO2Z1bmN0aW9uIFlBKEEpe3JldHVybiBJLmlzUGxhaW5PYmplY3QoQSl8fEkuaXNBcnJheShBKX1mdW5jdGlvbiB4ZShBKXtyZXR1cm4gSS5lbmRzV2l0aChBLCJbXSIpP0Euc2xpY2UoMCwtMik6QX1mdW5jdGlvbiBMZShBLGUsdCl7cmV0dXJuIEE/QS5jb25jYXQoZSkubWFwKGZ1bmN0aW9uKG4saSl7cmV0dXJuIG49eGUobiksIXQmJmk/IlsiK24rIl0iOm59KS5qb2luKHQ/Ii4iOiIiKTplfWZ1bmN0aW9uIFNyKEEpe3JldHVybiBJLmlzQXJyYXkoQSkmJiFBLnNvbWUoWUEpfXZhciBGcj1JLnRvRmxhdE9iamVjdChJLHt9LG51bGwsZnVuY3Rpb24oZSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KGUpfSk7ZnVuY3Rpb24ga3IoQSxlLHQpe2lmKCFJLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO2U9ZXx8bmV3KEVBfHxGb3JtRGF0YSksdD1JLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oYyxmKXtyZXR1cm4hSS5pc1VuZGVmaW5lZChmW2NdKX0pO2xldCByPXQubWV0YVRva2VucyxuPXQudmlzaXRvcnx8cyxpPXQuZG90cyxvPXQuaW5kZXhlcyxDPSh0LkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJkkuaXNTcGVjQ29tcGxpYW50Rm9ybShlKTtpZighSS5pc0Z1bmN0aW9uKG4pKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gbCh1KXtpZih1PT09bnVsbClyZXR1cm4iIjtpZihJLmlzRGF0ZSh1KSlyZXR1cm4gdS50b0lTT1N0cmluZygpO2lmKCFDJiZJLmlzQmxvYih1KSl0aHJvdyBuZXcgcCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gSS5pc0FycmF5QnVmZmVyKHUpfHxJLmlzVHlwZWRBcnJheSh1KT9DJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbdV0pOkJ1ZmZlci5mcm9tKHUpOnV9ZnVuY3Rpb24gcyh1LGMsZil7bGV0IGQ9dTtpZih1JiYhZiYmdHlwZW9mIHU9PSJvYmplY3QiKXtpZihJLmVuZHNXaXRoKGMsInt9IikpYz1yP2M6Yy5zbGljZSgwLC0yKSx1PUpTT04uc3RyaW5naWZ5KHUpO2Vsc2UgaWYoSS5pc0FycmF5KHUpJiZTcih1KXx8KEkuaXNGaWxlTGlzdCh1KXx8SS5lbmRzV2l0aChjLCJbXSIpKSYmKGQ9SS50b0FycmF5KHUpKSlyZXR1cm4gYz14ZShjKSxkLmZvckVhY2goZnVuY3Rpb24oUyxEdCl7IShJLmlzVW5kZWZpbmVkKFMpfHxTPT09bnVsbCkmJmUuYXBwZW5kKG89PT0hMD9MZShbY10sRHQsaSk6bz09PW51bGw/YzpjKyJbXSIsbChTKSl9KSwhMX1yZXR1cm4gWUEodSk/ITA6KGUuYXBwZW5kKExlKGYsYyxpKSxsKHUpKSwhMSl9bGV0IGE9W10sRT1PYmplY3QuYXNzaWduKEZyLHtkZWZhdWx0VmlzaXRvcjpzLGNvbnZlcnRWYWx1ZTpsLGlzVmlzaXRhYmxlOllBfSk7ZnVuY3Rpb24gQih1LGMpe2lmKCFJLmlzVW5kZWZpbmVkKHUpKXtpZihhLmluZGV4T2YodSkhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrYy5qb2luKCIuIikpO2EucHVzaCh1KSxJLmZvckVhY2godSxmdW5jdGlvbihkLGspeyghKEkuaXNVbmRlZmluZWQoZCl8fGQ9PT1udWxsKSYmbi5jYWxsKGUsZCxJLmlzU3RyaW5nKGspP2sudHJpbSgpOmssYyxFKSk9PT0hMCYmQihkLGM/Yy5jb25jYXQoayk6W2tdKX0pLGEucG9wKCl9fWlmKCFJLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gQihBKSxlfXZhciB4PWtyO2Z1bmN0aW9uIE9lKEEpe2xldCBlPXsiISI6IiUyMSIsIiciOiIlMjciLCIoIjoiJTI4IiwiKSI6IiUyOSIsIn4iOiIlN0UiLCIlMjAiOiIrIiwiJTAwIjoiXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shJygpfl18JTIwfCUwMC9nLGZ1bmN0aW9uKHIpe3JldHVybiBlW3JdfSl9ZnVuY3Rpb24gUGUoQSxlKXt0aGlzLl9wYWlycz1bXSxBJiZ4KEEsdGhpcyxlKX12YXIgSmU9UGUucHJvdG90eXBlO0plLmFwcGVuZD1mdW5jdGlvbihlLHQpe3RoaXMuX3BhaXJzLnB1c2goW2UsdF0pfTtKZS50b1N0cmluZz1mdW5jdGlvbihlKXtsZXQgdD1lP2Z1bmN0aW9uKHIpe3JldHVybiBlLmNhbGwodGhpcyxyLE9lKX06T2U7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihuKXtyZXR1cm4gdChuWzBdKSsiPSIrdChuWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIFFBPVBlO2Z1bmN0aW9uIFJyKEEpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvJTNBL2dpLCI6IikucmVwbGFjZSgvJTI0L2csIiQiKS5yZXBsYWNlKC8lMkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjAvZywiKyIpLnJlcGxhY2UoLyU1Qi9naSwiWyIpLnJlcGxhY2UoLyU1RC9naSwiXSIpfWZ1bmN0aW9uIEFBKEEsZSx0KXtpZighZSlyZXR1cm4gQTtsZXQgcj10JiZ0LmVuY29kZXx8UnIsbj10JiZ0LnNlcmlhbGl6ZSxpO2lmKG4/aT1uKGUsdCk6aT1JLmlzVVJMU2VhcmNoUGFyYW1zKGUpP2UudG9TdHJpbmcoKTpuZXcgUUEoZSx0KS50b1N0cmluZyhyKSxpKXtsZXQgbz1BLmluZGV4T2YoIiMiKTtvIT09LTEmJihBPUEuc2xpY2UoMCxvKSksQSs9KEEuaW5kZXhPZigiPyIpPT09LTE/Ij8iOiImIikraX1yZXR1cm4gQX12YXIgcUE9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLmhhbmRsZXJzPVtdfXVzZShlLHQscil7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOmUscmVqZWN0ZWQ6dCxzeW5jaHJvbm91czpyP3Iuc3luY2hyb25vdXM6ITEscnVuV2hlbjpyP3IucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX1lamVjdChlKXt0aGlzLmhhbmRsZXJzW2VdJiYodGhpcy5oYW5kbGVyc1tlXT1udWxsKX1jbGVhcigpe3RoaXMuaGFuZGxlcnMmJih0aGlzLmhhbmRsZXJzPVtdKX1mb3JFYWNoKGUpe0kuZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKHIpe3IhPT1udWxsJiZlKHIpfSl9fSxLQT1xQTt2YXIgZkE9e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITF9O3ZhciBIZT10eXBlb2YgVVJMU2VhcmNoUGFyYW1zPCJ1Ij9VUkxTZWFyY2hQYXJhbXM6UUE7dmFyIE1lPXR5cGVvZiBGb3JtRGF0YTwidSI/Rm9ybURhdGE6bnVsbDt2YXIgWWU9dHlwZW9mIEJsb2I8InUiP0Jsb2I6bnVsbDt2YXIgcWU9e2lzQnJvd3NlcjohMCxjbGFzc2VzOntVUkxTZWFyY2hQYXJhbXM6SGUsRm9ybURhdGE6TWUsQmxvYjpZZX0scHJvdG9jb2xzOlsiaHR0cCIsImh0dHBzIiwiZmlsZSIsImJsb2IiLCJ1cmwiLCJkYXRhIl19O3ZhciBXQT17fTtGdChXQSx7aGFzQnJvd3NlckVudjooKT0+S2UsaGFzU3RhbmRhcmRCcm93c2VyRW52OigpPT5icixoYXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY6KCk9PlVyfSk7dmFyIEtlPXR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUiLGJyPShBPT5LZSYmWyJSZWFjdE5hdGl2ZSIsIk5hdGl2ZVNjcmlwdCIsIk5TIl0uaW5kZXhPZihBKTwwKSh0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmbmF2aWdhdG9yLnByb2R1Y3QpLFVyPXR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIjt2YXIgdz17Li4uV0EsLi4ucWV9O2Z1bmN0aW9uIHZBKEEsZSl7cmV0dXJuIHgoQSxuZXcgdy5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyxPYmplY3QuYXNzaWduKHt2aXNpdG9yOmZ1bmN0aW9uKHQscixuLGkpe3JldHVybiB3LmlzTm9kZSYmSS5pc0J1ZmZlcih0KT8odGhpcy5hcHBlbmQocix0LnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOmkuZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfX0sZSkpfWZ1bmN0aW9uIE5yKEEpe3JldHVybiBJLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxBKS5tYXAoZT0+ZVswXT09PSJbXSI/IiI6ZVsxXXx8ZVswXSl9ZnVuY3Rpb24gR3IoQSl7bGV0IGU9e30sdD1PYmplY3Qua2V5cyhBKSxyLG49dC5sZW5ndGgsaTtmb3Iocj0wO3I8bjtyKyspaT10W3JdLGVbaV09QVtpXTtyZXR1cm4gZX1mdW5jdGlvbiBUcihBKXtmdW5jdGlvbiBlKHQscixuLGkpe2xldCBvPXRbaSsrXSxnPU51bWJlci5pc0Zpbml0ZSgrbyksQz1pPj10Lmxlbmd0aDtyZXR1cm4gbz0hbyYmSS5pc0FycmF5KG4pP24ubGVuZ3RoOm8sQz8oSS5oYXNPd25Qcm9wKG4sbyk/bltvXT1bbltvXSxyXTpuW29dPXIsIWcpOigoIW5bb118fCFJLmlzT2JqZWN0KG5bb10pKSYmKG5bb109W10pLGUodCxyLG5bb10saSkmJkkuaXNBcnJheShuW29dKSYmKG5bb109R3IobltvXSkpLCFnKX1pZihJLmlzRm9ybURhdGEoQSkmJkkuaXNGdW5jdGlvbihBLmVudHJpZXMpKXtsZXQgdD17fTtyZXR1cm4gSS5mb3JFYWNoRW50cnkoQSwocixuKT0+e2UoTnIociksbix0LDApfSksdH1yZXR1cm4gbnVsbH12YXIgcEE9VHI7ZnVuY3Rpb24gTHIoQSxlLHQpe2lmKEkuaXNTdHJpbmcoQSkpdHJ5e3JldHVybihlfHxKU09OLnBhcnNlKShBKSxJLnRyaW0oQSl9Y2F0Y2gocil7aWYoci5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyByfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoQSl9dmFyIGpBPXt0cmFuc2l0aW9uYWw6ZkEsYWRhcHRlcjpbInhociIsImh0dHAiXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihlLHQpe2xldCByPXQuZ2V0Q29udGVudFR5cGUoKXx8IiIsbj1yLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxpPUkuaXNPYmplY3QoZSk7aWYoaSYmSS5pc0hUTUxGb3JtKGUpJiYoZT1uZXcgRm9ybURhdGEoZSkpLEkuaXNGb3JtRGF0YShlKSlyZXR1cm4gbiYmbj9KU09OLnN0cmluZ2lmeShwQShlKSk6ZTtpZihJLmlzQXJyYXlCdWZmZXIoZSl8fEkuaXNCdWZmZXIoZSl8fEkuaXNTdHJlYW0oZSl8fEkuaXNGaWxlKGUpfHxJLmlzQmxvYihlKSlyZXR1cm4gZTtpZihJLmlzQXJyYXlCdWZmZXJWaWV3KGUpKXJldHVybiBlLmJ1ZmZlcjtpZihJLmlzVVJMU2VhcmNoUGFyYW1zKGUpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLGUudG9TdHJpbmcoKTtsZXQgZztpZihpKXtpZihyLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiB2QShlLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKGc9SS5pc0ZpbGVMaXN0KGUpKXx8ci5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBDPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4geChnP3siZmlsZXNbXSI6ZX06ZSxDJiZuZXcgQyx0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIGl8fG4/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSxMcihlKSk6ZX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihlKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8akEudHJhbnNpdGlvbmFsLHI9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxuPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKGUmJkkuaXNTdHJpbmcoZSkmJihyJiYhdGhpcy5yZXNwb25zZVR5cGV8fG4pKXtsZXQgbz0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZuO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlKX1jYXRjaChnKXtpZihvKXRocm93IGcubmFtZT09PSJTeW50YXhFcnJvciI/cC5mcm9tKGcscC5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTpnfX1yZXR1cm4gZX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6dy5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6dy5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0yMDAmJmU8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07SS5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLEE9PntqQS5oZWFkZXJzW0FdPXt9fSk7dmFyIFc9akE7dmFyIHhyPUkudG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksV2U9QT0+e2xldCBlPXt9LHQscixuO3JldHVybiBBJiZBLnNwbGl0KGAKYCkuZm9yRWFjaChmdW5jdGlvbihvKXtuPW8uaW5kZXhPZigiOiIpLHQ9by5zdWJzdHJpbmcoMCxuKS50cmltKCkudG9Mb3dlckNhc2UoKSxyPW8uc3Vic3RyaW5nKG4rMSkudHJpbSgpLCEoIXR8fGVbdF0mJnhyW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2gocik6ZVt0XT1bcl06ZVt0XT1lW3RdP2VbdF0rIiwgIityOnIpfSksZX07dmFyIHZlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBkQShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6SS5pc0FycmF5KEEpP0EubWFwKGRBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gT3IoQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15ccyw7PV0rKVxzKig/Oj1ccyooW14sO10rKSk/L2cscjtmb3IoO3I9dC5leGVjKEEpOyllW3JbMV1dPXJbMl07cmV0dXJuIGV9dmFyIFByPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhIyQlJicqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIF9BKEEsZSx0LHIsbil7aWYoSS5pc0Z1bmN0aW9uKHIpKXJldHVybiByLmNhbGwodGhpcyxlLHQpO2lmKG4mJihlPXQpLCEhSS5pc1N0cmluZyhlKSl7aWYoSS5pc1N0cmluZyhyKSlyZXR1cm4gZS5pbmRleE9mKHIpIT09LTE7aWYoSS5pc1JlZ0V4cChyKSlyZXR1cm4gci50ZXN0KGUpfX1mdW5jdGlvbiBKcihBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxkXSkoXHcqKS9nLChlLHQscik9PnQudG9VcHBlckNhc2UoKStyKX1mdW5jdGlvbiBIcihBLGUpe2xldCB0PUkudG9DYW1lbENhc2UoIiAiK2UpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChyPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KEEscit0LHt2YWx1ZTpmdW5jdGlvbihuLGksbyl7cmV0dXJuIHRoaXNbcl0uY2FsbCh0aGlzLGUsbixpLG8pfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciB2PWNsYXNze2NvbnN0cnVjdG9yKGUpe2UmJnRoaXMuc2V0KGUpfXNldChlLHQscil7bGV0IG49dGhpcztmdW5jdGlvbiBpKGcsQyxsKXtsZXQgcz1lQShDKTtpZighcyl0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IGE9SS5maW5kS2V5KG4scyk7KCFhfHxuW2FdPT09dm9pZCAwfHxsPT09ITB8fGw9PT12b2lkIDAmJm5bYV0hPT0hMSkmJihuW2F8fENdPWRBKGcpKX1sZXQgbz0oZyxDKT0+SS5mb3JFYWNoKGcsKGwscyk9PmkobCxzLEMpKTtyZXR1cm4gSS5pc1BsYWluT2JqZWN0KGUpfHxlIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9vKGUsdCk6SS5pc1N0cmluZyhlKSYmKGU9ZS50cmltKCkpJiYhUHIoZSk/byhXZShlKSx0KTplIT1udWxsJiZpKHQsZSxyKSx0aGlzfWdldChlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IHI9SS5maW5kS2V5KHRoaXMsZSk7aWYocil7bGV0IG49dGhpc1tyXTtpZighdClyZXR1cm4gbjtpZih0PT09ITApcmV0dXJuIE9yKG4pO2lmKEkuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMsbixyKTtpZihJLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMobik7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IHI9SS5maW5kS2V5KHRoaXMsZSk7cmV0dXJuISEociYmdGhpc1tyXSE9PXZvaWQgMCYmKCF0fHxfQSh0aGlzLHRoaXNbcl0scix0KSkpfXJldHVybiExfWRlbGV0ZShlLHQpe2xldCByPXRoaXMsbj0hMTtmdW5jdGlvbiBpKG8pe2lmKG89ZUEobyksbyl7bGV0IGc9SS5maW5kS2V5KHIsbyk7ZyYmKCF0fHxfQShyLHJbZ10sZyx0KSkmJihkZWxldGUgcltnXSxuPSEwKX19cmV0dXJuIEkuaXNBcnJheShlKT9lLmZvckVhY2goaSk6aShlKSxufWNsZWFyKGUpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLHI9dC5sZW5ndGgsbj0hMTtmb3IoO3ItLTspe2xldCBpPXRbcl07KCFlfHxfQSh0aGlzLHRoaXNbaV0saSxlLCEwKSkmJihkZWxldGUgdGhpc1tpXSxuPSEwKX1yZXR1cm4gbn1ub3JtYWxpemUoZSl7bGV0IHQ9dGhpcyxyPXt9O3JldHVybiBJLmZvckVhY2godGhpcywobixpKT0+e2xldCBvPUkuZmluZEtleShyLGkpO2lmKG8pe3Rbb109ZEEobiksZGVsZXRlIHRbaV07cmV0dXJufWxldCBnPWU/SnIoaSk6U3RyaW5nKGkpLnRyaW0oKTtnIT09aSYmZGVsZXRlIHRbaV0sdFtnXT1kQShuKSxyW2ddPSEwfSksdGhpc31jb25jYXQoLi4uZSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uZSl9dG9KU09OKGUpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIEkuZm9yRWFjaCh0aGlzLChyLG4pPT57ciE9bnVsbCYmciE9PSExJiYodFtuXT1lJiZJLmlzQXJyYXkocik/ci5qb2luKCIsICIpOnIpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbZSx0XSk9PmUrIjogIit0KS5qb2luKGAKYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIHRoaXM/ZTpuZXcgdGhpcyhlKX1zdGF0aWMgY29uY2F0KGUsLi4udCl7bGV0IHI9bmV3IHRoaXMoZSk7cmV0dXJuIHQuZm9yRWFjaChuPT5yLnNldChuKSkscn1zdGF0aWMgYWNjZXNzb3IoZSl7bGV0IHI9KHRoaXNbdmVdPXRoaXNbdmVdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsbj10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBpKG8pe2xldCBnPWVBKG8pO3JbZ118fChIcihuLG8pLHJbZ109ITApfXJldHVybiBJLmlzQXJyYXkoZSk/ZS5mb3JFYWNoKGkpOmkoZSksdGhpc319O3YuYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO0kucmVkdWNlRGVzY3JpcHRvcnModi5wcm90b3R5cGUsKHt2YWx1ZTpBfSxlKT0+e2xldCB0PWVbMF0udG9VcHBlckNhc2UoKStlLnNsaWNlKDEpO3JldHVybntnZXQ6KCk9PkEsc2V0KHIpe3RoaXNbdF09cn19fSk7SS5mcmVlemVNZXRob2RzKHYpO3ZhciBEPXY7ZnVuY3Rpb24gdEEoQSxlKXtsZXQgdD10aGlzfHxXLHI9ZXx8dCxuPUQuZnJvbShyLmhlYWRlcnMpLGk9ci5kYXRhO3JldHVybiBJLmZvckVhY2goQSxmdW5jdGlvbihnKXtpPWcuY2FsbCh0LGksbi5ub3JtYWxpemUoKSxlP2Uuc3RhdHVzOnZvaWQgMCl9KSxuLm5vcm1hbGl6ZSgpLGl9ZnVuY3Rpb24gckEoQSl7cmV0dXJuISEoQSYmQS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBqZShBLGUsdCl7cC5jYWxsKHRoaXMsQT8/ImNhbmNlbGVkIixwLkVSUl9DQU5DRUxFRCxlLHQpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9SS5pbmhlcml0cyhqZSxwLHtfX0NBTkNFTF9fOiEwfSk7dmFyIE89amU7ZnVuY3Rpb24gekEoQSxlLHQpe2xldCByPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IXJ8fHIodC5zdGF0dXMpP0EodCk6ZShuZXcgcCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFtwLkVSUl9CQURfUkVRVUVTVCxwLkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfXZhciBfZT13Lmhhc1N0YW5kYXJkQnJvd3NlckVudj97d3JpdGUoQSxlLHQscixuLGkpe2xldCBvPVtBKyI9IitlbmNvZGVVUklDb21wb25lbnQoZSldO0kuaXNOdW1iZXIodCkmJm8ucHVzaCgiZXhwaXJlcz0iK25ldyBEYXRlKHQpLnRvR01UU3RyaW5nKCkpLEkuaXNTdHJpbmcocikmJm8ucHVzaCgicGF0aD0iK3IpLEkuaXNTdHJpbmcobikmJm8ucHVzaCgiZG9tYWluPSIrbiksaT09PSEwJiZvLnB1c2goInNlY3VyZSIpLGRvY3VtZW50LmNvb2tpZT1vLmpvaW4oIjsgIil9LHJlYWQoQSl7bGV0IGU9ZG9jdW1lbnQuY29va2llLm1hdGNoKG5ldyBSZWdFeHAoIihefDtcXHMqKSgiK0ErIik9KFteO10qKSIpKTtyZXR1cm4gZT9kZWNvZGVVUklDb21wb25lbnQoZVszXSk6bnVsbH0scmVtb3ZlKEEpe3RoaXMud3JpdGUoQSwiIixEYXRlLm5vdygpLTg2NGU1KX19Ont3cml0ZSgpe30scmVhZCgpe3JldHVybiBudWxsfSxyZW1vdmUoKXt9fTtmdW5jdGlvbiBWQShBKXtyZXR1cm4vXihbYS16XVthLXpcZCtcLS5dKjopP1wvXC8vaS50ZXN0KEEpfWZ1bmN0aW9uIFpBKEEsZSl7cmV0dXJuIGU/QS5yZXBsYWNlKC9cLyskLywiIikrIi8iK2UucmVwbGFjZSgvXlwvKy8sIiIpOkF9ZnVuY3Rpb24gaUEoQSxlKXtyZXR1cm4gQSYmIVZBKGUpP1pBKEEsZSk6ZX12YXIgemU9dy5oYXNTdGFuZGFyZEJyb3dzZXJFbnY/ZnVuY3Rpb24oKXtsZXQgZT0vKG1zaWV8dHJpZGVudCkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpLHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYSIpLHI7ZnVuY3Rpb24gbihpKXtsZXQgbz1pO3JldHVybiBlJiYodC5zZXRBdHRyaWJ1dGUoImhyZWYiLG8pLG89dC5ocmVmKSx0LnNldEF0dHJpYnV0ZSgiaHJlZiIsbykse2hyZWY6dC5ocmVmLHByb3RvY29sOnQucHJvdG9jb2w/dC5wcm90b2NvbC5yZXBsYWNlKC86JC8sIiIpOiIiLGhvc3Q6dC5ob3N0LHNlYXJjaDp0LnNlYXJjaD90LnNlYXJjaC5yZXBsYWNlKC9eXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiMvLCIiKToiIixob3N0bmFtZTp0Lmhvc3RuYW1lLHBvcnQ6dC5wb3J0LHBhdGhuYW1lOnQucGF0aG5hbWUuY2hhckF0KDApPT09Ii8iP3QucGF0aG5hbWU6Ii8iK3QucGF0aG5hbWV9fXJldHVybiByPW4od2luZG93LmxvY2F0aW9uLmhyZWYpLGZ1bmN0aW9uKG8pe2xldCBnPUkuaXNTdHJpbmcobyk/bihvKTpvO3JldHVybiBnLnByb3RvY29sPT09ci5wcm90b2NvbCYmZy5ob3N0PT09ci5ob3N0fX0oKTpmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiEwfX0oKTtmdW5jdGlvbiBYQShBKXtsZXQgZT0vXihbLStcd117MSwyNX0pKDo/XC9cL3w6KS8uZXhlYyhBKTtyZXR1cm4gZSYmZVsxXXx8IiJ9ZnVuY3Rpb24gTXIoQSxlKXtBPUF8fDEwO2xldCB0PW5ldyBBcnJheShBKSxyPW5ldyBBcnJheShBKSxuPTAsaT0wLG87cmV0dXJuIGU9ZSE9PXZvaWQgMD9lOjFlMyxmdW5jdGlvbihDKXtsZXQgbD1EYXRlLm5vdygpLHM9cltpXTtvfHwobz1sKSx0W25dPUMscltuXT1sO2xldCBhPWksRT0wO2Zvcig7YSE9PW47KUUrPXRbYSsrXSxhPWElQTtpZihuPShuKzEpJUEsbj09PWkmJihpPShpKzEpJUEpLGwtbzxlKXJldHVybjtsZXQgQj1zJiZsLXM7cmV0dXJuIEI/TWF0aC5yb3VuZChFKjFlMy9CKTp2b2lkIDB9fXZhciBWZT1NcjtmdW5jdGlvbiBaZShBLGUpe2xldCB0PTAscj1WZSg1MCwyNTApO3JldHVybiBuPT57bGV0IGk9bi5sb2FkZWQsbz1uLmxlbmd0aENvbXB1dGFibGU/bi50b3RhbDp2b2lkIDAsZz1pLXQsQz1yKGcpLGw9aTw9bzt0PWk7bGV0IHM9e2xvYWRlZDppLHRvdGFsOm8scHJvZ3Jlc3M6bz9pL286dm9pZCAwLGJ5dGVzOmcscmF0ZTpDfHx2b2lkIDAsZXN0aW1hdGVkOkMmJm8mJmw/KG8taSkvQzp2b2lkIDAsZXZlbnQ6bn07c1tlPyJkb3dubG9hZCI6InVwbG9hZCJdPSEwLEEocyl9fXZhciBZcj10eXBlb2YgWE1MSHR0cFJlcXVlc3Q8InUiLFhlPVlyJiZmdW5jdGlvbihBKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24odCxyKXtsZXQgbj1BLmRhdGEsaT1ELmZyb20oQS5oZWFkZXJzKS5ub3JtYWxpemUoKSx7cmVzcG9uc2VUeXBlOm8sd2l0aFhTUkZUb2tlbjpnfT1BLEM7ZnVuY3Rpb24gbCgpe0EuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udW5zdWJzY3JpYmUoQyksQS5zaWduYWwmJkEuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixDKX1sZXQgcztpZihJLmlzRm9ybURhdGEobikpe2lmKHcuaGFzU3RhbmRhcmRCcm93c2VyRW52fHx3Lmhhc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudilpLnNldENvbnRlbnRUeXBlKCExKTtlbHNlIGlmKChzPWkuZ2V0Q29udGVudFR5cGUoKSkhPT0hMSl7bGV0W2MsLi4uZl09cz9zLnNwbGl0KCI7IikubWFwKGQ9PmQudHJpbSgpKS5maWx0ZXIoQm9vbGVhbik6W107aS5zZXRDb250ZW50VHlwZShbY3x8Im11bHRpcGFydC9mb3JtLWRhdGEiLC4uLmZdLmpvaW4oIjsgIikpfX1sZXQgYT1uZXcgWE1MSHR0cFJlcXVlc3Q7aWYoQS5hdXRoKXtsZXQgYz1BLmF1dGgudXNlcm5hbWV8fCIiLGY9QS5hdXRoLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChBLmF1dGgucGFzc3dvcmQpKToiIjtpLnNldCgiQXV0aG9yaXphdGlvbiIsIkJhc2ljICIrYnRvYShjKyI6IitmKSl9bGV0IEU9aUEoQS5iYXNlVVJMLEEudXJsKTthLm9wZW4oQS5tZXRob2QudG9VcHBlckNhc2UoKSxBQShFLEEucGFyYW1zLEEucGFyYW1zU2VyaWFsaXplciksITApLGEudGltZW91dD1BLnRpbWVvdXQ7ZnVuY3Rpb24gQigpe2lmKCFhKXJldHVybjtsZXQgYz1ELmZyb20oImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiBhJiZhLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKSxkPXtkYXRhOiFvfHxvPT09InRleHQifHxvPT09Impzb24iP2EucmVzcG9uc2VUZXh0OmEucmVzcG9uc2Usc3RhdHVzOmEuc3RhdHVzLHN0YXR1c1RleHQ6YS5zdGF0dXNUZXh0LGhlYWRlcnM6Yyxjb25maWc6QSxyZXF1ZXN0OmF9O3pBKGZ1bmN0aW9uKFMpe3QoUyksbCgpfSxmdW5jdGlvbihTKXtyKFMpLGwoKX0sZCksYT1udWxsfWlmKCJvbmxvYWRlbmQiaW4gYT9hLm9ubG9hZGVuZD1COmEub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IWF8fGEucmVhZHlTdGF0ZSE9PTR8fGEuc3RhdHVzPT09MCYmIShhLnJlc3BvbnNlVVJMJiZhLnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChCKX0sYS5vbmFib3J0PWZ1bmN0aW9uKCl7YSYmKHIobmV3IHAoIlJlcXVlc3QgYWJvcnRlZCIscC5FQ09OTkFCT1JURUQsQSxhKSksYT1udWxsKX0sYS5vbmVycm9yPWZ1bmN0aW9uKCl7cihuZXcgcCgiTmV0d29yayBFcnJvciIscC5FUlJfTkVUV09SSyxBLGEpKSxhPW51bGx9LGEub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IGY9QS50aW1lb3V0PyJ0aW1lb3V0IG9mICIrQS50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLGQ9QS50cmFuc2l0aW9uYWx8fGZBO0EudGltZW91dEVycm9yTWVzc2FnZSYmKGY9QS50aW1lb3V0RXJyb3JNZXNzYWdlKSxyKG5ldyBwKGYsZC5jbGFyaWZ5VGltZW91dEVycm9yP3AuRVRJTUVET1VUOnAuRUNPTk5BQk9SVEVELEEsYSkpLGE9bnVsbH0sdy5oYXNTdGFuZGFyZEJyb3dzZXJFbnYmJihnJiZJLmlzRnVuY3Rpb24oZykmJihnPWcoQSkpLGd8fGchPT0hMSYmemUoRSkpKXtsZXQgYz1BLnhzcmZIZWFkZXJOYW1lJiZBLnhzcmZDb29raWVOYW1lJiZfZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO2MmJmkuc2V0KEEueHNyZkhlYWRlck5hbWUsYyl9bj09PXZvaWQgMCYmaS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBhJiZJLmZvckVhY2goaS50b0pTT04oKSxmdW5jdGlvbihmLGQpe2Euc2V0UmVxdWVzdEhlYWRlcihkLGYpfSksSS5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChhLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxvJiZvIT09Impzb24iJiYoYS5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmYS5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsWmUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZhLnVwbG9hZCYmYS51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihDPWM9PnthJiYocighY3x8Yy50eXBlP25ldyBPKG51bGwsQSxhKTpjKSxhLmFib3J0KCksYT1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUoQyksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP0MoKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsQykpKTtsZXQgdT1YQShFKTtpZih1JiZ3LnByb3RvY29scy5pbmRleE9mKHUpPT09LTEpe3IobmV3IHAoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrdSsiOiIscC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1hLnNlbmQobnx8bnVsbCl9KX07dmFyICRBPXtodHRwOkVBLHhocjpYZX07SS5mb3JFYWNoKCRBLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyICRlPUE9PmAtICR7QX1gLHFyPUE9PkkuaXNGdW5jdGlvbihBKXx8QT09PW51bGx8fEE9PT0hMSxtQT17Z2V0QWRhcHRlcjpBPT57QT1JLmlzQXJyYXkoQSk/QTpbQV07bGV0e2xlbmd0aDplfT1BLHQscixuPXt9O2ZvcihsZXQgaT0wO2k8ZTtpKyspe3Q9QVtpXTtsZXQgbztpZihyPXQsIXFyKHQpJiYocj0kQVsobz1TdHJpbmcodCkpLnRvTG93ZXJDYXNlKCldLHI9PT12b2lkIDApKXRocm93IG5ldyBwKGBVbmtub3duIGFkYXB0ZXIgJyR7b30nYCk7aWYocilicmVhaztuW298fCIjIitpXT1yfWlmKCFyKXtsZXQgaT1PYmplY3QuZW50cmllcyhuKS5tYXAoKFtnLENdKT0+YGFkYXB0ZXIgJHtnfSBgKyhDPT09ITE/ImlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50IjoiaXMgbm90IGF2YWlsYWJsZSBpbiB0aGUgYnVpbGQiKSksbz1lP2kubGVuZ3RoPjE/YHNpbmNlIDoKYCtpLm1hcCgkZSkuam9pbihgCmApOiIgIiskZShpWzBdKToiYXMgbm8gYWRhcHRlciBzcGVjaWZpZWQiO3Rocm93IG5ldyBwKCJUaGVyZSBpcyBubyBzdWl0YWJsZSBhZGFwdGVyIHRvIGRpc3BhdGNoIHRoZSByZXF1ZXN0ICIrbywiRVJSX05PVF9TVVBQT1JUIil9cmV0dXJuIHJ9LGFkYXB0ZXJzOiRBfTtmdW5jdGlvbiBBZShBKXtpZihBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnRocm93SWZSZXF1ZXN0ZWQoKSxBLnNpZ25hbCYmQS5zaWduYWwuYWJvcnRlZCl0aHJvdyBuZXcgTyhudWxsLEEpfWZ1bmN0aW9uIGhBKEEpe3JldHVybiBBZShBKSxBLmhlYWRlcnM9RC5mcm9tKEEuaGVhZGVycyksQS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlcXVlc3QpLFsicG9zdCIsInB1dCIsInBhdGNoIl0uaW5kZXhPZihBLm1ldGhvZCkhPT0tMSYmQS5oZWFkZXJzLnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiLCExKSxtQS5nZXRBZGFwdGVyKEEuYWRhcHRlcnx8Vy5hZGFwdGVyKShBKS50aGVuKGZ1bmN0aW9uKHIpe3JldHVybiBBZShBKSxyLmRhdGE9dEEuY2FsbChBLEEudHJhbnNmb3JtUmVzcG9uc2Usciksci5oZWFkZXJzPUQuZnJvbShyLmhlYWRlcnMpLHJ9LGZ1bmN0aW9uKHIpe3JldHVybiByQShyKXx8KEFlKEEpLHImJnIucmVzcG9uc2UmJihyLnJlc3BvbnNlLmRhdGE9dEEuY2FsbChBLEEudHJhbnNmb3JtUmVzcG9uc2Usci5yZXNwb25zZSksci5yZXNwb25zZS5oZWFkZXJzPUQuZnJvbShyLnJlc3BvbnNlLmhlYWRlcnMpKSksUHJvbWlzZS5yZWplY3Qocil9KX12YXIgQXQ9QT0+QSBpbnN0YW5jZW9mIEQ/QS50b0pTT04oKTpBO2Z1bmN0aW9uIFQoQSxlKXtlPWV8fHt9O2xldCB0PXt9O2Z1bmN0aW9uIHIobCxzLGEpe3JldHVybiBJLmlzUGxhaW5PYmplY3QobCkmJkkuaXNQbGFpbk9iamVjdChzKT9JLm1lcmdlLmNhbGwoe2Nhc2VsZXNzOmF9LGwscyk6SS5pc1BsYWluT2JqZWN0KHMpP0kubWVyZ2Uoe30scyk6SS5pc0FycmF5KHMpP3Muc2xpY2UoKTpzfWZ1bmN0aW9uIG4obCxzLGEpe2lmKEkuaXNVbmRlZmluZWQocykpe2lmKCFJLmlzVW5kZWZpbmVkKGwpKXJldHVybiByKHZvaWQgMCxsLGEpfWVsc2UgcmV0dXJuIHIobCxzLGEpfWZ1bmN0aW9uIGkobCxzKXtpZighSS5pc1VuZGVmaW5lZChzKSlyZXR1cm4gcih2b2lkIDAscyl9ZnVuY3Rpb24gbyhsLHMpe2lmKEkuaXNVbmRlZmluZWQocykpe2lmKCFJLmlzVW5kZWZpbmVkKGwpKXJldHVybiByKHZvaWQgMCxsKX1lbHNlIHJldHVybiByKHZvaWQgMCxzKX1mdW5jdGlvbiBnKGwscyxhKXtpZihhIGluIGUpcmV0dXJuIHIobCxzKTtpZihhIGluIEEpcmV0dXJuIHIodm9pZCAwLGwpfWxldCBDPXt1cmw6aSxtZXRob2Q6aSxkYXRhOmksYmFzZVVSTDpvLHRyYW5zZm9ybVJlcXVlc3Q6byx0cmFuc2Zvcm1SZXNwb25zZTpvLHBhcmFtc1NlcmlhbGl6ZXI6byx0aW1lb3V0Om8sdGltZW91dE1lc3NhZ2U6byx3aXRoQ3JlZGVudGlhbHM6byx3aXRoWFNSRlRva2VuOm8sYWRhcHRlcjpvLHJlc3BvbnNlVHlwZTpvLHhzcmZDb29raWVOYW1lOm8seHNyZkhlYWRlck5hbWU6byxvblVwbG9hZFByb2dyZXNzOm8sb25Eb3dubG9hZFByb2dyZXNzOm8sZGVjb21wcmVzczpvLG1heENvbnRlbnRMZW5ndGg6byxtYXhCb2R5TGVuZ3RoOm8sYmVmb3JlUmVkaXJlY3Q6byx0cmFuc3BvcnQ6byxodHRwQWdlbnQ6byxodHRwc0FnZW50Om8sY2FuY2VsVG9rZW46byxzb2NrZXRQYXRoOm8scmVzcG9uc2VFbmNvZGluZzpvLHZhbGlkYXRlU3RhdHVzOmcsaGVhZGVyczoobCxzKT0+bihBdChsKSxBdChzKSwhMCl9O3JldHVybiBJLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihzKXtsZXQgYT1DW3NdfHxuLEU9YShBW3NdLGVbc10scyk7SS5pc1VuZGVmaW5lZChFKSYmYSE9PWd8fCh0W3NdPUUpfSksdH12YXIgeUE9IjEuNi4yIjt2YXIgZWU9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57ZWVbQV09ZnVuY3Rpb24ocil7cmV0dXJuIHR5cGVvZiByPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIGV0PXt9O2VlLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQscil7ZnVuY3Rpb24gbihpLG8pe3JldHVybiJbQXhpb3MgdiIreUErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiAnIitpKyInIitvKyhyPyIuICIrcjoiIil9cmV0dXJuKGksbyxnKT0+e2lmKGU9PT0hMSl0aHJvdyBuZXcgcChuKG8sIiBoYXMgYmVlbiByZW1vdmVkIisodD8iIGluICIrdDoiIikpLHAuRVJSX0RFUFJFQ0FURUQpO3JldHVybiB0JiYhZXRbb10mJihldFtvXT0hMCxjb25zb2xlLndhcm4obihvLCIgaGFzIGJlZW4gZGVwcmVjYXRlZCBzaW5jZSB2Iit0KyIgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmVhciBmdXR1cmUiKSkpLGU/ZShpLG8sZyk6ITB9fTtmdW5jdGlvbiBLcihBLGUsdCl7aWYodHlwZW9mIEEhPSJvYmplY3QiKXRocm93IG5ldyBwKCJvcHRpb25zIG11c3QgYmUgYW4gb2JqZWN0IixwLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtsZXQgcj1PYmplY3Qua2V5cyhBKSxuPXIubGVuZ3RoO2Zvcig7bi0tID4wOyl7bGV0IGk9cltuXSxvPWVbaV07aWYobyl7bGV0IGc9QVtpXSxDPWc9PT12b2lkIDB8fG8oZyxpLEEpO2lmKEMhPT0hMCl0aHJvdyBuZXcgcCgib3B0aW9uICIraSsiIG11c3QgYmUgIitDLHAuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2NvbnRpbnVlfWlmKHQhPT0hMCl0aHJvdyBuZXcgcCgiVW5rbm93biBvcHRpb24gIitpLHAuRVJSX0JBRF9PUFRJT04pfX12YXIgd0E9e2Fzc2VydE9wdGlvbnM6S3IsdmFsaWRhdG9yczplZX07dmFyIFA9d0EudmFsaWRhdG9ycyxqPWNsYXNze2NvbnN0cnVjdG9yKGUpe3RoaXMuZGVmYXVsdHM9ZSx0aGlzLmludGVyY2VwdG9ycz17cmVxdWVzdDpuZXcgS0EscmVzcG9uc2U6bmV3IEtBfX1yZXF1ZXN0KGUsdCl7dHlwZW9mIGU9PSJzdHJpbmciPyh0PXR8fHt9LHQudXJsPWUpOnQ9ZXx8e30sdD1UKHRoaXMuZGVmYXVsdHMsdCk7bGV0e3RyYW5zaXRpb25hbDpyLHBhcmFtc1NlcmlhbGl6ZXI6bixoZWFkZXJzOml9PXQ7ciE9PXZvaWQgMCYmd0EuYXNzZXJ0T3B0aW9ucyhyLHtzaWxlbnRKU09OUGFyc2luZzpQLnRyYW5zaXRpb25hbChQLmJvb2xlYW4pLGZvcmNlZEpTT05QYXJzaW5nOlAudHJhbnNpdGlvbmFsKFAuYm9vbGVhbiksY2xhcmlmeVRpbWVvdXRFcnJvcjpQLnRyYW5zaXRpb25hbChQLmJvb2xlYW4pfSwhMSksbiE9bnVsbCYmKEkuaXNGdW5jdGlvbihuKT90LnBhcmFtc1NlcmlhbGl6ZXI9e3NlcmlhbGl6ZTpufTp3QS5hc3NlcnRPcHRpb25zKG4se2VuY29kZTpQLmZ1bmN0aW9uLHNlcmlhbGl6ZTpQLmZ1bmN0aW9ufSwhMCkpLHQubWV0aG9kPSh0Lm1ldGhvZHx8dGhpcy5kZWZhdWx0cy5tZXRob2R8fCJnZXQiKS50b0xvd2VyQ2FzZSgpO2xldCBvPWkmJkkubWVyZ2UoaS5jb21tb24saVt0Lm1ldGhvZF0pO2kmJkkuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJwb3N0IiwicHV0IiwicGF0Y2giLCJjb21tb24iXSx1PT57ZGVsZXRlIGlbdV19KSx0LmhlYWRlcnM9RC5jb25jYXQobyxpKTtsZXQgZz1bXSxDPSEwO3RoaXMuaW50ZXJjZXB0b3JzLnJlcXVlc3QuZm9yRWFjaChmdW5jdGlvbihjKXt0eXBlb2YgYy5ydW5XaGVuPT0iZnVuY3Rpb24iJiZjLnJ1bldoZW4odCk9PT0hMXx8KEM9QyYmYy5zeW5jaHJvbm91cyxnLnVuc2hpZnQoYy5mdWxmaWxsZWQsYy5yZWplY3RlZCkpfSk7bGV0IGw9W107dGhpcy5pbnRlcmNlcHRvcnMucmVzcG9uc2UuZm9yRWFjaChmdW5jdGlvbihjKXtsLnB1c2goYy5mdWxmaWxsZWQsYy5yZWplY3RlZCl9KTtsZXQgcyxhPTAsRTtpZighQyl7bGV0IHU9W2hBLmJpbmQodGhpcyksdm9pZCAwXTtmb3IodS51bnNoaWZ0LmFwcGx5KHUsZyksdS5wdXNoLmFwcGx5KHUsbCksRT11Lmxlbmd0aCxzPVByb21pc2UucmVzb2x2ZSh0KTthPEU7KXM9cy50aGVuKHVbYSsrXSx1W2ErK10pO3JldHVybiBzfUU9Zy5sZW5ndGg7bGV0IEI9dDtmb3IoYT0wO2E8RTspe2xldCB1PWdbYSsrXSxjPWdbYSsrXTt0cnl7Qj11KEIpfWNhdGNoKGYpe2MuY2FsbCh0aGlzLGYpO2JyZWFrfX10cnl7cz1oQS5jYWxsKHRoaXMsQil9Y2F0Y2godSl7cmV0dXJuIFByb21pc2UucmVqZWN0KHUpfWZvcihhPTAsRT1sLmxlbmd0aDthPEU7KXM9cy50aGVuKGxbYSsrXSxsW2ErK10pO3JldHVybiBzfWdldFVyaShlKXtlPVQodGhpcy5kZWZhdWx0cyxlKTtsZXQgdD1pQShlLmJhc2VVUkwsZS51cmwpO3JldHVybiBBQSh0LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplcil9fTtJLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKGUpe2oucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHQscil7cmV0dXJuIHRoaXMucmVxdWVzdChUKHJ8fHt9LHttZXRob2Q6ZSx1cmw6dCxkYXRhOihyfHx7fSkuZGF0YX0pKX19KTtJLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbihlKXtmdW5jdGlvbiB0KHIpe3JldHVybiBmdW5jdGlvbihpLG8sZyl7cmV0dXJuIHRoaXMucmVxdWVzdChUKGd8fHt9LHttZXRob2Q6ZSxoZWFkZXJzOnI/eyJDb250ZW50LVR5cGUiOiJtdWx0aXBhcnQvZm9ybS1kYXRhIn06e30sdXJsOmksZGF0YTpvfSkpfX1qLnByb3RvdHlwZVtlXT10KCksai5wcm90b3R5cGVbZSsiRm9ybSJdPXQoITApfSk7dmFyIG5BPWo7dmFyIHRlPWNsYXNzIEF7Y29uc3RydWN0b3IoZSl7aWYodHlwZW9mIGUhPSJmdW5jdGlvbiIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXhlY3V0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uLiIpO2xldCB0O3RoaXMucHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihpKXt0PWl9KTtsZXQgcj10aGlzO3RoaXMucHJvbWlzZS50aGVuKG49PntpZighci5fbGlzdGVuZXJzKXJldHVybjtsZXQgaT1yLl9saXN0ZW5lcnMubGVuZ3RoO2Zvcig7aS0tID4wOylyLl9saXN0ZW5lcnNbaV0obik7ci5fbGlzdGVuZXJzPW51bGx9KSx0aGlzLnByb21pc2UudGhlbj1uPT57bGV0IGksbz1uZXcgUHJvbWlzZShnPT57ci5zdWJzY3JpYmUoZyksaT1nfSkudGhlbihuKTtyZXR1cm4gby5jYW5jZWw9ZnVuY3Rpb24oKXtyLnVuc3Vic2NyaWJlKGkpfSxvfSxlKGZ1bmN0aW9uKGksbyxnKXtyLnJlYXNvbnx8KHIucmVhc29uPW5ldyBPKGksbyxnKSx0KHIucmVhc29uKSl9KX10aHJvd0lmUmVxdWVzdGVkKCl7aWYodGhpcy5yZWFzb24pdGhyb3cgdGhpcy5yZWFzb259c3Vic2NyaWJlKGUpe2lmKHRoaXMucmVhc29uKXtlKHRoaXMucmVhc29uKTtyZXR1cm59dGhpcy5fbGlzdGVuZXJzP3RoaXMuX2xpc3RlbmVycy5wdXNoKGUpOnRoaXMuX2xpc3RlbmVycz1bZV19dW5zdWJzY3JpYmUoZSl7aWYoIXRoaXMuX2xpc3RlbmVycylyZXR1cm47bGV0IHQ9dGhpcy5fbGlzdGVuZXJzLmluZGV4T2YoZSk7dCE9PS0xJiZ0aGlzLl9saXN0ZW5lcnMuc3BsaWNlKHQsMSl9c3RhdGljIHNvdXJjZSgpe2xldCBlO3JldHVybnt0b2tlbjpuZXcgQShmdW5jdGlvbihuKXtlPW59KSxjYW5jZWw6ZX19fSx0dD10ZTtmdW5jdGlvbiByZShBKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIEEuYXBwbHkobnVsbCx0KX19ZnVuY3Rpb24gaWUoQSl7cmV0dXJuIEkuaXNPYmplY3QoQSkmJkEuaXNBeGlvc0Vycm9yPT09ITB9dmFyIG5lPXtDb250aW51ZToxMDAsU3dpdGNoaW5nUHJvdG9jb2xzOjEwMSxQcm9jZXNzaW5nOjEwMixFYXJseUhpbnRzOjEwMyxPazoyMDAsQ3JlYXRlZDoyMDEsQWNjZXB0ZWQ6MjAyLE5vbkF1dGhvcml0YXRpdmVJbmZvcm1hdGlvbjoyMDMsTm9Db250ZW50OjIwNCxSZXNldENvbnRlbnQ6MjA1LFBhcnRpYWxDb250ZW50OjIwNixNdWx0aVN0YXR1czoyMDcsQWxyZWFkeVJlcG9ydGVkOjIwOCxJbVVzZWQ6MjI2LE11bHRpcGxlQ2hvaWNlczozMDAsTW92ZWRQZXJtYW5lbnRseTozMDEsRm91bmQ6MzAyLFNlZU90aGVyOjMwMyxOb3RNb2RpZmllZDozMDQsVXNlUHJveHk6MzA1LFVudXNlZDozMDYsVGVtcG9yYXJ5UmVkaXJlY3Q6MzA3LFBlcm1hbmVudFJlZGlyZWN0OjMwOCxCYWRSZXF1ZXN0OjQwMCxVbmF1dGhvcml6ZWQ6NDAxLFBheW1lbnRSZXF1aXJlZDo0MDIsRm9yYmlkZGVuOjQwMyxOb3RGb3VuZDo0MDQsTWV0aG9kTm90QWxsb3dlZDo0MDUsTm90QWNjZXB0YWJsZTo0MDYsUHJveHlBdXRoZW50aWNhdGlvblJlcXVpcmVkOjQwNyxSZXF1ZXN0VGltZW91dDo0MDgsQ29uZmxpY3Q6NDA5LEdvbmU6NDEwLExlbmd0aFJlcXVpcmVkOjQxMSxQcmVjb25kaXRpb25GYWlsZWQ6NDEyLFBheWxvYWRUb29MYXJnZTo0MTMsVXJpVG9vTG9uZzo0MTQsVW5zdXBwb3J0ZWRNZWRpYVR5cGU6NDE1LFJhbmdlTm90U2F0aXNmaWFibGU6NDE2LEV4cGVjdGF0aW9uRmFpbGVkOjQxNyxJbUFUZWFwb3Q6NDE4LE1pc2RpcmVjdGVkUmVxdWVzdDo0MjEsVW5wcm9jZXNzYWJsZUVudGl0eTo0MjIsTG9ja2VkOjQyMyxGYWlsZWREZXBlbmRlbmN5OjQyNCxUb29FYXJseTo0MjUsVXBncmFkZVJlcXVpcmVkOjQyNixQcmVjb25kaXRpb25SZXF1aXJlZDo0MjgsVG9vTWFueVJlcXVlc3RzOjQyOSxSZXF1ZXN0SGVhZGVyRmllbGRzVG9vTGFyZ2U6NDMxLFVuYXZhaWxhYmxlRm9yTGVnYWxSZWFzb25zOjQ1MSxJbnRlcm5hbFNlcnZlckVycm9yOjUwMCxOb3RJbXBsZW1lbnRlZDo1MDEsQmFkR2F0ZXdheTo1MDIsU2VydmljZVVuYXZhaWxhYmxlOjUwMyxHYXRld2F5VGltZW91dDo1MDQsSHR0cFZlcnNpb25Ob3RTdXBwb3J0ZWQ6NTA1LFZhcmlhbnRBbHNvTmVnb3RpYXRlczo1MDYsSW5zdWZmaWNpZW50U3RvcmFnZTo1MDcsTG9vcERldGVjdGVkOjUwOCxOb3RFeHRlbmRlZDo1MTAsTmV0d29ya0F1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NTExfTtPYmplY3QuZW50cmllcyhuZSkuZm9yRWFjaCgoW0EsZV0pPT57bmVbZV09QX0pO3ZhciBydD1uZTtmdW5jdGlvbiBpdChBKXtsZXQgZT1uZXcgbkEoQSksdD1aKG5BLnByb3RvdHlwZS5yZXF1ZXN0LGUpO3JldHVybiBJLmV4dGVuZCh0LG5BLnByb3RvdHlwZSxlLHthbGxPd25LZXlzOiEwfSksSS5leHRlbmQodCxlLG51bGwse2FsbE93bktleXM6ITB9KSx0LmNyZWF0ZT1mdW5jdGlvbihuKXtyZXR1cm4gaXQoVChBLG4pKX0sdH12YXIgbT1pdChXKTttLkF4aW9zPW5BO20uQ2FuY2VsZWRFcnJvcj1PO20uQ2FuY2VsVG9rZW49dHQ7bS5pc0NhbmNlbD1yQTttLlZFUlNJT049eUE7bS50b0Zvcm1EYXRhPXg7bS5BeGlvc0Vycm9yPXA7bS5DYW5jZWw9bS5DYW5jZWxlZEVycm9yO20uYWxsPWZ1bmN0aW9uKGUpe3JldHVybiBQcm9taXNlLmFsbChlKX07bS5zcHJlYWQ9cmU7bS5pc0F4aW9zRXJyb3I9aWU7bS5tZXJnZUNvbmZpZz1UO20uQXhpb3NIZWFkZXJzPUQ7bS5mb3JtVG9KU09OPUE9PnBBKEkuaXNIVE1MRm9ybShBKT9uZXcgRm9ybURhdGEoQSk6QSk7bS5nZXRBZGFwdGVyPW1BLmdldEFkYXB0ZXI7bS5IdHRwU3RhdHVzQ29kZT1ydDttLmRlZmF1bHQ9bTt2YXIgXz1tO3ZhcntBeGlvczpHYSxBeGlvc0Vycm9yOlRhLENhbmNlbGVkRXJyb3I6TGEsaXNDYW5jZWw6eGEsQ2FuY2VsVG9rZW46T2EsVkVSU0lPTjpQYSxhbGw6SmEsQ2FuY2VsOkhhLGlzQXhpb3NFcnJvcjpNYSxzcHJlYWQ6WWEsdG9Gb3JtRGF0YTpxYSxBeGlvc0hlYWRlcnM6S2EsSHR0cFN0YXR1c0NvZGU6V2EsZm9ybVRvSlNPTjp2YSxnZXRBZGFwdGVyOmphLG1lcmdlQ29uZmlnOl9hfT1fO2FzeW5jIGZ1bmN0aW9uIFdyKEEsZSl7bGV0IHQ9QSxyPW51bGw7aWYodD09PW51bGwpcj1uZXcgV29ya2VyKG5ldyBVUkwoIi4vd2ViLXdvcmtlcnMvaXRrLXdhc20tcGlwZWxpbmUud29ya2VyLmpzIixpbXBvcnQubWV0YS51cmwpLHt0eXBlOiJtb2R1bGUifSk7ZWxzZSBpZih0LnN0YXJ0c1dpdGgoImh0dHAiKSl7bGV0IG49YXdhaXQgXy5nZXQodCx7cmVzcG9uc2VUeXBlOiJibG9iIixwYXJhbXM6ZX0pLGk9VVJMLmNyZWF0ZU9iamVjdFVSTChuLmRhdGEpO3I9bmV3IFdvcmtlcihpLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSByPW5ldyBXb3JrZXIodCx7dHlwZToibW9kdWxlIn0pO3JldHVybiByfXZhciBvQT1XcjtmdW5jdGlvbiBudChBKXtsZXQgZT1PQShBKSx0PUE7cmV0dXJuIHQudGVybWluYXRlZD0hMSx0LndvcmtlclByb3h5PWUsdC5vcmlnaW5hbFRlcm1pbmF0ZT10LnRlcm1pbmF0ZSx0LnRlcm1pbmF0ZT0oKT0+e3QudGVybWluYXRlZD0hMCx0LndvcmtlclByb3h5W3hBXSgpLHQub3JpZ2luYWxUZXJtaW5hdGUoKX0se3dvcmtlclByb3h5OmUsd29ya2VyOnR9fWFzeW5jIGZ1bmN0aW9uIHZyKEEsZSx0KXtsZXQgcjtpZihBIT1udWxsKXtsZXQgaT1BO3JldHVybiBpLndvcmtlclByb3h5IT09dm9pZCAwPyhyPWkud29ya2VyUHJveHkse3dvcmtlclByb3h5OnIsd29ya2VyOml9KTpudChBKX1sZXQgbj1hd2FpdCBvQShlLHQpO3JldHVybiBudChuKX12YXIgb3Q9dnI7YXN5bmMgZnVuY3Rpb24ganIoQSxlLHQpe2xldCByPSJ1bmtub3duIjt0eXBlb2YgQSE9InN0cmluZyI/cj1BLmhyZWY6QS5zdGFydHNXaXRoKCJodHRwIik/cj1BOnI9dHlwZW9mIGU8InUiP2Ake2V9LyR7QX1gOkEsci5lbmRzV2l0aCgiLmpzIikmJihyPXIuc3Vic3RyaW5nKDAsci5sZW5ndGgtMykpLHIuZW5kc1dpdGgoIi53YXNtIikmJihyPXIuc3Vic3RyaW5nKDAsci5sZW5ndGgtNSkpO2xldCBuPWAke3J9Lndhc21gLG89KGF3YWl0IF8uZ2V0KG4se3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIiLHBhcmFtczp0fSkpLmRhdGE7cmV0dXJuKGF3YWl0IGltcG9ydChgJHtyfS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5Om99KX12YXIgYXQ9anI7dmFyIHN0PWFzeW5jKCk9PldlYkFzc2VtYmx5LnZhbGlkYXRlKG5ldyBVaW50OEFycmF5KFswLDk3LDExNSwxMDksMSwwLDAsMCwxLDUsMSw5NiwwLDEsMTIzLDMsMiwxLDAsMTAsMTAsMSw4LDAsNjUsMCwyNTMsMTUsMjUzLDk4LDExXSkpO3ZhciBsdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixJdD1uZXcgVGV4dEVuY29kZXIsZ3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIF9yKEEsZSl7bGV0IHQ9e2ZsYWdzOiJyIixlbmNvZGluZzoiYmluYXJ5In0scj1BLmZzX29wZW4oZSx0LmZsYWdzKSxpPUEuZnNfc3RhdChlKS5zaXplLG89bnVsbDtsdD9vPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcihpKTpvPW5ldyBBcnJheUJ1ZmZlcihpKTtsZXQgZz1uZXcgVWludDhBcnJheShvKTtyZXR1cm4gQS5mc19yZWFkKHIsZywwLGksMCksQS5mc19jbG9zZShyKSxnfWZ1bmN0aW9uIEJ0KEEsZSx0KXtsZXQgcj1udWxsO2x0P3I9bmV3IFNoYXJlZEFycmF5QnVmZmVyKHQpOnI9bmV3IEFycmF5QnVmZmVyKHQpO2xldCBuPW5ldyBVaW50OEFycmF5KHIpLGk9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLGUsdCk7cmV0dXJuIG4uc2V0KGkpLG59ZnVuY3Rpb24geShBLGUsdCxyKXtsZXQgbj0wO3JldHVybiBlIT09bnVsbCYmKG49QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfYXJyYXlfYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxyLGUuYnVmZmVyLmJ5dGVMZW5ndGhdKSxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkoZS5idWZmZXIpLG4pKSxufWZ1bmN0aW9uIHooQSxlLHQpe2xldCByPUpTT04uc3RyaW5naWZ5KGUpLG49QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfanNvbl9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LHIubGVuZ3RoXSk7QS53cml0ZUFzY2lpVG9NZW1vcnkocixuLCExKX1mdW5jdGlvbiBSKEEsZSx0LHIpe2xldCBuPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGUsdF0pLGk9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksbz1CdChBLG4saSk7cmV0dXJuIEwocixvLmJ1ZmZlcil9ZnVuY3Rpb24gb2UoQSxlKXtsZXQgdD1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfanNvbl9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciJdLFswLGVdKSxyPUEuQXNjaWlUb1N0cmluZyh0KTtyZXR1cm4gSlNPTi5wYXJzZShyKX1mdW5jdGlvbiB6cihBLGUsdCxyKXtyIT1udWxsJiZyLmxlbmd0aD4wJiZyLmZvckVhY2goZnVuY3Rpb24obCxzKXtzd2l0Y2gobC50eXBlKXtjYXNlIFEuVGV4dFN0cmVhbTp7bGV0IGE9SXQuZW5jb2RlKGwuZGF0YS5kYXRhKSxFPXkoQSxhLHMsMCksQj17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWB9O3ooQSxCLHMpO2JyZWFrfWNhc2UgUS5Kc29uQ29tcGF0aWJsZTp7bGV0IGE9SXQuZW5jb2RlKEpTT04uc3RyaW5naWZ5KGwuZGF0YSkpLEU9eShBLGEscywwKSxCPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YH07eihBLEIscyk7YnJlYWt9Y2FzZSBRLkJpbmFyeVN0cmVhbTp7bGV0IGE9bC5kYXRhLmRhdGEsRT15KEEsYSxzLDApLEI9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7RX1gfTt6KEEsQixzKTticmVha31jYXNlIFEuVGV4dEZpbGU6e0EuZnNfd3JpdGVGaWxlKGwuZGF0YS5wYXRoLGwuZGF0YS5kYXRhKTticmVha31jYXNlIFEuQmluYXJ5RmlsZTp7QS5mc193cml0ZUZpbGUobC5kYXRhLnBhdGgsbC5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgUS5JbWFnZTp7bGV0IGE9bC5kYXRhLEU9eShBLGEuZGF0YSxzLDApLEI9eShBLGEuZGlyZWN0aW9uLHMsMSksdT10eXBlb2YgYS5tZXRhZGF0YT8uZW50cmllczwidSI/SlNPTi5zdHJpbmdpZnkoQXJyYXkuZnJvbShhLm1ldGFkYXRhLmVudHJpZXMoKSkpOiJbXSIsYz17aW1hZ2VUeXBlOmEuaW1hZ2VUeXBlLG5hbWU6YS5uYW1lLG9yaWdpbjphLm9yaWdpbixzcGFjaW5nOmEuc3BhY2luZyxkaXJlY3Rpb246YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtCfWAsc2l6ZTphLnNpemUsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YCxtZXRhZGF0YTp1fTt6KEEsYyxzKTticmVha31jYXNlIFEuTWVzaDp7bGV0IGE9bC5kYXRhLEU9eShBLGEucG9pbnRzLHMsMCksQj15KEEsYS5jZWxscyxzLDEpLHU9eShBLGEucG9pbnREYXRhLHMsMiksYz15KEEsYS5jZWxsRGF0YSxzLDMpLGY9e21lc2hUeXBlOmEubWVzaFR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWAsbnVtYmVyT2ZDZWxsczphLm51bWJlck9mQ2VsbHMsY2VsbHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtCfWAsY2VsbEJ1ZmZlclNpemU6YS5jZWxsQnVmZmVyU2l6ZSxudW1iZXJPZlBvaW50UGl4ZWxzOmEubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt1fWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gfTt6KEEsZixzKTticmVha31jYXNlIFEuUG9seURhdGE6e2xldCBhPWwuZGF0YSxFPXkoQSxhLnBvaW50cyxzLDApLEI9eShBLGEudmVydGljZXMscywxKSx1PXkoQSxhLmxpbmVzLHMsMiksYz15KEEsYS5wb2x5Z29ucyxzLDMpLGY9eShBLGEudHJpYW5nbGVTdHJpcHMscyw0KSxkPXkoQSxhLnBvaW50RGF0YSxzLDUpLGs9eShBLGEucG9pbnREYXRhLHMsNiksUz17cG9seURhdGFUeXBlOmEucG9seURhdGFUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7RX1gLHZlcnRpY2VzQnVmZmVyU2l6ZTphLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0J9YCxsaW5lc0J1ZmZlclNpemU6YS5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt1fWAscG9seWdvbnNCdWZmZXJTaXplOmEucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTphLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxudW1iZXJPZlBvaW50UGl4ZWxzOmEubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtkfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7a31gfTt6KEEsUyxzKTticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgbj1BLnN0YWNrU2F2ZSgpLGk9MDt0cnl7aT1BLmNhbGxNYWluKGUuc2xpY2UoKSl9Y2F0Y2gobCl7dGhyb3cgdHlwZW9mIGw9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UobCkpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksbH1maW5hbGx5e0Euc3RhY2tSZXN0b3JlKG4pfWxldCBvPUEuZ2V0TW9kdWxlU3Rkb3V0KCksZz1BLmdldE1vZHVsZVN0ZGVycigpLEM9W107cmV0dXJuIHQhPW51bGwmJnQubGVuZ3RoPjAmJmk9PT0wJiZ0LmZvckVhY2goZnVuY3Rpb24obCxzKXtsZXQgYT1udWxsO3N3aXRjaChsLnR5cGUpe2Nhc2UgUS5UZXh0U3RyZWFtOntsZXQgQj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxzLDBdKSx1PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHMsMF0pLGM9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEIsdSk7YT17ZGF0YTpndC5kZWNvZGUoYyl9O2JyZWFrfWNhc2UgUS5Kc29uQ29tcGF0aWJsZTp7bGV0IEI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAscywwXSksdT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxzLDBdKSxjPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixCLHUpO2E9SlNPTi5wYXJzZShndC5kZWNvZGUoYykpO2JyZWFrfWNhc2UgUS5CaW5hcnlTdHJlYW06e2xldCBCPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHMsMF0pLHU9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAscywwXSk7YT17ZGF0YTpCdChBLEIsdSl9O2JyZWFrfWNhc2UgUS5UZXh0RmlsZTp7YT17cGF0aDpsLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUobC5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIFEuQmluYXJ5RmlsZTp7YT17cGF0aDpsLmRhdGEucGF0aCxkYXRhOl9yKEEsbC5kYXRhLnBhdGgpfTticmVha31jYXNlIFEuSW1hZ2U6e2xldCBCPW9lKEEscyk7Qi5kYXRhPVIoQSxzLDAsQi5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQi5kaXJlY3Rpb249UihBLHMsMSxNLkZsb2F0NjQpLEIubWV0YWRhdGE9bmV3IE1hcChCLm1ldGFkYXRhKSxhPUI7YnJlYWt9Y2FzZSBRLk1lc2g6e2xldCBCPW9lKEEscyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVIoQSxzLDAsQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkIucG9pbnRzPUwoQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mQ2VsbHM+MD9CLmNlbGxzPVIoQSxzLDEsQi5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qi5jZWxscz1MKEIubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mUG9pbnRQaXhlbHM+MD9CLnBvaW50RGF0YT1SKEEscywyLEIubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkIucG9pbnREYXRhPUwoQi5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qi5jZWxsRGF0YT1SKEEscywzLEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5jZWxsRGF0YT1MKEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGE9QjticmVha31jYXNlIFEuUG9seURhdGE6e2xldCBCPW9lKEEscyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVIoQSxzLDAsTS5GbG9hdDMyKTpCLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LEIudmVydGljZXNCdWZmZXJTaXplPjA/Qi52ZXJ0aWNlcz1SKEEscywxLGguVUludDMyKTpCLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxCLmxpbmVzQnVmZmVyU2l6ZT4wP0IubGluZXM9UihBLHMsMixoLlVJbnQzMik6Qi5saW5lcz1uZXcgVWludDMyQXJyYXksQi5wb2x5Z29uc0J1ZmZlclNpemU+MD9CLnBvbHlnb25zPVIoQSxzLDMsaC5VSW50MzIpOkIucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LEIudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/Qi50cmlhbmdsZVN0cmlwcz1SKEEscyw0LGguVUludDMyKTpCLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxCLm51bWJlck9mUG9pbnRQaXhlbHM+MD9CLnBvaW50RGF0YT1SKEEscyw1LEIucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpCLnBvaW50RGF0YT1MKEIucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQi5udW1iZXJPZkNlbGxQaXhlbHM+MD9CLmNlbGxEYXRhPVIoQSxzLDYsQi5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5jZWxsRGF0YT1MKEIucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxhPUI7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgRT17dHlwZTpsLnR5cGUsZGF0YTphfTtDLnB1c2goRSl9KSx7cmV0dXJuVmFsdWU6aSxzdGRvdXQ6byxzdGRlcnI6ZyxvdXRwdXRzOkN9fXZhciBDdD16cjt2YXIgVnI9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIFpyKEEsZSl7aWYoQT09bnVsbClyZXR1cm5bXTtsZXQgdD1bXTtmb3IobGV0IHI9MDtyPEEubGVuZ3RoO3IrKyl7bGV0IG49WHIoQVtyXSxlKTtuIT09bnVsbCYmdC5wdXNoKG4pfXJldHVybiB0fWZ1bmN0aW9uIFhyKEEsZSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgdD1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD90PUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKHQ9QSksVnImJnQgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmU/dDp0LnNsaWNlKDApfXZhciBjdD1acjtmdW5jdGlvbiAkcihBKXtyZXR1cm5bQS5kYXRhLEEuZGlyZWN0aW9uXX12YXIgdXQ9JHI7ZnVuY3Rpb24gQWkoQSl7cmV0dXJuW0EucG9pbnRzLEEucG9pbnREYXRhLEEuY2VsbHMsQS5jZWxsRGF0YV19dmFyIEV0PUFpO2Z1bmN0aW9uIGVpKEEpe3JldHVybltBLnBvaW50cyxBLnZlcnRpY2VzLEEubGluZXMsQS5wb2x5Z29ucyxBLnRyaWFuZ2xlU3RyaXBzLEEucG9pbnREYXRhLEEuY2VsbERhdGFdfXZhciBRdD1laTt2YXIgdGk7ZnVuY3Rpb24gREEoKXtyZXR1cm4gdGl9dmFyIHJpO2Z1bmN0aW9uIGZ0KCl7cmV0dXJuIHJpfXZhciBpaTtmdW5jdGlvbiBTQSgpe3JldHVybiBpaX12YXIgYWU9bmV3IE1hcDtmdW5jdGlvbiBuaSgpe2xldCBBPVNBKCk7cmV0dXJuIHR5cGVvZiBBPiJ1IiYmKEE9bnVsbCksQX1mdW5jdGlvbiBwdCgpe2xldCBBPURBKCk7cmV0dXJuIHR5cGVvZiBBPiJ1IiYmKEE9bmV3IFVSTCgiL3BpcGVsaW5lcyIsZG9jdW1lbnQubG9jYXRpb24ub3JpZ2luKS5ocmVmKSxBfWZ1bmN0aW9uIEZBKCl7bGV0IEE9ZnQoKTtyZXR1cm4gdHlwZW9mIEE+InUiJiYoQT17fSksQX1hc3luYyBmdW5jdGlvbiBvaShBLGUsdCl7bGV0IHI9QSxuPUE7aWYodHlwZW9mIEEhPSJzdHJpbmciJiYocj1uZXcgVVJMKEEuaHJlZiksbj1yLmhyZWYpLGFlLmhhcyhuKSlyZXR1cm4gYWUuZ2V0KG4pO3tsZXQgaT1hd2FpdCBhdChBLGU/LnRvU3RyaW5nKCk/P3B0KCksdD8/RkEoKSk7cmV0dXJuIGFlLnNldChuLGkpLGl9fWFzeW5jIGZ1bmN0aW9uIGFpKEEsZSx0LHIsbil7aWYoIWF3YWl0IHN0KCkpe2xldCBmPSJXZWJBc3NlbWJseSBTSU1EIHN1cHBvcnQgaXMgcmVxdWlyZWQgLS0gcGxlYXNlIHVwZGF0ZSB5b3VyIGJyb3dzZXIuIjt0aHJvdyBhbGVydChmKSxuZXcgRXJyb3IoZil9bGV0IGk9bj8ud2ViV29ya2VyPz9udWxsO2lmKGk9PT0hMSl7bGV0IGY9YXdhaXQgb2koQS50b1N0cmluZygpLG4/LnBpcGVsaW5lQmFzZVVybCxuPy5waXBlbGluZVF1ZXJ5UGFyYW1zPz9GQSgpKTtyZXR1cm4gQ3QoZixlLHQscil9bGV0IG89aSxnPW4/LnBpcGVsaW5lV29ya2VyVXJsPz9uaSgpLEM9dHlwZW9mIGchPSJzdHJpbmciJiZ0eXBlb2YgZz8uaHJlZjwidSI/Zy5ocmVmOmcse3dvcmtlclByb3h5Omwsd29ya2VyOnN9PWF3YWl0IG90KG8sQyxuPy5waXBlbGluZVF1ZXJ5UGFyYW1zPz9GQSgpKTtvPXM7bGV0IGE9W107ciE9bnVsbCYmci5sZW5ndGg+MCYmci5mb3JFYWNoKGZ1bmN0aW9uKGYpe2lmKGYudHlwZT09PVEuQmluYXJ5U3RyZWFtKXtsZXQgZD1mLmRhdGEuZGF0YTthLnB1c2goZCl9ZWxzZSBpZihmLnR5cGU9PT1RLkJpbmFyeUZpbGUpe2xldCBkPWYuZGF0YS5kYXRhO2EucHVzaChkKX1lbHNlIGlmKGYudHlwZT09PVEuSW1hZ2Upe2xldCBkPWYuZGF0YTtkLmRhdGEhPT1udWxsJiZhLnB1c2goLi4udXQoZCkpfWVsc2UgaWYoZi50eXBlPT09US5NZXNoKXtsZXQgZD1mLmRhdGE7YS5wdXNoKC4uLkV0KGQpKX1lbHNlIGlmKGYudHlwZT09PVEuUG9seURhdGEpe2xldCBkPWYuZGF0YTthLnB1c2goLi4uUXQoZCkpfX0pO2xldCBFPW4/LnBpcGVsaW5lQmFzZVVybD8/cHQoKSxCPXR5cGVvZiBFIT0ic3RyaW5nIiYmdHlwZW9mIEU/LmhyZWY8InUiP0UuaHJlZjpFLHU9ciE9bnVsbD9QQShyLGN0KGEsbj8ubm9Db3B5KSk6bnVsbCxjPWF3YWl0IGwucnVuUGlwZWxpbmUoQS50b1N0cmluZygpLEIsZSx0LHUsbj8ucGlwZWxpbmVRdWVyeVBhcmFtcz8/RkEoKSk7cmV0dXJue3JldHVyblZhbHVlOmMucmV0dXJuVmFsdWUsc3Rkb3V0OmMuc3Rkb3V0LHN0ZGVycjpjLnN0ZGVycixvdXRwdXRzOmMub3V0cHV0cyx3ZWJXb3JrZXI6b319dmFyIGI9YWk7dmFyIHNpPW51bGw7ZnVuY3Rpb24gZHQoKXtyZXR1cm4gc2l9dmFyIHNlLElpPWBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL0BpdGstd2FzbS9kaWNvbUAke2tBfS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gUHMoQSl7c2U9QX1mdW5jdGlvbiBOKCl7aWYodHlwZW9mIHNlPCJ1IilyZXR1cm4gc2U7bGV0IEE9REEoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6SWl9dmFyIEllLGdpPW51bGw7ZnVuY3Rpb24gbXQoQSl7SWU9QX1mdW5jdGlvbiBGKCl7aWYodHlwZW9mIEllPCJ1IilyZXR1cm4gSWU7bGV0IEE9U0EoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6Z2l9dmFyIFY9bnVsbDthc3luYyBmdW5jdGlvbiBodCgpe2xldCBBPUYoKSxlPXR5cGVvZiBBIT0ic3RyaW5nIiYmdHlwZW9mIEE/LmhyZWY8InUiP0EuaHJlZjpBO1Y9YXdhaXQgb0EoZSl9ZnVuY3Rpb24gV3MoQSl7Vj1BfWFzeW5jIGZ1bmN0aW9uIEooKXtpZihWIT09bnVsbClyZXR1cm4gVi50ZXJtaW5hdGVkJiZhd2FpdCBodCgpLFY7bGV0IEE9ZHQoKTtyZXR1cm4gQSE9PW51bGw/QTooYXdhaXQgaHQoKSxWKX1hc3luYyBmdW5jdGlvbiBsaShBLGUsdD17fSl7bGV0IHI9W3t0eXBlOlEuSnNvbkNvbXBhdGlibGV9LHt0eXBlOlEuSW1hZ2V9XSxuPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBTPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTtuPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KFMpfX1sZXQgaT1lO2lmKGUgaW5zdGFuY2VvZiBGaWxlKXtsZXQgUz1hd2FpdCBlLmFycmF5QnVmZmVyKCk7aT17cGF0aDplLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShTKX19bGV0IG89W3t0eXBlOlEuQmluYXJ5RmlsZSxkYXRhOm59LHt0eXBlOlEuQmluYXJ5RmlsZSxkYXRhOml9XSxnPVtdLEM9bi5wYXRoO2cucHVzaChDKTtsZXQgbD1pLnBhdGg7Zy5wdXNoKGwpO2xldCBzPSIwIjtnLnB1c2gocyk7bGV0IGE9IjEiO2cucHVzaChhKSxnLnB1c2goIi0tbWVtb3J5LWlvIiksdC5jb2xvck91dHB1dCYmdC5jb2xvck91dHB1dCYmZy5wdXNoKCItLWNvbG9yLW91dHB1dCIpLHQuY29uZmlnRmlsZSYmZy5wdXNoKCItLWNvbmZpZy1maWxlIix0LmNvbmZpZ0ZpbGUudG9TdHJpbmcoKSksdC5mcmFtZSYmZy5wdXNoKCItLWZyYW1lIix0LmZyYW1lLnRvU3RyaW5nKCkpLHQubm9QcmVzZW50YXRpb25TdGF0ZU91dHB1dCYmdC5ub1ByZXNlbnRhdGlvblN0YXRlT3V0cHV0JiZnLnB1c2goIi0tbm8tcHJlc2VudGF0aW9uLXN0YXRlLW91dHB1dCIpLHQubm9CaXRtYXBPdXRwdXQmJnQubm9CaXRtYXBPdXRwdXQmJmcucHVzaCgiLS1uby1iaXRtYXAtb3V0cHV0Iik7bGV0IEU9ImFwcGx5LXByZXNlbnRhdGlvbi1zdGF0ZS10by1pbWFnZSIsQj10Py53ZWJXb3JrZXI7Qj09PXZvaWQgMCYmKEI9YXdhaXQgSigpKTtsZXR7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6YyxzdGRlcnI6ZixvdXRwdXRzOmR9PWF3YWl0IGIoRSxnLHIsbyx7cGlwZWxpbmVCYXNlVXJsOk4oKSxwaXBlbGluZVdvcmtlclVybDpGKCksd2ViV29ya2VyOkIsbm9Db3B5OnQ/Lm5vQ29weX0pO2lmKGMhPT0wJiZmIT09IiIpdGhyb3cgbmV3IEVycm9yKGYpO3JldHVybnt3ZWJXb3JrZXI6dSxwcmVzZW50YXRpb25TdGF0ZU91dFN0cmVhbTpkWzBdPy5kYXRhLG91dHB1dEltYWdlOmRbMV0/LmRhdGF9fXZhciBCaT1saTthc3luYyBmdW5jdGlvbiBDaShBLGU9e30pe2xldCB0PVt7dHlwZTpRLkJpbmFyeVN0cmVhbX1dLHI9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IGM9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO3I9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoYyl9fWxldCBuPVt7dHlwZTpRLkJpbmFyeUZpbGUsZGF0YTpyfV0saT1bXSxvPXIucGF0aDtpLnB1c2gobyk7bGV0IGc9IjAiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksZS5yZWFkRmlsZU9ubHkmJmUucmVhZEZpbGVPbmx5JiZpLnB1c2goIi0tcmVhZC1maWxlLW9ubHkiKSxlLnJlYWREYXRhc2V0JiZlLnJlYWREYXRhc2V0JiZpLnB1c2goIi0tcmVhZC1kYXRhc2V0IiksZS5yZWFkWGZlckF1dG8mJmUucmVhZFhmZXJBdXRvJiZpLnB1c2goIi0tcmVhZC14ZmVyLWF1dG8iKSxlLnJlYWRYZmVyRGV0ZWN0JiZlLnJlYWRYZmVyRGV0ZWN0JiZpLnB1c2goIi0tcmVhZC14ZmVyLWRldGVjdCIpLGUucmVhZFhmZXJMaXR0bGUmJmUucmVhZFhmZXJMaXR0bGUmJmkucHVzaCgiLS1yZWFkLXhmZXItbGl0dGxlIiksZS5yZWFkWGZlckJpZyYmZS5yZWFkWGZlckJpZyYmaS5wdXNoKCItLXJlYWQteGZlci1iaWciKSxlLnJlYWRYZmVySW1wbGljaXQmJmUucmVhZFhmZXJJbXBsaWNpdCYmaS5wdXNoKCItLXJlYWQteGZlci1pbXBsaWNpdCIpLGUuYWNjZXB0T2RkTGVuZ3RoJiZlLmFjY2VwdE9kZExlbmd0aCYmaS5wdXNoKCItLWFjY2VwdC1vZGQtbGVuZ3RoIiksZS5hc3N1bWVFdmVuTGVuZ3RoJiZlLmFzc3VtZUV2ZW5MZW5ndGgmJmkucHVzaCgiLS1hc3N1bWUtZXZlbi1sZW5ndGgiKSxlLmVuYWJsZUNwMjQ2JiZlLmVuYWJsZUNwMjQ2JiZpLnB1c2goIi0tZW5hYmxlLWNwMjQ2IiksZS5kaXNhYmxlQ3AyNDYmJmUuZGlzYWJsZUNwMjQ2JiZpLnB1c2goIi0tZGlzYWJsZS1jcDI0NiIpLGUucmV0YWluVW4mJmUucmV0YWluVW4mJmkucHVzaCgiLS1yZXRhaW4tdW4iKSxlLmNvbnZlcnRVbiYmZS5jb252ZXJ0VW4mJmkucHVzaCgiLS1jb252ZXJ0LXVuIiksZS5lbmFibGVDb3JyZWN0aW9uJiZlLmVuYWJsZUNvcnJlY3Rpb24mJmkucHVzaCgiLS1lbmFibGUtY29ycmVjdGlvbiIpLGUuZGlzYWJsZUNvcnJlY3Rpb24mJmUuZGlzYWJsZUNvcnJlY3Rpb24mJmkucHVzaCgiLS1kaXNhYmxlLWNvcnJlY3Rpb24iKTtsZXQgQz0icmVhZC1kaWNvbS1lbmNhcHN1bGF0ZWQtcGRmIixsPWU/LndlYldvcmtlcjtsPT09dm9pZCAwJiYobD1hd2FpdCBKKCkpO2xldHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTphLHN0ZGVycjpFLG91dHB1dHM6Qn09YXdhaXQgYihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6TigpLHBpcGVsaW5lV29ya2VyVXJsOkYoKSx3ZWJXb3JrZXI6bCxub0NvcHk6ZT8ubm9Db3B5fSk7aWYoYSE9PTAmJkUhPT0iIil0aHJvdyBuZXcgRXJyb3IoRSk7cmV0dXJue3dlYldvcmtlcjpzLHBkZkJpbmFyeU91dHB1dDooQlswXT8uZGF0YSkuZGF0YX19dmFyIGNpPUNpO2FzeW5jIGZ1bmN0aW9uIHVpKEEsZT17fSl7bGV0IHQ9W3t0eXBlOlEuVGV4dFN0cmVhbX1dLHI9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IGM9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO3I9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoYyl9fWxldCBuPVt7dHlwZTpRLkJpbmFyeUZpbGUsZGF0YTpyfV0saT1bXSxvPXIucGF0aDtpLnB1c2gobyk7bGV0IGc9IjAiO2lmKGkucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksZS5yZWFkRmlsZU9ubHkmJmUucmVhZEZpbGVPbmx5JiZpLnB1c2goIi0tcmVhZC1maWxlLW9ubHkiKSxlLnJlYWREYXRhc2V0JiZlLnJlYWREYXRhc2V0JiZpLnB1c2goIi0tcmVhZC1kYXRhc2V0IiksZS5yZWFkWGZlckF1dG8mJmUucmVhZFhmZXJBdXRvJiZpLnB1c2goIi0tcmVhZC14ZmVyLWF1dG8iKSxlLnJlYWRYZmVyRGV0ZWN0JiZlLnJlYWRYZmVyRGV0ZWN0JiZpLnB1c2goIi0tcmVhZC14ZmVyLWRldGVjdCIpLGUucmVhZFhmZXJMaXR0bGUmJmUucmVhZFhmZXJMaXR0bGUmJmkucHVzaCgiLS1yZWFkLXhmZXItbGl0dGxlIiksZS5yZWFkWGZlckJpZyYmZS5yZWFkWGZlckJpZyYmaS5wdXNoKCItLXJlYWQteGZlci1iaWciKSxlLnJlYWRYZmVySW1wbGljaXQmJmUucmVhZFhmZXJJbXBsaWNpdCYmaS5wdXNoKCItLXJlYWQteGZlci1pbXBsaWNpdCIpLGUucHJvY2Vzc2luZ0RldGFpbHMmJmUucHJvY2Vzc2luZ0RldGFpbHMmJmkucHVzaCgiLS1wcm9jZXNzaW5nLWRldGFpbHMiKSxlLnVua25vd25SZWxhdGlvbnNoaXAmJmUudW5rbm93blJlbGF0aW9uc2hpcCYmaS5wdXNoKCItLXVua25vd24tcmVsYXRpb25zaGlwIiksZS5pbnZhbGlkSXRlbVZhbHVlJiZlLmludmFsaWRJdGVtVmFsdWUmJmkucHVzaCgiLS1pbnZhbGlkLWl0ZW0tdmFsdWUiKSxlLmlnbm9yZUNvbnN0cmFpbnRzJiZlLmlnbm9yZUNvbnN0cmFpbnRzJiZpLnB1c2goIi0taWdub3JlLWNvbnN0cmFpbnRzIiksZS5pZ25vcmVJdGVtRXJyb3JzJiZlLmlnbm9yZUl0ZW1FcnJvcnMmJmkucHVzaCgiLS1pZ25vcmUtaXRlbS1lcnJvcnMiKSxlLnNraXBJbnZhbGlkSXRlbXMmJmUuc2tpcEludmFsaWRJdGVtcyYmaS5wdXNoKCItLXNraXAtaW52YWxpZC1pdGVtcyIpLGUuZGlzYWJsZVZyQ2hlY2tlciYmZS5kaXNhYmxlVnJDaGVja2VyJiZpLnB1c2goIi0tZGlzYWJsZS12ci1jaGVja2VyIiksZS5jaGFyc2V0UmVxdWlyZSYmZS5jaGFyc2V0UmVxdWlyZSYmaS5wdXNoKCItLWNoYXJzZXQtcmVxdWlyZSIpLGUuY2hhcnNldEFzc3VtZSYmaS5wdXNoKCItLWNoYXJzZXQtYXNzdW1lIixlLmNoYXJzZXRBc3N1bWUudG9TdHJpbmcoKSksZS5jaGFyc2V0Q2hlY2tBbGwmJmUuY2hhcnNldENoZWNrQWxsJiZpLnB1c2goIi0tY2hhcnNldC1jaGVjay1hbGwiKSxlLmNvbnZlcnRUb1V0ZjgmJmUuY29udmVydFRvVXRmOCYmaS5wdXNoKCItLWNvbnZlcnQtdG8tdXRmOCIpLGUudXJsUHJlZml4JiZpLnB1c2goIi0tdXJsLXByZWZpeCIsZS51cmxQcmVmaXgudG9TdHJpbmcoKSksZS5odG1sMzImJmUuaHRtbDMyJiZpLnB1c2goIi0taHRtbC0zMiIpLGUuaHRtbDQwJiZlLmh0bWw0MCYmaS5wdXNoKCItLWh0bWwtNDAiKSxlLnhodG1sMTEmJmUueGh0bWwxMSYmaS5wdXNoKCItLXhodG1sLTExIiksZS5hZGREb2N1bWVudFR5cGUmJmUuYWRkRG9jdW1lbnRUeXBlJiZpLnB1c2goIi0tYWRkLWRvY3VtZW50LXR5cGUiKSxlLmNzc1JlZmVyZW5jZSl7bGV0IGM9bi5sZW5ndGgudG9TdHJpbmcoKTtuLnB1c2goe3R5cGU6US5UZXh0U3RyZWFtLGRhdGE6e2RhdGE6ZS5jc3NSZWZlcmVuY2V9fSksaS5wdXNoKCItLWNzcy1yZWZlcmVuY2UiLGMpfWlmKGUuY3NzRmlsZSl7bGV0IGM9ZS5jc3NGaWxlLGY9YztpZihjIGluc3RhbmNlb2YgRmlsZSl7bGV0IGs9YXdhaXQgYy5hcnJheUJ1ZmZlcigpO2Y9e3BhdGg6Yy5uYW1lLGRhdGE6bmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGspfX1pLnB1c2goIi0tY3NzLWZpbGUiKSxuLnB1c2goe3R5cGU6US5UZXh0RmlsZSxkYXRhOmZ9KTtsZXQgZD1jIGluc3RhbmNlb2YgRmlsZT9jLm5hbWU6Yy5wYXRoO2kucHVzaChkKX1lLmV4cGFuZElubGluZSYmZS5leHBhbmRJbmxpbmUmJmkucHVzaCgiLS1leHBhbmQtaW5saW5lIiksZS5uZXZlckV4cGFuZElubGluZSYmZS5uZXZlckV4cGFuZElubGluZSYmaS5wdXNoKCItLW5ldmVyLWV4cGFuZC1pbmxpbmUiKSxlLmFsd2F5c0V4cGFuZElubGluZSYmZS5hbHdheXNFeHBhbmRJbmxpbmUmJmkucHVzaCgiLS1hbHdheXMtZXhwYW5kLWlubGluZSIpLGUucmVuZGVyRnVsbERhdGEmJmUucmVuZGVyRnVsbERhdGEmJmkucHVzaCgiLS1yZW5kZXItZnVsbC1kYXRhIiksZS5zZWN0aW9uVGl0bGVJbmxpbmUmJmUuc2VjdGlvblRpdGxlSW5saW5lJiZpLnB1c2goIi0tc2VjdGlvbi10aXRsZS1pbmxpbmUiKSxlLmRvY3VtZW50VHlwZVRpdGxlJiZlLmRvY3VtZW50VHlwZVRpdGxlJiZpLnB1c2goIi0tZG9jdW1lbnQtdHlwZS10aXRsZSIpLGUucGF0aWVudEluZm9UaXRsZSYmZS5wYXRpZW50SW5mb1RpdGxlJiZpLnB1c2goIi0tcGF0aWVudC1pbmZvLXRpdGxlIiksZS5ub0RvY3VtZW50SGVhZGVyJiZlLm5vRG9jdW1lbnRIZWFkZXImJmkucHVzaCgiLS1uby1kb2N1bWVudC1oZWFkZXIiKSxlLnJlbmRlcklubGluZUNvZGVzJiZlLnJlbmRlcklubGluZUNvZGVzJiZpLnB1c2goIi0tcmVuZGVyLWlubGluZS1jb2RlcyIpLGUuY29uY2VwdE5hbWVDb2RlcyYmZS5jb25jZXB0TmFtZUNvZGVzJiZpLnB1c2goIi0tY29uY2VwdC1uYW1lLWNvZGVzIiksZS5udW1lcmljVW5pdENvZGVzJiZlLm51bWVyaWNVbml0Q29kZXMmJmkucHVzaCgiLS1udW1lcmljLXVuaXQtY29kZXMiKSxlLmNvZGVWYWx1ZVVuaXQmJmUuY29kZVZhbHVlVW5pdCYmaS5wdXNoKCItLWNvZGUtdmFsdWUtdW5pdCIpLGUuY29kZU1lYW5pbmdVbml0JiZlLmNvZGVNZWFuaW5nVW5pdCYmaS5wdXNoKCItLWNvZGUtbWVhbmluZy11bml0IiksZS5yZW5kZXJBbGxDb2RlcyYmZS5yZW5kZXJBbGxDb2RlcyYmaS5wdXNoKCItLXJlbmRlci1hbGwtY29kZXMiKSxlLmNvZGVEZXRhaWxzVG9vbHRpcCYmZS5jb2RlRGV0YWlsc1Rvb2x0aXAmJmkucHVzaCgiLS1jb2RlLWRldGFpbHMtdG9vbHRpcCIpO2xldCBDPSJzdHJ1Y3R1cmVkLXJlcG9ydC10by1odG1sIixsPWU/LndlYldvcmtlcjtsPT09dm9pZCAwJiYobD1hd2FpdCBKKCkpO2xldHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTphLHN0ZGVycjpFLG91dHB1dHM6Qn09YXdhaXQgYihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6TigpLHBpcGVsaW5lV29ya2VyVXJsOkYoKSx3ZWJXb3JrZXI6bCxub0NvcHk6ZT8ubm9Db3B5fSk7aWYoYSE9PTAmJkUhPT0iIil0aHJvdyBuZXcgRXJyb3IoRSk7cmV0dXJue3dlYldvcmtlcjpzLG91dHB1dFRleHQ6KEJbMF0/LmRhdGEpLmRhdGF9fXZhciBFaT11aTthc3luYyBmdW5jdGlvbiBRaShBLGU9e30pe2xldCB0PVt7dHlwZTpRLlRleHRTdHJlYW19XSxyPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBjPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTtyPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KGMpfX1sZXQgbj1be3R5cGU6US5CaW5hcnlGaWxlLGRhdGE6cn1dLGk9W10sbz1yLnBhdGg7aS5wdXNoKG8pO2xldCBnPSIwIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLGUudW5rbm93blJlbGF0aW9uc2hpcCYmZS51bmtub3duUmVsYXRpb25zaGlwJiZpLnB1c2goIi0tdW5rbm93bi1yZWxhdGlvbnNoaXAiKSxlLmludmFsaWRJdGVtVmFsdWUmJmUuaW52YWxpZEl0ZW1WYWx1ZSYmaS5wdXNoKCItLWludmFsaWQtaXRlbS12YWx1ZSIpLGUuaWdub3JlQ29uc3RyYWludHMmJmUuaWdub3JlQ29uc3RyYWludHMmJmkucHVzaCgiLS1pZ25vcmUtY29uc3RyYWludHMiKSxlLmlnbm9yZUl0ZW1FcnJvcnMmJmUuaWdub3JlSXRlbUVycm9ycyYmaS5wdXNoKCItLWlnbm9yZS1pdGVtLWVycm9ycyIpLGUuc2tpcEludmFsaWRJdGVtcyYmZS5za2lwSW52YWxpZEl0ZW1zJiZpLnB1c2goIi0tc2tpcC1pbnZhbGlkLWl0ZW1zIiksZS5ub0RvY3VtZW50SGVhZGVyJiZlLm5vRG9jdW1lbnRIZWFkZXImJmkucHVzaCgiLS1uby1kb2N1bWVudC1oZWFkZXIiKSxlLm51bWJlck5lc3RlZEl0ZW1zJiZlLm51bWJlck5lc3RlZEl0ZW1zJiZpLnB1c2goIi0tbnVtYmVyLW5lc3RlZC1pdGVtcyIpLGUuc2hvcnRlbkxvbmdWYWx1ZXMmJmUuc2hvcnRlbkxvbmdWYWx1ZXMmJmkucHVzaCgiLS1zaG9ydGVuLWxvbmctdmFsdWVzIiksZS5wcmludEluc3RhbmNlVWlkJiZlLnByaW50SW5zdGFuY2VVaWQmJmkucHVzaCgiLS1wcmludC1pbnN0YW5jZS11aWQiKSxlLnByaW50U29wY2xhc3NTaG9ydCYmZS5wcmludFNvcGNsYXNzU2hvcnQmJmkucHVzaCgiLS1wcmludC1zb3BjbGFzcy1zaG9ydCIpLGUucHJpbnRTb3BjbGFzc0xvbmcmJmUucHJpbnRTb3BjbGFzc0xvbmcmJmkucHVzaCgiLS1wcmludC1zb3BjbGFzcy1sb25nIiksZS5wcmludFNvcGNsYXNzVWlkJiZlLnByaW50U29wY2xhc3NVaWQmJmkucHVzaCgiLS1wcmludC1zb3BjbGFzcy11aWQiKSxlLnByaW50QWxsQ29kZXMmJmUucHJpbnRBbGxDb2RlcyYmaS5wdXNoKCItLXByaW50LWFsbC1jb2RlcyIpLGUucHJpbnRJbnZhbGlkQ29kZXMmJmUucHJpbnRJbnZhbGlkQ29kZXMmJmkucHVzaCgiLS1wcmludC1pbnZhbGlkLWNvZGVzIiksZS5wcmludFRlbXBsYXRlSWQmJmUucHJpbnRUZW1wbGF0ZUlkJiZpLnB1c2goIi0tcHJpbnQtdGVtcGxhdGUtaWQiKSxlLmluZGljYXRlRW5oYW5jZWQmJmUuaW5kaWNhdGVFbmhhbmNlZCYmaS5wdXNoKCItLWluZGljYXRlLWVuaGFuY2VkIiksZS5wcmludENvbG9yJiZlLnByaW50Q29sb3ImJmkucHVzaCgiLS1wcmludC1jb2xvciIpO2xldCBDPSJzdHJ1Y3R1cmVkLXJlcG9ydC10by10ZXh0IixsPWU/LndlYldvcmtlcjtsPT09dm9pZCAwJiYobD1hd2FpdCBKKCkpO2xldHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTphLHN0ZGVycjpFLG91dHB1dHM6Qn09YXdhaXQgYihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6TigpLHBpcGVsaW5lV29ya2VyVXJsOkYoKSx3ZWJXb3JrZXI6bCxub0NvcHk6ZT8ubm9Db3B5fSk7aWYoYSE9PTAmJkUhPT0iIil0aHJvdyBuZXcgRXJyb3IoRSk7cmV0dXJue3dlYldvcmtlcjpzLG91dHB1dFRleHQ6KEJbMF0/LmRhdGEpLmRhdGF9fXZhciBmaT1RaTthc3luYyBmdW5jdGlvbiBwaShBLGU9e30pe2xldCB0PVt7dHlwZTpRLkpzb25Db21wYXRpYmxlfV0scj1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgdT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7cj17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheSh1KX19bGV0IG49W3t0eXBlOlEuQmluYXJ5RmlsZSxkYXRhOnJ9XSxpPVtdLG89ci5wYXRoO2kucHVzaChvKTtsZXQgZz0iMCI7aWYoaS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgZS50YWdzVG9SZWFkPCJ1Iil7bGV0IHU9bi5sZW5ndGgudG9TdHJpbmcoKTtuLnB1c2goe3R5cGU6US5Kc29uQ29tcGF0aWJsZSxkYXRhOmUudGFnc1RvUmVhZH0pLGkucHVzaCgiLS10YWdzLXRvLXJlYWQiLHUpfWxldCBDPSJyZWFkLWRpY29tLXRhZ3MiLHt3ZWJXb3JrZXI6bCxyZXR1cm5WYWx1ZTpzLHN0ZGVycjphLG91dHB1dHM6RX09YXdhaXQgYihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6TigpLHBpcGVsaW5lV29ya2VyVXJsOkYoKSx3ZWJXb3JrZXI6ZT8ud2ViV29ya2VyPz9udWxsfSk7aWYocyE9PTApdGhyb3cgbmV3IEVycm9yKGEpO3JldHVybnt3ZWJXb3JrZXI6bCx0YWdzOkVbMF0uZGF0YX19dmFyIGRpPXBpO2FzeW5jIGZ1bmN0aW9uIG1pKEEsZT0hMSx0PXt9KXtsZXQgcj1be3R5cGU6US5JbWFnZX0se3R5cGU6US5Kc29uQ29tcGF0aWJsZX1dLG49W10saT1bXSxvPSIwIjtpLnB1c2gobyk7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksaS5wdXNoKCItLWlucHV0LWltYWdlcyIpLEEuZm9yRWFjaCh1PT57bi5wdXNoKHt0eXBlOlEuQmluYXJ5RmlsZSxkYXRhOnV9KSxpLnB1c2godS5wYXRoKX0pLHR5cGVvZiBlPCJ1IiYmZSYmaS5wdXNoKCItLXNpbmdsZS1zb3J0ZWQtc2VyaWVzIik7bGV0IEM9InJlYWQtaW1hZ2UtZGljb20tZmlsZS1zZXJpZXMiLHt3ZWJXb3JrZXI6bCxyZXR1cm5WYWx1ZTpzLHN0ZGVycjphLG91dHB1dHM6RX09YXdhaXQgYihDLGkscixuLHtwaXBlbGluZUJhc2VVcmw6TigpLHBpcGVsaW5lV29ya2VyVXJsOkYoKSx3ZWJXb3JrZXI6dD8ud2ViV29ya2VyPz9udWxsfSk7aWYocyE9PTApdGhyb3cgbmV3IEVycm9yKGEpO3JldHVybnt3ZWJXb3JrZXI6bCxvdXRwdXRJbWFnZTpFWzBdLmRhdGEsc29ydGVkRmlsZW5hbWVzOkVbMV0uZGF0YX19dmFyIGdlPW1pO3ZhciBoaT10eXBlb2YgZ2xvYmFsVGhpcy5uYXZpZ2F0b3I/LmhhcmR3YXJlQ29uY3VycmVuY3k9PSJudW1iZXIiP2dsb2JhbFRoaXMubmF2aWdhdG9yLmhhcmR3YXJlQ29uY3VycmVuY3k6NCx5dD04O2FzeW5jIGZ1bmN0aW9uIHlpKEE9e2lucHV0SW1hZ2VzOltdfSl7bGV0IGU9QS53ZWJXb3JrZXJQb29sPz9udWxsO2U9PT1udWxsJiYoZT1uZXcgR0EoaGksZ2UpKTtsZXQgdD1bXTtpZihBLmlucHV0SW1hZ2VzLmxlbmd0aDwxKXRocm93IG5ldyBFcnJvcignImlucHV0LWltYWdlcyIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtpZihhd2FpdCBQcm9taXNlLmFsbChBLmlucHV0SW1hZ2VzLm1hcChhc3luYyByPT57bGV0IG49cjtpZihyIGluc3RhbmNlb2YgRmlsZSl7bGV0IGk9YXdhaXQgci5hcnJheUJ1ZmZlcigpO249e3BhdGg6ci5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoaSl9fXQucHVzaChuKX0pKSxBLnNpbmdsZVNvcnRlZFNlcmllcyl7bGV0IHI9W107Zm9yKGxldCBDPTA7Qzx0Lmxlbmd0aDtDKz15dCl7bGV0IGw9dC5zbGljZShDLEMreXQpO3IucHVzaChbbCxBLnNpbmdsZVNvcnRlZFNlcmllcyx7fV0pfWxldCBuPWF3YWl0IGUucnVuVGFza3MocikucHJvbWlzZSxpPW4ubWFwKEM9PkMub3V0cHV0SW1hZ2UpLG89bi5yZWR1Y2UoKEMsbCk9PkMuY29uY2F0KGwuc29ydGVkRmlsZW5hbWVzKSxbXSk7cmV0dXJue291dHB1dEltYWdlOlVBKGkpLHdlYldvcmtlclBvb2w6ZSxzb3J0ZWRGaWxlbmFtZXM6b319ZWxzZXtsZXQgcj1bW3QsQS5zaW5nbGVTb3J0ZWRTZXJpZXMse31dXSxuPWF3YWl0IGUucnVuVGFza3MocikucHJvbWlzZTtyZXR1cm57b3V0cHV0SW1hZ2U6blswXS5vdXRwdXRJbWFnZSx3ZWJXb3JrZXJQb29sOmUsc29ydGVkRmlsZW5hbWVzOm5bMF0uc29ydGVkRmlsZW5hbWVzfX19dmFyIHdpPXlpO3ZhciB3dD0nZGF0YTp0ZXh0L2phdmFzY3JpcHQ7Y2hhcnNldD11dGYtOCx2YXIgdHQ9T2JqZWN0LmRlZmluZVByb3BlcnR5O3ZhciBldD0oQSxJKT0+e2Zvcih2YXIgdCBpbiBJKXR0KEEsdCx7Z2V0OklbdF0sZW51bWVyYWJsZTohMH0pfTt2YXIgdkE9U3ltYm9sKCJDb21saW5rLnByb3h5IiksZ3Q9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IikscnQ9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLG1BPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxlQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksJEE9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsaXQ9e2NhbkhhbmRsZTpBPT4kQShBKSYmQVt2QV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTpJLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gb0EoQSxJKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLHN0KEEpfX0sb3Q9e2NhbkhhbmRsZTpBPT4kQShBKSYmZUEgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgSTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP0k9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTpJPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtJLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LEFJPW5ldyBNYXAoW1sicHJveHkiLGl0XSxbInRocm93IixvdF1dKTtmdW5jdGlvbiBCdChBLEkpe2ZvcihsZXQgdCBvZiBBKWlmKEk9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoSSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gb0EoQSxJPWdsb2JhbFRoaXMsdD1bIioiXSl7SS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBlKGcpe2lmKCFnfHwhZy5kYXRhKXJldHVybjtpZighQnQodCxnLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gXCcke2cub3JpZ2lufVwnIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDpyLHR5cGU6aSxwYXRoOnN9PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LGcuZGF0YSksYT0oZy5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChiKSxuO3RyeXtsZXQgQz1zLnNsaWNlKDAsLTEpLnJlZHVjZSgoZixRKT0+ZltRXSxBKSxvPXMucmVkdWNlKChmLFEpPT5mW1FdLEEpO3N3aXRjaChpKXtjYXNlIkdFVCI6bj1vO2JyZWFrO2Nhc2UiU0VUIjpDW3Muc2xpY2UoLTEpWzBdXT1iKGcuZGF0YS52YWx1ZSksbj0hMDticmVhaztjYXNlIkFQUExZIjpuPW8uYXBwbHkoQyxhKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBmPW5ldyBvKC4uLmEpO249YXQoZil9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTpmLHBvcnQyOlF9PW5ldyBNZXNzYWdlQ2hhbm5lbDtvQShBLFEpLG49U0EoZixbZl0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6bj12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKEMpe249e3ZhbHVlOkMsW2VBXTowfX1Qcm9taXNlLnJlc29sdmUobikuY2F0Y2goQz0+KHt2YWx1ZTpDLFtlQV06MH0pKS50aGVuKEM9PntsZXRbbyxmXT1pQShDKTtJLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxvKSx7aWQ6cn0pLGYpLGk9PT0iUkVMRUFTRSImJihJLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGUpLElJKEkpLG1BIGluIEEmJnR5cGVvZiBBW21BXT09ImZ1bmN0aW9uIiYmQVttQV0oKSl9KS5jYXRjaChDPT57bGV0W28sZl09aUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtlQV06MH0pO0kucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LG8pLHtpZDpyfSksZil9KX0pLEkuc3RhcnQmJkkuc3RhcnQoKX1mdW5jdGlvbiBDdChBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiBJSShBKXtDdChBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIHN0KEEsSSl7cmV0dXJuIHBBKEEsW10sSSl9ZnVuY3Rpb24gdEEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIHRJKEEpe3JldHVybiBNKEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+e0lJKEEpfSl9dmFyIGdBPW5ldyBXZWFrTWFwLHJBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBJPShnQS5nZXQoQSl8fDApLTE7Z0Euc2V0KEEsSSksST09PTAmJnRJKEEpfSk7ZnVuY3Rpb24gUXQoQSxJKXtsZXQgdD0oZ0EuZ2V0KEkpfHwwKSsxO2dBLnNldChJLHQpLHJBJiZyQS5yZWdpc3RlcihBLEksQSl9ZnVuY3Rpb24gbnQoQSl7ckEmJnJBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gcEEoQSxJPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgZT0hMSxnPW5ldyBQcm94eSh0LHtnZXQocixpKXtpZih0QShlKSxpPT09cnQpcmV0dXJuKCk9PntudChnKSx0SShBKSxlPSEwfTtpZihpPT09InRoZW4iKXtpZihJLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9Pmd9O2xldCBzPU0oQSx7dHlwZToiR0VUIixwYXRoOkkubWFwKGE9PmEudG9TdHJpbmcoKSl9KS50aGVuKGIpO3JldHVybiBzLnRoZW4uYmluZChzKX1yZXR1cm4gcEEoQSxbLi4uSSxpXSl9LHNldChyLGkscyl7dEEoZSk7bGV0W2Esbl09aUEocyk7cmV0dXJuIE0oQSx7dHlwZToiU0VUIixwYXRoOlsuLi5JLGldLm1hcChDPT5DLnRvU3RyaW5nKCkpLHZhbHVlOmF9LG4pLnRoZW4oYil9LGFwcGx5KHIsaSxzKXt0QShlKTtsZXQgYT1JW0kubGVuZ3RoLTFdO2lmKGE9PT1ndClyZXR1cm4gTShBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKGIpO2lmKGE9PT0iYmluZCIpcmV0dXJuIHBBKEEsSS5zbGljZSgwLC0xKSk7bGV0W24sQ109X0Eocyk7cmV0dXJuIE0oQSx7dHlwZToiQVBQTFkiLHBhdGg6SS5tYXAobz0+by50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6bn0sQykudGhlbihiKX0sY29uc3RydWN0KHIsaSl7dEEoZSk7bGV0W3MsYV09X0EoaSk7cmV0dXJuIE0oQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOkkubWFwKG49Pm4udG9TdHJpbmcoKSksYXJndW1lbnRMaXN0OnN9LGEpLnRoZW4oYil9fSk7cmV0dXJuIFF0KGcsQSksZ31mdW5jdGlvbiBFdChBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBfQShBKXtsZXQgST1BLm1hcChpQSk7cmV0dXJuW0kubWFwKHQ9PnRbMF0pLEV0KEkubWFwKHQ9PnRbMV0pKV19dmFyIGVJPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIFNBKEEsSSl7cmV0dXJuIGVJLnNldChBLEkpLEF9ZnVuY3Rpb24gYXQoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W3ZBXTohMH0pfWZ1bmN0aW9uIGlBKEEpe2ZvcihsZXRbSSx0XW9mIEFJKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbZSxnXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6SSx2YWx1ZTplfSxnXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sZUkuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gYihBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBBSS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIE0oQSxJLHQpe3JldHVybiBuZXcgUHJvbWlzZShlPT57bGV0IGc9Y3QoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIHIoaSl7IWkuZGF0YXx8IWkuZGF0YS5pZHx8aS5kYXRhLmlkIT09Z3x8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsciksZShpLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOmd9LEkpLHQpfSl9ZnVuY3Rpb24gY3QoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIFcoQSxJKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseShJLGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzpmdH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6TkF9PU9iamVjdCxDQT0oQT0+ST0+e2xldCB0PWZ0LmNhbGwoSSk7cmV0dXJuIEFbdF18fChBW3RdPXQuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxVPUE9PihBPUEudG9Mb3dlckNhc2UoKSxJPT5DQShJKT09PUEpLHNBPUE9Pkk9PnR5cGVvZiBJPT09QSx7aXNBcnJheTpxfT1BcnJheSxaPXNBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiBsdChBKXtyZXR1cm4gQSE9PW51bGwmJiFaKEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIVooQS5jb25zdHJ1Y3RvcikmJkYoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIG9JPVUoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gRHQoQSl7bGV0IEk7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9JPUFycmF5QnVmZmVyLmlzVmlldyhBKTpJPUEmJkEuYnVmZmVyJiZvSShBLmJ1ZmZlciksSX12YXIgdXQ9c0EoInN0cmluZyIpLEY9c0EoImZ1bmN0aW9uIiksQkk9c0EoIm51bWJlciIpLFFBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsaHQ9QT0+QT09PSEwfHxBPT09ITEsQkE9QT0+e2lmKENBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IEk9TkEoQSk7cmV0dXJuKEk9PT1udWxsfHxJPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKEkpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0sZHQ9VSgiRGF0ZSIpLHl0PVUoIkZpbGUiKSx3dD1VKCJCbG9iIiksbXQ9VSgiRmlsZUxpc3QiKSxwdD1BPT5RQShBKSYmRihBLnBpcGUpLFN0PUE9PntsZXQgSTtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxGKEEuYXBwZW5kKSYmKChJPUNBKEEpKT09PSJmb3JtZGF0YSJ8fEk9PT0ib2JqZWN0IiYmRihBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxGdD1VKCJVUkxTZWFyY2hQYXJhbXMiKSxSdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywiIik7ZnVuY3Rpb24gVihBLEkse2FsbE93bktleXM6dD0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCBlLGc7aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLHEoQSkpZm9yKGU9MCxnPUEubGVuZ3RoO2U8ZztlKyspSS5jYWxsKG51bGwsQVtlXSxlLEEpO2Vsc2V7bGV0IHI9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxpPXIubGVuZ3RoLHM7Zm9yKGU9MDtlPGk7ZSsrKXM9cltlXSxJLmNhbGwobnVsbCxBW3NdLHMsQSl9fWZ1bmN0aW9uIENJKEEsSSl7ST1JLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksZT10Lmxlbmd0aCxnO2Zvcig7ZS0tID4wOylpZihnPXRbZV0sST09PWcudG9Mb3dlckNhc2UoKSlyZXR1cm4gZztyZXR1cm4gbnVsbH12YXIgc0k9dHlwZW9mIGdsb2JhbFRoaXM8InUiP2dsb2JhbFRoaXM6dHlwZW9mIHNlbGY8InUiP3NlbGY6dHlwZW9mIHdpbmRvdzwidSI/d2luZG93Omdsb2JhbCxRST1BPT4hWihBKSYmQSE9PXNJO2Z1bmN0aW9uIFJBKCl7bGV0e2Nhc2VsZXNzOkF9PVFJKHRoaXMpJiZ0aGlzfHx7fSxJPXt9LHQ9KGUsZyk9PntsZXQgcj1BJiZDSShJLGcpfHxnO0JBKElbcl0pJiZCQShlKT9JW3JdPVJBKElbcl0sZSk6QkEoZSk/SVtyXT1SQSh7fSxlKTpxKGUpP0lbcl09ZS5zbGljZSgpOklbcl09ZX07Zm9yKGxldCBlPTAsZz1hcmd1bWVudHMubGVuZ3RoO2U8ZztlKyspYXJndW1lbnRzW2VdJiZWKGFyZ3VtZW50c1tlXSx0KTtyZXR1cm4gSX12YXIgTnQ9KEEsSSx0LHthbGxPd25LZXlzOmV9PXt9KT0+KFYoSSwoZyxyKT0+e3QmJkYoZyk/QVtyXT1XKGcsdCk6QVtyXT1nfSx7YWxsT3duS2V5czplfSksQSksVXQ9QT0+KEEuY2hhckNvZGVBdCgwKT09PTY1Mjc5JiYoQT1BLnNsaWNlKDEpKSxBKSxHdD0oQSxJLHQsZSk9PntBLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKEkucHJvdG90eXBlLGUpLEEucHJvdG90eXBlLmNvbnN0cnVjdG9yPUEsT2JqZWN0LmRlZmluZVByb3BlcnR5KEEsInN1cGVyIix7dmFsdWU6SS5wcm90b3R5cGV9KSx0JiZPYmplY3QuYXNzaWduKEEucHJvdG90eXBlLHQpfSxrdD0oQSxJLHQsZSk9PntsZXQgZyxyLGkscz17fTtpZihJPUl8fHt9LEE9PW51bGwpcmV0dXJuIEk7ZG97Zm9yKGc9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSkscj1nLmxlbmd0aDtyLS0gPjA7KWk9Z1tyXSwoIWV8fGUoaSxBLEkpKSYmIXNbaV0mJihJW2ldPUFbaV0sc1tpXT0hMCk7QT10IT09ITEmJk5BKEEpfXdoaWxlKEEmJighdHx8dChBLEkpKSYmQSE9PU9iamVjdC5wcm90b3R5cGUpO3JldHVybiBJfSxMdD0oQSxJLHQpPT57QT1TdHJpbmcoQSksKHQ9PT12b2lkIDB8fHQ+QS5sZW5ndGgpJiYodD1BLmxlbmd0aCksdC09SS5sZW5ndGg7bGV0IGU9QS5pbmRleE9mKEksdCk7cmV0dXJuIGUhPT0tMSYmZT09PXR9LEp0PUE9PntpZighQSlyZXR1cm4gbnVsbDtpZihxKEEpKXJldHVybiBBO2xldCBJPUEubGVuZ3RoO2lmKCFCSShJKSlyZXR1cm4gbnVsbDtsZXQgdD1uZXcgQXJyYXkoSSk7Zm9yKDtJLS0gPjA7KXRbSV09QVtJXTtyZXR1cm4gdH0sSHQ9KEE9Pkk9PkEmJkkgaW5zdGFuY2VvZiBBKSh0eXBlb2YgVWludDhBcnJheTwidSImJk5BKFVpbnQ4QXJyYXkpKSxZdD0oQSxJKT0+e2xldCBlPShBJiZBW1N5bWJvbC5pdGVyYXRvcl0pLmNhbGwoQSksZztmb3IoOyhnPWUubmV4dCgpKSYmIWcuZG9uZTspe2xldCByPWcudmFsdWU7SS5jYWxsKEEsclswXSxyWzFdKX19LGJ0PShBLEkpPT57bGV0IHQsZT1bXTtmb3IoOyh0PUEuZXhlYyhJKSkhPT1udWxsOyllLnB1c2godCk7cmV0dXJuIGV9LE10PVUoIkhUTUxGb3JtRWxlbWVudCIpLHF0PUE9PkEudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bLV9cXHNdKFthLXpcXGRdKShcXHcqKS9nLGZ1bmN0aW9uKHQsZSxnKXtyZXR1cm4gZS50b1VwcGVyQ2FzZSgpK2d9KSxyST0oKHtoYXNPd25Qcm9wZXJ0eTpBfSk9PihJLHQpPT5BLmNhbGwoSSx0KSkoT2JqZWN0LnByb3RvdHlwZSksS3Q9VSgiUmVnRXhwIiksbkk9KEEsSSk9PntsZXQgdD1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyhBKSxlPXt9O1YodCwoZyxyKT0+e2xldCBpOyhpPUkoZyxyLEEpKSE9PSExJiYoZVtyXT1pfHxnKX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEEsZSl9LE90PUE9PntuSShBLChJLHQpPT57aWYoRihBKSYmWyJhcmd1bWVudHMiLCJjYWxsZXIiLCJjYWxsZWUiXS5pbmRleE9mKHQpIT09LTEpcmV0dXJuITE7bGV0IGU9QVt0XTtpZihGKGUpKXtpZihJLmVudW1lcmFibGU9ITEsIndyaXRhYmxlImluIEkpe0kud3JpdGFibGU9ITE7cmV0dXJufUkuc2V0fHwoSS5zZXQ9KCk9Pnt0aHJvdyBFcnJvcigiQ2FuIG5vdCByZXdyaXRlIHJlYWQtb25seSBtZXRob2QgXCciK3QrIlwnIil9KX19KX0sVHQ9KEEsSSk9PntsZXQgdD17fSxlPWc9PntnLmZvckVhY2gocj0+e3Rbcl09ITB9KX07cmV0dXJuIHEoQSk/ZShBKTplKFN0cmluZyhBKS5zcGxpdChJKSksdH0seHQ9KCk9Pnt9LFB0PShBLEkpPT4oQT0rQSxOdW1iZXIuaXNGaW5pdGUoQSk/QTpJKSxGQT0iYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoiLGlJPSIwMTIzNDU2Nzg5IixFST17RElHSVQ6aUksQUxQSEE6RkEsQUxQSEFfRElHSVQ6RkErRkEudG9VcHBlckNhc2UoKStpSX0sanQ9KEE9MTYsST1FSS5BTFBIQV9ESUdJVCk9PntsZXQgdD0iIix7bGVuZ3RoOmV9PUk7Zm9yKDtBLS07KXQrPUlbTWF0aC5yYW5kb20oKSplfDBdO3JldHVybiB0fTtmdW5jdGlvbiBXdChBKXtyZXR1cm4hIShBJiZGKEEuYXBwZW5kKSYmQVtTeW1ib2wudG9TdHJpbmdUYWddPT09IkZvcm1EYXRhIiYmQVtTeW1ib2wuaXRlcmF0b3JdKX12YXIgWnQ9QT0+e2xldCBJPW5ldyBBcnJheSgxMCksdD0oZSxnKT0+e2lmKFFBKGUpKXtpZihJLmluZGV4T2YoZSk+PTApcmV0dXJuO2lmKCEoInRvSlNPTiJpbiBlKSl7SVtnXT1lO2xldCByPXEoZSk/W106e307cmV0dXJuIFYoZSwoaSxzKT0+e2xldCBhPXQoaSxnKzEpOyFaKGEpJiYocltzXT1hKX0pLElbZ109dm9pZCAwLHJ9fXJldHVybiBlfTtyZXR1cm4gdChBLDApfSxWdD1VKCJBc3luY0Z1bmN0aW9uIiksWHQ9QT0+QSYmKFFBKEEpfHxGKEEpKSYmRihBLnRoZW4pJiZGKEEuY2F0Y2gpLEI9e2lzQXJyYXk6cSxpc0FycmF5QnVmZmVyOm9JLGlzQnVmZmVyOmx0LGlzRm9ybURhdGE6U3QsaXNBcnJheUJ1ZmZlclZpZXc6RHQsaXNTdHJpbmc6dXQsaXNOdW1iZXI6QkksaXNCb29sZWFuOmh0LGlzT2JqZWN0OlFBLGlzUGxhaW5PYmplY3Q6QkEsaXNVbmRlZmluZWQ6Wixpc0RhdGU6ZHQsaXNGaWxlOnl0LGlzQmxvYjp3dCxpc1JlZ0V4cDpLdCxpc0Z1bmN0aW9uOkYsaXNTdHJlYW06cHQsaXNVUkxTZWFyY2hQYXJhbXM6RnQsaXNUeXBlZEFycmF5Okh0LGlzRmlsZUxpc3Q6bXQsZm9yRWFjaDpWLG1lcmdlOlJBLGV4dGVuZDpOdCx0cmltOlJ0LHN0cmlwQk9NOlV0LGluaGVyaXRzOkd0LHRvRmxhdE9iamVjdDprdCxraW5kT2Y6Q0Esa2luZE9mVGVzdDpVLGVuZHNXaXRoOkx0LHRvQXJyYXk6SnQsZm9yRWFjaEVudHJ5Oll0LG1hdGNoQWxsOmJ0LGlzSFRNTEZvcm06TXQsaGFzT3duUHJvcGVydHk6ckksaGFzT3duUHJvcDpySSxyZWR1Y2VEZXNjcmlwdG9yczpuSSxmcmVlemVNZXRob2RzOk90LHRvT2JqZWN0U2V0OlR0LHRvQ2FtZWxDYXNlOnF0LG5vb3A6eHQsdG9GaW5pdGVOdW1iZXI6UHQsZmluZEtleTpDSSxnbG9iYWw6c0ksaXNDb250ZXh0RGVmaW5lZDpRSSxBTFBIQUJFVDpFSSxnZW5lcmF0ZVN0cmluZzpqdCxpc1NwZWNDb21wbGlhbnRGb3JtOld0LHRvSlNPTk9iamVjdDpadCxpc0FzeW5jRm46VnQsaXNUaGVuYWJsZTpYdH07ZnVuY3Rpb24gSyhBLEksdCxlLGcpe0Vycm9yLmNhbGwodGhpcyksRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2U/RXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UodGhpcyx0aGlzLmNvbnN0cnVjdG9yKTp0aGlzLnN0YWNrPW5ldyBFcnJvcigpLnN0YWNrLHRoaXMubWVzc2FnZT1BLHRoaXMubmFtZT0iQXhpb3NFcnJvciIsSSYmKHRoaXMuY29kZT1JKSx0JiYodGhpcy5jb25maWc9dCksZSYmKHRoaXMucmVxdWVzdD1lKSxnJiYodGhpcy5yZXNwb25zZT1nKX1CLmluaGVyaXRzKEssRXJyb3Ise3RvSlNPTjpmdW5jdGlvbigpe3JldHVybnttZXNzYWdlOnRoaXMubWVzc2FnZSxuYW1lOnRoaXMubmFtZSxkZXNjcmlwdGlvbjp0aGlzLmRlc2NyaXB0aW9uLG51bWJlcjp0aGlzLm51bWJlcixmaWxlTmFtZTp0aGlzLmZpbGVOYW1lLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGNvbHVtbk51bWJlcjp0aGlzLmNvbHVtbk51bWJlcixzdGFjazp0aGlzLnN0YWNrLGNvbmZpZzpCLnRvSlNPTk9iamVjdCh0aGlzLmNvbmZpZyksY29kZTp0aGlzLmNvZGUsc3RhdHVzOnRoaXMucmVzcG9uc2UmJnRoaXMucmVzcG9uc2Uuc3RhdHVzP3RoaXMucmVzcG9uc2Uuc3RhdHVzOm51bGx9fX0pO3ZhciBhST1LLnByb3RvdHlwZSxjST17fTtbIkVSUl9CQURfT1BUSU9OX1ZBTFVFIiwiRVJSX0JBRF9PUFRJT04iLCJFQ09OTkFCT1JURUQiLCJFVElNRURPVVQiLCJFUlJfTkVUV09SSyIsIkVSUl9GUl9UT09fTUFOWV9SRURJUkVDVFMiLCJFUlJfREVQUkVDQVRFRCIsIkVSUl9CQURfUkVTUE9OU0UiLCJFUlJfQkFEX1JFUVVFU1QiLCJFUlJfQ0FOQ0VMRUQiLCJFUlJfTk9UX1NVUFBPUlQiLCJFUlJfSU5WQUxJRF9VUkwiXS5mb3JFYWNoKEE9PntjSVtBXT17dmFsdWU6QX19KTtPYmplY3QuZGVmaW5lUHJvcGVydGllcyhLLGNJKTtPYmplY3QuZGVmaW5lUHJvcGVydHkoYUksImlzQXhpb3NFcnJvciIse3ZhbHVlOiEwfSk7Sy5mcm9tPShBLEksdCxlLGcscik9PntsZXQgaT1PYmplY3QuY3JlYXRlKGFJKTtyZXR1cm4gQi50b0ZsYXRPYmplY3QoQSxpLGZ1bmN0aW9uKGEpe3JldHVybiBhIT09RXJyb3IucHJvdG90eXBlfSxzPT5zIT09ImlzQXhpb3NFcnJvciIpLEsuY2FsbChpLEEubWVzc2FnZSxJLHQsZSxnKSxpLmNhdXNlPUEsaS5uYW1lPUEubmFtZSxyJiZPYmplY3QuYXNzaWduKGksciksaX07dmFyIGw9Szt2YXIgbkE9bnVsbDtmdW5jdGlvbiBVQShBKXtyZXR1cm4gQi5pc1BsYWluT2JqZWN0KEEpfHxCLmlzQXJyYXkoQSl9ZnVuY3Rpb24gbEkoQSl7cmV0dXJuIEIuZW5kc1dpdGgoQSwiW10iKT9BLnNsaWNlKDAsLTIpOkF9ZnVuY3Rpb24gZkkoQSxJLHQpe3JldHVybiBBP0EuY29uY2F0KEkpLm1hcChmdW5jdGlvbihnLHIpe3JldHVybiBnPWxJKGcpLCF0JiZyPyJbIitnKyJdIjpnfSkuam9pbih0PyIuIjoiIik6SX1mdW5jdGlvbiB6dChBKXtyZXR1cm4gQi5pc0FycmF5KEEpJiYhQS5zb21lKFVBKX12YXIgX3Q9Qi50b0ZsYXRPYmplY3QoQix7fSxudWxsLGZ1bmN0aW9uKEkpe3JldHVybi9eaXNbQS1aXS8udGVzdChJKX0pO2Z1bmN0aW9uIHZ0KEEsSSx0KXtpZighQi5pc09iamVjdChBKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJ0YXJnZXQgbXVzdCBiZSBhbiBvYmplY3QiKTtJPUl8fG5ldyhuQXx8Rm9ybURhdGEpLHQ9Qi50b0ZsYXRPYmplY3QodCx7bWV0YVRva2VuczohMCxkb3RzOiExLGluZGV4ZXM6ITF9LCExLGZ1bmN0aW9uKGMsdSl7cmV0dXJuIUIuaXNVbmRlZmluZWQodVtjXSl9KTtsZXQgZT10Lm1ldGFUb2tlbnMsZz10LnZpc2l0b3J8fEMscj10LmRvdHMsaT10LmluZGV4ZXMsYT0odC5CbG9ifHx0eXBlb2YgQmxvYjwidSImJkJsb2IpJiZCLmlzU3BlY0NvbXBsaWFudEZvcm0oSSk7aWYoIUIuaXNGdW5jdGlvbihnKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJ2aXNpdG9yIG11c3QgYmUgYSBmdW5jdGlvbiIpO2Z1bmN0aW9uIG4oRSl7aWYoRT09PW51bGwpcmV0dXJuIiI7aWYoQi5pc0RhdGUoRSkpcmV0dXJuIEUudG9JU09TdHJpbmcoKTtpZighYSYmQi5pc0Jsb2IoRSkpdGhyb3cgbmV3IGwoIkJsb2IgaXMgbm90IHN1cHBvcnRlZC4gVXNlIGEgQnVmZmVyIGluc3RlYWQuIik7cmV0dXJuIEIuaXNBcnJheUJ1ZmZlcihFKXx8Qi5pc1R5cGVkQXJyYXkoRSk/YSYmdHlwZW9mIEJsb2I9PSJmdW5jdGlvbiI/bmV3IEJsb2IoW0VdKTpCdWZmZXIuZnJvbShFKTpFfWZ1bmN0aW9uIEMoRSxjLHUpe2xldCBkPUU7aWYoRSYmIXUmJnR5cGVvZiBFPT0ib2JqZWN0Iil7aWYoQi5lbmRzV2l0aChjLCJ7fSIpKWM9ZT9jOmMuc2xpY2UoMCwtMiksRT1KU09OLnN0cmluZ2lmeShFKTtlbHNlIGlmKEIuaXNBcnJheShFKSYmenQoRSl8fChCLmlzRmlsZUxpc3QoRSl8fEIuZW5kc1dpdGgoYywiW10iKSkmJihkPUIudG9BcnJheShFKSkpcmV0dXJuIGM9bEkoYyksZC5mb3JFYWNoKGZ1bmN0aW9uKE4sSXQpeyEoQi5pc1VuZGVmaW5lZChOKXx8Tj09PW51bGwpJiZJLmFwcGVuZChpPT09ITA/ZkkoW2NdLEl0LHIpOmk9PT1udWxsP2M6YysiW10iLG4oTikpfSksITF9cmV0dXJuIFVBKEUpPyEwOihJLmFwcGVuZChmSSh1LGMsciksbihFKSksITEpfWxldCBvPVtdLGY9T2JqZWN0LmFzc2lnbihfdCx7ZGVmYXVsdFZpc2l0b3I6Qyxjb252ZXJ0VmFsdWU6bixpc1Zpc2l0YWJsZTpVQX0pO2Z1bmN0aW9uIFEoRSxjKXtpZighQi5pc1VuZGVmaW5lZChFKSl7aWYoby5pbmRleE9mKEUpIT09LTEpdGhyb3cgRXJyb3IoIkNpcmN1bGFyIHJlZmVyZW5jZSBkZXRlY3RlZCBpbiAiK2Muam9pbigiLiIpKTtvLnB1c2goRSksQi5mb3JFYWNoKEUsZnVuY3Rpb24oZCxSKXsoIShCLmlzVW5kZWZpbmVkKGQpfHxkPT09bnVsbCkmJmcuY2FsbChJLGQsQi5pc1N0cmluZyhSKT9SLnRyaW0oKTpSLGMsZikpPT09ITAmJlEoZCxjP2MuY29uY2F0KFIpOltSXSl9KSxvLnBvcCgpfX1pZighQi5pc09iamVjdChBKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJkYXRhIG11c3QgYmUgYW4gb2JqZWN0Iik7cmV0dXJuIFEoQSksSX12YXIgTD12dDtmdW5jdGlvbiBESShBKXtsZXQgST17IiEiOiIlMjUyMSIsIlwnIjoiJTI1MjciLCIoIjoiJTI1MjgiLCIpIjoiJTI1MjkiLCJ+IjoiJTI1N0UiLCIlMjUyMCI6IisiLCIlMjUwMCI6IlxcMCJ9O3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvWyFcJygpfl18JTI1MjB8JTI1MDAvZyxmdW5jdGlvbihlKXtyZXR1cm4gSVtlXX0pfWZ1bmN0aW9uIHVJKEEsSSl7dGhpcy5fcGFpcnM9W10sQSYmTChBLHRoaXMsSSl9dmFyIGhJPXVJLnByb3RvdHlwZTtoSS5hcHBlbmQ9ZnVuY3Rpb24oSSx0KXt0aGlzLl9wYWlycy5wdXNoKFtJLHRdKX07aEkudG9TdHJpbmc9ZnVuY3Rpb24oSSl7bGV0IHQ9ST9mdW5jdGlvbihlKXtyZXR1cm4gSS5jYWxsKHRoaXMsZSxESSl9OkRJO3JldHVybiB0aGlzLl9wYWlycy5tYXAoZnVuY3Rpb24oZyl7cmV0dXJuIHQoZ1swXSkrIj0iK3QoZ1sxXSl9LCIiKS5qb2luKCImIil9O3ZhciBFQT11STtmdW5jdGlvbiAkdChBKXtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoLyUyNTNBL2dpLCI6IikucmVwbGFjZSgvJTI1MjQvZywiJCIpLnJlcGxhY2UoLyUyNTJDL2dpLCIsIikucmVwbGFjZSgvJTI1MjAvZywiKyIpLnJlcGxhY2UoLyUyNTVCL2dpLCJbIikucmVwbGFjZSgvJTI1NUQvZ2ksIl0iKX1mdW5jdGlvbiBYKEEsSSx0KXtpZighSSlyZXR1cm4gQTtsZXQgZT10JiZ0LmVuY29kZXx8JHQsZz10JiZ0LnNlcmlhbGl6ZSxyO2lmKGc/cj1nKEksdCk6cj1CLmlzVVJMU2VhcmNoUGFyYW1zKEkpP0kudG9TdHJpbmcoKTpuZXcgRUEoSSx0KS50b1N0cmluZyhlKSxyKXtsZXQgaT1BLmluZGV4T2YoIiUyMyIpO2khPT0tMSYmKEE9QS5zbGljZSgwLGkpKSxBKz0oQS5pbmRleE9mKCI/Iik9PT0tMT8iPyI6IiYiKStyfXJldHVybiBBfXZhciBHQT1jbGFzc3tjb25zdHJ1Y3Rvcigpe3RoaXMuaGFuZGxlcnM9W119dXNlKEksdCxlKXtyZXR1cm4gdGhpcy5oYW5kbGVycy5wdXNoKHtmdWxmaWxsZWQ6SSxyZWplY3RlZDp0LHN5bmNocm9ub3VzOmU/ZS5zeW5jaHJvbm91czohMSxydW5XaGVuOmU/ZS5ydW5XaGVuOm51bGx9KSx0aGlzLmhhbmRsZXJzLmxlbmd0aC0xfWVqZWN0KEkpe3RoaXMuaGFuZGxlcnNbSV0mJih0aGlzLmhhbmRsZXJzW0ldPW51bGwpfWNsZWFyKCl7dGhpcy5oYW5kbGVycyYmKHRoaXMuaGFuZGxlcnM9W10pfWZvckVhY2goSSl7Qi5mb3JFYWNoKHRoaXMuaGFuZGxlcnMsZnVuY3Rpb24oZSl7ZSE9PW51bGwmJkkoZSl9KX19LGtBPUdBO3ZhciBhQT17c2lsZW50SlNPTlBhcnNpbmc6ITAsZm9yY2VkSlNPTlBhcnNpbmc6ITAsY2xhcmlmeVRpbWVvdXRFcnJvcjohMX07dmFyIGRJPXR5cGVvZiBVUkxTZWFyY2hQYXJhbXM8InUiP1VSTFNlYXJjaFBhcmFtczpFQTt2YXIgeUk9dHlwZW9mIEZvcm1EYXRhPCJ1Ij9Gb3JtRGF0YTpudWxsO3ZhciB3ST10eXBlb2YgQmxvYjwidSI/QmxvYjpudWxsO3ZhciBtST17aXNCcm93c2VyOiEwLGNsYXNzZXM6e1VSTFNlYXJjaFBhcmFtczpkSSxGb3JtRGF0YTp5SSxCbG9iOndJfSxwcm90b2NvbHM6WyJodHRwIiwiaHR0cHMiLCJmaWxlIiwiYmxvYiIsInVybCIsImRhdGEiXX07dmFyIExBPXt9O2V0KExBLHtoYXNCcm93c2VyRW52OigpPT5wSSxoYXNTdGFuZGFyZEJyb3dzZXJFbnY6KCk9PkFlLGhhc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudjooKT0+SWV9KTt2YXIgcEk9dHlwZW9mIHdpbmRvdzwidSImJnR5cGVvZiBkb2N1bWVudDwidSIsQWU9KEE9PnBJJiZbIlJlYWN0TmF0aXZlIiwiTmF0aXZlU2NyaXB0IiwiTlMiXS5pbmRleE9mKEEpPDApKHR5cGVvZiBuYXZpZ2F0b3I8InUiJiZuYXZpZ2F0b3IucHJvZHVjdCksSWU9dHlwZW9mIFdvcmtlckdsb2JhbFNjb3BlPCJ1IiYmc2VsZiBpbnN0YW5jZW9mIFdvcmtlckdsb2JhbFNjb3BlJiZ0eXBlb2Ygc2VsZi5pbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iO3ZhciB3PXsuLi5MQSwuLi5tSX07ZnVuY3Rpb24gSkEoQSxJKXtyZXR1cm4gTChBLG5ldyB3LmNsYXNzZXMuVVJMU2VhcmNoUGFyYW1zLE9iamVjdC5hc3NpZ24oe3Zpc2l0b3I6ZnVuY3Rpb24odCxlLGcscil7cmV0dXJuIHcuaXNOb2RlJiZCLmlzQnVmZmVyKHQpPyh0aGlzLmFwcGVuZChlLHQudG9TdHJpbmcoImJhc2U2NCIpKSwhMSk6ci5kZWZhdWx0VmlzaXRvci5hcHBseSh0aGlzLGFyZ3VtZW50cyl9fSxJKSl9ZnVuY3Rpb24gdGUoQSl7cmV0dXJuIEIubWF0Y2hBbGwoL1xcdyt8XFxbKFxcdyopXS9nLEEpLm1hcChJPT5JWzBdPT09IltdIj8iIjpJWzFdfHxJWzBdKX1mdW5jdGlvbiBlZShBKXtsZXQgST17fSx0PU9iamVjdC5rZXlzKEEpLGUsZz10Lmxlbmd0aCxyO2ZvcihlPTA7ZTxnO2UrKylyPXRbZV0sSVtyXT1BW3JdO3JldHVybiBJfWZ1bmN0aW9uIGdlKEEpe2Z1bmN0aW9uIEkodCxlLGcscil7bGV0IGk9dFtyKytdLHM9TnVtYmVyLmlzRmluaXRlKCtpKSxhPXI+PXQubGVuZ3RoO3JldHVybiBpPSFpJiZCLmlzQXJyYXkoZyk/Zy5sZW5ndGg6aSxhPyhCLmhhc093blByb3AoZyxpKT9nW2ldPVtnW2ldLGVdOmdbaV09ZSwhcyk6KCghZ1tpXXx8IUIuaXNPYmplY3QoZ1tpXSkpJiYoZ1tpXT1bXSksSSh0LGUsZ1tpXSxyKSYmQi5pc0FycmF5KGdbaV0pJiYoZ1tpXT1lZShnW2ldKSksIXMpfWlmKEIuaXNGb3JtRGF0YShBKSYmQi5pc0Z1bmN0aW9uKEEuZW50cmllcykpe2xldCB0PXt9O3JldHVybiBCLmZvckVhY2hFbnRyeShBLChlLGcpPT57SSh0ZShlKSxnLHQsMCl9KSx0fXJldHVybiBudWxsfXZhciBjQT1nZTtmdW5jdGlvbiByZShBLEksdCl7aWYoQi5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKEl8fEpTT04ucGFyc2UpKEEpLEIudHJpbShBKX1jYXRjaChlKXtpZihlLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IGV9cmV0dXJuKHR8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgSEE9e3RyYW5zaXRpb25hbDphQSxhZGFwdGVyOlsieGhyIiwiaHR0cCJdLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKEksdCl7bGV0IGU9dC5nZXRDb250ZW50VHlwZSgpfHwiIixnPWUuaW5kZXhPZigiYXBwbGljYXRpb24vanNvbiIpPi0xLHI9Qi5pc09iamVjdChJKTtpZihyJiZCLmlzSFRNTEZvcm0oSSkmJihJPW5ldyBGb3JtRGF0YShJKSksQi5pc0Zvcm1EYXRhKEkpKXJldHVybiBnJiZnP0pTT04uc3RyaW5naWZ5KGNBKEkpKTpJO2lmKEIuaXNBcnJheUJ1ZmZlcihJKXx8Qi5pc0J1ZmZlcihJKXx8Qi5pc1N0cmVhbShJKXx8Qi5pc0ZpbGUoSSl8fEIuaXNCbG9iKEkpKXJldHVybiBJO2lmKEIuaXNBcnJheUJ1ZmZlclZpZXcoSSkpcmV0dXJuIEkuYnVmZmVyO2lmKEIuaXNVUkxTZWFyY2hQYXJhbXMoSSkpcmV0dXJuIHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiwhMSksSS50b1N0cmluZygpO2xldCBzO2lmKHIpe2lmKGUuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIEpBKEksdGhpcy5mb3JtU2VyaWFsaXplcikudG9TdHJpbmcoKTtpZigocz1CLmlzRmlsZUxpc3QoSSkpfHxlLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IGE9dGhpcy5lbnYmJnRoaXMuZW52LkZvcm1EYXRhO3JldHVybiBMKHM/eyJmaWxlc1tdIjpJfTpJLGEmJm5ldyBhLHRoaXMuZm9ybVNlcmlhbGl6ZXIpfX1yZXR1cm4gcnx8Zz8odC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLHJlKEkpKTpJfV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKEkpe2xldCB0PXRoaXMudHJhbnNpdGlvbmFsfHxIQS50cmFuc2l0aW9uYWwsZT10JiZ0LmZvcmNlZEpTT05QYXJzaW5nLGc9dGhpcy5yZXNwb25zZVR5cGU9PT0ianNvbiI7aWYoSSYmQi5pc1N0cmluZyhJKSYmKGUmJiF0aGlzLnJlc3BvbnNlVHlwZXx8Zykpe2xldCBpPSEodCYmdC5zaWxlbnRKU09OUGFyc2luZykmJmc7dHJ5e3JldHVybiBKU09OLnBhcnNlKEkpfWNhdGNoKHMpe2lmKGkpdGhyb3cgcy5uYW1lPT09IlN5bnRheEVycm9yIj9sLmZyb20ocyxsLkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRoaXMucmVzcG9uc2UpOnN9fXJldHVybiBJfV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTp3LmNsYXNzZXMuRm9ybURhdGEsQmxvYjp3LmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24oSSl7cmV0dXJuIEk+PTIwMCYmSTwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoiLCJDb250ZW50LVR5cGUiOnZvaWQgMH19fTtCLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIl0sQT0+e0hBLmhlYWRlcnNbQV09e319KTt2YXIgTz1IQTt2YXIgaWU9Qi50b09iamVjdFNldChbImFnZSIsImF1dGhvcml6YXRpb24iLCJjb250ZW50LWxlbmd0aCIsImNvbnRlbnQtdHlwZSIsImV0YWciLCJleHBpcmVzIiwiZnJvbSIsImhvc3QiLCJpZi1tb2RpZmllZC1zaW5jZSIsImlmLXVubW9kaWZpZWQtc2luY2UiLCJsYXN0LW1vZGlmaWVkIiwibG9jYXRpb24iLCJtYXgtZm9yd2FyZHMiLCJwcm94eS1hdXRob3JpemF0aW9uIiwicmVmZXJlciIsInJldHJ5LWFmdGVyIiwidXNlci1hZ2VudCJdKSxTST1BPT57bGV0IEk9e30sdCxlLGc7cmV0dXJuIEEmJkEuc3BsaXQoYCUwQWApLmZvckVhY2goZnVuY3Rpb24oaSl7Zz1pLmluZGV4T2YoIjoiKSx0PWkuc3Vic3RyaW5nKDAsZykudHJpbSgpLnRvTG93ZXJDYXNlKCksZT1pLnN1YnN0cmluZyhnKzEpLnRyaW0oKSwhKCF0fHxJW3RdJiZpZVt0XSkmJih0PT09InNldC1jb29raWUiP0lbdF0/SVt0XS5wdXNoKGUpOklbdF09W2VdOklbdF09SVt0XT9JW3RdKyIsICIrZTplKX0pLEl9O3ZhciBGST1TeW1ib2woImludGVybmFscyIpO2Z1bmN0aW9uIHooQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBmQShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6Qi5pc0FycmF5KEEpP0EubWFwKGZBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gb2UoQSl7bGV0IEk9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15cXHMsOz1dKylcXHMqKD86PVxccyooW14sO10rKSk/L2csZTtmb3IoO2U9dC5leGVjKEEpOylJW2VbMV1dPWVbMl07cmV0dXJuIEl9dmFyIEJlPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhJTIzJCUmXCcqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIFlBKEEsSSx0LGUsZyl7aWYoQi5pc0Z1bmN0aW9uKGUpKXJldHVybiBlLmNhbGwodGhpcyxJLHQpO2lmKGcmJihJPXQpLCEhQi5pc1N0cmluZyhJKSl7aWYoQi5pc1N0cmluZyhlKSlyZXR1cm4gSS5pbmRleE9mKGUpIT09LTE7aWYoQi5pc1JlZ0V4cChlKSlyZXR1cm4gZS50ZXN0KEkpfX1mdW5jdGlvbiBDZShBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxcZF0pKFxcdyopL2csKEksdCxlKT0+dC50b1VwcGVyQ2FzZSgpK2UpfWZ1bmN0aW9uIHNlKEEsSSl7bGV0IHQ9Qi50b0NhbWVsQ2FzZSgiICIrSSk7WyJnZXQiLCJzZXQiLCJoYXMiXS5mb3JFYWNoKGU9PntPYmplY3QuZGVmaW5lUHJvcGVydHkoQSxlK3Qse3ZhbHVlOmZ1bmN0aW9uKGcscixpKXtyZXR1cm4gdGhpc1tlXS5jYWxsKHRoaXMsSSxnLHIsaSl9LGNvbmZpZ3VyYWJsZTohMH0pfSl9dmFyIFQ9Y2xhc3N7Y29uc3RydWN0b3IoSSl7SSYmdGhpcy5zZXQoSSl9c2V0KEksdCxlKXtsZXQgZz10aGlzO2Z1bmN0aW9uIHIocyxhLG4pe2xldCBDPXooYSk7aWYoIUMpdGhyb3cgbmV3IEVycm9yKCJoZWFkZXIgbmFtZSBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZyIpO2xldCBvPUIuZmluZEtleShnLEMpOyghb3x8Z1tvXT09PXZvaWQgMHx8bj09PSEwfHxuPT09dm9pZCAwJiZnW29dIT09ITEpJiYoZ1tvfHxhXT1mQShzKSl9bGV0IGk9KHMsYSk9PkIuZm9yRWFjaChzLChuLEMpPT5yKG4sQyxhKSk7cmV0dXJuIEIuaXNQbGFpbk9iamVjdChJKXx8SSBpbnN0YW5jZW9mIHRoaXMuY29uc3RydWN0b3I/aShJLHQpOkIuaXNTdHJpbmcoSSkmJihJPUkudHJpbSgpKSYmIUJlKEkpP2koU0koSSksdCk6SSE9bnVsbCYmcih0LEksZSksdGhpc31nZXQoSSx0KXtpZihJPXooSSksSSl7bGV0IGU9Qi5maW5kS2V5KHRoaXMsSSk7aWYoZSl7bGV0IGc9dGhpc1tlXTtpZighdClyZXR1cm4gZztpZih0PT09ITApcmV0dXJuIG9lKGcpO2lmKEIuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMsZyxlKTtpZihCLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMoZyk7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhJLHQpe2lmKEk9eihJKSxJKXtsZXQgZT1CLmZpbmRLZXkodGhpcyxJKTtyZXR1cm4hIShlJiZ0aGlzW2VdIT09dm9pZCAwJiYoIXR8fFlBKHRoaXMsdGhpc1tlXSxlLHQpKSl9cmV0dXJuITF9ZGVsZXRlKEksdCl7bGV0IGU9dGhpcyxnPSExO2Z1bmN0aW9uIHIoaSl7aWYoaT16KGkpLGkpe2xldCBzPUIuZmluZEtleShlLGkpO3MmJighdHx8WUEoZSxlW3NdLHMsdCkpJiYoZGVsZXRlIGVbc10sZz0hMCl9fXJldHVybiBCLmlzQXJyYXkoSSk/SS5mb3JFYWNoKHIpOnIoSSksZ31jbGVhcihJKXtsZXQgdD1PYmplY3Qua2V5cyh0aGlzKSxlPXQubGVuZ3RoLGc9ITE7Zm9yKDtlLS07KXtsZXQgcj10W2VdOyghSXx8WUEodGhpcyx0aGlzW3JdLHIsSSwhMCkpJiYoZGVsZXRlIHRoaXNbcl0sZz0hMCl9cmV0dXJuIGd9bm9ybWFsaXplKEkpe2xldCB0PXRoaXMsZT17fTtyZXR1cm4gQi5mb3JFYWNoKHRoaXMsKGcscik9PntsZXQgaT1CLmZpbmRLZXkoZSxyKTtpZihpKXt0W2ldPWZBKGcpLGRlbGV0ZSB0W3JdO3JldHVybn1sZXQgcz1JP0NlKHIpOlN0cmluZyhyKS50cmltKCk7cyE9PXImJmRlbGV0ZSB0W3JdLHRbc109ZkEoZyksZVtzXT0hMH0pLHRoaXN9Y29uY2F0KC4uLkkpe3JldHVybiB0aGlzLmNvbnN0cnVjdG9yLmNvbmNhdCh0aGlzLC4uLkkpfXRvSlNPTihJKXtsZXQgdD1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybiBCLmZvckVhY2godGhpcywoZSxnKT0+e2UhPW51bGwmJmUhPT0hMSYmKHRbZ109SSYmQi5pc0FycmF5KGUpP2Uuam9pbigiLCAiKTplKX0pLHR9W1N5bWJvbC5pdGVyYXRvcl0oKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSlbU3ltYm9sLml0ZXJhdG9yXSgpfXRvU3RyaW5nKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpLm1hcCgoW0ksdF0pPT5JKyI6ICIrdCkuam9pbihgJTBBYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShJKXtyZXR1cm4gSSBpbnN0YW5jZW9mIHRoaXM/STpuZXcgdGhpcyhJKX1zdGF0aWMgY29uY2F0KEksLi4udCl7bGV0IGU9bmV3IHRoaXMoSSk7cmV0dXJuIHQuZm9yRWFjaChnPT5lLnNldChnKSksZX1zdGF0aWMgYWNjZXNzb3IoSSl7bGV0IGU9KHRoaXNbRkldPXRoaXNbRkldPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsZz10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiByKGkpe2xldCBzPXooaSk7ZVtzXXx8KHNlKGcsaSksZVtzXT0hMCl9cmV0dXJuIEIuaXNBcnJheShJKT9JLmZvckVhY2gocik6cihJKSx0aGlzfX07VC5hY2Nlc3NvcihbIkNvbnRlbnQtVHlwZSIsIkNvbnRlbnQtTGVuZ3RoIiwiQWNjZXB0IiwiQWNjZXB0LUVuY29kaW5nIiwiVXNlci1BZ2VudCIsIkF1dGhvcml6YXRpb24iXSk7Qi5yZWR1Y2VEZXNjcmlwdG9ycyhULnByb3RvdHlwZSwoe3ZhbHVlOkF9LEkpPT57bGV0IHQ9SVswXS50b1VwcGVyQ2FzZSgpK0kuc2xpY2UoMSk7cmV0dXJue2dldDooKT0+QSxzZXQoZSl7dGhpc1t0XT1lfX19KTtCLmZyZWV6ZU1ldGhvZHMoVCk7dmFyIG09VDtmdW5jdGlvbiBfKEEsSSl7bGV0IHQ9dGhpc3x8TyxlPUl8fHQsZz1tLmZyb20oZS5oZWFkZXJzKSxyPWUuZGF0YTtyZXR1cm4gQi5mb3JFYWNoKEEsZnVuY3Rpb24ocyl7cj1zLmNhbGwodCxyLGcubm9ybWFsaXplKCksST9JLnN0YXR1czp2b2lkIDApfSksZy5ub3JtYWxpemUoKSxyfWZ1bmN0aW9uIHYoQSl7cmV0dXJuISEoQSYmQS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBSSShBLEksdCl7bC5jYWxsKHRoaXMsQT8/ImNhbmNlbGVkIixsLkVSUl9DQU5DRUxFRCxJLHQpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9Qi5pbmhlcml0cyhSSSxsLHtfX0NBTkNFTF9fOiEwfSk7dmFyIEo9Ukk7ZnVuY3Rpb24gYkEoQSxJLHQpe2xldCBlPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IWV8fGUodC5zdGF0dXMpP0EodCk6SShuZXcgbCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFtsLkVSUl9CQURfUkVRVUVTVCxsLkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfXZhciBOST13Lmhhc1N0YW5kYXJkQnJvd3NlckVudj97d3JpdGUoQSxJLHQsZSxnLHIpe2xldCBpPVtBKyI9IitlbmNvZGVVUklDb21wb25lbnQoSSldO0IuaXNOdW1iZXIodCkmJmkucHVzaCgiZXhwaXJlcz0iK25ldyBEYXRlKHQpLnRvR01UU3RyaW5nKCkpLEIuaXNTdHJpbmcoZSkmJmkucHVzaCgicGF0aD0iK2UpLEIuaXNTdHJpbmcoZykmJmkucHVzaCgiZG9tYWluPSIrZykscj09PSEwJiZpLnB1c2goInNlY3VyZSIpLGRvY3VtZW50LmNvb2tpZT1pLmpvaW4oIjsgIil9LHJlYWQoQSl7bGV0IEk9ZG9jdW1lbnQuY29va2llLm1hdGNoKG5ldyBSZWdFeHAoIihefDtcXFxccyopKCIrQSsiKT0oW147XSopIikpO3JldHVybiBJP2RlY29kZVVSSUNvbXBvbmVudChJWzNdKTpudWxsfSxyZW1vdmUoQSl7dGhpcy53cml0ZShBLCIiLERhdGUubm93KCktODY0ZTUpfX06e3dyaXRlKCl7fSxyZWFkKCl7cmV0dXJuIG51bGx9LHJlbW92ZSgpe319O2Z1bmN0aW9uIE1BKEEpe3JldHVybi9eKFthLXpdW2EtelxcZCtcXC0uXSo6KT9cXC9cXC8vaS50ZXN0KEEpfWZ1bmN0aW9uIHFBKEEsSSl7cmV0dXJuIEk/QS5yZXBsYWNlKC9cXC8rJC8sIiIpKyIvIitJLnJlcGxhY2UoL15cXC8rLywiIik6QX1mdW5jdGlvbiAkKEEsSSl7cmV0dXJuIEEmJiFNQShJKT9xQShBLEkpOkl9dmFyIFVJPXcuaGFzU3RhbmRhcmRCcm93c2VyRW52P2Z1bmN0aW9uKCl7bGV0IEk9Lyhtc2llfHRyaWRlbnQpL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KSx0PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKSxlO2Z1bmN0aW9uIGcocil7bGV0IGk9cjtyZXR1cm4gSSYmKHQuc2V0QXR0cmlidXRlKCJocmVmIixpKSxpPXQuaHJlZiksdC5zZXRBdHRyaWJ1dGUoImhyZWYiLGkpLHtocmVmOnQuaHJlZixwcm90b2NvbDp0LnByb3RvY29sP3QucHJvdG9jb2wucmVwbGFjZSgvOiQvLCIiKToiIixob3N0OnQuaG9zdCxzZWFyY2g6dC5zZWFyY2g/dC5zZWFyY2gucmVwbGFjZSgvXlxcPy8sIiIpOiIiLGhhc2g6dC5oYXNoP3QuaGFzaC5yZXBsYWNlKC9eJTIzLywiIik6IiIsaG9zdG5hbWU6dC5ob3N0bmFtZSxwb3J0OnQucG9ydCxwYXRobmFtZTp0LnBhdGhuYW1lLmNoYXJBdCgwKT09PSIvIj90LnBhdGhuYW1lOiIvIit0LnBhdGhuYW1lfX1yZXR1cm4gZT1nKHdpbmRvdy5sb2NhdGlvbi5ocmVmKSxmdW5jdGlvbihpKXtsZXQgcz1CLmlzU3RyaW5nKGkpP2coaSk6aTtyZXR1cm4gcy5wcm90b2NvbD09PWUucHJvdG9jb2wmJnMuaG9zdD09PWUuaG9zdH19KCk6ZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4hMH19KCk7ZnVuY3Rpb24gS0EoQSl7bGV0IEk9L14oWy0rXFx3XXsxLDI1fSkoOj9cXC9cXC98OikvLmV4ZWMoQSk7cmV0dXJuIEkmJklbMV18fCIifWZ1bmN0aW9uIFFlKEEsSSl7QT1BfHwxMDtsZXQgdD1uZXcgQXJyYXkoQSksZT1uZXcgQXJyYXkoQSksZz0wLHI9MCxpO3JldHVybiBJPUkhPT12b2lkIDA/SToxZTMsZnVuY3Rpb24oYSl7bGV0IG49RGF0ZS5ub3coKSxDPWVbcl07aXx8KGk9biksdFtnXT1hLGVbZ109bjtsZXQgbz1yLGY9MDtmb3IoO28hPT1nOylmKz10W28rK10sbz1vJUE7aWYoZz0oZysxKSVBLGc9PT1yJiYocj0ocisxKSVBKSxuLWk8SSlyZXR1cm47bGV0IFE9QyYmbi1DO3JldHVybiBRP01hdGgucm91bmQoZioxZTMvUSk6dm9pZCAwfX12YXIgR0k9UWU7ZnVuY3Rpb24ga0koQSxJKXtsZXQgdD0wLGU9R0koNTAsMjUwKTtyZXR1cm4gZz0+e2xldCByPWcubG9hZGVkLGk9Zy5sZW5ndGhDb21wdXRhYmxlP2cudG90YWw6dm9pZCAwLHM9ci10LGE9ZShzKSxuPXI8PWk7dD1yO2xldCBDPXtsb2FkZWQ6cix0b3RhbDppLHByb2dyZXNzOmk/ci9pOnZvaWQgMCxieXRlczpzLHJhdGU6YXx8dm9pZCAwLGVzdGltYXRlZDphJiZpJiZuPyhpLXIpL2E6dm9pZCAwLGV2ZW50Omd9O0NbST8iZG93bmxvYWQiOiJ1cGxvYWQiXT0hMCxBKEMpfX12YXIgbmU9dHlwZW9mIFhNTEh0dHBSZXF1ZXN0PCJ1IixMST1uZSYmZnVuY3Rpb24oQSl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHQsZSl7bGV0IGc9QS5kYXRhLHI9bS5mcm9tKEEuaGVhZGVycykubm9ybWFsaXplKCkse3Jlc3BvbnNlVHlwZTppLHdpdGhYU1JGVG9rZW46c309QSxhO2Z1bmN0aW9uIG4oKXtBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnVuc3Vic2NyaWJlKGEpLEEuc2lnbmFsJiZBLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKCJhYm9ydCIsYSl9bGV0IEM7aWYoQi5pc0Zvcm1EYXRhKGcpKXtpZih3Lmhhc1N0YW5kYXJkQnJvd3NlckVudnx8dy5oYXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnYpci5zZXRDb250ZW50VHlwZSghMSk7ZWxzZSBpZigoQz1yLmdldENvbnRlbnRUeXBlKCkpIT09ITEpe2xldFtjLC4uLnVdPUM/Qy5zcGxpdCgiOyIpLm1hcChkPT5kLnRyaW0oKSkuZmlsdGVyKEJvb2xlYW4pOltdO3Iuc2V0Q29udGVudFR5cGUoW2N8fCJtdWx0aXBhcnQvZm9ybS1kYXRhIiwuLi51XS5qb2luKCI7ICIpKX19bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IGM9QS5hdXRoLnVzZXJuYW1lfHwiIix1PUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7ci5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoYysiOiIrdSkpfWxldCBmPSQoQS5iYXNlVVJMLEEudXJsKTtvLm9wZW4oQS5tZXRob2QudG9VcHBlckNhc2UoKSxYKGYsQS5wYXJhbXMsQS5wYXJhbXNTZXJpYWxpemVyKSwhMCksby50aW1lb3V0PUEudGltZW91dDtmdW5jdGlvbiBRKCl7aWYoIW8pcmV0dXJuO2xldCBjPW0uZnJvbSgiZ2V0QWxsUmVzcG9uc2VIZWFkZXJzImluIG8mJm8uZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCkpLGQ9e2RhdGE6IWl8fGk9PT0idGV4dCJ8fGk9PT0ianNvbiI/by5yZXNwb25zZVRleHQ6by5yZXNwb25zZSxzdGF0dXM6by5zdGF0dXMsc3RhdHVzVGV4dDpvLnN0YXR1c1RleHQsaGVhZGVyczpjLGNvbmZpZzpBLHJlcXVlc3Q6b307YkEoZnVuY3Rpb24oTil7dChOKSxuKCl9LGZ1bmN0aW9uKE4pe2UoTiksbigpfSxkKSxvPW51bGx9aWYoIm9ubG9hZGVuZCJpbiBvP28ub25sb2FkZW5kPVE6by5vbnJlYWR5c3RhdGVjaGFuZ2U9ZnVuY3Rpb24oKXshb3x8by5yZWFkeVN0YXRlIT09NHx8by5zdGF0dXM9PT0wJiYhKG8ucmVzcG9uc2VVUkwmJm8ucmVzcG9uc2VVUkwuaW5kZXhPZigiZmlsZToiKT09PTApfHxzZXRUaW1lb3V0KFEpfSxvLm9uYWJvcnQ9ZnVuY3Rpb24oKXtvJiYoZShuZXcgbCgiUmVxdWVzdCBhYm9ydGVkIixsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGwpfSxvLm9uZXJyb3I9ZnVuY3Rpb24oKXtlKG5ldyBsKCJOZXR3b3JrIEVycm9yIixsLkVSUl9ORVRXT1JLLEEsbykpLG89bnVsbH0sby5vbnRpbWVvdXQ9ZnVuY3Rpb24oKXtsZXQgdT1BLnRpbWVvdXQ/InRpbWVvdXQgb2YgIitBLnRpbWVvdXQrIm1zIGV4Y2VlZGVkIjoidGltZW91dCBleGNlZWRlZCIsZD1BLnRyYW5zaXRpb25hbHx8YUE7QS50aW1lb3V0RXJyb3JNZXNzYWdlJiYodT1BLnRpbWVvdXRFcnJvck1lc3NhZ2UpLGUobmV3IGwodSxkLmNsYXJpZnlUaW1lb3V0RXJyb3I/bC5FVElNRURPVVQ6bC5FQ09OTkFCT1JURUQsQSxvKSksbz1udWxsfSx3Lmhhc1N0YW5kYXJkQnJvd3NlckVudiYmKHMmJkIuaXNGdW5jdGlvbihzKSYmKHM9cyhBKSksc3x8cyE9PSExJiZVSShmKSkpe2xldCBjPUEueHNyZkhlYWRlck5hbWUmJkEueHNyZkNvb2tpZU5hbWUmJk5JLnJlYWQoQS54c3JmQ29va2llTmFtZSk7YyYmci5zZXQoQS54c3JmSGVhZGVyTmFtZSxjKX1nPT09dm9pZCAwJiZyLnNldENvbnRlbnRUeXBlKG51bGwpLCJzZXRSZXF1ZXN0SGVhZGVyImluIG8mJkIuZm9yRWFjaChyLnRvSlNPTigpLGZ1bmN0aW9uKHUsZCl7by5zZXRSZXF1ZXN0SGVhZGVyKGQsdSl9KSxCLmlzVW5kZWZpbmVkKEEud2l0aENyZWRlbnRpYWxzKXx8KG8ud2l0aENyZWRlbnRpYWxzPSEhQS53aXRoQ3JlZGVudGlhbHMpLGkmJmkhPT0ianNvbiImJihvLnJlc3BvbnNlVHlwZT1BLnJlc3BvbnNlVHlwZSksdHlwZW9mIEEub25Eb3dubG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZvLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixrSShBLm9uRG93bmxvYWRQcm9ncmVzcywhMCkpLHR5cGVvZiBBLm9uVXBsb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJm8udXBsb2FkJiZvLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsa0koQS5vblVwbG9hZFByb2dyZXNzKSksKEEuY2FuY2VsVG9rZW58fEEuc2lnbmFsKSYmKGE9Yz0+e28mJihlKCFjfHxjLnR5cGU/bmV3IEoobnVsbCxBLG8pOmMpLG8uYWJvcnQoKSxvPW51bGwpfSxBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnN1YnNjcmliZShhKSxBLnNpZ25hbCYmKEEuc2lnbmFsLmFib3J0ZWQ/YSgpOkEuc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixhKSkpO2xldCBFPUtBKGYpO2lmKEUmJncucHJvdG9jb2xzLmluZGV4T2YoRSk9PT0tMSl7ZShuZXcgbCgiVW5zdXBwb3J0ZWQgcHJvdG9jb2wgIitFKyI6IixsLkVSUl9CQURfUkVRVUVTVCxBKSk7cmV0dXJufW8uc2VuZChnfHxudWxsKX0pfTt2YXIgT0E9e2h0dHA6bkEseGhyOkxJfTtCLmZvckVhY2goT0EsKEEsSSk9PntpZihBKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsIm5hbWUiLHt2YWx1ZTpJfSl9Y2F0Y2h7fU9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJhZGFwdGVyTmFtZSIse3ZhbHVlOkl9KX19KTt2YXIgSkk9QT0+YC0gJHtBfWAsRWU9QT0+Qi5pc0Z1bmN0aW9uKEEpfHxBPT09bnVsbHx8QT09PSExLGxBPXtnZXRBZGFwdGVyOkE9PntBPUIuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOkl9PUEsdCxlLGc9e307Zm9yKGxldCByPTA7cjxJO3IrKyl7dD1BW3JdO2xldCBpO2lmKGU9dCwhRWUodCkmJihlPU9BWyhpPVN0cmluZyh0KSkudG9Mb3dlckNhc2UoKV0sZT09PXZvaWQgMCkpdGhyb3cgbmV3IGwoYFVua25vd24gYWRhcHRlciBcJyR7aX1cJ2ApO2lmKGUpYnJlYWs7Z1tpfHwiJTIzIityXT1lfWlmKCFlKXtsZXQgcj1PYmplY3QuZW50cmllcyhnKS5tYXAoKFtzLGFdKT0+YGFkYXB0ZXIgJHtzfSBgKyhhPT09ITE/ImlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50IjoiaXMgbm90IGF2YWlsYWJsZSBpbiB0aGUgYnVpbGQiKSksaT1JP3IubGVuZ3RoPjE/YHNpbmNlIDolMEFgK3IubWFwKEpJKS5qb2luKGAlMEFgKToiICIrSkkoclswXSk6ImFzIG5vIGFkYXB0ZXIgc3BlY2lmaWVkIjt0aHJvdyBuZXcgbCgiVGhlcmUgaXMgbm8gc3VpdGFibGUgYWRhcHRlciB0byBkaXNwYXRjaCB0aGUgcmVxdWVzdCAiK2ksIkVSUl9OT1RfU1VQUE9SVCIpfXJldHVybiBlfSxhZGFwdGVyczpPQX07ZnVuY3Rpb24gVEEoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IEoobnVsbCxBKX1mdW5jdGlvbiBEQShBKXtyZXR1cm4gVEEoQSksQS5oZWFkZXJzPW0uZnJvbShBLmhlYWRlcnMpLEEuZGF0YT1fLmNhbGwoQSxBLnRyYW5zZm9ybVJlcXVlc3QpLFsicG9zdCIsInB1dCIsInBhdGNoIl0uaW5kZXhPZihBLm1ldGhvZCkhPT0tMSYmQS5oZWFkZXJzLnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiLCExKSxsQS5nZXRBZGFwdGVyKEEuYWRhcHRlcnx8Ty5hZGFwdGVyKShBKS50aGVuKGZ1bmN0aW9uKGUpe3JldHVybiBUQShBKSxlLmRhdGE9Xy5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxlKSxlLmhlYWRlcnM9bS5mcm9tKGUuaGVhZGVycyksZX0sZnVuY3Rpb24oZSl7cmV0dXJuIHYoZSl8fChUQShBKSxlJiZlLnJlc3BvbnNlJiYoZS5yZXNwb25zZS5kYXRhPV8uY2FsbChBLEEudHJhbnNmb3JtUmVzcG9uc2UsZS5yZXNwb25zZSksZS5yZXNwb25zZS5oZWFkZXJzPW0uZnJvbShlLnJlc3BvbnNlLmhlYWRlcnMpKSksUHJvbWlzZS5yZWplY3QoZSl9KX12YXIgSEk9QT0+QSBpbnN0YW5jZW9mIG0/QS50b0pTT04oKTpBO2Z1bmN0aW9uIEcoQSxJKXtJPUl8fHt9O2xldCB0PXt9O2Z1bmN0aW9uIGUobixDLG8pe3JldHVybiBCLmlzUGxhaW5PYmplY3QobikmJkIuaXNQbGFpbk9iamVjdChDKT9CLm1lcmdlLmNhbGwoe2Nhc2VsZXNzOm99LG4sQyk6Qi5pc1BsYWluT2JqZWN0KEMpP0IubWVyZ2Uoe30sQyk6Qi5pc0FycmF5KEMpP0Muc2xpY2UoKTpDfWZ1bmN0aW9uIGcobixDLG8pe2lmKEIuaXNVbmRlZmluZWQoQykpe2lmKCFCLmlzVW5kZWZpbmVkKG4pKXJldHVybiBlKHZvaWQgMCxuLG8pfWVsc2UgcmV0dXJuIGUobixDLG8pfWZ1bmN0aW9uIHIobixDKXtpZighQi5pc1VuZGVmaW5lZChDKSlyZXR1cm4gZSh2b2lkIDAsQyl9ZnVuY3Rpb24gaShuLEMpe2lmKEIuaXNVbmRlZmluZWQoQykpe2lmKCFCLmlzVW5kZWZpbmVkKG4pKXJldHVybiBlKHZvaWQgMCxuKX1lbHNlIHJldHVybiBlKHZvaWQgMCxDKX1mdW5jdGlvbiBzKG4sQyxvKXtpZihvIGluIEkpcmV0dXJuIGUobixDKTtpZihvIGluIEEpcmV0dXJuIGUodm9pZCAwLG4pfWxldCBhPXt1cmw6cixtZXRob2Q6cixkYXRhOnIsYmFzZVVSTDppLHRyYW5zZm9ybVJlcXVlc3Q6aSx0cmFuc2Zvcm1SZXNwb25zZTppLHBhcmFtc1NlcmlhbGl6ZXI6aSx0aW1lb3V0OmksdGltZW91dE1lc3NhZ2U6aSx3aXRoQ3JlZGVudGlhbHM6aSx3aXRoWFNSRlRva2VuOmksYWRhcHRlcjppLHJlc3BvbnNlVHlwZTppLHhzcmZDb29raWVOYW1lOmkseHNyZkhlYWRlck5hbWU6aSxvblVwbG9hZFByb2dyZXNzOmksb25Eb3dubG9hZFByb2dyZXNzOmksZGVjb21wcmVzczppLG1heENvbnRlbnRMZW5ndGg6aSxtYXhCb2R5TGVuZ3RoOmksYmVmb3JlUmVkaXJlY3Q6aSx0cmFuc3BvcnQ6aSxodHRwQWdlbnQ6aSxodHRwc0FnZW50OmksY2FuY2VsVG9rZW46aSxzb2NrZXRQYXRoOmkscmVzcG9uc2VFbmNvZGluZzppLHZhbGlkYXRlU3RhdHVzOnMsaGVhZGVyczoobixDKT0+ZyhISShuKSxISShDKSwhMCl9O3JldHVybiBCLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLEkpKSxmdW5jdGlvbihDKXtsZXQgbz1hW0NdfHxnLGY9byhBW0NdLElbQ10sQyk7Qi5pc1VuZGVmaW5lZChmKSYmbyE9PXN8fCh0W0NdPWYpfSksdH12YXIgdUE9IjEuNi4yIjt2YXIgeEE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLEkpPT57eEFbQV09ZnVuY3Rpb24oZSl7cmV0dXJuIHR5cGVvZiBlPT09QXx8ImEiKyhJPDE/Im4gIjoiICIpK0F9fSk7dmFyIFlJPXt9O3hBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihJLHQsZSl7ZnVuY3Rpb24gZyhyLGkpe3JldHVybiJbQXhpb3MgdiIrdUErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiBcJyIrcisiXCciK2krKGU/Ii4gIitlOiIiKX1yZXR1cm4ocixpLHMpPT57aWYoST09PSExKXRocm93IG5ldyBsKGcoaSwiIGhhcyBiZWVuIHJlbW92ZWQiKyh0PyIgaW4gIit0OiIiKSksbC5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIHQmJiFZSVtpXSYmKFlJW2ldPSEwLGNvbnNvbGUud2FybihnKGksIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksST9JKHIsaSxzKTohMH19O2Z1bmN0aW9uIGFlKEEsSSx0KXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IGwoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLGwuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBlPU9iamVjdC5rZXlzKEEpLGc9ZS5sZW5ndGg7Zm9yKDtnLS0gPjA7KXtsZXQgcj1lW2ddLGk9SVtyXTtpZihpKXtsZXQgcz1BW3JdLGE9cz09PXZvaWQgMHx8aShzLHIsQSk7aWYoYSE9PSEwKXRocm93IG5ldyBsKCJvcHRpb24gIityKyIgbXVzdCBiZSAiK2EsbC5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYodCE9PSEwKXRocm93IG5ldyBsKCJVbmtub3duIG9wdGlvbiAiK3IsbC5FUlJfQkFEX09QVElPTil9fXZhciBoQT17YXNzZXJ0T3B0aW9uczphZSx2YWxpZGF0b3JzOnhBfTt2YXIgSD1oQS52YWxpZGF0b3JzLHg9Y2xhc3N7Y29uc3RydWN0b3IoSSl7dGhpcy5kZWZhdWx0cz1JLHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBrQSxyZXNwb25zZTpuZXcga0F9fXJlcXVlc3QoSSx0KXt0eXBlb2YgST09InN0cmluZyI/KHQ9dHx8e30sdC51cmw9SSk6dD1JfHx7fSx0PUcodGhpcy5kZWZhdWx0cyx0KTtsZXR7dHJhbnNpdGlvbmFsOmUscGFyYW1zU2VyaWFsaXplcjpnLGhlYWRlcnM6cn09dDtlIT09dm9pZCAwJiZoQS5hc3NlcnRPcHRpb25zKGUse3NpbGVudEpTT05QYXJzaW5nOkgudHJhbnNpdGlvbmFsKEguYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6SC50cmFuc2l0aW9uYWwoSC5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOkgudHJhbnNpdGlvbmFsKEguYm9vbGVhbil9LCExKSxnIT1udWxsJiYoQi5pc0Z1bmN0aW9uKGcpP3QucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOmd9OmhBLmFzc2VydE9wdGlvbnMoZyx7ZW5jb2RlOkguZnVuY3Rpb24sc2VyaWFsaXplOkguZnVuY3Rpb259LCEwKSksdC5tZXRob2Q9KHQubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGk9ciYmQi5tZXJnZShyLmNvbW1vbixyW3QubWV0aG9kXSk7ciYmQi5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCIsImNvbW1vbiJdLEU9PntkZWxldGUgcltFXX0pLHQuaGVhZGVycz1tLmNvbmNhdChpLHIpO2xldCBzPVtdLGE9ITA7dGhpcy5pbnRlcmNlcHRvcnMucmVxdWVzdC5mb3JFYWNoKGZ1bmN0aW9uKGMpe3R5cGVvZiBjLnJ1bldoZW49PSJmdW5jdGlvbiImJmMucnVuV2hlbih0KT09PSExfHwoYT1hJiZjLnN5bmNocm9ub3VzLHMudW5zaGlmdChjLmZ1bGZpbGxlZCxjLnJlamVjdGVkKSl9KTtsZXQgbj1bXTt0aGlzLmludGVyY2VwdG9ycy5yZXNwb25zZS5mb3JFYWNoKGZ1bmN0aW9uKGMpe24ucHVzaChjLmZ1bGZpbGxlZCxjLnJlamVjdGVkKX0pO2xldCBDLG89MCxmO2lmKCFhKXtsZXQgRT1bREEuYmluZCh0aGlzKSx2b2lkIDBdO2ZvcihFLnVuc2hpZnQuYXBwbHkoRSxzKSxFLnB1c2guYXBwbHkoRSxuKSxmPUUubGVuZ3RoLEM9UHJvbWlzZS5yZXNvbHZlKHQpO288ZjspQz1DLnRoZW4oRVtvKytdLEVbbysrXSk7cmV0dXJuIEN9Zj1zLmxlbmd0aDtsZXQgUT10O2ZvcihvPTA7bzxmOyl7bGV0IEU9c1tvKytdLGM9c1tvKytdO3RyeXtRPUUoUSl9Y2F0Y2godSl7Yy5jYWxsKHRoaXMsdSk7YnJlYWt9fXRyeXtDPURBLmNhbGwodGhpcyxRKX1jYXRjaChFKXtyZXR1cm4gUHJvbWlzZS5yZWplY3QoRSl9Zm9yKG89MCxmPW4ubGVuZ3RoO288ZjspQz1DLnRoZW4obltvKytdLG5bbysrXSk7cmV0dXJuIEN9Z2V0VXJpKEkpe0k9Ryh0aGlzLmRlZmF1bHRzLEkpO2xldCB0PSQoSS5iYXNlVVJMLEkudXJsKTtyZXR1cm4gWCh0LEkucGFyYW1zLEkucGFyYW1zU2VyaWFsaXplcil9fTtCLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKEkpe3gucHJvdG90eXBlW0ldPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMucmVxdWVzdChHKGV8fHt9LHttZXRob2Q6SSx1cmw6dCxkYXRhOihlfHx7fSkuZGF0YX0pKX19KTtCLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbihJKXtmdW5jdGlvbiB0KGUpe3JldHVybiBmdW5jdGlvbihyLGkscyl7cmV0dXJuIHRoaXMucmVxdWVzdChHKHN8fHt9LHttZXRob2Q6SSxoZWFkZXJzOmU/eyJDb250ZW50LVR5cGUiOiJtdWx0aXBhcnQvZm9ybS1kYXRhIn06e30sdXJsOnIsZGF0YTppfSkpfX14LnByb3RvdHlwZVtJXT10KCkseC5wcm90b3R5cGVbSSsiRm9ybSJdPXQoITApfSk7dmFyIEFBPXg7dmFyIFBBPWNsYXNzIEF7Y29uc3RydWN0b3IoSSl7aWYodHlwZW9mIEkhPSJmdW5jdGlvbiIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXhlY3V0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uLiIpO2xldCB0O3RoaXMucHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihyKXt0PXJ9KTtsZXQgZT10aGlzO3RoaXMucHJvbWlzZS50aGVuKGc9PntpZighZS5fbGlzdGVuZXJzKXJldHVybjtsZXQgcj1lLl9saXN0ZW5lcnMubGVuZ3RoO2Zvcig7ci0tID4wOyllLl9saXN0ZW5lcnNbcl0oZyk7ZS5fbGlzdGVuZXJzPW51bGx9KSx0aGlzLnByb21pc2UudGhlbj1nPT57bGV0IHIsaT1uZXcgUHJvbWlzZShzPT57ZS5zdWJzY3JpYmUocykscj1zfSkudGhlbihnKTtyZXR1cm4gaS5jYW5jZWw9ZnVuY3Rpb24oKXtlLnVuc3Vic2NyaWJlKHIpfSxpfSxJKGZ1bmN0aW9uKHIsaSxzKXtlLnJlYXNvbnx8KGUucmVhc29uPW5ldyBKKHIsaSxzKSx0KGUucmVhc29uKSl9KX10aHJvd0lmUmVxdWVzdGVkKCl7aWYodGhpcy5yZWFzb24pdGhyb3cgdGhpcy5yZWFzb259c3Vic2NyaWJlKEkpe2lmKHRoaXMucmVhc29uKXtJKHRoaXMucmVhc29uKTtyZXR1cm59dGhpcy5fbGlzdGVuZXJzP3RoaXMuX2xpc3RlbmVycy5wdXNoKEkpOnRoaXMuX2xpc3RlbmVycz1bSV19dW5zdWJzY3JpYmUoSSl7aWYoIXRoaXMuX2xpc3RlbmVycylyZXR1cm47bGV0IHQ9dGhpcy5fbGlzdGVuZXJzLmluZGV4T2YoSSk7dCE9PS0xJiZ0aGlzLl9saXN0ZW5lcnMuc3BsaWNlKHQsMSl9c3RhdGljIHNvdXJjZSgpe2xldCBJO3JldHVybnt0b2tlbjpuZXcgQShmdW5jdGlvbihnKXtJPWd9KSxjYW5jZWw6SX19fSxiST1QQTtmdW5jdGlvbiBqQShBKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIEEuYXBwbHkobnVsbCx0KX19ZnVuY3Rpb24gV0EoQSl7cmV0dXJuIEIuaXNPYmplY3QoQSkmJkEuaXNBeGlvc0Vycm9yPT09ITB9dmFyIFpBPXtDb250aW51ZToxMDAsU3dpdGNoaW5nUHJvdG9jb2xzOjEwMSxQcm9jZXNzaW5nOjEwMixFYXJseUhpbnRzOjEwMyxPazoyMDAsQ3JlYXRlZDoyMDEsQWNjZXB0ZWQ6MjAyLE5vbkF1dGhvcml0YXRpdmVJbmZvcm1hdGlvbjoyMDMsTm9Db250ZW50OjIwNCxSZXNldENvbnRlbnQ6MjA1LFBhcnRpYWxDb250ZW50OjIwNixNdWx0aVN0YXR1czoyMDcsQWxyZWFkeVJlcG9ydGVkOjIwOCxJbVVzZWQ6MjI2LE11bHRpcGxlQ2hvaWNlczozMDAsTW92ZWRQZXJtYW5lbnRseTozMDEsRm91bmQ6MzAyLFNlZU90aGVyOjMwMyxOb3RNb2RpZmllZDozMDQsVXNlUHJveHk6MzA1LFVudXNlZDozMDYsVGVtcG9yYXJ5UmVkaXJlY3Q6MzA3LFBlcm1hbmVudFJlZGlyZWN0OjMwOCxCYWRSZXF1ZXN0OjQwMCxVbmF1dGhvcml6ZWQ6NDAxLFBheW1lbnRSZXF1aXJlZDo0MDIsRm9yYmlkZGVuOjQwMyxOb3RGb3VuZDo0MDQsTWV0aG9kTm90QWxsb3dlZDo0MDUsTm90QWNjZXB0YWJsZTo0MDYsUHJveHlBdXRoZW50aWNhdGlvblJlcXVpcmVkOjQwNyxSZXF1ZXN0VGltZW91dDo0MDgsQ29uZmxpY3Q6NDA5LEdvbmU6NDEwLExlbmd0aFJlcXVpcmVkOjQxMSxQcmVjb25kaXRpb25GYWlsZWQ6NDEyLFBheWxvYWRUb29MYXJnZTo0MTMsVXJpVG9vTG9uZzo0MTQsVW5zdXBwb3J0ZWRNZWRpYVR5cGU6NDE1LFJhbmdlTm90U2F0aXNmaWFibGU6NDE2LEV4cGVjdGF0aW9uRmFpbGVkOjQxNyxJbUFUZWFwb3Q6NDE4LE1pc2RpcmVjdGVkUmVxdWVzdDo0MjEsVW5wcm9jZXNzYWJsZUVudGl0eTo0MjIsTG9ja2VkOjQyMyxGYWlsZWREZXBlbmRlbmN5OjQyNCxUb29FYXJseTo0MjUsVXBncmFkZVJlcXVpcmVkOjQyNixQcmVjb25kaXRpb25SZXF1aXJlZDo0MjgsVG9vTWFueVJlcXVlc3RzOjQyOSxSZXF1ZXN0SGVhZGVyRmllbGRzVG9vTGFyZ2U6NDMxLFVuYXZhaWxhYmxlRm9yTGVnYWxSZWFzb25zOjQ1MSxJbnRlcm5hbFNlcnZlckVycm9yOjUwMCxOb3RJbXBsZW1lbnRlZDo1MDEsQmFkR2F0ZXdheTo1MDIsU2VydmljZVVuYXZhaWxhYmxlOjUwMyxHYXRld2F5VGltZW91dDo1MDQsSHR0cFZlcnNpb25Ob3RTdXBwb3J0ZWQ6NTA1LFZhcmlhbnRBbHNvTmVnb3RpYXRlczo1MDYsSW5zdWZmaWNpZW50U3RvcmFnZTo1MDcsTG9vcERldGVjdGVkOjUwOCxOb3RFeHRlbmRlZDo1MTAsTmV0d29ya0F1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NTExfTtPYmplY3QuZW50cmllcyhaQSkuZm9yRWFjaCgoW0EsSV0pPT57WkFbSV09QX0pO3ZhciBNST1aQTtmdW5jdGlvbiBxSShBKXtsZXQgST1uZXcgQUEoQSksdD1XKEFBLnByb3RvdHlwZS5yZXF1ZXN0LEkpO3JldHVybiBCLmV4dGVuZCh0LEFBLnByb3RvdHlwZSxJLHthbGxPd25LZXlzOiEwfSksQi5leHRlbmQodCxJLG51bGwse2FsbE93bktleXM6ITB9KSx0LmNyZWF0ZT1mdW5jdGlvbihnKXtyZXR1cm4gcUkoRyhBLGcpKX0sdH12YXIgaD1xSShPKTtoLkF4aW9zPUFBO2guQ2FuY2VsZWRFcnJvcj1KO2guQ2FuY2VsVG9rZW49Ykk7aC5pc0NhbmNlbD12O2guVkVSU0lPTj11QTtoLnRvRm9ybURhdGE9TDtoLkF4aW9zRXJyb3I9bDtoLkNhbmNlbD1oLkNhbmNlbGVkRXJyb3I7aC5hbGw9ZnVuY3Rpb24oSSl7cmV0dXJuIFByb21pc2UuYWxsKEkpfTtoLnNwcmVhZD1qQTtoLmlzQXhpb3NFcnJvcj1XQTtoLm1lcmdlQ29uZmlnPUc7aC5BeGlvc0hlYWRlcnM9bTtoLmZvcm1Ub0pTT049QT0+Y0EoQi5pc0hUTUxGb3JtKEEpP25ldyBGb3JtRGF0YShBKTpBKTtoLmdldEFkYXB0ZXI9bEEuZ2V0QWRhcHRlcjtoLkh0dHBTdGF0dXNDb2RlPU1JO2guZGVmYXVsdD1oO3ZhciBkQT1oO3ZhcntBeGlvczpvaSxBeGlvc0Vycm9yOkJpLENhbmNlbGVkRXJyb3I6Q2ksaXNDYW5jZWw6c2ksQ2FuY2VsVG9rZW46UWksVkVSU0lPTjpuaSxhbGw6RWksQ2FuY2VsOmFpLGlzQXhpb3NFcnJvcjpjaSxzcHJlYWQ6ZmksdG9Gb3JtRGF0YTpsaSxBeGlvc0hlYWRlcnM6RGksSHR0cFN0YXR1c0NvZGU6dWksZm9ybVRvSlNPTjpoaSxnZXRBZGFwdGVyOmRpLG1lcmdlQ29uZmlnOnlpfT1kQTt2YXIgSUEsayxYQSxWQT17ZW52OntlbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoOmZ1bmN0aW9uKEEpe1hBPW5ldyBVaW50OEFycmF5KGsuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKX19fSx5QT1jbGFzc3tpbml0KCl7cmV0dXJuIElBfHwodHlwZW9mIGZldGNoPCJ1Ij9JQT1mZXRjaCgiZGF0YTphcHBsaWNhdGlvbi93YXNtO2Jhc2U2NCwiK0tJKS50aGVuKEk9PkkuYXJyYXlCdWZmZXIoKSkudGhlbihJPT5XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShJLFZBKSkudGhlbih0aGlzLl9pbml0KTpJQT1XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShCdWZmZXIuZnJvbShLSSwiYmFzZTY0IiksVkEpLnRoZW4odGhpcy5faW5pdCksSUEpfV9pbml0KEkpe2s9SS5pbnN0YW5jZSxWQS5lbnYuZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aCgwKX1kZWNvZGUoSSx0PTApe2lmKCFrKXRocm93IG5ldyBFcnJvcigiWlNURERlY29kZXI6IEF3YWl0IC5pbml0KCkgYmVmb3JlIGRlY29kaW5nLiIpO2xldCBlPUkuYnl0ZUxlbmd0aCxnPWsuZXhwb3J0cy5tYWxsb2MoZSk7WEEuc2V0KEksZyksdD10fHxOdW1iZXIoay5leHBvcnRzLlpTVERfZmluZERlY29tcHJlc3NlZFNpemUoZyxlKSk7bGV0IHI9ay5leHBvcnRzLm1hbGxvYyh0KSxpPWsuZXhwb3J0cy5aU1REX2RlY29tcHJlc3Mocix0LGcsZSkscz1YQS5zbGljZShyLHIraSk7cmV0dXJuIGsuZXhwb3J0cy5mcmVlKGcpLGsuZXhwb3J0cy5mcmVlKHIpLHN9fSxLST0iQUdGemJRRUFBQUFCYmc1Z0EzOS9md0YvWUFGL0FYOWdBbjkvQUdBQmZ3QmdCWDkvZjM5L0FYOWdBMzkvZndCZ0JIOS9mMzhCZjJBQUFYOWdBbjkvQVg5Z0IzOS9mMzkvZjM4QmYyQUNmMzhCZm1BSWYzOS9mMzkvZjM4QmYyQUZmMzkvZjM4QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndGL0FpY0JBMlZ1ZGg5bGJYTmpjbWx3ZEdWdVgyNXZkR2xtZVY5dFpXMXZjbmxmWjNKdmQzUm9BQU1ESXlJSEFBQUJBUU1IQXdFQUNRUUFCUUVJQ0FFRkJnUUVCQU1HQUFBS0FBVUxEQTBHQkFVQmNBRUJBUVVIQVFHQUFvQ0FBZ1lJQVg4QlFZQ2pCQXNIcmdFTEJtMWxiVzl5ZVFJQUJtMWhiR3h2WXdBRkJHWnlaV1VBQmd4YVUxUkVYMmx6UlhKeWIzSUFFaGxhVTFSRVgyWnBibVJFWldOdmJYQnlaWE56WldSVGFYcGxBQndQV2xOVVJGOWtaV052YlhCeVpYTnpBQ0laWDE5cGJtUnBjbVZqZEY5bWRXNWpkR2x2Ymw5MFlXSnNaUUVBRUY5ZlpYSnlibTlmYkc5allYUnBiMjRBQVFsemRHRmphMU5oZG1VQUJ3eHpkR0ZqYTFKbGMzUnZjbVVBQ0FwemRHRmphMEZzYkc5akFBa0tpL0lCSWdVQVFZUWZDek1CQVg4Z0FnUkFJQUFoQXdOQUlBTWdBUzBBQURvQUFDQURRUUZxSVFNZ0FVRUJhaUVCSUFKQkFXc2lBZzBBQ3dzZ0FBc3BBUUYvSUFJRVFDQUFJUU1EUUNBRElBRTZBQUFnQTBFQmFpRURJQUpCQVdzaUFnMEFDd3NnQUF0c0FRSi9RWUFmS0FJQUlnRWdBRUVIYWtGNGNTSUNhaUVBQWtBZ0FrRUFJQUFnQVUwYkRRQWdBRDhBUVJCMFN3UkFJQUEvQUVFUWRHdEIvLzhEYWtFUWRrQUFRWDlHQkg5QkFBVkJBQkFBUVFFTFJRMEJDMEdBSHlBQU5nSUFJQUVQQzBHRUgwRXdOZ0lBUVg4THVTY0JDMzhqQUVFUWF5SUtKQUFDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBSUFCQjlBRk5CRUJCaUI4b0FnQWlCa0VRSUFCQkMycEJlSEVnQUVFTFNSc2lCVUVEZGlJQWRpSUJRUU54QkVBQ1FDQUJRWDl6UVFGeElBQnFJZ0pCQTNRaUFVR3dIMm9pQUNBQlFiZ2ZhaWdDQUNJQktBSUlJZ1JHQkVCQmlCOGdCa0YrSUFKM2NUWUNBQXdCQ3lBRUlBQTJBZ3dnQUNBRU5nSUlDeUFCUVFocUlRQWdBU0FDUVFOMElnSkJBM0kyQWdRZ0FTQUNhaUlCSUFFb0FnUkJBWEkyQWdRTUR3c2dCVUdRSHlnQ0FDSUhUUTBCSUFFRVFBSkFRUUlnQUhRaUFrRUFJQUpyY2lBQklBQjBjV2dpQVVFRGRDSUFRYkFmYWlJQ0lBQkJ1QjlxS0FJQUlnQW9BZ2dpQkVZRVFFR0lIeUFHUVg0Z0FYZHhJZ1kyQWdBTUFRc2dCQ0FDTmdJTUlBSWdCRFlDQ0FzZ0FDQUZRUU55TmdJRUlBQWdCV29pQ0NBQlFRTjBJZ0VnQldzaUJFRUJjallDQkNBQUlBRnFJQVEyQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUZCbkI4b0FnQWhBZ0ovSUFaQkFTQUhRUU4yZENJRGNVVUVRRUdJSHlBRElBWnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEF5QUJJQUkyQWdnZ0F5QUNOZ0lNSUFJZ0FUWUNEQ0FDSUFNMkFnZ0xJQUJCQ0dvaEFFR2NIeUFJTmdJQVFaQWZJQVEyQWdBTUR3dEJqQjhvQWdBaUMwVU5BU0FMYUVFQ2RFRzRJV29vQWdBaUFpZ0NCRUY0Y1NBRmF5RURJQUloQVFOQUFrQWdBU2dDRUNJQVJRUkFJQUVvQWhRaUFFVU5BUXNnQUNnQ0JFRjRjU0FGYXlJQklBTWdBU0FEU1NJQkd5RURJQUFnQWlBQkd5RUNJQUFoQVF3QkN3c2dBaWdDR0NFSklBSWdBaWdDRENJRVJ3UkFRWmdmS0FJQUdpQUNLQUlJSWdBZ0JEWUNEQ0FFSUFBMkFnZ01EZ3NnQWtFVWFpSUJLQUlBSWdCRkJFQWdBaWdDRUNJQVJRMERJQUpCRUdvaEFRc0RRQ0FCSVFnZ0FDSUVRUlJxSWdFb0FnQWlBQTBBSUFSQkVHb2hBU0FFS0FJUUlnQU5BQXNnQ0VFQU5nSUFEQTBMUVg4aEJTQUFRYjkvU3cwQUlBQkJDMm9pQUVGNGNTRUZRWXdmS0FJQUlnaEZEUUJCQUNBRmF5RURBa0FDUUFKQUFuOUJBQ0FGUVlBQ1NRMEFHa0VmSUFWQi8vLy9CMHNOQUJvZ0JVRW1JQUJCQ0habklnQnJka0VCY1NBQVFRRjBhMEUrYWdzaUIwRUNkRUc0SVdvb0FnQWlBVVVFUUVFQUlRQU1BUXRCQUNFQUlBVkJHU0FIUVFGMmEwRUFJQWRCSDBjYmRDRUNBMEFDUUNBQktBSUVRWGh4SUFWcklnWWdBMDhOQUNBQklRUWdCaUlERFFCQkFDRURJQUVoQUF3REN5QUFJQUVvQWhRaUJpQUdJQUVnQWtFZGRrRUVjV29vQWhBaUFVWWJJQUFnQmhzaEFDQUNRUUYwSVFJZ0FRMEFDd3NnQUNBRWNrVUVRRUVBSVFSQkFpQUhkQ0lBUVFBZ0FHdHlJQWh4SWdCRkRRTWdBR2hCQW5SQnVDRnFLQUlBSVFBTElBQkZEUUVMQTBBZ0FDZ0NCRUY0Y1NBRmF5SUNJQU5KSVFFZ0FpQURJQUViSVFNZ0FDQUVJQUViSVFRZ0FDZ0NFQ0lCQkg4Z0FRVWdBQ2dDRkFzaUFBMEFDd3NnQkVVTkFDQURRWkFmS0FJQUlBVnJUdzBBSUFRb0FoZ2hCeUFFSUFRb0Fnd2lBa2NFUUVHWUh5Z0NBQm9nQkNnQ0NDSUFJQUkyQWd3Z0FpQUFOZ0lJREF3TElBUkJGR29pQVNnQ0FDSUFSUVJBSUFRb0FoQWlBRVVOQXlBRVFSQnFJUUVMQTBBZ0FTRUdJQUFpQWtFVWFpSUJLQUlBSWdBTkFDQUNRUkJxSVFFZ0FpZ0NFQ0lBRFFBTElBWkJBRFlDQUF3TEN5QUZRWkFmS0FJQUlnUk5CRUJCbkI4b0FnQWhBQUpBSUFRZ0JXc2lBVUVRVHdSQUlBQWdCV29pQWlBQlFRRnlOZ0lFSUFBZ0JHb2dBVFlDQUNBQUlBVkJBM0kyQWdRTUFRc2dBQ0FFUVFOeU5nSUVJQUFnQkdvaUFTQUJLQUlFUVFGeU5nSUVRUUFoQWtFQUlRRUxRWkFmSUFFMkFnQkJuQjhnQWpZQ0FDQUFRUWhxSVFBTURRc2dCVUdVSHlnQ0FDSUNTUVJBUVpRZklBSWdCV3NpQVRZQ0FFR2dIMEdnSHlnQ0FDSUFJQVZxSWdJMkFnQWdBaUFCUVFGeU5nSUVJQUFnQlVFRGNqWUNCQ0FBUVFocUlRQU1EUXRCQUNFQUlBVkJMMm9pQXdKL1FlQWlLQUlBQkVCQjZDSW9BZ0FNQVF0QjdDSkNmemNDQUVIa0lrS0FvSUNBZ0lBRU53SUFRZUFpSUFwQkRHcEJjSEZCMktyVnFnVnpOZ0lBUWZRaVFRQTJBZ0JCeENKQkFEWUNBRUdBSUFzaUFXb2lCa0VBSUFGcklnaHhJZ0VnQlUwTkRFSEFJaWdDQUNJRUJFQkJ1Q0lvQWdBaUJ5QUJhaUlKSUFkTklBUWdDVWx5RFEwTEFrQkJ4Q0l0QUFCQkJIRkZCRUFDUUFKQUFrQUNRRUdnSHlnQ0FDSUVCRUJCeUNJaEFBTkFJQVFnQUNnQ0FDSUhUd1JBSUFjZ0FDZ0NCR29nQkVzTkF3c2dBQ2dDQ0NJQURRQUxDMEVBRUFRaUFrRi9SZzBESUFFaEJrSGtJaWdDQUNJQVFRRnJJZ1FnQW5FRVFDQUJJQUpySUFJZ0JHcEJBQ0FBYTNGcUlRWUxJQVVnQms4TkEwSEFJaWdDQUNJQUJFQkJ1Q0lvQWdBaUJDQUdhaUlJSUFSTklBQWdDRWx5RFFRTElBWVFCQ0lBSUFKSERRRU1CUXNnQmlBQ2F5QUljU0lHRUFRaUFpQUFLQUlBSUFBb0FnUnFSZzBCSUFJaEFBc2dBRUYvUmcwQklBVkJNR29nQmswRVFDQUFJUUlNQkF0QjZDSW9BZ0FpQWlBRElBWnJha0VBSUFKcmNTSUNFQVJCZjBZTkFTQUNJQVpxSVFZZ0FDRUNEQU1MSUFKQmYwY05BZ3RCeENKQnhDSW9BZ0JCQkhJMkFnQUxJQUVRQkNJQ1FYOUdRUUFRQkNJQVFYOUdjaUFBSUFKTmNnMEZJQUFnQW1zaUJpQUZRU2hxVFEwRkMwRzRJa0c0SWlnQ0FDQUdhaUlBTmdJQVFid2lLQUlBSUFCSkJFQkJ2Q0lnQURZQ0FBc0NRRUdnSHlnQ0FDSURCRUJCeUNJaEFBTkFJQUlnQUNnQ0FDSUJJQUFvQWdRaUJHcEdEUUlnQUNnQ0NDSUFEUUFMREFRTFFaZ2ZLQUlBSWdCQkFDQUFJQUpORzBVRVFFR1lIeUFDTmdJQUMwRUFJUUJCekNJZ0JqWUNBRUhJSWlBQ05nSUFRYWdmUVg4MkFnQkJyQjlCNENJb0FnQTJBZ0JCMUNKQkFEWUNBQU5BSUFCQkEzUWlBVUc0SDJvZ0FVR3dIMm9pQkRZQ0FDQUJRYndmYWlBRU5nSUFJQUJCQVdvaUFFRWdSdzBBQzBHVUh5QUdRU2hySWdCQmVDQUNhMEVIY1NJQmF5SUVOZ0lBUWFBZklBRWdBbW9pQVRZQ0FDQUJJQVJCQVhJMkFnUWdBQ0FDYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFRTElBSWdBMDBnQVNBRFMzSU5BaUFBS0FJTVFRaHhEUUlnQUNBRUlBWnFOZ0lFUWFBZklBTkJlQ0FEYTBFSGNTSUFhaUlCTmdJQVFaUWZRWlFmS0FJQUlBWnFJZ0lnQUdzaUFEWUNBQ0FCSUFCQkFYSTJBZ1FnQWlBRGFrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBTUxRUUFoQkF3S0MwRUFJUUlNQ0F0Qm1COG9BZ0FnQWtzRVFFR1lIeUFDTmdJQUN5QUNJQVpxSVFGQnlDSWhBQUpBQWtBQ1FBTkFJQUVnQUNnQ0FFY0VRQ0FBS0FJSUlnQU5BUXdDQ3dzZ0FDMEFERUVJY1VVTkFRdEJ5Q0loQUFOQUlBTWdBQ2dDQUNJQlR3UkFJQUVnQUNnQ0JHb2lCQ0FEU3cwREN5QUFLQUlJSVFBTUFBc0FDeUFBSUFJMkFnQWdBQ0FBS0FJRUlBWnFOZ0lFSUFKQmVDQUNhMEVIY1dvaUJ5QUZRUU55TmdJRUlBRkJlQ0FCYTBFSGNXb2lCaUFGSUFkcUlnVnJJUUFnQXlBR1JnUkFRYUFmSUFVMkFnQkJsQjlCbEI4b0FnQWdBR29pQURZQ0FDQUZJQUJCQVhJMkFnUU1DQXRCbkI4b0FnQWdCa1lFUUVHY0h5QUZOZ0lBUVpBZlFaQWZLQUlBSUFCcUlnQTJBZ0FnQlNBQVFRRnlOZ0lFSUFBZ0JXb2dBRFlDQUF3SUN5QUdLQUlFSWdOQkEzRkJBVWNOQmlBRFFYaHhJUWtnQTBIL0FVMEVRQ0FHS0FJTUlnRWdCaWdDQ0NJQ1JnUkFRWWdmUVlnZktBSUFRWDRnQTBFRGRuZHhOZ0lBREFjTElBSWdBVFlDRENBQklBSTJBZ2dNQmdzZ0JpZ0NHQ0VJSUFZZ0JpZ0NEQ0lDUndSQUlBWW9BZ2dpQVNBQ05nSU1JQUlnQVRZQ0NBd0ZDeUFHUVJScUlnRW9BZ0FpQTBVRVFDQUdLQUlRSWdORkRRUWdCa0VRYWlFQkN3TkFJQUVoQkNBRElnSkJGR29pQVNnQ0FDSUREUUFnQWtFUWFpRUJJQUlvQWhBaUF3MEFDeUFFUVFBMkFnQU1CQXRCbEI4Z0JrRW9heUlBUVhnZ0FtdEJCM0VpQVdzaUNEWUNBRUdnSHlBQklBSnFJZ0UyQWdBZ0FTQUlRUUZ5TmdJRUlBQWdBbXBCS0RZQ0JFR2tIMEh3SWlnQ0FEWUNBQ0FESUFSQkp5QUVhMEVIY1dwQkwyc2lBQ0FBSUFOQkVHcEpHeUlCUVJzMkFnUWdBVUhRSWlrQ0FEY0NFQ0FCUWNnaUtRSUFOd0lJUWRBaUlBRkJDR28yQWdCQnpDSWdCallDQUVISUlpQUNOZ0lBUWRRaVFRQTJBZ0FnQVVFWWFpRUFBMEFnQUVFSE5nSUVJQUJCQ0dvZ0FFRUVhaUVBSUFSSkRRQUxJQUVnQTBZTkFDQUJJQUVvQWdSQmZuRTJBZ1FnQXlBQklBTnJJZ0pCQVhJMkFnUWdBU0FDTmdJQUlBSkIvd0ZOQkVBZ0FrRjRjVUd3SDJvaEFBSi9RWWdmS0FJQUlnRkJBU0FDUVFOMmRDSUNjVVVFUUVHSUh5QUJJQUp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hBU0FBSUFNMkFnZ2dBU0FETmdJTUlBTWdBRFlDRENBRElBRTJBZ2dNQVF0Qkh5RUFJQUpCLy8vL0IwMEVRQ0FDUVNZZ0FrRUlkbWNpQUd0MlFRRnhJQUJCQVhSclFUNXFJUUFMSUFNZ0FEWUNIQ0FEUWdBM0FoQWdBRUVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQkVFQklBQjBJZ1p4UlFSQVFZd2ZJQVFnQm5JMkFnQWdBU0FETmdJQURBRUxJQUpCR1NBQVFRRjJhMEVBSUFCQkgwY2JkQ0VBSUFFb0FnQWhCQU5BSUFRaUFTZ0NCRUY0Y1NBQ1JnMENJQUJCSFhZaEJDQUFRUUYwSVFBZ0FTQUVRUVJ4YWlJR0tBSVFJZ1FOQUFzZ0JpQUROZ0lRQ3lBRElBRTJBaGdnQXlBRE5nSU1JQU1nQXpZQ0NBd0JDeUFCS0FJSUlnQWdBellDRENBQklBTTJBZ2dnQTBFQU5nSVlJQU1nQVRZQ0RDQURJQUEyQWdnTFFaUWZLQUlBSWdBZ0JVME5BRUdVSHlBQUlBVnJJZ0UyQWdCQm9COUJvQjhvQWdBaUFDQUZhaUlDTmdJQUlBSWdBVUVCY2pZQ0JDQUFJQVZCQTNJMkFnUWdBRUVJYWlFQURBZ0xRWVFmUVRBMkFnQkJBQ0VBREFjTFFRQWhBZ3NnQ0VVTkFBSkFJQVlvQWh3aUFVRUNkRUc0SVdvaUJDZ0NBQ0FHUmdSQUlBUWdBallDQUNBQ0RRRkJqQjlCakI4b0FnQkJmaUFCZDNFMkFnQU1BZ3NnQ0VFUVFSUWdDQ2dDRUNBR1JodHFJQUkyQWdBZ0FrVU5BUXNnQWlBSU5nSVlJQVlvQWhBaUFRUkFJQUlnQVRZQ0VDQUJJQUkyQWhnTElBWW9BaFFpQVVVTkFDQUNJQUUyQWhRZ0FTQUNOZ0lZQ3lBQUlBbHFJUUFnQmlBSmFpSUdLQUlFSVFNTElBWWdBMEYrY1RZQ0JDQUZJQUJCQVhJMkFnUWdBQ0FGYWlBQU5nSUFJQUJCL3dGTkJFQWdBRUY0Y1VHd0gyb2hBUUovUVlnZktBSUFJZ0pCQVNBQVFRTjJkQ0lBY1VVRVFFR0lIeUFBSUFKeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQUNBQklBVTJBZ2dnQUNBRk5nSU1JQVVnQVRZQ0RDQUZJQUEyQWdnTUFRdEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBVWdBellDSENBRlFnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUFrRUJJQU4wSWdSeFJRUkFRWXdmSUFJZ0JISTJBZ0FnQVNBRk5nSUFEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQWdOQUlBSWlBU2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBaUFEUVFGMElRTWdBU0FDUVFSeGFpSUVLQUlRSWdJTkFBc2dCQ0FGTmdJUUN5QUZJQUUyQWhnZ0JTQUZOZ0lNSUFVZ0JUWUNDQXdCQ3lBQktBSUlJZ0FnQlRZQ0RDQUJJQVUyQWdnZ0JVRUFOZ0lZSUFVZ0FUWUNEQ0FGSUFBMkFnZ0xJQWRCQ0dvaEFBd0NDd0pBSUFkRkRRQUNRQ0FFS0FJY0lnQkJBblJCdUNGcUlnRW9BZ0FnQkVZRVFDQUJJQUkyQWdBZ0FnMEJRWXdmSUFoQmZpQUFkM0VpQ0RZQ0FBd0NDeUFIUVJCQkZDQUhLQUlRSUFSR0cyb2dBallDQUNBQ1JRMEJDeUFDSUFjMkFoZ2dCQ2dDRUNJQUJFQWdBaUFBTmdJUUlBQWdBallDR0FzZ0JDZ0NGQ0lBUlEwQUlBSWdBRFlDRkNBQUlBSTJBaGdMQWtBZ0EwRVBUUVJBSUFRZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQkdvaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFRZ0JVRURjallDQkNBRUlBVnFJZ0lnQTBFQmNqWUNCQ0FDSUFOcUlBTTJBZ0FnQTBIL0FVMEVRQ0FEUVhoeFFiQWZhaUVBQW45QmlCOG9BZ0FpQVVFQklBTkJBM1owSWdOeFJRUkFRWWdmSUFFZ0EzSTJBZ0FnQUF3QkN5QUFLQUlJQ3lFQklBQWdBallDQ0NBQklBSTJBZ3dnQWlBQU5nSU1JQUlnQVRZQ0NBd0JDMEVmSVFBZ0EwSC8vLzhIVFFSQUlBTkJKaUFEUVFoMlp5SUFhM1pCQVhFZ0FFRUJkR3RCUG1vaEFBc2dBaUFBTmdJY0lBSkNBRGNDRUNBQVFRSjBRYmdoYWlFQkFrQUNRQ0FJUVFFZ0FIUWlCbkZGQkVCQmpCOGdCaUFJY2pZQ0FDQUJJQUkyQWdBTUFRc2dBMEVaSUFCQkFYWnJRUUFnQUVFZlJ4dDBJUUFnQVNnQ0FDRUZBMEFnQlNJQktBSUVRWGh4SUFOR0RRSWdBRUVkZGlFR0lBQkJBWFFoQUNBQklBWkJCSEZxSWdZb0FoQWlCUTBBQ3lBR0lBSTJBaEFMSUFJZ0FUWUNHQ0FDSUFJMkFnd2dBaUFDTmdJSURBRUxJQUVvQWdnaUFDQUNOZ0lNSUFFZ0FqWUNDQ0FDUVFBMkFoZ2dBaUFCTmdJTUlBSWdBRFlDQ0FzZ0JFRUlhaUVBREFFTEFrQWdDVVVOQUFKQUlBSW9BaHdpQUVFQ2RFRzRJV29pQVNnQ0FDQUNSZ1JBSUFFZ0JEWUNBQ0FFRFFGQmpCOGdDMEYrSUFCM2NUWUNBQXdDQ3lBSlFSQkJGQ0FKS0FJUUlBSkdHMm9nQkRZQ0FDQUVSUTBCQ3lBRUlBazJBaGdnQWlnQ0VDSUFCRUFnQkNBQU5nSVFJQUFnQkRZQ0dBc2dBaWdDRkNJQVJRMEFJQVFnQURZQ0ZDQUFJQVEyQWhnTEFrQWdBMEVQVFFSQUlBSWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0Ftb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBSWdCVUVEY2pZQ0JDQUNJQVZxSWdRZ0EwRUJjallDQkNBRElBUnFJQU0yQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUJCbkI4b0FnQWhBUUovUVFFZ0IwRURkblFpQlNBR2NVVUVRRUdJSHlBRklBWnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEJpQUFJQUUyQWdnZ0JpQUJOZ0lNSUFFZ0FEWUNEQ0FCSUFZMkFnZ0xRWndmSUFRMkFnQkJrQjhnQXpZQ0FBc2dBa0VJYWlFQUN5QUtRUkJxSkFBZ0FBdlNDd0VIZndKQUlBQkZEUUFnQUVFSWF5SUNJQUJCQkdzb0FnQWlBVUY0Y1NJQWFpRUZBa0FnQVVFQmNRMEFJQUZCQTNGRkRRRWdBaUFDS0FJQUlnRnJJZ0pCbUI4b0FnQkpEUUVnQUNBQmFpRUFBa0FDUUVHY0h5Z0NBQ0FDUndSQUlBRkIvd0ZOQkVBZ0FVRURkaUVFSUFJb0Fnd2lBU0FDS0FJSUlnTkdCRUJCaUI5QmlCOG9BZ0JCZmlBRWQzRTJBZ0FNQlFzZ0F5QUJOZ0lNSUFFZ0F6WUNDQXdFQ3lBQ0tBSVlJUVlnQWlBQ0tBSU1JZ0ZIQkVBZ0FpZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQUpCRkdvaUJDZ0NBQ0lEUlFSQUlBSW9BaEFpQTBVTkFpQUNRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGS0FJRUlnRkJBM0ZCQTBjTkFrR1FIeUFBTmdJQUlBVWdBVUYrY1RZQ0JDQUNJQUJCQVhJMkFnUWdCU0FBTmdJQUR3dEJBQ0VCQ3lBR1JRMEFBa0FnQWlnQ0hDSURRUUowUWJnaGFpSUVLQUlBSUFKR0JFQWdCQ0FCTmdJQUlBRU5BVUdNSDBHTUh5Z0NBRUYrSUFOM2NUWUNBQXdDQ3lBR1FSQkJGQ0FHS0FJUUlBSkdHMm9nQVRZQ0FDQUJSUTBCQ3lBQklBWTJBaGdnQWlnQ0VDSURCRUFnQVNBRE5nSVFJQU1nQVRZQ0dBc2dBaWdDRkNJRFJRMEFJQUVnQXpZQ0ZDQURJQUUyQWhnTElBSWdCVThOQUNBRktBSUVJZ0ZCQVhGRkRRQUNRQUpBQWtBQ1FDQUJRUUp4UlFSQVFhQWZLQUlBSUFWR0JFQkJvQjhnQWpZQ0FFR1VIMEdVSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUNRWndmS0FJQVJ3MEdRWkFmUVFBMkFnQkJuQjlCQURZQ0FBOExRWndmS0FJQUlBVkdCRUJCbkI4Z0FqWUNBRUdRSDBHUUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FBSUFKcUlBQTJBZ0FQQ3lBQlFYaHhJQUJxSVFBZ0FVSC9BVTBFUUNBQlFRTjJJUVFnQlNnQ0RDSUJJQVVvQWdnaUEwWUVRRUdJSDBHSUh5Z0NBRUYrSUFSM2NUWUNBQXdGQ3lBRElBRTJBZ3dnQVNBRE5nSUlEQVFMSUFVb0FoZ2hCaUFGSUFVb0Fnd2lBVWNFUUVHWUh5Z0NBQm9nQlNnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBVkJGR29pQkNnQ0FDSURSUVJBSUFVb0FoQWlBMFVOQWlBRlFSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZJQUZCZm5FMkFnUWdBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQXdEQzBFQUlRRUxJQVpGRFFBQ1FDQUZLQUljSWdOQkFuUkJ1Q0ZxSWdRb0FnQWdCVVlFUUNBRUlBRTJBZ0FnQVEwQlFZd2ZRWXdmS0FJQVFYNGdBM2R4TmdJQURBSUxJQVpCRUVFVUlBWW9BaEFnQlVZYmFpQUJOZ0lBSUFGRkRRRUxJQUVnQmpZQ0dDQUZLQUlRSWdNRVFDQUJJQU0yQWhBZ0F5QUJOZ0lZQ3lBRktBSVVJZ05GRFFBZ0FTQUROZ0lVSUFNZ0FUWUNHQXNnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUNBQ1Fad2ZLQUlBUncwQVFaQWZJQUEyQWdBUEN5QUFRZjhCVFFSQUlBQkJlSEZCc0I5cUlRRUNmMEdJSHlnQ0FDSURRUUVnQUVFRGRuUWlBSEZGQkVCQmlCOGdBQ0FEY2pZQ0FDQUJEQUVMSUFFb0FnZ0xJUUFnQVNBQ05nSUlJQUFnQWpZQ0RDQUNJQUUyQWd3Z0FpQUFOZ0lJRHd0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFJZ0F6WUNIQ0FDUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtBQ1FFR01IeWdDQUNJRVFRRWdBM1FpQjNGRkJFQkJqQjhnQkNBSGNqWUNBQ0FCSUFJMkFnQWdBaUFCTmdJWURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBUU5BSUFFaUJDZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFTQURRUUYwSVFNZ0JDQUJRUVJ4YWlJSFFSQnFLQUlBSWdFTkFBc2dCeUFDTmdJUUlBSWdCRFlDR0FzZ0FpQUNOZ0lNSUFJZ0FqWUNDQXdCQ3lBRUtBSUlJZ0FnQWpZQ0RDQUVJQUkyQWdnZ0FrRUFOZ0lZSUFJZ0JEWUNEQ0FDSUFBMkFnZ0xRYWdmUWFnZktBSUFRUUZySWdCQmZ5QUFHellDQUFzTEJBQWpBQXNHQUNBQUpBQUxFQUFqQUNBQWEwRndjU0lBSkFBZ0FBdEtBUUYvSUFBZ0FVa0VRQ0FBSUFFZ0FoQUNEd3NnQWdSQUlBQWdBbW9oQXlBQklBSnFJUUVEUUNBRFFRRnJJZ01nQVVFQmF5SUJMUUFBT2dBQUlBSkJBV3NpQWcwQUN3c2dBQXY5RGdJUmZ3RitJd0JCTUdzaUJ5UUFRYmgvSVFnQ1FDQUZSUTBBSUFRc0FBQWlDVUgvQVhFaEN3SkFJQWxCQUVnRVFDQUxRZjRBYTBFQmRpSUdJQVZQRFFKQmJDRUlJQXRCL3dCcklndEIvd0ZMRFFJZ0JFRUJhaUVJUVFBaEJRTkFJQVVnQzA4RVFDQUxJUWdnQmlFTERBTUZJQUFnQldvZ0NDQUZRUUYyYWlJRUxRQUFRUVIyT2dBQUlBQWdCVUVCY21vZ0JDMEFBRUVQY1RvQUFDQUZRUUpxSVFVTUFRc0FDd0FMSUFVZ0MwME5BU0FIUWY4Qk5nSUVJQVlnQjBFRWFpQUhRUWhxSUFSQkFXb2lEaUFMRUF3aUJFR0lmMHNFUUNBRUlRZ01BZ3RCVkNFSUlBY29BZ2dpRUVFR1N3MEJJQWNvQWdRaUVVRUJkQ0lKUVFKcXJVSUJJQkN0aGlJWVFRRWdFSFFpRFVFQmFpSUZyVUlDaG54OFFndDhRdnovLy8vLy8vLy8vd0NEUXVRQ1ZnMEJRVkloQ0NBUlFmOEJTdzBCSUExQmYzTkJBblJCNUFKcXJTQVJRUUZxSWhWQkFYU3RJQmg4UWdoOFZBMEJJQXNnQkdzaEZpQUVJQTVxSVJjZ0JrR0FCR29pRWlBRlFRSjBhaUlSSUFscVFRSnFJUTRnQmtHRUJHb2hFMEdBZ0FJZ0VIUkJFSFloQ1VFQUlRVkJBU0VQSUExQkFXc2lGQ0VLQTBBZ0JTQVZSa1VFUUFKQUlBWWdCVUVCZENJSWFpOEJBQ0lFUWYvL0EwWUVRQ0FUSUFwQkFuUnFJQVU2QUFJZ0NrRUJheUVLUVFFaEJBd0JDeUFQUVFBZ0NTQUV3VW9iSVE4TElBZ2dFV29nQkRzQkFDQUZRUUZxSVFVTUFRc0xJQVlnRHpzQmdnUWdCaUFRT3dHQUJBSkFJQW9nRkVZRVFDQU5RUU4ySVFoQ0FDRVlRUUFoRHdOQUlBd2dGVVlFUUNBSUlBMUJBWFpxUVFOcUlnbEJBWFFoQ0VFQUlRUkJBQ0VLQTBCQkFDRUZJQW9nRFU4TkJBTkFJQVZCQWtaRkJFQWdFeUFGSUFsc0lBUnFJQlJ4UVFKMGFpQU9JQVVnQ21wcUxRQUFPZ0FDSUFWQkFXb2hCUXdCQ3dzZ0NrRUNhaUVLSUFRZ0NHb2dGSEVoQkF3QUN3QUZJQVlnREVFQmRHb3VBUUFoQ1NBT0lBOXFJZ1FnR0RjQUFFRUlJUVVEUUNBRklBbE9SUVJBSUFRZ0JXb2dHRGNBQUNBRlFRaHFJUVVNQVFzTElCaENnWUtFaUpDZ3dJQUJmQ0VZSUF4QkFXb2hEQ0FKSUE5cUlROE1BUXNBQ3dBTElBMUJBM1lnRFVFQmRtcEJBMm9oQ0VFQUlRVURRQ0FNSUJWR1JRUkFRUUFoQ1NBR0lBeEJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBSlJrVUVRQ0FUSUFWQkFuUnFJQXc2QUFJRFFDQUZJQWhxSUJSeElnVWdDa3NOQUFzZ0NVRUJhaUVKREFFTEN5QU1RUUZxSVF3TUFRc0xRWDhoQ0NBRkRRSUxJQkJCQVdvaENFRUFJUVVEUUNBRklBMUdSUVJBSUJFZ0V5QUZRUUowYWlJT0xRQUNRUUYwYWlJRUlBUXZBUUFpQ1VFQmFqc0JBQ0FPSUFnZ0NXZEJZSE5xSWdRNkFBTWdEaUFKSUFSMElBMXJPd0VBSUFWQkFXb2hCUXdCQ3dzQ1FBSkFJQVl2QVlJRUJFQWdCMEVjYWlJRUlCY2dGaEFOSWdoQmlIOUxEUUlnQjBFVWFpQUVJQklRRGlBSFFReHFJQVFnRWhBT1FRQWhCUU5BSUFkQkhHb2lCQkFQSUFWQit3RkxjZzBDSUFBZ0JXb2lCaUFIUVJScUlBUVFFRG9BQUNBR0lBZEJER29nQkJBUU9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVNQXdVZ0FDQUVhaUFIUVJScUlBZEJIR29pQkJBUU9nQUFJQVlnQjBFTWFpQUVFQkE2QUFNZ0JVRUVhaUVGREFFTEFBc0FDeUFIUVJ4cUlnUWdGeUFXRUEwaUNFR0lmMHNOQVNBSFFSUnFJQVFnRWhBT0lBZEJER29nQkNBU0VBNUJBQ0VGQTBBZ0IwRWNhaUlFRUE4Z0JVSDdBVXR5UlFSQUlBQWdCV29pQmlBSFFSUnFJQVFRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVRklBQWdCR29nQjBFVWFpQUhRUnhxSWdRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBRElBVkJCR29oQlF3Q0N3c0xBbjhEUUVHNmZ5RUlJQVZCL1FGTERRTWdBQ0FGYWlJR0lBZEJGR29nQjBFY2FpSUpFQkU2QUFBZ0JrRUJhaUVFSUFrUUQwRURSZ1JBSUFkQkRHb2hDRUVDREFJTElBVkIvQUZMRFFNZ0JpQUhRUXhxSUFkQkhHb2lCQkFST2dBQklBVkJBbW9oQlNBRUVBOUJBMGNOQUFzZ0FDQUZhaUVFSUFkQkZHb2hDRUVEQ3lBRUlBZ2dCMEVjYWhBUk9nQUFJQVpxSUFCcklRZ01BUXNDZndOQVFicC9JUWdnQlVIOUFVc05BaUFBSUFWcUlnWWdCMEVVYWlBSFFSeHFJZ2tRRURvQUFDQUdRUUZxSVFRZ0NSQVBRUU5HQkVBZ0IwRU1haUVJUVFJTUFnc2dCVUg4QVVzTkFpQUdJQWRCREdvZ0IwRWNhaUlFRUJBNkFBRWdCVUVDYWlFRklBUVFEMEVEUncwQUN5QUFJQVZxSVFRZ0IwRVVhaUVJUVFNTElBUWdDQ0FIUVJ4cUVCQTZBQUFnQm1vZ0FHc2hDQXNnQ0VHSWYwc05BUXNnQ0NFRVFRQWhCU0FCUVFCQk5CQURJUWxCQUNFS0EwQWdCQ0FGUndSQUlBQWdCV29pQmkwQUFDSUJRUXRMQkVCQmJDRUlEQU1GSUFrZ0FVRUNkR29pQVNBQktBSUFRUUZxTmdJQUlBVkJBV29oQlVFQklBWXRBQUIwUVFGMUlBcHFJUW9NQWdzQUN3dEJiQ0VJSUFwRkRRQWdDbWNpQlVFZmN5SUJRUXRMRFFBZ0EwRWdJQVZyTmdJQVFRRkJBaUFCZENBS2F5SURaMEVmY3lJQmRDQURSdzBBSUFBZ0JHb2dBVUVCYWlJQU9nQUFJQWtnQUVFQ2RHb2lBQ0FBS0FJQVFRRnFOZ0lBSUFrb0FnUWlBRUVDU1NBQVFRRnhjZzBBSUFJZ0JFRUJhallDQUNBTFFRRnFJUWdMSUFkQk1Hb2tBQ0FJQzZBRkFReC9Jd0JCRUdzaURDUUFBbjhnQkVFSFRRUkFJQXhDQURjRENDQU1RUWhxSWdVZ0F5QUVFQUlhUVd3Z0FDQUJJQUlnQlVFSUVBd2lBQ0FBSUFSTEd5QUFJQUJCaVg5Skd3d0JDeUFBUVFBZ0FTZ0NBRUVCYWlJTlFRRjBFQU1oRDBGVUlBTW9BQUFpQmtFUGNTSUFRUXBMRFFBYUlBSWdBRUVGYWpZQ0FDQURJQVJxSWdKQkJHc2hCeUFDUVFkcklRc2dBRUVHYWlFT1FRUWhBaUFHUVFSMklRVkJJQ0FBZENJSVFRRnlJUWxCQUNFQVFRRWhCaUFESVFRRFFBSkFJQVpCQVhGRkJFQURRQ0FGUVg5elFZQ0FnSUI0Y21naUJrRVlTVVVFUUNBQVFTUnFJUUFnQkNBTFRRUi9JQVJCQTJvRklBUWdDMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMSUFJZ0JrRWVjU0lLYWtFQ2FpRUNJQVpCQVhaQkEyd2dBR29nQlNBS2RrRURjV29pQUNBTlR3MEJBbjhnQkNBTFN5QUNRUU4ySUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQVFnQjJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVMSUFVZ0NFRUJhM0VpQmlBSVFRRjBRUUZySWdvZ0NXc2lFRWtFZnlBT1FRRnJCU0FGSUFweElnVWdFRUVBSUFVZ0NFNGJheUVHSUE0TElRVWdEeUFBUVFGMGFpQUdRUUZySWdvN0FRQWdBRUVCYWlFQUlBSWdCV29oQWlBSVFRRWdCbXNnQ2lBR1FRQktHeUFKYWlJSlNnUkFJQWxCQWtnTkFVRWdJQWxuSWdWcklRNUJBU0FGUVI5emRDRUlDeUFBSUExUERRQWdDa0VBUnlFR0FuOGdCQ0FMU3lBQ1FRTjFJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBSWdCQ0FIYTBFRGRHcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMUVd3Z0NVRUJSdzBBR2tGUUlBQWdEVXNOQUJwQmJDQUNRU0JLRFFBYUlBRWdBRUVCYXpZQ0FDQUVJQUpCQjJwQkEzVnFJQU5yQ3lBTVFSQnFKQUFMOGdFQkFYOGdBa1VFUUNBQVFnQTNBZ0FnQUVFQU5nSVFJQUJDQURjQ0NFRzRmdzhMSUFBZ0FUWUNEQ0FBSUFGQkJHbzJBaEFnQWtFRVR3UkFJQUFnQVNBQ2FpSUJRUVJySWdNMkFnZ2dBQ0FES0FBQU5nSUFJQUZCQVdzdEFBQWlBUVJBSUFBZ0FXZEJGMnMyQWdRZ0FnOExJQUJCQURZQ0JFRi9Ed3NnQUNBQk5nSUlJQUFnQVMwQUFDSUROZ0lBQWtBQ1FBSkFJQUpCQW1zT0FnRUFBZ3NnQUNBQkxRQUNRUkIwSUFOeUlnTTJBZ0FMSUFBZ0FTMEFBVUVJZENBRGFqWUNBQXNnQVNBQ2FrRUJheTBBQUNJQlJRUkFJQUJCQURZQ0JFRnNEd3NnQUNBQlp5QUNRUU4wYTBFSmFqWUNCQ0FDQzBRQkFuOGdBU0FDTHdFQUlnTWdBU2dDQkdvaUJEWUNCQ0FBSUFOQkFuUkJvQjFxS0FJQUlBRW9BZ0JCQUNBRWEzWnhOZ0lBSUFFUUR4b2dBQ0FDUVFScU5nSUVDNThCQVFSL1FRTWhBU0FBS0FJRUlnSkJJRTBFUUNBQUtBSUlJZ0VnQUNnQ0VFOEVRQ0FBSUFKQkIzRTJBZ1FnQUNBQklBSkJBM1pySWdJMkFnZ2dBQ0FDS0FBQU5nSUFRUUFQQ3lBQUtBSU1JZ01nQVVZRVFFRUJRUUlnQWtFZ1NSc1BDeUFBSUFFZ0FTQURheUFDUVFOMklnUWdBU0FFYXlBRFNTSUJHeUlEYXlJRU5nSUlJQUFnQWlBRFFRTjBhellDQkNBQUlBUW9BQUEyQWdBTElBRUxTQUVFZnlBQUtBSUVJQUFvQWdCQkFuUnFJZ0l0QUFJZ0FpOEJBQ0VFSUFFZ0FTZ0NCQ0lGSUFJdEFBTWlBbW8yQWdRZ0FDQUVJQUVvQWdBZ0JYUkJBQ0FDYTNacU5nSUFDMUlCQkg4Z0FDZ0NCQ0FBS0FJQVFRSjBhaUlDTFFBQ0lBSXZBUUFoQkNBQklBSXRBQU1pQWlBQktBSUVhaUlGTmdJRUlBQWdCQ0FDUVFKMFFhQWRhaWdDQUNBQktBSUFRUUFnQld0MmNXbzJBZ0FMQ0FBZ0FFR0lmMHNMR2dBZ0FBUkFJQUVFUUNBQ0lBQWdBUkVDQUE4TElBQVFCZ3NMcGdnQ0RYOEJmaU1BUVJCcklna2tBQ0FKUVFBMkFnd2dDVUVBTmdJSUFuOENRQ0FEUWVnSmFpQURJQWxCQ0dvZ0NVRU1haUFCSUFJZ0EwR0FBV29RQ3lJUFFZaC9TdzBBUVZRZ0NTZ0NEQ0lFSUFBb0FnQWlBVUgvQVhGQkFXcExEUUVhSUFCQkJHb2hDeUFBSUFGQi80R0FlSEVnQkVFUWRFR0FnUHdIY1hJMkFnQkJmeUFFSUFSQkFFZ2JRUUZxSVFCQkFDRUJJQWtvQWdnaEJVRUFJUUlEUUNBQUlBSkdCRUFnQlVFRGF5RUJRUUFoQUFOQUFrQkJBQ0VDSUFBZ0FVNEVRQU5BSUFBZ0JVNE5BaUFESUFBZ0EycEI2QWxxTFFBQVFRSjBha0ZBYXlJQklBRW9BZ0FpQVVFQmFqWUNBQ0FCSUFOcUlBQTZBT2dISUFCQkFXb2hBQXdBQ3dBRkEwQWdBa0VFUmtVRVFDQURJQU1nQUNBQ2FpSUhha0hvQ1dvdEFBQkJBblJxUVVCcklnZ2dDQ2dDQUNJSVFRRnFOZ0lBSUFNZ0NHb2dCem9BNkFjZ0FrRUJhaUVDREFFTEN5QUFRUVJxSVFBTUFnc0FDd3NnQkVFQmFpRU9JQU1vQWdBaEIwRUFJUUJCQVNFSUEwQWdDQ0FPUmcwRElBNGdDR3NoQkNBRElBaEJBblJxS0FJQUlRVUNRQUpBQWtBQ1FBSkFBa0JCQVNBSWRFRUJkU0lOUVFGckRnZ0FBUVFDQkFRRUF3UUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUFJUUVEUUNBQ0lBWkdEUVVnQXlBQ0lBZHFhaTBBNkFjaENpQUxJQUZCQVhScUlnd2dCRG9BQVNBTUlBbzZBQUFnQWtFQmFpRUNJQUZCQVdvaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hDaUFBSVFFRFFDQUNJQXBHRFFRZ0N5QUJRUUYwYWlJR0lBTWdBaUFIYW1vdEFPZ0hJZ3c2QUFJZ0JpQUVPZ0FCSUFZZ0REb0FBQ0FHSUFRNkFBTWdBa0VCYWlFQ0lBRkJBbW9oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUVRUWgwUVlEK0EzRWhCQ0FBSVFFRFFDQUNJQVpHRFFNZ0N5QUJRUUYwYWlBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrTndBQUlBSkJBV29oQWlBQlFRUnFJUUVNQUFzQUMwRUFJUUlnQlVFQUlBVkJBRW9iSVFZZ0JFRUlkRUdBL2dOeElRUWdBQ0VCQTBBZ0FpQUdSZzBDSUFzZ0FVRUJkR29pQ2lBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSWhFM0FBZ2dDaUFSTndBQUlBSkJBV29oQWlBQlFRaHFJUUVNQUFzQUMwRUFJUUVnQlVFQUlBVkJBRW9iSVFvZ0JFRUlkRUdBL2dOeElRd2dBQ0VFQTBBZ0FTQUtSZzBCSUFzZ0JFRUJkR29oRUNBTUlBTWdBU0FIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSVJGQkFDRUNBMEFnQWlBTlRrVUVRQ0FRSUFKQkFYUnFJZ1lnRVRjQUdDQUdJQkUzQUJBZ0JpQVJOd0FJSUFZZ0VUY0FBQ0FDUVJCcUlRSU1BUXNMSUFGQkFXb2hBU0FFSUExcUlRUU1BQXNBQ3lBSVFRRnFJUWdnQlNBSGFpRUhJQVVnRFd3Z0FHb2hBQXdBQ3dBRklBTWdBa0VDZEdvaUIwRkFheUFCTmdJQUlBSkJBV29oQWlBSEtBSUFJQUZxSVFFTUFRc0FDd0FMSUE4TElBbEJFR29rQUF2eUFnRUdmeU1BUVNCcklnVWtBQ0FFS0FJQUlRWWdCVUVNYWlBQ0lBTVFEU0lEUVloL1RRUkFJQVJCQkdvaEFpQUFJQUZxSWdsQkEyc2hCRUVBSUFaQkVIWnJRUjl4SVFNRFFDQUZRUXhxRUE4Z0FDQUVUM0pGQkVBZ0FpQUZLQUlNSWdZZ0JTZ0NFQ0lIZENBRGRrRUJkR29pQ0MwQUFTRUtJQUFnQ0MwQUFEb0FBQ0FDSUFZZ0J5QUthaUlHZENBRGRrRUJkR29pQnkwQUFDRUlJQVVnQmlBSExRQUJhallDRUNBQUlBZzZBQUVnQUVFQ2FpRUFEQUVMQ3dOQUlBVkJER29RRHlFSElBVW9BZ3doQmlBRktBSVFJUVFnQUNBSlR5QUhja1VFUUNBQ0lBWWdCSFFnQTNaQkFYUnFJZ1l0QUFBaEJ5QUZJQVFnQmkwQUFXbzJBaEFnQUNBSE9nQUFJQUJCQVdvaEFBd0JDd3NEUUNBQUlBbFBSUVJBSUFJZ0JpQUVkQ0FEZGtFQmRHb2lCeTBBQVNFSUlBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0JDQUlhaUVFREFFTEMwRnNRV3dnQVNBRktBSVVJQVVvQWhoSEd5QUVRU0JIR3lFREN5QUZRU0JxSkFBZ0F3dlBGQUVqZnlNQVFkQUFheUlGSkFCQmJDRUpBa0FnQTBFS1NRMEFBa0FnQXlBQ0x3QUVJZ2NnQWk4QUFDSUlJQUl2QUFJaURXcHFRUVpxSWd4SkRRQWdCQzhCQWlFR0lBVkJQR29nQWtFR2FpSUNJQWdRRFNJSlFZaC9TdzBCSUFWQktHb2dBaUFJYWlJQ0lBMFFEU0lKUVloL1N3MEJJQVZCRkdvZ0FpQU5haUlDSUFjUURTSUpRWWgvU3cwQklBVWdBaUFIYWlBRElBeHJFQTBpQ1VHSWYwc05BU0FFUVFScUlRb2dBQ0FCYWlJZlFRTnJJU0JCQUNBR2EwRWZjU0VMSUFVb0FnZ2hFU0FGS0FJY0lSSWdCU2dDTUNFVElBVW9Ba1FoRkNBRktBSUVJUWtnQlNnQ0dDRU5JQVVvQWl3aERDQUZLQUpBSVFZZ0JTZ0NFQ0VoSUFVb0FpUWhJaUFGS0FJNElTTWdCU2dDVENFa0lBVW9BZ0FoRlNBRktBSVVJUllnQlNnQ0tDRVhJQVVvQWp3aEdFRUJJUThnQUNBQlFRTnFRUUoySWdScUlnTWdCR29pQWlBRWFpSVpJUVFnQWlFSUlBTWhCd05BSUE5QkFYRkZJQVFnSUU5eVJRUkFJQUFnQ2lBWUlBWjBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloR2lBT0xRQURJUkFnQnlBS0lCY2dESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdEaTBBQWlFYklBNHRBQU1oRHlBSUlBb2dGaUFOZENBTGRrRUNkR29pRGk4QkFEc0FBQ0FPTFFBQ0lSd2dEaTBBQXlFZElBUWdDaUFWSUFsMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhIaUFPTFFBRElRNGdBQ0FRYWlJbElBb2dHQ0FHSUJwcUlnWjBJQXQyUVFKMGFpSVFMd0VBT3dBQUlCQXRBQUlnRUMwQUF5RW1JQWNnRDJvaUp5QUtJQmNnRENBYmFpSWFkQ0FMZGtFQ2RHb2lCeThCQURzQUFDQUhMUUFDSVF3Z0J5MEFBeUVRSUFnZ0hXb2lHeUFLSUJZZ0RTQWNhaUlQZENBTGRrRUNkR29pQ0M4QkFEc0FBQ0FJTFFBQ0lRMGdDQzBBQXlFY0lBUWdEbW9pSFNBS0lCVWdDU0FlYWlJT2RDQUxka0VDZEdvaUNTOEJBRHNBQUNBR2FpRUFRUU1oQndKL0lCUWdKRWtFUUNBQUlRWkJBd3dCQ3lBQVFRZHhJUVlnRkNBQVFRTjJheUlVS0FBQUlSaEJBQXNnQ1MwQUF5RWVJQWt0QUFJaENDQU1JQnBxSVFBZ0V5QWpTUVIvSUFBRklCTWdBRUVEZG1zaUV5Z0FBQ0VYUVFBaEJ5QUFRUWR4Q3lFTUlBMGdEMm9oQUNBSGNpRUpRUU1oRHdKL0lCSWdJa2tFUUNBQUlRMUJBd3dCQ3lBQVFRZHhJUTBnRWlBQVFRTjJheUlTS0FBQUlSWkJBQXNnQ0NBT2FpRUFJQWx5SUJFZ0lVa0VmeUFBQlNBUklBQkJBM1pySWhFb0FBQWhGVUVBSVE4Z0FFRUhjUXNoQ1NBbElDWnFJUUFnRUNBbmFpRUhJQnNnSEdvaENDQWRJQjVxSVFRZ0QzSkZJUThNQVFzTElBVWdERFlDTENBRklBWTJBa0FnQlNBTk5nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUlnQjBrZ0FDQURTM0lOQUVGc0lRa2dDQ0FaU3cwQklBTkJBMnNoQ1FOQUlBVkJQR29RRDBVZ0FDQUpTWEVFUUNBQUlBb2dCU2dDUENJTklBVW9Ba0FpREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnQUNBT0xRQURhaUlHSUFvZ0RTQU1JQTR0QUFKcUlnQjBJQXQyUVFKMGFpSU1Md0VBT3dBQUlBVWdBQ0FNTFFBQ2FqWUNRQ0FHSUF3dEFBTnFJUUFNQVFVZ0EwRUNheUVNQTBBZ0JVRThhaEFQSVFZZ0JTZ0NQQ0VOSUFVb0FrQWhDU0FBSUF4TElBWnlSUVJBSUFBZ0NpQU5JQWwwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQ1NBR0xRQUNhallDUUNBQUlBWXRBQU5xSVFBTUFRc0xBMEFnQUNBTVMwVUVRQ0FBSUFvZ0RTQUpkQ0FMZGtFQ2RHb2lCaThCQURzQUFDQUFJQVl0QUFOcUlRQWdDU0FHTFFBQ2FpRUpEQUVMQ3dKQUlBQWdBMDhOQUNBQUlBb2dEU0FKZENBTGRpSUFRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSklBTXRBQUpxSVFrTUFRc2dDVUVmU3cwQVFTQWdDU0FLSUFCQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFrTElBSkJBMnNoREFOQUlBVkJLR29RRDBVZ0J5QU1TWEVFUUNBSElBb2dCU2dDS0NJR0lBVW9BaXdpQUhRZ0MzWkJBblJxSWcwdkFRQTdBQUFnQnlBTkxRQURhaUlESUFvZ0JpQUFJQTB0QUFKcUlnQjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBQ0FHTFFBQ2FqWUNMQ0FESUFZdEFBTnFJUWNNQVFVZ0FrRUNheUVHQTBBZ0JVRW9haEFQSVFNZ0JTZ0NLQ0VNSUFVb0Fpd2hBQ0FHSUFkSklBTnlSUVJBSUFjZ0NpQU1JQUIwSUF0MlFRSjBhaUlETHdFQU93QUFJQVVnQUNBRExRQUNhallDTENBSElBTXRBQU5xSVFjTUFRc0xBMEFnQmlBSFNVVUVRQ0FISUFvZ0RDQUFkQ0FMZGtFQ2RHb2lBeThCQURzQUFDQUhJQU10QUFOcUlRY2dBQ0FETFFBQ2FpRUFEQUVMQ3dKQUlBSWdCMDBOQUNBSElBb2dEQ0FBZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBQUlBTXRBQUpxSVFBTUFRc2dBRUVmU3cwQVFTQWdBQ0FLSUFKQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFBTElCbEJBMnNoREFOQUlBVkJGR29RRDBVZ0NDQU1TWEVFUUNBSUlBb2dCU2dDRkNJR0lBVW9BaGdpQW5RZ0MzWkJBblJxSWcwdkFRQTdBQUFnQ0NBTkxRQURhaUlESUFvZ0JpQUNJQTB0QUFKcUlnSjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBaUFHTFFBQ2FqWUNHQ0FESUFZdEFBTnFJUWdNQVFVZ0dVRUNheUVEQTBBZ0JVRVVhaEFQSVFJZ0JTZ0NGQ0VHSUFVb0FoZ2hCeUFESUFoSklBSnlSUVJBSUFnZ0NpQUdJQWQwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVVnQnlBQ0xRQUNhallDR0NBSUlBSXRBQU5xSVFnTUFRc0xBMEFnQXlBSVNVVUVRQ0FJSUFvZ0JpQUhkQ0FMZGtFQ2RHb2lBaThCQURzQUFDQUlJQUl0QUFOcUlRZ2dCeUFDTFFBQ2FpRUhEQUVMQ3dKQUlBZ2dHVThOQUNBSUlBb2dCaUFIZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSElBTXRBQUpxSVFjTUFRc2dCMEVmU3cwQVFTQWdCeUFLSUFKQkFuUnFMUUFDYWlJQ0lBSkJJRThiSVFjTEEwQWdCUkFQUlNBRUlDQkpjUVJBSUFRZ0NpQUZLQUlBSWdZZ0JTZ0NCQ0lDZENBTGRrRUNkR29pREM4QkFEc0FBQ0FFSUF3dEFBTnFJZ01nQ2lBR0lBSWdEQzBBQW1vaUFuUWdDM1pCQW5ScUlnUXZBUUE3QUFBZ0JTQUNJQVF0QUFKcU5nSUVJQU1nQkMwQUEyb2hCQXdCQlNBZlFRSnJJUU1EUUNBRkVBOGhBaUFGS0FJQUlRWWdCU2dDQkNFSUlBTWdCRWtnQW5KRkJFQWdCQ0FLSUFZZ0NIUWdDM1pCQW5ScUlnSXZBUUE3QUFBZ0JTQUlJQUl0QUFKcU5nSUVJQVFnQWkwQUEyb2hCQXdCQ3dzRFFDQURJQVJKUlFSQUlBUWdDaUFHSUFoMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0FpMEFBMm9oQkNBSUlBSXRBQUpxSVFnTUFRc0xBa0FnQkNBZlR3MEFJQVFnQ2lBR0lBaDBJQXQySWdKQkFuUnFJZ010QUFBNkFBQWdBeTBBQTBFQlJnUkFJQWdnQXkwQUFtb2hDQXdCQ3lBSVFSOUxEUUJCSUNBSUlBb2dBa0VDZEdvdEFBSnFJZ0lnQWtFZ1R4c2hDQXRCYkVGc1FXeEJiRUZzUVd4QmJFRnNJQUVnQ0VFZ1J4c2dCU2dDQ0NBRktBSU1SeHNnQjBFZ1J4c2dCU2dDSENBRktBSWdSeHNnQUVFZ1J4c2dCU2dDTUNBRktBSTBSeHNnQ1VFZ1J4c2dCU2dDUkNBRktBSklSeHNoQ1F3SkN3QUxBQXNBQ3dBTEFBc0FDd0FMQUF0QmJDRUpDeUFGUWRBQWFpUUFJQWtMN0JBQkhuOGpBRUhRQUdzaUJTUUFRV3doQ1FKQUlBTkJDa2tOQUFKQUlBTWdBaThBQkNJR0lBSXZBQUFpQnlBQ0x3QUNJZ2hxYWtFR2FpSU9TUTBBSUFRdkFRSWhEeUFGUVR4cUlBSkJCbW9pQWlBSEVBMGlDVUdJZjBzTkFTQUZRU2hxSUFJZ0Iyb2lBaUFJRUEwaUNVR0lmMHNOQVNBRlFSUnFJQUlnQ0dvaUFpQUdFQTBpQ1VHSWYwc05BU0FGSUFJZ0Jtb2dBeUFPYXhBTklnbEJpSDlMRFFFZ0JFRUVhaUVLSUFBZ0FXb2lIRUVEYXlFZFFRQWdEMnRCSDNFaEN5QUZLQUlJSVJFZ0JTZ0NIQ0VTSUFVb0FqQWhFeUFGS0FKRUlSUWdCU2dDQkNFSklBVW9BaGdoQmlBRktBSXNJUWNnQlNnQ1FDRUlJQVVvQWhBaEhpQUZLQUlrSVI4Z0JTZ0NPQ0VnSUFVb0Frd2hJU0FGS0FJQUlSVWdCU2dDRkNFV0lBVW9BaWdoRnlBRktBSThJUmhCQVNFTklBQWdBVUVEYWtFQ2RpSUNhaUlPSUFKcUlnOGdBbW9pR1NFRUlBOGhBaUFPSVFNRFFDQU5SU0FFSUIxUGNrVUVRQ0FLSUJnZ0NIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFBZ0NpQVhJQWQwSUF0MlFRRjBhaUlNTFFBQklSQWdBeUFNTFFBQU9nQUFJQW9nRmlBR2RDQUxka0VCZEdvaURDMEFBU0VhSUFJZ0RDMEFBRG9BQUNBS0lCVWdDWFFnQzNaQkFYUnFJZ3d0QUFFaEd5QUVJQXd0QUFBNkFBQWdDaUFZSUFnZ0RXb2lDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBRWdDaUFYSUFjZ0VHb2lCM1FnQzNaQkFYUnFJZ3d0QUFFaEVDQURJQXd0QUFBNkFBRWdDaUFXSUFZZ0dtb2lESFFnQzNaQkFYUnFJZ1l0QUFFaEdpQUNJQVl0QUFBNkFBRWdDaUFWSUFrZ0cyb2lHM1FnQzNaQkFYUnFJZ2t0QUFFaElpQUVJQWt0QUFBNkFBRWdDQ0FOYWlFR1FRTWhDUUovSUJRZ0lVa0VRRUVESVEwZ0Jnd0JDeUFVSUFaQkEzWnJJaFFvQUFBaEdFRUFJUTBnQmtFSGNRc2hDQ0FISUJCcUlRWWdFeUFnU1FSL0lBWUZJQk1nQmtFRGRtc2lFeWdBQUNFWFFRQWhDU0FHUVFkeEN5RUhJQXdnR21vaERDQUpJQTF5SVJCQkF5RU5BbjhnRWlBZlNRUkFJQXdoQmtFRERBRUxJQXhCQjNFaEJpQVNJQXhCQTNackloSW9BQUFoRmtFQUN5QWJJQ0pxSVF3Z0VISWhFQ0FSSUI1SkJIOGdEQVVnRVNBTVFRTjJheUlSS0FBQUlSVkJBQ0VOSUF4QkIzRUxJUWtnQkVFQ2FpRUVJQUpCQW1vaEFpQURRUUpxSVFNZ0FFRUNhaUVBSUEwZ0VISkZJUTBNQVFzTElBVWdCellDTENBRklBZzJBa0FnQlNBR05nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUFnRGtzZ0F5QVBTM0lOQUVGc0lRa2dBaUFaU3cwQklBNUJBMnNoQ1FOQUlBVkJQR29RRHlBQUlBbFBja1VFUUNBS0lBVW9BandpQmlBRktBSkFJZ2QwSUF0MlFRRjBhaUlJTFFBQklRd2dBQ0FJTFFBQU9nQUFJQW9nQmlBSElBeHFJZ1owSUF0MlFRRjBhaUlITFFBQUlRZ2dCU0FHSUFjdEFBRnFOZ0pBSUFBZ0NEb0FBU0FBUVFKcUlRQU1BUXNMQTBBZ0JVRThhaEFQSVFjZ0JTZ0NQQ0VHSUFVb0FrQWhDU0FBSUE1UElBZHlSUVJBSUFvZ0JpQUpkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdDU0FHTFFBQmFqWUNRQ0FBSUFjNkFBQWdBRUVCYWlFQURBRUxDd05BSUFBZ0RrOUZCRUFnQ2lBR0lBbDBJQXQyUVFGMGFpSUhMUUFCSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQ1dvaENRd0JDd3NnRDBFRGF5RUFBMEFnQlVFb2FoQVBJQUFnQTAxeVJRUkFJQW9nQlNnQ0tDSUdJQVVvQWl3aUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBRElBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFpd2dBeUFJT2dBQklBTkJBbW9oQXd3QkN3c0RRQ0FGUVNocUVBOGhCeUFGS0FJb0lRWWdCU2dDTENFQUlBTWdEMDhnQjNKRkJFQWdDaUFHSUFCMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBQUlBWXRBQUZxTmdJc0lBTWdCem9BQUNBRFFRRnFJUU1NQVFzTEEwQWdBeUFQVDBVRVFDQUtJQVlnQUhRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FESUFjdEFBQTZBQUFnQTBFQmFpRURJQUFnQ0dvaEFBd0JDd3NnR1VFRGF5RURBMEFnQlVFVWFoQVBJQUlnQTA5eVJRUkFJQW9nQlNnQ0ZDSUdJQVVvQWhnaUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBQ0lBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFoZ2dBaUFJT2dBQklBSkJBbW9oQWd3QkN3c0RRQ0FGUVJScUVBOGhCeUFGS0FJVUlRWWdCU2dDR0NFRElBSWdHVThnQjNKRkJFQWdDaUFHSUFOMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBRElBWXRBQUZxTmdJWUlBSWdCem9BQUNBQ1FRRnFJUUlNQVFzTEEwQWdBaUFaVDBVRVFDQUtJQVlnQTNRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FDSUFjdEFBQTZBQUFnQWtFQmFpRUNJQU1nQ0dvaEF3d0JDd3NEUUNBRkVBOGdCQ0FkVDNKRkJFQWdDaUFGS0FJQUlnSWdCU2dDQkNJR2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBS0lBSWdCaUFJYWlJQ2RDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0FpQUdMUUFCYWpZQ0JDQUVJQWM2QUFFZ0JFRUNhaUVFREFFTEN3TkFJQVVRRHlFSElBVW9BZ0FoQmlBRktBSUVJUUlnQkNBY1R5QUhja1VFUUNBS0lBWWdBblFnQzNaQkFYUnFJZ1l0QUFBaEJ5QUZJQUlnQmkwQUFXbzJBZ1FnQkNBSE9nQUFJQVJCQVdvaEJBd0JDd3NEUUNBRUlCeFBSUVJBSUFvZ0JpQUNkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUVRUUZxSVFRZ0FpQUlhaUVDREFFTEMwRnNRV3hCYkVGc1FXeEJiRUZzUVd3Z0FTQUNRU0JIR3lBRktBSUlJQVVvQWd4SEd5QURRU0JIR3lBRktBSWNJQVVvQWlCSEd5QUFRU0JIR3lBRktBSXdJQVVvQWpSSEd5QUpRU0JIR3lBRktBSkVJQVVvQWtoSEd5RUpEQUVMUVd3aENRc2dCVUhRQUdva0FDQUpDMWdCQTM4Q1FDQUFLQUtRNndFaUFVVU5BQ0FCS0FJQUlBRkJ0TlVCYWlnQ0FDSUNJQUZCdU5VQmFpZ0NBQ0lERUJNZ0FnUkFJQU1nQVNBQ0VRSUFEQUVMSUFFUUJnc2dBRUVBTmdLZzZ3RWdBRUlBTndPUTZ3RUw2UU1DQkg4Q2ZpQUFRUUJCS0JBRElRUWdBa0VCUVFVZ0F4c2lBRWtFUUNBQUR3c2dBVVVFUUVGL0R3dEJBU0VHQWtBQ1FDQURRUUZHRFFBZ0F5RUdJQUVvQUFBaUJVR282cjVwUmcwQVFYWWhBeUFGUVhCeFFkRFV0TUlCUncwQlFRZ2hBeUFDUVFoSkRRRWdBVFVBQkNFSUlBUkJBVFlDRkNBRUlBZzNBd0JCQUE4TElBRWdBaUFHRUJvaUF5QUNTdzBBSUFRZ0F6WUNHRUZ5SVFNZ0FDQUJhaUlGUVFGckxRQUFJZ0pCQ0hFTkFDQUNRU0J4SWdaRkJFQkJjQ0VESUFVdEFBQWlCVUduQVVzTkFTQUZRUWR4clVJQklBVkJBM1pCQ21xdGhpSUlRZ09JZmlBSWZDRUpJQUJCQVdvaEFBc2dBa0VHZGlFRklBSkJBblpCQUNFREFrQUNRQUpBQWtBZ0FrRURjVUVCYXc0REFBRUNBd3NnQUNBQmFpMEFBQ0VESUFCQkFXb2hBQXdDQ3lBQUlBRnFMd0FBSVFNZ0FFRUNhaUVBREFFTElBQWdBV29vQUFBaEF5QUFRUVJxSVFBTFFRRnhJUUlDZmdKQUFrQUNRQUpBSUFWQkFXc09Bd0VDQXdBTFFuOGdCa1VOQXhvZ0FDQUJhakVBQUF3REN5QUFJQUZxTXdBQVFvQUNmQXdDQ3lBQUlBRnFOUUFBREFFTElBQWdBV29wQUFBTElRZ2dCQ0FDTmdJZ0lBUWdBellDSENBRUlBZzNBd0JCQUNFRElBUkJBRFlDRkNBRUlBZ2dDU0FHR3lJSU53TUlJQVJDZ0lBSUlBZ2dDRUtBZ0FoYUd6NENFQXNnQXd0ZkFRRi9RYmgvSVFNZ0FVRUJRUVVnQWhzaUFrOEVmeUFBSUFKcVFRRnJMUUFBSWdCQkEzRkJBblJCb0I1cUtBSUFJQUpxSUFCQkJIWkJESEZCc0I1cUtBSUFhaUFBUVNCeElnRkZhaUFCUVFWMklBQkJ3QUJKY1dvRlFiaC9Dd3NNQUNBQUlBRWdBa0VBRUJrTGx3TUNCWDhDZmlNQVFVQnFJZ1FrQUFKQUEwQWdBVUVGVHdSQUFrQWdBQ2dBQUVGd2NVSFExTFRDQVVZRVFFSitJUWNnQVVFSVNRMEVJQUFvQUFRaUFrRjNTdzBFSUFKQkNHb2lBeUFCU3cwRUlBSkJnWDlKRFFFTUJBc2dCRUVZYWlBQUlBRVFHeUVDUW40Z0JDa0RHRUlBSUFRb0FpeEJBVWNiSUFJYklnZENmVllOQXlBSElBaDhJZ2dnQjFSQ2ZpRUhEUU1DUUFKQUlBRkJDRWtOQUNBQUtBQUFRWEJ4UWREVXRNSUJSdzBBSUFBb0FBUWlBa0YzU3cwRlFiaC9JQUpCQ0dvaUFpQUJJQUpKR3lFRERBRUxJQVJCR0dvZ0FDQUJFQnNpQWtHSWYwc0VRQ0FDSVFNTUFRdEJ1SDhoQXlBQ0RRQWdBU0FFS0FJd0lnSnJJUVVnQUNBQ2FpRUdBMEFnQmlBRklBUkJER29RSFNJRFFZaC9TdzBCSUFOQkEyb2lBaUFGU3dSQVFiaC9JUU1NQWdzZ0JTQUNheUVGSUFJZ0Jtb2hCaUFFS0FJUVJRMEFDeUFFS0FJNEJIOUJ1SDhoQXlBRlFRUkpEUUVnQmtFRWFnVWdCZ3NnQUdzaEF3c2dBMEdJZjBzTkF3c2dBU0FEYXlFQklBQWdBMm9oQUF3QkN3dENmaUFJSUFFYklRY0xJQVJCUUdza0FDQUhDMlFCQVg5QnVIOGhBd0pBSUFGQkEwa05BQ0FBTFFBQ0lRRWdBaUFBTHdBQUlnQkJBWEUyQWdRZ0FpQUFRUUYyUVFOeElnTTJBZ0FnQWlBQUlBRkJFSFJ5UVFOMklnQTJBZ2dDUUFKQUlBTkJBV3NPQXdJQkFBRUxRV3dQQ3lBQUlRTUxJQU1MUkFFQ2Z5QUJJQUlvQWdRaUF5QUJLQUlFYWlJRU5nSUVJQUFnQTBFQ2RFR2dIV29vQWdBZ0FTZ0NBRUVBSUFScmRuRTJBZ0FnQVJBUEdpQUFJQUpCQ0dvMkFnUUx6Z0VCQm45QnVuOGhDZ0pBSUFJb0FnUWlDQ0FDS0FJQUlnbHFJZzBnQVNBQWEwc05BRUZzSVFvZ0NTQUVJQU1vQWdBaUMydExEUUFnQUNBSmFpSUVJQUlvQWdnaURHc2hBaUFBSUFGQklHc2lBQ0FMSUFsQkFCQWdJQU1nQ1NBTGFqWUNBQUpBQWtBZ0JDQUZheUFNVHdSQUlBSWhCUXdCQ3lBTUlBUWdCbXRMRFFJZ0J5QUhJQUlnQldzaUFtb2lBU0FJYWs4RVFDQUVJQUVnQ0JBS0dnd0NDeUFDSUFocUlRZ2dCQ0FCUVFBZ0Ftc1FDaUFDYXlFRUN5QUVJQUFnQlNBSVFRRVFJQXNnRFNFS0N5QUtDOGNFQVFKL0lBQWdBMm9oQmdKQUlBTkJCMHdFUUFOQUlBQWdCazhOQWlBQUlBSXRBQUE2QUFBZ0FFRUJhaUVBSUFKQkFXb2hBZ3dBQ3dBTElBUkJBVVlFUUFKQUlBQWdBbXNpQlVFSFRRUkFJQUFnQWkwQUFEb0FBQ0FBSUFJdEFBRTZBQUVnQUNBQ0xRQUNPZ0FDSUFBZ0FpMEFBem9BQXlBQUlBSWdCVUVDZENJRlFjQWVhaWdDQUdvaUFpZ0FBRFlBQkNBQ0lBVkI0QjVxS0FJQWF5RUNEQUVMSUFBZ0Fpa0FBRGNBQUFzZ0FrRUlhaUVDSUFCQkNHb2hBQXNnQVNBR1R3UkFJQUFnQTJvaEFTQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUEwQWdBQ0FDS1FBQU53QUFJQUpCQ0dvaEFpQUFRUWhxSWdBZ0FVa05BQXdEQ3dBTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dBMEVSU1EwQklBQkJFR29oQUFOQUlBQWdBaWtBRURjQUFDQUFJQUlwQUJnM0FBZ2dBQ0FDS1FBZ053QVFJQUFnQWlrQUtEY0FHQ0FDUVNCcUlRSWdBRUVnYWlJQUlBRkpEUUFMREFFTEFrQWdBQ0FCU3dSQUlBQWhBUXdCQ3lBQklBQnJJUVVDUUNBRVFRRkhJQUFnQW10QkQwcHlSUVJBSUFJaEF3TkFJQUFnQXlrQUFEY0FBQ0FEUVFocUlRTWdBRUVJYWlJQUlBRkpEUUFMREFFTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dCVUVSU0EwQUlBQkJFR29oQUNBQ0lRTURRQ0FBSUFNcEFCQTNBQUFnQUNBREtRQVlOd0FJSUFBZ0F5a0FJRGNBRUNBQUlBTXBBQ2czQUJnZ0EwRWdhaUVESUFCQklHb2lBQ0FCU1EwQUN3c2dBaUFGYWlFQ0N3TkFJQUVnQms4TkFTQUJJQUl0QUFBNkFBQWdBVUVCYWlFQklBSkJBV29oQWd3QUN3QUxDNjRIQWdWL0FYNGpBRUdBQVdzaUVTUUFJQkVnQXpZQ2ZFRi9JUThDUUFKQUFrQUNRQUpBSUFJT0JBRUFBd0lFQ3lBR1JRUkFRYmgvSVE4TUJBdEJiQ0VQSUFVdEFBQWlBaUFEU3cwRElBZ2dBa0VDZENJQ2FpZ0NBQ0VESUFJZ0Iyb29BZ0FoQWlBQVFRQTZBQXNnQUVJQU53SUFJQUFnQWpZQ0RDQUFJQU02QUFvZ0FFRUFPd0VJSUFFZ0FEWUNBRUVCSVE4TUF3c2dBU0FKTmdJQVFRQWhEd3dDQ3lBS1JRUkFRV3doRHd3Q0MwRUFJUThnQzBVZ0RFRVpTSElOQVVFSUlBUjBRUWhxSVFCQkFDRURBMEFnQUNBRFRRMENJQU5CUUdzaEF3d0FDd0FMUVd3aER5QVJJQkZCL0FCcUlCRkIrQUJxSUFVZ0JoQU1JZ05CaUg5TERRQWdFU2dDZUNJQ0lBUkxEUUFnRVNnQ2ZFRUJhaUVKSUFCQkNHb2hDMEdBZ0FJZ0FuUkJFSFVoQlVFQklSQkJBU0FDZENJUFFRRnJJZ29oRWdOQUlBa2dEa2NFUUFKQUlCRWdEa0VCZENJRWFpOEJBQ0lNUWYvL0EwWUVRQ0FMSUJKQkEzUnFJQTQyQWdRZ0VrRUJheUVTUVFFaERBd0JDeUFRUVFBZ0JTQU13VW9iSVJBTElBUWdEV29nRERzQkFDQU9RUUZxSVE0TUFRc0xJQUFnQWpZQ0JDQUFJQkEyQWdBQ1FDQUtJQkpHQkVBZ0RVSHFBR29oQmtFQUlSQkJBQ0VNQTBBZ0NTQVFSZ1JBSUE5QkEzWWdEMEVCZG1wQkEyb2lCVUVCZENFRVFRQWhERUVBSVJJRFFFRUFJUTRnRHlBU1RRMEVBMEFnRGtFQ1J3UkFJQXNnQlNBT2JDQU1haUFLY1VFRGRHb2dCaUFPSUJKcWFpMEFBRFlDQkNBT1FRRnFJUTRNQVFzTElCSkJBbW9oRWlBRUlBeHFJQXB4SVF3TUFBc0FCU0FSSUJCQkFYUnFMZ0VBSVFVZ0JpQU1haUlFSUJNM0FBQkJDQ0VPQTBBZ0JTQU9TZ1JBSUFRZ0Rtb2dFemNBQUNBT1FRaHFJUTRNQVFzTElCTkNnWUtFaUpDZ3dJQUJmQ0VUSUJCQkFXb2hFQ0FGSUF4cUlRd01BUXNBQ3dBTElBOUJBM1lnRDBFQmRtcEJBMm9oQlVFQUlSQkJBQ0VPQTBBZ0NTQVFSZzBCUVFBaERDQVJJQkJCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQU1Sd1JBSUFzZ0RrRURkR29nRURZQ0JBTkFJQVVnRG1vZ0NuRWlEaUFTU3cwQUN5QU1RUUZxSVF3TUFRc0xJQkJCQVdvaEVBd0FDd0FMSUFKQkFXb2hCVUVBSVF3RFFDQU1JQTlIQkVBZ0RTQUxJQXhCQTNScUlna29BZ1FpQkVFQmRHb2lBaUFDTHdFQUlnWkJBV283QVFBZ0NTQUZJQVpuUVdCemFpSUNPZ0FESUFrZ0JpQUNkQ0FQYXpzQkFDQUpJQWdnQkVFQ2RDSUNhaWdDQURvQUFpQUpJQUlnQjJvb0FnQTJBZ1FnREVFQmFpRU1EQUVMQ3lBQklBQTJBZ0FnQXlFUEN5QVJRWUFCYWlRQUlBOEw3Vm9DTzM4R2ZpTUFRZUFCYXlJRUpBQUNRRUd3N0FrUUJTSUZSUVJBUVVBaEJ3d0JDeUFGUWdBM0F2VHFBU0FGUVFBMkFzVHJBU0FGUVFBMkFyVHJBU0FGUWdBM0FwenJBU0FGUVFBMkFyanBBU0FGUVFBMkFxenNDU0FGUWdBM0F0VHJBU0FGUWdBM0FxenJBU0FGUWdBM0E0anJBU0FGUWdBM0F1VHFBU0FGUWdBM0F1VHJBU0FGUVlHQWdNQUFOZ0s4NndFZ0JVSUFOd0trNndFZ0JVSDg2Z0ZxUVFBMkFnQWdCVUdRNndGcVFnQTNBd0FnQlJBWUlBVkJyTlVCYWlFVUlBVkIrT3NCYWlFY0lBVkJzT29CYWlFaUlBVkJvREJxSVNvZ0JVR1lJR29oS3lBRlFhalFBR29oSGlBRlFSQnFJU3dnQlVFSWFpRW9JQVZCQkdvaExTQUZRY0RwQVdvaEtTQUZRWWpyQVdvZ0JFR1VBV29oTHlBRVFZd0JhaUV3SUFSQmhBRnFJVEVnQkVIY0FHb2hNaUFFUWRRQWFpRXpJQVJCekFCcUlUUWdBQ0VkQWtBQ1FBSkFBa0FDUUFOQVFRRkJCU0FGS0FMazZnRWJJUVlDUUFOQUlBTWdCa2tOQVNBQ0tBQUFRWEJ4UWREVXRNSUJSZ1JBUWJoL0lRY2dBMEVJU1EwSUlBSW9BQVFpRGtGM1N3UkFRWEloQnd3SkN5QURJQTVCQ0dvaUNVa05DQ0FPUVlCL1N3UkFJQWtoQnd3SkN5QURJQWxySVFNZ0FpQUphaUVDREFFTEN5QUZRZ0EzQXF6cEFTQUZRZ0EzQStqcEFTQUZRUUEyQXBqckFTQUZRZ0EzQTREcUFTQUZRZ00zQS9qcEFTQUZRYlRwQVdwQ0FEY0NBQ0FGUWZEcEFXcENBRGNEQUNBRlFhalFBR29pQ1VHTWdJRGdBRFlDQUNBRlFhelFBV3BCNEJJcEFnQTNBZ0FnQlVHMDBBRnFRZWdTS0FJQU5nSUFJQVVnQlVFUWFqWUNBQ0FGSUFWQm9EQnFOZ0lFSUFVZ0JVR1lJR28yQWdnZ0JTQUpOZ0lNSUFWQkFVRUZJQVVvQXVUcUFSczJBcnpwQVFKQUlBRkZEUUFnQlNnQ3JPa0JJZ2tnSFVZTkFDQUZJQWsyQXJqcEFTQUZJQjAyQXF6cEFTQUZLQUt3NlFFaERpQUZJQjAyQXJEcEFTQUZJQjBnRGlBSmEybzJBclRwQVF0QnVIOGhDU0FEUVFWQkNTQUZLQUxrNmdFaUJodEpEUVVnQWtFQlFRVWdCaHNnQmhBYUlnNUJpSDlMQkVBZ0RpRUpEQVVMSUFNZ0RrRURha2tOQlNBcElBSWdEaUFHRUJraUJrR0lmMHNFUUNBR0lRa01CUXNnQmcwRkFrQUNRQ0FGS0FLbzZ3RkJBVWNOQUNBRktBS2s2d0VpQ1VVTkFDQUZLQUtVNndGRkRRQWdDU2dDQkVFQmF5SUhJQVVvQXR6cEFTSUtyVUtIbGErdm1MYmVtNTUvZmtMSno5bXk4ZVc2NmllRlFoZUpRcy9XMDc3U3g2dlpRbjVDK2ZQZDhabjJtYXNXZkNJL1FpR0lJRCtGUXMvVzA3N1N4NnZaUW40aVAwSWRpQ0EvaFVMNTg5M3htZmFacXhaK0lqOUNJSWdnUDRXbmNTRUdJQWtvQWdBaEZRTkFRUUFoQ0FKQUlCVWdCa0VDZEdvb0FnQWlDVVVOQUNBSktBSUlRUWhKRFFBZ0NTZ0NCQ0lTS0FBQVFiZkl3dUYrUncwQUlCSW9BQVFoQ0FzZ0NDQUtSd1JBSUFZZ0IzRkJBV29oQmlBSURRRUxDeUFKUlEwQUlBVVFHQ0FGUVg4MkFxRHJBU0FGSUFrMkFwVHJBU0FGSUFVb0F0enBBU0lJTmdLWTZ3RU1BUXNnQlNnQzNPa0JJUWdMQWtBZ0NFVU5BQ0FGS0FLWTZ3RWdDRVlOQUVGZ0lRa01CZ3NDUUNBRktBTGc2UUVFUUNBRklBVW9BdWpxQVNJSlJUWUM3T29CSUFrTkFTQUZRdm5xME5EbnlhSGs0UUEzQTZqcUFTQUZRZ0EzQTZEcUFTQUZRcy9XMDc3U3g2dlpRamNEbU9vQklBVkMxdXVDN3VyOWlmWGdBRGNEa09vQklBVkNBRGNEaU9vQklDSkJBRUVvRUFNYURBRUxJQVZCQURZQzdPb0JDeUFCSUIxcUlTVWdCU0FGS1FQbzZRRWdEcTE4TndQbzZRRWdBeUFPYXlFRElBSWdEbW9oQWlBZElRNERRQ0FDSUFNZ0JFRXNhaEFkSWhWQmlIOUxCRUFnRlNFSkRBWUxJQU5CQTJzaU5TQVZTUTBFSUFKQkEyb2hHMEZzSVFrQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQ0FFS0FJc0RnTUNBUUFWQ3lBVlFmLy9CMHNORXlBVlFRTkpEUklnQlNrRHlPa0JJVDhDUUFKQUlCc3RBQUFpQ1VFRGNTSWFRUUZyRGdNR0FRQUhDeUFGS0FLQTZnRU5BRUZpSVFrTUZRc2dGVUVGU1EwU0lCc29BQUFoQXdKL0FrQUNRQUpBSUFsQkFuWkJBM0VpQ1VFQ2F3NENBUUlBQ3lBSlFRQkhJUWNnQTBFRWRrSC9CM0VoQzBFRElRWWdBMEVPZGtIL0IzRU1BZ3RCQkNFR0lBTkJCSFpCLy84QWNTRUxRUUVoQnlBRFFSSjJEQUVMSUFOQkJIWkIvLzhQY1NJTFFZQ0FDRXNORTBFQklRZEJCU0VHSUFJdEFBZEJDblFnQTBFV2RuSUxJZ2dnQm1vaUNTQVZTdzBTQWtBZ0MwR0JCa2tOQUNBRktBS2M2d0ZGRFFCQkFDRURBMEFnQTBHRGdBRkxEUUVnQTBGQWF5RUREQUFMQUFzZ0JpQWJhaUVQSUJwQkEwY05CaUFGS0FJTUlnSXRBQUZCQ0hRaEF5QUhEUWNnQTBVTkNDQUVRZkFBYWlBUElBZ1FEU0lEUVloL1N3MEpJQUpCQkdvaEJpQUxJQnhxSWhKQkEyc2hDa0VBSUFJdkFRSnJRUjl4SVFjZ0hDRURBMEFnQkVId0FHb1FEMFVnQXlBS1NYRUVRQ0FESUFZZ0JDZ0NjQ0lJSUFRb0FuUWlEM1FnQjNaQkFuUnFJZ0l2QVFBN0FBQWdBeUFDTFFBRGFpSURJQVlnQ0NBUElBSXRBQUpxSWdoMElBZDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0NDQUNMUUFDYWpZQ2RDQURJQUl0QUFOcUlRTU1BUVVnRWtFQ2F5RUlBMEFnQkVId0FHb1FEeUVQSUFRb0FuQWhDaUFFS0FKMElRSWdBeUFJU3lBUGNrVUVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lDaThCQURzQUFDQUVJQUlnQ2kwQUFtbzJBblFnQXlBS0xRQURhaUVEREFFTEN3TkFJQU1nQ0UwRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUR5OEJBRHNBQUNBRElBOHRBQU5xSVFNZ0FpQVBMUUFDYWlFQ0RBRUxDd0pBSUFNZ0VrOE5BQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lBeTBBQURvQUFDQURMUUFEUVFGR0JFQWdBaUFETFFBQ2FpRUNEQUVMSUFKQkgwc05BRUVnSUFJZ0F5MEFBbW9pQWlBQ1FTQlBHeUVDQzBGc1FXd2dDeUFFS0FKNElBUW9BbnhIR3lBQ1FTQkhHeUVEREFzTEFBc0FDeUFFS0FJMElnSWdKU0FPYTBzTkNpQU9SUVJBUVFBaENTQUNEUUlNRGdzZ0RpQWJMUUFBSUFJUUF4b2dBaUVKREF3TElCVWdKU0FPYTBzTkNTQU9EUUZCQUNFSklCVkZEUXdMUWJaL0lRa01FUXNnRGlBYklCVVFBaG9nRlNFSkRBb0xJQndnR3dKL0FrQUNRQUpBSUFsQkFuWkJBM0ZCQVdzT0F3RUFBZ0FMSUFsQkEzWWhBMEVCREFJTElCc3ZBQUJCQkhZaEEwRUNEQUVMSUJWQkJFa05EaUFDTHdBRElBSXRBQVZCRUhSeUlnSkJqNENBQVVzTkRpQUNRUVIySVFOQkF3c2lBbW90QUFBZ0EwRWdhaEFESVFrZ0JTQUROZ0tBNndFZ0JTQUpOZ0x3NmdFZ0FrRUJhaUVKREFVTElCVUNmd0pBQWtBQ1FDQUpRUUoyUVFOeFFRRnJEZ01CQUFJQUN5QUpRUU4ySVFOQkFRd0NDeUFiTHdBQVFRUjJJUU5CQWd3QkN5QUNMd0FESUFJdEFBVkJFSFJ5UVFSMklRTkJBd3NpQWlBRGFpSUpRU0JxU1FSQUlBa2dGVXNORFNBY0lBSWdHMm9nQXhBQ0lRSWdCU0FETmdLQTZ3RWdCU0FDTmdMdzZnRWdBaUFEYWlJQ1FnQTNBQmdnQWtJQU53QVFJQUpDQURjQUNDQUNRZ0EzQUFBTUJRc2dCU0FETmdLQTZ3RWdCU0FDSUJ0cU5nTHc2Z0VNQkFzZ0IwVUVRQ0FlSUE4Z0NDQVVFQlFpQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZTRUREQU1MSUF0RklBaEZjZzBMSUF0QkNIWWlBeUFJSUF0SkJIOGdDRUVFZENBTGJnVkJEd3RCR0d3aUFrR01DR29vQWdCc0lBSkJpQWhxS0FJQWFpSUdRUU4ySUFacUlBSkJnQWhxS0FJQUlBSkJoQWhxS0FJQUlBTnNha2tFUUNNQVFSQnJJaEFrQUNBZUtBSUFJUU1nRkVId0JHcEJBRUhzQUJBRElRWkJWQ0VDQWtBZ0EwSC9BWEVpREVFTVN3MEFBa0FnRkVIY0NXb2dCaUFRUVFocUlCQkJER29nRHlBSUlCUkIzQXRxSWhjUUN5SVNRWWgvU3cwQUlCQW9BZ3dpQmlBTVN3MEJJQlJCcUFWcUlRMGdGRUdrQldvaE5pQWVRUVJxSVJFZ0EwR0FnSUI0Y1NFM0lBWkJBV29pRXlFQ0lBWWhBd05BSUFJaUIwRUJheUVDSUFNaUNrRUJheUVESUJRZ0NrRUNkR29vQXZBRVJRMEFDMEVCSUFjZ0IwRUJUUnNoRmtFQUlRZEJBU0VDQTBBZ0FpQVdSd1JBSUJRZ0FrRUNkQ0lEYWlnQzhBUWhHQ0FESUExcUlBYzJBZ0FnQWtFQmFpRUNJQWNnR0dvaEJ3d0JDd3NnRFNBSE5nSUFRUUFoQWlBUUtBSUlJUU1EUUNBQ0lBTkhCRUFnRFNBQ0lCUnFRZHdKYWkwQUFDSVlRUUowYWlJWklCa29BZ0FpR1VFQmFqWUNBQ0FVSUJsQkFYUnFJaGtnR0RvQTNRVWdHU0FDT2dEY0JTQUNRUUZxSVFJTUFRc0xRUUFoQXlBTlFRQTJBZ0FnRENBR1FYOXphaUVHUVFFaEFnTkFJQUlnRmtjRVFDQVVJQUpCQW5ScUlnMGdBellDQUNBTktBTHdCQ0FDSUFacWRDQURhaUVESUFKQkFXb2hBZ3dCQ3dzZ0RDQVRJQXBySWdaclFRRnFJUW9nQmlFREEwQWdBeUFLU1FSQUlCUWdBMEUwYkdvaERVRUJJUUlEUUNBQ0lCWkhCRUFnRFNBQ1FRSjBJaGhxSUJRZ0dHb29BZ0FnQTNZMkFnQWdBa0VCYWlFQ0RBRUxDeUFEUVFGcUlRTU1BUXNMSUJjZ0ZFRTBFQUloT0NBVVFaQU1haUU1SUJNZ0RHc2hPaUFVUWR3RmFpRVhRUUFoQ2dOQUFrQUNRQ0FISUFwSEJFQkJBU0FNSUJNZ0Z5QUtRUUYwYWlJQ0xRQUJJZzFySWdOckloaDBJUmtnQWkwQUFDRVdJRGdnRFVFQ2RHb2lIeWdDQUNFQ0lBWWdHRTBFUUNBMlFRRWdBeUE2YWlJTklBMUJBVXdiSWlCQkFuUWlKR29vQWdBaERTQTVJQlFnQTBFMGJHcEJOQkFDSVNFZ0RVRUJkQ0VtSUJFZ0FrRUNkR29oSXlBZ1FRRk5EUUlnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFZ0lDRWdKR29vQWdBaEpFRUFJUUlEUUNBQ0lDUkdEUU1nSXlBQ1FRSjBhaUFnTmdFQUlBSkJBV29oQWd3QUN3QUxJQUlnQWlBWmFpSU5JQUlnRFVzYklRMGdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVEQTBBZ0FpQU5SZzBESUJFZ0FrRUNkR29nQXpZQkFDQUNRUUZxSVFJTUFBc0FDeUFlSUF4QkVIUWdOM0lnREhKQmdBSnlOZ0lBREFNTElBY2dEV3NoSkNBWElDWnFJU1pCQUNFTkEwQWdEU0FrUmcwQlFRRWdHQ0FUSUNZZ0RVRUJkR29pSnkwQUFTSUNheUk3YTNRaVBDQWhJQUpCQW5ScUlpQW9BZ0FpQW1vaFBTQURJRHRxUVJCMFFZQ0EvQWR4SUNjdEFBQkJDSFJ5SUJaeVFZQ0FnQkJ5SVNjRFFDQWpJQUpCQW5ScUlDYzJBUUFnQWtFQmFpSUNJRDFKRFFBTElDQWdJQ2dDQUNBOGFqWUNBQ0FOUVFGcUlRME1BQXNBQ3lBZklCOG9BZ0FnR1dvMkFnQWdDa0VCYWlFS0RBQUxBQXNnRWlFQ0N5QVFRUkJxSkFBZ0FrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGaUVEREFNTElCNGdEeUFJSUJRUUZDSUNRWWgvU3lBQ0lBaFBjZzBMSUJ3Z0N5QUNJQTlxSUFnZ0Ftc2dIaEFYSVFNTUFnc2dBd1JBSUJ3Z0N5QVBJQWdnQWhBV0lRTU1BZ3NnSENBTElBOGdDQ0FDRUJjaEF3d0JDeUFjSUFzZ0R5QUlJQUlRRlNFREN5QURRWWgvU3cwSUlBVWdDellDZ09zQklBVWdIRFlDOE9vQklBVkJBVFlDZ09vQklCcEJBa1lFUUNBRklCNDJBZ3dMSUFzZ0hHb2lBa0lBTndBQUlBSkNBRGNBR0NBQ1FnQTNBQkFnQWtJQU53QUlJQWxCaUg5TERRb0xJQWtnRlVZTkNDQVZJQWxySVFZZ0JTZ0NuT3NCSVFvQ1FDQUpJQnRxSWdNdEFBQWlEMFVFUUVFQklRSkJBQ0VQUWJoL0lRa2dCa0VCUmcwQkRBc0xBbjhnQTBFQmFpQVB3Q0lDUVFCT0RRQWFJQUpCZjBZRVFDQUdRUU5JRFFzZ0F5OEFBVUdBL2dGcUlROGdBMEVEYWd3QkN5QUdRUUpJRFFvZ0F5MEFBU0FQUVFoMGNrR0FnQUpySVE4Z0EwRUNhZ3NoRWtHNGZ5RUpJQkpCQVdvaUFpQVZJQnRxSWdkTERRb2dMQ0FGSUJJdEFBQWlFa0VHZGtFalFRa2dBaUFISUFKclFjQVFRZEFSUWZBU0lBVW9Bb1RxQVNBS0lBOGdGQkFoSWdsQmlIOUxEUWdnS3lBb0lCSkJCSFpCQTNGQkgwRUlJQUlnQ1dvaUFpQUhJQUpyUVlBTFFZQU1RWUFYSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUNFR0lmMHNOQ0VGc0lRa2dLaUF0SUJKQkFuWkJBM0ZCTkVFSklBSWdDR29pQWlBSElBSnJRWUFOUWVBT1FaQVpJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQjBHSWYwc05DaUFDSUFkcUlBTnJJZ0loQ1NBQ1FZaC9TdzBLQ3lBT0lBOUJBRXh5RFFFTFFicC9JUWtNQ0FzZ0pTQU9heUVKSUFZZ0Ftc2hCaUFDSUFOcUlRY0NRQUpBQWtBZ0NrVUVRQ0FQUVFsSUlBVXBBOGpwQVVLQmdJQUlWSElOQWlBb0tBSUFJZ0pCQ0dvaEVpQUNLQUlFSVFwQkFDRURRUUFoQWdOQUlBTWdDblpGQkVBZ0FpQVNJQU5CQTNScUxRQUNRUlpMYWlFQ0lBTkJBV29oQXd3QkN3c2dCVUVBTmdLYzZ3RWdBa0VJSUFwcmRFRVVUdzBCREFNTElBVkJBRFlDbk9zQkN5QUVJQVVvQXZEcUFTSUROZ0xjQVNBSklBNXFJUllnQXlBRktBS0E2d0ZxSVJjQ1FDQVBSUVJBSUE0aEJ3d0JDeUFGS0FLNDZRRWhHaUFGS0FLMDZRRWhHQ0FGS0FLdzZRRWhFaUFGUVFFMkFvVHFBVUVBSVFNRFFDQURRUU5IQkVBZ0JDQURRUUowSWdKcUlBSWdCV3BCck5BQmFpZ0NBRFlDWkNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUVRocUlnSWdCeUFHRUExQmlIOUxEUU5CQ0NBUElBOUJDRTRiSVI4Z05DQUNJQVVvQWdBUUhpQXpJQUlnQlNnQ0NCQWVJRElnQWlBRktBSUVFQjRnRGlBU2F5RVpRUUFoQ0FOQUlBUkJPR29RRDBFRFJpQUlJQjlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ2RCRUhZaUVVSC9BWEVoQ3lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklneEJFSFlpSVVIL0FYRWhFQ0FFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRWWdRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ2tIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSUtheUlOSUFJZ0FpQU5TeHNpRXlBS2FqWUNQQ0FHSUFRb0FqZ2dDblJCQUNBVGEzWWdBaUFUYXlJVGRHb2hDaUFFUVRocUVBOGFJQUlnRFUwTkFTQUVJQVFvQWp3aUFpQVRhallDUENBRUtBSTRJQUowUVFBZ0UydDJJQXBxSVFvTUFRc2dCQ0FDSUFRb0Fqd2lEV28yQWp3Z0JDZ0NPQ0FOZEVFQUlBcHJkaUFHYWlFS0lBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlBbzJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FEQkVBZ0JDZ0NaQ0VLREFNTElBUW9BbWdoQ2d3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBWWdBMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ1pGSUFacUlRb2dBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUFvMkFtUUxweUVDSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lCQnFOZ0k4SUFRb0FqZ2dCblJCQUNBaGEzWWdBbW9oQWdzZ0N5QVFha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQXRxTmdJOElBUW9BamdnQm5SQkFDQVJhM1lnQTJvaEF3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUJrRUFJQWRCR0hZaUN5QUVLQUk4YWlJUWEzWWdDMEVDZEVHZ0hXb29BZ0J4SUFkQi8vOERjV28yQWt3Z0JDQVFJQXhCR0hZaUIyb2lDellDUENBRUlBZEJBblJCb0IxcUtBSUFJQVpCQUNBTGEzWnhJQXhCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnWkJHSFlpQnlBRUtBSThhaUlMTmdJOElBUWdCMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQXRyZG5FZ0JrSC8vd054YWpZQ1ZDQUVRZkFBYWlBSVFReHNhaUlHSUFvMkFnZ2dCaUFDTmdJRUlBWWdBellDQUNBSVFRRnFJUWdnQXlBWmFpQUNhaUVaREFFTEN5QUlJQjlJRFFNZ0ZrRWdheUVoSUE0aEJ3TkFJQVJCT0dvUUQwRURSaUFJSUE5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdaQkVIWWlJMEgvQVhFaENpQUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZzFCRUhZaUlFSC9BWEVoRXlBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUU1nUVVJZ2lDQkFRaUNJcHlFTEFrQWdRa0lRaUtjaURFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lNYXlJUklBSWdBaUFSU3hzaUVDQU1hallDUENBRElBUW9BamdnREhSQkFDQVFhM1lnQWlBUWF5SU1kR29oRUNBRVFUaHFFQThhSUFJZ0VVME5BU0FFSUFRb0Fqd2lBaUFNYWpZQ1BDQUVLQUk0SUFKMFFRQWdER3QySUJCcUlSQU1BUXNnQkNBQ0lBUW9BandpRUdvMkFqd2dCQ2dDT0NBUWRFRUFJQXhyZGlBRGFpRVFJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQkEyQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBTEJFQWdCQ2dDWkNFUURBTUxJQVFvQW1naEVBd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQU1nQzBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdORklBTnFJUkFnQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlCQTJBbVFMcHlFTUlFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQk5xTmdJOElBUW9BamdnQW5SQkFDQWdhM1lnREdvaERBc2dDaUFUYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUFwcU5nSThJQVFvQWpnZ0FuUkJBQ0FqYTNZZ0Myb2hDd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lBa0VBSUFaQkdIWWlBeUFFS0FJOGFpSUthM1lnQTBFQ2RFR2dIV29vQWdCeElBWkIvLzhEY1dvMkFrd2dCQ0FLSUExQkdIWWlBMm9pQmpZQ1BDQUVJQU5CQW5SQm9CMXFLQUlBSUFKQkFDQUdhM1p4SUExQi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ0pCR0hZaUF5QUVLQUk4YWlJR05nSThJQVFnQTBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUFacmRuRWdBa0gvL3dOeGFqWUNWQUpBQWtBQ1FDQUVLQUxjQVNJRElBUkI4QUJxSUFoQkIzRkJER3hxSWhNb0FnQWlFV29pSXlBWFN3MEFJQWNnRXlnQ0JDSU5JQkZxSWdwcUlDRkxEUUFnQ2tFZ2FpQVdJQWRyVFEwQkN5QUVJQk1vQWdnMkFoZ2dCQ0FUS1FJQU53TVFJQWNnRmlBRVFSQnFJQVJCM0FGcUlCY2dFaUFZSUJvUUh5RUtEQUVMSUFjZ0VXb2hBaUFUS0FJSUlRWWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQUpBSUJGQkVVa05BQ0FISUFNcEFCQTNBQkFnQnlBREtRQVlOd0FZSUJGQkVHdEJFVWdOQUNBRFFSQnFJUU1nQjBFZ2FpRVJBMEFnRVNBREtRQVFOd0FBSUJFZ0F5a0FHRGNBQ0NBUklBTXBBQ0EzQUJBZ0VTQURLUUFvTndBWUlBTkJJR29oQXlBUlFTQnFJaEVnQWtrTkFBc0xJQUlnQm1zaEF5QUVJQ00yQXR3QklBSWdFbXNnQmtrRVFDQUdJQUlnR0d0TERRY2dHaUFhSUFNZ0Vtc2lBMm9pRVNBTmFrOEVRQ0FDSUJFZ0RSQUtHZ3dDQ3lBRElBMXFJUTBnQWlBUlFRQWdBMnNRQ2lBRGF5RUNJQkloQXdzZ0JrRVFUd1JBSUFJZ0F5a0FBRGNBQUNBQ0lBTXBBQWczQUFnZ0RVRVJTQTBCSUFJZ0RXb2hCaUFDUVJCcUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFHU1EwQUN3d0JDd0pBSUFaQkIwMEVRQ0FDSUFNdEFBQTZBQUFnQWlBRExRQUJPZ0FCSUFJZ0F5MEFBam9BQWlBQ0lBTXRBQU02QUFNZ0FpQURJQVpCQW5RaUJrSEFIbW9vQWdCcUlnTW9BQUEyQUFRZ0F5QUdRZUFlYWlnQ0FHc2hBd3dCQ3lBQ0lBTXBBQUEzQUFBTElBMUJDVWtOQUNBQ0lBMXFJUkVnQWtFSWFpSUdJQU5CQ0dvaUEydEJEMHdFUUFOQUlBWWdBeWtBQURjQUFDQURRUWhxSVFNZ0JrRUlhaUlHSUJGSkRRQU1BZ3NBQ3lBR0lBTXBBQUEzQUFBZ0JpQURLUUFJTndBSUlBMUJHVWdOQUNBQ1FSaHFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBUlNRMEFDd3NnQ2tHSWYwc0VRQ0FLSVFrTUJnVWdFeUFRTmdJSUlCTWdERFlDQkNBVElBczJBZ0FnQ0VFQmFpRUlJQWNnQ21vaEJ5QUxJQmxxSUF4cUlSa01BZ3NBQ3dzZ0NDQVBTQTBESUFnZ0gyc2hCZ05BQWtBZ0JpQVBUZ1JBUVFBaEF3TkFJQU5CQTBZTkFpQUZJQU5CQW5RaUFtcEJyTkFCYWlBQ0lBUnFLQUprTmdJQUlBTkJBV29oQXd3QUN3QUxBa0FDUUFKQUlBUW9BdHdCSWdNZ0JFSHdBR29nQmtFSGNVRU1iR29pQ0NnQ0FDSU1haUlRSUJkTERRQWdCeUFJS0FJRUlnc2dER29pQ21vZ0lVc05BQ0FLUVNCcUlCWWdCMnRORFFFTElBUWdDQ2dDQ0RZQ0tDQUVJQWdwQWdBM0F5QWdCeUFXSUFSQklHb2dCRUhjQVdvZ0Z5QVNJQmdnR2hBZklRb01BUXNnQnlBTWFpRUNJQWdvQWdnaENDQUhJQU1wQUFBM0FBQWdCeUFES1FBSU53QUlBa0FnREVFUlNRMEFJQWNnQXlrQUVEY0FFQ0FISUFNcEFCZzNBQmdnREVFUWEwRVJTQTBBSUFOQkVHb2hBeUFIUVNCcUlRd0RRQ0FNSUFNcEFCQTNBQUFnRENBREtRQVlOd0FJSUF3Z0F5a0FJRGNBRUNBTUlBTXBBQ2czQUJnZ0EwRWdhaUVESUF4QklHb2lEQ0FDU1EwQUN3c2dBaUFJYXlFRElBUWdFRFlDM0FFZ0FpQVNheUFJU1FSQUlBZ2dBaUFZYTBzTkJ5QWFJQm9nQXlBU2F5SURhaUlNSUF0cVR3UkFJQUlnRENBTEVBb2FEQUlMSUFNZ0Myb2hDeUFDSUF4QkFDQURheEFLSUFOcklRSWdFaUVEQ3lBSVFSQlBCRUFnQWlBREtRQUFOd0FBSUFJZ0F5a0FDRGNBQ0NBTFFSRklEUUVnQWlBTGFpRUlJQUpCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQUlnQXkwQUFEb0FBQ0FDSUFNdEFBRTZBQUVnQWlBRExRQUNPZ0FDSUFJZ0F5MEFBem9BQXlBQ0lBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFJZ0F5a0FBRGNBQUFzZ0MwRUpTUTBBSUFJZ0Myb2hEQ0FDUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnREVrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0MwRVpTQTBBSUFKQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF4SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3R0JTQUdRUUZxSVFZZ0J5QUthaUVIREFJTEFBc0xJQVFvQXR3QklRTUxRYnAvSVFrZ0Z5QURheUlDSUJZZ0IydExEUUlnQndSL0lBY2dBeUFDRUFJZ0Ftb0ZRUUFMSUE1cklRa01BZ3NnQlVFQU5nS2M2d0VMSUFRZ0JTZ0M4T29CSWdNMkF0d0JJQWtnRG1vaERDQURJQVVvQW9EckFXb2hFQUpBSUE5RkJFQWdEaUVHREFFTElBVW9BcmpwQVNFTklBVW9BclRwQVNFVElBVW9BckRwQVNFU0lBVkJBVFlDaE9vQlFRQWhBd05BSUFOQkEwY0VRQ0FFSUFOQkFuUWlBbW9nQWlBRmFrR3MwQUZxS0FJQU5nS2NBU0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRZkFBYWlJQ0lBY2dCaEFOUVloL1N3MEJJREVnQWlBRktBSUFFQjRnTUNBQ0lBVW9BZ2dRSGlBdklBSWdCU2dDQkJBZUlBeEJJR3NoR0NBT0lRWURRQ0FFS0FLSUFTQUVLQUtFQVVFRGRHb3BBZ0FpUUtjaUNrRVFkaUlaUWY4QmNTRUxJQVFvQXBnQklBUW9BcFFCUVFOMGFpa0NBQ0pCcHlJV1FSQjJJaDlCL3dGeElSb2dCQ2dDa0FFZ0JDZ0NqQUZCQTNScUtRSUFJa0pDSUlpbklRY2dRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ0VIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ2RDSUlheUlSSUFJZ0FpQVJTeHNpRnlBSWFqWUNkQ0FISUFRb0FuQWdDSFJCQUNBWGEzWWdBaUFYYXlJWGRHb2hDQ0FFUWZBQWFoQVBHaUFDSUJGTkRRRWdCQ0FFS0FKMElnSWdGMm8yQW5RZ0JDZ0NjQ0FDZEVFQUlCZHJkaUFJYWlFSURBRUxJQVFnQWlBRUtBSjBJaEZxTmdKMElBUW9BbkFnRVhSQkFDQUlhM1lnQjJvaENDQUVRZkFBYWhBUEdnc2dCQ2tDbkFFaFJDQUVJQWcyQXB3QklBUWdSRGNDb0FFTUFRc0NRQ0FDUlFSQUlBTUVRQ0FFS0FLY0FTRUlEQU1MSUFRb0FxQUJJUWdNQVFzZ0JDQUVLQUowSWdKQkFXbzJBblFDZnlBSElBTkZhaUFFS0FKd0lBSjBRUjkyYWlJQ1FRTkdCRUFnQkNnQ25BRkJBV3NNQVFzZ0FrRUNkQ0FFYWlnQ25BRUxJZ2RGSUFkcUlRZ2dBa0VCUndSQUlBUWdCQ2dDb0FFMkFxUUJDd3NnQkNBRUtBS2NBVFlDb0FFZ0JDQUlOZ0tjQVF1bklRSWdRVUtBZ1B3SGcxQkZCRUFnQkNBRUtBSjBJZ2NnR21vMkFuUWdCQ2dDY0NBSGRFRUFJQjlyZGlBQ2FpRUNDeUFMSUJwcVFSUlBCRUFnQkVId0FHb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDZENJSElBdHFOZ0owSUFRb0FuQWdCM1JCQUNBWmEzWWdBMm9oQXdzZ0JFSHdBR29RRHhvZ0JDQUVLQUp3SWdkQkFDQUtRUmgySWdzZ0JDZ0NkR29pR210MklBdEJBblJCb0IxcUtBSUFjU0FLUWYvL0EzRnFOZ0tFQVNBRUlCb2dGa0VZZGlJS2FpSUxOZ0owSUFRZ0NrRUNkRUdnSFdvb0FnQWdCMEVBSUF0cmRuRWdGa0gvL3dOeGFqWUNsQUVnQkVId0FHb1FEeG9nQkNCQ3B5SUhRUmgySWdvZ0JDZ0NkR29pQ3pZQ2RDQUVJQXBCQW5SQm9CMXFLQUlBSUFRb0FuQkJBQ0FMYTNaeElBZEIvLzhEY1dvMkFvd0JJQVFnQXpZQ09DQUVJQUkyQWp3Z0JDQUlOZ0pBQWtBQ1FBSkFJQVFvQXR3Qklnc2dBMm9pRmlBUVN3MEFJQVlnQWlBRGFpSUthaUFZU3cwQUlBcEJJR29nRENBR2EwME5BUXNnQkNBRVFVQnJLQUlBTmdJSUlBUWdCQ2tET0RjREFDQUdJQXdnQkNBRVFkd0JhaUFRSUJJZ0V5QU5FQjhoQ2d3QkN5QURJQVpxSVFjZ0JpQUxLUUFBTndBQUlBWWdDeWtBQ0RjQUNBSkFJQU5CRVVrTkFDQUdJQXNwQUJBM0FCQWdCaUFMS1FBWU53QVlJQU5CRUd0QkVVZ05BQ0FMUVJCcUlRTWdCa0VnYWlFTEEwQWdDeUFES1FBUU53QUFJQXNnQXlrQUdEY0FDQ0FMSUFNcEFDQTNBQkFnQ3lBREtRQW9Od0FZSUFOQklHb2hBeUFMUVNCcUlnc2dCMGtOQUFzTElBY2dDR3NoQXlBRUlCWTJBdHdCSUFjZ0Vtc2dDRWtFUUNBSUlBY2dFMnRMRFFRZ0RTQU5JQU1nRW1zaUEyb2lDeUFDYWs4RVFDQUhJQXNnQWhBS0dnd0NDeUFISUF0QkFDQURheEFLSUFRZ0FpQURhaUlDTmdJOElBTnJJUWNnRWlFREN5QUlRUkJQQkVBZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNDQUNRUkZJRFFFZ0FpQUhhaUVJSUFkQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFjZ0F5MEFBRG9BQUNBSElBTXRBQUU2QUFFZ0J5QURMUUFDT2dBQ0lBY2dBeTBBQXpvQUF5QUhJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBY2dBeWtBQURjQUFBc2dBa0VKU1EwQUlBSWdCMm9oQ3lBSFFRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0Mwa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dBa0VaU0EwQUlBZEJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBdEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0RDeUFHSUFwcUlRWWdCRUh3QUdvUUR5RURJQTlCQVdzaUR3MEFDMEVBSVFJZ0EwRUNTUTBCQTBBZ0FrRURSd1JBSUFVZ0FrRUNkQ0lEYWtHczBBRnFJQU1nQkdvb0Fwd0JOZ0lBSUFKQkFXb2hBZ3dCQ3dzZ0JDZ0MzQUVoQXd0QnVuOGhDU0FRSUFOcklnSWdEQ0FHYTBzTkFDQUdCSDhnQmlBRElBSVFBaUFDYWdWQkFBc2dEbXNoQ1FzZ0NVR0lmMHNOQmdzQ1FDQUZLQUxzNmdGRkRRQWdCU0FGS1FPSTZnRWdDYTE4TndPSTZnRUNRQ0FGS0FMUTZnRWlBaUFKYWlJSVFSOU5CRUFnRGtVTkFTQUNJQ0pxSUE0Z0NSQUNHaUFGS0FMUTZnRWdDV29oQ0F3QkN5QU9JUU1nQWdSQUlBSWdJbW9nQTBFZ0lBSnJFQUlhSUFVb0F0RHFBU0VDSUFWQkFEWUMwT29CSUFVZ0JTa0RrT29CSUFVcEFMRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEa09vQklBVWdCU2tEbU9vQklBVXBBTGpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG1Pb0JJQVVnQlNrRG9Pb0JJQVVwQU1EcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RvT29CSUFVZ0JTa0RxT29CSUFVcEFNanFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEcU9vQklBTWdBbXRCSUdvaEF3c2dDU0FPYWlJQ0lBTkJJR3BQQkVBZ0FrRWdheUVHSUFVcEE2anFBU0UvSUFVcEE2RHFBU0ZBSUFVcEE1anFBU0ZCSUFVcEE1RHFBU0ZDQTBBZ0F5a0FHRUxQMXRPKzBzZXIyVUorSUQ5OFFoK0pRb2VWcjYrWXR0NmJubjkrSVQ4Z0F5a0FFRUxQMXRPKzBzZXIyVUorSUVCOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVBZ0F5a0FDRUxQMXRPKzBzZXIyVUorSUVGOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVFZ0F5a0FBRUxQMXRPKzBzZXIyVUorSUVKOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVJZ0EwRWdhaUlESUFaTkRRQUxJQVVnUHpjRHFPb0JJQVVnUURjRG9Pb0JJQVVnUVRjRG1Pb0JJQVVnUWpjRGtPb0JDeUFDSUFOTkRRRWdJaUFESUFJZ0Eyc2lDQkFDR2dzZ0JTQUlOZ0xRNmdFTElEVWdGV3NoQXlBVklCdHFJUUlnQ1NBT2FpRU9JQVFvQWpCRkRRQUxJQ2twQXdBaVAwSi9VU0EvSUE0Z0hXdXNVWEpGQkVCQmJDRUpEQVlMSUFVb0F1RHBBUVJBUVdvaENTQURRUVJKRFFZZ0JTZ0M2T29CUlFSQUlDSWdCU2dDME9vQmFpRUtBbjRnQlNrRGlPb0JJajlDSUZvRVFDQUZLUU9ZNmdFaVFFSUhpU0FGS1FPUTZnRWlRVUlCaVh3Z0JTa0RvT29CSWtKQ0RJbDhJQVVwQTZqcUFTSkRRaEtKZkNCQlFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5SUVCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZm9WQ2g1V3ZyNWkyM3B1ZWYzNUNuYU8xNm9PeGpZcjZBSDBnUWtMUDF0Tyswc2VyMlVKK1FoK0pRb2VWcjYrWXR0NmJubjkraFVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0JEUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlEQUVMSUFVcEE2RHFBVUxGejlteThlVzY2aWQ4Q3lBL2ZDRS9JQ0loQmdOQUlBb2dCa0VJYWlJSFR3UkFJQVlwQUFCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZmlBL2hVSWJpVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTRS9JQWNoQmd3QkN3c0NRQ0FLSUFaQkJHb2lDRWtFUUNBR0lRZ01BUXNnQmpVQUFFS0hsYSt2bUxiZW01NS9maUEvaFVJWGlVTFAxdE8rMHNlcjJVSitRdm56M2ZHWjlwbXJGbndoUHdzRFFDQUlJQXBKQkVBZ0NERUFBRUxGejlteThlVzY2aWQrSUQrRlFndUpRb2VWcjYrWXR0NmJubjkrSVQ4Z0NFRUJhaUVJREFFTEN5QUNLQUFBSUQ5Q0lZZ2dQNFZDejliVHZ0TEhxOWxDZmlJL1FoMklJRCtGUXZuejNmR1o5cG1yRm40aVAwSWdpQ0EvaGFkSERRY0xJQU5CQkdzaEF5QUNRUVJxSVFJTElBNGdIV3NpQ1VHSmYwOE5CQ0FCSUFscklRRWdDU0FkYWlFZFFRRWhQZ3dCQ3d0QnVIOGhCeUFERFFRZ0hTQUFheUVIREFRTFFXd2hDUXdCQzBHNGZ5RUpDMEc0ZnlFSElBbEJka1lnUG5FTkFRc2dDU0VIQ3lnQ0FBMEFJQVZCL09vQmFpZ0NBQ0VCSUFWQitPb0JhaWdDQUNFQUlBVVFHQ0FGS0FLdzZ3RWdBQ0FCRUJNZ0JVRUFOZ0t3NndFZ0JTZ0NwT3NCSWdJRVFBSkFBa0FDUUFKQUlBSW9BZ0FpQXdSQUlBQkZEUUlnQVNBRElBQVJBZ0FNQVFzZ0FFVU5BZ3NnQVNBQ0lBQVJBZ0FNQWdzZ0F4QUdDeUFDRUFZTElBVkJBRFlDcE9zQkN5QUFCRUFnQVNBRklBQVJBZ0FNQVFzZ0JSQUdDeUFFUWVBQmFpUUFJQWNMQzZnVkNRQkJpQWdMRFFFQUFBQUJBQUFBQWdBQUFBSUFRYUFJQzdNR0FRQUFBQUVBQUFBQ0FBQUFBZ0FBQUNZQUFBQ0NBQUFBSVFVQUFFb0FBQUJuQ0FBQUpnQUFBTUFCQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBS1FBQUFDd0NBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFMd0FBQU1vQ0FBQ0FBQUFBaWdVQUFFb0FBQUNFQ1FBQU5RQUFBSE1EQUFDQUFBQUFuUVVBQUVvQUFBQ2dDUUFBUFFBQUFJRURBQUNBQUFBQTZ3VUFBRXNBQUFBK0NnQUFSQUFBQUo0REFBQ0FBQUFBVFFZQUFFc0FBQUNxQ2dBQVN3QUFBTE1EQUFDQUFBQUF3UVlBQUUwQUFBQWZEUUFBVFFBQUFGTUVBQUNBQUFBQUl3Z0FBRkVBQUFDbUR3QUFWQUFBQUprRUFBQ0FBQUFBU3drQUFGY0FBQUN4RWdBQVdBQUFBTm9FQUFDQUFBQUFid2tBQUYwQUFBQWpGQUFBVkFBQUFFVUZBQUNBQUFBQVZBb0FBR29BQUFDTUZBQUFhZ0FBQUs4RkFBQ0FBQUFBZGdrQUFId0FBQUJPRUFBQWZBQUFBTklDQUFDQUFBQUFZd2NBQUpFQUFBQ1FCd0FBa2dBQUFBQUFBQUFCQUFBQUFRQUFBQVVBQUFBTkFBQUFIUUFBQUQwQUFBQjlBQUFBL1FBQUFQMEJBQUQ5QXdBQS9RY0FBUDBQQUFEOUh3QUEvVDhBQVAxL0FBRDkvd0FBL2Y4QkFQMy9Bd0Q5L3djQS9mOFBBUDMvSHdEOS96OEEvZjkvQVAzLy93RDkvLzhCL2YvL0EvMy8vd2Y5Ly84UC9mLy9ILzMvL3ovOS8vOS9BQUFBQUFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBUkFBQUFFZ0FBQUJNQUFBQVVBQUFBRlFBQUFCWUFBQUFYQUFBQUdBQUFBQmtBQUFBYUFBQUFHd0FBQUJ3QUFBQWRBQUFBSGdBQUFCOEFBQUFEQUFBQUJBQUFBQVVBQUFBR0FBQUFCd0FBQUFnQUFBQUpBQUFBQ2dBQUFBc0FBQUFNQUFBQURRQUFBQTRBQUFBUEFBQUFFQUFBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZnQUFBQmNBQUFBWUFBQUFHUUFBQUJvQUFBQWJBQUFBSEFBQUFCMEFBQUFlQUFBQUh3QUFBQ0FBQUFBaEFBQUFJZ0FBQUNNQUFBQWxBQUFBSndBQUFDa0FBQUFyQUFBQUx3QUFBRE1BQUFBN0FBQUFRd0FBQUZNQUFBQmpBQUFBZ3dBQUFBTUJBQUFEQWdBQUF3UUFBQU1JQUFBREVBQUFBeUFBQUFOQUFBQURnQUFBQXdBQkFFSGdEd3RSQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQkFBQUFBVUFBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0FBQUF3QUFBQU5BQUFBRGdBQUFBOEFBQUFRQUVIRUVBdUxBUUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFTQUFBQUZBQUFBQllBQUFBWUFBQUFIQUFBQUNBQUFBQW9BQUFBTUFBQUFFQUFBQUNBQUFBQUFBRUFBQUFDQUFBQUJBQUFBQWdBQUFBUUFBQUFJQUFBQUVBQUFBQ0FBQUFBQUFFQVFaQVNDK1lFQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFCQUFBQUJBQUFBQWdBQUFBQUFBQUFBUUFCQVFZQUFBQUFBQUFFQUFBQUFCQUFBQVFBQUFBQUlBQUFCUUVBQUFBQUFBQUZBd0FBQUFBQUFBVUVBQUFBQUFBQUJRWUFBQUFBQUFBRkJ3QUFBQUFBQUFVSkFBQUFBQUFBQlFvQUFBQUFBQUFGREFBQUFBQUFBQVlPQUFBQUFBQUJCUkFBQUFBQUFBRUZGQUFBQUFBQUFRVVdBQUFBQUFBQ0JSd0FBQUFBQUFNRklBQUFBQUFBQkFVd0FBQUFJQUFHQlVBQUFBQUFBQWNGZ0FBQUFBQUFDQVlBQVFBQUFBQUtCZ0FFQUFBQUFBd0dBQkFBQUNBQUFBUUFBQUFBQUFBQUJBRUFBQUFBQUFBRkFnQUFBQ0FBQUFVRUFBQUFBQUFBQlFVQUFBQWdBQUFGQndBQUFBQUFBQVVJQUFBQUlBQUFCUW9BQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBSUFBQkJSQUFBQUFBQUFFRkVnQUFBQ0FBQVFVV0FBQUFBQUFDQlJnQUFBQWdBQU1GSUFBQUFBQUFBd1VvQUFBQUFBQUdCRUFBQUFBUUFBWUVRQUFBQUNBQUJ3V0FBQUFBQUFBSkJnQUNBQUFBQUFzR0FBZ0FBREFBQUFRQUFBQUFFQUFBQkFFQUFBQWdBQUFGQWdBQUFDQUFBQVVEQUFBQUlBQUFCUVVBQUFBZ0FBQUZCZ0FBQUNBQUFBVUlBQUFBSUFBQUJRa0FBQUFnQUFBRkN3QUFBQ0FBQUFVTUFBQUFBQUFBQmc4QUFBQWdBQUVGRWdBQUFDQUFBUVVVQUFBQUlBQUNCUmdBQUFBZ0FBSUZIQUFBQUNBQUF3VW9BQUFBSUFBRUJUQUFBQUFBQUJBR0FBQUJBQUFBRHdZQWdBQUFBQUFPQmdCQUFBQUFBQTBHQUNBQVFZQVhDNGNDQVFBQkFRVUFBQUFBQUFBRkFBQUFBQUFBQmdROUFBQUFBQUFKQmYwQkFBQUFBQThGL1g4QUFBQUFGUVg5L3g4QUFBQURCUVVBQUFBQUFBY0VmUUFBQUFBQURBWDlEd0FBQUFBU0JmMy9Bd0FBQUJjRi9mOS9BQUFBQlFVZEFBQUFBQUFJQlAwQUFBQUFBQTRGL1Q4QUFBQUFGQVg5L3c4QUFBQUNCUUVBQUFBUUFBY0VmUUFBQUFBQUN3WDlCd0FBQUFBUkJmMy9BUUFBQUJZRi9mOC9BQUFBQkFVTkFBQUFFQUFJQlAwQUFBQUFBQTBGL1I4QUFBQUFFd1g5L3djQUFBQUJCUUVBQUFBUUFBWUVQUUFBQUFBQUNnWDlBd0FBQUFBUUJmMy9BQUFBQUJ3Ri9mLy9Ed0FBR3dYOS8vOEhBQUFhQmYzLy93TUFBQmtGL2YvL0FRQUFHQVg5Ly84QVFaQVpDNFlFQVFBQkFRWUFBQUFBQUFBR0F3QUFBQUFBQUFRRUFBQUFJQUFBQlFVQUFBQUFBQUFGQmdBQUFBQUFBQVVJQUFBQUFBQUFCUWtBQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBQUFBQUJoQUFBQUFBQUFBR0V3QUFBQUFBQUFZV0FBQUFBQUFBQmhrQUFBQUFBQUFHSEFBQUFBQUFBQVlmQUFBQUFBQUFCaUlBQUFBQUFBRUdKUUFBQUFBQUFRWXBBQUFBQUFBQ0JpOEFBQUFBQUFNR093QUFBQUFBQkFaVEFBQUFBQUFIQm9NQUFBQUFBQWtHQXdJQUFCQUFBQVFFQUFBQUFBQUFCQVVBQUFBZ0FBQUZCZ0FBQUFBQUFBVUhBQUFBSUFBQUJRa0FBQUFBQUFBRkNnQUFBQUFBQUFZTUFBQUFBQUFBQmc4QUFBQUFBQUFHRWdBQUFBQUFBQVlWQUFBQUFBQUFCaGdBQUFBQUFBQUdHd0FBQUFBQUFBWWVBQUFBQUFBQUJpRUFBQUFBQUFFR0l3QUFBQUFBQVFZbkFBQUFBQUFDQmlzQUFBQUFBQU1HTXdBQUFBQUFCQVpEQUFBQUFBQUZCbU1BQUFBQUFBZ0dBd0VBQUNBQUFBUUVBQUFBTUFBQUJBUUFBQUFRQUFBRUJRQUFBQ0FBQUFVSEFBQUFJQUFBQlFnQUFBQWdBQUFGQ2dBQUFDQUFBQVVMQUFBQUFBQUFCZzRBQUFBQUFBQUdFUUFBQUFBQUFBWVVBQUFBQUFBQUJoY0FBQUFBQUFBR0dnQUFBQUFBQUFZZEFBQUFBQUFBQmlBQUFBQUFBQkFHQXdBQkFBQUFEd1lEZ0FBQUFBQU9CZ05BQUFBQUFBMEdBeUFBQUFBQURBWURFQUFBQUFBTEJnTUlBQUFBQUFvR0F3UUFRYVFkQzlrQkFRQUFBQU1BQUFBSEFBQUFEd0FBQUI4QUFBQS9BQUFBZndBQUFQOEFBQUQvQVFBQS93TUFBUDhIQUFEL0R3QUEveDhBQVA4L0FBRC9md0FBLy84QUFQLy9BUUQvL3dNQS8vOEhBUC8vRHdELy94OEEvLzgvQVAvL2Z3RC8vLzhBLy8vL0FmLy8vd1AvLy84SC8vLy9ELy8vL3gvLy8vOC8vLy8vZndBQUFBQUJBQUFBQWdBQUFBUUFBQUFBQUFBQUFnQUFBQVFBQUFBSUFBQUFBQUFBQUFFQUFBQUNBQUFBQVFBQUFBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUFnQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QkJnQjhMQTRBUkFRPT0iO3ZhciBPST1uZXcgeUEsVEk9ITE7YXN5bmMgZnVuY3Rpb24gY2UoQSxJLHQpe2xldCBlPW51bGw7dHlwZW9mIEEhPSJzdHJpbmciP2U9QS5ocmVmOkEuc3RhcnRzV2l0aCgiaHR0cCIpP2U9QTplPWAke0l9LyR7QX1gLGUuZW5kc1dpdGgoIi5qcyIpJiYoZT1lLnN1YnN0cmluZygwLGUubGVuZ3RoLTMpKSxlLmVuZHNXaXRoKCIud2FzbSIpJiYoZT1lLnN1YnN0cmluZygwLGUubGVuZ3RoLTUpKTtsZXQgZz1gJHtlfS53YXNtYCxyPWF3YWl0IGRBLmdldChgJHtnfS56c3RgLHtyZXNwb25zZVR5cGU6ImFycmF5YnVmZmVyIixwYXJhbXM6dH0pO1RJfHwoYXdhaXQgT0kuaW5pdCgpLFRJPSEwKTtsZXQgcz1PSS5kZWNvZGUobmV3IFVpbnQ4QXJyYXkoci5kYXRhKSkuYnVmZmVyO3JldHVybihhd2FpdCBpbXBvcnQoYCR7ZX0uanNgKSkuZGVmYXVsdCh7d2FzbUJpbmFyeTpzfSl9dmFyIHhJPWNlO3ZhciB3QT1uZXcgTWFwO2FzeW5jIGZ1bmN0aW9uIGZlKEEsSSx0KXtsZXQgZT1BLGc9QSxyPW51bGw7cmV0dXJuIHR5cGVvZiBBIT0ic3RyaW5nIiYmKGU9bmV3IFVSTChBLmhyZWYpLGc9ZS5ocmVmKSx3QS5oYXMoZyk/cj1hd2FpdCB3QS5nZXQoZyk6KHdBLnNldChnLHhJKGUsSSx0KSkscj1hd2FpdCB3QS5nZXQoZykpLHJ9dmFyIFBJPWZlO3ZhciBsZT17VGV4dEZpbGU6IlRleHRGaWxlIixCaW5hcnlGaWxlOiJCaW5hcnlGaWxlIixUZXh0U3RyZWFtOiJUZXh0U3RyZWFtIixCaW5hcnlTdHJlYW06IkJpbmFyeVN0cmVhbSIsSW1hZ2U6IkltYWdlIixNZXNoOiJNZXNoIixQb2x5RGF0YToiUG9seURhdGEiLEpzb25Db21wYXRpYmxlOiJKc29uQ29tcGF0aWJsZSJ9LEQ9bGU7dmFyIERlPXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0scD1EZTt2YXIgdWU9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LFA9dWU7ZnVuY3Rpb24gaGUoQSxJKXtsZXQgdD1udWxsO3N3aXRjaChBKXtjYXNlIHAuVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoSSk7YnJlYWt9Y2FzZSBwLkludDg6e3Q9bmV3IEludDhBcnJheShJKTticmVha31jYXNlIHAuVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShJKTticmVha31jYXNlIHAuSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoSSk7YnJlYWt9Y2FzZSBwLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoSSk7YnJlYWt9Y2FzZSBwLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KEkpO2JyZWFrfWNhc2UgcC5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KEkpOnQ9bmV3IFVpbnQ4QXJyYXkoSSk7YnJlYWt9Y2FzZSBwLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoSSk6dD1uZXcgVWludDhBcnJheShJKTticmVha31jYXNlIFAuRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KEkpO2JyZWFrfWNhc2UgUC5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoSSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIFk9aGU7dmFyIFpJPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPT0iZnVuY3Rpb24iLGpJPW5ldyBUZXh0RW5jb2RlcixXST1uZXcgVGV4dERlY29kZXIoInV0Zi04Iik7ZnVuY3Rpb24gZGUoQSxJKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxlPUEuZnNfb3BlbihJLHQuZmxhZ3MpLHI9QS5mc19zdGF0KEkpLnNpemUsaT1udWxsO1pJP2k9bmV3IFNoYXJlZEFycmF5QnVmZmVyKHIpOmk9bmV3IEFycmF5QnVmZmVyKHIpO2xldCBzPW5ldyBVaW50OEFycmF5KGkpO3JldHVybiBBLmZzX3JlYWQoZSxzLDAsciwwKSxBLmZzX2Nsb3NlKGUpLHN9ZnVuY3Rpb24gVkkoQSxJLHQpe2xldCBlPW51bGw7Wkk/ZT1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6ZT1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IGc9bmV3IFVpbnQ4QXJyYXkoZSkscj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsSSx0KTtyZXR1cm4gZy5zZXQociksZ31mdW5jdGlvbiB5KEEsSSx0LGUpe2xldCBnPTA7cmV0dXJuIEkhPT1udWxsJiYoZz1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LGUsSS5idWZmZXIuYnl0ZUxlbmd0aF0pLEEuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShJLmJ1ZmZlciksZykpLGd9ZnVuY3Rpb24gaihBLEksdCl7bGV0IGU9SlNPTi5zdHJpbmdpZnkoSSksZz1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsZS5sZW5ndGhdKTtBLndyaXRlQXNjaWlUb01lbW9yeShlLGcsITEpfWZ1bmN0aW9uIFMoQSxJLHQsZSl7bGV0IGc9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsSSx0XSkscj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxJLHRdKSxpPVZJKEEsZyxyKTtyZXR1cm4gWShlLGkuYnVmZmVyKX1mdW5jdGlvbiB6QShBLEkpe2xldCB0PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsSV0pLGU9QS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKGUpfWZ1bmN0aW9uIHllKEEsSSx0LGUpe2UhPW51bGwmJmUubGVuZ3RoPjAmJmUuZm9yRWFjaChmdW5jdGlvbihuLEMpe3N3aXRjaChuLnR5cGUpe2Nhc2UgRC5UZXh0U3RyZWFtOntsZXQgbz1qSS5lbmNvZGUobi5kYXRhLmRhdGEpLGY9eShBLG8sQywwKSxRPXtzaXplOm8uYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YH07aihBLFEsQyk7YnJlYWt9Y2FzZSBELkpzb25Db21wYXRpYmxlOntsZXQgbz1qSS5lbmNvZGUoSlNPTi5zdHJpbmdpZnkobi5kYXRhKSksZj15KEEsbyxDLDApLFE9e3NpemU6by5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gfTtqKEEsUSxDKTticmVha31jYXNlIEQuQmluYXJ5U3RyZWFtOntsZXQgbz1uLmRhdGEuZGF0YSxmPXkoQSxvLEMsMCksUT17c2l6ZTpvLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWB9O2ooQSxRLEMpO2JyZWFrfWNhc2UgRC5UZXh0RmlsZTp7QS5mc193cml0ZUZpbGUobi5kYXRhLnBhdGgsbi5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgRC5CaW5hcnlGaWxlOntBLmZzX3dyaXRlRmlsZShuLmRhdGEucGF0aCxuLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBELkltYWdlOntsZXQgbz1uLmRhdGEsZj15KEEsby5kYXRhLEMsMCksUT15KEEsby5kaXJlY3Rpb24sQywxKSxFPXR5cGVvZiBvLm1ldGFkYXRhPy5lbnRyaWVzPCJ1Ij9KU09OLnN0cmluZ2lmeShBcnJheS5mcm9tKG8ubWV0YWRhdGEuZW50cmllcygpKSk6IltdIixjPXtpbWFnZVR5cGU6by5pbWFnZVR5cGUsbmFtZTpvLm5hbWUsb3JpZ2luOm8ub3JpZ2luLHNwYWNpbmc6by5zcGFjaW5nLGRpcmVjdGlvbjpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke1F9YCxzaXplOm8uc2l6ZSxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG1ldGFkYXRhOkV9O2ooQSxjLEMpO2JyZWFrfWNhc2UgRC5NZXNoOntsZXQgbz1uLmRhdGEsZj15KEEsby5wb2ludHMsQywwKSxRPXkoQSxvLmNlbGxzLEMsMSksRT15KEEsby5wb2ludERhdGEsQywyKSxjPXkoQSxvLmNlbGxEYXRhLEMsMyksdT17bWVzaFR5cGU6by5tZXNoVHlwZSxuYW1lOm8ubmFtZSxudW1iZXJPZlBvaW50czpvLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxudW1iZXJPZkNlbGxzOm8ubnVtYmVyT2ZDZWxscyxjZWxsczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke1F9YCxjZWxsQnVmZmVyU2l6ZTpvLmNlbGxCdWZmZXJTaXplLG51bWJlck9mUG9pbnRQaXhlbHM6by5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YCxudW1iZXJPZkNlbGxQaXhlbHM6by5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtjfWB9O2ooQSx1LEMpO2JyZWFrfWNhc2UgRC5Qb2x5RGF0YTp7bGV0IG89bi5kYXRhLGY9eShBLG8ucG9pbnRzLEMsMCksUT15KEEsby52ZXJ0aWNlcyxDLDEpLEU9eShBLG8ubGluZXMsQywyKSxjPXkoQSxvLnBvbHlnb25zLEMsMyksdT15KEEsby50cmlhbmdsZVN0cmlwcyxDLDQpLGQ9eShBLG8ucG9pbnREYXRhLEMsNSksUj15KEEsby5wb2ludERhdGEsQyw2KSxOPXtwb2x5RGF0YVR5cGU6by5wb2x5RGF0YVR5cGUsbmFtZTpvLm5hbWUsbnVtYmVyT2ZQb2ludHM6by5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWAsdmVydGljZXNCdWZmZXJTaXplOm8udmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGxpbmVzQnVmZmVyU2l6ZTpvLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YCxwb2x5Z29uc0J1ZmZlclNpemU6by5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtjfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOm8udHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7dX1gLG51bWJlck9mUG9pbnRQaXhlbHM6by5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2R9YCxudW1iZXJPZkNlbGxQaXhlbHM6by5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtSfWB9O2ooQSxOLEMpO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIGlucHV0IEludGVyZmFjZVR5cGUiKX19KSxBLnJlc2V0TW9kdWxlU3Rkb3V0KCksQS5yZXNldE1vZHVsZVN0ZGVycigpO2xldCBnPUEuc3RhY2tTYXZlKCkscj0wO3RyeXtyPUEuY2FsbE1haW4oSS5zbGljZSgpKX1jYXRjaChuKXt0aHJvdyB0eXBlb2Ygbj09Im51bWJlciImJihjb25zb2xlLmxvZygiRXhjZXB0aW9uIHdoaWxlIHJ1bm5pbmcgcGlwZWxpbmU6IiksY29uc29sZS5sb2coInN0ZG91dDoiLEEuZ2V0TW9kdWxlU3Rkb3V0KCkpLGNvbnNvbGUuZXJyb3IoInN0ZGVycjoiLEEuZ2V0TW9kdWxlU3RkZXJyKCkpLHR5cGVvZiBBLmdldEV4Y2VwdGlvbk1lc3NhZ2U8InUiP2NvbnNvbGUuZXJyb3IoImV4Y2VwdGlvbjoiLEEuZ2V0RXhjZXB0aW9uTWVzc2FnZShuKSk6Y29uc29sZS5lcnJvcigiQnVpbGQgbW9kdWxlIGluIERlYnVnIG1vZGUgZm9yIGV4Y2VwdGlvbiBtZXNzYWdlIGluZm9ybWF0aW9uLiIpKSxufWZpbmFsbHl7QS5zdGFja1Jlc3RvcmUoZyl9bGV0IGk9QS5nZXRNb2R1bGVTdGRvdXQoKSxzPUEuZ2V0TW9kdWxlU3RkZXJyKCksYT1bXTtyZXR1cm4gdCE9bnVsbCYmdC5sZW5ndGg+MCYmcj09PTAmJnQuZm9yRWFjaChmdW5jdGlvbihuLEMpe2xldCBvPW51bGw7c3dpdGNoKG4udHlwZSl7Y2FzZSBELlRleHRTdHJlYW06e2xldCBRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEMsMF0pLEU9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQywwXSksYz1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsUSxFKTtvPXtkYXRhOldJLmRlY29kZShjKX07YnJlYWt9Y2FzZSBELkpzb25Db21wYXRpYmxlOntsZXQgUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxDLDBdKSxFPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEMsMF0pLGM9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLFEsRSk7bz1KU09OLnBhcnNlKFdJLmRlY29kZShjKSk7YnJlYWt9Y2FzZSBELkJpbmFyeVN0cmVhbTp7bGV0IFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQywwXSksRT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxDLDBdKTtvPXtkYXRhOlZJKEEsUSxFKX07YnJlYWt9Y2FzZSBELlRleHRGaWxlOntvPXtwYXRoOm4uZGF0YS5wYXRoLGRhdGE6QS5mc19yZWFkRmlsZShuLmRhdGEucGF0aCx7ZW5jb2Rpbmc6InV0ZjgifSl9O2JyZWFrfWNhc2UgRC5CaW5hcnlGaWxlOntvPXtwYXRoOm4uZGF0YS5wYXRoLGRhdGE6ZGUoQSxuLmRhdGEucGF0aCl9O2JyZWFrfWNhc2UgRC5JbWFnZTp7bGV0IFE9ekEoQSxDKTtRLmRhdGE9UyhBLEMsMCxRLmltYWdlVHlwZS5jb21wb25lbnRUeXBlKSxRLmRpcmVjdGlvbj1TKEEsQywxLFAuRmxvYXQ2NCksUS5tZXRhZGF0YT1uZXcgTWFwKFEubWV0YWRhdGEpLG89UTticmVha31jYXNlIEQuTWVzaDp7bGV0IFE9ekEoQSxDKTtRLm51bWJlck9mUG9pbnRzPjA/US5wb2ludHM9UyhBLEMsMCxRLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSk6US5wb2ludHM9WShRLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLFEubnVtYmVyT2ZDZWxscz4wP1EuY2VsbHM9UyhBLEMsMSxRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlKTpRLmNlbGxzPVkoUS5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLFEubnVtYmVyT2ZQb2ludFBpeGVscz4wP1EucG9pbnREYXRhPVMoQSxDLDIsUS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6US5wb2ludERhdGE9WShRLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksUS5udW1iZXJPZkNlbGxQaXhlbHM+MD9RLmNlbGxEYXRhPVMoQSxDLDMsUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlKTpRLmNlbGxEYXRhPVkoUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksbz1RO2JyZWFrfWNhc2UgRC5Qb2x5RGF0YTp7bGV0IFE9ekEoQSxDKTtRLm51bWJlck9mUG9pbnRzPjA/US5wb2ludHM9UyhBLEMsMCxQLkZsb2F0MzIpOlEucG9pbnRzPW5ldyBGbG9hdDMyQXJyYXksUS52ZXJ0aWNlc0J1ZmZlclNpemU+MD9RLnZlcnRpY2VzPVMoQSxDLDEscC5VSW50MzIpOlEudmVydGljZXM9bmV3IFVpbnQzMkFycmF5LFEubGluZXNCdWZmZXJTaXplPjA/US5saW5lcz1TKEEsQywyLHAuVUludDMyKTpRLmxpbmVzPW5ldyBVaW50MzJBcnJheSxRLnBvbHlnb25zQnVmZmVyU2l6ZT4wP1EucG9seWdvbnM9UyhBLEMsMyxwLlVJbnQzMik6US5wb2x5Z29ucz1uZXcgVWludDMyQXJyYXksUS50cmlhbmdsZVN0cmlwc0J1ZmZlclNpemU+MD9RLnRyaWFuZ2xlU3RyaXBzPVMoQSxDLDQscC5VSW50MzIpOlEudHJpYW5nbGVTdHJpcHM9bmV3IFVpbnQzMkFycmF5LFEubnVtYmVyT2ZQb2ludFBpeGVscz4wP1EucG9pbnREYXRhPVMoQSxDLDUsUS5wb2x5RGF0YVR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOlEucG9pbnREYXRhPVkoUS5wb2x5RGF0YVR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxRLm51bWJlck9mQ2VsbFBpeGVscz4wP1EuY2VsbERhdGE9UyhBLEMsNixRLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlKTpRLmNlbGxEYXRhPVkoUS5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLG89UTticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBvdXRwdXQgSW50ZXJmYWNlVHlwZSIpfWxldCBmPXt0eXBlOm4udHlwZSxkYXRhOm99O2EucHVzaChmKX0pLHtyZXR1cm5WYWx1ZTpyLHN0ZG91dDppLHN0ZGVycjpzLG91dHB1dHM6YX19dmFyIFhJPXllO3ZhciB3ZT10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcjwidSI7ZnVuY3Rpb24gbWUoQSxJKXtpZihBPT1udWxsKXJldHVybltdO2xldCB0PVtdO2ZvcihsZXQgZT0wO2U8QS5sZW5ndGg7ZSsrKXtsZXQgZz1wZShBW2VdLEkpO2chPT1udWxsJiZ0LnB1c2goZyl9cmV0dXJuIHR9ZnVuY3Rpb24gcGUoQSxJKXtpZihBPT1udWxsKXJldHVybiBudWxsO2xldCB0PW51bGw7cmV0dXJuIEEuYnVmZmVyIT09dm9pZCAwP3Q9QS5idWZmZXI6QS5ieXRlTGVuZ3RoIT09dm9pZCAwJiYodD1BKSx3ZSYmdCBpbnN0YW5jZW9mIFNoYXJlZEFycmF5QnVmZmVyP251bGw6ST90OnQuc2xpY2UoMCl9dmFyIHpJPW1lO2Z1bmN0aW9uIFNlKEEpe3JldHVybltBLmRhdGEsQS5kaXJlY3Rpb25dfXZhciBfST1TZTtmdW5jdGlvbiBGZShBKXtyZXR1cm5bQS5wb2ludHMsQS5wb2ludERhdGEsQS5jZWxscyxBLmNlbGxEYXRhXX12YXIgdkk9RmU7ZnVuY3Rpb24gUmUoQSl7cmV0dXJuW0EucG9pbnRzLEEudmVydGljZXMsQS5saW5lcyxBLnBvbHlnb25zLEEudHJpYW5nbGVTdHJpcHMsQS5wb2ludERhdGEsQS5jZWxsRGF0YV19dmFyICRJPVJlO2FzeW5jIGZ1bmN0aW9uIE5lKEEsSSx0LGUpe2xldCBnPVhJKEEsSSx0LGUpLHI9W107cmV0dXJuIGcub3V0cHV0cy5mb3JFYWNoKGZ1bmN0aW9uKGkpe2lmKGkudHlwZT09PUQuQmluYXJ5U3RyZWFtfHxpLnR5cGU9PT1ELkJpbmFyeUZpbGUpe2xldCBzPWkuZGF0YTtyLnB1c2gocyl9ZWxzZSBpZihpLnR5cGU9PT1ELkltYWdlKXtsZXQgcz1pLmRhdGE7ci5wdXNoKC4uLl9JKHMpKX1lbHNlIGlmKGkudHlwZT09PUQuTWVzaCl7bGV0IHM9aS5kYXRhO3IucHVzaCguLi52SShzKSl9ZWxzZSBpZihpLnR5cGU9PT1ELlBvbHlEYXRhKXtsZXQgcz1pLmRhdGE7ci5wdXNoKC4uLiRJKHMpKX19KSxTQShnLHpJKHIsITApKX12YXIgQXQ9TmU7dmFyIFVlPXtydW5QaXBlbGluZTphc3luYyBmdW5jdGlvbihBLEksdCxlLGcscil7bGV0IGk9YXdhaXQgUEkoQSxJLHIpO3JldHVybiBhd2FpdCBBdChpLHQsZSxnKX19O29BKFVlKTslMEEvKiEgQnVuZGxlZCBsaWNlbnNlIGluZm9ybWF0aW9uOiUwQSUwQWNvbWxpbmsvZGlzdC9lc20vY29tbGluay5tanM6JTBBICAoKiolMEEgICAqIEBsaWNlbnNlJTBBICAgKiBDb3B5cmlnaHQgMjAxOSBHb29nbGUgTExDJTBBICAgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMCUwQSAgICopJTBBKi8lMEEnO210KHd0KTtleHBvcnR7QmkgYXMgYXBwbHlQcmVzZW50YXRpb25TdGF0ZVRvSW1hZ2UsSiBhcyBnZXREZWZhdWx0V2ViV29ya2VyLEYgYXMgZ2V0UGlwZWxpbmVXb3JrZXJVcmwsTiBhcyBnZXRQaXBlbGluZXNCYXNlVXJsLGNpIGFzIHJlYWREaWNvbUVuY2Fwc3VsYXRlZFBkZixkaSBhcyByZWFkRGljb21UYWdzLHdpIGFzIHJlYWRJbWFnZURpY29tRmlsZVNlcmllcyxnZSBhcyByZWFkSW1hZ2VEaWNvbUZpbGVTZXJpZXNXb3JrZXJGdW5jdGlvbixXcyBhcyBzZXREZWZhdWx0V2ViV29ya2VyLG10IGFzIHNldFBpcGVsaW5lV29ya2VyVXJsLFBzIGFzIHNldFBpcGVsaW5lc0Jhc2VVcmwsRWkgYXMgc3RydWN0dXJlZFJlcG9ydFRvSHRtbCxmaSBhcyBzdHJ1Y3R1cmVkUmVwb3J0VG9UZXh0LGtBIGFzIHZlcnNpb259OwovKiEgQnVuZGxlZCBsaWNlbnNlIGluZm9ybWF0aW9uOgoKY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczoKICAoKioKICAgKiBAbGljZW5zZQogICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMKICAgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMAogICAqKQoqLwo=""" +default_js_module = """data:text/javascript;base64,dmFyIFN0PU9iamVjdC5kZWZpbmVQcm9wZXJ0eTt2YXIgRnQ9KEEsZSk9Pntmb3IodmFyIHQgaW4gZSlTdChBLHQse2dldDplW3RdLGVudW1lcmFibGU6ITB9KX07dmFyIGt0PSI2LjAuMSIsa0E9a3Q7dmFyIFJ0PXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0saD1SdDt2YXIgYnQ9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LE09YnQ7ZnVuY3Rpb24gVXQoQSxlKXtsZXQgdD1udWxsO3N3aXRjaChBKXtjYXNlIGguVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBoLkludDg6e3Q9bmV3IEludDhBcnJheShlKTticmVha31jYXNlIGguVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShlKTticmVha31jYXNlIGguSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBoLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBoLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgaC5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBoLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoZSk6dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIE0uRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KGUpO2JyZWFrfWNhc2UgTS5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoZSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIHg9VXQ7dmFyIE50PXtVbmtub3duOiJVbmtub3duIixTY2FsYXI6IlNjYWxhciIsUkdCOiJSR0IiLFJHQkE6IlJHQkEiLE9mZnNldDoiT2Zmc2V0IixWZWN0b3I6IlZlY3RvciIsUG9pbnQ6IlBvaW50IixDb3ZhcmlhbnRWZWN0b3I6IkNvdmFyaWFudFZlY3RvciIsU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvcjoiU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvciIsRGlmZnVzaW9uVGVuc29yM0Q6IkRpZmZ1c2lvblRlbnNvcjNEIixDb21wbGV4OiJDb21wbGV4IixGaXhlZEFycmF5OiJGaXhlZEFycmF5IixBcnJheToiQXJyYXkiLE1hdHJpeDoiTWF0cml4IixWYXJpYWJsZUxlbmd0aFZlY3RvcjoiVmFyaWFibGVMZW5ndGhWZWN0b3IiLFZhcmlhYmxlU2l6ZU1hdHJpeDoiVmFyaWFibGVTaXplTWF0cml4In0sbGU9TnQ7dmFyIFJBPWNsYXNze2RpbWVuc2lvbjtjb21wb25lbnRUeXBlO3BpeGVsVHlwZTtjb21wb25lbnRzO2NvbnN0cnVjdG9yKGU9Mix0PWguVUludDgscj1sZS5TY2FsYXIsbj0xKXt0aGlzLmRpbWVuc2lvbj1lLHRoaXMuY29tcG9uZW50VHlwZT10LHRoaXMucGl4ZWxUeXBlPXIsdGhpcy5jb21wb25lbnRzPW59fSxCZT1SQTtmdW5jdGlvbiBHdChBLGUsdCxyLG4pe0Fbcit0KmVdPW59dmFyIENlPUd0O3ZhciBiQT1jbGFzc3tpbWFnZVR5cGU7bmFtZT0iaW1hZ2UiO29yaWdpbjtzcGFjaW5nO2RpcmVjdGlvbjtzaXplO21ldGFkYXRhO2RhdGE7Y29uc3RydWN0b3IoZT1uZXcgQmUpe3RoaXMuaW1hZ2VUeXBlPWU7bGV0IHQ9ZS5kaW1lbnNpb247dGhpcy5vcmlnaW49bmV3IEFycmF5KHQpLHRoaXMub3JpZ2luLmZpbGwoMCksdGhpcy5zcGFjaW5nPW5ldyBBcnJheSh0KSx0aGlzLnNwYWNpbmcuZmlsbCgxKSx0aGlzLmRpcmVjdGlvbj1uZXcgRmxvYXQ2NEFycmF5KHQqdCksdGhpcy5kaXJlY3Rpb24uZmlsbCgwKTtmb3IobGV0IHI9MDtyPHQ7cisrKUNlKHRoaXMuZGlyZWN0aW9uLHQscixyLDEpO3RoaXMuc2l6ZT1uZXcgQXJyYXkodCksdGhpcy5zaXplLmZpbGwoMCksdGhpcy5tZXRhZGF0YT1uZXcgTWFwLHRoaXMuZGF0YT1udWxsfX0sY2U9YkE7ZnVuY3Rpb24gVHQoQSl7aWYoQS5sZW5ndGg8MSl0aHJvdyBFcnJvcigiQXQgbGVhc3Qgb25lIGltYWdlcyBpcyByZXF1aXJlZC4iKTtsZXQgZT1BWzBdO2lmKGUuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIkltYWdlIGRhdGEgaXMgbnVsbC4iKTtsZXQgdD1uZXcgY2UoZS5pbWFnZVR5cGUpO3Qub3JpZ2luPUFycmF5LmZyb20oZS5vcmlnaW4pLHQuc3BhY2luZz1BcnJheS5mcm9tKGUuc3BhY2luZyk7bGV0IHI9dC5pbWFnZVR5cGUuZGltZW5zaW9uO3QuZGlyZWN0aW9uPWUuZGlyZWN0aW9uLnNsaWNlKCk7bGV0IG49ci0xO3Quc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSk7bGV0IGk9QS5yZWR1Y2UoKHMsYSk9PnMrYS5zaXplW25dLDApO3Quc2l6ZVtuXT1pO2xldCBvPXQuc2l6ZS5yZWR1Y2UoKHMsYSk9PnMqYSwxKSp0LmltYWdlVHlwZS5jb21wb25lbnRzLEk9ZS5kYXRhLmNvbnN0cnVjdG9yO3QuZGF0YT1uZXcgSShvKTtsZXQgQz10LmltYWdlVHlwZS5jb21wb25lbnRzO2ZvcihsZXQgcz0wO3M8dC5zaXplLmxlbmd0aC0xO3MrKylDKj10LnNpemVbc107bGV0IGw9MDtpZih0LmRhdGEhPW51bGwpZm9yKGxldCBzPTA7czxBLmxlbmd0aDtzKyspdC5kYXRhLnNldChBW3NdLmRhdGEsQypsKSxsKz1BW3NdLnNpemVbbl07ZWxzZSB0aHJvdyBFcnJvcigiQ291bGQgbm90IGNyZWF0ZSByZXN1bHQgaW1hZ2UgZGF0YS4iKTtyZXR1cm4gdH12YXIgVUE9VHQ7dmFyIE5BPWNsYXNze2Zjbjt3b3JrZXJRdWV1ZTtydW5JbmZvO2NvbnN0cnVjdG9yKGUsdCl7dGhpcy5mY249dCx0aGlzLndvcmtlclF1ZXVlPW5ldyBBcnJheShlKSx0aGlzLndvcmtlclF1ZXVlLmZpbGwobnVsbCksdGhpcy5ydW5JbmZvPVtdfXJ1blRhc2tzKGUsdD1udWxsKXtsZXQgcj17dGFza1F1ZXVlOltdLHJlc3VsdHM6W10sYWRkaW5nVGFza3M6ITEscG9zdHBvbmVkOiExLHJ1bm5pbmdXb3JrZXJzOjAsaW5kZXg6MCxjb21wbGV0ZWRUYXNrczowLHByb2dyZXNzQ2FsbGJhY2s6dCxjYW5jZWxlZDohMX07cmV0dXJuIHRoaXMucnVuSW5mby5wdXNoKHIpLHIuaW5kZXg9dGhpcy5ydW5JbmZvLmxlbmd0aC0xLHtwcm9taXNlOm5ldyBQcm9taXNlKChuLGkpPT57ci5yZXNvbHZlPW4sci5yZWplY3Q9aSxyLnJlc3VsdHM9bmV3IEFycmF5KGUubGVuZ3RoKSxyLmNvbXBsZXRlZFRhc2tzPTAsci5hZGRpbmdUYXNrcz0hMCxlLmZvckVhY2goKG8sSSk9Pnt0aGlzLmFkZFRhc2soci5pbmRleCxJLG8pfSksci5hZGRpbmdUYXNrcz0hMX0pLHJ1bklkOnIuaW5kZXh9fXRlcm1pbmF0ZVdvcmtlcnMoKXtmb3IobGV0IGU9MDtlPHRoaXMud29ya2VyUXVldWUubGVuZ3RoO2UrKyl7bGV0IHQ9dGhpcy53b3JrZXJRdWV1ZVtlXTt0Py50ZXJtaW5hdGUoKSx0aGlzLndvcmtlclF1ZXVlW2VdPW51bGx9fWNhbmNlbChlKXtsZXQgdD10aGlzLnJ1bkluZm9bZV07dCE9bnVsbCYmKHQuY2FuY2VsZWQ9ITApfWFkZFRhc2soZSx0LHIpe2xldCBuPXRoaXMucnVuSW5mb1tlXTtpZihuPy5jYW5jZWxlZD09PSEwKXtuLnJlamVjdCgiUmVtYWluaW5nIHRhc2tzIGNhbmNlbGVkIiksdGhpcy5jbGVhclRhc2sobi5pbmRleCk7cmV0dXJufWlmKHRoaXMud29ya2VyUXVldWUubGVuZ3RoPjApe2xldCBpPXRoaXMud29ya2VyUXVldWUucG9wKCk7bi5ydW5uaW5nV29ya2VycysrLHJbci5sZW5ndGgtMV0ud2ViV29ya2VyPWksdGhpcy5mY24oLi4ucikudGhlbigoe3dlYldvcmtlcjpvLC4uLkl9KT0+e2lmKHRoaXMud29ya2VyUXVldWUucHVzaChvKSx0aGlzLnJ1bkluZm9bZV0hPT1udWxsKXtpZihuLnJ1bm5pbmdXb3JrZXJzLS0sbi5yZXN1bHRzW3RdPUksbi5jb21wbGV0ZWRUYXNrcysrLG4ucHJvZ3Jlc3NDYWxsYmFjayE9bnVsbCYmbi5wcm9ncmVzc0NhbGxiYWNrKG4uY29tcGxldGVkVGFza3Msbi5yZXN1bHRzLmxlbmd0aCksbi50YXNrUXVldWUubGVuZ3RoPjApe2xldCBDPW4udGFza1F1ZXVlLnNoaWZ0KCk7dGhpcy5hZGRUYXNrKGUsQ1swXSxDWzFdKX1lbHNlIGlmKCFuLmFkZGluZ1Rhc2tzJiZuLnJ1bm5pbmdXb3JrZXJzPT09MCl7bGV0IEM9bi5yZXN1bHRzO24ucmVzb2x2ZShDKSx0aGlzLmNsZWFyVGFzayhuLmluZGV4KX19fSkuY2F0Y2gobz0+e24ucmVqZWN0KG8pLHRoaXMuY2xlYXJUYXNrKG4uaW5kZXgpfSl9ZWxzZSBuLnJ1bm5pbmdXb3JrZXJzIT09MHx8bi5wb3N0cG9uZWQ/bi50YXNrUXVldWUucHVzaChbdCxyXSk6KG4ucG9zdHBvbmVkPSEwLHNldFRpbWVvdXQoKCk9PntuLnBvc3Rwb25lZD0hMSx0aGlzLmFkZFRhc2sobi5pbmRleCx0LHIpfSw1MCkpfWNsZWFyVGFzayhlKXt0aGlzLnJ1bkluZm9bZV0ucmVzdWx0cz1bXSx0aGlzLnJ1bkluZm9bZV0udGFza1F1ZXVlPVtdLHRoaXMucnVuSW5mb1tlXS5wcm9ncmVzc0NhbGxiYWNrPW51bGwsdGhpcy5ydW5JbmZvW2VdLmNhbmNlbGVkPW51bGwsdGhpcy5ydW5JbmZvW2VdLnJlamVjdD0oKT0+e30sdGhpcy5ydW5JbmZvW2VdLnJlc29sdmU9KCk9Pnt9fX0sR0E9TkE7dmFyIEx0PXtUZXh0RmlsZToiVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkJpbmFyeUZpbGUiLFRleHRTdHJlYW06IlRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiQmluYXJ5U3RyZWFtIixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2giLFBvbHlEYXRhOiJQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6Ikpzb25Db21wYXRpYmxlIn0sZj1MdDt2YXIgRWU9U3ltYm9sKCJDb21saW5rLnByb3h5IikseHQ9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IikseEE9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLFRBPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxzQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksZmU9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsT3Q9e2NhbkhhbmRsZTpBPT5mZShBKSYmQVtFZV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTplLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gcGUoQSxlKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLE9BKEEpfX0sUHQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmc0EgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgZTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP2U9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTplPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtlLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LFFlPW5ldyBNYXAoW1sicHJveHkiLE90XSxbInRocm93IixQdF1dKTtmdW5jdGlvbiBKdChBLGUpe2ZvcihsZXQgdCBvZiBBKWlmKGU9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gcGUoQSxlPWdsb2JhbFRoaXMsdD1bIioiXSl7ZS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiByKG4pe2lmKCFufHwhbi5kYXRhKXJldHVybjtpZighSnQodCxuLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gJyR7bi5vcmlnaW59JyBmb3IgY29tbGluayBwcm94eWApO3JldHVybn1sZXR7aWQ6aSx0eXBlOm8scGF0aDpJfT1PYmplY3QuYXNzaWduKHtwYXRoOltdfSxuLmRhdGEpLEM9KG4uZGF0YS5hcmd1bWVudExpc3R8fFtdKS5tYXAoSCksbDt0cnl7bGV0IHM9SS5zbGljZSgwLC0xKS5yZWR1Y2UoKEUsQik9PkVbQl0sQSksYT1JLnJlZHVjZSgoRSxCKT0+RVtCXSxBKTtzd2l0Y2gobyl7Y2FzZSJHRVQiOmw9YTticmVhaztjYXNlIlNFVCI6c1tJLnNsaWNlKC0xKVswXV09SChuLmRhdGEudmFsdWUpLGw9ITA7YnJlYWs7Y2FzZSJBUFBMWSI6bD1hLmFwcGx5KHMsQyk7YnJlYWs7Y2FzZSJDT05TVFJVQ1QiOntsZXQgRT1uZXcgYSguLi5DKTtsPUt0KEUpfWJyZWFrO2Nhc2UiRU5EUE9JTlQiOntsZXR7cG9ydDE6RSxwb3J0MjpCfT1uZXcgTWVzc2FnZUNoYW5uZWw7cGUoQSxCKSxsPVBBKEUsW0VdKX1icmVhaztjYXNlIlJFTEVBU0UiOmw9dm9pZCAwO2JyZWFrO2RlZmF1bHQ6cmV0dXJufX1jYXRjaChzKXtsPXt2YWx1ZTpzLFtzQV06MH19UHJvbWlzZS5yZXNvbHZlKGwpLmNhdGNoKHM9Pih7dmFsdWU6cyxbc0FdOjB9KSkudGhlbihzPT57bGV0W2EsRV09bEEocyk7ZS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sYSkse2lkOml9KSxFKSxvPT09IlJFTEVBU0UiJiYoZS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixyKSxkZShlKSxUQSBpbiBBJiZ0eXBlb2YgQVtUQV09PSJmdW5jdGlvbiImJkFbVEFdKCkpfSkuY2F0Y2gocz0+e2xldFthLEVdPWxBKHt2YWx1ZTpuZXcgVHlwZUVycm9yKCJVbnNlcmlhbGl6YWJsZSByZXR1cm4gdmFsdWUiKSxbc0FdOjB9KTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxhKSx7aWQ6aX0pLEUpfSl9KSxlLnN0YXJ0JiZlLnN0YXJ0KCl9ZnVuY3Rpb24gSHQoQSl7cmV0dXJuIEEuY29uc3RydWN0b3IubmFtZT09PSJNZXNzYWdlUG9ydCJ9ZnVuY3Rpb24gZGUoQSl7SHQoQSkmJkEuY2xvc2UoKX1mdW5jdGlvbiBPQShBLGUpe3JldHVybiBMQShBLFtdLGUpfWZ1bmN0aW9uIGFBKEEpe2lmKEEpdGhyb3cgbmV3IEVycm9yKCJQcm94eSBoYXMgYmVlbiByZWxlYXNlZCBhbmQgaXMgbm90IHVzZWFibGUiKX1mdW5jdGlvbiBtZShBKXtyZXR1cm4gWShBLHt0eXBlOiJSRUxFQVNFIn0pLnRoZW4oKCk9PntkZShBKX0pfXZhciBJQT1uZXcgV2Vha01hcCxnQT0iRmluYWxpemF0aW9uUmVnaXN0cnkiaW4gZ2xvYmFsVGhpcyYmbmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KEE9PntsZXQgZT0oSUEuZ2V0KEEpfHwwKS0xO0lBLnNldChBLGUpLGU9PT0wJiZtZShBKX0pO2Z1bmN0aW9uIE10KEEsZSl7bGV0IHQ9KElBLmdldChlKXx8MCkrMTtJQS5zZXQoZSx0KSxnQSYmZ0EucmVnaXN0ZXIoQSxlLEEpfWZ1bmN0aW9uIFl0KEEpe2dBJiZnQS51bnJlZ2lzdGVyKEEpfWZ1bmN0aW9uIExBKEEsZT1bXSx0PWZ1bmN0aW9uKCl7fSl7bGV0IHI9ITEsbj1uZXcgUHJveHkodCx7Z2V0KGksbyl7aWYoYUEociksbz09PXhBKXJldHVybigpPT57WXQobiksbWUoQSkscj0hMH07aWYobz09PSJ0aGVuIil7aWYoZS5sZW5ndGg9PT0wKXJldHVybnt0aGVuOigpPT5ufTtsZXQgST1ZKEEse3R5cGU6IkdFVCIscGF0aDplLm1hcChDPT5DLnRvU3RyaW5nKCkpfSkudGhlbihIKTtyZXR1cm4gSS50aGVuLmJpbmQoSSl9cmV0dXJuIExBKEEsWy4uLmUsb10pfSxzZXQoaSxvLEkpe2FBKHIpO2xldFtDLGxdPWxBKEkpO3JldHVybiBZKEEse3R5cGU6IlNFVCIscGF0aDpbLi4uZSxvXS5tYXAocz0+cy50b1N0cmluZygpKSx2YWx1ZTpDfSxsKS50aGVuKEgpfSxhcHBseShpLG8sSSl7YUEocik7bGV0IEM9ZVtlLmxlbmd0aC0xXTtpZihDPT09eHQpcmV0dXJuIFkoQSx7dHlwZToiRU5EUE9JTlQifSkudGhlbihIKTtpZihDPT09ImJpbmQiKXJldHVybiBMQShBLGUuc2xpY2UoMCwtMSkpO2xldFtsLHNdPXVlKEkpO3JldHVybiBZKEEse3R5cGU6IkFQUExZIixwYXRoOmUubWFwKGE9PmEudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Omx9LHMpLnRoZW4oSCl9LGNvbnN0cnVjdChpLG8pe2FBKHIpO2xldFtJLENdPXVlKG8pO3JldHVybiBZKEEse3R5cGU6IkNPTlNUUlVDVCIscGF0aDplLm1hcChsPT5sLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpJfSxDKS50aGVuKEgpfX0pO3JldHVybiBNdChuLEEpLG59ZnVuY3Rpb24gcXQoQSl7cmV0dXJuIEFycmF5LnByb3RvdHlwZS5jb25jYXQuYXBwbHkoW10sQSl9ZnVuY3Rpb24gdWUoQSl7bGV0IGU9QS5tYXAobEEpO3JldHVybltlLm1hcCh0PT50WzBdKSxxdChlLm1hcCh0PT50WzFdKSldfXZhciBoZT1uZXcgV2Vha01hcDtmdW5jdGlvbiBQQShBLGUpe3JldHVybiBoZS5zZXQoQSxlKSxBfWZ1bmN0aW9uIEt0KEEpe3JldHVybiBPYmplY3QuYXNzaWduKEEse1tFZV06ITB9KX1mdW5jdGlvbiBsQShBKXtmb3IobGV0W2UsdF1vZiBRZSlpZih0LmNhbkhhbmRsZShBKSl7bGV0W3Isbl09dC5zZXJpYWxpemUoQSk7cmV0dXJuW3t0eXBlOiJIQU5ETEVSIixuYW1lOmUsdmFsdWU6cn0sbl19cmV0dXJuW3t0eXBlOiJSQVciLHZhbHVlOkF9LGhlLmdldChBKXx8W11dfWZ1bmN0aW9uIEgoQSl7c3dpdGNoKEEudHlwZSl7Y2FzZSJIQU5ETEVSIjpyZXR1cm4gUWUuZ2V0KEEubmFtZSkuZGVzZXJpYWxpemUoQS52YWx1ZSk7Y2FzZSJSQVciOnJldHVybiBBLnZhbHVlfX1mdW5jdGlvbiBZKEEsZSx0KXtyZXR1cm4gbmV3IFByb21pc2Uocj0+e2xldCBuPVd0KCk7QS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBpKG8peyFvLmRhdGF8fCFvLmRhdGEuaWR8fG8uZGF0YS5pZCE9PW58fChBLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGkpLHIoby5kYXRhKSl9KSxBLnN0YXJ0JiZBLnN0YXJ0KCksQS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKHtpZDpufSxlKSx0KX0pfWZ1bmN0aW9uIFd0KCl7cmV0dXJuIG5ldyBBcnJheSg0KS5maWxsKDApLm1hcCgoKT0+TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKk51bWJlci5NQVhfU0FGRV9JTlRFR0VSKS50b1N0cmluZygxNikpLmpvaW4oIi0iKX1mdW5jdGlvbiBaKEEsZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIEEuYXBwbHkoZSxhcmd1bWVudHMpfX12YXJ7dG9TdHJpbmc6dnR9PU9iamVjdC5wcm90b3R5cGUse2dldFByb3RvdHlwZU9mOk1BfT1PYmplY3QsQ0E9KEE9PmU9PntsZXQgdD12dC5jYWxsKGUpO3JldHVybiBBW3RdfHwoQVt0XT10LnNsaWNlKDgsLTEpLnRvTG93ZXJDYXNlKCkpfSkoT2JqZWN0LmNyZWF0ZShudWxsKSksRz1BPT4oQT1BLnRvTG93ZXJDYXNlKCksZT0+Q0EoZSk9PT1BKSxjQT1BPT5lPT50eXBlb2YgZT09PUEse2lzQXJyYXk6cX09QXJyYXksWD1jQSgidW5kZWZpbmVkIik7ZnVuY3Rpb24ganQoQSl7cmV0dXJuIEEhPT1udWxsJiYhWChBKSYmQS5jb25zdHJ1Y3RvciE9PW51bGwmJiFYKEEuY29uc3RydWN0b3IpJiZOKEEuY29uc3RydWN0b3IuaXNCdWZmZXIpJiZBLmNvbnN0cnVjdG9yLmlzQnVmZmVyKEEpfXZhciBTZT1HKCJBcnJheUJ1ZmZlciIpO2Z1bmN0aW9uIF90KEEpe2xldCBlO3JldHVybiB0eXBlb2YgQXJyYXlCdWZmZXI8InUiJiZBcnJheUJ1ZmZlci5pc1ZpZXc/ZT1BcnJheUJ1ZmZlci5pc1ZpZXcoQSk6ZT1BJiZBLmJ1ZmZlciYmU2UoQS5idWZmZXIpLGV9dmFyIHp0PWNBKCJzdHJpbmciKSxOPWNBKCJmdW5jdGlvbiIpLEZlPWNBKCJudW1iZXIiKSx1QT1BPT5BIT09bnVsbCYmdHlwZW9mIEE9PSJvYmplY3QiLFZ0PUE9PkE9PT0hMHx8QT09PSExLEJBPUE9PntpZihDQShBKSE9PSJvYmplY3QiKXJldHVybiExO2xldCBlPU1BKEEpO3JldHVybihlPT09bnVsbHx8ZT09PU9iamVjdC5wcm90b3R5cGV8fE9iamVjdC5nZXRQcm90b3R5cGVPZihlKT09PW51bGwpJiYhKFN5bWJvbC50b1N0cmluZ1RhZyBpbiBBKSYmIShTeW1ib2wuaXRlcmF0b3IgaW4gQSl9LFp0PUcoIkRhdGUiKSxYdD1HKCJGaWxlIiksJHQ9RygiQmxvYiIpLEFyPUcoIkZpbGVMaXN0IiksZXI9QT0+dUEoQSkmJk4oQS5waXBlKSx0cj1BPT57bGV0IGU7cmV0dXJuIEEmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJkEgaW5zdGFuY2VvZiBGb3JtRGF0YXx8TihBLmFwcGVuZCkmJigoZT1DQShBKSk9PT0iZm9ybWRhdGEifHxlPT09Im9iamVjdCImJk4oQS50b1N0cmluZykmJkEudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0scnI9RygiVVJMU2VhcmNoUGFyYW1zIiksaXI9QT0+QS50cmltP0EudHJpbSgpOkEucmVwbGFjZSgvXltcc1x1RkVGRlx4QTBdK3xbXHNcdUZFRkZceEEwXSskL2csIiIpO2Z1bmN0aW9uICQoQSxlLHthbGxPd25LZXlzOnQ9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgcixuO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSxxKEEpKWZvcihyPTAsbj1BLmxlbmd0aDtyPG47cisrKWUuY2FsbChudWxsLEFbcl0scixBKTtlbHNle2xldCBpPXQ/T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSk6T2JqZWN0LmtleXMoQSksbz1pLmxlbmd0aCxJO2ZvcihyPTA7cjxvO3IrKylJPWlbcl0sZS5jYWxsKG51bGwsQVtJXSxJLEEpfX1mdW5jdGlvbiBrZShBLGUpe2U9ZS50b0xvd2VyQ2FzZSgpO2xldCB0PU9iamVjdC5rZXlzKEEpLHI9dC5sZW5ndGgsbjtmb3IoO3ItLSA+MDspaWYobj10W3JdLGU9PT1uLnRvTG93ZXJDYXNlKCkpcmV0dXJuIG47cmV0dXJuIG51bGx9dmFyIFJlPXR5cGVvZiBnbG9iYWxUaGlzPCJ1Ij9nbG9iYWxUaGlzOnR5cGVvZiBzZWxmPCJ1Ij9zZWxmOnR5cGVvZiB3aW5kb3c8InUiP3dpbmRvdzpnbG9iYWwsYmU9QT0+IVgoQSkmJkEhPT1SZTtmdW5jdGlvbiBIQSgpe2xldHtjYXNlbGVzczpBfT1iZSh0aGlzKSYmdGhpc3x8e30sZT17fSx0PShyLG4pPT57bGV0IGk9QSYma2UoZSxuKXx8bjtCQShlW2ldKSYmQkEocik/ZVtpXT1IQShlW2ldLHIpOkJBKHIpP2VbaV09SEEoe30scik6cShyKT9lW2ldPXIuc2xpY2UoKTplW2ldPXJ9O2ZvcihsZXQgcj0wLG49YXJndW1lbnRzLmxlbmd0aDtyPG47cisrKWFyZ3VtZW50c1tyXSYmJChhcmd1bWVudHNbcl0sdCk7cmV0dXJuIGV9dmFyIG5yPShBLGUsdCx7YWxsT3duS2V5czpyfT17fSk9PigkKGUsKG4saSk9Pnt0JiZOKG4pP0FbaV09WihuLHQpOkFbaV09bn0se2FsbE93bktleXM6cn0pLEEpLG9yPUE9PihBLmNoYXJDb2RlQXQoMCk9PT02NTI3OSYmKEE9QS5zbGljZSgxKSksQSksYXI9KEEsZSx0LHIpPT57QS5wcm90b3R5cGU9T2JqZWN0LmNyZWF0ZShlLnByb3RvdHlwZSxyKSxBLnByb3RvdHlwZS5jb25zdHJ1Y3Rvcj1BLE9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJzdXBlciIse3ZhbHVlOmUucHJvdG90eXBlfSksdCYmT2JqZWN0LmFzc2lnbihBLnByb3RvdHlwZSx0KX0sc3I9KEEsZSx0LHIpPT57bGV0IG4saSxvLEk9e307aWYoZT1lfHx7fSxBPT1udWxsKXJldHVybiBlO2Rve2ZvcihuPU9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKEEpLGk9bi5sZW5ndGg7aS0tID4wOylvPW5baV0sKCFyfHxyKG8sQSxlKSkmJiFJW29dJiYoZVtvXT1BW29dLElbb109ITApO0E9dCE9PSExJiZNQShBKX13aGlsZShBJiYoIXR8fHQoQSxlKSkmJkEhPT1PYmplY3QucHJvdG90eXBlKTtyZXR1cm4gZX0sSXI9KEEsZSx0KT0+e0E9U3RyaW5nKEEpLCh0PT09dm9pZCAwfHx0PkEubGVuZ3RoKSYmKHQ9QS5sZW5ndGgpLHQtPWUubGVuZ3RoO2xldCByPUEuaW5kZXhPZihlLHQpO3JldHVybiByIT09LTEmJnI9PT10fSxncj1BPT57aWYoIUEpcmV0dXJuIG51bGw7aWYocShBKSlyZXR1cm4gQTtsZXQgZT1BLmxlbmd0aDtpZighRmUoZSkpcmV0dXJuIG51bGw7bGV0IHQ9bmV3IEFycmF5KGUpO2Zvcig7ZS0tID4wOyl0W2VdPUFbZV07cmV0dXJuIHR9LGxyPShBPT5lPT5BJiZlIGluc3RhbmNlb2YgQSkodHlwZW9mIFVpbnQ4QXJyYXk8InUiJiZNQShVaW50OEFycmF5KSksQnI9KEEsZSk9PntsZXQgcj0oQSYmQVtTeW1ib2wuaXRlcmF0b3JdKS5jYWxsKEEpLG47Zm9yKDsobj1yLm5leHQoKSkmJiFuLmRvbmU7KXtsZXQgaT1uLnZhbHVlO2UuY2FsbChBLGlbMF0saVsxXSl9fSxDcj0oQSxlKT0+e2xldCB0LHI9W107Zm9yKDsodD1BLmV4ZWMoZSkpIT09bnVsbDspci5wdXNoKHQpO3JldHVybiByfSxjcj1HKCJIVE1MRm9ybUVsZW1lbnQiKSx1cj1BPT5BLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvWy1fXHNdKFthLXpcZF0pKFx3KikvZyxmdW5jdGlvbih0LHIsbil7cmV0dXJuIHIudG9VcHBlckNhc2UoKStufSksd2U9KCh7aGFzT3duUHJvcGVydHk6QX0pPT4oZSx0KT0+QS5jYWxsKGUsdCkpKE9iamVjdC5wcm90b3R5cGUpLEVyPUcoIlJlZ0V4cCIpLFVlPShBLGUpPT57bGV0IHQ9T2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoQSkscj17fTskKHQsKG4saSk9PntsZXQgbzsobz1lKG4saSxBKSkhPT0hMSYmKHJbaV09b3x8bil9KSxPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBLHIpfSxmcj1BPT57VWUoQSwoZSx0KT0+e2lmKE4oQSkmJlsiYXJndW1lbnRzIiwiY2FsbGVyIiwiY2FsbGVlIl0uaW5kZXhPZih0KSE9PS0xKXJldHVybiExO2xldCByPUFbdF07aWYoTihyKSl7aWYoZS5lbnVtZXJhYmxlPSExLCJ3cml0YWJsZSJpbiBlKXtlLndyaXRhYmxlPSExO3JldHVybn1lLnNldHx8KGUuc2V0PSgpPT57dGhyb3cgRXJyb3IoIkNhbiBub3QgcmV3cml0ZSByZWFkLW9ubHkgbWV0aG9kICciK3QrIiciKX0pfX0pfSxRcj0oQSxlKT0+e2xldCB0PXt9LHI9bj0+e24uZm9yRWFjaChpPT57dFtpXT0hMH0pfTtyZXR1cm4gcShBKT9yKEEpOnIoU3RyaW5nKEEpLnNwbGl0KGUpKSx0fSxwcj0oKT0+e30sZHI9KEEsZSk9PihBPStBLE51bWJlci5pc0Zpbml0ZShBKT9BOmUpLEpBPSJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiIsRGU9IjAxMjM0NTY3ODkiLE5lPXtESUdJVDpEZSxBTFBIQTpKQSxBTFBIQV9ESUdJVDpKQStKQS50b1VwcGVyQ2FzZSgpK0RlfSxtcj0oQT0xNixlPU5lLkFMUEhBX0RJR0lUKT0+e2xldCB0PSIiLHtsZW5ndGg6cn09ZTtmb3IoO0EtLTspdCs9ZVtNYXRoLnJhbmRvbSgpKnJ8MF07cmV0dXJuIHR9O2Z1bmN0aW9uIGhyKEEpe3JldHVybiEhKEEmJk4oQS5hcHBlbmQpJiZBW1N5bWJvbC50b1N0cmluZ1RhZ109PT0iRm9ybURhdGEiJiZBW1N5bWJvbC5pdGVyYXRvcl0pfXZhciB5cj1BPT57bGV0IGU9bmV3IEFycmF5KDEwKSx0PShyLG4pPT57aWYodUEocikpe2lmKGUuaW5kZXhPZihyKT49MClyZXR1cm47aWYoISgidG9KU09OImluIHIpKXtlW25dPXI7bGV0IGk9cShyKT9bXTp7fTtyZXR1cm4gJChyLChvLEkpPT57bGV0IEM9dChvLG4rMSk7IVgoQykmJihpW0ldPUMpfSksZVtuXT12b2lkIDAsaX19cmV0dXJuIHJ9O3JldHVybiB0KEEsMCl9LHdyPUcoIkFzeW5jRnVuY3Rpb24iKSxEcj1BPT5BJiYodUEoQSl8fE4oQSkpJiZOKEEudGhlbikmJk4oQS5jYXRjaCksZz17aXNBcnJheTpxLGlzQXJyYXlCdWZmZXI6U2UsaXNCdWZmZXI6anQsaXNGb3JtRGF0YTp0cixpc0FycmF5QnVmZmVyVmlldzpfdCxpc1N0cmluZzp6dCxpc051bWJlcjpGZSxpc0Jvb2xlYW46VnQsaXNPYmplY3Q6dUEsaXNQbGFpbk9iamVjdDpCQSxpc1VuZGVmaW5lZDpYLGlzRGF0ZTpadCxpc0ZpbGU6WHQsaXNCbG9iOiR0LGlzUmVnRXhwOkVyLGlzRnVuY3Rpb246Tixpc1N0cmVhbTplcixpc1VSTFNlYXJjaFBhcmFtczpycixpc1R5cGVkQXJyYXk6bHIsaXNGaWxlTGlzdDpBcixmb3JFYWNoOiQsbWVyZ2U6SEEsZXh0ZW5kOm5yLHRyaW06aXIsc3RyaXBCT006b3IsaW5oZXJpdHM6YXIsdG9GbGF0T2JqZWN0OnNyLGtpbmRPZjpDQSxraW5kT2ZUZXN0OkcsZW5kc1dpdGg6SXIsdG9BcnJheTpncixmb3JFYWNoRW50cnk6QnIsbWF0Y2hBbGw6Q3IsaXNIVE1MRm9ybTpjcixoYXNPd25Qcm9wZXJ0eTp3ZSxoYXNPd25Qcm9wOndlLHJlZHVjZURlc2NyaXB0b3JzOlVlLGZyZWV6ZU1ldGhvZHM6ZnIsdG9PYmplY3RTZXQ6UXIsdG9DYW1lbENhc2U6dXIsbm9vcDpwcix0b0Zpbml0ZU51bWJlcjpkcixmaW5kS2V5OmtlLGdsb2JhbDpSZSxpc0NvbnRleHREZWZpbmVkOmJlLEFMUEhBQkVUOk5lLGdlbmVyYXRlU3RyaW5nOm1yLGlzU3BlY0NvbXBsaWFudEZvcm06aHIsdG9KU09OT2JqZWN0OnlyLGlzQXN5bmNGbjp3cixpc1RoZW5hYmxlOkRyfTtmdW5jdGlvbiBLKEEsZSx0LHIsbil7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPUEsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIixlJiYodGhpcy5jb2RlPWUpLHQmJih0aGlzLmNvbmZpZz10KSxyJiYodGhpcy5yZXF1ZXN0PXIpLG4mJih0aGlzLnJlc3BvbnNlPW4pfWcuaW5oZXJpdHMoSyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOmcudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIEdlPUsucHJvdG90eXBlLFRlPXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goQT0+e1RlW0FdPXt2YWx1ZTpBfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEssVGUpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShHZSwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtLLmZyb209KEEsZSx0LHIsbixpKT0+e2xldCBvPU9iamVjdC5jcmVhdGUoR2UpO3JldHVybiBnLnRvRmxhdE9iamVjdChBLG8sZnVuY3Rpb24oQyl7cmV0dXJuIEMhPT1FcnJvci5wcm90b3R5cGV9LEk9PkkhPT0iaXNBeGlvc0Vycm9yIiksSy5jYWxsKG8sQS5tZXNzYWdlLGUsdCxyLG4pLG8uY2F1c2U9QSxvLm5hbWU9QS5uYW1lLGkmJk9iamVjdC5hc3NpZ24obyxpKSxvfTt2YXIgcD1LO3ZhciBFQT1udWxsO2Z1bmN0aW9uIFlBKEEpe3JldHVybiBnLmlzUGxhaW5PYmplY3QoQSl8fGcuaXNBcnJheShBKX1mdW5jdGlvbiB4ZShBKXtyZXR1cm4gZy5lbmRzV2l0aChBLCJbXSIpP0Euc2xpY2UoMCwtMik6QX1mdW5jdGlvbiBMZShBLGUsdCl7cmV0dXJuIEE/QS5jb25jYXQoZSkubWFwKGZ1bmN0aW9uKG4saSl7cmV0dXJuIG49eGUobiksIXQmJmk/IlsiK24rIl0iOm59KS5qb2luKHQ/Ii4iOiIiKTplfWZ1bmN0aW9uIFNyKEEpe3JldHVybiBnLmlzQXJyYXkoQSkmJiFBLnNvbWUoWUEpfXZhciBGcj1nLnRvRmxhdE9iamVjdChnLHt9LG51bGwsZnVuY3Rpb24oZSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KGUpfSk7ZnVuY3Rpb24ga3IoQSxlLHQpe2lmKCFnLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO2U9ZXx8bmV3KEVBfHxGb3JtRGF0YSksdD1nLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oYyxRKXtyZXR1cm4hZy5pc1VuZGVmaW5lZChRW2NdKX0pO2xldCByPXQubWV0YVRva2VucyxuPXQudmlzaXRvcnx8cyxpPXQuZG90cyxvPXQuaW5kZXhlcyxDPSh0LkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJmcuaXNTcGVjQ29tcGxpYW50Rm9ybShlKTtpZighZy5pc0Z1bmN0aW9uKG4pKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gbCh1KXtpZih1PT09bnVsbClyZXR1cm4iIjtpZihnLmlzRGF0ZSh1KSlyZXR1cm4gdS50b0lTT1N0cmluZygpO2lmKCFDJiZnLmlzQmxvYih1KSl0aHJvdyBuZXcgcCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gZy5pc0FycmF5QnVmZmVyKHUpfHxnLmlzVHlwZWRBcnJheSh1KT9DJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbdV0pOkJ1ZmZlci5mcm9tKHUpOnV9ZnVuY3Rpb24gcyh1LGMsUSl7bGV0IGQ9dTtpZih1JiYhUSYmdHlwZW9mIHU9PSJvYmplY3QiKXtpZihnLmVuZHNXaXRoKGMsInt9IikpYz1yP2M6Yy5zbGljZSgwLC0yKSx1PUpTT04uc3RyaW5naWZ5KHUpO2Vsc2UgaWYoZy5pc0FycmF5KHUpJiZTcih1KXx8KGcuaXNGaWxlTGlzdCh1KXx8Zy5lbmRzV2l0aChjLCJbXSIpKSYmKGQ9Zy50b0FycmF5KHUpKSlyZXR1cm4gYz14ZShjKSxkLmZvckVhY2goZnVuY3Rpb24oayxEdCl7IShnLmlzVW5kZWZpbmVkKGspfHxrPT09bnVsbCkmJmUuYXBwZW5kKG89PT0hMD9MZShbY10sRHQsaSk6bz09PW51bGw/YzpjKyJbXSIsbChrKSl9KSwhMX1yZXR1cm4gWUEodSk/ITA6KGUuYXBwZW5kKExlKFEsYyxpKSxsKHUpKSwhMSl9bGV0IGE9W10sRT1PYmplY3QuYXNzaWduKEZyLHtkZWZhdWx0VmlzaXRvcjpzLGNvbnZlcnRWYWx1ZTpsLGlzVmlzaXRhYmxlOllBfSk7ZnVuY3Rpb24gQih1LGMpe2lmKCFnLmlzVW5kZWZpbmVkKHUpKXtpZihhLmluZGV4T2YodSkhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrYy5qb2luKCIuIikpO2EucHVzaCh1KSxnLmZvckVhY2godSxmdW5jdGlvbihkLGIpeyghKGcuaXNVbmRlZmluZWQoZCl8fGQ9PT1udWxsKSYmbi5jYWxsKGUsZCxnLmlzU3RyaW5nKGIpP2IudHJpbSgpOmIsYyxFKSk9PT0hMCYmQihkLGM/Yy5jb25jYXQoYik6W2JdKX0pLGEucG9wKCl9fWlmKCFnLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gQihBKSxlfXZhciBPPWtyO2Z1bmN0aW9uIE9lKEEpe2xldCBlPXsiISI6IiUyMSIsIiciOiIlMjciLCIoIjoiJTI4IiwiKSI6IiUyOSIsIn4iOiIlN0UiLCIlMjAiOiIrIiwiJTAwIjoiXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shJygpfl18JTIwfCUwMC9nLGZ1bmN0aW9uKHIpe3JldHVybiBlW3JdfSl9ZnVuY3Rpb24gUGUoQSxlKXt0aGlzLl9wYWlycz1bXSxBJiZPKEEsdGhpcyxlKX12YXIgSmU9UGUucHJvdG90eXBlO0plLmFwcGVuZD1mdW5jdGlvbihlLHQpe3RoaXMuX3BhaXJzLnB1c2goW2UsdF0pfTtKZS50b1N0cmluZz1mdW5jdGlvbihlKXtsZXQgdD1lP2Z1bmN0aW9uKHIpe3JldHVybiBlLmNhbGwodGhpcyxyLE9lKX06T2U7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihuKXtyZXR1cm4gdChuWzBdKSsiPSIrdChuWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIGZBPVBlO2Z1bmN0aW9uIFJyKEEpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvJTNBL2dpLCI6IikucmVwbGFjZSgvJTI0L2csIiQiKS5yZXBsYWNlKC8lMkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjAvZywiKyIpLnJlcGxhY2UoLyU1Qi9naSwiWyIpLnJlcGxhY2UoLyU1RC9naSwiXSIpfWZ1bmN0aW9uIEFBKEEsZSx0KXtpZighZSlyZXR1cm4gQTtsZXQgcj10JiZ0LmVuY29kZXx8UnIsbj10JiZ0LnNlcmlhbGl6ZSxpO2lmKG4/aT1uKGUsdCk6aT1nLmlzVVJMU2VhcmNoUGFyYW1zKGUpP2UudG9TdHJpbmcoKTpuZXcgZkEoZSx0KS50b1N0cmluZyhyKSxpKXtsZXQgbz1BLmluZGV4T2YoIiMiKTtvIT09LTEmJihBPUEuc2xpY2UoMCxvKSksQSs9KEEuaW5kZXhPZigiPyIpPT09LTE/Ij8iOiImIikraX1yZXR1cm4gQX12YXIgcUE9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLmhhbmRsZXJzPVtdfXVzZShlLHQscil7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOmUscmVqZWN0ZWQ6dCxzeW5jaHJvbm91czpyP3Iuc3luY2hyb25vdXM6ITEscnVuV2hlbjpyP3IucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX1lamVjdChlKXt0aGlzLmhhbmRsZXJzW2VdJiYodGhpcy5oYW5kbGVyc1tlXT1udWxsKX1jbGVhcigpe3RoaXMuaGFuZGxlcnMmJih0aGlzLmhhbmRsZXJzPVtdKX1mb3JFYWNoKGUpe2cuZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKHIpe3IhPT1udWxsJiZlKHIpfSl9fSxLQT1xQTt2YXIgUUE9e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITF9O3ZhciBIZT10eXBlb2YgVVJMU2VhcmNoUGFyYW1zPCJ1Ij9VUkxTZWFyY2hQYXJhbXM6ZkE7dmFyIE1lPXR5cGVvZiBGb3JtRGF0YTwidSI/Rm9ybURhdGE6bnVsbDt2YXIgWWU9dHlwZW9mIEJsb2I8InUiP0Jsb2I6bnVsbDt2YXIgcWU9e2lzQnJvd3NlcjohMCxjbGFzc2VzOntVUkxTZWFyY2hQYXJhbXM6SGUsRm9ybURhdGE6TWUsQmxvYjpZZX0scHJvdG9jb2xzOlsiaHR0cCIsImh0dHBzIiwiZmlsZSIsImJsb2IiLCJ1cmwiLCJkYXRhIl19O3ZhciBXQT17fTtGdChXQSx7aGFzQnJvd3NlckVudjooKT0+S2UsaGFzU3RhbmRhcmRCcm93c2VyRW52OigpPT5icixoYXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY6KCk9PlVyfSk7dmFyIEtlPXR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUiLGJyPShBPT5LZSYmWyJSZWFjdE5hdGl2ZSIsIk5hdGl2ZVNjcmlwdCIsIk5TIl0uaW5kZXhPZihBKTwwKSh0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmbmF2aWdhdG9yLnByb2R1Y3QpLFVyPXR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIjt2YXIgRD17Li4uV0EsLi4ucWV9O2Z1bmN0aW9uIHZBKEEsZSl7cmV0dXJuIE8oQSxuZXcgRC5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyxPYmplY3QuYXNzaWduKHt2aXNpdG9yOmZ1bmN0aW9uKHQscixuLGkpe3JldHVybiBELmlzTm9kZSYmZy5pc0J1ZmZlcih0KT8odGhpcy5hcHBlbmQocix0LnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOmkuZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfX0sZSkpfWZ1bmN0aW9uIE5yKEEpe3JldHVybiBnLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxBKS5tYXAoZT0+ZVswXT09PSJbXSI/IiI6ZVsxXXx8ZVswXSl9ZnVuY3Rpb24gR3IoQSl7bGV0IGU9e30sdD1PYmplY3Qua2V5cyhBKSxyLG49dC5sZW5ndGgsaTtmb3Iocj0wO3I8bjtyKyspaT10W3JdLGVbaV09QVtpXTtyZXR1cm4gZX1mdW5jdGlvbiBUcihBKXtmdW5jdGlvbiBlKHQscixuLGkpe2xldCBvPXRbaSsrXSxJPU51bWJlci5pc0Zpbml0ZSgrbyksQz1pPj10Lmxlbmd0aDtyZXR1cm4gbz0hbyYmZy5pc0FycmF5KG4pP24ubGVuZ3RoOm8sQz8oZy5oYXNPd25Qcm9wKG4sbyk/bltvXT1bbltvXSxyXTpuW29dPXIsIUkpOigoIW5bb118fCFnLmlzT2JqZWN0KG5bb10pKSYmKG5bb109W10pLGUodCxyLG5bb10saSkmJmcuaXNBcnJheShuW29dKSYmKG5bb109R3IobltvXSkpLCFJKX1pZihnLmlzRm9ybURhdGEoQSkmJmcuaXNGdW5jdGlvbihBLmVudHJpZXMpKXtsZXQgdD17fTtyZXR1cm4gZy5mb3JFYWNoRW50cnkoQSwocixuKT0+e2UoTnIociksbix0LDApfSksdH1yZXR1cm4gbnVsbH12YXIgcEE9VHI7ZnVuY3Rpb24gTHIoQSxlLHQpe2lmKGcuaXNTdHJpbmcoQSkpdHJ5e3JldHVybihlfHxKU09OLnBhcnNlKShBKSxnLnRyaW0oQSl9Y2F0Y2gocil7aWYoci5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyByfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoQSl9dmFyIGpBPXt0cmFuc2l0aW9uYWw6UUEsYWRhcHRlcjpbInhociIsImh0dHAiXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihlLHQpe2xldCByPXQuZ2V0Q29udGVudFR5cGUoKXx8IiIsbj1yLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxpPWcuaXNPYmplY3QoZSk7aWYoaSYmZy5pc0hUTUxGb3JtKGUpJiYoZT1uZXcgRm9ybURhdGEoZSkpLGcuaXNGb3JtRGF0YShlKSlyZXR1cm4gbiYmbj9KU09OLnN0cmluZ2lmeShwQShlKSk6ZTtpZihnLmlzQXJyYXlCdWZmZXIoZSl8fGcuaXNCdWZmZXIoZSl8fGcuaXNTdHJlYW0oZSl8fGcuaXNGaWxlKGUpfHxnLmlzQmxvYihlKSlyZXR1cm4gZTtpZihnLmlzQXJyYXlCdWZmZXJWaWV3KGUpKXJldHVybiBlLmJ1ZmZlcjtpZihnLmlzVVJMU2VhcmNoUGFyYW1zKGUpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLGUudG9TdHJpbmcoKTtsZXQgSTtpZihpKXtpZihyLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiB2QShlLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKEk9Zy5pc0ZpbGVMaXN0KGUpKXx8ci5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBDPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4gTyhJP3siZmlsZXNbXSI6ZX06ZSxDJiZuZXcgQyx0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIGl8fG4/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSxMcihlKSk6ZX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihlKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8akEudHJhbnNpdGlvbmFsLHI9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxuPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKGUmJmcuaXNTdHJpbmcoZSkmJihyJiYhdGhpcy5yZXNwb25zZVR5cGV8fG4pKXtsZXQgbz0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZuO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlKX1jYXRjaChJKXtpZihvKXRocm93IEkubmFtZT09PSJTeW50YXhFcnJvciI/cC5mcm9tKEkscC5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTpJfX1yZXR1cm4gZX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6RC5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6RC5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0yMDAmJmU8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07Zy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLEE9PntqQS5oZWFkZXJzW0FdPXt9fSk7dmFyIFc9akE7dmFyIHhyPWcudG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksV2U9QT0+e2xldCBlPXt9LHQscixuO3JldHVybiBBJiZBLnNwbGl0KGAKYCkuZm9yRWFjaChmdW5jdGlvbihvKXtuPW8uaW5kZXhPZigiOiIpLHQ9by5zdWJzdHJpbmcoMCxuKS50cmltKCkudG9Mb3dlckNhc2UoKSxyPW8uc3Vic3RyaW5nKG4rMSkudHJpbSgpLCEoIXR8fGVbdF0mJnhyW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2gocik6ZVt0XT1bcl06ZVt0XT1lW3RdP2VbdF0rIiwgIityOnIpfSksZX07dmFyIHZlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBkQShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6Zy5pc0FycmF5KEEpP0EubWFwKGRBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gT3IoQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15ccyw7PV0rKVxzKig/Oj1ccyooW14sO10rKSk/L2cscjtmb3IoO3I9dC5leGVjKEEpOyllW3JbMV1dPXJbMl07cmV0dXJuIGV9dmFyIFByPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhIyQlJicqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIF9BKEEsZSx0LHIsbil7aWYoZy5pc0Z1bmN0aW9uKHIpKXJldHVybiByLmNhbGwodGhpcyxlLHQpO2lmKG4mJihlPXQpLCEhZy5pc1N0cmluZyhlKSl7aWYoZy5pc1N0cmluZyhyKSlyZXR1cm4gZS5pbmRleE9mKHIpIT09LTE7aWYoZy5pc1JlZ0V4cChyKSlyZXR1cm4gci50ZXN0KGUpfX1mdW5jdGlvbiBKcihBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxkXSkoXHcqKS9nLChlLHQscik9PnQudG9VcHBlckNhc2UoKStyKX1mdW5jdGlvbiBIcihBLGUpe2xldCB0PWcudG9DYW1lbENhc2UoIiAiK2UpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChyPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KEEscit0LHt2YWx1ZTpmdW5jdGlvbihuLGksbyl7cmV0dXJuIHRoaXNbcl0uY2FsbCh0aGlzLGUsbixpLG8pfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciB2PWNsYXNze2NvbnN0cnVjdG9yKGUpe2UmJnRoaXMuc2V0KGUpfXNldChlLHQscil7bGV0IG49dGhpcztmdW5jdGlvbiBpKEksQyxsKXtsZXQgcz1lQShDKTtpZighcyl0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IGE9Zy5maW5kS2V5KG4scyk7KCFhfHxuW2FdPT09dm9pZCAwfHxsPT09ITB8fGw9PT12b2lkIDAmJm5bYV0hPT0hMSkmJihuW2F8fENdPWRBKEkpKX1sZXQgbz0oSSxDKT0+Zy5mb3JFYWNoKEksKGwscyk9PmkobCxzLEMpKTtyZXR1cm4gZy5pc1BsYWluT2JqZWN0KGUpfHxlIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9vKGUsdCk6Zy5pc1N0cmluZyhlKSYmKGU9ZS50cmltKCkpJiYhUHIoZSk/byhXZShlKSx0KTplIT1udWxsJiZpKHQsZSxyKSx0aGlzfWdldChlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IHI9Zy5maW5kS2V5KHRoaXMsZSk7aWYocil7bGV0IG49dGhpc1tyXTtpZighdClyZXR1cm4gbjtpZih0PT09ITApcmV0dXJuIE9yKG4pO2lmKGcuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMsbixyKTtpZihnLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMobik7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IHI9Zy5maW5kS2V5KHRoaXMsZSk7cmV0dXJuISEociYmdGhpc1tyXSE9PXZvaWQgMCYmKCF0fHxfQSh0aGlzLHRoaXNbcl0scix0KSkpfXJldHVybiExfWRlbGV0ZShlLHQpe2xldCByPXRoaXMsbj0hMTtmdW5jdGlvbiBpKG8pe2lmKG89ZUEobyksbyl7bGV0IEk9Zy5maW5kS2V5KHIsbyk7SSYmKCF0fHxfQShyLHJbSV0sSSx0KSkmJihkZWxldGUgcltJXSxuPSEwKX19cmV0dXJuIGcuaXNBcnJheShlKT9lLmZvckVhY2goaSk6aShlKSxufWNsZWFyKGUpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLHI9dC5sZW5ndGgsbj0hMTtmb3IoO3ItLTspe2xldCBpPXRbcl07KCFlfHxfQSh0aGlzLHRoaXNbaV0saSxlLCEwKSkmJihkZWxldGUgdGhpc1tpXSxuPSEwKX1yZXR1cm4gbn1ub3JtYWxpemUoZSl7bGV0IHQ9dGhpcyxyPXt9O3JldHVybiBnLmZvckVhY2godGhpcywobixpKT0+e2xldCBvPWcuZmluZEtleShyLGkpO2lmKG8pe3Rbb109ZEEobiksZGVsZXRlIHRbaV07cmV0dXJufWxldCBJPWU/SnIoaSk6U3RyaW5nKGkpLnRyaW0oKTtJIT09aSYmZGVsZXRlIHRbaV0sdFtJXT1kQShuKSxyW0ldPSEwfSksdGhpc31jb25jYXQoLi4uZSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uZSl9dG9KU09OKGUpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIGcuZm9yRWFjaCh0aGlzLChyLG4pPT57ciE9bnVsbCYmciE9PSExJiYodFtuXT1lJiZnLmlzQXJyYXkocik/ci5qb2luKCIsICIpOnIpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbZSx0XSk9PmUrIjogIit0KS5qb2luKGAKYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIHRoaXM/ZTpuZXcgdGhpcyhlKX1zdGF0aWMgY29uY2F0KGUsLi4udCl7bGV0IHI9bmV3IHRoaXMoZSk7cmV0dXJuIHQuZm9yRWFjaChuPT5yLnNldChuKSkscn1zdGF0aWMgYWNjZXNzb3IoZSl7bGV0IHI9KHRoaXNbdmVdPXRoaXNbdmVdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsbj10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBpKG8pe2xldCBJPWVBKG8pO3JbSV18fChIcihuLG8pLHJbSV09ITApfXJldHVybiBnLmlzQXJyYXkoZSk/ZS5mb3JFYWNoKGkpOmkoZSksdGhpc319O3YuYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO2cucmVkdWNlRGVzY3JpcHRvcnModi5wcm90b3R5cGUsKHt2YWx1ZTpBfSxlKT0+e2xldCB0PWVbMF0udG9VcHBlckNhc2UoKStlLnNsaWNlKDEpO3JldHVybntnZXQ6KCk9PkEsc2V0KHIpe3RoaXNbdF09cn19fSk7Zy5mcmVlemVNZXRob2RzKHYpO3ZhciBTPXY7ZnVuY3Rpb24gdEEoQSxlKXtsZXQgdD10aGlzfHxXLHI9ZXx8dCxuPVMuZnJvbShyLmhlYWRlcnMpLGk9ci5kYXRhO3JldHVybiBnLmZvckVhY2goQSxmdW5jdGlvbihJKXtpPUkuY2FsbCh0LGksbi5ub3JtYWxpemUoKSxlP2Uuc3RhdHVzOnZvaWQgMCl9KSxuLm5vcm1hbGl6ZSgpLGl9ZnVuY3Rpb24gckEoQSl7cmV0dXJuISEoQSYmQS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBqZShBLGUsdCl7cC5jYWxsKHRoaXMsQT8/ImNhbmNlbGVkIixwLkVSUl9DQU5DRUxFRCxlLHQpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9Zy5pbmhlcml0cyhqZSxwLHtfX0NBTkNFTF9fOiEwfSk7dmFyIFA9amU7ZnVuY3Rpb24gekEoQSxlLHQpe2xldCByPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IXJ8fHIodC5zdGF0dXMpP0EodCk6ZShuZXcgcCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFtwLkVSUl9CQURfUkVRVUVTVCxwLkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfXZhciBfZT1ELmhhc1N0YW5kYXJkQnJvd3NlckVudj97d3JpdGUoQSxlLHQscixuLGkpe2xldCBvPVtBKyI9IitlbmNvZGVVUklDb21wb25lbnQoZSldO2cuaXNOdW1iZXIodCkmJm8ucHVzaCgiZXhwaXJlcz0iK25ldyBEYXRlKHQpLnRvR01UU3RyaW5nKCkpLGcuaXNTdHJpbmcocikmJm8ucHVzaCgicGF0aD0iK3IpLGcuaXNTdHJpbmcobikmJm8ucHVzaCgiZG9tYWluPSIrbiksaT09PSEwJiZvLnB1c2goInNlY3VyZSIpLGRvY3VtZW50LmNvb2tpZT1vLmpvaW4oIjsgIil9LHJlYWQoQSl7bGV0IGU9ZG9jdW1lbnQuY29va2llLm1hdGNoKG5ldyBSZWdFeHAoIihefDtcXHMqKSgiK0ErIik9KFteO10qKSIpKTtyZXR1cm4gZT9kZWNvZGVVUklDb21wb25lbnQoZVszXSk6bnVsbH0scmVtb3ZlKEEpe3RoaXMud3JpdGUoQSwiIixEYXRlLm5vdygpLTg2NGU1KX19Ont3cml0ZSgpe30scmVhZCgpe3JldHVybiBudWxsfSxyZW1vdmUoKXt9fTtmdW5jdGlvbiBWQShBKXtyZXR1cm4vXihbYS16XVthLXpcZCtcLS5dKjopP1wvXC8vaS50ZXN0KEEpfWZ1bmN0aW9uIFpBKEEsZSl7cmV0dXJuIGU/QS5yZXBsYWNlKC9cLyskLywiIikrIi8iK2UucmVwbGFjZSgvXlwvKy8sIiIpOkF9ZnVuY3Rpb24gaUEoQSxlKXtyZXR1cm4gQSYmIVZBKGUpP1pBKEEsZSk6ZX12YXIgemU9RC5oYXNTdGFuZGFyZEJyb3dzZXJFbnY/ZnVuY3Rpb24oKXtsZXQgZT0vKG1zaWV8dHJpZGVudCkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpLHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYSIpLHI7ZnVuY3Rpb24gbihpKXtsZXQgbz1pO3JldHVybiBlJiYodC5zZXRBdHRyaWJ1dGUoImhyZWYiLG8pLG89dC5ocmVmKSx0LnNldEF0dHJpYnV0ZSgiaHJlZiIsbykse2hyZWY6dC5ocmVmLHByb3RvY29sOnQucHJvdG9jb2w/dC5wcm90b2NvbC5yZXBsYWNlKC86JC8sIiIpOiIiLGhvc3Q6dC5ob3N0LHNlYXJjaDp0LnNlYXJjaD90LnNlYXJjaC5yZXBsYWNlKC9eXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiMvLCIiKToiIixob3N0bmFtZTp0Lmhvc3RuYW1lLHBvcnQ6dC5wb3J0LHBhdGhuYW1lOnQucGF0aG5hbWUuY2hhckF0KDApPT09Ii8iP3QucGF0aG5hbWU6Ii8iK3QucGF0aG5hbWV9fXJldHVybiByPW4od2luZG93LmxvY2F0aW9uLmhyZWYpLGZ1bmN0aW9uKG8pe2xldCBJPWcuaXNTdHJpbmcobyk/bihvKTpvO3JldHVybiBJLnByb3RvY29sPT09ci5wcm90b2NvbCYmSS5ob3N0PT09ci5ob3N0fX0oKTpmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiEwfX0oKTtmdW5jdGlvbiBYQShBKXtsZXQgZT0vXihbLStcd117MSwyNX0pKDo/XC9cL3w6KS8uZXhlYyhBKTtyZXR1cm4gZSYmZVsxXXx8IiJ9ZnVuY3Rpb24gTXIoQSxlKXtBPUF8fDEwO2xldCB0PW5ldyBBcnJheShBKSxyPW5ldyBBcnJheShBKSxuPTAsaT0wLG87cmV0dXJuIGU9ZSE9PXZvaWQgMD9lOjFlMyxmdW5jdGlvbihDKXtsZXQgbD1EYXRlLm5vdygpLHM9cltpXTtvfHwobz1sKSx0W25dPUMscltuXT1sO2xldCBhPWksRT0wO2Zvcig7YSE9PW47KUUrPXRbYSsrXSxhPWElQTtpZihuPShuKzEpJUEsbj09PWkmJihpPShpKzEpJUEpLGwtbzxlKXJldHVybjtsZXQgQj1zJiZsLXM7cmV0dXJuIEI/TWF0aC5yb3VuZChFKjFlMy9CKTp2b2lkIDB9fXZhciBWZT1NcjtmdW5jdGlvbiBaZShBLGUpe2xldCB0PTAscj1WZSg1MCwyNTApO3JldHVybiBuPT57bGV0IGk9bi5sb2FkZWQsbz1uLmxlbmd0aENvbXB1dGFibGU/bi50b3RhbDp2b2lkIDAsST1pLXQsQz1yKEkpLGw9aTw9bzt0PWk7bGV0IHM9e2xvYWRlZDppLHRvdGFsOm8scHJvZ3Jlc3M6bz9pL286dm9pZCAwLGJ5dGVzOkkscmF0ZTpDfHx2b2lkIDAsZXN0aW1hdGVkOkMmJm8mJmw/KG8taSkvQzp2b2lkIDAsZXZlbnQ6bn07c1tlPyJkb3dubG9hZCI6InVwbG9hZCJdPSEwLEEocyl9fXZhciBZcj10eXBlb2YgWE1MSHR0cFJlcXVlc3Q8InUiLFhlPVlyJiZmdW5jdGlvbihBKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24odCxyKXtsZXQgbj1BLmRhdGEsaT1TLmZyb20oQS5oZWFkZXJzKS5ub3JtYWxpemUoKSx7cmVzcG9uc2VUeXBlOm8sd2l0aFhTUkZUb2tlbjpJfT1BLEM7ZnVuY3Rpb24gbCgpe0EuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udW5zdWJzY3JpYmUoQyksQS5zaWduYWwmJkEuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixDKX1sZXQgcztpZihnLmlzRm9ybURhdGEobikpe2lmKEQuaGFzU3RhbmRhcmRCcm93c2VyRW52fHxELmhhc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudilpLnNldENvbnRlbnRUeXBlKCExKTtlbHNlIGlmKChzPWkuZ2V0Q29udGVudFR5cGUoKSkhPT0hMSl7bGV0W2MsLi4uUV09cz9zLnNwbGl0KCI7IikubWFwKGQ9PmQudHJpbSgpKS5maWx0ZXIoQm9vbGVhbik6W107aS5zZXRDb250ZW50VHlwZShbY3x8Im11bHRpcGFydC9mb3JtLWRhdGEiLC4uLlFdLmpvaW4oIjsgIikpfX1sZXQgYT1uZXcgWE1MSHR0cFJlcXVlc3Q7aWYoQS5hdXRoKXtsZXQgYz1BLmF1dGgudXNlcm5hbWV8fCIiLFE9QS5hdXRoLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChBLmF1dGgucGFzc3dvcmQpKToiIjtpLnNldCgiQXV0aG9yaXphdGlvbiIsIkJhc2ljICIrYnRvYShjKyI6IitRKSl9bGV0IEU9aUEoQS5iYXNlVVJMLEEudXJsKTthLm9wZW4oQS5tZXRob2QudG9VcHBlckNhc2UoKSxBQShFLEEucGFyYW1zLEEucGFyYW1zU2VyaWFsaXplciksITApLGEudGltZW91dD1BLnRpbWVvdXQ7ZnVuY3Rpb24gQigpe2lmKCFhKXJldHVybjtsZXQgYz1TLmZyb20oImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiBhJiZhLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKSxkPXtkYXRhOiFvfHxvPT09InRleHQifHxvPT09Impzb24iP2EucmVzcG9uc2VUZXh0OmEucmVzcG9uc2Usc3RhdHVzOmEuc3RhdHVzLHN0YXR1c1RleHQ6YS5zdGF0dXNUZXh0LGhlYWRlcnM6Yyxjb25maWc6QSxyZXF1ZXN0OmF9O3pBKGZ1bmN0aW9uKGspe3QoayksbCgpfSxmdW5jdGlvbihrKXtyKGspLGwoKX0sZCksYT1udWxsfWlmKCJvbmxvYWRlbmQiaW4gYT9hLm9ubG9hZGVuZD1COmEub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IWF8fGEucmVhZHlTdGF0ZSE9PTR8fGEuc3RhdHVzPT09MCYmIShhLnJlc3BvbnNlVVJMJiZhLnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChCKX0sYS5vbmFib3J0PWZ1bmN0aW9uKCl7YSYmKHIobmV3IHAoIlJlcXVlc3QgYWJvcnRlZCIscC5FQ09OTkFCT1JURUQsQSxhKSksYT1udWxsKX0sYS5vbmVycm9yPWZ1bmN0aW9uKCl7cihuZXcgcCgiTmV0d29yayBFcnJvciIscC5FUlJfTkVUV09SSyxBLGEpKSxhPW51bGx9LGEub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IFE9QS50aW1lb3V0PyJ0aW1lb3V0IG9mICIrQS50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLGQ9QS50cmFuc2l0aW9uYWx8fFFBO0EudGltZW91dEVycm9yTWVzc2FnZSYmKFE9QS50aW1lb3V0RXJyb3JNZXNzYWdlKSxyKG5ldyBwKFEsZC5jbGFyaWZ5VGltZW91dEVycm9yP3AuRVRJTUVET1VUOnAuRUNPTk5BQk9SVEVELEEsYSkpLGE9bnVsbH0sRC5oYXNTdGFuZGFyZEJyb3dzZXJFbnYmJihJJiZnLmlzRnVuY3Rpb24oSSkmJihJPUkoQSkpLEl8fEkhPT0hMSYmemUoRSkpKXtsZXQgYz1BLnhzcmZIZWFkZXJOYW1lJiZBLnhzcmZDb29raWVOYW1lJiZfZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO2MmJmkuc2V0KEEueHNyZkhlYWRlck5hbWUsYyl9bj09PXZvaWQgMCYmaS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBhJiZnLmZvckVhY2goaS50b0pTT04oKSxmdW5jdGlvbihRLGQpe2Euc2V0UmVxdWVzdEhlYWRlcihkLFEpfSksZy5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChhLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxvJiZvIT09Impzb24iJiYoYS5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmYS5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsWmUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZhLnVwbG9hZCYmYS51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihDPWM9PnthJiYocighY3x8Yy50eXBlP25ldyBQKG51bGwsQSxhKTpjKSxhLmFib3J0KCksYT1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUoQyksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP0MoKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsQykpKTtsZXQgdT1YQShFKTtpZih1JiZELnByb3RvY29scy5pbmRleE9mKHUpPT09LTEpe3IobmV3IHAoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrdSsiOiIscC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1hLnNlbmQobnx8bnVsbCl9KX07dmFyICRBPXtodHRwOkVBLHhocjpYZX07Zy5mb3JFYWNoKCRBLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyICRlPUE9PmAtICR7QX1gLHFyPUE9PmcuaXNGdW5jdGlvbihBKXx8QT09PW51bGx8fEE9PT0hMSxtQT17Z2V0QWRhcHRlcjpBPT57QT1nLmlzQXJyYXkoQSk/QTpbQV07bGV0e2xlbmd0aDplfT1BLHQscixuPXt9O2ZvcihsZXQgaT0wO2k8ZTtpKyspe3Q9QVtpXTtsZXQgbztpZihyPXQsIXFyKHQpJiYocj0kQVsobz1TdHJpbmcodCkpLnRvTG93ZXJDYXNlKCldLHI9PT12b2lkIDApKXRocm93IG5ldyBwKGBVbmtub3duIGFkYXB0ZXIgJyR7b30nYCk7aWYocilicmVhaztuW298fCIjIitpXT1yfWlmKCFyKXtsZXQgaT1PYmplY3QuZW50cmllcyhuKS5tYXAoKFtJLENdKT0+YGFkYXB0ZXIgJHtJfSBgKyhDPT09ITE/ImlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50IjoiaXMgbm90IGF2YWlsYWJsZSBpbiB0aGUgYnVpbGQiKSksbz1lP2kubGVuZ3RoPjE/YHNpbmNlIDoKYCtpLm1hcCgkZSkuam9pbihgCmApOiIgIiskZShpWzBdKToiYXMgbm8gYWRhcHRlciBzcGVjaWZpZWQiO3Rocm93IG5ldyBwKCJUaGVyZSBpcyBubyBzdWl0YWJsZSBhZGFwdGVyIHRvIGRpc3BhdGNoIHRoZSByZXF1ZXN0ICIrbywiRVJSX05PVF9TVVBQT1JUIil9cmV0dXJuIHJ9LGFkYXB0ZXJzOiRBfTtmdW5jdGlvbiBBZShBKXtpZihBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnRocm93SWZSZXF1ZXN0ZWQoKSxBLnNpZ25hbCYmQS5zaWduYWwuYWJvcnRlZCl0aHJvdyBuZXcgUChudWxsLEEpfWZ1bmN0aW9uIGhBKEEpe3JldHVybiBBZShBKSxBLmhlYWRlcnM9Uy5mcm9tKEEuaGVhZGVycyksQS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlcXVlc3QpLFsicG9zdCIsInB1dCIsInBhdGNoIl0uaW5kZXhPZihBLm1ldGhvZCkhPT0tMSYmQS5oZWFkZXJzLnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiLCExKSxtQS5nZXRBZGFwdGVyKEEuYWRhcHRlcnx8Vy5hZGFwdGVyKShBKS50aGVuKGZ1bmN0aW9uKHIpe3JldHVybiBBZShBKSxyLmRhdGE9dEEuY2FsbChBLEEudHJhbnNmb3JtUmVzcG9uc2Usciksci5oZWFkZXJzPVMuZnJvbShyLmhlYWRlcnMpLHJ9LGZ1bmN0aW9uKHIpe3JldHVybiByQShyKXx8KEFlKEEpLHImJnIucmVzcG9uc2UmJihyLnJlc3BvbnNlLmRhdGE9dEEuY2FsbChBLEEudHJhbnNmb3JtUmVzcG9uc2Usci5yZXNwb25zZSksci5yZXNwb25zZS5oZWFkZXJzPVMuZnJvbShyLnJlc3BvbnNlLmhlYWRlcnMpKSksUHJvbWlzZS5yZWplY3Qocil9KX12YXIgQXQ9QT0+QSBpbnN0YW5jZW9mIFM/QS50b0pTT04oKTpBO2Z1bmN0aW9uIEwoQSxlKXtlPWV8fHt9O2xldCB0PXt9O2Z1bmN0aW9uIHIobCxzLGEpe3JldHVybiBnLmlzUGxhaW5PYmplY3QobCkmJmcuaXNQbGFpbk9iamVjdChzKT9nLm1lcmdlLmNhbGwoe2Nhc2VsZXNzOmF9LGwscyk6Zy5pc1BsYWluT2JqZWN0KHMpP2cubWVyZ2Uoe30scyk6Zy5pc0FycmF5KHMpP3Muc2xpY2UoKTpzfWZ1bmN0aW9uIG4obCxzLGEpe2lmKGcuaXNVbmRlZmluZWQocykpe2lmKCFnLmlzVW5kZWZpbmVkKGwpKXJldHVybiByKHZvaWQgMCxsLGEpfWVsc2UgcmV0dXJuIHIobCxzLGEpfWZ1bmN0aW9uIGkobCxzKXtpZighZy5pc1VuZGVmaW5lZChzKSlyZXR1cm4gcih2b2lkIDAscyl9ZnVuY3Rpb24gbyhsLHMpe2lmKGcuaXNVbmRlZmluZWQocykpe2lmKCFnLmlzVW5kZWZpbmVkKGwpKXJldHVybiByKHZvaWQgMCxsKX1lbHNlIHJldHVybiByKHZvaWQgMCxzKX1mdW5jdGlvbiBJKGwscyxhKXtpZihhIGluIGUpcmV0dXJuIHIobCxzKTtpZihhIGluIEEpcmV0dXJuIHIodm9pZCAwLGwpfWxldCBDPXt1cmw6aSxtZXRob2Q6aSxkYXRhOmksYmFzZVVSTDpvLHRyYW5zZm9ybVJlcXVlc3Q6byx0cmFuc2Zvcm1SZXNwb25zZTpvLHBhcmFtc1NlcmlhbGl6ZXI6byx0aW1lb3V0Om8sdGltZW91dE1lc3NhZ2U6byx3aXRoQ3JlZGVudGlhbHM6byx3aXRoWFNSRlRva2VuOm8sYWRhcHRlcjpvLHJlc3BvbnNlVHlwZTpvLHhzcmZDb29raWVOYW1lOm8seHNyZkhlYWRlck5hbWU6byxvblVwbG9hZFByb2dyZXNzOm8sb25Eb3dubG9hZFByb2dyZXNzOm8sZGVjb21wcmVzczpvLG1heENvbnRlbnRMZW5ndGg6byxtYXhCb2R5TGVuZ3RoOm8sYmVmb3JlUmVkaXJlY3Q6byx0cmFuc3BvcnQ6byxodHRwQWdlbnQ6byxodHRwc0FnZW50Om8sY2FuY2VsVG9rZW46byxzb2NrZXRQYXRoOm8scmVzcG9uc2VFbmNvZGluZzpvLHZhbGlkYXRlU3RhdHVzOkksaGVhZGVyczoobCxzKT0+bihBdChsKSxBdChzKSwhMCl9O3JldHVybiBnLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihzKXtsZXQgYT1DW3NdfHxuLEU9YShBW3NdLGVbc10scyk7Zy5pc1VuZGVmaW5lZChFKSYmYSE9PUl8fCh0W3NdPUUpfSksdH12YXIgeUE9IjEuNi4yIjt2YXIgZWU9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57ZWVbQV09ZnVuY3Rpb24ocil7cmV0dXJuIHR5cGVvZiByPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIGV0PXt9O2VlLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQscil7ZnVuY3Rpb24gbihpLG8pe3JldHVybiJbQXhpb3MgdiIreUErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiAnIitpKyInIitvKyhyPyIuICIrcjoiIil9cmV0dXJuKGksbyxJKT0+e2lmKGU9PT0hMSl0aHJvdyBuZXcgcChuKG8sIiBoYXMgYmVlbiByZW1vdmVkIisodD8iIGluICIrdDoiIikpLHAuRVJSX0RFUFJFQ0FURUQpO3JldHVybiB0JiYhZXRbb10mJihldFtvXT0hMCxjb25zb2xlLndhcm4obihvLCIgaGFzIGJlZW4gZGVwcmVjYXRlZCBzaW5jZSB2Iit0KyIgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmVhciBmdXR1cmUiKSkpLGU/ZShpLG8sSSk6ITB9fTtmdW5jdGlvbiBLcihBLGUsdCl7aWYodHlwZW9mIEEhPSJvYmplY3QiKXRocm93IG5ldyBwKCJvcHRpb25zIG11c3QgYmUgYW4gb2JqZWN0IixwLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtsZXQgcj1PYmplY3Qua2V5cyhBKSxuPXIubGVuZ3RoO2Zvcig7bi0tID4wOyl7bGV0IGk9cltuXSxvPWVbaV07aWYobyl7bGV0IEk9QVtpXSxDPUk9PT12b2lkIDB8fG8oSSxpLEEpO2lmKEMhPT0hMCl0aHJvdyBuZXcgcCgib3B0aW9uICIraSsiIG11c3QgYmUgIitDLHAuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2NvbnRpbnVlfWlmKHQhPT0hMCl0aHJvdyBuZXcgcCgiVW5rbm93biBvcHRpb24gIitpLHAuRVJSX0JBRF9PUFRJT04pfX12YXIgd0E9e2Fzc2VydE9wdGlvbnM6S3IsdmFsaWRhdG9yczplZX07dmFyIEo9d0EudmFsaWRhdG9ycyxqPWNsYXNze2NvbnN0cnVjdG9yKGUpe3RoaXMuZGVmYXVsdHM9ZSx0aGlzLmludGVyY2VwdG9ycz17cmVxdWVzdDpuZXcgS0EscmVzcG9uc2U6bmV3IEtBfX1yZXF1ZXN0KGUsdCl7dHlwZW9mIGU9PSJzdHJpbmciPyh0PXR8fHt9LHQudXJsPWUpOnQ9ZXx8e30sdD1MKHRoaXMuZGVmYXVsdHMsdCk7bGV0e3RyYW5zaXRpb25hbDpyLHBhcmFtc1NlcmlhbGl6ZXI6bixoZWFkZXJzOml9PXQ7ciE9PXZvaWQgMCYmd0EuYXNzZXJ0T3B0aW9ucyhyLHtzaWxlbnRKU09OUGFyc2luZzpKLnRyYW5zaXRpb25hbChKLmJvb2xlYW4pLGZvcmNlZEpTT05QYXJzaW5nOkoudHJhbnNpdGlvbmFsKEouYm9vbGVhbiksY2xhcmlmeVRpbWVvdXRFcnJvcjpKLnRyYW5zaXRpb25hbChKLmJvb2xlYW4pfSwhMSksbiE9bnVsbCYmKGcuaXNGdW5jdGlvbihuKT90LnBhcmFtc1NlcmlhbGl6ZXI9e3NlcmlhbGl6ZTpufTp3QS5hc3NlcnRPcHRpb25zKG4se2VuY29kZTpKLmZ1bmN0aW9uLHNlcmlhbGl6ZTpKLmZ1bmN0aW9ufSwhMCkpLHQubWV0aG9kPSh0Lm1ldGhvZHx8dGhpcy5kZWZhdWx0cy5tZXRob2R8fCJnZXQiKS50b0xvd2VyQ2FzZSgpO2xldCBvPWkmJmcubWVyZ2UoaS5jb21tb24saVt0Lm1ldGhvZF0pO2kmJmcuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJwb3N0IiwicHV0IiwicGF0Y2giLCJjb21tb24iXSx1PT57ZGVsZXRlIGlbdV19KSx0LmhlYWRlcnM9Uy5jb25jYXQobyxpKTtsZXQgST1bXSxDPSEwO3RoaXMuaW50ZXJjZXB0b3JzLnJlcXVlc3QuZm9yRWFjaChmdW5jdGlvbihjKXt0eXBlb2YgYy5ydW5XaGVuPT0iZnVuY3Rpb24iJiZjLnJ1bldoZW4odCk9PT0hMXx8KEM9QyYmYy5zeW5jaHJvbm91cyxJLnVuc2hpZnQoYy5mdWxmaWxsZWQsYy5yZWplY3RlZCkpfSk7bGV0IGw9W107dGhpcy5pbnRlcmNlcHRvcnMucmVzcG9uc2UuZm9yRWFjaChmdW5jdGlvbihjKXtsLnB1c2goYy5mdWxmaWxsZWQsYy5yZWplY3RlZCl9KTtsZXQgcyxhPTAsRTtpZighQyl7bGV0IHU9W2hBLmJpbmQodGhpcyksdm9pZCAwXTtmb3IodS51bnNoaWZ0LmFwcGx5KHUsSSksdS5wdXNoLmFwcGx5KHUsbCksRT11Lmxlbmd0aCxzPVByb21pc2UucmVzb2x2ZSh0KTthPEU7KXM9cy50aGVuKHVbYSsrXSx1W2ErK10pO3JldHVybiBzfUU9SS5sZW5ndGg7bGV0IEI9dDtmb3IoYT0wO2E8RTspe2xldCB1PUlbYSsrXSxjPUlbYSsrXTt0cnl7Qj11KEIpfWNhdGNoKFEpe2MuY2FsbCh0aGlzLFEpO2JyZWFrfX10cnl7cz1oQS5jYWxsKHRoaXMsQil9Y2F0Y2godSl7cmV0dXJuIFByb21pc2UucmVqZWN0KHUpfWZvcihhPTAsRT1sLmxlbmd0aDthPEU7KXM9cy50aGVuKGxbYSsrXSxsW2ErK10pO3JldHVybiBzfWdldFVyaShlKXtlPUwodGhpcy5kZWZhdWx0cyxlKTtsZXQgdD1pQShlLmJhc2VVUkwsZS51cmwpO3JldHVybiBBQSh0LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplcil9fTtnLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKGUpe2oucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHQscil7cmV0dXJuIHRoaXMucmVxdWVzdChMKHJ8fHt9LHttZXRob2Q6ZSx1cmw6dCxkYXRhOihyfHx7fSkuZGF0YX0pKX19KTtnLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbihlKXtmdW5jdGlvbiB0KHIpe3JldHVybiBmdW5jdGlvbihpLG8sSSl7cmV0dXJuIHRoaXMucmVxdWVzdChMKEl8fHt9LHttZXRob2Q6ZSxoZWFkZXJzOnI/eyJDb250ZW50LVR5cGUiOiJtdWx0aXBhcnQvZm9ybS1kYXRhIn06e30sdXJsOmksZGF0YTpvfSkpfX1qLnByb3RvdHlwZVtlXT10KCksai5wcm90b3R5cGVbZSsiRm9ybSJdPXQoITApfSk7dmFyIG5BPWo7dmFyIHRlPWNsYXNzIEF7Y29uc3RydWN0b3IoZSl7aWYodHlwZW9mIGUhPSJmdW5jdGlvbiIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXhlY3V0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uLiIpO2xldCB0O3RoaXMucHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihpKXt0PWl9KTtsZXQgcj10aGlzO3RoaXMucHJvbWlzZS50aGVuKG49PntpZighci5fbGlzdGVuZXJzKXJldHVybjtsZXQgaT1yLl9saXN0ZW5lcnMubGVuZ3RoO2Zvcig7aS0tID4wOylyLl9saXN0ZW5lcnNbaV0obik7ci5fbGlzdGVuZXJzPW51bGx9KSx0aGlzLnByb21pc2UudGhlbj1uPT57bGV0IGksbz1uZXcgUHJvbWlzZShJPT57ci5zdWJzY3JpYmUoSSksaT1JfSkudGhlbihuKTtyZXR1cm4gby5jYW5jZWw9ZnVuY3Rpb24oKXtyLnVuc3Vic2NyaWJlKGkpfSxvfSxlKGZ1bmN0aW9uKGksbyxJKXtyLnJlYXNvbnx8KHIucmVhc29uPW5ldyBQKGksbyxJKSx0KHIucmVhc29uKSl9KX10aHJvd0lmUmVxdWVzdGVkKCl7aWYodGhpcy5yZWFzb24pdGhyb3cgdGhpcy5yZWFzb259c3Vic2NyaWJlKGUpe2lmKHRoaXMucmVhc29uKXtlKHRoaXMucmVhc29uKTtyZXR1cm59dGhpcy5fbGlzdGVuZXJzP3RoaXMuX2xpc3RlbmVycy5wdXNoKGUpOnRoaXMuX2xpc3RlbmVycz1bZV19dW5zdWJzY3JpYmUoZSl7aWYoIXRoaXMuX2xpc3RlbmVycylyZXR1cm47bGV0IHQ9dGhpcy5fbGlzdGVuZXJzLmluZGV4T2YoZSk7dCE9PS0xJiZ0aGlzLl9saXN0ZW5lcnMuc3BsaWNlKHQsMSl9c3RhdGljIHNvdXJjZSgpe2xldCBlO3JldHVybnt0b2tlbjpuZXcgQShmdW5jdGlvbihuKXtlPW59KSxjYW5jZWw6ZX19fSx0dD10ZTtmdW5jdGlvbiByZShBKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIEEuYXBwbHkobnVsbCx0KX19ZnVuY3Rpb24gaWUoQSl7cmV0dXJuIGcuaXNPYmplY3QoQSkmJkEuaXNBeGlvc0Vycm9yPT09ITB9dmFyIG5lPXtDb250aW51ZToxMDAsU3dpdGNoaW5nUHJvdG9jb2xzOjEwMSxQcm9jZXNzaW5nOjEwMixFYXJseUhpbnRzOjEwMyxPazoyMDAsQ3JlYXRlZDoyMDEsQWNjZXB0ZWQ6MjAyLE5vbkF1dGhvcml0YXRpdmVJbmZvcm1hdGlvbjoyMDMsTm9Db250ZW50OjIwNCxSZXNldENvbnRlbnQ6MjA1LFBhcnRpYWxDb250ZW50OjIwNixNdWx0aVN0YXR1czoyMDcsQWxyZWFkeVJlcG9ydGVkOjIwOCxJbVVzZWQ6MjI2LE11bHRpcGxlQ2hvaWNlczozMDAsTW92ZWRQZXJtYW5lbnRseTozMDEsRm91bmQ6MzAyLFNlZU90aGVyOjMwMyxOb3RNb2RpZmllZDozMDQsVXNlUHJveHk6MzA1LFVudXNlZDozMDYsVGVtcG9yYXJ5UmVkaXJlY3Q6MzA3LFBlcm1hbmVudFJlZGlyZWN0OjMwOCxCYWRSZXF1ZXN0OjQwMCxVbmF1dGhvcml6ZWQ6NDAxLFBheW1lbnRSZXF1aXJlZDo0MDIsRm9yYmlkZGVuOjQwMyxOb3RGb3VuZDo0MDQsTWV0aG9kTm90QWxsb3dlZDo0MDUsTm90QWNjZXB0YWJsZTo0MDYsUHJveHlBdXRoZW50aWNhdGlvblJlcXVpcmVkOjQwNyxSZXF1ZXN0VGltZW91dDo0MDgsQ29uZmxpY3Q6NDA5LEdvbmU6NDEwLExlbmd0aFJlcXVpcmVkOjQxMSxQcmVjb25kaXRpb25GYWlsZWQ6NDEyLFBheWxvYWRUb29MYXJnZTo0MTMsVXJpVG9vTG9uZzo0MTQsVW5zdXBwb3J0ZWRNZWRpYVR5cGU6NDE1LFJhbmdlTm90U2F0aXNmaWFibGU6NDE2LEV4cGVjdGF0aW9uRmFpbGVkOjQxNyxJbUFUZWFwb3Q6NDE4LE1pc2RpcmVjdGVkUmVxdWVzdDo0MjEsVW5wcm9jZXNzYWJsZUVudGl0eTo0MjIsTG9ja2VkOjQyMyxGYWlsZWREZXBlbmRlbmN5OjQyNCxUb29FYXJseTo0MjUsVXBncmFkZVJlcXVpcmVkOjQyNixQcmVjb25kaXRpb25SZXF1aXJlZDo0MjgsVG9vTWFueVJlcXVlc3RzOjQyOSxSZXF1ZXN0SGVhZGVyRmllbGRzVG9vTGFyZ2U6NDMxLFVuYXZhaWxhYmxlRm9yTGVnYWxSZWFzb25zOjQ1MSxJbnRlcm5hbFNlcnZlckVycm9yOjUwMCxOb3RJbXBsZW1lbnRlZDo1MDEsQmFkR2F0ZXdheTo1MDIsU2VydmljZVVuYXZhaWxhYmxlOjUwMyxHYXRld2F5VGltZW91dDo1MDQsSHR0cFZlcnNpb25Ob3RTdXBwb3J0ZWQ6NTA1LFZhcmlhbnRBbHNvTmVnb3RpYXRlczo1MDYsSW5zdWZmaWNpZW50U3RvcmFnZTo1MDcsTG9vcERldGVjdGVkOjUwOCxOb3RFeHRlbmRlZDo1MTAsTmV0d29ya0F1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NTExfTtPYmplY3QuZW50cmllcyhuZSkuZm9yRWFjaCgoW0EsZV0pPT57bmVbZV09QX0pO3ZhciBydD1uZTtmdW5jdGlvbiBpdChBKXtsZXQgZT1uZXcgbkEoQSksdD1aKG5BLnByb3RvdHlwZS5yZXF1ZXN0LGUpO3JldHVybiBnLmV4dGVuZCh0LG5BLnByb3RvdHlwZSxlLHthbGxPd25LZXlzOiEwfSksZy5leHRlbmQodCxlLG51bGwse2FsbE93bktleXM6ITB9KSx0LmNyZWF0ZT1mdW5jdGlvbihuKXtyZXR1cm4gaXQoTChBLG4pKX0sdH12YXIgbT1pdChXKTttLkF4aW9zPW5BO20uQ2FuY2VsZWRFcnJvcj1QO20uQ2FuY2VsVG9rZW49dHQ7bS5pc0NhbmNlbD1yQTttLlZFUlNJT049eUE7bS50b0Zvcm1EYXRhPU87bS5BeGlvc0Vycm9yPXA7bS5DYW5jZWw9bS5DYW5jZWxlZEVycm9yO20uYWxsPWZ1bmN0aW9uKGUpe3JldHVybiBQcm9taXNlLmFsbChlKX07bS5zcHJlYWQ9cmU7bS5pc0F4aW9zRXJyb3I9aWU7bS5tZXJnZUNvbmZpZz1MO20uQXhpb3NIZWFkZXJzPVM7bS5mb3JtVG9KU09OPUE9PnBBKGcuaXNIVE1MRm9ybShBKT9uZXcgRm9ybURhdGEoQSk6QSk7bS5nZXRBZGFwdGVyPW1BLmdldEFkYXB0ZXI7bS5IdHRwU3RhdHVzQ29kZT1ydDttLmRlZmF1bHQ9bTt2YXIgXz1tO3ZhcntBeGlvczpMYSxBeGlvc0Vycm9yOnhhLENhbmNlbGVkRXJyb3I6T2EsaXNDYW5jZWw6UGEsQ2FuY2VsVG9rZW46SmEsVkVSU0lPTjpIYSxhbGw6TWEsQ2FuY2VsOllhLGlzQXhpb3NFcnJvcjpxYSxzcHJlYWQ6S2EsdG9Gb3JtRGF0YTpXYSxBeGlvc0hlYWRlcnM6dmEsSHR0cFN0YXR1c0NvZGU6amEsZm9ybVRvSlNPTjpfYSxnZXRBZGFwdGVyOnphLG1lcmdlQ29uZmlnOlZhfT1fO2FzeW5jIGZ1bmN0aW9uIFdyKEEsZSl7bGV0IHQ9QSxyPW51bGw7aWYodD09PW51bGwpcj1uZXcgV29ya2VyKG5ldyBVUkwoIi4vd2ViLXdvcmtlcnMvaXRrLXdhc20tcGlwZWxpbmUud29ya2VyLmpzIixpbXBvcnQubWV0YS51cmwpLHt0eXBlOiJtb2R1bGUifSk7ZWxzZSBpZih0LnN0YXJ0c1dpdGgoImh0dHAiKSl7bGV0IG49YXdhaXQgXy5nZXQodCx7cmVzcG9uc2VUeXBlOiJibG9iIixwYXJhbXM6ZX0pLGk9VVJMLmNyZWF0ZU9iamVjdFVSTChuLmRhdGEpO3I9bmV3IFdvcmtlcihpLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSByPW5ldyBXb3JrZXIodCx7dHlwZToibW9kdWxlIn0pO3JldHVybiByfXZhciBvQT1XcjtmdW5jdGlvbiBudChBKXtsZXQgZT1PQShBKSx0PUE7cmV0dXJuIHQudGVybWluYXRlZD0hMSx0LndvcmtlclByb3h5PWUsdC5vcmlnaW5hbFRlcm1pbmF0ZT10LnRlcm1pbmF0ZSx0LnRlcm1pbmF0ZT0oKT0+e3QudGVybWluYXRlZD0hMCx0LndvcmtlclByb3h5W3hBXSgpLHQub3JpZ2luYWxUZXJtaW5hdGUoKX0se3dvcmtlclByb3h5OmUsd29ya2VyOnR9fWFzeW5jIGZ1bmN0aW9uIHZyKEEsZSx0KXtsZXQgcjtpZihBIT1udWxsKXtsZXQgaT1BO3JldHVybiBpLndvcmtlclByb3h5IT09dm9pZCAwPyhyPWkud29ya2VyUHJveHkse3dvcmtlclByb3h5OnIsd29ya2VyOml9KTpudChBKX1sZXQgbj1hd2FpdCBvQShlLHQpO3JldHVybiBudChuKX12YXIgb3Q9dnI7YXN5bmMgZnVuY3Rpb24ganIoQSxlLHQpe2xldCByPSJ1bmtub3duIjt0eXBlb2YgQSE9InN0cmluZyI/cj1BLmhyZWY6QS5zdGFydHNXaXRoKCJodHRwIik/cj1BOnI9dHlwZW9mIGU8InUiP2Ake2V9LyR7QX1gOkEsci5lbmRzV2l0aCgiLmpzIikmJihyPXIuc3Vic3RyaW5nKDAsci5sZW5ndGgtMykpLHIuZW5kc1dpdGgoIi53YXNtIikmJihyPXIuc3Vic3RyaW5nKDAsci5sZW5ndGgtNSkpO2xldCBuPWAke3J9Lndhc21gLG89KGF3YWl0IF8uZ2V0KG4se3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIiLHBhcmFtczp0fSkpLmRhdGE7cmV0dXJuKGF3YWl0IGltcG9ydChgJHtyfS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5Om99KX12YXIgYXQ9anI7dmFyIHN0PWFzeW5jKCk9PldlYkFzc2VtYmx5LnZhbGlkYXRlKG5ldyBVaW50OEFycmF5KFswLDk3LDExNSwxMDksMSwwLDAsMCwxLDUsMSw5NiwwLDEsMTIzLDMsMiwxLDAsMTAsMTAsMSw4LDAsNjUsMCwyNTMsMTUsMjUzLDk4LDExXSkpO3ZhciBsdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixJdD1uZXcgVGV4dEVuY29kZXIsZ3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIF9yKEEsZSl7bGV0IHQ9e2ZsYWdzOiJyIixlbmNvZGluZzoiYmluYXJ5In0scj1BLmZzX29wZW4oZSx0LmZsYWdzKSxpPUEuZnNfc3RhdChlKS5zaXplLG89bnVsbDtsdD9vPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcihpKTpvPW5ldyBBcnJheUJ1ZmZlcihpKTtsZXQgST1uZXcgVWludDhBcnJheShvKTtyZXR1cm4gQS5mc19yZWFkKHIsSSwwLGksMCksQS5mc19jbG9zZShyKSxJfWZ1bmN0aW9uIEJ0KEEsZSx0KXtsZXQgcj1udWxsO2x0P3I9bmV3IFNoYXJlZEFycmF5QnVmZmVyKHQpOnI9bmV3IEFycmF5QnVmZmVyKHQpO2xldCBuPW5ldyBVaW50OEFycmF5KHIpLGk9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLGUsdCk7cmV0dXJuIG4uc2V0KGkpLG59ZnVuY3Rpb24geShBLGUsdCxyKXtsZXQgbj0wO3JldHVybiBlIT09bnVsbCYmKG49QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfYXJyYXlfYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxyLGUuYnVmZmVyLmJ5dGVMZW5ndGhdKSxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkoZS5idWZmZXIpLG4pKSxufWZ1bmN0aW9uIHooQSxlLHQpe2xldCByPUpTT04uc3RyaW5naWZ5KGUpLG49QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfanNvbl9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LHIubGVuZ3RoXSk7QS53cml0ZUFzY2lpVG9NZW1vcnkocixuLCExKX1mdW5jdGlvbiBVKEEsZSx0LHIpe2xldCBuPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGUsdF0pLGk9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksbz1CdChBLG4saSk7cmV0dXJuIHgocixvLmJ1ZmZlcil9ZnVuY3Rpb24gb2UoQSxlKXtsZXQgdD1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfanNvbl9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciJdLFswLGVdKSxyPUEuQXNjaWlUb1N0cmluZyh0KTtyZXR1cm4gSlNPTi5wYXJzZShyKX1mdW5jdGlvbiB6cihBLGUsdCxyKXtyIT1udWxsJiZyLmxlbmd0aD4wJiZyLmZvckVhY2goZnVuY3Rpb24obCxzKXtzd2l0Y2gobC50eXBlKXtjYXNlIGYuVGV4dFN0cmVhbTp7bGV0IGE9SXQuZW5jb2RlKGwuZGF0YS5kYXRhKSxFPXkoQSxhLHMsMCksQj17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWB9O3ooQSxCLHMpO2JyZWFrfWNhc2UgZi5Kc29uQ29tcGF0aWJsZTp7bGV0IGE9SXQuZW5jb2RlKEpTT04uc3RyaW5naWZ5KGwuZGF0YSkpLEU9eShBLGEscywwKSxCPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YH07eihBLEIscyk7YnJlYWt9Y2FzZSBmLkJpbmFyeVN0cmVhbTp7bGV0IGE9bC5kYXRhLmRhdGEsRT15KEEsYSxzLDApLEI9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7RX1gfTt6KEEsQixzKTticmVha31jYXNlIGYuVGV4dEZpbGU6e0EuZnNfd3JpdGVGaWxlKGwuZGF0YS5wYXRoLGwuZGF0YS5kYXRhKTticmVha31jYXNlIGYuQmluYXJ5RmlsZTp7QS5mc193cml0ZUZpbGUobC5kYXRhLnBhdGgsbC5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgZi5JbWFnZTp7bGV0IGE9bC5kYXRhLEU9eShBLGEuZGF0YSxzLDApLEI9eShBLGEuZGlyZWN0aW9uLHMsMSksdT10eXBlb2YgYS5tZXRhZGF0YT8uZW50cmllczwidSI/SlNPTi5zdHJpbmdpZnkoQXJyYXkuZnJvbShhLm1ldGFkYXRhLmVudHJpZXMoKSkpOiJbXSIsYz17aW1hZ2VUeXBlOmEuaW1hZ2VUeXBlLG5hbWU6YS5uYW1lLG9yaWdpbjphLm9yaWdpbixzcGFjaW5nOmEuc3BhY2luZyxkaXJlY3Rpb246YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtCfWAsc2l6ZTphLnNpemUsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YCxtZXRhZGF0YTp1fTt6KEEsYyxzKTticmVha31jYXNlIGYuTWVzaDp7bGV0IGE9bC5kYXRhLEU9eShBLGEucG9pbnRzLHMsMCksQj15KEEsYS5jZWxscyxzLDEpLHU9eShBLGEucG9pbnREYXRhLHMsMiksYz15KEEsYS5jZWxsRGF0YSxzLDMpLFE9e21lc2hUeXBlOmEubWVzaFR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWAsbnVtYmVyT2ZDZWxsczphLm51bWJlck9mQ2VsbHMsY2VsbHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtCfWAsY2VsbEJ1ZmZlclNpemU6YS5jZWxsQnVmZmVyU2l6ZSxudW1iZXJPZlBvaW50UGl4ZWxzOmEubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt1fWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gfTt6KEEsUSxzKTticmVha31jYXNlIGYuUG9seURhdGE6e2xldCBhPWwuZGF0YSxFPXkoQSxhLnBvaW50cyxzLDApLEI9eShBLGEudmVydGljZXMscywxKSx1PXkoQSxhLmxpbmVzLHMsMiksYz15KEEsYS5wb2x5Z29ucyxzLDMpLFE9eShBLGEudHJpYW5nbGVTdHJpcHMscyw0KSxkPXkoQSxhLnBvaW50RGF0YSxzLDUpLGI9eShBLGEucG9pbnREYXRhLHMsNiksaz17cG9seURhdGFUeXBlOmEucG9seURhdGFUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7RX1gLHZlcnRpY2VzQnVmZmVyU2l6ZTphLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0J9YCxsaW5lc0J1ZmZlclNpemU6YS5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt1fWAscG9seWdvbnNCdWZmZXJTaXplOmEucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Y31gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTphLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke1F9YCxudW1iZXJPZlBvaW50UGl4ZWxzOmEubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtkfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Yn1gfTt6KEEsayxzKTticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgbj1BLnN0YWNrU2F2ZSgpLGk9MDt0cnl7aT1BLmNhbGxNYWluKGUuc2xpY2UoKSl9Y2F0Y2gobCl7dGhyb3cgdHlwZW9mIGw9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UobCkpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksbH1maW5hbGx5e0Euc3RhY2tSZXN0b3JlKG4pfWxldCBvPUEuZ2V0TW9kdWxlU3Rkb3V0KCksST1BLmdldE1vZHVsZVN0ZGVycigpLEM9W107cmV0dXJuIHQhPW51bGwmJnQubGVuZ3RoPjAmJmk9PT0wJiZ0LmZvckVhY2goZnVuY3Rpb24obCxzKXtsZXQgYT1udWxsO3N3aXRjaChsLnR5cGUpe2Nhc2UgZi5UZXh0U3RyZWFtOntsZXQgQj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxzLDBdKSx1PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHMsMF0pLGM9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEIsdSk7YT17ZGF0YTpndC5kZWNvZGUoYyl9O2JyZWFrfWNhc2UgZi5Kc29uQ29tcGF0aWJsZTp7bGV0IEI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAscywwXSksdT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxzLDBdKSxjPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixCLHUpO2E9SlNPTi5wYXJzZShndC5kZWNvZGUoYykpO2JyZWFrfWNhc2UgZi5CaW5hcnlTdHJlYW06e2xldCBCPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHMsMF0pLHU9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAscywwXSk7YT17ZGF0YTpCdChBLEIsdSl9O2JyZWFrfWNhc2UgZi5UZXh0RmlsZTp7YT17cGF0aDpsLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUobC5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIGYuQmluYXJ5RmlsZTp7YT17cGF0aDpsLmRhdGEucGF0aCxkYXRhOl9yKEEsbC5kYXRhLnBhdGgpfTticmVha31jYXNlIGYuSW1hZ2U6e2xldCBCPW9lKEEscyk7Qi5kYXRhPVUoQSxzLDAsQi5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQi5kaXJlY3Rpb249VShBLHMsMSxNLkZsb2F0NjQpLEIubWV0YWRhdGE9bmV3IE1hcChCLm1ldGFkYXRhKSxhPUI7YnJlYWt9Y2FzZSBmLk1lc2g6e2xldCBCPW9lKEEscyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVUoQSxzLDAsQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkIucG9pbnRzPXgoQi5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mQ2VsbHM+MD9CLmNlbGxzPVUoQSxzLDEsQi5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qi5jZWxscz14KEIubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxCLm51bWJlck9mUG9pbnRQaXhlbHM+MD9CLnBvaW50RGF0YT1VKEEscywyLEIubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkIucG9pbnREYXRhPXgoQi5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEIubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qi5jZWxsRGF0YT1VKEEscywzLEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5jZWxsRGF0YT14KEIubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGE9QjticmVha31jYXNlIGYuUG9seURhdGE6e2xldCBCPW9lKEEscyk7Qi5udW1iZXJPZlBvaW50cz4wP0IucG9pbnRzPVUoQSxzLDAsTS5GbG9hdDMyKTpCLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LEIudmVydGljZXNCdWZmZXJTaXplPjA/Qi52ZXJ0aWNlcz1VKEEscywxLGguVUludDMyKTpCLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxCLmxpbmVzQnVmZmVyU2l6ZT4wP0IubGluZXM9VShBLHMsMixoLlVJbnQzMik6Qi5saW5lcz1uZXcgVWludDMyQXJyYXksQi5wb2x5Z29uc0J1ZmZlclNpemU+MD9CLnBvbHlnb25zPVUoQSxzLDMsaC5VSW50MzIpOkIucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LEIudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/Qi50cmlhbmdsZVN0cmlwcz1VKEEscyw0LGguVUludDMyKTpCLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxCLm51bWJlck9mUG9pbnRQaXhlbHM+MD9CLnBvaW50RGF0YT1VKEEscyw1LEIucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpCLnBvaW50RGF0YT14KEIucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQi5udW1iZXJPZkNlbGxQaXhlbHM+MD9CLmNlbGxEYXRhPVUoQSxzLDYsQi5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qi5jZWxsRGF0YT14KEIucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxhPUI7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgRT17dHlwZTpsLnR5cGUsZGF0YTphfTtDLnB1c2goRSl9KSx7cmV0dXJuVmFsdWU6aSxzdGRvdXQ6byxzdGRlcnI6SSxvdXRwdXRzOkN9fXZhciBDdD16cjt2YXIgVnI9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIFpyKEEsZSl7aWYoQT09bnVsbClyZXR1cm5bXTtsZXQgdD1bXTtmb3IobGV0IHI9MDtyPEEubGVuZ3RoO3IrKyl7bGV0IG49WHIoQVtyXSxlKTtuIT09bnVsbCYmdC5wdXNoKG4pfXJldHVybiB0fWZ1bmN0aW9uIFhyKEEsZSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgdD1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD90PUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKHQ9QSksVnImJnQgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmU/dDp0LnNsaWNlKDApfXZhciBjdD1acjtmdW5jdGlvbiAkcihBKXtyZXR1cm5bQS5kYXRhLEEuZGlyZWN0aW9uXX12YXIgdXQ9JHI7ZnVuY3Rpb24gQWkoQSl7cmV0dXJuW0EucG9pbnRzLEEucG9pbnREYXRhLEEuY2VsbHMsQS5jZWxsRGF0YV19dmFyIEV0PUFpO2Z1bmN0aW9uIGVpKEEpe3JldHVybltBLnBvaW50cyxBLnZlcnRpY2VzLEEubGluZXMsQS5wb2x5Z29ucyxBLnRyaWFuZ2xlU3RyaXBzLEEucG9pbnREYXRhLEEuY2VsbERhdGFdfXZhciBmdD1laTt2YXIgdGk7ZnVuY3Rpb24gREEoKXtyZXR1cm4gdGl9dmFyIHJpO2Z1bmN0aW9uIFF0KCl7cmV0dXJuIHJpfXZhciBpaTtmdW5jdGlvbiBTQSgpe3JldHVybiBpaX12YXIgYWU9bmV3IE1hcDtmdW5jdGlvbiBuaSgpe2xldCBBPVNBKCk7cmV0dXJuIHR5cGVvZiBBPiJ1IiYmKEE9bnVsbCksQX1mdW5jdGlvbiBwdCgpe2xldCBBPURBKCk7cmV0dXJuIHR5cGVvZiBBPiJ1IiYmKEE9bmV3IFVSTCgiL3BpcGVsaW5lcyIsZG9jdW1lbnQubG9jYXRpb24ub3JpZ2luKS5ocmVmKSxBfWZ1bmN0aW9uIEZBKCl7bGV0IEE9UXQoKTtyZXR1cm4gdHlwZW9mIEE+InUiJiYoQT17fSksQX1hc3luYyBmdW5jdGlvbiBvaShBLGUsdCl7bGV0IHI9QSxuPUE7aWYodHlwZW9mIEEhPSJzdHJpbmciJiYocj1uZXcgVVJMKEEuaHJlZiksbj1yLmhyZWYpLGFlLmhhcyhuKSlyZXR1cm4gYWUuZ2V0KG4pO3tsZXQgaT1hd2FpdCBhdChBLGU/LnRvU3RyaW5nKCk/P3B0KCksdD8/RkEoKSk7cmV0dXJuIGFlLnNldChuLGkpLGl9fWFzeW5jIGZ1bmN0aW9uIGFpKEEsZSx0LHIsbil7aWYoIWF3YWl0IHN0KCkpe2xldCBRPSJXZWJBc3NlbWJseSBTSU1EIHN1cHBvcnQgaXMgcmVxdWlyZWQgLS0gcGxlYXNlIHVwZGF0ZSB5b3VyIGJyb3dzZXIuIjt0aHJvdyBhbGVydChRKSxuZXcgRXJyb3IoUSl9bGV0IGk9bj8ud2ViV29ya2VyPz9udWxsO2lmKGk9PT0hMSl7bGV0IFE9YXdhaXQgb2koQS50b1N0cmluZygpLG4/LnBpcGVsaW5lQmFzZVVybCxuPy5waXBlbGluZVF1ZXJ5UGFyYW1zPz9GQSgpKTtyZXR1cm4gQ3QoUSxlLHQscil9bGV0IG89aSxJPW4/LnBpcGVsaW5lV29ya2VyVXJsPz9uaSgpLEM9dHlwZW9mIEkhPSJzdHJpbmciJiZ0eXBlb2YgST8uaHJlZjwidSI/SS5ocmVmOkkse3dvcmtlclByb3h5Omwsd29ya2VyOnN9PWF3YWl0IG90KG8sQyxuPy5waXBlbGluZVF1ZXJ5UGFyYW1zPz9GQSgpKTtvPXM7bGV0IGE9W107ciE9bnVsbCYmci5sZW5ndGg+MCYmci5mb3JFYWNoKGZ1bmN0aW9uKFEpe2lmKFEudHlwZT09PWYuQmluYXJ5U3RyZWFtKXtsZXQgZD1RLmRhdGEuZGF0YTthLnB1c2goZCl9ZWxzZSBpZihRLnR5cGU9PT1mLkJpbmFyeUZpbGUpe2xldCBkPVEuZGF0YS5kYXRhO2EucHVzaChkKX1lbHNlIGlmKFEudHlwZT09PWYuSW1hZ2Upe2xldCBkPVEuZGF0YTtkLmRhdGEhPT1udWxsJiZhLnB1c2goLi4udXQoZCkpfWVsc2UgaWYoUS50eXBlPT09Zi5NZXNoKXtsZXQgZD1RLmRhdGE7YS5wdXNoKC4uLkV0KGQpKX1lbHNlIGlmKFEudHlwZT09PWYuUG9seURhdGEpe2xldCBkPVEuZGF0YTthLnB1c2goLi4uZnQoZCkpfX0pO2xldCBFPW4/LnBpcGVsaW5lQmFzZVVybD8/cHQoKSxCPXR5cGVvZiBFIT0ic3RyaW5nIiYmdHlwZW9mIEU/LmhyZWY8InUiP0UuaHJlZjpFLHU9ciE9bnVsbD9QQShyLGN0KGEsbj8ubm9Db3B5KSk6bnVsbCxjPWF3YWl0IGwucnVuUGlwZWxpbmUoQS50b1N0cmluZygpLEIsZSx0LHUsbj8ucGlwZWxpbmVRdWVyeVBhcmFtcz8/RkEoKSk7cmV0dXJue3JldHVyblZhbHVlOmMucmV0dXJuVmFsdWUsc3Rkb3V0OmMuc3Rkb3V0LHN0ZGVycjpjLnN0ZGVycixvdXRwdXRzOmMub3V0cHV0cyx3ZWJXb3JrZXI6b319dmFyIEY9YWk7dmFyIHNpPW51bGw7ZnVuY3Rpb24gZHQoKXtyZXR1cm4gc2l9dmFyIHNlLElpPWBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL0BpdGstd2FzbS9kaWNvbUAke2tBfS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gSHMoQSl7c2U9QX1mdW5jdGlvbiBSKCl7aWYodHlwZW9mIHNlPCJ1IilyZXR1cm4gc2U7bGV0IEE9REEoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6SWl9dmFyIEllLGdpPW51bGw7ZnVuY3Rpb24gbXQoQSl7SWU9QX1mdW5jdGlvbiB3KCl7aWYodHlwZW9mIEllPCJ1IilyZXR1cm4gSWU7bGV0IEE9U0EoKTtyZXR1cm4gdHlwZW9mIEE8InUiP0E6Z2l9dmFyIFY9bnVsbDthc3luYyBmdW5jdGlvbiBodCgpe2xldCBBPXcoKSxlPXR5cGVvZiBBIT0ic3RyaW5nIiYmdHlwZW9mIEE/LmhyZWY8InUiP0EuaHJlZjpBO1Y9YXdhaXQgb0EoZSl9ZnVuY3Rpb24ganMoQSl7Vj1BfWFzeW5jIGZ1bmN0aW9uIFQoKXtpZihWIT09bnVsbClyZXR1cm4gVi50ZXJtaW5hdGVkJiZhd2FpdCBodCgpLFY7bGV0IEE9ZHQoKTtyZXR1cm4gQSE9PW51bGw/QTooYXdhaXQgaHQoKSxWKX1hc3luYyBmdW5jdGlvbiBsaShBLGUsdD17fSl7bGV0IHI9W3t0eXBlOmYuSnNvbkNvbXBhdGlibGV9LHt0eXBlOmYuSW1hZ2V9XSxuPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBrPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTtuPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KGspfX1sZXQgaT1lO2lmKGUgaW5zdGFuY2VvZiBGaWxlKXtsZXQgaz1hd2FpdCBlLmFycmF5QnVmZmVyKCk7aT17cGF0aDplLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShrKX19bGV0IG89W3t0eXBlOmYuQmluYXJ5RmlsZSxkYXRhOm59LHt0eXBlOmYuQmluYXJ5RmlsZSxkYXRhOml9XSxJPVtdLEM9bi5wYXRoO0kucHVzaChDKTtsZXQgbD1pLnBhdGg7SS5wdXNoKGwpO2xldCBzPSIwIjtJLnB1c2gocyk7bGV0IGE9IjEiO0kucHVzaChhKSxJLnB1c2goIi0tbWVtb3J5LWlvIiksdC5jb2xvck91dHB1dCYmdC5jb2xvck91dHB1dCYmSS5wdXNoKCItLWNvbG9yLW91dHB1dCIpLHQuY29uZmlnRmlsZSYmSS5wdXNoKCItLWNvbmZpZy1maWxlIix0LmNvbmZpZ0ZpbGUudG9TdHJpbmcoKSksdC5mcmFtZSYmSS5wdXNoKCItLWZyYW1lIix0LmZyYW1lLnRvU3RyaW5nKCkpLHQubm9QcmVzZW50YXRpb25TdGF0ZU91dHB1dCYmdC5ub1ByZXNlbnRhdGlvblN0YXRlT3V0cHV0JiZJLnB1c2goIi0tbm8tcHJlc2VudGF0aW9uLXN0YXRlLW91dHB1dCIpLHQubm9CaXRtYXBPdXRwdXQmJnQubm9CaXRtYXBPdXRwdXQmJkkucHVzaCgiLS1uby1iaXRtYXAtb3V0cHV0Iik7bGV0IEU9ImFwcGx5LXByZXNlbnRhdGlvbi1zdGF0ZS10by1pbWFnZSIsQj10Py53ZWJXb3JrZXI7Qj09PXZvaWQgMCYmKEI9YXdhaXQgVCgpKTtsZXR7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6YyxzdGRlcnI6USxvdXRwdXRzOmR9PWF3YWl0IEYoRSxJLHIsbyx7cGlwZWxpbmVCYXNlVXJsOlIoKSxwaXBlbGluZVdvcmtlclVybDp3KCksd2ViV29ya2VyOkIsbm9Db3B5OnQ/Lm5vQ29weX0pO2lmKGMhPT0wJiZRIT09IiIpdGhyb3cgbmV3IEVycm9yKFEpO3JldHVybnt3ZWJXb3JrZXI6dSxwcmVzZW50YXRpb25TdGF0ZU91dFN0cmVhbTpkWzBdPy5kYXRhLG91dHB1dEltYWdlOmRbMV0/LmRhdGF9fXZhciBCaT1saTthc3luYyBmdW5jdGlvbiBDaShBLGU9e30pe2xldCB0PVt7dHlwZTpmLkJpbmFyeVN0cmVhbX1dLHI9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IGM9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO3I9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoYyl9fWxldCBuPVt7dHlwZTpmLkJpbmFyeUZpbGUsZGF0YTpyfV0saT1bXSxvPXIucGF0aDtpLnB1c2gobyk7bGV0IEk9IjAiO2kucHVzaChJKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksZS5yZWFkRmlsZU9ubHkmJmUucmVhZEZpbGVPbmx5JiZpLnB1c2goIi0tcmVhZC1maWxlLW9ubHkiKSxlLnJlYWREYXRhc2V0JiZlLnJlYWREYXRhc2V0JiZpLnB1c2goIi0tcmVhZC1kYXRhc2V0IiksZS5yZWFkWGZlckF1dG8mJmUucmVhZFhmZXJBdXRvJiZpLnB1c2goIi0tcmVhZC14ZmVyLWF1dG8iKSxlLnJlYWRYZmVyRGV0ZWN0JiZlLnJlYWRYZmVyRGV0ZWN0JiZpLnB1c2goIi0tcmVhZC14ZmVyLWRldGVjdCIpLGUucmVhZFhmZXJMaXR0bGUmJmUucmVhZFhmZXJMaXR0bGUmJmkucHVzaCgiLS1yZWFkLXhmZXItbGl0dGxlIiksZS5yZWFkWGZlckJpZyYmZS5yZWFkWGZlckJpZyYmaS5wdXNoKCItLXJlYWQteGZlci1iaWciKSxlLnJlYWRYZmVySW1wbGljaXQmJmUucmVhZFhmZXJJbXBsaWNpdCYmaS5wdXNoKCItLXJlYWQteGZlci1pbXBsaWNpdCIpLGUuYWNjZXB0T2RkTGVuZ3RoJiZlLmFjY2VwdE9kZExlbmd0aCYmaS5wdXNoKCItLWFjY2VwdC1vZGQtbGVuZ3RoIiksZS5hc3N1bWVFdmVuTGVuZ3RoJiZlLmFzc3VtZUV2ZW5MZW5ndGgmJmkucHVzaCgiLS1hc3N1bWUtZXZlbi1sZW5ndGgiKSxlLmVuYWJsZUNwMjQ2JiZlLmVuYWJsZUNwMjQ2JiZpLnB1c2goIi0tZW5hYmxlLWNwMjQ2IiksZS5kaXNhYmxlQ3AyNDYmJmUuZGlzYWJsZUNwMjQ2JiZpLnB1c2goIi0tZGlzYWJsZS1jcDI0NiIpLGUucmV0YWluVW4mJmUucmV0YWluVW4mJmkucHVzaCgiLS1yZXRhaW4tdW4iKSxlLmNvbnZlcnRVbiYmZS5jb252ZXJ0VW4mJmkucHVzaCgiLS1jb252ZXJ0LXVuIiksZS5lbmFibGVDb3JyZWN0aW9uJiZlLmVuYWJsZUNvcnJlY3Rpb24mJmkucHVzaCgiLS1lbmFibGUtY29ycmVjdGlvbiIpLGUuZGlzYWJsZUNvcnJlY3Rpb24mJmUuZGlzYWJsZUNvcnJlY3Rpb24mJmkucHVzaCgiLS1kaXNhYmxlLWNvcnJlY3Rpb24iKTtsZXQgQz0icmVhZC1kaWNvbS1lbmNhcHN1bGF0ZWQtcGRmIixsPWU/LndlYldvcmtlcjtsPT09dm9pZCAwJiYobD1hd2FpdCBUKCkpO2xldHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTphLHN0ZGVycjpFLG91dHB1dHM6Qn09YXdhaXQgRihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6UigpLHBpcGVsaW5lV29ya2VyVXJsOncoKSx3ZWJXb3JrZXI6bCxub0NvcHk6ZT8ubm9Db3B5fSk7aWYoYSE9PTAmJkUhPT0iIil0aHJvdyBuZXcgRXJyb3IoRSk7cmV0dXJue3dlYldvcmtlcjpzLHBkZkJpbmFyeU91dHB1dDooQlswXT8uZGF0YSkuZGF0YX19dmFyIGNpPUNpO2FzeW5jIGZ1bmN0aW9uIHVpKEEsZT17fSl7bGV0IHQ9W3t0eXBlOmYuVGV4dFN0cmVhbX1dLHI9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IGM9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO3I9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoYyl9fWxldCBuPVt7dHlwZTpmLkJpbmFyeUZpbGUsZGF0YTpyfV0saT1bXSxvPXIucGF0aDtpLnB1c2gobyk7bGV0IEk9IjAiO2lmKGkucHVzaChJKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksZS5yZWFkRmlsZU9ubHkmJmUucmVhZEZpbGVPbmx5JiZpLnB1c2goIi0tcmVhZC1maWxlLW9ubHkiKSxlLnJlYWREYXRhc2V0JiZlLnJlYWREYXRhc2V0JiZpLnB1c2goIi0tcmVhZC1kYXRhc2V0IiksZS5yZWFkWGZlckF1dG8mJmUucmVhZFhmZXJBdXRvJiZpLnB1c2goIi0tcmVhZC14ZmVyLWF1dG8iKSxlLnJlYWRYZmVyRGV0ZWN0JiZlLnJlYWRYZmVyRGV0ZWN0JiZpLnB1c2goIi0tcmVhZC14ZmVyLWRldGVjdCIpLGUucmVhZFhmZXJMaXR0bGUmJmUucmVhZFhmZXJMaXR0bGUmJmkucHVzaCgiLS1yZWFkLXhmZXItbGl0dGxlIiksZS5yZWFkWGZlckJpZyYmZS5yZWFkWGZlckJpZyYmaS5wdXNoKCItLXJlYWQteGZlci1iaWciKSxlLnJlYWRYZmVySW1wbGljaXQmJmUucmVhZFhmZXJJbXBsaWNpdCYmaS5wdXNoKCItLXJlYWQteGZlci1pbXBsaWNpdCIpLGUucHJvY2Vzc2luZ0RldGFpbHMmJmUucHJvY2Vzc2luZ0RldGFpbHMmJmkucHVzaCgiLS1wcm9jZXNzaW5nLWRldGFpbHMiKSxlLnVua25vd25SZWxhdGlvbnNoaXAmJmUudW5rbm93blJlbGF0aW9uc2hpcCYmaS5wdXNoKCItLXVua25vd24tcmVsYXRpb25zaGlwIiksZS5pbnZhbGlkSXRlbVZhbHVlJiZlLmludmFsaWRJdGVtVmFsdWUmJmkucHVzaCgiLS1pbnZhbGlkLWl0ZW0tdmFsdWUiKSxlLmlnbm9yZUNvbnN0cmFpbnRzJiZlLmlnbm9yZUNvbnN0cmFpbnRzJiZpLnB1c2goIi0taWdub3JlLWNvbnN0cmFpbnRzIiksZS5pZ25vcmVJdGVtRXJyb3JzJiZlLmlnbm9yZUl0ZW1FcnJvcnMmJmkucHVzaCgiLS1pZ25vcmUtaXRlbS1lcnJvcnMiKSxlLnNraXBJbnZhbGlkSXRlbXMmJmUuc2tpcEludmFsaWRJdGVtcyYmaS5wdXNoKCItLXNraXAtaW52YWxpZC1pdGVtcyIpLGUuZGlzYWJsZVZyQ2hlY2tlciYmZS5kaXNhYmxlVnJDaGVja2VyJiZpLnB1c2goIi0tZGlzYWJsZS12ci1jaGVja2VyIiksZS5jaGFyc2V0UmVxdWlyZSYmZS5jaGFyc2V0UmVxdWlyZSYmaS5wdXNoKCItLWNoYXJzZXQtcmVxdWlyZSIpLGUuY2hhcnNldEFzc3VtZSYmaS5wdXNoKCItLWNoYXJzZXQtYXNzdW1lIixlLmNoYXJzZXRBc3N1bWUudG9TdHJpbmcoKSksZS5jaGFyc2V0Q2hlY2tBbGwmJmUuY2hhcnNldENoZWNrQWxsJiZpLnB1c2goIi0tY2hhcnNldC1jaGVjay1hbGwiKSxlLmNvbnZlcnRUb1V0ZjgmJmUuY29udmVydFRvVXRmOCYmaS5wdXNoKCItLWNvbnZlcnQtdG8tdXRmOCIpLGUudXJsUHJlZml4JiZpLnB1c2goIi0tdXJsLXByZWZpeCIsZS51cmxQcmVmaXgudG9TdHJpbmcoKSksZS5odG1sMzImJmUuaHRtbDMyJiZpLnB1c2goIi0taHRtbC0zMiIpLGUuaHRtbDQwJiZlLmh0bWw0MCYmaS5wdXNoKCItLWh0bWwtNDAiKSxlLnhodG1sMTEmJmUueGh0bWwxMSYmaS5wdXNoKCItLXhodG1sLTExIiksZS5hZGREb2N1bWVudFR5cGUmJmUuYWRkRG9jdW1lbnRUeXBlJiZpLnB1c2goIi0tYWRkLWRvY3VtZW50LXR5cGUiKSxlLmNzc1JlZmVyZW5jZSl7bGV0IGM9bi5sZW5ndGgudG9TdHJpbmcoKTtuLnB1c2goe3R5cGU6Zi5UZXh0U3RyZWFtLGRhdGE6e2RhdGE6ZS5jc3NSZWZlcmVuY2V9fSksaS5wdXNoKCItLWNzcy1yZWZlcmVuY2UiLGMpfWlmKGUuY3NzRmlsZSl7bGV0IGM9ZS5jc3NGaWxlLFE9YztpZihjIGluc3RhbmNlb2YgRmlsZSl7bGV0IGI9YXdhaXQgYy5hcnJheUJ1ZmZlcigpO1E9e3BhdGg6Yy5uYW1lLGRhdGE6bmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKGIpfX1pLnB1c2goIi0tY3NzLWZpbGUiKSxuLnB1c2goe3R5cGU6Zi5UZXh0RmlsZSxkYXRhOlF9KTtsZXQgZD1jIGluc3RhbmNlb2YgRmlsZT9jLm5hbWU6Yy5wYXRoO2kucHVzaChkKX1lLmV4cGFuZElubGluZSYmZS5leHBhbmRJbmxpbmUmJmkucHVzaCgiLS1leHBhbmQtaW5saW5lIiksZS5uZXZlckV4cGFuZElubGluZSYmZS5uZXZlckV4cGFuZElubGluZSYmaS5wdXNoKCItLW5ldmVyLWV4cGFuZC1pbmxpbmUiKSxlLmFsd2F5c0V4cGFuZElubGluZSYmZS5hbHdheXNFeHBhbmRJbmxpbmUmJmkucHVzaCgiLS1hbHdheXMtZXhwYW5kLWlubGluZSIpLGUucmVuZGVyRnVsbERhdGEmJmUucmVuZGVyRnVsbERhdGEmJmkucHVzaCgiLS1yZW5kZXItZnVsbC1kYXRhIiksZS5zZWN0aW9uVGl0bGVJbmxpbmUmJmUuc2VjdGlvblRpdGxlSW5saW5lJiZpLnB1c2goIi0tc2VjdGlvbi10aXRsZS1pbmxpbmUiKSxlLmRvY3VtZW50VHlwZVRpdGxlJiZlLmRvY3VtZW50VHlwZVRpdGxlJiZpLnB1c2goIi0tZG9jdW1lbnQtdHlwZS10aXRsZSIpLGUucGF0aWVudEluZm9UaXRsZSYmZS5wYXRpZW50SW5mb1RpdGxlJiZpLnB1c2goIi0tcGF0aWVudC1pbmZvLXRpdGxlIiksZS5ub0RvY3VtZW50SGVhZGVyJiZlLm5vRG9jdW1lbnRIZWFkZXImJmkucHVzaCgiLS1uby1kb2N1bWVudC1oZWFkZXIiKSxlLnJlbmRlcklubGluZUNvZGVzJiZlLnJlbmRlcklubGluZUNvZGVzJiZpLnB1c2goIi0tcmVuZGVyLWlubGluZS1jb2RlcyIpLGUuY29uY2VwdE5hbWVDb2RlcyYmZS5jb25jZXB0TmFtZUNvZGVzJiZpLnB1c2goIi0tY29uY2VwdC1uYW1lLWNvZGVzIiksZS5udW1lcmljVW5pdENvZGVzJiZlLm51bWVyaWNVbml0Q29kZXMmJmkucHVzaCgiLS1udW1lcmljLXVuaXQtY29kZXMiKSxlLmNvZGVWYWx1ZVVuaXQmJmUuY29kZVZhbHVlVW5pdCYmaS5wdXNoKCItLWNvZGUtdmFsdWUtdW5pdCIpLGUuY29kZU1lYW5pbmdVbml0JiZlLmNvZGVNZWFuaW5nVW5pdCYmaS5wdXNoKCItLWNvZGUtbWVhbmluZy11bml0IiksZS5yZW5kZXJBbGxDb2RlcyYmZS5yZW5kZXJBbGxDb2RlcyYmaS5wdXNoKCItLXJlbmRlci1hbGwtY29kZXMiKSxlLmNvZGVEZXRhaWxzVG9vbHRpcCYmZS5jb2RlRGV0YWlsc1Rvb2x0aXAmJmkucHVzaCgiLS1jb2RlLWRldGFpbHMtdG9vbHRpcCIpO2xldCBDPSJzdHJ1Y3R1cmVkLXJlcG9ydC10by1odG1sIixsPWU/LndlYldvcmtlcjtsPT09dm9pZCAwJiYobD1hd2FpdCBUKCkpO2xldHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTphLHN0ZGVycjpFLG91dHB1dHM6Qn09YXdhaXQgRihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6UigpLHBpcGVsaW5lV29ya2VyVXJsOncoKSx3ZWJXb3JrZXI6bCxub0NvcHk6ZT8ubm9Db3B5fSk7aWYoYSE9PTAmJkUhPT0iIil0aHJvdyBuZXcgRXJyb3IoRSk7cmV0dXJue3dlYldvcmtlcjpzLG91dHB1dFRleHQ6KEJbMF0/LmRhdGEpLmRhdGF9fXZhciBFaT11aTthc3luYyBmdW5jdGlvbiBmaShBLGU9e30pe2xldCB0PVt7dHlwZTpmLlRleHRTdHJlYW19XSxyPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBjPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTtyPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KGMpfX1sZXQgbj1be3R5cGU6Zi5CaW5hcnlGaWxlLGRhdGE6cn1dLGk9W10sbz1yLnBhdGg7aS5wdXNoKG8pO2xldCBJPSIwIjtpLnB1c2goSSksaS5wdXNoKCItLW1lbW9yeS1pbyIpLGUudW5rbm93blJlbGF0aW9uc2hpcCYmZS51bmtub3duUmVsYXRpb25zaGlwJiZpLnB1c2goIi0tdW5rbm93bi1yZWxhdGlvbnNoaXAiKSxlLmludmFsaWRJdGVtVmFsdWUmJmUuaW52YWxpZEl0ZW1WYWx1ZSYmaS5wdXNoKCItLWludmFsaWQtaXRlbS12YWx1ZSIpLGUuaWdub3JlQ29uc3RyYWludHMmJmUuaWdub3JlQ29uc3RyYWludHMmJmkucHVzaCgiLS1pZ25vcmUtY29uc3RyYWludHMiKSxlLmlnbm9yZUl0ZW1FcnJvcnMmJmUuaWdub3JlSXRlbUVycm9ycyYmaS5wdXNoKCItLWlnbm9yZS1pdGVtLWVycm9ycyIpLGUuc2tpcEludmFsaWRJdGVtcyYmZS5za2lwSW52YWxpZEl0ZW1zJiZpLnB1c2goIi0tc2tpcC1pbnZhbGlkLWl0ZW1zIiksZS5ub0RvY3VtZW50SGVhZGVyJiZlLm5vRG9jdW1lbnRIZWFkZXImJmkucHVzaCgiLS1uby1kb2N1bWVudC1oZWFkZXIiKSxlLm51bWJlck5lc3RlZEl0ZW1zJiZlLm51bWJlck5lc3RlZEl0ZW1zJiZpLnB1c2goIi0tbnVtYmVyLW5lc3RlZC1pdGVtcyIpLGUuc2hvcnRlbkxvbmdWYWx1ZXMmJmUuc2hvcnRlbkxvbmdWYWx1ZXMmJmkucHVzaCgiLS1zaG9ydGVuLWxvbmctdmFsdWVzIiksZS5wcmludEluc3RhbmNlVWlkJiZlLnByaW50SW5zdGFuY2VVaWQmJmkucHVzaCgiLS1wcmludC1pbnN0YW5jZS11aWQiKSxlLnByaW50U29wY2xhc3NTaG9ydCYmZS5wcmludFNvcGNsYXNzU2hvcnQmJmkucHVzaCgiLS1wcmludC1zb3BjbGFzcy1zaG9ydCIpLGUucHJpbnRTb3BjbGFzc0xvbmcmJmUucHJpbnRTb3BjbGFzc0xvbmcmJmkucHVzaCgiLS1wcmludC1zb3BjbGFzcy1sb25nIiksZS5wcmludFNvcGNsYXNzVWlkJiZlLnByaW50U29wY2xhc3NVaWQmJmkucHVzaCgiLS1wcmludC1zb3BjbGFzcy11aWQiKSxlLnByaW50QWxsQ29kZXMmJmUucHJpbnRBbGxDb2RlcyYmaS5wdXNoKCItLXByaW50LWFsbC1jb2RlcyIpLGUucHJpbnRJbnZhbGlkQ29kZXMmJmUucHJpbnRJbnZhbGlkQ29kZXMmJmkucHVzaCgiLS1wcmludC1pbnZhbGlkLWNvZGVzIiksZS5wcmludFRlbXBsYXRlSWQmJmUucHJpbnRUZW1wbGF0ZUlkJiZpLnB1c2goIi0tcHJpbnQtdGVtcGxhdGUtaWQiKSxlLmluZGljYXRlRW5oYW5jZWQmJmUuaW5kaWNhdGVFbmhhbmNlZCYmaS5wdXNoKCItLWluZGljYXRlLWVuaGFuY2VkIiksZS5wcmludENvbG9yJiZlLnByaW50Q29sb3ImJmkucHVzaCgiLS1wcmludC1jb2xvciIpO2xldCBDPSJzdHJ1Y3R1cmVkLXJlcG9ydC10by10ZXh0IixsPWU/LndlYldvcmtlcjtsPT09dm9pZCAwJiYobD1hd2FpdCBUKCkpO2xldHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTphLHN0ZGVycjpFLG91dHB1dHM6Qn09YXdhaXQgRihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6UigpLHBpcGVsaW5lV29ya2VyVXJsOncoKSx3ZWJXb3JrZXI6bCxub0NvcHk6ZT8ubm9Db3B5fSk7aWYoYSE9PTAmJkUhPT0iIil0aHJvdyBuZXcgRXJyb3IoRSk7cmV0dXJue3dlYldvcmtlcjpzLG91dHB1dFRleHQ6KEJbMF0/LmRhdGEpLmRhdGF9fXZhciBRaT1maTthc3luYyBmdW5jdGlvbiBwaShBLGU9e30pe2xldCB0PVt7dHlwZTpmLkpzb25Db21wYXRpYmxlfV0scj1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgdT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7cj17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheSh1KX19bGV0IG49W3t0eXBlOmYuQmluYXJ5RmlsZSxkYXRhOnJ9XSxpPVtdLG89ci5wYXRoO2kucHVzaChvKTtsZXQgST0iMCI7aWYoaS5wdXNoKEkpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgZS50YWdzVG9SZWFkPCJ1Iil7bGV0IHU9bi5sZW5ndGgudG9TdHJpbmcoKTtuLnB1c2goe3R5cGU6Zi5Kc29uQ29tcGF0aWJsZSxkYXRhOmUudGFnc1RvUmVhZH0pLGkucHVzaCgiLS10YWdzLXRvLXJlYWQiLHUpfWxldCBDPSJyZWFkLWRpY29tLXRhZ3MiLHt3ZWJXb3JrZXI6bCxyZXR1cm5WYWx1ZTpzLHN0ZGVycjphLG91dHB1dHM6RX09YXdhaXQgRihDLGksdCxuLHtwaXBlbGluZUJhc2VVcmw6UigpLHBpcGVsaW5lV29ya2VyVXJsOncoKSx3ZWJXb3JrZXI6ZT8ud2ViV29ya2VyPz9udWxsfSk7aWYocyE9PTApdGhyb3cgbmV3IEVycm9yKGEpO3JldHVybnt3ZWJXb3JrZXI6bCx0YWdzOkVbMF0uZGF0YX19dmFyIGRpPXBpO2FzeW5jIGZ1bmN0aW9uIG1pKEEsZT0hMSx0PXt9KXtsZXQgcj1be3R5cGU6Zi5JbWFnZX0se3R5cGU6Zi5Kc29uQ29tcGF0aWJsZX1dLG49W10saT1bXSxvPSIwIjtpLnB1c2gobyk7bGV0IEk9IjEiO2kucHVzaChJKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksaS5wdXNoKCItLWlucHV0LWltYWdlcyIpLEEuZm9yRWFjaCh1PT57bi5wdXNoKHt0eXBlOmYuQmluYXJ5RmlsZSxkYXRhOnV9KSxpLnB1c2godS5wYXRoKX0pLHR5cGVvZiBlPCJ1IiYmZSYmaS5wdXNoKCItLXNpbmdsZS1zb3J0ZWQtc2VyaWVzIik7bGV0IEM9InJlYWQtaW1hZ2UtZGljb20tZmlsZS1zZXJpZXMiLHt3ZWJXb3JrZXI6bCxyZXR1cm5WYWx1ZTpzLHN0ZGVycjphLG91dHB1dHM6RX09YXdhaXQgRihDLGkscixuLHtwaXBlbGluZUJhc2VVcmw6UigpLHBpcGVsaW5lV29ya2VyVXJsOncoKSx3ZWJXb3JrZXI6dD8ud2ViV29ya2VyPz9udWxsfSk7aWYocyE9PTApdGhyb3cgbmV3IEVycm9yKGEpO3JldHVybnt3ZWJXb3JrZXI6bCxvdXRwdXRJbWFnZTpFWzBdLmRhdGEsc29ydGVkRmlsZW5hbWVzOkVbMV0uZGF0YX19dmFyIGdlPW1pO3ZhciBoaT10eXBlb2YgZ2xvYmFsVGhpcy5uYXZpZ2F0b3I/LmhhcmR3YXJlQ29uY3VycmVuY3k9PSJudW1iZXIiP2dsb2JhbFRoaXMubmF2aWdhdG9yLmhhcmR3YXJlQ29uY3VycmVuY3k6NCx5dD04O2FzeW5jIGZ1bmN0aW9uIHlpKEE9e2lucHV0SW1hZ2VzOltdfSl7bGV0IGU9QS53ZWJXb3JrZXJQb29sPz9udWxsO2U9PT1udWxsJiYoZT1uZXcgR0EoaGksZ2UpKTtsZXQgdD1bXTtpZihBLmlucHV0SW1hZ2VzLmxlbmd0aDwxKXRocm93IG5ldyBFcnJvcignImlucHV0LWltYWdlcyIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtpZihhd2FpdCBQcm9taXNlLmFsbChBLmlucHV0SW1hZ2VzLm1hcChhc3luYyByPT57bGV0IG49cjtpZihyIGluc3RhbmNlb2YgRmlsZSl7bGV0IGk9YXdhaXQgci5hcnJheUJ1ZmZlcigpO249e3BhdGg6ci5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoaSl9fXQucHVzaChuKX0pKSxBLnNpbmdsZVNvcnRlZFNlcmllcyl7bGV0IHI9W107Zm9yKGxldCBDPTA7Qzx0Lmxlbmd0aDtDKz15dCl7bGV0IGw9dC5zbGljZShDLEMreXQpO3IucHVzaChbbCxBLnNpbmdsZVNvcnRlZFNlcmllcyx7fV0pfWxldCBuPWF3YWl0IGUucnVuVGFza3MocikucHJvbWlzZSxpPW4ubWFwKEM9PkMub3V0cHV0SW1hZ2UpLG89bi5yZWR1Y2UoKEMsbCk9PkMuY29uY2F0KGwuc29ydGVkRmlsZW5hbWVzKSxbXSk7cmV0dXJue291dHB1dEltYWdlOlVBKGkpLHdlYldvcmtlclBvb2w6ZSxzb3J0ZWRGaWxlbmFtZXM6b319ZWxzZXtsZXQgcj1bW3QsQS5zaW5nbGVTb3J0ZWRTZXJpZXMse31dXSxuPWF3YWl0IGUucnVuVGFza3MocikucHJvbWlzZTtyZXR1cm57b3V0cHV0SW1hZ2U6blswXS5vdXRwdXRJbWFnZSx3ZWJXb3JrZXJQb29sOmUsc29ydGVkRmlsZW5hbWVzOm5bMF0uc29ydGVkRmlsZW5hbWVzfX19dmFyIHdpPXlpO2FzeW5jIGZ1bmN0aW9uIERpKEE9e2ZpbGVzOltdfSl7bGV0IGU9W3t0eXBlOmYuSnNvbkNvbXBhdGlibGV9XSx0PVtdLHI9W10sbj0iMCI7aWYoci5wdXNoKG4pLHIucHVzaCgiLS1tZW1vcnktaW8iKSxBLmZpbGVzKXtpZihBLmZpbGVzLmxlbmd0aDwxKXRocm93IG5ldyBFcnJvcignImZpbGVzIiBvcHRpb24gbXVzdCBoYXZlIGEgbGVuZ3RoID4gMScpO3IucHVzaCgiLS1maWxlcyIpLGF3YWl0IFByb21pc2UuYWxsKEEuZmlsZXMubWFwKGFzeW5jIEU9PntsZXQgQj1FO2lmKEUgaW5zdGFuY2VvZiBGaWxlKXtsZXQgYz1hd2FpdCBFLmFycmF5QnVmZmVyKCk7Qj17cGF0aDpFLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShjKX19dC5wdXNoKHt0eXBlOmYuQmluYXJ5RmlsZSxkYXRhOkJ9KTtsZXQgdT1FIGluc3RhbmNlb2YgRmlsZT9FLm5hbWU6Qi5wYXRoO3IucHVzaCh1KX0pKX1sZXQgaT0iaW1hZ2Utc2V0cy1ub3JtYWxpemF0aW9uIixvPUE/LndlYldvcmtlcjtvPT09dm9pZCAwJiYobz1hd2FpdCBUKCkpO2xldHt3ZWJXb3JrZXI6SSxyZXR1cm5WYWx1ZTpDLHN0ZGVycjpsLG91dHB1dHM6c309YXdhaXQgRihpLHIsZSx0LHtwaXBlbGluZUJhc2VVcmw6UigpLHBpcGVsaW5lV29ya2VyVXJsOncoKSx3ZWJXb3JrZXI6byxub0NvcHk6QT8ubm9Db3B5fSk7aWYoQyE9PTAmJmwhPT0iIil0aHJvdyBuZXcgRXJyb3IobCk7cmV0dXJue3dlYldvcmtlcjpJLGltYWdlU2V0czpzWzBdPy5kYXRhfX12YXIgU2k9RGk7dmFyIHd0PSdkYXRhOnRleHQvamF2YXNjcmlwdDtjaGFyc2V0PXV0Zi04LHZhciB0dD1PYmplY3QuZGVmaW5lUHJvcGVydHk7dmFyIGV0PShBLEkpPT57Zm9yKHZhciB0IGluIEkpdHQoQSx0LHtnZXQ6SVt0XSxlbnVtZXJhYmxlOiEwfSl9O3ZhciB2QT1TeW1ib2woIkNvbWxpbmsucHJveHkiKSxndD1TeW1ib2woIkNvbWxpbmsuZW5kcG9pbnQiKSxydD1TeW1ib2woIkNvbWxpbmsucmVsZWFzZVByb3h5IiksbUE9U3ltYm9sKCJDb21saW5rLmZpbmFsaXplciIpLGVBPVN5bWJvbCgiQ29tbGluay50aHJvd24iKSwkQT1BPT50eXBlb2YgQT09Im9iamVjdCImJkEhPT1udWxsfHx0eXBlb2YgQT09ImZ1bmN0aW9uIixpdD17Y2FuSGFuZGxlOkE9PiRBKEEpJiZBW3ZBXSxzZXJpYWxpemUoQSl7bGV0e3BvcnQxOkkscG9ydDI6dH09bmV3IE1lc3NhZ2VDaGFubmVsO3JldHVybiBvQShBLEkpLFt0LFt0XV19LGRlc2VyaWFsaXplKEEpe3JldHVybiBBLnN0YXJ0KCksc3QoQSl9fSxvdD17Y2FuSGFuZGxlOkE9PiRBKEEpJiZlQSBpbiBBLHNlcmlhbGl6ZSh7dmFsdWU6QX0pe2xldCBJO3JldHVybiBBIGluc3RhbmNlb2YgRXJyb3I/ST17aXNFcnJvcjohMCx2YWx1ZTp7bWVzc2FnZTpBLm1lc3NhZ2UsbmFtZTpBLm5hbWUsc3RhY2s6QS5zdGFja319Okk9e2lzRXJyb3I6ITEsdmFsdWU6QX0sW0ksW11dfSxkZXNlcmlhbGl6ZShBKXt0aHJvdyBBLmlzRXJyb3I/T2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoQS52YWx1ZS5tZXNzYWdlKSxBLnZhbHVlKTpBLnZhbHVlfX0sQUk9bmV3IE1hcChbWyJwcm94eSIsaXRdLFsidGhyb3ciLG90XV0pO2Z1bmN0aW9uIEJ0KEEsSSl7Zm9yKGxldCB0IG9mIEEpaWYoST09PXR8fHQ9PT0iKiJ8fHQgaW5zdGFuY2VvZiBSZWdFeHAmJnQudGVzdChJKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiBvQShBLEk9Z2xvYmFsVGhpcyx0PVsiKiJdKXtJLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGUoZyl7aWYoIWd8fCFnLmRhdGEpcmV0dXJuO2lmKCFCdCh0LGcub3JpZ2luKSl7Y29uc29sZS53YXJuKGBJbnZhbGlkIG9yaWdpbiBcJyR7Zy5vcmlnaW59XCcgZm9yIGNvbWxpbmsgcHJveHlgKTtyZXR1cm59bGV0e2lkOnIsdHlwZTppLHBhdGg6c309T2JqZWN0LmFzc2lnbih7cGF0aDpbXX0sZy5kYXRhKSxhPShnLmRhdGEuYXJndW1lbnRMaXN0fHxbXSkubWFwKGIpLG47dHJ5e2xldCBDPXMuc2xpY2UoMCwtMSkucmVkdWNlKChmLFEpPT5mW1FdLEEpLG89cy5yZWR1Y2UoKGYsUSk9PmZbUV0sQSk7c3dpdGNoKGkpe2Nhc2UiR0VUIjpuPW87YnJlYWs7Y2FzZSJTRVQiOkNbcy5zbGljZSgtMSlbMF1dPWIoZy5kYXRhLnZhbHVlKSxuPSEwO2JyZWFrO2Nhc2UiQVBQTFkiOm49by5hcHBseShDLGEpO2JyZWFrO2Nhc2UiQ09OU1RSVUNUIjp7bGV0IGY9bmV3IG8oLi4uYSk7bj1hdChmKX1icmVhaztjYXNlIkVORFBPSU5UIjp7bGV0e3BvcnQxOmYscG9ydDI6UX09bmV3IE1lc3NhZ2VDaGFubmVsO29BKEEsUSksbj1TQShmLFtmXSl9YnJlYWs7Y2FzZSJSRUxFQVNFIjpuPXZvaWQgMDticmVhaztkZWZhdWx0OnJldHVybn19Y2F0Y2goQyl7bj17dmFsdWU6QyxbZUFdOjB9fVByb21pc2UucmVzb2x2ZShuKS5jYXRjaChDPT4oe3ZhbHVlOkMsW2VBXTowfSkpLnRoZW4oQz0+e2xldFtvLGZdPWlBKEMpO0kucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LG8pLHtpZDpyfSksZiksaT09PSJSRUxFQVNFIiYmKEkucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZSksSUkoSSksbUEgaW4gQSYmdHlwZW9mIEFbbUFdPT0iZnVuY3Rpb24iJiZBW21BXSgpKX0pLmNhdGNoKEM9PntsZXRbbyxmXT1pQSh7dmFsdWU6bmV3IFR5cGVFcnJvcigiVW5zZXJpYWxpemFibGUgcmV0dXJuIHZhbHVlIiksW2VBXTowfSk7SS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sbykse2lkOnJ9KSxmKX0pfSksSS5zdGFydCYmSS5zdGFydCgpfWZ1bmN0aW9uIEN0KEEpe3JldHVybiBBLmNvbnN0cnVjdG9yLm5hbWU9PT0iTWVzc2FnZVBvcnQifWZ1bmN0aW9uIElJKEEpe0N0KEEpJiZBLmNsb3NlKCl9ZnVuY3Rpb24gc3QoQSxJKXtyZXR1cm4gcEEoQSxbXSxJKX1mdW5jdGlvbiB0QShBKXtpZihBKXRocm93IG5ldyBFcnJvcigiUHJveHkgaGFzIGJlZW4gcmVsZWFzZWQgYW5kIGlzIG5vdCB1c2VhYmxlIil9ZnVuY3Rpb24gdEkoQSl7cmV0dXJuIE0oQSx7dHlwZToiUkVMRUFTRSJ9KS50aGVuKCgpPT57SUkoQSl9KX12YXIgZ0E9bmV3IFdlYWtNYXAsckE9IkZpbmFsaXphdGlvblJlZ2lzdHJ5ImluIGdsb2JhbFRoaXMmJm5ldyBGaW5hbGl6YXRpb25SZWdpc3RyeShBPT57bGV0IEk9KGdBLmdldChBKXx8MCktMTtnQS5zZXQoQSxJKSxJPT09MCYmdEkoQSl9KTtmdW5jdGlvbiBRdChBLEkpe2xldCB0PShnQS5nZXQoSSl8fDApKzE7Z0Euc2V0KEksdCksckEmJnJBLnJlZ2lzdGVyKEEsSSxBKX1mdW5jdGlvbiBudChBKXtyQSYmckEudW5yZWdpc3RlcihBKX1mdW5jdGlvbiBwQShBLEk9W10sdD1mdW5jdGlvbigpe30pe2xldCBlPSExLGc9bmV3IFByb3h5KHQse2dldChyLGkpe2lmKHRBKGUpLGk9PT1ydClyZXR1cm4oKT0+e250KGcpLHRJKEEpLGU9ITB9O2lmKGk9PT0idGhlbiIpe2lmKEkubGVuZ3RoPT09MClyZXR1cm57dGhlbjooKT0+Z307bGV0IHM9TShBLHt0eXBlOiJHRVQiLHBhdGg6SS5tYXAoYT0+YS50b1N0cmluZygpKX0pLnRoZW4oYik7cmV0dXJuIHMudGhlbi5iaW5kKHMpfXJldHVybiBwQShBLFsuLi5JLGldKX0sc2V0KHIsaSxzKXt0QShlKTtsZXRbYSxuXT1pQShzKTtyZXR1cm4gTShBLHt0eXBlOiJTRVQiLHBhdGg6Wy4uLkksaV0ubWFwKEM9PkMudG9TdHJpbmcoKSksdmFsdWU6YX0sbikudGhlbihiKX0sYXBwbHkocixpLHMpe3RBKGUpO2xldCBhPUlbSS5sZW5ndGgtMV07aWYoYT09PWd0KXJldHVybiBNKEEse3R5cGU6IkVORFBPSU5UIn0pLnRoZW4oYik7aWYoYT09PSJiaW5kIilyZXR1cm4gcEEoQSxJLnNsaWNlKDAsLTEpKTtsZXRbbixDXT1fQShzKTtyZXR1cm4gTShBLHt0eXBlOiJBUFBMWSIscGF0aDpJLm1hcChvPT5vLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpufSxDKS50aGVuKGIpfSxjb25zdHJ1Y3QocixpKXt0QShlKTtsZXRbcyxhXT1fQShpKTtyZXR1cm4gTShBLHt0eXBlOiJDT05TVFJVQ1QiLHBhdGg6SS5tYXAobj0+bi50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6c30sYSkudGhlbihiKX19KTtyZXR1cm4gUXQoZyxBKSxnfWZ1bmN0aW9uIEV0KEEpe3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLEEpfWZ1bmN0aW9uIF9BKEEpe2xldCBJPUEubWFwKGlBKTtyZXR1cm5bSS5tYXAodD0+dFswXSksRXQoSS5tYXAodD0+dFsxXSkpXX12YXIgZUk9bmV3IFdlYWtNYXA7ZnVuY3Rpb24gU0EoQSxJKXtyZXR1cm4gZUkuc2V0KEEsSSksQX1mdW5jdGlvbiBhdChBKXtyZXR1cm4gT2JqZWN0LmFzc2lnbihBLHtbdkFdOiEwfSl9ZnVuY3Rpb24gaUEoQSl7Zm9yKGxldFtJLHRdb2YgQUkpaWYodC5jYW5IYW5kbGUoQSkpe2xldFtlLGddPXQuc2VyaWFsaXplKEEpO3JldHVyblt7dHlwZToiSEFORExFUiIsbmFtZTpJLHZhbHVlOmV9LGddfXJldHVyblt7dHlwZToiUkFXIix2YWx1ZTpBfSxlSS5nZXQoQSl8fFtdXX1mdW5jdGlvbiBiKEEpe3N3aXRjaChBLnR5cGUpe2Nhc2UiSEFORExFUiI6cmV0dXJuIEFJLmdldChBLm5hbWUpLmRlc2VyaWFsaXplKEEudmFsdWUpO2Nhc2UiUkFXIjpyZXR1cm4gQS52YWx1ZX19ZnVuY3Rpb24gTShBLEksdCl7cmV0dXJuIG5ldyBQcm9taXNlKGU9PntsZXQgZz1jdCgpO0EuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gcihpKXshaS5kYXRhfHwhaS5kYXRhLmlkfHxpLmRhdGEuaWQhPT1nfHwoQS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixyKSxlKGkuZGF0YSkpfSksQS5zdGFydCYmQS5zdGFydCgpLEEucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbih7aWQ6Z30sSSksdCl9KX1mdW5jdGlvbiBjdCgpe3JldHVybiBuZXcgQXJyYXkoNCkuZmlsbCgwKS5tYXAoKCk9Pk1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikudG9TdHJpbmcoMTYpKS5qb2luKCItIil9ZnVuY3Rpb24gVyhBLEkpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiBBLmFwcGx5KEksYXJndW1lbnRzKX19dmFye3RvU3RyaW5nOmZ0fT1PYmplY3QucHJvdG90eXBlLHtnZXRQcm90b3R5cGVPZjpOQX09T2JqZWN0LENBPShBPT5JPT57bGV0IHQ9ZnQuY2FsbChJKTtyZXR1cm4gQVt0XXx8KEFbdF09dC5zbGljZSg4LC0xKS50b0xvd2VyQ2FzZSgpKX0pKE9iamVjdC5jcmVhdGUobnVsbCkpLFU9QT0+KEE9QS50b0xvd2VyQ2FzZSgpLEk9PkNBKEkpPT09QSksc0E9QT0+ST0+dHlwZW9mIEk9PT1BLHtpc0FycmF5OnF9PUFycmF5LFo9c0EoInVuZGVmaW5lZCIpO2Z1bmN0aW9uIGx0KEEpe3JldHVybiBBIT09bnVsbCYmIVooQSkmJkEuY29uc3RydWN0b3IhPT1udWxsJiYhWihBLmNvbnN0cnVjdG9yKSYmRihBLmNvbnN0cnVjdG9yLmlzQnVmZmVyKSYmQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcihBKX12YXIgb0k9VSgiQXJyYXlCdWZmZXIiKTtmdW5jdGlvbiBEdChBKXtsZXQgSTtyZXR1cm4gdHlwZW9mIEFycmF5QnVmZmVyPCJ1IiYmQXJyYXlCdWZmZXIuaXNWaWV3P0k9QXJyYXlCdWZmZXIuaXNWaWV3KEEpOkk9QSYmQS5idWZmZXImJm9JKEEuYnVmZmVyKSxJfXZhciB1dD1zQSgic3RyaW5nIiksRj1zQSgiZnVuY3Rpb24iKSxCST1zQSgibnVtYmVyIiksUUE9QT0+QSE9PW51bGwmJnR5cGVvZiBBPT0ib2JqZWN0IixodD1BPT5BPT09ITB8fEE9PT0hMSxCQT1BPT57aWYoQ0EoQSkhPT0ib2JqZWN0IilyZXR1cm4hMTtsZXQgST1OQShBKTtyZXR1cm4oST09PW51bGx8fEk9PT1PYmplY3QucHJvdG90eXBlfHxPYmplY3QuZ2V0UHJvdG90eXBlT2YoSSk9PT1udWxsKSYmIShTeW1ib2wudG9TdHJpbmdUYWcgaW4gQSkmJiEoU3ltYm9sLml0ZXJhdG9yIGluIEEpfSxkdD1VKCJEYXRlIikseXQ9VSgiRmlsZSIpLHd0PVUoIkJsb2IiKSxtdD1VKCJGaWxlTGlzdCIpLHB0PUE9PlFBKEEpJiZGKEEucGlwZSksU3Q9QT0+e2xldCBJO3JldHVybiBBJiYodHlwZW9mIEZvcm1EYXRhPT0iZnVuY3Rpb24iJiZBIGluc3RhbmNlb2YgRm9ybURhdGF8fEYoQS5hcHBlbmQpJiYoKEk9Q0EoQSkpPT09ImZvcm1kYXRhInx8ST09PSJvYmplY3QiJiZGKEEudG9TdHJpbmcpJiZBLnRvU3RyaW5nKCk9PT0iW29iamVjdCBGb3JtRGF0YV0iKSl9LEZ0PVUoIlVSTFNlYXJjaFBhcmFtcyIpLFJ0PUE9PkEudHJpbT9BLnRyaW0oKTpBLnJlcGxhY2UoL15bXFxzXFx1RkVGRlxceEEwXSt8W1xcc1xcdUZFRkZcXHhBMF0rJC9nLCIiKTtmdW5jdGlvbiBWKEEsSSx7YWxsT3duS2V5czp0PSExfT17fSl7aWYoQT09PW51bGx8fHR5cGVvZiBBPiJ1IilyZXR1cm47bGV0IGUsZztpZih0eXBlb2YgQSE9Im9iamVjdCImJihBPVtBXSkscShBKSlmb3IoZT0wLGc9QS5sZW5ndGg7ZTxnO2UrKylJLmNhbGwobnVsbCxBW2VdLGUsQSk7ZWxzZXtsZXQgcj10P09iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKEEpOk9iamVjdC5rZXlzKEEpLGk9ci5sZW5ndGgscztmb3IoZT0wO2U8aTtlKyspcz1yW2VdLEkuY2FsbChudWxsLEFbc10scyxBKX19ZnVuY3Rpb24gQ0koQSxJKXtJPUkudG9Mb3dlckNhc2UoKTtsZXQgdD1PYmplY3Qua2V5cyhBKSxlPXQubGVuZ3RoLGc7Zm9yKDtlLS0gPjA7KWlmKGc9dFtlXSxJPT09Zy50b0xvd2VyQ2FzZSgpKXJldHVybiBnO3JldHVybiBudWxsfXZhciBzST10eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsLFFJPUE9PiFaKEEpJiZBIT09c0k7ZnVuY3Rpb24gUkEoKXtsZXR7Y2FzZWxlc3M6QX09UUkodGhpcykmJnRoaXN8fHt9LEk9e30sdD0oZSxnKT0+e2xldCByPUEmJkNJKEksZyl8fGc7QkEoSVtyXSkmJkJBKGUpP0lbcl09UkEoSVtyXSxlKTpCQShlKT9JW3JdPVJBKHt9LGUpOnEoZSk/SVtyXT1lLnNsaWNlKCk6SVtyXT1lfTtmb3IobGV0IGU9MCxnPWFyZ3VtZW50cy5sZW5ndGg7ZTxnO2UrKylhcmd1bWVudHNbZV0mJlYoYXJndW1lbnRzW2VdLHQpO3JldHVybiBJfXZhciBOdD0oQSxJLHQse2FsbE93bktleXM6ZX09e30pPT4oVihJLChnLHIpPT57dCYmRihnKT9BW3JdPVcoZyx0KTpBW3JdPWd9LHthbGxPd25LZXlzOmV9KSxBKSxVdD1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLEd0PShBLEksdCxlKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoSS5wcm90b3R5cGUsZSksQS5wcm90b3R5cGUuY29uc3RydWN0b3I9QSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTpJLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsdCl9LGt0PShBLEksdCxlKT0+e2xldCBnLHIsaSxzPXt9O2lmKEk9SXx8e30sQT09bnVsbClyZXR1cm4gSTtkb3tmb3IoZz1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxyPWcubGVuZ3RoO3ItLSA+MDspaT1nW3JdLCghZXx8ZShpLEEsSSkpJiYhc1tpXSYmKElbaV09QVtpXSxzW2ldPSEwKTtBPXQhPT0hMSYmTkEoQSl9d2hpbGUoQSYmKCF0fHx0KEEsSSkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIEl9LEx0PShBLEksdCk9PntBPVN0cmluZyhBKSwodD09PXZvaWQgMHx8dD5BLmxlbmd0aCkmJih0PUEubGVuZ3RoKSx0LT1JLmxlbmd0aDtsZXQgZT1BLmluZGV4T2YoSSx0KTtyZXR1cm4gZSE9PS0xJiZlPT09dH0sSnQ9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKHEoQSkpcmV0dXJuIEE7bGV0IEk9QS5sZW5ndGg7aWYoIUJJKEkpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShJKTtmb3IoO0ktLSA+MDspdFtJXT1BW0ldO3JldHVybiB0fSxIdD0oQT0+ST0+QSYmSSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmTkEoVWludDhBcnJheSkpLFl0PShBLEkpPT57bGV0IGU9KEEmJkFbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChBKSxnO2Zvcig7KGc9ZS5uZXh0KCkpJiYhZy5kb25lOyl7bGV0IHI9Zy52YWx1ZTtJLmNhbGwoQSxyWzBdLHJbMV0pfX0sYnQ9KEEsSSk9PntsZXQgdCxlPVtdO2Zvcig7KHQ9QS5leGVjKEkpKSE9PW51bGw7KWUucHVzaCh0KTtyZXR1cm4gZX0sTXQ9VSgiSFRNTEZvcm1FbGVtZW50IikscXQ9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xcc10oW2EtelxcZF0pKFxcdyopL2csZnVuY3Rpb24odCxlLGcpe3JldHVybiBlLnRvVXBwZXJDYXNlKCkrZ30pLHJJPSgoe2hhc093blByb3BlcnR5OkF9KT0+KEksdCk9PkEuY2FsbChJLHQpKShPYmplY3QucHJvdG90eXBlKSxLdD1VKCJSZWdFeHAiKSxuST0oQSxJKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLGU9e307Vih0LChnLHIpPT57bGV0IGk7KGk9SShnLHIsQSkpIT09ITEmJihlW3JdPWl8fGcpfSksT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQSxlKX0sT3Q9QT0+e25JKEEsKEksdCk9PntpZihGKEEpJiZbImFyZ3VtZW50cyIsImNhbGxlciIsImNhbGxlZSJdLmluZGV4T2YodCkhPT0tMSlyZXR1cm4hMTtsZXQgZT1BW3RdO2lmKEYoZSkpe2lmKEkuZW51bWVyYWJsZT0hMSwid3JpdGFibGUiaW4gSSl7SS53cml0YWJsZT0hMTtyZXR1cm59SS5zZXR8fChJLnNldD0oKT0+e3Rocm93IEVycm9yKCJDYW4gbm90IHJld3JpdGUgcmVhZC1vbmx5IG1ldGhvZCBcJyIrdCsiXCciKX0pfX0pfSxUdD0oQSxJKT0+e2xldCB0PXt9LGU9Zz0+e2cuZm9yRWFjaChyPT57dFtyXT0hMH0pfTtyZXR1cm4gcShBKT9lKEEpOmUoU3RyaW5nKEEpLnNwbGl0KEkpKSx0fSx4dD0oKT0+e30sUHQ9KEEsSSk9PihBPStBLE51bWJlci5pc0Zpbml0ZShBKT9BOkkpLEZBPSJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiIsaUk9IjAxMjM0NTY3ODkiLEVJPXtESUdJVDppSSxBTFBIQTpGQSxBTFBIQV9ESUdJVDpGQStGQS50b1VwcGVyQ2FzZSgpK2lJfSxqdD0oQT0xNixJPUVJLkFMUEhBX0RJR0lUKT0+e2xldCB0PSIiLHtsZW5ndGg6ZX09STtmb3IoO0EtLTspdCs9SVtNYXRoLnJhbmRvbSgpKmV8MF07cmV0dXJuIHR9O2Z1bmN0aW9uIFd0KEEpe3JldHVybiEhKEEmJkYoQS5hcHBlbmQpJiZBW1N5bWJvbC50b1N0cmluZ1RhZ109PT0iRm9ybURhdGEiJiZBW1N5bWJvbC5pdGVyYXRvcl0pfXZhciBadD1BPT57bGV0IEk9bmV3IEFycmF5KDEwKSx0PShlLGcpPT57aWYoUUEoZSkpe2lmKEkuaW5kZXhPZihlKT49MClyZXR1cm47aWYoISgidG9KU09OImluIGUpKXtJW2ddPWU7bGV0IHI9cShlKT9bXTp7fTtyZXR1cm4gVihlLChpLHMpPT57bGV0IGE9dChpLGcrMSk7IVooYSkmJihyW3NdPWEpfSksSVtnXT12b2lkIDAscn19cmV0dXJuIGV9O3JldHVybiB0KEEsMCl9LFZ0PVUoIkFzeW5jRnVuY3Rpb24iKSxYdD1BPT5BJiYoUUEoQSl8fEYoQSkpJiZGKEEudGhlbikmJkYoQS5jYXRjaCksQj17aXNBcnJheTpxLGlzQXJyYXlCdWZmZXI6b0ksaXNCdWZmZXI6bHQsaXNGb3JtRGF0YTpTdCxpc0FycmF5QnVmZmVyVmlldzpEdCxpc1N0cmluZzp1dCxpc051bWJlcjpCSSxpc0Jvb2xlYW46aHQsaXNPYmplY3Q6UUEsaXNQbGFpbk9iamVjdDpCQSxpc1VuZGVmaW5lZDpaLGlzRGF0ZTpkdCxpc0ZpbGU6eXQsaXNCbG9iOnd0LGlzUmVnRXhwOkt0LGlzRnVuY3Rpb246Rixpc1N0cmVhbTpwdCxpc1VSTFNlYXJjaFBhcmFtczpGdCxpc1R5cGVkQXJyYXk6SHQsaXNGaWxlTGlzdDptdCxmb3JFYWNoOlYsbWVyZ2U6UkEsZXh0ZW5kOk50LHRyaW06UnQsc3RyaXBCT006VXQsaW5oZXJpdHM6R3QsdG9GbGF0T2JqZWN0Omt0LGtpbmRPZjpDQSxraW5kT2ZUZXN0OlUsZW5kc1dpdGg6THQsdG9BcnJheTpKdCxmb3JFYWNoRW50cnk6WXQsbWF0Y2hBbGw6YnQsaXNIVE1MRm9ybTpNdCxoYXNPd25Qcm9wZXJ0eTpySSxoYXNPd25Qcm9wOnJJLHJlZHVjZURlc2NyaXB0b3JzOm5JLGZyZWV6ZU1ldGhvZHM6T3QsdG9PYmplY3RTZXQ6VHQsdG9DYW1lbENhc2U6cXQsbm9vcDp4dCx0b0Zpbml0ZU51bWJlcjpQdCxmaW5kS2V5OkNJLGdsb2JhbDpzSSxpc0NvbnRleHREZWZpbmVkOlFJLEFMUEhBQkVUOkVJLGdlbmVyYXRlU3RyaW5nOmp0LGlzU3BlY0NvbXBsaWFudEZvcm06V3QsdG9KU09OT2JqZWN0Olp0LGlzQXN5bmNGbjpWdCxpc1RoZW5hYmxlOlh0fTtmdW5jdGlvbiBLKEEsSSx0LGUsZyl7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPUEsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIixJJiYodGhpcy5jb2RlPUkpLHQmJih0aGlzLmNvbmZpZz10KSxlJiYodGhpcy5yZXF1ZXN0PWUpLGcmJih0aGlzLnJlc3BvbnNlPWcpfUIuaW5oZXJpdHMoSyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOkIudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIGFJPUsucHJvdG90eXBlLGNJPXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goQT0+e2NJW0FdPXt2YWx1ZTpBfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEssY0kpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShhSSwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtLLmZyb209KEEsSSx0LGUsZyxyKT0+e2xldCBpPU9iamVjdC5jcmVhdGUoYUkpO3JldHVybiBCLnRvRmxhdE9iamVjdChBLGksZnVuY3Rpb24oYSl7cmV0dXJuIGEhPT1FcnJvci5wcm90b3R5cGV9LHM9PnMhPT0iaXNBeGlvc0Vycm9yIiksSy5jYWxsKGksQS5tZXNzYWdlLEksdCxlLGcpLGkuY2F1c2U9QSxpLm5hbWU9QS5uYW1lLHImJk9iamVjdC5hc3NpZ24oaSxyKSxpfTt2YXIgbD1LO3ZhciBuQT1udWxsO2Z1bmN0aW9uIFVBKEEpe3JldHVybiBCLmlzUGxhaW5PYmplY3QoQSl8fEIuaXNBcnJheShBKX1mdW5jdGlvbiBsSShBKXtyZXR1cm4gQi5lbmRzV2l0aChBLCJbXSIpP0Euc2xpY2UoMCwtMik6QX1mdW5jdGlvbiBmSShBLEksdCl7cmV0dXJuIEE/QS5jb25jYXQoSSkubWFwKGZ1bmN0aW9uKGcscil7cmV0dXJuIGc9bEkoZyksIXQmJnI/IlsiK2crIl0iOmd9KS5qb2luKHQ/Ii4iOiIiKTpJfWZ1bmN0aW9uIHp0KEEpe3JldHVybiBCLmlzQXJyYXkoQSkmJiFBLnNvbWUoVUEpfXZhciBfdD1CLnRvRmxhdE9iamVjdChCLHt9LG51bGwsZnVuY3Rpb24oSSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KEkpfSk7ZnVuY3Rpb24gdnQoQSxJLHQpe2lmKCFCLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO0k9SXx8bmV3KG5BfHxGb3JtRGF0YSksdD1CLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oYyx1KXtyZXR1cm4hQi5pc1VuZGVmaW5lZCh1W2NdKX0pO2xldCBlPXQubWV0YVRva2VucyxnPXQudmlzaXRvcnx8QyxyPXQuZG90cyxpPXQuaW5kZXhlcyxhPSh0LkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJkIuaXNTcGVjQ29tcGxpYW50Rm9ybShJKTtpZighQi5pc0Z1bmN0aW9uKGcpKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gbihFKXtpZihFPT09bnVsbClyZXR1cm4iIjtpZihCLmlzRGF0ZShFKSlyZXR1cm4gRS50b0lTT1N0cmluZygpO2lmKCFhJiZCLmlzQmxvYihFKSl0aHJvdyBuZXcgbCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gQi5pc0FycmF5QnVmZmVyKEUpfHxCLmlzVHlwZWRBcnJheShFKT9hJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbRV0pOkJ1ZmZlci5mcm9tKEUpOkV9ZnVuY3Rpb24gQyhFLGMsdSl7bGV0IGQ9RTtpZihFJiYhdSYmdHlwZW9mIEU9PSJvYmplY3QiKXtpZihCLmVuZHNXaXRoKGMsInt9IikpYz1lP2M6Yy5zbGljZSgwLC0yKSxFPUpTT04uc3RyaW5naWZ5KEUpO2Vsc2UgaWYoQi5pc0FycmF5KEUpJiZ6dChFKXx8KEIuaXNGaWxlTGlzdChFKXx8Qi5lbmRzV2l0aChjLCJbXSIpKSYmKGQ9Qi50b0FycmF5KEUpKSlyZXR1cm4gYz1sSShjKSxkLmZvckVhY2goZnVuY3Rpb24oTixJdCl7IShCLmlzVW5kZWZpbmVkKE4pfHxOPT09bnVsbCkmJkkuYXBwZW5kKGk9PT0hMD9mSShbY10sSXQscik6aT09PW51bGw/YzpjKyJbXSIsbihOKSl9KSwhMX1yZXR1cm4gVUEoRSk/ITA6KEkuYXBwZW5kKGZJKHUsYyxyKSxuKEUpKSwhMSl9bGV0IG89W10sZj1PYmplY3QuYXNzaWduKF90LHtkZWZhdWx0VmlzaXRvcjpDLGNvbnZlcnRWYWx1ZTpuLGlzVmlzaXRhYmxlOlVBfSk7ZnVuY3Rpb24gUShFLGMpe2lmKCFCLmlzVW5kZWZpbmVkKEUpKXtpZihvLmluZGV4T2YoRSkhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrYy5qb2luKCIuIikpO28ucHVzaChFKSxCLmZvckVhY2goRSxmdW5jdGlvbihkLFIpeyghKEIuaXNVbmRlZmluZWQoZCl8fGQ9PT1udWxsKSYmZy5jYWxsKEksZCxCLmlzU3RyaW5nKFIpP1IudHJpbSgpOlIsYyxmKSk9PT0hMCYmUShkLGM/Yy5jb25jYXQoUik6W1JdKX0pLG8ucG9wKCl9fWlmKCFCLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gUShBKSxJfXZhciBMPXZ0O2Z1bmN0aW9uIERJKEEpe2xldCBJPXsiISI6IiUyNTIxIiwiXCciOiIlMjUyNyIsIigiOiIlMjUyOCIsIikiOiIlMjUyOSIsIn4iOiIlMjU3RSIsIiUyNTIwIjoiKyIsIiUyNTAwIjoiXFwwIn07cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC9bIVwnKCl+XXwlMjUyMHwlMjUwMC9nLGZ1bmN0aW9uKGUpe3JldHVybiBJW2VdfSl9ZnVuY3Rpb24gdUkoQSxJKXt0aGlzLl9wYWlycz1bXSxBJiZMKEEsdGhpcyxJKX12YXIgaEk9dUkucHJvdG90eXBlO2hJLmFwcGVuZD1mdW5jdGlvbihJLHQpe3RoaXMuX3BhaXJzLnB1c2goW0ksdF0pfTtoSS50b1N0cmluZz1mdW5jdGlvbihJKXtsZXQgdD1JP2Z1bmN0aW9uKGUpe3JldHVybiBJLmNhbGwodGhpcyxlLERJKX06REk7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihnKXtyZXR1cm4gdChnWzBdKSsiPSIrdChnWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIEVBPXVJO2Z1bmN0aW9uICR0KEEpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvJTI1M0EvZ2ksIjoiKS5yZXBsYWNlKC8lMjUyNC9nLCIkIikucmVwbGFjZSgvJTI1MkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjUyMC9nLCIrIikucmVwbGFjZSgvJTI1NUIvZ2ksIlsiKS5yZXBsYWNlKC8lMjU1RC9naSwiXSIpfWZ1bmN0aW9uIFgoQSxJLHQpe2lmKCFJKXJldHVybiBBO2xldCBlPXQmJnQuZW5jb2RlfHwkdCxnPXQmJnQuc2VyaWFsaXplLHI7aWYoZz9yPWcoSSx0KTpyPUIuaXNVUkxTZWFyY2hQYXJhbXMoSSk/SS50b1N0cmluZygpOm5ldyBFQShJLHQpLnRvU3RyaW5nKGUpLHIpe2xldCBpPUEuaW5kZXhPZigiJTIzIik7aSE9PS0xJiYoQT1BLnNsaWNlKDAsaSkpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK3J9cmV0dXJuIEF9dmFyIEdBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoSSx0LGUpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDpJLHJlamVjdGVkOnQsc3luY2hyb25vdXM6ZT9lLnN5bmNocm9ub3VzOiExLHJ1bldoZW46ZT9lLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoSSl7dGhpcy5oYW5kbGVyc1tJXSYmKHRoaXMuaGFuZGxlcnNbSV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChJKXtCLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihlKXtlIT09bnVsbCYmSShlKX0pfX0sa0E9R0E7dmFyIGFBPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIgZEk9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOkVBO3ZhciB5ST10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIHdJPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIG1JPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOmRJLEZvcm1EYXRhOnlJLEJsb2I6d0l9LHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTt2YXIgTEE9e307ZXQoTEEse2hhc0Jyb3dzZXJFbnY6KCk9PnBJLGhhc1N0YW5kYXJkQnJvd3NlckVudjooKT0+QWUsaGFzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52OigpPT5JZX0pO3ZhciBwST10eXBlb2Ygd2luZG93PCJ1IiYmdHlwZW9mIGRvY3VtZW50PCJ1IixBZT0oQT0+cEkmJlsiUmVhY3ROYXRpdmUiLCJOYXRpdmVTY3JpcHQiLCJOUyJdLmluZGV4T2YoQSk8MCkodHlwZW9mIG5hdmlnYXRvcjwidSImJm5hdmlnYXRvci5wcm9kdWN0KSxJZT10eXBlb2YgV29ya2VyR2xvYmFsU2NvcGU8InUiJiZzZWxmIGluc3RhbmNlb2YgV29ya2VyR2xvYmFsU2NvcGUmJnR5cGVvZiBzZWxmLmltcG9ydFNjcmlwdHM9PSJmdW5jdGlvbiI7dmFyIHc9ey4uLkxBLC4uLm1JfTtmdW5jdGlvbiBKQShBLEkpe3JldHVybiBMKEEsbmV3IHcuY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMsT2JqZWN0LmFzc2lnbih7dmlzaXRvcjpmdW5jdGlvbih0LGUsZyxyKXtyZXR1cm4gdy5pc05vZGUmJkIuaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKGUsdC50b1N0cmluZygiYmFzZTY0IikpLCExKTpyLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19LEkpKX1mdW5jdGlvbiB0ZShBKXtyZXR1cm4gQi5tYXRjaEFsbCgvXFx3K3xcXFsoXFx3KildL2csQSkubWFwKEk9PklbMF09PT0iW10iPyIiOklbMV18fElbMF0pfWZ1bmN0aW9uIGVlKEEpe2xldCBJPXt9LHQ9T2JqZWN0LmtleXMoQSksZSxnPXQubGVuZ3RoLHI7Zm9yKGU9MDtlPGc7ZSsrKXI9dFtlXSxJW3JdPUFbcl07cmV0dXJuIEl9ZnVuY3Rpb24gZ2UoQSl7ZnVuY3Rpb24gSSh0LGUsZyxyKXtsZXQgaT10W3IrK10scz1OdW1iZXIuaXNGaW5pdGUoK2kpLGE9cj49dC5sZW5ndGg7cmV0dXJuIGk9IWkmJkIuaXNBcnJheShnKT9nLmxlbmd0aDppLGE/KEIuaGFzT3duUHJvcChnLGkpP2dbaV09W2dbaV0sZV06Z1tpXT1lLCFzKTooKCFnW2ldfHwhQi5pc09iamVjdChnW2ldKSkmJihnW2ldPVtdKSxJKHQsZSxnW2ldLHIpJiZCLmlzQXJyYXkoZ1tpXSkmJihnW2ldPWVlKGdbaV0pKSwhcyl9aWYoQi5pc0Zvcm1EYXRhKEEpJiZCLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIEIuZm9yRWFjaEVudHJ5KEEsKGUsZyk9PntJKHRlKGUpLGcsdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIGNBPWdlO2Z1bmN0aW9uIHJlKEEsSSx0KXtpZihCLmlzU3RyaW5nKEEpKXRyeXtyZXR1cm4oSXx8SlNPTi5wYXJzZSkoQSksQi50cmltKEEpfWNhdGNoKGUpe2lmKGUubmFtZSE9PSJTeW50YXhFcnJvciIpdGhyb3cgZX1yZXR1cm4odHx8SlNPTi5zdHJpbmdpZnkpKEEpfXZhciBIQT17dHJhbnNpdGlvbmFsOmFBLGFkYXB0ZXI6WyJ4aHIiLCJodHRwIl0sdHJhbnNmb3JtUmVxdWVzdDpbZnVuY3Rpb24oSSx0KXtsZXQgZT10LmdldENvbnRlbnRUeXBlKCl8fCIiLGc9ZS5pbmRleE9mKCJhcHBsaWNhdGlvbi9qc29uIik+LTEscj1CLmlzT2JqZWN0KEkpO2lmKHImJkIuaXNIVE1MRm9ybShJKSYmKEk9bmV3IEZvcm1EYXRhKEkpKSxCLmlzRm9ybURhdGEoSSkpcmV0dXJuIGcmJmc/SlNPTi5zdHJpbmdpZnkoY0EoSSkpOkk7aWYoQi5pc0FycmF5QnVmZmVyKEkpfHxCLmlzQnVmZmVyKEkpfHxCLmlzU3RyZWFtKEkpfHxCLmlzRmlsZShJKXx8Qi5pc0Jsb2IoSSkpcmV0dXJuIEk7aWYoQi5pc0FycmF5QnVmZmVyVmlldyhJKSlyZXR1cm4gSS5idWZmZXI7aWYoQi5pc1VSTFNlYXJjaFBhcmFtcyhJKSlyZXR1cm4gdC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkO2NoYXJzZXQ9dXRmLTgiLCExKSxJLnRvU3RyaW5nKCk7bGV0IHM7aWYocil7aWYoZS5pbmRleE9mKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiKT4tMSlyZXR1cm4gSkEoSSx0aGlzLmZvcm1TZXJpYWxpemVyKS50b1N0cmluZygpO2lmKChzPUIuaXNGaWxlTGlzdChJKSl8fGUuaW5kZXhPZigibXVsdGlwYXJ0L2Zvcm0tZGF0YSIpPi0xKXtsZXQgYT10aGlzLmVudiYmdGhpcy5lbnYuRm9ybURhdGE7cmV0dXJuIEwocz97ImZpbGVzW10iOkl9OkksYSYmbmV3IGEsdGhpcy5mb3JtU2VyaWFsaXplcil9fXJldHVybiByfHxnPyh0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi9qc29uIiwhMSkscmUoSSkpOkl9XSx0cmFuc2Zvcm1SZXNwb25zZTpbZnVuY3Rpb24oSSl7bGV0IHQ9dGhpcy50cmFuc2l0aW9uYWx8fEhBLnRyYW5zaXRpb25hbCxlPXQmJnQuZm9yY2VkSlNPTlBhcnNpbmcsZz10aGlzLnJlc3BvbnNlVHlwZT09PSJqc29uIjtpZihJJiZCLmlzU3RyaW5nKEkpJiYoZSYmIXRoaXMucmVzcG9uc2VUeXBlfHxnKSl7bGV0IGk9ISh0JiZ0LnNpbGVudEpTT05QYXJzaW5nKSYmZzt0cnl7cmV0dXJuIEpTT04ucGFyc2UoSSl9Y2F0Y2gocyl7aWYoaSl0aHJvdyBzLm5hbWU9PT0iU3ludGF4RXJyb3IiP2wuZnJvbShzLGwuRVJSX0JBRF9SRVNQT05TRSx0aGlzLG51bGwsdGhpcy5yZXNwb25zZSk6c319cmV0dXJuIEl9XSx0aW1lb3V0OjAseHNyZkNvb2tpZU5hbWU6IlhTUkYtVE9LRU4iLHhzcmZIZWFkZXJOYW1lOiJYLVhTUkYtVE9LRU4iLG1heENvbnRlbnRMZW5ndGg6LTEsbWF4Qm9keUxlbmd0aDotMSxlbnY6e0Zvcm1EYXRhOncuY2xhc3Nlcy5Gb3JtRGF0YSxCbG9iOncuY2xhc3Nlcy5CbG9ifSx2YWxpZGF0ZVN0YXR1czpmdW5jdGlvbihJKXtyZXR1cm4gST49MjAwJiZJPDMwMH0saGVhZGVyczp7Y29tbW9uOntBY2NlcHQ6ImFwcGxpY2F0aW9uL2pzb24sIHRleHQvcGxhaW4sICovKiIsIkNvbnRlbnQtVHlwZSI6dm9pZCAwfX19O0IuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJwb3N0IiwicHV0IiwicGF0Y2giXSxBPT57SEEuaGVhZGVyc1tBXT17fX0pO3ZhciBPPUhBO3ZhciBpZT1CLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLFNJPUE9PntsZXQgST17fSx0LGUsZztyZXR1cm4gQSYmQS5zcGxpdChgJTBBYCkuZm9yRWFjaChmdW5jdGlvbihpKXtnPWkuaW5kZXhPZigiOiIpLHQ9aS5zdWJzdHJpbmcoMCxnKS50cmltKCkudG9Mb3dlckNhc2UoKSxlPWkuc3Vic3RyaW5nKGcrMSkudHJpbSgpLCEoIXR8fElbdF0mJmllW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/SVt0XT9JW3RdLnB1c2goZSk6SVt0XT1bZV06SVt0XT1JW3RdP0lbdF0rIiwgIitlOmUpfSksSX07dmFyIEZJPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24geihBKXtyZXR1cm4gQSYmU3RyaW5nKEEpLnRyaW0oKS50b0xvd2VyQ2FzZSgpfWZ1bmN0aW9uIGZBKEEpe3JldHVybiBBPT09ITF8fEE9PW51bGw/QTpCLmlzQXJyYXkoQSk/QS5tYXAoZkEpOlN0cmluZyhBKX1mdW5jdGlvbiBvZShBKXtsZXQgST1PYmplY3QuY3JlYXRlKG51bGwpLHQ9LyhbXlxccyw7PV0rKVxccyooPzo9XFxzKihbXiw7XSspKT8vZyxlO2Zvcig7ZT10LmV4ZWMoQSk7KUlbZVsxXV09ZVsyXTtyZXR1cm4gSX12YXIgQmU9QT0+L15bLV9hLXpBLVowLTleYHx+LCElMjMkJSZcJyorLl0rJC8udGVzdChBLnRyaW0oKSk7ZnVuY3Rpb24gWUEoQSxJLHQsZSxnKXtpZihCLmlzRnVuY3Rpb24oZSkpcmV0dXJuIGUuY2FsbCh0aGlzLEksdCk7aWYoZyYmKEk9dCksISFCLmlzU3RyaW5nKEkpKXtpZihCLmlzU3RyaW5nKGUpKXJldHVybiBJLmluZGV4T2YoZSkhPT0tMTtpZihCLmlzUmVnRXhwKGUpKXJldHVybiBlLnRlc3QoSSl9fWZ1bmN0aW9uIENlKEEpe3JldHVybiBBLnRyaW0oKS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoLyhbYS16XFxkXSkoXFx3KikvZywoSSx0LGUpPT50LnRvVXBwZXJDYXNlKCkrZSl9ZnVuY3Rpb24gc2UoQSxJKXtsZXQgdD1CLnRvQ2FtZWxDYXNlKCIgIitJKTtbImdldCIsInNldCIsImhhcyJdLmZvckVhY2goZT0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLGUrdCx7dmFsdWU6ZnVuY3Rpb24oZyxyLGkpe3JldHVybiB0aGlzW2VdLmNhbGwodGhpcyxJLGcscixpKX0sY29uZmlndXJhYmxlOiEwfSl9KX12YXIgVD1jbGFzc3tjb25zdHJ1Y3RvcihJKXtJJiZ0aGlzLnNldChJKX1zZXQoSSx0LGUpe2xldCBnPXRoaXM7ZnVuY3Rpb24gcihzLGEsbil7bGV0IEM9eihhKTtpZighQyl0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IG89Qi5maW5kS2V5KGcsQyk7KCFvfHxnW29dPT09dm9pZCAwfHxuPT09ITB8fG49PT12b2lkIDAmJmdbb10hPT0hMSkmJihnW298fGFdPWZBKHMpKX1sZXQgaT0ocyxhKT0+Qi5mb3JFYWNoKHMsKG4sQyk9PnIobixDLGEpKTtyZXR1cm4gQi5pc1BsYWluT2JqZWN0KEkpfHxJIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9pKEksdCk6Qi5pc1N0cmluZyhJKSYmKEk9SS50cmltKCkpJiYhQmUoSSk/aShTSShJKSx0KTpJIT1udWxsJiZyKHQsSSxlKSx0aGlzfWdldChJLHQpe2lmKEk9eihJKSxJKXtsZXQgZT1CLmZpbmRLZXkodGhpcyxJKTtpZihlKXtsZXQgZz10aGlzW2VdO2lmKCF0KXJldHVybiBnO2lmKHQ9PT0hMClyZXR1cm4gb2UoZyk7aWYoQi5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxnLGUpO2lmKEIuaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhnKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKEksdCl7aWYoST16KEkpLEkpe2xldCBlPUIuZmluZEtleSh0aGlzLEkpO3JldHVybiEhKGUmJnRoaXNbZV0hPT12b2lkIDAmJighdHx8WUEodGhpcyx0aGlzW2VdLGUsdCkpKX1yZXR1cm4hMX1kZWxldGUoSSx0KXtsZXQgZT10aGlzLGc9ITE7ZnVuY3Rpb24gcihpKXtpZihpPXooaSksaSl7bGV0IHM9Qi5maW5kS2V5KGUsaSk7cyYmKCF0fHxZQShlLGVbc10scyx0KSkmJihkZWxldGUgZVtzXSxnPSEwKX19cmV0dXJuIEIuaXNBcnJheShJKT9JLmZvckVhY2gocik6cihJKSxnfWNsZWFyKEkpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLGU9dC5sZW5ndGgsZz0hMTtmb3IoO2UtLTspe2xldCByPXRbZV07KCFJfHxZQSh0aGlzLHRoaXNbcl0scixJLCEwKSkmJihkZWxldGUgdGhpc1tyXSxnPSEwKX1yZXR1cm4gZ31ub3JtYWxpemUoSSl7bGV0IHQ9dGhpcyxlPXt9O3JldHVybiBCLmZvckVhY2godGhpcywoZyxyKT0+e2xldCBpPUIuZmluZEtleShlLHIpO2lmKGkpe3RbaV09ZkEoZyksZGVsZXRlIHRbcl07cmV0dXJufWxldCBzPUk/Q2Uocik6U3RyaW5nKHIpLnRyaW0oKTtzIT09ciYmZGVsZXRlIHRbcl0sdFtzXT1mQShnKSxlW3NdPSEwfSksdGhpc31jb25jYXQoLi4uSSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uSSl9dG9KU09OKEkpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIEIuZm9yRWFjaCh0aGlzLChlLGcpPT57ZSE9bnVsbCYmZSE9PSExJiYodFtnXT1JJiZCLmlzQXJyYXkoZSk/ZS5qb2luKCIsICIpOmUpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbSSx0XSk9PkkrIjogIit0KS5qb2luKGAlMEFgKX1nZXRbU3ltYm9sLnRvU3RyaW5nVGFnXSgpe3JldHVybiJBeGlvc0hlYWRlcnMifXN0YXRpYyBmcm9tKEkpe3JldHVybiBJIGluc3RhbmNlb2YgdGhpcz9JOm5ldyB0aGlzKEkpfXN0YXRpYyBjb25jYXQoSSwuLi50KXtsZXQgZT1uZXcgdGhpcyhJKTtyZXR1cm4gdC5mb3JFYWNoKGc9PmUuc2V0KGcpKSxlfXN0YXRpYyBhY2Nlc3NvcihJKXtsZXQgZT0odGhpc1tGSV09dGhpc1tGSV09e2FjY2Vzc29yczp7fX0pLmFjY2Vzc29ycyxnPXRoaXMucHJvdG90eXBlO2Z1bmN0aW9uIHIoaSl7bGV0IHM9eihpKTtlW3NdfHwoc2UoZyxpKSxlW3NdPSEwKX1yZXR1cm4gQi5pc0FycmF5KEkpP0kuZm9yRWFjaChyKTpyKEkpLHRoaXN9fTtULmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtCLnJlZHVjZURlc2NyaXB0b3JzKFQucHJvdG90eXBlLCh7dmFsdWU6QX0sSSk9PntsZXQgdD1JWzBdLnRvVXBwZXJDYXNlKCkrSS5zbGljZSgxKTtyZXR1cm57Z2V0OigpPT5BLHNldChlKXt0aGlzW3RdPWV9fX0pO0IuZnJlZXplTWV0aG9kcyhUKTt2YXIgbT1UO2Z1bmN0aW9uIF8oQSxJKXtsZXQgdD10aGlzfHxPLGU9SXx8dCxnPW0uZnJvbShlLmhlYWRlcnMpLHI9ZS5kYXRhO3JldHVybiBCLmZvckVhY2goQSxmdW5jdGlvbihzKXtyPXMuY2FsbCh0LHIsZy5ub3JtYWxpemUoKSxJP0kuc3RhdHVzOnZvaWQgMCl9KSxnLm5vcm1hbGl6ZSgpLHJ9ZnVuY3Rpb24gdihBKXtyZXR1cm4hIShBJiZBLl9fQ0FOQ0VMX18pfWZ1bmN0aW9uIFJJKEEsSSx0KXtsLmNhbGwodGhpcyxBPz8iY2FuY2VsZWQiLGwuRVJSX0NBTkNFTEVELEksdCksdGhpcy5uYW1lPSJDYW5jZWxlZEVycm9yIn1CLmluaGVyaXRzKFJJLGwse19fQ0FOQ0VMX186ITB9KTt2YXIgSj1SSTtmdW5jdGlvbiBiQShBLEksdCl7bGV0IGU9dC5jb25maWcudmFsaWRhdGVTdGF0dXM7IXQuc3RhdHVzfHwhZXx8ZSh0LnN0YXR1cyk/QSh0KTpJKG5ldyBsKCJSZXF1ZXN0IGZhaWxlZCB3aXRoIHN0YXR1cyBjb2RlICIrdC5zdGF0dXMsW2wuRVJSX0JBRF9SRVFVRVNULGwuRVJSX0JBRF9SRVNQT05TRV1bTWF0aC5mbG9vcih0LnN0YXR1cy8xMDApLTRdLHQuY29uZmlnLHQucmVxdWVzdCx0KSl9dmFyIE5JPXcuaGFzU3RhbmRhcmRCcm93c2VyRW52P3t3cml0ZShBLEksdCxlLGcscil7bGV0IGk9W0ErIj0iK2VuY29kZVVSSUNvbXBvbmVudChJKV07Qi5pc051bWJlcih0KSYmaS5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUodCkudG9HTVRTdHJpbmcoKSksQi5pc1N0cmluZyhlKSYmaS5wdXNoKCJwYXRoPSIrZSksQi5pc1N0cmluZyhnKSYmaS5wdXNoKCJkb21haW49IitnKSxyPT09ITAmJmkucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPWkuam9pbigiOyAiKX0scmVhZChBKXtsZXQgST1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xcXFxzKikoIitBKyIpPShbXjtdKikiKSk7cmV0dXJuIEk/ZGVjb2RlVVJJQ29tcG9uZW50KElbM10pOm51bGx9LHJlbW92ZShBKXt0aGlzLndyaXRlKEEsIiIsRGF0ZS5ub3coKS04NjRlNSl9fTp7d3JpdGUoKXt9LHJlYWQoKXtyZXR1cm4gbnVsbH0scmVtb3ZlKCl7fX07ZnVuY3Rpb24gTUEoQSl7cmV0dXJuL14oW2Etel1bYS16XFxkK1xcLS5dKjopP1xcL1xcLy9pLnRlc3QoQSl9ZnVuY3Rpb24gcUEoQSxJKXtyZXR1cm4gST9BLnJlcGxhY2UoL1xcLyskLywiIikrIi8iK0kucmVwbGFjZSgvXlxcLysvLCIiKTpBfWZ1bmN0aW9uICQoQSxJKXtyZXR1cm4gQSYmIU1BKEkpP3FBKEEsSSk6SX12YXIgVUk9dy5oYXNTdGFuZGFyZEJyb3dzZXJFbnY/ZnVuY3Rpb24oKXtsZXQgST0vKG1zaWV8dHJpZGVudCkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpLHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYSIpLGU7ZnVuY3Rpb24gZyhyKXtsZXQgaT1yO3JldHVybiBJJiYodC5zZXRBdHRyaWJ1dGUoImhyZWYiLGkpLGk9dC5ocmVmKSx0LnNldEF0dHJpYnV0ZSgiaHJlZiIsaSkse2hyZWY6dC5ocmVmLHByb3RvY29sOnQucHJvdG9jb2w/dC5wcm90b2NvbC5yZXBsYWNlKC86JC8sIiIpOiIiLGhvc3Q6dC5ob3N0LHNlYXJjaDp0LnNlYXJjaD90LnNlYXJjaC5yZXBsYWNlKC9eXFw/LywiIik6IiIsaGFzaDp0Lmhhc2g/dC5oYXNoLnJlcGxhY2UoL14lMjMvLCIiKToiIixob3N0bmFtZTp0Lmhvc3RuYW1lLHBvcnQ6dC5wb3J0LHBhdGhuYW1lOnQucGF0aG5hbWUuY2hhckF0KDApPT09Ii8iP3QucGF0aG5hbWU6Ii8iK3QucGF0aG5hbWV9fXJldHVybiBlPWcod2luZG93LmxvY2F0aW9uLmhyZWYpLGZ1bmN0aW9uKGkpe2xldCBzPUIuaXNTdHJpbmcoaSk/ZyhpKTppO3JldHVybiBzLnByb3RvY29sPT09ZS5wcm90b2NvbCYmcy5ob3N0PT09ZS5ob3N0fX0oKTpmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiEwfX0oKTtmdW5jdGlvbiBLQShBKXtsZXQgST0vXihbLStcXHddezEsMjV9KSg6P1xcL1xcL3w6KS8uZXhlYyhBKTtyZXR1cm4gSSYmSVsxXXx8IiJ9ZnVuY3Rpb24gUWUoQSxJKXtBPUF8fDEwO2xldCB0PW5ldyBBcnJheShBKSxlPW5ldyBBcnJheShBKSxnPTAscj0wLGk7cmV0dXJuIEk9SSE9PXZvaWQgMD9JOjFlMyxmdW5jdGlvbihhKXtsZXQgbj1EYXRlLm5vdygpLEM9ZVtyXTtpfHwoaT1uKSx0W2ddPWEsZVtnXT1uO2xldCBvPXIsZj0wO2Zvcig7byE9PWc7KWYrPXRbbysrXSxvPW8lQTtpZihnPShnKzEpJUEsZz09PXImJihyPShyKzEpJUEpLG4taTxJKXJldHVybjtsZXQgUT1DJiZuLUM7cmV0dXJuIFE/TWF0aC5yb3VuZChmKjFlMy9RKTp2b2lkIDB9fXZhciBHST1RZTtmdW5jdGlvbiBrSShBLEkpe2xldCB0PTAsZT1HSSg1MCwyNTApO3JldHVybiBnPT57bGV0IHI9Zy5sb2FkZWQsaT1nLmxlbmd0aENvbXB1dGFibGU/Zy50b3RhbDp2b2lkIDAscz1yLXQsYT1lKHMpLG49cjw9aTt0PXI7bGV0IEM9e2xvYWRlZDpyLHRvdGFsOmkscHJvZ3Jlc3M6aT9yL2k6dm9pZCAwLGJ5dGVzOnMscmF0ZTphfHx2b2lkIDAsZXN0aW1hdGVkOmEmJmkmJm4/KGktcikvYTp2b2lkIDAsZXZlbnQ6Z307Q1tJPyJkb3dubG9hZCI6InVwbG9hZCJdPSEwLEEoQyl9fXZhciBuZT10eXBlb2YgWE1MSHR0cFJlcXVlc3Q8InUiLExJPW5lJiZmdW5jdGlvbihBKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24odCxlKXtsZXQgZz1BLmRhdGEscj1tLmZyb20oQS5oZWFkZXJzKS5ub3JtYWxpemUoKSx7cmVzcG9uc2VUeXBlOmksd2l0aFhTUkZUb2tlbjpzfT1BLGE7ZnVuY3Rpb24gbigpe0EuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udW5zdWJzY3JpYmUoYSksQS5zaWduYWwmJkEuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixhKX1sZXQgQztpZihCLmlzRm9ybURhdGEoZykpe2lmKHcuaGFzU3RhbmRhcmRCcm93c2VyRW52fHx3Lmhhc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudilyLnNldENvbnRlbnRUeXBlKCExKTtlbHNlIGlmKChDPXIuZ2V0Q29udGVudFR5cGUoKSkhPT0hMSl7bGV0W2MsLi4udV09Qz9DLnNwbGl0KCI7IikubWFwKGQ9PmQudHJpbSgpKS5maWx0ZXIoQm9vbGVhbik6W107ci5zZXRDb250ZW50VHlwZShbY3x8Im11bHRpcGFydC9mb3JtLWRhdGEiLC4uLnVdLmpvaW4oIjsgIikpfX1sZXQgbz1uZXcgWE1MSHR0cFJlcXVlc3Q7aWYoQS5hdXRoKXtsZXQgYz1BLmF1dGgudXNlcm5hbWV8fCIiLHU9QS5hdXRoLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChBLmF1dGgucGFzc3dvcmQpKToiIjtyLnNldCgiQXV0aG9yaXphdGlvbiIsIkJhc2ljICIrYnRvYShjKyI6Iit1KSl9bGV0IGY9JChBLmJhc2VVUkwsQS51cmwpO28ub3BlbihBLm1ldGhvZC50b1VwcGVyQ2FzZSgpLFgoZixBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIFEoKXtpZighbylyZXR1cm47bGV0IGM9bS5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksZD17ZGF0YTohaXx8aT09PSJ0ZXh0Inx8aT09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOmMsY29uZmlnOkEscmVxdWVzdDpvfTtiQShmdW5jdGlvbihOKXt0KE4pLG4oKX0sZnVuY3Rpb24oTil7ZShOKSxuKCl9LGQpLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9UTpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoUSl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihlKG5ldyBsKCJSZXF1ZXN0IGFib3J0ZWQiLGwuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe2UobmV3IGwoIk5ldHdvcmsgRXJyb3IiLGwuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCB1PUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixkPUEudHJhbnNpdGlvbmFsfHxhQTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJih1PUEudGltZW91dEVycm9yTWVzc2FnZSksZShuZXcgbCh1LGQuY2xhcmlmeVRpbWVvdXRFcnJvcj9sLkVUSU1FRE9VVDpsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LHcuaGFzU3RhbmRhcmRCcm93c2VyRW52JiYocyYmQi5pc0Z1bmN0aW9uKHMpJiYocz1zKEEpKSxzfHxzIT09ITEmJlVJKGYpKSl7bGV0IGM9QS54c3JmSGVhZGVyTmFtZSYmQS54c3JmQ29va2llTmFtZSYmTkkucmVhZChBLnhzcmZDb29raWVOYW1lKTtjJiZyLnNldChBLnhzcmZIZWFkZXJOYW1lLGMpfWc9PT12b2lkIDAmJnIuc2V0Q29udGVudFR5cGUobnVsbCksInNldFJlcXVlc3RIZWFkZXIiaW4gbyYmQi5mb3JFYWNoKHIudG9KU09OKCksZnVuY3Rpb24odSxkKXtvLnNldFJlcXVlc3RIZWFkZXIoZCx1KX0pLEIuaXNVbmRlZmluZWQoQS53aXRoQ3JlZGVudGlhbHMpfHwoby53aXRoQ3JlZGVudGlhbHM9ISFBLndpdGhDcmVkZW50aWFscyksaSYmaSE9PSJqc29uIiYmKG8ucmVzcG9uc2VUeXBlPUEucmVzcG9uc2VUeXBlKSx0eXBlb2YgQS5vbkRvd25sb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJm8uYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLGtJKEEub25Eb3dubG9hZFByb2dyZXNzLCEwKSksdHlwZW9mIEEub25VcGxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby51cGxvYWQmJm8udXBsb2FkLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixrSShBLm9uVXBsb2FkUHJvZ3Jlc3MpKSwoQS5jYW5jZWxUb2tlbnx8QS5zaWduYWwpJiYoYT1jPT57byYmKGUoIWN8fGMudHlwZT9uZXcgSihudWxsLEEsbyk6Yyksby5hYm9ydCgpLG89bnVsbCl9LEEuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4uc3Vic2NyaWJlKGEpLEEuc2lnbmFsJiYoQS5zaWduYWwuYWJvcnRlZD9hKCk6QS5zaWduYWwuYWRkRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGEpKSk7bGV0IEU9S0EoZik7aWYoRSYmdy5wcm90b2NvbHMuaW5kZXhPZihFKT09PS0xKXtlKG5ldyBsKCJVbnN1cHBvcnRlZCBwcm90b2NvbCAiK0UrIjoiLGwuRVJSX0JBRF9SRVFVRVNULEEpKTtyZXR1cm59by5zZW5kKGd8fG51bGwpfSl9O3ZhciBPQT17aHR0cDpuQSx4aHI6TEl9O0IuZm9yRWFjaChPQSwoQSxJKT0+e2lmKEEpe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwibmFtZSIse3ZhbHVlOkl9KX1jYXRjaHt9T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsImFkYXB0ZXJOYW1lIix7dmFsdWU6SX0pfX0pO3ZhciBKST1BPT5gLSAke0F9YCxFZT1BPT5CLmlzRnVuY3Rpb24oQSl8fEE9PT1udWxsfHxBPT09ITEsbEE9e2dldEFkYXB0ZXI6QT0+e0E9Qi5pc0FycmF5KEEpP0E6W0FdO2xldHtsZW5ndGg6SX09QSx0LGUsZz17fTtmb3IobGV0IHI9MDtyPEk7cisrKXt0PUFbcl07bGV0IGk7aWYoZT10LCFFZSh0KSYmKGU9T0FbKGk9U3RyaW5nKHQpKS50b0xvd2VyQ2FzZSgpXSxlPT09dm9pZCAwKSl0aHJvdyBuZXcgbChgVW5rbm93biBhZGFwdGVyIFwnJHtpfVwnYCk7aWYoZSlicmVhaztnW2l8fCIlMjMiK3JdPWV9aWYoIWUpe2xldCByPU9iamVjdC5lbnRyaWVzKGcpLm1hcCgoW3MsYV0pPT5gYWRhcHRlciAke3N9IGArKGE9PT0hMT8iaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZW52aXJvbm1lbnQiOiJpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZCIpKSxpPUk/ci5sZW5ndGg+MT9gc2luY2UgOiUwQWArci5tYXAoSkkpLmpvaW4oYCUwQWApOiIgIitKSShyWzBdKToiYXMgbm8gYWRhcHRlciBzcGVjaWZpZWQiO3Rocm93IG5ldyBsKCJUaGVyZSBpcyBubyBzdWl0YWJsZSBhZGFwdGVyIHRvIGRpc3BhdGNoIHRoZSByZXF1ZXN0ICIraSwiRVJSX05PVF9TVVBQT1JUIil9cmV0dXJuIGV9LGFkYXB0ZXJzOk9BfTtmdW5jdGlvbiBUQShBKXtpZihBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnRocm93SWZSZXF1ZXN0ZWQoKSxBLnNpZ25hbCYmQS5zaWduYWwuYWJvcnRlZCl0aHJvdyBuZXcgSihudWxsLEEpfWZ1bmN0aW9uIERBKEEpe3JldHVybiBUQShBKSxBLmhlYWRlcnM9bS5mcm9tKEEuaGVhZGVycyksQS5kYXRhPV8uY2FsbChBLEEudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKEEubWV0aG9kKSE9PS0xJiZBLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLGxBLmdldEFkYXB0ZXIoQS5hZGFwdGVyfHxPLmFkYXB0ZXIpKEEpLnRoZW4oZnVuY3Rpb24oZSl7cmV0dXJuIFRBKEEpLGUuZGF0YT1fLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLGUpLGUuaGVhZGVycz1tLmZyb20oZS5oZWFkZXJzKSxlfSxmdW5jdGlvbihlKXtyZXR1cm4gdihlKXx8KFRBKEEpLGUmJmUucmVzcG9uc2UmJihlLnJlc3BvbnNlLmRhdGE9Xy5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxlLnJlc3BvbnNlKSxlLnJlc3BvbnNlLmhlYWRlcnM9bS5mcm9tKGUucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChlKX0pfXZhciBIST1BPT5BIGluc3RhbmNlb2YgbT9BLnRvSlNPTigpOkE7ZnVuY3Rpb24gRyhBLEkpe0k9SXx8e307bGV0IHQ9e307ZnVuY3Rpb24gZShuLEMsbyl7cmV0dXJuIEIuaXNQbGFpbk9iamVjdChuKSYmQi5pc1BsYWluT2JqZWN0KEMpP0IubWVyZ2UuY2FsbCh7Y2FzZWxlc3M6b30sbixDKTpCLmlzUGxhaW5PYmplY3QoQyk/Qi5tZXJnZSh7fSxDKTpCLmlzQXJyYXkoQyk/Qy5zbGljZSgpOkN9ZnVuY3Rpb24gZyhuLEMsbyl7aWYoQi5pc1VuZGVmaW5lZChDKSl7aWYoIUIuaXNVbmRlZmluZWQobikpcmV0dXJuIGUodm9pZCAwLG4sbyl9ZWxzZSByZXR1cm4gZShuLEMsbyl9ZnVuY3Rpb24gcihuLEMpe2lmKCFCLmlzVW5kZWZpbmVkKEMpKXJldHVybiBlKHZvaWQgMCxDKX1mdW5jdGlvbiBpKG4sQyl7aWYoQi5pc1VuZGVmaW5lZChDKSl7aWYoIUIuaXNVbmRlZmluZWQobikpcmV0dXJuIGUodm9pZCAwLG4pfWVsc2UgcmV0dXJuIGUodm9pZCAwLEMpfWZ1bmN0aW9uIHMobixDLG8pe2lmKG8gaW4gSSlyZXR1cm4gZShuLEMpO2lmKG8gaW4gQSlyZXR1cm4gZSh2b2lkIDAsbil9bGV0IGE9e3VybDpyLG1ldGhvZDpyLGRhdGE6cixiYXNlVVJMOmksdHJhbnNmb3JtUmVxdWVzdDppLHRyYW5zZm9ybVJlc3BvbnNlOmkscGFyYW1zU2VyaWFsaXplcjppLHRpbWVvdXQ6aSx0aW1lb3V0TWVzc2FnZTppLHdpdGhDcmVkZW50aWFsczppLHdpdGhYU1JGVG9rZW46aSxhZGFwdGVyOmkscmVzcG9uc2VUeXBlOmkseHNyZkNvb2tpZU5hbWU6aSx4c3JmSGVhZGVyTmFtZTppLG9uVXBsb2FkUHJvZ3Jlc3M6aSxvbkRvd25sb2FkUHJvZ3Jlc3M6aSxkZWNvbXByZXNzOmksbWF4Q29udGVudExlbmd0aDppLG1heEJvZHlMZW5ndGg6aSxiZWZvcmVSZWRpcmVjdDppLHRyYW5zcG9ydDppLGh0dHBBZ2VudDppLGh0dHBzQWdlbnQ6aSxjYW5jZWxUb2tlbjppLHNvY2tldFBhdGg6aSxyZXNwb25zZUVuY29kaW5nOmksdmFsaWRhdGVTdGF0dXM6cyxoZWFkZXJzOihuLEMpPT5nKEhJKG4pLEhJKEMpLCEwKX07cmV0dXJuIEIuZm9yRWFjaChPYmplY3Qua2V5cyhPYmplY3QuYXNzaWduKHt9LEEsSSkpLGZ1bmN0aW9uKEMpe2xldCBvPWFbQ118fGcsZj1vKEFbQ10sSVtDXSxDKTtCLmlzVW5kZWZpbmVkKGYpJiZvIT09c3x8KHRbQ109Zil9KSx0fXZhciB1QT0iMS42LjIiO3ZhciB4QT17fTtbIm9iamVjdCIsImJvb2xlYW4iLCJudW1iZXIiLCJmdW5jdGlvbiIsInN0cmluZyIsInN5bWJvbCJdLmZvckVhY2goKEEsSSk9Pnt4QVtBXT1mdW5jdGlvbihlKXtyZXR1cm4gdHlwZW9mIGU9PT1BfHwiYSIrKEk8MT8ibiAiOiIgIikrQX19KTt2YXIgWUk9e307eEEudHJhbnNpdGlvbmFsPWZ1bmN0aW9uKEksdCxlKXtmdW5jdGlvbiBnKHIsaSl7cmV0dXJuIltBeGlvcyB2Iit1QSsiXSBUcmFuc2l0aW9uYWwgb3B0aW9uIFwnIityKyJcJyIraSsoZT8iLiAiK2U6IiIpfXJldHVybihyLGkscyk9PntpZihJPT09ITEpdGhyb3cgbmV3IGwoZyhpLCIgaGFzIGJlZW4gcmVtb3ZlZCIrKHQ/IiBpbiAiK3Q6IiIpKSxsLkVSUl9ERVBSRUNBVEVEKTtyZXR1cm4gdCYmIVlJW2ldJiYoWUlbaV09ITAsY29uc29sZS53YXJuKGcoaSwiIGhhcyBiZWVuIGRlcHJlY2F0ZWQgc2luY2UgdiIrdCsiIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5lYXIgZnV0dXJlIikpKSxJP0kocixpLHMpOiEwfX07ZnVuY3Rpb24gYWUoQSxJLHQpe2lmKHR5cGVvZiBBIT0ib2JqZWN0Iil0aHJvdyBuZXcgbCgib3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdCIsbC5FUlJfQkFEX09QVElPTl9WQUxVRSk7bGV0IGU9T2JqZWN0LmtleXMoQSksZz1lLmxlbmd0aDtmb3IoO2ctLSA+MDspe2xldCByPWVbZ10saT1JW3JdO2lmKGkpe2xldCBzPUFbcl0sYT1zPT09dm9pZCAwfHxpKHMscixBKTtpZihhIT09ITApdGhyb3cgbmV3IGwoIm9wdGlvbiAiK3IrIiBtdXN0IGJlICIrYSxsLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtjb250aW51ZX1pZih0IT09ITApdGhyb3cgbmV3IGwoIlVua25vd24gb3B0aW9uICIrcixsLkVSUl9CQURfT1BUSU9OKX19dmFyIGhBPXthc3NlcnRPcHRpb25zOmFlLHZhbGlkYXRvcnM6eEF9O3ZhciBIPWhBLnZhbGlkYXRvcnMseD1jbGFzc3tjb25zdHJ1Y3RvcihJKXt0aGlzLmRlZmF1bHRzPUksdGhpcy5pbnRlcmNlcHRvcnM9e3JlcXVlc3Q6bmV3IGtBLHJlc3BvbnNlOm5ldyBrQX19cmVxdWVzdChJLHQpe3R5cGVvZiBJPT0ic3RyaW5nIj8odD10fHx7fSx0LnVybD1JKTp0PUl8fHt9LHQ9Ryh0aGlzLmRlZmF1bHRzLHQpO2xldHt0cmFuc2l0aW9uYWw6ZSxwYXJhbXNTZXJpYWxpemVyOmcsaGVhZGVyczpyfT10O2UhPT12b2lkIDAmJmhBLmFzc2VydE9wdGlvbnMoZSx7c2lsZW50SlNPTlBhcnNpbmc6SC50cmFuc2l0aW9uYWwoSC5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzpILnRyYW5zaXRpb25hbChILmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6SC50cmFuc2l0aW9uYWwoSC5ib29sZWFuKX0sITEpLGchPW51bGwmJihCLmlzRnVuY3Rpb24oZyk/dC5wYXJhbXNTZXJpYWxpemVyPXtzZXJpYWxpemU6Z306aEEuYXNzZXJ0T3B0aW9ucyhnLHtlbmNvZGU6SC5mdW5jdGlvbixzZXJpYWxpemU6SC5mdW5jdGlvbn0sITApKSx0Lm1ldGhvZD0odC5tZXRob2R8fHRoaXMuZGVmYXVsdHMubWV0aG9kfHwiZ2V0IikudG9Mb3dlckNhc2UoKTtsZXQgaT1yJiZCLm1lcmdlKHIuY29tbW9uLHJbdC5tZXRob2RdKTtyJiZCLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sRT0+e2RlbGV0ZSByW0VdfSksdC5oZWFkZXJzPW0uY29uY2F0KGkscik7bGV0IHM9W10sYT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oYyl7dHlwZW9mIGMucnVuV2hlbj09ImZ1bmN0aW9uIiYmYy5ydW5XaGVuKHQpPT09ITF8fChhPWEmJmMuc3luY2hyb25vdXMscy51bnNoaWZ0KGMuZnVsZmlsbGVkLGMucmVqZWN0ZWQpKX0pO2xldCBuPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oYyl7bi5wdXNoKGMuZnVsZmlsbGVkLGMucmVqZWN0ZWQpfSk7bGV0IEMsbz0wLGY7aWYoIWEpe2xldCBFPVtEQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKEUudW5zaGlmdC5hcHBseShFLHMpLEUucHVzaC5hcHBseShFLG4pLGY9RS5sZW5ndGgsQz1Qcm9taXNlLnJlc29sdmUodCk7bzxmOylDPUMudGhlbihFW28rK10sRVtvKytdKTtyZXR1cm4gQ31mPXMubGVuZ3RoO2xldCBRPXQ7Zm9yKG89MDtvPGY7KXtsZXQgRT1zW28rK10sYz1zW28rK107dHJ5e1E9RShRKX1jYXRjaCh1KXtjLmNhbGwodGhpcyx1KTticmVha319dHJ5e0M9REEuY2FsbCh0aGlzLFEpfWNhdGNoKEUpe3JldHVybiBQcm9taXNlLnJlamVjdChFKX1mb3Iobz0wLGY9bi5sZW5ndGg7bzxmOylDPUMudGhlbihuW28rK10sbltvKytdKTtyZXR1cm4gQ31nZXRVcmkoSSl7ST1HKHRoaXMuZGVmYXVsdHMsSSk7bGV0IHQ9JChJLmJhc2VVUkwsSS51cmwpO3JldHVybiBYKHQsSS5wYXJhbXMsSS5wYXJhbXNTZXJpYWxpemVyKX19O0IuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJvcHRpb25zIl0sZnVuY3Rpb24oSSl7eC5wcm90b3R5cGVbSV09ZnVuY3Rpb24odCxlKXtyZXR1cm4gdGhpcy5yZXF1ZXN0KEcoZXx8e30se21ldGhvZDpJLHVybDp0LGRhdGE6KGV8fHt9KS5kYXRhfSkpfX0pO0IuZm9yRWFjaChbInBvc3QiLCJwdXQiLCJwYXRjaCJdLGZ1bmN0aW9uKEkpe2Z1bmN0aW9uIHQoZSl7cmV0dXJuIGZ1bmN0aW9uKHIsaSxzKXtyZXR1cm4gdGhpcy5yZXF1ZXN0KEcoc3x8e30se21ldGhvZDpJLGhlYWRlcnM6ZT97IkNvbnRlbnQtVHlwZSI6Im11bHRpcGFydC9mb3JtLWRhdGEifTp7fSx1cmw6cixkYXRhOml9KSl9fXgucHJvdG90eXBlW0ldPXQoKSx4LnByb3RvdHlwZVtJKyJGb3JtIl09dCghMCl9KTt2YXIgQUE9eDt2YXIgUEE9Y2xhc3MgQXtjb25zdHJ1Y3RvcihJKXtpZih0eXBlb2YgSSE9ImZ1bmN0aW9uIil0aHJvdyBuZXcgVHlwZUVycm9yKCJleGVjdXRvciBtdXN0IGJlIGEgZnVuY3Rpb24uIik7bGV0IHQ7dGhpcy5wcm9taXNlPW5ldyBQcm9taXNlKGZ1bmN0aW9uKHIpe3Q9cn0pO2xldCBlPXRoaXM7dGhpcy5wcm9taXNlLnRoZW4oZz0+e2lmKCFlLl9saXN0ZW5lcnMpcmV0dXJuO2xldCByPWUuX2xpc3RlbmVycy5sZW5ndGg7Zm9yKDtyLS0gPjA7KWUuX2xpc3RlbmVyc1tyXShnKTtlLl9saXN0ZW5lcnM9bnVsbH0pLHRoaXMucHJvbWlzZS50aGVuPWc9PntsZXQgcixpPW5ldyBQcm9taXNlKHM9PntlLnN1YnNjcmliZShzKSxyPXN9KS50aGVuKGcpO3JldHVybiBpLmNhbmNlbD1mdW5jdGlvbigpe2UudW5zdWJzY3JpYmUocil9LGl9LEkoZnVuY3Rpb24ocixpLHMpe2UucmVhc29ufHwoZS5yZWFzb249bmV3IEoocixpLHMpLHQoZS5yZWFzb24pKX0pfXRocm93SWZSZXF1ZXN0ZWQoKXtpZih0aGlzLnJlYXNvbil0aHJvdyB0aGlzLnJlYXNvbn1zdWJzY3JpYmUoSSl7aWYodGhpcy5yZWFzb24pe0kodGhpcy5yZWFzb24pO3JldHVybn10aGlzLl9saXN0ZW5lcnM/dGhpcy5fbGlzdGVuZXJzLnB1c2goSSk6dGhpcy5fbGlzdGVuZXJzPVtJXX11bnN1YnNjcmliZShJKXtpZighdGhpcy5fbGlzdGVuZXJzKXJldHVybjtsZXQgdD10aGlzLl9saXN0ZW5lcnMuaW5kZXhPZihJKTt0IT09LTEmJnRoaXMuX2xpc3RlbmVycy5zcGxpY2UodCwxKX1zdGF0aWMgc291cmNlKCl7bGV0IEk7cmV0dXJue3Rva2VuOm5ldyBBKGZ1bmN0aW9uKGcpe0k9Z30pLGNhbmNlbDpJfX19LGJJPVBBO2Z1bmN0aW9uIGpBKEEpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gQS5hcHBseShudWxsLHQpfX1mdW5jdGlvbiBXQShBKXtyZXR1cm4gQi5pc09iamVjdChBKSYmQS5pc0F4aW9zRXJyb3I9PT0hMH12YXIgWkE9e0NvbnRpbnVlOjEwMCxTd2l0Y2hpbmdQcm90b2NvbHM6MTAxLFByb2Nlc3Npbmc6MTAyLEVhcmx5SGludHM6MTAzLE9rOjIwMCxDcmVhdGVkOjIwMSxBY2NlcHRlZDoyMDIsTm9uQXV0aG9yaXRhdGl2ZUluZm9ybWF0aW9uOjIwMyxOb0NvbnRlbnQ6MjA0LFJlc2V0Q29udGVudDoyMDUsUGFydGlhbENvbnRlbnQ6MjA2LE11bHRpU3RhdHVzOjIwNyxBbHJlYWR5UmVwb3J0ZWQ6MjA4LEltVXNlZDoyMjYsTXVsdGlwbGVDaG9pY2VzOjMwMCxNb3ZlZFBlcm1hbmVudGx5OjMwMSxGb3VuZDozMDIsU2VlT3RoZXI6MzAzLE5vdE1vZGlmaWVkOjMwNCxVc2VQcm94eTozMDUsVW51c2VkOjMwNixUZW1wb3JhcnlSZWRpcmVjdDozMDcsUGVybWFuZW50UmVkaXJlY3Q6MzA4LEJhZFJlcXVlc3Q6NDAwLFVuYXV0aG9yaXplZDo0MDEsUGF5bWVudFJlcXVpcmVkOjQwMixGb3JiaWRkZW46NDAzLE5vdEZvdW5kOjQwNCxNZXRob2ROb3RBbGxvd2VkOjQwNSxOb3RBY2NlcHRhYmxlOjQwNixQcm94eUF1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NDA3LFJlcXVlc3RUaW1lb3V0OjQwOCxDb25mbGljdDo0MDksR29uZTo0MTAsTGVuZ3RoUmVxdWlyZWQ6NDExLFByZWNvbmRpdGlvbkZhaWxlZDo0MTIsUGF5bG9hZFRvb0xhcmdlOjQxMyxVcmlUb29Mb25nOjQxNCxVbnN1cHBvcnRlZE1lZGlhVHlwZTo0MTUsUmFuZ2VOb3RTYXRpc2ZpYWJsZTo0MTYsRXhwZWN0YXRpb25GYWlsZWQ6NDE3LEltQVRlYXBvdDo0MTgsTWlzZGlyZWN0ZWRSZXF1ZXN0OjQyMSxVbnByb2Nlc3NhYmxlRW50aXR5OjQyMixMb2NrZWQ6NDIzLEZhaWxlZERlcGVuZGVuY3k6NDI0LFRvb0Vhcmx5OjQyNSxVcGdyYWRlUmVxdWlyZWQ6NDI2LFByZWNvbmRpdGlvblJlcXVpcmVkOjQyOCxUb29NYW55UmVxdWVzdHM6NDI5LFJlcXVlc3RIZWFkZXJGaWVsZHNUb29MYXJnZTo0MzEsVW5hdmFpbGFibGVGb3JMZWdhbFJlYXNvbnM6NDUxLEludGVybmFsU2VydmVyRXJyb3I6NTAwLE5vdEltcGxlbWVudGVkOjUwMSxCYWRHYXRld2F5OjUwMixTZXJ2aWNlVW5hdmFpbGFibGU6NTAzLEdhdGV3YXlUaW1lb3V0OjUwNCxIdHRwVmVyc2lvbk5vdFN1cHBvcnRlZDo1MDUsVmFyaWFudEFsc29OZWdvdGlhdGVzOjUwNixJbnN1ZmZpY2llbnRTdG9yYWdlOjUwNyxMb29wRGV0ZWN0ZWQ6NTA4LE5vdEV4dGVuZGVkOjUxMCxOZXR3b3JrQXV0aGVudGljYXRpb25SZXF1aXJlZDo1MTF9O09iamVjdC5lbnRyaWVzKFpBKS5mb3JFYWNoKChbQSxJXSk9PntaQVtJXT1BfSk7dmFyIE1JPVpBO2Z1bmN0aW9uIHFJKEEpe2xldCBJPW5ldyBBQShBKSx0PVcoQUEucHJvdG90eXBlLnJlcXVlc3QsSSk7cmV0dXJuIEIuZXh0ZW5kKHQsQUEucHJvdG90eXBlLEkse2FsbE93bktleXM6ITB9KSxCLmV4dGVuZCh0LEksbnVsbCx7YWxsT3duS2V5czohMH0pLHQuY3JlYXRlPWZ1bmN0aW9uKGcpe3JldHVybiBxSShHKEEsZykpfSx0fXZhciBoPXFJKE8pO2guQXhpb3M9QUE7aC5DYW5jZWxlZEVycm9yPUo7aC5DYW5jZWxUb2tlbj1iSTtoLmlzQ2FuY2VsPXY7aC5WRVJTSU9OPXVBO2gudG9Gb3JtRGF0YT1MO2guQXhpb3NFcnJvcj1sO2guQ2FuY2VsPWguQ2FuY2VsZWRFcnJvcjtoLmFsbD1mdW5jdGlvbihJKXtyZXR1cm4gUHJvbWlzZS5hbGwoSSl9O2guc3ByZWFkPWpBO2guaXNBeGlvc0Vycm9yPVdBO2gubWVyZ2VDb25maWc9RztoLkF4aW9zSGVhZGVycz1tO2guZm9ybVRvSlNPTj1BPT5jQShCLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO2guZ2V0QWRhcHRlcj1sQS5nZXRBZGFwdGVyO2guSHR0cFN0YXR1c0NvZGU9TUk7aC5kZWZhdWx0PWg7dmFyIGRBPWg7dmFye0F4aW9zOm9pLEF4aW9zRXJyb3I6QmksQ2FuY2VsZWRFcnJvcjpDaSxpc0NhbmNlbDpzaSxDYW5jZWxUb2tlbjpRaSxWRVJTSU9OOm5pLGFsbDpFaSxDYW5jZWw6YWksaXNBeGlvc0Vycm9yOmNpLHNwcmVhZDpmaSx0b0Zvcm1EYXRhOmxpLEF4aW9zSGVhZGVyczpEaSxIdHRwU3RhdHVzQ29kZTp1aSxmb3JtVG9KU09OOmhpLGdldEFkYXB0ZXI6ZGksbWVyZ2VDb25maWc6eWl9PWRBO3ZhciBJQSxrLFhBLFZBPXtlbnY6e2Vtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGg6ZnVuY3Rpb24oQSl7WEE9bmV3IFVpbnQ4QXJyYXkoay5leHBvcnRzLm1lbW9yeS5idWZmZXIpfX19LHlBPWNsYXNze2luaXQoKXtyZXR1cm4gSUF8fCh0eXBlb2YgZmV0Y2g8InUiP0lBPWZldGNoKCJkYXRhOmFwcGxpY2F0aW9uL3dhc207YmFzZTY0LCIrS0kpLnRoZW4oST0+SS5hcnJheUJ1ZmZlcigpKS50aGVuKEk9PldlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKEksVkEpKS50aGVuKHRoaXMuX2luaXQpOklBPVdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKEJ1ZmZlci5mcm9tKEtJLCJiYXNlNjQiKSxWQSkudGhlbih0aGlzLl9pbml0KSxJQSl9X2luaXQoSSl7az1JLmluc3RhbmNlLFZBLmVudi5lbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoKDApfWRlY29kZShJLHQ9MCl7aWYoIWspdGhyb3cgbmV3IEVycm9yKCJaU1RERGVjb2RlcjogQXdhaXQgLmluaXQoKSBiZWZvcmUgZGVjb2RpbmcuIik7bGV0IGU9SS5ieXRlTGVuZ3RoLGc9ay5leHBvcnRzLm1hbGxvYyhlKTtYQS5zZXQoSSxnKSx0PXR8fE51bWJlcihrLmV4cG9ydHMuWlNURF9maW5kRGVjb21wcmVzc2VkU2l6ZShnLGUpKTtsZXQgcj1rLmV4cG9ydHMubWFsbG9jKHQpLGk9ay5leHBvcnRzLlpTVERfZGVjb21wcmVzcyhyLHQsZyxlKSxzPVhBLnNsaWNlKHIscitpKTtyZXR1cm4gay5leHBvcnRzLmZyZWUoZyksay5leHBvcnRzLmZyZWUociksc319LEtJPSJBR0Z6YlFFQUFBQUJiZzVnQTM5L2Z3Ri9ZQUYvQVg5Z0FuOS9BR0FCZndCZ0JYOS9mMzkvQVg5Z0EzOS9md0JnQkg5L2YzOEJmMkFBQVg5Z0FuOS9BWDlnQjM5L2YzOS9mMzhCZjJBQ2YzOEJmbUFJZjM5L2YzOS9mMzhCZjJBRmYzOS9mMzhBWUE1L2YzOS9mMzkvZjM5L2YzOS9md0YvQWljQkEyVnVkaDlsYlhOamNtbHdkR1Z1WDI1dmRHbG1lVjl0WlcxdmNubGZaM0p2ZDNSb0FBTURJeUlIQUFBQkFRTUhBd0VBQ1FRQUJRRUlDQUVGQmdRRUJBTUdBQUFLQUFVTERBMEdCQVVCY0FFQkFRVUhBUUdBQW9DQUFnWUlBWDhCUVlDakJBc0hyZ0VMQm0xbGJXOXllUUlBQm0xaGJHeHZZd0FGQkdaeVpXVUFCZ3hhVTFSRVgybHpSWEp5YjNJQUVobGFVMVJFWDJacGJtUkVaV052YlhCeVpYTnpaV1JUYVhwbEFCd1BXbE5VUkY5a1pXTnZiWEJ5WlhOekFDSVpYMTlwYm1ScGNtVmpkRjltZFc1amRHbHZibDkwWVdKc1pRRUFFRjlmWlhKeWJtOWZiRzlqWVhScGIyNEFBUWx6ZEdGamExTmhkbVVBQnd4emRHRmphMUpsYzNSdmNtVUFDQXB6ZEdGamEwRnNiRzlqQUFrS2kvSUJJZ1VBUVlRZkN6TUJBWDhnQWdSQUlBQWhBd05BSUFNZ0FTMEFBRG9BQUNBRFFRRnFJUU1nQVVFQmFpRUJJQUpCQVdzaUFnMEFDd3NnQUFzcEFRRi9JQUlFUUNBQUlRTURRQ0FESUFFNkFBQWdBMEVCYWlFRElBSkJBV3NpQWcwQUN3c2dBQXRzQVFKL1FZQWZLQUlBSWdFZ0FFRUhha0Y0Y1NJQ2FpRUFBa0FnQWtFQUlBQWdBVTBiRFFBZ0FEOEFRUkIwU3dSQUlBQS9BRUVRZEd0Qi8vOERha0VRZGtBQVFYOUdCSDlCQUFWQkFCQUFRUUVMUlEwQkMwR0FIeUFBTmdJQUlBRVBDMEdFSDBFd05nSUFRWDhMdVNjQkMzOGpBRUVRYXlJS0pBQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFJQUJCOUFGTkJFQkJpQjhvQWdBaUJrRVFJQUJCQzJwQmVIRWdBRUVMU1JzaUJVRURkaUlBZGlJQlFRTnhCRUFDUUNBQlFYOXpRUUZ4SUFCcUlnSkJBM1FpQVVHd0gyb2lBQ0FCUWJnZmFpZ0NBQ0lCS0FJSUlnUkdCRUJCaUI4Z0JrRitJQUozY1RZQ0FBd0JDeUFFSUFBMkFnd2dBQ0FFTmdJSUN5QUJRUWhxSVFBZ0FTQUNRUU4wSWdKQkEzSTJBZ1FnQVNBQ2FpSUJJQUVvQWdSQkFYSTJBZ1FNRHdzZ0JVR1FIeWdDQUNJSFRRMEJJQUVFUUFKQVFRSWdBSFFpQWtFQUlBSnJjaUFCSUFCMGNXZ2lBVUVEZENJQVFiQWZhaUlDSUFCQnVCOXFLQUlBSWdBb0FnZ2lCRVlFUUVHSUh5QUdRWDRnQVhkeElnWTJBZ0FNQVFzZ0JDQUNOZ0lNSUFJZ0JEWUNDQXNnQUNBRlFRTnlOZ0lFSUFBZ0JXb2lDQ0FCUVFOMElnRWdCV3NpQkVFQmNqWUNCQ0FBSUFGcUlBUTJBZ0FnQndSQUlBZEJlSEZCc0I5cUlRRkJuQjhvQWdBaEFnSi9JQVpCQVNBSFFRTjJkQ0lEY1VVRVFFR0lIeUFESUFaeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQXlBQklBSTJBZ2dnQXlBQ05nSU1JQUlnQVRZQ0RDQUNJQU0yQWdnTElBQkJDR29oQUVHY0h5QUlOZ0lBUVpBZklBUTJBZ0FNRHd0QmpCOG9BZ0FpQzBVTkFTQUxhRUVDZEVHNElXb29BZ0FpQWlnQ0JFRjRjU0FGYXlFRElBSWhBUU5BQWtBZ0FTZ0NFQ0lBUlFSQUlBRW9BaFFpQUVVTkFRc2dBQ2dDQkVGNGNTQUZheUlCSUFNZ0FTQURTU0lCR3lFRElBQWdBaUFCR3lFQ0lBQWhBUXdCQ3dzZ0FpZ0NHQ0VKSUFJZ0FpZ0NEQ0lFUndSQVFaZ2ZLQUlBR2lBQ0tBSUlJZ0FnQkRZQ0RDQUVJQUEyQWdnTURnc2dBa0VVYWlJQktBSUFJZ0JGQkVBZ0FpZ0NFQ0lBUlEwRElBSkJFR29oQVFzRFFDQUJJUWdnQUNJRVFSUnFJZ0VvQWdBaUFBMEFJQVJCRUdvaEFTQUVLQUlRSWdBTkFBc2dDRUVBTmdJQURBMExRWDhoQlNBQVFiOS9TdzBBSUFCQkMyb2lBRUY0Y1NFRlFZd2ZLQUlBSWdoRkRRQkJBQ0FGYXlFREFrQUNRQUpBQW45QkFDQUZRWUFDU1EwQUdrRWZJQVZCLy8vL0Iwc05BQm9nQlVFbUlBQkJDSFpuSWdCcmRrRUJjU0FBUVFGMGEwRSthZ3NpQjBFQ2RFRzRJV29vQWdBaUFVVUVRRUVBSVFBTUFRdEJBQ0VBSUFWQkdTQUhRUUYyYTBFQUlBZEJIMGNiZENFQ0EwQUNRQ0FCS0FJRVFYaHhJQVZySWdZZ0EwOE5BQ0FCSVFRZ0JpSUREUUJCQUNFRElBRWhBQXdEQ3lBQUlBRW9BaFFpQmlBR0lBRWdBa0VkZGtFRWNXb29BaEFpQVVZYklBQWdCaHNoQUNBQ1FRRjBJUUlnQVEwQUN3c2dBQ0FFY2tVRVFFRUFJUVJCQWlBSGRDSUFRUUFnQUd0eUlBaHhJZ0JGRFFNZ0FHaEJBblJCdUNGcUtBSUFJUUFMSUFCRkRRRUxBMEFnQUNnQ0JFRjRjU0FGYXlJQ0lBTkpJUUVnQWlBRElBRWJJUU1nQUNBRUlBRWJJUVFnQUNnQ0VDSUJCSDhnQVFVZ0FDZ0NGQXNpQUEwQUN3c2dCRVVOQUNBRFFaQWZLQUlBSUFWclR3MEFJQVFvQWhnaEJ5QUVJQVFvQWd3aUFrY0VRRUdZSHlnQ0FCb2dCQ2dDQ0NJQUlBSTJBZ3dnQWlBQU5nSUlEQXdMSUFSQkZHb2lBU2dDQUNJQVJRUkFJQVFvQWhBaUFFVU5BeUFFUVJCcUlRRUxBMEFnQVNFR0lBQWlBa0VVYWlJQktBSUFJZ0FOQUNBQ1FSQnFJUUVnQWlnQ0VDSUFEUUFMSUFaQkFEWUNBQXdMQ3lBRlFaQWZLQUlBSWdSTkJFQkJuQjhvQWdBaEFBSkFJQVFnQldzaUFVRVFUd1JBSUFBZ0JXb2lBaUFCUVFGeU5nSUVJQUFnQkdvZ0FUWUNBQ0FBSUFWQkEzSTJBZ1FNQVFzZ0FDQUVRUU55TmdJRUlBQWdCR29pQVNBQktBSUVRUUZ5TmdJRVFRQWhBa0VBSVFFTFFaQWZJQUUyQWdCQm5COGdBallDQUNBQVFRaHFJUUFNRFFzZ0JVR1VIeWdDQUNJQ1NRUkFRWlFmSUFJZ0JXc2lBVFlDQUVHZ0gwR2dIeWdDQUNJQUlBVnFJZ0kyQWdBZ0FpQUJRUUZ5TmdJRUlBQWdCVUVEY2pZQ0JDQUFRUWhxSVFBTURRdEJBQ0VBSUFWQkwyb2lBd0ovUWVBaUtBSUFCRUJCNkNJb0FnQU1BUXRCN0NKQ2Z6Y0NBRUhrSWtLQW9JQ0FnSUFFTndJQVFlQWlJQXBCREdwQmNIRkIyS3JWcWdWek5nSUFRZlFpUVFBMkFnQkJ4Q0pCQURZQ0FFR0FJQXNpQVdvaUJrRUFJQUZySWdoeElnRWdCVTBOREVIQUlpZ0NBQ0lFQkVCQnVDSW9BZ0FpQnlBQmFpSUpJQWROSUFRZ0NVbHlEUTBMQWtCQnhDSXRBQUJCQkhGRkJFQUNRQUpBQWtBQ1FFR2dIeWdDQUNJRUJFQkJ5Q0loQUFOQUlBUWdBQ2dDQUNJSFR3UkFJQWNnQUNnQ0JHb2dCRXNOQXdzZ0FDZ0NDQ0lBRFFBTEMwRUFFQVFpQWtGL1JnMERJQUVoQmtIa0lpZ0NBQ0lBUVFGcklnUWdBbkVFUUNBQklBSnJJQUlnQkdwQkFDQUFhM0ZxSVFZTElBVWdCazhOQTBIQUlpZ0NBQ0lBQkVCQnVDSW9BZ0FpQkNBR2FpSUlJQVJOSUFBZ0NFbHlEUVFMSUFZUUJDSUFJQUpIRFFFTUJRc2dCaUFDYXlBSWNTSUdFQVFpQWlBQUtBSUFJQUFvQWdScVJnMEJJQUloQUFzZ0FFRi9SZzBCSUFWQk1Hb2dCazBFUUNBQUlRSU1CQXRCNkNJb0FnQWlBaUFESUFacmFrRUFJQUpyY1NJQ0VBUkJmMFlOQVNBQ0lBWnFJUVlnQUNFQ0RBTUxJQUpCZjBjTkFndEJ4Q0pCeENJb0FnQkJCSEkyQWdBTElBRVFCQ0lDUVg5R1FRQVFCQ0lBUVg5R2NpQUFJQUpOY2cwRklBQWdBbXNpQmlBRlFTaHFUUTBGQzBHNElrRzRJaWdDQUNBR2FpSUFOZ0lBUWJ3aUtBSUFJQUJKQkVCQnZDSWdBRFlDQUFzQ1FFR2dIeWdDQUNJREJFQkJ5Q0loQUFOQUlBSWdBQ2dDQUNJQklBQW9BZ1FpQkdwR0RRSWdBQ2dDQ0NJQURRQUxEQVFMUVpnZktBSUFJZ0JCQUNBQUlBSk5HMFVFUUVHWUh5QUNOZ0lBQzBFQUlRQkJ6Q0lnQmpZQ0FFSElJaUFDTmdJQVFhZ2ZRWDgyQWdCQnJCOUI0Q0lvQWdBMkFnQkIxQ0pCQURZQ0FBTkFJQUJCQTNRaUFVRzRIMm9nQVVHd0gyb2lCRFlDQUNBQlFid2ZhaUFFTmdJQUlBQkJBV29pQUVFZ1J3MEFDMEdVSHlBR1FTaHJJZ0JCZUNBQ2EwRUhjU0lCYXlJRU5nSUFRYUFmSUFFZ0Ftb2lBVFlDQUNBQklBUkJBWEkyQWdRZ0FDQUNha0VvTmdJRVFhUWZRZkFpS0FJQU5nSUFEQVFMSUFJZ0EwMGdBU0FEUzNJTkFpQUFLQUlNUVFoeERRSWdBQ0FFSUFacU5nSUVRYUFmSUFOQmVDQURhMEVIY1NJQWFpSUJOZ0lBUVpRZlFaUWZLQUlBSUFacUlnSWdBR3NpQURZQ0FDQUJJQUJCQVhJMkFnUWdBaUFEYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFNTFFRQWhCQXdLQzBFQUlRSU1DQXRCbUI4b0FnQWdBa3NFUUVHWUh5QUNOZ0lBQ3lBQ0lBWnFJUUZCeUNJaEFBSkFBa0FDUUFOQUlBRWdBQ2dDQUVjRVFDQUFLQUlJSWdBTkFRd0NDd3NnQUMwQURFRUljVVVOQVF0QnlDSWhBQU5BSUFNZ0FDZ0NBQ0lCVHdSQUlBRWdBQ2dDQkdvaUJDQURTdzBEQ3lBQUtBSUlJUUFNQUFzQUN5QUFJQUkyQWdBZ0FDQUFLQUlFSUFacU5nSUVJQUpCZUNBQ2EwRUhjV29pQnlBRlFRTnlOZ0lFSUFGQmVDQUJhMEVIY1dvaUJpQUZJQWRxSWdWcklRQWdBeUFHUmdSQVFhQWZJQVUyQWdCQmxCOUJsQjhvQWdBZ0FHb2lBRFlDQUNBRklBQkJBWEkyQWdRTUNBdEJuQjhvQWdBZ0JrWUVRRUdjSHlBRk5nSUFRWkFmUVpBZktBSUFJQUJxSWdBMkFnQWdCU0FBUVFGeU5nSUVJQUFnQldvZ0FEWUNBQXdJQ3lBR0tBSUVJZ05CQTNGQkFVY05CaUFEUVhoeElRa2dBMEgvQVUwRVFDQUdLQUlNSWdFZ0JpZ0NDQ0lDUmdSQVFZZ2ZRWWdmS0FJQVFYNGdBMEVEZG5keE5nSUFEQWNMSUFJZ0FUWUNEQ0FCSUFJMkFnZ01CZ3NnQmlnQ0dDRUlJQVlnQmlnQ0RDSUNSd1JBSUFZb0FnZ2lBU0FDTmdJTUlBSWdBVFlDQ0F3RkN5QUdRUlJxSWdFb0FnQWlBMFVFUUNBR0tBSVFJZ05GRFFRZ0JrRVFhaUVCQ3dOQUlBRWhCQ0FESWdKQkZHb2lBU2dDQUNJRERRQWdBa0VRYWlFQklBSW9BaEFpQXcwQUN5QUVRUUEyQWdBTUJBdEJsQjhnQmtFb2F5SUFRWGdnQW10QkIzRWlBV3NpQ0RZQ0FFR2dIeUFCSUFKcUlnRTJBZ0FnQVNBSVFRRnlOZ0lFSUFBZ0FtcEJLRFlDQkVHa0gwSHdJaWdDQURZQ0FDQURJQVJCSnlBRWEwRUhjV3BCTDJzaUFDQUFJQU5CRUdwSkd5SUJRUnMyQWdRZ0FVSFFJaWtDQURjQ0VDQUJRY2dpS1FJQU53SUlRZEFpSUFGQkNHbzJBZ0JCekNJZ0JqWUNBRUhJSWlBQ05nSUFRZFFpUVFBMkFnQWdBVUVZYWlFQUEwQWdBRUVITmdJRUlBQkJDR29nQUVFRWFpRUFJQVJKRFFBTElBRWdBMFlOQUNBQklBRW9BZ1JCZm5FMkFnUWdBeUFCSUFOcklnSkJBWEkyQWdRZ0FTQUNOZ0lBSUFKQi93Rk5CRUFnQWtGNGNVR3dIMm9oQUFKL1FZZ2ZLQUlBSWdGQkFTQUNRUU4yZENJQ2NVVUVRRUdJSHlBQklBSnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEFTQUFJQU0yQWdnZ0FTQUROZ0lNSUFNZ0FEWUNEQ0FESUFFMkFnZ01BUXRCSHlFQUlBSkIvLy8vQjAwRVFDQUNRU1lnQWtFSWRtY2lBR3QyUVFGeElBQkJBWFJyUVQ1cUlRQUxJQU1nQURZQ0hDQURRZ0EzQWhBZ0FFRUNkRUc0SVdvaEFRSkFBa0JCakI4b0FnQWlCRUVCSUFCMElnWnhSUVJBUVl3ZklBUWdCbkkyQWdBZ0FTQUROZ0lBREFFTElBSkJHU0FBUVFGMmEwRUFJQUJCSDBjYmRDRUFJQUVvQWdBaEJBTkFJQVFpQVNnQ0JFRjRjU0FDUmcwQ0lBQkJIWFloQkNBQVFRRjBJUUFnQVNBRVFRUnhhaUlHS0FJUUlnUU5BQXNnQmlBRE5nSVFDeUFESUFFMkFoZ2dBeUFETmdJTUlBTWdBellDQ0F3QkN5QUJLQUlJSWdBZ0F6WUNEQ0FCSUFNMkFnZ2dBMEVBTmdJWUlBTWdBVFlDRENBRElBQTJBZ2dMUVpRZktBSUFJZ0FnQlUwTkFFR1VIeUFBSUFWcklnRTJBZ0JCb0I5Qm9COG9BZ0FpQUNBRmFpSUNOZ0lBSUFJZ0FVRUJjallDQkNBQUlBVkJBM0kyQWdRZ0FFRUlhaUVBREFnTFFZUWZRVEEyQWdCQkFDRUFEQWNMUVFBaEFnc2dDRVVOQUFKQUlBWW9BaHdpQVVFQ2RFRzRJV29pQkNnQ0FDQUdSZ1JBSUFRZ0FqWUNBQ0FDRFFGQmpCOUJqQjhvQWdCQmZpQUJkM0UyQWdBTUFnc2dDRUVRUVJRZ0NDZ0NFQ0FHUmh0cUlBSTJBZ0FnQWtVTkFRc2dBaUFJTmdJWUlBWW9BaEFpQVFSQUlBSWdBVFlDRUNBQklBSTJBaGdMSUFZb0FoUWlBVVVOQUNBQ0lBRTJBaFFnQVNBQ05nSVlDeUFBSUFscUlRQWdCaUFKYWlJR0tBSUVJUU1MSUFZZ0EwRitjVFlDQkNBRklBQkJBWEkyQWdRZ0FDQUZhaUFBTmdJQUlBQkIvd0ZOQkVBZ0FFRjRjVUd3SDJvaEFRSi9RWWdmS0FJQUlnSkJBU0FBUVFOMmRDSUFjVVVFUUVHSUh5QUFJQUp5TmdJQUlBRU1BUXNnQVNnQ0NBc2hBQ0FCSUFVMkFnZ2dBQ0FGTmdJTUlBVWdBVFlDRENBRklBQTJBZ2dNQVF0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFVZ0F6WUNIQ0FGUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQWtFQklBTjBJZ1J4UlFSQVFZd2ZJQUlnQkhJMkFnQWdBU0FGTmdJQURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBZ05BSUFJaUFTZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFpQURRUUYwSVFNZ0FTQUNRUVJ4YWlJRUtBSVFJZ0lOQUFzZ0JDQUZOZ0lRQ3lBRklBRTJBaGdnQlNBRk5nSU1JQVVnQlRZQ0NBd0JDeUFCS0FJSUlnQWdCVFlDRENBQklBVTJBZ2dnQlVFQU5nSVlJQVVnQVRZQ0RDQUZJQUEyQWdnTElBZEJDR29oQUF3Q0N3SkFJQWRGRFFBQ1FDQUVLQUljSWdCQkFuUkJ1Q0ZxSWdFb0FnQWdCRVlFUUNBQklBSTJBZ0FnQWcwQlFZd2ZJQWhCZmlBQWQzRWlDRFlDQUF3Q0N5QUhRUkJCRkNBSEtBSVFJQVJHRzJvZ0FqWUNBQ0FDUlEwQkN5QUNJQWMyQWhnZ0JDZ0NFQ0lBQkVBZ0FpQUFOZ0lRSUFBZ0FqWUNHQXNnQkNnQ0ZDSUFSUTBBSUFJZ0FEWUNGQ0FBSUFJMkFoZ0xBa0FnQTBFUFRRUkFJQVFnQXlBRmFpSUFRUU55TmdJRUlBQWdCR29pQUNBQUtBSUVRUUZ5TmdJRURBRUxJQVFnQlVFRGNqWUNCQ0FFSUFWcUlnSWdBMEVCY2pZQ0JDQUNJQU5xSUFNMkFnQWdBMEgvQVUwRVFDQURRWGh4UWJBZmFpRUFBbjlCaUI4b0FnQWlBVUVCSUFOQkEzWjBJZ054UlFSQVFZZ2ZJQUVnQTNJMkFnQWdBQXdCQ3lBQUtBSUlDeUVCSUFBZ0FqWUNDQ0FCSUFJMkFnd2dBaUFBTmdJTUlBSWdBVFlDQ0F3QkMwRWZJUUFnQTBILy8vOEhUUVJBSUFOQkppQURRUWgyWnlJQWEzWkJBWEVnQUVFQmRHdEJQbW9oQUFzZ0FpQUFOZ0ljSUFKQ0FEY0NFQ0FBUVFKMFFiZ2hhaUVCQWtBQ1FDQUlRUUVnQUhRaUJuRkZCRUJCakI4Z0JpQUljallDQUNBQklBSTJBZ0FNQVFzZ0EwRVpJQUJCQVhaclFRQWdBRUVmUnh0MElRQWdBU2dDQUNFRkEwQWdCU0lCS0FJRVFYaHhJQU5HRFFJZ0FFRWRkaUVHSUFCQkFYUWhBQ0FCSUFaQkJIRnFJZ1lvQWhBaUJRMEFDeUFHSUFJMkFoQUxJQUlnQVRZQ0dDQUNJQUkyQWd3Z0FpQUNOZ0lJREFFTElBRW9BZ2dpQUNBQ05nSU1JQUVnQWpZQ0NDQUNRUUEyQWhnZ0FpQUJOZ0lNSUFJZ0FEWUNDQXNnQkVFSWFpRUFEQUVMQWtBZ0NVVU5BQUpBSUFJb0Fod2lBRUVDZEVHNElXb2lBU2dDQUNBQ1JnUkFJQUVnQkRZQ0FDQUVEUUZCakI4Z0MwRitJQUIzY1RZQ0FBd0NDeUFKUVJCQkZDQUpLQUlRSUFKR0cyb2dCRFlDQUNBRVJRMEJDeUFFSUFrMkFoZ2dBaWdDRUNJQUJFQWdCQ0FBTmdJUUlBQWdCRFlDR0FzZ0FpZ0NGQ0lBUlEwQUlBUWdBRFlDRkNBQUlBUTJBaGdMQWtBZ0EwRVBUUVJBSUFJZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQW1vaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFJZ0JVRURjallDQkNBQ0lBVnFJZ1FnQTBFQmNqWUNCQ0FESUFScUlBTTJBZ0FnQndSQUlBZEJlSEZCc0I5cUlRQkJuQjhvQWdBaEFRSi9RUUVnQjBFRGRuUWlCU0FHY1VVRVFFR0lIeUFGSUFaeU5nSUFJQUFNQVFzZ0FDZ0NDQXNoQmlBQUlBRTJBZ2dnQmlBQk5nSU1JQUVnQURZQ0RDQUJJQVkyQWdnTFFad2ZJQVEyQWdCQmtCOGdBellDQUFzZ0FrRUlhaUVBQ3lBS1FSQnFKQUFnQUF2U0N3RUhmd0pBSUFCRkRRQWdBRUVJYXlJQ0lBQkJCR3NvQWdBaUFVRjRjU0lBYWlFRkFrQWdBVUVCY1EwQUlBRkJBM0ZGRFFFZ0FpQUNLQUlBSWdGcklnSkJtQjhvQWdCSkRRRWdBQ0FCYWlFQUFrQUNRRUdjSHlnQ0FDQUNSd1JBSUFGQi93Rk5CRUFnQVVFRGRpRUVJQUlvQWd3aUFTQUNLQUlJSWdOR0JFQkJpQjlCaUI4b0FnQkJmaUFFZDNFMkFnQU1CUXNnQXlBQk5nSU1JQUVnQXpZQ0NBd0VDeUFDS0FJWUlRWWdBaUFDS0FJTUlnRkhCRUFnQWlnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBSkJGR29pQkNnQ0FDSURSUVJBSUFJb0FoQWlBMFVOQWlBQ1FSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZLQUlFSWdGQkEzRkJBMGNOQWtHUUh5QUFOZ0lBSUFVZ0FVRitjVFlDQkNBQ0lBQkJBWEkyQWdRZ0JTQUFOZ0lBRHd0QkFDRUJDeUFHUlEwQUFrQWdBaWdDSENJRFFRSjBRYmdoYWlJRUtBSUFJQUpHQkVBZ0JDQUJOZ0lBSUFFTkFVR01IMEdNSHlnQ0FFRitJQU4zY1RZQ0FBd0NDeUFHUVJCQkZDQUdLQUlRSUFKR0cyb2dBVFlDQUNBQlJRMEJDeUFCSUFZMkFoZ2dBaWdDRUNJREJFQWdBU0FETmdJUUlBTWdBVFlDR0FzZ0FpZ0NGQ0lEUlEwQUlBRWdBellDRkNBRElBRTJBaGdMSUFJZ0JVOE5BQ0FGS0FJRUlnRkJBWEZGRFFBQ1FBSkFBa0FDUUNBQlFRSnhSUVJBUWFBZktBSUFJQVZHQkVCQm9COGdBallDQUVHVUgwR1VIeWdDQUNBQWFpSUFOZ0lBSUFJZ0FFRUJjallDQkNBQ1Fad2ZLQUlBUncwR1FaQWZRUUEyQWdCQm5COUJBRFlDQUE4TFFad2ZLQUlBSUFWR0JFQkJuQjhnQWpZQ0FFR1FIMEdRSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUFJQUpxSUFBMkFnQVBDeUFCUVhoeElBQnFJUUFnQVVIL0FVMEVRQ0FCUVFOMklRUWdCU2dDRENJQklBVW9BZ2dpQTBZRVFFR0lIMEdJSHlnQ0FFRitJQVIzY1RZQ0FBd0ZDeUFESUFFMkFnd2dBU0FETmdJSURBUUxJQVVvQWhnaEJpQUZJQVVvQWd3aUFVY0VRRUdZSHlnQ0FCb2dCU2dDQ0NJRElBRTJBZ3dnQVNBRE5nSUlEQU1MSUFWQkZHb2lCQ2dDQUNJRFJRUkFJQVVvQWhBaUEwVU5BaUFGUVJCcUlRUUxBMEFnQkNFSElBTWlBVUVVYWlJRUtBSUFJZ01OQUNBQlFSQnFJUVFnQVNnQ0VDSUREUUFMSUFkQkFEWUNBQXdDQ3lBRklBRkJmbkUyQWdRZ0FpQUFRUUZ5TmdJRUlBQWdBbW9nQURZQ0FBd0RDMEVBSVFFTElBWkZEUUFDUUNBRktBSWNJZ05CQW5SQnVDRnFJZ1FvQWdBZ0JVWUVRQ0FFSUFFMkFnQWdBUTBCUVl3ZlFZd2ZLQUlBUVg0Z0EzZHhOZ0lBREFJTElBWkJFRUVVSUFZb0FoQWdCVVliYWlBQk5nSUFJQUZGRFFFTElBRWdCallDR0NBRktBSVFJZ01FUUNBQklBTTJBaEFnQXlBQk5nSVlDeUFGS0FJVUlnTkZEUUFnQVNBRE5nSVVJQU1nQVRZQ0dBc2dBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQ0FDUVp3ZktBSUFSdzBBUVpBZklBQTJBZ0FQQ3lBQVFmOEJUUVJBSUFCQmVIRkJzQjlxSVFFQ2YwR0lIeWdDQUNJRFFRRWdBRUVEZG5RaUFIRkZCRUJCaUI4Z0FDQURjallDQUNBQkRBRUxJQUVvQWdnTElRQWdBU0FDTmdJSUlBQWdBallDRENBQ0lBRTJBZ3dnQWlBQU5nSUlEd3RCSHlFRElBQkIvLy8vQjAwRVFDQUFRU1lnQUVFSWRtY2lBV3QyUVFGeElBRkJBWFJyUVQ1cUlRTUxJQUlnQXpZQ0hDQUNRZ0EzQWhBZ0EwRUNkRUc0SVdvaEFRSkFBa0FDUUVHTUh5Z0NBQ0lFUVFFZ0EzUWlCM0ZGQkVCQmpCOGdCQ0FIY2pZQ0FDQUJJQUkyQWdBZ0FpQUJOZ0lZREFFTElBQkJHU0FEUVFGMmEwRUFJQU5CSDBjYmRDRURJQUVvQWdBaEFRTkFJQUVpQkNnQ0JFRjRjU0FBUmcwQ0lBTkJIWFloQVNBRFFRRjBJUU1nQkNBQlFRUnhhaUlIUVJCcUtBSUFJZ0VOQUFzZ0J5QUNOZ0lRSUFJZ0JEWUNHQXNnQWlBQ05nSU1JQUlnQWpZQ0NBd0JDeUFFS0FJSUlnQWdBallDRENBRUlBSTJBZ2dnQWtFQU5nSVlJQUlnQkRZQ0RDQUNJQUEyQWdnTFFhZ2ZRYWdmS0FJQVFRRnJJZ0JCZnlBQUd6WUNBQXNMQkFBakFBc0dBQ0FBSkFBTEVBQWpBQ0FBYTBGd2NTSUFKQUFnQUF0S0FRRi9JQUFnQVVrRVFDQUFJQUVnQWhBQ0R3c2dBZ1JBSUFBZ0Ftb2hBeUFCSUFKcUlRRURRQ0FEUVFGcklnTWdBVUVCYXlJQkxRQUFPZ0FBSUFKQkFXc2lBZzBBQ3dzZ0FBdjlEZ0lSZndGK0l3QkJNR3NpQnlRQVFiaC9JUWdDUUNBRlJRMEFJQVFzQUFBaUNVSC9BWEVoQ3dKQUlBbEJBRWdFUUNBTFFmNEFhMEVCZGlJR0lBVlBEUUpCYkNFSUlBdEIvd0JySWd0Qi93RkxEUUlnQkVFQmFpRUlRUUFoQlFOQUlBVWdDMDhFUUNBTElRZ2dCaUVMREFNRklBQWdCV29nQ0NBRlFRRjJhaUlFTFFBQVFRUjJPZ0FBSUFBZ0JVRUJjbW9nQkMwQUFFRVBjVG9BQUNBRlFRSnFJUVVNQVFzQUN3QUxJQVVnQzAwTkFTQUhRZjhCTmdJRUlBWWdCMEVFYWlBSFFRaHFJQVJCQVdvaURpQUxFQXdpQkVHSWYwc0VRQ0FFSVFnTUFndEJWQ0VJSUFjb0FnZ2lFRUVHU3cwQklBY29BZ1FpRVVFQmRDSUpRUUpxclVJQklCQ3RoaUlZUVFFZ0VIUWlEVUVCYWlJRnJVSUNobng4UWd0OFF2ei8vLy8vLy8vLy93Q0RRdVFDVmcwQlFWSWhDQ0FSUWY4QlN3MEJJQTFCZjNOQkFuUkI1QUpxclNBUlFRRnFJaFZCQVhTdElCaDhRZ2g4VkEwQklBc2dCR3NoRmlBRUlBNXFJUmNnQmtHQUJHb2lFaUFGUVFKMGFpSVJJQWxxUVFKcUlRNGdCa0dFQkdvaEUwR0FnQUlnRUhSQkVIWWhDVUVBSVFWQkFTRVBJQTFCQVdzaUZDRUtBMEFnQlNBVlJrVUVRQUpBSUFZZ0JVRUJkQ0lJYWk4QkFDSUVRZi8vQTBZRVFDQVRJQXBCQW5ScUlBVTZBQUlnQ2tFQmF5RUtRUUVoQkF3QkN5QVBRUUFnQ1NBRXdVb2JJUThMSUFnZ0VXb2dCRHNCQUNBRlFRRnFJUVVNQVFzTElBWWdEenNCZ2dRZ0JpQVFPd0dBQkFKQUlBb2dGRVlFUUNBTlFRTjJJUWhDQUNFWVFRQWhEd05BSUF3Z0ZVWUVRQ0FJSUExQkFYWnFRUU5xSWdsQkFYUWhDRUVBSVFSQkFDRUtBMEJCQUNFRklBb2dEVThOQkFOQUlBVkJBa1pGQkVBZ0V5QUZJQWxzSUFScUlCUnhRUUowYWlBT0lBVWdDbXBxTFFBQU9nQUNJQVZCQVdvaEJRd0JDd3NnQ2tFQ2FpRUtJQVFnQ0dvZ0ZIRWhCQXdBQ3dBRklBWWdERUVCZEdvdUFRQWhDU0FPSUE5cUlnUWdHRGNBQUVFSUlRVURRQ0FGSUFsT1JRUkFJQVFnQldvZ0dEY0FBQ0FGUVFocUlRVU1BUXNMSUJoQ2dZS0VpSkNnd0lBQmZDRVlJQXhCQVdvaERDQUpJQTlxSVE4TUFRc0FDd0FMSUExQkEzWWdEVUVCZG1wQkEyb2hDRUVBSVFVRFFDQU1JQlZHUlFSQVFRQWhDU0FHSUF4QkFYUnFMZ0VBSWdSQkFDQUVRUUJLR3lFRUEwQWdCQ0FKUmtVRVFDQVRJQVZCQW5ScUlBdzZBQUlEUUNBRklBaHFJQlJ4SWdVZ0Nrc05BQXNnQ1VFQmFpRUpEQUVMQ3lBTVFRRnFJUXdNQVFzTFFYOGhDQ0FGRFFJTElCQkJBV29oQ0VFQUlRVURRQ0FGSUExR1JRUkFJQkVnRXlBRlFRSjBhaUlPTFFBQ1FRRjBhaUlFSUFRdkFRQWlDVUVCYWpzQkFDQU9JQWdnQ1dkQllITnFJZ1E2QUFNZ0RpQUpJQVIwSUExck93RUFJQVZCQVdvaEJRd0JDd3NDUUFKQUlBWXZBWUlFQkVBZ0IwRWNhaUlFSUJjZ0ZoQU5JZ2hCaUg5TERRSWdCMEVVYWlBRUlCSVFEaUFIUVF4cUlBUWdFaEFPUVFBaEJRTkFJQWRCSEdvaUJCQVBJQVZCK3dGTGNnMENJQUFnQldvaUJpQUhRUlJxSUFRUUVEb0FBQ0FHSUFkQkRHb2dCQkFRT2dBQklBVkJBbkloQkNBSFFSeHFFQThFUUNBRUlRVU1Bd1VnQUNBRWFpQUhRUlJxSUFkQkhHb2lCQkFRT2dBQUlBWWdCMEVNYWlBRUVCQTZBQU1nQlVFRWFpRUZEQUVMQUFzQUN5QUhRUnhxSWdRZ0Z5QVdFQTBpQ0VHSWYwc05BU0FIUVJScUlBUWdFaEFPSUFkQkRHb2dCQ0FTRUE1QkFDRUZBMEFnQjBFY2FpSUVFQThnQlVIN0FVdHlSUVJBSUFBZ0JXb2lCaUFIUVJScUlBUVFFVG9BQUNBR0lBZEJER29nQkJBUk9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVGSUFBZ0JHb2dCMEVVYWlBSFFSeHFJZ1FRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FESUFWQkJHb2hCUXdDQ3dzTEFuOERRRUc2ZnlFSUlBVkIvUUZMRFFNZ0FDQUZhaUlHSUFkQkZHb2dCMEVjYWlJSkVCRTZBQUFnQmtFQmFpRUVJQWtRRDBFRFJnUkFJQWRCREdvaENFRUNEQUlMSUFWQi9BRkxEUU1nQmlBSFFReHFJQWRCSEdvaUJCQVJPZ0FCSUFWQkFtb2hCU0FFRUE5QkEwY05BQXNnQUNBRmFpRUVJQWRCRkdvaENFRURDeUFFSUFnZ0IwRWNhaEFST2dBQUlBWnFJQUJySVFnTUFRc0Nmd05BUWJwL0lRZ2dCVUg5QVVzTkFpQUFJQVZxSWdZZ0IwRVVhaUFIUVJ4cUlna1FFRG9BQUNBR1FRRnFJUVFnQ1JBUFFRTkdCRUFnQjBFTWFpRUlRUUlNQWdzZ0JVSDhBVXNOQWlBR0lBZEJER29nQjBFY2FpSUVFQkE2QUFFZ0JVRUNhaUVGSUFRUUQwRURSdzBBQ3lBQUlBVnFJUVFnQjBFVWFpRUlRUU1MSUFRZ0NDQUhRUnhxRUJBNkFBQWdCbW9nQUdzaENBc2dDRUdJZjBzTkFRc2dDQ0VFUVFBaEJTQUJRUUJCTkJBRElRbEJBQ0VLQTBBZ0JDQUZSd1JBSUFBZ0JXb2lCaTBBQUNJQlFRdExCRUJCYkNFSURBTUZJQWtnQVVFQ2RHb2lBU0FCS0FJQVFRRnFOZ0lBSUFWQkFXb2hCVUVCSUFZdEFBQjBRUUYxSUFwcUlRb01BZ3NBQ3d0QmJDRUlJQXBGRFFBZ0NtY2lCVUVmY3lJQlFRdExEUUFnQTBFZ0lBVnJOZ0lBUVFGQkFpQUJkQ0FLYXlJRFowRWZjeUlCZENBRFJ3MEFJQUFnQkdvZ0FVRUJhaUlBT2dBQUlBa2dBRUVDZEdvaUFDQUFLQUlBUVFGcU5nSUFJQWtvQWdRaUFFRUNTU0FBUVFGeGNnMEFJQUlnQkVFQmFqWUNBQ0FMUVFGcUlRZ0xJQWRCTUdva0FDQUlDNkFGQVF4L0l3QkJFR3NpRENRQUFuOGdCRUVIVFFSQUlBeENBRGNEQ0NBTVFRaHFJZ1VnQXlBRUVBSWFRV3dnQUNBQklBSWdCVUVJRUF3aUFDQUFJQVJMR3lBQUlBQkJpWDlKR3d3QkN5QUFRUUFnQVNnQ0FFRUJhaUlOUVFGMEVBTWhEMEZVSUFNb0FBQWlCa0VQY1NJQVFRcExEUUFhSUFJZ0FFRUZhallDQUNBRElBUnFJZ0pCQkdzaEJ5QUNRUWRySVFzZ0FFRUdhaUVPUVFRaEFpQUdRUVIySVFWQklDQUFkQ0lJUVFGeUlRbEJBQ0VBUVFFaEJpQURJUVFEUUFKQUlBWkJBWEZGQkVBRFFDQUZRWDl6UVlDQWdJQjRjbWdpQmtFWVNVVUVRQ0FBUVNScUlRQWdCQ0FMVFFSL0lBUkJBMm9GSUFRZ0MydEJBM1FnQW1wQkgzRWhBaUFIQ3lJRUtBQUFJQUoySVFVTUFRc0xJQUlnQmtFZWNTSUtha0VDYWlFQ0lBWkJBWFpCQTJ3Z0FHb2dCU0FLZGtFRGNXb2lBQ0FOVHcwQkFuOGdCQ0FMU3lBQ1FRTjJJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBUWdCMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVUxJQVVnQ0VFQmEzRWlCaUFJUVFGMFFRRnJJZ29nQ1dzaUVFa0VmeUFPUVFGckJTQUZJQXB4SWdVZ0VFRUFJQVVnQ0U0YmF5RUdJQTRMSVFVZ0R5QUFRUUYwYWlBR1FRRnJJZ283QVFBZ0FFRUJhaUVBSUFJZ0JXb2hBaUFJUVFFZ0Jtc2dDaUFHUVFCS0d5QUphaUlKU2dSQUlBbEJBa2dOQVVFZ0lBbG5JZ1ZySVE1QkFTQUZRUjl6ZENFSUN5QUFJQTFQRFFBZ0NrRUFSeUVHQW44Z0JDQUxTeUFDUVFOMUlBUnFJZ1VnQjB0eFJRUkFJQUpCQjNFaEFpQUZEQUVMSUFJZ0JDQUhhMEVEZEdwQkgzRWhBaUFIQ3lJRUtBQUFJQUoySVFVTUFRc0xRV3dnQ1VFQlJ3MEFHa0ZRSUFBZ0RVc05BQnBCYkNBQ1FTQktEUUFhSUFFZ0FFRUJhellDQUNBRUlBSkJCMnBCQTNWcUlBTnJDeUFNUVJCcUpBQUw4Z0VCQVg4Z0FrVUVRQ0FBUWdBM0FnQWdBRUVBTmdJUUlBQkNBRGNDQ0VHNGZ3OExJQUFnQVRZQ0RDQUFJQUZCQkdvMkFoQWdBa0VFVHdSQUlBQWdBU0FDYWlJQlFRUnJJZ00yQWdnZ0FDQURLQUFBTmdJQUlBRkJBV3N0QUFBaUFRUkFJQUFnQVdkQkYyczJBZ1FnQWc4TElBQkJBRFlDQkVGL0R3c2dBQ0FCTmdJSUlBQWdBUzBBQUNJRE5nSUFBa0FDUUFKQUlBSkJBbXNPQWdFQUFnc2dBQ0FCTFFBQ1FSQjBJQU55SWdNMkFnQUxJQUFnQVMwQUFVRUlkQ0FEYWpZQ0FBc2dBU0FDYWtFQmF5MEFBQ0lCUlFSQUlBQkJBRFlDQkVGc0R3c2dBQ0FCWnlBQ1FRTjBhMEVKYWpZQ0JDQUNDMFFCQW44Z0FTQUNMd0VBSWdNZ0FTZ0NCR29pQkRZQ0JDQUFJQU5CQW5SQm9CMXFLQUlBSUFFb0FnQkJBQ0FFYTNaeE5nSUFJQUVRRHhvZ0FDQUNRUVJxTmdJRUM1OEJBUVIvUVFNaEFTQUFLQUlFSWdKQklFMEVRQ0FBS0FJSUlnRWdBQ2dDRUU4RVFDQUFJQUpCQjNFMkFnUWdBQ0FCSUFKQkEzWnJJZ0kyQWdnZ0FDQUNLQUFBTmdJQVFRQVBDeUFBS0FJTUlnTWdBVVlFUUVFQlFRSWdBa0VnU1JzUEN5QUFJQUVnQVNBRGF5QUNRUU4ySWdRZ0FTQUVheUFEU1NJQkd5SURheUlFTmdJSUlBQWdBaUFEUVFOMGF6WUNCQ0FBSUFRb0FBQTJBZ0FMSUFFTFNBRUVmeUFBS0FJRUlBQW9BZ0JCQW5ScUlnSXRBQUlnQWk4QkFDRUVJQUVnQVNnQ0JDSUZJQUl0QUFNaUFtbzJBZ1FnQUNBRUlBRW9BZ0FnQlhSQkFDQUNhM1pxTmdJQUMxSUJCSDhnQUNnQ0JDQUFLQUlBUVFKMGFpSUNMUUFDSUFJdkFRQWhCQ0FCSUFJdEFBTWlBaUFCS0FJRWFpSUZOZ0lFSUFBZ0JDQUNRUUowUWFBZGFpZ0NBQ0FCS0FJQVFRQWdCV3QyY1dvMkFnQUxDQUFnQUVHSWYwc0xHZ0FnQUFSQUlBRUVRQ0FDSUFBZ0FSRUNBQThMSUFBUUJnc0xwZ2dDRFg4QmZpTUFRUkJySWdra0FDQUpRUUEyQWd3Z0NVRUFOZ0lJQW44Q1FDQURRZWdKYWlBRElBbEJDR29nQ1VFTWFpQUJJQUlnQTBHQUFXb1FDeUlQUVloL1N3MEFRVlFnQ1NnQ0RDSUVJQUFvQWdBaUFVSC9BWEZCQVdwTERRRWFJQUJCQkdvaEN5QUFJQUZCLzRHQWVIRWdCRUVRZEVHQWdQd0hjWEkyQWdCQmZ5QUVJQVJCQUVnYlFRRnFJUUJCQUNFQklBa29BZ2doQlVFQUlRSURRQ0FBSUFKR0JFQWdCVUVEYXlFQlFRQWhBQU5BQWtCQkFDRUNJQUFnQVU0RVFBTkFJQUFnQlU0TkFpQURJQUFnQTJwQjZBbHFMUUFBUVFKMGFrRkFheUlCSUFFb0FnQWlBVUVCYWpZQ0FDQUJJQU5xSUFBNkFPZ0hJQUJCQVdvaEFBd0FDd0FGQTBBZ0FrRUVSa1VFUUNBRElBTWdBQ0FDYWlJSGFrSG9DV290QUFCQkFuUnFRVUJySWdnZ0NDZ0NBQ0lJUVFGcU5nSUFJQU1nQ0dvZ0J6b0E2QWNnQWtFQmFpRUNEQUVMQ3lBQVFRUnFJUUFNQWdzQUN3c2dCRUVCYWlFT0lBTW9BZ0FoQjBFQUlRQkJBU0VJQTBBZ0NDQU9SZzBESUE0Z0NHc2hCQ0FESUFoQkFuUnFLQUlBSVFVQ1FBSkFBa0FDUUFKQUFrQkJBU0FJZEVFQmRTSU5RUUZyRGdnQUFRUUNCQVFFQXdRTFFRQWhBaUFGUVFBZ0JVRUFTaHNoQmlBQUlRRURRQ0FDSUFaR0RRVWdBeUFDSUFkcWFpMEE2QWNoQ2lBTElBRkJBWFJxSWd3Z0JEb0FBU0FNSUFvNkFBQWdBa0VCYWlFQ0lBRkJBV29oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaENpQUFJUUVEUUNBQ0lBcEdEUVFnQ3lBQlFRRjBhaUlHSUFNZ0FpQUhhbW90QU9nSElndzZBQUlnQmlBRU9nQUJJQVlnRERvQUFDQUdJQVE2QUFNZ0FrRUJhaUVDSUFGQkFtb2hBUXdBQ3dBTFFRQWhBaUFGUVFBZ0JVRUFTaHNoQmlBRVFRaDBRWUQrQTNFaEJDQUFJUUVEUUNBQ0lBWkdEUU1nQ3lBQlFRRjBhaUFFSUFNZ0FpQUhhbW90QU9nSGNxMUNnWUNFZ0pDQXdBQitOd0FBSUFKQkFXb2hBaUFCUVFScUlRRU1BQXNBQzBFQUlRSWdCVUVBSUFWQkFFb2JJUVlnQkVFSWRFR0EvZ054SVFRZ0FDRUJBMEFnQWlBR1JnMENJQXNnQVVFQmRHb2lDaUFFSUFNZ0FpQUhhbW90QU9nSGNxMUNnWUNFZ0pDQXdBQitJaEUzQUFnZ0NpQVJOd0FBSUFKQkFXb2hBaUFCUVFocUlRRU1BQXNBQzBFQUlRRWdCVUVBSUFWQkFFb2JJUW9nQkVFSWRFR0EvZ054SVF3Z0FDRUVBMEFnQVNBS1JnMEJJQXNnQkVFQmRHb2hFQ0FNSUFNZ0FTQUhhbW90QU9nSGNxMUNnWUNFZ0pDQXdBQitJUkZCQUNFQ0EwQWdBaUFOVGtVRVFDQVFJQUpCQVhScUlnWWdFVGNBR0NBR0lCRTNBQkFnQmlBUk53QUlJQVlnRVRjQUFDQUNRUkJxSVFJTUFRc0xJQUZCQVdvaEFTQUVJQTFxSVFRTUFBc0FDeUFJUVFGcUlRZ2dCU0FIYWlFSElBVWdEV3dnQUdvaEFBd0FDd0FGSUFNZ0FrRUNkR29pQjBGQWF5QUJOZ0lBSUFKQkFXb2hBaUFIS0FJQUlBRnFJUUVNQVFzQUN3QUxJQThMSUFsQkVHb2tBQXZ5QWdFR2Z5TUFRU0JySWdVa0FDQUVLQUlBSVFZZ0JVRU1haUFDSUFNUURTSURRWWgvVFFSQUlBUkJCR29oQWlBQUlBRnFJZ2xCQTJzaEJFRUFJQVpCRUhaclFSOXhJUU1EUUNBRlFReHFFQThnQUNBRVQzSkZCRUFnQWlBRktBSU1JZ1lnQlNnQ0VDSUhkQ0FEZGtFQmRHb2lDQzBBQVNFS0lBQWdDQzBBQURvQUFDQUNJQVlnQnlBS2FpSUdkQ0FEZGtFQmRHb2lCeTBBQUNFSUlBVWdCaUFITFFBQmFqWUNFQ0FBSUFnNkFBRWdBRUVDYWlFQURBRUxDd05BSUFWQkRHb1FEeUVISUFVb0Fnd2hCaUFGS0FJUUlRUWdBQ0FKVHlBSGNrVUVRQ0FDSUFZZ0JIUWdBM1pCQVhScUlnWXRBQUFoQnlBRklBUWdCaTBBQVdvMkFoQWdBQ0FIT2dBQUlBQkJBV29oQUF3QkN3c0RRQ0FBSUFsUFJRUkFJQUlnQmlBRWRDQURka0VCZEdvaUJ5MEFBU0VJSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQkNBSWFpRUVEQUVMQzBGc1FXd2dBU0FGS0FJVUlBVW9BaGhIR3lBRVFTQkhHeUVEQ3lBRlFTQnFKQUFnQXd2UEZBRWpmeU1BUWRBQWF5SUZKQUJCYkNFSkFrQWdBMEVLU1EwQUFrQWdBeUFDTHdBRUlnY2dBaThBQUNJSUlBSXZBQUlpRFdwcVFRWnFJZ3hKRFFBZ0JDOEJBaUVHSUFWQlBHb2dBa0VHYWlJQ0lBZ1FEU0lKUVloL1N3MEJJQVZCS0dvZ0FpQUlhaUlDSUEwUURTSUpRWWgvU3cwQklBVkJGR29nQWlBTmFpSUNJQWNRRFNJSlFZaC9TdzBCSUFVZ0FpQUhhaUFESUF4ckVBMGlDVUdJZjBzTkFTQUVRUVJxSVFvZ0FDQUJhaUlmUVFOcklTQkJBQ0FHYTBFZmNTRUxJQVVvQWdnaEVTQUZLQUljSVJJZ0JTZ0NNQ0VUSUFVb0FrUWhGQ0FGS0FJRUlRa2dCU2dDR0NFTklBVW9BaXdoRENBRktBSkFJUVlnQlNnQ0VDRWhJQVVvQWlRaElpQUZLQUk0SVNNZ0JTZ0NUQ0VrSUFVb0FnQWhGU0FGS0FJVUlSWWdCU2dDS0NFWElBVW9BandoR0VFQklROGdBQ0FCUVFOcVFRSjJJZ1JxSWdNZ0JHb2lBaUFFYWlJWklRUWdBaUVJSUFNaEJ3TkFJQTlCQVhGRklBUWdJRTl5UlFSQUlBQWdDaUFZSUFaMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhHaUFPTFFBRElSQWdCeUFLSUJjZ0RIUWdDM1pCQW5ScUlnNHZBUUE3QUFBZ0RpMEFBaUViSUE0dEFBTWhEeUFJSUFvZ0ZpQU5kQ0FMZGtFQ2RHb2lEaThCQURzQUFDQU9MUUFDSVJ3Z0RpMEFBeUVkSUFRZ0NpQVZJQWwwSUF0MlFRSjBhaUlPTHdFQU93QUFJQTR0QUFJaEhpQU9MUUFESVE0Z0FDQVFhaUlsSUFvZ0dDQUdJQnBxSWdaMElBdDJRUUowYWlJUUx3RUFPd0FBSUJBdEFBSWdFQzBBQXlFbUlBY2dEMm9pSnlBS0lCY2dEQ0FiYWlJYWRDQUxka0VDZEdvaUJ5OEJBRHNBQUNBSExRQUNJUXdnQnkwQUF5RVFJQWdnSFdvaUd5QUtJQllnRFNBY2FpSVBkQ0FMZGtFQ2RHb2lDQzhCQURzQUFDQUlMUUFDSVEwZ0NDMEFBeUVjSUFRZ0Rtb2lIU0FLSUJVZ0NTQWVhaUlPZENBTGRrRUNkR29pQ1M4QkFEc0FBQ0FHYWlFQVFRTWhCd0ovSUJRZ0pFa0VRQ0FBSVFaQkF3d0JDeUFBUVFkeElRWWdGQ0FBUVFOMmF5SVVLQUFBSVJoQkFBc2dDUzBBQXlFZUlBa3RBQUloQ0NBTUlCcHFJUUFnRXlBalNRUi9JQUFGSUJNZ0FFRURkbXNpRXlnQUFDRVhRUUFoQnlBQVFRZHhDeUVNSUEwZ0Qyb2hBQ0FIY2lFSlFRTWhEd0ovSUJJZ0lra0VRQ0FBSVExQkF3d0JDeUFBUVFkeElRMGdFaUFBUVFOMmF5SVNLQUFBSVJaQkFBc2dDQ0FPYWlFQUlBbHlJQkVnSVVrRWZ5QUFCU0FSSUFCQkEzWnJJaEVvQUFBaEZVRUFJUThnQUVFSGNRc2hDU0FsSUNacUlRQWdFQ0FuYWlFSElCc2dIR29oQ0NBZElCNXFJUVFnRDNKRklROE1BUXNMSUFVZ0REWUNMQ0FGSUFZMkFrQWdCU0FOTmdJWUlBVWdDVFlDQkNBRklCUTJBa1FnQlNBVE5nSXdJQVVnRWpZQ0hDQUZJQkUyQWdnZ0JTQVlOZ0k4SUFVZ0Z6WUNLQ0FGSUJZMkFoUWdCU0FWTmdJQUlBSWdCMGtnQUNBRFMzSU5BRUZzSVFrZ0NDQVpTdzBCSUFOQkEyc2hDUU5BSUFWQlBHb1FEMFVnQUNBSlNYRUVRQ0FBSUFvZ0JTZ0NQQ0lOSUFVb0FrQWlESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdBQ0FPTFFBRGFpSUdJQW9nRFNBTUlBNHRBQUpxSWdCMElBdDJRUUowYWlJTUx3RUFPd0FBSUFVZ0FDQU1MUUFDYWpZQ1FDQUdJQXd0QUFOcUlRQU1BUVVnQTBFQ2F5RU1BMEFnQlVFOGFoQVBJUVlnQlNnQ1BDRU5JQVVvQWtBaENTQUFJQXhMSUFaeVJRUkFJQUFnQ2lBTklBbDBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdDU0FHTFFBQ2FqWUNRQ0FBSUFZdEFBTnFJUUFNQVFzTEEwQWdBQ0FNUzBVRVFDQUFJQW9nRFNBSmRDQUxka0VDZEdvaUJpOEJBRHNBQUNBQUlBWXRBQU5xSVFBZ0NTQUdMUUFDYWlFSkRBRUxDd0pBSUFBZ0EwOE5BQ0FBSUFvZ0RTQUpkQ0FMZGlJQVFRSjBhaUlETFFBQU9nQUFJQU10QUFOQkFVWUVRQ0FKSUFNdEFBSnFJUWtNQVFzZ0NVRWZTdzBBUVNBZ0NTQUtJQUJCQW5ScUxRQUNhaUlBSUFCQklFOGJJUWtMSUFKQkEyc2hEQU5BSUFWQktHb1FEMFVnQnlBTVNYRUVRQ0FISUFvZ0JTZ0NLQ0lHSUFVb0Fpd2lBSFFnQzNaQkFuUnFJZzB2QVFBN0FBQWdCeUFOTFFBRGFpSURJQW9nQmlBQUlBMHRBQUpxSWdCMElBdDJRUUowYWlJR0x3RUFPd0FBSUFVZ0FDQUdMUUFDYWpZQ0xDQURJQVl0QUFOcUlRY01BUVVnQWtFQ2F5RUdBMEFnQlVFb2FoQVBJUU1nQlNnQ0tDRU1JQVVvQWl3aEFDQUdJQWRKSUFOeVJRUkFJQWNnQ2lBTUlBQjBJQXQyUVFKMGFpSURMd0VBT3dBQUlBVWdBQ0FETFFBQ2FqWUNMQ0FISUFNdEFBTnFJUWNNQVFzTEEwQWdCaUFIU1VVRVFDQUhJQW9nRENBQWRDQUxka0VDZEdvaUF5OEJBRHNBQUNBSElBTXRBQU5xSVFjZ0FDQURMUUFDYWlFQURBRUxDd0pBSUFJZ0IwME5BQ0FISUFvZ0RDQUFkQ0FMZGlJQ1FRSjBhaUlETFFBQU9nQUFJQU10QUFOQkFVWUVRQ0FBSUFNdEFBSnFJUUFNQVFzZ0FFRWZTdzBBUVNBZ0FDQUtJQUpCQW5ScUxRQUNhaUlBSUFCQklFOGJJUUFMSUJsQkEyc2hEQU5BSUFWQkZHb1FEMFVnQ0NBTVNYRUVRQ0FJSUFvZ0JTZ0NGQ0lHSUFVb0FoZ2lBblFnQzNaQkFuUnFJZzB2QVFBN0FBQWdDQ0FOTFFBRGFpSURJQW9nQmlBQ0lBMHRBQUpxSWdKMElBdDJRUUowYWlJR0x3RUFPd0FBSUFVZ0FpQUdMUUFDYWpZQ0dDQURJQVl0QUFOcUlRZ01BUVVnR1VFQ2F5RURBMEFnQlVFVWFoQVBJUUlnQlNnQ0ZDRUdJQVVvQWhnaEJ5QURJQWhKSUFKeVJRUkFJQWdnQ2lBR0lBZDBJQXQyUVFKMGFpSUNMd0VBT3dBQUlBVWdCeUFDTFFBQ2FqWUNHQ0FJSUFJdEFBTnFJUWdNQVFzTEEwQWdBeUFJU1VVRVFDQUlJQW9nQmlBSGRDQUxka0VDZEdvaUFpOEJBRHNBQUNBSUlBSXRBQU5xSVFnZ0J5QUNMUUFDYWlFSERBRUxDd0pBSUFnZ0dVOE5BQ0FJSUFvZ0JpQUhkQ0FMZGlJQ1FRSjBhaUlETFFBQU9nQUFJQU10QUFOQkFVWUVRQ0FISUFNdEFBSnFJUWNNQVFzZ0IwRWZTdzBBUVNBZ0J5QUtJQUpCQW5ScUxRQUNhaUlDSUFKQklFOGJJUWNMQTBBZ0JSQVBSU0FFSUNCSmNRUkFJQVFnQ2lBRktBSUFJZ1lnQlNnQ0JDSUNkQ0FMZGtFQ2RHb2lEQzhCQURzQUFDQUVJQXd0QUFOcUlnTWdDaUFHSUFJZ0RDMEFBbW9pQW5RZ0MzWkJBblJxSWdRdkFRQTdBQUFnQlNBQ0lBUXRBQUpxTmdJRUlBTWdCQzBBQTJvaEJBd0JCU0FmUVFKcklRTURRQ0FGRUE4aEFpQUZLQUlBSVFZZ0JTZ0NCQ0VJSUFNZ0JFa2dBbkpGQkVBZ0JDQUtJQVlnQ0hRZ0MzWkJBblJxSWdJdkFRQTdBQUFnQlNBSUlBSXRBQUpxTmdJRUlBUWdBaTBBQTJvaEJBd0JDd3NEUUNBRElBUkpSUVJBSUFRZ0NpQUdJQWgwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVFnQWkwQUEyb2hCQ0FJSUFJdEFBSnFJUWdNQVFzTEFrQWdCQ0FmVHcwQUlBUWdDaUFHSUFoMElBdDJJZ0pCQW5ScUlnTXRBQUE2QUFBZ0F5MEFBMEVCUmdSQUlBZ2dBeTBBQW1vaENBd0JDeUFJUVI5TERRQkJJQ0FJSUFvZ0FrRUNkR290QUFKcUlnSWdBa0VnVHhzaENBdEJiRUZzUVd4QmJFRnNRV3hCYkVGc0lBRWdDRUVnUnhzZ0JTZ0NDQ0FGS0FJTVJ4c2dCMEVnUnhzZ0JTZ0NIQ0FGS0FJZ1J4c2dBRUVnUnhzZ0JTZ0NNQ0FGS0FJMFJ4c2dDVUVnUnhzZ0JTZ0NSQ0FGS0FKSVJ4c2hDUXdKQ3dBTEFBc0FDd0FMQUFzQUN3QUxBQXRCYkNFSkN5QUZRZEFBYWlRQUlBa0w3QkFCSG44akFFSFFBR3NpQlNRQVFXd2hDUUpBSUFOQkNra05BQUpBSUFNZ0FpOEFCQ0lHSUFJdkFBQWlCeUFDTHdBQ0lnaHFha0VHYWlJT1NRMEFJQVF2QVFJaER5QUZRVHhxSUFKQkJtb2lBaUFIRUEwaUNVR0lmMHNOQVNBRlFTaHFJQUlnQjJvaUFpQUlFQTBpQ1VHSWYwc05BU0FGUVJScUlBSWdDR29pQWlBR0VBMGlDVUdJZjBzTkFTQUZJQUlnQm1vZ0F5QU9heEFOSWdsQmlIOUxEUUVnQkVFRWFpRUtJQUFnQVdvaUhFRURheUVkUVFBZ0QydEJIM0VoQ3lBRktBSUlJUkVnQlNnQ0hDRVNJQVVvQWpBaEV5QUZLQUpFSVJRZ0JTZ0NCQ0VKSUFVb0FoZ2hCaUFGS0FJc0lRY2dCU2dDUUNFSUlBVW9BaEFoSGlBRktBSWtJUjhnQlNnQ09DRWdJQVVvQWt3aElTQUZLQUlBSVJVZ0JTZ0NGQ0VXSUFVb0FpZ2hGeUFGS0FJOElSaEJBU0VOSUFBZ0FVRURha0VDZGlJQ2FpSU9JQUpxSWc4Z0Ftb2lHU0VFSUE4aEFpQU9JUU1EUUNBTlJTQUVJQjFQY2tVRVFDQUtJQmdnQ0hRZ0MzWkJBWFJxSWd3dEFBRWhEU0FBSUF3dEFBQTZBQUFnQ2lBWElBZDBJQXQyUVFGMGFpSU1MUUFCSVJBZ0F5QU1MUUFBT2dBQUlBb2dGaUFHZENBTGRrRUJkR29pREMwQUFTRWFJQUlnREMwQUFEb0FBQ0FLSUJVZ0NYUWdDM1pCQVhScUlnd3RBQUVoR3lBRUlBd3RBQUE2QUFBZ0NpQVlJQWdnRFdvaUNIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFFZ0NpQVhJQWNnRUdvaUIzUWdDM1pCQVhScUlnd3RBQUVoRUNBRElBd3RBQUE2QUFFZ0NpQVdJQVlnR21vaURIUWdDM1pCQVhScUlnWXRBQUVoR2lBQ0lBWXRBQUE2QUFFZ0NpQVZJQWtnRzJvaUczUWdDM1pCQVhScUlna3RBQUVoSWlBRUlBa3RBQUE2QUFFZ0NDQU5haUVHUVFNaENRSi9JQlFnSVVrRVFFRURJUTBnQmd3QkN5QVVJQVpCQTNackloUW9BQUFoR0VFQUlRMGdCa0VIY1FzaENDQUhJQkJxSVFZZ0V5QWdTUVIvSUFZRklCTWdCa0VEZG1zaUV5Z0FBQ0VYUVFBaENTQUdRUWR4Q3lFSElBd2dHbW9oRENBSklBMXlJUkJCQXlFTkFuOGdFaUFmU1FSQUlBd2hCa0VEREFFTElBeEJCM0VoQmlBU0lBeEJBM1pySWhJb0FBQWhGa0VBQ3lBYklDSnFJUXdnRUhJaEVDQVJJQjVKQkg4Z0RBVWdFU0FNUVFOMmF5SVJLQUFBSVJWQkFDRU5JQXhCQjNFTElRa2dCRUVDYWlFRUlBSkJBbW9oQWlBRFFRSnFJUU1nQUVFQ2FpRUFJQTBnRUhKRklRME1BUXNMSUFVZ0J6WUNMQ0FGSUFnMkFrQWdCU0FHTmdJWUlBVWdDVFlDQkNBRklCUTJBa1FnQlNBVE5nSXdJQVVnRWpZQ0hDQUZJQkUyQWdnZ0JTQVlOZ0k4SUFVZ0Z6WUNLQ0FGSUJZMkFoUWdCU0FWTmdJQUlBQWdEa3NnQXlBUFMzSU5BRUZzSVFrZ0FpQVpTdzBCSUE1QkEyc2hDUU5BSUFWQlBHb1FEeUFBSUFsUGNrVUVRQ0FLSUFVb0Fqd2lCaUFGS0FKQUlnZDBJQXQyUVFGMGFpSUlMUUFCSVF3Z0FDQUlMUUFBT2dBQUlBb2dCaUFISUF4cUlnWjBJQXQyUVFGMGFpSUhMUUFBSVFnZ0JTQUdJQWN0QUFGcU5nSkFJQUFnQ0RvQUFTQUFRUUpxSVFBTUFRc0xBMEFnQlVFOGFoQVBJUWNnQlNnQ1BDRUdJQVVvQWtBaENTQUFJQTVQSUFkeVJRUkFJQW9nQmlBSmRDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0NTQUdMUUFCYWpZQ1FDQUFJQWM2QUFBZ0FFRUJhaUVBREFFTEN3TkFJQUFnRGs5RkJFQWdDaUFHSUFsMElBdDJRUUYwYWlJSExRQUJJQUFnQnkwQUFEb0FBQ0FBUVFGcUlRQWdDV29oQ1F3QkN3c2dEMEVEYXlFQUEwQWdCVUVvYWhBUElBQWdBMDF5UlFSQUlBb2dCU2dDS0NJR0lBVW9BaXdpQjNRZ0MzWkJBWFJxSWdndEFBRWhEaUFESUFndEFBQTZBQUFnQ2lBR0lBY2dEbW9pQm5RZ0MzWkJBWFJxSWdjdEFBQWhDQ0FGSUFZZ0J5MEFBV28yQWl3Z0F5QUlPZ0FCSUFOQkFtb2hBd3dCQ3dzRFFDQUZRU2hxRUE4aEJ5QUZLQUlvSVFZZ0JTZ0NMQ0VBSUFNZ0QwOGdCM0pGQkVBZ0NpQUdJQUIwSUF0MlFRRjBhaUlHTFFBQUlRY2dCU0FBSUFZdEFBRnFOZ0lzSUFNZ0J6b0FBQ0FEUVFGcUlRTU1BUXNMQTBBZ0F5QVBUMFVFUUNBS0lBWWdBSFFnQzNaQkFYUnFJZ2N0QUFFaENDQURJQWN0QUFBNkFBQWdBMEVCYWlFRElBQWdDR29oQUF3QkN3c2dHVUVEYXlFREEwQWdCVUVVYWhBUElBSWdBMDl5UlFSQUlBb2dCU2dDRkNJR0lBVW9BaGdpQjNRZ0MzWkJBWFJxSWdndEFBRWhEaUFDSUFndEFBQTZBQUFnQ2lBR0lBY2dEbW9pQm5RZ0MzWkJBWFJxSWdjdEFBQWhDQ0FGSUFZZ0J5MEFBV28yQWhnZ0FpQUlPZ0FCSUFKQkFtb2hBZ3dCQ3dzRFFDQUZRUlJxRUE4aEJ5QUZLQUlVSVFZZ0JTZ0NHQ0VESUFJZ0dVOGdCM0pGQkVBZ0NpQUdJQU4wSUF0MlFRRjBhaUlHTFFBQUlRY2dCU0FESUFZdEFBRnFOZ0lZSUFJZ0J6b0FBQ0FDUVFGcUlRSU1BUXNMQTBBZ0FpQVpUMFVFUUNBS0lBWWdBM1FnQzNaQkFYUnFJZ2N0QUFFaENDQUNJQWN0QUFBNkFBQWdBa0VCYWlFQ0lBTWdDR29oQXd3QkN3c0RRQ0FGRUE4Z0JDQWRUM0pGQkVBZ0NpQUZLQUlBSWdJZ0JTZ0NCQ0lHZENBTGRrRUJkR29pQnkwQUFTRUlJQVFnQnkwQUFEb0FBQ0FLSUFJZ0JpQUlhaUlDZENBTGRrRUJkR29pQmkwQUFDRUhJQVVnQWlBR0xRQUJhallDQkNBRUlBYzZBQUVnQkVFQ2FpRUVEQUVMQ3dOQUlBVVFEeUVISUFVb0FnQWhCaUFGS0FJRUlRSWdCQ0FjVHlBSGNrVUVRQ0FLSUFZZ0FuUWdDM1pCQVhScUlnWXRBQUFoQnlBRklBSWdCaTBBQVdvMkFnUWdCQ0FIT2dBQUlBUkJBV29oQkF3QkN3c0RRQ0FFSUJ4UFJRUkFJQW9nQmlBQ2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBRVFRRnFJUVFnQWlBSWFpRUNEQUVMQzBGc1FXeEJiRUZzUVd4QmJFRnNRV3dnQVNBQ1FTQkhHeUFGS0FJSUlBVW9BZ3hIR3lBRFFTQkhHeUFGS0FJY0lBVW9BaUJIR3lBQVFTQkhHeUFGS0FJd0lBVW9BalJIR3lBSlFTQkhHeUFGS0FKRUlBVW9Ba2hIR3lFSkRBRUxRV3doQ1FzZ0JVSFFBR29rQUNBSkMxZ0JBMzhDUUNBQUtBS1E2d0VpQVVVTkFDQUJLQUlBSUFGQnROVUJhaWdDQUNJQ0lBRkJ1TlVCYWlnQ0FDSURFQk1nQWdSQUlBTWdBU0FDRVFJQURBRUxJQUVRQmdzZ0FFRUFOZ0tnNndFZ0FFSUFOd09RNndFTDZRTUNCSDhDZmlBQVFRQkJLQkFESVFRZ0FrRUJRUVVnQXhzaUFFa0VRQ0FBRHdzZ0FVVUVRRUYvRHd0QkFTRUdBa0FDUUNBRFFRRkdEUUFnQXlFR0lBRW9BQUFpQlVHbzZyNXBSZzBBUVhZaEF5QUZRWEJ4UWREVXRNSUJSdzBCUVFnaEF5QUNRUWhKRFFFZ0FUVUFCQ0VJSUFSQkFUWUNGQ0FFSUFnM0F3QkJBQThMSUFFZ0FpQUdFQm9pQXlBQ1N3MEFJQVFnQXpZQ0dFRnlJUU1nQUNBQmFpSUZRUUZyTFFBQUlnSkJDSEVOQUNBQ1FTQnhJZ1pGQkVCQmNDRURJQVV0QUFBaUJVR25BVXNOQVNBRlFRZHhyVUlCSUFWQkEzWkJDbXF0aGlJSVFnT0lmaUFJZkNFSklBQkJBV29oQUFzZ0FrRUdkaUVGSUFKQkFuWkJBQ0VEQWtBQ1FBSkFBa0FnQWtFRGNVRUJhdzREQUFFQ0F3c2dBQ0FCYWkwQUFDRURJQUJCQVdvaEFBd0NDeUFBSUFGcUx3QUFJUU1nQUVFQ2FpRUFEQUVMSUFBZ0FXb29BQUFoQXlBQVFRUnFJUUFMUVFGeElRSUNmZ0pBQWtBQ1FBSkFJQVZCQVdzT0F3RUNBd0FMUW44Z0JrVU5BeG9nQUNBQmFqRUFBQXdEQ3lBQUlBRnFNd0FBUW9BQ2ZBd0NDeUFBSUFGcU5RQUFEQUVMSUFBZ0FXb3BBQUFMSVFnZ0JDQUNOZ0lnSUFRZ0F6WUNIQ0FFSUFnM0F3QkJBQ0VESUFSQkFEWUNGQ0FFSUFnZ0NTQUdHeUlJTndNSUlBUkNnSUFJSUFnZ0NFS0FnQWhhR3o0Q0VBc2dBd3RmQVFGL1FiaC9JUU1nQVVFQlFRVWdBaHNpQWs4RWZ5QUFJQUpxUVFGckxRQUFJZ0JCQTNGQkFuUkJvQjVxS0FJQUlBSnFJQUJCQkhaQkRIRkJzQjVxS0FJQWFpQUFRU0J4SWdGRmFpQUJRUVYySUFCQndBQkpjV29GUWJoL0N3c01BQ0FBSUFFZ0FrRUFFQmtMbHdNQ0JYOENmaU1BUVVCcUlnUWtBQUpBQTBBZ0FVRUZUd1JBQWtBZ0FDZ0FBRUZ3Y1VIUTFMVENBVVlFUUVKK0lRY2dBVUVJU1EwRUlBQW9BQVFpQWtGM1N3MEVJQUpCQ0dvaUF5QUJTdzBFSUFKQmdYOUpEUUVNQkFzZ0JFRVlhaUFBSUFFUUd5RUNRbjRnQkNrREdFSUFJQVFvQWl4QkFVY2JJQUliSWdkQ2ZWWU5BeUFISUFoOElnZ2dCMVJDZmlFSERRTUNRQUpBSUFGQkNFa05BQ0FBS0FBQVFYQnhRZERVdE1JQlJ3MEFJQUFvQUFRaUFrRjNTdzBGUWJoL0lBSkJDR29pQWlBQklBSkpHeUVEREFFTElBUkJHR29nQUNBQkVCc2lBa0dJZjBzRVFDQUNJUU1NQVF0QnVIOGhBeUFDRFFBZ0FTQUVLQUl3SWdKcklRVWdBQ0FDYWlFR0EwQWdCaUFGSUFSQkRHb1FIU0lEUVloL1N3MEJJQU5CQTJvaUFpQUZTd1JBUWJoL0lRTU1BZ3NnQlNBQ2F5RUZJQUlnQm1vaEJpQUVLQUlRUlEwQUN5QUVLQUk0Qkg5QnVIOGhBeUFGUVFSSkRRRWdCa0VFYWdVZ0Jnc2dBR3NoQXdzZ0EwR0lmMHNOQXdzZ0FTQURheUVCSUFBZ0Eyb2hBQXdCQ3d0Q2ZpQUlJQUViSVFjTElBUkJRR3NrQUNBSEMyUUJBWDlCdUg4aEF3SkFJQUZCQTBrTkFDQUFMUUFDSVFFZ0FpQUFMd0FBSWdCQkFYRTJBZ1FnQWlBQVFRRjJRUU54SWdNMkFnQWdBaUFBSUFGQkVIUnlRUU4ySWdBMkFnZ0NRQUpBSUFOQkFXc09Bd0lCQUFFTFFXd1BDeUFBSVFNTElBTUxSQUVDZnlBQklBSW9BZ1FpQXlBQktBSUVhaUlFTmdJRUlBQWdBMEVDZEVHZ0hXb29BZ0FnQVNnQ0FFRUFJQVJyZG5FMkFnQWdBUkFQR2lBQUlBSkJDR28yQWdRTHpnRUJCbjlCdW44aENnSkFJQUlvQWdRaUNDQUNLQUlBSWdscUlnMGdBU0FBYTBzTkFFRnNJUW9nQ1NBRUlBTW9BZ0FpQzJ0TERRQWdBQ0FKYWlJRUlBSW9BZ2dpREdzaEFpQUFJQUZCSUdzaUFDQUxJQWxCQUJBZ0lBTWdDU0FMYWpZQ0FBSkFBa0FnQkNBRmF5QU1Ud1JBSUFJaEJRd0JDeUFNSUFRZ0JtdExEUUlnQnlBSElBSWdCV3NpQW1vaUFTQUlhazhFUUNBRUlBRWdDQkFLR2d3Q0N5QUNJQWhxSVFnZ0JDQUJRUUFnQW1zUUNpQUNheUVFQ3lBRUlBQWdCU0FJUVFFUUlBc2dEU0VLQ3lBS0M4Y0VBUUovSUFBZ0Eyb2hCZ0pBSUFOQkIwd0VRQU5BSUFBZ0JrOE5BaUFBSUFJdEFBQTZBQUFnQUVFQmFpRUFJQUpCQVdvaEFnd0FDd0FMSUFSQkFVWUVRQUpBSUFBZ0Ftc2lCVUVIVFFSQUlBQWdBaTBBQURvQUFDQUFJQUl0QUFFNkFBRWdBQ0FDTFFBQ09nQUNJQUFnQWkwQUF6b0FBeUFBSUFJZ0JVRUNkQ0lGUWNBZWFpZ0NBR29pQWlnQUFEWUFCQ0FDSUFWQjRCNXFLQUlBYXlFQ0RBRUxJQUFnQWlrQUFEY0FBQXNnQWtFSWFpRUNJQUJCQ0dvaEFBc2dBU0FHVHdSQUlBQWdBMm9oQVNBRVFRRkhJQUFnQW10QkQwcHlSUVJBQTBBZ0FDQUNLUUFBTndBQUlBSkJDR29oQWlBQVFRaHFJZ0FnQVVrTkFBd0RDd0FMSUFBZ0Fpa0FBRGNBQUNBQUlBSXBBQWczQUFnZ0EwRVJTUTBCSUFCQkVHb2hBQU5BSUFBZ0Fpa0FFRGNBQUNBQUlBSXBBQmczQUFnZ0FDQUNLUUFnTndBUUlBQWdBaWtBS0RjQUdDQUNRU0JxSVFJZ0FFRWdhaUlBSUFGSkRRQUxEQUVMQWtBZ0FDQUJTd1JBSUFBaEFRd0JDeUFCSUFCcklRVUNRQ0FFUVFGSElBQWdBbXRCRDBweVJRUkFJQUloQXdOQUlBQWdBeWtBQURjQUFDQURRUWhxSVFNZ0FFRUlhaUlBSUFGSkRRQUxEQUVMSUFBZ0Fpa0FBRGNBQUNBQUlBSXBBQWczQUFnZ0JVRVJTQTBBSUFCQkVHb2hBQ0FDSVFNRFFDQUFJQU1wQUJBM0FBQWdBQ0FES1FBWU53QUlJQUFnQXlrQUlEY0FFQ0FBSUFNcEFDZzNBQmdnQTBFZ2FpRURJQUJCSUdvaUFDQUJTUTBBQ3dzZ0FpQUZhaUVDQ3dOQUlBRWdCazhOQVNBQklBSXRBQUE2QUFBZ0FVRUJhaUVCSUFKQkFXb2hBZ3dBQ3dBTEM2NEhBZ1YvQVg0akFFR0FBV3NpRVNRQUlCRWdBellDZkVGL0lROENRQUpBQWtBQ1FBSkFJQUlPQkFFQUF3SUVDeUFHUlFSQVFiaC9JUThNQkF0QmJDRVBJQVV0QUFBaUFpQURTdzBESUFnZ0FrRUNkQ0lDYWlnQ0FDRURJQUlnQjJvb0FnQWhBaUFBUVFBNkFBc2dBRUlBTndJQUlBQWdBallDRENBQUlBTTZBQW9nQUVFQU93RUlJQUVnQURZQ0FFRUJJUThNQXdzZ0FTQUpOZ0lBUVFBaER3d0NDeUFLUlFSQVFXd2hEd3dDQzBFQUlROGdDMFVnREVFWlNISU5BVUVJSUFSMFFRaHFJUUJCQUNFREEwQWdBQ0FEVFEwQ0lBTkJRR3NoQXd3QUN3QUxRV3doRHlBUklCRkIvQUJxSUJGQitBQnFJQVVnQmhBTUlnTkJpSDlMRFFBZ0VTZ0NlQ0lDSUFSTERRQWdFU2dDZkVFQmFpRUpJQUJCQ0dvaEMwR0FnQUlnQW5SQkVIVWhCVUVCSVJCQkFTQUNkQ0lQUVFGcklnb2hFZ05BSUFrZ0RrY0VRQUpBSUJFZ0RrRUJkQ0lFYWk4QkFDSU1RZi8vQTBZRVFDQUxJQkpCQTNScUlBNDJBZ1FnRWtFQmF5RVNRUUVoREF3QkN5QVFRUUFnQlNBTXdVb2JJUkFMSUFRZ0RXb2dERHNCQUNBT1FRRnFJUTRNQVFzTElBQWdBallDQkNBQUlCQTJBZ0FDUUNBS0lCSkdCRUFnRFVIcUFHb2hCa0VBSVJCQkFDRU1BMEFnQ1NBUVJnUkFJQTlCQTNZZ0QwRUJkbXBCQTJvaUJVRUJkQ0VFUVFBaERFRUFJUklEUUVFQUlRNGdEeUFTVFEwRUEwQWdEa0VDUndSQUlBc2dCU0FPYkNBTWFpQUtjVUVEZEdvZ0JpQU9JQkpxYWkwQUFEWUNCQ0FPUVFGcUlRNE1BUXNMSUJKQkFtb2hFaUFFSUF4cUlBcHhJUXdNQUFzQUJTQVJJQkJCQVhScUxnRUFJUVVnQmlBTWFpSUVJQk0zQUFCQkNDRU9BMEFnQlNBT1NnUkFJQVFnRG1vZ0V6Y0FBQ0FPUVFocUlRNE1BUXNMSUJOQ2dZS0VpSkNnd0lBQmZDRVRJQkJCQVdvaEVDQUZJQXhxSVF3TUFRc0FDd0FMSUE5QkEzWWdEMEVCZG1wQkEyb2hCVUVBSVJCQkFDRU9BMEFnQ1NBUVJnMEJRUUFoRENBUklCQkJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBTVJ3UkFJQXNnRGtFRGRHb2dFRFlDQkFOQUlBVWdEbW9nQ25FaURpQVNTdzBBQ3lBTVFRRnFJUXdNQVFzTElCQkJBV29oRUF3QUN3QUxJQUpCQVdvaEJVRUFJUXdEUUNBTUlBOUhCRUFnRFNBTElBeEJBM1JxSWdrb0FnUWlCRUVCZEdvaUFpQUNMd0VBSWdaQkFXbzdBUUFnQ1NBRklBWm5RV0J6YWlJQ09nQURJQWtnQmlBQ2RDQVBhenNCQUNBSklBZ2dCRUVDZENJQ2FpZ0NBRG9BQWlBSklBSWdCMm9vQWdBMkFnUWdERUVCYWlFTURBRUxDeUFCSUFBMkFnQWdBeUVQQ3lBUlFZQUJhaVFBSUE4TDdWb0NPMzhHZmlNQVFlQUJheUlFSkFBQ1FFR3c3QWtRQlNJRlJRUkFRVUFoQnd3QkN5QUZRZ0EzQXZUcUFTQUZRUUEyQXNUckFTQUZRUUEyQXJUckFTQUZRZ0EzQXB6ckFTQUZRUUEyQXJqcEFTQUZRUUEyQXF6c0NTQUZRZ0EzQXRUckFTQUZRZ0EzQXF6ckFTQUZRZ0EzQTRqckFTQUZRZ0EzQXVUcUFTQUZRZ0EzQXVUckFTQUZRWUdBZ01BQU5nSzg2d0VnQlVJQU53S2s2d0VnQlVIODZnRnFRUUEyQWdBZ0JVR1E2d0ZxUWdBM0F3QWdCUkFZSUFWQnJOVUJhaUVVSUFWQitPc0JhaUVjSUFWQnNPb0JhaUVpSUFWQm9EQnFJU29nQlVHWUlHb2hLeUFGUWFqUUFHb2hIaUFGUVJCcUlTd2dCVUVJYWlFb0lBVkJCR29oTFNBRlFjRHBBV29oS1NBRlFZanJBV29nQkVHVUFXb2hMeUFFUVl3QmFpRXdJQVJCaEFGcUlURWdCRUhjQUdvaE1pQUVRZFFBYWlFeklBUkJ6QUJxSVRRZ0FDRWRBa0FDUUFKQUFrQUNRQU5BUVFGQkJTQUZLQUxrNmdFYklRWUNRQU5BSUFNZ0Jra05BU0FDS0FBQVFYQnhRZERVdE1JQlJnUkFRYmgvSVFjZ0EwRUlTUTBJSUFJb0FBUWlEa0YzU3dSQVFYSWhCd3dKQ3lBRElBNUJDR29pQ1VrTkNDQU9RWUIvU3dSQUlBa2hCd3dKQ3lBRElBbHJJUU1nQWlBSmFpRUNEQUVMQ3lBRlFnQTNBcXpwQVNBRlFnQTNBK2pwQVNBRlFRQTJBcGpyQVNBRlFnQTNBNERxQVNBRlFnTTNBL2pwQVNBRlFiVHBBV3BDQURjQ0FDQUZRZkRwQVdwQ0FEY0RBQ0FGUWFqUUFHb2lDVUdNZ0lEZ0FEWUNBQ0FGUWF6UUFXcEI0QklwQWdBM0FnQWdCVUcwMEFGcVFlZ1NLQUlBTmdJQUlBVWdCVUVRYWpZQ0FDQUZJQVZCb0RCcU5nSUVJQVVnQlVHWUlHbzJBZ2dnQlNBSk5nSU1JQVZCQVVFRklBVW9BdVRxQVJzMkFyenBBUUpBSUFGRkRRQWdCU2dDck9rQklna2dIVVlOQUNBRklBazJBcmpwQVNBRklCMDJBcXpwQVNBRktBS3c2UUVoRGlBRklCMDJBckRwQVNBRklCMGdEaUFKYTJvMkFyVHBBUXRCdUg4aENTQURRUVZCQ1NBRktBTGs2Z0VpQmh0SkRRVWdBa0VCUVFVZ0Joc2dCaEFhSWc1QmlIOUxCRUFnRGlFSkRBVUxJQU1nRGtFRGFra05CU0FwSUFJZ0RpQUdFQmtpQmtHSWYwc0VRQ0FHSVFrTUJRc2dCZzBGQWtBQ1FDQUZLQUtvNndGQkFVY05BQ0FGS0FLazZ3RWlDVVVOQUNBRktBS1U2d0ZGRFFBZ0NTZ0NCRUVCYXlJSElBVW9BdHpwQVNJS3JVS0hsYSt2bUxiZW01NS9ma0xKejlteThlVzY2aWVGUWhlSlFzL1cwNzdTeDZ2WlFuNUMrZlBkOFpuMm1hc1dmQ0kvUWlHSUlEK0ZRcy9XMDc3U3g2dlpRbjRpUDBJZGlDQS9oVUw1ODkzeG1mYVpxeForSWo5Q0lJZ2dQNFduY1NFR0lBa29BZ0FoRlFOQVFRQWhDQUpBSUJVZ0JrRUNkR29vQWdBaUNVVU5BQ0FKS0FJSVFRaEpEUUFnQ1NnQ0JDSVNLQUFBUWJmSXd1RitSdzBBSUJJb0FBUWhDQXNnQ0NBS1J3UkFJQVlnQjNGQkFXb2hCaUFJRFFFTEN5QUpSUTBBSUFVUUdDQUZRWDgyQXFEckFTQUZJQWsyQXBUckFTQUZJQVVvQXR6cEFTSUlOZ0tZNndFTUFRc2dCU2dDM09rQklRZ0xBa0FnQ0VVTkFDQUZLQUtZNndFZ0NFWU5BRUZnSVFrTUJnc0NRQ0FGS0FMZzZRRUVRQ0FGSUFVb0F1anFBU0lKUlRZQzdPb0JJQWtOQVNBRlF2bnEwTkRueWFIazRRQTNBNmpxQVNBRlFnQTNBNkRxQVNBRlFzL1cwNzdTeDZ2WlFqY0RtT29CSUFWQzF1dUM3dXI5aWZYZ0FEY0RrT29CSUFWQ0FEY0RpT29CSUNKQkFFRW9FQU1hREFFTElBVkJBRFlDN09vQkN5QUJJQjFxSVNVZ0JTQUZLUVBvNlFFZ0RxMThOd1BvNlFFZ0F5QU9heUVESUFJZ0Rtb2hBaUFkSVE0RFFDQUNJQU1nQkVFc2FoQWRJaFZCaUg5TEJFQWdGU0VKREFZTElBTkJBMnNpTlNBVlNRMEVJQUpCQTJvaEcwRnNJUWtDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FDQUVLQUlzRGdNQ0FRQVZDeUFWUWYvL0Iwc05FeUFWUVFOSkRSSWdCU2tEeU9rQklUOENRQUpBSUJzdEFBQWlDVUVEY1NJYVFRRnJEZ01HQVFBSEN5QUZLQUtBNmdFTkFFRmlJUWtNRlFzZ0ZVRUZTUTBTSUJzb0FBQWhBd0ovQWtBQ1FBSkFJQWxCQW5aQkEzRWlDVUVDYXc0Q0FRSUFDeUFKUVFCSElRY2dBMEVFZGtIL0IzRWhDMEVESVFZZ0EwRU9ka0gvQjNFTUFndEJCQ0VHSUFOQkJIWkIvLzhBY1NFTFFRRWhCeUFEUVJKMkRBRUxJQU5CQkhaQi8vOFBjU0lMUVlDQUNFc05FMEVCSVFkQkJTRUdJQUl0QUFkQkNuUWdBMEVXZG5JTElnZ2dCbW9pQ1NBVlN3MFNBa0FnQzBHQkJra05BQ0FGS0FLYzZ3RkZEUUJCQUNFREEwQWdBMEdEZ0FGTERRRWdBMEZBYXlFRERBQUxBQXNnQmlBYmFpRVBJQnBCQTBjTkJpQUZLQUlNSWdJdEFBRkJDSFFoQXlBSERRY2dBMFVOQ0NBRVFmQUFhaUFQSUFnUURTSURRWWgvU3cwSklBSkJCR29oQmlBTElCeHFJaEpCQTJzaENrRUFJQUl2QVFKclFSOXhJUWNnSENFREEwQWdCRUh3QUdvUUQwVWdBeUFLU1hFRVFDQURJQVlnQkNnQ2NDSUlJQVFvQW5RaUQzUWdCM1pCQW5ScUlnSXZBUUE3QUFBZ0F5QUNMUUFEYWlJRElBWWdDQ0FQSUFJdEFBSnFJZ2gwSUFkMlFRSjBhaUlDTHdFQU93QUFJQVFnQ0NBQ0xRQUNhallDZENBRElBSXRBQU5xSVFNTUFRVWdFa0VDYXlFSUEwQWdCRUh3QUdvUUR5RVBJQVFvQW5BaENpQUVLQUowSVFJZ0F5QUlTeUFQY2tVRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUNpOEJBRHNBQUNBRUlBSWdDaTBBQW1vMkFuUWdBeUFLTFFBRGFpRUREQUVMQ3dOQUlBTWdDRTBFUUNBRElBWWdDaUFDZENBSGRrRUNkR29pRHk4QkFEc0FBQ0FESUE4dEFBTnFJUU1nQWlBUExRQUNhaUVDREFFTEN3SkFJQU1nRWs4TkFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUF5MEFBRG9BQUNBRExRQURRUUZHQkVBZ0FpQURMUUFDYWlFQ0RBRUxJQUpCSDBzTkFFRWdJQUlnQXkwQUFtb2lBaUFDUVNCUEd5RUNDMEZzUVd3Z0N5QUVLQUo0SUFRb0FueEhHeUFDUVNCSEd5RUREQXNMQUFzQUN5QUVLQUkwSWdJZ0pTQU9hMHNOQ2lBT1JRUkFRUUFoQ1NBQ0RRSU1EZ3NnRGlBYkxRQUFJQUlRQXhvZ0FpRUpEQXdMSUJVZ0pTQU9hMHNOQ1NBT0RRRkJBQ0VKSUJWRkRRd0xRYlovSVFrTUVRc2dEaUFiSUJVUUFob2dGU0VKREFvTElCd2dHd0ovQWtBQ1FBSkFJQWxCQW5aQkEzRkJBV3NPQXdFQUFnQUxJQWxCQTNZaEEwRUJEQUlMSUJzdkFBQkJCSFloQTBFQ0RBRUxJQlZCQkVrTkRpQUNMd0FESUFJdEFBVkJFSFJ5SWdKQmo0Q0FBVXNORGlBQ1FRUjJJUU5CQXdzaUFtb3RBQUFnQTBFZ2FoQURJUWtnQlNBRE5nS0E2d0VnQlNBSk5nTHc2Z0VnQWtFQmFpRUpEQVVMSUJVQ2Z3SkFBa0FDUUNBSlFRSjJRUU54UVFGckRnTUJBQUlBQ3lBSlFRTjJJUU5CQVF3Q0N5QWJMd0FBUVFSMklRTkJBZ3dCQ3lBQ0x3QURJQUl0QUFWQkVIUnlRUVIySVFOQkF3c2lBaUFEYWlJSlFTQnFTUVJBSUFrZ0ZVc05EU0FjSUFJZ0cyb2dBeEFDSVFJZ0JTQUROZ0tBNndFZ0JTQUNOZ0x3NmdFZ0FpQURhaUlDUWdBM0FCZ2dBa0lBTndBUUlBSkNBRGNBQ0NBQ1FnQTNBQUFNQlFzZ0JTQUROZ0tBNndFZ0JTQUNJQnRxTmdMdzZnRU1CQXNnQjBVRVFDQWVJQThnQ0NBVUVCUWlBa0dJZjBzZ0FpQUlUM0lORENBY0lBc2dBaUFQYWlBSUlBSnJJQjRRRlNFRERBTUxJQXRGSUFoRmNnMExJQXRCQ0hZaUF5QUlJQXRKQkg4Z0NFRUVkQ0FMYmdWQkR3dEJHR3dpQWtHTUNHb29BZ0JzSUFKQmlBaHFLQUlBYWlJR1FRTjJJQVpxSUFKQmdBaHFLQUlBSUFKQmhBaHFLQUlBSUFOc2Fra0VRQ01BUVJCckloQWtBQ0FlS0FJQUlRTWdGRUh3QkdwQkFFSHNBQkFESVFaQlZDRUNBa0FnQTBIL0FYRWlERUVNU3cwQUFrQWdGRUhjQ1dvZ0JpQVFRUWhxSUJCQkRHb2dEeUFJSUJSQjNBdHFJaGNRQ3lJU1FZaC9TdzBBSUJBb0Fnd2lCaUFNU3cwQklCUkJxQVZxSVEwZ0ZFR2tCV29oTmlBZVFRUnFJUkVnQTBHQWdJQjRjU0UzSUFaQkFXb2lFeUVDSUFZaEF3TkFJQUlpQjBFQmF5RUNJQU1pQ2tFQmF5RURJQlFnQ2tFQ2RHb29BdkFFUlEwQUMwRUJJQWNnQjBFQlRSc2hGa0VBSVFkQkFTRUNBMEFnQWlBV1J3UkFJQlFnQWtFQ2RDSURhaWdDOEFRaEdDQURJQTFxSUFjMkFnQWdBa0VCYWlFQ0lBY2dHR29oQnd3QkN3c2dEU0FITmdJQVFRQWhBaUFRS0FJSUlRTURRQ0FDSUFOSEJFQWdEU0FDSUJScVFkd0phaTBBQUNJWVFRSjBhaUlaSUJrb0FnQWlHVUVCYWpZQ0FDQVVJQmxCQVhScUloa2dHRG9BM1FVZ0dTQUNPZ0RjQlNBQ1FRRnFJUUlNQVFzTFFRQWhBeUFOUVFBMkFnQWdEQ0FHUVg5emFpRUdRUUVoQWdOQUlBSWdGa2NFUUNBVUlBSkJBblJxSWcwZ0F6WUNBQ0FOS0FMd0JDQUNJQVpxZENBRGFpRURJQUpCQVdvaEFnd0JDd3NnRENBVElBcHJJZ1pyUVFGcUlRb2dCaUVEQTBBZ0F5QUtTUVJBSUJRZ0EwRTBiR29oRFVFQklRSURRQ0FDSUJaSEJFQWdEU0FDUVFKMEloaHFJQlFnR0dvb0FnQWdBM1kyQWdBZ0FrRUJhaUVDREFFTEN5QURRUUZxSVFNTUFRc0xJQmNnRkVFMEVBSWhPQ0FVUVpBTWFpRTVJQk1nREdzaE9pQVVRZHdGYWlFWFFRQWhDZ05BQWtBQ1FDQUhJQXBIQkVCQkFTQU1JQk1nRnlBS1FRRjBhaUlDTFFBQklnMXJJZ05ySWhoMElSa2dBaTBBQUNFV0lEZ2dEVUVDZEdvaUh5Z0NBQ0VDSUFZZ0dFMEVRQ0EyUVFFZ0F5QTZhaUlOSUExQkFVd2JJaUJCQW5RaUpHb29BZ0FoRFNBNUlCUWdBMEUwYkdwQk5CQUNJU0VnRFVFQmRDRW1JQkVnQWtFQ2RHb2hJeUFnUVFGTkRRSWdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVnSUNFZ0pHb29BZ0FoSkVFQUlRSURRQ0FDSUNSR0RRTWdJeUFDUVFKMGFpQWdOZ0VBSUFKQkFXb2hBZ3dBQ3dBTElBSWdBaUFaYWlJTklBSWdEVXNiSVEwZ0EwRVFkRUdBZ1B3SGNTQVdja0dBZ0lBSWNpRURBMEFnQWlBTlJnMERJQkVnQWtFQ2RHb2dBellCQUNBQ1FRRnFJUUlNQUFzQUN5QWVJQXhCRUhRZ04zSWdESEpCZ0FKeU5nSUFEQU1MSUFjZ0RXc2hKQ0FYSUNacUlTWkJBQ0VOQTBBZ0RTQWtSZzBCUVFFZ0dDQVRJQ1lnRFVFQmRHb2lKeTBBQVNJQ2F5STdhM1FpUENBaElBSkJBblJxSWlBb0FnQWlBbW9oUFNBRElEdHFRUkIwUVlDQS9BZHhJQ2N0QUFCQkNIUnlJQlp5UVlDQWdCQnlJU2NEUUNBaklBSkJBblJxSUNjMkFRQWdBa0VCYWlJQ0lEMUpEUUFMSUNBZ0lDZ0NBQ0E4YWpZQ0FDQU5RUUZxSVEwTUFBc0FDeUFmSUI4b0FnQWdHV28yQWdBZ0NrRUJhaUVLREFBTEFBc2dFaUVDQ3lBUVFSQnFKQUFnQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZpRUREQU1MSUI0Z0R5QUlJQlFRRkNJQ1FZaC9TeUFDSUFoUGNnMExJQndnQ3lBQ0lBOXFJQWdnQW1zZ0hoQVhJUU1NQWdzZ0F3UkFJQndnQ3lBUElBZ2dBaEFXSVFNTUFnc2dIQ0FMSUE4Z0NDQUNFQmNoQXd3QkN5QWNJQXNnRHlBSUlBSVFGU0VEQ3lBRFFZaC9TdzBJSUFVZ0N6WUNnT3NCSUFVZ0hEWUM4T29CSUFWQkFUWUNnT29CSUJwQkFrWUVRQ0FGSUI0MkFnd0xJQXNnSEdvaUFrSUFOd0FBSUFKQ0FEY0FHQ0FDUWdBM0FCQWdBa0lBTndBSUlBbEJpSDlMRFFvTElBa2dGVVlOQ0NBVklBbHJJUVlnQlNnQ25Pc0JJUW9DUUNBSklCdHFJZ010QUFBaUQwVUVRRUVCSVFKQkFDRVBRYmgvSVFrZ0JrRUJSZzBCREFzTEFuOGdBMEVCYWlBUHdDSUNRUUJPRFFBYUlBSkJmMFlFUUNBR1FRTklEUXNnQXk4QUFVR0EvZ0ZxSVE4Z0EwRURhZ3dCQ3lBR1FRSklEUW9nQXkwQUFTQVBRUWgwY2tHQWdBSnJJUThnQTBFQ2Fnc2hFa0c0ZnlFSklCSkJBV29pQWlBVklCdHFJZ2RMRFFvZ0xDQUZJQkl0QUFBaUVrRUdka0VqUVFrZ0FpQUhJQUpyUWNBUVFkQVJRZkFTSUFVb0FvVHFBU0FLSUE4Z0ZCQWhJZ2xCaUg5TERRZ2dLeUFvSUJKQkJIWkJBM0ZCSDBFSUlBSWdDV29pQWlBSElBSnJRWUFMUVlBTVFZQVhJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQ0VHSWYwc05DRUZzSVFrZ0tpQXRJQkpCQW5aQkEzRkJORUVKSUFJZ0NHb2lBaUFISUFKclFZQU5RZUFPUVpBWklBVW9Bb1RxQVNBRktBS2M2d0VnRHlBVUVDRWlCMEdJZjBzTkNpQUNJQWRxSUFOcklnSWhDU0FDUVloL1N3MEtDeUFPSUE5QkFFeHlEUUVMUWJwL0lRa01DQXNnSlNBT2F5RUpJQVlnQW1zaEJpQUNJQU5xSVFjQ1FBSkFBa0FnQ2tVRVFDQVBRUWxJSUFVcEE4anBBVUtCZ0lBSVZISU5BaUFvS0FJQUlnSkJDR29oRWlBQ0tBSUVJUXBCQUNFRFFRQWhBZ05BSUFNZ0NuWkZCRUFnQWlBU0lBTkJBM1JxTFFBQ1FSWkxhaUVDSUFOQkFXb2hBd3dCQ3dzZ0JVRUFOZ0tjNndFZ0FrRUlJQXByZEVFVVR3MEJEQU1MSUFWQkFEWUNuT3NCQ3lBRUlBVW9BdkRxQVNJRE5nTGNBU0FKSUE1cUlSWWdBeUFGS0FLQTZ3RnFJUmNDUUNBUFJRUkFJQTRoQnd3QkN5QUZLQUs0NlFFaEdpQUZLQUswNlFFaEdDQUZLQUt3NlFFaEVpQUZRUUUyQW9UcUFVRUFJUU1EUUNBRFFRTkhCRUFnQkNBRFFRSjBJZ0pxSUFJZ0JXcEJyTkFCYWlnQ0FEWUNaQ0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRVGhxSWdJZ0J5QUdFQTFCaUg5TERRTkJDQ0FQSUE5QkNFNGJJUjhnTkNBQ0lBVW9BZ0FRSGlBeklBSWdCU2dDQ0JBZUlESWdBaUFGS0FJRUVCNGdEaUFTYXlFWlFRQWhDQU5BSUFSQk9Hb1FEMEVEUmlBSUlCOU9ja1VFUUNBRUtBSlFJQVFvQWt4QkEzUnFLUUlBSWtDbklnZEJFSFlpRVVIL0FYRWhDeUFFS0FKZ0lBUW9BbHhCQTNScUtRSUFJa0duSWd4QkVIWWlJVUgvQVhFaEVDQUVLQUpZSUFRb0FsUkJBM1JxS1FJQUlrSkNJSWluSVFZZ1FVSWdpQ0JBUWlDSXB5RURBa0FnUWtJUWlLY2lDa0gvQVhFaUFrRUNUd1JBQWtBZ0FrRVpTU0EvUW9HQWdCQlVja1VFUUNBRVFTQWdCQ2dDUENJS2F5SU5JQUlnQWlBTlN4c2lFeUFLYWpZQ1BDQUdJQVFvQWpnZ0NuUkJBQ0FUYTNZZ0FpQVRheUlUZEdvaENpQUVRVGhxRUE4YUlBSWdEVTBOQVNBRUlBUW9BandpQWlBVGFqWUNQQ0FFS0FJNElBSjBRUUFnRTJ0MklBcHFJUW9NQVFzZ0JDQUNJQVFvQWp3aURXbzJBandnQkNnQ09DQU5kRUVBSUFwcmRpQUdhaUVLSUFSQk9Hb1FEeG9MSUFRcEFtUWhSQ0FFSUFvMkFtUWdCQ0JFTndKb0RBRUxBa0FnQWtVRVFDQURCRUFnQkNnQ1pDRUtEQU1MSUFRb0FtZ2hDZ3dCQ3lBRUlBUW9BandpQWtFQmFqWUNQQUovSUFZZ0EwVnFJQVFvQWpnZ0FuUkJIM1pxSWdKQkEwWUVRQ0FFS0FKa1FRRnJEQUVMSUFKQkFuUWdCR29vQW1RTElnWkZJQVpxSVFvZ0FrRUJSd1JBSUFRZ0JDZ0NhRFlDYkFzTElBUWdCQ2dDWkRZQ2FDQUVJQW8yQW1RTHB5RUNJRUZDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lHSUJCcU5nSThJQVFvQWpnZ0JuUkJBQ0FoYTNZZ0Ftb2hBZ3NnQ3lBUWFrRVVUd1JBSUFSQk9Hb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lBdHFOZ0k4SUFRb0FqZ2dCblJCQUNBUmEzWWdBMm9oQXdzZ0JFRTRhaEFQR2lBRUlBUW9BamdpQmtFQUlBZEJHSFlpQ3lBRUtBSThhaUlRYTNZZ0MwRUNkRUdnSFdvb0FnQnhJQWRCLy84RGNXbzJBa3dnQkNBUUlBeEJHSFlpQjJvaUN6WUNQQ0FFSUFkQkFuUkJvQjFxS0FJQUlBWkJBQ0FMYTNaeElBeEIvLzhEY1dvMkFsd2dCRUU0YWhBUEdpQUVJRUtuSWdaQkdIWWlCeUFFS0FJOGFpSUxOZ0k4SUFRZ0IwRUNkRUdnSFdvb0FnQWdCQ2dDT0VFQUlBdHJkbkVnQmtILy93TnhhallDVkNBRVFmQUFhaUFJUVF4c2FpSUdJQW8yQWdnZ0JpQUNOZ0lFSUFZZ0F6WUNBQ0FJUVFGcUlRZ2dBeUFaYWlBQ2FpRVpEQUVMQ3lBSUlCOUlEUU1nRmtFZ2F5RWhJQTRoQndOQUlBUkJPR29RRDBFRFJpQUlJQTlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ1pCRUhZaUkwSC9BWEVoQ2lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklnMUJFSFlpSUVIL0FYRWhFeUFFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRTWdRVUlnaUNCQVFpQ0lweUVMQWtBZ1FrSVFpS2NpREVIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSU1heUlSSUFJZ0FpQVJTeHNpRUNBTWFqWUNQQ0FESUFRb0FqZ2dESFJCQUNBUWEzWWdBaUFRYXlJTWRHb2hFQ0FFUVRocUVBOGFJQUlnRVUwTkFTQUVJQVFvQWp3aUFpQU1hallDUENBRUtBSTRJQUowUVFBZ0RHdDJJQkJxSVJBTUFRc2dCQ0FDSUFRb0Fqd2lFR28yQWp3Z0JDZ0NPQ0FRZEVFQUlBeHJkaUFEYWlFUUlBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlCQTJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FMQkVBZ0JDZ0NaQ0VRREFNTElBUW9BbWdoRUF3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBTWdDMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ05GSUFOcUlSQWdBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUJBMkFtUUxweUVNSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJQ0lCTnFOZ0k4SUFRb0FqZ2dBblJCQUNBZ2EzWWdER29oREFzZ0NpQVRha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQXBxTmdJOElBUW9BamdnQW5SQkFDQWphM1lnQzJvaEN3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUFrRUFJQVpCR0hZaUF5QUVLQUk4YWlJS2EzWWdBMEVDZEVHZ0hXb29BZ0J4SUFaQi8vOERjV28yQWt3Z0JDQUtJQTFCR0hZaUEyb2lCallDUENBRUlBTkJBblJCb0IxcUtBSUFJQUpCQUNBR2EzWnhJQTFCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnSkJHSFlpQXlBRUtBSThhaUlHTmdJOElBUWdBMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQVpyZG5FZ0FrSC8vd054YWpZQ1ZBSkFBa0FDUUNBRUtBTGNBU0lESUFSQjhBQnFJQWhCQjNGQkRHeHFJaE1vQWdBaUVXb2lJeUFYU3cwQUlBY2dFeWdDQkNJTklCRnFJZ3BxSUNGTERRQWdDa0VnYWlBV0lBZHJUUTBCQ3lBRUlCTW9BZ2cyQWhnZ0JDQVRLUUlBTndNUUlBY2dGaUFFUVJCcUlBUkIzQUZxSUJjZ0VpQVlJQm9RSHlFS0RBRUxJQWNnRVdvaEFpQVRLQUlJSVFZZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNBSkFJQkZCRVVrTkFDQUhJQU1wQUJBM0FCQWdCeUFES1FBWU53QVlJQkZCRUd0QkVVZ05BQ0FEUVJCcUlRTWdCMEVnYWlFUkEwQWdFU0FES1FBUU53QUFJQkVnQXlrQUdEY0FDQ0FSSUFNcEFDQTNBQkFnRVNBREtRQW9Od0FZSUFOQklHb2hBeUFSUVNCcUloRWdBa2tOQUFzTElBSWdCbXNoQXlBRUlDTTJBdHdCSUFJZ0Vtc2dCa2tFUUNBR0lBSWdHR3RMRFFjZ0dpQWFJQU1nRW1zaUEyb2lFU0FOYWs4RVFDQUNJQkVnRFJBS0dnd0NDeUFESUExcUlRMGdBaUFSUVFBZ0Eyc1FDaUFEYXlFQ0lCSWhBd3NnQmtFUVR3UkFJQUlnQXlrQUFEY0FBQ0FDSUFNcEFBZzNBQWdnRFVFUlNBMEJJQUlnRFdvaEJpQUNRUkJxSVFJRFFDQUNJQU1wQUJBM0FBQWdBaUFES1FBWU53QUlJQUlnQXlrQUlEY0FFQ0FDSUFNcEFDZzNBQmdnQTBFZ2FpRURJQUpCSUdvaUFpQUdTUTBBQ3d3QkN3SkFJQVpCQjAwRVFDQUNJQU10QUFBNkFBQWdBaUFETFFBQk9nQUJJQUlnQXkwQUFqb0FBaUFDSUFNdEFBTTZBQU1nQWlBRElBWkJBblFpQmtIQUhtb29BZ0JxSWdNb0FBQTJBQVFnQXlBR1FlQWVhaWdDQUdzaEF3d0JDeUFDSUFNcEFBQTNBQUFMSUExQkNVa05BQ0FDSUExcUlSRWdBa0VJYWlJR0lBTkJDR29pQTJ0QkQwd0VRQU5BSUFZZ0F5a0FBRGNBQUNBRFFRaHFJUU1nQmtFSWFpSUdJQkZKRFFBTUFnc0FDeUFHSUFNcEFBQTNBQUFnQmlBREtRQUlOd0FJSUExQkdVZ05BQ0FDUVJocUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFSU1EwQUN3c2dDa0dJZjBzRVFDQUtJUWtNQmdVZ0V5QVFOZ0lJSUJNZ0REWUNCQ0FUSUFzMkFnQWdDRUVCYWlFSUlBY2dDbW9oQnlBTElCbHFJQXhxSVJrTUFnc0FDd3NnQ0NBUFNBMERJQWdnSDJzaEJnTkFBa0FnQmlBUFRnUkFRUUFoQXdOQUlBTkJBMFlOQWlBRklBTkJBblFpQW1wQnJOQUJhaUFDSUFScUtBSmtOZ0lBSUFOQkFXb2hBd3dBQ3dBTEFrQUNRQUpBSUFRb0F0d0JJZ01nQkVId0FHb2dCa0VIY1VFTWJHb2lDQ2dDQUNJTWFpSVFJQmRMRFFBZ0J5QUlLQUlFSWdzZ0RHb2lDbW9nSVVzTkFDQUtRU0JxSUJZZ0IydE5EUUVMSUFRZ0NDZ0NDRFlDS0NBRUlBZ3BBZ0EzQXlBZ0J5QVdJQVJCSUdvZ0JFSGNBV29nRnlBU0lCZ2dHaEFmSVFvTUFRc2dCeUFNYWlFQ0lBZ29BZ2doQ0NBSElBTXBBQUEzQUFBZ0J5QURLUUFJTndBSUFrQWdERUVSU1EwQUlBY2dBeWtBRURjQUVDQUhJQU1wQUJnM0FCZ2dERUVRYTBFUlNBMEFJQU5CRUdvaEF5QUhRU0JxSVF3RFFDQU1JQU1wQUJBM0FBQWdEQ0FES1FBWU53QUlJQXdnQXlrQUlEY0FFQ0FNSUFNcEFDZzNBQmdnQTBFZ2FpRURJQXhCSUdvaURDQUNTUTBBQ3dzZ0FpQUlheUVESUFRZ0VEWUMzQUVnQWlBU2F5QUlTUVJBSUFnZ0FpQVlhMHNOQnlBYUlCb2dBeUFTYXlJRGFpSU1JQXRxVHdSQUlBSWdEQ0FMRUFvYURBSUxJQU1nQzJvaEN5QUNJQXhCQUNBRGF4QUtJQU5ySVFJZ0VpRURDeUFJUVJCUEJFQWdBaUFES1FBQU53QUFJQUlnQXlrQUNEY0FDQ0FMUVJGSURRRWdBaUFMYWlFSUlBSkJFR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBaEpEUUFMREFFTEFrQWdDRUVIVFFSQUlBSWdBeTBBQURvQUFDQUNJQU10QUFFNkFBRWdBaUFETFFBQ09nQUNJQUlnQXkwQUF6b0FBeUFDSUFNZ0NFRUNkQ0lJUWNBZWFpZ0NBR29pQXlnQUFEWUFCQ0FESUFoQjRCNXFLQUlBYXlFRERBRUxJQUlnQXlrQUFEY0FBQXNnQzBFSlNRMEFJQUlnQzJvaERDQUNRUWhxSWdnZ0EwRUlhaUlEYTBFUFRBUkFBMEFnQ0NBREtRQUFOd0FBSUFOQkNHb2hBeUFJUVFocUlnZ2dERWtOQUF3Q0N3QUxJQWdnQXlrQUFEY0FBQ0FJSUFNcEFBZzNBQWdnQzBFWlNBMEFJQUpCR0dvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQXhKRFFBTEN5QUtRWWgvU3dSQUlBb2hDUXdHQlNBR1FRRnFJUVlnQnlBS2FpRUhEQUlMQUFzTElBUW9BdHdCSVFNTFFicC9JUWtnRnlBRGF5SUNJQllnQjJ0TERRSWdCd1IvSUFjZ0F5QUNFQUlnQW1vRlFRQUxJQTVySVFrTUFnc2dCVUVBTmdLYzZ3RUxJQVFnQlNnQzhPb0JJZ00yQXR3QklBa2dEbW9oRENBRElBVW9Bb0RyQVdvaEVBSkFJQTlGQkVBZ0RpRUdEQUVMSUFVb0FyanBBU0VOSUFVb0FyVHBBU0VUSUFVb0FyRHBBU0VTSUFWQkFUWUNoT29CUVFBaEF3TkFJQU5CQTBjRVFDQUVJQU5CQW5RaUFtb2dBaUFGYWtHczBBRnFLQUlBTmdLY0FTQURRUUZxSVFNTUFRc0xRV3doQ1NBRVFmQUFhaUlDSUFjZ0JoQU5RWWgvU3cwQklERWdBaUFGS0FJQUVCNGdNQ0FDSUFVb0FnZ1FIaUF2SUFJZ0JTZ0NCQkFlSUF4QklHc2hHQ0FPSVFZRFFDQUVLQUtJQVNBRUtBS0VBVUVEZEdvcEFnQWlRS2NpQ2tFUWRpSVpRZjhCY1NFTElBUW9BcGdCSUFRb0FwUUJRUU4wYWlrQ0FDSkJweUlXUVJCMkloOUIvd0Z4SVJvZ0JDZ0NrQUVnQkNnQ2pBRkJBM1JxS1FJQUlrSkNJSWluSVFjZ1FVSWdpQ0JBUWlDSXB5RURBa0FnUWtJUWlLY2lDRUgvQVhFaUFrRUNUd1JBQWtBZ0FrRVpTU0EvUW9HQWdCQlVja1VFUUNBRVFTQWdCQ2dDZENJSWF5SVJJQUlnQWlBUlN4c2lGeUFJYWpZQ2RDQUhJQVFvQW5BZ0NIUkJBQ0FYYTNZZ0FpQVhheUlYZEdvaENDQUVRZkFBYWhBUEdpQUNJQkZORFFFZ0JDQUVLQUowSWdJZ0YybzJBblFnQkNnQ2NDQUNkRUVBSUJkcmRpQUlhaUVJREFFTElBUWdBaUFFS0FKMEloRnFOZ0owSUFRb0FuQWdFWFJCQUNBSWEzWWdCMm9oQ0NBRVFmQUFhaEFQR2dzZ0JDa0NuQUVoUkNBRUlBZzJBcHdCSUFRZ1JEY0NvQUVNQVFzQ1FDQUNSUVJBSUFNRVFDQUVLQUtjQVNFSURBTUxJQVFvQXFBQklRZ01BUXNnQkNBRUtBSjBJZ0pCQVdvMkFuUUNmeUFISUFORmFpQUVLQUp3SUFKMFFSOTJhaUlDUVFOR0JFQWdCQ2dDbkFGQkFXc01BUXNnQWtFQ2RDQUVhaWdDbkFFTElnZEZJQWRxSVFnZ0FrRUJSd1JBSUFRZ0JDZ0NvQUUyQXFRQkN3c2dCQ0FFS0FLY0FUWUNvQUVnQkNBSU5nS2NBUXVuSVFJZ1FVS0FnUHdIZzFCRkJFQWdCQ0FFS0FKMElnY2dHbW8yQW5RZ0JDZ0NjQ0FIZEVFQUlCOXJkaUFDYWlFQ0N5QUxJQnBxUVJSUEJFQWdCRUh3QUdvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NkQ0lISUF0cU5nSjBJQVFvQW5BZ0IzUkJBQ0FaYTNZZ0Eyb2hBd3NnQkVId0FHb1FEeG9nQkNBRUtBSndJZ2RCQUNBS1FSaDJJZ3NnQkNnQ2RHb2lHbXQySUF0QkFuUkJvQjFxS0FJQWNTQUtRZi8vQTNGcU5nS0VBU0FFSUJvZ0ZrRVlkaUlLYWlJTE5nSjBJQVFnQ2tFQ2RFR2dIV29vQWdBZ0IwRUFJQXRyZG5FZ0ZrSC8vd054YWpZQ2xBRWdCRUh3QUdvUUR4b2dCQ0JDcHlJSFFSaDJJZ29nQkNnQ2RHb2lDellDZENBRUlBcEJBblJCb0IxcUtBSUFJQVFvQW5CQkFDQUxhM1p4SUFkQi8vOERjV28yQW93QklBUWdBellDT0NBRUlBSTJBandnQkNBSU5nSkFBa0FDUUFKQUlBUW9BdHdCSWdzZ0Eyb2lGaUFRU3cwQUlBWWdBaUFEYWlJS2FpQVlTdzBBSUFwQklHb2dEQ0FHYTAwTkFRc2dCQ0FFUVVCcktBSUFOZ0lJSUFRZ0JDa0RPRGNEQUNBR0lBd2dCQ0FFUWR3QmFpQVFJQklnRXlBTkVCOGhDZ3dCQ3lBRElBWnFJUWNnQmlBTEtRQUFOd0FBSUFZZ0N5a0FDRGNBQ0FKQUlBTkJFVWtOQUNBR0lBc3BBQkEzQUJBZ0JpQUxLUUFZTndBWUlBTkJFR3RCRVVnTkFDQUxRUkJxSVFNZ0JrRWdhaUVMQTBBZ0N5QURLUUFRTndBQUlBc2dBeWtBR0RjQUNDQUxJQU1wQUNBM0FCQWdDeUFES1FBb053QVlJQU5CSUdvaEF5QUxRU0JxSWdzZ0Iwa05BQXNMSUFjZ0NHc2hBeUFFSUJZMkF0d0JJQWNnRW1zZ0NFa0VRQ0FJSUFjZ0UydExEUVFnRFNBTklBTWdFbXNpQTJvaUN5QUNhazhFUUNBSElBc2dBaEFLR2d3Q0N5QUhJQXRCQUNBRGF4QUtJQVFnQWlBRGFpSUNOZ0k4SUFOcklRY2dFaUVEQ3lBSVFSQlBCRUFnQnlBREtRQUFOd0FBSUFjZ0F5a0FDRGNBQ0NBQ1FSRklEUUVnQWlBSGFpRUlJQWRCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQWNnQXkwQUFEb0FBQ0FISUFNdEFBRTZBQUVnQnlBRExRQUNPZ0FDSUFjZ0F5MEFBem9BQXlBSElBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFjZ0F5a0FBRGNBQUFzZ0FrRUpTUTBBSUFJZ0Iyb2hDeUFIUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnQzBrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0FrRVpTQTBBSUFkQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF0SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3REN5QUdJQXBxSVFZZ0JFSHdBR29RRHlFRElBOUJBV3NpRHcwQUMwRUFJUUlnQTBFQ1NRMEJBMEFnQWtFRFJ3UkFJQVVnQWtFQ2RDSURha0dzMEFGcUlBTWdCR29vQXB3Qk5nSUFJQUpCQVdvaEFnd0JDd3NnQkNnQzNBRWhBd3RCdW44aENTQVFJQU5ySWdJZ0RDQUdhMHNOQUNBR0JIOGdCaUFESUFJUUFpQUNhZ1ZCQUFzZ0Rtc2hDUXNnQ1VHSWYwc05CZ3NDUUNBRktBTHM2Z0ZGRFFBZ0JTQUZLUU9JNmdFZ0NhMThOd09JNmdFQ1FDQUZLQUxRNmdFaUFpQUphaUlJUVI5TkJFQWdEa1VOQVNBQ0lDSnFJQTRnQ1JBQ0dpQUZLQUxRNmdFZ0NXb2hDQXdCQ3lBT0lRTWdBZ1JBSUFJZ0ltb2dBMEVnSUFKckVBSWFJQVVvQXREcUFTRUNJQVZCQURZQzBPb0JJQVVnQlNrRGtPb0JJQVVwQUxEcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RrT29CSUFVZ0JTa0RtT29CSUFVcEFManFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEbU9vQklBVWdCU2tEb09vQklBVXBBTURxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG9Pb0JJQVVnQlNrRHFPb0JJQVVwQU1qcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RxT29CSUFNZ0FtdEJJR29oQXdzZ0NTQU9haUlDSUFOQklHcFBCRUFnQWtFZ2F5RUdJQVVwQTZqcUFTRS9JQVVwQTZEcUFTRkFJQVVwQTVqcUFTRkJJQVVwQTVEcUFTRkNBMEFnQXlrQUdFTFAxdE8rMHNlcjJVSitJRDk4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVDhnQXlrQUVFTFAxdE8rMHNlcjJVSitJRUI4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVUFnQXlrQUNFTFAxdE8rMHNlcjJVSitJRUY4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVUVnQXlrQUFFTFAxdE8rMHNlcjJVSitJRUo4UWgrSlFvZVZyNitZdHQ2Ym5uOStJVUlnQTBFZ2FpSURJQVpORFFBTElBVWdQemNEcU9vQklBVWdRRGNEb09vQklBVWdRVGNEbU9vQklBVWdRamNEa09vQkN5QUNJQU5ORFFFZ0lpQURJQUlnQTJzaUNCQUNHZ3NnQlNBSU5nTFE2Z0VMSURVZ0ZXc2hBeUFWSUJ0cUlRSWdDU0FPYWlFT0lBUW9BakJGRFFBTElDa3BBd0FpUDBKL1VTQS9JQTRnSFd1c1VYSkZCRUJCYkNFSkRBWUxJQVVvQXVEcEFRUkFRV29oQ1NBRFFRUkpEUVlnQlNnQzZPb0JSUVJBSUNJZ0JTZ0MwT29CYWlFS0FuNGdCU2tEaU9vQklqOUNJRm9FUUNBRktRT1k2Z0VpUUVJSGlTQUZLUU9RNmdFaVFVSUJpWHdnQlNrRG9Pb0JJa0pDRElsOElBVXBBNmpxQVNKRFFoS0pmQ0JCUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlJRUJDejliVHZ0TEhxOWxDZmtJZmlVS0hsYSt2bUxiZW01NS9mb1ZDaDVXdnI1aTIzcHVlZjM1Q25hTzE2b094allyNkFIMGdRa0xQMXRPKzBzZXIyVUorUWgrSlFvZVZyNitZdHQ2Ym5uOStoVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTQkRRcy9XMDc3U3g2dlpRbjVDSDRsQ2g1V3ZyNWkyM3B1ZWYzNkZRb2VWcjYrWXR0NmJubjkrUXAyanRlcURzWTJLK2dCOURBRUxJQVVwQTZEcUFVTEZ6OW15OGVXNjZpZDhDeUEvZkNFL0lDSWhCZ05BSUFvZ0JrRUlhaUlIVHdSQUlBWXBBQUJDejliVHZ0TEhxOWxDZmtJZmlVS0hsYSt2bUxiZW01NS9maUEvaFVJYmlVS0hsYSt2bUxiZW01NS9ma0tkbzdYcWc3R05pdm9BZlNFL0lBY2hCZ3dCQ3dzQ1FDQUtJQVpCQkdvaUNFa0VRQ0FHSVFnTUFRc2dCalVBQUVLSGxhK3ZtTGJlbTU1L2ZpQS9oVUlYaVVMUDF0Tyswc2VyMlVKK1F2bnozZkdaOXBtckZud2hQd3NEUUNBSUlBcEpCRUFnQ0RFQUFFTEZ6OW15OGVXNjZpZCtJRCtGUWd1SlFvZVZyNitZdHQ2Ym5uOStJVDhnQ0VFQmFpRUlEQUVMQ3lBQ0tBQUFJRDlDSVlnZ1A0VkN6OWJUdnRMSHE5bENmaUkvUWgySUlEK0ZRdm56M2ZHWjlwbXJGbjRpUDBJZ2lDQS9oYWRIRFFjTElBTkJCR3NoQXlBQ1FRUnFJUUlMSUE0Z0hXc2lDVUdKZjA4TkJDQUJJQWxySVFFZ0NTQWRhaUVkUVFFaFBnd0JDd3RCdUg4aEJ5QUREUVFnSFNBQWF5RUhEQVFMUVd3aENRd0JDMEc0ZnlFSkMwRzRmeUVISUFsQmRrWWdQbkVOQVFzZ0NTRUhDeWdDQUEwQUlBVkIvT29CYWlnQ0FDRUJJQVZCK09vQmFpZ0NBQ0VBSUFVUUdDQUZLQUt3NndFZ0FDQUJFQk1nQlVFQU5nS3c2d0VnQlNnQ3BPc0JJZ0lFUUFKQUFrQUNRQUpBSUFJb0FnQWlBd1JBSUFCRkRRSWdBU0FESUFBUkFnQU1BUXNnQUVVTkFnc2dBU0FDSUFBUkFnQU1BZ3NnQXhBR0N5QUNFQVlMSUFWQkFEWUNwT3NCQ3lBQUJFQWdBU0FGSUFBUkFnQU1BUXNnQlJBR0N5QUVRZUFCYWlRQUlBY0xDNmdWQ1FCQmlBZ0xEUUVBQUFBQkFBQUFBZ0FBQUFJQVFhQUlDN01HQVFBQUFBRUFBQUFDQUFBQUFnQUFBQ1lBQUFDQ0FBQUFJUVVBQUVvQUFBQm5DQUFBSmdBQUFNQUJBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFLUUFBQUN3Q0FBQ0FBQUFBU1FVQUFFb0FBQUMrQ0FBQUx3QUFBTW9DQUFDQUFBQUFpZ1VBQUVvQUFBQ0VDUUFBTlFBQUFITURBQUNBQUFBQW5RVUFBRW9BQUFDZ0NRQUFQUUFBQUlFREFBQ0FBQUFBNndVQUFFc0FBQUErQ2dBQVJBQUFBSjREQUFDQUFBQUFUUVlBQUVzQUFBQ3FDZ0FBU3dBQUFMTURBQUNBQUFBQXdRWUFBRTBBQUFBZkRRQUFUUUFBQUZNRUFBQ0FBQUFBSXdnQUFGRUFBQUNtRHdBQVZBQUFBSmtFQUFDQUFBQUFTd2tBQUZjQUFBQ3hFZ0FBV0FBQUFOb0VBQUNBQUFBQWJ3a0FBRjBBQUFBakZBQUFWQUFBQUVVRkFBQ0FBQUFBVkFvQUFHb0FBQUNNRkFBQWFnQUFBSzhGQUFDQUFBQUFkZ2tBQUh3QUFBQk9FQUFBZkFBQUFOSUNBQUNBQUFBQVl3Y0FBSkVBQUFDUUJ3QUFrZ0FBQUFBQUFBQUJBQUFBQVFBQUFBVUFBQUFOQUFBQUhRQUFBRDBBQUFCOUFBQUEvUUFBQVAwQkFBRDlBd0FBL1FjQUFQMFBBQUQ5SHdBQS9UOEFBUDEvQUFEOS93QUEvZjhCQVAzL0F3RDkvd2NBL2Y4UEFQMy9Id0Q5L3o4QS9mOS9BUDMvL3dEOS8vOEIvZi8vQS8zLy93ZjkvLzhQL2YvL0gvMy8vei85Ly85L0FBQUFBQUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFSQUFBQUVnQUFBQk1BQUFBVUFBQUFGUUFBQUJZQUFBQVhBQUFBR0FBQUFCa0FBQUFhQUFBQUd3QUFBQndBQUFBZEFBQUFIZ0FBQUI4QUFBQURBQUFBQkFBQUFBVUFBQUFHQUFBQUJ3QUFBQWdBQUFBSkFBQUFDZ0FBQUFzQUFBQU1BQUFBRFFBQUFBNEFBQUFQQUFBQUVBQUFBQkVBQUFBU0FBQUFFd0FBQUJRQUFBQVZBQUFBRmdBQUFCY0FBQUFZQUFBQUdRQUFBQm9BQUFBYkFBQUFIQUFBQUIwQUFBQWVBQUFBSHdBQUFDQUFBQUFoQUFBQUlnQUFBQ01BQUFBbEFBQUFKd0FBQUNrQUFBQXJBQUFBTHdBQUFETUFBQUE3QUFBQVF3QUFBRk1BQUFCakFBQUFnd0FBQUFNQkFBQURBZ0FBQXdRQUFBTUlBQUFERUFBQUF5QUFBQU5BQUFBRGdBQUFBd0FCQUVIZ0R3dFJBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUF3QUFBQU1BQUFBRUFBQUFCQUFBQUFVQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QUFBQXdBQUFBTkFBQUFEZ0FBQUE4QUFBQVFBRUhFRUF1TEFRRUFBQUFDQUFBQUF3QUFBQVFBQUFBRkFBQUFCZ0FBQUFjQUFBQUlBQUFBQ1FBQUFBb0FBQUFMQUFBQURBQUFBQTBBQUFBT0FBQUFEd0FBQUJBQUFBQVNBQUFBRkFBQUFCWUFBQUFZQUFBQUhBQUFBQ0FBQUFBb0FBQUFNQUFBQUVBQUFBQ0FBQUFBQUFFQUFBQUNBQUFBQkFBQUFBZ0FBQUFRQUFBQUlBQUFBRUFBQUFDQUFBQUFBQUVBUVpBU0MrWUVBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUF3QUFBQU1BQUFBRUFBQUFCZ0FBQUFjQUFBQUlBQUFBQ1FBQUFBb0FBQUFMQUFBQURBQUFBQTBBQUFBT0FBQUFEd0FBQUJBQUFBQUJBQUFBQkFBQUFBZ0FBQUFBQUFBQUFRQUJBUVlBQUFBQUFBQUVBQUFBQUJBQUFBUUFBQUFBSUFBQUJRRUFBQUFBQUFBRkF3QUFBQUFBQUFVRUFBQUFBQUFBQlFZQUFBQUFBQUFGQndBQUFBQUFBQVVKQUFBQUFBQUFCUW9BQUFBQUFBQUZEQUFBQUFBQUFBWU9BQUFBQUFBQkJSQUFBQUFBQUFFRkZBQUFBQUFBQVFVV0FBQUFBQUFDQlJ3QUFBQUFBQU1GSUFBQUFBQUFCQVV3QUFBQUlBQUdCVUFBQUFBQUFBY0ZnQUFBQUFBQUNBWUFBUUFBQUFBS0JnQUVBQUFBQUF3R0FCQUFBQ0FBQUFRQUFBQUFBQUFBQkFFQUFBQUFBQUFGQWdBQUFDQUFBQVVFQUFBQUFBQUFCUVVBQUFBZ0FBQUZCd0FBQUFBQUFBVUlBQUFBSUFBQUJRb0FBQUFBQUFBRkN3QUFBQUFBQUFZTkFBQUFJQUFCQlJBQUFBQUFBQUVGRWdBQUFDQUFBUVVXQUFBQUFBQUNCUmdBQUFBZ0FBTUZJQUFBQUFBQUF3VW9BQUFBQUFBR0JFQUFBQUFRQUFZRVFBQUFBQ0FBQndXQUFBQUFBQUFKQmdBQ0FBQUFBQXNHQUFnQUFEQUFBQVFBQUFBQUVBQUFCQUVBQUFBZ0FBQUZBZ0FBQUNBQUFBVURBQUFBSUFBQUJRVUFBQUFnQUFBRkJnQUFBQ0FBQUFVSUFBQUFJQUFBQlFrQUFBQWdBQUFGQ3dBQUFDQUFBQVVNQUFBQUFBQUFCZzhBQUFBZ0FBRUZFZ0FBQUNBQUFRVVVBQUFBSUFBQ0JSZ0FBQUFnQUFJRkhBQUFBQ0FBQXdVb0FBQUFJQUFFQlRBQUFBQUFBQkFHQUFBQkFBQUFEd1lBZ0FBQUFBQU9CZ0JBQUFBQUFBMEdBQ0FBUVlBWEM0Y0NBUUFCQVFVQUFBQUFBQUFGQUFBQUFBQUFCZ1E5QUFBQUFBQUpCZjBCQUFBQUFBOEYvWDhBQUFBQUZRWDkveDhBQUFBREJRVUFBQUFBQUFjRWZRQUFBQUFBREFYOUR3QUFBQUFTQmYzL0F3QUFBQmNGL2Y5L0FBQUFCUVVkQUFBQUFBQUlCUDBBQUFBQUFBNEYvVDhBQUFBQUZBWDkvdzhBQUFBQ0JRRUFBQUFRQUFjRWZRQUFBQUFBQ3dYOUJ3QUFBQUFSQmYzL0FRQUFBQllGL2Y4L0FBQUFCQVVOQUFBQUVBQUlCUDBBQUFBQUFBMEYvUjhBQUFBQUV3WDkvd2NBQUFBQkJRRUFBQUFRQUFZRVBRQUFBQUFBQ2dYOUF3QUFBQUFRQmYzL0FBQUFBQndGL2YvL0R3QUFHd1g5Ly84SEFBQWFCZjMvL3dNQUFCa0YvZi8vQVFBQUdBWDkvLzhBUVpBWkM0WUVBUUFCQVFZQUFBQUFBQUFHQXdBQUFBQUFBQVFFQUFBQUlBQUFCUVVBQUFBQUFBQUZCZ0FBQUFBQUFBVUlBQUFBQUFBQUJRa0FBQUFBQUFBRkN3QUFBQUFBQUFZTkFBQUFBQUFBQmhBQUFBQUFBQUFHRXdBQUFBQUFBQVlXQUFBQUFBQUFCaGtBQUFBQUFBQUdIQUFBQUFBQUFBWWZBQUFBQUFBQUJpSUFBQUFBQUFFR0pRQUFBQUFBQVFZcEFBQUFBQUFDQmk4QUFBQUFBQU1HT3dBQUFBQUFCQVpUQUFBQUFBQUhCb01BQUFBQUFBa0dBd0lBQUJBQUFBUUVBQUFBQUFBQUJBVUFBQUFnQUFBRkJnQUFBQUFBQUFVSEFBQUFJQUFBQlFrQUFBQUFBQUFGQ2dBQUFBQUFBQVlNQUFBQUFBQUFCZzhBQUFBQUFBQUdFZ0FBQUFBQUFBWVZBQUFBQUFBQUJoZ0FBQUFBQUFBR0d3QUFBQUFBQUFZZUFBQUFBQUFBQmlFQUFBQUFBQUVHSXdBQUFBQUFBUVluQUFBQUFBQUNCaXNBQUFBQUFBTUdNd0FBQUFBQUJBWkRBQUFBQUFBRkJtTUFBQUFBQUFnR0F3RUFBQ0FBQUFRRUFBQUFNQUFBQkFRQUFBQVFBQUFFQlFBQUFDQUFBQVVIQUFBQUlBQUFCUWdBQUFBZ0FBQUZDZ0FBQUNBQUFBVUxBQUFBQUFBQUJnNEFBQUFBQUFBR0VRQUFBQUFBQUFZVUFBQUFBQUFBQmhjQUFBQUFBQUFHR2dBQUFBQUFBQVlkQUFBQUFBQUFCaUFBQUFBQUFCQUdBd0FCQUFBQUR3WURnQUFBQUFBT0JnTkFBQUFBQUEwR0F5QUFBQUFBREFZREVBQUFBQUFMQmdNSUFBQUFBQW9HQXdRQVFhUWRDOWtCQVFBQUFBTUFBQUFIQUFBQUR3QUFBQjhBQUFBL0FBQUFmd0FBQVA4QUFBRC9BUUFBL3dNQUFQOEhBQUQvRHdBQS94OEFBUDgvQUFEL2Z3QUEvLzhBQVAvL0FRRC8vd01BLy84SEFQLy9Ed0QvL3g4QS8vOC9BUC8vZndELy8vOEEvLy8vQWYvLy93UC8vLzhILy8vL0QvLy8veC8vLy84Ly8vLy9md0FBQUFBQkFBQUFBZ0FBQUFRQUFBQUFBQUFBQWdBQUFBUUFBQUFJQUFBQUFBQUFBQUVBQUFBQ0FBQUFBUUFBQUFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQWdBQUFBSEFBQUFDQUFBQUFrQUFBQUtBQUFBQ3dCQmdCOExBNEFSQVE9PSI7dmFyIE9JPW5ldyB5QSxUST0hMTthc3luYyBmdW5jdGlvbiBjZShBLEksdCl7bGV0IGU9bnVsbDt0eXBlb2YgQSE9InN0cmluZyI/ZT1BLmhyZWY6QS5zdGFydHNXaXRoKCJodHRwIik/ZT1BOmU9YCR7SX0vJHtBfWAsZS5lbmRzV2l0aCgiLmpzIikmJihlPWUuc3Vic3RyaW5nKDAsZS5sZW5ndGgtMykpLGUuZW5kc1dpdGgoIi53YXNtIikmJihlPWUuc3Vic3RyaW5nKDAsZS5sZW5ndGgtNSkpO2xldCBnPWAke2V9Lndhc21gLHI9YXdhaXQgZEEuZ2V0KGAke2d9LnpzdGAse3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIiLHBhcmFtczp0fSk7VEl8fChhd2FpdCBPSS5pbml0KCksVEk9ITApO2xldCBzPU9JLmRlY29kZShuZXcgVWludDhBcnJheShyLmRhdGEpKS5idWZmZXI7cmV0dXJuKGF3YWl0IGltcG9ydChgJHtlfS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5OnN9KX12YXIgeEk9Y2U7dmFyIHdBPW5ldyBNYXA7YXN5bmMgZnVuY3Rpb24gZmUoQSxJLHQpe2xldCBlPUEsZz1BLHI9bnVsbDtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciJiYoZT1uZXcgVVJMKEEuaHJlZiksZz1lLmhyZWYpLHdBLmhhcyhnKT9yPWF3YWl0IHdBLmdldChnKTood0Euc2V0KGcseEkoZSxJLHQpKSxyPWF3YWl0IHdBLmdldChnKSkscn12YXIgUEk9ZmU7dmFyIGxlPXtUZXh0RmlsZToiVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkJpbmFyeUZpbGUiLFRleHRTdHJlYW06IlRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiQmluYXJ5U3RyZWFtIixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2giLFBvbHlEYXRhOiJQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6Ikpzb25Db21wYXRpYmxlIn0sRD1sZTt2YXIgRGU9e0ludDg6ImludDgiLFVJbnQ4OiJ1aW50OCIsSW50MTY6ImludDE2IixVSW50MTY6InVpbnQxNiIsSW50MzI6ImludDMyIixVSW50MzI6InVpbnQzMiIsSW50NjQ6ImludDY0IixVSW50NjQ6InVpbnQ2NCIsU2l6ZVZhbHVlVHlwZToidWludDY0IixJZGVudGlmaWVyVHlwZToidWludDY0IixJbmRleFZhbHVlVHlwZToiaW50NjQiLE9mZnNldFZhbHVlVHlwZToiaW50NjQifSxwPURlO3ZhciB1ZT17RmxvYXQzMjoiZmxvYXQzMiIsRmxvYXQ2NDoiZmxvYXQ2NCIsU3BhY2VQcmVjaXNpb25UeXBlOiJmbG9hdDY0In0sUD11ZTtmdW5jdGlvbiBoZShBLEkpe2xldCB0PW51bGw7c3dpdGNoKEEpe2Nhc2UgcC5VSW50ODp7dD1uZXcgVWludDhBcnJheShJKTticmVha31jYXNlIHAuSW50ODp7dD1uZXcgSW50OEFycmF5KEkpO2JyZWFrfWNhc2UgcC5VSW50MTY6e3Q9bmV3IFVpbnQxNkFycmF5KEkpO2JyZWFrfWNhc2UgcC5JbnQxNjp7dD1uZXcgSW50MTZBcnJheShJKTticmVha31jYXNlIHAuVUludDMyOnt0PW5ldyBVaW50MzJBcnJheShJKTticmVha31jYXNlIHAuSW50MzI6e3Q9bmV3IEludDMyQXJyYXkoSSk7YnJlYWt9Y2FzZSBwLlVJbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnVWludDY0QXJyYXk9PSJmdW5jdGlvbiI/dD1uZXcgQmlnVWludDY0QXJyYXkoSSk6dD1uZXcgVWludDhBcnJheShJKTticmVha31jYXNlIHAuSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ0ludDY0QXJyYXk9PSJmdW5jdGlvbiI/dD1uZXcgQmlnSW50NjRBcnJheShJKTp0PW5ldyBVaW50OEFycmF5KEkpO2JyZWFrfWNhc2UgUC5GbG9hdDMyOnt0PW5ldyBGbG9hdDMyQXJyYXkoSSk7YnJlYWt9Y2FzZSBQLkZsb2F0NjQ6e3Q9bmV3IEZsb2F0NjRBcnJheShJKTticmVha31jYXNlIm51bGwiOnt0PW51bGw7YnJlYWt9Y2FzZSBudWxsOnt0PW51bGw7YnJlYWt9ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoIlR5cGUgaXMgbm90IHN1cHBvcnRlZCBhcyBhIFR5cGVkQXJyYXkiKX1yZXR1cm4gdH12YXIgWT1oZTt2YXIgWkk9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI9PSJmdW5jdGlvbiIsakk9bmV3IFRleHRFbmNvZGVyLFdJPW5ldyBUZXh0RGVjb2RlcigidXRmLTgiKTtmdW5jdGlvbiBkZShBLEkpe2xldCB0PXtmbGFnczoiciIsZW5jb2Rpbmc6ImJpbmFyeSJ9LGU9QS5mc19vcGVuKEksdC5mbGFncykscj1BLmZzX3N0YXQoSSkuc2l6ZSxpPW51bGw7Wkk/aT1uZXcgU2hhcmVkQXJyYXlCdWZmZXIocik6aT1uZXcgQXJyYXlCdWZmZXIocik7bGV0IHM9bmV3IFVpbnQ4QXJyYXkoaSk7cmV0dXJuIEEuZnNfcmVhZChlLHMsMCxyLDApLEEuZnNfY2xvc2UoZSksc31mdW5jdGlvbiBWSShBLEksdCl7bGV0IGU9bnVsbDtaST9lPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcih0KTplPW5ldyBBcnJheUJ1ZmZlcih0KTtsZXQgZz1uZXcgVWludDhBcnJheShlKSxyPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixJLHQpO3JldHVybiBnLnNldChyKSxnfWZ1bmN0aW9uIHkoQSxJLHQsZSl7bGV0IGc9MDtyZXR1cm4gSSE9PW51bGwmJihnPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2FycmF5X2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsZSxJLmJ1ZmZlci5ieXRlTGVuZ3RoXSksQS5IRUFQVTguc2V0KG5ldyBVaW50OEFycmF5KEkuYnVmZmVyKSxnKSksZ31mdW5jdGlvbiBqKEEsSSx0KXtsZXQgZT1KU09OLnN0cmluZ2lmeShJKSxnPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2pzb25fYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxlLmxlbmd0aF0pO0Eud3JpdGVBc2NpaVRvTWVtb3J5KGUsZywhMSl9ZnVuY3Rpb24gUyhBLEksdCxlKXtsZXQgZz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxJLHRdKSxyPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEksdF0pLGk9VkkoQSxnLHIpO3JldHVybiBZKGUsaS5idWZmZXIpfWZ1bmN0aW9uIHpBKEEsSSl7bGV0IHQ9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2pzb25fYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiXSxbMCxJXSksZT1BLkFzY2lpVG9TdHJpbmcodCk7cmV0dXJuIEpTT04ucGFyc2UoZSl9ZnVuY3Rpb24geWUoQSxJLHQsZSl7ZSE9bnVsbCYmZS5sZW5ndGg+MCYmZS5mb3JFYWNoKGZ1bmN0aW9uKG4sQyl7c3dpdGNoKG4udHlwZSl7Y2FzZSBELlRleHRTdHJlYW06e2xldCBvPWpJLmVuY29kZShuLmRhdGEuZGF0YSksZj15KEEsbyxDLDApLFE9e3NpemU6by5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gfTtqKEEsUSxDKTticmVha31jYXNlIEQuSnNvbkNvbXBhdGlibGU6e2xldCBvPWpJLmVuY29kZShKU09OLnN0cmluZ2lmeShuLmRhdGEpKSxmPXkoQSxvLEMsMCksUT17c2l6ZTpvLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWB9O2ooQSxRLEMpO2JyZWFrfWNhc2UgRC5CaW5hcnlTdHJlYW06e2xldCBvPW4uZGF0YS5kYXRhLGY9eShBLG8sQywwKSxRPXtzaXplOm8uYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YH07aihBLFEsQyk7YnJlYWt9Y2FzZSBELlRleHRGaWxlOntBLmZzX3dyaXRlRmlsZShuLmRhdGEucGF0aCxuLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBELkJpbmFyeUZpbGU6e0EuZnNfd3JpdGVGaWxlKG4uZGF0YS5wYXRoLG4uZGF0YS5kYXRhKTticmVha31jYXNlIEQuSW1hZ2U6e2xldCBvPW4uZGF0YSxmPXkoQSxvLmRhdGEsQywwKSxRPXkoQSxvLmRpcmVjdGlvbixDLDEpLEU9dHlwZW9mIG8ubWV0YWRhdGE/LmVudHJpZXM8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20oby5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLGM9e2ltYWdlVHlwZTpvLmltYWdlVHlwZSxuYW1lOm8ubmFtZSxvcmlnaW46by5vcmlnaW4sc3BhY2luZzpvLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLHNpemU6by5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWAsbWV0YWRhdGE6RX07aihBLGMsQyk7YnJlYWt9Y2FzZSBELk1lc2g6e2xldCBvPW4uZGF0YSxmPXkoQSxvLnBvaW50cyxDLDApLFE9eShBLG8uY2VsbHMsQywxKSxFPXkoQSxvLnBvaW50RGF0YSxDLDIpLGM9eShBLG8uY2VsbERhdGEsQywzKSx1PXttZXNoVHlwZTpvLm1lc2hUeXBlLG5hbWU6by5uYW1lLG51bWJlck9mUG9pbnRzOm8ubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG51bWJlck9mQ2VsbHM6by5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGNlbGxCdWZmZXJTaXplOm8uY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczpvLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7RX1gLG51bWJlck9mQ2VsbFBpeGVsczpvLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2N9YH07aihBLHUsQyk7YnJlYWt9Y2FzZSBELlBvbHlEYXRhOntsZXQgbz1uLmRhdGEsZj15KEEsby5wb2ludHMsQywwKSxRPXkoQSxvLnZlcnRpY2VzLEMsMSksRT15KEEsby5saW5lcyxDLDIpLGM9eShBLG8ucG9seWdvbnMsQywzKSx1PXkoQSxvLnRyaWFuZ2xlU3RyaXBzLEMsNCksZD15KEEsby5wb2ludERhdGEsQyw1KSxSPXkoQSxvLnBvaW50RGF0YSxDLDYpLE49e3BvbHlEYXRhVHlwZTpvLnBvbHlEYXRhVHlwZSxuYW1lOm8ubmFtZSxudW1iZXJPZlBvaW50czpvLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCx2ZXJ0aWNlc0J1ZmZlclNpemU6by52ZXJ0aWNlc0J1ZmZlclNpemUsdmVydGljZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtRfWAsbGluZXNCdWZmZXJTaXplOm8ubGluZXNCdWZmZXJTaXplLGxpbmVzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7RX1gLHBvbHlnb25zQnVmZmVyU2l6ZTpvLnBvbHlnb25zQnVmZmVyU2l6ZSxwb2x5Z29uczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2N9YCx0cmlhbmdsZVN0cmlwc0J1ZmZlclNpemU6by50cmlhbmdsZVN0cmlwc0J1ZmZlclNpemUsdHJpYW5nbGVTdHJpcHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt1fWAsbnVtYmVyT2ZQb2ludFBpeGVsczpvLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7ZH1gLG51bWJlck9mQ2VsbFBpeGVsczpvLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke1J9YH07aihBLE4sQyk7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLEEucmVzZXRNb2R1bGVTdGRvdXQoKSxBLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IGc9QS5zdGFja1NhdmUoKSxyPTA7dHJ5e3I9QS5jYWxsTWFpbihJLnNsaWNlKCkpfWNhdGNoKG4pe3Rocm93IHR5cGVvZiBuPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsQS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsQS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIEEuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsQS5nZXRFeGNlcHRpb25NZXNzYWdlKG4pKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLG59ZmluYWxseXtBLnN0YWNrUmVzdG9yZShnKX1sZXQgaT1BLmdldE1vZHVsZVN0ZG91dCgpLHM9QS5nZXRNb2R1bGVTdGRlcnIoKSxhPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZyPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKG4sQyl7bGV0IG89bnVsbDtzd2l0Y2gobi50eXBlKXtjYXNlIEQuVGV4dFN0cmVhbTp7bGV0IFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQywwXSksRT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxDLDBdKSxjPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixRLEUpO289e2RhdGE6V0kuZGVjb2RlKGMpfTticmVha31jYXNlIEQuSnNvbkNvbXBhdGlibGU6e2xldCBRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEMsMF0pLEU9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQywwXSksYz1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsUSxFKTtvPUpTT04ucGFyc2UoV0kuZGVjb2RlKGMpKTticmVha31jYXNlIEQuQmluYXJ5U3RyZWFtOntsZXQgUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxDLDBdKSxFPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEMsMF0pO289e2RhdGE6VkkoQSxRLEUpfTticmVha31jYXNlIEQuVGV4dEZpbGU6e289e3BhdGg6bi5kYXRhLnBhdGgsZGF0YTpBLmZzX3JlYWRGaWxlKG4uZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSBELkJpbmFyeUZpbGU6e289e3BhdGg6bi5kYXRhLnBhdGgsZGF0YTpkZShBLG4uZGF0YS5wYXRoKX07YnJlYWt9Y2FzZSBELkltYWdlOntsZXQgUT16QShBLEMpO1EuZGF0YT1TKEEsQywwLFEuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpLFEuZGlyZWN0aW9uPVMoQSxDLDEsUC5GbG9hdDY0KSxRLm1ldGFkYXRhPW5ldyBNYXAoUS5tZXRhZGF0YSksbz1RO2JyZWFrfWNhc2UgRC5NZXNoOntsZXQgUT16QShBLEMpO1EubnVtYmVyT2ZQb2ludHM+MD9RLnBvaW50cz1TKEEsQywwLFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlKTpRLnBvaW50cz1ZKFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksUS5udW1iZXJPZkNlbGxzPjA/US5jZWxscz1TKEEsQywxLFEubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUpOlEuY2VsbHM9WShRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksUS5udW1iZXJPZlBvaW50UGl4ZWxzPjA/US5wb2ludERhdGE9UyhBLEMsMixRLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpRLnBvaW50RGF0YT1ZKFEubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxRLm51bWJlck9mQ2VsbFBpeGVscz4wP1EuY2VsbERhdGE9UyhBLEMsMyxRLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOlEuY2VsbERhdGE9WShRLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxvPVE7YnJlYWt9Y2FzZSBELlBvbHlEYXRhOntsZXQgUT16QShBLEMpO1EubnVtYmVyT2ZQb2ludHM+MD9RLnBvaW50cz1TKEEsQywwLFAuRmxvYXQzMik6US5wb2ludHM9bmV3IEZsb2F0MzJBcnJheSxRLnZlcnRpY2VzQnVmZmVyU2l6ZT4wP1EudmVydGljZXM9UyhBLEMsMSxwLlVJbnQzMik6US52ZXJ0aWNlcz1uZXcgVWludDMyQXJyYXksUS5saW5lc0J1ZmZlclNpemU+MD9RLmxpbmVzPVMoQSxDLDIscC5VSW50MzIpOlEubGluZXM9bmV3IFVpbnQzMkFycmF5LFEucG9seWdvbnNCdWZmZXJTaXplPjA/US5wb2x5Z29ucz1TKEEsQywzLHAuVUludDMyKTpRLnBvbHlnb25zPW5ldyBVaW50MzJBcnJheSxRLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZT4wP1EudHJpYW5nbGVTdHJpcHM9UyhBLEMsNCxwLlVJbnQzMik6US50cmlhbmdsZVN0cmlwcz1uZXcgVWludDMyQXJyYXksUS5udW1iZXJPZlBvaW50UGl4ZWxzPjA/US5wb2ludERhdGE9UyhBLEMsNSxRLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6US5wb2ludERhdGE9WShRLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLFEubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/US5jZWxsRGF0YT1TKEEsQyw2LFEucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOlEuY2VsbERhdGE9WShRLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksbz1RO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIG91dHB1dCBJbnRlcmZhY2VUeXBlIil9bGV0IGY9e3R5cGU6bi50eXBlLGRhdGE6b307YS5wdXNoKGYpfSkse3JldHVyblZhbHVlOnIsc3Rkb3V0Omksc3RkZXJyOnMsb3V0cHV0czphfX12YXIgWEk9eWU7dmFyIHdlPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPCJ1IjtmdW5jdGlvbiBtZShBLEkpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IHQ9W107Zm9yKGxldCBlPTA7ZTxBLmxlbmd0aDtlKyspe2xldCBnPXBlKEFbZV0sSSk7ZyE9PW51bGwmJnQucHVzaChnKX1yZXR1cm4gdH1mdW5jdGlvbiBwZShBLEkpe2lmKEE9PW51bGwpcmV0dXJuIG51bGw7bGV0IHQ9bnVsbDtyZXR1cm4gQS5idWZmZXIhPT12b2lkIDA/dD1BLmJ1ZmZlcjpBLmJ5dGVMZW5ndGghPT12b2lkIDAmJih0PUEpLHdlJiZ0IGluc3RhbmNlb2YgU2hhcmVkQXJyYXlCdWZmZXI/bnVsbDpJP3Q6dC5zbGljZSgwKX12YXIgekk9bWU7ZnVuY3Rpb24gU2UoQSl7cmV0dXJuW0EuZGF0YSxBLmRpcmVjdGlvbl19dmFyIF9JPVNlO2Z1bmN0aW9uIEZlKEEpe3JldHVybltBLnBvaW50cyxBLnBvaW50RGF0YSxBLmNlbGxzLEEuY2VsbERhdGFdfXZhciB2ST1GZTtmdW5jdGlvbiBSZShBKXtyZXR1cm5bQS5wb2ludHMsQS52ZXJ0aWNlcyxBLmxpbmVzLEEucG9seWdvbnMsQS50cmlhbmdsZVN0cmlwcyxBLnBvaW50RGF0YSxBLmNlbGxEYXRhXX12YXIgJEk9UmU7YXN5bmMgZnVuY3Rpb24gTmUoQSxJLHQsZSl7bGV0IGc9WEkoQSxJLHQsZSkscj1bXTtyZXR1cm4gZy5vdXRwdXRzLmZvckVhY2goZnVuY3Rpb24oaSl7aWYoaS50eXBlPT09RC5CaW5hcnlTdHJlYW18fGkudHlwZT09PUQuQmluYXJ5RmlsZSl7bGV0IHM9aS5kYXRhO3IucHVzaChzKX1lbHNlIGlmKGkudHlwZT09PUQuSW1hZ2Upe2xldCBzPWkuZGF0YTtyLnB1c2goLi4uX0kocykpfWVsc2UgaWYoaS50eXBlPT09RC5NZXNoKXtsZXQgcz1pLmRhdGE7ci5wdXNoKC4uLnZJKHMpKX1lbHNlIGlmKGkudHlwZT09PUQuUG9seURhdGEpe2xldCBzPWkuZGF0YTtyLnB1c2goLi4uJEkocykpfX0pLFNBKGcsekkociwhMCkpfXZhciBBdD1OZTt2YXIgVWU9e3J1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsSSx0LGUsZyxyKXtsZXQgaT1hd2FpdCBQSShBLEkscik7cmV0dXJuIGF3YWl0IEF0KGksdCxlLGcpfX07b0EoVWUpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7bXQod3QpO2V4cG9ydHtCaSBhcyBhcHBseVByZXNlbnRhdGlvblN0YXRlVG9JbWFnZSxUIGFzIGdldERlZmF1bHRXZWJXb3JrZXIsdyBhcyBnZXRQaXBlbGluZVdvcmtlclVybCxSIGFzIGdldFBpcGVsaW5lc0Jhc2VVcmwsU2kgYXMgaW1hZ2VTZXRzTm9ybWFsaXphdGlvbixjaSBhcyByZWFkRGljb21FbmNhcHN1bGF0ZWRQZGYsZGkgYXMgcmVhZERpY29tVGFncyx3aSBhcyByZWFkSW1hZ2VEaWNvbUZpbGVTZXJpZXMsZ2UgYXMgcmVhZEltYWdlRGljb21GaWxlU2VyaWVzV29ya2VyRnVuY3Rpb24sanMgYXMgc2V0RGVmYXVsdFdlYldvcmtlcixtdCBhcyBzZXRQaXBlbGluZVdvcmtlclVybCxIcyBhcyBzZXRQaXBlbGluZXNCYXNlVXJsLEVpIGFzIHN0cnVjdHVyZWRSZXBvcnRUb0h0bWwsUWkgYXMgc3RydWN0dXJlZFJlcG9ydFRvVGV4dCxrQSBhcyB2ZXJzaW9ufTsKLyohIEJ1bmRsZWQgbGljZW5zZSBpbmZvcm1hdGlvbjoKCmNvbWxpbmsvZGlzdC9lc20vY29tbGluay5tanM6CiAgKCoqCiAgICogQGxpY2Vuc2UKICAgKiBDb3B5cmlnaHQgMjAxOSBHb29nbGUgTExDCiAgICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjAKICAgKikKKi8K""" default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) diff --git a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/__init__.py b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/__init__.py index f36a5e54a..b084efeb0 100644 --- a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/__init__.py +++ b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/__init__.py @@ -5,5 +5,6 @@ from .structured_report_to_html import structured_report_to_html from .structured_report_to_text import structured_report_to_text from .read_image_dicom_file_series import read_image_dicom_file_series +from .image_sets_normalization import image_sets_normalization from ._version import __version__ diff --git a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/image_sets_normalization.py b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/image_sets_normalization.py new file mode 100644 index 000000000..74d9f8d70 --- /dev/null +++ b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/image_sets_normalization.py @@ -0,0 +1,83 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, +) + +def image_sets_normalization( + files: List[os.PathLike] = [], + series_group_by: Optional[Any] = None, + image_set_group_by: Optional[Any] = None, +) -> Any: + """Group DICOM files into image sets + + :param files: DICOM files + :type files: os.PathLike + + :param series_group_by: Create series so that all instances in a series share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Series UID and Frame Of Reference UID tags. + :type series_group_by: Any + + :param image_set_group_by: Create image sets so that all series in a set share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Study UID tag. + :type image_set_group_by: Any + + :return: Image sets JSON + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_dicom_wasi').joinpath(Path('wasm_modules') / Path('image-sets-normalization.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + ] + + pipeline_inputs: List[PipelineInput] = [ + ] + + args: List[str] = ['--memory-io',] + # Inputs + # Outputs + image_sets_name = '0' + args.append(image_sets_name) + + # Options + input_count = len(pipeline_inputs) + if len(files) < 1: + raise ValueError('"files" kwarg must have a length > 1') + if len(files) > 0: + args.append('--files') + for value in files: + input_file = str(PurePosixPath(value)) + pipeline_inputs.append(PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(value))) + args.append(input_file) + + if series_group_by is not None: + pipeline_inputs.append(PipelineInput(InterfaceTypes.JsonCompatible, series_group_by)) + args.append('--series-group-by') + args.append(str(input_count)) + input_count += 1 + + if image_set_group_by is not None: + pipeline_inputs.append(PipelineInput(InterfaceTypes.JsonCompatible, image_set_group_by)) + args.append('--image-set-group-by') + args.append(str(input_count)) + input_count += 1 + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/apply-presentation-state-to-image.wasi.wasm b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/apply-presentation-state-to-image.wasi.wasm index 11312e72f..0eda6d6d2 100755 Binary files a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/apply-presentation-state-to-image.wasi.wasm and b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/apply-presentation-state-to-image.wasi.wasm differ diff --git a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/image-sets-normalization.wasi.wasm b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/image-sets-normalization.wasi.wasm new file mode 100755 index 000000000..c5e210089 Binary files /dev/null and b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/image-sets-normalization.wasi.wasm differ diff --git a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/read-image-dicom-file-series.wasi.wasm b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/read-image-dicom-file-series.wasi.wasm index 3e7733865..84f496c29 100755 Binary files a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/read-image-dicom-file-series.wasi.wasm and b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/wasm_modules/read-image-dicom-file-series.wasi.wasm differ diff --git a/packages/dicom/python/itkwasm-dicom-wasi/tests/test_image_sets_normalization.py b/packages/dicom/python/itkwasm-dicom-wasi/tests/test_image_sets_normalization.py new file mode 100644 index 000000000..a34d956c5 --- /dev/null +++ b/packages/dicom/python/itkwasm-dicom-wasi/tests/test_image_sets_normalization.py @@ -0,0 +1,115 @@ +from itkwasm_dicom_wasi import image_sets_normalization + +from .common import test_input_path, test_output_path + + +orientation_series = [ + test_input_path / "DicomImageOrientationTest" / "ImageOrientation.1.dcm", + test_input_path / "DicomImageOrientationTest" / "ImageOrientation.2.dcm", + test_input_path / "DicomImageOrientationTest" / "ImageOrientation.3.dcm", +] + +mr_series = [ + test_input_path / "dicom-images" / "MR" / "1-001.dcm", + test_input_path / "dicom-images" / "MR" / "1-002.dcm", + test_input_path / "dicom-images" / "MR" / "1-003.dcm", + test_input_path / "dicom-images" / "MR" / "1-004.dcm", + test_input_path / "dicom-images" / "MR" / "1-005.dcm", +] + +ct_series = [ + test_input_path / "dicom-images" / "CT" / "1-1.dcm", + test_input_path / "dicom-images" / "CT" / "1-2.dcm", +] + + +def pick_files(image_set): + instances = list(image_set["Study"]["Series"].values())[0]["Instances"].values() + files = [instance["ImageFrames"][0]["ID"] for instance in instances] + return files + + +def assert_equal(fileStrings, paths): + assert all(file == str(path) for file, path in zip(fileStrings, paths)) + + +def test_one_series(): + assert orientation_series[0].exists() + out_of_order = [ + orientation_series[1], + orientation_series[2], + orientation_series[0], + ] + image_sets = image_sets_normalization(out_of_order) + assert image_sets + sorted_files = pick_files(image_sets[0]) + assert_equal(sorted_files, orientation_series) + + +def test_ct(): + image_sets = image_sets_normalization(ct_series) + assert len(image_sets) == 1 + sorted_files = pick_files(image_sets[0]) + assert_equal(sorted_files, ct_series) + + +def test_mr(): + assert mr_series[0].exists() + out_of_order = [ + mr_series[1], + mr_series[2], + mr_series[0], + mr_series[3], + mr_series[4], + ] + image_sets = image_sets_normalization(out_of_order) + assert image_sets + sorted_files = pick_files(image_sets[0]) + assert_equal(sorted_files, mr_series) + + +def test_series_group_by_option(): + assert mr_series[0].exists() + group_by_tags = {"tags": ["0008|0018"]} # SOP Instance UID + image_sets = image_sets_normalization(mr_series, series_group_by=group_by_tags) + assert len(image_sets) == len(mr_series) + + +def test_two_series(): + files = [ + orientation_series[1], + mr_series[4], + mr_series[2], + mr_series[1], + orientation_series[2], + orientation_series[0], + mr_series[3], + mr_series[0], + ] + assert files[0].exists() + image_sets = image_sets_normalization(files) + assert len(image_sets) == 2 + for image_set, paths in zip(image_sets, [mr_series, orientation_series]): + sorted_files = pick_files(image_set) + assert_equal(sorted_files, paths) + + +def test_three_series(): + files = [ + ct_series[0], + orientation_series[1], + mr_series[4], + mr_series[2], + mr_series[1], + orientation_series[2], + ct_series[1], + orientation_series[0], + mr_series[3], + mr_series[0], + ] + assert files[0].exists() + image_sets = image_sets_normalization(files) + assert len(image_sets) == 3 + for image_set, paths in zip(image_sets, [mr_series, orientation_series, ct_series]): + sorted_files = pick_files(image_set) + assert_equal(sorted_files, paths) diff --git a/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/image_sets_normalization.py b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/image_sets_normalization.py new file mode 100644 index 000000000..0a09670b3 --- /dev/null +++ b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/image_sets_normalization.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, +) + +def image_sets_normalization( + files: List[os.PathLike] = [], + series_group_by: Optional[Any] = None, + image_set_group_by: Optional[Any] = None, +) -> Any: + """Group DICOM files into image sets + + :param files: DICOM files + :type files: os.PathLike + + :param series_group_by: Create series so that all instances in a series share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Series UID and Frame Of Reference UID tags. + :type series_group_by: Any + + :param image_set_group_by: Create image sets so that all series in a set share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Study UID tag. + :type image_set_group_by: Any + + :return: Image sets JSON + :rtype: Any + """ + func = environment_dispatch("itkwasm_dicom", "image_sets_normalization") + output = func(files=files, series_group_by=series_group_by, image_set_group_by=image_set_group_by) + return output diff --git a/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/image_sets_normalization_async.py b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/image_sets_normalization_async.py new file mode 100644 index 000000000..acf1546b1 --- /dev/null +++ b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/image_sets_normalization_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, +) + +async def image_sets_normalization_async( + files: List[os.PathLike] = [], + series_group_by: Optional[Any] = None, + image_set_group_by: Optional[Any] = None, +) -> Any: + """Group DICOM files into image sets + + :param files: DICOM files + :type files: os.PathLike + + :param series_group_by: Create series so that all instances in a series share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Series UID and Frame Of Reference UID tags. + :type series_group_by: Any + + :param image_set_group_by: Create image sets so that all series in a set share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Study UID tag. + :type image_set_group_by: Any + + :return: Image sets JSON + :rtype: Any + """ + func = environment_dispatch("itkwasm_dicom", "image_sets_normalization_async") + output = await func(files=files, series_group_by=series_group_by, image_set_group_by=image_set_group_by) + return output diff --git a/packages/dicom/typescript/cypress/e2e/image-sets-normalization.cy.ts b/packages/dicom/typescript/cypress/e2e/image-sets-normalization.cy.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/dicom/typescript/src/image-sets-normalization-node-options.ts b/packages/dicom/typescript/src/image-sets-normalization-node-options.ts new file mode 100644 index 000000000..9e87b517d --- /dev/null +++ b/packages/dicom/typescript/src/image-sets-normalization-node-options.ts @@ -0,0 +1,17 @@ +// Generated file. To retain edits, remove this comment. + +import { BinaryFile,JsonCompatible } from 'itk-wasm' + +interface ImageSetsNormalizationNodeOptions { + /** DICOM files */ + files: string[] | File[] | BinaryFile[] + + /** Create series so that all instances in a series share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Series UID and Frame Of Reference UID tags. */ + seriesGroupBy?: JsonCompatible + + /** Create image sets so that all series in a set share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Study UID tag. */ + imageSetGroupBy?: JsonCompatible + +} + +export default ImageSetsNormalizationNodeOptions diff --git a/packages/dicom/typescript/src/image-sets-normalization-node-result.ts b/packages/dicom/typescript/src/image-sets-normalization-node-result.ts new file mode 100644 index 000000000..4d7bd9ade --- /dev/null +++ b/packages/dicom/typescript/src/image-sets-normalization-node-result.ts @@ -0,0 +1,11 @@ +// Generated file. To retain edits, remove this comment. + +import { JsonCompatible } from 'itk-wasm' + +interface ImageSetsNormalizationNodeResult { + /** Image sets JSON */ + imageSets: JsonCompatible + +} + +export default ImageSetsNormalizationNodeResult diff --git a/packages/dicom/typescript/src/image-sets-normalization-node.ts b/packages/dicom/typescript/src/image-sets-normalization-node.ts new file mode 100644 index 000000000..079a318a2 --- /dev/null +++ b/packages/dicom/typescript/src/image-sets-normalization-node.ts @@ -0,0 +1,86 @@ +// Generated file. To retain edits, remove this comment. + +import { + JsonCompatible, + InterfaceTypes, + PipelineOutput, + PipelineInput, + runPipelineNode +} from 'itk-wasm' + +import ImageSetsNormalizationNodeOptions from './image-sets-normalization-node-options.js' +import ImageSetsNormalizationNodeResult from './image-sets-normalization-node-result.js' + +import path from 'path' +import { fileURLToPath } from 'url' + +/** + * Group DICOM files into image sets + * + * @param {ImageSetsNormalizationNodeOptions} options - options object + * + * @returns {Promise} - result object + */ +async function imageSetsNormalizationNode( + options: ImageSetsNormalizationNodeOptions = { files: [] as string[], } +) : Promise { + + const mountDirs: Set = new Set() + + const desiredOutputs: Array = [ + { type: InterfaceTypes.JsonCompatible }, + ] + + const inputs: Array = [ + ] + + const args = [] + // Inputs + // Outputs + const imageSetsName = '0' + args.push(imageSetsName) + + // Options + args.push('--memory-io') + if (options.files) { + if(options.files.length < 1) { + throw new Error('"files" option must have a length > 1') + } + args.push('--files') + + options.files.forEach((value) => { + mountDirs.add(path.dirname(value as string)) + args.push(value as string) + }) + } + if (options.seriesGroupBy) { + const inputCountString = inputs.length.toString() + inputs.push({ type: InterfaceTypes.JsonCompatible, data: options.seriesGroupBy as JsonCompatible }) + args.push('--series-group-by', inputCountString) + + } + if (options.imageSetGroupBy) { + const inputCountString = inputs.length.toString() + inputs.push({ type: InterfaceTypes.JsonCompatible, data: options.imageSetGroupBy as JsonCompatible }) + args.push('--image-set-group-by', inputCountString) + + } + + const pipelinePath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'pipelines', 'image-sets-normalization') + + const { + returnValue, + stderr, + outputs + } = await runPipelineNode(pipelinePath, args, desiredOutputs, inputs, mountDirs) + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr) + } + + const result = { + imageSets: outputs[0]?.data as JsonCompatible, + } + return result +} + +export default imageSetsNormalizationNode diff --git a/packages/dicom/typescript/src/image-sets-normalization-options.ts b/packages/dicom/typescript/src/image-sets-normalization-options.ts new file mode 100644 index 000000000..11a6422d0 --- /dev/null +++ b/packages/dicom/typescript/src/image-sets-normalization-options.ts @@ -0,0 +1,17 @@ +// Generated file. To retain edits, remove this comment. + +import { BinaryFile,JsonCompatible, WorkerPoolFunctionOption } from 'itk-wasm' + +interface ImageSetsNormalizationOptions extends WorkerPoolFunctionOption { + /** DICOM files */ + files: string[] | File[] | BinaryFile[] + + /** Create series so that all instances in a series share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Series UID and Frame Of Reference UID tags. */ + seriesGroupBy?: JsonCompatible + + /** Create image sets so that all series in a set share these tags. Option is a JSON object with a "tags" array. Example tag: "0008|103e". If not provided, defaults to Study UID tag. */ + imageSetGroupBy?: JsonCompatible + +} + +export default ImageSetsNormalizationOptions diff --git a/packages/dicom/typescript/src/image-sets-normalization-result.ts b/packages/dicom/typescript/src/image-sets-normalization-result.ts new file mode 100644 index 000000000..e0a008bdd --- /dev/null +++ b/packages/dicom/typescript/src/image-sets-normalization-result.ts @@ -0,0 +1,11 @@ +// Generated file. To retain edits, remove this comment. + +import { JsonCompatible, WorkerPoolFunctionResult } from 'itk-wasm' + +interface ImageSetsNormalizationResult extends WorkerPoolFunctionResult { + /** Image sets JSON */ + imageSets: JsonCompatible + +} + +export default ImageSetsNormalizationResult diff --git a/packages/dicom/typescript/src/image-sets-normalization.ts b/packages/dicom/typescript/src/image-sets-normalization.ts new file mode 100644 index 000000000..2f9d6f7c2 --- /dev/null +++ b/packages/dicom/typescript/src/image-sets-normalization.ts @@ -0,0 +1,99 @@ +// Generated file. To retain edits, remove this comment. + +import { + JsonCompatible, + BinaryFile, + InterfaceTypes, + PipelineOutput, + PipelineInput, + runPipeline +} from 'itk-wasm' + +import ImageSetsNormalizationOptions from './image-sets-normalization-options.js' +import ImageSetsNormalizationResult from './image-sets-normalization-result.js' + +import { getPipelinesBaseUrl } from './pipelines-base-url.js' +import { getPipelineWorkerUrl } from './pipeline-worker-url.js' + +import { getDefaultWebWorker } from './default-web-worker.js' + +/** + * Group DICOM files into image sets + * + * @param {ImageSetsNormalizationOptions} options - options object + * + * @returns {Promise} - result object + */ +async function imageSetsNormalization( + options: ImageSetsNormalizationOptions = { files: [] as BinaryFile[] | File[] | string[], } +) : Promise { + + const desiredOutputs: Array = [ + { type: InterfaceTypes.JsonCompatible }, + ] + + const inputs: Array = [ + ] + + const args = [] + // Inputs + // Outputs + const imageSetsName = '0' + args.push(imageSetsName) + + // Options + args.push('--memory-io') + if (options.files) { + if(options.files.length < 1) { + throw new Error('"files" option must have a length > 1') + } + args.push('--files') + + await Promise.all(options.files.map(async (value) => { + let valueFile = value + if (value instanceof File) { + const valueBuffer = await value.arrayBuffer() + valueFile = { path: value.name, data: new Uint8Array(valueBuffer) } + } + inputs.push({ type: InterfaceTypes.BinaryFile, data: valueFile as BinaryFile }) + const name = value instanceof File ? value.name : (valueFile as BinaryFile).path + args.push(name) + })) + } + if (options.seriesGroupBy) { + const inputCountString = inputs.length.toString() + inputs.push({ type: InterfaceTypes.JsonCompatible, data: options.seriesGroupBy as JsonCompatible }) + args.push('--series-group-by', inputCountString) + + } + if (options.imageSetGroupBy) { + const inputCountString = inputs.length.toString() + inputs.push({ type: InterfaceTypes.JsonCompatible, data: options.imageSetGroupBy as JsonCompatible }) + args.push('--image-set-group-by', inputCountString) + + } + + const pipelinePath = 'image-sets-normalization' + + let workerToUse = options?.webWorker + if (workerToUse === undefined) { + workerToUse = await getDefaultWebWorker() + } + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline(pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl(), pipelineWorkerUrl: getPipelineWorkerUrl(), webWorker: workerToUse, noCopy: options?.noCopy }) + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr) + } + + const result = { + webWorker: usedWebWorker as Worker, + imageSets: outputs[0]?.data as JsonCompatible, + } + return result +} + +export default imageSetsNormalization diff --git a/packages/dicom/typescript/src/index-node-only.ts b/packages/dicom/typescript/src/index-node-only.ts index 8d75fbcb1..716c44d87 100644 --- a/packages/dicom/typescript/src/index-node-only.ts +++ b/packages/dicom/typescript/src/index-node-only.ts @@ -42,6 +42,16 @@ import structuredReportToTextNode from './structured-report-to-text-node.js' export { structuredReportToTextNode } +import ImageSetsNormalizationNodeResult from './image-sets-normalization-node-result.js' +export type { ImageSetsNormalizationNodeResult } + +import ImageSetsNormalizationNodeOptions from './image-sets-normalization-node-options.js' +export type { ImageSetsNormalizationNodeOptions } + +import imageSetsNormalizationNode from './image-sets-normalization-node.js' +export { imageSetsNormalizationNode } + + import ReadDicomTagsNodeResult from './read-dicom-tags-node-result.js' export type { ReadDicomTagsNodeResult } diff --git a/packages/dicom/typescript/src/index-only.ts b/packages/dicom/typescript/src/index-only.ts index b3758756a..cce0de115 100644 --- a/packages/dicom/typescript/src/index-only.ts +++ b/packages/dicom/typescript/src/index-only.ts @@ -66,3 +66,14 @@ export { readImageDicomFileSeries } import readImageDicomFileSeriesWorkerFunction from './read-image-dicom-file-series-worker-function.js' export { readImageDicomFileSeriesWorkerFunction } + + + +import ImageSetsNormalizationResult from './image-sets-normalization-result.js' +export type { ImageSetsNormalizationResult } + +import ImageSetsNormalizationOptions from './image-sets-normalization-options.js' +export type { ImageSetsNormalizationOptions } + +import imageSetsNormalization from './image-sets-normalization.js' +export { imageSetsNormalization } diff --git a/packages/dicom/typescript/test/browser/demo-app/index.html b/packages/dicom/typescript/test/browser/demo-app/index.html index f2e908a15..4c0609d94 100644 --- a/packages/dicom/typescript/test/browser/demo-app/index.html +++ b/packages/dicom/typescript/test/browser/demo-app/index.html @@ -62,6 +62,7 @@

👨‍💻 Live API Demo ✨

readDicomEncapsulatedPdf structuredReportToHtml structuredReportToText + imageSetsNormalization readDicomTags readImageDicomFileSeries @@ -348,6 +349,36 @@

👨‍💻 Live API Demo ✨

+ + + Group DICOM files into image sets

+ +
+ + +

+ + +

+ + +

+ +
Load sample inputs + Run

+ +
+ + +
+ + Download +

+
+ +
+ + Read the tags from a DICOM file

diff --git a/packages/dicom/typescript/test/browser/demo-app/index.ts b/packages/dicom/typescript/test/browser/demo-app/index.ts index c3cdc456a..2c5c49656 100644 --- a/packages/dicom/typescript/test/browser/demo-app/index.ts +++ b/packages/dicom/typescript/test/browser/demo-app/index.ts @@ -20,6 +20,7 @@ import './apply-presentation-state-to-image-controller.js' import './read-dicom-encapsulated-pdf-controller.js' import './structured-report-to-html-controller.js' import './structured-report-to-text-controller.js' +import './image-sets-normalization-controller.js' import './read-dicom-tags-controller.js' import './read-image-dicom-file-series-controller.js' diff --git a/packages/dicom/typescript/test/node/gdcm.js b/packages/dicom/typescript/test/node/gdcm.js index bb1771f7b..2693a9b50 100644 --- a/packages/dicom/typescript/test/node/gdcm.js +++ b/packages/dicom/typescript/test/node/gdcm.js @@ -4,7 +4,7 @@ import glob from 'glob' import fs from 'fs-extra' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' -import { readImageDicomFileSeriesNode, readDicomTagsNode } from '../../dist/index-node.js' +import { readImageDicomFileSeriesNode, readDicomTagsNode, imageSetsNormalizationNode } from '../../dist/index-node.js' const testDataInputDirectory = path.resolve('..', 'test', 'data', 'input') const testSeriesDirectory = path.resolve(testDataInputDirectory, 'DicomImageOrientationTest') @@ -335,3 +335,10 @@ test('DICOM SOP: Nuclear Medicine Image.', async t => { ])) t.deepEqual(outputImage.size, [128, 128, 69]) }) + +test("imageSetsNormalizationNode returns image sets", async (t) => { + const { imageSetsMetadata } = await imageSetsNormalizationNode({ + files: testDicomSeriesFiles, + }); + t.assert(!!imageSetsMetadata); +});