UNPKG

image-scanner-with-trivy

Version:

Scan container images with Trivy in CDK deployment

185 lines 35.6 kB
"use strict"; var _a, _b; Object.defineProperty(exports, "__esModule", { value: true }); exports.ImageScannerWithTrivy = exports.ScanLogsOutput = exports.ImageConfigScanners = exports.Scanners = exports.Severity = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const path_1 = require("path"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_ecr_assets_1 = require("aws-cdk-lib/aws-ecr-assets"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const aws_logs_1 = require("aws-cdk-lib/aws-logs"); const custom_resources_1 = require("aws-cdk-lib/custom-resources"); const constructs_1 = require("constructs"); const types_1 = require("./types"); /** * Enum for Severity Selection * * @see https://aquasecurity.github.io/trivy/latest/docs/scanner/vulnerability/#severity-selection */ var Severity; (function (Severity) { Severity["UNKNOWN"] = "UNKNOWN"; Severity["LOW"] = "LOW"; Severity["MEDIUM"] = "MEDIUM"; Severity["HIGH"] = "HIGH"; Severity["CRITICAL"] = "CRITICAL"; })(Severity || (exports.Severity = Severity = {})); /** * Enum for Scanners * * @see https://aquasecurity.github.io/trivy/latest/docs/configuration/others/#enabledisable-scanners */ var Scanners; (function (Scanners) { Scanners["VULN"] = "vuln"; Scanners["CONFIG"] = "config"; Scanners["SECRET"] = "secret"; Scanners["LICENSE"] = "license"; })(Scanners || (exports.Scanners = Scanners = {})); /** * Enum for ImageConfigScanners * * @see https://aquasecurity.github.io/trivy/latest/docs/target/container_image/#container-image-metadata */ var ImageConfigScanners; (function (ImageConfigScanners) { ImageConfigScanners["CONFIG"] = "config"; ImageConfigScanners["SECRET"] = "secret"; })(ImageConfigScanners || (exports.ImageConfigScanners = ImageConfigScanners = {})); /** * Represents the output of the scan logs. */ class ScanLogsOutput { /** * Scan logs output to CloudWatch Logs log group. */ static cloudWatchLogs(options) { return new CloudWatchLogsOutput(options); } } exports.ScanLogsOutput = ScanLogsOutput; _a = JSII_RTTI_SYMBOL_1; ScanLogsOutput[_a] = { fqn: "image-scanner-with-trivy.ScanLogsOutput", version: "2.0.0" }; class CloudWatchLogsOutput extends ScanLogsOutput { constructor(options) { super(); this.logGroup = options.logGroup; } bind(grantee) { // Most Lambdas are granted AWSLambdaBasicExecutionRole and can write to any CloudWatch Logs. // However, just in case AWSLambdaBasicExecutionRole is not granted, allow writing to CloudWatch Logs. this.logGroup.grantWrite(grantee); return { type: types_1.ScanLogsOutputType.CLOUDWATCH_LOGS, logGroupName: this.logGroup.logGroupName, }; } } // Maximum Lambda memory size for default AWS account without quota limit increase const DEFAULT_MEMORY_SIZE = 3008; class ImageScannerWithTrivy extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); if (props.memorySize && !aws_cdk_lib_1.Token.isUnresolved(props.memorySize) && (props.memorySize < 3008 || props.memorySize > 10240)) { throw new Error(`You can specify between \`3008\` and \`10240\` for \`memorySize\`, got ${props.memorySize}.`); } const lambdaPurpose = 'Custom::ImageScannerWithTrivyCustomResourceLambda'; const customResourceLambda = new aws_lambda_1.SingletonFunction(this, 'CustomResourceLambda', { uuid: '470b6343-d267-f753-226c-1e99f09f319a', lambdaPurpose, runtime: aws_lambda_1.Runtime.FROM_IMAGE, handler: aws_lambda_1.Handler.FROM_IMAGE, code: aws_lambda_1.AssetCode.fromAssetImage((0, path_1.join)(__dirname, '../assets/lambda'), { platform: aws_ecr_assets_1.Platform.LINUX_ARM64, // exclude node_modules // because the native binary of the installed esbuild changes depending on the cpu architecture // and the hash value of the image asset changes depending on the execution environment. exclude: ['node_modules'], }), architecture: aws_lambda_1.Architecture.ARM_64, timeout: aws_cdk_lib_1.Duration.seconds(900), retryAttempts: 0, memorySize: props.memorySize ?? DEFAULT_MEMORY_SIZE, ephemeralStorageSize: aws_cdk_lib_1.Size.gibibytes(10), // for cases that need to update trivy DB: /tmp/trivy/db/trivy.db }); props.repository.grantPull(customResourceLambda); const customResourceLambdaLogGroupConstructName = `DefaultLogGroupFor${lambdaPurpose}`; this.validateLambdaDefaultLogGroupOptions(customResourceLambdaLogGroupConstructName, props); if (props.defaultLogGroupRemovalPolicy || props.defaultLogGroupRetentionDays) { this.ensureLambdaDefaultLogGroup(customResourceLambda, customResourceLambdaLogGroupConstructName, props); } const imageScannerProvider = new custom_resources_1.Provider(this, 'Provider', { onEventHandler: customResourceLambda, }); const imageScannerProperties = { addr: this.node.addr, imageUri: props.imageUri, ignoreUnfixed: String(props.ignoreUnfixed ?? false), severity: props.severity ?? [Severity.CRITICAL], scanners: props.scanners ?? [], imageConfigScanners: props.imageConfigScanners ?? [], exitCode: props.exitCode ?? 1, exitOnEol: props.exitOnEol ?? 1, trivyIgnore: props.trivyIgnore ?? [], platform: props.platform ?? '', output: props.scanLogsOutput?.bind(customResourceLambda), }; new aws_cdk_lib_1.CustomResource(this, 'Resource', { resourceType: 'Custom::ImageScannerWithTrivy', properties: imageScannerProperties, serviceToken: imageScannerProvider.serviceToken, }); } /** * Validates that specified default log group options are the same for existing default log group. */ validateLambdaDefaultLogGroupOptions(logGroupConstructName, props) { const existing = aws_cdk_lib_1.Stack.of(this).node.tryFindChild(logGroupConstructName); if (!existing) return; const cfnLogGroup = existing.node.defaultChild; if (!this.isSameResourceDeletionBehavior(props.defaultLogGroupRemovalPolicy, cfnLogGroup.cfnOptions.deletionPolicy) || cfnLogGroup.retentionInDays !== props.defaultLogGroupRetentionDays) { aws_cdk_lib_1.Annotations.of(this).addWarningV2('@image-scanner-with-trivy:duplicateLambdaDefaultLogGroupOptions', "You have to set the same values for 'defaultLogGroupRemovalPolicy' and 'defaultLogGroupRetentionDays' for each ImageScannerWithTrivy construct in the same stack."); } } /** * Creates the default log group for Scanner Lambda if it does not exist. * * This method checks if the default log group for Scanner Lambda exists in children of the stack construct. * If it does not exist, it creates the default log group for Scanner Lambda as a child of the stack construct. */ ensureLambdaDefaultLogGroup(singletonFunction, logGroupConstructName, props) { const existing = aws_cdk_lib_1.Stack.of(this).node.tryFindChild(logGroupConstructName); if (existing) { return existing; } return new aws_logs_1.LogGroup(aws_cdk_lib_1.Stack.of(this), logGroupConstructName, { logGroupName: `/aws/lambda/${singletonFunction.functionName}`, retention: props.defaultLogGroupRetentionDays, removalPolicy: props.defaultLogGroupRemovalPolicy, }); } isSameResourceDeletionBehavior(removalPolicy, deletionPolicy) { switch (removalPolicy) { case aws_cdk_lib_1.RemovalPolicy.DESTROY: return deletionPolicy === aws_cdk_lib_1.CfnDeletionPolicy.DELETE; case aws_cdk_lib_1.RemovalPolicy.RETAIN: return deletionPolicy === aws_cdk_lib_1.CfnDeletionPolicy.RETAIN; case aws_cdk_lib_1.RemovalPolicy.SNAPSHOT: return deletionPolicy === aws_cdk_lib_1.CfnDeletionPolicy.SNAPSHOT; case aws_cdk_lib_1.RemovalPolicy.RETAIN_ON_UPDATE_OR_DELETE: return deletionPolicy === aws_cdk_lib_1.CfnDeletionPolicy.RETAIN_EXCEPT_ON_CREATE; case undefined: return deletionPolicy === undefined; default: return removalPolicy; } } } exports.ImageScannerWithTrivy = ImageScannerWithTrivy; _b = JSII_RTTI_SYMBOL_1; ImageScannerWithTrivy[_b] = { fqn: "image-scanner-with-trivy.ImageScannerWithTrivy", version: "2.0.0" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2Utc2Nhbm5lci13aXRoLXRyaXZ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ltYWdlLXNjYW5uZXItd2l0aC10cml2eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLCtCQUE0QjtBQUM1Qiw2Q0FTcUI7QUFFckIsK0RBQXNEO0FBRXRELHVEQU1nQztBQUNoQyxtREFBdUY7QUFDdkYsbUVBQXdEO0FBQ3hELDJDQUF1QztBQUN2QyxtQ0FLaUI7QUFFakI7Ozs7R0FJRztBQUNILElBQVksUUFNWDtBQU5ELFdBQVksUUFBUTtJQUNsQiwrQkFBbUIsQ0FBQTtJQUNuQix1QkFBVyxDQUFBO0lBQ1gsNkJBQWlCLENBQUE7SUFDakIseUJBQWEsQ0FBQTtJQUNiLGlDQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFOVyxRQUFRLHdCQUFSLFFBQVEsUUFNbkI7QUFFRDs7OztHQUlHO0FBQ0gsSUFBWSxRQUtYO0FBTEQsV0FBWSxRQUFRO0lBQ2xCLHlCQUFhLENBQUE7SUFDYiw2QkFBaUIsQ0FBQTtJQUNqQiw2QkFBaUIsQ0FBQTtJQUNqQiwrQkFBbUIsQ0FBQTtBQUNyQixDQUFDLEVBTFcsUUFBUSx3QkFBUixRQUFRLFFBS25CO0FBRUQ7Ozs7R0FJRztBQUNILElBQVksbUJBR1g7QUFIRCxXQUFZLG1CQUFtQjtJQUM3Qix3Q0FBaUIsQ0FBQTtJQUNqQix3Q0FBaUIsQ0FBQTtBQUNuQixDQUFDLEVBSFcsbUJBQW1CLG1DQUFuQixtQkFBbUIsUUFHOUI7QUFZRDs7R0FFRztBQUNILE1BQXNCLGNBQWM7SUFDbEM7O09BRUc7SUFDSSxNQUFNLENBQUMsY0FBYyxDQUFDLE9BQWtDO1FBQzdELE9BQU8sSUFBSSxvQkFBb0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUMzQyxDQUFDOztBQU5ILHdDQVlDOzs7QUFFRCxNQUFNLG9CQUFxQixTQUFRLGNBQWM7SUFNL0MsWUFBWSxPQUFrQztRQUM1QyxLQUFLLEVBQUUsQ0FBQztRQUVSLElB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SyxTQUFTLENBQUM7WUFDdEM7Z0JBQ0UsT0FBTyxhQUE2QixDQUFDO1FBQ3pDLENBQUM7SUFDSCxDQUFDOztBQS9JSCxzREFnSkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5pbXBvcnQge1xuICBBbm5vdGF0aW9ucyxcbiAgQ2ZuRGVsZXRpb25Qb2xpY3ksXG4gIEN1c3RvbVJlc291cmNlLFxuICBEdXJhdGlvbixcbiAgUmVtb3ZhbFBvbGljeSxcbiAgU2l6ZSxcbiAgU3RhY2ssXG4gIFRva2VuLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBJUmVwb3NpdG9yeSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lY3InO1xuaW1wb3J0IHsgUGxhdGZvcm0gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWNyLWFzc2V0cyc7XG5pbXBvcnQgeyBJR3JhbnRhYmxlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQge1xuICBBcmNoaXRlY3R1cmUsXG4gIEFzc2V0Q29kZSxcbiAgSGFuZGxlcixcbiAgUnVudGltZSxcbiAgU2luZ2xldG9uRnVuY3Rpb24sXG59IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgQ2ZuTG9nR3JvdXAsIElMb2dHcm91cCwgTG9nR3JvdXAsIFJldGVudGlvbkRheXMgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbG9ncyc7XG5pbXBvcnQgeyBQcm92aWRlciB9IGZyb20gJ2F3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXMnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQge1xuICBDbG91ZFdhdGNoTG9nc091dHB1dE9wdGlvbnMsXG4gIFNjYW5Mb2dzT3V0cHV0T3B0aW9ucyxcbiAgU2NhbkxvZ3NPdXRwdXRUeXBlLFxuICBTY2FubmVyQ3VzdG9tUmVzb3VyY2VQcm9wcyxcbn0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogRW51bSBmb3IgU2V2ZXJpdHkgU2VsZWN0aW9uXG4gKlxuICogQHNlZSBodHRwczovL2FxdWFzZWN1cml0eS5naXRodWIuaW8vdHJpdnkvbGF0ZXN0L2RvY3Mvc2Nhbm5lci92dWxuZXJhYmlsaXR5LyNzZXZlcml0eS1zZWxlY3Rpb25cbiAqL1xuZXhwb3J0IGVudW0gU2V2ZXJpdHkge1xuICBVTktOT1dOID0gJ1VOS05PV04nLFxuICBMT1cgPSAnTE9XJyxcbiAgTUVESVVNID0gJ01FRElVTScsXG4gIEhJR0ggPSAnSElHSCcsXG4gIENSSVRJQ0FMID0gJ0NSSVRJQ0FMJyxcbn1cblxuLyoqXG4gKiBFbnVtIGZvciBTY2FubmVyc1xuICpcbiAqIEBzZWUgaHR0cHM6Ly9hcXVhc2VjdXJpdHkuZ2l0aHViLmlvL3RyaXZ5L2xhdGVzdC9kb2NzL2NvbmZpZ3VyYXRpb24vb3RoZXJzLyNlbmFibGVkaXNhYmxlLXNjYW5uZXJzXG4gKi9cbmV4cG9ydCBlbnVtIFNjYW5uZXJzIHtcbiAgVlVMTiA9ICd2dWxuJyxcbiAgQ09ORklHID0gJ2NvbmZpZycsXG4gIFNFQ1JFVCA9ICdzZWNyZXQnLFxuICBMSUNFTlNFID0gJ2xpY2Vuc2UnLFxufVxuXG4vKipcbiAqIEVudW0gZm9yIEltYWdlQ29uZmlnU2Nhbm5lcnNcbiAqXG4gKiBAc2VlIGh0dHBzOi8vYXF1YXNlY3VyaXR5LmdpdGh1Yi5pby90cml2eS9sYXRlc3QvZG9jcy90YXJnZXQvY29udGFpbmVyX2ltYWdlLyNjb250YWluZXItaW1hZ2UtbWV0YWRhdGFcbiAqL1xuZXhwb3J0IGVudW0gSW1hZ2VDb25maWdTY2FubmVycyB7XG4gIENPTkZJRyA9ICdjb25maWcnLFxuICBTRUNSRVQgPSAnc2VjcmV0Jyxcbn1cblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciBzY2FuIGxvZ3Mgb3V0cHV0IHRvIENsb3VkV2F0Y2ggTG9ncyBsb2cgZ3JvdXAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2xvdWRXYXRjaExvZ3NPdXRwdXRQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgbG9nIGdyb3VwIHRvIG91dHB1dCBzY2FuIGxvZ3MuXG4gICAqL1xuICByZWFkb25seSBsb2dHcm91cDogSUxvZ0dyb3VwO1xufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgdGhlIG91dHB1dCBvZiB0aGUgc2NhbiBsb2dzLlxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgU2NhbkxvZ3NPdXRwdXQge1xuICAvKipcbiAgICogU2NhbiBsb2dzIG91dHB1dCB0byBDbG91ZFdhdGNoIExvZ3MgbG9nIGdyb3VwLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjbG91ZFdhdGNoTG9ncyhvcHRpb25zOiBDbG91ZFdhdGNoTG9nc091dHB1dFByb3BzKTogU2NhbkxvZ3NPdXRwdXQge1xuICAgIHJldHVybiBuZXcgQ2xvdWRXYXRjaExvZ3NPdXRwdXQob3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgb3V0cHV0IGNvbmZpZ3VyYXRpb24gZm9yIHNjYW4gbG9ncy5cbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCBiaW5kKGdyYW50ZWU6IElHcmFudGFibGUpOiBTY2FuTG9nc091dHB1dE9wdGlvbnM7XG59XG5cbmNsYXNzIENsb3VkV2F0Y2hMb2dzT3V0cHV0IGV4dGVuZHMgU2NhbkxvZ3NPdXRwdXQge1xuICAvKipcbiAgICogVGhlIGxvZyBncm91cCB0byBvdXRwdXQgc2NhbiBsb2dzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBsb2dHcm91cDogSUxvZ0dyb3VwO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IENsb3VkV2F0Y2hMb2dzT3V0cHV0UHJvcHMpIHtcbiAgICBzdXBlcigpO1xuXG4gICAgdGhpcy5sb2dHcm91cCA9IG9wdGlvbnMubG9nR3JvdXA7XG4gIH1cblxuICBwdWJsaWMgYmluZChncmFudGVlOiBJR3JhbnRhYmxlKTogQ2xvdWRXYXRjaExvZ3NPdXRwdXRPcHRpb25zIHtcbiAgICAvLyBNb3N0IExhbWJkYXMgYXJlIGdyYW50ZWQgQVdTTGFtYmRhQmFzaWNFeGVjdXRpb25Sb2xlIGFuZCBjYW4gd3JpdGUgdG8gYW55IENsb3VkV2F0Y2ggTG9ncy5cbiAgICAvLyBIb3dldmVyLCBqdXN0IGluIGNhc2UgQVdTTGFtYmRhQmFzaWNFeGVjdXRpb25Sb2xlIGlzIG5vdCBncmFudGVkLCBhbGxvdyB3cml0aW5nIHRvIENsb3VkV2F0Y2ggTG9ncy5cbiAgICB0aGlzLmxvZ0dyb3VwLmdyYW50V3JpdGUoZ3JhbnRlZSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogU2NhbkxvZ3NPdXRwdXRUeXBlLkNMT1VEV0FUQ0hfTE9HUyxcbiAgICAgIGxvZ0dyb3VwTmFtZTogdGhpcy5sb2dHcm91cC5sb2dHcm91cE5hbWUsXG4gICAgfTtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEltYWdlU2Nhbm5lcldpdGhUcml2eVByb3BzIHtcbiAgLyoqXG4gICAqIEltYWdlIFVSSSBmb3Igc2NhbiB0YXJnZXQuXG4gICAqL1xuICByZWFkb25seSBpbWFnZVVyaTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZXBvc2l0b3J5IGluY2x1ZGluZyB0aGUgaW1hZ2UgVVJJIGZvciBzY2FuIHRhcmdldC5cbiAgICpcbiAgICogQmVjYXVzZSBvZiBncmFudFB1bGwgdG8gQ3VzdG9tUmVzb3VyY2VMYW1iZGEuXG4gICAqL1xuICByZWFkb25seSByZXBvc2l0b3J5OiBJUmVwb3NpdG9yeTtcblxuICAvKipcbiAgICogVGhlIHVuZml4ZWQvdW5maXhhYmxlIHZ1bG5lcmFiaWxpdGllcyBtZWFuIHRoYXQgdGhlIHBhdGNoIGhhcyBub3QgeWV0IGJlZW4gcHJvdmlkZWQgb24gdGhlaXIgZGlzdHJpYnV0aW9uLlxuICAgKlxuICAgKiBUbyBoaWRlIHVuZml4ZWQvdW5maXhhYmxlIHZ1bG5lcmFiaWxpdGllcywgeW91IGNhbiB1c2UgdGhlIGAtLWlnbm9yZS11bmZpeGVkYCBmbGFnLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vYXF1YXNlY3VyaXR5LmdpdGh1Yi5pby90cml2eS9sYXRlc3QvZG9jcy9zY2FubmVyL3Z1bG5lcmFiaWxpdHkvI3VuZml4ZWQtdnVsbmVyYWJpbGl0aWVzXG4gICAqL1xuICByZWFkb25seSBpZ25vcmVVbmZpeGVkPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogU2V2ZXJpdHkgU2VsZWN0aW9uXG4gICAqXG4gICAqIFRoZSBzZXZlcml0eSBpcyB0YWtlbiBmcm9tIHRoZSBzZWxlY3RlZCBkYXRhIHNvdXJjZSBzaW5jZSB0aGUgc2V2ZXJpdHkgZnJvbSB2ZW5kb3JzIGlzIG1vcmUgYWNjdXJhdGUuXG4gICAqIFVzaW5nIENWRS0yMDIzLTA0NjQgYXMgYW4gZXhhbXBsZSwgd2hpbGUgaXQgaXMgcmF0ZWQgYXMgXCJISUdIXCIgaW4gTlZELCBSZWQgSGF0IGhhcyBtYXJrZWQgaXRzICdJbXBhY3QnIGFzIFwiTG93XCIuIEFzIGEgcmVzdWx0LCBUcml2eSB3aWxsIGRpc3BsYXkgaXQgYXMgXCJMb3dcIi5cbiAgICpcbiAgICogVGhlIHNldmVyaXR5IGRlcGVuZHMgb24gdGhlIGNvbXBpbGUgb3B0aW9uLCB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uLCBldGMuIE5WRCBkb2Vzbid0IGtub3cgaG93IHRoZSB2ZW5kb3IgZGlzdHJpYnV0ZXMgdGhlIHNvZnR3YXJlLlxuICAgKiBSZWQgSGF0IGV2YWx1YXRlcyB0aGUgc2V2ZXJpdHkgbW9yZSBhY2N1cmF0ZWx5LiBUaGF0J3Mgd2h5IFRyaXZ5IHByZWZlcnMgdmVuZG9yIHNjb3JlcyBvdmVyIE5WRC5cbiAgICpcbiAgICogSXQgZGVmYXVsdHMgdG8gYENSSVRJQ0FMYCBJTiBUSElTIENPTlNUUlVDVCBmb3Igc2FmZXR5IGluIENJL0NELCBidXQgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvZiBUcml2eSBpcyBcIkNSSVRJQ0FMLEhJR0gsTUVESVVNLExPVyxVTktOT1dOXCIuXG4gICAqXG4gICAqIEBkZWZhdWx0IFtTZXZlcml0eS5DUklUSUNBTF1cbiAgICpcbiAgICogQHNlZSBodHRwczovL2FxdWFzZWN1cml0eS5naXRodWIuaW8vdHJpdnkvbGF0ZXN0L2RvY3Mvc2Nhbm5lci92dWxuZXJhYmlsaXR5LyNzZXZlcml0eS1zZWxlY3Rpb25cbiAgICovXG4gIHJlYWRvbmx5IHNldmVyaXR5PzogU2V2ZXJpdHlbXTtcblxuICAvKipcbiAgICogRW5hYmxlL0Rpc2FibGUgU2Nhbm5lcnNcbiAgICpcbiAgICogWW91IGNhbiBlbmFibGUvZGlzYWJsZSBzY2FubmVycyB3aXRoIHRoZSBgc2Nhbm5lcnNgLlxuICAgKlxuICAgKiBGb3IgZXhhbXBsZSwgY29udGFpbmVyIGltYWdlIHNjYW5uaW5nIGVuYWJsZXMgdnVsbmVyYWJpbGl0eSAoVlVMTikgYW5kIHNlY3JldCBzY2FubmVycyAoU0VDUkVUKSBieSBkZWZhdWx0LlxuICAgKiBJZiB5b3UgZG9uJ3QgbmVlZCBzZWNyZXQgc2Nhbm5pbmcsIGl0IGNhbiBiZSBkaXNhYmxlZCBieSBzcGVjaWZ5aW5nIFNjYW5uZXJzLlZVTE4gb25seS5cbiAgICpcbiAgICogQGRlZmF1bHQgW1NlY3VyaXR5LlZVTE4sU2Nhbm5lcnMuU0VDUkVUXVxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vYXF1YXNlY3VyaXR5LmdpdGh1Yi5pby90cml2eS9sYXRlc3QvZG9jcy9jb25maWd1cmF0aW9uL290aGVycy8jZW5hYmxlZGlzYWJsZS1zY2FubmVyc1xuICAgKi9cbiAgcmVhZG9ubHkgc2Nhbm5lcnM/OiBTY2FubmVyc1tdO1xuXG4gIC8qKlxuICAgKiBFbnVtIGZvciBJbWFnZUNvbmZpZ1NjYW5uZXJzXG4gICAqXG4gICAqIENvbnRhaW5lciBpbWFnZXMgaGF2ZSBjb25maWd1cmF0aW9uLiBkb2NrZXIgaW5zcGVjdCBhbmQgYGRvY2tlciBoaXN0b3J5YCBzaG93IHRoZSBpbmZvcm1hdGlvbiBhY2NvcmRpbmcgdG8gdGhlIGNvbmZpZ3VyYXRpb24uXG4gICAqIFRyaXZ5IHNjYW5zIHRoZSBjb25maWd1cmF0aW9uIG9mIGNvbnRhaW5lciBpbWFnZXMgZm9yXG4gICAqXG4gICAqIC0gTWlzY29uZmlndXJhdGlvbnNcbiAgICogLSBTZWNyZXRzXG4gICAqXG4gICAqIFRoZXkgYXJlIGRpc2FibGVkIGJ5IGRlZmF1bHQuIFlvdSBjYW4gZW5hYmxlIHRoZW0gd2l0aCBgaW1hZ2VDb25maWdTY2FubmVyc2AuXG4gICAqXG4gICAqIEBkZWZhdWx0IFtdXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9hcXVhc2VjdXJpdHkuZ2l0aHViLmlvL3RyaXZ5L2xhdGVzdC9kb2NzL3RhcmdldC9jb250YWluZXJfaW1hZ2UvI2NvbnRhaW5lci1pbWFnZS1tZXRhZGF0YVxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2VDb25maWdTY2FubmVycz86IEltYWdlQ29uZmlnU2Nhbm5lcnNbXTtcblxuICAvKipcbiAgICogRXhpdCBDb2RlXG4gICAqXG4gICAqIFVzZSB0aGUgYGV4aXRDb2RlYCBvcHRpb24gaWYgeW91IHdhbnQgdG8gZXhpdCB3aXRoIGEgbm9uLXplcm8gZXhpdCBjb2RlLlxuICAgKlxuICAgKiBZb3UgY2FuIHNwZWNpZnkgMCBpZiB5b3UgZG8gbm90IHdhbnQgdG8gZXhpdCBldmVuIHdoZW4gdnVsbmVyYWJpbGl0aWVzIGFyZSBkZXRlY3RlZC5cbiAgICpcbiAgICogSXQgZGVmYXVsdHMgdG8gMSBJTiBUSElTIENPTlNUUlVDVCBmb3Igc2FmZXR5IGluIENJL0NELiBJbiB0aGUgb3JpZ2luYWwgdHJpdnksIGl0IGlzIDAuXG4gICAqXG4gICAqIEBkZWZhdWx0IDFcbiAgICpcbiAgICogQHNlZSBodHRwczovL2FxdWFzZWN1cml0eS5naXRodWIuaW8vdHJpdnkvbGF0ZXN0L2RvY3MvY29uZmlndXJhdGlvbi9vdGhlcnMvI2V4aXQtY29kZVxuICAgKi9cbiAgcmVhZG9ubHkgZXhpdENvZGU/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEV4aXQgb24gRU9MXG4gICAqXG4gICAqIFNvbWV0aW1lcyB5b3UgbWF5IHN1cnByaXNpbmdseSBnZXQgMCB2dWxuZXJhYmlsaXRpZXMgaW4gYW4gb2xkIGltYWdlOlxuICAgKiAgLSBFbmFibGluZyAtLWlnbm9yZS11bmZpeGVkIG9wdGlvbiB3aGlsZSBhbGwgcGFja2FnZXMgaGF2ZSBubyBmaXhlZCB2ZXJzaW9ucy5cbiAgICogIC0gU2Nhbm5pbmcgYSByYXRoZXIgb3V0ZGF0ZWQgT1MgKGUuZy4gVWJ1bnR1IDEwLjA0KS5cbiAgICpcbiAgICogQW4gT1MgYXQgdGhlIGVuZCBvZiBzZXJ2aWNlL2xpZmUgKEVPTCkgdXN1YWxseSBnZXRzIGludG8gdGhpcyBzaXR1YXRpb24sIHdoaWNoIGlzIGRlZmluaXRlbHkgZnVsbCBvZiB2dWxuZXJhYmlsaXRpZXMuXG4gICAqIGBleGl0T25Fb2xgIGNhbiBmYWlsIHNjYW5uaW5nIG9uIEVPTCBPUyB3aXRoIGEgbm9uLXplcm8gY29kZS5cbiAgICpcbiAgICogSXQgZGVmYXVsdHMgdG8gMSBJTiBUSElTIENPTlNUUlVDVCBmb3Igc2FmZXR5IGluIENJL0NELiBJbiB0aGUgb3JpZ2luYWwgdHJpdnksIGl0IGlzIDAuXG4gICAqXG4gICAqIEBkZWZhdWx0IDFcbiAgICpcbiAgICogQHNlZSBodHRwczovL2FxdWFzZWN1cml0eS5naXRodWIuaW8vdHJpdnkvbGF0ZXN0L2RvY3MvY29uZmlndXJhdGlvbi9vdGhlcnMvI2V4aXQtb24tZW9sXG4gICAqL1xuICByZWFkb25seSBleGl0T25Fb2w/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEJ5IEZpbmRpbmcgSURzXG4gICAqXG4gICAqIFRoZSBpZ25vcmUgcnVsZXMgd3JpdHRlbiB0byB0aGUgLnRyaXZ5aWdub3JlIGluIHRyaXZ5LlxuICAgKiBQdXQgZWFjaCBsaW5lIHlvdSB3cml0ZSBpbiB0aGUgZmlsZSBpbnRvIG9uZSBlbGVtZW50IG9mIHRoZSBhcnJheS5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogICAgICQgY2F0IC50cml2eWlnbm9yZVxuICAgKiAgICAgIyBBY2NlcHQgdGhlIHJpc2tcbiAgICogICAgIENWRS0yMDE4LTE0NjE4XG4gICAqXG4gICAqICAgICAjIEFjY2VwdCB0aGUgcmlzayB1bnRpbCAyMDIzLTAxLTAxXG4gICAqICAgICBDVkUtMjAxOS0xNDY5NyBleHA6MjAyMy0wMS0wMVxuICAgKlxuICAgKiAgICAgIyBObyBpbXBhY3QgaW4gb3VyIHNldHRpbmdzXG4gICAqICAgICBDVkUtMjAxOS0xNTQzXG4gICAqXG4gICAqICAgICAjIElnbm9yZSBtaXNjb25maWd1cmF0aW9uc1xuICAgKiAgICAgQVZELURTLTAwMDJcbiAgICpcbiAgICogICAgICMgSWdub3JlIHNlY3JldHNcbiAgICogICAgIGdlbmVyaWMtdW53YW50ZWQtcnVsZVxuICAgKiAgICAgYXdzLWFjY291bnQtaWRcbiAgICpcbiAgICogQGRlZmF1bHQgW11cbiAgICpcbiAgICogQHNlZSBodHRwczovL2FxdWFzZWN1cml0eS5naXRodWIuaW8vdHJpdnkvbGF0ZXN0L2RvY3MvY29uZmlndXJhdGlvbi9maWx0ZXJpbmcvI3RyaXZ5aWdub3JlXG4gICAqL1xuICByZWFkb25seSB0cml2eUlnbm9yZT86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBNZW1vcnkgU2l6ZSAoTUIpIGZvciBTY2FubmVyIExhbWJkYVxuICAgKlxuICAgKiBZb3UgY2FuIHNwZWNpZnkgYmV0d2VlbiBgMzAwOGAgYW5kIGAxMDI0MGAuXG4gICAqXG4gICAqIElmIHRoaXMgQ29uc3RydWN0IGV4ZWN1dGlvbiB0ZXJtaW5hdGVzIGFibm9ybWFsbHkgZHVlIHRvIFNJR0tJTEwsIHRyeSBhIGxhcmdlciBzaXplLlxuICAgKlxuICAgKiBEZWZhdWx0IHZhbHVlIChgMzAwOGAgTUIpIGlzIE1heGltdW0gTGFtYmRhIG1lbW9yeSBzaXplIGZvciBkZWZhdWx0IEFXUyBhY2NvdW50IHdpdGhvdXQgcXVvdGEgbGltaXQgaW5jcmVhc2UuXG4gICAqXG4gICAqIEBkZWZhdWx0IDMwMDhcbiAgICovXG4gIHJlYWRvbmx5IG1lbW9yeVNpemU/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFNjYW4gSW1hZ2Ugb24gYSBzcGVjaWZpYyBBcmNoaXRlY3R1cmUgYW5kIE9TXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQsIFRyaXZ5IGxvYWRzIGFuIGltYWdlIG9uIGEgYGxpbnV4L2FtZDY0YCBtYWNoaW5lLlxuICAgKlxuICAgKiBUbyBjdXN0b21pemUgdGhpcywgcGFzcyBhIGBwbGF0Zm9ybWAgYXJndW1lbnQgaW4gdGhlIGZvcm1hdCBPUy9BcmNoaXRlY3R1cmUgZm9yIHRoZSBpbWFnZSwgc3VjaCBhcyBgbGludXgvYXJtNjRgXG4gICAqXG4gICAqIEBkZWZhdWx0IC1cbiAgICovXG4gIHJlYWRvbmx5IHBsYXRmb3JtPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVtb3ZhbCBwb2xpY3kgdG8gYXBwbHkgdG8gU2Nhbm5lciBMYW1iZGEncyBkZWZhdWx0IGxvZyBncm91cFxuICAgKlxuICAgKiBJZiB5b3UgdXNlIEltYWdlU2Nhbm5lcldpdGhUcml2eSBjb25zdHJ1Y3QgbXVsdGlwbGUgdGltZXMgaW4gdGhlIHNhbWUgc3RhY2ssIHlvdSBjYW5ub3Qgc2V0IGRpZmZlcmVudCByZW1vdmFsIHBvbGljaWVzIGZvciB0aGUgZGVmYXVsdCBsb2cgZ3JvdXAuXG4gICAqIFNlZSBgTm90ZXNgIHNlY3Rpb24gaW4gdGhlIFJFQURNRSBmb3IgbW9yZSBkZXRhaWxzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFNjYW5uZXIgTGFtYmRhIGNyZWF0ZXMgdGhlIGRlZmF1bHQgbG9nIGdyb3VwKGAvYXdzL2xhbWJkYS8ke2Z1bmN0aW9uTmFtZX1gKS5cbiAgICovXG4gIHJlYWRvbmx5IGRlZmF1bHRMb2dHcm91cFJlbW92YWxQb2xpY3k/OiBSZW1vdmFsUG9saWN5O1xuXG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIGRheXMgbG9nIGV2ZW50cyBhcmUga2VwdCBpbiBTY2FubmVyIExhbWJkYSdzIGRlZmF1bHQgbG9nIGdyb3VwXG4gICAqXG4gICAqIElmIHlvdSB1c2UgSW1hZ2VTY2FubmVyV2l0aFRyaXZ5IGNvbnN0cnVjdCBtdWx0aXBsZSB0aW1lcyBpbiB0aGUgc2FtZSBzdGFjaywgeW91IGNhbm5vdCBzZXQgZGlmZmVyZW50IHJldGVudGlvbiBkYXlzIGZvciB0aGUgZGVmYXVsdCBsb2cgZ3JvdXAuXG4gICAqIFNlZSBgTm90ZXNgIHNlY3Rpb24gaW4gdGhlIFJFQURNRSBmb3IgbW9yZSBkZXRhaWxzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFNjYW5uZXIgTGFtYmRhIGNyZWF0ZXMgdGhlIGRlZmF1bHQgbG9nIGdyb3VwKGAvYXdzL2xhbWJkYS8ke2Z1bmN0aW9uTmFtZX1gKSBhbmQgbG9nIGV2ZW50cyBuZXZlciBleHBpcmUuXG4gICAqL1xuICByZWFkb25seSBkZWZhdWx0TG9nR3JvdXBSZXRlbnRpb25EYXlzPzogUmV0ZW50aW9uRGF5cztcblxuICAvKipcbiAgICogQ29uZmlndXJhdGlvbiBmb3Igc2NhbiBsb2dzIG91dHB1dFxuICAgKlxuICAgKiBCeSBkZWZhdWx0LCBzY2FuIGxvZ3MgYXJlIG91dHB1dCB0byBkZWZhdWx0IGxvZyBncm91cCBjcmVhdGVkIGJ5IFNjYW5uZXIgTGFtYmRhLlxuICAgKlxuICAgKiBTcGVjaWZ5IHRoaXMgaWYgeW91IHdhbnQgdG8gc2VuZCBzY2FuIGxvZ3MgdG8gb3RoZXIgdGhhbiB0aGUgZGVmYXVsdCBsb2cgZ3JvdXAuXG4gICAqXG4gICAqIEN1cnJlbnRseSwgb25seSBgY2xvdWRXYXRjaExvZ3NgIGlzIHN1cHBvcnRlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBzY2FuIGxvZ3Mgb3V0cHV0IHRvIGRlZmF1bHQgbG9nIGdyb3VwIGNyZWF0ZWQgYnkgU2Nhbm5lciBMYW1iZGEoYC9hd3MvbGFtYmRhLyR7ZnVuY3Rpb25OYW1lfWApXG4gICAqL1xuICByZWFkb25seSBzY2FuTG9nc091dHB1dD86IFNjYW5Mb2dzT3V0cHV0O1xufVxuXG4vLyBNYXhpbXVtIExhbWJkYSBtZW1vcnkgc2l6ZSBmb3IgZGVmYXVsdCBBV1MgYWNjb3VudCB3aXRob3V0IHF1b3RhIGxpbWl0IGluY3JlYXNlXG5jb25zdCBERUZBVUxUX01FTU9SWV9TSVpFID0gMzAwODtcblxuZXhwb3J0IGNsYXNzIEltYWdlU2Nhbm5lcldpdGhUcml2eSBleHRlbmRzIENvbnN0cnVjdCB7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBJbWFnZVNjYW5uZXJXaXRoVHJpdnlQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBpZiAoXG4gICAgICBwcm9wcy5tZW1vcnlTaXplICYmXG4gICAgICAhVG9rZW4uaXNVbnJlc29sdmVkKHByb3BzLm1lbW9yeVNpemUpICYmXG4gICAgICAocHJvcHMubWVtb3J5U2l6ZSA8IDMwMDggfHwgcHJvcHMubWVtb3J5U2l6ZSA+IDEwMjQwKVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgWW91IGNhbiBzcGVjaWZ5IGJldHdlZW4gXFxgMzAwOFxcYCBhbmQgXFxgMTAyNDBcXGAgZm9yIFxcYG1lbW9yeVNpemVcXGAsIGdvdCAke3Byb3BzLm1lbW9yeVNpemV9LmAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGxhbWJkYVB1cnBvc2UgPSAnQ3VzdG9tOjpJbWFnZVNjYW5uZXJXaXRoVHJpdnlDdXN0b21SZXNvdXJjZUxhbWJkYSc7XG4gICAgY29uc3QgY3VzdG9tUmVzb3VyY2VMYW1iZGEgPSBuZXcgU2luZ2xldG9uRnVuY3Rpb24odGhpcywgJ0N1c3RvbVJlc291cmNlTGFtYmRhJywge1xuICAgICAgdXVpZDogJzQ3MGI2MzQzLWQyNjctZjc1My0yMjZjLTFlOTlmMDlmMzE5YScsXG4gICAgICBsYW1iZGFQdXJwb3NlLFxuICAgICAgcnVudGltZTogUnVudGltZS5GUk9NX0lNQUdFLFxuICAgICAgaGFuZGxlcjogSGFuZGxlci5GUk9NX0lNQUdFLFxuICAgICAgY29kZTogQXNzZXRDb2RlLmZyb21Bc3NldEltYWdlKGpvaW4oX19kaXJuYW1lLCAnLi4vYXNzZXRzL2xhbWJkYScpLCB7XG4gICAgICAgIHBsYXRmb3JtOiBQbGF0Zm9ybS5MSU5VWF9BUk02NCxcbiAgICAgICAgLy8gZXhjbHVkZSBub2RlX21vZHVsZXNcbiAgICAgICAgLy8gYmVjYXVzZSB0aGUgbmF0aXZlIGJpbmFyeSBvZiB0aGUgaW5zdGFsbGVkIGVzYnVpbGQgY2hhbmdlcyBkZXBlbmRpbmcgb24gdGhlIGNwdSBhcmNoaXRlY3R1cmVcbiAgICAgICAgLy8gYW5kIHRoZSBoYXNoIHZhbHVlIG9mIHRoZSBpbWFnZSBhc3NldCBjaGFuZ2VzIGRlcGVuZGluZyBvbiB0aGUgZXhlY3V0aW9uIGVudmlyb25tZW50LlxuICAgICAgICBleGNsdWRlOiBbJ25vZGVfbW9kdWxlcyddLFxuICAgICAgfSksXG4gICAgICBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZS5BUk1fNjQsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDkwMCksXG4gICAgICByZXRyeUF0dGVtcHRzOiAwLFxuICAgICAgbWVtb3J5U2l6ZTogcHJvcHMubWVtb3J5U2l6ZSA/PyBERUZBVUxUX01FTU9SWV9TSVpFLFxuICAgICAgZXBoZW1lcmFsU3RvcmFnZVNpemU6IFNpemUuZ2liaWJ5dGVzKDEwKSwgLy8gZm9yIGNhc2VzIHRoYXQgbmVlZCB0byB1cGRhdGUgdHJpdnkgREI6IC90bXAvdHJpdnkvZGIvdHJpdnkuZGJcbiAgICB9KTtcbiAgICBwcm9wcy5yZXBvc2l0b3J5LmdyYW50UHVsbChjdXN0b21SZXNvdXJjZUxhbWJkYSk7XG5cbiAgICBjb25zdCBjdXN0b21SZXNvdXJjZUxhbWJkYUxvZ0dyb3VwQ29uc3RydWN0TmFtZSA9IGBEZWZhdWx0TG9nR3JvdXBGb3Ike2xhbWJkYVB1cnBvc2V9YDtcblxuICAgIHRoaXMudmFsaWRhdGVMYW1iZGFEZWZhdWx0TG9nR3JvdXBPcHRpb25zKGN1c3RvbVJlc291cmNlTGFtYmRhTG9nR3JvdXBDb25zdHJ1Y3ROYW1lLCBwcm9wcyk7XG5cbiAgICBpZiAocHJvcHMuZGVmYXVsdExvZ0dyb3VwUmVtb3ZhbFBvbGljeSB8fCBwcm9wcy5kZWZhdWx0TG9nR3JvdXBSZXRlbnRpb25EYXlzKSB7XG4gICAgICB0aGlzLmVuc3VyZUxhbWJkYURlZmF1bHRMb2dHcm91cChcbiAgICAgICAgY3VzdG9tUmVzb3VyY2VMYW1iZGEsXG4gICAgICAgIGN1c3RvbVJlc291cmNlTGFtYmRhTG9nR3JvdXBDb25zdHJ1Y3ROYW1lLFxuICAgICAgICBwcm9wcyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgaW1hZ2VTY2FubmVyUHJvdmlkZXIgPSBuZXcgUHJvdmlkZXIodGhpcywgJ1Byb3ZpZGVyJywge1xuICAgICAgb25FdmVudEhhbmRsZXI6IGN1c3RvbVJlc291cmNlTGFtYmRhLFxuICAgIH0pO1xuXG4gICAgY29uc3QgaW1hZ2VTY2FubmVyUHJvcGVydGllczogU2Nhbm5lckN1c3RvbVJlc291cmNlUHJvcHMgPSB7XG4gICAgICBhZGRyOiB0aGlzLm5vZGUuYWRkcixcbiAgICAgIGltYWdlVXJpOiBwcm9wcy5pbWFnZVVyaSxcbiAgICAgIGlnbm9yZVVuZml4ZWQ6IFN0cmluZyhwcm9wcy5pZ25vcmVVbmZpeGVkID8/IGZhbHNlKSxcbiAgICAgIHNldmVyaXR5OiBwcm9wcy5zZXZlcml0eSA/PyBbU2V2ZXJpdHkuQ1JJVElDQUxdLFxuICAgICAgc2Nhbm5lcnM6IHByb3BzLnNjYW5uZXJzID8/IFtdLFxuICAgICAgaW1hZ2VDb25maWdTY2FubmVyczogcHJvcHMuaW1hZ2VDb25maWdTY2FubmVycyA/PyBbXSxcbiAgICAgIGV4aXRDb2RlOiBwcm9wcy5leGl0Q29kZSA/PyAxLFxuICAgICAgZXhpdE9uRW9sOiBwcm9wcy5leGl0T25Fb2wgPz8gMSxcbiAgICAgIHRyaXZ5SWdub3JlOiBwcm9wcy50cml2eUlnbm9yZSA/PyBbXSxcbiAgICAgIHBsYXRmb3JtOiBwcm9wcy5wbGF0Zm9ybSA/PyAnJyxcbiAgICAgIG91dHB1dDogcHJvcHMuc2NhbkxvZ3NPdXRwdXQ/LmJpbmQoY3VzdG9tUmVzb3VyY2VMYW1iZGEpLFxuICAgIH07XG5cbiAgICBuZXcgQ3VzdG9tUmVzb3VyY2UodGhpcywgJ1Jlc291cmNlJywge1xuICAgICAgcmVzb3VyY2VUeXBlOiAnQ3VzdG9tOjpJbWFnZVNjYW5uZXJXaXRoVHJpdnknLFxuICAgICAgcHJvcGVydGllczogaW1hZ2VTY2FubmVyUHJvcGVydGllcyxcbiAgICAgIHNlcnZpY2VUb2tlbjogaW1hZ2VTY2FubmVyUHJvdmlkZXIuc2VydmljZVRva2VuLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB0aGF0IHNwZWNpZmllZCBkZWZhdWx0IGxvZyBncm91cCBvcHRpb25zIGFyZSB0aGUgc2FtZSBmb3IgZXhpc3RpbmcgZGVmYXVsdCBsb2cgZ3JvdXAuXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlTGFtYmRhRGVmYXVsdExvZ0dyb3VwT3B0aW9ucyhcbiAgICBsb2dHcm91cENvbnN0cnVjdE5hbWU6IHN0cmluZyxcbiAgICBwcm9wczogSW1hZ2VTY2FubmVyV2l0aFRyaXZ5UHJvcHMsXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IGV4aXN0aW5nID0gU3RhY2sub2YodGhpcykubm9kZS50cnlGaW5kQ2hpbGQobG9nR3JvdXBDb25zdHJ1Y3ROYW1lKSBhc1xuICAgICAgfCBMb2dHcm91cFxuICAgICAgfCB1bmRlZmluZWQ7XG4gICAgaWYgKCFleGlzdGluZykgcmV0dXJuO1xuXG4gICAgY29uc3QgY2ZuTG9nR3JvdXAgPSBleGlzdGluZy5ub2RlLmRlZmF1bHRDaGlsZCBhcyBDZm5Mb2dHcm91cDtcblxuICAgIGlmIChcbiAgICAgICF0aGlzLmlzU2FtZVJlc291cmNlRGVsZXRpb25CZWhhdmlvcihcbiAgICAgICAgcHJvcHMuZGVmYXVsdExvZ0dyb3VwUmVtb3ZhbFBvbGljeSxcbiAgICAgICAgY2ZuTG9nR3JvdXAuY2ZuT3B0aW9ucy5kZWxldGlvblBvbGljeSxcbiAgICAgICkgfHxcbiAgICAgIGNmbkxvZ0dyb3VwLnJldGVudGlvbkluRGF5cyAhPT0gcHJvcHMuZGVmYXVsdExvZ0dyb3VwUmV0ZW50aW9uRGF5c1xuICAgICkge1xuICAgICAgQW5ub3RhdGlvbnMub2YodGhpcykuYWRkV2FybmluZ1YyKFxuICAgICAgICAnQGltYWdlLXNjYW5uZXItd2l0aC10cml2eTpkdXBsaWNhdGVMYW1iZGFEZWZhdWx0TG9nR3JvdXBPcHRpb25zJyxcbiAgICAgICAgXCJZb3UgaGF2ZSB0byBzZXQgdGhlIHNhbWUgdmFsdWVzIGZvciAnZGVmYXVsdExvZ0dyb3VwUmVtb3ZhbFBvbGljeScgYW5kICdkZWZhdWx0TG9nR3JvdXBSZXRlbnRpb25EYXlzJyBmb3IgZWFjaCBJbWFnZVNjYW5uZXJXaXRoVHJpdnkgY29uc3RydWN0IGluIHRoZSBzYW1lIHN0YWNrLlwiLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgZGVmYXVsdCBsb2cgZ3JvdXAgZm9yIFNjYW5uZXIgTGFtYmRhIGlmIGl0IGRvZXMgbm90IGV4aXN0LlxuICAgKlxuICAgKiBUaGlzIG1ldGhvZCBjaGVja3MgaWYgdGhlIGRlZmF1bHQgbG9nIGdyb3VwIGZvciBTY2FubmVyIExhbWJkYSBleGlzdHMgaW4gY2hpbGRyZW4gb2YgdGhlIHN0YWNrIGNvbnN0cnVjdC5cbiAgICogSWYgaXQgZG9lcyBub3QgZXhpc3QsIGl0IGNyZWF0ZXMgdGhlIGRlZmF1bHQgbG9nIGdyb3VwIGZvciBTY2FubmVyIExhbWJkYSBhcyBhIGNoaWxkIG9mIHRoZSBzdGFjayBjb25zdHJ1Y3QuXG4gICAqL1xuICBwcml2YXRlIGVuc3VyZUxhbWJkYURlZmF1bHRMb2dHcm91cChcbiAgICBzaW5nbGV0b25GdW5jdGlvbjogU2luZ2xldG9uRnVuY3Rpb24sXG4gICAgbG9nR3JvdXBDb25zdHJ1Y3ROYW1lOiBzdHJpbmcsXG4gICAgcHJvcHM6IEltYWdlU2Nhbm5lcldpdGhUcml2eVByb3BzLFxuICApOiBMb2dHcm91cCB7XG4gICAgY29uc3QgZXhpc3RpbmcgPSBTdGFjay5vZih0aGlzKS5ub2RlLnRyeUZpbmRDaGlsZChsb2dHcm91cENvbnN0cnVjdE5hbWUpIGFzXG4gICAgICB8IExvZ0dyb3VwXG4gICAgICB8IHVuZGVmaW5lZDtcbiAgICBpZiAoZXhpc3RpbmcpIHtcbiAgICAgIHJldHVybiBleGlzdGluZztcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IExvZ0dyb3VwKFN0YWNrLm9mKHRoaXMpLCBsb2dHcm91cENvbnN0cnVjdE5hbWUsIHtcbiAgICAgIGxvZ0dyb3VwTmFtZTogYC9hd3MvbGFtYmRhLyR7c2luZ2xldG9uRnVuY3Rpb24uZnVuY3Rpb25OYW1lfWAsXG4gICAgICByZXRlbnRpb246IHByb3BzLmRlZmF1bHRMb2dHcm91cFJldGVudGlvbkRheXMsXG4gICAgICByZW1vdmFsUG9saWN5OiBwcm9wcy5kZWZhdWx0TG9nR3JvdXBSZW1vdmFsUG9saWN5LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBpc1NhbWVSZXNvdXJjZURlbGV0aW9uQmVoYXZpb3IoXG4gICAgcmVtb3ZhbFBvbGljeT86IFJlbW92YWxQb2xpY3ksXG4gICAgZGVsZXRpb25Qb2xpY3k/OiBDZm5EZWxldGlvblBvbGljeSxcbiAgKTogYm9vbGVhbiB7XG4gICAgc3dpdGNoIChyZW1vdmFsUG9saWN5KSB7XG4gICAgICBjYXNlIFJlbW92YWxQb2xpY3kuREVTVFJPWTpcbiAgICAgICAgcmV0dXJuIGRlbGV0aW9uUG9saWN5ID09PSBDZm5EZWxldGlvblBvbGljeS5ERUxFVEU7XG4gICAgICBjYXNlIFJlbW92YWxQb2xpY3kuUkVUQUlOOlxuICAgICAgICByZXR1cm4gZGVsZXRpb25Qb2xpY3kgPT09IENmbkRlbGV0aW9uUG9saWN5LlJFVEFJTjtcbiAgICAgIGNhc2UgUmVtb3ZhbFBvbGljeS5TTkFQU0hPVDpcbiAgICAgICAgcmV0dXJuIGRlbGV0aW9uUG9saWN5ID09PSBDZm5EZWxldGlvblBvbGljeS5TTkFQU0hPVDtcbiAgICAgIGNhc2UgUmVtb3ZhbFBvbGljeS5SRVRBSU5fT05fVVBEQVRFX09SX0RFTEVURTpcbiAgICAgICAgcmV0dXJuIGRlbGV0aW9uUG9saWN5ID09PSBDZm5EZWxldGlvblBvbGljeS5SRVRBSU5fRVhDRVBUX09OX0NSRUFURTtcbiAgICAgIGNhc2UgdW5kZWZpbmVkOlxuICAgICAgICByZXR1cm4gZGVsZXRpb25Qb2xpY3kgPT09IHVuZGVmaW5lZDtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiByZW1vdmFsUG9saWN5IHNhdGlzZmllcyBuZXZlcjtcbiAgICB9XG4gIH1cbn1cbiJdfQ==