1 | ;
|
2 | var _a;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | exports.TableClass = exports.StreamViewType = exports.ProjectionType = exports.BillingMode = exports.AttributeType = exports.Table = exports.TableEncryption = exports.Operation = void 0;
|
5 | const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
|
6 | const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
7 | const appscaling = require("@aws-cdk/aws-applicationautoscaling");
|
8 | const cloudwatch = require("@aws-cdk/aws-cloudwatch");
|
9 | const iam = require("@aws-cdk/aws-iam");
|
10 | const kms = require("@aws-cdk/aws-kms");
|
11 | const core_1 = require("@aws-cdk/core");
|
12 | const dynamodb_canned_metrics_generated_1 = require("./dynamodb-canned-metrics.generated");
|
13 | const dynamodb_generated_1 = require("./dynamodb.generated");
|
14 | const perms = require("./perms");
|
15 | const replica_provider_1 = require("./replica-provider");
|
16 | const scalable_table_attribute_1 = require("./scalable-table-attribute");
|
17 | // keep this import separate from other imports to reduce chance for merge conflicts with v2-main
|
18 | // eslint-disable-next-line no-duplicate-imports, import/order
|
19 | const core_2 = require("@aws-cdk/core");
|
20 | const HASH_KEY_TYPE = 'HASH';
|
21 | const RANGE_KEY_TYPE = 'RANGE';
|
22 | // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-secondary-indexes
|
23 | const MAX_LOCAL_SECONDARY_INDEX_COUNT = 5;
|
24 | /**
|
25 | * Supported DynamoDB table operations.
|
26 | */
|
27 | var Operation;
|
28 | (function (Operation) {
|
29 | /** GetItem */
|
30 | Operation["GET_ITEM"] = "GetItem";
|
31 | /** BatchGetItem */
|
32 | Operation["BATCH_GET_ITEM"] = "BatchGetItem";
|
33 | /** Scan */
|
34 | Operation["SCAN"] = "Scan";
|
35 | /** Query */
|
36 | Operation["QUERY"] = "Query";
|
37 | /** GetRecords */
|
38 | Operation["GET_RECORDS"] = "GetRecords";
|
39 | /** PutItem */
|
40 | Operation["PUT_ITEM"] = "PutItem";
|
41 | /** DeleteItem */
|
42 | Operation["DELETE_ITEM"] = "DeleteItem";
|
43 | /** UpdateItem */
|
44 | Operation["UPDATE_ITEM"] = "UpdateItem";
|
45 | /** BatchWriteItem */
|
46 | Operation["BATCH_WRITE_ITEM"] = "BatchWriteItem";
|
47 | /** TransactWriteItems */
|
48 | Operation["TRANSACT_WRITE_ITEMS"] = "TransactWriteItems";
|
49 | /** TransactGetItems */
|
50 | Operation["TRANSACT_GET_ITEMS"] = "TransactGetItems";
|
51 | /** ExecuteTransaction */
|
52 | Operation["EXECUTE_TRANSACTION"] = "ExecuteTransaction";
|
53 | /** BatchExecuteStatement */
|
54 | Operation["BATCH_EXECUTE_STATEMENT"] = "BatchExecuteStatement";
|
55 | /** ExecuteStatement */
|
56 | Operation["EXECUTE_STATEMENT"] = "ExecuteStatement";
|
57 | })(Operation = exports.Operation || (exports.Operation = {}));
|
58 | /**
|
59 | * What kind of server-side encryption to apply to this table.
|
60 | */
|
61 | var TableEncryption;
|
62 | (function (TableEncryption) {
|
63 | /**
|
64 | * Server-side KMS encryption with a master key owned by AWS.
|
65 | */
|
66 | TableEncryption["DEFAULT"] = "AWS_OWNED";
|
67 | /**
|
68 | * Server-side KMS encryption with a customer master key managed by customer.
|
69 | * If `encryptionKey` is specified, this key will be used, otherwise, one will be defined.
|
70 | *
|
71 | * > **NOTE**: if `encryptionKey` is not specified and the `Table` construct creates
|
72 | * > a KMS key for you, the key will be created with default permissions. If you are using
|
73 | * > CDKv2, these permissions will be sufficient to enable the key for use with DynamoDB tables.
|
74 | * > If you are using CDKv1, make sure the feature flag `@aws-cdk/aws-kms:defaultKeyPolicies`
|
75 | * > is set to `true` in your `cdk.json`.
|
76 | */
|
77 | TableEncryption["CUSTOMER_MANAGED"] = "CUSTOMER_MANAGED";
|
78 | /**
|
79 | * Server-side KMS encryption with a master key managed by AWS.
|
80 | */
|
81 | TableEncryption["AWS_MANAGED"] = "AWS_MANAGED";
|
82 | })(TableEncryption = exports.TableEncryption || (exports.TableEncryption = {}));
|
83 | class TableBase extends core_1.Resource {
|
84 | constructor() {
|
85 | super(...arguments);
|
86 | this.regionalArns = new Array();
|
87 | }
|
88 | /**
|
89 | * Adds an IAM policy statement associated with this table to an IAM
|
90 | * principal's policy.
|
91 | *
|
92 | * If `encryptionKey` is present, appropriate grants to the key needs to be added
|
93 | * separately using the `table.encryptionKey.grant*` methods.
|
94 | *
|
95 | * @param grantee The principal (no-op if undefined)
|
96 | * @param actions The set of actions to allow (i.e. "dynamodb:PutItem", "dynamodb:GetItem", ...)
|
97 | */
|
98 | grant(grantee, ...actions) {
|
99 | return iam.Grant.addToPrincipal({
|
100 | grantee,
|
101 | actions,
|
102 | resourceArns: [
|
103 | this.tableArn,
|
104 | core_1.Lazy.string({ produce: () => this.hasIndex ? `${this.tableArn}/index/*` : core_1.Aws.NO_VALUE }),
|
105 | ...this.regionalArns,
|
106 | ...this.regionalArns.map(arn => core_1.Lazy.string({
|
107 | produce: () => this.hasIndex ? `${arn}/index/*` : core_1.Aws.NO_VALUE,
|
108 | })),
|
109 | ],
|
110 | scope: this,
|
111 | });
|
112 | }
|
113 | /**
|
114 | * Adds an IAM policy statement associated with this table's stream to an
|
115 | * IAM principal's policy.
|
116 | *
|
117 | * If `encryptionKey` is present, appropriate grants to the key needs to be added
|
118 | * separately using the `table.encryptionKey.grant*` methods.
|
119 | *
|
120 | * @param grantee The principal (no-op if undefined)
|
121 | * @param actions The set of actions to allow (i.e. "dynamodb:DescribeStream", "dynamodb:GetRecords", ...)
|
122 | */
|
123 | grantStream(grantee, ...actions) {
|
124 | if (!this.tableStreamArn) {
|
125 | throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`);
|
126 | }
|
127 | return iam.Grant.addToPrincipal({
|
128 | grantee,
|
129 | actions,
|
130 | resourceArns: [this.tableStreamArn],
|
131 | scope: this,
|
132 | });
|
133 | }
|
134 | /**
|
135 | * Permits an IAM principal all data read operations from this table:
|
136 | * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan, DescribeTable.
|
137 | *
|
138 | * Appropriate grants will also be added to the customer-managed KMS key
|
139 | * if one was configured.
|
140 | *
|
141 | * @param grantee The principal to grant access to
|
142 | */
|
143 | grantReadData(grantee) {
|
144 | const tableActions = perms.READ_DATA_ACTIONS.concat(perms.DESCRIBE_TABLE);
|
145 | return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, tableActions });
|
146 | }
|
147 | /**
|
148 | * Permits an IAM Principal to list streams attached to current dynamodb table.
|
149 | *
|
150 | * @param grantee The principal (no-op if undefined)
|
151 | */
|
152 | grantTableListStreams(grantee) {
|
153 | if (!this.tableStreamArn) {
|
154 | throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`);
|
155 | }
|
156 | return iam.Grant.addToPrincipal({
|
157 | grantee,
|
158 | actions: ['dynamodb:ListStreams'],
|
159 | resourceArns: ['*'],
|
160 | });
|
161 | }
|
162 | /**
|
163 | * Permits an IAM principal all stream data read operations for this
|
164 | * table's stream:
|
165 | * DescribeStream, GetRecords, GetShardIterator, ListStreams.
|
166 | *
|
167 | * Appropriate grants will also be added to the customer-managed KMS key
|
168 | * if one was configured.
|
169 | *
|
170 | * @param grantee The principal to grant access to
|
171 | */
|
172 | grantStreamRead(grantee) {
|
173 | this.grantTableListStreams(grantee);
|
174 | return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, streamActions: perms.READ_STREAM_DATA_ACTIONS });
|
175 | }
|
176 | /**
|
177 | * Permits an IAM principal all data write operations to this table:
|
178 | * BatchWriteItem, PutItem, UpdateItem, DeleteItem, DescribeTable.
|
179 | *
|
180 | * Appropriate grants will also be added to the customer-managed KMS key
|
181 | * if one was configured.
|
182 | *
|
183 | * @param grantee The principal to grant access to
|
184 | */
|
185 | grantWriteData(grantee) {
|
186 | const tableActions = perms.WRITE_DATA_ACTIONS.concat(perms.DESCRIBE_TABLE);
|
187 | const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS);
|
188 | return this.combinedGrant(grantee, { keyActions, tableActions });
|
189 | }
|
190 | /**
|
191 | * Permits an IAM principal to all data read/write operations to this table.
|
192 | * BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan,
|
193 | * BatchWriteItem, PutItem, UpdateItem, DeleteItem, DescribeTable
|
194 | *
|
195 | * Appropriate grants will also be added to the customer-managed KMS key
|
196 | * if one was configured.
|
197 | *
|
198 | * @param grantee The principal to grant access to
|
199 | */
|
200 | grantReadWriteData(grantee) {
|
201 | const tableActions = perms.READ_DATA_ACTIONS.concat(perms.WRITE_DATA_ACTIONS).concat(perms.DESCRIBE_TABLE);
|
202 | const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS);
|
203 | return this.combinedGrant(grantee, { keyActions, tableActions });
|
204 | }
|
205 | /**
|
206 | * Permits all DynamoDB operations ("dynamodb:*") to an IAM principal.
|
207 | *
|
208 | * Appropriate grants will also be added to the customer-managed KMS key
|
209 | * if one was configured.
|
210 | *
|
211 | * @param grantee The principal to grant access to
|
212 | */
|
213 | grantFullAccess(grantee) {
|
214 | const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS);
|
215 | return this.combinedGrant(grantee, { keyActions, tableActions: ['dynamodb:*'] });
|
216 | }
|
217 | /**
|
218 | * Return the given named metric for this Table
|
219 | *
|
220 | * By default, the metric will be calculated as a sum over a period of 5 minutes.
|
221 | * You can customize this by using the `statistic` and `period` properties.
|
222 | */
|
223 | metric(metricName, props) {
|
224 | return new cloudwatch.Metric({
|
225 | namespace: 'AWS/DynamoDB',
|
226 | metricName,
|
227 | dimensionsMap: {
|
228 | TableName: this.tableName,
|
229 | },
|
230 | ...props,
|
231 | }).attachTo(this);
|
232 | }
|
233 | /**
|
234 | * Metric for the consumed read capacity units this table
|
235 | *
|
236 | * By default, the metric will be calculated as a sum over a period of 5 minutes.
|
237 | * You can customize this by using the `statistic` and `period` properties.
|
238 | */
|
239 | metricConsumedReadCapacityUnits(props) {
|
240 | return this.cannedMetric(dynamodb_canned_metrics_generated_1.DynamoDBMetrics.consumedReadCapacityUnitsSum, props);
|
241 | }
|
242 | /**
|
243 | * Metric for the consumed write capacity units this table
|
244 | *
|
245 | * By default, the metric will be calculated as a sum over a period of 5 minutes.
|
246 | * You can customize this by using the `statistic` and `period` properties.
|
247 | */
|
248 | metricConsumedWriteCapacityUnits(props) {
|
249 | return this.cannedMetric(dynamodb_canned_metrics_generated_1.DynamoDBMetrics.consumedWriteCapacityUnitsSum, props);
|
250 | }
|
251 | /**
|
252 | * Metric for the system errors this table
|
253 | *
|
254 | * @deprecated use `metricSystemErrorsForOperations`.
|
255 | */
|
256 | metricSystemErrors(props) {
|
257 | var _b, _c, _d, _e;
|
258 | if (!((_b = props === null || props === void 0 ? void 0 : props.dimensions) === null || _b === void 0 ? void 0 : _b.Operation) && !((_c = props === null || props === void 0 ? void 0 : props.dimensionsMap) === null || _c === void 0 ? void 0 : _c.Operation)) {
|
259 | // 'Operation' must be passed because its an operational metric.
|
260 | throw new Error("'Operation' dimension must be passed for the 'SystemErrors' metric.");
|
261 | }
|
262 | const dimensionsMap = {
|
263 | TableName: this.tableName,
|
264 | ...(_d = props === null || props === void 0 ? void 0 : props.dimensions) !== null && _d !== void 0 ? _d : {},
|
265 | ...(_e = props === null || props === void 0 ? void 0 : props.dimensionsMap) !== null && _e !== void 0 ? _e : {},
|
266 | };
|
267 | return this.metric('SystemErrors', { statistic: 'sum', ...props, dimensionsMap });
|
268 | }
|
269 | /**
|
270 | * Metric for the user errors. Note that this metric reports user errors across all
|
271 | * the tables in the account and region the table resides in.
|
272 | *
|
273 | * By default, the metric will be calculated as a sum over a period of 5 minutes.
|
274 | * You can customize this by using the `statistic` and `period` properties.
|
275 | */
|
276 | metricUserErrors(props) {
|
277 | if (props === null || props === void 0 ? void 0 : props.dimensions) {
|
278 | throw new Error("'dimensions' is not supported for the 'UserErrors' metric");
|
279 | }
|
280 | // overriding 'dimensions' here because this metric is an account metric.
|
281 | // see 'UserErrors' in https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/metrics-dimensions.html
|
282 | return this.metric('UserErrors', { statistic: 'sum', ...props, dimensionsMap: {} });
|
283 | }
|
284 | /**
|
285 | * Metric for the conditional check failed requests this table
|
286 | *
|
287 | * By default, the metric will be calculated as a sum over a period of 5 minutes.
|
288 | * You can customize this by using the `statistic` and `period` properties.
|
289 | */
|
290 | metricConditionalCheckFailedRequests(props) {
|
291 | return this.metric('ConditionalCheckFailedRequests', { statistic: 'sum', ...props });
|
292 | }
|
293 | /**
|
294 | * How many requests are throttled on this table
|
295 | *
|
296 | * Default: sum over 5 minutes
|
297 | *
|
298 | * @deprecated Do not use this function. It returns an invalid metric. Use `metricThrottledRequestsForOperation` instead.
|
299 | */
|
300 | metricThrottledRequests(props) {
|
301 | return this.metric('ThrottledRequests', { statistic: 'sum', ...props });
|
302 | }
|
303 | /**
|
304 | * How many requests are throttled on this table, for the given operation
|
305 | *
|
306 | * Default: sum over 5 minutes
|
307 | */
|
308 | metricThrottledRequestsForOperation(operation, props) {
|
309 | return new cloudwatch.Metric({
|
310 | ...dynamodb_canned_metrics_generated_1.DynamoDBMetrics.throttledRequestsSum({ Operation: operation, TableName: this.tableName }),
|
311 | ...props,
|
312 | }).attachTo(this);
|
313 | }
|
314 | /**
|
315 | * Metric for the successful request latency this table.
|
316 | *
|
317 | * By default, the metric will be calculated as an average over a period of 5 minutes.
|
318 | * You can customize this by using the `statistic` and `period` properties.
|
319 | */
|
320 | metricSuccessfulRequestLatency(props) {
|
321 | var _b, _c, _d, _e, _f;
|
322 | if (!((_b = props === null || props === void 0 ? void 0 : props.dimensions) === null || _b === void 0 ? void 0 : _b.Operation) && !((_c = props === null || props === void 0 ? void 0 : props.dimensionsMap) === null || _c === void 0 ? void 0 : _c.Operation)) {
|
323 | throw new Error("'Operation' dimension must be passed for the 'SuccessfulRequestLatency' metric.");
|
324 | }
|
325 | const dimensionsMap = {
|
326 | TableName: this.tableName,
|
327 | Operation: (_e = (_d = props.dimensionsMap) === null || _d === void 0 ? void 0 : _d.Operation) !== null && _e !== void 0 ? _e : (_f = props.dimensions) === null || _f === void 0 ? void 0 : _f.Operation,
|
328 | };
|
329 | return new cloudwatch.Metric({
|
330 | ...dynamodb_canned_metrics_generated_1.DynamoDBMetrics.successfulRequestLatencyAverage(dimensionsMap),
|
331 | ...props,
|
332 | dimensionsMap,
|
333 | }).attachTo(this);
|
334 | }
|
335 | /**
|
336 | * Metric for the system errors this table.
|
337 | *
|
338 | * This will sum errors across all possible operations.
|
339 | * Note that by default, each individual metric will be calculated as a sum over a period of 5 minutes.
|
340 | * You can customize this by using the `statistic` and `period` properties.
|
341 | */
|
342 | metricSystemErrorsForOperations(props) {
|
343 | var _b, _c;
|
344 | if ((_b = props === null || props === void 0 ? void 0 : props.dimensions) === null || _b === void 0 ? void 0 : _b.Operation) {
|
345 | throw new Error("The Operation dimension is not supported. Use the 'operations' property.");
|
346 | }
|
347 | const operations = (_c = props === null || props === void 0 ? void 0 : props.operations) !== null && _c !== void 0 ? _c : Object.values(Operation);
|
348 | const values = this.createMetricsForOperations('SystemErrors', operations, { statistic: 'sum', ...props });
|
349 | const sum = new cloudwatch.MathExpression({
|
350 | expression: `${Object.keys(values).join(' + ')}`,
|
351 | usingMetrics: { ...values },
|
352 | color: props === null || props === void 0 ? void 0 : props.color,
|
353 | label: 'Sum of errors across all operations',
|
354 | period: props === null || props === void 0 ? void 0 : props.period,
|
355 | });
|
356 | return sum;
|
357 | }
|
358 | /**
|
359 | * Create a map of metrics that can be used in a math expression.
|
360 | *
|
361 | * Using the return value of this function as the `usingMetrics` property in `cloudwatch.MathExpression` allows you to
|
362 | * use the keys of this map as metric names inside you expression.
|
363 | *
|
364 | * @param metricName The metric name.
|
365 | * @param operations The list of operations to create metrics for.
|
366 | * @param props Properties for the individual metrics.
|
367 | * @param metricNameMapper Mapper function to allow controlling the individual metric name per operation.
|
368 | */
|
369 | createMetricsForOperations(metricName, operations, props, metricNameMapper) {
|
370 | var _b;
|
371 | const metrics = {};
|
372 | const mapper = metricNameMapper !== null && metricNameMapper !== void 0 ? metricNameMapper : (op => op.toLowerCase());
|
373 | if ((_b = props === null || props === void 0 ? void 0 : props.dimensions) === null || _b === void 0 ? void 0 : _b.Operation) {
|
374 | throw new Error('Invalid properties. Operation dimension is not supported when calculating operational metrics');
|
375 | }
|
376 | for (const operation of operations) {
|
377 | const metric = this.metric(metricName, {
|
378 | ...props,
|
379 | dimensionsMap: {
|
380 | TableName: this.tableName,
|
381 | Operation: operation,
|
382 | ...props === null || props === void 0 ? void 0 : props.dimensions,
|
383 | },
|
384 | });
|
385 | const operationMetricName = mapper(operation);
|
386 | const firstChar = operationMetricName.charAt(0);
|
387 | if (firstChar === firstChar.toUpperCase()) {
|
388 | // https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html#metric-math-syntax
|
389 | throw new Error(`Mapper generated an illegal operation metric name: ${operationMetricName}. Must start with a lowercase letter`);
|
390 | }
|
391 | metrics[operationMetricName] = metric;
|
392 | }
|
393 | return metrics;
|
394 | }
|
395 | /**
|
396 | * Adds an IAM policy statement associated with this table to an IAM
|
397 | * principal's policy.
|
398 | * @param grantee The principal (no-op if undefined)
|
399 | * @param opts Options for keyActions, tableActions and streamActions
|
400 | */
|
401 | combinedGrant(grantee, opts) {
|
402 | if (opts.tableActions) {
|
403 | const resources = [this.tableArn,
|
404 | core_1.Lazy.string({ produce: () => this.hasIndex ? `${this.tableArn}/index/*` : core_1.Aws.NO_VALUE }),
|
405 | ...this.regionalArns,
|
406 | ...this.regionalArns.map(arn => core_1.Lazy.string({
|
407 | produce: () => this.hasIndex ? `${arn}/index/*` : core_1.Aws.NO_VALUE,
|
408 | }))];
|
409 | const ret = iam.Grant.addToPrincipal({
|
410 | grantee,
|
411 | actions: opts.tableActions,
|
412 | resourceArns: resources,
|
413 | scope: this,
|
414 | });
|
415 | if (this.encryptionKey && opts.keyActions) {
|
416 | this.encryptionKey.grant(grantee, ...opts.keyActions);
|
417 | }
|
418 | return ret;
|
419 | }
|
420 | if (opts.streamActions) {
|
421 | if (!this.tableStreamArn) {
|
422 | throw new Error(`DynamoDB Streams must be enabled on the table ${this.node.path}`);
|
423 | }
|
424 | const resources = [this.tableStreamArn];
|
425 | const ret = iam.Grant.addToPrincipal({
|
426 | grantee,
|
427 | actions: opts.streamActions,
|
428 | resourceArns: resources,
|
429 | scope: this,
|
430 | });
|
431 | return ret;
|
432 | }
|
433 | throw new Error(`Unexpected 'action', ${opts.tableActions || opts.streamActions}`);
|
434 | }
|
435 | cannedMetric(fn, props) {
|
436 | return new cloudwatch.Metric({
|
437 | ...fn({ TableName: this.tableName }),
|
438 | ...props,
|
439 | }).attachTo(this);
|
440 | }
|
441 | }
|
442 | /**
|
443 | * Provides a DynamoDB table.
|
444 | */
|
445 | class Table extends TableBase {
|
446 | constructor(scope, id, props) {
|
447 | var _b, _c;
|
448 | super(scope, id, {
|
449 | physicalName: props.tableName,
|
450 | });
|
451 | this.keySchema = new Array();
|
452 | this.attributeDefinitions = new Array();
|
453 | this.globalSecondaryIndexes = new Array();
|
454 | this.localSecondaryIndexes = new Array();
|
455 | this.secondaryIndexSchemas = new Map();
|
456 | this.nonKeyAttributes = new Set();
|
457 | this.tableScaling = {};
|
458 | this.indexScaling = new Map();
|
459 | this.globalReplicaCustomResources = new Array();
|
460 | try {
|
461 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_TableProps(props);
|
462 | }
|
463 | catch (error) {
|
464 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
465 | Error.captureStackTrace(error, this.constructor);
|
466 | }
|
467 | throw error;
|
468 | }
|
469 | const { sseSpecification, encryptionKey } = this.parseEncryption(props);
|
470 | let streamSpecification;
|
471 | if (props.replicationRegions) {
|
472 | if (props.stream && props.stream !== StreamViewType.NEW_AND_OLD_IMAGES) {
|
473 | throw new Error('`stream` must be set to `NEW_AND_OLD_IMAGES` when specifying `replicationRegions`');
|
474 | }
|
475 | streamSpecification = { streamViewType: StreamViewType.NEW_AND_OLD_IMAGES };
|
476 | this.billingMode = (_b = props.billingMode) !== null && _b !== void 0 ? _b : BillingMode.PAY_PER_REQUEST;
|
477 | }
|
478 | else {
|
479 | this.billingMode = (_c = props.billingMode) !== null && _c !== void 0 ? _c : BillingMode.PROVISIONED;
|
480 | if (props.stream) {
|
481 | streamSpecification = { streamViewType: props.stream };
|
482 | }
|
483 | }
|
484 | this.validateProvisioning(props);
|
485 | this.table = new dynamodb_generated_1.CfnTable(this, 'Resource', {
|
486 | tableName: this.physicalName,
|
487 | keySchema: this.keySchema,
|
488 | attributeDefinitions: this.attributeDefinitions,
|
489 | globalSecondaryIndexes: core_1.Lazy.any({ produce: () => this.globalSecondaryIndexes }, { omitEmptyArray: true }),
|
490 | localSecondaryIndexes: core_1.Lazy.any({ produce: () => this.localSecondaryIndexes }, { omitEmptyArray: true }),
|
491 | pointInTimeRecoverySpecification: props.pointInTimeRecovery != null ? { pointInTimeRecoveryEnabled: props.pointInTimeRecovery } : undefined,
|
492 | billingMode: this.billingMode === BillingMode.PAY_PER_REQUEST ? this.billingMode : undefined,
|
493 | provisionedThroughput: this.billingMode === BillingMode.PAY_PER_REQUEST ? undefined : {
|
494 | readCapacityUnits: props.readCapacity || 5,
|
495 | writeCapacityUnits: props.writeCapacity || 5,
|
496 | },
|
497 | sseSpecification,
|
498 | streamSpecification,
|
499 | tableClass: props.tableClass,
|
500 | timeToLiveSpecification: props.timeToLiveAttribute ? { attributeName: props.timeToLiveAttribute, enabled: true } : undefined,
|
501 | contributorInsightsSpecification: props.contributorInsightsEnabled !== undefined ? { enabled: props.contributorInsightsEnabled } : undefined,
|
502 | kinesisStreamSpecification: props.kinesisStream ? { streamArn: props.kinesisStream.streamArn } : undefined,
|
503 | });
|
504 | this.table.applyRemovalPolicy(props.removalPolicy);
|
505 | this.encryptionKey = encryptionKey;
|
506 | this.tableArn = this.getResourceArnAttribute(this.table.attrArn, {
|
507 | service: 'dynamodb',
|
508 | resource: 'table',
|
509 | resourceName: this.physicalName,
|
510 | });
|
511 | this.tableName = this.getResourceNameAttribute(this.table.ref);
|
512 | if (props.tableName) {
|
513 | this.node.addMetadata('aws:cdk:hasPhysicalName', this.tableName);
|
514 | }
|
515 | this.tableStreamArn = streamSpecification ? this.table.attrStreamArn : undefined;
|
516 | this.scalingRole = this.makeScalingRole();
|
517 | this.addKey(props.partitionKey, HASH_KEY_TYPE);
|
518 | this.tablePartitionKey = props.partitionKey;
|
519 | if (props.sortKey) {
|
520 | this.addKey(props.sortKey, RANGE_KEY_TYPE);
|
521 | this.tableSortKey = props.sortKey;
|
522 | }
|
523 | if (props.replicationRegions && props.replicationRegions.length > 0) {
|
524 | this.createReplicaTables(props.replicationRegions, props.replicationTimeout, props.waitForReplicationToFinish);
|
525 | }
|
526 | }
|
527 | /**
|
528 | * Permits an IAM Principal to list all DynamoDB Streams.
|
529 | * @deprecated Use {@link #grantTableListStreams} for more granular permission
|
530 | * @param grantee The principal (no-op if undefined)
|
531 | */
|
532 | static grantListStreams(grantee) {
|
533 | try {
|
534 | jsiiDeprecationWarnings.print("@aws-cdk/aws-dynamodb.Table#grantListStreams", "Use {@link #grantTableListStreams} for more granular permission");
|
535 | }
|
536 | catch (error) {
|
537 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
538 | Error.captureStackTrace(error, this.grantListStreams);
|
539 | }
|
540 | throw error;
|
541 | }
|
542 | return iam.Grant.addToPrincipal({
|
543 | grantee,
|
544 | actions: ['dynamodb:ListStreams'],
|
545 | resourceArns: ['*'],
|
546 | });
|
547 | }
|
548 | /**
|
549 | * Creates a Table construct that represents an external table via table name.
|
550 | *
|
551 | * @param scope The parent creating construct (usually `this`).
|
552 | * @param id The construct's name.
|
553 | * @param tableName The table's name.
|
554 | */
|
555 | static fromTableName(scope, id, tableName) {
|
556 | return Table.fromTableAttributes(scope, id, { tableName });
|
557 | }
|
558 | /**
|
559 | * Creates a Table construct that represents an external table via table arn.
|
560 | *
|
561 | * @param scope The parent creating construct (usually `this`).
|
562 | * @param id The construct's name.
|
563 | * @param tableArn The table's ARN.
|
564 | */
|
565 | static fromTableArn(scope, id, tableArn) {
|
566 | return Table.fromTableAttributes(scope, id, { tableArn });
|
567 | }
|
568 | /**
|
569 | * Creates a Table construct that represents an external table.
|
570 | *
|
571 | * @param scope The parent creating construct (usually `this`).
|
572 | * @param id The construct's name.
|
573 | * @param attrs A `TableAttributes` object.
|
574 | */
|
575 | static fromTableAttributes(scope, id, attrs) {
|
576 | try {
|
577 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_TableAttributes(attrs);
|
578 | }
|
579 | catch (error) {
|
580 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
581 | Error.captureStackTrace(error, this.fromTableAttributes);
|
582 | }
|
583 | throw error;
|
584 | }
|
585 | class Import extends TableBase {
|
586 | constructor(_tableArn, tableName, tableStreamArn) {
|
587 | var _b, _c;
|
588 | super(scope, id);
|
589 | this.hasIndex = ((_b = attrs.globalIndexes) !== null && _b !== void 0 ? _b : []).length > 0 ||
|
590 | ((_c = attrs.localIndexes) !== null && _c !== void 0 ? _c : []).length > 0;
|
591 | this.tableArn = _tableArn;
|
592 | this.tableName = tableName;
|
593 | this.tableStreamArn = tableStreamArn;
|
594 | this.encryptionKey = attrs.encryptionKey;
|
595 | }
|
596 | }
|
597 | let name;
|
598 | let arn;
|
599 | const stack = core_1.Stack.of(scope);
|
600 | if (!attrs.tableName) {
|
601 | if (!attrs.tableArn) {
|
602 | throw new Error('One of tableName or tableArn is required!');
|
603 | }
|
604 | arn = attrs.tableArn;
|
605 | const maybeTableName = stack.splitArn(attrs.tableArn, core_1.ArnFormat.SLASH_RESOURCE_NAME).resourceName;
|
606 | if (!maybeTableName) {
|
607 | throw new Error('ARN for DynamoDB table must be in the form: ...');
|
608 | }
|
609 | name = maybeTableName;
|
610 | }
|
611 | else {
|
612 | if (attrs.tableArn) {
|
613 | throw new Error('Only one of tableArn or tableName can be provided');
|
614 | }
|
615 | name = attrs.tableName;
|
616 | arn = stack.formatArn({
|
617 | service: 'dynamodb',
|
618 | resource: 'table',
|
619 | resourceName: attrs.tableName,
|
620 | });
|
621 | }
|
622 | return new Import(arn, name, attrs.tableStreamArn);
|
623 | }
|
624 | /**
|
625 | * Add a global secondary index of table.
|
626 | *
|
627 | * @param props the property of global secondary index
|
628 | */
|
629 | addGlobalSecondaryIndex(props) {
|
630 | try {
|
631 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_GlobalSecondaryIndexProps(props);
|
632 | }
|
633 | catch (error) {
|
634 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
635 | Error.captureStackTrace(error, this.addGlobalSecondaryIndex);
|
636 | }
|
637 | throw error;
|
638 | }
|
639 | this.validateProvisioning(props);
|
640 | this.validateIndexName(props.indexName);
|
641 | // build key schema and projection for index
|
642 | const gsiKeySchema = this.buildIndexKeySchema(props.partitionKey, props.sortKey);
|
643 | const gsiProjection = this.buildIndexProjection(props);
|
644 | this.globalSecondaryIndexes.push({
|
645 | indexName: props.indexName,
|
646 | keySchema: gsiKeySchema,
|
647 | projection: gsiProjection,
|
648 | provisionedThroughput: this.billingMode === BillingMode.PAY_PER_REQUEST ? undefined : {
|
649 | readCapacityUnits: props.readCapacity || 5,
|
650 | writeCapacityUnits: props.writeCapacity || 5,
|
651 | },
|
652 | });
|
653 | this.secondaryIndexSchemas.set(props.indexName, {
|
654 | partitionKey: props.partitionKey,
|
655 | sortKey: props.sortKey,
|
656 | });
|
657 | this.indexScaling.set(props.indexName, {});
|
658 | }
|
659 | /**
|
660 | * Add a local secondary index of table.
|
661 | *
|
662 | * @param props the property of local secondary index
|
663 | */
|
664 | addLocalSecondaryIndex(props) {
|
665 | try {
|
666 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_LocalSecondaryIndexProps(props);
|
667 | }
|
668 | catch (error) {
|
669 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
670 | Error.captureStackTrace(error, this.addLocalSecondaryIndex);
|
671 | }
|
672 | throw error;
|
673 | }
|
674 | // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-secondary-indexes
|
675 | if (this.localSecondaryIndexes.length >= MAX_LOCAL_SECONDARY_INDEX_COUNT) {
|
676 | throw new RangeError(`a maximum number of local secondary index per table is ${MAX_LOCAL_SECONDARY_INDEX_COUNT}`);
|
677 | }
|
678 | this.validateIndexName(props.indexName);
|
679 | // build key schema and projection for index
|
680 | const lsiKeySchema = this.buildIndexKeySchema(this.tablePartitionKey, props.sortKey);
|
681 | const lsiProjection = this.buildIndexProjection(props);
|
682 | this.localSecondaryIndexes.push({
|
683 | indexName: props.indexName,
|
684 | keySchema: lsiKeySchema,
|
685 | projection: lsiProjection,
|
686 | });
|
687 | this.secondaryIndexSchemas.set(props.indexName, {
|
688 | partitionKey: this.tablePartitionKey,
|
689 | sortKey: props.sortKey,
|
690 | });
|
691 | }
|
692 | /**
|
693 | * Enable read capacity scaling for this table
|
694 | *
|
695 | * @returns An object to configure additional AutoScaling settings
|
696 | */
|
697 | autoScaleReadCapacity(props) {
|
698 | try {
|
699 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_EnableScalingProps(props);
|
700 | }
|
701 | catch (error) {
|
702 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
703 | Error.captureStackTrace(error, this.autoScaleReadCapacity);
|
704 | }
|
705 | throw error;
|
706 | }
|
707 | if (this.tableScaling.scalableReadAttribute) {
|
708 | throw new Error('Read AutoScaling already enabled for this table');
|
709 | }
|
710 | if (this.billingMode === BillingMode.PAY_PER_REQUEST) {
|
711 | throw new Error('AutoScaling is not available for tables with PAY_PER_REQUEST billing mode');
|
712 | }
|
713 | return this.tableScaling.scalableReadAttribute = new scalable_table_attribute_1.ScalableTableAttribute(this, 'ReadScaling', {
|
714 | serviceNamespace: appscaling.ServiceNamespace.DYNAMODB,
|
715 | resourceId: `table/${this.tableName}`,
|
716 | dimension: 'dynamodb:table:ReadCapacityUnits',
|
717 | role: this.scalingRole,
|
718 | ...props,
|
719 | });
|
720 | }
|
721 | /**
|
722 | * Enable write capacity scaling for this table
|
723 | *
|
724 | * @returns An object to configure additional AutoScaling settings for this attribute
|
725 | */
|
726 | autoScaleWriteCapacity(props) {
|
727 | try {
|
728 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_EnableScalingProps(props);
|
729 | }
|
730 | catch (error) {
|
731 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
732 | Error.captureStackTrace(error, this.autoScaleWriteCapacity);
|
733 | }
|
734 | throw error;
|
735 | }
|
736 | if (this.tableScaling.scalableWriteAttribute) {
|
737 | throw new Error('Write AutoScaling already enabled for this table');
|
738 | }
|
739 | if (this.billingMode === BillingMode.PAY_PER_REQUEST) {
|
740 | throw new Error('AutoScaling is not available for tables with PAY_PER_REQUEST billing mode');
|
741 | }
|
742 | this.tableScaling.scalableWriteAttribute = new scalable_table_attribute_1.ScalableTableAttribute(this, 'WriteScaling', {
|
743 | serviceNamespace: appscaling.ServiceNamespace.DYNAMODB,
|
744 | resourceId: `table/${this.tableName}`,
|
745 | dimension: 'dynamodb:table:WriteCapacityUnits',
|
746 | role: this.scalingRole,
|
747 | ...props,
|
748 | });
|
749 | for (const globalReplicaCustomResource of this.globalReplicaCustomResources) {
|
750 | globalReplicaCustomResource.node.addDependency(this.tableScaling.scalableWriteAttribute);
|
751 | }
|
752 | return this.tableScaling.scalableWriteAttribute;
|
753 | }
|
754 | /**
|
755 | * Enable read capacity scaling for the given GSI
|
756 | *
|
757 | * @returns An object to configure additional AutoScaling settings for this attribute
|
758 | */
|
759 | autoScaleGlobalSecondaryIndexReadCapacity(indexName, props) {
|
760 | try {
|
761 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_EnableScalingProps(props);
|
762 | }
|
763 | catch (error) {
|
764 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
765 | Error.captureStackTrace(error, this.autoScaleGlobalSecondaryIndexReadCapacity);
|
766 | }
|
767 | throw error;
|
768 | }
|
769 | if (this.billingMode === BillingMode.PAY_PER_REQUEST) {
|
770 | throw new Error('AutoScaling is not available for tables with PAY_PER_REQUEST billing mode');
|
771 | }
|
772 | const attributePair = this.indexScaling.get(indexName);
|
773 | if (!attributePair) {
|
774 | throw new Error(`No global secondary index with name ${indexName}`);
|
775 | }
|
776 | if (attributePair.scalableReadAttribute) {
|
777 | throw new Error('Read AutoScaling already enabled for this index');
|
778 | }
|
779 | return attributePair.scalableReadAttribute = new scalable_table_attribute_1.ScalableTableAttribute(this, `${indexName}ReadScaling`, {
|
780 | serviceNamespace: appscaling.ServiceNamespace.DYNAMODB,
|
781 | resourceId: `table/${this.tableName}/index/${indexName}`,
|
782 | dimension: 'dynamodb:index:ReadCapacityUnits',
|
783 | role: this.scalingRole,
|
784 | ...props,
|
785 | });
|
786 | }
|
787 | /**
|
788 | * Enable write capacity scaling for the given GSI
|
789 | *
|
790 | * @returns An object to configure additional AutoScaling settings for this attribute
|
791 | */
|
792 | autoScaleGlobalSecondaryIndexWriteCapacity(indexName, props) {
|
793 | try {
|
794 | jsiiDeprecationWarnings._aws_cdk_aws_dynamodb_EnableScalingProps(props);
|
795 | }
|
796 | catch (error) {
|
797 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
798 | Error.captureStackTrace(error, this.autoScaleGlobalSecondaryIndexWriteCapacity);
|
799 | }
|
800 | throw error;
|
801 | }
|
802 | if (this.billingMode === BillingMode.PAY_PER_REQUEST) {
|
803 | throw new Error('AutoScaling is not available for tables with PAY_PER_REQUEST billing mode');
|
804 | }
|
805 | const attributePair = this.indexScaling.get(indexName);
|
806 | if (!attributePair) {
|
807 | throw new Error(`No global secondary index with name ${indexName}`);
|
808 | }
|
809 | if (attributePair.scalableWriteAttribute) {
|
810 | throw new Error('Write AutoScaling already enabled for this index');
|
811 | }
|
812 | return attributePair.scalableWriteAttribute = new scalable_table_attribute_1.ScalableTableAttribute(this, `${indexName}WriteScaling`, {
|
813 | serviceNamespace: appscaling.ServiceNamespace.DYNAMODB,
|
814 | resourceId: `table/${this.tableName}/index/${indexName}`,
|
815 | dimension: 'dynamodb:index:WriteCapacityUnits',
|
816 | role: this.scalingRole,
|
817 | ...props,
|
818 | });
|
819 | }
|
820 | /**
|
821 | * Get schema attributes of table or index.
|
822 | *
|
823 | * @returns Schema of table or index.
|
824 | */
|
825 | schema(indexName) {
|
826 | if (!indexName) {
|
827 | return {
|
828 | partitionKey: this.tablePartitionKey,
|
829 | sortKey: this.tableSortKey,
|
830 | };
|
831 | }
|
832 | let schema = this.secondaryIndexSchemas.get(indexName);
|
833 | if (!schema) {
|
834 | throw new Error(`Cannot find schema for index: ${indexName}. Use 'addGlobalSecondaryIndex' or 'addLocalSecondaryIndex' to add index`);
|
835 | }
|
836 | return schema;
|
837 | }
|
838 | /**
|
839 | * Validate the table construct.
|
840 | *
|
841 | * @returns an array of validation error message
|
842 | */
|
843 | validate() {
|
844 | const errors = new Array();
|
845 | if (!this.tablePartitionKey) {
|
846 | errors.push('a partition key must be specified');
|
847 | }
|
848 | if (this.localSecondaryIndexes.length > 0 && !this.tableSortKey) {
|
849 | errors.push('a sort key of the table must be specified to add local secondary indexes');
|
850 | }
|
851 | if (this.globalReplicaCustomResources.length > 0 && this.billingMode === BillingMode.PROVISIONED) {
|
852 | const writeAutoScaleAttribute = this.tableScaling.scalableWriteAttribute;
|
853 | if (!writeAutoScaleAttribute) {
|
854 | errors.push('A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity. ' +
|
855 | 'Use the autoScaleWriteCapacity() method to enable it.');
|
856 | }
|
857 | else if (!writeAutoScaleAttribute._scalingPolicyCreated) {
|
858 | errors.push('A global Table that uses PROVISIONED as the billing mode needs auto-scaled write capacity with a policy. ' +
|
859 | 'Call one of the scaleOn*() methods of the object returned from autoScaleWriteCapacity()');
|
860 | }
|
861 | }
|
862 | return errors;
|
863 | }
|
864 | /**
|
865 | * Validate read and write capacity are not specified for on-demand tables (billing mode PAY_PER_REQUEST).
|
866 | *
|
867 | * @param props read and write capacity properties
|
868 | */
|
869 | validateProvisioning(props) {
|
870 | if (this.billingMode === BillingMode.PAY_PER_REQUEST) {
|
871 | if (props.readCapacity !== undefined || props.writeCapacity !== undefined) {
|
872 | throw new Error('you cannot provision read and write capacity for a table with PAY_PER_REQUEST billing mode');
|
873 | }
|
874 | }
|
875 | }
|
876 | /**
|
877 | * Validate index name to check if a duplicate name already exists.
|
878 | *
|
879 | * @param indexName a name of global or local secondary index
|
880 | */
|
881 | validateIndexName(indexName) {
|
882 | if (this.secondaryIndexSchemas.has(indexName)) {
|
883 | // a duplicate index name causes validation exception, status code 400, while trying to create CFN stack
|
884 | throw new Error(`a duplicate index name, ${indexName}, is not allowed`);
|
885 | }
|
886 | }
|
887 | /**
|
888 | * Validate non-key attributes by checking limits within secondary index, which may vary in future.
|
889 | *
|
890 | * @param nonKeyAttributes a list of non-key attribute names
|
891 | */
|
892 | validateNonKeyAttributes(nonKeyAttributes) {
|
893 | if (this.nonKeyAttributes.size + nonKeyAttributes.length > 100) {
|
894 | // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-secondary-indexes
|
895 | throw new RangeError('a maximum number of nonKeyAttributes across all of secondary indexes is 100');
|
896 | }
|
897 | // store all non-key attributes
|
898 | nonKeyAttributes.forEach(att => this.nonKeyAttributes.add(att));
|
899 | }
|
900 | buildIndexKeySchema(partitionKey, sortKey) {
|
901 | this.registerAttribute(partitionKey);
|
902 | const indexKeySchema = [
|
903 | { attributeName: partitionKey.name, keyType: HASH_KEY_TYPE },
|
904 | ];
|
905 | if (sortKey) {
|
906 | this.registerAttribute(sortKey);
|
907 | indexKeySchema.push({ attributeName: sortKey.name, keyType: RANGE_KEY_TYPE });
|
908 | }
|
909 | return indexKeySchema;
|
910 | }
|
911 | buildIndexProjection(props) {
|
912 | var _b, _c;
|
913 | if (props.projectionType === ProjectionType.INCLUDE && !props.nonKeyAttributes) {
|
914 | // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-projectionobject.html
|
915 | throw new Error(`non-key attributes should be specified when using ${ProjectionType.INCLUDE} projection type`);
|
916 | }
|
917 | if (props.projectionType !== ProjectionType.INCLUDE && props.nonKeyAttributes) {
|
918 | // this combination causes validation exception, status code 400, while trying to create CFN stack
|
919 | throw new Error(`non-key attributes should not be specified when not using ${ProjectionType.INCLUDE} projection type`);
|
920 | }
|
921 | if (props.nonKeyAttributes) {
|
922 | this.validateNonKeyAttributes(props.nonKeyAttributes);
|
923 | }
|
924 | return {
|
925 | projectionType: (_b = props.projectionType) !== null && _b !== void 0 ? _b : ProjectionType.ALL,
|
926 | nonKeyAttributes: (_c = props.nonKeyAttributes) !== null && _c !== void 0 ? _c : undefined,
|
927 | };
|
928 | }
|
929 | findKey(keyType) {
|
930 | return this.keySchema.find(prop => prop.keyType === keyType);
|
931 | }
|
932 | addKey(attribute, keyType) {
|
933 | const existingProp = this.findKey(keyType);
|
934 | if (existingProp) {
|
935 | throw new Error(`Unable to set ${attribute.name} as a ${keyType} key, because ${existingProp.attributeName} is a ${keyType} key`);
|
936 | }
|
937 | this.registerAttribute(attribute);
|
938 | this.keySchema.push({
|
939 | attributeName: attribute.name,
|
940 | keyType,
|
941 | });
|
942 | return this;
|
943 | }
|
944 | /**
|
945 | * Register the key attribute of table or secondary index to assemble attribute definitions of TableResourceProps.
|
946 | *
|
947 | * @param attribute the key attribute of table or secondary index
|
948 | */
|
949 | registerAttribute(attribute) {
|
950 | const { name, type } = attribute;
|
951 | const existingDef = this.attributeDefinitions.find(def => def.attributeName === name);
|
952 | if (existingDef && existingDef.attributeType !== type) {
|
953 | throw new Error(`Unable to specify ${name} as ${type} because it was already defined as ${existingDef.attributeType}`);
|
954 | }
|
955 | if (!existingDef) {
|
956 | this.attributeDefinitions.push({
|
957 | attributeName: name,
|
958 | attributeType: type,
|
959 | });
|
960 | }
|
961 | }
|
962 | /**
|
963 | * Return the role that will be used for AutoScaling
|
964 | */
|
965 | makeScalingRole() {
|
966 | // Use a Service Linked Role.
|
967 | // https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html
|
968 | return iam.Role.fromRoleArn(this, 'ScalingRole', core_1.Stack.of(this).formatArn({
|
969 | service: 'iam',
|
970 | region: '',
|
971 | resource: 'role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com',
|
972 | resourceName: 'AWSServiceRoleForApplicationAutoScaling_DynamoDBTable',
|
973 | }));
|
974 | }
|
975 | /**
|
976 | * Creates replica tables
|
977 | *
|
978 | * @param regions regions where to create tables
|
979 | */
|
980 | createReplicaTables(regions, timeout, waitForReplicationToFinish) {
|
981 | const stack = core_1.Stack.of(this);
|
982 | if (!core_1.Token.isUnresolved(stack.region) && regions.includes(stack.region)) {
|
983 | throw new Error('`replicationRegions` cannot include the region where this stack is deployed.');
|
984 | }
|
985 | const provider = replica_provider_1.ReplicaProvider.getOrCreate(this, { timeout });
|
986 | // Documentation at https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2gt_IAM.html
|
987 | // is currently incorrect. AWS Support recommends `dynamodb:*` in both source and destination regions
|
988 | const onEventHandlerPolicy = new SourceTableAttachedPolicy(this, provider.onEventHandler.role);
|
989 | const isCompleteHandlerPolicy = new SourceTableAttachedPolicy(this, provider.isCompleteHandler.role);
|
990 | // Permissions in the source region
|
991 | this.grant(onEventHandlerPolicy, 'dynamodb:*');
|
992 | this.grant(isCompleteHandlerPolicy, 'dynamodb:DescribeTable');
|
993 | let previousRegion;
|
994 | let previousRegionCondition;
|
995 | for (const region of new Set(regions)) { // Remove duplicates
|
996 | // Use multiple custom resources because multiple create/delete
|
997 | // updates cannot be combined in a single API call.
|
998 | const currentRegion = new core_1.CustomResource(this, `Replica${region}`, {
|
999 | serviceToken: provider.provider.serviceToken,
|
1000 | resourceType: 'Custom::DynamoDBReplica',
|
1001 | properties: {
|
1002 | TableName: this.tableName,
|
1003 | Region: region,
|
1004 | SkipReplicationCompletedWait: waitForReplicationToFinish == null
|
1005 | ? undefined
|
1006 | // CFN changes Custom Resource properties to strings anyways,
|
1007 | // so let's do that ourselves to make it clear in the handler this is a string, not a boolean
|
1008 | : (!waitForReplicationToFinish).toString(),
|
1009 | },
|
1010 | });
|
1011 | currentRegion.node.addDependency(onEventHandlerPolicy.policy, isCompleteHandlerPolicy.policy);
|
1012 | this.globalReplicaCustomResources.push(currentRegion);
|
1013 | // Deploy time check to prevent from creating a replica in the region
|
1014 | // where this stack is deployed. Only needed for environment agnostic
|
1015 | // stacks.
|
1016 | let createReplica;
|
1017 | if (core_1.Token.isUnresolved(stack.region)) {
|
1018 | createReplica = new core_1.CfnCondition(this, `StackRegionNotEquals${region}`, {
|
1019 | expression: core_1.Fn.conditionNot(core_1.Fn.conditionEquals(region, core_1.Aws.REGION)),
|
1020 | });
|
1021 | const cfnCustomResource = currentRegion.node.defaultChild;
|
1022 | cfnCustomResource.cfnOptions.condition = createReplica;
|
1023 | }
|
1024 | // Save regional arns for grantXxx() methods
|
1025 | this.regionalArns.push(stack.formatArn({
|
1026 | region,
|
1027 | service: 'dynamodb',
|
1028 | resource: 'table',
|
1029 | resourceName: this.tableName,
|
1030 | }));
|
1031 | // We need to create/delete regions sequentially because we cannot
|
1032 | // have multiple table updates at the same time. The `isCompleteHandler`
|
1033 | // of the provider waits until the replica is in an ACTIVE state.
|
1034 | if (previousRegion) {
|
1035 | if (previousRegionCondition) {
|
1036 | // we can't simply use a Dependency,
|
1037 | // because the previousRegion is protected by the "different region" Condition,
|
1038 | // and you can't have Fn::If in DependsOn.
|
1039 | // Instead, rely on Ref adding a dependency implicitly!
|
1040 | const previousRegionCfnResource = previousRegion.node.defaultChild;
|
1041 | const currentRegionCfnResource = currentRegion.node.defaultChild;
|
1042 | currentRegionCfnResource.addMetadata('DynamoDbReplicationDependency', core_1.Fn.conditionIf(previousRegionCondition.logicalId, previousRegionCfnResource.ref, core_1.Aws.NO_VALUE));
|
1043 | }
|
1044 | else {
|
1045 | currentRegion.node.addDependency(previousRegion);
|
1046 | }
|
1047 | }
|
1048 | previousRegion = currentRegion;
|
1049 | previousRegionCondition = createReplica;
|
1050 | }
|
1051 | // Permissions in the destination regions (outside of the loop to
|
1052 | // minimize statements in the policy)
|
1053 | onEventHandlerPolicy.grantPrincipal.addToPrincipalPolicy(new iam.PolicyStatement({
|
1054 | actions: ['dynamodb:*'],
|
1055 | resources: this.regionalArns,
|
1056 | }));
|
1057 | }
|
1058 | /**
|
1059 | * Whether this table has indexes
|
1060 | */
|
1061 | get hasIndex() {
|
1062 | return this.globalSecondaryIndexes.length + this.localSecondaryIndexes.length > 0;
|
1063 | }
|
1064 | /**
|
1065 | * Set up key properties and return the Table encryption property from the
|
1066 | * user's configuration.
|
1067 | */
|
1068 | parseEncryption(props) {
|
1069 | var _b;
|
1070 | let encryptionType = props.encryption;
|
1071 | if (encryptionType != null && props.serverSideEncryption != null) {
|
1072 | throw new Error('Only one of encryption and serverSideEncryption can be specified, but both were provided');
|
1073 | }
|
1074 | if (props.serverSideEncryption && props.encryptionKey) {
|
1075 | throw new Error('encryptionKey cannot be specified when serverSideEncryption is specified. Use encryption instead');
|
1076 | }
|
1077 | if (encryptionType === undefined) {
|
1078 | encryptionType = props.encryptionKey != null
|
1079 | // If there is a configured encryptionKey, the encryption is implicitly CUSTOMER_MANAGED
|
1080 | ? TableEncryption.CUSTOMER_MANAGED
|
1081 | // Otherwise, if severSideEncryption is enabled, it's AWS_MANAGED; else undefined (do not set anything)
|
1082 | : props.serverSideEncryption ? TableEncryption.AWS_MANAGED : undefined;
|
1083 | }
|
1084 | if (encryptionType !== TableEncryption.CUSTOMER_MANAGED && props.encryptionKey) {
|
1085 | throw new Error('`encryptionKey cannot be specified unless encryption is set to TableEncryption.CUSTOMER_MANAGED (it was set to ${encryptionType})`');
|
1086 | }
|
1087 | if (encryptionType === TableEncryption.CUSTOMER_MANAGED && props.replicationRegions) {
|
1088 | throw new Error('TableEncryption.CUSTOMER_MANAGED is not supported by DynamoDB Global Tables (where replicationRegions was set)');
|
1089 | }
|
1090 | switch (encryptionType) {
|
1091 | case TableEncryption.CUSTOMER_MANAGED:
|
1092 | const encryptionKey = (_b = props.encryptionKey) !== null && _b !== void 0 ? _b : new kms.Key(this, 'Key', {
|
1093 | description: `Customer-managed key auto-created for encrypting DynamoDB table at ${this.node.path}`,
|
1094 | enableKeyRotation: true,
|
1095 | });
|
1096 | return {
|
1097 | sseSpecification: { sseEnabled: true, kmsMasterKeyId: encryptionKey.keyArn, sseType: 'KMS' },
|
1098 | encryptionKey,
|
1099 | };
|
1100 | case TableEncryption.AWS_MANAGED:
|
1101 | // Not specifying "sseType: 'KMS'" here because it would cause phony changes to existing stacks.
|
1102 | return { sseSpecification: { sseEnabled: true } };
|
1103 | case TableEncryption.DEFAULT:
|
1104 | return { sseSpecification: { sseEnabled: false } };
|
1105 | case undefined:
|
1106 | // Not specifying "sseEnabled: false" here because it would cause phony changes to existing stacks.
|
1107 | return { sseSpecification: undefined };
|
1108 | default:
|
1109 | throw new Error(`Unexpected 'encryptionType': ${encryptionType}`);
|
1110 | }
|
1111 | }
|
1112 | }
|
1113 | exports.Table = Table;
|
1114 | _a = JSII_RTTI_SYMBOL_1;
|
1115 | Table[_a] = { fqn: "@aws-cdk/aws-dynamodb.Table", version: "1.156.0" };
|
1116 | /**
|
1117 | * Data types for attributes within a table
|
1118 | *
|
1119 | * @see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes
|
1120 | */
|
1121 | var AttributeType;
|
1122 | (function (AttributeType) {
|
1123 | /** Up to 400KiB of binary data (which must be encoded as base64 before sending to DynamoDB) */
|
1124 | AttributeType["BINARY"] = "B";
|
1125 | /** Numeric values made of up to 38 digits (positive, negative or zero) */
|
1126 | AttributeType["NUMBER"] = "N";
|
1127 | /** Up to 400KiB of UTF-8 encoded text */
|
1128 | AttributeType["STRING"] = "S";
|
1129 | })(AttributeType = exports.AttributeType || (exports.AttributeType = {}));
|
1130 | /**
|
1131 | * DynamoDB's Read/Write capacity modes.
|
1132 | */
|
1133 | var BillingMode;
|
1134 | (function (BillingMode) {
|
1135 | /**
|
1136 | * Pay only for what you use. You don't configure Read/Write capacity units.
|
1137 | */
|
1138 | BillingMode["PAY_PER_REQUEST"] = "PAY_PER_REQUEST";
|
1139 | /**
|
1140 | * Explicitly specified Read/Write capacity units.
|
1141 | */
|
1142 | BillingMode["PROVISIONED"] = "PROVISIONED";
|
1143 | })(BillingMode = exports.BillingMode || (exports.BillingMode = {}));
|
1144 | /**
|
1145 | * The set of attributes that are projected into the index
|
1146 | *
|
1147 | * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Projection.html
|
1148 | */
|
1149 | var ProjectionType;
|
1150 | (function (ProjectionType) {
|
1151 | /** Only the index and primary keys are projected into the index. */
|
1152 | ProjectionType["KEYS_ONLY"] = "KEYS_ONLY";
|
1153 | /** Only the specified table attributes are projected into the index. The list of projected attributes is in `nonKeyAttributes`. */
|
1154 | ProjectionType["INCLUDE"] = "INCLUDE";
|
1155 | /** All of the table attributes are projected into the index. */
|
1156 | ProjectionType["ALL"] = "ALL";
|
1157 | })(ProjectionType = exports.ProjectionType || (exports.ProjectionType = {}));
|
1158 | /**
|
1159 | * When an item in the table is modified, StreamViewType determines what information
|
1160 | * is written to the stream for this table.
|
1161 | *
|
1162 | * @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_StreamSpecification.html
|
1163 | */
|
1164 | var StreamViewType;
|
1165 | (function (StreamViewType) {
|
1166 | /** The entire item, as it appears after it was modified, is written to the stream. */
|
1167 | StreamViewType["NEW_IMAGE"] = "NEW_IMAGE";
|
1168 | /** The entire item, as it appeared before it was modified, is written to the stream. */
|
1169 | StreamViewType["OLD_IMAGE"] = "OLD_IMAGE";
|
1170 | /** Both the new and the old item images of the item are written to the stream. */
|
1171 | StreamViewType["NEW_AND_OLD_IMAGES"] = "NEW_AND_OLD_IMAGES";
|
1172 | /** Only the key attributes of the modified item are written to the stream. */
|
1173 | StreamViewType["KEYS_ONLY"] = "KEYS_ONLY";
|
1174 | })(StreamViewType = exports.StreamViewType || (exports.StreamViewType = {}));
|
1175 | /**
|
1176 | * DynamoDB's table class.
|
1177 | *
|
1178 | * @see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.TableClasses.html
|
1179 | */
|
1180 | var TableClass;
|
1181 | (function (TableClass) {
|
1182 | /** Default table class for DynamoDB. */
|
1183 | TableClass["STANDARD"] = "STANDARD";
|
1184 | /** Table class for DynamoDB that reduces storage costs compared to existing DynamoDB Standard tables. */
|
1185 | TableClass["STANDARD_INFREQUENT_ACCESS"] = "STANDARD_INFREQUENT_ACCESS";
|
1186 | })(TableClass = exports.TableClass || (exports.TableClass = {}));
|
1187 | /**
|
1188 | * An inline policy that is logically bound to the source table of a DynamoDB Global Tables
|
1189 | * "cluster". This is here to ensure permissions are removed as part of (and not before) the
|
1190 | * CleanUp phase of a stack update, when a replica is removed (or the entire "cluster" gets
|
1191 | * replaced).
|
1192 | *
|
1193 | * If statements are added directly to the handler roles (as opposed to in a separate inline
|
1194 | * policy resource), new permissions are in effect before clean up happens, and so replicas that
|
1195 | * need to be dropped can no longer be due to lack of permissions.
|
1196 | */
|
1197 | class SourceTableAttachedPolicy extends core_2.Construct {
|
1198 | constructor(sourceTable, role) {
|
1199 | super(sourceTable, `SourceTableAttachedManagedPolicy-${core_1.Names.nodeUniqueId(role.node)}`);
|
1200 | const policy = new iam.ManagedPolicy(this, 'Resource', {
|
1201 | // A CF update of the description property of a managed policy requires
|
1202 | // a replacement. Use the table name in the description to force a managed
|
1203 | // policy replacement when the table name changes. This way we preserve permissions
|
1204 | // to delete old replicas in case of a table replacement.
|
1205 | description: `DynamoDB replication managed policy for table ${sourceTable.tableName}`,
|
1206 | roles: [role],
|
1207 | });
|
1208 | this.policy = policy;
|
1209 | this.grantPrincipal = new SourceTableAttachedPrincipal(role, policy);
|
1210 | }
|
1211 | }
|
1212 | /**
|
1213 | * An `IPrincipal` entity that can be used as the target of `grant` calls, used by the
|
1214 | * `SourceTableAttachedPolicy` class so it can act as an `IGrantable`.
|
1215 | */
|
1216 | class SourceTableAttachedPrincipal extends iam.PrincipalBase {
|
1217 | constructor(role, policy) {
|
1218 | super();
|
1219 | this.role = role;
|
1220 | this.policy = policy;
|
1221 | }
|
1222 | get policyFragment() {
|
1223 | return this.role.policyFragment;
|
1224 | }
|
1225 | addToPrincipalPolicy(statement) {
|
1226 | this.policy.addStatements(statement);
|
1227 | return {
|
1228 | policyDependable: this.policy,
|
1229 | statementAdded: true,
|
1230 | };
|
1231 | }
|
1232 | }
|
1233 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0YWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxrRUFBa0U7QUFDbEUsc0RBQXNEO0FBQ3RELHdDQUF3QztBQUV4Qyx3Q0FBd0M7QUFDeEMsd0NBSXVCO0FBRXZCLDJGQUFzRTtBQUN0RSw2REFBK0Q7QUFDL0QsaUNBQWlDO0FBQ2pDLHlEQUFxRDtBQUVyRCx5RUFBb0U7QUFFcEUsaUdBQWlHO0FBQ2pHLDhEQUE4RDtBQUM5RCx3Q0FBMkQ7QUFFM0QsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDO0FBQzdCLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQztBQUUvQix3R0FBd0c7QUFDeEcsTUFBTSwrQkFBK0IsR0FBRyxDQUFDLENBQUM7QUFnQjFDOztHQUVHO0FBQ0gsSUFBWSxTQTRDWDtBQTVDRCxXQUFZLFNBQVM7SUFFbkIsY0FBYztJQUNkLGlDQUFvQixDQUFBO0lBRXBCLG1CQUFtQjtJQUNuQiw0Q0FBK0IsQ0FBQTtJQUUvQixXQUFXO0lBQ1gsMEJBQWEsQ0FBQTtJQUViLFlBQVk7SUFDWiw0QkFBZSxDQUFBO0lBRWYsaUJBQWlCO0lBQ2pCLHVDQUEwQixDQUFBO0lBRTFCLGNBQWM7SUFDZCxpQ0FBb0IsQ0FBQTtJQUVwQixpQkFBaUI7SUFDakIsdUNBQTBCLENBQUE7SUFFMUIsaUJBQWlCO0lBQ2pCLHVDQUEwQixDQUFBO0lBRTFCLHFCQUFxQjtJQUNyQixnREFBbUMsQ0FBQTtJQUVuQyx5QkFBeUI7SUFDekIsd0RBQTJDLENBQUE7SUFFM0MsdUJBQXVCO0lBQ3ZCLG9EQUF1QyxDQUFBO0lBRXZDLHlCQUF5QjtJQUN6Qix1REFBMEMsQ0FBQTtJQUUxQyw0QkFBNEI7SUFDNUIsOERBQWlELENBQUE7SUFFakQsdUJBQXVCO0lBQ3ZCLG1EQUFzQyxDQUFBO0FBRXhDLENBQUMsRUE1Q1csU0FBUyxHQUFULGlCQUFTLEtBQVQsaUJBQVMsUUE0Q3BCO0FBa0JEOztHQUVH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RSxDQUFDLENBQUM7UUFFeEYsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7WUFDckQsdUVBQXVFO1lBQ3ZFLDBFQUEwRTtZQUMxRSxtRkFBbUY7WUFDbkYseURBQXlEO1lBQ3pELFdBQVcsRUFBRSxpREFBaUQsV0FBVyxDQUFDLFNBQVMsRUFBRTtZQUNyRixLQUFLLEVBQUUsQ0FBQyxJQUFJLENBQUM7U0FDZCxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksNEJBQTRCLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0tBQ3RFO0NBQ0Y7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLDRCQUE2QixTQUFRLEdBQUcsQ0FBQyxhQUFhO0lBQzFELFlBQW9DLElBQWUsRUFBbUIsTUFBeUI7UUFDN0YsS0FBSyxFQUFFLENBQUM7UUFEMEIsU0FBSSxHQUFKLElBQUksQ0FBVztRQUFtQixXQUFNLEdBQU4sTUFBTSxDQUFtQjtLQUU5RjtJQUVELElBQVcsY0FBYztRQUN2QixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDO0tBQ2pDO0lBRU0sb0JBQW9CLENBQUMsU0FBOEI7UUFDeEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDckMsT0FBTztZQUNMLGdCQUFnQixFQUFFLElBQUksQ0FBQyxNQUFNO1lBQzdCLGNBQWMsRUFBRSxJQUFJO1NBQ3JCLENBQUM7S0FDSDtDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgYXBwc2NhbGluZyBmcm9tICdAYXdzLWNkay9hd3MtYXBwbGljYXRpb25hdXRvc2NhbGluZyc7XG5pbXBvcnQgKiBhcyBjbG91ZHdhdGNoIGZyb20gJ0Bhd3MtY2RrL2F3cy1jbG91ZHdhdGNoJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdAYXdzLWNkay9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGtpbmVzaXMgZnJvbSAnQGF3cy1jZGsvYXdzLWtpbmVzaXMnO1xuaW1wb3J0ICogYXMga21zIGZyb20gJ0Bhd3MtY2RrL2F3cy1rbXMnO1xuaW1wb3J0IHtcbiAgQXJuRm9ybWF0LFxuICBBd3MsIENmbkNvbmRpdGlvbiwgQ2ZuQ3VzdG9tUmVzb3VyY2UsIENmblJlc291cmNlLCBDdXN0b21SZXNvdXJjZSwgRHVyYXRpb24sXG4gIEZuLCBJUmVzb3VyY2UsIExhenksIE5hbWVzLCBSZW1vdmFsUG9saWN5LCBSZXNvdXJjZSwgU3RhY2ssIFRva2VuLFxufSBmcm9tICdAYXdzLWNkay9jb3JlJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgRHluYW1vREJNZXRyaWNzIH0gZnJvbSAnLi9keW5hbW9kYi1jYW5uZWQtbWV0cmljcy5nZW5lcmF0ZWQnO1xuaW1wb3J0IHsgQ2ZuVGFibGUsIENmblRhYmxlUHJvcHMgfSBmcm9tICcuL2R5bmFtb2RiLmdlbmVyYXRlZCc7XG5pbXBvcnQgKiBhcyBwZXJtcyBmcm9tICcuL3Blcm1zJztcbmltcG9ydCB7IFJlcGxpY2FQcm92aWRlciB9IGZyb20gJy4vcmVwbGljYS1wcm92aWRlcic7XG5pbXBvcnQgeyBFbmFibGVTY2FsaW5nUHJvcHMsIElTY2FsYWJsZVRhYmxlQXR0cmlidXRlIH0gZnJvbSAnLi9zY2FsYWJsZS1hdHRyaWJ1dGUtYXBpJztcbmltcG9ydCB7IFNjYWxhYmxlVGFibGVBdHRyaWJ1dGUgfSBmcm9tICcuL3NjYWxhYmxlLXRhYmxlLWF0dHJpYnV0ZSc7XG5cbi8vIGtlZXAgdGhpcyBpbXBvcnQgc2VwYXJhdGUgZnJvbSBvdGhlciBpbXBvcnRzIHRvIHJlZHVjZSBjaGFuY2UgZm9yIG1lcmdlIGNvbmZsaWN0cyB3aXRoIHYyLW1haW5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1kdXBsaWNhdGUtaW1wb3J0cywgaW1wb3J0L29yZGVyXG5pbXBvcnQgeyBDb25zdHJ1Y3QgYXMgQ29yZUNvbnN0cnVjdCB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuXG5jb25zdCBIQVNIX0tFWV9UWVBFID0gJ0hBU0gnO1xuY29uc3QgUkFOR0VfS0VZX1RZUEUgPSAnUkFOR0UnO1xuXG4vLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vYW1hem9uZHluYW1vZGIvbGF0ZXN0L2RldmVsb3Blcmd1aWRlL0xpbWl0cy5odG1sI2xpbWl0cy1zZWNvbmRhcnktaW5kZXhlc1xuY29uc3QgTUFYX0xPQ0FMX1NFQ09OREFSWV9JTkRFWF9DT1VOVCA9IDU7XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgY29uZmlndXJpbmcgYSBzeXN0ZW0gZXJyb3JzIG1ldHJpYyB0aGF0IGNvbnNpZGVycyBtdWx0aXBsZSBvcGVyYXRpb25zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN5c3RlbUVycm9yc0Zvck9wZXJhdGlvbnNNZXRyaWNPcHRpb25zIGV4dGVuZHMgY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zIHtcblxuICAvKipcbiAgICogVGhlIG9wZXJhdGlvbnMgdG8gYXBwbHkgdGhlIG1ldHJpYyB0by5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBbGwgb3BlcmF0aW9ucyBhdmFpbGFibGUgYnkgRHluYW1vREIgdGFibGVzIHdpbGwgYmUgY29uc2lkZXJlZC5cbiAgICovXG4gIHJlYWRvbmx5IG9wZXJhdGlvbnM/OiBPcGVyYXRpb25bXTtcblxufVxuXG4vKipcbiAqIFN1cHBvcnRlZCBEeW5hbW9EQiB0YWJsZSBvcGVyYXRpb25zLlxuICovXG5leHBvcnQgZW51bSBPcGVyYXRpb24ge1xuXG4gIC8qKiBHZXRJdGVtICovXG4gIEdFVF9JVEVNID0gJ0dldEl0ZW0nLFxuXG4gIC8qKiBCYXRjaEdldEl0ZW0gKi9cbiAgQkFUQ0hfR0VUX0lURU0gPSAnQmF0Y2hHZXRJdGVtJyxcblxuICAvKiogU2NhbiAqL1xuICBTQ0FOID0gJ1NjYW4nLFxuXG4gIC8qKiBRdWVyeSAqL1xuICBRVUVSWSA9ICdRdWVyeScsXG5cbiAgLyoqIEdldFJlY29yZHMgKi9cbiAgR0VUX1JFQ09SRFMgPSAnR2V0UmVjb3JkcycsXG5cbiAgLyoqIFB1dEl0ZW0gKi9cbiAgUFVUX0lURU0gPSAnUHV0SXRlbScsXG5cbiAgLyoqIERlbGV0ZUl0ZW0gKi9cbiAgREVMRVRFX0lURU0gPSAnRGVsZXRlSXRlbScsXG5cbiAgLyoqIFVwZGF0ZUl0ZW0gKi9cbiAgVVBEQVRFX0lURU0gPSAnVXBkYXRlSXRlbScsXG5cbiAgLyoqIEJhdGNoV3JpdGVJdGVtICovXG4gIEJBVENIX1dSSVRFX0lURU0gPSAnQmF0Y2hXcml0ZUl0ZW0nLFxuXG4gIC8qKiBUcmFuc2FjdFdyaXRlSXRlbXMgKi9cbiAgVFJBTlNBQ1RfV1JJVEVfSVRFTVMgPSAnVHJhbnNhY3RXcml0ZUl0ZW1zJyxcblxuICAvKiogVHJhbnNhY3RHZXRJdGVtcyAqL1xuICBUUkFOU0FDVF9HRVRfSVRFTVMgPSAnVHJhbnNhY3RHZXRJdGVtcycsXG5cbiAgLyoqIEV4ZWN1dGVUcmFuc2FjdGlvbiAqL1xuICBFWEVDVVRFX1RSQU5TQUNUSU9OID0gJ0V4ZWN1dGVUcmFuc2FjdGlvbicsXG5cbiAgLyoqIEJhdGNoRXhlY3V0ZVN0YXRlbWVudCAqL1xuICBCQVRDSF9FWEVDVVRFX1NUQVRFTUVOVCA9ICdCYXRjaEV4ZWN1dGVTdGF0ZW1lbnQnLFxuXG4gIC8qKiBFeGVjdXRlU3RhdGVtZW50ICovXG4gIEVYRUNVVEVfU1RBVEVNRU5UID0gJ0V4ZWN1dGVTdGF0ZW1lbnQnLFxuXG59XG5cbi8qKlxuICogUmVwcmVzZW50cyBhbiBhdHRyaWJ1dGUgZm9yIGRlc2NyaWJpbmcgdGhlIGtleSBzY2hlbWEgZm9yIHRoZSB0YWJsZVxuICogYW5kIGluZGV4ZXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXR0cmlidXRlIHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIGFuIGF0dHJpYnV0ZS5cbiAgICovXG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRhdGEgdHlwZSBvZiBhbiBhdHRyaWJ1dGUuXG4gICAqL1xuICByZWFkb25seSB0eXBlOiBBdHRyaWJ1dGVUeXBlO1xufVxuXG4vKipcbiAqIFdoYXQga2luZCBvZiBzZXJ2ZXItc2lkZSBlbmNyeXB0aW9uIHRvIGFwcGx5IHRvIHRoaXMgdGFibGUuXG4gKi9cbmV4cG9ydCBlbnVtIFRhYmxlRW5jcnlwdGlvbiB7XG4gIC8qKlxuICAgKiBTZXJ2ZXItc2lkZSBLTVMgZW5jcnlwdGlvbiB3aXRoIGEgbWFzdGVyIGtleSBvd25lZCBieSBBV1MuXG4gICAqL1xuICBERUZBVUxUID0gJ0FXU19PV05FRCcsXG5cbiAgLyoqXG4gICAqIFNlcnZlci1zaWRlIEtNUyBlbmNyeXB0aW9uIHdpdGggYSBjdXN0b21lciBtYXN0ZXIga2V5IG1hbmFnZWQgYnkgY3VzdG9tZXIuXG4gICAqIElmIGBlbmNyeXB0aW9uS2V5YCBpcyBzcGVjaWZpZWQsIHRoaXMga2V5IHdpbGwgYmUgdXNlZCwgb3RoZXJ3aXNlLCBvbmUgd2lsbCBiZSBkZWZpbmVkLlxuICAgKlxuICAgKiA+ICoqTk9URSoqOiBpZiBgZW5jcnlwdGlvbktleWAgaXMgbm90IHNwZWNpZmllZCBhbmQgdGhlIGBUYWJsZWAgY29uc3RydWN0IGNyZWF0ZXNcbiAgICogPiBhIEtNUyBrZXkgZm9yIHlvdSwgdGhlIGtleSB3aWxsIGJlIGNyZWF0ZWQgd2l0aCBkZWZhdWx0IHBlcm1pc3Npb25zLiBJZiB5b3UgYXJlIHVzaW5nXG4gICAqID4gQ0RLdjIsIHRoZXNlIHBlcm1pc3Npb25zIHdpbGwgYmUgc3VmZmljaWVudCB0byBlbmFibGUgdGhlIGtleSBmb3IgdXNlIHdpdGggRHluYW1vREIgdGFibGVzLlxuICAgKiA+IElmIHlvdSBhcmUgdXNpbmcgQ0RLdjEsIG1ha2Ugc3VyZSB0aGUgZmVhdHVyZSBmbGFnIGBAYXdzLWNkay9hd3Mta21zOmRlZmF1bHRLZXlQb2xpY2llc2BcbiAgICogPiBpcyBzZXQgdG8gYHRydWVgIGluIHlvdXIgYGNkay5qc29uYC5cbiAgICovXG4gIENVU1RPTUVSX01BTkFHRUQgPSAnQ1VTVE9NRVJfTUFOQUdFRCcsXG5cbiAgLyoqXG4gICAqIFNlcnZlci1zaWRlIEtNUyBlbmNyeXB0aW9uIHdpdGggYSBtYXN0ZXIga2V5IG1hbmFnZWQgYnkgQVdTLlxuICAgKi9cbiAgQVdTX01BTkFHRUQgPSAnQVdTX01BTkFHRUQnLFxufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgdGhlIHRhYmxlIHNjaGVtYSBhdHRyaWJ1dGVzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNjaGVtYU9wdGlvbnMge1xuICAvKipcbiAgICogUGFydGl0aW9uIGtleSBhdHRyaWJ1dGUgZGVmaW5pdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IHBhcnRpdGlvbktleTogQXR0cmlidXRlO1xuXG4gIC8qKlxuICAgKiBTb3J0IGtleSBhdHRyaWJ1dGUgZGVmaW5pdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgbm8gc29ydCBrZXlcbiAgICovXG4gIHJlYWRvbmx5IHNvcnRLZXk/OiBBdHRyaWJ1dGU7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBvZiBhIER5bmFtb0RCIFRhYmxlXG4gKlxuICogVXNlIHtAbGluayBUYWJsZVByb3BzfSBmb3IgYWxsIHRhYmxlIHByb3BlcnRpZXNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUYWJsZU9wdGlvbnMgZXh0ZW5kcyBTY2hlbWFPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSByZWFkIGNhcGFjaXR5IGZvciB0aGUgdGFibGUuIENhcmVmdWwgaWYgeW91IGFkZCBHbG9iYWwgU2Vjb25kYXJ5IEluZGV4ZXMsIGFzXG4gICAqIHRob3NlIHdpbGwgc2hhcmUgdGhlIHRhYmxlJ3MgcHJvdmlzaW9uZWQgdGhyb3VnaHB1dC5cbiAgICpcbiAgICogQ2FuIG9ubHkgYmUgcHJvdmlkZWQgaWYgYmlsbGluZ01vZGUgaXMgUHJvdmlzaW9uZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDVcbiAgICovXG4gIHJlYWRvbmx5IHJlYWRDYXBhY2l0eT86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSB3cml0ZSBjYXBhY2l0eSBmb3IgdGhlIHRhYmxlLiBDYXJlZnVsIGlmIHlvdSBhZGQgR2xvYmFsIFNlY29uZGFyeSBJbmRleGVzLCBhc1xuICAgKiB0aG9zZSB3aWxsIHNoYXJlIHRoZSB0YWJsZSdzIHByb3Zpc2lvbmVkIHRocm91Z2hwdXQuXG4gICAqXG4gICAqIENhbiBvbmx5IGJlIHByb3ZpZGVkIGlmIGJpbGxpbmdNb2RlIGlzIFByb3Zpc2lvbmVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCA1XG4gICAqL1xuICByZWFkb25seSB3cml0ZUNhcGFjaXR5PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBTcGVjaWZ5IGhvdyB5b3UgYXJlIGNoYXJnZWQgZm9yIHJlYWQgYW5kIHdyaXRlIHRocm91Z2hwdXQgYW5kIGhvdyB5b3UgbWFuYWdlIGNhcGFjaXR5LlxuICAgKlxuICAgKiBAZGVmYXVsdCBQUk9WSVNJT05FRCBpZiBgcmVwbGljYXRpb25SZWdpb25zYCBpcyBub3Qgc3BlY2lmaWVkLCBQQVlfUEVSX1JFUVVFU1Qgb3RoZXJ3aXNlXG4gICAqL1xuICByZWFkb25seSBiaWxsaW5nTW9kZT86IEJpbGxpbmdNb2RlO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHBvaW50LWluLXRpbWUgcmVjb3ZlcnkgaXMgZW5hYmxlZC5cbiAgICogQGRlZmF1bHQgLSBwb2ludC1pbi10aW1lIHJlY292ZXJ5IGlzIGRpc2FibGVkXG4gICAqL1xuICByZWFkb25seSBwb2ludEluVGltZVJlY292ZXJ5PzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciBzZXJ2ZXItc2lkZSBlbmNyeXB0aW9uIHdpdGggYW4gQVdTIG1hbmFnZWQgY3VzdG9tZXIgbWFzdGVyIGtleSBpcyBlbmFibGVkLlxuICAgKlxuICAgKiBUaGlzIHByb3BlcnR5IGNhbm5vdCBiZSBzZXQgaWYgYGVuY3J5cHRpb25gIGFuZC9vciBgZW5jcnlwdGlvbktleWAgaXMgc2V0LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHNlcnZlci1zaWRlIGVuY3J5cHRpb24gaXMgZW5hYmxlZCB3aXRoIGFuIEFXUyBvd25lZCBjdXN0b21lciBtYXN0ZXIga2V5XG4gICAqXG4gICAqIEBkZXByZWNhdGVkIFRoaXMgcHJvcGVydHkgaXMgZGVwcmVjYXRlZC4gSW4gb3JkZXIgdG8gb2J0YWluIHRoZSBzYW1lIGJlaGF2aW9yIGFzXG4gICAqIGVuYWJsaW5nIHRoaXMsIHNldCB0aGUgYGVuY3J5cHRpb25gIHByb3BlcnR5IHRvIGBUYWJsZUVuY3J5cHRpb24uQVdTX01BTkFHRURgIGluc3RlYWQuXG4gICAqL1xuICByZWFkb25seSBzZXJ2ZXJTaWRlRW5jcnlwdGlvbj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFNwZWNpZnkgdGhlIHRhYmxlIGNsYXNzLlxuICAgKiBAZGVmYXVsdCBTVEFOREFSRFxuICAgKi9cbiAgcmVhZG9ubHkgdGFibGVDbGFzcz86IFRhYmxlQ2xhc3M7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgc2VydmVyLXNpZGUgZW5jcnlwdGlvbiB3aXRoIGFuIEFXUyBtYW5hZ2VkIGN1c3RvbWVyIG1hc3RlciBrZXkgaXMgZW5hYmxlZC5cbiAgICpcbiAgICogVGhpcyBwcm9wZXJ0eSBjYW5ub3QgYmUgc2V0IGlmIGBzZXJ2ZXJTaWRlRW5jcnlwdGlvbmAgaXMgc2V0LlxuICAgKlxuICAgKiA+ICoqTk9URSoqOiBpZiB5b3Ugc2V0IHRoaXMgdG8gYENVU1RPTUVSX01BTkFHRURgIGFuZCBgZW5jcnlwdGlvbktleWAgaXMgbm90XG4gICAqID4gc3BlY2lmaWVkLCB0aGUga2V5IHRoYXQgdGhlIFRhYmxldCBnZW5lcmF0ZXMgZm9yIHlvdSB3aWxsIGJlIGNyZWF0ZWQgd2l0aFxuICAgKiA+IGRlZmF1bHQgcGVybWlzc2lvbnMuIElmIHlvdSBhcmUgdXNpbmcgQ0RLdjIsIHRoZXNlIHBlcm1pc3Npb25zIHdpbGwgYmVcbiAgICogPiBzdWZmaWNpZW50IHRvIGVuYWJsZSB0aGUga2V5IGZvciB1c2Ugd2l0aCBEeW5hbW9EQiB0YWJsZXMuICBJZiB5b3UgYXJlXG4gICAqID4gdXNpbmcgQ0RLdjEsIG1ha2Ugc3VyZSB0aGUgZmVhdHVyZSBmbGFnXG4gICAqID4gYEBhd3MtY2RrL2F3cy1rbXM6ZGVmYXVsdEtleVBvbGljaWVzYCBpcyBzZXQgdG8gYHRydWVgIGluIHlvdXIgYGNkay5qc29uYC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBzZXJ2ZXItc2lkZSBlbmNyeXB0aW9uIGlzIGVuYWJsZWQgd2l0aCBhbiBBV1Mgb3duZWQgY3VzdG9tZXIgbWFzdGVyIGtleVxuICAgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbj86IFRhYmxlRW5jcnlwdGlvbjtcblxuICAvKipcbiAgICogRXh0ZXJuYWwgS01TIGtleSB0byB1c2UgZm9yIHRhYmxlIGVuY3J5cHRpb24uXG4gICAqXG4gICAqIFRoaXMgcHJvcGVydHkgY2FuIG9ubHkgYmUgc2V0IGlmIGBlbmNyeXB0aW9uYCBpcyBzZXQgdG8gYFRhYmxlRW5jcnlwdGlvbi5DVVNUT01FUl9NQU5BR0VEYC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBJZiBgZW5jcnlwdGlvbmAgaXMgc2V0IHRvIGBUYWJsZUVuY3J5cHRpb24uQ1VTVE9NRVJfTUFOQUdFRGAgYW5kIHRoaXNcbiAgICogcHJvcGVydHkgaXMgdW5kZWZpbmVkLCBhIG5ldyBLTVMga2V5IHdpbGwgYmUgY3JlYXRlZCBhbmQgYXNzb2NpYXRlZCB3aXRoIHRoaXMgdGFibGUuXG4gICAqL1xuICByZWFkb25seSBlbmNyeXB0aW9uS2V5Pzoga21zLklLZXk7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIFRUTCBhdHRyaWJ1dGUuXG4gICAqIEBkZWZhdWx0IC0gVFRMIGlzIGRpc2FibGVkXG4gICAqL1xuICByZWFkb25seSB0aW1lVG9MaXZlQXR0cmlidXRlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGVuIGFuIGl0ZW0gaW4gdGhlIHRhYmxlIGlzIG1vZGlmaWVkLCBTdHJlYW1WaWV3VHlwZSBkZXRlcm1pbmVzIHdoYXQgaW5mb3JtYXRpb25cbiAgICogaXMgd3JpdHRlbiB0byB0aGUgc3RyZWFtIGZvciB0aGlzIHRhYmxlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHN0cmVhbXMgYXJlIGRpc2FibGVkIHVubGVzcyBgcmVwbGljYXRpb25SZWdpb25zYCBpcyBzcGVjaWZpZWRcbiAgICovXG4gIHJlYWRvbmx5IHN0cmVhbT86IFN0cmVhbVZpZXdUeXBlO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVtb3ZhbCBwb2xpY3kgdG8gYXBwbHkgdG8gdGhlIER5bmFtb0RCIFRhYmxlLlxuICAgKlxuICAgKiBAZGVmYXVsdCBSZW1vdmFsUG9saWN5LlJFVEFJTlxuICAgKi9cbiAgcmVhZG9ubHkgcmVtb3ZhbFBvbGljeT86IFJlbW92YWxQb2xpY3k7XG5cbiAgLyoqXG4gICAqIFJlZ2lvbnMgd2hlcmUgcmVwbGljYSB0YWJsZXMgd2lsbCBiZSBjcmVhdGVkXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gcmVwbGljYSB0YWJsZXMgYXJlIGNyZWF0ZWRcbiAgICovXG4gIHJlYWRvbmx5IHJlcGxpY2F0aW9uUmVnaW9ucz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgdGltZW91dCBmb3IgYSB0YWJsZSByZXBsaWNhdGlvbiBvcGVyYXRpb24gaW4gYSBzaW5nbGUgcmVnaW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDMwKVxuICAgKi9cbiAgcmVhZG9ubHkgcmVwbGljYXRpb25UaW1lb3V0PzogRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyB3aGV0aGVyIENsb3VkRm9ybWF0aW9uIHN0YWNrIHdhaXRzIGZvciByZXBsaWNhdGlvbiB0byBmaW5pc2guXG4gICAqIElmIHNldCB0byBmYWxzZSwgdGhlIENsb3VkRm9ybWF0aW9uIHJlc291cmNlIHdpbGwgbWFyayB0aGUgcmVzb3VyY2UgYXNcbiAgICogY3JlYXRlZCBhbmQgcmVwbGljYXRpb24gd2lsbCBiZSBjb21wbGV0ZWQgYXN5bmNocm9ub3VzbHkuIFRoaXMgcHJvcGVydHkgaXNcbiAgICogaWdub3JlZCBpZiByZXBsaWNhdGlvblJlZ2lvbnMgcHJvcGVydHkgaXMgbm90IHNldC5cbiAgICpcbiAgICogRE8gTk9UIFVOU0VUIHRoaXMgcHJvcGVydHkgaWYgYWRkaW5nL3JlbW92aW5nIG11bHRpcGxlIHJlcGxpY2F0aW9uUmVnaW9uc1xuICAgKiBpbiBvbmUgZGVwbG95bWVudCwgYXMgQ2xvdWRGb3JtYXRpb24gb25seSBzdXBwb3J0cyBvbmUgcmVnaW9uIHJlcGxpY2F0aW9uXG4gICAqIGF0IGEgdGltZS4gQ0RLIG92ZXJjb21lcyB0aGlzIGxpbWl0YXRpb24gYnkgd2FpdGluZyBmb3IgcmVwbGljYXRpb24gdG9cbiAgICogZmluaXNoIGJlZm9yZSBzdGFydGluZyBuZXcgcmVwbGljYXRpb25SZWdpb24uXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0Nsb3VkRm9ybWF0aW9uL2xhdGVzdC9Vc2VyR3VpZGUvYXdzLXJlc291cmNlLWR5bmFtb2RiLWdsb2JhbHRhYmxlLmh0bWwjY2ZuLWR5bmFtb2RiLWdsb2JhbHRhYmxlLXJlcGxpY2FzXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHdhaXRGb3JSZXBsaWNhdGlvblRvRmluaXNoPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciBDbG91ZFdhdGNoIGNvbnRyaWJ1dG9yIGluc2lnaHRzIGlzIGVuYWJsZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBjb250cmlidXRvckluc2lnaHRzRW5hYmxlZD86IGJvb2xlYW47XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgYSBEeW5hbW9EQiBUYWJsZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRhYmxlUHJvcHMgZXh0ZW5kcyBUYWJsZU9wdGlvbnMge1xuICAvKipcbiAgICogRW5mb3JjZXMgYSBwYXJ0aWN1bGFyIHBoeXNpY2FsIHRhYmxlIG5hbWUuXG4gICAqIEBkZWZhdWx0IDxnZW5lcmF0ZWQ+XG4gICAqL1xuICByZWFkb25seSB0YWJsZU5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEtpbmVzaXMgRGF0YSBTdHJlYW0gdG8gY2FwdHVyZSBpdGVtLWxldmVsIGNoYW5nZXMgZm9yIHRoZSB0YWJsZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBLaW5lc2lzIERhdGEgU3RyZWFtXG4gICAqL1xuICByZWFkb25seSBraW5lc2lzU3RyZWFtPzoga2luZXNpcy5JU3RyZWFtO1xufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIGEgc2Vjb25kYXJ5IGluZGV4XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2Vjb25kYXJ5SW5kZXhQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgc2Vjb25kYXJ5IGluZGV4LlxuICAgKi9cbiAgcmVhZG9ubHkgaW5kZXhOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBzZXQgb2YgYXR0cmlidXRlcyB0aGF0IGFyZSBwcm9qZWN0ZWQgaW50byB0aGUgc2Vjb25kYXJ5IGluZGV4LlxuICAgKiBAZGVmYXVsdCBBTExcbiAgICovXG4gIHJlYWRvbmx5IHByb2plY3Rpb25UeXBlPzogUHJvamVjdGlvblR5cGU7XG5cbiAgLyoqXG4gICAqIFRoZSBub24ta2V5IGF0dHJpYnV0ZXMgdGhhdCBhcmUgcHJvamVjdGVkIGludG8gdGhlIHNlY29uZGFyeSBpbmRleC5cbiAgICogQGRlZmF1bHQgLSBObyBhZGRpdGlvbmFsIGF0dHJpYnV0ZXNcbiAgICovXG4gIHJlYWRvbmx5IG5vbktleUF0dHJpYnV0ZXM/OiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBhIGdsb2JhbCBzZWNvbmRhcnkgaW5kZXhcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHbG9iYWxTZWNvbmRhcnlJbmRleFByb3BzIGV4dGVuZHMgU2Vjb25kYXJ5SW5kZXhQcm9wcywgU2NoZW1hT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgcmVhZCBjYXBhY2l0eSBmb3IgdGhlIGdsb2JhbCBzZWNvbmRhcnkgaW5kZXguXG4gICAqXG4gICAqIENhbiBvbmx5IGJlIHByb3ZpZGVkIGlmIHRhYmxlIGJpbGxpbmdNb2RlIGlzIFByb3Zpc2lvbmVkIG9yIHVuZGVmaW5lZC5cbiAgICpcbiAgICogQGRlZmF1bHQgNVxuICAgKi9cbiAgcmVhZG9ubHkgcmVhZENhcGFjaXR5PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgd3JpdGUgY2FwYWNpdHkgZm9yIHRoZSBnbG9iYWwgc2Vjb25kYXJ5IGluZGV4LlxuICAgKlxuICAgKiBDYW4gb25seSBiZSBwcm92aWRlZCBpZiB0YWJsZSBiaWxsaW5nTW9kZSBpcyBQcm92aXNpb25lZCBvciB1bmRlZmluZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDVcbiAgICovXG4gIHJlYWRvbmx5IHdyaXRlQ2FwYWNpdHk/OiBudW1iZXI7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgYSBsb2NhbCBzZWNvbmRhcnkgaW5kZXhcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2NhbFNlY29uZGFyeUluZGV4UHJvcHMgZXh0ZW5kcyBTZWNvbmRhcnlJbmRleFByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBhdHRyaWJ1dGUgb2YgYSBzb3J0IGtleSBmb3IgdGhlIGxvY2FsIHNlY29uZGFyeSBpbmRleC5cbiAgICovXG4gIHJlYWRvbmx5IHNvcnRLZXk6IEF0dHJpYnV0ZTtcbn1cblxuLyoqXG4gKiBBbiBpbnRlcmZhY2UgdGhhdCByZXByZXNlbnRzIGEgRHluYW1vREIgVGFibGUgLSBlaXRoZXIgY3JlYXRlZCB3aXRoIHRoZSBDREssIG9yIGFuIGV4aXN0aW5nIG9uZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJVGFibGUgZXh0ZW5kcyBJUmVzb3VyY2Uge1xuICAvKipcbiAgICogQXJuIG9mIHRoZSBkeW5hbW9kYiB0YWJsZS5cbiAgICpcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcmVhZG9ubHkgdGFibGVBcm46IHN0cmluZztcblxuICAvKipcbiAgICogVGFibGUgbmFtZSBvZiB0aGUgZHluYW1vZGIgdGFibGUuXG4gICAqXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHJlYWRvbmx5IHRhYmxlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBUk4gb2YgdGhlIHRhYmxlJ3Mgc3RyZWFtLCBpZiB0aGVyZSBpcyBvbmUuXG4gICAqXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHJlYWRvbmx5IHRhYmxlU3RyZWFtQXJuPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKlxuICAgKiBPcHRpb25hbCBLTVMgZW5jcnlwdGlvbiBrZXkgYXNzb2NpYXRlZCB3aXRoIHRoaXMgdGFibGUuXG4gICAqL1xuICByZWFkb25seSBlbmNyeXB0aW9uS2V5Pzoga21zLklLZXk7XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gSUFNIHBvbGljeSBzdGF0ZW1lbnQgYXNzb2NpYXRlZCB3aXRoIHRoaXMgdGFibGUgdG8gYW4gSUFNXG4gICAqIHByaW5jaXBhbCdzIHBvbGljeS5cbiAgICpcbiAgICogSWYgYGVuY3J5cHRpb25LZXlgIGlzIHByZXNlbnQsIGFwcHJvcHJpYXRlIGdyYW50cyB0byB0aGUga2V5IG5lZWRzIHRvIGJlIGFkZGVkXG4gICAqIHNlcGFyYXRlbHkgdXNpbmcgdGhlIGB0YWJsZS5lbmNyeXB0aW9uS2V5LmdyYW50KmAgbWV0aG9kcy5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCAobm8tb3AgaWYgdW5kZWZpbmVkKVxuICAgKiBAcGFyYW0gYWN0aW9ucyBUaGUgc2V0IG9mIGFjdGlvbnMgdG8gYWxsb3cgKGkuZS4gXCJkeW5hbW9kYjpQdXRJdGVtXCIsIFwiZHluYW1vZGI6R2V0SXRlbVwiLCAuLi4pXG4gICAqL1xuICBncmFudChncmFudGVlOiBpYW0uSUdyYW50YWJsZSwgLi4uYWN0aW9uczogc3RyaW5nW10pOiBpYW0uR3JhbnQ7XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gSUFNIHBvbGljeSBzdGF0ZW1lbnQgYXNzb2NpYXRlZCB3aXRoIHRoaXMgdGFibGUncyBzdHJlYW0gdG8gYW5cbiAgICogSUFNIHByaW5jaXBhbCdzIHBvbGljeS5cbiAgICpcbiAgICogSWYgYGVuY3J5cHRpb25LZXlgIGlzIHByZXNlbnQsIGFwcHJvcHJpYXRlIGdyYW50cyB0byB0aGUga2V5IG5lZWRzIHRvIGJlIGFkZGVkXG4gICAqIHNlcGFyYXRlbHkgdXNpbmcgdGhlIGB0YWJsZS5lbmNyeXB0aW9uS2V5LmdyYW50KmAgbWV0aG9kcy5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCAobm8tb3AgaWYgdW5kZWZpbmVkKVxuICAgKiBAcGFyYW0gYWN0aW9ucyBUaGUgc2V0IG9mIGFjdGlvbnMgdG8gYWxsb3cgKGkuZS4gXCJkeW5hbW9kYjpEZXNjcmliZVN0cmVhbVwiLCBcImR5bmFtb2RiOkdldFJlY29yZHNcIiwgLi4uKVxuICAgKi9cbiAgZ3JhbnRTdHJlYW0oZ3JhbnRlZTogaWFtLklHcmFudGFibGUsIC4uLmFjdGlvbnM6IHN0cmluZ1tdKTogaWFtLkdyYW50O1xuXG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBwcmluY2lwYWwgYWxsIGRhdGEgcmVhZCBvcGVyYXRpb25zIGZyb20gdGhpcyB0YWJsZTpcbiAgICogQmF0Y2hHZXRJdGVtLCBHZXRSZWNvcmRzLCBHZXRTaGFyZEl0ZXJhdG9yLCBRdWVyeSwgR2V0SXRlbSwgU2Nhbi5cbiAgICpcbiAgICogQXBwcm9wcmlhdGUgZ3JhbnRzIHdpbGwgYWxzbyBiZSBhZGRlZCB0byB0aGUgY3VzdG9tZXItbWFuYWdlZCBLTVMga2V5XG4gICAqIGlmIG9uZSB3YXMgY29uZmlndXJlZC5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCB0byBncmFudCBhY2Nlc3MgdG9cbiAgICovXG4gIGdyYW50UmVhZERhdGEoZ3JhbnRlZTogaWFtLklHcmFudGFibGUpOiBpYW0uR3JhbnQ7XG5cbiAgLyoqXG4gICAqIFBlcm1pdHMgYW4gSUFNIFByaW5jaXBhbCB0byBsaXN0IHN0cmVhbXMgYXR0YWNoZWQgdG8gY3VycmVudCBkeW5hbW9kYiB0YWJsZS5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCAobm8tb3AgaWYgdW5kZWZpbmVkKVxuICAgKi9cbiAgZ3JhbnRUYWJsZUxpc3RTdHJlYW1zKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50O1xuXG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBwcmluY2lwYWwgYWxsIHN0cmVhbSBkYXRhIHJlYWQgb3BlcmF0aW9ucyBmb3IgdGhpc1xuICAgKiB0YWJsZSdzIHN0cmVhbTpcbiAgICogRGVzY3JpYmVTdHJlYW0sIEdldFJlY29yZHMsIEdldFNoYXJkSXRlcmF0b3IsIExpc3RTdHJlYW1zLlxuICAgKlxuICAgKiBBcHByb3ByaWF0ZSBncmFudHMgd2lsbCBhbHNvIGJlIGFkZGVkIHRvIHRoZSBjdXN0b21lci1tYW5hZ2VkIEtNUyBrZXlcbiAgICogaWYgb25lIHdhcyBjb25maWd1cmVkLlxuICAgKlxuICAgKiBAcGFyYW0gZ3JhbnRlZSBUaGUgcHJpbmNpcGFsIHRvIGdyYW50IGFjY2VzcyB0b1xuICAgKi9cbiAgZ3JhbnRTdHJlYW1SZWFkKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50O1xuXG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBwcmluY2lwYWwgYWxsIGRhdGEgd3JpdGUgb3BlcmF0aW9ucyB0byB0aGlzIHRhYmxlOlxuICAgKiBCYXRjaFdyaXRlSXRlbSwgUHV0SXRlbSwgVXBkYXRlSXRlbSwgRGVsZXRlSXRlbS5cbiAgICpcbiAgICogQXBwcm9wcmlhdGUgZ3JhbnRzIHdpbGwgYWxzbyBiZSBhZGRlZCB0byB0aGUgY3VzdG9tZXItbWFuYWdlZCBLTVMga2V5XG4gICAqIGlmIG9uZSB3YXMgY29uZmlndXJlZC5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCB0byBncmFudCBhY2Nlc3MgdG9cbiAgICovXG4gIGdyYW50V3JpdGVEYXRhKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50O1xuXG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBwcmluY2lwYWwgdG8gYWxsIGRhdGEgcmVhZC93cml0ZSBvcGVyYXRpb25zIHRvIHRoaXMgdGFibGUuXG4gICAqIEJhdGNoR2V0SXRlbSwgR2V0UmVjb3JkcywgR2V0U2hhcmRJdGVyYXRvciwgUXVlcnksIEdldEl0ZW0sIFNjYW4sXG4gICAqIEJhdGNoV3JpdGVJdGVtLCBQdXRJdGVtLCBVcGRhdGVJdGVtLCBEZWxldGVJdGVtXG4gICAqXG4gICAqIEFwcHJvcHJpYXRlIGdyYW50cyB3aWxsIGFsc28gYmUgYWRkZWQgdG8gdGhlIGN1c3RvbWVyLW1hbmFnZWQgS01TIGtleVxuICAgKiBpZiBvbmUgd2FzIGNvbmZpZ3VyZWQuXG4gICAqXG4gICAqIEBwYXJhbSBncmFudGVlIFRoZSBwcmluY2lwYWwgdG8gZ3JhbnQgYWNjZXNzIHRvXG4gICAqL1xuICBncmFudFJlYWRXcml0ZURhdGEoZ3JhbnRlZTogaWFtLklHcmFudGFibGUpOiBpYW0uR3JhbnQ7XG5cbiAgLyoqXG4gICAqIFBlcm1pdHMgYWxsIER5bmFtb0RCIG9wZXJhdGlvbnMgKFwiZHluYW1vZGI6KlwiKSB0byBhbiBJQU0gcHJpbmNpcGFsLlxuICAgKlxuICAgKiBBcHByb3ByaWF0ZSBncmFudHMgd2lsbCBhbHNvIGJlIGFkZGVkIHRvIHRoZSBjdXN0b21lci1tYW5hZ2VkIEtNUyBrZXlcbiAgICogaWYgb25lIHdhcyBjb25maWd1cmVkLlxuICAgKlxuICAgKiBAcGFyYW0gZ3JhbnRlZSBUaGUgcHJpbmNpcGFsIHRvIGdyYW50IGFjY2VzcyB0b1xuICAgKi9cbiAgZ3JhbnRGdWxsQWNjZXNzKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50O1xuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBudW1iZXIgb2YgRXJyb3JzIGV4ZWN1dGluZyBhbGwgTGFtYmRhc1xuICAgKi9cbiAgbWV0cmljKG1ldHJpY05hbWU6IHN0cmluZywgcHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYztcblxuICAvKipcbiAgICogTWV0cmljIGZvciB0aGUgY29uc3VtZWQgcmVhZCBjYXBhY2l0eSB1bml0c1xuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgcHJvcGVydGllcyBvZiBhIG1ldHJpY1xuICAgKi9cbiAgbWV0cmljQ29uc3VtZWRSZWFkQ2FwYWNpdHlVbml0cyhwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBjb25zdW1lZCB3cml0ZSBjYXBhY2l0eSB1bml0c1xuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgcHJvcGVydGllcyBvZiBhIG1ldHJpY1xuICAgKi9cbiAgbWV0cmljQ29uc3VtZWRXcml0ZUNhcGFjaXR5VW5pdHMocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYztcblxuICAvKipcbiAgICogTWV0cmljIGZvciB0aGUgc3lzdGVtIGVycm9yc1xuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgcHJvcGVydGllcyBvZiBhIG1ldHJpY1xuICAgKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgYG1ldHJpY1N5c3RlbUVycm9yc0Zvck9wZXJhdGlvbnNgXG4gICAqL1xuICBtZXRyaWNTeXN0ZW1FcnJvcnMocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYztcblxuICAvKipcbiAgICogTWV0cmljIGZvciB0aGUgc3lzdGVtIGVycm9ycyB0aGlzIHRhYmxlXG4gICAqXG4gICAqIEBwYXJhbSBwcm9wcyBwcm9wZXJ0aWVzIG9mIGEgbWV0cmljXG4gICAqXG4gICAqL1xuICBtZXRyaWNTeXN0ZW1FcnJvcnNGb3JPcGVyYXRpb25zKHByb3BzPzogU3lzdGVtRXJyb3JzRm9yT3BlcmF0aW9uc01ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLklNZXRyaWM7XG5cbiAgLyoqXG4gICAqIE1ldHJpYyBmb3IgdGhlIHVzZXIgZXJyb3JzXG4gICAqXG4gICAqIEBwYXJhbSBwcm9wcyBwcm9wZXJ0aWVzIG9mIGEgbWV0cmljXG4gICAqL1xuICBtZXRyaWNVc2VyRXJyb3JzKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIE1ldHJpYyBmb3IgdGhlIGNvbmRpdGlvbmFsIGNoZWNrIGZhaWxlZCByZXF1ZXN0c1xuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgcHJvcGVydGllcyBvZiBhIG1ldHJpY1xuICAgKi9cbiAgbWV0cmljQ29uZGl0aW9uYWxDaGVja0ZhaWxlZFJlcXVlc3RzKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG5cbiAgLyoqXG4gICAqIE1ldHJpYyBmb3IgdGhyb3R0bGVkIHJlcXVlc3RzXG4gICAqXG4gICAqIEBwYXJhbSBwcm9wcyBwcm9wZXJ0aWVzIG9mIGEgbWV0cmljXG4gICAqXG4gICAqL1xuICBtZXRyaWNUaHJvdHRsZWRSZXF1ZXN0cyhwcm9wcz86IGNsb3Vkd2F0Y2guTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guTWV0cmljO1xuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBzdWNjZXNzZnVsIHJlcXVlc3QgbGF0ZW5jeVxuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgcHJvcGVydGllcyBvZiBhIG1ldHJpY1xuICAgKlxuICAgKi9cbiAgbWV0cmljU3VjY2Vzc2Z1bFJlcXVlc3RMYXRlbmN5KHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWM7XG59XG5cbi8qKlxuICogUmVmZXJlbmNlIHRvIGEgZHluYW1vZGIgdGFibGUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVGFibGVBdHRyaWJ1dGVzIHtcbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhlIGR5bmFtb2RiIHRhYmxlLlxuICAgKiBPbmUgb2YgdGhpcywgb3Ige0BsaW5rIHRhYmxlTmFtZX0sIGlzIHJlcXVpcmVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIHRhYmxlIGFyblxuICAgKi9cbiAgcmVhZG9ubHkgdGFibGVBcm4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSB0YWJsZSBuYW1lIG9mIHRoZSBkeW5hbW9kYiB0YWJsZS5cbiAgICogT25lIG9mIHRoaXMsIG9yIHtAbGluayB0YWJsZUFybn0sIGlzIHJlcXVpcmVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIHRhYmxlIG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IHRhYmxlTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIEFSTiBvZiB0aGUgdGFibGUncyBzdHJlYW0uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gdGFibGUgc3RyZWFtXG4gICAqL1xuICByZWFkb25seSB0YWJsZVN0cmVhbUFybj86IHN0cmluZztcblxuICAvKipcbiAgICogS01TIGVuY3J5cHRpb24ga2V5LCBpZiB0aGlzIHRhYmxlIHVzZXMgYSBjdXN0b21lci1tYW5hZ2VkIGVuY3J5cHRpb24ga2V5LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGtleVxuICAgKi9cbiAgcmVhZG9ubHkgZW5jcnlwdGlvbktleT86IGttcy5JS2V5O1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgZ2xvYmFsIGluZGV4ZXMgc2V0IGZvciB0aGlzIFRhYmxlLlxuICAgKiBOb3RlIHRoYXQgeW91IG5lZWQgdG8gc2V0IGVpdGhlciB0aGlzIHByb3BlcnR5LFxuICAgKiBvciB7QGxpbmsgbG9jYWxJbmRleGVzfSxcbiAgICogaWYgeW91IHdhbnQgbWV0aG9kcyBsaWtlIGdyYW50UmVhZERhdGEoKVxuICAgKiB0byBncmFudCBwZXJtaXNzaW9ucyBmb3IgaW5kZXhlcyBhcyB3ZWxsIGFzIHRoZSB0YWJsZSBpdHNlbGYuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gZ2xvYmFsIGluZGV4ZXNcbiAgICovXG4gIHJlYWRvbmx5IGdsb2JhbEluZGV4ZXM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGxvY2FsIGluZGV4ZXMgc2V0IGZvciB0aGlzIFRhYmxlLlxuICAgKiBOb3RlIHRoYXQgeW91IG5lZWQgdG8gc2V0IGVpdGhlciB0aGlzIHByb3BlcnR5LFxuICAgKiBvciB7QGxpbmsgZ2xvYmFsSW5kZXhlc30sXG4gICAqIGlmIHlvdSB3YW50IG1ldGhvZHMgbGlrZSBncmFudFJlYWREYXRhKClcbiAgICogdG8gZ3JhbnQgcGVybWlzc2lvbnMgZm9yIGluZGV4ZXMgYXMgd2VsbCBhcyB0aGUgdGFibGUgaXRzZWxmLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGxvY2FsIGluZGV4ZXNcbiAgICovXG4gIHJlYWRvbmx5IGxvY2FsSW5kZXhlcz86IHN0cmluZ1tdO1xufVxuXG5hYnN0cmFjdCBjbGFzcyBUYWJsZUJhc2UgZXh0ZW5kcyBSZXNvdXJjZSBpbXBsZW1lbnRzIElUYWJsZSB7XG4gIC8qKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgYWJzdHJhY3QgcmVhZG9ubHkgdGFibGVBcm46IHN0cmluZztcblxuICAvKipcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIGFic3RyYWN0IHJlYWRvbmx5IHRhYmxlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgYWJzdHJhY3QgcmVhZG9ubHkgdGFibGVTdHJlYW1Bcm4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEtNUyBlbmNyeXB0aW9uIGtleSwgaWYgdGhpcyB0YWJsZSB1c2VzIGEgY3VzdG9tZXItbWFuYWdlZCBlbmNyeXB0aW9uIGtleS5cbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSBlbmNyeXB0aW9uS2V5Pzoga21zLklLZXk7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHJlZ2lvbmFsQXJucyA9IG5ldyBBcnJheTxzdHJpbmc+KCk7XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gSUFNIHBvbGljeSBzdGF0ZW1lbnQgYXNzb2NpYXRlZCB3aXRoIHRoaXMgdGFibGUgdG8gYW4gSUFNXG4gICAqIHByaW5jaXBhbCdzIHBvbGljeS5cbiAgICpcbiAgICogSWYgYGVuY3J5cHRpb25LZXlgIGlzIHByZXNlbnQsIGFwcHJvcHJpYXRlIGdyYW50cyB0byB0aGUga2V5IG5lZWRzIHRvIGJlIGFkZGVkXG4gICAqIHNlcGFyYXRlbHkgdXNpbmcgdGhlIGB0YWJsZS5lbmNyeXB0aW9uS2V5LmdyYW50KmAgbWV0aG9kcy5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCAobm8tb3AgaWYgdW5kZWZpbmVkKVxuICAgKiBAcGFyYW0gYWN0aW9ucyBUaGUgc2V0IG9mIGFjdGlvbnMgdG8gYWxsb3cgKGkuZS4gXCJkeW5hbW9kYjpQdXRJdGVtXCIsIFwiZHluYW1vZGI6R2V0SXRlbVwiLCAuLi4pXG4gICAqL1xuICBwdWJsaWMgZ3JhbnQoZ3JhbnRlZTogaWFtLklHcmFudGFibGUsIC4uLmFjdGlvbnM6IHN0cmluZ1tdKTogaWFtLkdyYW50IHtcbiAgICByZXR1cm4gaWFtLkdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgIGdyYW50ZWUsXG4gICAgICBhY3Rpb25zLFxuICAgICAgcmVzb3VyY2VBcm5zOiBbXG4gICAgICAgIHRoaXMudGFibGVBcm4sXG4gICAgICAgIExhenkuc3RyaW5nKHsgcHJvZHVjZTogKCkgPT4gdGhpcy5oYXNJbmRleCA/IGAke3RoaXMudGFibGVBcm59L2luZGV4LypgIDogQXdzLk5PX1ZBTFVFIH0pLFxuICAgICAgICAuLi50aGlzLnJlZ2lvbmFsQXJucyxcbiAgICAgICAgLi4udGhpcy5yZWdpb25hbEFybnMubWFwKGFybiA9PiBMYXp5LnN0cmluZyh7XG4gICAgICAgICAgcHJvZHVjZTogKCkgPT4gdGhpcy5oYXNJbmRleCA/IGAke2Fybn0vaW5kZXgvKmAgOiBBd3MuTk9fVkFMVUUsXG4gICAgICAgIH0pKSxcbiAgICAgIF0sXG4gICAgICBzY29wZTogdGhpcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFuIElBTSBwb2xpY3kgc3RhdGVtZW50IGFzc29jaWF0ZWQgd2l0aCB0aGlzIHRhYmxlJ3Mgc3RyZWFtIHRvIGFuXG4gICAqIElBTSBwcmluY2lwYWwncyBwb2xpY3kuXG4gICAqXG4gICAqIElmIGBlbmNyeXB0aW9uS2V5YCBpcyBwcmVzZW50LCBhcHByb3ByaWF0ZSBncmFudHMgdG8gdGhlIGtleSBuZWVkcyB0byBiZSBhZGRlZFxuICAgKiBzZXBhcmF0ZWx5IHVzaW5nIHRoZSBgdGFibGUuZW5jcnlwdGlvbktleS5ncmFudCpgIG1ldGhvZHMuXG4gICAqXG4gICAqIEBwYXJhbSBncmFudGVlIFRoZSBwcmluY2lwYWwgKG5vLW9wIGlmIHVuZGVmaW5lZClcbiAgICogQHBhcmFtIGFjdGlvbnMgVGhlIHNldCBvZiBhY3Rpb25zIHRvIGFsbG93IChpLmUuIFwiZHluYW1vZGI6RGVzY3JpYmVTdHJlYW1cIiwgXCJkeW5hbW9kYjpHZXRSZWNvcmRzXCIsIC4uLilcbiAgICovXG4gIHB1YmxpYyBncmFudFN0cmVhbShncmFudGVlOiBpYW0uSUdyYW50YWJsZSwgLi4uYWN0aW9uczogc3RyaW5nW10pOiBpYW0uR3JhbnQge1xuICAgIGlmICghdGhpcy50YWJsZVN0cmVhbUFybikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBEeW5hbW9EQiBTdHJlYW1zIG11c3QgYmUgZW5hYmxlZCBvbiB0aGUgdGFibGUgJHt0aGlzLm5vZGUucGF0aH1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gaWFtLkdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgIGdyYW50ZWUsXG4gICAgICBhY3Rpb25zLFxuICAgICAgcmVzb3VyY2VBcm5zOiBbdGhpcy50YWJsZVN0cmVhbUFybl0sXG4gICAgICBzY29wZTogdGhpcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBwcmluY2lwYWwgYWxsIGRhdGEgcmVhZCBvcGVyYXRpb25zIGZyb20gdGhpcyB0YWJsZTpcbiAgICogQmF0Y2hHZXRJdGVtLCBHZXRSZWNvcmRzLCBHZXRTaGFyZEl0ZXJhdG9yLCBRdWVyeSwgR2V0SXRlbSwgU2NhbiwgRGVzY3JpYmVUYWJsZS5cbiAgICpcbiAgICogQXBwcm9wcmlhdGUgZ3JhbnRzIHdpbGwgYWxzbyBiZSBhZGRlZCB0byB0aGUgY3VzdG9tZXItbWFuYWdlZCBLTVMga2V5XG4gICAqIGlmIG9uZSB3YXMgY29uZmlndXJlZC5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCB0byBncmFudCBhY2Nlc3MgdG9cbiAgICovXG4gIHB1YmxpYyBncmFudFJlYWREYXRhKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50IHtcbiAgICBjb25zdCB0YWJsZUFjdGlvbnMgPSBwZXJtcy5SRUFEX0RBVEFfQUNUSU9OUy5jb25jYXQocGVybXMuREVTQ1JJQkVfVEFCTEUpO1xuICAgIHJldHVybiB0aGlzLmNvbWJpbmVkR3JhbnQoZ3JhbnRlZSwgeyBrZXlBY3Rpb25zOiBwZXJtcy5LRVlfUkVBRF9BQ1RJT05TLCB0YWJsZUFjdGlvbnMgfSk7XG4gIH1cblxuICAvKipcbiAgICogUGVybWl0cyBhbiBJQU0gUHJpbmNpcGFsIHRvIGxpc3Qgc3RyZWFtcyBhdHRhY2hlZCB0byBjdXJyZW50IGR5bmFtb2RiIHRhYmxlLlxuICAgKlxuICAgKiBAcGFyYW0gZ3JhbnRlZSBUaGUgcHJpbmNpcGFsIChuby1vcCBpZiB1bmRlZmluZWQpXG4gICAqL1xuICBwdWJsaWMgZ3JhbnRUYWJsZUxpc3RTdHJlYW1zKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50IHtcbiAgICBpZiAoIXRoaXMudGFibGVTdHJlYW1Bcm4pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRHluYW1vREIgU3RyZWFtcyBtdXN0IGJlIGVuYWJsZWQgb24gdGhlIHRhYmxlICR7dGhpcy5ub2RlLnBhdGh9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGlhbS5HcmFudC5hZGRUb1ByaW5jaXBhbCh7XG4gICAgICBncmFudGVlLFxuICAgICAgYWN0aW9uczogWydkeW5hbW9kYjpMaXN0U3RyZWFtcyddLFxuICAgICAgcmVzb3VyY2VBcm5zOiBbJyonXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBwcmluY2lwYWwgYWxsIHN0cmVhbSBkYXRhIHJlYWQgb3BlcmF0aW9ucyBmb3IgdGhpc1xuICAgKiB0YWJsZSdzIHN0cmVhbTpcbiAgICogRGVzY3JpYmVTdHJlYW0sIEdldFJlY29yZHMsIEdldFNoYXJkSXRlcmF0b3IsIExpc3RTdHJlYW1zLlxuICAgKlxuICAgKiBBcHByb3ByaWF0ZSBncmFudHMgd2lsbCBhbHNvIGJlIGFkZGVkIHRvIHRoZSBjdXN0b21lci1tYW5hZ2VkIEtNUyBrZXlcbiAgICogaWYgb25lIHdhcyBjb25maWd1cmVkLlxuICAgKlxuICAgKiBAcGFyYW0gZ3JhbnRlZSBUaGUgcHJpbmNpcGFsIHRvIGdyYW50IGFjY2VzcyB0b1xuICAgKi9cbiAgcHVibGljIGdyYW50U3RyZWFtUmVhZChncmFudGVlOiBpYW0uSUdyYW50YWJsZSk6IGlhbS5HcmFudCB7XG4gICAgdGhpcy5ncmFudFRhYmxlTGlzdFN0cmVhbXMoZ3JhbnRlZSk7XG4gICAgcmV0dXJuIHRoaXMuY29tYmluZWRHcmFudChncmFudGVlLCB7IGtleUFjdGlvbnM6IHBlcm1zLktFWV9SRUFEX0FDVElPTlMsIHN0cmVhbUFjdGlvbnM6IHBlcm1zLlJFQURfU1RSRUFNX0RBVEFfQUNUSU9OUyB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBwcmluY2lwYWwgYWxsIGRhdGEgd3JpdGUgb3BlcmF0aW9ucyB0byB0aGlzIHRhYmxlOlxuICAgKiBCYXRjaFdyaXRlSXRlbSwgUHV0SXRlbSwgVXBkYXRlSXRlbSwgRGVsZXRlSXRlbSwgRGVzY3JpYmVUYWJsZS5cbiAgICpcbiAgICogQXBwcm9wcmlhdGUgZ3JhbnRzIHdpbGwgYWxzbyBiZSBhZGRlZCB0byB0aGUgY3VzdG9tZXItbWFuYWdlZCBLTVMga2V5XG4gICAqIGlmIG9uZSB3YXMgY29uZmlndXJlZC5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCB0byBncmFudCBhY2Nlc3MgdG9cbiAgICovXG4gIHB1YmxpYyBncmFudFdyaXRlRGF0YShncmFudGVlOiBpYW0uSUdyYW50YWJsZSk6IGlhbS5HcmFudCB7XG4gICAgY29uc3QgdGFibGVBY3Rpb25zID0gcGVybXMuV1JJVEVfREFUQV9BQ1RJT05TLmNvbmNhdChwZXJtcy5ERVNDUklCRV9UQUJMRSk7XG4gICAgY29uc3Qga2V5QWN0aW9ucyA9IHBlcm1zLktFWV9SRUFEX0FDVElPTlMuY29uY2F0KHBlcm1zLktFWV9XUklURV9BQ1RJT05TKTtcbiAgICByZXR1cm4gdGhpcy5jb21iaW5lZEdyYW50KGdyYW50ZWUsIHsga2V5QWN0aW9ucywgdGFibGVBY3Rpb25zIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcm1pdHMgYW4gSUFNIHByaW5jaXBhbCB0byBhbGwgZGF0YSByZWFkL3dyaXRlIG9wZXJhdGlvbnMgdG8gdGhpcyB0YWJsZS5cbiAgICogQmF0Y2hHZXRJdGVtLCBHZXRSZWNvcmRzLCBHZXRTaGFyZEl0ZXJhdG9yLCBRdWVyeSwgR2V0SXRlbSwgU2NhbixcbiAgICogQmF0Y2hXcml0ZUl0ZW0sIFB1dEl0ZW0sIFVwZGF0ZUl0ZW0sIERlbGV0ZUl0ZW0sIERlc2NyaWJlVGFibGVcbiAgICpcbiAgICogQXBwcm9wcmlhdGUgZ3JhbnRzIHdpbGwgYWxzbyBiZSBhZGRlZCB0byB0aGUgY3VzdG9tZXItbWFuYWdlZCBLTVMga2V5XG4gICAqIGlmIG9uZSB3YXMgY29uZmlndXJlZC5cbiAgICpcbiAgICogQHBhcmFtIGdyYW50ZWUgVGhlIHByaW5jaXBhbCB0byBncmFudCBhY2Nlc3MgdG9cbiAgICovXG4gIHB1YmxpYyBncmFudFJlYWRXcml0ZURhdGEoZ3JhbnRlZTogaWFtLklHcmFudGFibGUpOiBpYW0uR3JhbnQge1xuICAgIGNvbnN0IHRhYmxlQWN0aW9ucyA9IHBlcm1zLlJFQURfREFUQV9BQ1RJT05TLmNvbmNhdChwZXJtcy5XUklURV9EQVRBX0FDVElPTlMpLmNvbmNhdChwZXJtcy5ERVNDUklCRV9UQUJMRSk7XG4gICAgY29uc3Qga2V5QWN0aW9ucyA9IHBlcm1zLktFWV9SRUFEX0FDVElPTlMuY29uY2F0KHBlcm1zLktFWV9XUklURV9BQ1RJT05TKTtcbiAgICByZXR1cm4gdGhpcy5jb21iaW5lZEdyYW50KGdyYW50ZWUsIHsga2V5QWN0aW9ucywgdGFibGVBY3Rpb25zIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcm1pdHMgYWxsIER5bmFtb0RCIG9wZXJhdGlvbnMgKFwiZHluYW1vZGI6KlwiKSB0byBhbiBJQU0gcHJpbmNpcGFsLlxuICAgKlxuICAgKiBBcHByb3ByaWF0ZSBncmFudHMgd2lsbCBhbHNvIGJlIGFkZGVkIHRvIHRoZSBjdXN0b21lci1tYW5hZ2VkIEtNUyBrZXlcbiAgICogaWYgb25lIHdhcyBjb25maWd1cmVkLlxuICAgKlxuICAgKiBAcGFyYW0gZ3JhbnRlZSBUaGUgcHJpbmNpcGFsIHRvIGdyYW50IGFjY2VzcyB0b1xuICAgKi9cbiAgcHVibGljIGdyYW50RnVsbEFjY2VzcyhncmFudGVlOiBpYW0uSUdyYW50YWJsZSkge1xuICAgIGNvbnN0IGtleUFjdGlvbnMgPSBwZXJtcy5LRVlfUkVBRF9BQ1RJT05TLmNvbmNhdChwZXJtcy5LRVlfV1JJVEVfQUNUSU9OUyk7XG4gICAgcmV0dXJuIHRoaXMuY29tYmluZWRHcmFudChncmFudGVlLCB7IGtleUFjdGlvbnMsIHRhYmxlQWN0aW9uczogWydkeW5hbW9kYjoqJ10gfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBnaXZlbiBuYW1lZCBtZXRyaWMgZm9yIHRoaXMgVGFibGVcbiAgICpcbiAgICogQnkgZGVmYXVsdCwgdGhlIG1ldHJpYyB3aWxsIGJlIGNhbGN1bGF0ZWQgYXMgYSBzdW0gb3ZlciBhIHBlcmlvZCBvZiA1IG1pbnV0ZXMuXG4gICAqIFlvdSBjYW4gY3VzdG9taXplIHRoaXMgYnkgdXNpbmcgdGhlIGBzdGF0aXN0aWNgIGFuZCBgcGVyaW9kYCBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcHVibGljIG1ldHJpYyhtZXRyaWNOYW1lOiBzdHJpbmcsIHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWMge1xuICAgIHJldHVybiBuZXcgY2xvdWR3YXRjaC5NZXRyaWMoe1xuICAgICAgbmFtZXNwYWNlOiAnQVdTL0R5bmFtb0RCJyxcbiAgICAgIG1ldHJpY05hbWUsXG4gICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgIFRhYmxlTmFtZTogdGhpcy50YWJsZU5hbWUsXG4gICAgICB9LFxuICAgICAgLi4ucHJvcHMsXG4gICAgfSkuYXR0YWNoVG8odGhpcyk7XG4gIH1cblxuICAvKipcbiAgICogTWV0cmljIGZvciB0aGUgY29uc3VtZWQgcmVhZCBjYXBhY2l0eSB1bml0cyB0aGlzIHRhYmxlXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQsIHRoZSBtZXRyaWMgd2lsbCBiZSBjYWxjdWxhdGVkIGFzIGEgc3VtIG92ZXIgYSBwZXJpb2Qgb2YgNSBtaW51dGVzLlxuICAgKiBZb3UgY2FuIGN1c3RvbWl6ZSB0aGlzIGJ5IHVzaW5nIHRoZSBgc3RhdGlzdGljYCBhbmQgYHBlcmlvZGAgcHJvcGVydGllcy5cbiAgICovXG4gIHB1YmxpYyBtZXRyaWNDb25zdW1lZFJlYWRDYXBhY2l0eVVuaXRzKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWMge1xuICAgIHJldHVybiB0aGlzLmNhbm5lZE1ldHJpYyhEeW5hbW9EQk1ldHJpY3MuY29uc3VtZWRSZWFkQ2FwYWNpdHlVbml0c1N1bSwgcHJvcHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldHJpYyBmb3IgdGhlIGNvbnN1bWVkIHdyaXRlIGNhcGFjaXR5IHVuaXRzIHRoaXMgdGFibGVcbiAgICpcbiAgICogQnkgZGVmYXVsdCwgdGhlIG1ldHJpYyB3aWxsIGJlIGNhbGN1bGF0ZWQgYXMgYSBzdW0gb3ZlciBhIHBlcmlvZCBvZiA1IG1pbnV0ZXMuXG4gICAqIFlvdSBjYW4gY3VzdG9taXplIHRoaXMgYnkgdXNpbmcgdGhlIGBzdGF0aXN0aWNgIGFuZCBgcGVyaW9kYCBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcHVibGljIG1ldHJpY0NvbnN1bWVkV3JpdGVDYXBhY2l0eVVuaXRzKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWMge1xuICAgIHJldHVybiB0aGlzLmNhbm5lZE1ldHJpYyhEeW5hbW9EQk1ldHJpY3MuY29uc3VtZWRXcml0ZUNhcGFjaXR5VW5pdHNTdW0sIHByb3BzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBzeXN0ZW0gZXJyb3JzIHRoaXMgdGFibGVcbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGBtZXRyaWNTeXN0ZW1FcnJvcnNGb3JPcGVyYXRpb25zYC5cbiAgICovXG4gIHB1YmxpYyBtZXRyaWNTeXN0ZW1FcnJvcnMocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgaWYgKCFwcm9wcz8uZGltZW5zaW9ucz8uT3BlcmF0aW9uICYmICFwcm9wcz8uZGltZW5zaW9uc01hcD8uT3BlcmF0aW9uKSB7XG4gICAgICAvLyAnT3BlcmF0aW9uJyBtdXN0IGJlIHBhc3NlZCBiZWNhdXNlIGl0cyBhbiBvcGVyYXRpb25hbCBtZXRyaWMuXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCInT3BlcmF0aW9uJyBkaW1lbnNpb24gbXVzdCBiZSBwYXNzZWQgZm9yIHRoZSAnU3lzdGVtRXJyb3JzJyBtZXRyaWMuXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGRpbWVuc2lvbnNNYXAgPSB7XG4gICAgICBUYWJsZU5hbWU6IHRoaXMudGFibGVOYW1lLFxuICAgICAgLi4ucHJvcHM/LmRpbWVuc2lvbnMgPz8ge30sXG4gICAgICAuLi5wcm9wcz8uZGltZW5zaW9uc01hcCA/PyB7fSxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHRoaXMubWV0cmljKCdTeXN0ZW1FcnJvcnMnLCB7IHN0YXRpc3RpYzogJ3N1bScsIC4uLnByb3BzLCBkaW1lbnNpb25zTWFwIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldHJpYyBmb3IgdGhlIHVzZXIgZXJyb3JzLiBOb3RlIHRoYXQgdGhpcyBtZXRyaWMgcmVwb3J0cyB1c2VyIGVycm9ycyBhY3Jvc3MgYWxsXG4gICAqIHRoZSB0YWJsZXMgaW4gdGhlIGFjY291bnQgYW5kIHJlZ2lvbiB0aGUgdGFibGUgcmVzaWRlcyBpbi5cbiAgICpcbiAgICogQnkgZGVmYXVsdCwgdGhlIG1ldHJpYyB3aWxsIGJlIGNhbGN1bGF0ZWQgYXMgYSBzdW0gb3ZlciBhIHBlcmlvZCBvZiA1IG1pbnV0ZXMuXG4gICAqIFlvdSBjYW4gY3VzdG9taXplIHRoaXMgYnkgdXNpbmcgdGhlIGBzdGF0aXN0aWNgIGFuZCBgcGVyaW9kYCBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcHVibGljIG1ldHJpY1VzZXJFcnJvcnMocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgaWYgKHByb3BzPy5kaW1lbnNpb25zKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCInZGltZW5zaW9ucycgaXMgbm90IHN1cHBvcnRlZCBmb3IgdGhlICdVc2VyRXJyb3JzJyBtZXRyaWNcIik7XG4gICAgfVxuXG4gICAgLy8gb3ZlcnJpZGluZyAnZGltZW5zaW9ucycgaGVyZSBiZWNhdXNlIHRoaXMgbWV0cmljIGlzIGFuIGFjY291bnQgbWV0cmljLlxuICAgIC8vIHNlZSAnVXNlckVycm9ycycgaW4gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2FtYXpvbmR5bmFtb2RiL2xhdGVzdC9kZXZlbG9wZXJndWlkZS9tZXRyaWNzLWRpbWVuc2lvbnMuaHRtbFxuICAgIHJldHVybiB0aGlzLm1ldHJpYygnVXNlckVycm9ycycsIHsgc3RhdGlzdGljOiAnc3VtJywgLi4ucHJvcHMsIGRpbWVuc2lvbnNNYXA6IHt9IH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldHJpYyBmb3IgdGhlIGNvbmRpdGlvbmFsIGNoZWNrIGZhaWxlZCByZXF1ZXN0cyB0aGlzIHRhYmxlXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQsIHRoZSBtZXRyaWMgd2lsbCBiZSBjYWxjdWxhdGVkIGFzIGEgc3VtIG92ZXIgYSBwZXJpb2Qgb2YgNSBtaW51dGVzLlxuICAgKiBZb3UgY2FuIGN1c3RvbWl6ZSB0aGlzIGJ5IHVzaW5nIHRoZSBgc3RhdGlzdGljYCBhbmQgYHBlcmlvZGAgcHJvcGVydGllcy5cbiAgICovXG4gIHB1YmxpYyBtZXRyaWNDb25kaXRpb25hbENoZWNrRmFpbGVkUmVxdWVzdHMocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgcmV0dXJuIHRoaXMubWV0cmljKCdDb25kaXRpb25hbENoZWNrRmFpbGVkUmVxdWVzdHMnLCB7IHN0YXRpc3RpYzogJ3N1bScsIC4uLnByb3BzIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEhvdyBtYW55IHJlcXVlc3RzIGFyZSB0aHJvdHRsZWQgb24gdGhpcyB0YWJsZVxuICAgKlxuICAgKiBEZWZhdWx0OiBzdW0gb3ZlciA1IG1pbnV0ZXNcbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgRG8gbm90IHVzZSB0aGlzIGZ1bmN0aW9uLiBJdCByZXR1cm5zIGFuIGludmFsaWQgbWV0cmljLiBVc2UgYG1ldHJpY1Rocm90dGxlZFJlcXVlc3RzRm9yT3BlcmF0aW9uYCBpbnN0ZWFkLlxuICAgKi9cbiAgcHVibGljIG1ldHJpY1Rocm90dGxlZFJlcXVlc3RzKHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWMge1xuICAgIHJldHVybiB0aGlzLm1ldHJpYygnVGhyb3R0bGVkUmVxdWVzdHMnLCB7IHN0YXRpc3RpYzogJ3N1bScsIC4uLnByb3BzIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEhvdyBtYW55IHJlcXVlc3RzIGFyZSB0aHJvdHRsZWQgb24gdGhpcyB0YWJsZSwgZm9yIHRoZSBnaXZlbiBvcGVyYXRpb25cbiAgICpcbiAgICogRGVmYXVsdDogc3VtIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBwdWJsaWMgbWV0cmljVGhyb3R0bGVkUmVxdWVzdHNGb3JPcGVyYXRpb24ob3BlcmF0aW9uOiBzdHJpbmcsIHByb3BzPzogY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zKTogY2xvdWR3YXRjaC5NZXRyaWMge1xuICAgIHJldHVybiBuZXcgY2xvdWR3YXRjaC5NZXRyaWMoe1xuICAgICAgLi4uRHluYW1vREJNZXRyaWNzLnRocm90dGxlZFJlcXVlc3RzU3VtKHsgT3BlcmF0aW9uOiBvcGVyYXRpb24sIFRhYmxlTmFtZTogdGhpcy50YWJsZU5hbWUgfSksXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KS5hdHRhY2hUbyh0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXRyaWMgZm9yIHRoZSBzdWNjZXNzZnVsIHJlcXVlc3QgbGF0ZW5jeSB0aGlzIHRhYmxlLlxuICAgKlxuICAgKiBCeSBkZWZhdWx0LCB0aGUgbWV0cmljIHdpbGwgYmUgY2FsY3VsYXRlZCBhcyBhbiBhdmVyYWdlIG92ZXIgYSBwZXJpb2Qgb2YgNSBtaW51dGVzLlxuICAgKiBZb3UgY2FuIGN1c3RvbWl6ZSB0aGlzIGJ5IHVzaW5nIHRoZSBgc3RhdGlzdGljYCBhbmQgYHBlcmlvZGAgcHJvcGVydGllcy5cbiAgICovXG4gIHB1YmxpYyBtZXRyaWNTdWNjZXNzZnVsUmVxdWVzdExhdGVuY3kocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgaWYgKCFwcm9wcz8uZGltZW5zaW9ucz8uT3BlcmF0aW9uICYmICFwcm9wcz8uZGltZW5zaW9uc01hcD8uT3BlcmF0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCInT3BlcmF0aW9uJyBkaW1lbnNpb24gbXVzdCBiZSBwYXNzZWQgZm9yIHRoZSAnU3VjY2Vzc2Z1bFJlcXVlc3RMYXRlbmN5JyBtZXRyaWMuXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IGRpbWVuc2lvbnNNYXAgPSB7XG4gICAgICBUYWJsZU5hbWU6IHRoaXMudGFibGVOYW1lLFxuICAgICAgT3BlcmF0aW9uOiBwcm9wcy5kaW1lbnNpb25zTWFwPy5PcGVyYXRpb24gPz8gcHJvcHMuZGltZW5zaW9ucz8uT3BlcmF0aW9uLFxuICAgIH07XG5cbiAgICByZXR1cm4gbmV3IGNsb3Vkd2F0Y2guTWV0cmljKHtcbiAgICAgIC4uLkR5bmFtb0RCTWV0cmljcy5zdWNjZXNzZnVsUmVxdWVzdExhdGVuY3lBdmVyYWdlKGRpbWVuc2lvbnNNYXApLFxuICAgICAgLi4ucHJvcHMsXG4gICAgICBkaW1lbnNpb25zTWFwLFxuICAgIH0pLmF0dGFjaFRvKHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ldHJpYyBmb3IgdGhlIHN5c3RlbSBlcnJvcnMgdGhpcyB0YWJsZS5cbiAgICpcbiAgICogVGhpcyB3aWxsIHN1bSBlcnJvcnMgYWNyb3NzIGFsbCBwb3NzaWJsZSBvcGVyYXRpb25zLlxuICAgKiBOb3RlIHRoYXQgYnkgZGVmYXVsdCwgZWFjaCBpbmRpdmlkdWFsIG1ldHJpYyB3aWxsIGJlIGNhbGN1bGF0ZWQgYXMgYSBzdW0gb3ZlciBhIHBlcmlvZCBvZiA1IG1pbnV0ZXMuXG4gICAqIFlvdSBjYW4gY3VzdG9taXplIHRoaXMgYnkgdXNpbmcgdGhlIGBzdGF0aXN0aWNgIGFuZCBgcGVyaW9kYCBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcHVibGljIG1ldHJpY1N5c3RlbUVycm9yc0Zvck9wZXJhdGlvbnMocHJvcHM/OiBTeXN0ZW1FcnJvcnNGb3JPcGVyYXRpb25zTWV0cmljT3B0aW9ucyk6IGNsb3Vkd2F0Y2guSU1ldHJpYyB7XG5cbiAgICBpZiAocHJvcHM/LmRpbWVuc2lvbnM/Lk9wZXJhdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhlIE9wZXJhdGlvbiBkaW1lbnNpb24gaXMgbm90IHN1cHBvcnRlZC4gVXNlIHRoZSAnb3BlcmF0aW9ucycgcHJvcGVydHkuXCIpO1xuICAgIH1cblxuICAgIGNvbnN0IG9wZXJhdGlvbnMgPSBwcm9wcz8ub3BlcmF0aW9ucyA/PyBPYmplY3QudmFsdWVzKE9wZXJhdGlvbik7XG5cbiAgICBjb25zdCB2YWx1ZXMgPSB0aGlzLmNyZWF0ZU1ldHJpY3NGb3JPcGVyYXRpb25zKCdTeXN0ZW1FcnJvcnMnLCBvcGVyYXRpb25zLCB7IHN0YXRpc3RpYzogJ3N1bScsIC4uLnByb3BzIH0pO1xuXG4gICAgY29uc3Qgc3VtID0gbmV3IGNsb3Vkd2F0Y2guTWF0aEV4cHJlc3Npb24oe1xuICAgICAgZXhwcmVzc2lvbjogYCR7T2JqZWN0LmtleXModmFsdWVzKS5qb2luKCcgKyAnKX1gLFxuICAgICAgdXNpbmdNZXRyaWNzOiB7IC4uLnZhbHVlcyB9LFxuICAgICAgY29sb3I6IHByb3BzPy5jb2xvcixcbiAgICAgIGxhYmVsOiAnU3VtIG9mIGVycm9ycyBhY3Jvc3MgYWxsIG9wZXJhdGlvbnMnLFxuICAgICAgcGVyaW9kOiBwcm9wcz8ucGVyaW9kLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHN1bTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBtYXAgb2YgbWV0cmljcyB0aGF0IGNhbiBiZSB1c2VkIGluIGEgbWF0aCBleHByZXNzaW9uLlxuICAgKlxuICAgKiBVc2luZyB0aGUgcmV0dXJuIHZhbHVlIG9mIHRoaXMgZnVuY3Rpb24gYXMgdGhlIGB1c2luZ01ldHJpY3NgIHByb3BlcnR5IGluIGBjbG91ZHdhdGNoLk1hdGhFeHByZXNzaW9uYCBhbGxvd3MgeW91IHRvXG4gICAqIHVzZSB0aGUga2V5cyBvZiB0aGlzIG1hcCBhcyBtZXRyaWMgbmFtZXMgaW5zaWRlIHlvdSBleHByZXNzaW9uLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0cmljTmFtZSBUaGUgbWV0cmljIG5hbWUuXG4gICAqIEBwYXJhbSBvcGVyYXRpb25zIFRoZSBsaXN0IG9mIG9wZXJhdGlvbnMgdG8gY3JlYXRlIG1ldHJpY3MgZm9yLlxuICAgKiBAcGFyYW0gcHJvcHMgUHJvcGVydGllcyBmb3IgdGhlIGluZGl2aWR1YWwgbWV0cmljcy5cbiAgICogQHBhcmFtIG1ldHJpY05hbWVNYXBwZXIgTWFwcGVyIGZ1bmN0aW9uIHRvIGFsbG93IGNvbnRyb2xsaW5nIHRoZSBpbmRpdmlkdWFsIG1ldHJpYyBuYW1lIHBlciBvcGVyYXRpb24uXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZU1ldHJpY3NGb3JPcGVyYXRpb25zKG1ldHJpY05hbWU6IHN0cmluZywgb3BlcmF0aW9uczogT3BlcmF0aW9uW10sXG4gICAgcHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMsIG1ldHJpY05hbWVNYXBwZXI/OiAob3A6IE9wZXJhdGlvbikgPT4gc3RyaW5nKTogUmVjb3JkPHN0cmluZywgY2xvdWR3YXRjaC5JTWV0cmljPiB7XG5cbiAgICBjb25zdCBtZXRyaWNzOiBSZWNvcmQ8c3RyaW5nLCBjbG91ZHdhdGNoLklNZXRyaWM+ID0ge307XG5cbiAgICBjb25zdCBtYXBwZXIgPSBtZXRyaWNOYW1lTWFwcGVyID8/IChvcCA9PiBvcC50b0xvd2VyQ2FzZSgpKTtcblxuICAgIGlmIChwcm9wcz8uZGltZW5zaW9ucz8uT3BlcmF0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcHJvcGVydGllcy4gT3BlcmF0aW9uIGRpbWVuc2lvbiBpcyBub3Qgc3VwcG9ydGVkIHdoZW4gY2FsY3VsYXRpbmcgb3BlcmF0aW9uYWwgbWV0cmljcycpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qgb3BlcmF0aW9uIG9mIG9wZXJhdGlvbnMpIHtcblxuICAgICAgY29uc3QgbWV0cmljID0gdGhpcy5tZXRyaWMobWV0cmljTmFtZSwge1xuICAgICAgICAuLi5wcm9wcyxcbiAgICAgICAgZGltZW5zaW9uc01hcDoge1xuICAgICAgICAgIFRhYmxlTmFtZTogdGhpcy50YWJsZU5hbWUsXG4gICAgICAgICAgT3BlcmF0aW9uOiBvcGVyYXRpb24sXG4gICAgICAgICAgLi4ucHJvcHM/LmRpbWVuc2lvbnMsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgY29uc3Qgb3BlcmF0aW9uTWV0cmljTmFtZSA9IG1hcHBlcihvcGVyYXRpb24pO1xuICAgICAgY29uc3QgZmlyc3RDaGFyID0gb3BlcmF0aW9uTWV0cmljTmFtZS5jaGFyQXQoMCk7XG5cbiAgICAgIGlmIChmaXJzdENoYXIgPT09IGZpcnN0Q2hhci50b1VwcGVyQ2FzZSgpKSB7XG4gICAgICAgIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25DbG91ZFdhdGNoL2xhdGVzdC9tb25pdG9yaW5nL3VzaW5nLW1ldHJpYy1tYXRoLmh0bWwjbWV0cmljLW1hdGgtc3ludGF4XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgTWFwcGVyIGdlbmVyYXRlZCBhbiBpbGxlZ2FsIG9wZXJhdGlvbiBtZXRyaWMgbmFtZTogJHtvcGVyYXRpb25NZXRyaWNOYW1lfS4gTXVzdCBzdGFydCB3aXRoIGEgbG93ZXJjYXNlIGxldHRlcmApO1xuICAgICAgfVxuXG4gICAgICBtZXRyaWNzW29wZXJhdGlvbk1ldHJpY05hbWVdID0gbWV0cmljO1xuICAgIH1cblxuICAgIHJldHVybiBtZXRyaWNzO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGdldCBoYXNJbmRleCgpOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBZGRzIGFuIElBTSBwb2xpY3kgc3RhdGVtZW50IGFzc29jaWF0ZWQgd2l0aCB0aGlzIHRhYmxlIHRvIGFuIElBTVxuICAgKiBwcmluY2lwYWwncyBwb2xpY3kuXG4gICAqIEBwYXJhbSBncmFudGVlIFRoZSBwcmluY2lwYWwgKG5vLW9wIGlmIHVuZGVmaW5lZClcbiAgICogQHBhcmFtIG9wdHMgT3B0aW9ucyBmb3Iga2V5QWN0aW9ucywgdGFibGVBY3Rpb25zIGFuZCBzdHJlYW1BY3Rpb25zXG4gICAqL1xuICBwcml2YXRlIGNvbWJpbmVkR3JhbnQoXG4gICAgZ3JhbnRlZTogaWFtLklHcmFudGFibGUsXG4gICAgb3B0czogeyBrZXlBY3Rpb25zPzogc3RyaW5nW10sIHRhYmxlQWN0aW9ucz86IHN0cmluZ1tdLCBzdHJlYW1BY3Rpb25zPzogc3RyaW5nW10gfSxcbiAgKTogaWFtLkdyYW50IHtcbiAgICBpZiAob3B0cy50YWJsZUFjdGlvbnMpIHtcbiAgICAgIGNvbnN0IHJlc291cmNlcyA9IFt0aGlzLnRhYmxlQXJuLFxuICAgICAgICBMYXp5LnN0cmluZyh7IHByb2R1Y2U6ICgpID0+IHRoaXMuaGFzSW5kZXggPyBgJHt0aGlzLnRhYmxlQXJufS9pbmRleC8qYCA6IEF3cy5OT19WQUxVRSB9KSxcbiAgICAgICAgLi4udGhpcy5yZWdpb25hbEFybnMsXG4gICAgICAgIC4uLnRoaXMucmVnaW9uYWxBcm5zLm1hcChhcm4gPT4gTGF6eS5zdHJpbmcoe1xuICAgICAgICAgIHByb2R1Y2U6ICgpID0+IHRoaXMuaGFzSW5kZXggPyBgJHthcm59L2luZGV4LypgIDogQXdzLk5PX1ZBTFVFLFxuICAgICAgICB9KSldO1xuICAgICAgY29uc3QgcmV0ID0gaWFtLkdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgICAgZ3JhbnRlZSxcbiAgICAgICAgYWN0aW9uczogb3B0cy50YWJsZUFjdGlvbnMsXG4gICAgICAgIHJlc291cmNlQXJuczogcmVzb3VyY2VzLFxuICAgICAgICBzY29wZTogdGhpcyxcbiAgICAgIH0pO1xuICAgICAgaWYgKHRoaXMuZW5jcnlwdGlvbktleSAmJiBvcHRzLmtleUFjdGlvbnMpIHtcbiAgICAgICAgdGhpcy5lbmNyeXB0aW9uS2V5LmdyYW50KGdyYW50ZWUsIC4uLm9wdHMua2V5QWN0aW9ucyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmV0O1xuICAgIH1cbiAgICBpZiAob3B0cy5zdHJlYW1BY3Rpb25zKSB7XG4gICAgICBpZiAoIXRoaXMudGFibGVTdHJlYW1Bcm4pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBEeW5hbW9EQiBTdHJlYW1zIG11c3QgYmUgZW5hYmxlZCBvbiB0aGUgdGFibGUgJHt0aGlzLm5vZGUucGF0aH1gKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJlc291cmNlcyA9IFt0aGlzLnRhYmxlU3RyZWFtQXJuXTtcbiAgICAgIGNvbnN0IHJldCA9IGlhbS5HcmFudC5hZGRUb1ByaW5jaXBhbCh7XG4gICAgICAgIGdyYW50ZWUsXG4gICAgICAgIGFjdGlvbnM6IG9wdHMuc3RyZWFtQWN0aW9ucyxcbiAgICAgICAgcmVzb3VyY2VBcm5zOiByZXNvdXJjZXMsXG4gICAgICAgIHNjb3BlOiB0aGlzLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmV0O1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYFVuZXhwZWN0ZWQgJ2FjdGlvbicsICR7b3B0cy50YWJsZUFjdGlvbnMgfHwgb3B0cy5zdHJlYW1BY3Rpb25zfWApO1xuICB9XG5cbiAgcHJpdmF0ZSBjYW5uZWRNZXRyaWMoXG4gICAgZm46IChkaW1zOiB7IFRhYmxlTmFtZTogc3RyaW5nIH0pID0+IGNsb3Vkd2F0Y2guTWV0cmljUHJvcHMsXG4gICAgcHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgcmV0dXJuIG5ldyBjbG91ZHdhdGNoLk1ldHJpYyh7XG4gICAgICAuLi5mbih7IFRhYmxlTmFtZTogdGhpcy50YWJsZU5hbWUgfSksXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KS5hdHRhY2hUbyh0aGlzKTtcbiAgfVxufVxuXG4vKipcbiAqIFByb3ZpZGVzIGEgRHluYW1vREIgdGFibGUuXG4gKi9cbmV4cG9ydCBjbGFzcyBUYWJsZSBleHRlbmRzIFRhYmxlQmFzZSB7XG4gIC8qKlxuICAgKiBQZXJtaXRzIGFuIElBTSBQcmluY2lwYWwgdG8gbGlzdCBhbGwgRHluYW1vREIgU3RyZWFtcy5cbiAgICogQGRlcHJlY2F0ZWQgVXNlIHtAbGluayAjZ3JhbnRUYWJsZUxpc3RTdHJlYW1zfSBmb3IgbW9yZSBncmFudWxhciBwZXJtaXNzaW9uXG4gICAqIEBwYXJhbSBncmFudGVlIFRoZSBwcmluY2lwYWwgKG5vLW9wIGlmIHVuZGVmaW5lZClcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ3JhbnRMaXN0U3RyZWFtcyhncmFudGVlOiBpYW0uSUdyYW50YWJsZSk6IGlhbS5HcmFudCB7XG4gICAgcmV0dXJuIGlhbS5HcmFudC5hZGRUb1ByaW5jaXBhbCh7XG4gICAgICBncmFudGVlLFxuICAgICAgYWN0aW9uczogWydkeW5hbW9kYjpMaXN0U3RyZWFtcyddLFxuICAgICAgcmVzb3VyY2VBcm5zOiBbJyonXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgVGFibGUgY29uc3RydWN0IHRoYXQgcmVwcmVzZW50cyBhbiBleHRlcm5hbCB0YWJsZSB2aWEgdGFibGUgbmFtZS5cbiAgICpcbiAgICogQHBhcmFtIHNjb3BlIFRoZSBwYXJlbnQgY3JlYXRpbmcgY29uc3RydWN0ICh1c3VhbGx5IGB0aGlzYCkuXG4gICAqIEBwYXJhbSBpZCBUaGUgY29uc3RydWN0J3MgbmFtZS5cbiAgICogQHBhcmFtIHRhYmxlTmFtZSBUaGUgdGFibGUncyBuYW1lLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmcm9tVGFibGVOYW1lKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHRhYmxlTmFtZTogc3RyaW5nKTogSVRhYmxlIHtcbiAgICByZXR1cm4gVGFibGUuZnJvbVRhYmxlQXR0cmlidXRlcyhzY29wZSwgaWQsIHsgdGFibGVOYW1lIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBUYWJsZSBjb25zdHJ1Y3QgdGhhdCByZXByZXNlbnRzIGFuIGV4dGVybmFsIHRhYmxlIHZpYSB0YWJsZSBhcm4uXG4gICAqXG4gICAqIEBwYXJhbSBzY29wZSBUaGUgcGFyZW50IGNyZWF0aW5nIGNvbnN0cnVjdCAodXN1YWxseSBgdGhpc2ApLlxuICAgKiBAcGFyYW0gaWQgVGhlIGNvbnN0cnVjdCdzIG5hbWUuXG4gICAqIEBwYXJhbSB0YWJsZUFybiBUaGUgdGFibGUncyBBUk4uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZyb21UYWJsZUFybihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCB0YWJsZUFybjogc3RyaW5nKTogSVRhYmxlIHtcbiAgICByZXR1cm4gVGFibGUuZnJvbVRhYmxlQXR0cmlidXRlcyhzY29wZSwgaWQsIHsgdGFibGVBcm4gfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIFRhYmxlIGNvbnN0cnVjdCB0aGF0IHJlcHJlc2VudHMgYW4gZXh0ZXJuYWwgdGFibGUuXG4gICAqXG4gICAqIEBwYXJhbSBzY29wZSBUaGUgcGFyZW50IGNyZWF0aW5nIGNvbnN0cnVjdCAodXN1YWxseSBgdGhpc2ApLlxuICAgKiBAcGFyYW0gaWQgVGhlIGNvbnN0cnVjdCdzIG5hbWUuXG4gICAqIEBwYXJhbSBhdHRycyBBIGBUYWJsZUF0dHJpYnV0ZXNgIG9iamVjdC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVRhYmxlQXR0cmlidXRlcyhzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBhdHRyczogVGFibGVBdHRyaWJ1dGVzKTogSVRhYmxlIHtcblxuICAgIGNsYXNzIEltcG9ydCBleHRlbmRzIFRhYmxlQmFzZSB7XG5cbiAgICAgIHB1YmxpYyByZWFkb25seSB0YWJsZU5hbWU6IHN0cmluZztcbiAgICAgIHB1YmxpYyByZWFkb25seSB0YWJsZUFybjogc3RyaW5nO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHRhYmxlU3RyZWFtQXJuPzogc3RyaW5nO1xuICAgICAgcHVibGljIHJlYWRvbmx5IGVuY3J5cHRpb25LZXk/OiBrbXMuSUtleTtcbiAgICAgIHByb3RlY3RlZCByZWFkb25seSBoYXNJbmRleCA9IChhdHRycy5nbG9iYWxJbmRleGVzID8/IFtdKS5sZW5ndGggPiAwIHx8XG4gICAgICAgIChhdHRycy5sb2NhbEluZGV4ZXMgPz8gW10pLmxlbmd0aCA+IDA7XG5cbiAgICAgIGNvbnN0cnVjdG9yKF90YWJsZUFybjogc3RyaW5nLCB0YWJsZU5hbWU6IHN0cmluZywgdGFibGVTdHJlYW1Bcm4/OiBzdHJpbmcpIHtcbiAgICAgICAgc3VwZXIoc2NvcGUsIGlkKTtcbiAgICAgICAgdGhpcy50YWJsZUFybiA9IF90YWJsZUFybjtcbiAgICAgICAgdGhpcy50YWJsZU5hbWUgPSB0YWJsZU5hbWU7XG4gICAgICAgIHRoaXMudGFibGVTdHJlYW1Bcm4gPSB0YWJsZVN0cmVhbUFybjtcbiAgICAgICAgdGhpcy5lbmNyeXB0aW9uS2V5ID0gYXR0cnMuZW5jcnlwdGlvbktleTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgbmFtZTogc3RyaW5nO1xuICAgIGxldCBhcm46IHN0cmluZztcbiAgICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHNjb3BlKTtcbiAgICBpZiAoIWF0dHJzLnRhYmxlTmFtZSkge1xuICAgICAgaWYgKCFhdHRycy50YWJsZUFybikgeyB0aHJvdyBuZXcgRXJyb3IoJ09uZSBvZiB0YWJsZU5hbWUgb3IgdGFibGVBcm4gaXMgcmVxdWlyZWQhJyk7IH1cblxuICAgICAgYXJuID0gYXR0cnMudGFibGVBcm47XG4gICAgICBjb25zdCBtYXliZVRhYmxlTmFtZSA9IHN0YWNrLnNwbGl0QXJuKGF0dHJzLnRhYmxlQXJuLCBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSkucmVzb3VyY2VOYW1lO1xuICAgICAgaWYgKCFtYXliZVRhYmxlTmFtZSkgeyB0aHJvdyBuZXcgRXJyb3IoJ0FSTiBmb3IgRHluYW1vREIgdGFibGUgbXVzdCBiZSBpbiB0aGUgZm9ybTogLi4uJyk7IH1cbiAgICAgIG5hbWUgPSBtYXliZVRhYmxlTmFtZTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGF0dHJzLnRhYmxlQXJuKSB7IHRocm93IG5ldyBFcnJvcignT25seSBvbmUgb2YgdGFibGVBcm4gb3IgdGFibGVOYW1lIGNhbiBiZSBwcm92aWRlZCcpOyB9XG4gICAgICBuYW1lID0gYXR0cnMudGFibGVOYW1lO1xuICAgICAgYXJuID0gc3RhY2suZm9ybWF0QXJuKHtcbiAgICAgICAgc2VydmljZTogJ2R5bmFtb2RiJyxcbiAgICAgICAgcmVzb3VyY2U6ICd0YWJsZScsXG4gICAgICAgIHJlc291cmNlTmFtZTogYXR0cnMudGFibGVOYW1lLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBJbXBvcnQoYXJuLCBuYW1lLCBhdHRycy50YWJsZVN0cmVhbUFybik7XG4gIH1cblxuICBwdWJsaWMgcmVhZG9ubHkgZW5jcnlwdGlvbktleT86IGttcy5JS2V5O1xuXG4gIC8qKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdGFibGVBcm46IHN0cmluZztcblxuICAvKipcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHRhYmxlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdGFibGVTdHJlYW1Bcm46IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBwcml2YXRlIHJlYWRvbmx5IHRhYmxlOiBDZm5UYWJsZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGtleVNjaGVtYSA9IG5ldyBBcnJheTxDZm5UYWJsZS5LZXlTY2hlbWFQcm9wZXJ0eT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBhdHRyaWJ1dGVEZWZpbml0aW9ucyA9IG5ldyBBcnJheTxDZm5UYWJsZS5BdHRyaWJ1dGVEZWZpbml0aW9uUHJvcGVydHk+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgZ2xvYmFsU2Vjb25kYXJ5SW5kZXhlcyA9IG5ldyBBcnJheTxDZm5UYWJsZS5HbG9iYWxTZWNvbmRhcnlJbmRleFByb3BlcnR5PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGxvY2FsU2Vjb25kYXJ5SW5kZXhlcyA9IG5ldyBBcnJheTxDZm5UYWJsZS5Mb2NhbFNlY29uZGFyeUluZGV4UHJvcGVydHk+KCk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBzZWNvbmRhcnlJbmRleFNjaGVtYXMgPSBuZXcgTWFwPHN0cmluZywgU2NoZW1hT3B0aW9ucz4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBub25LZXlBdHRyaWJ1dGVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgcHJpdmF0ZSByZWFkb25seSB0YWJsZVBhcnRpdGlvbktleTogQXR0cmlidXRlO1xuICBwcml2YXRlIHJlYWRvbmx5IHRhYmxlU29ydEtleT86IEF0dHJpYnV0ZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGJpbGxpbmdNb2RlOiBCaWxsaW5nTW9kZTtcbiAgcHJpdmF0ZSByZWFkb25seSB0YWJsZVNjYWxpbmc6IFNjYWxhYmxlQXR0cmlidXRlUGFpciA9IHt9O1xuICBwcml2YXRlIHJlYWRvbmx5IGluZGV4U2NhbGluZyA9IG5ldyBNYXA8c3RyaW5nLCBTY2FsYWJsZUF0dHJpYnV0ZVBhaXI+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2NhbGluZ1JvbGU6IGlhbS5JUm9sZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGdsb2JhbFJlcGxpY2FDdXN0b21SZXNvdXJjZXMgPSBuZXcgQXJyYXk8Q3VzdG9tUmVzb3VyY2U+KCk7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFRhYmxlUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIHBoeXNpY2FsTmFtZTogcHJvcHMudGFibGVOYW1lLFxuICAgIH0pO1xuXG4gICAgY29uc3QgeyBzc2VTcGVjaWZpY2F0aW9uLCBlbmNyeXB0aW9uS2V5IH0gPSB0aGlzLnBhcnNlRW5jcnlwdGlvbihwcm9wcyk7XG5cbiAgICBsZXQgc3RyZWFtU3BlY2lmaWNhdGlvbjogQ2ZuVGFibGUuU3RyZWFtU3BlY2lmaWNhdGlvblByb3BlcnR5IHwgdW5kZWZpbmVkO1xuICAgIGlmIChwcm9wcy5yZXBsaWNhdGlvblJlZ2lvbnMpIHtcbiAgICAgIGlmIChwcm9wcy5zdHJlYW0gJiYgcHJvcHMuc3RyZWFtICE9PSBTdHJlYW1WaWV3VHlwZS5ORVdfQU5EX09MRF9JTUFHRVMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdgc3RyZWFtYCBtdXN0IGJlIHNldCB0byBgTkVXX0FORF9PTERfSU1BR0VTYCB3aGVuIHNwZWNpZnlpbmcgYHJlcGxpY2F0aW9uUmVnaW9uc2AnKTtcbiAgICAgIH1cbiAgICAgIHN0cmVhbVNwZWNpZmljYXRpb24gPSB7IHN0cmVhbVZpZXdUeXBlOiBTdHJlYW1WaWV3VHlwZS5ORVdfQU5EX09MRF9JTUFHRVMgfTtcblxuICAgICAgdGhpcy5iaWxsaW5nTW9kZSA9IHByb3BzLmJpbGxpbmdNb2RlID8/IEJpbGxpbmdNb2RlLlBBWV9QRVJfUkVRVUVTVDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5iaWxsaW5nTW9kZSA9IHByb3BzLmJpbGxpbmdNb2RlID8/IEJpbGxpbmdNb2RlLlBST1ZJU0lPTkVEO1xuICAgICAgaWYgKHByb3BzLnN0cmVhbSkge1xuICAgICAgICBzdHJlYW1TcGVjaWZpY2F0aW9uID0geyBzdHJlYW1WaWV3VHlwZTogcHJvcHMuc3RyZWFtIH07XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMudmFsaWRhdGVQcm92aXNpb25pbmcocHJvcHMpO1xuXG4gICAgdGhpcy50YWJsZSA9IG5ldyBDZm5UYWJsZSh0aGlzLCAnUmVzb3VyY2UnLCB7XG4gICAgICB0YWJsZU5hbWU6IHRoaXMucGh5c2ljYWxOYW1lLFxuICAgICAga2V5U2NoZW1hOiB0aGlzLmtleVNjaGVtYSxcbiAgICAgIGF0dHJpYnV0ZURlZmluaXRpb25zOiB0aGlzLmF0dHJpYnV0ZURlZmluaXRpb25zLFxuICAgICAgZ2xvYmFsU2Vjb25kYXJ5SW5kZXhlczogTGF6eS5hbnkoeyBwcm9kdWNlOiAoKSA9PiB0aGlzLmdsb2JhbFNlY29uZGFyeUluZGV4ZXMgfSwgeyBvbWl0RW1wdHlBcnJheTogdHJ1ZSB9KSxcbiAgICAgIGxvY2FsU2Vjb25kYXJ5SW5kZXhlczogTGF6eS5hbnkoeyBwcm9kdWNlOiAoKSA9PiB0aGlzLmxvY2FsU2Vjb25kYXJ5SW5kZXhlcyB9LCB7IG9taXRFbXB0eUFycmF5OiB0cnVlIH0pLFxuICAgICAgcG9pbnRJblRpbWVSZWNvdmVyeVNwZWNpZmljYXRpb246IHByb3BzLnBvaW50SW5UaW1lUmVjb3ZlcnkgIT0gbnVsbCA/IHsgcG9pbnRJblRpbWVSZWNvdmVyeUVuYWJsZWQ6IHByb3BzLnBvaW50SW5UaW1lUmVjb3ZlcnkgfSA6IHVuZGVmaW5lZCxcbiAgICAgIGJpbGxpbmdNb2RlOiB0aGlzLmJpbGxpbmdNb2RlID09PSBCaWxsaW5nTW9kZS5QQVlfUEVSX1JFUVVFU1QgPyB0aGlzLmJpbGxpbmdNb2RlIDogdW5kZWZpbmVkLFxuICAgICAgcHJvdmlzaW9uZWRUaHJvdWdocHV0OiB0aGlzLmJpbGxpbmdNb2RlID09PSBCaWxsaW5nTW9kZS5QQVlfUEVSX1JFUVVFU1QgPyB1bmRlZmluZWQgOiB7XG4gICAgICAgIHJlYWRDYXBhY2l0eVVuaXRzOiBwcm9wcy5yZWFkQ2FwYWNpdHkgfHwgNSxcbiAgICAgICAgd3JpdGVDYXBhY2l0eVVuaXRzOiBwcm9wcy53cml0ZUNhcGFjaXR5IHx8IDUsXG4gICAgICB9LFxuICAgICAgc3NlU3BlY2lmaWNhdGlvbixcbiAgICAgIHN0cmVhbVNwZWNpZmljYXRpb24sXG4gICAgICB0YWJsZUNsYXNzOiBwcm9wcy50YWJsZUNsYXNzLFxuICAgICAgdGltZVRvTGl2ZVNwZWNpZmljYXRpb246IHByb3BzLnRpbWVUb0xpdmVBdHRyaWJ1dGUgPyB7IGF0dHJpYnV0ZU5hbWU6IHByb3BzLnRpbWVUb0xpdmVBdHRyaWJ1dGUsIGVuYWJsZWQ6IHRydWUgfSA6IHVuZGVmaW5lZCxcbiAgICAgIGNvbnRyaWJ1dG9ySW5zaWdodHNTcGVjaWZpY2F0aW9uOiBwcm9wcy5jb250cmlidXRvckluc2lnaHRzRW5hYmxlZCAhPT0gdW5kZWZpbmVkID8geyBlbmFibGVkOiBwcm9wcy5jb250cmlidXRvckluc2lnaHRzRW5hYmxlZCB9IDogdW5kZWZpbmVkLFxuICAgICAga2luZXNpc1N0cmVhbVNwZWNpZmljYXRpb246IHByb3BzLmtpbmVzaXNTdHJlYW0gPyB7IHN0cmVhbUFybjogcHJvcHMua2luZXNpc1N0cmVhbS5zdHJlYW1Bcm4gfSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcbiAgICB0aGlzLnRhYmxlLmFwcGx5UmVtb3ZhbFBvbGljeShwcm9wcy5yZW1vdmFsUG9saWN5KTtcblxuICAgIHRoaXMuZW5jcnlwdGlvbktleSA9IGVuY3J5cHRpb25LZXk7XG5cbiAgICB0aGlzLnRhYmxlQXJuID0gdGhpcy5nZXRSZXNvdXJjZUFybkF0dHJpYnV0ZSh0aGlzLnRhYmxlLmF0dHJBcm4sIHtcbiAgICAgIHNlcnZpY2U6ICdkeW5hbW9kYicsXG4gICAgICByZXNvdXJjZTogJ3RhYmxlJyxcbiAgICAgIHJlc291cmNlTmFtZTogdGhpcy5waHlzaWNhbE5hbWUsXG4gICAgfSk7XG4gICAgdGhpcy50YWJsZU5hbWUgPSB0aGlzLmdldFJlc291cmNlTmFtZUF0dHJpYnV0ZSh0aGlzLnRhYmxlLnJlZik7XG5cbiAgICBpZiAocHJvcHMudGFibGVOYW1lKSB7IHRoaXMubm9kZS5hZGRNZXRhZGF0YSgnYXdzOmNkazpoYXNQaHlzaWNhbE5hbWUnLCB0aGlzLnRhYmxlTmFtZSk7IH1cblxuICAgIHRoaXMudGFibGVTdHJlYW1Bcm4gPSBzdHJlYW1TcGVjaWZpY2F0aW9uID8gdGhpcy50YWJsZS5hdHRyU3RyZWFtQXJuIDogdW5kZWZpbmVkO1xuXG4gICAgdGhpcy5zY2FsaW5nUm9sZSA9IHRoaXMubWFrZVNjYWxpbmdSb2xlKCk7XG5cbiAgICB0aGlzLmFkZEtleShwcm9wcy5wYXJ0aXRpb25LZXksIEhBU0hfS0VZX1RZUEUpO1xuICAgIHRoaXMudGFibGVQYXJ0aXRpb25LZXkgPSBwcm9wcy5wYXJ0aXRpb25LZXk7XG5cbiAgICBpZiAocHJvcHMuc29ydEtleSkge1xuICAgICAgdGhpcy5hZGRLZXkocHJvcHMuc29ydEtleSwgUkFOR0VfS0VZX1RZUEUpO1xuICAgICAgdGhpcy50YWJsZVNvcnRLZXkgPSBwcm9wcy5zb3J0S2V5O1xuICAgIH1cblxuICAgIGlmIChwcm9wcy5yZXBsaWNhdGlvblJlZ2lvbnMgJiYgcHJvcHMucmVwbGljYXRpb25SZWdpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuY3JlYXRlUmVwbGljYVRhYmxlcyhwcm9wcy5yZXBsaWNhdGlvblJlZ2lvbnMsIHByb3BzLnJlcGxpY2F0aW9uVGltZW91dCwgcHJvcHMud2FpdEZvclJlcGxpY2F0aW9uVG9GaW5pc2gpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBnbG9iYWwgc2Vjb25kYXJ5IGluZGV4IG9mIHRhYmxlLlxuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgdGhlIHByb3BlcnR5IG9mIGdsb2JhbCBzZWNvbmRhcnkgaW5kZXhcbiAgICovXG4gIHB1YmxpYyBhZGRHbG9iYWxTZWNvbmRhcnlJbmRleChwcm9wczogR2xvYmFsU2Vjb25kYXJ5SW5kZXhQcm9wcykge1xuICAgIHRoaXMudmFsaWRhdGVQcm92aXNpb25pbmcocHJvcHMpO1xuICAgIHRoaXMudmFsaWRhdGVJbmRleE5hbWUocHJvcHMuaW5kZXhOYW1lKTtcblxuICAgIC8vIGJ1aWxkIGtleSBzY2hlbWEgYW5kIHByb2plY3Rpb24gZm9yIGluZGV4XG4gICAgY29uc3QgZ3NpS2V5U2NoZW1hID0gdGhpcy5idWlsZEluZGV4S2V5U2NoZW1hKHByb3BzLnBhcnRpdGlvbktleSwgcHJvcHMuc29ydEtleSk7XG4gICAgY29uc3QgZ3NpUHJvamVjdGlvbiA9IHRoaXMuYnVpbGRJbmRleFByb2plY3Rpb24ocHJvcHMpO1xuXG4gICAgdGhpcy5nbG9iYWxTZWNvbmRhcnlJbmRleGVzLnB1c2goe1xuICAgICAgaW5kZXhOYW1lOiBwcm9wcy5pbmRleE5hbWUsXG4gICAgICBrZXlTY2hlbWE6IGdzaUtleVNjaGVtYSxcbiAgICAgIHByb2plY3Rpb246IGdzaVByb2plY3Rpb24sXG4gICAgICBwcm92aXNpb25lZFRocm91Z2hwdXQ6IHRoaXMuYmlsbGluZ01vZGUgPT09IEJpbGxpbmdNb2RlLlBBWV9QRVJfUkVRVUVTVCA/IHVuZGVmaW5lZCA6IHtcbiAgICAgICAgcmVhZENhcGFjaXR5VW5pdHM6IHByb3BzLnJlYWRDYXBhY2l0eSB8fCA1LFxuICAgICAgICB3cml0ZUNhcGFjaXR5VW5pdHM6IHByb3BzLndyaXRlQ2FwYWNpdHkgfHwgNSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICB0aGlzLnNlY29uZGFyeUluZGV4U2NoZW1hcy5zZXQocHJvcHMuaW5kZXhOYW1lLCB7XG4gICAgICBwYXJ0aXRpb25LZXk6IHByb3BzLnBhcnRpdGlvbktleSxcbiAgICAgIHNvcnRLZXk6IHByb3BzLnNvcnRLZXksXG4gICAgfSk7XG5cbiAgICB0aGlzLmluZGV4U2NhbGluZy5zZXQocHJvcHMuaW5kZXhOYW1lLCB7fSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgbG9jYWwgc2Vjb25kYXJ5IGluZGV4IG9mIHRhYmxlLlxuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgdGhlIHByb3BlcnR5IG9mIGxvY2FsIHNlY29uZGFyeSBpbmRleFxuICAgKi9cbiAgcHVibGljIGFkZExvY2FsU2Vjb25kYXJ5SW5kZXgocHJvcHM6IExvY2FsU2Vjb25kYXJ5SW5kZXhQcm9wcykge1xuICAgIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9hbWF6b25keW5hbW9kYi9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvTGltaXRzLmh0bWwjbGltaXRzLXNlY29uZGFyeS1pbmRleGVzXG4gICAgaWYgKHRoaXMubG9jYWxTZWNvbmRhcnlJbmRleGVzLmxlbmd0aCA+PSBNQVhfTE9DQUxfU0VDT05EQVJZX0lOREVYX0NPVU5UKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihgYSBtYXhpbXVtIG51bWJlciBvZiBsb2NhbCBzZWNvbmRhcnkgaW5kZXggcGVyIHRhYmxlIGlzICR7TUFYX0xPQ0FMX1NFQ09OREFSWV9JTkRFWF9DT1VOVH1gKTtcbiAgICB9XG5cbiAgICB0aGlzLnZhbGlkYXRlSW5kZXhOYW1lKHByb3BzLmluZGV4TmFtZSk7XG5cbiAgICAvLyBidWlsZCBrZXkgc2NoZW1hIGFuZCBwcm9qZWN0aW9uIGZvciBpbmRleFxuICAgIGNvbnN0IGxzaUtleVNjaGVtYSA9IHRoaXMuYnVpbGRJbmRleEtleVNjaGVtYSh0aGlzLnRhYmxlUGFydGl0aW9uS2V5LCBwcm9wcy5zb3J0S2V5KTtcbiAgICBjb25zdCBsc2lQcm9qZWN0aW9uID0gdGhpcy5idWlsZEluZGV4UHJvamVjdGlvbihwcm9wcyk7XG5cbiAgICB0aGlzLmxvY2FsU2Vjb25kYXJ5SW5kZXhlcy5wdXNoKHtcbiAgICAgIGluZGV4TmFtZTogcHJvcHMuaW5kZXhOYW1lLFxuICAgICAga2V5U2NoZW1hOiBsc2lLZXlTY2hlbWEsXG4gICAgICBwcm9qZWN0aW9uOiBsc2lQcm9qZWN0aW9uLFxuICAgIH0pO1xuXG4gICAgdGhpcy5zZWNvbmRhcnlJbmRleFNjaGVtYXMuc2V0KHByb3BzLmluZGV4TmFtZSwge1xuICAgICAgcGFydGl0aW9uS2V5OiB0aGlzLnRhYmxlUGFydGl0aW9uS2V5LFxuICAgICAgc29ydEtleTogcHJvcHMuc29ydEtleSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmFibGUgcmVhZCBjYXBhY2l0eSBzY2FsaW5nIGZvciB0aGlzIHRhYmxlXG4gICAqXG4gICAqIEByZXR1cm5zIEFuIG9iamVjdCB0byBjb25maWd1cmUgYWRkaXRpb25hbCBBdXRvU2NhbGluZyBzZXR0aW5nc1xuICAgKi9cbiAgcHVibGljIGF1dG9TY2FsZVJlYWRDYXBhY2l0eShwcm9wczogRW5hYmxlU2NhbGluZ1Byb3BzKTogSVNjYWxhYmxlVGFibGVBdHRyaWJ1dGUge1xuICAgIGlmICh0aGlzLnRhYmxlU2NhbGluZy5zY2FsYWJsZVJlYWRBdHRyaWJ1dGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignUmVhZCBBdXRvU2NhbGluZyBhbHJlYWR5IGVuYWJsZWQgZm9yIHRoaXMgdGFibGUnKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuYmlsbGluZ01vZGUgPT09IEJpbGxpbmdNb2RlLlBBWV9QRVJfUkVRVUVTVCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBdXRvU2NhbGluZyBpcyBub3QgYXZhaWxhYmxlIGZvciB0YWJsZXMgd2l0aCBQQVlfUEVSX1JFUVVFU1QgYmlsbGluZyBtb2RlJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudGFibGVTY2FsaW5nLnNjYWxhYmxlUmVhZEF0dHJpYnV0ZSA9IG5ldyBTY2FsYWJsZVRhYmxlQXR0cmlidXRlKHRoaXMsICdSZWFkU2NhbGluZycsIHtcbiAgICAgIHNlcnZpY2VOYW1lc3BhY2U6IGFwcHNjYWxpbmcuU2VydmljZU5hbWVzcGFjZS5EWU5BTU9EQixcbiAgICAgIHJlc291cmNlSWQ6IGB0YWJsZS8ke3RoaXMudGFibGVOYW1lfWAsXG4gICAgICBkaW1lbnNpb246ICdkeW5hbW9kYjp0YWJsZTpSZWFkQ2FwYWNpdHlVbml0cycsXG4gICAgICByb2xlOiB0aGlzLnNjYWxpbmdSb2xlLFxuICAgICAgLi4ucHJvcHMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRW5hYmxlIHdyaXRlIGNhcGFjaXR5IHNjYWxpbmcgZm9yIHRoaXMgdGFibGVcbiAgICpcbiAgICogQHJldHVybnMgQW4gb2JqZWN0IHRvIGNvbmZpZ3VyZSBhZGRpdGlvbmFsIEF1dG9TY2FsaW5nIHNldHRpbmdzIGZvciB0aGlzIGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIGF1dG9TY2FsZVdyaXRlQ2FwYWNpdHkocHJvcHM6IEVuYWJsZVNjYWxpbmdQcm9wcyk6IElTY2FsYWJsZVRhYmxlQXR0cmlidXRlIHtcbiAgICBpZiAodGhpcy50YWJsZVNjYWxpbmcuc2NhbGFibGVXcml0ZUF0dHJpYnV0ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdXcml0ZSBBdXRvU2NhbGluZyBhbHJlYWR5IGVuYWJsZWQgZm9yIHRoaXMgdGFibGUnKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuYmlsbGluZ01vZGUgPT09IEJpbGxpbmdNb2RlLlBBWV9QRVJfUkVRVUVTVCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBdXRvU2NhbGluZyBpcyBub3QgYXZhaWxhYmxlIGZvciB0YWJsZXMgd2l0aCBQQVlfUEVSX1JFUVVFU1QgYmlsbGluZyBtb2RlJyk7XG4gICAgfVxuXG4gICAgdGhpcy50YWJsZVNjYWxpbmcuc2NhbGFibGVXcml0ZUF0dHJpYnV0ZSA9IG5ldyBTY2FsYWJsZVRhYmxlQXR0cmlidXRlKHRoaXMsICdXcml0ZVNjYWxpbmcnLCB7XG4gICAgICBzZXJ2aWNlTmFtZXNwYWNlOiBhcHBzY2FsaW5nLlNlcnZpY2VOYW1lc3BhY2UuRFlOQU1PREIsXG4gICAgICByZXNvdXJjZUlkOiBgdGFibGUvJHt0aGlzLnRhYmxlTmFtZX1gLFxuICAgICAgZGltZW5zaW9uOiAnZHluYW1vZGI6dGFibGU6V3JpdGVDYXBhY2l0eVVuaXRzJyxcbiAgICAgIHJvbGU6IHRoaXMuc2NhbGluZ1JvbGUsXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KTtcbiAgICBmb3IgKGNvbnN0IGdsb2JhbFJlcGxpY2FDdXN0b21SZXNvdXJjZSBvZiB0aGlzLmdsb2JhbFJlcGxpY2FDdXN0b21SZXNvdXJjZXMpIHtcbiAgICAgIGdsb2JhbFJlcGxpY2FDdXN0b21SZXNvdXJjZS5ub2RlLmFkZERlcGVuZGVuY3kodGhpcy50YWJsZVNjYWxpbmcuc2NhbGFibGVXcml0ZUF0dHJpYnV0ZSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnRhYmxlU2NhbGluZy5zY2FsYWJsZVdyaXRlQXR0cmlidXRlO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuYWJsZSByZWFkIGNhcGFjaXR5IHNjYWxpbmcgZm9yIHRoZSBnaXZlbiBHU0lcbiAgICpcbiAgICogQHJldHVybnMgQW4gb2JqZWN0IHRvIGNvbmZpZ3VyZSBhZGRpdGlvbmFsIEF1dG9TY2FsaW5nIHNldHRpbmdzIGZvciB0aGlzIGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIGF1dG9TY2FsZUdsb2JhbFNlY29uZGFyeUluZGV4UmVhZENhcGFjaXR5KGluZGV4TmFtZTogc3RyaW5nLCBwcm9wczogRW5hYmxlU2NhbGluZ1Byb3BzKTogSVNjYWxhYmxlVGFibGVBdHRyaWJ1dGUge1xuICAgIGlmICh0aGlzLmJpbGxpbmdNb2RlID09PSBCaWxsaW5nTW9kZS5QQVlfUEVSX1JFUVVFU1QpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQXV0b1NjYWxpbmcgaXMgbm90IGF2YWlsYWJsZSBmb3IgdGFibGVzIHdpdGggUEFZX1BFUl9SRVFVRVNUIGJpbGxpbmcgbW9kZScpO1xuICAgIH1cbiAgICBjb25zdCBhdHRyaWJ1dGVQYWlyID0gdGhpcy5pbmRleFNjYWxpbmcuZ2V0KGluZGV4TmFtZSk7XG4gICAgaWYgKCFhdHRyaWJ1dGVQYWlyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGdsb2JhbCBzZWNvbmRhcnkgaW5kZXggd2l0aCBuYW1lICR7aW5kZXhOYW1lfWApO1xuICAgIH1cbiAgICBpZiAoYXR0cmlidXRlUGFpci5zY2FsYWJsZVJlYWRBdHRyaWJ1dGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignUmVhZCBBdXRvU2NhbGluZyBhbHJlYWR5IGVuYWJsZWQgZm9yIHRoaXMgaW5kZXgnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXR0cmlidXRlUGFpci5zY2FsYWJsZVJlYWRBdHRyaWJ1dGUgPSBuZXcgU2NhbGFibGVUYWJsZUF0dHJpYnV0ZSh0aGlzLCBgJHtpbmRleE5hbWV9UmVhZFNjYWxpbmdgLCB7XG4gICAgICBzZXJ2aWNlTmFtZXNwYWNlOiBhcHBzY2FsaW5nLlNlcnZpY2VOYW1lc3BhY2UuRFlOQU1PREIsXG4gICAgICByZXNvdXJjZUlkOiBgdGFibGUvJHt0aGlzLnRhYmxlTmFtZX0vaW5kZXgvJHtpbmRleE5hbWV9YCxcbiAgICAgIGRpbWVuc2lvbjogJ2R5bmFtb2RiOmluZGV4OlJlYWRDYXBhY2l0eVVuaXRzJyxcbiAgICAgIHJvbGU6IHRoaXMuc2NhbGluZ1JvbGUsXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmFibGUgd3JpdGUgY2FwYWNpdHkgc2NhbGluZyBmb3IgdGhlIGdpdmVuIEdTSVxuICAgKlxuICAgKiBAcmV0dXJucyBBbiBvYmplY3QgdG8gY29uZmlndXJlIGFkZGl0aW9uYWwgQXV0b1NjYWxpbmcgc2V0dGluZ3MgZm9yIHRoaXMgYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgYXV0b1NjYWxlR2xvYmFsU2Vjb25kYXJ5SW5kZXhXcml0ZUNhcGFjaXR5KGluZGV4TmFtZTogc3RyaW5nLCBwcm9wczogRW5hYmxlU2NhbGluZ1Byb3BzKTogSVNjYWxhYmxlVGFibGVBdHRyaWJ1dGUge1xuICAgIGlmICh0aGlzLmJpbGxpbmdNb2RlID09PSBCaWxsaW5nTW9kZS5QQVlfUEVSX1JFUVVFU1QpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQXV0b1NjYWxpbmcgaXMgbm90IGF2YWlsYWJsZSBmb3IgdGFibGVzIHdpdGggUEFZX1BFUl9SRVFVRVNUIGJpbGxpbmcgbW9kZScpO1xuICAgIH1cbiAgICBjb25zdCBhdHRyaWJ1dGVQYWlyID0gdGhpcy5pbmRleFNjYWxpbmcuZ2V0KGluZGV4TmFtZSk7XG4gICAgaWYgKCFhdHRyaWJ1dGVQYWlyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGdsb2JhbCBzZWNvbmRhcnkgaW5kZXggd2l0aCBuYW1lICR7aW5kZXhOYW1lfWApO1xuICAgIH1cbiAgICBpZiAoYXR0cmlidXRlUGFpci5zY2FsYWJsZVdyaXRlQXR0cmlidXRlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1dyaXRlIEF1dG9TY2FsaW5nIGFscmVhZHkgZW5hYmxlZCBmb3IgdGhpcyBpbmRleCcpO1xuICAgIH1cblxuICAgIHJldHVybiBhdHRyaWJ1dGVQYWlyLnNjYWxhYmxlV3JpdGVBdHRyaWJ1dGUgPSBuZXcgU2NhbGFibGVUYWJsZUF0dHJpYnV0ZSh0aGlzLCBgJHtpbmRleE5hbWV9V3JpdGVTY2FsaW5nYCwge1xuICAgICAgc2VydmljZU5hbWVzcGFjZTogYXBwc2NhbGluZy5TZXJ2aWNlTmFtZXNwYWNlLkRZTkFNT0RCLFxuICAgICAgcmVzb3VyY2VJZDogYHRhYmxlLyR7dGhpcy50YWJsZU5hbWV9L2luZGV4LyR7aW5kZXhOYW1lfWAsXG4gICAgICBkaW1lbnNpb246ICdkeW5hbW9kYjppbmRleDpXcml0ZUNhcGFjaXR5VW5pdHMnLFxuICAgICAgcm9sZTogdGhpcy5zY2FsaW5nUm9sZSxcbiAgICAgIC4uLnByb3BzLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBzY2hlbWEgYXR0cmlidXRlcyBvZiB0YWJsZSBvciBpbmRleC5cbiAgICpcbiAgICogQHJldHVybnMgU2NoZW1hIG9mIHRhYmxlIG9yIGluZGV4LlxuICAgKi9cbiAgcHVibGljIHNjaGVtYShpbmRleE5hbWU/OiBzdHJpbmcpOiBTY2hlbWFPcHRpb25zIHtcbiAgICBpZiAoIWluZGV4TmFtZSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcGFydGl0aW9uS2V5OiB0aGlzLnRhYmxlUGFydGl0aW9uS2V5LFxuICAgICAgICBzb3J0S2V5OiB0aGlzLnRhYmxlU29ydEtleSxcbiAgICAgIH07XG4gICAgfVxuICAgIGxldCBzY2hlbWEgPSB0aGlzLnNlY29uZGFyeUluZGV4U2NoZW1hcy5nZXQoaW5kZXhOYW1lKTtcbiAgICBpZiAoIXNjaGVtYSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgZmluZCBzY2hlbWEgZm9yIGluZGV4OiAke2luZGV4TmFtZX0uIFVzZSAnYWRkR2xvYmFsU2Vjb25kYXJ5SW5kZXgnIG9yICdhZGRMb2NhbFNlY29uZGFyeUluZGV4JyB0byBhZGQgaW5kZXhgKTtcbiAgICB9XG4gICAgcmV0dXJuIHNjaGVtYTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgdGFibGUgY29uc3RydWN0LlxuICAgKlxuICAgKiBAcmV0dXJucyBhbiBhcnJheSBvZiB2YWxpZGF0aW9uIGVycm9yIG1lc3NhZ2VcbiAgICovXG4gIHByb3RlY3RlZCB2YWxpZGF0ZSgpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgZXJyb3JzID0gbmV3IEFycmF5PHN0cmluZz4oKTtcblxuICAgIGlmICghdGhpcy50YWJsZVBhcnRpdGlvbktleSkge1xuICAgICAgZXJyb3JzLnB1c2goJ2EgcGFydGl0aW9uIGtleSBtdXN0IGJlIHNwZWNpZmllZCcpO1xuICAgIH1cbiAgICBpZiAodGhpcy5sb2NhbFNlY29uZGFyeUluZGV4ZXMubGVuZ3RoID4gMCAmJiAhdGhpcy50YWJsZVNvcnRLZXkpIHtcbiAgICAgIGVycm9ycy5wdXNoKCdhIHNvcnQga2V5IG9mIHRoZSB0YWJsZSBtdXN0IGJlIHNwZWNpZmllZCB0byBhZGQgbG9jYWwgc2Vjb25kYXJ5IGluZGV4ZXMnKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5nbG9iYWxSZXBsaWNhQ3VzdG9tUmVzb3VyY2VzLmxlbmd0aCA+IDAgJiYgdGhpcy5iaWxsaW5nTW9kZSA9PT0gQmlsbGluZ01vZGUuUFJPVklTSU9ORUQpIHtcbiAgICAgIGNvbnN0IHdyaXRlQXV0b1NjYWxlQXR0cmlidXRlID0gdGhpcy50YWJsZVNjYWxpbmcuc2NhbGFibGVXcml0ZUF0dHJpYnV0ZTtcbiAgICAgIGlmICghd3JpdGVBdXRvU2NhbGVBdHRyaWJ1dGUpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goJ0EgZ2xvYmFsIFRhYmxlIHRoYXQgdXNlcyBQUk9WSVNJT05FRCBhcyB0aGUgYmlsbGluZyBtb2RlIG5lZWRzIGF1dG8tc2NhbGVkIHdyaXRlIGNhcGFjaXR5LiAnICtcbiAgICAgICAgICAnVXNlIHRoZSBhdXRvU2NhbGVXcml0ZUNhcGFjaXR5KCkgbWV0aG9kIHRvIGVuYWJsZSBpdC4nKTtcbiAgICAgIH0gZWxzZSBpZiAoIXdyaXRlQXV0b1NjYWxlQXR0cmlidXRlLl9zY2FsaW5nUG9saWN5Q3JlYXRlZCkge1xuICAgICAgICBlcnJvcnMucHVzaCgnQSBnbG9iYWwgVGFibGUgdGhhdCB1c2VzIFBST1ZJU0lPTkVEIGFzIHRoZSBiaWxsaW5nIG1vZGUgbmVlZHMgYXV0by1zY2FsZWQgd3JpdGUgY2FwYWNpdHkgd2l0aCBhIHBvbGljeS4gJyArXG4gICAgICAgICAgJ0NhbGwgb25lIG9mIHRoZSBzY2FsZU9uKigpIG1ldGhvZHMgb2YgdGhlIG9iamVjdCByZXR1cm5lZCBmcm9tIGF1dG9TY2FsZVdyaXRlQ2FwYWNpdHkoKScpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBlcnJvcnM7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgcmVhZCBhbmQgd3JpdGUgY2FwYWNpdHkgYXJlIG5vdCBzcGVjaWZpZWQgZm9yIG9uLWRlbWFuZCB0YWJsZXMgKGJpbGxpbmcgbW9kZSBQQVlfUEVSX1JFUVVFU1QpLlxuICAgKlxuICAgKiBAcGFyYW0gcHJvcHMgcmVhZCBhbmQgd3JpdGUgY2FwYWNpdHkgcHJvcGVydGllc1xuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZVByb3Zpc2lvbmluZyhwcm9wczogeyByZWFkQ2FwYWNpdHk/OiBudW1iZXIsIHdyaXRlQ2FwYWNpdHk/OiBudW1iZXIgfSk6IHZvaWQge1xuICAgIGlmICh0aGlzLmJpbGxpbmdNb2RlID09PSBCaWxsaW5nTW9kZS5QQVlfUEVSX1JFUVVFU1QpIHtcbiAgICAgIGlmIChwcm9wcy5yZWFkQ2FwYWNpdHkgIT09IHVuZGVmaW5lZCB8fCBwcm9wcy53cml0ZUNhcGFjaXR5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd5b3UgY2Fubm90IHByb3Zpc2lvbiByZWFkIGFuZCB3cml0ZSBjYXBhY2l0eSBmb3IgYSB0YWJsZSB3aXRoIFBBWV9QRVJfUkVRVUVTVCBiaWxsaW5nIG1vZGUnKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgaW5kZXggbmFtZSB0byBjaGVjayBpZiBhIGR1cGxpY2F0ZSBuYW1lIGFscmVhZHkgZXhpc3RzLlxuICAgKlxuICAgKiBAcGFyYW0gaW5kZXhOYW1lIGEgbmFtZSBvZiBnbG9iYWwgb3IgbG9jYWwgc2Vjb25kYXJ5IGluZGV4XG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlSW5kZXhOYW1lKGluZGV4TmFtZTogc3RyaW5nKSB7XG4gICAgaWYgKHRoaXMuc2Vjb25kYXJ5SW5kZXhTY2hlbWFzLmhhcyhpbmRleE5hbWUpKSB7XG4gICAgICAvLyBhIGR1cGxpY2F0ZSBpbmRleCBuYW1lIGNhdXNlcyB2YWxpZGF0aW9uIGV4Y2VwdGlvbiwgc3RhdHVzIGNvZGUgNDAwLCB3aGlsZSB0cnlpbmcgdG8gY3JlYXRlIENGTiBzdGFja1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBhIGR1cGxpY2F0ZSBpbmRleCBuYW1lLCAke2luZGV4TmFtZX0sIGlzIG5vdCBhbGxvd2VkYCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIG5vbi1rZXkgYXR0cmlidXRlcyBieSBjaGVja2luZyBsaW1pdHMgd2l0aGluIHNlY29uZGFyeSBpbmRleCwgd2hpY2ggbWF5IHZhcnkgaW4gZnV0dXJlLlxuICAgKlxuICAgKiBAcGFyYW0gbm9uS2V5QXR0cmlidXRlcyBhIGxpc3Qgb2Ygbm9uLWtleSBhdHRyaWJ1dGUgbmFtZXNcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVOb25LZXlBdHRyaWJ1dGVzKG5vbktleUF0dHJpYnV0ZXM6IHN0cmluZ1tdKSB7XG4gICAgaWYgKHRoaXMubm9uS2V5QXR0cmlidXRlcy5zaXplICsgbm9uS2V5QXR0cmlidXRlcy5sZW5ndGggPiAxMDApIHtcbiAgICAgIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9hbWF6b25keW5hbW9kYi9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvTGltaXRzLmh0bWwjbGltaXRzLXNlY29uZGFyeS1pbmRleGVzXG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignYSBtYXhpbXVtIG51bWJlciBvZiBub25LZXlBdHRyaWJ1dGVzIGFjcm9zcyBhbGwgb2Ygc2Vjb25kYXJ5IGluZGV4ZXMgaXMgMTAwJyk7XG4gICAgfVxuXG4gICAgLy8gc3RvcmUgYWxsIG5vbi1rZXkgYXR0cmlidXRlc1xuICAgIG5vbktleUF0dHJpYnV0ZXMuZm9yRWFjaChhdHQgPT4gdGhpcy5ub25LZXlBdHRyaWJ1dGVzLmFkZChhdHQpKTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRJbmRleEtleVNjaGVtYShwYXJ0aXRpb25LZXk6IEF0dHJpYnV0ZSwgc29ydEtleT86IEF0dHJpYnV0ZSk6IENmblRhYmxlLktleVNjaGVtYVByb3BlcnR5W10ge1xuICAgIHRoaXMucmVnaXN0ZXJBdHRyaWJ1dGUocGFydGl0aW9uS2V5KTtcbiAgICBjb25zdCBpbmRleEtleVNjaGVtYTogQ2ZuVGFibGUuS2V5U2NoZW1hUHJvcGVydHlbXSA9IFtcbiAgICAgIHsgYXR0cmlidXRlTmFtZTogcGFydGl0aW9uS2V5Lm5hbWUsIGtleVR5cGU6IEhBU0hfS0VZX1RZUEUgfSxcbiAgICBdO1xuXG4gICAgaWYgKHNvcnRLZXkpIHtcbiAgICAgIHRoaXMucmVnaXN0ZXJBdHRyaWJ1dGUoc29ydEtleSk7XG4gICAgICBpbmRleEtleVNjaGVtYS5wdXNoKHsgYXR0cmlidXRlTmFtZTogc29ydEtleS5uYW1lLCBrZXlUeXBlOiBSQU5HRV9LRVlfVFlQRSB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gaW5kZXhLZXlTY2hlbWE7XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkSW5kZXhQcm9qZWN0aW9uKHByb3BzOiBTZWNvbmRhcnlJbmRleFByb3BzKTogQ2ZuVGFibGUuUHJvamVjdGlvblByb3BlcnR5IHtcbiAgICBpZiAocHJvcHMucHJvamVjdGlvblR5cGUgPT09IFByb2plY3Rpb25UeXBlLklOQ0xVREUgJiYgIXByb3BzLm5vbktleUF0dHJpYnV0ZXMpIHtcbiAgICAgIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2F3cy1wcm9wZXJ0aWVzLWR5bmFtb2RiLXByb2plY3Rpb25vYmplY3QuaHRtbFxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBub24ta2V5IGF0dHJpYnV0ZXMgc2hvdWxkIGJlIHNwZWNpZmllZCB3aGVuIHVzaW5nICR7UHJvamVjdGlvblR5cGUuSU5DTFVERX0gcHJvamVjdGlvbiB0eXBlYCk7XG4gICAgfVxuXG4gICAgaWYgKHByb3BzLnByb2plY3Rpb25UeXBlICE9PSBQcm9qZWN0aW9uVHlwZS5JTkNMVURFICYmIHByb3BzLm5vbktleUF0dHJpYnV0ZXMpIHtcbiAgICAgIC8vIHRoaXMgY29tYmluYXRpb24gY2F1c2VzIHZhbGlkYXRpb24gZXhjZXB0aW9uLCBzdGF0dXMgY29kZSA0MDAsIHdoaWxlIHRyeWluZyB0byBjcmVhdGUgQ0ZOIHN0YWNrXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYG5vbi1rZXkgYXR0cmlidXRlcyBzaG91bGQgbm90IGJlIHNwZWNpZmllZCB3aGVuIG5vdCB1c2luZyAke1Byb2plY3Rpb25UeXBlLklOQ0xVREV9IHByb2plY3Rpb24gdHlwZWApO1xuICAgIH1cblxuICAgIGlmIChwcm9wcy5ub25LZXlBdHRyaWJ1dGVzKSB7XG4gICAgICB0aGlzLnZhbGlkYXRlTm9uS2V5QXR0cmlidXRlcyhwcm9wcy5ub25LZXlBdHRyaWJ1dGVzKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgcHJvamVjdGlvblR5cGU6IHByb3BzLnByb2plY3Rpb25UeXBlID8/IFByb2plY3Rpb25UeXBlLkFMTCxcbiAgICAgIG5vbktleUF0dHJpYnV0ZXM6IHByb3BzLm5vbktleUF0dHJpYnV0ZXMgPz8gdW5kZWZpbmVkLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGZpbmRLZXkoa2V5VHlwZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHRoaXMua2V5U2NoZW1hLmZpbmQocHJvcCA9PiBwcm9wLmtleVR5cGUgPT09IGtleVR5cGUpO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRLZXkoYXR0cmlidXRlOiBBdHRyaWJ1dGUsIGtleVR5cGU6IHN0cmluZykge1xuICAgIGNvbnN0IGV4aXN0aW5nUHJvcCA9IHRoaXMuZmluZEtleShrZXlUeXBlKTtcbiAgICBpZiAoZXhpc3RpbmdQcm9wKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byBzZXQgJHthdHRyaWJ1dGUubmFtZX0gYXMgYSAke2tleVR5cGV9IGtleSwgYmVjYXVzZSAke2V4aXN0aW5nUHJvcC5hdHRyaWJ1dGVOYW1lfSBpcyBhICR7a2V5VHlwZX0ga2V5YCk7XG4gICAgfVxuICAgIHRoaXMucmVnaXN0ZXJBdHRyaWJ1dGUoYXR0cmlidXRlKTtcbiAgICB0aGlzLmtleVNjaGVtYS5wdXNoKHtcbiAgICAgIGF0dHJpYnV0ZU5hbWU6IGF0dHJpYnV0ZS5uYW1lLFxuICAgICAga2V5VHlwZSxcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciB0aGUga2V5IGF0dHJpYnV0ZSBvZiB0YWJsZSBvciBzZWNvbmRhcnkgaW5kZXggdG8gYXNzZW1ibGUgYXR0cmlidXRlIGRlZmluaXRpb25zIG9mIFRhYmxlUmVzb3VyY2VQcm9wcy5cbiAgICpcbiAgICogQHBhcmFtIGF0dHJpYnV0ZSB0aGUga2V5IGF0dHJpYnV0ZSBvZiB0YWJsZSBvciBzZWNvbmRhcnkgaW5kZXhcbiAgICovXG4gIHByaXZhdGUgcmVnaXN0ZXJBdHRyaWJ1dGUoYXR0cmlidXRlOiBBdHRyaWJ1dGUpIHtcbiAgICBjb25zdCB7IG5hbWUsIHR5cGUgfSA9IGF0dHJpYnV0ZTtcbiAgICBjb25zdCBleGlzdGluZ0RlZiA9IHRoaXMuYXR0cmlidXRlRGVmaW5pdGlvbnMuZmluZChkZWYgPT4gZGVmLmF0dHJpYnV0ZU5hbWUgPT09IG5hbWUpO1xuICAgIGlmIChleGlzdGluZ0RlZiAmJiBleGlzdGluZ0RlZi5hdHRyaWJ1dGVUeXBlICE9PSB0eXBlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byBzcGVjaWZ5ICR7bmFtZX0gYXMgJHt0eXBlfSBiZWNhdXNlIGl0IHdhcyBhbHJlYWR5IGRlZmluZWQgYXMgJHtleGlzdGluZ0RlZi5hdHRyaWJ1dGVUeXBlfWApO1xuICAgIH1cbiAgICBpZiAoIWV4aXN0aW5nRGVmKSB7XG4gICAgICB0aGlzLmF0dHJpYnV0ZURlZmluaXRpb25zLnB1c2goe1xuICAgICAgICBhdHRyaWJ1dGVOYW1lOiBuYW1lLFxuICAgICAgICBhdHRyaWJ1dGVUeXBlOiB0eXBlLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgcm9sZSB0aGF0IHdpbGwgYmUgdXNlZCBmb3IgQXV0b1NjYWxpbmdcbiAgICovXG4gIHByaXZhdGUgbWFrZVNjYWxpbmdSb2xlKCk6IGlhbS5JUm9sZSB7XG4gICAgLy8gVXNlIGEgU2VydmljZSBMaW5rZWQgUm9sZS5cbiAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vYXV0b3NjYWxpbmcvYXBwbGljYXRpb24vdXNlcmd1aWRlL2FwcGxpY2F0aW9uLWF1dG8tc2NhbGluZy1zZXJ2aWNlLWxpbmtlZC1yb2xlcy5odG1sXG4gICAgcmV0dXJuIGlhbS5Sb2xlLmZyb21Sb2xlQXJuKHRoaXMsICdTY2FsaW5nUm9sZScsIFN0YWNrLm9mKHRoaXMpLmZvcm1hdEFybih7XG4gICAgICBzZXJ2aWNlOiAnaWFtJyxcbiAgICAgIHJlZ2lvbjogJycsXG4gICAgICByZXNvdXJjZTogJ3JvbGUvYXdzLXNlcnZpY2Utcm9sZS9keW5hbW9kYi5hcHBsaWNhdGlvbi1hdXRvc2NhbGluZy5hbWF6b25hd3MuY29tJyxcbiAgICAgIHJlc291cmNlTmFtZTogJ0FXU1NlcnZpY2VSb2xlRm9yQXBwbGljYXRpb25BdXRvU2NhbGluZ19EeW5hbW9EQlRhYmxlJyxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyByZXBsaWNhIHRhYmxlc1xuICAgKlxuICAgKiBAcGFyYW0gcmVnaW9ucyByZWdpb25zIHdoZXJlIHRvIGNyZWF0ZSB0YWJsZXNcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlUmVwbGljYVRhYmxlcyhyZWdpb25zOiBzdHJpbmdbXSwgdGltZW91dD86IER1cmF0aW9uLCB3YWl0Rm9yUmVwbGljYXRpb25Ub0ZpbmlzaD86IGJvb2xlYW4pIHtcbiAgICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHRoaXMpO1xuXG4gICAgaWYgKCFUb2tlbi5pc1VucmVzb2x2ZWQoc3RhY2sucmVnaW9uKSAmJiByZWdpb25zLmluY2x1ZGVzKHN0YWNrLnJlZ2lvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignYHJlcGxpY2F0aW9uUmVnaW9uc2AgY2Fubm90IGluY2x1ZGUgdGhlIHJlZ2lvbiB3aGVyZSB0aGlzIHN0YWNrIGlzIGRlcGxveWVkLicpO1xuICAgIH1cblxuICAgIGNvbnN0IHByb3ZpZGVyID0gUmVwbGljYVByb3ZpZGVyLmdldE9yQ3JlYXRlKHRoaXMsIHsgdGltZW91dCB9KTtcblxuICAgIC8vIERvY3VtZW50YXRpb24gYXQgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2FtYXpvbmR5bmFtb2RiL2xhdGVzdC9kZXZlbG9wZXJndWlkZS9WMmd0X0lBTS5odG1sXG4gICAgLy8gaXMgY3VycmVudGx5IGluY29ycmVjdC4gQVdTIFN1cHBvcnQgcmVjb21tZW5kcyBgZHluYW1vZGI6KmAgaW4gYm90aCBzb3VyY2UgYW5kIGRlc3RpbmF0aW9uIHJlZ2lvbnNcblxuICAgIGNvbnN0IG9uRXZlbnRIYW5kbGVyUG9saWN5ID0gbmV3IFNvdXJjZVRhYmxlQXR0YWNoZWRQb2xpY3kodGhpcywgcHJvdmlkZXIub25FdmVudEhhbmRsZXIucm9sZSEpO1xuICAgIGNvbnN0IGlzQ29tcGxldGVIYW5kbGVyUG9saWN5ID0gbmV3IFNvdXJjZVRhYmxlQXR0YWNoZWRQb2xpY3kodGhpcywgcHJvdmlkZXIuaXNDb21wbGV0ZUhhbmRsZXIucm9sZSEpO1xuXG4gICAgLy8gUGVybWlzc2lvbnMgaW4gdGhlIHNvdXJjZSByZWdpb25cbiAgICB0aGlzLmdyYW50KG9uRXZlbnRIYW5kbGVyUG9saWN5LCAnZHluYW1vZGI6KicpO1xuICAgIHRoaXMuZ3JhbnQoaXNDb21wbGV0ZUhhbmRsZXJQb2xpY3ksICdkeW5hbW9kYjpEZXNjcmliZVRhYmxlJyk7XG5cbiAgICBsZXQgcHJldmlvdXNSZWdpb246IEN1c3RvbVJlc291cmNlIHwgdW5kZWZpbmVkO1xuICAgIGxldCBwcmV2aW91c1JlZ2lvbkNvbmRpdGlvbjogQ2ZuQ29uZGl0aW9uIHwgdW5kZWZpbmVkO1xuICAgIGZvciAoY29uc3QgcmVnaW9uIG9mIG5ldyBTZXQocmVnaW9ucykpIHsgLy8gUmVtb3ZlIGR1cGxpY2F0ZXNcbiAgICAgIC8vIFVzZSBtdWx0aXBsZSBjdXN0b20gcmVzb3VyY2VzIGJlY2F1c2UgbXVsdGlwbGUgY3JlYXRlL2RlbGV0ZVxuICAgICAgLy8gdXBkYXRlcyBjYW5ub3QgYmUgY29tYmluZWQgaW4gYSBzaW5nbGUgQVBJIGNhbGwuXG4gICAgICBjb25zdCBjdXJyZW50UmVnaW9uID0gbmV3IEN1c3RvbVJlc291cmNlKHRoaXMsIGBSZXBsaWNhJHtyZWdpb259YCwge1xuICAgICAgICBzZXJ2aWNlVG9rZW46IHByb3ZpZGVyLnByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgICAgcmVzb3VyY2VUeXBlOiAnQ3VzdG9tOjpEeW5hbW9EQlJlcGxpY2EnLFxuICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgVGFibGVOYW1lOiB0aGlzLnRhYmxlTmFtZSxcbiAgICAgICAgICBSZWdpb246IHJlZ2lvbixcbiAgICAgICAgICBTa2lwUmVwbGljYXRpb25Db21wbGV0ZWRXYWl0OiB3YWl0Rm9yUmVwbGljYXRpb25Ub0ZpbmlzaCA9PSBudWxsXG4gICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgLy8gQ0ZOIGNoYW5nZXMgQ3VzdG9tIFJlc291cmNlIHByb3BlcnRpZXMgdG8gc3RyaW5ncyBhbnl3YXlzLFxuICAgICAgICAgICAgLy8gc28gbGV0J3MgZG8gdGhhdCBvdXJzZWx2ZXMgdG8gbWFrZSBpdCBjbGVhciBpbiB0aGUgaGFuZGxlciB0aGlzIGlzIGEgc3RyaW5nLCBub3QgYSBib29sZWFuXG4gICAgICAgICAgICA6ICghd2FpdEZvclJlcGxpY2F0aW9uVG9GaW5pc2gpLnRvU3RyaW5nKCksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIGN1cnJlbnRSZWdpb24ubm9kZS5hZGREZXBlbmRlbmN5KFxuICAgICAgICBvbkV2ZW50SGFuZGxlclBvbGljeS5wb2xpY3ksXG4gICAgICAgIGlzQ29tcGxldGVIYW5kbGVyUG9saWN5LnBvbGljeSxcbiAgICAgICk7XG4gICAgICB0aGlzLmdsb2JhbFJlcGxpY2FDdXN0b21SZXNvdXJjZXMucHVzaChjdXJyZW50UmVnaW9uKTtcblxuICAgICAgLy8gRGVwbG95IHRpbWUgY2hlY2sgdG8gcHJldmVudCBmcm9tIGNyZWF0aW5nIGEgcmVwbGljYSBpbiB0aGUgcmVnaW9uXG4gICAgICAvLyB3aGVyZSB0aGlzIHN0YWNrIGlzIGRlcGxveWVkLiBPbmx5IG5lZWRlZCBmb3IgZW52aXJvbm1lbnQgYWdub3N0aWNcbiAgICAgIC8vIHN0YWNrcy5cbiAgICAgIGxldCBjcmVhdGVSZXBsaWNhOiBDZm5Db25kaXRpb24gfCB1bmRlZmluZWQ7XG4gICAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKHN0YWNrLnJlZ2lvbikpIHtcbiAgICAgICAgY3JlYXRlUmVwbGljYSA9IG5ldyBDZm5Db25kaXRpb24odGhpcywgYFN0YWNrUmVnaW9uTm90RXF1YWxzJHtyZWdpb259YCwge1xuICAgICAgICAgIGV4cHJlc3Npb246IEZuLmNvbmRpdGlvbk5vdChGbi5jb25kaXRpb25FcXVhbHMocmVnaW9uLCBBd3MuUkVHSU9OKSksXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBjZm5DdXN0b21SZXNvdXJjZSA9IGN1cnJlbnRSZWdpb24ubm9kZS5kZWZhdWx0Q2hpbGQgYXMgQ2ZuQ3VzdG9tUmVzb3VyY2U7XG4gICAgICAgIGNmbkN1c3RvbVJlc291cmNlLmNmbk9wdGlvbnMuY29uZGl0aW9uID0gY3JlYXRlUmVwbGljYTtcbiAgICAgIH1cblxuICAgICAgLy8gU2F2ZSByZWdpb25hbCBhcm5zIGZvciBncmFudFh4eCgpIG1ldGhvZHNcbiAgICAgIHRoaXMucmVnaW9uYWxBcm5zLnB1c2goc3RhY2suZm9ybWF0QXJuKHtcbiAgICAgICAgcmVnaW9uLFxuICAgICAgICBzZXJ2aWNlOiAnZHluYW1vZGInLFxuICAgICAgICByZXNvdXJjZTogJ3RhYmxlJyxcbiAgICAgICAgcmVzb3VyY2VOYW1lOiB0aGlzLnRhYmxlTmFtZSxcbiAgICAgIH0pKTtcblxuICAgICAgLy8gV2UgbmVlZCB0byBjcmVhdGUvZGVsZXRlIHJlZ2lvbnMgc2VxdWVudGlhbGx5IGJlY2F1c2Ugd2UgY2Fubm90XG4gICAgICAvLyBoYXZlIG11bHRpcGxlIHRhYmxlIHVwZGF0ZXMgYXQgdGhlIHNhbWUgdGltZS4gVGhlIGBpc0NvbXBsZXRlSGFuZGxlcmBcbiAgICAgIC8vIG9mIHRoZSBwcm92aWRlciB3YWl0cyB1bnRpbCB0aGUgcmVwbGljYSBpcyBpbiBhbiBBQ1RJVkUgc3RhdGUuXG4gICAgICBpZiAocHJldmlvdXNSZWdpb24pIHtcbiAgICAgICAgaWYgKHByZXZpb3VzUmVnaW9uQ29uZGl0aW9uKSB7XG4gICAgICAgICAgLy8gd2UgY2FuJ3Qgc2ltcGx5IHVzZSBhIERlcGVuZGVuY3ksXG4gICAgICAgICAgLy8gYmVjYXVzZSB0aGUgcHJldmlvdXNSZWdpb24gaXMgcHJvdGVjdGVkIGJ5IHRoZSBcImRpZmZlcmVudCByZWdpb25cIiBDb25kaXRpb24sXG4gICAgICAgICAgLy8gYW5kIHlvdSBjYW4ndCBoYXZlIEZuOjpJZiBpbiBEZXBlbmRzT24uXG4gICAgICAgICAgLy8gSW5zdGVhZCwgcmVseSBvbiBSZWYgYWRkaW5nIGEgZGVwZW5kZW5jeSBpbXBsaWNpdGx5IVxuICAgICAgICAgIGNvbnN0IHByZXZpb3VzUmVnaW9uQ2ZuUmVzb3VyY2UgPSBwcmV2aW91c1JlZ2lvbi5ub2RlLmRlZmF1bHRDaGlsZCBhcyBDZm5SZXNvdXJjZTtcbiAgICAgICAgICBjb25zdCBjdXJyZW50UmVnaW9uQ2ZuUmVzb3VyY2UgPSBjdXJyZW50UmVnaW9uLm5vZGUuZGVmYXVsdENoaWxkIGFzIENmblJlc291cmNlO1xuICAgICAgICAgIGN1cnJlbnRSZWdpb25DZm5SZXNvdXJjZS5hZGRNZXRhZGF0YSgnRHluYW1vRGJSZXBsaWNhdGlvbkRlcGVuZGVuY3knLFxuICAgICAgICAgICAgRm4uY29uZGl0aW9uSWYocHJldmlvdXNSZWdpb25Db25kaXRpb24ubG9naWNhbElkLCBwcmV2aW91c1JlZ2lvbkNmblJlc291cmNlLnJlZiwgQXdzLk5PX1ZBTFVFKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY3VycmVudFJlZ2lvbi5ub2RlLmFkZERlcGVuZGVuY3kocHJldmlvdXNSZWdpb24pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHByZXZpb3VzUmVnaW9uID0gY3VycmVudFJlZ2lvbjtcbiAgICAgIHByZXZpb3VzUmVnaW9uQ29uZGl0aW9uID0gY3JlYXRlUmVwbGljYTtcbiAgICB9XG5cbiAgICAvLyBQZXJtaXNzaW9ucyBpbiB0aGUgZGVzdGluYXRpb24gcmVnaW9ucyAob3V0c2lkZSBvZiB0aGUgbG9vcCB0b1xuICAgIC8vIG1pbmltaXplIHN0YXRlbWVudHMgaW4gdGhlIHBvbGljeSlcbiAgICBvbkV2ZW50SGFuZGxlclBvbGljeS5ncmFudFByaW5jaXBhbC5hZGRUb1ByaW5jaXBhbFBvbGljeShuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICBhY3Rpb25zOiBbJ2R5bmFtb2RiOionXSxcbiAgICAgIHJlc291cmNlczogdGhpcy5yZWdpb25hbEFybnMsXG4gICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhpcyB0YWJsZSBoYXMgaW5kZXhlc1xuICAgKi9cbiAgcHJvdGVjdGVkIGdldCBoYXNJbmRleCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5nbG9iYWxTZWNvbmRhcnlJbmRleGVzLmxlbmd0aCArIHRoaXMubG9jYWxTZWNvbmRhcnlJbmRleGVzLmxlbmd0aCA+IDA7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHVwIGtleSBwcm9wZXJ0aWVzIGFuZCByZXR1cm4gdGhlIFRhYmxlIGVuY3J5cHRpb24gcHJvcGVydHkgZnJvbSB0aGVcbiAgICogdXNlcidzIGNvbmZpZ3VyYXRpb24uXG4gICAqL1xuICBwcml2YXRlIHBhcnNlRW5jcnlwdGlvbihwcm9wczogVGFibGVQcm9wcyk6IHsgc3NlU3BlY2lmaWNhdGlvbjogQ2ZuVGFibGVQcm9wc1snc3NlU3BlY2lmaWNhdGlvbiddLCBlbmNyeXB0aW9uS2V5Pzoga21zLklLZXkgfSB7XG4gICAgbGV0IGVuY3J5cHRpb25UeXBlID0gcHJvcHMuZW5jcnlwdGlvbjtcblxuICAgIGlmIChlbmNyeXB0aW9uVHlwZSAhPSBudWxsICYmIHByb3BzLnNlcnZlclNpZGVFbmNyeXB0aW9uICE9IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignT25seSBvbmUgb2YgZW5jcnlwdGlvbiBhbmQgc2VydmVyU2lkZUVuY3J5cHRpb24gY2FuIGJlIHNwZWNpZmllZCwgYnV0IGJvdGggd2VyZSBwcm92aWRlZCcpO1xuICAgIH1cblxuICAgIGlmIChwcm9wcy5zZXJ2ZXJTaWRlRW5jcnlwdGlvbiAmJiBwcm9wcy5lbmNyeXB0aW9uS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2VuY3J5cHRpb25LZXkgY2Fubm90IGJlIHNwZWNpZmllZCB3aGVuIHNlcnZlclNpZGVFbmNyeXB0aW9uIGlzIHNwZWNpZmllZC4gVXNlIGVuY3J5cHRpb24gaW5zdGVhZCcpO1xuICAgIH1cblxuICAgIGlmIChlbmNyeXB0aW9uVHlwZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBlbmNyeXB0aW9uVHlwZSA9IHByb3BzLmVuY3J5cHRpb25LZXkgIT0gbnVsbFxuICAgICAgICAvLyBJZiB0aGVyZSBpcyBhIGNvbmZpZ3VyZWQgZW5jcnlwdGlvbktleSwgdGhlIGVuY3J5cHRpb24gaXMgaW1wbGljaXRseSBDVVNUT01FUl9NQU5BR0VEXG4gICAgICAgID8gVGFibGVFbmNyeXB0aW9uLkNVU1RPTUVSX01BTkFHRURcbiAgICAgICAgLy8gT3RoZXJ3aXNlLCBpZiBzZXZlclNpZGVFbmNyeXB0aW9uIGlzIGVuYWJsZWQsIGl0J3MgQVdTX01BTkFHRUQ7IGVsc2UgdW5kZWZpbmVkIChkbyBub3Qgc2V0IGFueXRoaW5nKVxuICAgICAgICA6IHByb3BzLnNlcnZlclNpZGVFbmNyeXB0aW9uID8gVGFibGVFbmNyeXB0aW9uLkFXU19NQU5BR0VEIDogdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGlmIChlbmNyeXB0aW9uVHlwZSAhPT0gVGFibGVFbmNyeXB0aW9uLkNVU1RPTUVSX01BTkFHRUQgJiYgcHJvcHMuZW5jcnlwdGlvbktleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdgZW5jcnlwdGlvbktleSBjYW5ub3QgYmUgc3BlY2lmaWVkIHVubGVzcyBlbmNyeXB0aW9uIGlzIHNldCB0byBUYWJsZUVuY3J5cHRpb24uQ1VTVE9NRVJfTUFOQUdFRCAoaXQgd2FzIHNldCB0byAke2VuY3J5cHRpb25UeXBlfSlgJyk7XG4gICAgfVxuXG4gICAgaWYgKGVuY3J5cHRpb25UeXBlID09PSBUYWJsZUVuY3J5cHRpb24uQ1VTVE9NRVJfTUFOQUdFRCAmJiBwcm9wcy5yZXBsaWNhdGlvblJlZ2lvbnMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVGFibGVFbmNyeXB0aW9uLkNVU1RPTUVSX01BTkFHRUQgaXMgbm90IHN1cHBvcnRlZCBieSBEeW5hbW9EQiBHbG9iYWwgVGFibGVzICh3aGVyZSByZXBsaWNhdGlvblJlZ2lvbnMgd2FzIHNldCknKTtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKGVuY3J5cHRpb25UeXBlKSB7XG4gICAgICBjYXNlIFRhYmxlRW5jcnlwdGlvbi5DVVNUT01FUl9NQU5BR0VEOlxuICAgICAgICBjb25zdCBlbmNyeXB0aW9uS2V5ID0gcHJvcHMuZW5jcnlwdGlvbktleSA/PyBuZXcga21zLktleSh0aGlzLCAnS2V5Jywge1xuICAgICAgICAgIGRlc2NyaXB0aW9uOiBgQ3VzdG9tZXItbWFuYWdlZCBrZXkgYXV0by1jcmVhdGVkIGZvciBlbmNyeXB0aW5nIER5bmFtb0RCIHRhYmxlIGF0ICR7dGhpcy5ub2RlLnBhdGh9YCxcbiAgICAgICAgICBlbmFibGVLZXlSb3RhdGlvbjogdHJ1ZSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzc2VTcGVjaWZpY2F0aW9uOiB7IHNzZUVuYWJsZWQ6IHRydWUsIGttc01hc3RlcktleUlkOiBlbmNyeXB0aW9uS2V5LmtleUFybiwgc3NlVHlwZTogJ0tNUycgfSxcbiAgICAgICAgICBlbmNyeXB0aW9uS2V5LFxuICAgICAgICB9O1xuXG4gICAgICBjYXNlIFRhYmxlRW5jcnlwdGlvbi5BV1NfTUFOQUdFRDpcbiAgICAgICAgLy8gTm90IHNwZWNpZnlpbmcgXCJzc2VUeXBlOiAnS01TJ1wiIGhlcmUgYmVjYXVzZSBpdCB3b3VsZCBjYXVzZSBwaG9ueSBjaGFuZ2VzIHRvIGV4aXN0aW5nIHN0YWNrcy5cbiAgICAgICAgcmV0dXJuIHsgc3NlU3BlY2lmaWNhdGlvbjogeyBzc2VFbmFibGVkOiB0cnVlIH0gfTtcblxuICAgICAgY2FzZSBUYWJsZUVuY3J5cHRpb24uREVGQVVMVDpcbiAgICAgICAgcmV0dXJuIHsgc3NlU3BlY2lmaWNhdGlvbjogeyBzc2VFbmFibGVkOiBmYWxzZSB9IH07XG5cbiAgICAgIGNhc2UgdW5kZWZpbmVkOlxuICAgICAgICAvLyBOb3Qgc3BlY2lmeWluZyBcInNzZUVuYWJsZWQ6IGZhbHNlXCIgaGVyZSBiZWNhdXNlIGl0IHdvdWxkIGNhdXNlIHBob255IGNoYW5nZXMgdG8gZXhpc3Rpbmcgc3RhY2tzLlxuICAgICAgICByZXR1cm4geyBzc2VTcGVjaWZpY2F0aW9uOiB1bmRlZmluZWQgfTtcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmV4cGVjdGVkICdlbmNyeXB0aW9uVHlwZSc6ICR7ZW5jcnlwdGlvblR5cGV9YCk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogRGF0YSB0eXBlcyBmb3IgYXR0cmlidXRlcyB3aXRoaW4gYSB0YWJsZVxuICpcbiAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2FtYXpvbmR5bmFtb2RiL2xhdGVzdC9kZXZlbG9wZXJndWlkZS9Ib3dJdFdvcmtzLk5hbWluZ1J1bGVzRGF0YVR5cGVzLmh0bWwjSG93SXRXb3Jrcy5EYXRhVHlwZXNcbiAqL1xuZXhwb3J0IGVudW0gQXR0cmlidXRlVHlwZSB7XG4gIC8qKiBVcCB0byA0MDBLaUIgb2YgYmluYXJ5IGRhdGEgKHdoaWNoIG11c3QgYmUgZW5jb2RlZCBhcyBiYXNlNjQgYmVmb3JlIHNlbmRpbmcgdG8gRHluYW1vREIpICovXG4gIEJJTkFSWSA9ICdCJyxcbiAgLyoqIE51bWVyaWMgdmFsdWVzIG1hZGUgb2YgdXAgdG8gMzggZGlnaXRzIChwb3NpdGl2ZSwgbmVnYXRpdmUgb3IgemVybykgKi9cbiAgTlVNQkVSID0gJ04nLFxuICAvKiogVXAgdG8gNDAwS2lCIG9mIFVURi04IGVuY29kZWQgdGV4dCAqL1xuICBTVFJJTkcgPSAnUycsXG59XG5cbi8qKlxuICogRHluYW1vREIncyBSZWFkL1dyaXRlIGNhcGFjaXR5IG1vZGVzLlxuICovXG5leHBvcnQgZW51bSBCaWxsaW5nTW9kZSB7XG4gIC8qKlxuICAgKiBQYXkgb25seSBmb3Igd2hhdCB5b3UgdXNlLiBZb3UgZG9uJ3QgY29uZmlndXJlIFJlYWQvV3JpdGUgY2FwYWNpdHkgdW5pdHMuXG4gICAqL1xuICBQQVlfUEVSX1JFUVVFU1QgPSAnUEFZX1BFUl9SRVFVRVNUJyxcbiAgLyoqXG4gICAqIEV4cGxpY2l0bHkgc3BlY2lmaWVkIFJlYWQvV3JpdGUgY2FwYWNpdHkgdW5pdHMuXG4gICAqL1xuICBQUk9WSVNJT05FRCA9ICdQUk9WSVNJT05FRCcsXG59XG5cbi8qKlxuICogVGhlIHNldCBvZiBhdHRyaWJ1dGVzIHRoYXQgYXJlIHByb2plY3RlZCBpbnRvIHRoZSBpbmRleFxuICpcbiAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2FtYXpvbmR5bmFtb2RiL2xhdGVzdC9BUElSZWZlcmVuY2UvQVBJX1Byb2plY3Rpb24uaHRtbFxuICovXG5leHBvcnQgZW51bSBQcm9qZWN0aW9uVHlwZSB7XG4gIC8qKiBPbmx5IHRoZSBpbmRleCBhbmQgcHJpbWFyeSBrZXlzIGFyZSBwcm9qZWN0ZWQgaW50byB0aGUgaW5kZXguICovXG4gIEtFWVNfT05MWSA9ICdLRVlTX09OTFknLFxuICAvKiogT25seSB0aGUgc3BlY2lmaWVkIHRhYmxlIGF0dHJpYnV0ZXMgYXJlIHByb2plY3RlZCBpbnRvIHRoZSBpbmRleC4gVGhlIGxpc3Qgb2YgcHJvamVjdGVkIGF0dHJpYnV0ZXMgaXMgaW4gYG5vbktleUF0dHJpYnV0ZXNgLiAqL1xuICBJTkNMVURFID0gJ0lOQ0xVREUnLFxuICAvKiogQWxsIG9mIHRoZSB0YWJsZSBhdHRyaWJ1dGVzIGFyZSBwcm9qZWN0ZWQgaW50byB0aGUgaW5kZXguICovXG4gIEFMTCA9ICdBTEwnXG59XG5cbi8qKlxuICogV2hlbiBhbiBpdGVtIGluIHRoZSB0YWJsZSBpcyBtb2RpZmllZCwgU3RyZWFtVmlld1R5cGUgZGV0ZXJtaW5lcyB3aGF0IGluZm9ybWF0aW9uXG4gKiBpcyB3cml0dGVuIHRvIHRoZSBzdHJlYW0gZm9yIHRoaXMgdGFibGUuXG4gKlxuICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vYW1hem9uZHluYW1vZGIvbGF0ZXN0L0FQSVJlZmVyZW5jZS9BUElfU3RyZWFtU3BlY2lmaWNhdGlvbi5odG1sXG4gKi9cbmV4cG9ydCBlbnVtIFN0cmVhbVZpZXdUeXBlIHtcbiAgLyoqIFRoZSBlbnRpcmUgaXRlbSwgYXMgaXQgYXBwZWFycyBhZnRlciBpdCB3YXMgbW9kaWZpZWQsIGlzIHdyaXR0ZW4gdG8gdGhlIHN0cmVhbS4gKi9cbiAgTkVXX0lNQUdFID0gJ05FV19JTUFHRScsXG4gIC8qKiBUaGUgZW50aXJlIGl0ZW0sIGFzIGl0IGFwcGVhcmVkIGJlZm9yZSBpdCB3YXMgbW9kaWZpZWQsIGlzIHdyaXR0ZW4gdG8gdGhlIHN0cmVhbS4gKi9cbiAgT0xEX0lNQUdFID0gJ09MRF9JTUFHRScsXG4gIC8qKiBCb3RoIHRoZSBuZXcgYW5kIHRoZSBvbGQgaXRlbSBpbWFnZXMgb2YgdGhlIGl0ZW0gYXJlIHdyaXR0ZW4gdG8gdGhlIHN0cmVhbS4gKi9cbiAgTkVXX0FORF9PTERfSU1BR0VTID0gJ05FV19BTkRfT0xEX0lNQUdFUycsXG4gIC8qKiBPbmx5IHRoZSBrZXkgYXR0cmlidXRlcyBvZiB0aGUgbW9kaWZpZWQgaXRlbSBhcmUgd3JpdHRlbiB0byB0aGUgc3RyZWFtLiAqL1xuICBLRVlTX09OTFkgPSAnS0VZU19PTkxZJ1xufVxuXG4vKipcbiAqIER5bmFtb0RCJ3MgdGFibGUgY2xhc3MuXG4gKlxuICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vYW1hem9uZHluYW1vZGIvbGF0ZXN0L2RldmVsb3Blcmd1aWRlL0hvd0l0V29ya3MuVGFibGVDbGFzc2VzLmh0bWxcbiAqL1xuZXhwb3J0IGVudW0gVGFibGVDbGFzcyB7XG4gIC8qKiBEZWZhdWx0IHRhYmxlIGNsYXNzIGZvciBEeW5hbW9EQi4gKi9cbiAgU1RBTkRBUkQgPSAnU1RBTkRBUkQnLFxuXG4gIC8qKiBUYWJsZSBjbGFzcyBmb3IgRHluYW1vREIgdGhhdCByZWR1Y2VzIHN0b3JhZ2UgY29zdHMgY29tcGFyZWQgdG8gZXhpc3RpbmcgRHluYW1vREIgU3RhbmRhcmQgdGFibGVzLiAqL1xuICBTVEFOREFSRF9JTkZSRVFVRU5UX0FDQ0VTUyA9ICdTVEFOREFSRF9JTkZSRVFVRU5UX0FDQ0VTUycsXG59XG5cbi8qKlxuICogSnVzdCBhIGNvbnZlbmllbnQgd2F5IHRvIGtlZXAgdHJhY2sgb2YgYm90aCBhdHRyaWJ1dGVzXG4gKi9cbmludGVyZmFjZSBTY2FsYWJsZUF0dHJpYnV0ZVBhaXIge1xuICBzY2FsYWJsZVJlYWRBdHRyaWJ1dGU/OiBTY2FsYWJsZVRhYmxlQXR0cmlidXRlO1xuICBzY2FsYWJsZVdyaXRlQXR0cmlidXRlPzogU2NhbGFibGVUYWJsZUF0dHJpYnV0ZTtcbn1cblxuLyoqXG4gKiBBbiBpbmxpbmUgcG9saWN5IHRoYXQgaXMgbG9naWNhbGx5IGJvdW5kIHRvIHRoZSBzb3VyY2UgdGFibGUgb2YgYSBEeW5hbW9EQiBHbG9iYWwgVGFibGVzXG4gKiBcImNsdXN0ZXJcIi4gVGhpcyBpcyBoZXJlIHRvIGVuc3VyZSBwZXJtaXNzaW9ucyBhcmUgcmVtb3ZlZCBhcyBwYXJ0IG9mIChhbmQgbm90IGJlZm9yZSkgdGhlXG4gKiBDbGVhblVwIHBoYXNlIG9mIGEgc3RhY2sgdXBkYXRlLCB3aGVuIGEgcmVwbGljYSBpcyByZW1vdmVkIChvciB0aGUgZW50aXJlIFwiY2x1c3RlclwiIGdldHNcbiAqIHJlcGxhY2VkKS5cbiAqXG4gKiBJZiBzdGF0ZW1lbnRzIGFyZSBhZGRlZCBkaXJlY3RseSB0byB0aGUgaGFuZGxlciByb2xlcyAoYXMgb3Bwb3NlZCB0byBpbiBhIHNlcGFyYXRlIGlubGluZVxuICogcG9saWN5IHJlc291cmNlKSwgbmV3IHBlcm1pc3Npb25zIGFyZSBpbiBlZmZlY3QgYmVmb3JlIGNsZWFuIHVwIGhhcHBlbnMsIGFuZCBzbyByZXBsaWNhcyB0aGF0XG4gKiBuZWVkIHRvIGJlIGRyb3BwZWQgY2FuIG5vIGxvbmdlciBiZSBkdWUgdG8gbGFjayBvZiBwZXJtaXNzaW9ucy5cbiAqL1xuY2xhc3MgU291cmNlVGFibGVBdHRhY2hlZFBvbGljeSBleHRlbmRzIENvcmVDb25zdHJ1Y3QgaW1wbGVtZW50cyBpYW0uSUdyYW50YWJsZSB7XG4gIHB1YmxpYyByZWFkb25seSBncmFudFByaW5jaXBhbDogaWFtLklQcmluY2lwYWw7XG4gIHB1YmxpYyByZWFkb25seSBwb2xpY3k6IGlhbS5JTWFuYWdlZFBvbGljeTtcblxuICBwdWJsaWMgY29uc3RydWN0b3Ioc291cmNlVGFibGU6IFRhYmxlLCByb2xlOiBpYW0uSVJvbGUpIHtcbiAgICBzdXBlcihzb3VyY2VUYWJsZSwgYFNvdXJjZVRhYmxlQXR0YWNoZWRNYW5hZ2VkUG9saWN5LSR7TmFtZXMubm9kZVVuaXF1ZUlkKHJvbGUubm9kZSl9YCk7XG5cbiAgICBjb25zdCBwb2xpY3kgPSBuZXcgaWFtLk1hbmFnZWRQb2xpY3kodGhpcywgJ1Jlc291cmNlJywge1xuICAgICAgLy8gQSBDRiB1cGRhdGUgb2YgdGhlIGRlc2NyaXB0aW9uIHByb3BlcnR5IG9mIGEgbWFuYWdlZCBwb2xpY3kgcmVxdWlyZXNcbiAgICAgIC8vIGEgcmVwbGFjZW1lbnQuIFVzZSB0aGUgdGFibGUgbmFtZSBpbiB0aGUgZGVzY3JpcHRpb24gdG8gZm9yY2UgYSBtYW5hZ2VkXG4gICAgICAvLyBwb2xpY3kgcmVwbGFjZW1lbnQgd2hlbiB0aGUgdGFibGUgbmFtZSBjaGFuZ2VzLiBUaGlzIHdheSB3ZSBwcmVzZXJ2ZSBwZXJtaXNzaW9uc1xuICAgICAgLy8gdG8gZGVsZXRlIG9sZCByZXBsaWNhcyBpbiBjYXNlIG9mIGEgdGFibGUgcmVwbGFjZW1lbnQuXG4gICAgICBkZXNjcmlwdGlvbjogYER5bmFtb0RCIHJlcGxpY2F0aW9uIG1hbmFnZWQgcG9saWN5IGZvciB0YWJsZSAke3NvdXJjZVRhYmxlLnRhYmxlTmFtZX1gLFxuICAgICAgcm9sZXM6IFtyb2xlXSxcbiAgICB9KTtcbiAgICB0aGlzLnBvbGljeSA9IHBvbGljeTtcbiAgICB0aGlzLmdyYW50UHJpbmNpcGFsID0gbmV3IFNvdXJjZVRhYmxlQXR0YWNoZWRQcmluY2lwYWwocm9sZSwgcG9saWN5KTtcbiAgfVxufVxuXG4vKipcbiAqIEFuIGBJUHJpbmNpcGFsYCBlbnRpdHkgdGhhdCBjYW4gYmUgdXNlZCBhcyB0aGUgdGFyZ2V0IG9mIGBncmFudGAgY2FsbHMsIHVzZWQgYnkgdGhlXG4gKiBgU291cmNlVGFibGVBdHRhY2hlZFBvbGljeWAgY2xhc3Mgc28gaXQgY2FuIGFjdCBhcyBhbiBgSUdyYW50YWJsZWAuXG4gKi9cbmNsYXNzIFNvdXJjZVRhYmxlQXR0YWNoZWRQcmluY2lwYWwgZXh0ZW5kcyBpYW0uUHJpbmNpcGFsQmFzZSB7XG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHJvbGU6IGlhbS5JUm9sZSwgcHJpdmF0ZSByZWFkb25seSBwb2xpY3k6IGlhbS5NYW5hZ2VkUG9saWN5KSB7XG4gICAgc3VwZXIoKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgcG9saWN5RnJhZ21lbnQoKTogaWFtLlByaW5jaXBhbFBvbGljeUZyYWdtZW50IHtcbiAgICByZXR1cm4gdGhpcy5yb2xlLnBvbGljeUZyYWdtZW50O1xuICB9XG5cbiAgcHVibGljIGFkZFRvUHJpbmNpcGFsUG9saWN5KHN0YXRlbWVudDogaWFtLlBvbGljeVN0YXRlbWVudCk6IGlhbS5BZGRUb1ByaW5jaXBhbFBvbGljeVJlc3VsdCB7XG4gICAgdGhpcy5wb2xpY3kuYWRkU3RhdGVtZW50cyhzdGF0ZW1lbnQpO1xuICAgIHJldHVybiB7XG4gICAgICBwb2xpY3lEZXBlbmRhYmxlOiB0aGlzLnBvbGljeSxcbiAgICAgIHN0YXRlbWVudEFkZGVkOiB0cnVlLFxuICAgIH07XG4gIH1cbn1cbiJdfQ== |
\ | No newline at end of file |