UNPKG

cdk-sops-secrets

Version:

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

297 lines • 51.6 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.SopsSecret = exports.RawOutput = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const crypto_1 = require("crypto"); const aws_iam_1 = require("aws-cdk-lib/aws-iam"); const aws_kms_1 = require("aws-cdk-lib/aws-kms"); const aws_scheduler_1 = require("aws-cdk-lib/aws-scheduler"); const aws_secretsmanager_1 = require("aws-cdk-lib/aws-secretsmanager"); const aws_sns_1 = require("aws-cdk-lib/aws-sns"); const core_1 = require("aws-cdk-lib/core"); const constructs_1 = require("constructs"); const SopsSync_1 = require("./SopsSync"); const structuredData_1 = require("./structuredData"); var RawOutput; (function (RawOutput) { /** * Parse the secret as a string */ RawOutput["STRING"] = "STRING"; /** * Parse the secret as a binary */ RawOutput["BINARY"] = "BINARY"; })(RawOutput || (exports.RawOutput = RawOutput = {})); const DEFAULT_EXPIRATION_SUFFIX = '_expiration'; const DEFAULT_DAYS_BEFORE_EXPIRATION = 14; function sanitizeScheduleComponent(name) { return name.replace(/[^a-zA-Z0-9_-]/g, '-').replace(/^-+|-+$/g, ''); } function normalizeDaysBeforeExpiration(daysBeforeExpiration) { const configuredDays = Array.isArray(daysBeforeExpiration) ? daysBeforeExpiration : [daysBeforeExpiration ?? DEFAULT_DAYS_BEFORE_EXPIRATION]; if (configuredDays.length === 0) { throw new Error('daysBeforeExpiration must contain at least one non-negative integer.'); } const uniqueDays = Array.from(new Set(configuredDays)); uniqueDays.forEach((value) => { if (!Number.isInteger(value) || value < 0) { throw new Error(`daysBeforeExpiration must contain only non-negative integers, got "${value}".`); } }); return uniqueDays.sort((left, right) => left - right); } function scheduleOffsetSuffix(daysBeforeExpiration, includeReminderOffsetInIdentity) { return includeReminderOffsetInIdentity ? `-${daysBeforeExpiration}d` : ''; } function formatDaysBeforeExpiration(daysBeforeExpiration) { return `${daysBeforeExpiration} day${daysBeforeExpiration === 1 ? '' : 's'}`; } function sanitizeScheduleName(secretName, keyName, daysBeforeExpiration, includeReminderOffsetInIdentity) { const offsetSuffix = scheduleOffsetSuffix(daysBeforeExpiration, includeReminderOffsetInIdentity); const nameHash = (0, crypto_1.createHash)('sha1') .update(`${secretName}\0${keyName}\0${offsetSuffix}`) .digest('hex') .slice(0, 10); const sanitizedSecretName = sanitizeScheduleComponent(secretName); const sanitizedKeyName = sanitizeScheduleComponent(keyName); const readableName = [ sanitizedSecretName, sanitizedKeyName, offsetSuffix.slice(1), ] .filter((component) => component.length > 0) .join('-'); const maxReadableLength = 64 - nameHash.length - 1; const truncatedReadableName = readableName .slice(0, maxReadableLength) .replace(/-+$/g, ''); const scheduleName = truncatedReadableName.length > 0 ? truncatedReadableName : 'schedule'; return `${scheduleName}-${nameHash}`; } function scheduleResourceId(keyName, daysBeforeExpiration, includeReminderOffsetInIdentity) { const offsetSuffix = scheduleOffsetSuffix(daysBeforeExpiration, includeReminderOffsetInIdentity); const resourceHash = (0, crypto_1.createHash)('sha1') .update(`${keyName}\0${offsetSuffix}`) .digest('hex') .slice(0, 10); const readableKeyName = `${sanitizeScheduleComponent(keyName)}${offsetSuffix}` .slice(0, 48) .replace(/-+$/g, ''); const suffix = readableKeyName.length > 0 ? readableKeyName : 'Key'; return `ExpirationSchedule${suffix}${resourceHash}`; } function scheduleGroupResourceId() { return 'SopsSecretExpirationScheduleGroup'; } function scheduleGroupNameForStack(stack) { return sanitizeScheduleComponent(core_1.Names.uniqueId(stack)).slice(0, 64); } function parseExpirationDate(value) { const trimmed = value.trim(); if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) { const parsed = new Date(`${trimmed}T00:00:00.000Z`); if (!Number.isNaN(parsed.getTime())) { return parsed; } } const parsed = new Date(trimmed); if (Number.isNaN(parsed.getTime())) { throw new Error(`unsupported date format: "${value}"`); } return parsed; } function resolveExpirationSchedules(sourceData, expiration) { const suffix = expiration.expirationSuffix ?? DEFAULT_EXPIRATION_SUFFIX; const daysBeforeExpirationValues = normalizeDaysBeforeExpiration(expiration.daysBeforeExpiration); const schedules = []; const now = Date.now(); const includeReminderOffsetInIdentity = daysBeforeExpirationValues.length > 1; for (const key of Object.keys(sourceData).sort()) { if (!key.endsWith(suffix)) { continue; } const expiresAt = parseExpirationDate(sourceData[key]); const baseKey = key.slice(0, -suffix.length); daysBeforeExpirationValues.forEach((daysBeforeExpiration) => { const notifyAt = new Date(expiresAt.getTime()); notifyAt.setUTCDate(notifyAt.getUTCDate() - daysBeforeExpiration); if (notifyAt.getTime() < now) { return; } schedules.push({ baseKey, expiresAt, notifyAt, daysBeforeExpiration, includeReminderOffsetInIdentity, }); }); } return schedules; } function toIsoDateString(value) { return value.toISOString().slice(0, 10); } function truncateDescription(value) { return value.length > 512 ? value.slice(0, 512) : value; } function toScheduleExpression(value) { return `at(${value.toISOString().slice(0, 19)})`; } /** * A drop in replacement for the normal Secret, that is populated with the encrypted * content of the given sops file. */ class SopsSecret extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); this.secret = new aws_secretsmanager_1.Secret(this, 'Resource', props); // Fullfill secret Interface this.encryptionKey = this.secret.encryptionKey; this.secretArn = this.secret.secretArn; this.secretName = this.secret.secretName; this.secretRef = this.secret.secretRef; this.stack = core_1.Stack.of(scope); this.env = { account: this.stack.account, region: this.stack.region, }; let resourceType = props.sopsFileFormat == 'binary' ? SopsSync_1.ResourceType.SECRET_RAW : SopsSync_1.ResourceType.SECRET; if (props.rawOutput === RawOutput.BINARY) { resourceType = SopsSync_1.ResourceType.SECRET_BINARY; } if (props.rawOutput === RawOutput.STRING) { resourceType = SopsSync_1.ResourceType.SECRET_RAW; } const expiration = props.expirationNotification; if (expiration?.enabled ?? false) { const enabledExpiration = expiration; if (props.sopsFilePath === undefined) { throw new Error('Expiration scheduling requires a local sopsFilePath and does not support sopsS3Bucket/sopsS3Key.'); } if (props.rawOutput !== undefined) { throw new Error('Expiration scheduling does not support rawOutput. Remove rawOutput to use expirationNotification.'); } const fileFormat = props.sopsFileFormat === 'json' || props.sopsFileFormat === 'yaml' || props.sopsFileFormat === 'dotenv' ? props.sopsFileFormat : (0, structuredData_1.inferStructuredFileFormat)(props.sopsFilePath); if (fileFormat === undefined) { throw new Error('Expiration scheduling requires a structured local file in json, yaml, or dotenv format.'); } const topic = enabledExpiration.notificationTopic ?? new aws_sns_1.Topic(this, 'ExpirationNotificationTopic'); this.expirationNotificationTopic = topic; if (enabledExpiration.subscriber !== undefined) { topic.addSubscription(enabledExpiration.subscriber); } const schedulerRole = new aws_iam_1.Role(this, 'ExpirationSchedulerRole', { assumedBy: new aws_iam_1.ServicePrincipal('scheduler.amazonaws.com'), description: 'Role assumed by EventBridge Scheduler to publish expiration notifications', }); topic.grantPublish(schedulerRole); const scheduleGroupName = scheduleGroupNameForStack(this.stack); const existingScheduleGroup = this.stack.node.tryFindChild(scheduleGroupResourceId()); const scheduleGroup = existingScheduleGroup ?? new aws_scheduler_1.CfnScheduleGroup(this.stack, scheduleGroupResourceId(), { name: scheduleGroupName, }); this.addExpirationSchedules(props.sopsFilePath, fileFormat, enabledExpiration, props.secretName ?? core_1.Names.uniqueId(this), topic, schedulerRole, scheduleGroup, scheduleGroupName); } this.sync = new SopsSync_1.SopsSync(this, 'SopsSync', { target: this.secret.secretArn, resourceType, flattenSeparator: '.', secret: this.secret, ...props, }); } addExpirationSchedules(sopsFilePath, fileFormat, expiration, scheduleSecretName, topic, schedulerRole, scheduleGroup, scheduleGroupName) { const schedules = resolveExpirationSchedules((0, structuredData_1.flattenStructuredFileToStringMap)(sopsFilePath, '.', fileFormat), expiration); schedules.forEach((entry) => { const scheduleName = sanitizeScheduleName(scheduleSecretName, entry.baseKey, entry.daysBeforeExpiration, entry.includeReminderOffsetInIdentity); const summary = `Secret key "${entry.baseKey}" in ${scheduleSecretName} expires on ${toIsoDateString(entry.expiresAt)}.`; const leadTime = formatDaysBeforeExpiration(entry.daysBeforeExpiration); const message = [ 'SOPS secret expiration notification', '', summary, '', `Stack: ${this.stack.stackName}`, `Region: ${this.stack.region}`, `Account: ${this.stack.account}`, `Secret name: ${scheduleSecretName}`, `Secret ARN: ${this.secret.secretArn}`, `Key name: ${entry.baseKey}`, `Notification lead time: ${leadTime}`, `Expiration time: ${entry.expiresAt.toISOString()}`, ].join('\n'); const schedule = new aws_scheduler_1.CfnSchedule(this, scheduleResourceId(entry.baseKey, entry.daysBeforeExpiration, entry.includeReminderOffsetInIdentity), { description: truncateDescription(`Notify about expiration of SOPS secret key "${entry.baseKey}" ${leadTime} before expiration.`), groupName: scheduleGroupName, name: scheduleName, scheduleExpression: toScheduleExpression(entry.notifyAt), flexibleTimeWindow: { mode: 'OFF', }, target: { arn: topic.topicArn, roleArn: schedulerRole.roleArn, input: message, }, }); schedule.addDependency(scheduleGroup); }); } currentVersionId() { return this.sync.versionId; } grantRead(grantee, versionStages) { if (this.encryptionKey) { // @see https://docs.aws.amazon.com/kms/latest/developerguide/services-secrets-manager.html this.encryptionKey.grantDecrypt(new aws_kms_1.ViaServicePrincipal(`secretsmanager.${core_1.Stack.of(this).region}.amazonaws.com`, grantee.grantPrincipal)); } return this.secret.grantRead(grantee, versionStages); } grantWrite(_grantee) { throw new Error(`Method grantWrite(...) not allowed as this secret is managed by SopsSync`); } addRotationSchedule(id, options) { throw new Error(`Method addRotationSchedule('${id}', ${JSON.stringify(options)}) not allowed as this secret is managed by SopsSync`); } addToResourcePolicy(statement) { return this.secret.addToResourcePolicy(statement); } denyAccountRootDelete() { return this.secret.denyAccountRootDelete(); } attach(target) { return this.secret.attach(target); } cfnDynamicReferenceKey(options) { return this.secret.cfnDynamicReferenceKey(options); } applyRemovalPolicy(policy) { return this.secret.applyRemovalPolicy(policy); } secretValueFromJson(jsonField) { return core_1.SecretValue.secretsManager(this.secretArn, { jsonField, versionId: this.sync.versionId, }); } get secretValue() { return this.secretValueFromJson(''); } } exports.SopsSecret = SopsSecret; _a = JSII_RTTI_SYMBOL_1; SopsSecret[_a] = { fqn: "cdk-sops-secrets.SopsSecret", version: "2.8.1" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU29wc1NlY3JldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9Tb3BzU2VjcmV0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQW9DO0FBQ3BDLGlEQU82QjtBQUM3QixpREFBZ0U7QUFDaEUsNkRBQTBFO0FBQzFFLHVFQVN3QztBQUN4QyxpREFBd0U7QUFDeEUsMkNBTzBCO0FBQzFCLDJDQUF1QztBQUN2Qyx5Q0FBcUU7QUFDckUscURBSTBCO0FBRTFCLElBQVksU0FTWDtBQVRELFdBQVksU0FBUztJQUNuQjs7T0FFRztJQUNILDhCQUFpQixDQUFBO0lBQ2pCOztPQUVHO0lBQ0gsOEJBQWlCLENBQUE7QUFDbkIsQ0FBQyxFQVRXLFNBQVMseUJBQVQsU0FBUyxRQVNwQjtBQXVHRCxNQUFNLHlCQUF5QixHQUFHLGFBQWEsQ0FBQztBQUNoRCxNQUFNLDhCQUE4QixHQUFHLEVBQUUsQ0FBQztBQVUxQyxTQUFTLHlCQUF5QixDQUFDLElBQVk7SUFDN0MsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDdEUsQ0FBQztBQUVELFNBQVMsNkJBQTZCLENBQ3BDLG9CQUF3QztJQUV4QyxNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDO1FBQ3hELENBQUMsQ0FBQyxvQkFBb0I7UUFDdEIsQ0FBQyxDQUFDLENBQUMsb0JBQW9CLElBQUksOEJBQThCLENBQUMsQ0FBQztJQUU3RCxJQUFJLGNBQWMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDaEMsTUFBTSxJQUFJLEtBQUssQ0FDYixzRUFBc0UsQ0FDdkUsQ0FBQztJQUNKLENBQUM7SUFFRCxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUM7SUFDdkQsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1FBQzNCLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMxQyxNQUFNLElBQUksS0FBSyxDQUNiLHNFQUFzRSxLQUFLLElBQUksQ0FDaEYsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDLENBQUMsQ0FBQztJQUVILE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQztBQUN4RCxDQUFDO0FBRUQsU0FBUyxvQkFBb0IsQ0FDM0Isb0JBQTRCLEVBQzVCLCtCQUF3QztJQUV4QyxPQUFPLCtCQUErQixDQUFDLENBQUMsQ0FBQyxJQUFJLG9CQUFvQixHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUM1RSxDQUFDO0FBRUQsU0FBUywwQkFBMEIsQ0FBQyxvQkFBNEI7SUFDOUQsT0FBTyxHQUFHLG9CQUFvQixPQUFPLG9CQUFvQixLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUMvRSxDQUFDO0FBRUQsU0FBUyxvQkFBb0IsQ0FDM0IsVUFBa0IsRUFDbEIsT0FBZSxFQUNmLG9CQUE0QixFQUM1QiwrQkFBd0M7SUFFeEMsTUFBTSxZQUFZLEdBQUcsb0JBQW9CLENBQ3ZDLG9CQUFvQixFQUNwQiwrQkFBK0IsQ0FDaEMsQ0FBQztJQUNGLE1BQU0sUUFBUSxHQUFHLElBQUEsbUJBQVUsRUFBQyxNQUFNLENBQUM7U0FDaEMsTUFBTSxDQUFDLEdBQUcsVUFBVSxLQUFLLE9BQU8sS0FBSyxZQUFZLEVBQUUsQ0FBQztTQUNwRCxNQUFNLENBQUMsS0FBSyxDQUFDO1NBQ2IsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNoQixNQUFNLG1CQUFtQixHQUFHLHlCQUF5QixDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ2xFLE1BQU0sZ0JBQWdCLEdBQUcseUJBQXlCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDNUQsTUFBTSxZQUFZLEdBQUc7UUFDbkIsbUJBQW1CO1FBQ25CLGdCQUFnQjtRQUNoQixZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztLQUN0QjtTQUNFLE1BQU0sQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7U0FDM0MsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2IsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLEdBQUcsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFDbkQsTUFBTSxxQkFBcUIsR0FBRyxZQUFZO1NBQ3ZDLEtBQUssQ0FBQyxDQUFDLEVBQUUsaUJBQWlCLENBQUM7U0FDM0IsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN2QixNQUFNLFlBQVksR0FDaEIscUJBQXFCLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQztJQUN4RSxPQUFPLEdBQUcsWUFBWSxJQUFJLFFBQVEsRUFBRSxDQUFDO0FBQ3ZDLENBQUM7QUFFRCxTQUFTLGtCQUFrQixDQUN6QixPQUFlLEVBQ2Ysb0JBQTRCLEVBQzVCLCtCQUF3QztJQUV4QyxNQUFNLFlBQVksR0FBRyxvQkFBb0IsQ0FDdkMsb0JBQW9CLEVBQ3BCLCtCQUErQixDQUNoQyxDQUFDO0lBQ0YsTUFBTSxZQUFZLEdBQUcsSUFBQSxtQkFBVSxFQUFDLE1BQU0sQ0FBQztTQUNwQyxNQUFNLENBQUMsR0FBRyxPQUFPLEtBQUssWUFBWSxFQUFFLENBQUM7U0FDckMsTUFBTSxDQUFDLEtBQUssQ0FBQztTQUNiLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDaEIsTUFBTSxlQUFlLEdBQUcsR0FBRyx5QkFBeUIsQ0FBQyxPQUFPLENBQUMsR0FBRyxZQUFZLEVBQUU7U0FDM0UsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7U0FDWixPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZCLE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUNwRSxPQUFPLHFCQUFxQixNQUFNLEdBQUcsWUFBWSxFQUFFLENBQUM7QUFDdEQsQ0FBQztBQUVELFNBQVMsdUJBQXVCO0lBQzlCLE9BQU8sbUNBQW1DLENBQUM7QUFDN0MsQ0FBQztBQUVELFNBQVMseUJBQXlCLENBQUMsS0FBWTtJQUM3QyxPQUFPLHlCQUF5QixDQUFDLFlBQUssQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3ZFLENBQUM7QUFFRCxTQUFTLG1CQUFtQixDQUFDLEtBQWE7SUFDeEMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO0lBRTdCLElBQUkscUJBQXFCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDeEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxJQUFJLENBQUMsR0FBRyxPQUFPLGdCQUFnQixDQUFDLENBQUM7UUFDcEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUNwQyxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2pDLElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUMsRUFBRSxDQUFDO1FBQ25DLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRCxTQUFTLDBCQUEwQixDQUNqQyxVQUFrQyxFQUNsQyxVQUE2QjtJQUU3QixNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsZ0JBQWdCLElBQUkseUJBQXlCLENBQUM7SUFDeEUsTUFBTSwwQkFBMEIsR0FBRyw2QkFBNkIsQ0FDOUQsVUFBVSxDQUFDLG9CQUFvQixDQUNoQyxDQUFDO0lBQ0YsTUFBTSxTQUFTLEdBQThCLEVBQUUsQ0FBQztJQUNoRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDdkIsTUFBTSwrQkFBK0IsR0FBRywwQkFBMEIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBRTlFLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDMUIsU0FBUztRQUNYLENBQUM7UUFFRCxNQUFNLFNBQVMsR0FBRyxtQkFBbUIsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN2RCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU3QywwQkFBMEIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxvQkFBb0IsRUFBRSxFQUFFO1lBQzFELE1BQU0sUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQy9DLFFBQVEsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxHQUFHLG9CQUFvQixDQUFDLENBQUM7WUFFbEUsSUFBSSxRQUFRLENBQUMsT0FBTyxFQUFFLEdBQUcsR0FBRyxFQUFFLENBQUM7Z0JBQzdCLE9BQU87WUFDVCxDQUFDO1lBRUQsU0FBUyxDQUFDLElBQUksQ0FBQztnQkFDYixPQUFPO2dCQUNQLFNBQVM7Z0JBQ1QsUUFBUTtnQkFDUixvQkFBb0I7Z0JBQ3BCLCtCQUErQjthQUNoQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQsU0FBUyxlQUFlLENBQUMsS0FBVztJQUNsQyxPQUFPLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQzFDLENBQUM7QUFFRCxTQUFTLG1CQUFtQixDQUFDLEtBQWE7SUFDeEMsT0FBTyxLQUFLLENBQUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztBQUMxRCxDQUFDO0FBRUQsU0FBUyxvQkFBb0IsQ0FBQyxLQUFXO0lBQ3ZDLE9BQU8sTUFBTSxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDO0FBQ25ELENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFhLFVBQVcsU0FBUSxzQkFBUztJQWlCdkMsWUFBbUIsS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBc0I7UUFDckUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksMkJBQU0sQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFLEtBQTJCLENBQUMsQ0FBQztRQUV4RSw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQztRQUMvQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7UUFDekMsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQztRQUN2QyxJQUFJLENBQUMsS0FBSyxHQUFHLFlBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLEdBQUcsR0FBRztZQUNULE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU87WUFDM0IsTUFBTSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTTtTQUMxQixDQUFDO1FBRUYsSUFBSSxZQUFZLEdBQ2QsS0FBSyxDQUFDLGNBQWMsSUFBSSxRQUFRO1lBQzlCLENBQUMsQ0FBQyx1QkFBWSxDQUFDLFVBQVU7WUFDekIsQ0FBQyxDQUFDLHVCQUFZLENBQUMsTUFBTSxDQUFDO1FBQzFCLElBQUksS0FBSyxDQUFDLFNBQVMsS0FBSyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDekMsWUFBWSxHQUFHLHVCQUFZLENBQUMsYUFBYSxDQUFDO1FBQzVDLENBQUM7UUFDRCxJQUFJLEtBQUssQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3pDLFlBQVksR0FBRyx1QkFBWSxDQUFDLFVBQVUsQ0FBQztRQUN6QyxDQUFDO1FBRUQsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLHNCQUFzQixDQUFDO1FBRWhELElBQUksVUFBVSxFQUFFLE9BQU8sSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNqQyxNQUFNLGlCQUFpQixHQUFHLFVBQVcsQ0FBQztZQUV0QyxJQUFJLEtBQUssQ0FBQyxZQUFZLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3JDLE1BQU0sSUFBSSxLQUFLLENBQ2Isa0dBQWtHLENBQ25HLENBQUM7WUFDSixDQUFDO1lBQ0QsSUFBSSxLQUFLLENBQUMsU0FBUyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUNsQyxNQUFNLElBQUksS0FBSyxDQUNiLG1HQUFtRyxDQUNwRyxDQUFDO1lBQ0osQ0FBQztZQUVELE1BQU0sVUFBVSxHQUNkLEtBQUssQ0FBQyxjQUFjLEtBQUssTUFBTTtnQkFDL0IsS0FBSyxDQUFDLGNBQWMsS0FBSyxNQUFNO2dCQUMvQixLQUFLLENBQUMsY0FBYyxLQUFLLFFBQVE7Z0JBQy9CLENBQUMsQ0FBQyxLQUFLLENBQUMsY0FBYztnQkFDdEIsQ0FBQyxDQUFDLElBQUEsMENBQXlCLEVBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3BELElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUM3QixNQUFNLElBQUksS0FBSyxDQUNiLHlGQUF5RixDQUMxRixDQUFDO1lBQ0osQ0FBQztZQUVELE1BQU0sS0FBSyxHQUNULGlCQUFpQixDQUFDLGlCQUFpQjtnQkFDbkMsSUFBSSxlQUFLLENBQUMsSUFBSSxFQUFFLDZCQUE2QixDQUFDLENBQUM7WUFDakQsSUFBSSxDQUFDLDJCQUEyQixHQUFHLEtBQUssQ0FBQztZQUN6QyxJQUFJLGlCQUFpQixDQUFDLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDL0MsS0FBSyxDQUFDLGVBQWUsQ0FBQyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUN0RCxDQUFDO1lBRUQsTUFBTSxhQUFhLEdBQUcsSUFBSSxjQUFJLENBQUMsSUFBSSxFQUFFLHlCQUF5QixFQUFFO2dCQUM5RCxTQUFTLEVBQUUsSUFBSSwwQkFBZ0IsQ0FBQyx5QkFBeUIsQ0FBQztnQkFDMUQsV0FBVyxFQUNULDJFQUEyRTthQUM5RSxDQUFDLENBQUM7WUFDSCxLQUFLLENBQUMsWUFBWSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBRWxDLE1BQU0saUJBQWlCLEdBQUcseUJBQXlCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2hFLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUN4RCx1QkFBdUIsRUFBRSxDQUNNLENBQUM7WUFDbEMsTUFBTSxhQUFhLEdBQ2pCLHFCQUFxQjtnQkFDckIsSUFBSSxnQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLHVCQUF1QixFQUFFLEVBQUU7b0JBQzFELElBQUksRUFBRSxpQkFBaUI7aUJBQ3hCLENBQUMsQ0FBQztZQUVMLElBQUksQ0FBQyxzQkFBc0IsQ0FDekIsS0FBSyxDQUFDLFlBQVksRUFDbEIsVUFBVSxFQUNWLGlCQUFpQixFQUNqQixLQUFLLENBQUMsVUFBVSxJQUFJLFlBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQ3hDLEtBQUssRUFDTCxhQUFhLEVBQ2IsYUFBYSxFQUNiLGlCQUFpQixDQUNsQixDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxtQkFBUSxDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7WUFDekMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUztZQUM3QixZQUFZO1lBQ1osZ0JBQWdCLEVBQUUsR0FBRztZQUNyQixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsR0FBSSxLQUF5QjtTQUM5QixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sc0JBQXNCLENBQzVCLFlBQW9CLEVBQ3BCLFVBQWdDLEVBQ2hDLFVBQTZCLEVBQzdCLGtCQUEwQixFQUMxQixLQUFhLEVBQ2IsYUFBbUIsRUFDbkIsYUFBK0IsRUFDL0IsaUJBQXlCO1FBRXpCLE1BQU0sU0FBUyxHQUFHLDBCQUEwQixDQUMxQyxJQUFBLGlEQUFnQyxFQUFDLFlBQVksRUFBRSxHQUFHLEVBQUUsVUFBVSxDQUFDLEVBQy9ELFVBQVUsQ0FDWCxDQUFDO1FBRUYsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQzFCLE1BQU0sWUFBWSxHQUFHLG9CQUFvQixDQUN2QyxrQkFBa0IsRUFDbEIsS0FBSyxDQUFDLE9BQU8sRUFDYixLQUFLLENBQUMsb0JBQW9CLEVBQzFCLEtBQUssQ0FBQywrQkFBK0IsQ0FDdEMsQ0FBQztZQUNGLE1BQU0sT0FBTyxHQUFHLGVBQWUsS0FBSyxDQUFDLE9BQU8sUUFBUSxrQkFBa0IsZUFBZSxlQUFlLENBQ2xHLEtBQUssQ0FBQyxTQUFTLENBQ2hCLEdBQUcsQ0FBQztZQUNMLE1BQU0sUUFBUSxHQUFHLDBCQUEwQixDQUFDLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1lBQ3hFLE1BQU0sT0FBTyxHQUFHO2dCQUNkLHFDQUFxQztnQkFDckMsRUFBRTtnQkFDRixPQUFPO2dCQUNQLEVBQUU7Z0JBQ0YsVUFBVSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRTtnQkFDaEMsV0FBVyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRTtnQkFDOUIsWUFBWSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRTtnQkFDaEMsZ0JBQWdCLGtCQUFrQixFQUFFO2dCQUNwQyxlQUFlLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO2dCQUN0QyxhQUFhLEtBQUssQ0FBQyxPQUFPLEVBQUU7Z0JBQzVCLDJCQUEyQixRQUFRLEVBQUU7Z0JBQ3JDLG9CQUFvQixLQUFLLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxFQUFFO2FBQ3BELENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRWIsTUFBTSxRQUFRLEdBQUcsSUFBSSwyQkFBVyxDQUM5QixJQUFJLEVBQ0osa0JBQWtCLENBQ2hCLEtBQUssQ0FBQyxPQUFPLEVBQ2IsS0FBSyxDQUFDLG9CQUFvQixFQUMxQixLQUFLLENBQUMsK0JBQStCLENBQ3RDLEVBQ0Q7Z0JBQ0UsV0FBVyxFQUFFLG1CQUFtQixDQUM5QiwrQ0FBK0MsS0FBSyxDQUFDLE9BQU8sS0FBSyxRQUFRLHFCQUFxQixDQUMvRjtnQkFDRCxTQUFTLEVBQUUsaUJBQWlCO2dCQUM1QixJQUFJLEVBQUUsWUFBWTtnQkFDbEIsa0JBQWtCLEVBQUUsb0JBQW9CLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQztnQkFDeEQsa0JBQWtCLEVBQUU7b0JBQ2xCLElBQUksRUFBRSxLQUFLO2lCQUNaO2dCQUNELE1BQU0sRUFBRTtvQkFDTixHQUFHLEVBQUUsS0FBSyxDQUFDLFFBQVE7b0JBQ25CLE9BQU8sRUFBRSxhQUFhLENBQUMsT0FBTztvQkFDOUIsS0FBSyxFQUFFLE9BQU87aUJBQ2Y7YUFDRixDQUNGLENBQUM7WUFDRixRQUFRLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ3hDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVNLGdCQUFnQjtRQUNyQixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQzdCLENBQUM7SUFFTSxTQUFTLENBQUMsT0FBbUIsRUFBRSxhQUF3QjtRQUM1RCxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN2QiwyRkFBMkY7WUFDM0YsSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQzdCLElBQUksNkJBQW1CLENBQ3JCLGtCQUFrQixZQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sZ0JBQWdCLEVBQ3ZELE9BQU8sQ0FBQyxjQUFjLENBQ3ZCLENBQ0YsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBQ00sVUFBVSxDQUFDLFFBQW9CO1FBQ3BDLE1BQU0sSUFBSSxLQUFLLENBQ2IsMEVBQTBFLENBQzNFLENBQUM7SUFDSixDQUFDO0lBQ00sbUJBQW1CLENBQ3hCLEVBQVUsRUFDVixPQUFnQztRQUVoQyxNQUFNLElBQUksS0FBSyxDQUNiLCtCQUErQixFQUFFLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FDbkQsT0FBTyxDQUNSLHFEQUFxRCxDQUN2RCxDQUFDO0lBQ0osQ0FBQztJQUNNLG1CQUFtQixDQUN4QixTQUEwQjtRQUUxQixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUNNLHFCQUFxQjtRQUMxQixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUM3QyxDQUFDO0lBQ00sTUFBTSxDQUFDLE1BQStCO1FBQzNDLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUNNLHNCQUFzQixDQUFDLE9BQXFDO1FBQ2pFLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBQ00sa0JBQWtCLENBQUMsTUFBcUI7UUFDN0MsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFTSxtQkFBbUIsQ0FBQyxTQUFpQjtRQUMxQyxPQUFPLGtCQUFXLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDaEQsU0FBUztZQUNULFNBQVMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVM7U0FDL0IsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELElBQVcsV0FBVztRQUNwQixPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0QyxDQUFDOztBQXBQSCxnQ0FxUEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB7XG4gIEFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQsXG4gIEdyYW50LFxuICBJR3JhbnRhYmxlLFxuICBQb2xpY3lTdGF0ZW1lbnQsXG4gIFJvbGUsXG4gIFNlcnZpY2VQcmluY2lwYWwsXG59IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgSUtleSwgVmlhU2VydmljZVByaW5jaXBhbCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1rbXMnO1xuaW1wb3J0IHsgQ2ZuU2NoZWR1bGUsIENmblNjaGVkdWxlR3JvdXAgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc2NoZWR1bGVyJztcbmltcG9ydCB7XG4gIElTZWNyZXQsXG4gIElTZWNyZXRBdHRhY2htZW50VGFyZ2V0LFxuICBSZXBsaWNhUmVnaW9uLFxuICBSb3RhdGlvblNjaGVkdWxlLFxuICBSb3RhdGlvblNjaGVkdWxlT3B0aW9ucyxcbiAgU2VjcmV0LFxuICBTZWNyZXRQcm9wcyxcbiAgU2VjcmV0UmVmZXJlbmNlLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc2VjcmV0c21hbmFnZXInO1xuaW1wb3J0IHsgSVRvcGljLCBJVG9waWNTdWJzY3JpcHRpb24sIFRvcGljIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXNucyc7XG5pbXBvcnQge1xuICBOYW1lcyxcbiAgUmVtb3ZhbFBvbGljeSxcbiAgUmVzb3VyY2VFbnZpcm9ubWVudCxcbiAgU2VjcmV0c01hbmFnZXJTZWNyZXRPcHRpb25zLFxuICBTZWNyZXRWYWx1ZSxcbiAgU3RhY2ssXG59IGZyb20gJ2F3cy1jZGstbGliL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBSZXNvdXJjZVR5cGUsIFNvcHNTeW5jLCBTb3BzU3luY09wdGlvbnMgfSBmcm9tICcuL1NvcHNTeW5jJztcbmltcG9ydCB7XG4gIGZsYXR0ZW5TdHJ1Y3R1cmVkRmlsZVRvU3RyaW5nTWFwLFxuICBpbmZlclN0cnVjdHVyZWRGaWxlRm9ybWF0LFxuICBTdHJ1Y3R1cmVkRmlsZUZvcm1hdCxcbn0gZnJvbSAnLi9zdHJ1Y3R1cmVkRGF0YSc7XG5cbmV4cG9ydCBlbnVtIFJhd091dHB1dCB7XG4gIC8qKlxuICAgKiBQYXJzZSB0aGUgc2VjcmV0IGFzIGEgc3RyaW5nXG4gICAqL1xuICBTVFJJTkcgPSAnU1RSSU5HJyxcbiAgLyoqXG4gICAqIFBhcnNlIHRoZSBzZWNyZXQgYXMgYSBiaW5hcnlcbiAgICovXG4gIEJJTkFSWSA9ICdCSU5BUlknLFxufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGV4cGlyYXRpb24gbm90aWZpY2F0aW9ucyBvbiBzZWNyZXQga2V5cy5cbiAqIFdoZW4gZW5hYmxlZCwgQ0RLIHJlYWRzIHVuZW5jcnlwdGVkIGtleXMgZW5kaW5nIHdpdGggdGhlIGNvbmZpZ3VyZWQgc3VmZml4XG4gKiAoZS5nLiBgZ2l0bGFiX3Rva2VuX2V4cGlyYXRpb25gKSBmcm9tIHRoZSBsb2NhbCBgc29wc0ZpbGVQYXRoYCBhbmRcbiAqIHN5bnRoZXNpemVzIG9uZS10aW1lIEV2ZW50QnJpZGdlIFNjaGVkdWxlciBzY2hlZHVsZXMgdGhhdCBwdWJsaXNoIHRvIFNOU1xuICogYmVmb3JlIGVhY2ggZXhwaXJhdGlvbiBkYXRlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEV4cGlyYXRpb25PcHRpb25zIHtcbiAgLyoqXG4gICAqIEVuYWJsZSBleHBpcmF0aW9uIG5vdGlmaWNhdGlvbnMuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBlbmFibGVkPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQW4gZXhpc3RpbmcgU05TIHRvcGljIHRvIHB1Ymxpc2ggZXhwaXJhdGlvbiBub3RpZmljYXRpb25zIHRvLlxuICAgKiBJZiBub3QgcHJvdmlkZWQsIGEgbmV3IFNOUyB0b3BpYyB3aWxsIGJlIGNyZWF0ZWQgYXV0b21hdGljYWxseS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBIG5ldyBTTlMgdG9waWMgaXMgY3JlYXRlZFxuICAgKi9cbiAgcmVhZG9ubHkgbm90aWZpY2F0aW9uVG9waWM/OiBJVG9waWM7XG5cbiAgLyoqXG4gICAqIEEgc3Vic2NyaWJlciB0byBhdHRhY2ggdG8gdGhlIGV4cGlyYXRpb24gbm90aWZpY2F0aW9uIHRvcGljLlxuICAgKiBXb3JrcyBmb3IgYm90aCBhbiBhdXRvLWNyZWF0ZWQgdG9waWMgYW5kIGEgcHJvdmlkZWQgYG5vdGlmaWNhdGlvblRvcGljYC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBzdWJzY3JpYmVyIGlzIGFkZGVkXG4gICAqL1xuICByZWFkb25seSBzdWJzY3JpYmVyPzogSVRvcGljU3Vic2NyaXB0aW9uO1xuXG4gIC8qKlxuICAgKiBUaGUgc3VmZml4IHVzZWQgdG8gaWRlbnRpZnkgZXhwaXJhdGlvbiBkYXRlIGtleXMgaW4gdGhlIHNlY3JldC5cbiAgICogRm9yIGV4YW1wbGUsIGEgc3VmZml4IG9mIGBfZXhwaXJhdGlvbmAgd2lsbCBtYXRjaCBhbnkga2V5IGxpa2VcbiAgICogYGdpdGxhYl90b2tlbl9leHBpcmF0aW9uYCBhbmQgdHJlYXQgaXRzIHZhbHVlIGFzIHRoZSBleHBpcmF0aW9uIGRhdGVcbiAgICogZm9yIGBnaXRsYWJfdG9rZW5gLlxuICAgKlxuICAgKiBAZGVmYXVsdCAnX2V4cGlyYXRpb24nXG4gICAqL1xuICByZWFkb25seSBleHBpcmF0aW9uU3VmZml4Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBOdW1iZXIgb2YgZGF5cyBiZWZvcmUgdGhlIGV4cGlyYXRpb24gZGF0ZSB0byBzZW5kIHRoZSBTTlMgbm90aWZpY2F0aW9uLFxuICAgKiBvciBtdWx0aXBsZSByZW1pbmRlciBvZmZzZXRzIHRvIHN5bnRoZXNpemUgb25lIHNjaGVkdWxlIHBlciB2YWx1ZS5cbiAgICpcbiAgICogQGRlZmF1bHQgMTRcbiAgICovXG4gIHJlYWRvbmx5IGRheXNCZWZvcmVFeHBpcmF0aW9uPzogbnVtYmVyIHwgbnVtYmVyW107XG59XG5cbi8qKlxuICogVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvZiB0aGUgU29wc1NlY3JldFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNvcHNTZWNyZXRQcm9wcyBleHRlbmRzIFNvcHNTeW5jT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBTaG91bGQgdGhlIHNlY3JldCBwYXJzZWQgYW5kIHRyYW5zZm9ybWVkIHRvIGpzb24/XG4gICAqIEBkZWZhdWx0IC0gdW5kZWZpbmVkIC0gU1RSSU5HIGZvciBiaW5hcnkgc2VjcmV0cywgZWxzZSBubyByYXcgb3V0cHV0XG4gICAqL1xuICByZWFkb25seSByYXdPdXRwdXQ/OiBSYXdPdXRwdXQ7XG4gIC8qKlxuICAgKiBBbiBvcHRpb25hbCwgaHVtYW4tZnJpZW5kbHkgZGVzY3JpcHRpb24gb2YgdGhlIHNlY3JldC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBkZXNjcmlwdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGN1c3RvbWVyLW1hbmFnZWQgZW5jcnlwdGlvbiBrZXkgdG8gdXNlIGZvciBlbmNyeXB0aW5nIHRoZSBzZWNyZXQgdmFsdWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQSBkZWZhdWx0IEtNUyBrZXkgZm9yIHRoZSBhY2NvdW50IGFuZCByZWdpb24gaXMgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IGVuY3J5cHRpb25LZXk/OiBJS2V5O1xuICAvKipcbiAgICogQSBuYW1lIGZvciB0aGUgc2VjcmV0LiBOb3RlIHRoYXQgZGVsZXRpbmcgc2VjcmV0cyBmcm9tIFNlY3JldHNNYW5hZ2VyIGRvZXMgbm90IGhhcHBlbiBpbW1lZGlhdGVseSwgYnV0IGFmdGVyIGEgNyB0b1xuICAgKiAzMCBkYXlzIGJsYWNrb3V0IHBlcmlvZC4gRHVyaW5nIHRoYXQgcGVyaW9kLCBpdCBpcyBub3QgcG9zc2libGUgdG8gY3JlYXRlIGFub3RoZXIgc2VjcmV0IHRoYXQgc2hhcmVzIHRoZSBzYW1lIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQSBuYW1lIGlzIGdlbmVyYXRlZCBieSBDbG91ZEZvcm1hdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IHNlY3JldE5hbWU/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBQb2xpY3kgdG8gYXBwbHkgd2hlbiB0aGUgc2VjcmV0IGlzIHJlbW92ZWQgZnJvbSB0aGlzIHN0YWNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vdCBzZXQuXG4gICAqL1xuICByZWFkb25seSByZW1vdmFsUG9saWN5PzogUmVtb3ZhbFBvbGljeTtcbiAgLyoqXG4gICAqIEEgbGlzdCBvZiByZWdpb25zIHdoZXJlIHRvIHJlcGxpY2F0ZSB0aGlzIHNlY3JldC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBTZWNyZXQgaXMgbm90IHJlcGxpY2F0ZWRcbiAgICovXG4gIHJlYWRvbmx5IHJlcGxpY2FSZWdpb25zPzogUmVwbGljYVJlZ2lvbltdO1xuICAvKipcbiAgICogQ29uZmlndXJlIGV4cGlyYXRpb24gbm90aWZpY2F0aW9ucyBmb3Igc2VjcmV0IGtleXMuXG4gICAqIFdoZW4gYGVuYWJsZWQ6IHRydWVgLCBDREsgcmVhZHMgdW5lbmNyeXB0ZWQgZXhwaXJhdGlvbiBrZXlzIGZyb20gdGhlIGxvY2FsXG4gICAqIGBzb3BzRmlsZVBhdGhgIGFuZCBzeW50aGVzaXplcyBvbmUtdGltZSBFdmVudEJyaWRnZSBTY2hlZHVsZXIgc2NoZWR1bGVzXG4gICAqIHRoYXQgcHVibGlzaCB0byBTTlMgYmVmb3JlIGVhY2ggZXhwaXJhdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBFeHBpcmF0aW9uIG5vdGlmaWNhdGlvbnMgYXJlIGRpc2FibGVkXG4gICAqL1xuICByZWFkb25seSBleHBpcmF0aW9uTm90aWZpY2F0aW9uPzogRXhwaXJhdGlvbk9wdGlvbnM7XG59XG5cbmNvbnN0IERFRkFVTFRfRVhQSVJBVElPTl9TVUZGSVggPSAnX2V4cGlyYXRpb24nO1xuY29uc3QgREVGQVVMVF9EQVlTX0JFRk9SRV9FWFBJUkFUSU9OID0gMTQ7XG5cbmludGVyZmFjZSBFeHBpcmF0aW9uU2NoZWR1bGVFbnRyeSB7XG4gIHJlYWRvbmx5IGJhc2VLZXk6IHN0cmluZztcbiAgcmVhZG9ubHkgZXhwaXJlc0F0OiBEYXRlO1xuICByZWFkb25seSBub3RpZnlBdDogRGF0ZTtcbiAgcmVhZG9ubHkgZGF5c0JlZm9yZUV4cGlyYXRpb246IG51bWJlcjtcbiAgcmVhZG9ubHkgaW5jbHVkZVJlbWluZGVyT2Zmc2V0SW5JZGVudGl0eTogYm9vbGVhbjtcbn1cblxuZnVuY3Rpb24gc2FuaXRpemVTY2hlZHVsZUNvbXBvbmVudChuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gbmFtZS5yZXBsYWNlKC9bXmEtekEtWjAtOV8tXS9nLCAnLScpLnJlcGxhY2UoL14tK3wtKyQvZywgJycpO1xufVxuXG5mdW5jdGlvbiBub3JtYWxpemVEYXlzQmVmb3JlRXhwaXJhdGlvbihcbiAgZGF5c0JlZm9yZUV4cGlyYXRpb24/OiBudW1iZXIgfCBudW1iZXJbXSxcbik6IG51bWJlcltdIHtcbiAgY29uc3QgY29uZmlndXJlZERheXMgPSBBcnJheS5pc0FycmF5KGRheXNCZWZvcmVFeHBpcmF0aW9uKVxuICAgID8gZGF5c0JlZm9yZUV4cGlyYXRpb25cbiAgICA6IFtkYXlzQmVmb3JlRXhwaXJhdGlvbiA/PyBERUZBVUxUX0RBWVNfQkVGT1JFX0VYUElSQVRJT05dO1xuXG4gIGlmIChjb25maWd1cmVkRGF5cy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnZGF5c0JlZm9yZUV4cGlyYXRpb24gbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZSBub24tbmVnYXRpdmUgaW50ZWdlci4nLFxuICAgICk7XG4gIH1cblxuICBjb25zdCB1bmlxdWVEYXlzID0gQXJyYXkuZnJvbShuZXcgU2V0KGNvbmZpZ3VyZWREYXlzKSk7XG4gIHVuaXF1ZURheXMuZm9yRWFjaCgodmFsdWUpID0+IHtcbiAgICBpZiAoIU51bWJlci5pc0ludGVnZXIodmFsdWUpIHx8IHZhbHVlIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgZGF5c0JlZm9yZUV4cGlyYXRpb24gbXVzdCBjb250YWluIG9ubHkgbm9uLW5lZ2F0aXZlIGludGVnZXJzLCBnb3QgXCIke3ZhbHVlfVwiLmAsXG4gICAgICApO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHVuaXF1ZURheXMuc29ydCgobGVmdCwgcmlnaHQpID0+IGxlZnQgLSByaWdodCk7XG59XG5cbmZ1bmN0aW9uIHNjaGVkdWxlT2Zmc2V0U3VmZml4KFxuICBkYXlzQmVmb3JlRXhwaXJhdGlvbjogbnVtYmVyLFxuICBpbmNsdWRlUmVtaW5kZXJPZmZzZXRJbklkZW50aXR5OiBib29sZWFuLFxuKTogc3RyaW5nIHtcbiAgcmV0dXJuIGluY2x1ZGVSZW1pbmRlck9mZnNldEluSWRlbnRpdHkgPyBgLSR7ZGF5c0JlZm9yZUV4cGlyYXRpb259ZGAgOiAnJztcbn1cblxuZnVuY3Rpb24gZm9ybWF0RGF5c0JlZm9yZUV4cGlyYXRpb24oZGF5c0JlZm9yZUV4cGlyYXRpb246IG51bWJlcik6IHN0cmluZyB7XG4gIHJldHVybiBgJHtkYXlzQmVmb3JlRXhwaXJhdGlvbn0gZGF5JHtkYXlzQmVmb3JlRXhwaXJhdGlvbiA9PT0gMSA/ICcnIDogJ3MnfWA7XG59XG5cbmZ1bmN0aW9uIHNhbml0aXplU2NoZWR1bGVOYW1lKFxuICBzZWNyZXROYW1lOiBzdHJpbmcsXG4gIGtleU5hbWU6IHN0cmluZyxcbiAgZGF5c0JlZm9yZUV4cGlyYXRpb246IG51bWJlcixcbiAgaW5jbHVkZVJlbWluZGVyT2Zmc2V0SW5JZGVudGl0eTogYm9vbGVhbixcbik6IHN0cmluZyB7XG4gIGNvbnN0IG9mZnNldFN1ZmZpeCA9IHNjaGVkdWxlT2Zmc2V0U3VmZml4KFxuICAgIGRheXNCZWZvcmVFeHBpcmF0aW9uLFxuICAgIGluY2x1ZGVSZW1pbmRlck9mZnNldEluSWRlbnRpdHksXG4gICk7XG4gIGNvbnN0IG5hbWVIYXNoID0gY3JlYXRlSGFzaCgnc2hhMScpXG4gICAgLnVwZGF0ZShgJHtzZWNyZXROYW1lfVxcMCR7a2V5TmFtZX1cXDAke29mZnNldFN1ZmZpeH1gKVxuICAgIC5kaWdlc3QoJ2hleCcpXG4gICAgLnNsaWNlKDAsIDEwKTtcbiAgY29uc3Qgc2FuaXRpemVkU2VjcmV0TmFtZSA9IHNhbml0aXplU2NoZWR1bGVDb21wb25lbnQoc2VjcmV0TmFtZSk7XG4gIGNvbnN0IHNhbml0aXplZEtleU5hbWUgPSBzYW5pdGl6ZVNjaGVkdWxlQ29tcG9uZW50KGtleU5hbWUpO1xuICBjb25zdCByZWFkYWJsZU5hbWUgPSBbXG4gICAgc2FuaXRpemVkU2VjcmV0TmFtZSxcbiAgICBzYW5pdGl6ZWRLZXlOYW1lLFxuICAgIG9mZnNldFN1ZmZpeC5zbGljZSgxKSxcbiAgXVxuICAgIC5maWx0ZXIoKGNvbXBvbmVudCkgPT4gY29tcG9uZW50Lmxlbmd0aCA+IDApXG4gICAgLmpvaW4oJy0nKTtcbiAgY29uc3QgbWF4UmVhZGFibGVMZW5ndGggPSA2NCAtIG5hbWVIYXNoLmxlbmd0aCAtIDE7XG4gIGNvbnN0IHRydW5jYXRlZFJlYWRhYmxlTmFtZSA9IHJlYWRhYmxlTmFtZVxuICAgIC5zbGljZSgwLCBtYXhSZWFkYWJsZUxlbmd0aClcbiAgICAucmVwbGFjZSgvLSskL2csICcnKTtcbiAgY29uc3Qgc2NoZWR1bGVOYW1lID1cbiAgICB0cnVuY2F0ZWRSZWFkYWJsZU5hbWUubGVuZ3RoID4gMCA/IHRydW5jYXRlZFJlYWRhYmxlTmFtZSA6ICdzY2hlZHVsZSc7XG4gIHJldHVybiBgJHtzY2hlZHVsZU5hbWV9LSR7bmFtZUhhc2h9YDtcbn1cblxuZnVuY3Rpb24gc2NoZWR1bGVSZXNvdXJjZUlkKFxuICBrZXlOYW1lOiBzdHJpbmcsXG4gIGRheXNCZWZvcmVFeHBpcmF0aW9uOiBudW1iZXIsXG4gIGluY2x1ZGVSZW1pbmRlck9mZnNldEluSWRlbnRpdHk6IGJvb2xlYW4sXG4pOiBzdHJpbmcge1xuICBjb25zdCBvZmZzZXRTdWZmaXggPSBzY2hlZHVsZU9mZnNldFN1ZmZpeChcbiAgICBkYXlzQmVmb3JlRXhwaXJhdGlvbixcbiAgICBpbmNsdWRlUmVtaW5kZXJPZmZzZXRJbklkZW50aXR5LFxuICApO1xuICBjb25zdCByZXNvdXJjZUhhc2ggPSBjcmVhdGVIYXNoKCdzaGExJylcbiAgICAudXBkYXRlKGAke2tleU5hbWV9XFwwJHtvZmZzZXRTdWZmaXh9YClcbiAgICAuZGlnZXN0KCdoZXgnKVxuICAgIC5zbGljZSgwLCAxMCk7XG4gIGNvbnN0IHJlYWRhYmxlS2V5TmFtZSA9IGAke3Nhbml0aXplU2NoZWR1bGVDb21wb25lbnQoa2V5TmFtZSl9JHtvZmZzZXRTdWZmaXh9YFxuICAgIC5zbGljZSgwLCA0OClcbiAgICAucmVwbGFjZSgvLSskL2csICcnKTtcbiAgY29uc3Qgc3VmZml4ID0gcmVhZGFibGVLZXlOYW1lLmxlbmd0aCA+IDAgPyByZWFkYWJsZUtleU5hbWUgOiAnS2V5JztcbiAgcmV0dXJuIGBFeHBpcmF0aW9uU2NoZWR1bGUke3N1ZmZpeH0ke3Jlc291cmNlSGFzaH1gO1xufVxuXG5mdW5jdGlvbiBzY2hlZHVsZUdyb3VwUmVzb3VyY2VJZCgpOiBzdHJpbmcge1xuICByZXR1cm4gJ1NvcHNTZWNyZXRFeHBpcmF0aW9uU2NoZWR1bGVHcm91cCc7XG59XG5cbmZ1bmN0aW9uIHNjaGVkdWxlR3JvdXBOYW1lRm9yU3RhY2soc3RhY2s6IFN0YWNrKTogc3RyaW5nIHtcbiAgcmV0dXJuIHNhbml0aXplU2NoZWR1bGVDb21wb25lbnQoTmFtZXMudW5pcXVlSWQoc3RhY2spKS5zbGljZSgwLCA2NCk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlRXhwaXJhdGlvbkRhdGUodmFsdWU6IHN0cmluZyk6IERhdGUge1xuICBjb25zdCB0cmltbWVkID0gdmFsdWUudHJpbSgpO1xuXG4gIGlmICgvXlxcZHs0fS1cXGR7Mn0tXFxkezJ9JC8udGVzdCh0cmltbWVkKSkge1xuICAgIGNvbnN0IHBhcnNlZCA9IG5ldyBEYXRlKGAke3RyaW1tZWR9VDAwOjAwOjAwLjAwMFpgKTtcbiAgICBpZiAoIU51bWJlci5pc05hTihwYXJzZWQuZ2V0VGltZSgpKSkge1xuICAgICAgcmV0dXJuIHBhcnNlZDtcbiAgICB9XG4gIH1cblxuICBjb25zdCBwYXJzZWQgPSBuZXcgRGF0ZSh0cmltbWVkKTtcbiAgaWYgKE51bWJlci5pc05hTihwYXJzZWQuZ2V0VGltZSgpKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgdW5zdXBwb3J0ZWQgZGF0ZSBmb3JtYXQ6IFwiJHt2YWx1ZX1cImApO1xuICB9XG4gIHJldHVybiBwYXJzZWQ7XG59XG5cbmZ1bmN0aW9uIHJlc29sdmVFeHBpcmF0aW9uU2NoZWR1bGVzKFxuICBzb3VyY2VEYXRhOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICBleHBpcmF0aW9uOiBFeHBpcmF0aW9uT3B0aW9ucyxcbik6IEV4cGlyYXRpb25TY2hlZHVsZUVudHJ5W10ge1xuICBjb25zdCBzdWZmaXggPSBleHBpcmF0aW9uLmV4cGlyYXRpb25TdWZmaXggPz8gREVGQVVMVF9FWFBJUkFUSU9OX1NVRkZJWDtcbiAgY29uc3QgZGF5c0JlZm9yZUV4cGlyYXRpb25WYWx1ZXMgPSBub3JtYWxpemVEYXlzQmVmb3JlRXhwaXJhdGlvbihcbiAgICBleHBpcmF0aW9uLmRheXNCZWZvcmVFeHBpcmF0aW9uLFxuICApO1xuICBjb25zdCBzY2hlZHVsZXM6IEV4cGlyYXRpb25TY2hlZHVsZUVudHJ5W10gPSBbXTtcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgY29uc3QgaW5jbHVkZVJlbWluZGVyT2Zmc2V0SW5JZGVudGl0eSA9IGRheXNCZWZvcmVFeHBpcmF0aW9uVmFsdWVzLmxlbmd0aCA+IDE7XG5cbiAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMoc291cmNlRGF0YSkuc29ydCgpKSB7XG4gICAgaWYgKCFrZXkuZW5kc1dpdGgoc3VmZml4KSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgY29uc3QgZXhwaXJlc0F0ID0gcGFyc2VFeHBpcmF0aW9uRGF0ZShzb3VyY2VEYXRhW2tleV0pO1xuICAgIGNvbnN0IGJhc2VLZXkgPSBrZXkuc2xpY2UoMCwgLXN1ZmZpeC5sZW5ndGgpO1xuXG4gICAgZGF5c0JlZm9yZUV4cGlyYXRpb25WYWx1ZXMuZm9yRWFjaCgoZGF5c0JlZm9yZUV4cGlyYXRpb24pID0+IHtcbiAgICAgIGNvbnN0IG5vdGlmeUF0ID0gbmV3IERhdGUoZXhwaXJlc0F0LmdldFRpbWUoKSk7XG4gICAgICBub3RpZnlBdC5zZXRVVENEYXRlKG5vdGlmeUF0LmdldFVUQ0RhdGUoKSAtIGRheXNCZWZvcmVFeHBpcmF0aW9uKTtcblxuICAgICAgaWYgKG5vdGlmeUF0LmdldFRpbWUoKSA8IG5vdykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHNjaGVkdWxlcy5wdXNoKHtcbiAgICAgICAgYmFzZUtleSxcbiAgICAgICAgZXhwaXJlc0F0LFxuICAgICAgICBub3RpZnlBdCxcbiAgICAgICAgZGF5c0JlZm9yZUV4cGlyYXRpb24sXG4gICAgICAgIGluY2x1ZGVSZW1pbmRlck9mZnNldEluSWRlbnRpdHksXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBzY2hlZHVsZXM7XG59XG5cbmZ1bmN0aW9uIHRvSXNvRGF0ZVN0cmluZyh2YWx1ZTogRGF0ZSk6IHN0cmluZyB7XG4gIHJldHVybiB2YWx1ZS50b0lTT1N0cmluZygpLnNsaWNlKDAsIDEwKTtcbn1cblxuZnVuY3Rpb24gdHJ1bmNhdGVEZXNjcmlwdGlvbih2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHZhbHVlLmxlbmd0aCA+IDUxMiA/IHZhbHVlLnNsaWNlKDAsIDUxMikgOiB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gdG9TY2hlZHVsZUV4cHJlc3Npb24odmFsdWU6IERhdGUpOiBzdHJpbmcge1xuICByZXR1cm4gYGF0KCR7dmFsdWUudG9JU09TdHJpbmcoKS5zbGljZSgwLCAxOSl9KWA7XG59XG5cbi8qKlxuICogQSBkcm9wIGluIHJlcGxhY2VtZW50IGZvciB0aGUgbm9ybWFsIFNlY3JldCwgdGhhdCBpcyBwb3B1bGF0ZWQgd2l0aCB0aGUgZW5jcnlwdGVkXG4gKiBjb250ZW50IG9mIHRoZSBnaXZlbiBzb3BzIGZpbGUuXG4gKi9cbmV4cG9ydCBjbGFzcyBTb3BzU2VjcmV0IGV4dGVuZHMgQ29uc3RydWN0IGltcGxlbWVudHMgSVNlY3JldCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2VjcmV0OiBTZWNyZXQ7XG4gIHJlYWRvbmx5IGVuY3J5cHRpb25LZXk/OiBJS2V5IHwgdW5kZWZpbmVkO1xuICByZWFkb25seSBzZWNyZXRBcm46IHN0cmluZztcbiAgcmVhZG9ubHkgc2VjcmV0RnVsbEFybj86IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgcmVhZG9ubHkgc2VjcmV0TmFtZTogc3RyaW5nO1xuICByZWFkb25seSBzZWNyZXRSZWY6IFNlY3JldFJlZmVyZW5jZTtcbiAgcmVhZG9ubHkgc3RhY2s6IFN0YWNrO1xuICByZWFkb25seSBlbnY6IFJlc291cmNlRW52aXJvbm1lbnQ7XG5cbiAgLyoqXG4gICAqIFRoZSBTTlMgdG9waWMgdGhhdCByZWNlaXZlcyBleHBpcmF0aW9uIG5vdGlmaWNhdGlvbnMuXG4gICAqIE9ubHkgc2V0IHdoZW4gZXhwaXJhdGlvbiBub3RpZmljYXRpb25zIGFyZSBlbmFibGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgZXhwaXJhdGlvbk5vdGlmaWNhdGlvblRvcGljPzogSVRvcGljO1xuXG4gIHJlYWRvbmx5IHN5bmM6IFNvcHNTeW5jO1xuICBwdWJsaWMgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFNvcHNTZWNyZXRQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgdGhpcy5zZWNyZXQgPSBuZXcgU2VjcmV0KHRoaXMsICdSZXNvdXJjZScsIHByb3BzIHNhdGlzZmllcyBTZWNyZXRQcm9wcyk7XG5cbiAgICAvLyBGdWxsZmlsbCBzZWNyZXQgSW50ZXJmYWNlXG4gICAgdGhpcy5lbmNyeXB0aW9uS2V5ID0gdGhpcy5zZWNyZXQuZW5jcnlwdGlvbktleTtcbiAgICB0aGlzLnNlY3JldEFybiA9IHRoaXMuc2VjcmV0LnNlY3JldEFybjtcbiAgICB0aGlzLnNlY3JldE5hbWUgPSB0aGlzLnNlY3JldC5zZWNyZXROYW1lO1xuICAgIHRoaXMuc2VjcmV0UmVmID0gdGhpcy5zZWNyZXQuc2VjcmV0UmVmO1xuICAgIHRoaXMuc3RhY2sgPSBTdGFjay5vZihzY29wZSk7XG4gICAgdGhpcy5lbnYgPSB7XG4gICAgICBhY2NvdW50OiB0aGlzLnN0YWNrLmFjY291bnQsXG4gICAgICByZWdpb246IHRoaXMuc3RhY2sucmVnaW9uLFxuICAgIH07XG5cbiAgICBsZXQgcmVzb3VyY2VUeXBlID1cbiAgICAgIHByb3BzLnNvcHNGaWxlRm9ybWF0ID09ICdiaW5hcnknXG4gICAgICAgID8gUmVzb3VyY2VUeXBlLlNFQ1JFVF9SQVdcbiAgICAgICAgOiBSZXNvdXJjZVR5cGUuU0VDUkVUO1xuICAgIGlmIChwcm9wcy5yYXdPdXRwdXQgPT09IFJhd091dHB1dC5CSU5BUlkpIHtcbiAgICAgIHJlc291cmNlVHlwZSA9IFJlc291cmNlVHlwZS5TRUNSRVRfQklOQVJZO1xuICAgIH1cbiAgICBpZiAocHJvcHMucmF3T3V0cHV0ID09PSBSYXdPdXRwdXQuU1RSSU5HKSB7XG4gICAgICByZXNvdXJjZVR5cGUgPSBSZXNvdXJjZVR5cGUuU0VDUkVUX1JBVztcbiAgICB9XG5cbiAgICBjb25zdCBleHBpcmF0aW9uID0gcHJvcHMuZXhwaXJhdGlvbk5vdGlmaWNhdGlvbjtcblxuICAgIGlmIChleHBpcmF0aW9uPy5lbmFibGVkID8/IGZhbHNlKSB7XG4gICAgICBjb25zdCBlbmFibGVkRXhwaXJhdGlvbiA9IGV4cGlyYXRpb24hO1xuXG4gICAgICBpZiAocHJvcHMuc29wc0ZpbGVQYXRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICdFeHBpcmF0aW9uIHNjaGVkdWxpbmcgcmVxdWlyZXMgYSBsb2NhbCBzb3BzRmlsZVBhdGggYW5kIGRvZXMgbm90IHN1cHBvcnQgc29wc1MzQnVja2V0L3NvcHNTM0tleS4nLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKHByb3BzLnJhd091dHB1dCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAnRXhwaXJhdGlvbiBzY2hlZHVsaW5nIGRvZXMgbm90IHN1cHBvcnQgcmF3T3V0cHV0LiBSZW1vdmUgcmF3T3V0cHV0IHRvIHVzZSBleHBpcmF0aW9uTm90aWZpY2F0aW9uLicsXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZpbGVGb3JtYXQgPVxuICAgICAgICBwcm9wcy5zb3BzRmlsZUZvcm1hdCA9PT0gJ2pzb24nIHx8XG4gICAgICAgIHByb3BzLnNvcHNGaWxlRm9ybWF0ID09PSAneWFtbCcgfHxcbiAgICAgICAgcHJvcHMuc29wc0ZpbGVGb3JtYXQgPT09ICdkb3RlbnYnXG4gICAgICAgICAgPyBwcm9wcy5zb3BzRmlsZUZvcm1hdFxuICAgICAgICAgIDogaW5mZXJTdHJ1Y3R1cmVkRmlsZUZvcm1hdChwcm9wcy5zb3BzRmlsZVBhdGgpO1xuICAgICAgaWYgKGZpbGVGb3JtYXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ0V4cGlyYXRpb24gc2NoZWR1bGluZyByZXF1aXJlcyBhIHN0cnVjdHVyZWQgbG9jYWwgZmlsZSBpbiBqc29uLCB5YW1sLCBvciBkb3RlbnYgZm9ybWF0LicsXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRvcGljID1cbiAgICAgICAgZW5hYmxlZEV4cGlyYXRpb24ubm90aWZpY2F0aW9uVG9waWMgPz9cbiAgICAgICAgbmV3IFRvcGljKHRoaXMsICdFeHBpcmF0aW9uTm90aWZpY2F0aW9uVG9waWMnKTtcbiAgICAgIHRoaXMuZXhwaXJhdGlvbk5vdGlmaWNhdGlvblRvcGljID0gdG9waWM7XG4gICAgICBpZiAoZW5hYmxlZEV4cGlyYXRpb24uc3Vic2NyaWJlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRvcGljLmFkZFN1YnNjcmlwdGlvbihlbmFibGVkRXhwaXJhdGlvbi5zdWJzY3JpYmVyKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2NoZWR1bGVyUm9sZSA9IG5ldyBSb2xlKHRoaXMsICdFeHBpcmF0aW9uU2NoZWR1bGVyUm9sZScsIHtcbiAgICAgICAgYXNzdW1lZEJ5OiBuZXcgU2VydmljZVByaW5jaXBhbCgnc2NoZWR1bGVyLmFtYXpvbmF3cy5jb20nKSxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ1JvbGUgYXNzdW1lZCBieSBFdmVudEJyaWRnZSBTY2hlZHVsZXIgdG8gcHVibGlzaCBleHBpcmF0aW9uIG5vdGlmaWNhdGlvbnMnLFxuICAgICAgfSk7XG4gICAgICB0b3BpYy5ncmFudFB1Ymxpc2goc2NoZWR1bGVyUm9sZSk7XG5cbiAgICAgIGNvbnN0IHNjaGVkdWxlR3JvdXBOYW1lID0gc2NoZWR1bGVHcm91cE5hbWVGb3JTdGFjayh0aGlzLnN0YWNrKTtcbiAgICAgIGNvbnN0IGV4aXN0aW5nU2NoZWR1bGVHcm91cCA9IHRoaXMuc3RhY2subm9kZS50cnlGaW5kQ2hpbGQoXG4gICAgICAgIHNjaGVkdWxlR3JvdXBSZXNvdXJjZUlkKCksXG4gICAgICApIGFzIENmblNjaGVkdWxlR3JvdXAgfCB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBzY2hlZHVsZUdyb3VwID1cbiAgICAgICAgZXhpc3RpbmdTY2hlZHVsZUdyb3VwID8/XG4gICAgICAgIG5ldyBDZm5TY2hlZHVsZUdyb3VwKHRoaXMuc3RhY2ssIHNjaGVkdWxlR3JvdXBSZXNvdXJjZUlkKCksIHtcbiAgICAgICAgICBuYW1lOiBzY2hlZHVsZUdyb3VwTmFtZSxcbiAgICAgICAgfSk7XG5cbiAgICAgIHRoaXMuYWRkRXhwaXJhdGlvblNjaGVkdWxlcyhcbiAgICAgICAgcHJvcHMuc29wc0ZpbGVQYXRoLFxuICAgICAgICBmaWxlRm9ybWF0LFxuICAgICAgICBlbmFibGVkRXhwaXJhdGlvbixcbiAgICAgICAgcHJvcHMuc2VjcmV0TmFtZSA/PyBOYW1lcy51bmlxdWVJZCh0aGlzKSxcbiAgICAgICAgdG9waWMsXG4gICAgICAgIHNjaGVkdWxlclJvbGUsXG4gICAgICAgIHNjaGVkdWxlR3JvdXAsXG4gICAgICAgIHNjaGVkdWxlR3JvdXBOYW1lLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLnN5bmMgPSBuZXcgU29wc1N5bmModGhpcywgJ1NvcHNTeW5jJywge1xuICAgICAgdGFyZ2V0OiB0aGlzLnNlY3JldC5zZWNyZXRBcm4sXG4gICAgICByZXNvdXJjZVR5cGUsXG4gICAgICBmbGF0dGVuU2VwYXJhdG9yOiAnLicsXG4gICAgICBzZWNyZXQ6IHRoaXMuc2VjcmV0LFxuICAgICAgLi4uKHByb3BzIGFzIFNvcHNTeW5jT3B0aW9ucyksXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFkZEV4cGlyYXRpb25TY2hlZHVsZXMoXG4gICAgc29wc0ZpbGVQYXRoOiBzdHJpbmcsXG4gICAgZmlsZUZvcm1hdDogU3RydWN0dXJlZEZpbGVGb3JtYXQsXG4gICAgZXhwaXJhdGlvbjogRXhwaXJhdGlvbk9wdGlvbnMsXG4gICAgc2NoZWR1bGVTZWNyZXROYW1lOiBzdHJpbmcsXG4gICAgdG9waWM6IElUb3BpYyxcbiAgICBzY2hlZHVsZXJSb2xlOiBSb2xlLFxuICAgIHNjaGVkdWxlR3JvdXA6IENmblNjaGVkdWxlR3JvdXAsXG4gICAgc2NoZWR1bGVHcm91cE5hbWU6IHN0cmluZyxcbiAgKTogdm9pZCB7XG4gICAgY29uc3Qgc2NoZWR1bGVzID0gcmVzb2x2ZUV4cGlyYXRpb25TY2hlZHVsZXMoXG4gICAgICBmbGF0dGVuU3RydWN0dXJlZEZpbGVUb1N0cmluZ01hcChzb3BzRmlsZVBhdGgsICcuJywgZmlsZUZvcm1hdCksXG4gICAgICBleHBpcmF0aW9uLFxuICAgICk7XG5cbiAgICBzY2hlZHVsZXMuZm9yRWFjaCgoZW50cnkpID0+IHtcbiAgICAgIGNvbnN0IHNjaGVkdWxlTmFtZSA9IHNhbml0aXplU2NoZWR1bGVOYW1lKFxuICAgICAgICBzY2hlZHVsZVNlY3JldE5hbWUsXG4gICAgICAgIGVudHJ5LmJhc2VLZXksXG4gICAgICAgIGVudHJ5LmRheXNCZWZvcmVFeHBpcmF0aW9uLFxuICAgICAgICBlbnRyeS5pbmNsdWRlUmVtaW5kZXJPZmZzZXRJbklkZW50aXR5LFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHN1bW1hcnkgPSBgU2VjcmV0IGtleSBcIiR7ZW50cnkuYmFzZUtleX1cIiBpbiAke3NjaGVkdWxlU2VjcmV0TmFtZX0gZXhwaXJlcyBvbiAke3RvSXNvRGF0ZVN0cmluZyhcbiAgICAgICAgZW50cnkuZXhwaXJlc0F0LFxuICAgICAgKX0uYDtcbiAgICAgIGNvbnN0IGxlYWRUaW1lID0gZm9ybWF0RGF5c0JlZm9yZUV4cGlyYXRpb24oZW50cnkuZGF5c0JlZm9yZUV4cGlyYXRpb24pO1xuICAgICAgY29uc3QgbWVzc2FnZSA9IFtcbiAgICAgICAgJ1NPUFMgc2VjcmV0IGV4cGlyYXRpb24gbm90aWZpY2F0aW9uJyxcbiAgICAgICAgJycsXG4gICAgICAgIHN1bW1hcnksXG4gICAgICAgICcnLFxuICAgICAgICBgU3RhY2s6ICR7dGhpcy5zdGFjay5zdGFja05hbWV9YCxcbiAgICAgICAgYFJlZ2lvbjogJHt0aGlzLnN0YWNrLnJlZ2lvbn1gLFxuICAgICAgICBgQWNjb3VudDogJHt0aGlzLnN0YWNrLmFjY291bnR9YCxcbiAgICAgICAgYFNlY3JldCBuYW1lOiAke3NjaGVkdWxlU2VjcmV0TmFtZX1gLFxuICAgICAgICBgU2VjcmV0IEFSTjogJHt0aGlzLnNlY3JldC5zZWNyZXRBcm59YCxcbiAgICAgICAgYEtleSBuYW1lOiAke2VudHJ5LmJhc2VLZXl9YCxcbiAgICAgICAgYE5vdGlmaWNhdGlvbiBsZWFkIHRpbWU6ICR7bGVhZFRpbWV9YCxcbiAgICAgICAgYEV4cGlyYXRpb24gdGltZTogJHtlbnRyeS5leHBpcmVzQXQudG9JU09TdHJpbmcoKX1gLFxuICAgICAgXS5qb2luKCdcXG4nKTtcblxuICAgICAgY29uc3Qgc2NoZWR1bGUgPSBuZXcgQ2ZuU2NoZWR1bGUoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIHNjaGVkdWxlUmVzb3VyY2VJZChcbiAgICAgICAgICBlbnRyeS5iYXNlS2V5LFxuICAgICAgICAgIGVudHJ5LmRheXNCZWZvcmVFeHBpcmF0aW9uLFxuICAgICAgICAgIGVudHJ5LmluY2x1ZGVSZW1pbmRlck9mZnNldEluSWRlbnRpdHksXG4gICAgICAgICksXG4gICAgICAgIHtcbiAgICAgICAgICBkZXNjcmlwdGlvbjogdHJ1bmNhdGVEZXNjcmlwdGlvbihcbiAgICAgICAgICAgIGBOb3RpZnkgYWJvdXQgZXhwaXJhdGlvbiBvZiBTT1BTIHNlY3JldCBrZXkgXCIke2VudHJ5LmJhc2VLZXl9XCIgJHtsZWFkVGltZX0gYmVmb3JlIGV4cGlyYXRpb24uYCxcbiAgICAgICAgICApLFxuICAgICAgICAgIGdyb3VwTmFtZTogc2NoZWR1bGVHcm91cE5hbWUsXG4gICAgICAgICAgbmFtZTogc2NoZWR1bGVOYW1lLFxuICAgICAgICAgIHNjaGVkdWxlRXhwcmVzc2lvbjogdG9TY2hlZHVsZUV4cHJlc3Npb24oZW50cnkubm90aWZ5QXQpLFxuICAgICAgICAgIGZsZXhpYmxlVGltZVdpbmRvdzoge1xuICAgICAgICAgICAgbW9kZTogJ09GRicsXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0YXJnZXQ6IHtcbiAgICAgICAgICAgIGFybjogdG9waWMudG9waWNBcm4sXG4gICAgICAgICAgICByb2xlQXJuOiBzY2hlZHVsZXJSb2xlLnJvbGVBcm4sXG4gICAgICAgICAgICBpbnB1dDogbWVzc2FnZSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgKTtcbiAgICAgIHNjaGVkdWxlLmFkZERlcGVuZGVuY3koc2NoZWR1bGVHcm91cCk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgY3VycmVudFZlcnNpb25JZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnN5bmMudmVyc2lvbklkO1xuICB9XG5cbiAgcHVibGljIGdyYW50UmVhZChncmFudGVlOiBJR3JhbnRhYmxlLCB2ZXJzaW9uU3RhZ2VzPzogc3RyaW5nW10pOiBHcmFudCB7XG4gICAgaWYgKHRoaXMuZW5jcnlwdGlvbktleSkge1xuICAgICAgLy8gQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20va21zL2xhdGVzdC9kZXZlbG9wZXJndWlkZS9zZXJ2aWNlcy1zZWNyZXRzLW1hbmFnZXIuaHRtbFxuICAgICAgdGhpcy5lbmNyeXB0aW9uS2V5LmdyYW50RGVjcnlwdChcbiAgICAgICAgbmV3IFZpYVNlcnZpY2VQcmluY2lwYWwoXG4gICAgICAgICAgYHNlY3JldHNtYW5hZ2VyLiR7U3RhY2sub2YodGhpcykucmVnaW9ufS5hbWF6b25hd3MuY29tYCxcbiAgICAgICAgICBncmFudGVlLmdyYW50UHJpbmNpcGFsLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuc2VjcmV0LmdyYW50UmVhZChncmFudGVlLCB2ZXJzaW9uU3RhZ2VzKTtcbiAgfVxuICBwdWJsaWMgZ3JhbnRXcml0ZShfZ3JhbnRlZTogSUdyYW50YWJsZSk6IEdyYW50IHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgTWV0aG9kIGdyYW50V3JpdGUoLi4uKSBub3QgYWxsb3dlZCBhcyB0aGlzIHNlY3JldCBpcyBtYW5hZ2VkIGJ5IFNvcHNTeW5jYC