@sureshgururajan/aws-console-private-access-validator 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -88
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +0 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/test.d.ts +0 -0
- package/dist/test.d.ts.map +0 -0
- package/dist/test.js +0 -0
- package/dist/test.js.map +0 -0
- package/dist/types.d.ts +0 -0
- package/dist/types.d.ts.map +0 -0
- package/dist/types.js +0 -0
- package/dist/types.js.map +0 -0
- package/dist/validator.d.ts +0 -0
- package/dist/validator.d.ts.map +0 -0
- package/dist/validator.js +3 -1
- package/dist/validator.js.map +1 -1
- package/package.json +30 -29
- package/src/index.d.ts +1 -0
- package/src/index.js +85 -0
- package/src/index.ts +111 -110
- package/src/test.d.ts +1 -0
- package/src/test.js +26 -0
- package/src/test.ts +31 -31
- package/src/types.d.ts +16 -0
- package/src/types.js +2 -0
- package/src/types.ts +18 -18
- package/src/validator.d.ts +18 -0
- package/src/validator.js +236 -0
- package/src/validator.ts +310 -310
- package/tsconfig.json +20 -20
package/src/validator.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
export class ConsolePrivateAccessValidator {
|
|
2
|
+
template;
|
|
3
|
+
region;
|
|
4
|
+
checks = [];
|
|
5
|
+
constructor(template, region = 'us-east-1') {
|
|
6
|
+
this.template = template;
|
|
7
|
+
this.region = region;
|
|
8
|
+
}
|
|
9
|
+
validate() {
|
|
10
|
+
this.checks = [];
|
|
11
|
+
this.checkVpcEndpoints();
|
|
12
|
+
this.checkEndpointPolicies();
|
|
13
|
+
this.checkRoute53HostedZones();
|
|
14
|
+
this.checkSecurityGroups();
|
|
15
|
+
this.checkEc2Instance();
|
|
16
|
+
this.checkNatGateway();
|
|
17
|
+
this.checkNetworkConfiguration();
|
|
18
|
+
const failCount = this.checks.filter(c => c.status === 'fail').length;
|
|
19
|
+
const valid = failCount === 0;
|
|
20
|
+
return {
|
|
21
|
+
valid,
|
|
22
|
+
checks: this.checks,
|
|
23
|
+
summary: this.generateSummary(valid, failCount),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
getServiceName(serviceName) {
|
|
27
|
+
if (typeof serviceName === 'string') {
|
|
28
|
+
return serviceName;
|
|
29
|
+
}
|
|
30
|
+
if (serviceName?.['Fn::Join']) {
|
|
31
|
+
const parts = serviceName['Fn::Join'][1];
|
|
32
|
+
if (Array.isArray(parts)) {
|
|
33
|
+
// Handle Ref to AWS::Region by replacing with actual region
|
|
34
|
+
return parts
|
|
35
|
+
.map((part) => {
|
|
36
|
+
if (typeof part === 'string') {
|
|
37
|
+
return part;
|
|
38
|
+
}
|
|
39
|
+
if (part?.Ref === 'AWS::Region') {
|
|
40
|
+
return this.region;
|
|
41
|
+
}
|
|
42
|
+
return '';
|
|
43
|
+
})
|
|
44
|
+
.join('');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
checkVpcEndpoints() {
|
|
50
|
+
const requiredEndpoints = [
|
|
51
|
+
{ name: 'console', service: `com.amazonaws.${this.region}.console` },
|
|
52
|
+
{ name: 'signin', service: `com.amazonaws.${this.region}.signin` },
|
|
53
|
+
{ name: 'ssm', service: `com.amazonaws.${this.region}.ssm` },
|
|
54
|
+
{ name: 'ec2messages', service: `com.amazonaws.${this.region}.ec2messages` },
|
|
55
|
+
{ name: 'ssmmessages', service: `com.amazonaws.${this.region}.ssmmessages` },
|
|
56
|
+
];
|
|
57
|
+
const resources = this.template.Resources || {};
|
|
58
|
+
const interfaceEndpoints = Object.values(resources).filter((r) => r.Type === 'AWS::EC2::VPCEndpoint' && r.Properties?.VpcEndpointType === 'Interface');
|
|
59
|
+
for (const endpoint of requiredEndpoints) {
|
|
60
|
+
const found = interfaceEndpoints.some((e) => {
|
|
61
|
+
const serviceName = this.getServiceName(e.Properties?.ServiceName);
|
|
62
|
+
return serviceName && serviceName.includes(endpoint.service);
|
|
63
|
+
});
|
|
64
|
+
this.checks.push({
|
|
65
|
+
name: `VPC Endpoint: ${endpoint.name}`,
|
|
66
|
+
status: found ? 'pass' : 'fail',
|
|
67
|
+
message: found
|
|
68
|
+
? `Interface VPC endpoint for ${endpoint.name} found`
|
|
69
|
+
: `Missing interface VPC endpoint for ${endpoint.name}`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// Check for S3 Gateway endpoint
|
|
73
|
+
const s3Gateway = Object.values(resources).some((r) => {
|
|
74
|
+
const serviceName = this.getServiceName(r.Properties?.ServiceName);
|
|
75
|
+
return (r.Type === 'AWS::EC2::VPCEndpoint' &&
|
|
76
|
+
r.Properties?.VpcEndpointType === 'Gateway' &&
|
|
77
|
+
serviceName &&
|
|
78
|
+
serviceName.includes('s3'));
|
|
79
|
+
});
|
|
80
|
+
this.checks.push({
|
|
81
|
+
name: 'VPC Endpoint: S3 Gateway',
|
|
82
|
+
status: s3Gateway ? 'pass' : 'fail',
|
|
83
|
+
message: s3Gateway ? 'S3 Gateway VPC endpoint found' : 'Missing S3 Gateway VPC endpoint',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
checkEndpointPolicies() {
|
|
87
|
+
const resources = this.template.Resources || {};
|
|
88
|
+
const consoleEndpoint = Object.entries(resources).find(([_, r]) => {
|
|
89
|
+
const serviceName = this.getServiceName(r.Properties?.ServiceName);
|
|
90
|
+
return (r.Type === 'AWS::EC2::VPCEndpoint' &&
|
|
91
|
+
serviceName &&
|
|
92
|
+
serviceName.includes('console'));
|
|
93
|
+
});
|
|
94
|
+
const signinEndpoint = Object.entries(resources).find(([_, r]) => {
|
|
95
|
+
const serviceName = this.getServiceName(r.Properties?.ServiceName);
|
|
96
|
+
return (r.Type === 'AWS::EC2::VPCEndpoint' &&
|
|
97
|
+
serviceName &&
|
|
98
|
+
serviceName.includes('signin'));
|
|
99
|
+
});
|
|
100
|
+
for (const [name, endpoint] of [
|
|
101
|
+
['Console', consoleEndpoint],
|
|
102
|
+
['Signin', signinEndpoint],
|
|
103
|
+
]) {
|
|
104
|
+
if (!endpoint)
|
|
105
|
+
continue;
|
|
106
|
+
const [_, resource] = endpoint;
|
|
107
|
+
const hasPolicy = resource.Properties?.PolicyDocument;
|
|
108
|
+
this.checks.push({
|
|
109
|
+
name: `Endpoint Policy: ${name}`,
|
|
110
|
+
status: hasPolicy ? 'pass' : 'fail',
|
|
111
|
+
message: hasPolicy
|
|
112
|
+
? `${name} endpoint has a policy attached`
|
|
113
|
+
: `${name} endpoint is missing a policy`,
|
|
114
|
+
details: hasPolicy
|
|
115
|
+
? this.validatePolicyContent(resource.Properties.PolicyDocument)
|
|
116
|
+
: undefined,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
validatePolicyContent(policy) {
|
|
121
|
+
if (!policy.Statement || policy.Statement.length === 0) {
|
|
122
|
+
return 'Policy has no statements';
|
|
123
|
+
}
|
|
124
|
+
const statement = policy.Statement[0];
|
|
125
|
+
const hasAccountCondition = statement.Condition?.StringEquals?.['aws:PrincipalAccount'];
|
|
126
|
+
if (hasAccountCondition) {
|
|
127
|
+
return 'Policy restricts access to specific account(s)';
|
|
128
|
+
}
|
|
129
|
+
return 'Policy does not restrict access by account';
|
|
130
|
+
}
|
|
131
|
+
checkRoute53HostedZones() {
|
|
132
|
+
const resources = this.template.Resources || {};
|
|
133
|
+
const hostedZones = Object.values(resources).filter((r) => r.Type === 'AWS::Route53::HostedZone');
|
|
134
|
+
const requiredZones = ['console.aws.amazon.com', 'signin.aws.amazon.com'];
|
|
135
|
+
for (const zone of requiredZones) {
|
|
136
|
+
const found = hostedZones.some((hz) => {
|
|
137
|
+
const zoneName = hz.Properties?.Name;
|
|
138
|
+
// Route53 zone names may have a trailing dot
|
|
139
|
+
return zoneName === zone || zoneName === `${zone}.`;
|
|
140
|
+
});
|
|
141
|
+
this.checks.push({
|
|
142
|
+
name: `Route53 Hosted Zone: ${zone}`,
|
|
143
|
+
status: found ? 'pass' : 'fail',
|
|
144
|
+
message: found
|
|
145
|
+
? `Private hosted zone for ${zone} found`
|
|
146
|
+
: `Missing private hosted zone for ${zone}`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// Check for Route53 records
|
|
150
|
+
const recordSets = Object.values(resources).filter((r) => r.Type === 'AWS::Route53::RecordSet');
|
|
151
|
+
this.checks.push({
|
|
152
|
+
name: 'Route53 Records',
|
|
153
|
+
status: recordSets.length > 0 ? 'pass' : 'warning',
|
|
154
|
+
message: recordSets.length > 0
|
|
155
|
+
? `Found ${recordSets.length} Route53 records`
|
|
156
|
+
: 'No Route53 records found',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
checkSecurityGroups() {
|
|
160
|
+
const resources = this.template.Resources || {};
|
|
161
|
+
const securityGroups = Object.values(resources).filter((r) => r.Type === 'AWS::EC2::SecurityGroup');
|
|
162
|
+
const hasHttpsIngress = securityGroups.some((sg) => {
|
|
163
|
+
const ingress = sg.Properties?.SecurityGroupIngress || [];
|
|
164
|
+
return ingress.some((rule) => (rule.FromPort === 443 || rule.IpProtocol === 'tcp') &&
|
|
165
|
+
(rule.ToPort === 443 || rule.IpProtocol === 'tcp'));
|
|
166
|
+
});
|
|
167
|
+
this.checks.push({
|
|
168
|
+
name: 'Security Group: HTTPS Access',
|
|
169
|
+
status: hasHttpsIngress ? 'pass' : 'warning',
|
|
170
|
+
message: hasHttpsIngress
|
|
171
|
+
? 'Security group allows HTTPS (port 443) traffic'
|
|
172
|
+
: 'No security group rule found for HTTPS (port 443)',
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
checkEc2Instance() {
|
|
176
|
+
const resources = this.template.Resources || {};
|
|
177
|
+
const instance = Object.values(resources).find((r) => r.Type === 'AWS::EC2::Instance');
|
|
178
|
+
this.checks.push({
|
|
179
|
+
name: 'EC2 Instance',
|
|
180
|
+
status: instance ? 'pass' : 'warning',
|
|
181
|
+
message: instance ? 'EC2 instance found' : 'No EC2 instance found (optional)',
|
|
182
|
+
});
|
|
183
|
+
if (instance) {
|
|
184
|
+
const hasIamRole = instance.Properties?.IamInstanceProfile;
|
|
185
|
+
this.checks.push({
|
|
186
|
+
name: 'EC2 IAM Role',
|
|
187
|
+
status: hasIamRole ? 'pass' : 'warning',
|
|
188
|
+
message: hasIamRole
|
|
189
|
+
? 'EC2 instance has IAM instance profile'
|
|
190
|
+
: 'EC2 instance missing IAM instance profile',
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
checkNatGateway() {
|
|
195
|
+
const resources = this.template.Resources || {};
|
|
196
|
+
const natGateway = Object.values(resources).find((r) => r.Type === 'AWS::EC2::NatGateway');
|
|
197
|
+
this.checks.push({
|
|
198
|
+
name: 'NAT Gateway',
|
|
199
|
+
status: natGateway ? 'pass' : 'warning',
|
|
200
|
+
message: natGateway
|
|
201
|
+
? 'NAT Gateway found for private subnet egress'
|
|
202
|
+
: 'No NAT Gateway found (required for private subnet internet access)',
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
checkNetworkConfiguration() {
|
|
206
|
+
const resources = this.template.Resources || {};
|
|
207
|
+
// Check for private subnets
|
|
208
|
+
const privateSubnets = Object.values(resources).filter((r) => r.Type === 'AWS::EC2::Subnet' &&
|
|
209
|
+
!r.Properties?.MapPublicIpOnLaunch);
|
|
210
|
+
this.checks.push({
|
|
211
|
+
name: 'Private Subnets',
|
|
212
|
+
status: privateSubnets.length > 0 ? 'pass' : 'fail',
|
|
213
|
+
message: privateSubnets.length > 0
|
|
214
|
+
? `Found ${privateSubnets.length} private subnet(s)`
|
|
215
|
+
: 'No private subnets found',
|
|
216
|
+
});
|
|
217
|
+
// Check for route tables
|
|
218
|
+
const routeTables = Object.values(resources).filter((r) => r.Type === 'AWS::EC2::RouteTable');
|
|
219
|
+
this.checks.push({
|
|
220
|
+
name: 'Route Tables',
|
|
221
|
+
status: routeTables.length > 0 ? 'pass' : 'warning',
|
|
222
|
+
message: routeTables.length > 0
|
|
223
|
+
? `Found ${routeTables.length} route table(s)`
|
|
224
|
+
: 'No route tables found',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
generateSummary(valid, failCount) {
|
|
228
|
+
const passCount = this.checks.filter(c => c.status === 'pass').length;
|
|
229
|
+
const warningCount = this.checks.filter(c => c.status === 'warning').length;
|
|
230
|
+
if (valid) {
|
|
231
|
+
return `✓ Validation passed. All required checks passed (${passCount} passed, ${warningCount} warnings).`;
|
|
232
|
+
}
|
|
233
|
+
return `✗ Validation failed. ${failCount} check(s) failed, ${passCount} passed, ${warningCount} warnings.`;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE1BQU0sT0FBTyw2QkFBNkI7SUFDaEMsUUFBUSxDQUF5QjtJQUNqQyxNQUFNLENBQVM7SUFDZixNQUFNLEdBQXNCLEVBQUUsQ0FBQztJQUV2QyxZQUFZLFFBQWdDLEVBQUUsU0FBaUIsV0FBVztRQUN4RSxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQsUUFBUTtRQUNOLElBQUksQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBRWpCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1FBQy9CLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUVqQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDO1FBQ3RFLE1BQU0sS0FBSyxHQUFHLFNBQVMsS0FBSyxDQUFDLENBQUM7UUFFOUIsT0FBTztZQUNMLEtBQUs7WUFDTCxNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsT0FBTyxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQztTQUNoRCxDQUFDO0lBQ0osQ0FBQztJQUVPLGNBQWMsQ0FBQyxXQUFnQjtRQUNyQyxJQUFJLE9BQU8sV0FBVyxL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QVksR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUssU0FBUyxDQUFDLENBQUMsTUFBTSxDQUFDO1FBRTVFLElBQUksS0FBSyxFQUFFLENBQUM7WUFDVixPQUFPLG9EQUFvRCxTQUFTLFlBQVksWUFBWSxhQUFhLENBQUM7UUFDNUcsQ0FBQztRQUVELE9BQU8sd0JBQXdCLFNBQVMscUJBQXFCLFNBQVMsWUFBWSxZQUFZLFlBQVksQ0FBQztJQUM3RyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBWYWxpZGF0aW9uQ2hlY2ssIFZhbGlkYXRpb25SZXN1bHQsIENsb3VkRm9ybWF0aW9uVGVtcGxhdGUgfSBmcm9tICcuL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIENvbnNvbGVQcml2YXRlQWNjZXNzVmFsaWRhdG9yIHtcbiAgcHJpdmF0ZSB0ZW1wbGF0ZTogQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZTtcbiAgcHJpdmF0ZSByZWdpb246IHN0cmluZztcbiAgcHJpdmF0ZSBjaGVja3M6IFZhbGlkYXRpb25DaGVja1tdID0gW107XG5cbiAgY29uc3RydWN0b3IodGVtcGxhdGU6IENsb3VkRm9ybWF0aW9uVGVtcGxhdGUsIHJlZ2lvbjogc3RyaW5nID0gJ3VzLWVhc3QtMScpIHtcbiAgICB0aGlzLnRlbXBsYXRlID0gdGVtcGxhdGU7XG4gICAgdGhpcy5yZWdpb24gPSByZWdpb247XG4gIH1cblxuICB2YWxpZGF0ZSgpOiBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICB0aGlzLmNoZWNrcyA9IFtdO1xuXG4gICAgdGhpcy5jaGVja1ZwY0VuZHBvaW50cygpO1xuICAgIHRoaXMuY2hlY2tFbmRwb2ludFBvbGljaWVzKCk7XG4gICAgdGhpcy5jaGVja1JvdXRlNTNIb3N0ZWRab25lcygpO1xuICAgIHRoaXMuY2hlY2tTZWN1cml0eUdyb3VwcygpO1xuICAgIHRoaXMuY2hlY2tFYzJJbnN0YW5jZSgpO1xuICAgIHRoaXMuY2hlY2tOYXRHYXRld2F5KCk7XG4gICAgdGhpcy5jaGVja05ldHdvcmtDb25maWd1cmF0aW9uKCk7XG5cbiAgICBjb25zdCBmYWlsQ291bnQgPSB0aGlzLmNoZWNrcy5maWx0ZXIoYyA9PiBjLnN0YXR1cyA9PT0gJ2ZhaWwnKS5sZW5ndGg7XG4gICAgY29uc3QgdmFsaWQgPSBmYWlsQ291bnQgPT09IDA7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdmFsaWQsXG4gICAgICBjaGVja3M6IHRoaXMuY2hlY2tzLFxuICAgICAgc3VtbWFyeTogdGhpcy5nZW5lcmF0ZVN1bW1hcnkodmFsaWQsIGZhaWxDb3VudCksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0U2VydmljZU5hbWUoc2VydmljZU5hbWU6IGFueSk6IHN0cmluZyB8IG51bGwge1xuICAgIGlmICh0eXBlb2Ygc2VydmljZU5hbWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gc2VydmljZU5hbWU7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlTmFtZT8uWydGbjo6Sm9pbiddKSB7XG4gICAgICBjb25zdCBwYXJ0cyA9IHNlcnZpY2VOYW1lWydGbjo6Sm9pbiddWzFdO1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkocGFydHMpKSB7XG4gICAgICAgIC8vIEhhbmRsZSBSZWYgdG8gQVdTOjpSZWdpb24gYnkgcmVwbGFjaW5nIHdpdGggYWN0dWFsIHJlZ2lvblxuICAgICAgICByZXR1cm4gcGFydHNcbiAgICAgICAgICAubWFwKChwYXJ0OiBhbnkpID0+IHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFydCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHBhcnQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocGFydD8uUmVmID09PSAnQVdTOjpSZWdpb24nKSB7XG4gICAgICAgICAgICAgIHJldHVybiB0aGlzLnJlZ2lvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5qb2luKCcnKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBwcml2YXRlIGNoZWNrVnBjRW5kcG9pbnRzKCk6IHZvaWQge1xuICAgIGNvbnN0IHJlcXVpcmVkRW5kcG9pbnRzID0gW1xuICAgICAgeyBuYW1lOiAnY29uc29sZScsIHNlcnZpY2U6IGBjb20uYW1hem9uYXdzLiR7dGhpcy5yZWdpb259LmNvbnNvbGVgIH0sXG4gICAgICB7IG5hbWU6ICdzaWduaW4nLCBzZXJ2aWNlOiBgY29tLmFtYXpvbmF3cy4ke3RoaXMucmVnaW9ufS5zaWduaW5gIH0sXG4gICAgICB7IG5hbWU6ICdzc20nLCBzZXJ2aWNlOiBgY29tLmFtYXpvbmF3cy4ke3RoaXMucmVnaW9ufS5zc21gIH0sXG4gICAgICB7IG5hbWU6ICdlYzJtZXNzYWdlcycsIHNlcnZpY2U6IGBjb20uYW1hem9uYXdzLiR7dGhpcy5yZWdpb259LmVjMm1lc3NhZ2VzYCB9LFxuICAgICAgeyBuYW1lOiAnc3NtbWVzc2FnZXMnLCBzZXJ2aWNlOiBgY29tLmFtYXpvbmF3cy4ke3RoaXMucmVnaW9ufS5zc21tZXNzYWdlc2AgfSxcbiAgICBdO1xuXG4gICAgY29uc3QgcmVzb3VyY2VzID0gdGhpcy50ZW1wbGF0ZS5SZXNvdXJjZXMgfHwge307XG4gICAgY29uc3QgaW50ZXJmYWNlRW5kcG9pbnRzID0gT2JqZWN0LnZhbHVlcyhyZXNvdXJjZXMpLmZpbHRlcihcbiAgICAgIChyOiBhbnkpID0+IHIuVHlwZSA9PT0gJ0FXUzo6RUMyOjpWUENFbmRwb2ludCcgJiYgci5Qcm9wZXJ0aWVzPy5WcGNFbmRwb2ludFR5cGUgPT09ICdJbnRlcmZhY2UnXG4gICAgKTtcblxuICAgIGZvciAoY29uc3QgZW5kcG9pbnQgb2YgcmVxdWlyZWRFbmRwb2ludHMpIHtcbiAgICAgIGNvbnN0IGZvdW5kID0gaW50ZXJmYWNlRW5kcG9pbnRzLnNvbWUoKGU6IGFueSkgPT4ge1xuICAgICAgICBjb25zdCBzZXJ2aWNlTmFtZSA9IHRoaXMuZ2V0U2VydmljZU5hbWUoZS5Qcm9wZXJ0aWVzPy5TZXJ2aWNlTmFtZSk7XG4gICAgICAgIHJldHVybiBzZXJ2aWNlTmFtZSAmJiBzZXJ2aWNlTmFtZS5pbmNsdWRlcyhlbmRwb2ludC5zZXJ2aWNlKTtcbiAgICAgIH0pO1xuXG4gICAgICB0aGlzLmNoZWNrcy5wdXNoKHtcbiAgICAgICAgbmFtZTogYFZQQyBFbmRwb2ludDogJHtlbmRwb2ludC5uYW1lfWAsXG4gICAgICAgIHN0YXR1czogZm91bmQgPyAncGFzcycgOiAnZmFpbCcsXG4gICAgICAgIG1lc3NhZ2U6IGZvdW5kXG4gICAgICAgICAgPyBgSW50ZXJmYWNlIFZQQyBlbmRwb2ludCBmb3IgJHtlbmRwb2ludC5uYW1lfSBmb3VuZGBcbiAgICAgICAgICA6IGBNaXNzaW5nIGludGVyZmFjZSBWUEMgZW5kcG9pbnQgZm9yICR7ZW5kcG9pbnQubmFtZX1gLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgZm9yIFMzIEdhdGV3YXkgZW5kcG9pbnRcbiAgICBjb25zdCBzM0dhdGV3YXkgPSBPYmplY3QudmFsdWVzKHJlc291cmNlcykuc29tZShcbiAgICAgIChyOiBhbnkpID0+IHtcbiAgICAgICAgY29uc3Qgc2VydmljZU5hbWUgPSB0aGlzLmdldFNlcnZpY2VOYW1lKHIuUHJvcGVydGllcz8uU2VydmljZU5hbWUpO1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIHIuVHlwZSA9PT0gJ0FXUzo6RUMyOjpWUENFbmRwb2ludCcgJiZcbiAgICAgICAgICByLlByb3BlcnRpZXM/LlZwY0VuZHBvaW50VHlwZSA9PT0gJ0dhdGV3YXknICYmXG4gICAgICAgICAgc2VydmljZU5hbWUgJiZcbiAgICAgICAgICBzZXJ2aWNlTmFtZS5pbmNsdWRlcygnczMnKVxuICAgICAgICApO1xuICAgICAgfVxuICAgICk7XG5cbiAgICB0aGlzLmNoZWNrcy5wdXNoKHtcbiAgICAgIG5hbWU6ICdWUEMgRW5kcG9pbnQ6IFMzIEdhdGV3YXknLFxuICAgICAgc3RhdHVzOiBzM0dhdGV3YXkgPyAncGFzcycgOiAnZmFpbCcsXG4gICAgICBtZXNzYWdlOiBzM0dhdGV3YXkgPyAnUzMgR2F0ZXdheSBWUEMgZW5kcG9pbnQgZm91bmQnIDogJ01pc3NpbmcgUzMgR2F0ZXdheSBWUEMgZW5kcG9pbnQnLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjaGVja0VuZHBvaW50UG9saWNpZXMoKTogdm9pZCB7XG4gICAgY29uc3QgcmVzb3VyY2VzID0gdGhpcy50ZW1wbGF0ZS5SZXNvdXJjZXMgfHwge307XG4gICAgY29uc3QgY29uc29sZUVuZHBvaW50ID0gT2JqZWN0LmVudHJpZXMocmVzb3VyY2VzKS5maW5kKFxuICAgICAgKFtfLCByXTogW3N0cmluZywgYW55XSkgPT4ge1xuICAgICAgICBjb25zdCBzZXJ2aWNlTmFtZSA9IHRoaXMuZ2V0U2VydmljZU5hbWUoci5Qcm9wZXJ0aWVzPy5TZXJ2aWNlTmFtZSk7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgci5UeXBlID09PSAnQVdTOjpFQzI6OlZQQ0VuZHBvaW50JyAmJlxuICAgICAgICAgIHNlcnZpY2VOYW1lICYmXG4gICAgICAgICAgc2VydmljZU5hbWUuaW5jbHVkZXMoJ2NvbnNvbGUnKVxuICAgICAgICApO1xuICAgICAgfVxuICAgICk7XG5cbiAgICBjb25zdCBzaWduaW5FbmRwb2ludCA9IE9iamVjdC5lbnRyaWVzKHJlc291cmNlcykuZmluZChcbiAgICAgIChbXywgcl06IFtzdHJpbmcsIGFueV0pID0+IHtcbiAgICAgICAgY29uc3Qgc2VydmljZU5hbWUgPSB0aGlzLmdldFNlcnZpY2VOYW1lKHIuUHJvcGVydGllcz8uU2VydmljZU5hbWUpO1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIHIuVHlwZSA9PT0gJ0FXUzo6RUMyOjpWUENFbmRwb2ludCcgJiZcbiAgICAgICAgICBzZXJ2aWNlTmFtZSAmJlxuICAgICAgICAgIHNlcnZpY2VOYW1lLmluY2x1ZGVzKCdzaWduaW4nKVxuICAgICAgICApO1xuICAgICAgfVxuICAgICk7XG5cbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBlbmRwb2ludF0gb2YgW1xuICAgICAgWydDb25zb2xlJywgY29uc29sZUVuZHBvaW50XSxcbiAgICAgIFsnU2lnbmluJywgc2lnbmluRW5kcG9pbnRdLFxuICAgIF0pIHtcbiAgICAgIGlmICghZW5kcG9pbnQpIGNvbnRpbnVlO1xuXG4gICAgICBjb25zdCBbXywgcmVzb3VyY2VdID0gZW5kcG9pbnQgYXMgW3N0cmluZywgYW55XTtcbiAgICAgIGNvbnN0IGhhc1BvbGljeSA9IHJlc291cmNlLlByb3BlcnRpZXM/LlBvbGljeURvY3VtZW50O1xuXG4gICAgICB0aGlzLmNoZWNrcy5wdXNoKHtcbiAgICAgICAgbmFtZTogYEVuZHBvaW50IFBvbGljeTogJHtuYW1lfWAsXG4gICAgICAgIHN0YXR1czogaGFzUG9saWN5ID8gJ3Bhc3MnIDogJ2ZhaWwnLFxuICAgICAgICBtZXNzYWdlOiBoYXNQb2xpY3lcbiAgICAgICAgICA/IGAke25hbWV9IGVuZHBvaW50IGhhcyBhIHBvbGljeSBhdHRhY2hlZGBcbiAgICAgICAgICA6IGAke25hbWV9IGVuZHBvaW50IGlzIG1pc3NpbmcgYSBwb2xpY3lgLFxuICAgICAgICBkZXRhaWxzOiBoYXNQb2xpY3lcbiAgICAgICAgICA/IHRoaXMudmFsaWRhdGVQb2xpY3lDb250ZW50KHJlc291cmNlLlByb3BlcnRpZXMuUG9saWN5RG9jdW1lbnQpXG4gICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlUG9saWN5Q29udGVudChwb2xpY3k6IGFueSk6IHN0cmluZyB7XG4gICAgaWYgKCFwb2xpY3kuU3RhdGVtZW50IHx8IHBvbGljeS5TdGF0ZW1lbnQubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gJ1BvbGljeSBoYXMgbm8gc3RhdGVtZW50cyc7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdGVtZW50ID0gcG9saWN5LlN0YXRlbWVudFswXTtcbiAgICBjb25zdCBoYXNBY2NvdW50Q29uZGl0aW9uID0gc3RhdGVtZW50LkNvbmRpdGlvbj8uU3RyaW5nRXF1YWxzPy5bJ2F3czpQcmluY2lwYWxBY2NvdW50J107XG5cbiAgICBpZiAoaGFzQWNjb3VudENvbmRpdGlvbikge1xuICAgICAgcmV0dXJuICdQb2xpY3kgcmVzdHJpY3RzIGFjY2VzcyB0byBzcGVjaWZpYyBhY2NvdW50KHMpJztcbiAgICB9XG5cbiAgICByZXR1cm4gJ1BvbGljeSBkb2VzIG5vdCByZXN0cmljdCBhY2Nlc3MgYnkgYWNjb3VudCc7XG4gIH1cblxuICBwcml2YXRlIGNoZWNrUm91dGU1M0hvc3RlZFpvbmVzKCk6IHZvaWQge1xuICAgIGNvbnN0IHJlc291cmNlcyA9IHRoaXMudGVtcGxhdGUuUmVzb3VyY2VzIHx8IHt9O1xuICAgIGNvbnN0IGhvc3RlZFpvbmVzID0gT2JqZWN0LnZhbHVlcyhyZXNvdXJjZXMpLmZpbHRlcihcbiAgICAgIChyOiBhbnkpID0+IHIuVHlwZSA9PT0gJ0FXUzo6Um91dGU1Mzo6SG9zdGVkWm9uZSdcbiAgICApO1xuXG4gICAgY29uc3QgcmVxdWlyZWRab25lcyA9IFsnY29uc29sZS5hd3MuYW1hem9uLmNvbScsICdzaWduaW4uYXdzLmFtYXpvbi5jb20nXTtcblxuICAgIGZvciAoY29uc3Qgem9uZSBvZiByZXF1aXJlZFpvbmVzKSB7XG4gICAgICBjb25zdCBmb3VuZCA9IGhvc3RlZFpvbmVzLnNvbWUoKGh6OiBhbnkpID0+IHtcbiAgICAgICAgY29uc3Qgem9uZU5hbWUgPSBoei5Qcm9wZXJ0aWVzPy5OYW1lO1xuICAgICAgICAvLyBSb3V0ZTUzIHpvbmUgbmFtZXMgbWF5IGhhdmUgYSB0cmFpbGluZyBkb3RcbiAgICAgICAgcmV0dXJuIHpvbmVOYW1lID09PSB6b25lIHx8IHpvbmVOYW1lID09PSBgJHt6b25lfS5gO1xuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuY2hlY2tzLnB1c2goe1xuICAgICAgICBuYW1lOiBgUm91dGU1MyBIb3N0ZWQgWm9uZTogJHt6b25lfWAsXG4gICAgICAgIHN0YXR1czogZm91bmQgPyAncGFzcycgOiAnZmFpbCcsXG4gICAgICAgIG1lc3NhZ2U6IGZvdW5kXG4gICAgICAgICAgPyBgUHJpdmF0ZSBob3N0ZWQgem9uZSBmb3IgJHt6b25lfSBmb3VuZGBcbiAgICAgICAgICA6IGBNaXNzaW5nIHByaXZhdGUgaG9zdGVkIHpvbmUgZm9yICR7em9uZX1gLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgZm9yIFJvdXRlNTMgcmVjb3Jkc1xuICAgIGNvbnN0IHJlY29yZFNldHMgPSBPYmplY3QudmFsdWVzKHJlc291cmNlcykuZmlsdGVyKFxuICAgICAgKHI6IGFueSkgPT4gci5UeXBlID09PSAnQVdTOjpSb3V0ZTUzOjpSZWNvcmRTZXQnXG4gICAgKTtcblxuICAgIHRoaXMuY2hlY2tzLnB1c2goe1xuICAgICAgbmFtZTogJ1JvdXRlNTMgUmVjb3JkcycsXG4gICAgICBzdGF0dXM6IHJlY29yZFNldHMubGVuZ3RoID4gMCA/ICdwYXNzJyA6ICd3YXJuaW5nJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgIHJlY29yZFNldHMubGVuZ3RoID4gMFxuICAgICAgICAgID8gYEZvdW5kICR7cmVjb3JkU2V0cy5sZW5ndGh9IFJvdXRlNTMgcmVjb3Jkc2BcbiAgICAgICAgICA6ICdObyBSb3V0ZTUzIHJlY29yZHMgZm91bmQnLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjaGVja1NlY3VyaXR5R3JvdXBzKCk6IHZvaWQge1xuICAgIGNvbnN0IHJlc291cmNlcyA9IHRoaXMudGVtcGxhdGUuUmVzb3VyY2VzIHx8IHt9O1xuICAgIGNvbnN0IHNlY3VyaXR5R3JvdXBzID0gT2JqZWN0LnZhbHVlcyhyZXNvdXJjZXMpLmZpbHRlcihcbiAgICAgIChyOiBhbnkpID0+IHIuVHlwZSA9PT0gJ0FXUzo6RUMyOjpTZWN1cml0eUdyb3VwJ1xuICAgICk7XG5cbiAgICBjb25zdCBoYXNIdHRwc0luZ3Jlc3MgPSBzZWN1cml0eUdyb3Vwcy5zb21lKChzZzogYW55KSA9PiB7XG4gICAgICBjb25zdCBpbmdyZXNzID0gc2cuUHJvcGVydGllcz8uU2VjdXJpdHlHcm91cEluZ3Jlc3MgfHwgW107XG4gICAgICByZXR1cm4gaW5ncmVzcy5zb21lKFxuICAgICAgICAocnVsZTogYW55KSA9PlxuICAgICAgICAgIChydWxlLkZyb21Qb3J0ID09PSA0NDMgfHwgcnVsZS5JcFByb3RvY29sID09PSAndGNwJykgJiZcbiAgICAgICAgICAocnVsZS5Ub1BvcnQgPT09IDQ0MyB8fCBydWxlLklwUHJvdG9jb2wgPT09ICd0Y3AnKVxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIHRoaXMuY2hlY2tzLnB1c2goe1xuICAgICAgbmFtZTogJ1NlY3VyaXR5IEdyb3VwOiBIVFRQUyBBY2Nlc3MnLFxuICAgICAgc3RhdHVzOiBoYXNIdHRwc0luZ3Jlc3MgPyAncGFzcycgOiAnd2FybmluZycsXG4gICAgICBtZXNzYWdlOiBoYXNIdHRwc0luZ3Jlc3NcbiAgICAgICAgPyAnU2VjdXJpdHkgZ3JvdXAgYWxsb3dzIEhUVFBTIChwb3J0IDQ0MykgdHJhZmZpYydcbiAgICAgICAgOiAnTm8gc2VjdXJpdHkgZ3JvdXAgcnVsZSBmb3VuZCBmb3IgSFRUUFMgKHBvcnQgNDQzKScsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNoZWNrRWMySW5zdGFuY2UoKTogdm9pZCB7XG4gICAgY29uc3QgcmVzb3VyY2VzID0gdGhpcy50ZW1wbGF0ZS5SZXNvdXJjZXMgfHwge307XG4gICAgY29uc3QgaW5zdGFuY2UgPSBPYmplY3QudmFsdWVzKHJlc291cmNlcykuZmluZCgocjogYW55KSA9PiByLlR5cGUgPT09ICdBV1M6OkVDMjo6SW5zdGFuY2UnKTtcblxuICAgIHRoaXMuY2hlY2tzLnB1c2goe1xuICAgICAgbmFtZTogJ0VDMiBJbnN0YW5jZScsXG4gICAgICBzdGF0dXM6IGluc3RhbmNlID8gJ3Bhc3MnIDogJ3dhcm5pbmcnLFxuICAgICAgbWVzc2FnZTogaW5zdGFuY2UgPyAnRUMyIGluc3RhbmNlIGZvdW5kJyA6ICdObyBFQzIgaW5zdGFuY2UgZm91bmQgKG9wdGlvbmFsKScsXG4gICAgfSk7XG5cbiAgICBpZiAoaW5zdGFuY2UpIHtcbiAgICAgIGNvbnN0IGhhc0lhbVJvbGUgPSAoaW5zdGFuY2UgYXMgYW55KS5Qcm9wZXJ0aWVzPy5JYW1JbnN0YW5jZVByb2ZpbGU7XG4gICAgICB0aGlzLmNoZWNrcy5wdXNoKHtcbiAgICAgICAgbmFtZTogJ0VDMiBJQU0gUm9sZScsXG4gICAgICAgIHN0YXR1czogaGFzSWFtUm9sZSA/ICdwYXNzJyA6ICd3YXJuaW5nJyxcbiAgICAgICAgbWVzc2FnZTogaGFzSWFtUm9sZVxuICAgICAgICAgID8gJ0VDMiBpbnN0YW5jZSBoYXMgSUFNIGluc3RhbmNlIHByb2ZpbGUnXG4gICAgICAgICAgOiAnRUMyIGluc3RhbmNlIG1pc3NpbmcgSUFNIGluc3RhbmNlIHByb2ZpbGUnLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjaGVja05hdEdhdGV3YXkoKTogdm9pZCB7XG4gICAgY29uc3QgcmVzb3VyY2VzID0gdGhpcy50ZW1wbGF0ZS5SZXNvdXJjZXMgfHwge307XG4gICAgY29uc3QgbmF0R2F0ZXdheSA9IE9iamVjdC52YWx1ZXMocmVzb3VyY2VzKS5maW5kKChyOiBhbnkpID0+IHIuVHlwZSA9PT0gJ0FXUzo6RUMyOjpOYXRHYXRld2F5Jyk7XG5cbiAgICB0aGlzLmNoZWNrcy5wdXNoKHtcbiAgICAgIG5hbWU6ICdOQVQgR2F0ZXdheScsXG4gICAgICBzdGF0dXM6IG5hdEdhdGV3YXkgPyAncGFzcycgOiAnd2FybmluZycsXG4gICAgICBtZXNzYWdlOiBuYXRHYXRld2F5XG4gICAgICAgID8gJ05BVCBHYXRld2F5IGZvdW5kIGZvciBwcml2YXRlIHN1Ym5ldCBlZ3Jlc3MnXG4gICAgICAgIDogJ05vIE5BVCBHYXRld2F5IGZvdW5kIChyZXF1aXJlZCBmb3IgcHJpdmF0ZSBzdWJuZXQgaW50ZXJuZXQgYWNjZXNzKScsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNoZWNrTmV0d29ya0NvbmZpZ3VyYXRpb24oKTogdm9pZCB7XG4gICAgY29uc3QgcmVzb3VyY2VzID0gdGhpcy50ZW1wbGF0ZS5SZXNvdXJjZXMgfHwge307XG5cbiAgICAvLyBDaGVjayBmb3IgcHJpdmF0ZSBzdWJuZXRzXG4gICAgY29uc3QgcHJpdmF0ZVN1Ym5ldHMgPSBPYmplY3QudmFsdWVzKHJlc291cmNlcykuZmlsdGVyKFxuICAgICAgKHI6IGFueSkgPT5cbiAgICAgICAgci5UeXBlID09PSAnQVdTOjpFQzI6OlN1Ym5ldCcgJiZcbiAgICAgICAgIXIuUHJvcGVydGllcz8uTWFwUHVibGljSXBPbkxhdW5jaFxuICAgICk7XG5cbiAgICB0aGlzLmNoZWNrcy5wdXNoKHtcbiAgICAgIG5hbWU6ICdQcml2YXRlIFN1Ym5ldHMnLFxuICAgICAgc3RhdHVzOiBwcml2YXRlU3VibmV0cy5sZW5ndGggPiAwID8gJ3Bhc3MnIDogJ2ZhaWwnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgcHJpdmF0ZVN1Ym5ldHMubGVuZ3RoID4gMFxuICAgICAgICAgID8gYEZvdW5kICR7cHJpdmF0ZVN1Ym5ldHMubGVuZ3RofSBwcml2YXRlIHN1Ym5ldChzKWBcbiAgICAgICAgICA6ICdObyBwcml2YXRlIHN1Ym5ldHMgZm91bmQnLFxuICAgIH0pO1xuXG4gICAgLy8gQ2hlY2sgZm9yIHJvdXRlIHRhYmxlc1xuICAgIGNvbnN0IHJvdXRlVGFibGVzID0gT2JqZWN0LnZhbHVlcyhyZXNvdXJjZXMpLmZpbHRlcihcbiAgICAgIChyOiBhbnkpID0+IHIuVHlwZSA9PT0gJ0FXUzo6RUMyOjpSb3V0ZVRhYmxlJ1xuICAgICk7XG5cbiAgICB0aGlzLmNoZWNrcy5wdXNoKHtcbiAgICAgIG5hbWU6ICdSb3V0ZSBUYWJsZXMnLFxuICAgICAgc3RhdHVzOiByb3V0ZVRhYmxlcy5sZW5ndGggPiAwID8gJ3Bhc3MnIDogJ3dhcm5pbmcnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgcm91dGVUYWJsZXMubGVuZ3RoID4gMFxuICAgICAgICAgID8gYEZvdW5kICR7cm91dGVUYWJsZXMubGVuZ3RofSByb3V0ZSB0YWJsZShzKWBcbiAgICAgICAgICA6ICdObyByb3V0ZSB0YWJsZXMgZm91bmQnLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZW5lcmF0ZVN1bW1hcnkodmFsaWQ6IGJvb2xlYW4sIGZhaWxDb3VudDogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBjb25zdCBwYXNzQ291bnQgPSB0aGlzLmNoZWNrcy5maWx0ZXIoYyA9PiBjLnN0YXR1cyA9PT0gJ3Bhc3MnKS5sZW5ndGg7XG4gICAgY29uc3Qgd2FybmluZ0NvdW50ID0gdGhpcy5jaGVja3MuZmlsdGVyKGMgPT4gYy5zdGF0dXMgPT09ICd3YXJuaW5nJykubGVuZ3RoO1xuXG4gICAgaWYgKHZhbGlkKSB7XG4gICAgICByZXR1cm4gYOKckyBWYWxpZGF0aW9uIHBhc3NlZC4gQWxsIHJlcXVpcmVkIGNoZWNrcyBwYXNzZWQgKCR7cGFzc0NvdW50fSBwYXNzZWQsICR7d2FybmluZ0NvdW50fSB3YXJuaW5ncykuYDtcbiAgICB9XG5cbiAgICByZXR1cm4gYOKclyBWYWxpZGF0aW9uIGZhaWxlZC4gJHtmYWlsQ291bnR9IGNoZWNrKHMpIGZhaWxlZCwgJHtwYXNzQ291bnR9IHBhc3NlZCwgJHt3YXJuaW5nQ291bnR9IHdhcm5pbmdzLmA7XG4gIH1cbn1cbiJdfQ==
|