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