@chaim-tools/cdk-lib 0.1.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/README.md +238 -0
- package/lib/binders/base-chaim-binder.d.ts +144 -0
- package/lib/binders/base-chaim-binder.js +532 -0
- package/lib/binders/chaim-dynamodb-binder.d.ts +95 -0
- package/lib/binders/chaim-dynamodb-binder.js +292 -0
- package/lib/config/chaim-endpoints.d.ts +47 -0
- package/lib/config/chaim-endpoints.js +51 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +43 -0
- package/lib/lambda-handler/.test-temp/snapshot.json +1 -0
- package/lib/lambda-handler/handler.js +513 -0
- package/lib/lambda-handler/handler.test.ts +365 -0
- package/lib/lambda-handler/package-lock.json +1223 -0
- package/lib/lambda-handler/package.json +14 -0
- package/lib/services/ingestion-service.d.ts +50 -0
- package/lib/services/ingestion-service.js +81 -0
- package/lib/services/os-cache-paths.d.ts +52 -0
- package/lib/services/os-cache-paths.js +123 -0
- package/lib/services/schema-service.d.ts +11 -0
- package/lib/services/schema-service.js +67 -0
- package/lib/services/snapshot-cleanup.d.ts +78 -0
- package/lib/services/snapshot-cleanup.js +220 -0
- package/lib/types/base-binder-props.d.ts +32 -0
- package/lib/types/base-binder-props.js +17 -0
- package/lib/types/credentials.d.ts +57 -0
- package/lib/types/credentials.js +83 -0
- package/lib/types/data-store-metadata.d.ts +67 -0
- package/lib/types/data-store-metadata.js +4 -0
- package/lib/types/failure-mode.d.ts +16 -0
- package/lib/types/failure-mode.js +21 -0
- package/lib/types/ingest-contract.d.ts +110 -0
- package/lib/types/ingest-contract.js +12 -0
- package/lib/types/snapshot-cache-policy.d.ts +52 -0
- package/lib/types/snapshot-cache-policy.js +57 -0
- package/lib/types/snapshot-payload.d.ts +245 -0
- package/lib/types/snapshot-payload.js +3 -0
- package/lib/types/table-binding-config.d.ts +43 -0
- package/lib/types/table-binding-config.js +57 -0
- package/package.json +67 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.BaseChaimBinder = void 0;
|
|
27
|
+
const cdk = __importStar(require("aws-cdk-lib"));
|
|
28
|
+
const lambda = __importStar(require("aws-cdk-lib/aws-lambda"));
|
|
29
|
+
const iam = __importStar(require("aws-cdk-lib/aws-iam"));
|
|
30
|
+
const cr = __importStar(require("aws-cdk-lib/custom-resources"));
|
|
31
|
+
const constructs_1 = require("constructs");
|
|
32
|
+
const fs = __importStar(require("fs"));
|
|
33
|
+
const path = __importStar(require("path"));
|
|
34
|
+
const crypto = __importStar(require("crypto"));
|
|
35
|
+
const base_binder_props_1 = require("../types/base-binder-props");
|
|
36
|
+
const schema_service_1 = require("../services/schema-service");
|
|
37
|
+
const snapshot_cache_policy_1 = require("../types/snapshot-cache-policy");
|
|
38
|
+
const chaim_endpoints_1 = require("../config/chaim-endpoints");
|
|
39
|
+
const os_cache_paths_1 = require("../services/os-cache-paths");
|
|
40
|
+
const snapshot_cleanup_1 = require("../services/snapshot-cleanup");
|
|
41
|
+
/**
|
|
42
|
+
* Path to the canonical Lambda handler file.
|
|
43
|
+
* This handler implements the presigned upload flow for Chaim ingestion.
|
|
44
|
+
*/
|
|
45
|
+
const LAMBDA_HANDLER_PATH = path.join(__dirname, '..', 'lambda-handler', 'handler.js');
|
|
46
|
+
/**
|
|
47
|
+
* Abstract base class for all Chaim data store binders.
|
|
48
|
+
*
|
|
49
|
+
* Provides shared infrastructure:
|
|
50
|
+
* - Schema loading and validation
|
|
51
|
+
* - Snapshot payload construction
|
|
52
|
+
* - LOCAL snapshot writing during CDK synth (to OS cache)
|
|
53
|
+
* - Lambda-backed custom resource for S3 presigned upload + snapshot-ref
|
|
54
|
+
*
|
|
55
|
+
* Subclasses implement `extractMetadata()` for store-specific metadata extraction
|
|
56
|
+
* and optionally override `getTable()` for DynamoDB-like resources.
|
|
57
|
+
*/
|
|
58
|
+
class BaseChaimBinder extends constructs_1.Construct {
|
|
59
|
+
/** Validated schema data */
|
|
60
|
+
schemaData;
|
|
61
|
+
/** Extracted data store metadata */
|
|
62
|
+
dataStoreMetadata;
|
|
63
|
+
/** Generated resource ID ({resourceName}__{entityName}[__N]) */
|
|
64
|
+
resourceId;
|
|
65
|
+
/** Binding configuration */
|
|
66
|
+
config;
|
|
67
|
+
/** Base props (for internal use) */
|
|
68
|
+
baseProps;
|
|
69
|
+
constructor(scope, id, props) {
|
|
70
|
+
super(scope, id);
|
|
71
|
+
this.baseProps = props;
|
|
72
|
+
this.config = props.config;
|
|
73
|
+
// Validate props
|
|
74
|
+
(0, base_binder_props_1.validateBinderProps)(props);
|
|
75
|
+
// Validate consistency with other bindings to same table
|
|
76
|
+
this.validateTableConsistency();
|
|
77
|
+
// Load and validate schema
|
|
78
|
+
this.schemaData = schema_service_1.SchemaService.readSchema(props.schemaPath);
|
|
79
|
+
// Extract data store metadata (implemented by subclass)
|
|
80
|
+
this.dataStoreMetadata = this.extractMetadata();
|
|
81
|
+
// Build stack context
|
|
82
|
+
const stack = cdk.Stack.of(this);
|
|
83
|
+
const stackName = stack.stackName;
|
|
84
|
+
const datastoreType = this.dataStoreMetadata.type;
|
|
85
|
+
// Get resource and entity names
|
|
86
|
+
const resourceName = this.getResourceName();
|
|
87
|
+
const entityName = this.getEntityName();
|
|
88
|
+
// Generate resource ID
|
|
89
|
+
this.resourceId = `${resourceName}__${entityName}`;
|
|
90
|
+
// Normalize values for paths (handle CDK tokens)
|
|
91
|
+
const normalizedAccountId = (0, os_cache_paths_1.normalizeAccountId)(stack.account);
|
|
92
|
+
const normalizedRegion = (0, os_cache_paths_1.normalizeRegion)(stack.region);
|
|
93
|
+
const normalizedResourceName = (0, os_cache_paths_1.normalizeResourceName)(resourceName);
|
|
94
|
+
// Update resource ID with normalized name to avoid special characters
|
|
95
|
+
const normalizedResourceId = `${normalizedResourceName}__${entityName}`;
|
|
96
|
+
// Build LOCAL snapshot payload
|
|
97
|
+
const localSnapshot = this.buildLocalSnapshot({
|
|
98
|
+
accountId: normalizedAccountId,
|
|
99
|
+
region: normalizedRegion,
|
|
100
|
+
stackName,
|
|
101
|
+
datastoreType,
|
|
102
|
+
resourceName: normalizedResourceName,
|
|
103
|
+
resourceId: normalizedResourceId,
|
|
104
|
+
});
|
|
105
|
+
// Apply snapshot cache policy (cleanup if requested)
|
|
106
|
+
this.applySnapshotCachePolicy({
|
|
107
|
+
accountId: normalizedAccountId,
|
|
108
|
+
region: normalizedRegion,
|
|
109
|
+
stackName,
|
|
110
|
+
});
|
|
111
|
+
// Write LOCAL snapshot to OS cache for chaim-cli consumption
|
|
112
|
+
this.writeLocalSnapshotToDisk(localSnapshot);
|
|
113
|
+
// Get or create asset directory
|
|
114
|
+
const assetDir = this.writeSnapshotAsset(localSnapshot, stackName);
|
|
115
|
+
// Deploy Lambda-backed custom resource for ingestion
|
|
116
|
+
this.deployIngestionResources(assetDir);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Validate that all bindings to the same table use the same config.
|
|
120
|
+
*
|
|
121
|
+
* This is a safety check - sharing the same TableBindingConfig object
|
|
122
|
+
* already ensures consistency, but this catches cases where users
|
|
123
|
+
* create separate configs with identical values.
|
|
124
|
+
*/
|
|
125
|
+
validateTableConsistency() {
|
|
126
|
+
// Only for DynamoDB binders (has table property)
|
|
127
|
+
const table = this.baseProps.table;
|
|
128
|
+
if (!table) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// Find other binders for the same table
|
|
132
|
+
const stack = cdk.Stack.of(this);
|
|
133
|
+
const otherBinders = stack.node.findAll()
|
|
134
|
+
.filter(node => node instanceof BaseChaimBinder)
|
|
135
|
+
.filter(binder => binder !== this)
|
|
136
|
+
.filter(binder => {
|
|
137
|
+
const otherTable = binder.baseProps.table;
|
|
138
|
+
return otherTable === table;
|
|
139
|
+
})
|
|
140
|
+
.map(binder => binder);
|
|
141
|
+
if (otherBinders.length === 0) {
|
|
142
|
+
return; // First binding for this table
|
|
143
|
+
}
|
|
144
|
+
const firstBinder = otherBinders[0];
|
|
145
|
+
// Check if they're using the exact same config object (recommended)
|
|
146
|
+
if (this.config === firstBinder.config) {
|
|
147
|
+
return; // Perfect - same config object
|
|
148
|
+
}
|
|
149
|
+
// Different config objects - validate they have same values
|
|
150
|
+
if (this.config.appId !== firstBinder.config.appId) {
|
|
151
|
+
throw new Error(`Configuration conflict for table "${table.tableName}".\n\n` +
|
|
152
|
+
`Binder "${firstBinder.node.id}" uses appId: "${firstBinder.config.appId}"\n` +
|
|
153
|
+
`Binder "${this.node.id}" uses appId: "${this.config.appId}"\n\n` +
|
|
154
|
+
`All bindings to the same table MUST use the same appId.\n\n` +
|
|
155
|
+
`RECOMMENDED: Share the same TableBindingConfig object:\n` +
|
|
156
|
+
` const config = new TableBindingConfig('${firstBinder.config.appId}', credentials);\n` +
|
|
157
|
+
` new ChaimDynamoDBBinder(this, '${firstBinder.node.id}', { ..., config });\n` +
|
|
158
|
+
` new ChaimDynamoDBBinder(this, '${this.node.id}', { ..., config });`);
|
|
159
|
+
}
|
|
160
|
+
// Validate credentials match
|
|
161
|
+
const firstCreds = JSON.stringify(firstBinder.config.credentials);
|
|
162
|
+
const thisCreds = JSON.stringify(this.config.credentials);
|
|
163
|
+
if (firstCreds !== thisCreds) {
|
|
164
|
+
throw new Error(`Configuration conflict for table "${table.tableName}".\n\n` +
|
|
165
|
+
`Binder "${firstBinder.node.id}" uses different credentials than "${this.node.id}".\n\n` +
|
|
166
|
+
`All bindings to the same table MUST use the same credentials.\n\n` +
|
|
167
|
+
`RECOMMENDED: Share the same TableBindingConfig object to avoid this error.`);
|
|
168
|
+
}
|
|
169
|
+
// Warn about different failureMode (not an error)
|
|
170
|
+
if (this.config.failureMode !== firstBinder.config.failureMode) {
|
|
171
|
+
console.warn(`Warning: Different failureMode for table "${table.tableName}".\n` +
|
|
172
|
+
` "${firstBinder.node.id}": ${firstBinder.config.failureMode}\n` +
|
|
173
|
+
` "${this.node.id}": ${this.config.failureMode}\n` +
|
|
174
|
+
`Consider sharing the same TableBindingConfig object.`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Override in subclasses to provide the table construct for stable identity.
|
|
179
|
+
* Default returns undefined (will fall back to construct path).
|
|
180
|
+
*/
|
|
181
|
+
getTable() {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get the resource name for display and filenames.
|
|
186
|
+
* For DynamoDB, this is the user label (not necessarily the physical table name).
|
|
187
|
+
*
|
|
188
|
+
* Subclasses can override this to provide a more meaningful name
|
|
189
|
+
* (e.g., construct node ID instead of physical resource name which may contain tokens).
|
|
190
|
+
*/
|
|
191
|
+
getResourceName() {
|
|
192
|
+
const metadata = this.dataStoreMetadata;
|
|
193
|
+
return metadata.tableName || metadata.name || 'resource';
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get the entity name from schema.
|
|
197
|
+
*/
|
|
198
|
+
getEntityName() {
|
|
199
|
+
return this.schemaData.entityName;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Read package version from package.json.
|
|
203
|
+
* Used to populate producer metadata in snapshots.
|
|
204
|
+
*/
|
|
205
|
+
getPackageVersion() {
|
|
206
|
+
try {
|
|
207
|
+
const packagePath = path.join(__dirname, '..', '..', 'package.json');
|
|
208
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
|
|
209
|
+
return packageJson.version || '0.0.0';
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
console.warn('Failed to read package version:', error);
|
|
213
|
+
return '0.0.0';
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Build a LOCAL snapshot payload for CLI consumption.
|
|
218
|
+
* Does not include eventId or contentHash - those are generated at deploy-time.
|
|
219
|
+
*/
|
|
220
|
+
buildLocalSnapshot(params) {
|
|
221
|
+
const capturedAt = new Date().toISOString();
|
|
222
|
+
const stack = cdk.Stack.of(this);
|
|
223
|
+
// Build provider identity
|
|
224
|
+
const providerIdentity = {
|
|
225
|
+
cloud: 'aws',
|
|
226
|
+
accountId: params.accountId,
|
|
227
|
+
region: params.region,
|
|
228
|
+
deploymentSystem: 'cloudformation',
|
|
229
|
+
deploymentId: stack.stackId,
|
|
230
|
+
};
|
|
231
|
+
// Build binding identity
|
|
232
|
+
const stableResourceKey = `${params.datastoreType}:path:${params.stackName}/${params.resourceName}`;
|
|
233
|
+
const entityId = `${this.config.appId}:${this.schemaData.entityName}`;
|
|
234
|
+
const bindingId = `${this.config.appId}:${stableResourceKey}:${this.schemaData.entityName}`;
|
|
235
|
+
const identity = {
|
|
236
|
+
appId: this.config.appId,
|
|
237
|
+
entityName: this.schemaData.entityName,
|
|
238
|
+
stableResourceKeyStrategy: 'cdk-construct-path',
|
|
239
|
+
stableResourceKey,
|
|
240
|
+
resourceId: params.resourceId,
|
|
241
|
+
entityId,
|
|
242
|
+
bindingId,
|
|
243
|
+
};
|
|
244
|
+
// Build operation metadata
|
|
245
|
+
const operation = {
|
|
246
|
+
eventId: this.generateUuid(),
|
|
247
|
+
requestType: 'Create',
|
|
248
|
+
failureMode: this.config.failureMode,
|
|
249
|
+
};
|
|
250
|
+
// Build resolution metadata
|
|
251
|
+
const hasTokens = this.detectUnresolvedTokens(this.dataStoreMetadata);
|
|
252
|
+
const resolution = {
|
|
253
|
+
mode: 'LOCAL',
|
|
254
|
+
hasTokens,
|
|
255
|
+
};
|
|
256
|
+
// Build hashes
|
|
257
|
+
const schemaBytes = JSON.stringify(this.schemaData);
|
|
258
|
+
const schemaHash = 'sha256:' + crypto.createHash('sha256').update(schemaBytes).digest('hex');
|
|
259
|
+
const hashes = {
|
|
260
|
+
schemaHash,
|
|
261
|
+
contentHash: '',
|
|
262
|
+
};
|
|
263
|
+
// Build resource metadata
|
|
264
|
+
const resource = this.buildResourceMetadata(params);
|
|
265
|
+
// Build producer metadata
|
|
266
|
+
const producer = {
|
|
267
|
+
component: 'chaim-cdk',
|
|
268
|
+
version: this.getPackageVersion(),
|
|
269
|
+
runtime: process.version,
|
|
270
|
+
};
|
|
271
|
+
return {
|
|
272
|
+
snapshotVersion: chaim_endpoints_1.SNAPSHOT_SCHEMA_VERSION,
|
|
273
|
+
action: 'UPSERT',
|
|
274
|
+
capturedAt,
|
|
275
|
+
providerIdentity,
|
|
276
|
+
identity,
|
|
277
|
+
operation,
|
|
278
|
+
resolution,
|
|
279
|
+
hashes,
|
|
280
|
+
schema: this.schemaData,
|
|
281
|
+
resource,
|
|
282
|
+
producer,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Build resource metadata from dataStore metadata.
|
|
287
|
+
*/
|
|
288
|
+
buildResourceMetadata(params) {
|
|
289
|
+
const dynamoMetadata = this.dataStoreMetadata;
|
|
290
|
+
return {
|
|
291
|
+
type: 'dynamodb',
|
|
292
|
+
kind: 'table',
|
|
293
|
+
id: dynamoMetadata.tableArn,
|
|
294
|
+
name: dynamoMetadata.tableName,
|
|
295
|
+
region: params.region,
|
|
296
|
+
partitionKey: dynamoMetadata.partitionKey,
|
|
297
|
+
sortKey: dynamoMetadata.sortKey,
|
|
298
|
+
globalSecondaryIndexes: dynamoMetadata.globalSecondaryIndexes,
|
|
299
|
+
localSecondaryIndexes: dynamoMetadata.localSecondaryIndexes,
|
|
300
|
+
ttlAttribute: dynamoMetadata.ttlAttribute,
|
|
301
|
+
streamEnabled: dynamoMetadata.streamEnabled,
|
|
302
|
+
streamViewType: dynamoMetadata.streamViewType,
|
|
303
|
+
billingMode: dynamoMetadata.billingMode,
|
|
304
|
+
encryptionKeyArn: dynamoMetadata.encryptionKeyArn,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Detect if metadata contains unresolved CDK tokens.
|
|
309
|
+
*/
|
|
310
|
+
detectUnresolvedTokens(metadata) {
|
|
311
|
+
const str = JSON.stringify(metadata);
|
|
312
|
+
return str.includes('${Token[');
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Generate a UUID v4 for operation tracking.
|
|
316
|
+
*/
|
|
317
|
+
generateUuid() {
|
|
318
|
+
return crypto.randomUUID();
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Apply snapshot cache policy based on CDK context.
|
|
322
|
+
*
|
|
323
|
+
* Checks the `chaimSnapshotCachePolicy` context value:
|
|
324
|
+
* - NONE (default): No cleanup
|
|
325
|
+
* - PRUNE_STACK: Delete existing stack snapshots before writing new ones
|
|
326
|
+
*
|
|
327
|
+
* This runs once per stack (tracked by static flag) to avoid
|
|
328
|
+
* multiple cleanup attempts when binding multiple entities.
|
|
329
|
+
*/
|
|
330
|
+
applySnapshotCachePolicy(params) {
|
|
331
|
+
// Get policy from CDK context (defaults to NONE)
|
|
332
|
+
const policyValue = this.node.tryGetContext(snapshot_cache_policy_1.SNAPSHOT_CACHE_POLICY_CONTEXT_KEY);
|
|
333
|
+
const policy = this.parseSnapshotCachePolicy(policyValue);
|
|
334
|
+
if (policy === snapshot_cache_policy_1.SnapshotCachePolicy.NONE) {
|
|
335
|
+
return; // No cleanup
|
|
336
|
+
}
|
|
337
|
+
// Check if we've already cleaned this stack in this synth
|
|
338
|
+
const stack = cdk.Stack.of(this);
|
|
339
|
+
const cleanupKey = `__chaim_snapshot_cleanup_${params.stackName}`;
|
|
340
|
+
if (stack.node[cleanupKey]) {
|
|
341
|
+
return; // Already cleaned in this synth
|
|
342
|
+
}
|
|
343
|
+
// Mark as cleaned to avoid duplicate cleanup
|
|
344
|
+
stack.node[cleanupKey] = true;
|
|
345
|
+
if (policy === snapshot_cache_policy_1.SnapshotCachePolicy.PRUNE_STACK) {
|
|
346
|
+
const result = (0, snapshot_cleanup_1.pruneStackSnapshots)({
|
|
347
|
+
accountId: params.accountId,
|
|
348
|
+
region: params.region,
|
|
349
|
+
stackName: params.stackName,
|
|
350
|
+
verbose: false, // Don't spam console during synth
|
|
351
|
+
});
|
|
352
|
+
// Only log if verbose mode or errors
|
|
353
|
+
if (result.deletedCount > 0 || result.errors.length > 0) {
|
|
354
|
+
console.log(`[Chaim] Pruned ${result.deletedCount} snapshot(s) for stack: ${params.stackName}`);
|
|
355
|
+
if (result.errors.length > 0) {
|
|
356
|
+
console.warn(`[Chaim] Cleanup warnings:`, result.errors);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Parse snapshot cache policy from context value.
|
|
363
|
+
*/
|
|
364
|
+
parseSnapshotCachePolicy(value) {
|
|
365
|
+
if (typeof value !== 'string') {
|
|
366
|
+
return snapshot_cache_policy_1.DEFAULT_SNAPSHOT_CACHE_POLICY;
|
|
367
|
+
}
|
|
368
|
+
const upperValue = value.toUpperCase();
|
|
369
|
+
if (upperValue === 'NONE' || upperValue === 'DISABLED') {
|
|
370
|
+
return snapshot_cache_policy_1.SnapshotCachePolicy.NONE;
|
|
371
|
+
}
|
|
372
|
+
if (upperValue === 'PRUNE_STACK' || upperValue === 'PRUNE') {
|
|
373
|
+
return snapshot_cache_policy_1.SnapshotCachePolicy.PRUNE_STACK;
|
|
374
|
+
}
|
|
375
|
+
console.warn(`[Chaim] Unknown chaimSnapshotCachePolicy: "${value}". ` +
|
|
376
|
+
`Valid values: NONE, PRUNE_STACK. Defaulting to NONE.`);
|
|
377
|
+
return snapshot_cache_policy_1.DEFAULT_SNAPSHOT_CACHE_POLICY;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Extract stack name from stableResourceKey.
|
|
381
|
+
* Format: dynamodb:path:StackName/ResourceName
|
|
382
|
+
*/
|
|
383
|
+
extractStackNameFromResourceKey(stableResourceKey) {
|
|
384
|
+
const match = stableResourceKey.match(/path:([^/]+)/);
|
|
385
|
+
return match ? match[1] : 'unknown';
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Write LOCAL snapshot to OS cache for chaim-cli consumption.
|
|
389
|
+
* Uses hierarchical path: aws/{accountId}/{region}/{stackName}/{datastoreType}/{resourceId}.json
|
|
390
|
+
*
|
|
391
|
+
* @param snapshot - The snapshot payload to write
|
|
392
|
+
* @returns The path where snapshot was written
|
|
393
|
+
*/
|
|
394
|
+
writeLocalSnapshotToDisk(snapshot) {
|
|
395
|
+
const stackName = this.extractStackNameFromResourceKey(snapshot.identity.stableResourceKey);
|
|
396
|
+
const dir = (0, os_cache_paths_1.getSnapshotDir)({
|
|
397
|
+
accountId: snapshot.providerIdentity.accountId,
|
|
398
|
+
region: snapshot.providerIdentity.region,
|
|
399
|
+
stackName,
|
|
400
|
+
datastoreType: snapshot.resource.type,
|
|
401
|
+
});
|
|
402
|
+
(0, os_cache_paths_1.ensureDirExists)(dir);
|
|
403
|
+
const filePath = (0, os_cache_paths_1.getLocalSnapshotPath)({
|
|
404
|
+
accountId: snapshot.providerIdentity.accountId,
|
|
405
|
+
region: snapshot.providerIdentity.region,
|
|
406
|
+
stackName,
|
|
407
|
+
datastoreType: snapshot.resource.type,
|
|
408
|
+
resourceId: snapshot.identity.resourceId,
|
|
409
|
+
});
|
|
410
|
+
fs.writeFileSync(filePath, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
411
|
+
return filePath;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Find the CDK project root by walking up from current module.
|
|
415
|
+
*/
|
|
416
|
+
findCdkProjectRoot() {
|
|
417
|
+
let currentDir = __dirname;
|
|
418
|
+
for (let i = 0; i < 10; i++) {
|
|
419
|
+
const cdkJsonPath = path.join(currentDir, 'cdk.json');
|
|
420
|
+
if (fs.existsSync(cdkJsonPath)) {
|
|
421
|
+
return currentDir;
|
|
422
|
+
}
|
|
423
|
+
const parentDir = path.dirname(currentDir);
|
|
424
|
+
if (parentDir === currentDir) {
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
currentDir = parentDir;
|
|
428
|
+
}
|
|
429
|
+
// Fallback to cwd
|
|
430
|
+
return process.cwd();
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Write snapshot and Lambda handler to isolated CDK asset directory for Lambda bundling.
|
|
434
|
+
*
|
|
435
|
+
* Asset directory is per {stackName}/{resourceId} and MUST NOT be shared.
|
|
436
|
+
* The Lambda reads ./snapshot.json from its bundle, NOT from env vars or OS cache.
|
|
437
|
+
*
|
|
438
|
+
* The handler is copied from the canonical handler file (src/lambda-handler/handler.js)
|
|
439
|
+
* rather than being generated inline - this ensures a single source of truth.
|
|
440
|
+
*
|
|
441
|
+
* @returns The asset directory path
|
|
442
|
+
*/
|
|
443
|
+
writeSnapshotAsset(snapshot, stackName) {
|
|
444
|
+
const cdkRoot = this.findCdkProjectRoot();
|
|
445
|
+
const assetDir = path.join(cdkRoot, 'cdk.out', 'chaim', 'assets', stackName, this.resourceId);
|
|
446
|
+
(0, os_cache_paths_1.ensureDirExists)(assetDir);
|
|
447
|
+
// Write snapshot.json (OVERWRITE each synth)
|
|
448
|
+
const snapshotPath = path.join(assetDir, 'snapshot.json');
|
|
449
|
+
fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
450
|
+
// Copy canonical Lambda handler (OVERWRITE each synth)
|
|
451
|
+
const handlerDestPath = path.join(assetDir, 'index.js');
|
|
452
|
+
fs.copyFileSync(LAMBDA_HANDLER_PATH, handlerDestPath);
|
|
453
|
+
return assetDir;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Deploy Lambda function and custom resource for ingestion.
|
|
457
|
+
*/
|
|
458
|
+
deployIngestionResources(assetDir) {
|
|
459
|
+
const handler = this.createIngestionLambda(assetDir);
|
|
460
|
+
this.createCustomResource(handler);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Create Lambda function for ingestion workflow.
|
|
464
|
+
* Lambda reads snapshot from its bundled asset directory.
|
|
465
|
+
*/
|
|
466
|
+
createIngestionLambda(assetDir) {
|
|
467
|
+
const handler = new lambda.Function(this, 'IngestionHandler', {
|
|
468
|
+
runtime: lambda.Runtime.NODEJS_20_X,
|
|
469
|
+
handler: 'index.handler',
|
|
470
|
+
code: lambda.Code.fromAsset(assetDir),
|
|
471
|
+
timeout: cdk.Duration.minutes(5),
|
|
472
|
+
environment: this.buildLambdaEnvironment(),
|
|
473
|
+
});
|
|
474
|
+
// Grant CloudWatch Logs permissions
|
|
475
|
+
handler.addToRolePolicy(new iam.PolicyStatement({
|
|
476
|
+
effect: iam.Effect.ALLOW,
|
|
477
|
+
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
|
|
478
|
+
resources: ['*'],
|
|
479
|
+
}));
|
|
480
|
+
// Grant Secrets Manager permissions if using secrets
|
|
481
|
+
const { credentials } = this.config;
|
|
482
|
+
if (credentials.credentialType === 'secretsManager' && credentials.secretName) {
|
|
483
|
+
handler.addToRolePolicy(new iam.PolicyStatement({
|
|
484
|
+
effect: iam.Effect.ALLOW,
|
|
485
|
+
actions: ['secretsmanager:GetSecretValue'],
|
|
486
|
+
resources: [`arn:aws:secretsmanager:*:*:secret:${credentials.secretName}*`],
|
|
487
|
+
}));
|
|
488
|
+
}
|
|
489
|
+
return handler;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Build Lambda environment variables.
|
|
493
|
+
* Note: Snapshot is NOT passed via env - Lambda reads from bundled asset.
|
|
494
|
+
*/
|
|
495
|
+
buildLambdaEnvironment() {
|
|
496
|
+
// Allow maintainer override via CDK context, otherwise use default
|
|
497
|
+
const apiBaseUrl = this.node.tryGetContext('chaimApiBaseUrl') ?? chaim_endpoints_1.DEFAULT_CHAIM_API_BASE_URL;
|
|
498
|
+
const { credentials, failureMode } = this.config;
|
|
499
|
+
const env = {
|
|
500
|
+
APP_ID: this.config.appId,
|
|
501
|
+
FAILURE_MODE: failureMode,
|
|
502
|
+
CHAIM_API_BASE_URL: apiBaseUrl,
|
|
503
|
+
CHAIM_MAX_SNAPSHOT_BYTES: String(chaim_endpoints_1.DEFAULT_MAX_SNAPSHOT_BYTES),
|
|
504
|
+
};
|
|
505
|
+
if (credentials.credentialType === 'secretsManager') {
|
|
506
|
+
env.SECRET_NAME = credentials.secretName;
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
env.API_KEY = credentials.apiKey;
|
|
510
|
+
env.API_SECRET = credentials.apiSecret;
|
|
511
|
+
}
|
|
512
|
+
return env;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Create CloudFormation custom resource.
|
|
516
|
+
*/
|
|
517
|
+
createCustomResource(handler) {
|
|
518
|
+
const provider = new cr.Provider(this, 'IngestionProvider', {
|
|
519
|
+
onEventHandler: handler,
|
|
520
|
+
});
|
|
521
|
+
// Use resource ID for physical resource ID (stable across deploys)
|
|
522
|
+
new cdk.CustomResource(this, 'IngestionResource', {
|
|
523
|
+
serviceToken: provider.serviceToken,
|
|
524
|
+
properties: {
|
|
525
|
+
ResourceId: this.resourceId,
|
|
526
|
+
// ContentHash is computed at Lambda runtime
|
|
527
|
+
},
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
exports.BaseChaimBinder = BaseChaimBinder;
|
|
532
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1jaGFpbS1iaW5kZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYmluZGVycy9iYXNlLWNoYWltLWJpbmRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGlEQUFtQztBQUNuQywrREFBaUQ7QUFDakQseURBQTJDO0FBQzNDLGlFQUFtRDtBQUVuRCwyQ0FBdUM7QUFDdkMsdUNBQXlCO0FBQ3pCLDJDQUE2QjtBQUM3QiwrQ0FBaUM7QUFHakMsa0VBQWtGO0FBR2xGLCtEQUEyRDtBQUczRCwwRUFJd0M7QUFDeEMsK0RBSW1DO0FBQ25DLCtEQU9vQztBQUNwQyxtRUFBbUU7QUFFbkU7OztHQUdHO0FBQ0gsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFFdkY7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFzQixlQUFnQixTQUFRLHNCQUFTO0lBQ3JELDRCQUE0QjtJQUNaLFVBQVUsQ0FBYTtJQUV2QyxvQ0FBb0M7SUFDcEIsaUJBQWlCLENBQW9CO0lBRXJELGdFQUFnRTtJQUNoRCxVQUFVLENBQVM7SUFFbkMsNEJBQTRCO0lBQ1osTUFBTSxDQUFxQjtJQUUzQyxvQ0FBb0M7SUFDakIsU0FBUyxDQUFrQjtJQUU5QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXNCO1FBQzlELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUM7UUFDdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBRTNCLGlCQUFpQjtRQUNqQixJQUFBLHVDQUFtQixFQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTNCLHlEQUF5RDtRQUN6RCxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztR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RixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUF6a0JELDBDQXlrQkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjZGsgZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgY3IgZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgKiBhcyBkeW5hbW9kYiBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZHluYW1vZGInO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5cbmltcG9ydCB7IFNjaGVtYURhdGEgfSBmcm9tICdAY2hhaW0tdG9vbHMvY2hhaW0tYnByaW50LXNwZWMnO1xuaW1wb3J0IHsgQmFzZUJpbmRlclByb3BzLCB2YWxpZGF0ZUJpbmRlclByb3BzIH0gZnJvbSAnLi4vdHlwZXMvYmFzZS1iaW5kZXItcHJvcHMnO1xuaW1wb3J0IHsgRGF0YVN0b3JlTWV0YWRhdGEgfSBmcm9tICcuLi90eXBlcy9kYXRhLXN0b3JlLW1ldGFkYXRhJztcbmltcG9ydCB7IExvY2FsU25hcHNob3RQYXlsb2FkIH0gZnJvbSAnLi4vdHlwZXMvc25hcHNob3QtcGF5bG9hZCc7XG5pbXBvcnQgeyBTY2hlbWFTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvc2NoZW1hLXNlcnZpY2UnO1xuaW1wb3J0IHsgRmFpbHVyZU1vZGUgfSBmcm9tICcuLi90eXBlcy9mYWlsdXJlLW1vZGUnO1xuaW1wb3J0IHsgVGFibGVCaW5kaW5nQ29uZmlnIH0gZnJvbSAnLi4vdHlwZXMvdGFibGUtYmluZGluZy1jb25maWcnO1xuaW1wb3J0IHtcbiAgU25hcHNob3RDYWNoZVBvbGljeSxcbiAgREVGQVVMVF9TTkFQU0hPVF9DQUNIRV9QT0xJQ1ksXG4gIFNOQVBTSE9UX0NBQ0hFX1BPTElDWV9DT05URVhUX0tFWSxcbn0gZnJvbSAnLi4vdHlwZXMvc25hcHNob3QtY2FjaGUtcG9saWN5JztcbmltcG9ydCB7XG4gIERFRkFVTFRfQ0hBSU1fQVBJX0JBU0VfVVJMLFxuICBERUZBVUxUX01BWF9TTkFQU0hPVF9CWVRFUyxcbiAgU05BUFNIT1RfU0NIRU1BX1ZFUlNJT04sXG59IGZyb20gJy4uL2NvbmZpZy9jaGFpbS1lbmRwb2ludHMnO1xuaW1wb3J0IHtcbiAgbm9ybWFsaXplQWNjb3VudElkLFxuICBub3JtYWxpemVSZWdpb24sXG4gIG5vcm1hbGl6ZVJlc291cmNlTmFtZSxcbiAgZ2V0U25hcHNob3REaXIsXG4gIGdldExvY2FsU25hcHNob3RQYXRoLFxuICBlbnN1cmVEaXJFeGlzdHMsXG59IGZyb20gJy4uL3NlcnZpY2VzL29zLWNhY2hlLXBhdGhzJztcbmltcG9ydCB7IHBydW5lU3RhY2tTbmFwc2hvdHMgfSBmcm9tICcuLi9zZXJ2aWNlcy9zbmFwc2hvdC1jbGVhbnVwJztcblxuLyoqXG4gKiBQYXRoIHRvIHRoZSBjYW5vbmljYWwgTGFtYmRhIGhhbmRsZXIgZmlsZS5cbiAqIFRoaXMgaGFuZGxlciBpbXBsZW1lbnRzIHRoZSBwcmVzaWduZWQgdXBsb2FkIGZsb3cgZm9yIENoYWltIGluZ2VzdGlvbi5cbiAqL1xuY29uc3QgTEFNQkRBX0hBTkRMRVJfUEFUSCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICdsYW1iZGEtaGFuZGxlcicsICdoYW5kbGVyLmpzJyk7XG5cbi8qKlxuICogQWJzdHJhY3QgYmFzZSBjbGFzcyBmb3IgYWxsIENoYWltIGRhdGEgc3RvcmUgYmluZGVycy5cbiAqXG4gKiBQcm92aWRlcyBzaGFyZWQgaW5mcmFzdHJ1Y3R1cmU6XG4gKiAtIFNjaGVtYSBsb2FkaW5nIGFuZCB2YWxpZGF0aW9uXG4gKiAtIFNuYXBzaG90IHBheWxvYWQgY29uc3RydWN0aW9uXG4gKiAtIExPQ0FMIHNuYXBzaG90IHdyaXRpbmcgZHVyaW5nIENESyBzeW50aCAodG8gT1MgY2FjaGUpXG4gKiAtIExhbWJkYS1iYWNrZWQgY3VzdG9tIHJlc291cmNlIGZvciBTMyBwcmVzaWduZWQgdXBsb2FkICsgc25hcHNob3QtcmVmXG4gKlxuICogU3ViY2xhc3NlcyBpbXBsZW1lbnQgYGV4dHJhY3RNZXRhZGF0YSgpYCBmb3Igc3RvcmUtc3BlY2lmaWMgbWV0YWRhdGEgZXh0cmFjdGlvblxuICogYW5kIG9wdGlvbmFsbHkgb3ZlcnJpZGUgYGdldFRhYmxlKClgIGZvciBEeW5hbW9EQi1saWtlIHJlc291cmNlcy5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJhc2VDaGFpbUJpbmRlciBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKiBWYWxpZGF0ZWQgc2NoZW1hIGRhdGEgKi9cbiAgcHVibGljIHJlYWRvbmx5IHNjaGVtYURhdGE6IFNjaGVtYURhdGE7XG5cbiAgLyoqIEV4dHJhY3RlZCBkYXRhIHN0b3JlIG1ldGFkYXRhICovXG4gIHB1YmxpYyByZWFkb25seSBkYXRhU3RvcmVNZXRhZGF0YTogRGF0YVN0b3JlTWV0YWRhdGE7XG5cbiAgLyoqIEdlbmVyYXRlZCByZXNvdXJjZSBJRCAoe3Jlc291cmNlTmFtZX1fX3tlbnRpdHlOYW1lfVtfX05dKSAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcmVzb3VyY2VJZDogc3RyaW5nO1xuXG4gIC8qKiBCaW5kaW5nIGNvbmZpZ3VyYXRpb24gKi9cbiAgcHVibGljIHJlYWRvbmx5IGNvbmZpZzogVGFibGVCaW5kaW5nQ29uZmlnO1xuXG4gIC8qKiBCYXNlIHByb3BzIChmb3IgaW50ZXJuYWwgdXNlKSAqL1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgYmFzZVByb3BzOiBCYXNlQmluZGVyUHJvcHM7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEJhc2VCaW5kZXJQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICB0aGlzLmJhc2VQcm9wcyA9IHByb3BzO1xuICAgIHRoaXMuY29uZmlnID0gcHJvcHMuY29uZmlnO1xuXG4gICAgLy8gVmFsaWRhdGUgcHJvcHNcbiAgICB2YWxpZGF0ZUJpbmRlclByb3BzKHByb3BzKTtcblxuICAgIC8vIFZhbGlkYXRlIGNvbnNpc3RlbmN5IHdpdGggb3RoZXIgYmluZGluZ3MgdG8gc2FtZSB0YWJsZVxuICAgIHRoaXMudmFsaWRhdGVUYWJsZUNvbnNpc3RlbmN5KCk7XG5cbiAgICAvLyBMb2FkIGFuZCB2YWxpZGF0ZSBzY2hlbWFcbiAgICB0aGlzLnNjaGVtYURhdGEgPSBTY2hlbWFTZXJ2aWNlLnJlYWRTY2hlbWEocHJvcHMuc2NoZW1hUGF0aCk7XG5cbiAgICAvLyBFeHRyYWN0IGRhdGEgc3RvcmUgbWV0YWRhdGEgKGltcGxlbWVudGVkIGJ5IHN1YmNsYXNzKVxuICAgIHRoaXMuZGF0YVN0b3JlTWV0YWRhdGEgPSB0aGlzLmV4dHJhY3RNZXRhZGF0YSgpO1xuXG4gICAgLy8gQnVpbGQgc3RhY2sgY29udGV4dFxuICAgIGNvbnN0IHN0YWNrID0gY2RrLlN0YWNrLm9mKHRoaXMpO1xuICAgIGNvbnN0IHN0YWNrTmFtZSA9IHN0YWNrLnN0YWNrTmFtZTtcbiAgICBjb25zdCBkYXRhc3RvcmVUeXBlID0gdGhpcy5kYXRhU3RvcmVNZXRhZGF0YS50eXBlO1xuXG4gICAgLy8gR2V0IHJlc291cmNlIGFuZCBlbnRpdHkgbmFtZXNcbiAgICBjb25zdCByZXNvdXJjZU5hbWUgPSB0aGlzLmdldFJlc291cmNlTmFtZSgpO1xuICAgIGNvbnN0IGVudGl0eU5hbWUgPSB0aGlzLmdldEVudGl0eU5hbWUoKTtcblxuICAgIC8vIEdlbmVyYXRlIHJlc291cmNlIElEXG4gICAgdGhpcy5yZXNvdXJjZUlkID0gYCR7cmVzb3VyY2VOYW1lfV9fJHtlbnRpdHlOYW1lfWA7XG5cbiAgICAvLyBOb3JtYWxpemUgdmFsdWVzIGZvciBwYXRocyAoaGFuZGxlIENESyB0b2tlbnMpXG4gICAgY29uc3Qgbm9ybWFsaXplZEFjY291bnRJZCA9IG5vcm1hbGl6ZUFjY291bnRJZChzdGFjay5hY2NvdW50KTtcbiAgICBjb25zdCBub3JtYWxpemVkUmVnaW9uID0gbm9ybWFsaXplUmVnaW9uKHN0YWNrLnJlZ2lvbik7XG4gICAgY29uc3Qgbm9ybWFsaXplZFJlc291cmNlTmFtZSA9IG5vcm1hbGl6ZVJlc291cmNlTmFtZShyZXNvdXJjZU5hbWUpO1xuXG4gICAgLy8gVXBkYXRlIHJlc291cmNlIElEIHdpdGggbm9ybWFsaXplZCBuYW1lIHRvIGF2b2lkIHNwZWNpYWwgY2hhcmFjdGVyc1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRSZXNvdXJjZUlkID0gYCR7bm9ybWFsaXplZFJlc291cmNlTmFtZX1fXyR7ZW50aXR5TmFtZX1gO1xuXG4gICAgLy8gQnVpbGQgTE9DQUwgc25hcHNob3QgcGF5bG9hZFxuICAgIGNvbnN0IGxvY2FsU25hcHNob3QgPSB0aGlzLmJ1aWxkTG9jYWxTbmFwc2hvdCh7XG4gICAgICBhY2NvdW50SWQ6IG5vcm1hbGl6ZWRBY2NvdW50SWQsXG4gICAgICByZWdpb246IG5vcm1hbGl6ZWRSZWdpb24sXG4gICAgICBzdGFja05hbWUsXG4gICAgICBkYXRhc3RvcmVUeXBlLFxuICAgICAgcmVzb3VyY2VOYW1lOiBub3JtYWxpemVkUmVzb3VyY2VOYW1lLFxuICAgICAgcmVzb3VyY2VJZDogbm9ybWFsaXplZFJlc291cmNlSWQsXG4gICAgfSk7XG5cbiAgICAvLyBBcHBseSBzbmFwc2hvdCBjYWNoZSBwb2xpY3kgKGNsZWFudXAgaWYgcmVxdWVzdGVkKVxuICAgIHRoaXMuYXBwbHlTbmFwc2hvdENhY2hlUG9saWN5KHtcbiAgICAgIGFjY291bnRJZDogbm9ybWFsaXplZEFjY291bnRJZCxcbiAgICAgIHJlZ2lvbjogbm9ybWFsaXplZFJlZ2lvbixcbiAgICAgIHN0YWNrTmFtZSxcbiAgICB9KTtcblxuICAgIC8vIFdyaXRlIExPQ0FMIHNuYXBzaG90IHRvIE9TIGNhY2hlIGZvciBjaGFpbS1jbGkgY29uc3VtcHRpb25cbiAgICB0aGlzLndyaXRlTG9jYWxTbmFwc2hvdFRvRGlzayhsb2NhbFNuYXBzaG90KTtcblxuICAgIC8vIEdldCBvciBjcmVhdGUgYXNzZXQgZGlyZWN0b3J5XG4gICAgY29uc3QgYXNzZXREaXIgPSB0aGlzLndyaXRlU25hcHNob3RBc3NldChsb2NhbFNuYXBzaG90LCBzdGFja05hbWUpO1xuXG4gICAgLy8gRGVwbG95IExhbWJkYS1iYWNrZWQgY3VzdG9tIHJlc291cmNlIGZvciBpbmdlc3Rpb25cbiAgICB0aGlzLmRlcGxveUluZ2VzdGlvblJlc291cmNlcyhhc3NldERpcik7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGhhdCBhbGwgYmluZGluZ3MgdG8gdGhlIHNhbWUgdGFibGUgdXNlIHRoZSBzYW1lIGNvbmZpZy5cbiAgICogXG4gICAqIFRoaXMgaXMgYSBzYWZldHkgY2hlY2sgLSBzaGFyaW5nIHRoZSBzYW1lIFRhYmxlQmluZGluZ0NvbmZpZyBvYmplY3RcbiAgICogYWxyZWFkeSBlbnN1cmVzIGNvbnNpc3RlbmN5LCBidXQgdGhpcyBjYXRjaGVzIGNhc2VzIHdoZXJlIHVzZXJzXG4gICAqIGNyZWF0ZSBzZXBhcmF0ZSBjb25maWdzIHdpdGggaWRlbnRpY2FsIHZhbHVlcy5cbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVUYWJsZUNvbnNpc3RlbmN5KCk6IHZvaWQge1xuICAgIC8vIE9ubHkgZm9yIER5bmFtb0RCIGJpbmRlcnMgKGhhcyB0YWJsZSBwcm9wZXJ0eSlcbiAgICBjb25zdCB0YWJsZSA9ICh0aGlzLmJhc2VQcm9wcyBhcyBhbnkpLnRhYmxlO1xuICAgIGlmICghdGFibGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBGaW5kIG90aGVyIGJpbmRlcnMgZm9yIHRoZSBzYW1lIHRhYmxlXG4gICAgY29uc3Qgc3RhY2sgPSBjZGsuU3RhY2sub2YodGhpcyk7XG4gICAgY29uc3Qgb3RoZXJCaW5kZXJzID0gc3RhY2subm9kZS5maW5kQWxsKClcbiAgICAgIC5maWx0ZXIobm9kZSA9PiBub2RlIGluc3RhbmNlb2YgQmFzZUNoYWltQmluZGVyKVxuICAgICAgLmZpbHRlcihiaW5kZXIgPT4gYmluZGVyICE9PSB0aGlzKVxuICAgICAgLmZpbHRlcihiaW5kZXIgPT4ge1xuICAgICAgICBjb25zdCBvdGhlclRhYmxlID0gKChiaW5kZXIgYXMgQmFzZUNoYWltQmluZGVyKS5iYXNlUHJvcHMgYXMgYW55KS50YWJsZTtcbiAgICAgICAgcmV0dXJuIG90aGVyVGFibGUgPT09IHRhYmxlO1xuICAgICAgfSlcbiAgICAgIC5tYXAoYmluZGVyID0+IGJpbmRlciBhcyBCYXNlQ2hhaW1CaW5kZXIpO1xuXG4gICAgaWYgKG90aGVyQmluZGVycy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjsgLy8gRmlyc3QgYmluZGluZyBmb3IgdGhpcyB0YWJsZVxuICAgIH1cblxuICAgIGNvbnN0IGZpcnN0QmluZGVyID0gb3RoZXJCaW5kZXJzWzBdO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhleSdyZSB1c2luZyB0aGUgZXhhY3Qgc2FtZSBjb25maWcgb2JqZWN0IChyZWNvbW1lbmRlZClcbiAgICBpZiAodGhpcy5jb25maWcgPT09IGZpcnN0QmluZGVyLmNvbmZpZykge1xuICAgICAgcmV0dXJuOyAvLyBQZXJmZWN0IC0gc2FtZSBjb25maWcgb2JqZWN0XG4gICAgfVxuXG4gICAgLy8gRGlmZmVyZW50IGNvbmZpZyBvYmplY3RzIC0gdmFsaWRhdGUgdGhleSBoYXZlIHNhbWUgdmFsdWVzXG4gICAgaWYgKHRoaXMuY29uZmlnLmFwcElkICE9PSBmaXJzdEJpbmRlci5jb25maWcuYXBwSWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENvbmZpZ3VyYXRpb24gY29uZmxpY3QgZm9yIHRhYmxlIFwiJHt0YWJsZS50YWJsZU5hbWV9XCIuXFxuXFxuYCArXG4gICAgICAgIGBCaW5kZXIgXCIke2ZpcnN0QmluZGVyLm5vZGUuaWR9XCIgdXNlcyBhcHBJZDogXCIke2ZpcnN0QmluZGVyLmNvbmZpZy5hcHBJZH1cIlxcbmAgK1xuICAgICAgICBgQmluZGVyIFwiJHt0aGlzLm5vZGUuaWR9XCIgdXNlcyBhcHBJZDogXCIke3RoaXMuY29uZmlnLmFwcElkfVwiXFxuXFxuYCArXG4gICAgICAgIGBBbGwgYmluZGluZ3MgdG8gdGhlIHNhbWUgdGFibGUgTVVTVCB1c2UgdGhlIHNhbWUgYXBwSWQuXFxuXFxuYCArXG4gICAgICAgIGBSRUNPTU1FTkRFRDogU2hhcmUgdGhlIHNhbWUgVGFibGVCaW5kaW5nQ29uZmlnIG9iamVjdDpcXG5gICtcbiAgICAgICAgYCAgY29uc3QgY29uZmlnID0gbmV3IFRhYmxlQmluZGluZ0NvbmZpZygnJHtmaXJzdEJpbmRlci5jb25maWcuYXBwSWR9JywgY3JlZGVudGlhbHMpO1xcbmAgK1xuICAgICAgICBgICBuZXcgQ2hhaW1EeW5hbW9EQkJpbmRlcih0aGlzLCAnJHtmaXJzdEJpbmRlci5ub2RlLmlkfScsIHsgLi4uLCBjb25maWcgfSk7XFxuYCArXG4gICAgICAgIGAgIG5ldyBDaGFpbUR5bmFtb0RCQmluZGVyKHRoaXMsICcke3RoaXMubm9kZS5pZH0nLCB7IC4uLiwgY29uZmlnIH0pO2BcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgY3JlZGVudGlhbHMgbWF0Y2hcbiAgICBjb25zdCBmaXJzdENyZWRzID0gSlNPTi5zdHJpbmdpZnkoZmlyc3RCaW5kZXIuY29uZmlnLmNyZWRlbnRpYWxzKTtcbiAgICBjb25zdCB0aGlzQ3JlZHMgPSBKU09OLnN0cmluZ2lmeSh0aGlzLmNvbmZpZy5jcmVkZW50aWFscyk7XG4gICAgXG4gICAgaWYgKGZpcnN0Q3JlZHMgIT09IHRoaXNDcmVkcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgQ29uZmlndXJhdGlvbiBjb25mbGljdCBmb3IgdGFibGUgXCIke3RhYmxlLnRhYmxlTmFtZX1cIi5cXG5cXG5gICtcbiAgICAgICAgYEJpbmRlciBcIiR7Zmlyc3RCaW5kZXIubm9kZS5pZH1cIiB1c2VzIGRpZmZlcmVudCBjcmVkZW50aWFscyB0aGFuIFwiJHt0aGlzLm5vZGUuaWR9XCIuXFxuXFxuYCArXG4gICAgICAgIGBBbGwgYmluZGluZ3MgdG8gdGhlIHNhbWUgdGFibGUgTVVTVCB1c2UgdGhlIHNhbWUgY3JlZGVudGlhbHMuXFxuXFxuYCArXG4gICAgICAgIGBSRUNPTU1FTkRFRDogU2hhcmUgdGhlIHNhbWUgVGFibGVCaW5kaW5nQ29uZmlnIG9iamVjdCB0byBhdm9pZCB0aGlzIGVycm9yLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gV2FybiBhYm91dCBkaWZmZXJlbnQgZmFpbHVyZU1vZGUgKG5vdCBhbiBlcnJvcilcbiAgICBpZiAodGhpcy5jb25maWcuZmFpbHVyZU1vZGUgIT09IGZpcnN0QmluZGVyLmNvbmZpZy5mYWlsdXJlTW9kZSkge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBgV2FybmluZzogRGlmZmVyZW50IGZhaWx1cmVNb2RlIGZvciB0YWJsZSBcIiR7dGFibGUudGFibGVOYW1lfVwiLlxcbmAgK1xuICAgICAgICBgICBcIiR7Zmlyc3RCaW5kZXIubm9kZS5pZH1cIjogJHtmaXJzdEJpbmRlci5jb25maWcuZmFpbHVyZU1vZGV9XFxuYCArXG4gICAgICAgIGAgIFwiJHt0aGlzLm5vZGUuaWR9XCI6ICR7dGhpcy5jb25maWcuZmFpbHVyZU1vZGV9XFxuYCArXG4gICAgICAgIGBDb25zaWRlciBzaGFyaW5nIHRoZSBzYW1lIFRhYmxlQmluZGluZ0NvbmZpZyBvYmplY3QuYFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWJzdHJhY3QgbWV0aG9kIC0gc3ViY2xhc3NlcyBpbXBsZW1lbnQgc3RvcmUtc3BlY2lmaWMgbWV0YWRhdGEgZXh0cmFjdGlvbi5cbiAgICovXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBleHRyYWN0TWV0YWRhdGEoKTogRGF0YVN0b3JlTWV0YWRhdGE7XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIGluIHN1YmNsYXNzZXMgdG8gcHJvdmlkZSB0aGUgdGFibGUgY29uc3RydWN0IGZvciBzdGFibGUgaWRlbnRpdHkuXG4gICAqIERlZmF1bHQgcmV0dXJucyB1bmRlZmluZWQgKHdpbGwgZmFsbCBiYWNrIHRvIGNvbnN0cnVjdCBwYXRoKS5cbiAgICovXG4gIHByb3RlY3RlZCBnZXRUYWJsZSgpOiBkeW5hbW9kYi5JVGFibGUgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSByZXNvdXJjZSBuYW1lIGZvciBkaXNwbGF5IGFuZCBmaWxlbmFtZXMuXG4gICAqIEZvciBEeW5hbW9EQiwgdGhpcyBpcyB0aGUgdXNlciBsYWJlbCAobm90IG5lY2Vzc2FyaWx5IHRoZSBwaHlzaWNhbCB0YWJsZSBuYW1lKS5cbiAgICogXG4gICAqIFN1YmNsYXNzZXMgY2FuIG92ZXJyaWRlIHRoaXMgdG8gcHJvdmlkZSBhIG1vcmUgbWVhbmluZ2Z1bCBuYW1lXG4gICAqIChlLmcuLCBjb25zdHJ1Y3Qgbm9kZSBJRCBpbnN0ZWFkIG9mIHBoeXNpY2FsIHJlc291cmNlIG5hbWUgd2hpY2ggbWF5IGNvbnRhaW4gdG9rZW5zKS5cbiAgICovXG4gIHByb3RlY3RlZCBnZXRSZXNvdXJjZU5hbWUoKTogc3RyaW5nIHtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHRoaXMuZGF0YVN0b3JlTWV0YWRhdGEgYXMgYW55O1xuICAgIHJldHVybiBtZXRhZGF0YS50YWJsZU5hbWUgfHwgbWV0YWRhdGEubmFtZSB8fCAncmVzb3VyY2UnO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgZW50aXR5IG5hbWUgZnJvbSBzY2hlbWEuXG4gICAqL1xuICBwcml2YXRlIGdldEVudGl0eU5hbWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5zY2hlbWFEYXRhLmVudGl0eU5hbWU7XG4gIH1cblxuICAvKipcbiAgICogUmVhZCBwYWNrYWdlIHZlcnNpb24gZnJvbSBwYWNrYWdlLmpzb24uXG4gICAqIFVzZWQgdG8gcG9wdWxhdGUgcHJvZHVjZXIgbWV0YWRhdGEgaW4gc25hcHNob3RzLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRQYWNrYWdlVmVyc2lvbigpOiBzdHJpbmcge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYWNrYWdlUGF0aCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdwYWNrYWdlLmpzb24nKTtcbiAgICAgIGNvbnN0IHBhY2thZ2VKc29uID0gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMocGFja2FnZVBhdGgsICd1dGYtOCcpKTtcbiAgICAgIHJldHVybiBwYWNrYWdlSnNvbi52ZXJzaW9uIHx8ICcwLjAuMCc7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUud2FybignRmFpbGVkIHRvIHJlYWQgcGFja2FnZSB2ZXJzaW9uOicsIGVycm9yKTtcbiAgICAgIHJldHVybiAnMC4wLjAnO1xuICAgIH1cbiAgfVxuXG5cblxuICAvKipcbiAgICogQnVpbGQgYSBMT0NBTCBzbmFwc2hvdCBwYXlsb2FkIGZvciBDTEkgY29uc3VtcHRpb24uXG4gICAqIERvZXMgbm90IGluY2x1ZGUgZXZlbnRJZCBvciBjb250ZW50SGFzaCAtIHRob3NlIGFyZSBnZW5lcmF0ZWQgYXQgZGVwbG95LXRpbWUuXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkTG9jYWxTbmFwc2hvdChwYXJhbXM6IHtcbiAgICBhY2NvdW50SWQ6IHN0cmluZztcbiAgICByZWdpb246IHN0cmluZztcbiAgICBzdGFja05hbWU6IHN0cmluZztcbiAgICBkYXRhc3RvcmVUeXBlOiBzdHJpbmc7XG4gICAgcmVzb3VyY2VOYW1lOiBzdHJpbmc7XG4gICAgcmVzb3VyY2VJZDogc3RyaW5nO1xuICB9KTogTG9jYWxTbmFwc2hvdFBheWxvYWQge1xuICAgIGNvbnN0IGNhcHR1cmVkQXQgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG4gICAgY29uc3Qgc3RhY2sgPSBjZGsuU3RhY2sub2YodGhpcyk7XG5cbiAgICAvLyBCdWlsZCBwcm92aWRlciBpZGVudGl0eVxuICAgIGNvbnN0IHByb3ZpZGVySWRlbnRpdHkgPSB7XG4gICAgICBjbG91ZDogJ2F3cycgYXMgY29uc3QsXG4gICAgICBhY2NvdW50SWQ6IHBhcmFtcy5hY2NvdW50SWQsXG4gICAgICByZWdpb246IHBhcmFtcy5yZWdpb24sXG4gICAgICBkZXBsb3ltZW50U3lzdGVtOiAnY2xvdWRmb3JtYXRpb24nIGFzIGNvbnN0LFxuICAgICAgZGVwbG95bWVudElkOiBzdGFjay5zdGFja0lkLFxuICAgIH07XG5cbiAgICAvLyBCdWlsZCBiaW5kaW5nIGlkZW50aXR5XG4gICAgY29uc3Qgc3RhYmxlUmVzb3VyY2VLZXkgPSBgJHtwYXJhbXMuZGF0YXN0b3JlVHlwZX06cGF0aDoke3BhcmFtcy5zdGFja05hbWV9LyR7cGFyYW1zLnJlc291cmNlTmFtZX1gO1xuICAgIGNvbnN0IGVudGl0eUlkID0gYCR7dGhpcy5jb25maWcuYXBwSWR9OiR7dGhpcy5zY2hlbWFEYXRhLmVudGl0eU5hbWV9YDtcbiAgICBjb25zdCBiaW5kaW5nSWQgPSBgJHt0aGlzLmNvbmZpZy5hcHBJZH06JHtzdGFibGVSZXNvdXJjZUtleX06JHt0aGlzLnNjaGVtYURhdGEuZW50aXR5TmFtZX1gO1xuXG4gICAgY29uc3QgaWRlbnRpdHkgPSB7XG4gICAgICBhcHBJZDogdGhpcy5jb25maWcuYXBwSWQsXG4gICAgICBlbnRpdHlOYW1lOiB0aGlzLnNjaGVtYURhdGEuZW50aXR5TmFtZSxcbiAgICAgIHN0YWJsZVJlc291cmNlS2V5U3RyYXRlZ3k6ICdjZGstY29uc3RydWN0LXBhdGgnIGFzIGNvbnN0LFxuICAgICAgc3RhYmxlUmVzb3VyY2VLZXksXG4gICAgICByZXNvdXJjZUlkOiBwYXJhbXMucmVzb3VyY2VJZCxcbiAgICAgIGVudGl0eUlkLFxuICAgICAgYmluZGluZ0lkLFxuICAgIH07XG5cbiAgICAvLyBCdWlsZCBvcGVyYXRpb24gbWV0YWRhdGFcbiAgICBjb25zdCBvcGVyYXRpb24gPSB7XG4gICAgICBldmVudElkOiB0aGlzLmdlbmVyYXRlVXVpZCgpLFxuICAgICAgcmVxdWVzdFR5cGU6ICdDcmVhdGUnIGFzIGNvbnN0LFxuICAgICAgZmFpbHVyZU1vZGU6IHRoaXMuY29uZmlnLmZhaWx1cmVNb2RlLFxuICAgIH07XG5cbiAgICAvLyBCdWlsZCByZXNvbHV0aW9uIG1ldGFkYXRhXG4gICAgY29uc3QgaGFzVG9rZW5zID0gdGhpcy5kZXRlY3RVbnJlc29sdmVkVG9rZW5zKHRoaXMuZGF0YVN0b3JlTWV0YWRhdGEpO1xuICAgIGNvbnN0IHJlc29sdXRpb24gPSB7XG4gICAgICBtb2RlOiAnTE9DQUwnIGFzIGNvbnN0LFxuICAgICAgaGFzVG9rZW5zLFxuICAgIH07XG5cbiAgICAvLyBCdWlsZCBoYXNoZXNcbiAgICBjb25zdCBzY2hlbWFCeXRlcyA9IEpTT04uc3RyaW5naWZ5KHRoaXMuc2NoZW1hRGF0YSk7XG4gICAgY29uc3Qgc2NoZW1hSGFzaCA9ICdzaGEyNTY6JyArIGNyeXB0by5jcmVhdGVIYXNoKCdzaGEyNTYnKS51cGRhdGUoc2NoZW1hQnl0ZXMpLmRpZ2VzdCgnaGV4Jyk7XG4gICAgY29uc3QgaGFzaGVzID0ge1xuICAgICAgc2NoZW1hSGFzaCxcbiAgICAgIGNvbnRlbnRIYXNoOiAnJyxcbiAgICB9O1xuXG4gICAgLy8gQnVpbGQgcmVzb3VyY2UgbWV0YWRhdGFcbiAgICBjb25zdCByZXNvdXJjZSA9IHRoaXMuYnVpbGRSZXNvdXJjZU1ldGFkYXRhKHBhcmFtcyk7XG5cbiAgICAvLyBCdWlsZCBwcm9kdWNlciBtZXRhZGF0YVxuICAgIGNvbnN0IHByb2R1Y2VyID0ge1xuICAgICAgY29tcG9uZW50OiAnY2hhaW0tY2RrJyBhcyBjb25zdCxcbiAgICAgIHZlcnNpb246IHRoaXMuZ2V0UGFja2FnZVZlcnNpb24oKSxcbiAgICAgIHJ1bnRpbWU6IHByb2Nlc3MudmVyc2lvbixcbiAgICB9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHNuYXBzaG90VmVyc2lvbjogU05BUFNIT1RfU0NIRU1BX1ZFUlNJT04sXG4gICAgICBhY3Rpb246ICdVUFNFUlQnLFxuICAgICAgY2FwdHVyZWRBdCxcbiAgICAgIHByb3ZpZGVySWRlbnRpdHksXG4gICAgICBpZGVudGl0eSxcbiAgICAgIG9wZXJhdGlvbixcbiAgICAgIHJlc29sdXRpb24sXG4gICAgICBoYXNoZXMsXG4gICAgICBzY2hlbWE6IHRoaXMuc2NoZW1hRGF0YSxcbiAgICAgIHJlc291cmNlLFxuICAgICAgcHJvZHVjZXIsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCByZXNvdXJjZSBtZXRhZGF0YSBmcm9tIGRhdGFTdG9yZSBtZXRhZGF0YS5cbiAgICovXG4gIHByaXZhdGUgYnVpbGRSZXNvdXJjZU1ldGFkYXRhKHBhcmFtczogYW55KTogYW55IHtcbiAgICBjb25zdCBkeW5hbW9NZXRhZGF0YSA9IHRoaXMuZGF0YVN0b3JlTWV0YWRhdGEgYXMgYW55O1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICB0eXBlOiAnZHluYW1vZGInLFxuICAgICAga2luZDogJ3RhYmxlJyxcbiAgICAgIGlkOiBkeW5hbW9NZXRhZGF0YS50YWJsZUFybixcbiAgICAgIG5hbWU6IGR5bmFtb01ldGFkYXRhLnRhYmxlTmFtZSxcbiAgICAgIHJlZ2lvbjogcGFyYW1zLnJlZ2lvbixcbiAgICAgIHBhcnRpdGlvbktleTogZHluYW1vTWV0YWRhdGEucGFydGl0aW9uS2V5LFxuICAgICAgc29ydEtleTogZHluYW1vTWV0YWRhdGEuc29ydEtleSxcbiAgICAgIGdsb2JhbFNlY29uZGFyeUluZGV4ZXM6IGR5bmFtb01ldGFkYXRhLmdsb2JhbFNlY29uZGFyeUluZGV4ZXMsXG4gICAgICBsb2NhbFNlY29uZGFyeUluZGV4ZXM6IGR5bmFtb01ldGFkYXRhLmxvY2FsU2Vjb25kYXJ5SW5kZXhlcyxcbiAgICAgIHR0bEF0dHJpYnV0ZTogZHluYW1vTWV0YWRhdGEudHRsQXR0cmlidXRlLFxuICAgICAgc3RyZWFtRW5hYmxlZDogZHluYW1vTWV0YWRhdGEuc3RyZWFtRW5hYmxlZCxcbiAgICAgIHN0cmVhbVZpZXdUeXBlOiBkeW5hbW9NZXRhZGF0YS5zdHJlYW1WaWV3VHlwZSxcbiAgICAgIGJpbGxpbmdNb2RlOiBkeW5hbW9NZXRhZGF0YS5iaWxsaW5nTW9kZSxcbiAgICAgIGVuY3J5cHRpb25LZXlBcm46IGR5bmFtb01ldGFkYXRhLmVuY3J5cHRpb25LZXlBcm4sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlY3QgaWYgbWV0YWRhdGEgY29udGFpbnMgdW5yZXNvbHZlZCBDREsgdG9rZW5zLlxuICAgKi9cbiAgcHJpdmF0ZSBkZXRlY3RVbnJlc29sdmVkVG9rZW5zKG1ldGFkYXRhOiBhbnkpOiBib29sZWFuIHtcbiAgICBjb25zdCBzdHIgPSBKU09OLnN0cmluZ2lmeShtZXRhZGF0YSk7XG4gICAgcmV0dXJuIHN0ci5pbmNsdWRlcygnJHtUb2tlblsnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhIFVVSUQgdjQgZm9yIG9wZXJhdGlvbiB0cmFja2luZy5cbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVVdWlkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGNyeXB0by5yYW5kb21VVUlEKCk7XG4gIH1cblxuICAvKipcbiAgICogQXBwbHkgc25hcHNob3QgY2FjaGUgcG9saWN5IGJhc2VkIG9uIENESyBjb250ZXh0LlxuICAgKiBcbiAgICogQ2hlY2tzIHRoZSBgY2hhaW1TbmFwc2hvdENhY2hlUG9saWN5YCBjb250ZXh0IHZhbHVlOlxuICAgKiAtIE5PTkUgKGRlZmF1bHQpOiBObyBjbGVhbnVwXG4gICAqIC0gUFJVTkVfU1RBQ0s6IERlbGV0ZSBleGlzdGluZyBzdGFjayBzbmFwc2hvdHMgYmVmb3JlIHdyaXRpbmcgbmV3IG9uZXNcbiAgICogXG4gICAqIFRoaXMgcnVucyBvbmNlIHBlciBzdGFjayAodHJhY2tlZCBieSBzdGF0aWMgZmxhZykgdG8gYXZvaWRcbiAgICogbXVsdGlwbGUgY2xlYW51cCBhdHRlbXB0cyB3aGVuIGJpbmRpbmcgbXVsdGlwbGUgZW50aXRpZXMuXG4gICAqL1xuICBwcml2YXRlIGFwcGx5U25hcHNob3RDYWNoZVBvbGljeShwYXJhbXM6IHtcbiAgICBhY2NvdW50SWQ6IHN0cmluZztcbiAgICByZWdpb246IHN0cmluZztcbiAgICBzdGFja05hbWU6IHN0cmluZztcbiAgfSk6IHZvaWQge1xuICAgIC8vIEdldCBwb2xpY3kgZnJvbSBDREsgY29udGV4dCAoZGVmYXVsdHMgdG8gTk9ORSlcbiAgICBjb25zdCBwb2xpY3lWYWx1ZSA9IHRoaXMubm9kZS50cnlHZXRDb250ZXh0KFNOQVBTSE9UX0NBQ0hFX1BPTElDWV9DT05URVhUX0tFWSk7XG4gICAgY29uc3QgcG9saWN5ID0gdGhpcy5wYXJzZVNuYXBzaG90Q2FjaGVQb2xpY3kocG9saWN5VmFsdWUpO1xuXG4gICAgaWYgKHBvbGljeSA9PT0gU25hcHNob3RDYWNoZVBvbGljeS5OT05FKSB7XG4gICAgICByZXR1cm47IC8vIE5vIGNsZWFudXBcbiAgICB9XG5cbiAgICAvLyBDaGVjayBpZiB3ZSd2ZSBhbHJlYWR5IGNsZWFuZWQgdGhpcyBzdGFjayBpbiB0aGlzIHN5bnRoXG4gICAgY29uc3Qgc3RhY2sgPSBjZGsuU3RhY2sub2YodGhpcyk7XG4gICAgY29uc3QgY2xlYW51cEtleSA9IGBfX2NoYWltX3NuYXBzaG90X2NsZWFudXBfJHtwYXJhbXMuc3RhY2tOYW1lfWA7XG4gICAgXG4gICAgaWYgKChzdGFjay5ub2RlIGFzIGFueSlbY2xlYW51cEtleV0pIHtcbiAgICAgIHJldHVybjsgLy8gQWxyZWFkeSBjbGVhbmVkIGluIHRoaXMgc3ludGhcbiAgICB9XG5cbiAgICAvLyBNYXJrIGFzIGNsZWFuZWQgdG8gYXZvaWQgZHVwbGljYXRlIGNsZWFudXBcbiAgICAoc3RhY2subm9kZSBhcyBhbnkpW2NsZWFudXBLZXldID0gdHJ1ZTtcblxuICAgIGlmIChwb2xpY3kgPT09IFNuYXBzaG90Q2FjaGVQb2xpY3kuUFJVTkVfU1RBQ0spIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IHBydW5lU3RhY2tTbmFwc2hvdHMoe1xuICAgICAgICBhY2NvdW50SWQ6IHBhcmFtcy5hY2NvdW50SWQsXG4gICAgICAgIHJlZ2lvbjogcGFyYW1zLnJlZ2lvbixcbiAgICAgICAgc3RhY2tOYW1lOiBwYXJhbXMuc3RhY2tOYW1lLFxuICAgICAgICB2ZXJib3NlOiBmYWxzZSwgLy8gRG9uJ3Qgc3BhbSBjb25zb2xlIGR1cmluZyBzeW50aFxuICAgICAgfSk7XG5cbiAgICAgIC8vIE9ubHkgbG9nIGlmIHZlcmJvc2UgbW9kZSBvciBlcnJvcnNcbiAgICAgIGlmIChyZXN1bHQuZGVsZXRlZENvdW50ID4gMCB8fCByZXN1bHQuZXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc29sZS5sb2coYFtDaGFpbV0gUHJ1bmVkICR7cmVzdWx0LmRlbGV0ZWRDb3VudH0gc25hcHNob3QocykgZm9yIHN0YWNrOiAke3BhcmFtcy5zdGFja05hbWV9YCk7XG4gICAgICAgIFxuICAgICAgICBpZiAocmVzdWx0LmVycm9ycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKGBbQ2hhaW1dIENsZWFudXAgd2FybmluZ3M6YCwgcmVzdWx0LmVycm9ycyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUGFyc2Ugc25hcHNob3QgY2FjaGUgcG9saWN5IGZyb20gY29udGV4dCB2YWx1ZS5cbiAgICovXG4gIHByaXZhdGUgcGFyc2VTbmFwc2hvdENhY2hlUG9saWN5KHZhbHVlOiB1bmtub3duKTogU25hcHNob3RDYWNoZVBvbGljeSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBERUZBVUxUX1NOQVBTSE9UX0NBQ0hFX1BPTElDWTtcbiAgICB9XG5cbiAgICBjb25zdCB1cHBlclZhbHVlID0gdmFsdWUudG9VcHBlckNhc2UoKTtcbiAgICBcbiAgICBpZiAodXBwZXJWYWx1ZSA9PT0gJ05PTkUnIHx8IHVwcGVyVmFsdWUgPT09ICdESVNBQkxFRCcpIHtcbiAgICAgIHJldHVybiBTbmFwc2hvdENhY2hlUG9saWN5Lk5PTkU7XG4gICAgfVxuICAgIFxuICAgIGlmICh1cHBlclZhbHVlID09PSAnUFJVTkVfU1RBQ0snIHx8IHVwcGVyVmFsdWUgPT09ICdQUlVORScpIHtcbiAgICAgIHJldHVybiBTbmFwc2hvdENhY2hlUG9saWN5LlBSVU5FX1NUQUNLO1xuICAgIH1cblxuICAgIGNvbnNvbGUud2FybihcbiAgICAgIGBbQ2hhaW1dIFVua25vd24gY2hhaW1TbmFwc2hvdENhY2hlUG9saWN5OiBcIiR7dmFsdWV9XCIuIGAgK1xuICAgICAgYFZhbGlkIHZhbHVlczogTk9ORSwgUFJVTkVfU1RBQ0suIERlZmF1bHRpbmcgdG8gTk9ORS5gXG4gICAgKTtcbiAgICBcbiAgICByZXR1cm4gREVGQVVMVF9TTkFQU0hPVF9DQUNIRV9QT0xJQ1k7XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCBzdGFjayBuYW1lIGZyb20gc3RhYmxlUmVzb3VyY2VLZXkuXG4gICAqIEZvcm1hdDogZHluYW1vZGI6cGF0aDpTdGFja05hbWUvUmVzb3VyY2VOYW1lXG4gICAqL1xuICBwcml2YXRlIGV4dHJhY3RTdGFja05hbWVGcm9tUmVzb3VyY2VLZXkoc3RhYmxlUmVzb3VyY2VLZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgbWF0Y2ggPSBzdGFibGVSZXNvdXJjZUtleS5tYXRjaCgvcGF0aDooW14vXSspLyk7XG4gICAgcmV0dXJuIG1hdGNoID8gbWF0Y2hbMV0gOiAndW5rbm93bic7XG4gIH1cblxuICAvKipcbiAgICogV3JpdGUgTE9DQUwgc25hcHNob3QgdG8gT1MgY2FjaGUgZm9yIGNoYWltLWNsaSBjb25zdW1wdGlvbi5cbiAgICogVXNlcyBoaWVyYXJjaGljYWwgcGF0aDogYXdzL3thY2NvdW50SWR9L3tyZWdpb259L3tzdGFja05hbWV9L3tkYXRhc3RvcmVUeXBlfS97cmVzb3VyY2VJZH0uanNvblxuICAgKiBcbiAgICogQHBhcmFtIHNuYXBzaG90IC0gVGhlIHNuYXBzaG90IHBheWxvYWQgdG8gd3JpdGVcbiAgICogQHJldHVybnMgVGhlIHBhdGggd2hlcmUgc25hcHNob3Qgd2FzIHdyaXR0ZW5cbiAgICovXG4gIHByaXZhdGUgd3JpdGVMb2NhbFNuYXBzaG90VG9EaXNrKHNuYXBzaG90OiBMb2NhbFNuYXBzaG90UGF5bG9hZCk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3RhY2tOYW1lID0gdGhpcy5leHRyYWN0U3RhY2tOYW1lRnJvbVJlc291cmNlS2V5KHNuYXBzaG90LmlkZW50aXR5LnN0YWJsZVJlc291cmNlS2V5KTtcbiAgICBcbiAgICBjb25zdCBkaXIgPSBnZXRTbmFwc2hvdERpcih7XG4gICAgICBhY2NvdW50SWQ6IHNuYXBzaG90LnByb3ZpZGVySWRlbnRpdHkuYWNjb3VudElkLFxuICAgICAgcmVnaW9uOiBzbmFwc2hvdC5wcm92aWRlcklkZW50aXR5LnJlZ2lvbixcbiAgICAgIHN0YWNrTmFtZSxcbiAgICAgIGRhdGFzdG9yZVR5cGU6IHNuYXBzaG90LnJlc291cmNlLnR5cGUsXG4gICAgfSk7XG4gICAgXG4gICAgZW5zdXJlRGlyRXhpc3RzKGRpcik7XG4gICAgXG4gICAgY29uc3QgZmlsZVBhdGggPSBnZXRMb2NhbFNuYXBzaG90UGF0aCh7XG4gICAgICBhY2NvdW50SWQ6IHNuYXBzaG90LnByb3ZpZGVySWRlbnRpdHkuYWNjb3VudElkLFxuICAgICAgcmVnaW9uOiBzbmFwc2hvdC5wcm92aWRlcklkZW50aXR5LnJlZ2lvbixcbiAgICAgIHN0YWNrTmFtZSxcbiAgICAgIGRhdGFzdG9yZVR5cGU6IHNuYXBzaG90LnJlc291cmNlLnR5cGUsXG4gICAgICByZXNvdXJjZUlkOiBzbmFwc2hvdC5pZGVudGl0eS5yZXNvdXJjZUlkLFxuICAgIH0pO1xuICAgIFxuICAgIGZzLndyaXRlRmlsZVN5bmMoZmlsZVBhdGgsIEpTT04uc3RyaW5naWZ5KHNuYXBzaG90LCBudWxsLCAyKSwgJ3V0Zi04Jyk7XG4gICAgXG4gICAgcmV0dXJuIGZpbGVQYXRoO1xuICB9XG5cblxuICAvKipcbiAgICogRmluZCB0aGUgQ0RLIHByb2plY3Qgcm9vdCBieSB3YWxraW5nIHVwIGZyb20gY3VycmVudCBtb2R1bGUuXG4gICAqL1xuICBwcml2YXRlIGZpbmRDZGtQcm9qZWN0Um9vdCgpOiBzdHJpbmcge1xuICAgIGxldCBjdXJyZW50RGlyID0gX19kaXJuYW1lO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMTA7IGkrKykge1xuICAgICAgY29uc3QgY2RrSnNvblBhdGggPSBwYXRoLmpvaW4oY3VycmVudERpciwgJ2Nkay5qc29uJyk7XG4gICAgICBpZiAoZnMuZXhpc3RzU3luYyhjZGtKc29uUGF0aCkpIHtcbiAgICAgICAgcmV0dXJuIGN1cnJlbnREaXI7XG4gICAgICB9XG4gICAgICBjb25zdCBwYXJlbnREaXIgPSBwYXRoLmRpcm5hbWUoY3VycmVudERpcik7XG4gICAgICBpZiAocGFyZW50RGlyID09PSBjdXJyZW50RGlyKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY3VycmVudERpciA9IHBhcmVudERpcjtcbiAgICB9XG4gICAgLy8gRmFsbGJhY2sgdG8gY3dkXG4gICAgcmV0dXJuIHByb2Nlc3MuY3dkKCk7XG4gIH1cblxuICAvKipcbiAgICogV3JpdGUgc25hcHNob3QgYW5kIExhbWJkYSBoYW5kbGVyIHRvIGlzb2xhdGVkIENESyBhc3NldCBkaXJlY3RvcnkgZm9yIExhbWJkYSBidW5kbGluZy5cbiAgICogXG4gICAqIEFzc2V0IGRpcmVjdG9yeSBpcyBwZXIge3N0YWNrTmFtZX0ve3Jlc291cmNlSWR9IGFuZCBNVVNUIE5PVCBiZSBzaGFyZWQuXG4gICAqIFRoZSBMYW1iZGEgcmVhZHMgLi9zbmFwc2hvdC5qc29uIGZyb20gaXRzIGJ1bmRsZSwgTk9UIGZyb20gZW52IHZhcnMgb3IgT1MgY2FjaGUuXG4gICAqIFxuICAgKiBUaGUgaGFuZGxlciBpcyBjb3BpZWQgZnJvbSB0aGUgY2Fub25pY2FsIGhhbmRsZXIgZmlsZSAoc3JjL2xhbWJkYS1oYW5kbGVyL2hhbmRsZXIuanMpXG4gICAqIHJhdGhlciB0aGFuIGJlaW5nIGdlbmVyYXRlZCBpbmxpbmUgLSB0aGlzIGVuc3VyZXMgYSBzaW5nbGUgc291cmNlIG9mIHRydXRoLlxuICAgKlxuICAgKiBAcmV0dXJucyBUaGUgYXNzZXQgZGlyZWN0b3J5IHBhdGhcbiAgICovXG4gIHByaXZhdGUgd3JpdGVTbmFwc2hvdEFzc2V0KHNuYXBzaG90OiBMb2NhbFNuYXBzaG90UGF5bG9hZCwgc3RhY2tOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNka1Jvb3QgPSB0aGlzLmZpbmRDZGtQcm9qZWN0Um9vdCgpO1xuICAgIGNvbnN0IGFzc2V0RGlyID0gcGF0aC5qb2luKGNka1Jvb3QsICdjZGsub3V0JywgJ2NoYWltJywgJ2Fzc2V0cycsIHN0YWNrTmFtZSwgdGhpcy5yZXNvdXJjZUlkKTtcbiAgICBlbnN1cmVEaXJFeGlzdHMoYXNzZXREaXIpO1xuXG4gICAgLy8gV3JpdGUgc25hcHNob3QuanNvbiAoT1ZFUldSSVRFIGVhY2ggc3ludGgpXG4gICAgY29uc3Qgc25hcHNob3RQYXRoID0gcGF0aC5qb2luKGFzc2V0RGlyLCAnc25hcHNob3QuanNvbicpO1xuICAgIGZzLndyaXRlRmlsZVN5bmMoc25hcHNob3RQYXRoLCBKU09OLnN0cmluZ2lmeShzbmFwc2hvdCwgbnVsbCwgMiksICd1dGYtOCcpO1xuXG4gICAgLy8gQ29weSBjYW5vbmljYWwgTGFtYmRhIGhhbmRsZXIgKE9WRVJXUklURSBlYWNoIHN5bnRoKVxuICAgIGNvbnN0IGhhbmRsZXJEZXN0UGF0aCA9IHBhdGguam9pbihhc3NldERpciwgJ2luZGV4LmpzJyk7XG4gICAgZnMuY29weUZpbGVTeW5jKExBTUJEQV9IQU5ETEVSX1BBVEgsIGhhbmRsZXJEZXN0UGF0aCk7XG5cbiAgICByZXR1cm4gYXNzZXREaXI7XG4gIH1cblxuICAvKipcbiAgICogRGVwbG95IExhbWJkYSBmdW5jdGlvbiBhbmQgY3VzdG9tIHJlc291cmNlIGZvciBpbmdlc3Rpb24uXG4gICAqL1xuICBwcml2YXRlIGRlcGxveUluZ2VzdGlvblJlc291cmNlcyhhc3NldERpcjogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgaGFuZGxlciA9IHRoaXMuY3JlYXRlSW5nZXN0aW9uTGFtYmRhKGFzc2V0RGlyKTtcbiAgICB0aGlzLmNyZWF0ZUN1c3RvbVJlc291cmNlKGhhbmRsZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBMYW1iZGEgZnVuY3Rpb24gZm9yIGluZ2VzdGlvbiB3b3JrZmxvdy5cbiAgICogTGFtYmRhIHJlYWRzIHNuYXBzaG90IGZyb20gaXRzIGJ1bmRsZWQgYXNzZXQgZGlyZWN0b3J5LlxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVJbmdlc3Rpb25MYW1iZGEoYXNzZXREaXI6IHN0cmluZyk6IGxhbWJkYS5GdW5jdGlvbiB7XG4gICAgY29uc3QgaGFuZGxlciA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgJ0luZ2VzdGlvbkhhbmRsZXInLCB7XG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMjBfWCxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJyxcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChhc3NldERpciksXG4gICAgICB0aW1lb3V0OiBjZGsuRHVyYXRpb24ubWludXRlcyg1KSxcbiAgICAgIGVudmlyb25tZW50OiB0aGlzLmJ1aWxkTGFtYmRhRW52aXJvbm1lbnQoKSxcbiAgICB9KTtcblxuICAgIC8vIEdyYW50IENsb3VkV2F0Y2ggTG9ncyBwZXJtaXNzaW9uc1xuICAgIGhhbmRsZXIuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFsnbG9nczpDcmVhdGVMb2dHcm91cCcsICdsb2dzOkNyZWF0ZUxvZ1N0cmVhbScsICdsb2dzOlB1dExvZ0V2ZW50cyddLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgfSlcbiAgICApO1xuXG4gICAgLy8gR3JhbnQgU2VjcmV0cyBNYW5hZ2VyIHBlcm1pc3Npb25zIGlmIHVzaW5nIHNlY3JldHNcbiAgICBjb25zdCB7IGNyZWRlbnRpYWxzIH0gPSB0aGlzLmNvbmZpZztcbiAgICBpZiAoY3JlZGVudGlhbHMuY3JlZGVudGlhbFR5cGUgPT09ICdzZWNyZXRzTWFuYWdlcicgJiYgY3JlZGVudGlhbHMuc2VjcmV0TmFtZSkge1xuICAgICAgaGFuZGxlci5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgYWN0aW9uczogWydzZWNyZXRzbWFuYWdlcjpHZXRTZWNyZXRWYWx1ZSddLFxuICAgICAgICAgIHJlc291cmNlczogW2Bhcm46YXdzOnNlY3JldHNtYW5hZ2VyOio6KjpzZWNyZXQ6JHtjcmVkZW50aWFscy5zZWNyZXROYW1lfSpgXSxcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGhhbmRsZXI7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgTGFtYmRhIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAgICogTm90ZTogU25hcHNob3QgaXMgTk9UIHBhc3NlZCB2aWEgZW52IC0gTGFtYmRhIHJlYWRzIGZyb20gYnVuZGxlZCBhc3NldC5cbiAgICovXG4gIHByaXZhdGUgYnVpbGRMYW1iZGFFbnZpcm9ubWVudCgpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgICAvLyBBbGxvdyBtYWludGFpbmVyIG92ZXJyaWRlIHZpYSBDREsgY29udGV4dCwgb3RoZXJ3aXNlIHVzZSBkZWZhdWx0XG4gICAgY29uc3QgYXBpQmFzZVVybCA9IHRoaXMubm9kZS50cnlHZXRDb250ZXh0KCdjaGFpbUFwaUJhc2VVcmwnKSA/PyBERUZBVUxUX0NIQUlNX0FQSV9CQVNFX1VSTDtcbiAgICBjb25zdCB7IGNyZWRlbnRpYWxzLCBmYWlsdXJlTW9kZSB9ID0gdGhpcy5jb25maWc7XG5cbiAgICBjb25zdCBlbnY6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBBUFBfSUQ6IHRoaXMuY29uZmlnLmFwcElkLFxuICAgICAgRkFJTFVSRV9NT0RFOiBmYWlsdXJlTW9kZSxcbiAgICAgIENIQUlNX0FQSV9CQVNFX1VSTDogYXBpQmFzZVVybCxcbiAgICAgIENIQUlNX01BWF9TTkFQU0hPVF9CWVRFUzogU3RyaW5nKERFRkFVTFRfTUFYX1NOQVBTSE9UX0JZVEVTKSxcbiAgICB9O1xuXG4gICAgaWYgKGNyZWRlbnRpYWxzLmNyZWRlbnRpYWxUeXBlID09PSAnc2VjcmV0c01hbmFnZXInKSB7XG4gICAgICBlbnYuU0VDUkVUX05BTUUgPSBjcmVkZW50aWFscy5zZWNyZXROYW1lITtcbiAgICB9IGVsc2Uge1xuICAgICAgZW52LkFQSV9LRVkgPSBjcmVkZW50aWFscy5hcGlLZXkhO1xuICAgICAgZW52LkFQSV9TRUNSRVQgPSBjcmVkZW50aWFscy5hcGlTZWNyZXQhO1xuICAgIH1cblxuICAgIHJldHVybiBlbnY7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIENsb3VkRm9ybWF0aW9uIGN1c3RvbSByZXNvdXJjZS5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlQ3VzdG9tUmVzb3VyY2UoaGFuZGxlcjogbGFtYmRhLkZ1bmN0aW9uKTogdm9pZCB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBuZXcgY3IuUHJvdmlkZXIodGhpcywgJ0luZ2VzdGlvblByb3ZpZGVyJywge1xuICAgICAgb25FdmVudEhhbmRsZXI6IGhhbmRsZXIsXG4gICAgfSk7XG5cbiAgICAvLyBVc2UgcmVzb3VyY2UgSUQgZm9yIHBoeXNpY2FsIHJlc291cmNlIElEIChzdGFibGUgYWNyb3NzIGRlcGxveXMpXG4gICAgbmV3IGNkay5DdXN0b21SZXNvdXJjZSh0aGlzLCAnSW5nZXN0aW9uUmVzb3VyY2UnLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IHByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgUmVzb3VyY2VJZDogdGhpcy5yZXNvdXJjZUlkLFxuICAgICAgICAvLyBDb250ZW50SGFzaCBpcyBjb21wdXRlZCBhdCBMYW1iZGEgcnVudGltZVxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxufVxuIl19
|