@aws-cdk/toolkit-lib 1.30.0 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build-info.json +2 -2
- package/lib/actions/bootstrap/index.d.ts +5 -0
- package/lib/actions/bootstrap/index.js +35 -2
- package/lib/actions/deploy/index.d.ts +6 -0
- package/lib/actions/deploy/index.js +1 -1
- package/lib/actions/destroy/index.d.ts +6 -0
- package/lib/actions/destroy/index.js +1 -1
- package/lib/actions/diff/private/helpers.js +36 -3
- package/lib/api/aws-auth/account-cache.js +36 -3
- package/lib/api/aws-auth/sdk-provider.js +36 -3
- package/lib/api/aws-auth/sdk.d.ts +2 -1
- package/lib/api/aws-auth/sdk.js +2 -1
- package/lib/api/aws-auth/user-agent.js +35 -2
- package/lib/api/aws-auth/util.js +35 -2
- package/lib/api/bootstrap/bootstrap-environment.js +35 -2
- package/lib/api/bootstrap/bootstrap-props.d.ts +6 -0
- package/lib/api/bootstrap/bootstrap-props.js +1 -1
- package/lib/api/bootstrap/deploy-bootstrap.js +39 -4
- package/lib/api/cloud-assembly/context-store.js +36 -3
- package/lib/api/cloud-assembly/environment.js +37 -4
- package/lib/api/cloud-assembly/private/context-aware-source.js +35 -2
- package/lib/api/cloud-assembly/private/exec.js +35 -2
- package/lib/api/cloud-assembly/private/prepare-source.js +39 -6
- package/lib/api/cloud-assembly/source-builder.js +37 -4
- package/lib/api/cloud-assembly/stack-assembly.js +8 -4
- package/lib/api/cloudformation/logical-id-map.js +35 -2
- package/lib/api/cloudformation/nested-stack-helpers.js +36 -3
- package/lib/api/cloudformation/template-body-parameter.js +42 -6
- package/lib/api/deployments/asset-manifest-builder.js +35 -2
- package/lib/api/deployments/assets.js +42 -6
- package/lib/api/deployments/cfn-api.d.ts +4 -2
- package/lib/api/deployments/cfn-api.js +47 -6
- package/lib/api/deployments/deploy-stack.d.ts +13 -0
- package/lib/api/deployments/deploy-stack.js +29 -9
- package/lib/api/deployments/deployment-result.d.ts +7 -1
- package/lib/api/deployments/deployment-result.js +1 -1
- package/lib/api/deployments/deployments.d.ts +5 -0
- package/lib/api/deployments/deployments.js +42 -4
- package/lib/api/diagnosing/format-utils.d.ts +29 -0
- package/lib/api/diagnosing/format-utils.js +141 -1
- package/lib/api/diagnosing/investigate-custom-resource.d.ts +17 -0
- package/lib/api/diagnosing/investigate-custom-resource.js +247 -0
- package/lib/api/diagnosing/investigate-ecs-service.d.ts +20 -0
- package/lib/api/diagnosing/investigate-ecs-service.js +242 -0
- package/lib/api/diagnosing/resource-identifiers.d.ts +39 -0
- package/lib/api/diagnosing/resource-identifiers.js +90 -0
- package/lib/api/diagnosing/resource-investigation.d.ts +2 -30
- package/lib/api/diagnosing/resource-investigation.js +9 -289
- package/lib/api/diff/diff-formatter.js +11 -8
- package/lib/api/drift/drift-formatter.js +20 -17
- package/lib/api/garbage-collection/garbage-collector.js +7 -4
- package/lib/api/garbage-collection/progress-printer.js +7 -4
- package/lib/api/hotswap/hotswap-deployments.js +47 -10
- package/lib/api/hotswap/hotswap-template-cache.js +36 -3
- package/lib/api/io/private/io-default-messages.js +35 -2
- package/lib/api/io/private/message-maker.d.ts +4 -0
- package/lib/api/io/private/message-maker.js +3 -1
- package/lib/api/io/private/messages.d.ts +5 -0
- package/lib/api/io/private/messages.js +55 -2
- package/lib/api/io/private/span.js +35 -2
- package/lib/api/logs-monitor/logs-monitor.js +40 -4
- package/lib/api/network-detector/network-detector.js +37 -4
- package/lib/api/notices/cached-data-source.js +35 -2
- package/lib/api/notices/filter.js +35 -2
- package/lib/api/notices/notices.js +35 -2
- package/lib/api/notices/web-data-source.js +35 -2
- package/lib/api/refactoring/digest.js +35 -2
- package/lib/api/refactoring/stack-definitions.js +40 -4
- package/lib/api/resource-import/importer.js +60 -17
- package/lib/api/resource-import/migrator.js +42 -6
- package/lib/api/rwlock.js +35 -2
- package/lib/api/settings.js +38 -5
- package/lib/api/source-tracing/private/stack-source-tracing.js +38 -5
- package/lib/api/stack-events/resource-errors.d.ts +12 -0
- package/lib/api/stack-events/resource-errors.js +2 -1
- package/lib/api/stack-events/stack-activity-monitor.d.ts +5 -0
- package/lib/api/stack-events/stack-activity-monitor.js +42 -2
- package/lib/api/stack-events/stack-event-poller.d.ts +8 -1
- package/lib/api/stack-events/stack-event-poller.js +19 -1
- package/lib/api/stack-events/stack-progress-monitor.js +35 -2
- package/lib/api/toolkit-info.js +7 -4
- package/lib/api/tree.js +36 -3
- package/lib/api/validate/validate-formatting.js +53 -17
- package/lib/api/work-graph/build-destroy-work-graph.js +35 -2
- package/lib/api/work-graph/work-graph-builder.js +35 -2
- package/lib/context-providers/index.js +35 -2
- package/lib/private/activity-printer/current.d.ts +19 -0
- package/lib/private/activity-printer/current.js +109 -17
- package/lib/private/activity-printer/history.js +50 -14
- package/lib/private/tools.js +38 -1
- package/lib/toolkit/non-interactive-io-host.js +11 -8
- package/lib/toolkit/private/collect-annotation-report.js +35 -2
- package/lib/toolkit/private/validation-report.js +36 -3
- package/lib/toolkit/toolkit-error.d.ts +20 -0
- package/lib/toolkit/toolkit-error.js +30 -2
- package/lib/toolkit/toolkit.d.ts +8 -0
- package/lib/toolkit/toolkit.js +107 -41
- package/lib/toolkit/types.d.ts +22 -0
- package/lib/toolkit/types.js +1 -1
- package/lib/util/cfn-express.d.ts +24 -0
- package/lib/util/cfn-express.js +55 -0
- package/lib/util/content-hash.js +35 -2
- package/lib/util/directories.js +38 -5
- package/lib/util/guess-language.js +36 -3
- package/lib/util/index.d.ts +1 -0
- package/lib/util/index.js +2 -1
- package/lib/util/package-info.js +35 -2
- package/lib/util/serialize.js +36 -3
- package/lib/util/version-range.js +35 -2
- package/lib/util/yaml-cfn.js +36 -3
- package/package.json +2 -2
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.investigateCustomResource = investigateCustomResource;
|
|
4
|
+
const format_utils_1 = require("./format-utils");
|
|
5
|
+
const resource_identifiers_1 = require("./resource-identifiers");
|
|
6
|
+
const util_1 = require("../../util");
|
|
7
|
+
/** Fallback look-back when no failure timestamp is available. */
|
|
8
|
+
const FALLBACK_LOG_WINDOW_MS = 30 * 60 * 1000;
|
|
9
|
+
/**
|
|
10
|
+
* How far before/after the failure event to search CloudWatch Logs when we have a timestamp.
|
|
11
|
+
*
|
|
12
|
+
* The pre-window absorbs minor clock skew; the post-window covers output the function
|
|
13
|
+
* emits while it runs after the CloudFormation event was recorded.
|
|
14
|
+
*/
|
|
15
|
+
const LOG_WINDOW_BEFORE_MS = 2 * 60 * 1000;
|
|
16
|
+
const LOG_WINDOW_AFTER_MS = 15 * 60 * 1000;
|
|
17
|
+
/**
|
|
18
|
+
* Investigate a failed custom resource by surfacing its backing Lambda's CloudWatch logs.
|
|
19
|
+
*
|
|
20
|
+
* The CloudFormation event does not name the backing function — only the resource's
|
|
21
|
+
* `ServiceToken` (in the template) does. We resolve that to a function name, derive the
|
|
22
|
+
* log group (the `/aws/lambda/<fn>` convention, confirmed via the function's LoggingConfig
|
|
23
|
+
* only if the convention turns up empty), and fetch the relevant log lines.
|
|
24
|
+
*
|
|
25
|
+
* When the handler uses the cfn-response library, the failing log stream name is embedded
|
|
26
|
+
* in the status reason ("See the details in CloudWatch Log Stream: <name>"), so we can
|
|
27
|
+
* target that exact invocation.
|
|
28
|
+
*/
|
|
29
|
+
async function investigateCustomResource(err, sdk, debug) {
|
|
30
|
+
if (!err.logicalId) {
|
|
31
|
+
await debug('Custom resource investigation: no logical ID available');
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
const stackName = err.stackArn;
|
|
35
|
+
if (!stackName) {
|
|
36
|
+
await debug('Custom resource investigation: no stack ARN available');
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const cfn = sdk.cloudFormation();
|
|
40
|
+
const lambda = sdk.lambda();
|
|
41
|
+
const cwl = sdk.cloudWatchLogs();
|
|
42
|
+
const region = sdk.currentRegion;
|
|
43
|
+
// Fetch the template once: it carries both the ServiceToken and (for functions defined in
|
|
44
|
+
// this stack) the backing function's LoggingConfig. The template survives rollback even
|
|
45
|
+
// when the function itself is deleted, so it's the most reliable source for the log group.
|
|
46
|
+
const template = await getStackTemplate(cfn, stackName, debug);
|
|
47
|
+
if (!template) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const serviceToken = template.Resources?.[err.logicalId]?.Properties?.ServiceToken;
|
|
51
|
+
if (serviceToken === undefined) {
|
|
52
|
+
await debug(`Custom resource investigation: no ServiceToken on resource "${err.logicalId}"`);
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const referencedLogicalId = (0, resource_identifiers_1.serviceTokenReferencedLogicalId)(serviceToken);
|
|
56
|
+
const functionName = await resolveServiceTokenToFunctionName(cfn, stackName, serviceToken, referencedLogicalId, debug);
|
|
57
|
+
if (!functionName) {
|
|
58
|
+
await debug('Custom resource investigation: could not resolve ServiceToken to a Lambda function');
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
// Prefer the function's configured log group as derived from the template (rollback-proof).
|
|
62
|
+
// Only resolvable when the function is defined in this stack (ServiceToken is a Ref/GetAtt).
|
|
63
|
+
const templateLogGroup = referencedLogicalId
|
|
64
|
+
? await resolveConfiguredLogGroup(cfn, stackName, template, referencedLogicalId, debug)
|
|
65
|
+
: undefined;
|
|
66
|
+
// The cfn-response library writes the failing log stream name into the status reason
|
|
67
|
+
// (and uses it as the default physical ID). Targeting it gives the exact invocation.
|
|
68
|
+
const streamName = (0, resource_identifiers_1.extractLogStreamName)(err.message) ?? (0, resource_identifiers_1.logStreamNameFromPhysicalId)(err.physicalId);
|
|
69
|
+
return fetchCustomResourceLogs(cwl, lambda, functionName, templateLogGroup, streamName, err.timestamp, region, debug);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Fetch and parse the stack's (original) template. Returns `undefined` if it can't be read.
|
|
73
|
+
*/
|
|
74
|
+
async function getStackTemplate(cfn, stackName, debug) {
|
|
75
|
+
try {
|
|
76
|
+
const resp = await cfn.getTemplate({ StackName: stackName, TemplateStage: 'Original' });
|
|
77
|
+
if (!resp.TemplateBody) {
|
|
78
|
+
await debug('Custom resource investigation: empty template body');
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
return (0, util_1.deserializeStructure)(resp.TemplateBody);
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
await debug(`Custom resource investigation: failed to read template: ${e.message}`);
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve the backing Lambda's configured log group from the template.
|
|
90
|
+
*
|
|
91
|
+
* The template survives rollback (when the live function may not), so it is the preferred
|
|
92
|
+
* source. Handles the function's `LoggingConfig.LogGroup` as:
|
|
93
|
+
* - a literal string (returned directly);
|
|
94
|
+
* - a `Ref` to an `AWS::Logs::LogGroup` with a literal `LogGroupName` (returned directly);
|
|
95
|
+
* - a `Ref` to an `AWS::Logs::LogGroup` whose name CloudFormation generates (the common CDK
|
|
96
|
+
* case) — resolved to its physical name via `describeStackResources`, which still returns
|
|
97
|
+
* RETAINed/orphaned resources after a rollback.
|
|
98
|
+
*
|
|
99
|
+
* Returns `undefined` when there is no configured log group or it can't be resolved
|
|
100
|
+
* (caller then falls back to the live function configuration).
|
|
101
|
+
*/
|
|
102
|
+
async function resolveConfiguredLogGroup(cfn, stackName, template, functionLogicalId, debug) {
|
|
103
|
+
const logGroup = template.Resources?.[functionLogicalId]?.Properties?.LoggingConfig?.LogGroup;
|
|
104
|
+
if (typeof logGroup === 'string') {
|
|
105
|
+
return logGroup;
|
|
106
|
+
}
|
|
107
|
+
if (logGroup && typeof logGroup === 'object' && typeof logGroup.Ref === 'string') {
|
|
108
|
+
const referenced = template.Resources?.[logGroup.Ref];
|
|
109
|
+
const name = referenced?.Properties?.LogGroupName;
|
|
110
|
+
if (typeof name === 'string') {
|
|
111
|
+
return name;
|
|
112
|
+
}
|
|
113
|
+
// No explicit name (CloudFormation generates it) — resolve the log-group resource's
|
|
114
|
+
// physical name, which is the log group name.
|
|
115
|
+
return (await resolveStackResource(cfn, stackName, logGroup.Ref, debug))?.physicalId;
|
|
116
|
+
}
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Resolve a resource's physical ID and type by logical ID. Returns `undefined` on failure.
|
|
121
|
+
*/
|
|
122
|
+
async function resolveStackResource(cfn, stackName, logicalId, debug) {
|
|
123
|
+
try {
|
|
124
|
+
const resp = await cfn.describeStackResources({ StackName: stackName, LogicalResourceId: logicalId });
|
|
125
|
+
const resource = resp.StackResources?.[0];
|
|
126
|
+
return resource ? { physicalId: resource.PhysicalResourceId, resourceType: resource.ResourceType } : undefined;
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
await debug(`Custom resource investigation: failed to resolve resource "${logicalId}": ${e.message}`);
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolve a `ServiceToken` value (a literal ARN, an `Fn::GetAtt`, or a `Ref`) to a Lambda
|
|
135
|
+
* function name. Intrinsics are resolved via `describeStackResources`.
|
|
136
|
+
*/
|
|
137
|
+
async function resolveServiceTokenToFunctionName(cfn, stackName, serviceToken, referencedLogicalId, debug) {
|
|
138
|
+
if (referencedLogicalId) {
|
|
139
|
+
const resource = await resolveStackResource(cfn, stackName, referencedLogicalId, debug);
|
|
140
|
+
// Only treat the reference as a Lambda function. Without this, a ServiceToken pointing at
|
|
141
|
+
// a non-Lambda resource (e.g. an SNS topic) whose physical ID is a bare name would be
|
|
142
|
+
// mistaken for a function name, producing a misleading /aws/lambda/<name> log lookup.
|
|
143
|
+
if (resource?.resourceType && resource.resourceType !== 'AWS::Lambda::Function') {
|
|
144
|
+
await debug(`Custom resource investigation: ServiceToken references a ${resource.resourceType}, not a Lambda function`);
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
return resource?.physicalId ? (0, resource_identifiers_1.functionNameFromArnOrName)(resource.physicalId) : undefined;
|
|
148
|
+
}
|
|
149
|
+
if (typeof serviceToken === 'string') {
|
|
150
|
+
return (0, resource_identifiers_1.functionNameFromArnOrName)(serviceToken);
|
|
151
|
+
}
|
|
152
|
+
await debug('Custom resource investigation: unsupported ServiceToken shape');
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
async function fetchCustomResourceLogs(cwl, lambda, functionName, templateLogGroup, streamName, timestamp, region, debug) {
|
|
156
|
+
const failureTime = timestamp?.valueOf();
|
|
157
|
+
const startTime = failureTime !== undefined ? failureTime - LOG_WINDOW_BEFORE_MS : Date.now() - FALLBACK_LOG_WINDOW_MS;
|
|
158
|
+
const endTime = failureTime !== undefined ? failureTime + LOG_WINDOW_AFTER_MS : undefined;
|
|
159
|
+
// Convention first; only pay for the configured group if the convention group doesn't yield usable lines (empty group or fetch error).
|
|
160
|
+
const conventionGroup = `/aws/lambda/${functionName}`;
|
|
161
|
+
let result = await fetchLogLines(cwl, conventionGroup, streamName, startTime, endTime, debug);
|
|
162
|
+
// The group we point the user at. Once we learn the function's configured log group, prefer
|
|
163
|
+
// it for the link even if it too is empty — it's where the function actually logs, whereas
|
|
164
|
+
// the convention group may not exist for advanced-logging functions.
|
|
165
|
+
let logGroup = conventionGroup;
|
|
166
|
+
if (result.kind !== 'lines') {
|
|
167
|
+
// Prefer the template-derived group (rollback-proof); fall back to the live function
|
|
168
|
+
// configuration only when the template couldn't tell us (e.g. unresolvable intrinsic, or
|
|
169
|
+
// the function is defined outside this stack).
|
|
170
|
+
const configuredGroup = templateLogGroup ?? await configuredLogGroup(lambda, functionName, debug);
|
|
171
|
+
if (configuredGroup && configuredGroup !== conventionGroup) {
|
|
172
|
+
logGroup = configuredGroup;
|
|
173
|
+
const configuredResult = await fetchLogLines(cwl, configuredGroup, streamName, startTime, endTime, debug);
|
|
174
|
+
// Keep the configured-group result unless it errored while the convention attempt was a
|
|
175
|
+
// clean empty (an "empty" answer is more informative to surface than a fetch error).
|
|
176
|
+
if (configuredResult.kind === 'lines' || result.kind !== 'empty') {
|
|
177
|
+
result = configuredResult;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Lead with the log group so the user can tell which function these logs belong to
|
|
182
|
+
// (the formatter renders messages but not `source`, and the link is URL-encoded).
|
|
183
|
+
const header = `Logs from ${logGroup}:`;
|
|
184
|
+
const body = result.kind === 'lines'
|
|
185
|
+
? result.lines
|
|
186
|
+
: result.kind === 'error'
|
|
187
|
+
? ['Could not fetch logs (the log group may not exist, or the credentials lack logs:FilterLogEvents). See the console link below.']
|
|
188
|
+
: ['No log events found around the time of failure. The function may not have produced output, or logging may not be configured.'];
|
|
189
|
+
return [{
|
|
190
|
+
source: 'Custom Resource Lambda Logs',
|
|
191
|
+
messages: [header, ...body],
|
|
192
|
+
link: (0, format_utils_1.cloudWatchLogsConsoleUrl)(region, logGroup),
|
|
193
|
+
linkLabel: 'Logs',
|
|
194
|
+
}];
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Fetch and trim recent log lines from a group.
|
|
198
|
+
*
|
|
199
|
+
* Tries the targeted stream first (most relevant), but the cfn-response stream name can be
|
|
200
|
+
* stale on update/rollback failures (it's pinned to the original create invocation). If the
|
|
201
|
+
* targeted query finds nothing, falls back to a group-wide scan over the time window so a
|
|
202
|
+
* stale stream can't hide the actual failing invocation's logs.
|
|
203
|
+
*/
|
|
204
|
+
async function fetchLogLines(cwl, logGroup, streamName, startTime, endTime, debug) {
|
|
205
|
+
if (streamName) {
|
|
206
|
+
const targeted = await filterLogLines(cwl, logGroup, streamName, startTime, endTime, debug);
|
|
207
|
+
if (targeted.kind === 'lines') {
|
|
208
|
+
return targeted;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return filterLogLines(cwl, logGroup, undefined, startTime, endTime, debug);
|
|
212
|
+
}
|
|
213
|
+
async function filterLogLines(cwl, logGroup, streamName, startTime, endTime, debug) {
|
|
214
|
+
try {
|
|
215
|
+
const resp = await cwl.filterLogEvents({
|
|
216
|
+
logGroupName: logGroup,
|
|
217
|
+
startTime,
|
|
218
|
+
...(endTime !== undefined ? { endTime } : {}),
|
|
219
|
+
limit: 1000,
|
|
220
|
+
...(streamName ? { logStreamNames: [streamName] } : {}),
|
|
221
|
+
});
|
|
222
|
+
const events = resp.events ?? [];
|
|
223
|
+
if (events.length === 0) {
|
|
224
|
+
await debug(`Custom resource investigation: no log events in ${logGroup}${streamName ? ` (stream: ${streamName})` : ''}`);
|
|
225
|
+
return { kind: 'empty' };
|
|
226
|
+
}
|
|
227
|
+
// Lambda log events have a known structure (text- or JSON-format), unlike raw ECS
|
|
228
|
+
// container output, so we normalize them into readable lines before trimming.
|
|
229
|
+
return { kind: 'lines', lines: (0, format_utils_1.trimToRecentLines)((0, format_utils_1.parseLambdaLogEvents)(events)) };
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
await debug(`Custom resource investigation: failed to fetch logs from ${logGroup}: ${e.message}`);
|
|
233
|
+
return { kind: 'error' };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/** Read the function's configured (advanced-logging) log group, if any. */
|
|
237
|
+
async function configuredLogGroup(lambda, functionName, debug) {
|
|
238
|
+
try {
|
|
239
|
+
const resp = await lambda.getFunctionConfiguration({ FunctionName: functionName });
|
|
240
|
+
return resp.LoggingConfig?.LogGroup;
|
|
241
|
+
}
|
|
242
|
+
catch (e) {
|
|
243
|
+
await debug(`Custom resource investigation: failed to read function configuration: ${e.message}`);
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW52ZXN0aWdhdGUtY3VzdG9tLXJlc291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW52ZXN0aWdhdGUtY3VzdG9tLXJlc291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBb0NBLDhEQW9EQztBQXhGRCxpREFBbUc7QUFDbkcsaUVBS2dDO0FBRWhDLHFDQUFrRDtBQUlsRCxpRUFBaUU7QUFDakUsTUFBTSxzQkFBc0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUU5Qzs7Ozs7R0FLRztBQUNILE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDM0MsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUUzQzs7Ozs7Ozs7Ozs7R0FXRztBQUNJLEtBQUssVUFBVSx5QkFBeUIsQ0FDN0MsR0FBa0IsRUFDbEIsR0FBUSxFQUNSLEtBQXFDO0lBRXJDLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDbkIsTUFBTSxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUN0RSxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDO0lBQy9CLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNmLE1BQU0sS0FBSyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7UUFDckUsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ2pDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUM1QixNQUFNLEdBQUcsR0FBRyxHQUFHLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDakMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLGFBQWEsQ0FBQztJQUVqQywwRkFBMEY7SUFDMUYs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QUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztBQUNILENBQUM7QUFFRCwyRUFBMkU7QUFDM0UsS0FBSyxVQUFVLGtCQUFrQixDQUMvQixNQUFxQixFQUNyQixZQUFvQixFQUNwQixLQUFxQztJQUVyQyxJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxNQUFNLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLE9BQU8sSUFBSSxDQUFDLGFBQWEsRUFBRSxRQUFRLENBQUM7SUFDdEMsQ0FBQztJQUFDLE9BQU8sQ0FBTSxFQUFFLENBQUM7UUFDaEIsTUFBTSxLQUFLLENBQUMseUVBQXlFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2xHLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdHJpbVRvUmVjZW50TGluZXMsIHBhcnNlTGFtYmRhTG9nRXZlbnRzLCBjbG91ZFdhdGNoTG9nc0NvbnNvbGVVcmwgfSBmcm9tICcuL2Zvcm1hdC11dGlscyc7XG5pbXBvcnQge1xuICBzZXJ2aWNlVG9rZW5SZWZlcmVuY2VkTG9naWNhbElkLFxuICBmdW5jdGlvbk5hbWVGcm9tQXJuT3JOYW1lLFxuICBleHRyYWN0TG9nU3RyZWFtTmFtZSxcbiAgbG9nU3RyZWFtTmFtZUZyb21QaHlzaWNhbElkLFxufSBmcm9tICcuL3Jlc291cmNlLWlkZW50aWZpZXJzJztcbmltcG9ydCB0eXBlIHsgQWRkaXRpb25hbERpYWdub3N0aWNDb250ZXh0IH0gZnJvbSAnLi4vLi4vYWN0aW9ucy9kaWFnbm9zZSc7XG5pbXBvcnQgeyBkZXNlcmlhbGl6ZVN0cnVjdHVyZSB9IGZyb20gJy4uLy4uL3V0aWwnO1xuaW1wb3J0IHR5cGUgeyBJQ2xvdWRGb3JtYXRpb25DbGllbnQsIElDbG91ZFdhdGNoTG9nc0NsaWVudCwgSUxhbWJkYUNsaWVudCwgU0RLIH0gZnJvbSAnLi4vYXdzLWF1dGgvc2RrJztcbmltcG9ydCB0eXBlIHsgUmVzb3VyY2VFcnJvciB9IGZyb20gJy4uL3N0YWNrLWV2ZW50cy9yZXNvdXJjZS1lcnJvcnMnO1xuXG4vKiogRmFsbGJhY2sgbG9vay1iYWNrIHdoZW4gbm8gZmFpbHVyZSB0aW1lc3RhbXAgaXMgYXZhaWxhYmxlLiAqL1xuY29uc3QgRkFMTEJBQ0tfTE9HX1dJTkRPV19NUyA9IDMwICogNjAgKiAxMDAwO1xuXG4vKipcbiAqIEhvdyBmYXIgYmVmb3JlL2FmdGVyIHRoZSBmYWlsdXJlIGV2ZW50IHRvIHNlYXJjaCBDbG91ZFdhdGNoIExvZ3Mgd2hlbiB3ZSBoYXZlIGEgdGltZXN0YW1wLlxuICpcbiAqIFRoZSBwcmUtd2luZG93IGFic29yYnMgbWlub3IgY2xvY2sgc2tldzsgdGhlIHBvc3Qtd2luZG93IGNvdmVycyBvdXRwdXQgdGhlIGZ1bmN0aW9uXG4gKiBlbWl0cyB3aGlsZSBpdCBydW5zIGFmdGVyIHRoZSBDbG91ZEZvcm1hdGlvbiBldmVudCB3YXMgcmVjb3JkZWQuXG4gKi9cbmNvbnN0IExPR19XSU5ET1dfQkVGT1JFX01TID0gMiAqIDYwICogMTAwMDtcbmNvbnN0IExPR19XSU5ET1dfQUZURVJfTVMgPSAxNSAqIDYwICogMTAwMDtcblxuLyoqXG4gKiBJbnZlc3RpZ2F0ZSBhIGZhaWxlZCBjdXN0b20gcmVzb3VyY2UgYnkgc3VyZmFjaW5nIGl0cyBiYWNraW5nIExhbWJkYSdzIENsb3VkV2F0Y2ggbG9ncy5cbiAqXG4gKiBUaGUgQ2xvdWRGb3JtYXRpb24gZXZlbnQgZG9lcyBub3QgbmFtZSB0aGUgYmFja2luZyBmdW5jdGlvbiDigJQgb25seSB0aGUgcmVzb3VyY2Unc1xuICogYFNlcnZpY2VUb2tlbmAgKGluIHRoZSB0ZW1wbGF0ZSkgZG9lcy4gV2UgcmVzb2x2ZSB0aGF0IHRvIGEgZnVuY3Rpb24gbmFtZSwgZGVyaXZlIHRoZVxuICogbG9nIGdyb3VwICh0aGUgYC9hd3MvbGFtYmRhLzxmbj5gIGNvbnZlbnRpb24sIGNvbmZpcm1lZCB2aWEgdGhlIGZ1bmN0aW9uJ3MgTG9nZ2luZ0NvbmZpZ1xuICogb25seSBpZiB0aGUgY29udmVudGlvbiB0dXJucyB1cCBlbXB0eSksIGFuZCBmZXRjaCB0aGUgcmVsZXZhbnQgbG9nIGxpbmVzLlxuICpcbiAqIFdoZW4gdGhlIGhhbmRsZXIgdXNlcyB0aGUgY2ZuLXJlc3BvbnNlIGxpYnJhcnksIHRoZSBmYWlsaW5nIGxvZyBzdHJlYW0gbmFtZSBpcyBlbWJlZGRlZFxuICogaW4gdGhlIHN0YXR1cyByZWFzb24gKFwiU2VlIHRoZSBkZXRhaWxzIGluIENsb3VkV2F0Y2ggTG9nIFN0cmVhbTogPG5hbWU+XCIpLCBzbyB3ZSBjYW5cbiAqIHRhcmdldCB0aGF0IGV4YWN0IGludm9jYXRpb24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnZlc3RpZ2F0ZUN1c3RvbVJlc291cmNlKFxuICBlcnI6IFJlc291cmNlRXJyb3IsXG4gIHNkazogU0RLLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHRbXT4ge1xuICBpZiAoIWVyci5sb2dpY2FsSWQpIHtcbiAgICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IG5vIGxvZ2ljYWwgSUQgYXZhaWxhYmxlJyk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIGNvbnN0IHN0YWNrTmFtZSA9IGVyci5zdGFja0FybjtcbiAgaWYgKCFzdGFja05hbWUpIHtcbiAgICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IG5vIHN0YWNrIEFSTiBhdmFpbGFibGUnKTtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICBjb25zdCBjZm4gPSBzZGsuY2xvdWRGb3JtYXRpb24oKTtcbiAgY29uc3QgbGFtYmRhID0gc2RrLmxhbWJkYSgpO1xuICBjb25zdCBjd2wgPSBzZGsuY2xvdWRXYXRjaExvZ3MoKTtcbiAgY29uc3QgcmVnaW9uID0gc2RrLmN1cnJlbnRSZWdpb247XG5cbiAgLy8gRmV0Y2ggdGhlIHRlbXBsYXRlIG9uY2U6IGl0IGNhcnJpZXMgYm90aCB0aGUgU2VydmljZVRva2VuIGFuZCAoZm9yIGZ1bmN0aW9ucyBkZWZpbmVkIGluXG4gIC8vIHRoaXMgc3RhY2spIHRoZSBiYWNraW5nIGZ1bmN0aW9uJ3MgTG9nZ2luZ0NvbmZpZy4gVGhlIHRlbXBsYXRlIHN1cnZpdmVzIHJvbGxiYWNrIGV2ZW5cbiAgLy8gd2hlbiB0aGUgZnVuY3Rpb24gaXRzZWxmIGlzIGRlbGV0ZWQsIHNvIGl0J3MgdGhlIG1vc3QgcmVsaWFibGUgc291cmNlIGZvciB0aGUgbG9nIGdyb3VwLlxuICBjb25zdCB0ZW1wbGF0ZSA9IGF3YWl0IGdldFN0YWNrVGVtcGxhdGUoY2ZuLCBzdGFja05hbWUsIGRlYnVnKTtcbiAgaWYgKCF0ZW1wbGF0ZSkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHNlcnZpY2VUb2tlbiA9IHRlbXBsYXRlLlJlc291cmNlcz8uW2Vyci5sb2dpY2FsSWRdPy5Qcm9wZXJ0aWVzPy5TZXJ2aWNlVG9rZW47XG4gIGlmIChzZXJ2aWNlVG9rZW4gPT09IHVuZGVmaW5lZCkge1xuICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogbm8gU2VydmljZVRva2VuIG9uIHJlc291cmNlIFwiJHtlcnIubG9naWNhbElkfVwiYCk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcmVmZXJlbmNlZExvZ2ljYWxJZCA9IHNlcnZpY2VUb2tlblJlZmVyZW5jZWRMb2dpY2FsSWQoc2VydmljZVRva2VuKTtcbiAgY29uc3QgZnVuY3Rpb25OYW1lID0gYXdhaXQgcmVzb2x2ZVNlcnZpY2VUb2tlblRvRnVuY3Rpb25OYW1lKGNmbiwgc3RhY2tOYW1lLCBzZXJ2aWNlVG9rZW4sIHJlZmVyZW5jZWRMb2dpY2FsSWQsIGRlYnVnKTtcbiAgaWYgKCFmdW5jdGlvbk5hbWUpIHtcbiAgICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IGNvdWxkIG5vdCByZXNvbHZlIFNlcnZpY2VUb2tlbiB0byBhIExhbWJkYSBmdW5jdGlvbicpO1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIC8vIFByZWZlciB0aGUgZnVuY3Rpb24ncyBjb25maWd1cmVkIGxvZyBncm91cCBhcyBkZXJpdmVkIGZyb20gdGhlIHRlbXBsYXRlIChyb2xsYmFjay1wcm9vZikuXG4gIC8vIE9ubHkgcmVzb2x2YWJsZSB3aGVuIHRoZSBmdW5jdGlvbiBpcyBkZWZpbmVkIGluIHRoaXMgc3RhY2sgKFNlcnZpY2VUb2tlbiBpcyBhIFJlZi9HZXRBdHQpLlxuICBjb25zdCB0ZW1wbGF0ZUxvZ0dyb3VwID0gcmVmZXJlbmNlZExvZ2ljYWxJZFxuICAgID8gYXdhaXQgcmVzb2x2ZUNvbmZpZ3VyZWRMb2dHcm91cChjZm4sIHN0YWNrTmFtZSwgdGVtcGxhdGUsIHJlZmVyZW5jZWRMb2dpY2FsSWQsIGRlYnVnKVxuICAgIDogdW5kZWZpbmVkO1xuXG4gIC8vIFRoZSBjZm4tcmVzcG9uc2UgbGlicmFyeSB3cml0ZXMgdGhlIGZhaWxpbmcgbG9nIHN0cmVhbSBuYW1lIGludG8gdGhlIHN0YXR1cyByZWFzb25cbiAgLy8gKGFuZCB1c2VzIGl0IGFzIHRoZSBkZWZhdWx0IHBoeXNpY2FsIElEKS4gVGFyZ2V0aW5nIGl0IGdpdmVzIHRoZSBleGFjdCBpbnZvY2F0aW9uLlxuICBjb25zdCBzdHJlYW1OYW1lID0gZXh0cmFjdExvZ1N0cmVhbU5hbWUoZXJyLm1lc3NhZ2UpID8/IGxvZ1N0cmVhbU5hbWVGcm9tUGh5c2ljYWxJZChlcnIucGh5c2ljYWxJZCk7XG5cbiAgcmV0dXJuIGZldGNoQ3VzdG9tUmVzb3VyY2VMb2dzKGN3bCwgbGFtYmRhLCBmdW5jdGlvbk5hbWUsIHRlbXBsYXRlTG9nR3JvdXAsIHN0cmVhbU5hbWUsIGVyci50aW1lc3RhbXAsIHJlZ2lvbiwgZGVidWcpO1xufVxuXG4vKipcbiAqIEZldGNoIGFuZCBwYXJzZSB0aGUgc3RhY2sncyAob3JpZ2luYWwpIHRlbXBsYXRlLiBSZXR1cm5zIGB1bmRlZmluZWRgIGlmIGl0IGNhbid0IGJlIHJlYWQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldFN0YWNrVGVtcGxhdGUoXG4gIGNmbjogSUNsb3VkRm9ybWF0aW9uQ2xpZW50LFxuICBzdGFja05hbWU6IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8YW55IHwgdW5kZWZpbmVkPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IGNmbi5nZXRUZW1wbGF0ZSh7IFN0YWNrTmFtZTogc3RhY2tOYW1lLCBUZW1wbGF0ZVN0YWdlOiAnT3JpZ2luYWwnIH0pO1xuICAgIGlmICghcmVzcC5UZW1wbGF0ZUJvZHkpIHtcbiAgICAgIGF3YWl0IGRlYnVnKCdDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogZW1wdHkgdGVtcGxhdGUgYm9keScpO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIGRlc2VyaWFsaXplU3RydWN0dXJlKHJlc3AuVGVtcGxhdGVCb2R5KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgYXdhaXQgZGVidWcoYEN1c3RvbSByZXNvdXJjZSBpbnZlc3RpZ2F0aW9uOiBmYWlsZWQgdG8gcmVhZCB0ZW1wbGF0ZTogJHtlLm1lc3NhZ2V9YCk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIGJhY2tpbmcgTGFtYmRhJ3MgY29uZmlndXJlZCBsb2cgZ3JvdXAgZnJvbSB0aGUgdGVtcGxhdGUuXG4gKlxuICogVGhlIHRlbXBsYXRlIHN1cnZpdmVzIHJvbGxiYWNrICh3aGVuIHRoZSBsaXZlIGZ1bmN0aW9uIG1heSBub3QpLCBzbyBpdCBpcyB0aGUgcHJlZmVycmVkXG4gKiBzb3VyY2UuIEhhbmRsZXMgdGhlIGZ1bmN0aW9uJ3MgYExvZ2dpbmdDb25maWcuTG9nR3JvdXBgIGFzOlxuICogLSBhIGxpdGVyYWwgc3RyaW5nIChyZXR1cm5lZCBkaXJlY3RseSk7XG4gKiAtIGEgYFJlZmAgdG8gYW4gYEFXUzo6TG9nczo6TG9nR3JvdXBgIHdpdGggYSBsaXRlcmFsIGBMb2dHcm91cE5hbWVgIChyZXR1cm5lZCBkaXJlY3RseSk7XG4gKiAtIGEgYFJlZmAgdG8gYW4gYEFXUzo6TG9nczo6TG9nR3JvdXBgIHdob3NlIG5hbWUgQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzICh0aGUgY29tbW9uIENES1xuICogICBjYXNlKSDigJQgcmVzb2x2ZWQgdG8gaXRzIHBoeXNpY2FsIG5hbWUgdmlhIGBkZXNjcmliZVN0YWNrUmVzb3VyY2VzYCwgd2hpY2ggc3RpbGwgcmV0dXJuc1xuICogICBSRVRBSU5lZC9vcnBoYW5lZCByZXNvdXJjZXMgYWZ0ZXIgYSByb2xsYmFjay5cbiAqXG4gKiBSZXR1cm5zIGB1bmRlZmluZWRgIHdoZW4gdGhlcmUgaXMgbm8gY29uZmlndXJlZCBsb2cgZ3JvdXAgb3IgaXQgY2FuJ3QgYmUgcmVzb2x2ZWRcbiAqIChjYWxsZXIgdGhlbiBmYWxscyBiYWNrIHRvIHRoZSBsaXZlIGZ1bmN0aW9uIGNvbmZpZ3VyYXRpb24pLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQ29uZmlndXJlZExvZ0dyb3VwKFxuICBjZm46IElDbG91ZEZvcm1hdGlvbkNsaWVudCxcbiAgc3RhY2tOYW1lOiBzdHJpbmcsXG4gIHRlbXBsYXRlOiBhbnksXG4gIGZ1bmN0aW9uTG9naWNhbElkOiBzdHJpbmcsXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBjb25zdCBsb2dHcm91cCA9IHRlbXBsYXRlLlJlc291cmNlcz8uW2Z1bmN0aW9uTG9naWNhbElkXT8uUHJvcGVydGllcz8uTG9nZ2luZ0NvbmZpZz8uTG9nR3JvdXA7XG4gIGlmICh0eXBlb2YgbG9nR3JvdXAgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGxvZ0dyb3VwO1xuICB9XG4gIGlmIChsb2dHcm91cCAmJiB0eXBlb2YgbG9nR3JvdXAgPT09ICdvYmplY3QnICYmIHR5cGVvZiBsb2dHcm91cC5SZWYgPT09ICdzdHJpbmcnKSB7XG4gICAgY29uc3QgcmVmZXJlbmNlZCA9IHRlbXBsYXRlLlJlc291cmNlcz8uW2xvZ0dyb3VwLlJlZl07XG4gICAgY29uc3QgbmFtZSA9IHJlZmVyZW5jZWQ/LlByb3BlcnRpZXM/LkxvZ0dyb3VwTmFtZTtcbiAgICBpZiAodHlwZW9mIG5hbWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gbmFtZTtcbiAgICB9XG4gICAgLy8gTm8gZXhwbGljaXQgbmFtZSAoQ2xvdWRGb3JtYXRpb24gZ2VuZXJhdGVzIGl0KSDigJQgcmVzb2x2ZSB0aGUgbG9nLWdyb3VwIHJlc291cmNlJ3NcbiAgICAvLyBwaHlzaWNhbCBuYW1lLCB3aGljaCBpcyB0aGUgbG9nIGdyb3VwIG5hbWUuXG4gICAgcmV0dXJuIChhd2FpdCByZXNvbHZlU3RhY2tSZXNvdXJjZShjZm4sIHN0YWNrTmFtZSwgbG9nR3JvdXAuUmVmLCBkZWJ1ZykpPy5waHlzaWNhbElkO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHJlc291cmNlJ3MgcGh5c2ljYWwgSUQgYW5kIHR5cGUgYnkgbG9naWNhbCBJRC4gUmV0dXJucyBgdW5kZWZpbmVkYCBvbiBmYWlsdXJlLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlU3RhY2tSZXNvdXJjZShcbiAgY2ZuOiBJQ2xvdWRGb3JtYXRpb25DbGllbnQsXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBsb2dpY2FsSWQ6IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8eyBwaHlzaWNhbElkPzogc3RyaW5nOyByZXNvdXJjZVR5cGU/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBjZm4uZGVzY3JpYmVTdGFja1Jlc291cmNlcyh7IFN0YWNrTmFtZTogc3RhY2tOYW1lLCBMb2dpY2FsUmVzb3VyY2VJZDogbG9naWNhbElkIH0pO1xuICAgIGNvbnN0IHJlc291cmNlID0gcmVzcC5TdGFja1Jlc291cmNlcz8uWzBdO1xuICAgIHJldHVybiByZXNvdXJjZSA/IHsgcGh5c2ljYWxJZDogcmVzb3VyY2UuUGh5c2ljYWxSZXNvdXJjZUlkLCByZXNvdXJjZVR5cGU6IHJlc291cmNlLlJlc291cmNlVHlwZSB9IDogdW5kZWZpbmVkO1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBhd2FpdCBkZWJ1ZyhgQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IGZhaWxlZCB0byByZXNvbHZlIHJlc291cmNlIFwiJHtsb2dpY2FsSWR9XCI6ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgYFNlcnZpY2VUb2tlbmAgdmFsdWUgKGEgbGl0ZXJhbCBBUk4sIGFuIGBGbjo6R2V0QXR0YCwgb3IgYSBgUmVmYCkgdG8gYSBMYW1iZGFcbiAqIGZ1bmN0aW9uIG5hbWUuIEludHJpbnNpY3MgYXJlIHJlc29sdmVkIHZpYSBgZGVzY3JpYmVTdGFja1Jlc291cmNlc2AuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVTZXJ2aWNlVG9rZW5Ub0Z1bmN0aW9uTmFtZShcbiAgY2ZuOiBJQ2xvdWRGb3JtYXRpb25DbGllbnQsXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBzZXJ2aWNlVG9rZW46IGFueSxcbiAgcmVmZXJlbmNlZExvZ2ljYWxJZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgaWYgKHJlZmVyZW5jZWRMb2dpY2FsSWQpIHtcbiAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHJlc29sdmVTdGFja1Jlc291cmNlKGNmbiwgc3RhY2tOYW1lLCByZWZlcmVuY2VkTG9naWNhbElkLCBkZWJ1Zyk7XG4gICAgLy8gT25seSB0cmVhdCB0aGUgcmVmZXJlbmNlIGFzIGEgTGFtYmRhIGZ1bmN0aW9uLiBXaXRob3V0IHRoaXMsIGEgU2VydmljZVRva2VuIHBvaW50aW5nIGF0XG4gICAgLy8gYSBub24tTGFtYmRhIHJlc291cmNlIChlLmcuIGFuIFNOUyB0b3BpYykgd2hvc2UgcGh5c2ljYWwgSUQgaXMgYSBiYXJlIG5hbWUgd291bGQgYmVcbiAgICAvLyBtaXN0YWtlbiBmb3IgYSBmdW5jdGlvbiBuYW1lLCBwcm9kdWNpbmcgYSBtaXNsZWFkaW5nIC9hd3MvbGFtYmRhLzxuYW1lPiBsb2cgbG9va3VwLlxuICAgIGlmIChyZXNvdXJjZT8ucmVzb3VyY2VUeXBlICYmIHJlc291cmNlLnJlc291cmNlVHlwZSAhPT0gJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicpIHtcbiAgICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogU2VydmljZVRva2VuIHJlZmVyZW5jZXMgYSAke3Jlc291cmNlLnJlc291cmNlVHlwZX0sIG5vdCBhIExhbWJkYSBmdW5jdGlvbmApO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIHJlc291cmNlPy5waHlzaWNhbElkID8gZnVuY3Rpb25OYW1lRnJvbUFybk9yTmFtZShyZXNvdXJjZS5waHlzaWNhbElkKSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmICh0eXBlb2Ygc2VydmljZVRva2VuID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmdW5jdGlvbk5hbWVGcm9tQXJuT3JOYW1lKHNlcnZpY2VUb2tlbik7XG4gIH1cblxuICBhd2FpdCBkZWJ1ZygnQ3VzdG9tIHJlc291cmNlIGludmVzdGlnYXRpb246IHVuc3VwcG9ydGVkIFNlcnZpY2VUb2tlbiBzaGFwZScpO1xuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaEN1c3RvbVJlc291cmNlTG9ncyhcbiAgY3dsOiBJQ2xvdWRXYXRjaExvZ3NDbGllbnQsXG4gIGxhbWJkYTogSUxhbWJkYUNsaWVudCxcbiAgZnVuY3Rpb25OYW1lOiBzdHJpbmcsXG4gIHRlbXBsYXRlTG9nR3JvdXA6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgc3RyZWFtTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICB0aW1lc3RhbXA6IERhdGUgfCB1bmRlZmluZWQsXG4gIHJlZ2lvbjogc3RyaW5nLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHRbXT4ge1xuICBjb25zdCBmYWlsdXJlVGltZSA9IHRpbWVzdGFtcD8udmFsdWVPZigpO1xuICBjb25zdCBzdGFydFRpbWUgPSBmYWlsdXJlVGltZSAhPT0gdW5kZWZpbmVkID8gZmFpbHVyZVRpbWUgLSBMT0dfV0lORE9XX0JFRk9SRV9NUyA6IERhdGUubm93KCkgLSBGQUxMQkFDS19MT0dfV0lORE9XX01TO1xuICBjb25zdCBlbmRUaW1lID0gZmFpbHVyZVRpbWUgIT09IHVuZGVmaW5lZCA/IGZhaWx1cmVUaW1lICsgTE9HX1dJTkRPV19BRlRFUl9NUyA6IHVuZGVmaW5lZDtcblxuICAvLyBDb252ZW50aW9uIGZpcnN0OyBvbmx5IHBheSBmb3IgdGhlIGNvbmZpZ3VyZWQgZ3JvdXAgaWYgdGhlIGNvbnZlbnRpb24gZ3JvdXAgZG9lc24ndCB5aWVsZCB1c2FibGUgbGluZXMgKGVtcHR5IGdyb3VwIG9yIGZldGNoIGVycm9yKS5cbiAgY29uc3QgY29udmVudGlvbkdyb3VwID0gYC9hd3MvbGFtYmRhLyR7ZnVuY3Rpb25OYW1lfWA7XG4gIGxldCByZXN1bHQgPSBhd2FpdCBmZXRjaExvZ0xpbmVzKGN3bCwgY29udmVudGlvbkdyb3VwLCBzdHJlYW1OYW1lLCBzdGFydFRpbWUsIGVuZFRpbWUsIGRlYnVnKTtcbiAgLy8gVGhlIGdyb3VwIHdlIHBvaW50IHRoZSB1c2VyIGF0LiBPbmNlIHdlIGxlYXJuIHRoZSBmdW5jdGlvbidzIGNvbmZpZ3VyZWQgbG9nIGdyb3VwLCBwcmVmZXJcbiAgLy8gaXQgZm9yIHRoZSBsaW5rIGV2ZW4gaWYgaXQgdG9vIGlzIGVtcHR5IOKAlCBpdCdzIHdoZXJlIHRoZSBmdW5jdGlvbiBhY3R1YWxseSBsb2dzLCB3aGVyZWFzXG4gIC8vIHRoZSBjb252ZW50aW9uIGdyb3VwIG1heSBub3QgZXhpc3QgZm9yIGFkdmFuY2VkLWxvZ2dpbmcgZnVuY3Rpb25zLlxuICBsZXQgbG9nR3JvdXAgPSBjb252ZW50aW9uR3JvdXA7XG5cbiAgaWYgKHJlc3VsdC5raW5kICE9PSAnbGluZXMnKSB7XG4gICAgLy8gUHJlZmVyIHRoZSB0ZW1wbGF0ZS1kZXJpdmVkIGdyb3VwIChyb2xsYmFjay1wcm9vZik7IGZhbGwgYmFjayB0byB0aGUgbGl2ZSBmdW5jdGlvblxuICAgIC8vIGNvbmZpZ3VyYXRpb24gb25seSB3aGVuIHRoZSB0ZW1wbGF0ZSBjb3VsZG4ndCB0ZWxsIHVzIChlLmcuIHVucmVzb2x2YWJsZSBpbnRyaW5zaWMsIG9yXG4gICAgLy8gdGhlIGZ1bmN0aW9uIGlzIGRlZmluZWQgb3V0c2lkZSB0aGlzIHN0YWNrKS5cbiAgICBjb25zdCBjb25maWd1cmVkR3JvdXAgPSB0ZW1wbGF0ZUxvZ0dyb3VwID8/IGF3YWl0IGNvbmZpZ3VyZWRMb2dHcm91cChsYW1iZGEsIGZ1bmN0aW9uTmFtZSwgZGVidWcpO1xuICAgIGlmIChjb25maWd1cmVkR3JvdXAgJiYgY29uZmlndXJlZEdyb3VwICE9PSBjb252ZW50aW9uR3JvdXApIHtcbiAgICAgIGxvZ0dyb3VwID0gY29uZmlndXJlZEdyb3VwO1xuICAgICAgY29uc3QgY29uZmlndXJlZFJlc3VsdCA9IGF3YWl0IGZldGNoTG9nTGluZXMoY3dsLCBjb25maWd1cmVkR3JvdXAsIHN0cmVhbU5hbWUsIHN0YXJ0VGltZSwgZW5kVGltZSwgZGVidWcpO1xuICAgICAgLy8gS2VlcCB0aGUgY29uZmlndXJlZC1ncm91cCByZXN1bHQgdW5sZXNzIGl0IGVycm9yZWQgd2hpbGUgdGhlIGNvbnZlbnRpb24gYXR0ZW1wdCB3YXMgYVxuICAgICAgLy8gY2xlYW4gZW1wdHkgKGFuIFwiZW1wdHlcIiBhbnN3ZXIgaXMgbW9yZSBpbmZvcm1hdGl2ZSB0byBzdXJmYWNlIHRoYW4gYSBmZXRjaCBlcnJvcikuXG4gICAgICBpZiAoY29uZmlndXJlZFJlc3VsdC5raW5kID09PSAnbGluZXMnIHx8IHJlc3VsdC5raW5kICE9PSAnZW1wdHknKSB7XG4gICAgICAgIHJlc3VsdCA9IGNvbmZpZ3VyZWRSZXN1bHQ7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gTGVhZCB3aXRoIHRoZSBsb2cgZ3JvdXAgc28gdGhlIHVzZXIgY2FuIHRlbGwgd2hpY2ggZnVuY3Rpb24gdGhlc2UgbG9ncyBiZWxvbmcgdG9cbiAgLy8gKHRoZSBmb3JtYXR0ZXIgcmVuZGVycyBtZXNzYWdlcyBidXQgbm90IGBzb3VyY2VgLCBhbmQgdGhlIGxpbmsgaXMgVVJMLWVuY29kZWQpLlxuICBjb25zdCBoZWFkZXIgPSBgTG9ncyBmcm9tICR7bG9nR3JvdXB9OmA7XG4gIGNvbnN0IGJvZHkgPSByZXN1bHQua2luZCA9PT0gJ2xpbmVzJ1xuICAgID8gcmVzdWx0LmxpbmVzXG4gICAgOiByZXN1bHQua2luZCA9PT0gJ2Vycm9yJ1xuICAgICAgPyBbJ0NvdWxkIG5vdCBmZXRjaCBsb2dzICh0aGUgbG9nIGdyb3VwIG1heSBub3QgZXhpc3QsIG9yIHRoZSBjcmVkZW50aWFscyBsYWNrIGxvZ3M6RmlsdGVyTG9nRXZlbnRzKS4gU2VlIHRoZSBjb25zb2xlIGxpbmsgYmVsb3cuJ11cbiAgICAgIDogWydObyBsb2cgZXZlbnRzIGZvdW5kIGFyb3VuZCB0aGUgdGltZSBvZiBmYWlsdXJlLiBUaGUgZnVuY3Rpb24gbWF5IG5vdCBoYXZlIHByb2R1Y2VkIG91dHB1dCwgb3IgbG9nZ2luZyBtYXkgbm90IGJlIGNvbmZpZ3VyZWQuJ107XG5cbiAgcmV0dXJuIFt7XG4gICAgc291cmNlOiAnQ3VzdG9tIFJlc291cmNlIExhbWJkYSBMb2dzJyxcbiAgICBtZXNzYWdlczogW2hlYWRlciwgLi4uYm9keV0sXG4gICAgbGluazogY2xvdWRXYXRjaExvZ3NDb25zb2xlVXJsKHJlZ2lvbiwgbG9nR3JvdXApLFxuICAgIGxpbmtMYWJlbDogJ0xvZ3MnLFxuICB9XTtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2YgYXR0ZW1wdGluZyB0byBmZXRjaCBsb2dzIGZyb20gYSBncm91cDogdGhlIGxpbmVzIG9uIHN1Y2Nlc3MsIG9yIGEgcmVhc29uIHdlXG4gKiBoYXZlIG5vbmUg4oCUIGRpc3Rpbmd1aXNoaW5nIGFuIGVtcHR5IGdyb3VwIGZyb20gYSBmYWlsZWQgZmV0Y2ggKGUuZy4gbWlzc2luZyBwZXJtaXNzaW9ucyksXG4gKiBzbyB0aGUgdXNlci1mYWNpbmcgbWVzc2FnZSBjYW4gcmVmbGVjdCB0aGUgcmVhbCBjYXVzZS5cbiAqL1xudHlwZSBMb2dGZXRjaFJlc3VsdCA9XG4gIHwgeyBraW5kOiAnbGluZXMnOyBsaW5lczogc3RyaW5nW10gfVxuICB8IHsga2luZDogJ2VtcHR5JyB9XG4gIHwgeyBraW5kOiAnZXJyb3InIH07XG5cbi8qKlxuICogRmV0Y2ggYW5kIHRyaW0gcmVjZW50IGxvZyBsaW5lcyBmcm9tIGEgZ3JvdXAuXG4gKlxuICogVHJpZXMgdGhlIHRhcmdldGVkIHN0cmVhbSBmaXJzdCAobW9zdCByZWxldmFudCksIGJ1dCB0aGUgY2ZuLXJlc3BvbnNlIHN0cmVhbSBuYW1lIGNhbiBiZVxuICogc3RhbGUgb24gdXBkYXRlL3JvbGxiYWNrIGZhaWx1cmVzIChpdCdzIHBpbm5lZCB0byB0aGUgb3JpZ2luYWwgY3JlYXRlIGludm9jYXRpb24pLiBJZiB0aGVcbiAqIHRhcmdldGVkIHF1ZXJ5IGZpbmRzIG5vdGhpbmcsIGZhbGxzIGJhY2sgdG8gYSBncm91cC13aWRlIHNjYW4gb3ZlciB0aGUgdGltZSB3aW5kb3cgc28gYVxuICogc3RhbGUgc3RyZWFtIGNhbid0IGhpZGUgdGhlIGFjdHVhbCBmYWlsaW5nIGludm9jYXRpb24ncyBsb2dzLlxuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaExvZ0xpbmVzKFxuICBjd2w6IElDbG91ZFdhdGNoTG9nc0NsaWVudCxcbiAgbG9nR3JvdXA6IHN0cmluZyxcbiAgc3RyZWFtTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBzdGFydFRpbWU6IG51bWJlcixcbiAgZW5kVGltZTogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxMb2dGZXRjaFJlc3VsdD4ge1xuICBpZiAoc3RyZWFtTmFtZSkge1xuICAgIGNvbnN0IHRhcmdldGVkID0gYXdhaXQgZmlsdGVyTG9nTGluZXMoY3dsLCBsb2dHcm91cCwgc3RyZWFtTmFtZSwgc3RhcnRUaW1lLCBlbmRUaW1lLCBkZWJ1Zyk7XG4gICAgaWYgKHRhcmdldGVkLmtpbmQgPT09ICdsaW5lcycpIHtcbiAgICAgIHJldHVybiB0YXJnZXRlZDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZpbHRlckxvZ0xpbmVzKGN3bCwgbG9nR3JvdXAsIHVuZGVmaW5lZCwgc3RhcnRUaW1lLCBlbmRUaW1lLCBkZWJ1Zyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpbHRlckxvZ0xpbmVzKFxuICBjd2w6IElDbG91ZFdhdGNoTG9nc0NsaWVudCxcbiAgbG9nR3JvdXA6IHN0cmluZyxcbiAgc3RyZWFtTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBzdGFydFRpbWU6IG51bWJlcixcbiAgZW5kVGltZTogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBkZWJ1ZzogKG1zZzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+LFxuKTogUHJvbWlzZTxMb2dGZXRjaFJlc3VsdD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBjd2wuZmlsdGVyTG9nRXZlbnRzKHtcbiAgICAgIGxvZ0dyb3VwTmFtZTogbG9nR3JvdXAsXG4gICAgICBzdGFydFRpbWUsXG4gICAgICAuLi4oZW5kVGltZSAhPT0gdW5kZWZpbmVkID8geyBlbmRUaW1lIH0gOiB7fSksXG4gICAgICBsaW1pdDogMTAwMCxcbiAgICAgIC4uLihzdHJlYW1OYW1lID8geyBsb2dTdHJlYW1OYW1lczogW3N0cmVhbU5hbWVdIH0gOiB7fSksXG4gICAgfSk7XG4gICAgY29uc3QgZXZlbnRzID0gcmVzcC5ldmVudHMgPz8gW107XG4gICAgaWYgKGV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogbm8gbG9nIGV2ZW50cyBpbiAke2xvZ0dyb3VwfSR7c3RyZWFtTmFtZSA/IGAgKHN0cmVhbTogJHtzdHJlYW1OYW1lfSlgIDogJyd9YCk7XG4gICAgICByZXR1cm4geyBraW5kOiAnZW1wdHknIH07XG4gICAgfVxuICAgIC8vIExhbWJkYSBsb2cgZXZlbnRzIGhhdmUgYSBrbm93biBzdHJ1Y3R1cmUgKHRleHQtIG9yIEpTT04tZm9ybWF0KSwgdW5saWtlIHJhdyBFQ1NcbiAgICAvLyBjb250YWluZXIgb3V0cHV0LCBzbyB3ZSBub3JtYWxpemUgdGhlbSBpbnRvIHJlYWRhYmxlIGxpbmVzIGJlZm9yZSB0cmltbWluZy5cbiAgICByZXR1cm4geyBraW5kOiAnbGluZXMnLCBsaW5lczogdHJpbVRvUmVjZW50TGluZXMocGFyc2VMYW1iZGFMb2dFdmVudHMoZXZlbnRzKSkgfTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgYXdhaXQgZGVidWcoYEN1c3RvbSByZXNvdXJjZSBpbnZlc3RpZ2F0aW9uOiBmYWlsZWQgdG8gZmV0Y2ggbG9ncyBmcm9tICR7bG9nR3JvdXB9OiAke2UubWVzc2FnZX1gKTtcbiAgICByZXR1cm4geyBraW5kOiAnZXJyb3InIH07XG4gIH1cbn1cblxuLyoqIFJlYWQgdGhlIGZ1bmN0aW9uJ3MgY29uZmlndXJlZCAoYWR2YW5jZWQtbG9nZ2luZykgbG9nIGdyb3VwLCBpZiBhbnkuICovXG5hc3luYyBmdW5jdGlvbiBjb25maWd1cmVkTG9nR3JvdXAoXG4gIGxhbWJkYTogSUxhbWJkYUNsaWVudCxcbiAgZnVuY3Rpb25OYW1lOiBzdHJpbmcsXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBsYW1iZGEuZ2V0RnVuY3Rpb25Db25maWd1cmF0aW9uKHsgRnVuY3Rpb25OYW1lOiBmdW5jdGlvbk5hbWUgfSk7XG4gICAgcmV0dXJuIHJlc3AuTG9nZ2luZ0NvbmZpZz8uTG9nR3JvdXA7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIGF3YWl0IGRlYnVnKGBDdXN0b20gcmVzb3VyY2UgaW52ZXN0aWdhdGlvbjogZmFpbGVkIHRvIHJlYWQgZnVuY3Rpb24gY29uZmlndXJhdGlvbjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AdditionalDiagnosticContext } from '../../actions/diagnose';
|
|
2
|
+
import type { SDK } from '../aws-auth/sdk';
|
|
3
|
+
import type { ResourceError } from '../stack-events/resource-errors';
|
|
4
|
+
/**
|
|
5
|
+
* Options that influence how a resource is investigated.
|
|
6
|
+
*/
|
|
7
|
+
export interface InvestigateOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Whether CloudFormation rollback is enabled for this deployment.
|
|
10
|
+
*
|
|
11
|
+
* When rollback is enabled, a failed resource is torn down before we can
|
|
12
|
+
* inspect its runtime state, so we may suggest re-running with `--no-rollback`
|
|
13
|
+
* to retain that detail.
|
|
14
|
+
*
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
readonly rollbackEnabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function investigateEcsService(err: ResourceError, sdk: SDK, debug: (msg: string) => Promise<void>, options: InvestigateOptions): Promise<AdditionalDiagnosticContext[]>;
|
|
20
|
+
//# sourceMappingURL=investigate-ecs-service.d.ts.map
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.investigateEcsService = investigateEcsService;
|
|
4
|
+
const format_utils_1 = require("./format-utils");
|
|
5
|
+
const resource_identifiers_1 = require("./resource-identifiers");
|
|
6
|
+
/** Fallback look-back when no failure timestamp is available. */
|
|
7
|
+
const FALLBACK_LOG_WINDOW_MS = 30 * 60 * 1000;
|
|
8
|
+
async function investigateEcsService(err, sdk, debug, options) {
|
|
9
|
+
const physicalId = err.physicalId;
|
|
10
|
+
if (!physicalId) {
|
|
11
|
+
await debug('ECS investigation: no physical ID available');
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const { cluster, serviceName } = (0, resource_identifiers_1.parseEcsServiceIdentifier)(physicalId);
|
|
15
|
+
if (!serviceName) {
|
|
16
|
+
await debug(`ECS investigation: could not parse service identifier from "${physicalId}"`);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const region = sdk.currentRegion;
|
|
20
|
+
const ecs = sdk.ecs();
|
|
21
|
+
const cwl = sdk.cloudWatchLogs();
|
|
22
|
+
const service = await describeService(ecs, cluster, serviceName, debug);
|
|
23
|
+
if (!service) {
|
|
24
|
+
// The service is gone. The most common reason is that CloudFormation rolled the
|
|
25
|
+
// deployment back and deleted it, taking the task/runtime detail with it. If rollback
|
|
26
|
+
// was enabled, point the user at the flag that would have retained that detail.
|
|
27
|
+
if (options.rollbackEnabled) {
|
|
28
|
+
return [{
|
|
29
|
+
source: 'ECS Service',
|
|
30
|
+
messages: [
|
|
31
|
+
'The service and its tasks were removed during rollback, so container-level failure detail is unavailable.',
|
|
32
|
+
'Re-run the deployment with `--no-rollback` to retain the failed tasks and see why they stopped.',
|
|
33
|
+
],
|
|
34
|
+
}];
|
|
35
|
+
}
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const results = [];
|
|
39
|
+
const stoppedTaskResult = await getStoppedTaskReasons(ecs, cluster, serviceName, region, service, debug);
|
|
40
|
+
if (stoppedTaskResult.context) {
|
|
41
|
+
results.push(stoppedTaskResult.context);
|
|
42
|
+
}
|
|
43
|
+
const taskDefinitionArn = service.taskDefinition;
|
|
44
|
+
if (!taskDefinitionArn) {
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
const taskDefInfo = await getTaskDefinitionInfo(ecs, taskDefinitionArn, debug);
|
|
48
|
+
if (!taskDefInfo) {
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
const logConfigs = taskDefInfo.logConfigs;
|
|
52
|
+
if (logConfigs.length === 0) {
|
|
53
|
+
results.push({
|
|
54
|
+
source: 'CloudWatch Logs',
|
|
55
|
+
messages: [
|
|
56
|
+
'No CloudWatch Logs configuration found. Enable logging to see container output on failure.',
|
|
57
|
+
'Example:',
|
|
58
|
+
' taskDefinition.addContainer("app", {',
|
|
59
|
+
' // ...',
|
|
60
|
+
' logging: ecs.LogDrivers.awsLogs({ streamPrefix: "my-service" }),',
|
|
61
|
+
' });',
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
// `logConfigs` has one entry per container in the task definition that uses the awslogs
|
|
67
|
+
// driver — a handful at most — so this fan-out is bounded by the task shape and needs no
|
|
68
|
+
// explicit concurrency limit.
|
|
69
|
+
// eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
|
|
70
|
+
const logResults = await Promise.all(logConfigs.map(cfg => fetchRecentLogs(cwl, cfg, region, stoppedTaskResult.taskIds, debug)));
|
|
71
|
+
const logContexts = logResults.filter((c) => c !== undefined);
|
|
72
|
+
results.push(...logContexts);
|
|
73
|
+
if (logContexts.length === 0) {
|
|
74
|
+
results.push({
|
|
75
|
+
source: 'CloudWatch Logs',
|
|
76
|
+
messages: ['No CloudWatch Logs found.'],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return results;
|
|
80
|
+
}
|
|
81
|
+
async function describeService(ecs, cluster, serviceName, debug) {
|
|
82
|
+
try {
|
|
83
|
+
const resp = await ecs.describeServices({ cluster, services: [serviceName] });
|
|
84
|
+
const service = resp.services?.[0];
|
|
85
|
+
if (!service) {
|
|
86
|
+
await debug(`ECS investigation: service "${serviceName}" not found`);
|
|
87
|
+
}
|
|
88
|
+
return service;
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
await debug(`ECS investigation: failed to describe service: ${e.message}`);
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function getStoppedTaskReasons(ecs, cluster, serviceName, region, service, debug) {
|
|
96
|
+
try {
|
|
97
|
+
// Ask ECS for the service's stopped tasks. The IDs we need live in "has started 1 tasks: (task <id>)" events
|
|
98
|
+
const taskIds = await listStoppedTaskIds(ecs, cluster, serviceName, debug);
|
|
99
|
+
const messages = [];
|
|
100
|
+
if (taskIds.length > 0) {
|
|
101
|
+
// Show details from the most recently stopped task only.
|
|
102
|
+
const tasksResp = await ecs.describeTasks({ cluster, tasks: [taskIds[0]] });
|
|
103
|
+
const task = tasksResp.tasks?.[0];
|
|
104
|
+
if (task) {
|
|
105
|
+
if (task.stoppedReason) {
|
|
106
|
+
messages.push(`Task stopped: ${task.stoppedReason}`);
|
|
107
|
+
}
|
|
108
|
+
for (const container of task.containers ?? []) {
|
|
109
|
+
if (container.reason) {
|
|
110
|
+
messages.push(`Container "${container.name}": ${container.reason}`);
|
|
111
|
+
}
|
|
112
|
+
if (container.exitCode != null && container.exitCode !== 0) {
|
|
113
|
+
messages.push(`Container "${container.name}" exited with code ${container.exitCode}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (messages.length > 0 && taskIds.length > 1) {
|
|
118
|
+
messages.push(`(${taskIds.length - 1} other failed task(s) not shown)`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Fall back to the most relevant service event if we couldn't get a task-level reason
|
|
122
|
+
// (e.g. tasks already aged out, or no stopped tasks retained).
|
|
123
|
+
if (messages.length === 0) {
|
|
124
|
+
const failureEvent = (service.events ?? [])
|
|
125
|
+
.find(e => e.message?.includes('stopped') || e.message?.includes('failed') || e.message?.includes('unhealthy'));
|
|
126
|
+
if (failureEvent?.message) {
|
|
127
|
+
messages.push(failureEvent.message);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (messages.length === 0) {
|
|
131
|
+
return { taskIds };
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
context: {
|
|
135
|
+
source: 'ECS Stopped Tasks',
|
|
136
|
+
messages,
|
|
137
|
+
link: (0, resource_identifiers_1.ecsStoppedTasksConsoleUrl)(region, cluster ?? 'default', serviceName),
|
|
138
|
+
linkLabel: 'Tasks',
|
|
139
|
+
},
|
|
140
|
+
taskIds,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
await debug(`ECS investigation: failed to get stopped task reasons: ${e.message}`);
|
|
145
|
+
return { taskIds: [] };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Maximum number of stopped task IDs to consider. We only render detail for the most
|
|
150
|
+
* recent one, but keep a few so we can report how many others failed.
|
|
151
|
+
*/
|
|
152
|
+
const MAX_STOPPED_TASKS = 3;
|
|
153
|
+
/**
|
|
154
|
+
* List the bare task IDs of the service's stopped tasks, newest first.
|
|
155
|
+
*
|
|
156
|
+
* Prefers scoping by service name; if that yields nothing (some ECS API versions only
|
|
157
|
+
* apply the service filter to running tasks), falls back to listing the cluster's stopped
|
|
158
|
+
* tasks. Returns an empty array if none are retained (e.g. they aged out, or rollback
|
|
159
|
+
* already drained the cluster).
|
|
160
|
+
*/
|
|
161
|
+
async function listStoppedTaskIds(ecs, cluster, serviceName, debug) {
|
|
162
|
+
const toIds = (arns) => (arns ?? []).map(arn => arn.split('/').pop()).filter((id) => !!id);
|
|
163
|
+
let arns;
|
|
164
|
+
try {
|
|
165
|
+
const byService = await ecs.listTasks({ cluster, serviceName, desiredStatus: 'STOPPED' });
|
|
166
|
+
arns = byService.taskArns;
|
|
167
|
+
if (!arns || arns.length === 0) {
|
|
168
|
+
const byCluster = await ecs.listTasks({ cluster, desiredStatus: 'STOPPED' });
|
|
169
|
+
arns = byCluster.taskArns;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
await debug(`ECS investigation: failed to list stopped tasks: ${e.message}`);
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
return toIds(arns).slice(0, MAX_STOPPED_TASKS);
|
|
177
|
+
}
|
|
178
|
+
async function getTaskDefinitionInfo(ecs, taskDefinitionArn, debug) {
|
|
179
|
+
try {
|
|
180
|
+
const resp = await ecs.describeTaskDefinition({ taskDefinition: taskDefinitionArn });
|
|
181
|
+
const containers = resp.taskDefinition?.containerDefinitions ?? [];
|
|
182
|
+
const logConfigs = [];
|
|
183
|
+
for (const container of containers) {
|
|
184
|
+
const logConfig = container.logConfiguration;
|
|
185
|
+
if (logConfig?.logDriver === 'awslogs') {
|
|
186
|
+
const logGroup = logConfig.options?.['awslogs-group'];
|
|
187
|
+
if (logGroup) {
|
|
188
|
+
logConfigs.push({
|
|
189
|
+
logGroup,
|
|
190
|
+
streamPrefix: logConfig.options?.['awslogs-stream-prefix'],
|
|
191
|
+
containerName: container.name,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { logConfigs };
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
await debug(`ECS investigation: failed to describe task definition: ${e.message}`);
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function fetchRecentLogs(cwl, logConfig, region, taskIds, debug) {
|
|
204
|
+
try {
|
|
205
|
+
// Target the most recently failed task's log stream for the most relevant output
|
|
206
|
+
const lastTaskId = taskIds[0];
|
|
207
|
+
const targetStream = (logConfig.streamPrefix && logConfig.containerName && lastTaskId)
|
|
208
|
+
? `${logConfig.streamPrefix}/${logConfig.containerName}/${lastTaskId}`
|
|
209
|
+
: undefined;
|
|
210
|
+
const resp = await cwl.filterLogEvents({
|
|
211
|
+
logGroupName: logConfig.logGroup,
|
|
212
|
+
startTime: Date.now() - FALLBACK_LOG_WINDOW_MS,
|
|
213
|
+
limit: 1000,
|
|
214
|
+
...(targetStream
|
|
215
|
+
? { logStreamNames: [targetStream] }
|
|
216
|
+
: logConfig.streamPrefix ? { logStreamNamePrefix: logConfig.streamPrefix } : {}),
|
|
217
|
+
});
|
|
218
|
+
const events = resp.events ?? [];
|
|
219
|
+
if (events.length === 0) {
|
|
220
|
+
await debug(`ECS investigation: no recent log events in ${logConfig.logGroup}${targetStream ? ` (targeted stream: ${targetStream})` : ''}`);
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
const messages = (0, format_utils_1.trimToRecentLines)(events.map(e => e.message?.trimEnd()).filter((m) => m != null));
|
|
224
|
+
if (taskIds.length > 1) {
|
|
225
|
+
messages.push(`(showing logs from last failed task; ${taskIds.length - 1} other failed task(s) available in console)`);
|
|
226
|
+
}
|
|
227
|
+
const source = logConfig.containerName
|
|
228
|
+
? `CloudWatch Logs: ${logConfig.logGroup} (container: ${logConfig.containerName})`
|
|
229
|
+
: `CloudWatch Logs: ${logConfig.logGroup}`;
|
|
230
|
+
return {
|
|
231
|
+
source,
|
|
232
|
+
messages,
|
|
233
|
+
link: (0, format_utils_1.cloudWatchLogsConsoleUrl)(region, logConfig.logGroup),
|
|
234
|
+
linkLabel: 'Logs',
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
await debug(`ECS investigation: failed to fetch logs from ${logConfig.logGroup}: ${e.message}`);
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW52ZXN0aWdhdGUtZWNzLXNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbnZlc3RpZ2F0ZS1lY3Mtc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXlCQSxzREF5RkM7QUFsSEQsaURBQTZFO0FBQzdFLGlFQUE4RjtBQUs5RixpRUFBaUU7QUFDakUsTUFBTSxzQkFBc0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQWtCdkMsS0FBSyxVQUFVLHFCQUFxQixDQUN6QyxHQUFrQixFQUNsQixHQUFRLEVBQ1IsS0FBcUMsRUFDckMsT0FBMkI7SUFFM0IsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDLFVBQVUsQ0FBQztJQUNsQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDaEIsTUFBTSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztRQUMzRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxNQUFNLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxHQUFHLElBQUEsZ0RBQXlCLEVBQUMsVUFBVSxDQUFDLENBQUM7SUFDdkUsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pCLE1BQU0sS0FBSyxDQUFDLCtEQUErRCxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBQzFGLE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxhQUFhLENBQUM7SUFDakMsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3RCLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUVqQyxNQUFNLE9BQU8sR0FBRyxNQUFNLGVBQWUsQ0FBQyxHQUFHLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN4RSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixnRkFBZ0Y7UUFDaEYsc0ZBQXNGO1FB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UyxFQUFFLE1BQU07U0FDbEIsQ0FBQztJQUNKLENBQUM7SUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO1FBQ2hCLE1BQU0sS0FBSyxDQUFDLGdEQUFnRCxTQUFTLENBQUMsUUFBUSxLQUFLLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ2hHLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdHJpbVRvUmVjZW50TGluZXMsIGNsb3VkV2F0Y2hMb2dzQ29uc29sZVVybCB9IGZyb20gJy4vZm9ybWF0LXV0aWxzJztcbmltcG9ydCB7IHBhcnNlRWNzU2VydmljZUlkZW50aWZpZXIsIGVjc1N0b3BwZWRUYXNrc0NvbnNvbGVVcmwgfSBmcm9tICcuL3Jlc291cmNlLWlkZW50aWZpZXJzJztcbmltcG9ydCB0eXBlIHsgQWRkaXRpb25hbERpYWdub3N0aWNDb250ZXh0IH0gZnJvbSAnLi4vLi4vYWN0aW9ucy9kaWFnbm9zZSc7XG5pbXBvcnQgdHlwZSB7IElDbG91ZFdhdGNoTG9nc0NsaWVudCwgSUVDU0NsaWVudCwgU0RLIH0gZnJvbSAnLi4vYXdzLWF1dGgvc2RrJztcbmltcG9ydCB0eXBlIHsgUmVzb3VyY2VFcnJvciB9IGZyb20gJy4uL3N0YWNrLWV2ZW50cy9yZXNvdXJjZS1lcnJvcnMnO1xuXG4vKiogRmFsbGJhY2sgbG9vay1iYWNrIHdoZW4gbm8gZmFpbHVyZSB0aW1lc3RhbXAgaXMgYXZhaWxhYmxlLiAqL1xuY29uc3QgRkFMTEJBQ0tfTE9HX1dJTkRPV19NUyA9IDMwICogNjAgKiAxMDAwO1xuXG4vKipcbiAqIE9wdGlvbnMgdGhhdCBpbmZsdWVuY2UgaG93IGEgcmVzb3VyY2UgaXMgaW52ZXN0aWdhdGVkLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEludmVzdGlnYXRlT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGV0aGVyIENsb3VkRm9ybWF0aW9uIHJvbGxiYWNrIGlzIGVuYWJsZWQgZm9yIHRoaXMgZGVwbG95bWVudC5cbiAgICpcbiAgICogV2hlbiByb2xsYmFjayBpcyBlbmFibGVkLCBhIGZhaWxlZCByZXNvdXJjZSBpcyB0b3JuIGRvd24gYmVmb3JlIHdlIGNhblxuICAgKiBpbnNwZWN0IGl0cyBydW50aW1lIHN0YXRlLCBzbyB3ZSBtYXkgc3VnZ2VzdCByZS1ydW5uaW5nIHdpdGggYC0tbm8tcm9sbGJhY2tgXG4gICAqIHRvIHJldGFpbiB0aGF0IGRldGFpbC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgcm9sbGJhY2tFbmFibGVkPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGludmVzdGlnYXRlRWNzU2VydmljZShcbiAgZXJyOiBSZXNvdXJjZUVycm9yLFxuICBzZGs6IFNESyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbiAgb3B0aW9uczogSW52ZXN0aWdhdGVPcHRpb25zLFxuKTogUHJvbWlzZTxBZGRpdGlvbmFsRGlhZ25vc3RpY0NvbnRleHRbXT4ge1xuICBjb25zdCBwaHlzaWNhbElkID0gZXJyLnBoeXNpY2FsSWQ7XG4gIGlmICghcGh5c2ljYWxJZCkge1xuICAgIGF3YWl0IGRlYnVnKCdFQ1MgaW52ZXN0aWdhdGlvbjogbm8gcGh5c2ljYWwgSUQgYXZhaWxhYmxlJyk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgeyBjbHVzdGVyLCBzZXJ2aWNlTmFtZSB9ID0gcGFyc2VFY3NTZXJ2aWNlSWRlbnRpZmllcihwaHlzaWNhbElkKTtcbiAgaWYgKCFzZXJ2aWNlTmFtZSkge1xuICAgIGF3YWl0IGRlYnVnKGBFQ1MgaW52ZXN0aWdhdGlvbjogY291bGQgbm90IHBhcnNlIHNlcnZpY2UgaWRlbnRpZmllciBmcm9tIFwiJHtwaHlzaWNhbElkfVwiYCk7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcmVnaW9uID0gc2RrLmN1cnJlbnRSZWdpb247XG4gIGNvbnN0IGVjcyA9IHNkay5lY3MoKTtcbiAgY29uc3QgY3dsID0gc2RrLmNsb3VkV2F0Y2hMb2dzKCk7XG5cbiAgY29uc3Qgc2VydmljZSA9IGF3YWl0IGRlc2NyaWJlU2VydmljZShlY3MsIGNsdXN0ZXIsIHNlcnZpY2VOYW1lLCBkZWJ1Zyk7XG4gIGlmICghc2VydmljZSkge1xuICAgIC8vIFRoZSBzZXJ2aWNlIGlzIGdvbmUuIFRoZSBtb3N0IGNvbW1vbiByZWFzb24gaXMgdGhhdCBDbG91ZEZvcm1hdGlvbiByb2xsZWQgdGhlXG4gICAgLy8gZGVwbG95bWVudCBiYWNrIGFuZCBkZWxldGVkIGl0LCB0YWtpbmcgdGhlIHRhc2svcnVudGltZSBkZXRhaWwgd2l0aCBpdC4gSWYgcm9sbGJhY2tcbiAgICAvLyB3YXMgZW5hYmxlZCwgcG9pbnQgdGhlIHVzZXIgYXQgdGhlIGZsYWcgdGhhdCB3b3VsZCBoYXZlIHJldGFpbmVkIHRoYXQgZGV0YWlsLlxuICAgIGlmIChvcHRpb25zLnJvbGxiYWNrRW5hYmxlZCkge1xuICAgICAgcmV0dXJuIFt7XG4gICAgICAgIHNvdXJjZTogJ0VDUyBTZXJ2aWNlJyxcbiAgICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgICAnVGhlIHNlcnZpY2UgYW5kIGl0cyB0YXNrcyB3ZXJlIHJlbW92ZWQgZHVyaW5nIHJvbGxiYWNrLCBzbyBjb250YWluZXItbGV2ZWwgZmFpbHVyZSBkZXRhaWwgaXMgdW5hdmFpbGFibGUuJyxcbiAgICAgICAgICAnUmUtcnVuIHRoZSBkZXBsb3ltZW50IHdpdGggYC0tbm8tcm9sbGJhY2tgIHRvIHJldGFpbiB0aGUgZmFpbGVkIHRhc2tzIGFuZCBzZWUgd2h5IHRoZXkgc3RvcHBlZC4nLFxuICAgICAgICBdLFxuICAgICAgfV07XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdHM6IEFkZGl0aW9uYWxEaWFnbm9zdGljQ29udGV4dFtdID0gW107XG5cbiAgY29uc3Qgc3RvcHBlZFRhc2tSZXN1bHQgPSBhd2FpdCBnZXRTdG9wcGVkVGFza1JlYXNvbnMoZWNzLCBjbHVzdGVyLCBzZXJ2aWNlTmFtZSwgcmVnaW9uLCBzZXJ2aWNlLCBkZWJ1Zyk7XG4gIGlmIChzdG9wcGVkVGFza1Jlc3VsdC5jb250ZXh0KSB7XG4gICAgcmVzdWx0cy5wdXNoKHN0b3BwZWRUYXNrUmVzdWx0LmNvbnRleHQpO1xuICB9XG5cbiAgY29uc3QgdGFza0RlZmluaXRpb25Bcm4gPSBzZXJ2aWNlLnRhc2tEZWZpbml0aW9uO1xuICBpZiAoIXRhc2tEZWZpbml0aW9uQXJuKSB7XG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH1cblxuICBjb25zdCB0YXNrRGVmSW5mbyA9IGF3YWl0IGdldFRhc2tEZWZpbml0aW9uSW5mbyhlY3MsIHRhc2tEZWZpbml0aW9uQXJuLCBkZWJ1Zyk7XG4gIGlmICghdGFza0RlZkluZm8pIHtcbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIGNvbnN0IGxvZ0NvbmZpZ3MgPSB0YXNrRGVmSW5mby5sb2dDb25maWdzO1xuXG4gIGlmIChsb2dDb25maWdzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICBzb3VyY2U6ICdDbG91ZFdhdGNoIExvZ3MnLFxuICAgICAgbWVzc2FnZXM6IFtcbiAgICAgICAgJ05vIENsb3VkV2F0Y2ggTG9ncyBjb25maWd1cmF0aW9uIGZvdW5kLiBFbmFibGUgbG9nZ2luZyB0byBzZWUgY29udGFpbmVyIG91dHB1dCBvbiBmYWlsdXJlLicsXG4gICAgICAgICdFeGFtcGxlOicsXG4gICAgICAgICcgIHRhc2tEZWZpbml0aW9uLmFkZENvbnRhaW5lcihcImFwcFwiLCB7JyxcbiAgICAgICAgJyAgICAvLyAuLi4nLFxuICAgICAgICAnICAgIGxvZ2dpbmc6IGVjcy5Mb2dEcml2ZXJzLmF3c0xvZ3MoeyBzdHJlYW1QcmVmaXg6IFwibXktc2VydmljZVwiIH0pLCcsXG4gICAgICAgICcgIH0pOycsXG4gICAgICBdLFxuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLy8gYGxvZ0NvbmZpZ3NgIGhhcyBvbmUgZW50cnkgcGVyIGNvbnRhaW5lciBpbiB0aGUgdGFzayBkZWZpbml0aW9uIHRoYXQgdXNlcyB0aGUgYXdzbG9nc1xuICAvLyBkcml2ZXIg4oCUIGEgaGFuZGZ1bCBhdCBtb3N0IOKAlCBzbyB0aGlzIGZhbi1vdXQgaXMgYm91bmRlZCBieSB0aGUgdGFzayBzaGFwZSBhbmQgbmVlZHMgbm9cbiAgLy8gZXhwbGljaXQgY29uY3VycmVuY3kgbGltaXQuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAY2RrbGFicy9wcm9taXNlYWxsLW5vLXVuYm91bmRlZC1wYXJhbGxlbGlzbVxuICBjb25zdCBsb2dSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwobG9nQ29uZmlncy5tYXAoY2ZnID0+IGZldGNoUmVjZW50TG9ncyhjd2wsIGNmZywgcmVnaW9uLCBzdG9wcGVkVGFza1Jlc3VsdC50YXNrSWRzLCBkZWJ1ZykpKTtcbiAgY29uc3QgbG9nQ29udGV4dHMgPSBsb2dSZXN1bHRzLmZpbHRlcigoYyk6IGMgaXMgQWRkaXRpb25hbERpYWdub3N0aWNDb250ZXh0ID0+IGMgIT09IHVuZGVmaW5lZCk7XG5cbiAgcmVzdWx0cy5wdXNoKC4uLmxvZ0NvbnRleHRzKTtcbiAgaWYgKGxvZ0NvbnRleHRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICBzb3VyY2U6ICdDbG91ZFdhdGNoIExvZ3MnLFxuICAgICAgbWVzc2FnZXM6IFsnTm8gQ2xvdWRXYXRjaCBMb2dzIGZvdW5kLiddLFxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdHM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlc2NyaWJlU2VydmljZShcbiAgZWNzOiBJRUNTQ2xpZW50LFxuICBjbHVzdGVyOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pIHtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXNwID0gYXdhaXQgZWNzLmRlc2NyaWJlU2VydmljZXMoeyBjbHVzdGVyLCBzZXJ2aWNlczogW3NlcnZpY2VOYW1lXSB9KTtcbiAgICBjb25zdCBzZXJ2aWNlID0gcmVzcC5zZXJ2aWNlcz8uWzBdO1xuICAgIGlmICghc2VydmljZSkge1xuICAgICAgYXdhaXQgZGVidWcoYEVDUyBpbnZlc3RpZ2F0aW9uOiBzZXJ2aWNlIFwiJHtzZXJ2aWNlTmFtZX1cIiBub3QgZm91bmRgKTtcbiAgICB9XG4gICAgcmV0dXJuIHNlcnZpY2U7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIGF3YWl0IGRlYnVnKGBFQ1MgaW52ZXN0aWdhdGlvbjogZmFpbGVkIHRvIGRlc2NyaWJlIHNlcnZpY2U6ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuaW50ZXJmYWNlIFN0b3BwZWRUYXNrUmVzdWx0IHtcbiAgY29udGV4dD86IEFkZGl0aW9uYWxEaWFnbm9zdGljQ29udGV4dDtcbiAgdGFza0lkczogc3RyaW5nW107XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFN0b3BwZWRUYXNrUmVhc29ucyhcbiAgZWNzOiBJRUNTQ2xpZW50LFxuICBjbHVzdGVyOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gIHJlZ2lvbjogc3RyaW5nLFxuICBzZXJ2aWNlOiB7IGV2ZW50cz86IEFycmF5PHsgbWVzc2FnZT86IHN0cmluZyB9PjsgW2tleTogc3RyaW5nXTogYW55IH0sXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPFN0b3BwZWRUYXNrUmVzdWx0PiB7XG4gIHRyeSB7XG4gICAgLy8gQXNrIEVDUyBmb3IgdGhlIHNlcnZpY2UncyBzdG9wcGVkIHRhc2tzLiBUaGUgSURzIHdlIG5lZWQgbGl2ZSBpbiBcImhhcyBzdGFydGVkIDEgdGFza3M6ICh0YXNrIDxpZD4pXCIgZXZlbnRzXG4gICAgY29uc3QgdGFza0lkcyA9IGF3YWl0IGxpc3RTdG9wcGVkVGFza0lkcyhlY3MsIGNsdXN0ZXIsIHNlcnZpY2VOYW1lLCBkZWJ1Zyk7XG5cbiAgICBjb25zdCBtZXNzYWdlczogc3RyaW5nW10gPSBbXTtcblxuICAgIGlmICh0YXNrSWRzLmxlbmd0aCA+IDApIHtcbiAgICAgIC8vIFNob3cgZGV0YWlscyBmcm9tIHRoZSBtb3N0IHJlY2VudGx5IHN0b3BwZWQgdGFzayBvbmx5LlxuICAgICAgY29uc3QgdGFza3NSZXNwID0gYXdhaXQgZWNzLmRlc2NyaWJlVGFza3MoeyBjbHVzdGVyLCB0YXNrczogW3Rhc2tJZHNbMF1dIH0pO1xuICAgICAgY29uc3QgdGFzayA9IHRhc2tzUmVzcC50YXNrcz8uWzBdO1xuICAgICAgaWYgKHRhc2spIHtcbiAgICAgICAgaWYgKHRhc2suc3RvcHBlZFJlYXNvbikge1xuICAgICAgICAgIG1lc3NhZ2VzLnB1c2goYFRhc2sgc3RvcHBlZDogJHt0YXNrLnN0b3BwZWRSZWFzb259YCk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChjb25zdCBjb250YWluZXIgb2YgdGFzay5jb250YWluZXJzID8/IFtdKSB7XG4gICAgICAgICAgaWYgKGNvbnRhaW5lci5yZWFzb24pIHtcbiAgICAgICAgICAgIG1lc3NhZ2VzLnB1c2goYENvbnRhaW5lciBcIiR7Y29udGFpbmVyLm5hbWV9XCI6ICR7Y29udGFpbmVyLnJlYXNvbn1gKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGNvbnRhaW5lci5leGl0Q29kZSAhPSBudWxsICYmIGNvbnRhaW5lci5leGl0Q29kZSAhPT0gMCkge1xuICAgICAgICAgICAgbWVzc2FnZXMucHVzaChgQ29udGFpbmVyIFwiJHtjb250YWluZXIubmFtZX1cIiBleGl0ZWQgd2l0aCBjb2RlICR7Y29udGFpbmVyLmV4aXRDb2RlfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA+IDAgJiYgdGFza0lkcy5sZW5ndGggPiAxKSB7XG4gICAgICAgIG1lc3NhZ2VzLnB1c2goYCgke3Rhc2tJZHMubGVuZ3RoIC0gMX0gb3RoZXIgZmFpbGVkIHRhc2socykgbm90IHNob3duKWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZhbGwgYmFjayB0byB0aGUgbW9zdCByZWxldmFudCBzZXJ2aWNlIGV2ZW50IGlmIHdlIGNvdWxkbid0IGdldCBhIHRhc2stbGV2ZWwgcmVhc29uXG4gICAgLy8gKGUuZy4gdGFza3MgYWxyZWFkeSBhZ2VkIG91dCwgb3Igbm8gc3RvcHBlZCB0YXNrcyByZXRhaW5lZCkuXG4gICAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc3QgZmFpbHVyZUV2ZW50ID0gKHNlcnZpY2UuZXZlbnRzID8/IFtdKVxuICAgICAgICAuZmluZChlID0+IGUubWVzc2FnZT8uaW5jbHVkZXMoJ3N0b3BwZWQnKSB8fCBlLm1lc3NhZ2U/LmluY2x1ZGVzKCdmYWlsZWQnKSB8fCBlLm1lc3NhZ2U/LmluY2x1ZGVzKCd1bmhlYWx0aHknKSk7XG4gICAgICBpZiAoZmFpbHVyZUV2ZW50Py5tZXNzYWdlKSB7XG4gICAgICAgIG1lc3NhZ2VzLnB1c2goZmFpbHVyZUV2ZW50Lm1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChtZXNzYWdlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB7IHRhc2tJZHMgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29udGV4dDoge1xuICAgICAgICBzb3VyY2U6ICdFQ1MgU3RvcHBlZCBUYXNrcycsXG4gICAgICAgIG1lc3NhZ2VzLFxuICAgICAgICBsaW5rOiBlY3NTdG9wcGVkVGFza3NDb25zb2xlVXJsKHJlZ2lvbiwgY2x1c3RlciA/PyAnZGVmYXVsdCcsIHNlcnZpY2VOYW1lKSxcbiAgICAgICAgbGlua0xhYmVsOiAnVGFza3MnLFxuICAgICAgfSxcbiAgICAgIHRhc2tJZHMsXG4gICAgfTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgYXdhaXQgZGVidWcoYEVDUyBpbnZlc3RpZ2F0aW9uOiBmYWlsZWQgdG8gZ2V0IHN0b3BwZWQgdGFzayByZWFzb25zOiAke2UubWVzc2FnZX1gKTtcbiAgICByZXR1cm4geyB0YXNrSWRzOiBbXSB9O1xuICB9XG59XG5cbi8qKlxuICogTWF4aW11bSBudW1iZXIgb2Ygc3RvcHBlZCB0YXNrIElEcyB0byBjb25zaWRlci4gV2Ugb25seSByZW5kZXIgZGV0YWlsIGZvciB0aGUgbW9zdFxuICogcmVjZW50IG9uZSwgYnV0IGtlZXAgYSBmZXcgc28gd2UgY2FuIHJlcG9ydCBob3cgbWFueSBvdGhlcnMgZmFpbGVkLlxuICovXG5jb25zdCBNQVhfU1RPUFBFRF9UQVNLUyA9IDM7XG5cbi8qKlxuICogTGlzdCB0aGUgYmFyZSB0YXNrIElEcyBvZiB0aGUgc2VydmljZSdzIHN0b3BwZWQgdGFza3MsIG5ld2VzdCBmaXJzdC5cbiAqXG4gKiBQcmVmZXJzIHNjb3BpbmcgYnkgc2VydmljZSBuYW1lOyBpZiB0aGF0IHlpZWxkcyBub3RoaW5nIChzb21lIEVDUyBBUEkgdmVyc2lvbnMgb25seVxuICogYXBwbHkgdGhlIHNlcnZpY2UgZmlsdGVyIHRvIHJ1bm5pbmcgdGFza3MpLCBmYWxscyBiYWNrIHRvIGxpc3RpbmcgdGhlIGNsdXN0ZXIncyBzdG9wcGVkXG4gKiB0YXNrcy4gUmV0dXJucyBhbiBlbXB0eSBhcnJheSBpZiBub25lIGFyZSByZXRhaW5lZCAoZS5nLiB0aGV5IGFnZWQgb3V0LCBvciByb2xsYmFja1xuICogYWxyZWFkeSBkcmFpbmVkIHRoZSBjbHVzdGVyKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gbGlzdFN0b3BwZWRUYXNrSWRzKFxuICBlY3M6IElFQ1NDbGllbnQsXG4gIGNsdXN0ZXI6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgY29uc3QgdG9JZHMgPSAoYXJuczogc3RyaW5nW10gfCB1bmRlZmluZWQpID0+IChhcm5zID8/IFtdKS5tYXAoYXJuID0+IGFybi5zcGxpdCgnLycpLnBvcCgpKS5maWx0ZXIoKGlkKTogaWQgaXMgc3RyaW5nID0+ICEhaWQpO1xuXG4gIGxldCBhcm5zOiBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjb25zdCBieVNlcnZpY2UgPSBhd2FpdCBlY3MubGlzdFRhc2tzKHsgY2x1c3Rlciwgc2VydmljZU5hbWUsIGRlc2lyZWRTdGF0dXM6ICdTVE9QUEVEJyB9KTtcbiAgICBhcm5zID0gYnlTZXJ2aWNlLnRhc2tBcm5zO1xuICAgIGlmICghYXJucyB8fCBhcm5zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc3QgYnlDbHVzdGVyID0gYXdhaXQgZWNzLmxpc3RUYXNrcyh7IGNsdXN0ZXIsIGRlc2lyZWRTdGF0dXM6ICdTVE9QUEVEJyB9KTtcbiAgICAgIGFybnMgPSBieUNsdXN0ZXIudGFza0FybnM7XG4gICAgfVxuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBhd2FpdCBkZWJ1ZyhgRUNTIGludmVzdGlnYXRpb246IGZhaWxlZCB0byBsaXN0IHN0b3BwZWQgdGFza3M6ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIHJldHVybiB0b0lkcyhhcm5zKS5zbGljZSgwLCBNQVhfU1RPUFBFRF9UQVNLUyk7XG59XG5cbmludGVyZmFjZSBBd3NMb2dzQ29uZmlnIHtcbiAgbG9nR3JvdXA6IHN0cmluZztcbiAgc3RyZWFtUHJlZml4Pzogc3RyaW5nO1xuICBjb250YWluZXJOYW1lPzogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgVGFza0RlZmluaXRpb25JbmZvIHtcbiAgbG9nQ29uZmlnczogQXdzTG9nc0NvbmZpZ1tdO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRUYXNrRGVmaW5pdGlvbkluZm8oXG4gIGVjczogSUVDU0NsaWVudCxcbiAgdGFza0RlZmluaXRpb25Bcm46IHN0cmluZyxcbiAgZGVidWc6IChtc2c6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8VGFza0RlZmluaXRpb25JbmZvIHwgdW5kZWZpbmVkPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgcmVzcCA9IGF3YWl0IGVjcy5kZXNjcmliZVRhc2tEZWZpbml0aW9uKHsgdGFza0RlZmluaXRpb246IHRhc2tEZWZpbml0aW9uQXJuIH0pO1xuICAgIGNvbnN0IGNvbnRhaW5lcnMgPSByZXNwLnRhc2tEZWZpbml0aW9uPy5jb250YWluZXJEZWZpbml0aW9ucyA/PyBbXTtcbiAgICBjb25zdCBsb2dDb25maWdzOiBBd3NMb2dzQ29uZmlnW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGNvbnRhaW5lciBvZiBjb250YWluZXJzKSB7XG4gICAgICBjb25zdCBsb2dDb25maWcgPSBjb250YWluZXIubG9nQ29uZmlndXJhdGlvbjtcbiAgICAgIGlmIChsb2dDb25maWc/LmxvZ0RyaXZlciA9PT0gJ2F3c2xvZ3MnKSB7XG4gICAgICAgIGNvbnN0IGxvZ0dyb3VwID0gbG9nQ29uZmlnLm9wdGlvbnM/LlsnYXdzbG9ncy1ncm91cCddO1xuICAgICAgICBpZiAobG9nR3JvdXApIHtcbiAgICAgICAgICBsb2dDb25maWdzLnB1c2goe1xuICAgICAgICAgICAgbG9nR3JvdXAsXG4gICAgICAgICAgICBzdHJlYW1QcmVmaXg6IGxvZ0NvbmZpZy5vcHRpb25zPy5bJ2F3c2xvZ3Mtc3RyZWFtLXByZWZpeCddLFxuICAgICAgICAgICAgY29udGFpbmVyTmFtZTogY29udGFpbmVyLm5hbWUsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgbG9nQ29uZmlncyB9O1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBhd2FpdCBkZWJ1ZyhgRUNTIGludmVzdGlnYXRpb246IGZhaWxlZCB0byBkZXNjcmliZSB0YXNrIGRlZmluaXRpb246ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hSZWNlbnRMb2dzKFxuICBjd2w6IElDbG91ZFdhdGNoTG9nc0NsaWVudCxcbiAgbG9nQ29uZmlnOiBBd3NMb2dzQ29uZmlnLFxuICByZWdpb246IHN0cmluZyxcbiAgdGFza0lkczogc3RyaW5nW10sXG4gIGRlYnVnOiAobXNnOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPEFkZGl0aW9uYWxEaWFnbm9zdGljQ29udGV4dCB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIC8vIFRhcmdldCB0aGUgbW9zdCByZWNlbnRseSBmYWlsZWQgdGFzaydzIGxvZyBzdHJlYW0gZm9yIHRoZSBtb3N0IHJlbGV2YW50IG91dHB1dFxuICAgIGNvbnN0IGxhc3RUYXNrSWQgPSB0YXNrSWRzWzBdO1xuICAgIGNvbnN0IHRhcmdldFN0cmVhbSA9IChsb2dDb25maWcuc3RyZWFtUHJlZml4ICYmIGxvZ0NvbmZpZy5jb250YWluZXJOYW1lICYmIGxhc3RUYXNrSWQpXG4gICAgICA/IGAke2xvZ0NvbmZpZy5zdHJlYW1QcmVmaXh9LyR7bG9nQ29uZmlnLmNvbnRhaW5lck5hbWV9LyR7bGFzdFRhc2tJZH1gXG4gICAgICA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IHJlc3AgPSBhd2FpdCBjd2wuZmlsdGVyTG9nRXZlbnRzKHtcbiAgICAgIGxvZ0dyb3VwTmFtZTogbG9nQ29uZmlnLmxvZ0dyb3VwLFxuICAgICAgc3RhcnRUaW1lOiBEYXRlLm5vdygpIC0gRkFMTEJBQ0tfTE9HX1dJTkRPV19NUyxcbiAgICAgIGxpbWl0OiAxMDAwLFxuICAgICAgLi4uKHRhcmdldFN0cmVhbVxuICAgICAgICA/IHsgbG9nU3RyZWFtTmFtZXM6IFt0YXJnZXRTdHJlYW1dIH1cbiAgICAgICAgOiBsb2dDb25maWcuc3RyZWFtUHJlZml4ID8geyBsb2dTdHJlYW1OYW1lUHJlZml4OiBsb2dDb25maWcuc3RyZWFtUHJlZml4IH0gOiB7fSksXG4gICAgfSk7XG5cbiAgICBjb25zdCBldmVudHMgPSByZXNwLmV2ZW50cyA/PyBbXTtcbiAgICBpZiAoZXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYXdhaXQgZGVidWcoYEVDUyBpbnZlc3RpZ2F0aW9uOiBubyByZWNlbnQgbG9nIGV2ZW50cyBpbiAke2xvZ0NvbmZpZy5sb2dHcm91cH0ke3RhcmdldFN0cmVhbSA/IGAgKHRhcmdldGVkIHN0cmVhbTogJHt0YXJnZXRTdHJlYW19KWAgOiAnJ31gKTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgY29uc3QgbWVzc2FnZXMgPSB0cmltVG9SZWNlbnRMaW5lcyhcbiAgICAgIGV2ZW50cy5tYXAoZSA9PiBlLm1lc3NhZ2U/LnRyaW1FbmQoKSkuZmlsdGVyKChtKTogbSBpcyBzdHJpbmcgPT4gbSAhPSBudWxsKSxcbiAgICApO1xuXG4gICAgaWYgKHRhc2tJZHMubGVuZ3RoID4gMSkge1xuICAgICAgbWVzc2FnZXMucHVzaChgKHNob3dpbmcgbG9ncyBmcm9tIGxhc3QgZmFpbGVkIHRhc2s7ICR7dGFza0lkcy5sZW5ndGggLSAxfSBvdGhlciBmYWlsZWQgdGFzayhzKSBhdmFpbGFibGUgaW4gY29uc29sZSlgKTtcbiAgICB9XG5cbiAgICBjb25zdCBzb3VyY2UgPSBsb2dDb25maWcuY29udGFpbmVyTmFtZVxuICAgICAgPyBgQ2xvdWRXYXRjaCBMb2dzOiAke2xvZ0NvbmZpZy5sb2dHcm91cH0gKGNvbnRhaW5lcjogJHtsb2dDb25maWcuY29udGFpbmVyTmFtZX0pYFxuICAgICAgOiBgQ2xvdWRXYXRjaCBMb2dzOiAke2xvZ0NvbmZpZy5sb2dHcm91cH1gO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHNvdXJjZSxcbiAgICAgIG1lc3NhZ2VzLFxuICAgICAgbGluazogY2xvdWRXYXRjaExvZ3NDb25zb2xlVXJsKHJlZ2lvbiwgbG9nQ29uZmlnLmxvZ0dyb3VwKSxcbiAgICAgIGxpbmtMYWJlbDogJ0xvZ3MnLFxuICAgIH07XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIGF3YWl0IGRlYnVnKGBFQ1MgaW52ZXN0aWdhdGlvbjogZmFpbGVkIHRvIGZldGNoIGxvZ3MgZnJvbSAke2xvZ0NvbmZpZy5sb2dHcm91cH06ICR7ZS5tZXNzYWdlfWApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==
|