@psync/patch-package 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +19 -0
- package/README.md +422 -0
- package/dist/PackageDetails.js +126 -0
- package/dist/applyPatches.js +414 -0
- package/dist/assertNever.js +7 -0
- package/dist/coerceSemVer.js +11 -0
- package/dist/createIssue.js +115 -0
- package/dist/detectPackageManager.js +98 -0
- package/dist/filterFiles.js +16 -0
- package/dist/getAppRootPath.js +22 -0
- package/dist/getPackageResolution.js +121 -0
- package/dist/getPackageVersion.js +8 -0
- package/dist/hash.js +26 -0
- package/dist/index.js +208 -0
- package/dist/makePatch.js +450 -0
- package/dist/makeRegExp.js +28 -0
- package/dist/packageIsDevDependency.js +14 -0
- package/dist/parseBunLockfile.js +16 -0
- package/dist/patch/apply.js +251 -0
- package/dist/patch/parse.js +335 -0
- package/dist/patch/read.js +48 -0
- package/dist/patch/reverse.js +97 -0
- package/dist/patchFs.js +55 -0
- package/dist/path.js +17 -0
- package/dist/rebase.js +147 -0
- package/dist/resolveRelativeFileDependencies.js +20 -0
- package/dist/spawnSafe.js +28 -0
- package/dist/stateFile.js +71 -0
- package/index.js +3 -0
- package/package.json +102 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.executeEffects = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const assertNever_1 = require("../assertNever");
|
|
10
|
+
const executeEffects = (effects, { dryRun, bestEffort, errors, cwd, }) => {
|
|
11
|
+
const inCwd = (path) => (cwd ? (0, path_1.join)(cwd, path) : path);
|
|
12
|
+
const humanReadable = (path) => (0, path_1.relative)(process.cwd(), inCwd(path));
|
|
13
|
+
effects.forEach((eff) => {
|
|
14
|
+
switch (eff.type) {
|
|
15
|
+
case "file deletion":
|
|
16
|
+
if (dryRun) {
|
|
17
|
+
if (!fs_extra_1.default.existsSync(inCwd(eff.path))) {
|
|
18
|
+
throw new Error("Trying to delete file that doesn't exist: " +
|
|
19
|
+
humanReadable(eff.path));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// TODO: integrity checks
|
|
24
|
+
try {
|
|
25
|
+
fs_extra_1.default.unlinkSync(inCwd(eff.path));
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
if (bestEffort) {
|
|
29
|
+
errors?.push(`Failed to delete file ${eff.path}`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
case "rename":
|
|
38
|
+
if (dryRun) {
|
|
39
|
+
// TODO: see what patch files look like if moving to exising path
|
|
40
|
+
if (!fs_extra_1.default.existsSync(inCwd(eff.fromPath))) {
|
|
41
|
+
throw new Error("Trying to move file that doesn't exist: " +
|
|
42
|
+
humanReadable(eff.fromPath));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
try {
|
|
47
|
+
fs_extra_1.default.moveSync(inCwd(eff.fromPath), inCwd(eff.toPath));
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
if (bestEffort) {
|
|
51
|
+
errors?.push(`Failed to rename file ${eff.fromPath} to ${eff.toPath}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case "file creation":
|
|
60
|
+
if (dryRun) {
|
|
61
|
+
if (fs_extra_1.default.existsSync(inCwd(eff.path))) {
|
|
62
|
+
throw new Error("Trying to create file that already exists: " +
|
|
63
|
+
humanReadable(eff.path));
|
|
64
|
+
}
|
|
65
|
+
// todo: check file contents matches
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const fileContents = eff.hunk
|
|
69
|
+
? eff.hunk.parts[0].lines.join("\n") +
|
|
70
|
+
(eff.hunk.parts[0].noNewlineAtEndOfFile ? "" : "\n")
|
|
71
|
+
: "";
|
|
72
|
+
const path = inCwd(eff.path);
|
|
73
|
+
try {
|
|
74
|
+
fs_extra_1.default.ensureDirSync((0, path_1.dirname)(path));
|
|
75
|
+
fs_extra_1.default.writeFileSync(path, fileContents, { mode: eff.mode });
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
if (bestEffort) {
|
|
79
|
+
errors?.push(`Failed to create new file ${eff.path}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case "patch":
|
|
88
|
+
applyPatch(eff, { dryRun, cwd, bestEffort, errors });
|
|
89
|
+
break;
|
|
90
|
+
case "mode change":
|
|
91
|
+
const currentMode = fs_extra_1.default.statSync(inCwd(eff.path)).mode;
|
|
92
|
+
if (((isExecutable(eff.newMode) && isExecutable(currentMode)) ||
|
|
93
|
+
(!isExecutable(eff.newMode) && !isExecutable(currentMode))) &&
|
|
94
|
+
dryRun) {
|
|
95
|
+
console.log(`Mode change is not required for file ${humanReadable(eff.path)}`);
|
|
96
|
+
}
|
|
97
|
+
fs_extra_1.default.chmodSync(inCwd(eff.path), eff.newMode);
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
(0, assertNever_1.assertNever)(eff);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
exports.executeEffects = executeEffects;
|
|
105
|
+
function isExecutable(fileMode) {
|
|
106
|
+
// tslint:disable-next-line:no-bitwise
|
|
107
|
+
return (fileMode & 64) > 0;
|
|
108
|
+
}
|
|
109
|
+
const trimRight = (s) => s.replace(/\s+$/, "");
|
|
110
|
+
function linesAreEqual(a, b) {
|
|
111
|
+
return trimRight(a) === trimRight(b);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* How does noNewLineAtEndOfFile work?
|
|
115
|
+
*
|
|
116
|
+
* if you remove the newline from a file that had one without editing other bits:
|
|
117
|
+
*
|
|
118
|
+
* it creates an insertion/removal pair where the insertion has \ No new line at end of file
|
|
119
|
+
*
|
|
120
|
+
* if you edit a file that didn't have a new line and don't add one:
|
|
121
|
+
*
|
|
122
|
+
* both insertion and deletion have \ No new line at end of file
|
|
123
|
+
*
|
|
124
|
+
* if you edit a file that didn't have a new line and add one:
|
|
125
|
+
*
|
|
126
|
+
* deletion has \ No new line at end of file
|
|
127
|
+
* but not insertion
|
|
128
|
+
*
|
|
129
|
+
* if you edit a file that had a new line and leave it in:
|
|
130
|
+
*
|
|
131
|
+
* neither insetion nor deletion have the annoation
|
|
132
|
+
*
|
|
133
|
+
*/
|
|
134
|
+
function applyPatch({ hunks, path }, { dryRun, cwd, bestEffort, errors, }) {
|
|
135
|
+
path = cwd ? (0, path_1.resolve)(cwd, path) : path;
|
|
136
|
+
// modifying the file in place
|
|
137
|
+
const fileContents = fs_extra_1.default.readFileSync(path).toString();
|
|
138
|
+
const mode = fs_extra_1.default.statSync(path).mode;
|
|
139
|
+
const fileLines = fileContents.split(/\n/);
|
|
140
|
+
const result = [];
|
|
141
|
+
for (const hunk of hunks) {
|
|
142
|
+
let fuzzingOffset = 0;
|
|
143
|
+
while (true) {
|
|
144
|
+
const modifications = evaluateHunk(hunk, fileLines, fuzzingOffset);
|
|
145
|
+
if (modifications) {
|
|
146
|
+
result.push(modifications);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
fuzzingOffset =
|
|
150
|
+
fuzzingOffset < 0 ? fuzzingOffset * -1 : fuzzingOffset * -1 - 1;
|
|
151
|
+
if (Math.abs(fuzzingOffset) > 20) {
|
|
152
|
+
const message = `Cannot apply hunk ${hunks.indexOf(hunk)} for file ${(0, path_1.relative)(process.cwd(), path)}\n\`\`\`diff\n${hunk.source}\n\`\`\`\n`;
|
|
153
|
+
if (bestEffort) {
|
|
154
|
+
errors?.push(message);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
throw new Error(message);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (dryRun) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
let diffOffset = 0;
|
|
167
|
+
for (const modifications of result) {
|
|
168
|
+
for (const modification of modifications) {
|
|
169
|
+
switch (modification.type) {
|
|
170
|
+
case "splice":
|
|
171
|
+
fileLines.splice(modification.index + diffOffset, modification.numToDelete, ...modification.linesToInsert);
|
|
172
|
+
diffOffset +=
|
|
173
|
+
modification.linesToInsert.length - modification.numToDelete;
|
|
174
|
+
break;
|
|
175
|
+
case "pop":
|
|
176
|
+
fileLines.pop();
|
|
177
|
+
break;
|
|
178
|
+
case "push":
|
|
179
|
+
fileLines.push(modification.line);
|
|
180
|
+
break;
|
|
181
|
+
default:
|
|
182
|
+
(0, assertNever_1.assertNever)(modification);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
fs_extra_1.default.writeFileSync(path, fileLines.join("\n"), { mode });
|
|
188
|
+
}
|
|
189
|
+
catch (e) {
|
|
190
|
+
if (bestEffort) {
|
|
191
|
+
errors?.push(`Failed to write file ${path}`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
throw e;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function evaluateHunk(hunk, fileLines, fuzzingOffset) {
|
|
199
|
+
const result = [];
|
|
200
|
+
let contextIndex = hunk.header.original.start - 1 + fuzzingOffset;
|
|
201
|
+
// do bounds checks for index
|
|
202
|
+
if (contextIndex < 0) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
if (fileLines.length - contextIndex < hunk.header.original.length) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
for (const part of hunk.parts) {
|
|
209
|
+
switch (part.type) {
|
|
210
|
+
case "deletion":
|
|
211
|
+
case "context":
|
|
212
|
+
for (const line of part.lines) {
|
|
213
|
+
const originalLine = fileLines[contextIndex];
|
|
214
|
+
if (!linesAreEqual(originalLine, line)) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
contextIndex++;
|
|
218
|
+
}
|
|
219
|
+
if (part.type === "deletion") {
|
|
220
|
+
result.push({
|
|
221
|
+
type: "splice",
|
|
222
|
+
index: contextIndex - part.lines.length,
|
|
223
|
+
numToDelete: part.lines.length,
|
|
224
|
+
linesToInsert: [],
|
|
225
|
+
});
|
|
226
|
+
if (part.noNewlineAtEndOfFile) {
|
|
227
|
+
result.push({
|
|
228
|
+
type: "push",
|
|
229
|
+
line: "",
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
case "insertion":
|
|
235
|
+
result.push({
|
|
236
|
+
type: "splice",
|
|
237
|
+
index: contextIndex,
|
|
238
|
+
numToDelete: 0,
|
|
239
|
+
linesToInsert: part.lines,
|
|
240
|
+
});
|
|
241
|
+
if (part.noNewlineAtEndOfFile) {
|
|
242
|
+
result.push({ type: "pop" });
|
|
243
|
+
}
|
|
244
|
+
break;
|
|
245
|
+
default:
|
|
246
|
+
(0, assertNever_1.assertNever)(part.type);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcGF0Y2gvYXBwbHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsd0RBQXlCO0FBQ3pCLCtCQUF1RDtBQUV2RCxnREFBNEM7QUFFckMsTUFBTSxjQUFjLEdBQUcsQ0FDNUIsT0FBd0IsRUFDeEIsRUFDRSxNQUFNLEVBQ04sVUFBVSxFQUNWLE1BQU0sRUFDTixHQUFHLEdBQ3VFLEVBQzVFLEVBQUU7SUFDRixNQUFNLEtBQUssR0FBRyxDQUFDLElBQVksRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUEsV0FBSSxFQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDOUQsTUFBTSxhQUFhLEdBQUcsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUFDLElBQUEsZUFBUSxFQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtJQUM1RSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7UUFDdEIsUUFBUSxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDakIsS0FBSyxlQUFlO2dCQUNsQixJQUFJLE1BQU0sRUFBRSxDQUFDO29CQUNYLElBQUksQ0FBQyxrQkFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQzt3QkFDcEMsTUFBTSxJQUFJLEtBQUssQ0FDYiw0Q0FBNEM7NEJBQzFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQzFCLENBQUE7b0JBQ0gsQ0FBQztnQkFDSCxDQUFDO3FCQUFNLENBQUM7b0JBQ04seUJBQXlCO29CQUN6QixJQUFJLENBQUM7d0JBQ0gsa0JBQUUsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJ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RSxJQUFBLHlCQUFXLEVBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQzFCLENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUE7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gXCJmcy1leHRyYVwiXHJcbmltcG9ydCB7IGRpcm5hbWUsIGpvaW4sIHJlbGF0aXZlLCByZXNvbHZlIH0gZnJvbSBcInBhdGhcIlxyXG5pbXBvcnQgeyBQYXJzZWRQYXRjaEZpbGUsIEZpbGVQYXRjaCwgSHVuayB9IGZyb20gXCIuL3BhcnNlXCJcclxuaW1wb3J0IHsgYXNzZXJ0TmV2ZXIgfSBmcm9tIFwiLi4vYXNzZXJ0TmV2ZXJcIlxyXG5cclxuZXhwb3J0IGNvbnN0IGV4ZWN1dGVFZmZlY3RzID0gKFxyXG4gIGVmZmVjdHM6IFBhcnNlZFBhdGNoRmlsZSxcclxuICB7XHJcbiAgICBkcnlSdW4sXHJcbiAgICBiZXN0RWZmb3J0LFxyXG4gICAgZXJyb3JzLFxyXG4gICAgY3dkLFxyXG4gIH06IHsgZHJ5UnVuOiBib29sZWFuOyBjd2Q/OiBzdHJpbmc7IGVycm9ycz86IHN0cmluZ1tdOyBiZXN0RWZmb3J0OiBib29sZWFuIH0sXHJcbikgPT4ge1xyXG4gIGNvbnN0IGluQ3dkID0gKHBhdGg6IHN0cmluZykgPT4gKGN3ZCA/IGpvaW4oY3dkLCBwYXRoKSA6IHBhdGgpXHJcbiAgY29uc3QgaHVtYW5SZWFkYWJsZSA9IChwYXRoOiBzdHJpbmcpID0+IHJlbGF0aXZlKHByb2Nlc3MuY3dkKCksIGluQ3dkKHBhdGgpKVxyXG4gIGVmZmVjdHMuZm9yRWFjaCgoZWZmKSA9PiB7XHJcbiAgICBzd2l0Y2ggKGVmZi50eXBlKSB7XHJcbiAgICAgIGNhc2UgXCJmaWxlIGRlbGV0aW9uXCI6XHJcbiAgICAgICAgaWYgKGRyeVJ1bikge1xyXG4gICAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKGluQ3dkKGVmZi5wYXRoKSkpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxyXG4gICAgICAgICAgICAgIFwiVHJ5aW5nIHRvIGRlbGV0ZSBmaWxlIHRoYXQgZG9lc24ndCBleGlzdDogXCIgK1xyXG4gICAgICAgICAgICAgICAgaHVtYW5SZWFkYWJsZShlZmYucGF0aCksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gVE9ETzogaW50ZWdyaXR5IGNoZWNrc1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgZnMudW5saW5rU3luYyhpbkN3ZChlZmYucGF0aCkpXHJcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgICAgIGlmIChiZXN0RWZmb3J0KSB7XHJcbiAgICAgICAgICAgICAgZXJyb3JzPy5wdXNoKGBGYWlsZWQgdG8gZGVsZXRlIGZpbGUgJHtlZmYucGF0aH1gKVxyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIHRocm93IGVcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBicmVha1xyXG4gICAgICBjYXNlIFwicmVuYW1lXCI6XHJcbiAgICAgICAgaWYgKGRyeVJ1bikge1xyXG4gICAgICAgICAgLy8gVE9ETzogc2VlIHdoYXQgcGF0Y2ggZmlsZXMgbG9vayBsaWtlIGlmIG1vdmluZyB0byBleGlzaW5nIHBhdGhcclxuICAgICAgICAgIGlmICghZnMuZXhpc3RzU3luYyhpbkN3ZChlZmYuZnJvbVBhdGgpKSkge1xyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXHJcbiAgICAgICAgICAgICAgXCJUcnlpbmcgdG8gbW92ZSBmaWxlIHRoYXQgZG9lc24ndCBleGlzdDogXCIgK1xyXG4gICAgICAgICAgICAgICAgaHVtYW5SZWFkYWJsZShlZmYuZnJvbVBhdGgpLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGZzLm1vdmVTeW5jKGluQ3dkKGVmZi5mcm9tUGF0aCksIGluQ3dkKGVmZi50b1BhdGgpKVxyXG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICBpZiAoYmVzdEVmZm9ydCkge1xyXG4gICAgICAgICAgICAgIGVycm9ycz8ucHVzaChcclxuICAgICAgICAgICAgICAgIGBGYWlsZWQgdG8gcmVuYW1lIGZpbGUgJHtlZmYuZnJvbVBhdGh9IHRvICR7ZWZmLnRvUGF0aH1gLFxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICB0aHJvdyBlXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgYnJlYWtcclxuICAgICAgY2FzZSBcImZpbGUgY3JlYXRpb25cIjpcclxuICAgICAgICBpZiAoZHJ5UnVuKSB7XHJcbiAgICAgICAgICBpZiAoZnMuZXhpc3RzU3luYyhpbkN3ZChlZmYucGF0aCkpKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcclxuICAgICAgICAgICAgICBcIlRyeWluZyB0byBjcmVhdGUgZmlsZSB0aGF0IGFscmVhZHkgZXhpc3RzOiBcIiArXHJcbiAgICAgICAgICAgICAgICBodW1hblJlYWRhYmxlKGVmZi5wYXRoKSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgLy8gdG9kbzogY2hlY2sgZmlsZSBjb250ZW50cyBtYXRjaGVzXHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGNvbnN0IGZpbGVDb250ZW50cyA9IGVmZi5odW5rXHJcbiAgICAgICAgICAgID8gZWZmLmh1bmsucGFydHNbMF0ubGluZXMuam9pbihcIlxcblwiKSArXHJcbiAgICAgICAgICAgICAgKGVmZi5odW5rLnBhcnRzWzBdLm5vTmV3bGluZUF0RW5kT2ZGaWxlID8gXCJcIiA6IFwiXFxuXCIpXHJcbiAgICAgICAgICAgIDogXCJcIlxyXG4gICAgICAgICAgY29uc3QgcGF0aCA9IGluQ3dkKGVmZi5wYXRoKVxyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgZnMuZW5zdXJlRGlyU3luYyhkaXJuYW1lKHBhdGgpKVxyXG4gICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKHBhdGgsIGZpbGVDb250ZW50cywgeyBtb2RlOiBlZmYubW9kZSB9KVxyXG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICBpZiAoYmVzdEVmZm9ydCkge1xyXG4gICAgICAgICAgICAgIGVycm9ycz8ucHVzaChgRmFpbGVkIHRvIGNyZWF0ZSBuZXcgZmlsZSAke2VmZi5wYXRofWApXHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgZVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGJyZWFrXHJcbiAgICAgIGNhc2UgXCJwYXRjaFwiOlxyXG4gICAgICAgIGFwcGx5UGF0Y2goZWZmLCB7IGRyeVJ1biwgY3dkLCBiZXN0RWZmb3J0LCBlcnJvcnMgfSlcclxuICAgICAgICBicmVha1xyXG4gICAgICBjYXNlIFwibW9kZSBjaGFuZ2VcIjpcclxuICAgICAgICBjb25zdCBjdXJyZW50TW9kZSA9IGZzLnN0YXRTeW5jKGluQ3dkKGVmZi5wYXRoKSkubW9kZVxyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgICgoaXNFeGVjdXRhYmxlKGVmZi5uZXdNb2RlKSAmJiBpc0V4ZWN1dGFibGUoY3VycmVudE1vZGUpKSB8fFxyXG4gICAgICAgICAgICAoIWlzRXhlY3V0YWJsZShlZmYubmV3TW9kZSkgJiYgIWlzRXhlY3V0YWJsZShjdXJyZW50TW9kZSkpKSAmJlxyXG4gICAgICAgICAgZHJ5UnVuXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgICAgYE1vZGUgY2hhbmdlIGlzIG5vdCByZXF1aXJlZCBmb3IgZmlsZSAke2h1bWFuUmVhZGFibGUoZWZmLnBhdGgpfWAsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZzLmNobW9kU3luYyhpbkN3ZChlZmYucGF0aCksIGVmZi5uZXdNb2RlKVxyXG4gICAgICAgIGJyZWFrXHJcbiAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgYXNzZXJ0TmV2ZXIoZWZmKVxyXG4gICAgfVxyXG4gIH0pXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGlzRXhlY3V0YWJsZShmaWxlTW9kZTogbnVtYmVyKSB7XHJcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWJpdHdpc2VcclxuICByZXR1cm4gKGZpbGVNb2RlICYgMGIwMDFfMDAwXzAwMCkgPiAwXHJcbn1cclxuXHJcbmNvbnN0IHRyaW1SaWdodCA9IChzOiBzdHJpbmcpID0+IHMucmVwbGFjZSgvXFxzKyQvLCBcIlwiKVxyXG5mdW5jdGlvbiBsaW5lc0FyZUVxdWFsKGE6IHN0cmluZywgYjogc3RyaW5nKSB7XHJcbiAgcmV0dXJuIHRyaW1SaWdodChhKSA9PT0gdHJpbVJpZ2h0KGIpXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIb3cgZG9lcyBub05ld0xpbmVBdEVuZE9mRmlsZSB3b3JrP1xyXG4gKlxyXG4gKiBpZiB5b3UgcmVtb3ZlIHRoZSBuZXdsaW5lIGZyb20gYSBmaWxlIHRoYXQgaGFkIG9uZSB3aXRob3V0IGVkaXRpbmcgb3RoZXIgYml0czpcclxuICpcclxuICogICAgaXQgY3JlYXRlcyBhbiBpbnNlcnRpb24vcmVtb3ZhbCBwYWlyIHdoZXJlIHRoZSBpbnNlcnRpb24gaGFzIFxcIE5vIG5ldyBsaW5lIGF0IGVuZCBvZiBmaWxlXHJcbiAqXHJcbiAqIGlmIHlvdSBlZGl0IGEgZmlsZSB0aGF0IGRpZG4ndCBoYXZlIGEgbmV3IGxpbmUgYW5kIGRvbid0IGFkZCBvbmU6XHJcbiAqXHJcbiAqICAgIGJvdGggaW5zZXJ0aW9uIGFuZCBkZWxldGlvbiBoYXZlIFxcIE5vIG5ldyBsaW5lIGF0IGVuZCBvZiBmaWxlXHJcbiAqXHJcbiAqIGlmIHlvdSBlZGl0IGEgZmlsZSB0aGF0IGRpZG4ndCBoYXZlIGEgbmV3IGxpbmUgYW5kIGFkZCBvbmU6XHJcbiAqXHJcbiAqICAgIGRlbGV0aW9uIGhhcyBcXCBObyBuZXcgbGluZSBhdCBlbmQgb2YgZmlsZVxyXG4gKiAgICBidXQgbm90IGluc2VydGlvblxyXG4gKlxyXG4gKiBpZiB5b3UgZWRpdCBhIGZpbGUgdGhhdCBoYWQgYSBuZXcgbGluZSBhbmQgbGVhdmUgaXQgaW46XHJcbiAqXHJcbiAqICAgIG5laXRoZXIgaW5zZXRpb24gbm9yIGRlbGV0aW9uIGhhdmUgdGhlIGFubm9hdGlvblxyXG4gKlxyXG4gKi9cclxuXHJcbmZ1bmN0aW9uIGFwcGx5UGF0Y2goXHJcbiAgeyBodW5rcywgcGF0aCB9OiBGaWxlUGF0Y2gsXHJcbiAge1xyXG4gICAgZHJ5UnVuLFxyXG4gICAgY3dkLFxyXG4gICAgYmVzdEVmZm9ydCxcclxuICAgIGVycm9ycyxcclxuICB9OiB7IGRyeVJ1bjogYm9vbGVhbjsgY3dkPzogc3RyaW5nOyBiZXN0RWZmb3J0OiBib29sZWFuOyBlcnJvcnM/OiBzdHJpbmdbXSB9LFxyXG4pOiB2b2lkIHtcclxuICBwYXRoID0gY3dkID8gcmVzb2x2ZShjd2QsIHBhdGgpIDogcGF0aFxyXG4gIC8vIG1vZGlmeWluZyB0aGUgZmlsZSBpbiBwbGFjZVxyXG4gIGNvbnN0IGZpbGVDb250ZW50cyA9IGZzLnJlYWRGaWxlU3luYyhwYXRoKS50b1N0cmluZygpXHJcbiAgY29uc3QgbW9kZSA9IGZzLnN0YXRTeW5jKHBhdGgpLm1vZGVcclxuXHJcbiAgY29uc3QgZmlsZUxpbmVzOiBzdHJpbmdbXSA9IGZpbGVDb250ZW50cy5zcGxpdCgvXFxuLylcclxuXHJcbiAgY29uc3QgcmVzdWx0OiBNb2RpZmljYXRpb25bXVtdID0gW11cclxuXHJcbiAgZm9yIChjb25zdCBodW5rIG9mIGh1bmtzKSB7XHJcbiAgICBsZXQgZnV6emluZ09mZnNldCA9IDBcclxuICAgIHdoaWxlICh0cnVlKSB7XHJcbiAgICAgIGNvbnN0IG1vZGlmaWNhdGlvbnMgPSBldmFsdWF0ZUh1bmsoaHVuaywgZmlsZUxpbmVzLCBmdXp6aW5nT2Zmc2V0KVxyXG4gICAgICBpZiAobW9kaWZpY2F0aW9ucykge1xyXG4gICAgICAgIHJlc3VsdC5wdXNoKG1vZGlmaWNhdGlvbnMpXHJcbiAgICAgICAgYnJlYWtcclxuICAgICAgfVxyXG5cclxuICAgICAgZnV6emluZ09mZnNldCA9XHJcbiAgICAgICAgZnV6emluZ09mZnNldCA8IDAgPyBmdXp6aW5nT2Zmc2V0ICogLTEgOiBmdXp6aW5nT2Zmc2V0ICogLTEgLSAxXHJcblxyXG4gICAgICBpZiAoTWF0aC5hYnMoZnV6emluZ09mZnNldCkgPiAyMCkge1xyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBgQ2Fubm90IGFwcGx5IGh1bmsgJHtodW5rcy5pbmRleE9mKFxyXG4gICAgICAgICAgaHVuayxcclxuICAgICAgICApfSBmb3IgZmlsZSAke3JlbGF0aXZlKHByb2Nlc3MuY3dkKCksIHBhdGgpfVxcblxcYFxcYFxcYGRpZmZcXG4ke1xyXG4gICAgICAgICAgaHVuay5zb3VyY2VcclxuICAgICAgICB9XFxuXFxgXFxgXFxgXFxuYFxyXG5cclxuICAgICAgICBpZiAoYmVzdEVmZm9ydCkge1xyXG4gICAgICAgICAgZXJyb3JzPy5wdXNoKG1lc3NhZ2UpXHJcbiAgICAgICAgICBicmVha1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IobWVzc2FnZSlcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIGlmIChkcnlSdW4pIHtcclxuICAgIHJldHVyblxyXG4gIH1cclxuXHJcbiAgbGV0IGRpZmZPZmZzZXQgPSAwXHJcblxyXG4gIGZvciAoY29uc3QgbW9kaWZpY2F0aW9ucyBvZiByZXN1bHQpIHtcclxuICAgIGZvciAoY29uc3QgbW9kaWZpY2F0aW9uIG9mIG1vZGlmaWNhdGlvbnMpIHtcclxuICAgICAgc3dpdGNoIChtb2RpZmljYXRpb24udHlwZSkge1xyXG4gICAgICAgIGNhc2UgXCJzcGxpY2VcIjpcclxuICAgICAgICAgIGZpbGVMaW5lcy5zcGxpY2UoXHJcbiAgICAgICAgICAgIG1vZGlmaWNhdGlvbi5pbmRleCArIGRpZmZPZmZzZXQsXHJcbiAgICAgICAgICAgIG1vZGlmaWNhdGlvbi5udW1Ub0RlbGV0ZSxcclxuICAgICAgICAgICAgLi4ubW9kaWZpY2F0aW9uLmxpbmVzVG9JbnNlcnQsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICBkaWZmT2Zmc2V0ICs9XHJcbiAgICAgICAgICAgIG1vZGlmaWNhdGlvbi5saW5lc1RvSW5zZXJ0Lmxlbmd0aCAtIG1vZGlmaWNhdGlvbi5udW1Ub0RlbGV0ZVxyXG4gICAgICAgICAgYnJlYWtcclxuICAgICAgICBjYXNlIFwicG9wXCI6XHJcbiAgICAgICAgICBmaWxlTGluZXMucG9wKClcclxuICAgICAgICAgIGJyZWFrXHJcbiAgICAgICAgY2FzZSBcInB1c2hcIjpcclxuICAgICAgICAgIGZpbGVMaW5lcy5wdXNoKG1vZGlmaWNhdGlvbi5saW5lKVxyXG4gICAgICAgICAgYnJlYWtcclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgYXNzZXJ0TmV2ZXIobW9kaWZpY2F0aW9uKVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgZnMud3JpdGVGaWxlU3luYyhwYXRoLCBmaWxlTGluZXMuam9pbihcIlxcblwiKSwgeyBtb2RlIH0pXHJcbiAgfSBjYXRjaCAoZSkge1xyXG4gICAgaWYgKGJlc3RFZmZvcnQpIHtcclxuICAgICAgZXJyb3JzPy5wdXNoKGBGYWlsZWQgdG8gd3JpdGUgZmlsZSAke3BhdGh9YClcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IGVcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmludGVyZmFjZSBQdXNoIHtcclxuICB0eXBlOiBcInB1c2hcIlxyXG4gIGxpbmU6IHN0cmluZ1xyXG59XHJcbmludGVyZmFjZSBQb3Age1xyXG4gIHR5cGU6IFwicG9wXCJcclxufVxyXG5pbnRlcmZhY2UgU3BsaWNlIHtcclxuICB0eXBlOiBcInNwbGljZVwiXHJcbiAgaW5kZXg6IG51bWJlclxyXG4gIG51bVRvRGVsZXRlOiBudW1iZXJcclxuICBsaW5lc1RvSW5zZXJ0OiBzdHJpbmdbXVxyXG59XHJcblxyXG50eXBlIE1vZGlmaWNhdGlvbiA9IFB1c2ggfCBQb3AgfCBTcGxpY2VcclxuXHJcbmZ1bmN0aW9uIGV2YWx1YXRlSHVuayhcclxuICBodW5rOiBIdW5rLFxyXG4gIGZpbGVMaW5lczogc3RyaW5nW10sXHJcbiAgZnV6emluZ09mZnNldDogbnVtYmVyLFxyXG4pOiBNb2RpZmljYXRpb25bXSB8IG51bGwge1xyXG4gIGNvbnN0IHJlc3VsdDogTW9kaWZpY2F0aW9uW10gPSBbXVxyXG4gIGxldCBjb250ZXh0SW5kZXggPSBodW5rLmhlYWRlci5vcmlnaW5hbC5zdGFydCAtIDEgKyBmdXp6aW5nT2Zmc2V0XHJcbiAgLy8gZG8gYm91bmRzIGNoZWNrcyBmb3IgaW5kZXhcclxuICBpZiAoY29udGV4dEluZGV4IDwgMCkge1xyXG4gICAgcmV0dXJuIG51bGxcclxuICB9XHJcbiAgaWYgKGZpbGVMaW5lcy5sZW5ndGggLSBjb250ZXh0SW5kZXggPCBodW5rLmhlYWRlci5vcmlnaW5hbC5sZW5ndGgpIHtcclxuICAgIHJldHVybiBudWxsXHJcbiAgfVxyXG5cclxuICBmb3IgKGNvbnN0IHBhcnQgb2YgaHVuay5wYXJ0cykge1xyXG4gICAgc3dpdGNoIChwYXJ0LnR5cGUpIHtcclxuICAgICAgY2FzZSBcImRlbGV0aW9uXCI6XHJcbiAgICAgIGNhc2UgXCJjb250ZXh0XCI6XHJcbiAgICAgICAgZm9yIChjb25zdCBsaW5lIG9mIHBhcnQubGluZXMpIHtcclxuICAgICAgICAgIGNvbnN0IG9yaWdpbmFsTGluZSA9IGZpbGVMaW5lc1tjb250ZXh0SW5kZXhdXHJcbiAgICAgICAgICBpZiAoIWxpbmVzQXJlRXF1YWwob3JpZ2luYWxMaW5lLCBsaW5lKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgY29udGV4dEluZGV4KytcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChwYXJ0LnR5cGUgPT09IFwiZGVsZXRpb25cIikge1xyXG4gICAgICAgICAgcmVzdWx0LnB1c2goe1xyXG4gICAgICAgICAgICB0eXBlOiBcInNwbGljZVwiLFxyXG4gICAgICAgICAgICBpbmRleDogY29udGV4dEluZGV4IC0gcGFydC5saW5lcy5sZW5ndGgsXHJcbiAgICAgICAgICAgIG51bVRvRGVsZXRlOiBwYXJ0LmxpbmVzLmxlbmd0aCxcclxuICAgICAgICAgICAgbGluZXNUb0luc2VydDogW10sXHJcbiAgICAgICAgICB9KVxyXG5cclxuICAgICAgICAgIGlmIChwYXJ0Lm5vTmV3bGluZUF0RW5kT2ZGaWxlKSB7XHJcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKHtcclxuICAgICAgICAgICAgICB0eXBlOiBcInB1c2hcIixcclxuICAgICAgICAgICAgICBsaW5lOiBcIlwiLFxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBicmVha1xyXG4gICAgICBjYXNlIFwiaW5zZXJ0aW9uXCI6XHJcbiAgICAgICAgcmVzdWx0LnB1c2goe1xyXG4gICAgICAgICAgdHlwZTogXCJzcGxpY2VcIixcclxuICAgICAgICAgIGluZGV4OiBjb250ZXh0SW5kZXgsXHJcbiAgICAgICAgICBudW1Ub0RlbGV0ZTogMCxcclxuICAgICAgICAgIGxpbmVzVG9JbnNlcnQ6IHBhcnQubGluZXMsXHJcbiAgICAgICAgfSlcclxuICAgICAgICBpZiAocGFydC5ub05ld2xpbmVBdEVuZE9mRmlsZSkge1xyXG4gICAgICAgICAgcmVzdWx0LnB1c2goeyB0eXBlOiBcInBvcFwiIH0pXHJcbiAgICAgICAgfVxyXG4gICAgICAgIGJyZWFrXHJcbiAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgYXNzZXJ0TmV2ZXIocGFydC50eXBlKVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIHJlc3VsdFxyXG59XHJcbiJdfQ==
|