UNPKG

tslint-language-service

Version:
364 lines 59.1 kB
"use strict"; const path = require("path"); const mockRequire = require("mock-require"); const TSLINT_ERROR_CODE = 100000; function init(modules) { const ts = modules.typescript; let tslint = require('tslint'); let codeFixActions = new Map(); let registeredCodeFixes = false; let configCache = { filePath: null, configuration: null, isDefaultConfig: false, configFilePath: null }; // Work around the lack of API to register a CodeFix function registerCodeFix(action) { return ts.codefix.registerCodeFix(action); } if (!registeredCodeFixes && ts && ts.codefix) { registerCodeFixes(registerCodeFix); registeredCodeFixes = true; } function registerCodeFixes(registerCodeFix) { // Code fix for that is used for all tslint fixes registerCodeFix({ errorCodes: [TSLINT_ERROR_CODE], getCodeActions: (_context) => { return null; } }); } function fixRelativeConfigFilePath(config, projectRoot) { if (!config.configFile) { return config; } if (path.isAbsolute(config.configFile)) { return config; } config.configFile = path.join(projectRoot, config.configFile); return config; } function create(info) { info.project.projectService.logger.info("tslint-language-service loaded"); let config = fixRelativeConfigFilePath(info.config, info.project.getCurrentDirectory()); let configuration = null; if (config.mockTypeScriptVersion) { mockRequire('typescript', ts); tslint = mockRequire.reRequire('tslint'); } // Set up decorator const proxy = Object.create(null); const oldLS = info.languageService; for (const k in oldLS) { proxy[k] = function () { return oldLS[k].apply(oldLS, arguments); }; } // key to identify a rule failure function computeKey(start, end) { return `[${start},${end}]`; } function makeDiagnostic(problem, file) { let message = (problem.getRuleName() !== null) ? `${problem.getFailure()} (${problem.getRuleName()})` : `${problem.getFailure()}`; let category; if (config.alwaysShowRuleFailuresAsWarnings === true) { category = ts.DiagnosticCategory.Warning; } else if (problem.getRuleSeverity && problem.getRuleSeverity() === 'error') { // tslint5 supports to assign severities to rules category = ts.DiagnosticCategory.Error; } else { category = ts.DiagnosticCategory.Warning; } let diagnostic = { file: file, start: problem.getStartPosition().getPosition(), length: problem.getEndPosition().getPosition() - problem.getStartPosition().getPosition(), messageText: message, category: category, source: 'tslint', code: TSLINT_ERROR_CODE }; return diagnostic; } /** * Filter failures for the given document */ function filterProblemsForDocument(documentPath, failures) { let normalizedPath = path.normalize(documentPath); // we only show diagnostics targetting this open document, some tslint rule return diagnostics for other documents/files let normalizedFiles = new Map(); return failures.filter(each => { let fileName = each.getFileName(); if (!normalizedFiles.has(fileName)) { normalizedFiles.set(fileName, path.normalize(fileName)); } return normalizedFiles.get(fileName) === normalizedPath; }); } function replacementsAreEmpty(fix) { // in tslint 4 a Fix has a replacement property witht the Replacements if (fix.replacements) { return fix.replacements.length === 0; } // tslint 5 if (Array.isArray(fix)) { return fix.length === 0; } return false; } function recordCodeAction(problem, file) { let fix = null; // tslint can return a fix with an empty replacements array, these fixes are ignored if (problem.getFix && problem.getFix() && !replacementsAreEmpty(problem.getFix())) { fix = problem.getFix(); // createAutoFix(problem, document, problem.getFix()); } if (!fix) { return; } let documentAutoFixes = codeFixActions.get(file.fileName); if (!documentAutoFixes) { documentAutoFixes = new Map(); codeFixActions.set(file.fileName, documentAutoFixes); } documentAutoFixes.set(computeKey(problem.getStartPosition().getPosition(), problem.getEndPosition().getPosition()), problem); } function getConfigurationFailureMessage(err) { let errorMessage = `unknown error`; if (typeof err.message === 'string' || err.message instanceof String) { errorMessage = err.message; } return `tslint: Cannot read tslint configuration - '${errorMessage}'`; } function getConfiguration(filePath, configFileName) { if (configCache.configuration && configCache.filePath === filePath) { return configCache.configuration; } let isDefaultConfig = false; let configuration; let configFilePath = null; isDefaultConfig = tslint.Configuration.findConfigurationPath(configFileName, filePath) === undefined; let configurationResult = tslint.Configuration.findConfiguration(configFileName, filePath); // between tslint 4.0.1 and tslint 4.0.2 the attribute 'error' has been removed from IConfigurationLoadResult // in 4.0.2 findConfiguration throws an exception as in version ^3.0.0 if (configurationResult.error) { throw configurationResult.error; } configuration = configurationResult.results; // In tslint version 5 the 'no-unused-variable' rules breaks the TypeScript language service plugin. // See https://github.com/Microsoft/TypeScript/issues/15344 // Therefore we remove the rule from the configuration. // // In tslint 5 the rules are stored in a Map, in earlier versions they were stored in an Object if (config.disableNoUnusedVariableRule === true || config.disableNoUnusedVariableRule === undefined) { if (configuration.rules && configuration.rules instanceof Map) { configuration.rules.delete('no-unused-variable'); } if (configuration.jsRules && configuration.jsRules instanceof Map) { configuration.jsRules.delete('no-unused-variable'); } } configFilePath = configurationResult.path; configCache = { filePath: filePath, isDefaultConfig: isDefaultConfig, configuration: configuration, configFilePath: configFilePath }; return configCache.configuration; } function captureWarnings(message) { // TODO log to a user visible log and not only the TS-Server log info.project.projectService.logger.info(`[tslint] ${message}`); } function convertReplacementToTextChange(repl) { return { newText: repl.text, span: { start: repl.start, length: repl.length } }; } function getReplacements(fix) { let replacements = null; // in tslint4 a Fix has a replacement property with the Replacements if (fix.replacements) { // tslint4 replacements = fix.replacements; } else { // in tslint 5 a Fix is a Replacement | Replacement[] if (!Array.isArray(fix)) { replacements = [fix]; } else { replacements = fix; } } return replacements; } function addRuleFailureFix(fixes, problem, fileName) { let fix = problem.getFix(); let replacements = getReplacements(fix); fixes.push({ description: `Fix '${problem.getRuleName()}'`, changes: [{ fileName: fileName, textChanges: replacements.map(each => convertReplacementToTextChange(each)) }] }); } function addDisableRuleFix(fixes, problem, fileName, file) { fixes.push({ description: `Disable rule '${problem.getRuleName()}'`, changes: [{ fileName: fileName, textChanges: [{ newText: `// tslint:disable-next-line:${problem.getRuleName()}\n`, span: { start: file.getLineStarts()[problem.getStartPosition().getLineAndCharacter().line], length: 0 } }] }] }); } function addOpenConfigurationFix(fixes) { // the Open Configuration code action is disabled since there is no specified API to open an editor let openConfigFixEnabled = false; if (openConfigFixEnabled && configCache && configCache.configFilePath) { fixes.push({ description: `Open tslint.json`, changes: [{ fileName: configCache.configFilePath, textChanges: [] }] }); } } function addAllAutoFixable(fixes, documentFixes, fileName) { const allReplacements = getNonOverlappingReplacements(documentFixes); fixes.push({ description: `Fix all auto-fixable tslint failures`, changes: [{ fileName: fileName, textChanges: allReplacements.map(each => convertReplacementToTextChange(each)) }] }); } function getReplacement(failure, at) { return getReplacements(failure.getFix())[at]; } function sortFailures(failures) { // The failures.replacements are sorted by position, we sort on the position of the first replacement return failures.sort((a, b) => { return getReplacement(a, 0).start - getReplacement(b, 0).start; }); } function getNonOverlappingReplacements(documentFixes) { function overlaps(a, b) { return a.end >= b.start; } let sortedFailures = sortFailures([...documentFixes.values()]); let nonOverlapping = []; for (let i = 0; i < sortedFailures.length; i++) { let replacements = getReplacements(sortedFailures[i].getFix()); if (i === 0 || !overlaps(nonOverlapping[nonOverlapping.length - 1], replacements[0])) { nonOverlapping.push(...replacements); } } return nonOverlapping; } proxy.getSemanticDiagnostics = (fileName) => { const prior = oldLS.getSemanticDiagnostics(fileName); if (config.supressWhileTypeErrorsPresent && prior.length > 0) { return prior; } try { info.project.projectService.logger.info(`Computing tslint semantic diagnostics...`); if (codeFixActions.has(fileName)) { codeFixActions.delete(fileName); } if (config.ignoreDefinitionFiles === true && fileName.endsWith('.d.ts')) { return prior; } try { configuration = getConfiguration(fileName, config.configFile); } catch (err) { // TODO: show the reason for the configuration failure to the user and not only in the log // https://github.com/Microsoft/TypeScript/issues/15913 info.project.projectService.logger.info(getConfigurationFailureMessage(err)); return prior; } let result; // tslint writes warning messages using console.warn() // capture the warnings and write them to the tslint plugin log let warn = console.warn; console.warn = captureWarnings; try { // TODO the types of the Program provided by tsserver libary are not compatible with the one provided by typescript // casting away the type let options = { fix: false }; let linter = new tslint.Linter(options, oldLS.getProgram()); linter.lint(fileName, "", configuration); result = linter.getResult(); } catch (err) { let errorMessage = `unknown error`; if (typeof err.message === 'string' || err.message instanceof String) { errorMessage = err.message; } info.project.projectService.logger.info('tslint error ' + errorMessage); return prior; } finally { console.warn = warn; } if (result.failures.length > 0) { const tslintProblems = filterProblemsForDocument(fileName, result.failures); if (tslintProblems && tslintProblems.length) { const file = oldLS.getProgram().getSourceFile(fileName); const diagnostics = prior ? [...prior] : []; tslintProblems.forEach(problem => { diagnostics.push(makeDiagnostic(problem, file)); recordCodeAction(problem, file); }); return diagnostics; } } } catch (e) { info.project.projectService.logger.info(`tslint-language service error: ${e.toString()}`); info.project.projectService.logger.info(`Stack trace: ${e.stack}`); } return prior; }; proxy.getCodeFixesAtPosition = function (fileName, start, end, errorCodes, formatOptions) { let prior = oldLS.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions); if (config.supressWhileTypeErrorsPresent && prior.length > 0) { return prior; } info.project.projectService.logger.info("tslint-language-service getCodeFixes " + errorCodes[0]); let documentFixes = codeFixActions.get(fileName); if (documentFixes) { const fixes = prior ? [...prior] : []; let problem = documentFixes.get(computeKey(start, end)); if (problem) { addRuleFailureFix(fixes, problem, fileName); } addAllAutoFixable(fixes, documentFixes, fileName); if (problem) { addOpenConfigurationFix(fixes); addDisableRuleFix(fixes, problem, fileName, oldLS.getProgram().getSourceFile(fileName)); } return fixes; } return prior; }; return proxy; } return { create }; } module.exports = init; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUVBLDZCQUE2QjtBQUM3Qiw0Q0FBNEM7QUFZNUMsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLENBQUM7QUFFakMsY0FBYyxPQUF5QztJQUNuRCxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDO0lBQzlCLElBQUksTUFBTSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUUvQixJQUFJLGNBQWMsR0FBRyxJQUFJLEdBQUcsRUFBMkMsQ0FBQztJQUN4RSxJQUFJLG1CQUFtQixHQUFHLEtBQUssQ0FBQztJQUVoQyxJQUFJLFdBQVcsR0FBRztRQUNkLFFBQVEsRUFBVSxJQUFJO1FBQ3RCLGFBQWEsRUFBTyxJQUFJO1FBQ3hCLGVBQWUsRUFBRSxLQUFLO1FBQ3RCLGNBQWMsRUFBVSxJQUFJO0tBQy9CLENBQUM7SUFFRixvREFBb0Q7SUFDcEQseUJBQXlCLE1BQXVCO1FBQzVDLE1BQU0sQ0FBRSxFQUFVLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBRUQsRUFBRSxDQUFDLENBQUMsQ0FBQyxtQkFBbUIsSUFBSSxFQUFFLElBQUssRUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFDcEQsaUJBQWlCLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDbkMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0lBQy9CLENBQUM7SUFFRCwyQkFBMkIsZUFBa0Q7UUFDekUsaURBQWlEO1FBQ2pELGVBQWUsQ0FBQztZQUNaLFVBQVUsRUFBRSxDQUFDLGlCQUFpQixDQUFDO1lBQy9CLGNBQWMsRUFBRSxDQUFDLFFBQWEsRUFBRSxFQUFFO2dCQUM5QixNQUFNLENBQUMsSUFBSSxDQUFDO1lBQ2hCLENBQUM7U0FDSixDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsbUNBQW1DLE1B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LENBQUMsQ0FBQztnQkFDNUYsQ0FBQztnQkFFRCxNQUFNLENBQUMsS0FBSyxDQUFDO1lBQ2pCLENBQUM7WUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDO1FBQ2pCLENBQUMsQ0FBQztRQUNGLE1BQU0sQ0FBQyxLQUFLLENBQUM7SUFDakIsQ0FBQztJQUVELE1BQU0sQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDO0FBQ3RCLENBQUM7QUFFRCxpQkFBUyxJQUFJLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyB0c19tb2R1bGUgZnJvbSBcIi4uL25vZGVfbW9kdWxlcy90eXBlc2NyaXB0L2xpYi90c3NlcnZlcmxpYnJhcnlcIjtcbmltcG9ydCAqIGFzIHRzbGludCBmcm9tICd0c2xpbnQnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIG1vY2tSZXF1aXJlIGZyb20gJ21vY2stcmVxdWlyZSc7XG5cbi8vIFNldHRpbmdzIGZvciB0aGUgcGx1Z2luIHNlY3Rpb24gaW4gdHNjb25maWcuanNvblxuaW50ZXJmYWNlIFNldHRpbmdzIHtcbiAgICBhbHdheXNTaG93UnVsZUZhaWx1cmVzQXNXYXJuaW5ncz86IGJvb2xlYW47XG4gICAgaWdub3JlRGVmaW5pdGlvbkZpbGVzPzogYm9vbGVhbjtcbiAgICBjb25maWdGaWxlPzogc3RyaW5nO1xuICAgIGRpc2FibGVOb1VudXNlZFZhcmlhYmxlUnVsZT86IGJvb2xlYW4gIC8vIHN1cHBvcnQgdG8gZW5hYmxlL2Rpc2FibGUgdGhlIHdvcmthcm91bmQgZm9yIGh0dHBzOi8vZ2l0aHViLmNvbS9NaWNyb3NvZnQvVHlwZVNjcmlwdC9pc3N1ZXMvMTUzNDRcbiAgICBzdXByZXNzV2hpbGVUeXBlRXJyb3JzUHJlc2VudDogYm9vbGVhbjtcbiAgICBtb2NrVHlwZVNjcmlwdFZlcnNpb246IGJvb2xlYW47XG59XG5cbmNvbnN0IFRTTElOVF9FUlJPUl9DT0RFID0gMTAwMDAwO1xuXG5mdW5jdGlvbiBpbml0KG1vZHVsZXM6IHsgdHlwZXNjcmlwdDogdHlwZW9mIHRzX21vZHVsZSB9KSB7XG4gICAgY29uc3QgdHMgPSBtb2R1bGVzLnR5cGVzY3JpcHQ7XG4gICAgbGV0IHRzbGludCA9IHJlcXVpcmUoJ3RzbGludCcpO1xuXG4gICAgbGV0IGNvZGVGaXhBY3Rpb25zID0gbmV3IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIHRzbGludC5SdWxlRmFpbHVyZT4+KCk7XG4gICAgbGV0IHJlZ2lzdGVyZWRDb2RlRml4ZXMgPSBmYWxzZTtcblxuICAgIGxldCBjb25maWdDYWNoZSA9IHtcbiAgICAgICAgZmlsZVBhdGg6IDxzdHJpbmc+bnVsbCxcbiAgICAgICAgY29uZmlndXJhdGlvbjogPGFueT5udWxsLFxuICAgICAgICBpc0RlZmF1bHRDb25maWc6IGZhbHNlLFxuICAgICAgICBjb25maWdGaWxlUGF0aDogPHN0cmluZz5udWxsXG4gICAgfTtcblxuICAgIC8vIFdvcmsgYXJvdW5kIHRoZSBsYWNrIG9mIEFQSSB0byByZWdpc3RlciBhIENvZGVGaXhcbiAgICBmdW5jdGlvbiByZWdpc3RlckNvZGVGaXgoYWN0aW9uOiBjb2RlZml4LkNvZGVGaXgpIHtcbiAgICAgICAgcmV0dXJuICh0cyBhcyBhbnkpLmNvZGVmaXgucmVnaXN0ZXJDb2RlRml4KGFjdGlvbik7XG4gICAgfVxuXG4gICAgaWYgKCFyZWdpc3RlcmVkQ29kZUZpeGVzICYmIHRzICYmICh0cyBhcyBhbnkpLmNvZGVmaXgpIHtcbiAgICAgICAgcmVnaXN0ZXJDb2RlRml4ZXMocmVnaXN0ZXJDb2RlRml4KTtcbiAgICAgICAgcmVnaXN0ZXJlZENvZGVGaXhlcyA9IHRydWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVnaXN0ZXJDb2RlRml4ZXMocmVnaXN0ZXJDb2RlRml4OiAoYWN0aW9uOiBjb2RlZml4LkNvZGVGaXgpID0+IHZvaWQpIHtcbiAgICAgICAgLy8gQ29kZSBmaXggZm9yIHRoYXQgaXMgdXNlZCBmb3IgYWxsIHRzbGludCBmaXhlc1xuICAgICAgICByZWdpc3RlckNvZGVGaXgoe1xuICAgICAgICAgICAgZXJyb3JDb2RlczogW1RTTElOVF9FUlJPUl9DT0RFXSxcbiAgICAgICAgICAgIGdldENvZGVBY3Rpb25zOiAoX2NvbnRleHQ6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBmaXhSZWxhdGl2ZUNvbmZpZ0ZpbGVQYXRoKGNvbmZpZzogU2V0dGluZ3MsIHByb2plY3RSb290OiBzdHJpbmcpOiBTZXR0aW5ncyB7XG4gICAgICAgIGlmICghY29uZmlnLmNvbmZpZ0ZpbGUpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25maWc7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHBhdGguaXNBYnNvbHV0ZShjb25maWcuY29uZmlnRmlsZSkpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25maWc7XG4gICAgICAgIH1cbiAgICAgICAgY29uZmlnLmNvbmZpZ0ZpbGUgPSBwYXRoLmpvaW4ocHJvamVjdFJvb3QsIGNvbmZpZy5jb25maWdGaWxlKTtcbiAgICAgICAgcmV0dXJuIGNvbmZpZztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjcmVhdGUoaW5mbzogdHMuc2VydmVyLlBsdWdpbkNyZWF0ZUluZm8pIHtcbiAgICAgICAgaW5mby5wcm9qZWN0LnByb2plY3RTZXJ2aWNlLmxvZ2dlci5pbmZvKFwidHNsaW50LWxhbmd1YWdlLXNlcnZpY2UgbG9hZGVkXCIpO1xuICAgICAgICBsZXQgY29uZmlnOiBTZXR0aW5ncyA9IGZpeFJlbGF0aXZlQ29uZmlnRmlsZVBhdGgoaW5mby5jb25maWcsIGluZm8ucHJvamVjdC5nZXRDdXJyZW50RGlyZWN0b3J5KCkpO1xuICAgICAgICBsZXQgY29uZmlndXJhdGlvbjogdHNsaW50LkNvbmZpZ3VyYXRpb24uSUNvbmZpZ3VyYXRpb25GaWxlID0gbnVsbDtcblxuICAgICAgICBpZihjb25maWcubW9ja1R5cGVTY3JpcHRWZXJzaW9uKSB7XG4gICAgICAgICAgICBtb2NrUmVxdWlyZSgndHlwZXNjcmlwdCcsIHRzKTtcbiAgICAgICAgICAgIHRzbGludCA9IG1vY2tSZXF1aXJlLnJlUmVxdWlyZSgndHNsaW50Jyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTZXQgdXAgZGVjb3JhdG9yXG4gICAgICAgIGNvbnN0IHByb3h5ID0gT2JqZWN0LmNyZWF0ZShudWxsKSBhcyB0cy5MYW5ndWFnZVNlcnZpY2U7XG4gICAgICAgIGNvbnN0IG9sZExTID0gaW5mby5sYW5ndWFnZVNlcnZpY2U7XG4gICAgICAgIGZvciAoY29uc3QgayBpbiBvbGRMUykge1xuICAgICAgICAgICAgKDxhbnk+cHJveHkpW2tdID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoPGFueT5vbGRMUylba10uYXBwbHkob2xkTFMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBrZXkgdG8gaWRlbnRpZnkgYSBydWxlIGZhaWx1cmVcbiAgICAgICAgZnVuY3Rpb24gY29tcHV0ZUtleShzdGFydDogbnVtYmVyLCBlbmQ6IG51bWJlcik6IHN0cmluZyB7XG4gICAgICAgICAgICByZXR1cm4gYFske3N0YXJ0fSwke2VuZH1dYDtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIG1ha2VEaWFnbm9zdGljKHByb2JsZW06IHRzbGludC5SdWxlRmFpbHVyZSwgZmlsZTogdHMuU291cmNlRmlsZSk6IHRzLkRpYWdub3N0aWMge1xuICAgICAgICAgICAgbGV0IG1lc3NhZ2UgPSAocHJvYmxlbS5nZXRSdWxlTmFtZSgpICE9PSBudWxsKVxuICAgICAgICAgICAgICAgID8gYCR7cHJvYmxlbS5nZXRGYWlsdXJlKCl9ICgke3Byb2JsZW0uZ2V0UnVsZU5hbWUoKX0pYFxuICAgICAgICAgICAgICAgIDogYCR7cHJvYmxlbS5nZXRGYWlsdXJlKCl9YDtcblxuICAgICAgICAgICAgbGV0IGNhdGVnb3J5O1xuICAgICAgICAgICAgaWYgKGNvbmZpZy5hbHdheXNTaG93UnVsZUZhaWx1cmVzQXNXYXJuaW5ncyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIGNhdGVnb3J5ID0gdHMuRGlhZ25vc3RpY0NhdGVnb3J5Lldhcm5pbmc7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCg8YW55PnByb2JsZW0pLmdldFJ1bGVTZXZlcml0eSAmJiAoPGFueT5wcm9ibGVtKS5nZXRSdWxlU2V2ZXJpdHkoKSA9PT0gJ2Vycm9yJykge1xuICAgICAgICAgICAgICAgIC8vIHRzbGludDUgc3VwcG9ydHMgdG8gYXNzaWduIHNldmVyaXRpZXMgdG8gcnVsZXNcbiAgICAgICAgICAgICAgICBjYXRlZ29yeSA9IHRzLkRpYWdub3N0aWNDYXRlZ29yeS5FcnJvcjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY2F0ZWdvcnkgPSB0cy5EaWFnbm9zdGljQ2F0ZWdvcnkuV2FybmluZztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IGRpYWdub3N0aWM6IHRzLkRpYWdub3N0aWMgPSB7XG4gICAgICAgICAgICAgICAgZmlsZTogZmlsZSxcbiAgICAgICAgICAgICAgICBzdGFydDogcHJvYmxlbS5nZXRTdGFydFBvc2l0aW9uKCkuZ2V0UG9zaXRpb24oKSxcbiAgICAgICAgICAgICAgICBsZW5ndGg6IHByb2JsZW0uZ2V0RW5kUG9zaXRpb24oKS5nZXRQb3NpdGlvbigpIC0gcHJvYmxlbS5nZXRTdGFydFBvc2l0aW9uKCkuZ2V0UG9zaXRpb24oKSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlVGV4dDogbWVzc2FnZSxcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogY2F0ZWdvcnksXG4gICAgICAgICAgICAgICAgc291cmNlOiAndHNsaW50JyxcbiAgICAgICAgICAgICAgICBjb2RlOiBUU0xJTlRfRVJST1JfQ09ERVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBkaWFnbm9zdGljO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZpbHRlciBmYWlsdXJlcyBmb3IgdGhlIGdpdmVuIGRvY3VtZW50XG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBmaWx0ZXJQcm9ibGVtc0ZvckRvY3VtZW50KGRvY3VtZW50UGF0aDogc3RyaW5nLCBmYWlsdXJlczogdHNsaW50LlJ1bGVGYWlsdXJlW10pOiB0c2xpbnQuUnVsZUZhaWx1cmVbXSB7XG4gICAgICAgICAgICBsZXQgbm9ybWFsaXplZFBhdGggPSBwYXRoLm5vcm1hbGl6ZShkb2N1bWVudFBhdGgpO1xuICAgICAgICAgICAgLy8gd2Ugb25seSBzaG93IGRpYWdub3N0aWNzIHRhcmdldHRpbmcgdGhpcyBvcGVuIGRvY3VtZW50LCBzb21lIHRzbGludCBydWxlIHJldHVybiBkaWFnbm9zdGljcyBmb3Igb3RoZXIgZG9jdW1lbnRzL2ZpbGVzXG4gICAgICAgICAgICBsZXQgbm9ybWFsaXplZEZpbGVzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgICAgICAgICAgIHJldHVybiBmYWlsdXJlcy5maWx0ZXIoZWFjaCA9PiB7XG4gICAgICAgICAgICAgICAgbGV0IGZpbGVOYW1lID0gZWFjaC5nZXRGaWxlTmFtZSgpO1xuICAgICAgICAgICAgICAgIGlmICghbm9ybWFsaXplZEZpbGVzLmhhcyhmaWxlTmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZEZpbGVzLnNldChmaWxlTmFtZSwgcGF0aC5ub3JtYWxpemUoZmlsZU5hbWUpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZWRGaWxlcy5nZXQoZmlsZU5hbWUpID09PSBub3JtYWxpemVkUGF0aDtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gcmVwbGFjZW1lbnRzQXJlRW1wdHkoZml4OiB0c2xpbnQuRml4KTogYm9vbGVhbiB7XG4gICAgICAgICAgICAvLyBpbiB0c2xpbnQgNCBhIEZpeCBoYXMgYSByZXBsYWNlbWVudCBwcm9wZXJ0eSB3aXRodCB0aGUgUmVwbGFjZW1lbnRzXG4gICAgICAgICAgICBpZiAoKDxhbnk+Zml4KS5yZXBsYWNlbWVudHMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKDxhbnk+Zml4KS5yZXBsYWNlbWVudHMubGVuZ3RoID09PSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gdHNsaW50IDVcbiAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KGZpeCkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZml4Lmxlbmd0aCA9PT0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIHJlY29yZENvZGVBY3Rpb24ocHJvYmxlbTogdHNsaW50LlJ1bGVGYWlsdXJlLCBmaWxlOiB0cy5Tb3VyY2VGaWxlKSB7XG4gICAgICAgICAgICBsZXQgZml4OiB0c2xpbnQuRml4ID0gbnVsbDtcblxuICAgICAgICAgICAgLy8gdHNsaW50IGNhbiByZXR1cm4gYSBmaXggd2l0aCBhbiBlbXB0eSByZXBsYWNlbWVudHMgYXJyYXksIHRoZXNlIGZpeGVzIGFyZSBpZ25vcmVkXG4gICAgICAgICAgICBpZiAocHJvYmxlbS5nZXRGaXggJiYgcHJvYmxlbS5nZXRGaXgoKSAmJiAhcmVwbGFjZW1lbnRzQXJlRW1wdHkocHJvYmxlbS5nZXRGaXgoKSkpIHsgLy8gdHNsaW50IGZpeGVzIGFyZSBub3QgYXZhaWxhYmxlIGluIHRzbGludCA8IDMuMTdcbiAgICAgICAgICAgICAgICBmaXggPSBwcm9ibGVtLmdldEZpeCgpOyAvLyBjcmVhdGVBdXRvRml4KHByb2JsZW0sIGRvY3VtZW50LCBwcm9ibGVtLmdldEZpeCgpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCFmaXgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBkb2N1bWVudEF1dG9GaXhlczogTWFwPHN0cmluZywgdHNsaW50LlJ1bGVGYWlsdXJlPiA9IGNvZGVGaXhBY3Rpb25zLmdldChmaWxlLmZpbGVOYW1lKTtcbiAgICAgICAgICAgIGlmICghZG9jdW1lbnRBdXRvRml4ZXMpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudEF1dG9GaXhlcyA9IG5ldyBNYXA8c3RyaW5nLCB0c2xpbnQuUnVsZUZhaWx1cmU+KCk7XG4gICAgICAgICAgICAgICAgY29kZUZpeEFjdGlvbnMuc2V0KGZpbGUuZmlsZU5hbWUsIGRvY3VtZW50QXV0b0ZpeGVzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRvY3VtZW50QXV0b0ZpeGVzLnNldChjb21wdXRlS2V5KHByb2JsZW0uZ2V0U3RhcnRQb3NpdGlvbigpLmdldFBvc2l0aW9uKCksIHByb2JsZW0uZ2V0RW5kUG9zaXRpb24oKS5nZXRQb3NpdGlvbigpKSwgcHJvYmxlbSk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBnZXRDb25maWd1cmF0aW9uRmFpbHVyZU1lc3NhZ2UoZXJyOiBhbnkpOiBzdHJpbmcge1xuICAgICAgICAgICAgbGV0IGVycm9yTWVzc2FnZSA9IGB1bmtub3duIGVycm9yYDtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgZXJyLm1lc3NhZ2UgPT09ICdzdHJpbmcnIHx8IGVyci5tZXNzYWdlIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlID0gPHN0cmluZz5lcnIubWVzc2FnZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBgdHNsaW50OiBDYW5ub3QgcmVhZCB0c2xpbnQgY29uZmlndXJhdGlvbiAtICcke2Vycm9yTWVzc2FnZX0nYDtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGdldENvbmZpZ3VyYXRpb24oZmlsZVBhdGg6IHN0cmluZywgY29uZmlnRmlsZU5hbWU6IHN0cmluZyk6IGFueSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnQ2FjaGUuY29uZmlndXJhdGlvbiAmJiBjb25maWdDYWNoZS5maWxlUGF0aCA9PT0gZmlsZVBhdGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29uZmlnQ2FjaGUuY29uZmlndXJhdGlvbjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IGlzRGVmYXVsdENvbmZpZyA9IGZhbHNlO1xuICAgICAgICAgICAgbGV0IGNvbmZpZ3VyYXRpb247XG4gICAgICAgICAgICBsZXQgY29uZmlnRmlsZVBhdGggPSBudWxsO1xuXG4gICAgICAgICAgICBpc0RlZmF1bHRDb25maWcgPSB0c2xpbnQuQ29uZmlndXJhdGlvbi5maW5kQ29uZmlndXJhdGlvblBhdGgoY29uZmlnRmlsZU5hbWUsIGZpbGVQYXRoKSA9PT0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgbGV0IGNvbmZpZ3VyYXRpb25SZXN1bHQgPSB0c2xpbnQuQ29uZmlndXJhdGlvbi5maW5kQ29uZmlndXJhdGlvbihjb25maWdGaWxlTmFtZSwgZmlsZVBhdGgpO1xuXG4gICAgICAgICAgICAvLyBiZXR3ZWVuIHRzbGludCA0LjAuMSBhbmQgdHNsaW50IDQuMC4yIHRoZSBhdHRyaWJ1dGUgJ2Vycm9yJyBoYXMgYmVlbiByZW1vdmVkIGZyb20gSUNvbmZpZ3VyYXRpb25Mb2FkUmVzdWx0XG4gICAgICAgICAgICAvLyBpbiA0LjAuMiBmaW5kQ29uZmlndXJhdGlvbiB0aHJvd3MgYW4gZXhjZXB0aW9uIGFzIGluIHZlcnNpb24gXjMuMC4wXG4gICAgICAgICAgICBpZiAoKDxhbnk+Y29uZmlndXJhdGlvblJlc3VsdCkuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyAoPGFueT5jb25maWd1cmF0aW9uUmVzdWx0KS5lcnJvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbmZpZ3VyYXRpb24gPSBjb25maWd1cmF0aW9uUmVzdWx0LnJlc3VsdHM7XG5cbiAgICAgICAgICAgIC8vIEluIHRzbGludCB2ZXJzaW9uIDUgdGhlICduby11bnVzZWQtdmFyaWFibGUnIHJ1bGVzIGJyZWFrcyB0aGUgVHlwZVNjcmlwdCBsYW5ndWFnZSBzZXJ2aWNlIHBsdWdpbi5cbiAgICAgICAgICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vTWljcm9zb2Z0L1R5cGVTY3JpcHQvaXNzdWVzLzE1MzQ0XG4gICAgICAgICAgICAvLyBUaGVyZWZvcmUgd2UgcmVtb3ZlIHRoZSBydWxlIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gSW4gdHNsaW50IDUgdGhlIHJ1bGVzIGFyZSBzdG9yZWQgaW4gYSBNYXAsIGluIGVhcmxpZXIgdmVyc2lvbnMgdGhleSB3ZXJlIHN0b3JlZCBpbiBhbiBPYmplY3RcbiAgICAgICAgICAgIGlmIChjb25maWcuZGlzYWJsZU5vVW51c2VkVmFyaWFibGVSdWxlID09PSB0cnVlIHx8IGNvbmZpZy5kaXNhYmxlTm9VbnVzZWRWYXJpYWJsZVJ1bGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGlmIChjb25maWd1cmF0aW9uLnJ1bGVzICYmIGNvbmZpZ3VyYXRpb24ucnVsZXMgaW5zdGFuY2VvZiBNYXApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbi5ydWxlcy5kZWxldGUoJ25vLXVudXNlZC12YXJpYWJsZScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY29uZmlndXJhdGlvbi5qc1J1bGVzICYmIGNvbmZpZ3VyYXRpb24uanNSdWxlcyBpbnN0YW5jZW9mIE1hcCkge1xuICAgICAgICAgICAgICAgICAgICBjb25maWd1cmF0aW9uLmpzUnVsZXMuZGVsZXRlKCduby11bnVzZWQtdmFyaWFibGUnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbmZpZ0ZpbGVQYXRoID0gY29uZmlndXJhdGlvblJlc3VsdC5wYXRoO1xuXG4gICAgICAgICAgICBjb25maWdDYWNoZSA9IHtcbiAgICAgICAgICAgICAgICBmaWxlUGF0aDogZmlsZVBhdGgsXG4gICAgICAgICAgICAgICAgaXNEZWZhdWx0Q29uZmlnOiBpc0RlZmF1bHRDb25maWcsXG4gICAgICAgICAgICAgICAgY29uZmlndXJhdGlvbjogY29uZmlndXJhdGlvbixcbiAgICAgICAgICAgICAgICBjb25maWdGaWxlUGF0aDogY29uZmlnRmlsZVBhdGhcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gY29uZmlnQ2FjaGUuY29uZmlndXJhdGlvbjtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgZnVuY3Rpb24gY2FwdHVyZVdhcm5pbmdzKG1lc3NhZ2U/OiBhbnkpOiB2b2lkIHtcbiAgICAgICAgICAgIC8vIFRPRE8gbG9nIHRvIGEgdXNlciB2aXNpYmxlIGxvZyBhbmQgbm90IG9ubHkgdGhlIFRTLVNlcnZlciBsb2dcbiAgICAgICAgICAgIGluZm8ucHJvamVjdC5wcm9qZWN0U2VydmljZS5sb2dnZXIuaW5mbyhgW3RzbGludF0gJHttZXNzYWdlfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gY29udmVydFJlcGxhY2VtZW50VG9UZXh0Q2hhbmdlKHJlcGw6IHRzbGludC5SZXBsYWNlbWVudCk6IHRzLlRleHRDaGFuZ2Uge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBuZXdUZXh0OiByZXBsLnRleHQsXG4gICAgICAgICAgICAgICAgc3BhbjogeyBzdGFydDogcmVwbC5zdGFydCwgbGVuZ3RoOiByZXBsLmxlbmd0aCB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBmdW5jdGlvbiBnZXRSZXBsYWNlbWVudHMoZml4OiB0c2xpbnQuRml4KTogdHNsaW50LlJlcGxhY2VtZW50W117XG4gICAgICAgICAgICBsZXQgcmVwbGFjZW1lbnRzOiB0c2xpbnQuUmVwbGFjZW1lbnRbXSA9IG51bGw7XG4gICAgICAgICAgICAvLyBpbiB0c2xpbnQ0IGEgRml4IGhhcyBhIHJlcGxhY2VtZW50IHByb3BlcnR5IHdpdGggdGhlIFJlcGxhY2VtZW50c1xuICAgICAgICAgICAgaWYgKCg8YW55PmZpeCkucmVwbGFjZW1lbnRzKSB7XG4gICAgICAgICAgICAgICAgLy8gdHNsaW50NFxuICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50cyA9ICg8YW55PmZpeCkucmVwbGFjZW1lbnRzO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBpbiB0c2xpbnQgNSBhIEZpeCBpcyBhIFJlcGxhY2VtZW50IHwgUmVwbGFjZW1lbnRbXSAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheShmaXgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50cyA9IFs8YW55PmZpeF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnRzID0gZml4O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXBsYWNlbWVudHM7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBhZGRSdWxlRmFpbHVyZUZpeChmaXhlczogdHNfbW9kdWxlLkNvZGVBY3Rpb25bXSwgcHJvYmxlbTogdHNsaW50LlJ1bGVGYWlsdXJlLCBmaWxlTmFtZTogc3RyaW5nKSB7XG4gICAgICAgICAgICBsZXQgZml4ID0gcHJvYmxlbS5nZXRGaXgoKTtcbiAgICAgICAgICAgIGxldCByZXBsYWNlbWVudHM6IHRzbGludC5SZXBsYWNlbWVudFtdID0gZ2V0UmVwbGFjZW1lbnRzKGZpeCk7XG5cbiAgICAgICAgICAgIGZpeGVzLnB1c2goe1xuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgRml4ICcke3Byb2JsZW0uZ2V0UnVsZU5hbWUoKX0nYCxcbiAgICAgICAgICAgICAgICBjaGFuZ2VzOiBbe1xuICAgICAgICAgICAgICAgICAgICBmaWxlTmFtZTogZmlsZU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHRleHRDaGFuZ2VzOiByZXBsYWNlbWVudHMubWFwKGVhY2ggPT4gY29udmVydFJlcGxhY2VtZW50VG9UZXh0Q2hhbmdlKGVhY2gpKVxuICAgICAgICAgICAgICAgIH1dXG4gICAgICAgICAgICB9KTsgIFxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gYWRkRGlzYWJsZVJ1bGVGaXgoZml4ZXM6IHRzX21vZHVsZS5Db2RlQWN0aW9uW10sIHByb2JsZW06IHRzbGludC5SdWxlRmFpbHVyZSwgZmlsZU5hbWU6IHN0cmluZywgZmlsZTogdHNfbW9kdWxlLlNvdXJjZUZpbGUpIHtcbiAgICAgICAgICAgIGZpeGVzLnB1c2goe1xuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgRGlzYWJsZSBydWxlICcke3Byb2JsZW0uZ2V0UnVsZU5hbWUoKX0nYCxcbiAgICAgICAgICAgICAgICBjaGFuZ2VzOiBbe1xuICAgICAgICAgICAgICAgICAgICBmaWxlTmFtZTogZmlsZU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHRleHRDaGFuZ2VzOiBbe1xuICAgICAgICAgICAgICAgICAgICAgICAgbmV3VGV4dDogYC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZToke3Byb2JsZW0uZ2V0UnVsZU5hbWUoKX1cXG5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3BhbjogeyBzdGFydDogZmlsZS5nZXRMaW5lU3RhcnRzKClbcHJvYmxlbS5nZXRTdGFydFBvc2l0aW9uKCkuZ2V0TGluZUFuZENoYXJhY3RlcigpLmxpbmVdLCBsZW5ndGg6IDAgfVxuICAgICAgICAgICAgICAgICAgICB9XVxuICAgICAgICAgICAgICAgIH1dXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGFkZE9wZW5Db25maWd1cmF0aW9uRml4KGZpeGVzOiB0c19tb2R1bGUuQ29kZUFjdGlvbltdKSB7XG4gICAgICAgICAgICAvLyB0aGUgT3BlbiBDb25maWd1cmF0aW9uIGNvZGUgYWN0aW9uIGlzIGRpc2FibGVkIHNpbmNlIHRoZXJlIGlzIG5vIHNwZWNpZmllZCBBUEkgdG8gb3BlbiBhbiBlZGl0b3JcbiAgICAgICAgICAgIGxldCBvcGVuQ29uZmlnRml4RW5hYmxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKG9wZW5Db25maWdGaXhFbmFibGVkICYmIGNvbmZpZ0NhY2hlICYmIGNvbmZpZ0NhY2hlLmNvbmZpZ0ZpbGVQYXRoKSB7XG4gICAgICAgICAgICAgICAgZml4ZXMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgT3BlbiB0c2xpbnQuanNvbmAsXG4gICAgICAgICAgICAgICAgICAgIGNoYW5nZXM6IFt7XG4gICAgICAgICAgICAgICAgICAgICAgICBmaWxlTmFtZTogY29uZmlnQ2FjaGUuY29uZmlnRmlsZVBhdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0Q2hhbmdlczogW11cbiAgICAgICAgICAgICAgICAgICAgfV1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ