1 | ;
|
2 | var _a;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | exports.AssetStaging = void 0;
|
5 | const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
|
6 | const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
7 | const crypto = require("crypto");
|
8 | const os = require("os");
|
9 | const path = require("path");
|
10 | const cxapi = require("@aws-cdk/cx-api");
|
11 | const fs = require("fs-extra");
|
12 | const assets_1 = require("./assets");
|
13 | const bundling_1 = require("./bundling");
|
14 | const fs_1 = require("./fs");
|
15 | const names_1 = require("./names");
|
16 | const cache_1 = require("./private/cache");
|
17 | const stack_1 = require("./stack");
|
18 | const stage_1 = require("./stage");
|
19 | // v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch.
|
20 | // eslint-disable-next-line
|
21 | const construct_compat_1 = require("./construct-compat");
|
22 | const ARCHIVE_EXTENSIONS = ['.zip', '.jar'];
|
23 | /**
|
24 | * Stages a file or directory from a location on the file system into a staging
|
25 | * directory.
|
26 | *
|
27 | * This is controlled by the context key 'aws:cdk:asset-staging' and enabled
|
28 | * by the CLI by default in order to ensure that when the CDK app exists, all
|
29 | * assets are available for deployment. Otherwise, if an app references assets
|
30 | * in temporary locations, those will not be available when it exists (see
|
31 | * https://github.com/aws/aws-cdk/issues/1716).
|
32 | *
|
33 | * The `stagedPath` property is a stringified token that represents the location
|
34 | * of the file or directory after staging. It will be resolved only during the
|
35 | * "prepare" stage and may be either the original path or the staged path
|
36 | * depending on the context setting.
|
37 | *
|
38 | * The file/directory are staged based on their content hash (fingerprint). This
|
39 | * means that only if content was changed, copy will happen.
|
40 | */
|
41 | class AssetStaging extends construct_compat_1.Construct {
|
42 | constructor(scope, id, props) {
|
43 | super(scope, id);
|
44 | try {
|
45 | jsiiDeprecationWarnings._aws_cdk_core_AssetStagingProps(props);
|
46 | }
|
47 | catch (error) {
|
48 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
49 | Error.captureStackTrace(error, AssetStaging);
|
50 | }
|
51 | throw error;
|
52 | }
|
53 | this.sourcePath = path.resolve(props.sourcePath);
|
54 | this.fingerprintOptions = props;
|
55 | if (!fs.existsSync(this.sourcePath)) {
|
56 | throw new Error(`Cannot find asset at ${this.sourcePath}`);
|
57 | }
|
58 | this.sourceStats = fs.statSync(this.sourcePath);
|
59 | const outdir = stage_1.Stage.of(this)?.assetOutdir;
|
60 | if (!outdir) {
|
61 | throw new Error('unable to determine cloud assembly asset output directory. Assets must be defined indirectly within a "Stage" or an "App" scope');
|
62 | }
|
63 | this.assetOutdir = outdir;
|
64 | // Determine the hash type based on the props as props.assetHashType is
|
65 | // optional from a caller perspective.
|
66 | this.customSourceFingerprint = props.assetHash;
|
67 | this.hashType = determineHashType(props.assetHashType, this.customSourceFingerprint);
|
68 | // Decide what we're going to do, without actually doing it yet
|
69 | let stageThisAsset;
|
70 | let skip = false;
|
71 | if (props.bundling) {
|
72 | // Check if we actually have to bundle for this stack
|
73 | skip = !stack_1.Stack.of(this).bundlingRequired;
|
74 | const bundling = props.bundling;
|
75 | stageThisAsset = () => this.stageByBundling(bundling, skip);
|
76 | }
|
77 | else {
|
78 | stageThisAsset = () => this.stageByCopying();
|
79 | }
|
80 | // Calculate a cache key from the props. This way we can check if we already
|
81 | // staged this asset and reuse the result (e.g. the same asset with the same
|
82 | // configuration is used in multiple stacks). In this case we can completely
|
83 | // skip file system and bundling operations.
|
84 | //
|
85 | // The output directory and whether this asset is skipped or not should also be
|
86 | // part of the cache key to make sure we don't accidentally return the wrong
|
87 | // staged asset from the cache.
|
88 | this.cacheKey = calculateCacheKey({
|
89 | outdir: this.assetOutdir,
|
90 | sourcePath: path.resolve(props.sourcePath),
|
91 | bundling: props.bundling,
|
92 | assetHashType: this.hashType,
|
93 | customFingerprint: this.customSourceFingerprint,
|
94 | extraHash: props.extraHash,
|
95 | exclude: props.exclude,
|
96 | ignoreMode: props.ignoreMode,
|
97 | skip,
|
98 | });
|
99 | const staged = AssetStaging.assetCache.obtain(this.cacheKey, stageThisAsset);
|
100 | this.stagedPath = staged.stagedPath;
|
101 | this.absoluteStagedPath = staged.stagedPath;
|
102 | this.assetHash = staged.assetHash;
|
103 | this.packaging = staged.packaging;
|
104 | this.isArchive = staged.isArchive;
|
105 | }
|
106 | /**
|
107 | * Clears the asset hash cache
|
108 | */
|
109 | static clearAssetHashCache() {
|
110 | this.assetCache.clear();
|
111 | }
|
112 | /**
|
113 | * A cryptographic hash of the asset.
|
114 | *
|
115 | * @deprecated see `assetHash`.
|
116 | */
|
117 | get sourceHash() {
|
118 | try {
|
119 | jsiiDeprecationWarnings.print("@aws-cdk/core.AssetStaging#sourceHash", "see `assetHash`.");
|
120 | }
|
121 | catch (error) {
|
122 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
123 | Error.captureStackTrace(error, jsiiDeprecationWarnings.getPropertyDescriptor(this, "sourceHash").get);
|
124 | }
|
125 | throw error;
|
126 | }
|
127 | return this.assetHash;
|
128 | }
|
129 | /**
|
130 | * Return the path to the staged asset, relative to the Cloud Assembly (manifest) directory of the given stack
|
131 | *
|
132 | * Only returns a relative path if the asset was staged, returns an absolute path if
|
133 | * it was not staged.
|
134 | *
|
135 | * A bundled asset might end up in the outDir and still not count as
|
136 | * "staged"; if asset staging is disabled we're technically expected to
|
137 | * reference source directories, but we don't have a source directory for the
|
138 | * bundled outputs (as the bundle output is written to a temporary
|
139 | * directory). Nevertheless, we will still return an absolute path.
|
140 | *
|
141 | * A non-obvious directory layout may look like this:
|
142 | *
|
143 | * ```
|
144 | * CLOUD ASSEMBLY ROOT
|
145 | * +-- asset.12345abcdef/
|
146 | * +-- assembly-Stage
|
147 | * +-- MyStack.template.json
|
148 | * +-- MyStack.assets.json <- will contain { "path": "../asset.12345abcdef" }
|
149 | * ```
|
150 | */
|
151 | relativeStagedPath(stack) {
|
152 | try {
|
153 | jsiiDeprecationWarnings._aws_cdk_core_Stack(stack);
|
154 | }
|
155 | catch (error) {
|
156 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
157 | Error.captureStackTrace(error, this.relativeStagedPath);
|
158 | }
|
159 | throw error;
|
160 | }
|
161 | const asmManifestDir = stage_1.Stage.of(stack)?.outdir;
|
162 | if (!asmManifestDir) {
|
163 | return this.stagedPath;
|
164 | }
|
165 | const isOutsideAssetDir = path.relative(this.assetOutdir, this.stagedPath).startsWith('..');
|
166 | if (isOutsideAssetDir || this.stagingDisabled) {
|
167 | return this.stagedPath;
|
168 | }
|
169 | return path.relative(asmManifestDir, this.stagedPath);
|
170 | }
|
171 | /**
|
172 | * Stage the source to the target by copying
|
173 | *
|
174 | * Optionally skip if staging is disabled, in which case we pretend we did something but we don't really.
|
175 | */
|
176 | stageByCopying() {
|
177 | const assetHash = this.calculateHash(this.hashType);
|
178 | const stagedPath = this.stagingDisabled
|
179 | ? this.sourcePath
|
180 | : path.resolve(this.assetOutdir, renderAssetFilename(assetHash, path.extname(this.sourcePath)));
|
181 | if (!this.sourceStats.isDirectory() && !this.sourceStats.isFile()) {
|
182 | throw new Error(`Asset ${this.sourcePath} is expected to be either a directory or a regular file`);
|
183 | }
|
184 | this.stageAsset(this.sourcePath, stagedPath, 'copy');
|
185 | return {
|
186 | assetHash,
|
187 | stagedPath,
|
188 | packaging: this.sourceStats.isDirectory() ? assets_1.FileAssetPackaging.ZIP_DIRECTORY : assets_1.FileAssetPackaging.FILE,
|
189 | isArchive: this.sourceStats.isDirectory() || ARCHIVE_EXTENSIONS.includes(path.extname(this.sourcePath).toLowerCase()),
|
190 | };
|
191 | }
|
192 | /**
|
193 | * Stage the source to the target by bundling
|
194 | *
|
195 | * Optionally skip, in which case we pretend we did something but we don't really.
|
196 | */
|
197 | stageByBundling(bundling, skip) {
|
198 | if (!this.sourceStats.isDirectory()) {
|
199 | throw new Error(`Asset ${this.sourcePath} is expected to be a directory when bundling`);
|
200 | }
|
201 | if (skip) {
|
202 | // We should have bundled, but didn't to save time. Still pretend to have a hash.
|
203 | // If the asset uses OUTPUT or BUNDLE, we use a CUSTOM hash to avoid fingerprinting
|
204 | // a potentially very large source directory. Other hash types are kept the same.
|
205 | let hashType = this.hashType;
|
206 | if (hashType === assets_1.AssetHashType.OUTPUT || hashType === assets_1.AssetHashType.BUNDLE) {
|
207 | this.customSourceFingerprint = names_1.Names.uniqueId(this);
|
208 | hashType = assets_1.AssetHashType.CUSTOM;
|
209 | }
|
210 | return {
|
211 | assetHash: this.calculateHash(hashType, bundling),
|
212 | stagedPath: this.sourcePath,
|
213 | packaging: assets_1.FileAssetPackaging.ZIP_DIRECTORY,
|
214 | isArchive: true,
|
215 | };
|
216 | }
|
217 | // Try to calculate assetHash beforehand (if we can)
|
218 | let assetHash = this.hashType === assets_1.AssetHashType.SOURCE || this.hashType === assets_1.AssetHashType.CUSTOM
|
219 | ? this.calculateHash(this.hashType, bundling)
|
220 | : undefined;
|
221 | const bundleDir = this.determineBundleDir(this.assetOutdir, assetHash);
|
222 | this.bundle(bundling, bundleDir);
|
223 | // Check bundling output content and determine if we will need to archive
|
224 | const bundlingOutputType = bundling.outputType ?? bundling_1.BundlingOutput.AUTO_DISCOVER;
|
225 | const bundledAsset = determineBundledAsset(bundleDir, bundlingOutputType);
|
226 | // Calculate assetHash afterwards if we still must
|
227 | assetHash = assetHash ?? this.calculateHash(this.hashType, bundling, bundledAsset.path);
|
228 | const stagedPath = path.resolve(this.assetOutdir, renderAssetFilename(assetHash, bundledAsset.extension));
|
229 | this.stageAsset(bundledAsset.path, stagedPath, 'move');
|
230 | // If bundling produced a single archive file we "touch" this file in the bundling
|
231 | // directory after it has been moved to the staging directory. This way if bundling
|
232 | // is skipped because the bundling directory already exists we can still determine
|
233 | // the correct packaging type.
|
234 | if (bundledAsset.packaging === assets_1.FileAssetPackaging.FILE) {
|
235 | fs.closeSync(fs.openSync(bundledAsset.path, 'w'));
|
236 | }
|
237 | return {
|
238 | assetHash,
|
239 | stagedPath,
|
240 | packaging: bundledAsset.packaging,
|
241 | isArchive: true,
|
242 | };
|
243 | }
|
244 | /**
|
245 | * Whether staging has been disabled
|
246 | */
|
247 | get stagingDisabled() {
|
248 | return !!this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
|
249 | }
|
250 | /**
|
251 | * Copies or moves the files from sourcePath to targetPath.
|
252 | *
|
253 | * Moving implies the source directory is temporary and can be trashed.
|
254 | *
|
255 | * Will not do anything if source and target are the same.
|
256 | */
|
257 | stageAsset(sourcePath, targetPath, style) {
|
258 | // Is the work already done?
|
259 | const isAlreadyStaged = fs.existsSync(targetPath);
|
260 | if (isAlreadyStaged) {
|
261 | if (style === 'move' && sourcePath !== targetPath) {
|
262 | fs.removeSync(sourcePath);
|
263 | }
|
264 | return;
|
265 | }
|
266 | // Moving can be done quickly
|
267 | if (style == 'move') {
|
268 | fs.renameSync(sourcePath, targetPath);
|
269 | return;
|
270 | }
|
271 | // Copy file/directory to staging directory
|
272 | if (this.sourceStats.isFile()) {
|
273 | fs.copyFileSync(sourcePath, targetPath);
|
274 | }
|
275 | else if (this.sourceStats.isDirectory()) {
|
276 | fs.mkdirSync(targetPath);
|
277 | fs_1.FileSystem.copyDirectory(sourcePath, targetPath, this.fingerprintOptions);
|
278 | }
|
279 | else {
|
280 | throw new Error(`Unknown file type: ${sourcePath}`);
|
281 | }
|
282 | }
|
283 | /**
|
284 | * Determine the directory where we're going to write the bundling output
|
285 | *
|
286 | * This is the target directory where we're going to write the staged output
|
287 | * files if we can (if the hash is fully known), or a temporary directory
|
288 | * otherwise.
|
289 | */
|
290 | determineBundleDir(outdir, sourceHash) {
|
291 | if (sourceHash) {
|
292 | return path.resolve(outdir, renderAssetFilename(sourceHash));
|
293 | }
|
294 | // When the asset hash isn't known in advance, bundler outputs to an
|
295 | // intermediate directory named after the asset's cache key
|
296 | return path.resolve(outdir, `bundling-temp-${this.cacheKey}`);
|
297 | }
|
298 | /**
|
299 | * Bundles an asset to the given directory
|
300 | *
|
301 | * If the given directory already exists, assume that everything's already
|
302 | * in order and don't do anything.
|
303 | *
|
304 | * @param options Bundling options
|
305 | * @param bundleDir Where to create the bundle directory
|
306 | * @returns The fully resolved bundle output directory.
|
307 | */
|
308 | bundle(options, bundleDir) {
|
309 | if (fs.existsSync(bundleDir)) {
|
310 | return;
|
311 | }
|
312 | fs.ensureDirSync(bundleDir);
|
313 | // Chmod the bundleDir to full access.
|
314 | fs.chmodSync(bundleDir, 0o777);
|
315 | // Always mount input and output dir
|
316 | const volumes = [
|
317 | {
|
318 | hostPath: this.sourcePath,
|
319 | containerPath: AssetStaging.BUNDLING_INPUT_DIR,
|
320 | },
|
321 | {
|
322 | hostPath: bundleDir,
|
323 | containerPath: AssetStaging.BUNDLING_OUTPUT_DIR,
|
324 | },
|
325 | ...options.volumes ?? [],
|
326 | ];
|
327 | let localBundling;
|
328 | try {
|
329 | process.stderr.write(`Bundling asset ${this.node.path}...\n`);
|
330 | localBundling = options.local?.tryBundle(bundleDir, options);
|
331 | if (!localBundling) {
|
332 | let user;
|
333 | if (options.user) {
|
334 | user = options.user;
|
335 | }
|
336 | else { // Default to current user
|
337 | const userInfo = os.userInfo();
|
338 | user = userInfo.uid !== -1 // uid is -1 on Windows
|
339 | ? `${userInfo.uid}:${userInfo.gid}`
|
340 | : '1000:1000';
|
341 | }
|
342 | options.image.run({
|
343 | command: options.command,
|
344 | user,
|
345 | volumes,
|
346 | environment: options.environment,
|
347 | workingDirectory: options.workingDirectory ?? AssetStaging.BUNDLING_INPUT_DIR,
|
348 | securityOpt: options.securityOpt ?? '',
|
349 | });
|
350 | }
|
351 | }
|
352 | catch (err) {
|
353 | // When bundling fails, keep the bundle output for diagnosability, but
|
354 | // rename it out of the way so that the next run doesn't assume it has a
|
355 | // valid bundleDir.
|
356 | const bundleErrorDir = bundleDir + '-error';
|
357 | if (fs.existsSync(bundleErrorDir)) {
|
358 | // Remove the last bundleErrorDir.
|
359 | fs.removeSync(bundleErrorDir);
|
360 | }
|
361 | fs.renameSync(bundleDir, bundleErrorDir);
|
362 | throw new Error(`Failed to bundle asset ${this.node.path}, bundle output is located at ${bundleErrorDir}: ${err}`);
|
363 | }
|
364 | if (fs_1.FileSystem.isEmpty(bundleDir)) {
|
365 | const outputDir = localBundling ? bundleDir : AssetStaging.BUNDLING_OUTPUT_DIR;
|
366 | throw new Error(`Bundling did not produce any output. Check that content is written to ${outputDir}.`);
|
367 | }
|
368 | }
|
369 | calculateHash(hashType, bundling, outputDir) {
|
370 | // When bundling a CUSTOM or SOURCE asset hash type, we want the hash to include
|
371 | // the bundling configuration. We handle CUSTOM and bundled SOURCE hash types
|
372 | // as a special case to preserve existing user asset hashes in all other cases.
|
373 | if (hashType == assets_1.AssetHashType.CUSTOM || (hashType == assets_1.AssetHashType.SOURCE && bundling)) {
|
374 | const hash = crypto.createHash('sha256');
|
375 | // if asset hash is provided by user, use it, otherwise fingerprint the source.
|
376 | hash.update(this.customSourceFingerprint ?? fs_1.FileSystem.fingerprint(this.sourcePath, this.fingerprintOptions));
|
377 | // If we're bundling an asset, include the bundling configuration in the hash
|
378 | if (bundling) {
|
379 | hash.update(JSON.stringify(bundling));
|
380 | }
|
381 | return hash.digest('hex');
|
382 | }
|
383 | switch (hashType) {
|
384 | case assets_1.AssetHashType.SOURCE:
|
385 | return fs_1.FileSystem.fingerprint(this.sourcePath, this.fingerprintOptions);
|
386 | case assets_1.AssetHashType.BUNDLE:
|
387 | case assets_1.AssetHashType.OUTPUT:
|
388 | if (!outputDir) {
|
389 | throw new Error(`Cannot use \`${hashType}\` hash type when \`bundling\` is not specified.`);
|
390 | }
|
391 | return fs_1.FileSystem.fingerprint(outputDir, this.fingerprintOptions);
|
392 | default:
|
393 | throw new Error('Unknown asset hash type.');
|
394 | }
|
395 | }
|
396 | }
|
397 | exports.AssetStaging = AssetStaging;
|
398 | _a = JSII_RTTI_SYMBOL_1;
|
399 | AssetStaging[_a] = { fqn: "@aws-cdk/core.AssetStaging", version: "1.204.0" };
|
400 | /**
|
401 | * The directory inside the bundling container into which the asset sources will be mounted.
|
402 | */
|
403 | AssetStaging.BUNDLING_INPUT_DIR = '/asset-input';
|
404 | /**
|
405 | * The directory inside the bundling container into which the bundled output should be written.
|
406 | */
|
407 | AssetStaging.BUNDLING_OUTPUT_DIR = '/asset-output';
|
408 | /**
|
409 | * Cache of asset hashes based on asset configuration to avoid repeated file
|
410 | * system and bundling operations.
|
411 | */
|
412 | AssetStaging.assetCache = new cache_1.Cache();
|
413 | function renderAssetFilename(assetHash, extension = '') {
|
414 | return `asset.${assetHash}${extension}`;
|
415 | }
|
416 | /**
|
417 | * Determines the hash type from user-given prop values.
|
418 | *
|
419 | * @param assetHashType Asset hash type construct prop
|
420 | * @param customSourceFingerprint Asset hash seed given in the construct props
|
421 | */
|
422 | function determineHashType(assetHashType, customSourceFingerprint) {
|
423 | const hashType = customSourceFingerprint
|
424 | ? (assetHashType ?? assets_1.AssetHashType.CUSTOM)
|
425 | : (assetHashType ?? assets_1.AssetHashType.SOURCE);
|
426 | if (customSourceFingerprint && hashType !== assets_1.AssetHashType.CUSTOM) {
|
427 | throw new Error(`Cannot specify \`${assetHashType}\` for \`assetHashType\` when \`assetHash\` is specified. Use \`CUSTOM\` or leave \`undefined\`.`);
|
428 | }
|
429 | if (hashType === assets_1.AssetHashType.CUSTOM && !customSourceFingerprint) {
|
430 | throw new Error('`assetHash` must be specified when `assetHashType` is set to `AssetHashType.CUSTOM`.');
|
431 | }
|
432 | return hashType;
|
433 | }
|
434 | /**
|
435 | * Calculates a cache key from the props. Normalize by sorting keys.
|
436 | */
|
437 | function calculateCacheKey(props) {
|
438 | return crypto.createHash('sha256')
|
439 | .update(JSON.stringify(sortObject(props)))
|
440 | .digest('hex');
|
441 | }
|
442 | /**
|
443 | * Recursively sort object keys
|
444 | */
|
445 | function sortObject(object) {
|
446 | if (typeof object !== 'object' || object instanceof Array) {
|
447 | return object;
|
448 | }
|
449 | const ret = {};
|
450 | for (const key of Object.keys(object).sort()) {
|
451 | ret[key] = sortObject(object[key]);
|
452 | }
|
453 | return ret;
|
454 | }
|
455 | /**
|
456 | * Returns the single archive file of a directory or undefined
|
457 | */
|
458 | function singleArchiveFile(directory) {
|
459 | if (!fs.existsSync(directory)) {
|
460 | throw new Error(`Directory ${directory} does not exist.`);
|
461 | }
|
462 | if (!fs.statSync(directory).isDirectory()) {
|
463 | throw new Error(`${directory} is not a directory.`);
|
464 | }
|
465 | const content = fs.readdirSync(directory);
|
466 | if (content.length === 1) {
|
467 | const file = path.join(directory, content[0]);
|
468 | const extension = path.extname(content[0]).toLowerCase();
|
469 | if (fs.statSync(file).isFile() && ARCHIVE_EXTENSIONS.includes(extension)) {
|
470 | return file;
|
471 | }
|
472 | }
|
473 | return undefined;
|
474 | }
|
475 | /**
|
476 | * Returns the bundled asset to use based on the content of the bundle directory
|
477 | * and the type of output.
|
478 | */
|
479 | function determineBundledAsset(bundleDir, outputType) {
|
480 | const archiveFile = singleArchiveFile(bundleDir);
|
481 | // auto-discover means that if there is an archive file, we take it as the
|
482 | // bundle, otherwise, we will archive here.
|
483 | if (outputType === bundling_1.BundlingOutput.AUTO_DISCOVER) {
|
484 | outputType = archiveFile ? bundling_1.BundlingOutput.ARCHIVED : bundling_1.BundlingOutput.NOT_ARCHIVED;
|
485 | }
|
486 | switch (outputType) {
|
487 | case bundling_1.BundlingOutput.NOT_ARCHIVED:
|
488 | return { path: bundleDir, packaging: assets_1.FileAssetPackaging.ZIP_DIRECTORY };
|
489 | case bundling_1.BundlingOutput.ARCHIVED:
|
490 | if (!archiveFile) {
|
491 | throw new Error('Bundling output directory is expected to include only a single .zip or .jar file when `output` is set to `ARCHIVED`');
|
492 | }
|
493 | return { path: archiveFile, packaging: assets_1.FileAssetPackaging.FILE, extension: path.extname(archiveFile) };
|
494 | }
|
495 | }
|
496 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXQtc3RhZ2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImFzc2V0LXN0YWdpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IseUNBQXlDO0FBRXpDLCtCQUErQjtBQUMvQixxQ0FBMkU7QUFDM0UseUNBQTZEO0FBQzdELDZCQUFzRDtBQUN0RCxtQ0FBZ0M7QUFDaEMsMkNBQXdDO0FBQ3hDLG1DQUFnQztBQUNoQyxtQ0FBZ0M7QUFFaEMsZ0hBQWdIO0FBQ2hILDJCQUEyQjtBQUMzQix5REFBZ0U7QUFFaEUsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztBQXFDNUM7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBQ0gsTUFBYSxZQUFhLFNBQVEsNEJBQWE7SUF3RjdDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBd0I7UUFDaEUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQzs7Ozs7OytDQXpGUixZQUFZOzs7O1FBMkZyQixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxLQUFLLENBQUM7UUFFaEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFO1lBQ25DLE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO1NBQzVEO1FBRUQsSUFBSSxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUVoRCxNQUFNLE1BQU0sR0FBRyxhQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLFdBQVcsQ0FBQztRQUMzQyxJ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WyJpbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCAqIGFzIG9zIGZyb20gJ29zJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjeGFwaSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgeyBBc3NldEhhc2hUeXBlLCBBc3NldE9wdGlvbnMsIEZpbGVBc3NldFBhY2thZ2luZyB9IGZyb20gJy4vYXNzZXRzJztcbmltcG9ydCB7IEJ1bmRsaW5nT3B0aW9ucywgQnVuZGxpbmdPdXRwdXQgfSBmcm9tICcuL2J1bmRsaW5nJztcbmltcG9ydCB7IEZpbGVTeXN0ZW0sIEZpbmdlcnByaW50T3B0aW9ucyB9IGZyb20gJy4vZnMnO1xuaW1wb3J0IHsgTmFtZXMgfSBmcm9tICcuL25hbWVzJztcbmltcG9ydCB7IENhY2hlIH0gZnJvbSAnLi9wcml2YXRlL2NhY2hlJztcbmltcG9ydCB7IFN0YWNrIH0gZnJvbSAnLi9zdGFjayc7XG5pbXBvcnQgeyBTdGFnZSB9IGZyb20gJy4vc3RhZ2UnO1xuXG4vLyB2MiAtIGtlZXAgdGhpcyBpbXBvcnQgYXMgYSBzZXBhcmF0ZSBzZWN0aW9uIHRvIHJlZHVjZSBtZXJnZSBjb25mbGljdCB3aGVuIGZvcndhcmQgbWVyZ2luZyB3aXRoIHRoZSB2MiBicmFuY2guXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcbmltcG9ydCB7IENvbnN0cnVjdCBhcyBDb3JlQ29uc3RydWN0IH0gZnJvbSAnLi9jb25zdHJ1Y3QtY29tcGF0JztcblxuY29uc3QgQVJDSElWRV9FWFRFTlNJT05TID0gWycuemlwJywgJy5qYXInXTtcblxuLyoqXG4gKiBBIHByZXZpb3VzbHkgc3RhZ2VkIGFzc2V0XG4gKi9cbmludGVyZmFjZSBTdGFnZWRBc3NldCB7XG4gIC8qKlxuICAgKiBUaGUgcGF0aCB3aGVyZSB3ZSB3cm90ZSB0aGlzIGFzc2V0IHByZXZpb3VzbHlcbiAgICovXG4gIHJlYWRvbmx5IHN0YWdlZFBhdGg6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGhhc2ggd2UgdXNlZCBwcmV2aW91c2x5XG4gICAqL1xuICByZWFkb25seSBhc3NldEhhc2g6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHBhY2thZ2luZyBvZiB0aGUgYXNzZXRcbiAgICovXG4gIHJlYWRvbmx5IHBhY2thZ2luZzogRmlsZUFzc2V0UGFja2FnaW5nLFxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgYXNzZXQgaXMgYW4gYXJjaGl2ZVxuICAgKi9cbiAgcmVhZG9ubHkgaXNBcmNoaXZlOiBib29sZWFuO1xufVxuXG4vKipcbiAqIEluaXRpYWxpemF0aW9uIHByb3BlcnRpZXMgZm9yIGBBc3NldFN0YWdpbmdgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEFzc2V0U3RhZ2luZ1Byb3BzIGV4dGVuZHMgRmluZ2VycHJpbnRPcHRpb25zLCBBc3NldE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIHNvdXJjZSBmaWxlIG9yIGRpcmVjdG9yeSB0byBjb3B5IGZyb20uXG4gICAqL1xuICByZWFkb25seSBzb3VyY2VQYXRoOiBzdHJpbmc7XG59XG5cbi8qKlxuICogU3RhZ2VzIGEgZmlsZSBvciBkaXJlY3RvcnkgZnJvbSBhIGxvY2F0aW9uIG9uIHRoZSBmaWxlIHN5c3RlbSBpbnRvIGEgc3RhZ2luZ1xuICogZGlyZWN0b3J5LlxuICpcbiAqIFRoaXMgaXMgY29udHJvbGxlZCBieSB0aGUgY29udGV4dCBrZXkgJ2F3czpjZGs6YXNzZXQtc3RhZ2luZycgYW5kIGVuYWJsZWRcbiAqIGJ5IHRoZSBDTEkgYnkgZGVmYXVsdCBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCB3aGVuIHRoZSBDREsgYXBwIGV4aXN0cywgYWxsXG4gKiBhc3NldHMgYXJlIGF2YWlsYWJsZSBmb3IgZGVwbG95bWVudC4gT3RoZXJ3aXNlLCBpZiBhbiBhcHAgcmVmZXJlbmNlcyBhc3NldHNcbiAqIGluIHRlbXBvcmFyeSBsb2NhdGlvbnMsIHRob3NlIHdpbGwgbm90IGJlIGF2YWlsYWJsZSB3aGVuIGl0IGV4aXN0cyAoc2VlXG4gKiBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzE3MTYpLlxuICpcbiAqIFRoZSBgc3RhZ2VkUGF0aGAgcHJvcGVydHkgaXMgYSBzdHJpbmdpZmllZCB0b2tlbiB0aGF0IHJlcHJlc2VudHMgdGhlIGxvY2F0aW9uXG4gKiBvZiB0aGUgZmlsZSBvciBkaXJlY3RvcnkgYWZ0ZXIgc3RhZ2luZy4gSXQgd2lsbCBiZSByZXNvbHZlZCBvbmx5IGR1cmluZyB0aGVcbiAqIFwicHJlcGFyZVwiIHN0YWdlIGFuZCBtYXkgYmUgZWl0aGVyIHRoZSBvcmlnaW5hbCBwYXRoIG9yIHRoZSBzdGFnZWQgcGF0aFxuICogZGVwZW5kaW5nIG9uIHRoZSBjb250ZXh0IHNldHRpbmcuXG4gKlxuICogVGhlIGZpbGUvZGlyZWN0b3J5IGFyZSBzdGFnZWQgYmFzZWQgb24gdGhlaXIgY29udGVudCBoYXNoIChmaW5nZXJwcmludCkuIFRoaXNcbiAqIG1lYW5zIHRoYXQgb25seSBpZiBjb250ZW50IHdhcyBjaGFuZ2VkLCBjb3B5IHdpbGwgaGFwcGVuLlxuICovXG5leHBvcnQgY2xhc3MgQXNzZXRTdGFnaW5nIGV4dGVuZHMgQ29yZUNvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBUaGUgZGlyZWN0b3J5IGluc2lkZSB0aGUgYnVuZGxpbmcgY29udGFpbmVyIGludG8gd2hpY2ggdGhlIGFzc2V0IHNvdXJjZXMgd2lsbCBiZSBtb3VudGVkLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBCVU5ETElOR19JTlBVVF9ESVIgPSAnL2Fzc2V0LWlucHV0JztcblxuICAvKipcbiAgICogVGhlIGRpcmVjdG9yeSBpbnNpZGUgdGhlIGJ1bmRsaW5nIGNvbnRhaW5lciBpbnRvIHdoaWNoIHRoZSBidW5kbGVkIG91dHB1dCBzaG91bGQgYmUgd3JpdHRlbi5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQlVORExJTkdfT1VUUFVUX0RJUiA9ICcvYXNzZXQtb3V0cHV0JztcblxuICAvKipcbiAgICogQ2xlYXJzIHRoZSBhc3NldCBoYXNoIGNhY2hlXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNsZWFyQXNzZXRIYXNoQ2FjaGUoKSB7XG4gICAgdGhpcy5hc3NldENhY2hlLmNsZWFyKCk7XG4gIH1cblxuICAvKipcbiAgICogQ2FjaGUgb2YgYXNzZXQgaGFzaGVzIGJhc2VkIG9uIGFzc2V0IGNvbmZpZ3VyYXRpb24gdG8gYXZvaWQgcmVwZWF0ZWQgZmlsZVxuICAgKiBzeXN0ZW0gYW5kIGJ1bmRsaW5nIG9wZXJhdGlvbnMuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBhc3NldENhY2hlID0gbmV3IENhY2hlPFN0YWdlZEFzc2V0PigpO1xuXG4gIC8qKlxuICAgKiBBYnNvbHV0ZSBwYXRoIHRvIHRoZSBhc3NldCBkYXRhLlxuICAgKlxuICAgKiBJZiBhc3NldCBzdGFnaW5nIGlzIGRpc2FibGVkLCB0aGlzIHdpbGwganVzdCBiZSB0aGUgc291cmNlIHBhdGggb3JcbiAgICogYSB0ZW1wb3JhcnkgZGlyZWN0b3J5IHVzZWQgZm9yIGJ1bmRsaW5nLlxuICAgKlxuICAgKiBJZiBhc3NldCBzdGFnaW5nIGlzIGVuYWJsZWQgaXQgd2lsbCBiZSB0aGUgc3RhZ2VkIHBhdGguXG4gICAqXG4gICAqIElNUE9SVEFOVDogSWYgeW91IGFyZSBnb2luZyB0byBjYWxsIGBhZGRGaWxlQXNzZXQoKWAsIHVzZVxuICAgKiBgcmVsYXRpdmVTdGFnZWRQYXRoKClgIGluc3RlYWQuXG4gICAqXG4gICAqIEBkZXByZWNhdGVkIC0gVXNlIGBhYnNvbHV0ZVN0YWdlZFBhdGhgIGluc3RlYWQuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgc3RhZ2VkUGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBYnNvbHV0ZSBwYXRoIHRvIHRoZSBhc3NldCBkYXRhLlxuICAgKlxuICAgKiBJZiBhc3NldCBzdGFnaW5nIGlzIGRpc2FibGVkLCB0aGlzIHdpbGwganVzdCBiZSB0aGUgc291cmNlIHBhdGggb3JcbiAgICogYSB0ZW1wb3JhcnkgZGlyZWN0b3J5IHVzZWQgZm9yIGJ1bmRsaW5nLlxuICAgKlxuICAgKiBJZiBhc3NldCBzdGFnaW5nIGlzIGVuYWJsZWQgaXQgd2lsbCBiZSB0aGUgc3RhZ2VkIHBhdGguXG4gICAqXG4gICAqIElNUE9SVEFOVDogSWYgeW91IGFyZSBnb2luZyB0byBjYWxsIGBhZGRGaWxlQXNzZXQoKWAsIHVzZVxuICAgKiBgcmVsYXRpdmVTdGFnZWRQYXRoKClgIGluc3RlYWQuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYWJzb2x1dGVTdGFnZWRQYXRoOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBhYnNvbHV0ZSBwYXRoIG9mIHRoZSBhc3NldCBhcyBpdCB3YXMgcmVmZXJlbmNlZCBieSB0aGUgdXNlci5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBzb3VyY2VQYXRoOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEEgY3J5cHRvZ3JhcGhpYyBoYXNoIG9mIHRoZSBhc3NldC5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhc3NldEhhc2g6IHN0cmluZztcblxuICAvKipcbiAgICogSG93IHRoaXMgYXNzZXQgc2hvdWxkIGJlIHBhY2thZ2VkLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBhY2thZ2luZzogRmlsZUFzc2V0UGFja2FnaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgYXNzZXQgaXMgYW4gYXJjaGl2ZSAoemlwIG9yIGphcikuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaXNBcmNoaXZlOiBib29sZWFuO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZmluZ2VycHJpbnRPcHRpb25zOiBGaW5nZXJwcmludE9wdGlvbnM7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBoYXNoVHlwZTogQXNzZXRIYXNoVHlwZTtcbiAgcHJpdmF0ZSByZWFkb25seSBhc3NldE91dGRpcjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIGN1c3RvbSBzb3VyY2UgZmluZ2VycHJpbnQgZ2l2ZW4gYnkgdGhlIHVzZXJcbiAgICpcbiAgICogV2lsbCBub3QgYmUgdXNlZCBsaXRlcmFsbHksIGFsd2F5cyBoYXNoZWQgbGF0ZXIgb24uXG4gICAqL1xuICBwcml2YXRlIGN1c3RvbVNvdXJjZUZpbmdlcnByaW50Pzogc3RyaW5nO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgY2FjaGVLZXk6IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IHNvdXJjZVN0YXRzOiBmcy5TdGF0cztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogQXNzZXRTdGFnaW5nUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5zb3VyY2VQYXRoID0gcGF0aC5yZXNvbHZlKHByb3BzLnNvdXJjZVBhdGgpO1xuICAgIHRoaXMuZmluZ2VycHJpbnRPcHRpb25zID0gcHJvcHM7XG5cbiAgICBpZiAoIWZzLmV4aXN0c1N5bmModGhpcy5zb3VyY2VQYXRoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgZmluZCBhc3NldCBhdCAke3RoaXMuc291cmNlUGF0aH1gKTtcbiAgICB9XG5cbiAgICB0aGlzLnNvdXJjZVN0YXRzID0gZnMuc3RhdFN5bmModGhpcy5zb3VyY2VQYXRoKTtcblxuICAgIGNvbnN0IG91dGRpciA9IFN0YWdlLm9mKHRoaXMpPy5hc3NldE91dGRpcjtcbiAgICBpZiAoIW91dGRpcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmFibGUgdG8gZGV0ZXJtaW5lIGNsb3VkIGFzc2VtYmx5IGFzc2V0IG91dHB1dCBkaXJlY3RvcnkuIEFzc2V0cyBtdXN0IGJlIGRlZmluZWQgaW5kaXJlY3RseSB3aXRoaW4gYSBcIlN0YWdlXCIgb3IgYW4gXCJBcHBcIiBzY29wZScpO1xuICAgIH1cbiAgICB0aGlzLmFzc2V0T3V0ZGlyID0gb3V0ZGlyO1xuXG4gICAgLy8gRGV0ZXJtaW5lIHRoZSBoYXNoIHR5cGUgYmFzZWQgb24gdGhlIHByb3BzIGFzIHByb3BzLmFzc2V0SGFzaFR5cGUgaXNcbiAgICAvLyBvcHRpb25hbCBmcm9tIGEgY2FsbGVyIHBlcnNwZWN0aXZlLlxuICAgIHRoaXMuY3VzdG9tU291cmNlRmluZ2VycHJpbnQgPSBwcm9wcy5hc3NldEhhc2g7XG4gICAgdGhpcy5oYXNoVHlwZSA9IGRldGVybWluZUhhc2hUeXBlKHByb3BzLmFzc2V0SGFzaFR5cGUsIHRoaXMuY3VzdG9tU291cmNlRmluZ2VycHJpbnQpO1xuXG4gICAgLy8gRGVjaWRlIHdoYXQgd2UncmUgZ29pbmcgdG8gZG8sIHdpdGhvdXQgYWN0dWFsbHkgZG9pbmcgaXQgeWV0XG4gICAgbGV0IHN0YWdlVGhpc0Fzc2V0OiAoKSA9PiBTdGFnZWRBc3NldDtcbiAgICBsZXQgc2tpcCA9IGZhbHNlO1xuICAgIGlmIChwcm9wcy5idW5kbGluZykge1xuICAgICAgLy8gQ2hlY2sgaWYgd2UgYWN0dWFsbHkgaGF2ZSB0byBidW5kbGUgZm9yIHRoaXMgc3RhY2tcbiAgICAgIHNraXAgPSAhU3RhY2sub2YodGhpcykuYnVuZGxpbmdSZXF1aXJlZDtcbiAgICAgIGNvbnN0IGJ1bmRsaW5nID0gcHJvcHMuYnVuZGxpbmc7XG4gICAgICBzdGFnZVRoaXNBc3NldCA9ICgpID0+IHRoaXMuc3RhZ2VCeUJ1bmRsaW5nKGJ1bmRsaW5nLCBza2lwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3RhZ2VUaGlzQXNzZXQgPSAoKSA9PiB0aGlzLnN0YWdlQnlDb3B5aW5nKCk7XG4gICAgfVxuXG4gICAgLy8gQ2FsY3VsYXRlIGEgY2FjaGUga2V5IGZyb20gdGhlIHByb3BzLiBUaGlzIHdheSB3ZSBjYW4gY2hlY2sgaWYgd2UgYWxyZWFkeVxuICAgIC8vIHN0YWdlZCB0aGlzIGFzc2V0IGFuZCByZXVzZSB0aGUgcmVzdWx0IChlLmcuIHRoZSBzYW1lIGFzc2V0IHdpdGggdGhlIHNhbWVcbiAgICAvLyBjb25maWd1cmF0aW9uIGlzIHVzZWQgaW4gbXVsdGlwbGUgc3RhY2tzKS4gSW4gdGhpcyBjYXNlIHdlIGNhbiBjb21wbGV0ZWx5XG4gICAgLy8gc2tpcCBmaWxlIHN5c3RlbSBhbmQgYnVuZGxpbmcgb3BlcmF0aW9ucy5cbiAgICAvL1xuICAgIC8vIFRoZSBvdXRwdXQgZGlyZWN0b3J5IGFuZCB3aGV0aGVyIHRoaXMgYXNzZXQgaXMgc2tpcHBlZCBvciBub3Qgc2hvdWxkIGFsc28gYmVcbiAgICAvLyBwYXJ0IG9mIHRoZSBjYWNoZSBrZXkgdG8gbWFrZSBzdXJlIHdlIGRvbid0IGFjY2lkZW50YWxseSByZXR1cm4gdGhlIHdyb25nXG4gICAgLy8gc3RhZ2VkIGFzc2V0IGZyb20gdGhlIGNhY2hlLlxuICAgIHRoaXMuY2FjaGVLZXkgPSBjYWxjdWxhdGVDYWNoZUtleSh7XG4gICAgICBvdXRkaXI6IHRoaXMuYXNzZXRPdXRkaXIsXG4gICAgICBzb3VyY2VQYXRoOiBwYXRoLnJlc29sdmUocHJvcHMuc291cmNlUGF0aCksXG4gICAgICBidW5kbGluZzogcHJvcHMuYnVuZGxpbmcsXG4gICAgICBhc3NldEhhc2hUeXBlOiB0aGlzLmhhc2hUeXBlLFxuICAgICAgY3VzdG9tRmluZ2VycHJpbnQ6IHRoaXMuY3VzdG9tU291cmNlRmluZ2VycHJpbnQsXG4gICAgICBleHRyYUhhc2g6IHByb3BzLmV4dHJhSGFzaCxcbiAgICAgIGV4Y2x1ZGU6IHByb3BzLmV4Y2x1ZGUsXG4gICAgICBpZ25vcmVNb2RlOiBwcm9wcy5pZ25vcmVNb2RlLFxuICAgICAgc2tpcCxcbiAgICB9KTtcblxuICAgIGNvbnN0IHN0YWdlZCA9IEFzc2V0U3RhZ2luZy5hc3NldENhY2hlLm9idGFpbih0aGlzLmNhY2hlS2V5LCBzdGFnZVRoaXNBc3NldCk7XG4gICAgdGhpcy5zdGFnZWRQYXRoID0gc3RhZ2VkLnN0YWdlZFBhdGg7XG4gICAgdGhpcy5hYnNvbHV0ZVN0YWdlZFBhdGggPSBzdGFnZWQuc3RhZ2VkUGF0aDtcbiAgICB0aGlzLmFzc2V0SGFzaCA9IHN0YWdlZC5hc3NldEhhc2g7XG4gICAgdGhpcy5wYWNrYWdpbmcgPSBzdGFnZWQucGFja2FnaW5nO1xuICAgIHRoaXMuaXNBcmNoaXZlID0gc3RhZ2VkLmlzQXJjaGl2ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNyeXB0b2dyYXBoaWMgaGFzaCBvZiB0aGUgYXNzZXQuXG4gICAqXG4gICAqIEBkZXByZWNhdGVkIHNlZSBgYXNzZXRIYXNoYC5cbiAgICovXG4gIHB1YmxpYyBnZXQgc291cmNlSGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmFzc2V0SGFzaDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIHBhdGggdG8gdGhlIHN0YWdlZCBhc3NldCwgcmVsYXRpdmUgdG8gdGhlIENsb3VkIEFzc2VtYmx5IChtYW5pZmVzdCkgZGlyZWN0b3J5IG9mIHRoZSBnaXZlbiBzdGFja1xuICAgKlxuICAgKiBPbmx5IHJldHVybnMgYSByZWxhdGl2ZSBwYXRoIGlmIHRoZSBhc3NldCB3YXMgc3RhZ2VkLCByZXR1cm5zIGFuIGFic29sdXRlIHBhdGggaWZcbiAgICogaXQgd2FzIG5vdCBzdGFnZWQuXG4gICAqXG4gICAqIEEgYnVuZGxlZCBhc3NldCBtaWdodCBlbmQgdXAgaW4gdGhlIG91dERpciBhbmQgc3RpbGwgbm90IGNvdW50IGFzXG4gICAqIFwic3RhZ2VkXCI7IGlmIGFzc2V0IHN0YWdpbmcgaXMgZGlzYWJsZWQgd2UncmUgdGVjaG5pY2FsbHkgZXhwZWN0ZWQgdG9cbiAgICogcmVmZXJlbmNlIHNvdXJjZSBkaXJlY3RvcmllcywgYnV0IHdlIGRvbid0IGhhdmUgYSBzb3VyY2UgZGlyZWN0b3J5IGZvciB0aGVcbiAgICogYnVuZGxlZCBvdXRwdXRzIChhcyB0aGUgYnVuZGxlIG91dHB1dCBpcyB3cml0dGVuIHRvIGEgdGVtcG9yYXJ5XG4gICAqIGRpcmVjdG9yeSkuIE5ldmVydGhlbGVzcywgd2Ugd2lsbCBzdGlsbCByZXR1cm4gYW4gYWJzb2x1dGUgcGF0aC5cbiAgICpcbiAgICogQSBub24tb2J2aW91cyBkaXJlY3RvcnkgbGF5b3V0IG1heSBsb29rIGxpa2UgdGhpczpcbiAgICpcbiAgICogYGBgXG4gICAqICAgQ0xPVUQgQVNTRU1CTFkgUk9PVFxuICAgKiAgICAgKy0tIGFzc2V0LjEyMzQ1YWJjZGVmL1xuICAgKiAgICAgKy0tIGFzc2VtYmx5LVN0YWdlXG4gICAqICAgICAgICAgICArLS0gTXlTdGFjay50ZW1wbGF0ZS5qc29uXG4gICAqICAgICAgICAgICArLS0gTXlTdGFjay5hc3NldHMuanNvbiA8LSB3aWxsIGNvbnRhaW4geyBcInBhdGhcIjogXCIuLi9hc3NldC4xMjM0NWFiY2RlZlwiIH1cbiAgICogYGBgXG4gICAqL1xuICBwdWJsaWMgcmVsYXRpdmVTdGFnZWRQYXRoKHN0YWNrOiBTdGFjaykge1xuICAgIGNvbnN0IGFzbU1hbmlmZXN0RGlyID0gU3RhZ2Uub2Yoc3RhY2spPy5vdXRkaXI7XG4gICAgaWYgKCFhc21NYW5pZmVzdERpcikgeyByZXR1cm4gdGhpcy5zdGFnZWRQYXRoOyB9XG5cbiAgICBjb25zdCBpc091dHNpZGVBc3NldERpciA9IHBhdGgucmVsYXRpdmUodGhpcy5hc3NldE91dGRpciwgdGhpcy5zdGFnZWRQYXRoKS5zdGFydHNXaXRoKCcuLicpO1xuICAgIGlmIChpc091dHNpZGVBc3NldERpciB8fCB0aGlzLnN0YWdpbmdEaXNhYmxlZCkge1xuICAgICAgcmV0dXJuIHRoaXMuc3RhZ2VkUGF0aDtcbiAgICB9XG5cbiAgICByZXR1cm4gcGF0aC5yZWxhdGl2ZShhc21NYW5pZmVzdERpciwgdGhpcy5zdGFnZWRQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFnZSB0aGUgc291cmNlIHRvIHRoZSB0YXJnZXQgYnkgY29weWluZ1xuICAgKlxuICAgKiBPcHRpb25hbGx5IHNraXAgaWYgc3RhZ2luZyBpcyBkaXNhYmxlZCwgaW4gd2hpY2ggY2FzZSB3ZSBwcmV0ZW5kIHdlIGRpZCBzb21ldGhpbmcgYnV0IHdlIGRvbid0IHJlYWxseS5cbiAgICovXG4gIHByaXZhdGUgc3RhZ2VCeUNvcHlpbmcoKTogU3RhZ2VkQXNzZXQge1xuICAgIGNvbnN0IGFzc2V0SGFzaCA9IHRoaXMuY2FsY3VsYXRlSGFzaCh0aGlzLmhhc2hUeXBlKTtcbiAgICBjb25zdCBzdGFnZWRQYXRoID0gdGhpcy5zdGFnaW5nRGlzYWJsZWRcbiAgICAgID8gdGhpcy5zb3VyY2VQYXRoXG4gICAgICA6IHBhdGgucmVzb2x2ZSh0aGlzLmFzc2V0T3V0ZGlyLCByZW5kZXJBc3NldEZpbGVuYW1lKGFzc2V0SGFzaCwgcGF0aC5leHRuYW1lKHRoaXMuc291cmNlUGF0aCkpKTtcblxuICAgIGlmICghdGhpcy5zb3VyY2VTdGF0cy5pc0RpcmVjdG9yeSgpICYmICF0aGlzLnNvdXJjZVN0YXRzLmlzRmlsZSgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEFzc2V0ICR7dGhpcy5zb3VyY2VQYXRofSBpcyBleHBlY3RlZCB0byBiZSBlaXRoZXIgYSBkaXJlY3Rvcnkgb3IgYSByZWd1bGFyIGZpbGVgKTtcbiAgICB9XG5cbiAgICB0aGlzLnN0YWdlQXNzZXQodGhpcy5zb3VyY2VQYXRoLCBzdGFnZWRQYXRoLCAnY29weScpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGFzc2V0SGFzaCxcbiAgICAgIHN0YWdlZFBhdGgsXG4gICAgICBwYWNrYWdpbmc6IHRoaXMuc291cmNlU3RhdHMuaXNEaXJlY3RvcnkoKSA/IEZpbGVBc3NldFBhY2thZ2luZy5aSVBfRElSRUNUT1JZIDogRmlsZUFzc2V0UGFja2FnaW5nLkZJTEUsXG4gICAgICBpc0FyY2hpdmU6IHRoaXMuc291cmNlU3RhdHMuaXNEaXJlY3RvcnkoKSB8fCBBUkNISVZFX0VYVEVOU0lPTlMuaW5jbHVkZXMocGF0aC5leHRuYW1lKHRoaXMuc291cmNlUGF0aCkudG9Mb3dlckNhc2UoKSksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFnZSB0aGUgc291cmNlIHRvIHRoZSB0YXJnZXQgYnkgYnVuZGxpbmdcbiAgICpcbiAgICogT3B0aW9uYWxseSBza2lwLCBpbiB3aGljaCBjYXNlIHdlIHByZXRlbmQgd2UgZGlkIHNvbWV0aGluZyBidXQgd2UgZG9uJ3QgcmVhbGx5LlxuICAgKi9cbiAgcHJpdmF0ZSBzdGFnZUJ5QnVuZGxpbmcoYnVuZGxpbmc6IEJ1bmRsaW5nT3B0aW9ucywgc2tpcDogYm9vbGVhbik6IFN0YWdlZEFzc2V0IHtcbiAgICBpZiAoIXRoaXMuc291cmNlU3RhdHMuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBBc3NldCAke3RoaXMuc291cmNlUGF0aH0gaXMgZXhwZWN0ZWQgdG8gYmUgYSBkaXJlY3Rvcnkgd2hlbiBidW5kbGluZ2ApO1xuICAgIH1cblxuICAgIGlmIChza2lwKSB7XG4gICAgICAvLyBXZSBzaG91bGQgaGF2ZSBidW5kbGVkLCBidXQgZGlkbid0IHRvIHNhdmUgdGltZS4gU3RpbGwgcHJldGVuZCB0byBoYXZlIGEgaGFzaC5cbiAgICAgIC8vIElmIHRoZSBhc3NldCB1c2VzIE9VVFBVVCBvciBCVU5ETEUsIHdlIHVzZSBhIENVU1RPTSBoYXNoIHRvIGF2b2lkIGZpbmdlcnByaW50aW5nXG4gICAgICAvLyBhIHBvdGVudGlhbGx5IHZlcnkgbGFyZ2Ugc291cmNlIGRpcmVjdG9yeS4gT3RoZXIgaGFzaCB0eXBlcyBhcmUga2VwdCB0aGUgc2FtZS5cbiAgICAgIGxldCBoYXNoVHlwZSA9IHRoaXMuaGFzaFR5cGU7XG4gICAgICBpZiAoaGFzaFR5cGUgPT09IEFzc2V0SGFzaFR5cGUuT1VUUFVUIHx8IGhhc2hUeXBlID09PSBBc3NldEhhc2hUeXBlLkJVTkRMRSkge1xuICAgICAgICB0aGlzLmN1c3RvbVNvdXJjZUZpbmdlcnByaW50ID0gTmFtZXMudW5pcXVlSWQodGhpcyk7XG4gICAgICAgIGhhc2hUeXBlID0gQXNzZXRIYXNoVHlwZS5DVVNUT007XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhc3NldEhhc2g6IHRoaXMuY2FsY3VsYXRlSGFzaChoYXNoVHlwZSwgYnVuZGxpbmcpLFxuICAgICAgICBzdGFnZWRQYXRoOiB0aGlzLnNvdXJjZVBhdGgsXG4gICAgICAgIHBhY2thZ2luZzogRmlsZUFzc2V0UGFja2FnaW5nLlpJUF9ESVJFQ1RPUlksXG4gICAgICAgIGlzQXJjaGl2ZTogdHJ1ZSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIGNhbGN1bGF0ZSBhc3NldEhhc2ggYmVmb3JlaGFuZCAoaWYgd2UgY2FuKVxuICAgIGxldCBhc3NldEhhc2ggPSB0aGlzLmhhc2hUeXBlID09PSBBc3NldEhhc2hUeXBlLlNPVVJDRSB8fCB0aGlzLmhhc2hUeXBlID09PSBBc3NldEhhc2hUeXBlLkNVU1RPTVxuICAgICAgPyB0aGlzLmNhbGN1bGF0ZUhhc2godGhpcy5oYXNoVHlwZSwgYnVuZGxpbmcpXG4gICAgICA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IGJ1bmRsZURpciA9IHRoaXMuZGV0ZXJtaW5lQnVuZGxlRGlyKHRoaXMuYXNzZXRPdXRkaXIsIGFzc2V0SGFzaCk7XG4gICAgdGhpcy5idW5kbGUoYnVuZGxpbmcsIGJ1bmRsZURpcik7XG5cbiAgICAvLyBDaGVjayBidW5kbGluZyBvdXRwdXQgY29udGVudCBhbmQgZGV0ZXJtaW5lIGlmIHdlIHdpbGwgbmVlZCB0byBhcmNoaXZlXG4gICAgY29uc3QgYnVuZGxpbmdPdXRwdXRUeXBlID0gYnVuZGxpbmcub3V0cHV0VHlwZSA/PyBCdW5kbGluZ091dHB1dC5BVVRPX0RJU0NPVkVSO1xuICAgIGNvbnN0IGJ1bmRsZWRBc3NldCA9IGRldGVybWluZUJ1bmRsZWRBc3NldChidW5kbGVEaXIsIGJ1bmRsaW5nT3V0cHV0VHlwZSk7XG5cbiAgICAvLyBDYWxjdWxhdGUgYXNzZXRIYXNoIGFmdGVyd2FyZHMgaWYgd2Ugc3RpbGwgbXVzdFxuICAgIGFzc2V0SGFzaCA9IGFzc2V0SGFzaCA/PyB0aGlzLmNhbGN1bGF0ZUhhc2godGhpcy5oYXNoVHlwZSwgYnVuZGxpbmcsIGJ1bmRsZWRBc3NldC5wYXRoKTtcbiAgICBjb25zdCBzdGFnZWRQYXRoID0gcGF0aC5yZXNvbHZlKHRoaXMuYXNzZXRPdXRkaXIsIHJlbmRlckFzc2V0RmlsZW5hbWUoYXNzZXRIYXNoLCBidW5kbGVkQXNzZXQuZXh0ZW5zaW9uKSk7XG5cbiAgICB0aGlzLnN0YWdlQXNzZXQoYnVuZGxlZEFzc2V0LnBhdGgsIHN0YWdlZFBhdGgsICdtb3ZlJyk7XG5cbiAgICAvLyBJZiBidW5kbGluZyBwcm9kdWNlZCBhIHNpbmdsZSBhcmNoaXZlIGZpbGUgd2UgXCJ0b3VjaFwiIHRoaXMgZmlsZSBpbiB0aGUgYnVuZGxpbmdcbiAgICAvLyBkaXJlY3RvcnkgYWZ0ZXIgaXQgaGFzIGJlZW4gbW92ZWQgdG8gdGhlIHN0YWdpbmcgZGlyZWN0b3J5LiBUaGlzIHdheSBpZiBidW5kbGluZ1xuICAgIC8vIGlzIHNraXBwZWQgYmVjYXVzZSB0aGUgYnVuZGxpbmcgZGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIHdlIGNhbiBzdGlsbCBkZXRlcm1pbmVcbiAgICAvLyB0aGUgY29ycmVjdCBwYWNrYWdpbmcgdHlwZS5cbiAgICBpZiAoYnVuZGxlZEFzc2V0LnBhY2thZ2luZyA9PT0gRmlsZUFzc2V0UGFja2FnaW5nLkZJTEUpIHtcbiAgICAgIGZzLmNsb3NlU3luYyhmcy5vcGVuU3luYyhidW5kbGVkQXNzZXQucGF0aCwgJ3cnKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGFzc2V0SGFzaCxcbiAgICAgIHN0YWdlZFBhdGgsXG4gICAgICBwYWNrYWdpbmc6IGJ1bmRsZWRBc3NldC5wYWNrYWdpbmcsXG4gICAgICBpc0FyY2hpdmU6IHRydWUsIC8vIGJ1bmRsaW5nIGFsd2F5cyBwcm9kdWNlcyBhbiBhcmNoaXZlXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHN0YWdpbmcgaGFzIGJlZW4gZGlzYWJsZWRcbiAgICovXG4gIHByaXZhdGUgZ2V0IHN0YWdpbmdEaXNhYmxlZCgpIHtcbiAgICByZXR1cm4gISF0aGlzLm5vZGUudHJ5R2V0Q29udGV4dChjeGFwaS5ESVNBQkxFX0FTU0VUX1NUQUdJTkdfQ09OVEVYVCk7XG4gIH1cblxuICAvKipcbiAgICogQ29waWVzIG9yIG1vdmVzIHRoZSBmaWxlcyBmcm9tIHNvdXJjZVBhdGggdG8gdGFyZ2V0UGF0aC5cbiAgICpcbiAgICogTW92aW5nIGltcGxpZXMgdGhlIHNvdXJjZSBkaXJlY3RvcnkgaXMgdGVtcG9yYXJ5IGFuZCBjYW4gYmUgdHJhc2hlZC5cbiAgICpcbiAgICogV2lsbCBub3QgZG8gYW55dGhpbmcgaWYgc291cmNlIGFuZCB0YXJnZXQgYXJlIHRoZSBzYW1lLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGFnZUFzc2V0KHNvdXJjZVBhdGg6IHN0cmluZywgdGFyZ2V0UGF0aDogc3RyaW5nLCBzdHlsZTogJ21vdmUnIHwgJ2NvcHknKSB7XG4gICAgLy8gSXMgdGhlIHdvcmsgYWxyZWFkeSBkb25lP1xuICAgIGNvbnN0IGlzQWxyZWFkeVN0YWdlZCA9IGZzLmV4aXN0c1N5bmModGFyZ2V0UGF0aCk7XG4gICAgaWYgKGlzQWxyZWFkeVN0YWdlZCkge1xuICAgICAgaWYgKHN0eWxlID09PSAnbW92ZScgJiYgc291cmNlUGF0aCAhPT0gdGFyZ2V0UGF0aCkge1xuICAgICAgICBmcy5yZW1vdmVTeW5jKHNvdXJjZVBhdGgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIE1vdmluZyBjYW4gYmUgZG9uZSBxdWlja2x5XG4gICAgaWYgKHN0eWxlID09ICdtb3ZlJykge1xuICAgICAgZnMucmVuYW1lU3luYyhzb3VyY2VQYXRoLCB0YXJnZXRQYXRoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBDb3B5IGZpbGUvZGlyZWN0b3J5IHRvIHN0YWdpbmcgZGlyZWN0b3J5XG4gICAgaWYgKHRoaXMuc291cmNlU3RhdHMuaXNGaWxlKCkpIHtcbiAgICAgIGZzLmNvcHlGaWxlU3luYyhzb3VyY2VQYXRoLCB0YXJnZXRQYXRoKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuc291cmNlU3RhdHMuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgZnMubWtkaXJTeW5jKHRhcmdldFBhdGgpO1xuICAgICAgRmlsZVN5c3RlbS5jb3B5RGlyZWN0b3J5KHNvdXJjZVBhdGgsIHRhcmdldFBhdGgsIHRoaXMuZmluZ2VycHJpbnRPcHRpb25zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIGZpbGUgdHlwZTogJHtzb3VyY2VQYXRofWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgdGhlIGRpcmVjdG9yeSB3aGVyZSB3ZSdyZSBnb2luZyB0byB3cml0ZSB0aGUgYnVuZGxpbmcgb3V0cHV0XG4gICAqXG4gICAqIFRoaXMgaXMgdGhlIHRhcmdldCBkaXJlY3Rvcnkgd2hlcmUgd2UncmUgZ29pbmcgdG8gd3JpdGUgdGhlIHN0YWdlZCBvdXRwdXRcbiAgICogZmlsZXMgaWYgd2UgY2FuIChpZiB0aGUgaGFzaCBpcyBmdWxseSBrbm93biksIG9yIGEgdGVtcG9yYXJ5IGRpcmVjdG9yeVxuICAgKiBvdGhlcndpc2UuXG4gICAqL1xuICBwcml2YXRlIGRldGVybWluZUJ1bmRsZURpcihvdXRkaXI6IHN0cmluZywgc291cmNlSGFzaD86IHN0cmluZykge1xuICAgIGlmIChzb3VyY2VIYXNoKSB7XG4gICAgICByZXR1cm4gcGF0aC5yZXNvbHZlKG91dGRpciwgcmVuZGVyQXNzZXRGaWxlbmFtZShzb3VyY2VIYXNoKSk7XG4gICAgfVxuXG4gICAgLy8gV2hlbiB0aGUgYXNzZXQgaGFzaCBpc24ndCBrbm93biBpbiBhZHZhbmNlLCBidW5kbGVyIG91dHB1dHMgdG8gYW5cbiAgICAvLyBpbnRlcm1lZGlhdGUgZGlyZWN0b3J5IG5hbWVkIGFmdGVyIHRoZSBhc3NldCdzIGNhY2hlIGtleVxuICAgIHJldHVybiBwYXRoLnJlc29sdmUob3V0ZGlyLCBgYnVuZGxpbmctdGVtcC0ke3RoaXMuY2FjaGVLZXl9YCk7XG4gIH1cblxuICAvKipcbiAgICogQnVuZGxlcyBhbiBhc3NldCB0byB0aGUgZ2l2ZW4gZGlyZWN0b3J5XG4gICAqXG4gICAqIElmIHRoZSBnaXZlbiBkaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMsIGFzc3VtZSB0aGF0IGV2ZXJ5dGhpbmcncyBhbHJlYWR5XG4gICAqIGluIG9yZGVyIGFuZCBkb24ndCBkbyBhbnl0aGluZy5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMgQnVuZGxpbmcgb3B0aW9uc1xuICAgKiBAcGFyYW0gYnVuZGxlRGlyIFdoZXJlIHRvIGNyZWF0ZSB0aGUgYnVuZGxlIGRpcmVjdG9yeVxuICAgKiBAcmV0dXJucyBUaGUgZnVsbHkgcmVzb2x2ZWQgYnVuZGxlIG91dHB1dCBkaXJlY3RvcnkuXG4gICAqL1xuICBwcml2YXRlIGJ1bmRsZShvcHRpb25zOiBCdW5kbGluZ09wdGlvbnMsIGJ1bmRsZURpcjogc3RyaW5nKSB7XG4gICAgaWYgKGZzLmV4aXN0c1N5bmMoYnVuZGxlRGlyKSkgeyByZXR1cm47IH1cblxuICAgIGZzLmVuc3VyZURpclN5bmMoYnVuZGxlRGlyKTtcbiAgICAvLyBDaG1vZCB0aGUgYnVuZGxlRGlyIHRvIGZ1bGwgYWNjZXNzLlxuICAgIGZzLmNobW9kU3luYyhidW5kbGVEaXIsIDBvNzc3KTtcblxuICAgIC8vIEFsd2F5cyBtb3VudCBpbnB1dCBhbmQgb3V0cHV0IGRpclxuICAgIGNvbnN0IHZvbHVtZXMgPSBbXG4gICAgICB7XG4gICAgICAgIGhvc3RQYXRoOiB0aGlzLnNvdXJjZVBhdGgsXG4gICAgICAgIGNvbnRhaW5lclBhdGg6IEFzc2V0U3RhZ2luZy5CVU5ETElOR19JTlBVVF9ESVIsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBob3N0UGF0aDogYnVuZGxlRGlyLFxuICAgICAgICBjb250YWluZXJQYXRoOiBBc3NldFN0YWdpbmcuQlVORExJTkdfT1VUUFVUX0RJUixcbiAgICAgIH0sXG4gICAgICAuLi5vcHRpb25zLnZvbHVtZXMgPz8gW10sXG4gICAgXTtcblxuICAgIGxldCBsb2NhbEJ1bmRsaW5nOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICAgIHRyeSB7XG4gICAgICBwcm9jZXNzLnN0ZGVyci53cml0ZShgQnVuZGxpbmcgYXNzZXQgJHt0aGlzLm5vZGUucGF0aH0uLi5cXG5gKTtcblxuICAgICAgbG9jYWxCdW5kbGluZyA9IG9wdGlvbnMubG9jYWw/LnRyeUJ1bmRsZShidW5kbGVEaXIsIG9wdGlvbnMpO1xuICAgICAgaWYgKCFsb2NhbEJ1bmRsaW5nKSB7XG4gICAgICAgIGxldCB1c2VyOiBzdHJpbmc7XG4gICAgICAgIGlmIChvcHRpb25zLnVzZXIpIHtcbiAgICAgICAgICB1c2VyID0gb3B0aW9ucy51c2VyO1xuICAgICAgICB9IGVsc2UgeyAvLyBEZWZhdWx0IHRvIGN1cnJlbnQgdXNlclxuICAgICAgICAgIGNvbnN0IHVzZXJJbmZvID0gb3MudXNlckluZm8oKTtcbiAgICAgICAgICB1c2VyID0gdXNlckluZm8udWlkICE9PSAtMSAvLyB1aWQgaXMgLTEgb24gV2luZG93c1xuICAgICAgICAgICAgPyBgJHt1c2VySW5mby51aWR9OiR7dXNlckluZm8uZ2lkfWBcbiAgICAgICAgICAgIDogJzEwMDA6MTAwMCc7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zLmltYWdlLnJ1bih7XG4gICAgICAgICAgY29tbWFuZDogb3B0aW9ucy5jb21tYW5kLFxuICAgICAgICAgIHVzZXIsXG4gICAgICAgICAgdm9sdW1lcyxcbiAgICAgICAgICBlbnZpcm9ubWVudDogb3B0aW9ucy5lbnZpcm9ubWVudCxcbiAgICAgICAgICB3b3JraW5nRGlyZWN0b3J5OiBvcHRpb25zLndvcmtpbmdEaXJlY3RvcnkgPz8gQXNzZXRTdGFnaW5nLkJVTkRMSU5HX0lOUFVUX0RJUixcbiAgICAgICAgICBzZWN1cml0eU9wdDogb3B0aW9ucy5zZWN1cml0eU9wdCA/PyAnJyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBXaGVuIGJ1bmRsaW5nIGZhaWxzLCBrZWVwIHRoZSBidW5kbGUgb3V0cHV0IGZvciBkaWFnbm9zYWJpbGl0eSwgYnV0XG4gICAgICAvLyByZW5hbWUgaXQgb3V0IG9mIHRoZSB3YXkgc28gdGhhdCB0aGUgbmV4dCBydW4gZG9lc24ndCBhc3N1bWUgaXQgaGFzIGFcbiAgICAgIC8vIHZhbGlkIGJ1bmRsZURpci5cbiAgICAgIGNvbnN0IGJ1bmRsZUVycm9yRGlyID0gYnVuZGxlRGlyICsgJy1lcnJvcic7XG4gICAgICBpZiAoZnMuZXhpc3RzU3luYyhidW5kbGVFcnJvckRpcikpIHtcbiAgICAgICAgLy8gUmVtb3ZlIHRoZSBsYXN0IGJ1bmRsZUVycm9yRGlyLlxuICAgICAgICBmcy5yZW1vdmVTeW5jKGJ1bmRsZUVycm9yRGlyKTtcbiAgICAgIH1cblxuICAgICAgZnMucmVuYW1lU3luYyhidW5kbGVEaXIsIGJ1bmRsZUVycm9yRGlyKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGJ1bmRsZSBhc3NldCAke3RoaXMubm9kZS5wYXRofSwgYnVuZGxlIG91dHB1dCBpcyBsb2NhdGVkIGF0ICR7YnVuZGxlRXJyb3JEaXJ9OiAke2Vycn1gKTtcbiAgICB9XG5cbiAgICBpZiAoRmlsZVN5c3RlbS5pc0VtcHR5KGJ1bmRsZURpcikpIHtcbiAgICAgIGNvbnN0IG91dHB1dERpciA9IGxvY2FsQnVuZGxpbmcgPyBidW5kbGVEaXIgOiBBc3NldFN0YWdpbmcuQlVORExJTkdfT1VUUFVUX0RJUjtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQnVuZGxpbmcgZGlkIG5vdCBwcm9kdWNlIGFueSBvdXRwdXQuIENoZWNrIHRoYXQgY29udGVudCBpcyB3cml0dGVuIHRvICR7b3V0cHV0RGlyfS5gKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGNhbGN1bGF0ZUhhc2goaGFzaFR5cGU6IEFzc2V0SGFzaFR5cGUsIGJ1bmRsaW5nPzogQnVuZGxpbmdPcHRpb25zLCBvdXRwdXREaXI/OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIC8vIFdoZW4gYnVuZGxpbmcgYSBDVVNUT00gb3IgU09VUkNFIGFzc2V0IGhhc2ggdHlwZSwgd2Ugd2FudCB0aGUgaGFzaCB0byBpbmNsdWRlXG4gICAgLy8gdGhlIGJ1bmRsaW5nIGNvbmZpZ3VyYXRpb24uIFdlIGhhbmRsZSBDVVNUT00gYW5kIGJ1bmRsZWQgU09VUkNFIGhhc2ggdHlwZXNcbiAgICAvLyBhcyBhIHNwZWNpYWwgY2FzZSB0byBwcmVzZXJ2ZSBleGlzdGluZyB1c2VyIGFzc2V0IGhhc2hlcyBpbiBhbGwgb3RoZXIgY2FzZXMuXG4gICAgaWYgKGhhc2hUeXBlID09IEFzc2V0SGFzaFR5cGUuQ1VTVE9NIHx8IChoYXNoVHlwZSA9PSBBc3NldEhhc2hUeXBlLlNPVVJDRSAmJiBidW5kbGluZykpIHtcbiAgICAgIGNvbnN0IGhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2Jyk7XG5cbiAgICAgIC8vIGlmIGFzc2V0IGhhc2ggaXMgcHJvdmlkZWQgYnkgdXNlciwgdXNlIGl0LCBvdGhlcndpc2UgZmluZ2VycHJpbnQgdGhlIHNvdXJjZS5cbiAgICAgIGhhc2gudXBkYXRlKHRoaXMuY3VzdG9tU291cmNlRmluZ2VycHJpbnQgPz8gRmlsZVN5c3RlbS5maW5nZXJwcmludCh0aGlzLnNvdXJjZVBhdGgsIHRoaXMuZmluZ2VycHJpbnRPcHRpb25zKSk7XG5cbiAgICAgIC8vIElmIHdlJ3JlIGJ1bmRsaW5nIGFuIGFzc2V0LCBpbmNsdWRlIHRoZSBidW5kbGluZyBjb25maWd1cmF0aW9uIGluIHRoZSBoYXNoXG4gICAgICBpZiAoYnVuZGxpbmcpIHtcbiAgICAgICAgaGFzaC51cGRhdGUoSlNPTi5zdHJpbmdpZnkoYnVuZGxpbmcpKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGhhc2guZGlnZXN0KCdoZXgnKTtcbiAgICB9XG5cbiAgICBzd2l0Y2ggKGhhc2hUeXBlKSB7XG4gICAgICBjYXNlIEFzc2V0SGFzaFR5cGUuU09VUkNFOlxuICAgICAgICByZXR1cm4gRmlsZVN5c3RlbS5maW5nZXJwcmludCh0aGlzLnNvdXJjZVBhdGgsIHRoaXMuZmluZ2VycHJpbnRPcHRpb25zKTtcbiAgICAgIGNhc2UgQXNzZXRIYXNoVHlwZS5CVU5ETEU6XG4gICAgICBjYXNlIEFzc2V0SGFzaFR5cGUuT1VUUFVUOlxuICAgICAgICBpZiAoIW91dHB1dERpcikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHVzZSBcXGAke2hhc2hUeXBlfVxcYCBoYXNoIHR5cGUgd2hlbiBcXGBidW5kbGluZ1xcYCBpcyBub3Qgc3BlY2lmaWVkLmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBGaWxlU3lzdGVtLmZpbmdlcnByaW50KG91dHB1dERpciwgdGhpcy5maW5nZXJwcmludE9wdGlvbnMpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmtub3duIGFzc2V0IGhhc2ggdHlwZS4nKTtcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gcmVuZGVyQXNzZXRGaWxlbmFtZShhc3NldEhhc2g6IHN0cmluZywgZXh0ZW5zaW9uID0gJycpIHtcbiAgcmV0dXJuIGBhc3NldC4ke2Fzc2V0SGFzaH0ke2V4dGVuc2lvbn1gO1xufVxuXG4vKipcbiAqIERldGVybWluZXMgdGhlIGhhc2ggdHlwZSBmcm9tIHVzZXItZ2l2ZW4gcHJvcCB2YWx1ZXMuXG4gKlxuICogQHBhcmFtIGFzc2V0SGFzaFR5cGUgQXNzZXQgaGFzaCB0eXBlIGNvbnN0cnVjdCBwcm9wXG4gKiBAcGFyYW0gY3VzdG9tU291cmNlRmluZ2VycHJpbnQgQXNzZXQgaGFzaCBzZWVkIGdpdmVuIGluIHRoZSBjb25zdHJ1Y3QgcHJvcHNcbiAqL1xuZnVuY3Rpb24gZGV0ZXJtaW5lSGFzaFR5cGUoYXNzZXRIYXNoVHlwZT86IEFzc2V0SGFzaFR5cGUsIGN1c3RvbVNvdXJjZUZpbmdlcnByaW50Pzogc3RyaW5nKSB7XG4gIGNvbnN0IGhhc2hUeXBlID0gY3VzdG9tU291cmNlRmluZ2VycHJpbnRcbiAgICA/IChhc3NldEhhc2hUeXBlID8/IEFzc2V0SGFzaFR5cGUuQ1VTVE9NKVxuICAgIDogKGFzc2V0SGFzaFR5cGUgPz8gQXNzZXRIYXNoVHlwZS5TT1VSQ0UpO1xuXG4gIGlmIChjdXN0b21Tb3VyY2VGaW5nZXJwcmludCAmJiBoYXNoVHlwZSAhPT0gQXNzZXRIYXNoVHlwZS5DVVNUT00pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBzcGVjaWZ5IFxcYCR7YXNzZXRIYXNoVHlwZX1cXGAgZm9yIFxcYGFzc2V0SGFzaFR5cGVcXGAgd2hlbiBcXGBhc3NldEhhc2hcXGAgaXMgc3BlY2lmaWVkLiBVc2UgXFxgQ1VTVE9NXFxgIG9yIGxlYXZlIFxcYHVuZGVmaW5lZFxcYC5gKTtcbiAgfVxuICBpZiAoaGFzaFR5cGUgPT09IEFzc2V0SGFzaFR5cGUuQ1VTVE9NICYmICFjdXN0b21Tb3VyY2VGaW5nZXJwcmludCkge1xuICAgIHRocm93IG5ldyBFcnJvcignYGFzc2V0SGFzaGAgbXVzdCBiZSBzcGVjaWZpZWQgd2hlbiBgYXNzZXRIYXNoVHlwZWAgaXMgc2V0IHRvIGBBc3NldEhhc2hUeXBlLkNVU1RPTWAuJyk7XG4gIH1cblxuICByZXR1cm4gaGFzaFR5cGU7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlcyBhIGNhY2hlIGtleSBmcm9tIHRoZSBwcm9wcy4gTm9ybWFsaXplIGJ5IHNvcnRpbmcga2V5cy5cbiAqL1xuZnVuY3Rpb24gY2FsY3VsYXRlQ2FjaGVLZXk8QSBleHRlbmRzIG9iamVjdD4ocHJvcHM6IEEpOiBzdHJpbmcge1xuICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpXG4gICAgLnVwZGF0ZShKU09OLnN0cmluZ2lmeShzb3J0T2JqZWN0KHByb3BzKSkpXG4gICAgLmRpZ2VzdCgnaGV4Jyk7XG59XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgc29ydCBvYmplY3Qga2V5c1xuICovXG5mdW5jdGlvbiBzb3J0T2JqZWN0KG9iamVjdDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSk6IHsgW2tleTogc3RyaW5nXTogYW55IH0ge1xuICBpZiAodHlwZW9mIG9iamVjdCAhPT0gJ29iamVjdCcgfHwgb2JqZWN0IGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICByZXR1cm4gb2JqZWN0O1xuICB9XG4gIGNvbnN0IHJldDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHt9O1xuICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhvYmplY3QpLnNvcnQoKSkge1xuICAgIHJldFtrZXldID0gc29ydE9iamVjdChvYmplY3Rba2V5XSk7XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBzaW5nbGUgYXJjaGl2ZSBmaWxlIG9mIGEgZGlyZWN0b3J5IG9yIHVuZGVmaW5lZFxuICovXG5mdW5jdGlvbiBzaW5nbGVBcmNoaXZlRmlsZShkaXJlY3Rvcnk6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghZnMuZXhpc3RzU3luYyhkaXJlY3RvcnkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBEaXJlY3RvcnkgJHtkaXJlY3Rvcnl9IGRvZXMgbm90IGV4aXN0LmApO1xuICB9XG5cbiAgaWYgKCFmcy5zdGF0U3luYyhkaXJlY3RvcnkpLmlzRGlyZWN0b3J5KCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZGlyZWN0b3J5fSBpcyBub3QgYSBkaXJlY3RvcnkuYCk7XG4gIH1cblxuICBjb25zdCBjb250ZW50ID0gZnMucmVhZGRpclN5bmMoZGlyZWN0b3J5KTtcbiAgaWYgKGNvbnRlbnQubGVuZ3RoID09PSAxKSB7XG4gICAgY29uc3QgZmlsZSA9IHBhdGguam9pbihkaXJlY3RvcnksIGNvbnRlbnRbMF0pO1xuICAgIGNvbnN0IGV4dGVuc2lvbiA9IHBhdGguZXh0bmFtZShjb250ZW50WzBdKS50b0xvd2VyQ2FzZSgpO1xuICAgIGlmIChmcy5zdGF0U3luYyhmaWxlKS5pc0ZpbGUoKSAmJiBBUkNISVZFX0VYVEVOU0lPTlMuaW5jbHVkZXMoZXh0ZW5zaW9uKSkge1xuICAgICAgcmV0dXJuIGZpbGU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuaW50ZXJmYWNlIEJ1bmRsZWRBc3NldCB7XG4gIHBhdGg6IHN0cmluZyxcbiAgcGFja2FnaW5nOiBGaWxlQXNzZXRQYWNrYWdpbmcsXG4gIGV4dGVuc2lvbj86IHN0cmluZ1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIGJ1bmRsZWQgYXNzZXQgdG8gdXNlIGJhc2VkIG9uIHRoZSBjb250ZW50IG9mIHRoZSBidW5kbGUgZGlyZWN0b3J5XG4gKiBhbmQgdGhlIHR5cGUgb2Ygb3V0cHV0LlxuICovXG5mdW5jdGlvbiBkZXRlcm1pbmVCdW5kbGVkQXNzZXQoYnVuZGxlRGlyOiBzdHJpbmcsIG91dHB1dFR5cGU6IEJ1bmRsaW5nT3V0cHV0KTogQnVuZGxlZEFzc2V0IHtcbiAgY29uc3QgYXJjaGl2ZUZpbGUgPSBzaW5nbGVBcmNoaXZlRmlsZShidW5kbGVEaXIpO1xuXG4gIC8vIGF1dG8tZGlzY292ZXIgbWVhbnMgdGhhdCBpZiB0aGVyZSBpcyBhbiBhcmNoaXZlIGZpbGUsIHdlIHRha2UgaXQgYXMgdGhlXG4gIC8vIGJ1bmRsZSwgb3RoZXJ3aXNlLCB3ZSB3aWxsIGFyY2hpdmUgaGVyZS5cbiAgaWYgKG91dHB1dFR5cGUgPT09IEJ1bmRsaW5nT3V0cHV0LkFVVE9fRElTQ09WRVIpIHtcbiAgICBvdXRwdXRUeXBlID0gYXJjaGl2ZUZpbGUgPyBCdW5kbGluZ091dHB1dC5BUkNISVZFRCA6IEJ1bmRsaW5nT3V0cHV0Lk5PVF9BUkNISVZFRDtcbiAgfVxuXG4gIHN3aXRjaCAob3V0cHV0VHlwZSkge1xuICAgIGNhc2UgQnVuZGxpbmdPdXRwdXQuTk9UX0FSQ0hJVkVEOlxuICAgICAgcmV0dXJuIHsgcGF0aDogYnVuZGxlRGlyLCBwYWNrYWdpbmc6IEZpbGVBc3NldFBhY2thZ2luZy5aSVBfRElSRUNUT1JZIH07XG4gICAgY2FzZSBCdW5kbGluZ091dHB1dC5BUkNISVZFRDpcbiAgICAgIGlmICghYXJjaGl2ZUZpbGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdCdW5kbGluZyBvdXRwdXQgZGlyZWN0b3J5IGlzIGV4cGVjdGVkIHRvIGluY2x1ZGUgb25seSBhIHNpbmdsZSAuemlwIG9yIC5qYXIgZmlsZSB3aGVuIGBvdXRwdXRgIGlzIHNldCB0byBgQVJDSElWRURgJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4geyBwYXRoOiBhcmNoaXZlRmlsZSwgcGFja2FnaW5nOiBGaWxlQXNzZXRQYWNrYWdpbmcuRklMRSwgZXh0ZW5zaW9uOiBwYXRoLmV4dG5hbWUoYXJjaGl2ZUZpbGUpIH07XG4gIH1cbn1cbiJdfQ== |
\ | No newline at end of file |