applyPatches.js 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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.applyPatch = exports.applyPatchesForPackage = exports.applyPatchesForApp = void 0;
  7. const chalk_1 = __importDefault(require("chalk"));
  8. const fs_1 = require("fs");
  9. const fs_extra_1 = require("fs-extra");
  10. const path_1 = require("path");
  11. const semver_1 = __importDefault(require("semver"));
  12. const hash_1 = require("./hash");
  13. const makePatch_1 = require("./makePatch");
  14. const packageIsDevDependency_1 = require("./packageIsDevDependency");
  15. const apply_1 = require("./patch/apply");
  16. const read_1 = require("./patch/read");
  17. const reverse_1 = require("./patch/reverse");
  18. const patchFs_1 = require("./patchFs");
  19. const path_2 = require("./path");
  20. const stateFile_1 = require("./stateFile");
  21. class PatchApplicationError extends Error {
  22. constructor(msg) {
  23. super(msg);
  24. }
  25. }
  26. function getInstalledPackageVersion({ appPath, path, pathSpecifier, isDevOnly, patchFilename, }) {
  27. const packageDir = path_2.join(appPath, path);
  28. if (!fs_extra_1.existsSync(packageDir)) {
  29. if (process.env.NODE_ENV === "production" && isDevOnly) {
  30. return null;
  31. }
  32. let err = `${chalk_1.default.red("Error:")} Patch file found for package ${path_1.posix.basename(pathSpecifier)}` + ` which is not present at ${path_2.relative(".", packageDir)}`;
  33. if (!isDevOnly && process.env.NODE_ENV === "production") {
  34. err += `
  35. If this package is a dev dependency, rename the patch file to
  36. ${chalk_1.default.bold(patchFilename.replace(".patch", ".dev.patch"))}
  37. `;
  38. }
  39. throw new PatchApplicationError(err);
  40. }
  41. const { version } = require(path_2.join(packageDir, "package.json"));
  42. // normalize version for `npm ci`
  43. const result = semver_1.default.valid(version);
  44. if (result === null) {
  45. throw new PatchApplicationError(`${chalk_1.default.red("Error:")} Version string '${version}' cannot be parsed from ${path_2.join(packageDir, "package.json")}`);
  46. }
  47. return result;
  48. }
  49. function logPatchApplication(patchDetails) {
  50. const sequenceString = patchDetails.sequenceNumber != null
  51. ? ` (${patchDetails.sequenceNumber}${patchDetails.sequenceName ? " " + patchDetails.sequenceName : ""})`
  52. : "";
  53. console.log(`${chalk_1.default.bold(patchDetails.pathSpecifier)}@${patchDetails.version}${sequenceString} ${chalk_1.default.green("✔")}`);
  54. }
  55. function applyPatchesForApp({ appPath, reverse, patchDir, shouldExitWithError, shouldExitWithWarning, bestEffort, }) {
  56. const patchesDirectory = path_2.join(appPath, patchDir);
  57. const groupedPatches = patchFs_1.getGroupedPatches(patchesDirectory);
  58. if (groupedPatches.numPatchFiles === 0) {
  59. console.log(chalk_1.default.blueBright("No patch files found"));
  60. return;
  61. }
  62. const errors = [];
  63. const warnings = [...groupedPatches.warnings];
  64. for (const patches of Object.values(groupedPatches.pathSpecifierToPatchFiles)) {
  65. applyPatchesForPackage({
  66. patches,
  67. appPath,
  68. patchDir,
  69. reverse,
  70. warnings,
  71. errors,
  72. bestEffort,
  73. });
  74. }
  75. for (const warning of warnings) {
  76. console.log(warning);
  77. }
  78. for (const error of errors) {
  79. console.log(error);
  80. }
  81. const problemsSummary = [];
  82. if (warnings.length) {
  83. problemsSummary.push(chalk_1.default.yellow(`${warnings.length} warning(s)`));
  84. }
  85. if (errors.length) {
  86. problemsSummary.push(chalk_1.default.red(`${errors.length} error(s)`));
  87. }
  88. if (problemsSummary.length) {
  89. console.log("---");
  90. console.log("patch-package finished with", problemsSummary.join(", ") + ".");
  91. }
  92. if (errors.length && shouldExitWithError) {
  93. process.exit(1);
  94. }
  95. if (warnings.length && shouldExitWithWarning) {
  96. process.exit(1);
  97. }
  98. process.exit(0);
  99. }
  100. exports.applyPatchesForApp = applyPatchesForApp;
  101. function applyPatchesForPackage({ patches, appPath, patchDir, reverse, warnings, errors, bestEffort, }) {
  102. const pathSpecifier = patches[0].pathSpecifier;
  103. const state = patches.length > 1 ? stateFile_1.getPatchApplicationState(patches[0]) : null;
  104. const unappliedPatches = patches.slice(0);
  105. const appliedPatches = [];
  106. // if there are multiple patches to apply, we can't rely on the reverse-patch-dry-run behavior to make this operation
  107. // idempotent, so instead we need to check the state file to see whether we have already applied any of the patches
  108. // todo: once this is battle tested we might want to use the same approach for single patches as well, but it's not biggie since the dry run thing is fast
  109. if (unappliedPatches && state) {
  110. for (let i = 0; i < state.patches.length; i++) {
  111. const patchThatWasApplied = state.patches[i];
  112. if (!patchThatWasApplied.didApply) {
  113. break;
  114. }
  115. const patchToApply = unappliedPatches[0];
  116. const currentPatchHash = hash_1.hashFile(path_2.join(appPath, patchDir, patchToApply.patchFilename));
  117. if (patchThatWasApplied.patchContentHash === currentPatchHash) {
  118. // this patch was applied we can skip it
  119. appliedPatches.push(unappliedPatches.shift());
  120. }
  121. else {
  122. console.log(chalk_1.default.red("Error:"), `The patches for ${chalk_1.default.bold(pathSpecifier)} have changed.`, `You should reinstall your node_modules folder to make sure the package is up to date`);
  123. process.exit(1);
  124. }
  125. }
  126. }
  127. if (reverse && state) {
  128. // if we are reversing the patches we need to make the unappliedPatches array
  129. // be the reversed version of the appliedPatches array.
  130. // The applied patches array should then be empty because it is used differently
  131. // when outputting the state file.
  132. unappliedPatches.length = 0;
  133. unappliedPatches.push(...appliedPatches);
  134. unappliedPatches.reverse();
  135. appliedPatches.length = 0;
  136. }
  137. if (appliedPatches.length) {
  138. // some patches have already been applied
  139. appliedPatches.forEach(logPatchApplication);
  140. }
  141. if (!unappliedPatches.length) {
  142. return;
  143. }
  144. let failedPatch = null;
  145. packageLoop: for (const patchDetails of unappliedPatches) {
  146. try {
  147. const { name, version, path, isDevOnly, patchFilename } = patchDetails;
  148. const installedPackageVersion = getInstalledPackageVersion({
  149. appPath,
  150. path,
  151. pathSpecifier,
  152. isDevOnly: isDevOnly ||
  153. // check for direct-dependents in prod
  154. (process.env.NODE_ENV === "production" &&
  155. packageIsDevDependency_1.packageIsDevDependency({
  156. appPath,
  157. patchDetails,
  158. })),
  159. patchFilename,
  160. });
  161. if (!installedPackageVersion) {
  162. // it's ok we're in production mode and this is a dev only package
  163. console.log(`Skipping dev-only ${chalk_1.default.bold(pathSpecifier)}@${version} ${chalk_1.default.blue("✔")}`);
  164. continue;
  165. }
  166. if (applyPatch({
  167. patchFilePath: path_2.join(appPath, patchDir, patchFilename),
  168. reverse,
  169. patchDetails,
  170. patchDir,
  171. cwd: process.cwd(),
  172. bestEffort,
  173. })) {
  174. appliedPatches.push(patchDetails);
  175. // yay patch was applied successfully
  176. // print warning if version mismatch
  177. if (installedPackageVersion !== version) {
  178. warnings.push(createVersionMismatchWarning({
  179. packageName: name,
  180. actualVersion: installedPackageVersion,
  181. originalVersion: version,
  182. pathSpecifier,
  183. path,
  184. }));
  185. }
  186. logPatchApplication(patchDetails);
  187. }
  188. else if (patches.length > 1) {
  189. makePatch_1.logPatchSequenceError({ patchDetails });
  190. // in case the package has multiple patches, we need to break out of this inner loop
  191. // because we don't want to apply more patches on top of the broken state
  192. failedPatch = patchDetails;
  193. break packageLoop;
  194. }
  195. else if (installedPackageVersion === version) {
  196. // completely failed to apply patch
  197. // TODO: propagate useful error messages from patch application
  198. errors.push(createBrokenPatchFileError({
  199. packageName: name,
  200. patchFilename,
  201. pathSpecifier,
  202. path,
  203. }));
  204. break packageLoop;
  205. }
  206. else {
  207. errors.push(createPatchApplicationFailureError({
  208. packageName: name,
  209. actualVersion: installedPackageVersion,
  210. originalVersion: version,
  211. patchFilename,
  212. path,
  213. pathSpecifier,
  214. }));
  215. // in case the package has multiple patches, we need to break out of this inner loop
  216. // because we don't want to apply more patches on top of the broken state
  217. break packageLoop;
  218. }
  219. }
  220. catch (error) {
  221. if (error instanceof PatchApplicationError) {
  222. errors.push(error.message);
  223. }
  224. else {
  225. errors.push(createUnexpectedError({
  226. filename: patchDetails.patchFilename,
  227. error: error,
  228. }));
  229. }
  230. // in case the package has multiple patches, we need to break out of this inner loop
  231. // because we don't want to apply more patches on top of the broken state
  232. break packageLoop;
  233. }
  234. }
  235. if (patches.length > 1) {
  236. if (reverse) {
  237. if (!state) {
  238. throw new Error("unexpected state: no state file found while reversing");
  239. }
  240. // if we removed all the patches that were previously applied we can delete the state file
  241. if (appliedPatches.length === patches.length) {
  242. stateFile_1.clearPatchApplicationState(patches[0]);
  243. }
  244. else {
  245. // We failed while reversing patches and some are still in the applied state.
  246. // We need to update the state file to reflect that.
  247. // appliedPatches is currently the patches that were successfully reversed, in the order they were reversed
  248. // So we need to find the index of the last reversed patch in the original patches array
  249. // and then remove all the patches after that. Sorry for the confusing code.
  250. const lastReversedPatchIndex = patches.indexOf(appliedPatches[appliedPatches.length - 1]);
  251. if (lastReversedPatchIndex === -1) {
  252. throw new Error("unexpected state: failed to find last reversed patch in original patches array");
  253. }
  254. stateFile_1.savePatchApplicationState({
  255. packageDetails: patches[0],
  256. patches: patches.slice(0, lastReversedPatchIndex).map((patch) => ({
  257. didApply: true,
  258. patchContentHash: hash_1.hashFile(path_2.join(appPath, patchDir, patch.patchFilename)),
  259. patchFilename: patch.patchFilename,
  260. })),
  261. isRebasing: false,
  262. });
  263. }
  264. }
  265. else {
  266. const nextState = appliedPatches.map((patch) => ({
  267. didApply: true,
  268. patchContentHash: hash_1.hashFile(path_2.join(appPath, patchDir, patch.patchFilename)),
  269. patchFilename: patch.patchFilename,
  270. }));
  271. if (failedPatch) {
  272. nextState.push({
  273. didApply: false,
  274. patchContentHash: hash_1.hashFile(path_2.join(appPath, patchDir, failedPatch.patchFilename)),
  275. patchFilename: failedPatch.patchFilename,
  276. });
  277. }
  278. stateFile_1.savePatchApplicationState({
  279. packageDetails: patches[0],
  280. patches: nextState,
  281. isRebasing: !!failedPatch,
  282. });
  283. }
  284. if (failedPatch) {
  285. process.exit(1);
  286. }
  287. }
  288. }
  289. exports.applyPatchesForPackage = applyPatchesForPackage;
  290. function applyPatch({ patchFilePath, reverse, patchDetails, patchDir, cwd, bestEffort, }) {
  291. const patch = read_1.readPatch({
  292. patchFilePath,
  293. patchDetails,
  294. patchDir,
  295. });
  296. const forward = reverse ? reverse_1.reversePatch(patch) : patch;
  297. try {
  298. if (!bestEffort) {
  299. apply_1.executeEffects(forward, { dryRun: true, cwd, bestEffort: false });
  300. }
  301. const errors = bestEffort ? [] : undefined;
  302. apply_1.executeEffects(forward, { dryRun: false, cwd, bestEffort, errors });
  303. if (errors === null || errors === void 0 ? void 0 : errors.length) {
  304. console.log("Saving errors to", chalk_1.default.cyan.bold("./patch-package-errors.log"));
  305. fs_1.writeFileSync("patch-package-errors.log", errors.join("\n\n"));
  306. process.exit(0);
  307. }
  308. }
  309. catch (e) {
  310. try {
  311. const backward = reverse ? patch : reverse_1.reversePatch(patch);
  312. apply_1.executeEffects(backward, {
  313. dryRun: true,
  314. cwd,
  315. bestEffort: false,
  316. });
  317. }
  318. catch (e) {
  319. return false;
  320. }
  321. }
  322. return true;
  323. }
  324. exports.applyPatch = applyPatch;
  325. function createVersionMismatchWarning({ packageName, actualVersion, originalVersion, pathSpecifier, path, }) {
  326. return `
  327. ${chalk_1.default.yellow("Warning:")} patch-package detected a patch file version mismatch
  328. Don't worry! This is probably fine. The patch was still applied
  329. successfully. Here's the deets:
  330. Patch file created for
  331. ${packageName}@${chalk_1.default.bold(originalVersion)}
  332. applied to
  333. ${packageName}@${chalk_1.default.bold(actualVersion)}
  334. At path
  335. ${path}
  336. This warning is just to give you a heads-up. There is a small chance of
  337. breakage even though the patch was applied successfully. Make sure the package
  338. still behaves like you expect (you wrote tests, right?) and then run
  339. ${chalk_1.default.bold(`patch-package ${pathSpecifier}`)}
  340. to update the version in the patch file name and make this warning go away.
  341. `;
  342. }
  343. function createBrokenPatchFileError({ packageName, patchFilename, path, pathSpecifier, }) {
  344. return `
  345. ${chalk_1.default.red.bold("**ERROR**")} ${chalk_1.default.red(`Failed to apply patch for package ${chalk_1.default.bold(packageName)} at path`)}
  346. ${path}
  347. This error was caused because patch-package cannot apply the following patch file:
  348. patches/${patchFilename}
  349. Try removing node_modules and trying again. If that doesn't work, maybe there was
  350. an accidental change made to the patch file? Try recreating it by manually
  351. editing the appropriate files and running:
  352. patch-package ${pathSpecifier}
  353. If that doesn't work, then it's a bug in patch-package, so please submit a bug
  354. report. Thanks!
  355. https://github.com/ds300/patch-package/issues
  356. `;
  357. }
  358. function createPatchApplicationFailureError({ packageName, actualVersion, originalVersion, patchFilename, path, pathSpecifier, }) {
  359. return `
  360. ${chalk_1.default.red.bold("**ERROR**")} ${chalk_1.default.red(`Failed to apply patch for package ${chalk_1.default.bold(packageName)} at path`)}
  361. ${path}
  362. This error was caused because ${chalk_1.default.bold(packageName)} has changed since you
  363. made the patch file for it. This introduced conflicts with your patch,
  364. just like a merge conflict in Git when separate incompatible changes are
  365. made to the same piece of code.
  366. Maybe this means your patch file is no longer necessary, in which case
  367. hooray! Just delete it!
  368. Otherwise, you need to generate a new patch file.
  369. To generate a new one, just repeat the steps you made to generate the first
  370. one.
  371. i.e. manually make the appropriate file changes, then run
  372. patch-package ${pathSpecifier}
  373. Info:
  374. Patch file: patches/${patchFilename}
  375. Patch was made for version: ${chalk_1.default.green.bold(originalVersion)}
  376. Installed version: ${chalk_1.default.red.bold(actualVersion)}
  377. `;
  378. }
  379. function createUnexpectedError({ filename, error, }) {
  380. return `
  381. ${chalk_1.default.red.bold("**ERROR**")} ${chalk_1.default.red(`Failed to apply patch file ${chalk_1.default.bold(filename)}`)}
  382. ${error.stack}
  383. `;
  384. }
  385. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbHlQYXRjaGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2FwcGx5UGF0Y2hlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxrREFBeUI7QUFDekIsMkJBQWtDO0FBQ2xDLHVDQUFxQztBQUNyQywrQkFBNEI7QUFDNUIsb0RBQTJCO0FBQzNCLGlDQUFpQztBQUNqQywyQ0FBbUQ7QUFFbkQscUVBQWlFO0FBQ2pFLHlDQUE4QztBQUM5Qyx1Q0FBd0M7QUFDeEMsNkNBQThDO0FBQzlDLHVDQUE2QztBQUM3QyxpQ0FBdUM7QUFDdkMsMkNBS29CO0FBRXBCLE1BQU0scUJBQXNCLFNBQVEsS0FBSztJQUN2QyxZQUFZLEdBQVc7UUFDckIsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQ1osQ0FBQztDQUNGO0FBRUQsU0FBUywwQkFBMEIsQ0FBQyxFQUNsQyxPQUFPLEVBQ1AsSUFBSSxFQUNKLGFBQWEsRUFDYixTQUFTLEVBQ1QsYUFBYSxHQU9kO0lBQ0MsTUFBTSxVQUFVLEdBQUcsV0FBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUN0QyxJQUFJLENBQUMscUJBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRTtRQUMzQixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLFlBQVksSUFBSSxTQUFTLEVBQUU7WUFDdEQsT0FBTyxJQUFJLENBQUE7U0FDWjtRQUVELElBQUksR0FBRyxHQUNMLEdBQUcsZUFBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsaUNBQWlDLFlBQUssQ0FBQyxRQUFRLENBQ25FLGFBQWEsQ0FDZCxFQUFFLEdBQUcsNEJBQTRCLGVBQVEsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQTtRQUUvRCxJQUFJLENBQUMsU0FBUyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLFlBQVksRUFBRTtZQUN2RCxHQUFHLElBQUk7Ozs7TUFJUCxlQUFLLENB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LFdBQVcsRUFDWCxhQUFhLEVBQ2IsZUFBZSxFQUNmLGFBQWEsRUFDYixJQUFJLEVBQ0osYUFBYSxHQVFkO0lBQ0MsT0FBTztFQUNQLGVBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLGVBQUssQ0FBQyxHQUFHLENBQ3RDLHFDQUFxQyxlQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQ3ZFOztNQUVHLElBQUk7O2tDQUV3QixlQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7O29CQWVyQyxhQUFhOzs7MEJBR1AsYUFBYTtrQ0FDTCxlQUFLLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUM7eUJBQzFDLGVBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQztDQUNyRCxDQUFBO0FBQ0QsQ0FBQztBQUVELFNBQVMscUJBQXFCLENBQUMsRUFDN0IsUUFBUSxFQUNSLEtBQUssR0FJTjtJQUNDLE9BQU87RUFDUCxlQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxlQUFLLENBQUMsR0FBRyxDQUN0Qyw4QkFBOEIsZUFBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUNyRDs7RUFFRCxLQUFLLENBQUMsS0FBSzs7R0FFVixDQUFBO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIlxuaW1wb3J0IHsgd3JpdGVGaWxlU3luYyB9IGZyb20gXCJmc1wiXG5pbXBvcnQgeyBleGlzdHNTeW5jIH0gZnJvbSBcImZzLWV4dHJhXCJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSBcInBhdGhcIlxuaW1wb3J0IHNlbXZlciBmcm9tIFwic2VtdmVyXCJcbmltcG9ydCB7IGhhc2hGaWxlIH0gZnJvbSBcIi4vaGFzaFwiXG5pbXBvcnQgeyBsb2dQYXRjaFNlcXVlbmNlRXJyb3IgfSBmcm9tIFwiLi9tYWtlUGF0Y2hcIlxuaW1wb3J0IHsgUGFja2FnZURldGFpbHMsIFBhdGNoZWRQYWNrYWdlRGV0YWlscyB9IGZyb20gXCIuL1BhY2thZ2VEZXRhaWxzXCJcbmltcG9ydCB7IHBhY2thZ2VJc0RldkRlcGVuZGVuY3kgfSBmcm9tIFwiLi9wYWNrYWdlSXNEZXZEZXBlbmRlbmN5XCJcbmltcG9ydCB7IGV4ZWN1dGVFZmZlY3RzIH0gZnJvbSBcIi4vcGF0Y2gvYXBwbHlcIlxuaW1wb3J0IHsgcmVhZFBhdGNoIH0gZnJvbSBcIi4vcGF0Y2gvcmVhZFwiXG5pbXBvcnQgeyByZXZlcnNlUGF0Y2ggfSBmcm9tIFwiLi9wYXRjaC9yZXZlcnNlXCJcbmltcG9ydCB7IGdldEdyb3VwZWRQYXRjaGVzIH0gZnJvbSBcIi4vcGF0Y2hGc1wiXG5pbXBvcnQgeyBqb2luLCByZWxhdGl2ZSB9IGZyb20gXCIuL3BhdGhcIlxuaW1wb3J0IHtcbiAgY2xlYXJQYXRjaEFwcGxpY2F0aW9uU3RhdGUsXG4gIGdldFBhdGNoQXBwbGljYXRpb25TdGF0ZSxcbiAgUGF0Y2hTdGF0ZSxcbiAgc2F2ZVBhdGNoQXBwbGljYXRpb25TdGF0ZSxcbn0gZnJvbSBcIi4vc3RhdGVGaWxlXCJcblxuY2xhc3MgUGF0Y2hBcHBsaWNhdGlvbkVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZykge1xuICAgIHN1cGVyKG1zZylcbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRJbnN0YWxsZWRQYWNrYWdlVmVyc2lvbih7XG4gIGFwcFBhdGgsXG4gIHBhdGgsXG4gIHBhdGhTcGVjaWZpZXIsXG4gIGlzRGV2T25seSxcbiAgcGF0Y2hGaWxlbmFtZSxcbn06IHtcbiAgYXBwUGF0aDogc3RyaW5nXG4gIHBhdGg6IHN0cmluZ1xuICBwYXRoU3BlY2lmaWVyOiBzdHJpbmdcbiAgaXNEZXZPbmx5OiBib29sZWFuXG4gIHBhdGNoRmlsZW5hbWU6IHN0cmluZ1xufSk6IG51bGwgfCBzdHJpbmcge1xuICBjb25zdCBwYWNrYWdlRGlyID0gam9pbihhcHBQYXRoLCBwYXRoKVxuICBpZiAoIWV4aXN0c1N5bmMocGFja2FnZURpcikpIHtcbiAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IFwicHJvZHVjdGlvblwiICYmIGlzRGV2T25seSkge1xuICAgICAgcmV0dXJuIG51bGxcbiAgICB9XG5cbiAgICBsZXQgZXJyID1cbiAgICAgIGAke2NoYWxrLnJlZChcIkVycm9yOlwiKX0gUGF0Y2ggZmlsZSBmb3VuZCBmb3IgcGFja2FnZSAke3Bvc2l4LmJhc2VuYW1lKFxuICAgICAgICBwYXRoU3BlY2lmaWVyLFxuICAgICAgKX1gICsgYCB3aGljaCBpcyBub3QgcHJlc2VudCBhdCAke3JlbGF0aXZlKFwiLlwiLCBwYWNrYWdlRGlyKX1gXG5cbiAgICBpZiAoIWlzRGV2T25seSAmJiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gXCJwcm9kdWN0aW9uXCIpIHtcbiAgICAgIGVyciArPSBgXG5cbiAgSWYgdGhpcyBwYWNrYWdlIGlzIGEgZGV2IGRlcGVuZGVuY3ksIHJlbmFtZSB0aGUgcGF0Y2ggZmlsZSB0b1xuICBcbiAgICAke2NoYWxrLmJvbGQocGF0Y2hGaWxlbmFtZS5yZXBsYWNlKFwiLnBhdGNoXCIsIFwiLmRldi5wYXRjaFwiKSl9XG5gXG4gICAgfVxuICAgIHRocm93IG5ldyBQYXRjaEFwcGxpY2F0aW9uRXJyb3IoZXJyKVxuICB9XG5cbiAgY29uc3QgeyB2ZXJzaW9uIH0gPSByZXF1aXJlKGpvaW4ocGFja2FnZURpciwgXCJwYWNrYWdlLmpzb25cIikpXG4gIC8vIG5vcm1hbGl6ZSB2ZXJzaW9uIGZvciBgbnBtIGNpYFxuICBjb25zdCByZXN1bHQgPSBzZW12ZXIudmFsaWQodmVyc2lvbilcbiAgaWYgKHJlc3VsdCA9PT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBQYXRjaEFwcGxpY2F0aW9uRXJyb3IoXG4gICAgICBgJHtjaGFsay5yZWQoXG4gICAgICAgIFwiRXJyb3I6XCIsXG4gICAgICApfSBWZXJzaW9uIHN0cmluZyAnJHt2ZXJzaW9ufScgY2Fubm90IGJlIHBhcnNlZCBmcm9tICR7am9pbihcbiAgICAgICAgcGFja2FnZURpcixcbiAgICAgICAgXCJwYWNrYWdlLmpzb25cIixcbiAgICAgICl9YCxcbiAgICApXG4gIH1cblxuICByZXR1cm4gcmVzdWx0IGFzIHN0cmluZ1xufVxuXG5mdW5jdGlvbiBsb2dQYXRjaEFwcGxpY2F0aW9uKHBhdGNoRGV0YWlsczogUGF0Y2hlZFBhY2thZ2VEZXRhaWxzKSB7XG4gIGNvbnN0IHNlcXVlbmNlU3RyaW5nID1cbiAgICBwYXRjaERldGFpbHMuc2VxdWVuY2VOdW1iZXIgIT0gbnVsbFxuICAgICAgPyBgICgke3BhdGNoRGV0YWlscy5zZXF1ZW5jZU51bWJlcn0ke1xuICAgICAgICAgIHBhdGNoRGV0YWlscy5zZXF1ZW5jZU5hbWUgPyBcIiBcIiArIHBhdGNoRGV0YWlscy5zZXF1ZW5jZU5hbWUgOiBcIlwiXG4gICAgICAgIH0pYFxuICAgICAgOiBcIlwiXG4gIGNvbnNvbGUubG9nKFxuICAgIGAke2NoYWxrLmJvbGQocGF0Y2hEZXRhaWxzLnBhdGhTcGVjaWZpZXIpfUAke1xuICAgICAgcGF0Y2hEZXRhaWxzLnZlcnNpb25cbiAgICB9JHtzZXF1ZW5jZVN0cmluZ30gJHtjaGFsay5ncmVlbihcIuKclFwiKX1gLFxuICApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVBhdGNoZXNGb3JBcHAoe1xuICBhcHBQYXRoLFxuICByZXZlcnNlLFxuICBwYXRjaERpcixcbiAgc2hvdWxkRXhpdFdpdGhFcnJvcixcbiAgc2hvdWxkRXhpdFdpdGhXYXJuaW5nLFxuICBiZXN0RWZmb3J0LFxufToge1xuICBhcHBQYXRoOiBzdHJpbmdcbiAgcmV2ZXJzZTogYm9vbGVhblxuICBwYXRjaERpcjogc3RyaW5nXG4gIHNob3VsZEV4aXRXaXRoRXJyb3I6IGJvb2xlYW5cbiAgc2hvdWxkRXhpdFdpdGhXYXJuaW5nOiBib29sZWFuXG4gIGJlc3RFZmZvcnQ6IGJvb2xlYW5cbn0pOiB2b2lkIHtcbiAgY29uc3QgcGF0Y2hlc0RpcmVjdG9yeSA9IGpvaW4oYXBwUGF0aCwgcGF0Y2hEaXIpXG4gIGNvbnN0IGdyb3VwZWRQYXRjaGVzID0gZ2V0R3JvdXBlZFBhdGNoZXMocGF0Y2hlc0RpcmVjdG9yeSlcblxuICBpZiAoZ3JvdXBlZFBhdGNoZXMubnVtUGF0Y2hGaWxlcyA9PT0gMCkge1xuICAgIGNvbnNvbGUubG9nKGNoYWxrLmJsdWVCcmlnaHQoXCJObyBwYXRjaCBmaWxlcyBmb3VuZFwiKSlcbiAgICByZXR1cm5cbiAgfVxuXG4gIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXVxuICBjb25zdCB3YXJuaW5nczogc3RyaW5nW10gPSBbLi4uZ3JvdXBlZFBhdGNoZXMud2FybmluZ3NdXG5cbiAgZm9yIChjb25zdCBwYXRjaGVzIG9mIE9iamVjdC52YWx1ZXMoXG4gICAgZ3JvdXBlZFBhdGNoZXMucGF0aFNwZWNpZmllclRvUGF0Y2hGaWxlcyxcbiAgKSkge1xuICAgIGFwcGx5UGF0Y2hlc0ZvclBhY2thZ2Uoe1xuICAgICAgcGF0Y2hlcyxcbiAgICAgIGFwcFBhdGgsXG4gICAgICBwYXRjaERpcixcbiAgICAgIHJldmVyc2UsXG4gICAgICB3YXJuaW5ncyxcbiAgICAgIGVycm9ycyxcbiAgICAgIGJlc3RFZmZvcnQsXG4gICAgfSlcbiAgfVxuXG4gIGZvciAoY29uc3Qgd2FybmluZyBvZiB3YXJuaW5ncykge1xuICAgIGNvbnNvbGUubG9nKHdhcm5pbmcpXG4gIH1cbiAgZm9yIChjb25zdCBlcnJvciBvZiBlcnJvcnMpIHtcbiAgICBjb25zb2xlLmxvZyhlcnJvcilcbiAgfVxuXG4gIGNvbnN0IHByb2JsZW1zU3VtbWFyeSA9IFtdXG4gIGlmICh3YXJuaW5ncy5sZW5ndGgpIHtcbiAgICBwcm9ibGVtc1N1bW1hcnkucHVzaChjaGFsay55ZWxsb3coYCR7d2FybmluZ3MubGVuZ3RofSB3YXJuaW5nKHMpYCkpXG4gIH1cbiAgaWYgKGVycm9ycy5sZW5ndGgpIHtcbiAgICBwcm9ibGVtc1N1bW1hcnkucHVzaChjaGFsay5yZWQoYCR7ZXJyb3JzLmxlbmd0aH0gZXJyb3IocylgKSlcbiAgfVxuXG4gIGlmIChwcm9ibGVtc1N1bW1hcnkubGVuZ3RoKSB7XG4gICAgY29uc29sZS5sb2coXCItLS1cIilcbiAgICBjb25zb2xlLmxvZyhcInBhdGNoLXBhY2thZ2UgZmluaXNoZWQgd2l0aFwiLCBwcm9ibGVtc1N1bW1hcnkuam9pbihcIiwgXCIpICsgXCIuXCIpXG4gIH1cblxuICBpZiAoZXJyb3JzLmxlbmd0aCAmJiBzaG91bGRFeGl0V2l0aEVycm9yKSB7XG4gICAgcHJvY2Vzcy5leGl0KDEpXG4gIH1cblxuICBpZiAod2FybmluZ3MubGVuZ3RoICYmIHNob3VsZEV4aXRXaXRoV2FybmluZykge1xuICAgIHByb2Nlc3MuZXhpdCgxKVxuICB9XG5cbiAgcHJvY2Vzcy5leGl0KDApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVBhdGNoZXNGb3JQYWNrYWdlKHtcbiAgcGF0Y2hlcyxcbiAgYXBwUGF0aCxcbiAgcGF0Y2hEaXIsXG4gIHJldmVyc2UsXG4gIHdhcm5pbmdzLFxuICBlcnJvcnMsXG4gIGJlc3RFZmZvcnQsXG59OiB7XG4gIHBhdGNoZXM6IFBhdGNoZWRQYWNrYWdlRGV0YWlsc1tdXG4gIGFwcFBhdGg6IHN0cmluZ1xuICBwYXRjaERpcjogc3RyaW5nXG4gIHJldmVyc2U6IGJvb2xlYW5cbiAgd2FybmluZ3M6IHN0cmluZ1tdXG4gIGVycm9yczogc3RyaW5nW11cbiAgYmVzdEVmZm9ydDogYm9vbGVhblxufSkge1xuICBjb25zdCBwYXRoU3BlY2lmaWVyID0gcGF0Y2hlc1swXS5wYXRoU3BlY2lmaWVyXG4gIGNvbnN0IHN0YXRlID0gcGF0Y2hlcy5sZW5ndGggPiAxID8gZ2V0UGF0Y2hBcHBsaWNhdGlvblN0YXRlKHBhdGNoZXNbMF0pIDogbnVsbFxuICBjb25zdCB1bmFwcGxpZWRQYXRjaGVzID0gcGF0Y2hlcy5zbGljZSgwKVxuICBjb25zdCBhcHBsaWVkUGF0Y2hlczogUGF0Y2hlZFBhY2thZ2VEZXRhaWxzW10gPSBbXVxuICAvLyBpZiB0aGVyZSBhcmUgbXVsdGlwbGUgcGF0Y2hlcyB0byBhcHBseSwgd2UgY2FuJ3QgcmVseSBvbiB0aGUgcmV2ZXJzZS1wYXRjaC1kcnktcnVuIGJlaGF2aW9yIHRvIG1ha2UgdGhpcyBvcGVyYXRpb25cbiAgLy8gaWRlbXBvdGVudCwgc28gaW5zdGVhZCB3ZSBuZWVkIHRvIGNoZWNrIHRoZSBzdGF0ZSBmaWxlIHRvIHNlZSB3aGV0aGVyIHdlIGhhdmUgYWxyZWFkeSBhcHBsaWVkIGFueSBvZiB0aGUgcGF0Y2hlc1xuICAvLyB0b2RvOiBvbmNlIHRoaXMgaXMgYmF0dGxlIHRlc3RlZCB3ZSBtaWdodCB3YW50IHRvIHVzZSB0aGUgc2FtZSBhcHByb2FjaCBmb3Igc2luZ2xlIHBhdGNoZXMgYXMgd2VsbCwgYnV0IGl0J3Mgbm90IGJpZ2dpZSBzaW5jZSB0aGUgZHJ5IHJ1biB0aGluZyBpcyBmYXN0XG4gIGlmICh1bmFwcGxpZWRQYXRjaGVzICYmIHN0YXRlKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdGF0ZS5wYXRjaGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBwYXRjaFRoYXRXYXNBcHBsaWVkID0gc3RhdGUucGF0Y2hlc1tpXVxuICAgICAgaWYgKCFwYXRjaFRoYXRXYXNBcHBsaWVkLmRpZEFwcGx5KSB7XG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgICBjb25zdCBwYXRjaFRvQXBwbHkgPSB1bmFwcGxpZWRQYXRjaGVzWzBdXG4gICAgICBjb25zdCBjdXJyZW50UGF0Y2hIYXNoID0gaGFzaEZpbGUoXG4gICAgICAgIGpvaW4oYXBwUGF0aCwgcGF0Y2hEaXIsIHBhdGNoVG9BcHBseS5wYXRjaEZpbGVuYW1lKSxcbiAgICAgIClcbiAgICAgIGlmIChwYXRjaFRoYXRXYXNBcHBsaWVkLnBhdGNoQ29udGVudEhhc2ggPT09IGN1cnJlbnRQYXRjaEhhc2gpIHtcbiAgICAgICAgLy8gdGhpcyBwYXRjaCB3YXMgYXBwbGllZCB3ZSBjYW4gc2tpcCBpdFxuICAgICAgICBhcHBsaWVkUGF0Y2hlcy5wdXNoKHVuYXBwbGllZFBhdGNoZXMuc2hpZnQoKSEpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBjaGFsay5yZWQoXCJFcnJvcjpcIiksXG4gICAgICAgICAgYFRoZSBwYXRjaGVzIGZvciAke2NoYWxrLmJvbGQocGF0aFNwZWNpZmllcil9IGhhdmUgY2hhbmdlZC5gLFxuICAgICAgICAgIGBZb3Ugc2hvdWxkIHJlaW5zdGFsbCB5b3VyIG5vZGVfbW9kdWxlcyBmb2xkZXIgdG8gbWFrZSBzdXJlIHRoZSBwYWNrYWdlIGlzIHVwIHRvIGRhdGVgLFxuICAgICAgICApXG4gICAgICAgIHByb2Nlc3MuZXhpdCgxKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmIChyZXZlcnNlICYmIHN0YXRlKSB7XG4gICAgLy8gaWYgd2UgYXJlIHJldmVyc2luZyB0aGUgcGF0Y2hlcyB3ZSBuZWVkIHRvIG1ha2UgdGhlIHVuYXBwbGllZFBhdGNoZXMgYXJyYXlcbiAgICAvLyBiZSB0aGUgcmV2ZXJzZWQgdmVyc2lvbiBvZiB0aGUgYXBwbGllZFBhdGNoZXMgYXJyYXkuXG4gICAgLy8gVGhlIGFwcGxpZWQgcGF0Y2hlcyBhcnJheSBzaG91bGQgdGhlbiBiZSBlbXB0eSBiZWNhdXNlIGl0IGlzIHVzZWQgZGlmZmVyZW50bHlcbiAgICAvLyB3aGVuIG91dHB1dHRpbmcgdGhlIHN0YXRlIGZpbGUuXG4gICAgdW5hcHBsaWVkUGF0Y2hlcy5sZW5ndGggPSAwXG4gICAgdW5hcHBsaWVkUGF0Y2hlcy5wdXNoKC4uLmFwcGxpZWRQYXRjaGVzKVxuICAgIHVuYXBwbGllZFBhdGNoZXMucmV2ZXJzZSgpXG4gICAgYXBwbGllZFBhdGNoZXMubGVuZ3RoID0gMFxuICB9XG4gIGlmIChhcHBsaWVkUGF0Y2hlcy5sZW5ndGgpIHtcbiAgICAvLyBzb21lIHBhdGNoZXMgaGF2ZSBhbHJlYWR5IGJlZW4gYXBwbGllZFxuICAgIGFwcGxpZWRQYXRjaGVzLmZvckVhY2gobG9nUGF0Y2hBcHBsaWNhdGlvbilcbiAgfVxuICBpZiAoIXVuYXBwbGllZFBhdGNoZXMubGVuZ3RoKSB7XG4gICAgcmV0dXJuXG4gIH1cbiAgbGV0IGZhaWxlZFBhdGNoOiBQYXRjaGVkUGFja2FnZURldGFpbHMgfCBudWxsID0gbnVsbFxuICBwYWNrYWdlTG9vcDogZm9yIChjb25zdCBwYXRjaERldGFpbHMgb2YgdW5hcHBsaWVkUGF0Y2hlcykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IG5hbWUsIHZlcnNpb24sIHBhdGgsIGlzRGV2T25seSwgcGF0Y2hGaWxlbmFtZSB9ID0gcGF0Y2hEZXRhaWxzXG5cbiAgICAgIGNvbnN0IGluc3RhbGxlZFBhY2thZ2VWZXJzaW9uID0gZ2V0SW5zdGFsbGVkUGFja2FnZVZlcnNpb24oe1xuICAgICAgICBhcHBQYXRoLFxuICAgICAgICBwYXRoLFxuICAgICAgICBwYXRoU3BlY2lmaWVyLFxuICAgICAgICBpc0Rldk9ubHk6XG4gICAgICAgICAgaXNEZXZPbmx5IHx8XG4gICAgICAgICAgLy8gY2hlY2sgZm9yIGRpcmVjdC1kZXBlbmRlbnRzIGluIHByb2RcbiAgICAgICAgICAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09IFwicHJvZHVjdGlvblwiICYmXG4gICAgICAgICAgICBwYWNrYWdlSXNEZXZEZXBlbmRlbmN5KHtcbiAgICAgICAgICAgICAgYXBwUGF0aCxcbiAgICAgICAgICAgICAgcGF0Y2hEZXRhaWxzLFxuICAgICAgICAgICAgfSkpLFxuICAgICAgICBwYXRjaEZpbGVuYW1lLFxuICAgICAgfSlcbiAgICAgIGlmICghaW5zdGFsbGVkUGFja2FnZVZlcnNpb24pIHtcbiAgICAgICAgLy8gaXQncyBvayB3ZSdyZSBpbiBwcm9kdWN0aW9uIG1vZGUgYW5kIHRoaXMgaXMgYSBkZXYgb25seSBwYWNrYWdlXG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGBTa2lwcGluZyBkZXYtb25seSAke2NoYWxrLmJvbGQoXG4gICAgICAgICAgICBwYXRoU3BlY2lmaWVyLFxuICAgICAgICAgICl9QCR7dmVyc2lvbn0gJHtjaGFsay5ibHVlKFwi4pyUXCIpfWAsXG4gICAgICAgIClcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICBhcHBseVBhdGNoKHtcbiAgICAgICAgICBwYXRjaEZpbGVQYXRoOiBqb2luKGFwcFBhdGgsIHBhdGNoRGlyLCBwYXRjaEZpbGVuYW1lKSBhcyBzdHJpbmcsXG4gICAgICAgICAgcmV2ZXJzZSxcbiAgICAgICAgICBwYXRjaERldGFpbHMsXG4gICAgICAgICAgcGF0Y2hEaXIsXG4gICAgICAgICAgY3dkOiBwcm9jZXNzLmN3ZCgpLFxuICAgICAgICAgIGJlc3RFZmZvcnQsXG4gICAgICAgIH0pXG4gICAgICApIHtcbiAgICAgICAgYXBwbGllZFBhdGNoZXMucHVzaChwYXRjaERldGFpbHMpXG4gICAgICAgIC8vIHlheSBwYXRjaCB3YXMgYXBwbGllZCBzdWNjZXNzZnVsbHlcbiAgICAgICAgLy8gcHJpbnQgd2FybmluZyBpZiB2ZXJzaW9uIG1pc21hdGNoXG4gICAgICAgIGlmIChpbnN0YWxsZWRQYWNrYWdlVmVyc2lvbiAhPT0gdmVyc2lvbikge1xuICAgICAgICAgIHdhcm5pbmdzLnB1c2goXG4gICAgICAgICAgICBjcmVhdGVWZXJzaW9uTWlzbWF0Y2hXYXJuaW5nKHtcbiAgICAgICAgICAgICAgcGFja2FnZU5hbWU6IG5hbWUsXG4gICAgICAgICAgICAgIGFjdHVhbFZlcnNpb246IGluc3RhbGxlZFBhY2thZ2VWZXJzaW9uLFxuICAgICAgICAgICAgICBvcmlnaW5hbFZlcnNpb246IHZlcnNpb24sXG4gICAgICAgICAgICAgIHBhdGhTcGVjaWZpZXIsXG4gICAgICAgICAgICAgIHBhdGgsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApXG4gICAgICAgIH1cbiAgICAgICAgbG9nUGF0Y2hBcHBsaWNhdGlvbihwYXRjaERldGFpbHMpXG4gICAgICB9IGVsc2UgaWYgKHBhdGNoZXMubGVuZ3RoID4gMSkge1xuICAgICAgICBsb2dQYXRjaFNlcXVlbmNlRXJyb3IoeyBwYXRjaERldGFpbHMgfSlcbiAgICAgICAgLy8gaW4gY2FzZSB0aGUgcGFja2FnZSBoYXMgbXVsdGlwbGUgcGF0Y2hlcywgd2UgbmVlZCB0byBicmVhayBvdXQgb2YgdGhpcyBpbm5lciBsb29wXG4gICAgICAgIC8vIGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudCB0byBhcHBseSBtb3JlIHBhdGNoZXMgb24gdG9wIG9mIHRoZSBicm9rZW4gc3RhdGVcbiAgICAgICAgZmFpbGVkUGF0Y2ggPSBwYXRjaERldGFpbHNcbiAgICAgICAgYnJlYWsgcGFja2FnZUxvb3BcbiAgICAgIH0gZWxzZSBpZiAoaW5zdGFsbGVkUGFja2FnZVZlcnNpb24gPT09IHZlcnNpb24pIHtcbiAgICAgICAgLy8gY29tcGxldGVseSBmYWlsZWQgdG8gYXBwbHkgcGF0Y2hcbiAgICAgICAgLy8gVE9ETzogcHJvcGFnYXRlIHVzZWZ1bCBlcnJvciBtZXNzYWdlcyBmcm9tIHBhdGNoIGFwcGxpY2F0aW9uXG4gICAgICAgIGVycm9ycy5wdXNoKFxuICAgICAgICAgIGNyZWF0ZUJyb2tlblBhdGNoRmlsZUVycm9yKHtcbiAgICAgICAgICAgIHBhY2thZ2VOYW1lOiBuYW1lLFxuICAgICAgICAgICAgcGF0Y2hGaWxlbmFtZSxcbiAgICAgICAgICAgIHBhdGhTcGVjaWZpZXIsXG4gICAgICAgICAgICBwYXRoLFxuICAgICAgICAgIH0pLFxuICAgICAgICApXG4gICAgICAgIGJyZWFrIHBhY2thZ2VMb29wXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlcnJvcnMucHVzaChcbiAgICAgICAgICBjcmVhdGVQYXRjaEFwcGxpY2F0aW9uRmFpbHVyZUVycm9yKHtcbiAgICAgICAgICAgIHBhY2thZ2VOYW1lOiBuYW1lLFxuICAgICAgICAgICAgYWN0dWFsVmVyc2lvbjogaW5zdGFsbGVkUGFja2FnZVZlcnNpb24sXG4gICAgICAgICAgICBvcmlnaW5hbFZlcnNpb246IHZlcnNpb24sXG4gICAgICAgICAgICBwYXRjaEZpbGVuYW1lLFxuICAgICAgICAgICAgcGF0aCxcbiAgICAgICAgICAgIHBhdGhTcGVjaWZpZXIsXG4gICAgICAgICAgfSksXG4gICAgICAgIClcbiAgICAgICAgLy8gaW4gY2FzZSB0aGUgcGFja2FnZSBoYXMgbXVsdGlwbGUgcGF0Y2hlcywgd2UgbmVlZCB0byBicmVhayBvdXQgb2YgdGhpcyBpbm5lciBsb29wXG4gICAgICAgIC8vIGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudCB0byBhcHBseSBtb3JlIHBhdGNoZXMgb24gdG9wIG9mIHRoZSBicm9rZW4gc3RhdGVcbiAgICAgICAgYnJlYWsgcGFja2FnZUxvb3BcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgUGF0Y2hBcHBsaWNhdGlvbkVycm9yKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGVycm9yLm1lc3NhZ2UpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBlcnJvcnMucHVzaChcbiAgICAgICAgICBjcmVhdGVVbmV4cGVjdGVkRXJyb3Ioe1xuICAgICAgICAgICAgZmlsZW5hbWU6IHBhdGNoRGV0YWlscy5wYXRjaEZpbGVuYW1lLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yIGFzIEVycm9yLFxuICAgICAgICAgIH0pLFxuICAgICAgICApXG4gICAgICB9XG4gICAgICAvLyBpbiBjYXNlIHRoZSBwYWNrYWdlIGhhcyBtdWx0aXBsZSBwYXRjaGVzLCB3ZSBuZWVkIHRvIGJyZWFrIG91dCBvZiB0aGlzIGlubmVyIGxvb3BcbiAgICAgIC8vIGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudCB0byBhcHBseSBtb3JlIHBhdGNoZXMgb24gdG9wIG9mIHRoZSBicm9rZW4gc3RhdGVcbiAgICAgIGJyZWFrIHBhY2thZ2VMb29wXG4gICAgfVxuICB9XG5cbiAgaWYgKHBhdGNoZXMubGVuZ3RoID4gMSkge1xuICAgIGlmIChyZXZlcnNlKSB7XG4gICAgICBpZiAoIXN0YXRlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcInVuZXhwZWN0ZWQgc3RhdGU6IG5vIHN0YXRlIGZpbGUgZm91bmQgd2hpbGUgcmV2ZXJzaW5nXCIpXG4gICAgICB9XG4gICAgICAvLyBpZiB3ZSByZW1vdmVkIGFsbCB0aGUgcGF0Y2hlcyB0aGF0IHdlcmUgcHJldmlvdXNseSBhcHBsaWVkIHdlIGNhbiBkZWxldGUgdGhlIHN0YXRlIGZpbGVcbiAgICAgIGlmIChhcHBsaWVkUGF0Y2hlcy5sZW5ndGggPT09IHBhdGNoZXMubGVuZ3RoKSB7XG4gICAgICAgIGNsZWFyUGF0Y2hBcHBsaWNhdGlvblN0YXRlKHBhdGNoZXNbMF0pXG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBXZSBmYWlsZWQgd2hpbGUgcmV2ZXJzaW5nIHBhdGNoZXMgYW5kIHNvbWUgYXJlIHN0aWxsIGluIHRoZSBhcHBsaWVkIHN0YXRlLlxuICAgICAgICAvLyBXZSBuZWVkIHRvIHVwZGF0ZSB0aGUgc3RhdGUgZmlsZSB0byByZWZsZWN0IHRoYXQuXG4gICAgICAgIC8vIGFwcGxpZWRQYXRjaGVzIGlzIGN1cnJlbnRseSB0aGUgcGF0Y2hlcyB0aGF0IHdlcmUgc3VjY2Vzc2Z1bGx5IHJldmVyc2VkLCBpbiB0aGUgb3JkZXIgdGhleSB3ZXJlIHJldmVyc2VkXG4gICAgICAgIC8vIFNvIHdlIG5lZWQgdG8gZmluZCB0aGUgaW5kZXggb2YgdGhlIGxhc3QgcmV2ZXJzZWQgcGF0Y2ggaW4gdGhlIG9yaWdpbmFsIHBhdGNoZXMgYXJyYXlcbiAgICAgICAgLy8gYW5kIHRoZW4gcmVtb3ZlIGFsbCB0aGUgcGF0Y2hlcyBhZnRlciB0aGF0LiBTb3JyeSBmb3IgdGhlIGNvbmZ1c2luZyBjb2RlLlxuICAgICAgICBjb25zdCBsYXN0UmV2ZXJzZWRQYXRjaEluZGV4ID0gcGF0Y2hlcy5pbmRleE9mKFxuICAgICAgICAgIGFwcGxpZWRQYXRjaGVzW2FwcGxpZWRQYXRjaGVzLmxlbmd0aCAtIDFdLFxuICAgICAgICApXG4gICAgICAgIGlmIChsYXN0UmV2ZXJzZWRQYXRjaEluZGV4ID09PSAtMSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIFwidW5leHBlY3RlZCBzdGF0ZTogZmFpbGVkIHRvIGZpbmQgbGFzdCByZXZlcnNlZCBwYXRjaCBpbiBvcmlnaW5hbCBwYXRjaGVzIGFycmF5XCIsXG4gICAgICAgICAgKVxuICAgICAgICB9XG5cbiAgICAgICAgc2F2ZVBhdGNoQXBwbGljYXRpb25TdGF0ZSh7XG4gICAgICAgICAgcGFja2FnZURldGFpbHM6IHBhdGNoZXNbMF0sXG4gICAgICAgICAgcGF0Y2hlczogcGF0Y2hlcy5zbGljZSgwLCBsYXN0UmV2ZXJzZWRQYXRjaEluZGV4KS5tYXAoKHBhdGNoKSA9PiAoe1xuICAgICAgICAgICAgZGlkQXBwbHk6IHRydWUsXG4gICAgICAgICAgICBwYXRjaENvbnRlbnRIYXNoOiBoYXNoRmlsZShcbiAgICAgICAgICAgICAgam9pbihhcHBQYXRoLCBwYXRjaERpciwgcGF0Y2gucGF0Y2hGaWxlbmFtZSksXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgcGF0Y2hGaWxlbmFtZTogcGF0Y2gucGF0Y2hGaWxlbmFtZSxcbiAgICAgICAgICB9KSksXG4gICAgICAgICAgaXNSZWJhc2luZzogZmFsc2UsXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5leHRTdGF0ZSA9IGFwcGxpZWRQYXRjaGVzLm1hcChcbiAgICAgICAgKHBhdGNoKTogUGF0Y2hTdGF0ZSA9PiAoe1xuICAgICAgICAgIGRpZEFwcGx5OiB0cnVlLFxuICAgICAgICAgIHBhdGNoQ29udGVudEhhc2g6IGhhc2hGaWxlKFxuICAgICAgICAgICAgam9pbihhcHBQYXRoLCBwYXRjaERpciwgcGF0Y2gucGF0Y2hGaWxlbmFtZSksXG4gICAgICAgICAgKSxcbiAgICAgICAgICBwYXRjaEZpbGVuYW1lOiBwYXRjaC5wYXRjaEZpbGVuYW1lLFxuICAgICAgICB9KSxcbiAgICAgIClcblxuICAgICAgaWYgKGZhaWxlZFBhdGNoKSB7XG4gICAgICAgIG5leHRTdGF0ZS5wdXNoKHtcbiAgICAgICAgICBkaWRBcHBseTogZmFsc2UsXG4gICAgICAgICAgcGF0Y2hDb250ZW50SGFzaDogaGFzaEZpbGUoXG4gICAgICAgICAgICBqb2luKGFwcFBhdGgsIHBhdGNoRGlyLCBmYWlsZWRQYXRjaC5wYXRjaEZpbGVuYW1lKSxcbiAgICAgICAgICApLFxuICAgICAgICAgIHBhdGNoRmlsZW5hbWU6IGZhaWxlZFBhdGNoLnBhdGNoRmlsZW5hbWUsXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgICBzYXZlUGF0Y2hBcHBsaWNhdGlvblN0YXRlKHtcbiAgICAgICAgcGFja2FnZURldGFpbHM6IHBhdGNoZXNbMF0sXG4gICAgICAgIHBhdGNoZXM6IG5leHRTdGF0ZSxcbiAgICAgICAgaXNSZWJhc2luZzogISFmYWlsZWRQYXRjaCxcbiAgICAgIH0pXG4gICAgfVxuICAgIGlmIChmYWlsZWRQYXRjaCkge1xuICAgICAgcHJvY2Vzcy5leGl0KDEpXG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVBhdGNoKHtcbiAgcGF0Y2hGaWxlUGF0aCxcbiAgcmV2ZXJzZSxcbiAgcGF0Y2hEZXRhaWxzLFxuICBwYXRjaERpcixcbiAgY3dkLFxuICBiZXN0RWZmb3J0LFxufToge1xuICBwYXRjaEZpbGVQYXRoOiBzdHJpbmdcbiAgcmV2ZXJzZTogYm9vbGVhblxuICBwYXRjaERldGFpbHM6IFBhY2thZ2VEZXRhaWxzXG4gIHBhdGNoRGlyOiBzdHJpbmdcbiAgY3dkOiBzdHJpbmdcbiAgYmVzdEVmZm9ydDogYm9vbGVhblxufSk6IGJvb2xlYW4ge1xuICBjb25zdCBwYXRjaCA9IHJlYWRQYXRjaCh7XG4gICAgcGF0Y2hGaWxlUGF0aCxcbiAgICBwYXRjaERldGFpbHMsXG4gICAgcGF0Y2hEaXIsXG4gIH0pXG5cbiAgY29uc3QgZm9yd2FyZCA9IHJldmVyc2UgPyByZXZlcnNlUGF0Y2gocGF0Y2gpIDogcGF0Y2hcbiAgdHJ5IHtcbiAgICBpZiAoIWJlc3RFZmZvcnQpIHtcbiAgICAgIGV4ZWN1dGVFZmZlY3RzKGZvcndhcmQsIHsgZHJ5UnVuOiB0cnVlLCBjd2QsIGJlc3RFZmZvcnQ6IGZhbHNlIH0pXG4gICAgfVxuICAgIGNvbnN0IGVycm9yczogc3RyaW5nW10gfCB1bmRlZmluZWQgPSBiZXN0RWZmb3J0ID8gW10gOiB1bmRlZmluZWRcbiAgICBleGVjdXRlRWZmZWN0cyhmb3J3YXJkLCB7IGRyeVJ1bjogZmFsc2UsIGN3ZCwgYmVzdEVmZm9ydCwgZXJyb3JzIH0pXG4gICAgaWYgKGVycm9ycz8ubGVuZ3RoKSB7XG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgXCJTYXZpbmcgZXJyb3JzIHRvXCIsXG4gICAgICAgIGNoYWxrLmN5YW4uYm9sZChcIi4vcGF0Y2gtcGFja2FnZS1lcnJvcnMubG9nXCIpLFxuICAgICAgKVxuICAgICAgd3JpdGVGaWxlU3luYyhcInBhdGNoLXBhY2thZ2UtZXJyb3JzLmxvZ1wiLCBlcnJvcnMuam9pbihcIlxcblxcblwiKSlcbiAgICAgIHByb2Nlc3MuZXhpdCgwKVxuICAgIH1cbiAgfSBjYXRjaCAoZSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBiYWNrd2FyZCA9IHJldmVyc2UgPyBwYXRjaCA6IHJldmVyc2VQYXRjaChwYXRjaClcbiAgICAgIGV4ZWN1dGVFZmZlY3RzKGJhY2t3YXJkLCB7XG4gICAgICAgIGRyeVJ1bjogdHJ1ZSxcbiAgICAgICAgY3dkLFxuICAgICAgICBiZXN0RWZmb3J0OiBmYWxzZSxcbiAgICAgIH0pXG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRydWVcbn1cblxuZnVuY3Rpb24gY3JlYXRlVmVyc2lvbk1pc21hdGNoV2FybmluZyh7XG4gIHBhY2thZ2VOYW1lLFxuICBhY3R1YWxWZXJzaW9uLFxuICBvcmlnaW5hbFZlcnNpb24sXG4gIHBhdGhTcGVjaWZpZXIsXG4gIHBhdGgsXG59OiB7XG4gIHBhY2thZ2VOYW1lOiBzdHJpbmdcbiAgYWN0dWFsVmVyc2lvbjogc3RyaW5nXG4gIG9yaWdpbmFsVmVyc2lvbjogc3RyaW5nXG4gIHBhdGhTcGVjaWZpZXI6IHN0cmluZ1xuICBwYXRoOiBzdHJpbmdcbn0pIHtcbiAgcmV0dXJuIGBcbiR7Y2hhbGsueWVsbG93KFwiV2FybmluZzpcIil9IHBhdGNoLXBhY2thZ2UgZGV0ZWN0ZWQgYSBwYXRjaCBmaWxlIHZlcnNpb24gbWlzbWF0Y2hcblxuICBEb24ndCB3b3JyeSEgVGhpcyBpcyBwcm9iYWJseSBmaW5lLiBUaGUgcGF0Y2ggd2FzIHN0aWxsIGFwcGxpZWRcbiAgc3VjY2Vzc2Z1bGx5LiBIZXJlJ3MgdGhlIGRlZXRzOlxuXG4gIFBhdGNoIGZpbGUgY3JlYXRlZCBmb3JcblxuICAgICR7cGFja2FnZU5hbWV9QCR7Y2hhbGsuYm9sZChvcmlnaW5hbFZlcnNpb24pfVxuXG4gIGFwcGxpZWQgdG9cblxuICAgICR7cGFja2FnZU5hbWV9QCR7Y2hhbGsuYm9sZChhY3R1YWxWZXJzaW9uKX1cbiAgXG4gIEF0IHBhdGhcbiAgXG4gICAgJHtwYXRofVxuXG4gIFRoaXMgd2FybmluZyBpcyBqdXN0IHRvIGdpdmUgeW91IGEgaGVhZHMtdXAuIFRoZXJlIGlzIGEgc21hbGwgY2hhbmNlIG9mXG4gIGJyZWFrYWdlIGV2ZW4gdGhvdWdoIHRoZSBwYXRjaCB3YXMgYXBwbGllZCBzdWNjZXNzZnVsbHkuIE1ha2Ugc3VyZSB0aGUgcGFja2FnZVxuICBzdGlsbCBiZWhhdmVzIGxpa2UgeW91IGV4cGVjdCAoeW91IHdyb3RlIHRlc3RzLCByaWdodD8pIGFuZCB0aGVuIHJ1blxuXG4gICAgJHtjaGFsay5ib2xkKGBwYXRjaC1wYWNrYWdlICR7cGF0aFNwZWNpZmllcn1gKX1cblxuICB0byB1cGRhdGUgdGhlIHZlcnNpb24gaW4gdGhlIHBhdGNoIGZpbGUgbmFtZSBhbmQgbWFrZSB0aGlzIHdhcm5pbmcgZ28gYXdheS5cbmBcbn1cblxuZnVuY3Rpb24gY3JlYXRlQnJva2VuUGF0Y2hGaWxlRXJyb3Ioe1xuICBwYWNrYWdlTmFtZSxcbiAgcGF0Y2hGaWxlbmFtZSxcbiAgcGF0aCxcbiAgcGF0aFNwZWNpZmllcixcbn06IHtcbiAgcGFja2FnZU5hbWU6IHN0cmluZ1xuICBwYXRjaEZpbGVuYW1lOiBzdHJpbmdcbiAgcGF0aDogc3RyaW5nXG4gIHBhdGhTcGVjaWZpZXI6IHN0cmluZ1xufSkge1xuICByZXR1cm4gYFxuJHtjaGFsay5yZWQuYm9sZChcIioqRVJST1IqKlwiKX0gJHtjaGFsay5yZWQoXG4gICAgYEZhaWxlZCB0byBhcHBseSBwYXRjaCBmb3IgcGFja2FnZSAke2NoYWxrLmJvbGQocGFja2FnZU5hbWUpfSBhdCBwYXRoYCxcbiAgKX1cbiAgXG4gICAgJHtwYXRofVxuXG4gIFRoaXMgZXJyb3Igd2FzIGNhdXNlZCBiZWNhdXNlIHBhdGNoLXBhY2thZ2UgY2Fubm90IGFwcGx5IHRoZSBmb2xsb3dpbmcgcGF0Y2ggZmlsZTpcblxuICAgIHBhdGNoZXMvJHtwYXRjaEZpbGVuYW1lfVxuXG4gIFRyeSByZW1vdmluZyBub2RlX21vZHVsZXMgYW5kIHRyeWluZyBhZ2Fpbi4gSWYgdGhhdCBkb2Vzbid0IHdvcmssIG1heWJlIHRoZXJlIHdhc1xuICBhbiBhY2NpZGVudGFsIGNoYW5nZSBtYWRlIHRvIHRoZSBwYXRjaCBmaWxlPyBUcnkgcmVjcmVhdGluZyBpdCBieSBtYW51YWxseVxuICBlZGl0aW5nIHRoZSBhcHByb3ByaWF0ZSBmaWxlcyBhbmQgcnVubmluZzpcbiAgXG4gICAgcGF0Y2gtcGFja2FnZSAke3BhdGhTcGVjaWZpZXJ9XG4gIFxuICBJZiB0aGF0IGRvZXNuJ3Qgd29yaywgdGhlbiBpdCdzIGEgYnVnIGluIHBhdGNoLXBhY2thZ2UsIHNvIHBsZWFzZSBzdWJtaXQgYSBidWdcbiAgcmVwb3J0LiBUaGFua3MhXG5cbiAgICBodHRwczovL2dpdGh1Yi5jb20vZHMzMDAvcGF0Y2gtcGFja2FnZS9pc3N1ZXNcbiAgICBcbmBcbn1cblxuZnVuY3Rpb24gY3JlYXRlUGF0Y2hBcHBsaWNhdGlvbkZhaWx1cmVFcnJvcih7XG4gIHBhY2thZ2VOYW1lLFxuICBhY3R1YWxWZXJzaW9uLFxuICBvcmlnaW5hbFZlcnNpb24sXG4gIHBhdGNoRmlsZW5hbWUsXG4gIHBhdGgsXG4gIHBhdGhTcGVjaWZpZXIsXG59OiB7XG4gIHBhY2thZ2VOYW1lOiBzdHJpbmdcbiAgYWN0dWFsVmVyc2lvbjogc3RyaW5nXG4gIG9yaWdpbmFsVmVyc2lvbjogc3RyaW5nXG4gIHBhdGNoRmlsZW5hbWU6IHN0cmluZ1xuICBwYXRoOiBzdHJpbmdcbiAgcGF0aFNwZWNpZmllcjogc3RyaW5nXG59KSB7XG4gIHJldHVybiBgXG4ke2NoYWxrLnJlZC5ib2xkKFwiKipFUlJPUioqXCIpfSAke2NoYWxrLnJlZChcbiAgICBgRmFpbGVkIHRvIGFwcGx5IHBhdGNoIGZvciBwYWNrYWdlICR7Y2hhbGsuYm9sZChwYWNrYWdlTmFtZSl9IGF0IHBhdGhgLFxuICApfVxuICBcbiAgICAke3BhdGh9XG5cbiAgVGhpcyBlcnJvciB3YXMgY2F1c2VkIGJlY2F1c2UgJHtjaGFsay5ib2xkKHBhY2thZ2VOYW1lKX0gaGFzIGNoYW5nZWQgc2luY2UgeW91XG4gIG1hZGUgdGhlIHBhdGNoIGZpbGUgZm9yIGl0LiBUaGlzIGludHJvZHVjZWQgY29uZmxpY3RzIHdpdGggeW91ciBwYXRjaCxcbiAganVzdCBsaWtlIGEgbWVyZ2UgY29uZmxpY3QgaW4gR2l0IHdoZW4gc2VwYXJhdGUgaW5jb21wYXRpYmxlIGNoYW5nZXMgYXJlXG4gIG1hZGUgdG8gdGhlIHNhbWUgcGllY2Ugb2YgY29kZS5cblxuICBNYXliZSB0aGlzIG1lYW5zIHlvdXIgcGF0Y2ggZmlsZSBpcyBubyBsb25nZXIgbmVjZXNzYXJ5LCBpbiB3aGljaCBjYXNlXG4gIGhvb3JheSEgSnVzdCBkZWxldGUgaXQhXG5cbiAgT3RoZXJ3aXNlLCB5b3UgbmVlZCB0byBnZW5lcmF0ZSBhIG5ldyBwYXRjaCBmaWxlLlxuXG4gIFRvIGdlbmVyYXRlIGEgbmV3IG9uZSwganVzdCByZXBlYXQgdGhlIHN0ZXBzIHlvdSBtYWRlIHRvIGdlbmVyYXRlIHRoZSBmaXJzdFxuICBvbmUuXG5cbiAgaS5lLiBtYW51YWxseSBtYWtlIHRoZSBhcHByb3ByaWF0ZSBmaWxlIGNoYW5nZXMsIHRoZW4gcnVuIFxuXG4gICAgcGF0Y2gtcGFja2FnZSAke3BhdGhTcGVjaWZpZXJ9XG5cbiAgSW5mbzpcbiAgICBQYXRjaCBmaWxlOiBwYXRjaGVzLyR7cGF0Y2hGaWxlbmFtZX1cbiAgICBQYXRjaCB3YXMgbWFkZSBmb3IgdmVyc2lvbjogJHtjaGFsay5ncmVlbi5ib2xkKG9yaWdpbmFsVmVyc2lvbil9XG4gICAgSW5zdGFsbGVkIHZlcnNpb246ICR7Y2hhbGsucmVkLmJvbGQoYWN0dWFsVmVyc2lvbil9XG5gXG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVVuZXhwZWN0ZWRFcnJvcih7XG4gIGZpbGVuYW1lLFxuICBlcnJvcixcbn06IHtcbiAgZmlsZW5hbWU6IHN0cmluZ1xuICBlcnJvcjogRXJyb3Jcbn0pIHtcbiAgcmV0dXJuIGBcbiR7Y2hhbGsucmVkLmJvbGQoXCIqKkVSUk9SKipcIil9ICR7Y2hhbGsucmVkKFxuICAgIGBGYWlsZWQgdG8gYXBwbHkgcGF0Y2ggZmlsZSAke2NoYWxrLmJvbGQoZmlsZW5hbWUpfWAsXG4gICl9XG4gIFxuJHtlcnJvci5zdGFja31cblxuICBgXG59XG4iXX0=