@cdklabs/cdk-hyperledger-fabric-network
Version:
CDK construct to deploy a Hyperledger Fabric network running on Amazon Managed Blockchain
234 lines • 45.4 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HyperledgerFabricNetwork = exports.ThresholdComparator = exports.NetworkEdition = exports.FrameworkVersion = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT-0
const cdk = require("aws-cdk-lib");
const managedblockchain = require("aws-cdk-lib/aws-managedblockchain");
const secretsmanager = require("aws-cdk-lib/aws-secretsmanager");
const customresources = require("aws-cdk-lib/custom-resources");
const constructs = require("constructs");
const client = require("./client");
const identity = require("./identity");
const node = require("./node");
const user = require("./user");
const utilities = require("./utilities");
/**
* Define which Hyperledger Fabric framework to use
*/
var FrameworkVersion;
(function (FrameworkVersion) {
FrameworkVersion["VERSION_1_2"] = "1.2";
FrameworkVersion["VERSION_1_4"] = "1.4";
FrameworkVersion["VERSION_2_2"] = "2.2";
})(FrameworkVersion || (exports.FrameworkVersion = FrameworkVersion = {}));
/**
* Starter networks are cheaper, but are limited to 2 nodes that
* can only be from a subset of types (see node.ts for the list)
*/
var NetworkEdition;
(function (NetworkEdition) {
NetworkEdition["STARTER"] = "STARTER";
NetworkEdition["STANDARD"] = "STANDARD";
})(NetworkEdition || (exports.NetworkEdition = NetworkEdition = {}));
/**
* Constants to define ties in voting for new members
*/
var ThresholdComparator;
(function (ThresholdComparator) {
ThresholdComparator["GREATER_THAN"] = "GREATER_THAN";
ThresholdComparator["GREATER_THAN_OR_EQUAL_TO"] = "GREATER_THAN_OR_EQUAL_TO";
})(ThresholdComparator || (exports.ThresholdComparator = ThresholdComparator = {}));
/**
* Creates a Hyperledger Fabric network on Amazon Managed Blockchain
*/
class HyperledgerFabricNetwork extends constructs.Construct {
constructor(scope, id, props) {
super(scope, id);
// Collect metadata on the stack
const partition = cdk.Stack.of(this).partition;
const region = cdk.Stack.of(this).region;
const account = cdk.Stack.of(this).account;
// Populate instance variables from input properties, using defaults if values not provided
this.networkName = props.networkName;
this.networkDescription = props.networkDescription ?? props.networkName;
this.memberName = props.memberName;
this.memberDescription = props.memberDescription ?? props.memberName;
this.frameworkVersion = props.frameworkVersion ?? FrameworkVersion.VERSION_1_4;
this.networkEdition = props.networkEdition ?? NetworkEdition.STANDARD;
this.proposalDurationInHours = props.proposalDurationInHours ?? 24;
this.thresholdPercentage = props.thresholdPercentage ?? 50;
this.thresholdComparator = props.thresholdComparator ?? ThresholdComparator.GREATER_THAN;
this.enableCaLogging = props.enableCaLogging ?? true;
this.enrollAdmin = props.enrollAdmin ?? true;
this.users = [];
// Ensure the parameters captured above are valid, so we don't
// need to wait until deployment time to discover an error
utilities.validateRegion(region);
if (!utilities.validateString(this.networkName, 1, 64)) {
throw new Error('Network name is invalid or not provided. It can be up to 64 characters long.');
}
if (!utilities.validateString(this.networkDescription, 0, 128)) {
throw new Error('Network description is invalid. It can be up to 128 characters long.');
}
if (!utilities.validateString(this.memberName, 1, 64, /^(?!-|[0-9])(?!.*-$)(?!.*?--)[a-zA-Z0-9-]+$/)) {
throw new Error('Member name is invalid or not provided. It can be up to 64 characters long, and can have alphanumeric characters and hyphen(s). It cannot start with a number, or start and end with a hyphen (-), or have two consecutive hyphens. The member name must also be unique across the network.');
}
if (!utilities.validateString(this.memberDescription, 0, 128)) {
throw new Error('Member description is invalid. It can be up to 128 characters long.');
}
if (!utilities.validateInteger(this.proposalDurationInHours, 1, 168)) {
throw new Error('Voting policy proposal duration must be between 1 and 168 hours.');
}
if (!utilities.validateInteger(this.thresholdPercentage, 0, 100)) {
throw new Error('Voting policy threshold percentage must be between 0 and 100.');
}
// Ensure the users property is not defined,
// if the enrollAdmin property is disabled
if (!this.enrollAdmin && props.users) {
throw new Error('Enroll admin property has to be enabled for registering users');
}
// Ensure the user affiliation includes the member name,
// if the user list for registration is provided
if (props.users) {
props.users.forEach(e => {
if (!e.affilitation.startsWith(this.memberName))
throw new Error('User affiliation is invalid. Affiliation should start with Member name');
});
}
// Per the Managed Blockchain documentation, the admin password must be at least eight
// characters long and no more than 32 characters. It must contain at least one uppercase
// letter, one lowercase letter, and one digit. It cannot have a single quotation mark (‘),
// a double quotation marks (“), a forward slash(/), a backward slash(\), @, or a space;
// several other characters are exluded here to make the password easier to use in scripts
const passwordRequirements = {
passwordLength: 32,
requireEachIncludedType: true,
excludeCharacters: '\'"/\\@ &{}<>*|',
};
this.adminPasswordSecret = new secretsmanager.Secret(this, 'AdminPassword', { generateSecretString: passwordRequirements });
// The initially enrolled admin user credentials will be stored in these secrets
this.adminPrivateKeySecret = new secretsmanager.Secret(this, 'AdminPrivateKey');
this.adminSignedCertSecret = new secretsmanager.Secret(this, 'AdminSignedCert');
// Build out the Cloudformation construct for the network/member
const networkConfiguration = {
name: this.networkName,
description: this.networkDescription,
framework: 'HYPERLEDGER_FABRIC',
frameworkVersion: this.frameworkVersion,
networkFrameworkConfiguration: {
networkFabricConfiguration: {
edition: this.networkEdition,
},
},
votingPolicy: {
approvalThresholdPolicy: {
proposalDurationInHours: this.proposalDurationInHours,
thresholdPercentage: this.thresholdPercentage,
thresholdComparator: this.thresholdComparator,
},
},
};
// Note the use of the unwrap below is the only possible way to get
// the secret value into the CloudFormation; it will still not directly
// be included in the synthesized template so usage here is still safe
const memberConfiguration = {
name: this.memberName,
description: this.memberDescription,
memberFrameworkConfiguration: {
memberFabricConfiguration: {
adminUsername: 'admin',
adminPassword: this.adminPasswordSecret.secretValue.unsafeUnwrap(),
},
},
};
const network = new managedblockchain.CfnMember(this, 'Network', { networkConfiguration, memberConfiguration });
// Capture data included in the Cloudformation output in instance variables
this.networkId = network.getAtt('NetworkId').toString();
this.memberId = network.getAtt('MemberId').toString();
// Build out the associated node constructs
this.nodes = node.HyperledgerFabricNode.constructNodes(this, props.nodes);
// Due to a race condition in CDK custom resources (https://github.com/aws/aws-cdk/issues/18237),
// the necessary permissions for all SDK calls in the stack need to be added here, even though
// the calls in this construct don't need access to the nodes; this also means node constructs
// can't populate their outputs fully until later, which is annoying
const nodeIds = this.nodes.map(n => n.nodeId);
const nodeArns = nodeIds.map(i => `arn:${partition}:managedblockchain:${region}:${account}:nodes/${i}`);
const sdkCallPolicy = customresources.AwsCustomResourcePolicy.fromSdkCalls({
resources: [
`arn:${partition}:managedblockchain:${region}::networks/${this.networkId}`,
`arn:${partition}:managedblockchain:${region}:${account}:members/${this.memberId}`,
...nodeArns,
],
});
// Cloudformation doesn't include all the network and member attributes
// needed to use Hyperledger Fabric, so use SDK calls to fetch said data
const networkDataSdkCall = {
service: 'ManagedBlockchain',
action: 'getNetwork',
parameters: { NetworkId: this.networkId },
physicalResourceId: customresources.PhysicalResourceId.of('Id'),
};
const memberDataSdkCall = {
service: 'ManagedBlockchain',
action: 'getMember',
parameters: { NetworkId: this.networkId, MemberId: this.memberId },
physicalResourceId: customresources.PhysicalResourceId.of('Id'),
};
// Data items need fetching on creation and updating; nothing needs doing on deletion
const networkData = new customresources.AwsCustomResource(this, 'NetworkDataResource', {
policy: sdkCallPolicy,
onCreate: networkDataSdkCall,
onUpdate: networkDataSdkCall,
});
const memberData = new customresources.AwsCustomResource(this, 'MemberDataResource', {
policy: sdkCallPolicy,
onCreate: memberDataSdkCall,
onUpdate: memberDataSdkCall,
});
// Cloudformation doesn't include logging configuration so use SDK call to do so
const logConfiguration = {
Fabric: { CaLogs: { Cloudwatch: { Enabled: this.enableCaLogging } } },
};
const configureCaLogSdkCall = {
service: 'ManagedBlockchain',
action: 'updateMember',
parameters: { NetworkId: this.networkId, MemberId: this.memberId, LogPublishingConfiguration: logConfiguration },
physicalResourceId: customresources.PhysicalResourceId.of('Id'),
};
new customresources.AwsCustomResource(this, 'ConfigureCaLogResource', {
policy: sdkCallPolicy,
onCreate: configureCaLogSdkCall,
onUpdate: configureCaLogSdkCall,
});
// Grab items out of the above return values and stick them in output properties
this.vpcEndpointServiceName = networkData.getResponseField('Network.VpcEndpointServiceName');
this.ordererEndpoint = networkData.getResponseField('Network.FrameworkAttributes.Fabric.OrderingServiceEndpoint');
this.caEndpoint = memberData.getResponseField('Member.FrameworkAttributes.Fabric.CaEndpoint');
// As stated earlier, node constructs can't populate all their properties
// until after the above network and member SDK calls succeed; thus the
// function calls below where fetches are split out and logging is configured
for (const n of this.nodes) {
n.configureLogging(sdkCallPolicy);
n.fetchData(sdkCallPolicy);
}
// Build out the client VPC construct
this.client = new client.HyperledgerFabricClient(this, 'NetworkClient', props.client);
// Enroll admin and users, if enabled
if (this.enrollAdmin) {
// Build out all the custom resources to register and enroll identities to CA
const identityResources = new identity.HyperledgerFabricIdentity(this, 'Identity');
// Enroll the administrator and store its credentials on Secrets Manager
new cdk.CustomResource(this, 'AdminCustomResource', { serviceToken: identityResources.adminProvider.serviceToken });
// Register and enroll users, if provided
if (props.users)
this.users = Array.from(props.users.entries()).map(e => new user.HyperledgerFabricUser(this, `User${e[0]}`, e[1]));
}
}
}
exports.HyperledgerFabricNetwork = HyperledgerFabricNetwork;
_a = JSII_RTTI_SYMBOL_1;
HyperledgerFabricNetwork[_a] = { fqn: "@cdklabs/cdk-hyperledger-fabric-network.HyperledgerFabricNetwork", version: "0.8.918" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29yay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9uZXR3b3JrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEscUVBQXFFO0FBQ3JFLGlDQUFpQztBQUdqQyxtQ0FBbUM7QUFDbkMsdUVBQXVFO0FBQ3ZFLGlFQUFpRTtBQUNqRSxnRUFBZ0U7QUFDaEUseUNBQXlDO0FBRXpDLG1DQUFtQztBQUNuQyx1Q0FBdUM7QUFDdkMsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQix5Q0FBeUM7QUFHekM7O0dBRUc7QUFDSCxJQUFZLGdCQUlYO0FBSkQsV0FBWSxnQkFBZ0I7SUFDMUIsdUNBQW1CLENBQUE7SUFDbkIsdUNBQW1CLENBQUE7SUFDbkIsdUNBQW1CLENBQUE7QUFDckIsQ0FBQyxFQUpXLGdCQUFnQixnQ0FBaEIsZ0JBQWdCLFFBSTNCO0FBRUQ7OztHQUdHO0FBQ0gsSUFBWSxjQUdYO0FBSEQsV0FBWSxjQUFjO0lBQ3hCLHFDQUFtQixDQUFBO0lBQ25CLHVDQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFIVyxjQUFjLDhCQUFkLGNBQWMsUUFHekI7QUFFRDs7R0FFRztBQUNILElBQVksbUJBR1g7QUFIRCxXQUFZLG1CQUFtQjtJQUM3QixvREFBNkIsQ0FBQTtJQUM3Qiw0RUFBcUQsQ0FBQTtBQUN2RCxDQUFDLEVBSFcsbUJBQW1CLG1DQUFuQixtQkFBbUIsUUFHOUI7QUFvR0Q7O0dBRUc7QUFDSCxNQUFhLHdCQUF5QixTQUFRLFVBQVUsQ0FBQyxTQUFTO0lBa0hoRSxZQUFZLEtBQTJCLEVBQUUsRUFBVSxFQUFFLEtBQW9DO1FBRXZGLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsZ0NBQWdDO1FBQ2hDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUMvQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsS0FBSyxD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LENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0SSxDQUFDO0lBRUgsQ0FBQzs7QUE1VEgsNERBOFRDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlULTBcblxuXG5pbXBvcnQgKiBhcyBjZGsgZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgbWFuYWdlZGJsb2NrY2hhaW4gZnJvbSAnYXdzLWNkay1saWIvYXdzLW1hbmFnZWRibG9ja2NoYWluJztcbmltcG9ydCAqIGFzIHNlY3JldHNtYW5hZ2VyIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zZWNyZXRzbWFuYWdlcic7XG5pbXBvcnQgKiBhcyBjdXN0b21yZXNvdXJjZXMgZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgKiBhcyBjb25zdHJ1Y3RzIGZyb20gJ2NvbnN0cnVjdHMnO1xuXG5pbXBvcnQgKiBhcyBjbGllbnQgZnJvbSAnLi9jbGllbnQnO1xuaW1wb3J0ICogYXMgaWRlbnRpdHkgZnJvbSAnLi9pZGVudGl0eSc7XG5pbXBvcnQgKiBhcyBub2RlIGZyb20gJy4vbm9kZSc7XG5pbXBvcnQgKiBhcyB1c2VyIGZyb20gJy4vdXNlcic7XG5pbXBvcnQgKiBhcyB1dGlsaXRpZXMgZnJvbSAnLi91dGlsaXRpZXMnO1xuXG5cbi8qKlxuICogRGVmaW5lIHdoaWNoIEh5cGVybGVkZ2VyIEZhYnJpYyBmcmFtZXdvcmsgdG8gdXNlXG4gKi9cbmV4cG9ydCBlbnVtIEZyYW1ld29ya1ZlcnNpb24ge1xuICBWRVJTSU9OXzFfMiA9ICcxLjInLFxuICBWRVJTSU9OXzFfNCA9ICcxLjQnLFxuICBWRVJTSU9OXzJfMiA9ICcyLjInLFxufVxuXG4vKipcbiAqIFN0YXJ0ZXIgbmV0d29ya3MgYXJlIGNoZWFwZXIsIGJ1dCBhcmUgbGltaXRlZCB0byAyIG5vZGVzIHRoYXRcbiAqIGNhbiBvbmx5IGJlIGZyb20gYSBzdWJzZXQgb2YgdHlwZXMgKHNlZSBub2RlLnRzIGZvciB0aGUgbGlzdClcbiAqL1xuZXhwb3J0IGVudW0gTmV0d29ya0VkaXRpb24ge1xuICBTVEFSVEVSID0gJ1NUQVJURVInLFxuICBTVEFOREFSRCA9ICdTVEFOREFSRCcsXG59XG5cbi8qKlxuICogQ29uc3RhbnRzIHRvIGRlZmluZSB0aWVzIGluIHZvdGluZyBmb3IgbmV3IG1lbWJlcnNcbiAqL1xuZXhwb3J0IGVudW0gVGhyZXNob2xkQ29tcGFyYXRvciB7XG4gIEdSRUFURVJfVEhBTiA9ICdHUkVBVEVSX1RIQU4nLFxuICBHUkVBVEVSX1RIQU5fT1JfRVFVQUxfVE8gPSAnR1JFQVRFUl9USEFOX09SX0VRVUFMX1RPJyxcbn1cblxuXG4vKipcbiAqIENvbnN0cnVjdCBwcm9wZXJ0aWVzIGZvciBgSHlwZXJsZWRnZXJGYWJyaWNOZXR3b3JrYFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEh5cGVybGVkZ2VyRmFicmljTmV0d29ya1Byb3BzIHtcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG5ldHdvcmsgbmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgbmV0d29ya05hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG5ldHdvcmsgZGVzY3JpcHRpb25cbiAgICpcbiAgICogQGRlZmF1bHQgLSBTZXQgdG8gbWF0Y2ggbmV0d29yayBuYW1lXG4gICAqL1xuICByZWFkb25seSBuZXR3b3JrRGVzY3JpcHRpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBtZW1iZXIgbmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgbWVtYmVyTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbWVtYmVyIGRlc2NyaXB0aW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gU2V0IHRvIG1hdGNoIG1lbWJlciBuYW1lXG4gICAqL1xuICByZWFkb25seSBtZW1iZXJEZXNjcmlwdGlvbj86IHN0cmluZztcblxuICAvKipcbiAgICogSHlwZXJsZWRnZXIgRmFicmljIGZyYW1ld29yayB2ZXJzaW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRnJhbWV3b3JrVmVyc2lvbi5WRVJTSU9OXzFfNFxuICAgKi9cbiAgcmVhZG9ubHkgZnJhbWV3b3JrVmVyc2lvbj86IEZyYW1ld29ya1ZlcnNpb247XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIGVkaXRpb25cbiAgICpcbiAgICogQGRlZmF1bHQgLSBOZXR3b3JrRWRpdGlvbi5TVEFOREFSRFxuICAgKi9cbiAgcmVhZG9ubHkgbmV0d29ya0VkaXRpb24/OiBOZXR3b3JrRWRpdGlvbjtcblxuICAvKipcbiAgICogVGhlIGR1cmF0aW9uIGZyb20gdGhlIHRpbWUgdGhhdCBhIHByb3Bvc2FsIGlzIGNyZWF0ZWQgdW50aWwgaXQgZXhwaXJlc1xuICAgKiBAZGVmYXVsdCAtIDI0IGhvdXJzXG4gICAqL1xuICByZWFkb25seSBwcm9wb3NhbER1cmF0aW9uSW5Ib3Vycz86IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIHBlcmNlbnRhZ2Ugb2Ygdm90ZXMgYW1vbmcgYWxsIG1lbWJlcnMgdGhhdCBtdXN0IGJlIHllcyBmb3IgYSBwcm9wb3NhbCB0byBiZSBhcHByb3ZlZFxuICAgKiBAZGVmYXVsdCAtIDUwIHBlcmNlbnRcbiAgICovXG4gIHJlYWRvbmx5IHRocmVzaG9sZFBlcmNlbnRhZ2U/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgd2hldGhlciB0aGUgeWVzIHZvdGVzIG11c3QgYmUgZ3JlYXRlciB0aGFuIHRoZSB0aHJlc2hvbGQgcGVyY2VudGFnZVxuICAgKiBvciBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB0aGUgdGhyZWhvbGQgcGVyY2VudGFnZSB0byBiZSBhcHByb3ZlZFxuICAgKiBAZGVmYXVsdCAtIEdSRUFURVJfVEhBTlxuICAgKi9cbiAgcmVhZG9ubHkgdGhyZXNob2xkQ29tcGFyYXRvcj86IFRocmVzaG9sZENvbXBhcmF0b3I7XG5cbiAgLyoqXG4gICAqIFRoZSBjb25maWd1cmF0aW9uIHRvIGVuYWJsZSBvciBkaXNhYmxlIGNlcnRpZmljYXRlIGF1dGhvcml0eSBsb2dnaW5nXG4gICAqIEBkZWZhdWx0IC0gdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgZW5hYmxlQ2FMb2dnaW5nPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogTGlzdCBvZiBub2RlcyB0byBjcmVhdGUgb24gdGhlIG5ldHdvcmtcbiAgICpcbiAgICogQGRlZmF1bHQgLSBPbmUgbm9kZSB3aXRoIGRlZmF1bHQgY29uZmlndXJhdGlvblxuICAgKi9cbiAgcmVhZG9ubHkgbm9kZXM/OiBBcnJheTxub2RlLkh5cGVybGVkZ2VyRmFicmljTm9kZVByb3BzPjtcblxuICAvKipcbiAgICogVGhlIENsaWVudCBuZXR3b3JrIHRvIGludGVyYWN0IHdpdGggdGhlIEh5cGVybGVkZ2VyIEZhYnJpYyBuZXR3b3JrXG4gICAqIEBkZWZhdWx0IC0gQ2xpZW50IG5ldHdvcmsgd2l0aCBEZWZhdWx0IHByb3BlcnRpZXNcbiAgICogKENJRFItYDEwLjAuMC4wLzE2YCBhbmQgc3VibmV0cyBvZiB0eXBlIGBQUklWQVRFX0lTT0xBVEVEYClcbiAgICovXG4gIHJlYWRvbmx5IGNsaWVudD86IGNsaWVudC5IeXBlcmxlZGdlckZhYnJpY0NsaWVudFByb3BzO1xuXG4gIC8qKlxuICAgKiBDb25maWd1cmF0aW9uIHRvIGVuYWJsZS9kaXNhYmxlIGVucm9sbG1lbnQgb2YgYWRtaW4gdXNlclxuICAgKiBAZGVmYXVsdCAtIHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGVucm9sbEFkbWluPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogTGlzdCBvZiB1c2VycyB0byByZWdpc3RlciB3aXRoIEZhYnJpYyBDQVxuICAgKiBOb3RlOiBlbnJvbGxBZG1pbiBwcm9wZXJ0eSBoYXMgdG8gYmUgZW5hYmxlZCBmb3IgcmVnaXN0ZXJpbmcgdXNlcnNcbiAgICovXG4gIHJlYWRvbmx5IHVzZXJzPzogQXJyYXk8dXNlci5IeXBlcmxlZGdlckZhYnJpY1VzZXJQcm9wcz47XG5cbn1cblxuXG4vKipcbiAqIENyZWF0ZXMgYSBIeXBlcmxlZGdlciBGYWJyaWMgbmV0d29yayBvbiBBbWF6b24gTWFuYWdlZCBCbG9ja2NoYWluXG4gKi9cbmV4cG9ydCBjbGFzcyBIeXBlcmxlZGdlckZhYnJpY05ldHdvcmsgZXh0ZW5kcyBjb25zdHJ1Y3RzLkNvbnN0cnVjdCB7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIG5hbWVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuZXR3b3JrTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbmV0d29yayBkZXNjcmlwdGlvblxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG5ldHdvcmtEZXNjcmlwdGlvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbmV0d29yayBpZGVudGlmaWVyIGdlbmVyYXRlZCBvbiBjb25zdHJ1Y3Rpb25cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuZXR3b3JrSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG1lbWJlciBuYW1lXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbWVtYmVyTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbWVtYmVyIGRlc2NyaXB0aW9uXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbWVtYmVyRGVzY3JpcHRpb246IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG1lbWJlciBpZGVudGlmaWVyIGdlbmVyYXRlZCBvbiBjb25zdHJ1Y3Rpb25cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBtZW1iZXJJZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBIeXBlcmxlZGdlciBGYWJyaWMgZnJhbWV3b3JrIHZlcnNpb25cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBmcmFtZXdvcmtWZXJzaW9uOiBGcmFtZXdvcmtWZXJzaW9uO1xuXG4gIC8qKlxuICAgKiBNYW5hZ2VkIEJsb2NrY2hhaW4gbmV0d29yayBlZGl0aW9uXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbmV0d29ya0VkaXRpb246IE5ldHdvcmtFZGl0aW9uO1xuXG4gIC8qKlxuICAgKiBUaGUgZHVyYXRpb24gZnJvbSB0aGUgdGltZSB0aGF0IGEgcHJvcG9zYWwgaXMgY3JlYXRlZCB1bnRpbCBpdCBleHBpcmVzXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcHJvcG9zYWxEdXJhdGlvbkluSG91cnM6IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIHBlcmNlbnRhZ2Ugb2Ygdm90ZXMgYW1vbmcgYWxsIG1lbWJlcnMgdGhhdCBtdXN0IGJlIHllcyBmb3IgYSBwcm9wb3NhbCB0byBiZSBhcHByb3ZlZFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHRocmVzaG9sZFBlcmNlbnRhZ2U6IG51bWJlcjtcblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSB5ZXMgdm90ZXMgbXVzdCBiZSBncmVhdGVyIHRoYW4gdGhlIHRocmVzaG9sZCBwZXJjZW50YWdlXG4gICAqIG9yIG11c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHRoZSB0aHJlaG9sZCBwZXJjZW50YWdlIHRvIGJlIGFwcHJvdmVkXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdGhyZXNob2xkQ29tcGFyYXRvcjogVGhyZXNob2xkQ29tcGFyYXRvcjtcblxuICAvKipcbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gdG8gZW5hYmxlIG9yIGRpc2FibGUgY2VydGlmaWNhdGUgYXV0aG9yaXR5IGxvZ2dpbmdcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBlbmFibGVDYUxvZ2dpbmc6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIFZQQyBlbmRwb2ludCBzZXJ2aWNlIG5hbWVcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB2cGNFbmRwb2ludFNlcnZpY2VOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE1hbmFnZWQgQmxvY2tjaGFpbiBuZXR3b3JrIG9yZGVyaW5nIHNlcnZpY2UgZW5kcG9pbnRcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBvcmRlcmVyRW5kcG9pbnQ6IHN0cmluZztcblxuICAvKipcbiAgICogTWFuYWdlZCBCbG9ja2NoYWluIG1lbWJlciBDQSBlbmRwb2ludFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNhRW5kcG9pbnQ6IHN0cmluZztcblxuICAvKipcbiAgICogU2VjcmV0IEFSTiBmb3IgdGhlIEh5cGVybGVkZ2VyIEZhYnJpYyBhZG1pbiBwYXNzd29yZFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFkbWluUGFzc3dvcmRTZWNyZXQ6IHNlY3JldHNtYW5hZ2VyLlNlY3JldDtcblxuICAvKipcbiAgICogU2VjcmV0IGZvciBIeXBlcmxlZGdlciBGYWJyaWMgYWRtaW4gcHJpdmF0ZSBrZXlcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhZG1pblByaXZhdGVLZXlTZWNyZXQ6IHNlY3JldHNtYW5hZ2VyLlNlY3JldDtcblxuICAvKipcbiAgICogU2VjcmV0IGZvciBIeXBlcmxlZGdlciBGYWJyaWMgYWRtaW4gc2lnbmVkIGNlcnRpZmljYXRlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYWRtaW5TaWduZWRDZXJ0U2VjcmV0OiBzZWNyZXRzbWFuYWdlci5TZWNyZXQ7XG5cbiAgLyoqXG4gICAqIExpc3Qgb2Ygbm9kZXMgY3JlYXRlZCBpbiB0aGUgbmV0d29ya1xuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG5vZGVzOiBBcnJheTxub2RlLkh5cGVybGVkZ2VyRmFicmljTm9kZT47XG5cbiAgLyoqXG4gICAqIFRoZSBjbGllbnQgbmV0d29yayB0byBpbnRlcmFjdCB3aXRoIHRoZSBIeXBlcmxlZGdlciBGYWJyaWMgbmV0d29ya1xuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNsaWVudDogY2xpZW50Lkh5cGVybGVkZ2VyRmFicmljQ2xpZW50O1xuXG4gIC8qKlxuICAgKiBDb25maWd1cmF0aW9uIHRvIGVuYWJsZS9kaXNhYmxlIGFkbWluIHVzZXIgZW5yb2xsbWVudFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGVucm9sbEFkbWluOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBMaXN0IG9mIHVzZXJzIHJlZ2lzdGVyZWQgd2l0aCBDQVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHVzZXJzOiBBcnJheTx1c2VyLkh5cGVybGVkZ2VyRmFicmljVXNlcj47XG5cblxuICBjb25zdHJ1Y3RvcihzY29wZTogY29uc3RydWN0cy5Db25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBIeXBlcmxlZGdlckZhYnJpY05ldHdvcmtQcm9wcykge1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8vIENvbGxlY3QgbWV0YWRhdGEgb24gdGhlIHN0YWNrXG4gICAgY29uc3QgcGFydGl0aW9uID0gY2RrLlN0YWNrLm9mKHRoaXMpLnBhcnRpdGlvbjtcbiAgICBjb25zdCByZWdpb24gPSBjZGsuU3RhY2sub2YodGhpcykucmVnaW9uO1xuICAgIGNvbnN0IGFjY291bnQgPSBjZGsuU3RhY2sub2YodGhpcykuYWNjb3VudDtcblxuICAgIC8vIFBvcHVsYXRlIGluc3RhbmNlIHZhcmlhYmxlcyBmcm9tIGlucHV0IHByb3BlcnRpZXMsIHVzaW5nIGRlZmF1bHRzIGlmIHZhbHVlcyBub3QgcHJvdmlkZWRcbiAgICB0aGlzLm5ldHdvcmtOYW1lID0gcHJvcHMubmV0d29ya05hbWU7XG4gICAgdGhpcy5uZXR3b3JrRGVzY3JpcHRpb24gPSBwcm9wcy5uZXR3b3JrRGVzY3JpcHRpb24gPz8gcHJvcHMubmV0d29ya05hbWU7XG4gICAgdGhpcy5tZW1iZXJOYW1lID0gcHJvcHMubWVtYmVyTmFtZTtcbiAgICB0aGlzLm1lbWJlckRlc2NyaXB0aW9uID0gcHJvcHMubWVtYmVyRGVzY3JpcHRpb24gPz8gcHJvcHMubWVtYmVyTmFtZTtcbiAgICB0aGlzLmZyYW1ld29ya1ZlcnNpb24gPSBwcm9wcy5mcmFtZXdvcmtWZXJzaW9uID8/IEZyYW1ld29ya1ZlcnNpb24uVkVSU0lPTl8xXzQ7XG4gICAgdGhpcy5uZXR3b3JrRWRpdGlvbiA9IHByb3BzLm5ldHdvcmtFZGl0aW9uID8/IE5ldHdvcmtFZGl0aW9uLlNUQU5EQVJEO1xuICAgIHRoaXMucHJvcG9zYWxEdXJhdGlvbkluSG91cnMgPSBwcm9wcy5wcm9wb3NhbER1cmF0aW9uSW5Ib3VycyA/PyAyNDtcbiAgICB0aGlzLnRocmVzaG9sZFBlcmNlbnRhZ2UgPSBwcm9wcy50aHJlc2hvbGRQZXJjZW50YWdlID8/IDUwO1xuICAgIHRoaXMudGhyZXNob2xkQ29tcGFyYXRvciA9IHByb3BzLnRocmVzaG9sZENvbXBhcmF0b3IgPz8gVGhyZXNob2xkQ29tcGFyYXRvci5HUkVBVEVSX1RIQU47XG4gICAgdGhpcy5lbmFibGVDYUxvZ2dpbmcgPSBwcm9wcy5lbmFibGVDYUxvZ2dpbmcgPz8gdHJ1ZTtcbiAgICB0aGlzLmVucm9sbEFkbWluID0gcHJvcHMuZW5yb2xsQWRtaW4gPz8gdHJ1ZTtcbiAgICB0aGlzLnVzZXJzID0gW107XG5cbiAgICAvLyBFbnN1cmUgdGhlIHBhcmFtZXRlcnMgY2FwdHVyZWQgYWJvdmUgYXJlIHZhbGlkLCBzbyB3ZSBkb24ndFxuICAgIC8vIG5lZWQgdG8gd2FpdCB1bnRpbCBkZXBsb3ltZW50IHRpbWUgdG8gZGlzY292ZXIgYW4gZXJyb3JcbiAgICB1dGlsaXRpZXMudmFsaWRhdGVSZWdpb24ocmVnaW9uKTtcbiAgICBpZiAoIXV0aWxpdGllcy52YWxpZGF0ZVN0cmluZyh0aGlzLm5ldHdvcmtOYW1lLCAxLCA2NCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTmV0d29yayBuYW1lIGlzIGludmFsaWQgb3Igbm90IHByb3ZpZGVkLiBJdCBjYW4gYmUgdXAgdG8gNjQgY2hhcmFjdGVycyBsb25nLicpO1xuICAgIH1cbiAgICBpZiAoIXV0aWxpdGllcy52YWxpZGF0ZVN0cmluZyh0aGlzLm5ldHdvcmtEZXNjcmlwdGlvbiwgMCwgMTI4KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdOZXR3b3JrIGRlc2NyaXB0aW9uIGlzIGludmFsaWQuIEl0IGNhbiBiZSB1cCB0byAxMjggY2hhcmFjdGVycyBsb25nLicpO1xuICAgIH1cbiAgICBpZiAoIXV0aWxpdGllcy52YWxpZGF0ZVN0cmluZyh0aGlzLm1lbWJlck5hbWUsIDEsIDY0LCAvXig/IS18WzAtOV0pKD8hLiotJCkoPyEuKj8tLSlbYS16QS1aMC05LV0rJC8pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01lbWJlciBuYW1lIGlzIGludmFsaWQgb3Igbm90IHByb3ZpZGVkLiBJdCBjYW4gYmUgdXAgdG8gNjQgY2hhcmFjdGVycyBsb25nLCBhbmQgY2FuIGhhdmUgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMgYW5kIGh5cGhlbihzKS4gSXQgY2Fubm90IHN0YXJ0IHdpdGggYSBudW1iZXIsIG9yIHN0YXJ0IGFuZCBlbmQgd2l0aCBhIGh5cGhlbiAoLSksIG9yIGhhdmUgdHdvIGNvbnNlY3V0aXZlIGh5cGhlbnMuIFRoZSBtZW1iZXIgbmFtZSBtdXN0IGFsc28gYmUgdW5pcXVlIGFjcm9zcyB0aGUgbmV0d29yay4nKTtcbiAgICB9XG4gICAgaWYgKCF1dGlsaXRpZXMudmFsaWRhdGVTdHJpbmcodGhpcy5tZW1iZXJEZXNjcmlwdGlvbiwgMCwgMTI4KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNZW1iZXIgZGVzY3JpcHRpb24gaXMgaW52YWxpZC4gSXQgY2FuIGJlIHVwIHRvIDEyOCBjaGFyYWN0ZXJzIGxvbmcuJyk7XG4gICAgfVxuICAgIGlmICghdXRpbGl0aWVzLnZhbGlkYXRlSW50ZWdlcih0aGlzLnByb3Bvc2FsRHVyYXRpb25JbkhvdXJzLCAxLCAxNjgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1ZvdGluZyBwb2xpY3kgcHJvcG9zYWwgZHVyYXRpb24gbXVzdCBiZSBiZXR3ZWVuIDEgYW5kIDE2OCBob3Vycy4nKTtcbiAgICB9XG4gICAgaWYgKCF1dGlsaXRpZXMudmFsaWRhdGVJbnRlZ2VyKHRoaXMudGhyZXNob2xkUGVyY2VudGFnZSwgMCwgMTAwKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdWb3RpbmcgcG9saWN5IHRocmVzaG9sZCBwZXJjZW50YWdlIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxMDAuJyk7XG4gICAgfVxuXG4gICAgLy8gRW5zdXJlIHRoZSB1c2VycyBwcm9wZXJ0eSBpcyBub3QgZGVmaW5lZCxcbiAgICAvLyBpZiB0aGUgZW5yb2xsQWRtaW4gcHJvcGVydHkgaXMgZGlzYWJsZWRcbiAgICBpZiAoIXRoaXMuZW5yb2xsQWRtaW4gJiYgcHJvcHMudXNlcnMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRW5yb2xsIGFkbWluIHByb3BlcnR5IGhhcyB0byBiZSBlbmFibGVkIGZvciByZWdpc3RlcmluZyB1c2VycycpO1xuICAgIH1cblxuICAgIC8vIEVuc3VyZSB0aGUgdXNlciBhZmZpbGlhdGlvbiBpbmNsdWRlcyB0aGUgbWVtYmVyIG5hbWUsXG4gICAgLy8gaWYgdGhlIHVzZXIgbGlzdCBmb3IgcmVnaXN0cmF0aW9uIGlzIHByb3ZpZGVkXG4gICAgaWYgKHByb3BzLnVzZXJzKSB7XG4gICAgICBwcm9wcy51c2Vycy5mb3JFYWNoKGUgPT4ge1xuICAgICAgICBpZiAoIWUuYWZmaWxpdGF0aW9uLnN0YXJ0c1dpdGgodGhpcy5tZW1iZXJOYW1lKSkgdGhyb3cgbmV3IEVycm9yKCdVc2VyIGFmZmlsaWF0aW9uIGlzIGludmFsaWQuIEFmZmlsaWF0aW9uIHNob3VsZCBzdGFydCB3aXRoIE1lbWJlciBuYW1lJyk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBQZXIgdGhlIE1hbmFnZWQgQmxvY2tjaGFpbiBkb2N1bWVudGF0aW9uLCB0aGUgYWRtaW4gcGFzc3dvcmQgbXVzdCBiZSBhdCBsZWFzdCBlaWdodFxuICAgIC8vIGNoYXJhY3RlcnMgbG9uZyBhbmQgbm8gbW9yZSB0aGFuIDMyIGNoYXJhY3RlcnMuIEl0IG11c3QgY29udGFpbiBhdCBsZWFzdCBvbmUgdXBwZXJjYXNlXG4gICAgLy8gbGV0dGVyLCBvbmUgbG93ZXJjYXNlIGxldHRlciwgYW5kIG9uZSBkaWdpdC4gSXQgY2Fubm90IGhhdmUgYSBzaW5nbGUgcXVvdGF0aW9uIG1hcmsgKOKAmCksXG4gICAgLy8gYSBkb3VibGUgcXVvdGF0aW9uIG1hcmtzICjigJwpLCBhIGZvcndhcmQgc2xhc2goLyksIGEgYmFja3dhcmQgc2xhc2goXFwpLCBALCBvciBhIHNwYWNlO1xuICAgIC8vIHNldmVyYWwgb3RoZXIgY2hhcmFjdGVycyBhcmUgZXhsdWRlZCBoZXJlIHRvIG1ha2UgdGhlIHBhc3N3b3JkIGVhc2llciB0byB1c2UgaW4gc2NyaXB0c1xuICAgIGNvbnN0IHBhc3N3b3JkUmVxdWlyZW1lbnRzID0ge1xuICAgICAgcGFzc3dvcmRMZW5ndGg6IDMyLFxuICAgICAgcmVxdWlyZUVhY2hJbmNsdWRlZFR5cGU6IHRydWUsXG4gICAgICBleGNsdWRlQ2hhcmFjdGVyczogJ1xcJ1wiL1xcXFxAICZ7fTw+KnwnLFxuICAgIH07XG4gICAgdGhpcy5hZG1pblBhc3N3b3JkU2VjcmV0ID0gbmV3IHNlY3JldHNtYW5hZ2VyLlNlY3JldCh0aGlzLCAnQWRtaW5QYXNzd29yZCcsIHsgZ2VuZXJhdGVTZWNyZXRTdHJpbmc6IHBhc3N3b3JkUmVxdWlyZW1lbnRzIH0pO1xuXG4gICAgLy8gVGhlIGluaXRpYWxseSBlbnJvbGxlZCBhZG1pbiB1c2VyIGNyZWRlbnRpYWxzIHdpbGwgYmUgc3RvcmVkIGluIHRoZXNlIHNlY3JldHNcbiAgICB0aGlzLmFkbWluUHJpdmF0ZUtleVNlY3JldCA9IG5ldyBzZWNyZXRzbWFuYWdlci5TZWNyZXQodGhpcywgJ0FkbWluUHJpdmF0ZUtleScpO1xuICAgIHRoaXMuYWRtaW5TaWduZWRDZXJ0U2VjcmV0ID0gbmV3IHNlY3JldHNtYW5hZ2VyLlNlY3JldCh0aGlzLCAnQWRtaW5TaWduZWRDZXJ0Jyk7XG5cbiAgICAvLyBCdWlsZCBvdXQgdGhlIENsb3VkZm9ybWF0aW9uIGNvbnN0cnVjdCBmb3IgdGhlIG5ldHdvcmsvbWVtYmVyXG4gICAgY29uc3QgbmV0d29ya0NvbmZpZ3VyYXRpb24gPSB7XG4gICAgICBuYW1lOiB0aGlzLm5ldHdvcmtOYW1lLFxuICAgICAgZGVzY3JpcHRpb246IHRoaXMubmV0d29ya0Rlc2NyaXB0aW9uLFxuICAgICAgZnJhbWV3b3JrOiAnSFlQRVJMRURHRVJfRkFCUklDJyxcbiAgICAgIGZyYW1ld29ya1ZlcnNpb246IHRoaXMuZnJhbWV3b3JrVmVyc2lvbixcbiAgICAgIG5ldHdvcmtGcmFtZXdvcmtDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIG5ldHdvcmtGYWJyaWNDb25maWd1cmF0aW9uOiB7XG4gICAgICAgICAgZWRpdGlvbjogdGhpcy5uZXR3b3JrRWRpdGlvbixcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICB2b3RpbmdQb2xpY3k6IHtcbiAgICAgICAgYXBwcm92YWxUaHJlc2hvbGRQb2xpY3k6IHtcbiAgICAgICAgICBwcm9wb3NhbER1cmF0aW9uSW5Ib3VyczogdGhpcy5wcm9wb3NhbER1cmF0aW9uSW5Ib3VycyxcbiAgICAgICAgICB0aHJlc2hvbGRQZXJjZW50YWdlOiB0aGlzLnRocmVzaG9sZFBlcmNlbnRhZ2UsXG4gICAgICAgICAgdGhyZXNob2xkQ29tcGFyYXRvcjogdGhpcy50aHJlc2hvbGRDb21wYXJhdG9yLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgLy8gTm90ZSB0aGUgdXNlIG9mIHRoZSB1bndyYXAgYmVsb3cgaXMgdGhlIG9ubHkgcG9zc2libGUgd2F5IHRvIGdldFxuICAgIC8vIHRoZSBzZWNyZXQgdmFsdWUgaW50byB0aGUgQ2xvdWRGb3JtYXRpb247IGl0IHdpbGwgc3RpbGwgbm90IGRpcmVjdGx5XG4gICAgLy8gYmUgaW5jbHVkZWQgaW4gdGhlIHN5bnRoZXNpemVkIHRlbXBsYXRlIHNvIHVzYWdlIGhlcmUgaXMgc3RpbGwgc2FmZVxuICAgIGNvbnN0IG1lbWJlckNvbmZpZ3VyYXRpb24gPSB7XG4gICAgICBuYW1lOiB0aGlzLm1lbWJlck5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogdGhpcy5tZW1iZXJEZXNjcmlwdGlvbixcbiAgICAgIG1lbWJlckZyYW1ld29ya0NvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgbWVtYmVyRmFicmljQ29uZmlndXJhdGlvbjoge1xuICAgICAgICAgIGFkbWluVXNlcm5hbWU6ICdhZG1pbicsXG4gICAgICAgICAgYWRtaW5QYXNzd29yZDogdGhpcy5hZG1pblBhc3N3b3JkU2VjcmV0LnNlY3JldFZhbHVlLnVuc2FmZVVud3JhcCgpLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IG5ldHdvcmsgPSBuZXcgbWFuYWdlZGJsb2NrY2hhaW4uQ2ZuTWVtYmVyKHRoaXMsICdOZXR3b3JrJywgeyBuZXR3b3JrQ29uZmlndXJhdGlvbiwgbWVtYmVyQ29uZmlndXJhdGlvbiB9KTtcblxuICAgIC8vIENhcHR1cmUgZGF0YSBpbmNsdWRlZCBpbiB0aGUgQ2xvdWRmb3JtYXRpb24gb3V0cHV0IGluIGluc3RhbmNlIHZhcmlhYmxlc1xuICAgIHRoaXMubmV0d29ya0lkID0gbmV0d29yay5nZXRBdHQoJ05ldHdvcmtJZCcpLnRvU3RyaW5nKCk7XG4gICAgdGhpcy5tZW1iZXJJZCA9IG5ldHdvcmsuZ2V0QXR0KCdNZW1iZXJJZCcpLnRvU3RyaW5nKCk7XG5cbiAgICAvLyBCdWlsZCBvdXQgdGhlIGFzc29jaWF0ZWQgbm9kZSBjb25zdHJ1Y3RzXG4gICAgdGhpcy5ub2RlcyA9IG5vZGUuSHlwZXJsZWRnZXJGYWJyaWNOb2RlLmNvbnN0cnVjdE5vZGVzKHRoaXMsIHByb3BzLm5vZGVzKTtcblxuICAgIC8vIER1ZSB0byBhIHJhY2UgY29uZGl0aW9uIGluIENESyBjdXN0b20gcmVzb3VyY2VzIChodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzE4MjM3KSxcbiAgICAvLyB0aGUgbmVjZXNzYXJ5IHBlcm1pc3Npb25zIGZvciBhbGwgU0RLIGNhbGxzIGluIHRoZSBzdGFjayBuZWVkIHRvIGJlIGFkZGVkIGhlcmUsIGV2ZW4gdGhvdWdoXG4gICAgLy8gdGhlIGNhbGxzIGluIHRoaXMgY29uc3RydWN0IGRvbid0IG5lZWQgYWNjZXNzIHRvIHRoZSBub2RlczsgdGhpcyBhbHNvIG1lYW5zIG5vZGUgY29uc3RydWN0c1xuICAgIC8vIGNhbid0IHBvcHVsYXRlIHRoZWlyIG91dHB1dHMgZnVsbHkgdW50aWwgbGF0ZXIsIHdoaWNoIGlzIGFubm95aW5nXG4gICAgY29uc3Qgbm9kZUlkcyA9IHRoaXMubm9kZXMubWFwKG4gPT4gbi5ub2RlSWQpO1xuICAgIGNvbnN0IG5vZGVBcm5zID0gbm9kZUlkcy5tYXAoaSA9PiBgYXJuOiR7cGFydGl0aW9ufTptYW5hZ2VkYmxvY2tjaGFpbjoke3JlZ2lvbn06JHthY2NvdW50fTpub2Rlcy8ke2l9YCk7XG4gICAgY29uc3Qgc2RrQ2FsbFBvbGljeSA9IGN1c3RvbXJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZVBvbGljeS5mcm9tU2RrQ2FsbHMoe1xuICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgIGBhcm46JHtwYXJ0aXRpb259Om1hbmFnZWRibG9ja2NoYWluOiR7cmVnaW9ufTo6bmV0d29ya3MvJHt0aGlzLm5ldHdvcmtJZH1gLFxuICAgICAgICBgYXJuOiR7cGFydGl0aW9ufTptYW5hZ2VkYmxvY2tjaGFpbjoke3JlZ2lvbn06JHthY2NvdW50fTptZW1iZXJzLyR7dGhpcy5tZW1iZXJJZH1gLFxuICAgICAgICAuLi5ub2RlQXJucyxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICAvLyBDbG91ZGZvcm1hdGlvbiBkb2Vzbid0IGluY2x1ZGUgYWxsIHRoZSBuZXR3b3JrIGFuZCBtZW1iZXIgYXR0cmlidXRlc1xuICAgIC8vIG5lZWRlZCB0byB1c2UgSHlwZXJsZWRnZXIgRmFicmljLCBzbyB1c2UgU0RLIGNhbGxzIHRvIGZldGNoIHNhaWQgZGF0YVxuICAgIGNvbnN0IG5ldHdvcmtEYXRhU2RrQ2FsbCA9IHtcbiAgICAgIHNlcnZpY2U6ICdNYW5hZ2VkQmxvY2tjaGFpbicsXG4gICAgICBhY3Rpb246ICdnZXROZXR3b3JrJyxcbiAgICAgIHBhcmFtZXRlcnM6IHsgTmV0d29ya0lkOiB0aGlzLm5ldHdvcmtJZCB9LFxuICAgICAgcGh5c2ljYWxSZXNvdXJjZUlkOiBjdXN0b21yZXNvdXJjZXMuUGh5c2ljYWxSZXNvdXJjZUlkLm9mKCdJZCcpLFxuICAgIH07XG4gICAgY29uc3QgbWVtYmVyRGF0YVNka0NhbGwgPSB7XG4gICAgICBzZXJ2aWNlOiAnTWFuYWdlZEJsb2NrY2hhaW4nLFxuICAgICAgYWN0aW9uOiAnZ2V0TWVtYmVyJyxcbiAgICAgIHBhcmFtZXRlcnM6IHsgTmV0d29ya0lkOiB0aGlzLm5ldHdvcmtJZCwgTWVtYmVySWQ6IHRoaXMubWVtYmVySWQgfSxcbiAgICAgIHBoeXNpY2FsUmVzb3VyY2VJZDogY3VzdG9tcmVzb3VyY2VzLlBoeXNpY2FsUmVzb3VyY2VJZC5vZignSWQnKSxcbiAgICB9O1xuXG4gICAgLy8gRGF0YSBpdGVtcyBuZWVkIGZldGNoaW5nIG9uIGNyZWF0aW9uIGFuZCB1cGRhdGluZzsgbm90aGluZyBuZWVkcyBkb2luZyBvbiBkZWxldGlvblxuICAgIGNvbnN0IG5ldHdvcmtEYXRhID0gbmV3IGN1c3RvbXJlc291cmNlcy5Bd3NDdXN0b21SZXNvdXJjZSh0aGlzLCAnTmV0d29ya0RhdGFSZXNvdXJjZScsIHtcbiAgICAgIHBvbGljeTogc2RrQ2FsbFBvbGljeSxcbiAgICAgIG9uQ3JlYXRlOiBuZXR3b3JrRGF0YVNka0NhbGwsXG4gICAgICBvblVwZGF0ZTogbmV0d29ya0RhdGFTZGtDYWxsLFxuICAgIH0pO1xuICAgIGNvbnN0IG1lbWJlckRhdGEgPSBuZXcgY3VzdG9tcmVzb3VyY2VzLkF3c0N1c3RvbVJlc291cmNlKHRoaXMsICdNZW1iZXJEYXRhUmVzb3VyY2UnLCB7XG4gICAgICBwb2xpY3k6IHNka0NhbGxQb2xpY3ksXG4gICAgICBvbkNyZWF0ZTogbWVtYmVyRGF0YVNka0NhbGwsXG4gICAgICBvblVwZGF0ZTogbWVtYmVyRGF0YVNka0NhbGwsXG4gICAgfSk7XG5cbiAgICAvLyBDbG91ZGZvcm1hdGlvbiBkb2Vzbid0IGluY2x1ZGUgbG9nZ2luZyBjb25maWd1cmF0aW9uIHNvIHVzZSBTREsgY2FsbCB0byBkbyBzb1xuICAgIGNvbnN0IGxvZ0NvbmZpZ3VyYXRpb24gPSB7XG4gICAgICBGYWJyaWM6IHsgQ2FMb2dzOiB7IENsb3Vkd2F0Y2g6IHsgRW5hYmxlZDogdGhpcy5lbmFibGVDYUxvZ2dpbmcgfSB9IH0sXG4gICAgfTtcbiAgICBjb25zdCBjb25maWd1cmVDYUxvZ1Nka0NhbGwgPSB7XG4gICAgICBzZXJ2aWNlOiAnTWFuYWdlZEJsb2NrY2hhaW4nLFxuICAgICAgYWN0aW9uOiAndXBkYXRlTWVtYmVyJyxcbiAgICAgIHBhcmFtZXRlcnM6IHsgTmV0d29ya0lkOiB0aGlzLm5ldHdvcmtJZCwgTWVtYmVySWQ6IHRoaXMubWVtYmVySWQsIExvZ1B1Ymxpc2hpbmdDb25maWd1cmF0aW9uOiBsb2dDb25maWd1cmF0aW9uIH0sXG4gICAgICBwaHlzaWNhbFJlc291cmNlSWQ6IGN1c3RvbXJlc291cmNlcy5QaHlzaWNhbFJlc291cmNlSWQub2YoJ0lkJyksXG4gICAgfTtcbiAgICBuZXcgY3VzdG9tcmVzb3VyY2VzLkF3c0N1c3RvbVJlc291cmNlKHRoaXMsICdDb25maWd1cmVDYUxvZ1Jlc291cmNlJywge1xuICAgICAgcG9saWN5OiBzZGtDYWxsUG9saWN5LFxuICAgICAgb25DcmVhdGU6IGNvbmZpZ3VyZUNhTG9nU2RrQ2FsbCxcbiAgICAgIG9uVXBkYXRlOiBjb25maWd1cmVDYUxvZ1Nka0NhbGwsXG4gICAgfSk7XG5cbiAgICAvLyBHcmFiIGl0ZW1zIG91dCBvZiB0aGUgYWJvdmUgcmV0dXJuIHZhbHVlcyBhbmQgc3RpY2sgdGhlbSBpbiBvdXRwdXQgcHJvcGVydGllc1xuICAgIHRoaXMudnBjRW5kcG9pbnRTZXJ2aWNlTmFtZSA9IG5ldHdvcmtEYXRhLmdldFJlc3BvbnNlRmllbGQoJ05ldHdvcmsuVnBjRW5kcG9pbnRTZXJ2aWNlTmFtZScpO1xuICAgIHRoaXMub3JkZXJlckVuZHBvaW50ID0gbmV0d29ya0RhdGEuZ2V0UmVzcG9uc2VGaWVsZCgnTmV0d29yay5GcmFtZXdvcmtBdHRyaWJ1dGVzLkZhYnJpYy5PcmRlcmluZ1NlcnZpY2VFbmRwb2ludCcpO1xuICAgIHRoaXMuY2FFbmRwb2ludCA9IG1lbWJlckRhdGEuZ2V0UmVzcG9uc2VGaWVsZCgnTWVtYmVyLkZyYW1ld29ya0F0dHJpYnV0ZXMuRmFicmljLkNhRW5kcG9pbnQnKTtcblxuICAgIC8vIEFzIHN0YXRlZCBlYXJsaWVyLCBub2RlIGNvbnN0cnVjdHMgY2FuJ3QgcG9wdWxhdGUgYWxsIHRoZWlyIHByb3BlcnRpZXNcbiAgICAvLyB1bnRpbCBhZnRlciB0aGUgYWJvdmUgbmV0d29yayBhbmQgbWVtYmVyIFNESyBjYWxscyBzdWNjZWVkOyB0aHVzIHRoZVxuICAgIC8vIGZ1bmN0aW9uIGNhbGxzIGJlbG93IHdoZXJlIGZldGNoZXMgYXJlIHNwbGl0IG91dCBhbmQgbG9nZ2luZyBpcyBjb25maWd1cmVkXG4gICAgZm9yIChjb25zdCBuIG9mIHRoaXMubm9kZXMpIHtcbiAgICAgIG4uY29uZmlndXJlTG9nZ2luZyhzZGtDYWxsUG9saWN5KTtcbiAgICAgIG4uZmV0Y2hEYXRhKHNka0NhbGxQb2xpY3kpO1xuICAgIH1cblxuICAgIC8vIEJ1aWxkIG91dCB0aGUgY2xpZW50IFZQQyBjb25zdHJ1Y3RcbiAgICB0aGlzLmNsaWVudCA9IG5ldyBjbGllbnQuSHlwZXJsZWRnZXJGYWJyaWNDbGllbnQodGhpcywgJ05ldHdvcmtDbGllbnQnLCBwcm9wcy5jbGllbnQpO1xuXG4gICAgLy8gRW5yb2xsIGFkbWluIGFuZCB1c2VycywgaWYgZW5hYmxlZFxuICAgIGlmICh0aGlzLmVucm9sbEFkbWluKSB7XG4gICAgICAvLyBCdWlsZCBvdXQgYWxsIHRoZSBjdXN0b20gcmVzb3VyY2VzIHRvIHJlZ2lzdGVyIGFuZCBlbnJvbGwgaWRlbnRpdGllcyB0byBDQVxuICAgICAgY29uc3QgaWRlbnRpdHlSZXNvdXJjZXMgPSBuZXcgaWRlbnRpdHkuSHlwZXJsZWRnZXJGYWJyaWNJZGVudGl0eSh0aGlzLCAnSWRlbnRpdHknKTtcblxuICAgICAgLy8gRW5yb2xsIHRoZSBhZG1pbmlzdHJhdG9yIGFuZCBzdG9yZSBpdHMgY3JlZGVudGlhbHMgb24gU2VjcmV0cyBNYW5hZ2VyXG4gICAgICBuZXcgY2RrLkN1c3RvbVJlc291cmNlKHRoaXMsICdBZG1pbkN1c3RvbVJlc291cmNlJywgeyBzZXJ2aWNlVG9rZW46IGlkZW50aXR5UmVzb3VyY2VzLmFkbWluUHJvdmlkZXIuc2VydmljZVRva2VuIH0pO1xuXG4gICAgICAvLyBSZWdpc3RlciBhbmQgZW5yb2xsIHVzZXJzLCBpZiBwcm92aWRlZFxuICAgICAgaWYgKHByb3BzLnVzZXJzKSB0aGlzLnVzZXJzID0gQXJyYXkuZnJvbShwcm9wcy51c2Vycy5lbnRyaWVzKCkpLm1hcChlID0+IG5ldyB1c2VyLkh5cGVybGVkZ2VyRmFicmljVXNlcih0aGlzLCBgVXNlciR7ZVswXX1gLCBlWzFdKSk7XG4gICAgfVxuXG4gIH1cblxufVxuIl19