projen
Version:
CDK for software projects
258 lines • 41.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.bump = bump;
const fs_1 = require("fs");
const path_1 = require("path");
const semver_1 = require("semver");
const logging = require("../logging");
const util_1 = require("../util");
const version_1 = require("../version");
const bump_type_1 = require("./bump-type");
const commit_tag_version_1 = require("./commit-tag-version");
/**
* Resolves the latest version from git tags and uses `commit-and-tag-version` to bump
* to the next version based on commits.
*
* This expects `commit-and-tag-version` to be installed in the path.
*
* @param cwd working directory (git repository)
* @param options options
*/
async function bump(cwd, options) {
const versionFile = (0, path_1.join)(cwd, options.versionFile);
const prerelease = options.prerelease;
const major = options.majorVersion;
const minor = options.minorVersion;
const minMajorVersion = options.minMajorVersion;
const tagPrefix = options.tagPrefix ?? "";
const bumpFile = (0, path_1.join)(cwd, options.bumpFile);
const changelogFile = (0, path_1.join)(cwd, options.changelog);
const releaseTagFile = (0, path_1.join)(cwd, options.releaseTagFile);
if (major && minMajorVersion) {
throw new Error(`minMajorVersion and majorVersion cannot be used together.`);
}
if (options.nextVersionCommand && minMajorVersion) {
throw new Error(`minMajorVersion and nextVersionCommand cannot be used together.`);
}
if (minor && !major) {
throw new Error(`minorVersion and majorVersion must be used together.`);
}
await fs_1.promises.mkdir((0, path_1.dirname)(bumpFile), { recursive: true });
await fs_1.promises.mkdir((0, path_1.dirname)(changelogFile), { recursive: true });
await fs_1.promises.mkdir((0, path_1.dirname)(releaseTagFile), { recursive: true });
const { latestVersion, latestTag, isFirstRelease } = determineLatestTag({
cwd,
major,
minor,
prerelease,
prefix: tagPrefix,
});
// Write the current version into the version file so that CATV will know the current version
const { contents, newline } = await tryReadVersionFile(versionFile);
contents.version = latestVersion;
logging.info(`Update ${versionFile} to latest resolved version: ${latestVersion}`);
await fs_1.promises.writeFile(versionFile, JSON.stringify(contents, undefined, 2) + (newline ? "\n" : ""));
// Determine the initial bump status. CATV will always do a patch even if
// there are no commits, so look at commits ourselves first to decide
// if we even should do nothing at all.
const shouldRelease = isFirstRelease
? true
: hasNewInterestingCommits({
cwd,
latestTag,
releasableCommits: options.releasableCommits,
});
const catv = new commit_tag_version_1.CommitAndTagVersion(options.bumpPackage, cwd, {
versionFile,
changelogFile,
prerelease,
configOptions: options.versionrcOptions,
tagPrefix,
});
// We used to translate `isFirstRelease` to the `--first-release` flag of CATV.
// What that does is skip a bump, only generate the changelog.
//
// Our `{ bump: none }` does the same, so we don't need to carry over this
// flag anymore.
let bumpType = shouldRelease && !isFirstRelease
? (0, bump_type_1.relativeBumpType)(latestVersion, await catv.dryRun())
: { bump: "none" };
logging.info(`Bump from commits: ${(0, bump_type_1.renderBumpType)(bumpType)}`);
if (options.nextVersionCommand) {
const nextVersion = (0, util_1.execCapture)(options.nextVersionCommand, {
cwd,
modEnv: {
VERSION: latestVersion,
SUGGESTED_BUMP: (0, bump_type_1.renderBumpType)(bumpType),
...(latestTag ? { LATEST_TAG: latestTag } : {}),
},
})
.toString()
.trim();
if (nextVersion) {
try {
bumpType = (0, bump_type_1.parseBumpType)(nextVersion);
logging.info(`Bump from nextVersionCommand: ${(0, bump_type_1.renderBumpType)(bumpType)}`);
}
catch (e) {
throw new Error(`nextVersionCommand "${options.nextVersionCommand}" returned invalid output: ${e}`);
}
}
}
// Respect minMajorVersion to correct the result of the nextVersionCommand
if (minMajorVersion) {
const bumpedVersion = (0, bump_type_1.performBump)(latestVersion, bumpType);
const [majorVersion] = bumpedVersion.split(".");
const majorVersionNumber = parseInt(majorVersion, 10);
if (majorVersionNumber < minMajorVersion) {
bumpType = { bump: "absolute", absolute: `${minMajorVersion}.0.0` };
}
}
// Invoke CATV with the options we landed on. If we decided not to do a bump,
// we will use this to regenerate the changelog of the most recent version.
const newRelease = bumpType.bump !== "none";
// If we're not doing a new release and this is not the
// first release, we're just regenerating the previous changelog again.
if (!newRelease && !isFirstRelease) {
await catv.regeneratePreviousChangeLog(latestVersion, latestTag);
}
else {
// Otherwise we're either doing a bump + release, or we're releasing the
// first version as 0.0.0 (which is already the number in the file so we
// skip bumping).
await catv.invoke({
releaseAs: newRelease ? (0, bump_type_1.renderBumpType)(bumpType) : undefined,
skipBump: !newRelease,
});
}
// Validate the version that we ended up with
const newVersion = (await tryReadVersionFile(versionFile)).version;
if (!newVersion) {
throw new Error(`bump failed: ${versionFile} does not have a version set`);
}
if (major) {
if (!newVersion.startsWith(`${major}.`)) {
throw new Error(`bump failed: this branch is configured to only publish v${major} releases - bump resulted in ${newVersion}`);
}
}
if (minor) {
if (!newVersion.startsWith(`${major}.${minor}`)) {
throw new Error(`bump failed: this branch is configured to only publish v${major}.${minor} releases - bump resulted in ${newVersion}`);
}
}
// Report curent status into the dist/ directory
const newTag = `${tagPrefix}v${newVersion}`;
await fs_1.promises.writeFile(bumpFile, newVersion);
await fs_1.promises.writeFile(releaseTagFile, newTag);
}
/**
* Determine based on releaseable commits whether we should release or not
*/
function hasNewInterestingCommits(options) {
const findCommits = (options.releasableCommits ?? version_1.ReleasableCommits.everyCommit().cmd).replace("$LATEST_TAG", options.latestTag);
const commitsSinceLastTag = (0, util_1.execOrUndefined)(findCommits, {
cwd: options.cwd,
})?.split("\n");
const numCommitsSinceLastTag = commitsSinceLastTag?.length ?? 0;
logging.info(`Number of commits since ${options.latestTag}: ${numCommitsSinceLastTag}`);
// Nothing to release right now
if (numCommitsSinceLastTag === 0) {
logging.info("No new interesting commits.");
return false;
}
return true;
}
async function tryReadVersionFile(versionFile) {
if (!(0, fs_1.existsSync)(versionFile)) {
return { contents: {}, newline: true };
}
const raw = await fs_1.promises.readFile(versionFile, "utf-8");
const contents = JSON.parse(raw);
return {
contents,
version: contents.version,
newline: raw.endsWith("\n"),
};
}
/**
* Determines the latest release tag.
* @param major (optional) A major version line to select from
* @param prerelease (optional) A pre-release suffix.
* @returns the latest tag, and whether it is the first release or not
*/
function determineLatestTag(options) {
const { cwd, major, minor, prerelease, prefix } = options;
// filter only tags for this prefix and major version if specified (start with "vNN.").
let prefixFilter;
if (major !== undefined && minor !== undefined) {
prefixFilter = `${prefix}v${major}.${minor}.*`;
}
else if (major !== undefined) {
prefixFilter = `${prefix}v${major}.*`;
}
else {
prefixFilter = `${prefix}v*`;
}
const listGitTags = [
"git",
'-c "versionsort.suffix=-"', // makes sure pre-release versions are listed after the primary version
"tag",
'--sort="-version:refname"', // sort as versions and not lexicographically
"--list",
`"${prefixFilter}"`,
].join(" ");
const stdout = (0, util_1.execCapture)(listGitTags, { cwd }).toString("utf8");
let tags = stdout?.split("\n");
// if prerelease is set and there are existing prerelease tags, filter versions that end with "-PRE.ddd".
const prereleaseTags = tags.filter((x) => new RegExp(`-${prerelease}\\.[0-9]+$`).test(x));
if (prerelease && prereleaseTags.length > 0) {
let prereleaseTag = prereleaseTags[0];
/**
* Cover the following case specifically
* 1 - v1.0.0
* 2 - v1.0.1-beta.0
* 3 - v1.0.1-beta.1
* 4 - v1.0.1
* 5 - now publish a new release on the prerelease branch
* by setting the latestTag as v1.0.1 instead of v1.0.1-beta.1
*/
const releaseTags = tags.filter((x) => new RegExp(`^${prefix}v([0-9]+)\\.([0-9]+)\\.([0-9]+)$`).test(x));
let releaseTag;
if (releaseTags.length > 0) {
releaseTag = releaseTags[0];
}
if (prefix) {
releaseTag = releaseTag?.substring(prefix.length);
prereleaseTag = prereleaseTag.substring(prefix.length);
}
if (releaseTag && (0, semver_1.compare)(releaseTag, prereleaseTag) === 1) {
tags = releaseTags;
}
else {
tags = prereleaseTags;
}
}
tags = tags.filter((x) => x);
// if a pre-release tag is used, then add it to the initial version
let isFirstRelease = false;
let latestTag;
if (tags.length > 0) {
latestTag = tags[0];
}
else {
const initial = `${prefix}v${major ?? 0}.${minor ?? 0}.0`;
latestTag = prerelease ? `${initial}-${prerelease}.0` : initial;
isFirstRelease = true;
}
// remove tag prefix (if exists)
let latestVersion = latestTag;
if (prefix && latestVersion.startsWith(prefix)) {
latestVersion = latestVersion.substr(prefix.length);
}
// remove "v" prefix (if exists)
if (latestVersion.startsWith("v")) {
latestVersion = latestVersion.substring(1);
}
return { latestVersion, latestTag, isFirstRelease };
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVtcC12ZXJzaW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3JlbGVhc2UvYnVtcC12ZXJzaW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBb0pBLG9CQTRKQztBQWhURCwyQkFBZ0Q7QUFDaEQsK0JBQXFDO0FBRXJDLG1DQUFpQztBQUNqQyxzQ0FBc0M7QUFDdEMsa0NBQXVEO0FBQ3ZELHdDQUErQztBQUMvQywyQ0FNcUI7QUFDckIsNkRBQTJEO0FBNkgzRDs7Ozs7Ozs7R0FRRztBQUNJLEtBQUssVUFBVSxJQUFJLENBQUMsR0FBVyxFQUFFLE9BQW9CO0lBQzFELE1BQU0sV0FBVyxHQUFHLElBQUEsV0FBSSxFQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDbkQsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQztJQUN0QyxNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDO0lBQ25DLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUM7SUFDbkMsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDLGVBQWUsQ0FBQztJQUNoRCxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsU0FBUyxJQUFJLEVBQUUsQ0FBQztJQUMxQyxNQUFNLFFBQVEsR0FBRyxJQUFBLFdBQUksRUFBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzdDLE1BQU0sYUFBYSxHQUFHLElBQUEsV0FBSSxFQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkQsTUFBTSxjQUFjLEdBQUcsSUFBQSxXQUFJLEVBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUV6RCxJQUFJLEtBQUssSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUM3QixNQUFNLElBQUksS0FBSyxDQUNiLDJEQUEyRCxDQUM1RCxDQUFDO0lBQ0osQ0FBQztJQUNELElB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fSBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IGRpcm5hbWUsIGpvaW4gfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgQ29uZmlnIH0gZnJvbSBcImNvbnZlbnRpb25hbC1jaGFuZ2Vsb2ctY29uZmlnLXNwZWNcIjtcbmltcG9ydCB7IGNvbXBhcmUgfSBmcm9tIFwic2VtdmVyXCI7XG5pbXBvcnQgKiBhcyBsb2dnaW5nIGZyb20gXCIuLi9sb2dnaW5nXCI7XG5pbXBvcnQgeyBleGVjQ2FwdHVyZSwgZXhlY09yVW5kZWZpbmVkIH0gZnJvbSBcIi4uL3V0aWxcIjtcbmltcG9ydCB7IFJlbGVhc2FibGVDb21taXRzIH0gZnJvbSBcIi4uL3ZlcnNpb25cIjtcbmltcG9ydCB7XG4gIEJ1bXBUeXBlLFxuICBwYXJzZUJ1bXBUeXBlLFxuICBwZXJmb3JtQnVtcCxcbiAgcmVsYXRpdmVCdW1wVHlwZSxcbiAgcmVuZGVyQnVtcFR5cGUsXG59IGZyb20gXCIuL2J1bXAtdHlwZVwiO1xuaW1wb3J0IHsgQ29tbWl0QW5kVGFnVmVyc2lvbiB9IGZyb20gXCIuL2NvbW1pdC10YWctdmVyc2lvblwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIEJ1bXBPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIGEgLmpzb24gZmlsZSB0byBzZXQgYHZlcnNpb25gLlxuICAgKi9cbiAgcmVhZG9ubHkgdmVyc2lvbkZpbGU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGNoYW5nZWxvZyBmaWxlIHRvIGdlbmVyYXRlLlxuICAgKi9cbiAgcmVhZG9ubHkgY2hhbmdlbG9nOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFVzZSBhIHByZS1yZWxlYXNlIHN1ZmZpeC5cbiAgICogQGRlZmF1bHQgLSBub3JtYWwgdmVyc2lvbmluZ1xuICAgKi9cbiAgcmVhZG9ubHkgcHJlcmVsZWFzZT86IHN0cmluZztcblxuICAvKipcbiAgICogRGVmaW5lcyB0aGUgbWFqb3IgdmVyc2lvbiBsaW5lLiBUaGlzIGlzIHVzZWQgdG8gc2VsZWN0IHRoZSBsYXRlc3QgdmVyc2lvblxuICAgKiBhbmQgYWxzbyBlbmZvcmNlIHRoYXQgbmV3IG1ham9yIHZlcnNpb25zIGFyZSBub3QgcmVsZWFzZWQgYWNjaWRlbnRhbGx5LlxuICAgKlxuICAgKiBDYW4gbm90IGJlIHNldCB0b2dldGhlciB3aXRoIGBtaW5NYWpvclZlcnNpb25gLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGFueSB2ZXJzaW9uIGlzIHN1cHBvcnRlZFxuICAgKi9cbiAgcmVhZG9ubHkgbWFqb3JWZXJzaW9uPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBEZWZpbmVzIHRoZSBtaW5pbWFsIG1ham9yIHZlcnNpb24uIFRoaXMgaXMgdXNlZCBpZiB5b3Ugd2FudCB0byBzdGFydCB3aXRoXG4gICAqIGEgc3BlY2lmaWMgbWFqb3IgdmVyc2lvbiwgYW5kIGluY3JlbWVudCBmcm9tIHRoZXJlIG9uLlxuICAgKiBUaGlzIGNhbiBiZSB1c2VmdWwgdG8gc2V0IHRvIDEsIGFzIGJyZWFraW5nIGNoYW5nZXMgYmVmb3JlIHRoZSAxLnggbWFqb3JcbiAgICogcmVsZWFzZSBhcmUgbm90IGluY3JlbWVudGluZyB0aGUgbWFqb3IgdmVyc2lvbiBudW1iZXIuXG4gICAqXG4gICAqIENhbiBub3QgYmUgc2V0IHRvZ2V0aGVyIHdpdGggYG1ham9yVmVyc2lvbmAuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gbWluaW11bSB2ZXJzaW9uIGlzIGJlaW5nIGVuZm9yY2VkXG4gICAqL1xuICByZWFkb25seSBtaW5NYWpvclZlcnNpb24/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIERlZmluZXMgdGhlIG1pbm9yIHZlcnNpb24gbGluZS4gVGhpcyBpcyB1c2VkIHRvIHNlbGVjdCB0aGUgbGF0ZXN0IHZlcnNpb25cbiAgICogYW5kIGFsc28gZW5mb3JjZSB0aGF0IG5ldyBtaW5vciB2ZXJzaW9ucyBhcmUgbm90IHJlbGVhc2VkIGFjY2lkZW50YWxseS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBhbnkgdmVyc2lvbiBpcyBzdXBwb3J0ZWRcbiAgICovXG4gIHJlYWRvbmx5IG1pbm9yVmVyc2lvbj86IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgYSBmaWxlIHdoaWNoIHdpbGwgaW5jbHVkZSB0aGUgb3V0cHV0IHZlcnNpb24gbnVtYmVyIChhIHRleHQgZmlsZSkuXG4gICAqXG4gICAqIFJlbGF0aXZlIHRvIGN3ZC5cbiAgICpcbiAgICogQGV4YW1wbGUgXCIudmVyc2lvbi50eHRcIlxuICAgKi9cbiAgcmVhZG9ubHkgYnVtcEZpbGU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGZpbGUgd2hpY2ggd2lsbCBpbmNsdWRlIHRoZSByZWxlYXNlIHRhZyAoYSB0ZXh0IGZpbGUpLlxuICAgKlxuICAgKiBSZWxhdGl2ZSB0byBjd2QuXG4gICAqXG4gICAqIEBleGFtcGxlIFwiLnJlbGVhc2V0YWcudHh0XCJcbiAgICovXG4gIHJlYWRvbmx5IHJlbGVhc2VUYWdGaWxlOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwcmVmaXggYXBwbGllZCB0byByZWxlYXNlIHRhZ3MuIEJ1bXBzIHdpbGwgYmUgbWFkZSBiYXNlZCBvbiB0aGUgbGF0ZXN0XG4gICAqIHZlcnNpb24gZm91bmQgd2l0aCB0aGlzIHByZWZpeC5cbiAgICovXG4gIHJlYWRvbmx5IHRhZ1ByZWZpeD86IHN0cmluZztcblxuICAvKipcbiAgICogQ29uZmlndXJhdGlvbiB2YWx1ZXMgdGhhdCB3b3VsZCBhcHBlbmQgdG8gdmVyc2lvbnJjIGZpbGUgb3Igb3ZlcndyaXRlIHZhbHVlc1xuICAgKiBjb21pbmcgdG8gdGhhdCBmcm9tIGRlZmF1bHQgb25lLlxuICAgKi9cbiAgcmVhZG9ubHkgdmVyc2lvbnJjT3B0aW9ucz86IENvbmZpZztcblxuICAvKipcbiAgICogQSBzaGVsbCBjb21tYW5kIHRvIGxpc3QgYWxsIHJlbGVhc2UgY29tbWl0cyBzaW5jZSB0aGUgbGF0ZXN0IHRhZy5cbiAgICpcbiAgICogQSBuZXcgcmVsZWFzZSB3aWxsIGJlIGluaXRpYXRlZCwgaWYgdGhlIG51bWJlciBvZiByZXR1cm5lZCBjb21taXRzIGlzIGdyZWF0ZXIgdGhhbiB6ZXJvLlxuICAgKlxuICAgKiBgJExBVEVTVF9UQUdgIHdpbGwgYmUgcmVwbGFjZWQgd2l0aCB0aGUgYWN0dWFsIGxhdGVzdCB0YWcgZm9yIHRoZSBnaXZlbiBwcmVmaXguXG4gICAqXG4gICAqIEBkZWZhdWx0IFwiZ2l0IGxvZyAtLW9uZWxpbmUgJExBVEVTVF9UQUcuLkhFQURcIlxuICAgKi9cbiAgcmVhZG9ubHkgcmVsZWFzYWJsZUNvbW1pdHM/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBgY29tbWl0LWFuZC10YWctdmVyc2lvbmAgY29tcGF0aWJsZSBwYWNrYWdlIHVzZWQgdG8gYnVtcCB0aGUgcGFja2FnZSB2ZXJzaW9uLCBhcyBhIGRlcGVuZGVuY3kgc3RyaW5nLlxuICAgKlxuICAgKiBUaGlzIGNhbiBiZSBhbnkgY29tcGF0aWJsZSBwYWNrYWdlIHZlcnNpb24sIGluY2x1ZGluZyB0aGUgZGVwcmVjYXRlZCBgc3RhbmRhcmQtdmVyc2lvbkA5YC5cbiAgICpcbiAgICogQGRlZmF1bHQgXCJjb21taXQtYW5kLXRhZy12ZXJzaW9uQDEyXCJcbiAgICovXG4gIHJlYWRvbmx5IGJ1bXBQYWNrYWdlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIHNoZWxsIGNvbW1hbmQgdG8gY29udHJvbCB0aGUgbmV4dCB2ZXJzaW9uIHRvIHJlbGVhc2UuXG4gICAqXG4gICAqIElmIHByZXNlbnQsIHRoaXMgc2hlbGwgY29tbWFuZCB3aWxsIGJlIHJ1biBiZWZvcmUgdGhlIGJ1bXAgaXMgZXhlY3V0ZWQsIGFuZFxuICAgKiBpdCBkZXRlcm1pbmVzIHdoYXQgdmVyc2lvbiB0byByZWxlYXNlLiBJdCB3aWxsIGJlIGV4ZWN1dGVkIGluIHRoZSBmb2xsb3dpbmdcbiAgICogZW52aXJvbm1lbnQ6XG4gICAqXG4gICAqIC0gV29ya2luZyBkaXJlY3Rvcnk6IHRoZSBwcm9qZWN0IGRpcmVjdG9yeS5cbiAgICogLSBgJFZFUlNJT05gOiB0aGUgY3VycmVudCB2ZXJzaW9uLiBMb29rcyBsaWtlIGAxLjIuM2AuXG4gICAqIC0gYCRMQVRFU1RfVEFHYDogdGhlIG1vc3QgcmVjZW50IHRhZy4gTG9va3MgbGlrZSBgcHJlZml4LXYxLjIuM2AsIG9yIG1heSBiZSB1bnNldC5cbiAgICpcbiAgICogVGhlIGNvbW1hbmQgc2hvdWxkIHByaW50IG9uZSBvZiB0aGUgZm9sbG93aW5nIHRvIGBzdGRvdXRgOlxuICAgKlxuICAgKiAtIE5vdGhpbmc6IHRoZSBuZXh0IHZlcnNpb24gbnVtYmVyIHdpbGwgYmUgZGV0ZXJtaW5lZCBiYXNlZCBvbiBjb21taXQgaGlzdG9yeS5cbiAgICogLSBgeC55LnpgOiB0aGUgbmV4dCB2ZXJzaW9uIG51bWJlciB3aWxsIGJlIGB4LnkuemAuXG4gICAqIC0gYG1ham9yfG1pbm9yfHBhdGNoYDogdGhlIG5leHQgdmVyc2lvbiBudW1iZXIgd2lsbCBiZSB0aGUgY3VycmVudCB2ZXJzaW9uIG51bWJlclxuICAgKiAgIHdpdGggdGhlIGluZGljYXRlZCBjb21wb25lbnQgYnVtcGVkLlxuICAgKlxuICAgKiBUaGlzIHNldHRpbmcgY2Fubm90IGJlIHNwZWNpZmllZCB0b2dldGhlciB3aXRoIGBtaW5NYWpvclZlcnNpb25gOyB0aGUgaW52b2tlZFxuICAgKiBzY3JpcHQgY2FuIGJlIHVzZWQgdG8gYWNoaWV2ZSB0aGUgZWZmZWN0cyBvZiBgbWluTWFqb3JWZXJzaW9uYC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBUaGUgbmV4dCB2ZXJzaW9uIHdpbGwgYmUgZGV0ZXJtaW5lZCBiYXNlZCBvbiB0aGUgY29tbWl0IGhpc3RvcnkgYW5kIHByb2plY3Qgc2V0dGluZ3MuXG4gICAqL1xuICByZWFkb25seSBuZXh0VmVyc2lvbkNvbW1hbmQ/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUmVzb2x2ZXMgdGhlIGxhdGVzdCB2ZXJzaW9uIGZyb20gZ2l0IHRhZ3MgYW5kIHVzZXMgYGNvbW1pdC1hbmQtdGFnLXZlcnNpb25gIHRvIGJ1bXBcbiAqIHRvIHRoZSBuZXh0IHZlcnNpb24gYmFzZWQgb24gY29tbWl0cy5cbiAqXG4gKiBUaGlzIGV4cGVjdHMgYGNvbW1pdC1hbmQtdGFnLXZlcnNpb25gIHRvIGJlIGluc3RhbGxlZCBpbiB0aGUgcGF0aC5cbiAqXG4gKiBAcGFyYW0gY3dkIHdvcmtpbmcgZGlyZWN0b3J5IChnaXQgcmVwb3NpdG9yeSlcbiAqIEBwYXJhbSBvcHRpb25zIG9wdGlvbnNcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGJ1bXAoY3dkOiBzdHJpbmcsIG9wdGlvbnM6IEJ1bXBPcHRpb25zKSB7XG4gIGNvbnN0IHZlcnNpb25GaWxlID0gam9pbihjd2QsIG9wdGlvbnMudmVyc2lvbkZpbGUpO1xuICBjb25zdCBwcmVyZWxlYXNlID0gb3B0aW9ucy5wcmVyZWxlYXNlO1xuICBjb25zdCBtYWpvciA9IG9wdGlvbnMubWFqb3JWZXJzaW9uO1xuICBjb25zdCBtaW5vciA9IG9wdGlvbnMubWlub3JWZXJzaW9uO1xuICBjb25zdCBtaW5NYWpvclZlcnNpb24gPSBvcHRpb25zLm1pbk1ham9yVmVyc2lvbjtcbiAgY29uc3QgdGFnUHJlZml4ID0gb3B0aW9ucy50YWdQcmVmaXggPz8gXCJcIjtcbiAgY29uc3QgYnVtcEZpbGUgPSBqb2luKGN3ZCwgb3B0aW9ucy5idW1wRmlsZSk7XG4gIGNvbnN0IGNoYW5nZWxvZ0ZpbGUgPSBqb2luKGN3ZCwgb3B0aW9ucy5jaGFuZ2Vsb2cpO1xuICBjb25zdCByZWxlYXNlVGFnRmlsZSA9IGpvaW4oY3dkLCBvcHRpb25zLnJlbGVhc2VUYWdGaWxlKTtcblxuICBpZiAobWFqb3IgJiYgbWluTWFqb3JWZXJzaW9uKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYG1pbk1ham9yVmVyc2lvbiBhbmQgbWFqb3JWZXJzaW9uIGNhbm5vdCBiZSB1c2VkIHRvZ2V0aGVyLmAsXG4gICAgKTtcbiAgfVxuICBpZiAob3B0aW9ucy5uZXh0VmVyc2lvbkNvbW1hbmQgJiYgbWluTWFqb3JWZXJzaW9uKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYG1pbk1ham9yVmVyc2lvbiBhbmQgbmV4dFZlcnNpb25Db21tYW5kIGNhbm5vdCBiZSB1c2VkIHRvZ2V0aGVyLmAsXG4gICAgKTtcbiAgfVxuICBpZiAobWlub3IgJiYgIW1ham9yKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBtaW5vclZlcnNpb24gYW5kIG1ham9yVmVyc2lvbiBtdXN0IGJlIHVzZWQgdG9nZXRoZXIuYCk7XG4gIH1cblxuICBhd2FpdCBmcy5ta2RpcihkaXJuYW1lKGJ1bXBGaWxlKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIGF3YWl0IGZzLm1rZGlyKGRpcm5hbWUoY2hhbmdlbG9nRmlsZSksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICBhd2FpdCBmcy5ta2RpcihkaXJuYW1lKHJlbGVhc2VUYWdGaWxlKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgY29uc3QgeyBsYXRlc3RWZXJzaW9uLCBsYXRlc3RUYWcsIGlzRmlyc3RSZWxlYXNlIH0gPSBkZXRlcm1pbmVMYXRlc3RUYWcoe1xuICAgIGN3ZCxcbiAgICBtYWpvcixcbiAgICBtaW5vcixcbiAgICBwcmVyZWxlYXNlLFxuICAgIHByZWZpeDogdGFnUHJlZml4LFxuICB9KTtcblxuICAvLyBXcml0ZSB0aGUgY3VycmVudCB2ZXJzaW9uIGludG8gdGhlIHZlcnNpb24gZmlsZSBzbyB0aGF0IENBVFYgd2lsbCBrbm93IHRoZSBjdXJyZW50IHZlcnNpb25cbiAgY29uc3QgeyBjb250ZW50cywgbmV3bGluZSB9ID0gYXdhaXQgdHJ5UmVhZFZlcnNpb25GaWxlKHZlcnNpb25GaWxlKTtcbiAgY29udGVudHMudmVyc2lvbiA9IGxhdGVzdFZlcnNpb247XG4gIGxvZ2dpbmcuaW5mbyhcbiAgICBgVXBkYXRlICR7dmVyc2lvbkZpbGV9IHRvIGxhdGVzdCByZXNvbHZlZCB2ZXJzaW9uOiAke2xhdGVzdFZlcnNpb259YCxcbiAgKTtcbiAgYXdhaXQgZnMud3JpdGVGaWxlKFxuICAgIHZlcnNpb25GaWxlLFxuICAgIEpTT04uc3RyaW5naWZ5KGNvbnRlbnRzLCB1bmRlZmluZWQsIDIpICsgKG5ld2xpbmUgPyBcIlxcblwiIDogXCJcIiksXG4gICk7XG5cbiAgLy8gRGV0ZXJtaW5lIHRoZSBpbml0aWFsIGJ1bXAgc3RhdHVzLiBDQVRWIHdpbGwgYWx3YXlzIGRvIGEgcGF0Y2ggZXZlbiBpZlxuICAvLyB0aGVyZSBhcmUgbm8gY29tbWl0cywgc28gbG9vayBhdCBjb21taXRzIG91cnNlbHZlcyBmaXJzdCB0byBkZWNpZGVcbiAgLy8gaWYgd2UgZXZlbiBzaG91bGQgZG8gbm90aGluZyBhdCBhbGwuXG4gIGNvbnN0IHNob3VsZFJlbGVhc2UgPSBpc0ZpcnN0UmVsZWFzZVxuICAgID8gdHJ1ZVxuICAgIDogaGFzTmV3SW50ZXJlc3RpbmdDb21taXRzKHtcbiAgICAgICAgY3dkLFxuICAgICAgICBsYXRlc3RUYWcsXG4gICAgICAgIHJlbGVhc2FibGVDb21taXRzOiBvcHRpb25zLnJlbGVhc2FibGVDb21taXRzLFxuICAgICAgfSk7XG5cbiAgY29uc3QgY2F0diA9IG5ldyBDb21taXRBbmRUYWdWZXJzaW9uKG9wdGlvbnMuYnVtcFBhY2thZ2UsIGN3ZCwge1xuICAgIHZlcnNpb25GaWxlLFxuICAgIGNoYW5nZWxvZ0ZpbGUsXG4gICAgcHJlcmVsZWFzZSxcbiAgICBjb25maWdPcHRpb25zOiBvcHRpb25zLnZlcnNpb25yY09wdGlvbnMsXG4gICAgdGFnUHJlZml4LFxuICB9KTtcblxuICAvLyBXZSB1c2VkIHRvIHRyYW5zbGF0ZSBgaXNGaXJzdFJlbGVhc2VgIHRvIHRoZSBgLS1maXJzdC1yZWxlYXNlYCBmbGFnIG9mIENBVFYuXG4gIC8vIFdoYXQgdGhhdCBkb2VzIGlzIHNraXAgYSBidW1wLCBvbmx5IGdlbmVyYXRlIHRoZSBjaGFuZ2Vsb2cuXG4gIC8vXG4gIC8vIE91ciBgeyBidW1wOiBub25lIH1gIGRvZXMgdGhlIHNhbWUsIHNvIHdlIGRvbid0IG5lZWQgdG8gY2Fycnkgb3ZlciB0aGlzXG4gIC8vIGZsYWcgYW55bW9yZS5cbiAgbGV0IGJ1bXBUeXBlOiBCdW1wVHlwZSA9XG4gICAgc2hvdWxkUmVsZWFzZSAmJiAhaXNGaXJzdFJlbGVhc2VcbiAgICAgID8gcmVsYXRpdmVCdW1wVHlwZShsYXRlc3RWZXJzaW9uLCBhd2FpdCBjYXR2LmRyeVJ1bigpKVxuICAgICAgOiB7IGJ1bXA6IFwibm9uZVwiIH07XG5cbiAgbG9nZ2luZy5pbmZvKGBCdW1wIGZyb20gY29tbWl0czogJHtyZW5kZXJCdW1wVHlwZShidW1wVHlwZSl9YCk7XG4gIGlmIChvcHRpb25zLm5leHRWZXJzaW9uQ29tbWFuZCkge1xuICAgIGNvbnN0IG5leHRWZXJzaW9uID0gZXhlY0NhcHR1cmUob3B0aW9ucy5uZXh0VmVyc2lvbkNvbW1hbmQsIHtcbiAgICAgIGN3ZCxcbiAgICAgIG1vZEVudjoge1xuICAgICAgICBWRVJTSU9OOiBsYXRlc3RWZXJzaW9uLFxuICAgICAgICBTVUdHRVNURURfQlVNUDogcmVuZGVyQnVtcFR5cGUoYnVtcFR5cGUpLFxuICAgICAgICAuLi4obGF0ZXN0VGFnID8geyBMQVRFU1RfVEFHOiBsYXRlc3RUYWcgfSA6IHt9KSxcbiAgICAgIH0sXG4gICAgfSlcbiAgICAgIC50b1N0cmluZygpXG4gICAgICAudHJpbSgpO1xuXG4gICAgaWYgKG5leHRWZXJzaW9uKSB7XG4gICAgICB0cnkge1xuICAgICAgICBidW1wVHlwZSA9IHBhcnNlQnVtcFR5cGUobmV4dFZlcnNpb24pO1xuICAgICAgICBsb2dnaW5nLmluZm8oXG4gICAgICAgICAgYEJ1bXAgZnJvbSBuZXh0VmVyc2lvbkNvbW1hbmQ6ICR7cmVuZGVyQnVtcFR5cGUoYnVtcFR5cGUpfWAsXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgbmV4dFZlcnNpb25Db21tYW5kIFwiJHtvcHRpb25zLm5leHRWZXJzaW9uQ29tbWFuZH1cIiByZXR1cm5lZCBpbnZhbGlkIG91dHB1dDogJHtlfWAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUmVzcGVjdCBtaW5NYWpvclZlcnNpb24gdG8gY29ycmVjdCB0aGUgcmVzdWx0IG9mIHRoZSBuZXh0VmVyc2lvbkNvbW1hbmRcbiAgaWYgKG1pbk1ham9yVmVyc2lvbikge1xuICAgIGNvbnN0IGJ1bXBlZFZlcnNpb24gPSBwZXJmb3JtQnVtcChsYXRlc3RWZXJzaW9uLCBidW1wVHlwZSk7XG4gICAgY29uc3QgW21ham9yVmVyc2lvbl0gPSBidW1wZWRWZXJzaW9uLnNwbGl0KFwiLlwiKTtcbiAgICBjb25zdCBtYWpvclZlcnNpb25OdW1iZXIgPSBwYXJzZUludChtYWpvclZlcnNpb24sIDEwKTtcbiAgICBpZiAobWFqb3JWZXJzaW9uTnVtYmVyIDwgbWluTWFqb3JWZXJzaW9uKSB7XG4gICAgICBidW1wVHlwZSA9IHsgYnVtcDogXCJhYnNvbHV0ZVwiLCBhYnNvbHV0ZTogYCR7bWluTWFqb3JWZXJzaW9ufS4wLjBgIH07XG4gICAgfVxuICB9XG5cbiAgLy8gSW52b2tlIENBVFYgd2l0aCB0aGUgb3B0aW9ucyB3ZSBsYW5kZWQgb24uIElmIHdlIGRlY2lkZWQgbm90IHRvIGRvIGEgYnVtcCxcbiAgLy8gd2Ugd2lsbCB1c2UgdGhpcyB0byByZWdlbmVyYXRlIHRoZSBjaGFuZ2Vsb2cgb2YgdGhlIG1vc3QgcmVjZW50IHZlcnNpb24uXG4gIGNvbnN0IG5ld1JlbGVhc2UgPSBidW1wVHlwZS5idW1wICE9PSBcIm5vbmVcIjtcblxuICAvLyBJZiB3ZSdyZSBub3QgZG9pbmcgYSBuZXcgcmVsZWFzZSBhbmQgdGhpcyBpcyBub3QgdGhlXG4gIC8vIGZpcnN0IHJlbGVhc2UsIHdlJ3JlIGp1c3QgcmVnZW5lcmF0aW5nIHRoZSBwcmV2aW91cyBjaGFuZ2Vsb2cgYWdhaW4uXG4gIGlmICghbmV3UmVsZWFzZSAmJiAhaXNGaXJzdFJlbGVhc2UpIHtcbiAgICBhd2FpdCBjYXR2LnJlZ2VuZXJhdGVQcmV2aW91c0NoYW5nZUxvZyhsYXRlc3RWZXJzaW9uLCBsYXRlc3RUYWcpO1xuICB9IGVsc2Uge1xuICAgIC8vIE90aGVyd2lzZSB3ZSdyZSBlaXRoZXIgZG9pbmcgYSBidW1wICsgcmVsZWFzZSwgb3Igd2UncmUgcmVsZWFzaW5nIHRoZVxuICAgIC8vIGZpcnN0IHZlcnNpb24gYXMgMC4wLjAgKHdoaWNoIGlzIGFscmVhZHkgdGhlIG51bWJlciBpbiB0aGUgZmlsZSBzbyB3ZVxuICAgIC8vIHNraXAgYnVtcGluZykuXG4gICAgYXdhaXQgY2F0di5pbnZva2Uoe1xuICAgICAgcmVsZWFzZUFzOiBuZXdSZWxlYXNlID8gcmVuZGVyQnVtcFR5cGUoYnVtcFR5cGUpIDogdW5kZWZpbmVkLFxuICAgICAgc2tpcEJ1bXA6ICFuZXdSZWxlYXNlLFxuICAgIH0pO1xuICB9XG5cbiAgLy8gVmFsaWRhdGUgdGhlIHZlcnNpb24gdGhhdCB3ZSBlbmRlZCB1cCB3aXRoXG4gIGNvbnN0IG5ld1ZlcnNpb24gPSAoYXdhaXQgdHJ5UmVhZFZlcnNpb25GaWxlKHZlcnNpb25GaWxlKSkudmVyc2lvbjtcbiAgaWYgKCFuZXdWZXJzaW9uKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBidW1wIGZhaWxlZDogJHt2ZXJzaW9uRmlsZX0gZG9lcyBub3QgaGF2ZSBhIHZlcnNpb24gc2V0YCk7XG4gIH1cbiAgaWYgKG1ham9yKSB7XG4gICAgaWYgKCFuZXdWZXJzaW9uLnN0YXJ0c1dpdGgoYCR7bWFqb3J9LmApKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBidW1wIGZhaWxlZDogdGhpcyBicmFuY2ggaXMgY29uZmlndXJlZCB0byBvbmx5IHB1Ymxpc2ggdiR7bWFqb3J9IHJlbGVhc2VzIC0gYnVtcCByZXN1bHRlZCBpbiAke25ld1ZlcnNpb259YCxcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIGlmIChtaW5vcikge1xuICAgIGlmICghbmV3VmVyc2lvbi5zdGFydHNXaXRoKGAke21ham9yfS4ke21pbm9yfWApKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBidW1wIGZhaWxlZDogdGhpcyBicmFuY2ggaXMgY29uZmlndXJlZCB0byBvbmx5IHB1Ymxpc2ggdiR7bWFqb3J9LiR7bWlub3J9IHJlbGVhc2VzIC0gYnVtcCByZXN1bHRlZCBpbiAke25ld1ZlcnNpb259YCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gUmVwb3J0IGN1cmVudCBzdGF0dXMgaW50byB0aGUgZGlzdC8gZGlyZWN0b3J5XG4gIGNvbnN0IG5ld1RhZyA9IGAke3RhZ1ByZWZpeH12JHtuZXdWZXJzaW9ufWA7XG4gIGF3YWl0IGZzLndyaXRlRmlsZShidW1wRmlsZSwgbmV3VmVyc2lvbik7XG4gIGF3YWl0IGZzLndyaXRlRmlsZShyZWxlYXNlVGFnRmlsZSwgbmV3VGFnKTtcbn1cblxuLyoqXG4gKiBEZXRlcm1pbmUgYmFzZWQgb24gcmVsZWFzZWFibGUgY29tbWl0cyB3aGV0aGVyIHdlIHNob3VsZCByZWxlYXNlIG9yIG5vdFxuICovXG5mdW5jdGlvbiBoYXNOZXdJbnRlcmVzdGluZ0NvbW1pdHMob3B0aW9uczoge1xuICByZWxlYXNhYmxlQ29tbWl0cz86IHN0cmluZztcbiAgbGF0ZXN0VGFnOiBzdHJpbmc7XG4gIGN3ZDogc3RyaW5nO1xufSkge1xuICBjb25zdCBmaW5kQ29tbWl0cyA9IChcbiAgICBvcHRpb25zLnJlbGVhc2FibGVDb21taXRzID8/IFJlbGVhc2FibGVDb21taXRzLmV2ZXJ5Q29tbWl0KCkuY21kXG4gICkucmVwbGFjZShcIiRMQVRFU1RfVEFHXCIsIG9wdGlvbnMubGF0ZXN0VGFnKTtcblxuICBjb25zdCBjb21taXRzU2luY2VMYXN0VGFnID0gZXhlY09yVW5kZWZpbmVkKGZpbmRDb21taXRzLCB7XG4gICAgY3dkOiBvcHRpb25zLmN3ZCxcbiAgfSk/LnNwbGl0KFwiXFxuXCIpO1xuICBjb25zdCBudW1Db21taXRzU2luY2VMYXN0VGFnID0gY29tbWl0c1NpbmNlTGFzdFRhZz8ubGVuZ3RoID8/IDA7XG4gIGxvZ2dpbmcuaW5mbyhcbiAgICBgTnVtYmVyIG9mIGNvbW1pdHMgc2luY2UgJHtvcHRpb25zLmxhdGVzdFRhZ306ICR7bnVtQ29tbWl0c1NpbmNlTGFzdFRhZ31gLFxuICApO1xuXG4gIC8vIE5vdGhpbmcgdG8gcmVsZWFzZSByaWdodCBub3dcbiAgaWYgKG51bUNvbW1pdHNTaW5jZUxhc3RUYWcgPT09IDApIHtcbiAgICBsb2dnaW5nLmluZm8oXCJObyBuZXcgaW50ZXJlc3RpbmcgY29tbWl0cy5cIik7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIHRydWU7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHRyeVJlYWRWZXJzaW9uRmlsZShcbiAgdmVyc2lvbkZpbGU6IHN0cmluZyxcbik6IFByb21pc2U8eyBjb250ZW50czogYW55OyB2ZXJzaW9uPzogc3RyaW5nOyBuZXdsaW5lOiBib29sZWFuIH0+IHtcbiAgaWYgKCFleGlzdHNTeW5jKHZlcnNpb25GaWxlKSkge1xuICAgIHJldHVybiB7IGNvbnRlbnRzOiB7fSwgbmV3bGluZTogdHJ1ZSB9O1xuICB9XG4gIGNvbnN0IHJhdyA9IGF3YWl0IGZzLnJlYWRGaWxlKHZlcnNpb25GaWxlLCBcInV0Zi04XCIpO1xuICBjb25zdCBjb250ZW50cyA9IEpTT04ucGFyc2UocmF3KTtcblxuICByZXR1cm4ge1xuICAgIGNvbnRlbnRzLFxuICAgIHZlcnNpb246IGNvbnRlbnRzLnZlcnNpb24sXG4gICAgbmV3bGluZTogcmF3LmVuZHNXaXRoKFwiXFxuXCIpLFxuICB9O1xufVxuXG5pbnRlcmZhY2UgTGF0ZXN0VGFnT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXb3JraW5nIGRpcmVjdG9yeSBvZiB0aGUgZ2l0IHJlcG9zaXRvcnkuXG4gICAqL1xuICByZWFkb25seSBjd2Q6IHN0cmluZztcbiAgLyoqXG4gICAqIE1ham9yIHZlcnNpb24gdG8gc2VsZWN0IGZyb20uXG4gICAqL1xuICByZWFkb25seSBtYWpvcj86IG51bWJlcjtcbiAgLyoqXG4gICAqIE1pbm9yIHZlcnNpb24gdG8gc2VsZWN0IGZyb20uXG4gICAqL1xuICByZWFkb25seSBtaW5vcj86IG51bWJlcjtcbiAgLyoqXG4gICAqIEEgcHJlLXJlbGVhc2Ugc3VmZml4LlxuICAgKi9cbiAgcmVhZG9ubHkgcHJlcmVsZWFzZT86IHN0cmluZztcbiAgLyoqXG4gICAqIEEgcHJlZml4IGFwcGxpZWQgdG8gYWxsIHRhZ3MuXG4gICAqL1xuICByZWFkb25seSBwcmVmaXg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBsYXRlc3QgcmVsZWFzZSB0YWcuXG4gKiBAcGFyYW0gbWFqb3IgKG9wdGlvbmFsKSBBIG1ham9yIHZlcnNpb24gbGluZSB0byBzZWxlY3QgZnJvbVxuICogQHBhcmFtIHByZXJlbGVhc2UgKG9wdGlvbmFsKSBBIHByZS1yZWxlYXNlIHN1ZmZpeC5cbiAqIEByZXR1cm5zIHRoZSBsYXRlc3QgdGFnLCBhbmQgd2hldGhlciBpdCBpcyB0aGUgZmlyc3QgcmVsZWFzZSBvciBub3RcbiAqL1xuZnVuY3Rpb24gZGV0ZXJtaW5lTGF0ZXN0VGFnKG9wdGlvbnM6IExhdGVzdFRhZ09wdGlvbnMpOiB7XG4gIGxhdGVzdFZlcnNpb246IHN0cmluZztcbiAgbGF0ZXN0VGFnOiBzdHJpbmc7XG4gIGlzRmlyc3RSZWxlYXNlOiBib29sZWFuO1xufSB7XG4gIGNvbnN0IHsgY3dkLCBtYWpvciwgbWlub3IsIHByZXJlbGVhc2UsIHByZWZpeCB9ID0gb3B0aW9ucztcblxuICAvLyBmaWx0ZXIgb25seSB0YWdzIGZvciB0aGlzIHByZWZpeCBhbmQgbWFqb3IgdmVyc2lvbiBpZiBzcGVjaWZpZWQgKHN0YXJ0IHdpdGggXCJ2Tk4uXCIpLlxuICBsZXQgcHJlZml4RmlsdGVyOiBzdHJpbmc7XG4gIGlmIChtYWpvciAhPT0gdW5kZWZpbmVkICYmIG1pbm9yICE9PSB1bmRlZmluZWQpIHtcbiAgICBwcmVmaXhGaWx0ZXIgPSBgJHtwcmVmaXh9diR7bWFqb3J9LiR7bWlub3J9LipgO1xuICB9IGVsc2UgaWYgKG1ham9yICE9PSB1bmRlZmluZWQpIHtcbiAgICBwcmVmaXhGaWx0ZXIgPSBgJHtwcmVmaXh9diR7bWFqb3J9LipgO1xuICB9IGVsc2Uge1xuICAgIHByZWZpeEZpbHRlciA9IGAke3ByZWZpeH12KmA7XG4gIH1cblxuICBjb25zdCBsaXN0R2l0VGFncyA9IFtcbiAgICBcImdpdFwiLFxuICAgICctYyBcInZlcnNpb25zb3J0LnN1ZmZpeD0tXCInLCAvLyBtYWtlcyBzdXJlIHByZS1yZWxlYXNlIHZlcnNpb25zIGFyZSBsaXN0ZWQgYWZ0ZXIgdGhlIHByaW1hcnkgdmVyc2lvblxuICAgIFwidGFnXCIsXG4gICAgJy0tc29ydD1cIi12ZXJzaW9uOnJlZm5hbWVcIicsIC8vIHNvcnQgYXMgdmVyc2lvbnMgYW5kIG5vdCBsZXhpY29ncmFwaGljYWxseVxuICAgIFwiLS1saXN0XCIsXG4gICAgYFwiJHtwcmVmaXhGaWx0ZXJ9XCJgLFxuICBdLmpvaW4oXCIgXCIpO1xuXG4gIGNvbnN0IHN0ZG91dCA9IGV4ZWNDYXB0dXJlKGxpc3RHaXRUYWdzLCB7IGN3ZCB9KS50b1N0cmluZyhcInV0ZjhcIik7XG5cbiAgbGV0IHRhZ3MgPSBzdGRvdXQ/LnNwbGl0KFwiXFxuXCIpO1xuXG4gIC8vIGlmIHByZXJlbGVhc2UgaXMgc2V0IGFuZCB0aGVyZSBhcmUgZXhpc3RpbmcgcHJlcmVsZWFzZSB0YWdzLCBmaWx0ZXIgdmVyc2lvbnMgdGhhdCBlbmQgd2l0aCBcIi1QUkUuZGRkXCIuXG4gIGNvbnN0IHByZXJlbGVhc2VUYWdzID0gdGFncy5maWx0ZXIoKHgpID0+XG4gICAgbmV3IFJlZ0V4cChgLSR7cHJlcmVsZWFzZX1cXFxcLlswLTldKyRgKS50ZXN0KHgpLFxuICApO1xuICBpZiAocHJlcmVsZWFzZSAmJiBwcmVyZWxlYXNlVGFncy5sZW5ndGggPiAwKSB7XG4gICAgbGV0IHByZXJlbGVhc2VUYWcgPSBwcmVyZWxlYXNlVGFnc1swXTtcblxuICAgIC8qKlxuICAgICAqIENvdmVyIHRoZSBmb2xsb3dpbmcgY2FzZSBzcGVjaWZpY2FsbHlcbiAgICAgKiAxIC0gdjEuMC4wXG4gICAgICogMiAtIHYxLjAuMS1iZXRhLjBcbiAgICAgKiAzIC0gdjEuMC4xLWJldGEuMVxuICAgICAqIDQgLSB2MS4wLjFcbiAgICAgKiA1IC0gbm93IHB1Ymxpc2ggYSBuZXcgcmVsZWFzZSBvbiB0aGUgcHJlcmVsZWFzZSBicmFuY2hcbiAgICAgKiAgICBieSBzZXR0aW5nIHRoZSBsYXRlc3RUYWcgYXMgdjEuMC4xIGluc3RlYWQgb2YgdjEuMC4xLWJldGEuMVxuICAgICAqL1xuICAgIGNvbnN0IHJlbGVhc2VUYWdzID0gdGFncy5maWx0ZXIoKHgpID0+XG4gICAgICBuZXcgUmVnRXhwKGBeJHtwcmVmaXh9dihbMC05XSspXFxcXC4oWzAtOV0rKVxcXFwuKFswLTldKykkYCkudGVzdCh4KSxcbiAgICApO1xuXG4gICAgbGV0IHJlbGVhc2VUYWc6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBpZiAocmVsZWFzZVRhZ3MubGVuZ3RoID4gMCkge1xuICAgICAgcmVsZWFzZVRhZyA9IHJlbGVhc2VUYWdzWzBdO1xuICAgIH1cblxuICAgIGlmIChwcmVmaXgpIHtcbiAgICAgIHJlbGVhc2VUYWcgPSByZWxlYXNlVGFnPy5zdWJzdHJpbmcocHJlZml4Lmxlbmd0aCk7XG4gICAgICBwcmVyZWxlYXNlVGFnID0gcHJlcmVsZWFzZVRhZy5zdWJzdHJpbmcocHJlZml4Lmxlbmd0aCk7XG4gICAgfVxuXG4gICAgaWYgKHJlbGVhc2VUYWcgJiYgY29tcGFyZShyZWxlYXNlVGFnLCBwcmVyZWxlYXNlVGFnKSA9PT0gMSkge1xuICAgICAgdGFncyA9IHJlbGVhc2VUYWdzO1xuICAgIH0gZWxzZSB7XG4gICAgICB0YWdzID0gcHJlcmVsZWFzZVRhZ3M7XG4gICAgfVxuICB9XG5cbiAgdGFncyA9IHRhZ3MuZmlsdGVyKCh4KSA9PiB4KTtcblxuICAvLyBpZiBhIHByZS1yZWxlYXNlIHRhZyBpcyB1c2VkLCB0aGVuIGFkZCBpdCB0byB0aGUgaW5pdGlhbCB2ZXJzaW9uXG4gIGxldCBpc0ZpcnN0UmVsZWFzZSA9IGZhbHNlO1xuICBsZXQgbGF0ZXN0VGFnO1xuXG4gIGlmICh0YWdzLmxlbmd0aCA+IDApIHtcbiAgICBsYXRlc3RUYWcgPSB0YWdzWzBdO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IGluaXRpYWwgPSBgJHtwcmVmaXh9diR7bWFqb3IgPz8gMH0uJHttaW5vciA/PyAwfS4wYDtcbiAgICBsYXRlc3RUYWcgPSBwcmVyZWxlYXNlID8gYCR7aW5pdGlhbH0tJHtwcmVyZWxlYXNlfS4wYCA6IGluaXRpYWw7XG4gICAgaXNGaXJzdFJlbGVhc2UgPSB0cnVlO1xuICB9XG5cbiAgLy8gcmVtb3ZlIHRhZyBwcmVmaXggKGlmIGV4aXN0cylcbiAgbGV0IGxhdGVzdFZlcnNpb24gPSBsYXRlc3RUYWc7XG4gIGlmIChwcmVmaXggJiYgbGF0ZXN0VmVyc2lvbi5zdGFydHNXaXRoKHByZWZpeCkpIHtcbiAgICBsYXRlc3RWZXJzaW9uID0gbGF0ZXN0VmVyc2lvbi5zdWJzdHIocHJlZml4Lmxlbmd0aCk7XG4gIH1cblxuICAvLyByZW1vdmUgXCJ2XCIgcHJlZml4IChpZiBleGlzdHMpXG4gIGlmIChsYXRlc3RWZXJzaW9uLnN0YXJ0c1dpdGgoXCJ2XCIpKSB7XG4gICAgbGF0ZXN0VmVyc2lvbiA9IGxhdGVzdFZlcnNpb24uc3Vic3RyaW5nKDEpO1xuICB9XG5cbiAgcmV0dXJuIHsgbGF0ZXN0VmVyc2lvbiwgbGF0ZXN0VGFnLCBpc0ZpcnN0UmVsZWFzZSB9O1xufVxuIl19