UNPKG

@aws-cdk/aws-kinesisanalytics-flink-alpha

Version:

A CDK Construct Library for Kinesis Analytics Flink applications

692 lines 86.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.Application = void 0; const jsiiDeprecationWarnings = require("../.warnings.jsii.js"); const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const cloudwatch = __importStar(require("aws-cdk-lib/aws-cloudwatch")); const ec2 = __importStar(require("aws-cdk-lib/aws-ec2")); const iam = __importStar(require("aws-cdk-lib/aws-iam")); const aws_kinesisanalytics_1 = require("aws-cdk-lib/aws-kinesisanalytics"); const logs = __importStar(require("aws-cdk-lib/aws-logs")); const core = __importStar(require("aws-cdk-lib/core")); const helpers_internal_1 = require("aws-cdk-lib/core/lib/helpers-internal"); const metadata_resource_1 = require("aws-cdk-lib/core/lib/metadata-resource"); const prop_injectable_1 = require("aws-cdk-lib/core/lib/prop-injectable"); const environment_properties_1 = require("./private/environment-properties"); const flink_application_configuration_1 = require("./private/flink-application-configuration"); const validation_1 = require("./private/validation"); /** * Implements the functionality shared between CDK created and imported * IApplications. */ class ApplicationBase extends core.Resource { /** * The underlying connections object for the connections getter. * * @internal */ _connections; /** Implement the convenience `IApplication.addToPrincipalPolicy` method. */ addToRolePolicy(policyStatement) { if (this.role) { this.role.addToPrincipalPolicy(policyStatement); return true; } return false; } get connections() { if (!this._connections) { throw new Error('This Application isn\'t associated with a VPC. Provide a "vpc" prop when creating the Application or "securityGroups" when importing it.'); } return this._connections; } /** * Return a CloudWatch metric associated with this Flink application. * * @param metricName The name of the metric * @param props Customization properties */ metric(metricName, props) { return new cloudwatch.Metric({ namespace: 'AWS/KinesisAnalytics', metricName, dimensionsMap: { Application: this.applicationName }, ...props, }).attachTo(this); } /** * The number of Kinesis Processing Units that are used to run your stream * processing application. The average number of KPUs used each hour * determines the billing for your application. * * Units: Count * * Reporting Level: Application * * @default - average over 5 minutes */ metricKpus(props) { return this.metric('KPUs', { statistic: 'Average', ...props }); } /** * The time elapsed during an outage for failing/recovering jobs. * * Units: Milliseconds * * Reporting Level: Application * * @default - average over 5 minutes */ metricDowntime(props) { return this.metric('downtime', { statistic: 'Average', ...props }); } /** * The time that the job has been running without interruption. * * Units: Milliseconds * * Reporting Level: Application * * @default - average over 5 minutes */ metricUptime(props) { return this.metric('uptime', { statistic: 'Average', ...props }); } /** * The total number of times this job has fully restarted since it was * submitted. This metric does not measure fine-grained restarts. * * Units: Count * * Reporting Level: Application * * @default - sum over 5 minutes */ metricFullRestarts(props) { return this.metric('fullRestarts', { statistic: 'Sum', ...props }); } /** * The number of times checkpointing has failed. * * Units: Count * * Reporting Level: Application * * @default - sum over 5 minutes */ metricNumberOfFailedCheckpoints(props) { return this.metric('numberOfFailedCheckpoints', { statistic: 'Sum', ...props }); } /** * The time it took to complete the last checkpoint. * * Units: Milliseconds * * Reporting Level: Application * * @default - maximum over 5 minutes */ metricLastCheckpointDuration(props) { return this.metric('lastCheckpointDuration', { statistic: 'Maximum', ...props }); } /** * The total size of the last checkpoint. * * Units: Bytes * * Reporting Level: Application * * @default - maximum over 5 minutes */ metricLastCheckpointSize(props) { return this.metric('lastCheckpointSize', { statistic: 'Maximum', ...props }); } /** * The overall percentage of CPU utilization across task managers. For * example, if there are five task managers, Kinesis Data Analytics publishes * five samples of this metric per reporting interval. * * Units: Percentage * * Reporting Level: Application * * @default - average over 5 minutes */ metricCpuUtilization(props) { return this.metric('cpuUtilization', { statistic: 'Average', ...props }); } /** * Overall heap memory utilization across task managers. For example, if there * are five task managers, Kinesis Data Analytics publishes five samples of * this metric per reporting interval. * * Units: Percentage * * Reporting Level: Application * * @default - average over 5 minutes */ metricHeapMemoryUtilization(props) { return this.metric('heapMemoryUtilization', { statistic: 'Average', ...props }); } /** * The total time spent performing old garbage collection operations. * * Units: Milliseconds * * Reporting Level: Application * * @default - sum over 5 minutes */ metricOldGenerationGCTime(props) { return this.metric('oldGenerationGCTime', { statistic: 'Sum', ...props }); } /** * The total number of old garbage collection operations that have occurred * across all task managers. * * Units: Count * * Reporting Level: Application * * @default - sum over 5 minutes */ metricOldGenerationGCCount(props) { return this.metric('oldGenerationGCCount', { statistic: 'Sum', ...props }); } /** * The total number of live threads used by the application. * * Units: Count * * Reporting Level: Application * * @default - average over 5 minutes */ metricThreadsCount(props) { return this.metric('threadsCount', { statistic: 'Average', ...props }); } /** * The total number of records this application, operator, or task has * received. * * Units: Count * * Reporting Level: Application, Operator, Task, Parallelism * * @default - average over 5 minutes */ metricNumRecordsIn(props) { return this.metric('numRecordsIn', { statistic: 'Average', ...props }); } /** * The total number of records this application, operator or task has received * per second. * * Units: Count/Second * * Reporting Level: Application, Operator, Task, Parallelism * * @default - average over 5 minutes */ metricNumRecordsInPerSecond(props) { return this.metric('numRecordsInPerSecond', { statistic: 'Average', ...props }); } /** * The total number of records this application, operator or task has emitted. * * Units: Count * * Reporting Level: Application, Operator, Task, Parallelism * * @default - average over 5 minutes */ metricNumRecordsOut(props) { return this.metric('numRecordsOut', { statistic: 'Average', ...props }); } /** * The total number of records this application, operator or task has emitted * per second. * * Units: Count/Second * * Reporting Level: Application, Operator, Task, Parallelism * * @default - average over 5 minutes */ metricNumRecordsOutPerSecond(props) { return this.metric('numRecordsOutPerSecond', { statistic: 'Average', ...props }); } /** * The number of records this operator or task has dropped due to arriving * late. * * Units: Count * * Reporting Level: Application, Operator, Task, Parallelism * * @default - sum over 5 minutes */ metricNumLateRecordsDropped(props) { return this.metric('numLateRecordsDropped', { statistic: 'Sum', ...props }); } /** * The last watermark this application/operator/task/thread has received. * * Units: Milliseconds * * Reporting Level: Application, Operator, Task, Parallelism * * @default - maximum over 5 minutes */ metricCurrentInputWatermark(props) { return this.metric('currentInputWatermark', { statistic: 'Maximum', ...props }); } /** * The last watermark this application/operator/task/thread has received. * * Units: Milliseconds * * Reporting Level: Application, Operator, Task, Parallelism * * @default - maximum over 5 minutes */ metricCurrentOutputWatermark(props) { return this.metric('currentOutputWatermark', { statistic: 'Maximum', ...props }); } /** * The amount of managed memory currently used. * * Units: Bytes * * Reporting Level: Application, Operator, Task, Parallelism * * @default - average over 5 minutes */ metricManagedMemoryUsed(props) { return this.metric('managedMemoryUsed', { statistic: 'Average', ...props }); } /** * The total amount of managed memory. * * Units: Bytes * * Reporting Level: Application, Operator, Task, Parallelism * * @default - average over 5 minutes */ metricManagedMemoryTotal(props) { return this.metric('managedMemoryTotal', { statistic: 'Average', ...props }); } /** * Derived from managedMemoryUsed/managedMemoryTotal. * * Units: Percentage * * Reporting Level: Application, Operator, Task, Parallelism * * @default - average over 5 minutes */ metricManagedMemoryUtilization(props) { return this.metric('managedMemoryUtilization', { statistic: 'Average', ...props }); } /** * The time (in milliseconds) this task or operator is idle (has no data to * process) per second. Idle time excludes back pressured time, so if the task * is back pressured it is not idle. * * Units: Milliseconds * * Reporting Level: Operator, Task, Parallelism * * @default - average over 5 minutes */ metricIdleTimeMsPerSecond(props) { return this.metric('idleTimeMsPerSecond', { statistic: 'Average', ...props }); } /** * The time (in milliseconds) this task or operator is back pressured per * second. * * Units: Milliseconds * * Reporting Level: Operator, Task, Parallelism * * @default - average over 5 minutes */ metricBackPressuredTimeMsPerSecond(props) { return this.metric('backPressuredTimeMsPerSecond', { statistic: 'Average', ...props }); } /** * The time (in milliseconds) this task or operator is busy (neither idle nor * back pressured) per second. Can be NaN, if the value could not be * calculated. * * Units: Milliseconds * * Reporting Level: Operator, Task, Parallelism * * @default - average over 5 minutes */ metricBusyTimePerMsPerSecond(props) { return this.metric('busyTimePerMsPerSecond', { statistic: 'Average', ...props }); } } /** * An imported Flink application. */ let Import = (() => { let _classDecorators = [prop_injectable_1.propertyInjectable]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; let _classSuper = ApplicationBase; var Import = class extends _classSuper { static { _classThis = this; } static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); Import = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); } /** Uniquely identifies this class. */ static PROPERTY_INJECTION_ID = '@aws-cdk.aws-kinesisanalytics-flink-alpha.Import'; grantPrincipal; role; applicationName; applicationArn; constructor(scope, id, attrs) { super(scope, id); // Enhanced CDK Analytics Telemetry (0, metadata_resource_1.addConstructMetadata)(this, attrs); // Imported applications have no associated role or grantPrincipal this.grantPrincipal = new iam.UnknownPrincipal({ resource: this }); this.role = undefined; this.applicationArn = attrs.applicationArn; const applicationName = core.Stack.of(scope).splitArn(attrs.applicationArn, core.ArnFormat.SLASH_RESOURCE_NAME).resourceName; if (!applicationName) { throw new Error(`applicationArn for fromApplicationArn (${attrs.applicationArn}) must include resource name`); } this.applicationName = applicationName; const securityGroups = attrs.securityGroups ?? []; if (securityGroups.length > 0) { this._connections = new ec2.Connections({ securityGroups }); } } static { __runInitializers(_classThis, _classExtraInitializers); } }; return Import = _classThis; })(); /** * The L2 construct for Flink Kinesis Data Applications. * * @resource AWS::KinesisAnalyticsV2::Application * */ let Application = (() => { let _classDecorators = [prop_injectable_1.propertyInjectable]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; let _classSuper = ApplicationBase; let _instanceExtraInitializers = []; let _get_applicationName_decorators; let _get_applicationArn_decorators; var Application = class extends _classSuper { static { _classThis = this; } static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0; _get_applicationName_decorators = [helpers_internal_1.memoizedGetter]; _get_applicationArn_decorators = [helpers_internal_1.memoizedGetter]; __esDecorate(this, null, _get_applicationName_decorators, { kind: "getter", name: "applicationName", static: false, private: false, access: { has: obj => "applicationName" in obj, get: obj => obj.applicationName }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(this, null, _get_applicationArn_decorators, { kind: "getter", name: "applicationArn", static: false, private: false, access: { has: obj => "applicationArn" in obj, get: obj => obj.applicationArn }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); Application = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); } static [JSII_RTTI_SYMBOL_1] = { fqn: "@aws-cdk/aws-kinesisanalytics-flink-alpha.Application", version: "2.261.0-alpha.0" }; /** Uniquely identifies this class. */ static PROPERTY_INJECTION_ID = '@aws-cdk.aws-kinesisanalytics-flink-alpha.Application'; /** * Import an existing Flink application defined outside of CDK code by * applicationName. */ static fromApplicationName(scope, id, applicationName) { const applicationArn = core.Stack.of(scope).formatArn(applicationArnComponents(applicationName)); return new Import(scope, id, { applicationArn }); } /** * Import an existing application defined outside of CDK code by * applicationArn. */ static fromApplicationArn(scope, id, applicationArn) { return new Import(scope, id, { applicationArn }); } /** * Import an existing application defined outside of CDK code. */ static fromApplicationAttributes(scope, id, attrs) { try { jsiiDeprecationWarnings._aws_cdk_aws_kinesisanalytics_flink_alpha_ApplicationAttributes(attrs); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.fromApplicationAttributes); } throw error; } return new Import(scope, id, { applicationArn: attrs.applicationArn, securityGroups: attrs.securityGroups, }); } // Role must be optional for JSII compatibility role = __runInitializers(this, _instanceExtraInitializers); grantPrincipal; resource; constructor(scope, id, props) { super(scope, id, { physicalName: props.applicationName }); try { jsiiDeprecationWarnings._aws_cdk_aws_kinesisanalytics_flink_alpha_ApplicationProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, Application); } throw error; } // Enhanced CDK Analytics Telemetry (0, metadata_resource_1.addConstructMetadata)(this, props); (0, validation_1.validateFlinkApplicationProps)(props); this.role = props.role ?? new iam.Role(this, 'Role', { assumedBy: new iam.ServicePrincipal('kinesisanalytics.amazonaws.com'), }); this.grantPrincipal = this.role; // Permit metric publishing to CloudWatch this.role.addToPrincipalPolicy(new iam.PolicyStatement({ actions: ['cloudwatch:PutMetricData'], resources: ['*'], })); const code = props.code.bind(this); code.bucket.grantRead(this); let vpcConfigurations; if (props.vpc) { const securityGroups = props.securityGroups ?? [ new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc, }), ]; this._connections = new ec2.Connections({ securityGroups }); const subnetSelection = props.vpcSubnets ?? { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, }; vpcConfigurations = [{ securityGroupIds: securityGroups.map(sg => sg.securityGroupId), subnetIds: props.vpc.selectSubnets(subnetSelection).subnetIds, }]; } const resource = new aws_kinesisanalytics_1.CfnApplicationV2(this, 'Resource', { applicationName: props.applicationName, runtimeEnvironment: props.runtime.value, serviceExecutionRole: this.role.roleArn, applicationConfiguration: { ...code.applicationCodeConfigurationProperty, environmentProperties: (0, environment_properties_1.environmentProperties)(props.propertyGroups), flinkApplicationConfiguration: (0, flink_application_configuration_1.flinkApplicationConfiguration)({ checkpointingEnabled: props.checkpointingEnabled, checkpointInterval: props.checkpointInterval, minPauseBetweenCheckpoints: props.minPauseBetweenCheckpoints, logLevel: props.logLevel, metricsLevel: props.metricsLevel, autoScalingEnabled: props.autoScalingEnabled, parallelism: props.parallelism, parallelismPerKpu: props.parallelismPerKpu, }), applicationSnapshotConfiguration: { snapshotsEnabled: props.snapshotsEnabled ?? true, }, vpcConfigurations, }, }); resource.node.addDependency(this.role); this.resource = resource; const logGroup = props.logGroup ?? new logs.LogGroup(this, 'LogGroup'); const logStream = new logs.LogStream(this, 'LogStream', { logGroup }); /* Permit logging */ this.role.addToPrincipalPolicy(new iam.PolicyStatement({ actions: ['logs:DescribeLogGroups'], resources: [ core.Stack.of(this).formatArn({ service: 'logs', resource: 'log-group', arnFormat: core.ArnFormat.COLON_RESOURCE_NAME, resourceName: '*', }), ], })); this.role.addToPrincipalPolicy(new iam.PolicyStatement({ actions: ['logs:DescribeLogStreams'], resources: [logGroup.logGroupArn], })); const logStreamArn = `arn:${core.Aws.PARTITION}:logs:${core.Aws.REGION}:${core.Aws.ACCOUNT_ID}:log-group:${logGroup.logGroupName}:log-stream:${logStream.logStreamName}`; this.role.addToPrincipalPolicy(new iam.PolicyStatement({ actions: ['logs:PutLogEvents'], resources: [logStreamArn], })); new aws_kinesisanalytics_1.CfnApplicationCloudWatchLoggingOptionV2(this, 'LoggingOption', { applicationName: this.resource.ref, cloudWatchLoggingOption: { logStreamArn, }, }); // Permissions required for VPC usage per: // https://docs.aws.amazon.com/kinesisanalytics/latest/java/vpc-permissions.html if (props.vpc) { this.role.addToPrincipalPolicy(new iam.PolicyStatement({ actions: [ 'ec2:DescribeVpcs', 'ec2:DescribeSubnets', 'ec2:DescribeSecurityGroups', 'ec2:DescribeDhcpOptions', 'ec2:CreateNetworkInterface', 'ec2:CreateNetworkInterfacePermission', 'ec2:DescribeNetworkInterfaces', 'ec2:DeleteNetworkInterface', ], resources: ['*'], })); } this.resource.applyRemovalPolicy(props.removalPolicy, { default: core.RemovalPolicy.DESTROY, }); } get applicationName() { return this.getResourceNameAttribute(this.resource.ref); } get applicationArn() { return this.getResourceArnAttribute(core.Stack.of(this).formatArn(applicationArnComponents(this.resource.ref)), applicationArnComponents(this.physicalName)); } static { __runInitializers(_classThis, _classExtraInitializers); } }; return Application = _classThis; })(); exports.Application = Application; function applicationArnComponents(resourceName) { return { service: 'kinesisanalytics', resource: 'application', resourceName, }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJhcHBsaWNhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1RUFBeUQ7QUFDekQseURBQTJDO0FBQzNDLHlEQUEyQztBQUMzQywyRUFBNkc7QUFDN0csMkRBQTZDO0FBQzdDLHVEQUF5QztBQUN6Qyw0RUFBdUU7QUFDdkUsOEVBQThFO0FBQzlFLDBFQUEwRTtBQUcxRSw2RUFBeUU7QUFDekUsK0ZBQTBGO0FBQzFGLHFEQUFpRztBQTRVakc7OztHQUdHO0FBQ0gsTUFBZSxlQUFnQixTQUFRLElBQUksQ0FBQyxRQUFRO0lBUWxEOzs7O09BSUc7SUFDTyxZQUFZLENBQW1CO0lBRXpDLDRFQUE0RTtJQUNyRSxlQUFlLENBQUMsZUFBb0M7UUFDekQsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDZCxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ2hELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sS0FBSyxDQUFDO0tBQ2Q7SUFFRCxJQUFXLFdBQVc7UUFDcEIsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLDBJQUEwSSxDQUFDLENBQUM7UUFDOUosQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQztLQUMxQjtJQUVEOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLFVBQWtCLEVBQUUsS0FBZ0M7UUFDekQsT0FBTyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUM7WUFDM0IsU0FBUyxFQUFFLHNCQUFzQjtZQUNqQyxVQUFVO1lBQ1YsYUFBYSxFQUFFLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxlQUFlLEVB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Q04sQ0FBQztZQUVELElBQUksQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsS0FBSyxDQUFDLGFBQWEsRUFBRTtnQkFDcEQsT0FBTyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTzthQUNwQyxDQUFDLENBQUM7U0FDSjtRQUdELElBQVcsZUFBZTtZQUN4QixPQUFPLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3pEO1FBR0QsSUFBVyxjQUFjO1lBQ3ZCLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixDQUNqQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUMsd0JBQXdCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUMxRSx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQzVDLENBQUM7U0FDSDs7WUEzS1UsdURBQVc7Ozs7O0FBQVgsa0NBQVc7QUE4S3hCLFNBQVMsd0JBQXdCLENBQUMsWUFBb0I7SUFDcEQsT0FBTztRQUNMLE9BQU8sRUFBRSxrQkFBa0I7UUFDM0IsUUFBUSxFQUFFLGFBQWE7UUFDdkIsWUFBWTtLQUNiLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY2xvdWR3YXRjaCBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2xvdWR3YXRjaCc7XG5pbXBvcnQgKiBhcyBlYzIgZnJvbSAnYXdzLWNkay1saWIvYXdzLWVjMic7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgeyBDZm5BcHBsaWNhdGlvbkNsb3VkV2F0Y2hMb2dnaW5nT3B0aW9uVjIsIENmbkFwcGxpY2F0aW9uVjIgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mta2luZXNpc2FuYWx5dGljcyc7XG5pbXBvcnQgKiBhcyBsb2dzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbmltcG9ydCAqIGFzIGNvcmUgZnJvbSAnYXdzLWNkay1saWIvY29yZSc7XG5pbXBvcnQgeyBtZW1vaXplZEdldHRlciB9IGZyb20gJ2F3cy1jZGstbGliL2NvcmUvbGliL2hlbHBlcnMtaW50ZXJuYWwnO1xuaW1wb3J0IHsgYWRkQ29uc3RydWN0TWV0YWRhdGEgfSBmcm9tICdhd3MtY2RrLWxpYi9jb3JlL2xpYi9tZXRhZGF0YS1yZXNvdXJjZSc7XG5pbXBvcnQgeyBwcm9wZXJ0eUluamVjdGFibGUgfSBmcm9tICdhd3MtY2RrLWxpYi9jb3JlL2xpYi9wcm9wLWluamVjdGFibGUnO1xuaW1wb3J0IHR5cGUgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB0eXBlIHsgQXBwbGljYXRpb25Db2RlIH0gZnJvbSAnLi9hcHBsaWNhdGlvbi1jb2RlJztcbmltcG9ydCB7IGVudmlyb25tZW50UHJvcGVydGllcyB9IGZyb20gJy4vcHJpdmF0ZS9lbnZpcm9ubWVudC1wcm9wZXJ0aWVzJztcbmltcG9ydCB7IGZsaW5rQXBwbGljYXRpb25Db25maWd1cmF0aW9uIH0gZnJvbSAnLi9wcml2YXRlL2ZsaW5rLWFwcGxpY2F0aW9uLWNvbmZpZ3VyYXRpb24nO1xuaW1wb3J0IHsgdmFsaWRhdGVGbGlua0FwcGxpY2F0aW9uUHJvcHMgYXMgdmFsaWRhdGVBcHBsaWNhdGlvblByb3BzIH0gZnJvbSAnLi9wcml2YXRlL3ZhbGlkYXRpb24nO1xuaW1wb3J0IHR5cGUgeyBMb2dMZXZlbCwgTWV0cmljc0xldmVsLCBSdW50aW1lIH0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogQW4gaW50ZXJmYWNlIGV4cHJlc3NpbmcgdGhlIHB1YmxpYyBwcm9wZXJ0aWVzIG9uIGJvdGggYW4gaW1wb3J0ZWQgYW5kXG4gKiBDREstY3JlYXRlZCBGbGluayBhcHBsaWNhdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJQXBwbGljYXRpb24gZXh0ZW5kcyBjb3JlLklSZXNvdXJjZSwgZWMyLklDb25uZWN0YWJsZSwgaWFtLklHcmFudGFibGUge1xuICAvKipcbiAgICogVGhlIGFwcGxpY2F0aW9uIEFSTi5cbiAgICpcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcmVhZG9ubHkgYXBwbGljYXRpb25Bcm46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIEZsaW5rIGFwcGxpY2F0aW9uLlxuICAgKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSBhcHBsaWNhdGlvbk5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGFwcGxpY2F0aW9uIElBTSByb2xlLlxuICAgKi9cbiAgcmVhZG9ubHkgcm9sZT86IGlhbS5JUm9sZTtcblxuICAvKipcbiAgICogQ29udmVuaWVuY2UgbWV0aG9kIGZvciBhZGRpbmcgYSBwb2xpY3kgc3RhdGVtZW50IHRvIHRoZSBhcHBsaWNhdGlvbiByb2xlLlxuICAgKi9cbiAgYWRkVG9Sb2xlUG9saWN5KHBvbGljeVN0YXRlbWVudDogaWFtLlBvbGljeVN0YXRlbWVudCk6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIENsb3VkV2F0Y2ggbWV0cmljIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEZsaW5rIGFwcGxpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0cmljTmFtZSBUaGUgbmFtZSBvZiB0aGUgbWV0cmljXG4gICAqIEBwYXJhbSBwcm9wcyBDdXN0b21pemF0aW9uIHByb3BlcnRpZXNcbiAgICovXG4gIG1ldHJpYyhtZXRyaWNOYW1lOiBzdHJpbmcsIHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgS2luZXNpcyBQcm9jZXNzaW5nIFVuaXRzIHRoYXQgYXJlIHVzZWQgdG8gcnVuIHlvdXIgc3RyZWFtXG4gICAqIHByb2Nlc3NpbmcgYXBwbGljYXRpb24uIFRoZSBhdmVyYWdlIG51bWJlciBvZiBLUFVzIHVzZWQgZWFjaCBob3VyXG4gICAqIGRldGVybWluZXMgdGhlIGJpbGxpbmcgZm9yIHlvdXIgYXBwbGljYXRpb24uXG4gICAqXG4gICAqIFVuaXRzOiBDb3VudFxuICAgKlxuICAgKiBSZXBvcnRpbmcgTGV2ZWw6IEFwcGxpY2F0aW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gYXZlcmFnZSBvdmVyIDUgbWludXRlc1xuICAgKi9cbiAgbWV0cmljS3B1cyhwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBUaGUgdGltZSBlbGFwc2VkIGR1cmluZyBhbiBvdXRhZ2UgZm9yIGZhaWxpbmcvcmVjb3ZlcmluZyBqb2JzLlxuICAgKlxuICAgKiBVbml0czogTWlsbGlzZWNvbmRzXG4gICAqXG4gICAqIFJlcG9ydGluZyBMZXZlbDogQXBwbGljYXRpb25cbiAgICpcbiAgICogQGRlZmF1bHQgLSBhdmVyYWdlIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNEb3dudGltZShwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBUaGUgdGltZSB0aGF0IHRoZSBqb2IgaGFzIGJlZW4gcnVubmluZyB3aXRob3V0IGludGVycnVwdGlvbi5cbiAgICpcbiAgICogVW5pdHM6IE1pbGxpc2Vjb25kc1xuICAgKlxuICAgKiBSZXBvcnRpbmcgTGV2ZWw6IEFwcGxpY2F0aW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gc2FtcGxlIGNvdW50IG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNVcHRpbWUocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYztcblxuICAvKipcbiAgICogVGhlIHRvdGFsIG51bWJlciBvZiB0aW1lcyB0aGlzIGpvYiBoYXMgZnVsbHkgcmVzdGFydGVkIHNpbmNlIGl0IHdhc1xuICAgKiBzdWJtaXR0ZWQuIFRoaXMgbWV0cmljIGRvZXMgbm90IG1lYXN1cmUgZmluZS1ncmFpbmVkIHJlc3RhcnRzLlxuICAgKlxuICAgKiBVbml0czogQ291bnRcbiAgICpcbiAgICogUmVwb3J0aW5nIExldmVsOiBBcHBsaWNhdGlvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHN1bSBvdmVyIDUgbWludXRlc1xuICAgKi9cbiAgbWV0cmljRnVsbFJlc3RhcnRzKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgdGltZXMgY2hlY2twb2ludGluZyBoYXMgZmFpbGVkLlxuICAgKlxuICAgKiBVbml0czogQ291bnRcbiAgICpcbiAgICogUmVwb3J0aW5nIExldmVsOiBBcHBsaWNhdGlvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHN1bSBvdmVyIDUgbWludXRlc1xuICAgKi9cbiAgbWV0cmljTnVtYmVyT2ZGYWlsZWRDaGVja3BvaW50cyhwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBUaGUgdGltZSBpdCB0b29rIHRvIGNvbXBsZXRlIHRoZSBsYXN0IGNoZWNrcG9pbnQuXG4gICAqXG4gICAqIFVuaXRzOiBNaWxsaXNlY29uZHNcbiAgICpcbiAgICogUmVwb3J0aW5nIExldmVsOiBBcHBsaWNhdGlvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG1heGltdW0gb3ZlciA1IG1pbnV0ZXNcbiAgICovXG4gIG1ldHJpY0xhc3RDaGVja3BvaW50RHVyYXRpb24ocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYztcblxuICAvKipcbiAgICogVGhlIHRvdGFsIHNpemUgb2YgdGhlIGxhc3QgY2hlY2twb2ludC5cbiAgICpcbiAgICogVW5pdHM6IEJ5dGVzXG4gICAqXG4gICAqIFJlcG9ydGluZyBMZXZlbDogQXBwbGljYXRpb25cbiAgICpcbiAgICogQGRlZmF1bHQgLSBtYXhpbXVtIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNMYXN0Q2hlY2twb2ludFNpemUocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYztcblxuICAvKipcbiAgICogVGhlIG92ZXJhbGwgcGVyY2VudGFnZSBvZiBDUFUgdXRpbGl6YXRpb24gYWNyb3NzIHRhc2sgbWFuYWdlcnMuIEZvclxuICAgKiBleGFtcGxlLCBpZiB0aGVyZSBhcmUgZml2ZSB0YXNrIG1hbmFnZXJzLCBLaW5lc2lzIERhdGEgQW5hbHl0aWNzIHB1Ymxpc2hlc1xuICAgKiBmaXZlIHNhbXBsZXMgb2YgdGhpcyBtZXRyaWMgcGVyIHJlcG9ydGluZyBpbnRlcnZhbC5cbiAgICpcbiAgICogVW5pdHM6IFBlcmNlbnRhZ2VcbiAgICpcbiAgICogUmVwb3J0aW5nIExldmVsOiBBcHBsaWNhdGlvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGF2ZXJhZ2Ugb3ZlciA1IG1pbnV0ZXNcbiAgICovXG4gIG1ldHJpY0NwdVV0aWxpemF0aW9uKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIE92ZXJhbGwgaGVhcCBtZW1vcnkgdXRpbGl6YXRpb24gYWNyb3NzIHRhc2sgbWFuYWdlcnMuIEZvciBleGFtcGxlLCBpZiB0aGVyZVxuICAgKiBhcmUgZml2ZSB0YXNrIG1hbmFnZXJzLCBLaW5lc2lzIERhdGEgQW5hbHl0aWNzIHB1Ymxpc2hlcyBmaXZlIHNhbXBsZXMgb2ZcbiAgICogdGhpcyBtZXRyaWMgcGVyIHJlcG9ydGluZyBpbnRlcnZhbC5cbiAgICpcbiAgICogVW5pdHM6IFBlcmNlbnRhZ2VcbiAgICpcbiAgICogUmVwb3J0aW5nIExldmVsOiBBcHBsaWNhdGlvblxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGF2ZXJhZ2Ugb3ZlciA1IG1pbnV0ZXNcbiAgICovXG4gIG1ldHJpY0hlYXBNZW1vcnlVdGlsaXphdGlvbihwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBUaGUgdG90YWwgdGltZSBzcGVudCBwZXJmb3JtaW5nIG9sZCBnYXJiYWdlIGNvbGxlY3Rpb24gb3BlcmF0aW9ucy5cbiAgICpcbiAgICogVW5pdHM6IE1pbGxpc2Vjb25kc1xuICAgKlxuICAgKiBSZXBvcnRpbmcgTGV2ZWw6IEFwcGxpY2F0aW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gc3VtIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNPbGRHZW5lcmF0aW9uR0NUaW1lKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIFRoZSB0b3RhbCBudW1iZXIgb2Ygb2xkIGdhcmJhZ2UgY29sbGVjdGlvbiBvcGVyYXRpb25zIHRoYXQgaGF2ZSBvY2N1cnJlZFxuICAgKiBhY3Jvc3MgYWxsIHRhc2sgbWFuYWdlcnMuXG4gICAqXG4gICAqIFVuaXRzOiBDb3VudFxuICAgKlxuICAgKiBSZXBvcnRpbmcgTGV2ZWw6IEFwcGxpY2F0aW9uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gc3VtIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNPbGRHZW5lcmF0aW9uR0NDb3VudChwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBUaGUgdG90YWwgbnVtYmVyIG9mIGxpdmUgdGhyZWFkcyB1c2VkIGJ5IHRoZSBhcHBsaWNhdGlvbi5cbiAgICpcbiAgICogVW5pdHM6IENvdW50XG4gICAqXG4gICAqIFJlcG9ydGluZyBMZXZlbDogQXBwbGljYXRpb25cbiAgICpcbiAgICogQGRlZmF1bHQgLSBhdmVyYWdlIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBtZXRyaWNUaHJlYWRzQ291bnQocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYztcblxuICAvKipcbiAgICogVGhlIHRvdGFsIG51bWJlciBvZiByZWNvcmRzIHRoaXMgYXBwbGljYXRpb24sIG9wZXJhdG9yLCBvciB0YXNrIGhhc1xuICAgKiByZWNlaXZlZC5cbiAgICpcbiAgICogVW5pdHM6IENvdW50XG4gICAqXG4gICAqIFJlcG9ydGluZyBMZXZlbDogQXBwbGljYXRpb24sIE9wZXJhdG9yLCBUYXNrLCBQYXJhbGxlbGlzbVxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGF2ZXJhZ2Ugb3ZlciA1IG1pbnV0ZXNcbiAgICovXG4gIG1ldHJpY051bVJlY29yZHNJbihwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2g