@blinkk/root-cms 2.0.0-rc.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.js CHANGED
@@ -33,18 +33,18 @@ async function generateTypes() {
33
33
  console.log("saved root-cms.d.ts!");
34
34
  }
35
35
  async function generateSchemaDts(outputPath, schemas) {
36
- const results = [TEMPLATE];
36
+ const dtsFormatter = new DtsFormatter();
37
37
  for (const fileId in schemas) {
38
38
  const schema = schemas[fileId];
39
- results.push(renderSchema(fileId, schema));
39
+ dtsFormatter.addSchemaFile(fileId, schema);
40
40
  }
41
- const output = results.join("\n\n").replaceAll("/** ", "/** ").replaceAll(" */", " */").replace(/\r\n|\r|\n/g, "\n");
41
+ const output = dtsFormatter.toString();
42
42
  await fs.writeFile(outputPath, output, "utf-8");
43
43
  }
44
- function fieldProperty(field) {
44
+ function fieldProperty(field, options) {
45
45
  const prop = dom.create.property(
46
46
  field.id,
47
- fieldType(field),
47
+ fieldType(field, options),
48
48
  dom.DeclarationFlags.Optional
49
49
  );
50
50
  const jsdoc = [];
@@ -63,9 +63,9 @@ function fieldProperty(field) {
63
63
  }
64
64
  return prop;
65
65
  }
66
- function fieldType(field) {
66
+ function fieldType(field, options) {
67
67
  if (field.type === "array") {
68
- return dom.type.array(fieldType(field.of));
68
+ return dom.type.array(fieldType(field.of, options));
69
69
  }
70
70
  if (field.type === "boolean") {
71
71
  return dom.type.boolean;
@@ -76,19 +76,53 @@ function fieldType(field) {
76
76
  if (field.type === "datetime") {
77
77
  return dom.type.number;
78
78
  }
79
+ if (field.type === "file") {
80
+ const fileType = dom.create.namedTypeReference("RootCMSFile");
81
+ return fileType;
82
+ }
79
83
  if (field.type === "image") {
80
84
  const imageType = dom.create.namedTypeReference("RootCMSImage");
81
85
  return imageType;
82
86
  }
83
- if (field.type === "file") {
84
- return dom.create.objectType([dom.create.property("src", dom.type.string)]);
85
- }
86
87
  if (field.type === "multiselect") {
87
88
  return dom.type.array(dom.type.string);
88
89
  }
89
90
  if (field.type === "oneof") {
90
- const oneofType = dom.create.namedTypeReference("RootCMSOneOf");
91
- return oneofType;
91
+ const oneOf = dom.create.namedTypeReference("RootCMSOneOf");
92
+ if (field.types && Array.isArray(field.types)) {
93
+ const unionTypes = [];
94
+ field.types.forEach((schema) => {
95
+ if (!schema.name) {
96
+ return;
97
+ }
98
+ const cleanName = alphanumeric(schema.name);
99
+ const oneOfTypeId = `${cleanName}Fields`;
100
+ if (!options.oneOfTypes[oneOfTypeId]) {
101
+ const oneOfTypeInterface = dom.create.interface(
102
+ oneOfTypeId,
103
+ dom.DeclarationFlags.Export
104
+ );
105
+ if (schema.description) {
106
+ oneOfTypeInterface.jsDocComment = schema.description;
107
+ }
108
+ const oneOfTypeFields = schema.fields || [];
109
+ oneOfTypeFields.forEach((f) => {
110
+ oneOfTypeInterface.members.push(fieldProperty(f, options));
111
+ });
112
+ options.oneOfTypes[oneOfTypeId] = oneOfTypeInterface;
113
+ }
114
+ const oneOfOption = dom.create.namedTypeReference("RootCMSOneOfOption");
115
+ oneOfOption.typeArguments = [
116
+ dom.type.stringLiteral(schema.name),
117
+ dom.create.namedTypeReference(oneOfTypeId)
118
+ ];
119
+ unionTypes.push(oneOfOption);
120
+ });
121
+ if (unionTypes.length > 0) {
122
+ oneOf.typeArguments = [dom.create.union(unionTypes)];
123
+ }
124
+ }
125
+ return oneOf;
92
126
  }
93
127
  if (field.type === "reference") {
94
128
  const referenceType = dom.create.namedTypeReference("RootCMSReference");
@@ -105,70 +139,36 @@ function fieldType(field) {
105
139
  return dom.type.string;
106
140
  }
107
141
  if (field.type === "object") {
108
- const subproperties = (field.fields || []).map((f) => fieldProperty(f));
142
+ const subproperties = (field.fields || []).map(
143
+ (f) => fieldProperty(f, options)
144
+ );
109
145
  return dom.create.objectType(subproperties);
110
146
  }
111
147
  return dom.type.unknown;
112
148
  }
113
- function renderSchema(fileId, schema) {
114
- const jsdoc = `Generated from \`${fileId}\`.`;
115
- const id = alphanumeric(path2.parse(fileId).name.split(".")[0]);
116
- const fieldsInterface = `${id}Fields`;
117
- const fields = dom.create.interface(
118
- fieldsInterface,
119
- dom.DeclarationFlags.Export
120
- );
121
- fields.jsDocComment = jsdoc;
122
- for (const field of schema.fields) {
123
- if (!field.id) {
124
- continue;
125
- }
126
- fields.members.push(fieldProperty(field));
127
- }
128
- const fieldsTypeOutput = dom.emit(fields, { singleLineJsDocComments: true }).trim();
129
- if (fileId.startsWith("/collections/")) {
130
- const baseType = dom.create.namedTypeReference("RootCMSDoc");
131
- baseType.typeArguments.push(dom.create.namedTypeReference(fieldsInterface));
132
- const docType = dom.create.alias(
133
- `${id}Doc`,
134
- baseType,
135
- dom.DeclarationFlags.Export
136
- );
137
- docType.jsDocComment = jsdoc;
138
- const docTypeOutput = dom.emit(docType, { singleLineJsDocComments: true }).trim();
139
- return reindent(fieldsTypeOutput + "\n\n" + docTypeOutput);
140
- }
141
- return reindent(fieldsTypeOutput);
142
- }
143
- function reindent(input) {
144
- const lines = input.split("\n");
145
- const results = [];
146
- for (const line of lines) {
147
- const convertedLine = line.replace(/ {4}/g, " ");
148
- results.push(convertedLine);
149
- }
150
- return results.join("\n");
151
- }
152
149
  function alphanumeric(input) {
153
150
  return input.replace(/[^a-zA-Z0-9]/g, "");
154
151
  }
155
- var __dirname, TEMPLATE;
152
+ var __dirname, TEMPLATE, DtsFormatter;
156
153
  var init_generate_types = __esm({
157
154
  "cli/generate-types.ts"() {
158
155
  "use strict";
159
156
  __dirname = path2.dirname(fileURLToPath(import.meta.url));
160
- TEMPLATE = `/** Root.js CMS types. This file is autogenerated. */
157
+ TEMPLATE = `/* eslint-disable */
158
+ /** Root.js CMS types. This file is autogenerated. */
161
159
 
162
- export interface RootCMSImage {
160
+ export interface RootCMSFile {
163
161
  src: string;
164
162
  width?: number;
165
163
  height?: number;
166
164
  alt?: string;
167
165
  }
168
166
 
169
- export type RootCMSOneOf<T = any> = T & {
170
- _type: string;
171
- };
167
+ export type RootCMSImage = RootCMSFile;
168
+
169
+ export type RootCMSOneOf<T = any> = T;
170
+
171
+ export type RootCMSOneOfOption<T, Base> = Base & {_type: T};
172
172
 
173
173
  export interface RootCMSRichTextBlock {
174
174
  type: string;
@@ -210,6 +210,99 @@ export interface RootCMSDoc<Fields extends {}> {
210
210
  /** User-entered field values from the CMS. */
211
211
  fields?: Fields;
212
212
  }`;
213
+ DtsFormatter = class {
214
+ constructor() {
215
+ /**
216
+ * Field types defined in either `.schema.ts` files or used by `oneOf()`
217
+ * fields.
218
+ */
219
+ this.fieldsTypes = {};
220
+ /**
221
+ * For `collections/*.schema.ts` files, output a corresponding "RootCMSDoc"
222
+ * type. For example, `collections/BlogPosts.schema.ts` would output a type
223
+ * called `BlogPostsDoc`.
224
+ */
225
+ this.docTypes = {};
226
+ }
227
+ /** Adds the types for a `.schema.ts` file to the `.d.ts` file. */
228
+ addSchemaFile(fileId, schema) {
229
+ const jsdoc = `Generated from \`${fileId}\`.`;
230
+ const typeId = alphanumeric(path2.parse(fileId).name.split(".")[0]);
231
+ const oneOfTypes = {};
232
+ const fieldsTypeId = `${typeId}Fields`;
233
+ const fieldsType = dom.create.interface(
234
+ fieldsTypeId,
235
+ dom.DeclarationFlags.Export
236
+ );
237
+ fieldsType.jsDocComment = jsdoc;
238
+ for (const field of schema.fields) {
239
+ if (!field.id) {
240
+ continue;
241
+ }
242
+ fieldsType.members.push(fieldProperty(field, { typeId, oneOfTypes }));
243
+ }
244
+ for (const oneOfTypeId in oneOfTypes) {
245
+ if (!this.fieldsTypes[fieldsTypeId]) {
246
+ this.fieldsTypes[oneOfTypeId] = oneOfTypes[oneOfTypeId];
247
+ }
248
+ }
249
+ this.fieldsTypes[fieldsTypeId] = fieldsType;
250
+ if (fileId.startsWith("/collections/")) {
251
+ const docTypeId = `${typeId}Doc`;
252
+ const baseType = dom.create.namedTypeReference("RootCMSDoc");
253
+ baseType.typeArguments.push(dom.create.namedTypeReference(fieldsTypeId));
254
+ const docType = dom.create.alias(
255
+ docTypeId,
256
+ baseType,
257
+ dom.DeclarationFlags.Export
258
+ );
259
+ docType.jsDocComment = jsdoc;
260
+ this.docTypes[docTypeId] = docType;
261
+ }
262
+ }
263
+ /** Generates the `.d.ts` output as a string. */
264
+ toString() {
265
+ const results = [TEMPLATE];
266
+ const sortedFieldsTypes = Object.keys(this.fieldsTypes).sort();
267
+ for (const fieldsTypeId of sortedFieldsTypes) {
268
+ const fieldsType = this.fieldsTypes[fieldsTypeId];
269
+ results.push(this.typeToString(fieldsType));
270
+ const docTypeId = this.fieldsTypeToDocType(fieldsTypeId);
271
+ const docType = this.docTypes[docTypeId];
272
+ if (docType) {
273
+ results.push(this.typeToString(docType));
274
+ }
275
+ }
276
+ const output = results.join("\n\n").replaceAll("/** ", "/** ").replaceAll(" */", " */").replace(/\r\n|\r|\n/g, "\n") + "\n";
277
+ return output;
278
+ }
279
+ /**
280
+ * Converts "<Name>Fields" to "<Name>Doc".
281
+ */
282
+ fieldsTypeToDocType(fieldsTypeId) {
283
+ if (!fieldsTypeId.endsWith("Fields")) {
284
+ throw new Error(`"${fieldsTypeId}" should be suffixed with "Fields"`);
285
+ }
286
+ const name = fieldsTypeId.slice(0, -6);
287
+ return `${name}Doc`;
288
+ }
289
+ typeToString(type2) {
290
+ return this.reformatOutput(dom.emit(type2, { singleLineJsDocComments: true }));
291
+ }
292
+ /**
293
+ * Formats the output to Google style conventions, e.g. 2-space indents and
294
+ * single quote strings.
295
+ */
296
+ reformatOutput(input) {
297
+ const lines = input.trim().split("\n");
298
+ const results = [];
299
+ for (const line of lines) {
300
+ const convertedLine = line.replace(/ {4}/g, " ").replaceAll('"', "'");
301
+ results.push(convertedLine);
302
+ }
303
+ return results.join("\n");
304
+ }
305
+ };
213
306
  }
214
307
  });
215
308
 
@@ -233,12 +326,10 @@ import { multipartMiddleware } from "@blinkk/root/middleware";
233
326
 
234
327
  // core/ai.ts
235
328
  import crypto from "node:crypto";
236
- import { generate } from "@genkit-ai/ai";
237
- import { configureGenkit } from "@genkit-ai/core";
238
329
  import { vertexAI } from "@genkit-ai/vertexai";
239
- import { gemini15ProPreview, gemini15FlashPreview } from "@genkit-ai/vertexai";
240
330
  import { Timestamp } from "firebase-admin/firestore";
241
- var genkitIsConfigured = false;
331
+ import { genkit } from "genkit";
332
+ var DEFAULT_MODEL = "vertexai/gemini-2.5-flash";
242
333
  var Chat = class {
243
334
  constructor(chatClient, id, options) {
244
335
  var _a;
@@ -246,52 +337,46 @@ var Chat = class {
246
337
  this.cmsClient = chatClient.cmsClient;
247
338
  this.cmsPluginOptions = this.cmsClient.cmsPlugin.getConfig();
248
339
  this.id = id;
249
- this.history = options == null ? void 0 : options.history;
250
- this.model = options == null ? void 0 : options.model;
251
- if (!this.model) {
252
- if (typeof ((_a = this.cmsPluginOptions.experiments) == null ? void 0 : _a.ai) === "object") {
253
- if (this.cmsPluginOptions.experiments.ai.model) {
254
- this.model = this.cmsPluginOptions.experiments.ai.model;
255
- }
256
- }
257
- }
340
+ this.history = (options == null ? void 0 : options.history) ?? [];
341
+ this.model = (options == null ? void 0 : options.model) || (typeof ((_a = this.cmsPluginOptions.experiments) == null ? void 0 : _a.ai) === "object" ? this.cmsPluginOptions.experiments.ai.model : void 0) || DEFAULT_MODEL;
342
+ const firebaseConfig = this.cmsPluginOptions.firebaseConfig;
343
+ this.ai = genkit({
344
+ plugins: [
345
+ vertexAI({
346
+ projectId: firebaseConfig.projectId,
347
+ location: firebaseConfig.location || "us-central1"
348
+ })
349
+ ]
350
+ });
258
351
  }
259
- async sendPrompt(prompt) {
260
- if (!genkitIsConfigured) {
261
- const firebaseConfig = this.cmsPluginOptions.firebaseConfig;
262
- configureGenkit({
263
- plugins: [
264
- vertexAI({
265
- projectId: firebaseConfig.projectId,
266
- // TODO(stevenle): figure out where to get this.
267
- location: firebaseConfig.location || "us-central1"
268
- })
269
- ]
352
+ /** Builds the messages for the AI request. */
353
+ async buildMessages() {
354
+ const messages = this.history;
355
+ if (messages.length === 0) {
356
+ messages.push({
357
+ role: "system",
358
+ content: [{ text: await this.buildSystemPrompt() }]
270
359
  });
271
- genkitIsConfigured = true;
272
- }
273
- let model = gemini15FlashPreview;
274
- if (this.model === "gemini-1.5-pro") {
275
- model = gemini15ProPreview;
276
360
  }
277
- if (!this.history) {
278
- await this.initHistory();
279
- }
280
- const res = await generate({
281
- model,
282
- prompt,
283
- history: this.history
361
+ return messages;
362
+ }
363
+ async sendPrompt(prompt) {
364
+ const res = await this.ai.generate({
365
+ messages: await this.buildMessages(),
366
+ model: this.model,
367
+ prompt
284
368
  });
285
- console.log(res.text());
286
- const history = res.toHistory();
287
- this.history = history;
288
- await this.dbDoc().update({ history, modifiedAt: Timestamp.now() });
289
- return res.text();
369
+ this.history = res.messages;
370
+ await this.dbDoc().update({
371
+ history: this.history,
372
+ modifiedAt: Timestamp.now()
373
+ });
374
+ return res.text;
290
375
  }
291
376
  dbDoc() {
292
377
  return this.chatClient.dbCollection().doc(this.id);
293
378
  }
294
- async initHistory() {
379
+ async buildSystemPrompt() {
295
380
  const systemText = [
296
381
  `You are an assistant for a headless CMS called Root CMS which is used on a website called ${this.cmsPluginOptions.name || this.cmsPluginOptions.id}. Your job is to answer questions about the docs in the system, and if requested, help suggest changes to the JSON data in the docs. If you don't know the answer, just say that you don't know, don't try to make up an answer. Be friendly and playful with your messaging.`,
297
382
  "",
@@ -306,8 +391,7 @@ var Chat = class {
306
391
  pages.docs.forEach((doc) => {
307
392
  systemText.push(JSON.stringify(doc));
308
393
  });
309
- this.history = [{ role: "system", content: [{ text: systemText.join("\n") }] }];
310
- console.log(this.history);
394
+ return systemText.join("\n");
311
395
  }
312
396
  };
313
397
  var ChatClient = class {
@@ -315,17 +399,18 @@ var ChatClient = class {
315
399
  this.cmsClient = cmsClient;
316
400
  this.user = user;
317
401
  }
318
- async createChat(options) {
402
+ async createChat() {
319
403
  const chatId = crypto.randomUUID();
320
404
  const docRef = this.dbCollection().doc(chatId);
405
+ const chat = new Chat(this, chatId);
321
406
  await docRef.set({
322
407
  id: chatId,
323
408
  createdBy: this.user,
324
409
  createdAt: Timestamp.now(),
325
410
  modifiedAt: Timestamp.now(),
326
- model: (options == null ? void 0 : options.model) || "gemini-1.5-flash"
411
+ model: chat.model
327
412
  });
328
- return new Chat(this, chatId);
413
+ return chat;
329
414
  }
330
415
  async getChat(chatId) {
331
416
  const docRef = this.dbCollection().doc(chatId);
@@ -354,10 +439,361 @@ var ChatClient = class {
354
439
 
355
440
  // core/client.ts
356
441
  import crypto2 from "node:crypto";
442
+ import {
443
+ FieldValue as FieldValue2,
444
+ Timestamp as Timestamp3
445
+ } from "firebase-admin/firestore";
446
+
447
+ // core/translations-manager.ts
357
448
  import {
358
449
  FieldValue,
359
450
  Timestamp as Timestamp2
360
451
  } from "firebase-admin/firestore";
452
+
453
+ // shared/strings.ts
454
+ import fnv from "fnv-plus";
455
+ function normalizeStr(str) {
456
+ const lines = str.trim().split("\n").map((line) => removeTrailingWhitespace(line));
457
+ return lines.join("\n");
458
+ }
459
+ function removeTrailingWhitespace(str) {
460
+ return str.trimEnd().replace(/&nbsp;$/, "");
461
+ }
462
+ function hashStr(str) {
463
+ if (!str || typeof str !== "string") {
464
+ throw new Error("input string is invalid");
465
+ }
466
+ return fnv.fast1a52hex(normalizeStr(str));
467
+ }
468
+
469
+ // core/translations-manager.ts
470
+ var TRANSLATIONS_DB_PATH_FORMAT = "/Projects/{project}/TranslationsManager/{mode}/Translations";
471
+ var TRANSLATIONS_LOCALE_DOC_DB_PATH_FORMAT = `${TRANSLATIONS_DB_PATH_FORMAT}/{id}:{locale}`;
472
+ var TranslationsManager = class {
473
+ constructor(cmsClient) {
474
+ this.cmsClient = cmsClient;
475
+ }
476
+ /**
477
+ * Saves draft translations for a translations doc id.
478
+ *
479
+ * Example:
480
+ * ```
481
+ * const strings = {
482
+ * 'one': {es: 'uno', fr: 'un'},
483
+ * 'two': {es: 'dos', fr: 'deux'},
484
+ * };
485
+ * await tm.saveTranslations('Pages/index', strings);
486
+ * ```
487
+ */
488
+ async saveTranslations(id, strings, options) {
489
+ const mode = "draft";
490
+ const localesSet = /* @__PURE__ */ new Set();
491
+ Object.values(strings).forEach((entry) => {
492
+ Object.keys(entry).forEach((locale) => {
493
+ if (locale !== "source") {
494
+ localesSet.add(locale);
495
+ }
496
+ });
497
+ });
498
+ const batch = this.cmsClient.db.batch();
499
+ const locales = Array.from(localesSet);
500
+ locales.forEach((locale) => {
501
+ const updates = {
502
+ id,
503
+ locale,
504
+ sys: {
505
+ modifiedAt: Timestamp2.now(),
506
+ modifiedBy: (options == null ? void 0 : options.modifiedBy) || "root-cms-client"
507
+ },
508
+ strings: {}
509
+ };
510
+ if ((options == null ? void 0 : options.tags) && options.tags.length > 0) {
511
+ updates.tags = FieldValue.arrayUnion(...options.tags);
512
+ }
513
+ let numUpdates = 0;
514
+ const hashMap = this.toLocaleDocHashMap(strings, locale);
515
+ Object.entries(hashMap).forEach(([hash, translations]) => {
516
+ Object.entries(translations).forEach(([locale2, translation]) => {
517
+ if (translation) {
518
+ updates.strings[hash] ??= {};
519
+ updates.strings[hash][locale2] = translation;
520
+ numUpdates += 1;
521
+ }
522
+ });
523
+ });
524
+ if (numUpdates > 0) {
525
+ const localeDocPath = buildTranslationsLocaleDocDbPath({
526
+ project: this.cmsClient.projectId,
527
+ mode,
528
+ id,
529
+ locale
530
+ });
531
+ const localeDocRef = this.cmsClient.db.doc(localeDocPath);
532
+ batch.set(localeDocRef, updates, { merge: true });
533
+ }
534
+ });
535
+ await batch.commit();
536
+ }
537
+ /**
538
+ * Publishes a translations doc.
539
+ */
540
+ async publishTranslations(id, options) {
541
+ const db = this.cmsClient.db;
542
+ const project = this.cmsClient.projectId;
543
+ const draftPath = buildTranslationsDbPath({ project, mode: "draft" });
544
+ const query = db.collection(draftPath).where("id", "==", id);
545
+ const res = await query.get();
546
+ if (res.size === 0) {
547
+ console.warn(`no translations to publish for ${id}`);
548
+ return;
549
+ }
550
+ const batch = (options == null ? void 0 : options.batch) || db.batch();
551
+ res.docs.forEach((doc) => {
552
+ const translationsLocaleDoc = doc.data();
553
+ const sys = {
554
+ ...translationsLocaleDoc.sys,
555
+ publishedAt: Timestamp2.now(),
556
+ publishedBy: (options == null ? void 0 : options.publishedBy) || "root-cms-client"
557
+ };
558
+ batch.update(doc.ref, { sys });
559
+ const publishedDocPath = buildTranslationsLocaleDocDbPath({
560
+ project,
561
+ mode: "published",
562
+ id: translationsLocaleDoc.id,
563
+ locale: translationsLocaleDoc.locale
564
+ });
565
+ const publishedDocRef = db.doc(publishedDocPath);
566
+ batch.set(publishedDocRef, { ...translationsLocaleDoc, sys });
567
+ });
568
+ const shouldCommitBatch = !(options == null ? void 0 : options.batch);
569
+ if (shouldCommitBatch) {
570
+ await batch.commit();
571
+ }
572
+ }
573
+ /**
574
+ * Fetches translations from one or more translations docs in the translations
575
+ * manager.
576
+ *
577
+ * Example:
578
+ * ```
579
+ * await tm.loadTranslations();
580
+ * // =>
581
+ * // {
582
+ * // "one": {"es": "uno", "fr": "un"},
583
+ * // "two": {"es": "dos", "fr": "deux"}
584
+ * // }
585
+ * ```
586
+ *
587
+ * To load a specific set of translations docs by id:
588
+ * ```
589
+ * const translationsToLoad = ['Global/strings', 'Global/header', 'Global/footer', 'Pages/index'];
590
+ * await tm.loadTranslations({ids: translationsToLoad});
591
+ * // =>
592
+ * // {
593
+ * // "one": {"es": "uno", "fr": "un"},
594
+ * // "two": {"es": "dos", "fr": "deux"}
595
+ * // }
596
+ * ```
597
+ *
598
+ * To load a subset of locales (more performant):
599
+ * ```
600
+ * await tm.loadTranslations({locales: ['es']});
601
+ * // =>
602
+ * // {
603
+ * // "one": {"es": "uno"},
604
+ * // "two": {"es": "dos"}
605
+ * // }
606
+ * ```
607
+ */
608
+ async loadTranslations(options) {
609
+ const mode = (options == null ? void 0 : options.mode) || "published";
610
+ const dbPath = buildTranslationsDbPath({
611
+ project: this.cmsClient.projectId,
612
+ mode
613
+ });
614
+ let query = this.cmsClient.db.collection(dbPath);
615
+ if ((options == null ? void 0 : options.ids) && options.ids.length > 0) {
616
+ query = query.where("id", "in", options.ids);
617
+ }
618
+ if ((options == null ? void 0 : options.tags) && options.tags.length > 0) {
619
+ query = query.where("tags", "array-contains", options.tags);
620
+ }
621
+ if ((options == null ? void 0 : options.locales) && options.locales.length > 0) {
622
+ query = query.where("locale", "in", options.locales);
623
+ }
624
+ const results = await query.get();
625
+ const strings = {};
626
+ results.forEach((result) => {
627
+ const localeDoc = result.data();
628
+ Object.values(localeDoc.strings || {}).forEach((item) => {
629
+ strings[item.source] ??= { source: item.source };
630
+ strings[item.source][localeDoc.locale] = item.translation;
631
+ });
632
+ });
633
+ return strings;
634
+ }
635
+ /**
636
+ * Fetches translations for a given locale, with optional fallbacks.
637
+ * The return value is a map of source string to translated string.
638
+ *
639
+ * Example:
640
+ * ```
641
+ * await translationsDoc.loadTranslationsForLocale('es');
642
+ * // =>
643
+ * // {
644
+ * // "one": "uno",
645
+ * // "two": "dos",
646
+ * // }
647
+ * ```
648
+ */
649
+ async loadTranslationsForLocale(locale, options) {
650
+ const localeSet = /* @__PURE__ */ new Set([
651
+ locale,
652
+ ...(options == null ? void 0 : options.fallbackLocales) || []
653
+ ]);
654
+ const fallbackLocales = Array.from(localeSet);
655
+ const multiLocaleStrings = await this.loadTranslations({
656
+ mode: options == null ? void 0 : options.mode,
657
+ locales: fallbackLocales
658
+ });
659
+ return this.toSingleLocaleMap(multiLocaleStrings, fallbackLocales);
660
+ }
661
+ /**
662
+ * Converts a multi-locale translations map to a flat single-locale map,
663
+ * with optional support for fallback locales.
664
+ *
665
+ * ```
666
+ * const multiLocaleStrings = {
667
+ * 'one': {es: 'uno', fr: 'un'},
668
+ * 'two': {es: 'dos', fr: 'deux'}
669
+ * };
670
+ * translationsDoc.toSingleLocaleMap(multiLocaleStrings, ['es']);
671
+ * // =>
672
+ * // {
673
+ * // "one": "uno",
674
+ * // "two": "dos",
675
+ * // }
676
+ * ```
677
+ */
678
+ toSingleLocaleMap(multiLocaleStrings, fallbackLocales) {
679
+ const singleLocaleStrings = {};
680
+ Object.entries(multiLocaleStrings).forEach(([source, translations]) => {
681
+ let translation = source;
682
+ for (const locale of fallbackLocales) {
683
+ if (translations[locale]) {
684
+ translation = translations[locale];
685
+ break;
686
+ }
687
+ }
688
+ singleLocaleStrings[source] = translation;
689
+ });
690
+ return singleLocaleStrings;
691
+ }
692
+ /**
693
+ * Converts a multi-locale translations map to a single-locale hashed version,
694
+ * used for storage in in the DB.
695
+ *
696
+ * ```
697
+ * const multiLocaleStrings = {
698
+ * 'one': {es: 'uno', fr: 'un'},
699
+ * 'two': {es: 'dos', fr: 'deux'}
700
+ * };
701
+ * translationsDoc.toLocaleDocHashMap(multiLocaleStrings, 'es');
702
+ * // =>
703
+ * // {
704
+ * // "<hash1>": {"source": "one", "translation": "uno"},
705
+ * // "<hash2>": {"source": "two", "translation": "dos"},
706
+ * // }
707
+ * ```
708
+ *
709
+ * One reason for using hashes is because the DB has limits on the number of
710
+ * chars that can be used as the "key" in a object map.
711
+ */
712
+ toLocaleDocHashMap(multiLocaleStrings, locale) {
713
+ const hashMap = {};
714
+ Object.entries(multiLocaleStrings).forEach(([source, translations]) => {
715
+ const translation = translations[locale];
716
+ if (translation) {
717
+ const hash = hashStr(source);
718
+ hashMap[hash] = { source, translation };
719
+ }
720
+ });
721
+ return hashMap;
722
+ }
723
+ /**
724
+ * Import translations from the v1 system to the TranslationsManager.
725
+ */
726
+ async importTranslationsFromV1() {
727
+ var _a;
728
+ const projectId = this.cmsClient.projectId;
729
+ const db = this.cmsClient.db;
730
+ const dbPath = `Projects/${projectId}/Translations`;
731
+ const query = db.collection(dbPath);
732
+ const querySnapshot = await query.get();
733
+ if (querySnapshot.size === 0) {
734
+ return;
735
+ }
736
+ console.log(
737
+ "[root cms] importing v1 Translations to v2 TranslationsManager"
738
+ );
739
+ const translationsDocs = {};
740
+ querySnapshot.forEach((doc) => {
741
+ const translation = doc.data();
742
+ const source = this.cmsClient.normalizeString(translation.source);
743
+ delete translation.source;
744
+ const tags = translation.tags || [];
745
+ delete translation.tags;
746
+ for (const tag of tags) {
747
+ if (tag.includes("/")) {
748
+ const translationsId = tag;
749
+ translationsDocs[translationsId] ??= {
750
+ id: translationsId,
751
+ tags,
752
+ strings: {}
753
+ };
754
+ translationsDocs[translationsId].strings[source] = translation;
755
+ }
756
+ }
757
+ });
758
+ if (Object.keys(translationsDocs).length === 0) {
759
+ console.log("[root cms] no v1 translations to save");
760
+ return;
761
+ }
762
+ for (const docId in translationsDocs) {
763
+ const [collection, slug] = docId.split("/");
764
+ if (collection && slug) {
765
+ const doc = await this.cmsClient.getDoc(collection, slug, {
766
+ mode: "draft"
767
+ });
768
+ const linkedSheet = (_a = doc == null ? void 0 : doc.sys) == null ? void 0 : _a.l10nSheet;
769
+ if (linkedSheet) {
770
+ translationsDocs[docId].sys.linkedSheet = linkedSheet;
771
+ }
772
+ }
773
+ }
774
+ Object.entries(translationsDocs).forEach(([translationsId, data]) => {
775
+ const len = Object.keys(data.strings).length;
776
+ console.log(`[root cms] saving ${len} string(s) to ${translationsId}...`);
777
+ this.saveTranslations(translationsId, data.strings, {
778
+ tags: data.tags || [translationsId]
779
+ });
780
+ });
781
+ }
782
+ };
783
+ function buildTranslationsDbPath(options) {
784
+ return TRANSLATIONS_DB_PATH_FORMAT.replace(
785
+ "{project}",
786
+ options.project
787
+ ).replace("{mode}", options.mode);
788
+ }
789
+ function buildTranslationsLocaleDocDbPath(options) {
790
+ return TRANSLATIONS_LOCALE_DOC_DB_PATH_FORMAT.replace(
791
+ "{project}",
792
+ options.project
793
+ ).replace("{mode}", options.mode).replace("{id}", options.id.replaceAll("/", "--")).replace("{locale}", options.locale);
794
+ }
795
+
796
+ // core/client.ts
361
797
  var RootCMSClient = class {
362
798
  constructor(rootConfig) {
363
799
  this.rootConfig = rootConfig;
@@ -383,13 +819,19 @@ var RootCMSClient = class {
383
819
  */
384
820
  async getRawDoc(collectionId, slug, options) {
385
821
  const mode = options.mode;
386
- const docRef = this.dbDocRef(collectionId, slug, { mode });
822
+ const modeCollection = mode === "draft" ? "Drafts" : "Published";
823
+ slug = slug.replaceAll("/", "--");
824
+ const dbPath = `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}/${slug}`;
825
+ const docRef = this.db.doc(dbPath);
387
826
  const doc = await docRef.get();
388
827
  if (doc.exists) {
389
828
  return doc.data();
390
829
  }
391
830
  return null;
392
831
  }
832
+ /**
833
+ * Firestore path for a collection.
834
+ */
393
835
  dbCollectionDocsPath(collectionId, options) {
394
836
  let modeCollection = "";
395
837
  if (options.mode === "draft") {
@@ -401,11 +843,17 @@ var RootCMSClient = class {
401
843
  }
402
844
  return `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}`;
403
845
  }
846
+ /**
847
+ * Firestore path for a content doc.
848
+ */
404
849
  dbDocPath(collectionId, slug, options) {
405
850
  const collectionDocsPath = this.dbCollectionDocsPath(collectionId, options);
406
851
  const normalizedSlug = slug.replaceAll("/", "--");
407
852
  return `${collectionDocsPath}/${normalizedSlug}`;
408
853
  }
854
+ /**
855
+ * Firestore doc ref for a content doc.
856
+ */
409
857
  dbDocRef(collectionId, slug, options) {
410
858
  const docPath = this.dbDocPath(collectionId, slug, options);
411
859
  return this.db.doc(docPath);
@@ -428,9 +876,9 @@ var RootCMSClient = class {
428
876
  slug,
429
877
  sys: {
430
878
  ...draftSys,
431
- createdAt: draftSys.createdAt ?? Timestamp2.now(),
879
+ createdAt: draftSys.createdAt ?? Timestamp3.now(),
432
880
  createdBy: draftSys.createdBy ?? modifiedBy,
433
- modifiedAt: Timestamp2.now(),
881
+ modifiedAt: Timestamp3.now(),
434
882
  modifiedBy,
435
883
  locales: (options == null ? void 0 : options.locales) ?? draftSys.locales ?? ["en"]
436
884
  },
@@ -526,6 +974,10 @@ var RootCMSClient = class {
526
974
  }
527
975
  let batchCount = 0;
528
976
  const batch = (options == null ? void 0 : options.batch) || this.db.batch();
977
+ const versionTags = ["published"];
978
+ if (options == null ? void 0 : options.releaseId) {
979
+ versionTags.push(`release:${options.releaseId}`);
980
+ }
529
981
  const publishedDocs = [];
530
982
  for (const doc of docs) {
531
983
  const { id, collection, slug, sys, fields } = doc;
@@ -538,7 +990,7 @@ var RootCMSClient = class {
538
990
  const publishedRef = this.db.doc(
539
991
  `${projectCollectionsPath}/${collection}/Published/${slug}`
540
992
  );
541
- const firstPublishedAt = sys.firstPublishedAt ?? FieldValue.serverTimestamp();
993
+ const firstPublishedAt = sys.firstPublishedAt ?? FieldValue2.serverTimestamp();
542
994
  const firstPublishedBy = sys.firstPublishedBy ?? publishedBy;
543
995
  batch.set(publishedRef, {
544
996
  id,
@@ -549,24 +1001,43 @@ var RootCMSClient = class {
549
1001
  ...sys,
550
1002
  firstPublishedAt,
551
1003
  firstPublishedBy,
552
- publishedAt: FieldValue.serverTimestamp(),
1004
+ publishedAt: FieldValue2.serverTimestamp(),
553
1005
  publishedBy
554
1006
  }
555
1007
  });
556
1008
  batchCount += 1;
1009
+ const versionRef = this.db.doc(
1010
+ `${projectCollectionsPath}/${collection}/Drafts/${slug}/Versions/${Date.now()}`
1011
+ );
1012
+ const versionData = {
1013
+ id,
1014
+ collection,
1015
+ slug,
1016
+ fields: fields || {},
1017
+ sys: {
1018
+ ...sys,
1019
+ firstPublishedAt,
1020
+ firstPublishedBy,
1021
+ publishedAt: FieldValue2.serverTimestamp(),
1022
+ publishedBy
1023
+ }
1024
+ };
1025
+ if (versionTags.length) {
1026
+ versionData.tags = versionTags;
1027
+ }
1028
+ batch.set(versionRef, versionData);
1029
+ batchCount += 1;
557
1030
  batch.delete(scheduledRef);
558
1031
  batchCount += 1;
559
1032
  batch.update(draftRef, {
560
- "sys.scheduledAt": FieldValue.delete(),
561
- "sys.scheduledBy": FieldValue.delete(),
1033
+ "sys.scheduledAt": FieldValue2.delete(),
1034
+ "sys.scheduledBy": FieldValue2.delete(),
562
1035
  "sys.firstPublishedAt": firstPublishedAt,
563
1036
  "sys.firstPublishedBy": firstPublishedBy,
564
- "sys.publishedAt": FieldValue.serverTimestamp(),
1037
+ "sys.publishedAt": FieldValue2.serverTimestamp(),
565
1038
  "sys.publishedBy": publishedBy
566
1039
  });
567
1040
  batchCount += 1;
568
- this.publishTranslationsDoc(doc.id, { batch });
569
- batchCount += 2;
570
1041
  publishedDocs.push(doc);
571
1042
  if (batchCount >= 400) {
572
1043
  await batch.commit();
@@ -613,6 +1084,7 @@ var RootCMSClient = class {
613
1084
  }
614
1085
  let batchCount = 0;
615
1086
  const batch = this.db.batch();
1087
+ const versionTags = ["published"];
616
1088
  const publishedDocs = [];
617
1089
  for (const doc of docs) {
618
1090
  const { id, collection, slug, data } = doc;
@@ -637,24 +1109,41 @@ var RootCMSClient = class {
637
1109
  ...sys,
638
1110
  firstPublishedAt,
639
1111
  firstPublishedBy,
640
- publishedAt: FieldValue.serverTimestamp(),
1112
+ publishedAt: FieldValue2.serverTimestamp(),
641
1113
  publishedBy: scheduledBy || ""
642
1114
  }
643
1115
  });
644
1116
  batchCount += 1;
1117
+ const versionRef = this.db.doc(
1118
+ `${projectCollectionsPath}/${collection}/Drafts/${slug}/Versions/${Date.now()}`
1119
+ );
1120
+ const versionData = {
1121
+ id,
1122
+ collection,
1123
+ slug,
1124
+ fields: data.fields || {},
1125
+ sys: {
1126
+ ...sys,
1127
+ firstPublishedAt,
1128
+ firstPublishedBy,
1129
+ publishedAt: FieldValue2.serverTimestamp(),
1130
+ publishedBy: scheduledBy || ""
1131
+ },
1132
+ tags: versionTags
1133
+ };
1134
+ batch.set(versionRef, versionData);
1135
+ batchCount += 1;
645
1136
  batch.delete(scheduledRef);
646
1137
  batchCount += 1;
647
1138
  batch.update(draftRef, {
648
- "sys.scheduledAt": FieldValue.delete(),
649
- "sys.scheduledBy": FieldValue.delete(),
1139
+ "sys.scheduledAt": FieldValue2.delete(),
1140
+ "sys.scheduledBy": FieldValue2.delete(),
650
1141
  "sys.firstPublishedAt": firstPublishedAt,
651
1142
  "sys.firstPublishedBy": firstPublishedBy,
652
- "sys.publishedAt": FieldValue.serverTimestamp(),
1143
+ "sys.publishedAt": FieldValue2.serverTimestamp(),
653
1144
  "sys.publishedBy": scheduledBy || "root-cms-client"
654
1145
  });
655
1146
  batchCount += 1;
656
- this.publishTranslationsDoc(doc.id, { batch });
657
- batchCount += 2;
658
1147
  publishedDocs.push(doc);
659
1148
  if (batchCount >= 400) {
660
1149
  await batch.commit();
@@ -674,50 +1163,31 @@ var RootCMSClient = class {
674
1163
  async publishScheduledReleases() {
675
1164
  const releasesPath = `Projects/${this.projectId}/Releases`;
676
1165
  const now = Math.ceil((/* @__PURE__ */ new Date()).getTime());
677
- const query = this.db.collection(releasesPath).where("scheduledAt", "<=", Timestamp2.fromMillis(now));
1166
+ const query = this.db.collection(releasesPath).where("scheduledAt", "<=", Timestamp3.fromMillis(now));
678
1167
  const querySnapshot = await query.get();
679
1168
  for (const snapshot of querySnapshot.docs) {
680
1169
  const release = snapshot.data();
681
1170
  const batch = this.db.batch();
682
1171
  const publishedBy = release.scheduledBy || "root-cms-client";
683
1172
  batch.update(snapshot.ref, {
684
- publishedAt: Timestamp2.now(),
1173
+ publishedAt: Timestamp3.now(),
685
1174
  publishedBy,
686
- scheduledAt: FieldValue.delete(),
687
- scheduledBy: FieldValue.delete()
1175
+ scheduledAt: FieldValue2.delete(),
1176
+ scheduledBy: FieldValue2.delete()
1177
+ });
1178
+ const dataSourceIds = release.dataSourceIds || [];
1179
+ if (dataSourceIds.length > 0) {
1180
+ await this.publishDataSources(dataSourceIds, {
1181
+ publishedBy,
1182
+ batch,
1183
+ commitBatch: false
1184
+ });
1185
+ }
1186
+ await this.publishDocs(release.docIds || [], {
1187
+ publishedBy,
1188
+ batch,
1189
+ releaseId: release.id
688
1190
  });
689
- await this.publishDocs(release.docIds || [], { publishedBy, batch });
690
- }
691
- }
692
- async publishTranslationsDoc(translationsId, options) {
693
- const docSlug = translationsId.replaceAll("/", "--");
694
- const draftRef = this.db.doc(
695
- `Projects/${this.projectId}/TranslationsManager/draft/Translations/${docSlug}`
696
- );
697
- const snapshot = await draftRef.get();
698
- if (!snapshot.exists) {
699
- console.warn(`translations ${translationsId} does not exist`);
700
- return;
701
- }
702
- const commitBatch = !(options == null ? void 0 : options.batch);
703
- const batch = (options == null ? void 0 : options.batch) || this.db.batch();
704
- batch.update(draftRef, {
705
- "sys.publishedAt": Timestamp2.now(),
706
- "sys.publishedBy": (options == null ? void 0 : options.publishedBy) || "root-cms-client"
707
- });
708
- const publishedRef = this.db.doc(
709
- `Projects/${this.projectId}/TranslationsManager/published/Translations/${docSlug}`
710
- );
711
- const data = { ...snapshot.data() };
712
- if (!data.sys) {
713
- data.sys = {};
714
- }
715
- data.sys.publishedAt = Timestamp2.now();
716
- data.sys.publishedBy = (options == null ? void 0 : options.publishedBy) || "root-cms-client";
717
- batch.set(publishedRef, data);
718
- if (commitBatch) {
719
- await batch.commit();
720
- this.logAction("translations.publish", { metadata: { translationsId } });
721
1191
  }
722
1192
  }
723
1193
  /**
@@ -727,7 +1197,7 @@ var RootCMSClient = class {
727
1197
  var _a;
728
1198
  if ((_a = doc.sys) == null ? void 0 : _a.publishingLocked) {
729
1199
  if (doc.sys.publishingLocked.until) {
730
- const now = Timestamp2.now().toMillis();
1200
+ const now = Timestamp3.now().toMillis();
731
1201
  const until = doc.sys.publishingLocked.until.toMillis();
732
1202
  return now < until;
733
1203
  }
@@ -736,60 +1206,83 @@ var RootCMSClient = class {
736
1206
  return false;
737
1207
  }
738
1208
  /**
739
- * Loads all published strings in the db.
1209
+ * Returns a `TranslationsManager` object for managing translations.
740
1210
  *
1211
+ * To get translations:
1212
+ * ```
1213
+ * await tm.loadTranslations({
1214
+ * ids: ['Global/strings', 'Pages/index'],
1215
+ * locales: ['es'],
1216
+ * });
1217
+ * ```
1218
+ *
1219
+ * NOTE: The `TranslationsManager` is a v2 feature that will eventually
1220
+ * replace the v1 translations system.
1221
+ */
1222
+ getTranslationsManager() {
1223
+ var _a;
1224
+ const cmsPluginOptions = this.cmsPlugin.getConfig();
1225
+ if ((_a = cmsPluginOptions.experiments) == null ? void 0 : _a.v2TranslationsManager) {
1226
+ throw new Error(
1227
+ "`v2TranslationsManager` is not enabled. update root.config.ts and add: `{experiments: {v2TranslationsManager: true}}`"
1228
+ );
1229
+ }
1230
+ return new TranslationsManager(this);
1231
+ }
1232
+ /**
1233
+ * Loads translations saved in the translations collection, optionally
1234
+ * filtered by tag.
1235
+ *
1236
+ * Returns a map like:
741
1237
  * ```
742
1238
  * {
743
1239
  * "<hash>": {"source": "Hello", "es": "Hola", "fr": "Bonjour"},
744
1240
  * }
745
1241
  * ```
746
- *
747
- * @deprecated Use `createBatchRequest()` to fetch draft/published translations.
748
1242
  */
749
1243
  async loadTranslations(options) {
750
- const dbPath = `Projects/${this.projectId}/TranslationsManager/published/Translations`;
751
- const translationsMap = {};
752
- const addTranslations = (hash, translations) => {
753
- translationsMap[hash] = Object.assign(
754
- translationsMap[hash] || {},
755
- translations
756
- );
757
- };
1244
+ const dbPath = `Projects/${this.projectId}/Translations`;
758
1245
  let query = this.db.collection(dbPath);
759
- if ((options == null ? void 0 : options.tags) && options.tags.length > 0) {
760
- query = query.where("sys.tags", "array-contains-any", options.tags);
761
- }
762
- const snapshot = await query.get();
763
- snapshot.forEach((doc) => {
764
- const data = doc.data();
765
- const strings = data.strings || {};
766
- Object.entries(strings).forEach(([hash, translations]) => {
767
- addTranslations(hash, translations);
768
- });
1246
+ if (options == null ? void 0 : options.tags) {
1247
+ query = query.where("tags", "array-contains-any", options.tags);
1248
+ }
1249
+ const querySnapshot = await query.get();
1250
+ const translationsMap = {};
1251
+ querySnapshot.forEach((doc) => {
1252
+ const hash = doc.id;
1253
+ translationsMap[hash] = doc.data();
769
1254
  });
770
1255
  return translationsMap;
771
1256
  }
772
- async saveDraftTranslations(translationsId, translations, options) {
773
- const docSlug = translationsId.replaceAll("/", "--");
774
- const docPath = `Projects/${this.projectId}/TranslationsManager/draft/${docSlug}`;
775
- const docRef = this.db.doc(docPath);
776
- const snapshot = await docRef.get();
777
- const data = snapshot.data() || {
778
- id: translationsId.replaceAll("--", "/"),
779
- sys: {},
780
- strings: {}
781
- };
782
- data.sys.modifiedAt = Timestamp2.now();
783
- data.sys.modifiedBy = (options == null ? void 0 : options.modifiedby) || "root-cms-client";
784
- const strings = data.strings || {};
785
- Object.entries(translations).forEach(([source, row]) => {
786
- const normalizedSource = this.normalizeString(source);
787
- const hash = this.getTranslationKey(normalizedSource);
788
- strings[hash] = { ...strings[hash], ...row, source: normalizedSource };
1257
+ /**
1258
+ * Saves a map of translations, e.g.:
1259
+ * ```
1260
+ * await client.saveTranslations({
1261
+ * "Hello": {"es": "Hola", "fr": "Bonjour"},
1262
+ * });
1263
+ * ```
1264
+ */
1265
+ async saveTranslations(translations, tags) {
1266
+ const translationsPath = `Projects/${this.projectId}/Translations`;
1267
+ const batch = this.db.batch();
1268
+ let batchCount = 0;
1269
+ Object.entries(translations).forEach(([source, sourceTranslations]) => {
1270
+ const hash = this.getTranslationKey(source);
1271
+ const translationRef = this.db.doc(`${translationsPath}/${hash}`);
1272
+ const data = {
1273
+ ...sourceTranslations,
1274
+ source: this.normalizeString(source)
1275
+ };
1276
+ if (tags) {
1277
+ data.tags = FieldValue2.arrayUnion(...tags);
1278
+ }
1279
+ batch.set(translationRef, data, { merge: true });
1280
+ batchCount += 1;
789
1281
  });
790
- data.strings = strings;
791
- await docRef.set(data);
792
- this.logAction("translations.save", { metadata: { translationsId } });
1282
+ if (batchCount > 500) {
1283
+ throw new Error("up to 500 translations can be saved at a time.");
1284
+ }
1285
+ await batch.commit();
793
1286
  }
794
1287
  /**
795
1288
  * Returns the "key" used for a translation as stored in the db. Translations
@@ -822,6 +1315,25 @@ var RootCMSClient = class {
822
1315
  const translationsMap = await this.loadTranslations(options);
823
1316
  return translationsForLocale(translationsMap, locale);
824
1317
  }
1318
+ /**
1319
+ * Firestore path for a translations file.
1320
+ */
1321
+ dbTranslationsPath(translationsId, options) {
1322
+ const mode = options.mode;
1323
+ if (!(mode === "draft" || mode === "published")) {
1324
+ throw new Error(`invalid mode: ${mode}`);
1325
+ }
1326
+ const slug = translationsId.replaceAll("/", "--");
1327
+ const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
1328
+ return dbPath;
1329
+ }
1330
+ /**
1331
+ * Firestore doc ref for a translations file.
1332
+ */
1333
+ dbTranslationsRef(translationsId, options) {
1334
+ const dbPath = this.dbTranslationsPath(translationsId, options);
1335
+ return this.db.doc(dbPath);
1336
+ }
825
1337
  /**
826
1338
  * Returns a data source configuration object.
827
1339
  */
@@ -852,7 +1364,7 @@ var RootCMSClient = class {
852
1364
  const syncedBy = (options == null ? void 0 : options.syncedBy) || "root-cms-client";
853
1365
  const updatedDataSource = {
854
1366
  ...dataSource,
855
- syncedAt: Timestamp2.now(),
1367
+ syncedAt: Timestamp3.now(),
856
1368
  syncedBy
857
1369
  };
858
1370
  const batch = this.db.batch();
@@ -861,7 +1373,7 @@ var RootCMSClient = class {
861
1373
  data
862
1374
  });
863
1375
  batch.update(dataSourceDocRef, {
864
- syncedAt: Timestamp2.now(),
1376
+ syncedAt: Timestamp3.now(),
865
1377
  syncedBy
866
1378
  });
867
1379
  await batch.commit();
@@ -886,25 +1398,64 @@ var RootCMSClient = class {
886
1398
  const publishedBy = (options == null ? void 0 : options.publishedBy) || "root-cms-client";
887
1399
  const updatedDataSource = {
888
1400
  ...dataSource,
889
- publishedAt: Timestamp2.now(),
1401
+ publishedAt: Timestamp3.now(),
890
1402
  publishedBy
891
1403
  };
892
1404
  const batch = this.db.batch();
893
1405
  batch.set(dataDocRefPublished, {
894
1406
  dataSource: updatedDataSource,
895
- data: (dataRes == null ? void 0 : dataRes.data) || null
1407
+ data: (dataRes == null ? void 0 : dataRes.data) || null,
1408
+ ...(dataRes == null ? void 0 : dataRes.headers) ? { headers: dataRes.headers } : {}
896
1409
  });
897
1410
  batch.update(dataDocRefDraft, {
898
1411
  dataSource: updatedDataSource
899
1412
  });
900
1413
  batch.update(dataSourceDocRef, {
901
- publishedAt: Timestamp2.now(),
1414
+ publishedAt: Timestamp3.now(),
902
1415
  publishedBy
903
1416
  });
904
1417
  await batch.commit();
905
1418
  console.log(`published data ${dataSourceId}`);
906
1419
  console.log(`published by: ${publishedBy}`);
907
1420
  }
1421
+ async publishDataSources(dataSourceIds, options) {
1422
+ const publishedBy = (options == null ? void 0 : options.publishedBy) || "root-cms-client";
1423
+ const batch = (options == null ? void 0 : options.batch) || this.db.batch();
1424
+ for (const id of dataSourceIds) {
1425
+ const dataSource = await this.getDataSource(id);
1426
+ if (!dataSource) {
1427
+ throw new Error(`data source not found: ${id}`);
1428
+ }
1429
+ const dataSourceDocRef = this.db.doc(
1430
+ `Projects/${this.projectId}/DataSources/${id}`
1431
+ );
1432
+ const dataDocRefDraft = this.db.doc(
1433
+ `Projects/${this.projectId}/DataSources/${id}/draft`
1434
+ );
1435
+ const dataDocRefPublished = this.db.doc(
1436
+ `Projects/${this.projectId}/DataSources/${id}/published`
1437
+ );
1438
+ const dataRes = await this.getFromDataSource(id, { mode: "draft" });
1439
+ const updatedDataSource = {
1440
+ ...dataSource,
1441
+ publishedAt: FieldValue2.serverTimestamp(),
1442
+ publishedBy
1443
+ };
1444
+ batch.set(dataDocRefPublished, {
1445
+ dataSource: updatedDataSource,
1446
+ data: (dataRes == null ? void 0 : dataRes.data) || null,
1447
+ ...(dataRes == null ? void 0 : dataRes.headers) ? { headers: dataRes.headers } : {}
1448
+ });
1449
+ batch.update(dataDocRefDraft, { dataSource: updatedDataSource });
1450
+ batch.update(dataSourceDocRef, {
1451
+ publishedAt: FieldValue2.serverTimestamp(),
1452
+ publishedBy
1453
+ });
1454
+ }
1455
+ if (!(options == null ? void 0 : options.batch) || (options == null ? void 0 : options.commitBatch)) {
1456
+ await batch.commit();
1457
+ }
1458
+ }
908
1459
  async fetchData(dataSource) {
909
1460
  if (dataSource.type === "http") {
910
1461
  return await this.fetchHttpData(dataSource);
@@ -937,6 +1488,12 @@ var RootCMSClient = class {
937
1488
  */
938
1489
  async getFromDataSource(dataSourceId, options) {
939
1490
  const mode = (options == null ? void 0 : options.mode) || "published";
1491
+ if (!(mode === "draft" || mode === "published")) {
1492
+ throw new Error(`invalid mode: ${mode}`);
1493
+ }
1494
+ if (!dataSourceId || dataSourceId.includes("/")) {
1495
+ throw new Error(`invalid data source id: ${dataSourceId}`);
1496
+ }
940
1497
  const docRef = this.dbDataSourceDataRef(dataSourceId, { mode });
941
1498
  const doc = await docRef.get();
942
1499
  if (doc.exists) {
@@ -944,6 +1501,9 @@ var RootCMSClient = class {
944
1501
  }
945
1502
  return null;
946
1503
  }
1504
+ /**
1505
+ * Firestore path for a datasource data.
1506
+ */
947
1507
  dbDataSourceDataPath(dataSourceId, options) {
948
1508
  if (!dataSourceId || dataSourceId.includes("/")) {
949
1509
  throw new Error(`invalid data source id: ${dataSourceId}`);
@@ -955,23 +1515,13 @@ var RootCMSClient = class {
955
1515
  const dbPath = `Projects/${this.projectId}/DataSources/${dataSourceId}/Data/${mode}`;
956
1516
  return dbPath;
957
1517
  }
1518
+ /**
1519
+ * Firestore doc ref for a datasource data.
1520
+ */
958
1521
  dbDataSourceDataRef(dataSourceId, options) {
959
1522
  const dbPath = this.dbDataSourceDataPath(dataSourceId, options);
960
1523
  return this.db.doc(dbPath);
961
1524
  }
962
- dbTranslationsPath(translationsId, options) {
963
- const mode = options.mode;
964
- if (!(mode === "draft" || mode === "published")) {
965
- throw new Error(`invalid mode: ${mode}`);
966
- }
967
- const slug = translationsId.replaceAll("/", "--");
968
- const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
969
- return dbPath;
970
- }
971
- dbTranslationsRef(translationsId, options) {
972
- const dbPath = this.dbTranslationsPath(translationsId, options);
973
- return this.db.doc(dbPath);
974
- }
975
1525
  /**
976
1526
  * Gets the user's role from the project's ACL.
977
1527
  */
@@ -996,57 +1546,194 @@ var RootCMSClient = class {
996
1546
  }
997
1547
  return null;
998
1548
  }
999
- /**
1000
- * Verifies user exists in the ACL list.
1001
- */
1002
- async userExistsInAcl(email) {
1003
- if (!email) {
1004
- return false;
1005
- }
1006
- const docRef = this.db.doc(`Projects/${this.projectId}`);
1007
- const snapshot = await docRef.get();
1008
- const data = snapshot.data() || {};
1009
- const acl = data.roles || {};
1010
- if (email in acl) {
1011
- return true;
1549
+ /**
1550
+ * Verifies user exists in the ACL list.
1551
+ */
1552
+ async userExistsInAcl(email) {
1553
+ if (!email) {
1554
+ return false;
1555
+ }
1556
+ const docRef = this.db.doc(`Projects/${this.projectId}`);
1557
+ const snapshot = await docRef.get();
1558
+ const data = snapshot.data() || {};
1559
+ const acl = data.roles || {};
1560
+ if (email in acl) {
1561
+ return true;
1562
+ }
1563
+ if (!email.includes("@")) {
1564
+ console.warn(`invalid email: ${email}`);
1565
+ return false;
1566
+ }
1567
+ const domain = email.split("@").at(-1);
1568
+ if (domain && `*@${domain}` in acl) {
1569
+ return true;
1570
+ }
1571
+ return false;
1572
+ }
1573
+ async logAction(action, options) {
1574
+ if (!action) {
1575
+ throw new Error('missing required: "action"');
1576
+ }
1577
+ const data = {
1578
+ action,
1579
+ timestamp: Timestamp3.now(),
1580
+ by: (options == null ? void 0 : options.by) || "system",
1581
+ metadata: (options == null ? void 0 : options.metadata) || {}
1582
+ };
1583
+ const colRef = this.db.collection(`Projects/${this.projectId}/ActionLogs`);
1584
+ await colRef.add(data);
1585
+ const metaStr = (options == null ? void 0 : options.metadata) ? stringifyObj(options.metadata) : "";
1586
+ console.log(`[${data.timestamp.toMillis()}] action: ${action} ${metaStr}`);
1587
+ const cmsPluginConfig = this.cmsPlugin.getConfig();
1588
+ if (cmsPluginConfig.onAction) {
1589
+ try {
1590
+ cmsPluginConfig.onAction(data);
1591
+ } catch (err) {
1592
+ console.error(err);
1593
+ }
1594
+ }
1595
+ }
1596
+ /**
1597
+ * Creates a batch request that is capable of fetching one or more docs,
1598
+ * corresponding translations, and dataSources.
1599
+ */
1600
+ createBatchRequest(options) {
1601
+ return new BatchRequest(this, options);
1602
+ }
1603
+ };
1604
+ function isRichTextData(data) {
1605
+ return Boolean(
1606
+ isObject(data) && Array.isArray(data.blocks) && data.time && data.version
1607
+ );
1608
+ }
1609
+ function getCmsPlugin(rootConfig) {
1610
+ const plugins = rootConfig.plugins || [];
1611
+ const plugin = plugins.find((plugin2) => plugin2.name === "root-cms");
1612
+ if (!plugin) {
1613
+ throw new Error("could not find root-cms plugin config in root.config.ts");
1614
+ }
1615
+ return plugin;
1616
+ }
1617
+ function marshalData(data) {
1618
+ if (isRichTextData(data)) {
1619
+ return data;
1620
+ }
1621
+ const result = {};
1622
+ for (const key in data) {
1623
+ const val = data[key];
1624
+ if (isObject(val)) {
1625
+ result[key] = marshalData(val);
1626
+ } else if (Array.isArray(val)) {
1627
+ if (val.length > 0 && val.some((item) => isObject(item))) {
1628
+ const items = val.map((item) => {
1629
+ if (isObject(item)) {
1630
+ return marshalData(item);
1631
+ }
1632
+ return item;
1633
+ });
1634
+ result[key] = toArrayObject(items);
1635
+ } else {
1636
+ result[key] = val;
1637
+ }
1638
+ } else {
1639
+ result[key] = val;
1640
+ }
1641
+ }
1642
+ return result;
1643
+ }
1644
+ function unmarshalData(data) {
1645
+ const result = {};
1646
+ for (const key in data) {
1647
+ const val = data[key];
1648
+ if (isObject(val)) {
1649
+ if (val.toMillis) {
1650
+ result[key] = val.toMillis();
1651
+ } else if (Object.hasOwn(val, "_array") && Array.isArray(val._array)) {
1652
+ const arr = val._array.map((arrayKey) => {
1653
+ return {
1654
+ ...unmarshalData(val[arrayKey] || {}),
1655
+ _arrayKey: arrayKey
1656
+ };
1657
+ });
1658
+ result[key] = arr;
1659
+ } else {
1660
+ result[key] = unmarshalData(val);
1661
+ }
1662
+ } else {
1663
+ result[key] = val;
1664
+ }
1665
+ }
1666
+ return result;
1667
+ }
1668
+ function toArrayObject(arr) {
1669
+ if (!Array.isArray(arr)) {
1670
+ return arr;
1671
+ }
1672
+ const arrObject = { _array: [] };
1673
+ for (const item of arr) {
1674
+ const key = randString(6);
1675
+ arrObject[key] = item;
1676
+ arrObject._array.push(key);
1677
+ }
1678
+ return arrObject;
1679
+ }
1680
+ function isObject(data) {
1681
+ return typeof data === "object" && !Array.isArray(data) && data !== null;
1682
+ }
1683
+ function randString(len) {
1684
+ const result = [];
1685
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1686
+ for (let i = 0; i < len; i++) {
1687
+ const rand = Math.floor(Math.random() * chars.length);
1688
+ result.push(chars.charAt(rand));
1689
+ }
1690
+ return result.join("");
1691
+ }
1692
+ function translationsForLocale(translationsMap, locale) {
1693
+ const localeTranslations = {};
1694
+ Object.values(translationsMap).forEach((string) => {
1695
+ const source = string.source;
1696
+ const translation = string[locale] || string.en || string.source;
1697
+ localeTranslations[source] = translation;
1698
+ });
1699
+ return localeTranslations;
1700
+ }
1701
+ function stringifyObj(obj) {
1702
+ function format(obj2) {
1703
+ if (obj2 === null) {
1704
+ return "null";
1012
1705
  }
1013
- if (!email.includes("@")) {
1014
- console.warn(`invalid email: ${email}`);
1015
- return false;
1706
+ if (typeof obj2 === "undefined") {
1707
+ return "undefined";
1016
1708
  }
1017
- const domain = email.split("@").at(-1);
1018
- if (domain && `*@${domain}` in acl) {
1019
- return true;
1709
+ if (typeof obj2 === "string") {
1710
+ return `"${obj2.replaceAll('"', '\\"')}"`;
1020
1711
  }
1021
- return false;
1022
- }
1023
- async logAction(action, options) {
1024
- if (!action) {
1025
- throw new Error('missing required: "action"');
1712
+ if (typeof obj2 !== "object") {
1713
+ return String(obj2);
1026
1714
  }
1027
- const data = {
1028
- action,
1029
- timestamp: Timestamp2.now(),
1030
- by: (options == null ? void 0 : options.by) || "system",
1031
- metadata: (options == null ? void 0 : options.metadata) || {}
1032
- };
1033
- const colRef = this.db.collection(`Projects/${this.projectId}/ActionLogs`);
1034
- await colRef.add(data);
1035
- const metaStr = (options == null ? void 0 : options.metadata) ? stringifyObj(options.metadata) : "";
1036
- console.log(`[${data.timestamp.toMillis()}] action: ${action} ${metaStr}`);
1037
- const cmsPluginConfig = this.cmsPlugin.getConfig();
1038
- if (cmsPluginConfig.onAction) {
1039
- try {
1040
- cmsPluginConfig.onAction(data);
1041
- } catch (err) {
1042
- console.error(err);
1043
- }
1715
+ if (Array.isArray(obj2)) {
1716
+ return `[${obj2.map(format).join(", ")}]`;
1044
1717
  }
1718
+ const entries = Object.entries(obj2).map(([key, value]) => {
1719
+ return `${key}: ${format(value)}`;
1720
+ });
1721
+ return `{${entries.join(", ")}}`;
1045
1722
  }
1046
- createBatchRequest(options) {
1047
- return new BatchRequest(this, options);
1723
+ return format(obj);
1724
+ }
1725
+ function parseDocId(docId) {
1726
+ const sepIndex = docId.indexOf("/");
1727
+ if (sepIndex <= 0) {
1728
+ throw new Error(`invalid doc id: ${docId}`);
1048
1729
  }
1049
- };
1730
+ const collection = docId.slice(0, sepIndex);
1731
+ const slug = docId.slice(sepIndex + 1).replaceAll("/", "--");
1732
+ if (!collection || !slug) {
1733
+ throw new Error(`invalid doc id: ${docId}`);
1734
+ }
1735
+ return { collection, slug };
1736
+ }
1050
1737
  var BatchRequest = class {
1051
1738
  constructor(cmsClient, options) {
1052
1739
  this.docIds = [];
@@ -1216,6 +1903,8 @@ var BatchResponse = class {
1216
1903
  * The input is either a single locale (e.g. "de") or an array of locales
1217
1904
  * representing the fallback tree, e.g. ["en-CA", "en-GB", "en"].
1218
1905
  *
1906
+ * TODO(stevenle): support the locale fallback tree.
1907
+ *
1219
1908
  * The returned value is a flat map of source string to translated string,
1220
1909
  * e.g.:
1221
1910
  * {"<source>": "<translation>"}
@@ -1249,145 +1938,10 @@ var BatchResponse = class {
1249
1938
  return translationsMap;
1250
1939
  }
1251
1940
  };
1252
- function isRichTextData(data) {
1253
- return Boolean(
1254
- isObject(data) && Array.isArray(data.blocks) && data.time && data.version
1255
- );
1256
- }
1257
- function marshalData(data) {
1258
- if (isRichTextData(data)) {
1259
- return data;
1260
- }
1261
- const result = {};
1262
- for (const key in data) {
1263
- const val = data[key];
1264
- if (isObject(val)) {
1265
- result[key] = marshalData(val);
1266
- } else if (Array.isArray(val)) {
1267
- if (val.length > 0 && val.some((item) => isObject(item))) {
1268
- const items = val.map((item) => {
1269
- if (isObject(item)) {
1270
- return marshalData(item);
1271
- }
1272
- return item;
1273
- });
1274
- result[key] = toArrayObject(items);
1275
- } else {
1276
- result[key] = val;
1277
- }
1278
- } else {
1279
- result[key] = val;
1280
- }
1281
- }
1282
- return result;
1283
- }
1284
- function unmarshalData(data) {
1285
- const result = {};
1286
- for (const key in data) {
1287
- const val = data[key];
1288
- if (isObject(val)) {
1289
- if (val.toMillis) {
1290
- result[key] = val.toMillis();
1291
- } else if (Object.hasOwn(val, "_array") && Array.isArray(val._array)) {
1292
- const arr = val._array.map((arrayKey) => {
1293
- return {
1294
- ...unmarshalData(val[arrayKey] || {}),
1295
- _arrayKey: arrayKey
1296
- };
1297
- });
1298
- result[key] = arr;
1299
- } else {
1300
- result[key] = unmarshalData(val);
1301
- }
1302
- } else {
1303
- result[key] = val;
1304
- }
1305
- }
1306
- return result;
1307
- }
1308
- function toArrayObject(arr) {
1309
- if (!Array.isArray(arr)) {
1310
- return arr;
1311
- }
1312
- const arrObject = { _array: [] };
1313
- for (const item of arr) {
1314
- const key = randString(6);
1315
- arrObject[key] = item;
1316
- arrObject._array.push(key);
1317
- }
1318
- return arrObject;
1319
- }
1320
- function isObject(data) {
1321
- return typeof data === "object" && !Array.isArray(data) && data !== null;
1322
- }
1323
- function randString(len) {
1324
- const result = [];
1325
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1326
- for (let i = 0; i < len; i++) {
1327
- const rand = Math.floor(Math.random() * chars.length);
1328
- result.push(chars.charAt(rand));
1329
- }
1330
- return result.join("");
1331
- }
1332
- function translationsForLocale(translationsMap, locale) {
1333
- const localeTranslations = {};
1334
- const fallbackLocales = Array.isArray(locale) ? locale : [locale];
1335
- if (!fallbackLocales.includes("en")) {
1336
- fallbackLocales.push("en");
1337
- }
1338
- Object.values(translationsMap).forEach((string) => {
1339
- const source = string.source;
1340
- let translation = source;
1341
- for (const fallbackLocale of fallbackLocales) {
1342
- if (string[fallbackLocale]) {
1343
- translation = string[fallbackLocale];
1344
- break;
1345
- }
1346
- }
1347
- localeTranslations[source] = translation;
1348
- });
1349
- return localeTranslations;
1350
- }
1351
- function stringifyObj(obj) {
1352
- function format(obj2) {
1353
- if (obj2 === null) {
1354
- return "null";
1355
- }
1356
- if (typeof obj2 === "undefined") {
1357
- return "undefined";
1358
- }
1359
- if (typeof obj2 === "string") {
1360
- return `"${obj2.replaceAll('"', '\\"')}"`;
1361
- }
1362
- if (typeof obj2 !== "object") {
1363
- return String(obj2);
1364
- }
1365
- if (Array.isArray(obj2)) {
1366
- return `[${obj2.map(format).join(", ")}]`;
1367
- }
1368
- const entries = Object.entries(obj2).map(([key, value]) => {
1369
- return `${key}: ${format(value)}`;
1370
- });
1371
- return `{${entries.join(", ")}}`;
1372
- }
1373
- return format(obj);
1374
- }
1375
- function parseDocId(docId) {
1376
- const sepIndex = docId.indexOf("/");
1377
- if (sepIndex <= 0) {
1378
- throw new Error(`invalid doc id: ${docId}`);
1379
- }
1380
- const collection = docId.slice(0, sepIndex);
1381
- const slug = docId.slice(sepIndex + 1).replaceAll("/", "--");
1382
- if (!collection || !slug) {
1383
- throw new Error(`invalid doc id: ${docId}`);
1384
- }
1385
- return { collection, slug };
1386
- }
1387
1941
 
1388
1942
  // core/versions.ts
1389
1943
  import path from "node:path";
1390
- import { Timestamp as Timestamp3 } from "firebase-admin/firestore";
1944
+ import { Timestamp as Timestamp4 } from "firebase-admin/firestore";
1391
1945
  import glob from "tiny-glob";
1392
1946
  var DOCUMENT_SAVE_OFFSET = 5 * 60 * 1e3;
1393
1947
  var VersionsService = class {
@@ -1406,7 +1960,7 @@ var VersionsService = class {
1406
1960
  const lastRun = await this.getLastRun();
1407
1961
  const lastRunWithOffset = lastRun === 0 ? lastRun : lastRun - DOCUMENT_SAVE_OFFSET;
1408
1962
  const changedDocs = await this.getDocsModifiedAfter(lastRunWithOffset);
1409
- const now = Timestamp3.now().toMillis();
1963
+ const now = Timestamp4.now().toMillis();
1410
1964
  const versions = changedDocs.filter((doc) => {
1411
1965
  const modifiedAt = doc.sys.modifiedAt.toMillis();
1412
1966
  return modifiedAt <= now - DOCUMENT_SAVE_OFFSET;
@@ -1452,7 +2006,7 @@ var VersionsService = class {
1452
2006
  * Saves {versionLastRun: <timestamp>} to the Projects/<projectId> doc.
1453
2007
  */
1454
2008
  async saveLastRun(millis) {
1455
- const ts = Timestamp3.fromMillis(millis);
2009
+ const ts = Timestamp4.fromMillis(millis);
1456
2010
  const projectDocRef = this.db.collection("Projects").doc(this.projectId);
1457
2011
  await projectDocRef.set({ versionsLastRun: ts }, { merge: true });
1458
2012
  }
@@ -1460,7 +2014,7 @@ var VersionsService = class {
1460
2014
  * Returns a list of all docs that were edited after a certain time.
1461
2015
  */
1462
2016
  async getDocsModifiedAfter(millis) {
1463
- const ts = Timestamp3.fromMillis(millis);
2017
+ const ts = Timestamp4.fromMillis(millis);
1464
2018
  const results = [];
1465
2019
  const collectionIds = await this.listCollections();
1466
2020
  for (const collectionId of collectionIds) {
@@ -1534,7 +2088,31 @@ function csvToArray(csvString) {
1534
2088
  }
1535
2089
 
1536
2090
  // core/api.ts
1537
- function api(server) {
2091
+ function api(server, options) {
2092
+ server.use("/cms/api/collection.get", async (req, res) => {
2093
+ if (req.method !== "POST" || !String(req.get("content-type")).startsWith("application/json")) {
2094
+ res.status(400).json({ success: false, error: "BAD_REQUEST" });
2095
+ return;
2096
+ }
2097
+ const reqBody = req.body || {};
2098
+ if (!reqBody.collectionId) {
2099
+ res.status(400).json({ success: false, error: "MISSING_COLLECTION_ID" });
2100
+ return;
2101
+ }
2102
+ try {
2103
+ const app = await options.getRenderer(req);
2104
+ const collections = app.getCollections();
2105
+ const collection = collections[reqBody.collectionId];
2106
+ if (!collection) {
2107
+ res.status(404).json({ success: false, error: "NOT_FOUND" });
2108
+ return;
2109
+ }
2110
+ res.status(200).json({ success: true, data: collection });
2111
+ } catch (err) {
2112
+ console.error(err.stack || err);
2113
+ res.status(500).json({ success: false, error: "UNKNOWN" });
2114
+ }
2115
+ });
1538
2116
  server.use("/cms/api/cron.run", async (req, res) => {
1539
2117
  try {
1540
2118
  await runCronJobs(req.rootConfig);
@@ -1692,102 +2270,15 @@ function api(server) {
1692
2270
  });
1693
2271
  }
1694
2272
 
1695
- // core/compatibility.ts
1696
- import { Timestamp as Timestamp4 } from "firebase-admin/firestore";
1697
- async function runCompatibilityChecks(rootConfig) {
1698
- const cmsClient = new RootCMSClient(rootConfig);
1699
- const projectId = cmsClient.projectId;
1700
- const db = cmsClient.db;
1701
- const projectConfigDocRef = db.doc(`Projects/${projectId}`);
1702
- const projectConfigDoc = await projectConfigDocRef.get();
1703
- const projectConfig = projectConfigDoc.data() || {};
1704
- const compatibilityVersions = projectConfig.compatibility || {};
1705
- let versionsChanged = false;
1706
- const translationsVersion = compatibilityVersions.translations || 0;
1707
- if (translationsVersion < 2) {
1708
- await migrateTranslationsToV2(rootConfig, cmsClient);
1709
- compatibilityVersions.translations = 2;
1710
- versionsChanged = true;
1711
- }
1712
- if (versionsChanged) {
1713
- await projectConfigDocRef.update({ compatibility: compatibilityVersions });
1714
- console.log("[root cms] updated db compatibility");
1715
- }
1716
- }
1717
- async function migrateTranslationsToV2(rootConfig, cmsClient) {
1718
- var _a, _b;
1719
- if ((_a = rootConfig.experiments) == null ? void 0 : _a.rootCmsDisableTranslationsToV2Check) {
1720
- return;
1721
- }
1722
- const projectId = cmsClient.projectId;
1723
- const db = cmsClient.db;
1724
- const dbPath = `Projects/${projectId}/Translations`;
1725
- const query = db.collection(dbPath);
1726
- const querySnapshot = await query.get();
1727
- if (querySnapshot.size === 0) {
1728
- return;
1729
- }
1730
- console.log("[root cms] updating translations v2 compatibility");
1731
- const translationsDocs = {};
1732
- querySnapshot.forEach((doc) => {
1733
- const hash = doc.id;
1734
- const translation = doc.data();
1735
- const tags = translation.tags || [];
1736
- delete translation.tags;
1737
- for (const tag of tags) {
1738
- if (tag.includes("/")) {
1739
- const translationsId = tag.replaceAll("/", "--");
1740
- translationsDocs[translationsId] ??= {
1741
- id: translationsId,
1742
- sys: {
1743
- modifiedAt: Timestamp4.now(),
1744
- modifiedBy: "root-cms-client",
1745
- publishedAt: Timestamp4.now(),
1746
- publishedBy: "root-cms-client",
1747
- tags
1748
- },
1749
- strings: {}
1750
- };
1751
- translationsDocs[translationsId].strings[hash] = translation;
1752
- }
1753
- }
1754
- });
1755
- if (Object.keys(translationsDocs).length === 0) {
1756
- console.log("[root cms] no translations to save");
1757
- return;
1758
- }
1759
- for (const docId in translationsDocs) {
1760
- const [collection, slug] = docId.split("/");
1761
- if (collection && slug) {
1762
- const doc = await cmsClient.getDoc(collection, slug, {
1763
- mode: "draft"
1764
- });
1765
- const linkedSheet = (_b = doc == null ? void 0 : doc.sys) == null ? void 0 : _b.l10nSheet;
1766
- if (linkedSheet) {
1767
- translationsDocs[docId].sys.linkedSheet = linkedSheet;
1768
- }
1769
- }
1770
- }
1771
- const batch = db.batch();
1772
- Object.entries(translationsDocs).forEach(([translationsId, data]) => {
1773
- const draftRef = db.doc(
1774
- `Projects/${projectId}/TranslationsManager/draft/Translations/${translationsId}`
1775
- );
1776
- const publishedRef = db.doc(
1777
- `Projects/${projectId}/TranslationsManager/published/Translations/${translationsId}`
1778
- );
1779
- batch.set(draftRef, data, { merge: true });
1780
- batch.set(publishedRef, data, { merge: true });
1781
- const len = Object.keys(data.strings).length;
1782
- console.log(`[root cms] saving ${len} string(s) to ${translationsId}...`);
1783
- });
1784
- await batch.commit();
1785
- console.log("[root cms] done migrating translations to v2");
1786
- }
1787
-
1788
2273
  // core/plugin.ts
1789
2274
  var __dirname2 = path3.dirname(fileURLToPath2(import.meta.url));
1790
2275
  var SESSION_COOKIE_AUTH = "root-cms-auth";
2276
+ var NONCONF_STATIC_PATHS = [
2277
+ "/cms/static/signin.css",
2278
+ "/cms/static/signin.js",
2279
+ "/cms/static/ui.css",
2280
+ "/cms/static/ui.js"
2281
+ ];
1791
2282
  function isExpired(decodedIdToken) {
1792
2283
  const ts = Math.floor((/* @__PURE__ */ new Date()).getTime() / 1e3);
1793
2284
  return ts >= decodedIdToken.exp;
@@ -1824,7 +2315,7 @@ function cmsPlugin(options) {
1824
2315
  if (urlPath === "/cms/api/cron.run") {
1825
2316
  return false;
1826
2317
  }
1827
- if (urlPath === "/cms/static/signin.css" || urlPath === "/cms/static/signin.js") {
2318
+ if (NONCONF_STATIC_PATHS.includes(urlPath)) {
1828
2319
  return false;
1829
2320
  }
1830
2321
  if (urlPath.startsWith("/cms")) {
@@ -1988,17 +2479,6 @@ function cmsPlugin(options) {
1988
2479
  ssrInput: () => ({
1989
2480
  cms: path3.resolve(__dirname2, "./app.js")
1990
2481
  }),
1991
- hooks: {
1992
- /**
1993
- * Startup hook. On `dev` and `build` commands, the plugin does
1994
- * compatibility checks.
1995
- */
1996
- startup: async ({ command, rootConfig }) => {
1997
- if (command === "dev" || command === "build") {
1998
- await runCompatibilityChecks(rootConfig);
1999
- }
2000
- }
2001
- },
2002
2482
  /**
2003
2483
  * Attaches CMS-specific middleware to the Root.js server.
2004
2484
  */
@@ -2086,7 +2566,7 @@ function cmsPlugin(options) {
2086
2566
  });
2087
2567
  const staticDir = path3.resolve(__dirname2, "ui");
2088
2568
  server.use("/cms/static", sirv(staticDir, { dev: false }));
2089
- api(server);
2569
+ api(server, { getRenderer });
2090
2570
  server.use("/cms", async (req, res) => {
2091
2571
  try {
2092
2572
  if (!req.user) {
@@ -2120,16 +2600,6 @@ function cmsPlugin(options) {
2120
2600
  function fileExists(filepath) {
2121
2601
  return fs2.access(filepath).then(() => true).catch(() => false);
2122
2602
  }
2123
- function getCmsPlugin(rootConfig) {
2124
- const plugins = rootConfig.plugins || [];
2125
- const plugin = plugins.find((plugin2) => plugin2.name === "root-cms");
2126
- if (!plugin) {
2127
- throw new Error("could not find root-cms plugin config in root.config.ts");
2128
- }
2129
- return plugin;
2130
- }
2131
2603
  export {
2132
- cmsPlugin,
2133
- getCmsPlugin
2604
+ cmsPlugin
2134
2605
  };
2135
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vY2xpL2dlbmVyYXRlLXR5cGVzLnRzIiwgIi4uL2NvcmUvcGx1Z2luLnRzIiwgIi4uL2NvcmUvYXBpLnRzIiwgIi4uL2NvcmUvYWkudHMiLCAiLi4vY29yZS9jbGllbnQudHMiLCAiLi4vY29yZS92ZXJzaW9ucy50cyIsICIuLi9jb3JlL2Nyb24udHMiLCAiLi4vY29yZS9jc3YudHMiLCAiLi4vY29yZS9jb21wYXRpYmlsaXR5LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJpbXBvcnQge3Byb21pc2VzIGFzIGZzfSBmcm9tICdub2RlOmZzJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge2ZpbGVVUkxUb1BhdGh9IGZyb20gJ25vZGU6dXJsJztcbmltcG9ydCB7bG9hZFJvb3RDb25maWcsIHZpdGVTc3JMb2FkTW9kdWxlfSBmcm9tICdAYmxpbmtrL3Jvb3Qvbm9kZSc7XG5pbXBvcnQgKiBhcyBkb20gZnJvbSAnZHRzLWRvbSc7XG5cbmltcG9ydCB7RmllbGQsIFNjaGVtYX0gZnJvbSAnLi4vY29yZS9zY2hlbWEuanMnO1xuXG50eXBlIFByb2plY3RNb2R1bGUgPSB0eXBlb2YgaW1wb3J0KCcuLi9jb3JlL3Byb2plY3QuanMnKTtcbmNvbnN0IF9fZGlybmFtZSA9IHBhdGguZGlybmFtZShmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCkpO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVUeXBlcygpIHtcbiAgY29uc3Qgcm9vdERpciA9IHByb2Nlc3MuY3dkKCk7XG4gIGNvbnN0IHJvb3RDb25maWcgPSBhd2FpdCBsb2FkUm9vdENvbmZpZyhyb290RGlyLCB7Y29tbWFuZDogJ3Jvb3QtY21zJ30pO1xuICBjb25zdCBtb2R1bGVQYXRoID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4vcHJvamVjdC5qcycpO1xuICBjb25zdCBwcm9qZWN0ID0gKGF3YWl0IHZpdGVTc3JMb2FkTW9kdWxlKFxuICAgIHJvb3RDb25maWcsXG4gICAgbW9kdWxlUGF0aFxuICApKSBhcyBQcm9qZWN0TW9kdWxlO1xuICBjb25zdCBzY2hlbWFzID0gcHJvamVjdC5nZXRQcm9qZWN0U2NoZW1hcygpO1xuICBjb25zdCBvdXRwdXRQYXRoID0gcGF0aC5yZXNvbHZlKHJvb3REaXIsICdyb290LWNtcy5kLnRzJyk7XG4gIGF3YWl0IGdlbmVyYXRlU2NoZW1hRHRzKG91dHB1dFBhdGgsIHNjaGVtYXMpO1xuICBjb25zb2xlLmxvZygnc2F2ZWQgcm9vdC1jbXMuZC50cyEnKTtcbn1cblxuY29uc3QgVEVNUExBVEUgPSBgLyoqIFJvb3QuanMgQ01TIHR5cGVzLiBUaGlzIGZpbGUgaXMgYXV0b2dlbmVyYXRlZC4gKi9cblxuZXhwb3J0IGludGVyZmFjZSBSb290Q01TSW1hZ2Uge1xuICBzcmM6IHN0cmluZztcbiAgd2lkdGg/OiBudW1iZXI7XG4gIGhlaWdodD86IG51bWJlcjtcbiAgYWx0Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBSb290Q01TT25lT2Y8VCA9IGFueT4gPSBUICYge1xuICBfdHlwZTogc3RyaW5nO1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBSb290Q01TUmljaFRleHRCbG9jayB7XG4gIHR5cGU6IHN0cmluZztcbiAgZGF0YTogYW55O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJvb3RDTVNSaWNoVGV4dCB7XG4gIGJsb2NrczogUm9vdENNU1JpY2hUZXh0QmxvY2tbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSb290Q01TUmVmZXJlbmNlIHtcbiAgLyoqIFRoZSBpZCBvZiB0aGUgZG9jLCBlLmcuIFwiUGFnZXMvZm9vLWJhclwiLiAqL1xuICBpZDogc3RyaW5nO1xuICAvKiogVGhlIGNvbGxlY3Rpb24gaWQgb2YgdGhlIGRvYywgZS5nLiBcIlBhZ2VzXCIuICovXG4gIGNvbGxlY3Rpb246IHN0cmluZztcbiAgLyoqIFRoZSBzbHVnIG9mIHRoZSBkb2MsIGUuZy4gXCJmb28tYmFyXCIuICovXG4gIHNsdWc6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSb290Q01TRG9jPEZpZWxkcyBleHRlbmRzIHt9PiB7XG4gIC8qKiBUaGUgaWQgb2YgdGhlIGRvYywgZS5nLiBcIlBhZ2VzL2Zvby1iYXJcIi4gKi9cbiAgaWQ6IHN0cmluZztcbiAgLyoqIFRoZSBjb2xsZWN0aW9uIGlkIG9mIHRoZSBkb2MsIGUuZy4gXCJQYWdlc1wiLiAqL1xuICBjb2xsZWN0aW9uOiBzdHJpbmc7XG4gIC8qKiBUaGUgc2x1ZyBvZiB0aGUgZG9jLCBlLmcuIFwiZm9vLWJhclwiLiAqL1xuICBzbHVnOiBzdHJpbmc7XG4gIC8qKiBTeXN0ZW0tbGV2ZWwgbWV0YWRhdGEuICovXG4gIHN5czoge1xuICAgIGNyZWF0ZWRBdDogbnVtYmVyO1xuICAgIGNyZWF0ZWRCeTogc3RyaW5nO1xuICAgIG1vZGlmaWVkQXQ6IG51bWJlcjtcbiAgICBtb2RpZmllZEJ5OiBzdHJpbmc7XG4gICAgZmlyc3RQdWJsaXNoZWRBdD86IG51bWJlcjtcbiAgICBmaXJzdFB1Ymxpc2hlZEJ5Pzogc3RyaW5nO1xuICAgIHB1Ymxpc2hlZEF0PzogbnVtYmVyO1xuICAgIHB1Ymxpc2hlZEJ5Pzogc3RyaW5nO1xuICAgIGxvY2FsZXM/OiBzdHJpbmdbXTtcbiAgfTtcbiAgLyoqIFVzZXItZW50ZXJlZCBmaWVsZCB2YWx1ZXMgZnJvbSB0aGUgQ01TLiAqL1xuICBmaWVsZHM/OiBGaWVsZHM7XG59YDtcblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSByb290LWNtcy5kLnRzIGZpbGUgZnJvbSB0aGUgLnNjaGVtYS50cyBmaWxlcyBpbiB0aGUgcHJvamVjdC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdlbmVyYXRlU2NoZW1hRHRzKFxuICBvdXRwdXRQYXRoOiBzdHJpbmcsXG4gIHNjaGVtYXM6IFJlY29yZDxzdHJpbmcsIFNjaGVtYT5cbikge1xuICBjb25zdCByZXN1bHRzID0gW1RFTVBMQVRFXTtcbiAgZm9yIChjb25zdCBmaWxlSWQgaW4gc2NoZW1hcykge1xuICAgIGNvbnN0IHNjaGVtYSA9IHNjaGVtYXNbZmlsZUlkXTtcbiAgICByZXN1bHRzLnB1c2gocmVuZGVyU2NoZW1hKGZpbGVJZCwgc2NoZW1hKSk7XG4gIH1cbiAgY29uc3Qgb3V0cHV0ID0gcmVzdWx0c1xuICAgIC5qb2luKCdcXG5cXG4nKVxuICAgIC5yZXBsYWNlQWxsKCcvKiogICcsICcvKiogJylcbiAgICAucmVwbGFjZUFsbCgnICAqLycsICcgKi8nKVxuICAgIC5yZXBsYWNlKC9cXHJcXG58XFxyfFxcbi9nLCAnXFxuJyk7XG4gIGF3YWl0IGZzLndyaXRlRmlsZShvdXRwdXRQYXRoLCBvdXRwdXQsICd1dGYtOCcpO1xufVxuXG5mdW5jdGlvbiBmaWVsZFByb3BlcnR5KGZpZWxkOiBGaWVsZCk6IGRvbS5Qcm9wZXJ0eURlY2xhcmF0aW9uIHtcbiAgY29uc3QgcHJvcCA9IGRvbS5jcmVhdGUucHJvcGVydHkoXG4gICAgZmllbGQuaWQhLFxuICAgIGZpZWxkVHlwZShmaWVsZCksXG4gICAgZG9tLkRlY2xhcmF0aW9uRmxhZ3MuT3B0aW9uYWxcbiAgKTtcbiAgY29uc3QganNkb2MgPSBbXTtcbiAgaWYgKGZpZWxkLmxhYmVsKSB7XG4gICAgaWYgKGZpZWxkLmhlbHApIHtcbiAgICAgIGpzZG9jLnB1c2goYCR7ZmllbGQubGFiZWx9LiAke2ZpZWxkLmhlbHB9YCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGpzZG9jLnB1c2goZmllbGQubGFiZWwpO1xuICAgIH1cbiAgfVxuICBpZiAoZmllbGQuZGVwcmVjYXRlZCkge1xuICAgIGpzZG9jLnB1c2goJ0BkZXByZWNhdGVkJyk7XG4gIH1cbiAgaWYgKGpzZG9jLmxlbmd0aCA+IDApIHtcbiAgICBwcm9wLmpzRG9jQ29tbWVudCA9IGpzZG9jLmpvaW4oJ1xcbicpO1xuICB9XG4gIHJldHVybiBwcm9wO1xufVxuXG5mdW5jdGlvbiBmaWVsZFR5cGUoZmllbGQ6IEZpZWxkKTogZG9tLlR5cGUge1xuICBpZiAoZmllbGQudHlwZSA9PT0gJ2FycmF5Jykge1xuICAgIHJldHVybiBkb20udHlwZS5hcnJheShmaWVsZFR5cGUoZmllbGQub2YpKTtcbiAgfVxuICBpZiAoZmllbGQudHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgcmV0dXJuIGRvbS50eXBlLmJvb2xlYW47XG4gIH1cbiAgaWYgKGZpZWxkLnR5cGUgPT09ICdkYXRlJykge1xuICAgIHJldHVybiBkb20udHlwZS5zdHJpbmc7XG4gIH1cbiAgaWYgKGZpZWxkLnR5cGUgPT09ICdkYXRldGltZScpIHtcbiAgICByZXR1cm4gZG9tLnR5cGUubnVtYmVyO1xuICB9XG4gIGlmIChmaWVsZC50eXBlID09PSAnaW1hZ2UnKSB7XG4gICAgY29uc3QgaW1hZ2VUeXBlID0gZG9tLmNyZWF0ZS5uYW1lZFR5cGVSZWZlcmVuY2UoJ1Jvb3RDTVNJbWFnZScpO1xuICAgIHJldHVybiBpbWFnZVR5cGU7XG4gIH1cbiAgaWYgKGZpZWxkLnR5cGUgPT09ICdmaWxlJykge1xuICAgIHJldHVybiBkb20uY3JlYXRlLm9iamVjdFR5cGUoW2RvbS5jcmVhdGUucHJvcGVydHkoJ3NyYycsIGRvbS50eXBlLnN0cmluZyldKTtcbiAgfVxuICBpZiAoZmllbGQudHlwZSA9PT0gJ211bHRpc2VsZWN0Jykge1xuICAgIHJldHVybiBkb20udHlwZS5hcnJheShkb20udHlwZS5zdHJpbmcpO1xuICB9XG4gIGlmIChmaWVsZC50eXBlID09PSAnb25lb2YnKSB7XG4gICAgY29uc3Qgb25lb2ZUeXBlID0gZG9tLmNyZWF0ZS5uYW1lZFR5cGVSZWZlcmVuY2UoJ1Jvb3RDTVNPbmVPZicpO1xuICAgIHJldHVybiBvbmVvZlR5cGU7XG4gIH1cbiAgaWYgKGZpZWxkLnR5cGUgPT09ICdyZWZlcmVuY2UnKSB7XG4gICAgY29uc3QgcmVmZXJlbmNlVHlwZSA9IGRvbS5jcmVhdGUubmFtZWRUeXBlUmVmZXJlbmNlKCdSb290Q01TUmVmZXJlbmNlJyk7XG4gICAgcmV0dXJuIHJlZmVyZW5jZVR5cGU7XG4gIH1cbiAgaWYgKGZpZWxkLnR5cGUgPT09ICdyaWNodGV4dCcpIHtcbiAgICBjb25zdCByaWNodGV4dFR5cGUgPSBkb20uY3JlYXRlLm5hbWVkVHlwZVJlZmVyZW5jZSgnUm9vdENNU1JpY2hUZXh0Jyk7XG4gICAgcmV0dXJuIHJpY2h0ZXh0VHlwZTtcbiAgfVxuICBpZiAoZmllbGQudHlwZSA9PT0gJ3NlbGVjdCcpIHtcbiAgICByZXR1cm4gZG9tLnR5cGUuc3RyaW5nO1xuICB9XG4gIGlmIChmaWVsZC50eXBlID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBkb20udHlwZS5zdHJpbmc7XG4gIH1cbiAgaWYgKGZpZWxkLnR5cGUgPT09ICdvYmplY3QnKSB7XG4gICAgY29uc3Qgc3VicHJvcGVydGllcyA9IChmaWVsZC5maWVsZHMgfHwgW10pLm1hcCgoZikgPT4gZmllbGRQcm9wZXJ0eShmKSk7XG4gICAgcmV0dXJuIGRvbS5jcmVhdGUub2JqZWN0VHlwZShzdWJwcm9wZXJ0aWVzKTtcbiAgfVxuICByZXR1cm4gZG9tLnR5cGUudW5rbm93bjtcbn1cblxuZnVuY3Rpb24gcmVuZGVyU2NoZW1hKGZpbGVJZDogc3RyaW5nLCBzY2hlbWE6IFNjaGVtYSk6IHN0cmluZyB7XG4gIGNvbnN0IGpzZG9jID0gYEdlbmVyYXRlZCBmcm9tIFxcYCR7ZmlsZUlkfVxcYC5gO1xuICBjb25zdCBpZCA9IGFscGhhbnVtZXJpYyhwYXRoLnBhcnNlKGZpbGVJZCkubmFtZS5zcGxpdCgnLicpWzBdKTtcbiAgY29uc3QgZmllbGRzSW50ZXJmYWNlID0gYCR7aWR9RmllbGRzYDtcbiAgY29uc3QgZmllbGRzID0gZG9tLmNyZWF0ZS5pbnRlcmZhY2UoXG4gICAgZmllbGRzSW50ZXJmYWNlLFxuICAgIGRvbS5EZWNsYXJhdGlvbkZsYWdzLkV4cG9ydFxuICApO1xuICBmaWVsZHMuanNEb2NDb21tZW50ID0ganNkb2M7XG4gIGZvciAoY29uc3QgZmllbGQgb2Ygc2NoZW1hLmZpZWxkcykge1xuICAgIGlmICghZmllbGQuaWQpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBmaWVsZHMubWVtYmVycy5wdXNoKGZpZWxkUHJvcGVydHkoZmllbGQpKTtcbiAgfVxuXG4gIGNvbnN0IGZpZWxkc1R5cGVPdXRwdXQgPSBkb21cbiAgICAuZW1pdChmaWVsZHMsIHtzaW5nbGVMaW5lSnNEb2NDb21tZW50czogdHJ1ZX0pXG4gICAgLnRyaW0oKTtcbiAgaWYgKGZpbGVJZC5zdGFydHNXaXRoKCcvY29sbGVjdGlvbnMvJykpIHtcbiAgICBjb25zdCBiYXNlVHlwZSA9IGRvbS5jcmVhdGUubmFtZWRUeXBlUmVmZXJlbmNlKCdSb290Q01TRG9jJyk7XG4gICAgYmFzZVR5cGUudHlwZUFyZ3VtZW50cy5wdXNoKGRvbS5jcmVhdGUubmFtZWRUeXBlUmVmZXJlbmNlKGZpZWxkc0ludGVyZmFjZSkpO1xuICAgIGNvbnN0IGRvY1R5cGUgPSBkb20uY3JlYXRlLmFsaWFzKFxuICAgICAgYCR7aWR9RG9jYCxcbiAgICAgIGJhc2VUeXBlLFxuICAgICAgZG9tLkRlY2xhcmF0aW9uRmxhZ3MuRXhwb3J0XG4gICAgKTtcbiAgICBkb2NUeXBlLmpzRG9jQ29tbWVudCA9IGpzZG9jO1xuXG4gICAgY29uc3QgZG9jVHlwZU91dHB1dCA9IGRvbVxuICAgICAgLmVtaXQoZG9jVHlwZSwge3NpbmdsZUxpbmVKc0RvY0NvbW1lbnRzOiB0cnVlfSlcbiAgICAgIC50cmltKCk7XG4gICAgcmV0dXJuIHJlaW5kZW50KGZpZWxkc1R5cGVPdXRwdXQgKyAnXFxuXFxuJyArIGRvY1R5cGVPdXRwdXQpO1xuICB9XG4gIHJldHVybiByZWluZGVudChmaWVsZHNUeXBlT3V0cHV0KTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyA0LXNwYWNlIGluZGVudHMgdG8gMi5cbiAqL1xuZnVuY3Rpb24gcmVpbmRlbnQoaW5wdXQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGxpbmVzID0gaW5wdXQuc3BsaXQoJ1xcbicpO1xuICBjb25zdCByZXN1bHRzOiBzdHJpbmdbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICBjb25zdCBjb252ZXJ0ZWRMaW5lID0gbGluZS5yZXBsYWNlKC8gezR9L2csICcgICcpO1xuICAgIHJlc3VsdHMucHVzaChjb252ZXJ0ZWRMaW5lKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0cy5qb2luKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIG5vbi1hbHBoYW51bWVyaWMgY2hhcnMgZnJvbSBhIHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gYWxwaGFudW1lcmljKGlucHV0OiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gaW5wdXQucmVwbGFjZSgvW15hLXpBLVowLTldL2csICcnKTtcbn1cbiIsICJpbXBvcnQge3Byb21pc2VzIGFzIGZzfSBmcm9tICdub2RlOmZzJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge2ZpbGVVUkxUb1BhdGh9IGZyb20gJ25vZGU6dXJsJztcbmltcG9ydCB0eXBlIHtcbiAgQ29uZmlndXJlU2VydmVyT3B0aW9ucyxcbiAgTmV4dEZ1bmN0aW9uLFxuICBQbHVnaW4sXG4gIFJlcXVlc3QsXG4gIFJlc3BvbnNlLFxuICBSb290Q29uZmlnLFxuICBTZXJ2ZXIsXG59IGZyb20gJ0BibGlua2svcm9vdCc7XG5pbXBvcnQgYm9keVBhcnNlciBmcm9tICdib2R5LXBhcnNlcic7XG5pbXBvcnQge1xuICBBcHAsXG4gIGFwcGxpY2F0aW9uRGVmYXVsdCxcbiAgZ2V0QXBwLFxuICBpbml0aWFsaXplQXBwLFxufSBmcm9tICdmaXJlYmFzZS1hZG1pbi9hcHAnO1xuaW1wb3J0IHtnZXRBdXRoLCBEZWNvZGVkSWRUb2tlbn0gZnJvbSAnZmlyZWJhc2UtYWRtaW4vYXV0aCc7XG5pbXBvcnQge0ZpcmVzdG9yZSwgZ2V0RmlyZXN0b3JlfSBmcm9tICdmaXJlYmFzZS1hZG1pbi9maXJlc3RvcmUnO1xuaW1wb3J0ICogYXMganNvbndlYnRva2VuIGZyb20gJ2pzb253ZWJ0b2tlbic7XG5pbXBvcnQgc2lydiBmcm9tICdzaXJ2JztcbmltcG9ydCB7YXBpfSBmcm9tICcuL2FwaS5qcyc7XG5pbXBvcnQge0FjdGlvbiwgUm9vdENNU0NsaWVudH0gZnJvbSAnLi9jbGllbnQuanMnO1xuaW1wb3J0IHtydW5Db21wYXRpYmlsaXR5Q2hlY2tzfSBmcm9tICcuL2NvbXBhdGliaWxpdHkuanMnO1xuXG5jb25zdCBfX2Rpcm5hbWUgPSBwYXRoLmRpcm5hbWUoZmlsZVVSTFRvUGF0aChpbXBvcnQubWV0YS51cmwpKTtcblxudHlwZSBBcHBNb2R1bGUgPSB0eXBlb2YgaW1wb3J0KCcuL2FwcC5qcycpO1xuXG4vLyBUaGUgc2Vzc2lvbiBrZXkgbmFtZSB1c2VkIGZvciBSb290IENNUyBhdXRoZW50aWNhdGlvbi5cbmNvbnN0IFNFU1NJT05fQ09PS0lFX0FVVEggPSAncm9vdC1jbXMtYXV0aCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ01TVXNlciB7XG4gIGVtYWlsOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ01TQUlDb25maWcge1xuICAvKiogQ3VzdG9tIEFQSSBlbmRwb2ludCBmb3IgY2hhdCBwcm9tcHRzLiAqL1xuICBlbmRwb2ludD86IHN0cmluZztcbiAgLyoqIEdlbiBBSSBtb2RlbCB0byB1c2UuIERlZmF1bHRzIHRvICdnZW1pbmktMS41LWZsYXNoJy4gKi9cbiAgbW9kZWw/OiAnZ2VtaW5pLTEuNS1mbGFzaCcgfCAnZ2VtaW5pLTEuNS1wcm8nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENNU1NpZGViYXJUb29sIHtcbiAgLyoqIFVSTCBmb3IgdGhlIHNpZGViYXIgaWNvbiBpbWFnZS4gKi9cbiAgaWNvbj86IHN0cmluZztcbiAgLyoqIExhYmVsLiAqL1xuICBsYWJlbD86IHN0cmluZztcbiAgLyoqIElmcmFtZSBVUkwgdG8gcmVuZGVyIGZvciB0aGUgdG9vbC4gKi9cbiAgaWZyYW1lVXJsPzogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBDTVNQbHVnaW5PcHRpb25zID0ge1xuICAvKipcbiAgICogVGhlIElEIG9mIHRoZSBwcm9qZWN0LiBEYXRhIHdpbGwgYmUgc3RvcmVkIHVuZGVyIHRoZSBuYW1lc3BhY2VcbiAgICogYFByb2plY3RzLyR7aWR9YCBpbiBmaXJlc3RvcmUuXG4gICAqL1xuICBpZD86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIHByb2plY3QuIFVzZWQgaW4gdGhlIGhlYWRlciBvZiB0aGUgQ01TIHRvIGhlbHAgaWRlbnRpZnlcbiAgICogdGhlIHByb2plY3QuXG4gICAqL1xuICBuYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBGaXJlYmFzZSBjb25maWcgb2JqZWN0LCB3aGljaCBjYW4gYmUgb2J0YWluZWQgaW4gdGhlIEZpcmViYXNlIENvbnNvbGUgYnlcbiAgICogZ29pbmcgdG8gXCJQcm9qZWN0IFNldHRpbmdzXCIuXG4gICAqL1xuICBmaXJlYmFzZUNvbmZpZzoge1xuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBhcGlLZXk6IHN0cmluZztcbiAgICBhdXRoRG9tYWluOiBzdHJpbmc7XG4gICAgcHJvamVjdElkOiBzdHJpbmc7XG4gICAgc3RvcmFnZUJ1Y2tldDogc3RyaW5nO1xuICAgIGRhdGFiYXNlSWQ/OiBzdHJpbmc7XG4gIH07XG5cbiAgLyoqXG4gICAqIEdBUEkgY3JlZGVudGlhbHMuIEluY2x1ZGUgaWYgdXNpbmcgR29vZ2xlIERyaXZlIGFuZCBHb29nbGUgU2hlZXRzIGZlYXR1cmVzLlxuICAgKiBTZWU6IGh0dHBzOi8vZGV2ZWxvcGVycy5nb29nbGUuY29tL3NoZWV0cy9hcGkvcXVpY2tzdGFydC9qc1xuICAgKi9cbiAgZ2FwaT86IHtcbiAgICAvKiogaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vc2hlZXRzL2FwaS9xdWlja3N0YXJ0L2pzI2NyZWF0ZV9hbl9hcGlfa2V5ICovXG4gICAgYXBpS2V5OiBzdHJpbmc7XG4gICAgLyoqIGh0dHBzOi8vZGV2ZWxvcGVycy5nb29nbGUuY29tL3NoZWV0cy9hcGkvcXVpY2tzdGFydC9qcyNhdXRob3JpemVfY3JlZGVudGlhbHNfZm9yX2Ffd2ViX2FwcGxpY2F0aW9uICovXG4gICAgY2xpZW50SWQ6IHN0cmluZztcbiAgfTtcblxuICAvKipcbiAgICogU2VjcmV0IHZhbHVlKHMpIHVzZWQgZm9yIHNpZ25pbmcgdGhlIHVzZXIgYXV0aGVudGljYXRpb24gY29va2llLlxuICAgKiBAZGVwcmVjYXRlZCBUaGlzIGlzIG5vdyBoYW5kbGVkIGRpcmVjdGx5IGJ5IHJvb3QncyBzZXNzaW9uTWlkZGxld2FyZSB1bmRlclxuICAgKiBgc2VydmVyLnNlc3Npb25Db29raWVTZWNyZXRgIGluIHJvb3QuY29uZmlnLnRzLlxuICAgKi9cbiAgY29va2llU2VjcmV0Pzogc3RyaW5nIHwgc3RyaW5nW107XG5cbiAgLyoqIEZ1bmN0aW9uIGNhbGxlZCB0byBjaGVjayBpZiBhIHVzZXIgc2hvdWxkIGhhdmUgYWNjZXNzIHRvIHRoZSBDTVMuICovXG4gIGlzVXNlckF1dGhvcml6ZWQ/OiAoXG4gICAgcmVxOiBSZXF1ZXN0LFxuICAgIHVzZXI6IENNU1VzZXJcbiAgKSA9PiBib29sZWFuIHwgUHJvbWlzZTxib29sZWFuPjtcblxuICAvKipcbiAgICogRnVuY3Rpb24gdG8gY2FsbCB0byBjaGVjayBpZiBsb2dpbiBpcyByZXF1aXJlZCBmb3IgYSBwYXJ0aWN1bGFyIHJlcXVlc3QuXG4gICAqL1xuICBpc0xvZ2luUmVxdWlyZWQ/OiAocmVxOiBSZXF1ZXN0KSA9PiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBCeSBkZWZhdWx0LCBpZnJhbWluZyB0aGUgQ01TIGlzIGRpc2FsbG93ZWQuIFNldHRpbmcgdGhpcyB2YWx1ZSB3aWxsIGFsbG93XG4gICAqIGlmcmFtZXMgZnJvbSB0aGUgc3BlY2lmaWVkIG9yaWdpbnMuIEV4YW1wbGU6XG4gICAqIGBgYFxuICAgKiBhbGxvd2VkSWZyYW1lT3JpZ2luczogWydodHRwczovL2FwcC5leGFtcGxlLmNvbSddXG4gICAqIGBgYFxuICAgKi9cbiAgYWxsb3dlZElmcmFtZU9yaWdpbnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogVVJMIHRvIEdDSSBzZXJ2aWNlIGZvciB0cmFuc2Zvcm1pbmcgdXBsb2FkZWQgR0NTIGltYWdlcyB0byBhIEdvb2dsZSBBcHBcbiAgICogRW5naW5lIEltYWdlcyBBUEkgc2VydmluZyBVUkwuXG4gICAqXG4gICAqIFNldHRpbmcgdGhpcyB0byBgdHJ1ZWAgdXNlcyB0aGUgZGVmYXVsdCBob3N0ZWQgc2VydmljZSBhdFxuICAgKiBodHRwczovL2djaS5yb290anMuZGV2LlxuICAgKlxuICAgKiBUbyBzZXQgdXAgR0NJOlxuICAgKlxuICAgKiAtIENyZWF0ZSBhIEdDUyBidWNrZXQgd2l0aCBmaW5lLWdyYWluZWQgcGVybWlzc2lvbnNcbiAgICogLSBTaGFyZSBvd25lciBhY2Nlc3MgdG8gdGhlIGJ1Y2tldCB3aXRoIHRoZSBzZXJ2aWNlIGFjY291bnQgcmV0dXJuZWQgaW5cbiAgICogICBodHRwczovL2djaS5yb290anMuZGV2L18vc2VydmljZV9hY2NvdW50XG4gICAqXG4gICAqIFRvIGRpc2FibGUgR0NJLCBsZWF2ZSB0aGlzIHZhbHVlIGVtcHR5IG9yIHNldCB0byBgZmFsc2VgLCB3aGljaCB3aGljaCB3aWxsXG4gICAqIHNlcnZlIGltYWdlcyBkaXJlY3RseSBmcm9tIEdDUyBpbnN0ZWFkLlxuICAgKi9cbiAgZ2NpPzogc3RyaW5nIHwgYm9vbGVhbjtcblxuICAvKipcbiAgICogQ3VzdG9taXphdGlvbiBvcHRpb25zIGZvciB0aGUgQ01TIHNpZGViYXIuXG4gICAqL1xuICBzaWRlYmFyPzoge1xuICAgIC8qKlxuICAgICAqIFNpZGViYXIgdG9vbHMsIGEgbWFwIG9mIHRoZSBzaWRlYmFyIGlkIHRvIGNvbmZpZyBvcHRpb25zLiBUaGUgc2lkZWJhclxuICAgICAqIHRvb2wgaXMgdXJsLW1hcHBlZCB0byBgL2Ntcy90b29scy86aWRgIGFuZCBkaXNwbGF5cyB0aGUgdG9vbCBpbiBhblxuICAgICAqIGlmcmFtZS5cbiAgICAgKi9cbiAgICB0b29scz86IFJlY29yZDxzdHJpbmcsIENNU1NpZGViYXJUb29sPjtcbiAgfTtcblxuICAvKipcbiAgICogQ2FsbGJhY2sgd2hlbiBhbiBhY3Rpb24gb2NjdXJzLlxuICAgKi9cbiAgb25BY3Rpb24/OiAoYWN0aW9uOiBBY3Rpb24pID0+IGFueTtcblxuICAvKipcbiAgICogRXhwZXJpbWVudGFsIGNvbmZpZyBvcHRpb25zLiBOb3RlOiB0aGVzZSBhcmUgc3ViamVjdCB0byBjaGFuZ2UgYXQgYW55IHRpbWUuXG4gICAqL1xuICBleHBlcmltZW50cz86IHtcbiAgICBhaT86IGJvb2xlYW4gfCBDTVNBSUNvbmZpZztcbiAgfTtcblxuICAvKipcbiAgICogQWRqdXN0IGNvbnNvbGUgb3V0cHV0IHZlcmJvc2l0eS4gRGVmYXVsdCBpcyBgJ2luZm8nYC5cbiAgICovXG4gIGxvZ0xldmVsPzogJ2luZm8nIHwgJ3dhcm4nIHwgJ2Vycm9yJyB8ICdzaWxlbnQnIHwgJ2RlYnVnJztcblxuICAvKipcbiAgICogV2hldGhlciB0byBlbmFibGUvZGlzYWJsZSBmaWxlIHdhdGNoaW5nIGluIGRldiAoZS5nLiBmb3IgZ2VuZXJhdGluZ1xuICAgKiBgcm9vdC1jbXMuZC50c2ApLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG4gICAqL1xuICB3YXRjaD86IGJvb2xlYW47XG59O1xuXG5leHBvcnQgdHlwZSBDTVNQbHVnaW4gPSBQbHVnaW4gJiB7XG4gIG5hbWU6ICdyb290LWNtcyc7XG4gIGdldENvbmZpZzogKCkgPT4gQ01TUGx1Z2luT3B0aW9ucztcbiAgZ2V0RmlyZWJhc2VBcHA6ICgpID0+IEFwcDtcbiAgZ2V0RmlyZXN0b3JlOiAoKSA9PiBGaXJlc3RvcmU7XG59O1xuXG5mdW5jdGlvbiBpc0V4cGlyZWQoZGVjb2RlZElkVG9rZW46IERlY29kZWRJZFRva2VuKSB7XG4gIGNvbnN0IHRzID0gTWF0aC5mbG9vcihuZXcgRGF0ZSgpLmdldFRpbWUoKSAvIDEwMDApO1xuICByZXR1cm4gdHMgPj0gZGVjb2RlZElkVG9rZW4uZXhwO1xufVxuXG5mdW5jdGlvbiBnZXRGaXJlYmFzZUFwcChnY3BQcm9qZWN0SWQ6IHN0cmluZyk6IEFwcCB7XG4gIGNvbnN0IGFwcE5hbWUgPSAncm9vdC1jbXMnO1xuICB0cnkge1xuICAgIHJldHVybiBnZXRBcHAoYXBwTmFtZSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmIChlcnIgJiYgZXJyLmNvZGUgPT09ICdhcHAvbm8tYXBwJykge1xuICAgICAgcmV0dXJuIGluaXRpYWxpemVBcHAoXG4gICAgICAgIHtcbiAgICAgICAgICBwcm9qZWN0SWQ6IGdjcFByb2plY3RJZCxcbiAgICAgICAgICBjcmVkZW50aWFsOiBhcHBsaWNhdGlvbkRlZmF1bHQoKSxcbiAgICAgICAgfSxcbiAgICAgICAgYXBwTmFtZVxuICAgICAgKTtcbiAgICB9XG4gICAgdGhyb3cgZXJyO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjbXNQbHVnaW4ob3B0aW9uczogQ01TUGx1Z2luT3B0aW9ucyk6IENNU1BsdWdpbiB7XG4gIGNvbnN0IGxvZ0xldmVsID0gb3B0aW9ucy5sb2dMZXZlbCB8fCAnaW5mbyc7XG5cbiAgaWYgKCFvcHRpb25zLmZpcmViYXNlQ29uZmlnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgJ21pc3NpbmcgZmlyZWJhc2VDb25maWcuIGNyZWF0ZSBhIG5ldyBhcHAgaW4gdGhlIGZpcmViYXNlIGFkbWluIGNvbnNvbGUgYW5kIGNvcHkgdGhlIGZpcmViYXNlIGNvbmZpZyBvYmplY3QgdG8gcm9vdC5jb25maWcudHMnXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IGZpcmViYXNlQ29uZmlnID0gb3B0aW9ucy5maXJlYmFzZUNvbmZpZyB8fCB7fTtcbiAgY29uc3QgYXBwID0gZ2V0RmlyZWJhc2VBcHAoZmlyZWJhc2VDb25maWcucHJvamVjdElkKTtcbiAgY29uc3QgYXV0aCA9IGdldEF1dGgoYXBwKTtcblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGxvZ2luIGlzIHJlcXVpcmVkIGZvciB0aGUgcmVxdWVzdC4gQ3VycmVudGx5IHJldHVybnMgYHRydWVgIGlmXG4gICAqIHRoZSBVUkwgcGF0aCBzdGFydHMgd2l0aCAvY21zIG9yIGlmID9wcmV2aWV3PXRydWUgaXMgaW4gdGhlIFVSTC5cbiAgICovXG4gIGZ1bmN0aW9uIGxvZ2luUmVxdWlyZWQocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gICAgY29uc3QgdXJsUGF0aCA9IFN0cmluZyhyZXEub3JpZ2luYWxVcmwpLnNwbGl0KCc/JylbMF0udG9Mb3dlckNhc2UoKTtcbiAgICAvLyBBbGxvdyB0aGUgY3JvbiB0byBydW4gdW5hdXRoZW50aWNhdGVkLiBUaGUgY3JvbiBqb2IgaXMgcmVzcG9uc2libGVcbiAgICAvLyBmb3Igc2F2aW5nIHZlcnNpb24gaGlzdG9yeS5cbiAgICBpZiAodXJsUGF0aCA9PT0gJy9jbXMvYXBpL2Nyb24ucnVuJykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvLyBBbGxvdyB0aGUgc2lnbmluLmNzcyBhbmQgc2lnbmluLmpzIGZpbGVzIHRvIGJlIHJlbmRlcmVkIHdpdGhvdXQgYXV0aC5cbiAgICBpZiAoXG4gICAgICB1cmxQYXRoID09PSAnL2Ntcy9zdGF0aWMvc2lnbmluLmNzcycgfHxcbiAgICAgIHVybFBhdGggPT09ICcvY21zL3N0YXRpYy9zaWduaW4uanMnXG4gICAgKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIC8vIFJlcXVpcmUgbG9naW4gb24gYWxsIGAvY21zL2AgcGF0aHMuXG4gICAgaWYgKHVybFBhdGguc3RhcnRzV2l0aCgnL2NtcycpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgLy8gUmVxdWlyZSBsb2dpbiBvbiBhbGwgcGF0aHMgdGhhdCBoYXZlIGA/cHJldmlldz10cnVlYCwgd2hpY2ggaXMgdXNlZCBieVxuICAgIC8vIHRoZSBwcmV2aWV3IGlmcmFtZSB0byByZW5kZXIgdGhlIHByZXZpZXcgZm9yIGEgcGFnZS5cbiAgICBpZiAoU3RyaW5nKHJlcS5xdWVyeS5wcmV2aWV3KSA9PT0gJ3RydWUnKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuaXNMb2dpblJlcXVpcmVkICYmIG9wdGlvbnMuaXNMb2dpblJlcXVpcmVkKHJlcSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpZXMgYSBuZXcgbG9naW4gcmVxdWVzdCBmb3IgYSB1c2VyLiBUaGUgcmVxdWVzdCBib2R5IHNob3VsZCBjb250YWluXG4gICAqIGFuIGlkVG9rZW4sIHdoaWNoIGlzIHZlcmlmaWVkIG9uIHByb2QgdXNpbmcgRmlyZWJhc2UgQWRtaW4gYW5kIElkZW50aXR5XG4gICAqIFRvb2xraXQuIElmIGEgYGlzVXNlckF1dGhvcml6ZWQoKWAgY29uZmlnIGlzIHNldCwgdGhpcyBmdW5jdGlvbiB3aWxsIGFsc29cbiAgICogdmVyaWZ5IHZpYSB0aGF0IGZ1bmN0aW9uLiBSZXR1cm5zIHRydWUgaWYgdGhlIGxvZ2luIHZlcmlmaWNhdGlvbiBzdWNjZWVkcy5cbiAgICovXG4gIGFzeW5jIGZ1bmN0aW9uIHZlcmlmeVVzZXJMb2dpbihcbiAgICByZXE6IFJlcXVlc3RcbiAgKTogUHJvbWlzZTx7YXV0aG9yaXplZDogYm9vbGVhbjsgcmVhc29uPzogc3RyaW5nfT4ge1xuICAgIGNvbnN0IGlkVG9rZW4gPSByZXEuYm9keT8uaWRUb2tlbjtcbiAgICBpZiAoIWlkVG9rZW4pIHtcbiAgICAgIGNvbnNvbGUubG9nKCdsb2dpbiBmYWlsZWQ6IG5vIGlkIHRva2VuJyk7XG4gICAgICByZXR1cm4ge2F1dGhvcml6ZWQ6IGZhbHNlLCByZWFzb246ICdubyB0b2tlbid9O1xuICAgIH1cblxuICAgIGxldCB1c2VyOiBDTVNVc2VyO1xuXG4gICAgLy8gT24gbG9jYWwgZGV2LCBzaW1wbHkgdmVyaWZ5IHRoZSBkZWNvZGVkIGlkVG9rZW4ncyBlbWFpbCBpcyBzZXQuIFRoZVxuICAgIC8vIGlkZW50aXR5IHRvb2xraXQgdGhhdCB2ZXJpZmllcyBpZCB0b2tlbnMgcmVxdWlyZXMgYSBzZXJ2aWNlIGFjY291bnQsXG4gICAgLy8gd2hpY2ggd2Ugd2FudCB0byBhdm9pZCBoYXZpbmcgdG8gc2V0IHVwIHdoZW4gdXNlcnMgYXJlIGRvaW5nIGxvY2FsIGRldi5cbiAgICAvLyBBdXRoZW50aWNhdGlvbiBpcyBzdGlsbCByZXF1aXJlZCBieSB0aGUgZnJvbnRlbmQgdXNpbmcgRmlyZWJhc2UgQXV0aCxcbiAgICAvLyB0aGlzIGp1c3QgYnlwYXNzZXMgdGhlIGluaXRpYWwgc2VydmVyIGNoZWNrIGJlZm9yZSB0aGUgdWkgaXMgcmVuZGVyZWQuXG4gICAgdHJ5IHtcbiAgICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50Jykge1xuICAgICAgICBjb25zdCBqd3QgPSBqc29ud2VidG9rZW4uZGVjb2RlKGlkVG9rZW4pIGFzIGpzb253ZWJ0b2tlbi5Kd3RQYXlsb2FkO1xuICAgICAgICBpZiAoIWp3dC5lbWFpbCB8fCAhand0LmVtYWlsX3ZlcmlmaWVkKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ2xvZ2luIGZhaWxlZDogZW1haWwgdW52ZXJpZmllZCcpO1xuICAgICAgICAgIHJldHVybiB7YXV0aG9yaXplZDogZmFsc2UsIHJlYXNvbjogJ2xvZ2luIGZhaWxlZCd9O1xuICAgICAgICB9XG4gICAgICAgIHVzZXIgPSB7ZW1haWw6IGp3dC5lbWFpbH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBqd3QgPSBhd2FpdCBhdXRoLnZlcmlmeUlkVG9rZW4oaWRUb2tlbiwgdHJ1ZSk7XG4gICAgICAgIGlmIChpc0V4cGlyZWQoand0KSkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdsb2dpbiBmYWlsZWQ6IGlkIHRva2VuIGlzIGV4cGlyZWQnKTtcbiAgICAgICAgICByZXR1cm4ge2F1dGhvcml6ZWQ6IGZhbHNlLCByZWFzb246ICdsb2dpbiBmYWlsZWQnfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWp3dC5lbWFpbCB8fCAhand0LmVtYWlsX3ZlcmlmaWVkKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ2xvZ2luIGZhaWxlZDogZW1haWwgdW52ZXJpZmllZCcpO1xuICAgICAgICAgIHJldHVybiB7YXV0aG9yaXplZDogZmFsc2UsIHJlYXNvbjogJ2xvZ2luIGZhaWxlZCd9O1xuICAgICAgICB9XG4gICAgICAgIHVzZXIgPSB7ZW1haWw6IGp3dC5lbWFpbH07XG4gICAgICB9XG5cbiAgICAgIC8vIFZlcmlmeSB0aGUgcHJvamVjdCdzIGBpc1VzZXJBdXRob3JpemVkKClgIGNvbmZpZyBvcHRpb24uXG4gICAgICBpZiAob3B0aW9ucy5pc1VzZXJBdXRob3JpemVkKSB7XG4gICAgICAgIGNvbnN0IGF1dGhvcml6ZWQgPSBhd2FpdCBvcHRpb25zLmlzVXNlckF1dGhvcml6ZWQocmVxLCB7XG4gICAgICAgICAgZW1haWw6IHVzZXIuZW1haWwsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoIWF1dGhvcml6ZWQpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZygnbG9naW4gZmFpbGVkOiB1c2VyIGlzIG5vdCBhdXRob3JpemVkJyk7XG4gICAgICAgICAgcmV0dXJuIHthdXRob3JpemVkOiBmYWxzZSwgcmVhc29uOiAnbm90IGF1dGhvcml6ZWQnfTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBWZXJpZnkgdGhlIHVzZXIgZXhpc3RzIGluIHRoZSBEQidzIEFDTCBsaXN0LlxuICAgICAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocmVxLnJvb3RDb25maWchKTtcbiAgICAgIGNvbnN0IHVzZXJIYXNBY2Nlc3MgPSBhd2FpdCBjbXNDbGllbnQudXNlckV4aXN0c0luQWNsKHVzZXIuZW1haWwpO1xuICAgICAgaWYgKCF1c2VySGFzQWNjZXNzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdsb2dpbiBmYWlsZWQ6IHVzZXIgaXMgbm90IGluIHRoZSBmaXJlc3RvcmUgYWNsIGxpc3QnKTtcbiAgICAgICAgcmV0dXJuIHthdXRob3JpemVkOiBmYWxzZSwgcmVhc29uOiAnbm90IGF1dGhvcml6ZWQnfTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ2ZhaWxlZCB0byB2ZXJpZnkgand0IHRva2VuJyk7XG4gICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICByZXR1cm4ge2F1dGhvcml6ZWQ6IGZhbHNlLCByZWFzb246ICd1bmtub3duIGVycm9yJ307XG4gICAgfVxuXG4gICAgcmV0dXJuIHthdXRob3JpemVkOiB0cnVlfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHVzZXIgYmFzZWQgb24gdGhlIHJlcXVlc3QncyBzZXNzaW9uIGNvb2tpZS4gVGhlXG4gICAqIHNlc3Npb24gY29va2llIGlzIGNoZWNrZWQgZm9yIHZhbGlkaXR5IHRocm91Z2ggRmlyZWJhc2UgQXV0aCBhbmQgdGhlIHVzZXInc1xuICAgKiBlbWFpbCBpcyB2ZXJpZmllZCB0byBoYXZlIGFjY2VzcyB0byBSb290IENNUywgb3RoZXJ3aXNlIHJldHVybnMgYG51bGxgLlxuICAgKi9cbiAgYXN5bmMgZnVuY3Rpb24gZ2V0Q3VycmVudFVzZXIocmVxOiBSZXF1ZXN0KTogUHJvbWlzZTxDTVNVc2VyIHwgbnVsbD4ge1xuICAgIGNvbnN0IHNlc3Npb25Db29raWUgPSByZXEuc2Vzc2lvbi5nZXRJdGVtKFNFU1NJT05fQ09PS0lFX0FVVEgpO1xuICAgIGlmICghc2Vzc2lvbkNvb2tpZSkge1xuICAgICAgaWYgKGxvZ0xldmVsID09PSAnZGVidWcnKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdubyBsb2dpbiBzZXNzaW9uIGNvb2tpZScpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gT24gbG9jYWwgZGV2LCB2ZXJpZnkgdGhlIGRlY29kZWQgaWRUb2tlbiBoYXMgYSB2YWxpZCBlbWFpbC4gVGhlIGZpcmViYXNlXG4gICAgLy8gYXV0aCB2ZXJpZmljYXRpb24gb3RoZXJ3aXNlIHdvdWxkIHJlcXVpcmUgYSBzZXJ2aWNlIGFjY291bnQuXG4gICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAnZGV2ZWxvcG1lbnQnKSB7XG4gICAgICBjb25zdCBqd3QgPSBqc29ud2VidG9rZW4uZGVjb2RlKHNlc3Npb25Db29raWUpIGFzIGpzb253ZWJ0b2tlbi5Kd3RQYXlsb2FkO1xuICAgICAgaWYgKCFqd3Q/LmVtYWlsIHx8ICFqd3Q/LmVtYWlsX3ZlcmlmaWVkKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgLy8gQ2hlY2sgd2hldGhlciB1c2VyIGlzIGF1dGhvcml6ZWQuXG4gICAgICBpZiAob3B0aW9ucy5pc1VzZXJBdXRob3JpemVkKSB7XG4gICAgICAgIGNvbnN0IGF1dGhvcml6ZWQgPSBhd2FpdCBvcHRpb25zLmlzVXNlckF1dGhvcml6ZWQocmVxLCB7XG4gICAgICAgICAgZW1haWw6IGp3dC5lbWFpbCxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICghYXV0aG9yaXplZCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdzZXNzaW9uIGZhaWxlZDogbm90IGF1dGhvcml6ZWQnKTtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gVmVyaWZ5IHRoZSB1c2VyIGV4aXN0cyBpbiB0aGUgREIncyBBQ0wgbGlzdC5cbiAgICAgIGNvbnN0IGNtc0NsaWVudCA9IG5ldyBSb290Q01TQ2xpZW50KHJlcS5yb290Q29uZmlnISk7XG4gICAgICBjb25zdCB1c2VySGFzQWNjZXNzID0gYXdhaXQgY21zQ2xpZW50LnVzZXJFeGlzdHNJbkFjbChqd3QuZW1haWwpO1xuICAgICAgaWYgKCF1c2VySGFzQWNjZXNzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdzZXNzaW9uIGZhaWxlZDogdXNlciBpcyBub3QgaW4gdGhlIGZpcmVzdG9yZSBhY2wgbGlzdCcpO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7ZW1haWw6IGp3dC5lbWFpbH07XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFZlcmlmeSB0aGUgaWRUb2tlbiB1c2luZyBmaXJlYmFzZSBhdXRoLCBjaGVja2luZyBmb3IgdG9rZW4gcmV2b2NhdGlvbnMuXG4gICAgICBjb25zdCBqd3QgPSBhd2FpdCBhdXRoLnZlcmlmeVNlc3Npb25Db29raWUoc2Vzc2lvbkNvb2tpZSwgdHJ1ZSk7XG4gICAgICBpZiAoaXNFeHBpcmVkKGp3dCkpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ3Nlc3Npb24gZmFpbGVkOiB0b2tlbiBpcyBleHBpcmVkJyk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgLy8gVmVyaWZ5IHVzZXIncyBlbWFpbCBpcyB2ZXJpZmllZC5cbiAgICAgIGlmICghand0LmVtYWlsIHx8ICFqd3QuZW1haWxfdmVyaWZpZWQpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ3Nlc3Npb24gZmFpbGVkOiBlbWFpbCBub3QgdmVyaWZpZWQnKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgICAvLyBDaGVjayB3aGV0aGVyIHVzZXIgaXMgYXV0aG9yaXplZC5cbiAgICAgIGlmIChvcHRpb25zLmlzVXNlckF1dGhvcml6ZWQpIHtcbiAgICAgICAgY29uc3QgYXV0aG9yaXplZCA9IGF3YWl0IG9wdGlvbnMuaXNVc2VyQXV0aG9yaXplZChyZXEsIHtcbiAgICAgICAgICBlbWFpbDogand0LmVtYWlsISxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICghYXV0aG9yaXplZCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdzZXNzaW9uIGZhaWxlZDogbm90IGF1dGhvcml6ZWQnKTtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gVmVyaWZ5IHRoZSB1c2VyIGV4aXN0cyBpbiB0aGUgREIncyBBQ0wgbGlzdC5cbiAgICAgIGNvbnN0IGNtc0NsaWVudCA9IG5ldyBSb290Q01TQ2xpZW50KHJlcS5yb290Q29uZmlnISk7XG4gICAgICBjb25zdCB1c2VySGFzQWNjZXNzID0gYXdhaXQgY21zQ2xpZW50LnVzZXJFeGlzdHNJbkFjbChqd3QuZW1haWwpO1xuICAgICAgaWYgKCF1c2VySGFzQWNjZXNzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdzZXNzaW9uIGZhaWxlZDogdXNlciBpcyBub3QgaW4gdGhlIGZpcmVzdG9yZSBhY2wgbGlzdCcpO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIC8vIEpXVCB2ZXJpZmllZC5cbiAgICAgIHJldHVybiB7ZW1haWw6IGp3dC5lbWFpbCF9O1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcignZmFpbGVkIHRvIHZlcmlmeSBqd3QgdG9rZW4nKTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHJlZGlyZWN0VG9Mb2dpbihyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpIHtcbiAgICBpZiAoU3RyaW5nKHJlcS5vcmlnaW5hbFVybCkudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKCcvY21zL2FwaScpKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMSkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnTk9UX0FVVEhPUklaRUQnfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKCdyZWRpcmVjdGluZyB0byBsb2dpbiBwYWdlJyk7XG4gICAgY29uc3QgcGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh7XG4gICAgICBjb250aW51ZTogcmVxLm9yaWdpbmFsVXJsLFxuICAgIH0pO1xuICAgIHJlcy5yZWRpcmVjdChgL2Ntcy9sb2dpbj8ke3BhcmFtcy50b1N0cmluZygpfWApO1xuICB9XG5cbiAgY29uc3QgcGx1Z2luOiBDTVNQbHVnaW4gPSB7XG4gICAgbmFtZTogJ3Jvb3QtY21zJyxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGNvbmZpZyBvcHRpb25zIHBhc3NlZCB0byB0aGUgcGx1Z2luLlxuICAgICAqL1xuICAgIGdldENvbmZpZzogKCkgPT4ge1xuICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIEZpcmViYXNlIEFwcCBpbnN0YW5jZSB1c2VkIGJ5IHRoZSBwbHVnaW4uXG4gICAgICovXG4gICAgZ2V0RmlyZWJhc2VBcHA6ICgpID0+IHtcbiAgICAgIHJldHVybiBhcHA7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIEZpcmVzdG9yZSBpbnN0YW5jZSB1c2VkIGJ5IHRoZSBwbHVnaW4uXG4gICAgICovXG4gICAgZ2V0RmlyZXN0b3JlOiAoKSA9PiB7XG4gICAgICBjb25zdCBkYXRhYmFzZUlkID0gZmlyZWJhc2VDb25maWcuZGF0YWJhc2VJZCB8fCAnKGRlZmF1bHQpJztcbiAgICAgIHJldHVybiBnZXRGaXJlc3RvcmUoYXBwLCBkYXRhYmFzZUlkKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQSBtYXAgb2Ygc3NyIGZpbGVzIHRvIGluY2x1ZGUgd2hlbiBydW5uaW5nIGByb290IGJ1aWxkYC5cbiAgICAgKi9cbiAgICBzc3JJbnB1dDogKCkgPT4gKHtcbiAgICAgIGNtczogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4vYXBwLmpzJyksXG4gICAgfSksXG5cbiAgICBob29rczoge1xuICAgICAgLyoqXG4gICAgICAgKiBTdGFydHVwIGhvb2suIE9uIGBkZXZgIGFuZCBgYnVpbGRgIGNvbW1hbmRzLCB0aGUgcGx1Z2luIGRvZXNcbiAgICAgICAqIGNvbXBhdGliaWxpdHkgY2hlY2tzLlxuICAgICAgICovXG4gICAgICBzdGFydHVwOiBhc3luYyAoe2NvbW1hbmQsIHJvb3RDb25maWd9KSA9PiB7XG4gICAgICAgIGlmIChjb21tYW5kID09PSAnZGV2JyB8fCBjb21tYW5kID09PSAnYnVpbGQnKSB7XG4gICAgICAgICAgYXdhaXQgcnVuQ29tcGF0aWJpbGl0eUNoZWNrcyhyb290Q29uZmlnKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQXR0YWNoZXMgQ01TLXNwZWNpZmljIG1pZGRsZXdhcmUgdG8gdGhlIFJvb3QuanMgc2VydmVyLlxuICAgICAqL1xuICAgIGNvbmZpZ3VyZVNlcnZlcjogYXN5bmMgKFxuICAgICAgc2VydmVyOiBTZXJ2ZXIsXG4gICAgICBzZXJ2ZXJPcHRpb25zOiBDb25maWd1cmVTZXJ2ZXJPcHRpb25zXG4gICAgKSA9PiB7XG4gICAgICBzZXJ2ZXIudXNlKGJvZHlQYXJzZXIuanNvbigpKTtcblxuICAgICAgYXN5bmMgZnVuY3Rpb24gZ2V0UmVuZGVyZXIocmVxOiBSZXF1ZXN0KTogUHJvbWlzZTxBcHBNb2R1bGU+IHtcbiAgICAgICAgaWYgKHNlcnZlck9wdGlvbnMudHlwZSA9PT0gJ2RldicpIHtcbiAgICAgICAgICBjb25zdCBhcHBGaWxlUGF0aCA9IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuL2FwcC5qcycpO1xuICAgICAgICAgIGNvbnN0IGFwcCA9IChhd2FpdCByZXEudml0ZVNlcnZlciEuc3NyTG9hZE1vZHVsZShcbiAgICAgICAgICAgIGFwcEZpbGVQYXRoXG4gICAgICAgICAgKSkgYXMgQXBwTW9kdWxlO1xuICAgICAgICAgIHJldHVybiBhcHA7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBhcHBJbXBvcnRQYXRoID0gcGF0aC5yZXNvbHZlKFxuICAgICAgICAgIHJlcS5yb290Q29uZmlnIS5yb290RGlyLFxuICAgICAgICAgICdkaXN0L3NlcnZlci9jbXMuanMnXG4gICAgICAgICk7XG4gICAgICAgIGlmICghKGF3YWl0IGZpbGVFeGlzdHMoYXBwSW1wb3J0UGF0aCkpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgJ2Rpc3Qvc2VydmVyL2Ntcy5qcyBub3QgZm91bmQuIHJ1biBgcm9vdCBidWlsZGAgdG8gY3JlYXRlIGl0LidcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFwcCA9IChhd2FpdCBpbXBvcnQoYXBwSW1wb3J0UGF0aCkpIGFzIEFwcE1vZHVsZTtcbiAgICAgICAgcmV0dXJuIGFwcDtcbiAgICAgIH1cblxuICAgICAgLy8gTG9naW4gaGFuZGxlci5cbiAgICAgIHNlcnZlci51c2UoJy9jbXMvbG9naW4nLCBhc3luYyAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICByZXEubWV0aG9kID09PSAnUFVUJyAmJlxuICAgICAgICAgIHJlcS5oZWFkZXJzWydjb250ZW50LXR5cGUnXSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nXG4gICAgICAgICkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCB7YXV0aG9yaXplZCwgcmVhc29ufSA9IGF3YWl0IHZlcmlmeVVzZXJMb2dpbihyZXEpO1xuICAgICAgICAgICAgaWYgKCFhdXRob3JpemVkKSB7XG4gICAgICAgICAgICAgIHJlc1xuICAgICAgICAgICAgICAgIC5zdGF0dXMoNDAxKVxuICAgICAgICAgICAgICAgIC5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdOT1RfQVVUSE9SSVpFRCcsIHJlYXNvbn0pO1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFNldCBzZXNzaW9uIGV4cGlyYXRpb24gdG8gNSBkYXlzLlxuICAgICAgICAgICAgY29uc3QgZXhwaXJlc0luID0gNjAgKiA2MCAqIDI0ICogNSAqIDEwMDA7XG4gICAgICAgICAgICBjb25zdCBpZFRva2VuID0gcmVxLmJvZHkuaWRUb2tlbiE7XG5cbiAgICAgICAgICAgIGxldCBzZXNzaW9uQ29va2llOiBzdHJpbmc7XG4gICAgICAgICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCcpIHtcbiAgICAgICAgICAgICAgc2Vzc2lvbkNvb2tpZSA9IGlkVG9rZW47XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBzZXNzaW9uQ29va2llID0gYXdhaXQgYXV0aC5jcmVhdGVTZXNzaW9uQ29va2llKGlkVG9rZW4sIHtcbiAgICAgICAgICAgICAgICBleHBpcmVzSW4sXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzLnNlc3Npb24uc2V0SXRlbShTRVNTSU9OX0NPT0tJRV9BVVRILCBzZXNzaW9uQ29va2llKTtcbiAgICAgICAgICAgIHJlcy5zYXZlU2Vzc2lvbigpO1xuICAgICAgICAgICAgcmVzLmpzb24oe3N1Y2Nlc3M6IHRydWV9KTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgICAgICAgIGlmIChlcnIuc3RhY2spIHtcbiAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnIuc3RhY2spO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzXG4gICAgICAgICAgICAgIC5zdGF0dXMoNTAwKVxuICAgICAgICAgICAgICAuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5LTk9XTl9TRVJWRVJfRVJST1InfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgYXBwID0gYXdhaXQgZ2V0UmVuZGVyZXIocmVxKTtcbiAgICAgICAgICBhcHAucmVuZGVyU2lnbkluKHJlcSwgcmVzLCB7XG4gICAgICAgICAgICByb290Q29uZmlnOiByZXEucm9vdENvbmZpZyEsXG4gICAgICAgICAgICBjbXNDb25maWc6IG9wdGlvbnMsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgICAgICBpZiAoZXJyLnN0YWNrKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGVyci5zdGFjayk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJlcy5zdGF0dXMoNTAwKS5zZW5kKCdVTktOT1dOIFNFUlZFUiBFUlJPUicpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgLy8gTG9nb3V0IGhhbmRsZXIuXG4gICAgICBzZXJ2ZXIudXNlKCcvY21zL2xvZ291dCcsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICAgICAgcmVzLnNlc3Npb24ucmVtb3ZlSXRlbShTRVNTSU9OX0NPT0tJRV9BVVRIKTtcbiAgICAgICAgcmVzLnNhdmVTZXNzaW9uKCk7XG4gICAgICAgIHJlcy5yZWRpcmVjdCgnL2Ntcy9sb2dpbicpO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIEluamVjdCB0aGUgY3VycmVudCB1c2VyIGludG8gdGhlIHJlcSBvYmplY3QgYW5kIGNoZWNrIGlmIGxvZ2luIGlzXG4gICAgICAvLyByZXF1aXJlZCwgc2VuZGluZyB1bmF1dGhlbnRpY2F0ZWQgdXNlcnMgdG8gdGhlIGxvZ2luIHBhZ2UuXG4gICAgICBzZXJ2ZXIudXNlKGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4ge1xuICAgICAgICBjb25zdCB1c2VyID0gYXdhaXQgZ2V0Q3VycmVudFVzZXIocmVxKTtcbiAgICAgICAgaWYgKHVzZXIpIHtcbiAgICAgICAgICByZXEudXNlciA9IHVzZXI7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiBubyB1c2VyIGFuZCBsb2dpbiBpcyByZXF1aXJlZCBmb3IgdGhlIGdpdmVuIHBhdGgsIHJlZGlyZWN0IHRvIHRoZVxuICAgICAgICAvLyBsb2dpbiBwYWdlLlxuICAgICAgICBpZiAoIXVzZXIgJiYgbG9naW5SZXF1aXJlZChyZXEpKSB7XG4gICAgICAgICAgcmVkaXJlY3RUb0xvZ2luKHJlcSwgcmVzKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBuZXh0KCk7XG4gICAgICB9KTtcblxuICAgICAgY29uc3Qgc3RhdGljRGlyID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJ3VpJyk7XG4gICAgICBzZXJ2ZXIudXNlKCcvY21zL3N0YXRpYycsIHNpcnYoc3RhdGljRGlyLCB7ZGV2OiBmYWxzZX0pKTtcblxuICAgICAgLy8gUmVnaXN0ZXIgQVBJIGhhbmRsZXJzLlxuICAgICAgYXBpKHNlcnZlcik7XG5cbiAgICAgIC8vIFJlbmRlciB0aGUgQ01TIFNQQS5cbiAgICAgIHNlcnZlci51c2UoJy9jbXMnLCBhc3luYyAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gRW5mb3JjZSBsb2dpbiBmb3IgYWxsIENNUyBwYXRocy4gVGhlIGByZXEudXNlcmAgd291bGQgb25seSBiZVxuICAgICAgICAgIC8vIHBvcHVsYXRlZCBpZiB0aGUgZmlyZWJhc2UgYXV0aCB0b2tlbiBpcyB2YWxpZCBhbmQgdGhlIHVzZXIgaGFzXG4gICAgICAgICAgLy8gYWNjZXNzIHZpYSB0aGUgUm9vdCBDTVMgc2hhcmVib3guXG4gICAgICAgICAgaWYgKCFyZXEudXNlcikge1xuICAgICAgICAgICAgcmVkaXJlY3RUb0xvZ2luKHJlcSwgcmVzKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgYXBwID0gYXdhaXQgZ2V0UmVuZGVyZXIocmVxKTtcbiAgICAgICAgICBhd2FpdCBhcHAucmVuZGVyQXBwKHJlcSwgcmVzLCB7XG4gICAgICAgICAgICByb290Q29uZmlnOiByZXEucm9vdENvbmZpZyEsXG4gICAgICAgICAgICBjbXNDb25maWc6IG9wdGlvbnMsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgIC8vIFRPRE8oc3RldmVubGUpOiByZW5kZXIgYSBjdXN0b20gZXJyb3IgcGFnZS5cbiAgICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgICAgcmVzLnN0YXR1cyg1MDApLnNlbmQoJ1VOS05PV04gU0VSVkVSIEVSUk9SJyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0sXG4gIH07XG5cbiAgaWYgKG9wdGlvbnMud2F0Y2ggIT09IGZhbHNlKSB7XG4gICAgcGx1Z2luLm9uRmlsZUNoYW5nZSA9IChcbiAgICAgIGV2ZW50TmFtZTogJ2FkZCcgfCAnYWRkRGlyJyB8ICdjaGFuZ2UnIHwgJ3VubGluaycgfCAndW5saW5rRGlyJyxcbiAgICAgIGZpbGVwYXRoOiBzdHJpbmdcbiAgICApID0+IHtcbiAgICAgIGlmIChmaWxlcGF0aC5lbmRzV2l0aCgnLnNjaGVtYS50cycpKSB7XG4gICAgICAgIC8vIEF2b2lkIGxvYWRpbmcgdGhlIGBnZW5lcmF0ZS10eXBlcy5qc2AgbW9kdWxlIGlmIGl0IGlzIG5vdCBuZWVkZWQuXG4gICAgICAgIC8vIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2JsaW5ray9yb290anMvaXNzdWVzLzQyNlxuICAgICAgICBpbXBvcnQoJy4uL2NsaS9nZW5lcmF0ZS10eXBlcy5qcycpLnRoZW4oKGdlbmVyYXRlVHlwZXNNb2R1bGUpID0+IHtcbiAgICAgICAgICBjb25zdCBnZW5lcmF0ZVR5cGVzID0gZ2VuZXJhdGVUeXBlc01vZHVsZS5nZW5lcmF0ZVR5cGVzO1xuICAgICAgICAgIGdlbmVyYXRlVHlwZXMoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBwbHVnaW47XG59XG5cbmZ1bmN0aW9uIGZpbGVFeGlzdHMoZmlsZXBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICByZXR1cm4gZnNcbiAgICAuYWNjZXNzKGZpbGVwYXRoKVxuICAgIC50aGVuKCgpID0+IHRydWUpXG4gICAgLmNhdGNoKCgpID0+IGZhbHNlKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldENtc1BsdWdpbihyb290Q29uZmlnOiBSb290Q29uZmlnKTogQ01TUGx1Z2luIHtcbiAgY29uc3QgcGx1Z2luczogUGx1Z2luW10gPSByb290Q29uZmlnLnBsdWdpbnMgfHwgW107XG4gIGNvbnN0IHBsdWdpbiA9IHBsdWdpbnMuZmluZCgocGx1Z2luKSA9PiBwbHVnaW4ubmFtZSA9PT0gJ3Jvb3QtY21zJyk7XG4gIGlmICghcGx1Z2luKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjb3VsZCBub3QgZmluZCByb290LWNtcyBwbHVnaW4gY29uZmlnIGluIHJvb3QuY29uZmlnLnRzJyk7XG4gIH1cbiAgcmV0dXJuIHBsdWdpbiBhcyBDTVNQbHVnaW47XG59XG4iLCAiaW1wb3J0IHtTZXJ2ZXIsIFJlcXVlc3QsIFJlc3BvbnNlfSBmcm9tICdAYmxpbmtrL3Jvb3QnO1xuaW1wb3J0IHttdWx0aXBhcnRNaWRkbGV3YXJlfSBmcm9tICdAYmxpbmtrL3Jvb3QvbWlkZGxld2FyZSc7XG5pbXBvcnQge0NoYXQsIENoYXRDbGllbnR9IGZyb20gJy4vYWkuanMnO1xuaW1wb3J0IHtSb290Q01TQ2xpZW50fSBmcm9tICcuL2NsaWVudC5qcyc7XG5pbXBvcnQge3J1bkNyb25Kb2JzfSBmcm9tICcuL2Nyb24uanMnO1xuaW1wb3J0IHthcnJheVRvQ3N2LCBjc3ZUb0FycmF5fSBmcm9tICcuL2Nzdi5qcyc7XG5cbi8qKlxuICogUmVnaXN0ZXJzIEFQSSBtaWRkbGV3YXJlIGhhbmRsZXJzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXBpKHNlcnZlcjogU2VydmVyKSB7XG4gIC8qKlxuICAgKiBSdW5zIENNUyBjcm9uIGpvYnMuXG4gICAqL1xuICBzZXJ2ZXIudXNlKCcvY21zL2FwaS9jcm9uLnJ1bicsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgcnVuQ3JvbkpvYnMocmVxLnJvb3RDb25maWchKTtcbiAgICAgIHJlcy5zdGF0dXMoMjAwKS5qc29uKHtzdWNjZXNzOiB0cnVlfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7c3VjY2VzczogZmFsc2V9KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBBY2NlcHRzIGEgSlNPTiBvYmplY3QgY29udGFpbmluZyB7aGVhZGVyczogWy4uLl0sIHJvd3M6IFsuLi5dfSBhbmQgc2VuZHNcbiAgICogYW4gSFRUUCByZXNwb25zZSB3aXRoIGEgY29ycmVzcG9uZGluZyBDU1YgZmlsZSBhcyBhbiBhdHRhY2htZW50LlxuICAgKlxuICAgKiBTYW1wbGUgcmVxdWVzdDpcbiAgICpcbiAgICogYGBganNvblxuICAgKiB7XG4gICAqICAgXCJoZWFkZXJzXCI6IFtcImZvb1wiXSxcbiAgICogICBcInJvd3NcIjogW1xuICAgKiAgICAge1wiZm9vXCI6IFwiYmFyXCJ9LFxuICAgKiAgICAge1wiZm9vXCI6IFwiYmF6XCJ9LFxuICAgKiAgIF1cbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIHNlcnZlci51c2UoJy9jbXMvYXBpL2Nzdi5kb3dubG9hZCcsIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICBpZiAoXG4gICAgICByZXEubWV0aG9kICE9PSAnUE9TVCcgfHxcbiAgICAgICFTdHJpbmcocmVxLmdldCgnY29udGVudC10eXBlJykpLnN0YXJ0c1dpdGgoJ2FwcGxpY2F0aW9uL2pzb24nKVxuICAgICkge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0JBRF9SRVFVRVNUJ30pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBib2R5ID0gcmVxLmJvZHkgfHwge307XG4gICAgICBjb25zdCBoZWFkZXJzID0gYm9keS5oZWFkZXJzIHx8IFtdO1xuICAgICAgY29uc3Qgcm93cyA9IGJvZHkucm93cyB8fCBbXTtcbiAgICAgIGNvbnN0IGNzdiA9IGFycmF5VG9Dc3Yoe2hlYWRlcnMsIHJvd3N9KTtcbiAgICAgIHJlcy5zZXRIZWFkZXIoJ0NvbnRlbnQtVHlwZScsICd0ZXh0L2NzdicpO1xuICAgICAgcmVzLnNldEhlYWRlcignQ29udGVudC1EaXNwb3NpdGlvbicsICdhdHRhY2htZW50OyBmaWxlbmFtZT1cImRhdGEuY3N2XCInKTtcbiAgICAgIHJlcy5zdGF0dXMoMjAwKS5lbmQoY3N2KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrIHx8IGVycik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5LTk9XTid9KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBJbXBvcnRzIGEgQ1NWIGZpbGUgYW5kIHJldHVybnMgYSBKU09OIGFycmF5IG9mIG9iamVjdHMgcmVwcmVzZW50aW5nIHRoZVxuICAgKiBDU1YuXG4gICAqXG4gICAqIFNhbXBsZSByZXNwb25zZTpcbiAgICpcbiAgICogYGBganNvblxuICAgKiB7XG4gICAqICAgXCJzdWNjZXNzXCI6IHRydWUsXG4gICAqICAgXCJkYXRhXCI6IFtcbiAgICogICAgIHtcImZvb1wiOiBcImJhclwifSxcbiAgICogICAgIHtcImZvb1wiOiBcImJhelwifSxcbiAgICogICBdXG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICBzZXJ2ZXIudXNlKFxuICAgICcvY21zL2FwaS9jc3YuaW1wb3J0JyxcbiAgICBtdWx0aXBhcnRNaWRkbGV3YXJlKCksXG4gICAgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgICAgaWYgKHJlcS5tZXRob2QgIT09ICdQT1NUJyB8fCAhcmVxLmZpbGVzIHx8ICFyZXEuZmlsZXMuZmlsZSkge1xuICAgICAgICByZXMuc3RhdHVzKDQwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnQkFEX1JFUVVFU1QnfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZmlsZSA9IHJlcS5maWxlcy5maWxlO1xuICAgICAgICBjb25zdCBjc3ZTdHJpbmcgPSBmaWxlLmJ1ZmZlci50b1N0cmluZygndXRmOCcpO1xuICAgICAgICBjb25zdCByb3dzID0gY3N2VG9BcnJheShjc3ZTdHJpbmcpO1xuICAgICAgICByZXMuc3RhdHVzKDIwMCkuanNvbih7c3VjY2VzczogdHJ1ZSwgZGF0YTogcm93c30pO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrIHx8IGVycik7XG4gICAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTktOT1dOJ30pO1xuICAgICAgfVxuICAgIH1cbiAgKTtcblxuICAvKipcbiAgICogUnVucyBhIGRhdGEgc291cmNlIHN5bmMuXG4gICAqL1xuICBzZXJ2ZXIudXNlKCcvY21zL2FwaS9kYXRhLnN5bmMnLCBhc3luYyAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgaWYgKFxuICAgICAgcmVxLm1ldGhvZCAhPT0gJ1BPU1QnIHx8XG4gICAgICAhU3RyaW5nKHJlcS5nZXQoJ2NvbnRlbnQtdHlwZScpKS5zdGFydHNXaXRoKCdhcHBsaWNhdGlvbi9qc29uJylcbiAgICApIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdCQURfUkVRVUVTVCd9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoIXJlcS51c2VyPy5lbWFpbCkge1xuICAgICAgcmVzLnN0YXR1cyg0MDEpLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ1VOQVVUSE9SSVpFRCd9KTtcbiAgICB9XG5cbiAgICBjb25zdCByZXFCb2R5ID0gcmVxLmJvZHkgfHwge307XG4gICAgY29uc3QgZGF0YVNvdXJjZUlkID0gcmVxQm9keS5pZDtcbiAgICBpZiAoIWRhdGFTb3VyY2VJZCkge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ01JU1NJTkdfSUQnfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGNtc0NsaWVudCA9IG5ldyBSb290Q01TQ2xpZW50KHJlcS5yb290Q29uZmlnISk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNtc0NsaWVudC5zeW5jRGF0YVNvdXJjZShkYXRhU291cmNlSWQsIHtzeW5jZWRCeTogcmVxLnVzZXIuZW1haWx9KTtcbiAgICAgIHJlcy5zdGF0dXMoMjAwKS5qc29uKHtzdWNjZXNzOiB0cnVlLCBpZDogZGF0YVNvdXJjZUlkfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVyci5zdGFjayB8fCBlcnIpO1xuICAgICAgcmVzLnN0YXR1cyg1MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ1VOS05PV04nfSk7XG4gICAgfVxuICB9KTtcblxuICAvKipcbiAgICogTG9ncyBhbiBhY3Rpb24uXG4gICAqL1xuICBzZXJ2ZXIudXNlKCcvY21zL2FwaS9hY3Rpb25zLmxvZycsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICBpZiAoXG4gICAgICByZXEubWV0aG9kICE9PSAnUE9TVCcgfHxcbiAgICAgICFTdHJpbmcocmVxLmdldCgnY29udGVudC10eXBlJykpLnN0YXJ0c1dpdGgoJ2FwcGxpY2F0aW9uL2pzb24nKVxuICAgICkge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0JBRF9SRVFVRVNUJ30pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghcmVxLnVzZXI/LmVtYWlsKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMSkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5BVVRIT1JJWkVEJ30pO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcUJvZHkgPSByZXEuYm9keSB8fCB7fTtcbiAgICBjb25zdCBhY3Rpb24gPSByZXFCb2R5LmFjdGlvbjtcbiAgICBpZiAoIWFjdGlvbikge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgZXJyb3I6ICdNSVNTSU5HX1JFUVVJUkVEX0ZJRUxEJyxcbiAgICAgICAgZmllbGQ6ICdhY3Rpb24nLFxuICAgICAgfSk7XG4gICAgfVxuICAgIGNvbnN0IG1ldGFkYXRhID0gcmVxQm9keS5tZXRhZGF0YSB8fCB7fTtcblxuICAgIGNvbnN0IGNtc0NsaWVudCA9IG5ldyBSb290Q01TQ2xpZW50KHJlcS5yb290Q29uZmlnISk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNtc0NsaWVudC5sb2dBY3Rpb24oYWN0aW9uLCB7XG4gICAgICAgIGJ5OiByZXEudXNlcj8uZW1haWwsXG4gICAgICAgIG1ldGFkYXRhOiBtZXRhZGF0YSxcbiAgICAgIH0pO1xuICAgICAgcmVzLnN0YXR1cygyMDApLmpzb24oe3N1Y2Nlc3M6IHRydWV9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrIHx8IGVycik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5LTk9XTid9KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBBSSBjaGF0Ym90LlxuICAgKi9cbiAgc2VydmVyLnVzZSgnL2Ntcy9hcGkvYWkuY2hhdCcsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICBpZiAoXG4gICAgICByZXEubWV0aG9kICE9PSAnUE9TVCcgfHxcbiAgICAgICFTdHJpbmcocmVxLmdldCgnY29udGVudC10eXBlJykpLnN0YXJ0c1dpdGgoJ2FwcGxpY2F0aW9uL2pzb24nKVxuICAgICkge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0JBRF9SRVFVRVNUJ30pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoIXJlcS51c2VyPy5lbWFpbCkge1xuICAgICAgcmVzLnN0YXR1cyg0MDEpLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ1VOQVVUSE9SSVpFRCd9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgcmVxQm9keSA9IHJlcS5ib2R5IHx8IHt9O1xuICAgIGlmICghcmVxQm9keS5wcm9tcHQpIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdNSVNTSU5HX1BST01QVCd9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgcHJvbXB0ID0gcmVxQm9keS5wcm9tcHQ7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocmVxLnJvb3RDb25maWchKTtcbiAgICAgIGNvbnN0IGNoYXRDbGllbnQgPSBuZXcgQ2hhdENsaWVudChjbXNDbGllbnQsIHJlcS51c2VyLmVtYWlsKTtcbiAgICAgIGxldCBjaGF0OiBDaGF0O1xuICAgICAgaWYgKHJlcUJvZHkuY2hhdElkKSB7XG4gICAgICAgIGNoYXQgPSBhd2FpdCBjaGF0Q2xpZW50LmdldENoYXQocmVxQm9keS5jaGF0SWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY2hhdCA9IGF3YWl0IGNoYXRDbGllbnQuY3JlYXRlQ2hhdCgpO1xuICAgICAgfVxuICAgICAgY29uc3QgY2hhdFJlc3BvbnNlID0gYXdhaXQgY2hhdC5zZW5kUHJvbXB0KHByb21wdCk7XG4gICAgICByZXNcbiAgICAgICAgLnN0YXR1cygyMDApXG4gICAgICAgIC5qc29uKHtzdWNjZXNzOiB0cnVlLCBjaGF0SWQ6IGNoYXQuaWQsIHJlc3BvbnNlOiBjaGF0UmVzcG9uc2V9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrIHx8IGVycik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5LTk9XTid9KTtcbiAgICB9XG4gIH0pO1xuXG4gIHNlcnZlci51c2UoJy9jbXMvYXBpL2FpLmxpc3RfY2hhdHMnLCBhc3luYyAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgaWYgKFxuICAgICAgcmVxLm1ldGhvZCAhPT0gJ1BPU1QnIHx8XG4gICAgICAhU3RyaW5nKHJlcS5nZXQoJ2NvbnRlbnQtdHlwZScpKS5zdGFydHNXaXRoKCdhcHBsaWNhdGlvbi9qc29uJylcbiAgICApIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdCQURfUkVRVUVTVCd9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCFyZXEudXNlcj8uZW1haWwpIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAxKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTkFVVEhPUklaRUQnfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHJlcUJvZHkgPSByZXEuYm9keSB8fCB7fTtcbiAgICBjb25zdCBsaW1pdCA9IHJlcUJvZHkubGltaXQ7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocmVxLnJvb3RDb25maWchKTtcbiAgICAgIGNvbnN0IGNoYXRDbGllbnQgPSBuZXcgQ2hhdENsaWVudChjbXNDbGllbnQsIHJlcS51c2VyLmVtYWlsKTtcbiAgICAgIGNvbnN0IGNoYXRzID0gYXdhaXQgY2hhdENsaWVudC5saXN0Q2hhdHMoe2xpbWl0fSk7XG4gICAgICByZXMuc3RhdHVzKDIwMCkuanNvbih7c3VjY2VzczogdHJ1ZSwgY2hhdHN9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrIHx8IGVycik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5LTk9XTid9KTtcbiAgICB9XG4gIH0pO1xufVxuIiwgImltcG9ydCBjcnlwdG8gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0IHtnZW5lcmF0ZX0gZnJvbSAnQGdlbmtpdC1haS9haSc7XG5pbXBvcnQge2NvbmZpZ3VyZUdlbmtpdH0gZnJvbSAnQGdlbmtpdC1haS9jb3JlJztcbmltcG9ydCB7dmVydGV4QUl9IGZyb20gJ0BnZW5raXQtYWkvdmVydGV4YWknO1xuaW1wb3J0IHtnZW1pbmkxNVByb1ByZXZpZXcsIGdlbWluaTE1Rmxhc2hQcmV2aWV3fSBmcm9tICdAZ2Vua2l0LWFpL3ZlcnRleGFpJztcbmltcG9ydCB7VGltZXN0YW1wfSBmcm9tICdmaXJlYmFzZS1hZG1pbi9maXJlc3RvcmUnO1xuaW1wb3J0IHtSb290Q01TQ2xpZW50fSBmcm9tICcuL2NsaWVudC5qcyc7XG5pbXBvcnQge0NNU1BsdWdpbk9wdGlvbnN9IGZyb20gJy4vcGx1Z2luLmpzJztcblxubGV0IGdlbmtpdElzQ29uZmlndXJlZCA9IGZhbHNlO1xuXG5pbnRlcmZhY2UgQ2hhdFByb21wdCB7XG4gIHRleHQ/OiBzdHJpbmc7XG4gIG1lZGlhPzoge1xuICAgIHVybDogc3RyaW5nO1xuICAgIGNvbnRlbnRUeXBlOiBzdHJpbmc7XG4gIH07XG59XG5cbmV4cG9ydCBjbGFzcyBDaGF0IHtcbiAgY2hhdENsaWVudDogQ2hhdENsaWVudDtcbiAgY21zQ2xpZW50OiBSb290Q01TQ2xpZW50O1xuICBjbXNQbHVnaW5PcHRpb25zOiBDTVNQbHVnaW5PcHRpb25zO1xuICBpZDogc3RyaW5nO1xuICBoaXN0b3J5PzogYW55O1xuICBtb2RlbD86IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihcbiAgICBjaGF0Q2xpZW50OiBDaGF0Q2xpZW50LFxuICAgIGlkOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHtoaXN0b3J5PzogYW55OyBtb2RlbD86IHN0cmluZ31cbiAgKSB7XG4gICAgdGhpcy5jaGF0Q2xpZW50ID0gY2hhdENsaWVudDtcbiAgICB0aGlzLmNtc0NsaWVudCA9IGNoYXRDbGllbnQuY21zQ2xpZW50O1xuICAgIHRoaXMuY21zUGx1Z2luT3B0aW9ucyA9IHRoaXMuY21zQ2xpZW50LmNtc1BsdWdpbi5nZXRDb25maWcoKTtcbiAgICB0aGlzLmlkID0gaWQ7XG4gICAgdGhpcy5oaXN0b3J5ID0gb3B0aW9ucz8uaGlzdG9yeTtcbiAgICB0aGlzLm1vZGVsID0gb3B0aW9ucz8ubW9kZWw7XG4gICAgaWYgKCF0aGlzLm1vZGVsKSB7XG4gICAgICBpZiAodHlwZW9mIHRoaXMuY21zUGx1Z2luT3B0aW9ucy5leHBlcmltZW50cz8uYWkgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIGlmICh0aGlzLmNtc1BsdWdpbk9wdGlvbnMuZXhwZXJpbWVudHMuYWkubW9kZWwpIHtcbiAgICAgICAgICB0aGlzLm1vZGVsID0gdGhpcy5jbXNQbHVnaW5PcHRpb25zLmV4cGVyaW1lbnRzLmFpLm1vZGVsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgc2VuZFByb21wdChwcm9tcHQ6IHN0cmluZyB8IENoYXRQcm9tcHQgfCBDaGF0UHJvbXB0W10pOiBQcm9taXNlPGFueT4ge1xuICAgIGlmICghZ2Vua2l0SXNDb25maWd1cmVkKSB7XG4gICAgICBjb25zdCBmaXJlYmFzZUNvbmZpZyA9IHRoaXMuY21zUGx1Z2luT3B0aW9ucy5maXJlYmFzZUNvbmZpZztcbiAgICAgIGNvbmZpZ3VyZUdlbmtpdCh7XG4gICAgICAgIHBsdWdpbnM6IFtcbiAgICAgICAgICB2ZXJ0ZXhBSSh7XG4gICAgICAgICAgICBwcm9qZWN0SWQ6IGZpcmViYXNlQ29uZmlnLnByb2plY3RJZCxcbiAgICAgICAgICAgIC8vIFRPRE8oc3RldmVubGUpOiBmaWd1cmUgb3V0IHdoZXJlIHRvIGdldCB0aGlzLlxuICAgICAgICAgICAgbG9jYXRpb246IGZpcmViYXNlQ29uZmlnLmxvY2F0aW9uIHx8ICd1cy1jZW50cmFsMScsXG4gICAgICAgICAgfSksXG4gICAgICAgIF0sXG4gICAgICB9KTtcbiAgICAgIGdlbmtpdElzQ29uZmlndXJlZCA9IHRydWU7XG4gICAgfVxuXG4gICAgbGV0IG1vZGVsID0gZ2VtaW5pMTVGbGFzaFByZXZpZXc7XG4gICAgaWYgKHRoaXMubW9kZWwgPT09ICdnZW1pbmktMS41LXBybycpIHtcbiAgICAgIG1vZGVsID0gZ2VtaW5pMTVQcm9QcmV2aWV3O1xuICAgIH1cblxuICAgIGlmICghdGhpcy5oaXN0b3J5KSB7XG4gICAgICAvLyBTZWVkIHRoZSBBSSB3aXRoIGluZm9ybWF0aW9uLlxuICAgICAgYXdhaXQgdGhpcy5pbml0SGlzdG9yeSgpO1xuICAgIH1cblxuICAgIC8vIGNvbnNvbGUubG9nKCdwcm9tcHQ6JywgcHJvbXB0KTtcbiAgICAvLyBpZiAodGhpcy5oaXN0b3J5KSB7XG4gICAgLy8gICBjb25zb2xlLmxvZygnaGlzdG9yeTonLCB0aGlzLmhpc3RvcnkpO1xuICAgIC8vIH1cbiAgICBjb25zdCByZXMgPSBhd2FpdCBnZW5lcmF0ZSh7XG4gICAgICBtb2RlbDogbW9kZWwsXG4gICAgICBwcm9tcHQ6IHByb21wdCBhcyBhbnksXG4gICAgICBoaXN0b3J5OiB0aGlzLmhpc3RvcnksXG4gICAgfSk7XG4gICAgY29uc29sZS5sb2cocmVzLnRleHQoKSk7XG4gICAgY29uc3QgaGlzdG9yeSA9IHJlcy50b0hpc3RvcnkoKTtcbiAgICB0aGlzLmhpc3RvcnkgPSBoaXN0b3J5O1xuICAgIGF3YWl0IHRoaXMuZGJEb2MoKS51cGRhdGUoe2hpc3RvcnksIG1vZGlmaWVkQXQ6IFRpbWVzdGFtcC5ub3coKX0pO1xuICAgIHJldHVybiByZXMudGV4dCgpO1xuICB9XG5cbiAgZGJEb2MoKSB7XG4gICAgcmV0dXJuIHRoaXMuY2hhdENsaWVudC5kYkNvbGxlY3Rpb24oKS5kb2ModGhpcy5pZCk7XG4gIH1cblxuICBhc3luYyBpbml0SGlzdG9yeSgpIHtcbiAgICBjb25zdCBzeXN0ZW1UZXh0ID0gW1xuICAgICAgYFlvdSBhcmUgYW4gYXNzaXN0YW50IGZvciBhIGhlYWRsZXNzIENNUyBjYWxsZWQgUm9vdCBDTVMgd2hpY2ggaXMgdXNlZCBvbiBhIHdlYnNpdGUgY2FsbGVkICR7XG4gICAgICAgIHRoaXMuY21zUGx1Z2luT3B0aW9ucy5uYW1lIHx8IHRoaXMuY21zUGx1Z2luT3B0aW9ucy5pZFxuICAgICAgfS4gWW91ciBqb2IgaXMgdG8gYW5zd2VyIHF1ZXN0aW9ucyBhYm91dCB0aGUgZG9jcyBpbiB0aGUgc3lzdGVtLCBhbmQgaWYgcmVxdWVzdGVkLCBoZWxwIHN1Z2dlc3QgY2hhbmdlcyB0byB0aGUgSlNPTiBkYXRhIGluIHRoZSBkb2NzLiBJZiB5b3UgZG9uJ3Qga25vdyB0aGUgYW5zd2VyLCBqdXN0IHNheSB0aGF0IHlvdSBkb24ndCBrbm93LCBkb24ndCB0cnkgdG8gbWFrZSB1cCBhbiBhbnN3ZXIuIEJlIGZyaWVuZGx5IGFuZCBwbGF5ZnVsIHdpdGggeW91ciBtZXNzYWdpbmcuYCxcbiAgICAgICcnLFxuICAgICAgJ0hlcmUgaXMgdGhlIHJvb3QuY29uZmlnLnRzIGZpbGUgZm9yIHRoZSBzaXRlOicsXG4gICAgICAnYGBgJyxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHRoaXMuY21zQ2xpZW50LnJvb3RDb25maWcsIG51bGwsIDIpLFxuICAgICAgJ2BgYCcsXG4gICAgICAnJyxcbiAgICAgICdIZXJlIGFyZSB0aGUgZG9jcyB0aGF0IGV4aXN0IGluIHRoZSBzeXN0ZW06JyxcbiAgICBdO1xuXG4gICAgLy8gVE9ETyhzdGV2ZW5sZSk6IHJlYWQgZnJvbSBhbGwgdGhlIGNvbGxlY3Rpb25zIGluIHRoZSBzeXN0ZW0uXG4gICAgY29uc3QgcGFnZXMgPSBhd2FpdCB0aGlzLmNtc0NsaWVudC5saXN0RG9jcygnUGFnZXMnLCB7bW9kZTogJ2RyYWZ0J30pO1xuICAgIHBhZ2VzLmRvY3MuZm9yRWFjaCgoZG9jOiBhbnkpID0+IHtcbiAgICAgIHN5c3RlbVRleHQucHVzaChKU09OLnN0cmluZ2lmeShkb2MpKTtcbiAgICB9KTtcblxuICAgIHRoaXMuaGlzdG9yeSA9IFt7cm9sZTogJ3N5c3RlbScsIGNvbnRlbnQ6IFt7dGV4dDogc3lzdGVtVGV4dC5qb2luKCdcXG4nKX1dfV07XG4gICAgY29uc29sZS5sb2codGhpcy5oaXN0b3J5KTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgQ2hhdENsaWVudCB7XG4gIGNtc0NsaWVudDogUm9vdENNU0NsaWVudDtcbiAgdXNlcjogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKGNtc0NsaWVudDogUm9vdENNU0NsaWVudCwgdXNlcjogc3RyaW5nKSB7XG4gICAgdGhpcy5jbXNDbGllbnQgPSBjbXNDbGllbnQ7XG4gICAgdGhpcy51c2VyID0gdXNlcjtcbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZUNoYXQob3B0aW9ucz86IHttb2RlbD86IHN0cmluZ30pOiBQcm9taXNlPENoYXQ+IHtcbiAgICBjb25zdCBjaGF0SWQgPSBjcnlwdG8ucmFuZG9tVVVJRCgpO1xuICAgIC8vIFNhdmUgY2hhdCB0byBkYiBzbyB0aGF0IHVzZXIgaGFzIGEgY2hhdCBoaXN0b3J5IGFuZCBjYW4gZW5hYmxlIFwic2hhcmluZ1wiXG4gICAgLy8gd2l0aCBvdGhlcnMuIFN0b3JlIHRoZSBtb2RlbCB1c2VkIHdpdGggdGhlIG1ldGFkYXRhLlxuICAgIGNvbnN0IGRvY1JlZiA9IHRoaXMuZGJDb2xsZWN0aW9uKCkuZG9jKGNoYXRJZCk7XG4gICAgYXdhaXQgZG9jUmVmLnNldCh7XG4gICAgICBpZDogY2hhdElkLFxuICAgICAgY3JlYXRlZEJ5OiB0aGlzLnVzZXIsXG4gICAgICBjcmVhdGVkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgIG1vZGlmaWVkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgIG1vZGVsOiBvcHRpb25zPy5tb2RlbCB8fCAnZ2VtaW5pLTEuNS1mbGFzaCcsXG4gICAgfSk7XG4gICAgcmV0dXJuIG5ldyBDaGF0KHRoaXMsIGNoYXRJZCk7XG4gIH1cblxuICBhc3luYyBnZXRDaGF0KGNoYXRJZDogc3RyaW5nKTogUHJvbWlzZTxDaGF0PiB7XG4gICAgLy8gRmV0Y2ggY2hhdCBmcm9tIGRiIHRvIHByZXNlcnZlIHRoZSBjb252ZXJzYXRpb24ncyBoaXN0b3J5LlxuICAgIGNvbnN0IGRvY1JlZiA9IHRoaXMuZGJDb2xsZWN0aW9uKCkuZG9jKGNoYXRJZCk7XG4gICAgY29uc3QgY2hhdERvYyA9IGF3YWl0IGRvY1JlZi5nZXQoKTtcbiAgICBpZiAoIWNoYXREb2MuZXhpc3RzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7Y2hhdElkfSBkb2VzIG5vdCBleGlzdGApO1xuICAgIH1cbiAgICBjb25zdCBjaGF0RGF0YSA9IGNoYXREb2MuZGF0YSgpIHx8IHt9O1xuICAgIHJldHVybiBuZXcgQ2hhdCh0aGlzLCBjaGF0SWQsIHtcbiAgICAgIGhpc3Rvcnk6IGNoYXREYXRhLmhpc3RvcnksXG4gICAgICBtb2RlbDogY2hhdERhdGEubW9kZWwsXG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBsaXN0Q2hhdHMob3B0aW9ucz86IHtsaW1pdD86IG51bWJlcn0pOiBQcm9taXNlPGFueVtdPiB7XG4gICAgY29uc3QgbGltaXQgPSBvcHRpb25zPy5saW1pdCB8fCAyMDtcbiAgICBjb25zdCBxdWVyeSA9IHRoaXMuZGJDb2xsZWN0aW9uKClcbiAgICAgIC53aGVyZSgnY3JlYXRlZEJ5JywgJz09JywgdGhpcy51c2VyKVxuICAgICAgLmxpbWl0KGxpbWl0KVxuICAgICAgLm9yZGVyQnkoJ2NyZWF0ZWRBdCcsICdkZXNjJyk7XG4gICAgY29uc3QgcmVzID0gYXdhaXQgcXVlcnkuZ2V0KCk7XG4gICAgcmV0dXJuIHJlcy5kb2NzLm1hcCgoZG9jKSA9PiBkb2MuZGF0YSgpKTtcbiAgfVxuXG4gIGRiQ29sbGVjdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5jbXNDbGllbnQuZGIuY29sbGVjdGlvbihcbiAgICAgIGBQcm9qZWN0cy8ke3RoaXMuY21zQ2xpZW50LnByb2plY3RJZH0vRXhwZXJpbWVudHMvYWkvQ2hhdGBcbiAgICApO1xuICB9XG59XG4iLCAiaW1wb3J0IGNyeXB0byBmcm9tICdub2RlOmNyeXB0byc7XG5pbXBvcnQgdHlwZSB7Um9vdENvbmZpZ30gZnJvbSAnQGJsaW5ray9yb290JztcbmltcG9ydCB7QXBwfSBmcm9tICdmaXJlYmFzZS1hZG1pbi9hcHAnO1xuaW1wb3J0IHtcbiAgRmllbGRWYWx1ZSxcbiAgRmlyZXN0b3JlLFxuICBRdWVyeSxcbiAgVGltZXN0YW1wLFxuICBXcml0ZUJhdGNoLFxufSBmcm9tICdmaXJlYmFzZS1hZG1pbi9maXJlc3RvcmUnO1xuaW1wb3J0IHtDTVNQbHVnaW4sIGdldENtc1BsdWdpbn0gZnJvbSAnLi9wbHVnaW4uanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIERvYzxGaWVsZHMgPSBhbnk+IHtcbiAgLyoqIFRoZSBpZCBvZiB0aGUgZG9jLCBlLmcuIFwiUGFnZXMvZm9vLWJhclwiLiAqL1xuICBpZDogc3RyaW5nO1xuICAvKiogVGhlIGNvbGxlY3Rpb24gaWQgb2YgdGhlIGRvYywgZS5nLiBcIlBhZ2VzXCIuICovXG4gIGNvbGxlY3Rpb246IHN0cmluZztcbiAgLyoqIFRoZSBzbHVnIG9mIHRoZSBkb2MsIGUuZy4gXCJmb28tYmFyXCIuICovXG4gIHNsdWc6IHN0cmluZztcbiAgc3lzOiB7XG4gICAgY3JlYXRlZEF0OiBudW1iZXI7XG4gICAgY3JlYXRlZEJ5OiBzdHJpbmc7XG4gICAgbW9kaWZpZWRBdDogbnVtYmVyO1xuICAgIG1vZGlmaWVkQnk6IHN0cmluZztcbiAgICBmaXJzdFB1Ymxpc2hlZEF0PzogbnVtYmVyO1xuICAgIGZpcnN0UHVibGlzaGVkQnk/OiBzdHJpbmc7XG4gICAgcHVibGlzaGVkQXQ/OiBudW1iZXI7XG4gICAgcHVibGlzaGVkQnk/OiBzdHJpbmc7XG4gICAgcHVibGlzaGluZ0xvY2tlZDoge1xuICAgICAgbG9ja2VkQXQ6IHN0cmluZztcbiAgICAgIGxvY2tlZEJ5OiBzdHJpbmc7XG4gICAgICByZWFzb246IHN0cmluZztcbiAgICAgIHVudGlsPzogVGltZXN0YW1wO1xuICAgIH07XG4gICAgbG9jYWxlcz86IHN0cmluZ1tdO1xuICB9O1xuICBmaWVsZHM6IEZpZWxkcztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUcmFuc2xhdGlvbnNEb2Mge1xuICBpZDogc3RyaW5nO1xuICBzeXM6IHtcbiAgICBtb2RpZmllZEF0OiBUaW1lc3RhbXA7XG4gICAgbW9kaWZpZWRCeTogc3RyaW5nO1xuICAgIHB1Ymxpc2hlZEF0PzogVGltZXN0YW1wO1xuICAgIHB1Ymxpc2hlZEJ5Pzogc3RyaW5nO1xuICAgIGxpbmtlZFNoZWV0Pzoge1xuICAgICAgc3ByZWFkc2hlZXRJZDogc3RyaW5nO1xuICAgICAgZ2lkOiBudW1iZXI7XG4gICAgICBsaW5rZWRBdDogVGltZXN0YW1wO1xuICAgICAgbGlua2VkQnk6IHN0cmluZztcbiAgICB9O1xuICAgIHRhZ3M/OiBzdHJpbmdbXTtcbiAgfTtcbiAgc3RyaW5nczogVHJhbnNsYXRpb25zTWFwO1xufVxuXG5leHBvcnQgdHlwZSBEb2NNb2RlID0gJ2RyYWZ0JyB8ICdwdWJsaXNoZWQnO1xuXG5leHBvcnQgdHlwZSBVc2VyUm9sZSA9ICdBRE1JTicgfCAnRURJVE9SJyB8ICdWSUVXRVInO1xuXG5leHBvcnQgdHlwZSBIdHRwTWV0aG9kID0gJ0dFVCcgfCAnUE9TVCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGF0YVNvdXJjZSB7XG4gIGlkOiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICB0eXBlOiAnaHR0cCcgfCAnZ3NoZWV0JztcbiAgdXJsOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBDdXJyZW50bHkgb25seSB1c2VkIGJ5IGdzaGVldC4gYGFycmF5YCByZXR1cm5zIHRoZSBzaGVldCBhcyBhbiBhcnJheSBvZlxuICAgKiBhcnJheXMsIGBtYXBgIHJldHVybnMgdGhlIHNoZWV0IGFzIGFuIGFycmF5IG9mIG9iamVjdHMuXG4gICAqL1xuICBkYXRhRm9ybWF0PzogJ2FycmF5JyB8ICdtYXAnO1xuICAvKipcbiAgICogT3B0aW9ucyBmb3IgSFRUUCByZXF1ZXN0cy5cbiAgICovXG4gIGh0dHBPcHRpb25zPzoge1xuICAgIG1ldGhvZDogSHR0cE1ldGhvZDtcbiAgICBoZWFkZXJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgICBib2R5Pzogc3RyaW5nO1xuICB9O1xuICBjcmVhdGVkQXQ6IFRpbWVzdGFtcDtcbiAgY3JlYXRlZEJ5OiBzdHJpbmc7XG4gIHN5bmNlZEF0PzogVGltZXN0YW1wO1xuICBzeW5jZWRCeT86IHN0cmluZztcbiAgcHVibGlzaGVkQXQ/OiBUaW1lc3RhbXA7XG4gIHB1Ymxpc2hlZEJ5Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERhdGFTb3VyY2VEYXRhPFQgPSBhbnk+IHtcbiAgZGF0YVNvdXJjZTogRGF0YVNvdXJjZTtcbiAgZGF0YTogVDtcbn1cblxuZXhwb3J0IHR5cGUgRGF0YVNvdXJjZU1vZGUgPSAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2V0RG9jT3B0aW9ucyB7XG4gIC8qKiBNb2RlLCBlaXRoZXIgXCJkcmFmdFwiIG9yIFwicHVibGlzaGVkXCIuICovXG4gIG1vZGU6IERvY01vZGU7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2V0RG9jT3B0aW9ucyB7XG4gIC8qKiBNb2RlLCBlaXRoZXIgXCJkcmFmdFwiIG9yIFwicHVibGlzaGVkXCIuICovXG4gIG1vZGU6IERvY01vZGU7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2F2ZURyYWZ0T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBMb2NhbGVzIHRvIGVuYWJsZS5cbiAgICovXG4gIGxvY2FsZXM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogRW1haWwgb2YgdXNlciBtb2RpZnlpbmcgdGhlIGRvYy4gSWYgYmxhbmssIGRlZmF1bHRzIHRvIGByb290LWNtcy1jbGllbnRgLlxuICAgKi9cbiAgbW9kaWZpZWRCeT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBMaXN0RG9jc09wdGlvbnMge1xuICBtb2RlOiBEb2NNb2RlO1xuICBvZmZzZXQ/OiBudW1iZXI7XG4gIGxpbWl0PzogbnVtYmVyO1xuICBvcmRlckJ5Pzogc3RyaW5nO1xuICBvcmRlckJ5RGlyZWN0aW9uPzogJ2FzYycgfCAnZGVzYyc7XG4gIHF1ZXJ5PzogKHF1ZXJ5OiBRdWVyeSkgPT4gUXVlcnk7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGZldGNoIHRoZSBcInJhd1wiIHZlcnNpb24gb2YgdGhlIGRvYyAoZm9yIHVzZSBpbiBjb25qdW5jdGlvbiB3aXRoXG4gICAqIGBzZXRSYXdEb2MoKWApLlxuICAgKi9cbiAgcmF3PzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHZXRDb3VudE9wdGlvbnMge1xuICBtb2RlOiBEb2NNb2RlO1xuICBxdWVyeT86IChxdWVyeTogUXVlcnkpID0+IFF1ZXJ5O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zbGF0aW9uIHtcbiAgW2xvY2FsZTogc3RyaW5nXTogc3RyaW5nO1xuICBzb3VyY2U6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUcmFuc2xhdGlvbnNNYXAge1xuICBbaGFzaDogc3RyaW5nXTogVHJhbnNsYXRpb247XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9jYWxlVHJhbnNsYXRpb25zIHtcbiAgW3NvdXJjZTogc3RyaW5nXTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExvYWRUcmFuc2xhdGlvbnNPcHRpb25zIHtcbiAgdGFncz86IHN0cmluZ1tdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlbGVhc2Uge1xuICBpZDogc3RyaW5nO1xuICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgZG9jSWRzPzogc3RyaW5nW107XG4gIGNyZWF0ZWRBdD86IFRpbWVzdGFtcDtcbiAgY3JlYXRlZEJ5Pzogc3RyaW5nO1xuICBzY2hlZHVsZWRBdD86IFRpbWVzdGFtcDtcbiAgc2NoZWR1bGVkQnk/OiBzdHJpbmc7XG4gIHB1Ymxpc2hlZEF0PzogVGltZXN0YW1wO1xuICBwdWJsaXNoZWRCeT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBY3Rpb248VCA9IGFueT4ge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGFjdGlvbi5cbiAgICovXG4gIGFjdGlvbjogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIHVzZXIncyBlbWFpbCB0aGF0IHBlcmZvcm1lZCB0aGUgYWN0aW9uIChvciBcInN5c3RlbVwiKS5cbiAgICovXG4gIGJ5Pzogc3RyaW5nO1xuICAvKipcbiAgICogVGltZXN0YW1wIHdoZW4gdGhlIGFjdGlvbiBvY2N1cnJlZC5cbiAgICovXG4gIHRpbWVzdGFtcDogVGltZXN0YW1wO1xuICAvKipcbiAgICogTWV0YWRhdGEgZm9yIHRoZSBhY3Rpb24uXG4gICAqL1xuICBtZXRhZGF0YT86IFQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGlzdEFjdGlvbnNPcHRpb25zIHtcbiAgLyoqXG4gICAqIEZpbHRlciBieSBhIHNwZWNpZmljIGFjdGlvbi4gRGVmYXVsdHMgdG8gYWxsIGFjdGlvbnMuXG4gICAqL1xuICBhY3Rpb24/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBGaWx0ZXIgYnkgYSBzcGVjaWZpYyB1c2VyLiBEZWZhdWx0cyB0byBhbGwgdXNlcnMuXG4gICAqL1xuICBieT86IHN0cmluZztcbiAgLyoqXG4gICAqIE1heCBudW1iZXIgb2YgYWN0aW9ucyB0byByZXR1cm4uIERlZmF1bHRzIHRvIDEwMC5cbiAgICovXG4gIGxpbWl0PzogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgUm9vdENNU0NsaWVudCB7XG4gIHJlYWRvbmx5IHJvb3RDb25maWc6IFJvb3RDb25maWc7XG4gIHJlYWRvbmx5IGNtc1BsdWdpbjogQ01TUGx1Z2luO1xuICByZWFkb25seSBwcm9qZWN0SWQ6IHN0cmluZztcbiAgcmVhZG9ubHkgYXBwOiBBcHA7XG4gIHJlYWRvbmx5IGRiOiBGaXJlc3RvcmU7XG5cbiAgY29uc3RydWN0b3Iocm9vdENvbmZpZzogUm9vdENvbmZpZykge1xuICAgIHRoaXMucm9vdENvbmZpZyA9IHJvb3RDb25maWc7XG4gICAgdGhpcy5jbXNQbHVnaW4gPSBnZXRDbXNQbHVnaW4odGhpcy5yb290Q29uZmlnKTtcblxuICAgIGNvbnN0IGNtc1BsdWdpbk9wdGlvbnMgPSB0aGlzLmNtc1BsdWdpbi5nZXRDb25maWcoKTtcbiAgICB0aGlzLnByb2plY3RJZCA9IGNtc1BsdWdpbk9wdGlvbnMuaWQgfHwgJ2RlZmF1bHQnO1xuICAgIHRoaXMuYXBwID0gdGhpcy5jbXNQbHVnaW4uZ2V0RmlyZWJhc2VBcHAoKTtcbiAgICB0aGlzLmRiID0gdGhpcy5jbXNQbHVnaW4uZ2V0RmlyZXN0b3JlKCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGRvYyBkYXRhIGZyb20gUm9vdC5qcyBDTVMuXG4gICAqL1xuICBhc3luYyBnZXREb2M8RmllbGRzID0gYW55PihcbiAgICBjb2xsZWN0aW9uSWQ6IHN0cmluZyxcbiAgICBzbHVnOiBzdHJpbmcsXG4gICAgb3B0aW9uczogR2V0RG9jT3B0aW9uc1xuICApOiBQcm9taXNlPERvYzxGaWVsZHM+IHwgbnVsbD4ge1xuICAgIGNvbnN0IHJhd0RhdGEgPSBhd2FpdCB0aGlzLmdldFJhd0RvYyhjb2xsZWN0aW9uSWQsIHNsdWcsIG9wdGlvbnMpO1xuICAgIGlmIChyYXdEYXRhKSB7XG4gICAgICByZXR1cm4gdW5tYXJzaGFsRGF0YShyYXdEYXRhKSBhcyBEb2M8RmllbGRzPjtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHJhdyBkb2MgZGF0YSBhcyBzdG9yZWQgaW4gdGhlIGRhdGFiYXNlLiBPbmx5IHVzZSB0aGlzIGlmIHlvdSBrbm93XG4gICAqIHdoYXQgeW91IGFyZSBkb2luZy5cbiAgICovXG4gIGFzeW5jIGdldFJhd0RvYyhcbiAgICBjb2xsZWN0aW9uSWQ6IHN0cmluZyxcbiAgICBzbHVnOiBzdHJpbmcsXG4gICAgb3B0aW9uczogR2V0RG9jT3B0aW9uc1xuICApOiBQcm9taXNlPGFueSB8IG51bGw+IHtcbiAgICBjb25zdCBtb2RlID0gb3B0aW9ucy5tb2RlO1xuICAgIGNvbnN0IGRvY1JlZiA9IHRoaXMuZGJEb2NSZWYoY29sbGVjdGlvbklkLCBzbHVnLCB7bW9kZX0pO1xuICAgIGNvbnN0IGRvYyA9IGF3YWl0IGRvY1JlZi5nZXQoKTtcbiAgICBpZiAoZG9jLmV4aXN0cykge1xuICAgICAgcmV0dXJuIGRvYy5kYXRhKCk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZGJDb2xsZWN0aW9uRG9jc1BhdGgoXG4gICAgY29sbGVjdGlvbklkOiBzdHJpbmcsXG4gICAgb3B0aW9uczoge21vZGU6ICdkcmFmdCcgfCAncHVibGlzaGVkJ31cbiAgKSB7XG4gICAgbGV0IG1vZGVDb2xsZWN0aW9uID0gJyc7XG4gICAgaWYgKG9wdGlvbnMubW9kZSA9PT0gJ2RyYWZ0Jykge1xuICAgICAgbW9kZUNvbGxlY3Rpb24gPSAnRHJhZnRzJztcbiAgICB9IGVsc2UgaWYgKG9wdGlvbnMubW9kZSA9PT0gJ3B1Ymxpc2hlZCcpIHtcbiAgICAgIG1vZGVDb2xsZWN0aW9uID0gJ1B1Ymxpc2hlZCc7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdW5rbm93biBtb2RlOiAke29wdGlvbnMubW9kZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9Db2xsZWN0aW9ucy8ke2NvbGxlY3Rpb25JZH0vJHttb2RlQ29sbGVjdGlvbn1gO1xuICB9XG5cbiAgZGJEb2NQYXRoKFxuICAgIGNvbGxlY3Rpb25JZDogc3RyaW5nLFxuICAgIHNsdWc6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7bW9kZTogJ2RyYWZ0JyB8ICdwdWJsaXNoZWQnfVxuICApIHtcbiAgICBjb25zdCBjb2xsZWN0aW9uRG9jc1BhdGggPSB0aGlzLmRiQ29sbGVjdGlvbkRvY3NQYXRoKGNvbGxlY3Rpb25JZCwgb3B0aW9ucyk7XG4gICAgLy8gU2x1Z3Mgd2l0aCBzbGFzaGVzIGFyZSBlbmNvZGVkIGFzIGAtLWAgaW4gdGhlIERCLlxuICAgIGNvbnN0IG5vcm1hbGl6ZWRTbHVnID0gc2x1Zy5yZXBsYWNlQWxsKCcvJywgJy0tJyk7XG4gICAgcmV0dXJuIGAke2NvbGxlY3Rpb25Eb2NzUGF0aH0vJHtub3JtYWxpemVkU2x1Z31gO1xuICB9XG5cbiAgZGJEb2NSZWYoXG4gICAgY29sbGVjdGlvbklkOiBzdHJpbmcsXG4gICAgc2x1Zzogc3RyaW5nLFxuICAgIG9wdGlvbnM6IHttb2RlOiAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCd9XG4gICkge1xuICAgIGNvbnN0IGRvY1BhdGggPSB0aGlzLmRiRG9jUGF0aChjb2xsZWN0aW9uSWQsIHNsdWcsIG9wdGlvbnMpO1xuICAgIHJldHVybiB0aGlzLmRiLmRvYyhkb2NQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYXZlcyBkcmFmdCBkYXRhIHRvIGEgZG9jLlxuICAgKlxuICAgKiBOb3RlOiB0aGlzIHNhdmVzIGRhdGEgdG8gdGhlIFwiZmllbGRzXCIgYXR0ciBvZiB0aGUgZHJhZnQgZG9jLiBJZiB5b3UgbmVlZCB0b1xuICAgKiBtb2RpZnkgdGhlIHN5cy1sZXZlbCBhdHRyaWJ1dGVzIG9mIHRoZSBkb2MsIHVzZSBgc2V0UmF3RG9jKClgLlxuICAgKi9cbiAgYXN5bmMgc2F2ZURyYWZ0RGF0YShcbiAgICBkb2NJZDogc3RyaW5nLFxuICAgIGZpZWxkc0RhdGE6IGFueSxcbiAgICBvcHRpb25zPzogU2F2ZURyYWZ0T3B0aW9uc1xuICApIHtcbiAgICBjb25zdCB7Y29sbGVjdGlvbiwgc2x1Z30gPSBwYXJzZURvY0lkKGRvY0lkKTtcbiAgICBjb25zdCBkcmFmdERvYyA9XG4gICAgICAoYXdhaXQgdGhpcy5nZXRSYXdEb2MoY29sbGVjdGlvbiwgc2x1Zywge21vZGU6ICdkcmFmdCd9KSkgfHwge307XG4gICAgY29uc3QgZHJhZnRTeXMgPSBkcmFmdERvYy5zeXMgfHwge307XG4gICAgY29uc3QgbW9kaWZpZWRCeSA9IG9wdGlvbnM/Lm1vZGlmaWVkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCc7XG4gICAgY29uc3QgZmllbGRzID0gbWFyc2hhbERhdGEoZmllbGRzRGF0YSB8fCB7fSk7XG4gICAgY29uc3QgZGF0YSA9IHtcbiAgICAgIGlkOiBkb2NJZCxcbiAgICAgIGNvbGxlY3Rpb24sXG4gICAgICBzbHVnLFxuICAgICAgc3lzOiB7XG4gICAgICAgIC4uLmRyYWZ0U3lzLFxuICAgICAgICBjcmVhdGVkQXQ6IGRyYWZ0U3lzLmNyZWF0ZWRBdCA/PyBUaW1lc3RhbXAubm93KCksXG4gICAgICAgIGNyZWF0ZWRCeTogZHJhZnRTeXMuY3JlYXRlZEJ5ID8/IG1vZGlmaWVkQnksXG4gICAgICAgIG1vZGlmaWVkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgICAgbW9kaWZpZWRCeSxcbiAgICAgICAgbG9jYWxlczogb3B0aW9ucz8ubG9jYWxlcyA/PyBkcmFmdFN5cy5sb2NhbGVzID8/IFsnZW4nXSxcbiAgICAgIH0sXG4gICAgICBmaWVsZHMsXG4gICAgfTtcbiAgICBhd2FpdCB0aGlzLnNldFJhd0RvYyhjb2xsZWN0aW9uLCBzbHVnLCBkYXRhLCB7bW9kZTogJ2RyYWZ0J30pO1xuICB9XG5cbiAgLyoqXG4gICAqIFByZWZlciBgc2F2ZURyYWZ0RGF0YSgnUGFnZXMvZm9vJywgZGF0YSlgLiBPbmx5IHVzZSB0aGlzIGlmIHlvdSBrbm93IHdoYXRcbiAgICogeW91J3JlIGRvaW5nLlxuICAgKi9cbiAgYXN5bmMgc2V0UmF3RG9jKFxuICAgIGNvbGxlY3Rpb25JZDogc3RyaW5nLFxuICAgIHNsdWc6IHN0cmluZyxcbiAgICBkYXRhOiBhbnksXG4gICAgb3B0aW9uczogU2V0RG9jT3B0aW9uc1xuICApIHtcbiAgICBjb25zdCBtb2RlID0gb3B0aW9ucy5tb2RlO1xuICAgIGNvbnN0IG1vZGVDb2xsZWN0aW9uID0gbW9kZSA9PT0gJ2RyYWZ0JyA/ICdEcmFmdHMnIDogJ1B1Ymxpc2hlZCc7XG4gICAgY29uc3QgZGJQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0NvbGxlY3Rpb25zLyR7Y29sbGVjdGlvbklkfS8ke21vZGVDb2xsZWN0aW9ufS8ke3NsdWd9YDtcbiAgICBjb25zdCBkb2NSZWYgPSB0aGlzLmRiLmRvYyhkYlBhdGgpO1xuICAgIGF3YWl0IGRvY1JlZi5zZXQoZGF0YSk7XG4gIH1cblxuICAvKipcbiAgICogTGlzdHMgZG9jcyBmcm9tIGEgUm9vdC5qcyBDTVMgY29sbGVjdGlvbi5cbiAgICovXG4gIGFzeW5jIGxpc3REb2NzPFQ+KFxuICAgIGNvbGxlY3Rpb25JZDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IExpc3REb2NzT3B0aW9uc1xuICApOiBQcm9taXNlPHtkb2NzOiBUW119PiB7XG4gICAgY29uc3QgbW9kZSA9IG9wdGlvbnMubW9kZTtcbiAgICBjb25zdCBtb2RlQ29sbGVjdGlvbiA9IG1vZGUgPT09ICdkcmFmdCcgPyAnRHJhZnRzJyA6ICdQdWJsaXNoZWQnO1xuICAgIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9Db2xsZWN0aW9ucy8ke2NvbGxlY3Rpb25JZH0vJHttb2RlQ29sbGVjdGlvbn1gO1xuICAgIGxldCBxdWVyeTogUXVlcnkgPSB0aGlzLmRiLmNvbGxlY3Rpb24oZGJQYXRoKTtcbiAgICBpZiAob3B0aW9ucy5saW1pdCkge1xuICAgICAgcXVlcnkgPSBxdWVyeS5saW1pdChvcHRpb25zLmxpbWl0KTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMub2Zmc2V0KSB7XG4gICAgICBxdWVyeSA9IHF1ZXJ5Lm9mZnNldChvcHRpb25zLm9mZnNldCk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLm9yZGVyQnkpIHtcbiAgICAgIHF1ZXJ5ID0gcXVlcnkub3JkZXJCeShvcHRpb25zLm9yZGVyQnksIG9wdGlvbnMub3JkZXJCeURpcmVjdGlvbik7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLnF1ZXJ5KSB7XG4gICAgICBxdWVyeSA9IG9wdGlvbnMucXVlcnkocXVlcnkpO1xuICAgIH1cbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgcXVlcnkuZ2V0KCk7XG4gICAgY29uc3QgZG9jczogVFtdID0gW107XG4gICAgcmVzdWx0cy5mb3JFYWNoKChyZXN1bHQpID0+IHtcbiAgICAgIGlmIChvcHRpb25zLnJhdykge1xuICAgICAgICAvLyBGb3IgY2FsbGVycyB0aGF0IHdpc2ggdG8gbW9kaWZ5IHRoZSByYXcgZG9jIHZpYSBgc2V0UmF3RG9jKClgLFxuICAgICAgICAvLyByZXR1cm4gdGhlIHVubW9kaWZpZWQgZG9jIGFzIHJldHVybmVkIGZyb20gZmlyZXN0b3JlLlxuICAgICAgICBjb25zdCByYXdEb2MgPSByZXN1bHQuZGF0YSgpIGFzIFQ7XG4gICAgICAgIGRvY3MucHVzaChyYXdEb2MpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgZG9jID0gdW5tYXJzaGFsRGF0YShyZXN1bHQuZGF0YSgpKSBhcyBUO1xuICAgICAgICBkb2NzLnB1c2goZG9jKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4ge2RvY3N9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIG51bWJlciBvZiBkb2NzIGluIGEgUm9vdC5qcyBDTVMgY29sbGVjdGlvbi5cbiAgICovXG4gIGFzeW5jIGdldERvY3NDb3VudChjb2xsZWN0aW9uSWQ6IHN0cmluZywgb3B0aW9uczogR2V0Q291bnRPcHRpb25zKSB7XG4gICAgY29uc3QgbW9kZSA9IG9wdGlvbnMubW9kZTtcbiAgICBjb25zdCBtb2RlQ29sbGVjdGlvbiA9IG1vZGUgPT09ICdkcmFmdCcgPyAnRHJhZnRzJyA6ICdQdWJsaXNoZWQnO1xuICAgIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9Db2xsZWN0aW9ucy8ke2NvbGxlY3Rpb25JZH0vJHttb2RlQ29sbGVjdGlvbn1gO1xuICAgIGxldCBxdWVyeTogUXVlcnkgPSB0aGlzLmRiLmNvbGxlY3Rpb24oZGJQYXRoKTtcbiAgICBpZiAob3B0aW9ucy5xdWVyeSkge1xuICAgICAgcXVlcnkgPSBvcHRpb25zLnF1ZXJ5KHF1ZXJ5KTtcbiAgICB9XG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHF1ZXJ5LmNvdW50KCkuZ2V0KCk7XG4gICAgY29uc3QgY291bnQgPSByZXN1bHRzLmRhdGEoKS5jb3VudDtcbiAgICByZXR1cm4gY291bnQ7XG4gIH1cblxuICAvKipcbiAgICogQmF0Y2ggcHVibGlzaGVzIGEgc2V0IG9mIGRvY3MgYnkgaWQuXG4gICAqL1xuICBhc3luYyBwdWJsaXNoRG9jcyhcbiAgICBkb2NJZHM6IHN0cmluZ1tdLFxuICAgIG9wdGlvbnM/OiB7cHVibGlzaGVkQnk6IHN0cmluZzsgYmF0Y2g/OiBXcml0ZUJhdGNofVxuICApIHtcbiAgICBjb25zdCBwcm9qZWN0Q29sbGVjdGlvbnNQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0NvbGxlY3Rpb25zYDtcbiAgICBjb25zdCBwdWJsaXNoZWRCeSA9IG9wdGlvbnM/LnB1Ymxpc2hlZEJ5IHx8ICdyb290LWNtcy1jbGllbnQnO1xuXG4gICAgLy8gRmV0Y2ggdGhlIGN1cnJlbnQgZHJhZnQgZGF0YSBmb3IgZWFjaCBkb2MuXG4gICAgY29uc3QgZG9jUmVmcyA9IGRvY0lkcy5tYXAoKGRvY0lkKSA9PiB7XG4gICAgICBjb25zdCBbY29sbGVjdGlvbiwgc2x1Z10gPSBkb2NJZC5zcGxpdCgnLycpO1xuICAgICAgaWYgKCFjb2xsZWN0aW9uIHx8ICFzbHVnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBkb2MgaWQ6ICR7ZG9jSWR9YCk7XG4gICAgICB9XG4gICAgICBjb25zdCBkb2NSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgICAgYCR7cHJvamVjdENvbGxlY3Rpb25zUGF0aH0vJHtjb2xsZWN0aW9ufS9EcmFmdHMvJHtzbHVnfWBcbiAgICAgICk7XG4gICAgICByZXR1cm4gZG9jUmVmO1xuICAgIH0pO1xuICAgIGNvbnN0IGRvY1NuYXBzaG90cyA9IGF3YWl0IHRoaXMuZGIuZ2V0QWxsKC4uLmRvY1JlZnMpO1xuICAgIGNvbnN0IGRvY3MgPSBkb2NTbmFwc2hvdHNcbiAgICAgIC8vIFJldHJpZXZlIHNuYXBzaG90IGRhdGEgZm9yIGVhY2ggZG9jLlxuICAgICAgLm1hcCgoc25hcHNob3QpID0+IHNuYXBzaG90LmRhdGEoKSBhcyBEb2MpXG4gICAgICAvLyBSZW1vdmUgZG9jcyB0aGF0IGRvbid0IGV4aXN0LlxuICAgICAgLmZpbHRlcigoZCkgPT4gISFkKTtcblxuICAgIGlmIChkb2NzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgY29uc29sZS5sb2coJ25vIGRvY3MgdG8gcHVibGlzaCcpO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIC8vIFZlcmlmeSB0aGVyZSBhcmUgbm8gcHVibGlzaGluZyBsb2NrcyBvbiBhbnkgZG9jcy5cbiAgICBmb3IgKGNvbnN0IGRvYyBvZiBkb2NzKSB7XG4gICAgICBpZiAodGhpcy50ZXN0UHVibGlzaGluZ0xvY2tlZChkb2MpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgcHVibGlzaGluZyBpcyBsb2NrZWQgZm9yIGRvYzogJHtkb2MuaWR9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gLy8gRWFjaCB0cmFuc2FjdGlvbiBvciBiYXRjaCBjYW4gd3JpdGUgYSBtYXggb2YgNTAwIG9wcy5cbiAgICAvLyAvLyBodHRwczovL2ZpcmViYXNlLmdvb2dsZS5jb20vZG9jcy9maXJlc3RvcmUvbWFuYWdlLWRhdGEvdHJhbnNhY3Rpb25zXG4gICAgbGV0IGJhdGNoQ291bnQgPSAwO1xuICAgIGNvbnN0IGJhdGNoID0gb3B0aW9ucz8uYmF0Y2ggfHwgdGhpcy5kYi5iYXRjaCgpO1xuICAgIGNvbnN0IHB1Ymxpc2hlZERvY3M6IGFueVtdID0gW107XG4gICAgZm9yIChjb25zdCBkb2Mgb2YgZG9jcykge1xuICAgICAgY29uc3Qge2lkLCBjb2xsZWN0aW9uLCBzbHVnLCBzeXMsIGZpZWxkc30gPSBkb2M7XG4gICAgICBjb25zdCBkcmFmdFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgICBgJHtwcm9qZWN0Q29sbGVjdGlvbnNQYXRofS8ke2NvbGxlY3Rpb259L0RyYWZ0cy8ke3NsdWd9YFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHNjaGVkdWxlZFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgICBgJHtwcm9qZWN0Q29sbGVjdGlvbnNQYXRofS8ke2NvbGxlY3Rpb259L1NjaGVkdWxlZC8ke3NsdWd9YFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHB1Ymxpc2hlZFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgICBgJHtwcm9qZWN0Q29sbGVjdGlvbnNQYXRofS8ke2NvbGxlY3Rpb259L1B1Ymxpc2hlZC8ke3NsdWd9YFxuICAgICAgKTtcblxuICAgICAgLy8gT25seSB1cGRhdGUgYGZpcnN0UHVibGlzaGVkYCBpZiBpdCBkb2Vzbid0IGFscmVhZHkgZXhpc3QuXG4gICAgICBjb25zdCBmaXJzdFB1Ymxpc2hlZEF0ID1cbiAgICAgICAgc3lzLmZpcnN0UHVibGlzaGVkQXQgPz8gRmllbGRWYWx1ZS5zZXJ2ZXJUaW1lc3RhbXAoKTtcbiAgICAgIGNvbnN0IGZpcnN0UHVibGlzaGVkQnkgPSBzeXMuZmlyc3RQdWJsaXNoZWRCeSA/PyBwdWJsaXNoZWRCeTtcblxuICAgICAgLy8gU2F2ZSBwdWJsaXNoZWQgZG9jLlxuICAgICAgYmF0Y2guc2V0KHB1Ymxpc2hlZFJlZiwge1xuICAgICAgICBpZCxcbiAgICAgICAgY29sbGVjdGlvbixcbiAgICAgICAgc2x1ZyxcbiAgICAgICAgZmllbGRzOiBmaWVsZHMgfHwge30sXG4gICAgICAgIHN5czoge1xuICAgICAgICAgIC4uLnN5cyxcbiAgICAgICAgICBmaXJzdFB1Ymxpc2hlZEF0OiBmaXJzdFB1Ymxpc2hlZEF0LFxuICAgICAgICAgIGZpcnN0UHVibGlzaGVkQnk6IGZpcnN0UHVibGlzaGVkQnksXG4gICAgICAgICAgcHVibGlzaGVkQXQ6IEZpZWxkVmFsdWUuc2VydmVyVGltZXN0YW1wKCksXG4gICAgICAgICAgcHVibGlzaGVkQnk6IHB1Ymxpc2hlZEJ5LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBiYXRjaENvdW50ICs9IDE7XG5cbiAgICAgIC8vIFJlbW92ZSBzY2hlZHVsZWQgZG9jLCBpZiBhbnkuXG4gICAgICBiYXRjaC5kZWxldGUoc2NoZWR1bGVkUmVmKTtcbiAgICAgIGJhdGNoQ291bnQgKz0gMTtcblxuICAgICAgLy8gVXBkYXRlIHRoZSBkcmFmdCBkb2MgdG8gcmVtb3ZlIGBzY2hlZHVsZWRBdGAgYW5kIGBzY2hlZHVsZWRCeWAgZmllbGRzXG4gICAgICAvLyBhbmQgdXBkYXRlIHRoZSBgcHVibGlzaGVkQXRgIGFuZCBgcHVibGlzaGVkQnlgIGZpZWxkcy5cbiAgICAgIGJhdGNoLnVwZGF0ZShkcmFmdFJlZiwge1xuICAgICAgICAnc3lzLnNjaGVkdWxlZEF0JzogRmllbGRWYWx1ZS5kZWxldGUoKSxcbiAgICAgICAgJ3N5cy5zY2hlZHVsZWRCeSc6IEZpZWxkVmFsdWUuZGVsZXRlKCksXG4gICAgICAgICdzeXMuZmlyc3RQdWJsaXNoZWRBdCc6IGZpcnN0UHVibGlzaGVkQXQsXG4gICAgICAgICdzeXMuZmlyc3RQdWJsaXNoZWRCeSc6IGZpcnN0UHVibGlzaGVkQnksXG4gICAgICAgICdzeXMucHVibGlzaGVkQXQnOiBGaWVsZFZhbHVlLnNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICAnc3lzLnB1Ymxpc2hlZEJ5JzogcHVibGlzaGVkQnksXG4gICAgICB9KTtcbiAgICAgIGJhdGNoQ291bnQgKz0gMTtcblxuICAgICAgdGhpcy5wdWJsaXNoVHJhbnNsYXRpb25zRG9jKGRvYy5pZCwge2JhdGNofSk7XG4gICAgICBiYXRjaENvdW50ICs9IDI7XG5cbiAgICAgIHB1Ymxpc2hlZERvY3MucHVzaChkb2MpO1xuXG4gICAgICBpZiAoYmF0Y2hDb3VudCA+PSA0MDApIHtcbiAgICAgICAgYXdhaXQgYmF0Y2guY29tbWl0KCk7XG4gICAgICAgIGJhdGNoQ291bnQgPSAwO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChiYXRjaENvdW50ID4gMCkge1xuICAgICAgYXdhaXQgYmF0Y2guY29tbWl0KCk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGBwdWJsaXNoZWQgJHtwdWJsaXNoZWREb2NzLmxlbmd0aH0gZG9jcyFgKTtcbiAgICByZXR1cm4gcHVibGlzaGVkRG9jcztcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoZXMgc2NoZWR1bGVkIGRvY3MuXG4gICAqL1xuICBhc3luYyBwdWJsaXNoU2NoZWR1bGVkRG9jcygpIHtcbiAgICBjb25zdCBwcm9qZWN0Q29sbGVjdGlvbnNQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0NvbGxlY3Rpb25zYDtcbiAgICBjb25zdCBub3cgPSBNYXRoLmNlaWwobmV3IERhdGUoKS5nZXRUaW1lKCkpO1xuXG4gICAgY29uc3Qgc25hcHNob3QgPSBhd2FpdCB0aGlzLmRiLmNvbGxlY3Rpb25Hcm91cCgnU2NoZWR1bGVkJykuZ2V0KCk7XG4gICAgY29uc3QgZG9jcyA9IHNuYXBzaG90LmRvY3NcbiAgICAgIC5maWx0ZXIoKGQpID0+IHtcbiAgICAgICAgLy8gRmlsdGVyIGRvY3MgYnkgcHJvamVjdC5cbiAgICAgICAgaWYgKCFkLnJlZi5wYXRoLnN0YXJ0c1dpdGgocHJvamVjdENvbGxlY3Rpb25zUGF0aCkpIHtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gRmlsdGVyIGRvY3Mgd2hlcmUgc2NoZWR1bGVkQXQgaXMgaW4gdGhlIHBhc3QuXG4gICAgICAgIC8vIE5PVEUoc3RldmVubGUpOiB0aGUgZmlsdGVyaW5nIGlzIGRvbmUgbWFudWFsbHkgaW5zdGVhZCBvZiB1c2luZyBhIHF1ZXJ5XG4gICAgICAgIC8vIHRvIGF2b2lkIGhhdmluZyB0byBjcmVhdGUgYW4gaW5kZXggaW4gZmlyZXN0b3JlLlxuICAgICAgICBjb25zdCBkYXRhID0gZC5kYXRhKCkgfHwge307XG4gICAgICAgIGNvbnN0IHNjaGVkdWxlZEF0OiBUaW1lc3RhbXAgfCB1bmRlZmluZWQgPSBkYXRhLnN5cz8uc2NoZWR1bGVkQXQ7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgc2NoZWR1bGVkQXQgJiYgc2NoZWR1bGVkQXQudG9NaWxsaXMgJiYgc2NoZWR1bGVkQXQudG9NaWxsaXMoKSA8PSBub3dcbiAgICAgICAgKTtcbiAgICAgIH0pXG4gICAgICAubWFwKChkKSA9PiB7XG4gICAgICAgIGNvbnN0IGRiUGF0aCA9IGQucmVmLnBhdGg7XG4gICAgICAgIGNvbnN0IHNlZ21lbnRzID0gZGJQYXRoLnNwbGl0KCcvJyk7XG4gICAgICAgIGNvbnN0IHNsdWcgPSBzZWdtZW50cy5hdCgtMSk7XG4gICAgICAgIGNvbnN0IGNvbGxlY3Rpb24gPSBzZWdtZW50cy5hdCgtMyk7XG4gICAgICAgIGNvbnN0IGlkID0gYCR7Y29sbGVjdGlvbn0vJHtzbHVnfWA7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZGF0YTogZC5kYXRhKCksXG4gICAgICAgICAgaWQsXG4gICAgICAgICAgY29sbGVjdGlvbixcbiAgICAgICAgICBzbHVnLFxuICAgICAgICB9O1xuICAgICAgfSk7XG5cbiAgICBpZiAoZG9jcy5sZW5ndGggPT09IDApIHtcbiAgICAgIGNvbnNvbGUubG9nKCdubyBkb2NzIHRvIHNjaGVkdWxlJyk7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgLy8gRWFjaCB0cmFuc2FjdGlvbiBvciBiYXRjaCBjYW4gd3JpdGUgYSBtYXggb2YgNTAwIG9wcy5cbiAgICAvLyBodHRwczovL2ZpcmViYXNlLmdvb2dsZS5jb20vZG9jcy9maXJlc3RvcmUvbWFuYWdlLWRhdGEvdHJhbnNhY3Rpb25zXG4gICAgbGV0IGJhdGNoQ291bnQgPSAwO1xuICAgIGNvbnN0IGJhdGNoID0gdGhpcy5kYi5iYXRjaCgpO1xuICAgIGNvbnN0IHB1Ymxpc2hlZERvY3M6IGFueVtdID0gW107XG4gICAgZm9yIChjb25zdCBkb2Mgb2YgZG9jcykge1xuICAgICAgY29uc3Qge2lkLCBjb2xsZWN0aW9uLCBzbHVnLCBkYXRhfSA9IGRvYztcbiAgICAgIGNvbnN0IGRyYWZ0UmVmID0gdGhpcy5kYi5kb2MoXG4gICAgICAgIGAke3Byb2plY3RDb2xsZWN0aW9uc1BhdGh9LyR7Y29sbGVjdGlvbn0vRHJhZnRzLyR7c2x1Z31gXG4gICAgICApO1xuICAgICAgY29uc3Qgc2NoZWR1bGVkUmVmID0gdGhpcy5kYi5kb2MoXG4gICAgICAgIGAke3Byb2plY3RDb2xsZWN0aW9uc1BhdGh9LyR7Y29sbGVjdGlvbn0vU2NoZWR1bGVkLyR7c2x1Z31gXG4gICAgICApO1xuICAgICAgY29uc3QgcHVibGlzaGVkUmVmID0gdGhpcy5kYi5kb2MoXG4gICAgICAgIGAke3Byb2plY3RDb2xsZWN0aW9uc1BhdGh9LyR7Y29sbGVjdGlvbn0vUHVibGlzaGVkLyR7c2x1Z31gXG4gICAgICApO1xuICAgICAgY29uc3Qge3NjaGVkdWxlZEF0LCBzY2hlZHVsZWRCeSwgLi4uc3lzfSA9IGRhdGEuc3lzIHx8IHt9O1xuXG4gICAgICAvLyBPbmx5IHVwZGF0ZSBgZmlyc3RQdWJsaXNoZWRgIGlmIGl0IGRvZXNuJ3QgYWxyZWFkeSBleGlzdC5cbiAgICAgIGNvbnN0IGZpcnN0UHVibGlzaGVkQXQgPSBzeXMuZmlyc3RQdWJsaXNoZWRBdCA/PyBzY2hlZHVsZWRBdDtcbiAgICAgIGNvbnN0IGZpcnN0UHVibGlzaGVkQnkgPVxuICAgICAgICBzeXMuZmlyc3RQdWJsaXNoZWRCeSA/PyAoc2NoZWR1bGVkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCcpO1xuXG4gICAgICAvLyBTYXZlIHB1Ymxpc2hlZCBkb2MuXG4gICAgICBiYXRjaC5zZXQocHVibGlzaGVkUmVmLCB7XG4gICAgICAgIGlkLFxuICAgICAgICBjb2xsZWN0aW9uLFxuICAgICAgICBzbHVnLFxuICAgICAgICBmaWVsZHM6IGRhdGEuZmllbGRzIHx8IHt9LFxuICAgICAgICBzeXM6IHtcbiAgICAgICAgICAuLi5zeXMsXG4gICAgICAgICAgZmlyc3RQdWJsaXNoZWRBdDogZmlyc3RQdWJsaXNoZWRBdCxcbiAgICAgICAgICBmaXJzdFB1Ymxpc2hlZEJ5OiBmaXJzdFB1Ymxpc2hlZEJ5LFxuICAgICAgICAgIHB1Ymxpc2hlZEF0OiBGaWVsZFZhbHVlLnNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICAgIHB1Ymxpc2hlZEJ5OiBzY2hlZHVsZWRCeSB8fCAnJyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgYmF0Y2hDb3VudCArPSAxO1xuXG4gICAgICAvLyBSZW1vdmUgcHVibGlzaGVkIGRvYy5cbiAgICAgIGJhdGNoLmRlbGV0ZShzY2hlZHVsZWRSZWYpO1xuICAgICAgYmF0Y2hDb3VudCArPSAxO1xuXG4gICAgICAvLyBVcGRhdGUgdGhlIGRyYWZ0IGRvYyB0byByZW1vdmUgYHNjaGVkdWxlZEF0YCBhbmQgYHNjaGVkdWxlZEJ5YCBmaWVsZHNcbiAgICAgIC8vIGFuZCB1cGRhdGUgdGhlIGBwdWJsaXNoZWRBdGAgYW5kIGBwdWJsaXNoZWRCeWAgZmllbGRzLlxuICAgICAgYmF0Y2gudXBkYXRlKGRyYWZ0UmVmLCB7XG4gICAgICAgICdzeXMuc2NoZWR1bGVkQXQnOiBGaWVsZFZhbHVlLmRlbGV0ZSgpLFxuICAgICAgICAnc3lzLnNjaGVkdWxlZEJ5JzogRmllbGRWYWx1ZS5kZWxldGUoKSxcbiAgICAgICAgJ3N5cy5maXJzdFB1Ymxpc2hlZEF0JzogZmlyc3RQdWJsaXNoZWRBdCxcbiAgICAgICAgJ3N5cy5maXJzdFB1Ymxpc2hlZEJ5JzogZmlyc3RQdWJsaXNoZWRCeSxcbiAgICAgICAgJ3N5cy5wdWJsaXNoZWRBdCc6IEZpZWxkVmFsdWUuc2VydmVyVGltZXN0YW1wKCksXG4gICAgICAgICdzeXMucHVibGlzaGVkQnknOiBzY2hlZHVsZWRCeSB8fCAncm9vdC1jbXMtY2xpZW50JyxcbiAgICAgIH0pO1xuICAgICAgYmF0Y2hDb3VudCArPSAxO1xuXG4gICAgICB0aGlzLnB1Ymxpc2hUcmFuc2xhdGlvbnNEb2MoZG9jLmlkLCB7YmF0Y2h9KTtcbiAgICAgIGJhdGNoQ291bnQgKz0gMjtcblxuICAgICAgcHVibGlzaGVkRG9jcy5wdXNoKGRvYyk7XG5cbiAgICAgIGlmIChiYXRjaENvdW50ID49IDQwMCkge1xuICAgICAgICBhd2FpdCBiYXRjaC5jb21taXQoKTtcbiAgICAgICAgYmF0Y2hDb3VudCA9IDA7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChiYXRjaENvdW50ID4gMCkge1xuICAgICAgYXdhaXQgYmF0Y2guY29tbWl0KCk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGBwdWJsaXNoZWQgJHtwdWJsaXNoZWREb2NzLmxlbmd0aH0gZG9jcyFgKTtcbiAgICByZXR1cm4gcHVibGlzaGVkRG9jcztcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoZXMgZG9jcyBpbiBzY2hlZHVsZWQgcmVsZWFzZXMuXG4gICAqL1xuICBhc3luYyBwdWJsaXNoU2NoZWR1bGVkUmVsZWFzZXMoKSB7XG4gICAgY29uc3QgcmVsZWFzZXNQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L1JlbGVhc2VzYDtcbiAgICBjb25zdCBub3cgPSBNYXRoLmNlaWwobmV3IERhdGUoKS5nZXRUaW1lKCkpO1xuICAgIGNvbnN0IHF1ZXJ5OiBRdWVyeSA9IHRoaXMuZGJcbiAgICAgIC5jb2xsZWN0aW9uKHJlbGVhc2VzUGF0aClcbiAgICAgIC53aGVyZSgnc2NoZWR1bGVkQXQnLCAnPD0nLCBUaW1lc3RhbXAuZnJvbU1pbGxpcyhub3cpKTtcbiAgICBjb25zdCBxdWVyeVNuYXBzaG90ID0gYXdhaXQgcXVlcnkuZ2V0KCk7XG5cbiAgICBmb3IgKGNvbnN0IHNuYXBzaG90IG9mIHF1ZXJ5U25hcHNob3QuZG9jcykge1xuICAgICAgY29uc3QgcmVsZWFzZSA9IHNuYXBzaG90LmRhdGEoKSBhcyBSZWxlYXNlO1xuICAgICAgY29uc3QgYmF0Y2ggPSB0aGlzLmRiLmJhdGNoKCk7XG4gICAgICBjb25zdCBwdWJsaXNoZWRCeSA9IHJlbGVhc2Uuc2NoZWR1bGVkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCc7XG4gICAgICBiYXRjaC51cGRhdGUoc25hcHNob3QucmVmLCB7XG4gICAgICAgIHB1Ymxpc2hlZEF0OiBUaW1lc3RhbXAubm93KCksXG4gICAgICAgIHB1Ymxpc2hlZEJ5OiBwdWJsaXNoZWRCeSxcbiAgICAgICAgc2NoZWR1bGVkQXQ6IEZpZWxkVmFsdWUuZGVsZXRlKCksXG4gICAgICAgIHNjaGVkdWxlZEJ5OiBGaWVsZFZhbHVlLmRlbGV0ZSgpLFxuICAgICAgfSk7XG4gICAgICBhd2FpdCB0aGlzLnB1Ymxpc2hEb2NzKHJlbGVhc2UuZG9jSWRzIHx8IFtdLCB7cHVibGlzaGVkQnksIGJhdGNofSk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcHVibGlzaFRyYW5zbGF0aW9uc0RvYyhcbiAgICB0cmFuc2xhdGlvbnNJZDogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7YmF0Y2g/OiBXcml0ZUJhdGNoOyBwdWJsaXNoZWRCeT86IHN0cmluZ31cbiAgKSB7XG4gICAgY29uc3QgZG9jU2x1ZyA9IHRyYW5zbGF0aW9uc0lkLnJlcGxhY2VBbGwoJy8nLCAnLS0nKTtcbiAgICBjb25zdCBkcmFmdFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L1RyYW5zbGF0aW9uc01hbmFnZXIvZHJhZnQvVHJhbnNsYXRpb25zLyR7ZG9jU2x1Z31gXG4gICAgKTtcbiAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGRyYWZ0UmVmLmdldCgpO1xuXG4gICAgaWYgKCFzbmFwc2hvdC5leGlzdHMpIHtcbiAgICAgIC8vIElnbm9yZSBtaXNzaW5nIHRyYW5zbGF0aW9ucy5cbiAgICAgIGNvbnNvbGUud2FybihgdHJhbnNsYXRpb25zICR7dHJhbnNsYXRpb25zSWR9IGRvZXMgbm90IGV4aXN0YCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSWYgdGhlIHRyYW5zbGF0aW9ucyBwdWJsaXNoaW5nIGlzIHRpZWQgdG8gYW5vdGhlciBiYXRjaCByZXF1ZXN0IChlLmcuIGRvY1xuICAgIC8vIHB1Ymxpc2hpbmcpLCB0aGUgYmF0Y2ggcmVxdWVzdCB3aWxsIGJlIGNvbW1pdHRlZCB1cHN0cmVhbS5cbiAgICBjb25zdCBjb21taXRCYXRjaCA9ICFvcHRpb25zPy5iYXRjaDtcblxuICAgIGNvbnN0IGJhdGNoID0gb3B0aW9ucz8uYmF0Y2ggfHwgdGhpcy5kYi5iYXRjaCgpO1xuICAgIGJhdGNoLnVwZGF0ZShkcmFmdFJlZiwge1xuICAgICAgJ3N5cy5wdWJsaXNoZWRBdCc6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgICdzeXMucHVibGlzaGVkQnknOiBvcHRpb25zPy5wdWJsaXNoZWRCeSB8fCAncm9vdC1jbXMtY2xpZW50JyxcbiAgICB9KTtcblxuICAgIGNvbnN0IHB1Ymxpc2hlZFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L1RyYW5zbGF0aW9uc01hbmFnZXIvcHVibGlzaGVkL1RyYW5zbGF0aW9ucy8ke2RvY1NsdWd9YFxuICAgICk7XG4gICAgY29uc3QgZGF0YSA9IHsuLi5zbmFwc2hvdC5kYXRhKCl9O1xuICAgIGlmICghZGF0YS5zeXMpIHtcbiAgICAgIGRhdGEuc3lzID0ge307XG4gICAgfVxuICAgIGRhdGEuc3lzLnB1Ymxpc2hlZEF0ID0gVGltZXN0YW1wLm5vdygpO1xuICAgIGRhdGEuc3lzLnB1Ymxpc2hlZEJ5ID0gb3B0aW9ucz8ucHVibGlzaGVkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCc7XG4gICAgYmF0Y2guc2V0KHB1Ymxpc2hlZFJlZiwgZGF0YSk7XG4gICAgaWYgKGNvbW1pdEJhdGNoKSB7XG4gICAgICBhd2FpdCBiYXRjaC5jb21taXQoKTtcbiAgICAgIHRoaXMubG9nQWN0aW9uKCd0cmFuc2xhdGlvbnMucHVibGlzaCcsIHttZXRhZGF0YToge3RyYW5zbGF0aW9uc0lkfX0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYSBkb2MgaXMgY3VycmVudGx5IFwibG9ja2VkXCIgZm9yIHB1Ymxpc2hpbmcuXG4gICAqL1xuICB0ZXN0UHVibGlzaGluZ0xvY2tlZChkb2M6IERvYykge1xuICAgIGlmIChkb2Muc3lzPy5wdWJsaXNoaW5nTG9ja2VkKSB7XG4gICAgICBpZiAoZG9jLnN5cy5wdWJsaXNoaW5nTG9ja2VkLnVudGlsKSB7XG4gICAgICAgIGNvbnN0IG5vdyA9IFRpbWVzdGFtcC5ub3coKS50b01pbGxpcygpO1xuICAgICAgICBjb25zdCB1bnRpbCA9IGRvYy5zeXMucHVibGlzaGluZ0xvY2tlZC51bnRpbC50b01pbGxpcygpO1xuICAgICAgICByZXR1cm4gbm93IDwgdW50aWw7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWRzIGFsbCBwdWJsaXNoZWQgc3RyaW5ncyBpbiB0aGUgZGIuXG4gICAqXG4gICAqIGBgYFxuICAgKiB7XG4gICAqICAgXCI8aGFzaD5cIjoge1wic291cmNlXCI6IFwiSGVsbG9cIiwgXCJlc1wiOiBcIkhvbGFcIiwgXCJmclwiOiBcIkJvbmpvdXJcIn0sXG4gICAqIH1cbiAgICogYGBgXG4gICAqXG4gICAqIEBkZXByZWNhdGVkIFVzZSBgY3JlYXRlQmF0Y2hSZXF1ZXN0KClgIHRvIGZldGNoIGRyYWZ0L3B1Ymxpc2hlZCB0cmFuc2xhdGlvbnMuXG4gICAqL1xuICBhc3luYyBsb2FkVHJhbnNsYXRpb25zKFxuICAgIG9wdGlvbnM/OiBMb2FkVHJhbnNsYXRpb25zT3B0aW9uc1xuICApOiBQcm9taXNlPFRyYW5zbGF0aW9uc01hcD4ge1xuICAgIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9UcmFuc2xhdGlvbnNNYW5hZ2VyL3B1Ymxpc2hlZC9UcmFuc2xhdGlvbnNgO1xuICAgIGNvbnN0IHRyYW5zbGF0aW9uc01hcDogVHJhbnNsYXRpb25zTWFwID0ge307XG5cbiAgICBjb25zdCBhZGRUcmFuc2xhdGlvbnMgPSAoaGFzaDogc3RyaW5nLCB0cmFuc2xhdGlvbnM6IFRyYW5zbGF0aW9uKSA9PiB7XG4gICAgICB0cmFuc2xhdGlvbnNNYXBbaGFzaF0gPSBPYmplY3QuYXNzaWduKFxuICAgICAgICB0cmFuc2xhdGlvbnNNYXBbaGFzaF0gfHwge30sXG4gICAgICAgIHRyYW5zbGF0aW9uc1xuICAgICAgKTtcbiAgICB9O1xuXG4gICAgbGV0IHF1ZXJ5OiBRdWVyeSA9IHRoaXMuZGIuY29sbGVjdGlvbihkYlBhdGgpO1xuICAgIGlmIChvcHRpb25zPy50YWdzICYmIG9wdGlvbnMudGFncy5sZW5ndGggPiAwKSB7XG4gICAgICBxdWVyeSA9IHF1ZXJ5LndoZXJlKCdzeXMudGFncycsICdhcnJheS1jb250YWlucy1hbnknLCBvcHRpb25zLnRhZ3MpO1xuICAgIH1cbiAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IHF1ZXJ5LmdldCgpO1xuICAgIHNuYXBzaG90LmZvckVhY2goKGRvYykgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGRvYy5kYXRhKCk7XG4gICAgICBjb25zdCBzdHJpbmdzID0gKGRhdGEuc3RyaW5ncyB8fCB7fSkgYXMgUmVjb3JkPHN0cmluZywgVHJhbnNsYXRpb24+O1xuICAgICAgT2JqZWN0LmVudHJpZXMoc3RyaW5ncykuZm9yRWFjaCgoW2hhc2gsIHRyYW5zbGF0aW9uc10pID0+IHtcbiAgICAgICAgYWRkVHJhbnNsYXRpb25zKGhhc2gsIHRyYW5zbGF0aW9ucyk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHJldHVybiB0cmFuc2xhdGlvbnNNYXA7XG4gIH1cblxuICBhc3luYyBzYXZlRHJhZnRUcmFuc2xhdGlvbnMoXG4gICAgdHJhbnNsYXRpb25zSWQ6IHN0cmluZyxcbiAgICB0cmFuc2xhdGlvbnM6IHtbc291cmNlOiBzdHJpbmddOiB7W2xvY2FsZTogc3RyaW5nXTogc3RyaW5nfX0sXG4gICAgb3B0aW9ucz86IHttb2RpZmllZGJ5Pzogc3RyaW5nfVxuICApIHtcbiAgICBjb25zdCBkb2NTbHVnID0gdHJhbnNsYXRpb25zSWQucmVwbGFjZUFsbCgnLycsICctLScpO1xuICAgIGNvbnN0IGRvY1BhdGggPSBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vVHJhbnNsYXRpb25zTWFuYWdlci9kcmFmdC8ke2RvY1NsdWd9YDtcbiAgICBjb25zdCBkb2NSZWYgPSB0aGlzLmRiLmRvYyhkb2NQYXRoKTtcblxuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZG9jUmVmLmdldCgpO1xuICAgIGNvbnN0IGRhdGEgPSBzbmFwc2hvdC5kYXRhKCkgfHwge1xuICAgICAgaWQ6IHRyYW5zbGF0aW9uc0lkLnJlcGxhY2VBbGwoJy0tJywgJy8nKSxcbiAgICAgIHN5czoge30sXG4gICAgICBzdHJpbmdzOiB7fSxcbiAgICB9O1xuICAgIGRhdGEuc3lzLm1vZGlmaWVkQXQgPSBUaW1lc3RhbXAubm93KCk7XG4gICAgZGF0YS5zeXMubW9kaWZpZWRCeSA9IG9wdGlvbnM/Lm1vZGlmaWVkYnkgfHwgJ3Jvb3QtY21zLWNsaWVudCc7XG5cbiAgICBjb25zdCBzdHJpbmdzID0gZGF0YS5zdHJpbmdzIHx8IHt9O1xuICAgIE9iamVjdC5lbnRyaWVzKHRyYW5zbGF0aW9ucykuZm9yRWFjaCgoW3NvdXJjZSwgcm93XSkgPT4ge1xuICAgICAgY29uc3Qgbm9ybWFsaXplZFNvdXJjZSA9IHRoaXMubm9ybWFsaXplU3RyaW5nKHNvdXJjZSk7XG4gICAgICBjb25zdCBoYXNoID0gdGhpcy5nZXRUcmFuc2xhdGlvbktleShub3JtYWxpemVkU291cmNlKTtcbiAgICAgIHN0cmluZ3NbaGFzaF0gPSB7Li4uc3RyaW5nc1toYXNoXSwgLi4ucm93LCBzb3VyY2U6IG5vcm1hbGl6ZWRTb3VyY2V9O1xuICAgIH0pO1xuICAgIGRhdGEuc3RyaW5ncyA9IHN0cmluZ3M7XG4gICAgYXdhaXQgZG9jUmVmLnNldChkYXRhKTtcbiAgICB0aGlzLmxvZ0FjdGlvbigndHJhbnNsYXRpb25zLnNhdmUnLCB7bWV0YWRhdGE6IHt0cmFuc2xhdGlvbnNJZH19KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBcImtleVwiIHVzZWQgZm9yIGEgdHJhbnNsYXRpb24gYXMgc3RvcmVkIGluIHRoZSBkYi4gVHJhbnNsYXRpb25zXG4gICAqIGFyZSBzdG9yZWQgdW5kZXIgYFByb2plY3RzLzxwcm9qZWN0IGlkPi9UcmFuc2xhdGlvbnMvPHNoYTEgaGFzaD5gLlxuICAgKi9cbiAgZ2V0VHJhbnNsYXRpb25LZXkoc291cmNlOiBzdHJpbmcpIHtcbiAgICBjb25zdCBzaGExID0gY3J5cHRvXG4gICAgICAuY3JlYXRlSGFzaCgnc2hhMScpXG4gICAgICAudXBkYXRlKHRoaXMubm9ybWFsaXplU3RyaW5nKHNvdXJjZSkpXG4gICAgICAuZGlnZXN0KCdoZXgnKTtcbiAgICByZXR1cm4gc2hhMTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhbnMgYSBzdHJpbmcgdGhhdCdzIHVzZWQgZm9yIHRyYW5zbGF0aW9ucy4gUGVyZm9ybXMgdGhlIGZvbGxvd2luZzpcbiAgICogLSBSZW1vdmVzIGFueSBsZWFkaW5nL3RyYWlsaW5nIHdoaXRlc3BhY2VcbiAgICogLSBSZW1vdmVzIHNwYWNlcyBhdCB0aGUgZW5kIG9mIGFueSBsaW5lXG4gICAqL1xuICBub3JtYWxpemVTdHJpbmcoc3RyOiBzdHJpbmcpIHtcbiAgICBjb25zdCBsaW5lcyA9IFN0cmluZyhzdHIpXG4gICAgICAudHJpbSgpXG4gICAgICAuc3BsaXQoJ1xcbicpXG4gICAgICAubWFwKChsaW5lKSA9PiBsaW5lLnRyaW1FbmQoKSk7XG4gICAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWRzIHRyYW5zbGF0aW9ucyBmb3IgYSBwYXJ0aWN1bGFyIGxvY2FsZS5cbiAgICpcbiAgICogUmV0dXJucyBhIG1hcCBsaWtlOlxuICAgKiBgYGBcbiAgICoge1xuICAgKiAgIFwiSGVsbG9cIjogXCJCb25qb3VyXCIsXG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBsb2FkVHJhbnNsYXRpb25zRm9yTG9jYWxlKFxuICAgIGxvY2FsZTogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiBMb2FkVHJhbnNsYXRpb25zT3B0aW9uc1xuICApOiBQcm9taXNlPExvY2FsZVRyYW5zbGF0aW9ucz4ge1xuICAgIGNvbnN0IHRyYW5zbGF0aW9uc01hcCA9IGF3YWl0IHRoaXMubG9hZFRyYW5zbGF0aW9ucyhvcHRpb25zKTtcbiAgICByZXR1cm4gdHJhbnNsYXRpb25zRm9yTG9jYWxlKHRyYW5zbGF0aW9uc01hcCwgbG9jYWxlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgZGF0YSBzb3VyY2UgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gICAqL1xuICBhc3luYyBnZXREYXRhU291cmNlKGRhdGFTb3VyY2VJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgZGJQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0RhdGFTb3VyY2VzLyR7ZGF0YVNvdXJjZUlkfWA7XG4gICAgY29uc3QgZG9jUmVmID0gdGhpcy5kYi5kb2MoZGJQYXRoKTtcbiAgICBjb25zdCBkb2MgPSBhd2FpdCBkb2NSZWYuZ2V0KCk7XG4gICAgaWYgKGRvYy5leGlzdHMpIHtcbiAgICAgIHJldHVybiBkb2MuZGF0YSgpIGFzIERhdGFTb3VyY2U7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFN5bmNzIGEgZGF0YSBzb3VyY2UgdG8gZHJhZnQgc3RhdGUuXG4gICAqL1xuICBhc3luYyBzeW5jRGF0YVNvdXJjZShkYXRhU291cmNlSWQ6IHN0cmluZywgb3B0aW9ucz86IHtzeW5jZWRCeT86IHN0cmluZ30pIHtcbiAgICBjb25zdCBkYXRhU291cmNlID0gYXdhaXQgdGhpcy5nZXREYXRhU291cmNlKGRhdGFTb3VyY2VJZCk7XG4gICAgaWYgKCFkYXRhU291cmNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGRhdGEgc291cmNlIG5vdCBmb3VuZDogJHtkYXRhU291cmNlSWR9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YSA9IGF3YWl0IHRoaXMuZmV0Y2hEYXRhKGRhdGFTb3VyY2UpO1xuXG4gICAgY29uc3QgZGF0YVNvdXJjZURvY1JlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0RhdGFTb3VyY2VzLyR7ZGF0YVNvdXJjZUlkfWBcbiAgICApO1xuICAgIGNvbnN0IGRhdGFEb2NSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgIGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9EYXRhU291cmNlcy8ke2RhdGFTb3VyY2VJZH0vRGF0YS9kcmFmdGBcbiAgICApO1xuICAgIGNvbnN0IHN5bmNlZEJ5ID0gb3B0aW9ucz8uc3luY2VkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCc7XG5cbiAgICBjb25zdCB1cGRhdGVkRGF0YVNvdXJjZTogRGF0YVNvdXJjZSA9IHtcbiAgICAgIC4uLmRhdGFTb3VyY2UsXG4gICAgICBzeW5jZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgc3luY2VkQnk6IHN5bmNlZEJ5LFxuICAgIH07XG5cbiAgICBjb25zdCBiYXRjaCA9IHRoaXMuZGIuYmF0Y2goKTtcbiAgICBiYXRjaC5zZXQoZGF0YURvY1JlZiwge1xuICAgICAgZGF0YVNvdXJjZTogdXBkYXRlZERhdGFTb3VyY2UsXG4gICAgICBkYXRhOiBkYXRhLFxuICAgIH0pO1xuICAgIGJhdGNoLnVwZGF0ZShkYXRhU291cmNlRG9jUmVmLCB7XG4gICAgICBzeW5jZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgc3luY2VkQnk6IHN5bmNlZEJ5LFxuICAgIH0pO1xuICAgIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuXG4gICAgY29uc29sZS5sb2coYHN5bmNlZCBkYXRhIHNvdXJjZTogJHtkYXRhU291cmNlSWR9YCk7XG4gICAgY29uc29sZS5sb2coYHN5bmNlZCBieTogJHtzeW5jZWRCeX1gKTtcbiAgfVxuXG4gIGFzeW5jIHB1Ymxpc2hEYXRhU291cmNlKFxuICAgIGRhdGFTb3VyY2VJZDogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7cHVibGlzaGVkQnk/OiBzdHJpbmd9XG4gICkge1xuICAgIGNvbnN0IGRhdGFTb3VyY2UgPSBhd2FpdCB0aGlzLmdldERhdGFTb3VyY2UoZGF0YVNvdXJjZUlkKTtcbiAgICBpZiAoIWRhdGFTb3VyY2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgZGF0YSBzb3VyY2Ugbm90IGZvdW5kOiAke2RhdGFTb3VyY2VJZH1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBkYXRhU291cmNlRG9jUmVmID0gdGhpcy5kYi5kb2MoXG4gICAgICBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vRGF0YVNvdXJjZXMvJHtkYXRhU291cmNlSWR9YFxuICAgICk7XG4gICAgY29uc3QgZGF0YURvY1JlZkRyYWZ0ID0gdGhpcy5kYi5kb2MoXG4gICAgICBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vRGF0YVNvdXJjZXMvJHtkYXRhU291cmNlSWR9L2RyYWZ0YFxuICAgICk7XG4gICAgY29uc3QgZGF0YURvY1JlZlB1Ymxpc2hlZCA9IHRoaXMuZGIuZG9jKFxuICAgICAgYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0RhdGFTb3VyY2VzLyR7ZGF0YVNvdXJjZUlkfS9wdWJsaXNoZWRgXG4gICAgKTtcblxuICAgIGNvbnN0IGRhdGFSZXMgPSBhd2FpdCB0aGlzLmdldEZyb21EYXRhU291cmNlKGRhdGFTb3VyY2VJZCwge21vZGU6ICdkcmFmdCd9KTtcblxuICAgIGNvbnN0IHB1Ymxpc2hlZEJ5ID0gb3B0aW9ucz8ucHVibGlzaGVkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCc7XG5cbiAgICBjb25zdCB1cGRhdGVkRGF0YVNvdXJjZTogRGF0YVNvdXJjZSA9IHtcbiAgICAgIC4uLmRhdGFTb3VyY2UsXG4gICAgICBwdWJsaXNoZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgcHVibGlzaGVkQnk6IHB1Ymxpc2hlZEJ5LFxuICAgIH07XG5cbiAgICBjb25zdCBiYXRjaCA9IHRoaXMuZGIuYmF0Y2goKTtcbiAgICBiYXRjaC5zZXQoZGF0YURvY1JlZlB1Ymxpc2hlZCwge1xuICAgICAgZGF0YVNvdXJjZTogdXBkYXRlZERhdGFTb3VyY2UsXG4gICAgICBkYXRhOiBkYXRhUmVzPy5kYXRhIHx8IG51bGwsXG4gICAgfSk7XG4gICAgYmF0Y2gudXBkYXRlKGRhdGFEb2NSZWZEcmFmdCwge1xuICAgICAgZGF0YVNvdXJjZTogdXBkYXRlZERhdGFTb3VyY2UsXG4gICAgfSk7XG4gICAgYmF0Y2gudXBkYXRlKGRhdGFTb3VyY2VEb2NSZWYsIHtcbiAgICAgIHB1Ymxpc2hlZEF0OiBUaW1lc3RhbXAubm93KCksXG4gICAgICBwdWJsaXNoZWRCeTogcHVibGlzaGVkQnksXG4gICAgfSk7XG4gICAgYXdhaXQgYmF0Y2guY29tbWl0KCk7XG5cbiAgICBjb25zb2xlLmxvZyhgcHVibGlzaGVkIGRhdGEgJHtkYXRhU291cmNlSWR9YCk7XG4gICAgY29uc29sZS5sb2coYHB1Ymxpc2hlZCBieTogJHtwdWJsaXNoZWRCeX1gKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hEYXRhKGRhdGFTb3VyY2U6IERhdGFTb3VyY2UpIHtcbiAgICBpZiAoZGF0YVNvdXJjZS50eXBlID09PSAnaHR0cCcpIHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmZldGNoSHR0cERhdGEoZGF0YVNvdXJjZSk7XG4gICAgfVxuICAgIC8vIFRPRE8oc3RldmVubGUpOiBpbXBsLlxuICAgIC8vIGlmIChkYXRhU291cmNlLnR5cGUgPT09ICdnc2hlZXQnKSB7XG4gICAgLy8gICByZXR1cm4gYXdhaXQgZmV0Y2hHc2hlZXREYXRhKGRhdGFTb3VyY2UpO1xuICAgIC8vIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYHVuc3VwcG9ydGVkIGRhdGEgc291cmNlOiAke2RhdGFTb3VyY2UudHlwZX1gKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hIdHRwRGF0YShkYXRhU291cmNlOiBEYXRhU291cmNlKSB7XG4gICAgY29uc3QgdXJsID0gZGF0YVNvdXJjZS51cmwgfHwgJyc7XG4gICAgaWYgKCF1cmwuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGB1cmwgbm90IHN1cHBvcnRlZDogJHt1cmx9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICBtZXRob2Q6IGRhdGFTb3VyY2UuaHR0cE9wdGlvbnM/Lm1ldGhvZCB8fCAnR0VUJyxcbiAgICAgIGhlYWRlcnM6IGRhdGFTb3VyY2UuaHR0cE9wdGlvbnM/LmhlYWRlcnMgfHwgW10sXG4gICAgICBib2R5OiBkYXRhU291cmNlLmh0dHBPcHRpb25zPy5ib2R5IHx8IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIGlmIChyZXMuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIGNvbnN0IGVyciA9IGF3YWl0IHJlcy50ZXh0KCk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHJlcSBmYWlsZWQ6ICR7ZXJyfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gU3RyaW5nKHJlcy5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJykpO1xuICAgIGlmIChjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpKSB7XG4gICAgICByZXR1cm4gYXdhaXQgcmVzLmpzb24oKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlcy50ZXh0KCk7XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2hlcyBkYXRhIGZyb20gYSBkYXRhIHNvdXJjZS5cbiAgICovXG4gIGFzeW5jIGdldEZyb21EYXRhU291cmNlPFQgPSBhbnk+KFxuICAgIGRhdGFTb3VyY2VJZDogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7bW9kZT86ICdkcmFmdCcgfCAncHVibGlzaGVkJ31cbiAgKTogUHJvbWlzZTxEYXRhU291cmNlRGF0YTxUPiB8IG51bGw+IHtcbiAgICBjb25zdCBtb2RlID0gb3B0aW9ucz8ubW9kZSB8fCAncHVibGlzaGVkJztcblxuICAgIGNvbnN0IGRvY1JlZiA9IHRoaXMuZGJEYXRhU291cmNlRGF0YVJlZihkYXRhU291cmNlSWQsIHttb2RlfSk7XG4gICAgY29uc3QgZG9jID0gYXdhaXQgZG9jUmVmLmdldCgpO1xuICAgIGlmIChkb2MuZXhpc3RzKSB7XG4gICAgICByZXR1cm4gZG9jLmRhdGEoKSBhcyBEYXRhU291cmNlRGF0YTxUPjtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBkYkRhdGFTb3VyY2VEYXRhUGF0aChcbiAgICBkYXRhU291cmNlSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7bW9kZTogJ2RyYWZ0JyB8ICdwdWJsaXNoZWQnfVxuICApIHtcbiAgICBpZiAoIWRhdGFTb3VyY2VJZCB8fCBkYXRhU291cmNlSWQuaW5jbHVkZXMoJy8nKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIGRhdGEgc291cmNlIGlkOiAke2RhdGFTb3VyY2VJZH1gKTtcbiAgICB9XG4gICAgY29uc3QgbW9kZSA9IG9wdGlvbnMubW9kZTtcbiAgICBpZiAoIShtb2RlID09PSAnZHJhZnQnIHx8IG1vZGUgPT09ICdwdWJsaXNoZWQnKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIG1vZGU6ICR7bW9kZX1gKTtcbiAgICB9XG4gICAgY29uc3QgZGJQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0RhdGFTb3VyY2VzLyR7ZGF0YVNvdXJjZUlkfS9EYXRhLyR7bW9kZX1gO1xuICAgIHJldHVybiBkYlBhdGg7XG4gIH1cblxuICBkYkRhdGFTb3VyY2VEYXRhUmVmKFxuICAgIGRhdGFTb3VyY2VJZDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IHttb2RlOiAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCd9XG4gICkge1xuICAgIGNvbnN0IGRiUGF0aCA9IHRoaXMuZGJEYXRhU291cmNlRGF0YVBhdGgoZGF0YVNvdXJjZUlkLCBvcHRpb25zKTtcbiAgICByZXR1cm4gdGhpcy5kYi5kb2MoZGJQYXRoKTtcbiAgfVxuXG4gIGRiVHJhbnNsYXRpb25zUGF0aChcbiAgICB0cmFuc2xhdGlvbnNJZDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IHttb2RlOiAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCd9XG4gICkge1xuICAgIGNvbnN0IG1vZGUgPSBvcHRpb25zLm1vZGU7XG4gICAgaWYgKCEobW9kZSA9PT0gJ2RyYWZ0JyB8fCBtb2RlID09PSAncHVibGlzaGVkJykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBtb2RlOiAke21vZGV9YCk7XG4gICAgfVxuICAgIGNvbnN0IHNsdWcgPSB0cmFuc2xhdGlvbnNJZC5yZXBsYWNlQWxsKCcvJywgJy0tJyk7XG4gICAgY29uc3QgZGJQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L1RyYW5zbGF0aW9uc01hbmFnZXIvJHttb2RlfS9UcmFuc2xhdGlvbnMvJHtzbHVnfWA7XG4gICAgcmV0dXJuIGRiUGF0aDtcbiAgfVxuXG4gIGRiVHJhbnNsYXRpb25zUmVmKFxuICAgIHRyYW5zbGF0aW9uc0lkOiBzdHJpbmcsXG4gICAgb3B0aW9uczoge21vZGU6ICdkcmFmdCcgfCAncHVibGlzaGVkJ31cbiAgKSB7XG4gICAgY29uc3QgZGJQYXRoID0gdGhpcy5kYlRyYW5zbGF0aW9uc1BhdGgodHJhbnNsYXRpb25zSWQsIG9wdGlvbnMpO1xuICAgIHJldHVybiB0aGlzLmRiLmRvYyhkYlBhdGgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIHVzZXIncyByb2xlIGZyb20gdGhlIHByb2plY3QncyBBQ0wuXG4gICAqL1xuICBhc3luYyBnZXRVc2VyUm9sZShlbWFpbDogc3RyaW5nKTogUHJvbWlzZTxVc2VyUm9sZSB8IG51bGw+IHtcbiAgICBpZiAoIWVtYWlsKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3QgZG9jUmVmID0gdGhpcy5kYi5kb2MoYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9YCk7XG4gICAgY29uc3Qgc25hcHNob3QgPSBhd2FpdCBkb2NSZWYuZ2V0KCk7XG4gICAgY29uc3QgZGF0YSA9IHNuYXBzaG90LmRhdGEoKSB8fCB7fTtcbiAgICBjb25zdCBhY2wgPSBkYXRhLnJvbGVzIHx8IHt9O1xuXG4gICAgaWYgKGVtYWlsIGluIGFjbCkge1xuICAgICAgcmV0dXJuIGFjbFtlbWFpbF07XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgd2lsZGNhcmQgZG9tYWlucywgZS5nLiBgKkBleGFtcGxlLmNvbWAuXG4gICAgaWYgKCFlbWFpbC5pbmNsdWRlcygnQCcpKSB7XG4gICAgICBjb25zb2xlLndhcm4oYGludmFsaWQgZW1haWw6ICR7ZW1haWx9YCk7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3QgZG9tYWluID0gZW1haWwuc3BsaXQoJ0AnKS5hdCgtMSk7XG4gICAgaWYgKGRvbWFpbiAmJiBgKkAke2RvbWFpbn1gIGluIGFjbCkge1xuICAgICAgcmV0dXJuIGFjbFtgKkAke2RvbWFpbn1gXTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpZXMgdXNlciBleGlzdHMgaW4gdGhlIEFDTCBsaXN0LlxuICAgKi9cbiAgYXN5bmMgdXNlckV4aXN0c0luQWNsKGVtYWlsOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAoIWVtYWlsKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IGRvY1JlZiA9IHRoaXMuZGIuZG9jKGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfWApO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZG9jUmVmLmdldCgpO1xuICAgIGNvbnN0IGRhdGEgPSBzbmFwc2hvdC5kYXRhKCkgfHwge307XG4gICAgY29uc3QgYWNsID0gZGF0YS5yb2xlcyB8fCB7fTtcbiAgICBpZiAoZW1haWwgaW4gYWNsKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayB3aWxkY2FyZCBkb21haW5zLCBlLmcuIGAqQGV4YW1wbGUuY29tYC5cbiAgICBpZiAoIWVtYWlsLmluY2x1ZGVzKCdAJykpIHtcbiAgICAgIGNvbnNvbGUud2FybihgaW52YWxpZCBlbWFpbDogJHtlbWFpbH1gKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgZG9tYWluID0gZW1haWwuc3BsaXQoJ0AnKS5hdCgtMSk7XG4gICAgaWYgKGRvbWFpbiAmJiBgKkAke2RvbWFpbn1gIGluIGFjbCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGFzeW5jIGxvZ0FjdGlvbihhY3Rpb246IHN0cmluZywgb3B0aW9ucz86IHtieT86IHN0cmluZzsgbWV0YWRhdGE/OiBhbnl9KSB7XG4gICAgaWYgKCFhY3Rpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZDogXCJhY3Rpb25cIicpO1xuICAgIH1cbiAgICBjb25zdCBkYXRhID0ge1xuICAgICAgYWN0aW9uOiBhY3Rpb24sXG4gICAgICB0aW1lc3RhbXA6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgIGJ5OiBvcHRpb25zPy5ieSB8fCAnc3lzdGVtJyxcbiAgICAgIG1ldGFkYXRhOiBvcHRpb25zPy5tZXRhZGF0YSB8fCB7fSxcbiAgICB9O1xuICAgIGNvbnN0IGNvbFJlZiA9IHRoaXMuZGIuY29sbGVjdGlvbihgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vQWN0aW9uTG9nc2ApO1xuICAgIGF3YWl0IGNvbFJlZi5hZGQoZGF0YSk7XG5cbiAgICBjb25zdCBtZXRhU3RyID0gb3B0aW9ucz8ubWV0YWRhdGEgPyBzdHJpbmdpZnlPYmoob3B0aW9ucy5tZXRhZGF0YSkgOiAnJztcbiAgICBjb25zb2xlLmxvZyhgWyR7ZGF0YS50aW1lc3RhbXAudG9NaWxsaXMoKX1dIGFjdGlvbjogJHthY3Rpb259ICR7bWV0YVN0cn1gKTtcblxuICAgIC8vIENhbGwgdGhlIGBvbkFjdGlvbigpYCBjYWxsYmFjayBmcm9tIGNtc1BsdWdpbigpLlxuICAgIGNvbnN0IGNtc1BsdWdpbkNvbmZpZyA9IHRoaXMuY21zUGx1Z2luLmdldENvbmZpZygpO1xuICAgIGlmIChjbXNQbHVnaW5Db25maWcub25BY3Rpb24pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNtc1BsdWdpbkNvbmZpZy5vbkFjdGlvbihkYXRhKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY3JlYXRlQmF0Y2hSZXF1ZXN0KG9wdGlvbnM6IEJhdGNoUmVxdWVzdE9wdGlvbnMpOiBCYXRjaFJlcXVlc3Qge1xuICAgIHJldHVybiBuZXcgQmF0Y2hSZXF1ZXN0KHRoaXMsIG9wdGlvbnMpO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmF0Y2hSZXF1ZXN0T3B0aW9ucyB7XG4gIG1vZGU6ICdkcmFmdCcgfCAncHVibGlzaGVkJztcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gYXV0b21hdGljYWxseSBmZXRjaCB0cmFuc2xhdGlvbnMgZm9yIHRoZSBkb2NzIHJldHJpZXZlZCBpbiB0aGVcbiAgICogcmVxdWVzdC5cbiAgICovXG4gIHRyYW5zbGF0ZT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmF0Y2hSZXF1ZXN0UXVlcnkge1xuICBxdWVyeUlkOiBzdHJpbmc7XG4gIGNvbGxlY3Rpb25JZDogc3RyaW5nO1xuICBxdWVyeU9wdGlvbnM/OiBCYXRjaFJlcXVlc3RRdWVyeU9wdGlvbnM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmF0Y2hSZXF1ZXN0UXVlcnlPcHRpb25zIHtcbiAgb2Zmc2V0PzogbnVtYmVyO1xuICBsaW1pdD86IG51bWJlcjtcbiAgb3JkZXJCeT86IHN0cmluZztcbiAgb3JkZXJCeURpcmVjdGlvbj86ICdhc2MnIHwgJ2Rlc2MnO1xuICBxdWVyeT86IChxdWVyeTogUXVlcnkpID0+IFF1ZXJ5O1xufVxuXG5leHBvcnQgY2xhc3MgQmF0Y2hSZXF1ZXN0IHtcbiAgY21zQ2xpZW50OiBSb290Q01TQ2xpZW50O1xuICBwcml2YXRlIG9wdGlvbnM6IEJhdGNoUmVxdWVzdE9wdGlvbnM7XG4gIHByaXZhdGUgZGI6IEZpcmVzdG9yZTtcbiAgcHJpdmF0ZSBkb2NJZHM6IHN0cmluZ1tdID0gW107XG4gIHByaXZhdGUgZGF0YVNvdXJjZUlkczogc3RyaW5nW10gPSBbXTtcbiAgcHJpdmF0ZSBxdWVyaWVzOiBCYXRjaFJlcXVlc3RRdWVyeVtdID0gW107XG4gIHByaXZhdGUgdHJhbnNsYXRpb25zSWRzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGNvbnN0cnVjdG9yKGNtc0NsaWVudDogUm9vdENNU0NsaWVudCwgb3B0aW9uczogQmF0Y2hSZXF1ZXN0T3B0aW9ucykge1xuICAgIHRoaXMuY21zQ2xpZW50ID0gY21zQ2xpZW50O1xuICAgIHRoaXMuZGIgPSBjbXNDbGllbnQuZGI7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgZG9jIHRvIHRoZSBiYXRjaCByZXF1ZXN0LlxuICAgKi9cbiAgYWRkRG9jKGRvY0lkOiBzdHJpbmcpIHtcbiAgICB0aGlzLmRvY0lkcy5wdXNoKGRvY0lkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgZGF0YSBzb3VyY2UgdG8gdGhlIGJhdGNoIHJlcXVlc3QuXG4gICAqL1xuICBhZGREYXRhU291cmNlKGRhdGFTb3VyY2VJZDogc3RyaW5nKSB7XG4gICAgdGhpcy5kYXRhU291cmNlSWRzLnB1c2goZGF0YVNvdXJjZUlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgY29sbGVjdGlvbi1iYXNlZCBxdWVyeSB0byB0aGUgYmF0Y2ggcmVxdWVzdC5cbiAgICovXG4gIGFkZFF1ZXJ5KFxuICAgIHF1ZXJ5SWQ6IHN0cmluZyxcbiAgICBjb2xsZWN0aW9uSWQ6IHN0cmluZyxcbiAgICBxdWVyeU9wdGlvbnM/OiBCYXRjaFJlcXVlc3RRdWVyeU9wdGlvbnNcbiAgKSB7XG4gICAgdGhpcy5xdWVyaWVzLnB1c2goe1xuICAgICAgcXVlcnlJZDogcXVlcnlJZCxcbiAgICAgIGNvbGxlY3Rpb25JZDogY29sbGVjdGlvbklkLFxuICAgICAgcXVlcnlPcHRpb25zOiBxdWVyeU9wdGlvbnMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHRyYW5zbGF0aW9uIGZpbGUgdG8gdGhlIHJlcXVlc3QuXG4gICAqL1xuICBhZGRUcmFuc2xhdGlvbnModHJhbnNsYXRpb25zSWQ6IHN0cmluZykge1xuICAgIHRoaXMudHJhbnNsYXRpb25zSWRzLnB1c2godHJhbnNsYXRpb25zSWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBEQi5cbiAgICovXG4gIGFzeW5jIGZldGNoKCk6IFByb21pc2U8QmF0Y2hSZXNwb25zZT4ge1xuICAgIGNvbnN0IHJlcyA9IG5ldyBCYXRjaFJlc3BvbnNlKCk7XG5cbiAgICBjb25zdCBwcm9taXNlcyA9IFtcbiAgICAgIHRoaXMuZmV0Y2hEb2NzKHJlcyksXG4gICAgICB0aGlzLmZldGNoUXVlcmllcyhyZXMpLFxuICAgICAgdGhpcy5mZXRjaERhdGFTb3VyY2VzKHJlcyksXG4gICAgXTtcbiAgICAvLyBJZiBgb3B0aW9ucy50cmFuc2xhdGVgIGlzIGRpc2FibGVkIGFuZCB0cmFuc2xhdGlvbnMgYXJlIHJlcXVlc3RlZCxcbiAgICAvLyBmZXRjaCB0aGUgdHJhbnNsYXRpb25zIGluIHBhcmFsbGVsIHdpdGggdGhlIG90aGVyIGRvY3MuXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMudHJhbnNsYXRlICYmIHRoaXMudHJhbnNsYXRpb25zSWRzLmxlbmd0aCA+IDApIHtcbiAgICAgIHByb21pc2VzLnB1c2godGhpcy5mZXRjaFRyYW5zbGF0aW9ucyhyZXMpKTtcbiAgICB9XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcyk7XG5cbiAgICAvLyBJZiBgb3B0aW9ucy50cmFuc2xhdGVgIGlzIGVuYWJsZWQsIHRoZSBmZXRjaFgoKSBtZXRob2RzIHdpbGxcbiAgICAvLyBhdXRvbWF0aWNhbGx5IGFkZCBlYWNoIGRvYydzIHRyYW5zbGF0aW9ucyBpZCB0byB0aGUgcmVxdWVzdCwgc29cbiAgICAvLyB0cmFuc2xhdGlvbnMgc2hvdWxkIGJlIGZldGNoZWQgYWZ0ZXIgYWxsIHRoZSBvdGhlciBkb2NzIGFyZSBmZXRjaGVkLlxuICAgIGlmICh0aGlzLnRyYW5zbGF0aW9uc0lkcy5sZW5ndGggPiAwKSB7XG4gICAgICBhd2FpdCB0aGlzLmZldGNoVHJhbnNsYXRpb25zKHJlcyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hEb2NzKHJlczogQmF0Y2hSZXNwb25zZSkge1xuICAgIGlmICh0aGlzLmRvY0lkcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZG9jUmVmcyA9IHRoaXMuZG9jSWRzLm1hcCgoZG9jSWQpID0+IHtcbiAgICAgIGNvbnN0IFtjb2xsZWN0aW9uSWQsIHNsdWddID0gZG9jSWQuc3BsaXQoJy8nKTtcbiAgICAgIHJldHVybiB0aGlzLmNtc0NsaWVudC5kYkRvY1JlZihjb2xsZWN0aW9uSWQsIHNsdWcsIHtcbiAgICAgICAgbW9kZTogdGhpcy5vcHRpb25zLm1vZGUsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBjb25zdCBkb2NzID0gYXdhaXQgdGhpcy5kYi5nZXRBbGwoLi4uZG9jUmVmcyk7XG4gICAgdGhpcy5kb2NJZHMuZm9yRWFjaCgoZG9jSWQsIGkpID0+IHtcbiAgICAgIGNvbnN0IGRvYyA9IGRvY3NbaV07XG4gICAgICBpZiAoIWRvYy5leGlzdHMpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBkb2MgXCIke2RvY0lkfVwiIGRvZXMgbm90IGV4aXN0YCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGRvY0RhdGEgPSB1bm1hcnNoYWxEYXRhKGRvYy5kYXRhKCkpIGFzIERvYztcbiAgICAgIHJlcy5kb2NzW2RvY0lkXSA9IGRvY0RhdGE7XG5cbiAgICAgIGlmICh0aGlzLm9wdGlvbnMudHJhbnNsYXRlKSB7XG4gICAgICAgIHRoaXMuYWRkVHJhbnNsYXRpb25zKGRvY0lkKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hRdWVyaWVzKHJlczogQmF0Y2hSZXNwb25zZSkge1xuICAgIGlmICh0aGlzLnF1ZXJpZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IG1vZGUgPSB0aGlzLm9wdGlvbnMubW9kZTtcblxuICAgIGNvbnN0IGhhbmRsZVF1ZXJ5ID0gYXN5bmMgKHF1ZXJ5SXRlbTogQmF0Y2hSZXF1ZXN0UXVlcnkpID0+IHtcbiAgICAgIGNvbnN0IGRvY3NQYXRoID0gdGhpcy5jbXNDbGllbnQuZGJDb2xsZWN0aW9uRG9jc1BhdGgoXG4gICAgICAgIHF1ZXJ5SXRlbS5jb2xsZWN0aW9uSWQsXG4gICAgICAgIHttb2RlfVxuICAgICAgKTtcbiAgICAgIGNvbnN0IHF1ZXJ5T3B0aW9ucyA9IHF1ZXJ5SXRlbS5xdWVyeU9wdGlvbnMgfHwge307XG4gICAgICBsZXQgcXVlcnk6IFF1ZXJ5ID0gdGhpcy5kYi5jb2xsZWN0aW9uKGRvY3NQYXRoKTtcbiAgICAgIGlmIChxdWVyeU9wdGlvbnMubGltaXQpIHtcbiAgICAgICAgcXVlcnkgPSBxdWVyeS5saW1pdChxdWVyeU9wdGlvbnMubGltaXQpO1xuICAgICAgfVxuICAgICAgaWYgKHF1ZXJ5T3B0aW9ucy5vZmZzZXQpIHtcbiAgICAgICAgcXVlcnkgPSBxdWVyeS5vZmZzZXQocXVlcnlPcHRpb25zLm9mZnNldCk7XG4gICAgICB9XG4gICAgICBpZiAocXVlcnlPcHRpb25zLm9yZGVyQnkpIHtcbiAgICAgICAgcXVlcnkgPSBxdWVyeS5vcmRlckJ5KFxuICAgICAgICAgIHF1ZXJ5T3B0aW9ucy5vcmRlckJ5LFxuICAgICAgICAgIHF1ZXJ5T3B0aW9ucy5vcmRlckJ5RGlyZWN0aW9uXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAocXVlcnlPcHRpb25zLnF1ZXJ5KSB7XG4gICAgICAgIHF1ZXJ5ID0gcXVlcnlPcHRpb25zLnF1ZXJ5KHF1ZXJ5KTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBxdWVyeS5nZXQoKTtcbiAgICAgIGNvbnN0IGRvY3M6IERvY1tdID0gW107XG4gICAgICByZXN1bHRzLmZvckVhY2goKHJlc3VsdCkgPT4ge1xuICAgICAgICBjb25zdCBkb2MgPSB1bm1hcnNoYWxEYXRhKHJlc3VsdC5kYXRhKCkpIGFzIERvYztcbiAgICAgICAgZG9jcy5wdXNoKGRvYyk7XG4gICAgICB9KTtcbiAgICAgIHJlcy5xdWVyaWVzW3F1ZXJ5SXRlbS5xdWVyeUlkXSA9IGRvY3M7XG4gICAgfTtcblxuICAgIGF3YWl0IFByb21pc2UuYWxsKHRoaXMucXVlcmllcy5tYXAoKHF1ZXJ5SXRlbSkgPT4gaGFuZGxlUXVlcnkocXVlcnlJdGVtKSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaERhdGFTb3VyY2VzKHJlczogQmF0Y2hSZXNwb25zZSkge1xuICAgIGlmICh0aGlzLmRhdGFTb3VyY2VJZHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGRvY1JlZnMgPSB0aGlzLmRhdGFTb3VyY2VJZHMubWFwKChkYXRhU291cmNlSWQpID0+IHtcbiAgICAgIHJldHVybiB0aGlzLmNtc0NsaWVudC5kYkRhdGFTb3VyY2VEYXRhUmVmKGRhdGFTb3VyY2VJZCwge1xuICAgICAgICBtb2RlOiB0aGlzLm9wdGlvbnMubW9kZSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGNvbnN0IGRvY3MgPSBhd2FpdCB0aGlzLmRiLmdldEFsbCguLi5kb2NSZWZzKTtcbiAgICB0aGlzLmRhdGFTb3VyY2VJZHMuZm9yRWFjaCgoZGF0YVNvdXJjZUlkLCBpKSA9PiB7XG4gICAgICBjb25zdCBkb2MgPSBkb2NzW2ldO1xuICAgICAgaWYgKCFkb2MuZXhpc3RzKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgXCJkYXRhIHNvdXJjZSBcIiR7ZGF0YVNvdXJjZUlkfVwiIGRvZXMgbm90IGV4aXN0YCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHJlcy5kYXRhU291cmNlc1tkYXRhU291cmNlSWRdID0gZG9jLmRhdGEoKSBhcyBEYXRhU291cmNlRGF0YTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hUcmFuc2xhdGlvbnMocmVzOiBCYXRjaFJlc3BvbnNlKSB7XG4gICAgaWYgKHRoaXMudHJhbnNsYXRpb25zSWRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGRvY1JlZnMgPSB0aGlzLnRyYW5zbGF0aW9uc0lkcy5tYXAoKHRyYW5zbGF0aW9uc0lkKSA9PiB7XG4gICAgICByZXR1cm4gdGhpcy5jbXNDbGllbnQuZGJUcmFuc2xhdGlvbnNSZWYodHJhbnNsYXRpb25zSWQsIHtcbiAgICAgICAgbW9kZTogdGhpcy5vcHRpb25zLm1vZGUsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBjb25zdCBkb2NzID0gYXdhaXQgdGhpcy5kYi5nZXRBbGwoLi4uZG9jUmVmcyk7XG4gICAgdGhpcy50cmFuc2xhdGlvbnNJZHMuZm9yRWFjaCgodHJhbnNsYXRpb25zSWQsIGkpID0+IHtcbiAgICAgIGNvbnN0IGRvYyA9IGRvY3NbaV07XG4gICAgICBpZiAoIWRvYy5leGlzdHMpIHtcbiAgICAgICAgLy8gY29uc29sZS53YXJuKGB0cmFuc2xhdGlvbnMgXCIke3RyYW5zbGF0aW9uc0lkfVwiIGRvZXMgbm90IGV4aXN0YCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHJlcy50cmFuc2xhdGlvbnNbdHJhbnNsYXRpb25zSWRdID0gZG9jLmRhdGEoKSBhcyBUcmFuc2xhdGlvbnNEb2M7XG4gICAgfSk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEJhdGNoUmVzcG9uc2Uge1xuICBkb2NzOiBSZWNvcmQ8c3RyaW5nLCBEb2M+ID0ge307XG4gIHF1ZXJpZXM6IFJlY29yZDxzdHJpbmcsIERvY1tdPiA9IHt9O1xuICBkYXRhU291cmNlczogUmVjb3JkPHN0cmluZywgRGF0YVNvdXJjZURhdGE+ID0ge307XG4gIHRyYW5zbGF0aW9uczogUmVjb3JkPHN0cmluZywgVHJhbnNsYXRpb25zRG9jPiA9IHt9O1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbWFwIG9mIHRyYW5zbGF0aW9ucyBmb3IgYSBnaXZlbiBsb2NhbGUgb3IgbG9jYWxlIGZhbGxiYWNrcy5cbiAgICpcbiAgICogVGhlIGlucHV0IGlzIGVpdGhlciBhIHNpbmdsZSBsb2NhbGUgKGUuZy4gXCJkZVwiKSBvciBhbiBhcnJheSBvZiBsb2NhbGVzXG4gICAqIHJlcHJlc2VudGluZyB0aGUgZmFsbGJhY2sgdHJlZSwgZS5nLiBbXCJlbi1DQVwiLCBcImVuLUdCXCIsIFwiZW5cIl0uXG4gICAqXG4gICAqIFRoZSByZXR1cm5lZCB2YWx1ZSBpcyBhIGZsYXQgbWFwIG9mIHNvdXJjZSBzdHJpbmcgdG8gdHJhbnNsYXRlZCBzdHJpbmcsXG4gICAqIGUuZy46XG4gICAqIHtcIjxzb3VyY2U+XCI6IFwiPHRyYW5zbGF0aW9uPlwifVxuICAgKi9cbiAgZ2V0VHJhbnNsYXRpb25zKGxvY2FsZTogc3RyaW5nIHwgc3RyaW5nW10pOiBMb2NhbGVUcmFuc2xhdGlvbnMge1xuICAgIGNvbnN0IHRyYW5zbGF0aW9uc01hcCA9IHRoaXMuZ2V0VHJhbnNsYXRpb25zTWFwKCk7XG4gICAgY29uc3QgdHJhbnNsYXRpb25zID0gdHJhbnNsYXRpb25zRm9yTG9jYWxlKHRyYW5zbGF0aW9uc01hcCwgbG9jYWxlKTtcbiAgICByZXR1cm4gdHJhbnNsYXRpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIE1lcmdlcyB0aGUgc3RyaW5ncyBmcm9tIGFsbCB0cmFuc2xhdGlvbnMgZmlsZXMgcmV0cmlldmVkIGluIHRoZSByZXF1ZXN0LlxuICAgKiBUaGUgcmV0dXJuZWQgdmFsdWUgaXMgYSBtYXAgb2Ygc3RyaW5nIHRvIHRyYW5zbGF0aW9ucywgZS5nLjpcbiAgICpcbiAgICoge1wiPGhhc2g+XCI6IHtcInNvdXJjZVwiOiBcIjxzb3VyY2U+XCIsIFwiPGxvY2FsZT5cIjogXCI8dHJhbnNsYXRpb24+XCJ9fVxuICAgKi9cbiAgcHJpdmF0ZSBnZXRUcmFuc2xhdGlvbnNNYXAoKTogVHJhbnNsYXRpb25zTWFwIHtcbiAgICAvLyBMb2FkIHRyYW5zbGF0aW9ucyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxuICAgIC8vIC0gZ2VuZXJpYyB0cmFuc2xhdGlvbnMgKGUuZy4gXCJnbG9iYWxcIilcbiAgICAvLyAtIGRvY3MgcmV0dXJuZWQgZnJvbSBxdWVyaWVzIChlLmcuIFwibGlzdCBhbGwgYmxvZyBwb3N0c1wiKVxuICAgIC8vIC0gc3BlY2lmaWMgZG9jcyAoZS5nLiBcIlBhZ2VzL2luZGV4XCIpXG4gICAgY29uc3QgdHJhbnNsYXRpb25zRG9jcyA9IE9iamVjdC52YWx1ZXModGhpcy50cmFuc2xhdGlvbnMpLnJldmVyc2UoKTtcblxuICAgIC8vIENvbnNvbGlkYXRlIHRoZSBzdHJpbmdzIGZyb20gYWxsIG9mIHRoZSB0cmFuc2xhdGlvbnMgZmlsZXMuXG4gICAgLy8ge1wiPGhhc2g+XCI6IHtcInNvdXJjZVwiOiBcIjxzb3VyY2U+XCIsIFwiPGxvY2FsZT5cIjogXCI8dHJhbnNsYXRpb24+XCJ9fVxuICAgIGNvbnN0IHRyYW5zbGF0aW9uc01hcDogVHJhbnNsYXRpb25zTWFwID0ge307XG4gICAgZm9yIChjb25zdCB0cmFuc2xhdGlvbnNEb2Mgb2YgdHJhbnNsYXRpb25zRG9jcykge1xuICAgICAgY29uc3Qgc3RyaW5ncyA9IHRyYW5zbGF0aW9uc0RvYy5zdHJpbmdzIHx8IHt9O1xuICAgICAgZm9yIChjb25zdCBoYXNoIGluIHN0cmluZ3MpIHtcbiAgICAgICAgY29uc3QgdHJhbnNsYXRpb25zID0gc3RyaW5nc1toYXNoXTtcbiAgICAgICAgdHJhbnNsYXRpb25zTWFwW2hhc2hdID8/PSB7c291cmNlOiB0cmFuc2xhdGlvbnMuc291cmNlfTtcbiAgICAgICAgZm9yIChjb25zdCBsb2NhbGUgaW4gdHJhbnNsYXRpb25zKSB7XG4gICAgICAgICAgaWYgKGxvY2FsZSAhPT0gJ3NvdXJjZScgJiYgdHJhbnNsYXRpb25zW2xvY2FsZV0pIHtcbiAgICAgICAgICAgIHRyYW5zbGF0aW9uc01hcFtoYXNoXVtsb2NhbGVdID0gdHJhbnNsYXRpb25zW2xvY2FsZV07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyYW5zbGF0aW9uc01hcDtcbiAgfVxufVxuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYGRhdGFgIGlzIGEgcmljaCB0ZXh0IGRhdGEgb2JqZWN0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNSaWNoVGV4dERhdGEoZGF0YTogYW55KSB7XG4gIC8vIFRoZSBSaWNoVGV4dEVkaXRvciB1c2VzIGVkaXRvcmpzIHVuZGVyIHRoZSBob29kLCB0aGUgZGF0YSBmb3JtYXQgaXNcbiAgLy8gc29tZXRoaW5nIGxpa2U6XG4gIC8vICB7XG4gIC8vICAgXCJ0aW1lXCI6IDE3MjE3NjEyMTE3MjAsXG4gIC8vICAgXCJ2ZXJzaW9uXCI6IFwiMi4yOC4yXCIsXG4gIC8vICAgXCJibG9ja3NcIjogWy4uLl1cbiAgLy8gfVxuICByZXR1cm4gQm9vbGVhbihcbiAgICBpc09iamVjdChkYXRhKSAmJiBBcnJheS5pc0FycmF5KGRhdGEuYmxvY2tzKSAmJiBkYXRhLnRpbWUgJiYgZGF0YS52ZXJzaW9uXG4gICk7XG59XG5cbi8qKlxuICogV2Fsa3MgdGhlIGRhdGEgdHJlZSBhbmQgY29udmVydHMgYW55IGFycmF5IG9mIG9iamVjdHMgaW50byBcImFycmF5IG9iamVjdHNcIlxuICogZm9yIHN0b3JhZ2UgaW4gZmlyZXN0b3JlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWFyc2hhbERhdGEoZGF0YTogYW55KTogYW55IHtcbiAgLy8gQXZvaWQgY2hhbmdpbmcgdGhlIGZvcm1hdCBvZiByaWNoIHRleHQgZGF0YS5cbiAgaWYgKGlzUmljaFRleHREYXRhKGRhdGEpKSB7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICBjb25zdCByZXN1bHQ6IGFueSA9IHt9O1xuICBmb3IgKGNvbnN0IGtleSBpbiBkYXRhKSB7XG4gICAgY29uc3QgdmFsID0gZGF0YVtrZXldO1xuICAgIGlmIChpc09iamVjdCh2YWwpKSB7XG4gICAgICByZXN1bHRba2V5XSA9IG1hcnNoYWxEYXRhKHZhbCk7XG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHZhbCkpIHtcbiAgICAgIGlmICh2YWwubGVuZ3RoID4gMCAmJiB2YWwuc29tZSgoaXRlbSkgPT4gaXNPYmplY3QoaXRlbSkpKSB7XG4gICAgICAgIGNvbnN0IGl0ZW1zID0gdmFsLm1hcCgoaXRlbSkgPT4ge1xuICAgICAgICAgIGlmIChpc09iamVjdChpdGVtKSkge1xuICAgICAgICAgICAgcmV0dXJuIG1hcnNoYWxEYXRhKGl0ZW0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gaXRlbTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJlc3VsdFtrZXldID0gdG9BcnJheU9iamVjdChpdGVtcyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHRba2V5XSA9IHZhbDtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmVzdWx0W2tleV0gPSB2YWw7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogV2Fsa3MgdGhlIGRhdGEgdHJlZSBhbmQgY29udmVydHMgYW55IFRpbWVzdGFtcCBvYmplY3RzIHRvIG1pbGxpcyBhbmQgYW55XG4gKiBfYXJyYXkgbWFwcyB0byBub3JtYWwgYXJyYXlzLlxuICpcbiAqIEUuZy46XG4gKlxuICogbm9ybWFsaXplRGF0YSh7XG4gKiAgIHN5czoge21vZGlmaWVkQXQ6IFRpbWVzdGFtcCgxMjMpfSxcbiAqICAgZmllbGRzOiB7XG4gKiAgICAgX2FycmF5OiBbJ2FzZGYnXSxcbiAqICAgICBhc2RmOiB7dGl0bGU6ICdoZWxsbyd9XG4gKiAgIH1cbiAqIH0pXG4gKiAvLyA9PiB7c3lzOiB7bW9kaWZpZWRBdDogMTIzfSwgZmllbGRzOiB7Zm9vOiBbe3RpdGxlOiAnaGVsbG8nfV19fVxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5tYXJzaGFsRGF0YShkYXRhOiBhbnkpOiBhbnkge1xuICBjb25zdCByZXN1bHQ6IGFueSA9IHt9O1xuICBmb3IgKGNvbnN0IGtleSBpbiBkYXRhKSB7XG4gICAgY29uc3QgdmFsID0gZGF0YVtrZXldO1xuICAgIGlmIChpc09iamVjdCh2YWwpKSB7XG4gICAgICBpZiAodmFsLnRvTWlsbGlzKSB7XG4gICAgICAgIHJlc3VsdFtrZXldID0gdmFsLnRvTWlsbGlzKCk7XG4gICAgICB9IGVsc2UgaWYgKE9iamVjdC5oYXNPd24odmFsLCAnX2FycmF5JykgJiYgQXJyYXkuaXNBcnJheSh2YWwuX2FycmF5KSkge1xuICAgICAgICBjb25zdCBhcnIgPSB2YWwuX2FycmF5Lm1hcCgoYXJyYXlLZXk6IHN0cmluZykgPT4ge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi51bm1hcnNoYWxEYXRhKHZhbFthcnJheUtleV0gfHwge30pLFxuICAgICAgICAgICAgX2FycmF5S2V5OiBhcnJheUtleSxcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgICAgcmVzdWx0W2tleV0gPSBhcnI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHRba2V5XSA9IHVubWFyc2hhbERhdGEodmFsKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmVzdWx0W2tleV0gPSB2YWw7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKiBAZGVwcmVjYXRlZCBVc2UgYHVubWFyc2hhbERhdGEoKWAgaW5zdGVhZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVEYXRhKGRhdGE6IGFueSk6IGFueSB7XG4gIHJldHVybiB1bm1hcnNoYWxEYXRhKGRhdGEpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFycmF5T2JqZWN0IHtcbiAgW2tleTogc3RyaW5nXTogYW55O1xuICBfYXJyYXk6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIFNlcmlhbGl6ZXMgYW4gYXJyYXkgaW50byBhbiBgQXJyYXlPYmplY3RgLCBlLmcuOlxuICpcbiAqIGBgYFxuICogbWFyc2hhbEFycmF5KFsxLCAyLCAzXSlcbiAqIC8vID0+IHthOiAxLCBiOiAyLCBjOiAzLCBfYXJyYXk6IFsnYScsICdiJywgJ2MnXX1cbiAqIGBgYFxuICpcbiAqIFRoaXMgZGF0YWJhc2Ugc3RvcmFnZSBtZXRob2QgbWFrZXMgaXQgZWFzaWVyIHRvIHVwZGF0ZSBhIHNpbmdsZSBmaWVsZCBpbiBhXG4gKiBkZWVwbHkgbmVzdGVkIGFycmF5IG9iamVjdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvQXJyYXlPYmplY3QoYXJyOiBhbnlbXSk6IEFycmF5T2JqZWN0IHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGFycikpIHtcbiAgICByZXR1cm4gYXJyO1xuICB9XG4gIGNvbnN0IGFyck9iamVjdDogQXJyYXlPYmplY3QgPSB7X2FycmF5OiBbXX07XG4gIGZvciAoY29uc3QgaXRlbSBvZiBhcnIpIHtcbiAgICBjb25zdCBrZXkgPSByYW5kU3RyaW5nKDYpO1xuICAgIGFyck9iamVjdFtrZXldID0gaXRlbTtcbiAgICBhcnJPYmplY3QuX2FycmF5LnB1c2goa2V5KTtcbiAgfVxuICByZXR1cm4gYXJyT2JqZWN0O1xufVxuXG5leHBvcnQgY29uc3QgbWFyc2hhbEFycmF5ID0gdG9BcnJheU9iamVjdDtcblxuLyoqXG4gKiBDb252ZXJ0cyBhbiBgQXJyYXlPYmplY3RgIHRvIGEgbm9ybWFsIGFycmF5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5tYXJzaGFsQXJyYXkoYXJyT2JqZWN0OiBBcnJheU9iamVjdCk6IGFueVtdIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGFyck9iamVjdD8uX2FycmF5KSkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICBjb25zdCBhcnIgPSBhcnJPYmplY3QuX2FycmF5Lm1hcCgoazogc3RyaW5nKSA9PiBhcnJPYmplY3Rba10pO1xuICByZXR1cm4gYXJyO1xufVxuXG5mdW5jdGlvbiBpc09iamVjdChkYXRhOiBhbnkpOiBib29sZWFuIHtcbiAgcmV0dXJuIHR5cGVvZiBkYXRhID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShkYXRhKSAmJiBkYXRhICE9PSBudWxsO1xufVxuXG5mdW5jdGlvbiByYW5kU3RyaW5nKGxlbjogbnVtYmVyKTogc3RyaW5nIHtcbiAgY29uc3QgcmVzdWx0ID0gW107XG4gIGNvbnN0IGNoYXJzID1cbiAgICAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODknO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgY29uc3QgcmFuZCA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIGNoYXJzLmxlbmd0aCk7XG4gICAgcmVzdWx0LnB1c2goY2hhcnMuY2hhckF0KHJhbmQpKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0LmpvaW4oJycpO1xufVxuXG4vKipcbiAqIENvbnZlcnRzIGEgdHJhbnNsYXRpb25zIG1hcCBmcm9tIGBsb2FkVHJhbnNsYXRpb25zKClgIHRvIGEgbWFwIG9mIHNvdXJjZSB0b1xuICogdHJhbnNsYXRlZCBzdHJpbmcgZm9yIGEgcGFydGljdWxhciBsb2NhbGUuXG4gKlxuICogUmV0dXJucyBhIG1hcCBsaWtlOlxuICogYGBgXG4gKiB7XG4gKiAgIFwiSGVsbG9cIjogXCJCb25qb3VyXCIsXG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zbGF0aW9uc0ZvckxvY2FsZShcbiAgdHJhbnNsYXRpb25zTWFwOiBUcmFuc2xhdGlvbnNNYXAsXG4gIGxvY2FsZTogc3RyaW5nIHwgc3RyaW5nW11cbikge1xuICBjb25zdCBsb2NhbGVUcmFuc2xhdGlvbnM6IExvY2FsZVRyYW5zbGF0aW9ucyA9IHt9O1xuXG4gIGNvbnN0IGZhbGxiYWNrTG9jYWxlcyA9IEFycmF5LmlzQXJyYXkobG9jYWxlKSA/IGxvY2FsZSA6IFtsb2NhbGVdO1xuICBpZiAoIWZhbGxiYWNrTG9jYWxlcy5pbmNsdWRlcygnZW4nKSkge1xuICAgIGZhbGxiYWNrTG9jYWxlcy5wdXNoKCdlbicpO1xuICB9XG5cbiAgT2JqZWN0LnZhbHVlcyh0cmFuc2xhdGlvbnNNYXApLmZvckVhY2goKHN0cmluZykgPT4ge1xuICAgIGNvbnN0IHNvdXJjZSA9IHN0cmluZy5zb3VyY2U7XG4gICAgbGV0IHRyYW5zbGF0aW9uID0gc291cmNlO1xuICAgIGZvciAoY29uc3QgZmFsbGJhY2tMb2NhbGUgb2YgZmFsbGJhY2tMb2NhbGVzKSB7XG4gICAgICBpZiAoc3RyaW5nW2ZhbGxiYWNrTG9jYWxlXSkge1xuICAgICAgICB0cmFuc2xhdGlvbiA9IHN0cmluZ1tmYWxsYmFja0xvY2FsZV07XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgICBsb2NhbGVUcmFuc2xhdGlvbnNbc291cmNlXSA9IHRyYW5zbGF0aW9uO1xuICB9KTtcbiAgcmV0dXJuIGxvY2FsZVRyYW5zbGF0aW9ucztcbn1cblxuLyoqIEEgcHJldHR5IHByaW50ZXIgZm9yIEphdmFTY3JpcHQgb2JqZWN0cy4gKi9cbmZ1bmN0aW9uIHN0cmluZ2lmeU9iaihvYmo6IGFueSkge1xuICBmdW5jdGlvbiBmb3JtYXQob2JqOiBhbnkpOiBzdHJpbmcge1xuICAgIGlmIChvYmogPT09IG51bGwpIHtcbiAgICAgIHJldHVybiAnbnVsbCc7XG4gICAgfVxuICAgIGlmICh0eXBlb2Ygb2JqID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuICd1bmRlZmluZWQnO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIG9iaiA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBgXCIke29iai5yZXBsYWNlQWxsKCdcIicsICdcXFxcXCInKX1cImA7XG4gICAgfVxuICAgIGlmICh0eXBlb2Ygb2JqICE9PSAnb2JqZWN0Jykge1xuICAgICAgcmV0dXJuIFN0cmluZyhvYmopO1xuICAgIH1cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgICByZXR1cm4gYFske29iai5tYXAoZm9ybWF0KS5qb2luKCcsICcpfV1gO1xuICAgIH1cbiAgICBjb25zdCBlbnRyaWVzOiBzdHJpbmdbXSA9IE9iamVjdC5lbnRyaWVzKG9iaikubWFwKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgIHJldHVybiBgJHtrZXl9OiAke2Zvcm1hdCh2YWx1ZSl9YDtcbiAgICB9KTtcbiAgICByZXR1cm4gYHske2VudHJpZXMuam9pbignLCAnKX19YDtcbiAgfVxuICByZXR1cm4gZm9ybWF0KG9iaik7XG59XG5cbi8qKlxuICogUGFyc2VzIGEgZG9jSWQgKGUuZy4gYFBhZ2VzL2Zvb2ApIGFuZCByZXR1cm5zIHRoZSBgY29sbGVjdGlvbmAgYW5kIGBzbHVnYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRG9jSWQoZG9jSWQ6IHN0cmluZykge1xuICBjb25zdCBzZXBJbmRleCA9IGRvY0lkLmluZGV4T2YoJy8nKTtcbiAgaWYgKHNlcEluZGV4IDw9IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgZG9jIGlkOiAke2RvY0lkfWApO1xuICB9XG4gIGNvbnN0IGNvbGxlY3Rpb24gPSBkb2NJZC5zbGljZSgwLCBzZXBJbmRleCk7XG4gIGNvbnN0IHNsdWcgPSBkb2NJZC5zbGljZShzZXBJbmRleCArIDEpLnJlcGxhY2VBbGwoJy8nLCAnLS0nKTtcbiAgaWYgKCFjb2xsZWN0aW9uIHx8ICFzbHVnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIGRvYyBpZDogJHtkb2NJZH1gKTtcbiAgfVxuICByZXR1cm4ge2NvbGxlY3Rpb24sIHNsdWd9O1xufVxuXG5leHBvcnQge2dldENtc1BsdWdpbn07XG4iLCAiLyoqXG4gKiBEb2N1bWVudCB2ZXJpb24gaGlzdG9yeS5cbiAqXG4gKiBWZXJpb25zIHNhdmUgdGhlIHN0YXRlIG9mIGEgZG9jdW1lbnQgYXQgZGlmZmVyZW50IG1vbWVudHMgaW4gdGltZSwgYWxsb3dpbmdcbiAqIHVzZXJzIHRvIHJldmVydCBiYWNrIHRvIGEgdmVyc2lvbiBpZi93aGVuIG5lZWRlZC5cbiAqXG4gKiBUaGUgc2F2ZVZlcnNpb25zKCkgZnVuY3Rpb24gaXMgbWVhbnQgdG8gYmUgcnVuIHdpdGhpbiBhIGNyb24gam9iIChlLmcgdXNpbmdcbiAqIGZpcmViYXNlIGZ1bmN0aW9ucykuIEV2ZXJ5IG1pbnV0ZSwgdGhlIHJ1bm5lciBjaGVja3MgZm9yIGFsbCBkb2N1bWVudHMgdGhhdFxuICogaGF2ZSBiZWVuIGVkaXRlZCBzaW5jZSB0aGUgbGFzdCBydW4uIFRvIGF2b2lkIHNhdmluZyBcInBhcnRpYWxcIiB2ZXJzaW9uc1xuICogKHdoZW4gdGhlIHVzZXIgbWlnaHQgYmUgaW4gdGhlIG1pZGRsZSBvZiBlZGl0aW5nIGEgZG9jdW1lbnQpLCB2ZXJzaW9ucyBvbmx5XG4gKiBydW4gb24gZG9jdW1lbnRzIHRoYXQgaGF2ZW4ndCBiZWVuIGVkaXRlZCB3aXRoaW4gdGhlIGxhc3QgNSBtaW5zIHRvIGVuc3VyZVxuICogdGhhdCB2ZXJzaW9uIGlzIFwic3RhYmxlXCIuXG4gKlxuICogSW4gdGhlIGRhdGFiYXNlLCB2ZXJzaW9ucyBhcmUgc3RvcmVkIGFzOlxuICogL1Byb2plY3RzLzxwcm9qZWN0SWQ+L0NvbGxlY3Rpb25zLzxjb2xsZWN0aW9uSWQ+L0RyYWZ0cy88ZG9jSWQ+L1ZlcnNpb25zLzx0aW1lc3RhbXA+XG4gKlxuICogV2hlcmUgPHRpbWVzdGFtcD4gaXMgdGhlIHVuaXggdGltZXN0YW1wIChtaWxsaXMpIHRoYXQgdGhlIGRvY3VtZW50IHdhcyBsYXN0XG4gKiBlZGl0ZWQuXG4gKi9cblxuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7Um9vdENvbmZpZ30gZnJvbSAnQGJsaW5ray9yb290JztcbmltcG9ydCB7RmlyZXN0b3JlLCBRdWVyeSwgVGltZXN0YW1wfSBmcm9tICdmaXJlYmFzZS1hZG1pbi9maXJlc3RvcmUnO1xuaW1wb3J0IGdsb2IgZnJvbSAndGlueS1nbG9iJztcbmltcG9ydCB7Z2V0Q21zUGx1Z2lufSBmcm9tICcuL2NsaWVudC5qcyc7XG5cbi8vIFRvIGF2b2lkIHNhdmluZyBcInBhcnRpYWxcIiB2ZXJzaW9ucyAod2hlbiB0aGUgdXNlciBtaWdodCBiZSBpbiB0aGUgbWlkZGxlIG9mXG4vLyBlZGl0aW5nIGEgZG9jdW1lbnQpLCB2ZXJzaW9ucyBvbmx5IHJ1biBvbiBkb2N1bWVudHMgdGhhdCBoYXZlbid0IGJlZW4gZWRpdGVkXG4vLyB3aXRoaW4gdGhlIGxhc3QgNSBtaW5zIHRvIGVuc3VyZSB0aGF0IHZlcnNpb24gaXMgXCJzdGFibGVcIi5cbmNvbnN0IERPQ1VNRU5UX1NBVkVfT0ZGU0VUID0gNSAqIDYwICogMTAwMDtcblxuaW50ZXJmYWNlIFBhcnRpYWxDTVNEb2Mge1xuICBba2V5OiBzdHJpbmddOiBhbnk7XG4gIGlkOiBzdHJpbmc7XG4gIGNvbGxlY3Rpb246IHN0cmluZztcbiAgc2x1Zzogc3RyaW5nO1xuICBzeXM6IHtcbiAgICBtb2RpZmllZEF0OiBUaW1lc3RhbXA7XG4gICAgbW9kaWZpZWRCeTogc3RyaW5nO1xuICB9O1xufVxuXG5leHBvcnQgY2xhc3MgVmVyc2lvbnNTZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSByb290Q29uZmlnOiBSb290Q29uZmlnO1xuICBwcml2YXRlIHJlYWRvbmx5IHByb2plY3RJZDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGRiOiBGaXJlc3RvcmU7XG5cbiAgY29uc3RydWN0b3Iocm9vdENvbmZpZzogUm9vdENvbmZpZykge1xuICAgIHRoaXMucm9vdENvbmZpZyA9IHJvb3RDb25maWc7XG4gICAgY29uc3QgY21zUGx1Z2luID0gZ2V0Q21zUGx1Z2luKHJvb3RDb25maWcpO1xuICAgIGNvbnN0IGNtc1BsdWdpbk9wdGlvbnMgPSBjbXNQbHVnaW4uZ2V0Q29uZmlnKCk7XG4gICAgY29uc3QgcHJvamVjdElkID0gY21zUGx1Z2luT3B0aW9ucy5pZCB8fCAnZGVmYXVsdCc7XG4gICAgdGhpcy5wcm9qZWN0SWQgPSBwcm9qZWN0SWQ7XG4gICAgdGhpcy5kYiA9IGNtc1BsdWdpbi5nZXRGaXJlc3RvcmUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYXZlcyBhIHZlcnNpb24gb2YgYWxsIGRvY3VtZW50cyB0aGF0IGhhdmUgYmVlbiBlZGl0ZWQgc2luY2UgdGhlIGxhc3QgcnVuLlxuICAgKi9cbiAgYXN5bmMgc2F2ZVZlcnNpb25zKCkge1xuICAgIC8vIE9mZnNldCB0aGUgXCJsYXN0IHJ1blwiIHRpbWUgYnkgNSBtaW5zLiBWZXJzaW9ucyBpZ25vcmUgZG9jcyB0aGF0IHdlcmVcbiAgICAvLyBlZGl0ZWQgd2l0aGluIHRoZSBsYXN0IDUgbWlucyB0byBhdm9pZCBwb3RlbnRpYWwgXCJwYXJ0aWFsXCIgdmVyc2lvbnMgd2hlblxuICAgIC8vIHVzZXIgaXMgaW4gdGhlIG1pZGRsZSBvZiBlZGl0aW5nIGEgZG9jdW1lbnQuXG4gICAgY29uc3QgbGFzdFJ1biA9IGF3YWl0IHRoaXMuZ2V0TGFzdFJ1bigpO1xuICAgIGNvbnN0IGxhc3RSdW5XaXRoT2Zmc2V0ID1cbiAgICAgIGxhc3RSdW4gPT09IDAgPyBsYXN0UnVuIDogbGFzdFJ1biAtIERPQ1VNRU5UX1NBVkVfT0ZGU0VUO1xuICAgIGNvbnN0IGNoYW5nZWREb2NzID0gYXdhaXQgdGhpcy5nZXREb2NzTW9kaWZpZWRBZnRlcihsYXN0UnVuV2l0aE9mZnNldCk7XG4gICAgY29uc3Qgbm93ID0gVGltZXN0YW1wLm5vdygpLnRvTWlsbGlzKCk7XG4gICAgY29uc3QgdmVyc2lvbnMgPSBjaGFuZ2VkRG9jcy5maWx0ZXIoKGRvYykgPT4ge1xuICAgICAgY29uc3QgbW9kaWZpZWRBdCA9IGRvYy5zeXMubW9kaWZpZWRBdC50b01pbGxpcygpO1xuICAgICAgcmV0dXJuIG1vZGlmaWVkQXQgPD0gbm93IC0gRE9DVU1FTlRfU0FWRV9PRkZTRVQ7XG4gICAgfSk7XG4gICAgaWYgKHZlcnNpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuc2F2ZVZlcnNpb25zVG9GaXJlc3RvcmUodmVyc2lvbnMpO1xuICAgIH1cbiAgICB0aGlzLnNhdmVMYXN0UnVuKG5vdyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNhdmVWZXJzaW9uc1RvRmlyZXN0b3JlKHZlcnNpb25zOiBQYXJ0aWFsQ01TRG9jW10pIHtcbiAgICBjb25zdCBiYXRjaCA9IHRoaXMuZGIuYmF0Y2goKTtcbiAgICB2ZXJzaW9ucy5mb3JFYWNoKCh2ZXJzaW9uKSA9PiB7XG4gICAgICBpZiAoIXZlcnNpb24uY29sbGVjdGlvbiB8fCAhdmVyc2lvbi5zbHVnIHx8ICF2ZXJzaW9uLnN5cz8ubW9kaWZpZWRBdCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCBtb2RpZmllZEF0TWlsbGlzID0gdmVyc2lvbi5zeXMubW9kaWZpZWRBdC50b01pbGxpcygpO1xuICAgICAgY29uc3QgdmVyc2lvblBhdGggPSBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vQ29sbGVjdGlvbnMvJHt2ZXJzaW9uLmNvbGxlY3Rpb259L0RyYWZ0cy8ke3ZlcnNpb24uc2x1Z30vVmVyc2lvbnMvJHttb2RpZmllZEF0TWlsbGlzfWA7XG4gICAgICBjb25zb2xlLmxvZyh2ZXJzaW9uUGF0aCk7XG4gICAgICBjb25zdCB2ZXJzaW9uUmVmID0gdGhpcy5kYi5kb2ModmVyc2lvblBhdGgpO1xuICAgICAgYmF0Y2guc2V0KHZlcnNpb25SZWYsIHZlcnNpb24pO1xuICAgIH0pO1xuICAgIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuICAgIGNvbnNvbGUubG9nKGB2ZXJzaW9uczogc2F2ZWQgJHt2ZXJzaW9ucy5sZW5ndGh9IHZlcnNpb25zYCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbGFzdCB0aW1lIChpbiBtaWxsaXMpIHNhdmVWZXJzaW9ucygpIHdhcyBydW4sIG9yIDAgaWYgaGFzXG4gICAqIG5ldmVyIGJlZW4gcnVuLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRMYXN0UnVuKCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgcHJvamVjdERvY1JlZiA9IHRoaXMuZGIuY29sbGVjdGlvbignUHJvamVjdHMnKS5kb2ModGhpcy5wcm9qZWN0SWQpO1xuICAgIGNvbnN0IHByb2plY3REb2MgPSBhd2FpdCBwcm9qZWN0RG9jUmVmLmdldCgpO1xuICAgIGlmIChwcm9qZWN0RG9jLmV4aXN0cykge1xuICAgICAgY29uc3QgZGF0YSA9IHByb2plY3REb2MuZGF0YSgpIHx8IHt9O1xuICAgICAgY29uc3QgdHMgPSBkYXRhLnZlcnNpb25zTGFzdFJ1biBhcyBUaW1lc3RhbXA7XG4gICAgICBpZiAodHMpIHtcbiAgICAgICAgcmV0dXJuIHRzLnRvTWlsbGlzKCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFNhdmVzIHt2ZXJzaW9uTGFzdFJ1bjogPHRpbWVzdGFtcD59IHRvIHRoZSBQcm9qZWN0cy88cHJvamVjdElkPiBkb2MuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNhdmVMYXN0UnVuKG1pbGxpczogbnVtYmVyKSB7XG4gICAgY29uc3QgdHMgPSBUaW1lc3RhbXAuZnJvbU1pbGxpcyhtaWxsaXMpO1xuICAgIGNvbnN0IHByb2plY3REb2NSZWYgPSB0aGlzLmRiLmNvbGxlY3Rpb24oJ1Byb2plY3RzJykuZG9jKHRoaXMucHJvamVjdElkKTtcbiAgICBhd2FpdCBwcm9qZWN0RG9jUmVmLnNldCh7dmVyc2lvbnNMYXN0UnVuOiB0c30sIHttZXJnZTogdHJ1ZX0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBsaXN0IG9mIGFsbCBkb2NzIHRoYXQgd2VyZSBlZGl0ZWQgYWZ0ZXIgYSBjZXJ0YWluIHRpbWUuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGdldERvY3NNb2RpZmllZEFmdGVyKG1pbGxpczogbnVtYmVyKTogUHJvbWlzZTxQYXJ0aWFsQ01TRG9jW10+IHtcbiAgICBjb25zdCB0cyA9IFRpbWVzdGFtcC5mcm9tTWlsbGlzKG1pbGxpcyk7XG4gICAgY29uc3QgcmVzdWx0czogUGFydGlhbENNU0RvY1tdID0gW107XG4gICAgY29uc3QgY29sbGVjdGlvbklkcyA9IGF3YWl0IHRoaXMubGlzdENvbGxlY3Rpb25zKCk7XG4gICAgLy8gTk9URTogSW5kaXZpZHVhbCBjb2xsZWN0aW9ucyBhcmUgcXVlcmllZCBpbnN0ZWFkIG9mIHVzaW5nIGFcbiAgICAvLyBjb2xsZWN0aW9uR3JvdXAgcXVlcnkgYmVjYXVzZSB0aGUgbGF0dGVyIHJlcXVpcmVzIGEgZmlyZXN0b3JlIGluZGV4IHRvIGJlXG4gICAgLy8gc2V0IHVwLlxuICAgIGZvciAoY29uc3QgY29sbGVjdGlvbklkIG9mIGNvbGxlY3Rpb25JZHMpIHtcbiAgICAgIGNvbnN0IGNvbGxlY3Rpb25QYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0NvbGxlY3Rpb25zLyR7Y29sbGVjdGlvbklkfS9EcmFmdHNgO1xuICAgICAgY29uc3QgcXVlcnk6IFF1ZXJ5ID0gdGhpcy5kYlxuICAgICAgICAuY29sbGVjdGlvbihjb2xsZWN0aW9uUGF0aClcbiAgICAgICAgLndoZXJlKCdzeXMubW9kaWZpZWRBdCcsICc+PScsIHRzKTtcbiAgICAgIGNvbnN0IHF1ZXJ5U25hcHNob3QgPSBhd2FpdCBxdWVyeS5nZXQoKTtcbiAgICAgIHF1ZXJ5U25hcHNob3QuZm9yRWFjaCgoZG9jKSA9PiB7XG4gICAgICAgIHJlc3VsdHMucHVzaChkb2MuZGF0YSgpIGFzIFBhcnRpYWxDTVNEb2MpO1xuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBsaXN0IG9mIGNvbGxlY3Rpb24gaWRzIGZvciB0aGUgUm9vdCBwcm9qZWN0LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBsaXN0Q29sbGVjdGlvbnMoKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGNvbnN0IGNvbGxlY3Rpb25JZHM6IHN0cmluZ1tdID0gW107XG4gICAgY29uc3QgY29sbGVjdGlvbkZpbGVOYW1lcyA9IGF3YWl0IGdsb2IoJyouc2NoZW1hLnRzJywge1xuICAgICAgY3dkOiBwYXRoLmpvaW4odGhpcy5yb290Q29uZmlnLnJvb3REaXIsICdjb2xsZWN0aW9ucycpLFxuICAgIH0pO1xuICAgIGNvbGxlY3Rpb25GaWxlTmFtZXMuZm9yRWFjaCgoZmlsZW5hbWUpID0+IHtcbiAgICAgIGNvbGxlY3Rpb25JZHMucHVzaChmaWxlbmFtZS5zbGljZSgwLCAtMTApKTtcbiAgICB9KTtcbiAgICByZXR1cm4gY29sbGVjdGlvbklkcztcbiAgfVxufVxuIiwgImltcG9ydCB7Um9vdENvbmZpZ30gZnJvbSAnQGJsaW5ray9yb290JztcbmltcG9ydCB7Um9vdENNU0NsaWVudH0gZnJvbSAnLi9jbGllbnQuanMnO1xuaW1wb3J0IHtWZXJzaW9uc1NlcnZpY2V9IGZyb20gJy4vdmVyc2lvbnMuanMnO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuQ3JvbkpvYnMocm9vdENvbmZpZzogUm9vdENvbmZpZykge1xuICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgcnVuQ3JvbkpvYigncHVibGlzaFNjaGVkdWxlZERvY3MnLCBydW5QdWJsaXNoU2NoZWR1bGVkRG9jcywgcm9vdENvbmZpZyksXG4gICAgcnVuQ3JvbkpvYignc2F2ZVZlcnNpb25zJywgcnVuU2F2ZVZlcnNpb25zLCByb290Q29uZmlnKSxcbiAgXSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1bkNyb25Kb2IoXG4gIG5hbWU6IHN0cmluZyxcbiAgZm46ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICAuLi5hcmdzOiBhbnlbXVxuKSB7XG4gIHRyeSB7XG4gICAgYXdhaXQgZm4oLi4uYXJncyk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnNvbGUubG9nKGBjcm9uIGZhaWxlZDogJHtuYW1lfWApO1xuICAgIGNvbnNvbGUuZXJyb3IoU3RyaW5nKGVyci5zdGFjayB8fCBlcnIpKTtcbiAgICB0aHJvdyBlcnI7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcnVuUHVibGlzaFNjaGVkdWxlZERvY3Mocm9vdENvbmZpZzogUm9vdENvbmZpZykge1xuICBjb25zdCBjbXNDbGllbnQgPSBuZXcgUm9vdENNU0NsaWVudChyb290Q29uZmlnKTtcbiAgYXdhaXQgY21zQ2xpZW50LnB1Ymxpc2hTY2hlZHVsZWREb2NzKCk7XG4gIGF3YWl0IGNtc0NsaWVudC5wdWJsaXNoU2NoZWR1bGVkUmVsZWFzZXMoKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcnVuU2F2ZVZlcnNpb25zKHJvb3RDb25maWc6IFJvb3RDb25maWcpIHtcbiAgY29uc3Qgc2VydmljZSA9IG5ldyBWZXJzaW9uc1NlcnZpY2Uocm9vdENvbmZpZyk7XG4gIGF3YWl0IHNlcnZpY2Uuc2F2ZVZlcnNpb25zKCk7XG59XG4iLCAiaW1wb3J0IHtwYXJzZSBhcyBjc3ZQYXJzZX0gZnJvbSAnY3N2LXBhcnNlL3N5bmMnO1xuaW1wb3J0IHtzdHJpbmdpZnkgYXMgY3N2U3RyaW5naWZ5fSBmcm9tICdjc3Ytc3RyaW5naWZ5L3N5bmMnO1xuXG5leHBvcnQgZnVuY3Rpb24gYXJyYXlUb0NzdihyZXE6IHtcbiAgaGVhZGVyczogc3RyaW5nW107XG4gIHJvd3M6IEFycmF5PFJlY29yZDxzdHJpbmcsIGFueT4+O1xufSk6IHN0cmluZyB7XG4gIGNvbnN0IGhlYWRlcnMgPSByZXEuaGVhZGVycyB8fCBbXTtcbiAgY29uc3Qgcm93cyA9IHJlcS5yb3dzIHx8IFtdO1xuICByZXR1cm4gY3N2U3RyaW5naWZ5KHJvd3MsIHtcbiAgICBoZWFkZXI6IHRydWUsXG4gICAgY29sdW1uczogaGVhZGVycyxcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjc3ZUb0FycmF5KGNzdlN0cmluZzogc3RyaW5nKSB7XG4gIGNvbnN0IHJvd3MgPSBjc3ZQYXJzZShjc3ZTdHJpbmcsIHtcbiAgICBjb2x1bW5zOiB0cnVlLFxuICAgIHNraXBfZW1wdHlfbGluZXM6IHRydWUsXG4gIH0pO1xuICByZXR1cm4gcm93cztcbn1cbiIsICJpbXBvcnQge1Jvb3RDb25maWd9IGZyb20gJ0BibGlua2svcm9vdCc7XG5pbXBvcnQge1RpbWVzdGFtcH0gZnJvbSAnZmlyZWJhc2UtYWRtaW4vZmlyZXN0b3JlJztcbmltcG9ydCB7Um9vdENNU0NsaWVudCwgVHJhbnNsYXRpb24sIFRyYW5zbGF0aW9uc0RvY30gZnJvbSAnLi9jbGllbnQuanMnO1xuXG4vKipcbiAqIFJ1bnMgY29tcGF0aWJpbGl0eSBjaGVja3MgdG8gZW5zdXJlIHRoZSBjdXJyZW50IHZlcnNpb24gb2Ygcm9vdCBzdXBwb3J0c1xuICogYW55IGJhY2t3YXJkcy1pbmNvbXBhdGlibGUgZGIgY2hhbmdlcy5cbiAqXG4gKiBDb21wYXRpYmlsaXR5IHZlcnNpb25zIGFyZSBzdG9yZWQgaW4gdGhlIGRiIGluIFByb2plY3RzLzxwcm9qZWN0SWQ+IHVuZGVyXG4gKiB0aGUgXCJjb21wYXRpYmlsaXR5XCIga2V5LiBJZiB0aGUgY29tcGF0aWJpbGl0eSB2ZXJzaW9uIGlzIGxlc3MgdGhhbiB0aGVcbiAqIGxhdGVzdCB2ZXJzaW9uLCBhIGJhY2t3YXJkcy1mcmllbmRseSBcIm1pZ3JhdGlvblwiIGlzIGRvbmUgdG8gZW5zdXJlXG4gKiBjb21wYXRpYmlsaXR5IG9uIGJvdGggdGhlIG9sZCBhbmQgbmV3IHZlcnNpb25zLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuQ29tcGF0aWJpbGl0eUNoZWNrcyhyb290Q29uZmlnOiBSb290Q29uZmlnKSB7XG4gIGNvbnN0IGNtc0NsaWVudCA9IG5ldyBSb290Q01TQ2xpZW50KHJvb3RDb25maWcpO1xuICBjb25zdCBwcm9qZWN0SWQgPSBjbXNDbGllbnQucHJvamVjdElkO1xuICBjb25zdCBkYiA9IGNtc0NsaWVudC5kYjtcbiAgY29uc3QgcHJvamVjdENvbmZpZ0RvY1JlZiA9IGRiLmRvYyhgUHJvamVjdHMvJHtwcm9qZWN0SWR9YCk7XG4gIGNvbnN0IHByb2plY3RDb25maWdEb2MgPSBhd2FpdCBwcm9qZWN0Q29uZmlnRG9jUmVmLmdldCgpO1xuICBjb25zdCBwcm9qZWN0Q29uZmlnID0gcHJvamVjdENvbmZpZ0RvYy5kYXRhKCkgfHwge307XG5cbiAgY29uc3QgY29tcGF0aWJpbGl0eVZlcnNpb25zID0gcHJvamVjdENvbmZpZy5jb21wYXRpYmlsaXR5IHx8IHt9O1xuICBsZXQgdmVyc2lvbnNDaGFuZ2VkID0gZmFsc2U7XG5cbiAgY29uc3QgdHJhbnNsYXRpb25zVmVyc2lvbiA9IGNvbXBhdGliaWxpdHlWZXJzaW9ucy50cmFuc2xhdGlvbnMgfHwgMDtcbiAgaWYgKHRyYW5zbGF0aW9uc1ZlcnNpb24gPCAyKSB7XG4gICAgYXdhaXQgbWlncmF0ZVRyYW5zbGF0aW9uc1RvVjIocm9vdENvbmZpZywgY21zQ2xpZW50KTtcbiAgICBjb21wYXRpYmlsaXR5VmVyc2lvbnMudHJhbnNsYXRpb25zID0gMjtcbiAgICB2ZXJzaW9uc0NoYW5nZWQgPSB0cnVlO1xuICB9XG5cbiAgaWYgKHZlcnNpb25zQ2hhbmdlZCkge1xuICAgIGF3YWl0IHByb2plY3RDb25maWdEb2NSZWYudXBkYXRlKHtjb21wYXRpYmlsaXR5OiBjb21wYXRpYmlsaXR5VmVyc2lvbnN9KTtcbiAgICBjb25zb2xlLmxvZygnW3Jvb3QgY21zXSB1cGRhdGVkIGRiIGNvbXBhdGliaWxpdHknKTtcbiAgfVxufVxuXG4vKipcbiAqIE1pZ3JhdGVzIHRyYW5zbGF0aW9ucyBmcm9tIHRoZSBcInYxXCIgZm9ybWF0IHRvIFwidjJcIi5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gbWlncmF0ZVRyYW5zbGF0aW9uc1RvVjIoXG4gIHJvb3RDb25maWc6IFJvb3RDb25maWcsXG4gIGNtc0NsaWVudDogUm9vdENNU0NsaWVudFxuKSB7XG4gIGlmIChyb290Q29uZmlnLmV4cGVyaW1lbnRzPy5yb290Q21zRGlzYWJsZVRyYW5zbGF0aW9uc1RvVjJDaGVjaykge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHByb2plY3RJZCA9IGNtc0NsaWVudC5wcm9qZWN0SWQ7XG4gIGNvbnN0IGRiID0gY21zQ2xpZW50LmRiO1xuICBjb25zdCBkYlBhdGggPSBgUHJvamVjdHMvJHtwcm9qZWN0SWR9L1RyYW5zbGF0aW9uc2A7XG4gIGNvbnN0IHF1ZXJ5ID0gZGIuY29sbGVjdGlvbihkYlBhdGgpO1xuICBjb25zdCBxdWVyeVNuYXBzaG90ID0gYXdhaXQgcXVlcnkuZ2V0KCk7XG4gIGlmIChxdWVyeVNuYXBzaG90LnNpemUgPT09IDApIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zb2xlLmxvZygnW3Jvb3QgY21zXSB1cGRhdGluZyB0cmFuc2xhdGlvbnMgdjIgY29tcGF0aWJpbGl0eScpO1xuXG4gIGNvbnN0IHRyYW5zbGF0aW9uc0RvY3M6IFJlY29yZDxzdHJpbmcsIFRyYW5zbGF0aW9uc0RvYz4gPSB7fTtcbiAgcXVlcnlTbmFwc2hvdC5mb3JFYWNoKChkb2MpID0+IHtcbiAgICBjb25zdCBoYXNoID0gZG9jLmlkO1xuICAgIGNvbnN0IHRyYW5zbGF0aW9uID0gZG9jLmRhdGEoKSBhcyBUcmFuc2xhdGlvbjtcbiAgICBjb25zdCB0YWdzID0gKHRyYW5zbGF0aW9uLnRhZ3MgfHwgW10pIGFzIHN0cmluZ1tdO1xuICAgIGRlbGV0ZSB0cmFuc2xhdGlvbi50YWdzO1xuICAgIGZvciAoY29uc3QgdGFnIG9mIHRhZ3MpIHtcbiAgICAgIGlmICh0YWcuaW5jbHVkZXMoJy8nKSkge1xuICAgICAgICBjb25zdCB0cmFuc2xhdGlvbnNJZCA9IHRhZy5yZXBsYWNlQWxsKCcvJywgJy0tJyk7XG4gICAgICAgIHRyYW5zbGF0aW9uc0RvY3NbdHJhbnNsYXRpb25zSWRdID8/PSB7XG4gICAgICAgICAgaWQ6IHRyYW5zbGF0aW9uc0lkLFxuICAgICAgICAgIHN5czoge1xuICAgICAgICAgICAgbW9kaWZpZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgICAgICAgbW9kaWZpZWRCeTogJ3Jvb3QtY21zLWNsaWVudCcsXG4gICAgICAgICAgICBwdWJsaXNoZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgICAgICAgcHVibGlzaGVkQnk6ICdyb290LWNtcy1jbGllbnQnLFxuICAgICAgICAgICAgdGFnczogdGFncyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHN0cmluZ3M6IHt9LFxuICAgICAgICB9O1xuICAgICAgICB0cmFuc2xhdGlvbnNEb2NzW3RyYW5zbGF0aW9uc0lkXS5zdHJpbmdzW2hhc2hdID0gdHJhbnNsYXRpb247XG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICBpZiAoT2JqZWN0LmtleXModHJhbnNsYXRpb25zRG9jcykubGVuZ3RoID09PSAwKSB7XG4gICAgY29uc29sZS5sb2coJ1tyb290IGNtc10gbm8gdHJhbnNsYXRpb25zIHRvIHNhdmUnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBNb3ZlIHRoZSBkb2MncyBcImwxMG5TaGVldFwiIHRvIHRoZSB0cmFuc2xhdGlvbnMgZG9jJ3MgXCJsaW5rZWRTaGVldFwiLlxuXG4gIGZvciAoY29uc3QgZG9jSWQgaW4gdHJhbnNsYXRpb25zRG9jcykge1xuICAgIGNvbnN0IFtjb2xsZWN0aW9uLCBzbHVnXSA9IGRvY0lkLnNwbGl0KCcvJyk7XG4gICAgaWYgKGNvbGxlY3Rpb24gJiYgc2x1Zykge1xuICAgICAgY29uc3QgZG9jOiBhbnkgPSBhd2FpdCBjbXNDbGllbnQuZ2V0RG9jKGNvbGxlY3Rpb24sIHNsdWcsIHtcbiAgICAgICAgbW9kZTogJ2RyYWZ0JyxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgbGlua2VkU2hlZXQgPSBkb2M/LnN5cz8ubDEwblNoZWV0O1xuICAgICAgaWYgKGxpbmtlZFNoZWV0KSB7XG4gICAgICAgIHRyYW5zbGF0aW9uc0RvY3NbZG9jSWRdLnN5cy5saW5rZWRTaGVldCA9IGxpbmtlZFNoZWV0O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGJhdGNoID0gZGIuYmF0Y2goKTtcbiAgT2JqZWN0LmVudHJpZXModHJhbnNsYXRpb25zRG9jcykuZm9yRWFjaCgoW3RyYW5zbGF0aW9uc0lkLCBkYXRhXSkgPT4ge1xuICAgIGNvbnN0IGRyYWZ0UmVmID0gZGIuZG9jKFxuICAgICAgYFByb2plY3RzLyR7cHJvamVjdElkfS9UcmFuc2xhdGlvbnNNYW5hZ2VyL2RyYWZ0L1RyYW5zbGF0aW9ucy8ke3RyYW5zbGF0aW9uc0lkfWBcbiAgICApO1xuICAgIGNvbnN0IHB1Ymxpc2hlZFJlZiA9IGRiLmRvYyhcbiAgICAgIGBQcm9qZWN0cy8ke3Byb2plY3RJZH0vVHJhbnNsYXRpb25zTWFuYWdlci9wdWJsaXNoZWQvVHJhbnNsYXRpb25zLyR7dHJhbnNsYXRpb25zSWR9YFxuICAgICk7XG4gICAgYmF0Y2guc2V0KGRyYWZ0UmVmLCBkYXRhLCB7bWVyZ2U6IHRydWV9KTtcbiAgICBiYXRjaC5zZXQocHVibGlzaGVkUmVmLCBkYXRhLCB7bWVyZ2U6IHRydWV9KTtcbiAgICBjb25zdCBsZW4gPSBPYmplY3Qua2V5cyhkYXRhLnN0cmluZ3MpLmxlbmd0aDtcbiAgICBjb25zb2xlLmxvZyhgW3Jvb3QgY21zXSBzYXZpbmcgJHtsZW59IHN0cmluZyhzKSB0byAke3RyYW5zbGF0aW9uc0lkfS4uLmApO1xuICB9KTtcbiAgYXdhaXQgYmF0Y2guY29tbWl0KCk7XG5cbiAgY29uc29sZS5sb2coJ1tyb290IGNtc10gZG9uZSBtaWdyYXRpbmcgdHJhbnNsYXRpb25zIHRvIHYyJyk7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxTQUFRLFlBQVksVUFBUztBQUM3QixPQUFPQSxXQUFVO0FBQ2pCLFNBQVEscUJBQW9CO0FBQzVCLFNBQVEsZ0JBQWdCLHlCQUF3QjtBQUNoRCxZQUFZLFNBQVM7QUFPckIsZUFBc0IsZ0JBQWdCO0FBQ3BDLFFBQU0sVUFBVSxRQUFRLElBQUk7QUFDNUIsUUFBTSxhQUFhLE1BQU0sZUFBZSxTQUFTLEVBQUMsU0FBUyxXQUFVLENBQUM7QUFDdEUsUUFBTSxhQUFhQSxNQUFLLFFBQVEsV0FBVyxjQUFjO0FBQ3pELFFBQU0sVUFBVyxNQUFNO0FBQUEsSUFDckI7QUFBQSxJQUNBO0FBQUEsRUFDRjtBQUNBLFFBQU0sVUFBVSxRQUFRLGtCQUFrQjtBQUMxQyxRQUFNLGFBQWFBLE1BQUssUUFBUSxTQUFTLGVBQWU7QUFDeEQsUUFBTSxrQkFBa0IsWUFBWSxPQUFPO0FBQzNDLFVBQVEsSUFBSSxzQkFBc0I7QUFDcEM7QUEyREEsZUFBc0Isa0JBQ3BCLFlBQ0EsU0FDQTtBQUNBLFFBQU0sVUFBVSxDQUFDLFFBQVE7QUFDekIsYUFB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LE1BQUssUUFBUUQsWUFBVyxJQUFJO0FBQzlDLGFBQU8sSUFBSSxlQUFlLEtBQUssV0FBVyxFQUFDLEtBQUssTUFBSyxDQUFDLENBQUM7QUFHdkQsVUFBSSxNQUFNO0FBR1YsYUFBTyxJQUFJLFFBQVEsT0FBTyxLQUFjLFFBQWtCO0FBQ3hELFlBQUk7QUFJRixjQUFJLENBQUMsSUFBSSxNQUFNO0FBQ2IsNEJBQWdCLEtBQUssR0FBRztBQUN4QjtBQUFBLFVBQ0Y7QUFDQSxnQkFBTUcsT0FBTSxNQUFNLFlBQVksR0FBRztBQUNqQyxnQkFBTUEsS0FBSSxVQUFVLEtBQUssS0FBSztBQUFBLFlBQzVCLFlBQVksSUFBSTtBQUFBLFlBQ2hCLFdBQVc7QUFBQSxVQUNiLENBQUM7QUFBQSxRQUNILFNBQVMsS0FBSztBQUVaLGtCQUFRLE1BQU0sR0FBRztBQUNqQixjQUFJLE9BQU8sR0FBRyxFQUFFLEtBQUssc0JBQXNCO0FBQUEsUUFDN0M7QUFBQSxNQUNGLENBQUM7QUFBQSxJQUNIO0FBQUEsRUFDRjtBQUVBLE1BQUksUUFBUSxVQUFVLE9BQU87QUFDM0IsV0FBTyxlQUFlLENBQ3BCLFdBQ0EsYUFDRztBQUNILFVBQUksU0FBUyxTQUFTLFlBQVksR0FBRztBQUduQyxzRkFBbUMsS0FBSyxDQUFDLHdCQUF3QjtBQUMvRCxnQkFBTUMsaUJBQWdCLG9CQUFvQjtBQUMxQyxVQUFBQSxlQUFjO0FBQUEsUUFDaEIsQ0FBQztBQUFBLE1BQ0g7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUVBLFNBQU87QUFDVDtBQUVBLFNBQVMsV0FBVyxVQUFvQztBQUN0RCxTQUFPQyxJQUNKLE9BQU8sUUFBUSxFQUNmLEtBQUssTUFBTSxJQUFJLEVBQ2YsTUFBTSxNQUFNLEtBQUs7QUFDdEI7QUFFTyxTQUFTLGFBQWEsWUFBbUM7QUFDOUQsUUFBTSxVQUFvQixXQUFXLFdBQVcsQ0FBQztBQUNqRCxRQUFNLFNBQVMsUUFBUSxLQUFLLENBQUNDLFlBQVdBLFFBQU8sU0FBUyxVQUFVO0FBQ2xFLE1BQUksQ0FBQyxRQUFRO0FBQ1gsVUFBTSxJQUFJLE1BQU0seURBQXlEO0FBQUEsRUFDM0U7QUFDQSxTQUFPO0FBQ1Q7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiZnMiLCAicGF0aCIsICJmaWxlVVJMVG9QYXRoIiwgImNyeXB0byIsICJUaW1lc3RhbXAiLCAiVGltZXN0YW1wIiwgImNyeXB0byIsICJvYmoiLCAiVGltZXN0YW1wIiwgImNtc1BsdWdpbiIsICJUaW1lc3RhbXAiLCAiVGltZXN0YW1wIiwgIlRpbWVzdGFtcCIsICJfX2Rpcm5hbWUiLCAicGF0aCIsICJmaWxlVVJMVG9QYXRoIiwgImFwcCIsICJnZW5lcmF0ZVR5cGVzIiwgImZzIiwgInBsdWdpbiJdCn0K