@aws/pdk
Version:
All documentation is located at: https://aws.github.io/aws-pdk
294 lines • 48.6 kB
JavaScript
;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeSafeWebsocketApi = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0 */
const fs = require("fs");
const path = require("path");
const monorepo_1 = require("../../monorepo");
const pdk_nag_1 = require("../../pdk-nag");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_apigatewayv2_1 = require("aws-cdk-lib/aws-apigatewayv2");
const aws_apigatewayv2_integrations_1 = require("aws-cdk-lib/aws-apigatewayv2-integrations");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
const aws_logs_1 = require("aws-cdk-lib/aws-logs");
const aws_s3_assets_1 = require("aws-cdk-lib/aws-s3-assets");
const custom_resources_1 = require("aws-cdk-lib/custom-resources");
const cdk_nag_1 = require("cdk-nag");
const constructs_1 = require("constructs");
const websocket_schema_1 = require("./prepare-spec-event-handler/websocket-schema");
/**
* A construct for creating a websocket API, based on the provided spec and integrations
*/
class TypeSafeWebsocketApi extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
(0, monorepo_1.addMetric)(scope, "type-safe-websocket-api");
this._props = props;
// Create the WebSocket API
this.api = new aws_apigatewayv2_1.WebSocketApi(this, id, {
...props,
routeSelectionExpression: "$request.body.route",
});
// Add the connect/disconnect routes
this.addRoute("$connect", {
integration: props.connect?.integration ??
new aws_apigatewayv2_integrations_1.WebSocketMockIntegration("ConnectIntegration"),
authorizer: props.authorizer,
});
const disconnectRoute = this.addRoute("$disconnect", {
integration: props.connect?.integration ??
new aws_apigatewayv2_integrations_1.WebSocketMockIntegration("DisconnectIntegration"),
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(disconnectRoute, ["AwsPrototyping-APIGWAuthorization", "AwsSolutions-APIG4"].map((ruleId) => ({
id: ruleId,
reason: `Authorizers only apply to the $connect route`,
})), true);
// Create a default stage
this.defaultStage = new aws_apigatewayv2_1.WebSocketStage(this, "default", {
webSocketApi: this.api,
autoDeploy: true,
stageName: "default",
...props.stageProps,
});
// Enable execution logs by default
this.defaultStage.node.defaultChild.defaultRouteSettings = {
loggingLevel: "INFO",
dataTraceEnabled: false,
};
// Enable access logging by default
if (!props.disableAccessLogging) {
const logGroup = new aws_logs_1.LogGroup(this, `AccessLogs`);
this.defaultStage.node.defaultChild.accessLogSettings = {
destinationArn: logGroup.logGroupArn,
format: `$context.identity.sourceIp - - [$context.requestTime] "$context.httpMethod $context.routeKey $context.protocol" $context.status $context.responseLength $context.requestId`,
};
}
const lambdaHandlers = [
...Object.values(props.integrations),
props.connect,
props.disconnect,
].flatMap((integration) => integration?.integration instanceof aws_apigatewayv2_integrations_1.WebSocketLambdaIntegration &&
integration.integration.handler?.grantPrincipal
? [integration.integration.handler]
: []);
const stack = aws_cdk_lib_1.Stack.of(this);
// By default, grant lambda handlers access to the management api
if (!props.disableGrantManagementAccessToLambdas) {
lambdaHandlers.forEach((fn) => {
this.defaultStage.grantManagementApiAccess(fn);
cdk_nag_1.NagSuppressions.addResourceSuppressions(fn, ["AwsPrototyping-IAMNoWildcardPermissions", "AwsSolutions-IAM5"].map((ruleId) => ({
id: ruleId,
reason: "WebSocket handlers are granted permissions to manage arbitrary connections",
appliesTo: [
{
regex: `/^Resource::arn:${pdk_nag_1.PDKNag.getStackPartitionRegex(stack)}:execute-api:${pdk_nag_1.PDKNag.getStackRegionRegex(stack)}:${pdk_nag_1.PDKNag.getStackAccountRegex(stack)}:.*\\/${this.defaultStage.stageName}\\/\\*\\/@connections\\/\\*$/g`,
},
],
})), true);
});
}
// Where the same function is used for multiple routes, grant permission for API gateway to invoke
// the lambda for all routes
const uniqueLambdaHandlers = new Set();
const duplicateLambdaHandlers = new Set();
lambdaHandlers.forEach((fn) => {
if (uniqueLambdaHandlers.has(fn)) {
duplicateLambdaHandlers.add(fn);
}
uniqueLambdaHandlers.add(fn);
});
[...duplicateLambdaHandlers].forEach((fn, i) => {
new aws_lambda_1.CfnPermission(this, `GrantRouteInvoke${i}`, {
action: "lambda:InvokeFunction",
principal: "apigateway.amazonaws.com",
functionName: fn.functionArn,
sourceArn: stack.formatArn({
service: "execute-api",
resource: this.api.apiId,
resourceName: "*",
}),
});
});
// Read and parse the spec
const spec = JSON.parse(fs.readFileSync(props.specPath, "utf-8"));
// Map of route key to paths
const serverOperationPaths = Object.fromEntries(Object.values(props.operationLookup).map((details) => [
details.path.replace(/\//g, ""),
details.path,
]));
// Locally check that we can extract the schema for every operation
const schemas = (0, websocket_schema_1.extractWebSocketSchemas)(Object.keys(serverOperationPaths), serverOperationPaths, spec);
// Check that every operation has an integration
const missingIntegrations = Object.keys(props.operationLookup).filter((operationId) => !props.integrations[operationId]);
if (missingIntegrations.length > 0) {
throw new Error(`Missing integrations for operations ${missingIntegrations.join(", ")}`);
}
// Create an asset for the spec, which we'll read from the custom resource
const inputSpec = new aws_s3_assets_1.Asset(this, "InputSpec", {
path: props.specPath,
});
// Function for managing schemas/models associated with routes
const schemaHandler = new aws_lambda_1.Function(this, "SchemaHandler", {
handler: "websocket-schema-handler.handler",
runtime: aws_lambda_1.Runtime.NODEJS_20_X,
code: aws_lambda_1.Code.fromAsset(path.join(__dirname, "./prepare-spec-event-handler")),
timeout: aws_cdk_lib_1.Duration.minutes(1),
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(schemaHandler, ["AwsPrototyping-IAMNoManagedPolicies", "AwsSolutions-IAM4"].map((ruleId) => ({
id: ruleId,
reason: `AWSLambdaBasicExecutionRole grants minimal permissions required for lambda execution`,
})), true);
schemaHandler.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: ["s3:GetObject"],
resources: [inputSpec.bucket.arnForObjects(inputSpec.s3ObjectKey)],
}));
schemaHandler.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: [
"apigateway:DELETE",
"apigateway:PATCH",
"apigateway:POST",
"apigateway:GET",
],
resources: [
stack.formatArn({
service: "apigateway",
account: "",
resource: `/apis/${this.api.apiId}/models`,
}),
stack.formatArn({
service: "apigateway",
account: "",
resource: `/apis/${this.api.apiId}/models/*`,
}),
],
}));
schemaHandler.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: ["apigateway:PATCH", "apigateway:GET"],
resources: [
stack.formatArn({
service: "apigateway",
account: "",
resource: `/apis/${this.api.apiId}/routes`,
}),
stack.formatArn({
service: "apigateway",
account: "",
resource: `/apis/${this.api.apiId}/routes/*`,
}),
],
}));
cdk_nag_1.NagSuppressions.addResourceSuppressions(schemaHandler, ["AwsPrototyping-IAMNoWildcardPermissions", "AwsSolutions-IAM5"].map((ruleId) => ({
id: ruleId,
reason: `Schema custom resource manages all routes and models`,
})), true);
const providerRole = new aws_iam_1.Role(this, "PrepareSpecProviderRole", {
assumedBy: new aws_iam_1.ServicePrincipal("lambda.amazonaws.com"),
inlinePolicies: {
logs: new aws_iam_1.PolicyDocument({
statements: [
new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.ALLOW,
actions: [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
],
resources: [
`arn:aws:logs:${stack.region}:${stack.account}:log-group:/aws/lambda/*`,
],
}),
],
}),
},
});
const provider = new custom_resources_1.Provider(this, "SchemaProvider", {
onEventHandler: schemaHandler,
role: providerRole,
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(providerRole, ["AwsPrototyping-IAMNoWildcardPermissions", "AwsSolutions-IAM5"].map((ruleId) => ({
id: ruleId,
reason: `Custom resource provider may invoke arbitrary lambda versions`,
})), true);
cdk_nag_1.NagSuppressions.addResourceSuppressions(provider, ["AwsPrototyping-LambdaLatestVersion", "AwsSolutions-L1"].map((ruleId) => ({
id: ruleId,
reason: `Provider framework lambda is managed by CDK`,
})), true);
const schemaCustomResourceProperties = {
apiId: this.api.apiId,
inputSpecLocation: {
bucket: inputSpec.s3BucketName,
key: inputSpec.s3ObjectKey,
},
serverOperationPaths,
};
const schemaCustomResource = new aws_cdk_lib_1.CustomResource(this, "SchemaCustomResource", {
serviceToken: provider.serviceToken,
properties: schemaCustomResourceProperties,
});
// Add a route for every integration
Object.entries(props.integrations).forEach(([operationId, integration]) => {
const op = props.operationLookup[operationId];
if (!op) {
throw new Error(`Integration not found in operation lookup for operation ${operationId}`);
}
// Add the route
const routeKey = op.path.replace(/\//g, "");
const route = this.addRoute(routeKey, {
integration: integration.integration,
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(route, ["AwsPrototyping-APIGWAuthorization", "AwsSolutions-APIG4"].map((ruleId) => ({
id: ruleId,
reason: `Authorizers only apply to the $connect route`,
})), true);
// Associate the route with its corresponding schema (which is created by the custom resource)
if (schemas[routeKey]) {
route.node.defaultChild.requestModels = {
model: routeKey,
};
route.node.defaultChild.modelSelectionExpression =
"model";
}
route.node.addDependency(schemaCustomResource);
});
}
/**
* Add a route to the websocket api
*/
addRoute(routeKey, options) {
// Unless disableMockIntegrationResponses is true, we automatically configure the integration requests and responses
// required to successfully mock the route, when the integration is a mock integration
const shouldAddMockResponse = !this._props.disableMockIntegrationResponses &&
options.integration instanceof aws_apigatewayv2_integrations_1.WebSocketMockIntegration;
const route = this.api.addRoute(routeKey, {
...options,
returnResponse: shouldAddMockResponse,
});
if (shouldAddMockResponse &&
options.integration?.integration
?.integrationId) {
const integration = options.integration
?.integration;
integration.node.defaultChild.requestTemplates = {
"application/json": '{"statusCode":200}',
};
new aws_apigatewayv2_1.CfnIntegrationResponse(this, `${routeKey}IntegRes`, {
apiId: this.api.apiId,
integrationId: integration.integrationId,
integrationResponseKey: "/2\\d\\d/",
templateSelectionExpression: "/2\\d\\d/",
responseTemplates: {
"200": '{"statusCode":200}',
},
});
}
return route;
}
}
exports.TypeSafeWebsocketApi = TypeSafeWebsocketApi;
_a = JSII_RTTI_SYMBOL_1;
TypeSafeWebsocketApi[_a] = { fqn: "@aws/pdk.type_safe_api.TypeSafeWebsocketApi", version: "0.26.14" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZS1zYWZlLXdlYnNvY2tldC1hcGkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0eXBlLXNhZmUtd2Vic29ja2V0LWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBO3NDQUNzQztBQUN0Qyx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLDRDQUEwQztBQUMxQywwQ0FBc0M7QUFDdEMsNkNBQThEO0FBQzlELG1FQVdzQztBQUN0Qyw2RkFHbUQ7QUFDbkQsaURBTTZCO0FBQzdCLHVEQU1nQztBQUNoQyxtREFBZ0Q7QUFDaEQsNkRBQWtEO0FBQ2xELG1FQUF3RDtBQUN4RCxxQ0FBMEM7QUFDMUMsMkNBQXVDO0FBRXZDLG9GQUF3RjtBQWtGeEY7O0dBRUc7QUFDSCxNQUFhLG9CQUFxQixTQUFRLHNCQUFTO0lBWWpELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBZ0M7UUFDeEUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFBLG9CQUFTLEVBQUMsS0FBSyxFQUFFLHlCQUF5QixDQUFDLENBQUM7UUFFNUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUM7UUFFcEIsMkJBQTJCO1FBQzNCLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSwrQkFBWSxDQUFDLElBQUksRUFBRSxFQUFFLEVBQUU7WUFDcEMsR0FBRyxLQUFLO1lBQ1Isd0JBQXdCLEVBQUUscUJBQXFCO1NBQ2hELENBQUMsQ0FBQztRQUVILG9DQUFvQztRQUNwQyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRTtZQUN4QixXQUFXLEVBQ1QsS0FBSyxDQUFDLE9BQU8sRUFBRSxXQUFXO2dCQUMxQixJQUFJLHdEQUF3QixDQUFDLG9CQUFvQixDQUFDO1lBQ3BELFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTtTQUM3QixDQUFDLENBQUM7UUFDSCxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRTtZ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QUVHO0lBQ0ssUUFBUSxDQUFDLFFBQWdCLEVBQUUsT0FBOEI7UUFDL0Qsb0hBQW9IO1FBQ3BILHNGQUFzRjtRQUN0RixNQUFNLHFCQUFxQixHQUN6QixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsK0JBQStCO1lBQzVDLE9BQU8sQ0FBQyxXQUFXLFlBQVksd0RBQXdCLENBQUM7UUFFMUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFO1lBQ3hDLEdBQUcsT0FBTztZQUNWLGNBQWMsRUFBRSxxQkFBcUI7U0FDdEMsQ0FBQyxDQUFDO1FBRUgsSUFDRSxxQkFBcUI7WUFDbkIsT0FBTyxDQUFDLFdBQW1CLEVBQUUsV0FBb0M7Z0JBQ2pFLEVBQUUsYUFBYSxFQUNqQixDQUFDO1lBQ0QsTUFBTSxXQUFXLEdBQUksT0FBTyxDQUFDLFdBQW1CO2dCQUM5QyxFQUFFLFdBQW1DLENBQUM7WUFDdkMsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUErQixDQUFDLGdCQUFnQixHQUFHO2dCQUNuRSxrQkFBa0IsRUFBRSxvQkFBb0I7YUFDekMsQ0FBQztZQUVGLElBQUkseUNBQXNCLENBQUMsSUFBSSxFQUFFLEdBQUcsUUFBUSxVQUFVLEVBQUU7Z0JBQ3RELEtBQUssRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUs7Z0JBQ3JCLGFBQWEsRUFBRSxXQUFXLENBQUMsYUFBYTtnQkFDeEMsc0JBQXNCLEVBQUUsV0FBVztnQkFDbkMsMkJBQTJCLEVBQUUsV0FBVztnQkFDeEMsaUJBQWlCLEVBQUU7b0JBQ2pCLEtBQUssRUFBRSxvQkFBb0I7aUJBQzVCO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQzs7QUF0WUgsb0RBdVlDIiwic291cmNlc0NvbnRlbnQiOlsiLyohIENvcHlyaWdodCBbQW1hem9uLmNvbV0oaHR0cDovL2FtYXpvbi5jb20vKSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wICovXG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGFkZE1ldHJpYyB9IGZyb20gXCJAYXdzL21vbm9yZXBvXCI7XG5pbXBvcnQgeyBQREtOYWcgfSBmcm9tIFwiQGF3cy9wZGstbmFnXCI7XG5pbXBvcnQgeyBDdXN0b21SZXNvdXJjZSwgRHVyYXRpb24sIFN0YWNrIH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQge1xuICBDZm5JbnRlZ3JhdGlvbixcbiAgQ2ZuSW50ZWdyYXRpb25SZXNwb25zZSxcbiAgQ2ZuUm91dGUsXG4gIENmblN0YWdlLFxuICBJV2ViU29ja2V0Um91dGVBdXRob3JpemVyLFxuICBXZWJTb2NrZXRBcGksXG4gIFdlYlNvY2tldEludGVncmF0aW9uLFxuICBXZWJTb2NrZXRSb3V0ZUludGVncmF0aW9uLFxuICBXZWJTb2NrZXRSb3V0ZU9wdGlvbnMsXG4gIFdlYlNvY2tldFN0YWdlLFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWFwaWdhdGV3YXl2MlwiO1xuaW1wb3J0IHtcbiAgV2ViU29ja2V0TGFtYmRhSW50ZWdyYXRpb24sXG4gIFdlYlNvY2tldE1vY2tJbnRlZ3JhdGlvbixcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1hcGlnYXRld2F5djItaW50ZWdyYXRpb25zXCI7XG5pbXBvcnQge1xuICBFZmZlY3QsXG4gIFBvbGljeURvY3VtZW50LFxuICBQb2xpY3lTdGF0ZW1lbnQsXG4gIFJvbGUsXG4gIFNlcnZpY2VQcmluY2lwYWwsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQge1xuICBDZm5QZXJtaXNzaW9uLFxuICBDb2RlLFxuICBJRnVuY3Rpb24sXG4gIEZ1bmN0aW9uIGFzIExhbWJkYUZ1bmN0aW9uLFxuICBSdW50aW1lLFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiO1xuaW1wb3J0IHsgTG9nR3JvdXAgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxvZ3NcIjtcbmltcG9ydCB7IEFzc2V0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zMy1hc3NldHNcIjtcbmltcG9ydCB7IFByb3ZpZGVyIH0gZnJvbSBcImF3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXNcIjtcbmltcG9ydCB7IE5hZ1N1cHByZXNzaW9ucyB9IGZyb20gXCJjZGstbmFnXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgT3BlbkFQSVYzIH0gZnJvbSBcIm9wZW5hcGktdHlwZXNcIjtcbmltcG9ydCB7IGV4dHJhY3RXZWJTb2NrZXRTY2hlbWFzIH0gZnJvbSBcIi4vcHJlcGFyZS1zcGVjLWV2ZW50LWhhbmRsZXIvd2Vic29ja2V0LXNjaGVtYVwiO1xuaW1wb3J0IHsgV2ViU29ja2V0U2NoZW1hUmVzb3VyY2VQcm9wZXJ0aWVzIH0gZnJvbSBcIi4vcHJlcGFyZS1zcGVjLWV2ZW50LWhhbmRsZXIvd2Vic29ja2V0LXNjaGVtYS1oYW5kbGVyXCI7XG5pbXBvcnQgeyBXZWJTb2NrZXRBcGlQcm9wcyB9IGZyb20gXCIuL3dlYnNvY2tldC93ZWJzb2NrZXQtYXBpLXByb3BzXCI7XG5pbXBvcnQgeyBXZWJTb2NrZXRTdGFnZVByb3BzIH0gZnJvbSBcIi4vd2Vic29ja2V0L3dlYnNvY2tldC1zdGFnZS1wcm9wc1wiO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYW4gaW50ZWdyYXRpb24gZm9yIGEgcm91dGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUeXBlU2FmZVdlYnNvY2tldEFwaUludGVncmF0aW9uIHtcbiAgLyoqXG4gICAqIFRoZSBpbnRlZ3JhdGlvbiB0byBzZXJ2aWNlIHRoZSByb3V0ZVxuICAgKi9cbiAgcmVhZG9ubHkgaW50ZWdyYXRpb246IFdlYlNvY2tldFJvdXRlSW50ZWdyYXRpb247XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2Vic29ja2V0T3BlcmF0aW9uRGV0YWlscyB7XG4gIC8qKlxuICAgKiBQYXRoIGluIHRoZSBPcGVuQVBJIHNwZWMgZm9yIHRoZSBvcGVyYXRpb25cbiAgICovXG4gIHJlYWRvbmx5IHBhdGg6IHN0cmluZztcbn1cblxuZXhwb3J0IHR5cGUgV2Vic29ja2V0T3BlcmF0aW9uTG9va3VwID0ge1xuICBbb3BlcmF0aW9uSWQ6IHN0cmluZ106IFdlYnNvY2tldE9wZXJhdGlvbkRldGFpbHM7XG59O1xuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIGEgVHlwZSBTYWZlIFdlYlNvY2tldCBBUElcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUeXBlU2FmZVdlYnNvY2tldEFwaVByb3BzIGV4dGVuZHMgV2ViU29ja2V0QXBpUHJvcHMge1xuICAvKipcbiAgICogUGF0aCB0byB0aGUgd2Vic29ja2V0IGFwaSBzcGVjaWZpY2F0aW9uIGpzb24gZmlsZVxuICAgKi9cbiAgcmVhZG9ubHkgc3BlY1BhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIERldGFpbHMgYWJvdXQgZWFjaCBvcGVyYXRpb25cbiAgICovXG4gIHJlYWRvbmx5IG9wZXJhdGlvbkxvb2t1cDogV2Vic29ja2V0T3BlcmF0aW9uTG9va3VwO1xuICAvKipcbiAgICogV2ViU29ja2V0IHJvdXRlcyBhbmQgdGhlaXIgY29ycmVzcG9uZGluZyBpbnRlZ3JhdGlvbnNcbiAgICovXG4gIHJlYWRvbmx5IGludGVncmF0aW9uczoge1xuICAgIFtvcGVyYXRpb25JZDogc3RyaW5nXTogVHlwZVNhZmVXZWJzb2NrZXRBcGlJbnRlZ3JhdGlvbjtcbiAgfTtcbiAgLyoqXG4gICAqIEludGVncmF0aW9uIGZvciB0aGUgJGNvbm5lY3Qgcm91dGUgKGludm9rZWQgd2hlbiBhIG5ldyBjbGllbnQgY29ubmVjdHMpXG4gICAqIEBkZWZhdWx0IG1vY2tlZFxuICAgKi9cbiAgcmVhZG9ubHkgY29ubmVjdD86IFR5cGVTYWZlV2Vic29ja2V0QXBpSW50ZWdyYXRpb247XG4gIC8qKlxuICAgKiBJbnRlZ3JhdGlvbiBmb3IgdGhlICRkaXNjb25uZWN0IHJvdXRlIChpbnZva2VkIHdoZW4gYSBjbGllbnQgZGlzY29ubmVjdHMpXG4gICAqIEBkZWZhdWx0IG1vY2tlZFxuICAgKi9cbiAgcmVhZG9ubHkgZGlzY29ubmVjdD86IFR5cGVTYWZlV2Vic29ja2V0QXBpSW50ZWdyYXRpb247XG4gIC8qKlxuICAgKiBBdXRob3JpemVyIHRvIHVzZSBmb3IgdGhlIEFQSSAoYXBwbGllZCB0byB0aGUgJGNvbm5lY3Qgcm91dGUpXG4gICAqIEBkZWZhdWx0IE5PTkVcbiAgICovXG4gIHJlYWRvbmx5IGF1dGhvcml6ZXI/OiBJV2ViU29ja2V0Um91dGVBdXRob3JpemVyO1xuICAvKipcbiAgICogT3B0aW9ucyBmb3IgdGhlIGRlZmF1bHQgc3RhZ2VcbiAgICovXG4gIHJlYWRvbmx5IHN0YWdlUHJvcHM/OiBXZWJTb2NrZXRTdGFnZVByb3BzO1xuICAvKipcbiAgICogQnkgZGVmYXVsdCwgYWxsIGxhbWJkYSBpbnRlZ3JhdGlvbnMgYXJlIGdyYW50ZWQgbWFuYWdlbWVudCBBUEkgYWNjZXNzIGZvciB0aGUgd2Vic29ja2V0IEFQSSB0byBzZW5kIG1lc3NhZ2VzLCBkaXNjb25uZWN0IGNsaWVudHMsIGV0Yy5cbiAgICogU2V0IHRvIHRydWUgaWYgeW91IHdvdWxkIGxpa2UgdG8gbWFuYWdlIHRoZXNlIHBlcm1pc3Npb25zIG1hbnVhbGx5LlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgZGlzYWJsZUdyYW50TWFuYWdlbWVudEFjY2Vzc1RvTGFtYmRhcz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBCeSBkZWZhdWx0LCBhbGwgbW9jayBpbnRlZ3JhdGlvbnMgd2lsbCBhdXRvbWF0aWNhbGx5IGJlIGNvbmZpZ3VyZWQgd2l0aCBpbnRlZ3JhdGlvbiByZXNwb25zZXMgc3VjaCB0aGF0IHRoZSBpbnRlZ3JhdGlvbiBpcyBjb25zaWRlcmVkXG4gICAqIHN1Y2Nlc3NmdWwuIFNldCB0byB0cnVlIHRvIGRpc2FibGUgdGhpcyAobW9jayBpbnRlZ3JhdGlvbnMgd2lsbCByZXNwb25kIHdpdGggZXJyb3JzKVxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgZGlzYWJsZU1vY2tJbnRlZ3JhdGlvblJlc3BvbnNlcz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBEaXNhYmxlIGFjY2VzcyBsb2dnaW5nXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBkaXNhYmxlQWNjZXNzTG9nZ2luZz86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQSBjb25zdHJ1Y3QgZm9yIGNyZWF0aW5nIGEgd2Vic29ja2V0IEFQSSwgYmFzZWQgb24gdGhlIHByb3ZpZGVkIHNwZWMgYW5kIGludGVncmF0aW9uc1xuICovXG5leHBvcnQgY2xhc3MgVHlwZVNhZmVXZWJzb2NrZXRBcGkgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAvKipcbiAgICogUmVmZXJlbmNlIHRvIHRoZSB3ZWJzb2NrZXQgQVBJXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYXBpOiBXZWJTb2NrZXRBcGk7XG4gIC8qKlxuICAgKiBSZWZlcmVuY2UgdG8gdGhlIGRlZmF1bHQgZGVwbG95IHN0YWdlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZGVmYXVsdFN0YWdlOiBXZWJTb2NrZXRTdGFnZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IF9wcm9wczogVHlwZVNhZmVXZWJzb2NrZXRBcGlQcm9wcztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogVHlwZVNhZmVXZWJzb2NrZXRBcGlQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBhZGRNZXRyaWMoc2NvcGUsIFwidHlwZS1zYWZlLXdlYnNvY2tldC1hcGlcIik7XG5cbiAgICB0aGlzLl9wcm9wcyA9IHByb3BzO1xuXG4gICAgLy8gQ3JlYXRlIHRoZSBXZWJTb2NrZXQgQVBJXG4gICAgdGhpcy5hcGkgPSBuZXcgV2ViU29ja2V0QXBpKHRoaXMsIGlkLCB7XG4gICAgICAuLi5wcm9wcyxcbiAgICAgIHJvdXRlU2VsZWN0aW9uRXhwcmVzc2lvbjogXCIkcmVxdWVzdC5ib2R5LnJvdXRlXCIsXG4gICAgfSk7XG5cbiAgICAvLyBBZGQgdGhlIGNvbm5lY3QvZGlzY29ubmVjdCByb3V0ZXNcbiAgICB0aGlzLmFkZFJvdXRlKFwiJGNvbm5lY3RcIiwge1xuICAgICAgaW50ZWdyYXRpb246XG4gICAgICAgIHByb3BzLmNvbm5lY3Q/LmludGVncmF0aW9uID8/XG4gICAgICAgIG5ldyBXZWJTb2NrZXRNb2NrSW50ZWdyYXRpb24oXCJDb25uZWN0SW50ZWdyYXRpb25cIiksXG4gICAgICBhdXRob3JpemVyOiBwcm9wcy5hdXRob3JpemVyLFxuICAgIH0pO1xuICAgIGNvbnN0IGRpc2Nvbm5lY3RSb3V0ZSA9IHRoaXMuYWRkUm91dGUoXCIkZGlzY29ubmVjdFwiLCB7XG4gICAgICBpbnRlZ3JhdGlvbjpcbiAgICAgICAgcHJvcHMuY29ubmVjdD8uaW50ZWdyYXRpb24gPz9cbiAgICAgICAgbmV3IFdlYlNvY2tldE1vY2tJbnRlZ3JhdGlvbihcIkRpc2Nvbm5lY3RJbnRlZ3JhdGlvblwiKSxcbiAgICB9KTtcbiAgICBOYWdTdXBwcmVzc2lvbnMuYWRkUmVzb3VyY2VTdXBwcmVzc2lvbnMoXG4gICAgICBkaXNjb25uZWN0Um91dGUsXG4gICAgICBbXCJBd3NQcm90b3R5cGluZy1BUElHV0F1dGhvcml6YXRpb25cIiwgXCJBd3NTb2x1dGlvbnMtQVBJRzRcIl0ubWFwKFxuICAgICAgICAocnVsZUlkKSA9PiAoe1xuICAgICAgICAgIGlkOiBydWxlSWQsXG4gICAgICAgICAgcmVhc29uOiBgQXV0aG9yaXplcnMgb25seSBhcHBseSB0byB0aGUgJGNvbm5lY3Qgcm91dGVgLFxuICAgICAgICB9KVxuICAgICAgKSxcbiAgICAgIHRydWVcbiAgICApO1xuXG4gICAgLy8gQ3JlYXRlIGEgZGVmYXVsdCBzdGFnZVxuICAgIHRoaXMuZGVmYXVsdFN0YWdlID0gbmV3IFdlYlNvY2tldFN0YWdlKHRoaXMsIFwiZGVmYXVsdFwiLCB7XG4gICAgICB3ZWJTb2NrZXRBcGk6IHRoaXMuYXBpLFxuICAgICAgYXV0b0RlcGxveTogdHJ1ZSxcbiAgICAgIHN0YWdlTmFtZTogXCJkZWZhdWx0XCIsXG4gICAgICAuLi5wcm9wcy5zdGFnZVByb3BzLFxuICAgIH0pO1xuXG4gICAgLy8gRW5hYmxlIGV4ZWN1dGlvbiBsb2dzIGJ5IGRlZmF1bHRcbiAgICAodGhpcy5kZWZhdWx0U3RhZ2Uubm9kZS5kZWZhdWx0Q2hpbGQgYXMgQ2ZuU3RhZ2UpLmRlZmF1bHRSb3V0ZVNldHRpbmdzID0ge1xuICAgICAgbG9nZ2luZ0xldmVsOiBcIklORk9cIixcbiAgICAgIGRhdGFUcmFjZUVuYWJsZWQ6IGZhbHNlLFxuICAgIH07XG5cbiAgICAvLyBFbmFibGUgYWNjZXNzIGxvZ2dpbmcgYnkgZGVmYXVsdFxuICAgIGlmICghcHJvcHMuZGlzYWJsZUFjY2Vzc0xvZ2dpbmcpIHtcbiAgICAgIGNvbnN0IGxvZ0dyb3VwID0gbmV3IExvZ0dyb3VwKHRoaXMsIGBBY2Nlc3NMb2dzYCk7XG4gICAgICAodGhpcy5kZWZhdWx0U3RhZ2Uubm9kZS5kZWZhdWx0Q2hpbGQgYXMgQ2ZuU3RhZ2UpLmFjY2Vzc0xvZ1NldHRpbmdzID0ge1xuICAgICAgICBkZXN0aW5hdGlvbkFybjogbG9nR3JvdXAubG9nR3JvdXBBcm4sXG4gICAgICAgIGZvcm1hdDogYCRjb250ZXh0LmlkZW50aXR5LnNvdXJjZUlwIC0gLSBbJGNvbnRleHQucmVxdWVzdFRpbWVdIFwiJGNvbnRleHQuaHR0cE1ldGhvZCAkY29udGV4dC5yb3V0ZUtleSAkY29udGV4dC5wcm90b2NvbFwiICRjb250ZXh0LnN0YXR1cyAkY29udGV4dC5yZXNwb25zZUxlbmd0aCAkY29udGV4dC5yZXF1ZXN0SWRgLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBsYW1iZGFIYW5kbGVyczogSUZ1bmN0aW9uW10gPSBbXG4gICAgICAuLi5PYmplY3QudmFsdWVzKHByb3BzLmludGVncmF0aW9ucyksXG4gICAgICBwcm9wcy5jb25uZWN0LFxuICAgICAgcHJvcHMuZGlzY29ubmVjdCxcbiAgICBdLmZsYXRNYXAoKGludGVncmF0aW9uKSA9PlxuICAgICAgaW50ZWdyYXRpb24/LmludGVncmF0aW9uIGluc3RhbmNlb2YgV2ViU29ja2V0TGFtYmRhSW50ZWdyYXRpb24gJiZcbiAgICAgIChpbnRlZ3JhdGlvbi5pbnRlZ3JhdGlvbiBhcyBhbnkpLmhhbmRsZXI/LmdyYW50UHJpbmNpcGFsXG4gICAgICAgID8gWyhpbnRlZ3JhdGlvbi5pbnRlZ3JhdGlvbiBhcyBhbnkpLmhhbmRsZXJdXG4gICAgICAgIDogW11cbiAgICApO1xuXG4gICAgY29uc3Qgc3RhY2sgPSBTdGFjay5vZih0aGlzKTtcblxuICAgIC8vIEJ5IGRlZmF1bHQsIGdyYW50IGxhbWJkYSBoYW5kbGVycyBhY2Nlc3MgdG8gdGhlIG1hbmFnZW1lbnQgYXBpXG4gICAgaWYgKCFwcm9wcy5kaXNhYmxlR3JhbnRNYW5hZ2VtZW50QWNjZXNzVG9MYW1iZGFzKSB7XG4gICAgICBsYW1iZGFIYW5kbGVycy5mb3JFYWNoKChmbikgPT4ge1xuICAgICAgICB0aGlzLmRlZmF1bHRTdGFnZS5ncmFudE1hbmFnZW1lbnRBcGlBY2Nlc3MoZm4pO1xuICAgICAgICBOYWdTdXBwcmVzc2lvbnMuYWRkUmVzb3VyY2VTdXBwcmVzc2lvbnMoXG4gICAgICAgICAgZm4sXG4gICAgICAgICAgW1wiQXdzUHJvdG90eXBpbmctSUFNTm9XaWxkY2FyZFBlcm1pc3Npb25zXCIsIFwiQXdzU29sdXRpb25zLUlBTTVcIl0ubWFwKFxuICAgICAgICAgICAgKHJ1bGVJZCkgPT4gKHtcbiAgICAgICAgICAgICAgaWQ6IHJ1bGVJZCxcbiAgICAgICAgICAgICAgcmVhc29uOlxuICAgICAgICAgICAgICAgIFwiV2ViU29ja2V0IGhhbmRsZXJzIGFyZSBncmFudGVkIHBlcm1pc3Npb25zIHRvIG1hbmFnZSBhcmJpdHJhcnkgY29ubmVjdGlvbnNcIixcbiAgICAgICAgICAgICAgYXBwbGllc1RvOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgcmVnZXg6IGAvXlJlc291cmNlOjphcm46JHtQREtOYWcuZ2V0U3RhY2tQYXJ0aXRpb25SZWdleChcbiAgICAgICAgICAgICAgICAgICAgc3RhY2tcbiAgICAgICAgICAgICAgICAgICl9OmV4ZWN1dGUtYXBpOiR7UERLTmFnLmdldFN0YWNrUmVnaW9uUmVnZXgoXG4gICAgICAgICAgICAgICAgICAgIHN0YWNrXG4gICAgICAgICAgICAgICAgICApfToke1BES05hZy5nZXRTdGFja0FjY291bnRSZWdleChzdGFjayl9Oi4qXFxcXC8ke1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRlZmF1bHRTdGFnZS5zdGFnZU5hbWVcbiAgICAgICAgICAgICAgICAgIH1cXFxcL1xcXFwqXFxcXC9AY29ubmVjdGlvbnNcXFxcL1xcXFwqJC9nYCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICApLFxuICAgICAgICAgIHRydWVcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIFdoZXJlIHRoZSBzYW1lIGZ1bmN0aW9uIGlzIHVzZWQgZm9yIG11bHRpcGxlIHJvdXRlcywgZ3JhbnQgcGVybWlzc2lvbiBmb3IgQVBJIGdhdGV3YXkgdG8gaW52b2tlXG4gICAgLy8gdGhlIGxhbWJkYSBmb3IgYWxsIHJvdXRlc1xuICAgIGNvbnN0IHVuaXF1ZUxhbWJkYUhhbmRsZXJzID0gbmV3IFNldDxJRnVuY3Rpb24+KCk7XG4gICAgY29uc3QgZHVwbGljYXRlTGFtYmRhSGFuZGxlcnMgPSBuZXcgU2V0PElGdW5jdGlvbj4oKTtcbiAgICBsYW1iZGFIYW5kbGVycy5mb3JFYWNoKChmbikgPT4ge1xuICAgICAgaWYgKHVuaXF1ZUxhbWJkYUhhbmRsZXJzLmhhcyhmbikpIHtcbiAgICAgICAgZHVwbGljYXRlTGFtYmRhSGFuZGxlcnMuYWRkKGZuKTtcbiAgICAgIH1cbiAgICAgIHVuaXF1ZUxhbWJkYUhhbmRsZXJzLmFkZChmbik7XG4gICAgfSk7XG4gICAgWy4uLmR1cGxpY2F0ZUxhbWJkYUhhbmRsZXJzXS5mb3JFYWNoKChmbiwgaSkgPT4ge1xuICAgICAgbmV3IENmblBlcm1pc3Npb24odGhpcywgYEdyYW50Um91dGVJbnZva2Uke2l9YCwge1xuICAgICAgICBhY3Rpb246IFwibGFtYmRhOkludm9rZUZ1bmN0aW9uXCIsXG4gICAgICAgIHByaW5jaXBhbDogXCJhcGlnYXRld2F5LmFtYXpvbmF3cy5jb21cIixcbiAgICAgICAgZnVuY3Rpb25OYW1lOiBmbi5mdW5jdGlvbkFybixcbiAgICAgICAgc291cmNlQXJuOiBzdGFjay5mb3JtYXRBcm4oe1xuICAgICAgICAgIHNlcnZpY2U6IFwiZXhlY3V0ZS1hcGlcIixcbiAgICAgICAgICByZXNvdXJjZTogdGhpcy5hcGkuYXBpSWQsXG4gICAgICAgICAgcmVzb3VyY2VOYW1lOiBcIipcIixcbiAgICAgICAgfSksXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIFJlYWQgYW5kIHBhcnNlIHRoZSBzcGVjXG4gICAgY29uc3Qgc3BlYyA9IEpTT04ucGFyc2UoXG4gICAgICBmcy5yZWFkRmlsZVN5bmMocHJvcHMuc3BlY1BhdGgsIFwidXRmLThcIilcbiAgICApIGFzIE9wZW5BUElWMy5Eb2N1bWVudDtcblxuICAgIC8vIE1hcCBvZiByb3V0ZSBrZXkgdG8gcGF0aHNcbiAgICBjb25zdCBzZXJ2ZXJPcGVyYXRpb25QYXRocyA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgIE9iamVjdC52YWx1ZXMocHJvcHMub3BlcmF0aW9uTG9va3VwKS5tYXAoKGRldGFpbHMpID0+IFtcbiAgICAgICAgZGV0YWlscy5wYXRoLnJlcGxhY2UoL1xcLy9nLCBcIlwiKSxcbiAgICAgICAgZGV0YWlscy5wYXRoLFxuICAgICAgXSlcbiAgICApO1xuXG4gICAgLy8gTG9jYWxseSBjaGVjayB0aGF0IHdlIGNhbiBleHRyYWN0IHRoZSBzY2hlbWEgZm9yIGV2ZXJ5IG9wZXJhdGlvblxuICAgIGNvbnN0IHNjaGVtYXMgPSBleHRyYWN0V2ViU29ja2V0U2NoZW1hcyhcbiAgICAgIE9iamVjdC5rZXlzKHNlcnZlck9wZXJhdGlvblBhdGhzKSxcbiAgICAgIHNlcnZlck9wZXJhdGlvblBhdGhzLFxuICAgICAgc3BlY1xuICAgICk7XG5cbiAgICAvLyBDaGVjayB0aGF0IGV2ZXJ5IG9wZXJhdGlvbiBoYXMgYW4gaW50ZWdyYXRpb25cbiAgICBjb25zdCBtaXNzaW5nSW50ZWdyYXRpb25zID0gT2JqZWN0LmtleXMocHJvcHMub3BlcmF0aW9uTG9va3VwKS5maWx0ZXIoXG4gICAgICAob3BlcmF0aW9uSWQpID0+ICFwcm9wcy5pbnRlZ3JhdGlvbnNbb3BlcmF0aW9uSWRdXG4gICAgKTtcbiAgICBpZiAobWlzc2luZ0ludGVncmF0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBNaXNzaW5nIGludGVncmF0aW9ucyBmb3Igb3BlcmF0aW9ucyAke21pc3NpbmdJbnRlZ3JhdGlvbnMuam9pbihcIiwgXCIpfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIGFuIGFzc2V0IGZvciB0aGUgc3BlYywgd2hpY2ggd2UnbGwgcmVhZCBmcm9tIHRoZSBjdXN0b20gcmVzb3VyY2VcbiAgICBjb25zdCBpbnB1dFNwZWMgPSBuZXcgQXNzZXQodGhpcywgXCJJbnB1dFNwZWNcIiwge1xuICAgICAgcGF0aDogcHJvcHMuc3BlY1BhdGgsXG4gICAgfSk7XG5cbiAgICAvLyBGdW5jdGlvbiBmb3IgbWFuYWdpbmcgc2NoZW1hcy9tb2RlbHMgYXNzb2NpYXRlZCB3aXRoIHJvdXRlc1xuICAgIGNvbnN0IHNjaGVtYUhhbmRsZXIgPSBuZXcgTGFtYmRhRnVuY3Rpb24odGhpcywgXCJTY2hlbWFIYW5kbGVyXCIsIHtcbiAgICAgIGhhbmRsZXI6IFwid2Vic29ja2V0LXNjaGVtYS1oYW5kbGVyLmhhbmRsZXJcIixcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTXzIwX1gsXG4gICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldChcbiAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgXCIuL3ByZXBhcmUtc3BlYy1ldmVudC1oYW5kbGVyXCIpXG4gICAgICApLFxuICAgICAgdGltZW91dDogRHVyYXRpb24ubWludXRlcygxKSxcbiAgICB9KTtcblxuICAgIE5hZ1N1cHByZXNzaW9ucy5hZGRSZXNvdXJjZVN1cHByZXNzaW9ucyhcbiAgICAgIHNjaGVtYUhhbmRsZXIsXG4gICAgICBbXCJBd3NQcm90b3R5cGluZy1JQU1Ob01hbmFnZWRQb2xpY2llc1wiLCBcIkF3c1NvbHV0aW9ucy1JQU00XCJdLm1hcChcbiAgICAgICAgKHJ1bGVJZCkgPT4gKHtcbiAgICAgICAgICBpZDogcnVsZUlkLFxuICAgICAgICAgIHJlYXNvbjogYEFXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZSBncmFudHMgbWluaW1hbCBwZXJtaXNzaW9ucyByZXF1aXJlZCBmb3IgbGFtYmRhIGV4ZWN1dGlvbmAsXG4gICAgICAgIH0pXG4gICAgICApLFxuICAgICAgdHJ1ZVxuICAgICk7XG5cbiAgICBzY2hlbWFIYW5kbGVyLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbXCJzMzpHZXRPYmplY3RcIl0sXG4gICAgICAgIHJlc291cmNlczogW2lucHV0U3BlYy5idWNrZXQuYXJuRm9yT2JqZWN0cyhpbnB1dFNwZWMuczNPYmplY3RLZXkpXSxcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIHNjaGVtYUhhbmRsZXIuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICBcImFwaWdhdGV3YXk6REVMRVRFXCIsXG4gICAgICAgICAgXCJhcGlnYXRld2F5OlBBVENIXCIsXG4gICAgICAgICAgXCJhcGlnYXRld2F5OlBPU1RcIixcbiAgICAgICAgICBcImFwaWdhdGV3YXk6R0VUXCIsXG4gICAgICAgIF0sXG4gICAgICAgIHJlc291cmNlczogW1xuICAgICAgICAgIHN0YWNrLmZvcm1hdEFybih7XG4gICAgICAgICAgICBzZXJ2aWNlOiBcImFwaWdhdGV3YXlcIixcbiAgICAgICAgICAgIGFjY291bnQ6IFwiXCIsXG4gICAgICAgICAgICByZXNvdXJjZTogYC9hcGlzLyR7dGhpcy5hcGkuYXBpSWR9L21vZGVsc2AsXG4gICAgICAgICAgfSksXG4gICAgICAgICAgc3RhY2suZm9ybWF0QXJuKHtcbiAgICAgICAgICAgIHNlcnZpY2U6IFwiYXBpZ2F0ZXdheVwiLFxuICAgICAgICAgICAgYWNjb3VudDogXCJcIixcbiAgICAgICAgICAgIHJlc291cmNlOiBgL2FwaXMvJHt0aGlzLmFwaS5hcGlJZH0vbW9kZWxzLypgLFxuICAgICAgICAgIH0pLFxuICAgICAgICBdLFxuICAgICAgfSlcbiAgICApO1xuICAgIHNjaGVtYUhhbmRsZXIuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFtcImFwaWdhdGV3YXk6UEFUQ0hcIiwgXCJhcGlnYXRld2F5OkdFVFwiXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgc3RhY2suZm9ybWF0QXJuKHtcbiAgICAgICAgICAgIHNlcnZpY2U6IFwiYXBpZ2F0ZXdheVwiLFxuICAgICAgICAgICAgYWNjb3VudDogXCJcIixcbiAgICAgICAgICAgIHJlc291cmNlOiBgL2FwaXMvJHt0aGlzLmFwaS5hcGlJZH0vcm91dGVzYCxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBzdGFjay5mb3JtYXRBcm4oe1xuICAgICAgICAgICAgc2VydmljZTogXCJhcGlnYXRld2F5XCIsXG4gICAgICAgICAgICBhY2NvdW50OiBcIlwiLFxuICAgICAgICAgICAgcmVzb3VyY2U6IGAvYXBpcy8ke3RoaXMuYXBpLmFwaUlkfS9yb3V0ZXMvKmAsXG4gICAgICAgICAgfSksXG4gICAgICAgIF0sXG4gICAgICB9KVxuICAgICk7XG5cbiAgICBOYWdTdXBwcmVzc2lvbnMuYWRkUmVzb3VyY2VTdXBwcmVzc2lvbnMoXG4gICAgICBzY2hlbWFIYW5kbGVyLFxuICAgICAgW1wiQXdzUHJvdG90eXBpbmctSUFNTm9XaWxkY2FyZFBlcm1pc3Npb25zXCIsIFwiQXdzU29sdXRpb25zLUlBTTVcIl0ubWFwKFxuICAgICAgICAocnVsZUlkKSA9PiAoe1xuICAgICAgICAgIGlkOiBydWxlSWQsXG4gICAgICAgICAgcmVhc29uOiBgU2NoZW1hIGN1c3RvbSByZXNvdXJjZSBtYW5hZ2VzIGFsbCByb3V0ZXMgYW5kIG1vZGVsc2AsXG4gICAgICAgIH0pXG4gICAgICApLFxuICAgICAgdHJ1ZVxuICAgICk7XG5cbiAgICBjb25zdCBwcm92aWRlclJvbGUgPSBuZXcgUm9sZSh0aGlzLCBcIlByZXBhcmVTcGVjUHJvdmlkZXJSb2xlXCIsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IFNlcnZpY2VQcmluY2lwYWwoXCJsYW1iZGEuYW1hem9uYXdzLmNvbVwiKSxcbiAgICAgIGlubGluZVBvbGljaWVzOiB7XG4gICAgICAgIGxvZ3M6IG5ldyBQb2xpY3lEb2N1bWVudCh7XG4gICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgXCJsb2dzOkNyZWF0ZUxvZ0dyb3VwXCIsXG4gICAgICAgICAgICAgICAgXCJsb2dzOkNyZWF0ZUxvZ1N0cmVhbVwiLFxuICAgICAgICAgICAgICAgIFwibG9nczpQdXRMb2dFdmVudHNcIixcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgICAgICAgYGFybjphd3M6bG9nczoke3N0YWNrLnJlZ2lvbn06JHtzdGFjay5hY2NvdW50fTpsb2ctZ3JvdXA6L2F3cy9sYW1iZGEvKmAsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICBdLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBwcm92aWRlciA9IG5ldyBQcm92aWRlcih0aGlzLCBcIlNjaGVtYVByb3ZpZGVyXCIsIHtcbiAgICAgIG9uRXZlbnRIYW5kbGVyOiBzY2hlbWFIYW5kbGVyLFxuICAgICAgcm9sZTogcHJvdmlkZXJSb2xlLFxuICAgIH0pO1xuXG4gICAgTmFnU3VwcHJlc3Npb25zLmFkZFJlc291cmNlU3VwcHJlc3Npb25zKFxuICAgICAgcHJvdmlkZXJSb2xlLFxuICAgICAgW1wiQXdzUHJvdG90eXBpbmctSUFNTm9XaWxkY2FyZFBlcm1pc3Npb25zXCIsIFwiQXdzU29sdXRpb25zLUlBTTVcIl0ubWFwKFxuICAgICAgICAocnVsZUlkKSA9PiAoe1xuICAgICAgICAgIGlkOiBydWxlSWQsXG4gICAgICAgICAgcmVhc29uOiBgQ3VzdG9tIHJlc291cmNlIHByb3ZpZGVyIG1heSBpbnZva2UgYXJiaXRyYXJ5IGxhbWJkYSB2ZXJzaW9uc2AsXG4gICAgICAgIH0pXG4gICAgICApLFxuICAgICAgdHJ1ZVxuICAgICk7XG4gICAgTmFnU3VwcHJlc3Npb25zLmFkZFJlc291cmNlU3VwcHJlc3Npb25zKFxuICAgICAgcHJvdmlkZXIsXG4gICAgICBbXCJBd3NQcm90b3R5cGluZy1MYW1iZGFMYXRlc3RWZXJzaW9uXCIsIFwiQXdzU29sdXRpb25zLUwxXCJdLm1hcChcbiAgICAgICAgKHJ1bGVJZCkgPT4gKHtcbiAgICAgICAgICBpZDogcnVsZUlkLFxuICAgICAgICAgIHJlYXNvbjogYFByb3ZpZGVyIGZyYW1ld29yayBsYW1iZGEgaXMgbWFuYWdlZCBieSBDREtgLFxuICAgICAgICB9KVxuICAgICAgKSxcbiAgICAgIHRydWVcbiAgICApO1xuXG4gICAgY29uc3Qgc2NoZW1hQ3VzdG9tUmVzb3VyY2VQcm9wZXJ0aWVzOiBXZWJTb2NrZXRTY2hlbWFSZXNvdXJjZVByb3BlcnRpZXMgPSB7XG4gICAgICBhcGlJZDogdGhpcy5hcGkuYXBpSWQsXG4gICAgICBpbnB1dFNwZWNMb2NhdGlvbjoge1xuICAgICAgICBidWNrZXQ6IGlucHV0U3BlYy5zM0J1Y2tldE5hbWUsXG4gICAgICAgIGtleTogaW5wdXRTcGVjLnMzT2JqZWN0S2V5LFxuICAgICAgfSxcbiAgICAgIHNlcnZlck9wZXJhdGlvblBhdGhzLFxuICAgIH07XG5cbiAgICBjb25zdCBzY2hlbWFDdXN0b21SZXNvdXJjZSA9IG5ldyBDdXN0b21SZXNvdXJjZShcbiAgICAgIHRoaXMsXG4gICAgICBcIlNjaGVtYUN1c3RvbVJlc291cmNlXCIsXG4gICAgICB7XG4gICAgICAgIHNlcnZpY2VUb2tlbjogcHJvdmlkZXIuc2VydmljZVRva2VuLFxuICAgICAgICBwcm9wZXJ0aWVzOiBzY2hlbWFDdXN0b21SZXNvdXJjZVByb3BlcnRpZXMsXG4gICAgICB9XG4gICAgKTtcblxuICAgIC8vIEFkZCBhIHJvdXRlIGZvciBldmVyeSBpbnRlZ3JhdGlvblxuICAgIE9iamVjdC5lbnRyaWVzKHByb3BzLmludGVncmF0aW9ucykuZm9yRWFjaCgoW29wZXJhdGlvbklkLCBpbnRlZ3JhdGlvbl0pID0+IHtcbiAgICAgIGNvbnN0IG9wID0gcHJvcHMub3BlcmF0aW9uTG9va3VwW29wZXJhdGlvbklkXTtcbiAgICAgIGlmICghb3ApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBJbnRlZ3JhdGlvbiBub3QgZm91bmQgaW4gb3BlcmF0aW9uIGxvb2t1cCBmb3Igb3BlcmF0aW9uICR7b3BlcmF0aW9uSWR9YFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBBZGQgdGhlIHJvdXRlXG4gICAgICBjb25zdCByb3V0ZUtleSA9IG9wLnBhdGgucmVwbGFjZSgvXFwvL2csIFwiXCIpO1xuICAgICAgY29uc3Qgcm91dGUgPSB0aGlzLmFkZFJvdXRlKHJvdXRlS2V5LCB7XG4gICAgICAgIGludGVncmF0aW9uOiBpbnRlZ3JhdGlvbi5pbnRlZ3JhdGlvbixcbiAgICAgIH0pO1xuICAgICAgTmFnU3VwcHJlc3Npb25zLmFkZFJlc291cmNlU3VwcHJlc3Npb25zKFxuICAgICAgICByb3V0ZSxcbiAgICAgICAgW1wiQXdzUHJvdG90eXBpbmctQVBJR1dBdXRob3JpemF0aW9uXCIsIFwiQXdzU29sdXRpb25zLUFQSUc0XCJdLm1hcChcbiAgICAgICAgICAocnVsZUlkKSA9PiAoe1xuICAgICAgICAgICAgaWQ6IHJ1bGVJZCxcbiAgICAgICAgICAgIHJlYXNvbjogYEF1dGhvcml6ZXJzIG9ubHkgYXBwbHkgdG8gdGhlICRjb25uZWN0IHJvdXRlYCxcbiAgICAgICAgICB9KVxuICAgICAgICApLFxuICAgICAgICB0cnVlXG4gICAgICApO1xuXG4gICAgICAvLyBBc3NvY2lhdGUgdGhlIHJvdXRlIHdpdGggaXRzIGNvcnJlc3BvbmRpbmcgc2NoZW1hICh3aGljaCBpcyBjcmVhdGVkIGJ5IHRoZSBjdXN0b20gcmVzb3VyY2UpXG4gICAgICBpZiAoc2NoZW1hc1tyb3V0ZUtleV0pIHtcbiAgICAgICAgKHJvdXRlLm5vZGUuZGVmYXVsdENoaWxkIGFzIENmblJvdXRlKS5yZXF1ZXN0TW9kZWxzID0ge1xuICAgICAgICAgIG1vZGVsOiByb3V0ZUtleSxcbiAgICAgICAgfTtcbiAgICAgICAgKHJvdXRlLm5vZGUuZGVmYXVsdENoaWxkIGFzIENmblJvdXRlKS5tb2RlbFNlbGVjdGlvbkV4cHJlc3Npb24gPVxuICAgICAgICAgIFwibW9kZWxcIjtcbiAgICAgIH1cbiAgICAgIHJvdXRlLm5vZGUuYWRkRGVwZW5kZW5jeShzY2hlbWFDdXN0b21SZXNvdXJjZSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgcm91dGUgdG8gdGhlIHdlYnNvY2tldCBhcGlcbiAgICovXG4gIHByaXZhdGUgYWRkUm91dGUocm91dGVLZXk6IHN0cmluZywgb3B0aW9uczogV2ViU29ja2V0Um91dGVPcHRpb25zKSB7XG4gICAgLy8gVW5sZXNzIGRpc2FibGVNb2NrSW50ZWdyYXRpb25SZXNwb25zZXMgaXMgdHJ1ZSwgd2UgYXV0b21hdGljYWxseSBjb25maWd1cmUgdGhlIGludGVncmF0aW9uIHJlcXVlc3RzIGFuZCByZXNwb25zZXNcbiAgICAvLyByZXF1aXJlZCB0byBzdWNjZXNzZnVsbHkgbW9jayB0aGUgcm91dGUsIHdoZW4gdGhlIGludGVncmF0aW9uIGlzIGEgbW9jayBpbnRlZ3JhdGlvblxuICAgIGNvbnN0IHNob3VsZEFkZE1vY2tSZXNwb25zZSA9XG4gICAgICAhdGhpcy5fcHJvcHMuZGlzYWJsZU1vY2tJbnRlZ3JhdGlvblJlc3BvbnNlcyAmJlxuICAgICAgb3B0aW9ucy5pbnRlZ3JhdGlvbiBpbnN0YW5jZW9mIFdlYlNvY2tldE1vY2tJbnRlZ3JhdGlvbjtcblxuICAgIGNvbnN0IHJvdXRlID0gdGhpcy5hcGkuYWRkUm91dGUocm91dGVLZXksIHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICByZXR1cm5SZXNwb25zZTogc2hvdWxkQWRkTW9ja1Jlc3BvbnNlLFxuICAgIH0pO1xuXG4gICAgaWYgKFxuICAgICAgc2hvdWxkQWRkTW9ja1Jlc3BvbnNlICYmXG4gICAgICAoKG9wdGlvbnMuaW50ZWdyYXRpb24gYXMgYW55KT8uaW50ZWdyYXRpb24gYXMgV2ViU29ja2V0SW50ZWdyYXRpb24pXG4gICAgICAgID8uaW50ZWdyYXRpb25JZFxuICAgICkge1xuICAgICAgY29uc3QgaW50ZWdyYXRpb24gPSAob3B0aW9ucy5pbnRlZ3JhdGlvbiBhcyBhbnkpXG4gICAgICAgID8uaW50ZWdyYXRpb24gYXMgV2ViU29ja2V0SW50ZWdyYXRpb247XG4gICAgICAoaW50ZWdyYXRpb24ubm9kZS5kZWZhdWx0Q2hpbGQgYXMgQ2ZuSW50ZWdyYXRpb24pLnJlcXVlc3RUZW1wbGF0ZXMgPSB7XG4gICAgICAgIFwiYXBwbGljYXRpb24vanNvblwiOiAne1wic3RhdHVzQ29kZVwiOjIwMH0nLFxuICAgICAgfTtcblxuICAgICAgbmV3IENmbkludGVncmF0aW9uUmVzcG9uc2UodGhpcywgYCR7cm91dGVLZXl9SW50ZWdSZXNgLCB7XG4gICAgICAgIGFwaUlkOiB0aGlzLmFwaS5hcGlJZCxcbiAgICAgICAgaW50ZWdyYXRpb25JZDogaW50ZWdyYXRpb24uaW50ZWdyYXRpb25JZCxcbiAgICAgICAgaW50ZWdyYXRpb25SZXNwb25zZUtleTogXCIvMlxcXFxkXFxcXGQvXCIsXG4gICAgICAgIHRlbXBsYXRlU2VsZWN0aW9uRXhwcmVzc2lvbjogXCIvMlxcXFxkXFxcXGQvXCIsXG4gICAgICAgIHJlc3BvbnNlVGVtcGxhdGVzOiB7XG4gICAgICAgICAgXCIyMDBcIjogJ3tcInN0YXR1c0NvZGVcIjoyMDB9JyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiByb3V0ZTtcbiAgfVxufVxuIl19