UNPKG

@cdktf/hcl2cdk

Version:
364 lines 62.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.attributeNameToCdktfName = exports.isRegistryModule = exports.convertProject = exports.getTerraformConfigFromDir = exports.convert = exports.convertToTypescript = exports.parseProviderRequirements = exports.getParsedHcl = exports.CODE_MARKER = void 0; // Copyright (c) HashiCorp, Inc // SPDX-License-Identifier: MPL-2.0 const hcl2json_1 = require("@cdktf/hcl2json"); const provider_generator_1 = require("@cdktf/provider-generator"); Object.defineProperty(exports, "isRegistryModule", { enumerable: true, get: function () { return provider_generator_1.isRegistryModule; } }); const t = __importStar(require("@babel/types")); const prettier_1 = __importDefault(require("prettier")); const path = __importStar(require("path")); const glob = __importStar(require("glob")); const fs = __importStar(require("fs")); const graphology_1 = require("graphology"); const rosetta = __importStar(require("jsii-rosetta")); const schema_1 = require("./schema"); const references_1 = require("./references"); const generation_1 = require("./generation"); const iteration_1 = require("./iteration"); const provider_1 = require("./provider"); const utils_1 = require("./utils"); const generation_2 = require("./generation"); Object.defineProperty(exports, "attributeNameToCdktfName", { enumerable: true, get: function () { return generation_2.attributeNameToCdktfName; } }); const jsii_rosetta_workarounds_1 = require("./jsii-rosetta-workarounds"); const iteration_2 = require("./iteration"); exports.CODE_MARKER = "// define resources here"; async function getParsedHcl(hcl) { utils_1.logger.debug(`Parsing HCL: ${hcl}`); // Get the JSON representation of the HCL let json; try { json = await (0, hcl2json_1.parse)("terraform.tf", hcl); } catch (err) { utils_1.logger.error(`Failed to parse HCL: ${err}`); throw new Error(`Error: Could not parse HCL, this means either that the HCL passed is invalid or that you found a bug. If the HCL seems valid, please file a bug under https://cdk.tf/bugs/new/convert`); } // Ensure the JSON representation matches the expected structure let plan; try { plan = schema_1.schema.parse(json); } catch (err) { throw new Error(`Error: HCL-JSON does not conform to schema. This is not expected, please file a bug under https://cdk.tf/bugs/new/convert Please include this information: ${JSON.stringify(err.errors)}`); } return plan; } exports.getParsedHcl = getParsedHcl; async function parseProviderRequirements(hcl) { utils_1.logger.debug("Parsing provider requirements"); const plan = await getParsedHcl(hcl); return (0, provider_1.getProviderRequirements)(plan); } exports.parseProviderRequirements = parseProviderRequirements; async function convertToTypescript(hcl, providerSchema, codeContainer) { var _a; utils_1.logger.debug("Converting to typescript"); const plan = await getParsedHcl(hcl); // Each key in the scope needs to be unique, therefore we save them in a set // Each variable needs to be unique as well, we save them in a record so we can identify if two variables are the same const scope = { providerSchema, providerGenerator: Object.keys(providerSchema.provider_schemas || {}).reduce((carry, fqpn) => { const providerGenerator = new provider_generator_1.TerraformProviderGenerator(new provider_generator_1.CodeMaker(), providerSchema); providerGenerator.buildResourceModels(fqpn); // can't use that type on the keys yet, since we are not on TS >=4.4 yet :sadcat: return { ...carry, [fqpn]: providerGenerator }; }, {}), constructs: new Set(), variables: {}, hasTokenBasedTypeCoercion: false, nodeIds: [], importables: [], topLevelConfig: {}, }; const graph = new graphology_1.DirectedGraph(); // Get all items in the JSON as a map of id to function that generates the AST // We will use this to construct the nodes for a dependency graph // We need to use a function here because the same node has different representation based on if it's referenced by another one const nodeMap = { ...(0, iteration_1.forEachProvider)(scope, plan.provider, generation_1.provider), ...(0, iteration_1.forEachGlobal)(scope, "var", plan.variable, generation_1.variable), // locals are a special case ...(0, iteration_1.forEachGlobal)(scope, "local", Array.isArray(plan.locals) ? plan.locals.reduce((carry, locals) => ({ ...carry, ...locals }), {}) : {}, generation_1.local), ...(0, iteration_1.forEachGlobal)(scope, "out", plan.output, generation_1.output), ...(0, iteration_1.forEachGlobal)(scope, "module", plan.module, generation_1.modules), ...(0, iteration_2.forEachImport)(scope, "import", plan.import, generation_1.imports), ...(0, iteration_1.forEachNamespaced)(scope, plan.resource, generation_1.resource), ...(0, iteration_1.forEachNamespaced)(scope, plan.data, generation_1.resource, "data"), }; // Add all nodes to the dependency graph so we can detect if an edge is added for an unknown link Object.entries(nodeMap).forEach(([key, value]) => { utils_1.logger.debug(`Adding node '${key}' to graph`); graph.addNode(key, value); }); // Finding references becomes easier of the to be referenced ids are already known const nodeIds = Object.keys(nodeMap); scope.nodeIds = nodeIds; async function addEdges(id, value) { (await (0, references_1.findUsedReferences)(nodeIds, value)).forEach((ref) => { if (!graph.hasDirectedEdge(ref.referencee.id, id) && graph.hasNode(ref.referencee.id) // in case the referencee is a dynamic variable ) { if (!graph.hasNode(id)) { throw new Error(`The dependency graph is expected to link from ${ref.referencee.id} to ${id} but ${id} does not exist. These nodes exist: ${graph.nodes().join("\n")}`); } // The graph should have no self-references if (id === ref.referencee.id) { utils_1.logger.debug(`Skipping self-reference for ${id}`); return; } utils_1.logger.debug(`Adding edge from ${ref.referencee.id} to ${id}`); graph.addDirectedEdge(ref.referencee.id, id, { ref }); } }); } // We recursively inspect each resource value to find references to other values // We add these to a dependency graph so that the programming code has the right order async function addGlobalEdges(_scope, _key, id, value) { await addEdges(id, value); } async function addProviderEdges(_scope, _key, id, value) { await addEdges(id, value); } async function addNamespacedEdges(_scope, _type, _key, id, value) { await addEdges(id, value); } await Promise.all(Object.values({ ...(0, iteration_1.forEachProvider)(scope, plan.provider, addProviderEdges), ...(0, iteration_1.forEachGlobal)(scope, "var", plan.variable, addGlobalEdges), // locals are a special case ...(0, iteration_1.forEachGlobal)(scope, "local", Array.isArray(plan.locals) ? plan.locals.reduce((carry, locals) => ({ ...carry, ...locals }), {}) : {}, addGlobalEdges), ...(0, iteration_1.forEachGlobal)(scope, "out", plan.output, addGlobalEdges), ...(0, iteration_1.forEachGlobal)(scope, "module", plan.module, addGlobalEdges), ...(0, iteration_1.forEachNamespaced)(scope, plan.resource, addNamespacedEdges), ...(0, iteration_1.forEachNamespaced)(scope, plan.data, addNamespacedEdges, "data"), }).map(({ code: addEdgesToGraph }) => addEdgesToGraph(graph))); utils_1.logger.debug(`Graph: ${JSON.stringify(graph, null, 2)}`); utils_1.logger.debug(`Starting to assemble the typescript code`); // We traverse the dependency graph to get the unordered JSON nodes into an ordered array // where no node is referenced before it's defined // As we check that the nodes on both ends of an edge exist we can be sure // that no infinite loop exists, there can be no stray dependency on a node const expressions = []; let nodesToVisit = [...nodeIds]; // This ensures we detect cycles and don't end up in an endless loop let nodesVisitedThisIteration = 0; do { nodesVisitedThisIteration = 0; // Find next nodes to visit const nodeExpressionGenerators = graph.mapNodes((nodeId, { code }) => { if (!nodesToVisit.includes(nodeId)) { return undefined; } const unresolvedDependencies = graph .inNeighbors(nodeId) .filter((item) => nodesToVisit.includes(item)); if (unresolvedDependencies.length === 0) { nodesToVisit = nodesToVisit.filter((id) => nodeId !== id); nodesVisitedThisIteration = nodesVisitedThisIteration + 1; utils_1.logger.debug(`Visiting node ${nodeId}`); return code; } return undefined; }); // Generate the code for the nodes for (const code of nodeExpressionGenerators) { if (code) { expressions.push(...(await code(graph))); } } utils_1.logger.debug(`${nodesToVisit.length} unvisited nodes: ${nodesToVisit.join(", ")}`); } while (nodesToVisit.length > 0 && nodesVisitedThisIteration != 0); if (nodesToVisit.length > 0) { throw new Error(`There are ${nodesToVisit.length} terraform elements that could not be visited. This is likely due to a cycle in the dependency graph. These nodes are: ${nodesToVisit.join(", ")}`); } utils_1.logger.debug(`${nodesToVisit.length} unvisited nodes: ${nodesToVisit.join(", ")}`); const backendExpressions = (await Promise.all(((_a = plan.terraform) === null || _a === void 0 ? void 0 : _a.map((terraform) => (0, generation_1.backendToExpression)(scope, terraform.backend))) || [Promise.resolve([])])).reduce((carry, item) => [...carry, ...item], []); utils_1.logger.debug(`Using these backend expressions: ${JSON.stringify(backendExpressions, null, 2)}`); // We collect all module sources const moduleRequirements = [ ...new Set(Object.values(plan.module || {}).reduce((carry, moduleBlock) => [ ...carry, ...moduleBlock.reduce((arr, { source, version }) => [ ...arr, version ? `${source}@${version}` : source, ], []), ], []) || []), ]; utils_1.logger.debug(`Found these modules: ${JSON.stringify(moduleRequirements, null, 2)}`); if (Object.keys(plan.variable || {}).length > 0 && expressions.length > 0) { expressions[0] = t.addComment(expressions[0], "leading", `Terraform Variables are not always the best fit for getting inputs in the context of Terraform CDK. You can read more about this at https://cdk.tf/variables`); } const providerRequirements = (0, provider_1.getProviderRequirements)(plan); utils_1.logger.debug(`Found these provider requirements: ${JSON.stringify(providerRequirements, null, 2)}`); // We add a comment if there are providers with missing schema information const providersLackingSchema = Object.keys(providerRequirements).filter((providerName) => providerName !== "terraform" && !Object.keys(providerSchema.provider_schemas || {}).some((schemaName) => schemaName.endsWith(providerName))); utils_1.logger.debug(`${providersLackingSchema.length} providers lack schema information: ${providersLackingSchema.join(", ")}`); if (providersLackingSchema.length > 0) { expressions[0] = t.addComment(expressions[0], "leading", `The following providers are missing schema information and might need manual adjustments to synthesize correctly: ${providersLackingSchema.join(", ")}. For a more precise conversion please use the --provider flag in convert.`); } // Always add constructs scope.importables.push({ constructName: "Construct", provider: "constructs", }); if (scope.hasTokenBasedTypeCoercion) { scope.importables.push({ constructName: "Token", provider: "cdktf", }); } // Add specific import for codeContainer (0, generation_1.addImportForCodeContainer)(scope, codeContainer); const constructImports = (0, generation_1.buildImports)(scope.importables); const code = [...(backendExpressions || []), ...expressions]; const configTypeName = Object.keys(scope.topLevelConfig).length > 0 ? "MyConfig" : undefined; const classConfig = configTypeName ? [(0, generation_1.generateConfigType)(configTypeName, scope.topLevelConfig)] : []; // We split up the generated code so that users can have more control over what to insert where return { // TODO: Remove imports and code because rosetta won't be able to translate them all: await (0, generation_1.gen)([ ...constructImports, ...(0, generation_1.moduleImports)(plan.module), ...classConfig, (0, generation_1.wrapCodeInConstructor)(codeContainer, code, "MyConvertedCode", configTypeName), ]), imports: await (0, generation_1.gen)([...constructImports, ...(0, generation_1.moduleImports)(plan.module)]), code: await (0, generation_1.gen)(code), providers: Object.entries(providerRequirements).map(([source, version]) => version === "*" ? source : `${source}@${version}`), modules: moduleRequirements, // We track some usage data to make it easier to understand what is used stats: { numberOfModules: moduleRequirements.length, numberOfProviders: Object.keys(providerRequirements).length, resources: (0, iteration_1.resourceStats)(plan.resource || {}), data: (0, iteration_1.resourceStats)(plan.data || {}), convertedLines: hcl.split("\n").length, }, }; } exports.convertToTypescript = convertToTypescript; const translators = { python: { visitor: () => new rosetta.PythonVisitor(), postTranslationMutation: jsii_rosetta_workarounds_1.replacePythonImports, }, java: { visitor: () => new rosetta.JavaVisitor(), postTranslationMutation: jsii_rosetta_workarounds_1.replaceJavaImports, }, csharp: { visitor: () => new rosetta.CSharpVisitor(), postTranslationMutation: jsii_rosetta_workarounds_1.replaceCsharpImports, }, go: { visitor: () => new rosetta.GoVisitor(), postTranslationMutation: jsii_rosetta_workarounds_1.replaceGoImports, }, }; function translatorForLanguage(language) { return (file, throwOnTranslationError) => { const { visitor, postTranslationMutation } = translators[language]; const { translation, diagnostics } = rosetta.translateTypeScript(file, visitor(), throwOnTranslationError ? { includeCompilerDiagnostics: true } : {}); if (throwOnTranslationError && diagnostics.filter((diag) => diag.isError).length > 0) { utils_1.logger.debug(`Could not translate TS to ${language}:\n${file.contents}`); throw new Error(`Could not translate TS to ${language}: ${diagnostics .map((diag) => diag.formattedMessage) .join("\n")}`); } return postTranslationMutation(translation); }; } async function convert(hcl, { language, providerSchema, throwOnTranslationError = false, codeContainer = "cdktf.TerraformStack", }) { const fileName = "terraform.tf"; const translater = language === "typescript" ? (file, _throwOnTranslationError) => file.contents : translatorForLanguage(language); if (!translater) { throw new Error("Unsupported language used: " + language); } const tsCode = await convertToTypescript(hcl, providerSchema, codeContainer); return { ...tsCode, all: translater({ fileName, contents: tsCode.all }, throwOnTranslationError), imports: translater({ fileName, contents: tsCode.imports }, false), code: translater({ fileName, contents: tsCode.code }, false), stats: { ...tsCode.stats, language }, }; } exports.convert = convert; function getTerraformConfigFromDir(importPath) { const absPath = path.resolve(importPath); const fileContents = glob .sync("./*.tf", { cwd: absPath }) .map((p) => fs.readFileSync(path.resolve(absPath, p), "utf8")); return fileContents.join("\n"); } exports.getTerraformConfigFromDir = getTerraformConfigFromDir; async function convertProject(combinedHcl, { language, providerSchema }) { if (language !== "typescript") { throw new Error("Unsupported language used: " + language); } const { imports, code, providers, modules: tfModules, stats, } = await convert(combinedHcl, { language, providerSchema, }); return { code: (inputMainFile) => { const importMainFile = [imports, inputMainFile].join("\n"); const outputMainFile = importMainFile.replace(exports.CODE_MARKER, code); return prettier_1.default.format(outputMainFile, { parser: "babel" }); }, cdktfJson: (inputCdktfJson) => { const cdktfJson = { ...inputCdktfJson }; cdktfJson.terraformProviders = providers; cdktfJson.terraformModules = tfModules; return cdktfJson; }, stats, }; } exports.convertProject = convertProject; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLCtCQUErQjtBQUMvQixtQ0FBbUM7QUFDbkMsOENBQXdDO0FBQ3hDLGtFQUltQztBQWdrQjFCLGlHQW5rQlAscUNBQWdCLE9BbWtCTztBQTlqQnpCLGdEQUFrQztBQUNsQyx3REFBZ0M7QUFDaEMsMkNBQTZCO0FBQzdCLDJDQUE2QjtBQUM3Qix1Q0FBeUI7QUFDekIsMkNBQTJDO0FBQzNDLHNEQUF3QztBQUd4QyxxQ0FBa0M7QUFDbEMsNkNBQWtEO0FBQ2xELDZDQWVzQjtBQUV0QiwyQ0FLcUI7QUFDckIseUNBQXFEO0FBQ3JELG1DQUFpQztBQUVqQyw2Q0FBd0Q7QUF5aEI3Qix5R0F6aEJsQixxQ0FBd0IsT0F5aEJrQjtBQXhoQm5ELHlFQUtvQztBQUVwQywyQ0FBNEM7QUFFL0IsUUFBQSxXQUFXLEdBQUcsMEJBQTBCLENBQUM7QUFFL0MsS0FBSyxVQUFVLFlBQVksQ0FBQyxHQUFXO0lBQzVDLGNBQU0sQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDcEMseUNBQXlDO0lBQ3pDLElBQUksSUFBNkIsQ0FBQztJQUNsQyxJQUFJLENBQUM7UUFDSCxJQUFJLEdBQUcsTUFBTSxJQUFBLGdCQUFLLEVBQUMsY0FBYyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IsY0FBTSxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUM1QyxNQUFNLElBQUksS0FBSyxDQUNiLHVMQUF1TCxDQUN4TCxDQUFDO0lBQ0osQ0FBQztJQUVELGdFQUFnRTtJQUNoRSxJQUFJLElBQTRCLENBQUM7SUFDakMsSUFBSSxDQUFDO1FBQ0gsSUFBSSxHQUFHLGVBQU0sQ0FBQyxLQUFLLENB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QUN2QyxNQUFNLFNBQVMsR0FBRyxFQUFFLEdBQUcsY0FBYyxFQUFFLENBQUM7WUFDeEMsU0FBUyxDQUFDLGtCQUFrQixHQUFHLFNBQVMsQ0FBQztZQUN6QyxTQUFTLENBQUMsZ0JBQWdCLEdBQUcsU0FBUyxDQUFDO1lBQ3ZDLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFDRCxLQUFLO0tBQ04sQ0FBQztBQUNKLENBQUM7QUFqQ0Qsd0NBaUNDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IChjKSBIYXNoaUNvcnAsIEluY1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1QTC0yLjBcbmltcG9ydCB7IHBhcnNlIH0gZnJvbSBcIkBjZGt0Zi9oY2wyanNvblwiO1xuaW1wb3J0IHtcbiAgaXNSZWdpc3RyeU1vZHVsZSxcbiAgVGVycmFmb3JtUHJvdmlkZXJHZW5lcmF0b3IsXG4gIENvZGVNYWtlcixcbn0gZnJvbSBcIkBjZGt0Zi9wcm92aWRlci1nZW5lcmF0b3JcIjtcblxuaW1wb3J0ICogYXMgdCBmcm9tIFwiQGJhYmVsL3R5cGVzXCI7XG5pbXBvcnQgcHJldHRpZXIgZnJvbSBcInByZXR0aWVyXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgKiBhcyBnbG9iIGZyb20gXCJnbG9iXCI7XG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IERpcmVjdGVkR3JhcGggfSBmcm9tIFwiZ3JhcGhvbG9neVwiO1xuaW1wb3J0ICogYXMgcm9zZXR0YSBmcm9tIFwianNpaS1yb3NldHRhXCI7XG5pbXBvcnQgKiBhcyB6IGZyb20gXCJ6b2RcIjtcblxuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSBcIi4vc2NoZW1hXCI7XG5pbXBvcnQgeyBmaW5kVXNlZFJlZmVyZW5jZXMgfSBmcm9tIFwiLi9yZWZlcmVuY2VzXCI7XG5pbXBvcnQge1xuICBiYWNrZW5kVG9FeHByZXNzaW9uLFxuICBnZW4sXG4gIGxvY2FsLFxuICBtb2R1bGVJbXBvcnRzLFxuICBtb2R1bGVzLFxuICBvdXRwdXQsXG4gIHByb3ZpZGVyLFxuICByZXNvdXJjZSxcbiAgdmFyaWFibGUsXG4gIHdyYXBDb2RlSW5Db25zdHJ1Y3RvcixcbiAgYWRkSW1wb3J0Rm9yQ29kZUNvbnRhaW5lcixcbiAgYnVpbGRJbXBvcnRzLFxuICBnZW5lcmF0ZUNvbmZpZ1R5cGUsXG4gIGltcG9ydHMsXG59IGZyb20gXCIuL2dlbmVyYXRpb25cIjtcbmltcG9ydCB7IFRlcnJhZm9ybVJlc291cmNlQmxvY2ssIFByb2dyYW1TY29wZSB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQge1xuICBmb3JFYWNoUHJvdmlkZXIsXG4gIGZvckVhY2hHbG9iYWwsXG4gIGZvckVhY2hOYW1lc3BhY2VkLFxuICByZXNvdXJjZVN0YXRzLFxufSBmcm9tIFwiLi9pdGVyYXRpb25cIjtcbmltcG9ydCB7IGdldFByb3ZpZGVyUmVxdWlyZW1lbnRzIH0gZnJvbSBcIi4vcHJvdmlkZXJcIjtcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCIuL3V0aWxzXCI7XG5pbXBvcnQgeyBGUVBOIH0gZnJvbSBcIkBjZGt0Zi9wcm92aWRlci1zY2hlbWFcIjtcbmltcG9ydCB7IGF0dHJpYnV0ZU5hbWVUb0Nka3RmTmFtZSB9IGZyb20gXCIuL2dlbmVyYXRpb25cIjtcbmltcG9ydCB7XG4gIHJlcGxhY2VDc2hhcnBJbXBvcnRzLFxuICByZXBsYWNlR29JbXBvcnRzLFxuICByZXBsYWNlSmF2YUltcG9ydHMsXG4gIHJlcGxhY2VQeXRob25JbXBvcnRzLFxufSBmcm9tIFwiLi9qc2lpLXJvc2V0dGEtd29ya2Fyb3VuZHNcIjtcbmltcG9ydCB7IFByb3ZpZGVyU2NoZW1hIH0gZnJvbSBcIkBjZGt0Zi9jb21tb25zXCI7XG5pbXBvcnQgeyBmb3JFYWNoSW1wb3J0IH0gZnJvbSBcIi4vaXRlcmF0aW9uXCI7XG5cbmV4cG9ydCBjb25zdCBDT0RFX01BUktFUiA9IFwiLy8gZGVmaW5lIHJlc291cmNlcyBoZXJlXCI7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRQYXJzZWRIY2woaGNsOiBzdHJpbmcpIHtcbiAgbG9nZ2VyLmRlYnVnKGBQYXJzaW5nIEhDTDogJHtoY2x9YCk7XG4gIC8vIEdldCB0aGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgSENMXG4gIGxldCBqc29uOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgdHJ5IHtcbiAgICBqc29uID0gYXdhaXQgcGFyc2UoXCJ0ZXJyYWZvcm0udGZcIiwgaGNsKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gcGFyc2UgSENMOiAke2Vycn1gKTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgRXJyb3I6IENvdWxkIG5vdCBwYXJzZSBIQ0wsIHRoaXMgbWVhbnMgZWl0aGVyIHRoYXQgdGhlIEhDTCBwYXNzZWQgaXMgaW52YWxpZCBvciB0aGF0IHlvdSBmb3VuZCBhIGJ1Zy4gSWYgdGhlIEhDTCBzZWVtcyB2YWxpZCwgcGxlYXNlIGZpbGUgYSBidWcgdW5kZXIgaHR0cHM6Ly9jZGsudGYvYnVncy9uZXcvY29udmVydGAsXG4gICAgKTtcbiAgfVxuXG4gIC8vIEVuc3VyZSB0aGUgSlNPTiByZXByZXNlbnRhdGlvbiBtYXRjaGVzIHRoZSBleHBlY3RlZCBzdHJ1Y3R1cmVcbiAgbGV0IHBsYW46IHouaW5mZXI8dHlwZW9mIHNjaGVtYT47XG4gIHRyeSB7XG4gICAgcGxhbiA9IHNjaGVtYS5wYXJzZShqc29uKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvcjogSENMLUpTT04gZG9lcyBub3QgY29uZm9ybSB0byBzY2hlbWEuIFRoaXMgaXMgbm90IGV4cGVjdGVkLCBwbGVhc2UgZmlsZSBhIGJ1ZyB1bmRlciBodHRwczovL2Nkay50Zi9idWdzL25ldy9jb252ZXJ0XG5QbGVhc2UgaW5jbHVkZSB0aGlzIGluZm9ybWF0aW9uOlxuJHtKU09OLnN0cmluZ2lmeSgoZXJyIGFzIHouWm9kRXJyb3IpLmVycm9ycyl9YCk7XG4gIH1cblxuICByZXR1cm4gcGxhbjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBhcnNlUHJvdmlkZXJSZXF1aXJlbWVudHMoaGNsOiBzdHJpbmcpIHtcbiAgbG9nZ2VyLmRlYnVnKFwiUGFyc2luZyBwcm92aWRlciByZXF1aXJlbWVudHNcIik7XG4gIGNvbnN0IHBsYW4gPSBhd2FpdCBnZXRQYXJzZWRIY2woaGNsKTtcbiAgcmV0dXJuIGdldFByb3ZpZGVyUmVxdWlyZW1lbnRzKHBsYW4pO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29udmVydFRvVHlwZXNjcmlwdChcbiAgaGNsOiBzdHJpbmcsXG4gIHByb3ZpZGVyU2NoZW1hOiBQcm92aWRlclNjaGVtYSxcbiAgY29kZUNvbnRhaW5lcjogc3RyaW5nLFxuKSB7XG4gIGxvZ2dlci5kZWJ1ZyhcIkNvbnZlcnRpbmcgdG8gdHlwZXNjcmlwdFwiKTtcbiAgY29uc3QgcGxhbiA9IGF3YWl0IGdldFBhcnNlZEhjbChoY2wpO1xuXG4gIC8vIEVhY2gga2V5IGluIHRoZSBzY29wZSBuZWVkcyB0byBiZSB1bmlxdWUsIHRoZXJlZm9yZSB3ZSBzYXZlIHRoZW0gaW4gYSBzZXRcbiAgLy8gRWFjaCB2YXJpYWJsZSBuZWVkcyB0byBiZSB1bmlxdWUgYXMgd2VsbCwgd2Ugc2F2ZSB0aGVtIGluIGEgcmVjb3JkIHNvIHdlIGNhbiBpZGVudGlmeSBpZiB0d28gdmFyaWFibGVzIGFyZSB0aGUgc2FtZVxuICBjb25zdCBzY29wZTogUHJvZ3JhbVNjb3BlID0ge1xuICAgIHByb3ZpZGVyU2NoZW1hLFxuICAgIHByb3ZpZGVyR2VuZXJhdG9yOiBPYmplY3Qua2V5cyhcbiAgICAgIHByb3ZpZGVyU2NoZW1hLnByb3ZpZGVyX3NjaGVtYXMgfHwge30sXG4gICAgKS5yZWR1Y2UoKGNhcnJ5LCBmcXBuKSA9PiB7XG4gICAgICBjb25zdCBwcm92aWRlckdlbmVyYXRvciA9IG5ldyBUZXJyYWZvcm1Qcm92aWRlckdlbmVyYXRvcihcbiAgICAgICAgbmV3IENvZGVNYWtlcigpLFxuICAgICAgICBwcm92aWRlclNjaGVtYSxcbiAgICAgICk7XG4gICAgICBwcm92aWRlckdlbmVyYXRvci5idWlsZFJlc291cmNlTW9kZWxzKGZxcG4gYXMgRlFQTik7IC8vIGNhbid0IHVzZSB0aGF0IHR5cGUgb24gdGhlIGtleXMgeWV0LCBzaW5jZSB3ZSBhcmUgbm90IG9uIFRTID49NC40IHlldCA6c2FkY2F0OlxuICAgICAgcmV0dXJuIHsgLi4uY2FycnksIFtmcXBuXTogcHJvdmlkZXJHZW5lcmF0b3IgfTtcbiAgICB9LCB7fSksXG4gICAgY29uc3RydWN0czogbmV3IFNldDxzdHJpbmc+KCksXG4gICAgdmFyaWFibGVzOiB7fSxcbiAgICBoYXNUb2tlbkJhc2VkVHlwZUNvZXJjaW9uOiBmYWxzZSxcbiAgICBub2RlSWRzOiBbXSxcbiAgICBpbXBvcnRhYmxlczogW10sXG4gICAgdG9wTGV2ZWxDb25maWc6IHt9LFxuICB9O1xuXG4gIGNvbnN0IGdyYXBoID0gbmV3IERpcmVjdGVkR3JhcGg8e1xuICAgIGNvZGU6IChcbiAgICAgIGc6IERpcmVjdGVkR3JhcGg8YW55PixcbiAgICApID0+IFByb21pc2U8QXJyYXk8dC5TdGF0ZW1lbnQgfCB0LlZhcmlhYmxlRGVjbGFyYXRpb24+PjtcbiAgfT4oKTtcblxuICAvLyBHZXQgYWxsIGl0ZW1zIGluIHRoZSBKU09OIGFzIGEgbWFwIG9mIGlkIHRvIGZ1bmN0aW9uIHRoYXQgZ2VuZXJhdGVzIHRoZSBBU1RcbiAgLy8gV2Ugd2lsbCB1c2UgdGhpcyB0byBjb25zdHJ1Y3QgdGhlIG5vZGVzIGZvciBhIGRlcGVuZGVuY3kgZ3JhcGhcbiAgLy8gV2UgbmVlZCB0byB1c2UgYSBmdW5jdGlvbiBoZXJlIGJlY2F1c2UgdGhlIHNhbWUgbm9kZSBoYXMgZGlmZmVyZW50IHJlcHJlc2VudGF0aW9uIGJhc2VkIG9uIGlmIGl0J3MgcmVmZXJlbmNlZCBieSBhbm90aGVyIG9uZVxuICBjb25zdCBub2RlTWFwOiBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIHtcbiAgICAgIGNvZGU6IChcbiAgICAgICAgZzogdHlwZW9mIGdyYXBoLFxuICAgICAgKSA9PiBQcm9taXNlPEFycmF5PHQuU3RhdGVtZW50IHwgdC5WYXJpYWJsZURlY2xhcmF0aW9uPj47XG4gICAgICB2YWx1ZTogdW5rbm93bjtcbiAgICB9XG4gID4gPSB7XG4gICAgLi4uZm9yRWFjaFByb3ZpZGVyKHNjb3BlLCBwbGFuLnByb3ZpZGVyLCBwcm92aWRlciksXG4gICAgLi4uZm9yRWFjaEdsb2JhbChzY29wZSwgXCJ2YXJcIiwgcGxhbi52YXJpYWJsZSwgdmFyaWFibGUpLFxuICAgIC8vIGxvY2FscyBhcmUgYSBzcGVjaWFsIGNhc2VcbiAgICAuLi5mb3JFYWNoR2xvYmFsKFxuICAgICAgc2NvcGUsXG4gICAgICBcImxvY2FsXCIsXG4gICAgICBBcnJheS5pc0FycmF5KHBsYW4ubG9jYWxzKVxuICAgICAgICA/IHBsYW4ubG9jYWxzLnJlZHVjZSgoY2FycnksIGxvY2FscykgPT4gKHsgLi4uY2FycnksIC4uLmxvY2FscyB9KSwge30pXG4gICAgICAgIDoge30sXG4gICAgICBsb2NhbCxcbiAgICApLFxuICAgIC4uLmZvckVhY2hHbG9iYWwoc2NvcGUsIFwib3V0XCIsIHBsYW4ub3V0cHV0LCBvdXRwdXQpLFxuICAgIC4uLmZvckVhY2hHbG9iYWwoc2NvcGUsIFwibW9kdWxlXCIsIHBsYW4ubW9kdWxlLCBtb2R1bGVzKSxcbiAgICAuLi5mb3JFYWNoSW1wb3J0KHNjb3BlLCBcImltcG9ydFwiLCBwbGFuLmltcG9ydCwgaW1wb3J0cyksXG4gICAgLi4uZm9yRWFjaE5hbWVzcGFjZWQoc2NvcGUsIHBsYW4ucmVzb3VyY2UsIHJlc291cmNlKSxcbiAgICAuLi5mb3JFYWNoTmFtZXNwYWNlZChzY29wZSwgcGxhbi5kYXRhLCByZXNvdXJjZSwgXCJkYXRhXCIpLFxuICB9O1xuXG4gIC8vIEFkZCBhbGwgbm9kZXMgdG8gdGhlIGRlcGVuZGVuY3kgZ3JhcGggc28gd2UgY2FuIGRldGVjdCBpZiBhbiBlZGdlIGlzIGFkZGVkIGZvciBhbiB1bmtub3duIGxpbmtcbiAgT2JqZWN0LmVudHJpZXMobm9kZU1hcCkuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgbG9nZ2VyLmRlYnVnKGBBZGRpbmcgbm9kZSAnJHtrZXl9JyB0byBncmFwaGApO1xuICAgIGdyYXBoLmFkZE5vZGUoa2V5LCB2YWx1ZSk7XG4gIH0pO1xuXG4gIC8vIEZpbmRpbmcgcmVmZXJlbmNlcyBiZWNvbWVzIGVhc2llciBvZiB0aGUgdG8gYmUgcmVmZXJlbmNlZCBpZHMgYXJlIGFscmVhZHkga25vd25cbiAgY29uc3Qgbm9kZUlkcyA9IE9iamVjdC5rZXlzKG5vZGVNYXApO1xuICBzY29wZS5ub2RlSWRzID0gbm9kZUlkcztcbiAgYXN5bmMgZnVuY3Rpb24gYWRkRWRnZXMoaWQ6IHN0cmluZywgdmFsdWU6IFRlcnJhZm9ybVJlc291cmNlQmxvY2spIHtcbiAgICAoYXdhaXQgZmluZFVzZWRSZWZlcmVuY2VzKG5vZGVJZHMsIHZhbHVlKSkuZm9yRWFjaCgocmVmKSA9PiB7XG4gICAgICBpZiAoXG4gICAgICAgICFncmFwaC5oYXNEaXJlY3RlZEVkZ2UocmVmLnJlZmVyZW5jZWUuaWQsIGlkKSAmJlxuICAgICAgICBncmFwaC5oYXNOb2RlKHJlZi5yZWZlcmVuY2VlLmlkKSAvLyBpbiBjYXNlIHRoZSByZWZlcmVuY2VlIGlzIGEgZHluYW1pYyB2YXJpYWJsZVxuICAgICAgKSB7XG4gICAgICAgIGlmICghZ3JhcGguaGFzTm9kZShpZCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgVGhlIGRlcGVuZGVuY3kgZ3JhcGggaXMgZXhwZWN0ZWQgdG8gbGluayBmcm9tICR7XG4gICAgICAgICAgICAgIHJlZi5yZWZlcmVuY2VlLmlkXG4gICAgICAgICAgICB9IHRvICR7aWR9IGJ1dCAke2lkfSBkb2VzIG5vdCBleGlzdC5cbiAgICAgICAgICAgIFRoZXNlIG5vZGVzIGV4aXN0OiAke2dyYXBoLm5vZGVzKCkuam9pbihcIlxcblwiKX1gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgZ3JhcGggc2hvdWxkIGhhdmUgbm8gc2VsZi1yZWZlcmVuY2VzXG4gICAgICAgIGlmIChpZCA9PT0gcmVmLnJlZmVyZW5jZWUuaWQpIHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYFNraXBwaW5nIHNlbGYtcmVmZXJlbmNlIGZvciAke2lkfWApO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgQWRkaW5nIGVkZ2UgZnJvbSAke3JlZi5yZWZlcmVuY2VlLmlkfSB0byAke2lkfWApO1xuICAgICAgICBncmFwaC5hZGREaXJlY3RlZEVkZ2UocmVmLnJlZmVyZW5jZWUuaWQsIGlkLCB7IHJlZiB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8vIFdlIHJlY3Vyc2l2ZWx5IGluc3BlY3QgZWFjaCByZXNvdXJjZSB2YWx1ZSB0byBmaW5kIHJlZmVyZW5jZXMgdG8gb3RoZXIgdmFsdWVzXG4gIC8vIFdlIGFkZCB0aGVzZSB0byBhIGRlcGVuZGVuY3kgZ3JhcGggc28gdGhhdCB0aGUgcHJvZ3JhbW1pbmcgY29kZSBoYXMgdGhlIHJpZ2h0IG9yZGVyXG4gIGFzeW5jIGZ1bmN0aW9uIGFkZEdsb2JhbEVkZ2VzKFxuICAgIF9zY29wZTogUHJvZ3JhbVNjb3BlLFxuICAgIF9rZXk6IHN0cmluZyxcbiAgICBpZDogc3RyaW5nLFxuICAgIHZhbHVlOiBUZXJyYWZvcm1SZXNvdXJjZUJsb2NrLFxuICApIHtcbiAgICBhd2FpdCBhZGRFZGdlcyhpZCwgdmFsdWUpO1xuICB9XG4gIGFzeW5jIGZ1bmN0aW9uIGFkZFByb3ZpZGVyRWRnZXMoXG4gICAgX3Njb3BlOiBQcm9ncmFtU2NvcGUsXG4gICAgX2tleTogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcsXG4gICAgdmFsdWU6IFRlcnJhZm9ybVJlc291cmNlQmxvY2ssXG4gICkge1xuICAgIGF3YWl0IGFkZEVkZ2VzKGlkLCB2YWx1ZSk7XG4gIH1cbiAgYXN5bmMgZnVuY3Rpb24gYWRkTmFtZXNwYWNlZEVkZ2VzKFxuICAgIF9zY29wZTogUHJvZ3JhbVNjb3BlLFxuICAgIF90eXBlOiBzdHJpbmcsXG4gICAgX2tleTogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcsXG4gICAgdmFsdWU6IFRlcnJhZm9ybVJlc291cmNlQmxvY2ssXG4gICkge1xuICAgIGF3YWl0IGFkZEVkZ2VzKGlkLCB2YWx1ZSk7XG4gIH1cblxuICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICBPYmplY3QudmFsdWVzKHtcbiAgICAgIC4uLmZvckVhY2hQcm92aWRlcihzY29wZSwgcGxhbi5wcm92aWRlciwgYWRkUHJvdmlkZXJFZGdlcyksXG4gICAgICAuLi5mb3JFYWNoR2xvYmFsKHNjb3BlLCBcInZhclwiLCBwbGFuLnZhcmlhYmxlLCBhZGRHbG9iYWxFZGdlcyksXG4gICAgICAvLyBsb2NhbHMgYXJlIGEgc3BlY2lhbCBjYXNlXG4gICAgICAuLi5mb3JFYWNoR2xvYmFsKFxuICAgICAgICBzY29wZSxcbiAgICAgICAgXCJsb2NhbFwiLFxuICAgICAgICBBcnJheS5pc0FycmF5KHBsYW4ubG9jYWxzKVxuICAgICAgICAgID8gcGxhbi5sb2NhbHMucmVkdWNlKChjYXJyeSwgbG9jYWxzKSA9PiAoeyAuLi5jYXJyeSwgLi4ubG9jYWxzIH0pLCB7fSlcbiAgICAgICAgICA6IHt9LFxuICAgICAgICBhZGRHbG9iYWxFZGdlcyxcbiAgICAgICksXG4gICAgICAuLi5mb3JFYWNoR2xvYmFsKHNjb3BlLCBcIm91dFwiLCBwbGFuLm91dHB1dCwgYWRkR2xvYmFsRWRnZXMpLFxuICAgICAgLi4uZm9yRWFjaEdsb2JhbChzY29wZSwgXCJtb2R1bGVcIiwgcGxhbi5tb2R1bGUsIGFkZEdsb2JhbEVkZ2VzKSxcbiAgICAgIC4uLmZvckVhY2hOYW1lc3BhY2VkKHNjb3BlLCBwbGFuLnJlc291cmNlLCBhZGROYW1lc3BhY2VkRWRnZXMpLFxuICAgICAgLi4uZm9yRWFjaE5hbWVzcGFjZWQoc2NvcGUsIHBsYW4uZGF0YSwgYWRkTmFtZXNwYWNlZEVkZ2VzLCBcImRhdGFcIiksXG4gICAgfSkubWFwKCh7IGNvZGU6IGFkZEVkZ2VzVG9HcmFwaCB9KSA9PiBhZGRFZGdlc1RvR3JhcGgoZ3JhcGgpKSxcbiAgKTtcblxuICBsb2dnZXIuZGVidWcoYEdyYXBoOiAke0pTT04uc3RyaW5naWZ5KGdyYXBoLCBudWxsLCAyKX1gKTtcbiAgbG9nZ2VyLmRlYnVnKGBTdGFydGluZyB0byBhc3NlbWJsZSB0aGUgdHlwZXNjcmlwdCBjb2RlYCk7XG4gIC8vIFdlIHRyYXZlcnNlIHRoZSBkZXBlbmRlbmN5IGdyYXBoIHRvIGdldCB0aGUgdW5vcmRlcmVkIEpTT04gbm9kZXMgaW50byBhbiBvcmRlcmVkIGFycmF5XG4gIC8vIHdoZXJlIG5vIG5vZGUgaXMgcmVmZXJlbmNlZCBiZWZvcmUgaXQncyBkZWZpbmVkXG4gIC8vIEFzIHdlIGNoZWNrIHRoYXQgdGhlIG5vZGVzIG9uIGJvdGggZW5kcyBvZiBhbiBlZGdlIGV4aXN0IHdlIGNhbiBiZSBzdXJlXG4gIC8vIHRoYXQgbm8gaW5maW5pdGUgbG9vcCBleGlzdHMsIHRoZXJlIGNhbiBiZSBubyBzdHJheSBkZXBlbmRlbmN5IG9uIGEgbm9kZVxuICBjb25zdCBleHByZXNzaW9uczogdC5TdGF0ZW1lbnRbXSA9IFtdO1xuICBsZXQgbm9kZXNUb1Zpc2l0ID0gWy4uLm5vZGVJZHNdO1xuICAvLyBUaGlzIGVuc3VyZXMgd2UgZGV0ZWN0IGN5Y2xlcyBhbmQgZG9uJ3QgZW5kIHVwIGluIGFuIGVuZGxlc3MgbG9vcFxuICBsZXQgbm9kZXNWaXNpdGVkVGhpc0l0ZXJhdGlvbiA9IDA7XG4gIGRvIHtcbiAgICBub2Rlc1Zpc2l0ZWRUaGlzSXRlcmF0aW9uID0gMDtcblxuICAgIC8vIEZpbmQgbmV4dCBub2RlcyB0byB2aXNpdFxuICAgIGNvbnN0IG5vZGVFeHByZXNzaW9uR2VuZXJhdG9ycyA9IGdyYXBoLm1hcE5vZGVzKChub2RlSWQsIHsgY29kZSB9KSA9PiB7XG4gICAgICBpZiAoIW5vZGVzVG9WaXNpdC5pbmNsdWRlcyhub2RlSWQpKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHVucmVzb2x2ZWREZXBlbmRlbmNpZXMgPSBncmFwaFxuICAgICAgICAuaW5OZWlnaGJvcnMobm9kZUlkKVxuICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBub2Rlc1RvVmlzaXQuaW5jbHVkZXMoaXRlbSkpO1xuXG4gICAgICBpZiAodW5yZXNvbHZlZERlcGVuZGVuY2llcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgbm9kZXNUb1Zpc2l0ID0gbm9kZXNUb1Zpc2l0LmZpbHRlcigoaWQpID0+IG5vZGVJZCAhPT0gaWQpO1xuICAgICAgICBub2Rlc1Zpc2l0ZWRUaGlzSXRlcmF0aW9uID0gbm9kZXNWaXNpdGVkVGhpc0l0ZXJhdGlvbiArIDE7XG5cbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBWaXNpdGluZyBub2RlICR7bm9kZUlkfWApO1xuICAgICAgICByZXR1cm4gY29kZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSk7XG5cbiAgICAvLyBHZW5lcmF0ZSB0aGUgY29kZSBmb3IgdGhlIG5vZGVzXG4gICAgZm9yIChjb25zdCBjb2RlIG9mIG5vZGVFeHByZXNzaW9uR2VuZXJhdG9ycykge1xuICAgICAgaWYgKGNvZGUpIHtcbiAgICAgICAgZXhwcmVzc2lvbnMuc