UNPKG

ness

Version:

✪ No-effort static sites deployed to your AWS account.

452 lines 49.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParameterValues = exports.TemplateParameters = exports.stabilizeStack = exports.waitForStackDeploy = exports.waitForStackDelete = exports.changeSetHasNoChanges = exports.waitForChangeSet = exports.CloudFormationStack = exports.toYAML = void 0; const stack_status_1 = require("./stack-status"); const yaml = __importStar(require("./yaml")); /** * Stringify to YAML */ function toYAML(obj) { return yaml.serialize(obj); } exports.toYAML = toYAML; /** * Parse either YAML or JSON */ function deserializeStructure(str) { try { return yaml.deserialize(str); } catch (e) { return JSON.parse(str); } } /** * Represents an (existing) Stack in CloudFormation * * Bundle and cache some information that we need during deployment (so we don't have to make * repeated calls to CloudFormation). */ class CloudFormationStack { constructor(cfn, stackName, stack) { this.cfn = cfn; this.stackName = stackName; this.stack = stack; } static async lookup(cfn, stackName) { try { const response = await cfn.describeStacks({ StackName: stackName }); return new CloudFormationStack(cfn, stackName, response.Stacks && response.Stacks[0]); } catch (e) { if (e instanceof Error) { if (e.message === `Stack with id ${stackName} does not exist`) { return new CloudFormationStack(cfn, stackName, undefined); } } throw e; } } /** * Return a copy of the given stack that does not exist * * It's a little silly that it needs arguments to do that, but there we go. */ static doesNotExist(cfn, stackName) { return new CloudFormationStack(cfn, stackName); } /** * From static information (for testing) */ static fromStaticInformation(cfn, stackName, stack) { return new CloudFormationStack(cfn, stackName, stack); } /** * Retrieve the stack's deployed template * * Cached, so will only be retrieved once. Will return an empty * structure if the stack does not exist. */ async template() { if (!this.exists) { return {}; } if (this._template === undefined) { const response = await this.cfn.getTemplate({ StackName: this.stackName, TemplateStage: 'Original', }); this._template = (response.TemplateBody && deserializeStructure(response.TemplateBody)) || {}; } return this._template; } /** * Whether the stack exists */ get exists() { return this.stack !== undefined; } /** * The stack's ID * * Throws if the stack doesn't exist. */ get stackId() { this.assertExists(); return this.stack.StackId; } /** * The stack's current outputs * * Empty object if the stack doesn't exist */ get outputs() { if (!this.exists) { return {}; } const result = {}; (this.stack.Outputs || []).forEach((output) => { result[output.OutputKey] = output.OutputValue; }); return result; } /** * The stack's status * * Special status NOT_FOUND if the stack does not exist. */ get stackStatus() { if (!this.exists) { return new stack_status_1.StackStatus('NOT_FOUND', 'Stack not found during lookup'); } return stack_status_1.StackStatus.fromStackDescription(this.stack); } /** * The stack's current tags * * Empty list of the stack does not exist */ get tags() { var _a; return ((_a = this.stack) === null || _a === void 0 ? void 0 : _a.Tags) || []; } /** * Return the names of all current parameters to the stack * * Empty list if the stack does not exist. */ get parameterNames() { return Object.keys(this.parameters); } /** * Return the names and values of all current parameters to the stack * * Empty object if the stack does not exist. */ get parameters() { var _a; if (!this.exists) { return {}; } const ret = {}; for (const param of (_a = this.stack.Parameters) !== null && _a !== void 0 ? _a : []) { ret[param.ParameterKey] = param.ParameterValue; } return ret; } /** * Return the termination protection of the stack */ get terminationProtection() { var _a; return (_a = this.stack) === null || _a === void 0 ? void 0 : _a.EnableTerminationProtection; } assertExists() { if (!this.exists) { throw new Error(`No stack named '${this.stackName}'`); } } } exports.CloudFormationStack = CloudFormationStack; /** * Describe a changeset in CloudFormation, regardless of its current state. * * @param cfn a CloudFormation client * @param stackName the name of the Stack the ChangeSet belongs to * @param changeSetName the name of the ChangeSet * * @returns CloudFormation information about the ChangeSet */ async function describeChangeSet(cfn, stackName, changeSetName) { const response = await cfn.describeChangeSet({ StackName: stackName, ChangeSetName: changeSetName }); return response; } /** * Waits for a function to return non-+undefined+ before returning. * * @param valueProvider a function that will return a value that is not +undefined+ once the wait should be over * @param timeout the time to wait between two calls to +valueProvider+ * * @returns the value that was returned by +valueProvider+ */ async function waitFor(valueProvider, timeout = 5000) { while (true) { const result = await valueProvider(); if (result === null) { return undefined; } else if (result !== undefined) { return result; } await new Promise((cb) => setTimeout(cb, timeout)); } } /** * Waits for a ChangeSet to be available for triggering a StackUpdate. * * Will return a changeset that is either ready to be executed or has no changes. * Will throw in other cases. * * @param cfn a CloudFormation client * @param stackName the name of the Stack that the ChangeSet belongs to * @param changeSetName the name of the ChangeSet * * @returns the CloudFormation description of the ChangeSet */ // eslint-disable-next-line max-len async function waitForChangeSet(cfn, stackName, changeSetName) { // debug('Waiting for changeset %s on stack %s to finish creating...', changeSetName, stackName) const ret = await waitFor(async () => { const description = await describeChangeSet(cfn, stackName, changeSetName); // The following doesn't use a switch because tsc will not allow fall-through, UNLESS it is allows // EVERYWHERE that uses this library directly or indirectly, which is undesirable. if (description.Status === 'CREATE_PENDING' || description.Status === 'CREATE_IN_PROGRESS') { // debug('Changeset %s on stack %s is still creating', changeSetName, stackName) return undefined; } if (description.Status === 'CREATE_COMPLETE' || changeSetHasNoChanges(description)) { return description; } // eslint-disable-next-line max-len throw new Error(`Failed to create ChangeSet ${changeSetName} on ${stackName}: ${description.Status || 'NO_STATUS'}, ${description.StatusReason || 'no reason provided'}`); }); if (!ret) { throw new Error('Change set took too long to be created; aborting'); } return ret; } exports.waitForChangeSet = waitForChangeSet; /** * Return true if the given change set has no changes * * This must be determined from the status, not the 'Changes' array on the * object; the latter can be empty because no resources were changed, but if * there are changes to Outputs, the change set can still be executed. */ function changeSetHasNoChanges(description) { const noChangeErrorPrefixes = [ // Error message for a regular template "The submitted information didn't contain changes.", // Error message when a Transform is involved (see #10650) 'No updates are to be performed.', ]; return (description.Status === 'FAILED' && noChangeErrorPrefixes.some((p) => { var _a; return ((_a = description.StatusReason) !== null && _a !== void 0 ? _a : '').startsWith(p); })); } exports.changeSetHasNoChanges = changeSetHasNoChanges; /** * Waits for a CloudFormation stack to stabilize in a complete/available state * after a delete operation is issued. * * Fails if the stack is in a FAILED state. Will not fail if the stack was * already deleted. * * @param cfn a CloudFormation client * @param stackName the name of the stack to wait for after a delete * * @returns the CloudFormation description of the stabilized stack after the delete attempt */ async function waitForStackDelete(cfn, stackName) { const stack = await stabilizeStack(cfn, stackName); if (!stack) { return undefined; } const status = stack.stackStatus; if (status.isFailure) { throw new Error(`The stack named ${stackName} is in a failed state. You may need to delete it from the AWS console : ${status}`); } else if (status.isDeleted) { return undefined; } return stack; } exports.waitForStackDelete = waitForStackDelete; /** * Waits for a CloudFormation stack to stabilize in a complete/available state * after an update/create operation is issued. * * Fails if the stack is in a FAILED state, ROLLBACK state, or DELETED state. * * @param cfn a CloudFormation client * @param stackName the name of the stack to wait for after an update * * @returns the CloudFormation description of the stabilized stack after the update attempt */ async function waitForStackDeploy(cfn, stackName) { const stack = await stabilizeStack(cfn, stackName); if (!stack) { return undefined; } const status = stack.stackStatus; if (status.isCreationFailure) { throw new Error(`The stack named ${stackName} failed creation, it may need to be manually deleted from the AWS console: ${status}`); } else if (!status.isDeploySuccess) { throw new Error(`The stack named ${stackName} failed to deploy: ${status}`); } return stack; } exports.waitForStackDeploy = waitForStackDeploy; /** * Wait for a stack to become stable (no longer _IN_PROGRESS), returning it */ async function stabilizeStack(cfn, stackName) { // debug('Waiting for stack %s to finish creating or updating...', stackName) return waitFor(async () => { const stack = await CloudFormationStack.lookup(cfn, stackName); if (!stack.exists) { // debug('Stack %s does not exist', stackName) return null; } const status = stack.stackStatus; if (status.isInProgress) { // debug( // 'Stack %s has an ongoing operation in progress and is not stable (%s)', // stackName, // status, // ) return undefined; } return stack; }); } exports.stabilizeStack = stabilizeStack; /** * The set of (formal) parameters that have been declared in a template */ class TemplateParameters { constructor(params) { this.params = params; } static fromTemplate(template) { return new TemplateParameters(template.Parameters || {}); } /** * Calculate stack parameters to pass from the given desired parameter values * * Will throw if parameters without a Default value or a Previous value are not * supplied. */ supplyAll(updates) { return new ParameterValues(this.params, updates); } /** * From the template, the given desired values and the current values, calculate the changes to the stack parameters * * Will take into account parameters already set on the template (will emit * 'UsePreviousValue: true' for those unless the value is changed), and will * throw if parameters without a Default value or a Previous value are not * supplied. */ updateExisting(updates, previousValues) { return new ParameterValues(this.params, updates, previousValues); } } exports.TemplateParameters = TemplateParameters; /** * The set of parameters we're going to pass to a Stack */ class ParameterValues { constructor(formalParams, updates, previousValues = {}) { this.formalParams = formalParams; this.values = {}; this.apiParameters = []; const missingRequired = new Array(); for (const [key, formalParam] of Object.entries(this.formalParams)) { // Check updates first, then use the previous value (if available), then use // the default (if available). // // If we don't find a parameter value using any of these methods, then that's an error. const updatedValue = updates[key]; if (updatedValue !== undefined) { this.values[key] = updatedValue; this.apiParameters.push({ ParameterKey: key, ParameterValue: updates[key] }); continue; } if (key in previousValues) { this.values[key] = previousValues[key]; this.apiParameters.push({ ParameterKey: key, UsePreviousValue: true }); continue; } if (formalParam.Default !== undefined) { this.values[key] = formalParam.Default; continue; } // Oh no missingRequired.push(key); } if (missingRequired.length > 0) { throw new Error(`The following CloudFormation Parameters are missing a value: ${missingRequired.join(', ')}`); } // Just append all supplied overrides that aren't really expected (this // will fail CFN but maybe people made typos that they want to be notified // of) const unknownParam = ([key, _]) => this.formalParams[key] === undefined; const hasValue = ([_, value]) => !!value; for (const [key, value] of Object.entries(updates).filter(unknownParam).filter(hasValue)) { this.values[key] = value; this.apiParameters.push({ ParameterKey: key, ParameterValue: value }); } } /** * Whether this set of parameter updates will change the actual stack values */ hasChanges(currentValues) { // If any of the parameters are SSM parameters, deploying must always happen // because we can't predict what the values will be. if (Object.values(this.formalParams).some((p) => p.Type.startsWith('AWS::SSM::Parameter::'))) { return true; } // Otherwise we're dirty if: // - any of the existing values are removed, or changed if (Object.entries(currentValues).some(([key, value]) => !(key in this.values) || value !== this.values[key])) { return true; } // - any of the values we're setting are new if (Object.keys(this.values).some((key) => !(key in currentValues))) { return true; } return false; } } exports.ParameterValues = ParameterValues; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmb3JtYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJvdmlkZXJzL2F3cy9jbG91ZGZvcm1hdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBT0EsaURBQTBDO0FBQzFDLDZDQUE4QjtBQWE5Qjs7R0FFRztBQUNILFNBQWdCLE1BQU0sQ0FBQyxHQUFRO0lBQzdCLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQTtBQUM1QixDQUFDO0FBRkQsd0JBRUM7QUFFRDs7R0FFRztBQUNILFNBQVMsb0JBQW9CLENBQUMsR0FBVztJQUN2QyxJQUFJO1FBQ0YsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0tBQzdCO0lBQUMsT0FBTyxDQUFDLEVBQUU7UUFDVixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUE7S0FDdkI7QUFDSCxDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFhLG1CQUFtQjtJQWlDOUIsWUFDbUIsR0FBbUIsRUFDcEIsU0FBaUIsRUFDaEIsS0FBYTtRQUZiLFFBQUcsR0FBSCxHQUFHLENBQWdCO1FBQ3BCLGNBQVMsR0FBVCxTQUFTLENBQVE7UUFDaEIsVUFBSyxHQUFMLEtBQUssQ0FBUTtJQUM3QixDQUFDO0lBcENHLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQW1CLEVBQUUsU0FBaUI7UUFDL0QsSUFBSTtZQUNGLE1BQU0sUUFBUSxHQUFHLE1BQU0sR0FBRyxDQUFDLGNBQWMsQ0FBQyxFQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUMsQ0FBQyxDQUFBO1lBQ2pFLE9BQU8sSUFBSSxtQkFBbUIsQ0FBQyxHQUFHLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxNQUFNLElBQUksUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO1NBQ3RGO1FBQUMsT0FB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IFN0YWNrLFxuICBUYWcsXG4gIERlc2NyaWJlQ2hhbmdlU2V0T3V0cHV0LFxuICBQYXJhbWV0ZXIsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1jbG91ZGZvcm1hdGlvbidcbmltcG9ydCB7U3RhY2tTdGF0dXN9IGZyb20gJy4vc3RhY2stc3RhdHVzJ1xuaW1wb3J0ICogYXMgeWFtbCBmcm9tICcuL3lhbWwnXG5cbmV4cG9ydCB0eXBlIFRlbXBsYXRlID0ge1xuICBQYXJhbWV0ZXJzPzogUmVjb3JkPHN0cmluZywgVGVtcGxhdGVQYXJhbWV0ZXI+XG4gIFtrZXk6IHN0cmluZ106IGFueVxufVxuXG5pbnRlcmZhY2UgVGVtcGxhdGVQYXJhbWV0ZXIge1xuICBUeXBlOiBzdHJpbmdcbiAgRGVmYXVsdD86IGFueVxuICBba2V5OiBzdHJpbmddOiBhbnlcbn1cblxuLyoqXG4gKiBTdHJpbmdpZnkgdG8gWUFNTFxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9ZQU1MKG9iajogYW55KTogc3RyaW5nIHtcbiAgcmV0dXJuIHlhbWwuc2VyaWFsaXplKG9iailcbn1cblxuLyoqXG4gKiBQYXJzZSBlaXRoZXIgWUFNTCBvciBKU09OXG4gKi9cbmZ1bmN0aW9uIGRlc2VyaWFsaXplU3RydWN0dXJlKHN0cjogc3RyaW5nKTogYW55IHtcbiAgdHJ5IHtcbiAgICByZXR1cm4geWFtbC5kZXNlcmlhbGl6ZShzdHIpXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShzdHIpXG4gIH1cbn1cblxuLyoqXG4gKiBSZXByZXNlbnRzIGFuIChleGlzdGluZykgU3RhY2sgaW4gQ2xvdWRGb3JtYXRpb25cbiAqXG4gKiBCdW5kbGUgYW5kIGNhY2hlIHNvbWUgaW5mb3JtYXRpb24gdGhhdCB3ZSBuZWVkIGR1cmluZyBkZXBsb3ltZW50IChzbyB3ZSBkb24ndCBoYXZlIHRvIG1ha2VcbiAqIHJlcGVhdGVkIGNhbGxzIHRvIENsb3VkRm9ybWF0aW9uKS5cbiAqL1xuZXhwb3J0IGNsYXNzIENsb3VkRm9ybWF0aW9uU3RhY2sge1xuICBwdWJsaWMgc3RhdGljIGFzeW5jIGxvb2t1cChjZm46IENsb3VkRm9ybWF0aW9uLCBzdGFja05hbWU6IHN0cmluZyk6IFByb21pc2U8Q2xvdWRGb3JtYXRpb25TdGFjaz4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNmbi5kZXNjcmliZVN0YWNrcyh7U3RhY2tOYW1lOiBzdGFja05hbWV9KVxuICAgICAgcmV0dXJuIG5ldyBDbG91ZEZvcm1hdGlvblN0YWNrKGNmbiwgc3RhY2tOYW1lLCByZXNwb25zZS5TdGFja3MgJiYgcmVzcG9uc2UuU3RhY2tzWzBdKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgaWYgKGUubWVzc2FnZSA9PT0gYFN0YWNrIHdpdGggaWQgJHtzdGFja05hbWV9IGRvZXMgbm90IGV4aXN0YCkge1xuICAgICAgICAgIHJldHVybiBuZXcgQ2xvdWRGb3JtYXRpb25TdGFjayhjZm4sIHN0YWNrTmFtZSwgdW5kZWZpbmVkKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aHJvdyBlXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGNvcHkgb2YgdGhlIGdpdmVuIHN0YWNrIHRoYXQgZG9lcyBub3QgZXhpc3RcbiAgICpcbiAgICogSXQncyBhIGxpdHRsZSBzaWxseSB0aGF0IGl0IG5lZWRzIGFyZ3VtZW50cyB0byBkbyB0aGF0LCBidXQgdGhlcmUgd2UgZ28uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGRvZXNOb3RFeGlzdChjZm46IENsb3VkRm9ybWF0aW9uLCBzdGFja05hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBuZXcgQ2xvdWRGb3JtYXRpb25TdGFjayhjZm4sIHN0YWNrTmFtZSlcbiAgfVxuXG4gIC8qKlxuICAgKiBGcm9tIHN0YXRpYyBpbmZvcm1hdGlvbiAoZm9yIHRlc3RpbmcpXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZyb21TdGF0aWNJbmZvcm1hdGlvbihjZm46IENsb3VkRm9ybWF0aW9uLCBzdGFja05hbWU6IHN0cmluZywgc3RhY2s6IFN0YWNrKSB7XG4gICAgcmV0dXJuIG5ldyBDbG91ZEZvcm1hdGlvblN0YWNrKGNmbiwgc3RhY2tOYW1lLCBzdGFjaylcbiAgfVxuXG4gIHByaXZhdGUgX3RlbXBsYXRlOiBhbnlcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZm46IENsb3VkRm9ybWF0aW9uLFxuICAgIHB1YmxpYyByZWFkb25seSBzdGFja05hbWU6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHN0YWNrPzogU3RhY2ssXG4gICkge31cblxuICAvKipcbiAgICogUmV0cmlldmUgdGhlIHN0YWNrJ3MgZGVwbG95ZWQgdGVtcGxhdGVcbiAgICpcbiAgICogQ2FjaGVkLCBzbyB3aWxsIG9ubHkgYmUgcmV0cmlldmVkIG9uY2UuIFdpbGwgcmV0dXJuIGFuIGVtcHR5XG4gICAqIHN0cnVjdHVyZSBpZiB0aGUgc3RhY2sgZG9lcyBub3QgZXhpc3QuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgdGVtcGxhdGUoKTogUHJvbWlzZTxUZW1wbGF0ZT4ge1xuICAgIGlmICghdGhpcy5leGlzdHMpIHtcbiAgICAgIHJldHVybiB7fVxuICAgIH1cblxuICAgIGlmICh0aGlzLl90ZW1wbGF0ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuY2ZuLmdldFRlbXBsYXRlKHtcbiAgICAgICAgU3RhY2tOYW1lOiB0aGlzLnN0YWNrTmFtZSxcbiAgICAgICAgVGVtcGxhdGVTdGFnZTogJ09yaWdpbmFsJyxcbiAgICAgIH0pXG4gICAgICB0aGlzLl90ZW1wbGF0ZSA9IChyZXNwb25zZS5UZW1wbGF0ZUJvZHkgJiYgZGVzZXJpYWxpemVTdHJ1Y3R1cmUocmVzcG9uc2UuVGVtcGxhdGVCb2R5KSkgfHwge31cbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX3RlbXBsYXRlXG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0aGUgc3RhY2sgZXhpc3RzXG4gICAqL1xuICBwdWJsaWMgZ2V0IGV4aXN0cygpIHtcbiAgICByZXR1cm4gdGhpcy5zdGFjayAhPT0gdW5kZWZpbmVkXG4gIH1cblxuICAvKipcbiAgICogVGhlIHN0YWNrJ3MgSURcbiAgICpcbiAgICogVGhyb3dzIGlmIHRoZSBzdGFjayBkb2Vzbid0IGV4aXN0LlxuICAgKi9cbiAgcHVibGljIGdldCBzdGFja0lkKCkge1xuICAgIHRoaXMuYXNzZXJ0RXhpc3RzKClcbiAgICByZXR1cm4gdGhpcy5zdGFjayEuU3RhY2tJZCFcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgc3RhY2sncyBjdXJyZW50IG91dHB1dHNcbiAgICpcbiAgICogRW1wdHkgb2JqZWN0IGlmIHRoZSBzdGFjayBkb2Vzbid0IGV4aXN0XG4gICAqL1xuICBwdWJsaWMgZ2V0IG91dHB1dHMoKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgaWYgKCF0aGlzLmV4aXN0cykge1xuICAgICAgcmV0dXJuIHt9XG4gICAgfVxuICAgIGNvbnN0IHJlc3VsdDoge1tuYW1lOiBzdHJpbmddOiBzdHJpbmd9ID0ge31cbiAgICA7KHRoaXMuc3RhY2shLk91dHB1dHMgfHwgW10pLmZvckVhY2goKG91dHB1dCkgPT4ge1xuICAgICAgcmVzdWx0W291dHB1dC5PdXRwdXRLZXkhXSA9IG91dHB1dC5PdXRwdXRWYWx1ZSFcbiAgICB9KVxuICAgIHJldHVybiByZXN1bHRcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgc3RhY2sncyBzdGF0dXNcbiAgICpcbiAgICogU3BlY2lhbCBzdGF0dXMgTk9UX0ZPVU5EIGlmIHRoZSBzdGFjayBkb2VzIG5vdCBleGlzdC5cbiAgICovXG4gIHB1YmxpYyBnZXQgc3RhY2tTdGF0dXMoKTogU3RhY2tTdGF0dXMge1xuICAgIGlmICghdGhpcy5leGlzdHMpIHtcbiAgICAgIHJldHVybiBuZXcgU3RhY2tTdGF0dXMoJ05PVF9GT1VORCcsICdTdGFjayBub3QgZm91bmQgZHVyaW5nIGxvb2t1cCcpXG4gICAgfVxuICAgIHJldHVybiBTdGFja1N0YXR1cy5mcm9tU3RhY2tEZXNjcmlwdGlvbih0aGlzLnN0YWNrISlcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgc3RhY2sncyBjdXJyZW50IHRhZ3NcbiAgICpcbiAgICogRW1wdHkgbGlzdCBvZiB0aGUgc3RhY2sgZG9lcyBub3QgZXhpc3RcbiAgICovXG4gIHB1YmxpYyBnZXQgdGFncygpOiBUYWdbXSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhY2s/LlRhZ3MgfHwgW11cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIG5hbWVzIG9mIGFsbCBjdXJyZW50IHBhcmFtZXRlcnMgdG8gdGhlIHN0YWNrXG4gICAqXG4gICAqIEVtcHR5IGxpc3QgaWYgdGhlIHN0YWNrIGRvZXMgbm90IGV4aXN0LlxuICAgKi9cbiAgcHVibGljIGdldCBwYXJhbWV0ZXJOYW1lcygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMucGFyYW1ldGVycylcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIG5hbWVzIGFuZCB2YWx1ZXMgb2YgYWxsIGN1cnJlbnQgcGFyYW1ldGVycyB0byB0aGUgc3RhY2tcbiAgICpcbiAgICogRW1wdHkgb2JqZWN0IGlmIHRoZSBzdGFjayBkb2VzIG5vdCBleGlzdC5cbiAgICovXG4gIHB1YmxpYyBnZXQgcGFyYW1ldGVycygpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgICBpZiAoIXRoaXMuZXhpc3RzKSB7XG4gICAgICByZXR1cm4ge31cbiAgICB9XG4gICAgY29uc3QgcmV0OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge31cbiAgICBmb3IgKGNvbnN0IHBhcmFtIG9mIHRoaXMuc3RhY2shLlBhcmFtZXRlcnMgPz8gW10pIHtcbiAgICAgIHJldFtwYXJhbS5QYXJhbWV0ZXJLZXkhXSA9IHBhcmFtLlBhcmFtZXRlclZhbHVlIVxuICAgIH1cbiAgICByZXR1cm4gcmV0XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSB0ZXJtaW5hdGlvbiBwcm90ZWN0aW9uIG9mIHRoZSBzdGFja1xuICAgKi9cbiAgcHVibGljIGdldCB0ZXJtaW5hdGlvblByb3RlY3Rpb24oKTogYm9vbGVhbiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc3RhY2s/LkVuYWJsZVRlcm1pbmF0aW9uUHJvdGVjdGlvblxuICB9XG5cbiAgcHJpdmF0ZSBhc3NlcnRFeGlzdHMoKSB7XG4gICAgaWYgKCF0aGlzLmV4aXN0cykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBzdGFjayBuYW1lZCAnJHt0aGlzLnN0YWNrTmFtZX0nYClcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBEZXNjcmliZSBhIGNoYW5nZXNldCBpbiBDbG91ZEZvcm1hdGlvbiwgcmVnYXJkbGVzcyBvZiBpdHMgY3VycmVudCBzdGF0ZS5cbiAqXG4gKiBAcGFyYW0gY2ZuICAgICAgIGEgQ2xvdWRGb3JtYXRpb24gY2xpZW50XG4gKiBAcGFyYW0gc3RhY2tOYW1lICAgdGhlIG5hbWUgb2YgdGhlIFN0YWNrIHRoZSBDaGFuZ2VTZXQgYmVsb25ncyB0b1xuICogQHBhcmFtIGNoYW5nZVNldE5hbWUgdGhlIG5hbWUgb2YgdGhlIENoYW5nZVNldFxuICpcbiAqIEByZXR1cm5zICAgICAgIENsb3VkRm9ybWF0aW9uIGluZm9ybWF0aW9uIGFib3V0IHRoZSBDaGFuZ2VTZXRcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZGVzY3JpYmVDaGFuZ2VTZXQoXG4gIGNmbjogQ2xvdWRGb3JtYXRpb24sXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBjaGFuZ2VTZXROYW1lOiBzdHJpbmcsXG4pOiBQcm9taXNlPERlc2NyaWJlQ2hhbmdlU2V0T3V0cHV0PiB7XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2ZuLmRlc2NyaWJlQ2hhbmdlU2V0KHtTdGFja05hbWU6IHN0YWNrTmFtZSwgQ2hhbmdlU2V0TmFtZTogY2hhbmdlU2V0TmFtZX0pXG4gIHJldHVybiByZXNwb25zZVxufVxuXG4vKipcbiAqIFdhaXRzIGZvciBhIGZ1bmN0aW9uIHRvIHJldHVybiBub24tK3VuZGVmaW5lZCsgYmVmb3JlIHJldHVybmluZy5cbiAqXG4gKiBAcGFyYW0gdmFsdWVQcm92aWRlciBhIGZ1bmN0aW9uIHRoYXQgd2lsbCByZXR1cm4gYSB2YWx1ZSB0aGF0IGlzIG5vdCArdW5kZWZpbmVkKyBvbmNlIHRoZSB3YWl0IHNob3VsZCBiZSBvdmVyXG4gKiBAcGFyYW0gdGltZW91dCAgICAgdGhlIHRpbWUgdG8gd2FpdCBiZXR3ZWVuIHR3byBjYWxscyB0byArdmFsdWVQcm92aWRlcitcbiAqXG4gKiBAcmV0dXJucyAgICAgICB0aGUgdmFsdWUgdGhhdCB3YXMgcmV0dXJuZWQgYnkgK3ZhbHVlUHJvdmlkZXIrXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHdhaXRGb3I8VD4oXG4gIHZhbHVlUHJvdmlkZXI6ICgpID0+IFByb21pc2U8VCB8IG51bGwgfCB1bmRlZmluZWQ+LFxuICB0aW1lb3V0OiBudW1iZXIgPSA1MDAwLFxuKTogUHJvbWlzZTxUIHwgdW5kZWZpbmVkPiB7XG4gIHdoaWxlICh0cnVlKSB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdmFsdWVQcm92aWRlcigpXG4gICAgaWYgKHJlc3VsdCA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH0gZWxzZSBpZiAocmVzdWx0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiByZXN1bHRcbiAgICB9XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKGNiKSA9PiBzZXRUaW1lb3V0KGNiLCB0aW1lb3V0KSlcbiAgfVxufVxuXG4vKipcbiAqIFdhaXRzIGZvciBhIENoYW5nZVNldCB0byBiZSBhdmFpbGFibGUgZm9yIHRyaWdnZXJpbmcgYSBTdGFja1VwZGF0ZS5cbiAqXG4gKiBXaWxsIHJldHVybiBhIGNoYW5nZXNldCB0aGF0IGlzIGVpdGhlciByZWFkeSB0byBiZSBleGVjdXRlZCBvciBoYXMgbm8gY2hhbmdlcy5cbiAqIFdpbGwgdGhyb3cgaW4gb3RoZXIgY2FzZXMuXG4gKlxuICogQHBhcmFtIGNmbiAgICAgICBhIENsb3VkRm9ybWF0aW9uIGNsaWVudFxuICogQHBhcmFtIHN0YWNrTmFtZSAgIHRoZSBuYW1lIG9mIHRoZSBTdGFjayB0aGF0IHRoZSBDaGFuZ2VTZXQgYmVsb25ncyB0b1xuICogQHBhcmFtIGNoYW5nZVNldE5hbWUgdGhlIG5hbWUgb2YgdGhlIENoYW5nZVNldFxuICpcbiAqIEByZXR1cm5zICAgICAgIHRoZSBDbG91ZEZvcm1hdGlvbiBkZXNjcmlwdGlvbiBvZiB0aGUgQ2hhbmdlU2V0XG4gKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd2FpdEZvckNoYW5nZVNldChcbiAgY2ZuOiBDbG91ZEZvcm1hdGlvbixcbiAgc3RhY2tOYW1lOiBzdHJpbmcsXG4gIGNoYW5nZVNldE5hbWU6IHN0cmluZyxcbik6IFByb21pc2U8RGVzY3JpYmVDaGFuZ2VTZXRPdXRwdXQ+IHtcbiAgLy8gZGVidWcoJ1dhaXRpbmcgZm9yIGNoYW5nZXNldCAlcyBvbiBzdGFjayAlcyB0byBmaW5pc2ggY3JlYXRpbmcuLi4nLCBjaGFuZ2VTZXROYW1lLCBzdGFja05hbWUpXG4gIGNvbnN0IHJldCA9IGF3YWl0IHdhaXRGb3IoYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gYXdhaXQgZGVzY3JpYmVDaGFuZ2VTZXQoY2ZuLCBzdGFja05hbWUsIGNoYW5nZVNldE5hbWUpXG4gICAgLy8gVGhlIGZvbGxvd2luZyBkb2Vzbid0IHVzZSBhIHN3aXRjaCBiZWNhdXNlIHRzYyB3aWxsIG5vdCBhbGxvdyBmYWxsLXRocm91Z2gsIFVOTEVTUyBpdCBpcyBhbGxvd3NcbiAgICAvLyBFVkVSWVdIRVJFIHRoYXQgdXNlcyB0aGlzIGxpYnJhcnkgZGlyZWN0bHkgb3IgaW5kaXJlY3RseSwgd2hpY2ggaXMgdW5kZXNpcmFibGUuXG4gICAgaWYgKGRlc2NyaXB0aW9uLlN0YXR1cyA9PT0gJ0NSRUFURV9QRU5ESU5HJyB8fCBkZXNjcmlwdGlvbi5TdGF0dXMgPT09ICdDUkVBVEVfSU5fUFJPR1JFU1MnKSB7XG4gICAgICAvLyBkZWJ1ZygnQ2hhbmdlc2V0ICVzIG9uIHN0YWNrICVzIGlzIHN0aWxsIGNyZWF0aW5nJywgY2hhbmdlU2V0TmFtZSwgc3RhY2tOYW1lKVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH1cblxuICAgIGlmIChkZXNjcmlwdGlvbi5TdGF0dXMgPT09ICdDUkVBVEVfQ09NUExFVEUnIHx8IGNoYW5nZVNldEhhc05vQ2hhbmdlcyhkZXNjcmlwdGlvbikpIHtcbiAgICAgIHJldHVybiBkZXNjcmlwdGlvblxuICAgIH1cblxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEZhaWxlZCB0byBjcmVhdGUgQ2hhbmdlU2V0ICR7Y2hhbmdlU2V0TmFtZX0gb24gJHtzdGFja05hbWV9OiAke1xuICAgICAgICBkZXNjcmlwdGlvbi5TdGF0dXMgfHwgJ05PX1NUQVRVUydcbiAgICAgIH0sICR7ZGVzY3JpcHRpb24uU3RhdHVzUmVhc29uIHx8ICdubyByZWFzb24gcHJvdmlkZWQnfWAsXG4gICAgKVxuICB9KVxuXG4gIGlmICghcmV0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDaGFuZ2Ugc2V0IHRvb2sgdG9vIGxvbmcgdG8gYmUgY3JlYXRlZDsgYWJvcnRpbmcnKVxuICB9XG5cbiAgcmV0dXJuIHJldFxufVxuXG4vKipcbiAqIFJldHVybiB0cnVlIGlmIHRoZSBnaXZlbiBjaGFuZ2Ugc2V0IGhhcyBubyBjaGFuZ2VzXG4gKlxuICogVGhpcyBtdXN0IGJlIGRldGVybWluZWQgZnJvbSB0aGUgc3RhdHVzLCBub3QgdGhlICdDaGFuZ2VzJyBhcnJheSBvbiB0aGVcbiAqIG9iamVjdDsgdGhlIGxhdHRlciBjYW4gYmUgZW1wdHkgYmVjYXVzZSBubyByZXNvdXJjZXMgd2VyZSBjaGFuZ2VkLCBidXQgaWZcbiAqIHRoZXJlIGFyZSBjaGFuZ2VzIHRvIE91dHB1dHMsIHRoZSBjaGFuZ2Ugc2V0IGNhbiBzdGlsbCBiZSBleGVjdXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoYW5nZVNldEhhc05vQ2hhbmdlcyhkZXNjcmlwdGlvbjogRGVzY3JpYmVDaGFuZ2VTZXRPdXRwdXQpIHtcbiAgY29uc3Qgbm9DaGFuZ2VFcnJvclByZWZpeGVzID0gW1xuICAgIC8vIEVycm9yIG1lc3NhZ2UgZm9yIGEgcmVndWxhciB0ZW1wbGF0ZVxuICAgIFwiVGhlIHN1Ym1pdHRlZCBpbmZvcm1hdGlvbiBkaWRuJ3QgY29udGFpbiBjaGFuZ2VzLlwiLFxuICAgIC8vIEVycm9yIG1lc3NhZ2Ugd2hlbiBhIFRyYW5zZm9ybSBpcyBpbnZvbHZlZCAoc2VlICMxMDY1MClcbiAgICAnTm8gdXBkYXRlcyBhcmUgdG8gYmUgcGVyZm9ybWVkLicsXG4gIF1cblxuICByZXR1cm4gKFxuICAgIGRlc2NyaXB0aW9uLlN0YXR1cyA9PT0gJ0ZBSUxFRCcgJiZcbiAgICBub0NoYW5nZUVycm9yUHJlZml4ZXMuc29tZSgocCkgPT4gKGRlc2NyaXB0aW9uLlN0YXR1c1JlYXNvbiA/PyAnJykuc3RhcnRzV2l0aChwKSlcbiAgKVxufVxuXG4vKipcbiAqIFdhaXRzIGZvciBhIENsb3VkRm9ybWF0aW9uIHN0YWNrIHRvIHN0YWJpbGl6ZSBpbiBhIGNvbXBsZXRlL2F2YWlsYWJsZSBzdGF0ZVxuICogYWZ0ZXIgYSBkZWxldGUgb3BlcmF0aW9uIGlzIGlzc3VlZC5cbiAqXG4gKiBGYWlscyBpZiB0aGUgc3RhY2sgaXMgaW4gYSBGQUlMRUQgc3RhdGUuIFdpbGwgbm90IGZhaWwgaWYgdGhlIHN0YWNrIHdhc1xuICogYWxyZWFkeSBkZWxldGVkLlxuICpcbiAqIEBwYXJhbSBjZm4gICAgICAgIGEgQ2xvdWRGb3JtYXRpb24gY2xpZW50XG4gKiBAcGFyYW0gc3RhY2tOYW1lICAgICAgdGhlIG5hbWUgb2YgdGhlIHN0YWNrIHRvIHdhaXQgZm9yIGFmdGVyIGEgZGVsZXRlXG4gKlxuICogQHJldHVybnMgICAgIHRoZSBDbG91ZEZvcm1hdGlvbiBkZXNjcmlwdGlvbiBvZiB0aGUgc3RhYmlsaXplZCBzdGFjayBhZnRlciB0aGUgZGVsZXRlIGF0dGVtcHRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdhaXRGb3JTdGFja0RlbGV0ZShcbiAgY2ZuOiBDbG91ZEZvcm1hdGlvbixcbiAgc3RhY2tOYW1lOiBzdHJpbmcsXG4pOiBQcm9taXNlPENsb3VkRm9ybWF0aW9uU3RhY2sgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3Qgc3RhY2sgPSBhd2FpdCBzdGFiaWxpemVTdGFjayhjZm4sIHN0YWNrTmFtZSlcbiAgaWYgKCFzdGFjaykge1xuICAgIHJldHVybiB1bmRlZmluZWRcbiAgfVxuXG4gIGNvbnN0IHN0YXR1cyA9IHN0YWNrLnN0YWNrU3RhdHVzXG4gIGlmIChzdGF0dXMuaXNGYWlsdXJlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFRoZSBzdGFjayBuYW1lZCAke3N0YWNrTmFtZX0gaXMgaW4gYSBmYWlsZWQgc3RhdGUuIFlvdSBtYXkgbmVlZCB0byBkZWxldGUgaXQgZnJvbSB0aGUgQVdTIGNvbnNvbGUgOiAke3N0YXR1c31gLFxuICAgIClcbiAgfSBlbHNlIGlmIChzdGF0dXMuaXNEZWxldGVkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZFxuICB9XG4gIHJldHVybiBzdGFja1xufVxuXG4vKipcbiAqIFdhaXRzIGZvciBhIENsb3VkRm9ybWF0aW9uIHN0YWNrIHRvIHN0YWJpbGl6ZSBpbiBhIGNvbXBsZXRlL2F2YWlsYWJsZSBzdGF0ZVxuICogYWZ0ZXIgYW4gdXBkYXRlL2NyZWF0ZSBvcGVyYXRpb24gaXMgaXNzdWVkLlxuICpcbiAqIEZhaWxzIGlmIHRoZSBzdGFjayBpcyBpbiBhIEZBSUxFRCBzdGF0ZSwgUk9MTEJBQ0sgc3RhdGUsIG9yIERFTEVURUQgc3RhdGUuXG4gKlxuICogQHBhcmFtIGNmbiAgICAgICAgYSBDbG91ZEZvcm1hdGlvbiBjbGllbnRcbiAqIEBwYXJhbSBzdGFja05hbWUgICAgICB0aGUgbmFtZSBvZiB0aGUgc3RhY2sgdG8gd2FpdCBmb3IgYWZ0ZXIgYW4gdXBkYXRlXG4gKlxuICogQHJldHVybnMgICAgIHRoZSBDbG91ZEZvcm1hdGlvbiBkZXNjcmlwdGlvbiBvZiB0aGUgc3RhYmlsaXplZCBzdGFjayBhZnRlciB0aGUgdXBkYXRlIGF0dGVtcHRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdhaXRGb3JTdGFja0RlcGxveShcbiAgY2ZuOiBDbG91ZEZvcm1hdGlvbixcbiAgc3RhY2tOYW1lOiBzdHJpbmcsXG4pOiBQcm9taXNlPENsb3VkRm9ybWF0aW9uU3RhY2sgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3Qgc3RhY2sgPSBhd2FpdCBzdGFiaWxpemVTdGFjayhjZm4sIHN0YWNrTmFtZSlcbiAgaWYgKCFzdGFjaykge1xuICAgIHJldHVybiB1bmRlZmluZWRcbiAgfVxuXG4gIGNvbnN0IHN0YXR1cyA9IHN0YWNrLnN0YWNrU3RhdHVzXG5cbiAgaWYgKHN0YXR1cy5pc0NyZWF0aW9uRmFpbHVyZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBUaGUgc3RhY2sgbmFtZWQgJHtzdGFja05hbWV9IGZhaWxlZCBjcmVhdGlvbiwgaXQgbWF5IG5lZWQgdG8gYmUgbWFudWFsbHkgZGVsZXRlZCBmcm9tIHRoZSBBV1MgY29uc29sZTogJHtzdGF0dXN9YCxcbiAgICApXG4gIH0gZWxzZSBpZiAoIXN0YXR1cy5pc0RlcGxveVN1Y2Nlc3MpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSBzdGFjayBuYW1lZCAke3N0YWNrTmFtZX0gZmFpbGVkIHRvIGRlcGxveTogJHtzdGF0dXN9YClcbiAgfVxuXG4gIHJldHVybiBzdGFja1xufVxuXG4vKipcbiAqIFdhaXQgZm9yIGEgc3RhY2sgdG8gYmVjb21lIHN0YWJsZSAobm8gbG9uZ2VyIF9JTl9QUk9HUkVTUyksIHJldHVybmluZyBpdFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhYmlsaXplU3RhY2soY2ZuOiBDbG91ZEZvcm1hdGlvbiwgc3RhY2tOYW1lOiBzdHJpbmcpIHtcbiAgLy8gZGVidWcoJ1dhaXRpbmcgZm9yIHN0YWNrICVzIHRvIGZpbmlzaCBjcmVhdGluZyBvciB1cGRhdGluZy4uLicsIHN0YWNrTmFtZSlcbiAgcmV0dXJuIHdhaXRGb3IoYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHN0YWNrID0gYXdhaXQgQ2xvdWRGb3JtYXRpb25TdGFjay5sb29rdXAoY2ZuLCBzdGFja05hbWUpXG4gICAgaWYgKCFzdGFjay5leGlzdHMpIHtcbiAgICAgIC8vIGRlYnVnKCdTdGFjayAlcyBkb2VzIG5vdCBleGlzdCcsIHN0YWNrTmFtZSlcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICAgIGNvbnN0IHN0YXR1cyA9IHN0YWNrLnN0YWNrU3RhdHVzXG4gICAgaWYgKHN0YXR1cy5pc0luUHJvZ3Jlc3MpIHtcbiAgICAgIC8vIGRlYnVnKFxuICAgICAgLy8gICAnU3RhY2sgJXMgaGFzIGFuIG9uZ29pbmcgb3BlcmF0aW9uIGluIHByb2dyZXNzIGFuZCBpcyBub3Qgc3RhYmxlICglcyknLFxuICAgICAgLy8gICBzdGFja05hbWUsXG4gICAgICAvLyAgIHN0YXR1cyxcbiAgICAgIC8vIClcbiAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICB9XG5cbiAgICByZXR1cm4gc3RhY2tcbiAgfSlcbn1cblxuLyoqXG4gKiBUaGUgc2V0IG9mIChmb3JtYWwpIHBhcmFtZXRlcnMgdGhhdCBoYXZlIGJlZW4gZGVjbGFyZWQgaW4gYSB0ZW1wbGF0ZVxuICovXG5leHBvcnQgY2xhc3MgVGVtcGxhdGVQYXJhbWV0ZXJzIHtcbiAgcHVibGljIHN0YXRpYyBmcm9tVGVtcGxhdGUodGVtcGxhdGU6IFRlbXBsYXRlKSB7XG4gICAgcmV0dXJuIG5ldyBUZW1wbGF0ZVBhcmFtZXRlcnModGVtcGxhdGUuUGFyYW1ldGVycyB8fCB7fSlcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgcGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBUZW1wbGF0ZVBhcmFtZXRlcj4pIHt9XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZSBzdGFjayBwYXJhbWV0ZXJzIHRvIHBhc3MgZnJvbSB0aGUgZ2l2ZW4gZGVzaXJlZCBwYXJhbWV0ZXIgdmFsdWVzXG4gICAqXG4gICAqIFdpbGwgdGhyb3cgaWYgcGFyYW1ldGVycyB3aXRob3V0IGEgRGVmYXVsdCB2YWx1ZSBvciBhIFByZXZpb3VzIHZhbHVlIGFyZSBub3RcbiAgICogc3VwcGxpZWQuXG4gICAqL1xuICBwdWJsaWMgc3VwcGx5QWxsKHVwZGF0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD4pOiBQYXJhbWV0ZXJWYWx1ZXMge1xuICAgIHJldHVybiBuZXcgUGFyYW1ldGVyVmFsdWVzKHRoaXMucGFyYW1zLCB1cGRhdGVzKVxuICB9XG5cbiAgLyoqXG4gICAqIEZyb20gdGhlIHRlbXBsYXRlLCB0aGUgZ2l2ZW4gZGVzaXJlZCB2YWx1ZXMgYW5kIHRoZSBjdXJyZW50IHZhbHVlcywgY2FsY3VsYXRlIHRoZSBjaGFuZ2VzIHRvIHRoZSBzdGFjayBwYXJhbWV0ZXJzXG4gICAqXG4gICAqIFdpbGwgdGFrZSBpbnRvIGFjY291bnQgcGFyYW1ldGVycyBhbHJlYWR5IHNldCBvbiB0aGUgdGVtcGxhdGUgKHdpbGwgZW1pdFxuICAgKiAnVXNlUHJldmlvdXNWYWx1ZTogdHJ1ZScgZm9yIHRob3NlIHVubGVzcyB0aGUgdmFsdWUgaXMgY2hhbmdlZCksIGFuZCB3aWxsXG4gICAqIHRocm93IGlmIHBhcmFtZXRlcnMgd2l0aG91dCBhIERlZmF1bHQgdmFsdWUgb3IgYSBQcmV2aW91cyB2YWx1ZSBhcmUgbm90XG4gICAqIHN1cHBsaWVkLlxuICAgKi9cbiAgcHVibGljIHVwZGF0ZUV4aXN0aW5nKFxuICAgIHVwZGF0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD4sXG4gICAgcHJldmlvdXNWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4sXG4gICk6IFBhcmFtZXRlclZhbHVlcyB7XG4gICAgcmV0dXJuIG5ldyBQYXJhbWV0ZXJWYWx1ZXModGhpcy5wYXJhbXMsIHVwZGF0ZXMsIHByZXZpb3VzVmFsdWVzKVxuICB9XG59XG5cbi8qKlxuICogVGhlIHNldCBvZiBwYXJhbWV0ZXJzIHdlJ3JlIGdvaW5nIHRvIHBhc3MgdG8gYSBTdGFja1xuICovXG5leHBvcnQgY2xhc3MgUGFyYW1ldGVyVmFsdWVzIHtcbiAgcHVibGljIHJlYWRvbmx5IHZhbHVlczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9XG4gIHB1YmxpYyByZWFkb25seSBhcGlQYXJhbWV0ZXJzOiBQYXJhbWV0ZXJbXSA9IFtdXG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBmb3JtYWxQYXJhbXM6IFJlY29yZDxzdHJpbmcsIFRlbXBsYXRlUGFyYW1ldGVyPixcbiAgICB1cGRhdGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+LFxuICAgIHByZXZpb3VzVmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge30sXG4gICkge1xuICAgIGNvbnN0IG1pc3NpbmdSZXF1aXJlZCA9IG5ldyBBcnJheTxzdHJpbmc+KClcblxuICAgIGZvciAoY29uc3QgW2tleSwgZm9ybWFsUGFyYW1dIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuZm9ybWFsUGFyYW1zKSkge1xuICAgICAgLy8gQ2hlY2sgdXBkYXRlcyBmaXJzdCwgdGhlbiB1c2UgdGhlIHByZXZpb3VzIHZhbHVlIChpZiBhdmFpbGFibGUpLCB0aGVuIHVzZVxuICAgICAgLy8gdGhlIGRlZmF1bHQgKGlmIGF2YWlsYWJsZSkuXG4gICAgICAvL1xuICAgICAgLy8gSWYgd2UgZG9uJ3QgZmluZCBhIHBhcmFtZXRlciB2YWx1ZSB1c2luZyBhbnkgb2YgdGhlc2UgbWV0aG9kcywgdGhlbiB0aGF0J3MgYW4gZXJyb3IuXG4gICAgICBjb25zdCB1cGRhdGVkVmFsdWUgPSB1cGRhdGVzW2tleV1cbiAgICAgIGlmICh1cGRhdGVkVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLnZhbHVlc1trZXldID0gdXBkYXRlZFZhbHVlXG4gICAgICAgIHRoaXMuYXBpUGFyYW1ldGVycy5wdXNoKHtQYXJhbWV0ZXJLZXk6IGtleSwgUGFyYW1ldGVyVmFsdWU6IHVwZGF0ZXNba2V5XX0pXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGlmIChrZXkgaW4gcHJldmlvdXNWYWx1ZXMpIHtcbiAgICAgICAgdGhpcy52YWx1ZXNba2V5XSA9IHByZXZpb3VzVmFsdWVzW2tleV1cbiAgICAgICAgdGhpcy5hcGlQYXJhbWV0ZXJzLnB1c2goe1BhcmFtZXRlcktleToga2V5LCBVc2VQcmV2aW91c1ZhbHVlOiB0cnVlfSlcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgaWYgKGZvcm1hbFBhcmFtLkRlZmF1bHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLnZhbHVlc1trZXldID0gZm9ybWFsUGFyYW0uRGVmYXVsdFxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyBPaCBub1xuICAgICAgbWlzc2luZ1JlcXVpcmVkLnB1c2goa2V5KVxuICAgIH1cblxuICAgIGlmIChtaXNzaW5nUmVxdWlyZWQubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgVGhlIGZvbGxvd2luZyBDbG91ZEZvcm1hdGlvbiBQYXJhbWV0ZXJzIGFyZSBtaXNzaW5nIGEgdmFsdWU6ICR7bWlzc2luZ1JlcXVpcmVkLmpvaW4oXG4gICAgICAgICAgJywgJyxcbiAgICAgICAgKX1gLFxuICAgICAgKVxuICAgIH1cblxuICAgIC8vIEp1c3QgYXBwZW5kIGFsbCBzdXBwbGllZCBvdmVycmlkZXMgdGhhdCBhcmVuJ3QgcmVhbGx5IGV4cGVjdGVkICh0aGlzXG4gICAgLy8gd2lsbCBmYWlsIENGTiBidXQgbWF5YmUgcGVvcGxlIG1hZGUgdHlwb3MgdGhhdCB0aGV5IHdhbnQgdG8gYmUgbm90aWZpZWRcbiAgICAvLyBvZilcbiAgICBjb25zdCB1bmtub3duUGFyYW0gPSAoW2tleSwgX106IFtzdHJpbmcsIGFueV0pID0+IHRoaXMuZm9ybWFsUGFyYW1zW2tleV0gPT09IHVuZGVmaW5lZFxuICAgIGNvbnN0IGhhc1ZhbHVlID0gKFtfLCB2YWx1ZV06IFtzdHJpbmcsIGFueV0pID0+ICEhdmFsdWVcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh1cGRhdGVzKS5maWx0ZXIodW5rbm93blBhcmFtKS5maWx0ZXIoaGFzVmFsdWUpKSB7XG4gICAgICB0aGlzLnZhbHVlc1trZXldID0gdmFsdWUhXG4gICAgICB0aGlzLmFwaVBhcmFtZXRlcnMucHVzaCh7UGFyYW1ldGVyS2V5OiBrZXksIFBhcmFtZXRlclZhbHVlOiB2YWx1ZX0pXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhpcyBzZXQgb2YgcGFyYW1ldGVyIHVwZGF0ZXMgd2lsbCBjaGFuZ2UgdGhlIGFjdHVhbCBzdGFjayB2YWx1ZXNcbiAgICovXG4gIHB1YmxpYyBoYXNDaGFuZ2VzKGN1cnJlbnRWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4pOiBib29sZWFuIHtcbiAgICAvLyBJZiBhbnkgb2YgdGhlIHBhcmFtZXRlcnMgYXJlIFNTTSBwYXJhbWV0ZXJzLCBkZXBsb3lpbmcgbXVzdCBhbHdheXMgaGFwcGVuXG4gICAgLy8gYmVjYXVzZSB3ZSBjYW4ndCBwcmVkaWN0IHdoYXQgdGhlIHZhbHVlcyB3aWxsIGJlLlxuICAgIGlmIChPYmplY3QudmFsdWVzKHRoaXMuZm9ybWFsUGFyYW1zKS5zb21lKChwKSA9PiBwLlR5cGUuc3RhcnRzV2l0aCgnQVdTOjpTU006OlBhcmFtZXRlcjo6JykpKSB7XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cblxuICAgIC8vIE90aGVyd2lzZSB3ZSdyZSBkaXJ0eSBpZjpcbiAgICAvLyAtIGFueSBvZiB0aGUgZXhpc3RpbmcgdmFsdWVzIGFyZSByZW1vdmVkLCBvciBjaGFuZ2VkXG4gICAgaWYgKFxuICAgICAgT2JqZWN0LmVudHJpZXMoY3VycmVudFZhbHVlcykuc29tZShcbiAgICAgICAgKFtrZXksIHZhbHVlXSkgPT4gIShrZXkgaW4gdGhpcy52YWx1ZXMpIHx8IHZhbHVlICE9PSB0aGlzLnZhbHVlc1trZXldLFxuICAgICAgKVxuICAgICkge1xuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG5cbiAgICAvLyAtIGFueSBvZiB0aGUgdmFsdWVzIHdlJ3JlIHNldHRpbmcgYXJlIG5ld1xuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLnZhbHVlcykuc29tZSgoa2V5KSA9PiAhKGtleSBpbiBjdXJyZW50VmFsdWVzKSkpIHtcbiAgICAgIHJldHVybiB0cnVlXG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cbn1cbiJdfQ==