UNPKG

95.8 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 wrapperOptions = {
181 childProcessTimeoutMs: Math.max(1000, (timeout - 5) * 1000),
182 wrapperVerbose
183 };
184 const { archive } = await googlePacker(fmodule, options, wrapperOptions, functionName);
185 const uploadUrlResponse = await throttleGoogleWrite(() => cloudFunctions.projects.locations.functions.generateUploadUrl({
186 parent: location
187 }));
188 const uploadResult = await uploadZip(uploadUrlResponse.data.uploadUrl, archive);
189 log_1.log.info(`Upload zip file response: ${uploadResult?.statusText}`);
190 return uploadUrlResponse.data.uploadUrl;
191 }
192 const trampoline = `projects/${project}/locations/${region}/functions/${functionName}`;
193 const resources = {
194 trampoline,
195 region
196 };
197 const state = {
198 resources,
199 services,
200 project,
201 functionName,
202 metrics: new GoogleMetrics(),
203 options
204 };
205 const { gc, retentionInDays, _gcWorker: gcWorker } = options;
206 if (gc === "auto" || gc === "force") {
207 log_1.log.gc(`Starting garbage collector`);
208 state.gcPromise = collectGarbage(gcWorker, services, project, retentionInDays).catch(err => {
209 log_1.log.gc(`Garbage collection error: ${err}`);
210 });
211 }
212 const pricingPromise = getGoogleCloudFunctionsPricing(services.cloudBilling, region);
213 const { mode } = options;
214 const responseQueuePromise = (async () => {
215 const topic = await pubsub.projects.topics.create({
216 name: getResponseQueueTopic(project, functionName)
217 });
218 resources.responseQueueTopic = topic.data.name ?? undefined;
219 resources.responseSubscription = getResponseSubscription(project, functionName);
220 log_1.log.info(`Creating response queue subscription`);
221 await pubsub.projects.subscriptions.create({
222 name: resources.responseSubscription,
223 requestBody: {
224 topic: resources.responseQueueTopic
225 }
226 });
227 })();
228 let requestQueuePromise;
229 if (mode === "queue") {
230 log_1.log.info(`Initializing queue`);
231 resources.requestQueueTopic = getRequestQueueTopic(project, functionName);
232 requestQueuePromise = pubsub.projects.topics.create({
233 name: resources.requestQueueTopic
234 });
235 resources.requestSubscription = getRequestSubscription(project, functionName, region);
236 }
237 const sourceUploadUrl = await createCodeBundle();
238 const { memorySize, googleCloudFunctionOptions, env } = options;
239 if (!GoogleCloudFunctionsMemorySizes.find(size => size === memorySize)) {
240 log_1.log.warn(`Invalid memorySize ${memorySize} for Google Cloud Functions`);
241 }
242 const requestBody = {
243 name: trampoline,
244 entryPoint: "trampoline",
245 timeout: `${timeout}s`,
246 availableMemoryMb: memorySize,
247 sourceUploadUrl,
248 environmentVariables: env,
249 runtime: "nodejs14",
250 ...googleCloudFunctionOptions
251 };
252 if (mode === "queue") {
253 await requestQueuePromise;
254 requestBody.eventTrigger = {
255 eventType: "providers/cloud.pubsub/eventTypes/topic.publish",
256 resource: resources.requestQueueTopic
257 };
258 }
259 else {
260 requestBody.httpsTrigger = {};
261 }
262 log_1.log.info(`Create function at ${location}`);
263 log_1.log.info(`Request body: %O`, requestBody);
264 await (0, throttle_1.retryOp)(3, async () => {
265 try {
266 log_1.log.info(`create function ${requestBody.name} [${options.description}]`);
267 await waitFor(cloudFunctions, () => cloudFunctions.projects.locations.functions.create({
268 location,
269 requestBody
270 }));
271 await cloudFunctions.projects.locations.functions.setIamPolicy({
272 resource: trampoline,
273 requestBody: {
274 policy: {
275 bindings: [
276 {
277 members: ["allUsers"],
278 role: "roles/cloudfunctions.invoker"
279 }
280 ]
281 }
282 }
283 });
284 }
285 catch (err) {
286 /* istanbul ignore next */
287 await deleteFunction(cloudFunctions, trampoline).catch(() => { });
288 throw new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.ECREATE }, "failed to create google cloud function");
289 }
290 });
291 if (mode === "https" || mode === "auto") {
292 try {
293 const func = await cloudFunctions.projects.locations.functions.get({
294 name: trampoline
295 });
296 if (!func.data.httpsTrigger) {
297 throw new error_1.FaastError("Could not get http trigger url");
298 }
299 const { url } = func.data.httpsTrigger;
300 if (!url) {
301 throw new error_1.FaastError("Could not get http trigger url");
302 }
303 log_1.log.info(`Function URL: ${url}`);
304 state.url = url;
305 }
306 catch (err) {
307 throw new error_1.FaastError(err, `Could not get function ${trampoline} or its url, despite it being created`);
308 }
309 }
310 await pricingPromise;
311 await responseQueuePromise;
312 return state;
313}
314exports.initialize = initialize;
315function getRequestQueueTopic(project, functionName) {
316 return `projects/${project}/topics/${functionName}-Requests`;
317}
318function getResponseQueueTopic(project, functionName) {
319 return `projects/${project}/topics/${functionName}-Responses`;
320}
321exports.getResponseQueueTopic = getResponseQueueTopic;
322function getResponseSubscription(project, functionName) {
323 return `projects/${project}/subscriptions/${functionName}-Responses`;
324}
325exports.getResponseSubscription = getResponseSubscription;
326function getRequestSubscription(project, functionName, region) {
327 return `projects/${project}/subscriptions/gcf-${functionName}-${region}-${functionName}-Requests`;
328}
329exports.getRequestSubscription = getRequestSubscription;
330const agent = new https.Agent({ keepAlive: true, timeout: 0, maxSockets: 1000 });
331async function callFunctionHttps(url, call, metrics, cancel) {
332 const source = new abort_controller_1.AbortController();
333 try {
334 const axiosConfig = {
335 method: "POST",
336 url,
337 headers: { "Content-Type": "application/json" },
338 body: (0, serialize_1.serialize)(call),
339 signal: source.signal,
340 responseType: "json",
341 retry: false,
342 agent
343 };
344 const rawResponse = await Promise.race([
345 gaxios.request(axiosConfig),
346 cancel
347 ]);
348 if (!rawResponse) {
349 log_1.log.info(`cancelling gcp invoke`);
350 source.abort();
351 return;
352 }
353 try {
354 metrics.outboundBytes += (0, shared_1.computeHttpResponseBytes)(rawResponse.headers);
355 }
356 catch (err) {
357 throw new error_1.FaastError(err, `Could not parse ${util.inspect(rawResponse.data)}`);
358 }
359 }
360 catch (err) {
361 const { response } = err;
362 if (response) {
363 if (response.status === 503) {
364 throw new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.EMEMORY }, "google cloud function: possibly out of memory");
365 }
366 throw new error_1.FaastError(err, `when invoking google cloud function: %s\nDetails: %s`, response.statusText, response.data);
367 }
368 throw new error_1.FaastError(err, `when invoking google cloud function`);
369 }
370}
371async function invoke(state, call, cancel) {
372 const { options, resources, services, url, metrics } = state;
373 switch (options.mode) {
374 case "auto":
375 case "https":
376 return callFunctionHttps(url, call, metrics, cancel);
377 case "queue":
378 const { requestQueueTopic } = resources;
379 const { pubsub } = services;
380 const serialized = (0, serialize_1.serialize)(call);
381 return (0, google_queue_1.publishPubSub)(pubsub, requestQueueTopic, serialized);
382 }
383}
384function poll(state, cancel) {
385 return (0, google_queue_1.receiveMessages)(state.services.pubsub, state.resources.responseSubscription, state.metrics, cancel);
386}
387function responseQueueId(state) {
388 return state.resources.responseQueueTopic;
389}
390async function deleteResources(services, resources, output = log_1.log.info) {
391 const { trampoline, requestQueueTopic, requestSubscription, responseSubscription, responseQueueTopic, region, ...rest } = resources;
392 const _exhaustiveCheck = {};
393 const { cloudFunctions, pubsub } = services;
394 // We deliberately rethrow transient errors here, so only if all prior
395 // deletes succeed do we proceed. If there's a transient error then future
396 // garbage collection will clean up. The order is important; the function
397 // itself must be deleted last.
398 const check = async (request) => {
399 try {
400 await request;
401 }
402 catch (err) {
403 /* istanbul ignore next */
404 if (err.message.match(/Resource not found/)) {
405 return;
406 }
407 throw err;
408 }
409 };
410 if (responseSubscription) {
411 await check(pubsub.projects.subscriptions.delete({ subscription: responseSubscription }));
412 output(`Deleted response subscription: ${responseSubscription}`);
413 }
414 if (responseQueueTopic) {
415 await check(pubsub.projects.topics.delete({ topic: responseQueueTopic }));
416 output(`Deleted response queue topic: ${responseQueueTopic}`);
417 }
418 if (requestSubscription) {
419 await check(pubsub.projects.subscriptions.delete({ subscription: requestSubscription }));
420 output(`Deleted response subscription: ${requestSubscription}`);
421 }
422 if (requestQueueTopic) {
423 await check(pubsub.projects.topics.delete({ topic: requestQueueTopic }));
424 output(`Deleted request queue topic: ${requestQueueTopic}`);
425 }
426 if (trampoline) {
427 await check(deleteFunction(cloudFunctions, trampoline));
428 output(`Deleted function ${trampoline}`);
429 }
430}
431async function cleanup(state, options) {
432 log_1.log.info(`google cleanup starting.`);
433 if (state.gcPromise) {
434 log_1.log.info(`Waiting for garbage collection...`);
435 await state.gcPromise;
436 log_1.log.info(`Garbage collection done.`);
437 }
438 if (options.deleteResources) {
439 try {
440 await deleteResources(state.services, state.resources);
441 }
442 catch (err) {
443 throw new error_1.FaastError(err, "delete resources failed");
444 }
445 }
446 log_1.log.info(`google cleanup done.`);
447}
448exports.cleanup = cleanup;
449let garbageCollectorRunning = false;
450async function collectGarbage(gcWorker, services, proj, retentionInDays) {
451 if (gcWorker === defaultGcWorker) {
452 if (garbageCollectorRunning) {
453 return;
454 }
455 garbageCollectorRunning = true;
456 }
457 try {
458 const { cloudFunctions } = services;
459 let pageToken;
460 let promises = [];
461 const scheduleDeleteResources = (0, throttle_1.throttle)({
462 concurrency: 5,
463 rate: 5,
464 burst: 2
465 }, async (gServices, fn) => {
466 const { region, name, project } = parseFunctionName(fn.name);
467 const resources = {
468 region,
469 trampoline: fn.name,
470 requestQueueTopic: getRequestQueueTopic(project, name),
471 requestSubscription: getRequestSubscription(project, name, region),
472 responseQueueTopic: getResponseQueueTopic(project, name),
473 responseSubscription: getResponseSubscription(project, name)
474 };
475 await gcWorker(resources, gServices);
476 });
477 const fnPattern = new RegExp(`/functions/faast-${shared_1.uuidv4Pattern}$`);
478 do {
479 const funcListResponse = await cloudFunctions.projects.locations.functions.list({
480 parent: `projects/${proj}/locations/-`,
481 pageToken
482 });
483 pageToken = funcListResponse.data.nextPageToken ?? undefined;
484 const garbageFunctions = (funcListResponse.data.functions || [])
485 .filter(fn => (0, shared_1.hasExpired)(fn.updateTime, retentionInDays))
486 .filter(fn => fn.name.match(fnPattern));
487 promises = garbageFunctions.map(fn => scheduleDeleteResources(services, fn));
488 } while (pageToken);
489 await Promise.all(promises);
490 }
491 finally {
492 if (gcWorker === defaultGcWorker) {
493 garbageCollectorRunning = false;
494 }
495 }
496}
497function parseFunctionName(path) {
498 const match = path.match(/^projects\/(.*)\/locations\/(.*)\/functions\/(.*)$/);
499 return match && { project: match[1], region: match[2], name: match[3] };
500}
501async function uploadZip(url, zipStream) {
502 const config = {
503 method: "PUT",
504 url,
505 body: zipStream,
506 headers: {
507 "content-type": "application/zip",
508 "x-goog-content-length-range": "0,104857600"
509 }
510 };
511 return gaxios.request(config);
512}
513async function googlePacker(functionModule, options, wrapperOptions, FunctionName) {
514 const { mode } = options;
515 const trampolineModule = mode === "queue" ? googleTrampolineQueue : googleTrampolineHttps;
516 return (0, packer_1.packer)(trampolineModule, functionModule, options, wrapperOptions, FunctionName);
517}
518exports.googlePacker = googlePacker;
519let getGooglePrice;
520function ensureGooglePriceCache(cloudBilling) {
521 if (getGooglePrice) {
522 return;
523 }
524 getGooglePrice = (0, throttle_1.throttle)({
525 concurrency: 1,
526 rate: 3,
527 memoize: true,
528 cache: cache_1.caches.googlePrices
529 }, async (region, serviceName, description, conversionFactor) => {
530 try {
531 const skusResponse = await cloudBilling.services.skus.list({
532 parent: serviceName
533 });
534 const { skus = [] } = skusResponse.data;
535 const matchingSkus = skus.filter(sku => sku.description === description);
536 log_1.log.provider(`matching SKUs: ${util.inspect(matchingSkus, { depth: null })}`);
537 const regionOrGlobalSku = matchingSkus.find(sku => sku.serviceRegions.find(r => r === region)) ??
538 matchingSkus.find(sku => sku.serviceRegions.find(r => r === "global"));
539 const pexp = regionOrGlobalSku.pricingInfo[0].pricingExpression;
540 const prices = pexp.tieredRates.map(rate => Number(rate.unitPrice.units ?? "0") +
541 rate.unitPrice.nanos / 1e9);
542 const price = Math.max(...prices) *
543 (conversionFactor / pexp.baseUnitConversionFactor);
544 log_1.log.provider(`Found price for ${serviceName}, ${description}, ${region}: ${price}`);
545 return price;
546 }
547 catch (err) {
548 throw new error_1.FaastError(err, `failed to get google pricing for "${description}"`);
549 }
550 });
551}
552let googleServices;
553const listGoogleServices = (0, throttle_1.throttle)({ concurrency: 1 }, async (cloudBilling) => {
554 if (googleServices) {
555 return googleServices;
556 }
557 const response = await cloudBilling.services.list();
558 googleServices = response.data.services;
559 return googleServices;
560});
561async function getGoogleCloudFunctionsPricing(cloudBilling, region) {
562 const services = await listGoogleServices(cloudBilling);
563 ensureGooglePriceCache(cloudBilling);
564 const getPricing = (serviceName, description, conversionFactor = 1) => {
565 const service = services.find(s => s.displayName === serviceName);
566 return getGooglePrice(region, service.name, description, conversionFactor);
567 };
568 return {
569 perInvocation: await getPricing("Cloud Functions", "Invocations"),
570 perGhzSecond: await getPricing("Cloud Functions", "CPU Time"),
571 perGbSecond: await getPricing("Cloud Functions", "Memory Time", 2 ** 30),
572 perGbOutboundData: await getPricing("Cloud Functions", `Network Egress from ${region}`, 2 ** 30),
573 perGbPubSub: await getPricing("Cloud Pub/Sub", "Message Delivery Basic", 2 ** 30)
574 };
575}
576// https://cloud.google.com/functions/pricing
577const gcfProvisonableMemoryTable = {
578 128: 0.2,
579 256: 0.4,
580 512: 0.8,
581 1024: 1.4,
582 2048: 2.4
583};
584async function costSnapshot(state, stats) {
585 const costs = new cost_1.CostSnapshot("google", state.options, stats);
586 const { memorySize = exports.defaults.memorySize } = state.options;
587 const provisionableSizes = (0, shared_1.keysOf)(gcfProvisonableMemoryTable)
588 .map(n => Number(n))
589 .sort((a, b) => a - b);
590 const provisionedMb = provisionableSizes.find(size => memorySize <= size);
591 if (!provisionedMb) {
592 log_1.log.warn(`Could not determine provisioned memory or CPU for requested memory size ${memorySize}`);
593 }
594 const provisionedGhz = gcfProvisonableMemoryTable[provisionedMb];
595 const billedTimeStats = stats.estimatedBilledTime;
596 const seconds = (billedTimeStats.mean / 1000) * billedTimeStats.samples;
597 const { region } = state.resources;
598 const prices = await getGoogleCloudFunctionsPricing(state.services.cloudBilling, region);
599 const provisionedGb = provisionedMb / 1024;
600 const functionCallDuration = new cost_1.CostMetric({
601 name: "functionCallDuration",
602 pricing: prices.perGbSecond * provisionedGb + prices.perGhzSecond * provisionedGhz,
603 unit: "second",
604 measured: seconds,
605 comment: `https://cloud.google.com/functions/pricing#compute_time (${provisionedMb} MB, ${provisionedGhz} GHz)`
606 });
607 costs.push(functionCallDuration);
608 const functionCallRequests = new cost_1.CostMetric({
609 name: "functionCallRequests",
610 pricing: prices.perInvocation,
611 measured: stats.invocations,
612 unit: "request",
613 comment: "https://cloud.google.com/functions/pricing#invocations"
614 });
615 costs.push(functionCallRequests);
616 const outboundDataTransfer = new cost_1.CostMetric({
617 name: "outboundDataTransfer",
618 pricing: prices.perGbOutboundData,
619 measured: state.metrics.outboundBytes / 2 ** 30,
620 unit: "GB",
621 comment: "https://cloud.google.com/functions/pricing#networking"
622 });
623 costs.push(outboundDataTransfer);
624 const pubsub = new cost_1.CostMetric({
625 name: "pubsub",
626 pricing: prices.perGbPubSub,
627 measured: state.metrics.pubSubBytes / 2 ** 30,
628 unit: "GB",
629 comment: "https://cloud.google.com/pubsub/pricing"
630 });
631 costs.push(pubsub);
632 return costs;
633}
634function logUrl(state) {
635 const { project, functionName } = state;
636 return `https://console.cloud.google.com/logs/viewer?project=${project}&resource=cloud_function%2Ffunction_name%2F${functionName}`;
637}
638exports.logUrl = logUrl;
639//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ29vZ2xlLWZhYXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2dvb2dsZS9nb29nbGUtZmFhc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsdURBQW1EO0FBQ25ELG1DQUE4RTtBQUM5RSwyQ0FNb0I7QUFDcEIsK0JBQStCO0FBQy9CLDZCQUE2QjtBQUM3QixvQ0FBa0M7QUFDbEMsa0NBQW1EO0FBQ25ELG9DQUF1RDtBQUN2RCxnQ0FBNkI7QUFDN0Isc0NBQWlEO0FBQ2pELDBDQVFxQjtBQUNyQiw0Q0FBeUM7QUFDekMsc0NBTW1CO0FBQ25CLDBDQUFnRDtBQUVoRCxpREFBZ0U7QUFDaEUsbURBQXFEO0FBQ3JELG1FQUFtRTtBQUNuRSxtRUFBbUU7QUFNbkUsTUFBTSxNQUFNLEdBQUcsSUFBSSxlQUFNLENBQUM7SUFDdEIsV0FBVyxFQUFFO1FBQ1QsS0FBSyxFQUFFLENBQUM7UUFDUixpQkFBaUIsRUFBRSxDQUFDO1FBQ3BCLFdBQVcsRUFBRSxJQUFBLGtDQUFrQixFQUFDLFNBQUcsQ0FBQyxJQUFJLENBQUM7S0FDNUM7Q0FDSixDQUFDLENBQUM7QUE4QkgsTUFBTSwrQkFBK0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztBQXdEcEUsTUFBYSxhQUFhO0lBQTFCO1FBQ0ksa0JBQWEsR0FBRyxDQUFDLENBQUM7UUFDbEIsZ0JBQVcsR0FBRyxDQUFDLENBQUM7SUFDcEIsQ0FBQztDQUFBO0FBSEQsc0NBR0M7QUF1QkQsU0FBZ0IsZUFBZSxDQUFDLFNBQTBCLEVBQUUsUUFBd0I7SUFDaEYsT0FBTyxlQUFlLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxTQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDeEQsQ0FBQztBQUZELDBDQUVDO0FBRVksUUFBQSxRQUFRLEdBQTRCO0lBQzdDLEdBQUcseUJBQWM7SUFDakIsTUFBTSxFQUFFLGFB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QUssQ0FBQztJQUN4QyxPQUFPLHdEQUF3RCxPQUFPLDhDQUE4QyxZQUFZLEVBQUUsQ0FBQztBQUN2SSxDQUFDO0FBSEQsd0JBR0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBYm9ydENvbnRyb2xsZXIgfSBmcm9tIFwiYWJvcnQtY29udHJvbGxlclwiO1xuaW1wb3J0IHsgR2F4aW9zLCBHYXhpb3NPcHRpb25zLCBHYXhpb3NQcm9taXNlLCBHYXhpb3NSZXNwb25zZSB9IGZyb20gXCJnYXhpb3NcIjtcbmltcG9ydCB7XG4gICAgY2xvdWRiaWxsaW5nX3YxLFxuICAgIGNsb3VkZnVuY3Rpb25zX3YxLFxuICAgIGdvb2dsZSxcbiAgICBHb29nbGVBcGlzLFxuICAgIHB1YnN1Yl92MVxufSBmcm9tIFwiZ29vZ2xlYXBpc1wiO1xuaW1wb3J0ICogYXMgaHR0cHMgZnJvbSBcImh0dHBzXCI7XG5pbXBvcnQgKiBhcyB1dGlsIGZyb20gXCJ1dGlsXCI7XG5pbXBvcnQgeyBjYWNoZXMgfSBmcm9tIFwiLi4vY2FjaGVcIjtcbmltcG9ydCB7IENvc3RNZXRyaWMsIENvc3RTbmFwc2hvdCB9IGZyb20gXCIuLi9jb3N0XCI7XG5pbXBvcnQgeyBGYWFzdEVycm9yLCBGYWFzdEVycm9yTmFtZXMgfSBmcm9tIFwiLi4vZXJyb3JcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCIuLi9sb2dcIjtcbmltcG9ydCB7IHBhY2tlciwgUGFja2VyUmVzdWx0IH0gZnJvbSBcIi4uL3BhY2tlclwiO1xuaW1wb3J0IHtcbiAgICBDbGVhbnVwT3B0aW9ucyxcbiAgICBjb21tb25EZWZhdWx0cyxcbiAgICBDb21tb25PcHRpb25zLFxuICAgIEZ1bmN0aW9uU3RhdHMsXG4gICAgUG9sbFJlc3VsdCxcbiAgICBQcm92aWRlckltcGwsXG4gICAgVVVJRFxufSBmcm9tIFwiLi4vcHJvdmlkZXJcIjtcbmltcG9ydCB7IHNlcmlhbGl6ZSB9IGZyb20gXCIuLi9zZXJpYWxpemVcIjtcbmltcG9ydCB7XG4gICAgY29tcHV0ZUh0dHBSZXNwb25zZUJ5dGVzLFxuICAgIGhhc0V4cGlyZWQsXG4gICAga2V5c09mLFxuICAgIHNsZWVwLFxuICAgIHV1aWR2NFBhdHRlcm5cbn0gZnJvbSBcIi4uL3NoYXJlZFwiO1xuaW1wb3J0IHsgcmV0cnlPcCwgdGhyb3R0bGUgfSBmcm9tIFwiLi4vdGhyb3R0bGVcIjtcbmltcG9ydCB7IEZ1bmN0aW9uQ2FsbCwgV3JhcHBlck9wdGlvbnMgfSBmcm9tIFwiLi4vd3JhcHBlclwiO1xuaW1wb3J0IHsgcHVibGlzaFB1YlN1YiwgcmVjZWl2ZU1lc3NhZ2VzIH0gZnJvbSBcIi4vZ29vZ2xlLXF1ZXVlXCI7XG5pbXBvcnQgeyBzaG91bGRSZXRyeVJlcXVlc3QgfSBmcm9tIFwiLi9nb29nbGUtc2hhcmVkXCI7XG5pbXBvcnQgKiBhcyBnb29nbGVUcmFtcG9saW5lSHR0cHMgZnJvbSBcIi4vZ29vZ2xlLXRyYW1wb2xpbmUtaHR0cHNcIjtcbmltcG9ydCAqIGFzIGdvb2dsZVRyYW1wb2xpbmVRdWV1ZSBmcm9tIFwiLi9nb29nbGUtdHJhbXBvbGluZS1xdWV1ZVwiO1xuXG5pbXBvcnQgQ2xvdWRGdW5jdGlvbnMgPSBjbG91ZGZ1bmN0aW9uc192MTtcbmltcG9ydCBQdWJTdWJBcGkgPSBwdWJzdWJfdjE7XG5pbXBvcnQgQ2xvdWRCaWxsaW5nID0gY2xvdWRiaWxsaW5nX3YxO1xuXG5jb25zdCBnYXhpb3MgPSBuZXcgR2F4aW9zKHtcbiAgICByZXRyeUNvbmZpZzoge1xuICAgICAgICByZXRyeTogMyxcbiAgICAgICAgbm9SZXNwb25zZVJldHJpZXM6IDMsXG4gICAgICAgIHNob3VsZFJldHJ5OiBzaG91bGRSZXRyeVJlcXVlc3QobG9nLmluZm8pXG4gICAgfVxufSk7XG5cbi8qKlxuICogVmFsaWQgR29vZ2xlIENsb3VkXG4gKiB7QGxpbmsgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2NvbXB1dGUvZG9jcy9yZWdpb25zLXpvbmVzLyB8IHJlZ2lvbnN9LiBPbmx5XG4gKiBzb21lIG9mIHRoZXNlXG4gKiB7QGxpbmsgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Z1bmN0aW9ucy9kb2NzL2xvY2F0aW9ucyB8IHJlZ2lvbnMgaGF2ZSBDbG91ZCBGdW5jdGlvbnN9LlxuICogQHB1YmxpY1xuICovXG5leHBvcnQgdHlwZSBHb29nbGVSZWdpb24gPVxuICAgIHwgXCJhc2lhLWVhc3QxXCJcbiAgICB8IFwiYXNpYS1lYXN0MlwiXG4gICAgfCBcImFzaWEtbm9ydGhlYXN0MVwiXG4gICAgfCBcImFzaWEtc291dGgxXCJcbiAgICB8IFwiYXNpYS1zb3V0aGVhc3QxXCJcbiAgICB8IFwiYXVzdHJhbGlhLXNvdXRoZWFzdDFcIlxuICAgIHwgXCJldXJvcGUtbm9ydGgxXCJcbiAgICB8IFwiZXVyb3BlLXdlc3QxXCJcbiAgICB8IFwiZXVyb3BlLXdlc3QyXCJcbiAgICB8IFwiZXVyb3BlLXdlc3QzXCJcbiAgICB8IFwiZXVyb3BlLXdlc3Q0XCJcbiAgICB8IFwiZXVyb3BlLXdlc3Q2XCJcbiAgICB8IFwibm9ydGhhbWVyaWNhLW5vcnRoZWFzdDFcIlxuICAgIHwgXCJzb3V0aGFtZXJpY2EtZWFzdDFcIlxuICAgIHwgXCJ1cy1jZW50cmFsMVwiXG4gICAgfCBcInVzLWVhc3QxXCJcbiAgICB8IFwidXMtZWFzdDRcIlxuICAgIHwgXCJ1cy13ZXN0MVwiXG4gICAgfCBcInVzLXdlc3QyXCI7XG5cbmNvbnN0IEdvb2dsZUNsb3VkRnVuY3Rpb25zTWVtb3J5U2l6ZXMgPSBbMTI4LCAyNTYsIDUxMiwgMTAyNCwgMjA0OF07XG5cbi8qKlxuICogR29vZ2xlLXNwZWNpZmljIG9wdGlvbnMgZm9yIHtAbGluayBmYWFzdEdvb2dsZX0uXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR29vZ2xlT3B0aW9ucyBleHRlbmRzIENvbW1vbk9wdGlvbnMge1xuICAgIC8qKlxuICAgICAqIFRoZSByZWdpb24gdG8gY3JlYXRlIHJlc291cmNlcyBpbi4gR2FyYmFnZSBjb2xsZWN0aW9uIGlzIGFsc28gbGltaXRlZCB0b1xuICAgICAqIHRoaXMgcmVnaW9uLiBEZWZhdWx0OiBgXCJ1cy1jZW50cmFsMVwiYC5cbiAgICAgKi9cbiAgICByZWdpb24/OiBHb29nbGVSZWdpb247XG4gICAgLyoqXG4gICAgICogQWRkaXRpb25hbCBvcHRpb25zIHRvIHBhc3MgdG8gR29vZ2xlIENsb3VkIEZ1bmN0aW9uIGNyZWF0aW9uLiBTZWVcbiAgICAgKiB7QGxpbmsgaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Z1bmN0aW9ucy9kb2NzL3JlZmVyZW5jZS9yZXN0L3YxL3Byb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnMjQ2xvdWRGdW5jdGlvbiB8IHByb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnN9LlxuICAgICAqIEByZW1hcmtzXG4gICAgICogSWYgeW91IG5lZWQgc3BlY2lhbGl6ZWQgb3B0aW9ucywgeW91IGNhbiBwYXNzIHRoZW0gdG8gdGhlIEdvb2dsZSBDbG91ZFxuICAgICAqIEZ1bmN0aW9ucyBBUEkgZGlyZWN0bHkuIE5vdGUgdGhhdCBpZiB5b3Ugb3ZlcnJpZGUgYW55IHNldHRpbmdzIHNldCBieVxuICAgICAqIGZhYXN0LmpzLCB5b3UgbWF5IGNhdXNlIGZhYXN0LmpzIHRvIG5vdCB3b3JrOlxuICAgICAqXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqICBjb25zdCByZXF1ZXN0Qm9keTogQ2xvdWRGdW5jdGlvbnMuU2NoZW1hJENsb3VkRnVuY3Rpb24gPSB7XG4gICAgICogICAgICBuYW1lLFxuICAgICAqICAgICAgZW50cnlQb2ludDogXCJ0cmFtcG9saW5lXCIsXG4gICAgICogICAgICB0aW1lb3V0LFxuICAgICAqICAgICAgYXZhaWxhYmxlTWVtb3J5TWIsXG4gICAgICogICAgICBzb3VyY2VVcGxvYWRVcmwsXG4gICAgICogICAgICBydW50aW1lOiBcIm5vZGVqczE0XCIsXG4gICAgICogICAgICAuLi5nb29nbGVDbG91ZEZ1bmN0aW9uT3B0aW9uc1xuICAgICAqICB9O1xuICAgICAqIGBgYFxuICAgICAqXG4gICAgICovXG4gICAgZ29vZ2xlQ2xvdWRGdW5jdGlvbk9wdGlvbnM/OiBDbG91ZEZ1bmN0aW9ucy5TY2hlbWEkQ2xvdWRGdW5jdGlvbjtcblxuICAgIC8qKiBAaW50ZXJuYWwgKi9cbiAgICBfZ2NXb3JrZXI/OiAocmVzb3VyY2VzOiBHb29nbGVSZXNvdXJjZXMsIHNlcnZpY2VzOiBHb29nbGVTZXJ2aWNlcykgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHb29nbGVSZXNvdXJjZXMge1xuICAgIHRyYW1wb2xpbmU6IHN0cmluZztcbiAgICByZXF1ZXN0UXVldWVUb3BpYz86IHN0cmluZztcbiAgICByZXF1ZXN0U3Vic2NyaXB0aW9uPzogc3RyaW5nO1xuICAgIHJlc3BvbnNlUXVldWVUb3BpYz86IHN0cmluZztcbiAgICByZXNwb25zZVN1YnNjcmlwdGlvbj86IHN0cmluZztcbiAgICByZWdpb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHb29nbGVDbG91ZFByaWNpbmcge1xuICAgIHBlckludm9jYXRpb246IG51bWJlcjtcbiAgICBwZXJHaHpTZWNvbmQ6IG51bWJlcjtcbiAgICBwZXJHYlNlY29uZDogbnVtYmVyO1xuICAgIHBlckdiT3V0Ym91bmREYXRhOiBudW1iZXI7XG4gICAgcGVyR2JQdWJTdWI6IG51bWJlcjtcbn1cblxuZXhwb3J0IGNsYXNzIEdvb2dsZU1ldHJpY3Mge1xuICAgIG91dGJvdW5kQnl0ZXMgPSAwO1xuICAgIHB1YlN1YkJ5dGVzID0gMDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHb29nbGVTZXJ2aWNlcyB7XG4gICAgcmVhZG9ubHkgY2xvdWRGdW5jdGlvbnM6IENsb3VkRnVuY3Rpb25zLkNsb3VkZnVuY3Rpb25zO1xuICAgIHJlYWRvbmx5IHB1YnN1YjogUHViU3ViQXBpLlB1YnN1YjtcbiAgICByZWFkb25seSBnb29nbGU6IEdvb2dsZUFwaXM7XG4gICAgcmVhZG9ubHkgY2xvdWRCaWxsaW5nOiBDbG91ZEJpbGxpbmcuQ2xvdWRiaWxsaW5nO1xufVxuXG4vKipcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdvb2dsZVN0YXRlIHtcbiAgICByZXNvdXJjZXM6IEdvb2dsZVJlc291cmNlcztcbiAgICBzZXJ2aWNlczogR29vZ2xlU2VydmljZXM7XG4gICAgdXJsPzogc3RyaW5nO1xuICAgIHByb2plY3Q6IHN0cmluZztcbiAgICBmdW5jdGlvbk5hbWU6IHN0cmluZztcbiAgICBtZXRyaWNzOiBHb29nbGVNZXRyaWNzO1xuICAgIG9wdGlvbnM6IFJlcXVpcmVkPEdvb2dsZU9wdGlvbnM+O1xuICAgIGdjUHJvbWlzZT86IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZWZhdWx0R2NXb3JrZXIocmVzb3VyY2VzOiBHb29nbGVSZXNvdXJjZXMsIHNlcnZpY2VzOiBHb29nbGVTZXJ2aWNlcykge1xuICAgIHJldHVybiBkZWxldGVSZXNvdXJjZXMoc2VydmljZXMsIHJlc291cmNlcywgbG9nLmdjKTtcbn1cblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRzOiBSZXF1aXJlZDxHb29nbGVPcHRpb25zPiA9IHtcbiAgICAuLi5jb21tb25EZWZhdWx0cyxcbiAgICByZWdpb246IFwidXMtY2VudHJhbDFcIixcbiAgICBnb29nbGVDbG91ZEZ1bmN0aW9uT3B0aW9uczoge30sXG4gICAgX2djV29ya2VyOiBkZWZhdWx0R2NXb3JrZXJcbn07XG5cbmV4cG9ydCBjb25zdCBHb29nbGVJbXBsOiBQcm92aWRlckltcGw8R29vZ2xlT3B0aW9ucywgR29vZ2xlU3RhdGU+ID0ge1xuICAgIG5hbWU6IFwiZ29vZ2xlXCIsXG4gICAgaW5pdGlhbGl6ZSxcbiAgICBkZWZhdWx0cyxcbiAgICBjbGVhbnVwLFxuICAgIGNvc3RTbmFwc2hvdCxcbiAgICBsb2dVcmwsXG4gICAgaW52b2tlLFxuICAgIHBvbGwsXG4gICAgcmVzcG9uc2VRdWV1ZUlkXG59O1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdGlhbGl6ZUdvb2dsZVNlcnZpY2VzKCk6IFByb21pc2U8R29vZ2xlU2VydmljZXM+IHtcbiAgICBjb25zdCBhdXRoID0gYXdhaXQgZ29vZ2xlLmF1dGguZ2V0Q2xpZW50KHtcbiAgICAgICAgc2NvcGVzOiBbXCJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2Nsb3VkLXBsYXRmb3JtXCJdXG4gICAgfSk7XG5cbiAgICBnb29nbGUub3B0aW9ucyh7XG4gICAgICAgIGF1dGgsXG4gICAgICAgIHJldHJ5Q29uZmlnOiB7XG4gICAgICAgICAgICByZXRyeTogOCxcbiAgICAgICAgICAgIHJldHJ5RGVsYXk6IDI1MCxcbiAgICAgICAgICAgIG5vUmVzcG9uc2VSZXRyaWVzOiAzLFxuICAgICAgICAgICAgc2hvdWxkUmV0cnk6IHNob3VsZFJldHJ5UmVxdWVzdChsb2cuaW5mbylcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiB7XG4gICAgICAgIGNsb3VkRnVuY3Rpb25zOiBnb29nbGUuY2xvdWRmdW5jdGlvbnMoXCJ2MVwiKSxcbiAgICAgICAgcHVic3ViOiBnb29nbGUucHVic3ViKFwidjFcIiksXG4gICAgICAgIGNsb3VkQmlsbGluZzogZ29vZ2xlLmNsb3VkYmlsbGluZyhcInYxXCIpLFxuICAgICAgICBnb29nbGVcbiAgICB9O1xufVxuXG5pbnRlcmZhY2UgUG9sbE9wdGlvbnMge1xuICAgIG1heFJldHJpZXM/OiBudW1iZXI7XG4gICAgZGVsYXk/OiAocmV0cmllczogbnVtYmVyKSA9PiBQcm9taXNlPHZvaWQ+O1xufVxuXG5pbnRlcmZhY2UgUG9sbENvbmZpZzxUPiBleHRlbmRzIFBvbGxPcHRpb25zIHtcbiAgICByZXF1ZXN0OiAoKSA9PiBQcm9taXNlPFQ+O1xuICAgIGNoZWNrRG9uZTogKHJlc3VsdDogVCkgPT4gYm9vbGVhbjtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGVmYXVsdFBvbGxEZWxheShyZXRyaWVzOiBudW1iZXIpIHtcbiAgICBpZiAocmV0cmllcyA+IDUpIHtcbiAgICAgICAgYXdhaXQgc2xlZXAoNSAqIDEwMDApO1xuICAgIH1cbiAgICBhd2FpdCBzbGVlcCgocmV0cmllcyArIDEpICogNTAwKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcG9sbE9wZXJhdGlvbjxUPih7XG4gICAgcmVxdWVzdCxcbiAgICBjaGVja0RvbmUsXG4gICAgZGVsYXkgPSBkZWZhdWx0UG9sbERlbGF5LFxuICAgIG1heFJldHJpZXMgPSA1MFxufTogUG9sbENvbmZpZzxUPik6IFByb21pc2U8VCB8IHVuZGVmaW5lZD4ge1xuICAgIGxldCByZXRyaWVzID0gMDtcbiAgICBhd2FpdCBkZWxheShyZXRyaWVzKTtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBsb2cuaW5mbyhgUG9sbGluZy4uLmApO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCByZXF1ZXN0KCk7XG4gICAgICAgIGlmIChjaGVja0RvbmUocmVzdWx0KSkge1xuICAgICAgICAgICAgbG9nLmluZm8oYERvbmUuYCk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZXRyaWVzKysgPj0gbWF4UmV0cmllcykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoYFRpbWVkIG91dCBhZnRlciAke3JldHJpZXN9IGF0dGVtcHRzLmApO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGRlbGF5KHJldHJpZXMpO1xuICAgIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcXVpZXRseTxUPihwcm9taXNlOiBHYXhpb3NQcm9taXNlPFQ+KSB7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHJvbWlzZTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdC5kYXRhO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG59XG5cbmNvbnN0IHRocm90dGxlR29vZ2xlV3JpdGUgPSB0aHJvdHRsZShcbiAgICB7XG4gICAgICAgIGNvbmN1cnJlbmN5OiA0LFxuICAgICAgICByYXRlOiAzLFxuICAgICAgICByZXRyeTogKGVyciwgbikgPT4ge1xuICAgICAgICAgICAgY29uc3QgeyBtZXNzYWdlIH0gPSBlcnIgYXMgRXJyb3I7XG4gICAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgICAgIG4gPCA2ICYmXG4gICAgICAgICAgICAgICAgKG1lc3NhZ2UubWF0Y2goL0J1aWxkIGZhaWxlZC8pICE9PSBudWxsIHx8XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UubWF0Y2goL1F1b3RhLykgIT09IG51bGwgfHxcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZS5tYXRjaCgvbG9hZCBhdHRlbXB0IHRpbWVkIG91dC8pICE9PSBudWxsIHx8XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UubWF0Y2goL0VDT05OUkVTRVQvKSAhPT0gbnVsbCB8fFxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlLm1hdGNoKC9mYWlsZWQgb24gbG9hZGluZyB1c2VyIGNvZGUvKSAhPSBudWxsKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgPFQ+KG9wOiAoKSA9PiBQcm9taXNlPFQ+KSA9PiBvcCgpXG4pO1xuXG5hc3luYyBmdW5jdGlvbiB3YWl0Rm9yKFxuICAgIGFwaTogQ2xvdWRGdW5jdGlvbnMuQ2xvdWRmdW5jdGlvbnMsXG4gICAgcmVzcG9uc2U6ICgpID0+IEdheGlvc1Byb21pc2U8Q2xvdWRGdW5jdGlvbnMuU2NoZW1hJE9wZXJhdGlvbj5cbikge1xuICAgIHJldHVybiB0aHJvdHRsZUdvb2dsZVdyaXRlKGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IG9wZXJhdGlvbjogR2F4aW9zUmVzcG9uc2U8Q2xvdWRGdW5jdGlvbnMuU2NoZW1hJE9wZXJhdGlvbj47XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBvcGVyYXRpb24gPSBhd2FpdCByZXNwb25zZSgpO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoZXJyLCBcImNvdWxkIG5vdCBnZXQgb3BlcmF0aW9uXCIpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG9wZXJhdGlvbk5hbWUgPSBvcGVyYXRpb24uZGF0YS5uYW1lITtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBwb2xsT3BlcmF0aW9uKHtcbiAgICAgICAgICAgICAgICByZXF1ZXN0OiAoKSA9PiBxdWlldGx5KGFwaS5vcGVyYXRpb25zLmdldCh7IG5hbWU6IG9wZXJhdGlvbk5hbWUgfSkpLFxuICAgICAgICAgICAgICAgIGNoZWNrRG9uZTogcmVzdWx0ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1bmRlcmx5aW5nID0gbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LmVycm9yLm1lc3NhZ2UgPz8gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgdW5kZXJseWluZy5zdGFjayA9IFwiXCI7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcih1bmRlcmx5aW5nLCBcIkVycm9yIHBvbGxpbmcgb3BlcmF0aW9uXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQuZG9uZSB8fCBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKGVyciwgXCJwb2xsIG9wZXJhdGlvbiBmYWlsZWRcIik7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGVsZXRlRnVuY3Rpb24oYXBpOiBDbG91ZEZ1bmN0aW9ucy5DbG91ZGZ1bmN0aW9ucywgcGF0aDogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHdhaXRGb3IoYXBpLCAoKSA9PlxuICAgICAgICAgICAgYXBpLnByb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnMuZGVsZXRlKHtcbiAgICAgICAgICAgICAgICBuYW1lOiBwYXRoXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGlmIChlcnIubWVzc2FnZS5tYXRjaCgvZG9lcyBub3QgZXhpc3QvKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycjtcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbml0aWFsaXplKFxuICAgIGZtb2R1bGU6IHN0cmluZyxcbiAgICBub25jZTogVVVJRCxcbiAgICBvcHRpb25zOiBSZXF1aXJlZDxHb29nbGVPcHRpb25zPlxuKTogUHJvbWlzZTxHb29nbGVTdGF0ZT4ge1xuICAgIGxvZy5pbmZvKGBDcmVhdGUgZ29vZ2xlIGNsb3VkIGZ1bmN0aW9uYCk7XG4gICAgY29uc3Qgc2VydmljZXMgPSBhd2FpdCBpbml0aWFsaXplR29vZ2xlU2VydmljZXMoKTtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ29vZ2xlLmF1dGguZ2V0UHJvamVjdElkKCk7XG4gICAgY29uc3QgeyBjbG91ZEZ1bmN0aW9ucywgcHVic3ViIH0gPSBzZXJ2aWNlcztcbiAgICBjb25zdCB7IHJlZ2lvbiB9ID0gb3B0aW9ucztcbiAgICBjb25zdCBsb2NhdGlvbiA9IGBwcm9qZWN0cy8ke3Byb2plY3R9L2xvY2F0aW9ucy8ke3JlZ2lvbn1gO1xuICAgIGNvbnN0IGZ1bmN0aW9uTmFtZSA9IFwiZmFhc3QtXCIgKyBub25jZTtcblxuICAgIGNvbnN0IHsgdGltZW91dCB9ID0gb3B0aW9ucztcbiAgICBjb25zdCB7IHdyYXBwZXJWZXJib3NlIH0gPSBvcHRpb25zLmRlYnVnT3B0aW9ucztcbiAgICBhc3luYyBmdW5jdGlvbiBjcmVhdGVDb2RlQnVuZGxlKCkge1xuICAgICAgICBjb25zdCB3cmFwcGVyT3B0aW9ucyA9IHtcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzc1RpbWVvdXRNczogTWF0aC5tYXgoMTAwMCwgKHRpbWVvdXQgLSA1KSAqIDEwMDApLFxuICAgICAgICAgICAgd3JhcHBlclZlcmJvc2VcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgeyBhcmNoaXZlIH0gPSBhd2FpdCBnb29nbGVQYWNrZXIoXG4gICAgICAgICAgICBmbW9kdWxlLFxuICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgIHdyYXBwZXJPcHRpb25zLFxuICAgICAgICAgICAgZnVuY3Rpb25OYW1lXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHVwbG9hZFVybFJlc3BvbnNlID0gYXdhaXQgdGhyb3R0bGVHb29nbGVXcml0ZSgoKSA9PlxuICAgICAgICAgICAgY2xvdWRGdW5jdGlvbnMucHJvamVjdHMubG9jYXRpb25zLmZ1bmN0aW9ucy5nZW5lcmF0ZVVwbG9hZFVybCh7XG4gICAgICAgICAgICAgICAgcGFyZW50OiBsb2NhdGlvblxuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCB1cGxvYWRSZXN1bHQgPSBhd2FpdCB1cGxvYWRaaXAodXBsb2FkVXJsUmVzcG9uc2UuZGF0YS51cGxvYWRVcmwhLCBhcmNoaXZlKTtcbiAgICAgICAgbG9nLmluZm8oYFVwbG9hZCB6aXAgZmlsZSByZXNwb25zZTogJHt1cGxvYWRSZXN1bHQ/LnN0YXR1c1RleHR9YCk7XG4gICAgICAgIHJldHVybiB1cGxvYWRVcmxSZXNwb25zZS5kYXRhLnVwbG9hZFVybDtcbiAgICB9XG5cbiAgICBjb25zdCB0cmFtcG9saW5lID0gYHByb2plY3RzLyR7cHJvamVjdH0vbG9jYXRpb25zLyR7cmVnaW9ufS9mdW5jdGlvbnMvJHtmdW5jdGlvbk5hbWV9YDtcblxuICAgIGNvbnN0IHJlc291cmNlczogR29vZ2xlUmVzb3VyY2VzID0ge1xuICAgICAgICB0cmFtcG9saW5lLFxuICAgICAgICByZWdpb25cbiAgICB9O1xuICAgIGNvbnN0IHN0YXRlOiBHb29nbGVTdGF0ZSA9IHtcbiAgICAgICAgcmVzb3VyY2VzLFxuICAgICAgICBzZXJ2aWNlcyxcbiAgICAgICAgcHJvamVjdCxcbiAgICAgICAgZnVuY3Rpb25OYW1lLFxuICAgICAgICBtZXRyaWNzOiBuZXcgR29vZ2xlTWV0cmljcygpLFxuICAgICAgICBvcHRpb25zXG4gICAgfTtcblxuICAgIGNvbnN0IHsgZ2MsIHJldGVudGlvbkluRGF5cywgX2djV29ya2VyOiBnY1dvcmtlciB9ID0gb3B0aW9ucztcbiAgICBpZiAoZ2MgPT09IFwiYXV0b1wiIHx8IGdjID09PSBcImZvcmNlXCIpIHtcbiAgICAgICAgbG9nLmdjKGBTdGFydGluZyBnYXJiYWdlIGNvbGxlY3RvcmApO1xuICAgICAgICBzdGF0ZS5nY1Byb21pc2UgPSBjb2xsZWN0R2FyYmFnZShcbiAgICAgICAgICAgIGdjV29ya2VyLFxuICAgICAgICAgICAgc2VydmljZXMsXG4gICAgICAgICAgICBwcm9qZWN0LFxuICAgICAgICAgICAgcmV0ZW50aW9uSW5EYXlzXG4gICAgICAgICkuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgIGxvZy5nYyhgR2FyYmFnZSBjb2xsZWN0aW9uIGVycm9yOiAke2Vycn1gKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgcHJpY2luZ1Byb21pc2UgPSBnZXRHb29nbGVDbG91ZEZ1bmN0aW9uc1ByaWNpbmcoc2VydmljZXMuY2xvdWRCaWxsaW5nLCByZWdpb24pO1xuXG4gICAgY29uc3QgeyBtb2RlIH0gPSBvcHRpb25zO1xuXG4gICAgY29uc3QgcmVzcG9uc2VRdWV1ZVByb21pc2UgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCB0b3BpYyA9IGF3YWl0IHB1YnN1Yi5wcm9qZWN0cy50b3BpY3MuY3JlYXRlKHtcbiAgICAgICAgICAgIG5hbWU6IGdldFJlc3BvbnNlUXVldWVUb3BpYyhwcm9qZWN0LCBmdW5jdGlvbk5hbWUpXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJlc291cmNlcy5yZXNwb25zZVF1ZXVlVG9waWMgPSB0b3BpYy5kYXRhLm5hbWUgPz8gdW5kZWZpbmVkO1xuICAgICAgICByZXNvdXJjZXMucmVzcG9uc2VTdWJzY3JpcHRpb24gPSBnZXRSZXNwb25zZVN1YnNjcmlwdGlvbihwcm9qZWN0LCBmdW5jdGlvbk5hbWUpO1xuICAgICAgICBsb2cuaW5mbyhgQ3JlYXRpbmcgcmVzcG9uc2UgcXVldWUgc3Vic2NyaXB0aW9uYCk7XG4gICAgICAgIGF3YWl0IHB1YnN1Yi5wcm9qZWN0cy5zdWJzY3JpcHRpb25zLmNyZWF0ZSh7XG4gICAgICAgICAgICBuYW1lOiByZXNvdXJjZXMucmVzcG9uc2VTdWJzY3JpcHRpb24sXG4gICAgICAgICAgICByZXF1ZXN0Qm9keToge1xuICAgICAgICAgICAgICAgIHRvcGljOiByZXNvdXJjZXMucmVzcG9uc2VRdWV1ZVRvcGljXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pKCk7XG5cbiAgICBsZXQgcmVxdWVzdFF1ZXVlUHJvbWlzZTtcbiAgICBpZiAobW9kZSA9PT0gXCJxdWV1ZVwiKSB7XG4gICAgICAgIGxvZy5pbmZvKGBJbml0aWFsaXppbmcgcXVldWVgKTtcbiAgICAgICAgcmVzb3VyY2VzLnJlcXVlc3RRdWV1ZVRvcGljID0gZ2V0UmVxdWVzdFF1ZXVlVG9waWMocHJvamVjdCwgZnVuY3Rpb25OYW1lKTtcbiAgICAgICAgcmVxdWVzdFF1ZXVlUHJvbWlzZSA9IHB1YnN1Yi5wcm9qZWN0cy50b3BpY3MuY3JlYXRlKHtcbiAgICAgICAgICAgIG5hbWU6IHJlc291cmNlcy5yZXF1ZXN0UXVldWVUb3BpY1xuICAgICAgICB9KTtcbiAgICAgICAgcmVzb3VyY2VzLnJlcXVlc3RTdWJzY3JpcHRpb24gPSBnZXRSZXF1ZXN0U3Vic2NyaXB0aW9uKFxuICAgICAgICAgICAgcHJvamVjdCxcbiAgICAgICAgICAgIGZ1bmN0aW9uTmFtZSxcbiAgICAgICAgICAgIHJlZ2lvblxuICAgICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHNvdXJjZVVwbG9hZFVybCA9IGF3YWl0IGNyZWF0ZUNvZGVCdW5kbGUoKTtcbiAgICBjb25zdCB7IG1lbW9yeVNpemUsIGdvb2dsZUNsb3VkRnVuY3Rpb25PcHRpb25zLCBlbnYgfSA9IG9wdGlvbnM7XG4gICAgaWYgKCFHb29nbGVDbG91ZEZ1bmN0aW9uc01lbW9yeVNpemVzLmZpbmQoc2l6ZSA9PiBzaXplID09PSBtZW1vcnlTaXplKSkge1xuICAgICAgICBsb2cud2FybihgSW52YWxpZCBtZW1vcnlTaXplICR7bWVtb3J5U2l6ZX0gZm9yIEdvb2dsZSBDbG91ZCBGdW5jdGlvbnNgKTtcbiAgICB9XG4gICAgY29uc3QgcmVxdWVzdEJvZHk6IENsb3VkRnVuY3Rpb25zLlNjaGVtYSRDbG91ZEZ1bmN0aW9uID0ge1xuICAgICAgICBuYW1lOiB0cmFtcG9saW5lLFxuICAgICAgICBlbnRyeVBvaW50OiBcInRyYW1wb2xpbmVcIixcbiAgICAgICAgdGltZW91dDogYCR7dGltZW91dH1zYCxcbiAgICAgICAgYXZhaWxhYmxlTWVtb3J5TWI6IG1lbW9yeVNpemUsXG4gICAgICAgIHNvdXJjZVVwbG9hZFVybCxcbiAgICAgICAgZW52aXJvbm1lbnRWYXJpYWJsZXM6IGVudixcbiAgICAgICAgcnVudGltZTogXCJub2RlanMxNFwiLFxuICAgICAgICAuLi5nb29nbGVDbG91ZEZ1bmN0aW9uT3B0aW9uc1xuICAgIH07XG4gICAgaWYgKG1vZGUgPT09IFwicXVldWVcIikge1xuICAgICAgICBhd2FpdCByZXF1ZXN0UXVldWVQcm9taXNlO1xuICAgICAgICByZXF1ZXN0Qm9keS5ldmVudFRyaWdnZXIgPSB7XG4gICAgICAgICAgICBldmVudFR5cGU6IFwicHJvdmlkZXJzL2Nsb3VkLnB1YnN1Yi9ldmVudFR5cGVzL3RvcGljLnB1Ymxpc2hcIixcbiAgICAgICAgICAgIHJlc291cmNlOiByZXNvdXJjZXMucmVxdWVzdFF1ZXVlVG9waWNcbiAgICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgICByZXF1ZXN0Qm9keS5odHRwc1RyaWdnZXIgPSB7fTtcbiAgICB9XG4gICAgbG9nLmluZm8oYENyZWF0ZSBmdW5jdGlvbiBhdCAke2xvY2F0aW9ufWApO1xuICAgIGxvZy5pbmZvKGBSZXF1ZXN0IGJvZHk6ICVPYCwgcmVxdWVzdEJvZHkpO1xuICAgIGF3YWl0IHJldHJ5T3AoMywgYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbG9nLmluZm8oYGNyZWF0ZSBmdW5jdGlvbiAke3JlcXVlc3RCb2R5Lm5hbWV9IFske29wdGlvbnMuZGVzY3JpcHRpb259XWApO1xuICAgICAgICAgICAgYXdhaXQgd2FpdEZvcihjbG91ZEZ1bmN0aW9ucywgKCkgPT5cbiAgICAgICAgICAgICAgICBjbG91ZEZ1bmN0aW9ucy5wcm9qZWN0cy5sb2NhdGlvbnMuZnVuY3Rpb25zLmNyZWF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uLFxuICAgICAgICAgICAgICAgICAgICByZXF1ZXN0Qm9keVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgYXdhaXQgY2xvdWRGdW5jdGlvbnMucHJvamVjdHMubG9jYXRpb25zLmZ1bmN0aW9ucy5zZXRJYW1Qb2xpY3koe1xuICAgICAgICAgICAgICAgIHJlc291cmNlOiB0cmFtcG9saW5lLFxuICAgICAgICAgICAgICAgIHJlcXVlc3RCb2R5OiB7XG4gICAgICAgICAgICAgICAgICAgIHBvbGljeToge1xuICAgICAgICAgICAgICAgICAgICAgICAgYmluZGluZ3M6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lbWJlcnM6IFtcImFsbFVzZXJzXCJdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb2xlOiBcInJvbGVzL2Nsb3VkZnVuY3Rpb25zLmludm9rZXJcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgICovXG4gICAgICAgICAgICBhd2FpdCBkZWxldGVGdW5jdGlvbihjbG91ZEZ1bmN0aW9ucywgdHJhbXBvbGluZSkuY2F0Y2goKCkgPT4ge30pO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgeyBjYXVzZTogZXJyLCBuYW1lOiBGYWFzdEVycm9yTmFtZXMuRUNSRUFURSB9LFxuICAgICAgICAgICAgICAgIFwiZmFpbGVkIHRvIGNyZWF0ZSBnb29nbGUgY2xvdWQgZnVuY3Rpb25cIlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIGlmIChtb2RlID09PSBcImh0dHBzXCIgfHwgbW9kZSA9PT0gXCJhdXRvXCIpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGZ1bmMgPSBhd2FpdCBjbG91ZEZ1bmN0aW9ucy5wcm9qZWN0cy5sb2NhdGlvbnMuZnVuY3Rpb25zLmdldCh7XG4gICAgICAgICAgICAgICAgbmFtZTogdHJhbXBvbGluZVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGlmICghZnVuYy5kYXRhLmh0dHBzVHJpZ2dlcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKFwiQ291bGQgbm90IGdldCBodHRwIHRyaWdnZXIgdXJsXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgeyB1cmwgfSA9IGZ1bmMuZGF0YS5odHRwc1RyaWdnZXIhO1xuICAgICAgICAgICAgaWYgKCF1cmwpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcIkNvdWxkIG5vdCBnZXQgaHR0cCB0cmlnZ2VyIHVybFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxvZy5pbmZvKGBGdW5jdGlvbiBVUkw6ICR7dXJsfWApO1xuICAgICAgICAgICAgc3RhdGUudXJsID0gdXJsO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgIGBDb3VsZCBub3QgZ2V0IGZ1bmN0aW9uICR7dHJhbXBvbGluZX0gb3IgaXRzIHVybCwgZGVzcGl0ZSBpdCBiZWluZyBjcmVhdGVkYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhd2FpdCBwcmljaW5nUHJvbWlzZTtcbiAgICBhd2FpdCByZXNwb25zZVF1ZXVlUHJvbWlzZTtcbiAgICByZXR1cm4gc3RhdGU7XG59XG5cbmZ1bmN0aW9uIGdldFJlcXVlc3RRdWV1ZVRvcGljKHByb2plY3Q6IHN0cmluZywgZnVuY3Rpb25OYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYHByb2plY3RzLyR7cHJvamVjdH0vdG9waWNzLyR7ZnVuY3Rpb25OYW1lfS1SZXF1ZXN0c2A7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRSZXNwb25zZVF1ZXVlVG9waWMocHJvamVjdDogc3RyaW5nLCBmdW5jdGlvbk5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBgcHJvamVjdHMvJHtwcm9qZWN0fS90b3BpY3MvJHtmdW5jdGlvbk5hbWV9LVJlc3BvbnNlc2A7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRSZXNwb25zZVN1YnNjcmlwdGlvbihwcm9qZWN0OiBzdHJpbmcsIGZ1bmN0aW9uTmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGBwcm9qZWN0cy8ke3Byb2plY3R9L3N1YnNjcmlwdGlvbnMvJHtmdW5jdGlvbk5hbWV9LVJlc3BvbnNlc2A7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRSZXF1ZXN0U3Vic2NyaXB0aW9uKFxuICAgIHByb2plY3Q6IHN0cmluZyxcbiAgICBmdW5jdGlvbk5hbWU6IHN0cmluZyxcbiAgICByZWdpb246IHN0cmluZ1xuKSB7XG4gICAgcmV0dXJuIGBwcm9qZWN0cy8ke3Byb2plY3R9L3N1YnNjcmlwdGlvbnMvZ2NmLSR7ZnVuY3Rpb25OYW1lfS0ke3JlZ2lvbn0tJHtmdW5jdGlvbk5hbWV9LVJlcXVlc3RzYDtcbn1cblxuY29uc3QgYWdlbnQgPSBuZXcgaHR0cHMuQWdlbnQoeyBrZWVwQWxpdmU6IHRydWUsIHRpbWVvdXQ6IDAsIG1heFNvY2tldHM6IDEwMDAgfSk7XG5cbmFzeW5jIGZ1bmN0aW9uIGNhbGxGdW5jdGlvbkh0dHBzKFxuICAgIHVybDogc3RyaW5nLFxuICAgIGNhbGw6IEZ1bmN0aW9uQ2FsbCxcbiAgICBtZXRyaWNzOiBHb29nbGVNZXRyaWNzLFxuICAgIGNhbmNlbDogUHJvbWlzZTx2b2lkPlxuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgc291cmNlID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGF4aW9zQ29uZmlnOiBHYXhpb3NPcHRpb25zID0ge1xuICAgICAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgICAgIHVybCxcbiAgICAgICAgICAgIGhlYWRlcnM6IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSxcbiAgICAgICAgICAgIGJvZHk6IHNlcmlhbGl6ZShjYWxsKSxcbiAgICAgICAgICAgIHNpZ25hbDogc291cmNlLnNpZ25hbCxcbiAgICAgICAgICAgIHJlc3BvbnNlVHlwZTogXCJqc29uXCIsXG4gICAgICAgICAgICByZXRyeTogZmFsc2UsXG4gICAgICAgICAgICBhZ2VudFxuICAgICAgICB9O1xuICAgICAgICBjb25zdCByYXdSZXNwb25zZSA9IGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgICAgICAgICBnYXhpb3MucmVxdWVzdDx2b2lkPihheGlvc0NvbmZpZyksXG4gICAgICAgICAgICBjYW5jZWxcbiAgICAgICAgXSk7XG5cbiAgICAgICAgaWYgKCFyYXdSZXNwb25zZSkge1xuICAgICAgICAgICAgbG9nLmluZm8oYGNhbmNlbGxpbmcgZ2NwIGludm9rZWApO1xuICAgICAgICAgICAgc291cmNlLmFib3J0KCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIG1ldHJpY3Mub3V0Ym91bmRCeXRlcyArPSBjb21wdXRlSHR0cFJlc3BvbnNlQnl0ZXMocmF3UmVzcG9uc2UhLmhlYWRlcnMpO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgIGBDb3VsZCBub3QgcGFyc2UgJHt1dGlsLmluc3BlY3QocmF3UmVzcG9uc2UuZGF0YSl9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGNvbnN0IHsgcmVzcG9uc2UgfSA9IGVycjtcbiAgICAgICAgaWYgKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSA1MDMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgeyBjYXVzZTogZXJyLCBuYW1lOiBGYWFzdEVycm9yTmFtZXMuRU1FTU9SWSB9LFxuICAgICAgICAgICAgICAgICAgICBcImdvb2dsZSBjbG91ZCBmdW5jdGlvbjogcG9zc2libHkgb3V0IG9mIG1lbW9yeVwiXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoXG4gICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgIGB3aGVuIGludm9raW5nIGdvb2dsZSBjbG91ZCBmdW5jdGlvbjogJXNcXG5EZXRhaWxzOiAlc2AsXG4gICAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzVGV4dCxcbiAgICAgICAgICAgICAgICByZXNwb25zZS5kYXRhXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKGVyciwgYHdoZW4gaW52b2tpbmcgZ29vZ2xlIGNsb3VkIGZ1bmN0aW9uYCk7XG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBpbnZva2UoXG4gICAgc3RhdGU6IEdvb2dsZVN0YXRlLFxuICAgIGNhbGw6IEZ1bmN0aW9uQ2FsbCxcbiAgICBjYW5jZWw6IFByb21pc2U8dm9pZD5cbik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgb3B0aW9ucywgcmVzb3VyY2VzLCBzZXJ2aWNlcywgdXJsLCBtZXRyaWNzIH0gPSBzdGF0ZTtcbiAgICBzd2l0Y2ggKG9wdGlvbnMubW9kZSkge1xuICAgICAgICBjYXNlIFwiYXV0b1wiOlxuICAgICAgICBjYXNlIFwiaHR0cHNcIjpcbiAgICAgICAgICAgIHJldHVybiBjYWxsRnVuY3Rpb25IdHRwcyh1cmwhLCBjYWxsLCBtZXRyaWNzLCBjYW5jZWwpO1xuICAgICAgICBjYXNlIFwicXVldWVcIjpcbiAgICAgICAgICAgIGNvbnN0IHsgcmVxdWVzdFF1ZXVlVG9waWMgfSA9IHJlc291cmNlcztcbiAgICAgICAgICAgIGNvbnN0IHsgcHVic3ViIH0gPSBzZXJ2aWNlcztcbiAgICAgICAgICAgIGNvbnN0IHNlcmlhbGl6ZWQgPSBzZXJpYWxpemUoY2FsbCk7XG4gICAgICAgICAgICByZXR1cm4gcHVibGlzaFB1YlN1YihwdWJzdWIsIHJlcXVlc3RRdWV1ZVRvcGljISwgc2VyaWFsaXplZCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBwb2xsKHN0YXRlOiBHb29nbGVTdGF0ZSwgY2FuY2VsOiBQcm9taXNlPHZvaWQ+KTogUHJvbWlzZTxQb2xsUmVzdWx0PiB7XG4gICAgcmV0dXJuIHJlY2VpdmVNZXNzYWdlcyhcbiAgICAgICAgc3RhdGUuc2VydmljZXMucHVic3ViLFxuICAgICAgICBzdGF0ZS5yZXNvdXJjZXMucmVzcG9uc2VTdWJzY3JpcHRpb24hLFxuICAgICAgICBzdGF0ZS5tZXRyaWNzLFxuICAgICAgICBjYW5jZWxcbiAgICApO1xufVxuXG5mdW5jdGlvbiByZXNwb25zZVF1ZXVlSWQoc3RhdGU6IEdvb2dsZVN0YXRlKSB7XG4gICAgcmV0dXJuIHN0YXRlLnJlc291cmNlcy5yZXNwb25zZVF1ZXVlVG9waWMhO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVSZXNvdXJjZXMoXG4gICAgc2VydmljZXM6IEdvb2dsZVNlcnZpY2VzLFxuICAgIHJlc291cmNlczogR29vZ2xlUmVzb3VyY2VzLFxuICAgIG91dHB1dDogKG1zZzogc3RyaW5nKSA9PiB2b2lkID0gbG9nLmluZm9cbikge1xuICAgIGNvbnN0IHtcbiAgICAgICAgdHJhbXBvbGluZSxcbiAgICAgICAgcmVxdWVzdFF1ZXVlVG9waWMsXG4gICAgICAgIHJlcXVlc3RTdWJzY3JpcHRpb24sXG4gICAgICAgIHJlc3BvbnNlU3Vic2NyaXB0aW9uLFxuICAgICAgICByZXNwb25zZVF1ZXVlVG9waWMsXG4gICAgICAgIHJlZ2lvbixcbiAgICAgICAgLi4ucmVzdFxuICAgIH0gPSByZXNvdXJjZXM7XG4gICAgY29uc3QgX2V4aGF1c3RpdmVDaGVjazogUmVxdWlyZWQ8dHlwZW9mIHJlc3Q+ID0ge307XG4gICAgY29uc3QgeyBjbG91ZEZ1bmN0aW9ucywgcHVic3ViIH0gPSBzZXJ2aWNlcztcblxuICAgIC8vIFdlIGRlbGliZXJhdGVseSByZXRocm93IHRyYW5zaWVudCBlcnJvcnMgaGVyZSwgc28gb25seSBpZiBhbGwgcHJpb3JcbiAgICAvLyBkZWxldGVzIHN1Y2NlZWQgZG8gd2UgcHJvY2VlZC4gSWYgdGhlcmUncyBhIHRyYW5zaWVudCBlcnJvciB0aGVuIGZ1dHVyZVxuICAgIC8vIGdhcmJhZ2UgY29sbGVjdGlvbiB3aWxsIGNsZWFuIHVwLiBUaGUgb3JkZXIgaXMgaW1wb3J0YW50OyB0aGUgZnVuY3Rpb25cbiAgICAvLyBpdHNlbGYgbXVzdCBiZSBkZWxldGVkIGxhc3QuXG4gICAgY29uc3QgY2hlY2sgPSBhc3luYyA8VD4ocmVxdWVzdDogUHJvbWlzZTxUPikgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgcmVxdWVzdDtcbiAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICAqL1xuICAgICAgICAgICAgaWYgKGVyci5tZXNzYWdlLm1hdGNoKC9SZXNvdXJjZSBub3QgZm91bmQvKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAocmVzcG9uc2VTdWJzY3JpcHRpb24pIHtcbiAgICAgICAgYXdhaXQgY2hlY2soXG4gICAgICAgICAgICBwdWJzdWIucHJvamVjdHMuc3Vic2NyaXB0aW9ucy5kZWxldGUoeyBzdWJzY3JpcHRpb246IHJlc3BvbnNlU3Vic2NyaXB0aW9uIH0pXG4gICAgICAgICk7XG4gICAgICAgIG91dHB1dChgRGVsZXRlZCByZXNwb25zZSBzdWJzY3JpcHRpb246ICR7cmVzcG9uc2VTdWJzY3JpcHRpb259YCk7XG4gICAgfVxuICAgIGlmIChyZXNwb25zZVF1ZXVlVG9waWMpIHtcbiAgICAgICAgYXdhaXQgY2hlY2socHVic3ViLnByb2plY3RzLnRvcGljcy5kZWxldGUoeyB0b3BpYzogcmVzcG9uc2VRdWV1ZVRvcGljIH0pKTtcbiAgICAgICAgb3V0cHV0KGBEZWxldGVkIHJlc3BvbnNlIHF1ZXVlIHRvcGljOiAke3Jlc3BvbnNlUXVldWVUb3BpY31gKTtcbiAgICB9XG4gICAgaWYgKHJlcXVlc3RTdWJzY3JpcHRpb24pIHtcbiAgICAgICAgYXdhaXQgY2hlY2soXG4gICAgICAgICAgICBwdWJzdWIucHJvamVjdHMuc3Vic2NyaXB0aW9ucy5kZWxldGUoeyBzdWJzY3JpcHRpb246IHJlcXVlc3RTdWJzY3JpcHRpb24gfSlcbiAgICAgICAgKTtcbiAgICAgICAgb3V0cHV0KGBEZWxldGVkIHJlc3BvbnNlIHN1YnNjcmlwdGlvbjogJHtyZXF1ZXN0U3Vic2NyaXB0aW9ufWApO1xuICAgIH1cbiAgICBpZiAocmVxdWVzdFF1ZXVlVG9waWMpIHtcbiAgICAgICAgYXdhaXQgY2hlY2socHVic3ViLnByb2plY3RzLnRvcGljcy5kZWxldGUoeyB0b3BpYzogcmVxdWVzdFF1ZXVlVG9waWMgfSkpO1xuICAgICAgICBvdXRwdXQoYERlbGV0ZWQgcmVxdWVzdCBxdWV1ZSB0b3BpYzogJHtyZXF1ZXN0UXVldWVUb3BpY31gKTtcbiAgICB9XG4gICAgaWYgKHRyYW1wb2xpbmUpIHtcbiAgICAgICAgYXdhaXQgY2hlY2soZGVsZXRlRnVuY3Rpb24oY2xvdWRGdW5jdGlvbnMsIHRyYW1wb2xpbmUpKTtcbiAgICAgICAgb3V0cHV0KGBEZWxldGVkIGZ1bmN0aW9uICR7dHJhbXBvbGluZX1gKTtcbiAgICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhbnVwKHN0YXRlOiBHb29nbGVTdGF0ZSwgb3B0aW9uczogQ2xlYW51cE9wdGlvbnMpIHtcbiAgICBsb2cuaW5mbyhgZ29vZ2xlIGNsZWFudXAgc3RhcnRpbmcuYCk7XG4gICAgaWYgKHN0YXRlLmdjUHJvbWlzZSkge1xuICAgICAgICBsb2cuaW5mbyhgV2FpdGluZyBmb3IgZ2FyYmFnZSBjb2xsZWN0aW9uLi4uYCk7XG4gICAgICAgIGF3YWl0IHN0YXRlLmdjUHJvbWlzZTtcbiAgICAgICAgbG9nLmluZm8oYEdhcmJhZ2UgY29sbGVjdGlvbiBkb25lLmApO1xuICAgIH1cblxuICAgIGlmIChvcHRpb25zLmRlbGV0ZVJlc291cmNlcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgZGVsZXRlUmVzb3VyY2VzKHN0YXRlLnNlcnZpY2VzLCBzdGF0ZS5yZXNvdXJjZXMpO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEZhYXN0RXJyb3IoZXJyLCBcImRlbGV0ZSByZXNvdXJjZXMgZmFpbGVkXCIpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGxvZy5pbmZvKGBnb29nbGUgY2xlYW51cCBkb25lLmApO1xufVxuXG5sZXQgZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcgPSBmYWxzZTtcblxuYXN5bmMgZnVuY3Rpb24gY29sbGVjdEdhcmJhZ2UoXG4gICAgZ2NXb3JrZXI6IHR5cGVvZiBkZWZhdWx0R2NXb3JrZXIsXG4gICAgc2VydmljZXM6IEdvb2dsZVNlcnZpY2VzLFxuICAgIHByb2o6IHN0cmluZyxcbiAgICByZXRlbnRpb25JbkRheXM6IG51bWJlclxuKSB7XG4gICAgaWYgKGdjV29ya2VyID09PSBkZWZhdWx0R2NXb3JrZXIpIHtcbiAgICAgICAgaWYgKGdhcmJhZ2VDb2xsZWN0b3JSdW5uaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgZ2FyYmFnZUNvbGxlY3RvclJ1bm5pbmcgPSB0cnVlO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICBjb25zdCB7IGNsb3VkRnVuY3Rpb25zIH0gPSBzZXJ2aWNlcztcblxuICAgICAgICBsZXQgcGFnZVRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICAgICAgbGV0IHByb21pc2VzID0gW107XG4gICAgICAgIGNvbnN0IHNjaGVkdWxlRGVsZXRlUmVzb3VyY2VzID0gdGhyb3R0bGUoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgY29uY3VycmVuY3k6IDUsXG4gICAgICAgICAgICAgICAgcmF0ZTogNSxcbiAgICAgICAgICAgICAgICBidXJzdDogMlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGFzeW5jIChcbiAgICAgICAgICAgICAgICBnU2VydmljZXM6IEdvb2dsZVNlcnZpY2VzLFxuICAgICAgICAgICAgICAgIGZuOiBDbG91ZEZ1bmN0aW9ucy5TY2hlbWEkQ2xvdWRGdW5jdGlvblxuICAgICAgICAgICAgKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgeyByZWdpb24sIG5hbWUsIHByb2plY3QgfSA9IHBhcnNlRnVuY3Rpb25OYW1lKGZuLm5hbWUhKSE7XG5cbiAgICAgICAgICAgICAgICBjb25zdCByZXNvdXJjZXM6IEdvb2dsZVJlc291cmNlcyA9IHtcbiAgICAgICAgICAgICAgICAgICAgcmVnaW9uLFxuICAgICAgICAgICAgICAgICAgICB0cmFtcG9saW5lOiBmbi5uYW1lISxcbiAgICAgICAgICAgICAgICAgICAgcmVxdWVzdFF1ZXVlVG9waWM6IGdldFJlcXVlc3RRdWV1ZVRvcGljKHByb2plY3QsIG5hbWUpLFxuICAgICAgICAgICAgICAgICAgICByZXF1ZXN0U3Vic2NyaXB0aW9uOiBnZXRSZXF1ZXN0U3Vic2NyaXB0aW9uKHByb2plY3QsIG5hbWUsIHJlZ2lvbiksXG4gICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlUXVldWVUb3BpYzogZ2V0UmVzcG9uc2VRdWV1ZVRvcGljKHByb2plY3QsIG5hbWUpLFxuICAgICAgICAgICAgICAgICAgICByZXNwb25zZVN1YnNjcmlwdGlvbjogZ2V0UmVzcG9uc2VTdWJzY3JpcHRpb24ocHJvamVjdCwgbmFtZSlcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGF3YWl0IGdjV29ya2VyKHJlc291cmNlcywgZ1NlcnZpY2VzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCBmblBhdHRlcm4gPSBuZXcgUmVnRXhwKGAvZnVuY3Rpb25zL2ZhYXN0LSR7dXVpZHY0UGF0dGVybn0kYCk7XG4gICAgICAgIGRvIHtcbiAgICAgICAgICAgIGNvbnN0IGZ1bmNMaXN0UmVzcG9uc2UgPVxuICAgICAgICAgICAgICAgIGF3YWl0IGNsb3VkRnVuY3Rpb25zLnByb2plY3RzLmxvY2F0aW9ucy5mdW5jdGlvbnMubGlzdCh7XG4gICAgICAgICAgICAgICAgICAgIHBhcmVudDogYHByb2plY3RzLyR7cHJvan0vbG9jYXRpb25zLy1gLFxuICAgICAgICAgICAgICAgICAgICBwYWdlVG9rZW5cbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcGFnZVRva2VuID0gZnVuY0xpc3RSZXNwb25zZS5kYXRhLm5leHRQYWdlVG9rZW4gPz8gdW5kZWZpbmVkO1xuICAgICAgICAgICAgY29uc3QgZ2FyYmFnZUZ1bmN0aW9ucyA9IChmdW5jTGlzdFJlc3BvbnNlLmRhdGEuZnVuY3Rpb25zIHx8IFtdKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoZm4gPT4gaGFzRXhwaXJlZChmbi51cGRhdGVUaW1lLCByZXRlbnRpb25JbkRheXMpKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoZm4gPT4gZm4ubmFtZSEubWF0Y2goZm5QYXR0ZXJuKSk7XG5cbiAgICAgICAgICAgIHByb21pc2VzID0gZ2FyYmFnZUZ1bmN0aW9ucy5tYXAoZm4gPT4gc2NoZWR1bGVEZWxldGVSZXNvdXJjZXMoc2VydmljZXMsIGZuKSk7XG4gICAgICAgIH0gd2hpbGUgKHBhZ2VUb2tlbik7XG5cbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIGlmIChnY1dvcmtlciA9PT0gZGVmYXVsdEdjV29ya2VyKSB7XG4gICAgICAgICAgICBnYXJiYWdlQ29sbGVjdG9yUnVubmluZyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBwYXJzZUZ1bmN0aW9uTmFtZShwYXRoOiBzdHJpbmcpIHtcbiAgICBjb25zdCBtYXRjaCA9IHBhdGgubWF0Y2goL15wcm9qZWN0c1xcLyguKilcXC9sb2NhdGlvbnNcXC8oLiopXFwvZnVuY3Rpb25zXFwvKC4qKSQvKTtcbiAgICByZXR1cm4gbWF0Y2ggJiYgeyBwcm9qZWN0OiBtYXRjaFsxXSwgcmVnaW9uOiBtYXRjaFsyXSwgbmFtZTogbWF0Y2hbM10gfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdXBsb2FkWmlwKHVybDogc3RyaW5nLCB6aXBTdHJlYW06IE5vZGVKUy5SZWFkYWJsZVN0cmVhbSkge1xuICAgIGNvbnN0IGNvbmZpZzogR2F4aW9zT3B0aW9ucyA9IHtcbiAgICAgICAgbWV0aG9kOiBcIlBVVFwiLFxuICAgICAgICB1cmwsXG4gICAgICAgIGJvZHk6IHppcFN0cmVhbSxcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgXCJjb250ZW50LXR5cGVcIjogXCJhcHBsaWNhdGlvbi96aXBcIixcbiAgICAgICAgICAgIFwieC1nb29nLWNvbnRlbnQtbGVuZ3RoLXJhbmdlXCI6IFwiMCwxMDQ4NTc2MDBcIlxuICAgICAgICB9XG4gICAgfTtcbiAgICByZXR1cm4gZ2F4aW9zLnJlcXVlc3QoY29uZmlnKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdvb2dsZVBhY2tlcihcbiAgICBmdW5jdGlvbk1vZHVsZTogc3RyaW5nLFxuICAgIG9wdGlvbnM6IENvbW1vbk9wdGlvbnMsXG4gICAgd3JhcHBlck9wdGlvbnM6IFdyYXBwZXJPcHRpb25zLFxuICAgIEZ1bmN0aW9uTmFtZTogc3RyaW5nXG4pOiBQcm9taXNlPFBhY2tlclJlc3VsdD4ge1xuICAgIGNvbnN0IHsgbW9kZSB9ID0gb3B0aW9ucztcbiAgICBjb25zdCB0cmFtcG9saW5lTW9kdWxlID1cbiAgICAgICAgbW9kZSA9PT0gXCJxdWV1ZVwiID8gZ29vZ2xlVHJhbXBvbGluZVF1ZXVlIDogZ29vZ2xlVHJhbXBvbGluZUh0dHBzO1xuICAgIHJldHVybiBwYWNrZXIoXG4gICAgICAgIHRyYW1wb2xpbmVNb2R1bGUsXG4gICAgICAgIGZ1bmN0aW9uTW9kdWxlLFxuICAgICAgICBvcHRpb25zLFxuICAgICAgICB3cmFwcGVyT3B0aW9ucyxcbiAgICAgICAgRnVuY3Rpb25OYW1lXG4gICAgKTtcbn1cblxubGV0IGdldEdvb2dsZVByaWNlOlxuICAgIHwgdW5kZWZpbmVkXG4gICAgfCAoKFxuICAgICAgICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgICAgICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgICAgICAgZGVzY3JpcHRpb246IHN0cmluZyxcbiAgICAgICAgICBjb252ZXJzaW9uRmFjdG9yOiBudW1iZXJcbiAgICAgICkgPT4gUHJvbWlzZTxudW1iZXI+KTtcblxuZnVuY3Rpb24gZW5zdXJlR29vZ2xlUHJpY2VDYWNoZShjbG91ZEJpbGxpbmc6IENsb3VkQmlsbGluZy5DbG91ZGJpbGxpbmcpIHtcbiAgICBpZiAoZ2V0R29vZ2xlUHJpY2UpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBnZXRHb29nbGVQcmljZSA9IHRocm90dGxlKFxuICAgICAgICB7XG4gICAgICAgICAgICBjb25jdXJyZW5jeTogMSxcbiAgICAgICAgICAgIHJhdGU6IDMsXG4gICAgICAgICAgICBtZW1vaXplOiB0cnVlLFxuICAgICAgICAgICAgY2FjaGU6IGNhY2hlcy5nb29nbGVQcmljZXNcbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgKFxuICAgICAgICAgICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgICAgICAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IHN0cmluZyxcbiAgICAgICAgICAgIGNvbnZlcnNpb25GYWN0b3I6IG51bWJlclxuICAgICAgICApID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc2t1c1Jlc3BvbnNlID0gYXdhaXQgY2xvdWRCaWxsaW5nLnNlcnZpY2VzLnNrdXMubGlzdCh7XG4gICAgICAgICAgICAgICAgICAgIHBhcmVudDogc2VydmljZU5hbWVcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBjb25zdCB7IHNrdXMgPSBbXSB9ID0gc2t1c1Jlc3BvbnNlLmRhdGE7XG4gICAgICAgICAgICAgICAgY29uc3QgbWF0Y2hpbmdTa3VzID0gc2t1cy5maWx0ZXIoc2t1ID0+IHNrdS5kZXNjcmlwdGlvbiA9PT0gZGVzY3JpcHRpb24pO1xuICAgICAgICAgICAgICAgIGxvZy5wcm92aWRlcihcbiAgICAgICAgICAgICAgICAgICAgYG1hdGNoaW5nIFNLVXM6ICR7dXRpbC5pbnNwZWN0KG1hdGNoaW5nU2t1cywgeyBkZXB0aDogbnVsbCB9KX1gXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHJlZ2lvbk9yR2xvYmFsU2t1ID1cbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hpbmdTa3VzLmZpbmQoc2t1ID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBza3Uuc2VydmljZVJlZ2lvbnMhLmZpbmQociA9PiByID09PSByZWdpb24pXG4gICAgICAgICAgICAgICAgICAgICkgPz9cbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hpbmdTa3VzLmZpbmQoc2t1ID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBza3Uuc2VydmljZVJlZ2lvbnMhLmZpbmQociA9PiByID09PSBcImdsb2JhbFwiKVxuICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgcGV4cCA9IHJlZ2lvbk9yR2xvYmFsU2t1IS5wcmljaW5nSW5mbyFbMF0ucHJpY2luZ0V4cHJlc3Npb24hO1xuICAgICAgICAgICAgICAgIGNvbnN0IHByaWNlcyA9IHBleHAudGllcmVkUmF0ZXMhLm1hcChcbiAgICAgICAgICAgICAgICAgICAgcmF0ZSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHJhdGUudW5pdFByaWNlIS51bml0cyA/PyBcIjBcIikgK1xuICAgICAgICAgICAgICAgICAgICAgICAgcmF0ZS51bml0UHJpY2UhLm5hbm9zISAvIDFlOVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgY29uc3QgcHJpY2UgPVxuICAgICAgICAgICAgICAgICAgICBNYXRoLm1heCguLi5wcmljZXMpICpcbiAgICAgICAgICAgICAgICAgICAgKGNvbnZlcnNpb25GYWN0b3IgLyBwZXhwLmJhc2VVbml0Q29udmVyc2lvbkZhY3RvciEpO1xuICAgICAgICAgICAgICAgIGxvZy5wcm92aWRlcihcbiAgICAgICAgICAgICAgICAgICAgYEZvdW5kIHByaWNlIGZvciAke3NlcnZpY2VOYW1lfSwgJHtkZXNjcmlwdGlvbn0sICR7cmVnaW9ufTogJHtwcmljZX1gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcHJpY2U7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKFxuICAgICAgICAgICAgICAgICAgICBlcnIsXG4gICAgICAgICAgICAgICAgICAgIGBmYWlsZWQgdG8gZ2V0IGdvb2dsZSBwcmljaW5nIGZvciBcIiR7ZGVzY3JpcHRpb259XCJgXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICk7XG59XG5cbmxldCBnb29nbGVTZXJ2aWNlczogY2xvdWRiaWxsaW5nX3YxLlNjaGVtYSRTZXJ2aWNlW10gfCB1bmRlZmluZWQ7XG5cbmNvbnN0IGxpc3RHb29nbGVTZXJ2aWNlcyA9IHRocm90dGxlKFxuICAgIHsgY29uY3VycmVuY3k6IDEgfSxcbiAgICBhc3luYyAoY2xvdWRCaWxsaW5nOiBDbG91ZEJpbGxpbmcuQ2xvdWRiaWxsaW5nKSA9PiB7XG4gICAgICAgIGlmIChnb29nbGVTZXJ2aWNlcykge1xuICAgICAgICAgICAgcmV0dXJuIGdvb2dsZVNlcnZpY2VzO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xvdWRCaWxsaW5nLnNlcnZpY2VzLmxpc3QoKTtcbiAgICAgICAgZ29vZ2xlU2VydmljZXMgPSByZXNwb25zZS5kYXRhLnNlcnZpY2VzITtcbiAgICAgICAgcmV0dXJuIGdvb2dsZVNlcnZpY2VzO1xuICAgIH1cbik7XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEdvb2dsZUNsb3VkRnVuY3Rpb25zUHJpY2luZyhcbiAgICBjbG91ZEJpbGxpbmc6IENsb3VkQmlsbGluZy5DbG91ZGJpbGxpbmcsXG4gICAgcmVnaW9uOiBzdHJpbmdcbik6IFByb21pc2U8R29vZ2xlQ2xvdWRQcmljaW5nPiB7XG4gICAgY29uc3Qgc2VydmljZXMgPSBhd2FpdCBsaXN0R29vZ2xlU2VydmljZXMoY2xvdWRCaWxsaW5nKTtcbiAgICBlbnN1cmVHb29nbGVQcmljZUNhY2hlKGNsb3VkQmlsbGluZyk7XG5cbiAgICBjb25zdCBnZXRQcmljaW5nID0gKFxuICAgICAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgICAgICBkZXNjcmlwdGlvbjogc3RyaW5nLFxuICAgICAgICBjb252ZXJzaW9uRmFjdG9yOiBudW1iZXIgPSAxXG4gICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IHNlcnZpY2UgPSBzZXJ2aWNlcy5maW5kKHMgPT4gcy5kaXNwbGF5TmFtZSA9PT0gc2VydmljZU5hbWUpITtcbiAgICAgICAgcmV0dXJuIGdldEdvb2dsZVByaWNlIShyZWdpb24sIHNlcnZpY2UubmFtZSEsIGRlc2NyaXB0aW9uLCBjb252ZXJzaW9uRmFjdG9yKTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgcGVySW52b2NhdGlvbjogYXdhaXQgZ2V0UHJpY2luZyhcIkNsb3VkIEZ1bmN0aW9uc1wiLCBcIkludm9jYXRpb25zXCIpLFxuICAgICAgICBwZXJHaHpTZWNvbmQ6IGF3YWl0IGdldFByaWNpbmcoXCJDbG91ZCBGdW5jdGlvbnNcIiwgXCJDUFUgVGltZVwiKSxcbiAgICAgICAgcGVyR2JTZWNvbmQ6IGF3YWl0IGdldFByaWNpbmcoXCJDbG91ZCBGdW5jdGlvbnNcIiwgXCJNZW1vcnkgVGltZVwiLCAyICoqIDMwKSxcbiAgICAgICAgcGVyR2JPdXRib3VuZERhdGE6IGF3YWl0IGdldFByaWNpbmcoXG4gICAgICAgICAgICBcIkNsb3VkIEZ1bmN0aW9uc1wiLFxuICAgICAgICAgICAgYE5ldHdvcmsgRWdyZXNzIGZyb20gJHtyZWdpb259YCxcbiAgICAgICAgICAgIDIgKiogMzBcbiAgICAgICAgKSxcbiAgICAgICAgcGVyR2JQdWJTdWI6IGF3YWl0IGdldFByaWNpbmcoXCJDbG91ZCBQdWIvU3ViXCIsIFwiTWVzc2FnZSBEZWxpdmVyeSBCYXNpY1wiLCAyICoqIDMwKVxuICAgIH07XG59XG5cbi8vIGh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9mdW5jdGlvbnMvcHJpY2luZ1xuY29uc3QgZ2NmUHJvdmlzb25hYmxlTWVtb3J5VGFibGU6IHsgW21lbTogbnVtYmVyXTogbnVtYmVyIH0gPSB7XG4gICAgMTI4OiAwLjIsXG4gICAgMjU2OiAwLjQsXG4gICAgNTEyOiAwLjgsXG4gICAgMTAyNDogMS40LFxuICAgIDIwNDg6IDIuNFxufTtcblxuYXN5bmMgZnVuY3Rpb24gY29zdFNuYXBzaG90KFxuICAgIHN0YXRlOiBHb29nbGVTdGF0ZSxcbiAgICBzdGF0czogRnVuY3Rpb25TdGF0c1xuKTogUHJvbWlzZTxDb3N0U25hcHNob3Q+IHtcbiAgICBjb25zdCBjb3N0cyA9IG5ldyBDb3N0U25hcHNob3QoXCJnb29nbGVcIiwgc3RhdGUub3B0aW9ucywgc3RhdHMpO1xuICAgIGNvbnN0IHsgbWVtb3J5U2l6ZSA9IGRlZmF1bHRzLm1lbW9yeVNpemUgfSA9IHN0YXRlLm9wdGlvbnM7XG4gICAgY29uc3QgcHJvdmlzaW9uYWJsZVNpemVzID0ga2V5c09mKGdjZlByb3Zpc29uYWJsZU1lbW9yeVRhYmxlKVxuICAgICAgICAubWFwKG4gPT4gTnVtYmVyKG4pKVxuICAgICAgICAuc29ydCgoYSwgYikgPT4gYSAtIGIpO1xuICAgIGNvbnN0IHByb3Zpc2lvbmVkTWIgPSBwcm92aXNpb25hYmxlU2l6ZXMuZmluZChzaXplID0+IG1lbW9yeVNpemUgPD0gc2l6ZSk7XG4gICAgaWYgKCFwcm92aXNpb25lZE1iKSB7XG4gICAgICAgIGxvZy53YXJuKFxuICAgICAgICAgICAgYENvdWxkIG5vdCBkZXRlcm1pbmUgcHJvdmlzaW9uZWQgbWVtb3J5IG9yIENQVSBmb3IgcmVxdWVzdGVkIG1lbW9yeSBzaXplICR7bWVtb3J5U2l6ZX1gXG4gICAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IHByb3Zpc2lvbmVkR2h6ID0gZ2NmUHJvdmlzb25hYmxlTWVtb3J5VGFibGVbcHJvdmlzaW9uZWRNYiFdO1xuICAgIGNvbnN0IGJpbGxlZFRpbWVTdGF0cyA9IHN0YXRzLmVzdGltYXRlZEJpbGxlZFRpbWU7XG4gICAgY29uc3Qgc2Vjb25kcyA9IChiaWxsZWRUaW1lU3RhdHMubWVhbiAvIDEwMDApICogYmlsbGVkVGltZVN0YXRzLnNhbXBsZXM7XG5cbiAgICBjb25zdCB7IHJlZ2lvbiB9ID0gc3RhdGUucmVzb3VyY2VzO1xuICAgIGNvbnN0IHByaWNlcyA9IGF3YWl0IGdldEdvb2dsZUNsb3VkRnVuY3Rpb25zUHJpY2luZyhcbiAgICAgICAgc3RhdGUuc2VydmljZXMuY2xvdWRCaWxsaW5nLFxuICAgICAgICByZWdpb25cbiAgICApO1xuXG4gICAgY29uc3QgcHJvdmlzaW9uZWRHYiA9IHByb3Zpc2lvbmVkTWIhIC8gMTAyNDtcbiAgICBjb25zdCBmdW5jdGlvbkNhbGxEdXJhdGlvbiA9IG5ldyBDb3N0TWV0cmljKHtcbiAgICAgICAgbmFtZTogXCJmdW5jdGlvbkNhbGxEdXJhdGlvblwiLFxuICAgICAgICBwcmljaW5nOlxuICAgICAgICAgICAgcHJpY2VzLnBlckdiU2Vjb25kICogcHJvdmlzaW9uZWRHYiArIHByaWNlcy5wZXJHaHpTZWNvbmQgKiBwcm92aXNpb25lZEdoeixcbiAgICAgICAgdW5pdDogXCJzZWNvbmRcIixcbiAgICAgICAgbWVhc3VyZWQ6IHNlY29uZHMsXG4gICAgICAgIGNvbW1lbnQ6IGBodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vZnVuY3Rpb25zL3ByaWNpbmcjY29tcHV0ZV90aW1lICgke3Byb3Zpc2lvbmVkTWJ9IE1CLCAke3Byb3Zpc2lvbmVkR2h6fSBHSHopYFxuICAgIH0pO1xuICAgIGNvc3RzLnB1c2goZnVuY3Rpb25DYWxsRHVyYXRpb24pO1xuXG4gICAgY29uc3QgZnVuY3Rpb25DYWxsUmVxdWVzdHMgPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwiZnVuY3Rpb25DYWxsUmVxdWVzdHNcIixcbiAgICAgICAgcHJpY2luZzogcHJpY2VzLnBlckludm9jYXRpb24sXG4gICAgICAgIG1lYXN1cmVkOiBzdGF0cy5pbnZvY2F0aW9ucyxcbiAgICAgICAgdW5pdDogXCJyZXF1ZXN0XCIsXG4gICAgICAgIGNvbW1lbnQ6IFwiaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Z1bmN0aW9ucy9wcmljaW5nI2ludm9jYXRpb25zXCJcbiAgICB9KTtcbiAgICBjb3N0cy5wdXNoKGZ1bmN0aW9uQ2FsbFJlcXVlc3RzKTtcblxuICAgIGNvbnN0IG91dGJvdW5kRGF0YVRyYW5zZmVyID0gbmV3IENvc3RNZXRyaWMoe1xuICAgICAgICBuYW1lOiBcIm91dGJvdW5kRGF0YVRyYW5zZmVyXCIsXG4gICAgICAgIHByaWNpbmc6IHByaWNlcy5wZXJHYk91dGJvdW5kRGF0YSxcbiAgICAgICAgbWVhc3VyZWQ6IHN0YXRlLm1ldHJpY3Mub3V0Ym91bmRCeXRlcyAvIDIgKiogMzAsXG4gICAgICAgIHVuaXQ6IFwiR0JcIixcbiAgICAgICAgY29tbWVudDogXCJodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vZnVuY3Rpb25zL3ByaWNpbmcjbmV0d29ya2luZ1wiXG4gICAgfSk7XG4gICAgY29zdHMucHVzaChvdXRib3VuZERhdGFUcmFuc2Zlcik7XG5cbiAgICBjb25zdCBwdWJzdWIgPSBuZXcgQ29zdE1ldHJpYyh7XG4gICAgICAgIG5hbWU6IFwicHVic3ViXCIsXG4gICAgICAgIHByaWNpbmc6IHByaWNlcy5wZXJHYlB1YlN1YixcbiAgICAgICAgbWVhc3VyZWQ6IHN0YXRlLm1ldHJpY3MucHViU3ViQnl0ZXMgLyAyICoqIDMwLFxuICAgICAgICB1bml0OiBcIkdCXCIsXG4gICAgICAgIGNvbW1lbnQ6IFwiaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3B1YnN1Yi9wcmljaW5nXCJcbiAgICB9KTtcbiAgICBjb3N0cy5wdXNoKHB1YnN1Yik7XG5cbiAgICByZXR1cm4gY29zdHM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2dVcmwoc3RhdGU6IEdvb2dsZVN0YXRlKSB7XG4gICAgY29uc3QgeyBwcm9qZWN0LCBmdW5jdGlvbk5hbWUgfSA9IHN0YXRlO1xuICAgIHJldHVybiBgaHR0cHM6Ly9jb25zb2xlLmNsb3VkLmdvb2dsZS5jb20vbG9ncy92aWV3ZXI/cHJvamVjdD0ke3Byb2plY3R9JnJlc291cmNlPWNsb3VkX2Z1bmN0aW9uJTJGZnVuY3Rpb25fbmFtZSUyRiR7ZnVuY3Rpb25OYW1lfWA7XG59XG4iXX0=
\No newline at end of file