ness
Version:
✪ No-effort static sites deployed to your AWS account.
452 lines • 49.6 kB
JavaScript
"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==