UNPKG

96 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.Fn = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const cloudformation_lang_1 = require("./private/cloudformation-lang");
8const intrinsic_1 = require("./private/intrinsic");
9const reference_1 = require("./reference");
10const stack_trace_1 = require("./stack-trace");
11const token_1 = require("./token");
12/* eslint-disable max-len */
13/**
14 * CloudFormation intrinsic functions.
15 * http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
16 */
17class Fn {
18 constructor() { }
19 /**
20 * The ``Ref`` intrinsic function returns the value of the specified parameter or resource.
21 * Note that it doesn't validate the logicalName, it mainly serves paremeter/resource reference defined in a ``CfnInclude`` template.
22 * @param logicalName The logical name of a parameter/resource for which you want to retrieve its value.
23 */
24 static ref(logicalName) {
25 return new FnRef(logicalName).toString();
26 }
27 /**
28 * The ``Fn::GetAtt`` intrinsic function returns the value of an attribute
29 * from a resource in the template.
30 * @param logicalNameOfResource The logical name (also called logical ID) of
31 * the resource that contains the attribute that you want.
32 * @param attributeName The name of the resource-specific attribute whose
33 * value you want. See the resource's reference page for details about the
34 * attributes available for that resource type.
35 * @returns an IResolvable object
36 */
37 static getAtt(logicalNameOfResource, attributeName) {
38 return new FnGetAtt(logicalNameOfResource, attributeName);
39 }
40 /**
41 * The intrinsic function ``Fn::Join`` appends a set of values into a single
42 * value, separated by the specified delimiter. If a delimiter is the empty
43 * string, the set of values are concatenated with no delimiter.
44 * @param delimiter The value you want to occur between fragments. The
45 * delimiter will occur between fragments only. It will not terminate the
46 * final value.
47 * @param listOfValues The list of values you want combined.
48 * @returns a token represented as a string
49 */
50 static join(delimiter, listOfValues) {
51 if (listOfValues.length === 0) {
52 throw new Error('FnJoin requires at least one value to be provided');
53 }
54 return new FnJoin(delimiter, listOfValues).toString();
55 }
56 /**
57 * Split a string token into a token list of string values.
58 *
59 * Specify the location of splits with a delimiter such as ',' (a comma).
60 * Renders to the `Fn::Split` intrinsic function.
61 *
62 * Lists with unknown lengths (default)
63 * -------------------------------------
64 *
65 * Since this function is used to work with deploy-time values, if `assumedLength`
66 * is not given the CDK cannot know the length of the resulting list at synthesis time.
67 * This brings the following restrictions:
68 *
69 * - You must use `Fn.select(i, list)` to pick elements out of the list (you must not use
70 * `list[i]`).
71 * - You cannot add elements to the list, remove elements from the list,
72 * combine two such lists together, or take a slice of the list.
73 * - You cannot pass the list to constructs that do any of the above.
74 *
75 * The only valid operation with such a tokenized list is to pass it unmodified to a
76 * CloudFormation Resource construct.
77 *
78 * Lists with assumed lengths
79 * --------------------------
80 *
81 * Pass `assumedLength` if you know the length of the list that will be
82 * produced by splitting. The actual list length at deploy time may be
83 * *longer* than the number you pass, but not *shorter*.
84 *
85 * The returned list will look like:
86 *
87 * ```
88 * [Fn.select(0, split), Fn.select(1, split), Fn.select(2, split), ...]
89 * ```
90 *
91 * The restrictions from the section "Lists with unknown lengths" will now be lifted,
92 * at the expense of having to know and fix the length of the list.
93 *
94 * @param delimiter A string value that determines where the source string is divided.
95 * @param source The string value that you want to split.
96 * @param assumedLength The length of the list that will be produced by splitting
97 * @returns a token represented as a string array
98 */
99 static split(delimiter, source, assumedLength) {
100 // short-circut if source is not a token
101 if (!token_1.Token.isUnresolved(source)) {
102 return source.split(delimiter);
103 }
104 if (token_1.Token.isUnresolved(delimiter)) {
105 // Limitation of CloudFormation
106 throw new Error('Fn.split: \'delimiter\' may not be a token value');
107 }
108 const split = token_1.Token.asList(new FnSplit(delimiter, source));
109 if (assumedLength === undefined) {
110 return split;
111 }
112 if (token_1.Token.isUnresolved(assumedLength)) {
113 throw new Error('Fn.split: \'assumedLength\' may not be a token value');
114 }
115 return range(assumedLength).map(i => Fn.select(i, split));
116 }
117 /**
118 * The intrinsic function ``Fn::Select`` returns a single object from a list of objects by index.
119 * @param index The index of the object to retrieve. This must be a value from zero to N-1, where N represents the number of elements in the array.
120 * @param array The list of objects to select from. This list must not be null, nor can it have null entries.
121 * @returns a token represented as a string
122 */
123 static select(index, array) {
124 if (!token_1.Token.isUnresolved(index) && !token_1.Token.isUnresolved(array) && !array.some(token_1.Token.isUnresolved)) {
125 return array[index];
126 }
127 return new FnSelect(index, array).toString();
128 }
129 /**
130 * The intrinsic function ``Fn::Sub`` substitutes variables in an input string
131 * with values that you specify. In your templates, you can use this function
132 * to construct commands or outputs that include values that aren't available
133 * until you create or update a stack.
134 * @param body A string with variables that AWS CloudFormation substitutes
135 * with their associated values at runtime. Write variables as ${MyVarName}.
136 * Variables can be template parameter names, resource logical IDs, resource
137 * attributes, or a variable in a key-value map. If you specify only template
138 * parameter names, resource logical IDs, and resource attributes, don't
139 * specify a key-value map.
140 * @param variables The name of a variable that you included in the String
141 * parameter. The value that AWS CloudFormation substitutes for the associated
142 * variable name at runtime.
143 * @returns a token represented as a string
144 */
145 static sub(body, variables) {
146 return new FnSub(body, variables).toString();
147 }
148 /**
149 * The intrinsic function ``Fn::Base64`` returns the Base64 representation of
150 * the input string. This function is typically used to pass encoded data to
151 * Amazon EC2 instances by way of the UserData property.
152 * @param data The string value you want to convert to Base64.
153 * @returns a token represented as a string
154 */
155 static base64(data) {
156 return new FnBase64(data).toString();
157 }
158 /**
159 * The intrinsic function ``Fn::Cidr`` returns the specified Cidr address block.
160 * @param ipBlock The user-specified default Cidr address block.
161 * @param count The number of subnets' Cidr block wanted. Count can be 1 to 256.
162 * @param sizeMask The digit covered in the subnet.
163 * @returns a token represented as a string
164 */
165 static cidr(ipBlock, count, sizeMask) {
166 return token_1.Token.asList(new FnCidr(ipBlock, count, sizeMask));
167 }
168 /**
169 * Given an url, parse the domain name
170 * @param url the url to parse
171 */
172 static parseDomainName(url) {
173 const noHttps = Fn.select(1, Fn.split('//', url));
174 return Fn.select(0, Fn.split('/', noHttps));
175 }
176 /**
177 * The intrinsic function ``Fn::GetAZs`` returns an array that lists
178 * Availability Zones for a specified region. Because customers have access to
179 * different Availability Zones, the intrinsic function ``Fn::GetAZs`` enables
180 * template authors to write templates that adapt to the calling user's
181 * access. That way you don't have to hard-code a full list of Availability
182 * Zones for a specified region.
183 * @param region The name of the region for which you want to get the
184 * Availability Zones. You can use the AWS::Region pseudo parameter to specify
185 * the region in which the stack is created. Specifying an empty string is
186 * equivalent to specifying AWS::Region.
187 * @returns a token represented as a string array
188 */
189 static getAzs(region) {
190 return token_1.Token.asList(new FnGetAZs(region));
191 }
192 /**
193 * The intrinsic function ``Fn::ImportValue`` returns the value of an output
194 * exported by another stack. You typically use this function to create
195 * cross-stack references. In the following example template snippets, Stack A
196 * exports VPC security group values and Stack B imports them.
197 * @param sharedValueToImport The stack output value that you want to import.
198 * @returns a token represented as a string
199 */
200 static importValue(sharedValueToImport) {
201 return new FnImportValue(sharedValueToImport).toString();
202 }
203 /**
204 * Like `Fn.importValue`, but import a list with a known length
205 *
206 * If you explicitly want a list with an unknown length, call `Fn.split(',',
207 * Fn.importValue(exportName))`. See the documentation of `Fn.split` to read
208 * more about the limitations of using lists of unknown length.
209 *
210 * `Fn.importListValue(exportName, assumedLength)` is the same as
211 * `Fn.split(',', Fn.importValue(exportName), assumedLength)`,
212 * but easier to read and impossible to forget to pass `assumedLength`.
213 */
214 static importListValue(sharedValueToImport, assumedLength, delimiter = ',') {
215 return Fn.split(delimiter, Fn.importValue(sharedValueToImport), assumedLength);
216 }
217 /**
218 * The intrinsic function ``Fn::FindInMap`` returns the value corresponding to
219 * keys in a two-level map that is declared in the Mappings section.
220 * @returns a token represented as a string
221 */
222 static findInMap(mapName, topLevelKey, secondLevelKey) {
223 return Fn._findInMap(mapName, topLevelKey, secondLevelKey).toString();
224 }
225 /**
226 * An additional function used in CfnParser,
227 * as Fn::FindInMap does not always return a string.
228 *
229 * @internal
230 */
231 static _findInMap(mapName, topLevelKey, secondLevelKey) {
232 return new FnFindInMap(mapName, topLevelKey, secondLevelKey);
233 }
234 /**
235 * Creates a token representing the ``Fn::Transform`` expression
236 * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-transform.html
237 * @param macroName The name of the macro to perform the processing
238 * @param parameters The parameters to be passed to the macro
239 * @returns a token representing the transform expression
240 */
241 static transform(macroName, parameters) {
242 return new FnTransform(macroName, parameters);
243 }
244 /**
245 * Returns true if all the specified conditions evaluate to true, or returns
246 * false if any one of the conditions evaluates to false. ``Fn::And`` acts as
247 * an AND operator. The minimum number of conditions that you can include is
248 * 1.
249 * @param conditions conditions to AND
250 * @returns an FnCondition token
251 */
252 static conditionAnd(...conditions) {
253 try {
254 jsiiDeprecationWarnings._aws_cdk_core_ICfnConditionExpression(conditions);
255 }
256 catch (error) {
257 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
258 Error.captureStackTrace(error, this.conditionAnd);
259 }
260 throw error;
261 }
262 if (conditions.length === 0) {
263 throw new Error('Fn.conditionAnd() needs at least one argument');
264 }
265 if (conditions.length === 1) {
266 return conditions[0];
267 }
268 return Fn.conditionAnd(..._inGroupsOf(conditions, 10).map(group => new FnAnd(...group)));
269 }
270 /**
271 * Compares if two values are equal. Returns true if the two values are equal
272 * or false if they aren't.
273 * @param lhs A value of any type that you want to compare.
274 * @param rhs A value of any type that you want to compare.
275 * @returns an FnCondition token
276 */
277 static conditionEquals(lhs, rhs) {
278 return new FnEquals(lhs, rhs);
279 }
280 /**
281 * Returns one value if the specified condition evaluates to true and another
282 * value if the specified condition evaluates to false. Currently, AWS
283 * CloudFormation supports the ``Fn::If`` intrinsic function in the metadata
284 * attribute, update policy attribute, and property values in the Resources
285 * section and Outputs sections of a template. You can use the AWS::NoValue
286 * pseudo parameter as a return value to remove the corresponding property.
287 * @param conditionId A reference to a condition in the Conditions section. Use
288 * the condition's name to reference it.
289 * @param valueIfTrue A value to be returned if the specified condition
290 * evaluates to true.
291 * @param valueIfFalse A value to be returned if the specified condition
292 * evaluates to false.
293 * @returns an FnCondition token
294 */
295 static conditionIf(conditionId, valueIfTrue, valueIfFalse) {
296 return new FnIf(conditionId, valueIfTrue, valueIfFalse);
297 }
298 /**
299 * Returns true for a condition that evaluates to false or returns false for a
300 * condition that evaluates to true. ``Fn::Not`` acts as a NOT operator.
301 * @param condition A condition such as ``Fn::Equals`` that evaluates to true
302 * or false.
303 * @returns an FnCondition token
304 */
305 static conditionNot(condition) {
306 try {
307 jsiiDeprecationWarnings._aws_cdk_core_ICfnConditionExpression(condition);
308 }
309 catch (error) {
310 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
311 Error.captureStackTrace(error, this.conditionNot);
312 }
313 throw error;
314 }
315 return new FnNot(condition);
316 }
317 /**
318 * Returns true if any one of the specified conditions evaluate to true, or
319 * returns false if all of the conditions evaluates to false. ``Fn::Or`` acts
320 * as an OR operator. The minimum number of conditions that you can include is
321 * 1.
322 * @param conditions conditions that evaluates to true or false.
323 * @returns an FnCondition token
324 */
325 static conditionOr(...conditions) {
326 try {
327 jsiiDeprecationWarnings._aws_cdk_core_ICfnConditionExpression(conditions);
328 }
329 catch (error) {
330 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
331 Error.captureStackTrace(error, this.conditionOr);
332 }
333 throw error;
334 }
335 if (conditions.length === 0) {
336 throw new Error('Fn.conditionOr() needs at least one argument');
337 }
338 if (conditions.length === 1) {
339 return conditions[0];
340 }
341 return Fn.conditionOr(..._inGroupsOf(conditions, 10).map(group => new FnOr(...group)));
342 }
343 /**
344 * Returns true if a specified string matches at least one value in a list of
345 * strings.
346 * @param listOfStrings A list of strings, such as "A", "B", "C".
347 * @param value A string, such as "A", that you want to compare against a list of strings.
348 * @returns an FnCondition token
349 */
350 static conditionContains(listOfStrings, value) {
351 return new FnContains(listOfStrings, value);
352 }
353 /**
354 * Returns true if a specified string matches all values in a list.
355 * @param listOfStrings A list of strings, such as "A", "B", "C".
356 * @param value A string, such as "A", that you want to compare against a list
357 * of strings.
358 * @returns an FnCondition token
359 */
360 static conditionEachMemberEquals(listOfStrings, value) {
361 return new FnEachMemberEquals(listOfStrings, value);
362 }
363 /**
364 * Returns true if each member in a list of strings matches at least one value
365 * in a second list of strings.
366 * @param stringsToCheck A list of strings, such as "A", "B", "C". AWS
367 * CloudFormation checks whether each member in the strings_to_check parameter
368 * is in the strings_to_match parameter.
369 * @param stringsToMatch A list of strings, such as "A", "B", "C". Each member
370 * in the strings_to_match parameter is compared against the members of the
371 * strings_to_check parameter.
372 * @returns an FnCondition token
373 */
374 static conditionEachMemberIn(stringsToCheck, stringsToMatch) {
375 return new FnEachMemberIn(stringsToCheck, stringsToMatch);
376 }
377 /**
378 * Returns all values for a specified parameter type.
379 * @param parameterType An AWS-specific parameter type, such as
380 * AWS::EC2::SecurityGroup::Id or AWS::EC2::VPC::Id. For more information, see
381 * Parameters in the AWS CloudFormation User Guide.
382 * @returns a token represented as a string array
383 */
384 static refAll(parameterType) {
385 return token_1.Token.asList(new FnRefAll(parameterType));
386 }
387 /**
388 * Returns an attribute value or list of values for a specific parameter and
389 * attribute.
390 * @param parameterOrLogicalId The name of a parameter for which you want to
391 * retrieve attribute values. The parameter must be declared in the Parameters
392 * section of the template.
393 * @param attribute The name of an attribute from which you want to retrieve a
394 * value.
395 * @returns a token represented as a string
396 */
397 static valueOf(parameterOrLogicalId, attribute) {
398 return new FnValueOf(parameterOrLogicalId, attribute).toString();
399 }
400 /**
401 * Returns a list of all attribute values for a given parameter type and
402 * attribute.
403 * @param parameterType An AWS-specific parameter type, such as
404 * AWS::EC2::SecurityGroup::Id or AWS::EC2::VPC::Id. For more information, see
405 * Parameters in the AWS CloudFormation User Guide.
406 * @param attribute The name of an attribute from which you want to retrieve a
407 * value. For more information about attributes, see Supported Attributes.
408 * @returns a token represented as a string array
409 */
410 static valueOfAll(parameterType, attribute) {
411 return token_1.Token.asList(new FnValueOfAll(parameterType, attribute));
412 }
413}
414exports.Fn = Fn;
415_a = JSII_RTTI_SYMBOL_1;
416Fn[_a] = { fqn: "@aws-cdk/core.Fn", version: "1.204.0" };
417/**
418 * Base class for tokens that represent CloudFormation intrinsic functions.
419 */
420class FnBase extends intrinsic_1.Intrinsic {
421 constructor(name, value) {
422 super({ [name]: value });
423 }
424}
425/**
426 * The intrinsic function ``Ref`` returns the value of the specified parameter or resource.
427 * When you specify a parameter's logical name, it returns the value of the parameter.
428 * When you specify a resource's logical name, it returns a value that you can typically use to refer to that resource, such as a physical ID.
429 */
430class FnRef extends FnBase {
431 /**
432 * Creates an ``Ref`` function.
433 * @param logicalName The logical name of a parameter/resource for which you want to retrieve its value.
434 */
435 constructor(logicalName) {
436 super('Ref', logicalName);
437 }
438}
439/**
440 * The intrinsic function ``Fn::FindInMap`` returns the value corresponding to keys in a two-level
441 * map that is declared in the Mappings section.
442 */
443class FnFindInMap extends FnBase {
444 /**
445 * Creates an ``Fn::FindInMap`` function.
446 * @param mapName The logical name of a mapping declared in the Mappings section that contains the keys and values.
447 * @param topLevelKey The top-level key name. Its value is a list of key-value pairs.
448 * @param secondLevelKey The second-level key name, which is set to one of the keys from the list assigned to TopLevelKey.
449 */
450 constructor(mapName, topLevelKey, secondLevelKey) {
451 super('Fn::FindInMap', [mapName, topLevelKey, secondLevelKey]);
452 }
453}
454/**
455 * The intrinsic function ``Fn::Transform`` specifies a macro to perform custom processing on part of a stack template.
456 */
457class FnTransform extends FnBase {
458 /**
459 * creates an ``Fn::Transform`` function.
460 * @param macroName The name of the macro to be invoked
461 * @param parameters the parameters to pass to it
462 */
463 constructor(macroName, parameters) {
464 super('Fn::Transform', { Name: macroName, Parameters: parameters });
465 }
466}
467/**
468 * The ``Fn::GetAtt`` intrinsic function returns the value of an attribute from a resource in the template.
469 */
470class FnGetAtt extends FnBase {
471 /**
472 * Creates a ``Fn::GetAtt`` function.
473 * @param logicalNameOfResource The logical name (also called logical ID) of the resource that contains the attribute that you want.
474 * @param attributeName The name of the resource-specific attribute whose value you want. See the resource's reference page for details about the attributes available for that resource type.
475 */
476 constructor(logicalNameOfResource, attributeName) {
477 super('Fn::GetAtt', [logicalNameOfResource, attributeName]);
478 }
479}
480/**
481 * The intrinsic function ``Fn::GetAZs`` returns an array that lists Availability Zones for a
482 * specified region. Because customers have access to different Availability Zones, the intrinsic
483 * function ``Fn::GetAZs`` enables template authors to write templates that adapt to the calling
484 * user's access. That way you don't have to hard-code a full list of Availability Zones for a
485 * specified region.
486 */
487class FnGetAZs extends FnBase {
488 /**
489 * Creates an ``Fn::GetAZs`` function.
490 * @param region The name of the region for which you want to get the Availability Zones.
491 * You can use the AWS::Region pseudo parameter to specify the region in
492 * which the stack is created. Specifying an empty string is equivalent to
493 * specifying AWS::Region.
494 */
495 constructor(region) {
496 super('Fn::GetAZs', region || '');
497 }
498}
499/**
500 * The intrinsic function ``Fn::ImportValue`` returns the value of an output exported by another stack.
501 * You typically use this function to create cross-stack references. In the following example
502 * template snippets, Stack A exports VPC security group values and Stack B imports them.
503 */
504class FnImportValue extends FnBase {
505 /**
506 * Creates an ``Fn::ImportValue`` function.
507 * @param sharedValueToImport The stack output value that you want to import.
508 */
509 constructor(sharedValueToImport) {
510 super('Fn::ImportValue', sharedValueToImport);
511 }
512}
513/**
514 * The intrinsic function ``Fn::Select`` returns a single object from a list of objects by index.
515 */
516class FnSelect extends FnBase {
517 /**
518 * Creates an ``Fn::Select`` function.
519 * @param index The index of the object to retrieve. This must be a value from zero to N-1, where N represents the number of elements in the array.
520 * @param array The list of objects to select from. This list must not be null, nor can it have null entries.
521 */
522 constructor(index, array) {
523 super('Fn::Select', [index, array]);
524 }
525}
526/**
527 * To split a string into a list of string values so that you can select an element from the
528 * resulting string list, use the ``Fn::Split`` intrinsic function. Specify the location of splits
529 * with a delimiter, such as , (a comma). After you split a string, use the ``Fn::Select`` function
530 * to pick a specific element.
531 */
532class FnSplit extends FnBase {
533 /**
534 * Create an ``Fn::Split`` function.
535 * @param delimiter A string value that determines where the source string is divided.
536 * @param source The string value that you want to split.
537 */
538 constructor(delimiter, source) {
539 super('Fn::Split', [delimiter, source]);
540 }
541}
542/**
543 * The intrinsic function ``Fn::Sub`` substitutes variables in an input string with values that
544 * you specify. In your templates, you can use this function to construct commands or outputs
545 * that include values that aren't available until you create or update a stack.
546 */
547class FnSub extends FnBase {
548 /**
549 * Creates an ``Fn::Sub`` function.
550 * @param body A string with variables that AWS CloudFormation substitutes with their
551 * associated values at runtime. Write variables as ${MyVarName}. Variables
552 * can be template parameter names, resource logical IDs, resource attributes,
553 * or a variable in a key-value map. If you specify only template parameter names,
554 * resource logical IDs, and resource attributes, don't specify a key-value map.
555 * @param variables The name of a variable that you included in the String parameter.
556 * The value that AWS CloudFormation substitutes for the associated variable name at runtime.
557 */
558 constructor(body, variables) {
559 super('Fn::Sub', variables ? [body, variables] : body);
560 }
561}
562/**
563 * The intrinsic function ``Fn::Base64`` returns the Base64 representation of the input string.
564 * This function is typically used to pass encoded data to Amazon EC2 instances by way of
565 * the UserData property.
566 */
567class FnBase64 extends FnBase {
568 /**
569 * Creates an ``Fn::Base64`` function.
570 * @param data The string value you want to convert to Base64.
571 */
572 constructor(data) {
573 super('Fn::Base64', data);
574 }
575}
576/**
577 * The intrinsic function ``Fn::Cidr`` returns the specified Cidr address block.
578 */
579class FnCidr extends FnBase {
580 /**
581 * Creates an ``Fn::Cidr`` function.
582 * @param ipBlock The user-specified default Cidr address block.
583 * @param count The number of subnets' Cidr block wanted. Count can be 1 to 256.
584 * @param sizeMask The digit covered in the subnet.
585 */
586 constructor(ipBlock, count, sizeMask) {
587 if (count < 1 || count > 256) {
588 throw new Error(`Fn::Cidr's count attribute must be betwen 1 and 256, ${count} was provided.`);
589 }
590 super('Fn::Cidr', [ipBlock, count, sizeMask]);
591 }
592}
593class FnConditionBase extends intrinsic_1.Intrinsic {
594 constructor(type, value) {
595 super({ [type]: value });
596 this.disambiguator = true;
597 }
598}
599/**
600 * Returns true if all the specified conditions evaluate to true, or returns false if any one
601 * of the conditions evaluates to false. ``Fn::And`` acts as an AND operator. The minimum number of
602 * conditions that you can include is 2, and the maximum is 10.
603 */
604class FnAnd extends FnConditionBase {
605 constructor(...condition) {
606 super('Fn::And', condition);
607 }
608}
609/**
610 * Compares if two values are equal. Returns true if the two values are equal or false
611 * if they aren't.
612 */
613class FnEquals extends FnConditionBase {
614 /**
615 * Creates an ``Fn::Equals`` condition function.
616 * @param lhs A value of any type that you want to compare.
617 * @param rhs A value of any type that you want to compare.
618 */
619 constructor(lhs, rhs) {
620 super('Fn::Equals', [lhs, rhs]);
621 }
622}
623/**
624 * Returns one value if the specified condition evaluates to true and another value if the
625 * specified condition evaluates to false. Currently, AWS CloudFormation supports the ``Fn::If``
626 * intrinsic function in the metadata attribute, update policy attribute, and property values
627 * in the Resources section and Outputs sections of a template. You can use the AWS::NoValue
628 * pseudo parameter as a return value to remove the corresponding property.
629 */
630class FnIf extends FnConditionBase {
631 /**
632 * Creates an ``Fn::If`` condition function.
633 * @param condition A reference to a condition in the Conditions section. Use the condition's name to reference it.
634 * @param valueIfTrue A value to be returned if the specified condition evaluates to true.
635 * @param valueIfFalse A value to be returned if the specified condition evaluates to false.
636 */
637 constructor(condition, valueIfTrue, valueIfFalse) {
638 super('Fn::If', [condition, valueIfTrue, valueIfFalse]);
639 }
640}
641/**
642 * Returns true for a condition that evaluates to false or returns false for a condition that evaluates to true.
643 * ``Fn::Not`` acts as a NOT operator.
644 */
645class FnNot extends FnConditionBase {
646 /**
647 * Creates an ``Fn::Not`` condition function.
648 * @param condition A condition such as ``Fn::Equals`` that evaluates to true or false.
649 */
650 constructor(condition) {
651 super('Fn::Not', [condition]);
652 }
653}
654/**
655 * Returns true if any one of the specified conditions evaluate to true, or returns false if
656 * all of the conditions evaluates to false. ``Fn::Or`` acts as an OR operator. The minimum number
657 * of conditions that you can include is 2, and the maximum is 10.
658 */
659class FnOr extends FnConditionBase {
660 /**
661 * Creates an ``Fn::Or`` condition function.
662 * @param condition A condition that evaluates to true or false.
663 */
664 constructor(...condition) {
665 super('Fn::Or', condition);
666 }
667}
668/**
669 * Returns true if a specified string matches at least one value in a list of strings.
670 */
671class FnContains extends FnConditionBase {
672 /**
673 * Creates an ``Fn::Contains`` function.
674 * @param listOfStrings A list of strings, such as "A", "B", "C".
675 * @param value A string, such as "A", that you want to compare against a list of strings.
676 */
677 constructor(listOfStrings, value) {
678 super('Fn::Contains', [listOfStrings, value]);
679 }
680}
681/**
682 * Returns true if a specified string matches all values in a list.
683 */
684class FnEachMemberEquals extends FnConditionBase {
685 /**
686 * Creates an ``Fn::EachMemberEquals`` function.
687 * @param listOfStrings A list of strings, such as "A", "B", "C".
688 * @param value A string, such as "A", that you want to compare against a list of strings.
689 */
690 constructor(listOfStrings, value) {
691 super('Fn::EachMemberEquals', [listOfStrings, value]);
692 }
693}
694/**
695 * Returns true if each member in a list of strings matches at least one value in a second
696 * list of strings.
697 */
698class FnEachMemberIn extends FnConditionBase {
699 /**
700 * Creates an ``Fn::EachMemberIn`` function.
701 * @param stringsToCheck A list of strings, such as "A", "B", "C". AWS CloudFormation checks whether each member in the strings_to_check parameter is in the strings_to_match parameter.
702 * @param stringsToMatch A list of strings, such as "A", "B", "C". Each member in the strings_to_match parameter is compared against the members of the strings_to_check parameter.
703 */
704 constructor(stringsToCheck, stringsToMatch) {
705 super('Fn::EachMemberIn', [stringsToCheck, stringsToMatch]);
706 }
707}
708/**
709 * Returns all values for a specified parameter type.
710 */
711class FnRefAll extends FnBase {
712 /**
713 * Creates an ``Fn::RefAll`` function.
714 * @param parameterType An AWS-specific parameter type, such as AWS::EC2::SecurityGroup::Id or
715 * AWS::EC2::VPC::Id. For more information, see Parameters in the AWS
716 * CloudFormation User Guide.
717 */
718 constructor(parameterType) {
719 super('Fn::RefAll', parameterType);
720 }
721}
722/**
723 * Returns an attribute value or list of values for a specific parameter and attribute.
724 */
725class FnValueOf extends FnBase {
726 /**
727 * Creates an ``Fn::ValueOf`` function.
728 * @param parameterOrLogicalId The name of a parameter for which you want to retrieve attribute values. The parameter must be declared in the Parameters section of the template.
729 * @param attribute The name of an attribute from which you want to retrieve a value.
730 */
731 constructor(parameterOrLogicalId, attribute) {
732 super('Fn::ValueOf', [parameterOrLogicalId, attribute]);
733 }
734}
735/**
736 * Returns a list of all attribute values for a given parameter type and attribute.
737 */
738class FnValueOfAll extends FnBase {
739 /**
740 * Creates an ``Fn::ValueOfAll`` function.
741 * @param parameterType An AWS-specific parameter type, such as AWS::EC2::SecurityGroup::Id or AWS::EC2::VPC::Id. For more information, see Parameters in the AWS CloudFormation User Guide.
742 * @param attribute The name of an attribute from which you want to retrieve a value. For more information about attributes, see Supported Attributes.
743 */
744 constructor(parameterType, attribute) {
745 super('Fn::ValueOfAll', [parameterType, attribute]);
746 }
747}
748/**
749 * The intrinsic function ``Fn::Join`` appends a set of values into a single value, separated by
750 * the specified delimiter. If a delimiter is the empty string, the set of values are concatenated
751 * with no delimiter.
752 */
753class FnJoin {
754 /**
755 * Creates an ``Fn::Join`` function.
756 * @param delimiter The value you want to occur between fragments. The delimiter will occur between fragments only.
757 * It will not terminate the final value.
758 * @param listOfValues The list of values you want combined.
759 */
760 constructor(delimiter, listOfValues) {
761 if (listOfValues.length === 0) {
762 throw new Error('FnJoin requires at least one value to be provided');
763 }
764 this.delimiter = delimiter;
765 this.listOfValues = listOfValues;
766 this.creationStack = stack_trace_1.captureStackTrace();
767 }
768 resolve(context) {
769 if (token_1.Token.isUnresolved(this.listOfValues)) {
770 // This is a list token, don't try to do smart things with it.
771 return { 'Fn::Join': [this.delimiter, this.listOfValues] };
772 }
773 const resolved = this.resolveValues(context);
774 if (resolved.length === 1) {
775 return resolved[0];
776 }
777 return { 'Fn::Join': [this.delimiter, resolved] };
778 }
779 toString() {
780 return token_1.Token.asString(this, { displayHint: 'Fn::Join' });
781 }
782 toJSON() {
783 return '<Fn::Join>';
784 }
785 /**
786 * Optimization: if an Fn::Join is nested in another one and they share the same delimiter, then flatten it up. Also,
787 * if two concatenated elements are literal strings (not tokens), then pre-concatenate them with the delimiter, to
788 * generate shorter output.
789 */
790 resolveValues(context) {
791 const resolvedValues = this.listOfValues.map(x => reference_1.Reference.isReference(x) ? x : context.resolve(x));
792 return cloudformation_lang_1.minimalCloudFormationJoin(this.delimiter, resolvedValues);
793 }
794}
795function _inGroupsOf(array, maxGroup) {
796 const result = new Array();
797 for (let i = 0; i < array.length; i += maxGroup) {
798 result.push(array.slice(i, i + maxGroup));
799 }
800 return result;
801}
802function range(n) {
803 const ret = [];
804 for (let i = 0; i < n; i++) {
805 ret.push(i);
806 }
807 return ret;
808}
809//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2ZuLWZuLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2ZuLWZuLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUNBLHVFQUEwRTtBQUMxRSxtREFBZ0Q7QUFDaEQsMkNBQXdDO0FBRXhDLCtDQUFrRDtBQUNsRCxtQ0FBZ0M7QUFFaEMsNEJBQTRCO0FBRTVCOzs7R0FHRztBQUNILE1BQWEsRUFBRTtJQWdaYixpQkFBeUI7SUEvWXpCOzs7O09BSUc7SUFDSSxNQUFNLENBQUMsR0FBRyxDQUFDLFdBQW1CO1FBQ25DLE9BQU8sSUFBSSxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7S0FDMUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSSxNQUFNLENBQUMsTUFBTSxDQUFDLHFCQUE2QixFQUFFLGFBQXFCO1FBQ3ZFLE9BQU8sSUFBSSxRQUFRLENBQUMscUJBQXFCLEVBQUUsYUFBYSxDQUFDLENBQUM7S0FDM0Q7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQWlCLEVBQUUsWUFBc0I7UUFDMUQsSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUM3QixNQUFNLElBQUksS0FBSyxDQUFDLG1EQUFtRCxDQUFDLENBQUM7U0FDdEU7UUFFRCxPQUFPLElBQUksTUFBTSxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztLQUN2RDtJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0EwQ0c7SUFDSSxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQWlCLEVBQUUsTUFBYyxFQUFFLGFBQXNCO1FBQzNFLHdDQUF3QztRQUN4QyxJQUFJLENBQUMsYUFBSyxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUMvQixPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7U0FDaEM7UUFFRCxJQUFJLGFB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QUFDLEVBQUUsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUM7S0FDM0M7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQsU0FBUyxLQUFLLENBQUMsQ0FBUztJQUN0QixNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUM7SUFDZixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQzFCLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDYjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IElDZm5Db25kaXRpb25FeHByZXNzaW9uLCBJQ2ZuUnVsZUNvbmRpdGlvbkV4cHJlc3Npb24gfSBmcm9tICcuL2Nmbi1jb25kaXRpb24nO1xuaW1wb3J0IHsgbWluaW1hbENsb3VkRm9ybWF0aW9uSm9pbiB9IGZyb20gJy4vcHJpdmF0ZS9jbG91ZGZvcm1hdGlvbi1sYW5nJztcbmltcG9ydCB7IEludHJpbnNpYyB9IGZyb20gJy4vcHJpdmF0ZS9pbnRyaW5zaWMnO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSAnLi9yZWZlcmVuY2UnO1xuaW1wb3J0IHsgSVJlc29sdmFibGUsIElSZXNvbHZlQ29udGV4dCB9IGZyb20gJy4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBjYXB0dXJlU3RhY2tUcmFjZSB9IGZyb20gJy4vc3RhY2stdHJhY2UnO1xuaW1wb3J0IHsgVG9rZW4gfSBmcm9tICcuL3Rva2VuJztcblxuLyogZXNsaW50LWRpc2FibGUgbWF4LWxlbiAqL1xuXG4vKipcbiAqIENsb3VkRm9ybWF0aW9uIGludHJpbnNpYyBmdW5jdGlvbnMuXG4gKiBodHRwOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2ludHJpbnNpYy1mdW5jdGlvbi1yZWZlcmVuY2UuaHRtbFxuICovXG5leHBvcnQgY2xhc3MgRm4ge1xuICAvKipcbiAgICogVGhlIGBgUmVmYGAgaW50cmluc2ljIGZ1bmN0aW9uIHJldHVybnMgdGhlIHZhbHVlIG9mIHRoZSBzcGVjaWZpZWQgcGFyYW1ldGVyIG9yIHJlc291cmNlLlxuICAgKiBOb3RlIHRoYXQgaXQgZG9lc24ndCB2YWxpZGF0ZSB0aGUgbG9naWNhbE5hbWUsIGl0IG1haW5seSBzZXJ2ZXMgcGFyZW1ldGVyL3Jlc291cmNlIHJlZmVyZW5jZSBkZWZpbmVkIGluIGEgYGBDZm5JbmNsdWRlYGAgdGVtcGxhdGUuXG4gICAqIEBwYXJhbSBsb2dpY2FsTmFtZSBUaGUgbG9naWNhbCBuYW1lIG9mIGEgcGFyYW1ldGVyL3Jlc291cmNlIGZvciB3aGljaCB5b3Ugd2FudCB0byByZXRyaWV2ZSBpdHMgdmFsdWUuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHJlZihsb2dpY2FsTmFtZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbmV3IEZuUmVmKGxvZ2ljYWxOYW1lKS50b1N0cmluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBgYEZuOjpHZXRBdHRgYCBpbnRyaW5zaWMgZnVuY3Rpb24gcmV0dXJucyB0aGUgdmFsdWUgb2YgYW4gYXR0cmlidXRlXG4gICAqIGZyb20gYSByZXNvdXJjZSBpbiB0aGUgdGVtcGxhdGUuXG4gICAqIEBwYXJhbSBsb2dpY2FsTmFtZU9mUmVzb3VyY2UgVGhlIGxvZ2ljYWwgbmFtZSAoYWxzbyBjYWxsZWQgbG9naWNhbCBJRCkgb2ZcbiAgICogdGhlIHJlc291cmNlIHRoYXQgY29udGFpbnMgdGhlIGF0dHJpYnV0ZSB0aGF0IHlvdSB3YW50LlxuICAgKiBAcGFyYW0gYXR0cmlidXRlTmFtZSBUaGUgbmFtZSBvZiB0aGUgcmVzb3VyY2Utc3BlY2lmaWMgYXR0cmlidXRlIHdob3NlXG4gICAqIHZhbHVlIHlvdSB3YW50LiBTZWUgdGhlIHJlc291cmNlJ3MgcmVmZXJlbmNlIHBhZ2UgZm9yIGRldGFpbHMgYWJvdXQgdGhlXG4gICAqIGF0dHJpYnV0ZXMgYXZhaWxhYmxlIGZvciB0aGF0IHJlc291cmNlIHR5cGUuXG4gICAqIEByZXR1cm5zIGFuIElSZXNvbHZhYmxlIG9iamVjdFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBnZXRBdHQobG9naWNhbE5hbWVPZlJlc291cmNlOiBzdHJpbmcsIGF0dHJpYnV0ZU5hbWU6IHN0cmluZyk6IElSZXNvbHZhYmxlIHtcbiAgICByZXR1cm4gbmV3IEZuR2V0QXR0KGxvZ2ljYWxOYW1lT2ZSZXNvdXJjZSwgYXR0cmlidXRlTmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpKb2luYGAgYXBwZW5kcyBhIHNldCBvZiB2YWx1ZXMgaW50byBhIHNpbmdsZVxuICAgKiB2YWx1ZSwgc2VwYXJhdGVkIGJ5IHRoZSBzcGVjaWZpZWQgZGVsaW1pdGVyLiBJZiBhIGRlbGltaXRlciBpcyB0aGUgZW1wdHlcbiAgICogc3RyaW5nLCB0aGUgc2V0IG9mIHZhbHVlcyBhcmUgY29uY2F0ZW5hdGVkIHdpdGggbm8gZGVsaW1pdGVyLlxuICAgKiBAcGFyYW0gZGVsaW1pdGVyIFRoZSB2YWx1ZSB5b3Ugd2FudCB0byBvY2N1ciBiZXR3ZWVuIGZyYWdtZW50cy4gVGhlXG4gICAqIGRlbGltaXRlciB3aWxsIG9jY3VyIGJldHdlZW4gZnJhZ21lbnRzIG9ubHkuIEl0IHdpbGwgbm90IHRlcm1pbmF0ZSB0aGVcbiAgICogZmluYWwgdmFsdWUuXG4gICAqIEBwYXJhbSBsaXN0T2ZWYWx1ZXMgVGhlIGxpc3Qgb2YgdmFsdWVzIHlvdSB3YW50IGNvbWJpbmVkLlxuICAgKiBAcmV0dXJucyBhIHRva2VuIHJlcHJlc2VudGVkIGFzIGEgc3RyaW5nXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGpvaW4oZGVsaW1pdGVyOiBzdHJpbmcsIGxpc3RPZlZhbHVlczogc3RyaW5nW10pOiBzdHJpbmcge1xuICAgIGlmIChsaXN0T2ZWYWx1ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZuSm9pbiByZXF1aXJlcyBhdCBsZWFzdCBvbmUgdmFsdWUgdG8gYmUgcHJvdmlkZWQnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IEZuSm9pbihkZWxpbWl0ZXIsIGxpc3RPZlZhbHVlcykudG9TdHJpbmcoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTcGxpdCBhIHN0cmluZyB0b2tlbiBpbnRvIGEgdG9rZW4gbGlzdCBvZiBzdHJpbmcgdmFsdWVzLlxuICAgKlxuICAgKiBTcGVjaWZ5IHRoZSBsb2NhdGlvbiBvZiBzcGxpdHMgd2l0aCBhIGRlbGltaXRlciBzdWNoIGFzICcsJyAoYSBjb21tYSkuXG4gICAqIFJlbmRlcnMgdG8gdGhlIGBGbjo6U3BsaXRgIGludHJpbnNpYyBmdW5jdGlvbi5cbiAgICpcbiAgICogTGlzdHMgd2l0aCB1bmtub3duIGxlbmd0aHMgKGRlZmF1bHQpXG4gICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICpcbiAgICogU2luY2UgdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIHdvcmsgd2l0aCBkZXBsb3ktdGltZSB2YWx1ZXMsIGlmIGBhc3N1bWVkTGVuZ3RoYFxuICAgKiBpcyBub3QgZ2l2ZW4gdGhlIENESyBjYW5ub3Qga25vdyB0aGUgbGVuZ3RoIG9mIHRoZSByZXN1bHRpbmcgbGlzdCBhdCBzeW50aGVzaXMgdGltZS5cbiAgICogVGhpcyBicmluZ3MgdGhlIGZvbGxvd2luZyByZXN0cmljdGlvbnM6XG4gICAqXG4gICAqIC0gWW91IG11c3QgdXNlIGBGbi5zZWxlY3QoaSwgbGlzdClgIHRvIHBpY2sgZWxlbWVudHMgb3V0IG9mIHRoZSBsaXN0ICh5b3UgbXVzdCBub3QgdXNlXG4gICAqICAgYGxpc3RbaV1gKS5cbiAgICogLSBZb3UgY2Fubm90IGFkZCBlbGVtZW50cyB0byB0aGUgbGlzdCwgcmVtb3ZlIGVsZW1lbnRzIGZyb20gdGhlIGxpc3QsXG4gICAqICAgY29tYmluZSB0d28gc3VjaCBsaXN0cyB0b2dldGhlciwgb3IgdGFrZSBhIHNsaWNlIG9mIHRoZSBsaXN0LlxuICAgKiAtIFlvdSBjYW5ub3QgcGFzcyB0aGUgbGlzdCB0byBjb25zdHJ1Y3RzIHRoYXQgZG8gYW55IG9mIHRoZSBhYm92ZS5cbiAgICpcbiAgICogVGhlIG9ubHkgdmFsaWQgb3BlcmF0aW9uIHdpdGggc3VjaCBhIHRva2VuaXplZCBsaXN0IGlzIHRvIHBhc3MgaXQgdW5tb2RpZmllZCB0byBhXG4gICAqIENsb3VkRm9ybWF0aW9uIFJlc291cmNlIGNvbnN0cnVjdC5cbiAgICpcbiAgICogTGlzdHMgd2l0aCBhc3N1bWVkIGxlbmd0aHNcbiAgICogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICpcbiAgICogUGFzcyBgYXNzdW1lZExlbmd0aGAgaWYgeW91IGtub3cgdGhlIGxlbmd0aCBvZiB0aGUgbGlzdCB0aGF0IHdpbGwgYmVcbiAgICogcHJvZHVjZWQgYnkgc3BsaXR0aW5nLiBUaGUgYWN0dWFsIGxpc3QgbGVuZ3RoIGF0IGRlcGxveSB0aW1lIG1heSBiZVxuICAgKiAqbG9uZ2VyKiB0aGFuIHRoZSBudW1iZXIgeW91IHBhc3MsIGJ1dCBub3QgKnNob3J0ZXIqLlxuICAgKlxuICAgKiBUaGUgcmV0dXJuZWQgbGlzdCB3aWxsIGxvb2sgbGlrZTpcbiAgICpcbiAgICogYGBgXG4gICAqIFtGbi5zZWxlY3QoMCwgc3BsaXQpLCBGbi5zZWxlY3QoMSwgc3BsaXQpLCBGbi5zZWxlY3QoMiwgc3BsaXQpLCAuLi5dXG4gICAqIGBgYFxuICAgKlxuICAgKiBUaGUgcmVzdHJpY3Rpb25zIGZyb20gdGhlIHNlY3Rpb24gXCJMaXN0cyB3aXRoIHVua25vd24gbGVuZ3Roc1wiIHdpbGwgbm93IGJlIGxpZnRlZCxcbiAgICogYXQgdGhlIGV4cGVuc2Ugb2YgaGF2aW5nIHRvIGtub3cgYW5kIGZpeCB0aGUgbGVuZ3RoIG9mIHRoZSBsaXN0LlxuICAgKlxuICAgKiBAcGFyYW0gZGVsaW1pdGVyIEEgc3RyaW5nIHZhbHVlIHRoYXQgZGV0ZXJtaW5lcyB3aGVyZSB0aGUgc291cmNlIHN0cmluZyBpcyBkaXZpZGVkLlxuICAgKiBAcGFyYW0gc291cmNlIFRoZSBzdHJpbmcgdmFsdWUgdGhhdCB5b3Ugd2FudCB0byBzcGxpdC5cbiAgICogQHBhcmFtIGFzc3VtZWRMZW5ndGggVGhlIGxlbmd0aCBvZiB0aGUgbGlzdCB0aGF0IHdpbGwgYmUgcHJvZHVjZWQgYnkgc3BsaXR0aW5nXG4gICAqIEByZXR1cm5zIGEgdG9rZW4gcmVwcmVzZW50ZWQgYXMgYSBzdHJpbmcgYXJyYXlcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc3BsaXQoZGVsaW1pdGVyOiBzdHJpbmcsIHNvdXJjZTogc3RyaW5nLCBhc3N1bWVkTGVuZ3RoPzogbnVtYmVyKTogc3RyaW5nW10ge1xuICAgIC8vIHNob3J0LWNpcmN1dCBpZiBzb3VyY2UgaXMgbm90IGEgdG9rZW5cbiAgICBpZiAoIVRva2VuLmlzVW5yZXNvbHZlZChzb3VyY2UpKSB7XG4gICAgICByZXR1cm4gc291cmNlLnNwbGl0KGRlbGltaXRlcik7XG4gICAgfVxuXG4gICAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChkZWxpbWl0ZXIpKSB7XG4gICAgICAvLyBMaW1pdGF0aW9uIG9mIENsb3VkRm9ybWF0aW9uXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZuLnNwbGl0OiBcXCdkZWxpbWl0ZXJcXCcgbWF5IG5vdCBiZSBhIHRva2VuIHZhbHVlJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3BsaXQgPSBUb2tlbi5hc0xpc3QobmV3IEZuU3BsaXQoZGVsaW1pdGVyLCBzb3VyY2UpKTtcbiAgICBpZiAoYXNzdW1lZExlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gc3BsaXQ7XG4gICAgfVxuXG4gICAgaWYgKFRva2VuLmlzVW5yZXNvbHZlZChhc3N1bWVkTGVuZ3RoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdGbi5zcGxpdDogXFwnYXNzdW1lZExlbmd0aFxcJyBtYXkgbm90IGJlIGEgdG9rZW4gdmFsdWUnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmFuZ2UoYXNzdW1lZExlbmd0aCkubWFwKGkgPT4gRm4uc2VsZWN0KGksIHNwbGl0KSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpTZWxlY3RgYCByZXR1cm5zIGEgc2luZ2xlIG9iamVjdCBmcm9tIGEgbGlzdCBvZiBvYmplY3RzIGJ5IGluZGV4LlxuICAgKiBAcGFyYW0gaW5kZXggVGhlIGluZGV4IG9mIHRoZSBvYmplY3QgdG8gcmV0cmlldmUuIFRoaXMgbXVzdCBiZSBhIHZhbHVlIGZyb20gemVybyB0byBOLTEsIHdoZXJlIE4gcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIGluIHRoZSBhcnJheS5cbiAgICogQHBhcmFtIGFycmF5IFRoZSBsaXN0IG9mIG9iamVjdHMgdG8gc2VsZWN0IGZyb20uIFRoaXMgbGlzdCBtdXN0IG5vdCBiZSBudWxsLCBub3IgY2FuIGl0IGhhdmUgbnVsbCBlbnRyaWVzLlxuICAgKiBAcmV0dXJucyBhIHRva2VuIHJlcHJlc2VudGVkIGFzIGEgc3RyaW5nXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHNlbGVjdChpbmRleDogbnVtYmVyLCBhcnJheTogc3RyaW5nW10pOiBzdHJpbmcge1xuICAgIGlmICghVG9rZW4uaXNVbnJlc29sdmVkKGluZGV4KSAmJiAhVG9rZW4uaXNVbnJlc29sdmVkKGFycmF5KSAmJiAhYXJyYXkuc29tZShUb2tlbi5pc1VucmVzb2x2ZWQpKSB7XG4gICAgICByZXR1cm4gYXJyYXlbaW5kZXhdO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgRm5TZWxlY3QoaW5kZXgsIGFycmF5KS50b1N0cmluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBpbnRyaW5zaWMgZnVuY3Rpb24gYGBGbjo6U3ViYGAgc3Vic3RpdHV0ZXMgdmFyaWFibGVzIGluIGFuIGlucHV0IHN0cmluZ1xuICAgKiB3aXRoIHZhbHVlcyB0aGF0IHlvdSBzcGVjaWZ5LiBJbiB5b3VyIHRlbXBsYXRlcywgeW91IGNhbiB1c2UgdGhpcyBmdW5jdGlvblxuICAgKiB0byBjb25zdHJ1Y3QgY29tbWFuZHMgb3Igb3V0cHV0cyB0aGF0IGluY2x1ZGUgdmFsdWVzIHRoYXQgYXJlbid0IGF2YWlsYWJsZVxuICAgKiB1bnRpbCB5b3UgY3JlYXRlIG9yIHVwZGF0ZSBhIHN0YWNrLlxuICAgKiBAcGFyYW0gYm9keSBBIHN0cmluZyB3aXRoIHZhcmlhYmxlcyB0aGF0IEFXUyBDbG91ZEZvcm1hdGlvbiBzdWJzdGl0dXRlc1xuICAgKiB3aXRoIHRoZWlyIGFzc29jaWF0ZWQgdmFsdWVzIGF0IHJ1bnRpbWUuIFdyaXRlIHZhcmlhYmxlcyBhcyAke015VmFyTmFtZX0uXG4gICAqIFZhcmlhYmxlcyBjYW4gYmUgdGVtcGxhdGUgcGFyYW1ldGVyIG5hbWVzLCByZXNvdXJjZSBsb2dpY2FsIElEcywgcmVzb3VyY2VcbiAgICogYXR0cmlidXRlcywgb3IgYSB2YXJpYWJsZSBpbiBhIGtleS12YWx1ZSBtYXAuIElmIHlvdSBzcGVjaWZ5IG9ubHkgdGVtcGxhdGVcbiAgICogcGFyYW1ldGVyIG5hbWVzLCByZXNvdXJjZSBsb2dpY2FsIElEcywgYW5kIHJlc291cmNlIGF0dHJpYnV0ZXMsIGRvbid0XG4gICAqIHNwZWNpZnkgYSBrZXktdmFsdWUgbWFwLlxuICAgKiBAcGFyYW0gdmFyaWFibGVzIFRoZSBuYW1lIG9mIGEgdmFyaWFibGUgdGhhdCB5b3UgaW5jbHVkZWQgaW4gdGhlIFN0cmluZ1xuICAgKiBwYXJhbWV0ZXIuIFRoZSB2YWx1ZSB0aGF0IEFXUyBDbG91ZEZvcm1hdGlvbiBzdWJzdGl0dXRlcyBmb3IgdGhlIGFzc29jaWF0ZWRcbiAgICogdmFyaWFibGUgbmFtZSBhdCBydW50aW1lLlxuICAgKiBAcmV0dXJucyBhIHRva2VuIHJlcHJlc2VudGVkIGFzIGEgc3RyaW5nXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHN1Yihib2R5OiBzdHJpbmcsIHZhcmlhYmxlcz86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0pOiBzdHJpbmcge1xuICAgIHJldHVybiBuZXcgRm5TdWIoYm9keSwgdmFyaWFibGVzKS50b1N0cmluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBpbnRyaW5zaWMgZnVuY3Rpb24gYGBGbjo6QmFzZTY0YGAgcmV0dXJucyB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uIG9mXG4gICAqIHRoZSBpbnB1dCBzdHJpbmcuIFRoaXMgZnVuY3Rpb24gaXMgdHlwaWNhbGx5IHVzZWQgdG8gcGFzcyBlbmNvZGVkIGRhdGEgdG9cbiAgICogQW1hem9uIEVDMiBpbnN0YW5jZXMgYnkgd2F5IG9mIHRoZSBVc2VyRGF0YSBwcm9wZXJ0eS5cbiAgICogQHBhcmFtIGRhdGEgVGhlIHN0cmluZyB2YWx1ZSB5b3Ugd2FudCB0byBjb252ZXJ0IHRvIEJhc2U2NC5cbiAgICogQHJldHVybnMgYSB0b2tlbiByZXByZXNlbnRlZCBhcyBhIHN0cmluZ1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBiYXNlNjQoZGF0YTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbmV3IEZuQmFzZTY0KGRhdGEpLnRvU3RyaW5nKCk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpDaWRyYGAgcmV0dXJucyB0aGUgc3BlY2lmaWVkIENpZHIgYWRkcmVzcyBibG9jay5cbiAgICogQHBhcmFtIGlwQmxvY2sgIFRoZSB1c2VyLXNwZWNpZmllZCBkZWZhdWx0IENpZHIgYWRkcmVzcyBibG9jay5cbiAgICogQHBhcmFtIGNvdW50ICBUaGUgbnVtYmVyIG9mIHN1Ym5ldHMnIENpZHIgYmxvY2sgd2FudGVkLiBDb3VudCBjYW4gYmUgMSB0byAyNTYuXG4gICAqIEBwYXJhbSBzaXplTWFzayBUaGUgZGlnaXQgY292ZXJlZCBpbiB0aGUgc3VibmV0LlxuICAgKiBAcmV0dXJucyBhIHRva2VuIHJlcHJlc2VudGVkIGFzIGEgc3RyaW5nXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNpZHIoaXBCbG9jazogc3RyaW5nLCBjb3VudDogbnVtYmVyLCBzaXplTWFzaz86IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gVG9rZW4uYXNMaXN0KG5ldyBGbkNpZHIoaXBCbG9jaywgY291bnQsIHNpemVNYXNrKSk7XG4gIH1cblxuICAvKipcbiAgICogR2l2ZW4gYW4gdXJsLCBwYXJzZSB0aGUgZG9tYWluIG5hbWVcbiAgICogQHBhcmFtIHVybCB0aGUgdXJsIHRvIHBhcnNlXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHBhcnNlRG9tYWluTmFtZSh1cmw6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3Qgbm9IdHRwcyA9IEZuLnNlbGVjdCgxLCBGbi5zcGxpdCgnLy8nLCB1cmwpKTtcbiAgICByZXR1cm4gRm4uc2VsZWN0KDAsIEZuLnNwbGl0KCcvJywgbm9IdHRwcykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBpbnRyaW5zaWMgZnVuY3Rpb24gYGBGbjo6R2V0QVpzYGAgcmV0dXJucyBhbiBhcnJheSB0aGF0IGxpc3RzXG4gICAqIEF2YWlsYWJpbGl0eSBab25lcyBmb3IgYSBzcGVjaWZpZWQgcmVnaW9uLiBCZWNhdXNlIGN1c3RvbWVycyBoYXZlIGFjY2VzcyB0b1xuICAgKiBkaWZmZXJlbnQgQXZhaWxhYmlsaXR5IFpvbmVzLCB0aGUgaW50cmluc2ljIGZ1bmN0aW9uIGBgRm46OkdldEFac2BgIGVuYWJsZXNcbiAgICogdGVtcGxhdGUgYXV0aG9ycyB0byB3cml0ZSB0ZW1wbGF0ZXMgdGhhdCBhZGFwdCB0byB0aGUgY2FsbGluZyB1c2VyJ3NcbiAgICogYWNjZXNzLiBUaGF0IHdheSB5b3UgZG9uJ3QgaGF2ZSB0byBoYXJkLWNvZGUgYSBmdWxsIGxpc3Qgb2YgQXZhaWxhYmlsaXR5XG4gICAqIFpvbmVzIGZvciBhIHNwZWNpZmllZCByZWdpb24uXG4gICAqIEBwYXJhbSByZWdpb24gVGhlIG5hbWUgb2YgdGhlIHJlZ2lvbiBmb3Igd2hpY2ggeW91IHdhbnQgdG8gZ2V0IHRoZVxuICAgKiBBdmFpbGFiaWxpdHkgWm9uZXMuIFlvdSBjYW4gdXNlIHRoZSBBV1M6OlJlZ2lvbiBwc2V1ZG8gcGFyYW1ldGVyIHRvIHNwZWNpZnlcbiAgICogdGhlIHJlZ2lvbiBpbiB3aGljaCB0aGUgc3RhY2sgaXMgY3JlYXRlZC4gU3BlY2lmeWluZyBhbiBlbXB0eSBzdHJpbmcgaXNcbiAgICogZXF1aXZhbGVudCB0byBzcGVjaWZ5aW5nIEFXUzo6UmVnaW9uLlxuICAgKiBAcmV0dXJucyBhIHRva2VuIHJlcHJlc2VudGVkIGFzIGEgc3RyaW5nIGFycmF5XG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldEF6cyhyZWdpb24/OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIFRva2VuLmFzTGlzdChuZXcgRm5HZXRBWnMocmVnaW9uKSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpJbXBvcnRWYWx1ZWBgIHJldHVybnMgdGhlIHZhbHVlIG9mIGFuIG91dHB1dFxuICAgKiBleHBvcnRlZCBieSBhbm90aGVyIHN0YWNrLiBZb3UgdHlwaWNhbGx5IHVzZSB0aGlzIGZ1bmN0aW9uIHRvIGNyZWF0ZVxuICAgKiBjcm9zcy1zdGFjayByZWZlcmVuY2VzLiBJbiB0aGUgZm9sbG93aW5nIGV4YW1wbGUgdGVtcGxhdGUgc25pcHBldHMsIFN0YWNrIEFcbiAgICogZXhwb3J0cyBWUEMgc2VjdXJpdHkgZ3JvdXAgdmFsdWVzIGFuZCBTdGFjayBCIGltcG9ydHMgdGhlbS5cbiAgICogQHBhcmFtIHNoYXJlZFZhbHVlVG9JbXBvcnQgVGhlIHN0YWNrIG91dHB1dCB2YWx1ZSB0aGF0IHlvdSB3YW50IHRvIGltcG9ydC5cbiAgICogQHJldHVybnMgYSB0b2tlbiByZXByZXNlbnRlZCBhcyBhIHN0cmluZ1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBpbXBvcnRWYWx1ZShzaGFyZWRWYWx1ZVRvSW1wb3J0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBuZXcgRm5JbXBvcnRWYWx1ZShzaGFyZWRWYWx1ZVRvSW1wb3J0KS50b1N0cmluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIExpa2UgYEZuLmltcG9ydFZhbHVlYCwgYnV0IGltcG9ydCBhIGxpc3Qgd2l0aCBhIGtub3duIGxlbmd0aFxuICAgKlxuICAgKiBJZiB5b3UgZXhwbGljaXRseSB3YW50IGEgbGlzdCB3aXRoIGFuIHVua25vd24gbGVuZ3RoLCBjYWxsIGBGbi5zcGxpdCgnLCcsXG4gICAqIEZuLmltcG9ydFZhbHVlKGV4cG9ydE5hbWUpKWAuIFNlZSB0aGUgZG9jdW1lbnRhdGlvbiBvZiBgRm4uc3BsaXRgIHRvIHJlYWRcbiAgICogbW9yZSBhYm91dCB0aGUgbGltaXRhdGlvbnMgb2YgdXNpbmcgbGlzdHMgb2YgdW5rbm93biBsZW5ndGguXG4gICAqXG4gICAqIGBGbi5pbXBvcnRMaXN0VmFsdWUoZXhwb3J0TmFtZSwgYXNzdW1lZExlbmd0aClgIGlzIHRoZSBzYW1lIGFzXG4gICAqIGBGbi5zcGxpdCgnLCcsIEZuLmltcG9ydFZhbHVlKGV4cG9ydE5hbWUpLCBhc3N1bWVkTGVuZ3RoKWAsXG4gICAqIGJ1dCBlYXNpZXIgdG8gcmVhZCBhbmQgaW1wb3NzaWJsZSB0byBmb3JnZXQgdG8gcGFzcyBgYXNzdW1lZExlbmd0aGAuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGltcG9ydExpc3RWYWx1ZShzaGFyZWRWYWx1ZVRvSW1wb3J0OiBzdHJpbmcsIGFzc3VtZWRMZW5ndGg6IG51bWJlciwgZGVsaW1pdGVyID0gJywnKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBGbi5zcGxpdChkZWxpbWl0ZXIsIEZuLmltcG9ydFZhbHVlKHNoYXJlZFZhbHVlVG9JbXBvcnQpLCBhc3N1bWVkTGVuZ3RoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgaW50cmluc2ljIGZ1bmN0aW9uIGBgRm46OkZpbmRJbk1hcGBgIHJldHVybnMgdGhlIHZhbHVlIGNvcnJlc3BvbmRpbmcgdG9cbiAgICoga2V5cyBpbiBhIHR3by1sZXZlbCBtYXAgdGhhdCBpcyBkZWNsYXJlZCBpbiB0aGUgTWFwcGluZ3Mgc2VjdGlvbi5cbiAgICogQHJldHVybnMgYSB0b2tlbiByZXByZXNlbnRlZCBhcyBhIHN0cmluZ1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmaW5kSW5NYXAobWFwTmFtZTogc3RyaW5nLCB0b3BMZXZlbEtleTogc3RyaW5nLCBzZWNvbmRMZXZlbEtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gRm4uX2ZpbmRJbk1hcChtYXBOYW1lLCB0b3BMZXZlbEtleSwgc2Vjb25kTGV2ZWxLZXkpLnRvU3RyaW5nKCk7XG4gIH1cblxuICAvKipcbiAgICogQW4gYWRkaXRpb25hbCBmdW5jdGlvbiB1c2VkIGluIENmblBhcnNlcixcbiAgICogYXMgRm46OkZpbmRJbk1hcCBkb2VzIG5vdCBhbHdheXMgcmV0dXJuIGEgc3RyaW5nLlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgX2ZpbmRJbk1hcChtYXBOYW1lOiBzdHJpbmcsIHRvcExldmVsS2V5OiBzdHJpbmcsIHNlY29uZExldmVsS2V5OiBzdHJpbmcpOiBJUmVzb2x2YWJsZSB7XG4gICAgcmV0dXJuIG5ldyBGbkZpbmRJbk1hcChtYXBOYW1lLCB0b3BMZXZlbEtleSwgc2Vjb25kTGV2ZWxLZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSB0b2tlbiByZXByZXNlbnRpbmcgdGhlIGBgRm46OlRyYW5zZm9ybWBgIGV4cHJlc3Npb25cbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTQ2xvdWRGb3JtYXRpb24vbGF0ZXN0L1VzZXJHdWlkZS9pbnRyaW5zaWMtZnVuY3Rpb24tcmVmZXJlbmNlLXRyYW5zZm9ybS5odG1sXG4gICAqIEBwYXJhbSBtYWNyb05hbWUgVGhlIG5hbWUgb2YgdGhlIG1hY3JvIHRvIHBlcmZvcm0gdGhlIHByb2Nlc3NpbmdcbiAgICogQHBhcmFtIHBhcmFtZXRlcnMgVGhlIHBhcmFtZXRlcnMgdG8gYmUgcGFzc2VkIHRvIHRoZSBtYWNyb1xuICAgKiBAcmV0dXJucyBhIHRva2VuIHJlcHJlc2VudGluZyB0aGUgdHJhbnNmb3JtIGV4cHJlc3Npb25cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgdHJhbnNmb3JtKG1hY3JvTmFtZTogc3RyaW5nLCBwYXJhbWV0ZXJzOiB7IFtuYW1lOiBzdHJpbmddOiBhbnkgfSk6IElSZXNvbHZhYmxlIHtcbiAgICByZXR1cm4gbmV3IEZuVHJhbnNmb3JtKG1hY3JvTmFtZSwgcGFyYW1ldGVycyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIGFsbCB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbnMgZXZhbHVhdGUgdG8gdHJ1ZSwgb3IgcmV0dXJuc1xuICAgKiBmYWxzZSBpZiBhbnkgb25lIG9mIHRoZSBjb25kaXRpb25zIGV2YWx1YXRlcyB0byBmYWxzZS4gYGBGbjo6QW5kYGAgYWN0cyBhc1xuICAgKiBhbiBBTkQgb3BlcmF0b3IuIFRoZSBtaW5pbXVtIG51bWJlciBvZiBjb25kaXRpb25zIHRoYXQgeW91IGNhbiBpbmNsdWRlIGlzXG4gICAqIDEuXG4gICAqIEBwYXJhbSBjb25kaXRpb25zIGNvbmRpdGlvbnMgdG8gQU5EXG4gICAqIEByZXR1cm5zIGFuIEZuQ29uZGl0aW9uIHRva2VuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNvbmRpdGlvbkFuZCguLi5jb25kaXRpb25zOiBJQ2ZuQ29uZGl0aW9uRXhwcmVzc2lvbltdKTogSUNmblJ1bGVDb25kaXRpb25FeHByZXNzaW9uIHtcbiAgICBpZiAoY29uZGl0aW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRm4uY29uZGl0aW9uQW5kKCkgbmVlZHMgYXQgbGVhc3Qgb25lIGFyZ3VtZW50Jyk7XG4gICAgfVxuICAgIGlmIChjb25kaXRpb25zLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIGNvbmRpdGlvbnNbMF0gYXMgSUNmblJ1bGVDb25kaXRpb25FeHByZXNzaW9uO1xuICAgIH1cbiAgICByZXR1cm4gRm4uY29uZGl0aW9uQW5kKC4uLl9pbkdyb3Vwc09mKGNvbmRpdGlvbnMsIDEwKS5tYXAoZ3JvdXAgPT4gbmV3IEZuQW5kKC4uLmdyb3VwKSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbXBhcmVzIGlmIHR3byB2YWx1ZXMgYXJlIGVxdWFsLiBSZXR1cm5zIHRydWUgaWYgdGhlIHR3byB2YWx1ZXMgYXJlIGVxdWFsXG4gICAqIG9yIGZhbHNlIGlmIHRoZXkgYXJlbid0LlxuICAgKiBAcGFyYW0gbGhzIEEgdmFsdWUgb2YgYW55IHR5cGUgdGhhdCB5b3Ugd2FudCB0byBjb21wYXJlLlxuICAgKiBAcGFyYW0gcmhzIEEgdmFsdWUgb2YgYW55IHR5cGUgdGhhdCB5b3Ugd2FudCB0byBjb21wYXJlLlxuICAgKiBAcmV0dXJucyBhbiBGbkNvbmRpdGlvbiB0b2tlblxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb25kaXRpb25FcXVhbHMobGhzOiBhbnksIHJoczogYW55KTogSUNmblJ1bGVDb25kaXRpb25FeHByZXNzaW9uIHtcbiAgICByZXR1cm4gbmV3IEZuRXF1YWxzKGxocywgcmhzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIG9uZSB2YWx1ZSBpZiB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbiBldmFsdWF0ZXMgdG8gdHJ1ZSBhbmQgYW5vdGhlclxuICAgKiB2YWx1ZSBpZiB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbiBldmFsdWF0ZXMgdG8gZmFsc2UuIEN1cnJlbnRseSwgQVdTXG4gICAqIENsb3VkRm9ybWF0aW9uIHN1cHBvcnRzIHRoZSBgYEZuOjpJZmBgIGludHJpbnNpYyBmdW5jdGlvbiBpbiB0aGUgbWV0YWRhdGFcbiAgICogYXR0cmlidXRlLCB1cGRhdGUgcG9saWN5IGF0dHJpYnV0ZSwgYW5kIHByb3BlcnR5IHZhbHVlcyBpbiB0aGUgUmVzb3VyY2VzXG4gICAqIHNlY3Rpb24gYW5kIE91dHB1dHMgc2VjdGlvbnMgb2YgYSB0ZW1wbGF0ZS4gWW91IGNhbiB1c2UgdGhlIEFXUzo6Tm9WYWx1ZVxuICAgKiBwc2V1ZG8gcGFyYW1ldGVyIGFzIGEgcmV0dXJuIHZhbHVlIHRvIHJlbW92ZSB0aGUgY29ycmVzcG9uZGluZyBwcm9wZXJ0eS5cbiAgICogQHBhcmFtIGNvbmRpdGlvbklkIEEgcmVmZXJlbmNlIHRvIGEgY29uZGl0aW9uIGluIHRoZSBDb25kaXRpb25zIHNlY3Rpb24uIFVzZVxuICAgKiB0aGUgY29uZGl0aW9uJ3MgbmFtZSB0byByZWZlcmVuY2UgaXQuXG4gICAqIEBwYXJhbSB2YWx1ZUlmVHJ1ZSBBIHZhbHVlIHRvIGJlIHJldHVybmVkIGlmIHRoZSBzcGVjaWZpZWQgY29uZGl0aW9uXG4gICAqIGV2YWx1YXRlcyB0byB0cnVlLlxuICAgKiBAcGFyYW0gdmFsdWVJZkZhbHNlIEEgdmFsdWUgdG8gYmUgcmV0dXJuZWQgaWYgdGhlIHNwZWNpZmllZCBjb25kaXRpb25cbiAgICogZXZhbHVhdGVzIHRvIGZhbHNlLlxuICAgKiBAcmV0dXJucyBhbiBGbkNvbmRpdGlvbiB0b2tlblxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb25kaXRpb25JZihjb25kaXRpb25JZDogc3RyaW5nLCB2YWx1ZUlmVHJ1ZTogYW55LCB2YWx1ZUlmRmFsc2U6IGFueSk6IElDZm5SdWxlQ29uZGl0aW9uRXhwcmVzc2lvbiB7XG4gICAgcmV0dXJuIG5ldyBGbklmKGNvbmRpdGlvbklkLCB2YWx1ZUlmVHJ1ZSwgdmFsdWVJZkZhbHNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgZm9yIGEgY29uZGl0aW9uIHRoYXQgZXZhbHVhdGVzIHRvIGZhbHNlIG9yIHJldHVybnMgZmFsc2UgZm9yIGFcbiAgICogY29uZGl0aW9uIHRoYXQgZXZhbHVhdGVzIHRvIHRydWUuIGBgRm46Ok5vdGBgIGFjdHMgYXMgYSBOT1Qgb3BlcmF0b3IuXG4gICAqIEBwYXJhbSBjb25kaXRpb24gQSBjb25kaXRpb24gc3VjaCBhcyBgYEZuOjpFcXVhbHNgYCB0aGF0IGV2YWx1YXRlcyB0byB0cnVlXG4gICAqIG9yIGZhbHNlLlxuICAgKiBAcmV0dXJucyBhbiBGbkNvbmRpdGlvbiB0b2tlblxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb25kaXRpb25Ob3QoY29uZGl0aW9uOiBJQ2ZuQ29uZGl0aW9uRXhwcmVzc2lvbik6IElDZm5SdWxlQ29uZGl0aW9uRXhwcmVzc2lvbiB7XG4gICAgcmV0dXJuIG5ldyBGbk5vdChjb25kaXRpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBhbnkgb25lIG9mIHRoZSBzcGVjaWZpZWQgY29uZGl0aW9ucyBldmFsdWF0ZSB0byB0cnVlLCBvclxuICAgKiByZXR1cm5zIGZhbHNlIGlmIGFsbCBvZiB0aGUgY29uZGl0aW9ucyBldmFsdWF0ZXMgdG8gZmFsc2UuIGBgRm46Ok9yYGAgYWN0c1xuICAgKiBhcyBhbiBPUiBvcGVyYXRvci4gVGhlIG1pbmltdW0gbnVtYmVyIG9mIGNvbmRpdGlvbnMgdGhhdCB5b3UgY2FuIGluY2x1ZGUgaXNcbiAgICogMS5cbiAgICogQHBhcmFtIGNvbmRpdGlvbnMgY29uZGl0aW9ucyB0aGF0IGV2YWx1YXRlcyB0byB0cnVlIG9yIGZhbHNlLlxuICAgKiBAcmV0dXJucyBhbiBGbkNvbmRpdGlvbiB0b2tlblxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjb25kaXRpb25PciguLi5jb25kaXRpb25zOiBJQ2ZuQ29uZGl0aW9uRXhwcmVzc2lvbltdKTogSUNmblJ1bGVDb25kaXRpb25FeHByZXNzaW9uIHtcbiAgICBpZiAoY29uZGl0aW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRm4uY29uZGl0aW9uT3IoKSBuZWVkcyBhdCBsZWFzdCBvbmUgYXJndW1lbnQnKTtcbiAgICB9XG4gICAgaWYgKGNvbmRpdGlvbnMubGVuZ3RoID09PSAxKSB7XG4gICAgICByZXR1cm4gY29uZGl0aW9uc1swXSBhcyBJQ2ZuUnVsZUNvbmRpdGlvbkV4cHJlc3Npb247XG4gICAgfVxuICAgIHJldHVybiBGbi5jb25kaXRpb25PciguLi5faW5Hcm91cHNPZihjb25kaXRpb25zLCAxMCkubWFwKGdyb3VwID0+IG5ldyBGbk9yKC4uLmdyb3VwKSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBhIHNwZWNpZmllZCBzdHJpbmcgbWF0Y2hlcyBhdCBsZWFzdCBvbmUgdmFsdWUgaW4gYSBsaXN0IG9mXG4gICAqIHN0cmluZ3MuXG4gICAqIEBwYXJhbSBsaXN0T2ZTdHJpbmdzIEEgbGlzdCBvZiBzdHJpbmdzLCBzdWNoIGFzIFwiQVwiLCBcIkJcIiwgXCJDXCIuXG4gICAqIEBwYXJhbSB2YWx1ZSBBIHN0cmluZywgc3VjaCBhcyBcIkFcIiwgdGhhdCB5b3Ugd2FudCB0byBjb21wYXJlIGFnYWluc3QgYSBsaXN0IG9mIHN0cmluZ3MuXG4gICAqIEByZXR1cm5zIGFuIEZuQ29uZGl0aW9uIHRva2VuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNvbmRpdGlvbkNvbnRhaW5zKGxpc3RPZlN0cmluZ3M6IHN0cmluZ1tdLCB2YWx1ZTogc3RyaW5nKTogSUNmblJ1bGVDb25kaXRpb25FeHByZXNzaW9uIHtcbiAgICByZXR1cm4gbmV3IEZuQ29udGFpbnMobGlzdE9mU3RyaW5ncywgdmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBhIHNwZWNpZmllZCBzdHJpbmcgbWF0Y2hlcyBhbGwgdmFsdWVzIGluIGEgbGlzdC5cbiAgICogQHBhcmFtIGxpc3RPZlN0cmluZ3MgQSBsaXN0IG9mIHN0cmluZ3MsIHN1Y2ggYXMgXCJBXCIsIFwiQlwiLCBcIkNcIi5cbiAgICogQHBhcmFtIHZhbHVlIEEgc3RyaW5nLCBzdWNoIGFzIFwiQVwiLCB0aGF0IHlvdSB3YW50IHRvIGNvbXBhcmUgYWdhaW5zdCBhIGxpc3RcbiAgICogb2Ygc3RyaW5ncy5cbiAgICogQHJldHVybnMgYW4gRm5Db25kaXRpb24gdG9rZW5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY29uZGl0aW9uRWFjaE1lbWJlckVxdWFscyhsaXN0T2ZTdHJpbmdzOiBzdHJpbmdbXSwgdmFsdWU6IHN0cmluZyk6IElDZm5SdWxlQ29uZGl0aW9uRXhwcmVzc2lvbiB7XG4gICAgcmV0dXJuIG5ldyBGbkVhY2hNZW1iZXJFcXVhbHMobGlzdE9mU3RyaW5ncywgdmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiBlYWNoIG1lbWJlciBpbiBhIGxpc3Qgb2Ygc3RyaW5ncyBtYXRjaGVzIGF0IGxlYXN0IG9uZSB2YWx1ZVxuICAgKiBpbiBhIHNlY29uZCBsaXN0IG9mIHN0cmluZ3MuXG4gICAqIEBwYXJhbSBzdHJpbmdzVG9DaGVjayBBIGxpc3Qgb2Ygc3RyaW5ncywgc3VjaCBhcyBcIkFcIiwgXCJCXCIsIFwiQ1wiLiBBV1NcbiAgICogQ2xvdWRGb3JtYXRpb24gY2hlY2tzIHdoZXRoZXIgZWFjaCBtZW1iZXIgaW4gdGhlIHN0cmluZ3NfdG9fY2hlY2sgcGFyYW1ldGVyXG4gICAqIGlzIGluIHRoZSBzdHJpbmdzX3RvX21hdGNoIHBhcmFtZXRlci5cbiAgICogQHBhcmFtIHN0cmluZ3NUb01hdGNoIEEgbGlzdCBvZiBzdHJpbmdzLCBzdWNoIGFzIFwiQVwiLCBcIkJcIiwgXCJDXCIuIEVhY2ggbWVtYmVyXG4gICAqIGluIHRoZSBzdHJpbmdzX3RvX21hdGNoIHBhcmFtZXRlciBpcyBjb21wYXJlZCBhZ2FpbnN0IHRoZSBtZW1iZXJzIG9mIHRoZVxuICAgKiBzdHJpbmdzX3RvX2NoZWNrIHBhcmFtZXRlci5cbiAgICogQHJldHVybnMgYW4gRm5Db25kaXRpb24gdG9rZW5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY29uZGl0aW9uRWFjaE1lbWJlckluKHN0cmluZ3NUb0NoZWNrOiBzdHJpbmdbXSwgc3RyaW5nc1RvTWF0Y2g6IHN0cmluZ1tdKTogSUNmblJ1bGVDb25kaXRpb25FeHByZXNzaW9uIHtcbiAgICByZXR1cm4gbmV3IEZuRWFjaE1lbWJlckluKHN0cmluZ3NUb0NoZWNrLCBzdHJpbmdzVG9NYXRjaCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhbGwgdmFsdWVzIGZvciBhIHNwZWNpZmllZCBwYXJhbWV0ZXIgdHlwZS5cbiAgICogQHBhcmFtIHBhcmFtZXRlclR5cGUgQW4gQVdTLXNwZWNpZmljIHBhcmFtZXRlciB0eXBlLCBzdWNoIGFzXG4gICAqIEFXUzo6RUMyOjpTZWN1cml0eUdyb3VwOjpJZCBvciBBV1M6OkVDMjo6VlBDOjpJZC4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZVxuICAgKiBQYXJhbWV0ZXJzIGluIHRoZSBBV1MgQ2xvdWRGb3JtYXRpb24gVXNlciBHdWlkZS5cbiAgICogQHJldHVybnMgYSB0b2tlbiByZXByZXNlbnRlZCBhcyBhIHN0cmluZyBhcnJheVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyByZWZBbGwocGFyYW1ldGVyVHlwZTogc3RyaW5nKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBUb2tlbi5hc0xpc3QobmV3IEZuUmVmQWxsKHBhcmFtZXRlclR5cGUpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIGF0dHJpYnV0ZSB2YWx1ZSBvciBsaXN0IG9mIHZhbHVlcyBmb3IgYSBzcGVjaWZpYyBwYXJhbWV0ZXIgYW5kXG4gICAqIGF0dHJpYnV0ZS5cbiAgICogQHBhcmFtIHBhcmFtZXRlck9yTG9naWNhbElkIFRoZSBuYW1lIG9mIGEgcGFyYW1ldGVyIGZvciB3aGljaCB5b3Ugd2FudCB0b1xuICAgKiByZXRyaWV2ZSBhdHRyaWJ1dGUgdmFsdWVzLiBUaGUgcGFyYW1ldGVyIG11c3QgYmUgZGVjbGFyZWQgaW4gdGhlIFBhcmFtZXRlcnNcbiAgICogc2VjdGlvbiBvZiB0aGUgdGVtcGxhdGUuXG4gICAqIEBwYXJhbSBhdHRyaWJ1dGUgVGhlIG5hbWUgb2YgYW4gYXR0cmlidXRlIGZyb20gd2hpY2ggeW91IHdhbnQgdG8gcmV0cmlldmUgYVxuICAgKiB2YWx1ZS5cbiAgICogQHJldHVybnMgYSB0b2tlbiByZXByZXNlbnRlZCBhcyBhIHN0cmluZ1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyB2YWx1ZU9mKHBhcmFtZXRlck9yTG9naWNhbElkOiBzdHJpbmcsIGF0dHJpYnV0ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbmV3IEZuVmFsdWVPZihwYXJhbWV0ZXJPckxvZ2ljYWxJZCwgYXR0cmlidXRlKS50b1N0cmluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBsaXN0IG9mIGFsbCBhdHRyaWJ1dGUgdmFsdWVzIGZvciBhIGdpdmVuIHBhcmFtZXRlciB0eXBlIGFuZFxuICAgKiBhdHRyaWJ1dGUuXG4gICAqIEBwYXJhbSBwYXJhbWV0ZXJUeXBlIEFuIEFXUy1zcGVjaWZpYyBwYXJhbWV0ZXIgdHlwZSwgc3VjaCBhc1xuICAgKiBBV1M6OkVDMjo6U2VjdXJpdHlHcm91cDo6SWQgb3IgQVdTOjpFQzI6OlZQQzo6SWQuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWVcbiAgICogUGFyYW1ldGVycyBpbiB0aGUgQVdTIENsb3VkRm9ybWF0aW9uIFVzZXIgR3VpZGUuXG4gICAqIEBwYXJhbSBhdHRyaWJ1dGUgVGhlIG5hbWUgb2YgYW4gYXR0cmlidXRlIGZyb20gd2hpY2ggeW91IHdhbnQgdG8gcmV0cmlldmUgYVxuICAgKiB2YWx1ZS4gRm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgYXR0cmlidXRlcywgc2VlIFN1cHBvcnRlZCBBdHRyaWJ1dGVzLlxuICAgKiBAcmV0dXJucyBhIHRva2VuIHJlcHJlc2VudGVkIGFzIGEgc3RyaW5nIGFycmF5XG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHZhbHVlT2ZBbGwocGFyYW1ldGVyVHlwZTogc3RyaW5nLCBhdHRyaWJ1dGU6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gVG9rZW4uYXNMaXN0KG5ldyBGblZhbHVlT2ZBbGwocGFyYW1ldGVyVHlwZSwgYXR0cmlidXRlKSk7XG4gIH1cblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKCkgeyB9XG59XG5cbi8qKlxuICogQmFzZSBjbGFzcyBmb3IgdG9rZW5zIHRoYXQgcmVwcmVzZW50IENsb3VkRm9ybWF0aW9uIGludHJpbnNpYyBmdW5jdGlvbnMuXG4gKi9cbmNsYXNzIEZuQmFzZSBleHRlbmRzIEludHJpbnNpYyB7XG4gIGNvbnN0cnVjdG9yKG5hbWU6IHN0cmluZywgdmFsdWU6IGFueSkge1xuICAgIHN1cGVyKHsgW25hbWVdOiB2YWx1ZSB9KTtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBpbnRyaW5zaWMgZnVuY3Rpb24gYGBSZWZgYCByZXR1cm5zIHRoZSB2YWx1ZSBvZiB0aGUgc3BlY2lmaWVkIHBhcmFtZXRlciBvciByZXNvdXJjZS5cbiAqIFdoZW4geW91IHNwZWNpZnkgYSBwYXJhbWV0ZXIncyBsb2dpY2FsIG5hbWUsIGl0IHJldHVybnMgdGhlIHZhbHVlIG9mIHRoZSBwYXJhbWV0ZXIuXG4gKiBXaGVuIHlvdSBzcGVjaWZ5IGEgcmVzb3VyY2UncyBsb2dpY2FsIG5hbWUsIGl0IHJldHVybnMgYSB2YWx1ZSB0aGF0IHlvdSBjYW4gdHlwaWNhbGx5IHVzZSB0byByZWZlciB0byB0aGF0IHJlc291cmNlLCBzdWNoIGFzIGEgcGh5c2ljYWwgSUQuXG4gKi9cbmNsYXNzIEZuUmVmIGV4dGVuZHMgRm5CYXNlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYGBSZWZgYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGxvZ2ljYWxOYW1lIFRoZSBsb2dpY2FsIG5hbWUgb2YgYSBwYXJhbWV0ZXIvcmVzb3VyY2UgZm9yIHdoaWNoIHlvdSB3YW50IHRvIHJldHJpZXZlIGl0cyB2YWx1ZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGxvZ2ljYWxOYW1lOiBzdHJpbmcpIHtcbiAgICBzdXBlcignUmVmJywgbG9naWNhbE5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpGaW5kSW5NYXBgYCByZXR1cm5zIHRoZSB2YWx1ZSBjb3JyZXNwb25kaW5nIHRvIGtleXMgaW4gYSB0d28tbGV2ZWxcbiAqIG1hcCB0aGF0IGlzIGRlY2xhcmVkIGluIHRoZSBNYXBwaW5ncyBzZWN0aW9uLlxuICovXG5jbGFzcyBGbkZpbmRJbk1hcCBleHRlbmRzIEZuQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46OkZpbmRJbk1hcGBgIGZ1bmN0aW9uLlxuICAgKiBAcGFyYW0gbWFwTmFtZSBUaGUgbG9naWNhbCBuYW1lIG9mIGEgbWFwcGluZyBkZWNsYXJlZCBpbiB0aGUgTWFwcGluZ3Mgc2VjdGlvbiB0aGF0IGNvbnRhaW5zIHRoZSBrZXlzIGFuZCB2YWx1ZXMuXG4gICAqIEBwYXJhbSB0b3BMZXZlbEtleSBUaGUgdG9wLWxldmVsIGtleSBuYW1lLiBJdHMgdmFsdWUgaXMgYSBsaXN0IG9mIGtleS12YWx1ZSBwYWlycy5cbiAgICogQHBhcmFtIHNlY29uZExldmVsS2V5IFRoZSBzZWNvbmQtbGV2ZWwga2V5IG5hbWUsIHdoaWNoIGlzIHNldCB0byBvbmUgb2YgdGhlIGtleXMgZnJvbSB0aGUgbGlzdCBhc3NpZ25lZCB0byBUb3BMZXZlbEtleS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKG1hcE5hbWU6IHN0cmluZywgdG9wTGV2ZWxLZXk6IGFueSwgc2Vjb25kTGV2ZWxLZXk6IGFueSkge1xuICAgIHN1cGVyKCdGbjo6RmluZEluTWFwJywgW21hcE5hbWUsIHRvcExldmVsS2V5LCBzZWNvbmRMZXZlbEtleV0pO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpUcmFuc2Zvcm1gYCBzcGVjaWZpZXMgYSBtYWNybyB0byBwZXJmb3JtIGN1c3RvbSBwcm9jZXNzaW5nIG9uIHBhcnQgb2YgYSBzdGFjayB0ZW1wbGF0ZS5cbiAqL1xuY2xhc3MgRm5UcmFuc2Zvcm0gZXh0ZW5kcyBGbkJhc2Uge1xuICAvKipcbiAgICogY3JlYXRlcyBhbiBgYEZuOjpUcmFuc2Zvcm1gYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIG1hY3JvTmFtZSBUaGUgbmFtZSBvZiB0aGUgbWFjcm8gdG8gYmUgaW52b2tlZFxuICAgKiBAcGFyYW0gcGFyYW1ldGVycyB0aGUgcGFyYW1ldGVycyB0byBwYXNzIHRvIGl0XG4gICAqL1xuICBjb25zdHJ1Y3RvcihtYWNyb05hbWU6IHN0cmluZywgcGFyYW1ldGVyczogeyBbbmFtZTogc3RyaW5nXTogYW55IH0pIHtcbiAgICBzdXBlcignRm46OlRyYW5zZm9ybScsIHsgTmFtZTogbWFjcm9OYW1lLCBQYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzIH0pO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGBgRm46OkdldEF0dGBgIGludHJpbnNpYyBmdW5jdGlvbiByZXR1cm5zIHRoZSB2YWx1ZSBvZiBhbiBhdHRyaWJ1dGUgZnJvbSBhIHJlc291cmNlIGluIHRoZSB0ZW1wbGF0ZS5cbiAqL1xuY2xhc3MgRm5HZXRBdHQgZXh0ZW5kcyBGbkJhc2Uge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIGBgRm46OkdldEF0dGBgIGZ1bmN0aW9uLlxuICAgKiBAcGFyYW0gbG9naWNhbE5hbWVPZlJlc291cmNlIFRoZSBsb2dpY2FsIG5hbWUgKGFsc28gY2FsbGVkIGxvZ2ljYWwgSUQpIG9mIHRoZSByZXNvdXJjZSB0aGF0IGNvbnRhaW5zIHRoZSBhdHRyaWJ1dGUgdGhhdCB5b3Ugd2FudC5cbiAgICogQHBhcmFtIGF0dHJpYnV0ZU5hbWUgVGhlIG5hbWUgb2YgdGhlIHJlc291cmNlLXNwZWNpZmljIGF0dHJpYnV0ZSB3aG9zZSB2YWx1ZSB5b3Ugd2FudC4gU2VlIHRoZSByZXNvdXJjZSdzIHJlZmVyZW5jZSBwYWdlIGZvciBkZXRhaWxzIGFib3V0IHRoZSBhdHRyaWJ1dGVzIGF2YWlsYWJsZSBmb3IgdGhhdCByZXNvdXJjZSB0eXBlLlxuICAgKi9cbiAgY29uc3RydWN0b3IobG9naWNhbE5hbWVPZlJlc291cmNlOiBzdHJpbmcsIGF0dHJpYnV0ZU5hbWU6IHN0cmluZykge1xuICAgIHN1cGVyKCdGbjo6R2V0QXR0JywgW2xvZ2ljYWxOYW1lT2ZSZXNvdXJjZSwgYXR0cmlidXRlTmFtZV0pO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpHZXRBWnNgYCByZXR1cm5zIGFuIGFycmF5IHRoYXQgbGlzdHMgQXZhaWxhYmlsaXR5IFpvbmVzIGZvciBhXG4gKiBzcGVjaWZpZWQgcmVnaW9uLiBCZWNhdXNlIGN1c3RvbWVycyBoYXZlIGFjY2VzcyB0byBkaWZmZXJlbnQgQXZhaWxhYmlsaXR5IFpvbmVzLCB0aGUgaW50cmluc2ljXG4gKiBmdW5jdGlvbiBgYEZuOjpHZXRBWnNgYCBlbmFibGVzIHRlbXBsYXRlIGF1dGhvcnMgdG8gd3JpdGUgdGVtcGxhdGVzIHRoYXQgYWRhcHQgdG8gdGhlIGNhbGxpbmdcbiAqIHVzZXIncyBhY2Nlc3MuIFRoYXQgd2F5IHlvdSBkb24ndCBoYXZlIHRvIGhhcmQtY29kZSBhIGZ1bGwgbGlzdCBvZiBBdmFpbGFiaWxpdHkgWm9uZXMgZm9yIGFcbiAqIHNwZWNpZmllZCByZWdpb24uXG4gKi9cbmNsYXNzIEZuR2V0QVpzIGV4dGVuZHMgRm5CYXNlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYGBGbjo6R2V0QVpzYGAgZnVuY3Rpb24uXG4gICAqIEBwYXJhbSByZWdpb24gVGhlIG5hbWUgb2YgdGhlIHJlZ2lvbiBmb3Igd2hpY2ggeW91IHdhbnQgdG8gZ2V0IHRoZSBBdmFpbGFiaWxpdHkgWm9uZXMuXG4gICAqICAgICAgICAgWW91IGNhbiB1c2UgdGhlIEFXUzo6UmVnaW9uIHBzZXVkbyBwYXJhbWV0ZXIgdG8gc3BlY2lmeSB0aGUgcmVnaW9uIGluXG4gICAqICAgICAgICAgd2hpY2ggdGhlIHN0YWNrIGlzIGNyZWF0ZWQuIFNwZWNpZnlpbmcgYW4gZW1wdHkgc3RyaW5nIGlzIGVxdWl2YWxlbnQgdG9cbiAgICogICAgICAgICBzcGVjaWZ5aW5nIEFXUzo6UmVnaW9uLlxuICAgKi9cbiAgY29uc3RydWN0b3IocmVnaW9uPzogc3RyaW5nKSB7XG4gICAgc3VwZXIoJ0ZuOjpHZXRBWnMnLCByZWdpb24gfHwgJycpO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpJbXBvcnRWYWx1ZWBgIHJldHVybnMgdGhlIHZhbHVlIG9mIGFuIG91dHB1dCBleHBvcnRlZCBieSBhbm90aGVyIHN0YWNrLlxuICogWW91IHR5cGljYWxseSB1c2UgdGhpcyBmdW5jdGlvbiB0byBjcmVhdGUgY3Jvc3Mtc3RhY2sgcmVmZXJlbmNlcy4gSW4gdGhlIGZvbGxvd2luZyBleGFtcGxlXG4gKiB0ZW1wbGF0ZSBzbmlwcGV0cywgU3RhY2sgQSBleHBvcnRzIFZQQyBzZWN1cml0eSBncm91cCB2YWx1ZXMgYW5kIFN0YWNrIEIgaW1wb3J0cyB0aGVtLlxuICovXG5jbGFzcyBGbkltcG9ydFZhbHVlIGV4dGVuZHMgRm5CYXNlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYGBGbjo6SW1wb3J0VmFsdWVgYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIHNoYXJlZFZhbHVlVG9JbXBvcnQgVGhlIHN0YWNrIG91dHB1dCB2YWx1ZSB0aGF0IHlvdSB3YW50IHRvIGltcG9ydC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHNoYXJlZFZhbHVlVG9JbXBvcnQ6IHN0cmluZykge1xuICAgIHN1cGVyKCdGbjo6SW1wb3J0VmFsdWUnLCBzaGFyZWRWYWx1ZVRvSW1wb3J0KTtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBpbnRyaW5zaWMgZnVuY3Rpb24gYGBGbjo6U2VsZWN0YGAgcmV0dXJucyBhIHNpbmdsZSBvYmplY3QgZnJvbSBhIGxpc3Qgb2Ygb2JqZWN0cyBieSBpbmRleC5cbiAqL1xuY2xhc3MgRm5TZWxlY3QgZXh0ZW5kcyBGbkJhc2Uge1xuICAvKipcbiAgICogQ3JlYXRlcyBhbiBgYEZuOjpTZWxlY3RgYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGluZGV4IFRoZSBpbmRleCBvZiB0aGUgb2JqZWN0IHRvIHJldHJpZXZlLiBUaGlzIG11c3QgYmUgYSB2YWx1ZSBmcm9tIHplcm8gdG8gTi0xLCB3aGVyZSBOIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiB0aGUgYXJyYXkuXG4gICAqIEBwYXJhbSBhcnJheSBUaGUgbGlzdCBvZiBvYmplY3RzIHRvIHNlbGVjdCBmcm9tLiBUaGlzIGxpc3QgbXVzdCBub3QgYmUgbnVsbCwgbm9yIGNhbiBpdCBoYXZlIG51bGwgZW50cmllcy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGluZGV4OiBudW1iZXIsIGFycmF5OiBhbnkpIHtcbiAgICBzdXBlcignRm46OlNlbGVjdCcsIFtpbmRleCwgYXJyYXldKTtcbiAgfVxufVxuXG4vKipcbiAqIFRvIHNwbGl0IGEgc3RyaW5nIGludG8gYSBsaXN0IG9mIHN0cmluZyB2YWx1ZXMgc28gdGhhdCB5b3UgY2FuIHNlbGVjdCBhbiBlbGVtZW50IGZyb20gdGhlXG4gKiByZXN1bHRpbmcgc3RyaW5nIGxpc3QsIHVzZSB0aGUgYGBGbjo6U3BsaXRgYCBpbnRyaW5zaWMgZnVuY3Rpb24uIFNwZWNpZnkgdGhlIGxvY2F0aW9uIG9mIHNwbGl0c1xuICogd2l0aCBhIGRlbGltaXRlciwgc3VjaCBhcyAsIChhIGNvbW1hKS4gQWZ0ZXIgeW91IHNwbGl0IGEgc3RyaW5nLCB1c2UgdGhlIGBgRm46OlNlbGVjdGBgIGZ1bmN0aW9uXG4gKiB0byBwaWNrIGEgc3BlY2lmaWMgZWxlbWVudC5cbiAqL1xuY2xhc3MgRm5TcGxpdCBleHRlbmRzIEZuQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGUgYW4gYGBGbjo6U3BsaXRgYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGRlbGltaXRlciBBIHN0cmluZyB2YWx1ZSB0aGF0IGRldGVybWluZXMgd2hlcmUgdGhlIHNvdXJjZSBzdHJpbmcgaXMgZGl2aWRlZC5cbiAgICogQHBhcmFtIHNvdXJjZSBUaGUgc3RyaW5nIHZhbHVlIHRoYXQgeW91IHdhbnQgdG8gc3BsaXQuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihkZWxpbWl0ZXI6IHN0cmluZywgc291cmNlOiBhbnkpIHtcbiAgICBzdXBlcignRm46OlNwbGl0JywgW2RlbGltaXRlciwgc291cmNlXSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgaW50cmluc2ljIGZ1bmN0aW9uIGBgRm46OlN1YmBgIHN1YnN0aXR1dGVzIHZhcmlhYmxlcyBpbiBhbiBpbnB1dCBzdHJpbmcgd2l0aCB2YWx1ZXMgdGhhdFxuICogeW91IHNwZWNpZnkuIEluIHlvdXIgdGVtcGxhdGVzLCB5b3UgY2FuIHVzZSB0aGlzIGZ1bmN0aW9uIHRvIGNvbnN0cnVjdCBjb21tYW5kcyBvciBvdXRwdXRzXG4gKiB0aGF0IGluY2x1ZGUgdmFsdWVzIHRoYXQgYXJlbid0IGF2YWlsYWJsZSB1bnRpbCB5b3UgY3JlYXRlIG9yIHVwZGF0ZSBhIHN0YWNrLlxuICovXG5jbGFzcyBGblN1YiBleHRlbmRzIEZuQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46OlN1YmBgIGZ1bmN0aW9uLlxuICAgKiBAcGFyYW0gYm9keSBBIHN0cmluZyB3aXRoIHZhcmlhYmxlcyB0aGF0IEFXUyBDbG91ZEZvcm1hdGlvbiBzdWJzdGl0dXRlcyB3aXRoIHRoZWlyXG4gICAqICAgICAgIGFzc29jaWF0ZWQgdmFsdWVzIGF0IHJ1bnRpbWUuIFdyaXRlIHZhcmlhYmxlcyBhcyAke015VmFyTmFtZX0uIFZhcmlhYmxlc1xuICAgKiAgICAgICBjYW4gYmUgdGVtcGxhdGUgcGFyYW1ldGVyIG5hbWVzLCByZXNvdXJjZSBsb2dpY2FsIElEcywgcmVzb3VyY2UgYXR0cmlidXRlcyxcbiAgICogICAgICAgb3IgYSB2YXJpYWJsZSBpbiBhIGtleS12YWx1ZSBtYXAuIElmIHlvdSBzcGVjaWZ5IG9ubHkgdGVtcGxhdGUgcGFyYW1ldGVyIG5hbWVzLFxuICAgKiAgICAgICByZXNvdXJjZSBsb2dpY2FsIElEcywgYW5kIHJlc291cmNlIGF0dHJpYnV0ZXMsIGRvbid0IHNwZWNpZnkgYSBrZXktdmFsdWUgbWFwLlxuICAgKiBAcGFyYW0gdmFyaWFibGVzIFRoZSBuYW1lIG9mIGEgdmFyaWFibGUgdGhhdCB5b3UgaW5jbHVkZWQgaW4gdGhlIFN0cmluZyBwYXJhbWV0ZXIuXG4gICAqICAgICAgICAgIFRoZSB2YWx1ZSB0aGF0IEFXUyBDbG91ZEZvcm1hdGlvbiBzdWJzdGl0dXRlcyBmb3IgdGhlIGFzc29jaWF0ZWQgdmFyaWFibGUgbmFtZSBhdCBydW50aW1lLlxuICAgKi9cbiAgY29uc3RydWN0b3IoYm9keTogc3RyaW5nLCB2YXJpYWJsZXM/OiB7IFtrZXk6IHN0cmluZ106IGFueSB9KSB7XG4gICAgc3VwZXIoJ0ZuOjpTdWInLCB2YXJpYWJsZXMgPyBbYm9keSwgdmFyaWFibGVzXSA6IGJvZHkpO1xuICB9XG59XG5cbi8qKlxuICogVGhlIGludHJpbnNpYyBmdW5jdGlvbiBgYEZuOjpCYXNlNjRgYCByZXR1cm5zIHRoZSBCYXNlNjQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHN0cmluZy5cbiAqIFRoaXMgZnVuY3Rpb24gaXMgdHlwaWNhbGx5IHVzZWQgdG8gcGFzcyBlbmNvZGVkIGRhdGEgdG8gQW1hem9uIEVDMiBpbnN0YW5jZXMgYnkgd2F5IG9mXG4gKiB0aGUgVXNlckRhdGEgcHJvcGVydHkuXG4gKi9cbmNsYXNzIEZuQmFzZTY0IGV4dGVuZHMgRm5CYXNlIHtcblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBgYEZuOjpCYXNlNjRgYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGRhdGEgVGhlIHN0cmluZyB2YWx1ZSB5b3Ugd2FudCB0byBjb252ZXJ0IHRvIEJhc2U2NC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGRhdGE6IGFueSkge1xuICAgIHN1cGVyKCdGbjo6QmFzZTY0JywgZGF0YSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgaW50cmluc2ljIGZ1bmN0aW9uIGBgRm46OkNpZHJgYCByZXR1cm5zIHRoZSBzcGVjaWZpZWQgQ2lkciBhZGRyZXNzIGJsb2NrLlxuICovXG5jbGFzcyBGbkNpZHIgZXh0ZW5kcyBGbkJhc2Uge1xuICAvKipcbiAgICogQ3JlYXRlcyBhbiBgYEZuOjpDaWRyYGAgZnVuY3Rpb24uXG4gICAqIEBwYXJhbSBpcEJsb2NrICBUaGUgdXNlci1zcGVjaWZpZWQgZGVmYXVsdCBDaWRyIGFkZHJlc3MgYmxvY2suXG4gICAqIEBwYXJhbSBjb3VudCAgVGhlIG51bWJlciBvZiBzdWJuZXRzJyBDaWRyIGJsb2NrIHdhbnRlZC4gQ291bnQgY2FuIGJlIDEgdG8gMjU2LlxuICAgKiBAcGFyYW0gc2l6ZU1hc2sgVGhlIGRpZ2l0IGNvdmVyZWQgaW4gdGhlIHN1Ym5ldC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGlwQmxvY2s6IGFueSwgY291bnQ6IGFueSwgc2l6ZU1hc2s/OiBhbnkpIHtcbiAgICBpZiAoY291bnQgPCAxIHx8IGNvdW50ID4gMjU2KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZuOjpDaWRyJ3MgY291bnQgYXR0cmlidXRlIG11c3QgYmUgYmV0d2VuIDEgYW5kIDI1NiwgJHtjb3VudH0gd2FzIHByb3ZpZGVkLmApO1xuICAgIH1cbiAgICBzdXBlcignRm46OkNpZHInLCBbaXBCbG9jaywgY291bnQsIHNpemVNYXNrXSk7XG4gIH1cbn1cblxuY2xhc3MgRm5Db25kaXRpb25CYXNlIGV4dGVuZHMgSW50cmluc2ljIGltcGxlbWVudHMgSUNmblJ1bGVDb25kaXRpb25FeHByZXNzaW9uIHtcbiAgcmVhZG9ubHkgZGlzYW1iaWd1YXRvciA9IHRydWU7XG4gIGNvbnN0cnVjdG9yKHR5cGU6IHN0cmluZywgdmFsdWU6IGFueSkge1xuICAgIHN1cGVyKHsgW3R5cGVdOiB2YWx1ZSB9KTtcbiAgfVxufVxuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBhbGwgdGhlIHNwZWNpZmllZCBjb25kaXRpb25zIGV2YWx1YXRlIHRvIHRydWUsIG9yIHJldHVybnMgZmFsc2UgaWYgYW55IG9uZVxuICogIG9mIHRoZSBjb25kaXRpb25zIGV2YWx1YXRlcyB0byBmYWxzZS4gYGBGbjo6QW5kYGAgYWN0cyBhcyBhbiBBTkQgb3BlcmF0b3IuIFRoZSBtaW5pbXVtIG51bWJlciBvZlxuICogY29uZGl0aW9ucyB0aGF0IHlvdSBjYW4gaW5jbHVkZSBpcyAyLCBhbmQgdGhlIG1heGltdW0gaXMgMTAuXG4gKi9cbmNsYXNzIEZuQW5kIGV4dGVuZHMgRm5Db25kaXRpb25CYXNlIHtcbiAgY29uc3RydWN0b3IoLi4uY29uZGl0aW9uOiBJQ2ZuQ29uZGl0aW9uRXhwcmVzc2lvbltdKSB7XG4gICAgc3VwZXIoJ0ZuOjpBbmQnLCBjb25kaXRpb24pO1xuICB9XG59XG5cbi8qKlxuICogQ29tcGFyZXMgaWYgdHdvIHZhbHVlcyBhcmUgZXF1YWwuIFJldHVybnMgdHJ1ZSBpZiB0aGUgdHdvIHZhbHVlcyBhcmUgZXF1YWwgb3IgZmFsc2VcbiAqIGlmIHRoZXkgYXJlbid0LlxuICovXG5jbGFzcyBGbkVxdWFscyBleHRlbmRzIEZuQ29uZGl0aW9uQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46OkVxdWFsc2BgIGNvbmRpdGlvbiBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGxocyBBIHZhbHVlIG9mIGFueSB0eXBlIHRoYXQgeW91IHdhbnQgdG8gY29tcGFyZS5cbiAgICogQHBhcmFtIHJocyBBIHZhbHVlIG9mIGFueSB0eXBlIHRoYXQgeW91IHdhbnQgdG8gY29tcGFyZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGxoczogYW55LCByaHM6IGFueSkge1xuICAgIHN1cGVyKCdGbjo6RXF1YWxzJywgW2xocywgcmhzXSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIG9uZSB2YWx1ZSBpZiB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbiBldmFsdWF0ZXMgdG8gdHJ1ZSBhbmQgYW5vdGhlciB2YWx1ZSBpZiB0aGVcbiAqIHNwZWNpZmllZCBjb25kaXRpb24gZXZhbHVhdGVzIHRvIGZhbHNlLiBDdXJyZW50bHksIEFXUyBDbG91ZEZvcm1hdGlvbiBzdXBwb3J0cyB0aGUgYGBGbjo6SWZgYFxuICogaW50cmluc2ljIGZ1bmN0aW9uIGluIHRoZSBtZXRhZGF0YSBhdHRyaWJ1dGUsIHVwZGF0ZSBwb2xpY3kgYXR0cmlidXRlLCBhbmQgcHJvcGVydHkgdmFsdWVzXG4gKiBpbiB0aGUgUmVzb3VyY2VzIHNlY3Rpb24gYW5kIE91dHB1dHMgc2VjdGlvbnMgb2YgYSB0ZW1wbGF0ZS4gWW91IGNhbiB1c2UgdGhlIEFXUzo6Tm9WYWx1ZVxuICogcHNldWRvIHBhcmFtZXRlciBhcyBhIHJldHVybiB2YWx1ZSB0byByZW1vdmUgdGhlIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkuXG4gKi9cbmNsYXNzIEZuSWYgZXh0ZW5kcyBGbkNvbmRpdGlvbkJhc2Uge1xuICAvKipcbiAgICogQ3JlYXRlcyBhbiBgYEZuOjpJZmBgIGNvbmRpdGlvbiBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGNvbmRpdGlvbiBBIHJlZmVyZW5jZSB0byBhIGNvbmRpdGlvbiBpbiB0aGUgQ29uZGl0aW9ucyBzZWN0aW9uLiBVc2UgdGhlIGNvbmRpdGlvbidzIG5hbWUgdG8gcmVmZXJlbmNlIGl0LlxuICAgKiBAcGFyYW0gdmFsdWVJZlRydWUgQSB2YWx1ZSB0byBiZSByZXR1cm5lZCBpZiB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbiBldmFsdWF0ZXMgdG8gdHJ1ZS5cbiAgICogQHBhcmFtIHZhbHVlSWZGYWxzZSBBIHZhbHVlIHRvIGJlIHJldHVybmVkIGlmIHRoZSBzcGVjaWZpZWQgY29uZGl0aW9uIGV2YWx1YXRlcyB0byBmYWxzZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGNvbmRpdGlvbjogc3RyaW5nLCB2YWx1ZUlmVHJ1ZTogYW55LCB2YWx1ZUlmRmFsc2U6IGFueSkge1xuICAgIHN1cGVyKCdGbjo6SWYnLCBbY29uZGl0aW9uLCB2YWx1ZUlmVHJ1ZSwgdmFsdWVJZkZhbHNlXSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgZm9yIGEgY29uZGl0aW9uIHRoYXQgZXZhbHVhdGVzIHRvIGZhbHNlIG9yIHJldHVybnMgZmFsc2UgZm9yIGEgY29uZGl0aW9uIHRoYXQgZXZhbHVhdGVzIHRvIHRydWUuXG4gKiBgYEZuOjpOb3RgYCBhY3RzIGFzIGEgTk9UIG9wZXJhdG9yLlxuICovXG5jbGFzcyBGbk5vdCBleHRlbmRzIEZuQ29uZGl0aW9uQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46Ok5vdGBgIGNvbmRpdGlvbiBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGNvbmRpdGlvbiBBIGNvbmRpdGlvbiBzdWNoIGFzIGBgRm46OkVxdWFsc2BgIHRoYXQgZXZhbHVhdGVzIHRvIHRydWUgb3IgZmFsc2UuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihjb25kaXRpb246IElDZm5Db25kaXRpb25FeHByZXNzaW9uKSB7XG4gICAgc3VwZXIoJ0ZuOjpOb3QnLCBbY29uZGl0aW9uXSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgYW55IG9uZSBvZiB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbnMgZXZhbHVhdGUgdG8gdHJ1ZSwgb3IgcmV0dXJucyBmYWxzZSBpZlxuICogYWxsIG9mIHRoZSBjb25kaXRpb25zIGV2YWx1YXRlcyB0byBmYWxzZS4gYGBGbjo6T3JgYCBhY3RzIGFzIGFuIE9SIG9wZXJhdG9yLiBUaGUgbWluaW11bSBudW1iZXJcbiAqIG9mIGNvbmRpdGlvbnMgdGhhdCB5b3UgY2FuIGluY2x1ZGUgaXMgMiwgYW5kIHRoZSBtYXhpbXVtIGlzIDEwLlxuICovXG5jbGFzcyBGbk9yIGV4dGVuZHMgRm5Db25kaXRpb25CYXNlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYGBGbjo6T3JgYCBjb25kaXRpb24gZnVuY3Rpb24uXG4gICAqIEBwYXJhbSBjb25kaXRpb24gQSBjb25kaXRpb24gdGhhdCBldmFsdWF0ZXMgdG8gdHJ1ZSBvciBmYWxzZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKC4uLmNvbmRpdGlvbjogSUNmbkNvbmRpdGlvbkV4cHJlc3Npb25bXSkge1xuICAgIHN1cGVyKCdGbjo6T3InLCBjb25kaXRpb24pO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIGEgc3BlY2lmaWVkIHN0cmluZyBtYXRjaGVzIGF0IGxlYXN0IG9uZSB2YWx1ZSBpbiBhIGxpc3Qgb2Ygc3RyaW5ncy5cbiAqL1xuY2xhc3MgRm5Db250YWlucyBleHRlbmRzIEZuQ29uZGl0aW9uQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46OkNvbnRhaW5zYGAgZnVuY3Rpb24uXG4gICAqIEBwYXJhbSBsaXN0T2ZTdHJpbmdzIEEgbGlzdCBvZiBzdHJpbmdzLCBzdWNoIGFzIFwiQVwiLCBcIkJcIiwgXCJDXCIuXG4gICAqIEBwYXJhbSB2YWx1ZSBBIHN0cmluZywgc3VjaCBhcyBcIkFcIiwgdGhhdCB5b3Ugd2FudCB0byBjb21wYXJlIGFnYWluc3QgYSBsaXN0IG9mIHN0cmluZ3MuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihsaXN0T2ZTdHJpbmdzOiBhbnksIHZhbHVlOiBzdHJpbmcpIHtcbiAgICBzdXBlcignRm46OkNvbnRhaW5zJywgW2xpc3RPZlN0cmluZ3MsIHZhbHVlXSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgYSBzcGVjaWZpZWQgc3RyaW5nIG1hdGNoZXMgYWxsIHZhbHVlcyBpbiBhIGxpc3QuXG4gKi9cbmNsYXNzIEZuRWFjaE1lbWJlckVxdWFscyBleHRlbmRzIEZuQ29uZGl0aW9uQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46OkVhY2hNZW1iZXJFcXVhbHNgYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGxpc3RPZlN0cmluZ3MgQSBsaXN0IG9mIHN0cmluZ3MsIHN1Y2ggYXMgXCJBXCIsIFwiQlwiLCBcIkNcIi5cbiAgICogQHBhcmFtIHZhbHVlIEEgc3RyaW5nLCBzdWNoIGFzIFwiQVwiLCB0aGF0IHlvdSB3YW50IHRvIGNvbXBhcmUgYWdhaW5zdCBhIGxpc3Qgb2Ygc3RyaW5ncy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGxpc3RPZlN0cmluZ3M6IGFueSwgdmFsdWU6IHN0cmluZykge1xuICAgIHN1cGVyKCdGbjo6RWFjaE1lbWJlckVxdWFscycsIFtsaXN0T2ZTdHJpbmdzLCB2YWx1ZV0pO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIGVhY2ggbWVtYmVyIGluIGEgbGlzdCBvZiBzdHJpbmdzIG1hdGNoZXMgYXQgbGVhc3Qgb25lIHZhbHVlIGluIGEgc2Vjb25kXG4gKiBsaXN0IG9mIHN0cmluZ3MuXG4gKi9cbmNsYXNzIEZuRWFjaE1lbWJlckluIGV4dGVuZHMgRm5Db25kaXRpb25CYXNlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYGBGbjo6RWFjaE1lbWJlckluYGAgZnVuY3Rpb24uXG4gICAqIEBwYXJhbSBzdHJpbmdzVG9DaGVjayBBIGxpc3Qgb2Ygc3RyaW5ncywgc3VjaCBhcyBcIkFcIiwgXCJCXCIsIFwiQ1wiLiBBV1MgQ2xvdWRGb3JtYXRpb24gY2hlY2tzIHdoZXRoZXIgZWFjaCBtZW1iZXIgaW4gdGhlIHN0cmluZ3NfdG9fY2hlY2sgcGFyYW1ldGVyIGlzIGluIHRoZSBzdHJpbmdzX3RvX21hdGNoIHBhcmFtZXRlci5cbiAgICogQHBhcmFtIHN0cmluZ3NUb01hdGNoIEEgbGlzdCBvZiBzdHJpbmdzLCBzdWNoIGFzIFwiQVwiLCBcIkJcIiwgXCJDXCIuIEVhY2ggbWVtYmVyIGluIHRoZSBzdHJpbmdzX3RvX21hdGNoIHBhcmFtZXRlciBpcyBjb21wYXJlZCBhZ2FpbnN0IHRoZSBtZW1iZXJzIG9mIHRoZSBzdHJpbmdzX3RvX2NoZWNrIHBhcmFtZXRlci5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHN0cmluZ3NUb0NoZWNrOiBzdHJpbmdbXSwgc3RyaW5nc1RvTWF0Y2g6IHN0cmluZ1tdKSB7XG4gICAgc3VwZXIoJ0ZuOjpFYWNoTWVtYmVySW4nLCBbc3RyaW5nc1RvQ2hlY2ssIHN0cmluZ3NUb01hdGNoXSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGFsbCB2YWx1ZXMgZm9yIGEgc3BlY2lmaWVkIHBhcmFtZXRlciB0eXBlLlxuICovXG5jbGFzcyBGblJlZkFsbCBleHRlbmRzIEZuQmFzZSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46OlJlZkFsbGBgIGZ1bmN0aW9uLlxuICAgKiBAcGFyYW0gcGFyYW1ldGVyVHlwZSBBbiBBV1Mtc3BlY2lmaWMgcGFyYW1ldGVyIHR5cGUsIHN1Y2ggYXMgQVdTOjpFQzI6OlNlY3VyaXR5R3JvdXA6OklkIG9yXG4gICAqICAgICAgICAgICAgQVdTOjpFQzI6OlZQQzo6SWQuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgUGFyYW1ldGVycyBpbiB0aGUgQVdTXG4gICAqICAgICAgICAgICAgQ2xvdWRGb3JtYXRpb24gVXNlciBHdWlkZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHBhcmFtZXRlclR5cGU6IHN0cmluZykge1xuICAgIHN1cGVyKCdGbjo6UmVmQWxsJywgcGFyYW1ldGVyVHlwZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGFuIGF0dHJpYnV0ZSB2YWx1ZSBvciBsaXN0IG9mIHZhbHVlcyBmb3IgYSBzcGVjaWZpYyBwYXJhbWV0ZXIgYW5kIGF0dHJpYnV0ZS5cbiAqL1xuY2xhc3MgRm5WYWx1ZU9mIGV4dGVuZHMgRm5CYXNlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYGBGbjo6VmFsdWVPZmBgIGZ1bmN0aW9uLlxuICAgKiBAcGFyYW0gcGFyYW1ldGVyT3JMb2dpY2FsSWQgVGhlIG5hbWUgb2YgYSBwYXJhbWV0ZXIgZm9yIHdoaWNoIHlvdSB3YW50IHRvIHJldHJpZXZlIGF0dHJpYnV0ZSB2YWx1ZXMuIFRoZSBwYXJhbWV0ZXIgbXVzdCBiZSBkZWNsYXJlZCBpbiB0aGUgUGFyYW1ldGVycyBzZWN0aW9uIG9mIHRoZSB0ZW1wbGF0ZS5cbiAgICogQHBhcmFtIGF0dHJpYnV0ZSBUaGUgbmFtZSBvZiBhbiBhdHRyaWJ1dGUgZnJvbSB3aGljaCB5b3Ugd2FudCB0byByZXRyaWV2ZSBhIHZhbHVlLlxuICAgKi9cbiAgY29uc3RydWN0b3IocGFyYW1ldGVyT3JMb2dpY2FsSWQ6IHN0cmluZywgYXR0cmlidXRlOiBzdHJpbmcpIHtcbiAgICBzdXBlcignRm46OlZhbHVlT2YnLCBbcGFyYW1ldGVyT3JMb2dpY2FsSWQsIGF0dHJpYnV0ZV0pO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJucyBhIGxpc3Qgb2YgYWxsIGF0dHJpYnV0ZSB2YWx1ZXMgZm9yIGEgZ2l2ZW4gcGFyYW1ldGVyIHR5cGUgYW5kIGF0dHJpYnV0ZS5cbiAqL1xuY2xhc3MgRm5WYWx1ZU9mQWxsIGV4dGVuZHMgRm5CYXNlIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gYGBGbjo6VmFsdWVPZkFsbGBgIGZ1bmN0aW9uLlxuICAgKiBAcGFyYW0gcGFyYW1ldGVyVHlwZSBBbiBBV1Mtc3BlY2lmaWMgcGFyYW1ldGVyIHR5cGUsIHN1Y2ggYXMgQVdTOjpFQzI6OlNlY3VyaXR5R3JvdXA6OklkIG9yIEFXUzo6RUMyOjpWUEM6OklkLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiwgc2VlIFBhcmFtZXRlcnMgaW4gdGhlIEFXUyBDbG91ZEZvcm1hdGlvbiBVc2VyIEd1aWRlLlxuICAgKiBAcGFyYW0gYXR0cmlidXRlIFRoZSBuYW1lIG9mIGFuIGF0dHJpYnV0ZSBmcm9tIHdoaWNoIHlvdSB3YW50IHRvIHJldHJpZXZlIGEgdmFsdWUuIEZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGF0dHJpYnV0ZXMsIHNlZSBTdXBwb3J0ZWQgQXR0cmlidXRlcy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHBhcmFtZXRlclR5cGU6IHN0cmluZywgYXR0cmlidXRlOiBzdHJpbmcpIHtcbiAgICBzdXBlcignRm46OlZhbHVlT2ZBbGwnLCBbcGFyYW1ldGVyVHlwZSwgYXR0cmlidXRlXSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgaW50cmluc2ljIGZ1bmN0aW9uIGBgRm46OkpvaW5gYCBhcHBlbmRzIGEgc2V0IG9mIHZhbHVlcyBpbnRvIGEgc2luZ2xlIHZhbHVlLCBzZXBhcmF0ZWQgYnlcbiAqIHRoZSBzcGVjaWZpZWQgZGVsaW1pdGVyLiBJZiBhIGRlbGltaXRlciBpcyB0aGUgZW1wdHkgc3RyaW5nLCB0aGUgc2V0IG9mIHZhbHVlcyBhcmUgY29uY2F0ZW5hdGVkXG4gKiB3aXRoIG5vIGRlbGltaXRlci5cbiAqL1xuY2xhc3MgRm5Kb2luIGltcGxlbWVudHMgSVJlc29sdmFibGUge1xuICBwdWJsaWMgcmVhZG9ubHkgY3JlYXRpb25TdGFjazogc3RyaW5nW107XG5cbiAgcHJpdmF0ZSByZWFkb25seSBkZWxpbWl0ZXI6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBsaXN0T2ZWYWx1ZXM6IGFueVtdO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGBgRm46OkpvaW5gYCBmdW5jdGlvbi5cbiAgICogQHBhcmFtIGRlbGltaXRlciBUaGUgdmFsdWUgeW91IHdhbnQgdG8gb2NjdXIgYmV0d2VlbiBmcmFnbWVudHMuIFRoZSBkZWxpbWl0ZXIgd2lsbCBvY2N1ciBiZXR3ZWVuIGZyYWdtZW50cyBvbmx5LlxuICAgKiAgICAgICAgICBJdCB3aWxsIG5vdCB0ZXJtaW5hdGUgdGhlIGZpbmFsIHZhbHVlLlxuICAgKiBAcGFyYW0gbGlzdE9mVmFsdWVzIFRoZSBsaXN0IG9mIHZhbHVlcyB5b3Ugd2FudCBjb21iaW5lZC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGRlbGltaXRlcjogc3RyaW5nLCBsaXN0T2ZWYWx1ZXM6IGFueVtdKSB7XG4gICAgaWYgKGxpc3RPZlZhbHVlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRm5Kb2luIHJlcXVpcmVzIGF0IGxlYXN0IG9uZSB2YWx1ZSB0byBiZSBwcm92aWRlZCcpO1xuICAgIH1cblxuICAgIHRoaXMuZGVsaW1pdGVyID0gZGVsaW1pdGVyO1xuICAgIHRoaXMubGlzdE9mVmFsdWVzID0gbGlzdE9mVmFsdWVzO1xuICAgIHRoaXMuY3JlYXRpb25TdGFjayA9IGNhcHR1cmVTdGFja1RyYWNlKCk7XG4gIH1cblxuICBwdWJsaWMgcmVzb2x2ZShjb250ZXh0OiBJUmVzb2x2ZUNvbnRleHQpOiBhbnkge1xuICAgIGlmIChUb2tlbi5pc1VucmVzb2x2ZWQodGhpcy5saXN0T2ZWYWx1ZXMpKSB7XG4gICAgICAvLyBUaGlzIGlzIGEgbGlzdCB0b2tlbiwgZG9uJ3QgdHJ5IHRvIGRvIHNtYXJ0IHRoaW5ncyB3aXRoIGl0LlxuICAgICAgcmV0dXJuIHsgJ0ZuOjpKb2luJzogW3RoaXMuZGVsaW1pdGVyLCB0aGlzLmxpc3RPZlZhbHVlc10gfTtcbiAgICB9XG4gICAgY29uc3QgcmVzb2x2ZWQgPSB0aGlzLnJlc29sdmVWYWx1ZXMoY29udGV4dCk7XG4gICAgaWYgKHJlc29sdmVkLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIHJlc29sdmVkWzBdO1xuICAgIH1cbiAgICByZXR1cm4geyAnRm46OkpvaW4nOiBbdGhpcy5kZWxpbWl0ZXIsIHJlc29sdmVkXSB9O1xuICB9XG5cbiAgcHVibGljIHRvU3RyaW5nKCkge1xuICAgIHJldHVybiBUb2tlbi5hc1N0cmluZyh0aGlzLCB7IGRpc3BsYXlIaW50OiAnRm46OkpvaW4nIH0pO1xuICB9XG5cbiAgcHVibGljIHRvSlNPTigpIHtcbiAgICByZXR1cm4gJzxGbjo6Sm9pbj4nO1xuICB9XG5cbiAgLyoqXG4gICAqIE9wdGltaXphdGlvbjogaWYgYW4gRm46OkpvaW4gaXMgbmVzdGVkIGluIGFub3RoZXIgb25lIGFuZCB0aGV5IHNoYXJlIHRoZSBzYW1lIGRlbGltaXRlciwgdGhlbiBmbGF0dGVuIGl0IHVwLiBBbHNvLFxuICAgKiBpZiB0d28gY29uY2F0ZW5hdGVkIGVsZW1lbnRzIGFyZSBsaXRlcmFsIHN0cmluZ3MgKG5vdCB0b2tlbnMpLCB0aGVuIHByZS1jb25jYXRlbmF0ZSB0aGVtIHdpdGggdGhlIGRlbGltaXRlciwgdG9cbiAgICogZ2VuZXJhdGUgc2hvcnRlciBvdXRwdXQuXG4gICAqL1xuICBwcml2YXRlIHJlc29sdmVWYWx1ZXMoY29udGV4dDogSVJlc29sdmVDb250ZXh0KSB7XG4gICAgY29uc3QgcmVzb2x2ZWRWYWx1ZXMgPSB0aGlzLmxpc3RPZlZhbHVlcy5tYXAoeCA9PiBSZWZlcmVuY2UuaXNSZWZlcmVuY2UoeCkgPyB4IDogY29udGV4dC5yZXNvbHZlKHgpKTtcbiAgICByZXR1cm4gbWluaW1hbENsb3VkRm9ybWF0aW9uSm9pbih0aGlzLmRlbGltaXRlciwgcmVzb2x2ZWRWYWx1ZXMpO1xuICB9XG59XG5cbmZ1bmN0aW9uIF9pbkdyb3Vwc09mPFQ+KGFycmF5OiBUW10sIG1heEdyb3VwOiBudW1iZXIpOiBUW11bXSB7XG4gIGNvbnN0IHJlc3VsdCA9IG5ldyBBcnJheTxUW10+KCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyYXkubGVuZ3RoOyBpICs9IG1heEdyb3VwKSB7XG4gICAgcmVzdWx0LnB1c2goYXJyYXkuc2xpY2UoaSwgaSArIG1heEdyb3VwKSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gcmFuZ2UobjogbnVtYmVyKTogbnVtYmVyW10ge1xuICBjb25zdCByZXQgPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICByZXQucHVzaChpKTtcbiAgfVxuICByZXR1cm4gcmV0O1xufSJdfQ==
\No newline at end of file