@blinkk/root-cms 2.0.0-rc.0 → 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/functions.js CHANGED
@@ -1,57 +1,362 @@
1
1
  // core/functions.ts
2
- import path3 from "node:path";
2
+ import path2 from "node:path";
3
3
  import { loadBundledConfig } from "@blinkk/root/node";
4
4
  import { onSchedule } from "firebase-functions/v2/scheduler";
5
5
 
6
6
  // core/client.ts
7
- import crypto2 from "node:crypto";
7
+ import crypto from "node:crypto";
8
8
  import {
9
- FieldValue,
10
- Timestamp as Timestamp3
9
+ FieldValue as FieldValue2,
10
+ Timestamp as Timestamp2
11
11
  } from "firebase-admin/firestore";
12
12
 
13
- // core/plugin.ts
14
- import { promises as fs } from "node:fs";
15
- import path from "node:path";
16
- import { fileURLToPath } from "node:url";
17
- import bodyParser from "body-parser";
13
+ // core/translations-manager.ts
18
14
  import {
19
- applicationDefault,
20
- getApp,
21
- initializeApp
22
- } from "firebase-admin/app";
23
- import { getAuth } from "firebase-admin/auth";
24
- import { getFirestore } from "firebase-admin/firestore";
25
- import * as jsonwebtoken from "jsonwebtoken";
26
- import sirv from "sirv";
27
-
28
- // core/api.ts
29
- import { multipartMiddleware } from "@blinkk/root/middleware";
30
-
31
- // core/ai.ts
32
- import crypto from "node:crypto";
33
- import { generate } from "@genkit-ai/ai";
34
- import { configureGenkit } from "@genkit-ai/core";
35
- import { vertexAI } from "@genkit-ai/vertexai";
36
- import { gemini15ProPreview, gemini15FlashPreview } from "@genkit-ai/vertexai";
37
- import { Timestamp } from "firebase-admin/firestore";
38
-
39
- // core/csv.ts
40
- import { parse as csvParse } from "csv-parse/sync";
41
- import { stringify as csvStringify } from "csv-stringify/sync";
15
+ FieldValue,
16
+ Timestamp
17
+ } from "firebase-admin/firestore";
42
18
 
43
- // core/compatibility.ts
44
- import { Timestamp as Timestamp2 } from "firebase-admin/firestore";
19
+ // shared/strings.ts
20
+ import fnv from "fnv-plus";
21
+ function normalizeStr(str) {
22
+ const lines = str.trim().split("\n").map((line) => removeTrailingWhitespace(line));
23
+ return lines.join("\n");
24
+ }
25
+ function removeTrailingWhitespace(str) {
26
+ return str.trimEnd().replace(/ $/, "");
27
+ }
28
+ function hashStr(str) {
29
+ if (!str || typeof str !== "string") {
30
+ throw new Error("input string is invalid");
31
+ }
32
+ return fnv.fast1a52hex(normalizeStr(str));
33
+ }
45
34
 
46
- // core/plugin.ts
47
- var __dirname = path.dirname(fileURLToPath(import.meta.url));
48
- function getCmsPlugin(rootConfig) {
49
- const plugins = rootConfig.plugins || [];
50
- const plugin = plugins.find((plugin2) => plugin2.name === "root-cms");
51
- if (!plugin) {
52
- throw new Error("could not find root-cms plugin config in root.config.ts");
35
+ // core/translations-manager.ts
36
+ var TRANSLATIONS_DB_PATH_FORMAT = "/Projects/{project}/TranslationsManager/{mode}/Translations";
37
+ var TRANSLATIONS_LOCALE_DOC_DB_PATH_FORMAT = `${TRANSLATIONS_DB_PATH_FORMAT}/{id}:{locale}`;
38
+ var TranslationsManager = class {
39
+ constructor(cmsClient) {
40
+ this.cmsClient = cmsClient;
53
41
  }
54
- return plugin;
42
+ /**
43
+ * Saves draft translations for a translations doc id.
44
+ *
45
+ * Example:
46
+ * ```
47
+ * const strings = {
48
+ * 'one': {es: 'uno', fr: 'un'},
49
+ * 'two': {es: 'dos', fr: 'deux'},
50
+ * };
51
+ * await tm.saveTranslations('Pages/index', strings);
52
+ * ```
53
+ */
54
+ async saveTranslations(id, strings, options) {
55
+ const mode = "draft";
56
+ const localesSet = /* @__PURE__ */ new Set();
57
+ Object.values(strings).forEach((entry) => {
58
+ Object.keys(entry).forEach((locale) => {
59
+ if (locale !== "source") {
60
+ localesSet.add(locale);
61
+ }
62
+ });
63
+ });
64
+ const batch = this.cmsClient.db.batch();
65
+ const locales = Array.from(localesSet);
66
+ locales.forEach((locale) => {
67
+ const updates = {
68
+ id,
69
+ locale,
70
+ sys: {
71
+ modifiedAt: Timestamp.now(),
72
+ modifiedBy: (options == null ? void 0 : options.modifiedBy) || "root-cms-client"
73
+ },
74
+ strings: {}
75
+ };
76
+ if ((options == null ? void 0 : options.tags) && options.tags.length > 0) {
77
+ updates.tags = FieldValue.arrayUnion(...options.tags);
78
+ }
79
+ let numUpdates = 0;
80
+ const hashMap = this.toLocaleDocHashMap(strings, locale);
81
+ Object.entries(hashMap).forEach(([hash, translations]) => {
82
+ Object.entries(translations).forEach(([locale2, translation]) => {
83
+ if (translation) {
84
+ updates.strings[hash] ??= {};
85
+ updates.strings[hash][locale2] = translation;
86
+ numUpdates += 1;
87
+ }
88
+ });
89
+ });
90
+ if (numUpdates > 0) {
91
+ const localeDocPath = buildTranslationsLocaleDocDbPath({
92
+ project: this.cmsClient.projectId,
93
+ mode,
94
+ id,
95
+ locale
96
+ });
97
+ const localeDocRef = this.cmsClient.db.doc(localeDocPath);
98
+ batch.set(localeDocRef, updates, { merge: true });
99
+ }
100
+ });
101
+ await batch.commit();
102
+ }
103
+ /**
104
+ * Publishes a translations doc.
105
+ */
106
+ async publishTranslations(id, options) {
107
+ const db = this.cmsClient.db;
108
+ const project = this.cmsClient.projectId;
109
+ const draftPath = buildTranslationsDbPath({ project, mode: "draft" });
110
+ const query = db.collection(draftPath).where("id", "==", id);
111
+ const res = await query.get();
112
+ if (res.size === 0) {
113
+ console.warn(`no translations to publish for ${id}`);
114
+ return;
115
+ }
116
+ const batch = (options == null ? void 0 : options.batch) || db.batch();
117
+ res.docs.forEach((doc) => {
118
+ const translationsLocaleDoc = doc.data();
119
+ const sys = {
120
+ ...translationsLocaleDoc.sys,
121
+ publishedAt: Timestamp.now(),
122
+ publishedBy: (options == null ? void 0 : options.publishedBy) || "root-cms-client"
123
+ };
124
+ batch.update(doc.ref, { sys });
125
+ const publishedDocPath = buildTranslationsLocaleDocDbPath({
126
+ project,
127
+ mode: "published",
128
+ id: translationsLocaleDoc.id,
129
+ locale: translationsLocaleDoc.locale
130
+ });
131
+ const publishedDocRef = db.doc(publishedDocPath);
132
+ batch.set(publishedDocRef, { ...translationsLocaleDoc, sys });
133
+ });
134
+ const shouldCommitBatch = !(options == null ? void 0 : options.batch);
135
+ if (shouldCommitBatch) {
136
+ await batch.commit();
137
+ }
138
+ }
139
+ /**
140
+ * Fetches translations from one or more translations docs in the translations
141
+ * manager.
142
+ *
143
+ * Example:
144
+ * ```
145
+ * await tm.loadTranslations();
146
+ * // =>
147
+ * // {
148
+ * // "one": {"es": "uno", "fr": "un"},
149
+ * // "two": {"es": "dos", "fr": "deux"}
150
+ * // }
151
+ * ```
152
+ *
153
+ * To load a specific set of translations docs by id:
154
+ * ```
155
+ * const translationsToLoad = ['Global/strings', 'Global/header', 'Global/footer', 'Pages/index'];
156
+ * await tm.loadTranslations({ids: translationsToLoad});
157
+ * // =>
158
+ * // {
159
+ * // "one": {"es": "uno", "fr": "un"},
160
+ * // "two": {"es": "dos", "fr": "deux"}
161
+ * // }
162
+ * ```
163
+ *
164
+ * To load a subset of locales (more performant):
165
+ * ```
166
+ * await tm.loadTranslations({locales: ['es']});
167
+ * // =>
168
+ * // {
169
+ * // "one": {"es": "uno"},
170
+ * // "two": {"es": "dos"}
171
+ * // }
172
+ * ```
173
+ */
174
+ async loadTranslations(options) {
175
+ const mode = (options == null ? void 0 : options.mode) || "published";
176
+ const dbPath = buildTranslationsDbPath({
177
+ project: this.cmsClient.projectId,
178
+ mode
179
+ });
180
+ let query = this.cmsClient.db.collection(dbPath);
181
+ if ((options == null ? void 0 : options.ids) && options.ids.length > 0) {
182
+ query = query.where("id", "in", options.ids);
183
+ }
184
+ if ((options == null ? void 0 : options.tags) && options.tags.length > 0) {
185
+ query = query.where("tags", "array-contains", options.tags);
186
+ }
187
+ if ((options == null ? void 0 : options.locales) && options.locales.length > 0) {
188
+ query = query.where("locale", "in", options.locales);
189
+ }
190
+ const results = await query.get();
191
+ const strings = {};
192
+ results.forEach((result) => {
193
+ const localeDoc = result.data();
194
+ Object.values(localeDoc.strings || {}).forEach((item) => {
195
+ strings[item.source] ??= { source: item.source };
196
+ strings[item.source][localeDoc.locale] = item.translation;
197
+ });
198
+ });
199
+ return strings;
200
+ }
201
+ /**
202
+ * Fetches translations for a given locale, with optional fallbacks.
203
+ * The return value is a map of source string to translated string.
204
+ *
205
+ * Example:
206
+ * ```
207
+ * await translationsDoc.loadTranslationsForLocale('es');
208
+ * // =>
209
+ * // {
210
+ * // "one": "uno",
211
+ * // "two": "dos",
212
+ * // }
213
+ * ```
214
+ */
215
+ async loadTranslationsForLocale(locale, options) {
216
+ const localeSet = /* @__PURE__ */ new Set([
217
+ locale,
218
+ ...(options == null ? void 0 : options.fallbackLocales) || []
219
+ ]);
220
+ const fallbackLocales = Array.from(localeSet);
221
+ const multiLocaleStrings = await this.loadTranslations({
222
+ mode: options == null ? void 0 : options.mode,
223
+ locales: fallbackLocales
224
+ });
225
+ return this.toSingleLocaleMap(multiLocaleStrings, fallbackLocales);
226
+ }
227
+ /**
228
+ * Converts a multi-locale translations map to a flat single-locale map,
229
+ * with optional support for fallback locales.
230
+ *
231
+ * ```
232
+ * const multiLocaleStrings = {
233
+ * 'one': {es: 'uno', fr: 'un'},
234
+ * 'two': {es: 'dos', fr: 'deux'}
235
+ * };
236
+ * translationsDoc.toSingleLocaleMap(multiLocaleStrings, ['es']);
237
+ * // =>
238
+ * // {
239
+ * // "one": "uno",
240
+ * // "two": "dos",
241
+ * // }
242
+ * ```
243
+ */
244
+ toSingleLocaleMap(multiLocaleStrings, fallbackLocales) {
245
+ const singleLocaleStrings = {};
246
+ Object.entries(multiLocaleStrings).forEach(([source, translations]) => {
247
+ let translation = source;
248
+ for (const locale of fallbackLocales) {
249
+ if (translations[locale]) {
250
+ translation = translations[locale];
251
+ break;
252
+ }
253
+ }
254
+ singleLocaleStrings[source] = translation;
255
+ });
256
+ return singleLocaleStrings;
257
+ }
258
+ /**
259
+ * Converts a multi-locale translations map to a single-locale hashed version,
260
+ * used for storage in in the DB.
261
+ *
262
+ * ```
263
+ * const multiLocaleStrings = {
264
+ * 'one': {es: 'uno', fr: 'un'},
265
+ * 'two': {es: 'dos', fr: 'deux'}
266
+ * };
267
+ * translationsDoc.toLocaleDocHashMap(multiLocaleStrings, 'es');
268
+ * // =>
269
+ * // {
270
+ * // "<hash1>": {"source": "one", "translation": "uno"},
271
+ * // "<hash2>": {"source": "two", "translation": "dos"},
272
+ * // }
273
+ * ```
274
+ *
275
+ * One reason for using hashes is because the DB has limits on the number of
276
+ * chars that can be used as the "key" in a object map.
277
+ */
278
+ toLocaleDocHashMap(multiLocaleStrings, locale) {
279
+ const hashMap = {};
280
+ Object.entries(multiLocaleStrings).forEach(([source, translations]) => {
281
+ const translation = translations[locale];
282
+ if (translation) {
283
+ const hash = hashStr(source);
284
+ hashMap[hash] = { source, translation };
285
+ }
286
+ });
287
+ return hashMap;
288
+ }
289
+ /**
290
+ * Import translations from the v1 system to the TranslationsManager.
291
+ */
292
+ async importTranslationsFromV1() {
293
+ var _a;
294
+ const projectId = this.cmsClient.projectId;
295
+ const db = this.cmsClient.db;
296
+ const dbPath = `Projects/${projectId}/Translations`;
297
+ const query = db.collection(dbPath);
298
+ const querySnapshot = await query.get();
299
+ if (querySnapshot.size === 0) {
300
+ return;
301
+ }
302
+ console.log(
303
+ "[root cms] importing v1 Translations to v2 TranslationsManager"
304
+ );
305
+ const translationsDocs = {};
306
+ querySnapshot.forEach((doc) => {
307
+ const translation = doc.data();
308
+ const source = this.cmsClient.normalizeString(translation.source);
309
+ delete translation.source;
310
+ const tags = translation.tags || [];
311
+ delete translation.tags;
312
+ for (const tag of tags) {
313
+ if (tag.includes("/")) {
314
+ const translationsId = tag;
315
+ translationsDocs[translationsId] ??= {
316
+ id: translationsId,
317
+ tags,
318
+ strings: {}
319
+ };
320
+ translationsDocs[translationsId].strings[source] = translation;
321
+ }
322
+ }
323
+ });
324
+ if (Object.keys(translationsDocs).length === 0) {
325
+ console.log("[root cms] no v1 translations to save");
326
+ return;
327
+ }
328
+ for (const docId in translationsDocs) {
329
+ const [collection, slug] = docId.split("/");
330
+ if (collection && slug) {
331
+ const doc = await this.cmsClient.getDoc(collection, slug, {
332
+ mode: "draft"
333
+ });
334
+ const linkedSheet = (_a = doc == null ? void 0 : doc.sys) == null ? void 0 : _a.l10nSheet;
335
+ if (linkedSheet) {
336
+ translationsDocs[docId].sys.linkedSheet = linkedSheet;
337
+ }
338
+ }
339
+ }
340
+ Object.entries(translationsDocs).forEach(([translationsId, data]) => {
341
+ const len = Object.keys(data.strings).length;
342
+ console.log(`[root cms] saving ${len} string(s) to ${translationsId}...`);
343
+ this.saveTranslations(translationsId, data.strings, {
344
+ tags: data.tags || [translationsId]
345
+ });
346
+ });
347
+ }
348
+ };
349
+ function buildTranslationsDbPath(options) {
350
+ return TRANSLATIONS_DB_PATH_FORMAT.replace(
351
+ "{project}",
352
+ options.project
353
+ ).replace("{mode}", options.mode);
354
+ }
355
+ function buildTranslationsLocaleDocDbPath(options) {
356
+ return TRANSLATIONS_LOCALE_DOC_DB_PATH_FORMAT.replace(
357
+ "{project}",
358
+ options.project
359
+ ).replace("{mode}", options.mode).replace("{id}", options.id.replaceAll("/", "--")).replace("{locale}", options.locale);
55
360
  }
56
361
 
57
362
  // core/client.ts
@@ -80,13 +385,19 @@ var RootCMSClient = class {
80
385
  */
81
386
  async getRawDoc(collectionId, slug, options) {
82
387
  const mode = options.mode;
83
- const docRef = this.dbDocRef(collectionId, slug, { mode });
388
+ const modeCollection = mode === "draft" ? "Drafts" : "Published";
389
+ slug = slug.replaceAll("/", "--");
390
+ const dbPath = `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}/${slug}`;
391
+ const docRef = this.db.doc(dbPath);
84
392
  const doc = await docRef.get();
85
393
  if (doc.exists) {
86
394
  return doc.data();
87
395
  }
88
396
  return null;
89
397
  }
398
+ /**
399
+ * Firestore path for a collection.
400
+ */
90
401
  dbCollectionDocsPath(collectionId, options) {
91
402
  let modeCollection = "";
92
403
  if (options.mode === "draft") {
@@ -98,11 +409,17 @@ var RootCMSClient = class {
98
409
  }
99
410
  return `Projects/${this.projectId}/Collections/${collectionId}/${modeCollection}`;
100
411
  }
412
+ /**
413
+ * Firestore path for a content doc.
414
+ */
101
415
  dbDocPath(collectionId, slug, options) {
102
416
  const collectionDocsPath = this.dbCollectionDocsPath(collectionId, options);
103
417
  const normalizedSlug = slug.replaceAll("/", "--");
104
418
  return `${collectionDocsPath}/${normalizedSlug}`;
105
419
  }
420
+ /**
421
+ * Firestore doc ref for a content doc.
422
+ */
106
423
  dbDocRef(collectionId, slug, options) {
107
424
  const docPath = this.dbDocPath(collectionId, slug, options);
108
425
  return this.db.doc(docPath);
@@ -125,9 +442,9 @@ var RootCMSClient = class {
125
442
  slug,
126
443
  sys: {
127
444
  ...draftSys,
128
- createdAt: draftSys.createdAt ?? Timestamp3.now(),
445
+ createdAt: draftSys.createdAt ?? Timestamp2.now(),
129
446
  createdBy: draftSys.createdBy ?? modifiedBy,
130
- modifiedAt: Timestamp3.now(),
447
+ modifiedAt: Timestamp2.now(),
131
448
  modifiedBy,
132
449
  locales: (options == null ? void 0 : options.locales) ?? draftSys.locales ?? ["en"]
133
450
  },
@@ -223,6 +540,10 @@ var RootCMSClient = class {
223
540
  }
224
541
  let batchCount = 0;
225
542
  const batch = (options == null ? void 0 : options.batch) || this.db.batch();
543
+ const versionTags = ["published"];
544
+ if (options == null ? void 0 : options.releaseId) {
545
+ versionTags.push(`release:${options.releaseId}`);
546
+ }
226
547
  const publishedDocs = [];
227
548
  for (const doc of docs) {
228
549
  const { id, collection, slug, sys, fields } = doc;
@@ -235,7 +556,7 @@ var RootCMSClient = class {
235
556
  const publishedRef = this.db.doc(
236
557
  `${projectCollectionsPath}/${collection}/Published/${slug}`
237
558
  );
238
- const firstPublishedAt = sys.firstPublishedAt ?? FieldValue.serverTimestamp();
559
+ const firstPublishedAt = sys.firstPublishedAt ?? FieldValue2.serverTimestamp();
239
560
  const firstPublishedBy = sys.firstPublishedBy ?? publishedBy;
240
561
  batch.set(publishedRef, {
241
562
  id,
@@ -246,24 +567,43 @@ var RootCMSClient = class {
246
567
  ...sys,
247
568
  firstPublishedAt,
248
569
  firstPublishedBy,
249
- publishedAt: FieldValue.serverTimestamp(),
570
+ publishedAt: FieldValue2.serverTimestamp(),
250
571
  publishedBy
251
572
  }
252
573
  });
253
574
  batchCount += 1;
575
+ const versionRef = this.db.doc(
576
+ `${projectCollectionsPath}/${collection}/Drafts/${slug}/Versions/${Date.now()}`
577
+ );
578
+ const versionData = {
579
+ id,
580
+ collection,
581
+ slug,
582
+ fields: fields || {},
583
+ sys: {
584
+ ...sys,
585
+ firstPublishedAt,
586
+ firstPublishedBy,
587
+ publishedAt: FieldValue2.serverTimestamp(),
588
+ publishedBy
589
+ }
590
+ };
591
+ if (versionTags.length) {
592
+ versionData.tags = versionTags;
593
+ }
594
+ batch.set(versionRef, versionData);
595
+ batchCount += 1;
254
596
  batch.delete(scheduledRef);
255
597
  batchCount += 1;
256
598
  batch.update(draftRef, {
257
- "sys.scheduledAt": FieldValue.delete(),
258
- "sys.scheduledBy": FieldValue.delete(),
599
+ "sys.scheduledAt": FieldValue2.delete(),
600
+ "sys.scheduledBy": FieldValue2.delete(),
259
601
  "sys.firstPublishedAt": firstPublishedAt,
260
602
  "sys.firstPublishedBy": firstPublishedBy,
261
- "sys.publishedAt": FieldValue.serverTimestamp(),
603
+ "sys.publishedAt": FieldValue2.serverTimestamp(),
262
604
  "sys.publishedBy": publishedBy
263
605
  });
264
606
  batchCount += 1;
265
- this.publishTranslationsDoc(doc.id, { batch });
266
- batchCount += 2;
267
607
  publishedDocs.push(doc);
268
608
  if (batchCount >= 400) {
269
609
  await batch.commit();
@@ -310,6 +650,7 @@ var RootCMSClient = class {
310
650
  }
311
651
  let batchCount = 0;
312
652
  const batch = this.db.batch();
653
+ const versionTags = ["published"];
313
654
  const publishedDocs = [];
314
655
  for (const doc of docs) {
315
656
  const { id, collection, slug, data } = doc;
@@ -334,24 +675,41 @@ var RootCMSClient = class {
334
675
  ...sys,
335
676
  firstPublishedAt,
336
677
  firstPublishedBy,
337
- publishedAt: FieldValue.serverTimestamp(),
678
+ publishedAt: FieldValue2.serverTimestamp(),
338
679
  publishedBy: scheduledBy || ""
339
680
  }
340
681
  });
341
682
  batchCount += 1;
683
+ const versionRef = this.db.doc(
684
+ `${projectCollectionsPath}/${collection}/Drafts/${slug}/Versions/${Date.now()}`
685
+ );
686
+ const versionData = {
687
+ id,
688
+ collection,
689
+ slug,
690
+ fields: data.fields || {},
691
+ sys: {
692
+ ...sys,
693
+ firstPublishedAt,
694
+ firstPublishedBy,
695
+ publishedAt: FieldValue2.serverTimestamp(),
696
+ publishedBy: scheduledBy || ""
697
+ },
698
+ tags: versionTags
699
+ };
700
+ batch.set(versionRef, versionData);
701
+ batchCount += 1;
342
702
  batch.delete(scheduledRef);
343
703
  batchCount += 1;
344
704
  batch.update(draftRef, {
345
- "sys.scheduledAt": FieldValue.delete(),
346
- "sys.scheduledBy": FieldValue.delete(),
705
+ "sys.scheduledAt": FieldValue2.delete(),
706
+ "sys.scheduledBy": FieldValue2.delete(),
347
707
  "sys.firstPublishedAt": firstPublishedAt,
348
708
  "sys.firstPublishedBy": firstPublishedBy,
349
- "sys.publishedAt": FieldValue.serverTimestamp(),
709
+ "sys.publishedAt": FieldValue2.serverTimestamp(),
350
710
  "sys.publishedBy": scheduledBy || "root-cms-client"
351
711
  });
352
712
  batchCount += 1;
353
- this.publishTranslationsDoc(doc.id, { batch });
354
- batchCount += 2;
355
713
  publishedDocs.push(doc);
356
714
  if (batchCount >= 400) {
357
715
  await batch.commit();
@@ -371,50 +729,31 @@ var RootCMSClient = class {
371
729
  async publishScheduledReleases() {
372
730
  const releasesPath = `Projects/${this.projectId}/Releases`;
373
731
  const now = Math.ceil((/* @__PURE__ */ new Date()).getTime());
374
- const query = this.db.collection(releasesPath).where("scheduledAt", "<=", Timestamp3.fromMillis(now));
732
+ const query = this.db.collection(releasesPath).where("scheduledAt", "<=", Timestamp2.fromMillis(now));
375
733
  const querySnapshot = await query.get();
376
734
  for (const snapshot of querySnapshot.docs) {
377
735
  const release = snapshot.data();
378
736
  const batch = this.db.batch();
379
737
  const publishedBy = release.scheduledBy || "root-cms-client";
380
738
  batch.update(snapshot.ref, {
381
- publishedAt: Timestamp3.now(),
739
+ publishedAt: Timestamp2.now(),
382
740
  publishedBy,
383
- scheduledAt: FieldValue.delete(),
384
- scheduledBy: FieldValue.delete()
741
+ scheduledAt: FieldValue2.delete(),
742
+ scheduledBy: FieldValue2.delete()
743
+ });
744
+ const dataSourceIds = release.dataSourceIds || [];
745
+ if (dataSourceIds.length > 0) {
746
+ await this.publishDataSources(dataSourceIds, {
747
+ publishedBy,
748
+ batch,
749
+ commitBatch: false
750
+ });
751
+ }
752
+ await this.publishDocs(release.docIds || [], {
753
+ publishedBy,
754
+ batch,
755
+ releaseId: release.id
385
756
  });
386
- await this.publishDocs(release.docIds || [], { publishedBy, batch });
387
- }
388
- }
389
- async publishTranslationsDoc(translationsId, options) {
390
- const docSlug = translationsId.replaceAll("/", "--");
391
- const draftRef = this.db.doc(
392
- `Projects/${this.projectId}/TranslationsManager/draft/Translations/${docSlug}`
393
- );
394
- const snapshot = await draftRef.get();
395
- if (!snapshot.exists) {
396
- console.warn(`translations ${translationsId} does not exist`);
397
- return;
398
- }
399
- const commitBatch = !(options == null ? void 0 : options.batch);
400
- const batch = (options == null ? void 0 : options.batch) || this.db.batch();
401
- batch.update(draftRef, {
402
- "sys.publishedAt": Timestamp3.now(),
403
- "sys.publishedBy": (options == null ? void 0 : options.publishedBy) || "root-cms-client"
404
- });
405
- const publishedRef = this.db.doc(
406
- `Projects/${this.projectId}/TranslationsManager/published/Translations/${docSlug}`
407
- );
408
- const data = { ...snapshot.data() };
409
- if (!data.sys) {
410
- data.sys = {};
411
- }
412
- data.sys.publishedAt = Timestamp3.now();
413
- data.sys.publishedBy = (options == null ? void 0 : options.publishedBy) || "root-cms-client";
414
- batch.set(publishedRef, data);
415
- if (commitBatch) {
416
- await batch.commit();
417
- this.logAction("translations.publish", { metadata: { translationsId } });
418
757
  }
419
758
  }
420
759
  /**
@@ -424,7 +763,7 @@ var RootCMSClient = class {
424
763
  var _a;
425
764
  if ((_a = doc.sys) == null ? void 0 : _a.publishingLocked) {
426
765
  if (doc.sys.publishingLocked.until) {
427
- const now = Timestamp3.now().toMillis();
766
+ const now = Timestamp2.now().toMillis();
428
767
  const until = doc.sys.publishingLocked.until.toMillis();
429
768
  return now < until;
430
769
  }
@@ -433,36 +772,51 @@ var RootCMSClient = class {
433
772
  return false;
434
773
  }
435
774
  /**
436
- * Loads all published strings in the db.
775
+ * Returns a `TranslationsManager` object for managing translations.
776
+ *
777
+ * To get translations:
778
+ * ```
779
+ * await tm.loadTranslations({
780
+ * ids: ['Global/strings', 'Pages/index'],
781
+ * locales: ['es'],
782
+ * });
783
+ * ```
784
+ *
785
+ * NOTE: The `TranslationsManager` is a v2 feature that will eventually
786
+ * replace the v1 translations system.
787
+ */
788
+ getTranslationsManager() {
789
+ var _a;
790
+ const cmsPluginOptions = this.cmsPlugin.getConfig();
791
+ if ((_a = cmsPluginOptions.experiments) == null ? void 0 : _a.v2TranslationsManager) {
792
+ throw new Error(
793
+ "`v2TranslationsManager` is not enabled. update root.config.ts and add: `{experiments: {v2TranslationsManager: true}}`"
794
+ );
795
+ }
796
+ return new TranslationsManager(this);
797
+ }
798
+ /**
799
+ * Loads translations saved in the translations collection, optionally
800
+ * filtered by tag.
437
801
  *
802
+ * Returns a map like:
438
803
  * ```
439
804
  * {
440
805
  * "<hash>": {"source": "Hello", "es": "Hola", "fr": "Bonjour"},
441
806
  * }
442
807
  * ```
443
- *
444
- * @deprecated Use `createBatchRequest()` to fetch draft/published translations.
445
808
  */
446
809
  async loadTranslations(options) {
447
- const dbPath = `Projects/${this.projectId}/TranslationsManager/published/Translations`;
448
- const translationsMap = {};
449
- const addTranslations = (hash, translations) => {
450
- translationsMap[hash] = Object.assign(
451
- translationsMap[hash] || {},
452
- translations
453
- );
454
- };
810
+ const dbPath = `Projects/${this.projectId}/Translations`;
455
811
  let query = this.db.collection(dbPath);
456
- if ((options == null ? void 0 : options.tags) && options.tags.length > 0) {
457
- query = query.where("sys.tags", "array-contains-any", options.tags);
458
- }
459
- const snapshot = await query.get();
460
- snapshot.forEach((doc) => {
461
- const data = doc.data();
462
- const strings = data.strings || {};
463
- Object.entries(strings).forEach(([hash, translations]) => {
464
- addTranslations(hash, translations);
465
- });
812
+ if (options == null ? void 0 : options.tags) {
813
+ query = query.where("tags", "array-contains-any", options.tags);
814
+ }
815
+ const querySnapshot = await query.get();
816
+ const translationsMap = {};
817
+ querySnapshot.forEach((doc) => {
818
+ const hash = doc.id;
819
+ translationsMap[hash] = doc.data();
466
820
  });
467
821
  return translationsMap;
468
822
  }
@@ -473,9 +827,6 @@ var RootCMSClient = class {
473
827
  * "Hello": {"es": "Hola", "fr": "Bonjour"},
474
828
  * });
475
829
  * ```
476
- *
477
- * @deprecated Use `saveDraftTranslations()` and `publishTranslations()`
478
- * instead.
479
830
  */
480
831
  async saveTranslations(translations, tags) {
481
832
  const translationsPath = `Projects/${this.projectId}/Translations`;
@@ -489,7 +840,7 @@ var RootCMSClient = class {
489
840
  source: this.normalizeString(source)
490
841
  };
491
842
  if (tags) {
492
- data.tags = tags;
843
+ data.tags = FieldValue2.arrayUnion(...tags);
493
844
  }
494
845
  batch.set(translationRef, data, { merge: true });
495
846
  batchCount += 1;
@@ -499,34 +850,12 @@ var RootCMSClient = class {
499
850
  }
500
851
  await batch.commit();
501
852
  }
502
- async saveDraftTranslations(translationsId, translations, options) {
503
- const docSlug = translationsId.replaceAll("/", "--");
504
- const docPath = `Projects/${this.projectId}/TranslationsManager/draft/${docSlug}`;
505
- const docRef = this.db.doc(docPath);
506
- const snapshot = await docRef.get();
507
- const data = snapshot.data() || {
508
- id: translationsId.replaceAll("--", "/"),
509
- sys: {},
510
- strings: {}
511
- };
512
- data.sys.modifiedAt = Timestamp3.now();
513
- data.sys.modifiedBy = (options == null ? void 0 : options.modifiedby) || "root-cms-client";
514
- const strings = data.strings || {};
515
- Object.entries(translations).forEach(([source, row]) => {
516
- const normalizedSource = this.normalizeString(source);
517
- const hash = this.getTranslationKey(normalizedSource);
518
- strings[hash] = { ...strings[hash], ...row, source: normalizedSource };
519
- });
520
- data.strings = strings;
521
- await docRef.set(data);
522
- this.logAction("translations.save", { metadata: { translationsId } });
523
- }
524
853
  /**
525
854
  * Returns the "key" used for a translation as stored in the db. Translations
526
855
  * are stored under `Projects/<project id>/Translations/<sha1 hash>`.
527
856
  */
528
857
  getTranslationKey(source) {
529
- const sha1 = crypto2.createHash("sha1").update(this.normalizeString(source)).digest("hex");
858
+ const sha1 = crypto.createHash("sha1").update(this.normalizeString(source)).digest("hex");
530
859
  return sha1;
531
860
  }
532
861
  /**
@@ -552,6 +881,25 @@ var RootCMSClient = class {
552
881
  const translationsMap = await this.loadTranslations(options);
553
882
  return translationsForLocale(translationsMap, locale);
554
883
  }
884
+ /**
885
+ * Firestore path for a translations file.
886
+ */
887
+ dbTranslationsPath(translationsId, options) {
888
+ const mode = options.mode;
889
+ if (!(mode === "draft" || mode === "published")) {
890
+ throw new Error(`invalid mode: ${mode}`);
891
+ }
892
+ const slug = translationsId.replaceAll("/", "--");
893
+ const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
894
+ return dbPath;
895
+ }
896
+ /**
897
+ * Firestore doc ref for a translations file.
898
+ */
899
+ dbTranslationsRef(translationsId, options) {
900
+ const dbPath = this.dbTranslationsPath(translationsId, options);
901
+ return this.db.doc(dbPath);
902
+ }
555
903
  /**
556
904
  * Returns a data source configuration object.
557
905
  */
@@ -582,7 +930,7 @@ var RootCMSClient = class {
582
930
  const syncedBy = (options == null ? void 0 : options.syncedBy) || "root-cms-client";
583
931
  const updatedDataSource = {
584
932
  ...dataSource,
585
- syncedAt: Timestamp3.now(),
933
+ syncedAt: Timestamp2.now(),
586
934
  syncedBy
587
935
  };
588
936
  const batch = this.db.batch();
@@ -591,7 +939,7 @@ var RootCMSClient = class {
591
939
  data
592
940
  });
593
941
  batch.update(dataSourceDocRef, {
594
- syncedAt: Timestamp3.now(),
942
+ syncedAt: Timestamp2.now(),
595
943
  syncedBy
596
944
  });
597
945
  await batch.commit();
@@ -616,25 +964,64 @@ var RootCMSClient = class {
616
964
  const publishedBy = (options == null ? void 0 : options.publishedBy) || "root-cms-client";
617
965
  const updatedDataSource = {
618
966
  ...dataSource,
619
- publishedAt: Timestamp3.now(),
967
+ publishedAt: Timestamp2.now(),
620
968
  publishedBy
621
969
  };
622
970
  const batch = this.db.batch();
623
971
  batch.set(dataDocRefPublished, {
624
972
  dataSource: updatedDataSource,
625
- data: (dataRes == null ? void 0 : dataRes.data) || null
973
+ data: (dataRes == null ? void 0 : dataRes.data) || null,
974
+ ...(dataRes == null ? void 0 : dataRes.headers) ? { headers: dataRes.headers } : {}
626
975
  });
627
976
  batch.update(dataDocRefDraft, {
628
977
  dataSource: updatedDataSource
629
978
  });
630
979
  batch.update(dataSourceDocRef, {
631
- publishedAt: Timestamp3.now(),
980
+ publishedAt: Timestamp2.now(),
632
981
  publishedBy
633
982
  });
634
983
  await batch.commit();
635
984
  console.log(`published data ${dataSourceId}`);
636
985
  console.log(`published by: ${publishedBy}`);
637
986
  }
987
+ async publishDataSources(dataSourceIds, options) {
988
+ const publishedBy = (options == null ? void 0 : options.publishedBy) || "root-cms-client";
989
+ const batch = (options == null ? void 0 : options.batch) || this.db.batch();
990
+ for (const id of dataSourceIds) {
991
+ const dataSource = await this.getDataSource(id);
992
+ if (!dataSource) {
993
+ throw new Error(`data source not found: ${id}`);
994
+ }
995
+ const dataSourceDocRef = this.db.doc(
996
+ `Projects/${this.projectId}/DataSources/${id}`
997
+ );
998
+ const dataDocRefDraft = this.db.doc(
999
+ `Projects/${this.projectId}/DataSources/${id}/draft`
1000
+ );
1001
+ const dataDocRefPublished = this.db.doc(
1002
+ `Projects/${this.projectId}/DataSources/${id}/published`
1003
+ );
1004
+ const dataRes = await this.getFromDataSource(id, { mode: "draft" });
1005
+ const updatedDataSource = {
1006
+ ...dataSource,
1007
+ publishedAt: FieldValue2.serverTimestamp(),
1008
+ publishedBy
1009
+ };
1010
+ batch.set(dataDocRefPublished, {
1011
+ dataSource: updatedDataSource,
1012
+ data: (dataRes == null ? void 0 : dataRes.data) || null,
1013
+ ...(dataRes == null ? void 0 : dataRes.headers) ? { headers: dataRes.headers } : {}
1014
+ });
1015
+ batch.update(dataDocRefDraft, { dataSource: updatedDataSource });
1016
+ batch.update(dataSourceDocRef, {
1017
+ publishedAt: FieldValue2.serverTimestamp(),
1018
+ publishedBy
1019
+ });
1020
+ }
1021
+ if (!(options == null ? void 0 : options.batch) || (options == null ? void 0 : options.commitBatch)) {
1022
+ await batch.commit();
1023
+ }
1024
+ }
638
1025
  async fetchData(dataSource) {
639
1026
  if (dataSource.type === "http") {
640
1027
  return await this.fetchHttpData(dataSource);
@@ -667,6 +1054,12 @@ var RootCMSClient = class {
667
1054
  */
668
1055
  async getFromDataSource(dataSourceId, options) {
669
1056
  const mode = (options == null ? void 0 : options.mode) || "published";
1057
+ if (!(mode === "draft" || mode === "published")) {
1058
+ throw new Error(`invalid mode: ${mode}`);
1059
+ }
1060
+ if (!dataSourceId || dataSourceId.includes("/")) {
1061
+ throw new Error(`invalid data source id: ${dataSourceId}`);
1062
+ }
670
1063
  const docRef = this.dbDataSourceDataRef(dataSourceId, { mode });
671
1064
  const doc = await docRef.get();
672
1065
  if (doc.exists) {
@@ -674,6 +1067,9 @@ var RootCMSClient = class {
674
1067
  }
675
1068
  return null;
676
1069
  }
1070
+ /**
1071
+ * Firestore path for a datasource data.
1072
+ */
677
1073
  dbDataSourceDataPath(dataSourceId, options) {
678
1074
  if (!dataSourceId || dataSourceId.includes("/")) {
679
1075
  throw new Error(`invalid data source id: ${dataSourceId}`);
@@ -685,23 +1081,13 @@ var RootCMSClient = class {
685
1081
  const dbPath = `Projects/${this.projectId}/DataSources/${dataSourceId}/Data/${mode}`;
686
1082
  return dbPath;
687
1083
  }
1084
+ /**
1085
+ * Firestore doc ref for a datasource data.
1086
+ */
688
1087
  dbDataSourceDataRef(dataSourceId, options) {
689
1088
  const dbPath = this.dbDataSourceDataPath(dataSourceId, options);
690
1089
  return this.db.doc(dbPath);
691
1090
  }
692
- dbTranslationsPath(translationsId, options) {
693
- const mode = options.mode;
694
- if (!(mode === "draft" || mode === "published")) {
695
- throw new Error(`invalid mode: ${mode}`);
696
- }
697
- const slug = translationsId.replaceAll("/", "--");
698
- const dbPath = `Projects/${this.projectId}/TranslationsManager/${mode}/Translations/${slug}`;
699
- return dbPath;
700
- }
701
- dbTranslationsRef(translationsId, options) {
702
- const dbPath = this.dbTranslationsPath(translationsId, options);
703
- return this.db.doc(dbPath);
704
- }
705
1091
  /**
706
1092
  * Gets the user's role from the project's ACL.
707
1093
  */
@@ -756,7 +1142,7 @@ var RootCMSClient = class {
756
1142
  }
757
1143
  const data = {
758
1144
  action,
759
- timestamp: Timestamp3.now(),
1145
+ timestamp: Timestamp2.now(),
760
1146
  by: (options == null ? void 0 : options.by) || "system",
761
1147
  metadata: (options == null ? void 0 : options.metadata) || {}
762
1148
  };
@@ -773,11 +1159,148 @@ var RootCMSClient = class {
773
1159
  }
774
1160
  }
775
1161
  }
1162
+ /**
1163
+ * Creates a batch request that is capable of fetching one or more docs,
1164
+ * corresponding translations, and dataSources.
1165
+ */
776
1166
  createBatchRequest(options) {
777
1167
  return new BatchRequest(this, options);
778
1168
  }
779
1169
  };
780
- var BatchRequest = class {
1170
+ function isRichTextData(data) {
1171
+ return Boolean(
1172
+ isObject(data) && Array.isArray(data.blocks) && data.time && data.version
1173
+ );
1174
+ }
1175
+ function getCmsPlugin(rootConfig) {
1176
+ const plugins = rootConfig.plugins || [];
1177
+ const plugin = plugins.find((plugin2) => plugin2.name === "root-cms");
1178
+ if (!plugin) {
1179
+ throw new Error("could not find root-cms plugin config in root.config.ts");
1180
+ }
1181
+ return plugin;
1182
+ }
1183
+ function marshalData(data) {
1184
+ if (isRichTextData(data)) {
1185
+ return data;
1186
+ }
1187
+ const result = {};
1188
+ for (const key in data) {
1189
+ const val = data[key];
1190
+ if (isObject(val)) {
1191
+ result[key] = marshalData(val);
1192
+ } else if (Array.isArray(val)) {
1193
+ if (val.length > 0 && val.some((item) => isObject(item))) {
1194
+ const items = val.map((item) => {
1195
+ if (isObject(item)) {
1196
+ return marshalData(item);
1197
+ }
1198
+ return item;
1199
+ });
1200
+ result[key] = toArrayObject(items);
1201
+ } else {
1202
+ result[key] = val;
1203
+ }
1204
+ } else {
1205
+ result[key] = val;
1206
+ }
1207
+ }
1208
+ return result;
1209
+ }
1210
+ function unmarshalData(data) {
1211
+ const result = {};
1212
+ for (const key in data) {
1213
+ const val = data[key];
1214
+ if (isObject(val)) {
1215
+ if (val.toMillis) {
1216
+ result[key] = val.toMillis();
1217
+ } else if (Object.hasOwn(val, "_array") && Array.isArray(val._array)) {
1218
+ const arr = val._array.map((arrayKey) => {
1219
+ return {
1220
+ ...unmarshalData(val[arrayKey] || {}),
1221
+ _arrayKey: arrayKey
1222
+ };
1223
+ });
1224
+ result[key] = arr;
1225
+ } else {
1226
+ result[key] = unmarshalData(val);
1227
+ }
1228
+ } else {
1229
+ result[key] = val;
1230
+ }
1231
+ }
1232
+ return result;
1233
+ }
1234
+ function toArrayObject(arr) {
1235
+ if (!Array.isArray(arr)) {
1236
+ return arr;
1237
+ }
1238
+ const arrObject = { _array: [] };
1239
+ for (const item of arr) {
1240
+ const key = randString(6);
1241
+ arrObject[key] = item;
1242
+ arrObject._array.push(key);
1243
+ }
1244
+ return arrObject;
1245
+ }
1246
+ function isObject(data) {
1247
+ return typeof data === "object" && !Array.isArray(data) && data !== null;
1248
+ }
1249
+ function randString(len) {
1250
+ const result = [];
1251
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1252
+ for (let i = 0; i < len; i++) {
1253
+ const rand = Math.floor(Math.random() * chars.length);
1254
+ result.push(chars.charAt(rand));
1255
+ }
1256
+ return result.join("");
1257
+ }
1258
+ function translationsForLocale(translationsMap, locale) {
1259
+ const localeTranslations = {};
1260
+ Object.values(translationsMap).forEach((string) => {
1261
+ const source = string.source;
1262
+ const translation = string[locale] || string.en || string.source;
1263
+ localeTranslations[source] = translation;
1264
+ });
1265
+ return localeTranslations;
1266
+ }
1267
+ function stringifyObj(obj) {
1268
+ function format(obj2) {
1269
+ if (obj2 === null) {
1270
+ return "null";
1271
+ }
1272
+ if (typeof obj2 === "undefined") {
1273
+ return "undefined";
1274
+ }
1275
+ if (typeof obj2 === "string") {
1276
+ return `"${obj2.replaceAll('"', '\\"')}"`;
1277
+ }
1278
+ if (typeof obj2 !== "object") {
1279
+ return String(obj2);
1280
+ }
1281
+ if (Array.isArray(obj2)) {
1282
+ return `[${obj2.map(format).join(", ")}]`;
1283
+ }
1284
+ const entries = Object.entries(obj2).map(([key, value]) => {
1285
+ return `${key}: ${format(value)}`;
1286
+ });
1287
+ return `{${entries.join(", ")}}`;
1288
+ }
1289
+ return format(obj);
1290
+ }
1291
+ function parseDocId(docId) {
1292
+ const sepIndex = docId.indexOf("/");
1293
+ if (sepIndex <= 0) {
1294
+ throw new Error(`invalid doc id: ${docId}`);
1295
+ }
1296
+ const collection = docId.slice(0, sepIndex);
1297
+ const slug = docId.slice(sepIndex + 1).replaceAll("/", "--");
1298
+ if (!collection || !slug) {
1299
+ throw new Error(`invalid doc id: ${docId}`);
1300
+ }
1301
+ return { collection, slug };
1302
+ }
1303
+ var BatchRequest = class {
781
1304
  constructor(cmsClient, options) {
782
1305
  this.docIds = [];
783
1306
  this.dataSourceIds = [];
@@ -946,6 +1469,8 @@ var BatchResponse = class {
946
1469
  * The input is either a single locale (e.g. "de") or an array of locales
947
1470
  * representing the fallback tree, e.g. ["en-CA", "en-GB", "en"].
948
1471
  *
1472
+ * TODO(stevenle): support the locale fallback tree.
1473
+ *
949
1474
  * The returned value is a flat map of source string to translated string,
950
1475
  * e.g.:
951
1476
  * {"<source>": "<translation>"}
@@ -979,145 +1504,10 @@ var BatchResponse = class {
979
1504
  return translationsMap;
980
1505
  }
981
1506
  };
982
- function isRichTextData(data) {
983
- return Boolean(
984
- isObject(data) && Array.isArray(data.blocks) && data.time && data.version
985
- );
986
- }
987
- function marshalData(data) {
988
- if (isRichTextData(data)) {
989
- return data;
990
- }
991
- const result = {};
992
- for (const key in data) {
993
- const val = data[key];
994
- if (isObject(val)) {
995
- result[key] = marshalData(val);
996
- } else if (Array.isArray(val)) {
997
- if (val.length > 0 && val.some((item) => isObject(item))) {
998
- const items = val.map((item) => {
999
- if (isObject(item)) {
1000
- return marshalData(item);
1001
- }
1002
- return item;
1003
- });
1004
- result[key] = toArrayObject(items);
1005
- } else {
1006
- result[key] = val;
1007
- }
1008
- } else {
1009
- result[key] = val;
1010
- }
1011
- }
1012
- return result;
1013
- }
1014
- function unmarshalData(data) {
1015
- const result = {};
1016
- for (const key in data) {
1017
- const val = data[key];
1018
- if (isObject(val)) {
1019
- if (val.toMillis) {
1020
- result[key] = val.toMillis();
1021
- } else if (Object.hasOwn(val, "_array") && Array.isArray(val._array)) {
1022
- const arr = val._array.map((arrayKey) => {
1023
- return {
1024
- ...unmarshalData(val[arrayKey] || {}),
1025
- _arrayKey: arrayKey
1026
- };
1027
- });
1028
- result[key] = arr;
1029
- } else {
1030
- result[key] = unmarshalData(val);
1031
- }
1032
- } else {
1033
- result[key] = val;
1034
- }
1035
- }
1036
- return result;
1037
- }
1038
- function toArrayObject(arr) {
1039
- if (!Array.isArray(arr)) {
1040
- return arr;
1041
- }
1042
- const arrObject = { _array: [] };
1043
- for (const item of arr) {
1044
- const key = randString(6);
1045
- arrObject[key] = item;
1046
- arrObject._array.push(key);
1047
- }
1048
- return arrObject;
1049
- }
1050
- function isObject(data) {
1051
- return typeof data === "object" && !Array.isArray(data) && data !== null;
1052
- }
1053
- function randString(len) {
1054
- const result = [];
1055
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1056
- for (let i = 0; i < len; i++) {
1057
- const rand = Math.floor(Math.random() * chars.length);
1058
- result.push(chars.charAt(rand));
1059
- }
1060
- return result.join("");
1061
- }
1062
- function translationsForLocale(translationsMap, locale) {
1063
- const localeTranslations = {};
1064
- const fallbackLocales = Array.isArray(locale) ? locale : [locale];
1065
- if (!fallbackLocales.includes("en")) {
1066
- fallbackLocales.push("en");
1067
- }
1068
- Object.values(translationsMap).forEach((string) => {
1069
- const source = string.source;
1070
- let translation = source;
1071
- for (const fallbackLocale of fallbackLocales) {
1072
- if (string[fallbackLocale]) {
1073
- translation = string[fallbackLocale];
1074
- break;
1075
- }
1076
- }
1077
- localeTranslations[source] = translation;
1078
- });
1079
- return localeTranslations;
1080
- }
1081
- function stringifyObj(obj) {
1082
- function format(obj2) {
1083
- if (obj2 === null) {
1084
- return "null";
1085
- }
1086
- if (typeof obj2 === "undefined") {
1087
- return "undefined";
1088
- }
1089
- if (typeof obj2 === "string") {
1090
- return `"${obj2.replaceAll('"', '\\"')}"`;
1091
- }
1092
- if (typeof obj2 !== "object") {
1093
- return String(obj2);
1094
- }
1095
- if (Array.isArray(obj2)) {
1096
- return `[${obj2.map(format).join(", ")}]`;
1097
- }
1098
- const entries = Object.entries(obj2).map(([key, value]) => {
1099
- return `${key}: ${format(value)}`;
1100
- });
1101
- return `{${entries.join(", ")}}`;
1102
- }
1103
- return format(obj);
1104
- }
1105
- function parseDocId(docId) {
1106
- const sepIndex = docId.indexOf("/");
1107
- if (sepIndex <= 0) {
1108
- throw new Error(`invalid doc id: ${docId}`);
1109
- }
1110
- const collection = docId.slice(0, sepIndex);
1111
- const slug = docId.slice(sepIndex + 1).replaceAll("/", "--");
1112
- if (!collection || !slug) {
1113
- throw new Error(`invalid doc id: ${docId}`);
1114
- }
1115
- return { collection, slug };
1116
- }
1117
1507
 
1118
1508
  // core/versions.ts
1119
- import path2 from "node:path";
1120
- import { Timestamp as Timestamp4 } from "firebase-admin/firestore";
1509
+ import path from "node:path";
1510
+ import { Timestamp as Timestamp3 } from "firebase-admin/firestore";
1121
1511
  import glob from "tiny-glob";
1122
1512
  var DOCUMENT_SAVE_OFFSET = 5 * 60 * 1e3;
1123
1513
  var VersionsService = class {
@@ -1136,7 +1526,7 @@ var VersionsService = class {
1136
1526
  const lastRun = await this.getLastRun();
1137
1527
  const lastRunWithOffset = lastRun === 0 ? lastRun : lastRun - DOCUMENT_SAVE_OFFSET;
1138
1528
  const changedDocs = await this.getDocsModifiedAfter(lastRunWithOffset);
1139
- const now = Timestamp4.now().toMillis();
1529
+ const now = Timestamp3.now().toMillis();
1140
1530
  const versions = changedDocs.filter((doc) => {
1141
1531
  const modifiedAt = doc.sys.modifiedAt.toMillis();
1142
1532
  return modifiedAt <= now - DOCUMENT_SAVE_OFFSET;
@@ -1182,7 +1572,7 @@ var VersionsService = class {
1182
1572
  * Saves {versionLastRun: <timestamp>} to the Projects/<projectId> doc.
1183
1573
  */
1184
1574
  async saveLastRun(millis) {
1185
- const ts = Timestamp4.fromMillis(millis);
1575
+ const ts = Timestamp3.fromMillis(millis);
1186
1576
  const projectDocRef = this.db.collection("Projects").doc(this.projectId);
1187
1577
  await projectDocRef.set({ versionsLastRun: ts }, { merge: true });
1188
1578
  }
@@ -1190,7 +1580,7 @@ var VersionsService = class {
1190
1580
  * Returns a list of all docs that were edited after a certain time.
1191
1581
  */
1192
1582
  async getDocsModifiedAfter(millis) {
1193
- const ts = Timestamp4.fromMillis(millis);
1583
+ const ts = Timestamp3.fromMillis(millis);
1194
1584
  const results = [];
1195
1585
  const collectionIds = await this.listCollections();
1196
1586
  for (const collectionId of collectionIds) {
@@ -1209,7 +1599,7 @@ var VersionsService = class {
1209
1599
  async listCollections() {
1210
1600
  const collectionIds = [];
1211
1601
  const collectionFileNames = await glob("*.schema.ts", {
1212
- cwd: path2.join(this.rootConfig.rootDir, "collections")
1602
+ cwd: path.join(this.rootConfig.rootDir, "collections")
1213
1603
  });
1214
1604
  collectionFileNames.forEach((filename) => {
1215
1605
  collectionIds.push(filename.slice(0, -10));
@@ -1246,7 +1636,7 @@ async function runSaveVersions(rootConfig) {
1246
1636
 
1247
1637
  // core/functions.ts
1248
1638
  function cron(options) {
1249
- const rootDir = path3.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
1639
+ const rootDir = path2.resolve((options == null ? void 0 : options.rootDir) || process.cwd());
1250
1640
  const scheduleOptions = {
1251
1641
  schedule: "every 1 mins",
1252
1642
  ...options == null ? void 0 : options.scheduleOptions
@@ -1259,4 +1649,3 @@ function cron(options) {
1259
1649
  export {
1260
1650
  cron
1261
1651
  };
1262
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vY29yZS9mdW5jdGlvbnMudHMiLCAiLi4vY29yZS9jbGllbnQudHMiLCAiLi4vY29yZS9wbHVnaW4udHMiLCAiLi4vY29yZS9hcGkudHMiLCAiLi4vY29yZS9haS50cyIsICIuLi9jb3JlL2Nzdi50cyIsICIuLi9jb3JlL2NvbXBhdGliaWxpdHkudHMiLCAiLi4vY29yZS92ZXJzaW9ucy50cyIsICIuLi9jb3JlL2Nyb24udHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge2xvYWRCdW5kbGVkQ29uZmlnfSBmcm9tICdAYmxpbmtrL3Jvb3Qvbm9kZSc7XG5pbXBvcnQge1NjaGVkdWxlT3B0aW9ucywgb25TY2hlZHVsZX0gZnJvbSAnZmlyZWJhc2UtZnVuY3Rpb25zL3YyL3NjaGVkdWxlcic7XG5pbXBvcnQge3J1bkNyb25Kb2JzfSBmcm9tICcuL2Nyb24uanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENyb25PcHRpb25zIHtcbiAgcm9vdERpcj86IHN0cmluZztcbiAgc2NoZWR1bGVPcHRpb25zPzogUGFydGlhbDxTY2hlZHVsZU9wdGlvbnM+O1xufVxuXG4vKipcbiAqIFJ1bnMgb2ZmbGluZSBDTVMgdGFza3MsIHN1Y2ggYXMgcHVibGlzaGluZyBvZiBzY2hlZHVsZWQgZG9jcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyb24ob3B0aW9ucz86IENyb25PcHRpb25zKSB7XG4gIGNvbnN0IHJvb3REaXIgPSBwYXRoLnJlc29sdmUob3B0aW9ucz8ucm9vdERpciB8fCBwcm9jZXNzLmN3ZCgpKTtcbiAgY29uc3Qgc2NoZWR1bGVPcHRpb25zOiBTY2hlZHVsZU9wdGlvbnMgPSB7XG4gICAgc2NoZWR1bGU6ICdldmVyeSAxIG1pbnMnLFxuICAgIC4uLm9wdGlvbnM/LnNjaGVkdWxlT3B0aW9ucyxcbiAgfTtcbiAgcmV0dXJuIG9uU2NoZWR1bGUoc2NoZWR1bGVPcHRpb25zLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3Qgcm9vdENvbmZpZyA9IGF3YWl0IGxvYWRCdW5kbGVkQ29uZmlnKHJvb3REaXIsIHtjb21tYW5kOiAnY21zLWNyb24nfSk7XG4gICAgYXdhaXQgcnVuQ3JvbkpvYnMocm9vdENvbmZpZyk7XG4gIH0pO1xufVxuIiwgImltcG9ydCBjcnlwdG8gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0IHR5cGUge1Jvb3RDb25maWd9IGZyb20gJ0BibGlua2svcm9vdCc7XG5pbXBvcnQge0FwcH0gZnJvbSAnZmlyZWJhc2UtYWRtaW4vYXBwJztcbmltcG9ydCB7XG4gIEZpZWxkVmFsdWUsXG4gIEZpcmVzdG9yZSxcbiAgUXVlcnksXG4gIFRpbWVzdGFtcCxcbiAgV3JpdGVCYXRjaCxcbn0gZnJvbSAnZmlyZWJhc2UtYWRtaW4vZmlyZXN0b3JlJztcbmltcG9ydCB7Q01TUGx1Z2luLCBnZXRDbXNQbHVnaW59IGZyb20gJy4vcGx1Z2luLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBEb2M8RmllbGRzID0gYW55PiB7XG4gIC8qKiBUaGUgaWQgb2YgdGhlIGRvYywgZS5nLiBcIlBhZ2VzL2Zvby1iYXJcIi4gKi9cbiAgaWQ6IHN0cmluZztcbiAgLyoqIFRoZSBjb2xsZWN0aW9uIGlkIG9mIHRoZSBkb2MsIGUuZy4gXCJQYWdlc1wiLiAqL1xuICBjb2xsZWN0aW9uOiBzdHJpbmc7XG4gIC8qKiBUaGUgc2x1ZyBvZiB0aGUgZG9jLCBlLmcuIFwiZm9vLWJhclwiLiAqL1xuICBzbHVnOiBzdHJpbmc7XG4gIHN5czoge1xuICAgIGNyZWF0ZWRBdDogbnVtYmVyO1xuICAgIGNyZWF0ZWRCeTogc3RyaW5nO1xuICAgIG1vZGlmaWVkQXQ6IG51bWJlcjtcbiAgICBtb2RpZmllZEJ5OiBzdHJpbmc7XG4gICAgZmlyc3RQdWJsaXNoZWRBdD86IG51bWJlcjtcbiAgICBmaXJzdFB1Ymxpc2hlZEJ5Pzogc3RyaW5nO1xuICAgIHB1Ymxpc2hlZEF0PzogbnVtYmVyO1xuICAgIHB1Ymxpc2hlZEJ5Pzogc3RyaW5nO1xuICAgIHB1Ymxpc2hpbmdMb2NrZWQ6IHtcbiAgICAgIGxvY2tlZEF0OiBzdHJpbmc7XG4gICAgICBsb2NrZWRCeTogc3RyaW5nO1xuICAgICAgcmVhc29uOiBzdHJpbmc7XG4gICAgICB1bnRpbD86IFRpbWVzdGFtcDtcbiAgICB9O1xuICAgIGxvY2FsZXM/OiBzdHJpbmdbXTtcbiAgfTtcbiAgZmllbGRzOiBGaWVsZHM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNsYXRpb25zRG9jIHtcbiAgaWQ6IHN0cmluZztcbiAgc3lzOiB7XG4gICAgbW9kaWZpZWRBdDogVGltZXN0YW1wO1xuICAgIG1vZGlmaWVkQnk6IHN0cmluZztcbiAgICBwdWJsaXNoZWRBdD86IFRpbWVzdGFtcDtcbiAgICBwdWJsaXNoZWRCeT86IHN0cmluZztcbiAgICBsaW5rZWRTaGVldD86IHtcbiAgICAgIHNwcmVhZHNoZWV0SWQ6IHN0cmluZztcbiAgICAgIGdpZDogbnVtYmVyO1xuICAgICAgbGlua2VkQXQ6IFRpbWVzdGFtcDtcbiAgICAgIGxpbmtlZEJ5OiBzdHJpbmc7XG4gICAgfTtcbiAgICB0YWdzPzogc3RyaW5nW107XG4gIH07XG4gIHN0cmluZ3M6IFRyYW5zbGF0aW9uc01hcDtcbn1cblxuZXhwb3J0IHR5cGUgRG9jTW9kZSA9ICdkcmFmdCcgfCAncHVibGlzaGVkJztcblxuZXhwb3J0IHR5cGUgVXNlclJvbGUgPSAnQURNSU4nIHwgJ0VESVRPUicgfCAnVklFV0VSJztcblxuZXhwb3J0IHR5cGUgSHR0cE1ldGhvZCA9ICdHRVQnIHwgJ1BPU1QnO1xuXG5leHBvcnQgaW50ZXJmYWNlIERhdGFTb3VyY2Uge1xuICBpZDogc3RyaW5nO1xuICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgdHlwZTogJ2h0dHAnIHwgJ2dzaGVldCc7XG4gIHVybDogc3RyaW5nO1xuICAvKipcbiAgICogQ3VycmVudGx5IG9ubHkgdXNlZCBieSBnc2hlZXQuIGBhcnJheWAgcmV0dXJucyB0aGUgc2hlZXQgYXMgYW4gYXJyYXkgb2ZcbiAgICogYXJyYXlzLCBgbWFwYCByZXR1cm5zIHRoZSBzaGVldCBhcyBhbiBhcnJheSBvZiBvYmplY3RzLlxuICAgKi9cbiAgZGF0YUZvcm1hdD86ICdhcnJheScgfCAnbWFwJztcbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIEhUVFAgcmVxdWVzdHMuXG4gICAqL1xuICBodHRwT3B0aW9ucz86IHtcbiAgICBtZXRob2Q6IEh0dHBNZXRob2Q7XG4gICAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gICAgYm9keT86IHN0cmluZztcbiAgfTtcbiAgY3JlYXRlZEF0OiBUaW1lc3RhbXA7XG4gIGNyZWF0ZWRCeTogc3RyaW5nO1xuICBzeW5jZWRBdD86IFRpbWVzdGFtcDtcbiAgc3luY2VkQnk/OiBzdHJpbmc7XG4gIHB1Ymxpc2hlZEF0PzogVGltZXN0YW1wO1xuICBwdWJsaXNoZWRCeT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEYXRhU291cmNlRGF0YTxUID0gYW55PiB7XG4gIGRhdGFTb3VyY2U6IERhdGFTb3VyY2U7XG4gIGRhdGE6IFQ7XG59XG5cbmV4cG9ydCB0eXBlIERhdGFTb3VyY2VNb2RlID0gJ2RyYWZ0JyB8ICdwdWJsaXNoZWQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEdldERvY09wdGlvbnMge1xuICAvKiogTW9kZSwgZWl0aGVyIFwiZHJhZnRcIiBvciBcInB1Ymxpc2hlZFwiLiAqL1xuICBtb2RlOiBEb2NNb2RlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNldERvY09wdGlvbnMge1xuICAvKiogTW9kZSwgZWl0aGVyIFwiZHJhZnRcIiBvciBcInB1Ymxpc2hlZFwiLiAqL1xuICBtb2RlOiBEb2NNb2RlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNhdmVEcmFmdE9wdGlvbnMge1xuICAvKipcbiAgICogTG9jYWxlcyB0byBlbmFibGUuXG4gICAqL1xuICBsb2NhbGVzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEVtYWlsIG9mIHVzZXIgbW9kaWZ5aW5nIHRoZSBkb2MuIElmIGJsYW5rLCBkZWZhdWx0cyB0byBgcm9vdC1jbXMtY2xpZW50YC5cbiAgICovXG4gIG1vZGlmaWVkQnk/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGlzdERvY3NPcHRpb25zIHtcbiAgbW9kZTogRG9jTW9kZTtcbiAgb2Zmc2V0PzogbnVtYmVyO1xuICBsaW1pdD86IG51bWJlcjtcbiAgb3JkZXJCeT86IHN0cmluZztcbiAgb3JkZXJCeURpcmVjdGlvbj86ICdhc2MnIHwgJ2Rlc2MnO1xuICBxdWVyeT86IChxdWVyeTogUXVlcnkpID0+IFF1ZXJ5O1xuICAvKipcbiAgICogV2hldGhlciB0byBmZXRjaCB0aGUgXCJyYXdcIiB2ZXJzaW9uIG9mIHRoZSBkb2MgKGZvciB1c2UgaW4gY29uanVuY3Rpb24gd2l0aFxuICAgKiBgc2V0UmF3RG9jKClgKS5cbiAgICovXG4gIHJhdz86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2V0Q291bnRPcHRpb25zIHtcbiAgbW9kZTogRG9jTW9kZTtcbiAgcXVlcnk/OiAocXVlcnk6IFF1ZXJ5KSA9PiBRdWVyeTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUcmFuc2xhdGlvbiB7XG4gIFtsb2NhbGU6IHN0cmluZ106IHN0cmluZztcbiAgc291cmNlOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNsYXRpb25zTWFwIHtcbiAgW2hhc2g6IHN0cmluZ106IFRyYW5zbGF0aW9uO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExvY2FsZVRyYW5zbGF0aW9ucyB7XG4gIFtzb3VyY2U6IHN0cmluZ106IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBMb2FkVHJhbnNsYXRpb25zT3B0aW9ucyB7XG4gIHRhZ3M/OiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZWxlYXNlIHtcbiAgaWQ6IHN0cmluZztcbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIGRvY0lkcz86IHN0cmluZ1tdO1xuICBjcmVhdGVkQXQ/OiBUaW1lc3RhbXA7XG4gIGNyZWF0ZWRCeT86IHN0cmluZztcbiAgc2NoZWR1bGVkQXQ/OiBUaW1lc3RhbXA7XG4gIHNjaGVkdWxlZEJ5Pzogc3RyaW5nO1xuICBwdWJsaXNoZWRBdD86IFRpbWVzdGFtcDtcbiAgcHVibGlzaGVkQnk/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQWN0aW9uPFQgPSBhbnk+IHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBhY3Rpb24uXG4gICAqL1xuICBhY3Rpb246IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSB1c2VyJ3MgZW1haWwgdGhhdCBwZXJmb3JtZWQgdGhlIGFjdGlvbiAob3IgXCJzeXN0ZW1cIikuXG4gICAqL1xuICBieT86IHN0cmluZztcbiAgLyoqXG4gICAqIFRpbWVzdGFtcCB3aGVuIHRoZSBhY3Rpb24gb2NjdXJyZWQuXG4gICAqL1xuICB0aW1lc3RhbXA6IFRpbWVzdGFtcDtcbiAgLyoqXG4gICAqIE1ldGFkYXRhIGZvciB0aGUgYWN0aW9uLlxuICAgKi9cbiAgbWV0YWRhdGE/OiBUO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExpc3RBY3Rpb25zT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBGaWx0ZXIgYnkgYSBzcGVjaWZpYyBhY3Rpb24uIERlZmF1bHRzIHRvIGFsbCBhY3Rpb25zLlxuICAgKi9cbiAgYWN0aW9uPzogc3RyaW5nO1xuICAvKipcbiAgICogRmlsdGVyIGJ5IGEgc3BlY2lmaWMgdXNlci4gRGVmYXVsdHMgdG8gYWxsIHVzZXJzLlxuICAgKi9cbiAgYnk/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBNYXggbnVtYmVyIG9mIGFjdGlvbnMgdG8gcmV0dXJuLiBEZWZhdWx0cyB0byAxMDAuXG4gICAqL1xuICBsaW1pdD86IG51bWJlcjtcbn1cblxuZXhwb3J0IGNsYXNzIFJvb3RDTVNDbGllbnQge1xuICByZWFkb25seSByb290Q29uZmlnOiBSb290Q29uZmlnO1xuICByZWFkb25seSBjbXNQbHVnaW46IENNU1BsdWdpbjtcbiAgcmVhZG9ubHkgcHJvamVjdElkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGFwcDogQXBwO1xuICByZWFkb25seSBkYjogRmlyZXN0b3JlO1xuXG4gIGNvbnN0cnVjdG9yKHJvb3RDb25maWc6IFJvb3RDb25maWcpIHtcbiAgICB0aGlzLnJvb3RDb25maWcgPSByb290Q29uZmlnO1xuICAgIHRoaXMuY21zUGx1Z2luID0gZ2V0Q21zUGx1Z2luKHRoaXMucm9vdENvbmZpZyk7XG5cbiAgICBjb25zdCBjbXNQbHVnaW5PcHRpb25zID0gdGhpcy5jbXNQbHVnaW4uZ2V0Q29uZmlnKCk7XG4gICAgdGhpcy5wcm9qZWN0SWQgPSBjbXNQbHVnaW5PcHRpb25zLmlkIHx8ICdkZWZhdWx0JztcbiAgICB0aGlzLmFwcCA9IHRoaXMuY21zUGx1Z2luLmdldEZpcmViYXNlQXBwKCk7XG4gICAgdGhpcy5kYiA9IHRoaXMuY21zUGx1Z2luLmdldEZpcmVzdG9yZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBkb2MgZGF0YSBmcm9tIFJvb3QuanMgQ01TLlxuICAgKi9cbiAgYXN5bmMgZ2V0RG9jPEZpZWxkcyA9IGFueT4oXG4gICAgY29sbGVjdGlvbklkOiBzdHJpbmcsXG4gICAgc2x1Zzogc3RyaW5nLFxuICAgIG9wdGlvbnM6IEdldERvY09wdGlvbnNcbiAgKTogUHJvbWlzZTxEb2M8RmllbGRzPiB8IG51bGw+IHtcbiAgICBjb25zdCByYXdEYXRhID0gYXdhaXQgdGhpcy5nZXRSYXdEb2MoY29sbGVjdGlvbklkLCBzbHVnLCBvcHRpb25zKTtcbiAgICBpZiAocmF3RGF0YSkge1xuICAgICAgcmV0dXJuIHVubWFyc2hhbERhdGEocmF3RGF0YSkgYXMgRG9jPEZpZWxkcz47XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyByYXcgZG9jIGRhdGEgYXMgc3RvcmVkIGluIHRoZSBkYXRhYmFzZS4gT25seSB1c2UgdGhpcyBpZiB5b3Uga25vd1xuICAgKiB3aGF0IHlvdSBhcmUgZG9pbmcuXG4gICAqL1xuICBhc3luYyBnZXRSYXdEb2MoXG4gICAgY29sbGVjdGlvbklkOiBzdHJpbmcsXG4gICAgc2x1Zzogc3RyaW5nLFxuICAgIG9wdGlvbnM6IEdldERvY09wdGlvbnNcbiAgKTogUHJvbWlzZTxhbnkgfCBudWxsPiB7XG4gICAgY29uc3QgbW9kZSA9IG9wdGlvbnMubW9kZTtcbiAgICBjb25zdCBkb2NSZWYgPSB0aGlzLmRiRG9jUmVmKGNvbGxlY3Rpb25JZCwgc2x1Zywge21vZGV9KTtcbiAgICBjb25zdCBkb2MgPSBhd2FpdCBkb2NSZWYuZ2V0KCk7XG4gICAgaWYgKGRvYy5leGlzdHMpIHtcbiAgICAgIHJldHVybiBkb2MuZGF0YSgpO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGRiQ29sbGVjdGlvbkRvY3NQYXRoKFxuICAgIGNvbGxlY3Rpb25JZDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IHttb2RlOiAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCd9XG4gICkge1xuICAgIGxldCBtb2RlQ29sbGVjdGlvbiA9ICcnO1xuICAgIGlmIChvcHRpb25zLm1vZGUgPT09ICdkcmFmdCcpIHtcbiAgICAgIG1vZGVDb2xsZWN0aW9uID0gJ0RyYWZ0cyc7XG4gICAgfSBlbHNlIGlmIChvcHRpb25zLm1vZGUgPT09ICdwdWJsaXNoZWQnKSB7XG4gICAgICBtb2RlQ29sbGVjdGlvbiA9ICdQdWJsaXNoZWQnO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHVua25vd24gbW9kZTogJHtvcHRpb25zLm1vZGV9YCk7XG4gICAgfVxuICAgIHJldHVybiBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vQ29sbGVjdGlvbnMvJHtjb2xsZWN0aW9uSWR9LyR7bW9kZUNvbGxlY3Rpb259YDtcbiAgfVxuXG4gIGRiRG9jUGF0aChcbiAgICBjb2xsZWN0aW9uSWQ6IHN0cmluZyxcbiAgICBzbHVnOiBzdHJpbmcsXG4gICAgb3B0aW9uczoge21vZGU6ICdkcmFmdCcgfCAncHVibGlzaGVkJ31cbiAgKSB7XG4gICAgY29uc3QgY29sbGVjdGlvbkRvY3NQYXRoID0gdGhpcy5kYkNvbGxlY3Rpb25Eb2NzUGF0aChjb2xsZWN0aW9uSWQsIG9wdGlvbnMpO1xuICAgIC8vIFNsdWdzIHdpdGggc2xhc2hlcyBhcmUgZW5jb2RlZCBhcyBgLS1gIGluIHRoZSBEQi5cbiAgICBjb25zdCBub3JtYWxpemVkU2x1ZyA9IHNsdWcucmVwbGFjZUFsbCgnLycsICctLScpO1xuICAgIHJldHVybiBgJHtjb2xsZWN0aW9uRG9jc1BhdGh9LyR7bm9ybWFsaXplZFNsdWd9YDtcbiAgfVxuXG4gIGRiRG9jUmVmKFxuICAgIGNvbGxlY3Rpb25JZDogc3RyaW5nLFxuICAgIHNsdWc6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7bW9kZTogJ2RyYWZ0JyB8ICdwdWJsaXNoZWQnfVxuICApIHtcbiAgICBjb25zdCBkb2NQYXRoID0gdGhpcy5kYkRvY1BhdGgoY29sbGVjdGlvbklkLCBzbHVnLCBvcHRpb25zKTtcbiAgICByZXR1cm4gdGhpcy5kYi5kb2MoZG9jUGF0aCk7XG4gIH1cblxuICAvKipcbiAgICogU2F2ZXMgZHJhZnQgZGF0YSB0byBhIGRvYy5cbiAgICpcbiAgICogTm90ZTogdGhpcyBzYXZlcyBkYXRhIHRvIHRoZSBcImZpZWxkc1wiIGF0dHIgb2YgdGhlIGRyYWZ0IGRvYy4gSWYgeW91IG5lZWQgdG9cbiAgICogbW9kaWZ5IHRoZSBzeXMtbGV2ZWwgYXR0cmlidXRlcyBvZiB0aGUgZG9jLCB1c2UgYHNldFJhd0RvYygpYC5cbiAgICovXG4gIGFzeW5jIHNhdmVEcmFmdERhdGEoXG4gICAgZG9jSWQ6IHN0cmluZyxcbiAgICBmaWVsZHNEYXRhOiBhbnksXG4gICAgb3B0aW9ucz86IFNhdmVEcmFmdE9wdGlvbnNcbiAgKSB7XG4gICAgY29uc3Qge2NvbGxlY3Rpb24sIHNsdWd9ID0gcGFyc2VEb2NJZChkb2NJZCk7XG4gICAgY29uc3QgZHJhZnREb2MgPVxuICAgICAgKGF3YWl0IHRoaXMuZ2V0UmF3RG9jKGNvbGxlY3Rpb24sIHNsdWcsIHttb2RlOiAnZHJhZnQnfSkpIHx8IHt9O1xuICAgIGNvbnN0IGRyYWZ0U3lzID0gZHJhZnREb2Muc3lzIHx8IHt9O1xuICAgIGNvbnN0IG1vZGlmaWVkQnkgPSBvcHRpb25zPy5tb2RpZmllZEJ5IHx8ICdyb290LWNtcy1jbGllbnQnO1xuICAgIGNvbnN0IGZpZWxkcyA9IG1hcnNoYWxEYXRhKGZpZWxkc0RhdGEgfHwge30pO1xuICAgIGNvbnN0IGRhdGEgPSB7XG4gICAgICBpZDogZG9jSWQsXG4gICAgICBjb2xsZWN0aW9uLFxuICAgICAgc2x1ZyxcbiAgICAgIHN5czoge1xuICAgICAgICAuLi5kcmFmdFN5cyxcbiAgICAgICAgY3JlYXRlZEF0OiBkcmFmdFN5cy5jcmVhdGVkQXQgPz8gVGltZXN0YW1wLm5vdygpLFxuICAgICAgICBjcmVhdGVkQnk6IGRyYWZ0U3lzLmNyZWF0ZWRCeSA/PyBtb2RpZmllZEJ5LFxuICAgICAgICBtb2RpZmllZEF0OiBUaW1lc3RhbXAubm93KCksXG4gICAgICAgIG1vZGlmaWVkQnksXG4gICAgICAgIGxvY2FsZXM6IG9wdGlvbnM/LmxvY2FsZXMgPz8gZHJhZnRTeXMubG9jYWxlcyA/PyBbJ2VuJ10sXG4gICAgICB9LFxuICAgICAgZmllbGRzLFxuICAgIH07XG4gICAgYXdhaXQgdGhpcy5zZXRSYXdEb2MoY29sbGVjdGlvbiwgc2x1ZywgZGF0YSwge21vZGU6ICdkcmFmdCd9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmVmZXIgYHNhdmVEcmFmdERhdGEoJ1BhZ2VzL2ZvbycsIGRhdGEpYC4gT25seSB1c2UgdGhpcyBpZiB5b3Uga25vdyB3aGF0XG4gICAqIHlvdSdyZSBkb2luZy5cbiAgICovXG4gIGFzeW5jIHNldFJhd0RvYyhcbiAgICBjb2xsZWN0aW9uSWQ6IHN0cmluZyxcbiAgICBzbHVnOiBzdHJpbmcsXG4gICAgZGF0YTogYW55LFxuICAgIG9wdGlvbnM6IFNldERvY09wdGlvbnNcbiAgKSB7XG4gICAgY29uc3QgbW9kZSA9IG9wdGlvbnMubW9kZTtcbiAgICBjb25zdCBtb2RlQ29sbGVjdGlvbiA9IG1vZGUgPT09ICdkcmFmdCcgPyAnRHJhZnRzJyA6ICdQdWJsaXNoZWQnO1xuICAgIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9Db2xsZWN0aW9ucy8ke2NvbGxlY3Rpb25JZH0vJHttb2RlQ29sbGVjdGlvbn0vJHtzbHVnfWA7XG4gICAgY29uc3QgZG9jUmVmID0gdGhpcy5kYi5kb2MoZGJQYXRoKTtcbiAgICBhd2FpdCBkb2NSZWYuc2V0KGRhdGEpO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3RzIGRvY3MgZnJvbSBhIFJvb3QuanMgQ01TIGNvbGxlY3Rpb24uXG4gICAqL1xuICBhc3luYyBsaXN0RG9jczxUPihcbiAgICBjb2xsZWN0aW9uSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zOiBMaXN0RG9jc09wdGlvbnNcbiAgKTogUHJvbWlzZTx7ZG9jczogVFtdfT4ge1xuICAgIGNvbnN0IG1vZGUgPSBvcHRpb25zLm1vZGU7XG4gICAgY29uc3QgbW9kZUNvbGxlY3Rpb24gPSBtb2RlID09PSAnZHJhZnQnID8gJ0RyYWZ0cycgOiAnUHVibGlzaGVkJztcbiAgICBjb25zdCBkYlBhdGggPSBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vQ29sbGVjdGlvbnMvJHtjb2xsZWN0aW9uSWR9LyR7bW9kZUNvbGxlY3Rpb259YDtcbiAgICBsZXQgcXVlcnk6IFF1ZXJ5ID0gdGhpcy5kYi5jb2xsZWN0aW9uKGRiUGF0aCk7XG4gICAgaWYgKG9wdGlvbnMubGltaXQpIHtcbiAgICAgIHF1ZXJ5ID0gcXVlcnkubGltaXQob3B0aW9ucy5saW1pdCk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLm9mZnNldCkge1xuICAgICAgcXVlcnkgPSBxdWVyeS5vZmZzZXQob3B0aW9ucy5vZmZzZXQpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5vcmRlckJ5KSB7XG4gICAgICBxdWVyeSA9IHF1ZXJ5Lm9yZGVyQnkob3B0aW9ucy5vcmRlckJ5LCBvcHRpb25zLm9yZGVyQnlEaXJlY3Rpb24pO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5xdWVyeSkge1xuICAgICAgcXVlcnkgPSBvcHRpb25zLnF1ZXJ5KHF1ZXJ5KTtcbiAgICB9XG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHF1ZXJ5LmdldCgpO1xuICAgIGNvbnN0IGRvY3M6IFRbXSA9IFtdO1xuICAgIHJlc3VsdHMuZm9yRWFjaCgocmVzdWx0KSA9PiB7XG4gICAgICBpZiAob3B0aW9ucy5yYXcpIHtcbiAgICAgICAgLy8gRm9yIGNhbGxlcnMgdGhhdCB3aXNoIHRvIG1vZGlmeSB0aGUgcmF3IGRvYyB2aWEgYHNldFJhd0RvYygpYCxcbiAgICAgICAgLy8gcmV0dXJuIHRoZSB1bm1vZGlmaWVkIGRvYyBhcyByZXR1cm5lZCBmcm9tIGZpcmVzdG9yZS5cbiAgICAgICAgY29uc3QgcmF3RG9jID0gcmVzdWx0LmRhdGEoKSBhcyBUO1xuICAgICAgICBkb2NzLnB1c2gocmF3RG9jKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGRvYyA9IHVubWFyc2hhbERhdGEocmVzdWx0LmRhdGEoKSkgYXMgVDtcbiAgICAgICAgZG9jcy5wdXNoKGRvYyk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHtkb2NzfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgZG9jcyBpbiBhIFJvb3QuanMgQ01TIGNvbGxlY3Rpb24uXG4gICAqL1xuICBhc3luYyBnZXREb2NzQ291bnQoY29sbGVjdGlvbklkOiBzdHJpbmcsIG9wdGlvbnM6IEdldENvdW50T3B0aW9ucykge1xuICAgIGNvbnN0IG1vZGUgPSBvcHRpb25zLm1vZGU7XG4gICAgY29uc3QgbW9kZUNvbGxlY3Rpb24gPSBtb2RlID09PSAnZHJhZnQnID8gJ0RyYWZ0cycgOiAnUHVibGlzaGVkJztcbiAgICBjb25zdCBkYlBhdGggPSBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vQ29sbGVjdGlvbnMvJHtjb2xsZWN0aW9uSWR9LyR7bW9kZUNvbGxlY3Rpb259YDtcbiAgICBsZXQgcXVlcnk6IFF1ZXJ5ID0gdGhpcy5kYi5jb2xsZWN0aW9uKGRiUGF0aCk7XG4gICAgaWYgKG9wdGlvbnMucXVlcnkpIHtcbiAgICAgIHF1ZXJ5ID0gb3B0aW9ucy5xdWVyeShxdWVyeSk7XG4gICAgfVxuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBxdWVyeS5jb3VudCgpLmdldCgpO1xuICAgIGNvbnN0IGNvdW50ID0gcmVzdWx0cy5kYXRhKCkuY291bnQ7XG4gICAgcmV0dXJuIGNvdW50O1xuICB9XG5cbiAgLyoqXG4gICAqIEJhdGNoIHB1Ymxpc2hlcyBhIHNldCBvZiBkb2NzIGJ5IGlkLlxuICAgKi9cbiAgYXN5bmMgcHVibGlzaERvY3MoXG4gICAgZG9jSWRzOiBzdHJpbmdbXSxcbiAgICBvcHRpb25zPzoge3B1Ymxpc2hlZEJ5OiBzdHJpbmc7IGJhdGNoPzogV3JpdGVCYXRjaH1cbiAgKSB7XG4gICAgY29uc3QgcHJvamVjdENvbGxlY3Rpb25zUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9Db2xsZWN0aW9uc2A7XG4gICAgY29uc3QgcHVibGlzaGVkQnkgPSBvcHRpb25zPy5wdWJsaXNoZWRCeSB8fCAncm9vdC1jbXMtY2xpZW50JztcblxuICAgIC8vIEZldGNoIHRoZSBjdXJyZW50IGRyYWZ0IGRhdGEgZm9yIGVhY2ggZG9jLlxuICAgIGNvbnN0IGRvY1JlZnMgPSBkb2NJZHMubWFwKChkb2NJZCkgPT4ge1xuICAgICAgY29uc3QgW2NvbGxlY3Rpb24sIHNsdWddID0gZG9jSWQuc3BsaXQoJy8nKTtcbiAgICAgIGlmICghY29sbGVjdGlvbiB8fCAhc2x1Zykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgZG9jIGlkOiAke2RvY0lkfWApO1xuICAgICAgfVxuICAgICAgY29uc3QgZG9jUmVmID0gdGhpcy5kYi5kb2MoXG4gICAgICAgIGAke3Byb2plY3RDb2xsZWN0aW9uc1BhdGh9LyR7Y29sbGVjdGlvbn0vRHJhZnRzLyR7c2x1Z31gXG4gICAgICApO1xuICAgICAgcmV0dXJuIGRvY1JlZjtcbiAgICB9KTtcbiAgICBjb25zdCBkb2NTbmFwc2hvdHMgPSBhd2FpdCB0aGlzLmRiLmdldEFsbCguLi5kb2NSZWZzKTtcbiAgICBjb25zdCBkb2NzID0gZG9jU25hcHNob3RzXG4gICAgICAvLyBSZXRyaWV2ZSBzbmFwc2hvdCBkYXRhIGZvciBlYWNoIGRvYy5cbiAgICAgIC5tYXAoKHNuYXBzaG90KSA9PiBzbmFwc2hvdC5kYXRhKCkgYXMgRG9jKVxuICAgICAgLy8gUmVtb3ZlIGRvY3MgdGhhdCBkb24ndCBleGlzdC5cbiAgICAgIC5maWx0ZXIoKGQpID0+ICEhZCk7XG5cbiAgICBpZiAoZG9jcy5sZW5ndGggPT09IDApIHtcbiAgICAgIGNvbnNvbGUubG9nKCdubyBkb2NzIHRvIHB1Ymxpc2gnKTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICAvLyBWZXJpZnkgdGhlcmUgYXJlIG5vIHB1Ymxpc2hpbmcgbG9ja3Mgb24gYW55IGRvY3MuXG4gICAgZm9yIChjb25zdCBkb2Mgb2YgZG9jcykge1xuICAgICAgaWYgKHRoaXMudGVzdFB1Ymxpc2hpbmdMb2NrZWQoZG9jKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHB1Ymxpc2hpbmcgaXMgbG9ja2VkIGZvciBkb2M6ICR7ZG9jLmlkfWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIC8vIEVhY2ggdHJhbnNhY3Rpb24gb3IgYmF0Y2ggY2FuIHdyaXRlIGEgbWF4IG9mIDUwMCBvcHMuXG4gICAgLy8gLy8gaHR0cHM6Ly9maXJlYmFzZS5nb29nbGUuY29tL2RvY3MvZmlyZXN0b3JlL21hbmFnZS1kYXRhL3RyYW5zYWN0aW9uc1xuICAgIGxldCBiYXRjaENvdW50ID0gMDtcbiAgICBjb25zdCBiYXRjaCA9IG9wdGlvbnM/LmJhdGNoIHx8IHRoaXMuZGIuYmF0Y2goKTtcbiAgICBjb25zdCBwdWJsaXNoZWREb2NzOiBhbnlbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgZG9jIG9mIGRvY3MpIHtcbiAgICAgIGNvbnN0IHtpZCwgY29sbGVjdGlvbiwgc2x1Zywgc3lzLCBmaWVsZHN9ID0gZG9jO1xuICAgICAgY29uc3QgZHJhZnRSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgICAgYCR7cHJvamVjdENvbGxlY3Rpb25zUGF0aH0vJHtjb2xsZWN0aW9ufS9EcmFmdHMvJHtzbHVnfWBcbiAgICAgICk7XG4gICAgICBjb25zdCBzY2hlZHVsZWRSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgICAgYCR7cHJvamVjdENvbGxlY3Rpb25zUGF0aH0vJHtjb2xsZWN0aW9ufS9TY2hlZHVsZWQvJHtzbHVnfWBcbiAgICAgICk7XG4gICAgICBjb25zdCBwdWJsaXNoZWRSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgICAgYCR7cHJvamVjdENvbGxlY3Rpb25zUGF0aH0vJHtjb2xsZWN0aW9ufS9QdWJsaXNoZWQvJHtzbHVnfWBcbiAgICAgICk7XG5cbiAgICAgIC8vIE9ubHkgdXBkYXRlIGBmaXJzdFB1Ymxpc2hlZGAgaWYgaXQgZG9lc24ndCBhbHJlYWR5IGV4aXN0LlxuICAgICAgY29uc3QgZmlyc3RQdWJsaXNoZWRBdCA9XG4gICAgICAgIHN5cy5maXJzdFB1Ymxpc2hlZEF0ID8/IEZpZWxkVmFsdWUuc2VydmVyVGltZXN0YW1wKCk7XG4gICAgICBjb25zdCBmaXJzdFB1Ymxpc2hlZEJ5ID0gc3lzLmZpcnN0UHVibGlzaGVkQnkgPz8gcHVibGlzaGVkQnk7XG5cbiAgICAgIC8vIFNhdmUgcHVibGlzaGVkIGRvYy5cbiAgICAgIGJhdGNoLnNldChwdWJsaXNoZWRSZWYsIHtcbiAgICAgICAgaWQsXG4gICAgICAgIGNvbGxlY3Rpb24sXG4gICAgICAgIHNsdWcsXG4gICAgICAgIGZpZWxkczogZmllbGRzIHx8IHt9LFxuICAgICAgICBzeXM6IHtcbiAgICAgICAgICAuLi5zeXMsXG4gICAgICAgICAgZmlyc3RQdWJsaXNoZWRBdDogZmlyc3RQdWJsaXNoZWRBdCxcbiAgICAgICAgICBmaXJzdFB1Ymxpc2hlZEJ5OiBmaXJzdFB1Ymxpc2hlZEJ5LFxuICAgICAgICAgIHB1Ymxpc2hlZEF0OiBGaWVsZFZhbHVlLnNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICAgIHB1Ymxpc2hlZEJ5OiBwdWJsaXNoZWRCeSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgYmF0Y2hDb3VudCArPSAxO1xuXG4gICAgICAvLyBSZW1vdmUgc2NoZWR1bGVkIGRvYywgaWYgYW55LlxuICAgICAgYmF0Y2guZGVsZXRlKHNjaGVkdWxlZFJlZik7XG4gICAgICBiYXRjaENvdW50ICs9IDE7XG5cbiAgICAgIC8vIFVwZGF0ZSB0aGUgZHJhZnQgZG9jIHRvIHJlbW92ZSBgc2NoZWR1bGVkQXRgIGFuZCBgc2NoZWR1bGVkQnlgIGZpZWxkc1xuICAgICAgLy8gYW5kIHVwZGF0ZSB0aGUgYHB1Ymxpc2hlZEF0YCBhbmQgYHB1Ymxpc2hlZEJ5YCBmaWVsZHMuXG4gICAgICBiYXRjaC51cGRhdGUoZHJhZnRSZWYsIHtcbiAgICAgICAgJ3N5cy5zY2hlZHVsZWRBdCc6IEZpZWxkVmFsdWUuZGVsZXRlKCksXG4gICAgICAgICdzeXMuc2NoZWR1bGVkQnknOiBGaWVsZFZhbHVlLmRlbGV0ZSgpLFxuICAgICAgICAnc3lzLmZpcnN0UHVibGlzaGVkQXQnOiBmaXJzdFB1Ymxpc2hlZEF0LFxuICAgICAgICAnc3lzLmZpcnN0UHVibGlzaGVkQnknOiBmaXJzdFB1Ymxpc2hlZEJ5LFxuICAgICAgICAnc3lzLnB1Ymxpc2hlZEF0JzogRmllbGRWYWx1ZS5zZXJ2ZXJUaW1lc3RhbXAoKSxcbiAgICAgICAgJ3N5cy5wdWJsaXNoZWRCeSc6IHB1Ymxpc2hlZEJ5LFxuICAgICAgfSk7XG4gICAgICBiYXRjaENvdW50ICs9IDE7XG5cbiAgICAgIHRoaXMucHVibGlzaFRyYW5zbGF0aW9uc0RvYyhkb2MuaWQsIHtiYXRjaH0pO1xuICAgICAgYmF0Y2hDb3VudCArPSAyO1xuXG4gICAgICBwdWJsaXNoZWREb2NzLnB1c2goZG9jKTtcblxuICAgICAgaWYgKGJhdGNoQ291bnQgPj0gNDAwKSB7XG4gICAgICAgIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuICAgICAgICBiYXRjaENvdW50ID0gMDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoYmF0Y2hDb3VudCA+IDApIHtcbiAgICAgIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuICAgIH1cbiAgICBjb25zb2xlLmxvZyhgcHVibGlzaGVkICR7cHVibGlzaGVkRG9jcy5sZW5ndGh9IGRvY3MhYCk7XG4gICAgcmV0dXJuIHB1Ymxpc2hlZERvY3M7XG4gIH1cblxuICAvKipcbiAgICogUHVibGlzaGVzIHNjaGVkdWxlZCBkb2NzLlxuICAgKi9cbiAgYXN5bmMgcHVibGlzaFNjaGVkdWxlZERvY3MoKSB7XG4gICAgY29uc3QgcHJvamVjdENvbGxlY3Rpb25zUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9Db2xsZWN0aW9uc2A7XG4gICAgY29uc3Qgbm93ID0gTWF0aC5jZWlsKG5ldyBEYXRlKCkuZ2V0VGltZSgpKTtcblxuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgdGhpcy5kYi5jb2xsZWN0aW9uR3JvdXAoJ1NjaGVkdWxlZCcpLmdldCgpO1xuICAgIGNvbnN0IGRvY3MgPSBzbmFwc2hvdC5kb2NzXG4gICAgICAuZmlsdGVyKChkKSA9PiB7XG4gICAgICAgIC8vIEZpbHRlciBkb2NzIGJ5IHByb2plY3QuXG4gICAgICAgIGlmICghZC5yZWYucGF0aC5zdGFydHNXaXRoKHByb2plY3RDb2xsZWN0aW9uc1BhdGgpKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIEZpbHRlciBkb2NzIHdoZXJlIHNjaGVkdWxlZEF0IGlzIGluIHRoZSBwYXN0LlxuICAgICAgICAvLyBOT1RFKHN0ZXZlbmxlKTogdGhlIGZpbHRlcmluZyBpcyBkb25lIG1hbnVhbGx5IGluc3RlYWQgb2YgdXNpbmcgYSBxdWVyeVxuICAgICAgICAvLyB0byBhdm9pZCBoYXZpbmcgdG8gY3JlYXRlIGFuIGluZGV4IGluIGZpcmVzdG9yZS5cbiAgICAgICAgY29uc3QgZGF0YSA9IGQuZGF0YSgpIHx8IHt9O1xuICAgICAgICBjb25zdCBzY2hlZHVsZWRBdDogVGltZXN0YW1wIHwgdW5kZWZpbmVkID0gZGF0YS5zeXM/LnNjaGVkdWxlZEF0O1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIHNjaGVkdWxlZEF0ICYmIHNjaGVkdWxlZEF0LnRvTWlsbGlzICYmIHNjaGVkdWxlZEF0LnRvTWlsbGlzKCkgPD0gbm93XG4gICAgICAgICk7XG4gICAgICB9KVxuICAgICAgLm1hcCgoZCkgPT4ge1xuICAgICAgICBjb25zdCBkYlBhdGggPSBkLnJlZi5wYXRoO1xuICAgICAgICBjb25zdCBzZWdtZW50cyA9IGRiUGF0aC5zcGxpdCgnLycpO1xuICAgICAgICBjb25zdCBzbHVnID0gc2VnbWVudHMuYXQoLTEpO1xuICAgICAgICBjb25zdCBjb2xsZWN0aW9uID0gc2VnbWVudHMuYXQoLTMpO1xuICAgICAgICBjb25zdCBpZCA9IGAke2NvbGxlY3Rpb259LyR7c2x1Z31gO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGRhdGE6IGQuZGF0YSgpLFxuICAgICAgICAgIGlkLFxuICAgICAgICAgIGNvbGxlY3Rpb24sXG4gICAgICAgICAgc2x1ZyxcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuXG4gICAgaWYgKGRvY3MubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZygnbm8gZG9jcyB0byBzY2hlZHVsZScpO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIC8vIEVhY2ggdHJhbnNhY3Rpb24gb3IgYmF0Y2ggY2FuIHdyaXRlIGEgbWF4IG9mIDUwMCBvcHMuXG4gICAgLy8gaHR0cHM6Ly9maXJlYmFzZS5nb29nbGUuY29tL2RvY3MvZmlyZXN0b3JlL21hbmFnZS1kYXRhL3RyYW5zYWN0aW9uc1xuICAgIGxldCBiYXRjaENvdW50ID0gMDtcbiAgICBjb25zdCBiYXRjaCA9IHRoaXMuZGIuYmF0Y2goKTtcbiAgICBjb25zdCBwdWJsaXNoZWREb2NzOiBhbnlbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgZG9jIG9mIGRvY3MpIHtcbiAgICAgIGNvbnN0IHtpZCwgY29sbGVjdGlvbiwgc2x1ZywgZGF0YX0gPSBkb2M7XG4gICAgICBjb25zdCBkcmFmdFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgICBgJHtwcm9qZWN0Q29sbGVjdGlvbnNQYXRofS8ke2NvbGxlY3Rpb259L0RyYWZ0cy8ke3NsdWd9YFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHNjaGVkdWxlZFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgICBgJHtwcm9qZWN0Q29sbGVjdGlvbnNQYXRofS8ke2NvbGxlY3Rpb259L1NjaGVkdWxlZC8ke3NsdWd9YFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHB1Ymxpc2hlZFJlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgICBgJHtwcm9qZWN0Q29sbGVjdGlvbnNQYXRofS8ke2NvbGxlY3Rpb259L1B1Ymxpc2hlZC8ke3NsdWd9YFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHtzY2hlZHVsZWRBdCwgc2NoZWR1bGVkQnksIC4uLnN5c30gPSBkYXRhLnN5cyB8fCB7fTtcblxuICAgICAgLy8gT25seSB1cGRhdGUgYGZpcnN0UHVibGlzaGVkYCBpZiBpdCBkb2Vzbid0IGFscmVhZHkgZXhpc3QuXG4gICAgICBjb25zdCBmaXJzdFB1Ymxpc2hlZEF0ID0gc3lzLmZpcnN0UHVibGlzaGVkQXQgPz8gc2NoZWR1bGVkQXQ7XG4gICAgICBjb25zdCBmaXJzdFB1Ymxpc2hlZEJ5ID1cbiAgICAgICAgc3lzLmZpcnN0UHVibGlzaGVkQnkgPz8gKHNjaGVkdWxlZEJ5IHx8ICdyb290LWNtcy1jbGllbnQnKTtcblxuICAgICAgLy8gU2F2ZSBwdWJsaXNoZWQgZG9jLlxuICAgICAgYmF0Y2guc2V0KHB1Ymxpc2hlZFJlZiwge1xuICAgICAgICBpZCxcbiAgICAgICAgY29sbGVjdGlvbixcbiAgICAgICAgc2x1ZyxcbiAgICAgICAgZmllbGRzOiBkYXRhLmZpZWxkcyB8fCB7fSxcbiAgICAgICAgc3lzOiB7XG4gICAgICAgICAgLi4uc3lzLFxuICAgICAgICAgIGZpcnN0UHVibGlzaGVkQXQ6IGZpcnN0UHVibGlzaGVkQXQsXG4gICAgICAgICAgZmlyc3RQdWJsaXNoZWRCeTogZmlyc3RQdWJsaXNoZWRCeSxcbiAgICAgICAgICBwdWJsaXNoZWRBdDogRmllbGRWYWx1ZS5zZXJ2ZXJUaW1lc3RhbXAoKSxcbiAgICAgICAgICBwdWJsaXNoZWRCeTogc2NoZWR1bGVkQnkgfHwgJycsXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIGJhdGNoQ291bnQgKz0gMTtcblxuICAgICAgLy8gUmVtb3ZlIHB1Ymxpc2hlZCBkb2MuXG4gICAgICBiYXRjaC5kZWxldGUoc2NoZWR1bGVkUmVmKTtcbiAgICAgIGJhdGNoQ291bnQgKz0gMTtcblxuICAgICAgLy8gVXBkYXRlIHRoZSBkcmFmdCBkb2MgdG8gcmVtb3ZlIGBzY2hlZHVsZWRBdGAgYW5kIGBzY2hlZHVsZWRCeWAgZmllbGRzXG4gICAgICAvLyBhbmQgdXBkYXRlIHRoZSBgcHVibGlzaGVkQXRgIGFuZCBgcHVibGlzaGVkQnlgIGZpZWxkcy5cbiAgICAgIGJhdGNoLnVwZGF0ZShkcmFmdFJlZiwge1xuICAgICAgICAnc3lzLnNjaGVkdWxlZEF0JzogRmllbGRWYWx1ZS5kZWxldGUoKSxcbiAgICAgICAgJ3N5cy5zY2hlZHVsZWRCeSc6IEZpZWxkVmFsdWUuZGVsZXRlKCksXG4gICAgICAgICdzeXMuZmlyc3RQdWJsaXNoZWRBdCc6IGZpcnN0UHVibGlzaGVkQXQsXG4gICAgICAgICdzeXMuZmlyc3RQdWJsaXNoZWRCeSc6IGZpcnN0UHVibGlzaGVkQnksXG4gICAgICAgICdzeXMucHVibGlzaGVkQXQnOiBGaWVsZFZhbHVlLnNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICAnc3lzLnB1Ymxpc2hlZEJ5Jzogc2NoZWR1bGVkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCcsXG4gICAgICB9KTtcbiAgICAgIGJhdGNoQ291bnQgKz0gMTtcblxuICAgICAgdGhpcy5wdWJsaXNoVHJhbnNsYXRpb25zRG9jKGRvYy5pZCwge2JhdGNofSk7XG4gICAgICBiYXRjaENvdW50ICs9IDI7XG5cbiAgICAgIHB1Ymxpc2hlZERvY3MucHVzaChkb2MpO1xuXG4gICAgICBpZiAoYmF0Y2hDb3VudCA+PSA0MDApIHtcbiAgICAgICAgYXdhaXQgYmF0Y2guY29tbWl0KCk7XG4gICAgICAgIGJhdGNoQ291bnQgPSAwO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoYmF0Y2hDb3VudCA+IDApIHtcbiAgICAgIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuICAgIH1cbiAgICBjb25zb2xlLmxvZyhgcHVibGlzaGVkICR7cHVibGlzaGVkRG9jcy5sZW5ndGh9IGRvY3MhYCk7XG4gICAgcmV0dXJuIHB1Ymxpc2hlZERvY3M7XG4gIH1cblxuICAvKipcbiAgICogUHVibGlzaGVzIGRvY3MgaW4gc2NoZWR1bGVkIHJlbGVhc2VzLlxuICAgKi9cbiAgYXN5bmMgcHVibGlzaFNjaGVkdWxlZFJlbGVhc2VzKCkge1xuICAgIGNvbnN0IHJlbGVhc2VzUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9SZWxlYXNlc2A7XG4gICAgY29uc3Qgbm93ID0gTWF0aC5jZWlsKG5ldyBEYXRlKCkuZ2V0VGltZSgpKTtcbiAgICBjb25zdCBxdWVyeTogUXVlcnkgPSB0aGlzLmRiXG4gICAgICAuY29sbGVjdGlvbihyZWxlYXNlc1BhdGgpXG4gICAgICAud2hlcmUoJ3NjaGVkdWxlZEF0JywgJzw9JywgVGltZXN0YW1wLmZyb21NaWxsaXMobm93KSk7XG4gICAgY29uc3QgcXVlcnlTbmFwc2hvdCA9IGF3YWl0IHF1ZXJ5LmdldCgpO1xuXG4gICAgZm9yIChjb25zdCBzbmFwc2hvdCBvZiBxdWVyeVNuYXBzaG90LmRvY3MpIHtcbiAgICAgIGNvbnN0IHJlbGVhc2UgPSBzbmFwc2hvdC5kYXRhKCkgYXMgUmVsZWFzZTtcbiAgICAgIGNvbnN0IGJhdGNoID0gdGhpcy5kYi5iYXRjaCgpO1xuICAgICAgY29uc3QgcHVibGlzaGVkQnkgPSByZWxlYXNlLnNjaGVkdWxlZEJ5IHx8ICdyb290LWNtcy1jbGllbnQnO1xuICAgICAgYmF0Y2gudXBkYXRlKHNuYXBzaG90LnJlZiwge1xuICAgICAgICBwdWJsaXNoZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgICBwdWJsaXNoZWRCeTogcHVibGlzaGVkQnksXG4gICAgICAgIHNjaGVkdWxlZEF0OiBGaWVsZFZhbHVlLmRlbGV0ZSgpLFxuICAgICAgICBzY2hlZHVsZWRCeTogRmllbGRWYWx1ZS5kZWxldGUoKSxcbiAgICAgIH0pO1xuICAgICAgYXdhaXQgdGhpcy5wdWJsaXNoRG9jcyhyZWxlYXNlLmRvY0lkcyB8fCBbXSwge3B1Ymxpc2hlZEJ5LCBiYXRjaH0pO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHB1Ymxpc2hUcmFuc2xhdGlvbnNEb2MoXG4gICAgdHJhbnNsYXRpb25zSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge2JhdGNoPzogV3JpdGVCYXRjaDsgcHVibGlzaGVkQnk/OiBzdHJpbmd9XG4gICkge1xuICAgIGNvbnN0IGRvY1NsdWcgPSB0cmFuc2xhdGlvbnNJZC5yZXBsYWNlQWxsKCcvJywgJy0tJyk7XG4gICAgY29uc3QgZHJhZnRSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgIGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9UcmFuc2xhdGlvbnNNYW5hZ2VyL2RyYWZ0L1RyYW5zbGF0aW9ucy8ke2RvY1NsdWd9YFxuICAgICk7XG4gICAgY29uc3Qgc25hcHNob3QgPSBhd2FpdCBkcmFmdFJlZi5nZXQoKTtcblxuICAgIGlmICghc25hcHNob3QuZXhpc3RzKSB7XG4gICAgICAvLyBJZ25vcmUgbWlzc2luZyB0cmFuc2xhdGlvbnMuXG4gICAgICBjb25zb2xlLndhcm4oYHRyYW5zbGF0aW9ucyAke3RyYW5zbGF0aW9uc0lkfSBkb2VzIG5vdCBleGlzdGApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIElmIHRoZSB0cmFuc2xhdGlvbnMgcHVibGlzaGluZyBpcyB0aWVkIHRvIGFub3RoZXIgYmF0Y2ggcmVxdWVzdCAoZS5nLiBkb2NcbiAgICAvLyBwdWJsaXNoaW5nKSwgdGhlIGJhdGNoIHJlcXVlc3Qgd2lsbCBiZSBjb21taXR0ZWQgdXBzdHJlYW0uXG4gICAgY29uc3QgY29tbWl0QmF0Y2ggPSAhb3B0aW9ucz8uYmF0Y2g7XG5cbiAgICBjb25zdCBiYXRjaCA9IG9wdGlvbnM/LmJhdGNoIHx8IHRoaXMuZGIuYmF0Y2goKTtcbiAgICBiYXRjaC51cGRhdGUoZHJhZnRSZWYsIHtcbiAgICAgICdzeXMucHVibGlzaGVkQXQnOiBUaW1lc3RhbXAubm93KCksXG4gICAgICAnc3lzLnB1Ymxpc2hlZEJ5Jzogb3B0aW9ucz8ucHVibGlzaGVkQnkgfHwgJ3Jvb3QtY21zLWNsaWVudCcsXG4gICAgfSk7XG5cbiAgICBjb25zdCBwdWJsaXNoZWRSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgIGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9UcmFuc2xhdGlvbnNNYW5hZ2VyL3B1Ymxpc2hlZC9UcmFuc2xhdGlvbnMvJHtkb2NTbHVnfWBcbiAgICApO1xuICAgIGNvbnN0IGRhdGEgPSB7Li4uc25hcHNob3QuZGF0YSgpfTtcbiAgICBpZiAoIWRhdGEuc3lzKSB7XG4gICAgICBkYXRhLnN5cyA9IHt9O1xuICAgIH1cbiAgICBkYXRhLnN5cy5wdWJsaXNoZWRBdCA9IFRpbWVzdGFtcC5ub3coKTtcbiAgICBkYXRhLnN5cy5wdWJsaXNoZWRCeSA9IG9wdGlvbnM/LnB1Ymxpc2hlZEJ5IHx8ICdyb290LWNtcy1jbGllbnQnO1xuICAgIGJhdGNoLnNldChwdWJsaXNoZWRSZWYsIGRhdGEpO1xuICAgIGlmIChjb21taXRCYXRjaCkge1xuICAgICAgYXdhaXQgYmF0Y2guY29tbWl0KCk7XG4gICAgICB0aGlzLmxvZ0FjdGlvbigndHJhbnNsYXRpb25zLnB1Ymxpc2gnLCB7bWV0YWRhdGE6IHt0cmFuc2xhdGlvbnNJZH19KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGEgZG9jIGlzIGN1cnJlbnRseSBcImxvY2tlZFwiIGZvciBwdWJsaXNoaW5nLlxuICAgKi9cbiAgdGVzdFB1Ymxpc2hpbmdMb2NrZWQoZG9jOiBEb2MpIHtcbiAgICBpZiAoZG9jLnN5cz8ucHVibGlzaGluZ0xvY2tlZCkge1xuICAgICAgaWYgKGRvYy5zeXMucHVibGlzaGluZ0xvY2tlZC51bnRpbCkge1xuICAgICAgICBjb25zdCBub3cgPSBUaW1lc3RhbXAubm93KCkudG9NaWxsaXMoKTtcbiAgICAgICAgY29uc3QgdW50aWwgPSBkb2Muc3lzLnB1Ymxpc2hpbmdMb2NrZWQudW50aWwudG9NaWxsaXMoKTtcbiAgICAgICAgcmV0dXJuIG5vdyA8IHVudGlsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkcyBhbGwgcHVibGlzaGVkIHN0cmluZ3MgaW4gdGhlIGRiLlxuICAgKlxuICAgKiBgYGBcbiAgICoge1xuICAgKiAgIFwiPGhhc2g+XCI6IHtcInNvdXJjZVwiOiBcIkhlbGxvXCIsIFwiZXNcIjogXCJIb2xhXCIsIFwiZnJcIjogXCJCb25qb3VyXCJ9LFxuICAgKiB9XG4gICAqIGBgYFxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCBVc2UgYGNyZWF0ZUJhdGNoUmVxdWVzdCgpYCB0byBmZXRjaCBkcmFmdC9wdWJsaXNoZWQgdHJhbnNsYXRpb25zLlxuICAgKi9cbiAgYXN5bmMgbG9hZFRyYW5zbGF0aW9ucyhcbiAgICBvcHRpb25zPzogTG9hZFRyYW5zbGF0aW9uc09wdGlvbnNcbiAgKTogUHJvbWlzZTxUcmFuc2xhdGlvbnNNYXA+IHtcbiAgICBjb25zdCBkYlBhdGggPSBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vVHJhbnNsYXRpb25zTWFuYWdlci9wdWJsaXNoZWQvVHJhbnNsYXRpb25zYDtcbiAgICBjb25zdCB0cmFuc2xhdGlvbnNNYXA6IFRyYW5zbGF0aW9uc01hcCA9IHt9O1xuXG4gICAgY29uc3QgYWRkVHJhbnNsYXRpb25zID0gKGhhc2g6IHN0cmluZywgdHJhbnNsYXRpb25zOiBUcmFuc2xhdGlvbikgPT4ge1xuICAgICAgdHJhbnNsYXRpb25zTWFwW2hhc2hdID0gT2JqZWN0LmFzc2lnbihcbiAgICAgICAgdHJhbnNsYXRpb25zTWFwW2hhc2hdIHx8IHt9LFxuICAgICAgICB0cmFuc2xhdGlvbnNcbiAgICAgICk7XG4gICAgfTtcblxuICAgIGxldCBxdWVyeTogUXVlcnkgPSB0aGlzLmRiLmNvbGxlY3Rpb24oZGJQYXRoKTtcbiAgICBpZiAob3B0aW9ucz8udGFncyAmJiBvcHRpb25zLnRhZ3MubGVuZ3RoID4gMCkge1xuICAgICAgcXVlcnkgPSBxdWVyeS53aGVyZSgnc3lzLnRhZ3MnLCAnYXJyYXktY29udGFpbnMtYW55Jywgb3B0aW9ucy50YWdzKTtcbiAgICB9XG4gICAgY29uc3Qgc25hcHNob3QgPSBhd2FpdCBxdWVyeS5nZXQoKTtcbiAgICBzbmFwc2hvdC5mb3JFYWNoKChkb2MpID0+IHtcbiAgICAgIGNvbnN0IGRhdGEgPSBkb2MuZGF0YSgpO1xuICAgICAgY29uc3Qgc3RyaW5ncyA9IChkYXRhLnN0cmluZ3MgfHwge30pIGFzIFJlY29yZDxzdHJpbmcsIFRyYW5zbGF0aW9uPjtcbiAgICAgIE9iamVjdC5lbnRyaWVzKHN0cmluZ3MpLmZvckVhY2goKFtoYXNoLCB0cmFuc2xhdGlvbnNdKSA9PiB7XG4gICAgICAgIGFkZFRyYW5zbGF0aW9ucyhoYXNoLCB0cmFuc2xhdGlvbnMpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdHJhbnNsYXRpb25zTWFwO1xuICB9XG5cbiAgLyoqXG4gICAqIFNhdmVzIGEgbWFwIG9mIHRyYW5zbGF0aW9ucywgZS5nLjpcbiAgICogYGBgXG4gICAqIGF3YWl0IGNsaWVudC5zYXZlVHJhbnNsYXRpb25zKHtcbiAgICogICBcIkhlbGxvXCI6IHtcImVzXCI6IFwiSG9sYVwiLCBcImZyXCI6IFwiQm9uam91clwifSxcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCBVc2UgYHNhdmVEcmFmdFRyYW5zbGF0aW9ucygpYCBhbmQgYHB1Ymxpc2hUcmFuc2xhdGlvbnMoKWBcbiAgICogaW5zdGVhZC5cbiAgICovXG4gIGFzeW5jIHNhdmVUcmFuc2xhdGlvbnMoXG4gICAgdHJhbnNsYXRpb25zOiB7XG4gICAgICBbc291cmNlOiBzdHJpbmddOiB7W2xvY2FsZTogc3RyaW5nXTogc3RyaW5nfTtcbiAgICB9LFxuICAgIHRhZ3M/OiBzdHJpbmdbXVxuICApIHtcbiAgICBjb25zdCB0cmFuc2xhdGlvbnNQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L1RyYW5zbGF0aW9uc2A7XG4gICAgY29uc3QgYmF0Y2ggPSB0aGlzLmRiLmJhdGNoKCk7XG4gICAgbGV0IGJhdGNoQ291bnQgPSAwO1xuICAgIE9iamVjdC5lbnRyaWVzKHRyYW5zbGF0aW9ucykuZm9yRWFjaCgoW3NvdXJjZSwgc291cmNlVHJhbnNsYXRpb25zXSkgPT4ge1xuICAgICAgY29uc3QgaGFzaCA9IHRoaXMuZ2V0VHJhbnNsYXRpb25LZXkoc291cmNlKTtcbiAgICAgIGNvbnN0IHRyYW5zbGF0aW9uUmVmID0gdGhpcy5kYi5kb2MoYCR7dHJhbnNsYXRpb25zUGF0aH0vJHtoYXNofWApO1xuICAgICAgY29uc3QgZGF0YTogYW55ID0ge1xuICAgICAgICAuLi5zb3VyY2VUcmFuc2xhdGlvbnMsXG4gICAgICAgIHNvdXJjZTogdGhpcy5ub3JtYWxpemVTdHJpbmcoc291cmNlKSxcbiAgICAgIH07XG4gICAgICBpZiAodGFncykge1xuICAgICAgICBkYXRhLnRhZ3MgPSB0YWdzO1xuICAgICAgfVxuICAgICAgYmF0Y2guc2V0KHRyYW5zbGF0aW9uUmVmLCBkYXRhLCB7bWVyZ2U6IHRydWV9KTtcbiAgICAgIGJhdGNoQ291bnQgKz0gMTtcbiAgICB9KTtcbiAgICBpZiAoYmF0Y2hDb3VudCA+IDUwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd1cCB0byA1MDAgdHJhbnNsYXRpb25zIGNhbiBiZSBzYXZlZCBhdCBhIHRpbWUuJyk7XG4gICAgfVxuICAgIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuICB9XG5cbiAgYXN5bmMgc2F2ZURyYWZ0VHJhbnNsYXRpb25zKFxuICAgIHRyYW5zbGF0aW9uc0lkOiBzdHJpbmcsXG4gICAgdHJhbnNsYXRpb25zOiB7W3NvdXJjZTogc3RyaW5nXToge1tsb2NhbGU6IHN0cmluZ106IHN0cmluZ319LFxuICAgIG9wdGlvbnM/OiB7bW9kaWZpZWRieT86IHN0cmluZ31cbiAgKSB7XG4gICAgY29uc3QgZG9jU2x1ZyA9IHRyYW5zbGF0aW9uc0lkLnJlcGxhY2VBbGwoJy8nLCAnLS0nKTtcbiAgICBjb25zdCBkb2NQYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L1RyYW5zbGF0aW9uc01hbmFnZXIvZHJhZnQvJHtkb2NTbHVnfWA7XG4gICAgY29uc3QgZG9jUmVmID0gdGhpcy5kYi5kb2MoZG9jUGF0aCk7XG5cbiAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGRvY1JlZi5nZXQoKTtcbiAgICBjb25zdCBkYXRhID0gc25hcHNob3QuZGF0YSgpIHx8IHtcbiAgICAgIGlkOiB0cmFuc2xhdGlvbnNJZC5yZXBsYWNlQWxsKCctLScsICcvJyksXG4gICAgICBzeXM6IHt9LFxuICAgICAgc3RyaW5nczoge30sXG4gICAgfTtcbiAgICBkYXRhLnN5cy5tb2RpZmllZEF0ID0gVGltZXN0YW1wLm5vdygpO1xuICAgIGRhdGEuc3lzLm1vZGlmaWVkQnkgPSBvcHRpb25zPy5tb2RpZmllZGJ5IHx8ICdyb290LWNtcy1jbGllbnQnO1xuXG4gICAgY29uc3Qgc3RyaW5ncyA9IGRhdGEuc3RyaW5ncyB8fCB7fTtcbiAgICBPYmplY3QuZW50cmllcyh0cmFuc2xhdGlvbnMpLmZvckVhY2goKFtzb3VyY2UsIHJvd10pID0+IHtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRTb3VyY2UgPSB0aGlzLm5vcm1hbGl6ZVN0cmluZyhzb3VyY2UpO1xuICAgICAgY29uc3QgaGFzaCA9IHRoaXMuZ2V0VHJhbnNsYXRpb25LZXkobm9ybWFsaXplZFNvdXJjZSk7XG4gICAgICBzdHJpbmdzW2hhc2hdID0gey4uLnN0cmluZ3NbaGFzaF0sIC4uLnJvdywgc291cmNlOiBub3JtYWxpemVkU291cmNlfTtcbiAgICB9KTtcbiAgICBkYXRhLnN0cmluZ3MgPSBzdHJpbmdzO1xuICAgIGF3YWl0IGRvY1JlZi5zZXQoZGF0YSk7XG4gICAgdGhpcy5sb2dBY3Rpb24oJ3RyYW5zbGF0aW9ucy5zYXZlJywge21ldGFkYXRhOiB7dHJhbnNsYXRpb25zSWR9fSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgXCJrZXlcIiB1c2VkIGZvciBhIHRyYW5zbGF0aW9uIGFzIHN0b3JlZCBpbiB0aGUgZGIuIFRyYW5zbGF0aW9uc1xuICAgKiBhcmUgc3RvcmVkIHVuZGVyIGBQcm9qZWN0cy88cHJvamVjdCBpZD4vVHJhbnNsYXRpb25zLzxzaGExIGhhc2g+YC5cbiAgICovXG4gIGdldFRyYW5zbGF0aW9uS2V5KHNvdXJjZTogc3RyaW5nKSB7XG4gICAgY29uc3Qgc2hhMSA9IGNyeXB0b1xuICAgICAgLmNyZWF0ZUhhc2goJ3NoYTEnKVxuICAgICAgLnVwZGF0ZSh0aGlzLm5vcm1hbGl6ZVN0cmluZyhzb3VyY2UpKVxuICAgICAgLmRpZ2VzdCgnaGV4Jyk7XG4gICAgcmV0dXJuIHNoYTE7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYW5zIGEgc3RyaW5nIHRoYXQncyB1c2VkIGZvciB0cmFuc2xhdGlvbnMuIFBlcmZvcm1zIHRoZSBmb2xsb3dpbmc6XG4gICAqIC0gUmVtb3ZlcyBhbnkgbGVhZGluZy90cmFpbGluZyB3aGl0ZXNwYWNlXG4gICAqIC0gUmVtb3ZlcyBzcGFjZXMgYXQgdGhlIGVuZCBvZiBhbnkgbGluZVxuICAgKi9cbiAgbm9ybWFsaXplU3RyaW5nKHN0cjogc3RyaW5nKSB7XG4gICAgY29uc3QgbGluZXMgPSBTdHJpbmcoc3RyKVxuICAgICAgLnRyaW0oKVxuICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgLm1hcCgobGluZSkgPT4gbGluZS50cmltRW5kKCkpO1xuICAgIHJldHVybiBsaW5lcy5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2FkcyB0cmFuc2xhdGlvbnMgZm9yIGEgcGFydGljdWxhciBsb2NhbGUuXG4gICAqXG4gICAqIFJldHVybnMgYSBtYXAgbGlrZTpcbiAgICogYGBgXG4gICAqIHtcbiAgICogICBcIkhlbGxvXCI6IFwiQm9uam91clwiLFxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgbG9hZFRyYW5zbGF0aW9uc0ZvckxvY2FsZShcbiAgICBsb2NhbGU6IHN0cmluZyxcbiAgICBvcHRpb25zPzogTG9hZFRyYW5zbGF0aW9uc09wdGlvbnNcbiAgKTogUHJvbWlzZTxMb2NhbGVUcmFuc2xhdGlvbnM+IHtcbiAgICBjb25zdCB0cmFuc2xhdGlvbnNNYXAgPSBhd2FpdCB0aGlzLmxvYWRUcmFuc2xhdGlvbnMob3B0aW9ucyk7XG4gICAgcmV0dXJuIHRyYW5zbGF0aW9uc0ZvckxvY2FsZSh0cmFuc2xhdGlvbnNNYXAsIGxvY2FsZSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIGRhdGEgc291cmNlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICAgKi9cbiAgYXN5bmMgZ2V0RGF0YVNvdXJjZShkYXRhU291cmNlSWQ6IHN0cmluZykge1xuICAgIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9EYXRhU291cmNlcy8ke2RhdGFTb3VyY2VJZH1gO1xuICAgIGNvbnN0IGRvY1JlZiA9IHRoaXMuZGIuZG9jKGRiUGF0aCk7XG4gICAgY29uc3QgZG9jID0gYXdhaXQgZG9jUmVmLmdldCgpO1xuICAgIGlmIChkb2MuZXhpc3RzKSB7XG4gICAgICByZXR1cm4gZG9jLmRhdGEoKSBhcyBEYXRhU291cmNlO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTeW5jcyBhIGRhdGEgc291cmNlIHRvIGRyYWZ0IHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgc3luY0RhdGFTb3VyY2UoZGF0YVNvdXJjZUlkOiBzdHJpbmcsIG9wdGlvbnM/OiB7c3luY2VkQnk/OiBzdHJpbmd9KSB7XG4gICAgY29uc3QgZGF0YVNvdXJjZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YVNvdXJjZShkYXRhU291cmNlSWQpO1xuICAgIGlmICghZGF0YVNvdXJjZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBkYXRhIHNvdXJjZSBub3QgZm91bmQ6ICR7ZGF0YVNvdXJjZUlkfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCB0aGlzLmZldGNoRGF0YShkYXRhU291cmNlKTtcblxuICAgIGNvbnN0IGRhdGFTb3VyY2VEb2NSZWYgPSB0aGlzLmRiLmRvYyhcbiAgICAgIGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9EYXRhU291cmNlcy8ke2RhdGFTb3VyY2VJZH1gXG4gICAgKTtcbiAgICBjb25zdCBkYXRhRG9jUmVmID0gdGhpcy5kYi5kb2MoXG4gICAgICBgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH0vRGF0YVNvdXJjZXMvJHtkYXRhU291cmNlSWR9L0RhdGEvZHJhZnRgXG4gICAgKTtcbiAgICBjb25zdCBzeW5jZWRCeSA9IG9wdGlvbnM/LnN5bmNlZEJ5IHx8ICdyb290LWNtcy1jbGllbnQnO1xuXG4gICAgY29uc3QgdXBkYXRlZERhdGFTb3VyY2U6IERhdGFTb3VyY2UgPSB7XG4gICAgICAuLi5kYXRhU291cmNlLFxuICAgICAgc3luY2VkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgIHN5bmNlZEJ5OiBzeW5jZWRCeSxcbiAgICB9O1xuXG4gICAgY29uc3QgYmF0Y2ggPSB0aGlzLmRiLmJhdGNoKCk7XG4gICAgYmF0Y2guc2V0KGRhdGFEb2NSZWYsIHtcbiAgICAgIGRhdGFTb3VyY2U6IHVwZGF0ZWREYXRhU291cmNlLFxuICAgICAgZGF0YTogZGF0YSxcbiAgICB9KTtcbiAgICBiYXRjaC51cGRhdGUoZGF0YVNvdXJjZURvY1JlZiwge1xuICAgICAgc3luY2VkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgIHN5bmNlZEJ5OiBzeW5jZWRCeSxcbiAgICB9KTtcbiAgICBhd2FpdCBiYXRjaC5jb21taXQoKTtcblxuICAgIGNvbnNvbGUubG9nKGBzeW5jZWQgZGF0YSBzb3VyY2U6ICR7ZGF0YVNvdXJjZUlkfWApO1xuICAgIGNvbnNvbGUubG9nKGBzeW5jZWQgYnk6ICR7c3luY2VkQnl9YCk7XG4gIH1cblxuICBhc3luYyBwdWJsaXNoRGF0YVNvdXJjZShcbiAgICBkYXRhU291cmNlSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge3B1Ymxpc2hlZEJ5Pzogc3RyaW5nfVxuICApIHtcbiAgICBjb25zdCBkYXRhU291cmNlID0gYXdhaXQgdGhpcy5nZXREYXRhU291cmNlKGRhdGFTb3VyY2VJZCk7XG4gICAgaWYgKCFkYXRhU291cmNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGRhdGEgc291cmNlIG5vdCBmb3VuZDogJHtkYXRhU291cmNlSWR9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YVNvdXJjZURvY1JlZiA9IHRoaXMuZGIuZG9jKFxuICAgICAgYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0RhdGFTb3VyY2VzLyR7ZGF0YVNvdXJjZUlkfWBcbiAgICApO1xuICAgIGNvbnN0IGRhdGFEb2NSZWZEcmFmdCA9IHRoaXMuZGIuZG9jKFxuICAgICAgYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0RhdGFTb3VyY2VzLyR7ZGF0YVNvdXJjZUlkfS9kcmFmdGBcbiAgICApO1xuICAgIGNvbnN0IGRhdGFEb2NSZWZQdWJsaXNoZWQgPSB0aGlzLmRiLmRvYyhcbiAgICAgIGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9EYXRhU291cmNlcy8ke2RhdGFTb3VyY2VJZH0vcHVibGlzaGVkYFxuICAgICk7XG5cbiAgICBjb25zdCBkYXRhUmVzID0gYXdhaXQgdGhpcy5nZXRGcm9tRGF0YVNvdXJjZShkYXRhU291cmNlSWQsIHttb2RlOiAnZHJhZnQnfSk7XG5cbiAgICBjb25zdCBwdWJsaXNoZWRCeSA9IG9wdGlvbnM/LnB1Ymxpc2hlZEJ5IHx8ICdyb290LWNtcy1jbGllbnQnO1xuXG4gICAgY29uc3QgdXBkYXRlZERhdGFTb3VyY2U6IERhdGFTb3VyY2UgPSB7XG4gICAgICAuLi5kYXRhU291cmNlLFxuICAgICAgcHVibGlzaGVkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgIHB1Ymxpc2hlZEJ5OiBwdWJsaXNoZWRCeSxcbiAgICB9O1xuXG4gICAgY29uc3QgYmF0Y2ggPSB0aGlzLmRiLmJhdGNoKCk7XG4gICAgYmF0Y2guc2V0KGRhdGFEb2NSZWZQdWJsaXNoZWQsIHtcbiAgICAgIGRhdGFTb3VyY2U6IHVwZGF0ZWREYXRhU291cmNlLFxuICAgICAgZGF0YTogZGF0YVJlcz8uZGF0YSB8fCBudWxsLFxuICAgIH0pO1xuICAgIGJhdGNoLnVwZGF0ZShkYXRhRG9jUmVmRHJhZnQsIHtcbiAgICAgIGRhdGFTb3VyY2U6IHVwZGF0ZWREYXRhU291cmNlLFxuICAgIH0pO1xuICAgIGJhdGNoLnVwZGF0ZShkYXRhU291cmNlRG9jUmVmLCB7XG4gICAgICBwdWJsaXNoZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgcHVibGlzaGVkQnk6IHB1Ymxpc2hlZEJ5LFxuICAgIH0pO1xuICAgIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuXG4gICAgY29uc29sZS5sb2coYHB1Ymxpc2hlZCBkYXRhICR7ZGF0YVNvdXJjZUlkfWApO1xuICAgIGNvbnNvbGUubG9nKGBwdWJsaXNoZWQgYnk6ICR7cHVibGlzaGVkQnl9YCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZldGNoRGF0YShkYXRhU291cmNlOiBEYXRhU291cmNlKSB7XG4gICAgaWYgKGRhdGFTb3VyY2UudHlwZSA9PT0gJ2h0dHAnKSB7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5mZXRjaEh0dHBEYXRhKGRhdGFTb3VyY2UpO1xuICAgIH1cbiAgICAvLyBUT0RPKHN0ZXZlbmxlKTogaW1wbC5cbiAgICAvLyBpZiAoZGF0YVNvdXJjZS50eXBlID09PSAnZ3NoZWV0Jykge1xuICAgIC8vICAgcmV0dXJuIGF3YWl0IGZldGNoR3NoZWV0RGF0YShkYXRhU291cmNlKTtcbiAgICAvLyB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGB1bnN1cHBvcnRlZCBkYXRhIHNvdXJjZTogJHtkYXRhU291cmNlLnR5cGV9YCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZldGNoSHR0cERhdGEoZGF0YVNvdXJjZTogRGF0YVNvdXJjZSkge1xuICAgIGNvbnN0IHVybCA9IGRhdGFTb3VyY2UudXJsIHx8ICcnO1xuICAgIGlmICghdXJsLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgdXJsIG5vdCBzdXBwb3J0ZWQ6ICR7dXJsfWApO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgbWV0aG9kOiBkYXRhU291cmNlLmh0dHBPcHRpb25zPy5tZXRob2QgfHwgJ0dFVCcsXG4gICAgICBoZWFkZXJzOiBkYXRhU291cmNlLmh0dHBPcHRpb25zPy5oZWFkZXJzIHx8IFtdLFxuICAgICAgYm9keTogZGF0YVNvdXJjZS5odHRwT3B0aW9ucz8uYm9keSB8fCB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICBpZiAocmVzLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICBjb25zdCBlcnIgPSBhd2FpdCByZXMudGV4dCgpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGByZXEgZmFpbGVkOiAke2Vycn1gKTtcbiAgICB9XG5cbiAgICBjb25zdCBjb250ZW50VHlwZSA9IFN0cmluZyhyZXMuaGVhZGVycy5nZXQoJ2NvbnRlbnQtdHlwZScpKTtcbiAgICBpZiAoY29udGVudFR5cGUuaW5jbHVkZXMoJ2FwcGxpY2F0aW9uL2pzb24nKSkge1xuICAgICAgcmV0dXJuIGF3YWl0IHJlcy5qc29uKCk7XG4gICAgfVxuICAgIHJldHVybiByZXMudGV4dCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoZXMgZGF0YSBmcm9tIGEgZGF0YSBzb3VyY2UuXG4gICAqL1xuICBhc3luYyBnZXRGcm9tRGF0YVNvdXJjZTxUID0gYW55PihcbiAgICBkYXRhU291cmNlSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge21vZGU/OiAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCd9XG4gICk6IFByb21pc2U8RGF0YVNvdXJjZURhdGE8VD4gfCBudWxsPiB7XG4gICAgY29uc3QgbW9kZSA9IG9wdGlvbnM/Lm1vZGUgfHwgJ3B1Ymxpc2hlZCc7XG5cbiAgICBjb25zdCBkb2NSZWYgPSB0aGlzLmRiRGF0YVNvdXJjZURhdGFSZWYoZGF0YVNvdXJjZUlkLCB7bW9kZX0pO1xuICAgIGNvbnN0IGRvYyA9IGF3YWl0IGRvY1JlZi5nZXQoKTtcbiAgICBpZiAoZG9jLmV4aXN0cykge1xuICAgICAgcmV0dXJuIGRvYy5kYXRhKCkgYXMgRGF0YVNvdXJjZURhdGE8VD47XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgZGJEYXRhU291cmNlRGF0YVBhdGgoXG4gICAgZGF0YVNvdXJjZUlkOiBzdHJpbmcsXG4gICAgb3B0aW9uczoge21vZGU6ICdkcmFmdCcgfCAncHVibGlzaGVkJ31cbiAgKSB7XG4gICAgaWYgKCFkYXRhU291cmNlSWQgfHwgZGF0YVNvdXJjZUlkLmluY2x1ZGVzKCcvJykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBkYXRhIHNvdXJjZSBpZDogJHtkYXRhU291cmNlSWR9YCk7XG4gICAgfVxuICAgIGNvbnN0IG1vZGUgPSBvcHRpb25zLm1vZGU7XG4gICAgaWYgKCEobW9kZSA9PT0gJ2RyYWZ0JyB8fCBtb2RlID09PSAncHVibGlzaGVkJykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBtb2RlOiAke21vZGV9YCk7XG4gICAgfVxuICAgIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9EYXRhU291cmNlcy8ke2RhdGFTb3VyY2VJZH0vRGF0YS8ke21vZGV9YDtcbiAgICByZXR1cm4gZGJQYXRoO1xuICB9XG5cbiAgZGJEYXRhU291cmNlRGF0YVJlZihcbiAgICBkYXRhU291cmNlSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7bW9kZTogJ2RyYWZ0JyB8ICdwdWJsaXNoZWQnfVxuICApIHtcbiAgICBjb25zdCBkYlBhdGggPSB0aGlzLmRiRGF0YVNvdXJjZURhdGFQYXRoKGRhdGFTb3VyY2VJZCwgb3B0aW9ucyk7XG4gICAgcmV0dXJuIHRoaXMuZGIuZG9jKGRiUGF0aCk7XG4gIH1cblxuICBkYlRyYW5zbGF0aW9uc1BhdGgoXG4gICAgdHJhbnNsYXRpb25zSWQ6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7bW9kZTogJ2RyYWZ0JyB8ICdwdWJsaXNoZWQnfVxuICApIHtcbiAgICBjb25zdCBtb2RlID0gb3B0aW9ucy5tb2RlO1xuICAgIGlmICghKG1vZGUgPT09ICdkcmFmdCcgfHwgbW9kZSA9PT0gJ3B1Ymxpc2hlZCcpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgbW9kZTogJHttb2RlfWApO1xuICAgIH1cbiAgICBjb25zdCBzbHVnID0gdHJhbnNsYXRpb25zSWQucmVwbGFjZUFsbCgnLycsICctLScpO1xuICAgIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9UcmFuc2xhdGlvbnNNYW5hZ2VyLyR7bW9kZX0vVHJhbnNsYXRpb25zLyR7c2x1Z31gO1xuICAgIHJldHVybiBkYlBhdGg7XG4gIH1cblxuICBkYlRyYW5zbGF0aW9uc1JlZihcbiAgICB0cmFuc2xhdGlvbnNJZDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IHttb2RlOiAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCd9XG4gICkge1xuICAgIGNvbnN0IGRiUGF0aCA9IHRoaXMuZGJUcmFuc2xhdGlvbnNQYXRoKHRyYW5zbGF0aW9uc0lkLCBvcHRpb25zKTtcbiAgICByZXR1cm4gdGhpcy5kYi5kb2MoZGJQYXRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSB1c2VyJ3Mgcm9sZSBmcm9tIHRoZSBwcm9qZWN0J3MgQUNMLlxuICAgKi9cbiAgYXN5bmMgZ2V0VXNlclJvbGUoZW1haWw6IHN0cmluZyk6IFByb21pc2U8VXNlclJvbGUgfCBudWxsPiB7XG4gICAgaWYgKCFlbWFpbCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IGRvY1JlZiA9IHRoaXMuZGIuZG9jKGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfWApO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZG9jUmVmLmdldCgpO1xuICAgIGNvbnN0IGRhdGEgPSBzbmFwc2hvdC5kYXRhKCkgfHwge307XG4gICAgY29uc3QgYWNsID0gZGF0YS5yb2xlcyB8fCB7fTtcblxuICAgIGlmIChlbWFpbCBpbiBhY2wpIHtcbiAgICAgIHJldHVybiBhY2xbZW1haWxdO1xuICAgIH1cblxuICAgIC8vIENoZWNrIHdpbGRjYXJkIGRvbWFpbnMsIGUuZy4gYCpAZXhhbXBsZS5jb21gLlxuICAgIGlmICghZW1haWwuaW5jbHVkZXMoJ0AnKSkge1xuICAgICAgY29uc29sZS53YXJuKGBpbnZhbGlkIGVtYWlsOiAke2VtYWlsfWApO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IGRvbWFpbiA9IGVtYWlsLnNwbGl0KCdAJykuYXQoLTEpO1xuICAgIGlmIChkb21haW4gJiYgYCpAJHtkb21haW59YCBpbiBhY2wpIHtcbiAgICAgIHJldHVybiBhY2xbYCpAJHtkb21haW59YF07XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWVzIHVzZXIgZXhpc3RzIGluIHRoZSBBQ0wgbGlzdC5cbiAgICovXG4gIGFzeW5jIHVzZXJFeGlzdHNJbkFjbChlbWFpbDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKCFlbWFpbCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBkb2NSZWYgPSB0aGlzLmRiLmRvYyhgUHJvamVjdHMvJHt0aGlzLnByb2plY3RJZH1gKTtcbiAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGRvY1JlZi5nZXQoKTtcbiAgICBjb25zdCBkYXRhID0gc25hcHNob3QuZGF0YSgpIHx8IHt9O1xuICAgIGNvbnN0IGFjbCA9IGRhdGEucm9sZXMgfHwge307XG4gICAgaWYgKGVtYWlsIGluIGFjbCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgd2lsZGNhcmQgZG9tYWlucywgZS5nLiBgKkBleGFtcGxlLmNvbWAuXG4gICAgaWYgKCFlbWFpbC5pbmNsdWRlcygnQCcpKSB7XG4gICAgICBjb25zb2xlLndhcm4oYGludmFsaWQgZW1haWw6ICR7ZW1haWx9YCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IGRvbWFpbiA9IGVtYWlsLnNwbGl0KCdAJykuYXQoLTEpO1xuICAgIGlmIChkb21haW4gJiYgYCpAJHtkb21haW59YCBpbiBhY2wpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBhc3luYyBsb2dBY3Rpb24oYWN0aW9uOiBzdHJpbmcsIG9wdGlvbnM/OiB7Ynk/OiBzdHJpbmc7IG1ldGFkYXRhPzogYW55fSkge1xuICAgIGlmICghYWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQ6IFwiYWN0aW9uXCInKTtcbiAgICB9XG4gICAgY29uc3QgZGF0YSA9IHtcbiAgICAgIGFjdGlvbjogYWN0aW9uLFxuICAgICAgdGltZXN0YW1wOiBUaW1lc3RhbXAubm93KCksXG4gICAgICBieTogb3B0aW9ucz8uYnkgfHwgJ3N5c3RlbScsXG4gICAgICBtZXRhZGF0YTogb3B0aW9ucz8ubWV0YWRhdGEgfHwge30sXG4gICAgfTtcbiAgICBjb25zdCBjb2xSZWYgPSB0aGlzLmRiLmNvbGxlY3Rpb24oYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0FjdGlvbkxvZ3NgKTtcbiAgICBhd2FpdCBjb2xSZWYuYWRkKGRhdGEpO1xuXG4gICAgY29uc3QgbWV0YVN0ciA9IG9wdGlvbnM/Lm1ldGFkYXRhID8gc3RyaW5naWZ5T2JqKG9wdGlvbnMubWV0YWRhdGEpIDogJyc7XG4gICAgY29uc29sZS5sb2coYFske2RhdGEudGltZXN0YW1wLnRvTWlsbGlzKCl9XSBhY3Rpb246ICR7YWN0aW9ufSAke21ldGFTdHJ9YCk7XG5cbiAgICAvLyBDYWxsIHRoZSBgb25BY3Rpb24oKWAgY2FsbGJhY2sgZnJvbSBjbXNQbHVnaW4oKS5cbiAgICBjb25zdCBjbXNQbHVnaW5Db25maWcgPSB0aGlzLmNtc1BsdWdpbi5nZXRDb25maWcoKTtcbiAgICBpZiAoY21zUGx1Z2luQ29uZmlnLm9uQWN0aW9uKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjbXNQbHVnaW5Db25maWcub25BY3Rpb24oZGF0YSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNyZWF0ZUJhdGNoUmVxdWVzdChvcHRpb25zOiBCYXRjaFJlcXVlc3RPcHRpb25zKTogQmF0Y2hSZXF1ZXN0IHtcbiAgICByZXR1cm4gbmV3IEJhdGNoUmVxdWVzdCh0aGlzLCBvcHRpb25zKTtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJhdGNoUmVxdWVzdE9wdGlvbnMge1xuICBtb2RlOiAnZHJhZnQnIHwgJ3B1Ymxpc2hlZCc7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGF1dG9tYXRpY2FsbHkgZmV0Y2ggdHJhbnNsYXRpb25zIGZvciB0aGUgZG9jcyByZXRyaWV2ZWQgaW4gdGhlXG4gICAqIHJlcXVlc3QuXG4gICAqL1xuICB0cmFuc2xhdGU/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJhdGNoUmVxdWVzdFF1ZXJ5IHtcbiAgcXVlcnlJZDogc3RyaW5nO1xuICBjb2xsZWN0aW9uSWQ6IHN0cmluZztcbiAgcXVlcnlPcHRpb25zPzogQmF0Y2hSZXF1ZXN0UXVlcnlPcHRpb25zO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJhdGNoUmVxdWVzdFF1ZXJ5T3B0aW9ucyB7XG4gIG9mZnNldD86IG51bWJlcjtcbiAgbGltaXQ/OiBudW1iZXI7XG4gIG9yZGVyQnk/OiBzdHJpbmc7XG4gIG9yZGVyQnlEaXJlY3Rpb24/OiAnYXNjJyB8ICdkZXNjJztcbiAgcXVlcnk/OiAocXVlcnk6IFF1ZXJ5KSA9PiBRdWVyeTtcbn1cblxuZXhwb3J0IGNsYXNzIEJhdGNoUmVxdWVzdCB7XG4gIGNtc0NsaWVudDogUm9vdENNU0NsaWVudDtcbiAgcHJpdmF0ZSBvcHRpb25zOiBCYXRjaFJlcXVlc3RPcHRpb25zO1xuICBwcml2YXRlIGRiOiBGaXJlc3RvcmU7XG4gIHByaXZhdGUgZG9jSWRzOiBzdHJpbmdbXSA9IFtdO1xuICBwcml2YXRlIGRhdGFTb3VyY2VJZHM6IHN0cmluZ1tdID0gW107XG4gIHByaXZhdGUgcXVlcmllczogQmF0Y2hSZXF1ZXN0UXVlcnlbXSA9IFtdO1xuICBwcml2YXRlIHRyYW5zbGF0aW9uc0lkczogc3RyaW5nW10gPSBbXTtcblxuICBjb25zdHJ1Y3RvcihjbXNDbGllbnQ6IFJvb3RDTVNDbGllbnQsIG9wdGlvbnM6IEJhdGNoUmVxdWVzdE9wdGlvbnMpIHtcbiAgICB0aGlzLmNtc0NsaWVudCA9IGNtc0NsaWVudDtcbiAgICB0aGlzLmRiID0gY21zQ2xpZW50LmRiO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIGRvYyB0byB0aGUgYmF0Y2ggcmVxdWVzdC5cbiAgICovXG4gIGFkZERvYyhkb2NJZDogc3RyaW5nKSB7XG4gICAgdGhpcy5kb2NJZHMucHVzaChkb2NJZCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIGRhdGEgc291cmNlIHRvIHRoZSBiYXRjaCByZXF1ZXN0LlxuICAgKi9cbiAgYWRkRGF0YVNvdXJjZShkYXRhU291cmNlSWQ6IHN0cmluZykge1xuICAgIHRoaXMuZGF0YVNvdXJjZUlkcy5wdXNoKGRhdGFTb3VyY2VJZCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIGNvbGxlY3Rpb24tYmFzZWQgcXVlcnkgdG8gdGhlIGJhdGNoIHJlcXVlc3QuXG4gICAqL1xuICBhZGRRdWVyeShcbiAgICBxdWVyeUlkOiBzdHJpbmcsXG4gICAgY29sbGVjdGlvbklkOiBzdHJpbmcsXG4gICAgcXVlcnlPcHRpb25zPzogQmF0Y2hSZXF1ZXN0UXVlcnlPcHRpb25zXG4gICkge1xuICAgIHRoaXMucXVlcmllcy5wdXNoKHtcbiAgICAgIHF1ZXJ5SWQ6IHF1ZXJ5SWQsXG4gICAgICBjb2xsZWN0aW9uSWQ6IGNvbGxlY3Rpb25JZCxcbiAgICAgIHF1ZXJ5T3B0aW9uczogcXVlcnlPcHRpb25zLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSB0cmFuc2xhdGlvbiBmaWxlIHRvIHRoZSByZXF1ZXN0LlxuICAgKi9cbiAgYWRkVHJhbnNsYXRpb25zKHRyYW5zbGF0aW9uc0lkOiBzdHJpbmcpIHtcbiAgICB0aGlzLnRyYW5zbGF0aW9uc0lkcy5wdXNoKHRyYW5zbGF0aW9uc0lkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgREIuXG4gICAqL1xuICBhc3luYyBmZXRjaCgpOiBQcm9taXNlPEJhdGNoUmVzcG9uc2U+IHtcbiAgICBjb25zdCByZXMgPSBuZXcgQmF0Y2hSZXNwb25zZSgpO1xuXG4gICAgY29uc3QgcHJvbWlzZXMgPSBbXG4gICAgICB0aGlzLmZldGNoRG9jcyhyZXMpLFxuICAgICAgdGhpcy5mZXRjaFF1ZXJpZXMocmVzKSxcbiAgICAgIHRoaXMuZmV0Y2hEYXRhU291cmNlcyhyZXMpLFxuICAgIF07XG4gICAgLy8gSWYgYG9wdGlvbnMudHJhbnNsYXRlYCBpcyBkaXNhYmxlZCBhbmQgdHJhbnNsYXRpb25zIGFyZSByZXF1ZXN0ZWQsXG4gICAgLy8gZmV0Y2ggdGhlIHRyYW5zbGF0aW9ucyBpbiBwYXJhbGxlbCB3aXRoIHRoZSBvdGhlciBkb2NzLlxuICAgIGlmICghdGhpcy5vcHRpb25zLnRyYW5zbGF0ZSAmJiB0aGlzLnRyYW5zbGF0aW9uc0lkcy5sZW5ndGggPiAwKSB7XG4gICAgICBwcm9taXNlcy5wdXNoKHRoaXMuZmV0Y2hUcmFuc2xhdGlvbnMocmVzKSk7XG4gICAgfVxuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuXG4gICAgLy8gSWYgYG9wdGlvbnMudHJhbnNsYXRlYCBpcyBlbmFibGVkLCB0aGUgZmV0Y2hYKCkgbWV0aG9kcyB3aWxsXG4gICAgLy8gYXV0b21hdGljYWxseSBhZGQgZWFjaCBkb2MncyB0cmFuc2xhdGlvbnMgaWQgdG8gdGhlIHJlcXVlc3QsIHNvXG4gICAgLy8gdHJhbnNsYXRpb25zIHNob3VsZCBiZSBmZXRjaGVkIGFmdGVyIGFsbCB0aGUgb3RoZXIgZG9jcyBhcmUgZmV0Y2hlZC5cbiAgICBpZiAodGhpcy50cmFuc2xhdGlvbnNJZHMubGVuZ3RoID4gMCkge1xuICAgICAgYXdhaXQgdGhpcy5mZXRjaFRyYW5zbGF0aW9ucyhyZXMpO1xuICAgIH1cblxuICAgIHJldHVybiByZXM7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZldGNoRG9jcyhyZXM6IEJhdGNoUmVzcG9uc2UpIHtcbiAgICBpZiAodGhpcy5kb2NJZHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGRvY1JlZnMgPSB0aGlzLmRvY0lkcy5tYXAoKGRvY0lkKSA9PiB7XG4gICAgICBjb25zdCBbY29sbGVjdGlvbklkLCBzbHVnXSA9IGRvY0lkLnNwbGl0KCcvJyk7XG4gICAgICByZXR1cm4gdGhpcy5jbXNDbGllbnQuZGJEb2NSZWYoY29sbGVjdGlvbklkLCBzbHVnLCB7XG4gICAgICAgIG1vZGU6IHRoaXMub3B0aW9ucy5tb2RlLFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgY29uc3QgZG9jcyA9IGF3YWl0IHRoaXMuZGIuZ2V0QWxsKC4uLmRvY1JlZnMpO1xuICAgIHRoaXMuZG9jSWRzLmZvckVhY2goKGRvY0lkLCBpKSA9PiB7XG4gICAgICBjb25zdCBkb2MgPSBkb2NzW2ldO1xuICAgICAgaWYgKCFkb2MuZXhpc3RzKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgZG9jIFwiJHtkb2NJZH1cIiBkb2VzIG5vdCBleGlzdGApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCBkb2NEYXRhID0gdW5tYXJzaGFsRGF0YShkb2MuZGF0YSgpKSBhcyBEb2M7XG4gICAgICByZXMuZG9jc1tkb2NJZF0gPSBkb2NEYXRhO1xuXG4gICAgICBpZiAodGhpcy5vcHRpb25zLnRyYW5zbGF0ZSkge1xuICAgICAgICB0aGlzLmFkZFRyYW5zbGF0aW9ucyhkb2NJZCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZldGNoUXVlcmllcyhyZXM6IEJhdGNoUmVzcG9uc2UpIHtcbiAgICBpZiAodGhpcy5xdWVyaWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBtb2RlID0gdGhpcy5vcHRpb25zLm1vZGU7XG5cbiAgICBjb25zdCBoYW5kbGVRdWVyeSA9IGFzeW5jIChxdWVyeUl0ZW06IEJhdGNoUmVxdWVzdFF1ZXJ5KSA9PiB7XG4gICAgICBjb25zdCBkb2NzUGF0aCA9IHRoaXMuY21zQ2xpZW50LmRiQ29sbGVjdGlvbkRvY3NQYXRoKFxuICAgICAgICBxdWVyeUl0ZW0uY29sbGVjdGlvbklkLFxuICAgICAgICB7bW9kZX1cbiAgICAgICk7XG4gICAgICBjb25zdCBxdWVyeU9wdGlvbnMgPSBxdWVyeUl0ZW0ucXVlcnlPcHRpb25zIHx8IHt9O1xuICAgICAgbGV0IHF1ZXJ5OiBRdWVyeSA9IHRoaXMuZGIuY29sbGVjdGlvbihkb2NzUGF0aCk7XG4gICAgICBpZiAocXVlcnlPcHRpb25zLmxpbWl0KSB7XG4gICAgICAgIHF1ZXJ5ID0gcXVlcnkubGltaXQocXVlcnlPcHRpb25zLmxpbWl0KTtcbiAgICAgIH1cbiAgICAgIGlmIChxdWVyeU9wdGlvbnMub2Zmc2V0KSB7XG4gICAgICAgIHF1ZXJ5ID0gcXVlcnkub2Zmc2V0KHF1ZXJ5T3B0aW9ucy5vZmZzZXQpO1xuICAgICAgfVxuICAgICAgaWYgKHF1ZXJ5T3B0aW9ucy5vcmRlckJ5KSB7XG4gICAgICAgIHF1ZXJ5ID0gcXVlcnkub3JkZXJCeShcbiAgICAgICAgICBxdWVyeU9wdGlvbnMub3JkZXJCeSxcbiAgICAgICAgICBxdWVyeU9wdGlvbnMub3JkZXJCeURpcmVjdGlvblxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKHF1ZXJ5T3B0aW9ucy5xdWVyeSkge1xuICAgICAgICBxdWVyeSA9IHF1ZXJ5T3B0aW9ucy5xdWVyeShxdWVyeSk7XG4gICAgICB9XG4gICAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgcXVlcnkuZ2V0KCk7XG4gICAgICBjb25zdCBkb2NzOiBEb2NbXSA9IFtdO1xuICAgICAgcmVzdWx0cy5mb3JFYWNoKChyZXN1bHQpID0+IHtcbiAgICAgICAgY29uc3QgZG9jID0gdW5tYXJzaGFsRGF0YShyZXN1bHQuZGF0YSgpKSBhcyBEb2M7XG4gICAgICAgIGRvY3MucHVzaChkb2MpO1xuICAgICAgfSk7XG4gICAgICByZXMucXVlcmllc1txdWVyeUl0ZW0ucXVlcnlJZF0gPSBkb2NzO1xuICAgIH07XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLnF1ZXJpZXMubWFwKChxdWVyeUl0ZW0pID0+IGhhbmRsZVF1ZXJ5KHF1ZXJ5SXRlbSkpKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hEYXRhU291cmNlcyhyZXM6IEJhdGNoUmVzcG9uc2UpIHtcbiAgICBpZiAodGhpcy5kYXRhU291cmNlSWRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBkb2NSZWZzID0gdGhpcy5kYXRhU291cmNlSWRzLm1hcCgoZGF0YVNvdXJjZUlkKSA9PiB7XG4gICAgICByZXR1cm4gdGhpcy5jbXNDbGllbnQuZGJEYXRhU291cmNlRGF0YVJlZihkYXRhU291cmNlSWQsIHtcbiAgICAgICAgbW9kZTogdGhpcy5vcHRpb25zLm1vZGUsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBjb25zdCBkb2NzID0gYXdhaXQgdGhpcy5kYi5nZXRBbGwoLi4uZG9jUmVmcyk7XG4gICAgdGhpcy5kYXRhU291cmNlSWRzLmZvckVhY2goKGRhdGFTb3VyY2VJZCwgaSkgPT4ge1xuICAgICAgY29uc3QgZG9jID0gZG9jc1tpXTtcbiAgICAgIGlmICghZG9jLmV4aXN0cykge1xuICAgICAgICBjb25zb2xlLndhcm4oYFwiZGF0YSBzb3VyY2UgXCIke2RhdGFTb3VyY2VJZH1cIiBkb2VzIG5vdCBleGlzdGApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICByZXMuZGF0YVNvdXJjZXNbZGF0YVNvdXJjZUlkXSA9IGRvYy5kYXRhKCkgYXMgRGF0YVNvdXJjZURhdGE7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGZldGNoVHJhbnNsYXRpb25zKHJlczogQmF0Y2hSZXNwb25zZSkge1xuICAgIGlmICh0aGlzLnRyYW5zbGF0aW9uc0lkcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBkb2NSZWZzID0gdGhpcy50cmFuc2xhdGlvbnNJZHMubWFwKCh0cmFuc2xhdGlvbnNJZCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuY21zQ2xpZW50LmRiVHJhbnNsYXRpb25zUmVmKHRyYW5zbGF0aW9uc0lkLCB7XG4gICAgICAgIG1vZGU6IHRoaXMub3B0aW9ucy5tb2RlLFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgY29uc3QgZG9jcyA9IGF3YWl0IHRoaXMuZGIuZ2V0QWxsKC4uLmRvY1JlZnMpO1xuICAgIHRoaXMudHJhbnNsYXRpb25zSWRzLmZvckVhY2goKHRyYW5zbGF0aW9uc0lkLCBpKSA9PiB7XG4gICAgICBjb25zdCBkb2MgPSBkb2NzW2ldO1xuICAgICAgaWYgKCFkb2MuZXhpc3RzKSB7XG4gICAgICAgIC8vIGNvbnNvbGUud2FybihgdHJhbnNsYXRpb25zIFwiJHt0cmFuc2xhdGlvbnNJZH1cIiBkb2VzIG5vdCBleGlzdGApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICByZXMudHJhbnNsYXRpb25zW3RyYW5zbGF0aW9uc0lkXSA9IGRvYy5kYXRhKCkgYXMgVHJhbnNsYXRpb25zRG9jO1xuICAgIH0pO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBCYXRjaFJlc3BvbnNlIHtcbiAgZG9jczogUmVjb3JkPHN0cmluZywgRG9jPiA9IHt9O1xuICBxdWVyaWVzOiBSZWNvcmQ8c3RyaW5nLCBEb2NbXT4gPSB7fTtcbiAgZGF0YVNvdXJjZXM6IFJlY29yZDxzdHJpbmcsIERhdGFTb3VyY2VEYXRhPiA9IHt9O1xuICB0cmFuc2xhdGlvbnM6IFJlY29yZDxzdHJpbmcsIFRyYW5zbGF0aW9uc0RvYz4gPSB7fTtcblxuICAvKipcbiAgICogUmV0dXJucyBhIG1hcCBvZiB0cmFuc2xhdGlvbnMgZm9yIGEgZ2l2ZW4gbG9jYWxlIG9yIGxvY2FsZSBmYWxsYmFja3MuXG4gICAqXG4gICAqIFRoZSBpbnB1dCBpcyBlaXRoZXIgYSBzaW5nbGUgbG9jYWxlIChlLmcuIFwiZGVcIikgb3IgYW4gYXJyYXkgb2YgbG9jYWxlc1xuICAgKiByZXByZXNlbnRpbmcgdGhlIGZhbGxiYWNrIHRyZWUsIGUuZy4gW1wiZW4tQ0FcIiwgXCJlbi1HQlwiLCBcImVuXCJdLlxuICAgKlxuICAgKiBUaGUgcmV0dXJuZWQgdmFsdWUgaXMgYSBmbGF0IG1hcCBvZiBzb3VyY2Ugc3RyaW5nIHRvIHRyYW5zbGF0ZWQgc3RyaW5nLFxuICAgKiBlLmcuOlxuICAgKiB7XCI8c291cmNlPlwiOiBcIjx0cmFuc2xhdGlvbj5cIn1cbiAgICovXG4gIGdldFRyYW5zbGF0aW9ucyhsb2NhbGU6IHN0cmluZyB8IHN0cmluZ1tdKTogTG9jYWxlVHJhbnNsYXRpb25zIHtcbiAgICBjb25zdCB0cmFuc2xhdGlvbnNNYXAgPSB0aGlzLmdldFRyYW5zbGF0aW9uc01hcCgpO1xuICAgIGNvbnN0IHRyYW5zbGF0aW9ucyA9IHRyYW5zbGF0aW9uc0ZvckxvY2FsZSh0cmFuc2xhdGlvbnNNYXAsIGxvY2FsZSk7XG4gICAgcmV0dXJuIHRyYW5zbGF0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBNZXJnZXMgdGhlIHN0cmluZ3MgZnJvbSBhbGwgdHJhbnNsYXRpb25zIGZpbGVzIHJldHJpZXZlZCBpbiB0aGUgcmVxdWVzdC5cbiAgICogVGhlIHJldHVybmVkIHZhbHVlIGlzIGEgbWFwIG9mIHN0cmluZyB0byB0cmFuc2xhdGlvbnMsIGUuZy46XG4gICAqXG4gICAqIHtcIjxoYXNoPlwiOiB7XCJzb3VyY2VcIjogXCI8c291cmNlPlwiLCBcIjxsb2NhbGU+XCI6IFwiPHRyYW5zbGF0aW9uPlwifX1cbiAgICovXG4gIHByaXZhdGUgZ2V0VHJhbnNsYXRpb25zTWFwKCk6IFRyYW5zbGF0aW9uc01hcCB7XG4gICAgLy8gTG9hZCB0cmFuc2xhdGlvbnMgaW4gdGhlIGZvbGxvd2luZyBvcmRlcjpcbiAgICAvLyAtIGdlbmVyaWMgdHJhbnNsYXRpb25zIChlLmcuIFwiZ2xvYmFsXCIpXG4gICAgLy8gLSBkb2NzIHJldHVybmVkIGZyb20gcXVlcmllcyAoZS5nLiBcImxpc3QgYWxsIGJsb2cgcG9zdHNcIilcbiAgICAvLyAtIHNwZWNpZmljIGRvY3MgKGUuZy4gXCJQYWdlcy9pbmRleFwiKVxuICAgIGNvbnN0IHRyYW5zbGF0aW9uc0RvY3MgPSBPYmplY3QudmFsdWVzKHRoaXMudHJhbnNsYXRpb25zKS5yZXZlcnNlKCk7XG5cbiAgICAvLyBDb25zb2xpZGF0ZSB0aGUgc3RyaW5ncyBmcm9tIGFsbCBvZiB0aGUgdHJhbnNsYXRpb25zIGZpbGVzLlxuICAgIC8vIHtcIjxoYXNoPlwiOiB7XCJzb3VyY2VcIjogXCI8c291cmNlPlwiLCBcIjxsb2NhbGU+XCI6IFwiPHRyYW5zbGF0aW9uPlwifX1cbiAgICBjb25zdCB0cmFuc2xhdGlvbnNNYXA6IFRyYW5zbGF0aW9uc01hcCA9IHt9O1xuICAgIGZvciAoY29uc3QgdHJhbnNsYXRpb25zRG9jIG9mIHRyYW5zbGF0aW9uc0RvY3MpIHtcbiAgICAgIGNvbnN0IHN0cmluZ3MgPSB0cmFuc2xhdGlvbnNEb2Muc3RyaW5ncyB8fCB7fTtcbiAgICAgIGZvciAoY29uc3QgaGFzaCBpbiBzdHJpbmdzKSB7XG4gICAgICAgIGNvbnN0IHRyYW5zbGF0aW9ucyA9IHN0cmluZ3NbaGFzaF07XG4gICAgICAgIHRyYW5zbGF0aW9uc01hcFtoYXNoXSA/Pz0ge3NvdXJjZTogdHJhbnNsYXRpb25zLnNvdXJjZX07XG4gICAgICAgIGZvciAoY29uc3QgbG9jYWxlIGluIHRyYW5zbGF0aW9ucykge1xuICAgICAgICAgIGlmIChsb2NhbGUgIT09ICdzb3VyY2UnICYmIHRyYW5zbGF0aW9uc1tsb2NhbGVdKSB7XG4gICAgICAgICAgICB0cmFuc2xhdGlvbnNNYXBbaGFzaF1bbG9jYWxlXSA9IHRyYW5zbGF0aW9uc1tsb2NhbGVdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cmFuc2xhdGlvbnNNYXA7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgdGhlIGBkYXRhYCBpcyBhIHJpY2ggdGV4dCBkYXRhIG9iamVjdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUmljaFRleHREYXRhKGRhdGE6IGFueSkge1xuICAvLyBUaGUgUmljaFRleHRFZGl0b3IgdXNlcyBlZGl0b3JqcyB1bmRlciB0aGUgaG9vZCwgdGhlIGRhdGEgZm9ybWF0IGlzXG4gIC8vIHNvbWV0aGluZyBsaWtlOlxuICAvLyAge1xuICAvLyAgIFwidGltZVwiOiAxNzIxNzYxMjExNzIwLFxuICAvLyAgIFwidmVyc2lvblwiOiBcIjIuMjguMlwiLFxuICAvLyAgIFwiYmxvY2tzXCI6IFsuLi5dXG4gIC8vIH1cbiAgcmV0dXJuIEJvb2xlYW4oXG4gICAgaXNPYmplY3QoZGF0YSkgJiYgQXJyYXkuaXNBcnJheShkYXRhLmJsb2NrcykgJiYgZGF0YS50aW1lICYmIGRhdGEudmVyc2lvblxuICApO1xufVxuXG4vKipcbiAqIFdhbGtzIHRoZSBkYXRhIHRyZWUgYW5kIGNvbnZlcnRzIGFueSBhcnJheSBvZiBvYmplY3RzIGludG8gXCJhcnJheSBvYmplY3RzXCJcbiAqIGZvciBzdG9yYWdlIGluIGZpcmVzdG9yZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hcnNoYWxEYXRhKGRhdGE6IGFueSk6IGFueSB7XG4gIC8vIEF2b2lkIGNoYW5naW5nIHRoZSBmb3JtYXQgb2YgcmljaCB0ZXh0IGRhdGEuXG4gIGlmIChpc1JpY2hUZXh0RGF0YShkYXRhKSkge1xuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgY29uc3QgcmVzdWx0OiBhbnkgPSB7fTtcbiAgZm9yIChjb25zdCBrZXkgaW4gZGF0YSkge1xuICAgIGNvbnN0IHZhbCA9IGRhdGFba2V5XTtcbiAgICBpZiAoaXNPYmplY3QodmFsKSkge1xuICAgICAgcmVzdWx0W2tleV0gPSBtYXJzaGFsRGF0YSh2YWwpO1xuICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheSh2YWwpKSB7XG4gICAgICBpZiAodmFsLmxlbmd0aCA+IDAgJiYgdmFsLnNvbWUoKGl0ZW0pID0+IGlzT2JqZWN0KGl0ZW0pKSkge1xuICAgICAgICBjb25zdCBpdGVtcyA9IHZhbC5tYXAoKGl0ZW0pID0+IHtcbiAgICAgICAgICBpZiAoaXNPYmplY3QoaXRlbSkpIHtcbiAgICAgICAgICAgIHJldHVybiBtYXJzaGFsRGF0YShpdGVtKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGl0ZW07XG4gICAgICAgIH0pO1xuICAgICAgICByZXN1bHRba2V5XSA9IHRvQXJyYXlPYmplY3QoaXRlbXMpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzdWx0W2tleV0gPSB2YWw7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3VsdFtrZXldID0gdmFsO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIFdhbGtzIHRoZSBkYXRhIHRyZWUgYW5kIGNvbnZlcnRzIGFueSBUaW1lc3RhbXAgb2JqZWN0cyB0byBtaWxsaXMgYW5kIGFueVxuICogX2FycmF5IG1hcHMgdG8gbm9ybWFsIGFycmF5cy5cbiAqXG4gKiBFLmcuOlxuICpcbiAqIG5vcm1hbGl6ZURhdGEoe1xuICogICBzeXM6IHttb2RpZmllZEF0OiBUaW1lc3RhbXAoMTIzKX0sXG4gKiAgIGZpZWxkczoge1xuICogICAgIF9hcnJheTogWydhc2RmJ10sXG4gKiAgICAgYXNkZjoge3RpdGxlOiAnaGVsbG8nfVxuICogICB9XG4gKiB9KVxuICogLy8gPT4ge3N5czoge21vZGlmaWVkQXQ6IDEyM30sIGZpZWxkczoge2ZvbzogW3t0aXRsZTogJ2hlbGxvJ31dfX1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVubWFyc2hhbERhdGEoZGF0YTogYW55KTogYW55IHtcbiAgY29uc3QgcmVzdWx0OiBhbnkgPSB7fTtcbiAgZm9yIChjb25zdCBrZXkgaW4gZGF0YSkge1xuICAgIGNvbnN0IHZhbCA9IGRhdGFba2V5XTtcbiAgICBpZiAoaXNPYmplY3QodmFsKSkge1xuICAgICAgaWYgKHZhbC50b01pbGxpcykge1xuICAgICAgICByZXN1bHRba2V5XSA9IHZhbC50b01pbGxpcygpO1xuICAgICAgfSBlbHNlIGlmIChPYmplY3QuaGFzT3duKHZhbCwgJ19hcnJheScpICYmIEFycmF5LmlzQXJyYXkodmFsLl9hcnJheSkpIHtcbiAgICAgICAgY29uc3QgYXJyID0gdmFsLl9hcnJheS5tYXAoKGFycmF5S2V5OiBzdHJpbmcpID0+IHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4udW5tYXJzaGFsRGF0YSh2YWxbYXJyYXlLZXldIHx8IHt9KSxcbiAgICAgICAgICAgIF9hcnJheUtleTogYXJyYXlLZXksXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJlc3VsdFtrZXldID0gYXJyO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzdWx0W2tleV0gPSB1bm1hcnNoYWxEYXRhKHZhbCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3VsdFtrZXldID0gdmFsO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKiogQGRlcHJlY2F0ZWQgVXNlIGB1bm1hcnNoYWxEYXRhKClgIGluc3RlYWQuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplRGF0YShkYXRhOiBhbnkpOiBhbnkge1xuICByZXR1cm4gdW5tYXJzaGFsRGF0YShkYXRhKTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBcnJheU9iamVjdCB7XG4gIFtrZXk6IHN0cmluZ106IGFueTtcbiAgX2FycmF5OiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBTZXJpYWxpemVzIGFuIGFycmF5IGludG8gYW4gYEFycmF5T2JqZWN0YCwgZS5nLjpcbiAqXG4gKiBgYGBcbiAqIG1hcnNoYWxBcnJheShbMSwgMiwgM10pXG4gKiAvLyA9PiB7YTogMSwgYjogMiwgYzogMywgX2FycmF5OiBbJ2EnLCAnYicsICdjJ119XG4gKiBgYGBcbiAqXG4gKiBUaGlzIGRhdGFiYXNlIHN0b3JhZ2UgbWV0aG9kIG1ha2VzIGl0IGVhc2llciB0byB1cGRhdGUgYSBzaW5nbGUgZmllbGQgaW4gYVxuICogZGVlcGx5IG5lc3RlZCBhcnJheSBvYmplY3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b0FycmF5T2JqZWN0KGFycjogYW55W10pOiBBcnJheU9iamVjdCB7XG4gIGlmICghQXJyYXkuaXNBcnJheShhcnIpKSB7XG4gICAgcmV0dXJuIGFycjtcbiAgfVxuICBjb25zdCBhcnJPYmplY3Q6IEFycmF5T2JqZWN0ID0ge19hcnJheTogW119O1xuICBmb3IgKGNvbnN0IGl0ZW0gb2YgYXJyKSB7XG4gICAgY29uc3Qga2V5ID0gcmFuZFN0cmluZyg2KTtcbiAgICBhcnJPYmplY3Rba2V5XSA9IGl0ZW07XG4gICAgYXJyT2JqZWN0Ll9hcnJheS5wdXNoKGtleSk7XG4gIH1cbiAgcmV0dXJuIGFyck9iamVjdDtcbn1cblxuZXhwb3J0IGNvbnN0IG1hcnNoYWxBcnJheSA9IHRvQXJyYXlPYmplY3Q7XG5cbi8qKlxuICogQ29udmVydHMgYW4gYEFycmF5T2JqZWN0YCB0byBhIG5vcm1hbCBhcnJheS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVubWFyc2hhbEFycmF5KGFyck9iamVjdDogQXJyYXlPYmplY3QpOiBhbnlbXSB7XG4gIGlmICghQXJyYXkuaXNBcnJheShhcnJPYmplY3Q/Ll9hcnJheSkpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgY29uc3QgYXJyID0gYXJyT2JqZWN0Ll9hcnJheS5tYXAoKGs6IHN0cmluZykgPT4gYXJyT2JqZWN0W2tdKTtcbiAgcmV0dXJuIGFycjtcbn1cblxuZnVuY3Rpb24gaXNPYmplY3QoZGF0YTogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiB0eXBlb2YgZGF0YSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoZGF0YSkgJiYgZGF0YSAhPT0gbnVsbDtcbn1cblxuZnVuY3Rpb24gcmFuZFN0cmluZyhsZW46IG51bWJlcik6IHN0cmluZyB7XG4gIGNvbnN0IHJlc3VsdCA9IFtdO1xuICBjb25zdCBjaGFycyA9XG4gICAgJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5JztcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgIGNvbnN0IHJhbmQgPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBjaGFycy5sZW5ndGgpO1xuICAgIHJlc3VsdC5wdXNoKGNoYXJzLmNoYXJBdChyYW5kKSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdC5qb2luKCcnKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIHRyYW5zbGF0aW9ucyBtYXAgZnJvbSBgbG9hZFRyYW5zbGF0aW9ucygpYCB0byBhIG1hcCBvZiBzb3VyY2UgdG9cbiAqIHRyYW5zbGF0ZWQgc3RyaW5nIGZvciBhIHBhcnRpY3VsYXIgbG9jYWxlLlxuICpcbiAqIFJldHVybnMgYSBtYXAgbGlrZTpcbiAqIGBgYFxuICoge1xuICogICBcIkhlbGxvXCI6IFwiQm9uam91clwiLFxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cmFuc2xhdGlvbnNGb3JMb2NhbGUoXG4gIHRyYW5zbGF0aW9uc01hcDogVHJhbnNsYXRpb25zTWFwLFxuICBsb2NhbGU6IHN0cmluZyB8IHN0cmluZ1tdXG4pIHtcbiAgY29uc3QgbG9jYWxlVHJhbnNsYXRpb25zOiBMb2NhbGVUcmFuc2xhdGlvbnMgPSB7fTtcblxuICBjb25zdCBmYWxsYmFja0xvY2FsZXMgPSBBcnJheS5pc0FycmF5KGxvY2FsZSkgPyBsb2NhbGUgOiBbbG9jYWxlXTtcbiAgaWYgKCFmYWxsYmFja0xvY2FsZXMuaW5jbHVkZXMoJ2VuJykpIHtcbiAgICBmYWxsYmFja0xvY2FsZXMucHVzaCgnZW4nKTtcbiAgfVxuXG4gIE9iamVjdC52YWx1ZXModHJhbnNsYXRpb25zTWFwKS5mb3JFYWNoKChzdHJpbmcpID0+IHtcbiAgICBjb25zdCBzb3VyY2UgPSBzdHJpbmcuc291cmNlO1xuICAgIGxldCB0cmFuc2xhdGlvbiA9IHNvdXJjZTtcbiAgICBmb3IgKGNvbnN0IGZhbGxiYWNrTG9jYWxlIG9mIGZhbGxiYWNrTG9jYWxlcykge1xuICAgICAgaWYgKHN0cmluZ1tmYWxsYmFja0xvY2FsZV0pIHtcbiAgICAgICAgdHJhbnNsYXRpb24gPSBzdHJpbmdbZmFsbGJhY2tMb2NhbGVdO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgbG9jYWxlVHJhbnNsYXRpb25zW3NvdXJjZV0gPSB0cmFuc2xhdGlvbjtcbiAgfSk7XG4gIHJldHVybiBsb2NhbGVUcmFuc2xhdGlvbnM7XG59XG5cbi8qKiBBIHByZXR0eSBwcmludGVyIGZvciBKYXZhU2NyaXB0IG9iamVjdHMuICovXG5mdW5jdGlvbiBzdHJpbmdpZnlPYmoob2JqOiBhbnkpIHtcbiAgZnVuY3Rpb24gZm9ybWF0KG9iajogYW55KTogc3RyaW5nIHtcbiAgICBpZiAob2JqID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gJ251bGwnO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIG9iaiA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHJldHVybiAndW5kZWZpbmVkJztcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBvYmogPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gYFwiJHtvYmoucmVwbGFjZUFsbCgnXCInLCAnXFxcXFwiJyl9XCJgO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcbiAgICAgIHJldHVybiBTdHJpbmcob2JqKTtcbiAgICB9XG4gICAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgICAgcmV0dXJuIGBbJHtvYmoubWFwKGZvcm1hdCkuam9pbignLCAnKX1dYDtcbiAgICB9XG4gICAgY29uc3QgZW50cmllczogc3RyaW5nW10gPSBPYmplY3QuZW50cmllcyhvYmopLm1hcCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICByZXR1cm4gYCR7a2V5fTogJHtmb3JtYXQodmFsdWUpfWA7XG4gICAgfSk7XG4gICAgcmV0dXJuIGB7JHtlbnRyaWVzLmpvaW4oJywgJyl9fWA7XG4gIH1cbiAgcmV0dXJuIGZvcm1hdChvYmopO1xufVxuXG4vKipcbiAqIFBhcnNlcyBhIGRvY0lkIChlLmcuIGBQYWdlcy9mb29gKSBhbmQgcmV0dXJucyB0aGUgYGNvbGxlY3Rpb25gIGFuZCBgc2x1Z2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZURvY0lkKGRvY0lkOiBzdHJpbmcpIHtcbiAgY29uc3Qgc2VwSW5kZXggPSBkb2NJZC5pbmRleE9mKCcvJyk7XG4gIGlmIChzZXBJbmRleCA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIGRvYyBpZDogJHtkb2NJZH1gKTtcbiAgfVxuICBjb25zdCBjb2xsZWN0aW9uID0gZG9jSWQuc2xpY2UoMCwgc2VwSW5kZXgpO1xuICBjb25zdCBzbHVnID0gZG9jSWQuc2xpY2Uoc2VwSW5kZXggKyAxKS5yZXBsYWNlQWxsKCcvJywgJy0tJyk7XG4gIGlmICghY29sbGVjdGlvbiB8fCAhc2x1Zykge1xuICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBkb2MgaWQ6ICR7ZG9jSWR9YCk7XG4gIH1cbiAgcmV0dXJuIHtjb2xsZWN0aW9uLCBzbHVnfTtcbn1cblxuZXhwb3J0IHtnZXRDbXNQbHVnaW59O1xuIiwgImltcG9ydCB7cHJvbWlzZXMgYXMgZnN9IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7ZmlsZVVSTFRvUGF0aH0gZnJvbSAnbm9kZTp1cmwnO1xuaW1wb3J0IHR5cGUge1xuICBDb25maWd1cmVTZXJ2ZXJPcHRpb25zLFxuICBOZXh0RnVuY3Rpb24sXG4gIFBsdWdpbixcbiAgUmVxdWVzdCxcbiAgUmVzcG9uc2UsXG4gIFJvb3RDb25maWcsXG4gIFNlcnZlcixcbn0gZnJvbSAnQGJsaW5ray9yb290JztcbmltcG9ydCBib2R5UGFyc2VyIGZyb20gJ2JvZHktcGFyc2VyJztcbmltcG9ydCB7XG4gIEFwcCxcbiAgYXBwbGljYXRpb25EZWZhdWx0LFxuICBnZXRBcHAsXG4gIGluaXRpYWxpemVBcHAsXG59IGZyb20gJ2ZpcmViYXNlLWFkbWluL2FwcCc7XG5pbXBvcnQge2dldEF1dGgsIERlY29kZWRJZFRva2VufSBmcm9tICdmaXJlYmFzZS1hZG1pbi9hdXRoJztcbmltcG9ydCB7RmlyZXN0b3JlLCBnZXRGaXJlc3RvcmV9IGZyb20gJ2ZpcmViYXNlLWFkbWluL2ZpcmVzdG9yZSc7XG5pbXBvcnQgKiBhcyBqc29ud2VidG9rZW4gZnJvbSAnanNvbndlYnRva2VuJztcbmltcG9ydCBzaXJ2IGZyb20gJ3NpcnYnO1xuaW1wb3J0IHthcGl9IGZyb20gJy4vYXBpLmpzJztcbmltcG9ydCB7QWN0aW9uLCBSb290Q01TQ2xpZW50fSBmcm9tICcuL2NsaWVudC5qcyc7XG5pbXBvcnQge3J1bkNvbXBhdGliaWxpdHlDaGVja3N9IGZyb20gJy4vY29tcGF0aWJpbGl0eS5qcyc7XG5cbmNvbnN0IF9fZGlybmFtZSA9IHBhdGguZGlybmFtZShmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCkpO1xuXG50eXBlIEFwcE1vZHVsZSA9IHR5cGVvZiBpbXBvcnQoJy4vYXBwLmpzJyk7XG5cbi8vIFRoZSBzZXNzaW9uIGtleSBuYW1lIHVzZWQgZm9yIFJvb3QgQ01TIGF1dGhlbnRpY2F0aW9uLlxuY29uc3QgU0VTU0lPTl9DT09LSUVfQVVUSCA9ICdyb290LWNtcy1hdXRoJztcblxuZXhwb3J0IGludGVyZmFjZSBDTVNVc2VyIHtcbiAgZW1haWw6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDTVNBSUNvbmZpZyB7XG4gIC8qKiBDdXN0b20gQVBJIGVuZHBvaW50IGZvciBjaGF0IHByb21wdHMuICovXG4gIGVuZHBvaW50Pzogc3RyaW5nO1xuICAvKiogR2VuIEFJIG1vZGVsIHRvIHVzZS4gRGVmYXVsdHMgdG8gJ2dlbWluaS0xLjUtZmxhc2gnLiAqL1xuICBtb2RlbD86ICdnZW1pbmktMS41LWZsYXNoJyB8ICdnZW1pbmktMS41LXBybyc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ01TU2lkZWJhclRvb2wge1xuICAvKiogVVJMIGZvciB0aGUgc2lkZWJhciBpY29uIGltYWdlLiAqL1xuICBpY29uPzogc3RyaW5nO1xuICAvKiogTGFiZWwuICovXG4gIGxhYmVsPzogc3RyaW5nO1xuICAvKiogSWZyYW1lIFVSTCB0byByZW5kZXIgZm9yIHRoZSB0b29sLiAqL1xuICBpZnJhbWVVcmw/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIENNU1BsdWdpbk9wdGlvbnMgPSB7XG4gIC8qKlxuICAgKiBUaGUgSUQgb2YgdGhlIHByb2plY3QuIERhdGEgd2lsbCBiZSBzdG9yZWQgdW5kZXIgdGhlIG5hbWVzcGFjZVxuICAgKiBgUHJvamVjdHMvJHtpZH1gIGluIGZpcmVzdG9yZS5cbiAgICovXG4gIGlkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgcHJvamVjdC4gVXNlZCBpbiB0aGUgaGVhZGVyIG9mIHRoZSBDTVMgdG8gaGVscCBpZGVudGlmeVxuICAgKiB0aGUgcHJvamVjdC5cbiAgICovXG4gIG5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEZpcmViYXNlIGNvbmZpZyBvYmplY3QsIHdoaWNoIGNhbiBiZSBvYnRhaW5lZCBpbiB0aGUgRmlyZWJhc2UgQ29uc29sZSBieVxuICAgKiBnb2luZyB0byBcIlByb2plY3QgU2V0dGluZ3NcIi5cbiAgICovXG4gIGZpcmViYXNlQ29uZmlnOiB7XG4gICAgW2tleTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIGFwaUtleTogc3RyaW5nO1xuICAgIGF1dGhEb21haW46IHN0cmluZztcbiAgICBwcm9qZWN0SWQ6IHN0cmluZztcbiAgICBzdG9yYWdlQnVja2V0OiBzdHJpbmc7XG4gICAgZGF0YWJhc2VJZD86IHN0cmluZztcbiAgfTtcblxuICAvKipcbiAgICogR0FQSSBjcmVkZW50aWFscy4gSW5jbHVkZSBpZiB1c2luZyBHb29nbGUgRHJpdmUgYW5kIEdvb2dsZSBTaGVldHMgZmVhdHVyZXMuXG4gICAqIFNlZTogaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vc2hlZXRzL2FwaS9xdWlja3N0YXJ0L2pzXG4gICAqL1xuICBnYXBpPzoge1xuICAgIC8qKiBodHRwczovL2RldmVsb3BlcnMuZ29vZ2xlLmNvbS9zaGVldHMvYXBpL3F1aWNrc3RhcnQvanMjY3JlYXRlX2FuX2FwaV9rZXkgKi9cbiAgICBhcGlLZXk6IHN0cmluZztcbiAgICAvKiogaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vc2hlZXRzL2FwaS9xdWlja3N0YXJ0L2pzI2F1dGhvcml6ZV9jcmVkZW50aWFsc19mb3JfYV93ZWJfYXBwbGljYXRpb24gKi9cbiAgICBjbGllbnRJZDogc3RyaW5nO1xuICB9O1xuXG4gIC8qKlxuICAgKiBTZWNyZXQgdmFsdWUocykgdXNlZCBmb3Igc2lnbmluZyB0aGUgdXNlciBhdXRoZW50aWNhdGlvbiBjb29raWUuXG4gICAqIEBkZXByZWNhdGVkIFRoaXMgaXMgbm93IGhhbmRsZWQgZGlyZWN0bHkgYnkgcm9vdCdzIHNlc3Npb25NaWRkbGV3YXJlIHVuZGVyXG4gICAqIGBzZXJ2ZXIuc2Vzc2lvbkNvb2tpZVNlY3JldGAgaW4gcm9vdC5jb25maWcudHMuXG4gICAqL1xuICBjb29raWVTZWNyZXQ/OiBzdHJpbmcgfCBzdHJpbmdbXTtcblxuICAvKiogRnVuY3Rpb24gY2FsbGVkIHRvIGNoZWNrIGlmIGEgdXNlciBzaG91bGQgaGF2ZSBhY2Nlc3MgdG8gdGhlIENNUy4gKi9cbiAgaXNVc2VyQXV0aG9yaXplZD86IChcbiAgICByZXE6IFJlcXVlc3QsXG4gICAgdXNlcjogQ01TVXNlclxuICApID0+IGJvb2xlYW4gfCBQcm9taXNlPGJvb2xlYW4+O1xuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB0byBjYWxsIHRvIGNoZWNrIGlmIGxvZ2luIGlzIHJlcXVpcmVkIGZvciBhIHBhcnRpY3VsYXIgcmVxdWVzdC5cbiAgICovXG4gIGlzTG9naW5SZXF1aXJlZD86IChyZXE6IFJlcXVlc3QpID0+IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEJ5IGRlZmF1bHQsIGlmcmFtaW5nIHRoZSBDTVMgaXMgZGlzYWxsb3dlZC4gU2V0dGluZyB0aGlzIHZhbHVlIHdpbGwgYWxsb3dcbiAgICogaWZyYW1lcyBmcm9tIHRoZSBzcGVjaWZpZWQgb3JpZ2lucy4gRXhhbXBsZTpcbiAgICogYGBgXG4gICAqIGFsbG93ZWRJZnJhbWVPcmlnaW5zOiBbJ2h0dHBzOi8vYXBwLmV4YW1wbGUuY29tJ11cbiAgICogYGBgXG4gICAqL1xuICBhbGxvd2VkSWZyYW1lT3JpZ2lucz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBVUkwgdG8gR0NJIHNlcnZpY2UgZm9yIHRyYW5zZm9ybWluZyB1cGxvYWRlZCBHQ1MgaW1hZ2VzIHRvIGEgR29vZ2xlIEFwcFxuICAgKiBFbmdpbmUgSW1hZ2VzIEFQSSBzZXJ2aW5nIFVSTC5cbiAgICpcbiAgICogU2V0dGluZyB0aGlzIHRvIGB0cnVlYCB1c2VzIHRoZSBkZWZhdWx0IGhvc3RlZCBzZXJ2aWNlIGF0XG4gICAqIGh0dHBzOi8vZ2NpLnJvb3Rqcy5kZXYuXG4gICAqXG4gICAqIFRvIHNldCB1cCBHQ0k6XG4gICAqXG4gICAqIC0gQ3JlYXRlIGEgR0NTIGJ1Y2tldCB3aXRoIGZpbmUtZ3JhaW5lZCBwZXJtaXNzaW9uc1xuICAgKiAtIFNoYXJlIG93bmVyIGFjY2VzcyB0byB0aGUgYnVja2V0IHdpdGggdGhlIHNlcnZpY2UgYWNjb3VudCByZXR1cm5lZCBpblxuICAgKiAgIGh0dHBzOi8vZ2NpLnJvb3Rqcy5kZXYvXy9zZXJ2aWNlX2FjY291bnRcbiAgICpcbiAgICogVG8gZGlzYWJsZSBHQ0ksIGxlYXZlIHRoaXMgdmFsdWUgZW1wdHkgb3Igc2V0IHRvIGBmYWxzZWAsIHdoaWNoIHdoaWNoIHdpbGxcbiAgICogc2VydmUgaW1hZ2VzIGRpcmVjdGx5IGZyb20gR0NTIGluc3RlYWQuXG4gICAqL1xuICBnY2k/OiBzdHJpbmcgfCBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBDdXN0b21pemF0aW9uIG9wdGlvbnMgZm9yIHRoZSBDTVMgc2lkZWJhci5cbiAgICovXG4gIHNpZGViYXI/OiB7XG4gICAgLyoqXG4gICAgICogU2lkZWJhciB0b29scywgYSBtYXAgb2YgdGhlIHNpZGViYXIgaWQgdG8gY29uZmlnIG9wdGlvbnMuIFRoZSBzaWRlYmFyXG4gICAgICogdG9vbCBpcyB1cmwtbWFwcGVkIHRvIGAvY21zL3Rvb2xzLzppZGAgYW5kIGRpc3BsYXlzIHRoZSB0b29sIGluIGFuXG4gICAgICogaWZyYW1lLlxuICAgICAqL1xuICAgIHRvb2xzPzogUmVjb3JkPHN0cmluZywgQ01TU2lkZWJhclRvb2w+O1xuICB9O1xuXG4gIC8qKlxuICAgKiBDYWxsYmFjayB3aGVuIGFuIGFjdGlvbiBvY2N1cnMuXG4gICAqL1xuICBvbkFjdGlvbj86IChhY3Rpb246IEFjdGlvbikgPT4gYW55O1xuXG4gIC8qKlxuICAgKiBFeHBlcmltZW50YWwgY29uZmlnIG9wdGlvbnMuIE5vdGU6IHRoZXNlIGFyZSBzdWJqZWN0IHRvIGNoYW5nZSBhdCBhbnkgdGltZS5cbiAgICovXG4gIGV4cGVyaW1lbnRzPzoge1xuICAgIGFpPzogYm9vbGVhbiB8IENNU0FJQ29uZmlnO1xuICB9O1xuXG4gIC8qKlxuICAgKiBBZGp1c3QgY29uc29sZSBvdXRwdXQgdmVyYm9zaXR5LiBEZWZhdWx0IGlzIGAnaW5mbydgLlxuICAgKi9cbiAgbG9nTGV2ZWw/OiAnaW5mbycgfCAnd2FybicgfCAnZXJyb3InIHwgJ3NpbGVudCcgfCAnZGVidWcnO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGVuYWJsZS9kaXNhYmxlIGZpbGUgd2F0Y2hpbmcgaW4gZGV2IChlLmcuIGZvciBnZW5lcmF0aW5nXG4gICAqIGByb290LWNtcy5kLnRzYCkuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICovXG4gIHdhdGNoPzogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCB0eXBlIENNU1BsdWdpbiA9IFBsdWdpbiAmIHtcbiAgbmFtZTogJ3Jvb3QtY21zJztcbiAgZ2V0Q29uZmlnOiAoKSA9PiBDTVNQbHVnaW5PcHRpb25zO1xuICBnZXRGaXJlYmFzZUFwcDogKCkgPT4gQXBwO1xuICBnZXRGaXJlc3RvcmU6ICgpID0+IEZpcmVzdG9yZTtcbn07XG5cbmZ1bmN0aW9uIGlzRXhwaXJlZChkZWNvZGVkSWRUb2tlbjogRGVjb2RlZElkVG9rZW4pIHtcbiAgY29uc3QgdHMgPSBNYXRoLmZsb29yKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC8gMTAwMCk7XG4gIHJldHVybiB0cyA+PSBkZWNvZGVkSWRUb2tlbi5leHA7XG59XG5cbmZ1bmN0aW9uIGdldEZpcmViYXNlQXBwKGdjcFByb2plY3RJZDogc3RyaW5nKTogQXBwIHtcbiAgY29uc3QgYXBwTmFtZSA9ICdyb290LWNtcyc7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGdldEFwcChhcHBOYW1lKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgaWYgKGVyciAmJiBlcnIuY29kZSA9PT0gJ2FwcC9uby1hcHAnKSB7XG4gICAgICByZXR1cm4gaW5pdGlhbGl6ZUFwcChcbiAgICAgICAge1xuICAgICAgICAgIHByb2plY3RJZDogZ2NwUHJvamVjdElkLFxuICAgICAgICAgIGNyZWRlbnRpYWw6IGFwcGxpY2F0aW9uRGVmYXVsdCgpLFxuICAgICAgICB9LFxuICAgICAgICBhcHBOYW1lXG4gICAgICApO1xuICAgIH1cbiAgICB0aHJvdyBlcnI7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNtc1BsdWdpbihvcHRpb25zOiBDTVNQbHVnaW5PcHRpb25zKTogQ01TUGx1Z2luIHtcbiAgY29uc3QgbG9nTGV2ZWwgPSBvcHRpb25zLmxvZ0xldmVsIHx8ICdpbmZvJztcblxuICBpZiAoIW9wdGlvbnMuZmlyZWJhc2VDb25maWcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnbWlzc2luZyBmaXJlYmFzZUNvbmZpZy4gY3JlYXRlIGEgbmV3IGFwcCBpbiB0aGUgZmlyZWJhc2UgYWRtaW4gY29uc29sZSBhbmQgY29weSB0aGUgZmlyZWJhc2UgY29uZmlnIG9iamVjdCB0byByb290LmNvbmZpZy50cydcbiAgICApO1xuICB9XG5cbiAgY29uc3QgZmlyZWJhc2VDb25maWcgPSBvcHRpb25zLmZpcmViYXNlQ29uZmlnIHx8IHt9O1xuICBjb25zdCBhcHAgPSBnZXRGaXJlYmFzZUFwcChmaXJlYmFzZUNvbmZpZy5wcm9qZWN0SWQpO1xuICBjb25zdCBhdXRoID0gZ2V0QXV0aChhcHApO1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgbG9naW4gaXMgcmVxdWlyZWQgZm9yIHRoZSByZXF1ZXN0LiBDdXJyZW50bHkgcmV0dXJucyBgdHJ1ZWAgaWZcbiAgICogdGhlIFVSTCBwYXRoIHN0YXJ0cyB3aXRoIC9jbXMgb3IgaWYgP3ByZXZpZXc9dHJ1ZSBpcyBpbiB0aGUgVVJMLlxuICAgKi9cbiAgZnVuY3Rpb24gbG9naW5SZXF1aXJlZChyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgICBjb25zdCB1cmxQYXRoID0gU3RyaW5nKHJlcS5vcmlnaW5hbFVybCkuc3BsaXQoJz8nKVswXS50b0xvd2VyQ2FzZSgpO1xuICAgIC8vIEFsbG93IHRoZSBjcm9uIHRvIHJ1biB1bmF1dGhlbnRpY2F0ZWQuIFRoZSBjcm9uIGpvYiBpcyByZXNwb25zaWJsZVxuICAgIC8vIGZvciBzYXZpbmcgdmVyc2lvbiBoaXN0b3J5LlxuICAgIGlmICh1cmxQYXRoID09PSAnL2Ntcy9hcGkvY3Jvbi5ydW4nKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIC8vIEFsbG93IHRoZSBzaWduaW4uY3NzIGFuZCBzaWduaW4uanMgZmlsZXMgdG8gYmUgcmVuZGVyZWQgd2l0aG91dCBhdXRoLlxuICAgIGlmIChcbiAgICAgIHVybFBhdGggPT09ICcvY21zL3N0YXRpYy9zaWduaW4uY3NzJyB8fFxuICAgICAgdXJsUGF0aCA9PT0gJy9jbXMvc3RhdGljL3NpZ25pbi5qcydcbiAgICApIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gUmVxdWlyZSBsb2dpbiBvbiBhbGwgYC9jbXMvYCBwYXRocy5cbiAgICBpZiAodXJsUGF0aC5zdGFydHNXaXRoKCcvY21zJykpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICAvLyBSZXF1aXJlIGxvZ2luIG9uIGFsbCBwYXRocyB0aGF0IGhhdmUgYD9wcmV2aWV3PXRydWVgLCB3aGljaCBpcyB1c2VkIGJ5XG4gICAgLy8gdGhlIHByZXZpZXcgaWZyYW1lIHRvIHJlbmRlciB0aGUgcHJldmlldyBmb3IgYSBwYWdlLlxuICAgIGlmIChTdHJpbmcocmVxLnF1ZXJ5LnByZXZpZXcpID09PSAndHJ1ZScpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5pc0xvZ2luUmVxdWlyZWQgJiYgb3B0aW9ucy5pc0xvZ2luUmVxdWlyZWQocmVxKSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmllcyBhIG5ldyBsb2dpbiByZXF1ZXN0IGZvciBhIHVzZXIuIFRoZSByZXF1ZXN0IGJvZHkgc2hvdWxkIGNvbnRhaW5cbiAgICogYW4gaWRUb2tlbiwgd2hpY2ggaXMgdmVyaWZpZWQgb24gcHJvZCB1c2luZyBGaXJlYmFzZSBBZG1pbiBhbmQgSWRlbnRpdHlcbiAgICogVG9vbGtpdC4gSWYgYSBgaXNVc2VyQXV0aG9yaXplZCgpYCBjb25maWcgaXMgc2V0LCB0aGlzIGZ1bmN0aW9uIHdpbGwgYWxzb1xuICAgKiB2ZXJpZnkgdmlhIHRoYXQgZnVuY3Rpb24uIFJldHVybnMgdHJ1ZSBpZiB0aGUgbG9naW4gdmVyaWZpY2F0aW9uIHN1Y2NlZWRzLlxuICAgKi9cbiAgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5VXNlckxvZ2luKFxuICAgIHJlcTogUmVxdWVzdFxuICApOiBQcm9taXNlPHthdXRob3JpemVkOiBib29sZWFuOyByZWFzb24/OiBzdHJpbmd9PiB7XG4gICAgY29uc3QgaWRUb2tlbiA9IHJlcS5ib2R5Py5pZFRva2VuO1xuICAgIGlmICghaWRUb2tlbikge1xuICAgICAgY29uc29sZS5sb2coJ2xvZ2luIGZhaWxlZDogbm8gaWQgdG9rZW4nKTtcbiAgICAgIHJldHVybiB7YXV0aG9yaXplZDogZmFsc2UsIHJlYXNvbjogJ25vIHRva2VuJ307XG4gICAgfVxuXG4gICAgbGV0IHVzZXI6IENNU1VzZXI7XG5cbiAgICAvLyBPbiBsb2NhbCBkZXYsIHNpbXBseSB2ZXJpZnkgdGhlIGRlY29kZWQgaWRUb2tlbidzIGVtYWlsIGlzIHNldC4gVGhlXG4gICAgLy8gaWRlbnRpdHkgdG9vbGtpdCB0aGF0IHZlcmlmaWVzIGlkIHRva2VucyByZXF1aXJlcyBhIHNlcnZpY2UgYWNjb3VudCxcbiAgICAvLyB3aGljaCB3ZSB3YW50IHRvIGF2b2lkIGhhdmluZyB0byBzZXQgdXAgd2hlbiB1c2VycyBhcmUgZG9pbmcgbG9jYWwgZGV2LlxuICAgIC8vIEF1dGhlbnRpY2F0aW9uIGlzIHN0aWxsIHJlcXVpcmVkIGJ5IHRoZSBmcm9udGVuZCB1c2luZyBGaXJlYmFzZSBBdXRoLFxuICAgIC8vIHRoaXMganVzdCBieXBhc3NlcyB0aGUgaW5pdGlhbCBzZXJ2ZXIgY2hlY2sgYmVmb3JlIHRoZSB1aSBpcyByZW5kZXJlZC5cbiAgICB0cnkge1xuICAgICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAnZGV2ZWxvcG1lbnQnKSB7XG4gICAgICAgIGNvbnN0IGp3dCA9IGpzb253ZWJ0b2tlbi5kZWNvZGUoaWRUb2tlbikgYXMganNvbndlYnRva2VuLkp3dFBheWxvYWQ7XG4gICAgICAgIGlmICghand0LmVtYWlsIHx8ICFqd3QuZW1haWxfdmVyaWZpZWQpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZygnbG9naW4gZmFpbGVkOiBlbWFpbCB1bnZlcmlmaWVkJyk7XG4gICAgICAgICAgcmV0dXJuIHthdXRob3JpemVkOiBmYWxzZSwgcmVhc29uOiAnbG9naW4gZmFpbGVkJ307XG4gICAgICAgIH1cbiAgICAgICAgdXNlciA9IHtlbWFpbDogand0LmVtYWlsfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGp3dCA9IGF3YWl0IGF1dGgudmVyaWZ5SWRUb2tlbihpZFRva2VuLCB0cnVlKTtcbiAgICAgICAgaWYgKGlzRXhwaXJlZChqd3QpKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ2xvZ2luIGZhaWxlZDogaWQgdG9rZW4gaXMgZXhwaXJlZCcpO1xuICAgICAgICAgIHJldHVybiB7YXV0aG9yaXplZDogZmFsc2UsIHJlYXNvbjogJ2xvZ2luIGZhaWxlZCd9O1xuICAgICAgICB9XG4gICAgICAgIGlmICghand0LmVtYWlsIHx8ICFqd3QuZW1haWxfdmVyaWZpZWQpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZygnbG9naW4gZmFpbGVkOiBlbWFpbCB1bnZlcmlmaWVkJyk7XG4gICAgICAgICAgcmV0dXJuIHthdXRob3JpemVkOiBmYWxzZSwgcmVhc29uOiAnbG9naW4gZmFpbGVkJ307XG4gICAgICAgIH1cbiAgICAgICAgdXNlciA9IHtlbWFpbDogand0LmVtYWlsfTtcbiAgICAgIH1cblxuICAgICAgLy8gVmVyaWZ5IHRoZSBwcm9qZWN0J3MgYGlzVXNlckF1dGhvcml6ZWQoKWAgY29uZmlnIG9wdGlvbi5cbiAgICAgIGlmIChvcHRpb25zLmlzVXNlckF1dGhvcml6ZWQpIHtcbiAgICAgICAgY29uc3QgYXV0aG9yaXplZCA9IGF3YWl0IG9wdGlvbnMuaXNVc2VyQXV0aG9yaXplZChyZXEsIHtcbiAgICAgICAgICBlbWFpbDogdXNlci5lbWFpbCxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICghYXV0aG9yaXplZCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdsb2dpbiBmYWlsZWQ6IHVzZXIgaXMgbm90IGF1dGhvcml6ZWQnKTtcbiAgICAgICAgICByZXR1cm4ge2F1dGhvcml6ZWQ6IGZhbHNlLCByZWFzb246ICdub3QgYXV0aG9yaXplZCd9O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFZlcmlmeSB0aGUgdXNlciBleGlzdHMgaW4gdGhlIERCJ3MgQUNMIGxpc3QuXG4gICAgICBjb25zdCBjbXNDbGllbnQgPSBuZXcgUm9vdENNU0NsaWVudChyZXEucm9vdENvbmZpZyEpO1xuICAgICAgY29uc3QgdXNlckhhc0FjY2VzcyA9IGF3YWl0IGNtc0NsaWVudC51c2VyRXhpc3RzSW5BY2wodXNlci5lbWFpbCk7XG4gICAgICBpZiAoIXVzZXJIYXNBY2Nlc3MpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ2xvZ2luIGZhaWxlZDogdXNlciBpcyBub3QgaW4gdGhlIGZpcmVzdG9yZSBhY2wgbGlzdCcpO1xuICAgICAgICByZXR1cm4ge2F1dGhvcml6ZWQ6IGZhbHNlLCByZWFzb246ICdub3QgYXV0aG9yaXplZCd9O1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcignZmFpbGVkIHRvIHZlcmlmeSBqd3QgdG9rZW4nKTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgIHJldHVybiB7YXV0aG9yaXplZDogZmFsc2UsIHJlYXNvbjogJ3Vua25vd24gZXJyb3InfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge2F1dGhvcml6ZWQ6IHRydWV9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgdXNlciBiYXNlZCBvbiB0aGUgcmVxdWVzdCdzIHNlc3Npb24gY29va2llLiBUaGVcbiAgICogc2Vzc2lvbiBjb29raWUgaXMgY2hlY2tlZCBmb3IgdmFsaWRpdHkgdGhyb3VnaCBGaXJlYmFzZSBBdXRoIGFuZCB0aGUgdXNlcidzXG4gICAqIGVtYWlsIGlzIHZlcmlmaWVkIHRvIGhhdmUgYWNjZXNzIHRvIFJvb3QgQ01TLCBvdGhlcndpc2UgcmV0dXJucyBgbnVsbGAuXG4gICAqL1xuICBhc3luYyBmdW5jdGlvbiBnZXRDdXJyZW50VXNlcihyZXE6IFJlcXVlc3QpOiBQcm9taXNlPENNU1VzZXIgfCBudWxsPiB7XG4gICAgY29uc3Qgc2Vzc2lvbkNvb2tpZSA9IHJlcS5zZXNzaW9uLmdldEl0ZW0oU0VTU0lPTl9DT09LSUVfQVVUSCk7XG4gICAgaWYgKCFzZXNzaW9uQ29va2llKSB7XG4gICAgICBpZiAobG9nTGV2ZWwgPT09ICdkZWJ1ZycpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ25vIGxvZ2luIHNlc3Npb24gY29va2llJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBPbiBsb2NhbCBkZXYsIHZlcmlmeSB0aGUgZGVjb2RlZCBpZFRva2VuIGhhcyBhIHZhbGlkIGVtYWlsLiBUaGUgZmlyZWJhc2VcbiAgICAvLyBhdXRoIHZlcmlmaWNhdGlvbiBvdGhlcndpc2Ugd291bGQgcmVxdWlyZSBhIHNlcnZpY2UgYWNjb3VudC5cbiAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCcpIHtcbiAgICAgIGNvbnN0IGp3dCA9IGpzb253ZWJ0b2tlbi5kZWNvZGUoc2Vzc2lvbkNvb2tpZSkgYXMganNvbndlYnRva2VuLkp3dFBheWxvYWQ7XG4gICAgICBpZiAoIWp3dD8uZW1haWwgfHwgIWp3dD8uZW1haWxfdmVyaWZpZWQpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgICAvLyBDaGVjayB3aGV0aGVyIHVzZXIgaXMgYXV0aG9yaXplZC5cbiAgICAgIGlmIChvcHRpb25zLmlzVXNlckF1dGhvcml6ZWQpIHtcbiAgICAgICAgY29uc3QgYXV0aG9yaXplZCA9IGF3YWl0IG9wdGlvbnMuaXNVc2VyQXV0aG9yaXplZChyZXEsIHtcbiAgICAgICAgICBlbWFpbDogand0LmVtYWlsLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKCFhdXRob3JpemVkKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ3Nlc3Npb24gZmFpbGVkOiBub3QgYXV0aG9yaXplZCcpO1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBWZXJpZnkgdGhlIHVzZXIgZXhpc3RzIGluIHRoZSBEQidzIEFDTCBsaXN0LlxuICAgICAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocmVxLnJvb3RDb25maWchKTtcbiAgICAgIGNvbnN0IHVzZXJIYXNBY2Nlc3MgPSBhd2FpdCBjbXNDbGllbnQudXNlckV4aXN0c0luQWNsKGp3dC5lbWFpbCk7XG4gICAgICBpZiAoIXVzZXJIYXNBY2Nlc3MpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ3Nlc3Npb24gZmFpbGVkOiB1c2VyIGlzIG5vdCBpbiB0aGUgZmlyZXN0b3JlIGFjbCBsaXN0Jyk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtlbWFpbDogand0LmVtYWlsfTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgLy8gVmVyaWZ5IHRoZSBpZFRva2VuIHVzaW5nIGZpcmViYXNlIGF1dGgsIGNoZWNraW5nIGZvciB0b2tlbiByZXZvY2F0aW9ucy5cbiAgICAgIGNvbnN0IGp3dCA9IGF3YWl0IGF1dGgudmVyaWZ5U2Vzc2lvbkNvb2tpZShzZXNzaW9uQ29va2llLCB0cnVlKTtcbiAgICAgIGlmIChpc0V4cGlyZWQoand0KSkge1xuICAgICAgICBjb25zb2xlLmxvZygnc2Vzc2lvbiBmYWlsZWQ6IHRva2VuIGlzIGV4cGlyZWQnKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgICAvLyBWZXJpZnkgdXNlcidzIGVtYWlsIGlzIHZlcmlmaWVkLlxuICAgICAgaWYgKCFqd3QuZW1haWwgfHwgIWp3dC5lbWFpbF92ZXJpZmllZCkge1xuICAgICAgICBjb25zb2xlLmxvZygnc2Vzc2lvbiBmYWlsZWQ6IGVtYWlsIG5vdCB2ZXJpZmllZCcpO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIC8vIENoZWNrIHdoZXRoZXIgdXNlciBpcyBhdXRob3JpemVkLlxuICAgICAgaWYgKG9wdGlvbnMuaXNVc2VyQXV0aG9yaXplZCkge1xuICAgICAgICBjb25zdCBhdXRob3JpemVkID0gYXdhaXQgb3B0aW9ucy5pc1VzZXJBdXRob3JpemVkKHJlcSwge1xuICAgICAgICAgIGVtYWlsOiBqd3QuZW1haWwhLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKCFhdXRob3JpemVkKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ3Nlc3Npb24gZmFpbGVkOiBub3QgYXV0aG9yaXplZCcpO1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBWZXJpZnkgdGhlIHVzZXIgZXhpc3RzIGluIHRoZSBEQidzIEFDTCBsaXN0LlxuICAgICAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocmVxLnJvb3RDb25maWchKTtcbiAgICAgIGNvbnN0IHVzZXJIYXNBY2Nlc3MgPSBhd2FpdCBjbXNDbGllbnQudXNlckV4aXN0c0luQWNsKGp3dC5lbWFpbCk7XG4gICAgICBpZiAoIXVzZXJIYXNBY2Nlc3MpIHtcbiAgICAgICAgY29uc29sZS5sb2coJ3Nlc3Npb24gZmFpbGVkOiB1c2VyIGlzIG5vdCBpbiB0aGUgZmlyZXN0b3JlIGFjbCBsaXN0Jyk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgLy8gSldUIHZlcmlmaWVkLlxuICAgICAgcmV0dXJuIHtlbWFpbDogand0LmVtYWlsIX07XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdmYWlsZWQgdG8gdmVyaWZ5IGp3dCB0b2tlbicpO1xuICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVkaXJlY3RUb0xvZ2luKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkge1xuICAgIGlmIChTdHJpbmcocmVxLm9yaWdpbmFsVXJsKS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoJy9jbXMvYXBpJykpIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAxKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdOT1RfQVVUSE9SSVpFRCd9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc29sZS5sb2coJ3JlZGlyZWN0aW5nIHRvIGxvZ2luIHBhZ2UnKTtcbiAgICBjb25zdCBwYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHtcbiAgICAgIGNvbnRpbnVlOiByZXEub3JpZ2luYWxVcmwsXG4gICAgfSk7XG4gICAgcmVzLnJlZGlyZWN0KGAvY21zL2xvZ2luPyR7cGFyYW1zLnRvU3RyaW5nKCl9YCk7XG4gIH1cblxuICBjb25zdCBwbHVnaW46IENNU1BsdWdpbiA9IHtcbiAgICBuYW1lOiAncm9vdC1jbXMnLFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgY29uZmlnIG9wdGlvbnMgcGFzc2VkIHRvIHRoZSBwbHVnaW4uXG4gICAgICovXG4gICAgZ2V0Q29uZmlnOiAoKSA9PiB7XG4gICAgICByZXR1cm4gb3B0aW9ucztcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgRmlyZWJhc2UgQXBwIGluc3RhbmNlIHVzZWQgYnkgdGhlIHBsdWdpbi5cbiAgICAgKi9cbiAgICBnZXRGaXJlYmFzZUFwcDogKCkgPT4ge1xuICAgICAgcmV0dXJuIGFwcDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgRmlyZXN0b3JlIGluc3RhbmNlIHVzZWQgYnkgdGhlIHBsdWdpbi5cbiAgICAgKi9cbiAgICBnZXRGaXJlc3RvcmU6ICgpID0+IHtcbiAgICAgIGNvbnN0IGRhdGFiYXNlSWQgPSBmaXJlYmFzZUNvbmZpZy5kYXRhYmFzZUlkIHx8ICcoZGVmYXVsdCknO1xuICAgICAgcmV0dXJuIGdldEZpcmVzdG9yZShhcHAsIGRhdGFiYXNlSWQpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBIG1hcCBvZiBzc3IgZmlsZXMgdG8gaW5jbHVkZSB3aGVuIHJ1bm5pbmcgYHJvb3QgYnVpbGRgLlxuICAgICAqL1xuICAgIHNzcklucHV0OiAoKSA9PiAoe1xuICAgICAgY21zOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi9hcHAuanMnKSxcbiAgICB9KSxcblxuICAgIGhvb2tzOiB7XG4gICAgICAvKipcbiAgICAgICAqIFN0YXJ0dXAgaG9vay4gT24gYGRldmAgYW5kIGBidWlsZGAgY29tbWFuZHMsIHRoZSBwbHVnaW4gZG9lc1xuICAgICAgICogY29tcGF0aWJpbGl0eSBjaGVja3MuXG4gICAgICAgKi9cbiAgICAgIHN0YXJ0dXA6IGFzeW5jICh7Y29tbWFuZCwgcm9vdENvbmZpZ30pID0+IHtcbiAgICAgICAgaWYgKGNvbW1hbmQgPT09ICdkZXYnIHx8IGNvbW1hbmQgPT09ICdidWlsZCcpIHtcbiAgICAgICAgICBhd2FpdCBydW5Db21wYXRpYmlsaXR5Q2hlY2tzKHJvb3RDb25maWcpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBdHRhY2hlcyBDTVMtc3BlY2lmaWMgbWlkZGxld2FyZSB0byB0aGUgUm9vdC5qcyBzZXJ2ZXIuXG4gICAgICovXG4gICAgY29uZmlndXJlU2VydmVyOiBhc3luYyAoXG4gICAgICBzZXJ2ZXI6IFNlcnZlcixcbiAgICAgIHNlcnZlck9wdGlvbnM6IENvbmZpZ3VyZVNlcnZlck9wdGlvbnNcbiAgICApID0+IHtcbiAgICAgIHNlcnZlci51c2UoYm9keVBhcnNlci5qc29uKCkpO1xuXG4gICAgICBhc3luYyBmdW5jdGlvbiBnZXRSZW5kZXJlcihyZXE6IFJlcXVlc3QpOiBQcm9taXNlPEFwcE1vZHVsZT4ge1xuICAgICAgICBpZiAoc2VydmVyT3B0aW9ucy50eXBlID09PSAnZGV2Jykge1xuICAgICAgICAgIGNvbnN0IGFwcEZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4vYXBwLmpzJyk7XG4gICAgICAgICAgY29uc3QgYXBwID0gKGF3YWl0IHJlcS52aXRlU2VydmVyIS5zc3JMb2FkTW9kdWxlKFxuICAgICAgICAgICAgYXBwRmlsZVBhdGhcbiAgICAgICAgICApKSBhcyBBcHBNb2R1bGU7XG4gICAgICAgICAgcmV0dXJuIGFwcDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGFwcEltcG9ydFBhdGggPSBwYXRoLnJlc29sdmUoXG4gICAgICAgICAgcmVxLnJvb3RDb25maWchLnJvb3REaXIsXG4gICAgICAgICAgJ2Rpc3Qvc2VydmVyL2Ntcy5qcydcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKCEoYXdhaXQgZmlsZUV4aXN0cyhhcHBJbXBvcnRQYXRoKSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAnZGlzdC9zZXJ2ZXIvY21zLmpzIG5vdCBmb3VuZC4gcnVuIGByb290IGJ1aWxkYCB0byBjcmVhdGUgaXQuJ1xuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYXBwID0gKGF3YWl0IGltcG9ydChhcHBJbXBvcnRQYXRoKSkgYXMgQXBwTW9kdWxlO1xuICAgICAgICByZXR1cm4gYXBwO1xuICAgICAgfVxuXG4gICAgICAvLyBMb2dpbiBoYW5kbGVyLlxuICAgICAgc2VydmVyLnVzZSgnL2Ntcy9sb2dpbicsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIHJlcS5tZXRob2QgPT09ICdQVVQnICYmXG4gICAgICAgICAgcmVxLmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddID09PSAnYXBwbGljYXRpb24vanNvbidcbiAgICAgICAgKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHthdXRob3JpemVkLCByZWFzb259ID0gYXdhaXQgdmVyaWZ5VXNlckxvZ2luKHJlcSk7XG4gICAgICAgICAgICBpZiAoIWF1dGhvcml6ZWQpIHtcbiAgICAgICAgICAgICAgcmVzXG4gICAgICAgICAgICAgICAgLnN0YXR1cyg0MDEpXG4gICAgICAgICAgICAgICAgLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ05PVF9BVVRIT1JJWkVEJywgcmVhc29ufSk7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gU2V0IHNlc3Npb24gZXhwaXJhdGlvbiB0byA1IGRheXMuXG4gICAgICAgICAgICBjb25zdCBleHBpcmVzSW4gPSA2MCAqIDYwICogMjQgKiA1ICogMTAwMDtcbiAgICAgICAgICAgIGNvbnN0IGlkVG9rZW4gPSByZXEuYm9keS5pZFRva2VuITtcblxuICAgICAgICAgICAgbGV0IHNlc3Npb25Db29raWU6IHN0cmluZztcbiAgICAgICAgICAgIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50Jykge1xuICAgICAgICAgICAgICBzZXNzaW9uQ29va2llID0gaWRUb2tlbjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHNlc3Npb25Db29raWUgPSBhd2FpdCBhdXRoLmNyZWF0ZVNlc3Npb25Db29raWUoaWRUb2tlbiwge1xuICAgICAgICAgICAgICAgIGV4cGlyZXNJbixcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXMuc2Vzc2lvbi5zZXRJdGVtKFNFU1NJT05fQ09PS0lFX0FVVEgsIHNlc3Npb25Db29raWUpO1xuICAgICAgICAgICAgcmVzLnNhdmVTZXNzaW9uKCk7XG4gICAgICAgICAgICByZXMuanNvbih7c3VjY2VzczogdHJ1ZX0pO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgICAgICAgaWYgKGVyci5zdGFjaykge1xuICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVyci5zdGFjayk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXNcbiAgICAgICAgICAgICAgLnN0YXR1cyg1MDApXG4gICAgICAgICAgICAgIC5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTktOT1dOX1NFUlZFUl9FUlJPUid9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBhcHAgPSBhd2FpdCBnZXRSZW5kZXJlcihyZXEpO1xuICAgICAgICAgIGFwcC5yZW5kZXJTaWduSW4ocmVxLCByZXMsIHtcbiAgICAgICAgICAgIHJvb3RDb25maWc6IHJlcS5yb290Q29uZmlnISxcbiAgICAgICAgICAgIGNtc0NvbmZpZzogb3B0aW9ucyxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgICAgIGlmIChlcnIuc3RhY2spIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmVzLnN0YXR1cyg1MDApLnNlbmQoJ1VOS05PV04gU0VSVkVSIEVSUk9SJyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICAvLyBMb2dvdXQgaGFuZGxlci5cbiAgICAgIHNlcnZlci51c2UoJy9jbXMvbG9nb3V0JywgYXN5bmMgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgICAgICByZXMuc2Vzc2lvbi5yZW1vdmVJdGVtKFNFU1NJT05fQ09PS0lFX0FVVEgpO1xuICAgICAgICByZXMuc2F2ZVNlc3Npb24oKTtcbiAgICAgICAgcmVzLnJlZGlyZWN0KCcvY21zL2xvZ2luJyk7XG4gICAgICB9KTtcblxuICAgICAgLy8gSW5qZWN0IHRoZSBjdXJyZW50IHVzZXIgaW50byB0aGUgcmVxIG9iamVjdCBhbmQgY2hlY2sgaWYgbG9naW4gaXNcbiAgICAgIC8vIHJlcXVpcmVkLCBzZW5kaW5nIHVuYXV0aGVudGljYXRlZCB1c2VycyB0byB0aGUgbG9naW4gcGFnZS5cbiAgICAgIHNlcnZlci51c2UoYXN5bmMgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKSA9PiB7XG4gICAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCBnZXRDdXJyZW50VXNlcihyZXEpO1xuICAgICAgICBpZiAodXNlcikge1xuICAgICAgICAgIHJlcS51c2VyID0gdXNlcjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIG5vIHVzZXIgYW5kIGxvZ2luIGlzIHJlcXVpcmVkIGZvciB0aGUgZ2l2ZW4gcGF0aCwgcmVkaXJlY3QgdG8gdGhlXG4gICAgICAgIC8vIGxvZ2luIHBhZ2UuXG4gICAgICAgIGlmICghdXNlciAmJiBsb2dpblJlcXVpcmVkKHJlcSkpIHtcbiAgICAgICAgICByZWRpcmVjdFRvTG9naW4ocmVxLCByZXMpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIG5leHQoKTtcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBzdGF0aWNEaXIgPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAndWknKTtcbiAgICAgIHNlcnZlci51c2UoJy9jbXMvc3RhdGljJywgc2lydihzdGF0aWNEaXIsIHtkZXY6IGZhbHNlfSkpO1xuXG4gICAgICAvLyBSZWdpc3RlciBBUEkgaGFuZGxlcnMuXG4gICAgICBhcGkoc2VydmVyKTtcblxuICAgICAgLy8gUmVuZGVyIHRoZSBDTVMgU1BBLlxuICAgICAgc2VydmVyLnVzZSgnL2NtcycsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBFbmZvcmNlIGxvZ2luIGZvciBhbGwgQ01TIHBhdGhzLiBUaGUgYHJlcS51c2VyYCB3b3VsZCBvbmx5IGJlXG4gICAgICAgICAgLy8gcG9wdWxhdGVkIGlmIHRoZSBmaXJlYmFzZSBhdXRoIHRva2VuIGlzIHZhbGlkIGFuZCB0aGUgdXNlciBoYXNcbiAgICAgICAgICAvLyBhY2Nlc3MgdmlhIHRoZSBSb290IENNUyBzaGFyZWJveC5cbiAgICAgICAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICAgICAgICByZWRpcmVjdFRvTG9naW4ocmVxLCByZXMpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBhcHAgPSBhd2FpdCBnZXRSZW5kZXJlcihyZXEpO1xuICAgICAgICAgIGF3YWl0IGFwcC5yZW5kZXJBcHAocmVxLCByZXMsIHtcbiAgICAgICAgICAgIHJvb3RDb25maWc6IHJlcS5yb290Q29uZmlnISxcbiAgICAgICAgICAgIGNtc0NvbmZpZzogb3B0aW9ucyxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgLy8gVE9ETyhzdGV2ZW5sZSk6IHJlbmRlciBhIGN1c3RvbSBlcnJvciBwYWdlLlxuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgICAgICByZXMuc3RhdHVzKDUwMCkuc2VuZCgnVU5LTk9XTiBTRVJWRVIgRVJST1InKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSxcbiAgfTtcblxuICBpZiAob3B0aW9ucy53YXRjaCAhPT0gZmFsc2UpIHtcbiAgICBwbHVnaW4ub25GaWxlQ2hhbmdlID0gKFxuICAgICAgZXZlbnROYW1lOiAnYWRkJyB8ICdhZGREaXInIHwgJ2NoYW5nZScgfCAndW5saW5rJyB8ICd1bmxpbmtEaXInLFxuICAgICAgZmlsZXBhdGg6IHN0cmluZ1xuICAgICkgPT4ge1xuICAgICAgaWYgKGZpbGVwYXRoLmVuZHNXaXRoKCcuc2NoZW1hLnRzJykpIHtcbiAgICAgICAgLy8gQXZvaWQgbG9hZGluZyB0aGUgYGdlbmVyYXRlLXR5cGVzLmpzYCBtb2R1bGUgaWYgaXQgaXMgbm90IG5lZWRlZC5cbiAgICAgICAgLy8gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vYmxpbmtrL3Jvb3Rqcy9pc3N1ZXMvNDI2XG4gICAgICAgIGltcG9ydCgnLi4vY2xpL2dlbmVyYXRlLXR5cGVzLmpzJykudGhlbigoZ2VuZXJhdGVUeXBlc01vZHVsZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGdlbmVyYXRlVHlwZXMgPSBnZW5lcmF0ZVR5cGVzTW9kdWxlLmdlbmVyYXRlVHlwZXM7XG4gICAgICAgICAgZ2VuZXJhdGVUeXBlcygpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIHBsdWdpbjtcbn1cblxuZnVuY3Rpb24gZmlsZUV4aXN0cyhmaWxlcGF0aDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHJldHVybiBmc1xuICAgIC5hY2Nlc3MoZmlsZXBhdGgpXG4gICAgLnRoZW4oKCkgPT4gdHJ1ZSlcbiAgICAuY2F0Y2goKCkgPT4gZmFsc2UpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q21zUGx1Z2luKHJvb3RDb25maWc6IFJvb3RDb25maWcpOiBDTVNQbHVnaW4ge1xuICBjb25zdCBwbHVnaW5zOiBQbHVnaW5bXSA9IHJvb3RDb25maWcucGx1Z2lucyB8fCBbXTtcbiAgY29uc3QgcGx1Z2luID0gcGx1Z2lucy5maW5kKChwbHVnaW4pID0+IHBsdWdpbi5uYW1lID09PSAncm9vdC1jbXMnKTtcbiAgaWYgKCFwbHVnaW4pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NvdWxkIG5vdCBmaW5kIHJvb3QtY21zIHBsdWdpbiBjb25maWcgaW4gcm9vdC5jb25maWcudHMnKTtcbiAgfVxuICByZXR1cm4gcGx1Z2luIGFzIENNU1BsdWdpbjtcbn1cbiIsICJpbXBvcnQge1NlcnZlciwgUmVxdWVzdCwgUmVzcG9uc2V9IGZyb20gJ0BibGlua2svcm9vdCc7XG5pbXBvcnQge211bHRpcGFydE1pZGRsZXdhcmV9IGZyb20gJ0BibGlua2svcm9vdC9taWRkbGV3YXJlJztcbmltcG9ydCB7Q2hhdCwgQ2hhdENsaWVudH0gZnJvbSAnLi9haS5qcyc7XG5pbXBvcnQge1Jvb3RDTVNDbGllbnR9IGZyb20gJy4vY2xpZW50LmpzJztcbmltcG9ydCB7cnVuQ3JvbkpvYnN9IGZyb20gJy4vY3Jvbi5qcyc7XG5pbXBvcnQge2FycmF5VG9Dc3YsIGNzdlRvQXJyYXl9IGZyb20gJy4vY3N2LmpzJztcblxuLyoqXG4gKiBSZWdpc3RlcnMgQVBJIG1pZGRsZXdhcmUgaGFuZGxlcnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcGkoc2VydmVyOiBTZXJ2ZXIpIHtcbiAgLyoqXG4gICAqIFJ1bnMgQ01TIGNyb24gam9icy5cbiAgICovXG4gIHNlcnZlci51c2UoJy9jbXMvYXBpL2Nyb24ucnVuJywgYXN5bmMgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBydW5Dcm9uSm9icyhyZXEucm9vdENvbmZpZyEpO1xuICAgICAgcmVzLnN0YXR1cygyMDApLmpzb24oe3N1Y2Nlc3M6IHRydWV9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZX0pO1xuICAgIH1cbiAgfSk7XG5cbiAgLyoqXG4gICAqIEFjY2VwdHMgYSBKU09OIG9iamVjdCBjb250YWluaW5nIHtoZWFkZXJzOiBbLi4uXSwgcm93czogWy4uLl19IGFuZCBzZW5kc1xuICAgKiBhbiBIVFRQIHJlc3BvbnNlIHdpdGggYSBjb3JyZXNwb25kaW5nIENTViBmaWxlIGFzIGFuIGF0dGFjaG1lbnQuXG4gICAqXG4gICAqIFNhbXBsZSByZXF1ZXN0OlxuICAgKlxuICAgKiBgYGBqc29uXG4gICAqIHtcbiAgICogICBcImhlYWRlcnNcIjogW1wiZm9vXCJdLFxuICAgKiAgIFwicm93c1wiOiBbXG4gICAqICAgICB7XCJmb29cIjogXCJiYXJcIn0sXG4gICAqICAgICB7XCJmb29cIjogXCJiYXpcIn0sXG4gICAqICAgXVxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgc2VydmVyLnVzZSgnL2Ntcy9hcGkvY3N2LmRvd25sb2FkJywgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgIGlmIChcbiAgICAgIHJlcS5tZXRob2QgIT09ICdQT1NUJyB8fFxuICAgICAgIVN0cmluZyhyZXEuZ2V0KCdjb250ZW50LXR5cGUnKSkuc3RhcnRzV2l0aCgnYXBwbGljYXRpb24vanNvbicpXG4gICAgKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnQkFEX1JFUVVFU1QnfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGJvZHkgPSByZXEuYm9keSB8fCB7fTtcbiAgICAgIGNvbnN0IGhlYWRlcnMgPSBib2R5LmhlYWRlcnMgfHwgW107XG4gICAgICBjb25zdCByb3dzID0gYm9keS5yb3dzIHx8IFtdO1xuICAgICAgY29uc3QgY3N2ID0gYXJyYXlUb0Nzdih7aGVhZGVycywgcm93c30pO1xuICAgICAgcmVzLnNldEhlYWRlcignQ29udGVudC1UeXBlJywgJ3RleHQvY3N2Jyk7XG4gICAgICByZXMuc2V0SGVhZGVyKCdDb250ZW50LURpc3Bvc2l0aW9uJywgJ2F0dGFjaG1lbnQ7IGZpbGVuYW1lPVwiZGF0YS5jc3ZcIicpO1xuICAgICAgcmVzLnN0YXR1cygyMDApLmVuZChjc3YpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnIuc3RhY2sgfHwgZXJyKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTktOT1dOJ30pO1xuICAgIH1cbiAgfSk7XG5cbiAgLyoqXG4gICAqIEltcG9ydHMgYSBDU1YgZmlsZSBhbmQgcmV0dXJucyBhIEpTT04gYXJyYXkgb2Ygb2JqZWN0cyByZXByZXNlbnRpbmcgdGhlXG4gICAqIENTVi5cbiAgICpcbiAgICogU2FtcGxlIHJlc3BvbnNlOlxuICAgKlxuICAgKiBgYGBqc29uXG4gICAqIHtcbiAgICogICBcInN1Y2Nlc3NcIjogdHJ1ZSxcbiAgICogICBcImRhdGFcIjogW1xuICAgKiAgICAge1wiZm9vXCI6IFwiYmFyXCJ9LFxuICAgKiAgICAge1wiZm9vXCI6IFwiYmF6XCJ9LFxuICAgKiAgIF1cbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIHNlcnZlci51c2UoXG4gICAgJy9jbXMvYXBpL2Nzdi5pbXBvcnQnLFxuICAgIG11bHRpcGFydE1pZGRsZXdhcmUoKSxcbiAgICAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgICBpZiAocmVxLm1ldGhvZCAhPT0gJ1BPU1QnIHx8ICFyZXEuZmlsZXMgfHwgIXJlcS5maWxlcy5maWxlKSB7XG4gICAgICAgIHJlcy5zdGF0dXMoNDAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdCQURfUkVRVUVTVCd9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBmaWxlID0gcmVxLmZpbGVzLmZpbGU7XG4gICAgICAgIGNvbnN0IGNzdlN0cmluZyA9IGZpbGUuYnVmZmVyLnRvU3RyaW5nKCd1dGY4Jyk7XG4gICAgICAgIGNvbnN0IHJvd3MgPSBjc3ZUb0FycmF5KGNzdlN0cmluZyk7XG4gICAgICAgIHJlcy5zdGF0dXMoMjAwKS5qc29uKHtzdWNjZXNzOiB0cnVlLCBkYXRhOiByb3dzfSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnIuc3RhY2sgfHwgZXJyKTtcbiAgICAgICAgcmVzLnN0YXR1cyg1MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ1VOS05PV04nfSk7XG4gICAgICB9XG4gICAgfVxuICApO1xuXG4gIC8qKlxuICAgKiBSdW5zIGEgZGF0YSBzb3VyY2Ugc3luYy5cbiAgICovXG4gIHNlcnZlci51c2UoJy9jbXMvYXBpL2RhdGEuc3luYycsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICBpZiAoXG4gICAgICByZXEubWV0aG9kICE9PSAnUE9TVCcgfHxcbiAgICAgICFTdHJpbmcocmVxLmdldCgnY29udGVudC10eXBlJykpLnN0YXJ0c1dpdGgoJ2FwcGxpY2F0aW9uL2pzb24nKVxuICAgICkge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0JBRF9SRVFVRVNUJ30pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghcmVxLnVzZXI/LmVtYWlsKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMSkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5BVVRIT1JJWkVEJ30pO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcUJvZHkgPSByZXEuYm9keSB8fCB7fTtcbiAgICBjb25zdCBkYXRhU291cmNlSWQgPSByZXFCb2R5LmlkO1xuICAgIGlmICghZGF0YVNvdXJjZUlkKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnTUlTU0lOR19JRCd9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocmVxLnJvb3RDb25maWchKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY21zQ2xpZW50LnN5bmNEYXRhU291cmNlKGRhdGFTb3VyY2VJZCwge3N5bmNlZEJ5OiByZXEudXNlci5lbWFpbH0pO1xuICAgICAgcmVzLnN0YXR1cygyMDApLmpzb24oe3N1Y2Nlc3M6IHRydWUsIGlkOiBkYXRhU291cmNlSWR9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrIHx8IGVycik7XG4gICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5LTk9XTid9KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBMb2dzIGFuIGFjdGlvbi5cbiAgICovXG4gIHNlcnZlci51c2UoJy9jbXMvYXBpL2FjdGlvbnMubG9nJywgYXN5bmMgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgIGlmIChcbiAgICAgIHJlcS5tZXRob2QgIT09ICdQT1NUJyB8fFxuICAgICAgIVN0cmluZyhyZXEuZ2V0KCdjb250ZW50LXR5cGUnKSkuc3RhcnRzV2l0aCgnYXBwbGljYXRpb24vanNvbicpXG4gICAgKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnQkFEX1JFUVVFU1QnfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFyZXEudXNlcj8uZW1haWwpIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAxKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTkFVVEhPUklaRUQnfSk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVxQm9keSA9IHJlcS5ib2R5IHx8IHt9O1xuICAgIGNvbnN0IGFjdGlvbiA9IHJlcUJvZHkuYWN0aW9uO1xuICAgIGlmICghYWN0aW9uKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMCkuanNvbih7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBlcnJvcjogJ01JU1NJTkdfUkVRVUlSRURfRklFTEQnLFxuICAgICAgICBmaWVsZDogJ2FjdGlvbicsXG4gICAgICB9KTtcbiAgICB9XG4gICAgY29uc3QgbWV0YWRhdGEgPSByZXFCb2R5Lm1ldGFkYXRhIHx8IHt9O1xuXG4gICAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocmVxLnJvb3RDb25maWchKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY21zQ2xpZW50LmxvZ0FjdGlvbihhY3Rpb24sIHtcbiAgICAgICAgYnk6IHJlcS51c2VyPy5lbWFpbCxcbiAgICAgICAgbWV0YWRhdGE6IG1ldGFkYXRhLFxuICAgICAgfSk7XG4gICAgICByZXMuc3RhdHVzKDIwMCkuanNvbih7c3VjY2VzczogdHJ1ZX0pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnIuc3RhY2sgfHwgZXJyKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTktOT1dOJ30pO1xuICAgIH1cbiAgfSk7XG5cbiAgLyoqXG4gICAqIEFJIGNoYXRib3QuXG4gICAqL1xuICBzZXJ2ZXIudXNlKCcvY21zL2FwaS9haS5jaGF0JywgYXN5bmMgKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkgPT4ge1xuICAgIGlmIChcbiAgICAgIHJlcS5tZXRob2QgIT09ICdQT1NUJyB8fFxuICAgICAgIVN0cmluZyhyZXEuZ2V0KCdjb250ZW50LXR5cGUnKSkuc3RhcnRzV2l0aCgnYXBwbGljYXRpb24vanNvbicpXG4gICAgKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMCkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnQkFEX1JFUVVFU1QnfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghcmVxLnVzZXI/LmVtYWlsKSB7XG4gICAgICByZXMuc3RhdHVzKDQwMSkuanNvbih7c3VjY2VzczogZmFsc2UsIGVycm9yOiAnVU5BVVRIT1JJWkVEJ30pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCByZXFCb2R5ID0gcmVxLmJvZHkgfHwge307XG4gICAgaWYgKCFyZXFCb2R5LnByb21wdCkge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ01JU1NJTkdfUFJPTVBUJ30pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBwcm9tcHQgPSByZXFCb2R5LnByb21wdDtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBjbXNDbGllbnQgPSBuZXcgUm9vdENNU0NsaWVudChyZXEucm9vdENvbmZpZyEpO1xuICAgICAgY29uc3QgY2hhdENsaWVudCA9IG5ldyBDaGF0Q2xpZW50KGNtc0NsaWVudCwgcmVxLnVzZXIuZW1haWwpO1xuICAgICAgbGV0IGNoYXQ6IENoYXQ7XG4gICAgICBpZiAocmVxQm9keS5jaGF0SWQpIHtcbiAgICAgICAgY2hhdCA9IGF3YWl0IGNoYXRDbGllbnQuZ2V0Q2hhdChyZXFCb2R5LmNoYXRJZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjaGF0ID0gYXdhaXQgY2hhdENsaWVudC5jcmVhdGVDaGF0KCk7XG4gICAgICB9XG4gICAgICBjb25zdCBjaGF0UmVzcG9uc2UgPSBhd2FpdCBjaGF0LnNlbmRQcm9tcHQocHJvbXB0KTtcbiAgICAgIHJlc1xuICAgICAgICAuc3RhdHVzKDIwMClcbiAgICAgICAgLmpzb24oe3N1Y2Nlc3M6IHRydWUsIGNoYXRJZDogY2hhdC5pZCwgcmVzcG9uc2U6IGNoYXRSZXNwb25zZX0pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnIuc3RhY2sgfHwgZXJyKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTktOT1dOJ30pO1xuICAgIH1cbiAgfSk7XG5cbiAgc2VydmVyLnVzZSgnL2Ntcy9hcGkvYWkubGlzdF9jaGF0cycsIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICBpZiAoXG4gICAgICByZXEubWV0aG9kICE9PSAnUE9TVCcgfHxcbiAgICAgICFTdHJpbmcocmVxLmdldCgnY29udGVudC10eXBlJykpLnN0YXJ0c1dpdGgoJ2FwcGxpY2F0aW9uL2pzb24nKVxuICAgICkge1xuICAgICAgcmVzLnN0YXR1cyg0MDApLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ0JBRF9SRVFVRVNUJ30pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoIXJlcS51c2VyPy5lbWFpbCkge1xuICAgICAgcmVzLnN0YXR1cyg0MDEpLmpzb24oe3N1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogJ1VOQVVUSE9SSVpFRCd9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgcmVxQm9keSA9IHJlcS5ib2R5IHx8IHt9O1xuICAgIGNvbnN0IGxpbWl0ID0gcmVxQm9keS5saW1pdDtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBjbXNDbGllbnQgPSBuZXcgUm9vdENNU0NsaWVudChyZXEucm9vdENvbmZpZyEpO1xuICAgICAgY29uc3QgY2hhdENsaWVudCA9IG5ldyBDaGF0Q2xpZW50KGNtc0NsaWVudCwgcmVxLnVzZXIuZW1haWwpO1xuICAgICAgY29uc3QgY2hhdHMgPSBhd2FpdCBjaGF0Q2xpZW50Lmxpc3RDaGF0cyh7bGltaXR9KTtcbiAgICAgIHJlcy5zdGF0dXMoMjAwKS5qc29uKHtzdWNjZXNzOiB0cnVlLCBjaGF0c30pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnIuc3RhY2sgfHwgZXJyKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdVTktOT1dOJ30pO1xuICAgIH1cbiAgfSk7XG59XG4iLCAiaW1wb3J0IGNyeXB0byBmcm9tICdub2RlOmNyeXB0byc7XG5pbXBvcnQge2dlbmVyYXRlfSBmcm9tICdAZ2Vua2l0LWFpL2FpJztcbmltcG9ydCB7Y29uZmlndXJlR2Vua2l0fSBmcm9tICdAZ2Vua2l0LWFpL2NvcmUnO1xuaW1wb3J0IHt2ZXJ0ZXhBSX0gZnJvbSAnQGdlbmtpdC1haS92ZXJ0ZXhhaSc7XG5pbXBvcnQge2dlbWluaTE1UHJvUHJldmlldywgZ2VtaW5pMTVGbGFzaFByZXZpZXd9IGZyb20gJ0BnZW5raXQtYWkvdmVydGV4YWknO1xuaW1wb3J0IHtUaW1lc3RhbXB9IGZyb20gJ2ZpcmViYXNlLWFkbWluL2ZpcmVzdG9yZSc7XG5pbXBvcnQge1Jvb3RDTVNDbGllbnR9IGZyb20gJy4vY2xpZW50LmpzJztcbmltcG9ydCB7Q01TUGx1Z2luT3B0aW9uc30gZnJvbSAnLi9wbHVnaW4uanMnO1xuXG5sZXQgZ2Vua2l0SXNDb25maWd1cmVkID0gZmFsc2U7XG5cbmludGVyZmFjZSBDaGF0UHJvbXB0IHtcbiAgdGV4dD86IHN0cmluZztcbiAgbWVkaWE/OiB7XG4gICAgdXJsOiBzdHJpbmc7XG4gICAgY29udGVudFR5cGU6IHN0cmluZztcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIENoYXQge1xuICBjaGF0Q2xpZW50OiBDaGF0Q2xpZW50O1xuICBjbXNDbGllbnQ6IFJvb3RDTVNDbGllbnQ7XG4gIGNtc1BsdWdpbk9wdGlvbnM6IENNU1BsdWdpbk9wdGlvbnM7XG4gIGlkOiBzdHJpbmc7XG4gIGhpc3Rvcnk/OiBhbnk7XG4gIG1vZGVsPzogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGNoYXRDbGllbnQ6IENoYXRDbGllbnQsXG4gICAgaWQ6IHN0cmluZyxcbiAgICBvcHRpb25zPzoge2hpc3Rvcnk/OiBhbnk7IG1vZGVsPzogc3RyaW5nfVxuICApIHtcbiAgICB0aGlzLmNoYXRDbGllbnQgPSBjaGF0Q2xpZW50O1xuICAgIHRoaXMuY21zQ2xpZW50ID0gY2hhdENsaWVudC5jbXNDbGllbnQ7XG4gICAgdGhpcy5jbXNQbHVnaW5PcHRpb25zID0gdGhpcy5jbXNDbGllbnQuY21zUGx1Z2luLmdldENvbmZpZygpO1xuICAgIHRoaXMuaWQgPSBpZDtcbiAgICB0aGlzLmhpc3RvcnkgPSBvcHRpb25zPy5oaXN0b3J5O1xuICAgIHRoaXMubW9kZWwgPSBvcHRpb25zPy5tb2RlbDtcbiAgICBpZiAoIXRoaXMubW9kZWwpIHtcbiAgICAgIGlmICh0eXBlb2YgdGhpcy5jbXNQbHVnaW5PcHRpb25zLmV4cGVyaW1lbnRzPy5haSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgaWYgKHRoaXMuY21zUGx1Z2luT3B0aW9ucy5leHBlcmltZW50cy5haS5tb2RlbCkge1xuICAgICAgICAgIHRoaXMubW9kZWwgPSB0aGlzLmNtc1BsdWdpbk9wdGlvbnMuZXhwZXJpbWVudHMuYWkubW9kZWw7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBhc3luYyBzZW5kUHJvbXB0KHByb21wdDogc3RyaW5nIHwgQ2hhdFByb21wdCB8IENoYXRQcm9tcHRbXSk6IFByb21pc2U8YW55PiB7XG4gICAgaWYgKCFnZW5raXRJc0NvbmZpZ3VyZWQpIHtcbiAgICAgIGNvbnN0IGZpcmViYXNlQ29uZmlnID0gdGhpcy5jbXNQbHVnaW5PcHRpb25zLmZpcmViYXNlQ29uZmlnO1xuICAgICAgY29uZmlndXJlR2Vua2l0KHtcbiAgICAgICAgcGx1Z2luczogW1xuICAgICAgICAgIHZlcnRleEFJKHtcbiAgICAgICAgICAgIHByb2plY3RJZDogZmlyZWJhc2VDb25maWcucHJvamVjdElkLFxuICAgICAgICAgICAgLy8gVE9ETyhzdGV2ZW5sZSk6IGZpZ3VyZSBvdXQgd2hlcmUgdG8gZ2V0IHRoaXMuXG4gICAgICAgICAgICBsb2NhdGlvbjogZmlyZWJhc2VDb25maWcubG9jYXRpb24gfHwgJ3VzLWNlbnRyYWwxJyxcbiAgICAgICAgICB9KSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuICAgICAgZ2Vua2l0SXNDb25maWd1cmVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBsZXQgbW9kZWwgPSBnZW1pbmkxNUZsYXNoUHJldmlldztcbiAgICBpZiAodGhpcy5tb2RlbCA9PT0gJ2dlbWluaS0xLjUtcHJvJykge1xuICAgICAgbW9kZWwgPSBnZW1pbmkxNVByb1ByZXZpZXc7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmhpc3RvcnkpIHtcbiAgICAgIC8vIFNlZWQgdGhlIEFJIHdpdGggaW5mb3JtYXRpb24uXG4gICAgICBhd2FpdCB0aGlzLmluaXRIaXN0b3J5KCk7XG4gICAgfVxuXG4gICAgLy8gY29uc29sZS5sb2coJ3Byb21wdDonLCBwcm9tcHQpO1xuICAgIC8vIGlmICh0aGlzLmhpc3RvcnkpIHtcbiAgICAvLyAgIGNvbnNvbGUubG9nKCdoaXN0b3J5OicsIHRoaXMuaGlzdG9yeSk7XG4gICAgLy8gfVxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGdlbmVyYXRlKHtcbiAgICAgIG1vZGVsOiBtb2RlbCxcbiAgICAgIHByb21wdDogcHJvbXB0IGFzIGFueSxcbiAgICAgIGhpc3Rvcnk6IHRoaXMuaGlzdG9yeSxcbiAgICB9KTtcbiAgICBjb25zb2xlLmxvZyhyZXMudGV4dCgpKTtcbiAgICBjb25zdCBoaXN0b3J5ID0gcmVzLnRvSGlzdG9yeSgpO1xuICAgIHRoaXMuaGlzdG9yeSA9IGhpc3Rvcnk7XG4gICAgYXdhaXQgdGhpcy5kYkRvYygpLnVwZGF0ZSh7aGlzdG9yeSwgbW9kaWZpZWRBdDogVGltZXN0YW1wLm5vdygpfSk7XG4gICAgcmV0dXJuIHJlcy50ZXh0KCk7XG4gIH1cblxuICBkYkRvYygpIHtcbiAgICByZXR1cm4gdGhpcy5jaGF0Q2xpZW50LmRiQ29sbGVjdGlvbigpLmRvYyh0aGlzLmlkKTtcbiAgfVxuXG4gIGFzeW5jIGluaXRIaXN0b3J5KCkge1xuICAgIGNvbnN0IHN5c3RlbVRleHQgPSBbXG4gICAgICBgWW91IGFyZSBhbiBhc3Npc3RhbnQgZm9yIGEgaGVhZGxlc3MgQ01TIGNhbGxlZCBSb290IENNUyB3aGljaCBpcyB1c2VkIG9uIGEgd2Vic2l0ZSBjYWxsZWQgJHtcbiAgICAgICAgdGhpcy5jbXNQbHVnaW5PcHRpb25zLm5hbWUgfHwgdGhpcy5jbXNQbHVnaW5PcHRpb25zLmlkXG4gICAgICB9LiBZb3VyIGpvYiBpcyB0byBhbnN3ZXIgcXVlc3Rpb25zIGFib3V0IHRoZSBkb2NzIGluIHRoZSBzeXN0ZW0sIGFuZCBpZiByZXF1ZXN0ZWQsIGhlbHAgc3VnZ2VzdCBjaGFuZ2VzIHRvIHRoZSBKU09OIGRhdGEgaW4gdGhlIGRvY3MuIElmIHlvdSBkb24ndCBrbm93IHRoZSBhbnN3ZXIsIGp1c3Qgc2F5IHRoYXQgeW91IGRvbid0IGtub3csIGRvbid0IHRyeSB0byBtYWtlIHVwIGFuIGFuc3dlci4gQmUgZnJpZW5kbHkgYW5kIHBsYXlmdWwgd2l0aCB5b3VyIG1lc3NhZ2luZy5gLFxuICAgICAgJycsXG4gICAgICAnSGVyZSBpcyB0aGUgcm9vdC5jb25maWcudHMgZmlsZSBmb3IgdGhlIHNpdGU6JyxcbiAgICAgICdgYGAnLFxuICAgICAgSlNPTi5zdHJpbmdpZnkodGhpcy5jbXNDbGllbnQucm9vdENvbmZpZywgbnVsbCwgMiksXG4gICAgICAnYGBgJyxcbiAgICAgICcnLFxuICAgICAgJ0hlcmUgYXJlIHRoZSBkb2NzIHRoYXQgZXhpc3QgaW4gdGhlIHN5c3RlbTonLFxuICAgIF07XG5cbiAgICAvLyBUT0RPKHN0ZXZlbmxlKTogcmVhZCBmcm9tIGFsbCB0aGUgY29sbGVjdGlvbnMgaW4gdGhlIHN5c3RlbS5cbiAgICBjb25zdCBwYWdlcyA9IGF3YWl0IHRoaXMuY21zQ2xpZW50Lmxpc3REb2NzKCdQYWdlcycsIHttb2RlOiAnZHJhZnQnfSk7XG4gICAgcGFnZXMuZG9jcy5mb3JFYWNoKChkb2M6IGFueSkgPT4ge1xuICAgICAgc3lzdGVtVGV4dC5wdXNoKEpTT04uc3RyaW5naWZ5KGRvYykpO1xuICAgIH0pO1xuXG4gICAgdGhpcy5oaXN0b3J5ID0gW3tyb2xlOiAnc3lzdGVtJywgY29udGVudDogW3t0ZXh0OiBzeXN0ZW1UZXh0LmpvaW4oJ1xcbicpfV19XTtcbiAgICBjb25zb2xlLmxvZyh0aGlzLmhpc3RvcnkpO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBDaGF0Q2xpZW50IHtcbiAgY21zQ2xpZW50OiBSb290Q01TQ2xpZW50O1xuICB1c2VyOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoY21zQ2xpZW50OiBSb290Q01TQ2xpZW50LCB1c2VyOiBzdHJpbmcpIHtcbiAgICB0aGlzLmNtc0NsaWVudCA9IGNtc0NsaWVudDtcbiAgICB0aGlzLnVzZXIgPSB1c2VyO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlQ2hhdChvcHRpb25zPzoge21vZGVsPzogc3RyaW5nfSk6IFByb21pc2U8Q2hhdD4ge1xuICAgIGNvbnN0IGNoYXRJZCA9IGNyeXB0by5yYW5kb21VVUlEKCk7XG4gICAgLy8gU2F2ZSBjaGF0IHRvIGRiIHNvIHRoYXQgdXNlciBoYXMgYSBjaGF0IGhpc3RvcnkgYW5kIGNhbiBlbmFibGUgXCJzaGFyaW5nXCJcbiAgICAvLyB3aXRoIG90aGVycy4gU3RvcmUgdGhlIG1vZGVsIHVzZWQgd2l0aCB0aGUgbWV0YWRhdGEuXG4gICAgY29uc3QgZG9jUmVmID0gdGhpcy5kYkNvbGxlY3Rpb24oKS5kb2MoY2hhdElkKTtcbiAgICBhd2FpdCBkb2NSZWYuc2V0KHtcbiAgICAgIGlkOiBjaGF0SWQsXG4gICAgICBjcmVhdGVkQnk6IHRoaXMudXNlcixcbiAgICAgIGNyZWF0ZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgbW9kaWZpZWRBdDogVGltZXN0YW1wLm5vdygpLFxuICAgICAgbW9kZWw6IG9wdGlvbnM/Lm1vZGVsIHx8ICdnZW1pbmktMS41LWZsYXNoJyxcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3IENoYXQodGhpcywgY2hhdElkKTtcbiAgfVxuXG4gIGFzeW5jIGdldENoYXQoY2hhdElkOiBzdHJpbmcpOiBQcm9taXNlPENoYXQ+IHtcbiAgICAvLyBGZXRjaCBjaGF0IGZyb20gZGIgdG8gcHJlc2VydmUgdGhlIGNvbnZlcnNhdGlvbidzIGhpc3RvcnkuXG4gICAgY29uc3QgZG9jUmVmID0gdGhpcy5kYkNvbGxlY3Rpb24oKS5kb2MoY2hhdElkKTtcbiAgICBjb25zdCBjaGF0RG9jID0gYXdhaXQgZG9jUmVmLmdldCgpO1xuICAgIGlmICghY2hhdERvYy5leGlzdHMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtjaGF0SWR9IGRvZXMgbm90IGV4aXN0YCk7XG4gICAgfVxuICAgIGNvbnN0IGNoYXREYXRhID0gY2hhdERvYy5kYXRhKCkgfHwge307XG4gICAgcmV0dXJuIG5ldyBDaGF0KHRoaXMsIGNoYXRJZCwge1xuICAgICAgaGlzdG9yeTogY2hhdERhdGEuaGlzdG9yeSxcbiAgICAgIG1vZGVsOiBjaGF0RGF0YS5tb2RlbCxcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGxpc3RDaGF0cyhvcHRpb25zPzoge2xpbWl0PzogbnVtYmVyfSk6IFByb21pc2U8YW55W10+IHtcbiAgICBjb25zdCBsaW1pdCA9IG9wdGlvbnM/LmxpbWl0IHx8IDIwO1xuICAgIGNvbnN0IHF1ZXJ5ID0gdGhpcy5kYkNvbGxlY3Rpb24oKVxuICAgICAgLndoZXJlKCdjcmVhdGVkQnknLCAnPT0nLCB0aGlzLnVzZXIpXG4gICAgICAubGltaXQobGltaXQpXG4gICAgICAub3JkZXJCeSgnY3JlYXRlZEF0JywgJ2Rlc2MnKTtcbiAgICBjb25zdCByZXMgPSBhd2FpdCBxdWVyeS5nZXQoKTtcbiAgICByZXR1cm4gcmVzLmRvY3MubWFwKChkb2MpID0+IGRvYy5kYXRhKCkpO1xuICB9XG5cbiAgZGJDb2xsZWN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLmNtc0NsaWVudC5kYi5jb2xsZWN0aW9uKFxuICAgICAgYFByb2plY3RzLyR7dGhpcy5jbXNDbGllbnQucHJvamVjdElkfS9FeHBlcmltZW50cy9haS9DaGF0YFxuICAgICk7XG4gIH1cbn1cbiIsICJpbXBvcnQge3BhcnNlIGFzIGNzdlBhcnNlfSBmcm9tICdjc3YtcGFyc2Uvc3luYyc7XG5pbXBvcnQge3N0cmluZ2lmeSBhcyBjc3ZTdHJpbmdpZnl9IGZyb20gJ2Nzdi1zdHJpbmdpZnkvc3luYyc7XG5cbmV4cG9ydCBmdW5jdGlvbiBhcnJheVRvQ3N2KHJlcToge1xuICBoZWFkZXJzOiBzdHJpbmdbXTtcbiAgcm93czogQXJyYXk8UmVjb3JkPHN0cmluZywgYW55Pj47XG59KTogc3RyaW5nIHtcbiAgY29uc3QgaGVhZGVycyA9IHJlcS5oZWFkZXJzIHx8IFtdO1xuICBjb25zdCByb3dzID0gcmVxLnJvd3MgfHwgW107XG4gIHJldHVybiBjc3ZTdHJpbmdpZnkocm93cywge1xuICAgIGhlYWRlcjogdHJ1ZSxcbiAgICBjb2x1bW5zOiBoZWFkZXJzLFxuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNzdlRvQXJyYXkoY3N2U3RyaW5nOiBzdHJpbmcpIHtcbiAgY29uc3Qgcm93cyA9IGNzdlBhcnNlKGNzdlN0cmluZywge1xuICAgIGNvbHVtbnM6IHRydWUsXG4gICAgc2tpcF9lbXB0eV9saW5lczogdHJ1ZSxcbiAgfSk7XG4gIHJldHVybiByb3dzO1xufVxuIiwgImltcG9ydCB7Um9vdENvbmZpZ30gZnJvbSAnQGJsaW5ray9yb290JztcbmltcG9ydCB7VGltZXN0YW1wfSBmcm9tICdmaXJlYmFzZS1hZG1pbi9maXJlc3RvcmUnO1xuaW1wb3J0IHtSb290Q01TQ2xpZW50LCBUcmFuc2xhdGlvbiwgVHJhbnNsYXRpb25zRG9jfSBmcm9tICcuL2NsaWVudC5qcyc7XG5cbi8qKlxuICogUnVucyBjb21wYXRpYmlsaXR5IGNoZWNrcyB0byBlbnN1cmUgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiByb290IHN1cHBvcnRzXG4gKiBhbnkgYmFja3dhcmRzLWluY29tcGF0aWJsZSBkYiBjaGFuZ2VzLlxuICpcbiAqIENvbXBhdGliaWxpdHkgdmVyc2lvbnMgYXJlIHN0b3JlZCBpbiB0aGUgZGIgaW4gUHJvamVjdHMvPHByb2plY3RJZD4gdW5kZXJcbiAqIHRoZSBcImNvbXBhdGliaWxpdHlcIiBrZXkuIElmIHRoZSBjb21wYXRpYmlsaXR5IHZlcnNpb24gaXMgbGVzcyB0aGFuIHRoZVxuICogbGF0ZXN0IHZlcnNpb24sIGEgYmFja3dhcmRzLWZyaWVuZGx5IFwibWlncmF0aW9uXCIgaXMgZG9uZSB0byBlbnN1cmVcbiAqIGNvbXBhdGliaWxpdHkgb24gYm90aCB0aGUgb2xkIGFuZCBuZXcgdmVyc2lvbnMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW5Db21wYXRpYmlsaXR5Q2hlY2tzKHJvb3RDb25maWc6IFJvb3RDb25maWcpIHtcbiAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocm9vdENvbmZpZyk7XG4gIGNvbnN0IHByb2plY3RJZCA9IGNtc0NsaWVudC5wcm9qZWN0SWQ7XG4gIGNvbnN0IGRiID0gY21zQ2xpZW50LmRiO1xuICBjb25zdCBwcm9qZWN0Q29uZmlnRG9jUmVmID0gZGIuZG9jKGBQcm9qZWN0cy8ke3Byb2plY3RJZH1gKTtcbiAgY29uc3QgcHJvamVjdENvbmZpZ0RvYyA9IGF3YWl0IHByb2plY3RDb25maWdEb2NSZWYuZ2V0KCk7XG4gIGNvbnN0IHByb2plY3RDb25maWcgPSBwcm9qZWN0Q29uZmlnRG9jLmRhdGEoKSB8fCB7fTtcblxuICBjb25zdCBjb21wYXRpYmlsaXR5VmVyc2lvbnMgPSBwcm9qZWN0Q29uZmlnLmNvbXBhdGliaWxpdHkgfHwge307XG4gIGxldCB2ZXJzaW9uc0NoYW5nZWQgPSBmYWxzZTtcblxuICBjb25zdCB0cmFuc2xhdGlvbnNWZXJzaW9uID0gY29tcGF0aWJpbGl0eVZlcnNpb25zLnRyYW5zbGF0aW9ucyB8fCAwO1xuICBpZiAodHJhbnNsYXRpb25zVmVyc2lvbiA8IDIpIHtcbiAgICBhd2FpdCBtaWdyYXRlVHJhbnNsYXRpb25zVG9WMihyb290Q29uZmlnLCBjbXNDbGllbnQpO1xuICAgIGNvbXBhdGliaWxpdHlWZXJzaW9ucy50cmFuc2xhdGlvbnMgPSAyO1xuICAgIHZlcnNpb25zQ2hhbmdlZCA9IHRydWU7XG4gIH1cblxuICBpZiAodmVyc2lvbnNDaGFuZ2VkKSB7XG4gICAgYXdhaXQgcHJvamVjdENvbmZpZ0RvY1JlZi51cGRhdGUoe2NvbXBhdGliaWxpdHk6IGNvbXBhdGliaWxpdHlWZXJzaW9uc30pO1xuICAgIGNvbnNvbGUubG9nKCdbcm9vdCBjbXNdIHVwZGF0ZWQgZGIgY29tcGF0aWJpbGl0eScpO1xuICB9XG59XG5cbi8qKlxuICogTWlncmF0ZXMgdHJhbnNsYXRpb25zIGZyb20gdGhlIFwidjFcIiBmb3JtYXQgdG8gXCJ2MlwiLlxuICovXG5hc3luYyBmdW5jdGlvbiBtaWdyYXRlVHJhbnNsYXRpb25zVG9WMihcbiAgcm9vdENvbmZpZzogUm9vdENvbmZpZyxcbiAgY21zQ2xpZW50OiBSb290Q01TQ2xpZW50XG4pIHtcbiAgaWYgKHJvb3RDb25maWcuZXhwZXJpbWVudHM/LnJvb3RDbXNEaXNhYmxlVHJhbnNsYXRpb25zVG9WMkNoZWNrKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgcHJvamVjdElkID0gY21zQ2xpZW50LnByb2plY3RJZDtcbiAgY29uc3QgZGIgPSBjbXNDbGllbnQuZGI7XG4gIGNvbnN0IGRiUGF0aCA9IGBQcm9qZWN0cy8ke3Byb2plY3RJZH0vVHJhbnNsYXRpb25zYDtcbiAgY29uc3QgcXVlcnkgPSBkYi5jb2xsZWN0aW9uKGRiUGF0aCk7XG4gIGNvbnN0IHF1ZXJ5U25hcHNob3QgPSBhd2FpdCBxdWVyeS5nZXQoKTtcbiAgaWYgKHF1ZXJ5U25hcHNob3Quc2l6ZSA9PT0gMCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnNvbGUubG9nKCdbcm9vdCBjbXNdIHVwZGF0aW5nIHRyYW5zbGF0aW9ucyB2MiBjb21wYXRpYmlsaXR5Jyk7XG5cbiAgY29uc3QgdHJhbnNsYXRpb25zRG9jczogUmVjb3JkPHN0cmluZywgVHJhbnNsYXRpb25zRG9jPiA9IHt9O1xuICBxdWVyeVNuYXBzaG90LmZvckVhY2goKGRvYykgPT4ge1xuICAgIGNvbnN0IGhhc2ggPSBkb2MuaWQ7XG4gICAgY29uc3QgdHJhbnNsYXRpb24gPSBkb2MuZGF0YSgpIGFzIFRyYW5zbGF0aW9uO1xuICAgIGNvbnN0IHRhZ3MgPSAodHJhbnNsYXRpb24udGFncyB8fCBbXSkgYXMgc3RyaW5nW107XG4gICAgZGVsZXRlIHRyYW5zbGF0aW9uLnRhZ3M7XG4gICAgZm9yIChjb25zdCB0YWcgb2YgdGFncykge1xuICAgICAgaWYgKHRhZy5pbmNsdWRlcygnLycpKSB7XG4gICAgICAgIGNvbnN0IHRyYW5zbGF0aW9uc0lkID0gdGFnO1xuICAgICAgICB0cmFuc2xhdGlvbnNEb2NzW3RyYW5zbGF0aW9uc0lkXSA/Pz0ge1xuICAgICAgICAgIGlkOiB0cmFuc2xhdGlvbnNJZCxcbiAgICAgICAgICBzeXM6IHtcbiAgICAgICAgICAgIG1vZGlmaWVkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgICAgICAgIG1vZGlmaWVkQnk6ICdyb290LWNtcy1jbGllbnQnLFxuICAgICAgICAgICAgcHVibGlzaGVkQXQ6IFRpbWVzdGFtcC5ub3coKSxcbiAgICAgICAgICAgIHB1Ymxpc2hlZEJ5OiAncm9vdC1jbXMtY2xpZW50JyxcbiAgICAgICAgICAgIHRhZ3M6IHRhZ3MsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBzdHJpbmdzOiB7fSxcbiAgICAgICAgfTtcbiAgICAgICAgdHJhbnNsYXRpb25zRG9jc1t0cmFuc2xhdGlvbnNJZF0uc3RyaW5nc1toYXNoXSA9IHRyYW5zbGF0aW9uO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgaWYgKE9iamVjdC5rZXlzKHRyYW5zbGF0aW9uc0RvY3MpLmxlbmd0aCA9PT0gMCkge1xuICAgIGNvbnNvbGUubG9nKCdbcm9vdCBjbXNdIG5vIHRyYW5zbGF0aW9ucyB0byBzYXZlJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gTW92ZSB0aGUgZG9jJ3MgXCJsMTBuU2hlZXRcIiB0byB0aGUgdHJhbnNsYXRpb25zIGRvYydzIFwibGlua2VkU2hlZXRcIi5cblxuICBmb3IgKGNvbnN0IGRvY0lkIGluIHRyYW5zbGF0aW9uc0RvY3MpIHtcbiAgICBjb25zdCBbY29sbGVjdGlvbiwgc2x1Z10gPSBkb2NJZC5zcGxpdCgnLycpO1xuICAgIGlmIChjb2xsZWN0aW9uICYmIHNsdWcpIHtcbiAgICAgIGNvbnN0IGRvYzogYW55ID0gYXdhaXQgY21zQ2xpZW50LmdldERvYyhjb2xsZWN0aW9uLCBzbHVnLCB7XG4gICAgICAgIG1vZGU6ICdkcmFmdCcsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGxpbmtlZFNoZWV0ID0gZG9jPy5zeXM/LmwxMG5TaGVldDtcbiAgICAgIGlmIChsaW5rZWRTaGVldCkge1xuICAgICAgICB0cmFuc2xhdGlvbnNEb2NzW2RvY0lkXS5zeXMubGlua2VkU2hlZXQgPSBsaW5rZWRTaGVldDtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCBiYXRjaCA9IGRiLmJhdGNoKCk7XG4gIE9iamVjdC5lbnRyaWVzKHRyYW5zbGF0aW9uc0RvY3MpLmZvckVhY2goKFt0cmFuc2xhdGlvbnNJZCwgZGF0YV0pID0+IHtcbiAgICBjb25zdCBkcmFmdFJlZiA9IGRiLmRvYyhcbiAgICAgIGBQcm9qZWN0cy8ke3Byb2plY3RJZH0vVHJhbnNsYXRpb25zTWFuYWdlci9kcmFmdC9UcmFuc2xhdGlvbnMvJHt0cmFuc2xhdGlvbnNJZH1gXG4gICAgKTtcbiAgICBjb25zdCBwdWJsaXNoZWRSZWYgPSBkYi5kb2MoXG4gICAgICBgUHJvamVjdHMvJHtwcm9qZWN0SWR9L1RyYW5zbGF0aW9uc01hbmFnZXIvcHVibGlzaGVkL1RyYW5zbGF0aW9ucy8ke3RyYW5zbGF0aW9uc0lkfWBcbiAgICApO1xuICAgIGJhdGNoLnNldChkcmFmdFJlZiwgZGF0YSwge21lcmdlOiB0cnVlfSk7XG4gICAgYmF0Y2guc2V0KHB1Ymxpc2hlZFJlZiwgZGF0YSwge21lcmdlOiB0cnVlfSk7XG4gICAgY29uc3QgbGVuID0gT2JqZWN0LmtleXMoZGF0YS5zdHJpbmdzKS5sZW5ndGg7XG4gICAgY29uc29sZS5sb2coYFtyb290IGNtc10gc2F2aW5nICR7bGVufSBzdHJpbmcocykgdG8gJHt0cmFuc2xhdGlvbnNJZH0uLi5gKTtcbiAgfSk7XG4gIGF3YWl0IGJhdGNoLmNvbW1pdCgpO1xuXG4gIGNvbnNvbGUubG9nKCdbcm9vdCBjbXNdIGRvbmUgbWlncmF0aW5nIHRyYW5zbGF0aW9ucyB0byB2MicpO1xufVxuIiwgIi8qKlxuICogRG9jdW1lbnQgdmVyaW9uIGhpc3RvcnkuXG4gKlxuICogVmVyaW9ucyBzYXZlIHRoZSBzdGF0ZSBvZiBhIGRvY3VtZW50IGF0IGRpZmZlcmVudCBtb21lbnRzIGluIHRpbWUsIGFsbG93aW5nXG4gKiB1c2VycyB0byByZXZlcnQgYmFjayB0byBhIHZlcnNpb24gaWYvd2hlbiBuZWVkZWQuXG4gKlxuICogVGhlIHNhdmVWZXJzaW9ucygpIGZ1bmN0aW9uIGlzIG1lYW50IHRvIGJlIHJ1biB3aXRoaW4gYSBjcm9uIGpvYiAoZS5nIHVzaW5nXG4gKiBmaXJlYmFzZSBmdW5jdGlvbnMpLiBFdmVyeSBtaW51dGUsIHRoZSBydW5uZXIgY2hlY2tzIGZvciBhbGwgZG9jdW1lbnRzIHRoYXRcbiAqIGhhdmUgYmVlbiBlZGl0ZWQgc2luY2UgdGhlIGxhc3QgcnVuLiBUbyBhdm9pZCBzYXZpbmcgXCJwYXJ0aWFsXCIgdmVyc2lvbnNcbiAqICh3aGVuIHRoZSB1c2VyIG1pZ2h0IGJlIGluIHRoZSBtaWRkbGUgb2YgZWRpdGluZyBhIGRvY3VtZW50KSwgdmVyc2lvbnMgb25seVxuICogcnVuIG9uIGRvY3VtZW50cyB0aGF0IGhhdmVuJ3QgYmVlbiBlZGl0ZWQgd2l0aGluIHRoZSBsYXN0IDUgbWlucyB0byBlbnN1cmVcbiAqIHRoYXQgdmVyc2lvbiBpcyBcInN0YWJsZVwiLlxuICpcbiAqIEluIHRoZSBkYXRhYmFzZSwgdmVyc2lvbnMgYXJlIHN0b3JlZCBhczpcbiAqIC9Qcm9qZWN0cy88cHJvamVjdElkPi9Db2xsZWN0aW9ucy88Y29sbGVjdGlvbklkPi9EcmFmdHMvPGRvY0lkPi9WZXJzaW9ucy88dGltZXN0YW1wPlxuICpcbiAqIFdoZXJlIDx0aW1lc3RhbXA+IGlzIHRoZSB1bml4IHRpbWVzdGFtcCAobWlsbGlzKSB0aGF0IHRoZSBkb2N1bWVudCB3YXMgbGFzdFxuICogZWRpdGVkLlxuICovXG5cbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge1Jvb3RDb25maWd9IGZyb20gJ0BibGlua2svcm9vdCc7XG5pbXBvcnQge0ZpcmVzdG9yZSwgUXVlcnksIFRpbWVzdGFtcH0gZnJvbSAnZmlyZWJhc2UtYWRtaW4vZmlyZXN0b3JlJztcbmltcG9ydCBnbG9iIGZyb20gJ3RpbnktZ2xvYic7XG5pbXBvcnQge2dldENtc1BsdWdpbn0gZnJvbSAnLi9jbGllbnQuanMnO1xuXG4vLyBUbyBhdm9pZCBzYXZpbmcgXCJwYXJ0aWFsXCIgdmVyc2lvbnMgKHdoZW4gdGhlIHVzZXIgbWlnaHQgYmUgaW4gdGhlIG1pZGRsZSBvZlxuLy8gZWRpdGluZyBhIGRvY3VtZW50KSwgdmVyc2lvbnMgb25seSBydW4gb24gZG9jdW1lbnRzIHRoYXQgaGF2ZW4ndCBiZWVuIGVkaXRlZFxuLy8gd2l0aGluIHRoZSBsYXN0IDUgbWlucyB0byBlbnN1cmUgdGhhdCB2ZXJzaW9uIGlzIFwic3RhYmxlXCIuXG5jb25zdCBET0NVTUVOVF9TQVZFX09GRlNFVCA9IDUgKiA2MCAqIDEwMDA7XG5cbmludGVyZmFjZSBQYXJ0aWFsQ01TRG9jIHtcbiAgW2tleTogc3RyaW5nXTogYW55O1xuICBpZDogc3RyaW5nO1xuICBjb2xsZWN0aW9uOiBzdHJpbmc7XG4gIHNsdWc6IHN0cmluZztcbiAgc3lzOiB7XG4gICAgbW9kaWZpZWRBdDogVGltZXN0YW1wO1xuICAgIG1vZGlmaWVkQnk6IHN0cmluZztcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIFZlcnNpb25zU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgcm9vdENvbmZpZzogUm9vdENvbmZpZztcbiAgcHJpdmF0ZSByZWFkb25seSBwcm9qZWN0SWQ6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBkYjogRmlyZXN0b3JlO1xuXG4gIGNvbnN0cnVjdG9yKHJvb3RDb25maWc6IFJvb3RDb25maWcpIHtcbiAgICB0aGlzLnJvb3RDb25maWcgPSByb290Q29uZmlnO1xuICAgIGNvbnN0IGNtc1BsdWdpbiA9IGdldENtc1BsdWdpbihyb290Q29uZmlnKTtcbiAgICBjb25zdCBjbXNQbHVnaW5PcHRpb25zID0gY21zUGx1Z2luLmdldENvbmZpZygpO1xuICAgIGNvbnN0IHByb2plY3RJZCA9IGNtc1BsdWdpbk9wdGlvbnMuaWQgfHwgJ2RlZmF1bHQnO1xuICAgIHRoaXMucHJvamVjdElkID0gcHJvamVjdElkO1xuICAgIHRoaXMuZGIgPSBjbXNQbHVnaW4uZ2V0RmlyZXN0b3JlKCk7XG4gIH1cblxuICAvKipcbiAgICogU2F2ZXMgYSB2ZXJzaW9uIG9mIGFsbCBkb2N1bWVudHMgdGhhdCBoYXZlIGJlZW4gZWRpdGVkIHNpbmNlIHRoZSBsYXN0IHJ1bi5cbiAgICovXG4gIGFzeW5jIHNhdmVWZXJzaW9ucygpIHtcbiAgICAvLyBPZmZzZXQgdGhlIFwibGFzdCBydW5cIiB0aW1lIGJ5IDUgbWlucy4gVmVyc2lvbnMgaWdub3JlIGRvY3MgdGhhdCB3ZXJlXG4gICAgLy8gZWRpdGVkIHdpdGhpbiB0aGUgbGFzdCA1IG1pbnMgdG8gYXZvaWQgcG90ZW50aWFsIFwicGFydGlhbFwiIHZlcnNpb25zIHdoZW5cbiAgICAvLyB1c2VyIGlzIGluIHRoZSBtaWRkbGUgb2YgZWRpdGluZyBhIGRvY3VtZW50LlxuICAgIGNvbnN0IGxhc3RSdW4gPSBhd2FpdCB0aGlzLmdldExhc3RSdW4oKTtcbiAgICBjb25zdCBsYXN0UnVuV2l0aE9mZnNldCA9XG4gICAgICBsYXN0UnVuID09PSAwID8gbGFzdFJ1biA6IGxhc3RSdW4gLSBET0NVTUVOVF9TQVZFX09GRlNFVDtcbiAgICBjb25zdCBjaGFuZ2VkRG9jcyA9IGF3YWl0IHRoaXMuZ2V0RG9jc01vZGlmaWVkQWZ0ZXIobGFzdFJ1bldpdGhPZmZzZXQpO1xuICAgIGNvbnN0IG5vdyA9IFRpbWVzdGFtcC5ub3coKS50b01pbGxpcygpO1xuICAgIGNvbnN0IHZlcnNpb25zID0gY2hhbmdlZERvY3MuZmlsdGVyKChkb2MpID0+IHtcbiAgICAgIGNvbnN0IG1vZGlmaWVkQXQgPSBkb2Muc3lzLm1vZGlmaWVkQXQudG9NaWxsaXMoKTtcbiAgICAgIHJldHVybiBtb2RpZmllZEF0IDw9IG5vdyAtIERPQ1VNRU5UX1NBVkVfT0ZGU0VUO1xuICAgIH0pO1xuICAgIGlmICh2ZXJzaW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnNhdmVWZXJzaW9uc1RvRmlyZXN0b3JlKHZlcnNpb25zKTtcbiAgICB9XG4gICAgdGhpcy5zYXZlTGFzdFJ1bihub3cpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzYXZlVmVyc2lvbnNUb0ZpcmVzdG9yZSh2ZXJzaW9uczogUGFydGlhbENNU0RvY1tdKSB7XG4gICAgY29uc3QgYmF0Y2ggPSB0aGlzLmRiLmJhdGNoKCk7XG4gICAgdmVyc2lvbnMuZm9yRWFjaCgodmVyc2lvbikgPT4ge1xuICAgICAgaWYgKCF2ZXJzaW9uLmNvbGxlY3Rpb24gfHwgIXZlcnNpb24uc2x1ZyB8fCAhdmVyc2lvbi5zeXM/Lm1vZGlmaWVkQXQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3QgbW9kaWZpZWRBdE1pbGxpcyA9IHZlcnNpb24uc3lzLm1vZGlmaWVkQXQudG9NaWxsaXMoKTtcbiAgICAgIGNvbnN0IHZlcnNpb25QYXRoID0gYFByb2plY3RzLyR7dGhpcy5wcm9qZWN0SWR9L0NvbGxlY3Rpb25zLyR7dmVyc2lvbi5jb2xsZWN0aW9ufS9EcmFmdHMvJHt2ZXJzaW9uLnNsdWd9L1ZlcnNpb25zLyR7bW9kaWZpZWRBdE1pbGxpc31gO1xuICAgICAgY29uc29sZS5sb2codmVyc2lvblBhdGgpO1xuICAgICAgY29uc3QgdmVyc2lvblJlZiA9IHRoaXMuZGIuZG9jKHZlcnNpb25QYXRoKTtcbiAgICAgIGJhdGNoLnNldCh2ZXJzaW9uUmVmLCB2ZXJzaW9uKTtcbiAgICB9KTtcbiAgICBhd2FpdCBiYXRjaC5jb21taXQoKTtcbiAgICBjb25zb2xlLmxvZyhgdmVyc2lvbnM6IHNhdmVkICR7dmVyc2lvbnMubGVuZ3RofSB2ZXJzaW9uc2ApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGxhc3QgdGltZSAoaW4gbWlsbGlzKSBzYXZlVmVyc2lvbnMoKSB3YXMgcnVuLCBvciAwIGlmIGhhc1xuICAgKiBuZXZlciBiZWVuIHJ1bi5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0TGFzdFJ1bigpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHByb2plY3REb2NSZWYgPSB0aGlzLmRiLmNvbGxlY3Rpb24oJ1Byb2plY3RzJykuZG9jKHRoaXMucHJvamVjdElkKTtcbiAgICBjb25zdCBwcm9qZWN0RG9jID0gYXdhaXQgcHJvamVjdERvY1JlZi5nZXQoKTtcbiAgICBpZiAocHJvamVjdERvYy5leGlzdHMpIHtcbiAgICAgIGNvbnN0IGRhdGEgPSBwcm9qZWN0RG9jLmRhdGEoKSB8fCB7fTtcbiAgICAgIGNvbnN0IHRzID0gZGF0YS52ZXJzaW9uc0xhc3RSdW4gYXMgVGltZXN0YW1wO1xuICAgICAgaWYgKHRzKSB7XG4gICAgICAgIHJldHVybiB0cy50b01pbGxpcygpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYXZlcyB7dmVyc2lvbkxhc3RSdW46IDx0aW1lc3RhbXA+fSB0byB0aGUgUHJvamVjdHMvPHByb2plY3RJZD4gZG9jLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzYXZlTGFzdFJ1bihtaWxsaXM6IG51bWJlcikge1xuICAgIGNvbnN0IHRzID0gVGltZXN0YW1wLmZyb21NaWxsaXMobWlsbGlzKTtcbiAgICBjb25zdCBwcm9qZWN0RG9jUmVmID0gdGhpcy5kYi5jb2xsZWN0aW9uKCdQcm9qZWN0cycpLmRvYyh0aGlzLnByb2plY3RJZCk7XG4gICAgYXdhaXQgcHJvamVjdERvY1JlZi5zZXQoe3ZlcnNpb25zTGFzdFJ1bjogdHN9LCB7bWVyZ2U6IHRydWV9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbGlzdCBvZiBhbGwgZG9jcyB0aGF0IHdlcmUgZWRpdGVkIGFmdGVyIGEgY2VydGFpbiB0aW1lLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXREb2NzTW9kaWZpZWRBZnRlcihtaWxsaXM6IG51bWJlcik6IFByb21pc2U8UGFydGlhbENNU0RvY1tdPiB7XG4gICAgY29uc3QgdHMgPSBUaW1lc3RhbXAuZnJvbU1pbGxpcyhtaWxsaXMpO1xuICAgIGNvbnN0IHJlc3VsdHM6IFBhcnRpYWxDTVNEb2NbXSA9IFtdO1xuICAgIGNvbnN0IGNvbGxlY3Rpb25JZHMgPSBhd2FpdCB0aGlzLmxpc3RDb2xsZWN0aW9ucygpO1xuICAgIC8vIE5PVEU6IEluZGl2aWR1YWwgY29sbGVjdGlvbnMgYXJlIHF1ZXJpZWQgaW5zdGVhZCBvZiB1c2luZyBhXG4gICAgLy8gY29sbGVjdGlvbkdyb3VwIHF1ZXJ5IGJlY2F1c2UgdGhlIGxhdHRlciByZXF1aXJlcyBhIGZpcmVzdG9yZSBpbmRleCB0byBiZVxuICAgIC8vIHNldCB1cC5cbiAgICBmb3IgKGNvbnN0IGNvbGxlY3Rpb25JZCBvZiBjb2xsZWN0aW9uSWRzKSB7XG4gICAgICBjb25zdCBjb2xsZWN0aW9uUGF0aCA9IGBQcm9qZWN0cy8ke3RoaXMucHJvamVjdElkfS9Db2xsZWN0aW9ucy8ke2NvbGxlY3Rpb25JZH0vRHJhZnRzYDtcbiAgICAgIGNvbnN0IHF1ZXJ5OiBRdWVyeSA9IHRoaXMuZGJcbiAgICAgICAgLmNvbGxlY3Rpb24oY29sbGVjdGlvblBhdGgpXG4gICAgICAgIC53aGVyZSgnc3lzLm1vZGlmaWVkQXQnLCAnPj0nLCB0cyk7XG4gICAgICBjb25zdCBxdWVyeVNuYXBzaG90ID0gYXdhaXQgcXVlcnkuZ2V0KCk7XG4gICAgICBxdWVyeVNuYXBzaG90LmZvckVhY2goKGRvYykgPT4ge1xuICAgICAgICByZXN1bHRzLnB1c2goZG9jLmRhdGEoKSBhcyBQYXJ0aWFsQ01TRG9jKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbGlzdCBvZiBjb2xsZWN0aW9uIGlkcyBmb3IgdGhlIFJvb3QgcHJvamVjdC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgbGlzdENvbGxlY3Rpb25zKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBjb25zdCBjb2xsZWN0aW9uSWRzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IGNvbGxlY3Rpb25GaWxlTmFtZXMgPSBhd2FpdCBnbG9iKCcqLnNjaGVtYS50cycsIHtcbiAgICAgIGN3ZDogcGF0aC5qb2luKHRoaXMucm9vdENvbmZpZy5yb290RGlyLCAnY29sbGVjdGlvbnMnKSxcbiAgICB9KTtcbiAgICBjb2xsZWN0aW9uRmlsZU5hbWVzLmZvckVhY2goKGZpbGVuYW1lKSA9PiB7XG4gICAgICBjb2xsZWN0aW9uSWRzLnB1c2goZmlsZW5hbWUuc2xpY2UoMCwgLTEwKSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGNvbGxlY3Rpb25JZHM7XG4gIH1cbn1cbiIsICJpbXBvcnQge1Jvb3RDb25maWd9IGZyb20gJ0BibGlua2svcm9vdCc7XG5pbXBvcnQge1Jvb3RDTVNDbGllbnR9IGZyb20gJy4vY2xpZW50LmpzJztcbmltcG9ydCB7VmVyc2lvbnNTZXJ2aWNlfSBmcm9tICcuL3ZlcnNpb25zLmpzJztcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bkNyb25Kb2JzKHJvb3RDb25maWc6IFJvb3RDb25maWcpIHtcbiAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIHJ1bkNyb25Kb2IoJ3B1Ymxpc2hTY2hlZHVsZWREb2NzJywgcnVuUHVibGlzaFNjaGVkdWxlZERvY3MsIHJvb3RDb25maWcpLFxuICAgIHJ1bkNyb25Kb2IoJ3NhdmVWZXJzaW9ucycsIHJ1blNhdmVWZXJzaW9ucywgcm9vdENvbmZpZyksXG4gIF0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBydW5Dcm9uSm9iKFxuICBuYW1lOiBzdHJpbmcsXG4gIGZuOiAoLi4uYXJnczogYW55W10pID0+IGFueSxcbiAgLi4uYXJnczogYW55W11cbikge1xuICB0cnkge1xuICAgIGF3YWl0IGZuKC4uLmFyZ3MpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBjb25zb2xlLmxvZyhgY3JvbiBmYWlsZWQ6ICR7bmFtZX1gKTtcbiAgICBjb25zb2xlLmVycm9yKFN0cmluZyhlcnIuc3RhY2sgfHwgZXJyKSk7XG4gICAgdGhyb3cgZXJyO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1blB1Ymxpc2hTY2hlZHVsZWREb2NzKHJvb3RDb25maWc6IFJvb3RDb25maWcpIHtcbiAgY29uc3QgY21zQ2xpZW50ID0gbmV3IFJvb3RDTVNDbGllbnQocm9vdENvbmZpZyk7XG4gIGF3YWl0IGNtc0NsaWVudC5wdWJsaXNoU2NoZWR1bGVkRG9jcygpO1xuICBhd2FpdCBjbXNDbGllbnQucHVibGlzaFNjaGVkdWxlZFJlbGVhc2VzKCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1blNhdmVWZXJzaW9ucyhyb290Q29uZmlnOiBSb290Q29uZmlnKSB7XG4gIGNvbnN0IHNlcnZpY2UgPSBuZXcgVmVyc2lvbnNTZXJ2aWNlKHJvb3RDb25maWcpO1xuICBhd2FpdCBzZXJ2aWNlLnNhdmVWZXJzaW9ucygpO1xufVxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFBLE9BQU9BLFdBQVU7QUFDakIsU0FBUSx5QkFBd0I7QUFDaEMsU0FBeUIsa0JBQWlCOzs7QUNGMUMsT0FBT0MsYUFBWTtBQUduQjtBQUFBLEVBQ0U7QUFBQSxFQUdBLGFBQUFDO0FBQUEsT0FFSzs7O0FDVFAsU0FBUSxZQUFZLFVBQVM7QUFDN0IsT0FBTyxVQUFVO0FBQ2pCLFNBQVEscUJBQW9CO0FBVTVCLE9BQU8sZ0JBQWdCO0FBQ3ZCO0FBQUEsRUFFRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVEsZUFBOEI7QUFDdEMsU0FBbUIsb0JBQW1CO0FBQ3RDLFlBQVksa0JBQWtCO0FBQzlCLE9BQU8sVUFBVTs7O0FDckJqQixTQUFRLDJCQUEwQjs7O0FDRGxDLE9BQU8sWUFBWTtBQUNuQixTQUFRLGdCQUFlO0FBQ3ZCLFNBQVEsdUJBQXNCO0FBQzlCLFNBQVEsZ0JBQWU7QUFDdkIsU0FBUSxvQkFBb0IsNEJBQTJCO0FBQ3ZELFNBQVEsaUJB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QTtBQUFBO0FBQUE7QUFBQSxFQUtBLE1BQWMsa0JBQXFDO0FBQ2pELFVBQU0sZ0JBQTBCLENBQUM7QUFDakMsVUFBTSxzQkFBc0IsTUFBTSxLQUFLLGVBQWU7QUFBQSxNQUNwRCxLQUFLQyxNQUFLLEtBQUssS0FBSyxXQUFXLFNBQVMsYUFBYTtBQUFBLElBQ3ZELENBQUM7QUFDRCx3QkFBb0IsUUFBUSxDQUFDLGFBQWE7QUFDeEMsb0JBQWMsS0FBSyxTQUFTLE1BQU0sR0FBRyxHQUFHLENBQUM7QUFBQSxJQUMzQyxDQUFDO0FBQ0QsV0FBTztBQUFBLEVBQ1Q7QUFDRjs7O0FDeEpBLGVBQXNCLFlBQVksWUFBd0I7QUFDeEQsUUFBTSxRQUFRLElBQUk7QUFBQSxJQUNoQixXQUFXLHdCQUF3Qix5QkFBeUIsVUFBVTtBQUFBLElBQ3RFLFdBQVcsZ0JBQWdCLGlCQUFpQixVQUFVO0FBQUEsRUFDeEQsQ0FBQztBQUNIO0FBRUEsZUFBZSxXQUNiLE1BQ0EsT0FDRyxNQUNIO0FBQ0EsTUFBSTtBQUNGLFVBQU0sR0FBRyxHQUFHLElBQUk7QUFBQSxFQUNsQixTQUFTLEtBQUs7QUFDWixZQUFRLElBQUksZ0JBQWdCLElBQUksRUFBRTtBQUNsQyxZQUFRLE1BQU0sT0FBTyxJQUFJLFNBQVMsR0FBRyxDQUFDO0FBQ3RDLFVBQU07QUFBQSxFQUNSO0FBQ0Y7QUFFQSxlQUFlLHdCQUF3QixZQUF3QjtBQUM3RCxRQUFNLFlBQVksSUFBSSxjQUFjLFVBQVU7QUFDOUMsUUFBTSxVQUFVLHFCQUFxQjtBQUNyQyxRQUFNLFVBQVUseUJBQXlCO0FBQzNDO0FBRUEsZUFBZSxnQkFBZ0IsWUFBd0I7QUFDckQsUUFBTSxVQUFVLElBQUksZ0JBQWdCLFVBQVU7QUFDOUMsUUFBTSxRQUFRLGFBQWE7QUFDN0I7OztBUnJCTyxTQUFTLEtBQUssU0FBdUI7QUFDMUMsUUFBTSxVQUFVQyxNQUFLLFNBQVEsbUNBQVMsWUFBVyxRQUFRLElBQUksQ0FBQztBQUM5RCxRQUFNLGtCQUFtQztBQUFBLElBQ3ZDLFVBQVU7QUFBQSxJQUNWLEdBQUcsbUNBQVM7QUFBQSxFQUNkO0FBQ0EsU0FBTyxXQUFXLGlCQUFpQixZQUFZO0FBQzdDLFVBQU0sYUFBYSxNQUFNLGtCQUFrQixTQUFTLEVBQUMsU0FBUyxXQUFVLENBQUM7QUFDekUsVUFBTSxZQUFZLFVBQVU7QUFBQSxFQUM5QixDQUFDO0FBQ0g7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiY3J5cHRvIiwgIlRpbWVzdGFtcCIsICJUaW1lc3RhbXAiLCAicGx1Z2luIiwgIlRpbWVzdGFtcCIsICJjcnlwdG8iLCAib2JqIiwgInBhdGgiLCAiVGltZXN0YW1wIiwgIlRpbWVzdGFtcCIsICJwYXRoIiwgInBhdGgiXQp9Cg==