You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
394 lines
36 KiB
394 lines
36 KiB
|
2 months ago
|
/*istanbul ignore start*/
|
||
|
|
"use strict";
|
||
|
|
|
||
|
|
Object.defineProperty(exports, "__esModule", {
|
||
|
|
value: true
|
||
|
|
});
|
||
|
|
exports.applyPatch = applyPatch;
|
||
|
|
exports.applyPatches = applyPatches;
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
var
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_string = require("../util/string")
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
;
|
||
|
|
var
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_lineEndings = require("./line-endings")
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
;
|
||
|
|
var
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_parse = require("./parse")
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
;
|
||
|
|
var
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_distanceIterator = _interopRequireDefault(require("../util/distance-iterator"))
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
;
|
||
|
|
/*istanbul ignore start*/ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
function applyPatch(source, uniDiff) {
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
var
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
||
|
|
if (typeof uniDiff === 'string') {
|
||
|
|
uniDiff =
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_parse
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
parsePatch)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(uniDiff);
|
||
|
|
}
|
||
|
|
if (Array.isArray(uniDiff)) {
|
||
|
|
if (uniDiff.length > 1) {
|
||
|
|
throw new Error('applyPatch only works with a single input.');
|
||
|
|
}
|
||
|
|
uniDiff = uniDiff[0];
|
||
|
|
}
|
||
|
|
if (options.autoConvertLineEndings || options.autoConvertLineEndings == null) {
|
||
|
|
if (
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_string
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
hasOnlyWinLineEndings)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(source) &&
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_lineEndings
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
isUnix)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(uniDiff)) {
|
||
|
|
uniDiff =
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_lineEndings
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
unixToWin)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(uniDiff);
|
||
|
|
} else if (
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_string
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
hasOnlyUnixLineEndings)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(source) &&
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_lineEndings
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
isWin)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(uniDiff)) {
|
||
|
|
uniDiff =
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_lineEndings
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
winToUnix)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(uniDiff);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Apply the diff to the input
|
||
|
|
var lines = source.split('\n'),
|
||
|
|
hunks = uniDiff.hunks,
|
||
|
|
compareLine = options.compareLine || function (lineNumber, line, operation, patchContent)
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
{
|
||
|
|
return (
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
line === patchContent
|
||
|
|
);
|
||
|
|
},
|
||
|
|
fuzzFactor = options.fuzzFactor || 0,
|
||
|
|
minLine = 0;
|
||
|
|
if (fuzzFactor < 0 || !Number.isInteger(fuzzFactor)) {
|
||
|
|
throw new Error('fuzzFactor must be a non-negative integer');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Special case for empty patch.
|
||
|
|
if (!hunks.length) {
|
||
|
|
return source;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Before anything else, handle EOFNL insertion/removal. If the patch tells us to make a change
|
||
|
|
// to the EOFNL that is redundant/impossible - i.e. to remove a newline that's not there, or add a
|
||
|
|
// newline that already exists - then we either return false and fail to apply the patch (if
|
||
|
|
// fuzzFactor is 0) or simply ignore the problem and do nothing (if fuzzFactor is >0).
|
||
|
|
// If we do need to remove/add a newline at EOF, this will always be in the final hunk:
|
||
|
|
var prevLine = '',
|
||
|
|
removeEOFNL = false,
|
||
|
|
addEOFNL = false;
|
||
|
|
for (var i = 0; i < hunks[hunks.length - 1].lines.length; i++) {
|
||
|
|
var line = hunks[hunks.length - 1].lines[i];
|
||
|
|
if (line[0] == '\\') {
|
||
|
|
if (prevLine[0] == '+') {
|
||
|
|
removeEOFNL = true;
|
||
|
|
} else if (prevLine[0] == '-') {
|
||
|
|
addEOFNL = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
prevLine = line;
|
||
|
|
}
|
||
|
|
if (removeEOFNL) {
|
||
|
|
if (addEOFNL) {
|
||
|
|
// This means the final line gets changed but doesn't have a trailing newline in either the
|
||
|
|
// original or patched version. In that case, we do nothing if fuzzFactor > 0, and if
|
||
|
|
// fuzzFactor is 0, we simply validate that the source file has no trailing newline.
|
||
|
|
if (!fuzzFactor && lines[lines.length - 1] == '') {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
} else if (lines[lines.length - 1] == '') {
|
||
|
|
lines.pop();
|
||
|
|
} else if (!fuzzFactor) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
} else if (addEOFNL) {
|
||
|
|
if (lines[lines.length - 1] != '') {
|
||
|
|
lines.push('');
|
||
|
|
} else if (!fuzzFactor) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Checks if the hunk can be made to fit at the provided location with at most `maxErrors`
|
||
|
|
* insertions, substitutions, or deletions, while ensuring also that:
|
||
|
|
* - lines deleted in the hunk match exactly, and
|
||
|
|
* - wherever an insertion operation or block of insertion operations appears in the hunk, the
|
||
|
|
* immediately preceding and following lines of context match exactly
|
||
|
|
*
|
||
|
|
* `toPos` should be set such that lines[toPos] is meant to match hunkLines[0].
|
||
|
|
*
|
||
|
|
* If the hunk can be applied, returns an object with properties `oldLineLastI` and
|
||
|
|
* `replacementLines`. Otherwise, returns null.
|
||
|
|
*/
|
||
|
|
function applyHunk(hunkLines, toPos, maxErrors) {
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
var
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
hunkLinesI = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
var
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
lastContextLineMatched = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
var
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
patchedLines = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : [];
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
var
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
patchedLinesLength = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
|
||
|
|
var nConsecutiveOldContextLines = 0;
|
||
|
|
var nextContextLineMustMatch = false;
|
||
|
|
for (; hunkLinesI < hunkLines.length; hunkLinesI++) {
|
||
|
|
var hunkLine = hunkLines[hunkLinesI],
|
||
|
|
operation = hunkLine.length > 0 ? hunkLine[0] : ' ',
|
||
|
|
content = hunkLine.length > 0 ? hunkLine.substr(1) : hunkLine;
|
||
|
|
if (operation === '-') {
|
||
|
|
if (compareLine(toPos + 1, lines[toPos], operation, content)) {
|
||
|
|
toPos++;
|
||
|
|
nConsecutiveOldContextLines = 0;
|
||
|
|
} else {
|
||
|
|
if (!maxErrors || lines[toPos] == null) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
patchedLines[patchedLinesLength] = lines[toPos];
|
||
|
|
return applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI, false, patchedLines, patchedLinesLength + 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (operation === '+') {
|
||
|
|
if (!lastContextLineMatched) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
patchedLines[patchedLinesLength] = content;
|
||
|
|
patchedLinesLength++;
|
||
|
|
nConsecutiveOldContextLines = 0;
|
||
|
|
nextContextLineMustMatch = true;
|
||
|
|
}
|
||
|
|
if (operation === ' ') {
|
||
|
|
nConsecutiveOldContextLines++;
|
||
|
|
patchedLines[patchedLinesLength] = lines[toPos];
|
||
|
|
if (compareLine(toPos + 1, lines[toPos], operation, content)) {
|
||
|
|
patchedLinesLength++;
|
||
|
|
lastContextLineMatched = true;
|
||
|
|
nextContextLineMustMatch = false;
|
||
|
|
toPos++;
|
||
|
|
} else {
|
||
|
|
if (nextContextLineMustMatch || !maxErrors) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Consider 3 possibilities in sequence:
|
||
|
|
// 1. lines contains a *substitution* not included in the patch context, or
|
||
|
|
// 2. lines contains an *insertion* not included in the patch context, or
|
||
|
|
// 3. lines contains a *deletion* not included in the patch context
|
||
|
|
// The first two options are of course only possible if the line from lines is non-null -
|
||
|
|
// i.e. only option 3 is possible if we've overrun the end of the old file.
|
||
|
|
return lines[toPos] && (applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI + 1, false, patchedLines, patchedLinesLength + 1) || applyHunk(hunkLines, toPos + 1, maxErrors - 1, hunkLinesI, false, patchedLines, patchedLinesLength + 1)) || applyHunk(hunkLines, toPos, maxErrors - 1, hunkLinesI + 1, false, patchedLines, patchedLinesLength);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Before returning, trim any unmodified context lines off the end of patchedLines and reduce
|
||
|
|
// toPos (and thus oldLineLastI) accordingly. This allows later hunks to be applied to a region
|
||
|
|
// that starts in this hunk's trailing context.
|
||
|
|
patchedLinesLength -= nConsecutiveOldContextLines;
|
||
|
|
toPos -= nConsecutiveOldContextLines;
|
||
|
|
patchedLines.length = patchedLinesLength;
|
||
|
|
return {
|
||
|
|
patchedLines: patchedLines,
|
||
|
|
oldLineLastI: toPos - 1
|
||
|
|
};
|
||
|
|
}
|
||
|
|
var resultLines = [];
|
||
|
|
|
||
|
|
// Search best fit offsets for each hunk based on the previous ones
|
||
|
|
var prevHunkOffset = 0;
|
||
|
|
for (var _i = 0; _i < hunks.length; _i++) {
|
||
|
|
var hunk = hunks[_i];
|
||
|
|
var hunkResult =
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
void 0
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
;
|
||
|
|
var maxLine = lines.length - hunk.oldLines + fuzzFactor;
|
||
|
|
var toPos =
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
void 0
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
;
|
||
|
|
for (var maxErrors = 0; maxErrors <= fuzzFactor; maxErrors++) {
|
||
|
|
toPos = hunk.oldStart + prevHunkOffset - 1;
|
||
|
|
var iterator =
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_distanceIterator
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
[
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
"default"
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
])(toPos, minLine, maxLine);
|
||
|
|
for (; toPos !== undefined; toPos = iterator()) {
|
||
|
|
hunkResult = applyHunk(hunk.lines, toPos, maxErrors);
|
||
|
|
if (hunkResult) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (hunkResult) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!hunkResult) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Copy everything from the end of where we applied the last hunk to the start of this hunk
|
||
|
|
for (var _i2 = minLine; _i2 < toPos; _i2++) {
|
||
|
|
resultLines.push(lines[_i2]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add the lines produced by applying the hunk:
|
||
|
|
for (var _i3 = 0; _i3 < hunkResult.patchedLines.length; _i3++) {
|
||
|
|
var _line = hunkResult.patchedLines[_i3];
|
||
|
|
resultLines.push(_line);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set lower text limit to end of the current hunk, so next ones don't try
|
||
|
|
// to fit over already patched text
|
||
|
|
minLine = hunkResult.oldLineLastI + 1;
|
||
|
|
|
||
|
|
// Note the offset between where the patch said the hunk should've applied and where we
|
||
|
|
// applied it, so we can adjust future hunks accordingly:
|
||
|
|
prevHunkOffset = toPos + 1 - hunk.oldStart;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Copy over the rest of the lines from the old text
|
||
|
|
for (var _i4 = minLine; _i4 < lines.length; _i4++) {
|
||
|
|
resultLines.push(lines[_i4]);
|
||
|
|
}
|
||
|
|
return resultLines.join('\n');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Wrapper that supports multiple file patches via callbacks.
|
||
|
|
function applyPatches(uniDiff, options) {
|
||
|
|
if (typeof uniDiff === 'string') {
|
||
|
|
uniDiff =
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
(0,
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
_parse
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
.
|
||
|
|
/*istanbul ignore start*/
|
||
|
|
parsePatch)
|
||
|
|
/*istanbul ignore end*/
|
||
|
|
(uniDiff);
|
||
|
|
}
|
||
|
|
var currentIndex = 0;
|
||
|
|
function processIndex() {
|
||
|
|
var index = uniDiff[currentIndex++];
|
||
|
|
if (!index) {
|
||
|
|
return options.complete();
|
||
|
|
}
|
||
|
|
options.loadFile(index, function (err, data) {
|
||
|
|
if (err) {
|
||
|
|
return options.complete(err);
|
||
|
|
}
|
||
|
|
var updatedContent = applyPatch(data, index, options);
|
||
|
|
options.patched(index, updatedContent, function (err) {
|
||
|
|
if (err) {
|
||
|
|
return options.complete(err);
|
||
|
|
}
|
||
|
|
processIndex();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
processIndex();
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfc3RyaW5nIiwicmVxdWlyZSIsIl9saW5lRW5kaW5ncyIsIl9wYXJzZSIsIl9kaXN0YW5jZUl0ZXJhdG9yIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIm9iaiIsIl9fZXNNb2R1bGUiLCJhcHBseVBhdGNoIiwic291cmNlIiwidW5pRGlmZiIsIm9wdGlvbnMiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJ1bmRlZmluZWQiLCJwYXJzZVBhdGNoIiwiQXJyYXkiLCJpc0FycmF5IiwiRXJyb3IiLCJhdXRvQ29udmVydExpbmVFbmRpbmdzIiwiaGFzT25seVdpbkxpbmVFbmRpbmdzIiwiaXNVbml4IiwidW5peFRvV2luIiwiaGFzT25seVVuaXhMaW5lRW5kaW5ncyIsImlzV2luIiwid2luVG9Vbml4IiwibGluZXMiLCJzcGxpdCIsImh1bmtzIiwiY29tcGFyZUxpbmUiLCJsaW5lTnVtYmVyIiwibGluZSIsIm9wZXJhdGlvbiIsInBhdGNoQ29udGVudCIsImZ1enpGYWN0b3IiLCJtaW5MaW5lIiwiTnVtYmVyIiwiaXNJbnRlZ2VyIiwicHJldkxpbmUiLCJyZW1vdmVFT0ZOTCIsImFkZEVPRk5MIiwiaSIsInBvcCIsInB1c2giLCJhcHBseUh1bmsiLCJodW5rTGluZXMiLCJ0b1BvcyIsIm1heEVycm9ycyIsImh1bmtMaW5lc0kiLCJsYXN0Q29udGV4dExpbmVNYXRjaGVkIiwicGF0Y2hlZExpbmVzIiwicGF0Y2hlZExpbmVzTGVuZ3RoIiwibkNvbnNlY3V0aXZlT2xkQ29udGV4dExpbmVzIiwibmV4dENvbnRleHRMaW5lTXVzdE1hdGNoIiwiaHVua0xpbmUiLCJjb250ZW50Iiwic3Vic3RyIiwib2xkTGluZUxhc3RJIiwicmVzdWx0TGluZXMiLCJwcmV2SHVua09mZnNldCIsImh1bmsiLCJodW5rUmVzdWx0IiwibWF4TGluZSIsIm9sZExpbmVzIiwib2xkU3RhcnQiLCJpdGVyYXRvciIsImRpc3RhbmNlSXRlcmF0b3IiLCJqb2luIiwiYXBwbHlQYXRjaGVzIiwiY3VycmVudEluZGV4IiwicHJvY2Vzc0luZGV4IiwiaW5kZXgiLCJjb21wbGV0ZSIsImxvYWRGaWxlIiwiZXJyIiwiZGF0YSIsInVwZGF0ZWRDb250ZW50IiwicGF0Y2hlZCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wYXRjaC9hcHBseS5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge2hhc09ubHlXaW5MaW5lRW5kaW5ncywgaGFzT25seVVuaXhMaW5lRW5kaW5nc30gZnJvbSAnLi4vdXRpbC9zdHJpbmcnO1xuaW1wb3J0IHtpc1dpbiwgaXNVbml4LCB1bml4VG9XaW4sIHdpblRvVW5peH0gZnJvbSAnLi9saW5lLWVuZGluZ3MnO1xuaW1wb3J0IHtwYXJzZVBhdGNofSBmcm9tICcuL3BhcnNlJztcbmltcG9ydCBkaXN0YW5jZUl0ZXJhdG9yIGZyb20gJy4uL3V0aWwvZGlzdGFuY2UtaXRlcmF0b3InO1xuXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlQYXRjaChzb3VyY2UsIHVuaURpZmYsIG9wdGlvbnMgPSB7fSkge1xuICBpZiAodHlwZW9mIHVuaURpZmYgPT09ICdzdHJpbmcnKSB7XG4gICAgdW5pRGlmZiA9IHBhcnNlUGF0Y2godW5pRGlmZik7XG4gIH1cblxuICBpZiAoQXJyYXkuaXNBcnJheSh1bmlEaWZmKSkge1xuICAgIGlmICh1bmlEaWZmLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignYXBwbHlQYXRjaCBvbmx5IHdvcmtzIHdpdGggYSBzaW5nbGUgaW5wdXQuJyk7XG4gICAgfVxuXG4gICAgdW5pRGlmZiA9IHVuaURpZmZbMF07XG4gIH1cblxuICBpZiAob3B0aW9ucy5hdXRvQ29udmVydExpbmVFbmRpbmdzIHx8IG9wdGlvbnMuYXV0b0NvbnZlcnRMaW5lRW5kaW5ncyA9PSBudWxsKSB7XG4gICAgaWYgKGhhc09ubHlXaW5MaW5lRW5kaW5ncyhzb3VyY2UpICYmIGlzVW5peCh1bmlEaWZmKSkge1xuICAgICAgdW5pRGlmZiA9IHVuaXhUb1dpbih1bmlEaWZmKTtcbiAgICB9IGVsc2UgaWYgKGhhc09ubHlVbml4TGluZUVuZGluZ3Moc291cmNlKSAmJiBpc1dpbih1bmlEaWZmKSkge1xuICAgICAgdW5pRGlmZiA9IHdpblRvVW5peCh1bmlEaWZmKTtcbiAgICB9XG4gIH1cblxuICAvLyBBcHBseSB0aGUgZGlmZiB0byB0aGUgaW5wdXRcbiAgbGV0IGxpbmVzID0gc291cmNlLnNwbGl0KCdcXG4nKSxcbiAgICAgIGh1bmtzID0gdW5pRGlmZi5odW5rcyxcblxuICAgICAgY29tcGFyZUxpbmUgPSBvcHRpb25zLmNvbXBhcmVMaW5lIHx8ICgobGluZU51bWJlciwgbGluZSwgb3BlcmF0aW9uLCBwYXRjaENvbnRlbnQpID0+IGxpbmUgPT09IHBhdGNoQ29udGVudCksXG4gICAgICBmdXp6RmFjdG9yID0gb3B0aW9ucy5mdXp6RmFjdG9yIHx8IDAsXG4gICAgICBtaW5MaW5lID0gMDtcblxuICBpZiAoZnV6ekZhY3RvciA8IDAgfHwgIU51bWJlci5pc0ludGVnZXIoZnV6ekZhY3RvcikpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2Z1enpGYWN0b3IgbXVzdCBiZSBhIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyJyk7XG4gIH1cblxuICAvLyBTcGVjaWFsIGNhc2UgZm9yIGVtcHR5IHBhdGNoLlxuICBpZiAoIWh1bmtzLmxlbmd0aCkge1xuICAgIHJldHVybiBzb3VyY2U7XG4gIH1cblxuICAvLyBCZWZvcmUgYW55dGhpbmcgZWxzZSwgaGFuZGxlIEVPRk5MIGluc2VydGlvbi9yZW1vdmFsLiBJZiB0aGUgcGF0Y2ggdGVsbHMgdXMgdG8gbWFrZSBhIGNoYW5nZVxuICAvLyB0byB0aGUgRU9GTkwgdGhhdCBpcyByZWR1bmRhbnQvaW1wb3NzaWJsZSAtIGkuZS4gdG8gcmVtb3ZlIGEgbmV3bGluZSB0aGF0J3Mgbm90IHRoZXJlLCBvciBhZGQgYVxuICAvLyBuZXdsaW5lIHRoYXQgYWxyZWFkeSBleGlzdHMgLSB0aGVuIHdlIGVpdGhlciByZXR1cm4gZmFsc2UgYW5kIGZhaWwgdG8gYXBwbHkgdGhlIHBhdGNoIChpZlxuICAvLyBmdXp6RmFjdG9yIGlzIDApIG9yIHNpbXBseSBpZ25vcmUgdGhlIHByb2JsZW0gYW5kIGRvIG5vdGhpbmcgKGlmIGZ1enpGYWN0b3IgaXMgPjApLlxuICAvLyBJZiB3ZSBkbyBuZWVkIHRvIHJlbW92ZS9hZGQgYSBuZXdsaW5lIGF0IEVPRiwgdGhpcyB3aWxsIGFsd2F5cyBiZSBpbiB0aGUgZmluYWwgaHVuazpcbiAgbGV0IHByZXZMaW5lID0gJycsXG4gICAgICByZW1vdmVFT0ZOTCA9IGZhbHNlLFxuICAgICAgYWRkRU9GTkwgPSBmYWxzZTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBodW5rc1todW5rcy5sZW5ndGggLSAxXS5
|