UNPKG

147 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.rootPathTo = exports.Stack = exports.STACK_RESOURCE_LIMIT_CONTEXT = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const fs = require("fs");
8const path = require("path");
9const cxschema = require("@aws-cdk/cloud-assembly-schema");
10const cxapi = require("@aws-cdk/cx-api");
11const constructs_1 = require("constructs");
12const minimatch = require("minimatch");
13const annotations_1 = require("./annotations");
14const app_1 = require("./app");
15const arn_1 = require("./arn");
16const cfn_element_1 = require("./cfn-element");
17const cfn_fn_1 = require("./cfn-fn");
18const cfn_pseudo_1 = require("./cfn-pseudo");
19const cfn_resource_1 = require("./cfn-resource");
20const context_provider_1 = require("./context-provider");
21const feature_flags_1 = require("./feature-flags");
22const cloudformation_lang_1 = require("./private/cloudformation-lang");
23const logical_id_1 = require("./private/logical-id");
24const resolve_1 = require("./private/resolve");
25const uniqueid_1 = require("./private/uniqueid");
26// v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch.
27// eslint-disable-next-line
28const construct_compat_1 = require("./construct-compat");
29const STACK_SYMBOL = Symbol.for('@aws-cdk/core.Stack');
30const MY_STACK_CACHE = Symbol.for('@aws-cdk/core.Stack.myStack');
31exports.STACK_RESOURCE_LIMIT_CONTEXT = '@aws-cdk/core:stackResourceLimit';
32const VALID_STACK_NAME_REGEX = /^[A-Za-z][A-Za-z0-9-]*$/;
33const MAX_RESOURCES = 500;
34/**
35 * A root construct which represents a single CloudFormation stack.
36 */
37class Stack extends construct_compat_1.Construct {
38 /**
39 * Creates a new stack.
40 *
41 * @param scope Parent of this stack, usually an `App` or a `Stage`, but could be any construct.
42 * @param id The construct ID of this stack. If `stackName` is not explicitly
43 * defined, this id (and any parent IDs) will be used to determine the
44 * physical ID of the stack.
45 * @param props Stack properties.
46 */
47 constructor(scope, id, props = {}) {
48 try {
49 jsiiDeprecationWarnings._aws_cdk_core_StackProps(props);
50 }
51 catch (error) {
52 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
53 Error.captureStackTrace(error, Stack);
54 }
55 throw error;
56 }
57 // For unit test scope and id are optional for stacks, but we still want an App
58 // as the parent because apps implement much of the synthesis logic.
59 scope = scope ?? new app_1.App({
60 autoSynth: false,
61 outdir: fs_1.FileSystem.mkdtemp('cdk-test-app-'),
62 });
63 // "Default" is a "hidden id" from a `node.uniqueId` perspective
64 id = id ?? 'Default';
65 super(scope, id);
66 this._missingContext = new Array();
67 this._stackDependencies = {};
68 this.templateOptions = {};
69 Object.defineProperty(this, STACK_SYMBOL, { value: true });
70 this._logicalIds = new logical_id_1.LogicalIDs();
71 const { account, region, environment } = this.parseEnvironment(props.env);
72 this.account = account;
73 this.region = region;
74 this.environment = environment;
75 this.terminationProtection = props.terminationProtection;
76 if (props.description !== undefined) {
77 // Max length 1024 bytes
78 // Typically 2 bytes per character, may be more for more exotic characters
79 if (props.description.length > 512) {
80 throw new Error(`Stack description must be <= 1024 bytes. Received description: '${props.description}'`);
81 }
82 this.templateOptions.description = props.description;
83 }
84 this._stackName = props.stackName ?? this.generateStackName();
85 if (this._stackName.length > 128) {
86 throw new Error(`Stack name must be <= 128 characters. Stack name: '${this._stackName}'`);
87 }
88 this.tags = new tag_manager_1.TagManager(cfn_resource_1.TagType.KEY_VALUE, 'aws:cdk:stack', props.tags);
89 if (!VALID_STACK_NAME_REGEX.test(this.stackName)) {
90 throw new Error(`Stack name must match the regular expression: ${VALID_STACK_NAME_REGEX.toString()}, got '${this.stackName}'`);
91 }
92 // the preferred behavior is to generate a unique id for this stack and use
93 // it as the artifact ID in the assembly. this allows multiple stacks to use
94 // the same name. however, this behavior is breaking for 1.x so it's only
95 // applied under a feature flag which is applied automatically for new
96 // projects created using `cdk init`.
97 //
98 // Also use the new behavior if we are using the new CI/CD-ready synthesizer; that way
99 // people only have to flip one flag.
100 const featureFlags = feature_flags_1.FeatureFlags.of(this);
101 const stackNameDupeContext = featureFlags.isEnabled(cxapi.ENABLE_STACK_NAME_DUPLICATES_CONTEXT);
102 const newStyleSynthesisContext = featureFlags.isEnabled(cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT);
103 this.artifactId = (stackNameDupeContext || newStyleSynthesisContext)
104 ? this.generateStackArtifactId()
105 : this.stackName;
106 this.templateFile = `${this.artifactId}.template.json`;
107 // Not for nested stacks
108 this._versionReportingEnabled = (props.analyticsReporting ?? this.node.tryGetContext(cxapi.ANALYTICS_REPORTING_ENABLED_CONTEXT))
109 && !this.nestedStackParent;
110 this.synthesizer = props.synthesizer ?? (newStyleSynthesisContext
111 ? new stack_synthesizers_1.DefaultStackSynthesizer()
112 : new stack_synthesizers_1.LegacyStackSynthesizer());
113 this.synthesizer.bind(this);
114 }
115 /**
116 * Return whether the given object is a Stack.
117 *
118 * We do attribute detection since we can't reliably use 'instanceof'.
119 */
120 static isStack(x) {
121 return x !== null && typeof (x) === 'object' && STACK_SYMBOL in x;
122 }
123 /**
124 * Looks up the first stack scope in which `construct` is defined. Fails if there is no stack up the tree.
125 * @param construct The construct to start the search from.
126 */
127 static of(construct) {
128 // we want this to be as cheap as possible. cache this result by mutating
129 // the object. anecdotally, at the time of this writing, @aws-cdk/core unit
130 // tests hit this cache 1,112 times, @aws-cdk/aws-cloudformation unit tests
131 // hit this 2,435 times).
132 const cache = construct[MY_STACK_CACHE];
133 if (cache) {
134 return cache;
135 }
136 else {
137 const value = _lookup(construct);
138 Object.defineProperty(construct, MY_STACK_CACHE, {
139 enumerable: false,
140 writable: false,
141 configurable: false,
142 value,
143 });
144 return value;
145 }
146 function _lookup(c) {
147 if (Stack.isStack(c)) {
148 return c;
149 }
150 const _scope = constructs_1.Node.of(c).scope;
151 if (stage_1.Stage.isStage(c) || !_scope) {
152 throw new Error(`${construct.constructor?.name ?? 'Construct'} at '${constructs_1.Node.of(construct).path}' should be created in the scope of a Stack, but no Stack found`);
153 }
154 return _lookup(_scope);
155 }
156 }
157 /**
158 * Resolve a tokenized value in the context of the current stack.
159 */
160 resolve(obj) {
161 return resolve_1.resolve(obj, {
162 scope: this,
163 prefix: [],
164 resolver: cloudformation_lang_1.CLOUDFORMATION_TOKEN_RESOLVER,
165 preparing: false,
166 });
167 }
168 /**
169 * Convert an object, potentially containing tokens, to a JSON string
170 */
171 toJsonString(obj, space) {
172 return cloudformation_lang_1.CloudFormationLang.toJSON(obj, space).toString();
173 }
174 /**
175 * DEPRECATED
176 * @deprecated use `reportMissingContextKey()`
177 */
178 reportMissingContext(report) {
179 try {
180 jsiiDeprecationWarnings.print("@aws-cdk/core.Stack#reportMissingContext", "use `reportMissingContextKey()`");
181 }
182 catch (error) {
183 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
184 Error.captureStackTrace(error, this.reportMissingContext);
185 }
186 throw error;
187 }
188 if (!Object.values(cxschema.ContextProvider).includes(report.provider)) {
189 throw new Error(`Unknown context provider requested in: ${JSON.stringify(report)}`);
190 }
191 this.reportMissingContextKey(report);
192 }
193 /**
194 * Indicate that a context key was expected
195 *
196 * Contains instructions which will be emitted into the cloud assembly on how
197 * the key should be supplied.
198 *
199 * @param report The set of parameters needed to obtain the context
200 */
201 reportMissingContextKey(report) {
202 this._missingContext.push(report);
203 }
204 /**
205 * Rename a generated logical identities
206 *
207 * To modify the naming scheme strategy, extend the `Stack` class and
208 * override the `allocateLogicalId` method.
209 */
210 renameLogicalId(oldId, newId) {
211 this._logicalIds.addRename(oldId, newId);
212 }
213 /**
214 * Allocates a stack-unique CloudFormation-compatible logical identity for a
215 * specific resource.
216 *
217 * This method is called when a `CfnElement` is created and used to render the
218 * initial logical identity of resources. Logical ID renames are applied at
219 * this stage.
220 *
221 * This method uses the protected method `allocateLogicalId` to render the
222 * logical ID for an element. To modify the naming scheme, extend the `Stack`
223 * class and override this method.
224 *
225 * @param element The CloudFormation element for which a logical identity is
226 * needed.
227 */
228 getLogicalId(element) {
229 try {
230 jsiiDeprecationWarnings._aws_cdk_core_CfnElement(element);
231 }
232 catch (error) {
233 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
234 Error.captureStackTrace(error, this.getLogicalId);
235 }
236 throw error;
237 }
238 const logicalId = this.allocateLogicalId(element);
239 return this._logicalIds.applyRename(logicalId);
240 }
241 /**
242 * Add a dependency between this stack and another stack.
243 *
244 * This can be used to define dependencies between any two stacks within an
245 * app, and also supports nested stacks.
246 */
247 addDependency(target, reason) {
248 try {
249 jsiiDeprecationWarnings._aws_cdk_core_Stack(target);
250 }
251 catch (error) {
252 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
253 Error.captureStackTrace(error, this.addDependency);
254 }
255 throw error;
256 }
257 deps_1.addDependency(this, target, reason);
258 }
259 /**
260 * Return the stacks this stack depends on
261 */
262 get dependencies() {
263 return Object.values(this._stackDependencies).map(x => x.stack);
264 }
265 /**
266 * The concrete CloudFormation physical stack name.
267 *
268 * This is either the name defined explicitly in the `stackName` prop or
269 * allocated based on the stack's location in the construct tree. Stacks that
270 * are directly defined under the app use their construct `id` as their stack
271 * name. Stacks that are defined deeper within the tree will use a hashed naming
272 * scheme based on the construct path to ensure uniqueness.
273 *
274 * If you wish to obtain the deploy-time AWS::StackName intrinsic,
275 * you can use `Aws.stackName` directly.
276 */
277 get stackName() {
278 return this._stackName;
279 }
280 /**
281 * The partition in which this stack is defined
282 */
283 get partition() {
284 // Always return a non-scoped partition intrinsic. These will usually
285 // be used to construct an ARN, but there are no cross-partition
286 // calls anyway.
287 return cfn_pseudo_1.Aws.PARTITION;
288 }
289 /**
290 * The Amazon domain suffix for the region in which this stack is defined
291 */
292 get urlSuffix() {
293 // Since URL Suffix always follows partition, it is unscoped like partition is.
294 return cfn_pseudo_1.Aws.URL_SUFFIX;
295 }
296 /**
297 * The ID of the stack
298 *
299 * @example
300 * // After resolving, looks like
301 * 'arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123'
302 */
303 get stackId() {
304 return new cfn_pseudo_1.ScopedAws(this).stackId;
305 }
306 /**
307 * Returns the list of notification Amazon Resource Names (ARNs) for the current stack.
308 */
309 get notificationArns() {
310 return new cfn_pseudo_1.ScopedAws(this).notificationArns;
311 }
312 /**
313 * Indicates if this is a nested stack, in which case `parentStack` will include a reference to it's parent.
314 */
315 get nested() {
316 return this.nestedStackResource !== undefined;
317 }
318 /**
319 * Creates an ARN from components.
320 *
321 * If `partition`, `region` or `account` are not specified, the stack's
322 * partition, region and account will be used.
323 *
324 * If any component is the empty string, an empty string will be inserted
325 * into the generated ARN at the location that component corresponds to.
326 *
327 * The ARN will be formatted as follows:
328 *
329 * arn:{partition}:{service}:{region}:{account}:{resource}{sep}}{resource-name}
330 *
331 * The required ARN pieces that are omitted will be taken from the stack that
332 * the 'scope' is attached to. If all ARN pieces are supplied, the supplied scope
333 * can be 'undefined'.
334 */
335 formatArn(components) {
336 try {
337 jsiiDeprecationWarnings._aws_cdk_core_ArnComponents(components);
338 }
339 catch (error) {
340 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
341 Error.captureStackTrace(error, this.formatArn);
342 }
343 throw error;
344 }
345 return arn_1.Arn.format(components, this);
346 }
347 /**
348 * Given an ARN, parses it and returns components.
349 *
350 * IF THE ARN IS A CONCRETE STRING...
351 *
352 * ...it will be parsed and validated. The separator (`sep`) will be set to '/'
353 * if the 6th component includes a '/', in which case, `resource` will be set
354 * to the value before the '/' and `resourceName` will be the rest. In case
355 * there is no '/', `resource` will be set to the 6th components and
356 * `resourceName` will be set to the rest of the string.
357 *
358 * IF THE ARN IS A TOKEN...
359 *
360 * ...it cannot be validated, since we don't have the actual value yet at the
361 * time of this function call. You will have to supply `sepIfToken` and
362 * whether or not ARNs of the expected format usually have resource names
363 * in order to parse it properly. The resulting `ArnComponents` object will
364 * contain tokens for the subexpressions of the ARN, not string literals.
365 *
366 * If the resource name could possibly contain the separator char, the actual
367 * resource name cannot be properly parsed. This only occurs if the separator
368 * char is '/', and happens for example for S3 object ARNs, IAM Role ARNs,
369 * IAM OIDC Provider ARNs, etc. To properly extract the resource name from a
370 * Tokenized ARN, you must know the resource type and call
371 * `Arn.extractResourceName`.
372 *
373 * @param arn The ARN string to parse
374 * @param sepIfToken The separator used to separate resource from resourceName
375 * @param hasName Whether there is a name component in the ARN at all. For
376 * example, SNS Topics ARNs have the 'resource' component contain the topic
377 * name, and no 'resourceName' component.
378 *
379 * @returns an ArnComponents object which allows access to the various
380 * components of the ARN.
381 *
382 * @returns an ArnComponents object which allows access to the various
383 * components of the ARN.
384 *
385 * @deprecated use splitArn instead
386 */
387 parseArn(arn, sepIfToken = '/', hasName = true) {
388 try {
389 jsiiDeprecationWarnings.print("@aws-cdk/core.Stack#parseArn", "use splitArn instead");
390 }
391 catch (error) {
392 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
393 Error.captureStackTrace(error, this.parseArn);
394 }
395 throw error;
396 }
397 return arn_1.Arn.parse(arn, sepIfToken, hasName);
398 }
399 /**
400 * Splits the provided ARN into its components.
401 * Works both if 'arn' is a string like 'arn:aws:s3:::bucket',
402 * and a Token representing a dynamic CloudFormation expression
403 * (in which case the returned components will also be dynamic CloudFormation expressions,
404 * encoded as Tokens).
405 *
406 * @param arn the ARN to split into its components
407 * @param arnFormat the expected format of 'arn' - depends on what format the service 'arn' represents uses
408 */
409 splitArn(arn, arnFormat) {
410 try {
411 jsiiDeprecationWarnings._aws_cdk_core_ArnFormat(arnFormat);
412 }
413 catch (error) {
414 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
415 Error.captureStackTrace(error, this.splitArn);
416 }
417 throw error;
418 }
419 return arn_1.Arn.split(arn, arnFormat);
420 }
421 /**
422 * Returns the list of AZs that are available in the AWS environment
423 * (account/region) associated with this stack.
424 *
425 * If the stack is environment-agnostic (either account and/or region are
426 * tokens), this property will return an array with 2 tokens that will resolve
427 * at deploy-time to the first two availability zones returned from CloudFormation's
428 * `Fn::GetAZs` intrinsic function.
429 *
430 * If they are not available in the context, returns a set of dummy values and
431 * reports them as missing, and let the CLI resolve them by calling EC2
432 * `DescribeAvailabilityZones` on the target environment.
433 *
434 * To specify a different strategy for selecting availability zones override this method.
435 */
436 get availabilityZones() {
437 // if account/region are tokens, we can't obtain AZs through the context
438 // provider, so we fallback to use Fn::GetAZs. the current lowest common
439 // denominator is 2 AZs across all AWS regions.
440 const agnostic = token_1.Token.isUnresolved(this.account) || token_1.Token.isUnresolved(this.region);
441 if (agnostic) {
442 return this.node.tryGetContext(cxapi.AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY) || [
443 cfn_fn_1.Fn.select(0, cfn_fn_1.Fn.getAzs()),
444 cfn_fn_1.Fn.select(1, cfn_fn_1.Fn.getAzs()),
445 ];
446 }
447 const value = context_provider_1.ContextProvider.getValue(this, {
448 provider: cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER,
449 dummyValue: ['dummy1a', 'dummy1b', 'dummy1c'],
450 }).value;
451 if (!Array.isArray(value)) {
452 throw new Error(`Provider ${cxschema.ContextProvider.AVAILABILITY_ZONE_PROVIDER} expects a list`);
453 }
454 return value;
455 }
456 /**
457 * Register a file asset on this Stack
458 *
459 * @deprecated Use `stack.synthesizer.addFileAsset()` if you are calling,
460 * and a different IStackSynthesizer class if you are implementing.
461 */
462 addFileAsset(asset) {
463 try {
464 jsiiDeprecationWarnings.print("@aws-cdk/core.Stack#addFileAsset", "Use `stack.synthesizer.addFileAsset()` if you are calling,\nand a different IStackSynthesizer class if you are implementing.");
465 jsiiDeprecationWarnings._aws_cdk_core_FileAssetSource(asset);
466 }
467 catch (error) {
468 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
469 Error.captureStackTrace(error, this.addFileAsset);
470 }
471 throw error;
472 }
473 return this.synthesizer.addFileAsset(asset);
474 }
475 /**
476 * Register a docker image asset on this Stack
477 *
478 * @deprecated Use `stack.synthesizer.addDockerImageAsset()` if you are calling,
479 * and a different `IStackSynthesizer` class if you are implementing.
480 */
481 addDockerImageAsset(asset) {
482 try {
483 jsiiDeprecationWarnings.print("@aws-cdk/core.Stack#addDockerImageAsset", "Use `stack.synthesizer.addDockerImageAsset()` if you are calling,\nand a different `IStackSynthesizer` class if you are implementing.");
484 jsiiDeprecationWarnings._aws_cdk_core_DockerImageAssetSource(asset);
485 }
486 catch (error) {
487 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
488 Error.captureStackTrace(error, this.addDockerImageAsset);
489 }
490 throw error;
491 }
492 return this.synthesizer.addDockerImageAsset(asset);
493 }
494 /**
495 * If this is a nested stack, returns it's parent stack.
496 */
497 get nestedStackParent() {
498 return this.nestedStackResource && Stack.of(this.nestedStackResource);
499 }
500 /**
501 * Returns the parent of a nested stack.
502 *
503 * @deprecated use `nestedStackParent`
504 */
505 get parentStack() {
506 try {
507 jsiiDeprecationWarnings.print("@aws-cdk/core.Stack#parentStack", "use `nestedStackParent`");
508 }
509 catch (error) {
510 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
511 Error.captureStackTrace(error, jsiiDeprecationWarnings.getPropertyDescriptor(this, "parentStack").get);
512 }
513 throw error;
514 }
515 return this.nestedStackParent;
516 }
517 /**
518 * Add a Transform to this stack. A Transform is a macro that AWS
519 * CloudFormation uses to process your template.
520 *
521 * Duplicate values are removed when stack is synthesized.
522 *
523 * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html
524 * @param transform The transform to add
525 *
526 * @example
527 * declare const stack: Stack;
528 *
529 * stack.addTransform('AWS::Serverless-2016-10-31')
530 */
531 addTransform(transform) {
532 if (!this.templateOptions.transforms) {
533 this.templateOptions.transforms = [];
534 }
535 this.templateOptions.transforms.push(transform);
536 }
537 /**
538 * Called implicitly by the `addDependency` helper function in order to
539 * realize a dependency between two top-level stacks at the assembly level.
540 *
541 * Use `stack.addDependency` to define the dependency between any two stacks,
542 * and take into account nested stack relationships.
543 *
544 * @internal
545 */
546 _addAssemblyDependency(target, reason) {
547 // defensive: we should never get here for nested stacks
548 if (this.nested || target.nested) {
549 throw new Error('Cannot add assembly-level dependencies for nested stacks');
550 }
551 reason = reason || 'dependency added using stack.addDependency()';
552 const cycle = target.stackDependencyReasons(this);
553 if (cycle !== undefined) {
554 // eslint-disable-next-line max-len
555 throw new Error(`'${target.node.path}' depends on '${this.node.path}' (${cycle.join(', ')}). Adding this dependency (${reason}) would create a cyclic reference.`);
556 }
557 let dep = this._stackDependencies[names_1.Names.uniqueId(target)];
558 if (!dep) {
559 dep = this._stackDependencies[names_1.Names.uniqueId(target)] = {
560 stack: target,
561 reasons: [],
562 };
563 }
564 dep.reasons.push(reason);
565 if (process.env.CDK_DEBUG_DEPS) {
566 // eslint-disable-next-line no-console
567 console.error(`[CDK_DEBUG_DEPS] stack "${this.node.path}" depends on "${target.node.path}" because: ${reason}`);
568 }
569 }
570 /**
571 * Synthesizes the cloudformation template into a cloud assembly.
572 * @internal
573 */
574 _synthesizeTemplate(session, lookupRoleArn) {
575 // In principle, stack synthesis is delegated to the
576 // StackSynthesis object.
577 //
578 // However, some parts of synthesis currently use some private
579 // methods on Stack, and I don't really see the value in refactoring
580 // this right now, so some parts still happen here.
581 const builder = session.assembly;
582 const template = this._toCloudFormation();
583 // write the CloudFormation template as a JSON file
584 const outPath = path.join(builder.outdir, this.templateFile);
585 if (this.maxResources > 0) {
586 const resources = template.Resources || {};
587 const numberOfResources = Object.keys(resources).length;
588 if (numberOfResources > this.maxResources) {
589 const counts = Object.entries(count(Object.values(resources).map((r) => `${r?.Type}`))).map(([type, c]) => `${type} (${c})`).join(', ');
590 throw new Error(`Number of resources in stack '${this.node.path}': ${numberOfResources} is greater than allowed maximum of ${this.maxResources}: ${counts}`);
591 }
592 else if (numberOfResources >= (this.maxResources * 0.8)) {
593 annotations_1.Annotations.of(this).addInfo(`Number of resources: ${numberOfResources} is approaching allowed maximum of ${this.maxResources}`);
594 }
595 }
596 fs.writeFileSync(outPath, JSON.stringify(template, undefined, 1));
597 for (const ctx of this._missingContext) {
598 if (lookupRoleArn != null) {
599 builder.addMissing({ ...ctx, props: { ...ctx.props, lookupRoleArn } });
600 }
601 else {
602 builder.addMissing(ctx);
603 }
604 }
605 }
606 /**
607 * Look up a fact value for the given fact for the region of this stack
608 *
609 * Will return a definite value only if the region of the current stack is resolved.
610 * If not, a lookup map will be added to the stack and the lookup will be done at
611 * CDK deployment time.
612 *
613 * What regions will be included in the lookup map is controlled by the
614 * `@aws-cdk/core:target-partitions` context value: it must be set to a list
615 * of partitions, and only regions from the given partitions will be included.
616 * If no such context key is set, all regions will be included.
617 *
618 * This function is intended to be used by construct library authors. Application
619 * builders can rely on the abstractions offered by construct libraries and do
620 * not have to worry about regional facts.
621 *
622 * If `defaultValue` is not given, it is an error if the fact is unknown for
623 * the given region.
624 */
625 regionalFact(factName, defaultValue) {
626 if (!token_1.Token.isUnresolved(this.region)) {
627 const ret = region_info_1.Fact.find(this.region, factName) ?? defaultValue;
628 if (ret === undefined) {
629 throw new Error(`region-info: don't know ${factName} for region ${this.region}. Use 'Fact.register' to provide this value.`);
630 }
631 return ret;
632 }
633 const partitions = constructs_1.Node.of(this).tryGetContext(cxapi.TARGET_PARTITIONS);
634 if (partitions !== undefined && !Array.isArray(partitions)) {
635 throw new Error(`Context value '${cxapi.TARGET_PARTITIONS}' should be a list of strings, got: ${JSON.stringify(cxapi.TARGET_PARTITIONS)}`);
636 }
637 const lookupMap = partitions ? region_info_1.RegionInfo.limitedRegionMap(factName, partitions) : region_info_1.RegionInfo.regionMap(factName);
638 return region_lookup_1.deployTimeLookup(this, factName, lookupMap, defaultValue);
639 }
640 /**
641 * Create a CloudFormation Export for a value
642 *
643 * Returns a string representing the corresponding `Fn.importValue()`
644 * expression for this Export. You can control the name for the export by
645 * passing the `name` option.
646 *
647 * If you don't supply a value for `name`, the value you're exporting must be
648 * a Resource attribute (for example: `bucket.bucketName`) and it will be
649 * given the same name as the automatic cross-stack reference that would be created
650 * if you used the attribute in another Stack.
651 *
652 * One of the uses for this method is to *remove* the relationship between
653 * two Stacks established by automatic cross-stack references. It will
654 * temporarily ensure that the CloudFormation Export still exists while you
655 * remove the reference from the consuming stack. After that, you can remove
656 * the resource and the manual export.
657 *
658 * ## Example
659 *
660 * Here is how the process works. Let's say there are two stacks,
661 * `producerStack` and `consumerStack`, and `producerStack` has a bucket
662 * called `bucket`, which is referenced by `consumerStack` (perhaps because
663 * an AWS Lambda Function writes into it, or something like that).
664 *
665 * It is not safe to remove `producerStack.bucket` because as the bucket is being
666 * deleted, `consumerStack` might still be using it.
667 *
668 * Instead, the process takes two deployments:
669 *
670 * ### Deployment 1: break the relationship
671 *
672 * - Make sure `consumerStack` no longer references `bucket.bucketName` (maybe the consumer
673 * stack now uses its own bucket, or it writes to an AWS DynamoDB table, or maybe you just
674 * remove the Lambda Function altogether).
675 * - In the `ProducerStack` class, call `this.exportValue(this.bucket.bucketName)`. This
676 * will make sure the CloudFormation Export continues to exist while the relationship
677 * between the two stacks is being broken.
678 * - Deploy (this will effectively only change the `consumerStack`, but it's safe to deploy both).
679 *
680 * ### Deployment 2: remove the bucket resource
681 *
682 * - You are now free to remove the `bucket` resource from `producerStack`.
683 * - Don't forget to remove the `exportValue()` call as well.
684 * - Deploy again (this time only the `producerStack` will be changed -- the bucket will be deleted).
685 */
686 exportValue(exportedValue, options = {}) {
687 try {
688 jsiiDeprecationWarnings._aws_cdk_core_ExportValueOptions(options);
689 }
690 catch (error) {
691 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
692 Error.captureStackTrace(error, this.exportValue);
693 }
694 throw error;
695 }
696 if (options.name) {
697 new cfn_output_1.CfnOutput(this, `Export${options.name}`, {
698 value: exportedValue,
699 exportName: options.name,
700 });
701 return cfn_fn_1.Fn.importValue(options.name);
702 }
703 const resolvable = token_1.Tokenization.reverse(exportedValue);
704 if (!resolvable || !reference_1.Reference.isReference(resolvable)) {
705 throw new Error('exportValue: either supply \'name\' or make sure to export a resource attribute (like \'bucket.bucketName\')');
706 }
707 // if exportValue is being called manually (which is pre onPrepare) then the logicalId
708 // could potentially be changed by a call to overrideLogicalId. This would cause our Export/Import
709 // to have an incorrect id. For a better user experience, lock the logicalId and throw an error
710 // if the user tries to override the id _after_ calling exportValue
711 if (cfn_element_1.CfnElement.isCfnElement(resolvable.target)) {
712 resolvable.target._lockLogicalId();
713 }
714 // "teleport" the value here, in case it comes from a nested stack. This will also
715 // ensure the value is from our own scope.
716 const exportable = refs_1.referenceNestedStackValueInParent(resolvable, this);
717 // Ensure a singleton "Exports" scoping Construct
718 // This mostly exists to trigger LogicalID munging, which would be
719 // disabled if we parented constructs directly under Stack.
720 // Also it nicely prevents likely construct name clashes
721 const exportsScope = getCreateExportsScope(this);
722 // Ensure a singleton CfnOutput for this value
723 const resolved = this.resolve(exportable);
724 const id = 'Output' + JSON.stringify(resolved);
725 const exportName = generateExportName(exportsScope, id);
726 if (token_1.Token.isUnresolved(exportName)) {
727 throw new Error(`unresolved token in generated export name: ${JSON.stringify(this.resolve(exportName))}`);
728 }
729 const output = exportsScope.node.tryFindChild(id);
730 if (!output) {
731 new cfn_output_1.CfnOutput(exportsScope, id, { value: token_1.Token.asString(exportable), exportName });
732 }
733 return cfn_fn_1.Fn.importValue(exportName);
734 }
735 /**
736 * Returns the naming scheme used to allocate logical IDs. By default, uses
737 * the `HashedAddressingScheme` but this method can be overridden to customize
738 * this behavior.
739 *
740 * In order to make sure logical IDs are unique and stable, we hash the resource
741 * construct tree path (i.e. toplevel/secondlevel/.../myresource) and add it as
742 * a suffix to the path components joined without a separator (CloudFormation
743 * IDs only allow alphanumeric characters).
744 *
745 * The result will be:
746 *
747 * <path.join('')><md5(path.join('/')>
748 * "human" "hash"
749 *
750 * If the "human" part of the ID exceeds 240 characters, we simply trim it so
751 * the total ID doesn't exceed CloudFormation's 255 character limit.
752 *
753 * We only take 8 characters from the md5 hash (0.000005 chance of collision).
754 *
755 * Special cases:
756 *
757 * - If the path only contains a single component (i.e. it's a top-level
758 * resource), we won't add the hash to it. The hash is not needed for
759 * disamiguation and also, it allows for a more straightforward migration an
760 * existing CloudFormation template to a CDK stack without logical ID changes
761 * (or renames).
762 * - For aesthetic reasons, if the last components of the path are the same
763 * (i.e. `L1/L2/Pipeline/Pipeline`), they will be de-duplicated to make the
764 * resulting human portion of the ID more pleasing: `L1L2Pipeline<HASH>`
765 * instead of `L1L2PipelinePipeline<HASH>`
766 * - If a component is named "Default" it will be omitted from the path. This
767 * allows refactoring higher level abstractions around constructs without affecting
768 * the IDs of already deployed resources.
769 * - If a component is named "Resource" it will be omitted from the user-visible
770 * path, but included in the hash. This reduces visual noise in the human readable
771 * part of the identifier.
772 *
773 * @param cfnElement The element for which the logical ID is allocated.
774 */
775 allocateLogicalId(cfnElement) {
776 try {
777 jsiiDeprecationWarnings._aws_cdk_core_CfnElement(cfnElement);
778 }
779 catch (error) {
780 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
781 Error.captureStackTrace(error, this.allocateLogicalId);
782 }
783 throw error;
784 }
785 const scopes = cfnElement.node.scopes;
786 const stackIndex = scopes.indexOf(cfnElement.stack);
787 const pathComponents = scopes.slice(stackIndex + 1).map(x => x.node.id);
788 return uniqueid_1.makeUniqueId(pathComponents);
789 }
790 /**
791 * Validate stack name
792 *
793 * CloudFormation stack names can include dashes in addition to the regular identifier
794 * character classes, and we don't allow one of the magic markers.
795 *
796 * @internal
797 */
798 _validateId(name) {
799 if (name && !VALID_STACK_NAME_REGEX.test(name)) {
800 throw new Error(`Stack name must match the regular expression: ${VALID_STACK_NAME_REGEX.toString()}, got '${name}'`);
801 }
802 }
803 /**
804 * Returns the CloudFormation template for this stack by traversing
805 * the tree and invoking _toCloudFormation() on all Entity objects.
806 *
807 * @internal
808 */
809 _toCloudFormation() {
810 let transform;
811 if (this.templateOptions.transform) {
812 // eslint-disable-next-line max-len
813 annotations_1.Annotations.of(this).addWarning('This stack is using the deprecated `templateOptions.transform` property. Consider switching to `addTransform()`.');
814 this.addTransform(this.templateOptions.transform);
815 }
816 if (this.templateOptions.transforms) {
817 if (this.templateOptions.transforms.length === 1) { // Extract single value
818 transform = this.templateOptions.transforms[0];
819 }
820 else { // Remove duplicate values
821 transform = Array.from(new Set(this.templateOptions.transforms));
822 }
823 }
824 const template = {
825 Description: this.templateOptions.description,
826 Transform: transform,
827 AWSTemplateFormatVersion: this.templateOptions.templateFormatVersion,
828 Metadata: this.templateOptions.metadata,
829 };
830 const elements = cfnElements(this);
831 const fragments = elements.map(e => this.resolve(e._toCloudFormation()));
832 // merge in all CloudFormation fragments collected from the tree
833 for (const fragment of fragments) {
834 merge(template, fragment);
835 }
836 // resolve all tokens and remove all empties
837 const ret = this.resolve(template) || {};
838 this._logicalIds.assertAllRenamesApplied();
839 return ret;
840 }
841 /**
842 * Deprecated.
843 *
844 * @see https://github.com/aws/aws-cdk/pull/7187
845 * @returns reference itself without any change
846 * @deprecated cross reference handling has been moved to `App.prepare()`.
847 */
848 prepareCrossReference(_sourceStack, reference) {
849 try {
850 jsiiDeprecationWarnings.print("@aws-cdk/core.Stack#prepareCrossReference", "cross reference handling has been moved to `App.prepare()`.");
851 jsiiDeprecationWarnings._aws_cdk_core_Stack(_sourceStack);
852 jsiiDeprecationWarnings._aws_cdk_core_Reference(reference);
853 }
854 catch (error) {
855 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
856 Error.captureStackTrace(error, this.prepareCrossReference);
857 }
858 throw error;
859 }
860 return reference;
861 }
862 /**
863 * Determine the various stack environment attributes.
864 *
865 */
866 parseEnvironment(env = {}) {
867 // if an environment property is explicitly specified when the stack is
868 // created, it will be used. if not, use tokens for account and region.
869 //
870 // (They do not need to be anchored to any construct like resource attributes
871 // are, because we'll never Export/Fn::ImportValue them -- the only situation
872 // in which Export/Fn::ImportValue would work is if the value are the same
873 // between producer and consumer anyway, so we can just assume that they are).
874 const containingAssembly = stage_1.Stage.of(this);
875 const account = env.account ?? containingAssembly?.account ?? cfn_pseudo_1.Aws.ACCOUNT_ID;
876 const region = env.region ?? containingAssembly?.region ?? cfn_pseudo_1.Aws.REGION;
877 // this is the "aws://" env specification that will be written to the cloud assembly
878 // manifest. it will use "unknown-account" and "unknown-region" to indicate
879 // environment-agnosticness.
880 const envAccount = !token_1.Token.isUnresolved(account) ? account : cxapi.UNKNOWN_ACCOUNT;
881 const envRegion = !token_1.Token.isUnresolved(region) ? region : cxapi.UNKNOWN_REGION;
882 return {
883 account,
884 region,
885 environment: cxapi.EnvironmentUtils.format(envAccount, envRegion),
886 };
887 }
888 /**
889 * Maximum number of resources in the stack
890 *
891 * Set to 0 to mean "unlimited".
892 */
893 get maxResources() {
894 const contextLimit = this.node.tryGetContext(exports.STACK_RESOURCE_LIMIT_CONTEXT);
895 return contextLimit !== undefined ? parseInt(contextLimit, 10) : MAX_RESOURCES;
896 }
897 /**
898 * Check whether this stack has a (transitive) dependency on another stack
899 *
900 * Returns the list of reasons on the dependency path, or undefined
901 * if there is no dependency.
902 */
903 stackDependencyReasons(other) {
904 if (this === other) {
905 return [];
906 }
907 for (const dep of Object.values(this._stackDependencies)) {
908 const ret = dep.stack.stackDependencyReasons(other);
909 if (ret !== undefined) {
910 return [...dep.reasons, ...ret];
911 }
912 }
913 return undefined;
914 }
915 /**
916 * Calculate the stack name based on the construct path
917 *
918 * The stack name is the name under which we'll deploy the stack,
919 * and incorporates containing Stage names by default.
920 *
921 * Generally this looks a lot like how logical IDs are calculated.
922 * The stack name is calculated based on the construct root path,
923 * as follows:
924 *
925 * - Path is calculated with respect to containing App or Stage (if any)
926 * - If the path is one component long just use that component, otherwise
927 * combine them with a hash.
928 *
929 * Since the hash is quite ugly and we'd like to avoid it if possible -- but
930 * we can't anymore in the general case since it has been written into legacy
931 * stacks. The introduction of Stages makes it possible to make this nicer however.
932 * When a Stack is nested inside a Stage, we use the path components below the
933 * Stage, and prefix the path components of the Stage before it.
934 */
935 generateStackName() {
936 const assembly = stage_1.Stage.of(this);
937 const prefix = (assembly && assembly.stageName) ? `${assembly.stageName}-` : '';
938 return `${prefix}${this.generateStackId(assembly)}`;
939 }
940 /**
941 * The artifact ID for this stack
942 *
943 * Stack artifact ID is unique within the App's Cloud Assembly.
944 */
945 generateStackArtifactId() {
946 return this.generateStackId(this.node.root);
947 }
948 /**
949 * Generate an ID with respect to the given container construct.
950 */
951 generateStackId(container) {
952 const rootPath = rootPathTo(this, container);
953 const ids = rootPath.map(c => constructs_1.Node.of(c).id);
954 // In unit tests our Stack (which is the only component) may not have an
955 // id, so in that case just pretend it's "Stack".
956 if (ids.length === 1 && !ids[0]) {
957 throw new Error('unexpected: stack id must always be defined');
958 }
959 return makeStackName(ids);
960 }
961 /**
962 * Indicates whether the stack requires bundling or not
963 */
964 get bundlingRequired() {
965 const bundlingStacks = this.node.tryGetContext(cxapi.BUNDLING_STACKS) ?? ['*'];
966 // bundlingStacks is of the form `Stage/Stack`, convert it to `Stage-Stack` before comparing to stack name
967 return bundlingStacks.some(pattern => minimatch(this.stackName, pattern.replace('/', '-')));
968 }
969}
970exports.Stack = Stack;
971_a = JSII_RTTI_SYMBOL_1;
972Stack[_a] = { fqn: "@aws-cdk/core.Stack", version: "1.204.0" };
973function merge(template, fragment) {
974 for (const section of Object.keys(fragment)) {
975 const src = fragment[section];
976 // create top-level section if it doesn't exist
977 const dest = template[section];
978 if (!dest) {
979 template[section] = src;
980 }
981 else {
982 template[section] = mergeSection(section, dest, src);
983 }
984 }
985}
986function mergeSection(section, val1, val2) {
987 switch (section) {
988 case 'Description':
989 return `${val1}\n${val2}`;
990 case 'AWSTemplateFormatVersion':
991 if (val1 != null && val2 != null && val1 !== val2) {
992 throw new Error(`Conflicting CloudFormation template versions provided: '${val1}' and '${val2}`);
993 }
994 return val1 ?? val2;
995 case 'Transform':
996 return mergeSets(val1, val2);
997 default:
998 return mergeObjectsWithoutDuplicates(section, val1, val2);
999 }
1000}
1001function mergeSets(val1, val2) {
1002 const array1 = val1 == null ? [] : (Array.isArray(val1) ? val1 : [val1]);
1003 const array2 = val2 == null ? [] : (Array.isArray(val2) ? val2 : [val2]);
1004 for (const value of array2) {
1005 if (!array1.includes(value)) {
1006 array1.push(value);
1007 }
1008 }
1009 return array1.length === 1 ? array1[0] : array1;
1010}
1011function mergeObjectsWithoutDuplicates(section, dest, src) {
1012 if (typeof dest !== 'object') {
1013 throw new Error(`Expecting ${JSON.stringify(dest)} to be an object`);
1014 }
1015 if (typeof src !== 'object') {
1016 throw new Error(`Expecting ${JSON.stringify(src)} to be an object`);
1017 }
1018 // add all entities from source section to destination section
1019 for (const id of Object.keys(src)) {
1020 if (id in dest) {
1021 throw new Error(`section '${section}' already contains '${id}'`);
1022 }
1023 dest[id] = src[id];
1024 }
1025 return dest;
1026}
1027/**
1028 * Collect all CfnElements from a Stack.
1029 *
1030 * @param node Root node to collect all CfnElements from
1031 * @param into Array to append CfnElements to
1032 * @returns The same array as is being collected into
1033 */
1034function cfnElements(node, into = []) {
1035 if (cfn_element_1.CfnElement.isCfnElement(node)) {
1036 into.push(node);
1037 }
1038 for (const child of constructs_1.Node.of(node).children) {
1039 // Don't recurse into a substack
1040 if (Stack.isStack(child)) {
1041 continue;
1042 }
1043 cfnElements(child, into);
1044 }
1045 return into;
1046}
1047/**
1048 * Return the construct root path of the given construct relative to the given ancestor
1049 *
1050 * If no ancestor is given or the ancestor is not found, return the entire root path.
1051 */
1052function rootPathTo(construct, ancestor) {
1053 const scopes = constructs_1.Node.of(construct).scopes;
1054 for (let i = scopes.length - 2; i >= 0; i--) {
1055 if (scopes[i] === ancestor) {
1056 return scopes.slice(i + 1);
1057 }
1058 }
1059 return scopes;
1060}
1061exports.rootPathTo = rootPathTo;
1062/**
1063 * makeUniqueId, specialized for Stack names
1064 *
1065 * Stack names may contain '-', so we allow that character if the stack name
1066 * has only one component. Otherwise we fall back to the regular "makeUniqueId"
1067 * behavior.
1068 */
1069function makeStackName(components) {
1070 if (components.length === 1) {
1071 return components[0];
1072 }
1073 return uniqueid_1.makeUniqueId(components);
1074}
1075function getCreateExportsScope(stack) {
1076 const exportsName = 'Exports';
1077 let stackExports = stack.node.tryFindChild(exportsName);
1078 if (stackExports === undefined) {
1079 stackExports = new construct_compat_1.Construct(stack, exportsName);
1080 }
1081 return stackExports;
1082}
1083function generateExportName(stackExports, id) {
1084 const stackRelativeExports = feature_flags_1.FeatureFlags.of(stackExports).isEnabled(cxapi.STACK_RELATIVE_EXPORTS_CONTEXT);
1085 const stack = Stack.of(stackExports);
1086 const components = [
1087 ...stackExports.node.scopes
1088 .slice(stackRelativeExports ? stack.node.scopes.length : 2)
1089 .map(c => c.node.id),
1090 id,
1091 ];
1092 const prefix = stack.stackName ? stack.stackName + ':' : '';
1093 const localPart = uniqueid_1.makeUniqueId(components);
1094 const maxLength = 255;
1095 return prefix + localPart.slice(Math.max(0, localPart.length - maxLength + prefix.length));
1096}
1097function count(xs) {
1098 const ret = {};
1099 for (const x of xs) {
1100 if (x in ret) {
1101 ret[x] += 1;
1102 }
1103 else {
1104 ret[x] = 1;
1105 }
1106 }
1107 return ret;
1108}
1109// These imports have to be at the end to prevent circular imports
1110const cfn_output_1 = require("./cfn-output");
1111const deps_1 = require("./deps");
1112const fs_1 = require("./fs");
1113const names_1 = require("./names");
1114const reference_1 = require("./reference");
1115const stack_synthesizers_1 = require("./stack-synthesizers");
1116const stage_1 = require("./stage");
1117const tag_manager_1 = require("./tag-manager");
1118const token_1 = require("./token");
1119const refs_1 = require("./private/refs");
1120const region_info_1 = require("@aws-cdk/region-info");
1121const region_lookup_1 = require("./private/region-lookup");
1122//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzdGFjay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLDJEQUEyRDtBQUMzRCx5Q0FBeUM7QUFDekMsMkNBQXlEO0FBQ3pELHVDQUF1QztBQUN2QywrQ0FBNEM7QUFDNUMsK0JBQTRCO0FBQzVCLCtCQUFzRDtBQUV0RCwrQ0FBMkM7QUFDM0MscUNBQThCO0FBQzlCLDZDQUE4QztBQUM5QyxpREFBc0Q7QUFFdEQseURBQXFEO0FBRXJELG1EQUErQztBQUMvQyx1RUFBa0c7QUFDbEcscURBQWtEO0FBQ2xELCtDQUE0QztBQUM1QyxpREFBa0Q7QUFFbEQsZ0hBQWdIO0FBQ2hILDJCQUEyQjtBQUMzQix5REFBZ0U7QUFFaEUsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBQ3ZELE1BQU0sY0FBYyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsNkJBQTZCLENBQUMsQ0FBQztBQUVwRCxRQUFBLDRCQUE0QixHQUFHLGtDQUFrQyxDQUFDO0FBRS9FLE1BQU0sc0JBQXNCLEdBQUcseUJBQXlCLENBQUM7QUFFekQsTUFBTSxhQUFhLEdBQUcsR0FBRyxDQUFDO0FBa0gxQjs7R0FFRztBQUNILE1BQWEsS0FBTSxTQUFRLDRCQUFhO0lBK0t0Qzs7Ozs7Ozs7T0FRRztJQUNILFlBQW1CLEtBQWlCLEVBQUUsRUFBVyxFQUFFLFFBQW9CLEVBQUU7Ozs7OzsrQ0F4TDlELEtBQUs7Ozs7UUF5TGQsK0VBQStFO1FBQy9FLG9FQUFvRTtRQUNwRSxLQUFLLEdBQUcsS0FBSyxJQUFJLElBQUksU0FBRyxDQUFDO1lBQ3ZCLFNBQVMsRUFBRSxLQUFLO1lBQ2hCLE1BQU0sRUFBRSxlQUFVLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQztTQUM1QyxDQUFDLENBQUM7UUFFSCxnRUFBZ0U7UUFDaEUsRUFBRSxHQUFH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O0lBQ0YsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFNBQVMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUM1RCxNQUFNLFNBQVMsR0FBRyx1QkFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzNDLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQztJQUN0QixPQUFPLE1BQU0sR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxNQUFNLEdBQUcsU0FBUyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0FBQzdGLENBQUM7QUFtQkQsU0FBUyxLQUFLLENBQUMsRUFBWTtJQUN6QixNQUFNLEdBQUcsR0FBMkIsRUFBRSxDQUFDO0lBQ3ZDLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxFQUFFO1FBQ2xCLElBQUksQ0FBQyxJQUFJLEdBQUcsRUFBRTtZQUNaLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDYjthQUFNO1lBQ0wsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNaO0tBQ0Y7SUFDRCxPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRCxrRUFBa0U7QUFDbEUsNkNBQXlDO0FBQ3pDLGlDQUF1QztBQUN2Qyw2QkFBa0M7QUFDbEMsbUNBQWdDO0FBQ2hDLDJDQUF3QztBQUV4Qyw2REFBMEc7QUFDMUcsbUNBQWdDO0FBQ2hDLCtDQUFzRDtBQUN0RCxtQ0FBOEM7QUFDOUMseUNBQW1FO0FBQ25FLHNEQUF3RDtBQUN4RCwyREFBMkQiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgY3hzY2hlbWEgZnJvbSAnQGF3cy1jZGsvY2xvdWQtYXNzZW1ibHktc2NoZW1hJztcbmltcG9ydCAqIGFzIGN4YXBpIGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgeyBJQ29uc3RydWN0LCBDb25zdHJ1Y3QsIE5vZGUgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCAqIGFzIG1pbmltYXRjaCBmcm9tICdtaW5pbWF0Y2gnO1xuaW1wb3J0IHsgQW5ub3RhdGlvbnMgfSBmcm9tICcuL2Fubm90YXRpb25zJztcbmltcG9ydCB7IEFwcCB9IGZyb20gJy4vYXBwJztcbmltcG9ydCB7IEFybiwgQXJuQ29tcG9uZW50cywgQXJuRm9ybWF0IH0gZnJvbSAnLi9hcm4nO1xuaW1wb3J0IHsgRG9ja2VySW1hZ2VBc3NldExvY2F0aW9uLCBEb2NrZXJJbWFnZUFzc2V0U291cmNlLCBGaWxlQXNzZXRMb2NhdGlvbiwgRmlsZUFzc2V0U291cmNlIH0gZnJvbSAnLi9hc3NldHMnO1xuaW1wb3J0IHsgQ2ZuRWxlbWVudCB9IGZyb20gJy4vY2ZuLWVsZW1lbnQnO1xuaW1wb3J0IHsgRm4gfSBmcm9tICcuL2Nmbi1mbic7XG5pbXBvcnQgeyBBd3MsIFNjb3BlZEF3cyB9IGZyb20gJy4vY2ZuLXBzZXVkbyc7XG5pbXBvcnQgeyBDZm5SZXNvdXJjZSwgVGFnVHlwZSB9IGZyb20gJy4vY2ZuLXJlc291cmNlJztcbmltcG9ydCB7IElTeW50aGVzaXNTZXNzaW9uIH0gZnJvbSAnLi9jb25zdHJ1Y3QtY29tcGF0JztcbmltcG9ydCB7IENvbnRleHRQcm92aWRlciB9IGZyb20gJy4vY29udGV4dC1wcm92aWRlcic7XG5pbXBvcnQgeyBFbnZpcm9ubWVudCB9IGZyb20gJy4vZW52aXJvbm1lbnQnO1xuaW1wb3J0IHsgRmVhdHVyZUZsYWdzIH0gZnJvbSAnLi9mZWF0dXJlLWZsYWdzJztcbmltcG9ydCB7IENMT1VERk9STUFUSU9OX1RPS0VOX1JFU09MVkVSLCBDbG91ZEZvcm1hdGlvbkxhbmcgfSBmcm9tICcuL3ByaXZhdGUvY2xvdWRmb3JtYXRpb24tbGFuZyc7XG5pbXBvcnQgeyBMb2dpY2FsSURzIH0gZnJvbSAnLi9wcml2YXRlL2xvZ2ljYWwtaWQnO1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gJy4vcHJpdmF0ZS9yZXNvbHZlJztcbmltcG9ydCB7IG1ha2VVbmlxdWVJZCB9IGZyb20gJy4vcHJpdmF0ZS91bmlxdWVpZCc7XG5cbi8vIHYyIC0ga2VlcCB0aGlzIGltcG9ydCBhcyBhIHNlcGFyYXRlIHNlY3Rpb24gdG8gcmVkdWNlIG1lcmdlIGNvbmZsaWN0IHdoZW4gZm9yd2FyZCBtZXJnaW5nIHdpdGggdGhlIHYyIGJyYW5jaC5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuaW1wb3J0IHsgQ29uc3RydWN0IGFzIENvcmVDb25zdHJ1Y3QgfSBmcm9tICcuL2NvbnN0cnVjdC1jb21wYXQnO1xuXG5jb25zdCBTVEFDS19TWU1CT0wgPSBTeW1ib2wuZm9yKCdAYXdzLWNkay9jb3JlLlN0YWNrJyk7XG5jb25zdCBNWV9TVEFDS19DQUNIRSA9IFN5bWJvbC5mb3IoJ0Bhd3MtY2RrL2NvcmUuU3RhY2subXlTdGFjaycpO1xuXG5leHBvcnQgY29uc3QgU1RBQ0tfUkVTT1VSQ0VfTElNSVRfQ09OVEVYVCA9ICdAYXdzLWNkay9jb3JlOnN0YWNrUmVzb3VyY2VMaW1pdCc7XG5cbmNvbnN0IFZBTElEX1NUQUNLX05BTUVfUkVHRVggPSAvXltBLVphLXpdW0EtWmEtejAtOS1dKiQvO1xuXG5jb25zdCBNQVhfUkVTT1VSQ0VTID0gNTAwO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN0YWNrUHJvcHMge1xuICAvKipcbiAgICogQSBkZXNjcmlwdGlvbiBvZiB0aGUgc3RhY2suXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gZGVzY3JpcHRpb24uXG4gICAqL1xuICByZWFkb25seSBkZXNjcmlwdGlvbj86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIEFXUyBlbnZpcm9ubWVudCAoYWNjb3VudC9yZWdpb24pIHdoZXJlIHRoaXMgc3RhY2sgd2lsbCBiZSBkZXBsb3llZC5cbiAgICpcbiAgICogU2V0IHRoZSBgcmVnaW9uYC9gYWNjb3VudGAgZmllbGRzIG9mIGBlbnZgIHRvIGVpdGhlciBhIGNvbmNyZXRlIHZhbHVlIHRvXG4gICAqIHNlbGVjdCB0aGUgaW5kaWNhdGVkIGVudmlyb25tZW50IChyZWNvbW1lbmRlZCBmb3IgcHJvZHVjdGlvbiBzdGFja3MpLCBvciB0b1xuICAgKiB0aGUgdmFsdWVzIG9mIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICAgKiBgQ0RLX0RFRkFVTFRfUkVHSU9OYC9gQ0RLX0RFRkFVTFRfQUNDT1VOVGAgdG8gbGV0IHRoZSB0YXJnZXQgZW52aXJvbm1lbnRcbiAgICogZGVwZW5kIG9uIHRoZSBBV1MgY3JlZGVudGlhbHMvY29uZmlndXJhdGlvbiB0aGF0IHRoZSBDREsgQ0xJIGlzIGV4ZWN1dGVkXG4gICAqIHVuZGVyIChyZWNvbW1lbmRlZCBmb3IgZGV2ZWxvcG1lbnQgc3RhY2tzKS5cbiAgICpcbiAgICogSWYgdGhlIGBTdGFja2AgaXMgaW5zdGFudGlhdGVkIGluc2lkZSBhIGBTdGFnZWAsIGFueSB1bmRlZmluZWRcbiAgICogYHJlZ2lvbmAvYGFjY291bnRgIGZpZWxkcyBmcm9tIGBlbnZgIHdpbGwgZGVmYXVsdCB0byB0aGUgc2FtZSBmaWVsZCBvbiB0aGVcbiAgICogZW5jb21wYXNzaW5nIGBTdGFnZWAsIGlmIGNvbmZpZ3VyZWQgdGhlcmUuXG4gICAqXG4gICAqIElmIGVpdGhlciBgcmVnaW9uYCBvciBgYWNjb3VudGAgYXJlIG5vdCBzZXQgbm9yIGluaGVyaXRlZCBmcm9tIGBTdGFnZWAsIHRoZVxuICAgKiBTdGFjayB3aWxsIGJlIGNvbnNpZGVyZWQgXCIqZW52aXJvbm1lbnQtYWdub3N0aWMqXCJcIi4gRW52aXJvbm1lbnQtYWdub3N0aWNcbiAgICogc3RhY2tzIGNhbiBiZSBkZXBsb3llZCB0byBhbnkgZW52aXJvbm1lbnQgYnV0IG1heSBub3QgYmUgYWJsZSB0byB0YWtlXG4gICAqIGFkdmFudGFnZSBvZiBhbGwgZmVhdHVyZXMgb2YgdGhlIENESy4gRm9yIGV4YW1wbGUsIHRoZXkgd2lsbCBub3QgYmUgYWJsZSB0b1xuICAgKiB1c2UgZW52aXJvbm1lbnRhbCBjb250ZXh0IGxvb2t1cHMgc3VjaCBhcyBgZWMyLlZwYy5mcm9tTG9va3VwYCBhbmQgd2lsbCBub3RcbiAgICogYXV0b21hdGljYWxseSB0cmFuc2xhdGUgU2VydmljZSBQcmluY2lwYWxzIHRvIHRoZSByaWdodCBmb3JtYXQgYmFzZWQgb24gdGhlXG4gICAqIGVudmlyb25tZW50J3MgQVdTIHBhcnRpdGlvbiwgYW5kIG90aGVyIHN1Y2ggZW5oYW5jZW1lbnRzLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiAvLyBVc2UgYSBjb25jcmV0ZSBhY2NvdW50IGFuZCByZWdpb24gdG8gZGVwbG95IHRoaXMgc3RhY2sgdG86XG4gICAqIC8vIGAuYWNjb3VudGAgYW5kIGAucmVnaW9uYCB3aWxsIHNpbXBseSByZXR1cm4gdGhlc2UgdmFsdWVzLlxuICAgKiBuZXcgU3RhY2soYXBwLCAnU3RhY2sxJywge1xuICAgKiAgIGVudjoge1xuICAgKiAgICAgYWNjb3VudDogJzEyMzQ1Njc4OTAxMicsXG4gICAqICAgICByZWdpb246ICd1cy1lYXN0LTEnXG4gICAqICAgfSxcbiAgICogfSk7XG4gICAqXG4gICAqIC8vIFVzZSB0aGUgQ0xJJ3MgY3VycmVudCBjcmVkZW50aWFscyB0byBkZXRlcm1pbmUgdGhlIHRhcmdldCBlbnZpcm9ubWVudDpcbiAgICogLy8gYC5hY2NvdW50YCBhbmQgYC5yZWdpb25gIHdpbGwgcmVmbGVjdCB0aGUgYWNjb3VudCtyZWdpb24gdGhlIENMSVxuICAgKiAvLyBpcyBjb25maWd1cmVkIHRvIHVzZSAoYmFzZWQgb24gdGhlIHVzZXIgQ0xJIGNyZWRlbnRpYWxzKVxuICAgKiBuZXcgU3RhY2soYXBwLCAnU3RhY2syJywge1xuICAgKiAgIGVudjoge1xuICAgKiAgICAgYWNjb3VudDogcHJvY2Vzcy5lbnYuQ0RLX0RFRkFVTFRfQUNDT1VOVCxcbiAgICogICAgIHJlZ2lvbjogcHJvY2Vzcy5lbnYuQ0RLX0RFRkFVTFRfUkVHSU9OXG4gICAqICAgfSxcbiAgICogfSk7XG4gICAqXG4gICAqIC8vIERlZmluZSBtdWx0aXBsZSBzdGFja3Mgc3RhZ2UgYXNzb2NpYXRlZCB3aXRoIGFuIGVudmlyb25tZW50XG4gICAqIGNvbnN0IG15U3RhZ2UgPSBuZXcgU3RhZ2UoYXBwLCAnTXlTdGFnZScsIHtcbiAgICogICBlbnY6IHtcbiAgICogICAgIGFjY291bnQ6ICcxMjM0NTY3ODkwMTInLFxuICAgKiAgICAgcmVnaW9uOiAndXMtZWFzdC0xJ1xuICAgKiAgIH1cbiAgICogfSk7XG4gICAqXG4gICAqIC8vIGJvdGggb2YgdGhlc2Ugc3RhY2tzIHdpbGwgdXNlIHRoZSBzdGFnZSdzIGFjY291bnQvcmVnaW9uOlxuICAgKiAvLyBgLmFjY291bnRgIGFuZCBgLnJlZ2lvbmAgd2lsbCByZXNvbHZlIHRvIHRoZSBjb25jcmV0ZSB2YWx1ZXMgYXMgYWJvdmVcbiAgICogbmV3IE15U3RhY2sobXlTdGFnZSwgJ1N0YWNrMScpO1xuICAgKiBuZXcgWW91clN0YWNrKG15U3RhZ2UsICdTdGFjazInKTtcbiAgICpcbiAgICogLy8gRGVmaW5lIGFuIGVudmlyb25tZW50LWFnbm9zdGljIHN0YWNrOlxuICAgKiAvLyBgLmFjY291bnRgIGFuZCBgLnJlZ2lvbmAgd2lsbCByZXNvbHZlIHRvIGB7IFwiUmVmXCI6IFwiQVdTOjpBY2NvdW50SWRcIiB9YCBhbmQgYHsgXCJSZWZcIjogXCJBV1M6OlJlZ2lvblwiIH1gIHJlc3BlY3RpdmVseS5cbiAgICogLy8gd2hpY2ggd2lsbCBvbmx5IHJlc29sdmUgdG8gYWN0dWFsIHZhbHVlcyBieSBDbG91ZEZvcm1hdGlvbiBkdXJpbmcgZGVwbG95bWVudC5cbiAgICogbmV3IE15U3RhY2soYXBwLCAnU3RhY2sxJyk7XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhlIGVudmlyb25tZW50IG9mIHRoZSBjb250YWluaW5nIGBTdGFnZWAgaWYgYXZhaWxhYmxlLFxuICAgKiBvdGhlcndpc2UgY3JlYXRlIHRoZSBzdGFjayB3aWxsIGJlIGVudmlyb25tZW50LWFnbm9zdGljLlxuICAgKi9cbiAgcmVhZG9ubHkgZW52PzogRW52aXJvbm1lbnQ7XG5cbiAgLyoqXG4gICAqIE5hbWUgdG8gZGVwbG95IHRoZSBzdGFjayB3aXRoXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRGVyaXZlZCBmcm9tIGNvbnN0cnVjdCBwYXRoLlxuICAgKi9cbiAgcmVhZG9ubHkgc3RhY2tOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBTdGFjayB0YWdzIHRoYXQgd2lsbCBiZSBhcHBsaWVkIHRvIGFsbCB0aGUgdGFnZ2FibGUgcmVzb3VyY2VzIGFuZCB0aGUgc3RhY2sgaXRzZWxmLlxuICAgKlxuICAgKiBAZGVmYXVsdCB7fVxuICAgKi9cbiAgcmVhZG9ubHkgdGFncz86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG5cbiAgLyoqXG4gICAqIFN5bnRoZXNpcyBtZXRob2QgdG8gdXNlIHdoaWxlIGRlcGxveWluZyB0aGlzIHN0YWNrXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gYERlZmF1bHRTdGFja1N5bnRoZXNpemVyYCBpZiB0aGUgYEBhd3MtY2RrL2NvcmU6bmV3U3R5bGVTdGFja1N5bnRoZXNpc2AgZmVhdHVyZSBmbGFnXG4gICAqIGlzIHNldCwgYExlZ2FjeVN0YWNrU3ludGhlc2l6ZXJgIG90aGVyd2lzZS5cbiAgICovXG4gIHJlYWRvbmx5IHN5bnRoZXNpemVyPzogSVN0YWNrU3ludGhlc2l6ZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZW5hYmxlIHRlcm1pbmF0aW9uIHByb3RlY3Rpb24gZm9yIHRoaXMgc3RhY2suXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSB0ZXJtaW5hdGlvblByb3RlY3Rpb24/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBJbmNsdWRlIHJ1bnRpbWUgdmVyc2lvbmluZyBpbmZvcm1hdGlvbiBpbiB0aGlzIFN0YWNrXG4gICAqXG4gICAqIEBkZWZhdWx0IGBhbmFseXRpY3NSZXBvcnRpbmdgIHNldHRpbmcgb2YgY29udGFpbmluZyBgQXBwYCwgb3IgdmFsdWUgb2ZcbiAgICogJ2F3czpjZGs6dmVyc2lvbi1yZXBvcnRpbmcnIGNvbnRleHQga2V5XG4gICAqL1xuICByZWFkb25seSBhbmFseXRpY3NSZXBvcnRpbmc/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIEEgcm9vdCBjb25zdHJ1Y3Qgd2hpY2ggcmVwcmVzZW50cyBhIHNpbmdsZSBDbG91ZEZvcm1hdGlvbiBzdGFjay5cbiAqL1xuZXhwb3J0IGNsYXNzIFN0YWNrIGV4dGVuZHMgQ29yZUNvbnN0cnVjdCBpbXBsZW1lbnRzIElUYWdnYWJsZSB7XG4gIC8qKlxuICAgKiBSZXR1cm4gd2hldGhlciB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGEgU3RhY2suXG4gICAqXG4gICAqIFdlIGRvIGF0dHJpYnV0ZSBkZXRlY3Rpb24gc2luY2Ugd2UgY2FuJ3QgcmVsaWFibHkgdXNlICdpbnN0YW5jZW9mJy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgaXNTdGFjayh4OiBhbnkpOiB4IGlzIFN0YWNrIHtcbiAgICByZXR1cm4geCAhPT0gbnVsbCAmJiB0eXBlb2YoeCkgPT09ICdvYmplY3QnICYmIFNUQUNLX1NZTUJPTCBpbiB4O1xuICB9XG5cbiAgLyoqXG4gICAqIExvb2tzIHVwIHRoZSBmaXJzdCBzdGFjayBzY29wZSBpbiB3aGljaCBgY29uc3RydWN0YCBpcyBkZWZpbmVkLiBGYWlscyBpZiB0aGVyZSBpcyBubyBzdGFjayB1cCB0aGUgdHJlZS5cbiAgICogQHBhcmFtIGNvbnN0cnVjdCBUaGUgY29uc3RydWN0IHRvIHN0YXJ0IHRoZSBzZWFyY2ggZnJvbS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgb2YoY29uc3RydWN0OiBJQ29uc3RydWN0KTogU3RhY2sge1xuICAgIC8vIHdlIHdhbnQgdGhpcyB0byBiZSBhcyBjaGVhcCBhcyBwb3NzaWJsZS4gY2FjaGUgdGhpcyByZXN1bHQgYnkgbXV0YXRpbmdcbiAgICAvLyB0aGUgb2JqZWN0LiBhbmVjZG90YWxseSwgYXQgdGhlIHRpbWUgb2YgdGhpcyB3cml0aW5nLCBAYXdzLWNkay9jb3JlIHVuaXRcbiAgICAvLyB0ZXN0cyBoaXQgdGhpcyBjYWNoZSAxLDExMiB0aW1lcywgQGF3cy1jZGsvYXdzLWNsb3VkZm9ybWF0aW9uIHVuaXQgdGVzdHNcbiAgICAvLyBoaXQgdGhpcyAyLDQzNSB0aW1lcykuXG4gICAgY29uc3QgY2FjaGUgPSAoY29uc3RydWN0IGFzIGFueSlbTVlfU1RBQ0tfQ0FDSEVdIGFzIFN0YWNrIHwgdW5kZWZpbmVkO1xuICAgIGlmIChjYWNoZSkge1xuICAgICAgcmV0dXJuIGNhY2hlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCB2YWx1ZSA9IF9sb29rdXAoY29uc3RydWN0KTtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb25zdHJ1Y3QsIE1ZX1NUQUNLX0NBQ0hFLCB7XG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogZmFsc2UsXG4gICAgICAgIHZhbHVlLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gX2xvb2t1cChjOiBJQ29uc3RydWN0KTogU3RhY2sge1xuICAgICAgaWYgKFN0YWNrLmlzU3RhY2soYykpIHtcbiAgICAgICAgcmV0dXJuIGM7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IF9zY29wZSA9IE5vZGUub2YoYykuc2NvcGU7XG4gICAgICBpZiAoU3RhZ2UuaXNTdGFnZShjKSB8fCAhX3Njb3BlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtjb25zdHJ1Y3QuY29uc3RydWN0b3I/Lm5hbWUgPz8gJ0NvbnN0cnVjdCd9IGF0ICcke05vZGUub2YoY29uc3RydWN0KS5wYXRofScgc2hvdWxkIGJlIGNyZWF0ZWQgaW4gdGhlIHNjb3BlIG9mIGEgU3RhY2ssIGJ1dCBubyBTdGFjayBmb3VuZGApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gX2xvb2t1cChfc2NvcGUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUYWdzIHRvIGJlIGFwcGxpZWQgdG8gdGhlIHN0YWNrLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHRhZ3M6IFRhZ01hbmFnZXI7XG5cbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlIChsaWtlIHZlcnNpb24sIHRyYW5zZm9ybSwgZGVzY3JpcHRpb24pLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHRlbXBsYXRlT3B0aW9uczogSVRlbXBsYXRlT3B0aW9ucztcblxuICAvKipcbiAgICogVGhlIEFXUyByZWdpb24gaW50byB3aGljaCB0aGlzIHN0YWNrIHdpbGwgYmUgZGVwbG95ZWQgKGUuZy4gYHVzLXdlc3QtMmApLlxuICAgKlxuICAgKiBUaGlzIHZhbHVlIGlzIHJlc29sdmVkIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHJ1bGVzOlxuICAgKlxuICAgKiAxLiBUaGUgdmFsdWUgcHJvdmlkZWQgdG8gYGVudi5yZWdpb25gIHdoZW4gdGhlIHN0YWNrIGlzIGRlZmluZWQuIFRoaXMgY2FuXG4gICAqICAgIGVpdGhlciBiZSBhIGNvbmNlcmV0ZSByZWdpb24gKGUuZy4gYHVzLXdlc3QtMmApIG9yIHRoZSBgQXdzLnJlZ2lvbmBcbiAgICogICAgdG9rZW4uXG4gICAqIDMuIGBBd3MucmVnaW9uYCwgd2hpY2ggaXMgcmVwcmVzZW50cyB0aGUgQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljIHJlZmVyZW5jZVxuICAgKiAgICBgeyBcIlJlZlwiOiBcIkFXUzo6UmVnaW9uXCIgfWAgZW5jb2RlZCBhcyBhIHN0cmluZyB0b2tlbi5cbiAgICpcbiAgICogUHJlZmVyYWJseSwgeW91IHNob3VsZCB1c2UgdGhlIHJldHVybiB2YWx1ZSBhcyBhbiBvcGFxdWUgc3RyaW5nIGFuZCBub3RcbiAgICogYXR0ZW1wdCB0byBwYXJzZSBpdCB0byBpbXBsZW1lbnQgeW91ciBsb2dpYy4gSWYgeW91IGRvLCB5b3UgbXVzdCBmaXJzdFxuICAgKiBjaGVjayB0aGF0IGl0IGlzIGEgY29uY2VyZXRlIHZhbHVlIGFuIG5vdCBhbiB1bnJlc29sdmVkIHRva2VuLiBJZiB0aGlzXG4gICAqIHZhbHVlIGlzIGFuIHVucmVzb2x2ZWQgdG9rZW4gKGBUb2tlbi5pc1VucmVzb2x2ZWQoc3RhY2sucmVnaW9uKWAgcmV0dXJuc1xuICAgKiBgdHJ1ZWApLCB0aGlzIGltcGxpZXMgdGhhdCB0aGUgdXNlciB3aXNoZXMgdGhhdCB0aGlzIHN0YWNrIHdpbGwgc3ludGhlc2l6ZVxuICAgKiBpbnRvIGEgKipyZWdpb24tYWdub3N0aWMgdGVtcGxhdGUqKi4gSW4gdGhpcyBjYXNlLCB5b3VyIGNvZGUgc2hvdWxkIGVpdGhlclxuICAgKiBmYWlsICh0aHJvdyBhbiBlcnJvciwgZW1pdCBhIHN5bnRoIGVycm9yIHVzaW5nIGBBbm5vdGF0aW9ucy5vZihjb25zdHJ1Y3QpLmFkZEVycm9yKClgKSBvclxuICAgKiBpbXBsZW1lbnQgc29tZSBvdGhlciByZWdpb24tYWdub3N0aWMgYmVoYXZpb3IuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcmVnaW9uOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBBV1MgYWNjb3VudCBpbnRvIHdoaWNoIHRoaXMgc3RhY2sgd2lsbCBiZSBkZXBsb3llZC5cbiAgICpcbiAgICogVGhpcyB2YWx1ZSBpcyByZXNvbHZlZCBhY2NvcmRpbmcgdG8gdGhlIGZvbGxvd2luZyBydWxlczpcbiAgICpcbiAgICogMS4gVGhlIHZhbHVlIHByb3ZpZGVkIHRvIGBlbnYuYWNjb3VudGAgd2hlbiB0aGUgc3RhY2sgaXMgZGVmaW5lZC4gVGhpcyBjYW5cbiAgICogICAgZWl0aGVyIGJlIGEgY29uY2VyZXRlIGFjY291bnQgKGUuZy4gYDU4NTY5NTAzMTExMWApIG9yIHRoZVxuICAgKiAgICBgQXdzLmFjY291bnRJZGAgdG9rZW4uXG4gICAqIDMuIGBBd3MuYWNjb3VudElkYCwgd2hpY2ggcmVwcmVzZW50cyB0aGUgQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljIHJlZmVyZW5jZVxuICAgKiAgICBgeyBcIlJlZlwiOiBcIkFXUzo6QWNjb3VudElkXCIgfWAgZW5jb2RlZCBhcyBhIHN0cmluZyB0b2tlbi5cbiAgICpcbiAgICogUHJlZmVyYWJseSwgeW91IHNob3VsZCB1c2UgdGhlIHJldHVybiB2YWx1ZSBhcyBhbiBvcGFxdWUgc3RyaW5nIGFuZCBub3RcbiAgICogYXR0ZW1wdCB0byBwYXJzZSBpdCB0byBpbXBsZW1lbnQgeW91ciBsb2dpYy4gSWYgeW91IGRvLCB5b3UgbXVzdCBmaXJzdFxuICAgKiBjaGVjayB0aGF0IGl0IGlzIGEgY29uY2VyZXRlIHZhbHVlIGFuIG5vdCBhbiB1bnJlc29sdmVkIHRva2VuLiBJZiB0aGlzXG4gICAqIHZhbHVlIGlzIGFuIHVucmVzb2x2ZWQgdG9rZW4gKGBUb2tlbi5pc1VucmVzb2x2ZWQoc3RhY2suYWNjb3VudClgIHJldHVybnNcbiAgICogYHRydWVgKSwgdGhpcyBpbXBsaWVzIHRoYXQgdGhlIHVzZXIgd2lzaGVzIHRoYXQgdGhpcyBzdGFjayB3aWxsIHN5bnRoZXNpemVcbiAgICogaW50byBhICoqYWNjb3VudC1hZ25vc3RpYyB0ZW1wbGF0ZSoqLiBJbiB0aGlzIGNhc2UsIHlvdXIgY29kZSBzaG91bGQgZWl0aGVyXG4gICAqIGZhaWwgKHRocm93IGFuIGVycm9yLCBlbWl0IGEgc3ludGggZXJyb3IgdXNpbmcgYEFubm90YXRpb25zLm9mKGNvbnN0cnVjdCkuYWRkRXJyb3IoKWApIG9yXG4gICAqIGltcGxlbWVudCBzb21lIG90aGVyIHJlZ2lvbi1hZ25vc3RpYyBiZWhhdmlvci5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhY2NvdW50OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBlbnZpcm9ubWVudCBjb29yZGluYXRlcyBpbiB3aGljaCB0aGlzIHN0YWNrIGlzIGRlcGxveWVkLiBJbiB0aGUgZm9ybVxuICAgKiBgYXdzOi8vYWNjb3VudC9yZWdpb25gLiBVc2UgYHN0YWNrLmFjY291bnRgIGFuZCBgc3RhY2sucmVnaW9uYCB0byBvYnRhaW5cbiAgICogdGhlIHNwZWNpZmljIHZhbHVlcywgbm8gbmVlZCB0byBwYXJzZS5cbiAgICpcbiAgICogWW91IGNhbiB1c2UgdGhpcyB2YWx1ZSB0byBkZXRlcm1pbmUgaWYgdHdvIHN0YWNrcyBhcmUgdGFyZ2V0aW5nIHRoZSBzYW1lXG4gICAqIGVudmlyb25tZW50LlxuICAgKlxuICAgKiBJZiBlaXRoZXIgYHN0YWNrLmFjY291bnRgIG9yIGBzdGFjay5yZWdpb25gIGFyZSBub3QgY29uY3JldGUgdmFsdWVzIChlLmcuXG4gICAqIGBBd3MuYWNjb3VudGAgb3IgYEF3cy5yZWdpb25gKSB0aGUgc3BlY2lhbCBzdHJpbmdzIGB1bmtub3duLWFjY291bnRgIGFuZC9vclxuICAgKiBgdW5rbm93bi1yZWdpb25gIHdpbGwgYmUgdXNlZCByZXNwZWN0aXZlbHkgdG8gaW5kaWNhdGUgdGhpcyBzdGFjayBpc1xuICAgKiByZWdpb24vYWNjb3VudC1hZ25vc3RpYy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBlbnZpcm9ubWVudDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRlcm1pbmF0aW9uIHByb3RlY3Rpb24gaXMgZW5hYmxlZCBmb3IgdGhpcyBzdGFjay5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB0ZXJtaW5hdGlvblByb3RlY3Rpb24/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBJZiB0aGlzIGlzIGEgbmVzdGVkIHN0YWNrLCB0aGlzIHJlcHJlc2VudHMgaXRzIGBBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFja2BcbiAgICogcmVzb3VyY2UuIGB1bmRlZmluZWRgIGZvciB0b3AtbGV2ZWwgKG5vbi1uZXN0ZWQpIHN0YWNrcy5cbiAgICpcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuZXN0ZWRTdGFja1Jlc291cmNlPzogQ2ZuUmVzb3VyY2U7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZSBmaWxlIGVtaXR0ZWQgdG8gdGhlIG91dHB1dFxuICAgKiBkaXJlY3RvcnkgZHVyaW5nIHN5bnRoZXNpcy5cbiAgICpcbiAgICogRXhhbXBsZSB2YWx1ZTogYE15U3RhY2sudGVtcGxhdGUuanNvbmBcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB0ZW1wbGF0ZUZpbGU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIElEIG9mIHRoZSBjbG91ZCBhc3NlbWJseSBhcnRpZmFjdCBmb3IgdGhpcyBzdGFjay5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhcnRpZmFjdElkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFN5bnRoZXNpcyBtZXRob2QgZm9yIHRoaXMgc3RhY2tcbiAgICpcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBzeW50aGVzaXplcjogSVN0YWNrU3ludGhlc2l6ZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdmVyc2lvbiByZXBvcnRpbmcgaXMgZW5hYmxlZCBmb3IgdGhpcyBzdGFja1xuICAgKlxuICAgKiBDb250cm9scyB3aGV0aGVyIHRoZSBDREsgTWV0YWRhdGEgcmVzb3VyY2UgaXMgaW5qZWN0ZWRcbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgX3ZlcnNpb25SZXBvcnRpbmdFbmFibGVkOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBMb2dpY2FsIElEIGdlbmVyYXRpb24gc3RyYXRlZ3lcbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX2xvZ2ljYWxJZHM6IExvZ2ljYWxJRHM7XG5cbiAgLyoqXG4gICAqIE90aGVyIHN0YWNrcyB0aGlzIHN0YWNrIGRlcGVuZHMgb25cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX3N0YWNrRGVwZW5kZW5jaWVzOiB7IFt1bmlxdWVJZDogc3RyaW5nXTogU3RhY2tEZXBlbmRlbmN5IH07XG5cbiAgLyoqXG4gICAqIExpc3RzIGFsbCBtaXNzaW5nIGNvbnRleHR1YWwgaW5mb3JtYXRpb24uXG4gICAqIFRoaXMgaXMgcmV0dXJuZWQgd2hlbiB0aGUgc3RhY2sgaXMgc3ludGhlc2l6ZWQgdW5kZXIgdGhlICdtaXNzaW5nJyBhdHRyaWJ1dGVcbiAgICogYW5kIGFsbG93cyB0b29saW5nIHRvIG9idGFpbiB0aGUgY29udGV4dCBhbmQgcmUtc3ludGhlc2l6ZS5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX21pc3NpbmdDb250ZXh0OiBjeHNjaGVtYS5NaXNzaW5nQ29udGV4dFtdO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3N0YWNrTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IHN0YWNrLlxuICAgKlxuICAgKiBAcGFyYW0gc2NvcGUgUGFyZW50IG9mIHRoaXMgc3RhY2ssIHVzdWFsbHkgYW4gYEFwcGAgb3IgYSBgU3RhZ2VgLCBidXQgY291bGQgYmUgYW55IGNvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIFRoZSBjb25zdHJ1Y3QgSUQgb2YgdGhpcyBzdGFjay4gSWYgYHN0YWNrTmFtZWAgaXMgbm90IGV4cGxpY2l0bHlcbiAgICogZGVmaW5lZCwgdGhpcyBpZCAoYW5kIGFueSBwYXJlbnQgSURzKSB3aWxsIGJlIHVzZWQgdG8gZGV0ZXJtaW5lIHRoZVxuICAgKiBwaHlzaWNhbCBJRCBvZiB0aGUgc3RhY2suXG4gICAqIEBwYXJhbSBwcm9wcyBTdGFjayBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcHVibGljIGNvbnN0cnVjdG9yKHNjb3BlPzogQ29uc3RydWN0LCBpZD86IHN0cmluZywgcHJvcHM6IFN0YWNrUHJvcHMgPSB7fSkge1xuICAgIC8vIEZvciB1bml0IHRlc3Qgc2NvcGUgYW5kIGlkIGFyZSBvcHRpb25hbCBmb3Igc3RhY2tzLCBidXQgd2Ugc3RpbGwgd2FudCBhbiBBcHBcbiAgICAvLyBhcyB0aGUgcGFyZW50IGJlY2F1c2UgYXBwcyBpbXBsZW1lbnQgbXVjaCBvZiB0aGUgc3ludGhlc2lzIGxvZ2ljLlxuICAgIHNjb3BlID0gc2NvcGUgPz8gbmV3IEFwcCh7XG4gICAgICBhdXRvU3ludGg6IGZhbHNlLFxuICAgICAgb3V0ZGlyOiBGaWxlU3lzdGVtLm1rZHRlbXAoJ2Nkay10ZXN0LWFwcC0nKSxcbiAgICB9KTtcblxuICAgIC8vIFwiRGVmYXVsdFwiIGlzIGEgXCJoaWRkZW4gaWRcIiBmcm9tIGEgYG5vZGUudW5pcXVlSWRgIHBlcnNwZWN0aXZlXG4gICAgaWQgPSBpZCA/PyAnRGVmYXVsdCc7XG5cbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5fbWlzc2luZ0NvbnRleHQgPSBuZXcgQXJyYXk8Y3hzY2hlbWEuTWlzc2luZ0NvbnRleHQ+KCk7XG4gICAgdGhpcy5fc3RhY2tEZXBlbmRlbmNpZXMgPSB7IH07XG4gICAgdGhpcy50ZW1wbGF0ZU9wdGlvbnMgPSB7IH07XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgU1RBQ0tfU1lNQk9MLCB7IHZhbHVlOiB0cnVlIH0pO1xuXG4gICAgdGhpcy5fbG9naWNhbElkcyA9IG5ldyBMb2dpY2FsSURzKCk7XG5cbiAgICBjb25zdCB7IGFjY291bnQsIHJlZ2lvbiwgZW52aXJvbm1lbnQgfSA9IHRoaXMucGFyc2VFbnZpcm9ubWVudChwcm9wcy5lbnYpO1xuXG4gICAgdGhpcy5hY2NvdW50ID0gYWNjb3VudDtcbiAgICB0aGlzLnJlZ2lvbiA9IHJlZ2lvbjtcbiAgICB0aGlzLmVudmlyb25tZW50ID0gZW52aXJvbm1lbnQ7XG4gICAgdGhpcy50ZXJtaW5hdGlvblByb3RlY3Rpb24gPSBwcm9wcy50ZXJtaW5hdGlvblByb3RlY3Rpb247XG5cbiAgICBpZiAocHJvcHMuZGVzY3JpcHRpb24gIT09IHVuZGVmaW5lZCkge1xuICAgICAgLy8gTWF4IGxlbmd0aCAxMDI0IGJ5dGVzXG4gICAgICAvLyBUeXBpY2FsbHkgMiBieXRlcyBwZXIgY2hhcmFjdGVyLCBtYXkgYmUgbW9yZSBmb3IgbW9yZSBleG90aWMgY2hhcmFjdGVyc1xuICAgICAgaWYgKHByb3BzLmRlc2NyaXB0aW9uLmxlbmd0aCA+IDUxMikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFN0YWNrIGRlc2NyaXB0aW9uIG11c3QgYmUgPD0gMTAyNCBieXRlcy4gUmVjZWl2ZWQgZGVzY3JpcHRpb246ICcke3Byb3BzLmRlc2NyaXB0aW9ufSdgKTtcbiAgICAgIH1cbiAgICAgIHRoaXMudGVtcGxhdGVPcHRpb25zLmRlc2NyaXB0aW9uID0gcHJvcHMuZGVzY3JpcHRpb247XG4gICAgfVxuXG4gICAgdGhpcy5fc3RhY2tOYW1lID0gcHJvcHMuc3RhY2tOYW1lID8/IHRoaXMuZ2VuZXJhdGVTdGFja05hbWUoKTtcbiAgICBpZiAodGhpcy5fc3RhY2tOYW1lLmxlbmd0aCA+IDEyOCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBTdGFjayBuYW1lIG11c3QgYmUgPD0gMTI4IGNoYXJhY3RlcnMuIFN0YWNrIG5hbWU6ICcke3RoaXMuX3N0YWNrTmFtZX0nYCk7XG4gICAgfVxuICAgIHRoaXMudGFncyA9IG5ldyBUYWdNYW5hZ2VyKFRhZ1R5cGUuS0VZX1ZBTFVFLCAnYXdzOmNkazpzdGFjaycsIHByb3BzLnRhZ3MpO1xuXG4gICAgaWYgKCFWQUxJRF9TVEFDS19OQU1FX1JFR0VYLnRlc3QodGhpcy5zdGFja05hbWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFN0YWNrIG5hbWUgbXVzdCBtYXRjaCB0aGUgcmVndWxhciBleHByZXNzaW9uOiAke1ZBTElEX1NUQUNLX05BTUVfUkVHRVgudG9TdHJpbmcoKX0sIGdvdCAnJHt0aGlzLnN0YWNrTmFtZX0nYCk7XG4gICAgfVxuXG4gICAgLy8gdGhlIHByZWZlcnJlZCBiZWhhdmlvciBpcyB0byBnZW5lcmF0ZSBhIHVuaXF1ZSBpZCBmb3IgdGhpcyBzdGFjayBhbmQgdXNlXG4gICAgLy8gaXQgYXMgdGhlIGFydGlmYWN0IElEIGluIHRoZSBhc3NlbWJseS4gdGhpcyBhbGxvd3MgbXVsdGlwbGUgc3RhY2tzIHRvIHVzZVxuICAgIC8vIHRoZSBzYW1lIG5hbWUuIGhvd2V2ZXIsIHRoaXMgYmVoYXZpb3IgaXMgYnJlYWtpbmcgZm9yIDEueCBzbyBpdCdzIG9ubHlcbiAgICAvLyBhcHBsaWVkIHVuZGVyIGEgZmVhdHVyZSBmbGFnIHdoaWNoIGlzIGFwcGxpZWQgYXV0b21hdGljYWxseSBmb3IgbmV3XG4gICAgLy8gcHJvamVjdHMgY3JlYXRlZCB1c2luZyBgY2RrIGluaXRgLlxuICAgIC8vXG4gICAgLy8gQWxzbyB1c2UgdGhlIG5ldyBiZWhhdmlvciBpZiB3ZSBhcmUgdXNpbmcgdGhlIG5ldyBDSS9DRC1yZWFkeSBzeW50aGVzaXplcjsgdGhhdCB3YXlcbiAgICAvLyBwZW9wbGUgb25seSBoYXZlIHRvIGZsaXAgb25lIGZsYWcuXG4gICAgY29uc3QgZmVhdHVyZUZsYWdzID0gRmVhdHVyZUZsYWdzLm9mKHRoaXMpO1xuICAgIGNvbnN0IHN0YWNrTmFtZUR1cGVDb250ZXh0ID0gZmVhdHVyZUZsYWdzLmlzRW5hYmxlZChjeGFwaS5FTkFCTEVfU1RBQ0tfTkFNRV9EVVBMSUNBVEVTX0NPTlRFWFQpO1xuICAgIGNvbnN0IG5ld1N0eWxlU3ludGhlc2lzQ29udGV4dCA9IGZlYXR1cmVGbGFncy5pc0VuYWJsZWQoY3hhcGkuTkVXX1NUWUxFX1NUQUNLX1NZTlRIRVNJU19DT05URVhUKTtcbiAgICB0aGlzLmFydGlmYWN0SWQgPSAoc3RhY2tOYW1lRHVwZUNvbnRleHQgfHwgbmV3U3R5bGVTeW50aGVzaXNDb250ZXh0KVxuICAgICAgPyB0aGlzLmdlbmVyYXRlU3RhY2tBcnRpZmFjdElkKClcbiAgICAgIDogdGhpcy5zdGFja05hbWU7XG5cbiAgICB0aGlzLnRlbXBsYXRlRmlsZSA9IGAke3RoaXMuYXJ0aWZhY3RJZH0udGVtcGxhdGUuanNvbmA7XG5cbiAgICAvLyBOb3QgZm9yIG5lc3RlZCBzdGFja3NcbiAgICB0aGlzLl92ZXJzaW9uUmVwb3J0aW5nRW5hYmxlZCA9IChwcm9wcy5hbmFseXRpY3NSZXBvcnRpbmcgPz8gdGhpcy5ub2RlLnRyeUdldENvbnRleHQoY3hhcGkuQU5BTFlUSUNTX1JFUE9SVElOR19FTkFCTEVEX0NPTlRFWFQpKVxuICAgICAgJiYgIXRoaXMubmVzdGVkU3RhY2tQYXJlbnQ7XG5cbiAgICB0aGlzLnN5bnRoZXNpemVyID0gcHJvcHMuc3ludGhlc2l6ZXIgPz8gKG5ld1N0eWxlU3ludGhlc2lzQ29udGV4dFxuICAgICAgPyBuZXcgRGVmYXVsdFN0YWNrU3ludGhlc2l6ZXIoKVxuICAgICAgOiBuZXcgTGVnYWN5U3RhY2tTeW50aGVzaXplcigpKTtcbiAgICB0aGlzLnN5bnRoZXNpemVyLmJpbmQodGhpcyk7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSBhIHRva2VuaXplZCB2YWx1ZSBpbiB0aGUgY29udGV4dCBvZiB0aGUgY3VycmVudCBzdGFjay5cbiAgICovXG4gIHB1YmxpYyByZXNvbHZlKG9iajogYW55KTogYW55IHtcbiAgICByZXR1cm4gcmVzb2x2ZShvYmosIHtcbiAgICAgIHNjb3BlOiB0aGlzLFxuICAgICAgcHJlZml4OiBbXSxcbiAgICAgIHJlc29sdmVyOiBDTE9VREZPUk1BVElPTl9UT0tFTl9SRVNPTFZFUixcbiAgICAgIHByZXBhcmluZzogZmFsc2UsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCBhbiBvYmplY3QsIHBvdGVudGlhbGx5IGNvbnRhaW5pbmcgdG9rZW5zLCB0byBhIEpTT04gc3RyaW5nXG4gICAqL1xuICBwdWJsaWMgdG9Kc29uU3RyaW5nKG9iajogYW55LCBzcGFjZT86IG51bWJlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIENsb3VkRm9ybWF0aW9uTGFuZy50b0pTT04ob2JqLCBzcGFjZSkudG9TdHJpbmcoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBERVBSRUNBVEVEXG4gICAqIEBkZXByZWNhdGVkIHVzZSBgcmVwb3J0TWlzc2luZ0NvbnRleHRLZXkoKWBcbiAgICovXG4gIHB1YmxpYyByZXBvcnRNaXNzaW5nQ29udGV4dChyZXBvcnQ6IGN4YXBpLk1pc3NpbmdDb250ZXh0KSB7XG4gICAgaWYgKCFPYmplY3QudmFsdWVzKGN4c2NoZW1hLkNvbnRleHRQcm92aWRlcikuaW5jbHVkZXMocmVwb3J0LnByb3ZpZGVyIGFzIGN4c2NoZW1hLkNvbnRleHRQcm92aWRlcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBjb250ZXh0IHByb3ZpZGVyIHJlcXVlc3RlZCBpbjogJHtKU09OLnN0cmluZ2lmeShyZXBvcnQpfWApO1xuICAgIH1cbiAgICB0aGlzLnJlcG9ydE1pc3NpbmdDb250ZXh0S2V5KHJlcG9ydCBhcyBjeHNjaGVtYS5NaXNzaW5nQ29udGV4dCk7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGUgdGhhdCBhIGNvbnRleHQga2V5IHdhcyBleHBlY3RlZFxuICAgKlxuICAgKiBDb250YWlucyBpbnN0cnVjdGlvbnMgd2hpY2ggd2lsbCBiZSBlbWl0dGVkIGludG8gdGhlIGNsb3VkIGFzc2VtYmx5IG9uIGhvd1xuICAgKiB0aGUga2V5IHNob3VsZCBiZSBzdXBwbGllZC5cbiAgICpcbiAgICogQHBhcmFtIHJlcG9ydCBUaGUgc2V0IG9mIHBhcmFtZXRlcnMgbmVlZGVkIHRvIG9idGFpbiB0aGUgY29udGV4dFxuICAgKi9cbiAgcHVibGljIHJlcG9ydE1pc3NpbmdDb250ZXh0S2V5KHJlcG9ydDogY3hzY2hlbWEuTWlzc2luZ0NvbnRleHQpIHtcbiAgICB0aGlzLl9taXNzaW5nQ29udGV4dC5wdXNoKHJlcG9ydCk7XG4gIH1cblxuICAvKipcbiAgICogUmVuYW1lIGEgZ2VuZXJhdGVkIGxvZ2ljYWwgaWRlbnRpdGllc1xuICAgKlxuICAgKiBUbyBtb2RpZnkgdGhlIG5hbWluZyBzY2hlbWUgc3RyYXRlZ3ksIGV4dGVuZCB0aGUgYFN0YWNrYCBjbGFzcyBhbmRcbiAgICogb3ZlcnJpZGUgdGhlIGBhbGxvY2F0ZUxvZ2ljYWxJZGAgbWV0aG9kLlxuICAgKi9cbiAgcHVibGljIHJlbmFtZUxvZ2ljYWxJZChvbGRJZDogc3RyaW5nLCBuZXdJZDogc3RyaW5nKSB7XG4gICAgdGhpcy5fbG9naWNhbElkcy5hZGRSZW5hbWUob2xkSWQsIG5ld0lkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvY2F0ZXMgYSBzdGFjay11bmlxdWUgQ2xvdWRGb3JtYXRpb24tY29tcGF0aWJsZSBsb2dpY2FsIGlkZW50aXR5IGZvciBhXG4gICAqIHNwZWNpZmljIHJlc291cmNlLlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgd2hlbiBhIGBDZm5FbGVtZW50YCBpcyBjcmVhdGVkIGFuZCB1c2VkIHRvIHJlbmRlciB0aGVcbiAgICogaW5pdGlhbCBsb2dpY2FsIGlkZW50aXR5IG9mIHJlc291cmNlcy4gTG9naWNhbCBJRCByZW5hbWVzIGFyZSBhcHBsaWVkIGF0XG4gICAqIHRoaXMgc3RhZ2UuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIHVzZXMgdGhlIHByb3RlY3RlZCBtZXRob2QgYGFsbG9jYXRlTG9naWNhbElkYCB0byByZW5kZXIgdGhlXG4gICAqIGxvZ2ljYWwgSUQgZm9yIGFuIGVsZW1lbnQuIFRvIG1vZGlmeSB0aGUgbmFtaW5nIHNjaGVtZSwgZXh0ZW5kIHRoZSBgU3RhY2tgXG4gICAqIGNsYXNzIGFuZCBvdmVycmlkZSB0aGlzIG1ldGhvZC5cbiAgICpcbiAgICogQHBhcmFtIGVsZW1lbnQgVGhlIENsb3VkRm9ybWF0aW9uIGVsZW1lbnQgZm9yIHdoaWNoIGEgbG9naWNhbCBpZGVudGl0eSBpc1xuICAgKiBuZWVkZWQuXG4gICAqL1xuICBwdWJsaWMgZ2V0TG9naWNhbElkKGVsZW1lbnQ6IENmbkVsZW1lbnQpOiBzdHJpbmcge1xuICAgIGNvbnN0IGxvZ2ljYWxJZCA9IHRoaXMuYWxsb2NhdGVMb2dpY2FsSWQoZWxlbWVudCk7XG4gICAgcmV0dXJuIHRoaXMuX2xvZ2ljYWxJZHMuYXBwbHlSZW5hbWUobG9naWNhbElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBkZXBlbmRlbmN5IGJldHdlZW4gdGhpcyBzdGFjayBhbmQgYW5vdGhlciBzdGFjay5cbiAgICpcbiAgICogVGhpcyBjYW4gYmUgdXNlZCB0byBkZWZpbmUgZGVwZW5kZW5jaWVzIGJldHdlZW4gYW55IHR3byBzdGFja3Mgd2l0aGluIGFuXG4gICAqIGFwcCwgYW5kIGFsc28gc3VwcG9ydHMgbmVzdGVkIHN0YWNrcy5cbiAgICovXG4gIHB1YmxpYyBhZGREZXBlbmRlbmN5KHRhcmdldDogU3RhY2ssIHJlYXNvbj86IHN0cmluZykge1xuICAgIGFkZERlcGVuZGVuY3kodGhpcywgdGFyZ2V0LCByZWFzb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgc3RhY2tzIHRoaXMgc3RhY2sgZGVwZW5kcyBvblxuICAgKi9cbiAgcHVibGljIGdldCBkZXBlbmRlbmNpZXMoKTogU3RhY2tbXSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5fc3RhY2tEZXBlbmRlbmNpZXMpLm1hcCh4ID0+IHguc3RhY2spO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjb25jcmV0ZSBDbG91ZEZvcm1hdGlvbiBwaHlzaWNhbCBzdGFjayBuYW1lLlxuICAgKlxuICAgKiBUaGlzIGlzIGVpdGhlciB0aGUgbmFtZSBkZWZpbmVkIGV4cGxpY2l0bHkgaW4gdGhlIGBzdGFja05hbWVgIHByb3Agb3JcbiAgICogYWxsb2NhdGVkIGJhc2VkIG9uIHRoZSBzdGFjaydzIGxvY2F0aW9uIGluIHRoZSBjb25zdHJ1Y3QgdHJlZS4gU3RhY2tzIHRoYXRcbiAgICogYXJlIGRpcmVjdGx5IGRlZmluZWQgdW5kZXIgdGhlIGFwcCB1c2UgdGhlaXIgY29uc3RydWN0IGBpZGAgYXMgdGhlaXIgc3RhY2tcbiAgICogbmFtZS4gU3RhY2tzIHRoYXQgYXJlIGRlZmluZWQgZGVlcGVyIHdpdGhpbiB0aGUgdHJlZSB3aWxsIHVzZSBhIGhhc2hlZCBuYW1pbmdcbiAgICogc2NoZW1lIGJhc2VkIG9uIHRoZSBjb25zdHJ1Y3QgcGF0aCB0byBlbnN1cmUgdW5pcXVlbmVzcy5cbiAgICpcbiAgICogSWYgeW91IHdpc2ggdG8gb2J0YWluIHRoZSBkZXBsb3ktdGltZSBBV1M6OlN0YWNrTmFtZSBpbnRyaW5zaWMsXG4gICAqIHlvdSBjYW4gdXNlIGBBd3Muc3RhY2tOYW1lYCBkaXJlY3RseS5cbiAgICovXG4gIHB1YmxpYyBnZXQgc3RhY2tOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YWNrTmFtZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgcGFydGl0aW9uIGluIHdoaWNoIHRoaXMgc3RhY2sgaXMgZGVmaW5lZFxuICAgKi9cbiAgcHVibGljIGdldCBwYXJ0aXRpb24oKTogc3RyaW5nIHtcbiAgICAvLyBBbHdheXMgcmV0dXJuIGEgbm9uLXNjb3BlZCBwYXJ0aXRpb24gaW50cmluc2ljLiBUaGVzZSB3aWxsIHVzdWFsbHlcbiAgICAvLyBiZSB1c2VkIHRvIGNvbnN0cnVjdCBhbiBBUk4sIGJ1dCB0aGVyZSBhcmUgbm8gY3Jvc3MtcGFydGl0aW9uXG4gICAgLy8gY2FsbHMgYW55d2F5LlxuICAgIHJldHVybiBBd3MuUEFSVElUSU9OO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBBbWF6b24gZG9tYWluIHN1ZmZpeCBmb3IgdGhlIHJlZ2lvbiBpbiB3aGljaCB0aGlzIHN0YWNrIGlzIGRlZmluZWRcbiAgICovXG4gIHB1YmxpYyBnZXQgdXJsU3VmZml4KCk6IHN0cmluZyB7XG4gICAgLy8gU2luY2UgVVJMIFN1ZmZpeCBhbHdheXMgZm9sbG93cyBwYXJ0aXRpb24sIGl0IGlzIHVuc2NvcGVkIGxpa2UgcGFydGl0aW9uIGlzLlxuICAgIHJldHVybiBBd3MuVVJMX1NVRkZJWDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgSUQgb2YgdGhlIHN0YWNrXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIC8vIEFmdGVyIHJlc29sdmluZywgbG9va3MgbGlrZVxuICAgKiAnYXJuOmF3czpjbG91ZGZvcm1hdGlvbjp1cy13ZXN0LTI6MTIzNDU2Nzg5MDEyOnN0YWNrL3Rlc3RzdGFjay81MWFmM2RjMC1kYTc3LTExZTQtODcyZS0xMjM0NTY3ZGIxMjMnXG4gICAqL1xuICBwdWJsaWMgZ2V0IHN0YWNrSWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbmV3IFNjb3BlZEF3cyh0aGlzKS5zdGFja0lkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGxpc3Qgb2Ygbm90aWZpY2F0aW9uIEFtYXpvbiBSZXNvdXJjZSBOYW1lcyAoQVJOcykgZm9yIHRoZSBjdXJyZW50IHN0YWNrLlxuICAgKi9cbiAgcHVibGljIGdldCBub3RpZmljYXRpb25Bcm5zKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gbmV3IFNjb3BlZEF3cyh0aGlzKS5ub3RpZmljYXRpb25Bcm5zO1xuICB9XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGlzIGlzIGEgbmVzdGVkIHN0YWNrLCBpbiB3aGljaCBjYXNlIGBwYXJlbnRTdGFja2Agd2lsbCBpbmNsdWRlIGEgcmVmZXJlbmNlIHRvIGl0J3MgcGFyZW50LlxuICAgKi9cbiAgcHVibGljIGdldCBuZXN0ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubmVzdGVkU3RhY2tSZXNvdXJjZSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gQVJOIGZyb20gY29tcG9uZW50cy5cbiAgICpcbiAgICogSWYgYHBhcnRpdGlvbmAsIGByZWdpb25gIG9yIGBhY2NvdW50YCBhcmUgbm90IHNwZWNpZmllZCwgdGhlIHN0YWNrJ3NcbiAgICogcGFydGl0aW9uLCByZWdpb24gYW5kIGFjY291bnQgd2lsbCBiZSB1c2VkLlxuICAgKlxuICAgKiBJZiBhbnkgY29tcG9uZW50IGlzIHRoZSBlbXB0eSBzdHJpbmcsIGFuIGVtcHR5IHN0cmluZyB3aWxsIGJlIGluc2VydGVkXG4gICAqIGludG8gdGhlIGdlbmVyYXRlZCBBUk4gYXQgdGhlIGxvY2F0aW9uIHRoYXQgY29tcG9uZW50IGNvcnJlc3BvbmRzIHRvLlxuICAgKlxuICAgKiBUaGUgQVJOIHdpbGwgYmUgZm9ybWF0dGVkIGFzIGZvbGxvd3M6XG4gICAqXG4gICAqICAgYXJuOntwYXJ0aXRpb259OntzZXJ2aWNlfTp7cmVnaW9ufTp7YWNjb3VudH06e3Jlc291cmNlfXtzZXB9fXtyZXNvdXJjZS1uYW1lfVxuICAgKlxuICAgKiBUaGUgcmVxdWlyZWQgQVJOIHBpZWNlcyB0aGF0IGFyZSBvbWl0dGVkIHdpbGwgYmUgdGFrZW4gZnJvbSB0aGUgc3RhY2sgdGhhdFxuICAgKiB0aGUgJ3Njb3BlJyBpcyBhdHRhY2hlZCB0by4gSWYgYWxsIEFSTiBwaWVjZXMgYXJlIHN1cHBsaWVkLCB0aGUgc3VwcGxpZWQgc2NvcGVcbiAgICogY2FuIGJlICd1bmRlZmluZWQnLlxuICAgKi9cbiAgcHVibGljIGZvcm1hdEFybihjb21wb25lbnRzOiBBcm5Db21wb25lbnRzKTogc3RyaW5nIHtcbiAgICByZXR1cm4gQXJuLmZvcm1hdChjb21wb25lbnRzLCB0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHaXZlbiBhbiBBUk4sIHBhcnNlcyBpdCBhbmQgcmV0dXJucyBjb21wb25lbnRzLlxuICAgKlxuICAgKiBJRiBUSEUgQVJOIElTIEEgQ09OQ1JFVEUgU1RSSU5HLi4uXG4gICAqXG4gICAqIC4uLml0IHdpbGwgYmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQuIFRoZSBzZXBhcmF0b3IgKGBzZXBgKSB3aWxsIGJlIHNldCB0byAnLydcbiAgICogaWYgdGhlIDZ0aCBjb21wb25lbnQgaW5jbHVkZXMgYSAnLycsIGluIHdoaWNoIGNhc2UsIGByZXNvdXJjZWAgd2lsbCBiZSBzZXRcbiAgICogdG8gdGhlIHZhbHVlIGJlZm9yZSB0aGUgJy8nIGFuZCBgcmVzb3VyY2VOYW1lYCB3aWxsIGJlIHRoZSByZXN0LiBJbiBjYXNlXG4gICAqIHRoZXJlIGlzIG5vICcvJywgYHJlc291cmNlYCB3aWxsIGJlIHNldCB0byB0aGUgNnRoIGNvbXBvbmVudHMgYW5kXG4gICAqIGByZXNvdXJjZU5hbWVgIHdpbGwgYmUgc2V0IHRvIHRoZSByZXN0IG9mIHRoZSBzdHJpbmcuXG4gICAqXG4gICAqIElGIFRIRSBBUk4gSVMgQSBUT0tFTi4uLlxuICAgKlxuICAgKiAuLi5pdCBjYW5ub3QgYmUgdmFsaWRhdGVkLCBzaW5jZSB3ZSBkb24ndCBoYXZlIHRoZSBhY3R1YWwgdmFsdWUgeWV0IGF0IHRoZVxuICAgKiB0aW1lIG9mIHRoaXMgZnVuY3Rpb24gY2FsbC4gWW91IHdpbGwgaGF2ZSB0byBzdXBwbHkgYHNlcElmVG9rZW5gIGFuZFxuICAgKiB3aGV0aGVyIG9yIG5vdCBBUk5zIG9mIHRoZSBleHBlY3RlZCBmb3JtYXQgdXN1YWxseSBoYXZlIHJlc291cmNlIG5hbWVzXG4gICAqIGluIG9yZGVyIHRvIHBhcnNlIGl0IHByb3Blcmx5LiBUaGUgcmVzdWx0aW5nIGBBcm5Db21wb25lbnRzYCBvYmplY3Qgd2lsbFxuICAgKiBjb250YWluIHRva2VucyBmb3IgdGhlIHN1YmV4cHJlc3Npb25zIG9mIHRoZSBBUk4sIG5vdCBzdHJpbmcgbGl0ZXJhbHMuXG4gICAqXG4gICAqIElmIHRoZSByZXNvdXJjZSBuYW1lIGNvdWxkIHBvc3NpYmx5IGNvbnRhaW4gdGhlIHNlcGFyYXRvciBjaGFyLCB0aGUgYWN0dWFsXG4gICAqIHJlc291cmNlIG5hbWUgY2Fubm90IGJlIHByb3Blcmx5IHBhcnNlZC4gVGhpcyBvbmx5IG9jY3VycyBpZiB0aGUgc2VwYXJhdG9yXG4gICAqIGNoYXIgaXMgJy8nLCBhbmQgaGFwcGVucyBmb3IgZXhhbXBsZSBmb3IgUzMgb2JqZWN0IEFSTnMsIElBTSBSb2xlIEFSTnMsXG4gICAqIElBTSBPSURDIFByb3ZpZGVyIEFSTnMsIGV0Yy4gVG8gcHJvcGVybHkgZXh0cmFjdCB0aGUgcmVzb3VyY2UgbmFtZSBmcm9tIGFcbiAgICogVG9rZW5pemVkIEFSTiwgeW91IG11c3Qga25vdyB0aGUgcmVzb3VyY2UgdHlwZSBhbmQgY2FsbFxuICAgKiBgQXJuLmV4dHJhY3RSZXNvdXJjZU5hbWVgLlxuICAgKlxuICAgKiBAcGFyYW0gYXJuIFRoZSBBUk4gc3RyaW5nIHRvIHBhcnNlXG4gICAqIEBwYXJhbSBzZXBJZlRva2VuIFRoZSBzZXBhcmF0b3IgdXNlZCB0byBzZXBhcmF0ZSByZXNvdXJjZSBmcm9tIHJlc291cmNlTmFtZVxuICAgKiBAcGFyYW0gaGFzTmFtZSBXaGV0aGVyIHRoZXJlIGlzIGEgbmFtZSBjb21wb25lbnQgaW4gdGhlIEFSTiBhdCBhbGwuIEZvclxuICAgKiBleGFtcGxlLCBTTlMgVG9waWNzIEFSTnMgaGF2ZSB0aGUgJ3Jlc291cmNlJyBjb21wb25lbnQgY29udGFpbiB0aGUgdG9waWNcbiAgICogbmFtZSwgYW5kIG5vICdyZXNvdXJjZU5hbWUnIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHJldHVybnMgYW4gQXJuQ29tcG9uZW50cyBvYmplY3Qgd2hpY2ggYWxsb3dzIGFjY2VzcyB0byB0aGUgdmFyaW91c1xuICAgKiBjb21wb25lbnRzIG9mIHRoZSBBUk4uXG4gICAqXG4gICAqIEByZXR1cm5zIGFuIEFybkNvbXBvbmVudHMgb2JqZWN0IHdoaWNoIGFsbG93cyBhY2Nlc3MgdG8gdGhlIHZhcmlvdXNcbiAgICogICAgICBjb21wb25lbnRzIG9mIHRoZSBBUk4uXG4gICAqXG4gICAqIEBkZXByZWNhdGVkIHVzZSBzcGxpdEFybiBpbnN0ZWFkXG4gICAqL1xuICBwdWJsaWMgcGFyc2VBcm4oYXJuOiBzdHJpbmcsIHNlcElmVG9rZW46IHN0cmluZyA9ICcvJywgaGFzTmFtZTogYm9vbGVhbiA9IHRydWUpOiBBcm5Db21wb25lbnRzIHtcbiAgICByZXR1cm4gQXJuLnBhcnNlKGFybiwgc2VwSWZUb2tlbiwgaGFzTmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogU3BsaXRzIHRoZSBwcm92aWRlZCBBUk4gaW50byBpdHMgY29tcG9uZW50cy5cbiAgICogV29ya3MgYm90aCBpZiAnYXJuJyBpcyBhIHN0cmluZyBsaWtlICdhcm46YXdzOnMzOjo6YnVja2V0JyxcbiAgICogYW5kIGEgVG9rZW4gcmVwcmVzZW50aW5nIGEgZHluYW1pYyBDbG91ZEZvcm1hdGlvbiBleHByZXNzaW9uXG4gICAqIChpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCBjb21wb25lbnRzIHdpbGwgYWxzbyBiZSBkeW5hbWljIENsb3VkRm9ybWF0aW9uIGV4cHJlc3Npb25zLFxuICAgKiBlbmNvZGVkIGFzIFRva2VucykuXG4gICAqXG4gICAqIEBwYXJhbSBhcm4gdGhlIEFSTiB0byBzcGxpdCBpbnRvIGl0cyBjb21wb25lbnRzXG4gICAqIEBwYXJhbSBhcm5Gb3JtYXQgdGhlIGV4cGVjdGVkIGZvcm1hdCBvZiAnYXJuJyAtIGRlcGVuZHMgb24gd2hhdCBmb3JtYXQgdGhlIHNlcnZpY2UgJ2FybicgcmVwcmVzZW50cyB1c2VzXG4gICAqL1xuICBwdWJsaWMgc3BsaXRBcm4oYXJuOiBzdHJpbmcsIGFybkZvcm1hdDogQXJuRm9ybWF0KTogQXJuQ29tcG9uZW50cyB7XG4gICAgcmV0dXJuIEFybi5zcGxpdChhcm4sIGFybkZvcm1hdCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbGlzdCBvZiBBWnMgdGhhdCBhcmUgYXZhaWxhYmxlIGluIHRoZSBBV1MgZW52aXJvbm1lbnRcbiAgICogKGFjY291bnQvcmVnaW9uKSBhc3NvY2lhdGVkIHdpdGggdGhpcyBzdGFjay5cbiAgICpcbiAgICogSWYgdGhlIHN0YWNrIGlzIGVudmlyb25tZW50LWFnbm9zdGljIChlaXRoZXIgYWNjb3VudCBhbmQvb3IgcmVnaW9uIGFyZVxuICAgKiB0b2tlbnMpLCB0aGlzIHByb3BlcnR5IHdpbGwgcmV0dXJuIGFuIGFycmF5IHdpdGggMiB0b2tlbnMgdGhhdCB3aWxsIHJlc29sdmVcbiAgICogYXQgZGVwbG95LXRpbWUgdG8gdGhlIGZpcnN0IHR3byBhdmFpbGFiaWxpdHkgem9uZXMgcmV0dXJuZWQgZnJvbSBDbG91ZEZvcm1hdGlvbidzXG4gICAqIGBGbjo6R2V0QVpzYCBpbnRyaW5zaWMgZnVuY3Rpb24uXG4gICAqXG4gICAqIElmIHRoZXkgYXJlIG5vdCBhdmFpbGFibGUgaW4gdGhlIGNvbnRleHQsIHJldHVybnMgYSBzZXQgb2YgZHVtbXkgdmFsdWVzIGFuZFxuICAgKiByZXBvcnRzIHRoZW0gYXMgbWlzc2luZywgYW5kIGxldCB0aGUgQ0xJIHJlc29sdmUgdGhlbSBieSBjYWxsaW5nIEVDMlxuICAgKiBgRGVzY3JpYmVBdmFpbGFiaWxpdHlab25lc2Agb24gdGhlIHRhcmdldCBlbnZpcm9ubWVudC5cbiAgICpcbiAgICogVG8gc3BlY2lmeSBhIGRpZmZlcmVudCBzdHJhdGVneSBmb3Igc2VsZWN0aW5nIGF2YWlsYWJpbGl0eSB6b25lcyBvdmVycmlkZSB0aGlzIG1ldGhvZC5cbiAgICovXG4gIHB1YmxpYyBnZXQgYXZhaWxhYmlsaXR5Wm9uZXMoKTogc3RyaW5nW10ge1xuICAgIC8vIGlmIGFjY291bnQvcmVnaW9uIGFyZSB0b2tlbnMsIHdlIGNhbid0IG9idGFpbiBBWnMgdGhyb3VnaCB0aGUgY29udGV4dFxuICAgIC8vIHByb3ZpZGVyLCBzbyB3ZSBmYWxsYmFjayB0byB1c2UgRm46OkdldEFacy4gdGhlIGN1cnJlbnQgbG93ZXN0IGNvbW1vblxuICAgIC8vIGRlbm9taW5hdG9yIGlzIDIgQVpzIGFjcm9zcyBhbGwgQVdTIHJlZ2lvbnMuXG4gICAgY29uc3QgYWdub3N0aWMgPSBUb2tlbi5pc1VucmVzb2x2ZWQodGhpcy5hY2NvdW50KSB8fCBUb2tlbi5pc1VucmVzb2x2ZWQodGhpcy5yZWdpb24pO1xuICAgIGlmIChhZ25vc3RpYykge1xuICAgICAgcmV0dXJuIHRoaXMubm9kZS50cnlHZXRDb250ZXh0KGN4YXBpLkFWQUlMQUJJTElUWV9aT05FX0ZBTExCQUNLX0NPTlRFWFRfS0VZKSB8fCBbXG4gICAgICAgIEZuLnNlbGVjdCgwLCBGbi5nZXRBenMoKSksXG4gICAgICAgIEZuLnNlbGVjdCgxLCBGbi5nZXRBenMoKSksXG4gICAgICBdO1xuICAgIH1cblxuICAgIGNvbnN0IHZhbHVlID0gQ29udGV4dFByb3ZpZGVyLmdldFZhbHVlKHRoaXMsIHtcbiAgICAgIHByb3ZpZGVyOiBjeHNjaGVtYS5Db250ZXh0UHJvdmlkZXIuQVZBSUxBQklMSVRZX1pPTkVfUFJPVklERVIsXG4gICAgICBkdW1teVZhbHVlOiBbJ2R1bW15MWEnLCAnZHVtbXkxYicsICdkdW1teTFjJ10sXG4gICAgfSkudmFsdWU7XG5cbiAgICBpZiAoIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFByb3ZpZGVyICR7Y3hzY2hlbWEuQ29udGV4dFByb3ZpZGVyLkFWQUlMQUJJTElUWV9aT05FX1BST1ZJREVSfSBleHBlY3RzIGEgbGlzdGApO1xuICAgIH1cblxuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhIGZpbGUgYXNzZXQgb24gdGhpcyBTdGFja1xuICAgKlxuICAgKiBAZGVwcmVjYXRlZCBVc2UgYHN0YWNrLnN5bnRoZXNpemVyLmFkZEZpbGVBc3NldCgpYCBpZiB5b3UgYXJlIGNhbGxpbmcsXG4gICAqIGFuZCBhIGRpZmZlcmVudCBJU3RhY2tTeW50aGVzaXplciBjbGFzcyBpZiB5b3UgYXJlIGltcGxlbWVudGluZy5cbiAgICovXG4gIHB1YmxpYyBhZGRGaWxlQXNzZXQoYXNzZXQ6IEZpbGVBc3NldFNvdXJjZSk6IEZpbGVBc3NldExvY2F0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5zeW50aGVzaXplci5hZGRGaWxlQXNzZXQoYXNzZXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVyIGEgZG9ja2VyIGltYWdlIGFzc2V0IG9uIHRoaXMgU3RhY2tcbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgVXNlIGBzdGFjay5zeW50aGVzaXplci5hZGREb2NrZXJJbWFnZUFzc2V0KClgIGlmIHlvdSBhcmUgY2FsbGluZyxcbiAgICogYW5kIGEgZGlmZmVyZW50IGBJU3RhY2tTeW50aGVzaXplcmAgY2xhc3MgaWYgeW91IGFyZSBpbXBsZW1lbnRpbmcuXG4gICAqL1xuICBwdWJsaWMgYWRkRG9ja2VySW1hZ2VBc3NldChhc3NldDogRG9ja2VySW1hZ2VBc3NldFNvdXJjZSk6IERvY2tlckltYWdlQXNzZXRMb2NhdGlvbiB7XG4gICAgcmV0dXJuIHRoaXMuc3ludGhlc2l6ZXIuYWRkRG9ja2VySW1hZ2VBc3NldChhc3NldCk7XG4gIH1cblxuICAvKipcbiAgICogSWYgdGhpcyBpcyBhIG5lc3RlZCBzdGFjaywgcmV0dXJucyBpdCdzIHBhcmVudCBzdGFjay5cbiAgICovXG4gIHB1YmxpYyBnZXQgbmVzdGVkU3RhY2tQYXJlbnQoKSB7XG4gICAgcmV0dXJuIHRoaXMubmVzdGVkU3RhY2tSZXNvdXJjZSAmJiBTdGFjay5vZih0aGlzLm5lc3RlZFN0YWNrUmVzb3VyY2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHBhcmVudCBvZiBhIG5lc3RlZCBzdGFjay5cbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGBuZXN0ZWRTdGFja1BhcmVudGBcbiAgICovXG4gIHB1YmxpYyBnZXQgcGFyZW50U3RhY2soKSB7XG4gICAgcmV0dXJuIHRoaXMubmVzdGVkU3RhY2tQYXJlbnQ7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgVHJhbnNmb3JtIHRvIHRoaXMgc3RhY2suIEEgVHJhbnNmb3JtIGlzIGEgbWFjcm8gdGhhdCBBV1NcbiAgICogQ2xvdWRGb3JtYXRpb24gdXNlcyB0byBwcm9jZXNzIHlvdXIgdGVtcGxhdGUuXG4gICAqXG4gICAqIER1cGxpY2F0ZSB2YWx1ZXMgYXJlIHJlbW92ZWQgd2hlbiBzdGFjayBpcyBzeW50aGVzaXplZC5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTQ2xvdWRGb3JtYXRpb24vbGF0ZXN0L1VzZXJHdWlkZS90cmFuc2Zvcm0tc2VjdGlvbi1zdHJ1Y3R1cmUuaHRtbFxuICAgKiBAcGFyYW0gdHJhbnNmb3JtIFRoZSB0cmFuc2Zvcm0gdG8gYWRkXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGRlY2xhcmUgY29uc3Qgc3RhY2s6IFN0YWNrO1xuICAgKlxuICAgKiBzdGFjay5hZGRUcmFuc2Zvcm0oJ0FXUzo6U2VydmVybGVzcy0yMDE2LTEwLTMxJylcbiAgICovXG4gIHB1YmxpYyBhZGRUcmFuc2Zvcm0odHJhbnNmb3JtOiBzdHJpbmcpIHtcbiAgICBpZiAoIXRoaXMudGVtcGxhdGVPcHRpb25zLnRyYW5zZm9ybXMpIHtcbiAgICAgIHRoaXMudGVtcGxhdGVPcHRpb25zLnRyYW5zZm9ybXMgPSBbXTtcbiAgICB9XG4gICAgdGhpcy50ZW1wbGF0ZU9wdGlvbnMudHJhbnNmb3Jtcy5wdXNoKHRyYW5zZm9ybSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbGVkIGltcGxpY2l0bHkgYnkgdGhlIGBhZGREZXBlbmRlbmN5YCBoZWxwZXIgZnVuY3Rpb24gaW4gb3JkZXIgdG9cbiAgICogcmVhbGl6ZSBhIGRlcGVuZGVuY3kgYmV0d2VlbiB0d28gdG9wLWxldmVsIHN0YWNrcyBhdCB0aGUgYXNzZW1ibHkgbGV2ZWwuXG4gICAqXG4gICAqIFVzZSBgc3RhY2suYWRkRGVwZW5kZW5jeWAgdG8gZGVmaW5lIHRoZSBkZXBlbmRlbmN5IGJldHdlZW4gYW55IHR3byBzdGFja3MsXG4gICAqIGFuZCB0YWtlIGludG8gYWNjb3VudCBuZXN0ZWQgc3RhY2sgcmVsYXRpb25zaGlwcy5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBwdWJsaWMgX2FkZEFzc2VtYmx5RGVwZW5kZW5jeSh0YXJnZXQ6IFN0YWNrLCByZWFzb24/OiBzdHJpbmcpIHtcbiAgICAvLyBkZWZlbnNpdmU6IHdlIHNob3VsZCBuZXZlciBnZXQgaGVyZSBmb3IgbmVzdGVkIHN0YWNrc1xuICAgIGlmICh0aGlzLm5lc3RlZCB8fCB0YXJnZXQubmVzdGVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBhZGQgYXNzZW1ibHktbGV2ZWwgZGVwZW5kZW5jaWVzIGZvciBuZXN0ZWQgc3RhY2tzJyk7XG4gICAgfVxuXG4gICAgcmVhc29uID0gcmVhc29uIHx8ICdkZXBlbmRlbmN5IGFkZGVkIHVzaW5nIHN0YWNrLmFkZERlcGVuZGVuY3koKSc7XG4gICAgY29uc3QgY3ljbGUgPSB0YXJnZXQuc3RhY2tEZXBlbmRlbmN5UmVhc29ucyh0aGlzKTtcbiAgICBpZiAoY3ljbGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG1heC1sZW5cbiAgICAgIHRocm93IG5ldyBFcnJvcihgJyR7dGFyZ2V0Lm5vZGUucGF0aH0nIGRlcGVuZHMgb24gJyR7dGhpcy5ub2RlLnBhdGh9JyAoJHtjeWNsZS5qb2luKCcsICcpfSkuIEFkZGluZyB0aGlzIGRlcGVuZGVuY3kgKCR7cmVhc29ufSkgd291bGQgY3JlYXRlIGEgY3ljbGljIHJlZmVyZW5jZS5gKTtcbiAgICB9XG5cbiAgICBsZXQgZGVwID0gdGhpcy5fc3RhY2tEZXBlbmRlbmNpZXNbTmFtZXMudW5pcXVlSWQodGFyZ2V0KV07XG4gICAgaWYgKCFkZXApIHtcbiAgICAgIGRlcCA9IHRoaXMuX3N0YWNrRGVwZW5kZW5jaWVzW05hbWVzLnVuaXF1ZUlkKHRhcmdldCldID0ge1xuICAgICAgICBzdGFjazogdGFyZ2V0LFxuICAgICAgICByZWFzb25zOiBbXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgZGVwLnJlYXNvbnMucHVzaChyZWFzb24pO1xuXG4gICAgaWYgKHByb2Nlc3MuZW52LkNES19ERUJVR19ERVBTKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgICAgY29uc29sZS5lcnJvcihgW0NES19ERUJVR19ERVBTXSBzdGFjayBcIiR7dGhpcy5ub2RlLnBhdGh9XCIgZGVwZW5kcyBvbiBcIiR7dGFyZ2V0Lm5vZGUucGF0aH1cIiBiZWNhdXNlOiAke3JlYXNvbn1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3ludGhlc2l6ZXMgdGhlIGNsb3VkZm9ybWF0aW9uIHRlbXBsYXRlIGludG8gYSBjbG91ZCBhc3NlbWJseS5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBwdWJsaWMgX3N5bnRoZXNpemVUZW1wbGF0ZShzZXNzaW9uOiBJU3ludGhlc2lzU2Vzc2lvbiwgbG9va3VwUm9sZUFybj86IHN0cmluZyk6IHZvaWQge1xuICAgIC8vIEluIHByaW5jaXBsZSwgc3RhY2sgc3ludGhlc2lzIGlzIGRlbGVnYXRlZCB0byB0aGVcbiAgICAvLyBTdGFja1N5bnRoZXNpcyBvYmplY3QuXG4gICAgLy9cbiAgICAvLyBIb3dldmVyLCBzb21lIHBhcnRzIG9mIHN5bnRoZXNpcyBjdXJyZW50bHkgdXNlIHNvbWUgcHJpdmF0ZVxuICAgIC8vIG1ldGhvZHMgb24gU3RhY2ssIGFuZCBJIGRvbid0IHJlYWxseSBzZWUgdGhlIHZhbHVlIGluIHJlZmFjdG9yaW5nXG4gICAgLy8gdGhpcyByaWdodCBub3csIHNvIHNvbWUgcGFydHMgc3RpbGwgaGFwcGVuIGhlcmUuXG4gICAgY29uc3QgYnVpbGRlciA9IHNlc3Npb24uYXNzZW1ibHk7XG5cbiAgICBjb25zdCB0ZW1wbGF0ZSA9IHRoaXMuX3RvQ2xvdWRGb3JtYXRpb24oKTtcblxuICAgIC8vIHdyaXRlIHRoZSBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZSBhcyBhIEpTT04gZmlsZVxuICAgIGNvbnN0IG91dFBhdGggPSBwYXRoLmpvaW4oYnVpbGRlci5vdXRkaXIsIHRoaXMudGVtcGxhdGVGaWxlKTtcblxuICAgIGlmICh0aGlzLm1heFJlc291cmNlcyA+IDApIHtcbiAgICAgIGNvbnN0IHJlc291cmNlcyA9IHRlbXBsYXRlLlJlc291cmNlcyB8fCB7fTtcbiAgICAgIGNvbnN0IG51bWJlck9mUmVzb3VyY2VzID0gT2JqZWN0LmtleXMocmVzb3VyY2VzKS5sZW5ndGg7XG5cbiAgICAgIGlmIChudW1iZXJPZlJlc291cmNlcyA+IHRoaXMubWF4UmVzb3VyY2VzKSB7XG4gICAgICAgIGNvbnN0IGNvdW50cyA9IE9iamVjdC5lbnRyaWVzKGNvdW50KE9iamVjdC52YWx1ZXMocmVzb3VyY2VzKS5tYXAoKHI6IGFueSkgPT4gYCR7cj8uVHlwZX1gKSkpLm1hcCgoW3R5cGUsIGNdKSA9PiBgJHt0eXBlfSAoJHtjfSlgKS5qb2luKCcsICcpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE51bWJlciBvZiByZXNvdXJjZXMgaW4gc3RhY2sgJyR7dGhpcy5ub2RlLnBhdGh9JzogJHtudW1iZXJPZlJlc291cmNlc30gaXMgZ3JlYXRlciB0aGFuIGFsbG93ZWQgbWF4aW11bSBvZiAke3RoaXMubWF4UmVzb3VyY2VzfTogJHtjb3VudHN9YCk7XG4gICAgICB9IGVsc2UgaWYgKG51bWJlck9mUmVzb3VyY2VzID49ICh0aGlzLm1heFJlc291cmNlcyAqIDAuOCkpIHtcbiAgICAgICAgQW5ub3RhdGlvbnMub2YodGhpcykuYWRkSW5mbyhgTnVtYmVyIG9mIHJlc291cmNlczogJHtudW1iZXJPZlJlc291cmNlc30gaXMgYXBwcm9hY2hpbmcgYWxsb3dlZCBtYXhpbXVtIG9mICR7dGhpcy5tYXhSZXNvdXJjZXN9YCk7XG4gICAgICB9XG4gICAgfVxuICAgIGZzLndyaXRlRmlsZVN5bmMob3V0UGF0aCwgSlNPTi5zdHJpbmdpZnkodGVtcGxhdGUsIHVuZGVmaW5lZCwgMSkpO1xuXG4gICAgZm9yIChjb25zdCBjdHggb2YgdGhpcy5fbWlzc2luZ0NvbnRleHQpIHtcbiAgICAgIGlmIChsb29rdXBSb2xlQXJuICE9IG51bGwpIHtcbiAgICAgICAgYnVpbGRlci5hZGRNaXNzaW5nKHsgLi4uY3R4LCBwcm9wczogeyAuLi5jdHgucHJvcHMsIGxvb2t1cFJvbGVBcm4gfSB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGJ1aWxkZXIuYWRkTWlzc2luZyhjdHgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBMb29rIHVwIGEgZmFjdCB2YWx1ZSBmb3IgdGhlIGdpdmVuIGZhY3QgZm9yIHRoZSByZWdpb24gb2YgdGhpcyBzdGFja1xuICAgKlxuICAgKiBXaWxsIHJldHVybiBhIGRlZmluaXRlIHZhbHVlIG9ubHkgaWYgdGhlIHJlZ2lvbiBvZiB0aGUgY3VycmVudCBzdGFjayBpcyByZXNvbHZlZC5cbiAgICogSWYgbm90LCBhIGxvb2t1cCBtYXAgd2lsbCBiZSBhZGRlZCB0byB0aGUgc3RhY2sgYW5kIHRoZSBsb29rdXAgd2lsbCBiZSBkb25lIGF0XG4gICAqIENESyBkZXBsb3ltZW50IHRpbWUuXG4gICAqXG4gICAqIFdoYXQgcmVnaW9ucyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBsb29rdXAgbWFwIGlzIGNvbnRyb2xsZWQgYnkgdGhlXG4gICAqIGBAYXdzLWNkay9jb3JlOnRhcmdldC1wYXJ0aXRpb25zYCBjb250ZXh0IHZhbHVlOiBpdCBtdXN0IGJlIHNldCB0byBhIGxpc3RcbiAgICogb2YgcGFydGl0aW9ucywgYW5kIG9ubHkgcmVnaW9ucyBmcm9tIHRoZSBnaXZlbiBwYXJ0aXRpb25zIHdpbGwgYmUgaW5jbHVkZWQuXG4gICAqIElmIG5vIHN1Y2ggY29udGV4dCBrZXkgaXMgc2V0LCBhbGwgcmVnaW9ucyB3aWxsIGJlIGluY2x1ZGVkLlxuICAgKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGlzIGludGVuZGVkIHRvIGJlIHVzZWQgYnkgY29uc3RydWN0IGxpYnJhcnkgYXV0aG9ycy4gQXBwbGljYXRpb25cbiAgICogYnVpbGRlcnMgY2FuIHJlbHkgb24gdGhlIGFic3RyYWN0aW9ucyBvZmZlcmVkIGJ5IGNvbnN0cnVjdCBsaWJyYXJpZXMgYW5kIGRvXG4gICAqIG5vdCBoYXZlIHRvIHdvcnJ5IGFib3V0IHJlZ2lvbmFsIGZhY3RzLlxuICAgKlxuICAgKiBJZiBgZGVmYXVsdFZhbHVlYCBpcyBub3QgZ2l2ZW4sIGl0IGlzIGFuIGVycm9yIGlmIHRoZSBmYWN0IGlzIHVua25vd24gZm9yXG4gICAqIHRoZSBnaXZlbiByZWdpb24uXG4gICAqL1xuICBwdWJsaWMgcmVnaW9uYWxGYWN0KGZhY3ROYW1lOiBzdHJpbmcsIGRlZmF1bHRWYWx1ZT86IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKCFUb2tlbi5pc1VucmVzb2x2ZWQodGhpcy5yZWdpb24pKSB7XG4gICAgICBjb25zdCByZXQgPSBGYWN0LmZpbmQodGhpcy5yZWdpb24sIGZhY3ROYW1lKSA/PyBkZWZhdWx0VmFsdWU7XG4gICAgICBpZiAocmV0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGByZWdpb24taW5mbzogZG9uJ3Qga25vdyAke2ZhY3ROYW1lfSBmb3IgcmVnaW9uICR7dGhpcy5yZWdpb259LiBVc2UgJ0ZhY3QucmVnaXN0ZXInIHRvIHByb3ZpZGUgdGhpcyB2YWx1ZS5gKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXQ7XG4gICAgfVxuXG4gICAgY29uc3QgcGFydGl0aW9ucyA9IE5vZGUub2YodGhpcykudHJ5R2V0Q29udGV4dChjeGFwaS5UQVJHRVRfUEFSVElUSU9OUyk7XG4gICAgaWYgKHBhcnRpdGlvbnMgIT09IHVuZGVmaW5lZCAmJiAhQXJyYXkuaXNBcnJheShwYXJ0aXRpb25zKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb250ZXh0IHZhbHVlICcke2N4YXBpLlRBUkdFVF9QQVJUSVRJT05TfScgc2hvdWxkIGJlIGEgbGlzdCBvZiBzdHJpbmdzLCBnb3Q6ICR7SlNPTi5zdHJpbmdpZnkoY3hhcGkuVEFSR0VUX1BBUlRJVElPTlMpfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGxvb2t1cE1hcCA9IHBhcnRpdGlvbnMgPyBSZWdpb25JbmZvLmxpbWl0ZWRSZWdpb25NYXAoZmFjdE5hbWUsIHBhcnRpdGlvbnMpIDogUmVnaW9uSW5mby5yZWdpb25NYXAoZmFjdE5hbWUpO1xuXG4gICAgcmV0dXJuIGRlcGxveVRpbWVMb29rdXAodGhpcywgZmFjdE5hbWUsIGxvb2t1cE1hcCwgZGVmYXVsdFZhbHVlKTtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIENsb3VkRm9ybWF0aW9uIEV4cG9ydCBmb3IgYSB2YWx1ZVxuICAgKlxuICAgKiBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgY29ycmVzcG9uZGluZyBgRm4uaW1wb3J0VmFsdWUoKWBcbiAgICogZXhwcmVzc2lvbiBmb3IgdGhpcyBFeHBvcnQuIFlvdSBjYW4gY29udHJvbCB0aGUgbmFtZSBmb3IgdGhlIGV4cG9ydCBieVxuICAgKiBwYXNzaW5nIHRoZSBgbmFtZWAgb3B0aW9uLlxuICAgKlxuICAgKiBJZiB5b3UgZG9uJ3Qgc3VwcGx5IGEgdmFsdWUgZm9yIGBuYW1lYCwgdGhlIHZhbHVlIHlvdSdyZSBleHBvcnRpbmcgbXVzdCBiZVxuICAgKiBhIFJlc291cmNlIGF0dHJpYnV0ZSAoZm9yIGV4YW1wbGU6IGBidWNrZXQuYnVja2V0TmFtZWApIGFuZCBpdCB3aWxsIGJlXG4gICAqIGdpdmVuIHRoZSBzYW1lIG5hbWUgYXMgdGhlIGF1dG9tYXRpYyBjcm9zcy1zdGFjayByZWZlcmVuY2UgdGhhdCB3b3VsZCBiZSBjcmVhdGVkXG4gICAqIGlmIHlvdSB1c2VkIHRoZSBhdHRyaWJ1dGUgaW4gYW5vdGhlciBTdGFjay5cbiAgICpcbiAgICogT25lIG9mIHRoZSB1c2VzIGZvciB0aGlzIG1ldGhvZCBpcyB0byAqcmVtb3ZlKiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW5cbiAgICogdHdvIFN0YWNrcyBlc3RhYmxpc2hlZCBieSBhdXRvbWF0aWMgY3Jvc3Mtc3RhY2sgcmVmZXJlbmNlcy4gSXQgd2lsbFxuICAgKiB0ZW1wb3JhcmlseSBlbnN1cmUgdGhhdCB0aGUgQ2xvdWRGb3JtYXRpb24gRXhwb3J0IHN0aWxsIGV4aXN0cyB3aGlsZSB5b3VcbiAgICogcmVtb3ZlIHRoZSByZWZlcmVuY2UgZnJvbSB0aGUgY29uc3VtaW5nIHN0YWNrLiBBZnRlciB0aGF0LCB5b3UgY2FuIHJlbW92ZVxuICAgKiB0aGUgcmVzb3VyY2UgYW5kIHRoZSBtYW51YWwgZXhwb3J0LlxuICAgKlxuICAgKiAjIyBFeGFtcGxlXG4gICAqXG4gICAqIEhlcmUgaXMgaG93IHRoZSBwcm9jZXNzIHdvcmtzLiBMZXQncyBzYXkgdGhlcmUgYXJlIHR3byBzdGFja3MsXG4gICAqIGBwcm9kdWNlclN0YWNrYCBhbmQgYGNvbnN1bWVyU3RhY2tgLCBhbmQgYHByb2R1Y2VyU3RhY2tgIGhhcyBhIGJ1Y2tldFxuICAgKiBjYWxsZWQgYGJ1Y2tldGAsIHdoaWNoIGlzIHJlZmVyZW5jZWQgYnkgYGNvbnN1bWVyU3RhY2tgIChwZXJoYXBzIGJlY2F1c2VcbiAgICogYW4gQVdTIExhbWJkYSBGdW5jdGlvbiB3cml0ZXMgaW50byBpdCwgb3Igc29tZXRoaW5nIGxpa2UgdGhhdCkuXG4gICAqXG4gICAqIEl0IGlzIG5vdCBzYWZlIHRvIHJlbW92ZSBgcHJvZHVjZXJTdGFjay5idWNrZXRgIGJlY2F1c2UgYXMgdGhlIGJ1Y2tldCBpcyBiZWluZ1xuICAgKiBkZWxldGVkLCBgY29uc3VtZXJTdGFja2AgbWlnaHQgc3RpbGwgYmUgdXNpbmcgaXQuXG4gICAqXG4gICAqIEluc3RlYWQsIHRoZSBwcm9jZXNzIHRha2VzIHR3byBkZXBsb3ltZW50czpcbiAgICpcbiAgICogIyMjIERlcGxveW1lbnQgMTogYnJlYWsgdGhlIHJlbGF0aW9uc2hpcFxuICAgKlxuICAgKiAtIE1ha2Ugc3VyZSBgY29uc3VtZXJTdGFja2Agbm8gbG9uZ2VyIHJlZmVyZW5jZXMgYGJ1Y2tldC5idWNrZXROYW1lYCAobWF5YmUgdGhlIGNvbnN1bWVyXG4gICAqICAgc3RhY2sgbm93IHVzZXMgaXRzIG93biBidWNrZXQsIG9yIGl0IHdyaXRlcyB0byBhbiBBV1MgRHluYW1vREIgdGFibGUsIG9yIG1heWJlIHlvdSBqdXN0XG4gICAqICAgcmVtb3ZlIHRoZSBMYW1iZGEgRnVuY3Rpb24gYWx0b2dldGhlcikuXG4gICAqIC0gSW4gdGhlIGBQcm9kdWNlclN0YWNrYCBjbGFzcywgY2FsbCBgdGhpcy5leHBvcnRWYWx1ZSh0aGlzLmJ1Y2tldC5idWNrZXROYW1lKWAuIFRoaXNcbiAgICogICB3aWxsIG1ha2Ugc3VyZSB0aGUgQ2xvdWRGb3JtYXRpb24gRXhwb3J0IGNvbnRpbnVlcyB0byBleGlzdCB3aGlsZSB0aGUgcmVsYXRpb25zaGlwXG4gICAqICAgYmV0d2VlbiB0aGUgdHdvIHN0YWNrcyBpcyBiZWluZyBicm9rZW4uXG4gICAqIC0gRGVwbG95ICh0aGlzIHdpbGwgZWZmZWN0aXZlbHkgb25seSBjaGFuZ2UgdGhlIGBjb25zdW1lclN0YWNrYCwgYnV0IGl0J3Mgc2FmZSB0byBkZXBsb3kgYm90aCkuXG4gICAqXG4gICAqICMjIyBEZXBsb3ltZW50IDI6IHJlbW92ZSB0aGUgYnVja2V0IHJlc291cmNlXG4gICAqXG4gICAqIC0gWW91IGFyZSBub3cgZnJlZSB0byByZW1vdmUgdGhlIGBidWNrZXRgIHJlc291cmNlIGZyb20gYHByb2R1Y2VyU3RhY2tgLlxuICAgKiAtIERvbid0IGZvcmdldCB0byByZW1vdmUgdGhlIGBleHBvcnRWYWx1ZSgpYCBjYWxsIGFzIHdlbGwuXG4gICAqIC0gRGVwbG95IGFnYWluICh0aGlzIHRpbWUgb25seSB0aGUgYHByb2R1Y2VyU3RhY2tgIHdpbGwgYmUgY2hhbmdlZCAtLSB0aGUgYnVja2V0IHdpbGwgYmUgZGVsZXRlZCkuXG4gICAqL1xuICBwdWJsaWMgZXhwb3J0VmFsdWUoZXhwb3J0ZWRWYWx1ZTogYW55LCBvcHRpb25zOiBFeHBvcnRWYWx1ZU9wdGlvbnMgPSB7fSkge1xuICAgIGlmIChvcHRpb25zLm5hbWUpIHtcbiAgICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYEV4cG9ydCR7b3B0aW9ucy5uYW1lfWAsIHtcbiAgICAgICAgdmFsdWU6IGV4cG9ydGVkVmFsdWUsXG4gICAgICAgIGV4cG9ydE5hbWU6IG9wdGlvbnMubmFtZSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIEZuLmltcG9ydFZhbHVlKG9wdGlvbnMubmFtZSk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzb2x2YWJsZSA9IFRva2VuaXphdGlvbi5yZXZlcnNlKGV4cG9ydGVkVmFsdWUpO1xuICAgIGlmICghcmVzb2x2YWJsZSB8fCAhUmVmZXJlbmNlLmlzUmVmZXJlbmNlKHJlc29sdmFibGUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cG9ydFZhbHVlOiBlaXRoZXIgc3VwcGx5IFxcJ25hbWVcXCcgb3IgbWFrZSBzdXJlIHRvIGV4cG9ydCBhIHJlc291cmNlIGF0dHJpYnV0ZSAobGlrZSBcXCdidWNrZXQuYnVja2V0TmFtZVxcJyknKTtcbiAgICB9XG5cbiAgICAvLyBpZiBleHBvcnRWYWx1ZSBpcyBiZWluZyBjYWxsZWQgbWFudWFsbHkgKHdoaWNoIGlzIHByZSBvblByZXBhcmUpIHRoZW4gdGhlIGxvZ2ljYWxJZFxuICAgIC8vIGNvdWxkIHBvdGVudGlhbGx5IGJlIGNoYW5nZWQgYnkgYSBjYWxsIHRvIG92ZXJyaWRlTG9naWNhbElkLiBUaGlzIHdvdWxkIGNhdXNlIG91ciBFeHBvcnQvSW1wb3J0XG4gICAgLy8gdG8gaGF2ZSBhbiBpbmNvcnJlY3QgaWQuIEZvciBhIGJldHRlciB1c2VyIGV4cGVyaWVuY2UsIGxvY2sgdGhlIGxvZ2ljYWxJZCBhbmQgdGhyb3cgYW4gZXJyb3JcbiAgICAvLyBpZiB0aGUgdXNlciB0cmllcyB0byBvdmVycmlkZSB0aGUgaWQgX2FmdGVyXyBjYWxsaW5nIGV4cG9ydFZhbHVlXG4gICAgaWYgKENmbkVsZW1lbnQuaXNDZm5FbGVtZW50KHJlc29sdmFibGUudGFyZ2V0KSkge1xuICAgICAgcmVzb2x2YWJsZS50YXJnZXQuX2xvY2tMb2dpY2FsSWQoKTtcbiAgICB9XG5cbiAgICAvLyBcInRlbGVwb3J0XCIgdGhlIHZhbHVlIGhlcmUsIGluIGNhc2UgaXQgY29tZXMgZnJvbSBhIG5lc3RlZCBzdGFjay4gVGhpcyB3aWxsIGFsc29cbiAgICAvLyBlbnN1cmUgdGhlIHZhbHVlIGlzIGZyb20gb3VyIG93biBzY29wZS5cbiAgICBjb25zdCBleHBvcnRhYmxlID0gcmVmZXJlbmNlTmVzdGVkU3RhY2tWYWx1ZUluUGFyZW50KHJlc29sdmFibGUsIHRoaXMpO1xuXG4gICAgLy8gRW5zdXJlIGEgc2luZ2xldG9uIFwiRXhwb3J0c1wiIHNjb3BpbmcgQ29uc3RydWN0XG4gICAgLy8gVGhpcyBtb3N0bHkgZXhpc3RzIHRvIHRyaWdnZXIgTG9naWNhbElEIG11bmdpbmcsIHdoaWNoIHdvdWxkIGJlXG4gICAgLy8gZGlzYWJsZWQgaWYgd2UgcGFyZW50ZWQgY29uc3RydWN0cyBkaXJlY3RseSB1bmRlciBTdGFjay5cbiAgICAvLyBBbHNvIGl0IG5pY2VseSBwcmV2ZW50cyBsaWtlbHkgY29uc3RydWN0IG5hbWUgY2xhc2hlc1xuICAgIGNvbnN0IGV4cG9ydHNTY29wZSA9IGdldENyZWF0ZUV4cG9ydHNTY29wZSh0aGlzKTtcblxuICAgIC8vIEVuc3VyZSBhIHNpbmdsZXRvbiBDZm5PdXRwdXQgZm9yIHRoaXMgdmFsdWVcbiAgICBjb25zdCByZXNvbHZlZCA9IHRoaXMucmVzb2x2ZShleHBvcnRhYmxlKTtcbiAgICBjb25zdCBpZCA9ICdPdXRwdXQnICsgSlNPTi5zdHJpbmdpZnkocmVzb2x2ZWQpO1xuICAgIGNvbnN0IGV4cG9ydE5hbWUgPSBnZW5lcmF0ZUV4cG9ydE5hbWUoZXhwb3J0c1Njb3BlLCBpZCk7XG5cbiAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKGV4cG9ydE5hbWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHVucmVzb2x2ZWQgdG9rZW4gaW4gZ2VuZXJhdGVkIGV4cG9ydCBuYW1lOiAke0pTT04uc3RyaW5naWZ5KHRoaXMucmVzb2x2ZShleHBvcnROYW1lKSl9YCk7XG4gICAgfVxuXG4gICAgY29uc3Qgb3V0cHV0ID0gZXhwb3J0c1Njb3BlLm5vZGUudHJ5RmluZENoaWxkKGlkKSBhcyBDZm5PdXRwdXQ7XG4gICAgaWYgKCFvdXRwdXQpIHtcbiAgICAgIG5ldyBDZm5PdXRwdXQoZXhwb3J0c1Njb3BlLCBpZCwgeyB2YWx1ZTogVG9rZW4uYXNTdHJpbmcoZXhwb3J0YWJsZSksIGV4cG9ydE5hbWUgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIEZuLmltcG9ydFZhbHVlKGV4cG9ydE5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIG5hbWluZyBzY2hlbWUgdXNlZCB0byBhbGxvY2F0ZSBsb2dpY2FsIElEcy4gQnkgZGVmYXVsdCwgdXNlc1xuICAgKiB0aGUgYEhhc2hlZEFkZHJlc3NpbmdTY2hlbWVgIGJ1dCB0aGlzIG1ldGhvZCBjYW4gYmUgb3ZlcnJpZGRlbiB0byBjdXN0b21pemVcbiAgICogdGhpcyBiZWhhdmlvci5cbiAgICpcbiAgICogSW4gb3JkZXIgdG8gbWFrZSBzdXJlIGxvZ2ljYWwgSURzIGFyZSB1bmlxdWUgYW5kIHN0YWJsZSwgd2UgaGFzaCB0aGUgcmVzb3VyY2VcbiAgICogY29uc3RydWN0IHRyZWUgcGF0aCAoaS5lLiB0b3BsZXZlbC9zZWNvbmRsZXZlbC8uLi4vbXlyZXNvdXJjZSkgYW5kIGFkZCBpdCBhc1xuICAgKiBhIHN1ZmZpeCB0byB0aGUgcGF0aCBjb21wb25lbnRzIGpvaW5lZCB3aXRob3V0IGEgc2VwYXJhdG9yIChDbG91ZEZvcm1hdGlvblxuICAgKiBJRHMgb25seSBhbGxvdyBhbHBoYW51bWVyaWMgY2hhcmFjdGVycykuXG4gICAqXG4gICAqIFRoZSByZXN1bHQgd2lsbCBiZTpcbiAgICpcbiAgICogICA8cGF0aC5qb2luKCcnKT48bWQ1KHBhdGguam9pbignLycpPlxuICAgKiAgICAgXCJodW1hblwiICAgICAgXCJoYXNoXCJcbiAgICpcbiAgICogSWYgdGhlIFwiaHVtYW5cIiBwYXJ0IG9mIHRoZSBJRCBleGNlZWRzIDI0MCBjaGFyYWN0ZXJzLCB3ZSBzaW1wbHkgdHJpbSBpdCBzb1xuICAgKiB0aGUgdG90YWwgSUQgZG9lc24ndCBleGNlZWQgQ2xvdWRGb3JtYXRpb24ncyAyNTUgY2hhcmFjdGVyIGxpbWl0LlxuICAgKlxuICAgKiBXZSBvbmx5IHRha2UgOCBjaGFyYWN0ZXJzIGZyb20gdGhlIG1kNSBoYXNoICgwLjAwMDAwNSBjaGFuY2Ugb2YgY29sbGlzaW9uKS5cbiAgICpcbiAgICogU3BlY2lhbCBjYXNlczpcbiAgICpcbiAgICogLSBJZiB0aGUgcGF0aCBvbmx5IGNvbnRhaW5zIGEgc2luZ2xlIGNvbXBvbmVudCAoaS5lLiBpdCdzIGEgdG9wLWxldmVsXG4gICAqICAgcmVzb3VyY2UpLCB3ZSB3b24ndCBhZGQgdGhlIGhhc2ggdG8gaXQuIFRoZSBoYXNoIGlzIG5vdCBuZWVkZWQgZm9yXG4gICAqICAgZGlzYW1pZ3VhdGlvbiBhbmQgYWxzbywgaXQgYWxsb3dzIGZvciBhIG1vcmUgc3RyYWlnaHRmb3J3YXJkIG1pZ3JhdGlvbiBhblxuICAgKiAgIGV4aXN0aW5nIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlIHRvIGEgQ0RLIHN0YWNrIHdpdGhvdXQgbG9naWNhbCBJRCBjaGFuZ2VzXG4gICAqICAgKG9yIHJlbmFtZXMpLlxuICAgKiAtIEZvciBhZXN0aGV0aWMgcmVhc29ucywgaWYgdGhlIGxhc3QgY29tcG9uZW50cyBvZiB0aGUgcGF0aCBhcmUgdGhlIHNhbWVcbiAgICogICAoaS5lLiBgTDEvTDIvUGlwZWxpbmUvUGlwZWxpbmVgKSwgdGhleSB3aWxsIGJlIGRlLWR1cGxpY2F0ZWQgdG8gbWFrZSB0aGVcbiAgICogICByZXN1bHRpbmcgaHVtYW4gcG9ydGlvbiBvZiB0aGUgSUQgbW9yZSBwbGVhc2luZzogYEwxTDJQaXBlbGluZTxIQVNIPmBcbiAgICogICBpbnN0ZWFkIG9mIGBMMUwyUGlwZWxpbmVQaXBlbGluZTxIQVNIPmBcbiAgICogLSBJZiBhIGNvbXBvbmVudCBpcyBuYW1lZCBcIkRlZmF1bHRcIiBpdCB3aWxsIGJlIG9taXR0ZWQgZnJvbSB0aGUgcGF0aC4gVGhpc1xuICAgKiAgIGFsbG93cyByZWZhY3RvcmluZyBoaWdoZXIgbGV2ZWwgYWJzdHJhY3Rpb25zIGFyb3VuZCBjb25zdHJ1Y3RzIHdpdGhvdXQgYWZmZWN0aW5nXG4gICAqICAgdGhlIElEcyBvZiBhbHJlYWR5IGRlcGxveWVkIHJlc291cmNlcy5cbiAgICogLSBJZiBhIGNvbXBvbmVudCBpcyBuYW1lZCBcIlJlc291cmNlXCIgaXQgd2lsbCBiZSBvbWl0dGVkIGZyb20gdGhlIHVzZXItdmlzaWJsZVxuICAgKiAgIHBhdGgsIGJ1dCBpbmNsdWRlZCBpbiB0aGUgaGFzaC4gVGhpcyByZWR1Y2VzIHZpc3VhbCBub2lzZSBpbiB0aGUgaHVtYW4gcmVhZGFibGVcbiAgICogICBwYXJ0IG9mIHRoZSBpZGVudGlmaWVyLlxuICAgKlxuICAgKiBAcGFyYW0gY2ZuRWxlbWVudCBUaGUgZWxlbWVudCBmb3Igd2hpY2ggdGhlIGxvZ2ljYWwgSUQgaXMgYWxsb2NhdGVkLlxuICAgKi9cbiAgcHJvdGVjdGVkIGFsbG9jYXRlTG9naWNhbElkKGNmbkVsZW1lbnQ6IENmbkVsZW1lbnQpOiBzdHJpbmcge1xuICAgIGNvbnN0IHNjb3BlcyA9IGNmbkVsZW1lbnQubm9kZS5zY29wZXM7XG4gICAgY29uc3Qgc3RhY2tJbmRleCA9IHNjb3Blcy5pbmRleE9mKGNmbkVsZW1lbnQuc3RhY2spO1xuICAgIGNvbnN0IHBhdGhDb21wb25lbnRzID0gc2NvcGVzLnNsaWNlKHN0YWNrSW5kZXggKyAxKS5tYXAoeCA9PiB4Lm5vZGUuaWQpO1xuICAgIHJldHVybiBtYWtlVW5pcXVlSWQocGF0aENvbXBvbmVudHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHN0YWNrIG5hbWVcbiAgICpcbiAgICogQ2xvdWRGb3JtYXRpb24gc3RhY2sgbmFtZXMgY2FuIGluY2x1ZGUgZGFzaGVzIGluIGFkZGl0aW9uIHRvIHRoZSByZWd1bGFyIGlkZW50aWZpZXJcbiAgICogY2hhcmFjdGVyIGNsYXNzZXMsIGFuZCB3ZSBkb24ndCBhbGxvdyBvbmUgb2YgdGhlIG1hZ2ljIG1hcmtlcnMuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHJvdGVjdGVkIF92YWxpZGF0ZUlkKG5hbWU6IHN0cmluZykge1xuICAgIGlmIChuYW1lICYmICFWQUxJRF9TVEFDS19OQU1FX1JFR0VYLnRlc3QobmFtZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgU3RhY2sgbmFtZSBtdXN0IG1hdGNoIHRoZSByZWd1bGFyIGV4cHJlc3Npb246ICR7VkFMSURfU1RBQ0tfTkFNRV9SRUdFWC50b1N0cmluZygpfSwgZ290ICcke25hbWV9J2ApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZSBmb3IgdGhpcyBzdGFjayBieSB0cmF2ZXJzaW5nXG4gICAqIHRoZSB0cmVlIGFuZCBpbnZva2luZyBfdG9DbG91ZEZvcm1hdGlvbigpIG9uIGFsbCBFbnRpdHkgb2JqZWN0cy5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBwcm90ZWN0ZWQgX3RvQ2xvdWRGb3JtYXRpb24oKSB7XG4gICAgbGV0IHRyYW5zZm9ybTogc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ7XG5cbiAgICBpZiAodGhpcy50ZW1wbGF0ZU9wdGlvbnMudHJhbnNmb3JtKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxlblxuICAgICAgQW5ub3RhdGlvbnMub2YodGhpcykuYWRkV2FybmluZygnVGhpcyBzdGFjayBpcyB1c2luZyB0aGUgZGVwcmVjYXRlZCBgdGVtcGxhdGVPcHRpb25zLnRyYW5zZm9ybWAgcHJvcGVydHkuIENvbnNpZGVyIHN3aXRjaGluZyB0byBgYWRkVHJhbnNmb3JtKClgLicpO1xuICAgICAgdGhpcy5hZGRUcmFuc2Zvcm0odGhpcy50ZW1wbGF0ZU9wdGlvbnMudHJhbnNmb3JtKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy50ZW1wbGF0ZU9wdGlvbnMudHJhbnNmb3Jtcykge1xuICAgICAgaWYgKHRoaXMudGVtcGxhdGVPcHRpb25zLnRyYW5zZm9ybXMubGVuZ3RoID09PSAxKSB7IC8vIEV4dHJhY3Qgc2luZ2xlIHZhbHVlXG4gICAgICAgIHRyYW5zZm9ybSA9IHRoaXMudGVtcGxhdGVPcHRpb25zLnRyYW5zZm9ybXNbMF07XG4gICAgICB9IGVsc2UgeyAvLyBSZW1vdmUgZHVwbGljYXRlIHZhbHVlc1xuICAgICAgICB0cmFuc2Zvcm0gPSBBcnJheS5mcm9tKG5ldyBTZXQodGhpcy50ZW1wbGF0ZU9wdGlvbnMudHJhbnNmb3JtcykpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHRlbXBsYXRlOiBhbnkgPSB7XG4gICAgICBEZXNjcmlwdGlvbjogdGhpcy50ZW1wbGF0ZU9wdGlvbnMuZGVzY3JpcHRpb24sXG4gICAgICBUcmFuc2Zvcm06IHRyYW5zZm9ybSxcbiAgICAgIEFXU1RlbXBsYXRlRm9ybWF0VmVyc2lvbjogdGhpcy50ZW1wbGF0ZU9wdGlvbnMudGVtcGxhdGVGb3JtYXRWZXJzaW9uLFxuICAgICAgTWV0YWRhdGE6IHRoaXMudGVtcGxhdGVPcHRpb25zLm1ldGFkYXRhLFxuICAgIH07XG5cbiAgICBjb25zdCBlbGVtZW50cyA9IGNmbkVsZW1lbnRzKHRoaXMpO1xuICAgIGNvbnN0IGZyYWdtZW50cyA9IGVsZW1lbnRzLm1hcChlID0+IHRoaXMucmVzb2x2ZShlLl90b0Nsb3VkRm9ybWF0aW9uKCkpKTtcblxuICAgIC8vIG1lcmdlIGluIGFsbCBDbG91ZEZvcm1hdGlvbiBmcmFnbWVudHMgY29sbGVjdGVkIGZyb20gdGhlIHRyZWVcbiAgICBmb3IgKGNvbnN0IGZyYWdtZW50IG9mIGZyYWdtZW50cykge1xuICAgICAgbWVyZ2UodGVtcGxhdGUsIGZyYWdtZW50KTtcbiAgICB9XG5cbiAgICAvLyByZXNvbHZlIGFsbCB0b2tlbnMgYW5kIHJlbW92ZSBhbGwgZW1wdGllc1xuICAgIGNvbnN0IHJldCA9IHRoaXMucmVzb2x2ZSh0ZW1wbGF0ZSkgfHwge307XG5cbiAgICB0aGlzLl9sb2dpY2FsSWRzLmFzc2VydEFsbFJlbmFtZXNBcHBsaWVkKCk7XG5cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIERlcHJlY2F0ZWQuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3MtY2RrL3B1bGwvNzE4N1xuICAgKiBAcmV0dXJucyByZWZlcmVuY2UgaXRzZWxmIHdpdGhvdXQgYW55IGNoYW5nZVxuICAgKiBAZGVwcmVjYXRlZCBjcm9zcyByZWZlcmVuY2UgaGFuZGxpbmcgaGFzIGJlZW4gbW92ZWQgdG8gYEFwcC5wcmVwYXJlKClgLlxuICAgKi9cbiAgcHJvdGVjdGVkIHByZXBhcmVDcm9zc1JlZmVyZW5jZShfc291cmNlU3RhY2s6IFN0YWNrLCByZWZlcmVuY2U6IFJlZmVyZW5jZSk6IElSZXNvbHZhYmxlIHtcbiAgICByZXR1cm4gcmVmZXJlbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZSB0aGUgdmFyaW91cyBzdGFjayBlbnZpcm9ubWVudCBhdHRyaWJ1dGVzLlxuICAgKlxuICAgKi9cbiAgcHJpdmF0ZSBwYXJzZUVudmlyb25tZW50KGVudjogRW52aXJvbm1lbnQgPSB7fSkge1xuICAgIC8vIGlmIGFuIGVudmlyb25tZW50IHByb3BlcnR5IGlzIGV4cGxpY2l0bHkgc3BlY2lmaWVkIHdoZW4gdGhlIHN0YWNrIGlzXG4gICAgLy8gY3JlYXRlZCwgaXQgd2lsbCBiZSB1c2VkLiBpZiBub3QsIHVzZSB0b2tlbnMgZm9yIGFjY291bnQgYW5kIHJlZ2lvbi5cbiAgICAvL1xuICAgIC8vIChUaGV5IGRvIG5vdCBuZWVkIHRvIGJlIGFuY2hvcmVkIHRvIGFueSBjb25zdHJ1Y3QgbGlrZSByZXNvdXJjZSBhdHRyaWJ1dGVzXG4gICAgLy8gYXJlLCBiZWNhdXNlIHdlJ2xsIG5ldmVyIEV4cG9ydC9Gbjo6SW1wb3J0VmFsdWUgdGhlbSAtLSB0aGUgb25seSBzaXR1YXRpb25cbiAgICAvLyBpbiB3aGljaCBFeHBvcnQvRm46OkltcG9ydFZhbHVlIHdvdWxkIHdvcmsgaXMgaWYgdGhlIHZhbHVlIGFyZSB0aGUgc2FtZVxuICAgIC8vIGJldHdlZW4gcHJvZHVjZXIgYW5kIGNvbnN1bWVyIGFueXdheSwgc28gd2UgY2FuIGp1c3QgYXNzdW1lIHRoYXQgdGhleSBhcmUpLlxuICAgIGNvbnN0IGNvbnRhaW5pbmdBc3NlbWJseSA9IFN0YWdlLm9mKHRoaXMpO1xuICAgIGNvbnN0IGFjY291bnQgPSBlbnYuYWNjb3VudCA/PyBjb250YWluaW5nQXNzZW1ibHk/LmFjY291bnQgPz8gQXdzLkFDQ09VTlRfSUQ7XG4gICAgY29uc3QgcmVnaW9uID0gZW52LnJlZ2lvbiA/PyBjb250YWluaW5nQXNzZW1ibHk/LnJlZ2lvbiA/PyBBd3MuUkVHSU9OO1xuXG4gICAgLy8gdGhpcyBpcyB0aGUgXCJhd3M6Ly9cIiBlbnYgc3BlY2lmaWNhdGlvbiB0aGF0IHdpbGwgYmUgd3JpdHRlbiB0byB0aGUgY2xvdWQgYXNzZW1ibHlcbiAgICAvLyBtYW5pZmVzdC4gaXQgd2lsbCB1c2UgXCJ1bmtub3duLWFjY291bnRcIiBhbmQgXCJ1bmtub3duLXJlZ2lvblwiIHRvIGluZGljYXRlXG4gICAgLy8gZW52aXJvbm1lbnQtYWdub3N0aWNuZXNzLlxuICAgIGNvbnN0IGVudkFjY291bnQgPSAhVG9rZW4uaXNVbnJlc29sdmVkKGFjY291bnQpID8gYWNjb3VudCA6IGN4YXBpLlVOS05PV05fQUNDT1VOVDtcbiAgICBjb25zdCBlbnZSZWdpb24gPSAhVG9rZW4uaXNVbnJlc29sdmVkKHJlZ2lvbikgPyByZWdpb24gOiBjeGFwaS5VTktOT1dOX1JFR0lPTjtcblxuICAgIHJldHVybiB7XG4gICAgICBhY2NvdW50LFxuICAgICAgcmVnaW9uLFxuICAgICAgZW52aXJvbm1lbnQ6IGN4YXBpLkVudmlyb25tZW50VXRpbHMuZm9ybWF0KGVudkFjY291bnQsIGVudlJlZ2lvbiksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgaW4gdGhlIHN0YWNrXG4gICAqXG4gICAqIFNldCB0byAwIHRvIG1lYW4gXCJ1bmxpbWl0ZWRcIi5cbiAgICovXG4gIHByaXZhdGUgZ2V0IG1heFJlc291cmNlcygpOiBudW1iZXIge1xuICAgIGNvbnN0IGNvbnRleHRMaW1pdCA9IHRoaXMubm9kZS50cnlHZXRDb250ZXh0KFNUQUNLX1JFU09VUkNFX0xJTUlUX0NPTlRFWFQpO1xuICAgIHJldHVybiBjb250ZXh0TGltaXQgIT09IHVuZGVmaW5lZCA/IHBhcnNlSW50KGNvbnRleHRMaW1pdCwgMTApIDogTUFYX1JFU09VUkNFUztcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayB3aGV0aGVyIHRoaXMgc3RhY2sgaGFzIGEgKHRyYW5zaXRpdmUpIGRlcGVuZGVuY3kgb24gYW5vdGhlciBzdGFja1xuICAgKlxuICAgKiBSZXR1cm5zIHRoZSBsaXN0IG9mIHJlYXNvbnMgb24gdGhlIGRlcGVuZGVuY3kgcGF0aCwgb3IgdW5kZWZpbmVkXG4gICAqIGlmIHRoZXJlIGlzIG5vIGRlcGVuZGVuY3kuXG4gICAqL1xuICBwcml2YXRlIHN0YWNrRGVwZW5kZW5jeVJlYXNvbnMob3RoZXI6IFN0YWNrKTogc3RyaW5nW10gfCB1bmRlZmluZWQge1xuICAgIGlmICh0aGlzID09PSBvdGhlcikgeyByZXR1cm4gW107IH1cbiAgICBmb3IgKGNvbnN0IGRlcCBvZiBPYmplY3QudmFsdWVzKHRoaXMuX3N0YWNrRGVwZW5kZW5jaWVzKSkge1xuICAgICAgY29uc3QgcmV0ID0gZGVwLnN0YWNrLnN0YWNrRGVwZW5kZW5jeVJlYXNvbnMob3RoZXIpO1xuICAgICAgaWYgKHJldCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBbLi4uZGVwLnJlYXNvbnMsIC4uLnJldF07XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogQ2FsY3VsYXRlIHRoZSBzdGFjayBuYW1lIGJhc2VkIG9uIHRoZSBjb25zdHJ1Y3QgcGF0aFxuICAgKlxuICAgKiBUaGUgc3RhY2sgbmFtZSBpcyB0aGUgbmFtZSB1bmRlciB3aGljaCB3ZSdsbCBkZXBsb3kgdGhlIHN0YWNrLFxuICAgKiBhbmQgaW5jb3Jwb3JhdGVzIGNvbnRhaW5pbmcgU3RhZ2UgbmFtZXMgYnkgZGVmYXVsdC5cbiAgICpcbiAgICogR2VuZXJhbGx5IHRoaXMgbG9va3MgYSBsb3QgbGlrZSBob3cgbG9naWNhbCBJRHMgYXJlIGNhbGN1bGF0ZWQuXG4gICAqIFRoZSBzdGFjayBuYW1lIGlzIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlIGNvbnN0cnVjdCByb290IHBhdGgsXG4gICAqIGFzIGZvbGxvd3M6XG4gICAqXG4gICAqIC0gUGF0aCBpcyBjYWxjdWxhdGVkIHdpdGggcmVzcGVjdCB0byBjb250YWluaW5nIEFwcCBvciBTdGFnZSAoaWYgYW55KVxuICAgKiAtIElmIHRoZSBwYXRoIGlzIG9uZSBjb21wb25lbnQgbG9uZyBqdXN0IHVzZSB0aGF0IGNvbXBvbmVudCwgb3RoZXJ3aXNlXG4gICAqICAgY29tYmluZSB0aGVtIHdpdGggYSBoYXNoLlxuICAgKlxuICAgKiBTaW5jZSB0aGUgaGFzaCBpcyBxdWl0ZSB1Z2x5IGFuZCB3ZSdkIGxpa2UgdG8gYXZvaWQgaXQgaWYgcG9zc2libGUgLS0gYnV0XG4gICAqIHdlIGNhbid0IGFueW1vcmUgaW4gdGhlIGdlbmVyYWwgY2FzZSBzaW5jZSBpdCBoYXMgYmVlbiB3cml0dGVuIGludG8gbGVnYWN5XG4gICAqIHN0YWNrcy4gVGhlIGludHJvZHVjdGlvbiBvZiBTdGFnZXMgbWFrZXMgaXQgcG9zc2libGUgdG8gbWFrZSB0aGlzIG5pY2VyIGhvd2V2ZXIuXG4gICAqIFdoZW4gYSBTdGFjayBpcyBuZXN0ZWQgaW5zaWRlIGEgU3RhZ2UsIHdlIHVzZSB0aGUgcGF0aCBjb21wb25lbnRzIGJlbG93IHRoZVxuICAgKiBTdGFnZSwgYW5kIHByZWZpeCB0aGUgcGF0aCBjb21wb25lbnRzIG9mIHRoZSBTdGFnZSBiZWZvcmUgaXQuXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlU3RhY2tOYW1lKCkge1xuICAgIGNvbnN0IGFzc2VtYmx5ID0gU3RhZ2Uub2YodGhpcyk7XG4gICAgY29uc3QgcHJlZml4ID0gKGFzc2VtYmx5ICYmIGFzc2VtYmx5LnN0YWdlTmFtZSkgPyBgJHthc3NlbWJseS5zdGFnZU5hbWV9LWAgOiAnJztcbiAgICByZXR1cm4gYCR7cHJlZml4fSR7dGhpcy5nZW5lcmF0ZVN0YWNrSWQoYXNzZW1ibHkpfWA7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGFydGlmYWN0IElEIGZvciB0aGlzIHN0YWNrXG4gICAqXG4gICAqIFN0YWNrIGFydGlmYWN0IElEIGlzIHVuaXF1ZSB3aXRoaW4gdGhlIEFwcCdzIENsb3VkIEFzc2VtYmx5LlxuICAgKi9cbiAgcHJpdmF0ZSBnZW5lcmF0ZVN0YWNrQXJ0aWZhY3RJZCgpIHtcbiAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZVN0YWNrSWQodGhpcy5ub2RlLnJvb3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGFuIElEIHdpdGggcmVzcGVjdCB0byB0aGUgZ2l2ZW4gY29udGFpbmVyIGNvbnN0cnVjdC5cbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVTdGFja0lkKGNvbnRhaW5lcjogSUNvbnN0cnVjdCB8IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IHJvb3RQYXRoID0gcm9vdFBhdGhUbyh0aGlzLCBjb250YWluZXIpO1xuICAgIGNvbnN0IGlkcyA9IHJvb3RQYXRoLm1hcChjID0+IE5vZGUub2YoYykuaWQpO1xuXG4gICAgLy8gSW4gdW5pdCB0ZXN0cyBvdXIgU3RhY2sgKHdoaWNoIGlzIHRoZSBvbmx5IGNvbXBvbmVudCkgbWF5IG5vdCBoYXZlIGFuXG4gICAgLy8gaWQsIHNvIGluIHRoYXQgY2FzZSBqdXN0IHByZXRlbmQgaXQncyBcIlN0YWNrXCIuXG4gICAgaWYgKGlkcy5sZW5ndGggPT09IDEgJiYgIWlkc1swXSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmV4cGVjdGVkOiBzdGFjayBpZCBtdXN0IGFsd2F5cyBiZSBkZWZpbmVkJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1ha2VTdGFja05hbWUoaWRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgd2hldGhlciB0aGUgc3RhY2sgcmVxdWlyZXMgYnVuZGxpbmcgb3Igbm90XG4gICAqL1xuICBwdWJsaWMgZ2V0IGJ1bmRsaW5nUmVxdWlyZWQoKSB7XG4gICAgY29uc3QgYnVuZGxpbmdTdGFja3M6IHN0cmluZ1tdID0gdGhpcy5ub2RlLnRyeUdldENvbnRleHQoY3hhcGkuQlVORExJTkdfU1RBQ0tTKSA/PyBbJyonXTtcblxuICAgIC8vIGJ1bmRsaW5nU3RhY2tzIGlzIG9mIHRoZSBmb3JtIGBTdGFnZS9TdGFja2AsIGNvbnZlcnQgaXQgdG8gYFN0YWdlLVN0YWNrYCBiZWZvcmUgY29tcGFyaW5nIHRvIHN0YWNrIG5hbWVcbiAgICByZXR1cm4gYnVuZGxpbmdTdGFja3Muc29tZShwYXR0ZXJuID0+IG1pbmltYXRjaChcbiAgICAgIHRoaXMuc3RhY2tOYW1lLFxuICAgICAgcGF0dGVybi5yZXBsYWNlKCcvJywgJy0nKSxcbiAgICApKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBtZXJnZSh0ZW1wbGF0ZTogYW55LCBmcmFnbWVudDogYW55KTogdm9pZCB7XG4gIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBPYmplY3Qua2V5cyhmcmFnbWVudCkpIHtcbiAgICBjb25zdCBzcmMgPSBmcmFnbWVudFtzZWN0aW9uXTtcblxuICAgIC8vIGNyZWF0ZSB0b3AtbGV2ZWwgc2VjdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0XG4gICAgY29uc3QgZGVzdCA9IHRlbXBsYXRlW3NlY3Rpb25dO1xuICAgIGlmICghZGVzdCkge1xuICAgICAgdGVtcGxhdGVbc2VjdGlvbl0gPSBzcmM7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRlbXBsYXRlW3NlY3Rpb25dID0gbWVyZ2VTZWN0aW9uKHNlY3Rpb24sIGRlc3QsIHNyYyk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIG1lcmdlU2VjdGlvbihzZWN0aW9uOiBzdHJpbmcsIHZhbDE6IGFueSwgdmFsMjogYW55KTogYW55IHtcbiAgc3dpdGNoIChzZWN0aW9uKSB7XG4gICAgY2FzZSAnRGVzY3JpcHRpb24nOlxuICAgICAgcmV0dXJuIGAke3ZhbDF9XFxuJHt2YWwyfWA7XG4gICAgY2FzZSAnQVdTVGVtcGxhdGVGb3JtYXRWZXJzaW9uJzpcbiAgICAgIGlmICh2YWwxICE9IG51bGwgJiYgdmFsMiAhPSBudWxsICYmIHZhbDEgIT09IHZhbDIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb25mbGljdGluZyBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZSB2ZXJzaW9ucyBwcm92aWRlZDogJyR7dmFsMX0nIGFuZCAnJHt2YWwyfWApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHZhbDEgPz8gdmFsMjtcbiAgICBjYXNlICdUcmFuc2Zvcm0nOlxuICAgICAgcmV0dXJuIG1lcmdlU2V0cyh2YWwxLCB2YWwyKTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIG1lcmdlT2JqZWN0c1dpdGhvdXREdXBsaWNhdGVzKHNlY3Rpb24sIHZhbDEsIHZhbDIpO1xuICB9XG59XG5cbmZ1bmN0aW9uIG1lcmdlU2V0cyh2YWwxOiBhbnksIHZhbDI6IGFueSk6IGFueSB7XG4gIGNvbnN0IGFycmF5MSA9IHZhbDEgPT0gbnVsbCA/IFtdIDogKEFycmF5LmlzQXJyYXkodmFsMSkgPyB2YWwxIDogW3ZhbDFdKTtcbiAgY29uc3QgYXJyYXkyID0gdmFsMiA9PSBudWxsID8gW10gOiAoQXJyYXkuaXNBcnJheSh2YWwyKSA/IHZhbDIgOiBbdmFsMl0pO1xuICBmb3IgKGNvbnN0IHZhbHVlIG9mIGFycmF5Mikge1xuICAgIGlmICghYXJyYXkxLmluY2x1ZGVzKHZhbHVlKSkge1xuICAgICAgYXJyYXkxLnB1c2godmFsdWUpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gYXJyYXkxLmxlbmd0aCA9PT0gMSA/IGFycmF5MVswXSA6IGFycmF5MTtcbn1cblxuZnVuY3Rpb24gbWVyZ2VPYmplY3RzV2l0aG91dER1cGxpY2F0ZXMoc2VjdGlvbjogc3RyaW5nLCBkZXN0OiBhbnksIHNyYzogYW55KTogYW55IHtcbiAgaWYgKHR5cGVvZiBkZXN0ICE9PSAnb2JqZWN0Jykge1xuICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0aW5nICR7SlNPTi5zdHJpbmdpZnkoZGVzdCl9IHRvIGJlIGFuIG9iamVjdGApO1xuICB9XG4gIGlmICh0eXBlb2Ygc3JjICE9PSAnb2JqZWN0Jykge1xuICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0aW5nICR7SlNPTi5zdHJpbmdpZnkoc3JjKX0gdG8gYmUgYW4gb2JqZWN0YCk7XG4gIH1cblxuICAvLyBhZGQgYWxsIGVudGl0aWVzIGZyb20gc291cmNlIHNlY3Rpb24gdG8gZGVzdGluYXRpb24gc2VjdGlvblxuICBmb3IgKGNvbnN0IGlkIG9mIE9iamVjdC5rZXlzKHNyYykpIHtcbiAgICBpZiAoaWQgaW4gZGVzdCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBzZWN0aW9uICcke3NlY3Rpb259JyBhbHJlYWR5IGNvbnRhaW5zICcke2lkfSdgKTtcbiAgICB9XG4gICAgZGVzdFtpZF0gPSBzcmNbaWRdO1xuICB9XG5cbiAgcmV0dXJuIGRlc3Q7XG59XG5cbi8qKlxuICogQ2xvdWRGb3JtYXRpb24gdGVtcGxhdGUgb3B0aW9ucyBmb3IgYSBzdGFjay5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJVGVtcGxhdGVPcHRpb25zIHtcbiAgLyoqXG4gICAqIEdldHMgb3Igc2V0cyB0aGUgZGVzY3JpcHRpb24gb2YgdGhpcyBzdGFjay5cbiAgICogSWYgcHJvdmlkZWQsIGl0IHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlJ3MgXCJEZXNjcmlwdGlvblwiIGF0dHJpYnV0ZS5cbiAgICovXG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBHZXRzIG9yIHNldHMgdGhlIEFXU1RlbXBsYXRlRm9ybWF0VmVyc2lvbiBmaWVsZCBvZiB0aGUgQ2xvdWRGb3JtYXRpb24gdGVtcGxhdGUuXG4gICAqL1xuICB0ZW1wbGF0ZUZvcm1hdFZlcnNpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEdldHMgb3Igc2V0cyB0aGUgdG9wLWxldmVsIHRlbXBsYXRlIHRyYW5zZm9ybSBmb3IgdGhpcyBzdGFjayAoZS5nLiBcIkFXUzo6U2VydmVybGVzcy0yMDE2LTEwLTMxXCIpLlxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgYHRyYW5zZm9ybXNgIGluc3RlYWQuXG4gICAqL1xuICB0cmFuc2Zvcm0/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEdldHMgb3Igc2V0cyB0aGUgdG9wLWxldmVsIHRlbXBsYXRlIHRyYW5zZm9ybShzKSBmb3IgdGhpcyBzdGFjayAoZS5nLiBgW1wiQVdTOjpTZXJ2ZXJsZXNzLTIwMTYtMTAtMzFcIl1gKS5cbiAgICovXG4gIHRyYW5zZm9ybXM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogTWV0YWRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZS5cbiAgICovXG4gIG1ldGFkYXRhPzogeyBba2V5OiBzdHJpbmddOiBhbnkgfTtcbn1cblxuLyoqXG4gKiBDb2xsZWN0IGFsbCBDZm5FbGVtZW50cyBmcm9tIGEgU3RhY2suXG4gKlxuICogQHBhcmFtIG5vZGUgUm9vdCBub2RlIHRvIGNvbGxlY3QgYWxsIENmbkVsZW1lbnRzIGZyb21cbiAqIEBwYXJhbSBpbnRvIEFycmF5IHRvIGFwcGVuZCBDZm5FbGVtZW50cyB0b1xuICogQHJldHVybnMgVGhlIHNhbWUgYXJyYXkgYXMgaXMgYmVpbmcgY29sbGVjdGVkIGludG9cbiAqL1xuZnVuY3Rpb24gY2ZuRWxlbWVudHMobm9kZTogSUNvbnN0cnVjdCwgaW50bzogQ2ZuRWxlbWVudFtdID0gW10pOiBDZm5FbGVtZW50W10ge1xuICBpZiAoQ2ZuRWxlbWVudC5pc0NmbkVsZW1lbnQobm9kZSkpIHtcbiAgICBpbnRvLnB1c2gobm9kZSk7XG4gIH1cblxuICBmb3IgKGNvbnN0IGNoaWxkIG9mIE5vZGUub2Yobm9kZSkuY2hpbGRyZW4pIHtcbiAgICAvLyBEb24ndCByZWN1cnNlIGludG8gYSBzdWJzdGFja1xuICAgIGlmIChTdGFjay5pc1N0YWNrKGNoaWxkKSkgeyBjb250aW51ZTsgfVxuXG4gICAgY2ZuRWxlbWVudHMoY2hpbGQsIGludG8pO1xuICB9XG5cbiAgcmV0dXJuIGludG87XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBjb25zdHJ1Y3Qgcm9vdCBwYXRoIG9mIHRoZSBnaXZlbiBjb25zdHJ1Y3QgcmVsYXRpdmUgdG8gdGhlIGdpdmVuIGFuY2VzdG9yXG4gKlxuICogSWYgbm8gYW5jZXN0b3IgaXMgZ2l2ZW4gb3IgdGhlIGFuY2VzdG9yIGlzIG5vdCBmb3VuZCwgcmV0dXJuIHRoZSBlbnRpcmUgcm9vdCBwYXRoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcm9vdFBhdGhUbyhjb25zdHJ1Y3Q6IElDb25zdHJ1Y3QsIGFuY2VzdG9yPzogSUNvbnN0cnVjdCk6IElDb25zdHJ1Y3RbXSB7XG4gIGNvbnN0IHNjb3BlcyA9IE5vZGUub2YoY29uc3RydWN0KS5zY29wZXM7XG4gIGZvciAobGV0IGkgPSBzY29wZXMubGVuZ3RoIC0gMjsgaSA+PSAwOyBpLS0pIHtcbiAgICBpZiAoc2NvcGVzW2ldID09PSBhbmNlc3Rvcikge1xuICAgICAgcmV0dXJuIHNjb3Blcy5zbGljZShpICsgMSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBzY29wZXM7XG59XG5cbi8qKlxuICogbWFrZVVuaXF1ZUlkLCBzcGVjaWFsaXplZCBmb3IgU3RhY2sgbmFtZXNcbiAqXG4gKiBTdGFjayBuYW1lcyBtYXkgY29udGFpbiAnLScsIHNvIHdlIGFsbG93IHRoYXQgY2hhcmFjdGVyIGlmIHRoZSBzdGFjayBuYW1lXG4gKiBoYXMgb25seSBvbmUgY29tcG9uZW50LiBPdGhlcndpc2Ugd2UgZmFsbCBiYWNrIHRvIHRoZSByZWd1bGFyIFwibWFrZVVuaXF1ZUlkXCJcbiAqIGJlaGF2aW9yLlxuICovXG5mdW5jdGlvbiBtYWtlU3RhY2tOYW1lKGNvbXBvbmVudHM6IHN0cmluZ1tdKSB7XG4gIGlmIChjb21wb25lbnRzLmxlbmd0aCA9PT0gMSkgeyByZXR1cm4gY29tcG9uZW50c1swXTsgfVxuICByZXR1cm4gbWFrZVVuaXF1ZUlkKGNvbXBvbmVudHMpO1xufVxuXG5mdW5jdGlvbiBnZXRDcmVhdGVFeHBvcnRzU2NvcGUoc3RhY2s6IFN0YWNrKSB7XG4gIGNvbnN0IGV4cG9ydHNOYW1lID0gJ0V4cG9ydHMnO1xuICBsZXQgc3RhY2tFeHBvcnRzID0gc3RhY2subm9kZS50cnlGaW5kQ2hpbGQoZXhwb3J0c05hbWUpIGFzIENvcmVDb25zdHJ1Y3Q7XG4gIGlmIChzdGFja0V4cG9ydHMgPT09IHVuZGVmaW5lZCkge1xuICAgIHN0YWNrRXhwb3J0cyA9IG5ldyBDb3JlQ29uc3RydWN0KHN0YWNrLCBleHBvcnRzTmFtZSk7XG4gIH1cblxuICByZXR1cm4gc3RhY2tFeHBvcnRzO1xufVxuXG5mdW5jdGlvbiBnZW5lcmF0ZUV4cG9ydE5hbWUoc3RhY2tFeHBvcnRzOiBDb3JlQ29uc3RydWN0LCBpZDogc3RyaW5nKSB7XG4gIGNvbnN0IHN0YWNrUmVsYXRpdmVFeHBvcnRzID0gRmVhdHVyZUZsYWdzLm9mKHN0YWNrRXhwb3J0cykuaXNFbmFibGVkKGN4YXBpLlNUQUNLX1JFTEFUSVZFX0VYUE9SVFNfQ09OVEVYVCk7XG4gIGNvbnN0IHN0YWNrID0gU3RhY2sub2Yoc3RhY2tFeHBvcnRzKTtcblxuICBjb25zdCBjb21wb25lbnRzID0gW1xuICAgIC4uLnN0YWNrRXhwb3J0cy5ub2RlLnNjb3Blc1xuICAgICAgLnNsaWNlKHN0YWNrUmVsYXRpdmVFeHBvcnRzID8gc3RhY2subm9kZS5zY29wZXMubGVuZ3RoIDogMilcbiAgICAgIC5tYXAoYyA9PiBjLm5vZGUuaWQpLFxuICAgIGlkLFxuICBdO1xuICBjb25zdCBwcmVmaXggPSBzdGFjay5zdGFja05hbWUgPyBzdGFjay5zdGFja05hbWUgKyAnOicgOiAnJztcbiAgY29uc3QgbG9jYWxQYXJ0ID0gbWFrZVVuaXF1ZUlkKGNvbXBvbmVudHMpO1xuICBjb25zdCBtYXhMZW5ndGggPSAyNTU7XG4gIHJldHVybiBwcmVmaXggKyBsb2NhbFBhcnQuc2xpY2UoTWF0aC5tYXgoMCwgbG9jYWxQYXJ0Lmxlbmd0aCAtIG1heExlbmd0aCArIHByZWZpeC5sZW5ndGgpKTtcbn1cblxuaW50ZXJmYWNlIFN0YWNrRGVwZW5kZW5jeSB7XG4gIHN0YWNrOiBTdGFjaztcbiAgcmVhc29uczogc3RyaW5nW107XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgdGhlIGBzdGFjay5leHBvcnRWYWx1ZSgpYCBtZXRob2RcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFeHBvcnRWYWx1ZU9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGV4cG9ydCB0byBjcmVhdGVcbiAgICpcbiAgICogQGRlZmF1bHQgLSBBIG5hbWUgaXMgYXV0b21hdGljYWxseSBjaG9zZW5cbiAgICovXG4gIHJlYWRvbmx5IG5hbWU/OiBzdHJpbmc7XG59XG5cbmZ1bmN0aW9uIGNvdW50KHhzOiBzdHJpbmdbXSk6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4ge1xuICBjb25zdCByZXQ6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcbiAgZm9yIChjb25zdCB4IG9mIHhzKSB7XG4gICAgaWYgKHggaW4gcmV0KSB7XG4gICAgICByZXRbeF0gKz0gMTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0W3hdID0gMTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cblxuLy8gVGhlc2UgaW1wb3J0cyBoYXZlIHRvIGJlIGF0IHRoZSBlbmQgdG8gcHJldmVudCBjaXJjdWxhciBpbXBvcnRzXG5pbXBvcnQgeyBDZm5PdXRwdXQgfSBmcm9tICcuL2Nmbi1vdXRwdXQnO1xuaW1wb3J0IHsgYWRkRGVwZW5kZW5jeSB9IGZyb20gJy4vZGVwcyc7XG5pbXBvcnQgeyBGaWxlU3lzdGVtIH0gZnJvbSAnLi9mcyc7XG5pbXBvcnQgeyBOYW1lcyB9IGZyb20gJy4vbmFtZXMnO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSAnLi9yZWZlcmVuY2UnO1xuaW1wb3J0IHsgSVJlc29sdmFibGUgfSBmcm9tICcuL3Jlc29sdmFibGUnO1xuaW1wb3J0IHsgRGVmYXVsdFN0YWNrU3ludGhlc2l6ZXIsIElTdGFja1N5bnRoZXNpemVyLCBMZWdhY3lTdGFja1N5bnRoZXNpemVyIH0gZnJvbSAnLi9zdGFjay1zeW50aGVzaXplcnMnO1xuaW1wb3J0IHsgU3RhZ2UgfSBmcm9tICcuL3N0YWdlJztcbmltcG9ydCB7IElUYWdnYWJsZSwgVGFnTWFuYWdlciB9IGZyb20gJy4vdGFnLW1hbmFnZXInO1xuaW1wb3J0IHsgVG9rZW4sIFRva2VuaXphdGlvbiB9IGZyb20gJy4vdG9rZW4nO1xuaW1wb3J0IHsgcmVmZXJlbmNlTmVzdGVkU3RhY2tWYWx1ZUluUGFyZW50IH0gZnJvbSAnLi9wcml2YXRlL3JlZnMnO1xuaW1wb3J0IHsgRmFjdCwgUmVnaW9uSW5mbyB9IGZyb20gJ0Bhd3MtY2RrL3JlZ2lvbi1pbmZvJztcbmltcG9ydCB7IGRlcGxveVRpbWVMb29rdXAgfSBmcm9tICcuL3ByaXZhdGUvcmVnaW9uLWxvb2t1cCc7XG5cbiJdfQ==
\No newline at end of file