@circuitly/diff
Version:
A javascript text diff implementation.
281 lines (274 loc) • 40.8 kB
JavaScript
;
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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