UNPKG

96.2 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.logUrl = exports.googlePacker = exports.cleanup = exports.getRequestSubscription = exports.getResponseSubscription = exports.getResponseQueueTopic = exports.initialize = exports.initializeGoogleServices = exports.GoogleImpl = exports.defaults = exports.defaultGcWorker = exports.GoogleMetrics = void 0;
4const abort_controller_1 = require("abort-controller");
5const gaxios_1 = require("gaxios");
6const googleapis_1 = require("googleapis");
7const https = require("https");
8const util = require("util");
9const cache_1 = require("../cache");
10const cost_1 = require("../cost");
11const error_1 = require("../error");
12const log_1 = require("../log");
13const packer_1 = require("../packer");
14const provider_1 = require("../provider");
15const serialize_1 = require("../serialize");
16const shared_1 = require("../shared");
17const throttle_1 = require("../throttle");
18const google_queue_1 = require("./google-queue");
19const google_shared_1 = require("./google-shared");
20const googleTrampolineHttps = require("./google-trampoline-https");
21const googleTrampolineQueue = require("./google-trampoline-queue");
22const gaxios = new gaxios_1.Gaxios({
23 retryConfig: {
24 retry: 3,
25 noResponseRetries: 3,
26 shouldRetry: (0, google_shared_1.shouldRetryRequest)(log_1.log.info)
27 }
28});
29const GoogleCloudFunctionsMemorySizes = [128, 256, 512, 1024, 2048];
30class GoogleMetrics {
31 constructor() {
32 this.outboundBytes = 0;
33 this.pubSubBytes = 0;
34 }
35}
36exports.GoogleMetrics = GoogleMetrics;
37function defaultGcWorker(resources, services) {
38 return deleteResources(services, resources, log_1.log.gc);
39}
40exports.defaultGcWorker = defaultGcWorker;
41exports.defaults = {
42 ...provider_1.commonDefaults,
43 region: "us-central1",
44 googleCloudFunctionOptions: {},
45 _gcWorker: defaultGcWorker
46};
47exports.GoogleImpl = {
48 name: "google",
49 initialize,
50 defaults: exports.defaults,
51 cleanup,
52 costSnapshot,
53 logUrl,
54 invoke,
55 poll,
56 responseQueueId
57};
58async function initializeGoogleServices() {
59 const auth = await googleapis_1.google.auth.getClient({
60 scopes: ["https://www.googleapis.com/auth/cloud-platform"]
61 });
62 googleapis_1.google.options({
63 auth,
64 retryConfig: {
65 retry: 8,
66 retryDelay: 250,
67 noResponseRetries: 3,
68 shouldRetry: (0, google_shared_1.shouldRetryRequest)(log_1.log.info)
69 }
70 });
71 return {
72 cloudFunctions: googleapis_1.google.cloudfunctions("v1"),
73 pubsub: googleapis_1.google.pubsub("v1"),
74 cloudBilling: googleapis_1.google.cloudbilling("v1"),
75 google: googleapis_1.google
76 };
77}
78exports.initializeGoogleServices = initializeGoogleServices;
79async function defaultPollDelay(retries) {
80 if (retries > 5) {
81 await (0, shared_1.sleep)(5 * 1000);
82 }
83 await (0, shared_1.sleep)((retries + 1) * 500);
84}
85async function pollOperation({ request, checkDone, delay = defaultPollDelay, maxRetries = 50 }) {
86 let retries = 0;
87 await delay(retries);
88 while (true) {
89 log_1.log.info(`Polling...`);
90 const result = await request();
91 if (checkDone(result)) {
92 log_1.log.info(`Done.`);
93 return result;
94 }
95 if (retries++ >= maxRetries) {
96 throw new error_1.FaastError(`Timed out after ${retries} attempts.`);
97 }
98 await delay(retries);
99 }
100}
101async function quietly(promise) {
102 try {
103 const result = await promise;
104 return result.data;
105 }
106 catch (err) {
107 return;
108 }
109}
110const throttleGoogleWrite = (0, throttle_1.throttle)({
111 concurrency: 4,
112 rate: 3,
113 retry: (err, n) => {
114 const { message } = err;
115 return (n < 6 &&
116 (message.match(/Build failed/) !== null ||
117 message.match(/Quota/) !== null ||
118 message.match(/load attempt timed out/) !== null ||
119 message.match(/ECONNRESET/) !== null ||
120 message.match(/failed on loading user code/) != null));
121 }
122}, (op) => op());
123async function waitFor(api, response) {
124 return throttleGoogleWrite(async () => {
125 let operation;
126 try {
127 operation = await response();
128 }
129 catch (err) {
130 throw new error_1.FaastError(err, "could not get operation");
131 }
132 const operationName = operation.data.name;
133 try {
134 return pollOperation({
135 request: () => quietly(api.operations.get({ name: operationName })),
136 checkDone: result => {
137 /* istanbul ignore if */
138 if (!result) {
139 return false;
140 }
141 /* istanbul ignore if */
142 if (result.error) {
143 const underlying = new error_1.FaastError(result.error.message ?? undefined);
144 underlying.stack = "";
145 throw new error_1.FaastError(underlying, "Error polling operation");
146 }
147 return result.done || false;
148 }
149 });
150 }
151 catch (err) {
152 throw new error_1.FaastError(err, "poll operation failed");
153 }
154 });
155}
156async function deleteFunction(api, path) {
157 try {
158 return await waitFor(api, () => api.projects.locations.functions.delete({
159 name: path
160 }));
161 }
162 catch (err) {
163 if (err.message.match(/does not exist/)) {
164 return;
165 }
166 throw err;
167 }
168}
169async function initialize(fmodule, nonce, options) {
170 log_1.log.info(`Create google cloud function`);
171 const services = await initializeGoogleServices();
172 const project = await googleapis_1.google.auth.getProjectId();
173 const { cloudFunctions, pubsub } = services;
174 const { region } = options;
175 const location = `projects/${project}/locations/${region}`;
176 const functionName = "faast-" + nonce;
177 const { timeout } = options;
178 const { wrapperVerbose } = options.debugOptions;
179 async function createCodeBundle() {
180 const childProcessMemoryLimitMb = options.childProcessMemoryMb;
181 const wrapperOptions = {
182 childProcessTimeoutMs: Math.max(1000, (timeout - 5) * 1000),
183 wrapperVerbose,
184 childProcessMemoryLimitMb
185 };
186 const { archive } = await googlePacker(fmodule, options, wrapperOptions, functionName);
187 const uploadUrlResponse = await throttleGoogleWrite(() => cloudFunctions.projects.locations.functions.generateUploadUrl({
188 parent: location
189 }));
190 const uploadResult = await uploadZip(uploadUrlResponse.data.uploadUrl, archive);
191 log_1.log.info(`Upload zip file response: ${uploadResult?.statusText}`);
192 return uploadUrlResponse.data.uploadUrl;
193 }
194 const trampoline = `projects/${project}/locations/${region}/functions/${functionName}`;
195 const resources = {
196 trampoline,
197 region
198 };
199 const state = {
200 resources,
201 services,
202 project,
203 functionName,
204 metrics: new GoogleMetrics(),
205 options
206 };
207 const { gc, retentionInDays, _gcWorker: gcWorker } = options;
208 if (gc === "auto" || gc === "force") {
209 log_1.log.gc(`Starting garbage collector`);
210 state.gcPromise = collectGarbage(gcWorker, services, project, retentionInDays).catch(err => {
211 log_1.log.gc(`Garbage collection error: ${err}`);
212 });
213 }
214 const pricingPromise = getGoogleCloudFunctionsPricing(services.cloudBilling, region);
215 const { mode } = options;
216 const responseQueuePromise = (async () => {
217 const topic = await pubsub.projects.topics.create({
218 name: getResponseQueueTopic(project, functionName)
219 });
220 resources.responseQueueTopic = topic.data.name ?? undefined;
221 resources.responseSubscription = getResponseSubscription(project, functionName);
222 log_1.log.info(`Creating response queue subscription`);
223 await pubsub.projects.subscriptions.create({
224 name: resources.responseSubscription,
225 requestBody: {
226 topic: resources.responseQueueTopic
227 }
228 });
229 })();
230 let requestQueuePromise;
231 if (mode === "queue") {
232 log_1.log.info(`Initializing queue`);
233 resources.requestQueueTopic = getRequestQueueTopic(project, functionName);
234 requestQueuePromise = pubsub.projects.topics.create({
235 name: resources.requestQueueTopic
236 });
237 resources.requestSubscription = getRequestSubscription(project, functionName, region);
238 }
239 const sourceUploadUrl = await createCodeBundle();
240 const { memorySize, googleCloudFunctionOptions, env } = options;
241 if (!GoogleCloudFunctionsMemorySizes.find(size => size === memorySize)) {
242 log_1.log.warn(`Invalid memorySize ${memorySize} for Google Cloud Functions`);
243 }
244 const requestBody = {
245 name: trampoline,
246 entryPoint: "trampoline",
247 timeout: `${timeout}s`,
248 availableMemoryMb: memorySize,
249 sourceUploadUrl,
250 environmentVariables: env,
251 runtime: "nodejs14",
252 ...googleCloudFunctionOptions
253 };
254 if (mode === "queue") {
255 await requestQueuePromise;
256 requestBody.eventTrigger = {
257 eventType: "providers/cloud.pubsub/eventTypes/topic.publish",
258 resource: resources.requestQueueTopic
259 };
260 }
261 else {
262 requestBody.httpsTrigger = {};
263 }
264 log_1.log.info(`Create function at ${location}`);
265 log_1.log.info(`Request body: %O`, requestBody);
266 await (0, throttle_1.retryOp)(3, async () => {
267 try {
268 log_1.log.info(`create function ${requestBody.name} [${options.description}]`);
269 await waitFor(cloudFunctions, () => cloudFunctions.projects.locations.functions.create({
270 location,
271 requestBody
272 }));
273 await cloudFunctions.projects.locations.functions.setIamPolicy({
274 resource: trampoline,
275 requestBody: {
276 policy: {
277 bindings: [
278 {
279 members: ["allUsers"],
280 role: "roles/cloudfunctions.invoker"
281 }
282 ]
283 }
284 }
285 });
286 }
287 catch (err) {
288 /* istanbul ignore next */
289 await deleteFunction(cloudFunctions, trampoline).catch(() => { });
290 throw new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.ECREATE }, "failed to create google cloud function");
291 }
292 });
293 if (mode === "https" || mode === "auto") {
294 try {
295 const func = await cloudFunctions.projects.locations.functions.get({
296 name: trampoline
297 });
298 if (!func.data.httpsTrigger) {
299 throw new error_1.FaastError("Could not get http trigger url");
300 }
301 const { url } = func.data.httpsTrigger;
302 if (!url) {
303 throw new error_1.FaastError("Could not get http trigger url");
304 }
305 log_1.log.info(`Function URL: ${url}`);
306 state.url = url;
307 }
308 catch (err) {
309 throw new error_1.FaastError(err, `Could not get function ${trampoline} or its url, despite it being created`);
310 }
311 }
312 await pricingPromise;
313 await responseQueuePromise;
314 return state;
315}
316exports.initialize = initialize;
317function getRequestQueueTopic(project, functionName) {
318 return `projects/${project}/topics/${functionName}-Requests`;
319}
320function getResponseQueueTopic(project, functionName) {
321 return `projects/${project}/topics/${functionName}-Responses`;
322}
323exports.getResponseQueueTopic = getResponseQueueTopic;
324function getResponseSubscription(project, functionName) {
325 return `projects/${project}/subscriptions/${functionName}-Responses`;
326}
327exports.getResponseSubscription = getResponseSubscription;
328function getRequestSubscription(project, functionName, region) {
329 return `projects/${project}/subscriptions/gcf-${functionName}-${region}-${functionName}-Requests`;
330}
331exports.getRequestSubscription = getRequestSubscription;
332const agent = new https.Agent({ keepAlive: true, timeout: 0, maxSockets: 1000 });
333async function callFunctionHttps(url, call, metrics, cancel) {
334 const source = new abort_controller_1.AbortController();
335 try {
336 const axiosConfig = {
337 method: "POST",
338 url,
339 headers: { "Content-Type": "application/json" },
340 body: (0, serialize_1.serialize)(call),
341 signal: source.signal,
342 responseType: "json",
343 retry: false,
344 agent
345 };
346 const rawResponse = await Promise.race([
347 gaxios.request(axiosConfig),
348 cancel
349 ]);
350 if (!rawResponse) {
351 log_1.log.info(`cancelling gcp invoke`);
352 source.abort();
353 return;
354 }
355 try {
356 metrics.outboundBytes += (0, shared_1.computeHttpResponseBytes)(rawResponse.headers);
357 }
358 catch (err) {
359 throw new error_1.FaastError(err, `Could not parse ${util.inspect(rawResponse.data)}`);
360 }
361 }
362 catch (err) {
363 const { response } = err;
364 if (response) {
365 if (response.status === 503) {
366 throw new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.EMEMORY }, "google cloud function: possibly out of memory");
367 }
368 throw new error_1.FaastError(err, `when invoking google cloud function: %s\nDetails: %s`, response.statusText, response.data);
369 }
370 throw new error_1.FaastError(err, `when invoking google cloud function`);
371 }
372}
373async function invoke(state, call, cancel) {
374 const { options, resources, services, url, metrics } = state;
375 switch (options.mode) {
376 case "auto":
377 case "https":
378 return callFunctionHttps(url, call, metrics, cancel);
379 case "queue":
380 const { requestQueueTopic } = resources;
381 const { pubsub } = services;
382 const serialized = (0, serialize_1.serialize)(call);
383 return (0, google_queue_1.publishPubSub)(pubsub, requestQueueTopic, serialized);
384 }
385}
386function poll(state, cancel) {
387 return (0, google_queue_1.receiveMessages)(state.services.pubsub, state.resources.responseSubscription, state.metrics, cancel);
388}
389function responseQueueId(state) {
390 return state.resources.responseQueueTopic;
391}
392async function deleteResources(services, resources, output = log_1.log.info) {
393 const { trampoline, requestQueueTopic, requestSubscription, responseSubscription, responseQueueTopic, region, ...rest } = resources;
394 const _exhaustiveCheck = {};
395 const { cloudFunctions, pubsub } = services;
396 // We deliberately rethrow transient errors here, so only if all prior
397 // deletes succeed do we proceed. If there's a transient error then future
398 // garbage collection will clean up. The order is important; the function
399 // itself must be deleted last.
400 const check = async (request) => {
401 try {
402 await request;
403 }
404 catch (err) {
405 /* istanbul ignore next */
406 if (err.message.match(/Resource not found/)) {
407 return;
408 }
409 throw err;
410 }
411 };
412 if (responseSubscription) {
413 await check(pubsub.projects.subscriptions.delete({ subscription: responseSubscription }));
414 output(`Deleted response subscription: ${responseSubscription}`);
415 }
416 if (responseQueueTopic) {
417 await check(pubsub.projects.topics.delete({ topic: responseQueueTopic }));
418 output(`Deleted response queue topic: ${responseQueueTopic}`);
419 }
420 if (requestSubscription) {
421 await check(pubsub.projects.subscriptions.delete({ subscription: requestSubscription }));
422 output(`Deleted response subscription: ${requestSubscription}`);
423 }
424 if (requestQueueTopic) {
425 await check(pubsub.projects.topics.delete({ topic: requestQueueTopic }));
426 output(`Deleted request queue topic: ${requestQueueTopic}`);
427 }
428 if (trampoline) {
429 await check(deleteFunction(cloudFunctions, trampoline));
430 output(`Deleted function ${trampoline}`);
431 }
432}
433async function cleanup(state, options) {
434 log_1.log.info(`google cleanup starting.`);
435 if (state.gcPromise) {
436 log_1.log.info(`Waiting for garbage collection...`);
437 await state.gcPromise;
438 log_1.log.info(`Garbage collection done.`);
439 }
440 if (options.deleteResources) {
441 try {
442 await deleteResources(state.services, state.resources);
443 }
444 catch (err) {
445 throw new error_1.FaastError(err, "delete resources failed");
446 }
447 }
448 log_1.log.info(`google cleanup done.`);
449}
450exports.cleanup = cleanup;
451let garbageCollectorRunning = false;
452async function collectGarbage(gcWorker, services, proj, retentionInDays) {
453 if (gcWorker === defaultGcWorker) {
454 if (garbageCollectorRunning) {
455 return;
456 }
457 garbageCollectorRunning = true;
458 }
459 try {
460 const { cloudFunctions } = services;
461 let pageToken;
462 let promises = [];
463 const scheduleDeleteResources = (0, throttle_1.throttle)({
464 concurrency: 5,
465 rate: 5,
466 burst: 2
467 }, async (gServices, fn) => {
468 const { region, name, project } = parseFunctionName(fn.name);
469 const resources = {
470 region,
471 trampoline: fn.name,
472 requestQueueTopic: getRequestQueueTopic(project, name),
473 requestSubscription: getRequestSubscription(project, name, region),
474 responseQueueTopic: getResponseQueueTopic(project, name),
475 responseSubscription: getResponseSubscription(project, name)
476 };
477 await gcWorker(resources, gServices);
478 });
479 const fnPattern = new RegExp(`/functions/faast-${shared_1.uuidv4Pattern}$`);
480 do {
481 const funcListResponse = await cloudFunctions.projects.locations.functions.list({
482 parent: `projects/${proj}/locations/-`,
483 pageToken
484 });
485 pageToken = funcListResponse.data.nextPageToken ?? undefined;
486 const garbageFunctions = (funcListResponse.data.functions || [])
487 .filter(fn => (0, shared_1.hasExpired)(fn.updateTime, retentionInDays))
488 .filter(fn => fn.name.match(fnPattern));
489 promises = garbageFunctions.map(fn => scheduleDeleteResources(services, fn));
490 } while (pageToken);
491 await Promise.all(promises);
492 }
493 finally {
494 if (gcWorker === defaultGcWorker) {
495 garbageCollectorRunning = false;
496 }
497 }
498}
499function parseFunctionName(path) {
500 const match = path.match(/^projects\/(.*)\/locations\/(.*)\/functions\/(.*)$/);
501 return match && { project: match[1], region: match[2], name: match[3] };
502}
503async function uploadZip(url, zipStream) {
504 const config = {
505 method: "PUT",
506 url,
507 body: zipStream,
508 headers: {
509 "content-type": "application/zip",
510 "x-goog-content-length-range": "0,104857600"
511 }
512 };
513 return gaxios.request(config);
514}
515async function googlePacker(functionModule, options, wrapperOptions, FunctionName) {
516 const { mode } = options;
517 const trampolineModule = mode === "queue" ? googleTrampolineQueue : googleTrampolineHttps;
518 return (0, packer_1.packer)(trampolineModule, functionModule, options, wrapperOptions, FunctionName);
519}
520exports.googlePacker = googlePacker;
521let getGooglePrice;
522function ensureGooglePriceCache(cloudBilling) {
523 if (getGooglePrice) {
524 return;
525 }
526 getGooglePrice = (0, throttle_1.throttle)({
527 concurrency: 1,
528 rate: 3,
529 memoize: true,
530 cache: cache_1.caches.googlePrices
531 }, async (region, serviceName, description, conversionFactor) => {
532 try {
533 const skusResponse = await cloudBilling.services.skus.list({
534 parent: serviceName
535 });
536 const { skus = [] } = skusResponse.data;
537 const matchingSkus = skus.filter(sku => sku.description === description);
538 log_1.log.provider(`matching SKUs: ${util.inspect(matchingSkus, { depth: null })}`);
539 const regionOrGlobalSku = matchingSkus.find(sku => sku.serviceRegions.find(r => r === region)) ??
540 matchingSkus.find(sku => sku.serviceRegions.find(r => r === "global"));
541 const pexp = regionOrGlobalSku.pricingInfo[0].pricingExpression;
542 const prices = pexp.tieredRates.map(rate => Number(rate.unitPrice.units ?? "0") +
543 rate.unitPrice.nanos / 1e9);
544 const price = Math.max(...prices) *
545 (conversionFactor / pexp.baseUnitConversionFactor);
546 log_1.log.provider(`Found price for ${serviceName}, ${description}, ${region}: ${price}`);
547 return price;
548 }
549 catch (err) {
550 throw new error_1.FaastError(err, `failed to get google pricing for "${description}"`);
551 }
552 });
553}
554let googleServices;
555const listGoogleServices = (0, throttle_1.throttle)({ concurrency: 1 }, async (cloudBilling) => {
556 if (googleServices) {
557 return googleServices;
558 }
559 const response = await cloudBilling.services.list();
560 googleServices = response.data.services;
561 return googleServices;
562});
563async function getGoogleCloudFunctionsPricing(cloudBilling, region) {
564 const services = await listGoogleServices(cloudBilling);
565 ensureGooglePriceCache(cloudBilling);
566 const getPricing = (serviceName, description, conversionFactor = 1) => {
567 const service = services.find(s => s.displayName === serviceName);
568 return getGooglePrice(region, service.name, description, conversionFactor);
569 };
570 return {
571 perInvocation: await getPricing("Cloud Functions", "Invocations"),
572 perGhzSecond: await getPricing("Cloud Functions", "CPU Time"),
573 perGbSecond: await getPricing("Cloud Functions", "Memory Time", 2 ** 30),
574 perGbOutboundData: await getPricing("Cloud Functions", `Network Egress from ${region}`, 2 ** 30),
575 perGbPubSub: await getPricing("Cloud Pub/Sub", "Message Delivery Basic", 2 ** 30)
576 };
577}
578// https://cloud.google.com/functions/pricing
579const gcfProvisonableMemoryTable = {
580 128: 0.2,
581 256: 0.4,
582 512: 0.8,
583 1024: 1.4,
584 2048: 2.4
585};
586async function costSnapshot(state, stats) {
587 const costs = new cost_1.CostSnapshot("google", state.options, stats);
588 const { memorySize = exports.defaults.memorySize } = state.options;
589 const provisionableSizes = (0, shared_1.keysOf)(gcfProvisonableMemoryTable)
590 .map(n => Number(n))
591 .sort((a, b) => a - b);
592 const provisionedMb = provisionableSizes.find(size => memorySize <= size);
593 if (!provisionedMb) {
594 log_1.log.warn(`Could not determine provisioned memory or CPU for requested memory size ${memorySize}`);
595 }
596 const provisionedGhz = gcfProvisonableMemoryTable[provisionedMb];
597 const billedTimeStats = stats.estimatedBilledTime;
598 const seconds = (billedTimeStats.mean / 1000) * billedTimeStats.samples;
599 const { region } = state.resources;
600 const prices = await getGoogleCloudFunctionsPricing(state.services.cloudBilling, region);
601 const provisionedGb = provisionedMb / 1024;
602 const functionCallDuration = new cost_1.CostMetric({
603 name: "functionCallDuration",
604 pricing: prices.perGbSecond * provisionedGb + prices.perGhzSecond * provisionedGhz,
605 unit: "second",
606 measured: seconds,
607 comment: `https://cloud.google.com/functions/pricing#compute_time (${provisionedMb} MB, ${provisionedGhz} GHz)`
608 });
609 costs.push(functionCallDuration);
610 const functionCallRequests = new cost_1.CostMetric({
611 name: "functionCallRequests",
612 pricing: prices.perInvocation,
613 measured: stats.invocations,
614 unit: "request",
615 comment: "https://cloud.google.com/functions/pricing#invocations"
616 });
617 costs.push(functionCallRequests);
618 const outboundDataTransfer = new cost_1.CostMetric({
619 name: "outboundDataTransfer",
620 pricing: prices.perGbOutboundData,
621 measured: state.metrics.outboundBytes / 2 ** 30,
622 unit: "GB",
623 comment: "https://cloud.google.com/functions/pricing#networking"
624 });
625 costs.push(outboundDataTransfer);
626 const pubsub = new cost_1.CostMetric({
627 name: "pubsub",
628 pricing: prices.perGbPubSub,
629 measured: state.metrics.pubSubBytes / 2 ** 30,
630 unit: "GB",
631 comment: "https://cloud.google.com/pubsub/pricing"
632 });
633 costs.push(pubsub);
634 return costs;
635}
636function logUrl(state) {
637 const { project, functionName } = state;
638 return `https://console.cloud.google.com/logs/viewer?project=${project}&resource=cloud_function%2Ffunction_name%2F${functionName}`;
639}
640exports.logUrl = logUrl;
641//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ29vZ2xlLWZhYXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2dvb2dsZS9nb29nbGUtZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsdURBQW1EO0FBQ25ELG1DQUE4RTtBQUM5RSwyQ0FNb0I7QUFDcEIsK0JBQStCO0FBQy9CLDZCQUE2QjtBQUM3QixvQ0FBa0M7QUFDbEMsa0NBQW1EO0FBQ25ELG9DQUF1RDtBQUN2RCxnQ0FBNkI7QUFDN0Isc0NBQWlEO0FBQ2pELDBDQVFxQjtBQUNyQiw0Q0FBeUM7QUFDekMsc0NBTW1CO0FBQ25CLDBDQUFnRDtBQUVoRCxpREFBZ0U7QUFDaEUsbURBQXFEO0FBQ3JELG1FQUFtRTtBQUNuRSxtRUFBbUU7QUFNbkUsTUFBTSxNQUFNLEdBQUcsSUFBSSxlQUFNLENBQUM7SUFDdEIsV0FBVyxFQUFFO1FBQ1QsS0FBSyxFQUFFLENBQUM7UUFDUixpQkFBaUIsRUFBRSxDQUFDO1FBQ3BCLFdBQVcsRUFBRSxJQUFBLGtDQUFrQixFQUFDLFNBQUcsQ0FBQyxJQUFJLENBQUM7S0FDNUM7Q0FDSixDQUFDLENBQUM7QUE4QkgsTUFBTSwrQkFBK0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztBQXdEcEUsTUFBYSxhQUFhO0lBQTFCO1FBQ0ksa0JBQWEsR0FBRyxDQUFDLENBQUM7UUFDbEIsZ0JBQVcsR0FBRyxDQUFDLENBQUM7SUFDcEIsQ0FBQztDQUFBO0FBSEQsc0NBR0M7QUF1QkQsU0FBZ0IsZUFBZSxDQUFDLFNBQTBCLEVBQUUsUUFBd0I7SUFDaEYsT0FBTyxlQUFlLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxTQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDeEQsQ0FBQztBQUZELDBDQUVDO0FBRVksUUFBQSxRQUFRLEdBQTRCO0lBQzdDLEdBQUcseUJBQWM7SUFDakIsTUFBTSxFQUFFLGFB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QU0sQ0FBQyxLQUFrQjtJQUNyQyxNQUFNLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxHQUFHLEtBQUssQ0FBQztJQUN4QyxPQUFPLHdEQUF3RCxPQUFPLDhDQUE4QyxZQUFZLEVBQUUsQ0FBQztBQUN2SSxDQUFDO0FBSEQsd0JBR0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBYm9ydENvbnRyb2xsZXIgfSBmcm9tIFwiYWJvcnQtY29udHJvbGxlclwiO1xuaW1wb3J0IHsgR2F4aW9zLCBHYXhpb3NPcHRpb25zLCBHYXhpb3NQcm9taXNlLCBHYXhpb3NSZXNwb25zZSB9IGZyb20gXCJnYXhpb3NcIjtcbmltcG9ydCB7XG4gICAgY2xvdWRiaWxsaW5nX3YxLFxuICAgIGNsb3VkZnVuY3Rpb25zX3YxLFxuICAgIGdvb2dsZSxcbiAgICBHb29nbGVBcGlzLFxuICAgIHB1YnN1Yl92MVxufSBmcm9tIFwiZ29vZ2xlYXBpc1wiO1xuaW1wb3J0ICogYXMgaHR0cHMgZnJvbSBcImh0dHBzXCI7XG5pbXBvcnQgKiBhcyB1dGlsIGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBjYWNoZXMgfSBmcm9tIFwiLi4vY2FjaGVcIjtcbmltcG9ydCB7IENvc3RNZXRyaWMsIENvc3RTbmFwc2hvdCB9IGZyb20gXCIuLi9jb3N0XCI7XG5pbXBvcnQgeyBGYWFzdEVycm9yLCBGYWFzdEVycm9yTmFtZXMgfSBmcm9tIFwiLi4vZXJyb3JcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCIuLi9sb2dcIjtcbmltcG9ydCB7IHBhY2tlciwgUGFja2VyUmVzdWx0IH0gZnJvbSBcIi4uL3BhY2tlclwiO1xuaW1wb3J0IHtcbiAgICBDbGVhbnVwT3B0aW9ucyxcbiAgICBjb21tb25EZWZhdWx0cyxcbiAgICBDb21tb25PcHRpb25zLFxuICAgIEZ1bmN0aW9uU3RhdHMsXG4gICAgUG9sbFJlc3VsdCxcbiAgICBQcm92aWRlckltcGwsXG4gICAgVVVJRFxufSBmcm9tIFwiLi4vcHJvdmlkZXJcIjtcbmltcG9ydCB7IHNlcmlhbGl6ZSB9IGZyb20gXCIuLi9zZXJpYWxpemVcIjtcbmltcG9ydCB7XG4gICAgY29tcHV0ZUh0dHBSZXNwb25zZUJ5dGVzLFxuICAgIGhhc0V4cGlyZWQsXG4gICAga2V5c09mLFxuICAgIHNsZWVwLFxuICAgIHV1aWR2NFBhdHRlcm5cbn0gZnJvbSBcIi4uL3NoYXJlZFwiO1xuaW1wb3J0IHsgcmV0cnlPcCwgdGhyb3R0bGUgfSBmcm9tIFwiLi4vdGhyb3R0bGVcIjtcbmltcG9ydCB7IEZ1bmN0aW9uQ2FsbCwgV3JhcHBlck9wdGlvbnMgfSBmcm9tIFwiLi4vd3JhcHBlclwiO1xuaW1wb3J0IHsgcHVibGlzaFB1YlN1YiwgcmVjZWl2ZU1lc3NhZ2VzIH0gZnJvbSBcIi4vZ29vZ2xlLXF1ZXVlXCI7XG5pbXBvcnQgeyBzaG91bGRSZXRyeVJlcXVlc3QgfSBmcm9tIFwiLi9nb29nbGUtc2hhcmVkXCI7XG5pbXBvcnQgKiBhcyBnb29nbGVUcmFtcG9saW5lSHR0cHMgZnJvbSBcIi4vZ29vZ2xlLXRyYW1wb2xpbmUtaHR0cHNcIjtcbmltcG9ydCAqIGFzIGdvb2dsZVRyYW1wb2xpbmVRdWV1ZSBmcm9tIFwiLi9nb29nbGUtdHJhbXBvbGluZS1xdWV1ZVwiO1xuXG5pbXBvcnQgQ2xvdWRGdW5jdGlvbnMgPSBjbG91ZGZ1bmN0aW9uc192MTtcbmltcG9ydCBQdWJTdWJBcGkgPSBwdWJzdWJfdjE7XG5pbXBvcnQgQ2xvdWRCaWxsaW5nID0gY2xvdWRiaWxsaW5nX3YxO1xuXG5jb25zdCBnYXhpb3MgPSBuZXcgR2F4aW9zKHtcbiAgICByZXRyeUNvbmZpZzoge1xuICAgICAgICByZXRyeTogMyxcbiAgICAgICAgbm9SZXNwb25zZVJldHJpZXM6IDMsXG4gICAgICAgIHNob3VsZFJldHJ5OiBzaG91bGRSZXRyeVJlcXVlc3QobG9nLmluZm8pXG4gICAgfVxufSk7XG5cbi8qKlxuICogVmFsaWQgR29vZ2xlIENsb3VkXG4gKiB7QGxpbmsgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2NvbXB1dGUvZG9jcy9yZWdpb25zLXpvbmVzLyB8IHJlZ2lvbnN9LiBPbmx5XG4gKiBzb21lIG9mIHRoZXNlXG4gKiB7QGxpbmsgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Z1bmN0aW9ucy9kb2NzL2xvY2F0aW9ucyB8IHJlZ2lvbnMgaGF2ZSBDbG91ZCBGdW5jdGlvbnN9LlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgdHlwZSBHb29nbGVSZWdpb24gPVxuICAgIHwgXCJhc2lhLWVhc3QxXCJcbiAgICB8IFwiYXNpYS1lYXN0MlwiXG4gICAgfCBcImFzaWEtbm9ydGhlYXN0MVwiXG4gICAgfCBcImFzaWEtc291dGgxXCJcbiAgICB8IFwiYXNpYS1zb3V0aGVhc3QxXCJcbiAgICB8IFwiYXVzdHJhbGlhLXNvdXRoZWFzdDFcIlxuICAgIHwgXCJldXJvcGUtbm9ydGgxXCJcbiAgICB8IFwiZXVyb3BlLXdlc3QxXCJcbiAgICB8IFwiZXVyb3BlLXdlc3QyXCJcbiAgICB8IFwiZXVyb3BlLXdlc3QzXCJcbiAgICB8IFwiZXVyb3BlLXdlc3Q0XCJcbiAgICB8IFwiZXVyb3BlLXdlc3Q2XCJcbiAgICB8IFwibm9ydGhhbWVyaWNhLW5vcnRoZWFzdDFcIlxuICAgIHwgXCJzb3V0aGFtZXJpY2EtZWFzdDFcIlxuICAgIHwgXCJ1cy1jZW50cmFsMVwiXG4gICAgfCBcInVzLWVhc3QxXCJcbiAgICB8IFwidXMtZWFzdDRcIlxuICAgIHwgXCJ1cy13ZXN0MVwiXG4gICAgfCBcInVzLXdlc3QyXCI7XG5cbmNvbnN0IEdvb2dsZUNsb3VkRnVuY3Rpb25zTWVtb3J5U2l6ZXMgPSBbMTI4LCAyNTYsIDUxMiwgMTAyNCwgMjA0OF07XG5cbi8qKlxuICogR29vZ2xlLXNwZWNpZmljIG9wdGlvbnMgZm9yIHtAbGluayBmYWFzdEdvb2dsZX0uXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR29vZ2xlT3B0aW9ucyBleHRlbmRzIENvbW1vbk9wdGlvbnMge1xuICAgIC8qKlxuICAgICAqIFRoZSByZWdpb24gdG8gY3JlYXRlIHJlc291cmNlcyBpbi4gR2FyYmFnZSBjb2xsZWN0aW9uIGlzIGFsc28gbGltaXRlZCB0b1xuICAgICAqIHRoaXMgcmVnaW9uLiBEZWZhdWx0OiBgXCJ1cy1jZW50cmFsMVwiYC5cbiAgICAgKi9cbiAgICByZWdpb24/OiBHb29nbGVSZWdpb247XG4gICAgLyoqXG4gICAgICogQWRkaXRpb25hbCBvcHRpb25zIHRvIHBhc3MgdG8gR29vZ2xlIENsb3VkIEZ1bmN0aW9uIGNyZWF0aW9uLiBTZWVcbiAgICAgKiB7QGxpbmsgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Z1bmN0aW9ucy9kb2NzL3JlZmVyZW5jZS9yZXN0L3YxL3Byb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnMjQ2xvdWRGdW5jdGlvbiB8IHByb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnN9LlxuICAgICAqIEByZW1hcmtzXG4gICAgICogSWYgeW91IG5lZWQgc3BlY2lhbGl6ZWQgb3B0aW9ucywgeW91IGNhbiBwYXNzIHRoZW0gdG8gdGhlIEdvb2dsZSBDbG91ZFxuICAgICAqIEZ1bmN0aW9ucyBBUEkgZGlyZWN0bHkuIE5vdGUgdGhhdCBpZiB5b3Ugb3ZlcnJpZGUgYW55IHNldHRpbmdzIHNldCBieVxuICAgICAqIGZhYXN0LmpzLCB5b3UgbWF5IGNhdXNlIGZhYXN0LmpzIHRvIG5vdCB3b3JrOlxuICAgICAqXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqICBjb25zdCByZXF1ZXN0Qm9keTogQ2xvdWRGdW5jdGlvbnMuU2NoZW1hJENsb3VkRnVuY3Rpb24gPSB7XG4gICAgICogICAgICBuYW1lLFxuICAgICAqICAgICAgZW50cnlQb2ludDogXCJ0cmFtcG9saW5lXCIsXG4gICAgICogICAgICB0aW1lb3V0LFxuICAgICAqICAgICAgYXZhaWxhYmxlTWVtb3J5TWIsXG4gICAgICogICAgICBzb3VyY2VVcGxvYWRVcmwsXG4gICAgICogICAgICBydW50aW1lOiBcIm5vZGVqczE0XCIsXG4gICAgICogICAgICAuLi5nb29nbGVDbG91ZEZ1bmN0aW9uT3B0aW9uc1xuICAgICAqICB9O1xuICAgICAqIGBgYFxuICAgICAqXG4gICAgICovXG4gICAgZ29vZ2xlQ2xvdWRGdW5jdGlvbk9wdGlvbnM/OiBDbG91ZEZ1bmN0aW9ucy5TY2hlbWEkQ2xvdWRGdW5jdGlvbjtcblxuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBfZ2NXb3JrZXI/OiAocmVzb3VyY2VzOiBHb29nbGVSZXNvdXJjZXMsIHNlcnZpY2VzOiBHb29nbGVTZXJ2aWNlcykgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHb29nbGVSZXNvdXJjZXMge1xuICAgIHRyYW1wb2xpbmU6IHN0cmluZztcbiAgICByZXF1ZXN0UXVldWVUb3BpYz86IHN0cmluZztcbiAgICByZXF1ZXN0U3Vic2NyaXB0aW9uPzogc3RyaW5nO1xuICAgIHJlc3BvbnNlUXVldWVUb3BpYz86IHN0cmluZztcbiAgICByZXNwb25zZVN1YnNjcmlwdGlvbj86IHN0cmluZztcbiAgICByZWdpb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHb29nbGVDbG91ZFByaWNpbmcge1xuICAgIHBlckludm9jYXRpb246IG51bWJlcjtcbiAgICBwZXJHaHpTZWNvbmQ6IG51bWJlcjtcbiAgICBwZXJHYlNlY29uZDogbnVtYmVyO1xuICAgIHBlckdiT3V0Ym91bmREYXRhOiBudW1iZXI7XG4gICAgcGVyR2JQdWJTdWI6IG51bWJlcjtcbn1cblxuZXhwb3J0IGNsYXNzIEdvb2dsZU1ldHJpY3Mge1xuICAgIG91dGJvdW5kQnl0ZXMgPSAwO1xuICAgIHB1YlN1YkJ5dGVzID0gMDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHb29nbGVTZXJ2aWNlcyB7XG4gICAgcmVhZG9ubHkgY2xvdWRGdW5jdGlvbnM6IENsb3VkRnVuY3Rpb25zLkNsb3VkZnVuY3Rpb25zO1xuICAgIHJlYWRvbmx5IHB1YnN1YjogUHViU3ViQXBpLlB1YnN1YjtcbiAgICByZWFkb25seSBnb29nbGU6IEdvb2dsZUFwaXM7XG4gICAgcmVhZG9ubHkgY2xvdWRCaWxsaW5nOiBDbG91ZEJpbGxpbmcuQ2xvdWRiaWxsaW5nO1xufVxuXG4vKipcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdvb2dsZVN0YXRlIHtcbiAgICByZXNvdXJjZXM6IEdvb2dsZVJlc291cmNlcztcbiAgICBzZXJ2aWNlczogR29vZ2xlU2VydmljZXM7XG4gICAgdXJsPzogc3RyaW5nO1xuICAgIHByb2plY3Q6IHN0cmluZztcbiAgICBmdW5jdGlvbk5hbWU6IHN0cmluZztcbiAgICBtZXRyaWNzOiBHb29nbGVNZXRyaWNzO1xuICAgIG9wdGlvbnM6IFJlcXVpcmVkPEdvb2dsZU9wdGlvbnM+O1xuICAgIGdjUHJvbWlzZT86IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZWZhdWx0R2NXb3JrZXIocmVzb3VyY2VzOiBHb29nbGVSZXNvdXJjZXMsIHNlcnZpY2VzOiBHb29nbGVTZXJ2aWNlcykge1xuICAgIHJldHVybiBkZWxldGVSZXNvdXJjZXMoc2VydmljZXMsIHJlc291cmNlcywgbG9nLmdjKTtcbn1cblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRzOiBSZXF1aXJlZDxHb29nbGVPcHRpb25zPiA9IHtcbiAgICAuLi5jb21tb25EZWZhdWx0cyxcbiAgICByZWdpb246IFwidXMtY2VudHJhbDFcIixcbiAgICBnb29nbGVDbG91ZEZ1bmN0aW9uT3B0aW9uczoge30sXG4gICAgX2djV29ya2VyOiBkZWZhdWx0R2NXb3JrZXJcbn07XG5cbmV4cG9ydCBjb25zdCBHb29nbGVJbXBsOiBQcm92aWRlckltcGw8R29vZ2xlT3B0aW9ucywgR29vZ2xlU3RhdGU+ID0ge1xuICAgIG5hbWU6IFwiZ29vZ2xlXCIsXG4gICAgaW5pdGlhbGl6ZSxcbiAgICBkZWZhdWx0cyxcbiAgICBjbGVhbnVwLFxuICAgIGNvc3RTbmFwc2hvdCxcbiAgICBsb2dVcmwsXG4gICAgaW52b2tlLFxuICAgIHBvbGwsXG4gICAgcmVzcG9uc2VRdWV1ZUlkXG59O1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdGlhbGl6ZUdvb2dsZVNlcnZpY2VzKCk6IFByb21pc2U8R29vZ2xlU2VydmljZXM+IHtcbiAgICBjb25zdCBhdXRoID0gYXdhaXQgZ29vZ2xlLmF1dGguZ2V0Q2xpZW50KHtcbiAgICAgICAgc2NvcGVzOiBbXCJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2Nsb3VkLXBsYXRmb3JtXCJdXG4gICAgfSk7XG5cbiAgICBnb29nbGUub3B0aW9ucyh7XG4gICAgICAgIGF1dGgsXG4gICAgICAgIHJldHJ5Q29uZmlnOiB7XG4gICAgICAgICAgICByZXRyeTogOCxcbiAgICAgICAgICAgIHJldHJ5RGVsYXk6IDI1MCxcbiAgICAgICAgICAgIG5vUmVzcG9uc2VSZXRyaWVzOiAzLFxuICAgICAgICAgICAgc2hvdWxkUmV0cnk6IHNob3VsZFJldHJ5UmVxdWVzdChsb2cuaW5mbylcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiB7XG4gICAgICAgIGNsb3VkRnVuY3Rpb25zOiBnb29nbGUuY2xvdWRmdW5jdGlvbnMoXCJ2MVwiKSxcbiAgICAgICAgcHVic3ViOiBnb29nbGUucHVic3ViKFwidjFcIiksXG4gICAgICAgIGNsb3VkQmlsbGluZzogZ29vZ2xlLmNsb3VkYmlsbGluZyhcInYxXCIpLFxuICAgICAgICBnb29nbGVcbiAgICB9O1xufVxuXG5pbnRlcmZhY2UgUG9sbE9wdGlvbnMge1xuICAgIG1heFJldHJpZXM/OiBudW1iZXI7XG4gICAgZGVsYXk/OiAocmV0cmllczogbnVtYmVyKSA9PiBQcm9taXNlPHZvaWQ+O1xufVxuXG5pbnRlcmZhY2UgUG9sbENvbmZpZzxUPiBleHRlbmRzIFBvbGxPcHRpb25zIHtcbiAgICByZXF1ZXN0OiAoKSA9PiBQcm9taXNlPFQ+O1xuICAgIGNoZWNrRG9uZTogKHJlc3VsdDogVCkgPT4gYm9vbGVhbjtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGVmYXVsdFBvbGxEZWxheShyZXRyaWVzOiBudW1iZXIpIHtcbiAgICBpZiAocmV0cmllcyA+IDUpIHtcbiAgICAgICAgYXdhaXQgc2xlZXAoNSAqIDEwMDApO1xuICAgIH1cbiAgICBhd2FpdCBzbGVlcCgocmV0cmllcyArIDEpICogNTAwKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcG9sbE9wZXJhdGlvbjxUPih7XG4gICAgcmVxdWVzdCxcbiAgICBjaGVja0RvbmUsXG4gICAgZGVsYXkgPSBkZWZhdWx0UG9sbERlbGF5LFxuICAgIG1heFJldHJpZXMgPSA1MFxufTogUG9sbENvbmZpZzxUPik6IFByb21pc2U8VCB8IHVuZGVmaW5lZD4ge1xuICAgIGxldCByZXRyaWVzID0gMDtcbiAgICBhd2FpdCBkZWxheShyZXRyaWVzKTtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBsb2cuaW5mbyhgUG9sbGluZy4uLmApO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZXF1ZXN0KCk7XG4gICAgICAgIGlmIChjaGVja0RvbmUocmVzdWx0KSkge1xuICAgICAgICAgICAgbG9nLmluZm8oYERvbmUuYCk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZXRyaWVzKysgPj0gbWF4UmV0cmllcykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoYFRpbWVkIG91dCBhZnRlciAke3JldHJpZXN9IGF0dGVtcHRzLmApO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGRlbGF5KHJldHJpZXMpO1xuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcXVpZXRseTxUPihwcm9taXNlOiBHYXhpb3NQcm9taXNlPFQ+KSB7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHJvbWlzZTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdC5kYXRhO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG59XG5cbmNvbnN0IHRocm90dGxlR29vZ2xlV3JpdGUgPSB0aHJvdHRsZShcbiAgICB7XG4gICAgICAgIGNvbmN1cnJlbmN5OiA0LFxuICAgICAgICByYXRlOiAzLFxuICAgICAgICByZXRyeTogKGVyciwgbikgPT4ge1xuICAgICAgICAgICAgY29uc3QgeyBtZXNzYWdlIH0gPSBlcnIgYXMgRXJyb3I7XG4gICAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgICAgIG4gPCA2ICYmXG4gICAgICAgICAgICAgICAgKG1lc3NhZ2UubWF0Y2goL0J1aWxkIGZhaWxlZC8pICE9PSBudWxsIHx8XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UubWF0Y2goL1F1b3RhLykgIT09IG51bGwgfHxcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZS5tYXRjaCgvbG9hZCBhdHRlbXB0IHRpbWVkIG91dC8pICE9PSBudWxsIHx8XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UubWF0Y2goL0VDT05OUkVTRVQvKSAhPT0gbnVsbCB8fFxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlLm1hdGNoKC9mYWlsZWQgb24gbG9hZGluZyB1c2VyIGNvZGUvKSAhPSBudWxsKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgPFQ+KG9wOiAoKSA9PiBQcm9taXNlPFQ+KSA9PiBvcCgpXG4pO1xuXG5hc3luYyBmdW5jdGlvbiB3YWl0Rm9yKFxuICAgIGFwaTogQ2xvdWRGdW5jdGlvbnMuQ2xvdWRmdW5jdGlvbnMsXG4gICAgcmVzcG9uc2U6ICgpID0+IEdheGlvc1Byb21pc2U8Q2xvdWRGdW5jdGlvbnMuU2NoZW1hJE9wZXJhdGlvbj5cbikge1xuICAgIHJldHVybiB0aHJvdHRsZUdvb2dsZVdyaXRlKGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IG9wZXJhdGlvbjogR2F4aW9zUmVzcG9uc2U8Q2xvdWRGdW5jdGlvbnMuU2NoZW1hJE9wZXJhdGlvbj47XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBvcGVyYXRpb24gPSBhd2FpdCByZXNwb25zZSgpO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoZXJyLCBcImNvdWxkIG5vdCBnZXQgb3BlcmF0aW9uXCIpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG9wZXJhdGlvbk5hbWUgPSBvcGVyYXRpb24uZGF0YS5uYW1lITtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBwb2xsT3BlcmF0aW9uKHtcbiAgICAgICAgICAgICAgICByZXF1ZXN0OiAoKSA9PiBxdWlldGx5KGFwaS5vcGVyYXRpb25zLmdldCh7IG5hbWU6IG9wZXJhdGlvbk5hbWUgfSkpLFxuICAgICAgICAgICAgICAgIGNoZWNrRG9uZTogcmVzdWx0ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1bmRlcmx5aW5nID0gbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LmVycm9yLm1lc3NhZ2UgPz8gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgdW5kZXJseWluZy5zdGFjayA9IFwiXCI7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcih1bmRlcmx5aW5nLCBcIkVycm9yIHBvbGxpbmcgb3BlcmF0aW9uXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQuZG9uZSB8fCBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKGVyciwgXCJwb2xsIG9wZXJhdGlvbiBmYWlsZWRcIik7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGVsZXRlRnVuY3Rpb24oYXBpOiBDbG91ZEZ1bmN0aW9ucy5DbG91ZGZ1bmN0aW9ucywgcGF0aDogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHdhaXRGb3IoYXBpLCAoKSA9PlxuICAgICAgICAgICAgYXBpLnByb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnMuZGVsZXRlKHtcbiAgICAgICAgICAgICAgICBuYW1lOiBwYXRoXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGlmIChlcnIubWVzc2FnZS5tYXRjaCgvZG9lcyBub3QgZXhpc3QvKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycjtcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbml0aWFsaXplKFxuICAgIGZtb2R1bGU6IHN0cmluZyxcbiAgICBub25jZTogVVVJRCxcbiAgICBvcHRpb25zOiBSZXF1aXJlZDxHb29nbGVPcHRpb25zPlxuKTogUHJvbWlzZTxHb29nbGVTdGF0ZT4ge1xuICAgIGxvZy5pbmZvKGBDcmVhdGUgZ29vZ2xlIGNsb3VkIGZ1bmN0aW9uYCk7XG4gICAgY29uc3Qgc2VydmljZXMgPSBhd2FpdCBpbml0aWFsaXplR29vZ2xlU2VydmljZXMoKTtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ29vZ2xlLmF1dGguZ2V0UHJvamVjdElkKCk7XG4gICAgY29uc3QgeyBjbG91ZEZ1bmN0aW9ucywgcHVic3ViIH0gPSBzZXJ2aWNlcztcbiAgICBjb25zdCB7IHJlZ2lvbiB9ID0gb3B0aW9ucztcbiAgICBjb25zdCBsb2NhdGlvbiA9IGBwcm9qZWN0cy8ke3Byb2plY3R9L2xvY2F0aW9ucy8ke3JlZ2lvbn1gO1xuICAgIGNvbnN0IGZ1bmN0aW9uTmFtZSA9IFwiZmFhc3QtXCIgKyBub25jZTtcblxuICAgIGNvbnN0IHsgdGltZW91dCB9ID0gb3B0aW9ucztcbiAgICBjb25zdCB7IHdyYXBwZXJWZXJib3NlIH0gPSBvcHRpb25zLmRlYnVnT3B0aW9ucztcbiAgICBhc3luYyBmdW5jdGlvbiBjcmVhdGVDb2RlQnVuZGxlKCkge1xuICAgICAgICBjb25zdCBjaGlsZFByb2Nlc3NNZW1vcnlMaW1pdE1iID0gb3B0aW9ucy5jaGlsZFByb2Nlc3NNZW1vcnlNYjtcbiAgICAgICAgY29uc3Qgd3JhcHBlck9wdGlvbnMgPSB7XG4gICAgICAgICAgICBjaGlsZFByb2Nlc3NUaW1lb3V0TXM6IE1hdGgubWF4KDEwMDAsICh0aW1lb3V0IC0gNSkgKiAxMDAwKSxcbiAgICAgICAgICAgIHdyYXBwZXJWZXJib3NlLFxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzTWVtb3J5TGltaXRNYlxuICAgICAgICB9O1xuICAgICAgICBjb25zdCB7IGFyY2hpdmUgfSA9IGF3YWl0IGdvb2dsZVBhY2tlcihcbiAgICAgICAgICAgIGZtb2R1bGUsXG4gICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgd3JhcHBlck9wdGlvbnMsXG4gICAgICAgICAgICBmdW5jdGlvbk5hbWVcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdXBsb2FkVXJsUmVzcG9uc2UgPSBhd2FpdCB0aHJvdHRsZUdvb2dsZVdyaXRlKCgpID0+XG4gICAgICAgICAgICBjbG91ZEZ1bmN0aW9ucy5wcm9qZWN0cy5sb2NhdGlvbnMuZnVuY3Rpb25zLmdlbmVyYXRlVXBsb2FkVXJsKHtcbiAgICAgICAgICAgICAgICBwYXJlbnQ6IGxvY2F0aW9uXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IHVwbG9hZFJlc3VsdCA9IGF3YWl0IHVwbG9hZFppcCh1cGxvYWRVcmxSZXNwb25zZS5kYXRhLnVwbG9hZFVybCEsIGFyY2hpdmUpO1xuICAgICAgICBsb2cuaW5mbyhgVXBsb2FkIHppcCBmaWxlIHJlc3BvbnNlOiAke3VwbG9hZFJlc3VsdD8uc3RhdHVzVGV4dH1gKTtcbiAgICAgICAgcmV0dXJuIHVwbG9hZFVybFJlc3BvbnNlLmRhdGEudXBsb2FkVXJsO1xuICAgIH1cblxuICAgIGNvbnN0IHRyYW1wb2xpbmUgPSBgcHJvamVjdHMvJHtwcm9qZWN0fS9sb2NhdGlvbnMvJHtyZWdpb259L2Z1bmN0aW9ucy8ke2Z1bmN0aW9uTmFtZX1gO1xuXG4gICAgY29uc3QgcmVzb3VyY2VzOiBHb29nbGVSZXNvdXJjZXMgPSB7XG4gICAgICAgIHRyYW1wb2xpbmUsXG4gICAgICAgIHJlZ2lvblxuICAgIH07XG4gICAgY29uc3Qgc3RhdGU6IEdvb2dsZVN0YXRlID0ge1xuICAgICAgICByZXNvdXJjZXMsXG4gICAgICAgIHNlcnZpY2VzLFxuICAgICAgICBwcm9qZWN0LFxuICAgICAgICBmdW5jdGlvbk5hbWUsXG4gICAgICAgIG1ldHJpY3M6IG5ldyBHb29nbGVNZXRyaWNzKCksXG4gICAgICAgIG9wdGlvbnNcbiAgICB9O1xuXG4gICAgY29uc3QgeyBnYywgcmV0ZW50aW9uSW5EYXlzLCBfZ2NXb3JrZXI6IGdjV29ya2VyIH0gPSBvcHRpb25zO1xuICAgIGlmIChnYyA9PT0gXCJhdXRvXCIgfHwgZ2MgPT09IFwiZm9yY2VcIikge1xuICAgICAgICBsb2cuZ2MoYFN0YXJ0aW5nIGdhcmJhZ2UgY29sbGVjdG9yYCk7XG4gICAgICAgIHN0YXRlLmdjUHJvbWlzZSA9IGNvbGxlY3RHYXJiYWdlKFxuICAgICAgICAgICAgZ2NXb3JrZXIsXG4gICAgICAgICAgICBzZXJ2aWNlcyxcbiAgICAgICAgICAgIHByb2plY3QsXG4gICAgICAgICAgICByZXRlbnRpb25JbkRheXNcbiAgICAgICAgKS5jYXRjaChlcnIgPT4ge1xuICAgICAgICAgICAgbG9nLmdjKGBHYXJiYWdlIGNvbGxlY3Rpb24gZXJyb3I6ICR7ZXJyfWApO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBjb25zdCBwcmljaW5nUHJvbWlzZSA9IGdldEdvb2dsZUNsb3VkRnVuY3Rpb25zUHJpY2luZyhzZXJ2aWNlcy5jbG91ZEJpbGxpbmcsIHJlZ2lvbik7XG5cbiAgICBjb25zdCB7IG1vZGUgfSA9IG9wdGlvbnM7XG5cbiAgICBjb25zdCByZXNwb25zZVF1ZXVlUHJvbWlzZSA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHRvcGljID0gYXdhaXQgcHVic3ViLnByb2plY3RzLnRvcGljcy5jcmVhdGUoe1xuICAgICAgICAgICAgbmFtZTogZ2V0UmVzcG9uc2VRdWV1ZVRvcGljKHByb2plY3QsIGZ1bmN0aW9uTmFtZSlcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmVzb3VyY2VzLnJlc3BvbnNlUXVldWVUb3BpYyA9IHRvcGljLmRhdGEubmFtZSA/PyB1bmRlZmluZWQ7XG4gICAgICAgIHJlc291cmNlcy5yZXNwb25zZVN1YnNjcmlwdGlvbiA9IGdldFJlc3BvbnNlU3Vic2NyaXB0aW9uKHByb2plY3QsIGZ1bmN0aW9uTmFtZSk7XG4gICAgICAgIGxvZy5pbmZvKGBDcmVhdGluZyByZXNwb25zZSBxdWV1ZSBzdWJzY3JpcHRpb25gKTtcbiAgICAgICAgYXdhaXQgcHVic3ViLnByb2plY3RzLnN1YnNjcmlwdGlvbnMuY3JlYXRlKHtcbiAgICAgICAgICAgIG5hbWU6IHJlc291cmNlcy5yZXNwb25zZVN1YnNjcmlwdGlvbixcbiAgICAgICAgICAgIHJlcXVlc3RCb2R5OiB7XG4gICAgICAgICAgICAgICAgdG9waWM6IHJlc291cmNlcy5yZXNwb25zZVF1ZXVlVG9waWNcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSkoKTtcblxuICAgIGxldCByZXF1ZXN0UXVldWVQcm9taXNlO1xuICAgIGlmIChtb2RlID09PSBcInF1ZXVlXCIpIHtcbiAgICAgICAgbG9nLmluZm8oYEluaXRpYWxpemluZyBxdWV1ZWApO1xuICAgICAgICByZXNvdXJjZXMucmVxdWVzdFF1ZXVlVG9waWMgPSBnZXRSZXF1ZXN0UXVldWVUb3BpYyhwcm9qZWN0LCBmdW5jdGlvbk5hbWUpO1xuICAgICAgICByZXF1ZXN0UXVldWVQcm9taXNlID0gcHVic3ViLnByb2plY3RzLnRvcGljcy5jcmVhdGUoe1xuICAgICAgICAgICAgbmFtZTogcmVzb3VyY2VzLnJlcXVlc3RRdWV1ZVRvcGljXG4gICAgICAgIH0pO1xuICAgICAgICByZXNvdXJjZXMucmVxdWVzdFN1YnNjcmlwdGlvbiA9IGdldFJlcXVlc3RTdWJzY3JpcHRpb24oXG4gICAgICAgICAgICBwcm9qZWN0LFxuICAgICAgICAgICAgZnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgcmVnaW9uXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3Qgc291cmNlVXBsb2FkVXJsID0gYXdhaXQgY3JlYXRlQ29kZUJ1bmRsZSgpO1xuICAgIGNvbnN0IHsgbWVtb3J5U2l6ZSwgZ29vZ2xlQ2xvdWRGdW5jdGlvbk9wdGlvbnMsIGVudiB9ID0gb3B0aW9ucztcbiAgICBpZiAoIUdvb2dsZUNsb3VkRnVuY3Rpb25zTWVtb3J5U2l6ZXMuZmluZChzaXplID0+IHNpemUgPT09IG1lbW9yeVNpemUpKSB7XG4gICAgICAgIGxvZy53YXJuKGBJbnZhbGlkIG1lbW9yeVNpemUgJHttZW1vcnlTaXplfSBmb3IgR29vZ2xlIENsb3VkIEZ1bmN0aW9uc2ApO1xuICAgIH1cbiAgICBjb25zdCByZXF1ZXN0Qm9keTogQ2xvdWRGdW5jdGlvbnMuU2NoZW1hJENsb3VkRnVuY3Rpb24gPSB7XG4gICAgICAgIG5hbWU6IHRyYW1wb2xpbmUsXG4gICAgICAgIGVudHJ5UG9pbnQ6IFwidHJhbXBvbGluZVwiLFxuICAgICAgICB0aW1lb3V0OiBgJHt0aW1lb3V0fXNgLFxuICAgICAgICBhdmFpbGFibGVNZW1vcnlNYjogbWVtb3J5U2l6ZSxcbiAgICAgICAgc291cmNlVXBsb2FkVXJsLFxuICAgICAgICBlbnZpcm9ubWVudFZhcmlhYmxlczogZW52LFxuICAgICAgICBydW50aW1lOiBcIm5vZGVqczE0XCIsXG4gICAgICAgIC4uLmdvb2dsZUNsb3VkRnVuY3Rpb25PcHRpb25zXG4gICAgfTtcbiAgICBpZiAobW9kZSA9PT0gXCJxdWV1ZVwiKSB7XG4gICAgICAgIGF3YWl0IHJlcXVlc3RRdWV1ZVByb21pc2U7XG4gICAgICAgIHJlcXVlc3RCb2R5LmV2ZW50VHJpZ2dlciA9IHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogXCJwcm92aWRlcnMvY2xvdWQucHVic3ViL2V2ZW50VHlwZXMvdG9waWMucHVibGlzaFwiLFxuICAgICAgICAgICAgcmVzb3VyY2U6IHJlc291cmNlcy5yZXF1ZXN0UXVldWVUb3BpY1xuICAgICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHJlcXVlc3RCb2R5Lmh0dHBzVHJpZ2dlciA9IHt9O1xuICAgIH1cbiAgICBsb2cuaW5mbyhgQ3JlYXRlIGZ1bmN0aW9uIGF0ICR7bG9jYXRpb259YCk7XG4gICAgbG9nLmluZm8oYFJlcXVlc3QgYm9keTogJU9gLCByZXF1ZXN0Qm9keSk7XG4gICAgYXdhaXQgcmV0cnlPcCgzLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsb2cuaW5mbyhgY3JlYXRlIGZ1bmN0aW9uICR7cmVxdWVzdEJvZHkubmFtZX0gWyR7b3B0aW9ucy5kZXNjcmlwdGlvbn1dYCk7XG4gICAgICAgICAgICBhd2FpdCB3YWl0Rm9yKGNsb3VkRnVuY3Rpb25zLCAoKSA9PlxuICAgICAgICAgICAgICAgIGNsb3VkRnVuY3Rpb25zLnByb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnMuY3JlYXRlKHtcbiAgICAgICAgICAgICAgICAgICAgbG9jYXRpb24sXG4gICAgICAgICAgICAgICAgICAgIHJlcXVlc3RCb2R5XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBhd2FpdCBjbG91ZEZ1bmN0aW9ucy5wcm9qZWN0cy5sb2NhdGlvbnMuZnVuY3Rpb25zLnNldElhbVBvbGljeSh7XG4gICAgICAgICAgICAgICAgcmVzb3VyY2U6IHRyYW1wb2xpbmUsXG4gICAgICAgICAgICAgICAgcmVxdWVzdEJvZHk6IHtcbiAgICAgICAgICAgICAgICAgICAgcG9saWN5OiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBiaW5kaW5nczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVtYmVyczogW1wiYWxsVXNlcnNcIl0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvbGU6IFwicm9sZXMvY2xvdWRmdW5jdGlvbnMuaW52b2tlclwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAgKi9cbiAgICAgICAgICAgIGF3YWl0IGRlbGV0ZUZ1bmN0aW9uKGNsb3VkRnVuY3Rpb25zLCB0cmFtcG9saW5lKS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICB7IGNhdXNlOiBlcnIsIG5hbWU6IEZhYXN0RXJyb3JOYW1lcy5FQ1JFQVRFIH0sXG4gICAgICAgICAgICAgICAgXCJmYWlsZWQgdG8gY3JlYXRlIGdvb2dsZSBjbG91ZCBmdW5jdGlvblwiXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgaWYgKG1vZGUgPT09IFwiaHR0cHNcIiB8fCBtb2RlID09PSBcImF1dG9cIikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgZnVuYyA9IGF3YWl0IGNsb3VkRnVuY3Rpb25zLnByb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnMuZ2V0KHtcbiAgICAgICAgICAgICAgICBuYW1lOiB0cmFtcG9saW5lXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKCFmdW5jLmRhdGEuaHR0cHNUcmlnZ2VyKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXCJDb3VsZCBub3QgZ2V0IGh0dHAgdHJpZ2dlciB1cmxcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCB7IHVybCB9ID0gZnVuYy5kYXRhLmh0dHBzVHJpZ2dlciE7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKFwiQ291bGQgbm90IGdldCBodHRwIHRyaWdnZXIgdXJsXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbG9nLmluZm8oYEZ1bmN0aW9uIFVSTDogJHt1cmx9YCk7XG4gICAgICAgICAgICBzdGF0ZS51cmwgPSB1cmw7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICBlcnIsXG4gICAgICAgICAgICAgICAgYENvdWxkIG5vdCBnZXQgZnVuY3Rpb24gJHt0cmFtcG9saW5lfSBvciBpdHMgdXJsLCBkZXNwaXRlIGl0IGJlaW5nIGNyZWF0ZWRgXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGF3YWl0IHByaWNpbmdQcm9taXNlO1xuICAgIGF3YWl0IHJlc3BvbnNlUXVldWVQcm9taXNlO1xuICAgIHJldHVybiBzdGF0ZTtcbn1cblxuZnVuY3Rpb24gZ2V0UmVxdWVzdFF1ZXVlVG9waWMocHJvamVjdDogc3RyaW5nLCBmdW5jdGlvbk5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBgcHJvamVjdHMvJHtwcm9qZWN0fS90b3BpY3MvJHtmdW5jdGlvbk5hbWV9LVJlcXVlc3RzYDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFJlc3BvbnNlUXVldWVUb3BpYyhwcm9qZWN0OiBzdHJpbmcsIGZ1bmN0aW9uTmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGBwcm9qZWN0cy8ke3Byb2plY3R9L3RvcGljcy8ke2Z1bmN0aW9uTmFtZX0tUmVzcG9uc2VzYDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFJlc3BvbnNlU3Vic2NyaXB0aW9uKHByb2plY3Q6IHN0cmluZywgZnVuY3Rpb25OYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYHByb2plY3RzLyR7cHJvamVjdH0vc3Vic2NyaXB0aW9ucy8ke2Z1bmN0aW9uTmFtZX0tUmVzcG9uc2VzYDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFJlcXVlc3RTdWJzY3JpcHRpb24oXG4gICAgcHJvamVjdDogc3RyaW5nLFxuICAgIGZ1bmN0aW9uTmFtZTogc3RyaW5nLFxuICAgIHJlZ2lvbjogc3RyaW5nXG4pIHtcbiAgICByZXR1cm4gYHByb2plY3RzLyR7cHJvamVjdH0vc3Vic2NyaXB0aW9ucy9nY2YtJHtmdW5jdGlvbk5hbWV9LSR7cmVnaW9ufS0ke2Z1bmN0aW9uTmFtZX0tUmVxdWVzdHNgO1xufVxuXG5jb25zdCBhZ2VudCA9IG5ldyBodHRwcy5BZ2VudCh7IGtlZXBBbGl2ZTogdHJ1ZSwgdGltZW91dDogMCwgbWF4U29ja2V0czogMTAwMCB9KTtcblxuYXN5bmMgZnVuY3Rpb24gY2FsbEZ1bmN0aW9uSHR0cHMoXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgY2FsbDogRnVuY3Rpb25DYWxsLFxuICAgIG1ldHJpY3M6IEdvb2dsZU1ldHJpY3MsXG4gICAgY2FuY2VsOiBQcm9taXNlPHZvaWQ+XG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBzb3VyY2UgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgYXhpb3NDb25maWc6IEdheGlvc09wdGlvbnMgPSB7XG4gICAgICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICAgICAgdXJsLFxuICAgICAgICAgICAgaGVhZGVyczogeyBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIiB9LFxuICAgICAgICAgICAgYm9keTogc2VyaWFsaXplKGNhbGwpLFxuICAgICAgICAgICAgc2lnbmFsOiBzb3VyY2Uuc2lnbmFsLFxuICAgICAgICAgICAgcmVzcG9uc2VUeXBlOiBcImpzb25cIixcbiAgICAgICAgICAgIHJldHJ5OiBmYWxzZSxcbiAgICAgICAgICAgIGFnZW50XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IHJhd1Jlc3BvbnNlID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgICAgIGdheGlvcy5yZXF1ZXN0PHZvaWQ+KGF4aW9zQ29uZmlnKSxcbiAgICAgICAgICAgIGNhbmNlbFxuICAgICAgICBdKTtcblxuICAgICAgICBpZiAoIXJhd1Jlc3BvbnNlKSB7XG4gICAgICAgICAgICBsb2cuaW5mbyhgY2FuY2VsbGluZyBnY3AgaW52b2tlYCk7XG4gICAgICAgICAgICBzb3VyY2UuYWJvcnQoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbWV0cmljcy5vdXRib3VuZEJ5dGVzICs9IGNvbXB1dGVIdHRwUmVzcG9uc2VCeXRlcyhyYXdSZXNwb25zZSEuaGVhZGVycyk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICBlcnIsXG4gICAgICAgICAgICAgICAgYENvdWxkIG5vdCBwYXJzZSAke3V0aWwuaW5zcGVjdChyYXdSZXNwb25zZS5kYXRhKX1gXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgY29uc3QgeyByZXNwb25zZSB9ID0gZXJyO1xuICAgICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIGlmIChyZXNwb25zZS5zdGF0dXMgPT09IDUwMykge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKFxuICAgICAgICAgICAgICAgICAgICB7IGNhdXNlOiBlcnIsIG5hbWU6IEZhYXN0RXJyb3JOYW1lcy5FTUVNT1JZIH0sXG4gICAgICAgICAgICAgICAgICAgIFwiZ29vZ2xlIGNsb3VkIGZ1bmN0aW9uOiBwb3NzaWJseSBvdXQgb2YgbWVtb3J5XCJcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICBlcnIsXG4gICAgICAgICAgICAgICAgYHdoZW4gaW52b2tpbmcgZ29vZ2xlIGNsb3VkIGZ1bmN0aW9uOiAlc1xcbkRldGFpbHM6ICVzYCxcbiAgICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXNUZXh0LFxuICAgICAgICAgICAgICAgIHJlc3BvbnNlLmRhdGFcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoZXJyLCBgd2hlbiBpbnZva2luZyBnb29nbGUgY2xvdWQgZnVuY3Rpb25gKTtcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGludm9rZShcbiAgICBzdGF0ZTogR29vZ2xlU3RhdGUsXG4gICAgY2FsbDogRnVuY3Rpb25DYWxsLFxuICAgIGNhbmNlbDogUHJvbWlzZTx2b2lkPlxuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBvcHRpb25zLCByZXNvdXJjZXMsIHNlcnZpY2VzLCB1cmwsIG1ldHJpY3MgfSA9IHN0YXRlO1xuICAgIHN3aXRjaCAob3B0aW9ucy5tb2RlKSB7XG4gICAgICAgIGNhc2UgXCJhdXRvXCI6XG4gICAgICAgIGNhc2UgXCJodHRwc1wiOlxuICAgICAgICAgICAgcmV0dXJuIGNhbGxGdW5jdGlvbkh0dHBzKHVybCEsIGNhbGwsIG1ldHJpY3MsIGNhbmNlbCk7XG4gICAgICAgIGNhc2UgXCJxdWV1ZVwiOlxuICAgICAgICAgICAgY29uc3QgeyByZXF1ZXN0UXVldWVUb3BpYyB9ID0gcmVzb3VyY2VzO1xuICAgICAgICAgICAgY29uc3QgeyBwdWJzdWIgfSA9IHNlcnZpY2VzO1xuICAgICAgICAgICAgY29uc3Qgc2VyaWFsaXplZCA9IHNlcmlhbGl6ZShjYWxsKTtcbiAgICAgICAgICAgIHJldHVybiBwdWJsaXNoUHViU3ViKHB1YnN1YiwgcmVxdWVzdFF1ZXVlVG9waWMhLCBzZXJpYWxpemVkKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHBvbGwoc3RhdGU6IEdvb2dsZVN0YXRlLCBjYW5jZWw6IFByb21pc2U8dm9pZD4pOiBQcm9taXNlPFBvbGxSZXN1bHQ+IHtcbiAgICByZXR1cm4gcmVjZWl2ZU1lc3NhZ2VzKFxuICAgICAgICBzdGF0ZS5zZXJ2aWNlcy5wdWJzdWIsXG4gICAgICAgIHN0YXRlLnJlc291cmNlcy5yZXNwb25zZVN1YnNjcmlwdGlvbiEsXG4gICAgICAgIHN0YXRlLm1ldHJpY3MsXG4gICAgICAgIGNhbmNlbFxuICAgICk7XG59XG5cbmZ1bmN0aW9uIHJlc3BvbnNlUXVldWVJZChzdGF0ZTogR29vZ2xlU3RhdGUpIHtcbiAgICByZXR1cm4gc3RhdGUucmVzb3VyY2VzLnJlc3BvbnNlUXVldWVUb3BpYyE7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlbGV0ZVJlc291cmNlcyhcbiAgICBzZXJ2aWNlczogR29vZ2xlU2VydmljZXMsXG4gICAgcmVzb3VyY2VzOiBHb29nbGVSZXNvdXJjZXMsXG4gICAgb3V0cHV0OiAobXNnOiBzdHJpbmcpID0+IHZvaWQgPSBsb2cuaW5mb1xuKSB7XG4gICAgY29uc3Qge1xuICAgICAgICB0cmFtcG9saW5lLFxuICAgICAgICByZXF1ZXN0UXVldWVUb3BpYyxcbiAgICAgICAgcmVxdWVzdFN1YnNjcmlwdGlvbixcbiAgICAgICAgcmVzcG9uc2VTdWJzY3JpcHRpb24sXG4gICAgICAgIHJlc3BvbnNlUXVldWVUb3BpYyxcbiAgICAgICAgcmVnaW9uLFxuICAgICAgICAuLi5yZXN0XG4gICAgfSA9IHJlc291cmNlcztcbiAgICBjb25zdCBfZXhoYXVzdGl2ZUNoZWNrOiBSZXF1aXJlZDx0eXBlb2YgcmVzdD4gPSB7fTtcbiAgICBjb25zdCB7IGNsb3VkRnVuY3Rpb25zLCBwdWJzdWIgfSA9IHNlcnZpY2VzO1xuXG4gICAgLy8gV2UgZGVsaWJlcmF0ZWx5IHJldGhyb3cgdHJhbnNpZW50IGVycm9ycyBoZXJlLCBzbyBvbmx5IGlmIGFsbCBwcmlvclxuICAgIC8vIGRlbGV0ZXMgc3VjY2VlZCBkbyB3ZSBwcm9jZWVkLiBJZiB0aGVyZSdzIGEgdHJhbnNpZW50IGVycm9yIHRoZW4gZnV0dXJlXG4gICAgLy8gZ2FyYmFnZSBjb2xsZWN0aW9uIHdpbGwgY2xlYW4gdXAuIFRoZSBvcmRlciBpcyBpbXBvcnRhbnQ7IHRoZSBmdW5jdGlvblxuICAgIC8vIGl0c2VsZiBtdXN0IGJlIGRlbGV0ZWQgbGFzdC5cbiAgICBjb25zdCBjaGVjayA9IGFzeW5jIDxUPihyZXF1ZXN0OiBQcm9taXNlPFQ+KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCByZXF1ZXN0O1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgICovXG4gICAgICAgICAgICBpZiAoZXJyLm1lc3NhZ2UubWF0Y2goL1Jlc291cmNlIG5vdCBmb3VuZC8pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIGlmIChyZXNwb25zZVN1YnNjcmlwdGlvbikge1xuICAgICAgICBhd2FpdCBjaGVjayhcbiAgICAgICAgICAgIHB1YnN1Yi5wcm9qZWN0cy5zdWJzY3JpcHRpb25zLmRlbGV0ZSh7IHN1YnNjcmlwdGlvbjogcmVzcG9uc2VTdWJzY3JpcHRpb24gfSlcbiAgICAgICAgKTtcbiAgICAgICAgb3V0cHV0KGBEZWxldGVkIHJlc3BvbnNlIHN1YnNjcmlwdGlvbjogJHtyZXNwb25zZVN1YnNjcmlwdGlvbn1gKTtcbiAgICB9XG4gICAgaWYgKHJlc3BvbnNlUXVldWVUb3BpYykge1xuICAgICAgICBhd2FpdCBjaGVjayhwdWJzdWIucHJvamVjdHMudG9waWNzLmRlbGV0ZSh7IHRvcGljOiByZXNwb25zZVF1ZXVlVG9waWMgfSkpO1xuICAgICAgICBvdXRwdXQoYERlbGV0ZWQgcmVzcG9uc2UgcXVldWUgdG9waWM6ICR7cmVzcG9uc2VRdWV1ZVRvcGljfWApO1xuICAgIH1cbiAgICBpZiAocmVxdWVzdFN1YnNjcmlwdGlvbikge1xuICAgICAgICBhd2FpdCBjaGVjayhcbiAgICAgICAgICAgIHB1YnN1Yi5wcm9qZWN0cy5zdWJzY3JpcHRpb25zLmRlbGV0ZSh7IHN1YnNjcmlwdGlvbjogcmVxdWVzdFN1YnNjcmlwdGlvbiB9KVxuICAgICAgICApO1xuICAgICAgICBvdXRwdXQoYERlbGV0ZWQgcmVzcG9uc2Ugc3Vic2NyaXB0aW9uOiAke3JlcXVlc3RTdWJzY3JpcHRpb259YCk7XG4gICAgfVxuICAgIGlmIChyZXF1ZXN0UXVldWVUb3BpYykge1xuICAgICAgICBhd2FpdCBjaGVjayhwdWJzdWIucHJvamVjdHMudG9waWNzLmRlbGV0ZSh7IHRvcGljOiByZXF1ZXN0UXVldWVUb3BpYyB9KSk7XG4gICAgICAgIG91dHB1dChgRGVsZXRlZCByZXF1ZXN0IHF1ZXVlIHRvcGljOiAke3JlcXVlc3RRdWV1ZVRvcGljfWApO1xuICAgIH1cbiAgICBpZiAodHJhbXBvbGluZSkge1xuICAgICAgICBhd2FpdCBjaGVjayhkZWxldGVGdW5jdGlvbihjbG91ZEZ1bmN0aW9ucywgdHJhbXBvbGluZSkpO1xuICAgICAgICBvdXRwdXQoYERlbGV0ZWQgZnVuY3Rpb24gJHt0cmFtcG9saW5lfWApO1xuICAgIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFudXAoc3RhdGU6IEdvb2dsZVN0YXRlLCBvcHRpb25zOiBDbGVhbnVwT3B0aW9ucykge1xuICAgIGxvZy5pbmZvKGBnb29nbGUgY2xlYW51cCBzdGFydGluZy5gKTtcbiAgICBpZiAoc3RhdGUuZ2NQcm9taXNlKSB7XG4gICAgICAgIGxvZy5pbmZvKGBXYWl0aW5nIGZvciBnYXJiYWdlIGNvbGxlY3Rpb24uLi5gKTtcbiAgICAgICAgYXdhaXQgc3RhdGUuZ2NQcm9taXNlO1xuICAgICAgICBsb2cuaW5mbyhgR2FyYmFnZSBjb2xsZWN0aW9uIGRvbmUuYCk7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuZGVsZXRlUmVzb3VyY2VzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBkZWxldGVSZXNvdXJjZXMoc3RhdGUuc2VydmljZXMsIHN0YXRlLnJlc291cmNlcyk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihlcnIsIFwiZGVsZXRlIHJlc291cmNlcyBmYWlsZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG4gICAgbG9nLmluZm8oYGdvb2dsZSBjbGVhbnVwIGRvbmUuYCk7XG59XG5cbmxldCBnYXJiYWdlQ29sbGVjdG9yUnVubmluZyA9IGZhbHNlO1xuXG5hc3luYyBmdW5jdGlvbiBjb2xsZWN0R2FyYmFnZShcbiAgICBnY1dvcmtlcjogdHlwZW9mIGRlZmF1bHRHY1dvcmtlcixcbiAgICBzZXJ2aWNlczogR29vZ2xlU2VydmljZXMsXG4gICAgcHJvajogc3RyaW5nLFxuICAgIHJldGVudGlvbkluRGF5czogbnVtYmVyXG4pIHtcbiAgICBpZiAoZ2NXb3JrZXIgPT09IGRlZmF1bHRHY1dvcmtlcikge1xuICAgICAgICBpZiAoZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBnYXJiYWdlQ29sbGVjdG9yUnVubmluZyA9IHRydWU7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHsgY2xvdWRGdW5jdGlvbnMgfSA9IHNlcnZpY2VzO1xuXG4gICAgICAgIGxldCBwYWdlVG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAgICAgICBsZXQgcHJvbWlzZXMgPSBbXTtcbiAgICAgICAgY29uc3Qgc2NoZWR1bGVEZWxldGVSZXNvdXJjZXMgPSB0aHJvdHRsZShcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBjb25jdXJyZW5jeTogNSxcbiAgICAgICAgICAgICAgICByYXRlOiA1LFxuICAgICAgICAgICAgICAgIGJ1cnN0OiAyXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYXN5bmMgKFxuICAgICAgICAgICAgICAgIGdTZXJ2aWNlczogR29vZ2xlU2VydmljZXMsXG4gICAgICAgICAgICAgICAgZm46IENsb3VkRnVuY3Rpb25zLlNjaGVtYSRDbG91ZEZ1bmN0aW9uXG4gICAgICAgICAgICApID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCB7IHJlZ2lvbiwgbmFtZSwgcHJvamVjdCB9ID0gcGFyc2VGdW5jdGlvbk5hbWUoZm4ubmFtZSEpITtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHJlc291cmNlczogR29vZ2xlUmVzb3VyY2VzID0ge1xuICAgICAgICAgICAgICAgICAgICByZWdpb24sXG4gICAgICAgICAgICAgICAgICAgIHRyYW1wb2xpbmU6IGZuLm5hbWUhLFxuICAgICAgICAgICAgICAgICAgICByZXF1ZXN0UXVldWVUb3BpYzogZ2V0UmVxdWVzdFF1ZXVlVG9waWMocHJvamVjdCwgbmFtZSksXG4gICAgICAgICAgICAgICAgICAgIHJlcXVlc3RTdWJzY3JpcHRpb246IGdldFJlcXVlc3RTdWJzY3JpcHRpb24ocHJvamVjdCwgbmFtZSwgcmVnaW9uKSxcbiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VRdWV1ZVRvcGljOiBnZXRSZXNwb25zZVF1ZXVlVG9waWMocHJvamVjdCwgbmFtZSksXG4gICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlU3Vic2NyaXB0aW9uOiBnZXRSZXNwb25zZVN1YnNjcmlwdGlvbihwcm9qZWN0LCBuYW1lKVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgYXdhaXQgZ2NXb3JrZXIocmVzb3VyY2VzLCBnU2VydmljZXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IGZuUGF0dGVybiA9IG5ldyBSZWdFeHAoYC9mdW5jdGlvbnMvZmFhc3QtJHt1dWlkdjRQYXR0ZXJufSRgKTtcbiAgICAgICAgZG8ge1xuICAgICAgICAgICAgY29uc3QgZnVuY0xpc3RSZXNwb25zZSA9XG4gICAgICAgICAgICAgICAgYXdhaXQgY2xvdWRGdW5jdGlvbnMucHJvamVjdHMubG9jYXRpb25zLmZ1bmN0aW9ucy5saXN0KHtcbiAgICAgICAgICAgICAgICAgICAgcGFyZW50OiBgcHJvamVjdHMvJHtwcm9qfS9sb2NhdGlvbnMvLWAsXG4gICAgICAgICAgICAgICAgICAgIHBhZ2VUb2tlblxuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBwYWdlVG9rZW4gPSBmdW5jTGlzdFJlc3BvbnNlLmRhdGEubmV4dFBhZ2VUb2tlbiA/PyB1bmRlZmluZWQ7XG4gICAgICAgICAgICBjb25zdCBnYXJiYWdlRnVuY3Rpb25zID0gKGZ1bmNMaXN0UmVzcG9uc2UuZGF0YS5mdW5jdGlvbnMgfHwgW10pXG4gICAgICAgICAgICAgICAgLmZpbHRlcihmbiA9PiBoYXNFeHBpcmVkKGZuLnVwZGF0ZVRpbWUsIHJldGVudGlvbkluRGF5cykpXG4gICAgICAgICAgICAgICAgLmZpbHRlcihmbiA9PiBmbi5uYW1lIS5tYXRjaChmblBhdHRlcm4pKTtcblxuICAgICAgICAgICAgcHJvbWlzZXMgPSBnYXJiYWdlRnVuY3Rpb25zLm1hcChmbiA9PiBzY2hlZHVsZURlbGV0ZVJlc291cmNlcyhzZXJ2aWNlcywgZm4pKTtcbiAgICAgICAgfSB3aGlsZSAocGFnZVRva2VuKTtcblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKGdjV29ya2VyID09PSBkZWZhdWx0R2NXb3JrZXIpIHtcbiAgICAgICAgICAgIGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlRnVuY3Rpb25OYW1lKHBhdGg6IHN0cmluZykge1xuICAgIGNvbnN0IG1hdGNoID0gcGF0aC5tYXRjaCgvXnByb2plY3RzXFwvKC4qKVxcL2xvY2F0aW9uc1xcLyguKilcXC9mdW5jdGlvbnNcXC8oLiopJC8pO1xuICAgIHJldHVybiBtYXRjaCAmJiB7IHByb2plY3Q6IG1hdGNoWzFdLCByZWdpb246IG1hdGNoWzJdLCBuYW1lOiBtYXRjaFszXSB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiB1cGxvYWRaaXAodXJsOiBzdHJpbmcsIHppcFN0cmVhbTogTm9kZUpTLlJlYWRhYmxlU3RyZWFtKSB7XG4gICAgY29uc3QgY29uZmlnOiBHYXhpb3NPcHRpb25zID0ge1xuICAgICAgICBtZXRob2Q6IFwiUFVUXCIsXG4gICAgICAgIHVybCxcbiAgICAgICAgYm9keTogemlwU3RyZWFtLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICBcImNvbnRlbnQtdHlwZVwiOiBcImFwcGxpY2F0aW9uL3ppcFwiLFxuICAgICAgICAgICAgXCJ4LWdvb2ctY29udGVudC1sZW5ndGgtcmFuZ2VcIjogXCIwLDEwNDg1NzYwMFwiXG4gICAgICAgIH1cbiAgICB9O1xuICAgIHJldHVybiBnYXhpb3MucmVxdWVzdChjb25maWcpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ29vZ2xlUGFja2VyKFxuICAgIGZ1bmN0aW9uTW9kdWxlOiBzdHJpbmcsXG4gICAgb3B0aW9uczogQ29tbW9uT3B0aW9ucyxcbiAgICB3cmFwcGVyT3B0aW9uczogV3JhcHBlck9wdGlvbnMsXG4gICAgRnVuY3Rpb25OYW1lOiBzdHJpbmdcbik6IFByb21pc2U8UGFja2VyUmVzdWx0PiB7XG4gICAgY29uc3QgeyBtb2RlIH0gPSBvcHRpb25zO1xuICAgIGNvbnN0IHRyYW1wb2xpbmVNb2R1bGUgPVxuICAgICAgICBtb2RlID09PSBcInF1ZXVlXCIgPyBnb29nbGVUcmFtcG9saW5lUXVldWUgOiBnb29nbGVUcmFtcG9saW5lSHR0cHM7XG4gICAgcmV0dXJuIHBhY2tlcihcbiAgICAgICAgdHJhbXBvbGluZU1vZHVsZSxcbiAgICAgICAgZnVuY3Rpb25Nb2R1bGUsXG4gICAgICAgIG9wdGlvbnMsXG4gICAgICAgIHdyYXBwZXJPcHRpb25zLFxuICAgICAgICBGdW5jdGlvbk5hbWVcbiAgICApO1xufVxuXG5sZXQgZ2V0R29vZ2xlUHJpY2U6XG4gICAgfCB1bmRlZmluZWRcbiAgICB8ICgoXG4gICAgICAgICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgICAgICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogc3RyaW5nLFxuICAgICAgICAgIGNvbnZlcnNpb25GYWN0b3I6IG51bWJlclxuICAgICAgKSA9PiBQcm9taXNlPG51bWJlcj4pO1xuXG5mdW5jdGlvbiBlbnN1cmVHb29nbGVQcmljZUNhY2hlKGNsb3VkQmlsbGluZzogQ2xvdWRCaWxsaW5nLkNsb3VkYmlsbGluZykge1xuICAgIGlmIChnZXRHb29nbGVQcmljZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGdldEdvb2dsZVByaWNlID0gdGhyb3R0bGUoXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbmN1cnJlbmN5OiAxLFxuICAgICAgICAgICAgcmF0ZTogMyxcbiAgICAgICAgICAgIG1lbW9pemU6IHRydWUsXG4gICAgICAgICAgICBjYWNoZTogY2FjaGVzLmdvb2dsZVByaWNlc1xuICAgICAgICB9LFxuICAgICAgICBhc3luYyAoXG4gICAgICAgICAgICByZWdpb246IHN0cmluZyxcbiAgICAgICAgICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogc3RyaW5nLFxuICAgICAgICAgICAgY29udmVyc2lvbkZhY3RvcjogbnVtYmVyXG4gICAgICAgICkgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBza3VzUmVzcG9uc2UgPSBhd2FpdCBjbG91ZEJpbGxpbmcuc2VydmljZXMuc2t1cy5saXN0KHtcbiAgICAgICAgICAgICAgICAgICAgcGFyZW50OiBzZXJ2aWNlTmFtZVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IHsgc2t1cyA9IFtdIH0gPSBza3VzUmVzcG9uc2UuZGF0YTtcbiAgICAgICAgICAgICAgICBjb25zdCBtYXRjaGluZ1NrdXMgPSBza3VzLmZpbHRlcihza3UgPT4gc2t1LmRlc2NyaXB0aW9uID09PSBkZXNjcmlwdGlvbik7XG4gICAgICAgICAgICAgICAgbG9nLnByb3ZpZGVyKFxuICAgICAgICAgICAgICAgICAgICBgbWF0Y2hpbmcgU0tVczogJHt1dGlsLmluc3BlY3QobWF0Y2hpbmdTa3VzLCB7IGRlcHRoOiBudWxsIH0pfWBcbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgcmVnaW9uT3JHbG9iYWxTa3UgPVxuICAgICAgICAgICAgICAgICAgICBtYXRjaGluZ1NrdXMuZmluZChza3UgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIHNrdS5zZXJ2aWNlUmVnaW9ucyEuZmluZChyID0+IHIgPT09IHJlZ2lvbilcbiAgICAgICAgICAgICAgICAgICAgKSA/P1xuICAgICAgICAgICAgICAgICAgICBtYXRjaGluZ1NrdXMuZmluZChza3UgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIHNrdS5zZXJ2aWNlUmVnaW9ucyEuZmluZChyID0+IHIgPT09IFwiZ2xvYmFsXCIpXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBwZXhwID0gcmVnaW9uT3JHbG9iYWxTa3UhLnByaWNpbmdJbmZvIVswXS5wcmljaW5nRXhwcmVzc2lvbiE7XG4gICAgICAgICAgICAgICAgY29uc3QgcHJpY2VzID0gcGV4cC50aWVyZWRSYXRlcyEubWFwKFxuICAgICAgICAgICAgICAgICAgICByYXRlID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXIocmF0ZS51bml0UHJpY2UhLnVuaXRzID8/IFwiMFwiKSArXG4gICAgICAgICAgICAgICAgICAgICAgICByYXRlLnVuaXRQcmljZSEubmFub3MhIC8gMWU5XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjb25zdCBwcmljZSA9XG4gICAgICAgICAgICAgICAgICAgIE1hdGgubWF4KC4uLnByaWNlcykgKlxuICAgICAgICAgICAgICAgICAgICAoY29udmVyc2lvbkZhY3RvciAvIHBleHAuYmFzZVVuaXRDb252ZXJzaW9uRmFjdG9yISk7XG4gICAgICAgICAgICAgICAgbG9nLnByb3ZpZGVyKFxuICAgICAgICAgICAgICAgICAgICBgRm91bmQgcHJpY2UgZm9yICR7c2VydmljZU5hbWV9LCAke2Rlc2NyaXB0aW9ufSwgJHtyZWdpb259OiAke3ByaWNlfWBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybiBwcmljZTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIGVycixcbiAgICAgICAgICAgICAgICAgICAgYGZhaWxlZCB0byBnZXQgZ29vZ2xlIHByaWNpbmcgZm9yIFwiJHtkZXNjcmlwdGlvbn1cImBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgKTtcbn1cblxubGV0IGdvb2dsZVNlcnZpY2VzOiBjbG91ZGJpbGxpbmdfdjEuU2NoZW1hJFNlcnZpY2VbXSB8IHVuZGVmaW5lZDtcblxuY29uc3QgbGlzdEdvb2dsZVNlcnZpY2VzID0gdGhyb3R0bGUoXG4gICAgeyBjb25jdXJyZW5jeTogMSB9LFxuICAgIGFzeW5jIChjbG91ZEJpbGxpbmc6IENsb3VkQmlsbGluZy5DbG91ZGJpbGxpbmcpID0+IHtcbiAgICAgICAgaWYgKGdvb2dsZVNlcnZpY2VzKSB7XG4gICAgICAgICAgICByZXR1cm4gZ29vZ2xlU2VydmljZXM7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbG91ZEJpbGxpbmcuc2VydmljZXMubGlzdCgpO1xuICAgICAgICBnb29nbGVTZXJ2aWNlcyA9IHJlc3BvbnNlLmRhdGEuc2VydmljZXMhO1xuICAgICAgICByZXR1cm4gZ29vZ2xlU2VydmljZXM7XG4gICAgfVxuKTtcblxuYXN5bmMgZnVuY3Rpb24gZ2V0R29vZ2xlQ2xvdWRGdW5jdGlvbnNQcmljaW5nKFxuICAgIGNsb3VkQmlsbGluZzogQ2xvdWRCaWxsaW5nLkNsb3VkYmlsbGluZyxcbiAgICByZWdpb246IHN0cmluZ1xuKTogUHJvbWlzZTxHb29nbGVDbG91ZFByaWNpbmc+IHtcbiAgICBjb25zdCBzZXJ2aWNlcyA9IGF3YWl0IGxpc3RHb29nbGVTZXJ2aWNlcyhjbG91ZEJpbGxpbmcpO1xuICAgIGVuc3VyZUdvb2dsZVByaWNlQ2FjaGUoY2xvdWRCaWxsaW5nKTtcblxuICAgIGNvbnN0IGdldFByaWNpbmcgPSAoXG4gICAgICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcsXG4gICAgICAgIGNvbnZlcnNpb25GYWN0b3I6IG51bWJlciA9IDFcbiAgICApID0+IHtcbiAgICAgICAgY29uc3Qgc2VydmljZSA9IHNlcnZpY2VzLmZpbmQocyA9PiBzLmRpc3BsYXlOYW1lID09PSBzZXJ2aWNlTmFtZSkhO1xuICAgICAgICByZXR1cm4gZ2V0R29vZ2xlUHJpY2UhKHJlZ2lvbiwgc2VydmljZS5uYW1lISwgZGVzY3JpcHRpb24sIGNvbnZlcnNpb25GYWN0b3IpO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgICBwZXJJbnZvY2F0aW9uOiBhd2FpdCBnZXRQcmljaW5nKFwiQ2xvdWQgRnVuY3Rpb25zXCIsIFwiSW52b2NhdGlvbnNcIiksXG4gICAgICAgIHBlckdoelNlY29uZDogYXdhaXQgZ2V0UHJpY2luZyhcIkNsb3VkIEZ1bmN0aW9uc1wiLCBcIkNQVSBUaW1lXCIpLFxuICAgICAgICBwZXJHYlNlY29uZDogYXdhaXQgZ2V0UHJpY2luZyhcIkNsb3VkIEZ1bmN0aW9uc1wiLCBcIk1lbW9yeSBUaW1lXCIsIDIgKiogMzApLFxuICAgICAgICBwZXJHYk91dGJvdW5kRGF0YTogYXdhaXQgZ2V0UHJpY2luZyhcbiAgICAgICAgICAgIFwiQ2xvdWQgRnVuY3Rpb25zXCIsXG4gICAgICAgICAgICBgTmV0d29yayBFZ3Jlc3MgZnJvbSAke3JlZ2lvbn1gLFxuICAgICAgICAgICAgMiAqKiAzMFxuICAgICAgICApLFxuICAgICAgICBwZXJHYlB1YlN1YjogYXdhaXQgZ2V0UHJpY2luZyhcIkNsb3VkIFB1Yi9TdWJcIiwgXCJNZXNzYWdlIERlbGl2ZXJ5IEJhc2ljXCIsIDIgKiogMzApXG4gICAgfTtcbn1cblxuLy8gaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Z1bmN0aW9ucy9wcmljaW5nXG5jb25zdCBnY2ZQcm92aXNvbmFibGVNZW1vcnlUYWJsZTogeyBbbWVtOiBudW1iZXJdOiBudW1iZXIgfSA9IHtcbiAgICAxMjg6IDAuMixcbiAgICAyNTY6IDAuNCxcbiAgICA1MTI6IDAuOCxcbiAgICAxMDI0OiAxLjQsXG4gICAgMjA0ODogMi40XG59O1xuXG5hc3luYyBmdW5jdGlvbiBjb3N0U25hcHNob3QoXG4gICAgc3RhdGU6IEdvb2dsZVN0YXRlLFxuICAgIHN0YXRzOiBGdW5jdGlvblN0YXRzXG4pOiBQcm9taXNlPENvc3RTbmFwc2hvdD4ge1xuICAgIGNvbnN0IGNvc3RzID0gbmV3IENvc3RTbmFwc2hvdChcImdvb2dsZVwiLCBzdGF0ZS5vcHRpb25zLCBzdGF0cyk7XG4gICAgY29uc3QgeyBtZW1vcnlTaXplID0gZGVmYXVsdHMubWVtb3J5U2l6ZSB9ID0gc3RhdGUub3B0aW9ucztcbiAgICBjb25zdCBwcm92aXNpb25hYmxlU2l6ZXMgPSBrZXlzT2YoZ2NmUHJvdmlzb25hYmxlTWVtb3J5VGFibGUpXG4gICAgICAgIC5tYXAobiA9PiBOdW1iZXIobikpXG4gICAgICAgIC5zb3J0KChhLCBiKSA9PiBhIC0gYik7XG4gICAgY29uc3QgcHJvdmlzaW9uZWRNYiA9IHByb3Zpc2lvbmFibGVTaXplcy5maW5kKHNpemUgPT4gbWVtb3J5U2l6ZSA8PSBzaXplKTtcbiAgICBpZiAoIXByb3Zpc2lvbmVkTWIpIHtcbiAgICAgICAgbG9nLndhcm4oXG4gICAgICAgICAgICBgQ291bGQgbm90IGRldGVybWluZSBwcm92aXNpb25lZCBtZW1vcnkgb3IgQ1BVIGZvciByZXF1ZXN0ZWQgbWVtb3J5IHNpemUgJHttZW1vcnlTaXplfWBcbiAgICAgICAgKTtcbiAgICB9XG4gICAgY29uc3QgcHJvdmlzaW9uZWRHaHogPSBnY2ZQcm92aXNvbmFibGVNZW1vcnlUYWJsZVtwcm92aXNpb25lZE1iIV07XG4gICAgY29uc3QgYmlsbGVkVGltZVN0YXRzID0gc3RhdHMuZXN0aW1hdGVkQmlsbGVkVGltZTtcbiAgICBjb25zdCBzZWNvbmRzID0gKGJpbGxlZFRpbWVTdGF0cy5tZWFuIC8gMTAwMCkgKiBiaWxsZWRUaW1lU3RhdHMuc2FtcGxlcztcblxuICAgIGNvbnN0IHsgcmVnaW9uIH0gPSBzdGF0ZS5yZXNvdXJjZXM7XG4gICAgY29uc3QgcHJpY2VzID0gYXdhaXQgZ2V0R29vZ2xlQ2xvdWRGdW5jdGlvbnNQcmljaW5nKFxuICAgICAgICBzdGF0ZS5zZXJ2aWNlcy5jbG91ZEJpbGxpbmcsXG4gICAgICAgIHJlZ2lvblxuICAgICk7XG5cbiAgICBjb25zdCBwcm92aXNpb25lZEdiID0gcHJvdmlzaW9uZWRNYiEgLyAxMDI0O1xuICAgIGNvbnN0IGZ1bmN0aW9uQ2FsbER1cmF0aW9uID0gbmV3IENvc3RNZXRyaWMoe1xuICAgICAgICBuYW1lOiBcImZ1bmN0aW9uQ2FsbER1cmF0aW9uXCIsXG4gICAgICAgIHByaWNpbmc6XG4gICAgICAgICAgICBwcmljZXMucGVyR2JTZWNvbmQgKiBwcm92aXNpb25lZEdiICsgcHJpY2VzLnBlckdoelNlY29uZCAqIHByb3Zpc2lvbmVkR2h6LFxuICAgICAgICB1bml0OiBcInNlY29uZFwiLFxuICAgICAgICBtZWFzdXJlZDogc2Vjb25kcyxcbiAgICAgICAgY29tbWVudDogYGh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9mdW5jdGlvbnMvcHJpY2luZyNjb21wdXRlX3RpbWUgKCR7cHJvdmlzaW9uZWRNYn0gTUIsICR7cHJvdmlzaW9uZWRHaHp9IEdIeilgXG4gICAgfSk7XG4gICAgY29zdHMucHVzaChmdW5jdGlvbkNhbGxEdXJhdGlvbik7XG5cbiAgICBjb25zdCBmdW5jdGlvbkNhbGxSZXF1ZXN0cyA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJmdW5jdGlvbkNhbGxSZXF1ZXN0c1wiLFxuICAgICAgICBwcmljaW5nOiBwcmljZXMucGVySW52b2NhdGlvbixcbiAgICAgICAgbWVhc3VyZWQ6IHN0YXRzLmludm9jYXRpb25zLFxuICAgICAgICB1bml0OiBcInJlcXVlc3RcIixcbiAgICAgICAgY29tbWVudDogXCJodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vZnVuY3Rpb25zL3ByaWNpbmcjaW52b2NhdGlvbnNcIlxuICAgIH0pO1xuICAgIGNvc3RzLnB1c2goZnVuY3Rpb25DYWxsUmVxdWVzdHMpO1xuXG4gICAgY29uc3Qgb3V0Ym91bmREYXRhVHJhbnNmZXIgPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwib3V0Ym91bmREYXRhVHJhbnNmZXJcIixcbiAgICAgICAgcHJpY2luZzogcHJpY2VzLnBlckdiT3V0Ym91bmREYXRhLFxuICAgICAgICBtZWFzdXJlZDogc3RhdGUubWV0cmljcy5vdXRib3VuZEJ5dGVzIC8gMiAqKiAzMCxcbiAgICAgICAgdW5pdDogXCJHQlwiLFxuICAgICAgICBjb21tZW50OiBcImh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9mdW5jdGlvbnMvcHJpY2luZyNuZXR3b3JraW5nXCJcbiAgICB9KTtcbiAgICBjb3N0cy5wdXNoKG91dGJvdW5kRGF0YVRyYW5zZmVyKTtcblxuICAgIGNvbnN0IHB1YnN1YiA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJwdWJzdWJcIixcbiAgICAgICAgcHJpY2luZzogcHJpY2VzLnBlckdiUHViU3ViLFxuICAgICAgICBtZWFzdXJlZDogc3RhdGUubWV0cmljcy5wdWJTdWJCeXRlcyAvIDIgKiogMzAsXG4gICAgICAgIHVuaXQ6IFwiR0JcIixcbiAgICAgICAgY29tbWVudDogXCJodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vcHVic3ViL3ByaWNpbmdcIlxuICAgIH0pO1xuICAgIGNvc3RzLnB1c2gocHVic3ViKTtcblxuICAgIHJldHVybiBjb3N0cztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1VybChzdGF0ZTogR29vZ2xlU3RhdGUpIHtcbiAgICBjb25zdCB7IHByb2plY3QsIGZ1bmN0aW9uTmFtZSB9ID0gc3RhdGU7XG4gICAgcmV0dXJuIGBodHRwczovL2NvbnNvbGUuY2xvdWQuZ29vZ2xlLmNvbS9sb2dzL3ZpZXdlcj9wcm9qZWN0PSR7cHJvamVjdH0mcmVzb3VyY2U9Y2xvdWRfZnVuY3Rpb24lMkZmdW5jdGlvbl9uYW1lJTJGJHtmdW5jdGlvbk5hbWV9YDtcbn1cbiJdfQ==
\No newline at end of file