@aws-cdk/aws-ec2
Version:
The CDK Construct Library for AWS::EC2
530 lines • 75.5 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SecurityGroup = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const cxschema = require("@aws-cdk/cloud-assembly-schema");
const core_1 = require("@aws-cdk/core");
const connections_1 = require("./connections");
const ec2_generated_1 = require("./ec2.generated");
const peer_1 = require("./peer");
const port_1 = require("./port");
const SECURITY_GROUP_SYMBOL = Symbol.for('@aws-cdk/iam.SecurityGroup');
const SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY = '@aws-cdk/aws-ec2.securityGroupDisableInlineRules';
/**
* A SecurityGroup that is not created in this template
*/
class SecurityGroupBase extends core_1.Resource {
constructor(scope, id, props) {
super(scope, id, props);
this.canInlineRule = false;
this.connections = new connections_1.Connections({ securityGroups: [this] });
this.peerAsTokenCount = 0;
Object.defineProperty(this, SECURITY_GROUP_SYMBOL, { value: true });
}
/**
* Return whether the indicated object is a security group
*/
static isSecurityGroup(x) {
return SECURITY_GROUP_SYMBOL in x;
}
get uniqueId() {
return core_1.Names.nodeUniqueId(this.node);
}
addIngressRule(peer, connection, description, remoteRule) {
if (description === undefined) {
description = `from ${peer.uniqueId}:${connection}`;
}
const [scope, id] = this.determineRuleScope(peer, connection, 'from', remoteRule);
// Skip duplicates
if (scope.node.tryFindChild(id) === undefined) {
new ec2_generated_1.CfnSecurityGroupIngress(scope, id, {
groupId: this.securityGroupId,
...peer.toIngressRuleConfig(),
...connection.toRuleJson(),
description,
});
}
}
addEgressRule(peer, connection, description, remoteRule) {
if (description === undefined) {
description = `to ${peer.uniqueId}:${connection}`;
}
const [scope, id] = this.determineRuleScope(peer, connection, 'to', remoteRule);
// Skip duplicates
if (scope.node.tryFindChild(id) === undefined) {
new ec2_generated_1.CfnSecurityGroupEgress(scope, id, {
groupId: this.securityGroupId,
...peer.toEgressRuleConfig(),
...connection.toRuleJson(),
description,
});
}
}
toIngressRuleConfig() {
return { sourceSecurityGroupId: this.securityGroupId };
}
toEgressRuleConfig() {
return { destinationSecurityGroupId: this.securityGroupId };
}
/**
* Determine where to parent a new ingress/egress rule
*
* A SecurityGroup rule is parented under the group it's related to, UNLESS
* we're in a cross-stack scenario with another Security Group. In that case,
* we respect the 'remoteRule' flag and will parent under the other security
* group.
*
* This is necessary to avoid cyclic dependencies between stacks, since both
* ingress and egress rules will reference both security groups, and a naive
* parenting will lead to the following situation:
*
* ╔════════════════════╗ ╔════════════════════╗
* ║ ┌───────────┐ ║ ║ ┌───────────┐ ║
* ║ │ GroupA │◀────╬─┐ ┌───╬───▶│ GroupB │ ║
* ║ └───────────┘ ║ │ │ ║ └───────────┘ ║
* ║ ▲ ║ │ │ ║ ▲ ║
* ║ │ ║ │ │ ║ │ ║
* ║ │ ║ │ │ ║ │ ║
* ║ ┌───────────┐ ║ └───┼───╬────┌───────────┐ ║
* ║ │ EgressA │─────╬─────┘ ║ │ IngressB │ ║
* ║ └───────────┘ ║ ║ └───────────┘ ║
* ║ ║ ║ ║
* ╚════════════════════╝ ╚════════════════════╝
*
* By having the ability to switch the parent, we avoid the cyclic reference by
* keeping all rules in a single stack.
*
* If this happens, we also have to change the construct ID, because
* otherwise we might have two objects with the same ID if we have
* multiple reversed security group relationships.
*
* ╔═══════════════════════════════════╗
* ║┌───────────┐ ║
* ║│ GroupB │ ║
* ║└───────────┘ ║
* ║ ▲ ║
* ║ │ ┌───────────┐ ║
* ║ ├────"from A"──│ IngressB │ ║
* ║ │ └───────────┘ ║
* ║ │ ┌───────────┐ ║
* ║ ├─────"to B"───│ EgressA │ ║
* ║ │ └───────────┘ ║
* ║ │ ┌───────────┐ ║
* ║ └─────"to B"───│ EgressC │ ║ <-- oops
* ║ └───────────┘ ║
* ╚═══════════════════════════════════╝
*/
determineRuleScope(peer, connection, fromTo, remoteRule) {
if (remoteRule && SecurityGroupBase.isSecurityGroup(peer) && differentStacks(this, peer)) {
// Reversed
const reversedFromTo = fromTo === 'from' ? 'to' : 'from';
return [peer, `${this.uniqueId}:${connection} ${reversedFromTo}`];
}
else {
// Regular (do old ID escaping to in order to not disturb existing deployments)
return [this, `${fromTo} ${this.renderPeer(peer)}:${connection}`.replace('/', '_')];
}
}
renderPeer(peer) {
if (core_1.Token.isUnresolved(peer.uniqueId)) {
// Need to return a unique value each time a peer
// is an unresolved token, else the duplicate skipper
// in `sg.addXxxRule` can detect unique rules as duplicates
return this.peerAsTokenCount++ ? `'{IndirectPeer${this.peerAsTokenCount}}'` : '{IndirectPeer}';
}
else {
return peer.uniqueId;
}
}
}
function differentStacks(group1, group2) {
return core_1.Stack.of(group1) !== core_1.Stack.of(group2);
}
/**
* Creates an Amazon EC2 security group within a VPC.
*
* Security Groups act like a firewall with a set of rules, and are associated
* with any AWS resource that has or creates Elastic Network Interfaces (ENIs).
* A typical example of a resource that has a security group is an Instance (or
* Auto Scaling Group of instances)
*
* If you are defining new infrastructure in CDK, there is a good chance you
* won't have to interact with this class at all. Like IAM Roles, Security
* Groups need to exist to control access between AWS resources, but CDK will
* automatically generate and populate them with least-privilege permissions
* for you so you can concentrate on your business logic.
*
* All Constructs that require Security Groups will create one for you if you
* don't specify one at construction. After construction, you can selectively
* allow connections to and between constructs via--for example-- the `instance.connections`
* object. Think of it as "allowing connections to your instance", rather than
* "adding ingress rules a security group". See the [Allowing
* Connections](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-ec2-readme.html#allowing-connections)
* section in the library documentation for examples.
*
* Direct manipulation of the Security Group through `addIngressRule` and
* `addEgressRule` is possible, but mutation through the `.connections` object
* is recommended. If you peer two constructs with security groups this way,
* appropriate rules will be created in both.
*
* If you have an existing security group you want to use in your CDK application,
* you would import it like this:
*
* ```ts
* const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(this, 'SG', 'sg-12345', {
* mutable: false
* });
* ```
*/
class SecurityGroup extends SecurityGroupBase {
constructor(scope, id, props) {
super(scope, id, {
physicalName: props.securityGroupName,
});
this.directIngressRules = [];
this.directEgressRules = [];
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_SecurityGroupProps(props);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, SecurityGroup);
}
throw error;
}
const groupDescription = props.description || this.node.path;
this.allowAllOutbound = props.allowAllOutbound !== false;
this.disableInlineRules = props.disableInlineRules !== undefined ?
!!props.disableInlineRules :
!!this.node.tryGetContext(SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY);
this.securityGroup = new ec2_generated_1.CfnSecurityGroup(this, 'Resource', {
groupName: this.physicalName,
groupDescription,
securityGroupIngress: core_1.Lazy.any({ produce: () => this.directIngressRules }, { omitEmptyArray: true }),
securityGroupEgress: core_1.Lazy.any({ produce: () => this.directEgressRules }, { omitEmptyArray: true }),
vpcId: props.vpc.vpcId,
});
this.securityGroupId = this.securityGroup.attrGroupId;
this.securityGroupVpcId = this.securityGroup.attrVpcId;
this.securityGroupName = this.securityGroup.ref;
this.addDefaultEgressRule();
}
/**
* Look up a security group by id.
*
* @deprecated Use `fromLookupById()` instead
*/
static fromLookup(scope, id, securityGroupId) {
try {
jsiiDeprecationWarnings.print("@aws-cdk/aws-ec2.SecurityGroup#fromLookup", "Use `fromLookupById()` instead");
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.fromLookup);
}
throw error;
}
return this.fromLookupAttributes(scope, id, { securityGroupId });
}
/**
* Look up a security group by id.
*/
static fromLookupById(scope, id, securityGroupId) {
return this.fromLookupAttributes(scope, id, { securityGroupId });
}
/**
* Look up a security group by name.
*/
static fromLookupByName(scope, id, securityGroupName, vpc) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_IVpc(vpc);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.fromLookupByName);
}
throw error;
}
return this.fromLookupAttributes(scope, id, { securityGroupName, vpc });
}
/**
* Import an existing security group into this app.
*
* This method will assume that the Security Group has a rule in it which allows
* all outbound traffic, and so will not add egress rules to the imported Security
* Group (only ingress rules).
*
* If your existing Security Group needs to have egress rules added, pass the
* `allowAllOutbound: false` option on import.
*/
static fromSecurityGroupId(scope, id, securityGroupId, options = {}) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_SecurityGroupImportOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.fromSecurityGroupId);
}
throw error;
}
class MutableImport extends SecurityGroupBase {
constructor() {
super(...arguments);
this.securityGroupId = securityGroupId;
this.allowAllOutbound = options.allowAllOutbound ?? true;
}
addEgressRule(peer, connection, description, remoteRule) {
// Only if allowAllOutbound has been disabled
if (options.allowAllOutbound === false) {
super.addEgressRule(peer, connection, description, remoteRule);
}
}
}
class ImmutableImport extends SecurityGroupBase {
constructor() {
super(...arguments);
this.securityGroupId = securityGroupId;
this.allowAllOutbound = options.allowAllOutbound ?? true;
}
addEgressRule(_peer, _connection, _description, _remoteRule) {
// do nothing
}
addIngressRule(_peer, _connection, _description, _remoteRule) {
// do nothing
}
}
return options.mutable !== false
? new MutableImport(scope, id)
: new ImmutableImport(scope, id);
}
/**
* Look up a security group.
*/
static fromLookupAttributes(scope, id, options) {
if (core_1.Token.isUnresolved(options.securityGroupId) || core_1.Token.isUnresolved(options.securityGroupName) || core_1.Token.isUnresolved(options.vpc?.vpcId)) {
throw new Error('All arguments to look up a security group must be concrete (no Tokens)');
}
const attributes = core_1.ContextProvider.getValue(scope, {
provider: cxschema.ContextProvider.SECURITY_GROUP_PROVIDER,
props: {
securityGroupId: options.securityGroupId,
securityGroupName: options.securityGroupName,
vpcId: options.vpc?.vpcId,
},
dummyValue: {
securityGroupId: 'sg-12345',
allowAllOutbound: true,
},
}).value;
return SecurityGroup.fromSecurityGroupId(scope, id, attributes.securityGroupId, {
allowAllOutbound: attributes.allowAllOutbound,
mutable: true,
});
}
addIngressRule(peer, connection, description, remoteRule) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_IPeer(peer);
jsiiDeprecationWarnings._aws_cdk_aws_ec2_Port(connection);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addIngressRule);
}
throw error;
}
if (!peer.canInlineRule || !connection.canInlineRule || this.disableInlineRules) {
super.addIngressRule(peer, connection, description, remoteRule);
return;
}
if (description === undefined) {
description = `from ${peer.uniqueId}:${connection}`;
}
this.addDirectIngressRule({
...peer.toIngressRuleConfig(),
...connection.toRuleJson(),
description,
});
}
addEgressRule(peer, connection, description, remoteRule) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_IPeer(peer);
jsiiDeprecationWarnings._aws_cdk_aws_ec2_Port(connection);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addEgressRule);
}
throw error;
}
if (this.allowAllOutbound) {
// In the case of "allowAllOutbound", we don't add any more rules. There
// is only one rule which allows all traffic and that subsumes any other
// rule.
if (!remoteRule) { // Warn only if addEgressRule() was explicitely called
core_1.Annotations.of(this).addWarning('Ignoring Egress rule since \'allowAllOutbound\' is set to true; To add customized rules, set allowAllOutbound=false on the SecurityGroup');
}
return;
}
else {
// Otherwise, if the bogus rule exists we can now remove it because the
// presence of any other rule will get rid of EC2's implicit "all
// outbound" rule anyway.
this.removeNoTrafficRule();
}
if (!peer.canInlineRule || !connection.canInlineRule || this.disableInlineRules) {
super.addEgressRule(peer, connection, description, remoteRule);
return;
}
if (description === undefined) {
description = `from ${peer.uniqueId}:${connection}`;
}
const rule = {
...peer.toEgressRuleConfig(),
...connection.toRuleJson(),
description,
};
if (isAllTrafficRule(rule)) {
// We cannot allow this; if someone adds the rule in this way, it will be
// removed again if they add other rules. We also can't automatically switch
// to "allOutbound=true" mode, because we might have already emitted
// EgressRule objects (which count as rules added later) and there's no way
// to recall those. Better to prevent this for now.
throw new Error('Cannot add an "all traffic" egress rule in this way; set allowAllOutbound=true on the SecurityGroup instead.');
}
this.addDirectEgressRule(rule);
}
/**
* Add a direct ingress rule
*/
addDirectIngressRule(rule) {
if (!this.hasIngressRule(rule)) {
this.directIngressRules.push(rule);
}
}
/**
* Return whether the given ingress rule exists on the group
*/
hasIngressRule(rule) {
return this.directIngressRules.findIndex(r => ingressRulesEqual(r, rule)) > -1;
}
/**
* Add a direct egress rule
*/
addDirectEgressRule(rule) {
if (!this.hasEgressRule(rule)) {
this.directEgressRules.push(rule);
}
}
/**
* Return whether the given egress rule exists on the group
*/
hasEgressRule(rule) {
return this.directEgressRules.findIndex(r => egressRulesEqual(r, rule)) > -1;
}
/**
* Add the default egress rule to the securityGroup
*
* This depends on allowAllOutbound:
*
* - If allowAllOutbound is true, we *TECHNICALLY* don't need to do anything, because
* EC2 is going to create this default rule anyway. But, for maximum readability
* of the template, we will add one anyway.
* - If allowAllOutbound is false, we add a bogus rule that matches no traffic in
* order to get rid of the default "all outbound" rule that EC2 creates by default.
* If other rules happen to get added later, we remove the bogus rule again so
* that it doesn't clutter up the template too much (even though that's not
* strictly necessary).
*/
addDefaultEgressRule() {
if (this.disableInlineRules) {
const peer = this.allowAllOutbound ? ALL_TRAFFIC_PEER : NO_TRAFFIC_PEER;
const port = this.allowAllOutbound ? ALL_TRAFFIC_PORT : NO_TRAFFIC_PORT;
const description = this.allowAllOutbound ? ALLOW_ALL_RULE.description : MATCH_NO_TRAFFIC.description;
super.addEgressRule(peer, port, description, false);
}
else {
const rule = this.allowAllOutbound ? ALLOW_ALL_RULE : MATCH_NO_TRAFFIC;
this.directEgressRules.push(rule);
}
}
/**
* Remove the bogus rule if it exists
*/
removeNoTrafficRule() {
if (this.disableInlineRules) {
const [scope, id] = this.determineRuleScope(NO_TRAFFIC_PEER, NO_TRAFFIC_PORT, 'to', false);
scope.node.tryRemoveChild(id);
}
else {
const i = this.directEgressRules.findIndex(r => egressRulesEqual(r, MATCH_NO_TRAFFIC));
if (i > -1) {
this.directEgressRules.splice(i, 1);
}
}
}
}
exports.SecurityGroup = SecurityGroup;
_a = JSII_RTTI_SYMBOL_1;
SecurityGroup[_a] = { fqn: "@aws-cdk/aws-ec2.SecurityGroup", version: "1.204.0" };
/**
* Egress rule that purposely matches no traffic
*
* This is used in order to disable the "all traffic" default of Security Groups.
*
* No machine can ever actually have the 255.255.255.255 IP address, but
* in order to lock it down even more we'll restrict to a nonexistent
* ICMP traffic type.
*/
const MATCH_NO_TRAFFIC = {
cidrIp: '255.255.255.255/32',
description: 'Disallow all traffic',
ipProtocol: 'icmp',
fromPort: 252,
toPort: 86,
};
const NO_TRAFFIC_PEER = peer_1.Peer.ipv4(MATCH_NO_TRAFFIC.cidrIp);
const NO_TRAFFIC_PORT = port_1.Port.icmpTypeAndCode(MATCH_NO_TRAFFIC.fromPort, MATCH_NO_TRAFFIC.toPort);
/**
* Egress rule that matches all traffic
*/
const ALLOW_ALL_RULE = {
cidrIp: '0.0.0.0/0',
description: 'Allow all outbound traffic by default',
ipProtocol: '-1',
};
const ALL_TRAFFIC_PEER = peer_1.Peer.anyIpv4();
const ALL_TRAFFIC_PORT = port_1.Port.allTraffic();
/**
* Compare two ingress rules for equality the same way CloudFormation would (discarding description)
*/
function ingressRulesEqual(a, b) {
return a.cidrIp === b.cidrIp
&& a.cidrIpv6 === b.cidrIpv6
&& a.fromPort === b.fromPort
&& a.toPort === b.toPort
&& a.ipProtocol === b.ipProtocol
&& a.sourceSecurityGroupId === b.sourceSecurityGroupId
&& a.sourceSecurityGroupName === b.sourceSecurityGroupName
&& a.sourceSecurityGroupOwnerId === b.sourceSecurityGroupOwnerId;
}
/**
* Compare two egress rules for equality the same way CloudFormation would (discarding description)
*/
function egressRulesEqual(a, b) {
return a.cidrIp === b.cidrIp
&& a.cidrIpv6 === b.cidrIpv6
&& a.fromPort === b.fromPort
&& a.toPort === b.toPort
&& a.ipProtocol === b.ipProtocol
&& a.destinationPrefixListId === b.destinationPrefixListId
&& a.destinationSecurityGroupId === b.destinationSecurityGroupId;
}
/**
* Whether this rule refers to all traffic
*/
function isAllTrafficRule(rule) {
return rule.cidrIp === '0.0.0.0/0' && rule.ipProtocol === '-1';
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdXJpdHktZ3JvdXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZWN1cml0eS1ncm91cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSwyREFBMkQ7QUFDM0Qsd0NBQTRIO0FBRzVILCtDQUE0QztBQUM1QyxtREFBb0c7QUFDcEcsaUNBQXFDO0FBQ3JDLGlDQUE4QjtBQUc5QixNQUFNLHFCQUFxQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLENBQUMsQ0FBQztBQUV2RSxNQUFNLCtDQUErQyxHQUFHLGtEQUFrRCxDQUFDO0FBd0MzRzs7R0FFRztBQUNILE1BQWUsaUJBQWtCLFNBQVEsZUFBUTtJQWlCL0MsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFxQjtRQUM3RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQVBWLGtCQUFhLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLGdCQUFXLEdBQWdCLElBQUkseUJBQVcsQ0FBQyxFQUFFLGNBQWMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUcvRSxxQkFBZ0IsR0FBVyxDQUFDLENBQUM7UUFLbkMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUscUJBQXFCLEVBQUUsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztLQUNyRTtJQXBCRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBTTtRQUNsQyxPQUFPLHFCQUFxQixJQUFJLENBQUMsQ0FBQztLQUNuQztJQWlCRCxJQUFXLFFBQVE7UUFDakIsT0FBTyxZQUFLLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztLQUN0QztJQUVNLGNBQWMsQ0FBQyxJQUFXLEVBQUUsVUFBZ0IsRUFBRSxXQUFvQixFQUFFLFVBQW9CO1FBQzdGLElBQUksV0FBVyxLQUFLLFNBQVMsRUFBRTtZQUM3QixXQUFXLEdBQUcs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QVE7V0FDekIsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsTUFBTTtXQUNyQixDQUFDLENBQUMsVUFBVSxLQUFLLENBQUMsQ0FBQyxVQUFVO1dBQzdCLENBQUMsQ0FBQyxxQkFBcUIsS0FBSyxDQUFDLENBQUMscUJBQXFCO1dBQ25ELENBQUMsQ0FBQyx1QkFBdUIsS0FBSyxDQUFDLENBQUMsdUJBQXVCO1dBQ3ZELENBQUMsQ0FBQywwQkFBMEIsS0FBSyxDQUFDLENBQUMsMEJBQTBCLENBQUM7QUFDckUsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxDQUFrQyxFQUFFLENBQWtDO0lBQzlGLE9BQU8sQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsTUFBTTtXQUN2QixDQUFDLENBQUMsUUFBUSxLQUFLLENBQUMsQ0FBQyxRQUFRO1dBQ3pCLENBQUMsQ0FBQyxRQUFRLEtBQUssQ0FBQyxDQUFDLFFBQVE7V0FDekIsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsTUFBTTtXQUNyQixDQUFDLENBQUMsVUFBVSxLQUFLLENBQUMsQ0FBQyxVQUFVO1dBQzdCLENBQUMsQ0FBQyx1QkFBdUIsS0FBSyxDQUFDLENBQUMsdUJBQXVCO1dBQ3ZELENBQUMsQ0FBQywwQkFBMEIsS0FBSyxDQUFDLENBQUMsMEJBQTBCLENBQUM7QUFDckUsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxnQkFBZ0IsQ0FBQyxJQUFTO0lBQ2pDLE9BQU8sSUFBSSxDQUFDLE1BQU0sS0FBSyxXQUFXLElBQUksSUFBSSxDQUFDLFVBQVUsS0FBSyxJQUFJLENBQUM7QUFDakUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGN4c2NoZW1hIGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSc7XG5pbXBvcnQgeyBBbm5vdGF0aW9ucywgQ29udGV4dFByb3ZpZGVyLCBJUmVzb3VyY2UsIExhenksIE5hbWVzLCBSZXNvdXJjZSwgUmVzb3VyY2VQcm9wcywgU3RhY2ssIFRva2VuIH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgKiBhcyBjeGFwaSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBDb25uZWN0aW9ucyB9IGZyb20gJy4vY29ubmVjdGlvbnMnO1xuaW1wb3J0IHsgQ2ZuU2VjdXJpdHlHcm91cCwgQ2ZuU2VjdXJpdHlHcm91cEVncmVzcywgQ2ZuU2VjdXJpdHlHcm91cEluZ3Jlc3MgfSBmcm9tICcuL2VjMi5nZW5lcmF0ZWQnO1xuaW1wb3J0IHsgSVBlZXIsIFBlZXIgfSBmcm9tICcuL3BlZXInO1xuaW1wb3J0IHsgUG9ydCB9IGZyb20gJy4vcG9ydCc7XG5pbXBvcnQgeyBJVnBjIH0gZnJvbSAnLi92cGMnO1xuXG5jb25zdCBTRUNVUklUWV9HUk9VUF9TWU1CT0wgPSBTeW1ib2wuZm9yKCdAYXdzLWNkay9pYW0uU2VjdXJpdHlHcm91cCcpO1xuXG5jb25zdCBTRUNVUklUWV9HUk9VUF9ESVNBQkxFX0lOTElORV9SVUxFU19DT05URVhUX0tFWSA9ICdAYXdzLWNkay9hd3MtZWMyLnNlY3VyaXR5R3JvdXBEaXNhYmxlSW5saW5lUnVsZXMnO1xuXG4vKipcbiAqIEludGVyZmFjZSBmb3Igc2VjdXJpdHkgZ3JvdXAtbGlrZSBvYmplY3RzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVNlY3VyaXR5R3JvdXAgZXh0ZW5kcyBJUmVzb3VyY2UsIElQZWVyIHtcbiAgLyoqXG4gICAqIElEIGZvciB0aGUgY3VycmVudCBzZWN1cml0eSBncm91cFxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSBzZWN1cml0eUdyb3VwSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgU2VjdXJpdHlHcm91cCBoYXMgYmVlbiBjb25maWd1cmVkIHRvIGFsbG93IGFsbCBvdXRib3VuZCB0cmFmZmljXG4gICAqL1xuICByZWFkb25seSBhbGxvd0FsbE91dGJvdW5kOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBZGQgYW4gaW5ncmVzcyBydWxlIGZvciB0aGUgY3VycmVudCBzZWN1cml0eSBncm91cFxuICAgKlxuICAgKiBgcmVtb3RlUnVsZWAgY29udHJvbHMgd2hlcmUgdGhlIFJ1bGUgb2JqZWN0IGlzIGNyZWF0ZWQgaWYgdGhlIHBlZXIgaXMgYWxzbyBhXG4gICAqIHNlY3VyaXR5R3JvdXAgYW5kIHRoZXkgYXJlIGluIGRpZmZlcmVudCBzdGFjay4gSWYgZmFsc2UgKGRlZmF1bHQpIHRoZVxuICAgKiBydWxlIG9iamVjdCBpcyBjcmVhdGVkIHVuZGVyIHRoZSBjdXJyZW50IFNlY3VyaXR5R3JvdXAgb2JqZWN0LiBJZiB0cnVlIGFuZCB0aGVcbiAgICogcGVlciBpcyBhbHNvIGEgU2VjdXJpdHlHcm91cCwgdGhlIHJ1bGUgb2JqZWN0IGlzIGNyZWF0ZWQgdW5kZXIgdGhlIHJlbW90ZVxuICAgKiBTZWN1cml0eUdyb3VwIG9iamVjdC5cbiAgICovXG4gIGFkZEluZ3Jlc3NSdWxlKHBlZXI6IElQZWVyLCBjb25uZWN0aW9uOiBQb3J0LCBkZXNjcmlwdGlvbj86IHN0cmluZywgcmVtb3RlUnVsZT86IGJvb2xlYW4pOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBBZGQgYW4gZWdyZXNzIHJ1bGUgZm9yIHRoZSBjdXJyZW50IHNlY3VyaXR5IGdyb3VwXG4gICAqXG4gICAqIGByZW1vdGVSdWxlYCBjb250cm9scyB3aGVyZSB0aGUgUnVsZSBvYmplY3QgaXMgY3JlYXRlZCBpZiB0aGUgcGVlciBpcyBhbHNvIGFcbiAgICogc2VjdXJpdHlHcm91cCBhbmQgdGhleSBhcmUgaW4gZGlmZmVyZW50IHN0YWNrLiBJZiBmYWxzZSAoZGVmYXVsdCkgdGhlXG4gICAqIHJ1bGUgb2JqZWN0IGlzIGNyZWF0ZWQgdW5kZXIgdGhlIGN1cnJlbnQgU2VjdXJpdHlHcm91cCBvYmplY3QuIElmIHRydWUgYW5kIHRoZVxuICAgKiBwZWVyIGlzIGFsc28gYSBTZWN1cml0eUdyb3VwLCB0aGUgcnVsZSBvYmplY3QgaXMgY3JlYXRlZCB1bmRlciB0aGUgcmVtb3RlXG4gICAqIFNlY3VyaXR5R3JvdXAgb2JqZWN0LlxuICAgKi9cbiAgYWRkRWdyZXNzUnVsZShwZWVyOiBJUGVlciwgY29ubmVjdGlvbjogUG9ydCwgZGVzY3JpcHRpb24/OiBzdHJpbmcsIHJlbW90ZVJ1bGU/OiBib29sZWFuKTogdm9pZDtcbn1cblxuLyoqXG4gKiBBIFNlY3VyaXR5R3JvdXAgdGhhdCBpcyBub3QgY3JlYXRlZCBpbiB0aGlzIHRlbXBsYXRlXG4gKi9cbmFic3RyYWN0IGNsYXNzIFNlY3VyaXR5R3JvdXBCYXNlIGV4dGVuZHMgUmVzb3VyY2UgaW1wbGVtZW50cyBJU2VjdXJpdHlHcm91cCB7XG4gIC8qKlxuICAgKiBSZXR1cm4gd2hldGhlciB0aGUgaW5kaWNhdGVkIG9iamVjdCBpcyBhIHNlY3VyaXR5IGdyb3VwXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGlzU2VjdXJpdHlHcm91cCh4OiBhbnkpOiB4IGlzIFNlY3VyaXR5R3JvdXBCYXNlIHtcbiAgICByZXR1cm4gU0VDVVJJVFlfR1JPVVBfU1lNQk9MIGluIHg7XG4gIH1cblxuICBwdWJsaWMgYWJzdHJhY3QgcmVhZG9ubHkgc2VjdXJpdHlHcm91cElkOiBzdHJpbmc7XG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSBhbGxvd0FsbE91dGJvdW5kOiBib29sZWFuO1xuXG4gIHB1YmxpYyByZWFkb25seSBjYW5JbmxpbmVSdWxlID0gZmFsc2U7XG4gIHB1YmxpYyByZWFkb25seSBjb25uZWN0aW9uczogQ29ubmVjdGlvbnMgPSBuZXcgQ29ubmVjdGlvbnMoeyBzZWN1cml0eUdyb3VwczogW3RoaXNdIH0pO1xuICBwdWJsaWMgcmVhZG9ubHkgZGVmYXVsdFBvcnQ/OiBQb3J0O1xuXG4gIHByaXZhdGUgcGVlckFzVG9rZW5Db3VudDogbnVtYmVyID0gMDtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wcz86IFJlc291cmNlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHByb3BzKTtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBTRUNVUklUWV9HUk9VUF9TWU1CT0wsIHsgdmFsdWU6IHRydWUgfSk7XG4gIH1cblxuICBwdWJsaWMgZ2V0IHVuaXF1ZUlkKCkge1xuICAgIHJldHVybiBOYW1lcy5ub2RlVW5pcXVlSWQodGhpcy5ub2RlKTtcbiAgfVxuXG4gIHB1YmxpYyBhZGRJbmdyZXNzUnVsZShwZWVyOiBJUGVlciwgY29ubmVjdGlvbjogUG9ydCwgZGVzY3JpcHRpb24/OiBzdHJpbmcsIHJlbW90ZVJ1bGU/OiBib29sZWFuKSB7XG4gICAgaWYgKGRlc2NyaXB0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGRlc2NyaXB0aW9uID0gYGZyb20gJHtwZWVyLnVuaXF1ZUlkfToke2Nvbm5lY3Rpb259YDtcbiAgICB9XG5cbiAgICBjb25zdCBbc2NvcGUsIGlkXSA9IHRoaXMuZGV0ZXJtaW5lUnVsZVNjb3BlKHBlZXIsIGNvbm5lY3Rpb24sICdmcm9tJywgcmVtb3RlUnVsZSk7XG5cbiAgICAvLyBTa2lwIGR1cGxpY2F0ZXNcbiAgICBpZiAoc2NvcGUubm9kZS50cnlGaW5kQ2hpbGQoaWQpID09PSB1bmRlZmluZWQpIHtcbiAgICAgIG5ldyBDZm5TZWN1cml0eUdyb3VwSW5ncmVzcyhzY29wZSwgaWQsIHtcbiAgICAgICAgZ3JvdXBJZDogdGhpcy5zZWN1cml0eUdyb3VwSWQsXG4gICAgICAgIC4uLnBlZXIudG9JbmdyZXNzUnVsZUNvbmZpZygpLFxuICAgICAgICAuLi5jb25uZWN0aW9uLnRvUnVsZUpzb24oKSxcbiAgICAgICAgZGVzY3JpcHRpb24sXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgYWRkRWdyZXNzUnVsZShwZWVyOiBJUGVlciwgY29ubmVjdGlvbjogUG9ydCwgZGVzY3JpcHRpb24/OiBzdHJpbmcsIHJlbW90ZVJ1bGU/OiBib29sZWFuKSB7XG4gICAgaWYgKGRlc2NyaXB0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGRlc2NyaXB0aW9uID0gYHRvICR7cGVlci51bmlxdWVJZH06JHtjb25uZWN0aW9ufWA7XG4gICAgfVxuXG4gICAgY29uc3QgW3Njb3BlLCBpZF0gPSB0aGlzLmRldGVybWluZVJ1bGVTY29wZShwZWVyLCBjb25uZWN0aW9uLCAndG8nLCByZW1vdGVSdWxlKTtcblxuICAgIC8vIFNraXAgZHVwbGljYXRlc1xuICAgIGlmIChzY29wZS5ub2RlLnRyeUZpbmRDaGlsZChpZCkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgbmV3IENmblNlY3VyaXR5R3JvdXBFZ3Jlc3Moc2NvcGUsIGlkLCB7XG4gICAgICAgIGdyb3VwSWQ6IHRoaXMuc2VjdXJpdHlHcm91cElkLFxuICAgICAgICAuLi5wZWVyLnRvRWdyZXNzUnVsZUNvbmZpZygpLFxuICAgICAgICAuLi5jb25uZWN0aW9uLnRvUnVsZUpzb24oKSxcbiAgICAgICAgZGVzY3JpcHRpb24sXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgdG9JbmdyZXNzUnVsZUNvbmZpZygpOiBhbnkge1xuICAgIHJldHVybiB7IHNvdXJjZVNlY3VyaXR5R3JvdXBJZDogdGhpcy5zZWN1cml0eUdyb3VwSWQgfTtcbiAgfVxuXG4gIHB1YmxpYyB0b0VncmVzc1J1bGVDb25maWcoKTogYW55IHtcbiAgICByZXR1cm4geyBkZXN0aW5hdGlvblNlY3VyaXR5R3JvdXBJZDogdGhpcy5zZWN1cml0eUdyb3VwSWQgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgd2hlcmUgdG8gcGFyZW50IGEgbmV3IGluZ3Jlc3MvZWdyZXNzIHJ1bGVcbiAgICpcbiAgICogQSBTZWN1cml0eUdyb3VwIHJ1bGUgaXMgcGFyZW50ZWQgdW5kZXIgdGhlIGdyb3VwIGl0J3MgcmVsYXRlZCB0bywgVU5MRVNTXG4gICAqIHdlJ3JlIGluIGEgY3Jvc3Mtc3RhY2sgc2NlbmFyaW8gd2l0aCBhbm90aGVyIFNlY3VyaXR5IEdyb3VwLiBJbiB0aGF0IGNhc2UsXG4gICAqIHdlIHJlc3BlY3QgdGhlICdyZW1vdGVSdWxlJyBmbGFnIGFuZCB3aWxsIHBhcmVudCB1bmRlciB0aGUgb3RoZXIgc2VjdXJpdHlcbiAgICogZ3JvdXAuXG4gICAqXG4gICAqIFRoaXMgaXMgbmVjZXNzYXJ5IHRvIGF2b2lkIGN5Y2xpYyBkZXBlbmRlbmNpZXMgYmV0d2VlbiBzdGFja3MsIHNpbmNlIGJvdGhcbiAgICogaW5ncmVzcyBhbmQgZWdyZXNzIHJ1bGVzIHdpbGwgcmVmZXJlbmNlIGJvdGggc2VjdXJpdHkgZ3JvdXBzLCBhbmQgYSBuYWl2ZVxuICAgKiBwYXJlbnRpbmcgd2lsbCBsZWFkIHRvIHRoZSBmb2xsb3dpbmcgc2l0dWF0aW9uOlxuICAgKlxuICAgKiAgIOKVlOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVlyAgICAgICAgIOKVlOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVl1xuICAgKiAgIOKVkSAg4pSM4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSQICAgICDilZEgICAgICAgICDilZEgICAg4pSM4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSQICAg4pWRXG4gICAqICAg4pWRICDilIIgIEdyb3VwQSAgIOKUguKXgOKUgOKUgOKUgOKUgOKVrOKUgOKUkCAgIOKUjOKUgOKUgOKUgOKVrOKUgOKUgOKUgOKWtuKUgiAgR3JvdXBCICAg4pSCICAg4pWRXG4gICAqICAg4pWRICDilJTilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJggICAgIOKVkSDilIIgICDilIIgICDilZEgICAg4pSU4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSYICAg4pWRXG4gICAqICAg4pWRICAgICAgICDilrIgICAgICAgICAgIOKVkSDilIIgICDilIIgICDilZEgICAgICAgICAg4payICAgICAgICAg4pWRXG4gICAqICAg4pWRICAgICAgICDilIIgICAgICAgICAgIOKVkSDilIIgICDilIIgICDilZEgICAgICAgICAg4pSCICAgICAgICAg4pWRXG4gICAqICAg4pWRICAgICAgICDilIIgICAgICAgICAgIOKVkSDilIIgICDilIIgICDilZEgICAgICAgICAg4pSCICAgICAgICAg4pWRXG4gICAqICAg4pWRICDilIzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJAgICAgIOKVkSDilJTilIDilIDilIDilLzilIDilIDilIDilazilIDilIDilIDilIDilIzilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJAgICDilZFcbiAgICogICDilZEgIOKUgiAgRWdyZXNzQSAg4pSC4pSA4pSA4pSA4pSA4pSA4pWs4pSA4pSA4pSA4pSA4pSA4pSYICAg4pWRICAgIOKUgiBJbmdyZXNzQiAg4pSCICAg4pWRXG4gICAqICAg4pWRICDilJTilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJggICAgIOKVkSAgICAgICAgIOKVkSAgICDilJTilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJggICDilZFcbiAgICogICDilZEgICAgICAgICAgICAgICAgICAgIOKVkSAgICAgICAgIOKVkSAgICAgICAgICAgICAgICAgICAg4pWRXG4gICAqICAg4pWa4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWdICAgICAgICAg4pWa4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWdXG4gICAqXG4gICAqIEJ5IGhhdmluZyB0aGUgYWJpbGl0eSB0byBzd2l0Y2ggdGhlIHBhcmVudCwgd2UgYXZvaWQgdGhlIGN5Y2xpYyByZWZlcmVuY2UgYnlcbiAgICoga2VlcGluZyBhbGwgcnVsZXMgaW4gYSBzaW5nbGUgc3RhY2suXG4gICAqXG4gICAqIElmIHRoaXMgaGFwcGVucywgd2UgYWxzbyBoYXZlIHRvIGNoYW5nZSB0aGUgY29uc3RydWN0IElELCBiZWNhdXNlXG4gICAqIG90aGVyd2lzZSB3ZSBtaWdodCBoYXZlIHR3byBvYmplY3RzIHdpdGggdGhlIHNhbWUgSUQgaWYgd2UgaGF2ZVxuICAgKiBtdWx0aXBsZSByZXZlcnNlZCBzZWN1cml0eSBncm91cCByZWxhdGlvbnNoaXBzLlxuICAgKlxuICAgKiAgIOKVlOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVl1xuICAgKiAgIOKVkeKUjOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUkCAgICAgICAgICAgICAgICAgICAgICDilZFcbiAgICogICDilZHilIIgIEdyb3VwQiAgIOKUgiAgICAgICAgICAgICAgICAgICAgICDilZFcbiAgICogICDilZHilJTilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilJggICAgICAgICAgICAgICAgICAgICAg4pWRXG4gICAqICAg4pWRICAgICAg4payICAgICAgICAgICAgICAgICAgICAgICAgICAgIOKVkVxuICAgKiAgIOKVkSAgICAgIOKUgiAgICAgICAgICAgICAg4pSM4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSQIOKVkVxuICAgKiAgIOKVkSAgICAgIOKUnOKUgOKUgOKUgOKUgFwiZnJvbSBBXCLilIDilIDilIIgSW5ncmVzc0IgIOKUgiDilZFcbiAgICogICDilZEgICAgICDilIIgICAgICAgICAgICAgIOKUlOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmCDilZFcbiAgICogICDilZEgICAgICDilIIgICAgICAgICAgICAgIOKUjOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUkCDilZFcbiAgICogICDilZEgICAgICDilJzilIDilIDilIDilIDilIBcInRvIEJcIuKUgOKUgOKUgOKUgiAgRWdyZXNzQSAg4pSCIOKVkVxuICAgKiAgIOKVkSAgICAgIOKUgiAgICAgICAgICAgICAg4pSU4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSYIOKVkVxuICAgKiAgIOKVkSAgICAgIOKUgiAgICAgICAgICAgICAg4pSM4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSQIOKVkVxuICAgKiAgIOKVkSAgICAgIOKUlOKUgOKUgOKUgOKUgOKUgFwidG8gQlwi4pSA4pSA4pSA4pSCICBFZ3Jlc3NDICDilIIg4pWRICA8LS0gb29wc1xuICAgKiAgIOKVkSAgICAgICAgICAgICAgICAgICAgIOKUlOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUmCDilZFcbiAgICogICDilZrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZ1cbiAgICovXG5cbiAgcHJvdGVjdGVkIGRldGVybWluZVJ1bGVTY29wZShcbiAgICBwZWVyOiBJUGVlcixcbiAgICBjb25uZWN0aW9uOiBQb3J0LFxuICAgIGZyb21UbzogJ2Zyb20nIHwgJ3RvJyxcbiAgICByZW1vdGVSdWxlPzogYm9vbGVhbik6IFtTZWN1cml0eUdyb3VwQmFzZSwgc3RyaW5nXSB7XG5cbiAgICBpZiAocmVtb3RlUnVsZSAmJiBTZWN1cml0eUdyb3VwQmFzZS5pc1NlY3VyaXR5R3JvdXAocGVlcikgJiYgZGlmZmVyZW50U3RhY2tzKHRoaXMsIHBlZXIpKSB7XG4gICAgICAvLyBSZXZlcnNlZFxuICAgICAgY29uc3QgcmV2ZXJzZWRGcm9tVG8gPSBmcm9tVG8gPT09ICdmcm9tJyA/ICd0bycgOiAnZnJvbSc7XG4gICAgICByZXR1cm4gW3BlZXIsIGAke3RoaXMudW5pcXVlSWR9OiR7Y29ubmVjdGlvbn0gJHtyZXZlcnNlZEZyb21Ub31gXTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUmVndWxhciAoZG8gb2xkIElEIGVzY2FwaW5nIHRvIGluIG9yZGVyIHRvIG5vdCBkaXN0dXJiIGV4aXN0aW5nIGRlcGxveW1lbnRzKVxuICAgICAgcmV0dXJuIFt0aGlzLCBgJHtmcm9tVG99ICR7dGhpcy5yZW5kZXJQZWVyKHBlZXIpfToke2Nvbm5lY3Rpb259YC5yZXBsYWNlKCcvJywgJ18nKV07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZW5kZXJQZWVyKHBlZXI6IElQZWVyKSB7XG4gICAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChwZWVyLnVuaXF1ZUlkKSkge1xuICAgICAgLy8gTmVlZCB0byByZXR1cm4gYSB1bmlxdWUgdmFsdWUgZWFjaCB0aW1lIGEgcGVlclxuICAgICAgLy8gaXMgYW4gdW5yZXNvbHZlZCB0b2tlbiwgZWxzZSB0aGUgZHVwbGljYXRlIHNraXBwZXJcbiAgICAgIC8vIGluIGBzZy5hZGRYeHhSdWxlYCBjYW4gZGV0ZWN0IHVuaXF1ZSBydWxlcyBhcyBkdXBsaWNhdGVzXG4gICAgICByZXR1cm4gdGhpcy5wZWVyQXNUb2tlbkNvdW50KysgPyBgJ3tJbmRpcmVjdFBlZXIke3RoaXMucGVlckFzVG9rZW5Db3VudH19J2AgOiAne0luZGlyZWN0UGVlcn0nO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gcGVlci51bmlxdWVJZDtcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gZGlmZmVyZW50U3RhY2tzKGdyb3VwMTogU2VjdXJpdHlHcm91cEJhc2UsIGdyb3VwMjogU2VjdXJpdHlHcm91cEJhc2UpIHtcbiAgcmV0dXJuIFN0YWNrLm9mKGdyb3VwMSkgIT09IFN0YWNrLm9mKGdyb3VwMik7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VjdXJpdHlHcm91cFByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBzZWN1cml0eSBncm91cC4gRm9yIHZhbGlkIHZhbHVlcywgc2VlIHRoZSBHcm91cE5hbWVcbiAgICogcGFyYW1ldGVyIG9mIHRoZSBDcmVhdGVTZWN1cml0eUdyb3VwIGFjdGlvbiBpbiB0aGUgQW1hem9uIEVDMiBBUElcbiAgICogUmVmZXJlbmNlLlxuICAgKlxuICAgKiBJdCBpcyBub3QgcmVjb21tZW5kZWQgdG8gdXNlIGFuIGV4cGxpY2l0IGdyb3VwIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IElmIHlvdSBkb24ndCBzcGVjaWZ5IGEgR3JvdXBOYW1lLCBBV1MgQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzIGFcbiAgICogdW5pcXVlIHBoeXNpY2FsIElEIGFuZCB1c2VzIHRoYXQgSUQgZm9yIHRoZSBncm91cCBuYW1lLlxuICAgKi9cbiAgcmVhZG9ubHkgc2VjdXJpdHlHcm91cE5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEEgZGVzY3JpcHRpb24gb2YgdGhlIHNlY3VyaXR5IGdyb3VwLlxuICAgKlxuICAgKiBAZGVmYXVsdCBUaGUgZGVmYXVsdCBuYW1lIHdpbGwgYmUgdGhlIGNvbnN0cnVjdCdzIENESyBwYXRoLlxuICAgKi9cbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBWUEMgaW4gd2hpY2ggdG8gY3JlYXRlIHRoZSBzZWN1cml0eSBncm91cC5cbiAgICovXG4gIHJlYWRvbmx5IHZwYzogSVZwYztcblxuICAvKipcbiAgICogV2hldGhlciB0byBhbGxvdyBhbGwgb3V0Ym91bmQgdHJhZmZpYyBieSBkZWZhdWx0LlxuICAgKlxuICAgKiBJZiB0aGlzIGlzIHNldCB0byB0cnVlLCB0aGVyZSB3aWxsIG9ubHkgYmUgYSBzaW5nbGUgZWdyZXNzIHJ1bGUgd2hpY2ggYWxsb3dzIGFsbFxuICAgKiBvdXRib3VuZCB0cmFmZmljLiBJZiB0aGlzIGlzIHNldCB0byBmYWxzZSwgbm8gb3V0Ym91bmQgdHJhZmZpYyB3aWxsIGJlIGFsbG93ZWQgYnlcbiAgICogZGVmYXVsdCBhbmQgYWxsIGVncmVzcyB0cmFmZmljIG11c3QgYmUgZXhwbGljaXRseSBhdXRob3JpemVkLlxu