UNPKG

cdk-sops-secrets

Version:

CDK Constructs that syncs your sops secrets into AWS SecretsManager secrets.

327 lines • 51.9 kB
"use strict"; var _a, _b; Object.defineProperty(exports, "__esModule", { value: true }); exports.Permissions = exports.SopsSync = exports.SopsSyncProvider = exports.ResourceType = exports.UploadType = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const fs = require("fs"); const path = require("path"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const aws_kms_1 = require("aws-cdk-lib/aws-kms"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const aws_s3_assets_1 = require("aws-cdk-lib/aws-s3-assets"); const constructs_1 = require("constructs"); var UploadType; (function (UploadType) { /** * Pass the secret data inline (base64 encoded and compressed) */ UploadType["INLINE"] = "INLINE"; /** * Uplaod the secret data as asset */ UploadType["ASSET"] = "ASSET"; })(UploadType || (exports.UploadType = UploadType = {})); var ResourceType; (function (ResourceType) { ResourceType["SECRET"] = "SECRET"; ResourceType["SECRET_RAW"] = "SECRET_RAW"; ResourceType["SECRET_BINARY"] = "SECRET_BINARY"; ResourceType["PARAMETER"] = "PARAMETER"; ResourceType["PARAMETER_MULTI"] = "PARAMETER_MULTI"; })(ResourceType || (exports.ResourceType = ResourceType = {})); class SopsSyncProvider extends aws_lambda_1.SingletonFunction { constructor(scope, id, props) { if (id === undefined) { aws_cdk_lib_1.Annotations.of(scope).addWarningV2('cdk-sops-secrets:omittingIdForSopsSyncProvider', 'Omitting id is deprecated. Please provide an id for the SopsSyncProvider. Default id will be removed in V3.'); } super(scope, id ?? 'SopsSyncProvider', { code: aws_lambda_1.Code.fromAsset(scope.node.tryGetContext('sops_sync_provider_asset_path') || path.join(__dirname, '../assets/cdk-sops-lambda.zip')), runtime: aws_lambda_1.Runtime.PROVIDED_AL2, handler: 'bootstrap', uuid: props?.uuid ?? 'SopsSyncProvider', role: props?.role, timeout: aws_cdk_lib_1.Duration.seconds(60), environment: { SOPS_AGE_KEY: aws_cdk_lib_1.Lazy.string({ produce: () => (this.sopsAgeKeys.map((secret) => secret.toString()) ?? []).join('\n'), }), }, vpc: props?.vpc, vpcSubnets: props?.vpcSubnets, securityGroups: props?.securityGroups, logRetention: props?.logRetention, logGroup: props?.logGroup, }); this.sopsAgeKeys = []; } addAgeKey(key) { this.sopsAgeKeys.push(key); } } exports.SopsSyncProvider = SopsSyncProvider; _a = JSII_RTTI_SYMBOL_1; SopsSyncProvider[_a] = { fqn: "cdk-sops-secrets.SopsSyncProvider", version: "2.3.1" }; /** * The custom resource, that is syncing the content from a sops file to a secret. */ class SopsSync extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); const provider = props.sopsProvider ?? new SopsSyncProvider(scope, 'SopsSyncProvider'); let uploadType = props.uploadType ?? UploadType.INLINE; let sopsFileFormat = props.sopsFileFormat; let sopsAsset = undefined; let sopsInline = undefined; let sopsS3File = undefined; if ((props.sopsFilePath == undefined && (props.sopsS3Bucket == undefined || props.sopsS3Key == undefined)) || (props.sopsFilePath !== undefined && props.sopsS3Bucket !== undefined && props.sopsS3Key !== undefined)) { throw new Error('You can either specify sopsFilePath or sopsS3Bucket and sopsS3Key!'); } if (props.sopsFilePath !== undefined) { if (sopsFileFormat === undefined) { const _sopsFileFormat = props.sopsFilePath.split('.').pop(); switch (_sopsFileFormat) { case 'json': { sopsFileFormat = 'json'; break; } case 'yaml': { sopsFileFormat = 'yaml'; break; } case 'yml': { sopsFileFormat = 'yaml'; break; } case 'dotenv': { sopsFileFormat = 'dotenv'; break; } case 'env': { sopsFileFormat = 'dotenv'; break; } case 'binary': { sopsFileFormat = 'binary'; break; } default: { aws_cdk_lib_1.Annotations.of(this).addError("Failed to determine sops file format. Please specify 'sopsFileFormat'!"); } } } if (!fs.existsSync(props.sopsFilePath)) { throw new Error(`File ${props.sopsFilePath} does not exist!`); } const sopsFileContent = fs.readFileSync(props.sopsFilePath); switch (uploadType) { case UploadType.INLINE: { sopsInline = { Content: sopsFileContent.toString('base64'), // We calculate the hash the same way as it would be done by new Asset(..) - so we can ensure stable version names even if switching from INLINE to ASSET and viceversa. Hash: aws_cdk_lib_1.FileSystem.fingerprint(props.sopsFilePath), }; break; } case UploadType.ASSET: { sopsAsset = new aws_s3_assets_1.Asset(this, 'Asset', { path: props.sopsFilePath, }); sopsS3File = { Bucket: sopsAsset.bucket.bucketName, Key: sopsAsset.s3ObjectKey, }; break; } } if ( // Is allways true, but to satisfy TS we check explicitly provider.role !== undefined && // Check if user has disabled automatic generation props.autoGenerateIamPermissions !== false) { Permissions.sopsKeys(this, { userDefinedKeys: props.sopsKmsKey, role: provider.role, sopsFileContent: sopsFileContent.toString(), }); Permissions.assetBucket(this, sopsAsset, provider.role, props.assetEncryptionKey); Permissions.encryptionKey(props.encryptionKey, provider.role); Permissions.secret(props.secret, provider.role); Permissions.parameters(this, props.parameterNames, provider.role); } else { aws_cdk_lib_1.Annotations.of(this).addWarning([ 'Please ensure proper permissions for the passed lambda function:', ' - write Access to the secret/parameters', ' - encrypt with the sopsKmsKey', ' - download from asset bucket', ].join('\n')); } if (props.sopsAgeKey !== undefined) { provider.addAgeKey(props.sopsAgeKey); } } else if (props.sopsS3Bucket !== undefined && props.sopsS3Key !== undefined) { sopsS3File = { Bucket: props.sopsS3Bucket, Key: props.sopsS3Key, }; uploadType = UploadType.ASSET; aws_cdk_lib_1.Annotations.of(this).addWarning('You have to manually add permissions to the sops provider to (permission to download file, to decrypt sops file)!'); } if (sopsFileFormat === undefined) { throw new Error('You have to specify sopsFileFormat!'); } const cr = new aws_cdk_lib_1.CustomResource(this, 'Resource', { serviceToken: provider.functionArn, resourceType: 'Custom::SopsSync', properties: { SopsS3File: sopsS3File, SopsInline: sopsInline, FlattenSeparator: props.flattenSeparator, Format: sopsFileFormat, EncryptionKey: props.encryptionKey?.keyId, ResourceType: props.resourceType, Target: props.target, }, }); this.versionId = cr.getAttString('VersionId'); } } exports.SopsSync = SopsSync; _b = JSII_RTTI_SYMBOL_1; SopsSync[_b] = { fqn: "cdk-sops-secrets.SopsSync", version: "2.3.1" }; var Permissions; (function (Permissions) { /** * Grants the necessary permissions for encrypt/decrypt on the customer managed encryption key * for the secrets / parameters. */ function encryptionKey(key, target) { if (key === undefined) { return; } key.grantEncryptDecrypt(target); } Permissions.encryptionKey = encryptionKey; function keysFromSopsContent(ctx, c) { const regexKey = /arn:aws:kms:[a-z0-9-]+:[\d]+:key\/[a-z0-9-]+/g; const resultsKey = c.match(regexKey); if (resultsKey !== null) { return resultsKey.map((result, index) => aws_kms_1.Key.fromKeyArn(ctx, `SopsKey${index}`, result)); } return []; } Permissions.keysFromSopsContent = keysFromSopsContent; function keysFromSopsContentAlias(ctx, c) { const regexAlias = /arn:aws:kms:[a-z0-9-]+:[\d]+:alias\/[a-z0-9-A-Z\/]+/g; const resultsAlias = c.match(regexAlias); if (resultsAlias !== null) { return resultsAlias.map((result, index) => aws_kms_1.Key.fromLookup(ctx, `SopsAlias${index}`, { aliasName: `alias/${result.split('/').slice(1).join('/')}`, })); } return []; } Permissions.keysFromSopsContentAlias = keysFromSopsContentAlias; /** * Grants the necessary permissions to decrypt the given sops file content. * Takes user defined keys, and searches the sops file for keys and aliases. */ function sopsKeys(ctx, props) { (props.userDefinedKeys ?? []) .concat(keysFromSopsContent(ctx, props.sopsFileContent), keysFromSopsContentAlias(ctx, props.sopsFileContent)) .forEach((key) => key.grantDecrypt(props.role)); } Permissions.sopsKeys = sopsKeys; /** * Grants the necessary permissions to write the given secrets. */ function secret(targetSecret, target) { if (targetSecret === undefined) { return; } targetSecret.grantWrite(target); } Permissions.secret = secret; function sliceParameters(params) { const result = []; /** * The maximum size of a managed policy is 6.144 bytes -> 1 character = 1 byte * bout 300 characters are reserved for the policy apart from resource arns * with some buffer, we end with an upper limit of 5750 bytes */ const limit = 5750; /** * Content for "arn:aws:ssm:ap-southeast-3:<accountnumer>:parameter/ */ const prefix = 55; let currentSize = 0; let currentChunk = []; for (const param of params) { const paramLength = param.length + prefix; if (currentSize + paramLength > limit) { result.push(currentChunk); currentChunk = []; currentSize = 0; } currentChunk.push(param); currentSize += paramLength; } if (currentChunk.length > 0) { result.push(currentChunk); } return result; } /** * Grants the necessary permissions to write the given parameters. */ function parameters(ctx, targetParameters, role) { if (targetParameters === undefined) { return; } const paramSlices = sliceParameters(targetParameters); for (let i = 0; i < paramSlices.length; i++) { const putPolicy = new aws_iam_1.ManagedPolicy(ctx, `SopsSecretParameterProviderManagedPolicyParameterAccess${i}`, { description: 'Policy to grant parameter provider permissions to put parameter', }); putPolicy.addStatements(new aws_iam_1.PolicyStatement({ actions: ['ssm:PutParameter'], resources: paramSlices[i].map((param) => `arn:aws:ssm:${aws_cdk_lib_1.Stack.of(ctx).region}:${aws_cdk_lib_1.Stack.of(ctx).account}:parameter${param.startsWith('/') ? param : `/${param}`}`), })); role.addManagedPolicy(putPolicy); } } Permissions.parameters = parameters; /** * Grants the necessary permissions to read the given asset from S3. */ function assetBucket(context, asset, target, assetKey) { if (asset === undefined) { return; } asset.bucket.grantRead(target); if (assetKey) { assetKey.grantDecrypt(target); } else { try { const qualifier = aws_cdk_lib_1.Stack.of(context).synthesizer.bootstrapQualifier ?? 'hnb659fds'; // hnb659fds is the AWS global default qualifier aws_kms_1.Key.fromLookup(context, 'AssetBucketKey', { aliasName: `alias/cdk-bootstrap/${qualifier}`, }).grantDecrypt(target); } catch (error) { aws_cdk_lib_1.Annotations.of(context).addWarningV2('no-asset-kms-key', `An error occured while retreving the KMS-Key for the Asset S3-Bucket from CDK Bootstrap. Set encryption key manually by using props.assetEncryptionKey. ${error}`); } } } Permissions.assetBucket = assetBucket; })(Permissions || (exports.Permissions = Permissions = {})); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU29wc1N5bmMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU29wc1N5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLDZDQVFxQjtBQUVyQixpREFLNkI7QUFDN0IsaURBQWdEO0FBQ2hELHVEQUEwRTtBQUUxRSw2REFBa0Q7QUFFbEQsMkNBQXVDO0FBR3ZDLElBQVksVUFTWDtBQVRELFdBQVksVUFBVTtJQUNwQjs7T0FFRztJQUNILCtCQUFpQixDQUFBO0lBQ2pCOztPQUVHO0lBQ0gsNkJBQWUsQ0FBQTtBQUNqQixDQUFDLEVBVFcsVUFBVSwwQkFBVixVQUFVLFFBU3JCO0FBRUQsSUFBWSxZQU1YO0FBTkQsV0FBWSxZQUFZO0lBQ3RCLGlDQUFpQixDQUFBO0lBQ2pCLHlDQUF5QixDQUFBO0lBQ3pCLCtDQUErQixDQUFBO0lBQy9CLHVDQUF1QixDQUFBO0lBQ3ZCLG1EQUFtQyxDQUFBO0FBQ3JDLENBQUMsRUFOVyxZQUFZLDRCQUFaLFlBQVksUUFNdkI7QUFzTEQsTUFBYSxnQkFBaUIsU0FBUSw4QkFBaUI7SUFHckQsWUFBWSxLQUFnQixFQUFFLEVBQVcsRUFBRSxLQUE2QjtRQUN0RSxJQUFJLEVBQUUsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNyQix5QkFBVyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxZQUFZLENBQ2hDLGdEQUFnRCxFQUNoRCw2R0FBNkcsQ0FDOUcsQ0FBQztRQUNKLENBQUM7UUFDRCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsSUFBSSxrQkFBa0IsRUFBRTtZQUNyQyxJQUFJLEVBQUUsaUJBQUksQ0FBQyxTQUFTLENBQ2xCLEtBQUssQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLCtCQUErQixDQUFDO2dCQUN2RCxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSwrQkFBK0IsQ0FBQyxDQUN4RDtZQUNELE9BQU8sRUFBRSxvQkFBTyxDQUFDLFlBQVk7WUFDN0IsT0FBTyxFQUFFLFdBQVc7WUFDcEIsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLElBQUksa0JBQWtCO1lBQ3ZDLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSTtZQUNqQixPQUFPLEVBQUUsc0JBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzdCLFdBQVcsRUFBRTtnQkFDWCxZQUFZLEVBQUUsa0JBQUksQ0FBQyxNQUFNLENBQUM7b0JBQ3hCLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FDWixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQzlELElBQUksQ0FDTDtpQkFDSixDQUFDO2FBQ0g7WUFDRCxHQUFHLEVBQUUsS0FBSyxFQUFFLEdBQUc7WUFDZixVQUFVLEVBQUUsS0FBSyxFQUFFLFVBQVU7WUFDN0IsY0FBYyxFQUFFLEtBQUssRUFBRSxjQUFjO1lBQ3JDLFlBQVksRUFBRSxLQUFLLEVBQUUsWUFBWTtZQUNqQyxRQUFRLEVBQUUsS0FBSyxFQUFFLFFBQVE7U0FDMUIsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVNLFNBQVMsQ0FBQyxHQUFnQjtRQUMvQixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QixDQUFDOztBQXZDSCw0Q0F3Q0M7OztBQUVEOztHQUVHO0FBQ0gsTUFBYSxRQUFTLFNBQVEsc0JBQVM7SUFNckMsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFvQjtRQUM1RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLE1BQU0sUUFBUSxHQUNaLEtBQUssQ0FBQyxZQUFZLElBQUksSUFBSSxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztRQUV4RSxJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUMsVUFBVSxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUM7UUFDdkQsSUFBSSxjQUFjLEdBQ2hCLEtBQUssQ0FBQyxjQUFjLENBQUM7UUFDdkIsSUFBSSxTQUFTLEdBQXNCLFNBQVMsQ0FBQztRQUM3QyxJQUFJLFVBQVUsR0FBa0QsU0FBUyxDQUFDO1FBQzFFLElBQUksVUFBVSxHQUFnRCxTQUFTLENBQUM7UUFFeEUsSUFDRSxDQUFDLEtBQUssQ0FBQyxZQUFZLElBQUksU0FBUztZQUM5QixDQUFDLEtBQUssQ0FBQyxZQUFZLElBQUksU0FBUyxJQUFJLEtBQUssQ0FBQyxTQUFTLElBQUksU0FBUyxDQUFDLENBQUM7WUFDcEUsQ0FBQyxLQUFLLENBQUMsWUFBWSxLQUFLLFNBQVM7Z0JBQy9CLEtBQUssQ0FBQyxZQUFZLEtBQUssU0FBUztnQkFDaEMsS0FBSyxDQUFDLFNBQVMsS0FBSyxTQUFTLENBQUMsRUFDaEMsQ0FBQztZQUNELE1BQU0sSUFBSSxLQUFLLENBQ2Isb0VBQW9FLENBQ3JFLENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxLQUFLLENBQUMsWUFBWSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3JDLElBQUksY0FBYyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUNqQyxNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDNUQsUUFBUSxlQUFlLEVBQUUsQ0FBQztvQkFDeEIsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDO3dCQUNaLGNBQWMsR0FBRyxNQUFNLENBQUM7d0JBQ3hCLE1BQU07b0JBQ1IsQ0FBQztvQkFDRCxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUM7d0JBQ1osY0FBYyxHQUFHLE1BQU0sQ0FBQzt3QkFDeEIsTUFBTTtvQkFDUixDQUFDO29CQUNELEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQzt3QkFDWCxjQUFjLEdBQUcsTUFBTSxDQUFDO3dCQUN4QixNQUFNO29CQUNSLENBQUM7b0JBQ0QsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDO3dCQUNkLGNBQWMsR0FBRyxRQUFRLENBQUM7d0JBQzFCLE1BQU07b0JBQ1IsQ0FBQztvQkFDRCxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUM7d0JBQ1gsY0FBYyxHQUFHLFFBQVEsQ0FBQzt3QkFDMUIsTUFBTTtvQkFDUixDQUFDO29CQUNELEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQzt3QkFDZCxjQUFjLEdBQUcsUUFBUSxDQUFDO3dCQUMxQixNQUFNO29CQUNSLENBQUM7b0JBQ0QsT0FBTyxDQUFDLENBQUMsQ0FBQzt3QkFDUix5QkFBVyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLENBQzNCLHdFQUF3RSxDQUN6RSxDQUFDO29CQUNKLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztnQkFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxRQUFRLEtBQUssQ0FBQyxZQUFZLGtCQUFrQixDQUFDLENBQUM7WUFDaEUsQ0FBQztZQUNELE1BQU0sZUFBZSxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBRTVELFFBQVEsVUFBVSxFQUFFLENBQUM7Z0JBQ25CLEtBQUssVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7b0JBQ3ZCLFVBQVUsR0FBRzt3QkFDWCxPQUFPLEVBQUUsZUFBZSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7d0JBQzNDLHdLQUF3Szt3QkFDeEssSUFBSSxFQUFFLHdCQUFVLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUM7cUJBQ2pELENBQUM7b0JBQ0YsTUFBTTtnQkFDUixDQUFDO2dCQUNELEtBQUssVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7b0JBQ3RCLFNBQVMsR0FBRyxJQUFJLHFCQUFLLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRTt3QkFDbkMsSUFBSSxFQUFFLEtBQUssQ0FBQyxZQUFZO3FCQUN6QixDQUFDLENBQUM7b0JBQ0gsVUFBVSxHQUFHO3dCQUNYLE1BQU0sRUFBRSxTQUFTLENBQUMsTUFBTSxDQUFDLFVBQVU7d0JBQ25DLEdBQUcsRUFBRSxTQUFTLENBQUMsV0FBVztxQkFDM0IsQ0FBQztvQkFDRixNQUFNO2dCQUNSLENBQUM7WUFDSCxDQUFDO1lBRUQ7WUFDRSx5REFBeUQ7WUFDekQsUUFBUSxDQUFDLElBQUksS0FBSyxTQUFTO2dCQUMzQixrREFBa0Q7Z0JBQ2xELEtBQUssQ0FBQywwQkFBMEIsS0FBSyxLQUFLLEVBQzFDLENBQUM7Z0JBQ0QsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUU7b0JBQ3pCLGVBQWUsRUFBRSxLQUFLLENBQUMsVUFBVTtvQkFDakMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJO29CQUNuQixlQUFlLEVBQUUsZUFBZSxDQUFDLFFBQVEsRUFBRTtpQkFDNUMsQ0FBQyxDQUFDO2dCQUNILFdBQVcsQ0FBQyxXQUFXLENBQ3JCLElBQUksRUFDSixTQUFTLEVBQ1QsUUFBUSxDQUFDLElBQUksRUFDYixLQUFLLENBQUMsa0JBQWtCLENBQ3pCLENBQUM7Z0JBQ0YsV0FBVyxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDOUQsV0FBVyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDaEQsV0FBVyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLGNBQWMsRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDcEUsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLHlCQUFXLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FDN0I7b0JBQ0Usa0VBQWtFO29CQUNsRSwyQ0FBMkM7b0JBQzNDLGlDQUFpQztvQkFDakMsZ0NBQWdDO2lCQUNqQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FDYixDQUFDO1lBQ0osQ0FBQztZQUNELElBQUksS0FBSyxDQUFDLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDbkMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDdkMsQ0FBQztRQUNILENBQUM7YUFBTSxJQUNMLEtBQUssQ0FBQyxZQUFZLEtBQUssU0FBUztZQUNoQyxLQUFLLENBQUMsU0FBUyxLQUFLLFNBQVMsRUFDN0IsQ0FBQztZQUNELFVBQVUsR0FBRztnQkFDWCxNQUFNLEVBQUUsS0FBSyxDQUFDLFlBQVk7Z0JBQzFCLEdBQUcsRUFBRSxLQUFLLENBQUMsU0FBUzthQUNyQixDQUFDO1lBQ0YsVUFBVSxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUM7WUFDOUIseUJBQVcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxDQUM3QixtSEFBbUgsQ0FDcEgsQ0FBQztRQUNKLENBQUM7UUFFRCxJQUFJLGNBQWMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNqQyxNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7UUFDekQsQ0FBQztRQUVELE1BQU0sRUFBRSxHQUFHLElBQUksNEJBQWMsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFO1lBQzlDLFlBQVksRUFBRSxRQUFRLENBQUMsV0FBVztZQUNsQyxZQUFZLEVBQUUsa0JBQWtCO1lBQ2hDLFVBQVUsRUFBRTtnQkFDVixVQUFVLEVBQUUsVUFBVTtnQkFDdEIsVUFBVSxFQUFFLFVBQVU7Z0JBQ3RCLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxnQkFBZ0I7Z0JBQ3hDLE1BQU0sRUFBRSxjQUFjO2dCQUN0QixhQUFhLEVBQUUsS0FBSyxDQUFDLGFBQWEsRUFBRSxLQUFLO2dCQUN6QyxZQUFZLEVBQUUsS0FBSyxDQUFDLFlBQVk7Z0JBQ2hDLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTTthQUNlO1NBQ3RDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNoRCxDQUFDOztBQTlKSCw0QkErSkM7OztBQUVELElBQWlCLFdBQVcsQ0EySzNCO0FBM0tELFdBQWlCLFdBQVc7SUFDMUI7OztPQUdHO0lBQ0gsU0FBZ0IsYUFBYSxDQUFDLEdBQXFCLEVBQUUsTUFBa0I7UUFDckUsSUFBSSxHQUFHLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDdEIsT0FBTztRQUNULENBQUM7UUFDRCxHQUFHLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUxlLHlCQUFhLGdCQUs1QixDQUFBO0lBRUQsU0FBZ0IsbUJBQW1CLENBQUMsR0FBYyxFQUFFLENBQVM7UUFDM0QsTUFBTSxRQUFRLEdBQUcsK0NBQStDLENBQUM7UUFDakUsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNyQyxJQUFJLFVBQVUsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUN4QixPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FDdEMsYUFBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsVUFBVSxLQUFLLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FDL0MsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFUZSwrQkFBbUIsc0JBU2xDLENBQUE7SUFFRCxTQUFnQix3QkFBd0IsQ0FBQyxHQUFjLEVBQUUsQ0FBUztRQUNoRSxNQUFNLFVBQVUsR0FBRyxzREFBc0QsQ0FBQztRQUMxRSxNQUFNLFlBQVksR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3pDLElBQUksWUFBWSxLQUFLLElBQUksRUFBRSxDQUFDO1lBQzFCLE9BQU8sWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUN4QyxhQUFHLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxZQUFZLEtBQUssRUFBRSxFQUFFO2dCQUN2QyxTQUFTLEVBQUUsU0FBUyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUU7YUFDM0QsQ0FBQyxDQUNILENBQUM7UUFDSixDQUFDO1FBQ0QsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBWGUsb0NBQXdCLDJCQVd2QyxDQUFBO0lBRUQ7OztPQUdHO0lBQ0gsU0FBZ0IsUUFBUSxDQUN0QixHQUFjLEVBQ2QsS0FJQztRQUVELENBQUMsS0FBSyxDQUFDLGVBQWUsSUFBSSxFQUFFLENBQUM7YUFDMUIsTUFBTSxDQUNMLG1CQUFtQixDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsZUFBZSxDQUFDLEVBQy9DLHdCQUF3QixDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsZUFBZSxDQUFDLENBQ3JEO2FBQ0EsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFkZSxvQkFBUSxXQWN2QixDQUFBO0lBRUQ7O09BRUc7SUFDSCxTQUFnQixNQUFNLENBQ3BCLFlBQWlDLEVBQ2pDLE1BQWtCO1FBRWxCLElBQUksWUFBWSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQy9CLE9BQU87UUFDVCxDQUFDO1FBQ0QsWUFBWSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBUmUsa0JBQU0sU0FRckIsQ0FBQTtJQUVELFNBQVMsZUFBZSxDQUFDLE1BQWdCO1FBQ3ZDLE1BQU0sTUFBTSxHQUFlLEVBQUUsQ0FBQztRQUM5Qjs7OztXQUlHO1FBQ0gsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDO1FBRW5COztXQUVHO1FBQ0gsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBRWxCLElBQUksV0FBVyxHQUFHLENBQUMsQ0FBQztRQUNwQixJQUFJLFlBQVksR0FBYSxFQUFFLENBQUM7UUFDaEMsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUMzQixNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztZQUMxQyxJQUFJLFdBQVcsR0FBRyxXQUFXLEdBQUcsS0FBSyxFQUFFLENBQUM7Z0JBQ3RDLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQzFCLFlBQVksR0FBRyxFQUFFLENBQUM7Z0JBQ2xCLFdBQVcsR0FBRyxDQUFDLENBQUM7WUFDbEIsQ0FBQztZQUNELFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDekIsV0FBVyxJQUFJLFdBQVcsQ0FBQztRQUM3QixDQUFDO1FBRUQsSUFBSSxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVCLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDNUIsQ0FBQztRQUNELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFRDs7T0FFRztJQUNILFNBQWdCLFVBQVUsQ0FDeEIsR0FBYyxFQUNkLGdCQUFzQyxFQUN0QyxJQUFXO1FBRVgsSUFBSSxnQkFBZ0IsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNuQyxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBRXRELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDNUMsTUFBTSxTQUFTLEdBQUcsSUFBSSx1QkFBYSxDQUNqQyxHQUFHLEVBQ0gsMERBQTBELENBQUMsRUFBRSxFQUM3RDtnQkFDRSxXQUFXLEVBQ1QsaUVBQWlFO2FBQ3BFLENBQ0YsQ0FBQztZQUNGLFNBQVMsQ0FBQyxhQUFhLENBQ3JCLElBQUkseUJBQWUsQ0FBQztnQkFDbEIsT0FBTyxFQUFFLENBQUMsa0JBQWtCLENBQUM7Z0JBQzdCLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUMzQixDQUFDLEtBQUssRUFBRSxFQUFFLENBQ1IsZUFBZSxtQkFBSyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLElBQ2pDLG1CQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQ2hCLGFBQWEsS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssRUFBRSxFQUFFLENBQzdEO2FBQ0YsQ0FBQyxDQUNILENBQUM7WUFDRixJQUFJLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDbkMsQ0FBQztJQUNILENBQUM7SUFqQ2Usc0JBQVUsYUFpQ3pCLENBQUE7SUFFRDs7T0FFRztJQUNILFNBQWdCLFdBQVcsQ0FDekIsT0FBa0IsRUFDbEIsS0FBd0IsRUFDeEIsTUFBa0IsRUFDbEIsUUFBMEI7UUFFMUIsSUFBSSxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDeEIsT0FBTztRQUNULENBQUM7UUFDRCxLQUFLLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUUvQixJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQ2IsUUFBUSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNoQyxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQztnQkFDSCxNQUFNLFNBQVMsR0FDYixtQkFBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLENBQUMsa0JBQWtCLElBQUksV0FBVyxDQUFDLENBQUMsZ0RBQWdEO2dCQUNuSCxhQUFHLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRTtvQkFDeEMsU0FBUyxFQUFFLHVCQUF1QixTQUFTLEVBQUU7aUJBQzlDLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDMUIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YseUJBQVcsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsWUFBWSxDQUNsQyxrQkFBa0IsRUFDbEIsMkpBQTJKLEtBQUssRUFBRSxDQUNuSyxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBM0JlLHVCQUFXLGNBMkIxQixDQUFBO0FBQ0gsQ0FBQyxFQTNLZ0IsV0FBVywyQkFBWCxXQUFXLFFBMkszQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQge1xuICBBbm5vdGF0aW9ucyxcbiAgQ3VzdG9tUmVzb3VyY2UsXG4gIER1cmF0aW9uLFxuICBGaWxlU3lzdGVtLFxuICBMYXp5LFxuICBTZWNyZXRWYWx1ZSxcbiAgU3RhY2ssXG59IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IElTZWN1cml0eUdyb3VwLCBJVnBjLCBTdWJuZXRTZWxlY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWMyJztcbmltcG9ydCB7XG4gIElHcmFudGFibGUsXG4gIElSb2xlLFxuICBNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3lTdGF0ZW1lbnQsXG59IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgSUtleSwgS2V5IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWttcyc7XG5pbXBvcnQgeyBDb2RlLCBSdW50aW1lLCBTaW5nbGV0b25GdW5jdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgUmV0ZW50aW9uRGF5cywgSUxvZ0dyb3VwIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0IHsgQXNzZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMtYXNzZXRzJztcbmltcG9ydCB7IElTZWNyZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc2VjcmV0c21hbmFnZXInO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBTb3BzU3luY1Jlc291cmNlUHJvcGVydHlzIH0gZnJvbSAnLi9MYW1iZGFJbnRlcmZhY2UnO1xuXG5leHBvcnQgZW51bSBVcGxvYWRUeXBlIHtcbiAgLyoqXG4gICAqIFBhc3MgdGhlIHNlY3JldCBkYXRhIGlubGluZSAoYmFzZTY0IGVuY29kZWQgYW5kIGNvbXByZXNzZWQpXG4gICAqL1xuICBJTkxJTkUgPSAnSU5MSU5FJyxcbiAgLyoqXG4gICAqIFVwbGFvZCB0aGUgc2VjcmV0IGRhdGEgYXMgYXNzZXRcbiAgICovXG4gIEFTU0VUID0gJ0FTU0VUJyxcbn1cblxuZXhwb3J0IGVudW0gUmVzb3VyY2VUeXBlIHtcbiAgU0VDUkVUID0gJ1NFQ1JFVCcsXG4gIFNFQ1JFVF9SQVcgPSAnU0VDUkVUX1JBVycsXG4gIFNFQ1JFVF9CSU5BUlkgPSAnU0VDUkVUX0JJTkFSWScsXG4gIFBBUkFNRVRFUiA9ICdQQVJBTUVURVInLFxuICBQQVJBTUVURVJfTVVMVEkgPSAnUEFSQU1FVEVSX01VTFRJJyxcbn1cblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBTb3BzU3luY1xuICovXG5leHBvcnQgaW50ZXJmYWNlIFNvcHNTeW5jT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgY3VzdG9tIHJlc291cmNlIHByb3ZpZGVyIHRvIHVzZS4gSWYgeW91IGRvbid0IHNwZWNpZnkgYW55LCBhIG5ld1xuICAgKiBwcm92aWRlciB3aWxsIGJlIGNyZWF0ZWQgLSBvciBpZiBhbHJlYWR5IGV4aXN0cyB3aXRoaW4gdGhpcyBzdGFjayAtIHJldXNlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBIG5ldyBzaW5nbGV0b24gcHJvdmlkZXIgd2lsbCBiZSBjcmVhdGVkXG4gICAqL1xuICByZWFkb25seSBzb3BzUHJvdmlkZXI/OiBTb3BzU3luY1Byb3ZpZGVyO1xuXG4gIC8qKlxuICAgKiBUaGUgZmlsZXBhdGggdG8gdGhlIHNvcHMgZmlsZVxuICAgKi9cbiAgcmVhZG9ubHkgc29wc0ZpbGVQYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJZiB5b3Ugd2FudCB0byBwYXNzIHRoZSBzb3BzIGZpbGUgdmlhIHMzLCB5b3UgY2FuIHNwZWNpZnkgdGhlIGJ1Y2tldFxuICAgKiB5b3UgY2FuIHVzZSBjZm4gcGFyYW1ldGVyIGhlcmVcbiAgICogQm90aCwgc29wc1MzQnVja2V0IGFuZCBzb3BzUzNLZXkgaGF2ZSB0byBiZSBzcGVjaWZpZWRcbiAgICovXG4gIHJlYWRvbmx5IHNvcHNTM0J1Y2tldD86IHN0cmluZztcblxuICAvKipcbiAgICogSWYgeW91IHdhbnQgdG8gcGFzcyB0aGUgc29wcyBmaWxlIHZpYSBzMywgeW91IGNhbiBzcGVjaWZ5IHRoZSBrZXkgaW5zaWRlIHRoZSBidWNrZXRcbiAgICogeW91IGNhbiB1c2UgY2ZuIHBhcmFtZXRlciBoZXJlXG4gICAqIEJvdGgsIHNvcHNTM0J1Y2tldCBhbmQgc29wc1MzS2V5IGhhdmUgdG8gYmUgc3BlY2lmaWVkXG4gICAqL1xuICByZWFkb25seSBzb3BzUzNLZXk/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEhvdyBzaG91bGQgdGhlIHNlY3JldCBiZSBwYXNzZWQgdG8gdGhlIEN1c3RvbVJlc291cmNlP1xuICAgKiBAZGVmYXVsdCBJTkxJTkVcbiAgICovXG4gIHJlYWRvbmx5IHVwbG9hZFR5cGU/OiBVcGxvYWRUeXBlO1xuXG4gIC8qKlxuICAgKiBUaGUgZm9ybWF0IG9mIHRoZSBzb3BzIGZpbGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhlIGZpbGVmb3JtYXQgd2lsbCBiZSBkZXJpdmVkIGZyb20gdGhlIGZpbGUgZW5kaW5nXG4gICAqL1xuICByZWFkb25seSBzb3BzRmlsZUZvcm1hdD86IHVuZGVmaW5lZCB8ICdqc29uJyB8ICd5YW1sJyB8ICdkb3RlbnYnIHwgJ2JpbmFyeSc7XG5cbiAgLyoqXG4gICAqIFRoZSBrbXNLZXkgdXNlZCB0byBlbmNyeXB0IHRoZSBzb3BzIGZpbGUuIEVuY3J5cHQgcGVybWlzc2lvbnNcbiAgICogd2lsbCBiZSBncmFudGVkIHRvIHRoZSBjdXN0b20gcmVzb3VyY2UgcHJvdmlkZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhlIGtleSB3aWxsIGJlIGRlcml2ZWQgZnJvbSB0aGUgc29wcyBmaWxlXG4gICAqL1xuICByZWFkb25seSBzb3BzS21zS2V5PzogSUtleVtdO1xuXG4gIC8qKlxuICAgKiBUaGUgYWdlIGtleSB0aGF0IHNob3VsZCBiZSB1c2VkIGZvciBlbmNyeXB0aW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgc29wc0FnZUtleT86IFNlY3JldFZhbHVlO1xuXG4gIC8qKlxuICAgKiBTaG91bGQgdGhpcyBjb25zdHJ1Y3QgYXV0b21hdGljYWxseSBjcmVhdGUgSUFNIHBlcm1pc3Npb25zP1xuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBhdXRvR2VuZXJhdGVJYW1QZXJtaXNzaW9ucz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBlbmNyeXB0aW9uIGtleSB1c2VkIGJ5IHRoZSBDREsgZGVmYXVsdCBBc3NldCBTMyBCdWNrZXQuXG4gICAqIEBkZWZhdWx0IC0gVHJ5aW5nIHRvIGdldCB0aGUga2V5IHVzaW5nIHRoZSBDREsgQm9vdHN0cmFwIGNvbnRleHQuXG4gICAqL1xuICByZWFkb25seSBhc3NldEVuY3J5cHRpb25LZXk/OiBJS2V5O1xufVxuXG4vKipcbiAqIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZXh0ZW5kZWQgYnkgdGhlIHRhcmdldCBTZWNyZXQgLyBQYXJhbWV0ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTb3BzU3luY1Byb3BzIGV4dGVuZHMgU29wc1N5bmNPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSB0YXJnZXQgdG8gcG9wdWxhdGUgd2l0aCB0aGUgc29wcyBmaWxlIGNvbnRlbnQuXG4gICAqIC0gZm9yIHNlY3JldCwgaXQncyB0aGUgbmFtZSBvciBhcm4gb2YgdGhlIHNlY3JldFxuICAgKiAtIGZvciBwYXJhbWV0ZXIsIGl0J3MgdGhlIG5hbWUgb2YgdGhlIHBhcmFtZXRlclxuICAgKiAtIGZvciBwYXJhbWV0ZXIgbXVsdGksIGl0J3MgdGhlIHByZWZpeCBvZiB0aGUgcGFyYW1ldGVyc1xuICAgKi9cbiAgcmVhZG9ubHkgdGFyZ2V0OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIElmIHRoZSBzdHJ1Y3R1cmUgc2hvdWxkIGJlIGZsYXR0ZW5lZCB1c2UgdGhlIHByb3ZpZGVkIHNlcGFyYXRvciBiZXR3ZWVuIGtleXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gdW5kZWZpbmVkXG4gICAqL1xuICByZWFkb25seSBmbGF0dGVuU2VwYXJhdG9yPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgZW5jcnlwdGlvbiBrZXkgdXNlZCBmb3IgZW5jcnlwdGluZyB0aGUgc3NtIHBhcmFtZXRlciBpZiBgcGFyYW1ldGVyTmFtZWAgaXMgc2V0LlxuICAgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbktleT86IElLZXk7XG5cbiAgLyoqXG4gICAqIFdpbGwgdGhpcyBTeW5jIGRlcGxveSBhIFNlY3JldCBvciBQYXJhbWV0ZXIocylcbiAgICovXG4gIHJlYWRvbmx5IHJlc291cmNlVHlwZTogUmVzb3VyY2VUeXBlO1xuXG4gIHJlYWRvbmx5IHNlY3JldD86IElTZWNyZXQ7XG4gIHJlYWRvbmx5IHBhcmFtZXRlck5hbWVzPzogc3RyaW5nW107XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBhIGN1c3RvbSBTb3BzU3luY1Byb3ZpZGVyLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNvcHNTeW5jUHJvdmlkZXJQcm9wcyB7XG4gIC8qKlxuICAgKiBWUEMgbmV0d29yayB0byBwbGFjZSBMYW1iZGEgbmV0d29yayBpbnRlcmZhY2VzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIExhbWJkYSBmdW5jdGlvbiBpcyBub3QgcGxhY2VkIHdpdGhpbiBhIFZQQy5cbiAgICovXG4gIHJlYWRvbmx5IHZwYz86IElWcGM7XG4gIC8qKlxuICAgKiBXaGVyZSB0byBwbGFjZSB0aGUgbmV0d29yayBpbnRlcmZhY2VzIHdpdGhpbiB0aGUgVlBDLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFN1Ym5ldHMgd2lsbCBiZSBjaG9zZW4gYXV0b21hdGljYWxseS5cbiAgICovXG4gIHJlYWRvbmx5IHZwY1N1Ym5ldHM/OiBTdWJuZXRTZWxlY3Rpb247XG4gIC8qKlxuICAgKiBPbmx5IGlmIGB2cGNgIGlzIHN1cHBsaWVkOiBUaGUgbGlzdCBvZiBzZWN1cml0eSBncm91cHMgdG8gYXNzb2NpYXRlIHdpdGggdGhlIExhbWJkYSdzIG5ldHdvcmsgaW50ZXJmYWNlcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBIGRlZGljYXRlZCBzZWN1cml0eSBncm91cCB3aWxsIGJlIGNyZWF0ZWQgZm9yIHRoZSBsYW1iZGEgZnVuY3Rpb24uXG4gICAqL1xuICByZWFkb25seSBzZWN1cml0eUdyb3Vwcz86IElTZWN1cml0eUdyb3VwW107XG5cbiAgLyoqXG4gICAqIFRoZSByb2xlIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIHRoZSBjdXN0b20gcmVzb3VyY2UgcHJvdmlkZXIuXG4gICAqIElmIHlvdSBkb24ndCBzcGVjaWZ5IGFueSwgYSBuZXcgcm9sZSB3aWxsIGJlIGNyZWF0ZWQgd2l0aCBhbGwgcmVxdWlyZWQgcGVybWlzc2lvbnNcbiAgICpcbiAgICogQGRlZmF1bHQgLSBhIG5ldyByb2xlIHdpbGwgYmUgY3JlYXRlZFxuICAgKi9cbiAgcmVhZG9ubHkgcm9sZT86IElSb2xlO1xuICAvKipcbiAgICogVGhlIG51bWJlciBvZiBkYXlzIGxvZyBldmVudHMgYXJlIGtlcHQgaW4gQ2xvdWRXYXRjaCBMb2dzLiBXaGVuIHVwZGF0aW5nXG4gICAqIHRoaXMgcHJvcGVydHksIHVuc2V0dGluZyBpdCBkb2Vzbid0IHJlbW92ZSB0aGUgbG9nIHJldGVudGlvbiBwb2xpY3kuIFRvXG4gICAqIHJlbW92ZSB0aGUgcmV0ZW50aW9uIHBvbGljeSwgc2V0IHRoZSB2YWx1ZSB0byBgSU5GSU5JVEVgLlxuICAgKlxuICAgKiBUaGlzIGlzIGEgbGVnYWN5IEFQSSBhbmQgd2Ugc3Ryb25nbHkgcmVjb21tZW5kIHlvdSBtb3ZlIGF3YXkgZnJvbSBpdCBpZiB5b3UgY2FuLlxuICAgKiBJbnN0ZWFkIGNyZWF0ZSBhIGZ1bGx5IGN1c3RvbWl6YWJsZSBsb2cgZ3JvdXAgd2l0aCBgbG9ncy5Mb2dHcm91cGAgYW5kIHVzZSB0aGUgYGxvZ0dyb3VwYCBwcm9wZXJ0eVxuICAgKiB0byBpbnN0cnVjdCB0aGUgTGFtYmRhIGZ1bmN0aW9uIHRvIHNlbmQgbG9ncyB0byBpdC5cbiAgICogTWlncmF0aW5nIGZyb20gYGxvZ1JldGVudGlvbmAgdG8gYGxvZ0dyb3VwYCB3aWxsIGNhdXNlIHRoZSBuYW1lIG9mIHRoZSBsb2cgZ3JvdXAgdG8gY2hhbmdlLlxuICAgKiBVc2VycyBhbmQgY29kZSBhbmQgcmVmZXJlbmNpbmcgdGhlIG5hbWUgdmVyYmF0aW0gd2lsbCBoYXZlIHRvIGFkanVzdC5cbiAgICpcbiAgICogSW4gQVdTIENESyBjb2RlLCB5b3UgY2FuIGFjY2VzcyB0aGUgbG9nIGdyb3VwIG5hbWUgZGlyZWN0bHkgZnJvbSB0aGUgTG9nR3JvdXAgY29uc3RydWN0OlxuICAgKiBgYGB0c1xuICAgKiBpbXBvcnQgKiBhcyBsb2dzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbiAgICpcbiAgICogZGVjbGFyZSBjb25zdCBteUxvZ0dyb3VwOiBsb2dzLkxvZ0dyb3VwO1xuICAgKiBteUxvZ0dyb3VwLmxvZ0dyb3VwTmFtZTtcbiAgICogYGBgXG4gICAqXG4gICAqIEBkZWZhdWx0IGxvZ3MuUmV0ZW50aW9uRGF5cy5JTkZJTklURVxuICAgKi9cbiAgcmVhZG9ubHkgbG9nUmV0ZW50aW9uPzogUmV0ZW50aW9uRGF5cztcbiAgLyoqXG4gICAqIFRoZSBsb2cgZ3JvdXAgdGhlIGZ1bmN0aW9uIHNlbmRzIGxvZ3MgdG8uXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQsIExhbWJkYSBmdW5jdGlvbnMgc2VuZCBsb2dzIHRvIGFuIGF1dG9tYXRpY2FsbHkgY3JlYXRlZCBkZWZhdWx0IGxvZyBncm91cCBuYW1lZCAvYXdzL2xhbWJkYS9cXDxmdW5jdGlvbiBuYW1lXFw+LlxuICAgKiBIb3dldmVyIHlvdSBjYW5ub3QgY2hhbmdlIHRoZSBwcm9wZXJ0aWVzIG9mIHRoaXMgYXV0by1jcmVhdGVkIGxvZyBncm91cCB1c2luZyB0aGUgQVdTIENESywgZS5nLiB5b3UgY2Fubm90IHNldCBhIGRpZmZlcmVudCBsb2cgcmV0ZW50aW9uLlxuICAgKlxuICAgKiBVc2UgdGhlIGBsb2dHcm91cGAgcHJvcGVydHkgdG8gY3JlYXRlIGEgZnVsbHkgY3VzdG9taXphYmxlIExvZ0dyb3VwIGFoZWFkIG9mIHRpbWUsIGFuZCBpbnN0cnVjdCB0aGUgTGFtYmRhIGZ1bmN0aW9uIHRvIHNlbmQgbG9ncyB0byBpdC5cbiAgICpcbiAgICogUHJvdmlkaW5nIGEgdXNlci1jb250cm9sbGVkIGxvZyBncm91cCB3YXMgcm9sbGVkIG91dCB0byBjb21tZXJjaWFsIHJlZ2lvbnMgb24gMjAyMy0xMS0xNi5cbiAgICogSWYgeW91IGFyZSBkZXBsb3lpbmcgdG8gYW5vdGhlciB0eXBlIG9mIHJlZ2lvbiwgcGxlYXNlIGNoZWNrIHJlZ2lvbmFsIGF2YWlsYWJpbGl0eSBmaXJzdC5cbiAgICpcbiAgICogQGRlZmF1bHQgYC9hd3MvbGFtYmRhLyR7dGhpcy5mdW5jdGlvbk5hbWV9YCAtIGRlZmF1bHQgbG9nIGdyb3VwIGNyZWF0ZWQgYnkgTGFtYmRhXG4gICAqL1xuICByZWFkb25seSBsb2dHcm91cD86IElMb2dHcm91cDtcbiAgLyoqXG4gICAqIEEgdW5pcXVlIGlkZW50aWZpZXIgdG8gaWRlbnRpZnkgdGhpcyBwcm92aWRlclxuICAgKlxuICAgKiBPdmVyd3JpdGUgdGhlIGRlZmF1bHQsIGlmIHlvdSBuZWVkIGEgZGVkaWNhdGVkIHByb3ZpZGVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCBTb3BzU3luY1Byb3ZpZGVyXG4gICAqL1xuICByZWFkb25seSB1dWlkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgU29wc1N5bmNQcm92aWRlciBleHRlbmRzIFNpbmdsZXRvbkZ1bmN0aW9uIGltcGxlbWVudHMgSUdyYW50YWJsZSB7XG4gIHByaXZhdGUgc29wc0FnZUtleXM6IFNlY3JldFZhbHVlW107XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ/OiBzdHJpbmcsIHByb3BzPzogU29wc1N5bmNQcm92aWRlclByb3BzKSB7XG4gICAgaWYgKGlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIEFubm90YXRpb25zLm9mKHNjb3BlKS5hZGRXYXJuaW5nVjIoXG4gICAgICAgICdjZGstc29wcy1zZWNyZXRzOm9taXR0aW5nSWRGb3JTb3BzU3luY1Byb3ZpZGVyJyxcbiAgICAgICAgJ09taXR0aW5nIGlkIGlzIGRlcHJlY2F0ZWQuIFBsZWFzZSBwcm92aWRlIGFuIGlkIGZvciB0aGUgU29wc1N5bmNQcm92aWRlci4gRGVmYXVsdCBpZCB3aWxsIGJlIHJlbW92ZWQgaW4gVjMuJyxcbiAgICAgICk7XG4gICAgfVxuICAgIHN1cGVyKHNjb3BlLCBpZCA/PyAnU29wc1N5bmNQcm92aWRlcicsIHtcbiAgICAgIGNvZGU6IENvZGUuZnJvbUFzc2V0KFxuICAgICAgICBzY29wZS5ub2RlLnRyeUdldENvbnRleHQoJ3NvcHNfc3luY19wcm92aWRlcl9hc3NldF9wYXRoJykgfHxcbiAgICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vYXNzZXRzL2Nkay1zb3BzLWxhbWJkYS56aXAnKSxcbiAgICAgICksXG4gICAgICBydW50aW1lOiBSdW50aW1lLlBST1ZJREVEX0FMMixcbiAgICAgIGhhbmRsZXI6ICdib290c3RyYXAnLFxuICAgICAgdXVpZDogcHJvcHM/LnV1aWQgPz8gJ1NvcHNTeW5jUHJvdmlkZXInLFxuICAgICAgcm9sZTogcHJvcHM/LnJvbGUsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDYwKSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIFNPUFNfQUdFX0tFWTogTGF6eS5zdHJpbmcoe1xuICAgICAgICAgIHByb2R1Y2U6ICgpID0+XG4gICAgICAgICAgICAodGhpcy5zb3BzQWdlS2V5cy5tYXAoKHNlY3JldCkgPT4gc2VjcmV0LnRvU3RyaW5nKCkpID8/IFtdKS5qb2luKFxuICAgICAgICAgICAgICAnXFxuJyxcbiAgICAgICAgICAgICksXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICAgIHZwYzogcHJvcHM/LnZwYyxcbiAgICAgIHZwY1N1Ym5ldHM6IHByb3BzPy52cGNTdWJuZXRzLFxuICAgICAgc2VjdXJpdHlHcm91cHM6IHByb3BzPy5zZWN1cml0eUdyb3VwcyxcbiAgICAgIGxvZ1JldGVudGlvbjogcHJvcHM/LmxvZ1JldGVudGlvbixcbiAgICAgIGxvZ0dyb3VwOiBwcm9wcz8ubG9nR3JvdXAsXG4gICAgfSk7XG4gICAgdGhpcy5zb3BzQWdlS2V5cyA9IFtdO1xuICB9XG5cbiAgcHVibGljIGFkZEFnZUtleShrZXk6IFNlY3JldFZhbHVlKSB7XG4gICAgdGhpcy5zb3BzQWdlS2V5cy5wdXNoKGtleSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgY3VzdG9tIHJlc291cmNlLCB0aGF0IGlzIHN5bmNpbmcgdGhlIGNvbnRlbnQgZnJvbSBhIHNvcHMgZmlsZSB0byBhIHNlY3JldC5cbiAqL1xuZXhwb3J0IGNsYXNzIFNvcHNTeW5jIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IHZlcnNpb25JZCBvZiB0aGUgc2VjcmV0IHBvcHVsYXRlZCB2aWEgdGhpcyByZXNvdXJjZVxuICAgKi9cbiAgcmVhZG9ubHkgdmVyc2lvbklkOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFNvcHNTeW5jUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3QgcHJvdmlkZXIgPVxuICAgICAgcHJvcHMuc29wc1Byb3ZpZGVyID8/IG5ldyBTb3BzU3luY1Byb3ZpZGVyKHNjb3BlLCAnU29wc1N5bmNQcm92aWRlcicpO1xuXG4gICAgbGV0IHVwbG9hZFR5cGUgPSBwcm9wcy51cGxvYWRUeXBlID8/IFVwbG9hZFR5cGUuSU5MSU5FO1xuICAgIGxldCBzb3BzRmlsZUZvcm1hdDogJ2pzb24nIHwgJ3lhbWwnIHwgJ2RvdGVudicgfCAnYmluYXJ5JyB8IHVuZGVmaW5lZCA9XG4gICAgICBwcm9wcy5zb3BzRmlsZUZvcm1hdDtcbiAgICBsZXQgc29wc0Fzc2V0OiBBc3NldCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICBsZXQgc29wc0lubGluZTogeyBDb250ZW50OiBzdHJpbmc7IEhhc2g6IHN0cmluZyB9IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgIGxldCBzb3BzUzNGaWxlOiB7IEJ1Y2tldDogc3RyaW5nOyBLZXk6IHN0cmluZyB9IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuXG4gICAgaWYgKFxuICAgICAgKHByb3BzLnNvcHNGaWxlUGF0aCA9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHByb3BzLnNvcHNTM0J1Y2tldCA9PSB1bmRlZmluZWQgfHwgcHJvcHMuc29wc1MzS2V5ID09IHVuZGVmaW5lZCkpIHx8XG4gICAgICAocHJvcHMuc29wc0ZpbGVQYXRoICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgcHJvcHMuc29wc1MzQnVja2V0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgcHJvcHMuc29wc1MzS2V5ICE9PSB1bmRlZmluZWQpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdZb3UgY2FuIGVpdGhlciBzcGVjaWZ5IHNvcHNGaWxlUGF0aCBvciBzb3BzUzNCdWNrZXQgYW5kIHNvcHNTM0tleSEnLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAocHJvcHMuc29wc0ZpbGVQYXRoICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmIChzb3BzRmlsZUZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0IF9zb3BzRmlsZUZvcm1hdCA9IHByb3BzLnNvcHNGaWxlUGF0aC5zcGxpdCgnLicpLnBvcCgpO1xuICAgICAgICBzd2l0Y2ggKF9zb3BzRmlsZUZvcm1hdCkge1xuICAgICAgICAgIGNhc2UgJ2pzb24nOiB7XG4gICAgICAgICAgICBzb3BzRmlsZUZvcm1hdCA9ICdqc29uJztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjYXNlICd5YW1sJzoge1xuICAgICAgICAgICAgc29wc0ZpbGVGb3JtYXQgPSAneWFtbCc7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgY2FzZSAneW1sJzoge1xuICAgICAgICAgICAgc29wc0ZpbGVGb3JtYXQgPSAneWFtbCc7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgY2FzZSAnZG90ZW52Jzoge1xuICAgICAgICAgICAgc29wc0ZpbGVGb3JtYXQgPSAnZG90ZW52JztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjYXNlICdlbnYnOiB7XG4gICAgICAgICAgICBzb3BzRmlsZUZvcm1hdCA9ICdkb3RlbnYnO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNhc2UgJ2JpbmFyeSc6IHtcbiAgICAgICAgICAgIHNvcHNGaWxlRm9ybWF0ID0gJ2JpbmFyeSc7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgQW5ub3RhdGlvbnMub2YodGhpcykuYWRkRXJyb3IoXG4gICAgICAgICAgICAgIFwiRmFpbGVkIHRvIGRldGVybWluZSBzb3BzIGZpbGUgZm9ybWF0LiBQbGVhc2Ugc3BlY2lmeSAnc29wc0ZpbGVGb3JtYXQnIVwiLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHByb3BzLnNvcHNGaWxlUGF0aCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBGaWxlICR7cHJvcHMuc29wc0ZpbGVQYXRofSBkb2VzIG5vdCBleGlzdCFgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNvcHNGaWxlQ29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhwcm9wcy5zb3BzRmlsZVBhdGgpO1xuXG4gICAgICBzd2l0Y2ggKHVwbG9hZFR5cGUpIHtcbiAgICAgICAgY2FzZSBVcGxvYWRUeXBlLklOTElORToge1xuICAgICAgICAgIHNvcHNJbmxpbmUgPSB7XG4gICAgICAgICAgICBDb250ZW50OiBzb3BzRmlsZUNvbnRlbnQudG9TdHJpbmcoJ2Jhc2U2NCcpLFxuICAgICAgICAgICAgLy8gV2UgY2FsY3VsYXRlIHRoZSBoYXNoIHRoZSBzYW1lIHdheSBhcyBpdCB3b3VsZCBiZSBkb25lIGJ5IG5ldyBBc3NldCguLikgLSBzbyB3ZSBjYW4gZW5zdXJlIHN0YWJsZSB2ZXJzaW9uIG5hbWVzIGV2ZW4gaWYgc3dpdGNoaW5nIGZyb20gSU5MSU5FIHRvIEFTU0VUIGFuZCB2aWNldmVyc2EuXG4gICAgICAgICAgICBIYXNoOiBGaWxlU3lzdGVtLmZpbmdlcnByaW50KHByb3BzLnNvcHNGaWxlUGF0aCksXG4gICAgICAgICAgfTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFVwbG9hZFR5cGUuQVNTRVQ6IHtcbiAgICAgICAgICBzb3BzQXNzZXQgPSBuZXcgQXNzZXQodGhpcywgJ0Fzc2V0Jywge1xuICAgICAgICAgICAgcGF0aDogcHJvcHMuc29wc0ZpbGVQYXRoLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHNvcHNTM0ZpbGUgPSB7XG4gICAgICAgICAgICBCdWNrZXQ6IHNvcHNBc3NldC5idWNrZXQuYnVja2V0TmFtZSxcbiAgICAgICAgICAgIEtleTogc29wc0Fzc2V0LnMzT2JqZWN0S2V5LFxuICAgICAgICAgIH07XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICAvLyBJcyBhbGx3YXlzIHRydWUsIGJ1dCB0byBzYXRpc2Z5IFRTIHdlIGNoZWNrIGV4cGxpY2l0bHlcbiAgICAgICAgcHJvdmlkZXIucm9sZSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgIC8vIENoZWNrIGlmIHVzZXIgaGFzIGRpc2FibGVkIGF1dG9tYXRpYyBnZW5lcmF0aW9uXG4gICAgICAgIHByb3BzLmF1dG9HZW5lcmF0ZUlhbVBlcm1pc3Npb25zICE9PSBmYWxzZVxuICAgICAgKSB7XG4gICAgICAgIFBlcm1pc3Npb25zLnNvcHNLZXlzKHRoaXMsIHtcbiAgICAgICAgICB1c2VyRGVmaW5lZEtleXM6IHByb3BzLnNvcHNLbXNLZXksXG4gICAgICAgICAgcm9sZTogcHJvdmlkZXIucm9sZSxcbiAgICAgICAgICBzb3BzRmlsZUNvbnRlbnQ6IHNvcHNGaWxlQ29udGVudC50b1N0cmluZygpLFxuICAgICAgICB9KTtcbiAgICAgICAgUGVybWlzc2lvbnMuYXNzZXRCdWNrZXQoXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBzb3BzQXNzZXQsXG4gICAgICAgICAgcHJvdmlkZXIucm9sZSxcbiAgICAgICAgICBwcm9wcy5hc3NldEVuY3J5cHRpb25LZXksXG4gICAgICAgICk7XG4gICAgICAgIFBlcm1pc3Npb25zLmVuY3J5cHRpb25LZXkocHJvcHMuZW5jcnlwdGlvbktleSwgcHJvdmlkZXIucm9sZSk7XG4gICAgICAgIFBlcm1pc3Npb25zLnNlY3JldChwcm9wcy5zZWNyZXQsIHByb3ZpZGVyLnJvbGUpO1xuICAgICAgICBQZXJtaXNzaW9ucy5wYXJhbWV0ZXJzKHRoaXMsIHByb3BzLnBhcmFtZXRlck5hbWVzLCBwcm92aWRlci5yb2xlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIEFubm90YXRpb25zLm9mKHRoaXMpLmFkZFdhcm5pbmcoXG4gICAgICAgICAgW1xuICAgICAgICAgICAgJ1BsZWFzZSBlbnN1cmUgcHJvcGVyIHBlcm1pc3Npb25zIGZvciB0aGUgcGFzc2VkIGxhbWJkYSBmdW5jdGlvbjonLFxuICAgICAgICAgICAgJyAgLSB3cml0ZSBBY2Nlc3MgdG8gdGhlIHNlY3JldC9wYXJhbWV0ZXJzJyxcbiAgICAgICAgICAgICcgIC0gZW5jcnlwdCB3aXRoIHRoZSBzb3BzS21zS2V5JyxcbiAgICAgICAgICAgICcgIC0gZG93bmxvYWQgZnJvbSBhc3NldCBidWNrZXQnLFxuICAgICAgICAgIF0uam9pbignXFxuJyksXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAocHJvcHMuc29wc0FnZUtleSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHByb3ZpZGVyLmFkZEFnZUtleShwcm9wcy5zb3BzQWdlS2V5KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKFxuICAgICAgcHJvcHMuc29wc1MzQnVja2V0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIHByb3BzLnNvcHNTM0tleSAhPT0gdW5kZWZpbmVkXG4gICAgKSB7XG4gICAgICBzb3BzUzNGaWxlID0ge1xuICAgICAgICBCdWNrZXQ6IHByb3BzLnNvcHNTM0J1Y2tldCxcbiAgICAgICAgS2V5OiBwcm9wcy5zb3BzUzNLZXksXG4gICAgICB9O1xuICAgICAgdXBsb2FkVHlwZSA9IFVwbG9hZFR5cGUuQVNTRVQ7XG4gICAgICBBbm5vdGF0aW9ucy5vZih0aGlzKS5hZGRXYXJuaW5nKFxuICAgICAgICAnWW91IGhhdmUgdG8gbWFudWFsbHkgYWRkIHBlcm1pc3Npb25zIHRvIHRoZSBzb3BzIHByb3ZpZGVyIHRvIChwZXJtaXNzaW9uIHRvIGRvd25sb2FkIGZpbGUsIHRvIGRlY3J5cHQgc29wcyBmaWxlKSEnLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoc29wc0ZpbGVGb3JtYXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgaGF2ZSB0byBzcGVjaWZ5IHNvcHNGaWxlRm9ybWF0IScpO1xuICAgIH1cblxuICAgIGNvbnN0IGNyID0gbmV3IEN1c3RvbVJlc291cmNlKHRoaXMsICdSZXNvdXJjZScsIHtcbiAgICAgIHNlcnZpY2VUb2tlbjogcHJvdmlkZXIuZnVuY3Rpb25Bcm4sXG4gICAgICByZXNvdXJjZVR5cGU6ICdDdXN0b206OlNvcHNTeW5jJyxcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgU29wc1MzRmlsZTogc29wc1MzRmlsZSxcbiAgICAgICAgU29wc0lubGluZTogc29wc0lubGluZSxcbiAgICAgICAgRmxhdHRlblNlcGFyYXRvcjogcHJvcHMuZmxhdHRlblNlcGFyYXRvcixcbiAgICAgICAgRm9ybWF0OiBzb3BzRmlsZUZvcm1hdCxcbiAgICAgICAgRW5jcnlwdGlvbktleTogcHJvcHMuZW5jcnlwdGlvbktleT8ua2V5SWQsXG4gICAgICAgIFJlc291cmNlVHlwZTogcHJvcHMucmVzb3VyY2VUeXBlLFxuICAgICAgICBUYXJnZXQ6IHByb3BzLnRhcmdldCxcbiAgICAgIH0gc2F0aXNmaWVzIFNvcHNTeW5jUmVzb3VyY2VQcm9wZXJ0eXMsXG4gICAgfSk7XG4gICAgdGhpcy52ZXJzaW9uSWQgPSBjci5nZXRBdHRTdHJpbmcoJ1ZlcnNpb25JZCcpO1xuICB9XG59XG5cbmV4cG9ydCBuYW1lc3BhY2UgUGVybWlzc2lvbnMge1xuICAvKipcbiAgICogR3JhbnRzIHRoZSBuZWNlc3NhcnkgcGVybWlzc2lvbnMgZm9yIGVuY3J5cHQvZGVjcnlwdCBvbiB0aGUgY3VzdG9tZXIgbWFuYWdlZCBlbmNyeXB0aW9uIGtleVxuICAgKiBmb3IgdGhlIHNlY3JldHMgLyBwYXJhbWV0ZXJzLlxuICAgKi9cbiAgZXhwb3J0IGZ1bmN0aW9uIGVuY3J5cHRpb25LZXkoa2V5OiBJS2V5IHwgdW5kZWZpbmVkLCB0YXJnZXQ6IElHcmFudGFibGUpIHtcbiAgICBpZiAoa2V5ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAga2V5LmdyYW50RW5jcnlwdERlY3J5cHQodGFyZ2V0KTtcbiAgfVxuXG4gIGV4cG9ydCBmdW5jdGlvbiBrZXlzRnJvbVNvcHNDb250ZW50KGN0eDogQ29uc3RydWN0LCBjOiBzdHJpbmcpOiBJS2V5W10ge1xuICAgIGNvbnN0IHJlZ2V4S2V5ID0gL2Fybjphd3M6a21zOlthLXowLTktXSs6W1xcZF0rOmtleVxcL1thLXowLTktXSsvZztcbiAgICBjb25zdCByZXN1bHRzS2V5ID0gYy5tYXRjaChyZWdleEtleSk7XG4gICAgaWYgKHJlc3VsdHNLZXkgIT09IG51bGwpIHtcbiAgICAgIHJldHVybiByZXN1bHRzS2V5Lm1hcCgocmVzdWx0LCBpbmRleCkgPT5cbiAgICAgICAgS2V5LmZyb21LZXlBcm4oY3R4LCBgU29wc0tleSR7aW5kZXh9YCwgcmVzdWx0KSxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGV4cG9ydCBmdW5jdGlvbiBrZXlzRnJvbVNvcHNDb250ZW50QWxpYXMoY3R4OiBDb25zdHJ1Y3QsIGM6IHN0cmluZyk6IElLZXlbXSB7XG4gICAgY29uc3QgcmVnZXhBbGlhcyA9IC9hcm46YXdzOmttczpbYS16MC05LV0rOltcXGRdKzphbGlhc1xcL1thLXowLTktQS1aXFwvXSsvZztcbiAgICBjb25zdCByZXN1bHRzQWxpYXMgPSBjLm1hdGNoKHJlZ2V4QWxpYXMpO1xuICAgIGlmIChyZXN1bHRzQWxpYXMgIT09IG51bGwpIHtcbiAgICAgIHJldHVybiByZXN1bHRzQWxpYXMubWFwKChyZXN1bHQsIGluZGV4KSA9PlxuICAgICAgICBLZXkuZnJvbUxvb2t1cChjdHgsIGBTb3BzQWxpYXMke2luZGV4fWAsIHtcbiAgICAgICAgICBhbGlhc05hbWU6IGBhbGlhcy8ke3Jlc3VsdC5zcGxpdCgnLycpLnNsaWNlKDEpLmpvaW4oJy8nKX1gLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHcmFudHMgdGhlIG5lY2Vzc2FyeSBwZXJtaXNzaW9ucyB0byBkZWNyeXB0IHRoZSBnaXZlbiBzb3BzIGZpbGUgY29udGVudC5cbiAgICogVGFrZXMgdXNlciBkZWZpbmVkIGtleXMsIGFuZCBzZWFyY2hlcyB0aGUgc29wcyBmaWxlIGZvciBrZXlzIGFuZCBhbGlhc2VzLlxuICAgKi9cbiAgZXhwb3J0IGZ1bmN0aW9uIHNvcHNLZXlzKFxuICAgIGN0eDogQ29uc3RydWN0LFxuICAgIHByb3BzOiB7XG4gICAgICB1c2VyRGVmaW5lZEtleXM/OiBJS2V5W107XG4gICAgICBzb3BzRmlsZUNvbnRlbnQ6IHN0cmluZztcbiAgICAgIHJvbGU6IElSb2xlO1xuICAgIH0sXG4gICkge1xuICAgIChwcm9wcy51c2VyRGVmaW5lZEtleXMgPz8gW10pXG4gICAgICAuY29uY2F0KFxuICAgICAgICBrZXlzRnJvbVNvcHNDb250ZW50KGN0eCwgcHJvcHMuc29wc0ZpbGVDb250ZW50KSxcbiAgICAgICAga2V5c0Zyb21Tb3BzQ29udGVudEFsaWFzKGN0eCwgcHJvcHMuc29wc0ZpbGVDb250ZW50KSxcbiAgICAgIClcbiAgICAgIC5mb3JFYWNoKChrZXkpID0+IGtleS5ncmFudERlY3J5cHQocHJvcHMucm9sZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdyYW50cyB0aGUgbmVjZXNzYXJ5IHBlcm1pc3Npb25zIHRvIHdyaXRlIHRoZSBnaXZlbiBzZWNyZXRzLlxuICAgKi9cbiAgZXhwb3J0IGZ1bmN0aW9uIHNlY3JldChcbiAgICB0YXJnZXRTZWNyZXQ6IElTZWNyZXQgfCB1bmRlZmluZWQsXG4gICAgdGFyZ2V0OiBJR3JhbnRhYmxlLFxuICApIHtcbiAgICBpZiAodGFyZ2V0U2VjcmV0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGFyZ2V0U2VjcmV0LmdyYW50V3JpdGUodGFyZ2V0KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNsaWNlUGFyYW1ldGVycyhwYXJhbXM6IHN0cmluZ1tdKTogc3RyaW5nW11bXSB7XG4gICAgY29uc3QgcmVzdWx0OiBzdHJpbmdbXVtdID0gW107XG4gICAgLyoqXG4gICAgICogVGhlIG1heGltdW0gc2l6ZSBvZiBhIG1hbmFnZWQgcG9saWN5IGlzIDYuMTQ0IGJ5dGVzIC0+IDEgY2hhcmFjdGVyID0gMSBieXRlXG4gICAgICogYm91dCAzMDAgY2hhcmFjdGVycyBhcmUgcmVzZXJ2ZWQgZm9yIHRoZSBwb2xpY3kgYXBhcnQgZnJvbSByZXNvdXJjZSBhcm5zXG4gICAgICogd2l0aCBzb21lIGJ1ZmZlciwgd2UgZW5kIHdpdGggYW4gdXBwZXIgbGltaXQgb2YgNTc1MCBieXRlc1xuICAgICAqL1xuICAgIGNvbnN0IGxpbWl0ID0gNTc1MDtcblxuICAgIC8qKlxuICAgICAqIENvbnRlbnQgZm9yIFwiYXJuOmF3czpzc206YXAtc291dGhlYXN0LTM6PGFjY291bnRudW1lcj46cGFyYW1ldGVyL1xuICAgICAqL1xuICAgIGNvbnN0IHByZWZpeCA9IDU1O1xuXG4gICAgbGV0IGN1cnJlbnRTaXplID0gMDtcbiAgICBsZXQgY3VycmVudENodW5rOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcGFyYW0gb2YgcGFyYW1zKSB7XG4gICAgICBjb25zdCBwYXJhbUxlbmd0aCA9IHBhcmFtLmxlbmd0aCArIHByZWZpeDtcbiAgICAgIGlmIChjdXJyZW50U2l6ZSArIHBhcmFtTGVuZ3RoID4gbGltaXQpIHtcbiAgICAgICAgcmVzdWx0LnB1c2goY3VycmVudENodW5rKTtcbiAgICAgICAgY3VycmVudENodW5rID0gW107XG4gICAgICAgIGN1cnJlbnRTaXplID0gMDtcbiAgICAgIH1cbiAgICAgIGN1cnJlbnRDaHVuay5wdXNoKHBhcmFtKTtcbiAgICAgIGN1cnJlbnRTaXplICs9IHBhcmFtTGVuZ3RoO1xuICAgIH1cblxuICAgIGlmIChjdXJyZW50Q2h1bmsubGVuZ3RoID4gMCkge1xuICAgICAgcmVzdWx0LnB1c2goY3VycmVudENodW5rKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHcmFudHMgdGhlIG5lY2Vzc2FyeSBwZXJtaXNzaW9ucyB0byB3cml0ZSB0aGUgZ2l2ZW4gcGFyYW1ldGVycy5cbiAgICovXG4gIGV4cG9ydCBmdW5jdGlvbiBwYXJhbWV0ZXJzKFxuICAgIGN0eDogQ29uc3RydWN0LFxuICAgIHRhcmdldFBhcmFtZXRlcnM6IHN0cmluZ1tdIHwgdW5kZWZpbmVkLFxuICAgIHJvbGU6IElSb2xlLFxuICApIHtcbiAgICBpZiAodGFyZ2V0UGFyYW1ldGVycyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFyYW1TbGljZXMgPSBzbGljZVBhcmFtZXRlcnModGFyZ2V0UGFyYW1ldGVycyk7XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcmFtU2xpY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBwdXRQb2xpY3kgPSBuZXcgTWFuYWdlZFBvbGljeShcbiAgICAgICAgY3R4LFxuICAgICAgICBgU29wc1NlY3JldFBhcmFtZXRlclByb3ZpZGVyTWFuYWdlZFBvbGljeVBhcmFtZXRlckFjY2VzcyR7aX1gLFxuICAgICAgICB7XG4gICAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgICAnUG9saWN5IHRvIGdyYW50IHBhcmFtZXRlciBwcm92aWRlciBwZXJtaXNzaW9ucyB0byBwdXQgcGFyYW1ldGVyJyxcbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgICBwdXRQb2xpY3kuYWRkU3RhdGVt