UNPKG

tc-ui-toolkit

Version:

React components used to develop tools for the desktop app translationCore

647 lines (523 loc) 65.3 kB
'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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9TY3JpcHR1cmVQYW5lL2hlbHBlcnMvdmVyc2VIZWxwZXJzLmpzIl0sIm5hbWVzIjpbInRleHRUb0h0bWwiLCJ0ZXh0Iiwic2hvd1VzZm0iLCJpbmRleE9mIiwicGFydHMiLCJzcGxpdCIsImh0bWwiLCJpIiwibGVuZ3RoIiwicHVzaCIsInZlcnNlU3RyaW5nIiwidmVyc2VUZXh0Iiwic2VsZWN0aW9ucyIsInRyYW5zbGF0ZSIsImZvbnRTdHlsZSIsImlzVGFyZ2V0QmlibGUiLCJmb250Q2xhc3MiLCJuZXdWZXJzZVRleHQiLCJyZXBsYWNlIiwidmVyc2VUZXh0U3BhbnMiLCJfc2VsZWN0aW9uQXJyYXkiLCJzdHJpbmdUb2tlbml6ZXIiLCJzZWxlY3Rpb25BcnJheSIsImxlbiIsInNlbGVjdGlvbiIsImluZGV4Iiwic3BhblN0eWxlIiwiYmFja2dyb3VuZENvbG9yIiwic2VsZWN0ZWQiLCJ2ZXJzZUFycmF5IiwiYmlibGVJZCIsImNvbnRleHRJZCIsImdldExleGljb25EYXRhIiwic2hvd1BvcG92ZXIiLCJ2ZXJzZVdvcmRDb3VudHMiLCJ2ZXJzZU9iamVjdHMiLCJWZXJzZU9iamVjdFV0aWxzIiwiZ2V0V29yZExpc3RGb3JWZXJzZSIsIndvcmRTcGFjaW5nIiwicHJldmlvdXNXb3JkIiwidmVyc2VTcGFuIiwiaXNIZWJyZXciLCJvcmlnTGFuZ0JpYmxlIiwiQXJyYXkiLCJpc0FycmF5IiwidmVyc2VPYmplY3QiLCJvYmplY3QiLCJuZXh0V29yZCIsInR5cGUiLCJwYWRkaW5nIiwid29yZCIsImlzSGlnaGxpZ2h0ZWRXb3JkIiwiaXNCZXR3ZWVuSGlnaGxpZ2h0ZWRXb3JkIiwicXVvdGUiLCJoaWdobGlnaHRIZWxwZXJzIiwiaXNXb3JkTWF0Y2giLCJjb250ZW50IiwiaGlnaGxpZ2h0ZWREZXRhaWxzIiwiZ2V0V29yZEhpZ2hsaWdodGVkRGV0YWlscyIsInBhZGRpbmdTcGFuU3R5bGUiLCJzdHJvbmciLCJ0b1N0cmluZyIsImUiLCJjdXJzb3IiLCJuZXN0ZWRNaWxlc3RvbmUiLCJnZXRXb3Jkc0Zyb21OZXN0ZWRNaWxlc3RvbmUiLCJqIiwibkxlbiIsIndvcmRTcGFucyIsIm5lc3RlZFdvcmRTcGFuIiwibmVzdGVkUHJldmlvdXNXb3JkIiwibmVzdGVkV29yZFNwYWNpbmciLCJzdWJzdHIiLCJhZGRTcGFjZSIsInRyYWlsaW5nU3BhY2UiLCJpc1VzZm1UYWdOb3RTcGFuIiwidGFnIiwiZW5kVGFnIiwiaXNQdW5jdHVhdGlvbkhpZ2hsaWdodGVkIiwiZ2V0VmVyc2VTcGFuUmFuZ2UiLCJsb3ciLCJoaWdoIiwicGFyc2VJbnQiLCJnZXRWZXJzZUxpc3QiLCJ2ZXJzZVN0ciIsInZlcnNlcyIsImlzVmVyc2VTcGFuIiwidmVyc2UiLCJpc1NwYW4iLCJpbmNsdWRlcyIsImlzVmVyc2VMaXN0IiwiaXNMaXN0IiwiaXNWZXJzZVNldCIsImlzU2V0IiwiZ2V0QmlibGVFbGVtZW50IiwiYmlibGVzIiwibGFuZ3VhZ2VJZCIsIm93bmVyIiwia2V5IiwiYmlibGVFbGVtZW50IiwiZ2V0VmVyc2VEYXRhRnJvbUJpYmxlIiwiYmlibGUiLCJjaGFwdGVyIiwidmVyc2VEYXRhIiwidmVyc2VMYWJlbCIsImNoYXB0ZXJEYXRhIiwidmVyc2VWYWwiLCJ2ZXJzZUluZGV4IiwiaXNWZXJzZUluU3BhbiIsImlzRmlyc3RWZXJzZSIsImhpIiwic3RhcnRWZXJzZSIsImNvdW50T3JpZ2luYWxXb3JkcyIsInZlcnNlQ250IiwibXVsdGlWZXJzZSIsImN1cnJlbnRWZXJzZUNvdW50cyIsInByZXZpb3VzVmVyc2VXb3JkQ291bnRzIiwidm8iLCJvcmlnV29yZCIsInByZXZpb3VzQ291bnQiLCJjdXJyZW50Q291bnQiLCJvY2N1cnJlbmNlcyIsImNoaWxkcmVuIiwiZ2V0VmVyc2VEYXRhIiwiYm9va0RhdGEiLCJ2ZXJzZUxpc3QiLCJjcmVhdGVWZXJzZU1hcmtlciIsImluaXRpYWxDaGFwdGVyIiwicmVmcyIsInZlcnNlU3BhbkRhdGEiLCJoaXN0b3J5IiwicmVmIiwiZGF0YSIsImxhYmVsIiwicHJvdG90eXBlIiwiYXBwbHkiLCJ3b3JkcyIsIk9iamVjdCIsImtleXMiLCJnZXRWZXJzZU1hcmtlciIsImNyZWF0ZUh0bWxJbnNlcnQiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFNQTs7QUFLQTs7Ozs7Ozs7Ozs7O0FBUUE7Ozs7OztBQU1BLFNBQVNBLFVBQVQsQ0FBb0JDLElBQXBCLEVBQTBCQyxRQUExQixFQUFvQztBQUNsQyxNQUFJQSxRQUFRLElBQUtELElBQUksQ0FBQ0UsT0FBTCxDQUFhLElBQWIsS0FBc0IsQ0FBdkMsRUFBMkM7QUFDekMsUUFBTUMsS0FBSyxHQUFHSCxJQUFJLENBQUNJLEtBQUwsQ0FBVyxJQUFYLENBQWQ7QUFDQSxRQUFNQyxJQUFJLEdBQUcsQ0FBQ0YsS0FBSyxDQUFDLENBQUQsQ0FBTixDQUFiOztBQUVBLFNBQUssSUFBSUcsQ0FBQyxHQUFHLENBQWIsRUFBZ0JBLENBQUMsR0FBR0gsS0FBSyxDQUFDSSxNQUExQixFQUFrQ0QsQ0FBQyxFQUFuQyxFQUF1QztBQUNyQ0QsTUFBQUEsSUFBSSxDQUFDRyxJQUFMLENBQVUsR0FBVjtBQUNBSCxNQUFBQSxJQUFJLENBQUNHLElBQUwsZUFBVSwyQ0FBVjtBQUNBSCxNQUFBQSxJQUFJLENBQUNHLElBQUwsQ0FBVUwsS0FBSyxDQUFDRyxDQUFELENBQWY7QUFDRDs7QUFDRCxXQUFPRCxJQUFQO0FBQ0Q7O0FBQ0QsU0FBT0wsSUFBUDtBQUNEO0FBRUQ7Ozs7Ozs7Ozs7Ozs7QUFXTyxJQUFNUyxXQUFXLEdBQUcsU0FBZEEsV0FBYyxDQUFDQyxTQUFELEVBQVlDLFVBQVosRUFBd0JDLFNBQXhCLEVBQTRGO0FBQUEsTUFBekRDLFNBQXlELHVFQUE3QyxJQUE2QztBQUFBLE1BQXZDQyxhQUF1QztBQUFBLE1BQXhCQyxTQUF3QjtBQUFBLE1BQWJkLFFBQWE7QUFDckgsTUFBSWUsWUFBWSxHQUFH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O0FBRUxDLElBQUFBLFVBQVUsRUFBVkEsVUFGSztBQUdMVSxJQUFBQSxVQUFVLEVBQVZBLFVBSEs7QUFJTGhGLElBQUFBLGVBQWUsRUFBZkE7QUFKSyxHQUFQO0FBTUQ7QUFHRDs7Ozs7OztBQUtPLFNBQVN5RyxjQUFULENBQXdCcEQsS0FBeEIsRUFBK0I7QUFDcEMsc0JBQU8sK0VBQUUsMkNBQUYsZUFBTywyQ0FBSUEsS0FBSixDQUFQLE1BQVA7QUFDRDtBQUVEOzs7Ozs7O0FBS0EsU0FBU3FELGdCQUFULENBQTBCdEksSUFBMUIsRUFBZ0M7QUFDOUIsU0FBTztBQUNMMEMsSUFBQUEsSUFBSSxFQUFFLE1BREQ7QUFFTDFDLElBQUFBLElBQUksRUFBRUEsSUFGRDtBQUdMTCxJQUFBQSxJQUFJLEVBQUU7QUFIRCxHQUFQO0FBS0Q7QUFFRDs7Ozs7OztBQUtPLFNBQVM2SCxpQkFBVCxDQUEyQnZDLEtBQTNCLEVBQWtDO0FBQ3ZDLFNBQU9xRCxnQkFBZ0IsQ0FBQ0QsY0FBYyxDQUFDcEQsS0FBRCxDQUFmLENBQXZCO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IGlzRXF1YWwgZnJvbSAnZGVlcC1lcXVhbCc7XG5pbXBvcnQgKiBhcyBzdHJpbmdUb2tlbml6ZXIgZnJvbSAnc3RyaW5nLXB1bmN0dWF0aW9uLXRva2VuaXplcic7XG5pbXBvcnQgeyBWZXJzZU9iamVjdFV0aWxzIH0gZnJvbSAnd29yZC1hbGlnbmVyJztcbmltcG9ydCB7IGdldFZlcnNlcyB9IGZyb20gJ2JpYmxlLXJlZmVyZW5jZS1yYW5nZSc7XG4vLyBoZWxwZXJzXG5pbXBvcnQgKiBhcyBoaWdobGlnaHRIZWxwZXJzIGZyb20gJy4vaGlnaGxpZ2h0SGVscGVycyc7XG5pbXBvcnQge1xuICBjcmVhdGVIaWdobGlnaHRlZFNwYW4sXG4gIGNyZWF0ZU5vbkNsaWNrYWJsZVNwYW4sXG4gIGNyZWF0ZVRleHRTcGFuLFxuICBvbldvcmRDbGljayxcbn0gZnJvbSAnLi9odG1sRWxlbWVudHNIZWxwZXJzJztcbmltcG9ydCB7XG4gIGhhc0xlYWRpbmdTcGFjZSxcbiAgaGFzVHJhaWxpbmdTcGFjZSxcbiAgcmVtb3ZlTWFya2VyLFxufSBmcm9tICcuL3VzZm1IZWxwZXJzJztcbmltcG9ydCB7XG4gIGlzSXNvbGF0ZWRMZWZ0UXVvdGUsXG4gIGlzTmVzdGVkTWlsZXN0b25lLFxuICBpc1dvcmQsXG4gIHB1bmN0dWF0aW9uV29yZFNwYWNpbmcsXG4gIHRleHRJc0VtcHR5SW5WZXJzZU9iamVjdCxcbn0gZnJvbSAnLi9zdHJpbmdIZWxwZXJzJztcblxuLyoqXG4gKiBpZiBzaG93aW5nIFVTRk0gY29kZXMsIHJlcGxhY2UgbmV3bGluZXNcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0XG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3dVc2ZtXG4gKiBAcmV0dXJuIHtKU1guRWxlbWVudH1cbiAqL1xuZnVuY3Rpb24gdGV4dFRvSHRtbCh0ZXh0LCBzaG93VXNmbSkge1xuICBpZiAoc2hvd1VzZm0gJiYgKHRleHQuaW5kZXhPZignXFxuJykgPj0gMCkpIHtcbiAgICBjb25zdCBwYXJ0cyA9IHRleHQuc3BsaXQoJ1xcbicpO1xuICAgIGNvbnN0IGh0bWwgPSBbcGFydHNbMF1dO1xuXG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKykge1xuICAgICAgaHRtbC5wdXNoKCfihrInKTtcbiAgICAgIGh0bWwucHVzaCg8YnIvPik7XG4gICAgICBodG1sLnB1c2gocGFydHNbaV0pO1xuICAgIH1cbiAgICByZXR1cm4gaHRtbDtcbiAgfVxuICByZXR1cm4gdGV4dDtcbn1cblxuLyoqXG4gKiByZW5kZXIgdGV4dCBhcyBIVE1MIGFuZCBvdmVybGF5IGFueSBzZWxlY3Rpb25zXG4gKiBAcGFyYW0ge1N0cmluZ30gdmVyc2VUZXh0XG4gKiBAcGFyYW0ge0FycmF5fSBzZWxlY3Rpb25zIC0gdGV4dCBzZWxlY3Rpb25zIHRvIGhpZ2hsaWdodFxuICogQHBhcmFtIHtGdW5jdGlvbn0gdHJhbnNsYXRlXG4gKiBAcGFyYW0ge09iamVjdH0gZm9udFN0eWxlIC0gZm9udCBzcGVjaWZpYyBzdHlsaW5nXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzVGFyZ2V0QmlibGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBmb250Q2xhc3NcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvd1VzZm1cbiAqIEByZXR1cm4geyp9XG4gKi9cbmV4cG9ydCBjb25zdCB2ZXJzZVN0cmluZyA9ICh2ZXJzZVRleHQsIHNlbGVjdGlvbnMsIHRyYW5zbGF0ZSwgZm9udFN0eWxlID0gbnVsbCwgaXNUYXJnZXRCaWJsZSwgZm9udENsYXNzLCBzaG93VXNmbSkgPT4ge1xuICBsZXQgbmV3VmVyc2VUZXh0ID0gdmVyc2VUZXh0O1xuXG4gIGlmICghc2hvd1VzZm0pIHtcbiAgICBuZXdWZXJzZVRleHQgPSByZW1vdmVNYXJrZXIodmVyc2VUZXh0KTtcbiAgICBuZXdWZXJzZVRleHQgPSBuZXdWZXJzZVRleHQucmVwbGFjZSgvXFxzKy9nLCAnICcpO1xuICAgIC8vIGlmIHN0cmluZyBvbmx5IGNvbnRhaW5zIHNwYWNlcyB0aGVuIG1ha2UgaXQgYW4gZW1wdHkgc3RyaW5nXG4gICAgbmV3VmVyc2VUZXh0ID0gbmV3VmVyc2VUZXh0LnJlcGxhY2UoL1xccy9nLCAnJykubGVuZ3RoID09PSAwID8gJycgOiBuZXdWZXJzZVRleHQ7XG4gIH1cblxuICAvLyBpZiBlbXB0eSBzdHJpbmcgdGhlbiBuZXdWZXJzZVRleHQgPSBwbGFjZSBob2xkZXIgd2FybmluZy5cbiAgaWYgKG5ld1ZlcnNlVGV4dC5sZW5ndGggPT09IDApIHtcbiAgICBuZXdWZXJzZVRleHQgPSB0cmFuc2xhdGUoJ3BhbmUubWlzc2luZ192ZXJzZV93YXJuaW5nJyk7XG4gIH1cblxuICBsZXQgdmVyc2VUZXh0U3BhbnMgPSA8c3BhbiBjbGFzc05hbWU9e2ZvbnRDbGFzc30+e3RleHRUb0h0bWwobmV3VmVyc2VUZXh0LCBzaG93VXNmbSl9PC9zcGFuPjtcblxuICBpZiAoIXNob3dVc2ZtICYmIHNlbGVjdGlvbnMgJiYgc2VsZWN0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgX3NlbGVjdGlvbkFycmF5ID0gc3RyaW5nVG9rZW5pemVyLnNlbGVjdGlvbkFycmF5KG5ld1ZlcnNlVGV4dCwgc2VsZWN0aW9ucyk7XG4gICAgdmVyc2VUZXh0U3BhbnMgPSBbXTtcbiAgICB2ZXJzZVRleHRTcGFucy5sZW5ndGggPSAwO1xuXG4gICAgZm9yIChsZXQgaSA9IDAsIGxlbiA9IF9zZWxlY3Rpb25BcnJheS5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgY29uc3Qgc2VsZWN0aW9uID0gX3NlbGVjdGlvbkFycmF5W2ldO1xuICAgICAgY29uc3QgaW5kZXggPSBpO1xuICAgICAgbGV0IHNwYW5TdHlsZSA9IHsgYmFja2dyb3VuZENvbG9yOiBzZWxlY3Rpb24uc2VsZWN0ZWQgPyAndmFyKC0taGlnaGxpZ2h0LWNvbG9yKScgOiAnJyB9O1xuXG4gICAgICBpZiAoZm9udFN0eWxlKSB7XG4gICAgICAgIHNwYW5TdHlsZSA9IHtcbiAgICAgICAgICAuLi5zcGFuU3R5bGUsXG4gICAgICAgICAgLi4uZm9udFN0eWxlLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgdmVyc2VUZXh0U3BhbnMucHVzaChcbiAgICAgICAgPHNwYW4ga2V5PXtpbmRleH0gY2xhc3NOYW1lPXtmb250Q2xhc3N9IHN0eWxlPXtzcGFuU3R5bGV9PlxuICAgICAgICAgIHtzZWxlY3Rpb24udGV4dH1cbiAgICAgICAgPC9zcGFuPixcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHZlcnNlVGV4dFNwYW5zO1xufTtcblxuLyoqXG4gKiBjcmVhdGUgdmVyc2UgZWxlbWVudHMgZnJvbSBhbiBhcnJheSBvZiB2ZXJzZSBvYmplY3RzXG4gKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gdmVyc2VUZXh0IC0gdmVyc2UgZGF0YVxuICogQHBhcmFtIHtTdHJpbmd9IGJpYmxlSWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0SWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGdldExleGljb25EYXRhXG4gKiBAcGFyYW0ge0Jvb2xlYW59IHNob3dQb3BvdmVyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSB0cmFuc2xhdGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBmb250U3R5bGUgLSBmb250IHNwZWNpZmljIHN0eWxpbmdcbiAqIEBwYXJhbSB7U3RyaW5nfSBmb250Q2xhc3MgLSBmb250IGNsYXNzIG5hbWVcbiAqIEBwYXJhbSB7YXJyYXl9IHZlcnNlV29yZENvdW50cyAtIGFycmF5IG9mIHdvcmQgY291bnRzIGZvciBtdWx0aS12ZXJzZVxuICogQHJldHVybiB7QXJyYXl9IC0gdmVyc2UgZWxlbWVudHMgdG8gZGlzcGxheVxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyc2VBcnJheSh2ZXJzZVRleHQgPSBbXSwgYmlibGVJZCwgY29udGV4dElkLCBnZXRMZXhpY29uRGF0YSwgc2hvd1BvcG92ZXIsIHRyYW5zbGF0ZSwgZm9udFN0eWxlID0gbnVsbCwgZm9udENsYXNzLCB2ZXJzZVdvcmRDb3VudHMgPSBudWxsKSB7XG4gIGxldCB2ZXJzZU9iamVjdHMgPSBWZXJzZU9iamVjdFV0aWxzLmdldFdvcmRMaXN0Rm9yVmVyc2UodmVyc2VUZXh0KTtcbiAgbGV0IHdvcmRTcGFjaW5nID0gJyc7XG4gIGxldCBwcmV2aW91c1dvcmQgPSBudWxsO1xuICBjb25zdCB2ZXJzZVNwYW4gPSBbXTtcbiAgdmVyc2VTcGFuLmxlbmd0aCA9IDA7XG5cbiAgaWYgKHZlcnNlVGV4dC52ZXJzZU9iamVjdHMgJiYgdGV4dElzRW1wdHlJblZlcnNlT2JqZWN0KHZlcnNlVGV4dCwgYmlibGVJZCkpIHsgLy8gaWYgZW1wdHkgdmVyc2Ugc3RyaW5nLlxuICAgIHZlcnNlU3Bhbi5wdXNoKFxuICAgICAgPHNwYW4ga2V5PXt0cmFuc2xhdGUoJ3BhbmUubWlzc2luZ192ZXJzZV93YXJuaW5nJyl9PlxuICAgICAgICB7dHJhbnNsYXRlKCdwYW5lLm1pc3NpbmdfdmVyc2Vfd2FybmluZycpfVxuICAgICAgPC9zcGFuPixcbiAgICApO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IGlzSGVicmV3ID0gKGJpYmxlSWQgPT09ICd1aGInKTtcbiAgICBjb25zdCBvcmlnTGFuZ0JpYmxlID0gaXNIZWJyZXcgfHwgYmlibGVJZCA9PT0gJ3VnbnQnO1xuICAgIHZlcnNlT2JqZWN0cyA9IEFycmF5LmlzQXJyYXkodmVyc2VPYmplY3RzKSA/IHZlcnNlT2JqZWN0cyA6IHZlcnNlT2JqZWN0cy52ZXJzZU9iamVjdDtcblxuICAgIGZvciAobGV0IGkgPSAwLCBsZW4gPSB2ZXJzZU9iamVjdHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIGNvbnN0IG9iamVjdCA9IHZlcnNlT2JqZWN0c1tpXTtcbiAgICAgIGNvbnN0IGluZGV4ID0gaTtcbiAgICAgIGNvbnN0IG5leHRXb3JkID0gdmVyc2VPYmplY3RzW2luZGV4ICsgMV07XG5cbiAgICAgIGlmIChvYmplY3QudHlwZSA9PT0gJ2h0bWwnKSB7XG4gICAgICAgIHZlcnNlU3Bhbi5wdXNoKG9iamVjdC5odG1sKTtcbiAgICAgIH0gZWxzZSBpZiAoaXNXb3JkKG9iamVjdCkpIHtcbiAgICAgICAgY29uc3QgcGFkZGluZyA9IHdvcmRTcGFjaW5nO1xuICAgICAgICB3b3JkU3BhY2luZyA9ICcgJzsgLy8gc3BhY2luZyBiZXR3ZWVuIHdvcmRzXG4gICAgICAgIGNvbnN0IHRleHQgPSAob2JqZWN0LndvcmQgfHwgb2JqZWN0LnRleHQpO1xuICAgICAgICBsZXQgaXNIaWdobGlnaHRlZFdvcmQgPSBmYWxzZTtcbiAgICAgICAgbGV0IGlzQmV0d2VlbkhpZ2hsaWdodGVkV29yZCA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChvcmlnTGFuZ0JpYmxlICYmIGNvbnRleHRJZC5xdW90ZSAmJiBvYmplY3QudGV4dCkge1xuICAgICAgICAgIGlzSGlnaGxpZ2h0ZWRXb3JkID0gaGlnaGxpZ2h0SGVscGVycy5pc1dvcmRNYXRjaChvYmplY3QsIGNvbnRleHRJZCwgdmVyc2VPYmplY3RzLCBpbmRleCk7XG4gICAgICAgICAgaXNCZXR3ZWVuSGlnaGxpZ2h0ZWRXb3JkID0gcHJldmlvdXNXb3JkICYmICFpc0VxdWFsKHByZXZpb3VzV29yZCwgb2JqZWN0KSAmJlxuICAgICAgICAgICAgaGlnaGxpZ2h0SGVscGVycy5pc1dvcmRNYXRjaChwcmV2aW91c1dvcmQsIGNvbnRleHRJZCwgdmVyc2VPYmplY3RzLCBpbmRleCAtIDEpICYmIGlzSGlnaGxpZ2h0ZWRXb3JkO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbnRleHRJZC5xdW90ZSAmJiBvYmplY3QuY29udGVudCkge1xuICAgICAgICAgIGNvbnN0IGhpZ2hsaWdodGVkRGV0YWlscyA9IGhpZ2hsaWdodEhlbHBlcnMuZ2V0V29yZEhpZ2hsaWdodGVkRGV0YWlscyhjb250ZXh0SWQsIHByZXZpb3VzV29yZCwgb2JqZWN0LCB2ZXJzZVdvcmRDb3VudHMpO1xuICAgICAgICAgIGlzSGlnaGxpZ2h0ZWRXb3JkID0gaGlnaGxpZ2h0ZWREZXRhaWxzLmlzSGlnaGxpZ2h0ZWRXb3JkO1xuICAgICAgICAgIGlzQmV0d2VlbkhpZ2hsaWd