UNPKG

149 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.AwsImpl = exports.costSnapshot = exports.requestAwsPrices = exports.awsPrice = exports.createResponseQueueImpl = exports.awsPacker = exports.getAccountId = exports.collectGarbage = exports.clearLastGc = exports.cleanup = exports.deleteResources = exports.deleteRole = exports.initialize = exports.logUrl = exports.createLayer = exports.ensureRole = exports.ensureRoleRaw = exports.createAwsApis = exports.quietly = exports.carefully = exports.AwsMetrics = exports.defaults = exports.defaultGcWorker = void 0;
4const aws_sdk_1 = require("aws-sdk");
5const crypto_1 = require("crypto");
6const fs_extra_1 = require("fs-extra");
7const https = require("https");
8const util_1 = require("util");
9const webpack_merge_1 = require("webpack-merge");
10const cache_1 = require("../cache");
11const cost_1 = require("../cost");
12const error_1 = require("../error");
13const faast_1 = require("../faast");
14const log_1 = require("../log");
15const packer_1 = require("../packer");
16const provider_1 = require("../provider");
17const serialize_1 = require("../serialize");
18const shared_1 = require("../shared");
19const throttle_1 = require("../throttle");
20const awsNpm = require("./aws-npm");
21const aws_queue_1 = require("./aws-queue");
22const aws_shared_1 = require("./aws-shared");
23const awsTrampoline = require("./aws-trampoline");
24exports.defaultGcWorker = (0, throttle_1.throttle)({ concurrency: 5, rate: 5, burst: 2 }, async (work, services) => {
25 switch (work.type) {
26 case "SetLogRetention":
27 if (await carefully(services.cloudwatch.putRetentionPolicy({
28 logGroupName: work.logGroupName,
29 retentionInDays: work.retentionInDays || 1
30 }))) {
31 log_1.log.gc(`Added retention policy %O`, work);
32 }
33 break;
34 case "DeleteResources":
35 await deleteResources(work.resources, services, log_1.log.gc);
36 break;
37 case "DeleteLayerVersion":
38 if (await carefully(services.lambda.deleteLayerVersion({
39 LayerName: work.LayerName,
40 VersionNumber: work.VersionNumber
41 }))) {
42 log_1.log.gc(`deleted layer %O`, work);
43 }
44 break;
45 }
46});
47exports.defaults = {
48 ...provider_1.commonDefaults,
49 region: "us-west-2",
50 RoleName: "faast-cached-lambda-role",
51 memorySize: 1728,
52 awsLambdaOptions: {},
53 awsConfig: {},
54 _gcWorker: exports.defaultGcWorker
55};
56class AwsMetrics {
57 constructor() {
58 this.outboundBytes = 0;
59 this.sns64kRequests = 0;
60 this.sqs64kRequests = 0;
61 }
62}
63exports.AwsMetrics = AwsMetrics;
64async function carefully(arg) {
65 try {
66 return await arg.promise();
67 }
68 catch (err) {
69 log_1.log.warn(err);
70 return;
71 }
72}
73exports.carefully = carefully;
74async function quietly(arg) {
75 try {
76 return await arg.promise();
77 }
78 catch (err) {
79 return;
80 }
81}
82exports.quietly = quietly;
83exports.createAwsApis = (0, throttle_1.throttle)({ concurrency: 1 }, async (region, awsConfig = {}) => {
84 const logger = log_1.log.awssdk.enabled ? { log: log_1.log.awssdk } : undefined;
85 const common = {
86 maxRetries: 6,
87 correctClockSkew: true,
88 logger,
89 ...awsConfig,
90 region
91 };
92 const agent = new https.Agent({ keepAlive: true, maxSockets: 1000, timeout: 0 });
93 const services = {
94 iam: new aws_sdk_1.IAM({ apiVersion: "2010-05-08", ...common }),
95 lambda: new aws_sdk_1.Lambda({ apiVersion: "2015-03-31", ...common }),
96 // Special Lambda instance with configuration optimized for
97 // invocations.
98 lambda2: new aws_sdk_1.Lambda({
99 apiVersion: "2015-03-31",
100 ...common,
101 // Retries are handled by faast.js, not the sdk.
102 maxRetries: 0,
103 // The default 120s timeout is too short, especially for https
104 // mode.
105 httpOptions: { timeout: 0, agent }
106 }),
107 cloudwatch: new aws_sdk_1.CloudWatchLogs({ apiVersion: "2014-03-28", ...common }),
108 sqs: new aws_sdk_1.SQS({ apiVersion: "2012-11-05", ...common }),
109 sns: new aws_sdk_1.SNS({ apiVersion: "2010-03-31", ...common }),
110 pricing: new aws_sdk_1.Pricing({ region: "us-east-1", ...common }),
111 sts: new aws_sdk_1.STS({ apiVersion: "2011-06-15", ...common }),
112 s3: new aws_sdk_1.S3({ apiVersion: "2006-03-01", ...common })
113 };
114 return services;
115});
116async function ensureRoleRaw(RoleName, services, createRole) {
117 const { iam } = services;
118 log_1.log.info(`Checking for cached lambda role`);
119 try {
120 const response = await iam.getRole({ RoleName }).promise();
121 return response.Role;
122 }
123 catch (err) {
124 if (!createRole) {
125 throw new error_1.FaastError(err, `could not find role "${RoleName}"`);
126 }
127 }
128 log_1.log.info(`Creating default role "${RoleName}" for faast trampoline function`);
129 const AssumeRolePolicyDocument = JSON.stringify({
130 Version: "2012-10-17",
131 Statement: [
132 {
133 Principal: { Service: "lambda.amazonaws.com" },
134 Action: "sts:AssumeRole",
135 Effect: "Allow"
136 }
137 ]
138 });
139 const roleParams = {
140 AssumeRolePolicyDocument,
141 RoleName,
142 Description: "role for lambda functions created by faast",
143 MaxSessionDuration: 3600
144 };
145 log_1.log.info(`Calling createRole`);
146 const PolicyArn = "arn:aws:iam::aws:policy/AdministratorAccess";
147 try {
148 const roleResponse = await iam.createRole(roleParams).promise();
149 log_1.log.info(`Attaching administrator role policy`);
150 await iam.attachRolePolicy({ RoleName, PolicyArn }).promise();
151 return roleResponse.Role;
152 }
153 catch (err) {
154 if (err.code === "EntityAlreadyExists") {
155 await (0, shared_1.sleep)(5000);
156 const roleResponse = await iam.getRole({ RoleName }).promise();
157 await iam.attachRolePolicy({ RoleName, PolicyArn }).promise();
158 return roleResponse.Role;
159 }
160 throw new error_1.FaastError(err, `failed to create role "${RoleName}"`);
161 }
162}
163exports.ensureRoleRaw = ensureRoleRaw;
164exports.ensureRole = (0, throttle_1.throttle)({ concurrency: 1, rate: 2, memoize: true, retry: 12 }, ensureRoleRaw);
165const ResponseQueueId = awsTrampoline.INVOCATION_TEST_QUEUE;
166const emptyFcall = { callId: "0", modulePath: "", name: "", args: "", ResponseQueueId };
167async function createLayer(lambda, packageJson, useDependencyCaching, FunctionName, region, retentionInDays, awsLambdaOptions) {
168 if (!packageJson) {
169 return;
170 }
171 log_1.log.info(`Building node_modules`);
172 const packageJsonContents = typeof packageJson === "string"
173 ? (await (0, fs_extra_1.readFile)(packageJson)).toString()
174 : JSON.stringify(packageJson);
175 let LayerName;
176 if (useDependencyCaching) {
177 const hasher = (0, crypto_1.createHash)("sha256");
178 hasher.update(packageJsonContents);
179 hasher.update(JSON.stringify(awsLambdaOptions.Architectures ?? ""));
180 const cacheKey = hasher.digest("hex");
181 LayerName = `faast-${cacheKey}`;
182 const layers = await quietly(lambda.listLayerVersions({ LayerName }));
183 if (layers?.LayerVersions?.length ?? 0 > 0) {
184 const [{ Version, LayerVersionArn, CreatedDate }] = layers?.LayerVersions ?? [];
185 if (!(0, shared_1.hasExpired)(CreatedDate, retentionInDays) && Version && LayerVersionArn) {
186 return { Version, LayerVersionArn, LayerName };
187 }
188 }
189 }
190 else {
191 LayerName = FunctionName;
192 }
193 try {
194 const faastModule = await (0, faast_1.faastAws)(awsNpm, {
195 region,
196 timeout: 300,
197 memorySize: 2048,
198 mode: "https",
199 gc: "off",
200 maxRetries: 0,
201 webpackOptions: {
202 externals: []
203 },
204 awsLambdaOptions
205 });
206 try {
207 const installArgs = {
208 packageJsonContents,
209 LayerName,
210 FunctionName,
211 region,
212 retentionInDays
213 };
214 const { installLog, layerInfo } = await faastModule.functions.npmInstall(installArgs);
215 log_1.log.info(installLog);
216 return layerInfo;
217 }
218 finally {
219 await faastModule.cleanup();
220 }
221 }
222 catch (err) {
223 throw new error_1.FaastError(err, "failed to create lambda layer from packageJson");
224 }
225}
226exports.createLayer = createLayer;
227function logUrl(state) {
228 const { region, FunctionName } = state.resources;
229 return (0, aws_shared_1.getLogUrl)(region, FunctionName);
230}
231exports.logUrl = logUrl;
232exports.initialize = (0, throttle_1.throttle)({ concurrency: Infinity, rate: 2 }, async (fModule, nonce, options) => {
233 const { region, timeout, memorySize, env, concurrency, mode } = options;
234 if (concurrency > 100 && mode !== "queue") {
235 log_1.log.warn(`Consider using queue mode for higher levels of concurrency:`);
236 log_1.log.warn(`https://faastjs.org/docs/api/faastjs.commonoptions.mode`);
237 }
238 log_1.log.info(`Creating AWS APIs`);
239 const services = await (0, exports.createAwsApis)(region, options.awsConfig);
240 const { lambda } = services;
241 const FunctionName = `faast-${nonce}`;
242 const { packageJson, useDependencyCaching, description } = options;
243 async function createFunctionRequest(Code, Role, responseQueueArn, layerInfo) {
244 const { Layers = [], ...rest } = options.awsLambdaOptions;
245 if (layerInfo) {
246 Layers.push(layerInfo.LayerVersionArn);
247 }
248 const request = {
249 FunctionName,
250 Role,
251 Runtime: "nodejs14.x",
252 Handler: "index.trampoline",
253 Code,
254 Description: "faast trampoline function",
255 Timeout: timeout,
256 MemorySize: memorySize,
257 Environment: { Variables: env },
258 Layers,
259 ...rest
260 };
261 log_1.log.info(`createFunctionRequest: %O`, request);
262 let func;
263 try {
264 func = await lambda.createFunction(request).promise();
265 await (0, throttle_1.retryOp)(2, () => lambda.waitFor("functionActive", { FunctionName }).promise());
266 }
267 catch (err) {
268 if (err?.message?.match(/Function already exist/)) {
269 func = (await lambda.getFunction({ FunctionName }).promise())
270 .Configuration;
271 }
272 else {
273 throw new error_1.FaastError(err, "Create function failure");
274 }
275 }
276 log_1.log.info(`Created function ${func.FunctionName}, FunctionArn: ${func.FunctionArn} [${description}]`);
277 log_1.log.minimal(`Created function ${func.FunctionName} [${description}]`);
278 try {
279 const config = await (0, throttle_1.retryOp)((err, n) => n < 5 && err?.message?.match(/destination ARN.*is invalid/), () => lambda
280 .putFunctionEventInvokeConfig({
281 FunctionName,
282 MaximumRetryAttempts: 0,
283 MaximumEventAgeInSeconds: 21600,
284 DestinationConfig: {
285 OnFailure: { Destination: responseQueueArn }
286 }
287 })
288 .promise());
289 log_1.log.info(`Function event invocation config: %O`, config);
290 }
291 catch (err) {
292 throw new error_1.FaastError(err, "putFunctionEventInvokeConfig failure");
293 }
294 return func;
295 }
296 const { wrapperVerbose } = options.debugOptions;
297 async function createCodeBundle() {
298 const { timeout, childProcess, mode } = options;
299 const hasLambdaTimeoutBug = mode !== "queue" && timeout >= 180;
300 const childProcessTimeoutMs = hasLambdaTimeoutBug && childProcess ? (timeout - 5) * 1000 : 0;
301 const childProcessMemoryLimitMb = options.childProcessMemoryMb;
302 const wrapperOptions = {
303 wrapperVerbose,
304 childProcessTimeoutMs,
305 childProcessMemoryLimitMb
306 };
307 const bundle = awsPacker(fModule, options, wrapperOptions, FunctionName);
308 return { ZipFile: await (0, shared_1.streamToBuffer)((await bundle).archive) };
309 }
310 const { RoleName } = options;
311 const state = {
312 resources: {
313 FunctionName,
314 RoleName,
315 region,
316 logGroupName: (0, aws_shared_1.getLogGroupName)(FunctionName)
317 },
318 services,
319 metrics: new AwsMetrics(),
320 options
321 };
322 const { gc, retentionInDays, _gcWorker: gcWorker } = options;
323 if (gc === "auto" || gc === "force") {
324 log_1.log.gc(`Starting garbage collector`);
325 state.gcPromise = collectGarbage(gcWorker, services, region, retentionInDays, gc).catch(err => {
326 log_1.log.gc(`Garbage collection error: ${err}`);
327 return "skipped";
328 });
329 }
330 try {
331 log_1.log.info(`Creating lambda function`);
332 const rolePromise = (0, exports.ensureRole)(RoleName, services, RoleName === exports.defaults.RoleName);
333 const responseQueuePromise = createResponseQueueImpl(state, FunctionName);
334 const pricingPromise = (0, exports.requestAwsPrices)(services.pricing, region);
335 const codeBundlePromise = createCodeBundle();
336 // Ensure role exists before creating lambda layer, which also needs the role.
337 const role = await rolePromise;
338 const layerPromise = createLayer(services.lambda, packageJson, useDependencyCaching, FunctionName, region, retentionInDays, options.awsLambdaOptions);
339 const codeBundle = await codeBundlePromise;
340 const responseQueueArn = await responseQueuePromise;
341 const layer = await layerPromise;
342 if (layer) {
343 state.resources.layer = layer;
344 }
345 let lambdaFnArn;
346 const retryable = [
347 /role/,
348 /KMS Exception/,
349 /internal service error/,
350 /Layer version/
351 ];
352 const shouldRetry = (err, n) => n < 5 && !!retryable.find(regex => err?.message?.match(regex));
353 await (0, throttle_1.retryOp)(shouldRetry, async () => {
354 try {
355 const lambdaFn = await createFunctionRequest(codeBundle, role.Arn, responseQueueArn, layer);
356 lambdaFnArn = lambdaFn.FunctionArn;
357 // If the role for the lambda function was created
358 // recently, test that the role works by invoking the
359 // function. If an exception occurs, the function is
360 // deleted and re-deployed. Empirically, this is the way
361 // to ensure successful lambda creation when an IAM role
362 // is recently created.
363 if (Date.now() - role.CreateDate.getTime() < 300 * 1000) {
364 const { metrics } = state;
365 const fn = FunctionName;
366 const never = new Promise(_ => { });
367 await (0, throttle_1.retryOp)(1, () => invokeHttps(lambda, fn, emptyFcall, metrics, never));
368 }
369 }
370 catch (err) {
371 /* istanbul ignore next */ {
372 await lambda
373 .deleteFunction({ FunctionName })
374 .promise()
375 .catch(_ => { });
376 throw new error_1.FaastError(err, `New lambda function ${FunctionName} failed invocation test`);
377 }
378 }
379 });
380 const { mode } = options;
381 if (mode === "queue") {
382 await createRequestQueueImpl(state, FunctionName, lambdaFnArn);
383 }
384 await pricingPromise;
385 log_1.log.info(`Lambda function initialization complete.`);
386 return state;
387 }
388 catch (err) {
389 try {
390 await cleanup(state, {
391 deleteResources: true,
392 deleteCaches: false,
393 gcTimeout: 30
394 });
395 }
396 catch { }
397 throw new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.ECREATE }, "failed to initialize cloud function");
398 }
399});
400async function invoke(state, call, cancel) {
401 const { metrics, services, resources, options } = state;
402 switch (options.mode) {
403 case "auto":
404 case "https":
405 const { lambda2 } = services;
406 const { FunctionName } = resources;
407 await invokeHttps(lambda2, FunctionName, call, metrics, cancel);
408 return;
409 case "queue":
410 const { sns } = services;
411 const { RequestTopicArn } = resources;
412 try {
413 await (0, aws_queue_1.publishFunctionCallMessage)(sns, RequestTopicArn, call, metrics);
414 }
415 catch (err) {
416 throw new error_1.FaastError(err, `invoke sns error ${(0, util_1.inspect)(call, undefined, 9)}`);
417 }
418 return;
419 }
420}
421function poll(state, cancel) {
422 return (0, aws_queue_1.receiveMessages)(state.services.sqs, state.resources.ResponseQueueUrl, state.metrics, cancel);
423}
424function responseQueueId(state) {
425 return state.resources.ResponseQueueUrl;
426}
427async function invokeHttps(lambda, FunctionName, message, metrics, cancel) {
428 const request = {
429 FunctionName,
430 Payload: (0, serialize_1.serialize)(message),
431 LogType: "None"
432 };
433 const awsRequest = lambda.invoke(request);
434 const rawResponse = await Promise.race([awsRequest.promise(), cancel]);
435 if (!rawResponse) {
436 log_1.log.info(`cancelling lambda invoke`);
437 awsRequest.abort();
438 return;
439 }
440 metrics.outboundBytes += (0, shared_1.computeHttpResponseBytes)(rawResponse.$response.httpResponse.headers);
441 if (rawResponse.LogResult) {
442 log_1.log.info(Buffer.from(rawResponse.LogResult, "base64").toString());
443 }
444 if (rawResponse.FunctionError) {
445 const error = (0, aws_queue_1.processAwsErrorMessage)(rawResponse.Payload);
446 throw error;
447 }
448}
449async function deleteRole(RoleName, iam) {
450 const policies = await carefully(iam.listAttachedRolePolicies({ RoleName }));
451 const AttachedPolicies = policies?.AttachedPolicies ?? [];
452 await Promise.all(AttachedPolicies.map(p => p.PolicyArn).map(PolicyArn => carefully(iam.detachRolePolicy({ RoleName, PolicyArn }))));
453 const rolePolicyListResponse = await carefully(iam.listRolePolicies({ RoleName }));
454 const RolePolicies = rolePolicyListResponse?.PolicyNames ?? [];
455 await Promise.all(RolePolicies.map(PolicyName => carefully(iam.deleteRolePolicy({ RoleName, PolicyName }))));
456 await carefully(iam.deleteRole({ RoleName }));
457}
458exports.deleteRole = deleteRole;
459async function deleteResources(resources, services, output = log_1.log.info) {
460 const { FunctionName, RoleName, region, RequestTopicArn, ResponseQueueUrl, ResponseQueueArn, SNSLambdaSubscriptionArn, logGroupName, layer, Bucket, ...rest } = resources;
461 const _exhaustiveCheck = {};
462 const { lambda, sqs, sns, iam, s3, cloudwatch } = services;
463 if (SNSLambdaSubscriptionArn) {
464 if (await quietly(sns.unsubscribe({ SubscriptionArn: SNSLambdaSubscriptionArn }))) {
465 output(`Deleted request queue subscription to lambda`);
466 }
467 }
468 if (RoleName) {
469 await deleteRole(RoleName, iam);
470 }
471 if (RequestTopicArn) {
472 if (await quietly(sns.deleteTopic({ TopicArn: RequestTopicArn }))) {
473 output(`Deleted request queue topic: ${RequestTopicArn}`);
474 }
475 }
476 if (ResponseQueueUrl) {
477 if (await quietly(sqs.deleteQueue({ QueueUrl: ResponseQueueUrl }))) {
478 output(`Deleted response queue: ${ResponseQueueUrl}`);
479 }
480 }
481 if (layer) {
482 if (await quietly(lambda.deleteLayerVersion({
483 LayerName: layer.LayerName,
484 VersionNumber: layer.Version
485 }))) {
486 output(`Deleted lambda layer: ${layer.LayerName}:${layer.Version}`);
487 }
488 }
489 if (Bucket) {
490 const objects = await quietly(s3.listObjectsV2({ Bucket, Prefix: "faast-" }));
491 if (objects) {
492 const keys = (objects.Contents || []).map(elem => ({ Key: elem.Key }));
493 if (await quietly(s3.deleteObjects({ Bucket, Delete: { Objects: keys } }))) {
494 output(`Deleted s3 objects: ${keys.length} objects in bucket ${Bucket}`);
495 }
496 }
497 if (await quietly(s3.deleteBucket({ Bucket }))) {
498 output(`Deleted s3 bucket: ${Bucket}`);
499 }
500 }
501 if (FunctionName) {
502 if (await quietly(lambda.deleteFunction({ FunctionName }))) {
503 output(`Deleted function: ${FunctionName}`);
504 }
505 }
506 if (logGroupName) {
507 if (await quietly(cloudwatch.deleteLogGroup({ logGroupName }))) {
508 output(`Deleted log group: ${logGroupName}`);
509 }
510 }
511}
512exports.deleteResources = deleteResources;
513async function addLogRetentionPolicy(FunctionName, cloudwatch) {
514 const logGroupName = (0, aws_shared_1.getLogGroupName)(FunctionName);
515 const response = await quietly(cloudwatch.putRetentionPolicy({ logGroupName, retentionInDays: 1 }));
516 if (response !== undefined) {
517 log_1.log.info(`Added 1 day retention policy to log group ${logGroupName}`);
518 }
519}
520async function cleanup(state, options) {
521 log_1.log.info(`aws cleanup starting.`);
522 if (state.gcPromise) {
523 log_1.log.info(`Waiting for garbage collection...`);
524 await state.gcPromise;
525 log_1.log.info(`Garbage collection done.`);
526 }
527 if (options.deleteResources) {
528 log_1.log.info(`Cleaning up infrastructure for ${state.resources.FunctionName}...`);
529 await addLogRetentionPolicy(state.resources.FunctionName, state.services.cloudwatch);
530 // Don't delete cached role. It may be in use by other instances of
531 // faast. Don't delete logs. They are often useful. By default log
532 // stream retention will be 1 day, and gc will clean out the log group
533 // after the streams are expired. Don't delete a lambda layer that is
534 // used to cache packages.
535 const { logGroupName, RoleName, layer, ...rest } = state.resources;
536 await deleteResources(rest, state.services);
537 if (!state.options.useDependencyCaching || options.deleteCaches) {
538 await deleteResources({ layer }, state.services);
539 }
540 }
541 log_1.log.info(`aws cleanup done.`);
542}
543exports.cleanup = cleanup;
544const logGroupNameRegexp = new RegExp(`^/aws/lambda/(faast-${shared_1.uuidv4Pattern})$`);
545function functionNameFromLogGroup(logGroupName) {
546 const match = logGroupName.match(logGroupNameRegexp);
547 return match && match[1];
548}
549let lastGc;
550function clearLastGc() {
551 lastGc = undefined;
552}
553exports.clearLastGc = clearLastGc;
554function forEachPage(description, request, process) {
555 const throttlePaging = (0, throttle_1.throttle)({ concurrency: 1, rate: 1 }, async () => { });
556 return new Promise((resolve, reject) => {
557 request.eachPage((err, page, done) => {
558 if (err) {
559 log_1.log.warn(`GC: Error when listing ${description}: ${err}`);
560 reject(err);
561 return false;
562 }
563 if (page === null) {
564 resolve();
565 }
566 else {
567 process(page).then(() => throttlePaging().then(done));
568 }
569 return true;
570 });
571 });
572}
573async function collectGarbage(executor, services, region, retentionInDays, mode) {
574 if (executor === exports.defaultGcWorker) {
575 if (mode === "auto") {
576 if (lastGc && Date.now() <= lastGc + 3600 * 1000) {
577 return "skipped";
578 }
579 const gcEntry = await cache_1.caches.awsGc.get("gc");
580 if (gcEntry) {
581 try {
582 const lastGcPersistent = JSON.parse(gcEntry.toString());
583 if (lastGcPersistent &&
584 typeof lastGcPersistent === "number" &&
585 Date.now() <= lastGcPersistent + 3600 * 1000) {
586 lastGc = lastGcPersistent;
587 return "skipped";
588 }
589 }
590 catch (err) {
591 log_1.log.warn(err);
592 }
593 }
594 }
595 lastGc = Date.now();
596 cache_1.caches.awsGc.set("gc", lastGc.toString());
597 }
598 const promises = [];
599 function scheduleWork(work) {
600 if (executor === exports.defaultGcWorker) {
601 log_1.log.gc(`Scheduling work pushing promise: %O`, work);
602 }
603 promises.push(executor(work, services));
604 }
605 const functionsWithLogGroups = new Set();
606 const logGroupRequest = services.cloudwatch.describeLogGroups({
607 logGroupNamePrefix: "/aws/lambda/faast-"
608 });
609 const accountId = await getAccountId(services.sts);
610 await forEachPage("log groups", logGroupRequest, async ({ logGroups = [] }) => {
611 logGroups.forEach(g => {
612 const FunctionName = functionNameFromLogGroup(g.logGroupName);
613 functionsWithLogGroups.add(FunctionName);
614 });
615 log_1.log.gc(`Log groups size: ${logGroups.length}`);
616 garbageCollectLogGroups(logGroups, retentionInDays, region, accountId, scheduleWork);
617 });
618 const listFunctionsRequest = services.lambda.listFunctions();
619 await forEachPage("lambda functions", listFunctionsRequest, async ({ Functions = [] }) => {
620 const fnPattern = new RegExp(`^faast-${shared_1.uuidv4Pattern}$`);
621 const funcs = (Functions || [])
622 .filter(fn => fn.FunctionName.match(fnPattern))
623 .filter(fn => !functionsWithLogGroups.has(fn.FunctionName))
624 .filter(fn => (0, shared_1.hasExpired)(fn.LastModified, retentionInDays))
625 .map(fn => fn.FunctionName);
626 deleteGarbageFunctions(region, accountId, funcs, scheduleWork);
627 });
628 // Collect Lambda Layers
629 const layersRequest = services.lambda.listLayers({
630 CompatibleRuntime: "nodejs"
631 });
632 await forEachPage("Lambda Layers", layersRequest, async ({ Layers = [] }) => {
633 for (const layer of Layers) {
634 if (layer.LayerName.match(/^faast-/)) {
635 const layerVersionRequest = services.lambda.listLayerVersions({
636 LayerName: layer.LayerName,
637 CompatibleRuntime: "nodejs"
638 });
639 await forEachPage("Lambda Layer Versions", layerVersionRequest, async ({ LayerVersions = [] }) => {
640 LayerVersions.forEach(layerVersion => {
641 if ((0, shared_1.hasExpired)(layerVersion.CreatedDate, retentionInDays)) {
642 scheduleWork({
643 type: "DeleteLayerVersion",
644 LayerName: layer.LayerName,
645 VersionNumber: layerVersion.Version
646 });
647 }
648 });
649 });
650 }
651 }
652 });
653 log_1.log.gc(`Awaiting ${promises.length} scheduled work promises`);
654 await Promise.all(promises);
655 return "done";
656}
657exports.collectGarbage = collectGarbage;
658async function getAccountId(sts) {
659 const response = await sts.getCallerIdentity().promise();
660 const { Account, Arn, UserId } = response;
661 log_1.log.info(`Account ID: %O`, { Account, Arn, UserId });
662 return response.Account;
663}
664exports.getAccountId = getAccountId;
665function garbageCollectLogGroups(logGroups, retentionInDays, region, accountId, scheduleWork) {
666 const logGroupsMissingRetentionPolicy = logGroups.filter(g => g.retentionInDays === undefined);
667 log_1.log.gc(`Log groups missing retention: ${logGroupsMissingRetentionPolicy.length}`);
668 logGroupsMissingRetentionPolicy.forEach(g => {
669 scheduleWork({
670 type: "SetLogRetention",
671 logGroupName: g.logGroupName,
672 retentionInDays
673 });
674 });
675 const garbageFunctions = logGroups
676 .filter(g => (0, shared_1.hasExpired)(g.creationTime, retentionInDays))
677 .map(g => functionNameFromLogGroup(g.logGroupName))
678 .filter(shared_1.defined);
679 deleteGarbageFunctions(region, accountId, garbageFunctions, scheduleWork);
680}
681function deleteGarbageFunctions(region, accountId, garbageFunctions, scheduleWork) {
682 garbageFunctions.forEach(FunctionName => {
683 const resources = {
684 FunctionName,
685 region,
686 RoleName: "",
687 RequestTopicArn: getSNSTopicArn(region, accountId, FunctionName),
688 ResponseQueueUrl: getResponseQueueUrl(region, accountId, FunctionName),
689 logGroupName: (0, aws_shared_1.getLogGroupName)(FunctionName),
690 Bucket: FunctionName
691 };
692 scheduleWork({ type: "DeleteResources", resources });
693 });
694}
695async function awsPacker(functionModule, options, wrapperOptions, FunctionName) {
696 return (0, packer_1.packer)(awsTrampoline, functionModule, {
697 ...options,
698 webpackOptions: (0, webpack_merge_1.default)(options.webpackOptions ?? {}, {
699 externals: [new RegExp("^aws-sdk/?")]
700 })
701 }, wrapperOptions, FunctionName);
702}
703exports.awsPacker = awsPacker;
704function getSNSTopicName(FunctionName) {
705 return `${FunctionName}-Requests`;
706}
707function getSNSTopicArn(region, accountId, FunctionName) {
708 const TopicName = getSNSTopicName(FunctionName);
709 return `arn:aws:sns:${region}:${accountId}:${TopicName}`;
710}
711function getSQSName(FunctionName) {
712 return `${FunctionName}-Responses`;
713}
714function getResponseQueueUrl(region, accountId, FunctionName) {
715 const queueName = getSQSName(FunctionName);
716 return `https://sqs.${region}.amazonaws.com/${accountId}/${queueName}`;
717}
718function createRequestQueueImpl(state, FunctionName, FunctionArn) {
719 const { sns, lambda } = state.services;
720 const { resources } = state;
721 log_1.log.info(`Creating SNS request topic`);
722 const createTopicPromise = (0, aws_queue_1.createSNSTopic)(sns, getSNSTopicName(FunctionName));
723 const assignRequestTopicArnPromise = createTopicPromise.then(topic => (resources.RequestTopicArn = topic));
724 const addPermissionsPromise = createTopicPromise.then(topic => {
725 log_1.log.info(`Adding SNS invoke permissions to function`);
726 return addSnsInvokePermissionsToFunction(FunctionName, topic, lambda);
727 });
728 const subscribePromise = createTopicPromise.then(topic => {
729 log_1.log.info(`Subscribing SNS to invoke lambda function`);
730 return sns
731 .subscribe({
732 TopicArn: topic,
733 Protocol: "lambda",
734 Endpoint: FunctionArn
735 })
736 .promise();
737 });
738 const assignSNSResponsePromise = subscribePromise.then(snsResponse => (resources.SNSLambdaSubscriptionArn = snsResponse.SubscriptionArn));
739 return Promise.all([
740 createTopicPromise,
741 assignRequestTopicArnPromise,
742 addPermissionsPromise,
743 subscribePromise,
744 assignSNSResponsePromise
745 ]);
746}
747async function createResponseQueueImpl(state, FunctionName) {
748 const { sqs } = state.services;
749 const { resources } = state;
750 log_1.log.info(`Creating SQS response queue`);
751 const { QueueUrl, QueueArn } = await (0, aws_queue_1.createSQSQueue)(getSQSName(FunctionName), 60, sqs);
752 resources.ResponseQueueUrl = QueueUrl;
753 resources.ResponseQueueArn = QueueArn;
754 log_1.log.info(`Created response queue`);
755 return QueueArn;
756}
757exports.createResponseQueueImpl = createResponseQueueImpl;
758function addSnsInvokePermissionsToFunction(FunctionName, RequestTopicArn, lambda) {
759 return lambda
760 .addPermission({
761 FunctionName,
762 Action: "lambda:InvokeFunction",
763 Principal: "sns.amazonaws.com",
764 StatementId: `${FunctionName}-Invoke`,
765 SourceArn: RequestTopicArn
766 })
767 .promise()
768 .catch(err => {
769 if (err.match(/already exists/)) {
770 }
771 else {
772 throw err;
773 }
774 });
775}
776const locations = {
777 "us-east-1": "US East (N. Virginia)",
778 "us-east-2": "US East (Ohio)",
779 "us-west-1": "US West (N. California)",
780 "us-west-2": "US West (Oregon)",
781 "ca-central-1": "Canada (Central)",
782 "eu-central-1": "EU (Frankfurt)",
783 "eu-west-1": "EU (Ireland)",
784 "eu-west-2": "EU (London)",
785 "eu-west-3": "EU (Paris)",
786 "ap-northeast-1": "Asia Pacific (Tokyo)",
787 "ap-northeast-2": "Asia Pacific (Seoul)",
788 "ap-northeast-3": "Asia Pacific (Osaka-Local)",
789 "ap-southeast-1": "Asia Pacific (Singapore)",
790 "ap-southeast-2": "Asia Pacific (Sydney)",
791 "ap-south-1": "Asia Pacific (Mumbai)",
792 "sa-east-1": "South America (São Paulo)"
793};
794exports.awsPrice = (0, throttle_1.throttle)({ concurrency: 6, rate: 5, memoize: true, cache: cache_1.caches.awsPrices }, async (pricing, ServiceCode, filter) => {
795 try {
796 function first(obj) {
797 return obj[Object.keys(obj)[0]];
798 }
799 function extractPrice(obj) {
800 const prices = Object.keys(obj.priceDimensions).map(key => Number(obj.priceDimensions[key].pricePerUnit.USD));
801 return Math.max(...prices);
802 }
803 const priceResult = await pricing
804 .getProducts({
805 ServiceCode,
806 Filters: Object.keys(filter).map(key => ({
807 Field: key,
808 Type: "TERM_MATCH",
809 Value: filter[key]
810 }))
811 })
812 .promise();
813 if (priceResult.PriceList.length > 1) {
814 log_1.log.warn(`Price query returned more than one product '${ServiceCode}' ($O)`, filter);
815 priceResult.PriceList.forEach(p => log_1.log.warn(`%O`, p));
816 }
817 const pList = priceResult.PriceList[0];
818 const price = extractPrice(first(pList.terms.OnDemand));
819 return price;
820 }
821 catch (err) {
822 /* istanbul ignore next */
823 {
824 const { message: m } = err;
825 if (!m.match(/Rate exceeded/) &&
826 !m.match(/EPROTO/) &&
827 !m.match(/socket hang up/)) {
828 log_1.log.warn(`Could not get AWS pricing for '${ServiceCode}' (%O)`, filter);
829 log_1.log.warn(err);
830 }
831 throw new error_1.FaastError(err, `failed to get AWS pricing for "${ServiceCode}"`);
832 }
833 }
834});
835const requestAwsPrices = async (pricing, region) => {
836 const location = locations[region];
837 /* istanbul ignore next */
838 return {
839 lambdaPerRequest: await (0, exports.awsPrice)(pricing, "AWSLambda", {
840 location,
841 group: "AWS-Lambda-Requests"
842 }).catch(_ => 0.0000002),
843 lambdaPerGbSecond: await (0, exports.awsPrice)(pricing, "AWSLambda", {
844 location,
845 group: "AWS-Lambda-Duration"
846 }).catch(_ => 0.00001667),
847 snsPer64kPublish: await (0, exports.awsPrice)(pricing, "AmazonSNS", {
848 location,
849 group: "SNS-Requests-Tier1"
850 }).catch(_ => 0.5 / 1e6),
851 sqsPer64kRequest: await (0, exports.awsPrice)(pricing, "AWSQueueService", {
852 location,
853 group: "SQS-APIRequest-Tier1",
854 queueType: "Standard"
855 }).catch(_ => 0.4 / 1e6),
856 dataOutPerGb: await (0, exports.awsPrice)(pricing, "AWSDataTransfer", {
857 fromLocation: location,
858 transferType: "AWS Outbound"
859 }).catch(_ => 0.09),
860 logsIngestedPerGb: await (0, exports.awsPrice)(pricing, "AmazonCloudWatch", {
861 location,
862 group: "Ingested Logs",
863 groupDescription: "Existing system, application, and custom log files"
864 }).catch(_ => 0.5)
865 };
866};
867exports.requestAwsPrices = requestAwsPrices;
868async function costSnapshot(state, stats) {
869 const { region } = state.resources;
870 const prices = await (0, exports.requestAwsPrices)(state.services.pricing, region);
871 const costMetrics = [];
872 const { memorySize = exports.defaults.memorySize } = state.options;
873 const billedTimeStats = stats.estimatedBilledTime;
874 const seconds = (billedTimeStats.mean / 1000) * billedTimeStats.samples || 0;
875 const provisionedGb = memorySize / 1024;
876 const functionCallDuration = new cost_1.CostMetric({
877 name: "functionCallDuration",
878 pricing: prices.lambdaPerGbSecond * provisionedGb,
879 unit: "second",
880 measured: seconds,
881 comment: `https://aws.amazon.com/lambda/pricing (rate = ${prices.lambdaPerGbSecond.toFixed(8)}/(GB*second) * ${provisionedGb} GB = ${(prices.lambdaPerGbSecond * provisionedGb).toFixed(8)}/second)`
882 });
883 costMetrics.push(functionCallDuration);
884 const functionCallRequests = new cost_1.CostMetric({
885 name: "functionCallRequests",
886 pricing: prices.lambdaPerRequest,
887 measured: stats.invocations,
888 unit: "request",
889 comment: "https://aws.amazon.com/lambda/pricing"
890 });
891 costMetrics.push(functionCallRequests);
892 const { metrics } = state;
893 const outboundDataTransfer = new cost_1.CostMetric({
894 name: "outboundDataTransfer",
895 pricing: prices.dataOutPerGb,
896 measured: metrics.outboundBytes / 2 ** 30,
897 unit: "GB",
898 comment: "https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer"
899 });
900 costMetrics.push(outboundDataTransfer);
901 const sqs = new cost_1.CostMetric({
902 name: "sqs",
903 pricing: prices.sqsPer64kRequest,
904 measured: metrics.sqs64kRequests,
905 unit: "request",
906 comment: "https://aws.amazon.com/sqs/pricing"
907 });
908 costMetrics.push(sqs);
909 const sns = new cost_1.CostMetric({
910 name: "sns",
911 pricing: prices.snsPer64kPublish,
912 measured: metrics.sns64kRequests,
913 unit: "request",
914 comment: "https://aws.amazon.com/sns/pricing"
915 });
916 costMetrics.push(sns);
917 const logIngestion = new cost_1.CostMetric({
918 name: "logIngestion",
919 pricing: prices.logsIngestedPerGb,
920 measured: 0,
921 unit: "GB",
922 comment: "https://aws.amazon.com/cloudwatch/pricing/ - Log ingestion costs not currently included.",
923 informationalOnly: true
924 });
925 costMetrics.push(logIngestion);
926 return new cost_1.CostSnapshot("aws", state.options, stats, costMetrics);
927}
928exports.costSnapshot = costSnapshot;
929exports.AwsImpl = {
930 name: "aws",
931 initialize: exports.initialize,
932 defaults: exports.defaults,
933 cleanup,
934 costSnapshot,
935 logUrl,
936 invoke,
937 poll,
938 responseQueueId
939};
940//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLWZhYXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2F3cy9hd3MtZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUNBV2lCO0FBRWpCLG1DQUFvQztBQUNwQyx1Q0FBb0M7QUFDcEMsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQixpREFBa0M7QUFDbEMsb0NBQWtDO0FBQ2xDLGtDQUFtRDtBQUNuRCxvQ0FBdUQ7QUFDdkQsb0NBQW9DO0FBQ3BDLGdDQUE2QjtBQUM3QixzQ0FBaUQ7QUFDakQsMENBUXFCO0FBQ3JCLDRDQUF5QztBQUN6QyxzQ0FPbUI7QUFDbkIsMENBQWdEO0FBRWhELG9DQUFvQztBQUVwQywyQ0FNcUI7QUFDckIsNkNBQTBEO0FBQzFELGtEQUFrRDtBQUVyQyxRQUFBLGVBQWUsR0FBRyxJQUFBLG1CQUFRLEVBQ25DLEVBQUUsV0FBVyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFDckMsS0FBSyxFQUFFLElBQWUsRUFBRSxRQUFxQixFQUFFLEVBQUU7SUFDN0MsUUFBUSxJQUFJLENBQUMsSUFBSSxFQUFFO1FBQ2YsS0FBSyxpQkFBaUI7WUFDbEIsSUFDSSxNQUFNLFNBQVMsQ0FDWCxRQUFRLENBQUMsVUFBVSxDQUFDLGtCQUFrQixDQUFDO2dCQUNuQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVk7Z0JBQy9CLGVBQWUsRUFBRSxJQUFJLENBQUMsZUFBZSxJQUFJLENBQUM7YUFDN0MsQ0FBQyxDQUNMLEVBQ0g7Z0JBQ0UsU0FBRyxDQUFDLEVBQUUsQ0FBQywyQkFBMkIsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUM3QztZQUNELE1BQU07UUFDVixLQUFLLGlCQUFpQjtZQUNsQixNQUFNLGVBQWUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFFBQVEsRUFBRSxTQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDeEQsTUFBTTtR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LE9BQU8sRUFBRSxvQ0FBb0M7S0FDaEQsQ0FBQyxDQUFDO0lBQ0gsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUV0QixNQUFNLEdBQUcsR0FBZSxJQUFJLGlCQUFVLENBQUM7UUFDbkMsSUFBSSxFQUFFLEtBQUs7UUFDWCxPQUFPLEVBQUUsTUFBTSxDQUFDLGdCQUFnQjtRQUNoQyxRQUFRLEVBQUUsT0FBTyxDQUFDLGNBQWM7UUFDaEMsSUFBSSxFQUFFLFNBQVM7UUFDZixPQUFPLEVBQUUsb0NBQW9DO0tBQ2hELENBQUMsQ0FBQztJQUNILFdBQVcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFFdEIsTUFBTSxZQUFZLEdBQWUsSUFBSSxpQkFBVSxDQUFDO1FBQzVDLElBQUksRUFBRSxjQUFjO1FBQ3BCLE9BQU8sRUFBRSxNQUFNLENBQUMsaUJBQWlCO1FBQ2pDLFFBQVEsRUFBRSxDQUFDO1FBQ1gsSUFBSSxFQUFFLElBQUk7UUFDVixPQUFPLEVBQ0gsMEZBQTBGO1FBQzlGLGlCQUFpQixFQUFFLElBQUk7S0FDMUIsQ0FBQyxDQUFDO0lBQ0gsV0FBVyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUUvQixPQUFPLElBQUksbUJBQVksQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7QUFDdEUsQ0FBQztBQXpFRCxvQ0F5RUM7QUFFWSxRQUFBLE9BQU8sR0FBdUM7SUFDdkQsSUFBSSxFQUFFLEtBQUs7SUFDWCxVQUFVLEVBQVYsa0JBQVU7SUFDVixRQUFRLEVBQVIsZ0JBQVE7SUFDUixPQUFPO0lBQ1AsWUFBWTtJQUNaLE1BQU07SUFDTixNQUFNO0lBQ04sSUFBSTtJQUNKLGVBQWU7Q0FDbEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgQVdTRXJyb3IsXG4gICAgQ2xvdWRXYXRjaExvZ3MsXG4gICAgSUFNLFxuICAgIExhbWJkYSxcbiAgICBQcmljaW5nLFxuICAgIFJlcXVlc3QsXG4gICAgUzMsXG4gICAgU05TLFxuICAgIFNRUyxcbiAgICBTVFNcbn0gZnJvbSBcImF3cy1zZGtcIjtcbmltcG9ydCB7IENvbmZpZ3VyYXRpb25PcHRpb25zIH0gZnJvbSBcImF3cy1zZGsvbGliL2NvbmZpZy1iYXNlXCI7XG5pbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tIFwiZnMtZXh0cmFcIjtcbmltcG9ydCAqIGFzIGh0dHBzIGZyb20gXCJodHRwc1wiO1xuaW1wb3J0IHsgaW5zcGVjdCB9IGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgbWVyZ2UgZnJvbSBcIndlYnBhY2stbWVyZ2VcIjtcbmltcG9ydCB7IGNhY2hlcyB9IGZyb20gXCIuLi9jYWNoZVwiO1xuaW1wb3J0IHsgQ29zdE1ldHJpYywgQ29zdFNuYXBzaG90IH0gZnJvbSBcIi4uL2Nvc3RcIjtcbmltcG9ydCB7IEZhYXN0RXJyb3IsIEZhYXN0RXJyb3JOYW1lcyB9IGZyb20gXCIuLi9lcnJvclwiO1xuaW1wb3J0IHsgZmFhc3RBd3MgfSBmcm9tIFwiLi4vZmFhc3RcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCIuLi9sb2dcIjtcbmltcG9ydCB7IHBhY2tlciwgUGFja2VyUmVzdWx0IH0gZnJvbSBcIi4uL3BhY2tlclwiO1xuaW1wb3J0IHtcbiAgICBDbGVhbnVwT3B0aW9ucyxcbiAgICBjb21tb25EZWZhdWx0cyxcbiAgICBDb21tb25PcHRpb25zLFxuICAgIEZ1bmN0aW9uU3RhdHMsXG4gICAgUG9sbFJlc3VsdCxcbiAgICBQcm92aWRlckltcGwsXG4gICAgVVVJRFxufSBmcm9tIFwiLi4vcHJvdmlkZXJcIjtcbmltcG9ydCB7IHNlcmlhbGl6ZSB9IGZyb20gXCIuLi9zZXJpYWxpemVcIjtcbmltcG9ydCB7XG4gICAgY29tcHV0ZUh0dHBSZXNwb25zZUJ5dGVzLFxuICAgIGRlZmluZWQsXG4gICAgaGFzRXhwaXJlZCxcbiAgICBzbGVlcCxcbiAgICBzdHJlYW1Ub0J1ZmZlcixcbiAgICB1dWlkdjRQYXR0ZXJuXG59IGZyb20gXCIuLi9zaGFyZWRcIjtcbmltcG9ydCB7IHJldHJ5T3AsIHRocm90dGxlIH0gZnJvbSBcIi4uL3Rocm90dGxlXCI7XG5pbXBvcnQgeyBGdW5jdGlvbkNhbGwsIFdyYXBwZXJPcHRpb25zIH0gZnJvbSBcIi4uL3dyYXBwZXJcIjtcbmltcG9ydCAqIGFzIGF3c05wbSBmcm9tIFwiLi9hd3MtbnBtXCI7XG5pbXBvcnQgeyBBd3NMYXllckluZm8gfSBmcm9tIFwiLi9hd3MtbnBtXCI7XG5pbXBvcnQge1xuICAgIGNyZWF0ZVNOU1RvcGljLFxuICAgIGNyZWF0ZVNRU1F1ZXVlLFxuICAgIHByb2Nlc3NBd3NFcnJvck1lc3NhZ2UsXG4gICAgcHVibGlzaEZ1bmN0aW9uQ2FsbE1lc3NhZ2UsXG4gICAgcmVjZWl2ZU1lc3NhZ2VzXG59IGZyb20gXCIuL2F3cy1xdWV1ZVwiO1xuaW1wb3J0IHsgZ2V0TG9nR3JvdXBOYW1lLCBnZXRMb2dVcmwgfSBmcm9tIFwiLi9hd3Mtc2hhcmVkXCI7XG5pbXBvcnQgKiBhcyBhd3NUcmFtcG9saW5lIGZyb20gXCIuL2F3cy10cmFtcG9saW5lXCI7XG5cbmV4cG9ydCBjb25zdCBkZWZhdWx0R2NXb3JrZXIgPSB0aHJvdHRsZShcbiAgICB7IGNvbmN1cnJlbmN5OiA1LCByYXRlOiA1LCBidXJzdDogMiB9LFxuICAgIGFzeW5jICh3b3JrOiBBd3NHY1dvcmssIHNlcnZpY2VzOiBBd3NTZXJ2aWNlcykgPT4ge1xuICAgICAgICBzd2l0Y2ggKHdvcmsudHlwZSkge1xuICAgICAgICAgICAgY2FzZSBcIlNldExvZ1JldGVudGlvblwiOlxuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgY2FyZWZ1bGx5KFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmljZXMuY2xvdWR3YXRjaC5wdXRSZXRlbnRpb25Qb2xpY3koe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ0dyb3VwTmFtZTogd29yay5sb2dHcm91cE5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0ZW50aW9uSW5EYXlzOiB3b3JrLnJldGVudGlvbkluRGF5cyB8fCAxXG4gICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZy5nYyhgQWRkZWQgcmV0ZW50aW9uIHBvbGljeSAlT2AsIHdvcmspO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJEZWxldGVSZXNvdXJjZXNcIjpcbiAgICAgICAgICAgICAgICBhd2FpdCBkZWxldGVSZXNvdXJjZXMod29yay5yZXNvdXJjZXMsIHNlcnZpY2VzLCBsb2cuZ2MpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcIkRlbGV0ZUxheWVyVmVyc2lvblwiOlxuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgY2FyZWZ1bGx5KFxuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmljZXMubGFtYmRhLmRlbGV0ZUxheWVyVmVyc2lvbih7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5ZXJOYW1lOiB3b3JrLkxheWVyTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWZXJzaW9uTnVtYmVyOiB3b3JrLlZlcnNpb25OdW1iZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nLmdjKGBkZWxldGVkIGxheWVyICVPYCwgd29yayk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuKTtcblxuLyoqXG4gKiBBV1Mtc3BlY2lmaWMgb3B0aW9ucyBmb3Ige0BsaW5rIGZhYXN0QXdzfS5cbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBd3NPcHRpb25zIGV4dGVuZHMgQ29tbW9uT3B0aW9ucyB7XG4gICAgLyoqXG4gICAgICogVGhlIHJlZ2lvbiB0byBjcmVhdGUgcmVzb3VyY2VzIGluLiBHYXJiYWdlIGNvbGxlY3Rpb24gaXMgYWxzbyBsaW1pdGVkIHRvXG4gICAgICogdGhpcyByZWdpb24uIERlZmF1bHQ6IGBcInVzLXdlc3QtMlwiYC5cbiAgICAgKi9cbiAgICByZWdpb24/OiBBd3NSZWdpb247XG4gICAgLyoqXG4gICAgICogVGhlIHJvbGUgdGhhdCB0aGUgbGFtYmRhIGZ1bmN0aW9uIHdpbGwgYXNzdW1lIHdoZW4gZXhlY3V0aW5nIHVzZXIgY29kZS5cbiAgICAgKiBEZWZhdWx0OiBgXCJmYWFzdC1jYWNoZWQtbGFtYmRhLXJvbGVcImAuIFJhcmVseSB1c2VkLlxuICAgICAqIEByZW1hcmtzXG4gICAgICogV2hlbiBhIGxhbWJkYSBleGVjdXRlcywgaXQgZmlyc3QgYXNzdW1lcyBhblxuICAgICAqIHtAbGluayBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vbGFtYmRhL2xhdGVzdC9kZy9sYW1iZGEtaW50cm8tZXhlY3V0aW9uLXJvbGUuaHRtbCB8IGV4ZWN1dGlvbiByb2xlfVxuICAgICAqIHRvIGdyYW50IGFjY2VzcyB0byByZXNvdXJjZXMuXG4gICAgICpcbiAgICAgKiBCeSBkZWZhdWx0LCBmYWFzdC5qcyBjcmVhdGVzIHRoaXMgZXhlY3V0aW9uIHJvbGUgZm9yIHlvdSBhbmQgbGVhdmVzIGl0XG4gICAgICogcGVybWFuZW50bHkgaW4geW91ciBhY2NvdW50ICh0aGUgcm9sZSBpcyBzaGFyZWQgYWNyb3NzIGFsbCBsYW1iZGFcbiAgICAgKiBmdW5jdGlvbnMgY3JlYXRlZCBieSBmYWFzdC5qcykuIEJ5IGRlZmF1bHQsIGZhYXN0LmpzIGdyYW50cyBhZG1pbmlzdHJhdG9yXG4gICAgICogcHJpdmlsZWdlcyB0byB0aGlzIHJvbGUgc28geW91ciBjb2RlIGNhbiBwZXJmb3JtIGFueSBBV1Mgb3BlcmF0aW9uIGl0XG4gICAgICogcmVxdWlyZXMuXG4gICAgICpcbiAgICAgKiBZb3UgY2FuXG4gICAgICoge0BsaW5rIGh0dHBzOi8vY29uc29sZS5hd3MuYW1hem9uLmNvbS9pYW0vaG9tZSMvcm9sZXMgfCBjcmVhdGUgYSBjdXN0b20gcm9sZX1cbiAgICAgKiB0aGF0IHNwZWNpZmllcyBtb3JlIGxpbWl0ZWQgcGVybWlzc2lvbnMgaWYgeW91IHByZWZlciBub3QgdG8gZ3JhbnRcbiAgICAgKiBhZG1pbmlzdHJhdG9yIHByaXZpbGVnZXMuIEFueSByb2xlIHlvdSBhc3NpZ24gZm9yIGZhYXN0LmpzIG1vZHVsZXMgbmVlZHNcbiAgICAgKiBhdCBsZWFzdCB0aGUgZm9sbG93aW5nIHBlcm1pc3Npb25zOlxuICAgICAqXG4gICAgICogLSBFeGVjdXRpb24gUm9sZTpcbiAgICAgKiBgYGBqc29uXG4gICAgICogICB7XG4gICAgICogICAgICAgXCJWZXJzaW9uXCI6IFwiMjAxMi0xMC0xN1wiLFxuICAgICAqICAgICAgIFwiU3RhdGVtZW50XCI6IFtcbiAgICAgKiAgICAgICAgICAge1xuICAgICAqICAgICAgICAgICAgICAgXCJFZmZlY3RcIjogXCJBbGxvd1wiLFxuICAgICAqICAgICAgICAgICAgICAgXCJBY3Rpb25cIjogW1wibG9nczoqXCJdLFxuICAgICAqICAgICAgICAgICAgICAgXCJSZXNvdXJjZVwiOiBcImFybjphd3M6bG9nczoqOio6bG9nLWdyb3VwOmZhYXN0LSpcIlxuICAgICAqICAgICAgICAgICB9LFxuICAgICAqICAgICAgICAgICB7XG4gICAgICogICAgICAgICAgICAgICBcIkVmZmVjdFwiOiBcIkFsbG93XCIsXG4gICAgICogICAgICAgICAgICAgICBcIkFjdGlvblwiOiBbXCJzcXM6KlwiXSxcbiAgICAgKiAgICAgICAgICAgICAgIFwiUmVzb3VyY2VcIjogXCJhcm46YXdzOnNxczoqOio6ZmFhc3QtKlwiXG4gICAgICogICAgICAgICAgIH1cbiAgICAgKiAgICAgICBdXG4gICAgICogICB9XG4gICAgICogYGBgXG4gICAgICpcbiAgICAgKiAtIFRydXN0IHJlbGF0aW9uc2hpcCAoYWxzbyBrbm93biBhcyBgQXNzdW1lUm9sZVBvbGljeURvY3VtZW50YCBpbiB0aGUgQVdTXG4gICAgICogICBTREspOlxuICAgICAqIGBgYGpzb25cbiAgICAgKiAgIHtcbiAgICAgKiAgICAgXCJWZXJzaW9uXCI6IFwiMjAxMi0xMC0xN1wiLFxuICAgICAqICAgICBcIlN0YXRlbWVudFwiOiBbXG4gICAgICogICAgICAge1xuICAgICAqICAgICAgICAgXCJFZmZlY3RcIjogXCJBbGxvd1wiLFxuICAgICAqICAgICAgICAgXCJQcmluY2lwYWxcIjoge1xuICAgICAqICAgICAgICAgICBcIlNlcnZpY2VcIjogXCJsYW1iZGEuYW1hem9uYXdzLmNvbVwiXG4gICAgICogICAgICAgICB9LFxuICAgICAqICAgICAgICAgXCJBY3Rpb25cIjogXCJzdHM6QXNzdW1lUm9sZVwiXG4gICAgICogICAgICAgfVxuICAgICAqICAgICBdXG4gICAgICogICB9XG4gICAgICogYGBgXG4gICAgICpcbiAgICAgKi9cbiAgICBSb2xlTmFtZT86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gcGFzcyB0byBBV1MgTGFtYmRhIGNyZWF0aW9uLiBTZWVcbiAgICAgKiB7QGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2xhbWJkYS9sYXRlc3QvZGcvQVBJX0NyZWF0ZUZ1bmN0aW9uLmh0bWwgfCBDcmVhdGVGdW5jdGlvbn0uXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBJZiB5b3UgbmVlZCBzcGVjaWFsaXplZCBvcHRpb25zLCB5b3UgY2FuIHBhc3MgdGhlbSB0byB0aGUgQVdTIExhbWJkYSBTREtcbiAgICAgKiBkaXJlY3RseS4gTm90ZSB0aGF0IGlmIHlvdSBvdmVycmlkZSBhbnkgc2V0dGluZ3Mgc2V0IGJ5IGZhYXN0LmpzLCB5b3UgbWF5XG4gICAgICogY2F1c2UgZmFhc3QuanMgdG8gbm90IHdvcms6XG4gICAgICpcbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogICBjb25zdCByZXF1ZXN0OiBhd3MuTGFtYmRhLkNyZWF0ZUZ1bmN0aW9uUmVxdWVzdCA9IHtcbiAgICAgKiAgICAgICBGdW5jdGlvbk5hbWUsXG4gICAgICogICAgICAgUm9sZSxcbiAgICAgKiAgICAgICBSdW50aW1lOiBcIm5vZGVqczE0LnhcIixcbiAgICAgKiAgICAgICBIYW5kbGVyOiBcImluZGV4LnRyYW1wb2xpbmVcIixcbiAgICAgKiAgICAgICBDb2RlLFxuICAgICAqICAgICAgIERlc2NyaXB0aW9uOiBcImZhYXN0IHRyYW1wb2xpbmUgZnVuY3Rpb25cIixcbiAgICAgKiAgICAgICBUaW1lb3V0LFxuICAgICAqICAgICAgIE1lbW9yeVNpemUsXG4gICAgICogICAgICAgLi4uYXdzTGFtYmRhT3B0aW9uc1xuICAgICAqICAgfTtcbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBhd3NMYW1iZGFPcHRpb25zPzogUGFydGlhbDxMYW1iZGEuQ3JlYXRlRnVuY3Rpb25SZXF1ZXN0PjtcblxuICAgIC8qKlxuICAgICAqIEFkZGl0aW9uYWwgb3B0aW9ucyB0byBwYXNzIHRvIGFsbCBBV1Mgc2VydmljZXMuIFNlZVxuICAgICAqIHtAbGluayBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTSmF2YVNjcmlwdFNESy9sYXRlc3QvQVdTL0NvbmZpZy5odG1sIHwgQVdTLkNvbmZpZ30uXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBJZiB5b3UgbmVlZCB0byBzcGVjaWZ5IEFXUyBvcHRpb25zIHN1Y2ggYXMgY3JlZGVudGlhbHMsIHlvdSBjYW4gcGFzcyBzZXRcbiAgICAgKiB0aGVzZSBvcHRpb25zIGhlcmUuIE5vdGUgdGhhdCBmYWFzdC5qcyB3aWxsIG92ZXJyaWRlIHNvbWUgb3B0aW9ucyBldmVuIGlmXG4gICAgICogdGhleSBhcmUgc3BlY2lmaWVkIGhlcmUsIHNwZWNpZmljYWxseSB0aGUgb3B0aW9ucyB1c2VkIHRvIGNyZWF0ZSB0aGVcbiAgICAgKiBgTGFtYmRhYCBzZXJ2aWNlLCB0byBlbnN1cmUgdGhleSBhbGxvdyBmb3IgZmFhc3QgdG8gZnVuY3Rpb24gY29ycmVjdGx5LlxuICAgICAqIE9wdGlvbnMgc2V0IGluIHtAbGluayBDb21tb25PcHRpb25zfSBvdmVycmlkZSB0aG9zZSBzZXQgaGVyZS5cbiAgICAgKlxuICAgICAqIEV4YW1wbGUgb2YgcGFzc2luZyBpbiBjcmVkZW50aWFsczpcbiAgICAgKlxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiAgIGNvbnN0IGNyZWRlbnRpYWxzID0geyBhY2Nlc3NLZXlJZCwgc2VjcmV0QWNjZXNzS2V5IH07XG4gICAgICogICBjb25zdCBtID0gYXdhaXQgZmFhc3RBd3MoZnVuY3MsIHsgY3JlZGVudGlhbHMgfSk7XG4gICAgICogYGBgXG4gICAgICovXG4gICAgYXdzQ29uZmlnPzogQ29uZmlndXJhdGlvbk9wdGlvbnM7XG5cbiAgICAvKiogQGludGVybmFsICovXG4gICAgX2djV29ya2VyPzogKHdvcms6IEF3c0djV29yaywgc2VydmljZXM6IEF3c1NlcnZpY2VzKSA9PiBQcm9taXNlPHZvaWQ+O1xufVxuXG5leHBvcnQgbGV0IGRlZmF1bHRzOiBSZXF1aXJlZDxBd3NPcHRpb25zPiA9IHtcbiAgICAuLi5jb21tb25EZWZhdWx0cyxcbiAgICByZWdpb246IFwidXMtd2VzdC0yXCIsXG4gICAgUm9sZU5hbWU6IFwiZmFhc3QtY2FjaGVkLWxhbWJkYS1yb2xlXCIsXG4gICAgbWVtb3J5U2l6ZTogMTcyOCxcbiAgICBhd3NMYW1iZGFPcHRpb25zOiB7fSxcbiAgICBhd3NDb25maWc6IHt9LFxuICAgIF9nY1dvcmtlcjogZGVmYXVsdEdjV29ya2VyXG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIEF3c1ByaWNlcyB7XG4gICAgbGFtYmRhUGVyUmVxdWVzdDogbnVtYmVyO1xuICAgIGxhbWJkYVBlckdiU2Vjb25kOiBudW1iZXI7XG4gICAgc25zUGVyNjRrUHVibGlzaDogbnVtYmVyO1xuICAgIHNxc1BlcjY0a1JlcXVlc3Q6IG51bWJlcjtcbiAgICBkYXRhT3V0UGVyR2I6IG51bWJlcjtcbiAgICBsb2dzSW5nZXN0ZWRQZXJHYjogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgQXdzTWV0cmljcyB7XG4gICAgb3V0Ym91bmRCeXRlcyA9IDA7XG4gICAgc25zNjRrUmVxdWVzdHMgPSAwO1xuICAgIHNxczY0a1JlcXVlc3RzID0gMDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBd3NSZXNvdXJjZXMge1xuICAgIEZ1bmN0aW9uTmFtZTogc3RyaW5nO1xuICAgIFJvbGVOYW1lOiBzdHJpbmc7XG4gICAgcmVnaW9uOiBBd3NSZWdpb247XG4gICAgUmVzcG9uc2VRdWV1ZVVybD86IHN0cmluZztcbiAgICBSZXNwb25zZVF1ZXVlQXJuPzogc3RyaW5nO1xuICAgIFJlcXVlc3RUb3BpY0Fybj86IHN0cmluZztcbiAgICBTTlNMYW1iZGFTdWJzY3JpcHRpb25Bcm4/OiBzdHJpbmc7XG4gICAgbG9nR3JvdXBOYW1lOiBzdHJpbmc7XG4gICAgbGF5ZXI/OiBBd3NMYXllckluZm87XG4gICAgQnVja2V0Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEF3c1NlcnZpY2VzIHtcbiAgICByZWFkb25seSBsYW1iZGE6IExhbWJkYTtcbiAgICByZWFkb25seSBsYW1iZGEyOiBMYW1iZGE7IC8vIFNwZWNpYWwgTGFtYmRhIGluc3RhbmNlIGNvbmZpZ3VyZWQgZm9yIGludm9jYXRpb25zLlxuICAgIHJlYWRvbmx5IGNsb3Vkd2F0Y2g6IENsb3VkV2F0Y2hMb2dzO1xuICAgIHJlYWRvbmx5IGlhbTogSUFNO1xuICAgIHJlYWRvbmx5IHNxczogU1FTO1xuICAgIHJlYWRvbmx5IHNuczogU05TO1xuICAgIHJlYWRvbmx5IHByaWNpbmc6IFByaWNpbmc7XG4gICAgcmVhZG9ubHkgc3RzOiBTVFM7XG4gICAgcmVhZG9ubHkgczM6IFMzO1xufVxuXG4vKipcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBd3NTdGF0ZSB7XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIHJlc291cmNlczogQXdzUmVzb3VyY2VzO1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBzZXJ2aWNlczogQXdzU2VydmljZXM7XG4gICAgLyoqIEBpbnRlcm5hbCAqL1xuICAgIG9wdGlvbnM6IFJlcXVpcmVkPEF3c09wdGlvbnM+O1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBtZXRyaWNzOiBBd3NNZXRyaWNzO1xuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBnY1Byb21pc2U/OiBQcm9taXNlPFwiZG9uZVwiIHwgXCJza2lwcGVkXCI+O1xufVxuXG5leHBvcnQgdHlwZSBBd3NHY1dvcmsgPVxuICAgIHwge1xuICAgICAgICAgIHR5cGU6IFwiU2V0TG9nUmV0ZW50aW9uXCI7XG4gICAgICAgICAgbG9nR3JvdXBOYW1lOiBzdHJpbmc7XG4gICAgICAgICAgcmV0ZW50aW9uSW5EYXlzOiBudW1iZXI7XG4gICAgICB9XG4gICAgfCB7XG4gICAgICAgICAgdHlwZTogXCJEZWxldGVSZXNvdXJjZXNcIjtcbiAgICAgICAgICByZXNvdXJjZXM6IEF3c1Jlc291cmNlcztcbiAgICAgIH1cbiAgICB8IHtcbiAgICAgICAgICB0eXBlOiBcIkRlbGV0ZUxheWVyVmVyc2lvblwiO1xuICAgICAgICAgIExheWVyTmFtZTogc3RyaW5nO1xuICAgICAgICAgIFZlcnNpb25OdW1iZXI6IG51bWJlcjtcbiAgICAgIH07XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjYXJlZnVsbHk8VT4oYXJnOiBSZXF1ZXN0PFUsIEFXU0Vycm9yPikge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBhcmcucHJvbWlzZSgpO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGxvZy53YXJuKGVycik7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBxdWlldGx5PFU+KGFyZzogUmVxdWVzdDxVLCBBV1NFcnJvcj4pIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgYXJnLnByb21pc2UoKTtcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxufVxuXG5leHBvcnQgY29uc3QgY3JlYXRlQXdzQXBpcyA9IHRocm90dGxlKFxuICAgIHsgY29uY3VycmVuY3k6IDEgfSxcbiAgICBhc3luYyAocmVnaW9uOiBBd3NSZWdpb24sIGF3c0NvbmZpZzogQ29uZmlndXJhdGlvbk9wdGlvbnMgPSB7fSkgPT4ge1xuICAgICAgICBjb25zdCBsb2dnZXIgPSBsb2cuYXdzc2RrLmVuYWJsZWQgPyB7IGxvZzogbG9nLmF3c3NkayB9IDogdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBjb21tb246IENvbmZpZ3VyYXRpb25PcHRpb25zID0ge1xuICAgICAgICAgICAgbWF4UmV0cmllczogNixcbiAgICAgICAgICAgIGNvcnJlY3RDbG9ja1NrZXc6IHRydWUsXG4gICAgICAgICAgICBsb2dnZXIsXG4gICAgICAgICAgICAuLi5hd3NDb25maWcsXG4gICAgICAgICAgICByZWdpb25cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgYWdlbnQgPSBuZXcgaHR0cHMuQWdlbnQoeyBrZWVwQWxpdmU6IHRydWUsIG1heFNvY2tldHM6IDEwMDAsIHRpbWVvdXQ6IDAgfSk7XG4gICAgICAgIGNvbnN0IHNlcnZpY2VzOiBBd3NTZXJ2aWNlcyA9IHtcbiAgICAgICAgICAgIGlhbTogbmV3IElBTSh7IGFwaVZlcnNpb246IFwiMjAxMC0wNS0wOFwiLCAuLi5jb21tb24gfSksXG4gICAgICAgICAgICBsYW1iZGE6IG5ldyBMYW1iZGEoeyBhcGlWZXJzaW9uOiBcIjIwMTUtMDMtMzFcIiwgLi4uY29tbW9uIH0pLFxuICAgICAgICAgICAgLy8gU3BlY2lhbCBMYW1iZGEgaW5zdGFuY2Ugd2l0aCBjb25maWd1cmF0aW9uIG9wdGltaXplZCBmb3JcbiAgICAgICAgICAgIC8vIGludm9jYXRpb25zLlxuICAgICAgICAgICAgbGFtYmRhMjogbmV3IExhbWJkYSh7XG4gICAgICAgICAgICAgICAgYXBpVmVyc2lvbjogXCIyMDE1LTAzLTMxXCIsXG4gICAgICAgICAgICAgICAgLi4uY29tbW9uLFxuICAgICAgICAgICAgICAgIC8vIFJldHJpZXMgYXJlIGhhbmRsZWQgYnkgZmFhc3QuanMsIG5vdCB0aGUgc2RrLlxuICAgICAgICAgICAgICAgIG1heFJldHJpZXM6IDAsXG4gICAgICAgICAgICAgICAgLy8gVGhlIGRlZmF1bHQgMTIwcyB0aW1lb3V0IGlzIHRvbyBzaG9ydCwgZXNwZWNpYWxseSBmb3IgaHR0cHNcbiAgICAgICAgICAgICAgICAvLyBtb2RlLlxuICAgICAgICAgICAgICAgIGh0dHBPcHRpb25zOiB7IHRpbWVvdXQ6IDAsIGFnZW50IH1cbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgY2xvdWR3YXRjaDogbmV3IENsb3VkV2F0Y2hMb2dzKHsgYXBpVmVyc2lvbjogXCIyMDE0LTAzLTI4XCIsIC4uLmNvbW1vbiB9KSxcbiAgICAgICAgICAgIHNxczogbmV3IFNRUyh7IGFwaVZlcnNpb246IFwiMjAxMi0xMS0wNVwiLCAuLi5jb21tb24gfSksXG4gICAgICAgICAgICBzbnM6IG5ldyBTTlMoeyBhcGlWZXJzaW9uOiBcIjIwMTAtMDMtMzFcIiwgLi4uY29tbW9uIH0pLFxuICAgICAgICAgICAgcHJpY2luZzogbmV3IFByaWNpbmcoeyByZWdpb246IFwidXMtZWFzdC0xXCIsIC4uLmNvbW1vbiB9KSxcbiAgICAgICAgICAgIHN0czogbmV3IFNUUyh7IGFwaVZlcnNpb246IFwiMjAxMS0wNi0xNVwiLCAuLi5jb21tb24gfSksXG4gICAgICAgICAgICBzMzogbmV3IFMzKHsgYXBpVmVyc2lvbjogXCIyMDA2LTAzLTAxXCIsIC4uLmNvbW1vbiB9KVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gc2VydmljZXM7XG4gICAgfVxuKTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGVuc3VyZVJvbGVSYXcoXG4gICAgUm9sZU5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlczogQXdzU2VydmljZXMsXG4gICAgY3JlYXRlUm9sZTogYm9vbGVhblxuKSB7XG4gICAgY29uc3QgeyBpYW0gfSA9IHNlcnZpY2VzO1xuICAgIGxvZy5pbmZvKGBDaGVja2luZyBmb3IgY2FjaGVkIGxhbWJkYSByb2xlYCk7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBpYW0uZ2V0Um9sZSh7IFJvbGVOYW1lIH0pLnByb21pc2UoKTtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlLlJvbGU7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgaWYgKCFjcmVhdGVSb2xlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihlcnIsIGBjb3VsZCBub3QgZmluZCByb2xlIFwiJHtSb2xlTmFtZX1cImApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxvZy5pbmZvKGBDcmVhdGluZyBkZWZhdWx0IHJvbGUgXCIke1JvbGVOYW1lfVwiIGZvciBmYWFzdCB0cmFtcG9saW5lIGZ1bmN0aW9uYCk7XG4gICAgY29uc3QgQXNzdW1lUm9sZVBvbGljeURvY3VtZW50ID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBWZXJzaW9uOiBcIjIwMTItMTAtMTdcIixcbiAgICAgICAgU3RhdGVtZW50OiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgUHJpbmNpcGFsOiB7IFNlcnZpY2U6IFwibGFtYmRhLmFtYXpvbmF3cy5jb21cIiB9LFxuICAgICAgICAgICAgICAgIEFjdGlvbjogXCJzdHM6QXNzdW1lUm9sZVwiLFxuICAgICAgICAgICAgICAgIEVmZmVjdDogXCJBbGxvd1wiXG4gICAgICAgICAgICB9XG4gICAgICAgIF1cbiAgICB9KTtcbiAgICBjb25zdCByb2xlUGFyYW1zOiBJQU0uQ3JlYXRlUm9sZVJlcXVlc3QgPSB7XG4gICAgICAgIEFzc3VtZVJvbGVQb2xpY3lEb2N1bWVudCxcbiAgICAgICAgUm9sZU5hbWUsXG4gICAgICAgIERlc2NyaXB0aW9uOiBcInJvbGUgZm9yIGxhbWJkYSBmdW5jdGlvbnMgY3JlYXRlZCBieSBmYWFzdFwiLFxuICAgICAgICBNYXhTZXNzaW9uRHVyYXRpb246IDM2MDBcbiAgICB9O1xuICAgIGxvZy5pbmZvKGBDYWxsaW5nIGNyZWF0ZVJvbGVgKTtcbiAgICBjb25zdCBQb2xpY3lBcm4gPSBcImFybjphd3M6aWFtOjphd3M6cG9saWN5L0FkbWluaXN0cmF0b3JBY2Nlc3NcIjtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCByb2xlUmVzcG9uc2UgPSBhd2FpdCBpYW0uY3JlYXRlUm9sZShyb2xlUGFyYW1zKS5wcm9taXNlKCk7XG4gICAgICAgIGxvZy5pbmZvKGBBdHRhY2hpbmcgYWRtaW5pc3RyYXRvciByb2xlIHBvbGljeWApO1xuICAgICAgICBhd2FpdCBpYW0uYXR0YWNoUm9sZVBvbGljeSh7IFJvbGVOYW1lLCBQb2xpY3lBcm4gfSkucHJvbWlzZSgpO1xuICAgICAgICByZXR1cm4gcm9sZVJlc3BvbnNlLlJvbGU7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgaWYgKGVyci5jb2RlID09PSBcIkVudGl0eUFscmVhZHlFeGlzdHNcIikge1xuICAgICAgICAgICAgYXdhaXQgc2xlZXAoNTAwMCk7XG4gICAgICAgICAgICBjb25zdCByb2xlUmVzcG9uc2UgPSBhd2FpdCBpYW0uZ2V0Um9sZSh7IFJvbGVOYW1lIH0pLnByb21pc2UoKTtcbiAgICAgICAgICAgIGF3YWl0IGlhbS5hdHRhY2hSb2xlUG9saWN5KHsgUm9sZU5hbWUsIFBvbGljeUFybiB9KS5wcm9taXNlKCk7XG4gICAgICAgICAgICByZXR1cm4gcm9sZVJlc3BvbnNlLlJvbGU7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoZXJyLCBgZmFpbGVkIHRvIGNyZWF0ZSByb2xlIFwiJHtSb2xlTmFtZX1cImApO1xuICAgIH1cbn1cblxuZXhwb3J0IGNvbnN0IGVuc3VyZVJvbGUgPSB0aHJvdHRsZShcbiAgICB7IGNvbmN1cnJlbmN5OiAxLCByYXRlOiAyLCBtZW1vaXplOiB0cnVlLCByZXRyeTogMTIgfSxcbiAgICBlbnN1cmVSb2xlUmF3XG4pO1xuXG5jb25zdCBSZXNwb25zZVF1ZXVlSWQgPSBhd3NUcmFtcG9saW5lLklOVk9DQVRJT05fVEVTVF9RVUVVRTtcbmNvbnN0IGVtcHR5RmNhbGwgPSB7IGNhbGxJZDogXCIwXCIsIG1vZHVsZVBhdGg6IFwiXCIsIG5hbWU6IFwiXCIsIGFyZ3M6IFwiXCIsIFJlc3BvbnNlUXVldWVJZCB9O1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlTGF5ZXIoXG4gICAgbGFtYmRhOiBMYW1iZGEsXG4gICAgcGFja2FnZUpzb246IHN0cmluZyB8IG9iamVjdCB8IHVuZGVmaW5lZCxcbiAgICB1c2VEZXBlbmRlbmN5Q2FjaGluZzogYm9vbGVhbixcbiAgICBGdW5jdGlvbk5hbWU6IHN0cmluZyxcbiAgICByZWdpb246IEF3c1JlZ2lvbixcbiAgICByZXRlbnRpb25JbkRheXM6IG51bWJlcixcbiAgICBhd3NMYW1iZGFPcHRpb25zOiBQYXJ0aWFsPExhbWJkYS5DcmVhdGVGdW5jdGlvblJlcXVlc3Q+XG4pOiBQcm9taXNlPEF3c0xheWVySW5mbyB8IHVuZGVmaW5lZD4ge1xuICAgIGlmICghcGFja2FnZUpzb24pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsb2cuaW5mbyhgQnVpbGRpbmcgbm9kZV9tb2R1bGVzYCk7XG5cbiAgICBjb25zdCBwYWNrYWdlSnNvbkNvbnRlbnRzID1cbiAgICAgICAgdHlwZW9mIHBhY2thZ2VKc29uID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICA/IChhd2FpdCByZWFkRmlsZShwYWNrYWdlSnNvbikpLnRvU3RyaW5nKClcbiAgICAgICAgICAgIDogSlNPTi5zdHJpbmdpZnkocGFja2FnZUpzb24pO1xuXG4gICAgbGV0IExheWVyTmFtZTtcbiAgICBpZiAodXNlRGVwZW5kZW5jeUNhY2hpbmcpIHtcbiAgICAgICAgY29uc3QgaGFzaGVyID0gY3JlYXRlSGFzaChcInNoYTI1NlwiKTtcbiAgICAgICAgaGFzaGVyLnVwZGF0ZShwYWNrYWdlSnNvbkNvbnRlbnRzKTtcbiAgICAgICAgaGFzaGVyLnVwZGF0ZShKU09OLnN0cmluZ2lmeShhd3NMYW1iZGFPcHRpb25zLkFyY2hpdGVjdHVyZXMgPz8gXCJcIikpO1xuICAgICAgICBjb25zdCBjYWNoZUtleSA9IGhhc2hlci5kaWdlc3QoXCJoZXhcIik7XG4gICAgICAgIExheWVyTmFtZSA9IGBmYWFzdC0ke2NhY2hlS2V5fWA7XG4gICAgICAgIGNvbnN0IGxheWVycyA9IGF3YWl0IHF1aWV0bHkobGFtYmRhLmxpc3RMYXllclZlcnNpb25zKHsgTGF5ZXJOYW1lIH0pKTtcbiAgICAgICAgaWYgKGxheWVycz8uTGF5ZXJWZXJzaW9ucz8ubGVuZ3RoID8/IDAgPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBbeyBWZXJzaW9uLCBMYXllclZlcnNpb25Bcm4sIENyZWF0ZWREYXRlIH1dID1cbiAgICAgICAgICAgICAgICBsYXllcnM/LkxheWVyVmVyc2lvbnMgPz8gW107XG4gICAgICAgICAgICBpZiAoIWhhc0V4cGlyZWQoQ3JlYXRlZERhdGUsIHJldGVudGlvbkluRGF5cykgJiYgVmVyc2lvbiAmJiBMYXllclZlcnNpb25Bcm4pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4geyBWZXJzaW9uLCBMYXllclZlcnNpb25Bcm4sIExheWVyTmFtZSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgTGF5ZXJOYW1lID0gRnVuY3Rpb25OYW1lO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGZhYXN0TW9kdWxlID0gYXdhaXQgZmFhc3RBd3MoYXdzTnBtLCB7XG4gICAgICAgICAgICByZWdpb24sXG4gICAgICAgICAgICB0aW1lb3V0OiAzMDAsXG4gICAgICAgICAgICBtZW1vcnlTaXplOiAyMDQ4LFxuICAgICAgICAgICAgbW9kZTogXCJodHRwc1wiLFxuICAgICAgICAgICAgZ2M6IFwib2ZmXCIsXG4gICAgICAgICAgICBtYXhSZXRyaWVzOiAwLFxuICAgICAgICAgICAgd2VicGFja09wdGlvbnM6IHtcbiAgICAgICAgICAgICAgICBleHRlcm5hbHM6IFtdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYXdzTGFtYmRhT3B0aW9uc1xuICAgICAgICB9KTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGluc3RhbGxBcmdzOiBhd3NOcG0uTnBtSW5zdGFsbEFyZ3MgPSB7XG4gICAgICAgICAgICAgICAgcGFja2FnZUpzb25Db250ZW50cyxcbiAgICAgICAgICAgICAgICBMYXllck5hbWUsXG4gICAgICAgICAgICAgICAgRnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgICAgIHJlZ2lvbixcbiAgICAgICAgICAgICAgICByZXRlbnRpb25JbkRheXNcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCB7IGluc3RhbGxMb2csIGxheWVySW5mbyB9ID0gYXdhaXQgZmFhc3RNb2R1bGUuZnVuY3Rpb25zLm5wbUluc3RhbGwoXG4gICAgICAgICAgICAgICAgaW5zdGFsbEFyZ3NcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBsb2cuaW5mbyhpbnN0YWxsTG9nKTtcbiAgICAgICAgICAgIHJldHVybiBsYXllckluZm87XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICBhd2FpdCBmYWFzdE1vZHVsZS5jbGVhbnVwKCk7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihlcnIsIFwiZmFpbGVkIHRvIGNyZWF0ZSBsYW1iZGEgbGF5ZXIgZnJvbSBwYWNrYWdlSnNvblwiKTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2dVcmwoc3RhdGU6IEF3c1N0YXRlKSB7XG4gICAgY29uc3QgeyByZWdpb24sIEZ1bmN0aW9uTmFtZSB9ID0gc3RhdGUucmVzb3VyY2VzO1xuICAgIHJldHVybiBnZXRMb2dVcmwocmVnaW9uLCBGdW5jdGlvbk5hbWUpO1xufVxuXG5leHBvcnQgY29uc3QgaW5pdGlhbGl6ZSA9IHRocm90dGxlKFxuICAgIHsgY29uY3VycmVuY3k6IEluZmluaXR5LCByYXRlOiAyIH0sXG4gICAgYXN5bmMgKGZNb2R1bGU6IHN0cmluZywgbm9uY2U6IFVVSUQsIG9wdGlvbnM6IFJlcXVpcmVkPEF3c09wdGlvbnM+KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgcmVnaW9uLCB0aW1lb3V0LCBtZW1vcnlTaXplLCBlbnYsIGNvbmN1cnJlbmN5LCBtb2RlIH0gPSBvcHRpb25zO1xuICAgICAgICBpZiAoY29uY3VycmVuY3kgPiAxMDAgJiYgbW9kZSAhPT0gXCJxdWV1ZVwiKSB7XG4gICAgICAgICAgICBsb2cud2FybihgQ29uc2lkZXIgdXNpbmcgcXVldWUgbW9kZSBmb3IgaGlnaGVyIGxldmVscyBvZiBjb25jdXJyZW5jeTpgKTtcbiAgICAgICAgICAgIGxvZy53YXJuKGBodHRwczovL2ZhYXN0anMub3JnL2RvY3MvYXBpL2ZhYXN0anMuY29tbW9ub3B0aW9ucy5tb2RlYCk7XG4gICAgICAgIH1cbiAgICAgICAgbG9nLmluZm8oYENyZWF0aW5nIEFXUyBBUElzYCk7XG4gICAgICAgIGNvbnN0IHNlcnZpY2VzID0gYXdhaXQgY3JlYXRlQXdzQXBpcyhyZWdpb24sIG9wdGlvbnMuYXdzQ29uZmlnKTtcbiAgICAgICAgY29uc3QgeyBsYW1iZGEgfSA9IHNlcnZpY2VzO1xuICAgICAgICBjb25zdCBGdW5jdGlvbk5hbWUgPSBgZmFhc3QtJHtub25jZX1gO1xuICAgICAgICBjb25zdCB7IHBhY2thZ2VKc29uLCB1c2VEZXBlbmRlbmN5Q2FjaGluZywgZGVzY3JpcHRpb24gfSA9IG9wdGlvbnM7XG5cbiAgICAgICAgYXN5bmMgZnVuY3Rpb24gY3JlYXRlRnVuY3Rpb25SZXF1ZXN0KFxuICAgICAgICAgICAgQ29kZTogTGFtYmRhLkZ1bmN0aW9uQ29kZSxcbiAgICAgICAgICAgIFJvbGU6IHN0cmluZyxcbiAgICAgICAgICAgIHJlc3BvbnNlUXVldWVBcm46IHN0cmluZyxcbiAgICAgICAgICAgIGxheWVySW5mbz86IEF3c0xheWVySW5mb1xuICAgICAgICApIHtcbiAgICAgICAgICAgIGNvbnN0IHsgTGF5ZXJzID0gW10sIC4uLnJlc3QgfSA9IG9wdGlvbnMuYXdzTGFtYmRhT3B0aW9ucztcbiAgICAgICAgICAgIGlmIChsYXllckluZm8pIHtcbiAgICAgICAgICAgICAgICBMYXllcnMucHVzaChsYXllckluZm8uTGF5ZXJWZXJzaW9uQXJuKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJlcXVlc3Q6IExhbWJkYS5DcmVhdGVGdW5jdGlvblJlcXVlc3QgPSB7XG4gICAgICAgICAgICAgICAgRnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgICAgIFJvbGUsXG4gICAgICAgICAgICAgICAgUnVudGltZTogXCJub2RlanMxNC54XCIsXG4gICAgICAgICAgICAgICAgSGFuZGxlcjogXCJpbmRleC50cmFtcG9saW5lXCIsXG4gICAgICAgICAgICAgICAgQ29kZSxcbiAgICAgICAgICAgICAgICBEZXNjcmlwdGlvbjogXCJmYWFzdCB0cmFtcG9saW5lIGZ1bmN0aW9uXCIsXG4gICAgICAgICAgICAgICAgVGltZW91dDogdGltZW91dCxcbiAgICAgICAgICAgICAgICBNZW1vcnlTaXplOiBtZW1vcnlTaXplLFxuICAgICAgICAgICAgICAgIEVudmlyb25tZW50OiB7IFZhcmlhYmxlczogZW52IH0sXG4gICAgICAgICAgICAgICAgTGF5ZXJzLFxuICAgICAgICAgICAgICAgIC4uLnJlc3RcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBsb2cuaW5mbyhgY3JlYXRlRnVuY3Rpb25SZXF1ZXN0OiAlT2AsIHJlcXVlc3QpO1xuICAgICAgICAgICAgbGV0IGZ1bmM7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGZ1bmMgPSBhd2FpdCBsYW1iZGEuY3JlYXRlRnVuY3Rpb24ocmVxdWVzdCkucHJvbWlzZSgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IHJldHJ5T3AoMiwgKCkgPT5cbiAgICAgICAgICAgICAgICAgICAgbGFtYmRhLndhaXRGb3IoXCJmdW5jdGlvbkFjdGl2ZVwiLCB7IEZ1bmN0aW9uTmFtZSB9KS5wcm9taXNlKClcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyPy5tZXNzYWdlPy5tYXRjaCgvRnVuY3Rpb24gYWxyZWFkeSBleGlzdC8pKSB7XG4gICAgICAgICAgICAgICAgICAgIGZ1bmMgPSAoYXdhaXQgbGFtYmRhLmdldEZ1bmN0aW9uKHsgRnVuY3Rpb25OYW1lIH0pLnByb21pc2UoKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5Db25maWd1cmF0aW9uITtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihlcnIsIFwiQ3JlYXRlIGZ1bmN0aW9uIGZhaWx1cmVcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbG9nLmluZm8oXG4gICAgICAgICAgICAgICAgYENyZWF0ZWQgZnVuY3Rpb24gJHtmdW5jLkZ1bmN0aW9uTmFtZX0sIEZ1bmN0aW9uQXJuOiAke2Z1bmMuRnVuY3Rpb25Bcm59IFske2Rlc2NyaXB0aW9ufV1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbG9nLm1pbmltYWwoYENyZWF0ZWQgZnVuY3Rpb24gJHtmdW5jLkZ1bmN0aW9uTmFtZX0gWyR7ZGVzY3JpcHRpb259XWApO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb25maWcgPSBhd2FpdCByZXRyeU9wKFxuICAgICAgICAgICAgICAgICAgICAoZXJyLCBuKSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgbiA8IDUgJiYgZXJyPy5tZXNzYWdlPy5tYXRjaCgvZGVzdGluYXRpb24gQVJOLippcyBpbnZhbGlkLyksXG4gICAgICAgICAgICAgICAgICAgICgpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAucHV0RnVuY3Rpb25FdmVudEludm9rZUNvbmZpZyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZ1bmN0aW9uTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF4aW11bVJldHJ5QXR0ZW1wdHM6IDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1heGltdW1FdmVudEFnZUluU2Vjb25kczogMjE2MDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlc3RpbmF0aW9uQ29uZmlnOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPbkZhaWx1cmU6IHsgRGVzdGluYXRpb246IHJlc3BvbnNlUXVldWVBcm4gfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAucHJvbWlzZSgpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBsb2cuaW5mbyhgRnVuY3Rpb24gZXZlbnQgaW52b2NhdGlvbiBjb25maWc6ICVPYCwgY29uZmlnKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoZXJyLCBcInB1dEZ1bmN0aW9uRXZlbnRJbnZva2VDb25maWcgZmFpbHVyZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBmdW5jO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHsgd3JhcHBlclZlcmJvc2UgfSA9IG9wdGlvbnMuZGVidWdPcHRpb25zO1xuICAgICAgICBhc3luYyBmdW5jdGlvbiBjcmVhdGVDb2RlQnVuZGxlKCkge1xuICAgICAgICAgICAgY29uc3QgeyB0aW1lb3V0LCBjaGlsZFByb2Nlc3MsIG1vZGUgfSA9IG9wdGlvbnM7XG4gICAgICAgICAgICBjb25zdCBoYXNMYW1iZGFUaW1lb3V0QnVnID0gbW9kZSAhPT0gXCJxdWV1ZVwiICYmIHRpbWVvdXQgPj0gMTgwO1xuICAgICAgICAgICAgY29uc3QgY2hpbGRQcm9jZXNzVGltZW91dE1zID1cbiAgICAgICAgICAgICAgICBoYXNMYW1iZGFUaW1lb3V0QnVnICYmIGNoaWxkUHJvY2VzcyA/ICh0aW1lb3V0IC0gNSkgKiAxMDAwIDogMDtcbiAgICAgICAgICAgIGNvbnN0IGNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWIgPSBvcHRpb25zLmNoaWxkUHJvY2Vzc01lbW9yeU1iO1xuICAgICAgICAgICAgY29uc3Qgd3JhcHBlck9wdGlvbnM6IFdyYXBwZXJPcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIHdyYXBwZXJWZXJib3NlLFxuICAgICAgICAgICAgICAgIGNoaWxkUHJvY2Vzc1RpbWVvdXRNcyxcbiAgICAgICAgICAgICAgICBjaGlsZFByb2Nlc3NNZW1vcnlMaW1pdE1iXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc3QgYnVuZGxlID0gYXdzUGFja2VyKGZNb2R1bGUsIG9wdGlvbnMsIHdyYXBwZXJPcHRpb25zLCBGdW5jdGlvbk5hbWUpO1xuICAgICAgICAgICAgcmV0dXJuIHsgWmlwRmlsZTogYXdhaXQgc3RyZWFtVG9CdWZmZXIoKGF3YWl0IGJ1bmRsZSkuYXJjaGl2ZSkgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHsgUm9sZU5hbWUgfSA9IG9wdGlvbnM7XG4gICAgICAgIGNvbnN0IHN0YXRlOiBBd3NTdGF0ZSA9IHtcbiAgICAgICAgICAgIHJlc291cmNlczoge1xuICAgICAgICAgICAgICAgIEZ1bmN0aW9uTmFtZSxcbiAgICAgICAgICAgICAgICBSb2xlTmFtZSxcbiAgICAgICAgICAgICAgICByZWdpb24sXG4gICAgICAgICAgICAgICAgbG9nR3JvdXBOYW1lOiBnZXRMb2dHcm91cE5hbWUoRnVuY3Rpb25OYW1lKVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNlcnZpY2VzLFxuICAgICAgICAgICAgbWV0cmljczogbmV3IEF3c01ldHJpY3MoKSxcbiAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCB7IGdjLCByZXRlbnRpb25JbkRheXMsIF9nY1dvcmtlcjogZ2NXb3JrZXIgfSA9IG9wdGlvbnM7XG4gICAgICAgIGlmIChnYyA9PT0gXCJhdXRvXCIgfHwgZ2MgPT09IFwiZm9yY2VcIikge1xuICAgICAgICAgICAgbG9nLmdjKGBTdGFydGluZyBnYXJiYWdlIGNvbGxlY3RvcmApO1xuICAgICAgICAgICAgc3RhdGUuZ2NQcm9taXNlID0gY29sbGVjdEdhcmJhZ2UoXG4gICAgICAgICAgICAgICAgZ2NXb3JrZXIsXG4gICAgICAgICAgICAgICAgc2VydmljZXMsXG4gICAgICAgICAgICAgICAgcmVnaW9uLFxuICAgICAgICAgICAgICAgIHJldGVudGlvbkluRGF5cyxcbiAgICAgICAgICAgICAgICBnY1xuICAgICAgICAgICAgKS5jYXRjaChlcnIgPT4ge1xuICAgICAgICAgICAgICAgIGxvZy5nYyhgR2FyYmFnZSBjb2xsZWN0aW9uIGVycm9yOiAke2Vycn1gKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJza2lwcGVkXCIgYXMgY29uc3Q7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsb2cuaW5mbyhgQ3JlYXRpbmcgbGFtYmRhIGZ1bmN0aW9uYCk7XG4gICAgICAgICAgICBjb25zdCByb2xlUHJvbWlzZSA9IGVuc3VyZVJvbGUoXG4gICAgICAgICAgICAgICAgUm9sZU5hbWUsXG4gICAgICAgICAgICAgICAgc2VydmljZXMsXG4gICAgICAgICAgICAgICAgUm9sZU5hbWUgPT09IGRlZmF1bHRzLlJvbGVOYW1lXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgcmVzcG9uc2VRdWV1ZVByb21pc2UgPSBjcmVhdGVSZXNwb25zZVF1ZXVlSW1wbChzdGF0ZSwgRnVuY3Rpb25OYW1lKTtcbiAgICAgICAgICAgIGNvbnN0IHByaWNpbmdQcm9taXNlID0gcmVxdWVzdEF3c1ByaWNlcyhzZXJ2aWNlcy5wcmljaW5nLCByZWdpb24pO1xuICAgICAgICAgICAgY29uc3QgY29kZUJ1bmRsZVByb21pc2UgPSBjcmVhdGVDb2RlQnVuZGxlKCk7XG4gICAgICAgICAgICAvLyBFbnN1cmUgcm9sZSBleGlzdHMgYmVmb3JlIGNyZWF0aW5nIGxhbWJkYSBsYXllciwgd2hpY2ggYWxzbyBuZWVkcyB0aGUgcm9sZS5cbiAgICAgICAgICAgIGNvbnN0IHJvbGUgPSBhd2FpdCByb2xlUHJvbWlzZTtcbiAgICAgICAgICAgIGNvbnN0IGxheWVyUHJvbWlzZSA9IGNyZWF0ZUxheWVyKFxuICAgICAgICAgICAgICAgIHNlcnZpY2VzLmxhbWJkYSxcbiAgICAgICAgICAgICAgICBwYWNrYWdlSnNvbixcbiAgICAgICAgICAgICAgICB1c2VEZXBlbmRlbmN5Q2FjaGluZyxcbiAgICAgICAgICAgICAgICBGdW5jdGlvbk5hbWUsXG4gICAgICAgICAgICAgICAgcmVnaW9uLFxuICAgICAgICAgICAgICAgIHJldGVudGlvbkluRGF5cyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLmF3c0xhbWJkYU9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGNvbnN0IGNvZGVCdW5kbGUgPSBhd2FpdCBjb2RlQnVuZGxlUHJvbWlzZTtcbiAgICAgICAgICAgIGNvbnN0IHJlc3BvbnNlUXVldWVBcm4gPSBhd2FpdCByZXNwb25zZVF1ZXVlUHJvbWlzZTtcbiAgICAgICAgICAgIGNvbnN0IGxheWVyID0gYXdhaXQgbGF5ZXJQcm9taXNlO1xuICAgICAgICAgICAgaWYgKGxheWVyKSB7XG4gICAgICAgICAgICAgICAgc3RhdGUucmVzb3VyY2VzLmxheWVyID0gbGF5ZXI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBsYW1iZGFGbkFybiE6IHN0cmluZztcbiAgICAgICAgICAgIGNvbnN0IHJldHJ5YWJsZSA9IFtcbiAgICAgICAgICAgICAgICAvcm9sZS8sXG4gICAgICAgICAgICAgICAgL0tNUyBFeGNlcHRpb24vLFxuICAgICAgICAgICAgICAgIC9pbnRlcm5hbCBzZXJ2aWNlIGVycm9yLyxcbiAgICAgICAgICAgICAgICAvTGF5ZXIgdmVyc2lvbi9cbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBjb25zdCBzaG91bGRSZXRyeSA9IChlcnI6IEVycm9yLCBuOiBudW1iZXIpID0+XG4gICAgICAgICAgICAgICAgbiA8IDUgJiYgISFyZXRyeWFibGUuZmluZChyZWdleCA9PiBlcnI/Lm1lc3NhZ2U/Lm1hdGNoKHJlZ2V4KSk7XG5cbiAgICAgICAgICAgIGF3YWl0IHJldHJ5T3Aoc2hvdWxkUmV0cnksIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBsYW1iZGFGbiA9IGF3YWl0IGNyZWF0ZUZ1bmN0aW9uUmVxdWVzdChcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvZGVCdW5kbGUsXG4gICAgICAgICAgICAgICAgICAgICAgICByb2xlLkFybixcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlUXVldWVBcm4sXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXllclxuICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgIGxhbWJkYUZuQXJuID0gbGFtYmRhRm4uRnVuY3Rpb25Bcm4hO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZSByb2xlIGZvciB0aGUgbGFtYmRhIGZ1bmN0aW9uIHdhcyBjcmVhdGVkXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlY2VudGx5LCB0ZXN0IHRoYXQgdGhlIHJvbGUgd29ya3MgYnkgaW52b2tpbmcgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIGZ1bmN0aW9uLiBJZiBhbiBleGNlcHRpb24gb2NjdXJzLCB0aGUgZnVuY3Rpb24gaXNcbiAgICAgICAgICAgICAgICAgICAgLy8gZGVsZXRlZCBhbmQgcmUtZGVwbG95ZWQuIEVtcGlyaWNhbGx5LCB0aGlzIGlzIHRoZSB3YXlcbiAgICAgICAgICAgICAgICAgICAgLy8gdG8gZW5zdXJlIHN1Y2Nlc3NmdWwgbGFtYmRhIGNyZWF0aW9uIHdoZW4gYW4gSUFNIHJvbGVcbiAgICAgICAgICAgICAgICAgICAgLy8gaXMgcmVjZW50bHkgY3JlYXRlZC5cbiAgICAgICAgICAgICAgICAgICAgaWYgKERhdGUubm93KCkgLSByb2xlLkNyZWF0ZURhdGUuZ2V0VGltZSgpIDwgMzAwICogMTAwMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgeyBtZXRyaWNzIH0gPSBzdGF0ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZuID0gRnVuY3Rpb25OYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbmV2ZXIgPSBuZXcgUHJvbWlzZTx2b2lkPihfID0+IHt9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHJldHJ5T3AoMSwgKCkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnZva2VIdHRwcyhsYW1iZGEsIGZuLCBlbXB0eUZjYWxsLCBtZXRyaWNzLCBuZXZlcilcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqLyB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBsYW1iZGFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVsZXRlRnVuY3Rpb24oeyBGdW5jdGlvbk5hbWUgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAucHJvbWlzZSgpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLmNhdGNoKF8gPT4ge30pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBOZXcgbGFtYmRhIGZ1bmN0aW9uICR7RnVuY3Rpb25OYW1lfSBmYWlsZWQgaW52b2NhdGlvbiB0ZXN0YFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBjb25zdCB7IG1vZGUgfSA9IG9wdGlvbnM7XG4gICAgICAgICAgICBpZiAobW9kZSA9PT0gXCJxdWV1ZVwiKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgY3JlYXRlUmVxdWVzdFF1ZXVlSW1wbChzdGF0ZSwgRnVuY3Rpb25OYW1lLCBsYW1iZGFGbkFybik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCBwcmljaW5nUHJvbWlzZTtcbiAgICAgICAgICAgIGxvZy5pbmZvKGBMYW1iZGEgZnVuY3Rpb24gaW5pdGlhbGl6YXRpb24gY29tcGxldGUuYCk7XG4gICAgICAgICAgICByZXR1cm4gc3RhdGU7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGF3YWl0IGNsZWFudXAoc3RhdGUsIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlUmVzb3VyY2VzOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBkZWxldGVDYWNoZXM6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBnY1RpbWVvdXQ6IDMwXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGNhdGNoIHt9XG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICB7IGNhdXNlOiBlcnIsIG5hbWU6IEZhYXN0RXJyb3JOYW1lcy5FQ1JFQVRFIH0sXG4gICAgICAgICAgICAgICAgXCJmYWlsZWQgdG8gaW5pdGlhbGl6ZSBjbG91ZCBmdW5jdGlvblwiXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuKTtcblxuYXN5bmMgZnVuY3Rpb24gaW52b2tlKFxuICAgIHN0YXRlOiBBd3NTdGF0ZSxcbiAgICBjYWxsOiBGdW5jdGlvbkNhbGwsXG4gICAgY2FuY2VsOiBQcm9taXNlPHZvaWQ+XG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IG1ldHJpY3MsIHNlcnZpY2VzLCByZXNvdXJjZXMsIG9wdGlvbnMgfSA9IHN0YXRlO1xuICAgIHN3aXRjaCAob3B0aW9ucy5tb2RlKSB7XG4gICAgICAgIGNhc2UgXCJhdXRvXCI6XG4gICAgICAgIGNhc2UgXCJodHRwc1wiOlxuICAgICAgICAgICAgY29uc3QgeyBsYW1iZGEyIH0gPSBzZXJ2aWNlcztcbiAgICAgICAgICAgIGNvbnN0IHsgRnVuY3Rpb25OYW1lIH0gPSByZXNvdXJjZXM7XG4gICAgICAgICAgICBhd2FpdCBpbnZva2VIdHRwcyhsYW1iZGEyLCBGdW5jdGlvbk5hbWUsIGNhbGwsIG1ldHJpY3MsIGNhbmNlbCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIGNhc2UgXCJxdWV1ZVwiOlxuICAgICAgICAgICAgY29uc3QgeyBzbnMgfSA9IHNlcnZpY2VzO1xuICAgICAgICAgICAgY29uc3QgeyBSZXF1ZXN0VG9waWNBcm4gfSA9IHJlc291cmNlcztcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgcHVibGlzaEZ1bmN0aW9uQ2FsbE1lc3NhZ2Uoc25zLCBSZXF1ZXN0VG9waWNBcm4hLCBjYWxsLCBtZXRyaWNzKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIGVycixcbiAgICAgICAgICAgICAgICAgICAgYGludm9rZSBzbnMgZXJyb3IgJHtpbnNwZWN0KGNhbGwsIHVuZGVmaW5lZCwgOSl9YFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgfVxufVxuXG5mdW5jdGlvbiBwb2xsKHN0YXRlOiBBd3NTdGF0ZSwgY2FuY2VsOiBQcm9taXNlPHZvaWQ+KTogUHJvbWlzZTxQb2xsUmVzdWx0PiB7XG4gICAgcmV0dXJuIHJlY2VpdmVNZXNzYWdlcyhcbiAgICAgICAgc3RhdGUuc2VydmljZXMuc3FzLFxuICAgICAgICBzdGF0ZS5yZXNvdXJjZXMuUmVzcG9uc2VRdWV1ZVVybCEsXG4gICAgICAgIHN0YXRlLm1ldHJpY3MsXG4gICAgICAgIGNhbmNlbFxuICAgICk7XG59XG5cbmZ1bmN0aW9uIHJlc3BvbnNlUXVldWVJZChzdGF0ZTogQXdzU3RhdGUpOiBzdHJpbmcge1xuICAgIHJldHVybiBzdGF0ZS5yZXNvdXJjZXMuUmVzcG9uc2VRdWV1ZVVybCE7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGludm9rZUh0dHBzKFxuICAgIGxhbWJkYTogTGFtYmRhLFxuICAgIEZ1bmN0aW9uTmFtZTogc3RyaW5nLFxuICAgIG1lc3NhZ2U6IEZ1bmN0aW9uQ2FsbCxcbiAgICBtZXRyaWNzOiBBd3NNZXRyaWNzLFxuICAgIGNhbmNlbDogUHJvbWlzZTx2b2lkPlxuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVxdWVzdDogTGFtYmRhLkludm9jYXRpb25SZXF1ZXN0ID0ge1xuICAgICAgICBGdW5jdGlvbk5hbWUsXG4gICAgICAgIFBheWxvYWQ6IHNlcmlhbGl6ZShtZXNzYWdlKSxcbiAgICAgICAgTG9nVHlwZTogXCJOb25lXCJcbiAgICB9O1xuICAgIGNvbnN0IGF3c1JlcXVlc3QgPSBsYW1iZGEuaW52b2tlKHJlcXVlc3QpO1xuICAgIGNvbnN0IHJhd1Jlc3BvbnNlID0gYXdhaXQgUHJvbWlzZS5yYWNlKFthd3NSZXF1ZXN0LnByb21pc2UoKSwgY2FuY2VsXSk7XG4gICAgaWYgKCFyYXdSZXNwb25zZSkge1xuICAgICAgICBsb2cuaW5mbyhgY2FuY2VsbGluZyBsYW1iZGEgaW52b2tlYCk7XG4gICAgICAgIGF3c1JlcXVlc3QuYWJvcnQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBtZXRyaWNzLm91dGJvdW5kQnl0ZXMgKz0gY29tcHV0ZUh0dHBSZXNwb25zZUJ5dGVzKFxuICAgICAgICByYXdSZXNwb25zZS4kcmVzcG9uc2UuaHR0cFJlc3BvbnNlLmhlYWRlcnNcbiAgICApO1xuXG4gICAgaWYgKHJhd1Jlc3BvbnNlLkxvZ1Jlc3VsdCkge1xuICAgICAgICBsb2cuaW5mbyhCdWZmZXIuZnJvbShyYXdSZXNwb25zZS5Mb2dSZXN1bHQhLCBcImJhc2U2NFwiKS50b1N0cmluZygpKTtcbiAgICB9XG5cbiAgICBpZiAocmF3UmVzcG9uc2UuRnVuY3Rpb25FcnJvcikge1xuICAgICAgICBjb25zdCBlcnJvciA9IHByb2Nlc3NBd3NFcnJvck1lc3NhZ2UocmF3UmVzcG9uc2UuUGF5bG9hZCBhcyBzdHJpbmcpO1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWxldGVSb2xlKFJvbGVOYW1lOiBzdHJpbmcsIGlhbTogSUFNKSB7XG4gICAgY29uc3QgcG9saWNpZXMgPSBhd2FpdCBjYXJlZnVsbHkoaWFtLmxpc3RBdHRhY2hlZFJvbGVQb2xpY2llcyh7IFJvbGVOYW1lIH0pKTtcbiAgICBjb25zdCBBdHRhY2hlZFBvbGljaWVzID0gcG9saWNpZXM/LkF0dGFjaGVkUG9saWNpZXMgPz8gW107XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIEF0dGFjaGVkUG9saWNpZXMubWFwKHAgPT4gcC5Qb2xpY3lBcm4hKS5tYXAoUG9saWN5QXJuID0+XG4gICAgICAgICAgICBjYXJlZnVsbHkoaWFtLmRldGFjaFJvbGVQb2xpY3koeyBSb2xlTmFtZSwgUG9saWN5QXJuIH0pKVxuICAgICAgICApXG4gICAgKTtcbiAgICBjb25zdCByb2xlUG9saWN5TGlzdFJlc3BvbnNlID0gYXdhaXQgY2FyZWZ1bGx5KGlhbS5saXN0Um9sZVBvbGljaWVzKHsgUm9sZU5hbWUgfSkpO1xuICAgIGNvbnN0IFJvbGVQb2xpY2llcyA9IHJvbGVQb2xpY3lMaXN0UmVzcG9uc2U/LlBvbGljeU5hbWVzID8/IFtdO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBSb2xlUG9saWNpZXMubWFwKFBvbGljeU5hbWUgPT5cbiAgICAgICAgICAgIGNhcmVmdWxseShpYW0uZGVsZXRlUm9sZVBvbGljeSh7IFJvbGVOYW1lLCBQb2xpY3lOYW1lIH0pKVxuICAgICAgICApXG4gICAgKTtcbiAgICBhd2FpdCBjYXJlZnVsbHkoaWFtLmRlbGV0ZVJvbGUoeyBSb2xlTmFtZSB9KSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWxldGVSZXNvdXJjZXMoXG4gICAgcmVzb3VyY2VzOiBQYXJ0aWFsPEF3c1Jlc291cmNlcz4sXG4gICAgc2VydmljZXM6IEF3c1NlcnZpY2VzLFxuICAgIG91dHB1dDogKG1zZzogc3RyaW5nKSA9PiB2b2lkID0gbG9nLmluZm9cbikge1xuICAgIGNvbnN0IHtcbiAgICAgICAgRnVuY3Rpb25OYW1lLFxuICAgICAgICBSb2xlTmFtZSxcbiAgICAgICAgcmVnaW9uLFxuICAgICAgICBSZXF1ZXN0VG9waWNBcm4sXG4gICAgICAgIFJlc3BvbnNlUXVldWVVcmwsXG4gICAgICAgIFJlc3BvbnNlUXVldWVBcm4sXG4gICAgICAgIFNOU0xhbWJkYVN1YnNjcmlwdGlvbkFybixcbiAgICAgICAgbG9nR3JvdXBOYW1lLFxuICAgICAgICBsYXllcixcbiAgICAgICAgQnVja2V0LFxuICAgICAgICAuLi5yZXN0XG4gICAgfSA9IHJlc291cmNlcztcbiAgICBjb25zdCBfZXhoYXVzdGl2ZUNoZWNrOiBSZXF1aXJlZDx0eXBlb2YgcmVzdD4gPSB7fTtcblxuICAgIGNvbnN0IHsgbGFtYmRhLCBzcXMsIHNucywgaWFtLCBzMywgY2xvdWR3YXRjaCB9ID0gc2VydmljZXM7XG4gICAgaWYgKFNOU0xhbWJkYVN1YnNjcmlwdGlvbkFybikge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICBhd2FpdCBxdWlldGx5KHNucy51bnN1YnNjcmliZSh7IFN1YnNjcmlwdGlvbkFybjogU05TTGFtYmRhU3Vic2NyaXB0aW9uQXJuIH0pKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIG91dHB1dChgRGVsZXRlZCByZXF1ZXN0IHF1ZXVlIHN1YnNjcmlwdGlvbiB0byBsYW1iZGFgKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoUm9sZU5hbWUpIHtcbiAgICAgICAgYXdhaXQgZGVsZXRlUm9sZShSb2xlTmFtZSwgaWFtKTtcbiAgICB9XG4gICAgaWYgKFJlcXVlc3RUb3BpY0Fybikge1xuICAgICAgICBpZiAoYXdhaXQgcXVpZXRseShzbnMuZGVsZXRlVG9waWMoeyBUb3BpY0FybjogUmVxdWVzdFRvcGljQXJuIH0pKSkge1xuICAgICAgICAgICAgb3V0cHV0KGBEZWxldGVkIHJlcXVlc3QgcXVldWUgdG9waWM6ICR7UmVxdWVzdFRvcGljQXJufWApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChSZXNwb25zZVF1ZXVlVXJsKSB7XG4gICAgICAgIGlmIChhd2FpdCBxdWlldGx5KHNxcy5kZWxldGVRdWV1ZSh7IFF1ZXVlVXJsOiBSZXNwb25zZVF1ZXVlVXJsIH0pKSkge1xuICAgICAgICAgICAgb3V0cHV0KGBEZWxldGVkIHJlc3BvbnNlIHF1ZXVlOiAke1Jlc3BvbnNlUXVldWVVcmx9YCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKGxheWVyKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGF3YWl0IHF1aWV0bHkoXG4gICAgICAgICAgICAgICAgbGFtYmRhLmRlbGV0ZUxheWVyVmVyc2lvbih7XG4gICAgICAgICAgICAgICAgICAgIExheWVyTmFtZTogbGF5ZXIuTGF5ZXJOYW1lLFxuICAgICAgICAgICAgICAgICAgICBWZXJzaW9uTnVtYmVyOiBsYXllci5WZXJzaW9uXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIClcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBvdXRwdXQoYERlbGV0ZWQgbGFtYmRhIGxheWVyOiAke2xheWVyLkxheWVyTmFtZX06JHtsYXllci5WZXJzaW9ufWApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChCdWNrZXQpIHtcbiAgICAgICAgY29uc3Qgb2JqZWN0cyA9IGF3YWl0IHF1aWV0bHkoczMubGlzdE9iamVjdHNWMih7IEJ1Y2tldCwgUHJlZml4OiBcImZhYXN0LVwiIH0pKTtcbiAgICAgICAgaWYgKG9iamVjdHMpIHtcbiAgICAgICAgICAgIGNvbnN0IGtleXMgPSAob2JqZWN0cy5Db250ZW50cyB8fCBbXSkubWFwKGVsZW0gPT4gKHsgS2V5OiBlbGVtLktleSEgfSkpO1xuICAgICAgICAgICAgaWYgKGF3YWl0IHF1aWV0bHkoczMuZGVsZXRlT2JqZWN0cyh7IEJ1Y2tldCwgRGVsZXRlOiB7IE9iamVjdHM6IGtleXMgfSB9KSkpIHtcbiAgICAgICAgICAgICAgICBvdXRwdXQoYERlbGV0ZWQgczMgb2JqZWN0czogJHtrZXlzLmxlbmd0aH0gb2JqZWN0cyBpbiBidWNrZXQgJHtCdWNrZXR9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGF3YWl0IHF1aWV0bHkoczMuZGVsZXRlQnVja2V0KHsgQnVja2V0IH0pKSkge1xuICAgICAgICAgICAgb3V0cHV0KGBEZWxldGVkIHMzIGJ1Y2tldDogJHtCdWNrZXR9YCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKEZ1bmN0aW9uTmFtZSkge1xuICAgICAgICBpZiAoYXdhaXQgcXVpZXRseShsYW1iZGEuZGVsZXRlRnVuY3Rpb24oeyBGdW5jdGlvbk5hbWUgfSkpKSB7XG4gICAgICAgICAgICBvdXRwdXQoYERlbGV0ZWQgZnVuY3Rpb246ICR7RnVuY3Rpb25OYW1lfWApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChsb2dHcm91cE5hbWUpIHtcbiAgICAgICAgaWYgKGF3YWl0IHF1aWV0bHkoY2xvdWR3YXRjaC5kZWxldGVMb2dHcm91cCh7IGxvZ0dyb3VwTmFtZSB9KSkpIHtcbiAgICAgICAgICAgIG91dHB1dChgRGVsZXRlZCBsb2cgZ3JvdXA6ICR7bG9nR3JvdXBOYW1lfWApO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBhZGRMb2dSZXRlbnRpb25Qb2xpY3koRnVuY3Rpb25OYW1lOiBzdHJpbmcsIGNsb3Vkd2F0Y2g6IENsb3VkV2F0Y2hMb2dzKSB7XG4gICAgY29uc3QgbG9nR3JvdXBOYW1lID0gZ2V0TG9nR3JvdXBOYW1lKEZ1bmN0aW9uTmFtZSk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBxdWlldGx5KFxuICAgICAgICBjbG91ZHdhdGNoLnB1dFJldGVudGlvblBvbGljeSh7IGxvZ0dyb3VwTmFtZSwgcmV0ZW50aW9uSW5EYXlzOiAxIH0pXG4gICAgKTtcbiAgICBpZiAocmVzcG9uc2UgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBsb2cuaW5mbyhgQWRkZWQgMSBkYXkgcmV0ZW50aW9uIHBvbGljeSB0byBsb2cgZ3JvdXAgJHtsb2dHcm91cE5hbWV9YCk7XG4gICAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYW51cChzdGF0ZTogQXdzU3RhdGUsIG9wdGlvbnM6IFJlcXVpcmVkPENsZWFudXBPcHRpb25zPikge1xuICAgIGxvZy5pbmZvKGBhd3MgY2xlYW51cCBzdGFydGluZy5gKTtcbiAgICBpZiAoc3RhdGUuZ2NQcm9taXNlKSB7XG4gICAgICAgIGxvZy5pbmZvKGBXYWl0aW5nIGZvciBnYXJiYWdlIGNvbGxlY3Rpb24uLi5gKTtcbiAgICAgICAgYXdhaXQgc3RhdGUuZ2NQcm9taXNlO1xuICAgICAgICBsb2cuaW5mbyhgR2FyYmFnZSBjb2xsZWN0aW9uIGRvbmUuYCk7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuZGVsZXRlUmVzb3VyY2VzKSB7XG4gICAgICAgIGxvZy5pbmZvKGBDbGVhbmluZyB1cCBpbmZyYXN0cnVjdHVyZSBmb3IgJHtzdGF0ZS5yZXNvdXJjZXMuRnVuY3Rpb25OYW1lfS4uLmApO1xuICAgICAgICBhd2FpdCBhZGRMb2dSZXRlbnRpb25Qb2xpY3koXG4gICAgICAgICAgICBzdGF0ZS5yZXNvdXJjZXMuRnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgc3RhdGUuc2VydmljZXMuY2xvdWR3YXRjaFxuICAgICAgICApO1xuICAgICAgICAvLyBEb24ndCBkZWxldGUgY2FjaGVkIHJvbGUuIEl0IG1heSBiZSBpbiB1c2UgYnkgb3RoZXIgaW5zdGFuY2VzIG9mXG4gICAgICAgIC8vIGZhYXN0LiBEb24ndCBkZWxldGUgbG9ncy4gVGhleSBhcmUgb2Z0ZW4gdXNlZnVsLiBCeSBkZWZhdWx0IGxvZ1xuICAgICAgICAvLyBzdHJlYW0gcmV0ZW50aW9uIHdpbGwgYmUgMSBkYXksIGFuZCBnYyB3aWxsIGNsZWFuIG91dCB0aGUgbG9nIGdyb3VwXG4gICAgICAgIC8vIGFmdGVyIHRoZSBzdHJlYW1zIGFyZSBleHBpcmVkLiBEb24ndCBkZWxldGUgYSBsYW1iZGEgbGF5ZXIgdGhhdCBpc1xuICAgICAgICAvLyB1c2VkIHRvIGNhY2hlIHBhY2thZ2VzLlxuICAgICAgICBjb25zdCB7IGxvZ0dyb3VwTmFtZSwgUm9sZU5hbWUsIGxheWVyLCAuLi5yZXN0IH0gPSBzdGF0ZS5yZXNvdXJjZXM7XG4gICAgICAgIGF3YWl0IGRlbGV0ZVJlc291cmNlcyhyZXN0LCBzdGF0ZS5zZXJ2aWNlcyk7XG4gICAgICAgIGlmICghc3RhdGUub3B0aW9ucy51c2VEZXBlbmRlbmN5Q2FjaGluZyB8fCBvcHRpb25zLmRlbGV0ZUNhY2hlcykge1xuICAgICAgICAgICAgYXdhaXQgZGVsZXRlUmVzb3VyY2VzKHsgbGF5ZXIgfSwgc3RhdGUuc2VydmljZXMpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxvZy5pbmZvKGBhd3MgY2xlYW51cCBkb25lLmApO1xufVxuXG5jb25zdCBsb2dHcm91cE5hbWVSZWdleHAgPSBuZXcgUmVnRXhwKGBeL2F3cy9sYW1iZGEvKGZhYXN0LSR7dXVpZHY0UGF0dGVybn0pJGApO1xuXG5mdW5jdGlvbiBmdW5jdGlvbk5hbWVGcm9tTG9nR3JvdXAobG9nR3JvdXBOYW1lOiBzdHJpbmcpIHtcbiAgICBjb25zdCBtYXRjaCA9IGxvZ0dyb3VwTmFtZS5tYXRjaChsb2dHcm91cE5hbWVSZWdleHApO1xuICAgIHJldHVybiBtYXRjaCAmJiBtYXRjaFsxXTtcbn1cblxubGV0IGxhc3RHYzogbnVtYmVyIHwgdW5kZWZpbmVkO1xuXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJMYXN0R2MoKSB7XG4gICAgbGFzdEdjID0gdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBmb3JFYWNoUGFnZTxSPihcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nLFxuICAgIHJlcXVlc3Q6IFJlcXVlc3Q8UiwgQVdTRXJyb3I+LFxuICAgIHByb2Nlc3M6IChwYWdlOiBSKSA9PiBQcm9taXNlPHZvaWQ+XG4pIHtcbiAgICBjb25zdCB0aHJvdHRsZVBhZ2luZyA9IHRocm90dGxlKHsgY29uY3VycmVuY3k6IDEsIHJhdGU6IDEgfSwgYXN5bmMgKCkgPT4ge30pO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHJlcXVlc3QuZWFjaFBhZ2UoKGVyciwgcGFnZSwgZG9uZSkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgIGxvZy53YXJuKGBHQzogRXJyb3Igd2hlbiBsaXN0aW5nICR7ZGVzY3JpcHRpb259OiAke2Vycn1gKTtcbiAgICAgICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocGFnZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcHJvY2VzcyhwYWdlKS50aGVuKCgpID0+IHRocm90dGxlUGFnaW5nKCkudGhlbihkb25lKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjb2xsZWN0R2FyYmFnZShcbiAgICBleGVjdXRvcjogdHlwZW9mIGRlZmF1bHRHY1dvcmtlcixcbiAgICBzZXJ2aWNlczogQXdzU2VydmljZXMsXG4gICAgcmVnaW9uOiBBd3NSZWdpb24sXG4gICAgcmV0ZW50aW9uSW5EYXlzOiBudW1iZXIsXG4gICAgbW9kZTogXCJhdXRvXCIgfCBcImZvcmNlXCJcbik6IFByb21pc2U8XCJkb25lXCIgfCBcInNraXBwZWRcIj4ge1xuICAgIGlmIChleGVjdXRvciA9PT0gZGVmYXVsdEdjV29ya2VyKSB7XG4gICAgICAgIGlmIChtb2RlID09PSBcImF1dG9cIikge1xuICAgICAgICAgICAgaWYgKGxhc3RHYyAmJiBEYXRlLm5vdygpIDw9IGxhc3RHYyArIDM2MDAgKiAxMDAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwic2tpcHBlZFwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgZ2NFbnRyeSA9IGF3YWl0IGNhY2hlcy5hd3NHYy5nZXQoXCJnY1wiKTtcbiAgICAgICAgICAgIGlmIChnY0VudHJ5KSB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbGFzdEdjUGVyc2lzdGVudCA9IEpTT04ucGFyc2UoZ2NFbnRyeS50b1N0cmluZygpKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdEdjUGVyc2lzdGVudCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZW9mIGxhc3RHY1BlcnNpc3RlbnQgPT09IFwibnVtYmVyXCIgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIERhdGUubm93KCkgPD0gbGFzdEdjUGVyc2lzdGVudCArIDM2MDAgKiAxMDAwXG4gICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdEdjID0gbGFzdEdjUGVyc2lzdGVudDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBcInNraXBwZWRcIjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZy53YXJuKGVycik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxhc3RHYyA9IERhdGUubm93KCk7XG4gICAgICAgIGNhY2hlcy5hd3NHYy5zZXQoXCJnY1wiLCBsYXN0R2MudG9TdHJpbmcoKSk7XG4gICAgfVxuICAgIGNvbnN0IHByb21pc2VzOiBQcm9taXNlPHZvaWQ+W10gPSBbXTtcbiAgICBmdW5jdGlvbiBzY2hlZHVsZVdvcmsod29yazogQXdzR2NXb3JrKSB7XG4gICAgICAgIGlmIChleGVjdXRvciA9PT0gZGVmYXVsdEdjV29ya2VyKSB7XG4gICAgICAgICAgICBsb2cuZ2MoYFNjaGVkdWxpbmcgd29yayBwdXNoaW5nIHByb21pc2U6ICVPYCwgd29yayk7XG4gICAgICAgIH1cbiAgICAgICAgcHJvbWlzZXMucHVzaChleGVjdXRvcih3b3JrLCBzZXJ2aWNlcykpO1xuICAgIH1cbiAgICBjb25zdCBmdW5jdGlvbnNXaXRoTG9nR3JvdXBzID0gbmV3IFNldCgpO1xuXG4gICAgY29uc3QgbG9nR3JvdXBSZXF1ZXN0ID0gc2VydmljZXMuY2xvdWR3YXRjaC5kZXNjcmliZUxvZ0dyb3Vwcyh7XG4gICAgICAgIGxvZ0dyb3VwTmFtZVByZWZpeDogXCIvYXdzL2xhbWJkYS9mYWFzdC1cIlxuICAgIH0pO1xuICAgIGNvbnN0IGFjY291bnRJZCA9IGF3YWl0IGdldEFjY291bnRJZChzZXJ2aWNlcy5zdHMpO1xuICAgIGF3YWl0IGZvckVhY2hQYWdlKFwibG9nIGdyb3Vwc1wiLCBsb2dHcm91cFJlcXVlc3QsIGFzeW5jICh7IGxvZ0dyb3VwcyA9IFtdIH0pID0+IHtcbiAgICAgICAgbG9nR3JvdXBzLmZvckVhY2goZyA9PiB7XG4gICAgICAgICAgICBjb25zdCBGdW5jdGlvbk5hbWUgPSBmdW5jdGlvbk5hbWVGcm9tTG9nR3JvdXAoZy5sb2dHcm91cE5hbWUhKTtcbiAgICAgICAgICAgIGZ1bmN0aW9uc1dpdGhMb2dHcm91cHMuYWRkKEZ1bmN0aW9uTmFtZSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGxvZy5nYyhgTG9nIGdyb3VwcyBzaXplOiAke2xvZ0dyb3Vwcy5sZW5ndGh9YCk7XG5cbiAgICAgICAgZ2FyYmFnZUNvbGxlY3RMb2dHcm91cHMoXG4gICAgICAgICAgICBsb2dHcm91cHMsXG4gICAgICAgICAgICByZXRlbnRpb25JbkRheXMsXG4gICAgICAgICAgICByZWdpb24sXG4gICAgICAgICAgICBhY2NvdW50SWQsXG4gICAgICAgICAgICBzY2hlZHVsZVdvcmtcbiAgICAgICAgKTtcbiAgICB9KTtcblxuICAgIGNvbnN0IGxpc3RGdW5jdGlvbnNSZXF1ZXN0ID0gc2VydmljZXMubGFtYmRhLmxpc3RGdW5jdGlvbnMoKTtcbiAgICBhd2FpdCBmb3JFYWNoUGFnZShcbiAgICAgICAgXCJsYW1iZGEgZnVuY3Rpb25zXCIsXG4gICAgICAgIGxpc3RGdW5jdGlvbnNSZXF1ZXN0LFxuICAgICAgICBhc3luYyAoeyBGdW5jdGlvbnMgPSBbXSB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBmblBhdHRlcm4gPSBuZXcgUmVnRXhwKGBeZmFhc3QtJHt1dWlkdjRQYXR0ZXJufSRgKTtcbiAgICAgICAgICAgIGNvbnN0IGZ1bmNzID0gKEZ1bmN0aW9ucyB8fCBbXSlcbiAgICAgICAgICAgICAgICAuZmlsdGVyKGZuID0+IGZuLkZ1bmN0aW9uTmFtZSEubWF0Y2goZm5QYXR0ZXJuKSlcbiAgICAgICAgICAgICAgICAuZmlsdGVyKGZuID0+ICFmdW5jdGlvbnNXaXRoTG9nR3JvdXBzLmhhcyhmbi5GdW5jdGlvbk5hbWUpKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoZm4gPT4gaGFzRXhwaXJlZChmbi5MYXN0TW9kaWZpZWQsIHJldGVudGlvbkluRGF5cykpXG4gICAgICAgICAgICAgICAgLm1hcChmbiA9PiBmbi5GdW5jdGlvbk5hbWUhKTtcbiAgICAgICAgICAgIGRlbGV0ZUdhcmJhZ2VGdW5jdGlvbnMocmVnaW9uLCBhY2NvdW50SWQsIGZ1bmNzLCBzY2hlZHVsZVdvcmspO1xuICAgICAgICB9XG4gICAgKTtcblxuICAgIC8vIENvbGxlY3QgTGFtYmRhIExheWVyc1xuICAgIGNvbnN0IGxheWVyc1JlcXVlc3QgPSBzZXJ2aWNlcy5sYW1iZGEubGlzdExheWVycyh7XG4gICAgICAgIENvbXBhdGlibGVSdW50aW1lOiBcIm5vZGVqc1wiXG4gICAgfSk7XG4gICAgYXdhaXQgZm9yRWFjaFBhZ2UoXCJMYW1iZGEgTGF5ZXJzXCIsIGxheWVyc1JlcXVlc3QsIGFzeW5jICh7IExheWVycyA9IFtdIH0pID0+IHtcbiAgICAgICAgZm9yIChjb25zdCBsYXllciBvZiBMYXllcnMpIHtcbiAgICAgICAgICAgIGlmIChsYXllci5MYXllck5hbWUhLm1hdGNoKC9eZmFhc3QtLykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBsYXllclZlcnNpb25SZXF1ZXN0ID0gc2VydmljZXMubGFtYmRhLmxpc3RMYXllclZlcnNpb25zKHtcbiAgICAgICAgICAgICAgICAgICAgTGF5ZXJOYW1lOiBsYXllci5MYXllck5hbWUhLFxuICAgICAgICAgICAgICAgICAgICBDb21wYXRpYmxlUnVudGltZTogXCJub2RlanNcIlxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGF3YWl0IGZvckVhY2hQYWdlKFxuICAgICAgICAgICAgICAgICAgICBcIkxhbWJkYSBMYXllciBWZXJzaW9uc1wiLFxuICAgICAgICAgICAgICAgICAgICBsYXllclZlcnNpb25SZXF1ZXN0LFxuICAgICAgICAgICAgICAgICAgICBhc3luYyAoeyBMYXllclZlcnNpb25zID0gW10gfSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgTGF5ZXJWZXJzaW9ucy5mb3JFYWNoKGxheWVyVmVyc2lvbiA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhhc0V4cGlyZWQobGF5ZXJWZXJzaW9uLkNyZWF0ZWREYXRlLCByZXRlbnRpb25JbkRheXMpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjaGVkdWxlV29yayh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBcIkRlbGV0ZUxheWVyVmVyc2lvblwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGF5ZXJOYW1lOiBsYXllci5MYXllck5hbWUhLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVmVyc2lvbk51bWJlcjogbGF5ZXJWZXJzaW9uLlZlcnNpb24hXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xuICAgIGxvZy5nYyhgQXdhaXRpbmcgJHtwcm9taXNlcy5sZW5ndGh9IHNjaGVkdWxlZCB3b3JrIHByb21pc2VzYCk7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuICAgIHJldHVybiBcImRvbmVcIjtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEFjY291bnRJZChzdHM6IFNUUykge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgc3RzLmdldENhbGxlcklkZW50aXR5KCkucHJvbWlzZSgpO1xuICAgIGNvbnN0IHsgQWNjb3VudCwgQXJuLCBVc2VySWQgfSA9IHJlc3BvbnNlO1xuICAgIGxvZy5pbmZvKGBBY2NvdW50IElEOiAlT2AsIHsgQWNjb3VudCwgQXJuLCBVc2VySWQgfSk7XG4gICAgcmV0dXJuIHJlc3BvbnNlLkFjY291bnQhO1xufVxuXG5mdW5jdGlvbiBnYXJiYWdlQ29sbGVjdExvZ0dyb3VwcyhcbiAgICBsb2dHcm91cHM6IENsb3VkV2F0Y2hMb2dzLkxvZ0dyb3VwW10sXG4gICAgcmV0ZW50aW9uSW5EYXlzOiBudW1iZXIsXG4gICAgcmVnaW9uOiBBd3NSZWdpb24sXG4gICAgYWNjb3VudElkOiBzdHJpbmcsXG4gICAgc2NoZWR1bGVXb3JrOiAod29yazogQXdzR2NXb3JrKSA9PiB2b2lkXG4pIHtcbiAgICBjb25zdCBsb2dHcm91cHNNaXNzaW5nUmV0ZW50aW9uUG9saWN5ID0gbG9nR3JvdXBzLmZpbHRlcihcbiAgICAgICAgZyA9PiBnLnJldGVudGlvbkluRGF5cyA9PT0gdW5kZWZpbmVkXG4gICAgKTtcblxuICAgIGxvZy5nYyhgTG9nIGdyb3VwcyBtaXNzaW5nIHJldGVudGlvbjogJHtsb2dHcm91cHNNaXNzaW5nUmV0ZW50aW9uUG9saWN5Lmxlbmd0aH1gKTtcblxuICAgIGxvZ0dyb3Vwc01pc3NpbmdSZXRlbnRpb25Qb2xpY3kuZm9yRWFjaChnID0+IHtcbiAgICAgICAgc2NoZWR1bGVXb3JrKHtcbiAgICAgICAgICAgIHR5cGU6IFwiU2V0TG9nUmV0ZW50aW9uXCIsXG4gICAgICAgICAgICBsb2dHcm91cE5hbWU6IGcubG9nR3JvdXBOYW1lISxcbiAgICAgICAgICAgIHJldGVudGlvbkluRGF5c1xuICAgICAgICB9KTtcbiAgICB9KTtcblxuICAgIGNvbnN0IGdhcmJhZ2VGdW5jdGlvbnMgPSBsb2dHcm91cHNcbiAgICAgICAgLmZpbHRlcihnID0+IGhhc0V4cGlyZWQoZy5jcmVhdGlvblRpbWUsIHJldGVudGlvbkluRGF5cykpXG4gICAgICAgIC5tYXAoZyA9PiBmdW5jdGlvbk5hbWVGcm9tTG9nR3JvdXAoZy5sb2dHcm91cE5hbWUhKSlcbiAgICAgICAgLmZpbHRlcihkZWZpbmVkKTtcblxuICAgIGRlbGV0ZUdhcmJhZ2VGdW5jdGlvbnMocmVnaW9uLCBhY2NvdW50SWQsIGdhcmJhZ2VGdW5jdGlvbnMsIHNjaGVkdWxlV29yayk7XG59XG5cbmZ1bmN0aW9uIGRlbGV0ZUdhcmJhZ2VGdW5jdGlvbnMoXG4gICAgcmVnaW9uOiBBd3NSZWdpb24sXG4gICAgYWNjb3VudElkOiBzdHJpbmcsXG4gICAgZ2FyYmFnZUZ1bmN0aW9uczogc3RyaW5nW10sXG4gICAgc2NoZWR1bGVXb3JrOiAod29yazogQXdzR2NXb3JrKSA9PiB2b2lkXG4pIHtcbiAgICBnYXJiYWdlRnVuY3Rpb25zLmZvckVhY2goRnVuY3Rpb25OYW1lID0+IHtcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzOiBBd3NSZXNvdXJjZXMgPSB7XG4gICAgICAgICAgICBGdW5jdGlvbk5hbWUsXG4gICAgICAgICAgICByZWdpb24sXG4gICAgICAgICAgICBSb2xlTmFtZTogXCJcIixcbiAgICAgICAgICAgIFJlcXVlc3RUb3BpY0FybjogZ2V0U05TVG9waWNBcm4ocmVnaW9uLCBhY2NvdW50SWQsIEZ1bmN0aW9uTmFtZSksXG4gICAgICAgICAgICBSZXNwb25zZVF1ZXVlVXJsOiBnZXRSZXNwb25zZVF1ZXVlVXJsKHJlZ2lvbiwgYWNjb3VudElkLCBGdW5jdGlvbk5hbWUpLFxuICAgICAgICAgICAgbG9nR3JvdXBOYW1lOiBnZXRMb2dHcm91cE5hbWUoRnVuY3Rpb25OYW1lKSxcbiAgICAgICAgICAgIEJ1Y2tldDogRnVuY3Rpb25OYW1lXG4gICAgICAgIH07XG4gICAgICAgIHNjaGVkdWxlV29yayh7IHR5cGU6IFwiRGVsZXRlUmVzb3VyY2VzXCIsIHJlc291cmNlcyB9KTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGF3c1BhY2tlcihcbiAgICBmdW5jdGlvbk1vZHVsZTogc3RyaW5nLFxuICAgIG9wdGlvbnM6IENvbW1vbk9wdGlvbnMsXG4gICAgd3JhcHBlck9wdGlvbnM6IFdyYXBwZXJPcHRpb25zLFxuICAgIEZ1bmN0aW9uTmFtZTogc3RyaW5nXG4pOiBQcm9taXNlPFBhY2tlclJlc3VsdD4ge1xuICAgIHJldHVybiBwYWNrZXIoXG4gICAgICAgIGF3c1RyYW1wb2xpbmUsXG4gICAgICAgIGZ1bmN0aW9uTW9kdWxlLFxuICAgICAgICB7XG4gICAgICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICAgICAgd2VicGFja09wdGlvbnM6IG1lcmdlKG9wdGlvbnMud2VicGFja09wdGlvbnMgPz8ge30sIHtcbiAgICAgICAgICAgICAgICBleHRlcm5hbHM6IFtuZXcgUmVnRXhwKFwiXmF3cy1zZGsvP1wiKV1cbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0sXG4gICAgICAgIHdyYXBwZXJPcHRpb25zLFxuICAgICAgICBGdW5jdGlvbk5hbWVcbiAgICApO1xufVxuXG5mdW5jdGlvbiBnZXRTTlNUb3BpY05hbWUoRnVuY3Rpb25OYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYCR7RnVuY3Rpb25OYW1lfS1SZXF1ZXN0c2A7XG59XG5cbmZ1bmN0aW9uIGdldFNOU1RvcGljQXJuKHJlZ2lvbjogQXdzUmVnaW9uLCBhY2NvdW50SWQ6IHN0cmluZywgRnVuY3Rpb25OYW1lOiBzdHJpbmcpIHtcbiAgICBjb25zdCBUb3BpY05hbWUgPSBnZXRTTlNUb3BpY05hbWUoRnVuY3Rpb25OYW1lKTtcbiAgICByZXR1cm4gYGFybjphd3M6c25zOiR7cmVnaW9ufToke2FjY291bnRJZH06JHtUb3BpY05hbWV9YDtcbn1cblxuZnVuY3Rpb24gZ2V0U1FTTmFtZShGdW5jdGlvbk5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBgJHtGdW5jdGlvbk5hbWV9LVJlc3BvbnNlc2A7XG59XG5cbmZ1bmN0aW9uIGdldFJlc3BvbnNlUXVldWVVcmwocmVnaW9uOiBBd3NSZWdpb24sIGFjY291bnRJZDogc3RyaW5nLCBGdW5jdGlvbk5hbWU6IHN0cmluZykge1xuICAgIGNvbnN0IHF1ZXVlTmFtZSA9IGdldFNRU05hbWUoRnVuY3Rpb25OYW1lKTtcbiAgICByZXR1cm4gYGh0dHBzOi8vc3FzLiR7cmVnaW9ufS5hbWF6b25hd3MuY29tLyR7YWNjb3VudElkfS8ke3F1ZXVlTmFtZX1gO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVSZXF1ZXN0UXVldWVJbXBsKFxuICAgIHN0YXRlOiBBd3NTdGF0ZSxcbiAgICBGdW5jdGlvbk5hbWU6IHN0cmluZyxcbiAgICBGdW5jdGlvbkFybjogc3RyaW5nXG4pIHtcbiAgICBjb25zdCB7IHNucywgbGFtYmRhIH0gPSBzdGF0ZS5zZXJ2aWNlcztcbiAgICBjb25zdCB7IHJlc291cmNlcyB9ID0gc3RhdGU7XG5cbiAgICBsb2cuaW5mbyhgQ3JlYXRpbmcgU05TIHJlcXVlc3QgdG9waWNgKTtcbiAgICBjb25zdCBjcmVhdGVUb3BpY1Byb21pc2UgPSBjcmVhdGVTTlNUb3BpYyhzbnMsIGdldFNOU1RvcGljTmFtZShGdW5jdGlvbk5hbWUpKTtcblxuICAgIGNvbnN0IGFzc2lnblJlcXVlc3RUb3BpY0FyblByb21pc2UgPSBjcmVhdGVUb3BpY1Byb21pc2UudGhlbihcbiAgICAgICAgdG9waWMgPT4gKHJlc291cmNlcy5SZXF1ZXN0VG9waWNBcm4gPSB0b3BpYylcbiAgICApO1xuXG4gICAgY29uc3QgYWRkUGVybWlzc2lvbnNQcm9taXNlID0gY3JlYXRlVG9waWNQcm9taXNlLnRoZW4odG9waWMgPT4ge1xuICAgICAgICBsb2cuaW5mbyhgQWRkaW5nIFNOUyBpbnZva2UgcGVybWlzc2lvbnMgdG8gZnVuY3Rpb25gKTtcbiAgICAgICAgcmV0dXJuIGFkZFNuc0ludm9rZVBlcm1pc3Npb25zVG9GdW5jdGlvbihGdW5jdGlvbk5hbWUsIHRvcGljLCBsYW1iZGEpO1xuICAgIH0pO1xuXG4gICAgY29uc3Qgc3Vic2NyaWJlUHJvbWlzZSA9IGNyZWF0ZVRvcGljUHJvbWlzZS50aGVuKHRvcGljID0+IHtcbiAgICAgICAgbG9nLmluZm8oYFN1YnNjcmliaW5nIFNOUyB0byBpbnZva2UgbGFtYmRhIGZ1bmN0aW9uYCk7XG4gICAgICAgIHJldHVybiBzbnNcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoe1xuICAgICAgICAgICAgICAgIFRvcGljQXJuOiB0b3BpYyxcbiAgICAgICAgICAgICAgICBQcm90b2NvbDogXCJsYW1iZGFcIixcbiAgICAgICAgICAgICAgICBFbmRwb2ludDogRnVuY3Rpb25Bcm5cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAucHJvbWlzZSgpO1xuICAgIH0pO1xuXG4gICAgY29uc3QgYXNzaWduU05TUmVzcG9uc2VQcm9taXNlID0gc3Vic2NyaWJlUHJvbWlzZS50aGVuKFxuICAgICAgICBzbnNSZXNwb25zZSA9PiAocmVzb3VyY2VzLlNOU0xhbWJkYVN1YnNjcmlwdGlvbkFybiA9IHNuc1Jlc3BvbnNlLlN1YnNjcmlwdGlvbkFybiEpXG4gICAgKTtcblxuICAgIHJldHVybiBQcm9taXNlLmFsbChbXG4gICAgICAgIGNyZWF0ZVRvcGljUHJvbWlzZSxcbiAgICAgICAgYXNzaWduUmVxdWVzdFRvcGljQXJuUHJvbWlzZSxcbiAgICAgICAgYWRkUGVybWlzc2lvbnNQcm9taXNlLFxuICAgICAgICBzdWJzY3JpYmVQcm9taXNlLFxuICAgICAgICBhc3NpZ25TTlNSZXNwb25zZVByb21pc2VcbiAgICBdKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVJlc3BvbnNlUXVldWVJbXBsKHN0YXRlOiBBd3NTdGF0ZSwgRnVuY3Rpb25OYW1lOiBzdHJpbmcpIHtcbiAgICBjb25zdCB7IHNxcyB9ID0gc3RhdGUuc2VydmljZXM7XG4gICAgY29uc3QgeyByZXNvdXJjZXMgfSA9IHN0YXRlO1xuICAgIGxvZy5pbmZvKGBDcmVhdGluZyBTUVMgcmVzcG9uc2UgcXVldWVgKTtcbiAgICBjb25zdCB7IFF1ZXVlVXJsLCBRdWV1ZUFybiB9ID0gYXdhaXQgY3JlYXRlU1FTUXVldWUoXG4gICAgICAgIGdldFNRU05hbWUoRnVuY3Rpb25OYW1lKSxcbiAgICAgICAgNjAsXG4gICAgICAgIHNxc1xuICAgICk7XG4gICAgcmVzb3VyY2VzLlJlc3BvbnNlUXVldWVVcmwgPSBRdWV1ZVVybDtcbiAgICByZXNvdXJjZXMuUmVzcG9uc2VRdWV1ZUFybiA9IFF1ZXVlQXJuO1xuICAgIGxvZy5pbmZvKGBDcmVhdGVkIHJlc3BvbnNlIHF1ZXVlYCk7XG4gICAgcmV0dXJuIFF1ZXVlQXJuITtcbn1cblxuZnVuY3Rpb24gYWRkU25zSW52b2tlUGVybWlzc2lvbnNUb0Z1bmN0aW9uKFxuICAgIEZ1bmN0aW9uTmFtZTogc3RyaW5nLFxuICAgIFJlcXVlc3RUb3BpY0Fybjogc3RyaW5nLFxuICAgIGxhbWJkYTogTGFtYmRhXG4pIHtcbiAgICByZXR1cm4gbGFtYmRhXG4gICAgICAgIC5hZGRQZXJtaXNzaW9uKHtcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZSxcbiAgICAgICAgICAgIEFjdGlvbjogXCJsYW1iZGE6SW52b2tlRnVuY3Rpb25cIixcbiAgICAgICAgICAgIFByaW5jaXBhbDogXCJzbnMuYW1hem9uYXdzLmNvbVwiLFxuICAgICAgICAgICAgU3RhdGVtZW50SWQ6IGAke0Z1bmN0aW9uTmFtZX0tSW52b2tlYCxcbiAgICAgICAgICAgIFNvdXJjZUFybjogUmVxdWVzdFRvcGljQXJuXG4gICAgICAgIH0pXG4gICAgICAgIC5wcm9taXNlKClcbiAgICAgICAgLmNhdGNoKGVyciA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyLm1hdGNoKC9hbHJlYWR5IGV4aXN0cy8pKSB7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG59XG5cbi8qKlxuICogVmFsaWQgQVdTXG4gKiB7QGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0VDMi9sYXRlc3QvVXNlckd1aWRlL3VzaW5nLXJlZ2lvbnMtYXZhaWxhYmlsaXR5LXpvbmVzLmh0bWwgfCByZWdpb25zfS5cbiAqIE5vdCBhbGwgb2YgdGhlc2UgcmVnaW9ucyBoYXZlIExhbWJkYSBzdXBwb3J0LlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgdHlwZSBBd3NSZWdpb24gPVxuICAgIHwgXCJ1cy1lYXN0LTFcIlxuICAgIHwgXCJ1cy1lYXN0LTJcIlxuICAgIHwgXCJ1cy13ZXN0LTFcIlxuICAgIHwgXCJ1cy13ZXN0LTJcIlxuICAgIHwgXCJjYS1jZW50cmFsLTFcIlxuICAgIHwgXCJldS1jZW50cmFsLTFcIlxuICAgIHwgXCJldS13ZXN0LTFcIlxuICAgIHwgXCJldS13ZXN0LTJcIlxuICAgIHwgXCJldS13ZXN0LTNcIlxuICAgIHwgXCJhcC1ub3J0aGVhc3QtMVwiXG4gICAgfCBcImFwLW5vcnRoZWFzdC0yXCJcbiAgICB8IFwiYXAtbm9ydGhlYXN0LTNcIlxuICAgIHwgXCJhcC1zb3V0aGVhc3QtMVwiXG4gICAgfCBcImFwLXNvdXRoZWFzdC0yXCJcbiAgICB8IFwiYXAtc291dGgtMVwiXG4gICAgfCBcInNhLWVhc3QtMVwiO1xuXG5jb25zdCBsb2NhdGlvbnMgPSB7XG4gICAgXCJ1cy1lYXN0LTFcIjogXCJVUyBFYXN0IChOLiBWaXJnaW5pYSlcIixcbiAgICBcInVzLWVhc3QtMlwiOiBcIlVTIEVhc3QgKE9oaW8pXCIsXG4gICAgXCJ1cy13ZXN0LTFcIjogXCJVUyBXZXN0IChOLiBDYWxpZm9ybmlhKVwiLFxuICAgIFwidXMtd2VzdC0yXCI6IFwiVVMgV2VzdCAoT3JlZ29uKVwiLFxuICAgIFwiY2EtY2VudHJhbC0xXCI6IFwiQ2FuYWRhIChDZW50cmFsKVwiLFxuICAgIFwiZXUtY2VudHJhbC0xXCI6IFwiRVUgKEZyYW5rZnVydClcIixcbiAgICBcImV1LXdlc3QtMVwiOiBcIkVVIChJcmVsYW5kKVwiLFxuICAgIFwiZXUtd2VzdC0yXCI6IFwiRVUgKExvbmRvbilcIixcbiAgICBcImV1LXdlc3QtM1wiOiBcIkVVIChQYXJpcylcIixcbiAgICBcImFwLW5vcnRoZWFzdC0xXCI6IFwiQXNpYSBQYWNpZmljIChUb2t5bylcIixcbiAgICBcImFwLW5vcnRoZWFzdC0yXCI6IFwiQXNpYSBQYWNpZmljIChTZW91bClcIixcbiAgICBcImFwLW5vcnRoZWFzdC0zXCI6IFwiQXNpYSBQYWNpZmljIChPc2FrYS1Mb2NhbClcIixcbiAgICBcImFwLXNvdXRoZWFzdC0xXCI6IFwiQXNpYSBQYWNpZmljIChTaW5nYXBvcmUpXCIsXG4gICAgXCJhcC1zb3V0aGVhc3QtMlwiOiBcIkFzaWEgUGFjaWZpYyAoU3lkbmV5KVwiLFxuICAgIFwiYXAtc291dGgtMVwiOiBcIkFzaWEgUGFjaWZpYyAoTXVtYmFpKVwiLFxuICAgIFwic2EtZWFzdC0xXCI6IFwiU291dGggQW1lcmljYSAoU8OjbyBQYXVsbylcIlxufTtcblxuZXhwb3J0IGNvbnN0IGF3c1ByaWNlID0gdGhyb3R0bGUoXG4gICAgeyBjb25jdXJyZW5jeTogNiwgcmF0ZTogNSwgbWVtb2l6ZTogdHJ1ZSwgY2FjaGU6IGNhY2hlcy5hd3NQcmljZXMgfSxcbiAgICBhc3luYyAocHJpY2luZzogUHJpY2luZywgU2VydmljZUNvZGU6IHN0cmluZywgZmlsdGVyOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBmdW5jdGlvbiBmaXJzdChvYmo6IGFueSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBvYmpbT2JqZWN0LmtleXMob2JqKVswXV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmdW5jdGlvbiBleHRyYWN0UHJpY2Uob2JqOiBhbnkpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwcmljZXMgPSBPYmplY3Qua2V5cyhvYmoucHJpY2VEaW1lbnNpb25zKS5tYXAoa2V5ID0+XG4gICAgICAgICAgICAgICAgICAgIE51bWJlcihvYmoucHJpY2VEaW1lbnNpb25zW2tleV0ucHJpY2VQZXJVbml0LlVTRClcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybiBNYXRoLm1heCguLi5wcmljZXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgcHJpY2VSZXN1bHQgPSBhd2FpdCBwcmljaW5nXG4gICAgICAgICAgICAgICAgLmdldFByb2R1Y3RzKHtcbiAgICAgICAgICAgICAgICAgICAgU2VydmljZUNvZGUsXG4gICAgICAgICAgICAgICAgICAgIEZpbHRlcnM6IE9iamVjdC5rZXlzKGZpbHRlcikubWFwKGtleSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgRmllbGQ6IGtleSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFR5cGU6IFwiVEVSTV9NQVRDSFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgVmFsdWU6IGZpbHRlcltrZXldXG4gICAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnByb21pc2UoKTtcbiAgICAgICAgICAgIGlmIChwcmljZVJlc3VsdC5QcmljZUxpc3QhLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICBsb2cud2FybihcbiAgICAgICAgICAgICAgICAgICAgYFByaWNlIHF1ZXJ5IHJldHVybmVkIG1vcmUgdGhhbiBvbmUgcHJvZHVjdCAnJHtTZXJ2aWNlQ29kZX0nICgkTylgLFxuICAgICAgICAgICAgICAgICAgICBmaWx0ZXJcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHByaWNlUmVzdWx0LlByaWNlTGlzdCEuZm9yRWFjaChwID0+IGxvZy53YXJuKGAlT2AsIHApKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHBMaXN0OiBhbnkgPSBwcmljZVJlc3VsdC5QcmljZUxpc3QhWzBdO1xuICAgICAgICAgICAgY29uc3QgcHJpY2UgPSBleHRyYWN0UHJpY2UoZmlyc3QocExpc3QudGVybXMuT25EZW1hbmQpKTtcbiAgICAgICAgICAgIHJldHVybiBwcmljZTtcbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICAqL1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNvbnN0IHsgbWVzc2FnZTogbSB9ID0gZXJyO1xuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgIW0ubWF0Y2goL1JhdGUgZXhjZWVkZWQvKSAmJlxuICAgICAgICAgICAgICAgICAgICAhbS5tYXRjaCgvRVBST1RPLykgJiZcbiAgICAgICAgICAgICAgICAgICAgIW0ubWF0Y2goL3NvY2tldCBoYW5nIHVwLylcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nLndhcm4oXG4gICAgICAgICAgICAgICAgICAgICAgICBgQ291bGQgbm90IGdldCBBV1MgcHJpY2luZyBmb3IgJyR7U2VydmljZUNvZGV9JyAoJU8pYCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlclxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBsb2cud2FybihlcnIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgICBgZmFpbGVkIHRvIGdldCBBV1MgcHJpY2luZyBmb3IgXCIke1NlcnZpY2VDb2RlfVwiYFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4pO1xuXG5leHBvcnQgY29uc3QgcmVxdWVzdEF3c1ByaWNlcyA9IGFzeW5jIChcbiAgICBwcmljaW5nOiBQcmljaW5nLFxuICAgIHJlZ2lvbjogQXdzUmVnaW9uXG4pOiBQcm9taXNlPEF3c1ByaWNlcz4gPT4ge1xuICAgIGNvbnN0IGxvY2F0aW9uID0gbG9jYXRpb25zW3JlZ2lvbl07XG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgICovXG4gICAgcmV0dXJuIHtcbiAgICAgICAgbGFtYmRhUGVyUmVxdWVzdDogYXdhaXQgYXdzUHJpY2UocHJpY2luZywgXCJBV1NMYW1iZGFcIiwge1xuICAgICAgICAgICAgbG9jYXRpb24sXG4gICAgICAgICAgICBncm91cDogXCJBV1MtTGFtYmRhLVJlcXVlc3RzXCJcbiAgICAgICAgfSkuY2F0Y2goXyA9PiAwLjAwMDAwMDIpLFxuICAgICAgICBsYW1iZGFQZXJHYlNlY29uZDogYXdhaXQgYXdzUHJpY2UocHJpY2luZywgXCJBV1NMYW1iZGFcIiwge1xuICAgICAgICAgICAgbG9jYXRpb24sXG4gICAgICAgICAgICBncm91cDogXCJBV1MtTGFtYmRhLUR1cmF0aW9uXCJcbiAgICAgICAgfSkuY2F0Y2goXyA9PiAwLjAwMDAxNjY3KSxcbiAgICAgICAgc25zUGVyNjRrUHVibGlzaDogYXdhaXQgYXdzUHJpY2UocHJpY2luZywgXCJBbWF6b25TTlNcIiwge1xuICAgICAgICAgICAgbG9jYXRpb24sXG4gICAgICAgICAgICBncm91cDogXCJTTlMtUmVxdWVzdHMtVGllcjFcIlxuICAgICAgICB9KS5jYXRjaChfID0+IDAuNSAvIDFlNiksXG4gICAgICAgIHNxc1BlcjY0a1JlcXVlc3Q6IGF3YWl0IGF3c1ByaWNlKHByaWNpbmcsIFwiQVdTUXVldWVTZXJ2aWNlXCIsIHtcbiAgICAgICAgICAgIGxvY2F0aW9uLFxuICAgICAgICAgICAgZ3JvdXA6IFwiU1FTLUFQSVJlcXVlc3QtVGllcjFcIixcbiAgICAgICAgICAgIHF1ZXVlVHlwZTogXCJTdGFuZGFyZFwiXG4gICAgICAgIH0pLmNhdGNoKF8gPT4gMC40IC8gMWU2KSxcbiAgICAgICAgZGF0YU91dFBlckdiOiBhd2FpdCBhd3NQcmljZShwcmljaW5nLCBcIkFXU0RhdGFUcmFuc2ZlclwiLCB7XG4gICAgICAgICAgICBmcm9tTG9jYXRpb246IGxvY2F0aW9uLFxuICAgICAgICAgICAgdHJhbnNmZXJUeXBlOiBcIkFXUyBPdXRib3VuZFwiXG4gICAgICAgIH0pLmNhdGNoKF8gPT4gMC4wOSksXG4gICAgICAgIGxvZ3NJbmdlc3RlZFBlckdiOiBhd2FpdCBhd3NQcmljZShwcmljaW5nLCBcIkFtYXpvbkNsb3VkV2F0Y2hcIiwge1xuICAgICAgICAgICAgbG9jYXRpb24sXG4gICAgICAgICAgICBncm91cDogXCJJbmdlc3RlZCBMb2dzXCIsXG4gICAgICAgICAgICBncm91cERlc2NyaXB0aW9uOiBcIkV4aXN0aW5nIHN5c3RlbSwgYXBwbGljYXRpb24sIGFuZCBjdXN0b20gbG9nIGZpbGVzXCJcbiAgICAgICAgfSkuY2F0Y2goXyA9PiAwLjUpXG4gICAgfTtcbn07XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjb3N0U25hcHNob3QoXG4gICAgc3RhdGU6IEF3c1N0YXRlLFxuICAgIHN0YXRzOiBGdW5jdGlvblN0YXRzXG4pOiBQcm9taXNlPENvc3RTbmFwc2hvdD4ge1xuICAgIGNvbnN0IHsgcmVnaW9uIH0gPSBzdGF0ZS5yZXNvdXJjZXM7XG4gICAgY29uc3QgcHJpY2VzID0gYXdhaXQgcmVxdWVzdEF3c1ByaWNlcyhzdGF0ZS5zZXJ2aWNlcy5wcmljaW5nLCByZWdpb24pO1xuICAgIGNvbnN0IGNvc3RNZXRyaWNzOiBDb3N0TWV0cmljW10gPSBbXTtcbiAgICBjb25zdCB7IG1lbW9yeVNpemUgPSBkZWZhdWx0cy5tZW1vcnlTaXplIH0gPSBzdGF0ZS5vcHRpb25zO1xuICAgIGNvbnN0IGJpbGxlZFRpbWVTdGF0cyA9IHN0YXRzLmVzdGltYXRlZEJpbGxlZFRpbWU7XG4gICAgY29uc3Qgc2Vjb25kcyA9IChiaWxsZWRUaW1lU3RhdHMubWVhbiAvIDEwMDApICogYmlsbGVkVGltZVN0YXRzLnNhbXBsZXMgfHwgMDtcbiAgICBjb25zdCBwcm92aXNpb25lZEdiID0gbWVtb3J5U2l6ZSAvIDEwMjQ7XG4gICAgY29uc3QgZnVuY3Rpb25DYWxsRHVyYXRpb24gPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwiZnVuY3Rpb25DYWxsRHVyYXRpb25cIixcbiAgICAgICAgcHJpY2luZzogcHJpY2VzLmxhbWJkYVBlckdiU2Vjb25kICogcHJvdmlzaW9uZWRHYixcbiAgICAgICAgdW5pdDogXCJzZWNvbmRcIixcbiAgICAgICAgbWVhc3VyZWQ6IHNlY29uZHMsXG4gICAgICAgIGNvbW1lbnQ6IGBodHRwczovL2F3cy5hbWF6b24uY29tL2xhbWJkYS9wcmljaW5nIChyYXRlID0gJHtwcmljZXMubGFtYmRhUGVyR2JTZWNvbmQudG9GaXhlZChcbiAgICAgICAgICAgIDhcbiAgICAgICAgKX0vKEdCKnNlY29uZCkgKiAke3Byb3Zpc2lvbmVkR2J9IEdCID0gJHsoXG4gICAgICAgICAgICBwcmljZXMubGFtYmRhUGVyR2JTZWNvbmQgKiBwcm92aXNpb25lZEdiXG4gICAgICAgICkudG9GaXhlZCg4KX0vc2Vjb25kKWBcbiAgICB9KTtcbiAgICBjb3N0TWV0cmljcy5wdXNoKGZ1bmN0aW9uQ2FsbER1cmF0aW9uKTtcblxuICAgIGNvbnN0IGZ1bmN0aW9uQ2FsbFJlcXVlc3RzID0gbmV3IENvc3RNZXRyaWMoe1xuICAgICAgICBuYW1lOiBcImZ1bmN0aW9uQ2FsbFJlcXVlc3RzXCIsXG4gICAgICAgIHByaWNpbmc6IHByaWNlcy5sYW1iZGFQZXJSZXF1ZXN0LFxuICAgICAgICBtZWFzdXJlZDogc3RhdHMuaW52b2NhdGlvbnMsXG4gICAgICAgIHVuaXQ6IFwicmVxdWVzdFwiLFxuICAgICAgICBjb21tZW50OiBcImh0dHBzOi8vYXdzLmFtYXpvbi5jb20vbGFtYmRhL3ByaWNpbmdcIlxuICAgIH0pO1xuICAgIGNvc3RNZXRyaWNzLnB1c2goZnVuY3Rpb25DYWxsUmVxdWVzdHMpO1xuXG4gICAgY29uc3QgeyBtZXRyaWNzIH0gPSBzdGF0ZTtcbiAgICBjb25zdCBvdXRib3VuZERhdGFUcmFuc2ZlciA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJvdXRib3VuZERhdGFUcmFuc2ZlclwiLFxuICAgICAgICBwcmljaW5nOiBwcmljZXMuZGF0YU91dFBlckdiLFxuICAgICAgICBtZWFzdXJlZDogbWV0cmljcy5vdXRib3VuZEJ5dGVzIC8gMiAqKiAzMCxcbiAgICAgICAgdW5pdDogXCJHQlwiLFxuICAgICAgICBjb21tZW50OiBcImh0dHBzOi8vYXdzLmFtYXpvbi5jb20vZWMyL3ByaWNpbmcvb24tZGVtYW5kLyNEYXRhX1RyYW5zZmVyXCJcbiAgICB9KTtcbiAgICBjb3N0TWV0cmljcy5wdXNoKG91dGJvdW5kRGF0YVRyYW5zZmVyKTtcblxuICAgIGNvbnN0IHNxczogQ29zdE1ldHJpYyA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJzcXNcIixcbiAgICAgICAgcHJpY2luZzogcHJpY2VzLnNxc1BlcjY0a1JlcXVlc3QsXG4gICAgICAgIG1lYXN1cmVkOiBtZXRyaWNzLnNxczY0a1JlcXVlc3RzLFxuICAgICAgICB1bml0OiBcInJlcXVlc3RcIixcbiAgICAgICAgY29tbWVudDogXCJodHRwczovL2F3cy5hbWF6b24uY29tL3Nxcy9wcmljaW5nXCJcbiAgICB9KTtcbiAgICBjb3N0TWV0cmljcy5wdXNoKHNxcyk7XG5cbiAgICBjb25zdCBzbnM6IENvc3RNZXRyaWMgPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwic25zXCIsXG4gICAgICAgIHByaWNpbmc6IHByaWNlcy5zbnNQZXI2NGtQdWJsaXNoLFxuICAgICAgICBtZWFzdXJlZDogbWV0cmljcy5zbnM2NGtSZXF1ZXN0cyxcbiAgICAgICAgdW5pdDogXCJyZXF1ZXN0XCIsXG4gICAgICAgIGNvbW1lbnQ6IFwiaHR0cHM6Ly9hd3MuYW1hem9uLmNvbS9zbnMvcHJpY2luZ1wiXG4gICAgfSk7XG4gICAgY29zdE1ldHJpY3MucHVzaChzbnMpO1xuXG4gICAgY29uc3QgbG9nSW5nZXN0aW9uOiBDb3N0TWV0cmljID0gbmV3IENvc3RNZXRyaWMoe1xuICAgICAgICBuYW1lOiBcImxvZ0luZ2VzdGlvblwiLFxuICAgICAgICBwcmljaW5nOiBwcmljZXMubG9nc0luZ2VzdGVkUGVyR2IsXG4gICAgICAgIG1lYXN1cmVkOiAwLFxuICAgICAgICB1bml0OiBcIkdCXCIsXG4gICAgICAgIGNvbW1lbnQ6XG4gICAgICAgICAgICBcImh0dHBzOi8vYXdzLmFtYXpvbi5jb20vY2xvdWR3YXRjaC9wcmljaW5nLyAtIExvZyBpbmdlc3Rpb24gY29zdHMgbm90IGN1cnJlbnRseSBpbmNsdWRlZC5cIixcbiAgICAgICAgaW5mb3JtYXRpb25hbE9ubHk6IHRydWVcbiAgICB9KTtcbiAgICBjb3N0TWV0cmljcy5wdXNoKGxvZ0luZ2VzdGlvbik7XG5cbiAgICByZXR1cm4gbmV3IENvc3RTbmFwc2hvdChcImF3c1wiLCBzdGF0ZS5vcHRpb25zLCBzdGF0cywgY29zdE1ldHJpY3MpO1xufVxuXG5leHBvcnQgY29uc3QgQXdzSW1wbDogUHJvdmlkZXJJbXBsPEF3c09wdGlvbnMsIEF3c1N0YXRlPiA9IHtcbiAgICBuYW1lOiBcImF3c1wiLFxuICAgIGluaXRpYWxpemUsXG4gICAgZGVmYXVsdHMsXG4gICAgY2xlYW51cCxcbiAgICBjb3N0U25hcHNob3QsXG4gICAgbG9nVXJsLFxuICAgIGludm9rZSxcbiAgICBwb2xsLFxuICAgIHJlc3BvbnNlUXVldWVJZFxufTtcbiJdfQ==
\No newline at end of file