simplr-tslint
Version:
A set of TSLint rules used in SimplrJS projects.
256 lines • 39.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript");
const Lint = require("tslint");
const changeCase = require("change-case");
const SKIP_ORIGIN_CHECKING = "skip-origin-checking";
var Format;
(function (Format) {
Format["None"] = "none";
Format["CamelCase"] = "camel-case";
Format["PascalCase"] = "pascal-case";
Format["ConstantCase"] = "constant-case";
Format["SnakeCase"] = "snake-case";
})(Format || (Format = {}));
var AccessModifier;
(function (AccessModifier) {
AccessModifier["Public"] = "public";
AccessModifier["Private"] = "private";
AccessModifier["Protected"] = "protected";
})(AccessModifier || (AccessModifier = {}));
var MemberKind;
(function (MemberKind) {
MemberKind["Method"] = "method";
MemberKind["Property"] = "property";
})(MemberKind || (MemberKind = {}));
function isRuleSettings(obj) {
return obj.formatRules != null || obj.ignoreParentSuffixes != null;
}
var FormatHelpers;
(function (FormatHelpers) {
function changeFormat(format, text) {
switch (format) {
case Format.None:
return text;
case Format.CamelCase:
return changeCase.camelCase(text);
case Format.PascalCase:
return changeCase.pascalCase(text);
case Format.ConstantCase:
return changeCase.constantCase(text);
case Format.SnakeCase:
return changeCase.snakeCase(text);
}
}
FormatHelpers.changeFormat = changeFormat;
function changeFormatWithPrefixes(format, text, allowedPrefixes = []) {
if (allowedPrefixes.length === 0) {
return changeFormat(format, text);
}
for (const allowedPrefix of allowedPrefixes) {
// Find prefix from text in allowed prefixes.
const prefix = text.substring(0, allowedPrefix.length);
if (allowedPrefix !== prefix) {
continue;
}
const textWithoutPrefix = text.substring(prefix.length, text.length);
return allowedPrefix + changeFormat(format, textWithoutPrefix);
}
return changeFormat(format, text);
}
FormatHelpers.changeFormatWithPrefixes = changeFormatWithPrefixes;
})(FormatHelpers || (FormatHelpers = {}));
var TsHelpers;
(function (TsHelpers) {
function modifierKindExistsInModifiers(modifiers, kind) {
if (modifiers != null) {
return modifiers.some(x => x.kind === kind);
}
return false;
}
TsHelpers.modifierKindExistsInModifiers = modifierKindExistsInModifiers;
function resolveAccessModifierFromModifiers(modifiers) {
let accessModifier;
if (modifiers != null) {
modifiers.forEach(modifier => {
switch (modifier.kind) {
case ts.SyntaxKind.PublicKeyword: {
accessModifier = AccessModifier.Public;
return;
}
case ts.SyntaxKind.PrivateKeyword: {
accessModifier = AccessModifier.Private;
return;
}
case ts.SyntaxKind.ProtectedKeyword: {
accessModifier = AccessModifier.Protected;
return;
}
}
});
}
return accessModifier;
}
TsHelpers.resolveAccessModifierFromModifiers = resolveAccessModifierFromModifiers;
function isDeclarationWithHeritageClauses(node) {
return node.heritageClauses != null;
}
TsHelpers.isDeclarationWithHeritageClauses = isDeclarationWithHeritageClauses;
/**
* Checks all heritage list to find specific given name. If it doesn't exist, it returns false.
* @param node Node with heritage list.
* @param targetName Name to search for in heritage list.
*/
function checkMemberNameInHeritageDeclarations(typeChecker, node, targetName) {
if (node == null) {
return false;
}
if (node.heritageClauses == null) {
return false;
}
// Go through Extends and Implements
for (const heritage of node.heritageClauses) {
if (heritage.types == null) {
continue;
}
// Go through types on that heritage.
for (const typeNode of heritage.types) {
const type = typeChecker.getTypeFromTypeNode(typeNode);
const targetSymbol = type.getSymbol();
if (targetSymbol != null && targetSymbol.declarations != null) {
// Target Symbol declarations.
for (const declaration of targetSymbol.declarations) {
// Interface and Classes declarations only.
if (ts.isInterfaceDeclaration(declaration) || ts.isClassDeclaration(declaration)) {
for (const member of declaration.members) {
// Check members name.
if (member.name != null && member.name.getText() === targetName) {
return true;
}
}
// Go deeper to checker their heritage lists.
return checkMemberNameInHeritageDeclarations(typeChecker, declaration, targetName);
}
}
}
}
}
return false;
}
TsHelpers.checkMemberNameInHeritageDeclarations = checkMemberNameInHeritageDeclarations;
})(TsHelpers || (TsHelpers = {}));
class Rule extends Lint.Rules.TypedRule {
static failureMessageFactory(name, neededCase) {
return `Declaration "${name}" format is not correct (${neededCase}).`;
}
parseOptions(options) {
const defaultFormat = options.ruleArguments.find(x => Object.values(Format).find(y => y === x) != null);
const skipOriginChecking = options.ruleArguments.findIndex(x => x === SKIP_ORIGIN_CHECKING) !== -1;
const ruleSettings = options.ruleArguments.find(x => isRuleSettings(x)) || {};
return {
defaultFormat: defaultFormat || Format.CamelCase,
skipOriginChecking: skipOriginChecking,
rules: ruleSettings.formatRules || [],
ignoreParentSuffixes: ruleSettings.ignoreParentSuffixes || [],
rawOptions: options
};
}
applyWithProgram(sourceFile, program) {
const parsedOptions = this.parseOptions(this.getOptions());
return this.applyWithWalker(new ClassMembersWalker(sourceFile, parsedOptions, program));
}
}
exports.Rule = Rule;
// The walker takes care of all the work.
class ClassMembersWalker extends Lint.ProgramAwareRuleWalker {
constructor(sourceFile, ruleOptions, program) {
super(sourceFile, ruleOptions.rawOptions, program);
this.ruleOptions = ruleOptions;
}
//#region Helping functions
getFormatRule(rule) {
const rules = this.ruleOptions.rules;
const index = rules.findIndex(x => {
for (const key in rule) {
if ((rule.hasOwnProperty(key) && rule[key] === x[key]) || rule[key] == null) {
return true;
}
}
return false;
});
return rules[index];
}
checkNameNode(nameNode, format = Format.None, allowedPrefixes = []) {
const name = nameNode.getText();
const casedName = FormatHelpers.changeFormatWithPrefixes(format, name, allowedPrefixes);
if (casedName !== name) {
// create a fixer for this failure
const fix = new Lint.Replacement(nameNode.getStart(), nameNode.getWidth(), casedName);
// create a failure at the current position
this.addFailure(this.createFailure(nameNode.getStart(), nameNode.getWidth(), Rule.failureMessageFactory(name, format), fix));
}
}
//#endregion
visitMethodSignature(node) {
this.checkDeclarationNameFormat(node, node.name, MemberKind.Method);
super.visitMethodSignature(node);
}
visitMethodDeclaration(node) {
this.checkDeclarationNameFormat(node, node.name, MemberKind.Method);
super.visitMethodDeclaration(node);
}
visitPropertySignature(node) {
this.checkDeclarationNameFormat(node, node.name, MemberKind.Property);
super.visitPropertySignature(node);
}
visitPropertyDeclaration(node) {
this.checkDeclarationNameFormat(node, node.name, MemberKind.Property);
super.visitPropertyDeclaration(node);
}
visitGetAccessor(node) {
this.checkDeclarationNameFormat(node, node.name, MemberKind.Property);
super.visitGetAccessor(node);
}
visitSetAccessor(node) {
this.checkDeclarationNameFormat(node, node.name, MemberKind.Property);
super.visitSetAccessor(node);
}
visitConstructorDeclaration(node) {
for (const parameter of node.parameters) {
const accessModifier = TsHelpers.resolveAccessModifierFromModifiers(parameter.modifiers);
if (accessModifier === AccessModifier.Private) {
this.checkDeclarationNameFormat(parameter, parameter.name, MemberKind.Property);
}
}
super.visitConstructorDeclaration(node);
}
checkDeclarationNameFormat(node, name, kind) {
// Check if parent does not exist in ignore list.
const parent = node.parent;
if (parent.name != null) {
const parentName = parent.name.getText();
const excluded = this.ruleOptions.ignoreParentSuffixes.findIndex(x => parentName.endsWith(x)) !== -1;
if (excluded) {
return;
}
}
const searchOption = {
kind: kind,
modifier: TsHelpers.resolveAccessModifierFromModifiers(node.modifiers) || AccessModifier.Public,
isStatic: TsHelpers.modifierKindExistsInModifiers(node.modifiers, ts.SyntaxKind.StaticKeyword)
};
// Resolve format rule
const formatRule = this.getFormatRule(searchOption);
if (formatRule == null && this.ruleOptions.defaultFormat == null) {
return;
}
const format = formatRule != null ? formatRule.format : this.ruleOptions.defaultFormat;
const allowedPrefixes = formatRule != null ? formatRule.allowedPrefixes : undefined;
// Check if name is existing from heritage.
if (this.ruleOptions.skipOriginChecking ||
(parent != null && !TsHelpers.checkMemberNameInHeritageDeclarations(this.getProgram().getTypeChecker(), parent, name.getText()))) {
this.checkNameNode(name, format, allowedPrefixes);
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3NNZW1iZXJzTmFtZVJ1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2xhc3NNZW1iZXJzTmFtZVJ1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxpQ0FBaUM7QUFDakMsK0JBQStCO0FBQy9CLDBDQUEwQztBQUUxQyxNQUFNLG9CQUFvQixHQUFHLHNCQUFzQixDQUFDO0FBRXBELElBQUssTUFNSjtBQU5ELFdBQUssTUFBTTtJQUNQLHVCQUFhLENBQUE7SUFDYixrQ0FBd0IsQ0FBQTtJQUN4QixvQ0FBMEIsQ0FBQTtJQUMxQix3Q0FBOEIsQ0FBQTtJQUM5QixrQ0FBd0IsQ0FBQTtBQUM1QixDQUFDLEVBTkksTUFBTSxLQUFOLE1BQU0sUUFNVjtBQUVELElBQUssY0FJSjtBQUpELFdBQUssY0FBYztJQUNmLG1DQUFpQixDQUFBO0lBQ2pCLHFDQUFtQixDQUFBO0lBQ25CLHlDQUF1QixDQUFBO0FBQzNCLENBQUMsRUFKSSxjQUFjLEtBQWQsY0FBYyxRQUlsQjtBQUVELElBQUssVUFHSjtBQUhELFdBQUssVUFBVTtJQUNYLCtCQUFpQixDQUFBO0lBQ2pCLG1DQUFxQixDQUFBO0FBQ3pCLENBQUMsRUFISSxVQUFVLEtBQVYsVUFBVSxRQUdkO0FBZ0JELHdCQUF3QixHQUEwQjtJQUM5QyxPQUFPLEdBQUcsQ0FBQyxXQUFXLElBQUksSUFBSSxJQUFJLEdBQUcsQ0FBQyxvQkFBb0IsSUFBSSxJQUFJLENBQUM7QUFDdkUsQ0FBQztBQWVELElBQVUsYUFBYSxDQWtDdEI7QUFsQ0QsV0FBVSxhQUFhO0lBQ25CLHNCQUE2QixNQUFjLEVBQUUsSUFBWTtRQUNyRCxRQUFRLE1BQU0sRUFBRTtZQUNaLEtBQUssTUFBTSxDQUFDLElBQUk7Z0JBQ1osT0FBTyxJQUFJLENBQUM7WUFDaEIsS0FBSyxNQUFNLENBQUMsU0FBUztnQkFDakIsT0FBTyxVQUFVLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3RDLEtBQUss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Q0FBQyxrQkFBa0I7WUFDbkMsQ0FBQyxNQUFNLElBQUksSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLHFDQUFxQyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxjQUFjLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsRUFDbEk7WUFDRSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsZUFBZSxDQUFDLENBQUM7U0FDckQ7SUFDTCxDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyB0cyBmcm9tIFwidHlwZXNjcmlwdFwiO1xyXG5pbXBvcnQgKiBhcyBMaW50IGZyb20gXCJ0c2xpbnRcIjtcclxuaW1wb3J0ICogYXMgY2hhbmdlQ2FzZSBmcm9tIFwiY2hhbmdlLWNhc2VcIjtcclxuXHJcbmNvbnN0IFNLSVBfT1JJR0lOX0NIRUNLSU5HID0gXCJza2lwLW9yaWdpbi1jaGVja2luZ1wiO1xyXG5cclxuZW51bSBGb3JtYXQge1xyXG4gICAgTm9uZSA9IFwibm9uZVwiLFxyXG4gICAgQ2FtZWxDYXNlID0gXCJjYW1lbC1jYXNlXCIsXHJcbiAgICBQYXNjYWxDYXNlID0gXCJwYXNjYWwtY2FzZVwiLFxyXG4gICAgQ29uc3RhbnRDYXNlID0gXCJjb25zdGFudC1jYXNlXCIsXHJcbiAgICBTbmFrZUNhc2UgPSBcInNuYWtlLWNhc2VcIlxyXG59XHJcblxyXG5lbnVtIEFjY2Vzc01vZGlmaWVyIHtcclxuICAgIFB1YmxpYyA9IFwicHVibGljXCIsXHJcbiAgICBQcml2YXRlID0gXCJwcml2YXRlXCIsXHJcbiAgICBQcm90ZWN0ZWQgPSBcInByb3RlY3RlZFwiXHJcbn1cclxuXHJcbmVudW0gTWVtYmVyS2luZCB7XHJcbiAgICBNZXRob2QgPSBcIm1ldGhvZFwiLFxyXG4gICAgUHJvcGVydHkgPSBcInByb3BlcnR5XCJcclxufVxyXG5cclxuaW50ZXJmYWNlIEZvcm1hdFJ1bGUge1xyXG4gICAga2luZDogTWVtYmVyS2luZDtcclxuICAgIC8qKlxyXG4gICAgICogRGVmYXVsdCBcInB1YmxpY1wiXHJcbiAgICAgKi9cclxuICAgIG1vZGlmaWVyPzogQWNjZXNzTW9kaWZpZXI7XHJcbiAgICAvKipcclxuICAgICAqIERlZmF1bHQgXCJub25lXCJcclxuICAgICAqL1xyXG4gICAgZm9ybWF0PzogRm9ybWF0O1xyXG4gICAgaXNTdGF0aWM/OiBib29sZWFuO1xyXG4gICAgYWxsb3dlZFByZWZpeGVzPzogc3RyaW5nW107XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGlzUnVsZVNldHRpbmdzKG9iajogUGFydGlhbDxSdWxlU2V0dGluZ3M+KTogb2JqIGlzIFJ1bGVTZXR0aW5ncyB7XHJcbiAgICByZXR1cm4gb2JqLmZvcm1hdFJ1bGVzICE9IG51bGwgfHwgb2JqLmlnbm9yZVBhcmVudFN1ZmZpeGVzICE9IG51bGw7XHJcbn1cclxuXHJcbmludGVyZmFjZSBSdWxlU2V0dGluZ3Mge1xyXG4gICAgZm9ybWF0UnVsZXM/OiBGb3JtYXRSdWxlW107XHJcbiAgICBpZ25vcmVQYXJlbnRTdWZmaXhlcz86IHN0cmluZ1tdO1xyXG59XHJcblxyXG5pbnRlcmZhY2UgUmVzb2x2ZWRSdWxlT3B0aW9ucyB7XHJcbiAgICBza2lwT3JpZ2luQ2hlY2tpbmc6IGJvb2xlYW47XHJcbiAgICBkZWZhdWx0Rm9ybWF0PzogRm9ybWF0O1xyXG4gICAgcnVsZXM6IEZvcm1hdFJ1bGVbXTtcclxuICAgIGlnbm9yZVBhcmVudFN1ZmZpeGVzOiBzdHJpbmdbXTtcclxuICAgIHJhd09wdGlvbnM6IExpbnQuSU9wdGlvbnM7XHJcbn1cclxuXHJcbm5hbWVzcGFjZSBGb3JtYXRIZWxwZXJzIHtcclxuICAgIGV4cG9ydCBmdW5jdGlvbiBjaGFuZ2VGb3JtYXQoZm9ybWF0OiBGb3JtYXQsIHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICAgICAgc3dpdGNoIChmb3JtYXQpIHtcclxuICAgICAgICAgICAgY2FzZSBGb3JtYXQuTm9uZTpcclxuICAgICAgICAgICAgICAgIHJldHVybiB0ZXh0O1xyXG4gICAgICAgICAgICBjYXNlIEZvcm1hdC5DYW1lbENhc2U6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gY2hhbmdlQ2FzZS5jYW1lbENhc2UodGV4dCk7XHJcbiAgICAgICAgICAgIGNhc2UgRm9ybWF0LlBhc2NhbENhc2U6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gY2hhbmdlQ2FzZS5wYXNjYWxDYXNlKHRleHQpO1xyXG4gICAgICAgICAgICBjYXNlIEZvcm1hdC5Db25zdGFudENhc2U6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gY2hhbmdlQ2FzZS5jb25zdGFudENhc2UodGV4dCk7XHJcbiAgICAgICAgICAgIGNhc2UgRm9ybWF0LlNuYWtlQ2FzZTpcclxuICAgICAgICAgICAgICAgIHJldHVybiBjaGFuZ2VDYXNlLnNuYWtlQ2FzZSh0ZXh0KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZXhwb3J0IGZ1bmN0aW9uIGNoYW5nZUZvcm1hdFdpdGhQcmVmaXhlcyhmb3JtYXQ6IEZvcm1hdCwgdGV4dDogc3RyaW5nLCBhbGxvd2VkUHJlZml4ZXM6IHN0cmluZ1tdID0gW10pOiBzdHJpbmcge1xyXG4gICAgICAgIGlmIChhbGxvd2VkUHJlZml4ZXMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBjaGFuZ2VGb3JtYXQoZm9ybWF0LCB0ZXh0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGZvciAoY29uc3QgYWxsb3dlZFByZWZpeCBvZiBhbGxvd2VkUHJlZml4ZXMpIHtcclxuICAgICAgICAgICAgLy8gRmluZCBwcmVmaXggZnJvbSB0ZXh0IGluIGFsbG93ZWQgcHJlZml4ZXMuXHJcbiAgICAgICAgICAgIGNvbnN0IHByZWZpeDogc3RyaW5nID0gdGV4dC5zdWJzdHJpbmcoMCwgYWxsb3dlZFByZWZpeC5sZW5ndGgpO1xyXG4gICAgICAgICAgICBpZiAoYWxsb3dlZFByZWZpeCAhPT0gcHJlZml4KSB7XHJcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjb25zdCB0ZXh0V2l0aG91dFByZWZpeDogc3RyaW5nID0gdGV4dC5zdWJzdHJpbmcocHJlZml4Lmxlbmd0aCwgdGV4dC5sZW5ndGgpO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIGFsbG93ZWRQcmVmaXggKyBjaGFuZ2VGb3JtYXQoZm9ybWF0LCB0ZXh0V2l0aG91dFByZWZpeCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gY2hhbmdlRm9ybWF0KGZvcm1hdCwgdGV4dCk7XHJcbiAgICB9XHJcbn1cclxuXHJcbm5hbWVzcGFjZSBUc0hlbHBlcnMge1xyXG4gICAgZXhwb3J0IGZ1bmN0aW9uIG1vZGlmaWVyS2luZEV4aXN0c0luTW9kaWZpZXJzKG1vZGlmaWVyczogdHMuTm9kZUFycmF5PHRzLk1vZGlmaWVyPiB8IHVuZGVmaW5lZCwga2luZDogdHMuU3ludGF4S2luZCk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmIChtb2RpZmllcnMgIT0gbnVsbCkge1xyXG4gICAgICAgICAgICByZXR1cm4gbW9kaWZpZXJzLnNvbWUoeCA9PiB4LmtpbmQgPT09IGtpbmQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQWNjZXNzTW9kaWZpZXJGcm9tTW9kaWZpZXJzKG1vZGlmaWVycz86IHRzLk5vZGVBcnJheTx0cy5Nb2RpZmllcj4pOiBBY2Nlc3NNb2RpZmllciB8IHVuZGVmaW5lZCB7XHJcbiAgICAgICAgbGV0IGFjY2Vzc01vZGlmaWVyOiBBY2Nlc3NNb2RpZmllciB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgICAgaWYgKG1vZGlmaWVycyAhPSBudWxsKSB7XHJcbiAgICAgICAgICAgIG1vZGlmaWVycy5mb3JFYWNoKG1vZGlmaWVyID0+IHtcclxuICAgICAgICAgICAgICAgIHN3aXRjaCAobW9kaWZpZXIua2luZCkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgdHMuU3ludGF4S2luZC5QdWJsaWNLZXl3b3JkOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjY2Vzc01vZGlmaWVyID0gQWNjZXNzTW9kaWZpZXIuUHVibGljO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgdHMuU3ludGF4S2luZC5Qcml2YXRlS2V5d29yZDoge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBhY2Nlc3NNb2RpZmllciA9IEFjY2Vzc01vZGlmaWVyLlByaXZhdGU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgY2FzZSB0cy5TeW50YXhLaW5kLlByb3RlY3RlZEtleXdvcmQ6IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYWNjZXNzTW9kaWZpZXIgPSBBY2Nlc3NNb2RpZmllci5Qcm90ZWN0ZWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIGFjY2Vzc01vZGlmaWVyO1xyXG4gICAgfVxyXG5cclxuICAgIGV4cG9ydCB0eXBlIENsYXNzT3JJbnRlcmZhY2VEZWNsYXJhdGlvbiA9IHRzLkNsYXNzRGVjbGFyYXRpb24gfCB0cy5JbnRlcmZhY2VEZWNsYXJhdGlvbjtcclxuXHJcbiAgICBleHBvcnQgZnVuY3Rpb24gaXNEZWNsYXJhdGlvbldpdGhIZXJpdGFnZUNsYXVzZXMobm9kZTogdHMuTm9kZSk6IG5vZGUgaXMgQ2xhc3NPckludGVyZmFjZURlY2xhcmF0aW9uIHtcclxuICAgICAgICByZXR1cm4gKG5vZGUgYXMgQ2xhc3NPckludGVyZmFjZURlY2xhcmF0aW9uKS5oZXJpdGFnZUNsYXVzZXMgIT0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENoZWNrcyBhbGwgaGVyaXRhZ2UgbGlzdCB0byBmaW5kIHNwZWNpZmljIGdpdmVuIG5hbWUuIElmIGl0IGRvZXNuJ3QgZXhpc3QsIGl0IHJldHVybnMgZmFsc2UuXHJcbiAgICAgKiBAcGFyYW0gbm9kZSBOb2RlIHdpdGggaGVyaXRhZ2UgbGlzdC5cclxuICAgICAqIEBwYXJhbSB0YXJnZXROYW1lIE5hbWUgdG8gc2VhcmNoIGZvciBpbiBoZXJpdGFnZSBsaXN0LlxyXG4gICAgICovXHJcbiAgICBleHBvcnQgZnVuY3Rpb24gY2hlY2tNZW1iZXJOYW1lSW5IZXJpdGFnZURlY2xhcmF0aW9ucyhcclxuICAgICAgICB0eXBlQ2hlY2tlcjogdHMuVHlwZUNoZWNrZXIsXHJcbiAgICAgICAgbm9kZTogVHNIZWxwZXJzLkNsYXNzT3JJbnRlcmZhY2VEZWNsYXJhdGlvbiB8IHVuZGVmaW5lZCxcclxuICAgICAgICB0YXJnZXROYW1lOiBzdHJpbmdcclxuICAgICk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGlmIChub2RlID09IG51bGwpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKG5vZGUuaGVyaXRhZ2VDbGF1c2VzID09IG51bGwpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gR28gdGhyb3VnaCBFeHRlbmRzIGFuZCBJbXBsZW1lbnRzXHJcbiAgICAgICAgZm9yIChjb25zdCBoZXJpdGFnZSBvZiBub2RlLmhlcml0YWdlQ2xhdXNlcykge1xyXG4gICAgICAgICAgICBpZiAoaGVyaXRhZ2UudHlwZXMgPT0gbnVsbCkge1xyXG4gICAgICAgICAgICAgICAgY29udGludWU7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIEdvIHRocm91Z2ggdHlwZXMgb24gdGhhdCBoZXJpdGFnZS5cclxuICAgICAgICAgICAgZm9yIChjb25zdCB0eXBlTm9kZSBvZiBoZXJpdGFnZS50eXBlcykge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgdHlwZSA9IHR5cGVDaGVja2VyLmdldFR5cGVGcm9tVHlwZU5vZGUodHlwZU5vZGUpO1xyXG4gICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0U3ltYm9sID0gdHlwZS5nZXRTeW1ib2woKTtcclxuXHJcbiAgICAgICAgICAgICAgICBpZiAodGFyZ2V0U3ltYm9sICE9IG51bGwgJiYgdGFyZ2V0U3ltYm9sLmRlY2xhcmF0aW9ucyAhPSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGFyZ2V0IFN5bWJvbCBkZWNsYXJhdGlvbnMuXHJcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBkZWNsYXJhdGlvbiBvZiB0YXJnZXRTeW1ib2wuZGVjbGFyYXRpb25zKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEludGVyZmFjZSBhbmQgQ2xhc3NlcyBkZWNsYXJhdGlvbnMgb25seS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRzLmlzSW50ZXJmYWNlRGVjbGFyYXRpb24oZGVjbGFyYXRpb24pIHx8IHRzLmlzQ2xhc3NEZWNsYXJhdGlvbihkZWNsYXJhdGlvbikpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgbWVtYmVyIG9mIGRlY2xhcmF0aW9uLm1lbWJlcnMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBtZW1iZXJzIG5hbWUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1lbWJlci5uYW1lICE9IG51bGwgJiYgbWVtYmVyLm5hbWUuZ2V0VGV4dCgpID09PSB0YXJnZXROYW1lKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHbyBkZWVwZXIgdG8gY2hlY2tlciB0aGVpciBoZXJpdGFnZSBsaXN0cy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjaGVja01lbWJlck5hbWVJbkhlcml0YWdlRGVjbGFyYXRpb25zKHR5cGVDaGVja2VyLCBkZWNsYXJhdGlvbiwgdGFyZ2V0TmFtZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIFJ1bGUgZXh0ZW5kcyBMaW50LlJ1bGVzLlR5cGVkUnVsZSB7XHJcbiAgICBwdWJsaWMgc3RhdGljIGZhaWx1cmVNZXNzYWdlRmFjdG9yeShuYW1lOiBzdHJpbmcsIG5lZWRlZENhc2U6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIGBEZWNsYXJhdGlvbiBcIiR7bmFtZX1cIiBmb3JtYXQgaXMgbm90IGNvcnJlY3QgKCR7bmVlZGVkQ2FzZX0pLmA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBwYXJzZU9wdGlvbnMob3B0aW9uczogTGludC5JT3B0aW9ucyk6IFJlc29sdmVkUnVsZU9wdGlvbnMge1xyXG4gICAgICAgIGNvbnN0IGRlZmF1bHRGb3JtYXQ6IEZvcm1hdCA9IG9wdGlvbnMucnVsZUFyZ3VtZW50cy5maW5kKHggPT4gT2JqZWN0LnZhbHVlcyhGb3JtYXQpLmZpbmQoeSA9PiB5ID09PSB4KSAhPSBudWxsKTtcclxuICAgICAgICBjb25zdCBza2lwT3JpZ2luQ2hlY2tpbmc6IGJvb2xlYW4gPSBvcHRpb25zLnJ1bGVBcmd1bWVudHMuZmluZEluZGV4KHggPT4geCA9PT0gU0tJUF9PUklHSU5fQ0hFQ0tJTkcpICE9PSAtMTtcclxuICAgICAgICBjb25zdCBydWxlU2V0dGluZ3M6IFJ1bGVTZXR0aW5ncyA9IG9wdGlvbnMucnVsZUFyZ3VtZW50cy5maW5kKHggPT4gaXNSdWxlU2V0dGluZ3MoeCkpIHx8IHt9O1xyXG5cclxuICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBkZWZhdWx0Rm9ybWF0OiBkZWZhdWx0Rm9ybWF0IHx8IEZvcm1hdC5DYW1lbENhc2UsXHJcbiAgICAgICAgICAgIHNraXBPcmlnaW5DaGVja2luZzogc2tpcE9yaWdpbkNoZWNraW5nLFxyXG4gICAgICAgICAgICBydWxlczogcnVsZVNldHRpbmdzLmZvcm1hdFJ1bGVzIHx8IFtdLFxyXG4gICAgICAgICAgICBpZ25vcmVQYXJlbnRTdWZmaXhlczogcnVsZVNldHRpbmdzLmlnbm9yZVBhcmVudFN1ZmZpeGVzIHx8IFtdLFxyXG4gICAgICAgICAgICByYXdPcHRpb25zOiBvcHRpb25zXHJcbiAgICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgYXBwbHlXaXRoUHJvZ3JhbShzb3VyY2VGaWxlOiB0cy5Tb3VyY2VGaWxlLCBwcm9ncmFtOiB0cy5Qcm9ncmFtKTogTGludC5SdWxlRmFpbHVyZVtdIHtcclxuICAgICAgICBjb25zdCBwYXJzZWRPcHRpb25zID0gdGhpcy5wYXJzZU9wdGlvbnModGhpcy5nZXRPcHRpb25zKCkpO1xyXG4gICAgICAgIHJldHVybiB0aGlzLmFwcGx5V2l0aFdhbGtlcihuZXcgQ2xhc3NNZW1iZXJzV2Fsa2VyKHNvdXJjZUZpbGUsIHBhcnNlZE9wdGlvbnMsIHByb2dyYW0pKTtcclxuICAgIH1cclxufVxyXG5cclxuLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm5vLWFueVxyXG50eXBlIERpY3Rpb25hcnk8VFZhbHVlID0gYW55PiA9IHsgW2tleTogc3RyaW5nXTogVFZhbHVlIH07XHJcblxyXG4vLyBUaGUgd2Fsa2VyIHRha2VzIGNhcmUgb2YgYWxsIHRoZSB3b3JrLlxyXG5jbGFzcyBDbGFzc01lbWJlcnNXYWxrZXIgZXh0ZW5kcyBMaW50LlByb2dyYW1Bd2FyZVJ1bGVXYWxrZXIge1xyXG4gICAgY29uc3RydWN0b3Ioc291cmNlRmlsZTogdHMuU291cmNlRmlsZSwgcHJpdmF0ZSBydWxlT3B0aW9uczogUmVzb2x2ZWRSdWxlT3B0aW9ucywgcHJvZ3JhbTogdHMuUHJvZ3JhbSkge1xyXG4gICAgICAgIHN1cGVyKHNvdXJjZUZpbGUsIHJ1bGVPcHRpb25zLnJhd09wdGlvbnMsIHByb2dyYW0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vI3JlZ2lvbiBIZWxwaW5nIGZ1bmN0aW9uc1xyXG4gICAgcHJpdmF0ZSBnZXRGb3JtYXRSdWxlKHJ1bGU6IFBhcnRpYWw8Rm9ybWF0UnVsZT4gJiBEaWN0aW9uYXJ5KTogRm9ybWF0UnVsZSB8IHVuZGVmaW5lZCB7XHJcbiAgICAgICAgY29uc3QgcnVsZXM6IEFycmF5PEZvcm1hdFJ1bGUgJiBEaWN0aW9uYXJ5PiA9IHRoaXMucnVsZU9wdGlvbnMucnVsZXM7XHJcblxyXG4gICAgICAgIGNvbnN0IGluZGV4ID0gcnVsZXMuZmluZEluZGV4KHggPT4ge1xyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBydWxlKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoKHJ1bGUuaGFzT3duUHJvcGVydHkoa2V5KSAmJiBydWxlW2tleV0gPT09IHhba2V5XSkgfHwgcnVsZVtrZXldID09IG51bGwpIHtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIHJldHVybiBydWxlc1tpbmRleF07XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBjaGVja05hbWVOb2RlKG5hbWVOb2RlOiB0cy5Ob2RlLCBmb3JtYXQ6IEZvcm1hdCA9IEZvcm1hdC5Ob25lLCBhbGxvd2VkUHJlZml4ZXM6IHN0cmluZ1tdID0gW10pOiB2b2lkIHtcclxuICAgICAgICBjb25zdCBuYW1lID0gbmFtZU5vZGUuZ2V0VGV4dCgpO1xyXG4gICAgICAgIGNvbnN0IGNhc2VkTmFtZSA9IEZvcm1hdEhlbHBlcnMuY2hhbmdlRm9ybWF0V2l0aFByZWZpeGVzKGZvcm1hdCwgbmFtZSwgYWxsb3dlZFByZWZpeGVzKTtcclxuXHJcbiAgICAgICAgaWYgKGNhc2VkTmFtZSAhPT0gbmFtZSkge1xyXG4gICAgICAgICAgICAvLyBjcmVhdGUgYSBmaXhlciBmb3IgdGhpcyBmYWlsdXJlXHJcbiAgICAgICAgICAgIGNvbnN0IGZpeCA9IG5ldyBMaW50LlJlcGxhY2VtZW50KG5hbWVOb2RlLmdldFN0YXJ0KCksIG5hbWVOb2RlLmdldFdpZHRoKCksIGNhc2VkTmFtZSk7XHJcblxyXG4gICAgICAgICAgICAvLyBjcmVhdGUgYSBmYWlsdXJlIGF0IHRoZSBjdXJyZW50IHBvc2l0aW9uXHJcbiAgICAgICAgICAgIHRoaXMuYWRkRmFpbHVyZSh0aGlzLmNyZWF0ZUZhaWx1cmUobmFtZU5vZGUuZ2V0U3RhcnQoKSwgbmFtZU5vZGUuZ2V0V2lkdGgoKSwgUnVsZS5mYWlsdXJlTWVzc2FnZUZhY3RvcnkobmFtZSwgZm9ybWF0KSwgZml4KSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vI2VuZHJlZ2lvblxyXG5cclxuICAgIHB1YmxpYyB2aXNpdE1ldGhvZFNpZ25hdHVyZShub2RlOiB0cy5NZXRob2RTaWduYXR1cmUpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLmNoZWNrRGVjbGFyYXRpb25OYW1lRm9ybWF0KG5vZGUsIG5vZGUubmFtZSwgTWVtYmVyS2luZC5NZXRob2QpO1xyXG4gICAgICAgIHN1cGVyLnZpc2l0TWV0aG9kU2lnbmF0dXJlKG5vZGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyB2aXNpdE1ldGhvZERlY2xhcmF0aW9uKG5vZGU6IHRzLk1ldGhvZERlY2xhcmF0aW9uKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5jaGVja0RlY2xhcmF0aW9uTmFtZUZvcm1hdChub2RlLCBub2RlLm5hbWUsIE1lbWJlcktpbmQuTWV0aG9kKTtcclxuICAgICAgICBzdXBlci52aXNpdE1ldGhvZERlY2xhcmF0aW9uKG5vZGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyB2aXNpdFByb3BlcnR5U2lnbmF0dXJlKG5vZGU6IHRzLlByb3BlcnR5U2lnbmF0dXJlKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5jaGVja0RlY2xhcmF0aW9uTmFtZUZvcm1hdChub2RlLCBub2RlLm5hbWUsIE1lbWJlcktpbmQuUHJvcGVydHkpO1xyXG4gICAgICAgIHN1cGVyLnZpc2l0UHJvcGVydHlTaWduYXR1cmUobm9kZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHZpc2l0UHJvcGVydHlEZWNsYXJhdGlvbihub2RlOiB0cy5Qcm9wZXJ0eURlY2xhcmF0aW9uKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5jaGVja0RlY2xhcmF0aW9uTmFtZUZvcm1hdChub2RlLCBub2RlLm5hbWUsIE1lbWJlcktpbmQuUHJvcGVydHkpO1xyXG4gICAgICAgIHN1cGVyLnZpc2l0UHJvcGVydHlEZWNsYXJhdGlvbihub2RlKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgdmlzaXRHZXRBY2Nlc3Nvcihub2RlOiB0cy5HZXRBY2Nlc3NvckRlY2xhcmF0aW9uKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5jaGVja0RlY2xhcmF0aW9uTmFtZUZvcm1hdChub2RlLCBub2RlLm5hbWUsIE1lbWJlcktpbmQuUHJvcGVydHkpO1xyXG4gICAgICAgIHN1cGVyLnZpc2l0R2V0QWNjZXNzb3Iobm9kZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHZpc2l0U2V0QWNjZXNzb3Iobm9kZTogdHMuU2V0QWNjZXNzb3JEZWNsYXJhdGlvbik6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuY2hlY2tEZWNsYXJhdGlvbk5hbWVGb3JtYXQobm9kZSwgbm9kZS5uYW1lLCBNZW1iZXJLaW5kLlByb3BlcnR5KTtcclxuICAgICAgICBzdXBlci52aXNpdFNldEFjY2Vzc29yKG5vZGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyB2aXNpdENvbnN0cnVjdG9yRGVjbGFyYXRpb24obm9kZTogdHMuQ29uc3RydWN0b3JEZWNsYXJhdGlvbik6IHZvaWQge1xyXG4gICAgICAgIGZvciAoY29uc3QgcGFyYW1ldGVyIG9mIG5vZGUucGFyYW1ldGVycykge1xyXG4gICAgICAgICAgICBjb25zdCBhY2Nlc3NNb2RpZmllciA9IFRzSGVscGVycy5yZXNvbHZlQWNjZXNzTW9kaWZpZXJGcm9tTW9kaWZpZXJzKHBhcmFtZXRlci5tb2RpZmllcnMpO1xyXG4gICAgICAgICAgICBpZiAoYWNjZXNzTW9kaWZpZXIgPT09IEFjY2Vzc01vZGlmaWVyLlByaXZhdGUpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY2hlY2tEZWNsYXJhdGlvbk5hbWVGb3JtYXQocGFyYW1ldGVyLCBwYXJhbWV0ZXIubmFtZSwgTWVtYmVyS2luZC5Qcm9wZXJ0eSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHN1cGVyLnZpc2l0Q29uc3RydWN0b3JEZWNsYXJhdGlvbihub2RlKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNoZWNrRGVjbGFyYXRpb25OYW1lRm9ybWF0KG5vZGU6IHRzLkRlY2xhcmF0aW9uLCBuYW1lOiB0cy5Ob2RlLCBraW5kOiBNZW1iZXJLaW5kKTogdm9pZCB7XHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgcGFyZW50IGRvZXMgbm90IGV4aXN0IGluIGlnbm9yZSBsaXN0LlxyXG4gICAgICAgIGNvbnN0IHBhcmVudCA9IG5vZGUucGFyZW50IGFzIFRzSGVscGVycy5DbGFzc09ySW50ZXJmYWNlRGVjbGFyYXRpb247XHJcbiAgICAgICAgaWYgKHBhcmVudC5uYW1lICE9IG51bGwpIHtcclxuICAgICAgICAgICAgY29uc3QgcGFyZW50TmFtZSA9IHBhcmVudC5uYW1lLmdldFRleHQoKTtcclxuICAgICAgICAgICAgY29uc3QgZXhjbHVkZWQgPSB0aGlzLnJ1bGVPcHRpb25zLmlnbm9yZVBhcmVudFN1ZmZpeGVzLmZpbmRJbmRleCh4ID0+IHBhcmVudE5hbWUuZW5kc1dpdGgoeCkpICE9PSAtMTtcclxuXHJcbiAgICAgICAgICAgIGlmIChleGNsdWRlZCkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCBzZWFyY2hPcHRpb246IFBhcnRpYWw8Rm9ybWF0UnVsZT4gPSB7XHJcbiAgICAgICAgICAgIGtpbmQ6IGtpbmQsXHJcbiAgICAgICAgICAgIG1vZGlmaWVyOiBUc0hlbHBlcnMucmVzb2x2ZUFjY2Vzc01vZGlmaWVyRnJvbU1vZGlmaWVycyhub2RlLm1vZGlmaWVycykgfHwgQWNjZXNzTW9kaWZpZXIuUHVibGljLFxyXG4gICAgICAgICAgICBpc1N0YXRpYzogVHNIZWxwZXJzLm1vZGlmaWVyS2luZEV4aXN0c0luTW9kaWZpZXJzKG5vZGUubW9kaWZpZXJzLCB0cy5TeW50YXhLaW5kLlN0YXRpY0tleXdvcmQpXHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gUmVzb2x2ZSBmb3JtYXQgcnVsZVxyXG4gICAgICAgIGNvbnN0IGZvcm1hdFJ1bGUgPSB0aGlzLmdldEZvcm1hdFJ1bGUoc2VhcmNoT3B0aW9uKTtcclxuICAgICAgICBpZiAoZm9ybWF0UnVsZSA9PSBudWxsICYmIHRoaXMucnVsZU9wdGlvbnMuZGVmYXVsdEZvcm1hdCA9PSBudWxsKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IGZvcm1hdDogRm9ybWF0IHwgdW5kZWZpbmVkID0gZm9ybWF0UnVsZSAhPSBudWxsID8gZm9ybWF0UnVsZS5mb3JtYXQgOiB0aGlzLnJ1bGVPcHRpb25zLmRlZmF1bHRGb3JtYXQ7XHJcbiAgICAgICAgY29uc3QgYWxsb3dlZFByZWZpeGVzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCA9IGZvcm1hdFJ1bGUgIT0gbnVsbCA/IGZvcm1hdFJ1bGUuYWxsb3dlZFByZWZpeGVzIDogdW5kZWZpbmVkO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpZiBuYW1lIGlzIGV4aXN0aW5nIGZyb20gaGVyaXRhZ2UuXHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgICB0aGlzLnJ1bGVPcHRpb25zLnNraXBPcmlnaW5DaGVja2luZyB8fFxyXG4gICAgICAgICAgICAocGFyZW50ICE9IG51bGwgJiYgIVRzSGVscGVycy5jaGVja01lbWJlck5hbWVJbkhlcml0YWdlRGVjbGFyYXRpb25zKHRoaXMuZ2V0UHJvZ3JhbSgpLmdldFR5cGVDaGVja2VyKCksIHBhcmVudCwgbmFtZS5nZXRUZXh0KCkpKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgICB0aGlzLmNoZWNrTmFtZU5vZGUobmFtZSwgZm9ybWF0LCBhbGxvd2VkUHJlZml4ZXMpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iXX0=