tc-ui-toolkit
Version:
React components used to develop tools for the desktop app translationCore
647 lines (523 loc) • 65.3 kB
JavaScript
'use strict';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.verseArray = verseArray;
exports.getVerseSpanRange = getVerseSpanRange;
exports.getVerseList = getVerseList;
exports.isVerseSpan = isVerseSpan;
exports.isVerseList = isVerseList;
exports.isVerseSet = isVerseSet;
exports.getBibleElement = getBibleElement;
exports.getVerseDataFromBible = getVerseDataFromBible;
exports.isVerseInSpan = isVerseInSpan;
exports.getVerseData = getVerseData;
exports.getVerseMarker = getVerseMarker;
exports.createVerseMarker = createVerseMarker;
exports.verseString = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _deepEqual = _interopRequireDefault(require("deep-equal"));
var stringTokenizer = _interopRequireWildcard(require("string-punctuation-tokenizer"));
var _wordAligner = require("word-aligner");
var _bibleReferenceRange = require("bible-reference-range");
var highlightHelpers = _interopRequireWildcard(require("./highlightHelpers"));
var _htmlElementsHelpers = require("./htmlElementsHelpers");
var _usfmHelpers = require("./usfmHelpers");
var _stringHelpers = require("./stringHelpers");
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/**
* if showing USFM codes, replace newlines
* @param {string} text
* @param {boolean} showUsfm
* @return {JSX.Element}
*/
function textToHtml(text, showUsfm) {
if (showUsfm && text.indexOf('\n') >= 0) {
var parts = text.split('\n');
var html = [parts[0]];
for (var i = 1; i < parts.length; i++) {
html.push('↲');
html.push( /*#__PURE__*/_react["default"].createElement("br", null));
html.push(parts[i]);
}
return html;
}
return text;
}
/**
* render text as HTML and overlay any selections
* @param {String} verseText
* @param {Array} selections - text selections to highlight
* @param {Function} translate
* @param {Object} fontStyle - font specific styling
* @param {boolean} isTargetBible
* @param {String} fontClass
* @param {boolean} showUsfm
* @return {*}
*/
var verseString = function verseString(verseText, selections, translate) {
var fontStyle = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
var isTargetBible = arguments.length > 4 ? arguments[4] : undefined;
var fontClass = arguments.length > 5 ? arguments[5] : undefined;
var showUsfm = arguments.length > 6 ? arguments[6] : undefined;
var newVerseText = verseText;
if (!showUsfm) {
newVerseText = (0, _usfmHelpers.removeMarker)(verseText);
newVerseText = newVerseText.replace(/\s+/g, ' '); // if string only contains spaces then make it an empty string
newVerseText = newVerseText.replace(/\s/g, '').length === 0 ? '' : newVerseText;
} // if empty string then newVerseText = place holder warning.
if (newVerseText.length === 0) {
newVerseText = translate('pane.missing_verse_warning');
}
var verseTextSpans = /*#__PURE__*/_react["default"].createElement("span", {
className: fontClass
}, textToHtml(newVerseText, showUsfm));
if (!showUsfm && selections && selections.length > 0) {
var _selectionArray = stringTokenizer.selectionArray(newVerseText, selections);
verseTextSpans = [];
verseTextSpans.length = 0;
for (var i = 0, len = _selectionArray.length; i < len; i++) {
var selection = _selectionArray[i];
var index = i;
var spanStyle = {
backgroundColor: selection.selected ? 'var(--highlight-color)' : ''
};
if (fontStyle) {
spanStyle = _objectSpread(_objectSpread({}, spanStyle), fontStyle);
}
verseTextSpans.push( /*#__PURE__*/_react["default"].createElement("span", {
key: index,
className: fontClass,
style: spanStyle
}, selection.text));
}
}
return verseTextSpans;
};
/**
* create verse elements from an array of verse objects
* @param {Array|Object} verseText - verse data
* @param {String} bibleId
* @param {Object} contextId
* @param {Function} getLexiconData
* @param {Boolean} showPopover
* @param {Function} translate
* @param {Object} fontStyle - font specific styling
* @param {String} fontClass - font class name
* @param {array} verseWordCounts - array of word counts for multi-verse
* @return {Array} - verse elements to display
*/
exports.verseString = verseString;
function verseArray() {
var verseText = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var bibleId = arguments.length > 1 ? arguments[1] : undefined;
var contextId = arguments.length > 2 ? arguments[2] : undefined;
var getLexiconData = arguments.length > 3 ? arguments[3] : undefined;
var showPopover = arguments.length > 4 ? arguments[4] : undefined;
var translate = arguments.length > 5 ? arguments[5] : undefined;
var fontStyle = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
var fontClass = arguments.length > 7 ? arguments[7] : undefined;
var verseWordCounts = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : null;
var verseObjects = _wordAligner.VerseObjectUtils.getWordListForVerse(verseText);
var wordSpacing = '';
var previousWord = null;
var verseSpan = [];
verseSpan.length = 0;
if (verseText.verseObjects && (0, _stringHelpers.textIsEmptyInVerseObject)(verseText, bibleId)) {
// if empty verse string.
verseSpan.push( /*#__PURE__*/_react["default"].createElement("span", {
key: translate('pane.missing_verse_warning')
}, translate('pane.missing_verse_warning')));
} else {
(function () {
var isHebrew = bibleId === 'uhb';
var origLangBible = isHebrew || bibleId === 'ugnt';
verseObjects = Array.isArray(verseObjects) ? verseObjects : verseObjects.verseObject;
var _loop = function _loop(i, len) {
var object = verseObjects[i];
var index = i;
var nextWord = verseObjects[index + 1];
if (object.type === 'html') {
verseSpan.push(object.html);
} else if ((0, _stringHelpers.isWord)(object)) {
var padding = wordSpacing;
wordSpacing = ' '; // spacing between words
var text = object.word || object.text;
var isHighlightedWord = false;
var isBetweenHighlightedWord = false;
if (origLangBible && contextId.quote && object.text) {
isHighlightedWord = highlightHelpers.isWordMatch(object, contextId, verseObjects, index);
isBetweenHighlightedWord = previousWord && !(0, _deepEqual["default"])(previousWord, object) && highlightHelpers.isWordMatch(previousWord, contextId, verseObjects, index - 1) && isHighlightedWord;
} else if (contextId.quote && object.content) {
var highlightedDetails = highlightHelpers.getWordHighlightedDetails(contextId, previousWord, object, verseWordCounts);
isHighlightedWord = highlightedDetails.isHighlightedWord;
isBetweenHighlightedWord = highlightedDetails.isBetweenHighlightedWord;
} // Save word to be used as previousWord in next word.
previousWord = object;
var paddingSpanStyle = {
backgroundColor: isBetweenHighlightedWord ? 'var(--highlight-color)' : 'transparent'
}; // TRICKY: for now we are disabling lexicon popups for any bible that is not ugnt or uhb. The reason for
// this is than some bibles have different strongs format. We are waiting on long term solution.
if (object.strong && origLangBible) {
// if clickable
var spanStyle = {
backgroundColor: isHighlightedWord ? 'var(--highlight-color)' : ''
};
if (fontStyle) {
spanStyle = _objectSpread(_objectSpread({}, spanStyle), fontStyle);
}
verseSpan.push( /*#__PURE__*/_react["default"].createElement("span", {
key: index.toString(),
onClick: function onClick(e) {
return (0, _htmlElementsHelpers.onWordClick)(e, object, getLexiconData, showPopover, translate, isHebrew);
},
style: {
cursor: 'pointer'
}
}, /*#__PURE__*/_react["default"].createElement("span", {
className: fontClass,
style: paddingSpanStyle
}, padding), /*#__PURE__*/_react["default"].createElement("span", {
className: fontClass,
style: spanStyle
}, (0, _usfmHelpers.removeMarker)(text))));
} else {
verseSpan.push((0, _htmlElementsHelpers.createNonClickableSpan)(index, paddingSpanStyle, padding, isHighlightedWord, text, fontClass));
}
} else if ((0, _stringHelpers.isNestedMilestone)(object)) {
// if nested milestone
var nestedMilestone = highlightHelpers.getWordsFromNestedMilestone(object, contextId, index, previousWord, wordSpacing, fontClass, verseWordCounts);
for (var j = 0, nLen = nestedMilestone.wordSpans.length; j < nLen; j++) {
var nestedWordSpan = nestedMilestone.wordSpans[j];
verseSpan.push(nestedWordSpan);
}
previousWord = nestedMilestone.nestedPreviousWord;
wordSpacing = nestedMilestone.nestedWordSpacing;
} else if (object.text) {
// if not word, show punctuation, etc. but not clickable
var _text = object.text;
if ((0, _usfmHelpers.hasLeadingSpace)(_text)) {
// leading spaces are not significant in html, so we need to replace with a hard space
_text = _text.substr(1);
highlightHelpers.addSpace(verseSpan, fontClass);
}
var trailingSpace = (0, _usfmHelpers.hasTrailingSpace)(_text);
if (trailingSpace && _text) {
// trailing spaces are not significant in html, so we need to replace with a hard space
_text = _text.substr(0, _text.length - 1);
}
var isUsfmTagNotSpan = object.tag && !object.endTag; // see if USFM tag does not have a matching end tag.
if (isUsfmTagNotSpan || (0, _stringHelpers.isIsolatedLeftQuote)(_text)) {
// if this was not just simple text marker, need to add whitespace
highlightHelpers.addSpace(verseSpan);
}
wordSpacing = (0, _stringHelpers.punctuationWordSpacing)(object); // spacing before words
if (highlightHelpers.isPunctuationHighlighted(previousWord, nextWord, contextId, verseObjects, index, verseWordCounts)) {
verseSpan.push((0, _htmlElementsHelpers.createHighlightedSpan)(index, _text, fontClass));
} else {
verseSpan.push((0, _htmlElementsHelpers.createTextSpan)(index, _text, fontClass));
}
if (trailingSpace) {
// add the trailing space after the text span
highlightHelpers.addSpace(verseSpan);
}
}
};
for (var i = 0, len = verseObjects.length; i < len; i++) {
_loop(i, len);
}
})();
}
return verseSpan;
}
/**
* get verse range from span
* @param {string} verseSpan
* @return {{high: number, low: number}}
*/
function getVerseSpanRange(verseSpan) {
var _verseSpan$split = verseSpan.split('-'),
_verseSpan$split2 = (0, _slicedToArray2["default"])(_verseSpan$split, 2),
low = _verseSpan$split2[0],
high = _verseSpan$split2[1];
if (low && high) {
low = parseInt(low, 10);
high = parseInt(high, 10);
if (low > 0 && high >= low) {
return {
low: low,
high: high
};
}
}
return {};
}
/**
* splits verse list into individual verses
* @param {string} verseStr
* @return {[number]}
*/
function getVerseList(verseStr) {
var verses = verseStr.toString().split(',');
return verses;
}
/**
* test if verse is valid verse span string
* @param {string|number} verse
* @return {boolean}
*/
function isVerseSpan(verse) {
var isSpan = typeof verse === 'string' && verse.includes('-');
return isSpan;
}
/**
* test if verse is valid verse list (verse numbers separated by commas)
* @param {string|number} verse
* @return {boolean}
*/
function isVerseList(verse) {
var isList = typeof verse === 'string' && verse.includes(',');
return isList;
}
/**
* test if verse is valid verse span or verse list
* @param {string|number} verse
* @return {boolean}
*/
function isVerseSet(verse) {
var isSet = isVerseSpan(verse) || isVerseList(verse);
return isSet;
}
/**
* get bible from bibles
* @param {object} bibles
* @param {string} languageId
* @param owner
* @param bibleId
* @return {*}
*/
function getBibleElement(bibles, languageId, bibleId) {
var _bibles$key;
var owner = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
var key = owner && languageId !== 'targetLanguage' ? "".concat(languageId, "_").concat(owner) : languageId;
var bibleElement = (_bibles$key = bibles[key]) === null || _bibles$key === void 0 ? void 0 : _bibles$key[bibleId];
return bibleElement;
}
/**
* try to find verse from chapter. If not found look for verse spans
* @param {object} bible
* @param {string} chapter
* @param {string} verse
* @return {object|null}
*/
function getVerseDataFromBible(bible, chapter, verse) {
var verseData = null;
var verseLabel = null;
try {
var chapterData = bible[chapter];
if (chapterData) {
verseData = chapterData[verse];
if (verseData) {
verseLabel = verse;
} else {
// search for verse span that contains verse
var verseVal = parseInt(verse);
for (var verseIndex in chapterData) {
if (isVerseSpan(verseIndex)) {
var _getVerseSpanRange = getVerseSpanRange(verseIndex),
low = _getVerseSpanRange.low,
high = _getVerseSpanRange.high;
if (verseVal >= low && verseVal <= high) {
verseData = chapterData[verseIndex];
verseLabel = verseIndex;
break;
}
}
}
}
} // eslint-disable-next-line no-empty
} catch (e) {}
return {
verseData: verseData,
verseLabel: verseLabel
};
}
/**
* check to see if verseLabel is a span, if so see if verse is the first verse in the span
* @param {string} verseLabel - verse label to test for span
* @param {string|number} verse - verse number to check if first verse in span
* @return {object|null}
*/
function isVerseInSpan(verseLabel, verse) {
var isVerseSpan = false,
isFirstVerse = false;
if (verseLabel) {
try {
var _verseLabel$split = verseLabel.split('-'),
_verseLabel$split2 = (0, _slicedToArray2["default"])(_verseLabel$split, 2),
hi = _verseLabel$split2[1];
isVerseSpan = !!hi;
if (isVerseSpan) {
if (typeof verse === 'string') {
verse = parseInt(verse);
}
var startVerse = parseInt(verseLabel);
isFirstVerse = verse === startVerse;
} // eslint-disable-next-line no-empty
} catch (e) {}
}
return {
isVerseSpan: isVerseSpan,
isFirstVerse: isFirstVerse
};
}
/**
* count original words in verseObjects - it is nested so this is recursive
* @param {array} verseObjects
* @param {number} verseCnt
* @param {boolean} multiVerse
* @param {object} previousVerseWordCounts
* @param {object} currentVerseCounts
*/
function countOriginalWords(verseObjects, verseCnt, multiVerse, currentVerseCounts, previousVerseWordCounts) {
if (verseObjects) {
var _iterator = _createForOfIteratorHelper(verseObjects),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var vo = _step.value;
if (multiVerse && (vo === null || vo === void 0 ? void 0 : vo.tag) === 'zaln') {
vo.verseCnt = verseCnt;
var origWord = vo === null || vo === void 0 ? void 0 : vo.content;
if (origWord) {
var previousCount = previousVerseWordCounts[origWord] || 0;
var currentCount = currentVerseCounts[origWord] || 0;
if (!currentCount) {
currentVerseCounts[origWord] = vo.occurrences + previousCount;
}
if (vo.children) {
countOriginalWords(vo.children, verseCnt, multiVerse, currentVerseCounts, previousVerseWordCounts);
}
}
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
}
/**
* gets verse data for verseList
* @param {object} bookData
* @param {number|string} chapter
* @param {string} verseList - can be a single verse, comma separated list of verses or verse range
* @param {function} createVerseMarker - to create a verse marker
* @returns {{verseData: {verseObjects: *[]}, verseLabel: string}}
*/
function getVerseData(bookData, chapter, verseList, createVerseMarker) {
var verseLabel = '';
var initialChapter;
var refs = (0, _bibleReferenceRange.getVerses)(bookData, "".concat(chapter, ":").concat(verseList));
var verseSpanData = [];
var history = []; // to guard against duplicate verses
var verseWordCounts = [];
var multiVerse = refs.length > 1;
if (refs && refs.length) {
initialChapter = refs[0].chapter;
}
for (var verseCnt = 0; verseCnt < refs.length; verseCnt++) {
var previousVerseWordCounts = verseCnt > 0 ? verseWordCounts[verseCnt - 1] : {};
var currentVerseCounts = {};
verseWordCounts.push(currentVerseCounts);
var ref = refs[verseCnt];
var _chapter = ref.chapter;
var data = ref.verseData;
var label = ref.verse;
if (_chapter !== initialChapter) {
label = "".concat(_chapter, ":").concat(label);
}
if (data && !history.includes(label)) {
// skip over duplicates
history.push(label + '');
if (verseSpanData.length) {
verseSpanData.push(createVerseMarker(label));
}
if (typeof data === 'string') {
// if data is stringtype , we need to wrap as a text verse object
verseSpanData.push({
type: 'text',
text: data
});
} else {
// get cumulative word counts for each verse
var verseObjects = data === null || data === void 0 ? void 0 : data.verseObjects;
if (verseObjects) {
countOriginalWords(verseObjects, verseCnt, multiVerse, currentVerseCounts, previousVerseWordCounts, verseWordCounts);
Array.prototype.push.apply(verseSpanData, data.verseObjects);
var words = Object.keys(previousVerseWordCounts);
for (var _i = 0, _words = words; _i < _words.length; _i++) {
var word = _words[_i];
// update current verse with counts from previous verse
if (!currentVerseCounts[word]) {
currentVerseCounts[word] = previousVerseWordCounts[word];
}
}
}
}
if (!verseLabel) {
verseLabel = label.toString();
}
}
}
if (!multiVerse) {
verseWordCounts = null;
}
var verseData = {
verseObjects: verseSpanData
};
return {
verseData: verseData,
verseLabel: verseLabel,
multiVerse: multiVerse,
verseWordCounts: verseWordCounts
};
}
/**
* create html to mark verse
* @param verse
* @return {JSX.Element}
*/
function getVerseMarker(verse) {
return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement("br", null), /*#__PURE__*/_react["default"].createElement("b", null, verse), " ");
}
/**
* create an html object to insert into scripture pane
* @param {JSX.Element} html
* @return {{html, text: string, type: string}}
*/
function createHtmlInsert(html) {
return {
type: 'html',
html: html,
text: ''
};
}
/**
* create an object to mark the beginning of a verse
* @param {string} verse
* @return {object}
*/
function createVerseMarker(verse) {
return createHtmlInsert(getVerseMarker(verse));
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9TY3JpcHR1cmVQYW5lL2hlbHBlcnMvdmVyc2VIZWxwZXJzLmpzIl0sIm5hbWVzIjpbInRleHRUb0h0bWwiLCJ0ZXh0Iiwic2hvd1VzZm0iLCJpbmRleE9mIiwicGFydHMiLCJzcGxpdCIsImh0bWwiLCJpIiwibGVuZ3RoIiwicHVzaCIsInZlcnNlU3RyaW5nIiwidmVyc2VUZXh0Iiwic2VsZWN0aW9ucyIsInRyYW5zbGF0ZSIsImZvbnRTdHlsZSIsImlzVGFyZ2V0QmlibGUiLCJmb250Q2xhc3MiLCJuZXdWZXJzZVRleHQiLCJyZXBsYWNlIiwidmVyc2VUZXh0U3BhbnMiLCJfc2VsZWN0aW9uQXJyYXkiLCJzdHJpbmdUb2tlbml6ZXIiLCJzZWxlY3Rpb25BcnJheSIsImxlbiIsInNlbGVjdGlvbiIsImluZGV4Iiwic3BhblN0eWxlIiwiYmFja2dyb3VuZENvbG9yIiwic2VsZWN0ZWQiLCJ2ZXJzZUFycmF5IiwiYmlibGVJZCIsImNvbnRleHRJZCIsImdldExleGljb25EYXRhIiwic2hvd1BvcG92ZXIiLCJ2ZXJzZVdvcmRDb3VudHMiLCJ2ZXJzZU9iamVjdHMiLCJWZXJzZU9iamVjdFV0aWxzIiwiZ2V0V29yZExpc3RGb3JWZXJzZSIsIndvcmRTcGFjaW5nIiwicHJldmlvdXNXb3JkIiwidmVyc2VTcGFuIiwiaXNIZWJyZXciLCJvcmlnTGFuZ0JpYmxlIiwiQXJyYXkiLCJpc0FycmF5IiwidmVyc2VPYmplY3QiLCJvYmplY3QiLCJuZXh0V29yZCIsInR5cGUiLCJwYWRkaW5nIiwid29yZCIsImlzSGlnaGxpZ2h0ZWRXb3JkIiwiaXNCZXR3ZWVuSGlnaGxpZ2h0ZWRXb3JkIiwicXVvdGUiLCJoaWdobGlnaHRIZWxwZXJzIiwiaXNXb3JkTWF0Y2giLCJjb250ZW50IiwiaGlnaGxpZ2h0ZWREZXRhaWxzIiwiZ2V0V29yZEhpZ2hsaWdodGVkRGV0YWlscyIsInBhZGRpbmdTcGFuU3R5bGUiLCJzdHJvbmciLCJ0b1N0cmluZyIsImUiLCJjdXJzb3IiLCJuZXN0ZWRNaWxlc3RvbmUiLCJnZXRXb3Jkc0Zyb21OZXN0ZWRNaWxlc3RvbmUiLCJqIiwibkxlbiIsIndvcmRTcGFucyIsIm5lc3RlZFdvcmRTcGFuIiwibmVzdGVkUHJldmlvdXNXb3JkIiwibmVzdGVkV29yZFNwYWNpbmciLCJzdWJzdHIiLCJhZGRTcGFjZSIsInRyYWlsaW5nU3BhY2UiLCJpc1VzZm1UYWdOb3RTcGFuIiwidGFnIiwiZW5kVGFnIiwiaXNQdW5jdHVhdGlvbkhpZ2hsaWdodGVkIiwiZ2V0VmVyc2VTcGFuUmFuZ2UiLCJsb3ciLCJoaWdoIiwicGFyc2VJbnQiLCJnZXRWZXJzZUxpc3QiLCJ2ZXJzZVN0ciIsInZlcnNlcyIsImlzVmVyc2VTcGFuIiwidmVyc2UiLCJpc1NwYW4iLCJpbmNsdWRlcyIsImlzVmVyc2VMaXN0IiwiaXNMaXN0IiwiaXNWZXJzZVNldCIsImlzU2V0IiwiZ2V0QmlibGVFbGVtZW50IiwiYmlibGVzIiwibGFuZ3VhZ2VJZCIsIm93bmVyIiwia2V5IiwiYmlibGVFbGVtZW50IiwiZ2V0VmVyc2VEYXRhRnJvbUJpYmxlIiwiYmlibGUiLCJjaGFwdGVyIiwidmVyc2VEYXRhIiwidmVyc2VMYWJlbCIsImNoYXB0ZXJEYXRhIiwidmVyc2VWYWwiLCJ2ZXJzZUluZGV4IiwiaXNWZXJzZUluU3BhbiIsImlzRmlyc3RWZXJzZSIsImhpIiwic3RhcnRWZXJzZSIsImNvdW50T3JpZ2luYWxXb3JkcyIsInZlcnNlQ250IiwibXVsdGlWZXJzZSIsImN1cnJlbnRWZXJzZUNvdW50cyIsInByZXZpb3VzVmVyc2VXb3JkQ291bnRzIiwidm8iLCJvcmlnV29yZCIsInByZXZpb3VzQ291bnQiLCJjdXJyZW50Q291bnQiLCJvY2N1cnJlbmNlcyIsImNoaWxkcmVuIiwiZ2V0VmVyc2VEYXRhIiwiYm9va0RhdGEiLCJ2ZXJzZUxpc3QiLCJjcmVhdGVWZXJzZU1hcmtlciIsImluaXRpYWxDaGFwdGVyIiwicmVmcyIsInZlcnNlU3BhbkRhdGEiLCJoaXN0b3J5IiwicmVmIiwiZGF0YSIsImxhYmVsIiwicHJvdG90eXBlIiwiYXBwbHkiLCJ3b3JkcyIsIk9iamVjdCIsImtleXMiLCJnZXRWZXJzZU1hcmtlciIsImNyZWF0ZUh0bWxJbnNlcnQiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFNQTs7QUFLQTs7Ozs7Ozs7Ozs7O0FBUUE7Ozs7OztBQU1BLFNBQVNBLFVBQVQsQ0FBb0JDLElBQXBCLEVBQTBCQyxRQUExQixFQUFvQztBQUNsQyxNQUFJQSxRQUFRLElBQUtELElBQUksQ0FBQ0UsT0FBTCxDQUFhLElBQWIsS0FBc0IsQ0FBdkMsRUFBMkM7QUFDekMsUUFBTUMsS0FBSyxHQUFHSCxJQUFJLENBQUNJLEtBQUwsQ0FBVyxJQUFYLENBQWQ7QUFDQSxRQUFNQyxJQUFJLEdBQUcsQ0FBQ0YsS0FBSyxDQUFDLENBQUQsQ0FBTixDQUFiOztBQUVBLFNBQUssSUFBSUcsQ0FBQyxHQUFHLENBQWIsRUFBZ0JBLENBQUMsR0FBR0gsS0FBSyxDQUFDSSxNQUExQixFQUFrQ0QsQ0FBQyxFQUFuQyxFQUF1QztBQUNyQ0QsTUFBQUEsSUFBSSxDQUFDRyxJQUFMLENBQVUsR0FBVjtBQUNBSCxNQUFBQSxJQUFJLENBQUNHLElBQUwsZUFBVSwyQ0FBVjtBQUNBSCxNQUFBQSxJQUFJLENBQUNHLElBQUwsQ0FBVUwsS0FBSyxDQUFDRyxDQUFELENBQWY7QUFDRDs7QUFDRCxXQUFPRCxJQUFQO0FBQ0Q7O0FBQ0QsU0FBT0wsSUFBUDtBQUNEO0FBRUQ7Ozs7Ozs7Ozs7Ozs7QUFXTyxJQUFNUyxXQUFXLEdBQUcsU0FBZEEsV0FBYyxDQUFDQyxTQUFELEVBQVlDLFVBQVosRUFBd0JDLFNBQXhCLEVBQTRGO0FBQUEsTUFBekRDLFNBQXlELHVFQUE3QyxJQUE2QztBQUFBLE1BQXZDQyxhQUF1QztBQUFBLE1BQXhCQyxTQUF3QjtBQUFBLE1BQWJkLFFBQWE7QUFDckgsTUFBSWUsWUFBWSxHQUFHTixTQUFuQjs7QUFFQSxNQUFJLENBQUNULFFBQUwsRUFBZTtBQUNiZSxJQUFBQSxZQUFZLEdBQUcsK0JBQWFOLFNBQWIsQ0FBZjtBQUNBTSxJQUFBQSxZQUFZLEdBQUdBLFlBQVksQ0FBQ0MsT0FBYixDQUFxQixNQUFyQixFQUE2QixHQUE3QixDQUFmLENBRmEsQ0FHYjs7QUFDQUQsSUFBQUEsWUFBWSxHQUFHQSxZQUFZLENBQUNDLE9BQWIsQ0FBcUIsS0FBckIsRUFBNEIsRUFBNUIsRUFBZ0NWLE1BQWhDLEtBQTJDLENBQTNDLEdBQStDLEVBQS9DLEdBQW9EUyxZQUFuRTtBQUNELEdBUm9ILENBVXJIOzs7QUFDQSxNQUFJQSxZQUFZLENBQUNULE1BQWIsS0FBd0IsQ0FBNUIsRUFBK0I7QUFDN0JTLElBQUFBLFlBQVksR0FBR0osU0FBUyxDQUFDLDRCQUFELENBQXhCO0FBQ0Q7O0FBRUQsTUFBSU0sY0FBYyxnQkFBRztBQUFNLElBQUEsU0FBUyxFQUFFSDtBQUFqQixLQUE2QmhCLFVBQVUsQ0FBQ2lCLFlBQUQsRUFBZWYsUUFBZixDQUF2QyxDQUFyQjs7QUFFQSxNQUFJLENBQUNBLFFBQUQsSUFBYVUsVUFBYixJQUEyQkEsVUFBVSxDQUFDSixNQUFYLEdBQW9CLENBQW5ELEVBQXNEO0FBQ3BELFFBQU1ZLGVBQWUsR0FBR0MsZUFBZSxDQUFDQyxjQUFoQixDQUErQkwsWUFBL0IsRUFBNkNMLFVBQTdDLENBQXhCOztBQUNBTyxJQUFBQSxjQUFjLEdBQUcsRUFBakI7QUFDQUEsSUFBQUEsY0FBYyxDQUFDWCxNQUFmLEdBQXdCLENBQXhCOztBQUVBLFNBQUssSUFBSUQsQ0FBQyxHQUFHLENBQVIsRUFBV2dCLEdBQUcsR0FBR0gsZUFBZSxDQUFDWixNQUF0QyxFQUE4Q0QsQ0FBQyxHQUFHZ0IsR0FBbEQsRUFBdURoQixDQUFDLEVBQXhELEVBQTREO0FBQzFELFVBQU1pQixTQUFTLEdBQUdKLGVBQWUsQ0FBQ2IsQ0FBRCxDQUFqQztBQUNBLFVBQU1rQixLQUFLLEdBQUdsQixDQUFkO0FBQ0EsVUFBSW1CLFNBQVMsR0FBRztBQUFFQyxRQUFBQSxlQUFlLEVBQUVILFNBQVMsQ0FBQ0ksUUFBVixHQUFxQix3QkFBckIsR0FBZ0Q7QUFBbkUsT0FBaEI7O0FBRUEsVUFBSWQsU0FBSixFQUFlO0FBQ2JZLFFBQUFBLFNBQVMsbUNBQ0pBLFNBREksR0FFSlosU0FGSSxDQUFUO0FBSUQ7O0FBQ0RLLE1BQUFBLGNBQWMsQ0FBQ1YsSUFBZixlQUNFO0FBQU0sUUFBQSxHQUFHLEVBQUVnQixLQUFYO0FBQWtCLFFBQUEsU0FBUyxFQUFFVCxTQUE3QjtBQUF3QyxRQUFBLEtBQUssRUFBRVU7QUFBL0MsU0FDR0YsU0FBUyxDQUFDdkIsSUFEYixDQURGO0FBS0Q7QUFDRjs7QUFFRCxTQUFPa0IsY0FBUDtBQUNELENBMUNNO0FBNENQOzs7Ozs7Ozs7Ozs7Ozs7OztBQWFPLFNBQVNVLFVBQVQsR0FBcUo7QUFBQSxNQUFqSWxCLFNBQWlJLHVFQUFySCxFQUFxSDtBQUFBLE1BQWpIbUIsT0FBaUg7QUFBQSxNQUF4R0MsU0FBd0c7QUFBQSxNQUE3RkMsY0FBNkY7QUFBQSxNQUE3RUMsV0FBNkU7QUFBQSxNQUFoRXBCLFNBQWdFO0FBQUEsTUFBckRDLFNBQXFELHVFQUF6QyxJQUF5QztBQUFBLE1BQW5DRSxTQUFtQztBQUFBLE1BQXhCa0IsZUFBd0IsdUVBQU4sSUFBTTs7QUFDMUosTUFBSUMsWUFBWSxHQUFHQyw4QkFBaUJDLG1CQUFqQixDQUFxQzFCLFNBQXJDLENBQW5COztBQUNBLE1BQUkyQixXQUFXLEdBQUcsRUFBbEI7QUFDQSxNQUFJQyxZQUFZLEdBQUcsSUFBbkI7QUFDQSxNQUFNQyxTQUFTLEdBQUcsRUFBbEI7QUFDQUEsRUFBQUEsU0FBUyxDQUFDaEMsTUFBVixHQUFtQixDQUFuQjs7QUFFQSxNQUFJRyxTQUFTLENBQUN3QixZQUFWLElBQTBCLDZDQUF5QnhCLFNBQXpCLEVBQW9DbUIsT0FBcEMsQ0FBOUIsRUFBNEU7QUFBRTtBQUM1RVUsSUFBQUEsU0FBUyxDQUFDL0IsSUFBVixlQUNFO0FBQU0sTUFBQSxHQUFHLEVBQUVJLFNBQVMsQ0FBQyw0QkFBRDtBQUFwQixPQUNHQSxTQUFTLENBQUMsNEJBQUQsQ0FEWixDQURGO0FBS0QsR0FORCxNQU1PO0FBQUE7QUFDTCxVQUFNNEIsUUFBUSxHQUFJWCxPQUFPLEtBQUssS0FBOUI7QUFDQSxVQUFNWSxhQUFhLEdBQUdELFFBQVEsSUFBSVgsT0FBTyxLQUFLLE1BQTlDO0FBQ0FLLE1BQUFBLFlBQVksR0FBR1EsS0FBSyxDQUFDQyxPQUFOLENBQWNULFlBQWQsSUFBOEJBLFlBQTlCLEdBQTZDQSxZQUFZLENBQUNVLFdBQXpFOztBQUhLLGlDQUtJdEMsQ0FMSixFQUtXZ0IsR0FMWDtBQU1ILFlBQU11QixNQUFNLEdBQUdYLFlBQVksQ0FBQzVCLENBQUQsQ0FBM0I7QUFDQSxZQUFNa0IsS0FBSyxHQUFHbEIsQ0FBZDtBQUNBLFlBQU13QyxRQUFRLEdBQUdaLFlBQVksQ0FBQ1YsS0FBSyxHQUFHLENBQVQsQ0FBN0I7O0FBRUEsWUFBSXFCLE1BQU0sQ0FBQ0UsSUFBUCxLQUFnQixNQUFwQixFQUE0QjtBQUMxQlIsVUFBQUEsU0FBUyxDQUFDL0IsSUFBVixDQUFlcUMsTUFBTSxDQUFDeEMsSUFBdEI7QUFDRCxTQUZELE1BRU8sSUFBSSwyQkFBT3dDLE1BQVAsQ0FBSixFQUFvQjtBQUN6QixjQUFNRyxPQUFPLEdBQUdYLFdBQWhCO0FBQ0FBLFVBQUFBLFdBQVcsR0FBRyxHQUFkLENBRnlCLENBRU47O0FBQ25CLGNBQU1yQyxJQUFJLEdBQUk2QyxNQUFNLENBQUNJLElBQVAsSUFBZUosTUFBTSxDQUFDN0MsSUFBcEM7QUFDQSxjQUFJa0QsaUJBQWlCLEdBQUcsS0FBeEI7QUFDQSxjQUFJQyx3QkFBd0IsR0FBRyxLQUEvQjs7QUFFQSxjQUFJVixhQUFhLElBQUlYLFNBQVMsQ0FBQ3NCLEtBQTNCLElBQW9DUCxNQUFNLENBQUM3QyxJQUEvQyxFQUFxRDtBQUNuRGtELFlBQUFBLGlCQUFpQixHQUFHRyxnQkFBZ0IsQ0FBQ0MsV0FBakIsQ0FBNkJULE1BQTdCLEVBQXFDZixTQUFyQyxFQUFnREksWUFBaEQsRUFBOERWLEtBQTlELENBQXBCO0FBQ0EyQixZQUFBQSx3QkFBd0IsR0FBR2IsWUFBWSxJQUFJLENBQUMsMkJBQVFBLFlBQVIsRUFBc0JPLE1BQXRCLENBQWpCLElBQ3pCUSxnQkFBZ0IsQ0FBQ0MsV0FBakIsQ0FBNkJoQixZQUE3QixFQUEyQ1IsU0FBM0MsRUFBc0RJLFlBQXRELEVBQW9FVixLQUFLLEdBQUcsQ0FBNUUsQ0FEeUIsSUFDeUQwQixpQkFEcEY7QUFFRCxXQUpELE1BSU8sSUFBSXBCLFNBQVMsQ0FBQ3NCLEtBQVYsSUFBbUJQLE1BQU0sQ0FBQ1UsT0FBOUIsRUFBdUM7QUFDNUMsZ0JBQU1DLGtCQUFrQixHQUFHSCxnQkFBZ0IsQ0FBQ0kseUJBQWpCLENBQTJDM0IsU0FBM0MsRUFBc0RRLFlBQXRELEVBQW9FTyxNQUFwRSxFQUE0RVosZUFBNUUsQ0FBM0I7QUFDQWlCLFlBQUFBLGlCQUFpQixHQUFHTSxrQkFBa0IsQ0FBQ04saUJBQXZDO0FBQ0FDLFlBQUFBLHdCQUF3QixHQUFHSyxrQkFBa0IsQ0FBQ0wsd0JBQTlDO0FBQ0QsV0Fmd0IsQ0FnQnpCOzs7QUFDQWIsVUFBQUEsWUFBWSxHQUFHTyxNQUFmO0FBQ0EsY0FBTWEsZ0JBQWdCLEdBQUc7QUFBRWhDLFlBQUFBLGVBQWUsRUFBRXlCLHdCQUF3QixHQUFHLHdCQUFILEdBQThCO0FBQXpFLFdBQXpCLENBbEJ5QixDQW9CekI7QUFDQTs7QUFDQSxjQUFJTixNQUFNLENBQUNjLE1BQVAsSUFBaUJsQixhQUFyQixFQUFvQztBQUFFO0FBQ3BDLGdCQUFJaEIsU0FBUyxHQUFHO0FBQUVDLGNBQUFBLGVBQWUsRUFBRXdCLGlCQUFpQixHQUFHLHdCQUFILEdBQThCO0FBQWxFLGFBQWhCOztBQUVBLGdCQUFJckMsU0FBSixFQUFlO0FBQ2JZLGNBQUFBLFNBQVMsbUNBQ0pBLFNBREksR0FFSlosU0FGSSxDQUFUO0FBSUQ7O0FBQ0QwQixZQUFBQSxTQUFTLENBQUMvQixJQUFWLGVBQ0U7QUFDRSxjQUFBLEdBQUcsRUFBRWdCLEtBQUssQ0FBQ29DLFFBQU4sRUFEUDtBQUVFLGNBQUEsT0FBTyxFQUFFLGlCQUFDQyxDQUFEO0FBQUEsdUJBQU8sc0NBQVlBLENBQVosRUFBZWhCLE1BQWYsRUFBdUJkLGNBQXZCLEVBQXVDQyxXQUF2QyxFQUFvRHBCLFNBQXBELEVBQStENEIsUUFBL0QsQ0FBUDtBQUFBLGVBRlg7QUFHRSxjQUFBLEtBQUssRUFBRTtBQUFFc0IsZ0JBQUFBLE1BQU0sRUFBRTtBQUFWO0FBSFQsNEJBS0U7QUFBTSxjQUFBLFNBQVMsRUFBRS9DLFNBQWpCO0FBQTRCLGNBQUEsS0FBSyxFQUFFMkM7QUFBbkMsZUFDR1YsT0FESCxDQUxGLGVBUUU7QUFBTSxjQUFBLFNBQVMsRUFBRWpDLFNBQWpCO0FBQTRCLGNBQUEsS0FBSyxFQUFFVTtBQUFuQyxlQUNHLCtCQUFhekIsSUFBYixDQURILENBUkYsQ0FERjtBQWNELFdBdkJELE1BdUJPO0FBQ0x1QyxZQUFBQSxTQUFTLENBQUMvQixJQUFWLENBQWUsaURBQXVCZ0IsS0FBdkIsRUFBOEJrQyxnQkFBOUIsRUFBZ0RWLE9BQWhELEVBQXlERSxpQkFBekQsRUFBNEVsRCxJQUE1RSxFQUFrRmUsU0FBbEYsQ0FBZjtBQUNEO0FBQ0YsU0FoRE0sTUFnREEsSUFBSSxzQ0FBa0I4QixNQUFsQixDQUFKLEVBQStCO0FBQUU7QUFDdEMsY0FBTWtCLGVBQWUsR0FBR1YsZ0JBQWdCLENBQUNXLDJCQUFqQixDQUE2Q25CLE1BQTdDLEVBQXFEZixTQUFyRCxFQUFnRU4sS0FBaEUsRUFBdUVjLFlBQXZFLEVBQXFGRCxXQUFyRixFQUFrR3RCLFNBQWxHLEVBQTZHa0IsZUFBN0csQ0FBeEI7O0FBRUEsZUFBSyxJQUFJZ0MsQ0FBQyxHQUFHLENBQVIsRUFBV0MsSUFBSSxHQUFHSCxlQUFlLENBQUNJLFNBQWhCLENBQTBCNUQsTUFBakQsRUFBeUQwRCxDQUFDLEdBQUdDLElBQTdELEVBQW1FRCxDQUFDLEVBQXBFLEVBQXdFO0FBQ3RFLGdCQUFNRyxjQUFjLEdBQUdMLGVBQWUsQ0FBQ0ksU0FBaEIsQ0FBMEJGLENBQTFCLENBQXZCO0FBQ0ExQixZQUFBQSxTQUFTLENBQUMvQixJQUFWLENBQWU0RCxjQUFmO0FBQ0Q7O0FBQ0Q5QixVQUFBQSxZQUFZLEdBQUd5QixlQUFlLENBQUNNLGtCQUEvQjtBQUNBaEMsVUFBQUEsV0FBVyxHQUFHMEIsZUFBZSxDQUFDTyxpQkFBOUI7QUFDRCxTQVRNLE1BU0EsSUFBSXpCLE1BQU0sQ0FBQzdDLElBQVgsRUFBaUI7QUFBRTtBQUN4QixjQUFJQSxLQUFJLEdBQUc2QyxNQUFNLENBQUM3QyxJQUFsQjs7QUFFQSxjQUFJLGtDQUFnQkEsS0FBaEIsQ0FBSixFQUEyQjtBQUFFO0FBQzNCQSxZQUFBQSxLQUFJLEdBQUdBLEtBQUksQ0FBQ3VFLE1BQUwsQ0FBWSxDQUFaLENBQVA7QUFDQWxCLFlBQUFBLGdCQUFnQixDQUFDbUIsUUFBakIsQ0FBMEJqQyxTQUExQixFQUFxQ3hCLFNBQXJDO0FBQ0Q7O0FBRUQsY0FBTTBELGFBQWEsR0FBRyxtQ0FBaUJ6RSxLQUFqQixDQUF0Qjs7QUFFQSxjQUFJeUUsYUFBYSxJQUFJekUsS0FBckIsRUFBMkI7QUFBRTtBQUMzQkEsWUFBQUEsS0FBSSxHQUFHQSxLQUFJLENBQUN1RSxNQUFMLENBQVksQ0FBWixFQUFldkUsS0FBSSxDQUFDTyxNQUFMLEdBQWMsQ0FBN0IsQ0FBUDtBQUNEOztBQUVELGNBQU1tRSxnQkFBZ0IsR0FBRzdCLE1BQU0sQ0FBQzhCLEdBQVAsSUFBYyxDQUFDOUIsTUFBTSxDQUFDK0IsTUFBL0MsQ0Fkc0IsQ0FjaUM7O0FBRXZELGNBQUlGLGdCQUFnQixJQUFJLHdDQUFvQjFFLEtBQXBCLENBQXhCLEVBQW1EO0FBQUU7QUFDbkRxRCxZQUFBQSxnQkFBZ0IsQ0FBQ21CLFFBQWpCLENBQTBCakMsU0FBMUI7QUFDRDs7QUFDREYsVUFBQUEsV0FBVyxHQUFHLDJDQUF1QlEsTUFBdkIsQ0FBZCxDQW5Cc0IsQ0FtQndCOztBQUU5QyxjQUFJUSxnQkFBZ0IsQ0FBQ3dCLHdCQUFqQixDQUEwQ3ZDLFlBQTFDLEVBQXdEUSxRQUF4RCxFQUFrRWhCLFNBQWxFLEVBQTZFSSxZQUE3RSxFQUEyRlYsS0FBM0YsRUFBa0dTLGVBQWxHLENBQUosRUFBd0g7QUFDdEhNLFlBQUFBLFNBQVMsQ0FBQy9CLElBQVYsQ0FBZSxnREFBc0JnQixLQUF0QixFQUE2QnhCLEtBQTdCLEVBQW1DZSxTQUFuQyxDQUFmO0FBQ0QsV0FGRCxNQUVPO0FBQ0x3QixZQUFBQSxTQUFTLENBQUMvQixJQUFWLENBQWUseUNBQWVnQixLQUFmLEVBQXNCeEIsS0FBdEIsRUFBNEJlLFNBQTVCLENBQWY7QUFDRDs7QUFFRCxjQUFJMEQsYUFBSixFQUFtQjtBQUFFO0FBQ25CcEIsWUFBQUEsZ0JBQWdCLENBQUNtQixRQUFqQixDQUEwQmpDLFNBQTFCO0FBQ0Q7QUFDRjtBQW5HRTs7QUFLTCxXQUFLLElBQUlqQyxDQUFDLEdBQUcsQ0FBUixFQUFXZ0IsR0FBRyxHQUFHWSxZQUFZLENBQUMzQixNQUFuQyxFQUEyQ0QsQ0FBQyxHQUFHZ0IsR0FBL0MsRUFBb0RoQixDQUFDLEVBQXJELEVBQXlEO0FBQUEsY0FBaERBLENBQWdELEVBQXpDZ0IsR0FBeUM7QUErRnhEO0FBcEdJO0FBcUdOOztBQUVELFNBQU9pQixTQUFQO0FBQ0Q7QUFFRDs7Ozs7OztBQUtPLFNBQVN1QyxpQkFBVCxDQUEyQnZDLFNBQTNCLEVBQXNDO0FBQUEseUJBQ3pCQSxTQUFTLENBQUNuQyxLQUFWLENBQWdCLEdBQWhCLENBRHlCO0FBQUE7QUFBQSxNQUN0QzJFLEdBRHNDO0FBQUEsTUFDakNDLElBRGlDOztBQUczQyxNQUFJRCxHQUFHLElBQUlDLElBQVgsRUFBaUI7QUFDZkQsSUFBQUEsR0FBRyxHQUFHRSxRQUFRLENBQUNGLEdBQUQsRUFBTSxFQUFOLENBQWQ7QUFDQUMsSUFBQUEsSUFBSSxHQUFHQyxRQUFRLENBQUNELElBQUQsRUFBTyxFQUFQLENBQWY7O0FBRUEsUUFBS0QsR0FBRyxHQUFHLENBQVAsSUFBY0MsSUFBSSxJQUFJRCxHQUExQixFQUFnQztBQUM5QixhQUFPO0FBQUVBLFFBQUFBLEdBQUcsRUFBSEEsR0FBRjtBQUFPQyxRQUFBQSxJQUFJLEVBQUpBO0FBQVAsT0FBUDtBQUNEO0FBQ0Y7O0FBQ0QsU0FBTyxFQUFQO0FBQ0Q7QUFFRDs7Ozs7OztBQUtPLFNBQVNFLFlBQVQsQ0FBc0JDLFFBQXRCLEVBQWdDO0FBQ3JDLE1BQU1DLE1BQU0sR0FBR0QsUUFBUSxDQUFDdkIsUUFBVCxHQUFvQnhELEtBQXBCLENBQTBCLEdBQTFCLENBQWY7QUFDQSxTQUFPZ0YsTUFBUDtBQUNEO0FBRUQ7Ozs7Ozs7QUFLTyxTQUFTQyxXQUFULENBQXFCQyxLQUFyQixFQUE0QjtBQUNqQyxNQUFNQyxNQUFNLEdBQUksT0FBT0QsS0FBUCxLQUFpQixRQUFsQixJQUErQkEsS0FBSyxDQUFDRSxRQUFOLENBQWUsR0FBZixDQUE5QztBQUNBLFNBQU9ELE1BQVA7QUFDRDtBQUVEOzs7Ozs7O0FBS08sU0FBU0UsV0FBVCxDQUFxQkgsS0FBckIsRUFBNEI7QUFDakMsTUFBTUksTUFBTSxHQUFJLE9BQU9KLEtBQVAsS0FBaUIsUUFBbEIsSUFBK0JBLEtBQUssQ0FBQ0UsUUFBTixDQUFlLEdBQWYsQ0FBOUM7QUFDQSxTQUFPRSxNQUFQO0FBQ0Q7QUFFRDs7Ozs7OztBQUtPLFNBQVNDLFVBQVQsQ0FBb0JMLEtBQXBCLEVBQTJCO0FBQ2hDLE1BQU1NLEtBQUssR0FBR1AsV0FBVyxDQUFDQyxLQUFELENBQVgsSUFBc0JHLFdBQVcsQ0FBQ0gsS0FBRCxDQUEvQztBQUNBLFNBQU9NLEtBQVA7QUFDRDtBQUVEOzs7Ozs7Ozs7O0FBUU8sU0FBU0MsZUFBVCxDQUF5QkMsTUFBekIsRUFBaUNDLFVBQWpDLEVBQTZDbEUsT0FBN0MsRUFBb0U7QUFBQTs7QUFBQSxNQUFkbUUsS0FBYyx1RUFBTixJQUFNO0FBQ3pFLE1BQU1DLEdBQUcsR0FBSUQsS0FBSyxJQUFJRCxVQUFVLEtBQUssZ0JBQXpCLGFBQWdEQSxVQUFoRCxjQUE4REMsS0FBOUQsSUFBd0VELFVBQXBGO0FBQ0EsTUFBTUcsWUFBWSxrQkFBR0osTUFBTSxDQUFDRyxHQUFELENBQVQsZ0RBQUcsWUFBY3BFLE9BQWQsQ0FBckI7QUFDQSxTQUFPcUUsWUFBUDtBQUNEO0FBRUQ7Ozs7Ozs7OztBQU9PLFNBQVNDLHFCQUFULENBQStCQyxLQUEvQixFQUFzQ0MsT0FBdEMsRUFBK0NmLEtBQS9DLEVBQXNEO0FBQzNELE1BQUlnQixTQUFTLEdBQUcsSUFBaEI7QUFDQSxNQUFJQyxVQUFVLEdBQUcsSUFBakI7O0FBRUEsTUFBSTtBQUNGLFFBQU1DLFdBQVcsR0FBR0osS0FBSyxDQUFDQyxPQUFELENBQXpCOztBQUVBLFFBQUlHLFdBQUosRUFBaUI7QUFDZkYsTUFBQUEsU0FBUyxHQUFHRSxXQUFXLENBQUNsQixLQUFELENBQXZCOztBQUVBLFVBQUlnQixTQUFKLEVBQWU7QUFDYkMsUUFBQUEsVUFBVSxHQUFHakIsS0FBYjtBQUNELE9BRkQsTUFFTztBQUFFO0FBQ1AsWUFBTW1CLFFBQVEsR0FBR3hCLFFBQVEsQ0FBQ0ssS0FBRCxDQUF6Qjs7QUFFQSxhQUFLLElBQUlvQixVQUFULElBQXVCRixXQUF2QixFQUFvQztBQUNsQyxjQUFJbkIsV0FBVyxDQUFDcUIsVUFBRCxDQUFmLEVBQTZCO0FBQUEscUNBQ0w1QixpQkFBaUIsQ0FBQzRCLFVBQUQsQ0FEWjtBQUFBLGdCQUNuQjNCLEdBRG1CLHNCQUNuQkEsR0FEbUI7QUFBQSxnQkFDZEMsSUFEYyxzQkFDZEEsSUFEYzs7QUFHM0IsZ0JBQU15QixRQUFRLElBQUkxQixHQUFiLElBQXNCMEIsUUFBUSxJQUFJekIsSUFBdkMsRUFBK0M7QUFDN0NzQixjQUFBQSxTQUFTLEdBQUdFLFdBQVcsQ0FBQ0UsVUFBRCxDQUF2QjtBQUNBSCxjQUFBQSxVQUFVLEdBQUdHLFVBQWI7QUFDQTtBQUNEO0FBQ0Y7QUFDRjtBQUNGO0FBQ0YsS0F2QkMsQ0F3QkY7O0FBQ0QsR0F6QkQsQ0F5QkUsT0FBTzdDLENBQVAsRUFBVSxDQUFFOztBQUNkLFNBQU87QUFBRXlDLElBQUFBLFNBQVMsRUFBVEEsU0FBRjtBQUFhQyxJQUFBQSxVQUFVLEVBQVZBO0FBQWIsR0FBUDtBQUNEO0FBRUQ7Ozs7Ozs7O0FBTU8sU0FBU0ksYUFBVCxDQUF1QkosVUFBdkIsRUFBbUNqQixLQUFuQyxFQUEwQztBQUMvQyxNQUFJRCxXQUFXLEdBQUcsS0FBbEI7QUFBQSxNQUF5QnVCLFlBQVksR0FBRyxLQUF4Qzs7QUFFQSxNQUFJTCxVQUFKLEVBQWdCO0FBQ2QsUUFBSTtBQUFBLDhCQUNhQSxVQUFVLENBQUNuRyxLQUFYLENBQWlCLEdBQWpCLENBRGI7QUFBQTtBQUFBLFVBQ095RyxFQURQOztBQUVGeEIsTUFBQUEsV0FBVyxHQUFHLENBQUMsQ0FBQ3dCLEVBQWhCOztBQUVBLFVBQUl4QixXQUFKLEVBQWlCO0FBQ2YsWUFBSSxPQUFPQyxLQUFQLEtBQWlCLFFBQXJCLEVBQStCO0FBQzdCQSxVQUFBQSxLQUFLLEdBQUdMLFFBQVEsQ0FBQ0ssS0FBRCxDQUFoQjtBQUNEOztBQUVELFlBQU13QixVQUFVLEdBQUc3QixRQUFRLENBQUNzQixVQUFELENBQTNCO0FBQ0FLLFFBQUFBLFlBQVksR0FBSXRCLEtBQUssS0FBS3dCLFVBQTFCO0FBQ0QsT0FYQyxDQVlGOztBQUNELEtBYkQsQ0FhRSxPQUFPakQsQ0FBUCxFQUFVLENBQ1g7QUFDRjs7QUFDRCxTQUFPO0FBQUV3QixJQUFBQSxXQUFXLEVBQVhBLFdBQUY7QUFBZXVCLElBQUFBLFlBQVksRUFBWkE7QUFBZixHQUFQO0FBQ0Q7QUFFRDs7Ozs7Ozs7OztBQVFBLFNBQVNHLGtCQUFULENBQTRCN0UsWUFBNUIsRUFBMEM4RSxRQUExQyxFQUFvREMsVUFBcEQsRUFBZ0VDLGtCQUFoRSxFQUFvRkMsdUJBQXBGLEVBQTZHO0FBQzNHLE1BQUlqRixZQUFKLEVBQWtCO0FBQUEsK0NBQ0NBLFlBREQ7QUFBQTs7QUFBQTtBQUNoQiwwREFBK0I7QUFBQSxZQUFwQmtGLEVBQW9COztBQUM3QixZQUFJSCxVQUFVLElBQUssQ0FBQUcsRUFBRSxTQUFGLElBQUFBLEVBQUUsV0FBRixZQUFBQSxFQUFFLENBQUV6QyxHQUFKLE1BQVksTUFBL0IsRUFBd0M7QUFDdEN5QyxVQUFBQSxFQUFFLENBQUNKLFFBQUgsR0FBY0EsUUFBZDtBQUNBLGNBQU1LLFFBQVEsR0FBR0QsRUFBSCxhQUFHQSxFQUFILHVCQUFHQSxFQUFFLENBQUU3RCxPQUFyQjs7QUFFQSxjQUFJOEQsUUFBSixFQUFjO0FBQ1osZ0JBQU1DLGFBQWEsR0FBR0gsdUJBQXVCLENBQUNFLFFBQUQsQ0FBdkIsSUFBcUMsQ0FBM0Q7QUFDQSxnQkFBTUUsWUFBWSxHQUFHTCxrQkFBa0IsQ0FBQ0csUUFBRCxDQUFsQixJQUFnQyxDQUFyRDs7QUFFQSxnQkFBSSxDQUFDRSxZQUFMLEVBQW1CO0FBQ2pCTCxjQUFBQSxrQkFBa0IsQ0FBQ0csUUFBRCxDQUFsQixHQUErQkQsRUFBRSxDQUFDSSxXQUFILEdBQWlCRixhQUFoRDtBQUNEOztBQUVELGdCQUFJRixFQUFFLENBQUNLLFFBQVAsRUFBaUI7QUFDZlYsY0FBQUEsa0JBQWtCLENBQUNLLEVBQUUsQ0FBQ0ssUUFBSixFQUFjVCxRQUFkLEVBQXdCQyxVQUF4QixFQUFvQ0Msa0JBQXBDLEVBQXdEQyx1QkFBeEQsQ0FBbEI7QUFDRDtBQUNGO0FBQ0Y7QUFDRjtBQW5CZTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBb0JqQjtBQUNGO0FBRUQ7Ozs7Ozs7Ozs7QUFRTyxTQUFTTyxZQUFULENBQXNCQyxRQUF0QixFQUFnQ3RCLE9BQWhDLEVBQXlDdUIsU0FBekMsRUFBb0RDLGlCQUFwRCxFQUF1RTtBQUM1RSxNQUFJdEIsVUFBVSxHQUFHLEVBQWpCO0FBQ0EsTUFBSXVCLGNBQUo7QUFDQSxNQUFNQyxJQUFJLEdBQUcsb0NBQVVKLFFBQVYsWUFBdUJ0QixPQUF2QixjQUFrQ3VCLFNBQWxDLEVBQWI7QUFDQSxNQUFJSSxhQUFhLEdBQUcsRUFBcEI7QUFDQSxNQUFNQyxPQUFPLEdBQUcsRUFBaEIsQ0FMNEUsQ0FLeEQ7O0FBQ3BCLE1BQUloRyxlQUFlLEdBQUcsRUFBdEI7QUFDQSxNQUFNZ0YsVUFBVSxHQUFHYyxJQUFJLENBQUN4SCxNQUFMLEdBQWMsQ0FBakM7O0FBRUEsTUFBSXdILElBQUksSUFBSUEsSUFBSSxDQUFDeEgsTUFBakIsRUFBeUI7QUFDdkJ1SCxJQUFBQSxjQUFjLEdBQUdDLElBQUksQ0FBQyxDQUFELENBQUosQ0FBUTFCLE9BQXpCO0FBQ0Q7O0FBRUQsT0FBSyxJQUFJVyxRQUFRLEdBQUcsQ0FBcEIsRUFBdUJBLFFBQVEsR0FBR2UsSUFBSSxDQUFDeEgsTUFBdkMsRUFBK0N5RyxRQUFRLEVBQXZELEVBQTJEO0FBQ3pELFFBQU1HLHVCQUF1QixHQUFHSCxRQUFRLEdBQUcsQ0FBWCxHQUFlL0UsZUFBZSxDQUFDK0UsUUFBUSxHQUFDLENBQVYsQ0FBOUIsR0FBNkMsRUFBN0U7QUFDQSxRQUFNRSxrQkFBa0IsR0FBRyxFQUEzQjtBQUNBakYsSUFBQUEsZUFBZSxDQUFDekIsSUFBaEIsQ0FBcUIwRyxrQkFBckI7QUFDQSxRQUFNZ0IsR0FBRyxHQUFHSCxJQUFJLENBQUNmLFFBQUQsQ0FBaEI7QUFDQSxRQUFNWCxRQUFPLEdBQUc2QixHQUFHLENBQUM3QixPQUFwQjtBQUNBLFFBQU04QixJQUFJLEdBQUdELEdBQUcsQ0FBQzVCLFNBQWpCO0FBQ0EsUUFBSThCLEtBQUssR0FBR0YsR0FBRyxDQUFDNUMsS0FBaEI7O0FBRUEsUUFBSWUsUUFBTyxLQUFLeUIsY0FBaEIsRUFBZ0M7QUFDOUJNLE1BQUFBLEtBQUssYUFBTS9CLFFBQU4sY0FBaUIrQixLQUFqQixDQUFMO0FBQ0Q7O0FBRUQsUUFBSUQsSUFBSSxJQUFJLENBQUNGLE9BQU8sQ0FBQ3pDLFFBQVIsQ0FBaUI0QyxLQUFqQixDQUFiLEVBQXNDO0FBQUU7QUFDdENILE1BQUFBLE9BQU8sQ0FBQ3pILElBQVIsQ0FBYTRILEtBQUssR0FBRyxFQUFyQjs7QUFFQSxVQUFJSixhQUFhLENBQUN6SCxNQUFsQixFQUEwQjtBQUN4QnlILFFBQUFBLGFBQWEsQ0FBQ3hILElBQWQsQ0FBbUJxSCxpQkFBaUIsQ0FBQ08sS0FBRCxDQUFwQztBQUNEOztBQUVELFVBQUksT0FBT0QsSUFBUCxLQUFnQixRQUFwQixFQUE4QjtBQUFFO0FBQzlCSCxRQUFBQSxhQUFhLENBQUN4SCxJQUFkLENBQW1CO0FBQ2pCdUMsVUFBQUEsSUFBSSxFQUFFLE1BRFc7QUFFakIvQyxVQUFBQSxJQUFJLEVBQUVtSTtBQUZXLFNBQW5CO0FBSUQsT0FMRCxNQUtPO0FBQUU7QUFDUCxZQUFNakcsWUFBWSxHQUFHaUcsSUFBSCxhQUFHQSxJQUFILHVCQUFHQSxJQUFJLENBQUVqRyxZQUEzQjs7QUFFQSxZQUFJQSxZQUFKLEVBQWtCO0FBQ2hCNkUsVUFBQUEsa0JBQWtCLENBQUM3RSxZQUFELEVBQWU4RSxRQUFmLEVBQXlCQyxVQUF6QixFQUFxQ0Msa0JBQXJDLEVBQXlEQyx1QkFBekQsRUFBa0ZsRixlQUFsRixDQUFsQjtBQUNBUyxVQUFBQSxLQUFLLENBQUMyRixTQUFOLENBQWdCN0gsSUFBaEIsQ0FBcUI4SCxLQUFyQixDQUEyQk4sYUFBM0IsRUFBMENHLElBQUksQ0FBQ2pHLFlBQS9DO0FBQ0EsY0FBTXFHLEtBQUssR0FBR0MsTUFBTSxDQUFDQyxJQUFQLENBQVl0Qix1QkFBWixDQUFkOztBQUVBLG9DQUFtQm9CLEtBQW5CLDRCQUEwQjtBQUFyQixnQkFBTXRGLElBQUksYUFBVjs7QUFBdUI7QUFDMUIsZ0JBQUksQ0FBQ2lFLGtCQUFrQixDQUFDakUsSUFBRCxDQUF2QixFQUErQjtBQUM3QmlFLGNBQUFBLGtCQUFrQixDQUFDakUsSUFBRCxDQUFsQixHQUEyQmtFLHVCQUF1QixDQUFDbEUsSUFBRCxDQUFsRDtBQUNEO0FBQ0Y7QUFDRjtBQUNGOztBQUVELFVBQUksQ0FBQ3NELFVBQUwsRUFBaUI7QUFDZkEsUUFBQUEsVUFBVSxHQUFHNkIsS0FBSyxDQUFDeEUsUUFBTixFQUFiO0FBQ0Q7QUFDRjtBQUNGOztBQUVELE1BQUksQ0FBQ3FELFVBQUwsRUFBaUI7QUFDZmhGLElBQUFBLGVBQWUsR0FBRyxJQUFsQjtBQUNEOztBQUVELE1BQU1xRSxTQUFTLEdBQUc7QUFBRXBFLElBQUFBLFlBQVksRUFBRThGO0FBQWhCLEdBQWxCO0FBQ0EsU0FBTztBQUNMMUIsSUFBQUEsU0FBUyxFQUFUQSxTQURLO0FBRUxDLElBQUFBLFVBQVUsRUFBVkEsVUFGSztBQUdMVSxJQUFBQSxVQUFVLEVBQVZBLFVBSEs7QUFJTGhGLElBQUFBLGVBQWUsRUFBZkE7QUFKSyxHQUFQO0FBTUQ7QUFHRDs7Ozs7OztBQUtPLFNBQVN5RyxjQUFULENBQXdCcEQsS0FBeEIsRUFBK0I7QUFDcEMsc0JBQU8sK0VBQUUsMkNBQUYsZUFBTywyQ0FBSUEsS0FBSixDQUFQLE1BQVA7QUFDRDtBQUVEOzs7Ozs7O0FBS0EsU0FBU3FELGdCQUFULENBQTBCdEksSUFBMUIsRUFBZ0M7QUFDOUIsU0FBTztBQUNMMEMsSUFBQUEsSUFBSSxFQUFFLE1BREQ7QUFFTDFDLElBQUFBLElBQUksRUFBRUEsSUFGRDtBQUdMTCxJQUFBQSxJQUFJLEVBQUU7QUFIRCxHQUFQO0FBS0Q7QUFFRDs7Ozs7OztBQUtPLFNBQVM2SCxpQkFBVCxDQUEyQnZDLEtBQTNCLEVBQWtDO0FBQ3ZDLFNBQU9xRCxnQkFBZ0IsQ0FBQ0QsY0FBYyxDQUFDcEQsS0FBRCxDQUFmLENBQXZCO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IGlzRXF1YWwgZnJvbSAnZGVlcC1lcXVhbCc7XG5pbXBvcnQgKiBhcyBzdHJpbmdUb2tlbml6ZXIgZnJvbSAnc3RyaW5nLXB1bmN0dWF0aW9uLXRva2VuaXplcic7XG5pbXBvcnQgeyBWZXJzZU9iamVjdFV0aWxzIH0gZnJvbSAnd29yZC1hbGlnbmVyJztcbmltcG9ydCB7IGdldFZlcnNlcyB9IGZyb20gJ2JpYmxlLXJlZmVyZW5jZS1yYW5nZSc7XG4vLyBoZWxwZXJzXG5pbXBvcnQgKiBhcyBoaWdobGlnaHRIZWxwZXJzIGZyb20gJy4vaGlnaGxpZ2h0SGVscGVycyc7XG5pbXBvcnQge1xuICBjcmVhdGVIaWdobGlnaHRlZFNwYW4sXG4gIGNyZWF0ZU5vbkNsaWNrYWJsZVNwYW4sXG4gIGNyZWF0ZVRleHRTcGFuLFxuICBvbldvcmRDbGljayxcbn0gZnJvbSAnLi9odG1sRWxlbWVudHNIZWxwZXJzJztcbmltcG9ydCB7XG4gIGhhc0xlYWRpbmdTcGFjZSxcbiAgaGFzVHJhaWxpbmdTcGFjZSxcbiAgcmVtb3ZlTWFya2VyLFxufSBmcm9tICcuL3VzZm1IZWxwZXJzJztcbmltcG9ydCB7XG4gIGlzSXNvbGF0ZWRMZWZ0UXVvdGUsXG4gIGlzTmVzdGVkTWlsZXN0b25lLFxuICBpc1dvcmQsXG4gIHB1bmN0dWF0aW9uV29yZFNwYWNpbmcsXG4gIHRleHRJc0VtcHR5SW5WZXJzZU9iamVjdCxcbn0gZnJvbSAnLi9zdHJpbmdIZWxwZXJzJztcblxuLyoqXG4gKiBpZiBzaG93aW5nIFVTRk0gY29kZXMsIHJlcGxhY2UgbmV3bGluZXNcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0XG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3dVc2ZtXG4gKiBAcmV0dXJuIHtKU1guRWxlbWVudH1cbiAqL1xuZnVuY3Rpb24gdGV4dFRvSHRtbCh0ZXh0LCBzaG93VXNmbSkge1xuICBpZiAoc2hvd1VzZm0gJiYgKHRleHQuaW5kZXhPZignXFxuJykgPj0gMCkpIHtcbiAgICBjb25zdCBwYXJ0cyA9IHRleHQuc3BsaXQoJ1xcbicpO1xuICAgIGNvbnN0IGh0bWwgPSBbcGFydHNbMF1dO1xuXG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKykge1xuICAgICAgaHRtbC5wdXNoKCfihrInKTtcbiAgICAgIGh0bWwucHVzaCg8YnIvPik7XG4gICAgICBodG1sLnB1c2gocGFydHNbaV0pO1xuICAgIH1cbiAgICByZXR1cm4gaHRtbDtcbiAgfVxuICByZXR1cm4gdGV4dDtcbn1cblxuLyoqXG4gKiByZW5kZXIgdGV4dCBhcyBIVE1MIGFuZCBvdmVybGF5IGFueSBzZWxlY3Rpb25zXG4gKiBAcGFyYW0ge1N0cmluZ30gdmVyc2VUZXh0XG4gKiBAcGFyYW0ge0FycmF5fSBzZWxlY3Rpb25zIC0gdGV4dCBzZWxlY3Rpb25zIHRvIGhpZ2hsaWdodFxuICogQHBhcmFtIHtGdW5jdGlvbn0gdHJhbnNsYXRlXG4gKiBAcGFyYW0ge09iamVjdH0gZm9udFN0eWxlIC0gZm9udCBzcGVjaWZpYyBzdHlsaW5nXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzVGFyZ2V0QmlibGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBmb250Q2xhc3NcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvd1VzZm1cbiAqIEByZXR1cm4geyp9XG4gKi9cbmV4cG9ydCBjb25zdCB2ZXJzZVN0cmluZyA9ICh2ZXJzZVRleHQsIHNlbGVjdGlvbnMsIHRyYW5zbGF0ZSwgZm9udFN0eWxlID0gbnVsbCwgaXNUYXJnZXRCaWJsZSwgZm9udENsYXNzLCBzaG93VXNmbSkgPT4ge1xuICBsZXQgbmV3VmVyc2VUZXh0ID0gdmVyc2VUZXh0O1xuXG4gIGlmICghc2hvd1VzZm0pIHtcbiAgICBuZXdWZXJzZVRleHQgPSByZW1vdmVNYXJrZXIodmVyc2VUZXh0KTtcbiAgICBuZXdWZXJzZVRleHQgPSBuZXdWZXJzZVRleHQucmVwbGFjZSgvXFxzKy9nLCAnICcpO1xuICAgIC8vIGlmIHN0cmluZyBvbmx5IGNvbnRhaW5zIHNwYWNlcyB0aGVuIG1ha2UgaXQgYW4gZW1wdHkgc3RyaW5nXG4gICAgbmV3VmVyc2VUZXh0ID0gbmV3VmVyc2VUZXh0LnJlcGxhY2UoL1xccy9nLCAnJykubGVuZ3RoID09PSAwID8gJycgOiBuZXdWZXJzZVRleHQ7XG4gIH1cblxuICAvLyBpZiBlbXB0eSBzdHJpbmcgdGhlbiBuZXdWZXJzZVRleHQgPSBwbGFjZSBob2xkZXIgd2FybmluZy5cbiAgaWYgKG5ld1ZlcnNlVGV4dC5sZW5ndGggPT09IDApIHtcbiAgICBuZXdWZXJzZVRleHQgPSB0cmFuc2xhdGUoJ3BhbmUubWlzc2luZ192ZXJzZV93YXJuaW5nJyk7XG4gIH1cblxuICBsZXQgdmVyc2VUZXh0U3BhbnMgPSA8c3BhbiBjbGFzc05hbWU9e2ZvbnRDbGFzc30+e3RleHRUb0h0bWwobmV3VmVyc2VUZXh0LCBzaG93VXNmbSl9PC9zcGFuPjtcblxuICBpZiAoIXNob3dVc2ZtICYmIHNlbGVjdGlvbnMgJiYgc2VsZWN0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgX3NlbGVjdGlvbkFycmF5ID0gc3RyaW5nVG9rZW5pemVyLnNlbGVjdGlvbkFycmF5KG5ld1ZlcnNlVGV4dCwgc2VsZWN0aW9ucyk7XG4gICAgdmVyc2VUZXh0U3BhbnMgPSBbXTtcbiAgICB2ZXJzZVRleHRTcGFucy5sZW5ndGggPSAwO1xuXG4gICAgZm9yIChsZXQgaSA9IDAsIGxlbiA9IF9zZWxlY3Rpb25BcnJheS5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgY29uc3Qgc2VsZWN0aW9uID0gX3NlbGVjdGlvbkFycmF5W2ldO1xuICAgICAgY29uc3QgaW5kZXggPSBpO1xuICAgICAgbGV0IHNwYW5TdHlsZSA9IHsgYmFja2dyb3VuZENvbG9yOiBzZWxlY3Rpb24uc2VsZWN0ZWQgPyAndmFyKC0taGlnaGxpZ2h0LWNvbG9yKScgOiAnJyB9O1xuXG4gICAgICBpZiAoZm9udFN0eWxlKSB7XG4gICAgICAgIHNwYW5TdHlsZSA9IHtcbiAgICAgICAgICAuLi5zcGFuU3R5bGUsXG4gICAgICAgICAgLi4uZm9udFN0eWxlLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgdmVyc2VUZXh0U3BhbnMucHVzaChcbiAgICAgICAgPHNwYW4ga2V5PXtpbmRleH0gY2xhc3NOYW1lPXtmb250Q2xhc3N9IHN0eWxlPXtzcGFuU3R5bGV9PlxuICAgICAgICAgIHtzZWxlY3Rpb24udGV4dH1cbiAgICAgICAgPC9zcGFuPixcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHZlcnNlVGV4dFNwYW5zO1xufTtcblxuLyoqXG4gKiBjcmVhdGUgdmVyc2UgZWxlbWVudHMgZnJvbSBhbiBhcnJheSBvZiB2ZXJzZSBvYmplY3RzXG4gKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gdmVyc2VUZXh0IC0gdmVyc2UgZGF0YVxuICogQHBhcmFtIHtTdHJpbmd9IGJpYmxlSWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0SWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGdldExleGljb25EYXRhXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNob3dQb3BvdmVyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0cmFuc2xhdGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBmb250U3R5bGUgLSBmb250IHNwZWNpZmljIHN0eWxpbmdcbiAqIEBwYXJhbSB7U3RyaW5nfSBmb250Q2xhc3MgLSBmb250IGNsYXNzIG5hbWVcbiAqIEBwYXJhbSB7YXJyYXl9IHZlcnNlV29yZENvdW50cyAtIGFycmF5IG9mIHdvcmQgY291bnRzIGZvciBtdWx0aS12ZXJzZVxuICogQHJldHVybiB7QXJyYXl9IC0gdmVyc2UgZWxlbWVudHMgdG8gZGlzcGxheVxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyc2VBcnJheSh2ZXJzZVRleHQgPSBbXSwgYmlibGVJZCwgY29udGV4dElkLCBnZXRMZXhpY29uRGF0YSwgc2hvd1BvcG92ZXIsIHRyYW5zbGF0ZSwgZm9udFN0eWxlID0gbnVsbCwgZm9udENsYXNzLCB2ZXJzZVdvcmRDb3VudHMgPSBudWxsKSB7XG4gIGxldCB2ZXJzZU9iamVjdHMgPSBWZXJzZU9iamVjdFV0aWxzLmdldFdvcmRMaXN0Rm9yVmVyc2UodmVyc2VUZXh0KTtcbiAgbGV0IHdvcmRTcGFjaW5nID0gJyc7XG4gIGxldCBwcmV2aW91c1dvcmQgPSBudWxsO1xuICBjb25zdCB2ZXJzZVNwYW4gPSBbXTtcbiAgdmVyc2VTcGFuLmxlbmd0aCA9IDA7XG5cbiAgaWYgKHZlcnNlVGV4dC52ZXJzZU9iamVjdHMgJiYgdGV4dElzRW1wdHlJblZlcnNlT2JqZWN0KHZlcnNlVGV4dCwgYmlibGVJZCkpIHsgLy8gaWYgZW1wdHkgdmVyc2Ugc3RyaW5nLlxuICAgIHZlcnNlU3Bhbi5wdXNoKFxuICAgICAgPHNwYW4ga2V5PXt0cmFuc2xhdGUoJ3BhbmUubWlzc2luZ192ZXJzZV93YXJuaW5nJyl9PlxuICAgICAgICB7dHJhbnNsYXRlKCdwYW5lLm1pc3NpbmdfdmVyc2Vfd2FybmluZycpfVxuICAgICAgPC9zcGFuPixcbiAgICApO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IGlzSGVicmV3ID0gKGJpYmxlSWQgPT09ICd1aGInKTtcbiAgICBjb25zdCBvcmlnTGFuZ0JpYmxlID0gaXNIZWJyZXcgfHwgYmlibGVJZCA9PT0gJ3VnbnQnO1xuICAgIHZlcnNlT2JqZWN0cyA9IEFycmF5LmlzQXJyYXkodmVyc2VPYmplY3RzKSA/IHZlcnNlT2JqZWN0cyA6IHZlcnNlT2JqZWN0cy52ZXJzZU9iamVjdDtcblxuICAgIGZvciAobGV0IGkgPSAwLCBsZW4gPSB2ZXJzZU9iamVjdHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIGNvbnN0IG9iamVjdCA9IHZlcnNlT2JqZWN0c1tpXTtcbiAgICAgIGNvbnN0IGluZGV4ID0gaTtcbiAgICAgIGNvbnN0IG5leHRXb3JkID0gdmVyc2VPYmplY3RzW2luZGV4ICsgMV07XG5cbiAgICAgIGlmIChvYmplY3QudHlwZSA9PT0gJ2h0bWwnKSB7XG4gICAgICAgIHZlcnNlU3Bhbi5wdXNoKG9iamVjdC5odG1sKTtcbiAgICAgIH0gZWxzZSBpZiAoaXNXb3JkKG9iamVjdCkpIHtcbiAgICAgICAgY29uc3QgcGFkZGluZyA9IHdvcmRTcGFjaW5nO1xuICAgICAgICB3b3JkU3BhY2luZyA9ICcgJzsgLy8gc3BhY2luZyBiZXR3ZWVuIHdvcmRzXG4gICAgICAgIGNvbnN0IHRleHQgPSAob2JqZWN0LndvcmQgfHwgb2JqZWN0LnRleHQpO1xuICAgICAgICBsZXQgaXNIaWdobGlnaHRlZFdvcmQgPSBmYWxzZTtcbiAgICAgICAgbGV0IGlzQmV0d2VlbkhpZ2hsaWdodGVkV29yZCA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChvcmlnTGFuZ0JpYmxlICYmIGNvbnRleHRJZC5xdW90ZSAmJiBvYmplY3QudGV4dCkge1xuICAgICAgICAgIGlzSGlnaGxpZ2h0ZWRXb3JkID0gaGlnaGxpZ2h0SGVscGVycy5pc1dvcmRNYXRjaChvYmplY3QsIGNvbnRleHRJZCwgdmVyc2VPYmplY3RzLCBpbmRleCk7XG4gICAgICAgICAgaXNCZXR3ZWVuSGlnaGxpZ2h0ZWRXb3JkID0gcHJldmlvdXNXb3JkICYmICFpc0VxdWFsKHByZXZpb3VzV29yZCwgb2JqZWN0KSAmJlxuICAgICAgICAgICAgaGlnaGxpZ2h0SGVscGVycy5pc1dvcmRNYXRjaChwcmV2aW91c1dvcmQsIGNvbnRleHRJZCwgdmVyc2VPYmplY3RzLCBpbmRleCAtIDEpICYmIGlzSGlnaGxpZ2h0ZWRXb3JkO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbnRleHRJZC5xdW90ZSAmJiBvYmplY3QuY29udGVudCkge1xuICAgICAgICAgIGNvbnN0IGhpZ2hsaWdodGVkRGV0YWlscyA9IGhpZ2hsaWdodEhlbHBlcnMuZ2V0V29yZEhpZ2hsaWdodGVkRGV0YWlscyhjb250ZXh0SWQsIHByZXZpb3VzV29yZCwgb2JqZWN0LCB2ZXJzZVdvcmRDb3VudHMpO1xuICAgICAgICAgIGlzSGlnaGxpZ2h0ZWRXb3JkID0gaGlnaGxpZ2h0ZWREZXRhaWxzLmlzSGlnaGxpZ2h0ZWRXb3JkO1xuICAgICAgICAgIGlzQmV0d2VlbkhpZ2hsaWd