UNPKG

@cloudcamp/aws-runtime

Version:

CloudCamp - Launch faster by building scalable infrastructure in few lines of code.

322 lines 32.5 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.App = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const cdk = require("aws-cdk-lib/core"); const _ = require("lodash"); const pipeline_1 = require("./pipeline"); const stage_1 = require("./stage"); const utils_1 = require("./utils"); const constants_1 = require("./constants"); const ssm = require("aws-cdk-lib/aws-ssm"); const pipelines = require("aws-cdk-lib/pipelines"); const stack_1 = require("./stack"); /** * (experimental) App represents your application running in the cloud․ Every app contains one or more ``{@link Stack | Stacks}``, which you can use to add your own resources, like a ``{@link WebService | WebService}`` or a ``{@link Database | Database}``. * * An app can be as big or small as you like - from a single webserver to * dozens of load-balanced instances serving different parts of your * application. * * This example adds a ``{@link WebService | WebService}`` to the * ``{@link App.production | production}`` stack: * * ```ts * import { App, WebService } from "@cloudcamp/aws-runtime"; * * let app = new App(); * * new WebService(app.production, "prod-web", { * dockerfile: "../Dockerfile" * }); * ``` * * @experimental * @order 1 */ class App extends cdk.App { /** * (experimental) Initialize your cloudcamp application. * * @experimental * @remarks App is a singleton class - it is instantiated exactly once, before * any other resources are created. * @topic Initialization */ constructor() { super({ autoSynth: true }); this.stages = new Map(); if (App.INSTANCE) { throw new Error("App has already been instantiated."); } App.INSTANCE = this; this.configuration = { account: this.getContextOrThrow(constants_1.CONTEXT_KEY_ACCOUNT), region: this.getContextOrThrow(constants_1.CONTEXT_KEY_REGION), repository: this.getContextOrThrow(constants_1.CONTEXT_KEY_REPOSITORY), name: this.getContextOrThrow(constants_1.CONTEXT_KEY_NAME), branch: this.getContextOrThrow(constants_1.CONTEXT_KEY_BRANCH), vpcId: this.getContextOrThrow(constants_1.CONTEXT_KEY_VPC), repositoryTokenSecret: this.getContextOrThrow(constants_1.CONTEXT_REPOSITORY_TOKEN_SECRET), }; cdk.Tags.of(this).add(constants_1.TAG_APP_NAME, this.configuration.name); this.pipelineStack = this.setupCodePipeline(); //add pipelineStack to our global list of stacks new ssm.StringParameter(this.pipelineStack, "ssm-stack", { parameterName: `/cloudcamp/${App.instance.configuration.name}/_/stack/${_.kebabCase(this.pipelineStack.stackName)}`, stringValue: this.pipelineStack.stackName, }); // We need the name of the codepipeline for later use new ssm.StringParameter(this.pipelineStack, "ssm-codepipeline", { parameterName: `/cloudcamp/${this.configuration.name}/_/codepipeline`, stringValue: this.pipelineStack.pipelineName, }); // Also, we need to identify the pipeline stack new ssm.StringParameter(this.pipelineStack, "ssm-pipeline-stack", { parameterName: `/cloudcamp/${this.configuration.name}/_/pipeline-stack`, stringValue: this.pipelineStack.stackName, }); } getContextOrThrow(key) { let value = this.node.tryGetContext(key); if (value == null) { throw new Error("Missing config in cdk.json: " + key); } return value; } /** * (experimental) Returns the global App singleton instance. * * Throws an exception if App has not been instantiated yet. * * @experimental */ static get instance() { if (!App.INSTANCE) { throw new Error("instance() called but App has not been instantiated yet."); } return App.INSTANCE; } /** * (experimental) Use this stack for anything related to the network, for example DNS entries. * * @experimental * @topic Stacks * @remarks To deploy resources to the cloud, they are added to a ``Stack``. * CloudCamp comes with three default stacks: */ get network() { return this.getOrAddStage("network").stack; } /** * (experimental) This stack can be used to create an environment for testing changes before deploying to production. * * @experimental */ get staging() { return this.getOrAddStage("staging").stack; } /** * (experimental) The production stack. * * @experimental */ get production() { return this.getOrAddStage("production").stack; } /** * (experimental) Get an existing stack by name. * * @param name The name of the stack. * @experimental * @topic Adding custom stacks * @remarks In addition to the default stacks provided by cloudcamp, you can * create your own stacks. */ getStack(name) { try { return this.getStage(name).stack; } catch (e) { if (e.message.startsWith("Stage doesn't exist")) { throw new Error("Stack doesn't exist: " + name); } else { throw e; } } } /** * (experimental) Add a new stack to your application. * * Pass a stack name to create a new, empty stack: * * ```ts * void 0; * import { App, WebService, Stack} from "@cloudcamp/aws-runtime"; * const app = new App(); * void 'show'; * const devStack = app.stack("development"); * ``` * * @param name The name of the stack. * @experimental */ stack(name) { if (this.stages.get(name)) { throw new Error("Stack already exists: " + name); } return this.getOrAddStage(name).stack; } getOrAddStage(id) { let existingStage = this.stages.get(id); if (existingStage) { return existingStage; } let stage = new stage_1.Stage(this, _.upperFirst(_.camelCase(id))); let stack = new stack_1.Stack(stage, id); stage.stack = stack; this.stages.set(id, stage); return stage; } /** * (experimental) Get an existing stage by name. * * Stages can be obtained by their name to modify their attributes. A common * use case is to require manual approval to deploy to the production stage: * * ```ts * const stage = app.getStage("production"); * stage.needsManualApproval = true; * ``` * * @param name The name of the stage. * @experimental * @topic Stages * @remarks Stages are responsible for building your stacks. By default, * CloudCamp creates a stage for each stack and gives it the same name. You * can customize this behaviour by adding your own stages. */ getStage(name) { if (name in ["network", "staging", "production"]) { return this.getOrAddStage(name); } if (!this.stages.has(name)) { throw new Error("Stage doesn't exist: " + name); } return this.stages.get(name); } /** * (experimental) Add a new stage. * * This method can be used to add a stage with a custom ``Stack`` subclass. * ```ts * import { App, WebService, Stack } from "@cloudcamp/aws-runtime"; * * class CustomStack extends Stack { * constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) { * super(scope, id, props); * new WebService(this, "web", { * dockerfile: "../Dockerfile" * }); * } * } * * // later in the code... * const app = new App(); * const stage = app.stage("dev"); * const stack = new CustomStack(stage, "dev"); * * // stack is automatically set to the new stack we created * if (stage.stack == stack) { * // outputs "True!" * console.log("True!"); * } * ``` * * @param name The name of the stage. * @param stage An optional stage object. * @experimental */ stage(name, stage) { if (this.stages.has(name)) { throw new Error("Stage already exists: " + name); } if (!stage) { stage = new stage_1.Stage(this, _.upperFirst(_.camelCase(name))); } this.stages.set(name, stage); return stage; } /** * @experimental * @ignore true */ get pipeline() { return this.pipelineStack.pipeline; } setupCodePipeline() { const repositoryUrl = this.configuration.repository; const branch = this.configuration.branch; let parsed = utils_1.parseRepositoryUrl(repositoryUrl); let repositoryTokenSecretName = this.configuration.repositoryTokenSecret; return new pipeline_1.PipelineStack(this, _.upperFirst(_.camelCase(this.configuration.name + "-pipeline")), { appName: this.configuration.name, repositoryTokenSecretName: repositoryTokenSecretName, host: parsed.host, owner: parsed.owner, repo: parsed.repo, branch: branch, }); } /** * (experimental) Synthesize this stage into a cloud assembly. * * Once an assembly has been synthesized, it cannot be modified. Subsequent * calls will return the same assembly. * * @experimental * @ignore true */ synth(options) { let names = Array.from(this.stages.keys()); names.sort((a, b) => { switch (a) { case "network": if (b == "staging" || b == "production") { return -1; } return 0; case "staging": if (b == "network") { return 1; } if (b == "production") { return -1; } return 0; case "production": if (b == "network" || b == "staging") { return 1; } return 0; default: return 0; } }); for (let name of names) { let stage = this.stages.get(name); let pre = undefined; if (stage.needsManualApproval) { pre = [new pipelines.ManualApprovalStep("approve-" + name)]; } this.pipeline.addStage(stage, { pre: pre }); } return super.synth(options); } } exports.App = App; _a = JSII_RTTI_SYMBOL_1; App[_a] = { fqn: "@cloudcamp/aws-runtime.App", version: "0.0.1" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2FwcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdDQUF3QztBQUN4Qyw0QkFBNEI7QUFDNUIseUNBQTJDO0FBQzNDLG1DQUFnQztBQUNoQyxtQ0FBNkM7QUFDN0MsMkNBU3FCO0FBQ3JCLDJDQUEyQztBQUUzQyxtREFBbUQ7QUFDbkQsbUNBQWdDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFjaEMsTUFBYSxHQUFJLFNBQVEsR0FBRyxDQUFDLEdBQUc7Ozs7Ozs7OztJQUk5QjtRQUNFLEtBQUssQ0FBQyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBa0dyQixXQUFNLEdBQXVCLElBQUksR0FBRyxFQUFFLENBQUM7UUFoRzdDLElBQUksR0FBRyxDQUFDLFFBQVEsRUFBRTtZQUNoQixNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUM7U0FDdkQ7UUFFRCxHQUFHLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUVwQixJQUFJLENBQUMsYUFBYSxHQUFHO1lBQ25CLE9BQU8sRUFBRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsK0JBQW1CLENBQUM7WUFDcEQsTUFBTSxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyw4QkFBa0IsQ0FBQztZQUNsRCxVQUFVLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLGtDQUFzQixDQUFDO1lBQzFELElBQUksRUFBRSxJQUFJLENBQUMsaUJBQWlCLENBQUMsNEJBQWdCLENBQUM7WUFDOUMsTUFBTSxFQUFFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyw4QkFBa0IsQ0FBQztZQUNsRCxLQUFLLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUFDLDJCQUFlLENBQUM7WUFDOUMscUJBQXFCLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixDQUMzQywyQ0FBK0IsQ0FDaEM7U0FDRixDQUFDO1FBRUYsR0FBRyxDQUFDLElB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RyxHQUFHLENBQUMsSUFBSSxTQUFTLENBQUMsa0JBQWtCLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7YUFDN0Q7WUFDRCxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztTQUM3QztRQUNELE9BQU8sS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM5QixDQUFDOztBQTlNSCxrQkErTUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjZGsgZnJvbSBcImF3cy1jZGstbGliL2NvcmVcIjtcbmltcG9ydCAqIGFzIF8gZnJvbSBcImxvZGFzaFwiO1xuaW1wb3J0IHsgUGlwZWxpbmVTdGFjayB9IGZyb20gXCIuL3BpcGVsaW5lXCI7XG5pbXBvcnQgeyBTdGFnZSB9IGZyb20gXCIuL3N0YWdlXCI7XG5pbXBvcnQgeyBwYXJzZVJlcG9zaXRvcnlVcmwgfSBmcm9tIFwiLi91dGlsc1wiO1xuaW1wb3J0IHtcbiAgQ09OVEVYVF9LRVlfQUNDT1VOVCxcbiAgQ09OVEVYVF9LRVlfQlJBTkNILFxuICBDT05URVhUX0tFWV9OQU1FLFxuICBDT05URVhUX0tFWV9SRUdJT04sXG4gIENPTlRFWFRfS0VZX1JFUE9TSVRPUlksXG4gIENPTlRFWFRfS0VZX1ZQQyxcbiAgQ09OVEVYVF9SRVBPU0lUT1JZX1RPS0VOX1NFQ1JFVCxcbiAgVEFHX0FQUF9OQU1FLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCAqIGFzIHNzbSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNzbVwiO1xuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSBcImF3cy1jZGstbGliL2N4LWFwaVwiO1xuaW1wb3J0ICogYXMgcGlwZWxpbmVzIGZyb20gXCJhd3MtY2RrLWxpYi9waXBlbGluZXNcIjtcbmltcG9ydCB7IFN0YWNrIH0gZnJvbSBcIi4vc3RhY2tcIjtcblxuZXhwb3J0IGludGVyZmFjZSBDb25maWd1cmF0aW9uIHtcbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuICByZWFkb25seSByZXBvc2l0b3J5OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGFjY291bnQ6IHN0cmluZztcbiAgcmVhZG9ubHkgcmVnaW9uOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGJyYW5jaDogc3RyaW5nO1xuICByZWFkb25seSB2cGNJZDogc3RyaW5nO1xuICByZWFkb25seSByZXBvc2l0b3J5VG9rZW5TZWNyZXQ6IHN0cmluZztcbn1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuXG5leHBvcnQgY2xhc3MgQXBwIGV4dGVuZHMgY2RrLkFwcCB7XG4gIHByaXZhdGUgc3RhdGljIElOU1RBTkNFPzogQXBwO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoeyBhdXRvU3ludGg6IHRydWUgfSk7XG5cbiAgICBpZiAoQXBwLklOU1RBTkNFKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBcHAgaGFzIGFscmVhZHkgYmVlbiBpbnN0YW50aWF0ZWQuXCIpO1xuICAgIH1cblxuICAgIEFwcC5JTlNUQU5DRSA9IHRoaXM7XG5cbiAgICB0aGlzLmNvbmZpZ3VyYXRpb24gPSB7XG4gICAgICBhY2NvdW50OiB0aGlzLmdldENvbnRleHRPclRocm93KENPTlRFWFRfS0VZX0FDQ09VTlQpLFxuICAgICAgcmVnaW9uOiB0aGlzLmdldENvbnRleHRPclRocm93KENPTlRFWFRfS0VZX1JFR0lPTiksXG4gICAgICByZXBvc2l0b3J5OiB0aGlzLmdldENvbnRleHRPclRocm93KENPTlRFWFRfS0VZX1JFUE9TSVRPUlkpLFxuICAgICAgbmFtZTogdGhpcy5nZXRDb250ZXh0T3JUaHJvdyhDT05URVhUX0tFWV9OQU1FKSxcbiAgICAgIGJyYW5jaDogdGhpcy5nZXRDb250ZXh0T3JUaHJvdyhDT05URVhUX0tFWV9CUkFOQ0gpLFxuICAgICAgdnBjSWQ6IHRoaXMuZ2V0Q29udGV4dE9yVGhyb3coQ09OVEVYVF9LRVlfVlBDKSxcbiAgICAgIHJlcG9zaXRvcnlUb2tlblNlY3JldDogdGhpcy5nZXRDb250ZXh0T3JUaHJvdyhcbiAgICAgICAgQ09OVEVYVF9SRVBPU0lUT1JZX1RPS0VOX1NFQ1JFVFxuICAgICAgKSxcbiAgICB9O1xuXG4gICAgY2RrLlRhZ3Mub2YodGhpcykuYWRkKFRBR19BUFBfTkFNRSwgdGhpcy5jb25maWd1cmF0aW9uLm5hbWUpO1xuICAgIHRoaXMucGlwZWxpbmVTdGFjayA9IHRoaXMuc2V0dXBDb2RlUGlwZWxpbmUoKTtcblxuICAgIC8vYWRkIHBpcGVsaW5lU3RhY2sgdG8gb3VyIGdsb2JhbCBsaXN0IG9mIHN0YWNrc1xuICAgIG5ldyBzc20uU3RyaW5nUGFyYW1ldGVyKHRoaXMucGlwZWxpbmVTdGFjaywgXCJzc20tc3RhY2tcIiwge1xuICAgICAgcGFyYW1ldGVyTmFtZTogYC9jbG91ZGNhbXAvJHtcbiAgICAgICAgQXBwLmluc3RhbmNlLmNvbmZpZ3VyYXRpb24ubmFtZVxuICAgICAgfS9fL3N0YWNrLyR7Xy5rZWJhYkNhc2UodGhpcy5waXBlbGluZVN0YWNrLnN0YWNrTmFtZSl9YCxcbiAgICAgIHN0cmluZ1ZhbHVlOiB0aGlzLnBpcGVsaW5lU3RhY2suc3RhY2tOYW1lLFxuICAgIH0pO1xuXG4gICAgLy8gV2UgbmVlZCB0aGUgbmFtZSBvZiB0aGUgY29kZXBpcGVsaW5lIGZvciBsYXRlciB1c2VcbiAgICBuZXcgc3NtLlN0cmluZ1BhcmFtZXRlcih0aGlzLnBpcGVsaW5lU3RhY2ssIFwic3NtLWNvZGVwaXBlbGluZVwiLCB7XG4gICAgICBwYXJhbWV0ZXJOYW1lOiBgL2Nsb3VkY2FtcC8ke3RoaXMuY29uZmlndXJhdGlvbi5uYW1lfS9fL2NvZGVwaXBlbGluZWAsXG4gICAgICBzdHJpbmdWYWx1ZTogdGhpcy5waXBlbGluZVN0YWNrLnBpcGVsaW5lTmFtZSxcbiAgICB9KTtcblxuICAgIC8vIEFsc28sIHdlIG5lZWQgdG8gaWRlbnRpZnkgdGhlIHBpcGVsaW5lIHN0YWNrXG4gICAgbmV3IHNzbS5TdHJpbmdQYXJhbWV0ZXIodGhpcy5waXBlbGluZVN0YWNrLCBcInNzbS1waXBlbGluZS1zdGFja1wiLCB7XG4gICAgICBwYXJhbWV0ZXJOYW1lOiBgL2Nsb3VkY2FtcC8ke3RoaXMuY29uZmlndXJhdGlvbi5uYW1lfS9fL3BpcGVsaW5lLXN0YWNrYCxcbiAgICAgIHN0cmluZ1ZhbHVlOiB0aGlzLnBpcGVsaW5lU3RhY2suc3RhY2tOYW1lLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRDb250ZXh0T3JUaHJvdyhrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgbGV0IHZhbHVlOiBzdHJpbmcgPSB0aGlzLm5vZGUudHJ5R2V0Q29udGV4dChrZXkpO1xuICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNaXNzaW5nIGNvbmZpZyBpbiBjZGsuanNvbjogXCIgKyBrZXkpO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgc3RhdGljIGdldCBpbnN0YW5jZSgpOiBBcHAge1xuICAgIGlmICghQXBwLklOU1RBTkNFKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIFwiaW5zdGFuY2UoKSBjYWxsZWQgYnV0IEFwcCBoYXMgbm90IGJlZW4gaW5zdGFudGlhdGVkIHlldC5cIlxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIEFwcC5JTlNUQU5DRTtcbiAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgZ2V0IG5ldHdvcmsoKTogU3RhY2sge1xuICAgIHJldHVybiB0aGlzLmdldE9yQWRkU3RhZ2UoXCJuZXR3b3JrXCIpLnN0YWNrO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgZ2V0IHN0YWdpbmcoKTogU3RhY2sge1xuICAgIHJldHVybiB0aGlzLmdldE9yQWRkU3RhZ2UoXCJzdGFnaW5nXCIpLnN0YWNrO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIGdldCBwcm9kdWN0aW9uKCk6IFN0YWNrIHtcbiAgICByZXR1cm4gdGhpcy5nZXRPckFkZFN0YWdlKFwicHJvZHVjdGlvblwiKS5zdGFjaztcbiAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIGdldFN0YWNrKG5hbWU6IHN0cmluZyk6IFN0YWNrIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0U3RhZ2UobmFtZSkuc3RhY2s7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgaWYgKChlIGFzIEVycm9yKS5tZXNzYWdlLnN0YXJ0c1dpdGgoXCJTdGFnZSBkb2Vzbid0IGV4aXN0XCIpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlN0YWNrIGRvZXNuJ3QgZXhpc3Q6IFwiICsgbmFtZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGFjayhuYW1lOiBzdHJpbmcpOiBTdGFjayB7XG4gICAgaWYgKHRoaXMuc3RhZ2VzLmdldChuYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU3RhY2sgYWxyZWFkeSBleGlzdHM6IFwiICsgbmFtZSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmdldE9yQWRkU3RhZ2UobmFtZSkuc3RhY2s7XG4gIH1cblxuICBwcml2YXRlIHN0YWdlczogTWFwPHN0cmluZywgU3RhZ2U+ID0gbmV3IE1hcCgpO1xuXG4gIHByaXZhdGUgZ2V0T3JBZGRTdGFnZShpZDogc3RyaW5nKSB7XG4gICAgbGV0IGV4aXN0aW5nU3RhZ2UgPSB0aGlzLnN0YWdlcy5nZXQoaWQpO1xuICAgIGlmIChleGlzdGluZ1N0YWdlKSB7XG4gICAgICByZXR1cm4gZXhpc3RpbmdTdGFnZTtcbiAgICB9XG4gICAgbGV0IHN0YWdlID0gbmV3IFN0YWdlKHRoaXMsIF8udXBwZXJGaXJzdChfLmNhbWVsQ2FzZShpZCkpKTtcbiAgICBsZXQgc3RhY2sgPSBuZXcgU3RhY2soc3RhZ2UsIGlkKTtcbiAgICBzdGFnZS5zdGFjayA9IHN0YWNrO1xuICAgIHRoaXMuc3RhZ2VzLnNldChpZCwgc3RhZ2UpO1xuXG4gICAgcmV0dXJuIHN0YWdlO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuXG4gIHB1YmxpYyBnZXRTdGFnZShuYW1lOiBzdHJpbmcpOiBTdGFnZSB7XG4gICAgaWYgKG5hbWUgaW4gW1wibmV0d29ya1wiLCBcInN0YWdpbmdcIiwgXCJwcm9kdWN0aW9uXCJdKSB7XG4gICAgICByZXR1cm4gdGhpcy5nZXRPckFkZFN0YWdlKG5hbWUpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuc3RhZ2VzLmhhcyhuYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU3RhZ2UgZG9lc24ndCBleGlzdDogXCIgKyBuYW1lKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuc3RhZ2VzLmdldChuYW1lKSE7XG4gIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHN0YWdlKG5hbWU6IHN0cmluZywgc3RhZ2U/OiBTdGFnZSk6IFN0YWdlIHtcbiAgICBpZiAodGhpcy5zdGFnZXMuaGFzKG5hbWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTdGFnZSBhbHJlYWR5IGV4aXN0czogXCIgKyBuYW1lKTtcbiAgICB9XG4gICAgaWYgKCFzdGFnZSkge1xuICAgICAgc3RhZ2UgPSBuZXcgU3RhZ2UodGhpcywgXy51cHBlckZpcnN0KF8uY2FtZWxDYXNlKG5hbWUpKSk7XG4gICAgfVxuICAgIHRoaXMuc3RhZ2VzLnNldChuYW1lLCBzdGFnZSk7XG4gICAgcmV0dXJuIHN0YWdlO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICBjb25maWd1cmF0aW9uOiBDb25maWd1cmF0aW9uO1xuXG4gIHByaXZhdGUgcGlwZWxpbmVTdGFjazogUGlwZWxpbmVTdGFjaztcbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgZ2V0IHBpcGVsaW5lKCkge1xuICAgIHJldHVybiB0aGlzLnBpcGVsaW5lU3RhY2sucGlwZWxpbmU7XG4gIH1cblxuICBwcml2YXRlIHNldHVwQ29kZVBpcGVsaW5lKCk6IFBpcGVsaW5lU3RhY2sge1xuICAgIGNvbnN0IHJlcG9zaXRvcnlVcmwgPSB0aGlzLmNvbmZpZ3VyYXRpb24ucmVwb3NpdG9yeTtcbiAgICBjb25zdCBicmFuY2ggPSB0aGlzLmNvbmZpZ3VyYXRpb24uYnJhbmNoO1xuICAgIGxldCBwYXJzZWQgPSBwYXJzZVJlcG9zaXRvcnlVcmwocmVwb3NpdG9yeVVybCk7XG4gICAgbGV0IHJlcG9zaXRvcnlUb2tlblNlY3JldE5hbWUgPSB0aGlzLmNvbmZpZ3VyYXRpb24ucmVwb3NpdG9yeVRva2VuU2VjcmV0O1xuICAgIHJldHVybiBuZXcgUGlwZWxpbmVTdGFjayhcbiAgICAgIHRoaXMsXG4gICAgICBfLnVwcGVyRmlyc3QoXy5jYW1lbENhc2UodGhpcy5jb25maWd1cmF0aW9uLm5hbWUgKyBcIi1waXBlbGluZVwiKSksXG4gICAgICB7XG4gICAgICAgIGFwcE5hbWU6IHRoaXMuY29uZmlndXJhdGlvbi5uYW1lLFxuICAgICAgICByZXBvc2l0b3J5VG9rZW5TZWNyZXROYW1lOiByZXBvc2l0b3J5VG9rZW5TZWNyZXROYW1lLFxuICAgICAgICBob3N0OiBwYXJzZWQuaG9zdCxcbiAgICAgICAgb3duZXI6IHBhcnNlZC5vd25lcixcbiAgICAgICAgcmVwbzogcGFyc2VkLnJlcG8sXG4gICAgICAgIGJyYW5jaDogYnJhbmNoLFxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHN5bnRoKG9wdGlvbnM/OiBjZGsuU3RhZ2VTeW50aGVzaXNPcHRpb25zKTogY3hhcGkuQ2xvdWRBc3NlbWJseSB7XG4gICAgbGV0IG5hbWVzID0gQXJyYXkuZnJvbSh0aGlzLnN0YWdlcy5rZXlzKCkpO1xuICAgIG5hbWVzLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgIHN3aXRjaCAoYSkge1xuICAgICAgICBjYXNlIFwibmV0d29ya1wiOlxuICAgICAgICAgIGlmIChiID09IFwic3RhZ2luZ1wiIHx8IGIgPT0gXCJwcm9kdWN0aW9uXCIpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIGNhc2UgXCJzdGFnaW5nXCI6XG4gICAgICAgICAgaWYgKGIgPT0gXCJuZXR3b3JrXCIpIHtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoYiA9PSBcInByb2R1Y3Rpb25cIikge1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgY2FzZSBcInByb2R1Y3Rpb25cIjpcbiAgICAgICAgICBpZiAoYiA9PSBcIm5ldHdvcmtcIiB8fCBiID09IFwic3RhZ2luZ1wiKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZm9yIChsZXQgbmFtZSBvZiBuYW1lcykge1xuICAgICAgbGV0IHN0YWdlID0gdGhpcy5zdGFnZXMuZ2V0KG5hbWUpITtcbiAgICAgIGxldCBwcmUgPSB1bmRlZmluZWQ7XG4gICAgICBpZiAoc3RhZ2UubmVlZHNNYW51YWxBcHByb3ZhbCkge1xuICAgICAgICBwcmUgPSBbbmV3IHBpcGVsaW5lcy5NYW51YWxBcHByb3ZhbFN0ZXAoXCJhcHByb3ZlLVwiICsgbmFtZSldO1xuICAgICAgfVxuICAgICAgdGhpcy5waXBlbGluZS5hZGRTdGFnZShzdGFnZSwgeyBwcmU6IHByZSB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHN1cGVyLnN5bnRoKG9wdGlvbnMpO1xuICB9XG59XG4iXX0=