UNPKG

simplr-tslint

Version:

A set of TSLint rules used in SimplrJS projects.

256 lines 39.4 kB
"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=