UNPKG

53.7 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.Role = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const core_1 = require("@aws-cdk/core");
8const constructs_1 = require("constructs");
9const grant_1 = require("./grant");
10const iam_generated_1 = require("./iam.generated");
11const policy_1 = require("./policy");
12const policy_document_1 = require("./policy-document");
13const principals_1 = require("./principals");
14const assume_role_policy_1 = require("./private/assume-role-policy");
15const immutable_role_1 = require("./private/immutable-role");
16const policydoc_adapter_1 = require("./private/policydoc-adapter");
17const util_1 = require("./util");
18/**
19 * IAM Role
20 *
21 * Defines an IAM role. The role is created with an assume policy document associated with
22 * the specified AWS service principal defined in `serviceAssumeRole`.
23 */
24class Role extends core_1.Resource {
25 constructor(scope, id, props) {
26 var _b;
27 super(scope, id, {
28 physicalName: props.roleName,
29 });
30 this.grantPrincipal = this;
31 this.principalAccount = this.env.account;
32 this.assumeRoleAction = 'sts:AssumeRole';
33 this.managedPolicies = [];
34 this.attachedPolicies = new util_1.AttachedPolicies();
35 try {
36 jsiiDeprecationWarnings._aws_cdk_aws_iam_RoleProps(props);
37 }
38 catch (error) {
39 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
40 Error.captureStackTrace(error, this.constructor);
41 }
42 throw error;
43 }
44 const externalIds = props.externalIds || [];
45 if (props.externalId) {
46 externalIds.push(props.externalId);
47 }
48 this.assumeRolePolicy = createAssumeRolePolicy(props.assumedBy, externalIds);
49 this.managedPolicies.push(...props.managedPolicies || []);
50 this.inlinePolicies = props.inlinePolicies || {};
51 this.permissionsBoundary = props.permissionsBoundary;
52 const maxSessionDuration = props.maxSessionDuration && props.maxSessionDuration.toSeconds();
53 validateMaxSessionDuration(maxSessionDuration);
54 const description = (props.description && ((_b = props.description) === null || _b === void 0 ? void 0 : _b.length) > 0) ? props.description : undefined;
55 if (description && description.length > 1000) {
56 throw new Error('Role description must be no longer than 1000 characters.');
57 }
58 const role = new iam_generated_1.CfnRole(this, 'Resource', {
59 assumeRolePolicyDocument: this.assumeRolePolicy,
60 managedPolicyArns: util_1.UniqueStringSet.from(() => this.managedPolicies.map(p => p.managedPolicyArn)),
61 policies: _flatten(this.inlinePolicies),
62 path: props.path,
63 permissionsBoundary: this.permissionsBoundary ? this.permissionsBoundary.managedPolicyArn : undefined,
64 roleName: this.physicalName,
65 maxSessionDuration,
66 description,
67 });
68 this.roleId = role.attrRoleId;
69 this.roleArn = this.getResourceArnAttribute(role.attrArn, {
70 region: '',
71 service: 'iam',
72 resource: 'role',
73 // Removes leading slash from path
74 resourceName: `${props.path ? props.path.substr(props.path.charAt(0) === '/' ? 1 : 0) : ''}${this.physicalName}`,
75 });
76 this.roleName = this.getResourceNameAttribute(role.ref);
77 this.policyFragment = new principals_1.ArnPrincipal(this.roleArn).policyFragment;
78 function _flatten(policies) {
79 if (policies == null || Object.keys(policies).length === 0) {
80 return undefined;
81 }
82 const result = new Array();
83 for (const policyName of Object.keys(policies)) {
84 const policyDocument = policies[policyName];
85 result.push({ policyName, policyDocument });
86 }
87 return result;
88 }
89 }
90 /**
91 * Import an external role by ARN.
92 *
93 * If the imported Role ARN is a Token (such as a
94 * `CfnParameter.valueAsString` or a `Fn.importValue()`) *and* the referenced
95 * role has a `path` (like `arn:...:role/AdminRoles/Alice`), the
96 * `roleName` property will not resolve to the correct value. Instead it
97 * will resolve to the first path component. We unfortunately cannot express
98 * the correct calculation of the full path name as a CloudFormation
99 * expression. In this scenario the Role ARN should be supplied without the
100 * `path` in order to resolve the correct role resource.
101 *
102 * @param scope construct scope
103 * @param id construct id
104 * @param roleArn the ARN of the role to import
105 * @param options allow customizing the behavior of the returned role
106 */
107 static fromRoleArn(scope, id, roleArn, options = {}) {
108 var _b;
109 try {
110 jsiiDeprecationWarnings._aws_cdk_aws_iam_FromRoleArnOptions(options);
111 }
112 catch (error) {
113 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
114 Error.captureStackTrace(error, this.fromRoleArn);
115 }
116 throw error;
117 }
118 const scopeStack = core_1.Stack.of(scope);
119 const parsedArn = scopeStack.splitArn(roleArn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
120 const resourceName = parsedArn.resourceName;
121 const roleAccount = parsedArn.account;
122 // service roles have an ARN like 'arn:aws:iam::<account>:role/service-role/<roleName>'
123 // or 'arn:aws:iam::<account>:role/service-role/servicename.amazonaws.com/service-role/<roleName>'
124 // we want to support these as well, so we just use the element after the last slash as role name
125 const roleName = resourceName.split('/').pop();
126 class Import extends core_1.Resource {
127 constructor(_scope, _id) {
128 super(_scope, _id, {
129 account: roleAccount,
130 });
131 this.grantPrincipal = this;
132 this.principalAccount = roleAccount;
133 this.assumeRoleAction = 'sts:AssumeRole';
134 this.policyFragment = new principals_1.ArnPrincipal(roleArn).policyFragment;
135 this.roleArn = roleArn;
136 this.roleName = roleName;
137 this.attachedPolicies = new util_1.AttachedPolicies();
138 }
139 addToPolicy(statement) {
140 return this.addToPrincipalPolicy(statement).statementAdded;
141 }
142 addToPrincipalPolicy(statement) {
143 if (!this.defaultPolicy) {
144 this.defaultPolicy = new policy_1.Policy(this, 'Policy');
145 this.attachInlinePolicy(this.defaultPolicy);
146 }
147 this.defaultPolicy.addStatements(statement);
148 return { statementAdded: true, policyDependable: this.defaultPolicy };
149 }
150 attachInlinePolicy(policy) {
151 const thisAndPolicyAccountComparison = core_1.Token.compareStrings(this.env.account, policy.env.account);
152 const equalOrAnyUnresolved = thisAndPolicyAccountComparison === core_1.TokenComparison.SAME ||
153 thisAndPolicyAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
154 thisAndPolicyAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
155 if (equalOrAnyUnresolved) {
156 this.attachedPolicies.attach(policy);
157 policy.attachToRole(this);
158 }
159 }
160 addManagedPolicy(_policy) {
161 // FIXME: Add warning that we're ignoring this
162 }
163 /**
164 * Grant permissions to the given principal to pass this role.
165 */
166 grantPassRole(identity) {
167 return this.grant(identity, 'iam:PassRole');
168 }
169 /**
170 * Grant the actions defined in actions to the identity Principal on this resource.
171 */
172 grant(grantee, ...actions) {
173 return grant_1.Grant.addToPrincipal({
174 grantee,
175 actions,
176 resourceArns: [this.roleArn],
177 scope: this,
178 });
179 }
180 }
181 if (options.addGrantsToResources !== undefined && options.mutable !== false) {
182 throw new Error('\'addGrantsToResources\' can only be passed if \'mutable: false\'');
183 }
184 const importedRole = new Import(scope, id);
185 const roleArnAndScopeStackAccountComparison = core_1.Token.compareStrings(importedRole.env.account, scopeStack.account);
186 const equalOrAnyUnresolved = roleArnAndScopeStackAccountComparison === core_1.TokenComparison.SAME ||
187 roleArnAndScopeStackAccountComparison === core_1.TokenComparison.BOTH_UNRESOLVED ||
188 roleArnAndScopeStackAccountComparison === core_1.TokenComparison.ONE_UNRESOLVED;
189 // we only return an immutable Role if both accounts were explicitly provided, and different
190 return options.mutable !== false && equalOrAnyUnresolved
191 ? importedRole
192 : new immutable_role_1.ImmutableRole(scope, `ImmutableRole${id}`, importedRole, (_b = options.addGrantsToResources) !== null && _b !== void 0 ? _b : false);
193 }
194 /**
195 * Import an external role by name.
196 *
197 * The imported role is assumed to exist in the same account as the account
198 * the scope's containing Stack is being deployed to.
199 */
200 static fromRoleName(scope, id, roleName) {
201 return Role.fromRoleArn(scope, id, core_1.Stack.of(scope).formatArn({
202 region: '',
203 service: 'iam',
204 resource: 'role',
205 resourceName: roleName,
206 }));
207 }
208 /**
209 * Adds a permission to the role's default policy document.
210 * If there is no default policy attached to this role, it will be created.
211 * @param statement The permission statement to add to the policy document
212 */
213 addToPrincipalPolicy(statement) {
214 try {
215 jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
216 }
217 catch (error) {
218 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
219 Error.captureStackTrace(error, this.addToPrincipalPolicy);
220 }
221 throw error;
222 }
223 if (!this.defaultPolicy) {
224 this.defaultPolicy = new policy_1.Policy(this, 'DefaultPolicy');
225 this.attachInlinePolicy(this.defaultPolicy);
226 }
227 this.defaultPolicy.addStatements(statement);
228 return { statementAdded: true, policyDependable: this.defaultPolicy };
229 }
230 addToPolicy(statement) {
231 try {
232 jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
233 }
234 catch (error) {
235 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
236 Error.captureStackTrace(error, this.addToPolicy);
237 }
238 throw error;
239 }
240 return this.addToPrincipalPolicy(statement).statementAdded;
241 }
242 /**
243 * Attaches a managed policy to this role.
244 * @param policy The the managed policy to attach.
245 */
246 addManagedPolicy(policy) {
247 try {
248 jsiiDeprecationWarnings._aws_cdk_aws_iam_IManagedPolicy(policy);
249 }
250 catch (error) {
251 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
252 Error.captureStackTrace(error, this.addManagedPolicy);
253 }
254 throw error;
255 }
256 if (this.managedPolicies.find(mp => mp === policy)) {
257 return;
258 }
259 this.managedPolicies.push(policy);
260 }
261 /**
262 * Attaches a policy to this role.
263 * @param policy The policy to attach
264 */
265 attachInlinePolicy(policy) {
266 try {
267 jsiiDeprecationWarnings._aws_cdk_aws_iam_Policy(policy);
268 }
269 catch (error) {
270 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
271 Error.captureStackTrace(error, this.attachInlinePolicy);
272 }
273 throw error;
274 }
275 this.attachedPolicies.attach(policy);
276 policy.attachToRole(this);
277 }
278 /**
279 * Grant the actions defined in actions to the identity Principal on this resource.
280 */
281 grant(grantee, ...actions) {
282 try {
283 jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(grantee);
284 }
285 catch (error) {
286 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
287 Error.captureStackTrace(error, this.grant);
288 }
289 throw error;
290 }
291 return grant_1.Grant.addToPrincipal({
292 grantee,
293 actions,
294 resourceArns: [this.roleArn],
295 scope: this,
296 });
297 }
298 /**
299 * Grant permissions to the given principal to pass this role.
300 */
301 grantPassRole(identity) {
302 try {
303 jsiiDeprecationWarnings._aws_cdk_aws_iam_IPrincipal(identity);
304 }
305 catch (error) {
306 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
307 Error.captureStackTrace(error, this.grantPassRole);
308 }
309 throw error;
310 }
311 return this.grant(identity, 'iam:PassRole');
312 }
313 /**
314 * Return a copy of this Role object whose Policies will not be updated
315 *
316 * Use the object returned by this method if you want this Role to be used by
317 * a construct without it automatically updating the Role's Policies.
318 *
319 * If you do, you are responsible for adding the correct statements to the
320 * Role's policies yourself.
321 */
322 withoutPolicyUpdates(options = {}) {
323 var _b;
324 try {
325 jsiiDeprecationWarnings._aws_cdk_aws_iam_WithoutPolicyUpdatesOptions(options);
326 }
327 catch (error) {
328 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
329 Error.captureStackTrace(error, this.withoutPolicyUpdates);
330 }
331 throw error;
332 }
333 if (!this.immutableRole) {
334 this.immutableRole = new immutable_role_1.ImmutableRole(constructs_1.Node.of(this).scope, `ImmutableRole${this.node.id}`, this, (_b = options.addGrantsToResources) !== null && _b !== void 0 ? _b : false);
335 }
336 return this.immutableRole;
337 }
338 validate() {
339 var _b;
340 const errors = super.validate();
341 errors.push(...((_b = this.assumeRolePolicy) === null || _b === void 0 ? void 0 : _b.validateForResourcePolicy()) || []);
342 for (const policy of Object.values(this.inlinePolicies)) {
343 errors.push(...policy.validateForIdentityPolicy());
344 }
345 return errors;
346 }
347}
348exports.Role = Role;
349_a = JSII_RTTI_SYMBOL_1;
350Role[_a] = { fqn: "@aws-cdk/aws-iam.Role", version: "1.156.1" };
351function createAssumeRolePolicy(principal, externalIds) {
352 const actualDoc = new policy_document_1.PolicyDocument();
353 // If requested, add externalIds to every statement added to this doc
354 const addDoc = externalIds.length === 0
355 ? actualDoc
356 : new policydoc_adapter_1.MutatingPolicyDocumentAdapter(actualDoc, (statement) => {
357 statement.addCondition('StringEquals', {
358 'sts:ExternalId': externalIds.length === 1 ? externalIds[0] : externalIds,
359 });
360 return statement;
361 });
362 assume_role_policy_1.defaultAddPrincipalToAssumeRole(principal, addDoc);
363 return actualDoc;
364}
365function validateMaxSessionDuration(duration) {
366 if (duration === undefined) {
367 return;
368 }
369 if (duration < 3600 || duration > 43200) {
370 throw new Error(`maxSessionDuration is set to ${duration}, but must be >= 3600sec (1hr) and <= 43200sec (12hrs)`);
371 }
372}
373//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9sZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJvbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsd0NBQTZGO0FBQzdGLDJDQUE2QztBQUM3QyxtQ0FBZ0M7QUFDaEMsbURBQTBDO0FBRzFDLHFDQUFrQztBQUNsQyx1REFBbUQ7QUFFbkQsNkNBQTZHO0FBQzdHLHFFQUErRTtBQUMvRSw2REFBeUQ7QUFDekQsbUVBQTRFO0FBQzVFLGlDQUEyRDtBQXNKM0Q7Ozs7O0dBS0c7QUFDSCxNQUFhLElBQUssU0FBUSxlQUFRO0lBc0toQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQWdCOztRQUN4RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLFlBQVksRUFBRSxLQUFLLENBQUMsUUFBUTtTQUM3QixDQUFDLENBQUM7UUEvQ1csbUJBQWMsR0FBZSxJQUFJLENBQUM7UUFDbEMscUJBQWdCLEdBQXVCLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO1FBRXhELHFCQUFnQixHQUFXLGdCQUFnQixDQUFDO1FBb0MzQyxvQkFBZSxHQUFxQixFQUFFLENBQUM7UUFDdkMscUJBQWdCLEdBQUcsSUFBSSx1QkFBZ0IsRUFBRSxDQUFDOzs7Ozs7Ozs7O1FBU3pELE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO1FBQzVDLElBQUksS0FBSyxDQUFDLFVBQVUsRUFBRTtZQUNwQixXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztTQUNwQztRQUVELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQzdFLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDLGVBQWUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsY0FBYyxHQUFHLEtBQUssQ0FBQyxjQUFjLElBQUksRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxtQkFBbUIsR0FBRyxLQUFLLENBQUMsbUJBQW1CLENBQUM7UUFDckQsTUFBTSxrQkFBa0IsR0FBRyxLQUFLLENBQUMsa0JBQWtCLElBQUksS0FBSyxDQUFDLGtCQUFrQixDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQzVGLDBCQUEwQixDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDL0MsTUFBTSxXQUFXLEdBQUcsQ0FBQyxLQUFLLENBQUMsV0FBVyxJQUFJLE9BQUEsS0FBSyxDQUFDLFdBQVcsMENBQUUsTUFBTSxJQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFFekcsSUFBSSxXQUFXLElBQUksV0FBVyxDQUFDLE1BQU0sR0FBRyxJQUFJLEVBQUU7WUFDNUMsTUFBTSxJQUFJLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO1NBQzdFO1FBRUQsTUFBTSxJQUFJLEdBQUcsSUFBSSx1QkFBTyxDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7WUFDekMsd0JBQXdCLEVBQUUsSUFBSSxDQUFDLGdCQUF1QjtZQUN0RCxpQkFBaUIsRUFBRSxzQkFBZSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1lBQ2hHLFFBQVEsRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQztZQUN2QyxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7WUFDaEIsbUJBQW1CLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLFNBQVM7WUFDckcsUUFBUSxFQUFFLElBQUksQ0FBQyxZQUFZO1lBQzNCLGtCQUFrQjtZQUNsQixXQUFXO1NBQ1osQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQzlCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDeEQsTUFBTSxFQUFFLEVBQUU7WUFDVixPQUFPLEVBQUUsS0FBSztZQUNkLFFBQVEsRUFBRSxNQUFNO1lBQ2hCLGtDQUFrQztZQUNsQyxZQUFZLEVBQUUsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFO1NBQ2pILENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUkseUJBQVksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsY0FBYyxDQUFDO1FBRXBFLFNBQVMsUUFBUSxDQUFDLFFBQTZDO1lBQzdELElBQUksUUFBUSxJQUFJLElBQUksSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7Z0JBQzFELE9BQU8sU0FBUyxDQUFDO2FBQ2xCO1lBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBSSxLQUFLLEVBQTBCLENBQUM7WUFDbkQsS0FBSyxNQUFNLFVBQVUsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFO2dCQUM5QyxNQUFNLGNBQWMsR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQzVDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQzthQUM3QztZQUNELE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7S0FDRjtJQTVORDs7Ozs7Ozs7Ozs7Ozs7OztPQWdCRztJQUNJLE1BQU0sQ0FBQyxXQUFXLENBQUMsS0FBZ0IsRUFBRSxFQUFVLEVBQUUsT0FBZSxFQUFFLFVBQThCLEVBQUU7Ozs7Ozs7Ozs7O1FBQ3ZHLE1BQU0sVUFBVSxHQUFHLFlBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsZ0JBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQzlFLE1BQU0sWUFBWSxHQUFHLFNBQVMsQ0FBQyxZQUFhLENBQUM7UUFDN0MsTUFBTSxXQUFXLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQztRQUN0Qyx1RkFBdUY7UUFDdkYsa0dBQWtHO1FBQ2xHLGlHQUFpRztRQUNqRyxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRyxDQUFDO1FBRWhELE1BQU0sTUFBTyxTQUFRLGVBQVE7WUFVM0IsWUFBWSxNQUFpQixFQUFFLEdBQVc7Z0JBQ3hDLEtBQUssQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFO29CQUNqQixPQUFPLEVBQUUsV0FBVztpQkFDckIsQ0FBQyxDQUFDO2dCQVpXLG1CQUFjLEdBQWUsSUFBSSxDQUFDO2dCQUNsQyxxQkFBZ0IsR0FBRyxXQUFXLENBQUM7Z0JBQy9CLHFCQUFnQixHQUFXLGdCQUFnQixDQUFDO2dCQUM1QyxtQkFBYyxHQUFHLElBQUkseUJBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxjQUFjLENBQUM7Z0JBQzFELFlBQU8sR0FBRyxPQUFPLENBQUM7Z0JBQ2xCLGFBQVEsR0FBRyxRQUFRLENBQUM7Z0JBQ25CLHFCQUFnQixHQUFHLElBQUksdUJBQWdCLEVBQUUsQ0FBQztZQU8zRCxDQUFDO1lBRU0sV0FBVyxDQUFDLFNBQTBCO2dCQUMzQyxPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsQ0FBQyxjQUFjLENBQUM7WUFDN0QsQ0FBQztZQUVNLG9CQUFvQixDQUFDLFNBQTBCO2dCQUNwRCxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtvQkFDdkIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLGVBQU0sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7b0JBQ2hELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7aUJBQzdDO2dCQUNELElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUM1QyxPQUFPLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDeEUsQ0FBQztZQUVNLGtCQUFrQixDQUFDLE1BQWM7Z0JBQ3RDLE1BQU0sOEJBQThCLEdBQUcsWUFBSyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNsRyxNQUFNLG9CQUFvQixHQUFHLDhCQUE4QixLQUFLLHNCQUFlLENBQUMsSUFBSTtvQkFDbEYsOEJBQThCLEtBQUssc0JBQWUsQ0FBQyxlQUFlO29CQUNsRSw4QkFBOEIsS0FBSyxzQkFBZSxDQUFDLGNBQWMsQ0FBQztnQkFDcEUsSUFBSSxvQkFBb0IsRUFBRTtvQkFDeEIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDckMsTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDM0I7WUFDSCxDQUFDO1lBRU0sZ0JBQWdCLENBQUMsT0FBdUI7Z0JBQzdDLDhDQUE4QztZQUNoRCxDQUFDO1lBRUQ7O2VBRUc7WUFDSSxhQUFhLENBQUMsUUFBb0I7Z0JBQ3ZDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsY0FBYyxDQUFDLENBQUM7WUFDOUMsQ0FBQztZQUVEOztlQUVHO1lBQ0ksS0FBSyxDQUFDLE9BQW1CLEVBQUUsR0FBRyxPQUFpQjtnQkFDcEQsT0FBTyxhQUFLLENBQUMsY0FBYyxDQUFDO29CQUMxQixPQUFPO29CQUNQLE9BQU87b0JBQ1AsWUFBWSxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztvQkFDNUIsS0FBSyxFQUFFLElBQUk7aUJBQ1osQ0FBQyxDQUFDO1lBQ0wsQ0FBQztTQUNGO1FBRUQsSUFBSSxPQUFPLENBQUMsb0JBQW9CLEtBQUssU0FBUyxJQUFJLE9BQU8sQ0FBQyxPQUFPLEtBQUssS0FBSyxFQUFFO1lBQzNFLE1BQU0sSUFBSSxLQUFLLENBQUMsbUVBQW1FLENBQUMsQ0FBQztTQUN0RjtRQUVELE1BQU0sWUFBWSxHQUFHLElBQUksTUFBTSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUMzQyxNQUFNLHFDQUFxQyxHQUFHLFlBQUssQ0FBQyxjQUFjLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2pILE1BQU0sb0JBQW9CLEdBQUcscUNBQXFDLEtBQUssc0JBQWUsQ0FBQyxJQUFJO1lBQ3pGLHFDQUFxQyxLQUFLLHNCQUFlLENBQUMsZUFBZTtZQUN6RSxxQ0FBcUMsS0FBSyxzQkFBZSxDQUFDLGNBQWMsQ0FBQztRQUMzRSw0RkFBNEY7UUFDNUYsT0FBTyxPQUFPLENBQUMsT0FBTyxLQUFLLEtBQUssSUFBSSxvQkFBb0I7WUFDdEQsQ0FBQyxDQUFDLFlBQVk7WUFDZCxDQUFDLENBQUMsSUFBSSw4QkFBYSxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxFQUFFLEVBQUUsWUFBWSxRQUFFLE9BQU8sQ0FBQyxvQkFBb0IsbUNBQUksS0FBSyxDQUFDLENBQUM7S0FDekc7SUFFRDs7Ozs7T0FLRztJQUNJLE1BQU0sQ0FBQyxZQUFZLENBQUMsS0FBZ0IsRUFBRSxFQUFVLEVBQUUsUUFBZ0I7UUFDdkUsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsWUFBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFDM0QsTUFBTSxFQUFFLEVBQUU7WUFDVixPQUFPLEVBQUUsS0FBSztZQUNkLFFBQVEsRUFBRSxNQUFNO1lBQ2hCLFlBQVksRUFBRSxRQUFRO1NBQ3ZCLENBQUMsQ0FBQyxDQUFDO0tBQ0w7SUF1R0Q7Ozs7T0FJRztJQUNJLG9CQUFvQixDQUFDLFNBQTBCOzs7Ozs7Ozs7O1FBQ3BELElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxlQUFNLENBQUMsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBQ3ZELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7U0FDN0M7UUFDRCxJQUFJLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM1QyxPQUFPLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7S0FDdkU7SUFFTSxXQUFXLENBQUMsU0FBMEI7Ozs7Ozs7Ozs7UUFDM0MsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUMsY0FBYyxDQUFDO0tBQzVEO0lBRUQ7OztPQUdHO0lBQ0ksZ0JBQWdCLENBQUMsTUFBc0I7Ozs7Ozs7Ozs7UUFDNUMsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxNQUFNLENBQUMsRUFBRTtZQUFFLE9BQU87U0FBRTtRQUMvRCxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztLQUNuQztJQUVEOzs7T0FHRztJQUNJLGtCQUFrQixDQUFDLE1BQWM7Ozs7Ozs7Ozs7UUFDdEMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNyQyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO0tBQzNCO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsT0FBbUIsRUFBRSxHQUFHLE9BQWlCOzs7Ozs7Ozs7O1FBQ3BELE9BQU8sYUFBSyxDQUFDLGNBQWMsQ0FBQztZQUMxQixPQUFPO1lBQ1AsT0FBTztZQUNQLFlBQVksRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7WUFDNUIsS0FBSyxFQUFFLElBQUk7U0FDWixDQUFDLENBQUM7S0FDSjtJQUVEOztPQUVHO0lBQ0ksYUFBYSxDQUFDLFFBQW9COzs7Ozs7Ozs7O1FBQ3ZDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsY0FBYyxDQUFDLENBQUM7S0FDN0M7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLG9CQUFvQixDQUFDLFVBQXVDLEVBQUU7Ozs7Ozs7Ozs7O1FBQ25FLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSw4QkFBYSxDQUFDLGlCQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQWtCLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsSUFBSSxRQUFFLE9BQU8sQ0FBQyxvQkFBb0IsbUNBQUksS0FBSyxDQUFDLENBQUM7U0FDdko7UUFFRCxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUM7S0FDM0I7SUFFUyxRQUFROztRQUNoQixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDaEMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQUEsSUFBSSxDQUFDLGdCQUFnQiwwQ0FBRSx5QkFBeUIsT0FBTSxFQUFFLENBQUMsQ0FBQztRQUN6RSxLQUFLLE1BQU0sTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxFQUFFO1lBQ3ZELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxDQUFDO1NBQ3BEO1FBQ0QsT0FBTyxNQUFNLENBQUM7S0FDZjs7QUE5U0gsb0JBK1NDOzs7QUErQkQsU0FBUyxzQkFBc0IsQ0FBQyxTQUFxQixFQUFFLFdBQXFCO0lBQzFFLE1BQU0sU0FBUyxHQUFHLElBQUksZ0NBQWMsRUFBRSxDQUFDO0lBRXZDLHFFQUFxRTtJQUNyRSxNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUM7UUFDckMsQ0FBQyxDQUFDLFNBQVM7UUFDWCxDQUFDLENBQUMsSUFBSSxpREFBNkIsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxTQUFTLEVBQUUsRUFBRTtZQUMzRCxTQUFTLENBQUMsWUFBWSxDQUFDLGNBQWMsRUFBRTtnQkFDckMsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVzthQUMxRSxDQUFDLENBQUM7WUFDSCxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDLENBQUMsQ0FBQztJQUVMLG9EQUErQixDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUVuRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQsU0FBUywwQkFBMEIsQ0FBQyxRQUFpQjtJQUNuRCxJQUFJLFFBQVEsS0FBSyxTQUFTLEVBQUU7UUFDMUIsT0FBTztLQUNSO0lBRUQsSUFBSSxRQUFRLEdBQUcsSUFBSSxJQUFJLFFBQVEsR0FBRyxLQUFLLEVBQUU7UUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsUUFBUSx3REFBd0QsQ0FBQyxDQUFDO0tBQ25IO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFybkZvcm1hdCwgRHVyYXRpb24sIFJlc291cmNlLCBTdGFjaywgVG9rZW4sIFRva2VuQ29tcGFyaXNvbiB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBOb2RlIH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBHcmFudCB9IGZyb20gJy4vZ3JhbnQnO1xuaW1wb3J0IHsgQ2ZuUm9sZSB9IGZyb20gJy4vaWFtLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBJSWRlbnRpdHkgfSBmcm9tICcuL2lkZW50aXR5LWJhc2UnO1xuaW1wb3J0IHsgSU1hbmFnZWRQb2xpY3kgfSBmcm9tICcuL21hbmFnZWQtcG9saWN5JztcbmltcG9ydCB7IFBvbGljeSB9IGZyb20gJy4vcG9saWN5JztcbmltcG9ydCB7IFBvbGljeURvY3VtZW50IH0gZnJvbSAnLi9wb2xpY3ktZG9jdW1lbnQnO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50IH0gZnJvbSAnLi9wb2xpY3ktc3RhdGVtZW50JztcbmltcG9ydCB7IEFkZFRvUHJpbmNpcGFsUG9saWN5UmVzdWx0LCBBcm5QcmluY2lwYWwsIElQcmluY2lwYWwsIFByaW5jaXBhbFBvbGljeUZyYWdtZW50IH0gZnJvbSAnLi9wcmluY2lwYWxzJztcbmltcG9ydCB7IGRlZmF1bHRBZGRQcmluY2lwYWxUb0Fzc3VtZVJvbGUgfSBmcm9tICcuL3ByaXZhdGUvYXNzdW1lLXJvbGUtcG9saWN5JztcbmltcG9ydCB7IEltbXV0YWJsZVJvbGUgfSBmcm9tICcuL3ByaXZhdGUvaW1tdXRhYmxlLXJvbGUnO1xuaW1wb3J0IHsgTXV0YXRpbmdQb2xpY3lEb2N1bWVudEFkYXB0ZXIgfSBmcm9tICcuL3ByaXZhdGUvcG9saWN5ZG9jLWFkYXB0ZXInO1xuaW1wb3J0IHsgQXR0YWNoZWRQb2xpY2llcywgVW5pcXVlU3RyaW5nU2V0IH0gZnJvbSAnLi91dGlsJztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBkZWZpbmluZyBhbiBJQU0gUm9sZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJvbGVQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgSUFNIHByaW5jaXBhbCAoaS5lLiBgbmV3IFNlcnZpY2VQcmluY2lwYWwoJ3Nucy5hbWF6b25hd3MuY29tJylgKVxuICAgKiB3aGljaCBjYW4gYXNzdW1lIHRoaXMgcm9sZS5cbiAgICpcbiAgICogWW91IGNhbiBsYXRlciBtb2RpZnkgdGhlIGFzc3VtZSByb2xlIHBvbGljeSBkb2N1bWVudCBieSBhY2Nlc3NpbmcgaXQgdmlhXG4gICAqIHRoZSBgYXNzdW1lUm9sZVBvbGljeWAgcHJvcGVydHkuXG4gICAqL1xuICByZWFkb25seSBhc3N1bWVkQnk6IElQcmluY2lwYWw7XG5cbiAgLyoqXG4gICAqIElEIHRoYXQgdGhlIHJvbGUgYXNzdW1lciBuZWVkcyB0byBwcm92aWRlIHdoZW4gYXNzdW1pbmcgdGhpcyByb2xlXG4gICAqXG4gICAqIElmIHRoZSBjb25maWd1cmVkIGFuZCBwcm92aWRlZCBleHRlcm5hbCBJRHMgZG8gbm90IG1hdGNoLCB0aGVcbiAgICogQXNzdW1lUm9sZSBvcGVyYXRpb24gd2lsbCBmYWlsLlxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCBzZWUge0BsaW5rIGV4dGVybmFsSWRzfVxuICAgKlxuICAgKiBAZGVmYXVsdCBObyBleHRlcm5hbCBJRCByZXF1aXJlZFxuICAgKi9cbiAgcmVhZG9ubHkgZXh0ZXJuYWxJZD86IHN0cmluZztcblxuICAvKipcbiAgICogTGlzdCBvZiBJRHMgdGhhdCB0aGUgcm9sZSBhc3N1bWVyIG5lZWRzIHRvIHByb3ZpZGUgb25lIG9mIHdoZW4gYXNzdW1pbmcgdGhpcyByb2xlXG4gICAqXG4gICAqIElmIHRoZSBjb25maWd1cmVkIGFuZCBwcm92aWRlZCBleHRlcm5hbCBJRHMgZG8gbm90IG1hdGNoLCB0aGVcbiAgICogQXNzdW1lUm9sZSBvcGVyYXRpb24gd2lsbCBmYWlsLlxuICAgKlxuICAgKiBAZGVmYXVsdCBObyBleHRlcm5hbCBJRCByZXF1aXJlZFxuICAgKi9cbiAgcmVhZG9ubHkgZXh0ZXJuYWxJZHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIG1hbmFnZWQgcG9saWNpZXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgcm9sZS5cbiAgICpcbiAgICogWW91IGNhbiBhZGQgbWFuYWdlZCBwb2xpY2llcyBsYXRlciB1c2luZ1xuICAgKiBgYWRkTWFuYWdlZFBvbGljeShNYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZShwb2xpY3lOYW1lKSlgLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIG1hbmFnZWQgcG9saWNpZXMuXG4gICAqL1xuICByZWFkb25seSBtYW5hZ2VkUG9saWNpZXM/OiBJTWFuYWdlZFBvbGljeVtdO1xuXG4gIC8qKlxuICAgKiBBIGxpc3Qgb2YgbmFtZWQgcG9saWNpZXMgdG8gaW5saW5lIGludG8gdGhpcyByb2xlLiBUaGVzZSBwb2xpY2llcyB3aWxsIGJlXG4gICAqIGNyZWF0ZWQgd2l0aCB0aGUgcm9sZSwgd2hlcmVhcyB0aG9zZSBhZGRlZCBieSBgYGFkZFRvUG9saWN5YGAgYXJlIGFkZGVkXG4gICAqIHVzaW5nIGEgc2VwYXJhdGUgQ2xvdWRGb3JtYXRpb24gcmVzb3VyY2UgKGFsbG93aW5nIGEgd2F5IGFyb3VuZCBjaXJjdWxhclxuICAgKiBkZXBlbmRlbmNpZXMgdGhhdCBjb3VsZCBvdGhlcndpc2UgYmUgaW50cm9kdWNlZCkuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcG9saWN5IGlzIGlubGluZWQgaW4gdGhlIFJvbGUgcmVzb3VyY2UuXG4gICAqL1xuICByZWFkb25seSBpbmxpbmVQb2xpY2llcz86IHsgW25hbWU6IHN0cmluZ106IFBvbGljeURvY3VtZW50IH07XG5cbiAgLyoqXG4gICAqIFRoZSBwYXRoIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJvbGUuIEZvciBpbmZvcm1hdGlvbiBhYm91dCBJQU0gcGF0aHMsIHNlZVxuICAgKiBGcmllbmRseSBOYW1lcyBhbmQgUGF0aHMgaW4gSUFNIFVzZXIgR3VpZGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC9cbiAgICovXG4gIHJlYWRvbmx5IHBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEFXUyBzdXBwb3J0cyBwZXJtaXNzaW9ucyBib3VuZGFyaWVzIGZvciBJQU0gZW50aXRpZXMgKHVzZXJzIG9yIHJvbGVzKS5cbiAgICogQSBwZXJtaXNzaW9ucyBib3VuZGFyeSBpcyBhbiBhZHZhbmNlZCBmZWF0dXJlIGZvciB1c2luZyBhIG1hbmFnZWQgcG9saWN5XG4gICAqIHRvIHNldCB0aGUgbWF4aW11bSBwZXJtaXNzaW9ucyB0aGF0IGFuIGlkZW50aXR5LWJhc2VkIHBvbGljeSBjYW4gZ3JhbnQgdG9cbiAgICogYW4gSUFNIGVudGl0eS4gQW4gZW50aXR5J3MgcGVybWlzc2lvbnMgYm91bmRhcnkgYWxsb3dzIGl0IHRvIHBlcmZvcm0gb25seVxuICAgKiB0aGUgYWN0aW9ucyB0aGF0IGFyZSBhbGxvd2VkIGJ5IGJvdGggaXRzIGlkZW50aXR5LWJhc2VkIHBvbGljaWVzIGFuZCBpdHNcbiAgICogcGVybWlzc2lvbnMgYm91bmRhcmllcy5cbiAgICpcbiAgICogQGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0Nsb3VkRm9ybWF0aW9uL2xhdGVzdC9Vc2VyR3VpZGUvYXdzLXJlc291cmNlLWlhbS1yb2xlLmh0bWwjY2ZuLWlhbS1yb2xlLXBlcm1pc3Npb25zYm91bmRhcnlcbiAgICogQGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL2FjY2Vzc19wb2xpY2llc19ib3VuZGFyaWVzLmh0bWxcbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBwZXJtaXNzaW9ucyBib3VuZGFyeS5cbiAgICovXG4gIHJlYWRvbmx5IHBlcm1pc3Npb25zQm91bmRhcnk/OiBJTWFuYWdlZFBvbGljeTtcblxuICAvKipcbiAgICogQSBuYW1lIGZvciB0aGUgSUFNIHJvbGUuIEZvciB2YWxpZCB2YWx1ZXMsIHNlZSB0aGUgUm9sZU5hbWUgcGFyYW1ldGVyIGZvclxuICAgKiB0aGUgQ3JlYXRlUm9sZSBhY3Rpb24gaW4gdGhlIElBTSBBUEkgUmVmZXJlbmNlLlxuICAgKlxuICAgKiBJTVBPUlRBTlQ6IElmIHlvdSBzcGVjaWZ5IGEgbmFtZSwgeW91IGNhbm5vdCBwZXJmb3JtIHVwZGF0ZXMgdGhhdCByZXF1aXJlXG4gICAqIHJlcGxhY2VtZW50IG9mIHRoaXMgcmVzb3VyY2UuIFlvdSBjYW4gcGVyZm9ybSB1cGRhdGVzIHRoYXQgcmVxdWlyZSBubyBvclxuICAgKiBzb21lIGludGVycnVwdGlvbi4gSWYgeW91IG11c3QgcmVwbGFjZSB0aGUgcmVzb3VyY2UsIHNwZWNpZnkgYSBuZXcgbmFtZS5cbiAgICpcbiAgICogSWYgeW91IHNwZWNpZnkgYSBuYW1lLCB5b3UgbXVzdCBzcGVjaWZ5IHRoZSBDQVBBQklMSVRZX05BTUVEX0lBTSB2YWx1ZSB0b1xuICAgKiBhY2tub3dsZWRnZSB5b3VyIHRlbXBsYXRlJ3MgY2FwYWJpbGl0aWVzLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiwgc2VlXG4gICAqIEFja25vd2xlZGdpbmcgSUFNIFJlc291cmNlcyBpbiBBV1MgQ2xvdWRGb3JtYXRpb24gVGVtcGxhdGVzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEFXUyBDbG91ZEZvcm1hdGlvbiBnZW5lcmF0ZXMgYSB1bmlxdWUgcGh5c2ljYWwgSUQgYW5kIHVzZXMgdGhhdCBJRFxuICAgKiBmb3IgdGhlIHJvbGUgbmFtZS5cbiAgICovXG4gIHJlYWRvbmx5IHJvbGVOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbWF4aW11bSBzZXNzaW9uIGR1cmF0aW9uIHRoYXQgeW91IHdhbnQgdG8gc2V0IGZvciB0aGUgc3BlY2lmaWVkIHJvbGUuXG4gICAqIFRoaXMgc2V0dGluZyBjYW4gaGF2ZSBhIHZhbHVlIGZyb20gMSBob3VyICgzNjAwc2VjKSB0byAxMiAoNDMyMDBzZWMpIGhvdXJzLlxuICAgKlxuICAgKiBBbnlvbmUgd2hvIGFzc3VtZXMgdGhlIHJvbGUgZnJvbSB0aGUgQVdTIENMSSBvciBBUEkgY2FuIHVzZSB0aGVcbiAgICogRHVyYXRpb25TZWNvbmRzIEFQSSBwYXJhbWV0ZXIgb3IgdGhlIGR1cmF0aW9uLXNlY29uZHMgQ0xJIHBhcmFtZXRlciB0b1xuICAgKiByZXF1ZXN0IGEgbG9uZ2VyIHNlc3Npb24uIFRoZSBNYXhTZXNzaW9uRHVyYXRpb24gc2V0dGluZyBkZXRlcm1pbmVzIHRoZVxuICAgKiBtYXhpbXVtIGR1cmF0aW9uIHRoYXQgY2FuIGJlIHJlcXVlc3RlZCB1c2luZyB0aGUgRHVyYXRpb25TZWNvbmRzXG4gICAqIHBhcmFtZXRlci5cbiAgICpcbiAgICogSWYgdXNlcnMgZG9uJ3Qgc3BlY2lmeSBhIHZhbHVlIGZvciB0aGUgRHVyYXRpb25TZWNvbmRzIHBhcmFtZXRlciwgdGhlaXJcbiAgICogc2VjdXJpdHkgY3JlZGVudGlhbHMgYXJlIHZhbGlkIGZvciBvbmUgaG91ciBieSBkZWZhdWx0LiBUaGlzIGFwcGxpZXMgd2hlblxuICAgKiB5b3UgdXNlIHRoZSBBc3N1bWVSb2xlKiBBUEkgb3BlcmF0aW9ucyBvciB0aGUgYXNzdW1lLXJvbGUqIENMSSBvcGVyYXRpb25zXG4gICAqIGJ1dCBkb2VzIG5vdCBhcHBseSB3aGVuIHlvdSB1c2UgdGhvc2Ugb3BlcmF0aW9ucyB0byBjcmVhdGUgYSBjb25zb2xlIFVSTC5cbiAgICpcbiAgICogQGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL2lkX3JvbGVzX3VzZS5odG1sXG4gICAqXG4gICAqIEBkZWZhdWx0IER1cmF0aW9uLmhvdXJzKDEpXG4gICAqL1xuICByZWFkb25seSBtYXhTZXNzaW9uRHVyYXRpb24/OiBEdXJhdGlvbjtcblxuICAvKipcbiAgICogQSBkZXNjcmlwdGlvbiBvZiB0aGUgcm9sZS4gSXQgY2FuIGJlIHVwIHRvIDEwMDAgY2hhcmFjdGVycyBsb25nLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGRlc2NyaXB0aW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBhbGxvd2luZyBjdXN0b21pemluZyB0aGUgYmVoYXZpb3Igb2Yge0BsaW5rIFJvbGUuZnJvbVJvbGVBcm59LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZyb21Sb2xlQXJuT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBpbXBvcnRlZCByb2xlIGNhbiBiZSBtb2RpZmllZCBieSBhdHRhY2hpbmcgcG9saWN5IHJlc291cmNlcyB0byBpdC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgbXV0YWJsZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEZvciBpbW11dGFibGUgcm9sZXM6IGFkZCBncmFudHMgdG8gcmVzb3VyY2VzIGluc3RlYWQgb2YgZHJvcHBpbmcgdGhlbVxuICAgKlxuICAgKiBJZiB0aGlzIGlzIGBmYWxzZWAgb3Igbm90IHNwZWNpZmllZCwgZ3JhbnQgcGVybWlzc2lvbnMgYWRkZWQgdG8gdGhpcyByb2xlIGFyZSBpZ25vcmVkLlxuICAgKiBJdCBpcyB5b3VyIG93biByZXNwb25zaWJpbGl0eSB0byBtYWtlIHN1cmUgdGhlIHJvbGUgaGFzIHRoZSByZXF1aXJlZCBwZXJtaXNzaW9ucy5cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgdHJ1ZWAsIGFueSBncmFudCBwZXJtaXNzaW9ucyB3aWxsIGJlIGFkZGVkIHRvIHRoZSByZXNvdXJjZSBpbnN0ZWFkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgYWRkR3JhbnRzVG9SZXNvdXJjZXM/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIElBTSBSb2xlXG4gKlxuICogRGVmaW5lcyBhbiBJQU0gcm9sZS4gVGhlIHJvbGUgaXMgY3JlYXRlZCB3aXRoIGFuIGFzc3VtZSBwb2xpY3kgZG9jdW1lbnQgYXNzb2NpYXRlZCB3aXRoXG4gKiB0aGUgc3BlY2lmaWVkIEFXUyBzZXJ2aWNlIHByaW5jaXBhbCBkZWZpbmVkIGluIGBzZXJ2aWNlQXNzdW1lUm9sZWAuXG4gKi9cbmV4cG9ydCBjbGFzcyBSb2xlIGV4dGVuZHMgUmVzb3VyY2UgaW1wbGVtZW50cyBJUm9sZSB7XG4gIC8qKlxuICAgKiBJbXBvcnQgYW4gZXh0ZXJuYWwgcm9sZSBieSBBUk4uXG4gICAqXG4gICAqIElmIHRoZSBpbXBvcnRlZCBSb2xlIEFSTiBpcyBhIFRva2VuIChzdWNoIGFzIGFcbiAgICogYENmblBhcmFtZXRlci52YWx1ZUFzU3RyaW5nYCBvciBhIGBGbi5pbXBvcnRWYWx1ZSgpYCkgKmFuZCogdGhlIHJlZmVyZW5jZWRcbiAgICogcm9sZSBoYXMgYSBgcGF0aGAgKGxpa2UgYGFybjouLi46cm9sZS9BZG1pblJvbGVzL0FsaWNlYCksIHRoZVxuICAgKiBgcm9sZU5hbWVgIHByb3BlcnR5IHdpbGwgbm90IHJlc29sdmUgdG8gdGhlIGNvcnJlY3QgdmFsdWUuIEluc3RlYWQgaXRcbiAgICogd2lsbCByZXNvbHZlIHRvIHRoZSBmaXJzdCBwYXRoIGNvbXBvbmVudC4gV2UgdW5mb3J0dW5hdGVseSBjYW5ub3QgZXhwcmVzc1xuICAgKiB0aGUgY29ycmVjdCBjYWxjdWxhdGlvbiBvZiB0aGUgZnVsbCBwYXRoIG5hbWUgYXMgYSBDbG91ZEZvcm1hdGlvblxuICAgKiBleHByZXNzaW9uLiBJbiB0aGlzIHNjZW5hcmlvIHRoZSBSb2xlIEFSTiBzaG91bGQgYmUgc3VwcGxpZWQgd2l0aG91dCB0aGVcbiAgICogYHBhdGhgIGluIG9yZGVyIHRvIHJlc29sdmUgdGhlIGNvcnJlY3Qgcm9sZSByZXNvdXJjZS5cbiAgICpcbiAgICogQHBhcmFtIHNjb3BlIGNvbnN0cnVjdCBzY29wZVxuICAgKiBAcGFyYW0gaWQgY29uc3RydWN0IGlkXG4gICAqIEBwYXJhbSByb2xlQXJuIHRoZSBBUk4gb2YgdGhlIHJvbGUgdG8gaW1wb3J0XG4gICAqIEBwYXJhbSBvcHRpb25zIGFsbG93IGN1c3RvbWl6aW5nIHRoZSBiZWhhdmlvciBvZiB0aGUgcmV0dXJuZWQgcm9sZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmcm9tUm9sZUFybihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCByb2xlQXJuOiBzdHJpbmcsIG9wdGlvbnM6IEZyb21Sb2xlQXJuT3B0aW9ucyA9IHt9KTogSVJvbGUge1xuICAgIGNvbnN0IHNjb3BlU3RhY2sgPSBTdGFjay5vZihzY29wZSk7XG4gICAgY29uc3QgcGFyc2VkQXJuID0gc2NvcGVTdGFjay5zcGxpdEFybihyb2xlQXJuLCBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSk7XG4gICAgY29uc3QgcmVzb3VyY2VOYW1lID0gcGFyc2VkQXJuLnJlc291cmNlTmFtZSE7XG4gICAgY29uc3Qgcm9sZUFjY291bnQgPSBwYXJzZWRBcm4uYWNjb3VudDtcbiAgICAvLyBzZXJ2aWNlIHJvbGVzIGhhdmUgYW4gQVJOIGxpa2UgJ2Fybjphd3M6aWFtOjo8YWNjb3VudD46cm9sZS9zZXJ2aWNlLXJvbGUvPHJvbGVOYW1lPidcbiAgICAvLyBvciAnYXJuOmF3czppYW06OjxhY2NvdW50Pjpyb2xlL3NlcnZpY2Utcm9sZS9zZXJ2aWNlbmFtZS5hbWF6b25hd3MuY29tL3NlcnZpY2Utcm9sZS88cm9sZU5hbWU+J1xuICAgIC8vIHdlIHdhbnQgdG8gc3VwcG9ydCB0aGVzZSBhcyB3ZWxsLCBzbyB3ZSBqdXN0IHVzZSB0aGUgZWxlbWVudCBhZnRlciB0aGUgbGFzdCBzbGFzaCBhcyByb2xlIG5hbWVcbiAgICBjb25zdCByb2xlTmFtZSA9IHJlc291cmNlTmFtZS5zcGxpdCgnLycpLnBvcCgpITtcblxuICAgIGNsYXNzIEltcG9ydCBleHRlbmRzIFJlc291cmNlIGltcGxlbWVudHMgSVJvbGUge1xuICAgICAgcHVibGljIHJlYWRvbmx5IGdyYW50UHJpbmNpcGFsOiBJUHJpbmNpcGFsID0gdGhpcztcbiAgICAgIHB1YmxpYyByZWFkb25seSBwcmluY2lwYWxBY2NvdW50ID0gcm9sZUFjY291bnQ7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgYXNzdW1lUm9sZUFjdGlvbjogc3RyaW5nID0gJ3N0czpBc3N1bWVSb2xlJztcbiAgICAgIHB1YmxpYyByZWFkb25seSBwb2xpY3lGcmFnbWVudCA9IG5ldyBBcm5QcmluY2lwYWwocm9sZUFybikucG9saWN5RnJhZ21lbnQ7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgcm9sZUFybiA9IHJvbGVBcm47XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgcm9sZU5hbWUgPSByb2xlTmFtZTtcbiAgICAgIHByaXZhdGUgcmVhZG9ubHkgYXR0YWNoZWRQb2xpY2llcyA9IG5ldyBBdHRhY2hlZFBvbGljaWVzKCk7XG4gICAgICBwcml2YXRlIGRlZmF1bHRQb2xpY3k/OiBQb2xpY3k7XG5cbiAgICAgIGNvbnN0cnVjdG9yKF9zY29wZTogQ29uc3RydWN0LCBfaWQ6IHN0cmluZykge1xuICAgICAgICBzdXBlcihfc2NvcGUsIF9pZCwge1xuICAgICAgICAgIGFjY291bnQ6IHJvbGVBY2NvdW50LFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGFkZFRvUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudCkuc3RhdGVtZW50QWRkZWQ7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyBhZGRUb1ByaW5jaXBhbFBvbGljeShzdGF0ZW1lbnQ6IFBvbGljeVN0YXRlbWVudCk6IEFkZFRvUHJpbmNpcGFsUG9saWN5UmVzdWx0IHtcbiAgICAgICAgaWYgKCF0aGlzLmRlZmF1bHRQb2xpY3kpIHtcbiAgICAgICAgICB0aGlzLmRlZmF1bHRQb2xpY3kgPSBuZXcgUG9saWN5KHRoaXMsICdQb2xpY3knKTtcbiAgICAgICAgICB0aGlzLmF0dGFjaElubGluZVBvbGljeSh0aGlzLmRlZmF1bHRQb2xpY3kpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZGVmYXVsdFBvbGljeS5hZGRTdGF0ZW1lbnRzKHN0YXRlbWVudCk7XG4gICAgICAgIHJldHVybiB7IHN0YXRlbWVudEFkZGVkOiB0cnVlLCBwb2xpY3lEZXBlbmRhYmxlOiB0aGlzLmRlZmF1bHRQb2xpY3kgfTtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGF0dGFjaElubGluZVBvbGljeShwb2xpY3k6IFBvbGljeSk6IHZvaWQge1xuICAgICAgICBjb25zdCB0aGlzQW5kUG9saWN5QWNjb3VudENvbXBhcmlzb24gPSBUb2tlbi5jb21wYXJlU3RyaW5ncyh0aGlzLmVudi5hY2NvdW50LCBwb2xpY3kuZW52LmFjY291bnQpO1xuICAgICAgICBjb25zdCBlcXVhbE9yQW55VW5yZXNvbHZlZCA9IHRoaXNBbmRQb2xpY3lBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLlNBTUUgfHxcbiAgICAgICAgICB0aGlzQW5kUG9saWN5QWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5CT1RIX1VOUkVTT0xWRUQgfHxcbiAgICAgICAgICB0aGlzQW5kUG9saWN5QWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5PTkVfVU5SRVNPTFZFRDtcbiAgICAgICAgaWYgKGVxdWFsT3JBbnlVbnJlc29sdmVkKSB7XG4gICAgICAgICAgdGhpcy5hdHRhY2hlZFBvbGljaWVzLmF0dGFjaChwb2xpY3kpO1xuICAgICAgICAgIHBvbGljeS5hdHRhY2hUb1JvbGUodGhpcyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcHVibGljIGFkZE1hbmFnZWRQb2xpY3koX3BvbGljeTogSU1hbmFnZWRQb2xpY3kpOiB2b2lkIHtcbiAgICAgICAgLy8gRklYTUU6IEFkZCB3YXJuaW5nIHRoYXQgd2UncmUgaWdub3JpbmcgdGhpc1xuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIEdyYW50IHBlcm1pc3Npb25zIHRvIHRoZSBnaXZlbiBwcmluY2lwYWwgdG8gcGFzcyB0aGlzIHJvbGUuXG4gICAgICAgKi9cbiAgICAgIHB1YmxpYyBncmFudFBhc3NSb2xlKGlkZW50aXR5OiBJUHJpbmNpcGFsKTogR3JhbnQge1xuICAgICAgICByZXR1cm4gdGhpcy5ncmFudChpZGVudGl0eSwgJ2lhbTpQYXNzUm9sZScpO1xuICAgICAgfVxuXG4gICAgICAvKipcbiAgICAgICAqIEdyYW50IHRoZSBhY3Rpb25zIGRlZmluZWQgaW4gYWN0aW9ucyB0byB0aGUgaWRlbnRpdHkgUHJpbmNpcGFsIG9uIHRoaXMgcmVzb3VyY2UuXG4gICAgICAgKi9cbiAgICAgIHB1YmxpYyBncmFudChncmFudGVlOiBJUHJpbmNpcGFsLCAuLi5hY3Rpb25zOiBzdHJpbmdbXSk6IEdyYW50IHtcbiAgICAgICAgcmV0dXJuIEdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgICAgICBncmFudGVlLFxuICAgICAgICAgIGFjdGlvbnMsXG4gICAgICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy5yb2xlQXJuXSxcbiAgICAgICAgICBzY29wZTogdGhpcyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuYWRkR3JhbnRzVG9SZXNvdXJjZXMgIT09IHVuZGVmaW5lZCAmJiBvcHRpb25zLm11dGFibGUgIT09IGZhbHNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1xcJ2FkZEdyYW50c1RvUmVzb3VyY2VzXFwnIGNhbiBvbmx5IGJlIHBhc3NlZCBpZiBcXCdtdXRhYmxlOiBmYWxzZVxcJycpO1xuICAgIH1cblxuICAgIGNvbnN0IGltcG9ydGVkUm9sZSA9IG5ldyBJbXBvcnQoc2NvcGUsIGlkKTtcbiAgICBjb25zdCByb2xlQXJuQW5kU2NvcGVTdGFja0FjY291bnRDb21wYXJpc29uID0gVG9rZW4uY29tcGFyZVN0cmluZ3MoaW1wb3J0ZWRSb2xlLmVudi5hY2NvdW50LCBzY29wZVN0YWNrLmFjY291bnQpO1xuICAgIGNvbnN0IGVxdWFsT3JBbnlVbnJlc29sdmVkID0gcm9sZUFybkFuZFNjb3BlU3RhY2tBY2NvdW50Q29tcGFyaXNvbiA9PT0gVG9rZW5Db21wYXJpc29uLlNBTUUgfHxcbiAgICAgIHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5CT1RIX1VOUkVTT0xWRUQgfHxcbiAgICAgIHJvbGVBcm5BbmRTY29wZVN0YWNrQWNjb3VudENvbXBhcmlzb24gPT09IFRva2VuQ29tcGFyaXNvbi5PTkVfVU5SRVNPTFZFRDtcbiAgICAvLyB3ZSBvbmx5IHJldHVybiBhbiBpbW11dGFibGUgUm9sZSBpZiBib3RoIGFjY291bnRzIHdlcmUgZXhwbGljaXRseSBwcm92aWRlZCwgYW5kIGRpZmZlcmVudFxuICAgIHJldHVybiBvcHRpb25zLm11dGFibGUgIT09IGZhbHNlICYmIGVxdWFsT3JBbnlVbnJlc29sdmVkXG4gICAgICA/IGltcG9ydGVkUm9sZVxuICAgICAgOiBuZXcgSW1tdXRhYmxlUm9sZShzY29wZSwgYEltbXV0YWJsZVJvbGUke2lkfWAsIGltcG9ydGVkUm9sZSwgb3B0aW9ucy5hZGRHcmFudHNUb1Jlc291cmNlcyA/PyBmYWxzZSk7XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IGFuIGV4dGVybmFsIHJvbGUgYnkgbmFtZS5cbiAgICpcbiAgICogVGhlIGltcG9ydGVkIHJvbGUgaXMgYXNzdW1lZCB0byBleGlzdCBpbiB0aGUgc2FtZSBhY2NvdW50IGFzIHRoZSBhY2NvdW50XG4gICAqIHRoZSBzY29wZSdzIGNvbnRhaW5pbmcgU3RhY2sgaXMgYmVpbmcgZGVwbG95ZWQgdG8uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZyb21Sb2xlTmFtZShzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCByb2xlTmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIFJvbGUuZnJvbVJvbGVBcm4oc2NvcGUsIGlkLCBTdGFjay5vZihzY29wZSkuZm9ybWF0QXJuKHtcbiAgICAgIHJlZ2lvbjogJycsXG4gICAgICBzZXJ2aWNlOiAnaWFtJyxcbiAgICAgIHJlc291cmNlOiAncm9sZScsXG4gICAgICByZXNvdXJjZU5hbWU6IHJvbGVOYW1lLFxuICAgIH0pKTtcbiAgfVxuXG4gIHB1YmxpYyByZWFkb25seSBncmFudFByaW5jaXBhbDogSVByaW5jaXBhbCA9IHRoaXM7XG4gIHB1YmxpYyByZWFkb25seSBwcmluY2lwYWxBY2NvdW50OiBzdHJpbmcgfCB1bmRlZmluZWQgPSB0aGlzLmVudi5hY2NvdW50O1xuXG4gIHB1YmxpYyByZWFkb25seSBhc3N1bWVSb2xlQWN0aW9uOiBzdHJpbmcgPSAnc3RzOkFzc3VtZVJvbGUnO1xuXG4gIC8qKlxuICAgKiBUaGUgYXNzdW1lIHJvbGUgcG9saWN5IGRvY3VtZW50IGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYXNzdW1lUm9sZVBvbGljeT86IFBvbGljeURvY3VtZW50O1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBBUk4gb2YgdGhpcyByb2xlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJvbGVBcm46IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc3RhYmxlIGFuZCB1bmlxdWUgc3RyaW5nIGlkZW50aWZ5aW5nIHRoZSByb2xlLiBGb3IgZXhhbXBsZSxcbiAgICogQUlEQUpRQUJMWlM0QTNRRFU1NzZRLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcm9sZUlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhlIHJvbGUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcm9sZU5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgcm9sZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwb2xpY3lGcmFnbWVudDogUHJpbmNpcGFsUG9saWN5RnJhZ21lbnQ7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHBlcm1pc3Npb25zIGJvdW5kYXJ5IGF0dGFjaGVkIHRvIHRoaXMgcm9sZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBlcm1pc3Npb25zQm91bmRhcnk/OiBJTWFuYWdlZFBvbGljeTtcblxuICBwcml2YXRlIGRlZmF1bHRQb2xpY3k/OiBQb2xpY3k7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWFuYWdlZFBvbGljaWVzOiBJTWFuYWdlZFBvbGljeVtdID0gW107XG4gIHByaXZhdGUgcmVhZG9ubHkgYXR0YWNoZWRQb2xpY2llcyA9IG5ldyBBdHRhY2hlZFBvbGljaWVzKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgaW5saW5lUG9saWNpZXM6IHsgW25hbWU6IHN0cmluZ106IFBvbGljeURvY3VtZW50IH07XG4gIHByaXZhdGUgaW1tdXRhYmxlUm9sZT86IElSb2xlO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBSb2xlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIHBoeXNpY2FsTmFtZTogcHJvcHMucm9sZU5hbWUsXG4gICAgfSk7XG5cbiAgICBjb25zdCBleHRlcm5hbElkcyA9IHByb3BzLmV4dGVybmFsSWRzIHx8IFtdO1xuICAgIGlmIChwcm9wcy5leHRlcm5hbElkKSB7XG4gICAgICBleHRlcm5hbElkcy5wdXNoKHByb3BzLmV4dGVybmFsSWQpO1xuICAgIH1cblxuICAgIHRoaXMuYXNzdW1lUm9sZVBvbGljeSA9IGNyZWF0ZUFzc3VtZVJvbGVQb2xpY3kocHJvcHMuYXNzdW1lZEJ5LCBleHRlcm5hbElkcyk7XG4gICAgdGhpcy5tYW5hZ2VkUG9saWNpZXMucHVzaCguLi5wcm9wcy5tYW5hZ2VkUG9saWNpZXMgfHwgW10pO1xuICAgIHRoaXMuaW5saW5lUG9saWNpZXMgPSBwcm9wcy5pbmxpbmVQb2xpY2llcyB8fCB7fTtcbiAgICB0aGlzLnBlcm1pc3Npb25zQm91bmRhcnkgPSBwcm9wcy5wZXJtaXNzaW9uc0JvdW5kYXJ5O1xuICAgIGNvbnN0IG1heFNlc3Npb25EdXJhdGlvbiA9IHByb3BzLm1heFNlc3Npb25EdXJhdGlvbiAmJiBwcm9wcy5tYXhTZXNzaW9uRHVyYXRpb24udG9TZWNvbmRzKCk7XG4gICAgdmFsaWRhdGVNYXhTZXNzaW9uRHVyYXRpb24obWF4U2Vzc2lvbkR1cmF0aW9uKTtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IChwcm9wcy5kZXNjcmlwdGlvbiAmJiBwcm9wcy5kZXNjcmlwdGlvbj8ubGVuZ3RoID4gMCkgPyBwcm9wcy5kZXNjcmlwdGlvbiA6IHVuZGVmaW5lZDtcblxuICAgIGlmIChkZXNjcmlwdGlvbiAmJiBkZXNjcmlwdGlvbi5sZW5ndGggPiAxMDAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JvbGUgZGVzY3JpcHRpb24gbXVzdCBiZSBubyBsb25nZXIgdGhhbiAxMDAwIGNoYXJhY3RlcnMuJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgcm9sZSA9IG5ldyBDZm5Sb2xlKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIGFzc3VtZVJvbGVQb2xpY3lEb2N1bWVudDogdGhpcy5hc3N1bWVSb2xlUG9saWN5IGFzIGFueSxcbiAgICAgIG1hbmFnZWRQb2xpY3lBcm5zOiBVbmlxdWVTdHJpbmdTZXQuZnJvbSgoKSA9PiB0aGlzLm1hbmFnZWRQb2xpY2llcy5tYXAocCA9PiBwLm1hbmFnZWRQb2xpY3lBcm4pKSxcbiAgICAgIHBvbGljaWVzOiBfZmxhdHRlbih0aGlzLmlubGluZVBvbGljaWVzKSxcbiAgICAgIHBhdGg6IHByb3BzLnBhdGgsXG4gICAgICBwZXJtaXNzaW9uc0JvdW5kYXJ5OiB0aGlzLnBlcm1pc3Npb25zQm91bmRhcnkgPyB0aGlzLnBlcm1pc3Npb25zQm91bmRhcnkubWFuYWdlZFBvbGljeUFybiA6IHVuZGVmaW5lZCxcbiAgICAgIHJvbGVOYW1lOiB0aGlzLnBoeXNpY2FsTmFtZSxcbiAgICAgIG1heFNlc3Npb25EdXJhdGlvbixcbiAgICAgIGRlc2NyaXB0aW9uLFxuICAgIH0pO1xuXG4gICAgdGhpcy5yb2xlSWQgPSByb2xlLmF0dHJSb2xlSWQ7XG4gICAgdGhpcy5yb2xlQXJuID0gdGhpcy5nZXRSZXNvdXJjZUFybkF0dHJpYnV0ZShyb2xlLmF0dHJBcm4sIHtcbiAgICAgIHJlZ2lvbjogJycsIC8vIElBTSBpcyBnbG9iYWwgaW4gZWFjaCBwYXJ0aXRpb25cbiAgICAgIHNlcnZpY2U6ICdpYW0nLFxuICAgICAgcmVzb3VyY2U6ICdyb2xlJyxcbiAgICAgIC8vIFJlbW92ZXMgbGVhZGluZyBzbGFzaCBmcm9tIHBhdGhcbiAgICAgIHJlc291cmNlTmFtZTogYCR7cHJvcHMucGF0aCA/IHByb3BzLnBhdGguc3Vic3RyKHByb3BzLnBhdGguY2hhckF0KDApID09PSAnLycgPyAxIDogMCkgOiAnJ30ke3RoaXMucGh5c2ljYWxOYW1lfWAsXG4gICAgfSk7XG4gICAgdGhpcy5yb2xlTmFtZSA9IHRoaXMuZ2V0UmVzb3VyY2VOYW1lQXR0cmlidXRlKHJvbGUucmVmKTtcbiAgICB0aGlzLnBvbGljeUZyYWdtZW50ID0gbmV3IEFyblByaW5jaXBhbCh0aGlzLnJvbGVBcm4pLnBvbGljeUZyYWdtZW50O1xuXG4gICAgZnVuY3Rpb24gX2ZsYXR0ZW4ocG9saWNpZXM/OiB7IFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudCB9KSB7XG4gICAgICBpZiAocG9saWNpZXMgPT0gbnVsbCB8fCBPYmplY3Qua2V5cyhwb2xpY2llcykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8Q2ZuUm9sZS5Qb2xpY3lQcm9wZXJ0eT4oKTtcbiAgICAgIGZvciAoY29uc3QgcG9saWN5TmFtZSBvZiBPYmplY3Qua2V5cyhwb2xpY2llcykpIHtcbiAgICAgICAgY29uc3QgcG9saWN5RG9jdW1lbnQgPSBwb2xpY2llc1twb2xpY3lOYW1lXTtcbiAgICAgICAgcmVzdWx0LnB1c2goeyBwb2xpY3lOYW1lLCBwb2xpY3lEb2N1bWVudCB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBwZXJtaXNzaW9uIHRvIHRoZSByb2xlJ3MgZGVmYXVsdCBwb2xpY3kgZG9jdW1lbnQuXG4gICAqIElmIHRoZXJlIGlzIG5vIGRlZmF1bHQgcG9saWN5IGF0dGFjaGVkIHRvIHRoaXMgcm9sZSwgaXQgd2lsbCBiZSBjcmVhdGVkLlxuICAgKiBAcGFyYW0gc3RhdGVtZW50IFRoZSBwZXJtaXNzaW9uIHN0YXRlbWVudCB0byBhZGQgdG8gdGhlIHBvbGljeSBkb2N1bWVudFxuICAgKi9cbiAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogUG9saWN5U3RhdGVtZW50KTogQWRkVG9QcmluY2lwYWxQb2xpY3lSZXN1bHQge1xuICAgIGlmICghdGhpcy5kZWZhdWx0UG9saWN5KSB7XG4gICAgICB0aGlzLmRlZmF1bHRQb2xpY3kgPSBuZXcgUG9saWN5KHRoaXMsICdEZWZhdWx0UG9saWN5Jyk7XG4gICAgICB0aGlzLmF0dGFjaElubGluZVBvbGljeSh0aGlzLmRlZmF1bHRQb2xpY3kpO1xuICAgIH1cbiAgICB0aGlzLmRlZmF1bHRQb2xpY3kuYWRkU3RhdGVtZW50cyhzdGF0ZW1lbnQpO1xuICAgIHJldHVybiB7IHN0YXRlbWVudEFkZGVkOiB0cnVlLCBwb2xpY3lEZXBlbmRhYmxlOiB0aGlzLmRlZmF1bHRQb2xpY3kgfTtcbiAgfVxuXG4gIHB1YmxpYyBhZGRUb1BvbGljeShzdGF0ZW1lbnQ6IFBvbGljeVN0YXRlbWVudCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudCkuc3RhdGVtZW50QWRkZWQ7XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoZXMgYSBtYW5hZ2VkIHBvbGljeSB0byB0aGlzIHJvbGUuXG4gICAqIEBwYXJhbSBwb2xpY3kgVGhlIHRoZSBtYW5hZ2VkIHBvbGljeSB0byBhdHRhY2guXG4gICAqL1xuICBwdWJsaWMgYWRkTWFuYWdlZFBvbGljeShwb2xpY3k6IElNYW5hZ2VkUG9saWN5KSB7XG4gICAgaWYgKHRoaXMubWFuYWdlZFBvbGljaWVzLmZpbmQobXAgPT4gbXAgPT09IHBvbGljeSkpIHsgcmV0dXJuOyB9XG4gICAgdGhpcy5tYW5hZ2VkUG9saWNpZXMucHVzaChwb2xpY3kpO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaGVzIGEgcG9saWN5IHRvIHRoaXMgcm9sZS5cbiAgICogQHBhcmFtIHBvbGljeSBUaGUgcG9saWN5IHRvIGF0dGFjaFxuICAgKi9cbiAgcHVibGljIGF0dGFjaElubGluZVBvbGljeShwb2xpY3k6IFBvbGljeSkge1xuICAgIHRoaXMuYXR0YWNoZWRQb2xpY2llcy5hdHRhY2gocG9saWN5KTtcbiAgICBwb2xpY3kuYXR0YWNoVG9Sb2xlKHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdyYW50IHRoZSBhY3Rpb25zIGRlZmluZWQgaW4gYWN0aW9ucyB0byB0aGUgaWRlbnRpdHkgUHJpbmNpcGFsIG9uIHRoaXMgcmVzb3VyY2UuXG4gICAqL1xuICBwdWJsaWMgZ3JhbnQoZ3JhbnRlZTogSVByaW5jaXBhbCwgLi4uYWN0aW9uczogc3RyaW5nW10pIHtcbiAgICByZXR1cm4gR3JhbnQuYWRkVG9QcmluY2lwYWwoe1xuICAgICAgZ3JhbnRlZSxcbiAgICAgIGFjdGlvbnMsXG4gICAgICByZXNvdXJjZUFybnM6IFt0aGlzLnJvbGVBcm5dLFxuICAgICAgc2NvcGU6IHRoaXMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICovXG4gIHB1YmxpYyBncmFudFBhc3NSb2xlKGlkZW50aXR5OiBJUHJpbmNpcGFsKSB7XG4gICAgcmV0dXJuIHRoaXMuZ3JhbnQoaWRlbnRpdHksICdpYW06UGFzc1JvbGUnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYSBjb3B5IG9mIHRoaXMgUm9sZSBvYmplY3Qgd2hvc2UgUG9saWNpZXMgd2lsbCBub3QgYmUgdXBkYXRlZFxuICAgKlxuICAgKiBVc2UgdGhlIG9iamVjdCByZXR1cm5lZCBieSB0aGlzIG1ldGhvZCBpZiB5b3Ugd2FudCB0aGlzIFJvbGUgdG8gYmUgdXNlZCBieVxuICAgKiBhIGNvbnN0cnVjdCB3aXRob3V0IGl0IGF1dG9tYXRpY2FsbHkgdXBkYXRpbmcgdGhlIFJvbGUncyBQb2xpY2llcy5cbiAgICpcbiAgICogSWYgeW91IGRvLCB5b3UgYXJlIHJlc3BvbnNpYmxlIGZvciBhZGRpbmcgdGhlIGNvcnJlY3Qgc3RhdGVtZW50cyB0byB0aGVcbiAgICogUm9sZSdzIHBvbGljaWVzIHlvdXJzZWxmLlxuICAgKi9cbiAgcHVibGljIHdpdGhvdXRQb2xpY3lVcGRhdGVzKG9wdGlvbnM6IFdpdGhvdXRQb2xpY3lVcGRhdGVzT3B0aW9ucyA9IHt9KTogSVJvbGUge1xuICAgIGlmICghdGhpcy5pbW11dGFibGVSb2xlKSB7XG4gICAgICB0aGlzLmltbXV0YWJsZVJvbGUgPSBuZXcgSW1tdXRhYmxlUm9sZShOb2RlLm9mKHRoaXMpLnNjb3BlIGFzIENvbnN0cnVjdCwgYEltbXV0YWJsZVJvbGUke3RoaXMubm9kZS5pZH1gLCB0aGlzLCBvcHRpb25zLmFkZEdyYW50c1RvUmVzb3VyY2VzID8/IGZhbHNlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5pbW11dGFibGVSb2xlO1xuICB9XG5cbiAgcHJvdGVjdGVkIHZhbGlkYXRlKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBlcnJvcnMgPSBzdXBlci52YWxpZGF0ZSgpO1xuICAgIGVycm9ycy5wdXNoKC4uLnRoaXMuYXNzdW1lUm9sZVBvbGljeT8udmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpIHx8IFtdKTtcbiAgICBmb3IgKGNvbnN0IHBvbGljeSBvZiBPYmplY3QudmFsdWVzKHRoaXMuaW5saW5lUG9saWNpZXMpKSB7XG4gICAgICBlcnJvcnMucHVzaCguLi5wb2xpY3kudmFsaWRhdGVGb3JJZGVudGl0eVBvbGljeSgpKTtcbiAgICB9XG4gICAgcmV0dXJuIGVycm9ycztcbiAgfVxufVxuXG4vKipcbiAqIEEgUm9sZSBvYmplY3RcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJUm9sZSBleHRlbmRzIElJZGVudGl0eSB7XG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBBUk4gb2YgdGhpcyByb2xlLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSByb2xlQXJuOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhpcyByb2xlLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSByb2xlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBHcmFudCB0aGUgYWN0aW9ucyBkZWZpbmVkIGluIGFjdGlvbnMgdG8gdGhlIGlkZW50aXR5IFByaW5jaXBhbCBvbiB0aGlzIHJlc291cmNlLlxuICAgKi9cbiAgZ3JhbnQoZ3JhbnRlZTogSVByaW5jaXBhbCwgLi4uYWN0aW9uczogc3RyaW5nW10pOiBHcmFudDtcblxuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIHByaW5jaXBhbCB0byBwYXNzIHRoaXMgcm9sZS5cbiAgICovXG4gIGdyYW50UGFzc1JvbGUoZ3JhbnRlZTogSVByaW5jaXBhbCk6IEdyYW50O1xufVxuXG5mdW5jdGlvbiBjcmVhdGVBc3N1bWVSb2xlUG9saWN5KHByaW5jaXBhbDogSVByaW5jaXBhbCwgZXh0ZXJuYWxJZHM6IHN0cmluZ1tdKSB7XG4gIGNvbnN0IGFjdHVhbERvYyA9IG5ldyBQb2xpY3lEb2N1bWVudCgpO1xuXG4gIC8vIElmIHJlcXVlc3RlZCwgYWRkIGV4dGVybmFsSWRzIHRvIGV2ZXJ5IHN0YXRlbWVudCBhZGRlZCB0byB0aGlzIGRvY1xuICBjb25zdCBhZGREb2MgPSBleHRlcm5hbElkcy5sZW5ndGggPT09IDBcbiAgICA/IGFjdHVhbERvY1xuICAgIDogbmV3IE11dGF0aW5nUG9saWN5RG9jdW1lbnRBZGFwdGVyKGFjdHVhbERvYywgKHN0YXRlbWVudCkgPT4ge1xuICAgICAgc3RhdGVtZW50LmFkZENvbmRpdGlvbignU3RyaW5nRXF1YWxzJywge1xuICAgICAgICAnc3RzOkV4dGVybmFsSWQnOiBleHRlcm5hbElkcy5sZW5ndGggPT09IDEgPyBleHRlcm5hbElkc1swXSA6IGV4dGVybmFsSWRzLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gc3RhdGVtZW50O1xuICAgIH0pO1xuXG4gIGRlZmF1bHRBZGRQcmluY2lwYWxUb0Fzc3VtZVJvbGUocHJpbmNpcGFsLCBhZGREb2MpO1xuXG4gIHJldHVybiBhY3R1YWxEb2M7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlTWF4U2Vzc2lvbkR1cmF0aW9uKGR1cmF0aW9uPzogbnVtYmVyKSB7XG4gIGlmIChkdXJhdGlvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKGR1cmF0aW9uIDwgMzYwMCB8fCBkdXJhdGlvbiA+IDQzMjAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBtYXhTZXNzaW9uRHVyYXRpb24gaXMgc2V0IHRvICR7ZHVyYXRpb259LCBidXQgbXVzdCBiZSA+PSAzNjAwc2VjICgxaHIpIGFuZCA8PSA0MzIwMHNlYyAoMTJocnMpYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciB0aGUgYHdpdGhvdXRQb2xpY3lVcGRhdGVzKClgIG1vZGlmaWVyIG9mIGEgUm9sZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdpdGhvdXRQb2xpY3lVcGRhdGVzT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBZGQgZ3JhbnRzIHRvIHJlc291cmNlcyBpbnN0ZWFkIG9mIGRyb3BwaW5nIHRoZW1cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgZmFsc2VgIG9yIG5vdCBzcGVjaWZpZWQsIGdyYW50IHBlcm1pc3Npb25zIGFkZGVkIHRvIHRoaXMgcm9sZSBhcmUgaWdub3JlZC5cbiAgICogSXQgaXMgeW91ciBvd24gcmVzcG9uc2liaWxpdHkgdG8gbWFrZSBzdXJlIHRoZSByb2xlIGhhcyB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMuXG4gICAqXG4gICAqIElmIHRoaXMgaXMgYHRydWVgLCBhbnkgZ3JhbnQgcGVybWlzc2lvbnMgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVzb3VyY2UgaW5zdGVhZC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFkZEdyYW50c1RvUmVzb3VyY2VzPzogYm9vbGVhbjtcbn0iXX0=
\No newline at end of file