UNPKG

@circuitly/diff

Version:

A javascript text diff implementation.

281 lines (274 loc) 40.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.diffWords = diffWords; exports.diffWordsWithSpace = diffWordsWithSpace; exports.wordWithSpaceDiff = exports.wordDiff = void 0; var _base = _interopRequireDefault(require("./base")); var _string = require("../util/string"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode // // Ranges and exceptions: // Latin-1 Supplement, 0080–00FF // - U+00D7 × Multiplication sign // - U+00F7 ÷ Division sign // Latin Extended-A, 0100–017F // Latin Extended-B, 0180–024F // IPA Extensions, 0250–02AF // Spacing Modifier Letters, 02B0–02FF // - U+02C7 ˇ ˇ Caron // - U+02D8 ˘ ˘ Breve // - U+02D9 ˙ ˙ Dot Above // - U+02DA ˚ ˚ Ring Above // - U+02DB ˛ ˛ Ogonek // - U+02DC ˜ ˜ Small Tilde // - U+02DD ˝ ˝ Double Acute Accent // Latin Extended Additional, 1E00–1EFF var extendedWordChars = "a-zA-Z0-9_\\u{C0}-\\u{FF}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}"; // Each token is one of the following: // - A punctuation mark plus the surrounding whitespace // - A word plus the surrounding whitespace // - Pure whitespace (but only in the special case where this the entire text // is just whitespace) // // We have to include surrounding whitespace in the tokens because the two // alternative approaches produce horribly broken results: // * If we just discard the whitespace, we can't fully reproduce the original // text from the sequence of tokens and any attempt to render the diff will // get the whitespace wrong. // * If we have separate tokens for whitespace, then in a typical text every // second token will be a single space character. But this often results in // the optimal diff between two texts being a perverse one that preserves // the spaces between words but deletes and reinserts actual common words. // See https://github.com/kpdecker/jsdiff/issues/160#issuecomment-1866099640 // for an example. // // Keeping the surrounding whitespace of course has implications for .equals // and .join, not just .tokenize. // This regex does NOT fully implement the tokenization rules described above. // Instead, it gives runs of whitespace their own "token". The tokenize method // then handles stitching whitespace tokens onto adjacent word or punctuation // tokens. var tokenizeIncludingWhitespace = new RegExp("[".concat(extendedWordChars, "]+|\\s+|[^").concat(extendedWordChars, "]"), 'ug'); var wordDiff = exports.wordDiff = new _base["default"](); wordDiff.equals = function (left, right, options) { if (options.ignoreCase) { left = left.toLowerCase(); right = right.toLowerCase(); } return left.trim() === right.trim(); }; wordDiff.tokenize = function (value) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var parts; if (options.intlSegmenter) { if (options.intlSegmenter.resolvedOptions().granularity != 'word') { throw new Error('The segmenter passed must have a granularity of "word"'); } parts = Array.from(options.intlSegmenter.segment(value), function (segment) { return segment.segment; }); } else { parts = value.match(tokenizeIncludingWhitespace) || []; } var tokens = []; var prevPart = null; parts.forEach(function (part) { if (/\s/.test(part)) { if (prevPart == null) { tokens.push(part); } else { tokens.push(tokens.pop() + part); } } else if (/\s/.test(prevPart)) { if (tokens[tokens.length - 1] == prevPart) { tokens.push(tokens.pop() + part); } else { tokens.push(prevPart + part); } } else { tokens.push(part); } prevPart = part; }); return tokens; }; wordDiff.join = function (tokens) { // Tokens being joined here will always have appeared consecutively in the // same text, so we can simply strip off the leading whitespace from all the // tokens except the first (and except any whitespace-only tokens - but such // a token will always be the first and only token anyway) and then join them // and the whitespace around words and punctuation will end up correct. return tokens.map(function (token, i) { if (i == 0) { return token; } else { return token.replace(/^\s+/, ''); } }).join(''); }; wordDiff.postProcess = function (changes, options) { if (!changes || options.oneChangePerToken) { return changes; } var lastKeep = null; // Change objects representing any insertion or deletion since the last // "keep" change object. There can be at most one of each. var insertion = null; var deletion = null; changes.forEach(function (change) { if (change.added) { insertion = change; } else if (change.removed) { deletion = change; } else { if (insertion || deletion) { // May be false at start of text dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change); } lastKeep = change; insertion = null; deletion = null; } }); if (insertion || deletion) { dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null); } return changes; }; function diffWords(oldStr, newStr, options) { // This option has never been documented and never will be (it's clearer to // just call `diffWordsWithSpace` directly if you need that behavior), but // has existed in jsdiff for a long time, so we retain support for it here // for the sake of backwards compatibility. if ((options === null || options === void 0 ? void 0 : options.ignoreWhitespace) != null && !options.ignoreWhitespace) { return diffWordsWithSpace(oldStr, newStr, options); } return wordDiff.diff(oldStr, newStr, options); } function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) { // Before returning, we tidy up the leading and trailing whitespace of the // change objects to eliminate cases where trailing whitespace in one object // is repeated as leading whitespace in the next. // Below are examples of the outcomes we want here to explain the code. // I=insert, K=keep, D=delete // 1. diffing 'foo bar baz' vs 'foo baz' // Prior to cleanup, we have K:'foo ' D:' bar ' K:' baz' // After cleanup, we want: K:'foo ' D:'bar ' K:'baz' // // 2. Diffing 'foo bar baz' vs 'foo qux baz' // Prior to cleanup, we have K:'foo ' D:' bar ' I:' qux ' K:' baz' // After cleanup, we want K:'foo ' D:'bar' I:'qux' K:' baz' // // 3. Diffing 'foo\nbar baz' vs 'foo baz' // Prior to cleanup, we have K:'foo ' D:'\nbar ' K:' baz' // After cleanup, we want K'foo' D:'\nbar' K:' baz' // // 4. Diffing 'foo baz' vs 'foo\nbar baz' // Prior to cleanup, we have K:'foo\n' I:'\nbar ' K:' baz' // After cleanup, we ideally want K'foo' I:'\nbar' K:' baz' // but don't actually manage this currently (the pre-cleanup change // objects don't contain enough information to make it possible). // // 5. Diffing 'foo bar baz' vs 'foo baz' // Prior to cleanup, we have K:'foo ' D:' bar ' K:' baz' // After cleanup, we want K:'foo ' D:' bar ' K:'baz' // // Our handling is unavoidably imperfect in the case where there's a single // indel between keeps and the whitespace has changed. For instance, consider // diffing 'foo\tbar\nbaz' vs 'foo baz'. Unless we create an extra change // object to represent the insertion of the space character (which isn't even // a token), we have no way to avoid losing information about the texts' // original whitespace in the result we return. Still, we do our best to // output something that will look sensible if we e.g. print it with // insertions in green and deletions in red. // Between two "keep" change objects (or before the first or after the last // change object), we can have either: // * A "delete" followed by an "insert" // * Just an "insert" // * Just a "delete" // We handle the three cases separately. if (deletion && insertion) { var oldWsPrefix = (0, _string.leadingWs)(deletion.value); var oldWsSuffix = (0, _string.trailingWs)(deletion.value); var newWsPrefix = (0, _string.leadingWs)(insertion.value); var newWsSuffix = (0, _string.trailingWs)(insertion.value); if (startKeep) { var commonWsPrefix = (0, _string.longestCommonPrefix)(oldWsPrefix, newWsPrefix); startKeep.value = (0, _string.replaceSuffix)(startKeep.value, newWsPrefix, commonWsPrefix); deletion.value = (0, _string.removePrefix)(deletion.value, commonWsPrefix); insertion.value = (0, _string.removePrefix)(insertion.value, commonWsPrefix); } if (endKeep) { var commonWsSuffix = (0, _string.longestCommonSuffix)(oldWsSuffix, newWsSuffix); endKeep.value = (0, _string.replacePrefix)(endKeep.value, newWsSuffix, commonWsSuffix); deletion.value = (0, _string.removeSuffix)(deletion.value, commonWsSuffix); insertion.value = (0, _string.removeSuffix)(insertion.value, commonWsSuffix); } } else if (insertion) { // The whitespaces all reflect what was in the new text rather than // the old, so we essentially have no information about whitespace // insertion or deletion. We just want to dedupe the whitespace. // We do that by having each change object keep its trailing // whitespace and deleting duplicate leading whitespace where // present. if (startKeep) { var ws = (0, _string.leadingWs)(insertion.value); insertion.value = insertion.value.substring(ws.length); } if (endKeep) { var _ws = (0, _string.leadingWs)(endKeep.value); endKeep.value = endKeep.value.substring(_ws.length); } // otherwise we've got a deletion and no insertion } else if (startKeep && endKeep) { var newWsFull = (0, _string.leadingWs)(endKeep.value), delWsStart = (0, _string.leadingWs)(deletion.value), delWsEnd = (0, _string.trailingWs)(deletion.value); // Any whitespace that comes straight after startKeep in both the old and // new texts, assign to startKeep and remove from the deletion. var newWsStart = (0, _string.longestCommonPrefix)(newWsFull, delWsStart); deletion.value = (0, _string.removePrefix)(deletion.value, newWsStart); // Any whitespace that comes straight before endKeep in both the old and // new texts, and hasn't already been assigned to startKeep, assign to // endKeep and remove from the deletion. var newWsEnd = (0, _string.longestCommonSuffix)((0, _string.removePrefix)(newWsFull, newWsStart), delWsEnd); deletion.value = (0, _string.removeSuffix)(deletion.value, newWsEnd); endKeep.value = (0, _string.replacePrefix)(endKeep.value, newWsFull, newWsEnd); // If there's any whitespace from the new text that HASN'T already been // assigned, assign it to the start: startKeep.value = (0, _string.replaceSuffix)(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length)); } else if (endKeep) { // We are at the start of the text. Preserve all the whitespace on // endKeep, and just remove whitespace from the end of deletion to the // extent that it overlaps with the start of endKeep. var endKeepWsPrefix = (0, _string.leadingWs)(endKeep.value); var deletionWsSuffix = (0, _string.trailingWs)(deletion.value); var overlap = (0, _string.maximumOverlap)(deletionWsSuffix, endKeepWsPrefix); deletion.value = (0, _string.removeSuffix)(deletion.value, overlap); } else if (startKeep) { // We are at the END of the text. Preserve all the whitespace on // startKeep, and just remove whitespace from the start of deletion to // the extent that it overlaps with the end of startKeep. var startKeepWsSuffix = (0, _string.trailingWs)(startKeep.value); var deletionWsPrefix = (0, _string.leadingWs)(deletion.value); var _overlap = (0, _string.maximumOverlap)(startKeepWsSuffix, deletionWsPrefix); deletion.value = (0, _string.removePrefix)(deletion.value, _overlap); } } var wordWithSpaceDiff = exports.wordWithSpaceDiff = new _base["default"](); wordWithSpaceDiff.tokenize = function (value) { // Slightly different to the tokenizeIncludingWhitespace regex used above in // that this one treats each individual newline as a distinct tokens, rather // than merging them into other surrounding whitespace. This was requested // in https://github.com/kpdecker/jsdiff/issues/180 & // https://github.com/kpdecker/jsdiff/issues/211 var regex = new RegExp("(\\r?\\n)|[".concat(extendedWordChars, "]+|[^\\S\\n\\r]+|[^").concat(extendedWordChars, "]"), 'ug'); return value.match(regex) || []; }; function diffWordsWithSpace(oldStr, newStr, options) { return wordWithSpaceDiff.diff(oldStr, newStr, options); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYmFzZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX3N0cmluZyIsImUiLCJfX2VzTW9kdWxlIiwiZXh0ZW5kZWRXb3JkQ2hhcnMiLCJ0b2tlbml6ZUluY2x1ZGluZ1doaXRlc3BhY2UiLCJSZWdFeHAiLCJjb25jYXQiLCJ3b3JkRGlmZiIsImV4cG9ydHMiLCJEaWZmIiwiZXF1YWxzIiwibGVmdCIsInJpZ2h0Iiwib3B0aW9ucyIsImlnbm9yZUNhc2UiLCJ0b0xvd2VyQ2FzZSIsInRyaW0iLCJ0b2tlbml6ZSIsInZhbHVlIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwidW5kZWZpbmVkIiwicGFydHMiLCJpbnRsU2VnbWVudGVyIiwicmVzb2x2ZWRPcHRpb25zIiwiZ3JhbnVsYXJpdHkiLCJFcnJvciIsIkFycmF5IiwiZnJvbSIsInNlZ21lbnQiLCJtYXRjaCIsInRva2VucyIsInByZXZQYXJ0IiwiZm9yRWFjaCIsInBhcnQiLCJ0ZXN0IiwicHVzaCIsInBvcCIsImpvaW4iLCJtYXAiLCJ0b2tlbiIsImkiLCJyZXBsYWNlIiwicG9zdFByb2Nlc3MiLCJjaGFuZ2VzIiwib25lQ2hhbmdlUGVyVG9rZW4iLCJsYXN0S2VlcCIsImluc2VydGlvbiIsImRlbGV0aW9uIiwiY2hhbmdlIiwiYWRkZWQiLCJyZW1vdmVkIiwiZGVkdXBlV2hpdGVzcGFjZUluQ2hhbmdlT2JqZWN0cyIsImRpZmZXb3JkcyIsIm9sZFN0ciIsIm5ld1N0ciIsImlnbm9yZVdoaXRlc3BhY2UiLCJkaWZmV29yZHNXaXRoU3BhY2UiLCJkaWZmIiwic3RhcnRLZWVwIiwiZW5kS2VlcCIsIm9sZFdzUHJlZml4IiwibGVhZGluZ1dzIiwib2xkV3NTdWZmaXgiLCJ0cmFpbGluZ1dzIiwibmV3V3NQcmVmaXgiLCJuZXdXc1N1ZmZpeCIsImNvbW1vbldzUHJlZml4IiwibG9uZ2VzdENvbW1vblByZWZpeCIsInJlcGxhY2VTdWZmaXgiLCJyZW1vdmVQcmVmaXgiLCJjb21tb25Xc1N1ZmZpeCIsImxvbmdlc3RDb21tb25TdWZmaXgiLCJyZXBsYWNlUHJlZml4IiwicmVtb3ZlU3VmZml4Iiwid3MiLCJzdWJzdHJpbmciLCJuZXdXc0Z1bGwiLCJkZWxXc1N0YXJ0IiwiZGVsV3NFbmQiLCJuZXdXc1N0YXJ0IiwibmV3V3NFbmQiLCJzbGljZSIsImVuZEtlZXBXc1ByZWZpeCIsImRlbGV0aW9uV3NTdWZmaXgiLCJvdmVybGFwIiwibWF4aW11bU92ZXJsYXAiLCJzdGFydEtlZXBXc1N1ZmZpeCIsImRlbGV0aW9uV3NQcmVmaXgiLCJ3b3JkV2l0aFNwYWNlRGlmZiIsInJlZ2V4Il0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2RpZmYvd29yZC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgRGlmZiBmcm9tICcuL2Jhc2UnO1xuaW1wb3J0IHsgbG9uZ2VzdENvbW1vblByZWZpeCwgbG9uZ2VzdENvbW1vblN1ZmZpeCwgcmVwbGFjZVByZWZpeCwgcmVwbGFjZVN1ZmZpeCwgcmVtb3ZlUHJlZml4LCByZW1vdmVTdWZmaXgsIG1heGltdW1PdmVybGFwLCBsZWFkaW5nV3MsIHRyYWlsaW5nV3MgfSBmcm9tICcuLi91dGlsL3N0cmluZyc7XG5cbi8vIEJhc2VkIG9uIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xhdGluX3NjcmlwdF9pbl9Vbmljb2RlXG4vL1xuLy8gUmFuZ2VzIGFuZCBleGNlcHRpb25zOlxuLy8gTGF0aW4tMSBTdXBwbGVtZW50LCAwMDgw4oCTMDBGRlxuLy8gIC0gVSswMEQ3ICDDlyBNdWx0aXBsaWNhdGlvbiBzaWduXG4vLyAgLSBVKzAwRjcgIMO3IERpdmlzaW9uIHNpZ25cbi8vIExhdGluIEV4dGVuZGVkLUEsIDAxMDDigJMwMTdGXG4vLyBMYXRpbiBFeHRlbmRlZC1CLCAwMTgw4oCTMDI0RlxuLy8gSVBBIEV4dGVuc2lvbnMsIDAyNTDigJMwMkFGXG4vLyBTcGFjaW5nIE1vZGlmaWVyIExldHRlcnMsIDAyQjDigJMwMkZGXG4vLyAgLSBVKzAyQzcgIMuHICYjNzExOyAgQ2Fyb25cbi8vICAtIFUrMDJEOCAgy5ggJiM3Mjg7ICBCcmV2ZVxuLy8gIC0gVSswMkQ5ICDLmSAmIzcyOTsgIERvdCBBYm92ZVxuLy8gIC0gVSswMkRBICDLmiAmIzczMDsgIFJpbmcgQWJvdmVcbi8vICAtIFUrMDJEQiAgy5sgJiM3MzE7ICBPZ29uZWtcbi8vICAtIFUrMDJEQyAgy5wgJiM3MzI7ICBTbWFsbCBUaWxkZVxuLy8gIC0gVSswMkREICDLnSAmIzczMzsgIERvdWJsZSBBY3V0ZSBBY2NlbnRcbi8vIExhdGluIEV4dGVuZGVkIEFkZGl0aW9uYWwsIDFFMDDigJMxRUZGXG5jb25zdCBleHRlbmRlZFdvcmRDaGFycyA9ICdhLXpBLVowLTlfXFxcXHV7QzB9LVxcXFx1e0ZGfVxcXFx1e0Q4fS1cXFxcdXtGNn1cXFxcdXtGOH0tXFxcXHV7MkM2fVxcXFx1ezJDOH0tXFxcXHV7MkQ3fVxcXFx1ezJERX0tXFxcXHV7MkZGfVxcXFx1ezFFMDB9LVxcXFx1ezFFRkZ9JztcblxuLy8gRWFjaCB0b2tlbiBpcyBvbmUgb2YgdGhlIGZvbGxvd2luZzpcbi8vIC0gQSBwdW5jdHVhdGlvbiBtYXJrIHBsdXMgdGhlIHN1cnJvdW5kaW5nIHdoaXRlc3BhY2Vcbi8vIC0gQSB3b3JkIHBsdXMgdGhlIHN1cnJvdW5kaW5nIHdoaXRlc3BhY2Vcbi8vIC0gUHVyZSB3aGl0ZXNwYWNlIChidXQgb25seSBpbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIHRoaXMgdGhlIGVudGlyZSB0ZXh0XG4vLyAgIGlzIGp1c3Qgd2hpdGVzcGFjZSlcbi8vXG4vLyBXZSBoYXZlIHRvIGluY2x1ZGUgc3Vycm91bmRpbmcgd2hpdGVzcGFjZSBpbiB0aGUgdG9rZW5zIGJlY2F1c2UgdGhlIHR3b1xuLy8gYWx0ZXJuYXRpdmUgYXBwcm9hY2hlcyBwcm9kdWNlIGhvcnJpYmx5IGJyb2tlbiByZXN1bHRzOlxuLy8gKiBJZiB3ZSBqdXN0IGRpc2NhcmQgdGhlIHdoaXRlc3BhY2UsIHdlIGNhbid0IGZ1bGx5IHJlcHJvZHVjZSB0aGUgb3JpZ2luYWxcbi8vICAgdGV4dCBmcm9tIHRoZSBzZXF1ZW5jZSBvZiB0b2tlbnMgYW5kIGFueSBhdHRlbXB0IHRvIHJlbmRlciB0aGUgZGlmZiB3aWxsXG4vLyAgIGdldCB0aGUgd2hpdGVzcGFjZSB3cm9uZy5cbi8vICogSWYgd2UgaGF2ZSBzZXBhcmF0ZSB0b2tlbnMgZm9yIHdoaXRlc3BhY2UsIHRoZW4gaW4gYSB0eXBpY2FsIHRleHQgZXZlcnlcbi8vICAgc2Vjb25kIHRva2VuIHdpbGwgYmUgYSBzaW5nbGUgc3BhY2UgY2hhcmFjdGVyLiBCdXQgdGhpcyBvZnRlbiByZXN1bHRzIGluXG4vLyAgIHRoZSBvcHRpbWFsIGRpZmYgYmV0d2VlbiB0d28gdGV4dHMgYmVpbmcgYSBwZXJ2ZXJzZSBvbmUgdGhhdCBwcmVzZXJ2ZXNcbi8vICAgdGhlIHNwYWNlcyBiZXR3ZWVuIHdvcmRzIGJ1dCBkZWxldGVzIGFuZCByZWluc2VydHMgYWN0dWFsIGNvbW1vbiB3b3Jkcy5cbi8vICAgU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9rcGRlY2tlci9qc2RpZmYvaXNzdWVzLzE2MCNpc3N1ZWNvbW1lbnQtMTg2NjA5OTY0MFxuLy8gICBmb3IgYW4gZXhhbXBsZS5cbi8vXG4vLyBLZWVwaW5nIHRoZSBzdXJyb3VuZGluZyB3aGl0ZXNwYWNlIG9mIGNvdXJzZSBoYXMgaW1wbGljYXRpb25zIGZvciAuZXF1YWxzXG4vLyBhbmQgLmpvaW4sIG5vdCBqdXN0IC50b2tlbml6ZS5cblxuLy8gVGhpcyByZWdleCBkb2VzIE5PVCBmdWxseSBpbXBsZW1lbnQgdGhlIHRva2VuaXphdGlvbiBydWxlcyBkZXNjcmliZWQgYWJvdmUuXG4vLyBJbnN0ZWFkLCBpdCBnaXZlcyBydW5zIG9mIHdoaXRlc3BhY2UgdGhlaXIgb3duIFwidG9rZW5cIi4gVGhlIHRva2VuaXplIG1ldGhvZFxuLy8gdGhlbiBoYW5kbGVzIHN0aXRjaGluZyB3aGl0ZXNwYWNlIHRva2VucyBvbnRvIGFkamFjZW50IHdvcmQgb3IgcHVuY3R1YXRpb25cbi8vIHRva2Vucy5cbmNvbnN0IHRva2VuaXplSW5jbHVkaW5nV2hpdGVzcGFjZSA9IG5ldyBSZWdFeHAoYFske2V4dGVuZGVkV29yZENoYXJzfV0rfFxcXFxzK3xbXiR7ZXh0ZW5kZWRXb3JkQ2hhcnN9XWAsICd1ZycpO1xuXG5leHBvcnQgY29uc3Qgd29yZERpZmYgPSBuZXcgRGlmZigpO1xud29yZERpZmYuZXF1YWxzID0gZnVuY3Rpb24obGVmdCwgcmlnaHQsIG9wdGlvbnMpIHtcbiAgaWYgKG9wdGlvbnMuaWdub3JlQ2FzZSkge1xuICAgIGxlZnQgPSBsZWZ0LnRvTG93ZXJDYXNlKCk7XG4gICAgcmlnaHQgPSByaWdodC50b0xvd2VyQ2FzZSgpO1xuICB9XG5cbiAgcmV0dXJuIGxlZnQudHJpbSgpID09PSByaWdodC50cmltKCk7XG59O1xuXG53b3JkRGlmZi50b2tlbml6ZSA9IGZ1bmN0aW9uKHZhbHVlLCBvcHRpb25zID0ge30pIHtcbiAgbGV0IHBhcnRzO1xuICBpZiAob3B0aW9ucy5pbnRsU2VnbWVudGVyKSB7XG4gICAgaWYgKG9wdGlvbnMuaW50bFNlZ21lbnRlci5yZXNvbHZlZE9wdGlvbnMoKS5ncmFudWxhcml0eSAhPSAnd29yZCcpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVGhlIHNlZ21lbnRlciBwYXNzZWQgbXVzdCBoYXZlIGEgZ3JhbnVsYXJpdHkgb2YgXCJ3b3JkXCInKTtcbiAgICB9XG4gICAgcGFydHMgPSBBcnJheS5mcm9tKG9wdGlvbnMuaW50bFNlZ21lbnRlci5zZWdtZW50KHZhbHVlKSwgc2VnbWVudCA9PiBzZWdtZW50LnNlZ21lbnQpO1xuICB9IGVsc2Uge1xuICAgIHBhcnRzID0gdmFsdWUubWF0Y2godG9rZW5pemVJbmNsdWRpbmdXaGl0ZXNwYWNlKSB8fCBbXTtcbiAgfVxuICBjb25zdCB0b2tlbnMgPSBbXTtcbiAgbGV0IHByZXZQYXJ0ID0gbnVsbDtcbiAgcGFydHMuZm9yRWFjaChwYXJ0ID0+IHtcbiAgICBpZiAoKC9cXHMvKS50ZXN0KHBhcnQpKSB7XG4gICAgICBpZiAocHJldlBhcnQgPT0gbnVsbCkge1xuICAgICAgICB0b2tlbnMucHVzaChwYXJ0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRva2Vucy5wdXNoKHRva2Vucy5wb3AoKSArIHBhcnQpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoKC9cXHMvKS50ZXN0KHByZXZQYXJ0KSkge1xuICAgICAgaWYgKHRva2Vuc1t0b2tlbnMubGVuZ3RoIC0gMV0gPT0gcHJldlBhcnQpIHtcbiAgICAgICAgdG9rZW5zLnB1c2godG9rZW5zLnBvcCgpICsgcGFydCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0b2tlbnMucHVzaChwcmV2UGFydCArIHBhcnQpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0b2tlbnMucHVzaChwYXJ0KTtcbiAgICB9XG5cbiAgICBwcmV2UGFydCA9IHBhcnQ7XG4gIH0pO1xuICByZXR1cm4gdG9rZW5zO1xufTtcblxud29yZERpZmYuam9pbiA9IGZ1bmN0aW9uKHRva2Vucykge1xuICAvLyBUb2tlbnMgYmVpbmcgam9pbmVkIGhlcmUgd2lsbCBhbHdheXMgaGF2ZSBhcHBlYXJlZCBjb25zZWN1dGl2ZWx5IGluIHRoZVxuICAvLyBzYW1lIHRleHQsIHNvIHdlIGNhbiBzaW1wbHkgc3RyaXAgb2ZmIHRoZSBsZWFkaW5nIHdoaXRlc3BhY2UgZnJvbSBhbGwgdGhlXG4gIC8vIHRva2VucyBleGNlcHQgdGhlIGZpcnN0IChhbmQgZXhjZXB0IGFueSB3aGl0ZXNwYWNlLW9ubHkgdG9rZW5zIC0gYnV0IHN1Y2hcbiAgLy8gYSB0b2tlbiB3aWxsIGFsd2F5cyBiZSB0aGUgZmlyc3QgYW5kIG9ubHkgdG9rZW4gYW55d2F5KSBhbmQgdGhlbiBqb2luIHRoZW1cbiAgLy8gYW5kIHRoZSB3aGl0ZXNwYWNlIGFyb3VuZCB3b3JkcyBhbmQgcHVuY3R1YXRpb24gd2lsbCBlbmQgdXAgY29ycmVjdC5cbiAgcmV0dXJuIHRva2Vucy5tYXAoKHRva2VuLCBpKSA9PiB7XG4gICAgaWYgKGkgPT0gMCkge1xuICAgICAgcmV0dXJuIHRva2VuO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdG9rZW4ucmVwbGFjZSgoL15cXHMrLyksICcnKTtcbiAgICB9XG4gIH0pLmpvaW4oJycpO1xufTtcblxud29yZERpZmYucG9zdFByb2Nlc3MgPSBmdW5jdGlvbihjaGFuZ2VzLCBvcHRpb25zKSB7XG4gIGlmICghY2hhbmdlcyB8fCBvcHRpb25zLm9uZUNoYW5nZVBlclRva2VuKSB7XG4gICAgcmV0dXJuIGNoYW5nZXM7XG4gIH1cblxuICBsZXQgbGFzdEtlZXAgPSBudWxsO1xuICAvLyBDaGFuZ2Ugb2JqZWN0cyByZXByZXNlbnRpbmcgYW55IGluc2VydGlvbiBvciBkZWxldGlvbiBzaW5jZSB0aGUgbGFzdFxuICAvLyBcImtlZXBcIiBjaGFuZ2Ugb2JqZWN0LiBUaGVyZSBjYW4gYmUgYXQgbW9zdCBvbmUgb2YgZWFjaC5cbiAgbGV0IGluc2VydGlvbiA9IG51bGw7XG4gIGxldCBkZWxldGlvbiA9IG51bGw7XG4gIGNoYW5nZXMuZm9yRWFjaChjaGFuZ2UgPT4ge1xuICAgIGlmIChjaGFuZ2UuYWRkZWQpIHtcbiAgICAgIGluc2VydGlvbiA9IGNoYW5nZTtcbiAgICB9IGVsc2UgaWYgKGNoYW5nZS5yZW1vdmVkKSB7XG4gICAgICBkZWxldGlvbiA9IGNoYW5nZTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGluc2VydGlvbiB8fCBkZWxldGlvbikgeyAvLyBNYXkgYmUgZmFsc2UgYXQgc3RhcnQgb2YgdGV4dFxuICAgICAgICBkZWR1cGVXaGl0ZXNwYWNlSW5DaGFuZ2VPYmplY3RzKGxhc3RLZWVwLCBkZWxldGlvbiwgaW5zZXJ0aW9uLCBjaGFuZ2UpO1xuICAgICAgfVxuICAgICAgbGFzdEtlZXAgPSBjaGFuZ2U7XG4gICAgICBpbnNlcnRpb24gPSBudWxsO1xuICAgICAgZGVsZXRpb24gPSBudWxsO1xuICAgIH1cbiAgfSk7XG4gIGlmIChpbnNlcnRpb24gfHwgZGVsZXRpb24pIHtcbiAgICBkZWR1cGVXaGl0ZXNwYWNlSW5DaGFuZ2VPYmplY3RzKGxhc3RLZWVwLCBkZWxldGlvbiwgaW5zZXJ0aW9uLCBudWxsKTtcbiAgfVxuICByZXR1cm4gY2hhbmdlcztcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmV29yZHMob2xkU3RyLCBuZXdTdHIsIG9wdGlvbnMpIHtcbiAgLy8gVGhpcyBvcHRpb24gaGFzIG5ldmVyIGJlZW4gZG9jdW1lbnRlZCBhbmQgbmV2ZXIgd2lsbCBiZSAoaXQncyBjbGVhcmVyIHRvXG4gIC8vIGp1c3QgY2FsbCBgZGlmZldvcmRzV2l0aFNwYWNlYCBkaXJlY3RseSBpZiB5b3UgbmVlZCB0aGF0IGJlaGF2aW9yKSwgYnV0XG4gIC8vIGhhcyBleGlzdGVkIGluIGpzZGlmZiBmb3IgYSBsb25nIHRpbWUsIHNvIHdlIHJldGFpbiBzdXBwb3J0IGZvciBpdCBoZXJlXG4gIC8vIGZvciB0aGUgc2FrZSBvZiBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS5cbiAgaWYgKG9wdGlvbnM/Lmlnbm9yZVdoaXRlc3BhY2UgIT0gbnVsbCAmJiAhb3B0aW9ucy5pZ25vcmVXaGl0ZXNwYWNlKSB7XG4gICAgcmV0dXJuIGRpZmZXb3Jkc1dpdGhTcGFjZShvbGRTdHIsIG5ld1N0ciwgb3B0aW9ucyk7XG4gIH1cblxuICByZXR1cm4gd29yZERpZmYuZGlmZihvbGRTdHIsIG5ld1N0ciwgb3B0aW9ucyk7XG59XG5cbmZ1bmN0aW9uIGRlZHVwZVdoaXRlc3BhY2VJbkNoYW5nZU9iamVjdHMoc3RhcnRLZWVwLCBkZWxldGlvbiwgaW5zZXJ0aW9uLCBlbmRLZWVwKSB7XG4gIC8vIEJlZm9yZSByZXR1cm5pbmcsIHdlIHRpZHkgdXAgdGhlIGxlYWRpbmcgYW5kIHRyYWlsaW5nIHdoaXRlc3BhY2Ugb2YgdGhlXG4gIC8vIGNoYW5nZSBvYmplY3RzIHRvIGVsaW1pbmF0ZSBjYXNlcyB3aGVyZSB0cmFpbGluZyB3aGl0ZXNwYWNlIGluIG9uZSBvYmplY3RcbiAgLy8gaXMgcmVwZWF0ZWQgYXMgbGVhZGluZyB3aGl0ZXNwYWNlIGluIHRoZSBuZXh0LlxuICAvLyBCZWxvdyBhcmUgZXhhbXBsZXMgb2YgdGhlIG91dGNvbWVzIHdlIHdhbnQgaGVyZSB0byBleHBsYWluIHRoZSBjb2RlLlxuICAvLyBJPWluc2VydCwgSz1rZWVwLCBEPWRlbGV0ZVxuICAvLyAxLiBkaWZmaW5nICdmb28gYmFyIGJheicgdnMgJ2ZvbyBiYXonXG4gIC8vICAgIFByaW9yIHRvIGNsZWFudXAsIHdlIGhhdmUgSzonZm9vICcgRDonIGJhciAnIEs6JyBiYXonXG4gIC8vICAgIEFmdGVyIGNsZWFudXAsIHdlIHdhbnQ6ICAgSzonZm9vICcgRDonYmFyICcgSzonYmF6J1xuICAvL1xuICAvLyAyLiBEaWZmaW5nICdmb28gYmFyIGJheicgdnMgJ2ZvbyBxdXggYmF6J1xuICAvLyAgICBQcmlvciB0byBjbGVhbnVwLCB3ZSBoYXZlIEs6J2ZvbyAnIEQ6JyBiYXIgJyBJOicgcXV4ICcgSzonIGJheidcbiAgLy8gICAgQWZ0ZXIgY2xlYW51cCwgd2Ugd2FudCBLOidmb28gJyBEOidiYXInIEk6J3F1eCcgSzonIGJheidcbiAgLy9cbiAgLy8gMy4gRGlmZmluZyAnZm9vXFxuYmFyIGJheicgdnMgJ2ZvbyBiYXonXG4gIC8vICAgIFByaW9yIHRvIGNsZWFudXAsIHdlIGhhdmUgSzonZm9vICcgRDonXFxuYmFyICcgSzonIGJheidcbiAgLy8gICAgQWZ0ZXIgY2xlYW51cCwgd2Ugd2FudCBLJ2ZvbycgRDonXFxuYmFyJyBLOicgYmF6J1xuICAvL1xuICAvLyA0LiBEaWZmaW5nICdmb28gYmF6JyB2cyAnZm9vXFxuYmFyIGJheidcbiAgLy8gICAgUHJpb3IgdG8gY2xlYW51cCwgd2UgaGF2ZSBLOidmb29cXG4nIEk6J1xcbmJhciAnIEs6JyBiYXonXG4gIC8vICAgIEFmdGVyIGNsZWFudXAsIHdlIGlkZWFsbHkgd2FudCBLJ2ZvbycgSTonXFxuYmFyJyBLOicgYmF6J1xuICAvLyAgICBidXQgZG9uJ3QgYWN0dWFsbHkgbWFuYWdlIHRoaXMgY3VycmVudGx5ICh0aGUgcHJlLWNsZWFudXAgY2hhbmdlXG4gIC8vICAgIG9iamVjdHMgZG9uJ3QgY29udGFpbiBlbm91Z2ggaW5mb3JtYXRpb24gdG8gbWFrZSBpdCBwb3NzaWJsZSkuXG4gIC8vXG4gIC8vIDUuIERpZmZpbmcgJ2ZvbyAgIGJhciBiYXonIHZzICdmb28gIGJheidcbiAgLy8gICAgUHJpb3IgdG8gY2xlYW51cCwgd2UgaGF2ZSBLOidmb28gICcgRDonICAgYmFyICcgSzonICBiYXonXG4gIC8vICAgIEFmdGVyIGNsZWFudXAsIHdlIHdhbnQgSzonZm9vICAnIEQ6JyBiYXIgJyBLOidiYXonXG4gIC8vXG4gIC8vIE91ciBoYW5kbGluZyBpcyB1bmF2b2lkYWJseSBpbXBlcmZlY3QgaW4gdGhlIGNhc2Ugd2hlcmUgdGhlcmUncyBhIHNpbmdsZVxuICAvLyBpbmRlbCBiZXR3ZWVuIGtlZXBzIGFuZCB0aGUgd2hpdGVzcGFjZSBoYXMgY2hhbmdlZC4gRm9yIGluc3RhbmNlLCBjb25zaWRlclxuICAvLyBkaWZmaW5nICdmb29cXHRiYXJcXG5iYXonIHZzICdmb28gYmF6Jy4gVW5sZXNzIHdlIGNyZWF0ZSBhbiBleHRyYSBjaGFuZ2VcbiAgLy8gb2JqZWN0IHRvIHJlcHJlc2VudCB0aGUgaW5zZXJ0aW9uIG9mIHRoZSBzcGFjZSBjaGFyYWN0ZXIgKHdoaWNoIGlzbid0IGV2ZW5cbiAgLy8gYSB0b2tlbiksIHdlIGhhdmUgbm8gd2F5IHRvIGF2b2lkIGxvc2luZyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgdGV4dHMnXG4gIC8vIG9yaWdpbmFsIHdoaXRlc3BhY2UgaW4gdGhlIHJlc3VsdCB3ZSByZXR1cm4uIFN0aWxsLCB3ZSBkbyBvdXIgYmVzdCB0b1xuICAvLyBvdXRwdXQgc29tZXRoaW5nIHRoYXQgd2lsbCBsb29rIHNlbnNpYmxlIGlmIHdlIGUuZy4gcHJpbnQgaXQgd2l0aFxuICAvLyBpbnNlcnRpb25zIGluIGdyZWVuIGFuZCBkZWxldGlvbnMgaW4gcmVkLlxuXG4gIC8vIEJldHdlZW4gdHdvIFwia2VlcFwiIGNoYW5nZSBvYmplY3RzIChvciBiZWZvcmUgdGhlIGZpcnN0IG9yIGFmdGVyIHRoZSBsYXN0XG4gIC8vIGNoYW5nZSBvYmplY3QpLCB3ZSBjYW4gaGF2ZSBlaXRoZXI6XG4gIC8vICogQSBcImRlbGV0ZVwiIGZvbGxvd2VkIGJ5IGFuIFwiaW5zZXJ0XCJcbiAgLy8gKiBKdXN0IGFuIFwiaW5zZXJ0XCJcbiAgLy8gKiBKdXN0IGEgXCJkZWxldGVcIlxuICAvLyBXZSBoYW5kbGUgdGhlIHRocmVlIGNhc2VzIHNlcGFyYXRlbHkuXG4gIGlmIChkZWxldGlvbiAmJiBpbnNlcnRpb24pIHtcbiAgICBjb25zdCBvbGRXc1ByZWZpeCA9IGxlYWRpbmdXcyhkZWxldGlvbi52YWx1ZSk7XG4gICAgY29uc3Qgb2xkV3NTdWZmaXggPSB0cmFpbGluZ1dzKGRlbGV0aW9uLnZhbHVlKTtcbiAgICBjb25zdCBuZXdXc1ByZWZpeCA9IGxlYWRpbmdXcyhpbnNlcnRpb24udmFsdWUpO1xuICAgIGNvbnN0IG5ld1dzU3VmZml4ID0gdHJhaWxpbmdXcyhpbnNlcnRpb24udmFsdWUpO1xuXG4gICAgaWYgKHN0YXJ0S2VlcCkge1xuICAgICAgY29uc3QgY29tbW9uV3NQcmVmaXggPSBsb25nZXN0Q29tbW9uUHJlZml4KG9sZFdzUHJlZml4LCBuZXdXc1ByZWZpeCk7XG4gICAgICBzdGFydEtlZXAudmFsdWUgPSByZXBsYWNlU3VmZml4KHN0YXJ0S2VlcC52YWx1ZSwgbmV3V3NQcmVmaXgsIGNvbW1vbldzUHJlZml4KTtcbiAgICAgIGRlbGV0aW9uLnZhbHVlID0gcmVtb3ZlUHJlZml4KGRlbGV0aW9uLnZhbHVlLCBjb21tb25Xc1ByZWZpeCk7XG4gICAgICBpbnNlcnRpb24udmFsdWUgPSByZW1vdmVQcmVmaXgoaW5zZXJ0aW9uLnZhbHVlLCBjb21tb25Xc1ByZWZpeCk7XG4gICAgfVxuICAgIGlmIChlbmRLZWVwKSB7XG4gICAgICBjb25zdCBjb21tb25Xc1N1ZmZpeCA9IGxvbmdlc3RDb21tb25TdWZmaXgob2xkV3NTdWZmaXgsIG5ld1dzU3VmZml4KTtcbiAgICAgIGVuZEtlZXAudmFsdWUgPSByZXBsYWNlUHJlZml4KGVuZEtlZXAudmFsdWUsIG5ld1dzU3VmZml4LCBjb21tb25Xc1N1ZmZpeCk7XG4gICAgICBkZWxldGlvbi52YWx1ZSA9IHJlbW92ZVN1ZmZpeChkZWxldGlvbi52YWx1ZSwgY29tbW9uV3NTdWZmaXgpO1xuICAgICAgaW5zZXJ0aW9uLnZhbHVlID0gcmVtb3ZlU3VmZml4KGluc2VydGlvbi52YWx1ZSwgY29tbW9uV3NTdWZmaXgpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpbnNlcnRpb24pIHtcbiAgICAvLyBUaGUgd2hpdGVzcGFjZXMgYWxsIHJlZmxlY3Qgd2hhdCB3YXMgaW4gdGhlIG5ldyB0ZXh0IHJhdGhlciB0aGFuXG4gICAgLy8gdGhlIG9sZCwgc28gd2UgZXNzZW50aWFsbHkgaGF2ZSBubyBpbmZvcm1hdGlvbiBhYm91dCB3aGl0ZXNwYWNlXG4gICAgLy8gaW5zZXJ0aW9uIG9yIGRlbGV0aW9uLiBXZSBqdXN0IHdhbnQgdG8gZGVkdXBlIHRoZSB3aGl0ZXNwYWNlLlxuICAgIC8vIFdlIGRvIHRoYXQgYnkgaGF2aW5nIGVhY2ggY2hhbmdlIG9iamVjdCBrZWVwIGl0cyB0cmFpbGluZ1xuICAgIC8vIHdoaXRlc3BhY2UgYW5kIGRlbGV0aW5nIGR1cGxpY2F0ZSBsZWFkaW5nIHdoaXRlc3BhY2Ugd2hlcmVcbiAgICAvLyBwcmVzZW50LlxuICAgIGlmIChzdGFydEtlZXApIHtcbiAgICAgIGNvbnN0IHdzID0gbGVhZGluZ1dzKGluc2VydGlvbi52YWx1ZSk7XG4gICAgICBpbnNlcnRpb24udmFsdWUgPSBpbnNlcnRpb24udmFsdWUuc3Vic3RyaW5nKHdzLmxlbmd0aCk7XG4gICAgfVxuICAgIGlmIChlbmRLZWVwKSB7XG4gICAgICBjb25zdCB3cyA9IGxlYWRpbmdXcyhlbmRLZWVwLnZhbHVlKTtcbiAgICAgIGVuZEtlZXAudmFsdWUgPSBlbmRLZWVwLnZhbHVlLnN1YnN0cmluZyh3cy5sZW5ndGgpO1xuICAgIH1cbiAgLy8gb3RoZXJ3aXNlIHdlJ3ZlIGdvdCBhIGRlbGV0aW9uIGFuZCBubyBpbnNlcnRpb25cbiAgfSBlbHNlIGlmIChzdGFydEtlZXAgJiYgZW5kS2VlcCkge1xuICAgIGNvbnN0IG5ld1dzRnVsbCA9IGxlYWRpbmdXcyhlbmRLZWVwLnZhbHVlKSxcbiAgICAgICAgZGVsV3NTdGFydCA9IGxlYWRpbmdXcyhkZWxldGlvbi52YWx1ZSksXG4gICAgICAgIGRlbFdzRW5kID0gdHJhaWxpbmdXcyhkZWxldGlvbi52YWx1ZSk7XG5cbiAgICAvLyBBbnkgd2hpdGVzcGFjZSB0aGF0IGNvbWVzIHN0cmFpZ2h0IGFmdGVyIHN0YXJ0S2VlcCBpbiBib3RoIHRoZSBvbGQgYW5kXG4gICAgLy8gbmV3IHRleHRzLCBhc3NpZ24gdG8gc3RhcnRLZWVwIGFuZCByZW1vdmUgZnJvbSB0aGUgZGVsZXRpb24uXG4gICAgY29uc3QgbmV3V3NTdGFydCA9IGxvbmdlc3RDb21tb25QcmVmaXgobmV3V3NGdWxsLCBkZWxXc1N0YXJ0KTtcbiAgICBkZWxldGlvbi52YWx1ZSA9IHJlbW92ZVByZWZpeChkZWxldGlvbi52YWx1ZSwgbmV3V3NTdGFydCk7XG5cbiAgICAvLyBBbnkgd2hpdGVzcGFjZSB0aGF0IGNvbWVzIHN0cmFpZ2h0IGJlZm9yZSBlbmRLZWVwIGluIGJvdGggdGhlIG9sZCBhbmRcbiAgICAvLyBuZXcgdGV4dHMsIGFuZCBoYXNuJ3QgYWxyZWFkeSBiZWVuIGFzc2lnbmVkIHRvIHN0YXJ0S2VlcCwgYXNzaWduIHRvXG4gICAgLy8gZW5kS2VlcCBhbmQgcmVtb3ZlIGZyb20gdGhlIGRlbGV0aW9uLlxuICAgIGNvbnN0IG5ld1dzRW5kID0gbG9uZ2VzdENvbW1vblN1ZmZpeChcbiAgICAgIHJlbW92ZVByZWZpeChuZXdXc0Z1bGwsIG5ld1dzU3RhcnQpLFxuICAgICAgZGVsV3NFbmRcbiAgICApO1xuICAgIGRlbGV0aW9uLnZhbHVlID0gcmVtb3ZlU3VmZml4KGRlbGV0aW9uLnZhbHVlLCBuZXdXc0VuZCk7XG4gICAgZW5kS2VlcC52YWx1ZSA9IHJlcGxhY2VQcmVmaXgoZW5kS2VlcC52YWx1ZSwgbmV3V3NGdWxsLCBuZXdXc0VuZCk7XG5cbiAgICAvLyBJZiB0aGVyZSdzIGFueSB3aGl0ZXNwYWNlIGZyb20gdGhlIG5ldyB0ZXh0IHRoYXQgSEFTTidUIGFscmVhZHkgYmVlblxuICAgIC8vIGFzc2lnbmVkLCBhc3NpZ24gaXQgdG8gdGhlIHN0YXJ0OlxuICAgIHN0YXJ0S2VlcC52YWx1ZSA9IHJlcGxhY2VTdWZmaXgoXG4gICAgICBzdGFydEtlZXAudmFsdWUsXG4gICAgICBuZXdXc0Z1bGwsXG4gICAgICBuZXdXc0Z1bGwuc2xpY2UoMCwgbmV3V3NGdWxsLmxlbmd0aCAtIG5ld1dzRW5kLmxlbmd0aClcbiAgICApO1xuICB9IGVsc2UgaWYgKGVuZEtlZXApIHtcbiAgICAvLyBXZSBhcmUgYXQgdGhlIHN0YXJ0IG9mIHRoZSB0ZXh0LiBQcmVzZXJ2ZSBhbGwgdGhlIHdoaXRlc3BhY2Ugb25cbiAgICAvLyBlbmRLZWVwLCBhbmQganVzdCByZW1vdmUgd2hpdGVzcGFjZSBmcm9tIHRoZSBlbmQgb2YgZGVsZXRpb24gdG8gdGhlXG4gICAgLy8gZXh0ZW50IHRoYXQgaXQgb3ZlcmxhcHMgd2l0aCB0aGUgc3RhcnQgb2YgZW5kS2VlcC5cbiAgICBjb25zdCBlbmRLZWVwV3NQcmVmaXggPSBsZWFkaW5nV3MoZW5kS2VlcC52YWx1ZSk7XG4gICAgY29uc3QgZGVsZXRpb25Xc1N1ZmZpeCA9IHRyYWlsaW5nV3MoZGVsZXRpb24udmFsdWUpO1xuICAgIGNvbnN0IG92ZXJsYXAgPSBtYXhpbXVtT3ZlcmxhcChkZWxldGlvbldzU3VmZml4LCBlbmRLZWVwV3NQcmVmaXgpO1xuICAgIGRlbGV0aW9uLnZhbHVlID0gcmVtb3ZlU3VmZml4KGRlbGV0aW9uLnZhbHVlLCBvdmVybGFwKTtcbiAgfSBlbHNlIGlmIChzdGFydEtlZXApIHtcbiAgICAvLyBXZSBhcmUgYXQgdGhlIEVORCBvZiB0aGUgdGV4dC4gUHJlc2VydmUgYWxsIHRoZSB3aGl0ZXNwYWNlIG9uXG4gICAgLy8gc3RhcnRLZWVwLCBhbmQganVzdCByZW1vdmUgd2hpdGVzcGFjZSBmcm9tIHRoZSBzdGFydCBvZiBkZWxldGlvbiB0b1xuICAgIC8vIHRoZSBleHRlbnQgdGhhdCBpdCBvdmVybGFwcyB3aXRoIHRoZSBlbmQgb2Ygc3RhcnRLZWVwLlxuICAgIGNvbnN0IHN0YXJ0S2VlcFdzU3VmZml4ID0gdHJhaWxpbmdXcyhzdGFydEtlZXAudmFsdWUpO1xuICAgIGNvbnN0IGRlbGV0aW9uV3NQcmVmaXggPSBsZWFkaW5nV3MoZGVsZXRpb24udmFsdWUpO1xuICAgIGNvbnN0IG92ZXJsYXAgPSBtYXhpbXVtT3ZlcmxhcChzdGFydEtlZXBXc1N1ZmZpeCwgZGVsZXRpb25Xc1ByZWZpeCk7XG4gICAgZGVsZXRpb24udmFsdWUgPSByZW1vdmVQcmVmaXgoZGVsZXRpb24udmFsdWUsIG92ZXJsYXApO1xuICB9XG59XG5cblxuZXhwb3J0IGNvbnN0IHdvcmRXaXRoU3BhY2VEaWZmID0gbmV3IERpZmYoKTtcbndvcmRXaXRoU3BhY2VEaWZmLnRva2VuaXplID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgLy8gU2xpZ2h0bHkgZGlmZmVyZW50IHRvIHRoZSB0b2tlbml6ZUluY2x1ZGluZ1doaXRlc3BhY2UgcmVnZXggdXNlZCBhYm92ZSBpblxuICAvLyB0aGF0IHRoaXMgb25lIHRyZWF0cyBlYWNoIGluZGl2aWR1YWwgbmV3bGluZSBhcyBhIGRpc3RpbmN0IHRva2VucywgcmF0aGVyXG4gIC8vIHRoYW4gbWVyZ2luZyB0aGVtIGludG8gb3RoZXIgc3Vycm91bmRpbmcgd2hpdGVzcGFjZS4gVGhpcyB3YXMgcmVxdWVzdGVkXG4gIC8vIGluIGh0dHBzOi8vZ2l0aHViLmNvbS9rcGRlY2tlci9qc2RpZmYvaXNzdWVzLzE4MCAmXG4gIC8vICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9rcGRlY2tlci9qc2RpZmYvaXNzdWVzLzIxMVxuICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYChcXFxccj9cXFxcbil8WyR7ZXh0ZW5kZWRXb3JkQ2hhcnN9XSt8W15cXFxcU1xcXFxuXFxcXHJdK3xbXiR7ZXh0ZW5kZWRXb3JkQ2hhcnN9XWAsICd1ZycpO1xuICByZXR1cm4gdmFsdWUubWF0Y2gocmVnZXgpIHx8IFtdO1xufTtcbmV4cG9ydCBmdW5jdGlvbiBkaWZmV29yZHNXaXRoU3BhY2Uob2xkU3RyLCBuZXdTdHIsIG9wdGlvbnMpIHtcbiAgcmV0dXJuIHdvcmRXaXRoU3BhY2VEaWZmLmRpZmYob2xkU3RyLCBuZXdTdHIsIG9wdGlvbnMpO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQUFBLElBQUFBLEtBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLE9BQUEsR0FBQUQsT0FBQTtBQUEySyxTQUFBRCx1QkFBQUcsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLGdCQUFBQSxDQUFBO0FBRTNLO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQU1FLGlCQUFpQixHQUFHLCtHQUErRzs7QUFFekk7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQU1DLDJCQUEyQixHQUFHLElBQUlDLE1BQU0sS0FBQUMsTUFBQSxDQUFLSCxpQkFBaUIsZ0JBQUFHLE1BQUEsQ0FBYUgsaUJBQWlCLFFBQUssSUFBSSxDQUFDO0FBRXJHLElBQU1JLFFBQVEsR0FBQUMsT0FBQSxDQUFBRCxRQUFBLEdBQUcsSUFBSUUsZ0JBQUksQ0FBQyxDQUFDO0FBQ2xDRixRQUFRLENBQUNHLE1BQU0sR0FBRyxVQUFTQyxJQUFJLEVBQUVDLEtBQUssRUFBRUMsT0FBTyxF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