@aws-cdk/aws-lambda
Version:
The CDK Construct Library for AWS::Lambda
431 lines • 62.5 kB
JavaScript
"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.QualifiedFunctionBase = exports.FunctionBase = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const crypto_1 = require("crypto");
const iam = require("@aws-cdk/aws-iam");
const core_1 = require("@aws-cdk/core");
const event_invoke_config_1 = require("./event-invoke-config");
const event_source_mapping_1 = require("./event-source-mapping");
const function_url_1 = require("./function-url");
const lambda_generated_1 = require("./lambda.generated");
const util_1 = require("./util");
class FunctionBase extends core_1.Resource {
constructor() {
super(...arguments);
/**
* Flag to delay adding a warning message until current version is invoked.
* @internal
*/
this._warnIfCurrentVersionCalled = false;
/**
* Mapping of invocation principals to grants. Used to de-dupe `grantInvoke()` calls.
* @internal
*/
this._invocationGrants = {};
/**
* Mapping of fucntion URL invocation principals to grants. Used to de-dupe `grantInvokeUrl()` calls.
* @internal
*/
this._functionUrlInvocationGrants = {};
}
/**
* A warning will be added to functions under the following conditions:
* - permissions that include `lambda:InvokeFunction` are added to the unqualified function.
* - function.currentVersion is invoked before or after the permission is created.
*
* This applies only to permissions on Lambda functions, not versions or aliases.
* This function is overridden as a noOp for QualifiedFunctionBase.
*/
considerWarningOnInvokeFunctionPermissions(scope, action) {
const affectedPermissions = ['lambda:InvokeFunction', 'lambda:*', 'lambda:Invoke*'];
if (affectedPermissions.includes(action)) {
if (scope.node.tryFindChild('CurrentVersion')) {
this.warnInvokeFunctionPermissions(scope);
}
else {
this._warnIfCurrentVersionCalled = true;
}
}
}
warnInvokeFunctionPermissions(scope) {
core_1.Annotations.of(scope).addWarning([
"AWS Lambda has changed their authorization strategy, which may cause client invocations using the 'Qualifier' parameter of the lambda function to fail with Access Denied errors.",
"If you are using a lambda Version or Alias, make sure to call 'grantInvoke' or 'addPermission' on the Version or Alias, not the underlying Function",
'See: https://github.com/aws/aws-cdk/issues/19273',
].join('\n'));
}
/**
* Adds a permission to the Lambda resource policy.
* @param id The id for the permission construct
* @param permission The permission to grant to this Lambda function. @see Permission for details.
*/
addPermission(id, permission) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_lambda_Permission(permission);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addPermission);
}
throw error;
}
if (!this.canCreatePermissions) {
// FIXME: @deprecated(v2) - throw an error if calling `addPermission` on a resource that doesn't support it.
return;
}
const principal = this.parsePermissionPrincipal(permission.principal);
const { sourceAccount, sourceArn } = this.parseConditions(permission.principal) ?? {};
const action = permission.action ?? 'lambda:InvokeFunction';
const scope = permission.scope ?? this;
this.considerWarningOnInvokeFunctionPermissions(scope, action);
new lambda_generated_1.CfnPermission(scope, id, {
action,
principal,
functionName: this.functionArn,
eventSourceToken: permission.eventSourceToken,
sourceAccount: permission.sourceAccount ?? sourceAccount,
sourceArn: permission.sourceArn ?? sourceArn,
functionUrlAuthType: permission.functionUrlAuthType,
});
}
/**
* Adds a statement to the IAM role assumed by the instance.
*/
addToRolePolicy(statement) {
if (!this.role) {
return;
}
this.role.addToPrincipalPolicy(statement);
}
/**
* Access the Connections object
*
* Will fail if not a VPC-enabled Lambda Function
*/
get connections() {
if (!this._connections) {
// eslint-disable-next-line max-len
throw new Error('Only VPC-associated Lambda Functions have security groups to manage. Supply the "vpc" parameter when creating the Lambda, or "securityGroupId" when importing it.');
}
return this._connections;
}
get latestVersion() {
if (!this._latestVersion) {
this._latestVersion = new LatestVersion(this);
}
return this._latestVersion;
}
/**
* Whether or not this Lambda function was bound to a VPC
*
* If this is is `false`, trying to access the `connections` object will fail.
*/
get isBoundToVpc() {
return !!this._connections;
}
addEventSourceMapping(id, options) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_lambda_EventSourceMappingOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addEventSourceMapping);
}
throw error;
}
return new event_source_mapping_1.EventSourceMapping(this, id, {
target: this,
...options,
});
}
/**
* Grant the given identity permissions to invoke this Lambda
*/
grantInvoke(grantee) {
const hash = crypto_1.createHash('sha256')
.update(JSON.stringify({
principal: grantee.grantPrincipal.toString(),
conditions: grantee.grantPrincipal.policyFragment.conditions,
}), 'utf8')
.digest('base64');
const identifier = `Invoke${hash}`;
// Memoize the result so subsequent grantInvoke() calls are idempotent
let grant = this._invocationGrants[identifier];
if (!grant) {
grant = this.grant(grantee, identifier, 'lambda:InvokeFunction', this.resourceArnsForGrantInvoke);
this._invocationGrants[identifier] = grant;
}
return grant;
}
/**
* Grant the given identity permissions to invoke this Lambda Function URL
*/
grantInvokeUrl(grantee) {
const identifier = `InvokeFunctionUrl${grantee.grantPrincipal}`; // calls the .toString() of the principal
// Memoize the result so subsequent grantInvoke() calls are idempotent
let grant = this._functionUrlInvocationGrants[identifier];
if (!grant) {
grant = this.grant(grantee, identifier, 'lambda:InvokeFunctionUrl', [this.functionArn], {
functionUrlAuthType: function_url_1.FunctionUrlAuthType.AWS_IAM,
});
this._functionUrlInvocationGrants[identifier] = grant;
}
return grant;
}
addEventSource(source) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_lambda_IEventSource(source);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addEventSource);
}
throw error;
}
source.bind(this);
}
configureAsyncInvoke(options) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_lambda_EventInvokeConfigOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.configureAsyncInvoke);
}
throw error;
}
if (this.node.tryFindChild('EventInvokeConfig') !== undefined) {
throw new Error(`An EventInvokeConfig has already been configured for the function at ${this.node.path}`);
}
new event_invoke_config_1.EventInvokeConfig(this, 'EventInvokeConfig', {
function: this,
...options,
});
}
addFunctionUrl(options) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_lambda_FunctionUrlOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addFunctionUrl);
}
throw error;
}
return new function_url_1.FunctionUrl(this, 'FunctionUrl', {
function: this,
...options,
});
}
/**
* Returns the construct tree node that corresponds to the lambda function.
* For use internally for constructs, when the tree is set up in non-standard ways. Ex: SingletonFunction.
* @internal
*/
_functionNode() {
return this.node;
}
/**
* Given the function arn, check if the account id matches this account
*
* Function ARNs look like this:
*
* arn:aws:lambda:region:account-id:function:function-name
*
* ..which means that in order to extract the `account-id` component from the ARN, we can
* split the ARN using ":" and select the component in index 4.
*
* @returns true if account id of function matches the account specified on the stack, false otherwise.
*
* @internal
*/
_isStackAccount() {
if (core_1.Token.isUnresolved(this.stack.account) || core_1.Token.isUnresolved(this.functionArn)) {
return false;
}
return this.stack.splitArn(this.functionArn, core_1.ArnFormat.SLASH_RESOURCE_NAME).account === this.stack.account;
}
grant(grantee, identifier, action, resourceArns, permissionOverrides) {
const grant = iam.Grant.addToPrincipalOrResource({
grantee,
actions: [action],
resourceArns,
// Fake resource-like object on which to call addToResourcePolicy(), which actually
// calls addPermission()
resource: {
addToResourcePolicy: (_statement) => {
// Couldn't add permissions to the principal, so add them locally.
this.addPermission(identifier, {
principal: grantee.grantPrincipal,
action: action,
...permissionOverrides,
});
const permissionNode = this._functionNode().tryFindChild(identifier);
if (!permissionNode && !this._skipPermissions) {
throw new Error('Cannot modify permission to lambda function. Function is either imported or $LATEST version.\n'
+ 'If the function is imported from the same account use `fromFunctionAttributes()` API with the `sameEnvironment` flag.\n'
+ 'If the function is imported from a different account and already has the correct permissions use `fromFunctionAttributes()` API with the `skipPermissions` flag.');
}
return { statementAdded: true, policyDependable: permissionNode };
},
node: this.node,
stack: this.stack,
env: this.env,
applyRemovalPolicy: this.applyRemovalPolicy,
},
});
return grant;
}
/**
* Translate IPrincipal to something we can pass to AWS::Lambda::Permissions
*
* Do some nasty things because `Permission` supports a subset of what the
* full IAM principal language supports, and we may not be able to parse strings
* outright because they may be tokens.
*
* Try to recognize some specific Principal classes first, then try a generic
* fallback.
*/
parsePermissionPrincipal(principal) {
// Try some specific common classes first.
// use duck-typing, not instance of
// @deprecated: after v2, we can change these to 'instanceof'
if ('wrapped' in principal) {
// eslint-disable-next-line dot-notation
principal = principal['wrapped'];
}
if ('accountId' in principal) {
return principal.accountId;
}
if ('service' in principal) {
return principal.service;
}
if ('arn' in principal) {
return principal.arn;
}
// Try a best-effort approach to support simple principals that are not any of the predefined
// classes, but are simple enough that they will fit into the Permission model. Main target
// here: imported Roles, Users, Groups.
//
// The principal cannot have conditions and must have a single { AWS: [arn] } entry.
const json = principal.policyFragment.principalJson;
if (Object.keys(principal.policyFragment.conditions).length === 0 && json.AWS) {
if (typeof json.AWS === 'string') {
return json.AWS;
}
if (Array.isArray(json.AWS) && json.AWS.length === 1 && typeof json.AWS[0] === 'string') {
return json.AWS[0];
}
}
throw new Error(`Invalid principal type for Lambda permission statement: ${principal.constructor.name}. ` +
'Supported: AccountPrincipal, ArnPrincipal, ServicePrincipal');
}
parseConditions(principal) {
if (this.isPrincipalWithConditions(principal)) {
const conditions = principal.policyFragment.conditions;
const conditionPairs = util_1.flatMap(Object.entries(conditions), ([operator, conditionObjs]) => Object.keys(conditionObjs).map(key => { return { operator, key }; }));
const supportedPrincipalConditions = [{ operator: 'ArnLike', key: 'aws:SourceArn' }, { operator: 'StringEquals', key: 'aws:SourceAccount' }];
const unsupportedConditions = conditionPairs.filter((condition) => !supportedPrincipalConditions.some((supportedCondition) => supportedCondition.operator === condition.operator && supportedCondition.key === condition.key));
if (unsupportedConditions.length == 0) {
return {
sourceAccount: conditions.StringEquals['aws:SourceAccount'],
sourceArn: conditions.ArnLike['aws:SourceArn'],
};
}
else {
throw new Error(`PrincipalWithConditions had unsupported conditions for Lambda permission statement: ${JSON.stringify(unsupportedConditions)}. ` +
`Supported operator/condition pairs: ${JSON.stringify(supportedPrincipalConditions)}`);
}
}
else {
return null;
}
}
isPrincipalWithConditions(principal) {
return 'conditions' in principal;
}
}
exports.FunctionBase = FunctionBase;
_a = JSII_RTTI_SYMBOL_1;
FunctionBase[_a] = { fqn: "@aws-cdk/aws-lambda.FunctionBase", version: "1.204.0" };
class QualifiedFunctionBase extends FunctionBase {
constructor() {
super(...arguments);
this.permissionsNode = this.node;
}
get latestVersion() {
return this.lambda.latestVersion;
}
get resourceArnsForGrantInvoke() {
return [this.functionArn];
}
configureAsyncInvoke(options) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_lambda_EventInvokeConfigOptions(options);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.configureAsyncInvoke);
}
throw error;
}
if (this.node.tryFindChild('EventInvokeConfig') !== undefined) {
throw new Error(`An EventInvokeConfig has already been configured for the qualified function at ${this.node.path}`);
}
new event_invoke_config_1.EventInvokeConfig(this, 'EventInvokeConfig', {
function: this.lambda,
qualifier: this.qualifier,
...options,
});
}
considerWarningOnInvokeFunctionPermissions(_scope, _action) {
// noOp
return;
}
}
exports.QualifiedFunctionBase = QualifiedFunctionBase;
_b = JSII_RTTI_SYMBOL_1;
QualifiedFunctionBase[_b] = { fqn: "@aws-cdk/aws-lambda.QualifiedFunctionBase", version: "1.204.0" };
/**
* The $LATEST version of a function, useful when attempting to create aliases.
*/
class LatestVersion extends FunctionBase {
constructor(lambda) {
super(lambda, '$LATEST');
this.version = '$LATEST';
this.permissionsNode = this.node;
this.canCreatePermissions = false;
this.lambda = lambda;
}
get functionArn() {
return `${this.lambda.functionArn}:${this.version}`;
}
get functionName() {
return `${this.lambda.functionName}:${this.version}`;
}
get architecture() {
return this.lambda.architecture;
}
get grantPrincipal() {
return this.lambda.grantPrincipal;
}
get latestVersion() {
return this;
}
get role() {
return this.lambda.role;
}
get edgeArn() {
throw new Error('$LATEST function version cannot be used for Lambda@Edge');
}
get resourceArnsForGrantInvoke() {
return [this.functionArn];
}
addAlias(aliasName, options = {}) {
return util_1.addAlias(this, this, aliasName, options);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb24tYmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImZ1bmN0aW9uLWJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsbUNBQW9DO0FBR3BDLHdDQUF3QztBQUN4Qyx3Q0FBa0c7QUFHbEcsK0RBQW9GO0FBRXBGLGlFQUF1RjtBQUN2RixpREFBc0Y7QUFFdEYseURBQW1EO0FBRW5ELGlDQUEyQztBQXFOM0MsTUFBc0IsWUFBYSxTQUFRLGVBQVE7SUFBbkQ7O1FBaUVFOzs7V0FHRztRQUNPLGdDQUEyQixHQUFZLEtBQUssQ0FBQztRQUV2RDs7O1dBR0c7UUFDTyxzQkFBaUIsR0FBOEIsRUFBRSxDQUFDO1FBRTVEOzs7V0FHRztRQUNPLGlDQUE0QixHQUE4QixFQUFFLENBQUM7S0E0VHhFO0lBMVRDOzs7Ozs7O09BT0c7SUFDSSwwQ0FBMEMsQ0FBQyxLQUFnQixFQUFFLE1BQWM7UUFDaEYsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLHVCQUF1QixFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3BGLElBQUksbUJBQW1CLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQ3hDLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsZ0JBQWdCLENBQUMsRUFBRTtnQkFDN0MsSUFBSSxDQUFDLDZCQUE2QixDQUFDLEtBQUssQ0FBQyxDQUFDO2FBQzNDO2lCQUFNO2dCQUNMLElBQUksQ0FBQywyQkFBMkIsR0FBRyxJQUFJLENBQUM7YUFDekM7U0FDRjtLQUNGO0lBRVMsNkJBQTZCLENBQUMsS0FBZ0I7UUFDdEQsa0JBQVcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsVUFBVSxDQUFDO1lBQy9CLG1MQUFtTDtZQUNuTCxxSkFBcUo7WUFDckosa0RBQWtEO1NBQ25ELENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7S0FDZjtJQUVEOzs7O09BSUc7SUFDSSxhQUFhLENB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QUFPLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDO0tBQ2pDO0lBRUQsSUFBVyxjQUFjO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUM7S0FDbkM7SUFFRCxJQUFXLGFBQWE7UUFDdEIsT0FBTyxJQUFJLENBQUM7S0FDYjtJQUVELElBQVcsSUFBSTtRQUNiLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7S0FDekI7SUFFRCxJQUFXLE9BQU87UUFDaEIsTUFBTSxJQUFJLEtBQUssQ0FBQyx5REFBeUQsQ0FBQyxDQUFDO0tBQzVFO0lBRUQsSUFBVywwQkFBMEI7UUFDbkMsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztLQUMzQjtJQUVNLFFBQVEsQ0FBQyxTQUFpQixFQUFFLFVBQXdCLEVBQUU7UUFDM0QsT0FBTyxlQUFRLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7S0FDakQ7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgY2xvdWR3YXRjaCBmcm9tICdAYXdzLWNkay9hd3MtY2xvdWR3YXRjaCc7XG5pbXBvcnQgKiBhcyBlYzIgZnJvbSAnQGF3cy1jZGsvYXdzLWVjMic7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSAnQGF3cy1jZGsvYXdzLWlhbSc7XG5pbXBvcnQgeyBBbm5vdGF0aW9ucywgQXJuRm9ybWF0LCBDb25zdHJ1Y3ROb2RlLCBJUmVzb3VyY2UsIFJlc291cmNlLCBUb2tlbiB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQWxpYXNPcHRpb25zIH0gZnJvbSAnLi9hbGlhcyc7XG5pbXBvcnQgeyBBcmNoaXRlY3R1cmUgfSBmcm9tICcuL2FyY2hpdGVjdHVyZSc7XG5pbXBvcnQgeyBFdmVudEludm9rZUNvbmZpZywgRXZlbnRJbnZva2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi9ldmVudC1pbnZva2UtY29uZmlnJztcbmltcG9ydCB7IElFdmVudFNvdXJjZSB9IGZyb20gJy4vZXZlbnQtc291cmNlJztcbmltcG9ydCB7IEV2ZW50U291cmNlTWFwcGluZywgRXZlbnRTb3VyY2VNYXBwaW5nT3B0aW9ucyB9IGZyb20gJy4vZXZlbnQtc291cmNlLW1hcHBpbmcnO1xuaW1wb3J0IHsgRnVuY3Rpb25VcmxBdXRoVHlwZSwgRnVuY3Rpb25VcmxPcHRpb25zLCBGdW5jdGlvblVybCB9IGZyb20gJy4vZnVuY3Rpb24tdXJsJztcbmltcG9ydCB7IElWZXJzaW9uIH0gZnJvbSAnLi9sYW1iZGEtdmVyc2lvbic7XG5pbXBvcnQgeyBDZm5QZXJtaXNzaW9uIH0gZnJvbSAnLi9sYW1iZGEuZ2VuZXJhdGVkJztcbmltcG9ydCB7IFBlcm1pc3Npb24gfSBmcm9tICcuL3Blcm1pc3Npb24nO1xuaW1wb3J0IHsgYWRkQWxpYXMsIGZsYXRNYXAgfSBmcm9tICcuL3V0aWwnO1xuXG4vLyBrZWVwIHRoaXMgaW1wb3J0IHNlcGFyYXRlIGZyb20gb3RoZXIgaW1wb3J0cyB0byByZWR1Y2UgY2hhbmNlIGZvciBtZXJnZSBjb25mbGljdHMgd2l0aCB2Mi1tYWluXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tZHVwbGljYXRlLWltcG9ydHMsIGltcG9ydC9vcmRlclxuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSUZ1bmN0aW9uIGV4dGVuZHMgSVJlc291cmNlLCBlYzIuSUNvbm5lY3RhYmxlLCBpYW0uSUdyYW50YWJsZSB7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbi5cbiAgICpcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcmVhZG9ubHkgZnVuY3Rpb25OYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhlIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSBmdW5jdGlvbkFybjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgSUFNIHJvbGUgYXNzb2NpYXRlZCB3aXRoIHRoaXMgZnVuY3Rpb24uXG4gICAqL1xuICByZWFkb25seSByb2xlPzogaWFtLklSb2xlO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCB0aGlzIExhbWJkYSBmdW5jdGlvbiB3YXMgYm91bmQgdG8gYSBWUENcbiAgICpcbiAgICogSWYgdGhpcyBpcyBpcyBgZmFsc2VgLCB0cnlpbmcgdG8gYWNjZXNzIHRoZSBgY29ubmVjdGlvbnNgIG9iamVjdCB3aWxsIGZhaWwuXG4gICAqL1xuICByZWFkb25seSBpc0JvdW5kVG9WcGM6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBgJExBVEVTVGAgdmVyc2lvbiBvZiB0aGlzIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBOb3RlIHRoYXQgdGhpcyBpcyByZWZlcmVuY2UgdG8gYSBub24tc3BlY2lmaWMgQVdTIExhbWJkYSB2ZXJzaW9uLCB3aGljaFxuICAgKiBtZWFucyB0aGUgZnVuY3Rpb24gdGhpcyB2ZXJzaW9uIHJlZmVycyB0byBjYW4gcmV0dXJuIGRpZmZlcmVudCByZXN1bHRzIGluXG4gICAqIGRpZmZlcmVudCBpbnZvY2F0aW9ucy5cbiAgICpcbiAgICogVG8gb2J0YWluIGEgcmVmZXJlbmNlIHRvIGFuIGV4cGxpY2l0IHZlcnNpb24gd2hpY2ggcmVmZXJlbmNlcyB0aGUgY3VycmVudFxuICAgKiBmdW5jdGlvbiBjb25maWd1cmF0aW9uLCB1c2UgYGxhbWJkYUZ1bmN0aW9uLmN1cnJlbnRWZXJzaW9uYCBpbnN0ZWFkLlxuICAgKi9cbiAgcmVhZG9ubHkgbGF0ZXN0VmVyc2lvbjogSVZlcnNpb247XG5cbiAgLyoqXG4gICAqIFRoZSBjb25zdHJ1Y3Qgbm9kZSB3aGVyZSBwZXJtaXNzaW9ucyBhcmUgYXR0YWNoZWQuXG4gICAqL1xuICByZWFkb25seSBwZXJtaXNzaW9uc05vZGU6IENvbnN0cnVjdE5vZGU7XG5cbiAgLyoqXG4gICAqIFRoZSBzeXN0ZW0gYXJjaGl0ZWN0dXJlcyBjb21wYXRpYmxlIHdpdGggdGhpcyBsYW1iZGEgZnVuY3Rpb24uXG4gICAqL1xuICByZWFkb25seSBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZTtcblxuICAvKipcbiAgICogVGhlIEFSTihzKSB0byBwdXQgaW50byB0aGUgcmVzb3VyY2UgZmllbGQgb2YgdGhlIGdlbmVyYXRlZCBJQU0gcG9saWN5IGZvciBncmFudEludm9rZSgpLlxuICAgKlxuICAgKiBUaGlzIHByb3BlcnR5IGlzIGZvciBjZGsgbW9kdWxlcyB0byBjb25zdW1lIG9ubHkuIFlvdSBzaG91bGQgbm90IG5lZWQgdG8gdXNlIHRoaXMgcHJvcGVydHkuXG4gICAqIEluc3RlYWQsIHVzZSBncmFudEludm9rZSgpIGRpcmVjdGx5LlxuICAgKi9cbiAgcmVhZG9ubHkgcmVzb3VyY2VBcm5zRm9yR3JhbnRJbnZva2U6IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBBZGRzIGFuIGV2ZW50IHNvdXJjZSB0aGF0IG1hcHMgdG8gdGhpcyBBV1MgTGFtYmRhIGZ1bmN0aW9uLlxuICAgKiBAcGFyYW0gaWQgY29uc3RydWN0IElEXG4gICAqIEBwYXJhbSBvcHRpb25zIG1hcHBpbmcgb3B0aW9uc1xuICAgKi9cbiAgYWRkRXZlbnRTb3VyY2VNYXBwaW5nKGlkOiBzdHJpbmcsIG9wdGlvbnM6IEV2ZW50U291cmNlTWFwcGluZ09wdGlvbnMpOiBFdmVudFNvdXJjZU1hcHBpbmc7XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBwZXJtaXNzaW9uIHRvIHRoZSBMYW1iZGEgcmVzb3VyY2UgcG9saWN5LlxuICAgKiBAcGFyYW0gaWQgVGhlIGlkIGZvciB0aGUgcGVybWlzc2lvbiBjb25zdHJ1Y3RcbiAgICogQHBhcmFtIHBlcm1pc3Npb24gVGhlIHBlcm1pc3Npb24gdG8gZ3JhbnQgdG8gdGhpcyBMYW1iZGEgZnVuY3Rpb24uIEBzZWUgUGVybWlzc2lvbiBmb3IgZGV0YWlscy5cbiAgICovXG4gIGFkZFBlcm1pc3Npb24oaWQ6IHN0cmluZywgcGVybWlzc2lvbjogUGVybWlzc2lvbik6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBzdGF0ZW1lbnQgdG8gdGhlIElBTSByb2xlIGFzc3VtZWQgYnkgdGhlIGluc3RhbmNlLlxuICAgKi9cbiAgYWRkVG9Sb2xlUG9saWN5KHN0YXRlbWVudDogaWFtLlBvbGljeVN0YXRlbWVudCk6IHZvaWQ7XG5cbiAgLyoqXG4gICAqIEdyYW50IHRoZSBnaXZlbiBpZGVudGl0eSBwZXJtaXNzaW9ucyB0byBpbnZva2UgdGhpcyBMYW1iZGFcbiAgICovXG4gIGdyYW50SW52b2tlKGlkZW50aXR5OiBpYW0uSUdyYW50YWJsZSk6IGlhbS5HcmFudDtcblxuICAvKipcbiAgICogR3JhbnQgdGhlIGdpdmVuIGlkZW50aXR5IHBlcm1pc3Npb25zIHRvIGludm9rZSB0aGlzIExhbWJkYSBGdW5jdGlvbiBVUkxcbiAgICovXG4gIGdyYW50SW52b2tlVXJsKGlkZW50aXR5OiBpYW0uSUdyYW50YWJsZSk6IGlhbS5HcmFudDtcblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBnaXZlbiBuYW1lZCBtZXRyaWMgZm9yIHRoaXMgTGFtYmRhXG4gICAqL1xuICBtZXRyaWMobWV0cmljTmFtZTogc3RyaW5nLCBwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBEdXJhdGlvbiBvZiB0aGlzIExhbWJkYVxuICAgKlxuICAgKiBAZGVmYXVsdCBhdmVyYWdlIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNEdXJhdGlvbihwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBudW1iZXIgb2YgaW52b2NhdGlvbnMgb2YgdGhpcyBMYW1iZGFcbiAgICpcbiAgICogQGRlZmF1bHQgc3VtIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNJbnZvY2F0aW9ucyhwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBudW1iZXIgb2YgdGhyb3R0bGVkIGludm9jYXRpb25zIG9mIHRoaXMgTGFtYmRhXG4gICAqXG4gICAqIEBkZWZhdWx0IHN1bSBvdmVyIDUgbWludXRlc1xuICAgKi9cbiAgbWV0cmljVGhyb3R0bGVzKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gZXZlbnQgc291cmNlIHRvIHRoaXMgZnVuY3Rpb24uXG4gICAqXG4gICAqIEV2ZW50IHNvdXJjZXMgYXJlIGltcGxlbWVudGVkIGluIHRoZSBAYXdzLWNkay9hd3MtbGFtYmRhLWV2ZW50LXNvdXJjZXMgbW9kdWxlLlxuICAgKlxuICAgKiBUaGUgZm9sbG93aW5nIGV4YW1wbGUgYWRkcyBhbiBTUVMgUXVldWUgYXMgYW4gZXZlbnQgc291cmNlOlxuICAgKiBgYGBcbiAgICogaW1wb3J0IHsgU3FzRXZlbnRTb3VyY2UgfSBmcm9tICdAYXdzLWNkay9hd3MtbGFtYmRhLWV2ZW50LXNvdXJjZXMnO1xuICAgKiBteUZ1bmN0aW9uLmFkZEV2ZW50U291cmNlKG5ldyBTcXNFdmVudFNvdXJjZShteVF1ZXVlKSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYWRkRXZlbnRTb3VyY2Uoc291cmNlOiBJRXZlbnRTb3VyY2UpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBDb25maWd1cmVzIG9wdGlvbnMgZm9yIGFzeW5jaHJvbm91cyBpbnZvY2F0aW9uLlxuICAgKi9cbiAgY29uZmlndXJlQXN5bmNJbnZva2Uob3B0aW9uczogRXZlbnRJbnZva2VDb25maWdPcHRpb25zKTogdm9pZDtcblxuICAvKipcbiAgICogQWRkcyBhIHVybCB0byB0aGlzIGxhbWJkYSBmdW5jdGlvbi5cbiAgICovXG4gIGFkZEZ1bmN0aW9uVXJsKG9wdGlvbnM/OiBGdW5jdGlvblVybE9wdGlvbnMpOiBGdW5jdGlvblVybDtcbn1cblxuLyoqXG4gKiBSZXByZXNlbnRzIGEgTGFtYmRhIGZ1bmN0aW9uIGRlZmluZWQgb3V0c2lkZSBvZiB0aGlzIHN0YWNrLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZ1bmN0aW9uQXR0cmlidXRlcyB7XG4gIC8qKlxuICAgKiBUaGUgQVJOIG9mIHRoZSBMYW1iZGEgZnVuY3Rpb24uXG4gICAqXG4gICAqIEZvcm1hdDogYXJuOjxwYXJ0aXRpb24+OmxhbWJkYTo8cmVnaW9uPjo8YWNjb3VudC1pZD46ZnVuY3Rpb246PGZ1bmN0aW9uLW5hbWU+XG4gICAqL1xuICByZWFkb25seSBmdW5jdGlvbkFybjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgSUFNIGV4ZWN1dGlvbiByb2xlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBJZiB0aGUgcm9sZSBpcyBub3Qgc3BlY2lmaWVkLCBhbnkgcm9sZS1yZWxhdGVkIG9wZXJhdGlvbnMgd2lsbCBuby1vcC5cbiAgICovXG4gIHJlYWRvbmx5IHJvbGU/OiBpYW0uSVJvbGU7XG5cbiAgLyoqXG4gICAqIElkIG9mIHRoZSBzZWN1cml0eSBncm91cCBvZiB0aGlzIExhbWJkYSwgaWYgaW4gYSBWUEMuXG4gICAqXG4gICAqIFRoaXMgbmVlZHMgdG8gYmUgZ2l2ZW4gaW4gb3JkZXIgdG8gc3VwcG9ydCBhbGxvd2luZyBjb25uZWN0aW9uc1xuICAgKiB0byB0aGlzIExhbWJkYS5cbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGBzZWN1cml0eUdyb3VwYCBpbnN0ZWFkXG4gICAqL1xuICByZWFkb25seSBzZWN1cml0eUdyb3VwSWQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBzZWN1cml0eSBncm91cCBvZiB0aGlzIExhbWJkYSwgaWYgaW4gYSBWUEMuXG4gICAqXG4gICAqIFRoaXMgbmVlZHMgdG8gYmUgZ2l2ZW4gaW4gb3JkZXIgdG8gc3VwcG9ydCBhbGxvd2luZyBjb25uZWN0aW9uc1xuICAgKiB0byB0aGlzIExhbWJkYS5cbiAgICovXG4gIHJlYWRvbmx5IHNlY3VyaXR5R3JvdXA/OiBlYzIuSVNlY3VyaXR5R3JvdXA7XG5cbiAgLyoqXG4gICAqIFNldHRpbmcgdGhpcyBwcm9wZXJ0eSBpbmZvcm1zIHRoZSBDREsgdGhhdCB0aGUgaW1wb3J0ZWQgZnVuY3Rpb24gaXMgaW4gdGhlIHNhbWUgZW52aXJvbm1lbnQgYXMgdGhlIHN0YWNrLlxuICAgKiBUaGlzIGFmZmVjdHMgY2VydGFpbiBiZWhhdmlvdXJzIHN1Y2ggYXMsIHdoZXRoZXIgdGhpcyBmdW5jdGlvbidzIHBlcm1pc3Npb24gY2FuIGJlIG1vZGlmaWVkLlxuICAgKiBXaGVuIG5vdCBjb25maWd1cmVkLCB0aGUgQ0RLIGF0dGVtcHRzIHRvIGF1dG8tZGV0ZXJtaW5lIHRoaXMuIEZvciBlbnZpcm9ubWVudCBhZ25vc3RpYyBzdGFja3MsIGkuZS4sIHN0YWNrc1xuICAgKiB3aGVyZSB0aGUgYWNjb3VudCBpcyBub3Qgc3BlY2lmaWVkIHdpdGggdGhlIGBlbnZgIHByb3BlcnR5LCB0aGlzIGlzIGRldGVybWluZWQgdG8gYmUgZmFsc2UuXG4gICAqXG4gICAqIFNldCB0aGlzIHRvIHByb3BlcnR5ICpPTkxZIElGKiB0aGUgaW1wb3J0ZWQgZnVuY3Rpb24gaXMgaW4gdGhlIHNhbWUgYWNjb3VudCBhcyB0aGUgc3RhY2tcbiAgICogaXQncyBpbXBvcnRlZCBpbi5cbiAgICogQGRlZmF1bHQgLSBkZXBlbmRzOiB0cnVlLCBpZiB0aGUgU3RhY2sgaXMgY29uZmlndXJlZCB3aXRoIGFuIGV4cGxpY2l0IGBlbnZgIChhY2NvdW50IGFuZCByZWdpb24pIGFuZCB0aGUgYWNjb3VudCBpcyB0aGUgc2FtZSBhcyB0aGlzIGZ1bmN0aW9uLlxuICAgKiBGb3IgZW52aXJvbm1lbnQtYWdub3N0aWMgc3RhY2tzIHRoaXMgd2lsbCBkZWZhdWx0IHRvIGBmYWxzZWAuXG4gICAqL1xuICByZWFkb25seSBzYW1lRW52aXJvbm1lbnQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBTZXR0aW5nIHRoaXMgcHJvcGVydHkgaW5mb3JtcyB0aGUgQ0RLIHRoYXQgdGhlIGltcG9ydGVkIGZ1bmN0aW9uIEFMUkVBRFkgSEFTIHRoZSBuZWNlc3NhcnkgcGVybWlzc2lvbnNcbiAgICogZm9yIHdoYXQgeW91IGFyZSB0cnlpbmcgdG8gZG8uIFdoZW4gbm90IGNvbmZpZ3VyZWQsIHRoZSBDREsgYXR0ZW1wdHMgdG8gYXV0by1kZXRlcm1pbmUgd2hldGhlciBvciBub3RcbiAgICogYWRkaXRpb25hbCBwZXJtaXNzaW9ucyBhcmUgbmVjZXNzYXJ5IG9uIHRoZSBmdW5jdGlvbiB3aGVuIGdyYW50IEFQSXMgYXJlIHVzZWQuIElmIHRoZSBDREsgdHJpZWQgdG8gYWRkXG4gICAqIHBlcm1pc3Npb25zIG9uIGFuIGltcG9ydGVkIGxhbWJkYSwgaXQgd2lsbCBmYWlsLlxuICAgKlxuICAgKiBTZXQgdGhpcyBwcm9wZXJ0eSAqT05MWSBJRiogeW91IGFyZSBjb21taXR0aW5nIHRvIG1hbmFnZSB0aGUgaW1wb3J0ZWQgZnVuY3Rpb24ncyBwZXJtaXNzaW9ucyBvdXRzaWRlIG9mXG4gICAqIENESy4gWW91IGFyZSBhY2tub3dsZWRnaW5nIHRoYXQgeW91ciBDREsgY29kZSBhbG9uZSB3aWxsIGhhdmUgaW5zdWZmaWNpZW50IHBlcm1pc3Npb25zIHRvIGFjY2VzcyB0aGVcbiAgICogaW1wb3J0ZWQgZnVuY3Rpb24uXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBza2lwUGVybWlzc2lvbnM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaGUgYXJjaGl0ZWN0dXJlIG9mIHRoaXMgTGFtYmRhIEZ1bmN0aW9uICh0aGlzIGlzIGFuIG9wdGlvbmFsIGF0dHJpYnV0ZSBhbmQgZGVmYXVsdHMgdG8gWDg2XzY0KS5cbiAgICogQGRlZmF1bHQgLSBBcmNoaXRlY3R1cmUuWDg2XzY0XG4gICAqL1xuICByZWFkb25seSBhcmNoaXRlY3R1cmU/OiBBcmNoaXRlY3R1cmU7XG59XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBGdW5jdGlvbkJhc2UgZXh0ZW5kcyBSZXNvdXJjZSBpbXBsZW1lbnRzIElGdW5jdGlvbiwgZWMyLklDbGllbnRWcG5Db25uZWN0aW9uSGFuZGxlciB7XG4gIC8qKlxuICAgKiBUaGUgcHJpbmNpcGFsIHRoaXMgTGFtYmRhIEZ1bmN0aW9uIGlzIHJ1bm5pbmcgYXNcbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSBncmFudFByaW5jaXBhbDogaWFtLklQcmluY2lwYWw7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbi5cbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSBmdW5jdGlvbk5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIEFSTiBmbyB0aGUgZnVuY3Rpb24uXG4gICAqL1xuICBwdWJsaWMgYWJzdHJhY3QgcmVhZG9ubHkgZnVuY3Rpb25Bcm46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIElBTSByb2xlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBVbmRlZmluZWQgaWYgdGhlIGZ1bmN0aW9uIHdhcyBpbXBvcnRlZCB3aXRob3V0IGEgcm9sZS5cbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSByb2xlPzogaWFtLklSb2xlO1xuXG4gIC8qKlxuICAgKiBUaGUgY29uc3RydWN0IG5vZGUgd2hlcmUgcGVybWlzc2lvbnMgYXJlIGF0dGFjaGVkLlxuICAgKi9cbiAgcHVibGljIGFic3RyYWN0IHJlYWRvbmx5IHBlcm1pc3Npb25zTm9kZTogQ29uc3RydWN0Tm9kZTtcblxuICAvKipcbiAgICogVGhlIGFyY2hpdGVjdHVyZSBvZiB0aGlzIExhbWJkYSBGdW5jdGlvbi5cbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZTtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgYWRkUGVybWlzc2lvbigpIGNhbGwgYWRkcyBhbnkgcGVybWlzc2lvbnNcbiAgICpcbiAgICogVHJ1ZSBmb3IgbmV3IExhbWJkYXMsIGZhbHNlIGZvciB2ZXJzaW9uICRMQVRFU1QgYW5kIGltcG9ydGVkIExhbWJkYXNcbiAgICogZnJvbSBkaWZmZXJlbnQgYWNjb3VudHMuXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgcmVhZG9ubHkgY2FuQ3JlYXRlUGVybWlzc2lvbnM6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBBUk4ocykgdG8gcHV0IGludG8gdGhlIHJlc291cmNlIGZpZWxkIG9mIHRoZSBnZW5lcmF0ZWQgSUFNIHBvbGljeSBmb3IgZ3JhbnRJbnZva2UoKVxuICAgKi9cbiAgcHVibGljIGFic3RyYWN0IHJlYWRvbmx5IHJlc291cmNlQXJuc0ZvckdyYW50SW52b2tlOiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgdXNlciBkZWNpZGVzIHRvIHNraXAgYWRkaW5nIHBlcm1pc3Npb25zLlxuICAgKiBUaGUgb25seSB1c2UgY2FzZSBpcyBmb3IgY3Jvc3MtYWNjb3VudCwgaW1wb3J0ZWQgbGFtYmRhc1xuICAgKiB3aGVyZSB0aGUgdXNlciBjb21taXRzIHRvIG1vZGlmeWluZyB0aGUgcGVybWlzc3Npb25zXG4gICAqIG9uIHRoZSBpbXBvcnRlZCBsYW1iZGEgb3V0c2lkZSBDREsuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF9za2lwUGVybWlzc2lvbnM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBY3R1YWwgY29ubmVjdGlvbnMgb2JqZWN0IGZvciB0aGlzIExhbWJkYVxuICAgKlxuICAgKiBNYXkgYmUgdW5zZXQsIGluIHdoaWNoIGNhc2UgdGhpcyBMYW1iZGEgaXMgbm90IGNvbmZpZ3VyZWQgdXNlIGluIGEgVlBDLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByb3RlY3RlZCBfY29ubmVjdGlvbnM/OiBlYzIuQ29ubmVjdGlvbnM7XG5cbiAgcHJpdmF0ZSBfbGF0ZXN0VmVyc2lvbj86IExhdGVzdFZlcnNpb247XG5cbiAgLyoqXG4gICAqIEZsYWcgdG8gZGVsYXkgYWRkaW5nIGEgd2FybmluZyBtZXNzYWdlIHVudGlsIGN1cnJlbnQgdmVyc2lvbiBpcyBpbnZva2VkLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByb3RlY3RlZCBfd2FybklmQ3VycmVudFZlcnNpb25DYWxsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvKipcbiAgICogTWFwcGluZyBvZiBpbnZvY2F0aW9uIHByaW5jaXBhbHMgdG8gZ3JhbnRzLiBVc2VkIHRvIGRlLWR1cGUgYGdyYW50SW52b2tlKClgIGNhbGxzLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByb3RlY3RlZCBfaW52b2NhdGlvbkdyYW50czogUmVjb3JkPHN0cmluZywgaWFtLkdyYW50PiA9IHt9O1xuXG4gIC8qKlxuICAgKiBNYXBwaW5nIG9mIGZ1Y250aW9uIFVSTCBpbnZvY2F0aW9uIHByaW5jaXBhbHMgdG8gZ3JhbnRzLiBVc2VkIHRvIGRlLWR1cGUgYGdyYW50SW52b2tlVXJsKClgIGNhbGxzLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByb3RlY3RlZCBfZnVuY3Rpb25VcmxJbnZvY2F0aW9uR3JhbnRzOiBSZWNvcmQ8c3RyaW5nLCBpYW0uR3JhbnQ+ID0ge307XG5cbiAgLyoqXG4gICAqIEEgd2FybmluZyB3aWxsIGJlIGFkZGVkIHRvIGZ1bmN0aW9ucyB1bmRlciB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gICAqIC0gcGVybWlzc2lvbnMgdGhhdCBpbmNsdWRlIGBsYW1iZGE6SW52b2tlRnVuY3Rpb25gIGFyZSBhZGRlZCB0byB0aGUgdW5xdWFsaWZpZWQgZnVuY3Rpb24uXG4gICAqIC0gZnVuY3Rpb24uY3VycmVudFZlcnNpb24gaXMgaW52b2tlZCBiZWZvcmUgb3IgYWZ0ZXIgdGhlIHBlcm1pc3Npb24gaXMgY3JlYXRlZC5cbiAgICpcbiAgICogVGhpcyBhcHBsaWVzIG9ubHkgdG8gcGVybWlzc2lvbnMgb24gTGFtYmRhIGZ1bmN0aW9ucywgbm90IHZlcnNpb25zIG9yIGFsaWFzZXMuXG4gICAqIFRoaXMgZnVuY3Rpb24gaXMgb3ZlcnJpZGRlbiBhcyBhIG5vT3AgZm9yIFF1YWxpZmllZEZ1bmN0aW9uQmFzZS5cbiAgICovXG4gIHB1YmxpYyBjb25zaWRlcldhcm5pbmdPbkludm9rZUZ1bmN0aW9uUGVybWlzc2lvbnMoc2NvcGU6IENvbnN0cnVjdCwgYWN0aW9uOiBzdHJpbmcpIHtcbiAgICBjb25zdCBhZmZlY3RlZFBlcm1pc3Npb25zID0gWydsYW1iZGE6SW52b2tlRnVuY3Rpb24nLCAnbGFtYmRhOionLCAnbGFtYmRhOkludm9rZSonXTtcbiAgICBpZiAoYWZmZWN0ZWRQZXJtaXNzaW9ucy5pbmNsdWRlcyhhY3Rpb24pKSB7XG4gICAgICBpZiAoc2NvcGUubm9kZS50cnlGaW5kQ2hpbGQoJ0N1cnJlbnRWZXJzaW9uJykpIHtcbiAgICAgICAgdGhpcy53YXJuSW52b2tlRnVuY3Rpb25QZXJtaXNzaW9ucyhzY29wZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLl93YXJuSWZDdXJyZW50VmVyc2lvbkNhbGxlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIHdhcm5JbnZva2VGdW5jdGlvblBlcm1pc3Npb25zKHNjb3BlOiBDb25zdHJ1Y3QpOiB2b2lkIHtcbiAgICBBbm5vdGF0aW9ucy5vZihzY29wZSkuYWRkV2FybmluZyhbXG4gICAgICBcIkFXUyBMYW1iZGEgaGFzIGNoYW5nZWQgdGhlaXIgYXV0aG9yaXphdGlvbiBzdHJhdGVneSwgd2hpY2ggbWF5IGNhdXNlIGNsaWVudCBpbnZvY2F0aW9ucyB1c2luZyB0aGUgJ1F1YWxpZmllcicgcGFyYW1ldGVyIG9mIHRoZSBsYW1iZGEgZnVuY3Rpb24gdG8gZmFpbCB3aXRoIEFjY2VzcyBEZW5pZWQgZXJyb3JzLlwiLFxuICAgICAgXCJJZiB5b3UgYXJlIHVzaW5nIGEgbGFtYmRhIFZlcnNpb24gb3IgQWxpYXMsIG1ha2Ugc3VyZSB0byBjYWxsICdncmFudEludm9rZScgb3IgJ2FkZFBlcm1pc3Npb24nIG9uIHRoZSBWZXJzaW9uIG9yIEFsaWFzLCBub3QgdGhlIHVuZGVybHlpbmcgRnVuY3Rpb25cIixcbiAgICAgICdTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvMTkyNzMnLFxuICAgIF0uam9pbignXFxuJykpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBwZXJtaXNzaW9uIHRvIHRoZSBMYW1iZGEgcmVzb3VyY2UgcG9saWN5LlxuICAgKiBAcGFyYW0gaWQgVGhlIGlkIGZvciB0aGUgcGVybWlzc2lvbiBjb25zdHJ1Y3RcbiAgICogQHBhcmFtIHBlcm1pc3Npb24gVGhlIHBlcm1pc3Npb24gdG8gZ3JhbnQgdG8gdGhpcyBMYW1iZGEgZnVuY3Rpb24uIEBzZWUgUGVybWlzc2lvbiBmb3IgZGV0YWlscy5cbiAgICovXG4gIHB1YmxpYyBhZGRQZXJtaXNzaW9uKGlkOiBzdHJpbmcsIHBlcm1pc3Npb246IFBlcm1pc3Npb24pIHtcbiAgICBpZiAoIXRoaXMuY2FuQ3JlYXRlUGVybWlzc2lvbnMpIHtcbiAgICAgIC8vIEZJWE1FOiBAZGVwcmVjYXRlZCh2MikgLSB0aHJvdyBhbiBlcnJvciBpZiBjYWxsaW5nIGBhZGRQZXJtaXNzaW9uYCBvbiBhIHJlc291cmNlIHRoYXQgZG9lc24ndCBzdXBwb3J0IGl0LlxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHByaW5jaXBhbCA9IHRoaXMucGFyc2VQZXJtaXNzaW9uUHJpbmNpcGFsKHBlcm1pc3Npb24ucHJpbmNpcGFsKTtcbiAgICBjb25zdCB7IHNvdXJjZUFjY291bnQsIHNvdXJjZUFybiB9ID0gdGhpcy5wYXJzZUNvbmRpdGlvbnMocGVybWlzc2lvbi5wcmluY2lwYWwpID8/IHt9O1xuICAgIGNvbnN0IGFjdGlvbiA9IHBlcm1pc3Npb24uYWN0aW9uID8/ICdsYW1iZGE6SW52b2tlRnVuY3Rpb24nO1xuICAgIGNvbnN0IHNjb3BlID0gcGVybWlzc2lvbi5zY29wZSA/PyB0aGlzO1xuXG4gICAgdGhpcy5jb25zaWRlcldhcm5pbmdPbkludm9rZUZ1bmN0aW9uUGVybWlzc2lvbnMoc2NvcGUsIGFjdGlvbik7XG5cbiAgICBuZXcgQ2ZuUGVybWlzc2lvbihzY29wZSwgaWQsIHtcbiAgICAgIGFjdGlvbixcbiAgICAgIHByaW5jaXBhbCxcbiAgICAgIGZ1bmN0aW9uTmFtZTogdGhpcy5mdW5jdGlvbkFybixcbiAgICAgIGV2ZW50U291cmNlVG9rZW46IHBlcm1pc3Npb24uZXZlbnRTb3VyY2VUb2tlbixcbiAgICAgIHNvdXJjZUFjY291bnQ6IHBlcm1pc3Npb24uc291cmNlQWNjb3VudCA/PyBzb3VyY2VBY2NvdW50LFxuICAgICAgc291cmNlQXJuOiBwZXJtaXNzaW9uLnNvdXJjZUFybiA/PyBzb3VyY2VBcm4sXG4gICAgICBmdW5jdGlvblVybEF1dGhUeXBlOiBwZXJtaXNzaW9uLmZ1bmN0aW9uVXJsQXV0aFR5cGUsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHN0YXRlbWVudCB0byB0aGUgSUFNIHJvbGUgYXNzdW1lZCBieSB0aGUgaW5zdGFuY2UuXG4gICAqL1xuICBwdWJsaWMgYWRkVG9Sb2xlUG9saWN5KHN0YXRlbWVudDogaWFtLlBvbGljeVN0YXRlbWVudCkge1xuICAgIGlmICghdGhpcy5yb2xlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5yb2xlLmFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudCk7XG4gIH1cblxuICAvKipcbiAgICogQWNjZXNzIHRoZSBDb25uZWN0aW9ucyBvYmplY3RcbiAgICpcbiAgICogV2lsbCBmYWlsIGlmIG5vdCBhIFZQQy1lbmFibGVkIExhbWJkYSBGdW5jdGlvblxuICAgKi9cbiAgcHVibGljIGdldCBjb25uZWN0aW9ucygpOiBlYzIuQ29ubmVjdGlvbnMge1xuICAgIGlmICghdGhpcy5fY29ubmVjdGlvbnMpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ09ubHkgVlBDLWFzc29jaWF0ZWQgTGFtYmRhIEZ1bmN0aW9ucyBoYXZlIHNlY3VyaXR5IGdyb3VwcyB0byBtYW5hZ2UuIFN1cHBseSB0aGUgXCJ2cGNcIiBwYXJhbWV0ZXIgd2hlbiBjcmVhdGluZyB0aGUgTGFtYmRhLCBvciBcInNlY3VyaXR5R3JvdXBJZFwiIHdoZW4gaW1wb3J0aW5nIGl0LicpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fY29ubmVjdGlvbnM7XG4gIH1cblxuICBwdWJsaWMgZ2V0IGxhdGVzdFZlcnNpb24oKTogSVZlcnNpb24ge1xuICAgIGlmICghdGhpcy5fbGF0ZXN0VmVyc2lvbikge1xuICAgICAgdGhpcy5fbGF0ZXN0VmVyc2lvbiA9IG5ldyBMYXRlc3RWZXJzaW9uKHRoaXMpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fbGF0ZXN0VmVyc2lvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCB0aGlzIExhbWJkYSBmdW5jdGlvbiB3YXMgYm91bmQgdG8gYSBWUENcbiAgICpcbiAgICogSWYgdGhpcyBpcyBpcyBgZmFsc2VgLCB0cnlpbmcgdG8gYWNjZXNzIHRoZSBgY29ubmVjdGlvbnNgIG9iamVjdCB3aWxsIGZhaWwuXG4gICAqL1xuICBwdWJsaWMgZ2V0IGlzQm91bmRUb1ZwYygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLl9jb25uZWN0aW9ucztcbiAgfVxuXG4gIHB1YmxpYyBhZGRFdmVudFNvdXJjZU1hcHBpbmcoaWQ6IHN0cmluZywgb3B0aW9uczogRXZlbnRTb3VyY2VNYXBwaW5nT3B0aW9ucyk6IEV2ZW50U291cmNlTWFwcGluZyB7XG4gICAgcmV0dXJuIG5ldyBFdmVudFNvdXJjZU1hcHBpbmcodGhpcywgaWQsIHtcbiAgICAgIHRhcmdldDogdGhpcyxcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR3JhbnQgdGhlIGdpdmVuIGlkZW50aXR5IHBlcm1pc3Npb25zIHRvIGludm9rZSB0aGlzIExhbWJkYVxuICAgKi9cbiAgcHVibGljIGdyYW50SW52b2tlKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50IHtcbiAgICBjb25zdCBoYXNoID0gY3JlYXRlSGFzaCgnc2hhMjU2JylcbiAgICAgIC51cGRhdGUoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBwcmluY2lwYWw6IGdyYW50ZWUuZ3JhbnRQcmluY2lwYWwudG9TdHJpbmcoKSxcbiAgICAgICAgY29uZGl0aW9uczogZ3JhbnRlZS5ncmFudFByaW5jaXBhbC5wb2xpY3lGcmFnbWVudC5jb25kaXRpb25zLFxuICAgICAgfSksICd1dGY4JylcbiAgICAgIC5kaWdlc3QoJ2Jhc2U2NCcpO1xuICAgIGNvbnN0IGlkZW50aWZpZXIgPSBgSW52b2tlJHtoYXNofWA7XG5cbiAgICAvLyBNZW1vaXplIHRoZSByZXN1bHQgc28gc3Vic2VxdWVudCBncmFudEludm9rZSgpIGNhbGxzIGFyZSBpZGVtcG90ZW50XG4gICAgbGV0IGdyYW50ID0gdGhpcy5faW52b2NhdGlvbkdyYW50c1tpZGVudGlmaWVyXTtcbiAgICBpZiAoIWdyYW50KSB7XG4gICAgICBncmFudCA9IHRoaXMuZ3JhbnQoZ3JhbnRlZSwgaWRlbnRpZmllciwgJ2xhbWJkYTpJbnZva2VGdW5jdGlvbicsIHRoaXMucmVzb3VyY2VBcm5zRm9yR3JhbnRJbnZva2UpO1xuICAgICAgdGhpcy5faW52b2NhdGlvbkdyYW50c1tpZGVudGlmaWVyXSA9IGdyYW50O1xuICAgIH1cbiAgICByZXR1cm4gZ3JhbnQ7XG4gIH1cblxuICAvKipcbiAgICogR3JhbnQgdGhlIGdpdmVuIGlkZW50aXR5IHBlcm1pc3Npb25zIHRvIGludm9rZSB0aGlzIExhbWJkYSBGdW5jdGlvbiBVUkxcbiAgICovXG4gIHB1YmxpYyBncmFudEludm9rZVVybChncmFudGVlOiBpYW0uSUdyYW50YWJsZSk6IGlhbS5HcmFudCB7XG4gICAgY29uc3QgaWRlbnRpZmllciA9IGBJbnZva2VGdW5jdGlvblVybCR7Z3JhbnRlZS5ncmFudFByaW5jaXBhbH1gOyAvLyBjYWxscyB0aGUgLnRvU3RyaW5nKCkgb2YgdGhlIHByaW5jaXBhbFxuXG4gICAgLy8gTWVtb2l6ZSB0aGUgcmVzdWx0IHNvIHN1YnNlcXVlbnQgZ3JhbnRJbnZva2UoKSBjYWxscyBhcmUgaWRlbXBvdGVudFxuICAgIGxldCBncmFudCA9IHRoaXMuX2Z1bmN0aW9uVXJsSW52b2NhdGlvbkdyYW50c1tpZGVudGlmaWVyXTtcbiAgICBpZiAoIWdyYW50KSB7XG4gICAgICBncmFudCA9IHRoaXMuZ3JhbnQoZ3JhbnRlZSwgaWRlbnRpZmllciwgJ2xhbWJkYTpJbnZva2VGdW5jdGlvblVybCcsIFt0aGlzLmZ1bmN0aW9uQXJuXSwge1xuICAgICAgICBmdW5jdGlvblVybEF1dGhUeXBlOiBGdW5jdGlvblVybEF1dGhUeXBlLkFXU19JQU0sXG4gICAgICB9KTtcbiAgICAgIHRoaXMuX2Z1bmN0aW9uVXJsSW52b2NhdGlvbkdyYW50c1